summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore58
-rw-r--r--BUILD/FINISH.sh2
-rwxr-xr-xBUILD/SETUP.sh10
-rwxr-xr-xBUILD/compile-pentium-debug2
-rwxr-xr-xBUILD/compile-pentium-debug-max2
-rw-r--r--BUILD/compile-pentium64-valgrind-max29
-rwxr-xr-xBUILD/compile-solaris-sparc-purify27
-rw-r--r--BitKeeper/etc/gone449
-rw-r--r--BitKeeper/etc/logging_ok29
-rwxr-xr-xBitKeeper/triggers/post-commit6
-rwxr-xr-xDocs/changelog-5.0.xml18
-rw-r--r--Docs/sp-imp-spec.txt1100
-rw-r--r--Docs/sp-implemented.txt112
-rw-r--r--Makefile.am7
-rw-r--r--VC++Files/client/mysqlclient.dsp8
-rw-r--r--VC++Files/client/mysqlclient_ia64.dsp8
-rw-r--r--VC++Files/client/mysqltest.dsp12
-rw-r--r--VC++Files/libmysql/libmysql.dsp8
-rw-r--r--VC++Files/libmysql/libmysql_ia64.dsp8
-rw-r--r--VC++Files/libmysqld/examples/test_libmysqld.dsp6
-rw-r--r--VC++Files/libmysqld/libmysqld.dsp48
-rw-r--r--VC++Files/libmysqltest/mytest.c1
-rw-r--r--VC++Files/mysql.dsw99
-rw-r--r--VC++Files/mysql_ia64.dsw3
-rw-r--r--VC++Files/mysqldemb/mysqldemb.dsp4
-rw-r--r--VC++Files/mysqlmanager/MySqlManager_ia64.dsp276
-rw-r--r--VC++Files/mysqlmanager/README.TXT102
-rw-r--r--VC++Files/mysqlmanager/RES/bitmap1.bmpbin630 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/bitmap3.bmpbin630 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/bmp00001.bmpbin246 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/bmp00002.bmpbin238 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/database.bmpbin238 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/fontd.bmpbin246 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/fontu.bmpbin246 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/mysqlmanager.icobin1078 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/mysqlmanager.rc213
-rw-r--r--VC++Files/mysqlmanager/RES/mysqlmanagerdoc.icobin1078 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/query_ex.bmpbin246 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/RES/toolbar.bmpbin1078 -> 0 bytes
-rw-r--r--VC++Files/mysqlmanager/childfrm.cpp65
-rw-r--r--VC++Files/mysqlmanager/childfrm.h52
-rw-r--r--VC++Files/mysqlmanager/cresource.h134
-rw-r--r--VC++Files/mysqlmanager/mainfrm.cpp137
-rw-r--r--VC++Files/mysqlmanager/mainfrm.h69
-rw-r--r--VC++Files/mysqlmanager/mysqlmanager.cpp168
-rw-r--r--VC++Files/mysqlmanager/mysqlmanager.dsp277
-rw-r--r--VC++Files/mysqlmanager/mysqlmanager.dsw28
-rw-r--r--VC++Files/mysqlmanager/mysqlmanager.h50
-rw-r--r--VC++Files/mysqlmanager/mysqlmanager.mak327
-rw-r--r--VC++Files/mysqlmanager/mysqlmanager.rc572
-rw-r--r--VC++Files/mysqlmanager/mysqlmanagerdoc.cpp84
-rw-r--r--VC++Files/mysqlmanager/mysqlmanagerdoc.h57
-rw-r--r--VC++Files/mysqlmanager/mysqlmanagerview.cpp849
-rw-r--r--VC++Files/mysqlmanager/mysqlmanagerview.h89
-rw-r--r--VC++Files/mysqlmanager/registerserver.cpp51
-rw-r--r--VC++Files/mysqlmanager/registerserver.h50
-rw-r--r--VC++Files/mysqlmanager/resource.h55
-rw-r--r--VC++Files/mysqlmanager/stdafx.cpp5
-rw-r--r--VC++Files/mysqlmanager/stdafx.h28
-rw-r--r--VC++Files/mysqlmanager/toolsql.cpp687
-rw-r--r--VC++Files/mysqlmanager/toolsql.h102
-rw-r--r--VC++Files/mysqlmanager/toolsqlquery.cpp110
-rw-r--r--VC++Files/mysqlmanager/toolsqlquery.h60
-rw-r--r--VC++Files/mysqlmanager/toolsqlresults.cpp73
-rw-r--r--VC++Files/mysqlmanager/toolsqlresults.h53
-rw-r--r--VC++Files/mysqlmanager/toolsqlstatus.cpp50
-rw-r--r--VC++Files/mysqlmanager/toolsqlstatus.h47
-rw-r--r--VC++Files/mysys/mysys.dsp5
-rwxr-xr-xVC++Files/prepare5
-rw-r--r--VC++Files/sql/mysqld.dsp86
-rw-r--r--VC++Files/sql/mysqldmax.dsp14
-rw-r--r--VC++Files/strings/strings.dsp12
-rw-r--r--VC++Files/strings/strings_ia64.dsp8
-rw-r--r--VC++Files/test1/mysql_thr.c1
-rw-r--r--VC++Files/winmysqladmin/main.cpp2
-rw-r--r--VC++Files/winmysqladmin/mysql.h2
-rw-r--r--VC++Files/winmysqladmin/winmysqladmin.cpp2
-rw-r--r--acinclude.m41990
-rw-r--r--client/Makefile.am19
-rw-r--r--client/mysql.cc37
-rw-r--r--client/mysqladmin.cc7
-rw-r--r--client/mysqlbinlog.cc621
-rw-r--r--client/mysqlcheck.c1
-rw-r--r--client/mysqldump.c333
-rw-r--r--client/mysqlimport.c1
-rw-r--r--client/mysqlshow.c95
-rw-r--r--client/mysqltest.c540
-rw-r--r--client/sql_string.cc649
-rw-r--r--client/sql_string.h125
-rw-r--r--config/ac-macros/alloca.m468
-rw-r--r--config/ac-macros/character_sets.m4431
-rw-r--r--config/ac-macros/check_cpu.m447
-rw-r--r--config/ac-macros/compiler_flag.m440
-rw-r--r--config/ac-macros/ha_archive.m429
-rw-r--r--config/ac-macros/ha_berkeley.m4267
-rw-r--r--config/ac-macros/ha_blackhole.m429
-rw-r--r--config/ac-macros/ha_example.m430
-rw-r--r--config/ac-macros/ha_federated.m429
-rw-r--r--config/ac-macros/ha_innodb.m477
-rw-r--r--config/ac-macros/ha_ndbcluster.m4154
-rw-r--r--config/ac-macros/ha_tina.m429
-rw-r--r--config/ac-macros/large_file.m4140
-rw-r--r--config/ac-macros/misc.m4695
-rw-r--r--config/ac-macros/openssl.m4133
-rw-r--r--config/ac-macros/readline.m461
-rw-r--r--config/ac-macros/zlib.m4116
-rw-r--r--configure.in763
-rw-r--r--dbug/Makefile.am61
-rw-r--r--dbug/dbug.c38
-rw-r--r--dbug/dbug_analyze.c28
-rw-r--r--dbug/dbug_long.h1
-rw-r--r--dbug/example1.c3
-rw-r--r--dbug/example2.c3
-rw-r--r--dbug/example3.c3
-rw-r--r--dbug/main.c39
-rw-r--r--dbug/monty.doc2
-rw-r--r--dbug/my_main.c39
-rw-r--r--dbug/user.r250
-rw-r--r--extra/Makefile.am24
-rw-r--r--extra/charset2html.c (renamed from mysys/charset2html.c)0
-rw-r--r--extra/comp_err.c1065
-rw-r--r--extra/perror.c3
-rw-r--r--heap/Makefile.am2
-rw-r--r--heap/_check.c4
-rw-r--r--heap/heapdef.h4
-rw-r--r--heap/hp_create.c35
-rw-r--r--heap/hp_delete.c6
-rw-r--r--heap/hp_hash.c239
-rw-r--r--heap/hp_open.c4
-rw-r--r--heap/hp_rkey.c4
-rw-r--r--heap/hp_rrnd.c8
-rw-r--r--heap/hp_update.c4
-rw-r--r--heap/hp_write.c6
-rw-r--r--include/Makefile.am17
-rw-r--r--include/config-netware.h1
-rw-r--r--include/config-win.h9
-rw-r--r--include/decimal.h107
-rw-r--r--include/errmsg.h7
-rw-r--r--include/m_ctype.h18
-rw-r--r--include/merge.h93
-rw-r--r--include/my_base.h54
-rw-r--r--include/my_bitmap.h4
-rw-r--r--include/my_dbug.h4
-rw-r--r--include/my_global.h46
-rw-r--r--include/my_handler.h34
-rw-r--r--include/my_net.h5
-rw-r--r--include/my_pthread.h18
-rw-r--r--include/my_sys.h96
-rw-r--r--include/my_time.h17
-rw-r--r--include/myisam.h7
-rw-r--r--include/mysql.h106
-rw-r--r--include/mysql_com.h50
-rw-r--r--include/mysql_embed.h1
-rw-r--r--include/mysqld_error.h322
-rw-r--r--include/mysys_err.h17
-rw-r--r--include/nisam.h212
-rw-r--r--include/queues.h1
-rw-r--r--include/sql_state.h164
-rw-r--r--include/violite.h20
-rw-r--r--innobase/btr/btr0btr.c513
-rw-r--r--innobase/btr/btr0cur.c591
-rw-r--r--innobase/btr/btr0pcur.c51
-rw-r--r--innobase/btr/btr0sea.c255
-rw-r--r--innobase/buf/buf0buf.c83
-rw-r--r--innobase/buf/buf0flu.c13
-rw-r--r--innobase/buf/buf0lru.c1
-rw-r--r--innobase/buf/buf0rea.c7
-rw-r--r--innobase/data/data0data.c13
-rw-r--r--innobase/data/data0type.c62
-rw-r--r--innobase/dict/dict0boot.c52
-rw-r--r--innobase/dict/dict0crea.c175
-rw-r--r--innobase/dict/dict0dict.c166
-rw-r--r--innobase/dict/dict0load.c172
-rw-r--r--innobase/dict/dict0mem.c9
-rw-r--r--innobase/fil/fil0fil.c58
-rw-r--r--innobase/fsp/fsp0fsp.c2
-rw-r--r--innobase/ibuf/ibuf0ibuf.c414
-rw-r--r--innobase/include/Makefile.am2
-rw-r--r--innobase/include/btr0btr.h22
-rw-r--r--innobase/include/btr0btr.ic9
-rw-r--r--innobase/include/btr0cur.h60
-rw-r--r--innobase/include/btr0cur.ic4
-rw-r--r--innobase/include/btr0pcur.h1
-rw-r--r--innobase/include/btr0sea.h10
-rw-r--r--innobase/include/buf0buf.h12
-rw-r--r--innobase/include/buf0flu.ic2
-rw-r--r--innobase/include/data0type.h109
-rw-r--r--innobase/include/data0type.ic248
-rw-r--r--innobase/include/dict0boot.h1
-rw-r--r--innobase/include/dict0crea.h15
-rw-r--r--innobase/include/dict0dict.h32
-rw-r--r--innobase/include/dict0dict.ic71
-rw-r--r--innobase/include/dict0mem.h13
-rw-r--r--innobase/include/fil0fil.h2
-rw-r--r--innobase/include/lock0lock.h43
-rw-r--r--innobase/include/lock0lock.ic5
-rw-r--r--innobase/include/mtr0log.h33
-rw-r--r--innobase/include/mtr0mtr.h26
-rw-r--r--innobase/include/os0file.h3
-rw-r--r--innobase/include/os0proc.h28
-rw-r--r--innobase/include/page0cur.h64
-rw-r--r--innobase/include/page0cur.ic21
-rw-r--r--innobase/include/page0page.h211
-rw-r--r--innobase/include/page0page.ic144
-rw-r--r--innobase/include/que0que.h7
-rw-r--r--innobase/include/rem0cmp.h24
-rw-r--r--innobase/include/rem0cmp.ic5
-rw-r--r--innobase/include/rem0rec.h455
-rw-r--r--innobase/include/rem0rec.ic1054
-rw-r--r--innobase/include/row0mysql.h129
-rw-r--r--innobase/include/row0mysql.ic119
-rw-r--r--innobase/include/row0row.h30
-rw-r--r--innobase/include/row0row.ic49
-rw-r--r--innobase/include/row0upd.h17
-rw-r--r--innobase/include/row0upd.ic6
-rw-r--r--innobase/include/row0vers.h7
-rw-r--r--innobase/include/row0vers.ic70
-rw-r--r--innobase/include/srv0srv.h136
-rw-r--r--innobase/include/srv0start.h10
-rw-r--r--innobase/include/sync0rw.h7
-rw-r--r--innobase/include/sync0sync.h30
-rw-r--r--innobase/include/sync0sync.ic8
-rw-r--r--innobase/include/trx0rec.h1
-rw-r--r--innobase/include/trx0roll.h32
-rw-r--r--innobase/include/trx0sys.ic7
-rw-r--r--innobase/include/trx0trx.h53
-rw-r--r--innobase/include/trx0undo.h48
-rw-r--r--innobase/include/trx0xa.h182
-rw-r--r--innobase/include/univ.i1
-rw-r--r--innobase/include/ut0byte.h15
-rw-r--r--innobase/include/ut0byte.ic21
-rw-r--r--innobase/include/ut0ut.h8
-rw-r--r--innobase/lock/lock0lock.c436
-rw-r--r--innobase/log/log0log.c90
-rw-r--r--innobase/log/log0recv.c200
-rw-r--r--innobase/mtr/mtr0log.c158
-rw-r--r--innobase/os/os0file.c37
-rw-r--r--innobase/os/os0proc.c87
-rw-r--r--innobase/os/os0thread.c2
-rw-r--r--innobase/page/page0cur.c460
-rw-r--r--innobase/page/page0page.c589
-rw-r--r--innobase/pars/pars0pars.c7
-rw-r--r--innobase/pars/pars0sym.c2
-rw-r--r--innobase/que/que0que.c1
-rw-r--r--innobase/read/read0read.c7
-rw-r--r--innobase/rem/rem0cmp.c115
-rw-r--r--innobase/rem/rem0rec.c1031
-rw-r--r--innobase/row/row0ins.c248
-rw-r--r--innobase/row/row0mysql.c654
-rw-r--r--innobase/row/row0purge.c17
-rw-r--r--innobase/row/row0row.c120
-rw-r--r--innobase/row/row0sel.c769
-rw-r--r--innobase/row/row0umod.c2
-rw-r--r--innobase/row/row0undo.c14
-rw-r--r--innobase/row/row0upd.c174
-rw-r--r--innobase/row/row0vers.c124
-rw-r--r--innobase/srv/srv0srv.c242
-rw-r--r--innobase/srv/srv0start.c33
-rw-r--r--innobase/sync/sync0rw.c9
-rw-r--r--innobase/sync/sync0sync.c271
-rw-r--r--innobase/trx/trx0rec.c106
-rw-r--r--innobase/trx/trx0roll.c133
-rw-r--r--innobase/trx/trx0sys.c25
-rw-r--r--innobase/trx/trx0trx.c365
-rw-r--r--innobase/trx/trx0undo.c262
-rw-r--r--innobase/ut/ut0mem.c2
-rw-r--r--innobase/ut/ut0ut.c26
-rw-r--r--isam/.cvsignore10
-rw-r--r--isam/ChangeLog186
-rw-r--r--isam/Makefile.am45
-rw-r--r--isam/_cache.c92
-rw-r--r--isam/_dbug.c132
-rw-r--r--isam/_dynrec.c1247
-rw-r--r--isam/_key.c238
-rw-r--r--isam/_locking.c345
-rw-r--r--isam/_packrec.c1184
-rw-r--r--isam/_page.c143
-rw-r--r--isam/_search.c889
-rw-r--r--isam/_statrec.c265
-rw-r--r--isam/close.c92
-rw-r--r--isam/create.c329
-rw-r--r--isam/delete.c615
-rw-r--r--isam/extra.c271
-rw-r--r--isam/info.c77
-rw-r--r--isam/isamchk.c3424
-rw-r--r--isam/isamdef.h418
-rw-r--r--isam/isamlog.c853
-rw-r--r--isam/log.c156
-rwxr-xr-xisam/make-ccc3
-rw-r--r--isam/open.c477
-rw-r--r--isam/pack_isam.c2046
-rw-r--r--isam/panic.c135
-rw-r--r--isam/range.c191
-rw-r--r--isam/rfirst.c34
-rw-r--r--isam/rkey.c63
-rw-r--r--isam/rlast.c34
-rw-r--r--isam/rnext.c67
-rw-r--r--isam/rprev.c64
-rw-r--r--isam/rrnd.c55
-rw-r--r--isam/rsame.c70
-rw-r--r--isam/rsamepos.c59
-rw-r--r--isam/sort.c561
-rw-r--r--isam/static.c45
-rw-r--r--isam/test1.c179
-rw-r--r--isam/test2.c841
-rw-r--r--isam/test3.c494
-rwxr-xr-xisam/test_all30
-rw-r--r--isam/test_all.res30
-rw-r--r--isam/update.c117
-rw-r--r--isam/write.c840
-rw-r--r--libmysql/Makefile.am3
-rw-r--r--libmysql/Makefile.shared8
-rw-r--r--libmysql/client_settings.h6
-rw-r--r--libmysql/errmsg.c28
-rw-r--r--libmysql/libmysql.c815
-rw-r--r--libmysql/libmysql.def2
-rw-r--r--libmysql_r/Makefile.am5
-rw-r--r--libmysqld/Makefile.am12
-rw-r--r--libmysqld/examples/Makefile.am19
-rw-r--r--libmysqld/examples/builder-sample/emb_samples.cpp1
-rw-r--r--libmysqld/lib_sql.cc15
-rw-r--r--libmysqld/libmysqld.def6
-rw-r--r--[-rwxr-xr-x]libmysqld/libmysqld.rc0
-rw-r--r--[-rwxr-xr-x]libmysqld/resource.h0
-rw-r--r--man/Makefile.am4
-rw-r--r--man/isamchk.1.in145
-rw-r--r--man/isamlog.1.in107
-rw-r--r--merge/.cvsignore3
-rw-r--r--merge/Makefile.am25
-rwxr-xr-xmerge/make-ccc3
-rw-r--r--merge/mrg_close.c40
-rw-r--r--merge/mrg_create.c61
-rw-r--r--merge/mrg_extra.c46
-rw-r--r--merge/mrg_info.c60
-rw-r--r--merge/mrg_open.c150
-rw-r--r--merge/mrg_panic.c47
-rw-r--r--merge/mrg_rrnd.c110
-rw-r--r--merge/mrg_rsame.c36
-rw-r--r--merge/mrg_update.c31
-rw-r--r--myisam/Makefile.am2
-rw-r--r--myisam/ft_boolean_search.c92
-rw-r--r--myisam/ft_parser.c39
-rw-r--r--myisam/ft_static.c36
-rw-r--r--myisam/ft_stopwords.c2
-rw-r--r--myisam/ft_test1.c85
-rw-r--r--myisam/ft_update.c35
-rw-r--r--myisam/ftdefs.h3
-rw-r--r--myisam/mi_check.c7
-rw-r--r--myisam/mi_checksum.c8
-rw-r--r--myisam/mi_create.c97
-rw-r--r--myisam/mi_dbug.c16
-rw-r--r--myisam/mi_delete.c47
-rw-r--r--myisam/mi_dynrec.c75
-rw-r--r--myisam/mi_extra.c7
-rw-r--r--myisam/mi_info.c33
-rw-r--r--myisam/mi_key.c81
-rw-r--r--myisam/mi_keycache.c1
-rw-r--r--myisam/mi_locking.c6
-rw-r--r--myisam/mi_open.c52
-rw-r--r--myisam/mi_packrec.c38
-rw-r--r--myisam/mi_page.c2
-rw-r--r--myisam/mi_range.c19
-rw-r--r--myisam/mi_rkey.c1
-rw-r--r--myisam/mi_search.c33
-rw-r--r--myisam/mi_test1.c71
-rw-r--r--myisam/mi_test3.c1
-rw-r--r--myisam/mi_test_all.res73
-rw-r--r--myisam/mi_unique.c74
-rw-r--r--myisam/mi_update.c9
-rw-r--r--myisam/mi_write.c14
-rw-r--r--myisam/myisamchk.c8
-rw-r--r--myisam/myisamdef.h5
-rw-r--r--myisam/myisampack.c19
-rw-r--r--myisam/sort.c3
-rw-r--r--myisammrg/Makefile.am2
-rw-r--r--myisammrg/myrg_static.c2
-rw-r--r--mysql-test/Makefile.am10
-rwxr-xr-xmysql-test/create-test-result4
-rw-r--r--mysql-test/include/big_test.inc4
-rw-r--r--mysql-test/include/have_cp932.inc4
-rw-r--r--mysql-test/include/have_eucjpms.inc4
-rw-r--r--mysql-test/include/have_federated_db.inc4
-rw-r--r--mysql-test/include/have_isam.inc4
-rw-r--r--mysql-test/include/have_ndb.inc4
-rw-r--r--mysql-test/include/ndb_default_cluster.inc4
-rw-r--r--mysql-test/include/ps_conv.inc2
-rw-r--r--mysql-test/include/ps_create.inc2
-rw-r--r--mysql-test/include/ps_modify.inc1
-rw-r--r--mysql-test/include/system_db_struct.inc2
-rw-r--r--mysql-test/include/testdb_only.inc30
-rw-r--r--mysql-test/include/varchar.inc238
-rw-r--r--mysql-test/lib/init_db.sql104
-rwxr-xr-xmysql-test/mysql-test-run.pl3
-rw-r--r--mysql-test/mysql-test-run.sh167
-rw-r--r--mysql-test/mysql_test_run_new.c32
-rw-r--r--mysql-test/ndb/Makefile.am1
-rw-r--r--mysql-test/ndb/basic.result10
-rw-r--r--mysql-test/ndb/ndb_config_2_node.ini4
-rw-r--r--mysql-test/ndb/ndb_range_bounds.pl190
-rw-r--r--mysql-test/ndb/ndbcluster.sh4
-rw-r--r--mysql-test/ndb/restart.test2
-rw-r--r--mysql-test/r/alter_table.result10
-rw-r--r--mysql-test/r/analyse.result43
-rw-r--r--mysql-test/r/ansi.result2
-rw-r--r--mysql-test/r/archive.result2441
-rw-r--r--mysql-test/r/auto_increment.result6
-rw-r--r--mysql-test/r/backup.result6
-rw-r--r--mysql-test/r/bdb.result614
-rw-r--r--mysql-test/r/bench_count_distinct.result2
-rw-r--r--mysql-test/r/bigint.result23
-rw-r--r--mysql-test/r/binlog.result135
-rw-r--r--mysql-test/r/blackhole.result2
-rw-r--r--mysql-test/r/bool.result18
-rw-r--r--mysql-test/r/case.result42
-rw-r--r--mysql-test/r/cast.result116
-rw-r--r--mysql-test/r/client_xml.result74
-rw-r--r--mysql-test/r/connect.result6
-rw-r--r--mysql-test/r/count_distinct.result7
-rw-r--r--mysql-test/r/count_distinct2.result2
-rw-r--r--mysql-test/r/create.result90
-rw-r--r--mysql-test/r/ctype_collate.result4
-rwxr-xr-xmysql-test/r/ctype_cp932.result11337
-rwxr-xr-xmysql-test/r/ctype_eucjpms.result9807
-rw-r--r--mysql-test/r/ctype_latin1_de.result4
-rw-r--r--mysql-test/r/ctype_many.result22
-rw-r--r--mysql-test/r/ctype_mb.result8
-rw-r--r--mysql-test/r/ctype_recoding.result12
-rw-r--r--mysql-test/r/ctype_tis620.result68
-rw-r--r--mysql-test/r/ctype_ucs.result36
-rw-r--r--mysql-test/r/ctype_ucs_binlog.result15
-rw-r--r--mysql-test/r/ctype_ujis.result2
-rw-r--r--mysql-test/r/ctype_utf8.result24
-rw-r--r--mysql-test/r/date_formats.result39
-rw-r--r--mysql-test/r/delayed.result3
-rw-r--r--mysql-test/r/derived.result9
-rw-r--r--mysql-test/r/distinct.result10
-rw-r--r--mysql-test/r/drop.result2
-rw-r--r--mysql-test/r/drop_temp_table.result5
-rw-r--r--mysql-test/r/endspace.result44
-rw-r--r--mysql-test/r/federated.result922
-rw-r--r--mysql-test/r/flush.result2
-rw-r--r--mysql-test/r/flush_block_commit.result15
-rw-r--r--mysql-test/r/flush_read_lock_kill.result9
-rw-r--r--mysql-test/r/fulltext.result9
-rw-r--r--mysql-test/r/func_concat.result6
-rw-r--r--mysql-test/r/func_default.result2
-rw-r--r--mysql-test/r/func_equal.result12
-rw-r--r--mysql-test/r/func_gconcat.result15
-rw-r--r--mysql-test/r/func_group.result203
-rw-r--r--mysql-test/r/func_if.result19
-rw-r--r--mysql-test/r/func_in.result2
-rw-r--r--mysql-test/r/func_like.result4
-rw-r--r--mysql-test/r/func_math.result10
-rw-r--r--mysql-test/r/func_misc.result2
-rw-r--r--mysql-test/r/func_op.result2
-rw-r--r--mysql-test/r/func_regexp.result2
-rw-r--r--mysql-test/r/func_sapdb.result49
-rw-r--r--mysql-test/r/func_set.result6
-rw-r--r--mysql-test/r/func_str.result99
-rw-r--r--mysql-test/r/func_system.result8
-rw-r--r--mysql-test/r/func_test.result18
-rw-r--r--mysql-test/r/func_time.result81
-rw-r--r--mysql-test/r/gis-rtree.result7
-rw-r--r--mysql-test/r/gis.result46
-rw-r--r--mysql-test/r/grant.result74
-rw-r--r--mysql-test/r/grant2.result196
-rw-r--r--mysql-test/r/grant3.result18
-rw-r--r--mysql-test/r/grant_cache.result16
-rw-r--r--mysql-test/r/greedy_optimizer.result657
-rw-r--r--mysql-test/r/group_by.result12
-rw-r--r--mysql-test/r/group_min_max.result1963
-rw-r--r--mysql-test/r/have_cp932.require2
-rw-r--r--mysql-test/r/have_eucjpms.require2
-rw-r--r--mysql-test/r/have_federated_db.require2
-rw-r--r--mysql-test/r/having.result204
-rw-r--r--mysql-test/r/heap.result443
-rw-r--r--mysql-test/r/heap_btree.result6
-rw-r--r--mysql-test/r/heap_hash.result26
-rw-r--r--mysql-test/r/help.result16
-rw-r--r--mysql-test/r/index_merge.result386
-rw-r--r--mysql-test/r/index_merge_bdb.result136
-rw-r--r--mysql-test/r/index_merge_innodb.result125
-rw-r--r--mysql-test/r/index_merge_innodb2.result136
-rw-r--r--mysql-test/r/index_merge_ror.result196
-rw-r--r--mysql-test/r/index_merge_ror_cpk.result120
-rw-r--r--mysql-test/r/information_schema.result728
-rw-r--r--mysql-test/r/information_schema_inno.result20
-rw-r--r--mysql-test/r/init_connect.result2
-rw-r--r--mysql-test/r/innodb-big.result34
-rw-r--r--mysql-test/r/innodb.result842
-rw-r--r--mysql-test/r/insert.result156
-rw-r--r--mysql-test/r/insert_select-binlog.result10
-rw-r--r--mysql-test/r/insert_select.result4
-rw-r--r--mysql-test/r/insert_update.result4
-rw-r--r--mysql-test/r/isam.result12
-rw-r--r--mysql-test/r/join_nested.result1323
-rw-r--r--mysql-test/r/join_outer.result112
-rw-r--r--mysql-test/r/key.result14
-rw-r--r--mysql-test/r/key_cache.result2
-rw-r--r--mysql-test/r/keywords.result16
-rw-r--r--mysql-test/r/kill.result12
-rw-r--r--mysql-test/r/limit.result2
-rw-r--r--mysql-test/r/loaddata.result62
-rw-r--r--mysql-test/r/lock.result2
-rw-r--r--mysql-test/r/lowercase_table.result1
-rw-r--r--mysql-test/r/lowercase_table3.result2
-rw-r--r--mysql-test/r/lowercase_table_grant.result8
-rw-r--r--mysql-test/r/lowercase_view.result133
-rw-r--r--mysql-test/r/merge.result46
-rw-r--r--mysql-test/r/metadata.result6
-rw-r--r--mysql-test/r/mix_innodb_myisam_binlog.result145
-rw-r--r--mysql-test/r/multi_update.result44
-rw-r--r--mysql-test/r/myisam.result642
-rw-r--r--mysql-test/r/mysqlbinlog.result94
-rw-r--r--mysql-test/r/mysqlbinlog2.result201
-rw-r--r--mysql-test/r/mysqldump.result83
-rw-r--r--mysql-test/r/mysqlshow.result76
-rw-r--r--mysql-test/r/ndb_alter_table.result8
-rw-r--r--mysql-test/r/ndb_autodiscover.result39
-rw-r--r--mysql-test/r/ndb_basic.result2
-rw-r--r--mysql-test/r/ndb_bitfield.result152
-rw-r--r--mysql-test/r/ndb_blob.result2
-rw-r--r--mysql-test/r/ndb_cache.result182
-rw-r--r--mysql-test/r/ndb_cache2.result623
-rw-r--r--mysql-test/r/ndb_cache_multi.result72
-rw-r--r--mysql-test/r/ndb_cache_multi2.result82
-rw-r--r--mysql-test/r/ndb_charset.result117
-rw-r--r--mysql-test/r/ndb_condition_pushdown.result1143
-rw-r--r--mysql-test/r/ndb_default_cluster.require2
-rw-r--r--mysql-test/r/ndb_grant.result38
-rw-r--r--mysql-test/r/ndb_index_ordered.result109
-rw-r--r--mysql-test/r/ndb_index_unique.result10
-rw-r--r--mysql-test/r/ndb_read_multi_range.result265
-rw-r--r--mysql-test/r/ndb_types.result29
-rw-r--r--mysql-test/r/negation_elimination.result2
-rw-r--r--mysql-test/r/null.result43
-rw-r--r--mysql-test/r/null_key.result13
-rw-r--r--mysql-test/r/odbc.result2
-rw-r--r--mysql-test/r/olap.result119
-rw-r--r--mysql-test/r/openssl_1.result8
-rw-r--r--mysql-test/r/order_by.result25
-rw-r--r--mysql-test/r/preload.result5
-rw-r--r--mysql-test/r/ps.result92
-rw-r--r--mysql-test/r/ps_1general.result70
-rw-r--r--mysql-test/r/ps_2myisam.result711
-rw-r--r--mysql-test/r/ps_3innodb.result711
-rw-r--r--mysql-test/r/ps_4heap.result717
-rw-r--r--mysql-test/r/ps_5merge.result1410
-rw-r--r--mysql-test/r/ps_6bdb.result711
-rw-r--r--mysql-test/r/ps_7ndb.result711
-rw-r--r--mysql-test/r/ps_grant.result18
-rw-r--r--mysql-test/r/query_cache.result38
-rw-r--r--mysql-test/r/range.result70
-rw-r--r--mysql-test/r/repair.result6
-rw-r--r--mysql-test/r/replace.result4
-rw-r--r--mysql-test/r/row.result11
-rw-r--r--mysql-test/r/rowid_order_bdb.result186
-rw-r--r--mysql-test/r/rowid_order_innodb.result186
-rw-r--r--mysql-test/r/rpl000001.result23
-rw-r--r--mysql-test/r/rpl000009.result3
-rw-r--r--mysql-test/r/rpl000015.result8
-rw-r--r--mysql-test/r/rpl_EE_error.result4
-rw-r--r--mysql-test/r/rpl_auto_increment.result185
-rw-r--r--mysql-test/r/rpl_change_master.result18
-rw-r--r--mysql-test/r/rpl_charset.result182
-rw-r--r--mysql-test/r/rpl_create_database.result32
-rw-r--r--mysql-test/r/rpl_deadlock.result16
-rw-r--r--mysql-test/r/rpl_drop_temp.result1
-rw-r--r--mysql-test/r/rpl_error_ignored_table.result24
-rw-r--r--mysql-test/r/rpl_failed_optimize.result4
-rw-r--r--mysql-test/r/rpl_flush_log_loop.result2
-rw-r--r--mysql-test/r/rpl_flush_tables.result38
-rw-r--r--mysql-test/r/rpl_loaddata.result29
-rw-r--r--mysql-test/r/rpl_loaddata_rule_m.result10
-rw-r--r--mysql-test/r/rpl_loaddata_rule_s.result4
-rw-r--r--mysql-test/r/rpl_loaddatalocal.result17
-rw-r--r--mysql-test/r/rpl_log.result112
-rw-r--r--mysql-test/r/rpl_log_pos.result14
-rw-r--r--mysql-test/r/rpl_max_relay_size.result14
-rw-r--r--mysql-test/r/rpl_multi_query.result4
-rw-r--r--mysql-test/r/rpl_openssl.result4
-rw-r--r--mysql-test/r/rpl_relayrotate.result7
-rw-r--r--mysql-test/r/rpl_replicate_do.result2
-rw-r--r--mysql-test/r/rpl_reset_slave.result8
-rw-r--r--mysql-test/r/rpl_rewrite_db.result6
-rw-r--r--mysql-test/r/rpl_rotate_logs.result11
-rw-r--r--mysql-test/r/rpl_server_id1.result2
-rw-r--r--mysql-test/r/rpl_server_id2.result2
-rw-r--r--mysql-test/r/rpl_session_var.result43
-rw-r--r--mysql-test/r/rpl_temporary.result32
-rw-r--r--mysql-test/r/rpl_timezone.result81
-rw-r--r--mysql-test/r/rpl_trunc_binlog.result6
-rw-r--r--mysql-test/r/rpl_until.result34
-rw-r--r--mysql-test/r/rpl_user_variables.result59
-rw-r--r--mysql-test/r/rpl_view.result44
-rw-r--r--mysql-test/r/schema.result11
-rw-r--r--mysql-test/r/select.result140
-rw-r--r--mysql-test/r/select_found.result2
-rw-r--r--mysql-test/r/server_id.require (renamed from mysql-test/r/have_isam.require)2
-rw-r--r--mysql-test/r/server_id1.require2
-rw-r--r--mysql-test/r/show_check.result139
-rw-r--r--mysql-test/r/sp-error.result645
-rw-r--r--mysql-test/r/sp-security.result196
-rw-r--r--mysql-test/r/sp-threads.result42
-rw-r--r--mysql-test/r/sp.result3044
-rw-r--r--mysql-test/r/sp_trans.result22
-rw-r--r--mysql-test/r/sql_mode.result279
-rw-r--r--mysql-test/r/strict.result1234
-rw-r--r--mysql-test/r/subselect.result216
-rw-r--r--mysql-test/r/subselect2.result12
-rw-r--r--mysql-test/r/sum_distinct-big.result108
-rw-r--r--mysql-test/r/sum_distinct.result97
-rw-r--r--mysql-test/r/symlink.result25
-rw-r--r--mysql-test/r/synchronization.result1
-rw-r--r--mysql-test/r/system_mysql_db.result56
-rw-r--r--mysql-test/r/temp_table.result28
-rw-r--r--mysql-test/r/testdb_only.require2
-rw-r--r--mysql-test/r/timezone2.result18
-rw-r--r--mysql-test/r/timezone_grant.result8
-rw-r--r--mysql-test/r/trigger.result208
-rw-r--r--mysql-test/r/type_bit.result439
-rw-r--r--mysql-test/r/type_bit_innodb.result404
-rw-r--r--mysql-test/r/type_blob.result41
-rw-r--r--mysql-test/r/type_date.result2
-rw-r--r--mysql-test/r/type_datetime.result16
-rw-r--r--mysql-test/r/type_decimal.result432
-rw-r--r--mysql-test/r/type_enum.result4
-rw-r--r--mysql-test/r/type_float.result34
-rw-r--r--mysql-test/r/type_newdecimal.result844
-rw-r--r--mysql-test/r/type_ranges.result196
-rw-r--r--mysql-test/r/type_set.result2
-rw-r--r--mysql-test/r/type_time.result6
-rw-r--r--mysql-test/r/type_timestamp.result4
-rw-r--r--mysql-test/r/type_uint.result4
-rw-r--r--mysql-test/r/type_varchar.result394
-rw-r--r--mysql-test/r/union.result51
-rw-r--r--mysql-test/r/user_limits.result96
-rw-r--r--mysql-test/r/user_var-binlog.result21
-rw-r--r--mysql-test/r/user_var.result52
-rw-r--r--mysql-test/r/varbinary.result2
-rw-r--r--mysql-test/r/variables.result61
-rw-r--r--mysql-test/r/view.result1714
-rw-r--r--mysql-test/r/view_grant.result304
-rw-r--r--mysql-test/r/view_query_cache.result126
-rw-r--r--mysql-test/r/view_skip_grants.result6
-rw-r--r--mysql-test/r/warnings.result30
-rw-r--r--mysql-test/r/xa.result45
-rw-r--r--mysql-test/std_data/loaddata5.dat3
-rw-r--r--mysql-test/std_data/rpl_timezone.dat2
-rw-r--r--mysql-test/std_data/trunc_binlog.000001bin119 -> 174 bytes
-rw-r--r--mysql-test/std_data/vchar.frmbin0 -> 8616 bytes
-rw-r--r--mysql-test/t/analyse.test8
-rw-r--r--mysql-test/t/archive.test31
-rw-r--r--mysql-test/t/backup.test5
-rw-r--r--mysql-test/t/bdb.test45
-rw-r--r--mysql-test/t/bigint.test10
-rw-r--r--mysql-test/t/binlog-master.opt1
-rw-r--r--mysql-test/t/binlog.test48
-rw-r--r--mysql-test/t/bool.test10
-rw-r--r--mysql-test/t/case.test5
-rw-r--r--mysql-test/t/cast.test26
-rw-r--r--mysql-test/t/client_xml.test21
-rw-r--r--mysql-test/t/connect.test2
-rw-r--r--mysql-test/t/count_distinct.test8
-rw-r--r--mysql-test/t/count_distinct2.test2
-rw-r--r--mysql-test/t/create.test23
-rw-r--r--mysql-test/t/ctype_cp932.test405
-rw-r--r--mysql-test/t/ctype_eucjpms.test353
-rw-r--r--mysql-test/t/ctype_latin1_de.test2
-rw-r--r--mysql-test/t/ctype_many.test6
-rw-r--r--mysql-test/t/ctype_ucs.test19
-rw-r--r--mysql-test/t/ctype_ucs_binlog.test2
-rw-r--r--mysql-test/t/date_formats.test1
-rw-r--r--mysql-test/t/delayed.test4
-rw-r--r--mysql-test/t/derived.test14
-rw-r--r--mysql-test/t/disabled.def12
-rw-r--r--mysql-test/t/distinct.test4
-rw-r--r--mysql-test/t/endspace.test8
-rw-r--r--mysql-test/t/federated.test880
-rw-r--r--mysql-test/t/flush.test2
-rw-r--r--mysql-test/t/flush_block_commit.test21
-rw-r--r--mysql-test/t/flush_read_lock_kill-master.opt1
-rw-r--r--mysql-test/t/flush_read_lock_kill.test49
-rw-r--r--mysql-test/t/fulltext.test2
-rw-r--r--mysql-test/t/func_compress.test2
-rw-r--r--mysql-test/t/func_concat.test6
-rw-r--r--mysql-test/t/func_equal.test4
-rw-r--r--mysql-test/t/func_gconcat.test9
-rw-r--r--mysql-test/t/func_group.test102
-rw-r--r--mysql-test/t/func_if.test5
-rw-r--r--mysql-test/t/func_math.test9
-rw-r--r--mysql-test/t/func_sapdb.test13
-rw-r--r--mysql-test/t/func_set.test2
-rw-r--r--mysql-test/t/func_str.test8
-rw-r--r--mysql-test/t/func_test.test9
-rw-r--r--mysql-test/t/func_time.test29
-rw-r--r--mysql-test/t/gis-rtree.test3
-rw-r--r--mysql-test/t/gis.test16
-rw-r--r--mysql-test/t/grant.test27
-rw-r--r--mysql-test/t/grant2.test194
-rw-r--r--mysql-test/t/grant3-master.opt1
-rw-r--r--mysql-test/t/grant3.test36
-rw-r--r--mysql-test/t/grant_cache.test14
-rw-r--r--mysql-test/t/greedy_optimizer.test313
-rw-r--r--mysql-test/t/group_min_max.test612
-rw-r--r--mysql-test/t/having.test199
-rw-r--r--mysql-test/t/heap.test242
-rw-r--r--mysql-test/t/heap_btree.test2
-rw-r--r--mysql-test/t/heap_hash.test2
-rw-r--r--mysql-test/t/index_merge.test328
-rw-r--r--mysql-test/t/index_merge_bdb.test52
-rw-r--r--mysql-test/t/index_merge_innodb.test122
-rw-r--r--mysql-test/t/index_merge_innodb2.test52
-rw-r--r--mysql-test/t/index_merge_ror.test250
-rw-r--r--mysql-test/t/index_merge_ror_cpk.test111
-rw-r--r--mysql-test/t/information_schema.test466
-rw-r--r--mysql-test/t/information_schema_inno.test19
-rw-r--r--mysql-test/t/init_connect.test2
-rw-r--r--mysql-test/t/innodb-big.test46
-rw-r--r--mysql-test/t/innodb.test144
-rw-r--r--mysql-test/t/insert.test42
-rw-r--r--mysql-test/t/insert_select.test2
-rw-r--r--mysql-test/t/isam.test247
-rw-r--r--mysql-test/t/join_nested.test754
-rw-r--r--mysql-test/t/join_outer.test67
-rw-r--r--mysql-test/t/key.test8
-rw-r--r--mysql-test/t/keywords.test8
-rw-r--r--mysql-test/t/kill.test19
-rw-r--r--mysql-test/t/limit.test2
-rw-r--r--mysql-test/t/loaddata.test45
-rw-r--r--mysql-test/t/lock.test2
-rw-r--r--mysql-test/t/lowercase_table.test1
-rw-r--r--mysql-test/t/lowercase_table3.test2
-rw-r--r--mysql-test/t/lowercase_view-master.opt1
-rw-r--r--mysql-test/t/lowercase_view.test140
-rw-r--r--mysql-test/t/merge.test6
-rw-r--r--mysql-test/t/mix_innodb_myisam_binlog.test47
-rw-r--r--mysql-test/t/multi_update.test76
-rw-r--r--mysql-test/t/myisam.test48
-rw-r--r--mysql-test/t/mysqlbinlog.test16
-rw-r--r--mysql-test/t/mysqlbinlog2.test16
-rw-r--r--mysql-test/t/mysqldump.test25
-rw-r--r--mysql-test/t/mysqlshow.test23
-rw-r--r--mysql-test/t/ndb_alter_table.test6
-rw-r--r--mysql-test/t/ndb_autodiscover.test45
-rw-r--r--mysql-test/t/ndb_basic.test2
-rw-r--r--mysql-test/t/ndb_bitfield.test62
-rw-r--r--mysql-test/t/ndb_cache.test108
-rw-r--r--mysql-test/t/ndb_cache2.test361
-rw-r--r--mysql-test/t/ndb_cache_multi.test65
-rw-r--r--mysql-test/t/ndb_cache_multi2.test82
-rw-r--r--mysql-test/t/ndb_charset.test80
-rw-r--r--mysql-test/t/ndb_condition_pushdown.test1049
-rw-r--r--mysql-test/t/ndb_grant.later13
-rw-r--r--mysql-test/t/ndb_index_ordered.test31
-rw-r--r--mysql-test/t/ndb_index_unique.test10
-rw-r--r--mysql-test/t/ndb_read_multi_range.test202
-rw-r--r--mysql-test/t/ndb_restore.test1
-rw-r--r--mysql-test/t/ndb_types.test21
-rw-r--r--mysql-test/t/null.test9
-rw-r--r--mysql-test/t/null_key.test2
-rw-r--r--mysql-test/t/olap.test7
-rw-r--r--mysql-test/t/openssl_1.test8
-rw-r--r--mysql-test/t/order_by.test7
-rw-r--r--mysql-test/t/ps.test91
-rw-r--r--mysql-test/t/ps_1general.test38
-rw-r--r--mysql-test/t/ps_4heap.test8
-rw-r--r--mysql-test/t/ps_5merge.test4
-rw-r--r--mysql-test/t/ps_grant.test13
-rw-r--r--mysql-test/t/query_cache.test34
-rw-r--r--mysql-test/t/range.test35
-rw-r--r--mysql-test/t/replace.test8
-rw-r--r--mysql-test/t/row.test4
-rw-r--r--mysql-test/t/rowid_order_bdb.test108
-rw-r--r--mysql-test/t/rowid_order_innodb.test108
-rw-r--r--mysql-test/t/rpl000001.test23
-rw-r--r--mysql-test/t/rpl000010-slave.opt2
-rw-r--r--mysql-test/t/rpl000015.test10
-rw-r--r--mysql-test/t/rpl000017.test2
-rw-r--r--mysql-test/t/rpl000018.test2
-rw-r--r--mysql-test/t/rpl_EE_error.test2
-rw-r--r--mysql-test/t/rpl_auto_increment-master.opt1
-rw-r--r--mysql-test/t/rpl_auto_increment.test104
-rw-r--r--mysql-test/t/rpl_change_master.test23
-rw-r--r--mysql-test/t/rpl_charset.test45
-rw-r--r--mysql-test/t/rpl_create_database.test1
-rw-r--r--mysql-test/t/rpl_deadlock.test4
-rw-r--r--mysql-test/t/rpl_drop_temp.test3
-rw-r--r--mysql-test/t/rpl_empty_master_crash.test2
-rw-r--r--mysql-test/t/rpl_error_ignored_table.test5
-rw-r--r--mysql-test/t/rpl_flush_log_loop.test2
-rw-r--r--mysql-test/t/rpl_flush_tables.test2
-rw-r--r--mysql-test/t/rpl_get_lock.test7
-rw-r--r--mysql-test/t/rpl_heap.test2
-rw-r--r--mysql-test/t/rpl_loaddata.test38
-rw-r--r--mysql-test/t/rpl_loaddata_rule_m.test6
-rw-r--r--mysql-test/t/rpl_loaddata_rule_s.test2
-rw-r--r--mysql-test/t/rpl_loaddatalocal.test24
-rw-r--r--mysql-test/t/rpl_log.test9
-rw-r--r--mysql-test/t/rpl_log_pos.test10
-rw-r--r--mysql-test/t/rpl_max_relay_size.test12
-rw-r--r--mysql-test/t/rpl_multi_query.test2
-rw-r--r--mysql-test/t/rpl_openssl.test4
-rw-r--r--mysql-test/t/rpl_redirect.test2
-rw-r--r--mysql-test/t/rpl_relayrotate-slave.opt3
-rw-r--r--mysql-test/t/rpl_relayrotate.test6
-rw-r--r--mysql-test/t/rpl_replicate_do.test2
-rw-r--r--mysql-test/t/rpl_reset_slave.test8
-rw-r--r--mysql-test/t/rpl_rotate_logs.test12
-rw-r--r--mysql-test/t/rpl_session_var.test42
-rw-r--r--mysql-test/t/rpl_temporary.test1
-rw-r--r--mysql-test/t/rpl_timezone-slave.opt2
-rw-r--r--mysql-test/t/rpl_timezone.test62
-rw-r--r--mysql-test/t/rpl_trunc_binlog.test22
-rw-r--r--mysql-test/t/rpl_until.test12
-rw-r--r--mysql-test/t/rpl_user_variables.test3
-rw-r--r--mysql-test/t/rpl_view.test44
-rw-r--r--mysql-test/t/schema.test8
-rw-r--r--mysql-test/t/select.test56
-rw-r--r--mysql-test/t/show_check.test38
-rw-r--r--mysql-test/t/sp-error.test907
-rw-r--r--mysql-test/t/sp-security.test306
-rw-r--r--mysql-test/t/sp-threads.test95
-rw-r--r--mysql-test/t/sp.test3740
-rw-r--r--mysql-test/t/sp_trans.test46
-rw-r--r--mysql-test/t/sql_mode.test105
-rw-r--r--mysql-test/t/strict.test1085
-rw-r--r--mysql-test/t/subselect.test83
-rw-r--r--mysql-test/t/sum_distinct-big.test67
-rw-r--r--mysql-test/t/sum_distinct.test95
-rw-r--r--mysql-test/t/symlink.test8
-rw-r--r--mysql-test/t/synchronization.test7
-rw-r--r--mysql-test/t/system_mysql_db.test5
-rw-r--r--mysql-test/t/system_mysql_db_fix.test10
-rw-r--r--mysql-test/t/temp_table.test15
-rw-r--r--mysql-test/t/timezone2.test2
-rw-r--r--mysql-test/t/timezone_grant.test4
-rw-r--r--mysql-test/t/trigger.test251
-rw-r--r--mysql-test/t/type_bit.test142
-rw-r--r--mysql-test/t/type_bit_innodb.test135
-rw-r--r--mysql-test/t/type_blob.test22
-rw-r--r--mysql-test/t/type_decimal.test108
-rw-r--r--mysql-test/t/type_newdecimal.test871
-rw-r--r--mysql-test/t/type_ranges.test14
-rw-r--r--mysql-test/t/type_timestamp.test2
-rw-r--r--mysql-test/t/type_varchar.test120
-rw-r--r--mysql-test/t/union.test36
-rw-r--r--mysql-test/t/user_limits.test169
-rw-r--r--mysql-test/t/user_var-binlog.test2
-rw-r--r--mysql-test/t/user_var.test30
-rw-r--r--mysql-test/t/variables.test35
-rw-r--r--mysql-test/t/view.test1535
-rw-r--r--mysql-test/t/view_grant.test403
-rw-r--r--mysql-test/t/view_query_cache.test87
-rw-r--r--mysql-test/t/view_skip_grants-master.opt1
-rw-r--r--mysql-test/t/view_skip_grants.test14
-rw-r--r--mysql-test/t/warnings.test6
-rw-r--r--mysql-test/t/xa.test58
-rw-r--r--mysql-test/valgrind.supp94
-rw-r--r--mysys/Makefile.am13
-rw-r--r--mysys/charset-def.c10
-rw-r--r--mysys/charset.c83
-rw-r--r--mysys/default.c356
-rw-r--r--mysys/errors.c10
-rw-r--r--mysys/hash.c2
-rw-r--r--mysys/list.c2
-rw-r--r--mysys/mf_getdate.c42
-rw-r--r--mysys/mf_iocache.c13
-rw-r--r--mysys/mf_iocache2.c7
-rw-r--r--mysys/mf_keycache.c10
-rw-r--r--mysys/my_alloc.c19
-rw-r--r--mysys/my_bit.c5
-rw-r--r--mysys/my_bitmap.c70
-rw-r--r--mysys/my_chsize.c10
-rw-r--r--mysys/my_error.c266
-rw-r--r--mysys/my_getopt.c3
-rw-r--r--mysys/my_handler.c25
-rw-r--r--mysys/my_largepage.c167
-rw-r--r--mysys/my_mmap.c91
-rw-r--r--mysys/my_open.c9
-rw-r--r--mysys/my_static.c8
-rw-r--r--mysys/my_sync.c32
-rw-r--r--mysys/ptr_cmp.c39
-rw-r--r--mysys/raid.cc14
-rw-r--r--mysys/thr_lock.c6
-rw-r--r--ndb/Makefile.am3
-rw-r--r--ndb/docs/Makefile.am36
-rw-r--r--ndb/docs/doxygen/Doxyfile.mgmapi15
-rw-r--r--ndb/docs/doxygen/Doxyfile.ndb26
-rw-r--r--ndb/docs/doxygen/Doxyfile.ndbapi16
-rw-r--r--ndb/docs/doxygen/Doxyfile.odbc14
-rw-r--r--ndb/docs/doxygen/Doxyfile.test14
-rwxr-xr-xndb/docs/doxygen/predoxy.pl2
-rw-r--r--ndb/examples/configurations/demos.tarbin40960 -> 0 bytes
-rw-r--r--ndb/examples/ndbapi_async_example/Makefile34
-rw-r--r--ndb/examples/ndbapi_example1/Makefile33
-rw-r--r--ndb/examples/ndbapi_example1/ndbapi_example1.cpp194
-rw-r--r--ndb/examples/ndbapi_example2/Makefile33
-rw-r--r--ndb/examples/ndbapi_example3/Makefile33
-rw-r--r--ndb/examples/ndbapi_example4/Makefile33
-rw-r--r--ndb/examples/ndbapi_example4/ndbapi_example4.cpp253
-rw-r--r--ndb/examples/ndbapi_example5/Makefile33
-rw-r--r--ndb/examples/ndbapi_scan_example/Makefile35
-rw-r--r--ndb/examples/select_all/Makefile33
-rw-r--r--ndb/examples/select_all/select_all.cpp259
-rw-r--r--ndb/include/Makefile.am11
-rw-r--r--ndb/include/debugger/EventLogger.hpp29
-rw-r--r--ndb/include/kernel/AttributeDescriptor.hpp86
-rw-r--r--ndb/include/kernel/AttributeHeader.hpp10
-rw-r--r--ndb/include/kernel/LogLevel.hpp4
-rw-r--r--ndb/include/kernel/ndb_limits.h9
-rw-r--r--ndb/include/kernel/signaldata/AccScan.hpp31
-rw-r--r--ndb/include/kernel/signaldata/CreateEvnt.hpp15
-rw-r--r--ndb/include/kernel/signaldata/CreateIndx.hpp3
-rw-r--r--ndb/include/kernel/signaldata/CreateTable.hpp1
-rw-r--r--ndb/include/kernel/signaldata/DictTabInfo.hpp220
-rw-r--r--ndb/include/kernel/signaldata/EventReport.hpp88
-rw-r--r--ndb/include/kernel/signaldata/ScanFrag.hpp19
-rw-r--r--ndb/include/kernel/signaldata/ScanTab.hpp54
-rw-r--r--ndb/include/kernel/signaldata/SignalData.hpp11
-rw-r--r--ndb/include/kernel/signaldata/SumaImpl.hpp2
-rw-r--r--ndb/include/kernel/signaldata/TcCommit.hpp4
-rw-r--r--ndb/include/kernel/signaldata/TcHbRep.hpp2
-rw-r--r--ndb/include/kernel/signaldata/TcIndx.hpp406
-rw-r--r--ndb/include/kernel/signaldata/TcKeyConf.hpp2
-rw-r--r--ndb/include/kernel/signaldata/TcKeyFailConf.hpp2
-rw-r--r--ndb/include/kernel/signaldata/TcKeyReq.hpp16
-rw-r--r--ndb/include/kernel/signaldata/TcRollbackRep.hpp2
-rwxr-xr-xndb/include/kernel/signaldata/TransIdAI.hpp2
-rw-r--r--ndb/include/kernel/signaldata/TupFrag.hpp15
-rw-r--r--ndb/include/kernel/signaldata/TuxBound.hpp6
-rw-r--r--ndb/include/kernel/trigger_definitions.h1
-rw-r--r--ndb/include/mgmapi/mgmapi.h893
-rw-r--r--ndb/include/mgmapi/mgmapi_config_parameters.h2
-rw-r--r--ndb/include/mgmapi/mgmapi_debug.h1
-rw-r--r--ndb/include/mgmapi/ndb_logevent.h618
-rw-r--r--ndb/include/mgmcommon/ConfigRetriever.hpp2
-rw-r--r--ndb/include/ndb_constants.h72
-rw-r--r--ndb/include/ndb_global.h.in33
-rw-r--r--ndb/include/ndb_types.h.in81
-rw-r--r--ndb/include/ndbapi/Ndb.hpp1529
-rw-r--r--ndb/include/ndbapi/NdbApi.hpp3
-rw-r--r--ndb/include/ndbapi/NdbBlob.hpp47
-rw-r--r--ndb/include/ndbapi/NdbDictionary.hpp917
-rw-r--r--ndb/include/ndbapi/NdbError.hpp11
-rw-r--r--ndb/include/ndbapi/NdbEventOperation.hpp144
-rw-r--r--ndb/include/ndbapi/NdbIndexOperation.hpp53
-rw-r--r--ndb/include/ndbapi/NdbIndexScanOperation.hpp64
-rw-r--r--ndb/include/ndbapi/NdbOperation.hpp219
-rw-r--r--ndb/include/ndbapi/NdbRecAttr.hpp41
-rw-r--r--ndb/include/ndbapi/NdbReceiver.hpp14
-rw-r--r--ndb/include/ndbapi/NdbResultSet.hpp162
-rw-r--r--ndb/include/ndbapi/NdbScanFilter.hpp73
-rw-r--r--ndb/include/ndbapi/NdbScanOperation.hpp192
-rw-r--r--ndb/include/ndbapi/NdbTransaction.hpp (renamed from ndb/include/ndbapi/NdbConnection.hpp)412
-rw-r--r--ndb/include/ndbapi/ndb_cluster_connection.hpp52
-rw-r--r--ndb/include/ndbapi/ndb_opt_defaults.h4
-rw-r--r--ndb/include/ndbapi/ndberror.h7
-rw-r--r--ndb/include/transporter/TransporterDefinitions.hpp98
-rw-r--r--ndb/include/transporter/TransporterRegistry.hpp46
-rw-r--r--ndb/include/util/Base64.hpp1
-rw-r--r--ndb/include/util/Bitmask.hpp57
-rw-r--r--ndb/include/util/NdbSqlUtil.hpp145
-rw-r--r--ndb/include/util/SocketClient.hpp6
-rw-r--r--ndb/include/util/SocketServer.hpp2
-rw-r--r--ndb/include/util/Vector.hpp8
-rw-r--r--ndb/include/util/md5_hash.hpp11
-rw-r--r--ndb/include/util/ndb_opts.h66
-rw-r--r--ndb/ndbapi-examples/Makefile (renamed from ndb/examples/Makefile)18
-rw-r--r--ndb/ndbapi-examples/mgmapi_logevent_example/Makefile23
-rw-r--r--ndb/ndbapi-examples/mgmapi_logevent_example/mgmapi_logevent.cpp140
-rw-r--r--ndb/ndbapi-examples/ndbapi_async_example/Makefile23
-rw-r--r--ndb/ndbapi-examples/ndbapi_async_example/ndbapi_async.cpp (renamed from ndb/examples/ndbapi_async_example/ndbapi_async.cpp)194
-rw-r--r--ndb/ndbapi-examples/ndbapi_async_example/readme.txt (renamed from ndb/examples/ndbapi_async_example/readme.txt)0
-rw-r--r--ndb/ndbapi-examples/ndbapi_async_example1/Makefile21
-rw-r--r--ndb/ndbapi-examples/ndbapi_async_example1/ndbapi_async1.cpp (renamed from ndb/examples/ndbapi_example2/ndbapi_example2.cpp)75
-rw-r--r--ndb/ndbapi-examples/ndbapi_event_example/Makefile23
-rw-r--r--ndb/ndbapi-examples/ndbapi_event_example/ndbapi_event.cpp (renamed from ndb/examples/ndbapi_example5/ndbapi_example5.cpp)210
-rw-r--r--ndb/ndbapi-examples/ndbapi_retries_example/Makefile21
-rw-r--r--ndb/ndbapi-examples/ndbapi_retries_example/ndbapi_retries.cpp (renamed from ndb/examples/ndbapi_example3/ndbapi_example3.cpp)107
-rw-r--r--ndb/ndbapi-examples/ndbapi_scan_example/Makefile23
-rw-r--r--ndb/ndbapi-examples/ndbapi_scan_example/ndbapi_scan.cpp (renamed from ndb/examples/ndbapi_scan_example/ndbapi_scan.cpp)587
-rw-r--r--ndb/ndbapi-examples/ndbapi_scan_example/readme.txt (renamed from ndb/examples/ndbapi_scan_example/readme.txt)0
-rw-r--r--ndb/ndbapi-examples/ndbapi_simple_example/Makefile23
-rw-r--r--ndb/ndbapi-examples/ndbapi_simple_example/ndbapi_simple.cpp278
-rw-r--r--ndb/ndbapi-examples/ndbapi_simple_index_example/Makefile23
-rw-r--r--ndb/ndbapi-examples/ndbapi_simple_index_example/ndbapi_simple_index.cpp254
-rw-r--r--ndb/src/Makefile.am2
-rw-r--r--ndb/src/common/debugger/EventLogger.cpp1962
-rw-r--r--ndb/src/common/debugger/signaldata/DictTabInfo.cpp24
-rw-r--r--ndb/src/common/debugger/signaldata/ScanTab.cpp11
-rw-r--r--ndb/src/common/debugger/signaldata/SignalDataPrint.cpp13
-rw-r--r--ndb/src/common/debugger/signaldata/SignalNames.cpp3
-rw-r--r--ndb/src/common/debugger/signaldata/SumaImpl.cpp76
-rw-r--r--ndb/src/common/debugger/signaldata/TcIndx.cpp85
-rw-r--r--ndb/src/common/debugger/signaldata/TcKeyReq.cpp5
-rw-r--r--ndb/src/common/mgmcommon/IPCConfig.cpp384
-rw-r--r--ndb/src/common/transporter/Makefile.am2
-rw-r--r--ndb/src/common/transporter/OSE_Transporter.cpp2
-rw-r--r--ndb/src/common/transporter/OSE_Transporter.hpp1
-rw-r--r--ndb/src/common/transporter/SCI_Transporter.cpp8
-rw-r--r--ndb/src/common/transporter/SCI_Transporter.hpp4
-rw-r--r--ndb/src/common/transporter/SHM_Transporter.cpp7
-rw-r--r--ndb/src/common/transporter/SHM_Transporter.hpp4
-rw-r--r--ndb/src/common/transporter/TCP_Transporter.cpp5
-rw-r--r--ndb/src/common/transporter/TCP_Transporter.hpp4
-rw-r--r--ndb/src/common/transporter/Transporter.cpp47
-rw-r--r--ndb/src/common/transporter/Transporter.hpp31
-rw-r--r--ndb/src/common/transporter/TransporterRegistry.cpp291
-rw-r--r--ndb/src/common/util/Base64.cpp13
-rw-r--r--ndb/src/common/util/Bitmask.cpp351
-rw-r--r--ndb/src/common/util/Makefile.am19
-rw-r--r--ndb/src/common/util/NdbSqlUtil.cpp1127
-rw-r--r--ndb/src/common/util/SocketServer.cpp38
-rw-r--r--ndb/src/common/util/md5_hash.cpp20
-rw-r--r--ndb/src/common/util/version.c3
-rw-r--r--ndb/src/cw/cpcd/main.cpp4
-rw-r--r--ndb/src/kernel/blocks/ERROR_codes.txt7
-rw-r--r--ndb/src/kernel/blocks/backup/Backup.cpp8
-rw-r--r--ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp17
-rw-r--r--ndb/src/kernel/blocks/dbacc/Dbacc.hpp165
-rw-r--r--ndb/src/kernel/blocks/dbacc/DbaccInit.cpp4
-rw-r--r--ndb/src/kernel/blocks/dbacc/DbaccMain.cpp2587
-rw-r--r--ndb/src/kernel/blocks/dbacc/Makefile.am2
-rw-r--r--ndb/src/kernel/blocks/dbdict/Dbdict.cpp189
-rw-r--r--ndb/src/kernel/blocks/dbdict/Dbdict.hpp7
-rw-r--r--ndb/src/kernel/blocks/dbdih/DbdihMain.cpp172
-rw-r--r--ndb/src/kernel/blocks/dblqh/Dblqh.hpp29
-rw-r--r--ndb/src/kernel/blocks/dblqh/DblqhInit.cpp2
-rw-r--r--ndb/src/kernel/blocks/dblqh/DblqhMain.cpp502
-rw-r--r--ndb/src/kernel/blocks/dbtc/Dbtc.hpp36
-rw-r--r--ndb/src/kernel/blocks/dbtc/DbtcMain.cpp403
-rw-r--r--ndb/src/kernel/blocks/dbtup/Dbtup.hpp30
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp2
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp117
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp26
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp53
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp357
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupSystemRestart.cpp2
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp6
-rw-r--r--ndb/src/kernel/blocks/dbtux/Dbtux.hpp15
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp44
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp6
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp23
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp5
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp12
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp2
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp240
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp124
-rw-r--r--ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp3
-rw-r--r--ndb/src/kernel/blocks/dbtux/Times.txt10
-rw-r--r--ndb/src/kernel/blocks/grep/Grep.cpp20
-rw-r--r--ndb/src/kernel/blocks/grep/Grep.hpp2
-rw-r--r--ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp16
-rw-r--r--ndb/src/kernel/blocks/qmgr/Qmgr.hpp2
-rw-r--r--ndb/src/kernel/blocks/qmgr/QmgrInit.cpp3
-rw-r--r--ndb/src/kernel/blocks/qmgr/QmgrMain.cpp34
-rw-r--r--ndb/src/kernel/blocks/suma/Suma.cpp142
-rw-r--r--ndb/src/kernel/blocks/suma/Suma.hpp2
-rw-r--r--ndb/src/kernel/main.cpp12
-rw-r--r--ndb/src/kernel/vm/Configuration.cpp19
-rw-r--r--ndb/src/kernel/vm/Configuration.hpp6
-rw-r--r--ndb/src/kernel/vm/FastScheduler.cpp2
-rw-r--r--ndb/src/kernel/vm/MetaData.hpp7
-rw-r--r--ndb/src/kernel/vm/SimulatedBlock.cpp4
-rw-r--r--ndb/src/kernel/vm/TransporterCallback.cpp8
-rw-r--r--ndb/src/kernel/vm/VMSignal.hpp10
-rw-r--r--ndb/src/mgmapi/LocalConfig.cpp57
-rw-r--r--ndb/src/mgmapi/Makefile.am2
-rw-r--r--ndb/src/mgmapi/mgmapi.cpp362
-rw-r--r--ndb/src/mgmapi/mgmapi_configuration.hpp16
-rw-r--r--ndb/src/mgmapi/mgmapi_internal.h77
-rw-r--r--ndb/src/mgmapi/ndb_logevent.cpp483
-rw-r--r--ndb/src/mgmapi/ndb_logevent.hpp (renamed from ndb/include/ndbapi/NdbCursorOperation.hpp)18
-rw-r--r--ndb/src/mgmclient/CommandInterpreter.cpp61
-rw-r--r--ndb/src/mgmclient/main.cpp13
-rw-r--r--ndb/src/mgmsrv/CommandInterpreter.cpp345
-rw-r--r--ndb/src/mgmsrv/CommandInterpreter.hpp92
-rw-r--r--ndb/src/mgmsrv/ConfigInfo.cpp73
-rw-r--r--ndb/src/mgmsrv/Makefile.am13
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.cpp254
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.hpp13
-rw-r--r--ndb/src/mgmsrv/Services.cpp139
-rw-r--r--ndb/src/mgmsrv/Services.hpp9
-rw-r--r--ndb/src/mgmsrv/main.cpp129
-rw-r--r--ndb/src/ndbapi/ClusterMgr.cpp27
-rw-r--r--ndb/src/ndbapi/DictCache.cpp2
-rw-r--r--ndb/src/ndbapi/Makefile.am5
-rw-r--r--ndb/src/ndbapi/Ndb.cpp180
-rw-r--r--ndb/src/ndbapi/NdbApiSignal.cpp2
-rw-r--r--ndb/src/ndbapi/NdbApiSignal.hpp2
-rw-r--r--ndb/src/ndbapi/NdbBlob.cpp71
-rw-r--r--ndb/src/ndbapi/NdbCursorOperation.cpp51
-rw-r--r--ndb/src/ndbapi/NdbDictionary.cpp161
-rw-r--r--ndb/src/ndbapi/NdbDictionaryImpl.cpp643
-rw-r--r--ndb/src/ndbapi/NdbDictionaryImpl.hpp63
-rw-r--r--ndb/src/ndbapi/NdbEventOperation.cpp20
-rw-r--r--ndb/src/ndbapi/NdbEventOperationImpl.cpp523
-rw-r--r--ndb/src/ndbapi/NdbEventOperationImpl.hpp31
-rw-r--r--ndb/src/ndbapi/NdbImpl.hpp6
-rw-r--r--ndb/src/ndbapi/NdbIndexOperation.cpp452
-rw-r--r--ndb/src/ndbapi/NdbOperation.cpp47
-rw-r--r--ndb/src/ndbapi/NdbOperationDefine.cpp108
-rw-r--r--ndb/src/ndbapi/NdbOperationExec.cpp27
-rw-r--r--ndb/src/ndbapi/NdbOperationInt.cpp86
-rw-r--r--ndb/src/ndbapi/NdbOperationSearch.cpp363
-rw-r--r--ndb/src/ndbapi/NdbPool.cpp6
-rw-r--r--ndb/src/ndbapi/NdbPoolImpl.cpp13
-rw-r--r--ndb/src/ndbapi/NdbPoolImpl.hpp8
-rw-r--r--ndb/src/ndbapi/NdbRecAttr.cpp78
-rw-r--r--ndb/src/ndbapi/NdbReceiver.cpp29
-rw-r--r--ndb/src/ndbapi/NdbResultSet.cpp103
-rw-r--r--ndb/src/ndbapi/NdbScanFilter.cpp266
-rw-r--r--ndb/src/ndbapi/NdbScanOperation.cpp358
-rw-r--r--ndb/src/ndbapi/NdbTransaction.cpp (renamed from ndb/src/ndbapi/NdbConnection.cpp)438
-rw-r--r--ndb/src/ndbapi/NdbTransactionScan.cpp (renamed from ndb/src/ndbapi/NdbConnectionScan.cpp)18
-rw-r--r--ndb/src/ndbapi/Ndberr.cpp13
-rw-r--r--ndb/src/ndbapi/Ndbif.cpp170
-rw-r--r--ndb/src/ndbapi/Ndbinit.cpp69
-rw-r--r--ndb/src/ndbapi/Ndblist.cpp44
-rw-r--r--ndb/src/ndbapi/TransporterFacade.cpp61
-rw-r--r--ndb/src/ndbapi/TransporterFacade.hpp13
-rw-r--r--ndb/src/ndbapi/ndb_cluster_connection.cpp139
-rw-r--r--ndb/src/ndbapi/ndb_cluster_connection_impl.hpp18
-rw-r--r--ndb/src/ndbapi/ndberror.c55
-rw-r--r--ndb/test/include/HugoCalculator.hpp9
-rw-r--r--ndb/test/include/HugoOperations.hpp19
-rw-r--r--ndb/test/include/HugoTransactions.hpp3
-rw-r--r--ndb/test/include/NDBT_Error.hpp6
-rw-r--r--ndb/test/include/NDBT_ResultRow.hpp7
-rw-r--r--ndb/test/include/NDBT_Tables.hpp6
-rw-r--r--ndb/test/include/NDBT_Test.hpp22
-rw-r--r--ndb/test/include/NdbSchemaOp.hpp51
-rw-r--r--ndb/test/include/UtilTransactions.hpp28
-rw-r--r--ndb/test/ndbapi/Makefile.am14
-rw-r--r--ndb/test/ndbapi/ScanFunctions.hpp23
-rw-r--r--ndb/test/ndbapi/ScanInterpretTest.hpp17
-rw-r--r--ndb/test/ndbapi/bank/Bank.cpp64
-rw-r--r--ndb/test/ndbapi/bank/Bank.hpp2
-rw-r--r--ndb/test/ndbapi/bank/BankLoad.cpp11
-rw-r--r--ndb/test/ndbapi/bank/bankCreator.cpp8
-rw-r--r--ndb/test/ndbapi/bank/bankMakeGL.cpp8
-rw-r--r--ndb/test/ndbapi/bank/bankSumAccounts.cpp8
-rw-r--r--ndb/test/ndbapi/bank/bankTimer.cpp8
-rw-r--r--ndb/test/ndbapi/bank/bankTransactionMaker.cpp8
-rw-r--r--ndb/test/ndbapi/bank/bankValidateAllGLs.cpp8
-rw-r--r--ndb/test/ndbapi/bank/testBank.cpp12
-rw-r--r--ndb/test/ndbapi/bench/userInterface.cpp6
-rw-r--r--ndb/test/ndbapi/bench/userInterface.h2
-rw-r--r--ndb/test/ndbapi/create_all_tabs.cpp7
-rw-r--r--ndb/test/ndbapi/create_tab.cpp8
-rw-r--r--ndb/test/ndbapi/drop_all_tabs.cpp8
-rw-r--r--ndb/test/ndbapi/flexAsynch.cpp16
-rw-r--r--ndb/test/ndbapi/flexBench.cpp15
-rw-r--r--ndb/test/ndbapi/flexHammer.cpp13
-rw-r--r--ndb/test/ndbapi/flexTT.cpp13
-rw-r--r--ndb/test/ndbapi/flex_bench_mysql.cpp2
-rw-r--r--ndb/test/ndbapi/slow_select.cpp28
-rw-r--r--ndb/test/ndbapi/testBackup.cpp16
-rw-r--r--ndb/test/ndbapi/testBitfield.cpp198
-rw-r--r--ndb/test/ndbapi/testBlobs.cpp34
-rw-r--r--ndb/test/ndbapi/testDataBuffers.cpp21
-rw-r--r--ndb/test/ndbapi/testDeadlock.cpp27
-rw-r--r--ndb/test/ndbapi/testDict.cpp43
-rw-r--r--ndb/test/ndbapi/testIndex.cpp19
-rw-r--r--ndb/test/ndbapi/testLcp.cpp12
-rw-r--r--ndb/test/ndbapi/testNdbApi.cpp69
-rw-r--r--ndb/test/ndbapi/testNodeRestart.cpp2
-rw-r--r--ndb/test/ndbapi/testOIBasic.cpp2665
-rw-r--r--ndb/test/ndbapi/testPartitioning.cpp430
-rw-r--r--ndb/test/ndbapi/testReadPerf.cpp32
-rw-r--r--ndb/test/ndbapi/testScan.cpp53
-rw-r--r--ndb/test/ndbapi/testScanPerf.cpp103
-rw-r--r--ndb/test/ndbapi/testTimeout.cpp60
-rw-r--r--ndb/test/ndbapi/test_event.cpp390
-rw-r--r--ndb/test/ndbapi/test_event_multi_table.cpp487
-rw-r--r--ndb/test/run-test/16node-tests.txt733
-rw-r--r--ndb/test/run-test/Makefile.am2
-rw-r--r--ndb/test/run-test/basic.txt2
-rw-r--r--ndb/test/run-test/daily-basic-tests.txt91
-rw-r--r--ndb/test/run-test/daily-devel-tests.txt31
-rw-r--r--ndb/test/src/HugoAsynchTransactions.cpp11
-rw-r--r--ndb/test/src/HugoCalculator.cpp298
-rw-r--r--ndb/test/src/HugoOperations.cpp313
-rw-r--r--ndb/test/src/HugoTransactions.cpp838
-rw-r--r--ndb/test/src/NDBT_ResultRow.cpp9
-rw-r--r--ndb/test/src/NDBT_Tables.cpp19
-rw-r--r--ndb/test/src/NDBT_Test.cpp50
-rw-r--r--ndb/test/src/NdbBackup.cpp2
-rw-r--r--ndb/test/src/NdbRestarts.cpp30
-rw-r--r--ndb/test/src/NdbSchemaOp.cpp3
-rw-r--r--ndb/test/src/UtilTransactions.cpp616
-rw-r--r--ndb/test/tools/Makefile.am3
-rw-r--r--ndb/test/tools/copy_tab.cpp9
-rw-r--r--ndb/test/tools/create_index.cpp7
-rw-r--r--ndb/test/tools/hugoFill.cpp7
-rw-r--r--ndb/test/tools/hugoLoad.cpp7
-rw-r--r--ndb/test/tools/hugoLockRecords.cpp7
-rw-r--r--ndb/test/tools/hugoPkDelete.cpp7
-rw-r--r--ndb/test/tools/hugoPkRead.cpp7
-rw-r--r--ndb/test/tools/hugoPkReadRecord.cpp7
-rw-r--r--ndb/test/tools/hugoPkUpdate.cpp7
-rw-r--r--ndb/test/tools/hugoScanRead.cpp10
-rw-r--r--ndb/test/tools/hugoScanUpdate.cpp7
-rw-r--r--ndb/test/tools/verify_index.cpp7
-rw-r--r--ndb/tools/delete_all.cpp47
-rw-r--r--ndb/tools/desc.cpp42
-rw-r--r--ndb/tools/drop_index.cpp31
-rw-r--r--ndb/tools/drop_tab.cpp31
-rw-r--r--ndb/tools/listTables.cpp24
-rw-r--r--ndb/tools/ndb_test_platform.cpp6
-rw-r--r--ndb/tools/restore/consumer.cpp2
-rw-r--r--ndb/tools/restore/consumer_restore.cpp34
-rw-r--r--ndb/tools/restore/consumer_restore.hpp4
-rw-r--r--ndb/tools/restore/consumer_restorem.cpp17
-rw-r--r--ndb/tools/restore/restore_main.cpp10
-rw-r--r--ndb/tools/select_all.cpp68
-rw-r--r--ndb/tools/select_count.cpp50
-rw-r--r--ndb/tools/waiter.cpp15
-rwxr-xr-xnetware/BUILD/compile-linux-tools2
-rwxr-xr-xnetware/BUILD/compile-netware-START2
-rwxr-xr-xnetware/BUILD/nwbootstrap4
-rw-r--r--netware/Makefile.am6
-rw-r--r--netware/my_manage.c4
-rw-r--r--netware/my_manage.h34
-rw-r--r--os2/ChangeLog.os23
-rw-r--r--os2/MySQL-Source.icc24
-rw-r--r--os2/MySQL-Sql.icc2
-rw-r--r--os2/MySQL-Util.icc12
-rw-r--r--regex/Makefile.am2
-rw-r--r--regex/engine.c2
-rw-r--r--regex/main.c2
-rw-r--r--regex/regerror.c6
-rw-r--r--scripts/Makefile.am2
-rw-r--r--scripts/fill_func_tables.sh8
-rw-r--r--scripts/make_binary_distribution.sh43
-rw-r--r--scripts/make_win_src_distribution.sh6
-rw-r--r--scripts/mysql_create_system_tables.sh123
-rw-r--r--scripts/mysql_fix_privilege_tables.sh47
-rw-r--r--scripts/mysql_fix_privilege_tables.sql202
-rw-r--r--scripts/mysql_install_db.sh2
-rw-r--r--scripts/mysql_tableinfo.sh32
-rw-r--r--scripts/mysqld_multi.sh68
-rw-r--r--scripts/mysqld_safe.sh54
-rw-r--r--server-tools/Makefile.am1
-rw-r--r--server-tools/instance-manager/Makefile.am93
-rw-r--r--server-tools/instance-manager/README11
-rw-r--r--server-tools/instance-manager/buffer.cc109
-rw-r--r--server-tools/instance-manager/buffer.h66
-rw-r--r--server-tools/instance-manager/command.cc (renamed from merge/mrg_static.c)25
-rw-r--r--server-tools/instance-manager/command.h47
-rw-r--r--server-tools/instance-manager/commands.cc410
-rw-r--r--server-tools/instance-manager/commands.h131
-rw-r--r--server-tools/instance-manager/factory.cc55
-rw-r--r--server-tools/instance-manager/factory.h45
-rw-r--r--server-tools/instance-manager/guardian.cc436
-rw-r--r--server-tools/instance-manager/guardian.h127
-rw-r--r--server-tools/instance-manager/instance.cc334
-rw-r--r--server-tools/instance-manager/instance.h66
-rw-r--r--server-tools/instance-manager/instance_map.cc273
-rw-r--r--server-tools/instance-manager/instance_map.h89
-rw-r--r--server-tools/instance-manager/instance_options.cc324
-rw-r--r--server-tools/instance-manager/instance_options.h90
-rw-r--r--server-tools/instance-manager/listener.cc340
-rw-r--r--server-tools/instance-manager/listener.h56
-rw-r--r--server-tools/instance-manager/log.cc169
-rw-r--r--server-tools/instance-manager/log.h81
-rw-r--r--server-tools/instance-manager/manager.cc231
-rw-r--r--server-tools/instance-manager/manager.h (renamed from merge/mrg_def.h)18
-rw-r--r--server-tools/instance-manager/messages.cc76
-rw-r--r--server-tools/instance-manager/messages.h (renamed from merge/mrg_delete.c)18
-rw-r--r--server-tools/instance-manager/mysql_connection.cc397
-rw-r--r--server-tools/instance-manager/mysql_connection.h54
-rw-r--r--server-tools/instance-manager/mysql_manager_error.h (renamed from merge/mrg_locking.c)26
-rw-r--r--server-tools/instance-manager/mysqlmanager.cc343
-rw-r--r--server-tools/instance-manager/options.cc238
-rw-r--r--server-tools/instance-manager/options.h50
-rw-r--r--server-tools/instance-manager/parse.cc184
-rw-r--r--server-tools/instance-manager/parse.h53
-rw-r--r--server-tools/instance-manager/parse_output.cc101
-rw-r--r--server-tools/instance-manager/parse_output.h (renamed from ndb/include/ndb_types.h)13
-rw-r--r--server-tools/instance-manager/priv.cc52
-rw-r--r--server-tools/instance-manager/priv.h77
-rw-r--r--server-tools/instance-manager/protocol.cc180
-rw-r--r--server-tools/instance-manager/protocol.h44
-rw-r--r--server-tools/instance-manager/thread_registry.cc209
-rw-r--r--server-tools/instance-manager/thread_registry.h116
-rw-r--r--server-tools/instance-manager/user_map.cc176
-rw-r--r--server-tools/instance-manager/user_map.h (renamed from isam/changed.c)43
-rw-r--r--sql-bench/limits/mysql-4.0.cfg557
-rw-r--r--sql-common/client.c65
-rw-r--r--sql-common/my_time.c233
-rw-r--r--sql/Makefile.am33
-rw-r--r--sql/derror.cc67
-rw-r--r--sql/examples/ha_archive.cc327
-rw-r--r--sql/examples/ha_archive.h48
-rw-r--r--sql/examples/ha_example.cc10
-rw-r--r--sql/examples/ha_tina.cc32
-rw-r--r--sql/field.cc3301
-rw-r--r--sql/field.h460
-rw-r--r--sql/field_conv.cc106
-rw-r--r--sql/filesort.cc274
-rw-r--r--sql/gen_lex_hash.cc24
-rw-r--r--sql/ha_berkeley.cc472
-rw-r--r--sql/ha_berkeley.h8
-rw-r--r--sql/ha_blackhole.cc9
-rw-r--r--sql/ha_federated.cc1927
-rw-r--r--sql/ha_federated.h188
-rw-r--r--sql/ha_heap.cc106
-rw-r--r--sql/ha_heap.h14
-rw-r--r--sql/ha_innodb.cc2319
-rw-r--r--sql/ha_innodb.h145
-rw-r--r--sql/ha_isam.cc402
-rw-r--r--sql/ha_isam.h79
-rw-r--r--sql/ha_isammrg.cc209
-rw-r--r--sql/ha_isammrg.h69
-rw-r--r--sql/ha_myisam.cc344
-rw-r--r--sql/ha_myisam.h4
-rw-r--r--sql/ha_myisammrg.cc97
-rw-r--r--sql/ha_ndbcluster.cc3917
-rw-r--r--sql/ha_ndbcluster.h480
-rw-r--r--sql/handler.cc1692
-rw-r--r--sql/handler.h444
-rw-r--r--sql/item.cc2891
-rw-r--r--sql/item.h832
-rw-r--r--sql/item_buff.cc38
-rw-r--r--sql/item_cmpfunc.cc966
-rw-r--r--sql/item_cmpfunc.h310
-rw-r--r--sql/item_create.cc36
-rw-r--r--sql/item_create.h4
-rw-r--r--sql/item_func.cc2043
-rw-r--r--sql/item_func.h499
-rw-r--r--sql/item_geofunc.cc19
-rw-r--r--sql/item_geofunc.h8
-rw-r--r--sql/item_row.cc20
-rw-r--r--sql/item_row.h8
-rw-r--r--sql/item_strfunc.cc142
-rw-r--r--sql/item_strfunc.h26
-rw-r--r--sql/item_subselect.cc344
-rw-r--r--sql/item_subselect.h32
-rw-r--r--sql/item_sum.cc2067
-rw-r--r--sql/item_sum.h427
-rw-r--r--sql/item_timefunc.cc304
-rw-r--r--sql/item_timefunc.h49
-rw-r--r--sql/item_uniq.cc6
-rw-r--r--sql/item_uniq.h7
-rw-r--r--sql/key.cc225
-rw-r--r--sql/lex.h98
-rw-r--r--sql/lock.cc126
-rw-r--r--sql/log.cc1820
-rw-r--r--sql/log_event.cc2466
-rw-r--r--sql/log_event.h1009
-rw-r--r--sql/my_decimal.cc237
-rw-r--r--sql/my_decimal.h334
-rw-r--r--sql/mysql_priv.h639
-rw-r--r--sql/mysqld.cc1165
-rw-r--r--sql/net_serv.cc30
-rw-r--r--sql/nt_servc.h5
-rw-r--r--sql/opt_range.cc6536
-rw-r--r--sql/opt_range.h641
-rw-r--r--sql/opt_sum.cc34
-rw-r--r--sql/parse_file.cc772
-rw-r--r--sql/parse_file.h69
-rw-r--r--sql/password.c4
-rw-r--r--sql/procedure.cc31
-rw-r--r--sql/procedure.h27
-rw-r--r--sql/protocol.cc207
-rw-r--r--sql/protocol.h20
-rw-r--r--sql/protocol_cursor.cc42
-rw-r--r--sql/records.cc53
-rw-r--r--sql/repl_failsafe.cc60
-rw-r--r--sql/repl_failsafe.h6
-rw-r--r--sql/set_var.cc323
-rw-r--r--sql/set_var.h41
-rw-r--r--sql/share/Makefile.am22
-rw-r--r--sql/share/charsets/Index.xml35
-rw-r--r--sql/share/czech/errmsg.txt333
-rw-r--r--sql/share/danish/errmsg.txt324
-rw-r--r--sql/share/dutch/errmsg.txt333
-rw-r--r--sql/share/english/errmsg.txt321
-rw-r--r--sql/share/errmsg.txt5348
-rw-r--r--sql/share/estonian/errmsg.txt326
-rw-r--r--sql/share/french/errmsg.txt321
-rw-r--r--sql/share/german/errmsg.txt334
-rw-r--r--sql/share/greek/errmsg.txt321
-rw-r--r--sql/share/hungarian/errmsg.txt326
-rw-r--r--sql/share/italian/errmsg.txt321
-rw-r--r--sql/share/japanese-sjis/errmsg.txt325
-rw-r--r--sql/share/japanese/errmsg.txt325
-rw-r--r--sql/share/korean/errmsg.txt321
-rw-r--r--sql/share/norwegian-ny/errmsg.txt323
-rw-r--r--sql/share/norwegian/errmsg.txt323
-rw-r--r--sql/share/polish/errmsg.txt326
-rw-r--r--sql/share/portuguese/errmsg.txt323
-rw-r--r--sql/share/romanian/errmsg.txt326
-rw-r--r--sql/share/russian/errmsg.txt326
-rw-r--r--sql/share/serbian/errmsg.txt314
-rw-r--r--sql/share/slovak/errmsg.txt329
-rw-r--r--sql/share/spanish/errmsg.txt325
-rw-r--r--sql/share/swedish/errmsg.txt321
-rw-r--r--sql/share/ukrainian/errmsg.txt327
-rw-r--r--sql/slave.cc1055
-rw-r--r--sql/slave.h55
-rw-r--r--sql/sp.cc1378
-rw-r--r--sql/sp.h106
-rw-r--r--sql/sp_cache.cc166
-rw-r--r--sql/sp_cache.h107
-rw-r--r--sql/sp_head.cc2351
-rw-r--r--sql/sp_head.h954
-rw-r--r--sql/sp_pcontext.cc334
-rw-r--r--sql/sp_pcontext.h308
-rw-r--r--sql/sp_rcontext.cc285
-rw-r--r--sql/sp_rcontext.h243
-rw-r--r--sql/spatial.cc2
-rw-r--r--sql/spatial.h2
-rw-r--r--sql/sql_acl.cc2842
-rw-r--r--sql/sql_acl.h108
-rw-r--r--sql/sql_analyse.cc213
-rw-r--r--sql/sql_analyse.h31
-rw-r--r--sql/sql_base.cc2212
-rw-r--r--sql/sql_cache.cc346
-rw-r--r--sql/sql_cache.h17
-rw-r--r--sql/sql_class.cc354
-rw-r--r--sql/sql_class.h596
-rw-r--r--sql/sql_db.cc285
-rw-r--r--sql/sql_delete.cc306
-rw-r--r--sql/sql_derived.cc279
-rw-r--r--sql/sql_do.cc6
-rw-r--r--sql/sql_error.cc68
-rw-r--r--sql/sql_error.h42
-rw-r--r--sql/sql_handler.cc215
-rw-r--r--sql/sql_help.cc124
-rw-r--r--sql/sql_insert.cc849
-rw-r--r--sql/sql_lex.cc779
-rw-r--r--sql/sql_lex.h290
-rw-r--r--sql/sql_list.h53
-rw-r--r--sql/sql_load.cc426
-rw-r--r--sql/sql_map.cc18
-rw-r--r--sql/sql_olap.cc4
-rw-r--r--sql/sql_parse.cc3466
-rw-r--r--sql/sql_prepare.cc874
-rw-r--r--sql/sql_rename.cc28
-rw-r--r--sql/sql_repl.cc556
-rw-r--r--sql/sql_repl.h26
-rw-r--r--sql/sql_select.cc5459
-rw-r--r--sql/sql_select.h131
-rw-r--r--sql/sql_show.cc3753
-rw-r--r--sql/sql_sort.h1
-rw-r--r--sql/sql_string.cc17
-rw-r--r--sql/sql_string.h39
-rw-r--r--sql/sql_table.cc1361
-rw-r--r--sql/sql_test.cc148
-rw-r--r--sql/sql_trigger.cc482
-rw-r--r--sql/sql_trigger.h78
-rw-r--r--sql/sql_udf.cc65
-rw-r--r--sql/sql_udf.h1
-rw-r--r--sql/sql_union.cc155
-rw-r--r--sql/sql_update.cc763
-rw-r--r--sql/sql_view.cc1136
-rw-r--r--sql/sql_view.h37
-rw-r--r--sql/sql_yacc.yy4973
-rw-r--r--sql/strfunc.cc6
-rw-r--r--sql/structs.h66
-rw-r--r--sql/table.cc1168
-rw-r--r--sql/table.h487
-rw-r--r--sql/time.cc212
-rw-r--r--sql/tztime.cc151
-rw-r--r--sql/tztime.h10
-rw-r--r--sql/udf_example.cc45
-rw-r--r--sql/uniques.cc477
-rw-r--r--sql/unireg.cc54
-rw-r--r--sql/unireg.h21
-rw-r--r--strings/Makefile.am30
-rw-r--r--strings/ctype-big5.c37
-rw-r--r--strings/ctype-bin.c23
-rw-r--r--strings/ctype-cp932.c5552
-rw-r--r--strings/ctype-czech.c20
-rw-r--r--strings/ctype-euc_kr.c1
-rw-r--r--strings/ctype-eucjpms.c8740
-rw-r--r--strings/ctype-gb2312.c1
-rw-r--r--strings/ctype-gbk.c28
-rw-r--r--strings/ctype-latin1.c18
-rw-r--r--strings/ctype-mb.c34
-rw-r--r--strings/ctype-simple.c52
-rw-r--r--strings/ctype-sjis.c32
-rw-r--r--strings/ctype-tis620.c30
-rw-r--r--strings/ctype-uca.c38
-rw-r--r--strings/ctype-ucs2.c48
-rw-r--r--strings/ctype-ujis.c1
-rw-r--r--strings/ctype-utf8.c70
-rw-r--r--strings/ctype-win1250ch.c19
-rw-r--r--strings/decimal.c2966
-rw-r--r--strings/llstr.c2
-rw-r--r--strings/my_strtoll10.c2
-rw-r--r--strings/my_vsnprintf.c27
-rw-r--r--strings/xml.c2
-rw-r--r--support-files/MySQL-shared-compat.spec.sh22
-rw-r--r--support-files/debian/gomi2
-rw-r--r--support-files/my-huge.cnf.sh4
-rw-r--r--support-files/my-innodb-heavy-4G.cnf.sh2
-rw-r--r--support-files/my-large.cnf.sh4
-rw-r--r--support-files/my-medium.cnf.sh4
-rw-r--r--support-files/my-small.cnf.sh2
-rw-r--r--support-files/mysql.server.sh130
-rw-r--r--support-files/mysql.spec.sh47
-rw-r--r--tests/Makefile.am10
-rw-r--r--tests/connect_test.c1
-rw-r--r--tests/deadlock_test.c1
-rw-r--r--tests/grant.pl4
-rw-r--r--tests/insert_test.c1
-rw-r--r--tests/list_test.c1
-rwxr-xr-xtests/mail_to_db.pl54
-rw-r--r--tests/mysql_client_test.c1569
-rwxr-xr-xtests/pmail.pl283
-rw-r--r--tests/select_test.c1
-rw-r--r--tests/showdb_test.c1
-rw-r--r--tests/ssl_test.c1
-rw-r--r--tests/thread_test.c1
-rw-r--r--tests/udf_test3
-rw-r--r--tests/udf_test.res24
-rw-r--r--tools/Makefile.am9
-rw-r--r--tools/mysqlmanager.c12
-rw-r--r--vio/test-sslserver.c7
-rw-r--r--vio/vio.c46
-rw-r--r--vio/viosocket.c60
-rw-r--r--vio/viossl.c21
-rw-r--r--vio/viosslfactories.c8
1527 files changed, 217568 insertions, 81442 deletions
diff --git a/.bzrignore b/.bzrignore
index c9f9f140366..cfe38741074 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -9,6 +9,7 @@
*.lo
*.o
*.reject
+*.so
*.spec
*/*_pure_*warnings
*/.pure
@@ -102,8 +103,10 @@ Makefile.in'
PENDING/*
TAGS
ac_available_languages_fragment
+acinclude.m4
aclocal.m4
analyse.test
+autom4te-2.53.cache/*
autom4te-2.53.cache/output.0
autom4te-2.53.cache/requests
autom4te-2.53.cache/traces.0
@@ -155,6 +158,7 @@ bdb/db/crdel_auto.c
bdb/db/db_auto.c
bdb/dbinc_auto/*.*
bdb/dbreg/dbreg_auto.c
+bdb/dist/autom4te-2.53.cache/*
bdb/dist/autom4te-2.53.cache/output.0
bdb/dist/autom4te-2.53.cache/requests
bdb/dist/autom4te-2.53.cache/traces.0
@@ -241,19 +245,24 @@ bdb/test/logtrack.list
bdb/txn/txn_auto.c
binary/*
bkpull.log
+bkpull.log*
bkpull.log.2
bkpull.log.3
bkpull.log.4
bkpull.log.5
bkpull.log.6
bkpush.log
+bkpush.log*
build.log
build_tags.sh
+client/decimal.c
client/insert_test
client/log_event.cc
client/log_event.h
client/mf_iocache.c
client/mf_iocache.cc
+client/my_decimal.cc
+client/my_decimal.h
client/mysql
client/mysqladmin
client/mysqladmin.c
@@ -282,23 +291,37 @@ config.status
configure
configure.lineno
core
+core.*
core.2430
db-*.*.*
+dbug/dbug_analyze
+dbug/example*.r
+dbug/factorial
+dbug/factorial.r
+dbug/main.r
+dbug/output*.r
+dbug/user.ps
dbug/user.t
depcomp
emacs.h
+extra/charset2html
extra/comp_err
+extra/created_include_files
extra/my_print_defaults
extra/mysql_install
extra/mysql_tzinfo_to_sql
extra/mysql_waitpid
+extra/mysqld_ername.h
+extra/mysqld_error.h
extra/perror
extra/replace
extra/resolve_stack_dump
extra/resolveip
+extra/sql_state.h
extra/tztime.cc
fcns.c
fcns.h
+gdbinit
gmon.out
hardcopy.0
heap/hp_test1
@@ -309,10 +332,14 @@ help.h
include/my_config.h
include/my_global.h
include/mysql_version.h
+include/mysqld_ername.h
+include/mysqld_error.h
include/readline
include/readline/*.h
include/readline/readline.h
+include/sql_state.h
include/widec.h
+innobase/autom4te-2.53.cache/*
innobase/autom4te-2.53.cache/output.0
innobase/autom4te-2.53.cache/requests
innobase/autom4te-2.53.cache/traces.0
@@ -355,6 +382,7 @@ libmysqld/derror.cc
libmysqld/discover.cc
libmysqld/errmsg.c
libmysqld/examples/client_test.c
+libmysqld/examples/client_test.cc
libmysqld/examples/completion_hash.cc
libmysqld/examples/completion_hash.h
libmysqld/examples/link_sources
@@ -378,6 +406,7 @@ libmysqld/gstream.cc
libmysqld/ha_archive.cc
libmysqld/ha_berkeley.cc
libmysqld/ha_example.cc
+libmysqld/ha_federated.cc
libmysqld/ha_heap.cc
libmysqld/ha_innobase.cc
libmysqld/ha_innodb.cc
@@ -410,6 +439,7 @@ libmysqld/log_event.cc
libmysqld/md5.c
libmysqld/mf_iocache.cc
libmysqld/mini_client.cc
+libmysqld/my_decimal.cc
libmysqld/my_time.c
libmysqld/net_pkg.cc
libmysqld/net_serv.cc
@@ -417,14 +447,21 @@ libmysqld/opt_ft.cc
libmysqld/opt_range.cc
libmysqld/opt_sum.cc
libmysqld/pack.c
+libmysqld/parse_file.cc
libmysqld/password.c
libmysqld/procedure.cc
libmysqld/protocol.cc
+libmysqld/protocol_cursor.cc
libmysqld/records.cc
libmysqld/repl_failsafe.cc
libmysqld/set_var.cc
libmysqld/simple-test
libmysqld/slave.cc
+libmysqld/sp.cc
+libmysqld/sp_cache.cc
+libmysqld/sp_head.cc
+libmysqld/sp_pcontext.cc
+libmysqld/sp_rcontext.cc
libmysqld/spatial.cc
libmysqld/sql_acl.cc
libmysqld/sql_analyse.cc
@@ -437,6 +474,7 @@ libmysqld/sql_db.cc
libmysqld/sql_delete.cc
libmysqld/sql_derived.cc
libmysqld/sql_do.cc
+libmysqld/sql_error.cc
libmysqld/sql_handler.cc
libmysqld/sql_help.cc
libmysqld/sql_insert.cc
@@ -447,6 +485,7 @@ libmysqld/sql_manager.cc
libmysqld/sql_map.cc
libmysqld/sql_olap.cc
libmysqld/sql_parse.cc
+libmysqld/sql_prepare.cc
libmysqld/sql_rename.cc
libmysqld/sql_repl.cc
libmysqld/sql_select.cc
@@ -455,10 +494,12 @@ libmysqld/sql_state.c
libmysqld/sql_string.cc
libmysqld/sql_table.cc
libmysqld/sql_test.cc
+libmysqld/sql_trigger.cc
libmysqld/sql_udf.cc
libmysqld/sql_union.cc
libmysqld/sql_unions.cc
libmysqld/sql_update.cc
+libmysqld/sql_view.cc
libmysqld/sql_yacc.cc
libmysqld/stacktrace.c
libmysqld/strfunc.cc
@@ -516,6 +557,7 @@ myisam/test2.MYI
mysql-4.0.2-alpha-pc-linux-gnu-i686.tar.gz
mysql-4.0.2-alpha.tar.gz
mysql-4.1.8-win-src.zip
+mysql-5.0.2-alpha.tar.gz
mysql-max-4.0.2-alpha-pc-linux-gnu-i686.tar.gz
mysql-test/gmon.out
mysql-test/install_test_db
@@ -538,6 +580,7 @@ mysql-test/r/ctype_ucs.err
mysql-test/r/derived.err
mysql-test/r/exampledb.err
mysql-test/r/func_encrypt.err
+mysql-test/r/index_merge_load.result
mysql-test/r/isam.err
mysql-test/r/lowercase_table2.err
mysql-test/r/multi_update.err
@@ -587,9 +630,11 @@ mysql-test/r/slave-running.eval
mysql-test/r/slave-stopped.eval
mysql-test/share/mysql
mysql-test/std_data/*.pem
+mysql-test/t/index_merge.load
mysql-test/var/*
mysql.kdevprj
mysql.proj
+mysql_priv.h
mysqld.S
mysqld.sym
mysys/#mf_iocache.c#
@@ -721,6 +766,7 @@ ndb/examples/ndbapi_example3/ndbapi_example3
ndb/examples/ndbapi_example5/ndbapi_example5
ndb/examples/select_all/select_all
ndb/include/ndb_global.h
+ndb/include/ndb_types.h
ndb/include/ndb_version.h
ndb/lib/libMGM_API.so
ndb/lib/libNDB_API.so
@@ -892,6 +938,11 @@ scripts/mysqldumpslow
scripts/mysqlhotcopy
scripts/safe_mysqld
select_test
+server-tools/instance-manager/client.c
+server-tools/instance-manager/client_settings.h
+server-tools/instance-manager/errmsg.c
+server-tools/instance-manager/mysqlmanager
+server-tools/instance-manager/thr_alarm.c
sql-bench/Results-linux/ATIS-mysql_bdb-Linux_2.2.14_my_SMP_i686
sql-bench/bench-count-distinct
sql-bench/bench-init.pl
@@ -956,7 +1007,9 @@ sql_prepare.cc
stamp-h
stamp-h.in
stamp-h1
+stamp-h1.in
stamp-h2
+stamp-h2.in
stamp-h3
stamp-h4
start_mysqld.sh
@@ -964,6 +1017,7 @@ strings/conf_to_src
strings/ctype_autoconf.c
strings/ctype_extra_sources.c
strings/str_test
+strings/test_decimal
support-files/MacOSX/Description.plist
support-files/MacOSX/Info.plist
support-files/MacOSX/ReadMe.txt
@@ -1052,3 +1106,7 @@ vio/test-ssl
vio/test-sslclient
vio/test-sslserver
vio/viotest-ssl
+VC++Files/client/mysql_amd64.dsp
+client/mysqltestmanager-pwgen
+client/mysqltestmanagerc
+tools/mysqltestmanager
diff --git a/BUILD/FINISH.sh b/BUILD/FINISH.sh
index 094eb8275d6..81defaa7f52 100644
--- a/BUILD/FINISH.sh
+++ b/BUILD/FINISH.sh
@@ -10,7 +10,7 @@ do
done
commands="\
-$make -k clean || true
+$make -k distclean || true
/bin/rm -rf */.deps/*.P config.cache innobase/config.cache bdb/build_unix/config.cache bdb/dist/autom4te.cache autom4te.cache innobase/autom4te.cache;
aclocal || (echo \"Can't execute aclocal\" && exit 1)
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index 8bb281f20e9..a507d30e518 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -48,8 +48,8 @@ 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-bdb --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid --with-vio"
-max_leave_isam_configs="--with-innodb --with-bdb --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid --with-vio --with-embedded-server"
+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"
@@ -57,7 +57,7 @@ path=`dirname $0`
. "$path/check-cpu"
alpha_cflags="$check_cpu_cflags -Wa,-m$cpu_flag"
-amd64_cflags="$check_cpu_cflags -DBIG_TABLES"
+amd64_cflags="$check_cpu_cflags"
pentium_cflags="$check_cpu_cflags"
pentium64_cflags="$check_cpu_cflags -m64"
ppc_cflags="$check_cpu_cflags"
@@ -73,9 +73,9 @@ debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMA
debug_extra_cflags="-O1 -Wuninitialized"
base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti"
-amd64_cxxflags="-DBIG_TABLES"
+amd64_cxxflags="" # If dropping '--with-big-tables', add here "-DBIG_TABLES"
-base_configs="$prefix_configs --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-readline"
+base_configs="$prefix_configs --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-readline --with-big-tables"
static_link="--with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static"
amd64_configs=""
alpha_configs="" # Not used yet
diff --git a/BUILD/compile-pentium-debug b/BUILD/compile-pentium-debug
index 4a9d0e74599..7957caead29 100755
--- a/BUILD/compile-pentium-debug
+++ b/BUILD/compile-pentium-debug
@@ -1,7 +1,7 @@
#! /bin/sh
path=`dirname $0`
-. "$path/SETUP.sh"
+. "$path/SETUP.sh" $@ --with-debug=full
extra_flags="$pentium_cflags $debug_cflags"
c_warnings="$c_warnings $debug_extra_warnings"
diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max
index 420657e0b73..7a11ad24c44 100755
--- a/BUILD/compile-pentium-debug-max
+++ b/BUILD/compile-pentium-debug-max
@@ -1,7 +1,7 @@
#! /bin/sh
path=`dirname $0`
-. "$path/SETUP.sh"
+. "$path/SETUP.sh" $@ --with-debug=full
extra_flags="$pentium_cflags $debug_cflags $max_cflags"
c_warnings="$c_warnings $debug_extra_warnings"
diff --git a/BUILD/compile-pentium64-valgrind-max b/BUILD/compile-pentium64-valgrind-max
new file mode 100644
index 00000000000..2e4ff8e0082
--- /dev/null
+++ b/BUILD/compile-pentium64-valgrind-max
@@ -0,0 +1,29 @@
+#! /bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="$pentium64_cflags $debug_cflags -USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify -DMYSQL_SERVER_SUFFIX=-valgrind-max"
+c_warnings="$c_warnings $debug_extra_warnings"
+cxx_warnings="$cxx_warnings $debug_extra_warnings"
+extra_configs="$pentium_configs $debug_configs"
+
+# We want to test isam when building with valgrind
+extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-isam --with-embedded-server --with-openssl --with-raid --with-ndbcluster"
+
+. "$path/FINISH.sh"
+
+if test -z "$just_print"
+then
+ set +v +x
+ echo "\
+******************************************************************************
+Note that by default BUILD/compile-pentium-valgrind-max calls 'configure' with
+--enable-assembler. When Valgrind detects an error involving an assembly
+function (for example an uninitialized value used as an argument of an
+assembly function), Valgrind will not print the stacktrace and 'valgrind
+--gdb-attach=yes' will not work either. If you need a stacktrace in those
+cases, you have to run BUILD/compile-pentium-valgrind-max with the
+--disable-assembler argument.
+******************************************************************************"
+fi
diff --git a/BUILD/compile-solaris-sparc-purify b/BUILD/compile-solaris-sparc-purify
index 5f5ba81396f..41ecd4ed530 100755
--- a/BUILD/compile-solaris-sparc-purify
+++ b/BUILD/compile-solaris-sparc-purify
@@ -15,19 +15,18 @@ do
--purecov*) mode=purecov ;;
--quantify) mode=quantify ;;
--cxxfilt) shift ; cxxfilt=$1 ;;
- -h | --help ) cat <<EOF; exit 0 ;;
-Usage: $0 [ options ]
-
-Where the 'options' are
-
- --debug Compile with DBUG enabled
- --purify Only prepare for Purify
- --purecov Only prepare for PureCover
- --quantify Only prepare for Quantify
- --cxxfilt <cxxfilt> Path to cxxfilt/c++filt program
- This program is needed for gcc 3.X
-EOF
- *) echo "No such option '$1'" ; exit 1 ;;
+ -h | --help )
+ echo "Usage: $0 [ options ]"
+ echo "Where the 'options' are"
+ echo " --help | -h Display this help"
+ echo " --debug Compile with DBUG enabled"
+ echo " --purify Only prepare for Purify"
+ echo " --purecov Only prepare for PureCover"
+ echo " --quantify Only prepare for Quantify"
+ echo " --cxxfilt <cxxfilt> Path to cxxfilt/c++filt program"
+ echo " This program is needed for gcc 3.X"
+ exit 0 ;;
+ *) echo "No such option '$1'" ; exit 1 ;;
esac
shift
done
@@ -38,7 +37,7 @@ aclocal && autoheader && aclocal && automake && autoconf
(cd bdb/dist && sh s_all)
(cd innobase && aclocal && autoheader && aclocal && automake && autoconf)
-CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-berkeley-db --with-innodb $EXTRA_CONFIG_FLAGS
+CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-berkeley-db --with-embedded-server --with-innodb $EXTRA_CONFIG_FLAGS
gmake -j 4
diff --git a/BitKeeper/etc/gone b/BitKeeper/etc/gone
index 63a759cf131..2b341c92a92 100644
--- a/BitKeeper/etc/gone
+++ b/BitKeeper/etc/gone
@@ -455,8 +455,444 @@ arjen@co3064164-a.bitbike.com|Docs/section.Comparisons.texi|20011108043647|22614
arjen@fred.bitbike.com|scripts/mysql_fix_extensions.sh|20020516001337|12363|f1048a78f4759b4d
ccarkner@nslinuxw10.bedford.progress.com|mysql-test/r/isolation.result|20010327145543|25059|4da11e109a3d93a9
ccarkner@nslinuxw10.bedford.progress.com|mysql-test/t/isolation.test|20010327145543|39049|6a39e4138dd4a456
+fs
jani@hynda.mysql.fi|client/mysqlcheck|20010419221207|26716|363e3278166d84ec
jcole@tetra.bedford.progress.com|BitKeeper/etc/logging_ok|20001004201211|30554
+jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aa
+jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aajimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6djimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27ajimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30jimw@mysql.com|mysql-test/t/ndb_alter_table.disabled|20050311230559|27526|411e026940e7a0aajimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6djimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27ajimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2
+jimw@mysql.com|mysql-test/t/ndb_autodiscover.disabled|20050311230559|58101|dda20d04dddbb06
+jimw@mysql.com|mysql-test/t/ndb_autodiscover2.disabled|20050311230559|22363|afa8e5b6e46a3ea1
+jimw@mysql.com|mysql-test/t/ndb_cache_multi.disabled|20050311230600|18039|9657b6eff7deb27a
+jimw@mysql.com|mysql-test/t/ndb_cache_multi2.disabled|20050311230600|47901|84fed1a78c0d3e6d
+jimw@mysql.com|mysql-test/t/ndb_multi.disabled|20050311230600|12240|2599367ad06100f6
+jimw@mysql.com|mysql-test/t/ndb_restore.disabled|20050311230600|30718|3c2453d6164b1a30
+korbit-kernel-2.4.1
+magnus@neptunus.(none)|ndb/src/client/Makefile|20040414084436|02010|6c2778d2bf4954a2
+magnus@neptunus.(none)|ndb/src/client/odbc/Extra.mk|20040414082358|47442|eabbb28986ca817d
+magnus@neptunus.(none)|ndb/src/client/odbc/Makefile|20040414084435|33394|9bc928a18aa88d66
+magnus@neptunus.(none)|ndb/src/client/odbc/NdbOdbc.cpp|20040414082358|49599|aa491b06c9172d11
+magnus@neptunus.(none)|ndb/src/client/odbc/NdbOdbc.def|20040414082358|51708|cd3eed2c4a0121e9
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/CodeGen.cpp|20040414082358|53823|170c83c0765b9160
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/CodeGen.hpp|20040414082358|56074|738f834f80cceba8
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_base.cpp|20040414082358|58196|96f8ceaac8138bfe
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_base.hpp|20040414082358|60340|794baaed32588409
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_column.cpp|20040414082358|62566|5dd0e5c1215bd8bf
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_column.hpp|20040414082358|64739|5d5816d1c496e588
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_comp_op.cpp|20040414082358|01507|6ab02cc3b1e08985
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_comp_op.hpp|20040414082358|03757|37cf1e4cee3a6bf1
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_index.cpp|20040414082358|06374|d1f95c5917afab9
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_index.hpp|20040414082358|08625|12bcb33350fc35c1
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_row.cpp|20040414082358|11036|33f73454f8ddf2d5
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_row.hpp|20040414082358|13441|38cb00cc1baa9ee7
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_table.cpp|20040414082358|15724|c25e7cc06414a927
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_create_table.hpp|20040414082358|18032|9648f467f3f0418e
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_data_type.cpp|20040414082358|20759|9e46a7ef85345d4
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_data_type.hpp|20040414082358|23055|5e8928968d3c0107
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl.cpp|20040414082358|25484|c38ee5368efaf688
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl.hpp|20040414082358|27775|75482ddd87b65036
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_column.cpp|20040414082358|32443|c524862773dd9f38
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_column.hpp|20040414082358|33650|c9e534e381b21599
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_constr.cpp|20040414082359|02893|80ae32f83a6c2f00
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_constr.hpp|20040414082359|05185|bca16806c57bc97e
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_row.cpp|20040414082359|07481|ec2fbc3b8ab08a52
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_ddl_row.hpp|20040414082359|09844|c18a43b3770ad25a
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete.cpp|20040414082359|12149|feac77b440d04327
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete.hpp|20040414082359|14544|c852ee069a761aab
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_index.cpp|20040414082359|17020|17ed96eca90fe4e7
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_index.hpp|20040414082359|19336|18a9bb119b04636
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_lookup.cpp|20040414082359|23008|1a3728f8c896684
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_lookup.hpp|20040414082359|26530|1be71525ed9ee69
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_scan.cpp|20040414082359|29062|b040ad7670c24eb5
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_delete_scan.hpp|20040414082359|31380|b9a11b4ec895d159
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml.cpp|20040414082359|33830|6826ad60f0f566e7
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml.hpp|20040414082359|36167|8fdbf19ad3174ca2
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml_column.cpp|20040414082359|38509|b71ce6186edf1655
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml_column.hpp|20040414082359|40901|a843b3418b30b7a3
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml_row.cpp|20040414082359|43239|17c791507b36cc06
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_dml_row.hpp|20040414082359|46942|33c4cffdd238728d
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_drop_index.cpp|20040414082359|54231|fc5cab67ae58d9f6
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_drop_index.hpp|20040414082359|55474|377c9eb280ec2ee2
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_drop_table.cpp|20040414082359|57899|9637d93efa68996a
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_drop_table.hpp|20040414082359|60249|d671379125e4bbbe
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr.cpp|20040414082359|64572|fafd271880c70cf3
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr.hpp|20040414082359|01410|9e8243e99e0ec84
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_column.cpp|20040414082359|03836|4c4fbcd5741cc8cf
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_column.hpp|20040414082359|06355|9c4cbbdf432dc475
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_const.cpp|20040414082359|08702|bdb29dcd94ac5e73
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_const.hpp|20040414082359|12473|9c8789cff376b832
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_conv.cpp|20040414082359|15160|d252fbfe8ef55fff
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_conv.hpp|20040414082359|18741|5cbea39eecb92a43
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_func.cpp|20040414082359|21099|5d3996f062fa3f52
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_func.hpp|20040414082359|23589|22aee1e4f92c49b9
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_op.cpp|20040414082359|25965|e1aaa0244f2efa4
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_op.hpp|20040414082359|28432|4eb8c02dd0602f
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_param.cpp|20040414082359|30810|a5e94ee7c5821611
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_param.hpp|20040414082359|33263|ec441ad8ef21aa2b
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_row.cpp|20040414082400|01179|bc73d8f9c681d418
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_expr_row.hpp|20040414082400|03567|c541c49ea8c0c4f2
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_idx_column.cpp|20040414082400|06012|7d4d074ce5daea0a
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_idx_column.hpp|20040414082400|08377|caabaafa34722be7
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_insert.cpp|20040414082400|10799|7d0ef7cc8f657fd5
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_insert.hpp|20040414082400|14354|cc96fa9b81169471
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_pred.cpp|20040414082400|16798|56faa755aa42ddfa
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_pred.hpp|20040414082400|19159|eada43753e8b1e6c
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_pred_op.cpp|20040414082400|21533|47d693dde1a6d907
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_pred_op.hpp|20040414082400|23992|b42256983d2bda7b
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query.cpp|20040414082400|26355|4ac293821c9b4602
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query.hpp|20040414082400|28888|f86fbd9a108206c0
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_count.cpp|20040414082400|31247|9fa96a57d2dde660
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_count.hpp|20040414082400|33607|bdbe6e4734abc0c5
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_distinct.cpp|20040414082400|37150|3ba18528aa67b9dd
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_distinct.hpp|20040414082400|39517|c12b2b7ff6b2e7b3
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_filter.cpp|20040414082400|41984|a3d067d5d8fb40c
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_filter.hpp|20040414082400|44363|d0a341f2e40f0183
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_group.cpp|20040414082400|46860|4443c844308f9a98
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_group.hpp|20040414082400|49266|ba4691be942c6e2a
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_index.cpp|20040414082400|51663|f0312c9e2f22daf6
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_index.hpp|20040414082400|54471|6baaf1abbb704bb1
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_join.cpp|20040414082400|56943|36e07422c67d6838
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_join.hpp|20040414082400|59419|c4d17d18c4e3b4a0
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_lookup.cpp|20040414082400|61998|3d80e3ddbdae531d
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_lookup.hpp|20040414082400|00081|73332533e5196630
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_project.cpp|20040414082400|01373|ebc22f71bb7ec98c
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_project.hpp|20040414082400|03788|2734cdf1f907e0a4
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_range.cpp|20040414082400|06316|62ddafd2d17063cc
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_range.hpp|20040414082400|09865|81546843616efefa
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_repeat.cpp|20040414082400|11154|ce8f2a065897d6e3
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_repeat.hpp|20040414082400|13697|c20e10d0db9ad53c
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_scan.cpp|20040414082400|16320|855e56d6f56de938
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_scan.hpp|20040414082400|20784|b93c277da5b2509b
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_sort.cpp|20040414082400|24684|c08fc07f739de097
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_sort.hpp|20040414082400|25997|84edb5e128eda962
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_sys.cpp|20040414082400|28427|1d6a4a1cec789001
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_query_sys.hpp|20040414082400|31003|f5182823da25f097
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_root.cpp|20040414082400|33423|4c26a01ced583e41
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_root.hpp|20040414082401|01466|de1fd878505d9e26
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_select.cpp|20040414082401|04049|75b2a39f282d8ef5
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_select.hpp|20040414082401|06512|f9fadc322d78033a
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_set_row.cpp|20040414082401|08991|1bda7e6f86f18aef
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_set_row.hpp|20040414082401|12465|32ac3de384b91229
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_stmt.cpp|20040414082401|13817|c0e9903aa90df90b
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_stmt.hpp|20040414082401|17310|fab11fc487e74d05
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_table.cpp|20040414082401|20990|c46b7a6e2ecf4f61
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_table.hpp|20040414082401|22331|a48d57a0375a6d56
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_table_list.cpp|20040414082402|33460|40948eccedfae7bb
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_table_list.hpp|20040414082402|34739|c1e880e9949d3a
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update.cpp|20040414082402|37093|ed36f4a7a928a91b
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update.hpp|20040414082402|39546|c1de760c7b580b0c
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_index.cpp|20040414082402|42086|a0c6ad33ffbbc00e
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_index.hpp|20040414082402|44472|b57bbe5c8d927df9
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_lookup.cpp|20040414082402|46928|3491782088e97384
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_lookup.hpp|20040414082402|49343|ee335822c3496863
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_scan.cpp|20040414082402|51785|35e5b7d4619b3e09
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Code_update_scan.hpp|20040414082402|54180|287f193ad48fbefd
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/Makefile|20040414084435|20906|420b8378d374f069
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/SimpleGram.ypp|20040414082402|57791|6301cedf92524710
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/SimpleParser.cpp|20040414082402|60351|549f93e2a7fd01b5
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/SimpleParser.hpp|20040414082402|62814|4fdff7ee3839efc4
+magnus@neptunus.(none)|ndb/src/client/odbc/codegen/SimpleScan.lpp|20040414082402|65230|e11862b97fe39faf
+magnus@neptunus.(none)|ndb/src/client/odbc/common/AttrArea.cpp|20040414082402|03357|1570da617a1a6c4b
+magnus@neptunus.(none)|ndb/src/client/odbc/common/AttrArea.hpp|20040414082402|06048|f3d78ccd37af4e6
+magnus@neptunus.(none)|ndb/src/client/odbc/common/CodeTree.cpp|20040414082402|08438|1a4912632b0a61ee
+magnus@neptunus.(none)|ndb/src/client/odbc/common/CodeTree.hpp|20040414082402|10916|dcb603cce390eafa
+magnus@neptunus.(none)|ndb/src/client/odbc/common/ConnArea.cpp|20040414082402|13287|103182cf445f0bc3
+magnus@neptunus.(none)|ndb/src/client/odbc/common/ConnArea.hpp|20040414082402|16782|ffe99deedf7dc1ee
+magnus@neptunus.(none)|ndb/src/client/odbc/common/Ctx.cpp|20040414082402|18121|ce1c13ba8a312eba
+magnus@neptunus.(none)|ndb/src/client/odbc/common/Ctx.hpp|20040414082402|20500|bc88aba55ab71063
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DataField.cpp|20040414082402|22982|6bb1fe1cb971c8f9
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DataField.hpp|20040414082402|25733|d324898a9a86463d
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DataRow.cpp|20040414082402|29367|8764a23cee4f9481
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DataRow.hpp|20040414082402|31983|66a65eee1a1b2f23
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DataType.cpp|20040414082402|34382|29b8ddd51fdd3a2f
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DataType.hpp|20040414082403|02299|adef26bc1dc940eb
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DescArea.cpp|20040414082403|04653|aab4edd7e336acdd
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DescArea.hpp|20040414082403|07055|20ba9b6484762f0f
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DiagArea.cpp|20040414082403|09406|e3662d8977947e67
+magnus@neptunus.(none)|ndb/src/client/odbc/common/DiagArea.hpp|20040414082403|11824|1c6595b5fac06eb2
+magnus@neptunus.(none)|ndb/src/client/odbc/common/Makefile|20040414084435|27122|8505f6b38fe5c219
+magnus@neptunus.(none)|ndb/src/client/odbc/common/OdbcData.cpp|20040414082403|16621|e557009c1ed1e017
+magnus@neptunus.(none)|ndb/src/client/odbc/common/OdbcData.hpp|20040414082403|19077|2125814c1293c0b3
+magnus@neptunus.(none)|ndb/src/client/odbc/common/ResultArea.cpp|20040414082403|21436|8bcc2a2d9a98b9b0
+magnus@neptunus.(none)|ndb/src/client/odbc/common/ResultArea.hpp|20040414082403|23832|8d4646b94be475d1
+magnus@neptunus.(none)|ndb/src/client/odbc/common/Sqlstate.cpp|20040414082403|26171|b844144af963c22c
+magnus@neptunus.(none)|ndb/src/client/odbc/common/Sqlstate.hpp|20040414082403|29665|60006ee1c27c6e5
+magnus@neptunus.(none)|ndb/src/client/odbc/common/StmtArea.cpp|20040414082403|32310|5c5f8613156e06b2
+magnus@neptunus.(none)|ndb/src/client/odbc/common/StmtArea.hpp|20040414082403|34785|9662e56ae164eb7f
+magnus@neptunus.(none)|ndb/src/client/odbc/common/StmtInfo.cpp|20040414082403|37141|54ee4040e5807214
+magnus@neptunus.(none)|ndb/src/client/odbc/common/StmtInfo.hpp|20040414082403|39465|6698d657391692fc
+magnus@neptunus.(none)|ndb/src/client/odbc/common/common.cpp|20040414082403|41862|4792b9ecddd99482
+magnus@neptunus.(none)|ndb/src/client/odbc/common/common.hpp|20040414082403|45229|25369fa6c80eff53
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictCatalog.cpp|20040414082403|46524|9804b0ff3eac2f8
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictCatalog.hpp|20040414082403|50152|cace2fb2f6bb65e5
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictColumn.cpp|20040414082403|56647|b69d90c53e5b618
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictColumn.hpp|20040414082403|58973|c2da1b7bd0408bd1
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictIndex.cpp|20040414082403|62455|a456d3039e6a39e3
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictIndex.hpp|20040414082403|64865|f53b91a41bb96663
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictSchema.cpp|20040414082403|01679|639403c84a47dfdd
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictSchema.hpp|20040414082403|04043|5aa7dc8ade17e94c
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictSys.cpp|20040414082403|06523|fb89465b10c32bb0
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictSys.hpp|20040414082403|08917|76583ba8aa88fd6f
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictTable.cpp|20040414082403|11346|8f4a9ee5a8038f87
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/DictTable.hpp|20040414082403|13733|cf99a9ac3dd49206
+magnus@neptunus.(none)|ndb/src/client/odbc/dictionary/Makefile|20040414084435|30267|4c1a6148787bdc2f
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/class.fig|20040414082403|16124|c0754ccad74d380a
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/descfield.pl|20040414082403|18935|e0bd59c2824824cc
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/diag.txt|20040414082403|21798|b66a7e227391335f
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/getinfo.pl|20040414082403|24266|2142ecf1567a66f6
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/gettypeinfo.pl|20040414082403|27572|2ea4c0589eac4e73
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/handleattr.pl|20040414082403|31383|b0c2a2901b68342e
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/main.hpp|20040414082404|00011|7b15eb7ffad488a0
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/ndbodbc.html|20040414082404|02501|a2f14fdd978b62cc
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/select.fig|20040414082404|04967|34f5222b5012e1d7
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/systables.pl|20040414082404|07386|1fa2191648bdb629
+magnus@neptunus.(none)|ndb/src/client/odbc/docs/type.txt|20040414082404|10311|feec700c81f5095f
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/Func.data|20040414082404|12860|9e75f15d921063f3
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/Func.pl|20040414082404|16530|aefb901bc3941d32
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/Makefile|20040414084435|24049|80d21270fc3ad931
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocConnect.cpp|20040414082404|18964|246af836b028d810
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocEnv.cpp|20040414082404|21279|eaf36cf2285ec2ac
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocHandle.cpp|20040414082404|23612|c0921921e84d1a10
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocHandleStd.cpp|20040414082404|27069|7d145f6e3640d913
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLAllocStmt.cpp|20040414082404|29405|362331ef456ec879
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBindCol.cpp|20040414082404|31826|fec3a78088d4951d
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBindParam.cpp|20040414082404|34178|a50b619a23efaab
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBindParameter.cpp|20040414082404|36965|533b1992496e2775
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBrowseConnect.cpp|20040414082404|39327|120b61a1ff6edee3
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLBulkOperations.cpp|20040414082404|41701|7a96be04250a388
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLCancel.cpp|20040414082404|45242|27eab683f6fa6ec6
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLCloseCursor.cpp|20040414082404|47634|6cbf193aadaf1058
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLColAttribute.cpp|20040414082404|51528|f2c858b16a9360d
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLColAttributes.cpp|20040414082404|53928|d4007908ee1309d
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLColumnPrivileges.cpp|20040414082404|56456|39a3020da4c3485b
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLColumns.cpp|20040414082404|58871|1c31107df60bb544
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLConnect.cpp|20040414082404|62974|868e02a519b72743
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLCopyDesc.cpp|20040414082404|64271|286522b25a029761
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDataSources.cpp|20040414082404|01136|12792108aac5b2ca
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDescribeCol.cpp|20040414082404|03611|1d1faafbcd3ecb3c
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDescribeParam.cpp|20040414082404|06014|70b016fa795ed275
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDisconnect.cpp|20040414082404|08470|9fb4c3d7a84db50a
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDriverConnect.cpp|20040414082404|10866|8dad42af7d17a9d9
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLDrivers.cpp|20040414082404|13335|400e7453e70f6e99
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLEndTran.cpp|20040414082404|15741|c37cce04cc303c01
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLError.cpp|20040414082404|18143|593b81885c15187b
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLExecDirect.cpp|20040414082404|20664|5e6274e76315339d
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLExecute.cpp|20040414082404|24388|1692a85f8639f71
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLExtendedFetch.cpp|20040414082404|27134|8b9d604580a83cfd
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFetch.cpp|20040414082404|29534|fa1606aa2dd901db
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFetchScroll.cpp|20040414082404|31991|cdb16803511963a1
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLForeignKeys.cpp|20040414082405|00096|4b8a9af2f6bf92cb
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFreeConnect.cpp|20040414082405|02501|92359420501ebc5b
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFreeEnv.cpp|20040414082405|04956|64f1776817464807
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFreeHandle.cpp|20040414082405|07349|2dc029edf912c2d
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLFreeStmt.cpp|20040414082405|09791|8f8cb0a43c02a67
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetConnectAttr.cpp|20040414082405|13307|b29ff18aeedd8966
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetConnectOption.cpp|20040414082405|15755|3e0bc4e1af95c682
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetCursorName.cpp|20040414082405|19268|8266b920671b6d01
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetData.cpp|20040414082405|21785|3d837348460c219d
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetDescField.cpp|20040414082405|24186|62828192a7d1d954
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetDescRec.cpp|20040414082405|26589|f54cc69bcd1238ad
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetDiagField.cpp|20040414082405|29075|673e1ea0f9d5121f
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetDiagRec.cpp|20040414082405|31498|bea0f68f5b940ab8
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetEnvAttr.cpp|20040414082405|33972|e742277d8bdf234d
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetFunctions.cpp|20040414082405|36391|72de050fbfb4a9bb
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetInfo.cpp|20040414082405|38935|e4e09d6bedbf02b1
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetStmtAttr.cpp|20040414082405|41363|de7dabc8c2acea7
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetStmtOption.cpp|20040414082405|43806|2ff900ebdd167077
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLGetTypeInfo.cpp|20040414082405|46378|333196b07473dff6
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLMoreResults.cpp|20040414082405|48899|483d94cb57379e81
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLNativeSql.cpp|20040414082405|51374|eeae6067f4a85c
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLNumParams.cpp|20040414082405|57810|8921304c3bcf4835
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLNumResultCols.cpp|20040414082405|59136|4d2b6527ffe81059
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLParamData.cpp|20040414082405|62648|163b046513f1e4ae
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLParamOptions.cpp|20040414082405|64040|bdcbccb961fff044
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLPrepare.cpp|20040414082405|00921|1d339fe24888087
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLPrimaryKeys.cpp|20040414082405|03420|5d7b2a0ae08a267
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLProcedureColumns.cpp|20040414082405|05843|c7a0535e9f50ff39
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLProcedures.cpp|20040414082405|08319|c59d025b22e2d1a6
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLPutData.cpp|20040414082405|11934|9dbf69ea9d369dbd
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLRowCount.cpp|20040414082405|14434|d4ac5b273afdb154
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetConnectAttr.cpp|20040414082405|16860|c2c520c34c41bd88
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetConnectOption.cpp|20040414082405|19298|dadc980d9f9cad1b
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetCursorName.cpp|20040414082405|21855|ccfc33dd2cf6abeb
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetDescField.cpp|20040414082405|24355|c4db694d1b9e8f77
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetDescRec.cpp|20040414082405|26866|f8dd72467d5012ab
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetEnvAttr.cpp|20040414082405|29480|7b50aeae6228c2db
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetParam.cpp|20040414082405|31915|e0dd2d5e8d3ec450
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetPos.cpp|20040414082405|34406|39a3e69960041aa7
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetScrollOptions.cpp|20040414082406|03524|6f8250379bb0cac8
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetStmtAttr.cpp|20040414082406|06008|e99b7e6025a1ae1f
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSetStmtOption.cpp|20040414082406|10068|87af3125a48c27fa
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLSpecialColumns.cpp|20040414082406|12486|1877b4c368825de5
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLStatistics.cpp|20040414082406|14949|87e0359f237aa66a
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLTablePrivileges.cpp|20040414082406|17508|fa16ea0fffa4edeb
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLTables.cpp|20040414082406|20645|c8b201068baec393
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/SQLTransact.cpp|20040414082406|23280|eb33c2f66ee85738
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/driver.cpp|20040414082406|25724|f8f1eeec35b08f18
+magnus@neptunus.(none)|ndb/src/client/odbc/driver/driver.hpp|20040414082406|29359|f108f4eef34ec8ea
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_comp_op.cpp|20040414082406|31800|eacbd7512b32d68b
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_create_index.cpp|20040414082406|35482|c6b8e670198adfa9
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_create_table.cpp|20040414082406|37927|76904d417bc0a59a
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_delete_index.cpp|20040414082406|40489|1ffe5af6eb160a68
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_delete_lookup.cpp|20040414082406|43115|5d24028ce16b6623
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_delete_scan.cpp|20040414082406|46919|810aa4058f73c941
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_drop_index.cpp|20040414082406|49349|3a3871ec6ee48c28
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_drop_table.cpp|20040414082406|51862|639a2faba4da14f4
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_expr_conv.cpp|20040414082406|54314|b5452bd4fbd7c945
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_expr_func.cpp|20040414082406|56759|c78ab0e67d54f38c
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_expr_op.cpp|20040414082406|59381|5e341b2e63495ba4
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_insert.cpp|20040414082406|61884|71dd4bf2fb913f2e
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_pred_op.cpp|20040414082406|64460|ebe7b65ba81e5185
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_index.cpp|20040414082406|01584|4cada676fa178001
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_lookup.cpp|20040414082406|05431|79dfe29b088d832
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_range.cpp|20040414082406|06819|7c4e148e81a292d6
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_scan.cpp|20040414082406|09339|7c66194f7f93346f
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_query_sys.cpp|20040414082406|11968|d66abe07cd519163
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_update_index.cpp|20040414082406|14543|86140a945f790890
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_update_lookup.cpp|20040414082406|17085|b7a7387620cf42ab
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Exec_update_scan.cpp|20040414082406|19743|2285c72106cffe0
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Executor.cpp|20040414082406|22273|ccb54cc8ffe18bae
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Executor.hpp|20040414082406|24762|c94d916ae5af2506
+magnus@neptunus.(none)|ndb/src/client/odbc/executor/Makefile|20040414084435|12419|a08f437558c2d3b4
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/AttrDbc.cpp|20040414082406|27307|24a034fbb22cdb23
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/AttrEnv.cpp|20040414082406|30042|7d74bcba78e149d0
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/AttrRoot.cpp|20040414082406|32507|5def5d7e228eedf0
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/AttrStmt.cpp|20040414082407|00551|5363ba63b35ff8f4
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/DescSpec.cpp|20040414082407|03310|cd50c1c855f1905
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/FuncTab.cpp|20040414082407|05927|e77abea11a532708
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleBase.cpp|20040414082407|08362|2ba63dce2dfec07b
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleBase.hpp|20040414082407|10820|8cf9a1e94d272328
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleDbc.cpp|20040414082407|13361|2a79fea6477b2c63
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleDbc.hpp|20040414082407|15852|9abc692ac6b0abb3
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleDesc.cpp|20040414082407|18335|e77eb1d73d171a98
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleDesc.hpp|20040414082407|20794|553aeb842b3da88e
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleEnv.cpp|20040414082407|23207|6b96fc6b188f252b
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleEnv.hpp|20040414082407|25666|572a7b4af6816f8b
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleRoot.cpp|20040414082407|28085|aa5044f74554fa9c
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleRoot.hpp|20040414082407|30587|2fcfca742c13cfb3
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleStmt.cpp|20040414082407|33024|782f96bda9eaf13c
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/HandleStmt.hpp|20040414082407|35570|6508fc97f3c772e1
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/InfoTab.cpp|20040414082407|38088|f89104b9c6fe7489
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/Makefile|20040414084435|15527|3d8d1529ad26ce76
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/PoolNdb.cpp|20040414082407|40567|793fa032699b7d98
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/PoolNdb.hpp|20040414082407|43172|db9e1a04d2fe705d
+magnus@neptunus.(none)|ndb/src/client/odbc/handles/handles.hpp|20040414082407|45564|bfe0b6a7a95ac142
+magnus@neptunus.(none)|ndb/src/ndbbaseclient/Makefile|20040414084439|01640|4b92d5e5b416dd0
+magnus@neptunus.(none)|ndb/src/ndbbaseclient/ndbbaseclient_dummy.cpp|20040414082426|08918|daee9eb6acbc94
+magnus@neptunus.(none)|ndb/src/ndbclient/Makefile|20040414084438|29978|f993f3afae0d4308
+magnus@neptunus.(none)|ndb/src/ndbclient/ndbclient_dummy.cpp|20040414082426|11587|73154070f5d0bfbf
+magnus@neptunus.(none)|ndb/src/newtonapi/Makefile|20040414084438|17704|bcbd9a7282094cc
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_binding.cpp|20040414082426|14355|dcc4fb57f9ab6cba
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_bulkread.cpp|20040414082426|17142|4ddfe02a93d2ba11
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_config.cpp|20040414082426|19935|38acf2ad3a932420
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_dac.cpp|20040414082426|10457|4615e3d0d8a15bff
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_error.cpp|20040414082426|12319|a58b4a1628a2d4b9
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_init.cpp|20040414082426|15064|80da7e3fa0775346
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_internal.hpp|20040414082426|17987|54884404e30c8823
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_process.cpp|20040414082426|22216|509e54294bc7efd2
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_process.hpp|20040414082426|24005|f0ddefb3b2d6a662
+magnus@neptunus.(none)|ndb/src/newtonapi/dba_schema.cpp|20040414082426|26757|1c3b8399853c108
+magnus@neptunus.(none)|ndb/src/rep/ExtSender.cpp|20040414082426|29555|1851d559cfddae43
+magnus@neptunus.(none)|ndb/src/rep/ExtSender.hpp|20040414082426|32345|10ae62ec85ee6692
+magnus@neptunus.(none)|ndb/src/rep/Makefile|20040414084438|44449|954f853c2d812c2c
+magnus@neptunus.(none)|ndb/src/rep/NodeConnectInfo.hpp|20040414082427|00605|9c4318dd55f3f84
+magnus@neptunus.(none)|ndb/src/rep/README|20040414082427|03407|6939b06d192a6b99
+magnus@neptunus.(none)|ndb/src/rep/RepApiInterpreter.cpp|20040414082427|06188|8ba561cb831ae353
+magnus@neptunus.(none)|ndb/src/rep/RepApiInterpreter.hpp|20040414082427|08968|31be5af2ba72d263
+magnus@neptunus.(none)|ndb/src/rep/RepApiService.cpp|20040414082427|11699|93d4005333167a0f
+magnus@neptunus.(none)|ndb/src/rep/RepApiService.hpp|20040414082432|07265|42f5ffb7e3baa54e
+magnus@neptunus.(none)|ndb/src/rep/RepCommandInterpreter.cpp|20040414082432|10009|f661a8ff312213f8
+magnus@neptunus.(none)|ndb/src/rep/RepCommandInterpreter.hpp|20040414082432|12750|fb6f22895e8c8679
+magnus@neptunus.(none)|ndb/src/rep/RepComponents.cpp|20040414082432|16488|fb067aee8e5a4a1f
+magnus@neptunus.(none)|ndb/src/rep/RepComponents.hpp|20040414082432|19179|9e632beac4f8bbf8
+magnus@neptunus.(none)|ndb/src/rep/RepMain.cpp|20040414082432|21936|de79cb7b6f3acd18
+magnus@neptunus.(none)|ndb/src/rep/Requestor.cpp|20040414082432|24636|c653fa987f84ce43
+magnus@neptunus.(none)|ndb/src/rep/Requestor.hpp|20040414082432|27340|a499054c9a128dbd
+magnus@neptunus.(none)|ndb/src/rep/RequestorSubscriptions.cpp|20040414082432|30099|f0643f7cc9aa9654
+magnus@neptunus.(none)|ndb/src/rep/SignalQueue.cpp|20040414082432|32849|6d32d876acc1a598
+magnus@neptunus.(none)|ndb/src/rep/SignalQueue.hpp|20040414082432|35536|b92204ff36f399d1
+magnus@neptunus.(none)|ndb/src/rep/TODO|20040414082432|38233|187896dd2e5dfd02
+magnus@neptunus.(none)|ndb/src/rep/adapters/AppNDB.cpp|20040414082432|46457|1db5eafacdeda3b7
+magnus@neptunus.(none)|ndb/src/rep/adapters/AppNDB.hpp|20040414082432|49233|2c3081224b4ff75f
+magnus@neptunus.(none)|ndb/src/rep/adapters/ExtAPI.cpp|20040414082432|51989|d98f38669b10ca97
+magnus@neptunus.(none)|ndb/src/rep/adapters/ExtAPI.hpp|20040414082432|54656|32bcb96bcd2d60c
+magnus@neptunus.(none)|ndb/src/rep/adapters/ExtNDB.cpp|20040414082432|57410|38cccb80529c02c6
+magnus@neptunus.(none)|ndb/src/rep/adapters/ExtNDB.hpp|20040414082432|60222|ee245e7e2c707685
+magnus@neptunus.(none)|ndb/src/rep/adapters/Makefile|20040414084438|21912|bcb9d87fd69a7911
+magnus@neptunus.(none)|ndb/src/rep/adapters/TableInfoPs.hpp|20040414082432|62988|56b1f8f75fe7cb1c
+magnus@neptunus.(none)|ndb/src/rep/dbug_hack.cpp|20040414082432|40989|f090906a24103f0
+magnus@neptunus.(none)|ndb/src/rep/rep_version.hpp|20040414082432|43779|82a23fe4dbb13cab
+magnus@neptunus.(none)|ndb/src/rep/repapi/Makefile|20040414084438|41386|25c4b35b84d945b4
+magnus@neptunus.(none)|ndb/src/rep/repapi/repapi.cpp|20040414082432|00155|82b9b00c67cfdcf7
+magnus@neptunus.(none)|ndb/src/rep/repapi/repapi.h|20040414082432|02987|6f8cf6b53a86a5ae
+magnus@neptunus.(none)|ndb/src/rep/state/Channel.cpp|20040414082432|05711|1d5f62245962b839
+magnus@neptunus.(none)|ndb/src/rep/state/Channel.hpp|20040414082432|08527|71c1d63ef4b2cbfe
+magnus@neptunus.(none)|ndb/src/rep/state/Interval.cpp|20040414082432|11324|3d079ca9cc21124d
+magnus@neptunus.(none)|ndb/src/rep/state/Interval.hpp|20040414082432|14048|85aa46fc419bb109
+magnus@neptunus.(none)|ndb/src/rep/state/Makefile|20040414084438|33082|6a9cedaeedcc4650
+magnus@neptunus.(none)|ndb/src/rep/state/RepState.cpp|20040414082432|16760|3d60b0a46e9477c1
+magnus@neptunus.(none)|ndb/src/rep/state/RepState.hpp|20040414082432|19671|94d7c472c8a7367
+magnus@neptunus.(none)|ndb/src/rep/state/RepStateEvent.cpp|20040414082432|22494|f51d7eb7b7aca0b
+magnus@neptunus.(none)|ndb/src/rep/state/RepStateRequests.cpp|20040414082432|25234|393882166df6929
+magnus@neptunus.(none)|ndb/src/rep/state/testInterval/Makefile|20040414084438|35164|e33e587a7947ac36
+magnus@neptunus.(none)|ndb/src/rep/state/testInterval/testInterval.cpp|20040414082432|27995|993f4118f616e80
+magnus@neptunus.(none)|ndb/src/rep/state/testRepState/Makefile|20040414084438|28225|f5a6d9415d7e0977
+magnus@neptunus.(none)|ndb/src/rep/state/testRepState/testRequestor.cpp|20040414082432|30850|4a943fae5be63c79
+magnus@neptunus.(none)|ndb/src/rep/state/testRepState/testRequestor.hpp|20040414082432|33580|583208c83ff5b554
+magnus@neptunus.(none)|ndb/src/rep/storage/GCIBuffer.cpp|20040414082433|01915|6e8c6f38ab63d1d6
+magnus@neptunus.(none)|ndb/src/rep/storage/GCIBuffer.hpp|20040414082433|04667|703e2016a7ec616f
+magnus@neptunus.(none)|ndb/src/rep/storage/GCIContainer.cpp|20040414082433|07490|9c53acd16fc5ac74
+magnus@neptunus.(none)|ndb/src/rep/storage/GCIContainer.hpp|20040414082433|10275|ac28cea9114659fd
+magnus@neptunus.(none)|ndb/src/rep/storage/GCIContainerPS.cpp|20040414082433|13103|116168903a2c617a
+magnus@neptunus.(none)|ndb/src/rep/storage/GCIContainerPS.hpp|20040414082433|15896|9a801ffe939e192e
+magnus@neptunus.(none)|ndb/src/rep/storage/GCIPage.cpp|20040414082433|18724|42fa918fbf36828a
+magnus@neptunus.(none)|ndb/src/rep/storage/GCIPage.hpp|20040414082433|22604|4197e2278326515e
+magnus@neptunus.(none)|ndb/src/rep/storage/LogRecord.hpp|20040414082433|25752|11644fe7c5f5d36
+magnus@neptunus.(none)|ndb/src/rep/storage/Makefile|20040414084438|25055|a955d34726662aba
+magnus@neptunus.(none)|ndb/src/rep/storage/NodeConnectInfo.hpp|20040414082433|28517|35a7682fd9dba464
+magnus@neptunus.(none)|ndb/src/rep/storage/NodeGroup.cpp|20040414082433|31343|adebbefb11cd1670
+magnus@neptunus.(none)|ndb/src/rep/storage/NodeGroup.hpp|20040414082433|34127|3fcddc2da5d10e45
+magnus@neptunus.(none)|ndb/src/rep/storage/NodeGroupInfo.cpp|20040414082433|36945|b1130e3c42777658
+magnus@neptunus.(none)|ndb/src/rep/storage/NodeGroupInfo.hpp|20040414082433|39718|7fd3b74f4b59a503
+magnus@neptunus.(none)|ndb/src/rep/transfer/Makefile|20040414084438|38260|6b43df78ea480db1
+magnus@neptunus.(none)|ndb/src/rep/transfer/TransPS.cpp|20040414082433|43592|7a88ca746987ac10
+magnus@neptunus.(none)|ndb/src/rep/transfer/TransPS.hpp|20040414082433|46546|846b26eaa80632a1
+magnus@neptunus.(none)|ndb/src/rep/transfer/TransSS.cpp|20040414082433|49370|8f12a062b240eecf
+magnus@neptunus.(none)|ndb/src/rep/transfer/TransSS.hpp|20040414082433|52255|7718b5e4ce9a4007
+magnus@neptunus.(none)|ndb/src/rep/transfer/TransSSSubscriptions.cpp|20040414082433|55067|6bc55e474f33e023
+magnus@neptunus.(none)|ndb/tools/ndbnet/Makefile.PL|20040414082442|56473|81be90388548652f
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net.pm|20040414082442|02828|425c84165071d5f6
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/Base.pm|20040414082442|11671|50a6f0d38fa1a57c
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/Client.pm|20040414082442|14568|45adb527c5cfdaf6
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/Command.pm|20040414082442|17582|a20dff1bfd06ea7a
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/Config.pm|20040414082442|20612|24456d4beba19604
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/Database.pm|20040414082442|23641|cc02e455b02c557
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/Env.pm|20040414082442|26624|ffeca4ab253818c3
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/Node.pm|20040414082442|29671|276106bf4000fe2b
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/NodeApi.pm|20040414082442|32765|3abf1d7bc947d3d0
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/NodeDb.pm|20040414082443|01346|9e3055381da679ce
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/NodeMgmt.pm|20040414082443|04349|5123fbffcfce73cb
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/Server.pm|20040414082443|07453|70208c964371fd4d
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/ServerINET.pm|20040414082443|10474|fc72d28fedd17795
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Net/ServerUNIX.pm|20040414082443|13573|ad3e25435fceb8d0
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Run.pm|20040414082442|05790|9b414f2b4b76a4da
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Run/Base.pm|20040414082443|16656|dd382c9eec2c38b1
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Run/Database.pm|20040414082443|19701|ec533cd5dd6a54a2
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Run/Env.pm|20040414082443|22716|a343841fae6d0514
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Run/Node.pm|20040414082443|25798|339139ded5fcf795
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util.pm|20040414082442|08694|9be64f1195ec502d
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/Base.pm|20040414082443|28821|f39906f304e8a49
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/Dir.pm|20040414082443|31912|4cbe8dd8c57149a7
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/Event.pm|20040414082443|35023|f445c1c094f57cf
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/File.pm|20040414082443|38178|48da8e977f39bf7
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/IO.pm|20040414082443|41286|6c6a63ce63fe2ee5
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/Lock.pm|20040414082443|44445|366e56786358b3d8
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/Log.pm|20040414082443|47535|e0da9468a6f9213a
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/Socket.pm|20040414082443|50710|371ccd6c5a818fa0
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/SocketINET.pm|20040414082443|53816|db8a45b1360b69f2
+magnus@neptunus.(none)|ndb/tools/ndbnet/lib/NDB/Util/SocketUNIX.pm|20040414082443|56977|9ffab2ada7f61530
+magnus@neptunus.(none)|ndb/tools/ndbnet/ndbnet.pl|20040414082442|59371|8f8f1b18f0458269
+magnus@neptunus.(none)|ndb/tools/ndbnet/ndbnetd.pl|20040414082442|62363|e44f1cfe7e8bbe14
+magnus@neptunus.(none)|ndb/tools/ndbnet/ndbrun|20040414082442|65454|5db549d7436ac81b
miguel@hegel.local|zlib/ChangeLog|20020319032513|28917|5d5425fc84737083
miguel@hegel.local|zlib/Make_vms.com|20020319032513|57151|35050a50ec612bbf
miguel@hegel.local|zlib/Makefile.riscos|20020319032513|63798|8ab53f195fe429af
@@ -748,6 +1184,7 @@ mwagner@evoq.home.mwagner.org|mysql-test/xml/xsl/README|20001013051514|26509|cd4
mwagner@evoq.home.mwagner.org|mysql-test/xml/xsl/mysqltest.xsl|20001013051514|27425|1b8f6ec4f1b5f634
mwagner@work.mysql.com|mysql-test/r/3.23/sel000001.result|20001010091454|28284|383913ae4505ec86
mwagner@work.mysql.com|mysql-test/r/3.23/sel000002.result|20001010091454|29230|d1787e6fd5dbc1cc
+ndb/src/client/Makefile
nick@nick.leippe.com|mysql-test/r/rpl_empty_master_crash.result|20020531235552|47718|615f521be2132141
nick@nick.leippe.com|mysql-test/t/rpl_empty_master_crash.test|20020531235552|52328|99464e737639ccc6
sasha@mysql.sashanet.com|BitKeeper/etc/logging_ok|20000801000905|12967|5b7d847a2158554
@@ -755,26 +1192,15 @@ sasha@mysql.sashanet.com|build-tags|20011125054855|05181|7afb7e785b80f97
sasha@mysql.sashanet.com|build-tags|20011201050944|25384|b6f6fff142121618
sasha@mysql.sashanet.com|libmysql_r/acconfig.h|20001128060846|51084|65f1202b3b5c345f
sasha@mysql.sashanet.com|mysql-test/README.gcov|20001012045950|28177|5a6da067a30780ce
-sasha@mysql.sashanet.com|mysql-test/README.gcov|20001214012355|41825|2de7575ca81155e5
sasha@mysql.sashanet.com|mysql-test/README|20001010001022|12739|108667adaeabe3f5
sasha@mysql.sashanet.com|mysql-test/r/3.23/alt000001.result|20001122072330|24729|393103dbf15f35c9
sasha@mysql.sashanet.com|mysql-test/r/3.23/ins000001.result|20001018175743|49824|f45c599efdf8352b
sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000001.a.result|20001118063528|39426|2987b17db06808c3
sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000001.b.result|20001118063528|44057|62e1fa91167cacc3
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000002.result|20001118063528|46039|109f5ceed1e0d64
sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000003.result|20001118063528|48148|68d6ee00beaa011
sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000004.a.result|20001118063528|50132|3415f066cb91c460
sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000004.b.result|20001118063528|52094|352b35351551485
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000005.result|20001118063528|54071|a50962bc2340ab9a
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000006.result|20001118063528|56081|5653051e8ce6b4aa
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000007.result|20001121063807|21606|e0c3b6134e0884da
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000008.result|20001121063807|23636|c5cfee19ca5a7da9
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000009.result|20001121063807|25633|ed8042446ab97926
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000010.result|20001122072330|29430|3228109b8965b0f8
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000011.result|20001125024912|48851|c29dce30aa97f265
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000012.result|20001126062901|05938|35d6596da7b90fc5
sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000012.status.result|20001126062901|09395|bbbd650b5beea32f
-sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000013.result|20001202171150|03876|ac5024e6cf6daac6
sasha@mysql.sashanet.com|mysql-test/r/3.23/rpl000013.status.result|20001202171150|06069|6bee190c298cc9fd
sasha@mysql.sashanet.com|mysql-test/r/3.23/sel000003.result|20001011230020|64653|d7b657b1e3a286a7
sasha@mysql.sashanet.com|mysql-test/r/3.23/sel000100.res|20001205131218|23520|84ed46856cb3a69f
@@ -783,7 +1209,6 @@ sasha@mysql.sashanet.com|mysql-test/r/binlog-backup-restore.result|2001042423392
sasha@mysql.sashanet.com|mysql-test/r/df_crash.result|20010406010433|59989|4a3dbee64843953d
sasha@mysql.sashanet.com|mysql-test/r/identity.result|20010910233028|16331|e41453a364242503
sasha@mysql.sashanet.com|mysql-test/r/mrg000002.result|20001212152450|11492|745be0854aaaaf5e
-sasha@mysql.sashanet.com|mysql-test/r/slave-running.result|20001208141122|24303|f73e49462cf59e1f
sasha@mysql.sashanet.com|mysql-test/r/slave-stopped.result|20001208141122|28916|25c134b1a4f1993a
sasha@mysql.sashanet.com|mysql-test/std_data/m.MRG|20001212152450|17736|3f5632c37af00f18
sasha@mysql.sashanet.com|mysql-test/std_data/m.frm|20001212152450|13897|e351dfe0b6824c0c
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 330d28daf52..346dcae3cfd 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -7,11 +7,13 @@ Greg@greg-laptop.
Miguel@light.local
Sinisa@sinisa.nasamreza.org
WAX@sergbook.mysql.com
+acurtis@ltantony.rdg.cyberkinetica.homeunix.net
acurtis@pcgem.rdg.cyberkinetica.com
acurtis@xiphis.org
administrador@light.hegel.local
ahlentz@co3064164-a.rochd1.qld.optusnet.com.au
akishkin@work.mysql.com
+anjuta@arthur.local
antony@ltantony.dsl-verizon.net
antony@ltantony.rdg.cyberkinetica.com
antony@ltantony.rdg.cyberkinetica.homeunix.net
@@ -24,10 +26,12 @@ bar@bar.intranet.mysql.r18.ru
bar@bar.mysql.r18.ru
bar@bar.udmsearch.izhnet.ru
bar@deer.(none)
+bar@eagle.intranet.mysql.r18.ru
bar@gw.udmsearch.izhnet.ru
bar@mysql.com
bar@noter.intranet.mysql.r18.ru
bell@51.0.168.192.in-addr.arpa
+bell@52.0.168.192.in-addr.arpa
bell@laptop.sanja.is.com.ua
bell@sanja.is.com.ua
bk@admin.bk
@@ -37,6 +41,7 @@ brian@brian-akers-computer.local
brian@private-client-ip-101.oz.net
brian@zim.(none)
carsten@tsort.bitbybit.dk
+cps@silver_beast.(none)
davida@isil.mysql.com
dean@mysql.com
dellis@goetia.(none)
@@ -47,11 +52,14 @@ dlenev@mysql.com
ejonore@mc03.ndb.mysql.com
evgen@moonbone.(none)
evgen@moonbone.local
+gbichot@production.mysql.com
gbichot@quadita2.mysql.com
gbichot@quadxeon.mysql.com
georg@beethoven.local
+georg@beethoven.site
georg@lmy002.wdf.sap.corp
gerberb@ou800.zenez.com
+gluh@eagle.intranet.mysql.r18.ru
gluh@gluh.(none)
gluh@gluh.mysql.r18.ru
gluh@mysql.com
@@ -82,11 +90,13 @@ jani@a193-229-222-105.elisa-laajakaista.fi
jani@a193-229-222-2.elisa-laajakaista.fi
jani@a80-186-24-72.elisa-laajakaista.fi
jani@a80-186-41-201.elisa-laajakaista.fi
+jani@a80-186-8-224.elisa-laajakaista.fi
jani@dsl-jkl1657.dial.inet.fi
jani@dsl-kpogw4gb5.dial.inet.fi
jani@hynda.(none)
jani@hynda.mysql.fi
jani@janikt.pp.saunalahti.fi
+jani@linux.local
jani@rhols221.adsl.netsonic.fi
jani@rhols221.arenanet.fi
jani@ua126d19.elisa.omakaista.fi
@@ -101,6 +111,9 @@ jcole@sarvik.tfr.cafe.ee
jcole@tetra.spaceapes.com
jimw@mysql.com
joerg@mysql.com
+jon@gigan.
+jonas@mysql.com
+joreland@bk-internal.mysql.com
joreland@mysql.com
jorge@linux.jorge.mysql.com
jplindst@t41.(none)
@@ -112,10 +125,12 @@ kostja@oak.local
lars@mysql.com
lenz@kallisto.mysql.com
lenz@mysql.com
+magnus@msdesk.mysql.com
magnus@neptunus.(none)
magnus@shellback.(none)
marko@hundin.mysql.fi
marty@linux.site
+marty@shark.
mats@mysql.com
matt@booty.(none)
matt@mysql.com
@@ -152,9 +167,11 @@ monty@tramp.mysql.fi
monty@work.mysql.com
mronstrom@build.mysql.com
mronstrom@mysql.com
+mskold@bk-internal.mysql.com
mskold@mysql.com
msvensson@build.mysql.com
msvensson@neptunus.(none)
+msvensson@neptunus.homeip.net
mwagner@cash.mwagner.org
mwagner@evoq.mwagner.org
mwagner@here.mwagner.org
@@ -163,16 +180,21 @@ mwagner@work.mysql.com
mydev@mysql.com
mysql@home.(none)
mysql@mc04.(none)
+mysqldev@bk-internal.mysql.com
mysqldev@build.mysql2.com
mysqldev@melody.local
mysqldev@mysql.com
mysqldev@o2k.irixworld.net
ndbdev@eel.hemma.oreland.se
ndbdev@ndbmaster.mysql.com
+ndbdev@shark.
nick@mysql.com
nick@nick.leippe.com
papa@gbichot.local
+patg@krsna.
patg@krsna.patg.net
+patg@patrick-galbraiths-computer.local
+patg@pc248.lfp.kcls.org
paul@central.snake.net
paul@frost.snake.net
paul@ice.local
@@ -182,11 +204,15 @@ paul@snake-hub.snake.net
paul@teton.kitebird.com
pekka@mysql.com
pem@mysql.com
+pem@per-erik-martins-dator.local
peter@linux.local
peter@mysql.com
peterg@mysql.com
petr@mysql.com
pgulutzan@linux.local
+pmartin@build.mysql2.com
+psergey@psergey-rh8.(none)
+psergey@psergey.(none)
ram@deer.(none)
ram@gw.mysql.r18.ru
ram@gw.udmsearch.izhnet.ru
@@ -208,6 +234,7 @@ salle@vafla.online.bg
sasha@mysql.sashanet.com
serg@build.mysql.com
serg@build.mysql2.com
+serg@mysql.com
serg@serg.mylan
serg@serg.mysql.com
serg@sergbook.mylan
@@ -245,6 +272,8 @@ ulli@morbus.(none)
venu@hundin.mysql.fi
venu@myvenu.com
venu@work.mysql.com
+vtkachenko@intelp4d.mysql.com
+vtkachenko@mail.mysql.com
vva@eagle.mysql.r18.ru
vva@genie.(none)
vva@mysql.r18.ru
diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit
index a54086a0d0d..fe263b79325 100755
--- a/BitKeeper/triggers/post-commit
+++ b/BitKeeper/triggers/post-commit
@@ -5,7 +5,7 @@ FROM=$USER@mysql.com
INTERNALS=internals@lists.mysql.com
DOCS=docs-commit@mysql.com
LIMIT=10000
-VERSION="4.1"
+VERSION="5.0"
if [ "$REAL_EMAIL" = "" ]
then
@@ -58,7 +58,7 @@ $BH
EOF
bk changes -v -r+
bk cset -r+ -d
- ) | head -n $LIMIT | /usr/sbin/sendmail -t
+ ) | /usr/sbin/sendmail -t
#++
# internals@ mail
@@ -102,7 +102,7 @@ Subject: bk commit - $VERSION tree (Manual) ($CHANGESET)$BS
EOF
bk changes -v -r+
bk cset -r+ -d
- ) | head -n $LIMIT | /usr/sbin/sendmail -t
+ ) | /usr/sbin/sendmail -t
fi
else
diff --git a/Docs/changelog-5.0.xml b/Docs/changelog-5.0.xml
new file mode 100755
index 00000000000..deb059716ad
--- /dev/null
+++ b/Docs/changelog-5.0.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
+<!--
+This is a dummy changelog file. Don't use it yet.
+It merges upward without conflict.
+-->
+<appendix id="news-5.0-x">
+
+ <title>
+ Changes in release 5.0.x
+ </title>
+
+ <para>
+ This is a dummy changelog file. Don't use it yet.
+ </para>
+
+</appendix>
diff --git a/Docs/sp-imp-spec.txt b/Docs/sp-imp-spec.txt
new file mode 100644
index 00000000000..ac17a375926
--- /dev/null
+++ b/Docs/sp-imp-spec.txt
@@ -0,0 +1,1100 @@
+
+ Implementation specification for Stored Procedures
+ ==================================================
+
+
+- How parsing and execution of queries work
+
+ In order to execute a query, the function sql_parse.cc:mysql_parse() is
+ called, which in turn calls the parser (yyparse()) with an updated Lex
+ structure as the result. mysql_parse() then calls mysql_execute_command()
+ which dispatches on the command code (in Lex) to the corresponding code for
+ executing that particular query.
+
+ There are three structures involved in the execution of a query which are of
+ interest to the stored procedure implementation:
+
+ - Lex (mentioned above) is the "compiled" query, that is the output from
+ the parser and what is then interpreted to do the actual work.
+ It constains an enum value (sql_command) which is the query type, and
+ all the data collected by the parser needed for the execution (table
+ names, fields, values, etc).
+ - THD is the "run-time" state of a connection, containing all that is
+ needed for a particular client connection, and, among other things, the
+ Lex structure currently being executed.
+ - Item_*: During parsing, all data is translated into "items", objects of
+ the subclasses of "Item", such as Item_int, Item_real, Item_string, etc,
+ for basic datatypes, and also various more specialized Item types for
+ expressions to be evaluated (Item_func objects).
+
+
+- How to fit Stored Procedure into this scheme
+
+ - An overview of the classes and files for stored procedures
+ (More detailed APIs at the end of this file)
+
+ - class sp_head (sp_head.{cc,h})
+ This contains, among other things, an array of "instructions" and the
+ method for executing the procedure.
+
+ - class sp_pcontext (sp_pcontext.{cc,h}
+ This is the parse context for the procedure. It's primarily used during
+ parsing to keep track of local parameters, variables and labels, but
+ it's also used at CALL time do find parameters mode (IN, OUT or INOUT)
+ and type when setting up the runtime context.
+
+ - class sp_instr (sp_head.{cc,h})
+ This is the base class for "instructions", that is, what is generated
+ by the parser. It turns out that we only need a minimum of 5 different
+ sub classes:
+ - sp_instr_stmt
+ Execute a statement. This is the "call-out" any normal SQL statement,
+ like a SELECT, INSERT etc. It contains the Lex structure for the
+ statement in question.
+ - sp_instr_set
+ Set the value of a local variable (or parameter)
+ - sp_instr_jump
+ An unconditional jump.
+ - sp_instr_jump_if_not
+ Jump if condition is not true. It turns out that the negative test is
+ most convenient when generating the code for the flow control
+ constructs.
+ - sp_instr_freturn
+ Return a value from a FUNCTION and exit.
+ For condition HANDLERs some special instructions are also needed, see
+ that section below.
+
+ - class sp_rcontext (sp_rcontext.h)
+ This is the runtime context in the THD structure.
+ It contains an array of items, the parameters and local variables for
+ the currently executing stored procedure.
+ This means that variable value lookup is in runtime is constant time,
+ a simple index operation.
+
+ - class Item_splocal (Item.{cc,h})
+ This is a subclass of Item. Its sole purpose is to hide the fact that
+ the real Item is actually in the current frame (runtime context).
+ It contains the frame offset and defers all methods to the real Item
+ in the frame. This is what the parser generates for local variables.
+
+ - Utility functions (sp.{cc,h})
+ This contains functions for creating, dropping and finding a stored
+ procedure in the mysql.proc table (or the internal cache).
+
+
+ - Parsing CREATE PROCEDURE ...
+
+ When parsing a CREATE PROCEDURE the parser first initializes the
+ sphead and spcont (runtime context) fields in the Lex.
+ The sql_command code for the result of parsing a is
+ SQLCOM_CREATE_PROCEDURE.
+
+ The parsing of the parameter list and body is relatively
+ straight-forward:
+
+ - Parameters:
+ name, type and mode (IN/OUT/INOUT) is pushed to spcont
+ - Declared local variables:
+ Same as parameters (mode is then IN)
+ - Local Variable references:
+ If an identifier is found in in spcont, an Item_splocal is created
+ with the variable's frame index, otherwise an Item_field or Item_ref
+ is created (as before).
+ - Statements:
+ The Lex in THD is replaced by a new Lex structure and the statement,
+ is parsed as usual. A sp_instr_stmt is created, containing the new
+ Lex, and added to added to the instructions in sphead.
+ Afterwards, the procedure's Lex is restored in THD.
+ - SET var:
+ Setting a local variable generates a sp_instr_set instruction,
+ containing the variable's frame offset, the expression (an Item),
+ and the type.
+ - Flow control:
+ Flow control constructs like, IF, WHILE, etc, generate a conditional
+ and unconditional jumps in the "obvious" way, but a few notes may
+ be required:
+ - Forward jumps: When jumping forward, the exact destination is not
+ known at the time of the creation of the jump instruction. The
+ sphead therefore contains list of instruction-label pairs for
+ each forward reference. When the position later is known, the
+ instructions in the list are updated with the correct location.
+ - Loop constructs have optional labels. If a loop doesn't have a
+ label, an anonymous label is generated to simplify the parsing.
+ - There are two types of CASE. The "simple" case is implemented
+ with an anonymous variable bound to the value to be tested.
+
+
+ - A simple example
+
+ Parsing the procedure:
+
+ create procedure a(s char(16))
+ begin
+ declare x int;
+ set x = 3;
+ while x > 0 do
+ set x = x-1;
+ insert into db.tab values (x, s);
+ end while;
+ end
+
+ would generate the following structures:
+ ______
+ thd: | | _________
+ | lex -+--->| | ___________________
+ |______| | spcont -+------------------->| "s",in,char(16):0 |
+ | sphead -+------ |("x",in,int :1)|
+ |_________| | |___________________|
+ ____V__________________
+ | m_name: "a" |
+ | m_defstr: "create ..."|
+ | m_instr: ... |
+ |_______________________|
+
+ Note that the contents of the spcont is changing during the parsing,
+ at all times reflecting the state of the would-be runtime frame.
+ The m_instr is an array of instructions:
+
+ Pos. Instruction
+ 0 sp_instr_set(1, '3')
+ 1 sp_instr_jump_if_not(5, 'x>0')
+ 2 sp_instr_set(1, 'x-1')
+ 3 sp_instr_stmt('insert into ...')
+ 4 sp_instr_jump(1)
+ 5 <end>
+
+ Here, '3', 'x>0', etc, represent the Items or Lex for the respective
+ expressions or statements.
+
+
+ - Parsing CREATE FUNCTION ...
+
+ Creating a functions is essensially the same thing as for a PROCEDURE,
+ with the addition that a FUNCTION has a return type and a RETURN
+ statement, but no OUT or INOUT parameters.
+
+ The main difference during parsing is that we store the result type
+ in the sp_head. However, there are big differences when it comes to
+ invoking a FUNCTION. (See below.)
+
+
+ - Storing, caching, dropping...
+
+ As seen above, the entired definition string, including the "CREATE
+ PROCEDURE" (or "FUNCTION") is kept. The procedure definition string is
+ stored in the table mysql.proc with the name and type as the key, the
+ type being one of the enum ("procedure","function").
+
+ A PROCEDURE is just stored in the mysql.proc table. A FUNCTION has an
+ additional requirement. They will be called in expressions with the same
+ syntax as UDFs, so UDFs and stored FUNCTIONs share the namespace. Thus,
+ we must make sure that we do not have UDFs and FUNCTIONs with the same
+ name (even if they are storded in different places).
+
+ This means that we can reparse the procedure as many time as we want.
+ The first time, the resulting Lex is used to store the procedure in
+ the database (using the function sp.c:sp_create_procedure()).
+
+ The simplest way would be to just leave it at that, and re-read the
+ procedure from the database each time it is called. (And in fact, that's
+ the way the earliest implementation will work.)
+ However, this is not very efficient, and we can do better. The full
+ implementation should work like this:
+
+ 1) Upon creation time, parse and store the procedure. Note that we still
+ need to parse it to catch syntax errors, but we can't check if called
+ procedures exists for instance.
+ 2) Upon first CALL, read from the database, parse it, and cache the
+ resulting Lex in memory. This time we can do more error checking.
+ 3) Upon subsequent CALLs, use the cached Lex.
+
+ Note that this implies that the Lex structure with its sphead must be
+ reentrant, that is, reusable and shareable between different threads
+ and calls. The runtime state for a procedure is kept in the sp_rcontext
+ in THD.
+
+ The mechanisms of storing, finding, and dropping procedures are
+ encapsulated in the files sp.{cc,h}.
+
+
+ - CALLing a procedure
+
+ A CALL is parsed just like any statement. The resulting Lex has the
+ sql_command SQLCOM_CALL, the procedure's name and the parameters are
+ pushed to the Lex' value_list.
+
+ sql_parse.cc:mysql_execute_command() then uses sp.cc:sp_find() to
+ get the sp_head for the procedure (which may have been read from the
+ database or feetched from the in-memory cache) and calls the sp_head's
+ method execute().
+ Note: It's important that substatements called by the procedure do not
+ do send_ok(). Fortunately, there is a flag in THD->net to disable
+ this during CALLs. If a substatement fails, it will however send
+ an error back to the client, so the CALL mechanism must return
+ immediately and without sending an error.
+
+ The sp_head::execute() method works as follows:
+
+ 1) Keep a pointer to the old runtime context in THD (if any)
+ 2) Create a new runtime context. The information about the required size
+ is in sp_head's parse time context.
+ 3) Push each parameter (from the CALL's Lex->value_list) to the new
+ context. If it's an OUT or INOUT parameter, the parameter's offset
+ in the caller's frame is set in the new context as well.
+ 4) For each instruction, call its execute() method.
+ The result is a pointer to the next instruction to execute (or NULL)
+ if an error occured.
+ 5) On success, set the new values of the OUT and INOUT parameters in
+ the caller's frame.
+
+ - USE database
+
+ Before executing the instruction we also keeps the current default
+ database (if any). If this was changed during execution (i.e. a "USE"
+ statement has been executed), we restore the current database to the
+ original.
+
+ This is the most useful way to handle USE in procedures. If we didn't,
+ the caller would find himself in a different database after calling
+ a function, which can be confusing.
+ Restoring the database also gives full freedom to the procedure writer:
+ - It's possible to write "general" procedures that are independent of
+ the actual database name.
+ - It's possible to write procedures that work on a particular database
+ by calling USE, without having to use fully qualified table names
+ everywhere (which doesn't help if you want to call other, "general",
+ procedures anyway).
+
+ - Evaluating Items
+
+ There are three occasions where we need to evaluate an expression:
+
+ - When SETing a variable
+ - When CALLing a procedure
+ - When testing an expression for a branch (in IF, WHILE, etc)
+
+ The semantics in stored procedures is "call-by-value", so we have to
+ evaluate any "func" Items at the point of the CALL or SET, otherwise
+ we would get a kind of "lazy" evaluation with unexpected results with
+ respect to OUT parameters for instance.
+ For this the support function, sp_head.cc:eval_func_item() is needed.
+
+
+ - Calling a FUNCTION
+
+ Functions don't have an explicit call keyword like procedures. Instead,
+ they appear in expressions with the conventional syntax "fun(arg, ...)".
+ The problem is that we already have User Defined Functions (UDFs) which
+ are called the same way. A UDF is detected by the lexical analyzer (not
+ the parser!), in the find_keyword() function, and returns a UDF_*_FUNC
+ or UDA_*_SUM token with the udf_func object as the yylval.
+
+ So, stored functions must be handled in a simpilar way, and as a
+ consequence, UDFs and functions must not have the same name.
+
+ - Detecting and parsing a FUNCTION invocation
+
+ The existance of UDFs are checked during the lexical analysis (in
+ sql_lex.cc:find_keyword()). This has the drawback that they must
+ exist before they are refered to, which was ok before SPs existed,
+ but then it becomes a problem. The first implementation of SP FUNCTIONs
+ will work the same way, but this should be fixed a.s.a.p. (This will
+ required some reworking of the way UDFs are handled, which is why it's
+ not done from the start.)
+ For the time being, a FUNCTION is detected the same way, and returns
+ the token SP_FUNC. During the parsing we only check for the *existance*
+ of the function, we don't parse it, since wa can't call the parser
+ recursively.
+
+ When encountering a SP_FUNC with parameters in the expression parser,
+ an instance of the new Item_func_sp class is created. Unlike UDFs, we
+ don't have different classes for different return types, since we at
+ this point don't know the type.
+
+ - Collecting FUNCTIONs to invoke
+
+ A FUNCTION differs from a PROCEDURE in one important aspect: Whereas a
+ PROCEDURE is CALLed as statement by itself, a FUNCTION is invoked
+ "on-the-fly" during the execution of *another* statement.
+ This makes things a lot more complicated compared to CALL:
+ - We can't read and parse the FUNCTION from the mysql.proc table at the
+ point of invocation; the server requires that all tables used are
+ opened and locked at the beginning of the query execution.
+ One "obvious" solution would be to simply push "mysql.proc" to the list
+ of tables used by the query, but this implies a "join" with this table
+ if the query is a select, so it doesn't work (and we can't exclude this
+ table easily; since a priviledged used might in fact want to search
+ the proc table).
+ Another solution would of course be to allow the opening and closing
+ of the mysql.proc table during a query execution, but this it not
+ possible at the present.
+
+ So, the solution is to collect the names of the refered FUNCTIONs during
+ parsing in the lex.
+ Then, before doing anything else in mysql_execute_command(), read all
+ functions from the database an keep them in the THD, where the function
+ sp_find_function() can find them during the execution.
+ Note: Even with an in-memory cache, we must still make sure that the
+ functions are indeed read and cached at this point.
+ The code that read and cache functions from the database must also be
+ invoked recursively for each read FUNCTION to make sure we have *all* the
+ functions we need.
+
+
+ - Parsing DROP PROCEDURE/FUNCTION
+
+ The procedure name is pushed to Lex->value_list.
+ The sql_command code for the result of parsing a is
+ SQLCOM_DROP_PROCEDURE/SQLCOM_DROP_FUNCTION.
+
+ Dropping is done by simply getting the procedure with the sp_find()
+ function and calling sp_drop() (both in sp.{cc,h}).
+
+ DROP PROCEDURE/FUNCTION also supports the non-standard "IF EXISTS",
+ analogous to other DROP statements in MySQL.
+
+
+ - Condition and Handlers
+
+ Condition names are lexical entities and are kept in the parser context
+ just like variables. But, condition are just "aliases" for SQLSTATE
+ strings, or mysqld error codes (which is a non-standard extension in
+ MySQL), and are only used during parsing.
+
+ Handlers comes in three types, CONTINUE, EXIT and UNDO. The latter is
+ like an EXIT handler with an implicit rollback, and is currently not
+ implemented.
+ The EXIT handler jumps to the end of its BEGIN-END block when finished.
+ The CONTINUE handler returns to the statement following that which
+ invoked the handler.
+
+ The handlers in effect at any point is part of each thread's runtime
+ state, so we need to push and pop handlers in the sp_rcontext during
+ execution. We use special instructions for this:
+ - sp_instr_hpush_jump
+ Push a handler. The instruction contains the necessary information,
+ like which conditions we handle and the location of the handler.
+ The jump takes us to the location after the handler code.
+ - sp_instr_hpop
+ Pop the handlers of the current frame (which we are just leaving).
+
+ It might seems strange to jump past the handlers like that, but there's
+ no extra cost in doing this, and for technical reasons it's easiest for
+ the parser to generate the handler instructions when they occur in the
+ source.
+
+ When an error occurs, one of the error routines is called and an error
+ message is normally sent back to the client immediately.
+ Catching a condition must be done in these error routines (there are
+ quite a few) to prevent them from doing this. We do this by calling
+ a method in the THD's sp_rcontext (if there is one). If a handler is
+ found, this is recorded in the context and the routine returns without
+ sending the error message.
+ The exectution loop (sp_head::execute()) checks for this after each
+ statement and invokes the handler that has been found. If several
+ errors or warnings occurs during one statement, only the first is
+ caught, the rest are ignored.
+
+ Invoking and returning from a handler is trivial in the EXIT case.
+ We simply jump to it, and it will have an sp_instr_jump as its last
+ instruction.
+
+ Calling and returning from a CONTINUE handler poses some special
+ problems. Since we need to return to the point after its invokation,
+ we push the return location on a stack in the sp_rcontext (this is
+ done by the exectution loop). The handler then ends with a special
+ instruction, sp_instr_hreturn, which returns to this location.
+
+ CONTINUE handlers have one additional problem: They are parsed at
+ the lexical level where they occur, so variable offsets will assume
+ that it's actually called at that level. However, a handler might be
+ invoked from a sub-block where additional local variables have been
+ declared, which will then share the location of any local variables
+ in the handler itself. So, when calling a CONTINUE handler, we need
+ to save any local variables above the handler's frame offset, and
+ restore them upon return. (This is not a problem for EXIT handlers,
+ since they will leave the block anyway.)
+ This is taken care of by the execution loop and the sp_instr_hreturn
+ instruction.
+
+ - Examples:
+
+ - EXIT handler
+ begin
+ declare x int default 0;
+
+ begin
+ declare exit handler for 'XXXXX' set x = 1;
+
+ (statement1);
+ (statement2);
+ end;
+ (statement3);
+ end
+
+ Pos. Instruction
+ 0 sp_instr_set(0, '0')
+ 1 sp_instr_hpush_jump(4, 1) # location and frame size
+ 2 sp_instr_set(0, '1')
+ 3 sp_instr_jump(6)
+ 4 sp_instr_stmt('statement1')
+ 5 sp_instr_stmt('statement2')
+ 6 sp_instr_hpop(1)
+ 7 sp_instr_stmt('statement3')
+
+ - CONTINUE handler
+ create procedure hndlr1(val int)
+ begin
+ declare x int default 0;
+ declare foo condition for 1146;
+ declare continue handler for foo set x = 1;
+
+ insert into t3 values ("hndlr1", val); # Non-existing table?
+ if x>0 then
+ insert into t1 values ("hndlr1", val); # This instead then
+ end if;
+ end|
+
+ Pos. Instruction
+ 0 sp_instr_set(1, '0')
+ 1 sp_instr_hpush_jump(4, 2)
+ 2 sp_instr_set(1, '1')
+ 3 sp_instr_hreturn(2) # frame size
+ 4 sp_instr_stmt('insert ... t3 ...')
+ 5 sp_instr_jump_if_not(7, 'x>0')
+ 6 sp_instr_stmt('insert ... t1 ...')
+ 7 sp_instr_hpop(2)
+
+
+ - Cursors
+
+ For stored procedures to be really useful, you want to have cursors.
+ MySQL doesn't yet have "real" cursor support (with API and ODBC support,
+ allowing updating, arbitrary scrolling, etc), but a simple asensitive,
+ non-scrolling, read-only cursor can be implemented in SPs using the
+ class Protocol_cursor.
+ This class intecepts the creation and sending of results sets and instead
+ stores it in-memory, as MYSQL_FIELDS and MYSQL_ROWS (as in the client API).
+
+ To support this, we need the usual name binding support in sp_pcontext
+ (similar to variables and conditions) to keep track on declared cursor
+ names, and a corresponding run-time mechanism in sp_rcontext.
+ Cursors are lexically scoped like everything with a body or BEGIN/END
+ block, so they are pushed and poped as usual (see conditions and variables
+ above).
+ The basic operations on a cursor are OPEN, FETCH and CLOSE, which will
+ each have a corresponding instruction. In addition, we need instructions
+ to push a new cursor (this will encapsulate the LEX of the SELECT statement
+ of the cursor), and a pop instruction:
+ - sp_instr_cpush
+ Push a cursor to the sp_rcontext. This instruction contains the LEX
+ for the select statement
+ - sp_instr_cpop
+ Pop a number of cursors from the sp_rcontext.
+ - sp_instr_copen
+ Open a cursor: This will execute the select and get the result set
+ in a sepeate memroot.
+ - sp_instr_cfetch
+ Fetch the next row from the in-memory result set. The instruction
+ contains a list of the variables (frame offsets) to set.
+ - sp_instr_cclose
+ Free the result set.
+
+ A cursor is a separate class, sp_cursor (defined in sp_rcontex.h) which
+ encapsulates the basic operations used by the above instructions.
+ This class contains the LEX, Protocol_cursor object, and its memroot,
+ as well as the cursor's current state.
+ Compiling and executing is fairly straight-forward. sp_instr_copen is
+ a subclass of sp_instr_stmt and uses its mechanism to execute a
+ substatement.
+
+ - Example:
+
+ begin
+ declare x int;
+ declare c cursor for select a from t1;
+
+ open c;
+ fetch c into x;
+ close c;
+ end
+
+ Pos. Instruction
+ 0 sp_instr_cpush('select a from ...')
+ 1 sp_instr_copen(0) # The 0'th cursor
+ 2 sp_instr_cfetch(0) # Contains the variable list
+ 3 sp_instr_cclose(0)
+ 4 sp_instr_cpop(1)
+
+
+
+ - The SP cache
+
+ There are two ways to cache SPs:
+
+ 1) one global cache, share by all threads/connections,
+ 2) one cache per thread.
+
+ There are pros and cons with both methods:
+
+ 1) Pros: Save memory, each SP only read from table once,
+ Cons: Needs locking (= serialization at access), requires thread-safe
+ data structures,
+ 2) Pros: Fast, no locking required (almost), limited thread-safe
+ requirement,
+ Cons: Uses more memory, each SP read from table once per thread.
+
+ Unfortunately, we cannot use alternative 1 for the time being, as most
+ of the datastructures to be cached (lex and items) are not reentrant
+ and thread-safe. (Things are modifed at execution, we have THD pointers
+ stored everywhere, etc.)
+ This leaves us with alternative 2, one cache per thread; or actually
+ two, since we keep FUNCTIONs and PROCEDUREs in separate caches.
+ This is not that terrible; the only case when it will perform
+ significantly worse than a global cache is when we have an application
+ where new threads are connecting, calling a procedure, and disconnecting,
+ over and over again.
+
+ The cache implementation itself is simple and straightforward, a hashtable
+ wrapped in a class and a C API (see APIs below).
+
+ There is however one issue with multiple caches: dropping and altering
+ procedures. Normally, this should be a very rare event in a running
+ system; it's typically something you do during development and testing,
+ so it's not unthinkable that we would simply ignore the issue and let
+ any threads running with a cached version of an SP keep doing so until
+ its disconnected.
+ But assuming we want to keep the caches consistent with respect to drop
+ and alter, it can be done:
+
+ 1) A global counter is needed, initialized to 0 at start.
+ 2) At each DROP or ALTER, increase the counter by one.
+ 3) Each cache has its own copy of the counter, copied at the last read.
+ 4) When looking up a name in the cache, first check if the global counter
+ is larger than the local copy.
+ If so, clear the cache and return "not found", and update the local
+ counter; otherwise, lookup as usual.
+
+ This minimizes the cost to a single brief lock for the access of an
+ integer when operating normally. Only in the event of an actual drop or
+ alter, is the cache cleared. This may seem to be drastic, but since we
+ assume that this is a rare event, it's not a problem.
+ It would of course be possible to have a much more fine-grained solution,
+ keeping track of each SP, but the overhead of doing so is not worth the
+ effort.
+
+
+ - Class and function APIs
+ This is an outline of the key types. Some types and other details
+ in the actual files have been omitted for readability.
+
+ - The parser context: sp_pcontext.h
+
+ typedef enum
+ {
+ sp_param_in,
+ sp_param_out,
+ sp_param_inout
+ } sp_param_mode_t;
+
+ typedef struct
+ {
+ LEX_STRING name;
+ enum enum_field_types type;
+ sp_param_mode_t mode;
+ uint offset; // Offset in current frame
+ my_bool isset;
+ } sp_pvar_t;
+
+ typedef struct sp_cond_type
+ {
+ enum { number, state, warning, notfound, exception } type;
+ char sqlstate[6];
+ uint mysqlerr;
+ } sp_cond_type_t;
+
+ class sp_pcontext
+ {
+ sp_pcontext();
+
+ // Return the maximum frame size
+ uint max_framesize();
+
+ // Return the current frame size
+ uint current_framesize();
+
+ // Return the number of parameters
+ uint params();
+
+ // Set the number of parameters to the current frame size
+ void set_params();
+
+ // Set type of the variable at offset 'i' in the frame
+ void set_type(uint i, enum enum_field_types type);
+
+ // Mark the i:th variable to "set" (i.e. having a value) with
+ // 'val' true.
+ void set_isset(uint i, my_bool val);
+
+ // Push the variable 'name' to the frame.
+ void push_var(LEX_STRING *name,
+ enum enum_field_types type, sp_param_mode_t mode);
+
+ // Pop 'num' variables from the frame.
+ void pop_var(uint num = 1);
+
+ // Find variable by name
+ sp_pvar_t *find_pvar(LEX_STRING *name);
+
+ // Find variable by index
+ sp_pvar_t *find_pvar(uint i);
+
+ // Push label 'name' of instruction index 'ip' to the label context
+ sp_label_t *push_label(char *name, uint ip);
+
+ // Find label 'name' in the context
+ sp_label_t *find_label(char *name);
+
+ // Return the last pushed label
+ sp_label_t *last_label();
+
+ // Return and remove the last pushed label.
+ sp_label_t *pop_label();
+
+ // Push a condition to the context
+ void push_cond(LEX_STRING *name, sp_cond_type_t *val);
+
+ // Pop a 'num' condition from the context
+ void pop_cond(uint num);
+
+ // Find a condition in the context
+ sp_cond_type_t *find_cond(LEX_STRING *name);
+
+ // Increase the handler count
+ void add_handler();
+
+ // Returns the handler count
+ uint handlers();
+
+ // Push a cursor
+ void push_cursor(LEX_STRING *name);
+
+ // Find a cursor
+ my_bool find_cursor(LEX_STRING *name, uint *poff);
+
+ // Pop 'num' cursors
+ void pop_cursor(uint num);
+
+ // Return the number of cursors
+ uint cursors();
+ }
+
+
+ - The run-time context (call frame): sp_rcontext.h
+
+ #define SP_HANDLER_NONE 0
+ #define SP_HANDLER_EXIT 1
+ #define SP_HANDLER_CONTINUE 2
+ #define SP_HANDLER_UNDO 3
+
+ typedef struct
+ {
+ struct sp_cond_type *cond;
+ uint handler; // Location of handler
+ int type;
+ uint foffset; // Frame offset for the handlers declare level
+ } sp_handler_t;
+
+ class sp_rcontext
+ {
+ // 'fsize' is the max size of the context, 'hmax' the number of handlers,
+ // 'cmax' the number of cursors
+ sp_rcontext(uint fsize, uint hmax, , uint cmax);
+
+ // Push value (parameter) 'i' to the frame
+ void push_item(Item *i);
+
+ // Set slot 'idx' to value 'i'
+ void set_item(uint idx, Item *i);
+
+ // Return the item in slot 'idx'
+ Item *get_item(uint idx);
+
+ // Set the "out" index 'oidx' for slot 'idx. If it's an IN slot,
+ // use 'oidx' -1.
+ void set_oindex(uint idx, int oidx);
+
+ // Return the "out" index for slot 'idx'
+ int get_oindex(uint idx);
+
+ // Set the FUNCTION result
+ void set_result(Item *i);
+
+ // Get the FUNCTION result
+ Item *get_result();
+
+ // Push handler at location 'h' for condition 'cond'. 'f' is the
+ // current variable frame size.
+ void push_handler(sp_cond_type_t *cond, uint h, int type, uint f);
+
+ // Pop 'count' handlers
+ void pop_handlers(uint count);
+
+ // Find a handler for this error. This sets the state for a found
+ // handler in the context. If called repeatedly without clearing,
+ // only the first call's state is kept.
+ int find_handler(uint sql_errno);
+
+ // Returns 1 if a handler has been found, with '*ip' and '*fp' set
+ // to the handler location and frame size respectively.
+ int found_handler(uint *ip, uint *fp);
+
+ // Clear the found handler state.
+ void clear_handler();
+
+ // Push a return address for a CONTINUE handler
+ void push_hstack(uint ip);
+
+ // Pop the CONTINUE handler return stack
+ uint pop_hstack();
+
+ // Save variables from frame index 'fp' and up.
+ void save_variables(uint fp);
+
+ // Restore saved variables from to frame index 'fp' and up.
+ void restore_variables(uint fp);
+
+ // Push a cursor for the statement (lex)
+ void push_cursor(LEX *lex);
+
+ // Pop 'count' cursors
+ void pop_cursors(uint count);
+
+ // Pop all cursors
+ void pop_all_cursors();
+
+ // Get the 'i'th cursor
+ sp_cursor *get_cursor(uint i);
+
+ }
+
+
+ - The procedure: sp_head.h
+
+ #define TYPE_ENUM_FUNCTION 1
+ #define TYPE_ENUM_PROCEDURE 2
+
+ class sp_head
+ {
+ int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
+
+ sp_head();
+
+ void init(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid);
+
+ // Store this procedure in the database. This is a wrapper around
+ // the function sp_create_procedure().
+ int create(THD *);
+
+ // Invoke a FUNCTION
+ int
+ execute_function(THD *thd, Item **args, uint argcount, Item **resp);
+
+ // CALL a PROCEDURE
+ int
+ execute_procedure(THD *thd, List<Item> *args);
+
+ // Add the instruction to this procedure.
+ void add_instr(sp_instr *);
+
+ // Returns the number of instructions.
+ uint instructions();
+
+ // Returns the last instruction
+ sp_instr *last_instruction();
+
+ // Resets lex in 'thd' and keeps a copy of the old one.
+ void reset_lex(THD *);
+
+ // Restores lex in 'thd' from our copy, but keeps some status from the
+ // one in 'thd', like ptr, tables, fields, etc.
+ void restore_lex(THD *);
+
+ // Put the instruction on the backpatch list, associated with
+ // the label.
+ void push_backpatch(sp_instr *, struct sp_label *);
+
+ // Update all instruction with this label in the backpatch list to
+ // the current position.
+ void backpatch(struct sp_label *);
+
+ // Returns the SP name (with optional length in '*lenp').
+ char *name(uint *lenp = 0);
+
+ // Returns the result type for a function
+ Item_result result();
+
+ // Sets various attributes
+ void sp_set_info(char *creator, uint creatorlen,
+ longlong created, longlong modified,
+ bool suid, char *comment, uint commentlen);
+ }
+
+
+ - Instructions
+
+ - The base class:
+ class sp_instr
+ {
+ // 'ip' is the index of this instruction
+ sp_instr(uint ip);
+
+ // Execute this instrution.
+ // '*nextp' will be set to the index of the next instruction
+ // to execute. (For most instruction this will be the
+ // instruction following this one.)
+ // Returns 0 on success, non-zero if some error occured.
+ virtual int execute(THD *, uint *nextp)
+ }
+
+ - Statement instruction:
+ class sp_instr_stmt : public sp_instr
+ {
+ sp_instr_stmt(uint ip);
+
+ int execute(THD *, uint *nextp);
+
+ // Set the statement's Lex
+ void set_lex(LEX *);
+
+ // Return the statement's Lex
+ LEX *get_lex();
+ }
+
+ - SET instruction:
+ class sp_instr_set : public sp_instr
+ {
+ // 'offset' is the variable's frame offset, 'val' the value,
+ // and 'type' the variable type.
+ sp_instr_set(uint ip,
+ uint offset, Item *val, enum enum_field_types type);
+
+ int execute(THD *, uint *nextp);
+ }
+
+ - Unconditional jump
+ class sp_instr_jump : public sp_instr
+ {
+ // No destination, must be set.
+ sp_instr_jump(uint ip);
+
+ // 'dest' is the destination instruction index.
+ sp_instr_jump(uint ip, uint dest);
+
+ int execute(THD *, uint *nextp);
+
+ // Set the destination instruction 'dest'.
+ void set_destination(uint dest);
+ }
+
+ - Conditional jump
+ class sp_instr_jump_if_not : public sp_instr_jump
+ {
+ // Jump if 'i' evaluates to false. Destination not set yet.
+ sp_instr_jump_if_not(uint ip, Item *i);
+
+ // Jump to 'dest' if 'i' evaluates to false.
+ sp_instr_jump_if_not(uint ip, Item *i, uint dest)
+
+ int execute(THD *, uint *nextp);
+ }
+
+ - Return a function value
+ class sp_instr_freturn : public sp_instr
+ {
+ // Return the value 'val'
+ sp_instr_freturn(uint ip, Item *val, enum enum_field_types type);
+
+ int execute(THD *thd, uint *nextp);
+ }
+
+ - Push a handler and jump
+ class sp_instr_hpush_jump : public sp_instr_jump
+ {
+ // Push handler of type 'htype', with current frame size 'fp'
+ sp_instr_hpush_jump(uint ip, int htype, uint fp);
+
+ int execute(THD *thd, uint *nextp);
+
+ // Add condition for this handler
+ void add_condition(struct sp_cond_type *cond);
+ }
+
+ - Pops handlers
+ class sp_instr_hpop : public sp_instr
+ {
+ // Pop 'count' handlers
+ sp_instr_hpop(uint ip, uint count);
+
+ int execute(THD *thd, uint *nextp);
+ }
+
+ - Return from a CONTINUE handler
+ class sp_instr_hreturn : public sp_instr
+ {
+ // Return from handler, and restore variables to 'fp'.
+ sp_instr_hreturn(uint ip, uint fp);
+
+ int execute(THD *thd, uint *nextp);
+ }
+
+ - Push a CURSOR
+ class sp_instr_cpush : public sp_instr_stmt
+ {
+ // Push a cursor for statement 'lex'
+ sp_instr_cpush(uint ip, LEX *lex)
+
+ int execute(THD *thd, uint *nextp);
+ }
+
+ - Pop CURSORs
+ class sp_instr_cpop : public sp_instr_stmt
+ {
+ // Pop 'count' cursors
+ sp_instr_cpop(uint ip, uint count)
+
+ int execute(THD *thd, uint *nextp);
+ }
+
+ - Open a CURSOR
+ class sp_instr_copen : public sp_instr_stmt
+ {
+ // Open the 'c'th cursor
+ sp_instr_copen(uint ip, uint c);
+
+ int execute(THD *thd, uint *nextp);
+ }
+
+ - Close a CURSOR
+ class sp_instr_cclose : public sp_instr
+ {
+ // Close the 'c'th cursor
+ sp_instr_cclose(uint ip, uint c);
+
+ int execute(THD *thd, uint *nextp);
+ }
+
+ - Fetch a row with CURSOR
+ class sp_instr_cfetch : public sp_instr
+ {
+ // Fetch next with the 'c'th cursor
+ sp_instr_cfetch(uint ip, uint c);
+
+ int execute(THD *thd, uint *nextp);
+
+ // Add a target variable for the fetch
+ void add_to_varlist(struct sp_pvar *var);
+ }
+
+
+ - Utility functions: sp.h
+
+ #define SP_OK 0
+ #define SP_KEY_NOT_FOUND -1
+ #define SP_OPEN_TABLE_FAILED -2
+ #define SP_WRITE_ROW_FAILED -3
+ #define SP_DELETE_ROW_FAILED -4
+ #define SP_GET_FIELD_FAILED -5
+ #define SP_PARSE_ERROR -6
+
+ // Finds a stored procedure given its name. Returns NULL if not found.
+ sp_head *sp_find_procedure(THD *, LEX_STRING *name);
+
+ // Store the procedure 'name' in the database. 'def' is the complete
+ // definition string ("create procedure ...").
+ int sp_create_procedure(THD *,
+ char *name, uint namelen,
+ char *def, uint deflen,
+ char *comment, uint commentlen, bool suid);
+
+ // Drop the procedure 'name' from the database.
+ int sp_drop_procedure(THD *, char *name, uint namelen);
+
+ // Finds a stored function given its name. Returns NULL if not found.
+ sp_head *sp_find_function(THD *, LEX_STRING *name);
+
+ // Store the function 'name' in the database. 'def' is the complete
+ // definition string ("create function ...").
+ int sp_create_function(THD *,
+ char *name, uint namelen,
+ char *def, uint deflen,
+ char *comment, uint commentlen, bool suid);
+
+ // Drop the function 'name' from the database.
+ int sp_drop_function(THD *, char *name, uint namelen);
+
+
+ - The cache: sp_cache.h
+
+ /* Initialize the SP caching once at startup */
+ void sp_cache_init();
+
+ /* Clear the cache *cp and set *cp to NULL */
+ void sp_cache_clear(sp_cache **cp);
+
+ /* Insert an SP to cache. If **cp points to NULL, it's set to a
+ new cache */
+ void sp_cache_insert(sp_cache **cp, sp_head *sp);
+
+ /* Lookup an SP in cache */
+ sp_head *sp_cache_lookup(sp_cache **cp, char *name, uint namelen);
+
+ /* Remove an SP from cache */
+ void sp_cache_remove(sp_cache **cp, sp_head *sp);
+
+
+ - The mysql.proc schema:
+
+ CREATE TABLE proc (
+ db char(64) binary 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') 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,
+ created timestamp,
+ modified timestamp,
+ 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'
+ ) DEFAULT 0 NOT NULL,
+ comment char(64) binary DEFAULT '' NOT NULL,
+ PRIMARY KEY (db,name,type)
+ ) comment='Stored Procedures';
+
+ --
+ \ No newline at end of file
diff --git a/Docs/sp-implemented.txt b/Docs/sp-implemented.txt
new file mode 100644
index 00000000000..6f2cf49b3b0
--- /dev/null
+++ b/Docs/sp-implemented.txt
@@ -0,0 +1,112 @@
+Stored Procedures implemented 2004-01-29:
+
+
+Summary of what's implemented:
+
+ - SQL PROCEDUREs/FUNCTIONs (CREATE/DROP)
+ - CALL
+ - DECLARE of local variables
+ - BEGIN/END, SET, CASE, IF, LOOP, WHILE, REPEAT, ITERATE, LEAVE
+ - SELECT INTO local variables
+ - "Non-query" FUNCTIONs only
+ - Prepared SP caching
+ - CONDITIONs and HANDLERs
+ - Simple read-only CURSORs.
+ - SHOW CREATE PROCEDURE/FUNCTION and SHOW PROCEDURE/FUNCTION STATUS
+
+
+Summary of Not Yet Implemented:
+
+ - SQL statements using tables (like SELECT, INSERT, UPDATE etc) in FUNCTIONs
+ - External languages
+ - Access control
+ - SQL-99 COMMIT (related to BEGIN/END)
+ - FOR-loops
+ - CASCADE/RESTRICT for ALTER and DROP
+ - ALTER/DROP METHOD (as it implies User Defined Types)
+ - SIGNAL and RESIGNAL, and UNDO handlers
+
+
+List of what's implemented:
+
+ - CREATE PROCEDURE|FUNCTION name ( args ) characteristics body
+ where characteristics is:
+ LANGUAGE SQL |
+ [NOT] DETERMINISTIC |
+ SQL SECURITY [DEFINER|INVOKER] |
+ COMMENT string
+ However the DETERMINISTIC setting is not currently used.
+
+ - ALTER PROCEDURE|FUNCTION name characteristics
+ CASCADE/RESTRICT is not implemented.
+ characteristics is:
+ COMMENT string |
+ SQL SECURITY [DEFINER|INVOKER] |
+ NAME newname
+
+ - DROP PROCEDURE|FUNCTION [IF EXISTS] name
+ CASCADE/RESTRICT is not implemented.
+
+ - CALL name (args)
+ OUT and INOUT parameters are also works for user variables ("global"
+ variables) - i.e., if a procedure is defined as:
+ CREATE PROCEDURE foo(OUT p INT) ...;
+ a call like:
+ CALL foo(@x);
+ will set @x to the output value.
+
+ - Function/Procedure body:
+ - BEGIN/END
+ Is parsed, but not the real thing with (optional) transaction
+ control, it only serves as block syntax for multiple statements (and
+ local variable binding).
+ Note: Multiple statements requires a client that can send bodies
+ containing ";". This is handled in the CLI clients mysql and
+ mysqltest with the "delimiter" command. Changing the end-of-query
+ delimiter ";" to for instance "|" allows ";" to be used in the
+ routine body.
+ - SET of local variables
+ Implemented as part of the pre-existing SET syntax. This allows an
+ extended syntax of "SET a=x, b=y, ..." where different variable types
+ (SP local and global) can be mixed. This also allows combinations
+ of local variables and some options that only make sense for
+ global/system variables; in that case the options are accepted but
+ ignored.
+ - The flow control constructs: CASE, IF, LOOP, WHILE, ITERATE and LEAVE
+ are fully implemented.
+ - SELECT ... INTO local variables (as well as global session variables)
+ is implemented. (Note: This is not SQL-99 feature, but common in other
+ databases.)
+ - A FUNCTION can have flow control contructs, but must not contain
+ an SQL query/statement, like SELECT, INSERT, UPDATE, etc. The reason
+ is that it's hard to allow this is that a FUNCTION is executed as part
+ of another query (unlike a PROCEDURE, which is called as a statement).
+ The table locking scheme used makes it difficult to allow "subqueries"
+ during FUNCTION invokation.
+ - SPs are cached, but with a separate cache for each thread (THD).
+ There are still quite a few non-reentrant constructs in the lexical
+ context which makes sharing prepared SPs impossible. And, even when
+ this is resolved, it's not necessarily the case that it will be faster
+ than a cache per thread. A global cache requires locks, which might
+ become a bottleneck. (It would save memory though.)
+ - CONDITIONs and HANDLERs are implemented, but not the SIGNAL and
+ RESIGNAL statements. (It's unclear if these can be implemented.)
+ The semantics of CONDITIONs is expanded to allow catching MySQL error
+ codes as well. UNDO handlers are not implemented (since we don't have
+ SQL-99 style transaction control yet).
+ - Simple read-only CURSORs are implemented, but not yet any of the
+ optional arguments to DECLARE (SCROLL, SENSITIVE, etc) or FETCH
+ (NEXT, PRIOR, etc). Cursors are ASENSITIVE, READ-ONLY, non-SCROLLing.
+ (The additional syntax will be added for completeness, but for the
+ most part unsupported with the current underlying cursor mechanism.)
+ N.B. The current implementation is temporary and only works within a
+ stored procedure, and may not perform well for very large result sets.
+ A "real" cursor implementation is under development; this will replace
+ the current one when it's finished.
+
+ - SHOW procedures and functions
+ SHOW CREATE PROCEDURE|FUNCTION <name>
+ returns the definition of a routine.
+ SHOW PROCEDURE|FUNCTION STATUS [LIKE <pattern>]
+ returns characteristics of routines, like the name, type, creator,
+ creation and modification dates, etc.
diff --git a/Makefile.am b/Makefile.am
index 93f34986a1b..78efd47b762 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,14 +25,14 @@ SUBDIRS = . include @docs_dirs@ @zlib_dir@ \
@thread_dirs@ pstack \
@sql_union_dirs@ scripts man tests \
netware @libmysqld_dirs@ \
- @bench_dirs@ support-files @fs_dirs@ @tools_dirs@
+ @bench_dirs@ support-files @tools_dirs@
DIST_SUBDIRS = . include @docs_dirs@ zlib \
@readline_topdir@ sql-common \
@thread_dirs@ pstack \
@sql_union_dirs@ scripts @man_dirs@ tests SSL\
BUILD netware os2 @libmysqld_dirs@ \
- @bench_dirs@ support-files @fs_dirs@ @tools_dirs@
+ @bench_dirs@ support-files @tools_dirs@
# Relink after clean
linked_sources = linked_client_sources linked_server_sources \
@@ -101,3 +101,6 @@ tags:
test:
cd mysql-test; ./mysql-test-run && ./mysql-test-run --ps-protocol
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/VC++Files/client/mysqlclient.dsp b/VC++Files/client/mysqlclient.dsp
index 75008858e55..157c576b187 100644
--- a/VC++Files/client/mysqlclient.dsp
+++ b/VC++Files/client/mysqlclient.dsp
@@ -147,6 +147,10 @@ SOURCE="..\strings\ctype-bin.c"
# End Source File
# Begin Source File
+SOURCE="..\strings\ctype-cp932.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\strings\ctype-czech.c"
# End Source File
# Begin Source File
@@ -155,6 +159,10 @@ SOURCE="..\strings\ctype-euc_kr.c"
# End Source File
# Begin Source File
+SOURCE="..\strings\ctype-eucjpms.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\strings\ctype-extra.c"
# End Source File
# Begin Source File
diff --git a/VC++Files/client/mysqlclient_ia64.dsp b/VC++Files/client/mysqlclient_ia64.dsp
index e91245c12b2..a69c5cf58af 100644
--- a/VC++Files/client/mysqlclient_ia64.dsp
+++ b/VC++Files/client/mysqlclient_ia64.dsp
@@ -147,6 +147,10 @@ SOURCE="..\strings\ctype-bin.c"
# End Source File
# Begin Source File
+SOURCE="..\strings\ctype-cp932.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\strings\ctype-czech.c"
# End Source File
# Begin Source File
@@ -155,6 +159,10 @@ SOURCE="..\strings\ctype-euc_kr.c"
# End Source File
# Begin Source File
+SOURCE="..\strings\ctype-eucjpms.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\strings\ctype-extra.c"
# End Source File
# Begin Source File
diff --git a/VC++Files/client/mysqltest.dsp b/VC++Files/client/mysqltest.dsp
index d04dc5bfce8..1ebd7a59b0c 100644
--- a/VC++Files/client/mysqltest.dsp
+++ b/VC++Files/client/mysqltest.dsp
@@ -42,8 +42,8 @@ RSC=rc.exe
# PROP Output_Dir ".\debug"
# PROP Intermediate_Dir ".\debug"
# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /I "../include" /I "../regex" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_WINDOWS" /D "_MBCS" /Fp".\debug/mysqltest.pch" /Fo".\debug/" /Fd".\debug/" /GZ /c /GX
-# ADD CPP /nologo /MTd /I "../include" /I "../regex" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_WINDOWS" /D "_MBCS" /Fp".\debug/mysqltest.pch" /Fo".\debug/" /Fd".\debug/" /GZ /c /GX
+# ADD BASE CPP /nologo /MTd /I "../extra" /I "../include" /I "../regex" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_WINDOWS" /D "_MBCS" /Fp".\debug/mysqltest.pch" /Fo".\debug/" /Fd".\debug/" /GZ /c /GX
+# ADD CPP /nologo /MTd /I "../extra" /I "../include" /I "../regex" /I "../" /Z7 /W3 /Od /G6 /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_WINDOWS" /D "_MBCS" /Fp".\debug/mysqltest.pch" /Fo".\debug/" /Fd".\debug/" /GZ /c /GX
# ADD BASE MTL /nologo /tlb".\debug\mysqltest.tlb" /win32
# ADD MTL /nologo /tlb".\debug\mysqltest.tlb" /win32
# ADD BASE RSC /l 1033 /d "_DEBUG"
@@ -67,8 +67,8 @@ LINK32=link.exe
# PROP Output_Dir ".\classic"
# PROP Intermediate_Dir ".\classic"
# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "_CONSOLE" /D "_WINDOWS" /D "LICENSE=Commercial" /D "DBUG_OFF" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\classic/mysqltest.pch" /Fo".\classic/" /Fd".\classic/" /c /GX
-# ADD CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "_CONSOLE" /D "_WINDOWS" /D "LICENSE=Commercial" /D "DBUG_OFF" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\classic/mysqltest.pch" /Fo".\classic/" /Fd".\classic/" /c /GX
+# ADD BASE CPP /nologo /MT /I "../extra" /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "_CONSOLE" /D "_WINDOWS" /D "LICENSE=Commercial" /D "DBUG_OFF" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\classic/mysqltest.pch" /Fo".\classic/" /Fd".\classic/" /c /GX
+# ADD CPP /nologo /MT /I "../extra" /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "_CONSOLE" /D "_WINDOWS" /D "LICENSE=Commercial" /D "DBUG_OFF" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\classic/mysqltest.pch" /Fo".\classic/" /Fd".\classic/" /c /GX
# ADD BASE MTL /nologo /tlb".\classic\mysqltest.tlb" /win32
# ADD MTL /nologo /tlb".\classic\mysqltest.tlb" /win32
# ADD BASE RSC /l 1033 /d "NDEBUG"
@@ -92,8 +92,8 @@ LINK32=link.exe
# PROP Output_Dir ".\release"
# PROP Intermediate_Dir ".\release"
# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_CONSOLE" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\release/mysqltest.pch" /Fo".\release/" /Fd".\release/" /c /GX
-# ADD CPP /nologo /MT /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_CONSOLE" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\release/mysqltest.pch" /Fo".\release/" /Fd".\release/" /c /GX
+# ADD BASE CPP /nologo /MT /I "../extra" /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_CONSOLE" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\release/mysqltest.pch" /Fo".\release/" /Fd".\release/" /c /GX
+# ADD CPP /nologo /MT /I "../extra" /I "../include" /I "../regex" /I "../" /W3 /Ob1 /G6 /D "DBUG_OFF" /D "_CONSOLE" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /GF /Gy /Fp".\release/mysqltest.pch" /Fo".\release/" /Fd".\release/" /c /GX
# ADD BASE MTL /nologo /tlb".\release\mysqltest.tlb" /win32
# ADD MTL /nologo /tlb".\release\mysqltest.tlb" /win32
# ADD BASE RSC /l 1033 /d "NDEBUG"
diff --git a/VC++Files/libmysql/libmysql.dsp b/VC++Files/libmysql/libmysql.dsp
index ce81a3b7435..34c479c73b4 100644
--- a/VC++Files/libmysql/libmysql.dsp
+++ b/VC++Files/libmysql/libmysql.dsp
@@ -139,6 +139,10 @@ SOURCE="..\strings\ctype-bin.c"
# End Source File
# Begin Source File
+SOURCE="..\strings\ctype-cp932.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\strings\ctype-czech.c"
# End Source File
# Begin Source File
@@ -147,6 +151,10 @@ SOURCE="..\strings\ctype-euc_kr.c"
# End Source File
# Begin Source File
+SOURCE="..\strings\ctype-eucjpms.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\strings\ctype-extra.c"
# End Source File
# Begin Source File
diff --git a/VC++Files/libmysql/libmysql_ia64.dsp b/VC++Files/libmysql/libmysql_ia64.dsp
index 4c4776dfc2f..fa851cb81c5 100644
--- a/VC++Files/libmysql/libmysql_ia64.dsp
+++ b/VC++Files/libmysql/libmysql_ia64.dsp
@@ -138,6 +138,10 @@ SOURCE="..\strings\ctype-bin.c"
# End Source File
# Begin Source File
+SOURCE="..\strings\ctype-cp932.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\strings\ctype-czech.c"
# End Source File
# Begin Source File
@@ -146,6 +150,10 @@ SOURCE="..\strings\ctype-euc_kr.c"
# End Source File
# Begin Source File
+SOURCE="..\strings\ctype-eucjpms.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\strings\ctype-extra.c"
# End Source File
# Begin Source File
diff --git a/VC++Files/libmysqld/examples/test_libmysqld.dsp b/VC++Files/libmysqld/examples/test_libmysqld.dsp
index 6707b8cd8ee..013bc41409d 100644
--- a/VC++Files/libmysqld/examples/test_libmysqld.dsp
+++ b/VC++Files/libmysqld/examples/test_libmysqld.dsp
@@ -47,7 +47,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 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 /machine:I386
-# 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 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 /nologo /subsystem:console /machine:I386 /nodefaultlib:"LIBCMTD" /out:"Release/mysql-server.exe"
+# 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 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 /nologo /subsystem:console /machine:I386 /nodefaultlib:"LIBCMTD" /out:"..\test_libmysqld.exe"
# Begin Target
# Name "test_libmysqld - Win32 Release"
@@ -71,9 +71,5 @@ SOURCE=..\..\client\readline.cpp
SOURCE=..\..\client\sql_string.cpp
# End Source File
# End Group
-# Begin Source File
-
-SOURCE=..\..\lib_release\libmysqld.lib
-# End Source File
# End Target
# End Project
diff --git a/VC++Files/libmysqld/libmysqld.dsp b/VC++Files/libmysqld/libmysqld.dsp
index 8205461c26f..c5c40b07dfd 100644
--- a/VC++Files/libmysqld/libmysqld.dsp
+++ b/VC++Files/libmysqld/libmysqld.dsp
@@ -228,10 +228,6 @@ SOURCE=..\sql\ha_innodb.cpp
# End Source File
# Begin Source File
-SOURCE=..\sql\ha_isammrg.cpp
-# End Source File
-# Begin Source File
-
SOURCE=..\sql\ha_myisam.cpp
# End Source File
# Begin Source File
@@ -348,9 +344,17 @@ SOURCE=..\mysys\my_alloc.c
# End Source File
# Begin Source File
+SOURCE=..\sql\my_decimal.cpp
+# End Source File
+# Begin Source File
+
SOURCE=..\mysys\my_getopt.c
# End Source File
# Begin Source File
+
+SOURCE=..\sql-common\my_time.c
+# End Source File
+# Begin Source File
SOURCE=..\sql\net_serv.cpp
# End Source File
@@ -364,11 +368,11 @@ SOURCE=..\sql\opt_sum.cpp
# End Source File
# Begin Source File
-SOURCE="..\sql-common\pack.c"
+SOURCE=..\sql-common\pack.c
# End Source File
# Begin Source File
-SOURCE=..\sql-common\my_time.c
+SOURCE=..\sql\parse_file.cpp
# End Source File
# Begin Source File
@@ -384,6 +388,10 @@ SOURCE=..\sql\protocol.cpp
# End Source File
# Begin Source File
+SOURCE=..\sql\protocol_cursor.cpp
+# End Source File
+# Begin Source File
+
SOURCE=..\sql\records.cpp
# End Source File
# Begin Source File
@@ -396,6 +404,26 @@ SOURCE=..\sql\set_var.cpp
# End Source File
# Begin Source File
+SOURCE=..\sql\sp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\sql\sp_cache.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\sql\sp_head.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\sql\sp_pcontext.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\sql\sp_rcontext.cpp
+# End Source File
+# Begin Source File
+
SOURCE=..\sql\spatial.cpp
# End Source File
# Begin Source File
@@ -516,6 +544,10 @@ SOURCE=..\sql\sql_test.cpp
# End Source File
# Begin Source File
+SOURCE=..\sql\sql_trigger.cpp
+# End Source File
+# Begin Source File
+
SOURCE=..\sql\sql_udf.cpp
# End Source File
# Begin Source File
@@ -525,6 +557,10 @@ SOURCE=..\sql\sql_union.cpp
# Begin Source File
SOURCE=..\sql\sql_update.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\sql\sql_view.cpp
# End Source File
# Begin Source File
diff --git a/VC++Files/libmysqltest/mytest.c b/VC++Files/libmysqltest/mytest.c
index 9af8c486e40..a1dc13db39f 100644
--- a/VC++Files/libmysqltest/mytest.c
+++ b/VC++Files/libmysqltest/mytest.c
@@ -91,6 +91,7 @@ main( int argc, char * argv[] )
mysql_real_connect( myData, NULL, NULL, NULL, NULL, MYSQL_PORT,
NULL, 0 ) )
{
+ myData->reconnect= 1;
if ( mysql_select_db( myData, szDB ) < 0 ) {
printf( "Can't select the %s database !\n", szDB ) ;
mysql_close( myData ) ;
diff --git a/VC++Files/mysql.dsw b/VC++Files/mysql.dsw
index d36cbc7a031..73db9d095cb 100644
--- a/VC++Files/mysql.dsw
+++ b/VC++Files/mysql.dsw
@@ -3,21 +3,6 @@ Microsoft Developer Studio Workspace File, Format Version 6.00
###############################################################################
-Project: "MySqlManager"=".\mysqlmanager\MySqlManager.dsp" - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
- Begin Project Dependency
- Project_Dep_Name mysqlclient
- End Project Dependency
-}}}
-
-###############################################################################
-
Project: "bdb"=".\bdb\bdb.dsp" - Package Owner=<4>
Package=<5>
@@ -84,42 +69,6 @@ Package=<4>
###############################################################################
-Project: "isam"=".\isam\isam.dsp" - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "isamchk"=".\isamchk\isamchk.dsp" - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
- Begin Project Dependency
- Project_Dep_Name isam
- End Project Dependency
- Begin Project Dependency
- Project_Dep_Name mysys
- End Project Dependency
- Begin Project Dependency
- Project_Dep_Name strings
- End Project Dependency
- Begin Project Dependency
- Project_Dep_Name dbug
- End Project Dependency
-}}}
-
-###############################################################################
-
Project: "libmysql"=".\libmysql\libmysql.dsp" - Package Owner=<4>
Package=<5>
@@ -177,18 +126,6 @@ Package=<4>
###############################################################################
-Project: "merge"=".\merge\merge.dsp" - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
Project: "myTest"=".\libmysqltest\myTest.dsp" - Package Owner=<4>
Package=<5>
@@ -444,12 +381,6 @@ Package=<4>
Project_Dep_Name heap
End Project Dependency
Begin Project Dependency
- Project_Dep_Name isam
- End Project Dependency
- Begin Project Dependency
- Project_Dep_Name merge
- End Project Dependency
- Begin Project Dependency
Project_Dep_Name mysys
End Project Dependency
Begin Project Dependency
@@ -474,9 +405,6 @@ Package=<4>
Project_Dep_Name mysqlimport
End Project Dependency
Begin Project Dependency
- Project_Dep_Name MySqlManager
- End Project Dependency
- Begin Project Dependency
Project_Dep_Name mysqlshow
End Project Dependency
Begin Project Dependency
@@ -570,9 +498,6 @@ Package=<4>
Project_Dep_Name innobase
End Project Dependency
Begin Project Dependency
- Project_Dep_Name merge
- End Project Dependency
- Begin Project Dependency
Project_Dep_Name myisam
End Project Dependency
Begin Project Dependency
@@ -648,30 +573,6 @@ Package=<4>
###############################################################################
-Project: "pack_isam"=".\pack_isam\pack_isam.dsp" - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
- Begin Project Dependency
- Project_Dep_Name dbug
- End Project Dependency
- Begin Project Dependency
- Project_Dep_Name isam
- End Project Dependency
- Begin Project Dependency
- Project_Dep_Name mysys
- End Project Dependency
- Begin Project Dependency
- Project_Dep_Name strings
- End Project Dependency
-}}}
-
-###############################################################################
-
Project: "perror"=".\perror\perror.dsp" - Package Owner=<4>
Package=<5>
diff --git a/VC++Files/mysql_ia64.dsw b/VC++Files/mysql_ia64.dsw
index 8af4a7e5c42..dd86d498afe 100644
--- a/VC++Files/mysql_ia64.dsw
+++ b/VC++Files/mysql_ia64.dsw
@@ -508,9 +508,6 @@ Package=<4>
Project_Dep_Name mysqlimport
End Project Dependency
Begin Project Dependency
- Project_Dep_Name MySqlManager
- End Project Dependency
- Begin Project Dependency
Project_Dep_Name mysqlshow
End Project Dependency
Begin Project Dependency
diff --git a/VC++Files/mysqldemb/mysqldemb.dsp b/VC++Files/mysqldemb/mysqldemb.dsp
index a8207d436a0..61a745ff7e8 100644
--- a/VC++Files/mysqldemb/mysqldemb.dsp
+++ b/VC++Files/mysqldemb/mysqldemb.dsp
@@ -169,10 +169,6 @@ SOURCE=..\sql\ha_innodb.cpp
# End Source File
# Begin Source File
-SOURCE=..\sql\ha_isammrg.cpp
-# End Source File
-# Begin Source File
-
SOURCE=..\sql\ha_myisam.cpp
# End Source File
# Begin Source File
diff --git a/VC++Files/mysqlmanager/MySqlManager_ia64.dsp b/VC++Files/mysqlmanager/MySqlManager_ia64.dsp
deleted file mode 100644
index b0ffc9e48c6..00000000000
--- a/VC++Files/mysqlmanager/MySqlManager_ia64.dsp
+++ /dev/null
@@ -1,276 +0,0 @@
-# Microsoft Developer Studio Project File - Name="MySqlManager" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Application" 0x0101
-
-CFG=MYSQLMANAGER - WinIA64 DEBUG
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "MySqlManager.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "MySqlManager.mak" CFG="MYSQLMANAGER - WinIA64 DEBUG"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "MySqlManager - WinIA64 Release" (based on "Win32 (x86) Application")
-!MESSAGE "MySqlManager - WinIA64 Debug" (based on "Win32 (x86) Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "MySqlManager - WinIA64 Release"
-
-# PROP BASE Use_MFC 6
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 6
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "release"
-# PROP Intermediate_Dir "release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN64" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
-# ADD CPP /nologo /MT /W3 /Zi /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /D "_IA64_" /D "WIN64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c
-# SUBTRACT CPP /WX /Fr /YX /Yc /Yu
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win64
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win64
-# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL"
-# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:windows /machine:IA64
-# ADD LINK32 /nologo /subsystem:windows /out:"../client_release/MySqlManager.exe" /machine:IA64
-# SUBTRACT LINK32 /nodefaultlib
-
-!ELSEIF "$(CFG)" == "MySqlManager - WinIA64 Debug"
-
-# PROP BASE Use_MFC 6
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 6
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "debug"
-# PROP Intermediate_Dir "debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN64" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
-# ADD CPP /nologo /MTd /W3 /GR /Zi /Od /I "../include" /D "_DEBUG" /D "_WINDOWS" /D "_IA64_" /D "WIN64" /D "WIN32" /D "_AFX_NO_DAO_SUPPORT" /FD /G2 /EHsc /Wp64 /Zm600 /c
-# SUBTRACT CPP /Fr /YX /Yc /Yu
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win64
-# ADD MTL /nologo /D "_DEBUG" /o "NUL" /win64
-# SUBTRACT MTL /mktyplib203
-# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:IA64
-# ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib /nologo /subsystem:windows /incremental:no /debug /out:"../client_debug/MySqlManager.exe" /libpath:"..\lib_debug\\" /machine:IA64
-
-!ENDIF
-
-# Begin Target
-
-# Name "MySqlManager - WinIA64 Release"
-# Name "MySqlManager - WinIA64 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\ChildFrm.cpp
-# End Source File
-# Begin Source File
-
-SOURCE="..\strings\ctype-extra.c"
-# End Source File
-# Begin Source File
-
-SOURCE="..\strings\ctype-latin1.c"
-# End Source File
-# Begin Source File
-
-SOURCE="..\strings\ctype-mb.c"
-# End Source File
-# Begin Source File
-
-SOURCE=..\strings\is_prefix.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\MainFrm.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\mysys\my_sleep.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\strings\my_vsnprintf.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManager.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManager.rc
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManagerDoc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManagerView.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\RegisterServer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.cpp
-# ADD CPP /Yc"stdafx.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSql.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlQuery.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlResults.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlStatus.cpp
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\ChildFrm.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\MainFrm.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManager.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManagerDoc.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManagerView.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\RegisterServer.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resource.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlQuery.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlResults.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlStatus.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
-# Begin Source File
-
-SOURCE=.\res\bitmap1.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\bitmap3.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\bmp00001.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\bmp00002.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\database.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\fontd.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\fontu.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\MySqlManager.ico
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\MySqlManager.rc2
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\MySqlManagerDoc.ico
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\query_ex.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\Toolbar.bmp
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\ReadMe.txt
-# End Source File
-# End Target
-# End Project
diff --git a/VC++Files/mysqlmanager/README.TXT b/VC++Files/mysqlmanager/README.TXT
deleted file mode 100644
index cdd54c2cba8..00000000000
--- a/VC++Files/mysqlmanager/README.TXT
+++ /dev/null
@@ -1,102 +0,0 @@
-========================================================================
- MICROSOFT FOUNDATION CLASS LIBRARY : MySqlManager
-========================================================================
-
-
-AppWizard has created this MySqlManager application for you. This application
-not only demonstrates the basics of using the Microsoft Foundation classes
-but is also a starting point for writing your application.
-
-This file contains a summary of what you will find in each of the files that
-make up your MySqlManager application.
-
-MySqlManager.h
- This is the main header file for the application. It includes other
- project specific headers (including Resource.h) and declares the
- CMySqlManagerApp application class.
-
-MySqlManager.cpp
- This is the main application source file that contains the application
- class CMySqlManagerApp.
-
-MySqlManager.rc
- This is a listing of all of the Microsoft Windows resources that the
- program uses. It includes the icons, bitmaps, and cursors that are stored
- in the RES subdirectory. This file can be directly edited in Microsoft
- Developer Studio.
-
-res\MySqlManager.ico
- This is an icon file, which is used as the application's icon. This
- icon is included by the main resource file MySqlManager.rc.
-
-res\MySqlManager.rc2
- This file contains resources that are not edited by Microsoft
- Developer Studio. You should place all resources not
- editable by the resource editor in this file.
-
-MySqlManager.clw
- This file contains information used by ClassWizard to edit existing
- classes or add new classes. ClassWizard also uses this file to store
- information needed to create and edit message maps and dialog data
- maps and to create prototype member functions.
-
-/////////////////////////////////////////////////////////////////////////////
-
-For the main frame window:
-
-MainFrm.h, MainFrm.cpp
- These files contain the frame class CMainFrame, which is derived from
- CMDIFrameWnd and controls all MDI frame features.
-
-res\Toolbar.bmp
- This bitmap file is used to create tiled images for the toolbar.
- The initial toolbar and status bar are constructed in the
- CMainFrame class. Edit this toolbar bitmap along with the
- array in MainFrm.cpp to add more toolbar buttons.
-
-/////////////////////////////////////////////////////////////////////////////
-
-AppWizard creates one document type and one view:
-
-MySqlManagerDoc.h, MySqlManagerDoc.cpp - the document
- These files contain your CMySqlManagerDoc class. Edit these files to
- add your special document data and to implement file saving and loading
- (via CMySqlManagerDoc::Serialize).
-
-MySqlManagerView.h, MySqlManagerView.cpp - the view of the document
- These files contain your CMySqlManagerView class.
- CMySqlManagerView objects are used to view CMySqlManagerDoc objects.
-
-res\MySqlManagerDoc.ico
- This is an icon file, which is used as the icon for MDI child windows
- for the CMySqlManagerDoc class. This icon is included by the main
- resource file MySqlManager.rc.
-
-
-/////////////////////////////////////////////////////////////////////////////
-Other standard files:
-
-StdAfx.h, StdAfx.cpp
- These files are used to build a precompiled header (PCH) file
- named MySqlManager.pch and a precompiled types file named StdAfx.obj.
-
-Resource.h
- This is the standard header file, which defines new resource IDs.
- Microsoft Developer Studio reads and updates this file.
-
-/////////////////////////////////////////////////////////////////////////////
-Other notes:
-
-AppWizard uses "TODO:" to indicate parts of the source code you
-should add to or customize.
-
-If your application uses MFC in a shared DLL, and your application is
-in a language other than the operating system's current language, you
-will need to copy the corresponding localized resources MFC40XXX.DLL
-from the Microsoft Visual C++ CD-ROM onto the system or system32 directory,
-and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation.
-For example, MFC40DEU.DLL contains resources translated to German.) If you
-don't do this, some of the UI elements of your application will remain in the
-language of the operating system.
-
-/////////////////////////////////////////////////////////////////////////////
diff --git a/VC++Files/mysqlmanager/RES/bitmap1.bmp b/VC++Files/mysqlmanager/RES/bitmap1.bmp
deleted file mode 100644
index 3751f1a6923..00000000000
--- a/VC++Files/mysqlmanager/RES/bitmap1.bmp
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/bitmap3.bmp b/VC++Files/mysqlmanager/RES/bitmap3.bmp
deleted file mode 100644
index 3751f1a6923..00000000000
--- a/VC++Files/mysqlmanager/RES/bitmap3.bmp
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/bmp00001.bmp b/VC++Files/mysqlmanager/RES/bmp00001.bmp
deleted file mode 100644
index e98e93d7850..00000000000
--- a/VC++Files/mysqlmanager/RES/bmp00001.bmp
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/bmp00002.bmp b/VC++Files/mysqlmanager/RES/bmp00002.bmp
deleted file mode 100644
index 2f2c195a683..00000000000
--- a/VC++Files/mysqlmanager/RES/bmp00002.bmp
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/database.bmp b/VC++Files/mysqlmanager/RES/database.bmp
deleted file mode 100644
index 2fc41313541..00000000000
--- a/VC++Files/mysqlmanager/RES/database.bmp
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/fontd.bmp b/VC++Files/mysqlmanager/RES/fontd.bmp
deleted file mode 100644
index c77b4f4fdd0..00000000000
--- a/VC++Files/mysqlmanager/RES/fontd.bmp
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/fontu.bmp b/VC++Files/mysqlmanager/RES/fontu.bmp
deleted file mode 100644
index c77b4f4fdd0..00000000000
--- a/VC++Files/mysqlmanager/RES/fontu.bmp
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/mysqlmanager.ico b/VC++Files/mysqlmanager/RES/mysqlmanager.ico
deleted file mode 100644
index 7eef0bcbe65..00000000000
--- a/VC++Files/mysqlmanager/RES/mysqlmanager.ico
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/mysqlmanager.rc2 b/VC++Files/mysqlmanager/RES/mysqlmanager.rc2
deleted file mode 100644
index 67d4f3f4a85..00000000000
--- a/VC++Files/mysqlmanager/RES/mysqlmanager.rc2
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// MYSQLMANAGER.RC2 - resources Microsoft Visual C++ does not edit directly
-//
-
-#ifdef APSTUDIO_INVOKED
- #error this file is not editable by Microsoft Visual C++
-#endif //APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-// Add manually edited resources here...
-
-/////////////////////////////////////////////////////////////////////////////
diff --git a/VC++Files/mysqlmanager/RES/mysqlmanagerdoc.ico b/VC++Files/mysqlmanager/RES/mysqlmanagerdoc.ico
deleted file mode 100644
index 2a1f1ae6ef1..00000000000
--- a/VC++Files/mysqlmanager/RES/mysqlmanagerdoc.ico
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/query_ex.bmp b/VC++Files/mysqlmanager/RES/query_ex.bmp
deleted file mode 100644
index cc77222decc..00000000000
--- a/VC++Files/mysqlmanager/RES/query_ex.bmp
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/RES/toolbar.bmp b/VC++Files/mysqlmanager/RES/toolbar.bmp
deleted file mode 100644
index d501723c1ce..00000000000
--- a/VC++Files/mysqlmanager/RES/toolbar.bmp
+++ /dev/null
Binary files differ
diff --git a/VC++Files/mysqlmanager/childfrm.cpp b/VC++Files/mysqlmanager/childfrm.cpp
deleted file mode 100644
index 08027e068ac..00000000000
--- a/VC++Files/mysqlmanager/childfrm.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-// ChildFrm.cpp : implementation of the CChildFrame class
-//
-
-#include "stdafx.h"
-#include "MySqlManager.h"
-
-#include "ChildFrm.h"
-
-#ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-// CChildFrame
-
-IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWnd)
-
-BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
-//{{AFX_MSG_MAP(CChildFrame)
-// NOTE - the ClassWizard will add and remove mapping macros here.
-// DO NOT EDIT what you see in these blocks of generated code !
-//}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-// CChildFrame construction/destruction
-
-CChildFrame::CChildFrame()
-{
- // TODO: add member initialization code here
-
-}
-
-CChildFrame::~CChildFrame()
-{
-}
-
-BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
-{
- // TODO: Modify the Window class or styles here by modifying
- // the CREATESTRUCT cs
-
- return CMDIChildWnd::PreCreateWindow(cs);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// CChildFrame diagnostics
-
-#ifdef _DEBUG
-void CChildFrame::AssertValid() const
-{
- CMDIChildWnd::AssertValid();
-}
-
-void CChildFrame::Dump(CDumpContext& dc) const
-{
- CMDIChildWnd::Dump(dc);
-}
-
-#endif //_DEBUG
-
-/////////////////////////////////////////////////////////////////////////////
-// CChildFrame message handlers
diff --git a/VC++Files/mysqlmanager/childfrm.h b/VC++Files/mysqlmanager/childfrm.h
deleted file mode 100644
index 3075be58a67..00000000000
--- a/VC++Files/mysqlmanager/childfrm.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// ChildFrm.h : interface of the CChildFrame class
-//
-/////////////////////////////////////////////////////////////////////////////
-
-#if !defined(AFX_CHILDFRM_H__826CB2F0_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_CHILDFRM_H__826CB2F0_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-class CChildFrame : public CMDIChildWnd
-{
- DECLARE_DYNCREATE(CChildFrame)
-public:
- CChildFrame();
-
-// Attributes
-public:
-
-// Operations
-public:
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CChildFrame)
- virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
- //}}AFX_VIRTUAL
-
-// Implementation
-public:
- virtual ~CChildFrame();
-#ifdef _DEBUG
- virtual void AssertValid() const;
- virtual void Dump(CDumpContext& dc) const;
-#endif
-
-// Generated message map functions
-protected:
- //{{AFX_MSG(CChildFrame)
- // NOTE - the ClassWizard will add and remove member functions here.
- // DO NOT EDIT what you see in these blocks of generated code!
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-/////////////////////////////////////////////////////////////////////////////
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_CHILDFRM_H__826CB2F0_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/cresource.h b/VC++Files/mysqlmanager/cresource.h
deleted file mode 100644
index 37c1839d758..00000000000
--- a/VC++Files/mysqlmanager/cresource.h
+++ /dev/null
@@ -1,134 +0,0 @@
-#ifndef _CRESOURCE_H
-#define _CRESOURCE_H
-
-/////////////////////////////////////////////////////////////////////////////
-
-#define MYSQL_PORT_AS_STRING "3306" /* Can't use # in preprocessor because of bugs in VC++ 5.0 */
-
-class CResource
-{
-public:
- enum eRESOURCETYPE
- {
- eNone
- , eServer
- , eDatabase
- , eTable
- , eField
- , eProcesslist
- , eProcesslistItem
- };
- virtual LPCTSTR GetDisplayName() { return ""; }
- virtual LPCTSTR GetHostName() { return LOCAL_HOST; }
- virtual LPCTSTR GetUserName() { return "root"; }
- virtual LPCTSTR GetPassword() { return ""; }
- virtual LPCTSTR GetPortName() { return MYSQL_PORT_AS_STRING; }
- virtual int GetPortNumber() { return MYSQL_PORT; }
- virtual eRESOURCETYPE GetType() { return eNone; }
-};
-
-/////////////////////////////////////////////////////////////////////////////
-
-class CResourceServer : public CResource
-{
-public:
- CResourceServer(LPCTSTR pszName = "",LPCTSTR pszHost = LOCAL_HOST ,LPCTSTR pszUser = "root", LPCTSTR pszPassword = "", LPCTSTR pszPort = MYSQL_PORT_AS_STRING)
- : m_strName(pszName)
- , m_strHost(pszHost)
- , m_strUser(pszUser)
- , m_strPassword(pszPassword)
- , m_strPort(pszPort)
- {
- }
- virtual LPCTSTR GetDisplayName() { return m_strName; }
- virtual LPCTSTR GetHostName() { return m_strHost; }
- virtual LPCTSTR GetUserName() { return m_strUser; }
- virtual LPCTSTR GetPassword() { return m_strPassword; }
- virtual eRESOURCETYPE GetType() { return eServer; }
- virtual LPCTSTR GetPortName() { return m_strPort; }
- virtual int GetPortNumber() { return atoi(m_strPort); }
- CString m_strName;
- CString m_strHost;
- CString m_strUser;
- CString m_strPassword;
- CString m_strPort;
- CStringArray m_rgFields;
-};
-
-/////////////////////////////////////////////////////////////////////////////
-
-class CResourceDatabase : public CResource
-{
-public:
- CResourceDatabase(LPCTSTR pszName = "")
- : m_strName(pszName)
- {
- }
- virtual LPCTSTR GetDisplayName() { return m_strName; }
- virtual eRESOURCETYPE GetType() { return eDatabase; }
- CString m_strName;
- CStringArray m_rgFields;
-};
-
-/////////////////////////////////////////////////////////////////////////////
-
-class CResourceTable : public CResource
-{
-public:
- CResourceTable(LPCTSTR pszName = "")
- : m_strName(pszName)
- {
- }
- virtual LPCTSTR GetDisplayName() { return m_strName; }
- virtual eRESOURCETYPE GetType() { return eTable; }
- CString m_strName;
- CStringArray m_rgFields;
-};
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-class CResourceField : public CResource
-{
-public:
- CResourceField(LPCTSTR pszName = "")
- : m_strName(pszName)
- {
- }
- virtual LPCTSTR GetDisplayName() { return m_strName; }
- virtual eRESOURCETYPE GetType() { return eField; }
- CString m_strName;
- CStringArray m_rgFields;
-};
-
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-class CResourceProcesslist : public CResource
-{
-public:
- CResourceProcesslist(LPCTSTR pszName = "Processlist")
- : m_strName(pszName)
- {
- }
- virtual LPCTSTR GetDisplayName() { return m_strName; }
- virtual eRESOURCETYPE GetType() { return eProcesslist; }
- CString m_strName;
- CStringArray m_rgFields;
-};
-
-/////////////////////////////////////////////////////////////////////////////
-
-class CResourceProcesslistItem : public CResourceProcesslist
-{
-public:
- CResourceProcesslistItem(LPCTSTR pszName = "ProcesslistItem")
- : CResourceProcesslist(pszName)
- {
- }
- virtual eRESOURCETYPE GetType() { return eProcesslistItem; }
-};
-
-
-#endif
diff --git a/VC++Files/mysqlmanager/mainfrm.cpp b/VC++Files/mysqlmanager/mainfrm.cpp
deleted file mode 100644
index 499704ed2a0..00000000000
--- a/VC++Files/mysqlmanager/mainfrm.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-// MainFrm.cpp : implementation of the CMainFrame class
-//
-
-#include "stdafx.h"
-#include "MySqlManager.h"
-#include "MainFrm.h"
-
-CMainFrame* CMainFrame::g_pMainFrame = NULL;
-
-#ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-// CMainFrame
-
-IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
-
-BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
-//{{AFX_MSG_MAP(CMainFrame)
-// NOTE - the ClassWizard will add and remove mapping macros here.
-// DO NOT EDIT what you see in these blocks of generated code !
- ON_WM_CREATE()
-//}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-static UINT indicators[] =
-{
- ID_SEPARATOR, // status line indicator
- ID_INDICATOR_CAPS,
- ID_INDICATOR_NUM,
- ID_INDICATOR_SCRL,
-};
-
-/////////////////////////////////////////////////////////////////////////////
-// CMainFrame construction/destruction
-
-CMainFrame::CMainFrame()
-{
- // TODO: add member initialization code here
-
-}
-
-CMainFrame::~CMainFrame()
-{
-}
-
-int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
-{
- if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
- return -1;
-
- if (!m_wndToolBar.Create(this) ||
- !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
- {
- TRACE0("Failed to create toolbar\n");
- return -1; // fail to create
- }
-
- if (!m_wndStatusBar.Create(this) ||
- !m_wndStatusBar.SetIndicators(indicators,
- sizeof(indicators)/sizeof(UINT)))
- {
- TRACE0("Failed to create status bar\n");
- return -1; // fail to create
- }
-
- // TODO: Remove this if you don't want tool tips or a resizeable toolbar
- m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
- CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
-
- // TODO: Delete these three lines if you don't want the toolbar to
- // be dockable
- m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
- EnableDocking(CBRS_ALIGN_ANY);
- DockControlBar(&m_wndToolBar);
-
- return 0;
-}
-
-BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
-{
- // TODO: Modify the Window class or styles here by modifying
- // the CREATESTRUCT cs
-
- return CMDIFrameWnd::PreCreateWindow(cs);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// CMainFrame diagnostics
-
-#ifdef _DEBUG
-void CMainFrame::AssertValid() const
-{
- CMDIFrameWnd::AssertValid();
-}
-
-void CMainFrame::Dump(CDumpContext& dc) const
-{
- CMDIFrameWnd::Dump(dc);
-}
-
-#endif //_DEBUG
-
-/////////////////////////////////////////////////////////////////////////////
-// CMainFrame message handlers
-
-int CMainFrame::StatusMsg ( LPCSTR fmt, ... )
-
-{
-
- char buf [2048];
- va_list args;
- va_start(args, fmt);
- int ret = vsprintf(buf, fmt, args);
-
- if ( this != NULL )
- {
- static char g_StatusMsg_Buffer_TT [ 2048 ];
- memcpy ( g_StatusMsg_Buffer_TT, buf, sizeof(g_StatusMsg_Buffer_TT) );
- m_wndStatusBar.SetPaneText ( 0, buf );
- m_wndStatusBar.UpdateWindow ();
- }
-
- va_end(args);
- return ( ret );
-
-}
-
-
-BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
-{
- g_pMainFrame = this;
- return CMDIFrameWnd::OnCreateClient(lpcs, pContext);
-}
diff --git a/VC++Files/mysqlmanager/mainfrm.h b/VC++Files/mysqlmanager/mainfrm.h
deleted file mode 100644
index 06c51965bb1..00000000000
--- a/VC++Files/mysqlmanager/mainfrm.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// MainFrm.h : interface of the CMainFrame class
-//
-/////////////////////////////////////////////////////////////////////////////
-
-#if !defined(AFX_MAINFRM_H__826CB2EE_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_MAINFRM_H__826CB2EE_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-class CMainFrame : public CMDIFrameWnd
-{
- DECLARE_DYNAMIC(CMainFrame)
-public:
- CMainFrame();
-
-// Attributes
-public:
-
-// Operations
-public:
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CMainFrame)
- public:
- virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
- protected:
- virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
- //}}AFX_VIRTUAL
-
-// Implementation
-public:
- virtual ~CMainFrame();
-#ifdef _DEBUG
- virtual void AssertValid() const;
- virtual void Dump(CDumpContext& dc) const;
-#endif
-
- int StatusMsg ( LPCSTR fmt, ... );
-
-protected: // control bar embedded members
- CStatusBar m_wndStatusBar;
- CToolBar m_wndToolBar;
-
-// Generated message map functions
-protected:
- //{{AFX_MSG(CMainFrame)
- afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
- // NOTE - the ClassWizard will add and remove member functions here.
- // DO NOT EDIT what you see in these blocks of generated code!
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-
-public:
-
-static CMainFrame* g_pMainFrame;
-
-};
-
-#define MainFrame ( CMainFrame::g_pMainFrame ? CMainFrame::g_pMainFrame : (CMainFrame*) AfxGetMainWnd() -> GetTopLevelFrame() )
-
-/////////////////////////////////////////////////////////////////////////////
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_MAINFRM_H__826CB2EE_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/mysqlmanager.cpp b/VC++Files/mysqlmanager/mysqlmanager.cpp
deleted file mode 100644
index 09a19181e22..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanager.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-// MySqlManager.cpp : Defines the class behaviors for the application.
-//
-
-#include "stdafx.h"
-#include "MySqlManager.h"
-
-#include "MainFrm.h"
-#include "ChildFrm.h"
-#include "MySqlManagerDoc.h"
-#include "MySqlManagerView.h"
-
-#ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerApp
-
-BEGIN_MESSAGE_MAP(CMySqlManagerApp, CWinApp)
-//{{AFX_MSG_MAP(CMySqlManagerApp)
- ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
-// NOTE - the ClassWizard will add and remove mapping macros here.
-// DO NOT EDIT what you see in these blocks of generated code!
-//}}AFX_MSG_MAP
-// Standard file based document commands
- ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
- ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
-// Standard print setup command
- ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerApp construction
-
-CMySqlManagerApp::CMySqlManagerApp()
-{
- // TODO: add construction code here,
- // Place all significant initialization in InitInstance
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// The one and only CMySqlManagerApp object
-
-CMySqlManagerApp theApp;
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerApp initialization
-
-BOOL CMySqlManagerApp::InitInstance()
-{
-
- WSADATA WsaData;
-
- if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
- {
- AfxMessageBox("WSAStartup Failed\n");
- return FALSE;
- }
-
- AfxEnableControlContainer();
-
- // Standard initialization
- // If you are not using these features and wish to reduce the size
- // of your final executable, you should remove from the following
- // the specific initialization routines you do not need.
-
-#ifdef _AFXDLL
- Enable3dControls(); // Call this when using MFC in a shared DLL
-#else
- Enable3dControlsStatic(); // Call this when linking to MFC statically
-#endif
-
- // Change the registry key under which our settings are stored.
- // You should modify this string to be something appropriate
- // such as the name of your company or organization.
- SetRegistryKey(_T("Local AppWizard-Generated Applications"));
-
- LoadStdProfileSettings(); // Load standard INI file options (including MRU)
-
- // Register the application's document templates. Document templates
- // serve as the connection between documents, frame windows and views.
-
- CMultiDocTemplate* pDocTemplate;
- pDocTemplate = new CMultiDocTemplate(
- IDR_MYSQLMTYPE,
- RUNTIME_CLASS(CMySqlManagerDoc),
- RUNTIME_CLASS(CChildFrame), // custom MDI child frame
- RUNTIME_CLASS(CMySqlManagerView));
- AddDocTemplate(pDocTemplate);
-
- // create main MDI Frame window
- CMainFrame* pMainFrame = new CMainFrame;
- if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
- return FALSE;
- m_pMainWnd = pMainFrame;
-
- // Parse command line for standard shell commands, DDE, file open
- CCommandLineInfo cmdInfo;
- ParseCommandLine(cmdInfo);
-
- // Dispatch commands specified on the command line
- if (!ProcessShellCommand(cmdInfo))
- return FALSE;
-
- // The main window has been initialized, so show and update it.
- pMainFrame->ShowWindow(m_nCmdShow);
- pMainFrame->UpdateWindow();
-
- return TRUE;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// CAboutDlg dialog used for App About
-
-class CAboutDlg : public CDialog
-{
-public:
- CAboutDlg();
-
-// Dialog Data
- //{{AFX_DATA(CAboutDlg)
- enum {IDD = IDD_ABOUTBOX};
- //}}AFX_DATA
-
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CAboutDlg)
-protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
-// Implementation
-protected:
- //{{AFX_MSG(CAboutDlg)
- // No message handlers
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
-{
- //{{AFX_DATA_INIT(CAboutDlg)
- //}}AFX_DATA_INIT
-}
-
-void CAboutDlg::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CAboutDlg)
- //}}AFX_DATA_MAP
-}
-
-BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
-//{{AFX_MSG_MAP(CAboutDlg)
-// No message handlers
-//}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-// App command to run the dialog
-void CMySqlManagerApp::OnAppAbout()
-{
- CAboutDlg aboutDlg;
- aboutDlg.DoModal();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerApp commands
diff --git a/VC++Files/mysqlmanager/mysqlmanager.dsp b/VC++Files/mysqlmanager/mysqlmanager.dsp
deleted file mode 100644
index 7f92e091904..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanager.dsp
+++ /dev/null
@@ -1,277 +0,0 @@
-# Microsoft Developer Studio Project File - Name="MySqlManager" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Application" 0x0101
-
-CFG=MySqlManager - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "MySqlManager.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "MySqlManager.mak" CFG="MySqlManager - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "MySqlManager - Win32 Release" (based on "Win32 (x86) Application")
-!MESSAGE "MySqlManager - Win32 Debug" (based on "Win32 (x86) Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=xicl6.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "MySqlManager - Win32 Release"
-
-# PROP BASE Use_MFC 6
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 6
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "release"
-# PROP Intermediate_Dir "release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
-# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /FD /c
-# SUBTRACT CPP /WX /Fr /YX /Yc /Yu
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL"
-# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=xilink6.exe
-# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
-# ADD LINK32 /nologo /subsystem:windows /machine:I386 /out:"../client_release/MySqlManager.exe"
-# SUBTRACT LINK32 /nodefaultlib
-
-!ELSEIF "$(CFG)" == "MySqlManager - Win32 Debug"
-
-# PROP BASE Use_MFC 6
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 6
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "debug"
-# PROP Intermediate_Dir "debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
-# ADD CPP /nologo /G6 /MTd /W3 /GR /GX /Z7 /Od /I "../include" /D "_DEBUG" /D "_WINDOWS" /FD /c
-# SUBTRACT CPP /Fr /YX /Yc /Yu
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "_DEBUG" /o "NUL" /win32
-# SUBTRACT MTL /mktyplib203
-# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=xilink6.exe
-# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /out:"../client_debug/MySqlManager.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
-# SUBTRACT LINK32 /pdb:none
-
-!ENDIF
-
-# Begin Target
-
-# Name "MySqlManager - Win32 Release"
-# Name "MySqlManager - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\ChildFrm.cpp
-# End Source File
-# Begin Source File
-
-SOURCE="..\strings\ctype-extra.c"
-# End Source File
-# Begin Source File
-
-SOURCE="..\strings\ctype-latin1.c"
-# End Source File
-# Begin Source File
-
-SOURCE="..\strings\ctype-mb.c"
-# End Source File
-# Begin Source File
-
-SOURCE=..\strings\is_prefix.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\MainFrm.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\mysys\my_sleep.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\strings\my_vsnprintf.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManager.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManager.rc
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManagerDoc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManagerView.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\RegisterServer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.cpp
-# ADD CPP /Yc"stdafx.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSql.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlQuery.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlResults.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlStatus.cpp
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\ChildFrm.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\MainFrm.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManager.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManagerDoc.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\MySqlManagerView.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\RegisterServer.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resource.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlQuery.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlResults.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ToolSqlStatus.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
-# Begin Source File
-
-SOURCE=.\res\bitmap1.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\bitmap3.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\bmp00001.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\bmp00002.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\database.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\fontd.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\fontu.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\MySqlManager.ico
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\MySqlManager.rc2
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\MySqlManagerDoc.ico
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\query_ex.bmp
-# End Source File
-# Begin Source File
-
-SOURCE=.\res\Toolbar.bmp
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\ReadMe.txt
-# End Source File
-# End Target
-# End Project
diff --git a/VC++Files/mysqlmanager/mysqlmanager.dsw b/VC++Files/mysqlmanager/mysqlmanager.dsw
deleted file mode 100644
index 013873b113b..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanager.dsw
+++ /dev/null
@@ -1,28 +0,0 @@
-Microsoft Developer Studio Workspace File, Format Version 5.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "MySqlManager"=.\MySqlManager.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
diff --git a/VC++Files/mysqlmanager/mysqlmanager.h b/VC++Files/mysqlmanager/mysqlmanager.h
deleted file mode 100644
index accb63a908f..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanager.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// MySqlManager.h : main header file for the MYSQLMANAGER application
-//
-
-#if !defined(AFX_MYSQLMANAGER_H__826CB2EA_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_MYSQLMANAGER_H__826CB2EA_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-#ifndef __AFXWIN_H__
- #error include 'stdafx.h' before including this file for PCH
-#endif
-
-#include "resource.h" // main symbols
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerApp:
-// See MySqlManager.cpp for the implementation of this class
-//
-
-class CMySqlManagerApp : public CWinApp
-{
-public:
- CMySqlManagerApp();
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CMySqlManagerApp)
- public:
- virtual BOOL InitInstance();
- //}}AFX_VIRTUAL
-
-// Implementation
-
- //{{AFX_MSG(CMySqlManagerApp)
- afx_msg void OnAppAbout();
- // NOTE - the ClassWizard will add and remove member functions here.
- // DO NOT EDIT what you see in these blocks of generated code !
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_MYSQLMANAGER_H__826CB2EA_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/mysqlmanager.mak b/VC++Files/mysqlmanager/mysqlmanager.mak
deleted file mode 100644
index b372daa52f2..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanager.mak
+++ /dev/null
@@ -1,327 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Based on MySqlManager.dsp
-!IF "$(CFG)" == ""
-CFG=MySqlManager - Win32 Debug
-!MESSAGE No configuration specified. Defaulting to MySqlManager - Win32 Debug.
-!ENDIF
-
-!IF "$(CFG)" != "MySqlManager - Win32 Release" && "$(CFG)" != "MySqlManager - Win32 Debug"
-!MESSAGE Invalid configuration "$(CFG)" specified.
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "MySqlManager.mak" CFG="MySqlManager - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "MySqlManager - Win32 Release" (based on "Win32 (x86) Application")
-!MESSAGE "MySqlManager - Win32 Debug" (based on "Win32 (x86) Application")
-!MESSAGE
-!ERROR An invalid configuration is specified.
-!ENDIF
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE
-NULL=nul
-!ENDIF
-
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "MySqlManager - Win32 Release"
-
-OUTDIR=.\release
-INTDIR=.\release
-# Begin Custom Macros
-OutDir=.\release
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "..\client_release\MySqlManager.exe" "$(OUTDIR)\MySqlManager.pch"
-
-!ELSE
-
-ALL : "mysqlclient - Win32 Release" "..\client_release\MySqlManager.exe" "$(OUTDIR)\MySqlManager.pch"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"mysqlclient - Win32 ReleaseCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\ChildFrm.obj"
- -@erase "$(INTDIR)\MainFrm.obj"
- -@erase "$(INTDIR)\MySqlManager.obj"
- -@erase "$(INTDIR)\MySqlManager.pch"
- -@erase "$(INTDIR)\MySqlManager.res"
- -@erase "$(INTDIR)\MySqlManagerDoc.obj"
- -@erase "$(INTDIR)\MySqlManagerView.obj"
- -@erase "$(INTDIR)\RegisterServer.obj"
- -@erase "$(INTDIR)\StdAfx.obj"
- -@erase "$(INTDIR)\ToolSql.obj"
- -@erase "$(INTDIR)\ToolSqlQuery.obj"
- -@erase "$(INTDIR)\ToolSqlResults.obj"
- -@erase "$(INTDIR)\ToolSqlStatus.obj"
- -@erase "$(INTDIR)\vc60.idb"
- -@erase "..\client_release\MySqlManager.exe"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP_PROJ=/nologo /G6 /MT /W3 /GX /O1 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
-MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\MySqlManager.res" /d "NDEBUG" /d "_AFXDLL"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\MySqlManager.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=/nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\MySqlManager.pdb" /machine:I386 /out:"../client_release/MySqlManager.exe"
-LINK32_OBJS= \
- "$(INTDIR)\ChildFrm.obj" \
- "$(INTDIR)\MainFrm.obj" \
- "$(INTDIR)\MySqlManager.obj" \
- "$(INTDIR)\MySqlManagerDoc.obj" \
- "$(INTDIR)\MySqlManagerView.obj" \
- "$(INTDIR)\RegisterServer.obj" \
- "$(INTDIR)\StdAfx.obj" \
- "$(INTDIR)\ToolSql.obj" \
- "$(INTDIR)\ToolSqlQuery.obj" \
- "$(INTDIR)\ToolSqlResults.obj" \
- "$(INTDIR)\ToolSqlStatus.obj" \
- "$(INTDIR)\MySqlManager.res" \
- "..\lib_release\mysqlclient.lib"
-
-"..\client_release\MySqlManager.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-!ELSEIF "$(CFG)" == "MySqlManager - Win32 Debug"
-
-OUTDIR=.\debug
-INTDIR=.\debug
-# Begin Custom Macros
-OutDir=.\debug
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "..\client_debug\MySqlManager.exe" "$(OUTDIR)\MySqlManager.pch"
-
-!ELSE
-
-ALL : "mysqlclient - Win32 Debug" "..\client_debug\MySqlManager.exe" "$(OUTDIR)\MySqlManager.pch"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"mysqlclient - Win32 DebugCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\ChildFrm.obj"
- -@erase "$(INTDIR)\MainFrm.obj"
- -@erase "$(INTDIR)\MySqlManager.obj"
- -@erase "$(INTDIR)\MySqlManager.pch"
- -@erase "$(INTDIR)\MySqlManager.res"
- -@erase "$(INTDIR)\MySqlManagerDoc.obj"
- -@erase "$(INTDIR)\MySqlManagerView.obj"
- -@erase "$(INTDIR)\RegisterServer.obj"
- -@erase "$(INTDIR)\StdAfx.obj"
- -@erase "$(INTDIR)\ToolSql.obj"
- -@erase "$(INTDIR)\ToolSqlQuery.obj"
- -@erase "$(INTDIR)\ToolSqlResults.obj"
- -@erase "$(INTDIR)\ToolSqlStatus.obj"
- -@erase "$(INTDIR)\vc60.idb"
- -@erase "$(INTDIR)\vc60.pdb"
- -@erase "$(OUTDIR)\MySqlManager.pdb"
- -@erase "..\client_debug\MySqlManager.exe"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP_PROJ=/nologo /G6 /MTd /W3 /Gm /GX /ZI /Od /I "../include" /D "_DEBUG" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
-MTL_PROJ=/nologo /D "_DEBUG" /o "NUL" /win32
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\MySqlManager.res" /d "_DEBUG"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\MySqlManager.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\MySqlManager.pdb" /debug /machine:I386 /out:"../client_debug/MySqlManager.exe" /pdbtype:sept /libpath:"..\lib_debug\\"
-LINK32_OBJS= \
- "$(INTDIR)\ChildFrm.obj" \
- "$(INTDIR)\MainFrm.obj" \
- "$(INTDIR)\MySqlManager.obj" \
- "$(INTDIR)\MySqlManagerDoc.obj" \
- "$(INTDIR)\MySqlManagerView.obj" \
- "$(INTDIR)\RegisterServer.obj" \
- "$(INTDIR)\StdAfx.obj" \
- "$(INTDIR)\ToolSql.obj" \
- "$(INTDIR)\ToolSqlQuery.obj" \
- "$(INTDIR)\ToolSqlResults.obj" \
- "$(INTDIR)\ToolSqlStatus.obj" \
- "$(INTDIR)\MySqlManager.res" \
- "..\lib_debug\mysqlclient.lib"
-
-"..\client_debug\MySqlManager.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-!ENDIF
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-
-!IF "$(NO_EXTERNAL_DEPS)" != "1"
-!IF EXISTS("MySqlManager.dep")
-!INCLUDE "MySqlManager.dep"
-!ELSE
-!MESSAGE Warning: cannot find "MySqlManager.dep"
-!ENDIF
-!ENDIF
-
-
-!IF "$(CFG)" == "MySqlManager - Win32 Release" || "$(CFG)" == "MySqlManager - Win32 Debug"
-SOURCE=.\ChildFrm.cpp
-
-"$(INTDIR)\ChildFrm.obj" : $(SOURCE) "$(INTDIR)"
-
-
-SOURCE=.\MainFrm.cpp
-
-"$(INTDIR)\MainFrm.obj" : $(SOURCE) "$(INTDIR)"
-
-
-SOURCE=.\MySqlManager.cpp
-
-"$(INTDIR)\MySqlManager.obj" : $(SOURCE) "$(INTDIR)"
-
-
-SOURCE=.\MySqlManager.rc
-
-"$(INTDIR)\MySqlManager.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) $(RSC_PROJ) $(SOURCE)
-
-
-SOURCE=.\MySqlManagerDoc.cpp
-
-"$(INTDIR)\MySqlManagerDoc.obj" : $(SOURCE) "$(INTDIR)"
-
-
-SOURCE=.\MySqlManagerView.cpp
-
-"$(INTDIR)\MySqlManagerView.obj" : $(SOURCE) "$(INTDIR)"
-
-
-SOURCE=.\RegisterServer.cpp
-
-"$(INTDIR)\RegisterServer.obj" : $(SOURCE) "$(INTDIR)"
-
-
-SOURCE=.\StdAfx.cpp
-
-!IF "$(CFG)" == "MySqlManager - Win32 Release"
-
-CPP_SWITCHES=/nologo /G6 /MT /W3 /GX /O1 /I "../include" /D "NDEBUG" /D "DBUG_OFF" /D "_WINDOWS" /Fp"$(INTDIR)\MySqlManager.pch" /Yc"stdafx.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
-
-"$(INTDIR)\StdAfx.obj" "$(INTDIR)\MySqlManager.pch" : $(SOURCE) "$(INTDIR)"
- $(CPP) @<<
- $(CPP_SWITCHES) $(SOURCE)
-<<
-
-
-!ELSEIF "$(CFG)" == "MySqlManager - Win32 Debug"
-
-CPP_SWITCHES=/nologo /G6 /MTd /W3 /Gm /GX /ZI /Od /I "../include" /D "_DEBUG" /D "_WINDOWS" /Fp"$(INTDIR)\MySqlManager.pch" /Yc"stdafx.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
-
-"$(INTDIR)\StdAfx.obj" "$(INTDIR)\MySqlManager.pch" : $(SOURCE) "$(INTDIR)"
- $(CPP) @<<
- $(CPP_SWITCHES) $(SOURCE)
-<<
-
-
-!ENDIF
-
-SOURCE=.\ToolSql.cpp
-
-"$(INTDIR)\ToolSql.obj" : $(SOURCE) "$(INTDIR)"
-
-
-SOURCE=.\ToolSqlQuery.cpp
-
-"$(INTDIR)\ToolSqlQuery.obj" : $(SOURCE) "$(INTDIR)"
-
-
-SOURCE=.\ToolSqlResults.cpp
-
-"$(INTDIR)\ToolSqlResults.obj" : $(SOURCE) "$(INTDIR)"
-
-
-SOURCE=.\ToolSqlStatus.cpp
-
-"$(INTDIR)\ToolSqlStatus.obj" : $(SOURCE) "$(INTDIR)"
-
-
-!IF "$(CFG)" == "MySqlManager - Win32 Release"
-
-"mysqlclient - Win32 Release" :
- cd "\MYSQL-3.23\client"
- $(MAKE) /$(MAKEFLAGS) /F ".\mysqlclient.mak" CFG="mysqlclient - Win32 Release"
- cd "..\mysqlmanager"
-
-"mysqlclient - Win32 ReleaseCLEAN" :
- cd "\MYSQL-3.23\client"
- $(MAKE) /$(MAKEFLAGS) /F ".\mysqlclient.mak" CFG="mysqlclient - Win32 Release" RECURSE=1 CLEAN
- cd "..\mysqlmanager"
-
-!ELSEIF "$(CFG)" == "MySqlManager - Win32 Debug"
-
-"mysqlclient - Win32 Debug" :
- cd "\MYSQL-3.23\client"
- $(MAKE) /$(MAKEFLAGS) /F ".\mysqlclient.mak" CFG="mysqlclient - Win32 Debug"
- cd "..\mysqlmanager"
-
-"mysqlclient - Win32 DebugCLEAN" :
- cd "\MYSQL-3.23\client"
- $(MAKE) /$(MAKEFLAGS) /F ".\mysqlclient.mak" CFG="mysqlclient - Win32 Debug" RECURSE=1 CLEAN
- cd "..\mysqlmanager"
-
-!ENDIF
-
-
-!ENDIF
-
diff --git a/VC++Files/mysqlmanager/mysqlmanager.rc b/VC++Files/mysqlmanager/mysqlmanager.rc
deleted file mode 100644
index 1dd9caeb686..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanager.rc
+++ /dev/null
@@ -1,572 +0,0 @@
-//Microsoft Developer Studio generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE DISCARDABLE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE DISCARDABLE
-BEGIN
- "#include ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE DISCARDABLE
-BEGIN
- "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
- "#define _AFX_NO_OLE_RESOURCES\r\n"
- "#define _AFX_NO_TRACKER_RESOURCES\r\n"
- "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
- "\r\n"
- "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
- "#ifdef _WIN32\r\n"
- "LANGUAGE 9, 1\r\n"
- "#pragma code_page(1252)\r\n"
- "#endif\r\n"
- "#include ""res\\MySqlManager.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
- "#include ""afxres.rc"" // Standard components\r\n"
- "#include ""afxprint.rc"" // printing/print preview resources\r\n"
- "#endif\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDR_MAINFRAME ICON DISCARDABLE "res\\MySqlManager.ico"
-IDR_MYSQLMTYPE ICON DISCARDABLE "res\\MySqlManagerDoc.ico"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Bitmap
-//
-
-IDR_MAINFRAME BITMAP MOVEABLE PURE "res\\Toolbar.bmp"
-IDB_BITMAP1 BITMAP DISCARDABLE "res\\bitmap3.bmp"
-IDB_QUERY_EXECU BITMAP FIXED IMPURE "res\\query_ex.bmp"
-IDB_QUERY_EXECD BITMAP FIXED IMPURE "res\\bmp00001.bmp"
-IDB_FONTU BITMAP FIXED IMPURE "res\\fontu.bmp"
-IDB_FONTD BITMAP FIXED IMPURE "res\\fontd.bmp"
-IDB_DATABASESU BITMAP FIXED IMPURE "res\\database.bmp"
-IDB_DATABASESD BITMAP FIXED IMPURE "res\\bmp00002.bmp"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Toolbar
-//
-
-IDR_MAINFRAME TOOLBAR DISCARDABLE 16, 15
-BEGIN
- BUTTON ID_FILE_NEW
- BUTTON ID_FILE_OPEN
- BUTTON ID_FILE_SAVE
- SEPARATOR
- BUTTON ID_EDIT_CUT
- BUTTON ID_EDIT_COPY
- BUTTON ID_EDIT_PASTE
- SEPARATOR
- BUTTON ID_FILE_PRINT
- BUTTON ID_APP_ABOUT
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Menu
-//
-
-IDR_MAINFRAME MENU PRELOAD DISCARDABLE
-BEGIN
- POPUP "&File"
- BEGIN
- MENUITEM "&New\tCtrl+N", ID_FILE_NEW
- MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
- MENUITEM SEPARATOR
- MENUITEM "P&rint Setup...", ID_FILE_PRINT_SETUP
- MENUITEM SEPARATOR
- MENUITEM "Recent File", ID_FILE_MRU_FILE1, GRAYED
- MENUITEM SEPARATOR
- MENUITEM "E&xit", ID_APP_EXIT
- END
- POPUP "&View"
- BEGIN
- MENUITEM "&Toolbar", ID_VIEW_TOOLBAR
- MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR
- END
- POPUP "&Help"
- BEGIN
- MENUITEM "&About MySqlManager...", ID_APP_ABOUT
- END
-END
-
-IDR_MYSQLMTYPE MENU PRELOAD DISCARDABLE
-BEGIN
- POPUP "&File"
- BEGIN
- MENUITEM "&New\tCtrl+N", ID_FILE_NEW
- MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
- MENUITEM "&Close", ID_FILE_CLOSE
- MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE
- MENUITEM "Save &As...", ID_FILE_SAVE_AS
- MENUITEM SEPARATOR
- MENUITEM "&Print...\tCtrl+P", ID_FILE_PRINT
- MENUITEM "Print Pre&view", ID_FILE_PRINT_PREVIEW
- MENUITEM "P&rint Setup...", ID_FILE_PRINT_SETUP
- MENUITEM SEPARATOR
- MENUITEM "Recent File", ID_FILE_MRU_FILE1, GRAYED
- MENUITEM SEPARATOR
- MENUITEM "E&xit", ID_APP_EXIT
- END
- POPUP "&Edit"
- BEGIN
- MENUITEM "&Undo\tCtrl+Z", ID_EDIT_UNDO
- MENUITEM SEPARATOR
- MENUITEM "Cu&t\tCtrl+X", ID_EDIT_CUT
- MENUITEM "&Copy\tCtrl+C", ID_EDIT_COPY
- MENUITEM "&Paste\tCtrl+V", ID_EDIT_PASTE
- END
- POPUP "&Tools"
- BEGIN
- MENUITEM "SQL &Query", IDM_SQL_TOOL_QUERY
- MENUITEM "Register Server", IDM_TOOLS_REGISTER_SERVER
- MENUITEM "Server Properties", IDM_TOOLS_SERVER_PROPERTIES
- END
- POPUP "&View"
- BEGIN
- MENUITEM "&Toolbar", ID_VIEW_TOOLBAR
- MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR
- END
- POPUP "&Window"
- BEGIN
- MENUITEM "&New Window", ID_WINDOW_NEW
- MENUITEM "&Cascade", ID_WINDOW_CASCADE
- MENUITEM "&Tile", ID_WINDOW_TILE_HORZ
- MENUITEM "&Arrange Icons", ID_WINDOW_ARRANGE
- END
- POPUP "&Help"
- BEGIN
- MENUITEM "&About MySqlManager...", ID_APP_ABOUT
- END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Accelerator
-//
-
-IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE
-BEGIN
- "C", ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
- "D", IDM_QUERY_DATABASES, VIRTKEY, ALT, NOINVERT
- "E", IDM_QUERY_EXEC, VIRTKEY, CONTROL, NOINVERT
- "N", ID_FILE_NEW, VIRTKEY, CONTROL, NOINVERT
- "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
- "P", ID_FILE_PRINT, VIRTKEY, CONTROL, NOINVERT
- "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT
- "V", ID_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT
- VK_BACK, ID_EDIT_UNDO, VIRTKEY, ALT, NOINVERT
- VK_DELETE, ID_EDIT_CUT, VIRTKEY, SHIFT, NOINVERT
- VK_F6, ID_NEXT_PANE, VIRTKEY, NOINVERT
- VK_F6, ID_PREV_PANE, VIRTKEY, SHIFT, NOINVERT
- VK_INSERT, ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
- VK_INSERT, ID_EDIT_PASTE, VIRTKEY, SHIFT, NOINVERT
- "X", ID_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT
- "X", IDM_QUERY_EXEC, VIRTKEY, ALT, NOINVERT
- "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL, NOINVERT
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 234, 72
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "About MySqlManager"
-FONT 8, "MS Sans Serif"
-BEGIN
- ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20
- LTEXT "MySqlManager Version 1.0.2",IDC_STATIC,37,10,119,8,
- SS_NOPREFIX
- LTEXT "By James Pereira (jpereira@iafrica.com)",IDC_STATIC,37,
- 49,146,9
- DEFPUSHBUTTON "OK",IDOK,195,7,32,14,WS_GROUP
- LTEXT "This file is public domain and comes with NO WARRANTY of any kind",
- IDC_STATIC,38,25,136,18,SS_SUNKEN
-END
-
-IDD_TOOL_SQL DIALOGEX 0, 0, 452, 246
-STYLE DS_3DLOOK | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION |
- WS_SYSMENU | WS_THICKFRAME
-EXSTYLE WS_EX_CLIENTEDGE
-CAPTION "mySQL Query Tool"
-FONT 8, "MS Sans Serif", 0, 0, 0x1
-BEGIN
- PUSHBUTTON "OK",IDOK,369,10,12,14,NOT WS_VISIBLE
- DEFPUSHBUTTON "Close",IDCANCEL,391,10,50,14
- CONTROL "Tab1",IDC_TAB1,"SysTabControl32",0x0,11,26,434,213
- CONTROL "IDB_QUERY_EXEC",IDC_QUERY_PB,"Button",BS_OWNERDRAW |
- WS_TABSTOP,106,10,12,14
- CONTROL "IDB_FONT",IDC_FONT_PB,"Button",BS_OWNERDRAW |
- WS_TABSTOP,123,10,12,14
- COMBOBOX IDC_SERVER_CB,12,9,85,128,CBS_DROPDOWN | CBS_SORT |
- WS_VSCROLL | WS_TABSTOP
- CONTROL "IDB_DATABASES",IDC_DATABASES_PB,"Button",BS_OWNERDRAW |
- WS_TABSTOP,142,10,12,14
- DEFPUSHBUTTON "&Start",IDC_START_PB,315,10,23,14
- DEFPUSHBUTTON "S&top",IDC_STOP_PB,343,10,23,14
- EDITTEXT IDC_TIMER_SECS,287,10,22,14,ES_AUTOHSCROLL
- LTEXT "Interval (s)",IDC_STATIC,249,11,34,8
- CONTROL "Clear",IDC_CLEAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
- 215,11,29,10
-END
-
-IDD_TOOL_SQL_QUERY DIALOG DISCARDABLE 0, 0, 452, 247
-STYLE WS_CHILD | WS_BORDER
-FONT 8, "MS Sans Serif"
-BEGIN
- EDITTEXT IDC_EDIT,11,11,434,229,ES_MULTILINE | ES_AUTOVSCROLL |
- ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL
-END
-
-IDD_TOOL_SQL_RESULTS DIALOG DISCARDABLE 0, 0, 452, 247
-STYLE WS_CHILD | WS_BORDER
-FONT 8, "MS Sans Serif"
-BEGIN
- EDITTEXT IDC_EDIT,11,11,434,229,ES_MULTILINE | ES_AUTOVSCROLL |
- ES_AUTOHSCROLL | WS_VSCROLL
-END
-
-IDD_REGISTER_SERVER DIALOG FIXED IMPURE 0, 0, 281, 199
-STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-CAPTION "Register Server"
-FONT 8, "MS Sans Serif"
-BEGIN
- GROUPBOX "",-1,5,0,270,195
- LTEXT "&Server:",-1,12,14,25,8
- COMBOBOX ID_SERVER_CB,46,12,159,60,CBS_DROPDOWN | CBS_AUTOHSCROLL |
- CBS_SORT | WS_VSCROLL | WS_TABSTOP
- LTEXT "&Host",-1,12,33,25,8
- COMBOBOX ID_HOST_CB,46,31,159,60,CBS_DROPDOWN | CBS_AUTOHSCROLL |
- CBS_SORT | WS_VSCROLL | WS_TABSTOP
- LTEXT "&Port",-1,12,53,25,8
- COMBOBOX ID_PORT_CB,46,50,159,60,CBS_DROPDOWN | CBS_AUTOHSCROLL |
- CBS_SORT | WS_VSCROLL | WS_TABSTOP
- GROUPBOX "Login Information",-1,12,82,194,76
- CONTROL "Use S&tandard Security",ID_USE_STANDARD_CK,"Button",
- BS_AUTORADIOBUTTON | WS_GROUP,19,107,94,11
- CONTROL "Use Tr&usted Connection",ID_USE_TRUSTED_CK,"Button",
- BS_AUTORADIOBUTTON,19,94,99,11
- LTEXT "&Login ID:",1060,37,124,35,8
- EDITTEXT ID_USER,77,122,120,12,ES_AUTOHSCROLL | WS_GROUP
- LTEXT "&Password:",1061,37,140,35,8
- EDITTEXT ID_PASSWORD,77,138,120,12,ES_PASSWORD | ES_AUTOHSCROLL
- LTEXT "S&erver Group:",-1,12,164,24,25
- CONTROL "&Display Server Status in Server Manager",
- ID_DISPLAY_SERVER_STATUS_CK,"Button",BS_AUTOCHECKBOX |
- WS_TABSTOP,44,168,152,10
- DEFPUSHBUTTON "&Register",IDOK,214,11,53,14
- PUSHBUTTON "Re&move",ID_REMOVE_PB,214,27,53,14
- PUSHBUTTON "&Close",IDCANCEL,214,43,53,14
- PUSHBUTTON "&Help",ID_HELP,214,59,53,14
- PUSHBUTTON "Ser&vers...",ID_SERVERS_PB,214,92,53,14
- PUSHBUTTON "&Groups...",ID_GROUPS_PB,214,108,53,14
-END
-
-IDD_TOOL_SQL_STATUS DIALOG DISCARDABLE 0, 0, 452, 247
-STYLE WS_CHILD | WS_BORDER
-FONT 8, "MS Sans Serif"
-BEGIN
- EDITTEXT IDC_EDIT,11,11,434,229,ES_MULTILINE | ES_AUTOVSCROLL |
- ES_AUTOHSCROLL | WS_VSCROLL
-END
-
-
-#ifndef _MAC
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,2
- PRODUCTVERSION 1,0,0,2
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x1L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", "\0"
- VALUE "FileDescription", "MySqlManager MFC Application\0"
- VALUE "FileVersion", "1, 0, 0, 2\0"
- VALUE "InternalName", "MySqlManager\0"
- VALUE "LegalCopyright", "Copyright (C) 1998\0"
- VALUE "OriginalFilename", "MySqlManager.EXE\0"
- VALUE "ProductName", "MySqlManager Application\0"
- VALUE "ProductVersion", "1, 0, 0, 2\0"
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-#endif // !_MAC
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO DISCARDABLE
-BEGIN
- IDD_ABOUTBOX, DIALOG
- BEGIN
- LEFTMARGIN, 6
- RIGHTMARGIN, 227
- TOPMARGIN, 7
- BOTTOMMARGIN, 65
- END
-
- IDD_TOOL_SQL, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 445
- TOPMARGIN, 7
- BOTTOMMARGIN, 239
- END
-
- IDD_TOOL_SQL_QUERY, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 445
- TOPMARGIN, 7
- BOTTOMMARGIN, 240
- END
-
- IDD_TOOL_SQL_RESULTS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 445
- TOPMARGIN, 7
- BOTTOMMARGIN, 240
- END
-
- IDD_TOOL_SQL_STATUS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 445
- TOPMARGIN, 7
- BOTTOMMARGIN, 240
- END
-END
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE PRELOAD DISCARDABLE
-BEGIN
- IDR_MAINFRAME "MySqlManager"
- IDR_MYSQLMTYPE "\nMySqlM\nMySqlM\n\n\nMySqlManager.Document\nMySqlM Document"
-END
-
-STRINGTABLE PRELOAD DISCARDABLE
-BEGIN
- AFX_IDS_APP_TITLE "MySqlManager"
- AFX_IDS_IDLEMESSAGE "Ready"
- IDS_QUERY_DATABASES "Query Database(s)"
- IDS_REFRESH "Refresh"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_INDICATOR_EXT "EXT"
- ID_INDICATOR_CAPS "CAP"
- ID_INDICATOR_NUM "NUM"
- ID_INDICATOR_SCRL "SCRL"
- ID_INDICATOR_OVR "OVR"
- ID_INDICATOR_REC "REC"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_FILE_NEW "Create a new document\nNew"
- ID_FILE_OPEN "Open an existing document\nOpen"
- ID_FILE_CLOSE "Close the active document\nClose"
- ID_FILE_SAVE "Save the active document\nSave"
- ID_FILE_SAVE_AS "Save the active document with a new name\nSave As"
- ID_FILE_PAGE_SETUP "Change the printing options\nPage Setup"
- ID_FILE_PRINT_SETUP "Change the printer and printing options\nPrint Setup"
- ID_FILE_PRINT "Print the active document\nPrint"
- ID_FILE_PRINT_PREVIEW "Display full pages\nPrint Preview"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_APP_ABOUT "Display program information, version number and copyright\nAbout"
- ID_APP_EXIT "Quit the application; prompts to save documents\nExit"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_FILE_MRU_FILE1 "Open this document"
- ID_FILE_MRU_FILE2 "Open this document"
- ID_FILE_MRU_FILE3 "Open this document"
- ID_FILE_MRU_FILE4 "Open this document"
- ID_FILE_MRU_FILE5 "Open this document"
- ID_FILE_MRU_FILE6 "Open this document"
- ID_FILE_MRU_FILE7 "Open this document"
- ID_FILE_MRU_FILE8 "Open this document"
- ID_FILE_MRU_FILE9 "Open this document"
- ID_FILE_MRU_FILE10 "Open this document"
- ID_FILE_MRU_FILE11 "Open this document"
- ID_FILE_MRU_FILE12 "Open this document"
- ID_FILE_MRU_FILE13 "Open this document"
- ID_FILE_MRU_FILE14 "Open this document"
- ID_FILE_MRU_FILE15 "Open this document"
- ID_FILE_MRU_FILE16 "Open this document"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_NEXT_PANE "Switch to the next window pane\nNext Pane"
- ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_WINDOW_NEW "Open another window for the active document\nNew Window"
- ID_WINDOW_ARRANGE "Arrange icons at the bottom of the window\nArrange Icons"
- ID_WINDOW_CASCADE "Arrange windows so they overlap\nCascade Windows"
- ID_WINDOW_TILE_HORZ "Arrange windows as non-overlapping tiles\nTile Windows"
- ID_WINDOW_TILE_VERT "Arrange windows as non-overlapping tiles\nTile Windows"
- ID_WINDOW_SPLIT "Split the active window into panes\nSplit"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_EDIT_CLEAR "Erase the selection\nErase"
- ID_EDIT_CLEAR_ALL "Erase everything\nErase All"
- ID_EDIT_COPY "Copy the selection and put it on the Clipboard\nCopy"
- ID_EDIT_CUT "Cut the selection and put it on the Clipboard\nCut"
- ID_EDIT_FIND "Find the specified text\nFind"
- ID_EDIT_PASTE "Insert Clipboard contents\nPaste"
- ID_EDIT_REPEAT "Repeat the last action\nRepeat"
- ID_EDIT_REPLACE "Replace specific text with different text\nReplace"
- ID_EDIT_SELECT_ALL "Select the entire document\nSelect All"
- ID_EDIT_UNDO "Undo the last action\nUndo"
- ID_EDIT_REDO "Redo the previously undone action\nRedo"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_VIEW_TOOLBAR "Show or hide the toolbar\nToggle ToolBar"
- ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- AFX_IDS_SCSIZE "Change the window size"
- AFX_IDS_SCMOVE "Change the window position"
- AFX_IDS_SCMINIMIZE "Reduce the window to an icon"
- AFX_IDS_SCMAXIMIZE "Enlarge the window to full size"
- AFX_IDS_SCNEXTWINDOW "Switch to the next document window"
- AFX_IDS_SCPREVWINDOW "Switch to the previous document window"
- AFX_IDS_SCCLOSE "Close the active window and prompts to save the documents"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- AFX_IDS_SCRESTORE "Restore the window to normal size"
- AFX_IDS_SCTASKLIST "Activate Task List"
- AFX_IDS_MDICHILD "Activate this window"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- AFX_IDS_PREVIEW_CLOSE "Close print preview mode\nCancel Preview"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- IDC_QUERY_PB "Execute Query"
- IDS_QUERY_EXEC "Execute Query"
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-#define _AFX_NO_SPLITTER_RESOURCES
-#define _AFX_NO_OLE_RESOURCES
-#define _AFX_NO_TRACKER_RESOURCES
-#define _AFX_NO_PROPERTY_RESOURCES
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE 9, 1
-#pragma code_page(1252)
-#endif
-#include "res\MySqlManager.rc2" // non-Microsoft Visual C++ edited resources
-#include "afxres.rc" // Standard components
-#include "afxprint.rc" // printing/print preview resources
-#endif
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
diff --git a/VC++Files/mysqlmanager/mysqlmanagerdoc.cpp b/VC++Files/mysqlmanager/mysqlmanagerdoc.cpp
deleted file mode 100644
index c89ce693a60..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanagerdoc.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-// MySqlManagerDoc.cpp : implementation of the CMySqlManagerDoc class
-//
-
-#include "stdafx.h"
-#include "MySqlManager.h"
-
-#include "MySqlManagerDoc.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerDoc
-
-IMPLEMENT_DYNCREATE(CMySqlManagerDoc, CDocument)
-
-BEGIN_MESSAGE_MAP(CMySqlManagerDoc, CDocument)
- //{{AFX_MSG_MAP(CMySqlManagerDoc)
- // NOTE - the ClassWizard will add and remove mapping macros here.
- // DO NOT EDIT what you see in these blocks of generated code!
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerDoc construction/destruction
-
-CMySqlManagerDoc::CMySqlManagerDoc()
-{
- // TODO: add one-time construction code here
-
-}
-
-CMySqlManagerDoc::~CMySqlManagerDoc()
-{
-}
-
-BOOL CMySqlManagerDoc::OnNewDocument()
-{
- if (!CDocument::OnNewDocument())
- return FALSE;
-
- // TODO: add reinitialization code here
- // (SDI documents will reuse this document)
-
- return TRUE;
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerDoc serialization
-
-void CMySqlManagerDoc::Serialize(CArchive& ar)
-{
- if (ar.IsStoring())
- {
- // TODO: add storing code here
- }
- else
- {
- // TODO: add loading code here
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerDoc diagnostics
-
-#ifdef _DEBUG
-void CMySqlManagerDoc::AssertValid() const
-{
- CDocument::AssertValid();
-}
-
-void CMySqlManagerDoc::Dump(CDumpContext& dc) const
-{
- CDocument::Dump(dc);
-}
-#endif //_DEBUG
-
-/////////////////////////////////////////////////////////////////////////////
-// CMySqlManagerDoc commands
diff --git a/VC++Files/mysqlmanager/mysqlmanagerdoc.h b/VC++Files/mysqlmanager/mysqlmanagerdoc.h
deleted file mode 100644
index f4a4d35cfd5..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanagerdoc.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// MySqlManagerDoc.h : interface of the CMySqlManagerDoc class
-//
-/////////////////////////////////////////////////////////////////////////////
-
-#if !defined(AFX_MYSQLMANAGERDOC_H__826CB2F2_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_MYSQLMANAGERDOC_H__826CB2F2_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-
-class CMySqlManagerDoc : public CDocument
-{
-protected: // create from serialization only
- CMySqlManagerDoc();
- DECLARE_DYNCREATE(CMySqlManagerDoc)
-
-// Attributes
-public:
-
-// Operations
-public:
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CMySqlManagerDoc)
- public:
- virtual BOOL OnNewDocument();
- virtual void Serialize(CArchive& ar);
- //}}AFX_VIRTUAL
-
-// Implementation
-public:
- virtual ~CMySqlManagerDoc();
-#ifdef _DEBUG
- virtual void AssertValid() const;
- virtual void Dump(CDumpContext& dc) const;
-#endif
-
-protected:
-
-// Generated message map functions
-protected:
- //{{AFX_MSG(CMySqlManagerDoc)
- // NOTE - the ClassWizard will add and remove member functions here.
- // DO NOT EDIT what you see in these blocks of generated code !
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-/////////////////////////////////////////////////////////////////////////////
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_MYSQLMANAGERDOC_H__826CB2F2_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/mysqlmanagerview.cpp b/VC++Files/mysqlmanager/mysqlmanagerview.cpp
deleted file mode 100644
index 1d4756e7d7a..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanagerview.cpp
+++ /dev/null
@@ -1,849 +0,0 @@
-// MySqlManagerView.cpp : implementation of the CMySqlManagerView class
-//
-
-#include "stdafx.h"
-#include "MySqlManager.h"
-#include "MySqlManagerDoc.h"
-#include "MySqlManagerView.h"
-#include "mainfrm.h"
-#include "ToolSql.h"
-#include "RegisterServer.h"
-
-class XStatus
-{
-public:
- XStatus ( LPCSTR fmt, ... )
- {
- char buf [2048];
- va_list args;
- va_start(args, fmt);
- int ret = vsprintf(buf, fmt, args);
- MainFrame->StatusMsg ( "%s", buf );
- va_end(args);
- }
- ~XStatus()
- {
- MainFrame->StatusMsg ( " ");
- }
-private:
- XStatus();
-};
-
-#ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-
-IMPLEMENT_DYNCREATE(CMySqlManagerView, CTreeView)
-
-BEGIN_MESSAGE_MAP(CMySqlManagerView, CTreeView)
-//{{AFX_MSG_MAP(CMySqlManagerView)
-ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
-ON_COMMAND(IDM_SQL_TOOL_QUERY, OnSqlToolQuery)
-ON_COMMAND(IDM_REFRESH, OnRefresh)
-ON_COMMAND(IDM_TOOLS_SERVER_PROPERTIES,OnServerProperties)
-ON_COMMAND(IDM_TOOLS_REGISTER_SERVER, OnRegisterServer)
-ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick)
-//}}AFX_MSG_MAP
-// Standard printing commands
-ON_COMMAND(ID_FILE_PRINT, CTreeView::OnFilePrint)
-ON_COMMAND(ID_FILE_PRINT_DIRECT, CTreeView::OnFilePrint)
-ON_COMMAND(ID_FILE_PRINT_PREVIEW, CTreeView::OnFilePrintPreview)
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-
-CMySqlManagerView::CMySqlManagerView()
-: m_pTree(0)
-, m_pImages(0)
-, m_pbmBmp(0)
-, m_pTool(0)
-{
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-CMySqlManagerView::~CMySqlManagerView()
-{
- if ( m_pbmBmp ) delete m_pbmBmp;
- if ( m_pImages ) delete m_pImages;
- if ( m_pTool )
- {
- m_pTool->DestroyWindow();
- delete m_pTool;
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-BOOL CMySqlManagerView::PreCreateWindow(CREATESTRUCT& cs)
-{
- return CTreeView::PreCreateWindow(cs);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::OnDraw(CDC* pDC)
-{
- CMySqlManagerDoc* pDoc = GetDocument();
- ASSERT_VALID(pDoc);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-BOOL CMySqlManagerView::OnPreparePrinting(CPrintInfo* pInfo)
-{
- return DoPreparePrinting(pInfo);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
-{
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
-{
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-#ifdef _DEBUG
-void CMySqlManagerView::AssertValid() const
-{
- CTreeView::AssertValid();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::Dump(CDumpContext& dc) const
-{
- CTreeView::Dump(dc);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-CMySqlManagerDoc* CMySqlManagerView::GetDocument() // non-debug version is inline
-{
- ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMySqlManagerDoc)));
- return (CMySqlManagerDoc*)m_pDocument;
-}
-#endif //_DEBUG
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::OnInitialUpdate()
-{
-
- CTreeView::OnInitialUpdate();
-
- m_pTree = & GetTreeCtrl();
- m_pImages = new CImageList;
- m_pImages->Create( 16, 16, FALSE, 0, 10 );
- m_pbmBmp = new CBitmap;
- m_pbmBmp->LoadBitmap( IDB_BITMAP1 );
- m_pImages->Add( m_pbmBmp, (COLORREF)0 );
- m_pTree->SetImageList( m_pImages, TVSIL_NORMAL );
-
- HTREEITEM h = AddResource ( TVI_ROOT, new CResourceServer ( "MySQL", "localhost", "root", "" ) );
-// AddResource ( h, new CResourceProcesslist () );
- h = AddResource ( TVI_ROOT, new CResourceServer ( "Test", "localhost", "test", "" ) );
-// AddResource ( h, new CResourceProcesslist () );
-
- m_pTree->ModifyStyle(0, TVS_HASLINES|TVS_HASBUTTONS);
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-HTREEITEM CMySqlManagerView::AddResource ( HTREEITEM hParent, CResource* pRes, HTREEITEM hLastItem )
-{
-
- TV_INSERTSTRUCT ItemStruct;
- memset( &ItemStruct, 0, sizeof(ItemStruct) );
- ItemStruct.hParent = hParent;
- ItemStruct.hInsertAfter = hLastItem;
- ItemStruct.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_IMAGE;
- ItemStruct.item.hItem = 0;
- ItemStruct.item.state = 0;
- ItemStruct.item.stateMask = 0;
- ItemStruct.item.pszText = (LPSTR) pRes->GetDisplayName();
- ItemStruct.item.cchTextMax = (int) strlen( ItemStruct.item.pszText );
- ItemStruct.item.iImage = 2;
- ItemStruct.item.iSelectedImage = 3;
- ItemStruct.item.cChildren = 0;
- ItemStruct.item.lParam = (long) pRes;
- hLastItem = m_pTree->InsertItem( &ItemStruct );
- return hLastItem;
-}
-
-//int InsertNetResources( LPNETRESOURCE lpNetResource, CTreeCtrl *pTreeCtrl, HTREEITEM hParent, int *pnCount )
-//{
-//
-// DWORD Erc;
-// NETRESOURCE *pNetRes;
-// HANDLE hEnum;
-//
-// if( !pTreeCtrl ) return -1;
-// if( pnCount ) *pnCount = 0;
-// Erc = WNetOpenEnum(
-// RESOURCE_GLOBALNET,//DWORD dwScope, // scope of enumeration
-// RESOURCETYPE_ANY,//DWORD dwType, // resource types to list
-// 0,//DWORD dwUsage, // resource usage to list
-// lpNetResource,//LPNETRESOURCE lpNetResource, // pointer to resource structure
-// &hEnum//LPHANDLE lphEnum // pointer to enumeration handle buffer
-// );
-// if( Erc )
-// {
-// ShowError( Erc );
-// return Erc;
-// }
-//
-//
-// DWORD dwBufferSize = 1024;
-// pNetRes = (NETRESOURCE *)malloc( dwBufferSize );
-//
-// while( TRUE )
-// {
-// DWORD dwCount = 0xFFFFFFFF;
-// Erc = WNetEnumResource(
-// hEnum,//HANDLE hEnum, // handle to enumeration
-// &dwCount,//LPDWORD lpcCount, // pointer to entries to list
-// pNetRes,//LPVOID lpBuffer, // pointer to buffer for results
-// &dwBufferSize//LPDWORD lpBufferSize // pointer to buffer size variable
-// );
-// if( Erc == ERROR_NO_MORE_ITEMS ) return 0;
-// if( Erc )
-// {
-// free( pNetRes );
-// pNetRes = (NETRESOURCE *)malloc( dwBufferSize );
-// Erc = WNetEnumResource(
-// hEnum,//HANDLE hEnum, // handle to enumeration
-// &dwCount,//LPDWORD lpcCount, // pointer to entries to list
-// pNetRes,//LPVOID lpBuffer, // pointer to buffer for results
-// &dwBufferSize//LPDWORD lpBufferSize // pointer to buffer size variable
-// );
-// }
-// if( Erc ){ ShowError( Erc ); return Erc; }
-//
-// TV_INSERTSTRUCT ItemStruct;
-// HTREEITEM hLastItem = TVI_FIRST;
-// DWORD i;
-//
-// if( pnCount ) *pnCount += dwCount;
-// for( i=0; i<dwCount; i++ )
-// {
-// memset( &ItemStruct, 0, sizeof(ItemStruct) );
-// ItemStruct.hParent = hParent;
-// ItemStruct.hInsertAfter = hLastItem;
-// ItemStruct.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_IMAGE;
-// ItemStruct.item.hItem = 0;
-// ItemStruct.item.state = 0;
-// ItemStruct.item.stateMask = 0;
-// ItemStruct.item.pszText = pNetRes[i].lpRemoteName;
-// ItemStruct.item.cchTextMax = strlen( ItemStruct.item.pszText );
-// ItemStruct.item.iImage = 2;
-// ItemStruct.item.iSelectedImage = 3;
-// ItemStruct.item.cChildren = 0;
-// ItemStruct.item.lParam = (long) (new CNetResource( &pNetRes[i] ));
-//
-// hLastItem = pTreeCtrl->InsertItem( &ItemStruct );
-// }
-// }//end while()
-//
-// WNetCloseEnum( hEnum );
-// free( pNetRes );
-// return Erc;
-//}
-
-/////////////////////////////////////////////////////////////////////////////
-
-static void print_top(MYSQL_RES *result)
-{
- uint length;
- MYSQL_FIELD *field;
- mysql_field_seek(result,0);
- while ((field = mysql_fetch_field(result)))
- {
- if ((length= (uint) strlen(field->name)) > field->max_length)
- field->max_length=length;
- else
- length=field->max_length;
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-static void print_header(MYSQL_RES *result,CStringArray& rg)
-{
- MYSQL_FIELD *field;
- print_top(result);
- mysql_field_seek(result,0);
- while ((field = mysql_fetch_field(result)))
- {
-// printf(" %-*s|",field->max_length+1,field->name);
- rg.Add(field->name);
- }
- print_top(result);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-static void print_row(MYSQL_RES *result,MYSQL_ROW row,CStringArray& rg)
-{
- uint i,length;
- MYSQL_FIELD *field;
- mysql_field_seek(result,0);
- for (i=0 ; i < mysql_num_fields(result); i++)
- {
- field = mysql_fetch_field(result);
- length=field->max_length;
- rg.Add(row[i] ? (char*) row[i] : "");
-// printf(" %-*s|",length+1,row[i] ? (char*) row[i] : "");
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::ProcessResultSet ( HTREEITEM hItem, LPVOID r, CResource* pResource )
-{
-
- MYSQL_RES* result = (MYSQL_RES *) r;
- MYSQL_ROW row;
-
- switch (pResource->GetType())
- {
- case CResource::eProcesslist:
- {
- CResourceProcesslist* p = (CResourceProcesslist*) pResource;
- CResourceProcesslistItem* pi = new CResourceProcesslistItem ();
- CString strText;
- print_header(result,p->m_rgFields);
- for (int i = 0; i<p->m_rgFields.GetSize(); i++ )
- {
- strText += p->m_rgFields[i];
- strText += " ";
- }
- pi->m_strName = strText;
- AddResource ( hItem, pi );
- for (int index=0;(row=mysql_fetch_row(result));index++)
- {
- pi = new CResourceProcesslistItem ();
- print_row(result,row,pi->m_rgFields);
- strText.Empty();
- for (int i = 0; i<pi->m_rgFields.GetSize(); i++ )
- {
- strText += pi->m_rgFields[i];
- strText += " ";
- }
- pi->m_strName = strText;
- AddResource ( hItem, pi );
- }
- print_top(result);
- break;
- }
- case CResource::eServer:
- {
- CResourceServer* p = (CResourceServer*) pResource;
- CResourceDatabase* pi = new CResourceDatabase ();
- CString strText;
- /* print_header(result,p->m_rgFields); */
- for (int i = 0; i<p->m_rgFields.GetSize(); i++ )
- {
- strText += p->m_rgFields[i];
- strText += " ";
- }
- pi->m_strName = strText;
- /* AddResource ( hItem, pi ); */
- for (int index=0;(row=mysql_fetch_row(result));index++)
- {
- pi = new CResourceDatabase ();
- print_row(result,row,pi->m_rgFields);
- strText.Empty();
- for (int i = 0; i<pi->m_rgFields.GetSize(); i++ )
- {
- strText += pi->m_rgFields[i];
- strText += " ";
- }
- pi->m_strName = strText;
- AddResource ( hItem, pi );
- }
- print_top(result);
- break;
- }
- case CResource::eDatabase:
- {
- CResourceDatabase* p = (CResourceDatabase*) pResource;
- CResourceTable* pi = new CResourceTable ();
- CString strText;
- /* print_header(result,p->m_rgFields); */
- for (int i = 0; i<p->m_rgFields.GetSize(); i++ )
- {
- strText += p->m_rgFields[i];
- strText += " ";
- }
- pi->m_strName = strText;
- /* AddResource ( hItem, pi ); */
- for (int index=0;(row=mysql_fetch_row(result));index++)
- {
- pi = new CResourceTable ();
- print_row(result,row,pi->m_rgFields);
- strText.Empty();
- for (int i = 0; i<pi->m_rgFields.GetSize(); i++ )
- {
- strText += pi->m_rgFields[i];
- strText += " ";
- }
- pi->m_strName = strText;
- AddResource ( hItem, pi );
- }
- print_top(result);
- break;
- }
- case CResource::eTable:
- {
- CResourceTable* p = (CResourceTable*) pResource;
- CResourceField* pi = new CResourceField ();
- CString strText;
- /* print_header(result,p->m_rgFields); */
- for (int i = 0; i<p->m_rgFields.GetSize(); i++ )
- {
- strText += p->m_rgFields[i];
- strText += " ";
- }
- pi->m_strName = strText;
- /* AddResource ( hItem, pi ); */
- for (int index=0;(row=mysql_fetch_row(result));index++)
- {
- pi = new CResourceField ();
- print_row(result,row,pi->m_rgFields);
- strText.Empty();
- for (int i = 0; i<pi->m_rgFields.GetSize(); i++ )
- {
- strText += pi->m_rgFields[i];
- strText += " ";
- }
- pi->m_strName = strText;
- AddResource ( hItem, pi );
- }
- print_top(result);
- break;
- }
- }
-
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-CResource* CMySqlManagerView::GetSelectedResource(HTREEITEM* phItemRet)
-{
- CResource* pResource = NULL;
- HTREEITEM hItem = m_pTree->GetSelectedItem();
- if ( hItem )
- {
- TV_ITEM item;
- memset( &item, 0, sizeof(TV_ITEM) );
- item.hItem = hItem;
- item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM ;
- m_pTree->GetItem( &item );
- if ( item.lParam )
- {
- pResource = (CResource*) item.lParam;
- }
- }
- if (phItemRet)
- {
- *phItemRet = hItem;
- }
- return pResource;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-CResourceServer* CMySqlManagerView::GetServerResource(HTREEITEM hItem)
-{
-
- TV_ITEM item;
-
- memset( &item, 0, sizeof(TV_ITEM) );
- item.hItem = hItem;
- item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM ;
- m_pTree->GetItem( &item );
- if ( !item.lParam ) return NULL;
-
- CResource* pResource = (CResource*) item.lParam;
-
- switch (pResource->GetType())
- {
- case CResource::eServer:
- {
- return (CResourceServer*) pResource;
- }
- case CResource::eDatabase:
- {
- HTREEITEM hParent = m_pTree->GetParentItem(hItem);
- memset( &item, 0, sizeof(TV_ITEM) );
- item.hItem = hParent;
- item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM ;
- m_pTree->GetItem( &item );
- if ( !item.lParam ) return NULL;
- return (CResourceServer*) item.lParam;
- }
- case CResource::eTable:
- {
- HTREEITEM hParent = m_pTree->GetParentItem(m_pTree->GetParentItem(hItem));
- memset( &item, 0, sizeof(TV_ITEM) );
- item.hItem = hParent;
- item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM ;
- m_pTree->GetItem( &item );
- if ( !item.lParam ) return NULL;
- return (CResourceServer*) item.lParam;
- }
- }
-
- return NULL;
-
-}
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult)
-{
- HTREEITEM hItem;
- hItem = m_pTree->GetSelectedItem();
- *pResult = 0;
- if ( !hItem ) return;
-
- TV_ITEM item;
- memset( &item, 0, sizeof(TV_ITEM) );
- item.hItem = hItem;
- item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM ;
- m_pTree->GetItem( &item );
-
- if ( ! item.lParam ) return;
-
- if ( item.cChildren ) return; //if has got children expand only
-
- CWaitCursor x;
-
- CResource* pResource = (CResource*) item.lParam;
-
- MYSQL mysql;
- MYSQL_RES *result;
-
- switch (pResource->GetType())
- {
- case CResource::eProcesslist:
- {
- XStatus x ( "Connecting to server %s on host %s..."
- , (LPCTSTR) pResource->GetDisplayName()
- , (LPCTSTR) pResource->GetHostName()
- );
- mysql_init(&mysql);
- if (!mysql_real_connect(&mysql,pResource->GetHostName(), pResource->GetUserName(),pResource->GetPassword(),0,pResource->GetPortNumber(), NullS,0))
- {
- PostMessage(WM_COMMAND,IDM_TOOLS_SERVER_PROPERTIES);
- return;
- }
- if (!(result=mysql_list_processes(&mysql)))
- {
- return;
- }
- ProcessResultSet ( hItem, result, pResource );
- mysql_free_result(result);
- mysql_close(&mysql);
- break;
- }
- case CResource::eServer:
- {
- MainFrame->StatusMsg ( "Connecting to server %s on host %s..."
- , (LPCTSTR) pResource->GetDisplayName()
- , (LPCTSTR) pResource->GetHostName()
- );
- mysql_init(&mysql);
- if (!mysql_real_connect(&mysql,pResource->GetHostName(), pResource->GetUserName(),pResource->GetPassword(),0,pResource->GetPortNumber(), NullS,0))
- {
- PostMessage(WM_COMMAND,IDM_TOOLS_SERVER_PROPERTIES);
- MainFrame->StatusMsg ( "Error: Connecting to server %s... (%s)"
- , (LPCTSTR) pResource->GetDisplayName()
- , mysql_error(&mysql)
- );
- return;
- }
- if (!(result=mysql_list_dbs(&mysql,0)))
- {
- }
- ProcessResultSet ( hItem, result, pResource );
- mysql_free_result(result);
- mysql_close(&mysql);
- MainFrame->StatusMsg ( " " );
- break;
- }
- case CResource::eDatabase:
- {
- CResourceServer* pServer = GetServerResource(hItem);
- if (!pServer) return;
- MainFrame->StatusMsg ( "Connecting to server %s on host %s..."
- , (LPCTSTR) pServer->GetDisplayName()
- , (LPCTSTR) pServer->GetHostName()
- );
- mysql_init(&mysql);
- if (!mysql_real_connect(&mysql,pServer->GetHostName(), pServer->GetUserName(),pServer->GetPassword(),0,pServer->GetPortNumber(), NullS,0))
- {
- PostMessage(WM_COMMAND,IDM_TOOLS_SERVER_PROPERTIES);
- MainFrame->StatusMsg ( "Error: Connecting to server %s... (%s)"
- , (LPCTSTR) pServer->GetDisplayName()
- , mysql_error(&mysql)
- );
- return;
- }
- CResourceDatabase* pRes = (CResourceDatabase*) pResource;
- CString strDB = pResource->GetDisplayName();
- strDB.TrimRight();
- if (mysql_select_db(&mysql,strDB))
- {
- MainFrame->StatusMsg ( "Error: Selecting database %s... (%s)"
- , (LPCTSTR) strDB
- , mysql_error(&mysql)
- );
- return;
- }
- if (!(result=mysql_list_tables(&mysql,0)))
- {
- }
- ProcessResultSet ( hItem, result, pRes );
- mysql_free_result(result);
- mysql_close(&mysql);
- MainFrame->StatusMsg ( " " );
- break;
- }
- case CResource::eTable:
- {
- CResourceServer* pServer = GetServerResource(hItem);
- if (!pServer) return;
- MainFrame->StatusMsg ( "Connecting to server %s on host %s..."
- , (LPCTSTR) pServer->GetDisplayName()
- , (LPCTSTR) pServer->GetHostName()
- );
- mysql_init(&mysql);
- if (!mysql_real_connect(&mysql,pServer->GetHostName(), pServer->GetUserName(),pServer->GetPassword(),0,pServer->GetPortNumber(), NullS,0))
- {
- PostMessage(WM_COMMAND,IDM_TOOLS_SERVER_PROPERTIES);
- MainFrame->StatusMsg ( "Error: Connecting to server %s... (%s)"
- , (LPCTSTR) pServer->GetDisplayName()
- , mysql_error(&mysql)
- );
- return;
- }
- HTREEITEM hParent = m_pTree->GetParentItem(hItem);
- memset( &item, 0, sizeof(TV_ITEM) );
- item.hItem = hParent;
- item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM ;
- m_pTree->GetItem( &item );
- if ( item.lParam )
- {
- CResourceDatabase* pResDatabase = (CResourceDatabase*) item.lParam;
- CResourceTable* pRes = (CResourceTable*) pResource;
- CString strDB = pResDatabase->GetDisplayName();
- CString strTable = pResource->GetDisplayName();
- strDB.TrimRight();
- strTable.TrimRight();
- if (mysql_select_db(&mysql,strDB))
- {
- return;
- }
- CString str; str.Format("show fields from %s",(LPCTSTR)strTable);
- if ( mysql_query(&mysql,str)==0 )
- {
- MYSQL_RES *result;
- if ((result=mysql_store_result(&mysql)))
- {
- ProcessResultSet ( hItem, result, pRes );
- mysql_free_result(result);
- }
- }
- }
- mysql_close(&mysql);
- break;
- }
- }
-
-// InsertNetResources( (LPNETRESOURCE)pTvItem->lParam,
-// &m_TreeCtrl,
-// hItem,
-// &pTvItem->cChildren );
-// pTvItem->mask = TVIF_CHILDREN;
-// m_TreeCtrl.SetItem( pTvItem );
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::OnRefresh()
-{
- HTREEITEM hItem = NULL;
- CResource* pResource = GetSelectedResource(&hItem);
- if (pResource&&hItem)
- {
- switch (pResource->GetType())
- {
- case CResource::eTable:
- {
-
- TV_ITEM item;
- MYSQL mysql;
-// MYSQL_RES *result;
-
- HTREEITEM hParent = m_pTree->GetParentItem(hItem);
-
- HTREEITEM hChild = m_pTree->GetChildItem(hItem);
- while (hChild)
- {
- HTREEITEM h = m_pTree->GetNextSiblingItem(hChild);
- BOOL b = m_pTree->DeleteItem(hChild);
- hChild = h;
- }
- mysql_init(&mysql);
- if (!mysql_real_connect(&mysql,pResource->GetHostName(), pResource->GetUserName(),pResource->GetPassword(),0,pResource->GetPortNumber(), NullS,0))
- {
- return;
- }
- memset( &item, 0, sizeof(TV_ITEM) );
- item.hItem = hParent;
- item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM ;
- m_pTree->GetItem( &item );
- if ( item.lParam )
- {
- CResourceDatabase* pResDatabase = (CResourceDatabase*) item.lParam;
- CResourceTable* pRes = (CResourceTable*) pResource;
- CString strDB = pResDatabase->GetDisplayName();
- CString strTable = pResource->GetDisplayName();
- strDB.TrimRight();
- strTable.TrimRight();
- if (mysql_select_db(&mysql,strDB))
- {
- return;
- }
- CString str; str.Format("show fields from %s",(LPCTSTR)strTable);
- if ( mysql_query(&mysql,str)==0 )
- {
- MYSQL_RES *result;
- if ((result=mysql_store_result(&mysql)))
- {
- ProcessResultSet ( hItem, result, pRes );
- mysql_free_result(result);
- }
- }
- }
- mysql_close(&mysql);
- break;
- }
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::OnRegisterServer()
-{
- CRegisterServer dlg;
- if (dlg.DoModal()!=IDOK) return;
- AddResource (
- TVI_ROOT,
- new CResourceServer ( dlg.m_strServer, dlg.m_strHost, dlg.m_strUser, dlg.m_strPassword, dlg.m_strPort )
- );
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::OnServerProperties()
-{
- HTREEITEM hItem;
- CResource* pRes = GetSelectedResource(&hItem);
- if (!pRes) return;
- if (pRes->GetType()!=CResource::eServer) return;
- CResourceServer* pResource = (CResourceServer*)pRes;
- CRegisterServer dlg;
- dlg.m_strHost = pResource->GetHostName();
- dlg.m_strUser = pResource->GetUserName();
- dlg.m_strPassword = pResource->GetPassword();
- dlg.m_strPort = pResource->GetPortName();
- if (dlg.DoModal()!=IDOK) return;
- pResource->m_strHost = dlg.m_strHost ;
- pResource->m_strUser = dlg.m_strUser ;
- pResource->m_strPassword = dlg.m_strPassword;
- pResource->m_strPort = dlg.m_strPort ;
- TV_ITEM item;
- memset( &item, 0, sizeof(TV_ITEM) );
- item.hItem = hItem;
- item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM ;
- m_pTree->GetItem( &item );
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CMySqlManagerView::OnSqlToolQuery()
-{
-
- HTREEITEM hItem;
-
- CResource* pResource = GetSelectedResource(&hItem);
-
- if (!pResource) return;
-
- CResourceServer* pServer = GetServerResource(hItem);
- if (!pServer) return; /* Avoid bug when selecting field */
-
- m_pTool = new CToolSql ( AfxGetMainWnd(), pServer, pResource );
-
- if ( ! m_pTool->Create(IDD_TOOL_SQL,this) )
- {
- delete m_pTool;
- m_pTool = 0;
- PostMessage(WM_COMMAND,IDM_TOOLS_SERVER_PROPERTIES);
- }
- else
- {
- m_pTool->ShowWindow(SW_SHOW);
- }
-
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-BOOL CMySqlManagerView::PreTranslateMessage(MSG* pMsg)
-{
- if (m_pTool && m_pTool->PreTranslateMessage(pMsg))
- return TRUE;
- return CTreeView::PreTranslateMessage(pMsg);
-}
-
-void CMySqlManagerView::OnRclick(NMHDR* pNMHDR, LRESULT* pResult)
-{
-
- POINT pt;
-
- GetCursorPos ( & pt );
-
- CMenu menu;
-
- menu.CreatePopupMenu ();
-
- menu.AppendMenu ( MF_ENABLED , IDM_SQL_TOOL_QUERY, "SQL Query" );
- menu.AppendMenu ( MF_ENABLED , IDM_REFRESH, "Refresh active item(s)" );
- menu.AppendMenu ( MF_ENABLED , IDM_TOOLS_REGISTER_SERVER, "Register server" );
- menu.AppendMenu ( MF_ENABLED , IDM_TOOLS_SERVER_PROPERTIES, "Properties" );
-
- menu.TrackPopupMenu ( TPM_LEFTALIGN | TPM_RIGHTBUTTON , pt.x, pt.y, CWnd::GetParent(), NULL );
-
- *pResult = 0;
-
-}
diff --git a/VC++Files/mysqlmanager/mysqlmanagerview.h b/VC++Files/mysqlmanager/mysqlmanagerview.h
deleted file mode 100644
index 97f5a2596d1..00000000000
--- a/VC++Files/mysqlmanager/mysqlmanagerview.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// MySqlManagerView.h : interface of the CMySqlManagerView class
-//
-/////////////////////////////////////////////////////////////////////////////
-
-#if !defined(AFX_MYSQLMANAGERVIEW_H__826CB2F4_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_MYSQLMANAGERVIEW_H__826CB2F4_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-#include <afxcview.h>
-#include "cresource.h"
-
-class CToolSql;
-
-class CMySqlManagerView : public CTreeView
-{
-protected: // create from serialization only
- CMySqlManagerView();
- DECLARE_DYNCREATE(CMySqlManagerView)
-
-// Attributes
-public:
- CMySqlManagerDoc* GetDocument();
-
-// Operations
-public:
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CMySqlManagerView)
- public:
- virtual void OnDraw(CDC* pDC); // overridden to draw this view
- virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
- virtual void OnInitialUpdate();
- virtual BOOL PreTranslateMessage(MSG* pMsg);
- protected:
- virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
- virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
- virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
- //}}AFX_VIRTUAL
-
-// Implementation
-
- CResource* GetSelectedResource(HTREEITEM* phItemRet=NULL);
- CResourceServer* GetServerResource(HTREEITEM hItem);
-
- HTREEITEM AddResource ( HTREEITEM hParent, CResource* pRes, HTREEITEM hLastItem = TVI_FIRST ) ;
- void ProcessResultSet ( HTREEITEM hItem, LPVOID result, CResource* pResource );
-
-public:
- virtual ~CMySqlManagerView();
-#ifdef _DEBUG
- virtual void AssertValid() const;
- virtual void Dump(CDumpContext& dc) const;
-#endif
-
-protected:
-
- CTreeCtrl* m_pTree;
- CImageList* m_pImages;
- CBitmap* m_pbmBmp;
- CToolSql* m_pTool;
-
-// Generated message map functions
-protected:
- //{{AFX_MSG(CMySqlManagerView)
- afx_msg void OnDblclk(NMHDR* pNMHDR, LRESULT* pResult);
- afx_msg void OnSqlToolQuery();
- afx_msg void OnRefresh();
- afx_msg void OnRegisterServer();
- afx_msg void OnServerProperties();
- afx_msg void OnRclick(NMHDR* pNMHDR, LRESULT* pResult);
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-#ifndef _DEBUG // debug version in MySqlManagerView.cpp
-inline CMySqlManagerDoc* CMySqlManagerView::GetDocument()
- { return (CMySqlManagerDoc*)m_pDocument; }
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_MYSQLMANAGERVIEW_H__826CB2F4_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/registerserver.cpp b/VC++Files/mysqlmanager/registerserver.cpp
deleted file mode 100644
index a0e9dcca3df..00000000000
--- a/VC++Files/mysqlmanager/registerserver.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-// RegisterServer.cpp : implementation file
-//
-
-#include "stdafx.h"
-#include "mysqlmanager.h"
-#include "RegisterServer.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-// CRegisterServer dialog
-
-
-CRegisterServer::CRegisterServer(CWnd* pParent /*=NULL*/)
- : CDialog(CRegisterServer::IDD, pParent)
- , m_strServer("servername")
- , m_strHost("localhost")
- , m_strUser("root")
- , m_strPassword("")
-{
- //{{AFX_DATA_INIT(CRegisterServer)
- m_strPort = _T("3306");
- //}}AFX_DATA_INIT
-}
-
-
-void CRegisterServer::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CRegisterServer)
- DDX_CBString(pDX, ID_SERVER_CB, m_strServer);
- DDX_CBString(pDX, ID_HOST_CB, m_strHost);
- DDX_Text(pDX, ID_USER, m_strUser);
- DDX_Text(pDX, ID_PASSWORD, m_strPassword);
- DDX_CBString(pDX, ID_PORT_CB, m_strPort);
- //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(CRegisterServer, CDialog)
- //{{AFX_MSG_MAP(CRegisterServer)
- // NOTE: the ClassWizard will add message map macros here
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-// CRegisterServer message handlers
diff --git a/VC++Files/mysqlmanager/registerserver.h b/VC++Files/mysqlmanager/registerserver.h
deleted file mode 100644
index f4ac2356b2c..00000000000
--- a/VC++Files/mysqlmanager/registerserver.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#if !defined(AFX_REGISTERSERVER_H__826CB2FF_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_REGISTERSERVER_H__826CB2FF_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-// RegisterServer.h : header file
-//
-
-/////////////////////////////////////////////////////////////////////////////
-// CRegisterServer dialog
-
-class CRegisterServer : public CDialog
-{
-// Construction
-public:
- CRegisterServer(CWnd* pParent = NULL); // standard constructor
-
-// Dialog Data
- //{{AFX_DATA(CRegisterServer)
- enum { IDD = IDD_REGISTER_SERVER };
- CString m_strServer;
- CString m_strHost;
- CString m_strUser;
- CString m_strPassword;
- CString m_strPort;
- //}}AFX_DATA
-
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CRegisterServer)
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
-// Implementation
-protected:
-
- // Generated message map functions
- //{{AFX_MSG(CRegisterServer)
- // NOTE: the ClassWizard will add member functions here
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_REGISTERSERVER_H__826CB2FF_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/resource.h b/VC++Files/mysqlmanager/resource.h
deleted file mode 100644
index def26ce6808..00000000000
--- a/VC++Files/mysqlmanager/resource.h
+++ /dev/null
@@ -1,55 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Developer Studio generated include file.
-// Used by MySqlManager.rc
-//
-#define IDC_START_PB 3
-#define IDC_STOP_PB 4
-#define ID_SERVERS_PB 7
-#define IDD_ABOUTBOX 100
-#define IDM_QUERY_EXEC 101
-#define IDM_QUERY_DATABASES 102
-#define IDM_REFRESH 103
-#define IDD_REGISTER_SERVER 114
-#define IDR_MAINFRAME 128
-#define IDR_MYSQLMTYPE 129
-#define IDD_TOOL_SQL 132
-#define IDB_BITMAP1 133
-#define IDD_TOOL_SQL_QUERY 134
-#define IDD_TOOL_SQL_RESULTS 135
-#define IDD_TOOL_SQL_STATUS 136
-#define IDC_TAB1 1000
-#define IDC_EDIT 1001
-#define IDC_QUERY_PB 1002
-#define IDC_FONT_PB 1003
-#define IDS_QUERY_EXEC 1003
-#define ID_SERVER_CB 1003
-#define ID_USER 1004
-#define IDC_SERVER_CB 1004
-#define IDC_DATABASES_PB 1005
-#define ID_PASSWORD 1005
-#define ID_HOST_CB 1006
-#define IDC_TIMER_SECS 1006
-#define ID_PORT_CB 1007
-#define IDC_CLEAR 1007
-#define ID_GROUPS_PB 1012
-#define ID_REMOVE_PB 1017
-#define ID_DISPLAY_SERVER_STATUS_CK 1057
-#define ID_USE_STANDARD_CK 1058
-#define ID_USE_TRUSTED_CK 1059
-#define IDM_SQL_TOOL_QUERY 32771
-#define IDM_TOOLS_REGISTER_SERVER 32772
-#define IDM_TOOLS_SERVER_PROPERTIES 32773
-#define IDS_QUERY_DATABASES 57346
-#define IDS_REFRESH 57347
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_3D_CONTROLS 1
-#define _APS_NEXT_RESOURCE_VALUE 136
-#define _APS_NEXT_COMMAND_VALUE 32775
-#define _APS_NEXT_CONTROL_VALUE 1008
-#define _APS_NEXT_SYMED_VALUE 104
-#endif
-#endif
diff --git a/VC++Files/mysqlmanager/stdafx.cpp b/VC++Files/mysqlmanager/stdafx.cpp
deleted file mode 100644
index 3e0251dff43..00000000000
--- a/VC++Files/mysqlmanager/stdafx.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// stdafx.cpp : source file that includes just the standard includes
-// MySqlManager.pch will be the pre-compiled header
-// stdafx.obj will contain the pre-compiled type information
-
-#include "stdafx.h"
diff --git a/VC++Files/mysqlmanager/stdafx.h b/VC++Files/mysqlmanager/stdafx.h
deleted file mode 100644
index 8cd7dfd04f3..00000000000
--- a/VC++Files/mysqlmanager/stdafx.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// stdafx.h : include file for standard system include files,
-// or project specific include files that are used frequently, but
-// are changed infrequently
-//
-
-#if !defined(AFX_STDAFX_H__826CB2EC_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_STDAFX_H__826CB2EC_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
-
-#include <afxwin.h> // MFC core and standard components
-#include <afxext.h> // MFC extensions
-#include <afxdisp.h> // MFC OLE automation classes
-#ifndef _AFX_NO_AFXCMN_SUPPORT
-#include <afxcmn.h> // MFC support for Windows Common Controls
-#endif // _AFX_NO_AFXCMN_SUPPORT
-
-#include <afxsock.h>
-#include "mysql.h"
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_STDAFX_H__826CB2EC_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/toolsql.cpp b/VC++Files/mysqlmanager/toolsql.cpp
deleted file mode 100644
index 1773a3a6dc7..00000000000
--- a/VC++Files/mysqlmanager/toolsql.cpp
+++ /dev/null
@@ -1,687 +0,0 @@
-// ToolSql.cpp : implementation file
-//
-
-#include "stdafx.h"
-#include "MySqlManager.h"
-#include "ToolSql.h"
-
-#define WINDOW_COORDS 0
-#define CLIENT_COORDS 1
-
-#define MY_TIMER_ID 0x1234
-
-#ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-
-CToolSql::CToolSql(CWnd* pParent,CResource* pServer,CResource* pResource)
-: CDialog(CToolSql::IDD, pParent)
-, m_pQuery(0)
-, m_pResults(0)
-, m_pStatus(0)
-, m_pServer(pServer)
-, m_pResource(pResource)
-, m_ui_timer(0)
-{
- //{{AFX_DATA_INIT(CToolSql)
- m_nIntervalTimerSeconds = 10;
- m_bClear = FALSE;
- //}}AFX_DATA_INIT
- memset ( & m_lf, 0,sizeof(m_lf) );
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-CToolSql::~CToolSql()
-{
-
- if (m_ui_timer)
- {
- KillTimer(MY_TIMER_ID);
- }
-
- if (m_pdb)
- {
- mysql_close(m_pdb);
- }
- if (m_pQuery)
- {
- m_pQuery->DestroyWindow();
- delete m_pQuery;
- }
- if (m_pResults)
- {
- m_pResults->DestroyWindow();
- delete m_pResults;
- }
- if (m_pStatus)
- {
- m_pStatus->DestroyWindow();
- delete m_pStatus;
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CToolSql)
- DDX_Control(pDX, IDC_STOP_PB, m_ctl_Stop);
- DDX_Control(pDX, IDC_START_PB, m_ctl_Start);
- DDX_Control(pDX, IDC_SERVER_CB, m_ctl_Server);
- DDX_Control(pDX, IDC_TAB1, m_tabs);
- DDX_Text(pDX, IDC_TIMER_SECS, m_nIntervalTimerSeconds);
- DDV_MinMaxInt(pDX, m_nIntervalTimerSeconds, 1, 120);
- DDX_Check(pDX, IDC_CLEAR, m_bClear);
- //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(CToolSql, CDialog)
-//{{AFX_MSG_MAP(CToolSql)
- ON_BN_CLICKED(IDC_QUERY_PB, OnQueryPb)
- ON_BN_CLICKED(IDC_DATABASES_PB, OnQueryDatabases)
- ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnSelchangeTab1)
- ON_BN_CLICKED(IDC_FONT_PB, OnFontPb)
- ON_WM_SIZE()
- ON_BN_CLICKED(IDC_START_PB, OnStartPb)
- ON_BN_CLICKED(IDC_STOP_PB, OnStopPb)
- ON_WM_TIMER()
- ON_WM_DESTROY()
- ON_BN_CLICKED(IDC_CLEAR, OnClear)
- ON_COMMAND(IDM_QUERY_EXEC, OnQueryPb)
- ON_COMMAND(IDM_QUERY_DATABASES, OnQueryDatabases)
- ON_EN_CHANGE(IDC_TIMER_SECS, OnChangeTimerSecs)
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-
-BOOL CToolSql::OnInitDialog()
-{
-
- CDialog::OnInitDialog();
-
- m_ctl_Start . EnableWindow(TRUE);
- m_ctl_Stop . EnableWindow(FALSE);
-
- CString strTitle;
-
- strTitle.Format ("mySql Query to %s on %s",m_pServer->GetDisplayName(),m_pServer->GetHostName());
-
- m_ctl_Server.AddString ( m_pServer->GetDisplayName() );
- m_ctl_Server.SetCurSel (0);
-
- SetWindowText(strTitle);
-
- CWaitCursor x;
-
- m_btn_QueryExec.AutoLoad ( IDC_QUERY_PB, this );
- m_btn_QueryDatabases.AutoLoad ( IDC_DATABASES_PB, this );
- m_btn_Font.AutoLoad ( IDC_FONT_PB, this );
-
- m_tabs.GetWindowRect ( m_rectTab[WINDOW_COORDS] );
- GetWindowRect ( m_rectDlg[WINDOW_COORDS] );
-
- m_tabs.GetClientRect ( m_rectTab[CLIENT_COORDS] );
- GetClientRect ( m_rectDlg[CLIENT_COORDS] );
-
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != NULL)
- {
- CString strText;
- strText.LoadString(IDS_QUERY_EXEC);
- if (!strText.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_QUERY_EXEC, strText);
- }
- strText.LoadString(IDS_QUERY_DATABASES);
- if (!strText.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_STRING, IDM_QUERY_DATABASES, strText);
- }
- }
-
-
- m_pdb = new MYSQL;
-
- CString strQuery ( "Query" );
- CString strResults ( "Results" );
- CString strStatus ( "Status" );
-
- TC_ITEM tc1 = { TCIF_TEXT, 0,0, (LPSTR)(LPCTSTR)strQuery, strQuery.GetLength(), 0,0};
- TC_ITEM tc2 = { TCIF_TEXT, 0,0, (LPSTR)(LPCTSTR)strResults, strResults.GetLength(), 0,0};
- TC_ITEM tc3 = { TCIF_TEXT, 0,0, (LPSTR)(LPCTSTR)strStatus, strStatus.GetLength(), 0,0};
-
- m_tabs.InsertItem ( 0,&tc1 );
- m_tabs.InsertItem ( 1,&tc2 );
- m_tabs.InsertItem ( 2,&tc3 );
-
- m_pQuery = new CToolSqlQuery ( NULL );
- m_pResults = new CToolSqlResults ( NULL );
- m_pStatus = new CToolSqlStatus ( NULL );
-
- try
- {
-
-// OpenDatabase();
-//
-// m_pSelection->SetDatabase ( & m_db );
-// m_pScript->SetDatabase ( & m_db );
-// m_pLog->SetDatabase ( & m_db );
-
- m_pQuery -> Create ( (LPCTSTR)IDD_TOOL_SQL_QUERY, &m_tabs );
- m_pResults -> Create ( (LPCTSTR)IDD_TOOL_SQL_RESULTS, &m_tabs );
- m_pStatus -> Create ( (LPCTSTR)IDD_TOOL_SQL_STATUS, &m_tabs );
-
- ActivateTab ( 0 );
-
- m_pQuery -> SetWindowPos(NULL,20,24,0,0,SWP_NOZORDER|SWP_NOSIZE);
- m_pResults -> SetWindowPos(NULL,20,24,0,0,SWP_NOZORDER|SWP_NOSIZE);
- m_pStatus -> SetWindowPos(NULL,20,24,0,0,SWP_NOZORDER|SWP_NOSIZE);
-
- DoOnSize( SIZE_RESTORED, m_rectDlg[CLIENT_COORDS].Width(), m_rectDlg[CLIENT_COORDS].Height() );
-
- }
- catch (...)
- {
- }
-
- mysql_init(m_pdb);
- if (!mysql_real_connect(m_pdb,m_pServer->GetHostName(), m_pServer->GetUserName(),m_pServer->GetPassword(),0,m_pServer->GetPortNumber(), NullS,0))
- {
-// my_printf_error(0,"connect to server at '%s' failed; error: '%s'",
-// MYF(ME_BELL), pResource->GetHostName(), mysql_error(&mysql));
- CString strText;
- strText.Format ( "connect to server at '%s' failed; error: '%s'", m_pServer->GetHostName(), mysql_error(m_pdb));
- AfxMessageBox(strText);
- EndDialog(IDCANCEL);
- return FALSE;
- }
-
- if ( m_pResource && m_pResource->GetType() == CResource::eDatabase )
- {
- CString strDB = m_pResource->GetDisplayName();
- strDB.TrimRight();
- if (mysql_select_db(m_pdb,strDB))
- {
- }
- }
-
- return FALSE; // return TRUE unless you set the focus to a control
- // EXCEPTION: OCX Property Pages should return FALSE
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::ActivateTab ( int tab )
-
-{
- switch (tab)
- {
- case 0: ;
- m_pResults-> ShowWindow(SW_HIDE);
- m_pStatus-> ShowWindow(SW_HIDE);
- m_pQuery-> ShowWindow(SW_SHOW);
- m_pQuery->m_ctl_edit.SetFocus();
- break;
- case 1: ;
- m_pQuery-> ShowWindow(SW_HIDE);
- m_pStatus-> ShowWindow(SW_HIDE);
- m_pResults-> ShowWindow(SW_SHOW);
- m_pResults->m_ctl_edit.SetFocus();
- break;
- case 2: ;
- m_pResults-> ShowWindow(SW_HIDE);
- m_pQuery-> ShowWindow(SW_HIDE);
- m_pStatus-> ShowWindow(SW_SHOW);
- m_pStatus->m_ctl_edit.SetFocus();
- break;
- default:
- break;
- }
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CalculateFontSize ( CEdit& ed, CSize& sizeRet )
-
-{
-
- CDC* pdc = ed.GetDC();
-
- int nAveWidth , nAveHeight;
- int i ;
-
- CSize size ;
-
- static BOOL bFirstTime = TRUE;
- static char rgchAlphabet [54] ;
-
- if ( bFirstTime )
- {
- bFirstTime = false;
- for ( i = 0 ; i <= 25 ; i++)
- {
- rgchAlphabet[i] = (char)(i+(int)'a') ;
- rgchAlphabet[i+26] = (char)(i+(int)'A') ;
- }
- rgchAlphabet[52] = 0x20;
- rgchAlphabet[53] = 0x20;
- }
-
- CFont* pf = ed.GetFont();
- LOGFONT lf;
- pf->GetLogFont(&lf);
- pdc->SelectObject (pf);
- GetTextExtentPoint32 ( pdc->m_hDC, (LPSTR) rgchAlphabet, 54, & size ) ;
-
- nAveWidth = size.cx / 54 ;
-
- if ( size.cx % 54 )
- {
- nAveWidth++;
- }
-
- nAveHeight = size.cy; //6 * size.cy / 4;
-
- sizeRet.cx = nAveWidth;
- sizeRet.cy = nAveHeight; // tm.tmHeight;
-
- ed.ReleaseDC(pdc);
-
-}
-
-///////////////////////////////////////////////////////////////////////////////
-int ProcessYieldMessage ()
-{
-
- CWinApp* pApp = AfxGetApp();
-
- if ( pApp )
- {
- MSG msgx;
- while (::PeekMessage(&msgx, NULL, NULL, NULL, PM_NOREMOVE))
- try
- {
- if (!pApp->PumpMessage())
- {
-// ExitProcess(1);
- }
- }
- catch (...)
- {
- }
- }
-
- return 0;
-
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-void print_table_data(MYSQL_RES *result,CString& str,CEdit& ed,LOGFONT& lf)
-{
- MYSQL_ROW cur;
- uint length;
- MYSQL_FIELD* field;
- bool* num_flag;
- my_ulonglong nRows = mysql_num_rows(result);
- uint nFields = mysql_num_fields(result);
- int* rgi = new int [nFields];
- memset ( rgi, 0, nFields*sizeof(int) );
- num_flag=(bool*) my_alloca(sizeof(bool)*nFields);
-
- ed.SetLimitText(65535*16);
-
- CSize sizeFont;
- CalculateFontSize ( ed, sizeFont );
- uint index = 0;
- rgi[index++]=0;
- CString separator("");
-
- mysql_field_seek(result,0);
-
- for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
- {
- uint length= (uint) strlen(field->name);
- length=max(length,field->max_length);
- if (length < 4 && !IS_NOT_NULL(field->flags))
- length=4; // Room for "NULL"
- field->max_length=length+1;
- int n=length+2;
- for (uint i=lstrlen(field->name); i-- > 0 ; ) separator+="-";
- if ( index!= nFields )
- {
- int o = rgi[index-1];
- rgi[index++]=o+((n+1)*sizeFont.cx)/2;
- }
- separator+='\t';
- str += field->name;
- str += "\t";
- num_flag[off]= IS_NUM(field->type);
- }
- separator += "\r\n";
- str += "\r\n";
- str += separator;
- ed.SetSel(-1,-1);
- ed.ReplaceSel(str);
-
- if ( 1 || nRows > 100 )
- {
- while ((cur = mysql_fetch_row(result)))
- {
- ProcessYieldMessage ();
- mysql_field_seek(result,0);
- str.Empty();
- ed.SetSel(-1,-1);
- for (uint off=0 ; off < mysql_num_fields(result); off++)
- {
- field = mysql_fetch_field(result);
- length=field->max_length;
- CString strText;
- strText.Format ("%s", cur[off] ? (char*) cur[off] : "NULL");
- str += strText;
- str += "\t";
- }
- str += "\r\n";
- ed.SetSel(-1,-1);
- ed.ReplaceSel(str);
- }
- }
- else
- {
- while ((cur = mysql_fetch_row(result)))
- {
- mysql_field_seek(result,0);
- for (uint off=0 ; off < mysql_num_fields(result); off++)
- {
- field = mysql_fetch_field(result);
- length=field->max_length;
- CString strText;
- strText.Format ("%s", cur[off] ? (char*) cur[off] : "NULL");
- str += strText;
- str += "\t";
- }
- str += "\r\n";
- }
- }
- my_afree((gptr) num_flag);
- str += "\r\n";
- ed.SetTabStops(nFields,rgi);
- delete [] rgi;
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnQueryPb()
-{
-
- CWaitCursor x;
-// mysql_select_db(m_pdb,"mysql");
-
- if ( m_pResource && m_pResource->GetType() == CResource::eDatabase )
- {
- CString strDB = m_pResource->GetDisplayName();
- strDB.TrimRight();
- if (mysql_select_db(m_pdb,strDB))
- {
- }
- }
-
- m_pQuery->UpdateData();
- m_pResults->m_edit.Empty();
- CString str = m_pQuery->m_edit;
- if ( mysql_real_query(m_pdb,str,str.GetLength())==0 )
- {
- MYSQL_RES *result;
- if ((result=mysql_store_result(m_pdb)))
- {
- my_ulonglong nRows = mysql_num_rows(result);
- m_pResults->UpdateData(FALSE);
- m_tabs.SetCurSel(1);
- ActivateTab ( 1 );
- print_table_data(result,m_pResults->m_edit,m_pResults->m_ctl_edit,m_lf);
-// m_pResults->UpdateData(FALSE);
- m_pResults->m_ctl_edit.SetSel(-1,-1);
- CString strText;
- strText.Format ( "\r\n(%d row(s) affected)\r\n", nRows );
- m_pResults->m_ctl_edit.ReplaceSel(strText);
- mysql_free_result(result);
- }
- else
- {
- m_pResults->m_edit = mysql_error(m_pdb);
- m_pResults->UpdateData(FALSE);
- }
- }
- else
- {
- m_pResults->m_edit = mysql_error(m_pdb);
- m_pResults->UpdateData(FALSE);
- }
-
- m_tabs.SetCurSel(1);
- ActivateTab ( 1 );
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnQueryDatabases()
-{
- CWaitCursor x;
- MYSQL_RES *result;
- m_pResults->m_edit.Empty();
- if ((result=mysql_list_dbs(m_pdb,0)))
- {
- my_ulonglong nRows = mysql_num_rows(result);
- print_table_data(result,m_pResults->m_edit,m_pResults->m_ctl_edit,m_lf);
- //m_pResults->UpdateData(FALSE);
- mysql_free_result(result);
- }
- else
- {
- m_pResults->m_edit = mysql_error(m_pdb);
- m_pResults->UpdateData(FALSE);
- }
-
- m_tabs.SetCurSel(1);
- ActivateTab ( 1 );
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
-{
- ActivateTab ( m_tabs.GetCurSel() );
- *pResult = 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnFontPb()
-{
-
- CFontDialog FontDlg ( & m_lf );
-
- if ( FontDlg.DoModal ( ) == IDOK )
- {
- if (m_font.GetSafeHandle())
- m_font.DeleteObject();
- m_lf = *FontDlg.m_cf.lpLogFont;
- m_font.CreateFontIndirect(FontDlg.m_cf.lpLogFont);
- m_pQuery->SetFont(&m_font);
- m_pResults->SetFont(&m_font);
- m_pStatus->SetFont(&m_font);
- }
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::DoOnSize(UINT nType, int cx, int cy)
-{
-
- int nx = cx - ( m_rectDlg[CLIENT_COORDS].Width ( ) - m_rectTab[CLIENT_COORDS].Width ( ) );
- int ny = cy - ( m_rectDlg[CLIENT_COORDS].Height ( ) - m_rectTab[CLIENT_COORDS].Height ( ) );
-
- if (IsWindow(m_tabs.GetSafeHwnd()))
- {
- m_tabs.SetWindowPos ( NULL
- , 0
- , 0
- , nx
- , ny
- , SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW );
-
- if (m_pResults&&IsWindow(m_pResults->GetSafeHwnd()))
- m_pResults -> SetWindowPos(NULL,20,24,nx-40,ny-48,SWP_NOZORDER | SWP_NOMOVE );
- if (m_pQuery&&IsWindow(m_pQuery->GetSafeHwnd()))
- m_pQuery -> SetWindowPos(NULL,20,24,nx-40,ny-48,SWP_NOZORDER | SWP_NOMOVE );
- if (m_pStatus&&IsWindow(m_pStatus->GetSafeHwnd()))
- m_pStatus -> SetWindowPos(NULL,20,24,nx-40,ny-48,SWP_NOZORDER | SWP_NOMOVE );
-// switch ( m_tabs.GetCurSel() )
-// {
-// case 0:
-// {
-// if (m_pResults&&IsWindow(m_pResults->GetSafeHwnd()))
-// m_pResults -> SetWindowPos(NULL,20,24,nx-40,ny-48,SWP_NOZORDER | SWP_NOMOVE | SWP_HIDEWINDOW );
-// if (m_pQuery&&IsWindow(m_pQuery->GetSafeHwnd()))
-// m_pQuery -> SetWindowPos(NULL,20,24,nx-40,ny-48,SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW );
-// break;
-// }
-// case 1:
-// {
-// if (m_pQuery&&IsWindow(m_pQuery->GetSafeHwnd()))
-// m_pQuery -> SetWindowPos(NULL,20,24,nx-40,ny-48,SWP_NOZORDER | SWP_NOMOVE | SWP_HIDEWINDOW );
-// if (m_pResults&&IsWindow(m_pResults->GetSafeHwnd()))
-// m_pResults -> SetWindowPos(NULL,20,24,nx-40,ny-48,SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW );
-// break;
-// }
-// }
- }
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnSize(UINT nType, int cx, int cy)
-{
-
- CDialog::OnSize(nType, cx, cy);
-
- DoOnSize ( nType, cx, cy );
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnOK()
-{
- CDialog::OnOK();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnCancel()
-{
- CDialog::OnCancel();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-BOOL CToolSql::PreTranslateMessage(MSG* pMsg)
-{
- return CDialog::PreTranslateMessage(pMsg);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::DoProcessListQuery()
-{
-
- MYSQL_RES *result;
- if (result=mysql_list_processes(m_pdb))
- {
- if (m_bClear)
- {
- m_pStatus->m_edit.Empty();
- m_pStatus->UpdateData(FALSE);
- }
- print_table_data(result,m_pStatus->m_edit,m_pStatus->m_ctl_edit,m_lf);
- mysql_free_result(result);
- }
- else
- {
-// my_printf_error(0,"process list failed; error: '%s'",MYF(ME_BELL),mysql_error(mysql));
- }
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnStartPb()
-{
- UpdateData();
- if (m_ui_timer) return;
- if (m_nIntervalTimerSeconds<1) return;
- ActivateTab ( 2 );
- m_ui_timer = SetTimer( MY_TIMER_ID, m_nIntervalTimerSeconds*1000, NULL );
- m_ctl_Start . EnableWindow(FALSE);
- m_ctl_Stop . EnableWindow(TRUE);
- DoProcessListQuery();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnStopPb()
-{
- UpdateData();
- if (m_ui_timer)
- {
- KillTimer(MY_TIMER_ID);
- m_ui_timer = 0;
- }
- m_ctl_Start . EnableWindow(TRUE);
- m_ctl_Stop . EnableWindow(FALSE);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSql::OnTimer(UINT nIDEvent)
-{
- DoProcessListQuery();
- CDialog::OnTimer(nIDEvent);
-}
-
-void CToolSql::OnDestroy()
-{
- if (m_ui_timer)
- {
- KillTimer(MY_TIMER_ID);
- m_ui_timer = 0;
- }
- CDialog::OnDestroy();
-}
-
-void CToolSql::OnClear()
-{
- UpdateData();
-}
-
-void CToolSql::OnChangeTimerSecs()
-{
- UpdateData();
-}
diff --git a/VC++Files/mysqlmanager/toolsql.h b/VC++Files/mysqlmanager/toolsql.h
deleted file mode 100644
index 7d608f46cd2..00000000000
--- a/VC++Files/mysqlmanager/toolsql.h
+++ /dev/null
@@ -1,102 +0,0 @@
-#if !defined(AFX_ToolSql_H__826CB2FC_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_ToolSql_H__826CB2FC_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-#include "ToolSqlQuery.h"
-#include "ToolSqlResults.h"
-#include "ToolSqlStatus.h"
-#include "cresource.h"
-#include <my_global.h>
-#include "my_sys.h"
-#include "mysql.h"
-
-
-/////////////////////////////////////////////////////////////////////////////
-// CToolSql dialog
-
-class CToolSql : public CDialog
-{
-// Construction
-public:
- CToolSql(CWnd* pParent = NULL,CResource* pServer=NULL,CResource* pResource=NULL);
- ~CToolSql();
-
-// Dialog Data
- //{{AFX_DATA(CToolSql)
- enum { IDD = IDD_TOOL_SQL };
- CButton m_ctl_Stop;
- CButton m_ctl_Start;
- CComboBox m_ctl_Server;
- CTabCtrl m_tabs;
- int m_nIntervalTimerSeconds;
- BOOL m_bClear;
- //}}AFX_DATA
-
- CBitmapButton m_btn_QueryExec;
- CBitmapButton m_btn_Font;
- CBitmapButton m_btn_QueryDatabases;
-
-#ifdef _WIN64
- __int64 m_ui_timer;
-#else
- UINT m_ui_timer;
-#endif
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CToolSql)
- public:
- virtual BOOL PreTranslateMessage(MSG* pMsg);
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
-// Implementation
-
- void ActivateTab ( int tab );
- void DoProcessListQuery();
-
- CToolSqlQuery* m_pQuery;
- CToolSqlResults* m_pResults;
- CToolSqlStatus* m_pStatus;
-
- CResource* m_pServer;
- CResource* m_pResource;
- MYSQL* m_pdb;
- CFont m_font;
- LOGFONT m_lf;
- CRect m_rectTab[2];
- CRect m_rectDlg[2];
-
-protected:
-
- // Generated message map functions
- //{{AFX_MSG(CToolSql)
- virtual BOOL OnInitDialog();
- afx_msg void OnQueryPb();
- afx_msg void OnQueryDatabases();
- afx_msg void OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult);
- afx_msg void OnFontPb();
- afx_msg void OnSize(UINT nType, int cx, int cy);
- virtual void OnOK();
- virtual void OnCancel();
- afx_msg void OnStartPb();
- afx_msg void OnStopPb();
- afx_msg void OnTimer(UINT nIDEvent);
- afx_msg void OnDestroy();
- afx_msg void OnClear();
- afx_msg void OnChangeTimerSecs();
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-
- void DoOnSize(UINT nType, int cx, int cy) ;
-
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_ToolSql_H__826CB2FC_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/toolsqlquery.cpp b/VC++Files/mysqlmanager/toolsqlquery.cpp
deleted file mode 100644
index 1f246f47786..00000000000
--- a/VC++Files/mysqlmanager/toolsqlquery.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-// ToolSqlQuery.cpp : implementation file
-//
-
-#include "stdafx.h"
-#include "MySqlManager.h"
-#include "ToolSqlQuery.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-
-CToolSqlQuery::CToolSqlQuery(CWnd* pParent /*=NULL*/)
- : CDialog(CToolSqlQuery::IDD, pParent)
-{
- //{{AFX_DATA_INIT(CToolSqlQuery)
- m_edit = _T("");
- //}}AFX_DATA_INIT
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlQuery::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CToolSqlQuery)
- DDX_Control(pDX, IDC_EDIT, m_ctl_edit);
- DDX_Text(pDX, IDC_EDIT, m_edit);
- //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(CToolSqlQuery, CDialog)
- //{{AFX_MSG_MAP(CToolSqlQuery)
- ON_WM_SIZE()
- ON_WM_CLOSE()
- ON_COMMAND(IDM_QUERY_EXEC, OnQueryPb)
- ON_COMMAND(IDM_QUERY_DATABASES, OnQueryDatabases)
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlQuery::SetFont(CFont* pFont, BOOL bRedraw)
-{
- m_ctl_edit.SetFont(pFont,bRedraw);
- m_ctl_edit.Invalidate();
- m_ctl_edit.UpdateWindow();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlQuery::OnSize(UINT nType, int cx, int cy)
-{
- CDialog::OnSize(nType, cx, cy);
- if (IsWindow(m_ctl_edit.GetSafeHwnd()))
- m_ctl_edit.SetWindowPos(NULL,20,24,cx-40,cy-48,SWP_NOZORDER | SWP_NOMOVE);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlQuery::OnCancel()
-{
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlQuery::OnClose()
-{
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlQuery::OnQueryPb()
-{
- GetParent()->GetParent()->PostMessage(WM_COMMAND,IDM_QUERY_EXEC);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlQuery::OnQueryDatabases()
-{
- GetParent()->GetParent()->PostMessage(WM_COMMAND,IDM_QUERY_DATABASES);
-}
-/////////////////////////////////////////////////////////////////////////////
-
-BOOL CToolSqlQuery::PreTranslateMessage(MSG* pMsg)
-{
- if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
- {
- if (::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
- return TRUE;
- }
- return CDialog::PreTranslateMessage(pMsg);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-BOOL CToolSqlQuery::OnInitDialog()
-{
-
- CDialog::OnInitDialog();
- m_hAccel = ::LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE ( IDR_MAINFRAME ));
- return TRUE; // return TRUE unless you set the focus to a control
- // EXCEPTION: OCX Property Pages should return FALSE
-}
diff --git a/VC++Files/mysqlmanager/toolsqlquery.h b/VC++Files/mysqlmanager/toolsqlquery.h
deleted file mode 100644
index c5d318c161b..00000000000
--- a/VC++Files/mysqlmanager/toolsqlquery.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#if !defined(AFX_TOOLSQLQUERY_H__826CB2FD_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_TOOLSQLQUERY_H__826CB2FD_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-// ToolSqlQuery.h : header file
-//
-
-/////////////////////////////////////////////////////////////////////////////
-// CToolSqlQuery dialog
-
-class CToolSqlQuery : public CDialog
-{
-// Construction
-public:
- CToolSqlQuery(CWnd* pParent = NULL); // standard constructor
-
-// Dialog Data
- //{{AFX_DATA(CToolSqlQuery)
- enum { IDD = IDD_TOOL_SQL_QUERY };
- CEdit m_ctl_edit;
- CString m_edit;
- //}}AFX_DATA
-
- HACCEL m_hAccel;
-
- void SetFont(CFont* pFont, BOOL bRedraw = TRUE);
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CToolSqlQuery)
- public:
- virtual BOOL PreTranslateMessage(MSG* pMsg);
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
-// Implementation
-
-protected:
-
- // Generated message map functions
- //{{AFX_MSG(CToolSqlQuery)
- afx_msg void OnSize(UINT nType, int cx, int cy);
- afx_msg void OnCancel();
- afx_msg void OnClose();
- virtual BOOL OnInitDialog();
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-
- afx_msg void OnQueryPb();
- afx_msg void OnQueryDatabases();
-
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_TOOLSQLQUERY_H__826CB2FD_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/toolsqlresults.cpp b/VC++Files/mysqlmanager/toolsqlresults.cpp
deleted file mode 100644
index b6cfcded18b..00000000000
--- a/VC++Files/mysqlmanager/toolsqlresults.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// ToolSqlResults.cpp : implementation file
-//
-
-#include "stdafx.h"
-#include "MySqlManager.h"
-#include "ToolSqlResults.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-
-CToolSqlResults::CToolSqlResults(CWnd* pParent /*=NULL*/)
- : CDialog(CToolSqlResults::IDD, pParent)
-{
- //{{AFX_DATA_INIT(CToolSqlResults)
- m_edit = _T("");
- //}}AFX_DATA_INIT
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlResults::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CToolSqlResults)
- DDX_Control(pDX, IDC_EDIT, m_ctl_edit);
- DDX_Text(pDX, IDC_EDIT, m_edit);
- //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(CToolSqlResults, CDialog)
- //{{AFX_MSG_MAP(CToolSqlResults)
- ON_WM_SIZE()
- ON_WM_CLOSE()
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlResults::SetFont(CFont* pFont, BOOL bRedraw)
-{
- m_ctl_edit.SetFont(pFont,bRedraw);
- m_ctl_edit.Invalidate();
- m_ctl_edit.UpdateWindow();
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlResults::OnSize(UINT nType, int cx, int cy)
-{
- CDialog::OnSize(nType, cx, cy);
- if (IsWindow(m_ctl_edit.GetSafeHwnd()))
- m_ctl_edit.SetWindowPos(NULL,20,24,cx-40,cy-48,SWP_NOZORDER | SWP_NOMOVE);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlResults::OnCancel()
-{
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CToolSqlResults::OnClose()
-{
-}
diff --git a/VC++Files/mysqlmanager/toolsqlresults.h b/VC++Files/mysqlmanager/toolsqlresults.h
deleted file mode 100644
index c4de651cb81..00000000000
--- a/VC++Files/mysqlmanager/toolsqlresults.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#if !defined(AFX_TOOLSQLRESULTS_H__826CB2FE_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
-#define AFX_TOOLSQLRESULTS_H__826CB2FE_8B6D_11D1_AEC1_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-// ToolSqlResults.h : header file
-//
-
-/////////////////////////////////////////////////////////////////////////////
-// CToolSqlResults dialog
-
-class CToolSqlResults : public CDialog
-{
-// Construction
-public:
- CToolSqlResults(CWnd* pParent = NULL); // standard constructor
-
-// Dialog Data
- //{{AFX_DATA(CToolSqlResults)
- enum { IDD = IDD_TOOL_SQL_RESULTS };
- CEdit m_ctl_edit;
- CString m_edit;
- //}}AFX_DATA
-
- void SetFont(CFont* pFont, BOOL bRedraw = TRUE);
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CToolSqlResults)
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
-// Implementation
-
-protected:
-
- // Generated message map functions
- //{{AFX_MSG(CToolSqlResults)
- afx_msg void OnSize(UINT nType, int cx, int cy);
- afx_msg void OnCancel();
- afx_msg void OnClose();
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-
-
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_TOOLSQLRESULTS_H__826CB2FE_8B6D_11D1_AEC1_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysqlmanager/toolsqlstatus.cpp b/VC++Files/mysqlmanager/toolsqlstatus.cpp
deleted file mode 100644
index 81605480783..00000000000
--- a/VC++Files/mysqlmanager/toolsqlstatus.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-// ToolSqlStatus.cpp : implementation file
-//
-
-#include "stdafx.h"
-#include "mysqlmanager.h"
-#include "ToolSqlStatus.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-// CToolSqlStatus dialog
-
-
-CToolSqlStatus::CToolSqlStatus(CWnd* pParent /*=NULL*/)
- : CDialog(CToolSqlStatus::IDD, pParent)
-{
- //{{AFX_DATA_INIT(CToolSqlStatus)
- m_edit = _T("");
- //}}AFX_DATA_INIT
-}
-
-
-void CToolSqlStatus::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CToolSqlStatus)
- DDX_Control(pDX, IDC_EDIT, m_ctl_edit);
- DDX_Text(pDX, IDC_EDIT, m_edit);
- //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(CToolSqlStatus, CDialog)
- //{{AFX_MSG_MAP(CToolSqlStatus)
- ON_WM_DESTROY()
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-// CToolSqlStatus message handlers
-
-void CToolSqlStatus::OnDestroy()
-{
- CDialog::OnDestroy();
-
-}
diff --git a/VC++Files/mysqlmanager/toolsqlstatus.h b/VC++Files/mysqlmanager/toolsqlstatus.h
deleted file mode 100644
index 5e4883b0b30..00000000000
--- a/VC++Files/mysqlmanager/toolsqlstatus.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#if !defined(AFX_TOOLSQLSTATUS_H__40C861B4_9E5A_11D1_AED0_00600806E071__INCLUDED_)
-#define AFX_TOOLSQLSTATUS_H__40C861B4_9E5A_11D1_AED0_00600806E071__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-// ToolSqlStatus.h : header file
-//
-
-/////////////////////////////////////////////////////////////////////////////
-// CToolSqlStatus dialog
-
-class CToolSqlStatus : public CDialog
-{
-// Construction
-public:
- CToolSqlStatus(CWnd* pParent = NULL); // standard constructor
-
-// Dialog Data
- //{{AFX_DATA(CToolSqlStatus)
- enum { IDD = IDD_TOOL_SQL_STATUS };
- CEdit m_ctl_edit;
- CString m_edit;
- //}}AFX_DATA
-
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CToolSqlStatus)
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
-// Implementation
-protected:
-
- // Generated message map functions
- //{{AFX_MSG(CToolSqlStatus)
- afx_msg void OnDestroy();
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_TOOLSQLSTATUS_H__40C861B4_9E5A_11D1_AED0_00600806E071__INCLUDED_)
diff --git a/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp
index ad6caf1986e..64c4378b678 100644
--- a/VC++Files/mysys/mysys.dsp
+++ b/VC++Files/mysys/mysys.dsp
@@ -448,6 +448,10 @@ SOURCE=.\my_mkdir.c
# End Source File
# Begin Source File
+SOURCE=.\my_mmap.c
+# End Source File
+# Begin Source File
+
SOURCE=.\my_net.c
# End Source File
# Begin Source File
@@ -536,7 +540,6 @@ SOURCE=.\my_windac.c
# End Source File
# Begin Source File
-
SOURCE=.\my_winsem.c
# End Source File
# Begin Source File
diff --git a/VC++Files/prepare b/VC++Files/prepare
index e0dff9e04c0..f68d0676fc9 100755
--- a/VC++Files/prepare
+++ b/VC++Files/prepare
@@ -67,8 +67,6 @@ link_dir_dirs()
}
link_dir_files 'heap'
-link_dir_files 'isam'
-link_dir_files 'merge'
link_dir_files 'mysys'
link_dir_files 'zlib'
link_dir_files 'regex'
@@ -91,7 +89,6 @@ link_dir_dirs 'innobase'
ln -s $SRCDIR/myisam/myisampack.c $SRCDIR/VC++Files/myisampack/
ln -s $SRCDIR/client/mysqlbinlog.cc $SRCDIR/VC++Files/mysqlbinlog/mysqlbinlog.cpp
-ln -s $SRCDIR/isam/pack_isam.c $SRCDIR/VC++Files/pack_isam/pack_isam.c
echo '/* added for win : */' >> $SRCDIR/config.h
echo '#undef HAVE_SCHED_H' >> $SRCDIR/config.h
@@ -101,4 +98,4 @@ echo '/* added for win : */' >> $SRCDIR/innobase/ib_config.h
echo '#undef HAVE_SCHED_H' >> $SRCDIR/innobase/ib_config.h
cd $SRCDIR/VC++Files
-echo '1' > prepare_done \ No newline at end of file
+echo '1' > prepare_done
diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp
index 3508e6b31d0..723c0d63b36 100644
--- a/VC++Files/sql/mysqld.dsp
+++ b/VC++Files/sql/mysqld.dsp
@@ -58,7 +58,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 /machine:I386
-# 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_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_release/mysqld.exe"
+# 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_release\vio.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_release/mysqld.exe"
# SUBTRACT LINK32 /debug
!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
@@ -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\isam.lib ..\lib_debug\merge.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 /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 /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/mysqld-debug.exe" /pdbtype:sept
!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
@@ -110,8 +110,8 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# 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 Wsock32.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /debug /machine:I386
-# 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_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /map /machine:I386 /out:"../client_release/mysqld-nt.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 Wsock32.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /debug /machine:I386
+# 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_release\vio.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /map /machine:I386 /out:"../client_release/mysqld-nt.exe"
# SUBTRACT LINK32 /pdb:none /debug
!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
@@ -138,9 +138,9 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# 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 Wsock32.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib /nologo /subsystem:console /map /machine:I386
+# 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 Wsock32.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib /nologo /subsystem:console /map /machine:I386
# SUBTRACT BASE LINK32 /pdb:none /debug
-# 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_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys-max.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib ..\lib_release\innodb.lib ..\lib_release\bdb.lib /nologo /subsystem:console /map /machine:I386 /out:"../client_release/mysqld-max-nt.exe"
+# 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_release\vio.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys-max.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib ..\lib_release\innodb.lib ..\lib_release\bdb.lib /nologo /subsystem:console /map /machine:I386 /out:"../client_release/mysqld-max-nt.exe"
# SUBTRACT LINK32 /pdb:none /debug
!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
@@ -167,8 +167,8 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# 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 Wsock32.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /debug /machine:I386
-# 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_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys-max.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\bdb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_release/mysqld-max.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 Wsock32.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /debug /machine:I386
+# 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_release\vio.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys-max.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\bdb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_release/mysqld-max.exe"
# SUBTRACT LINK32 /debug
!ELSEIF "$(CFG)" == "mysqld - Win32 classic"
@@ -194,9 +194,9 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# 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 Wsock32.lib ..\lib_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386
+# 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 Wsock32.lib ..\lib_release\vio.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386
# SUBTRACT BASE LINK32 /debug
-# 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_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_classic/mysqld.exe" /libpath:"..\lib_release"
+# 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_release\vio.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_classic/mysqld.exe" /libpath:"..\lib_release"
# SUBTRACT LINK32 /debug
!ELSEIF "$(CFG)" == "mysqld - Win32 pro"
@@ -222,9 +222,9 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# 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 Wsock32.lib ..\lib_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386
+# 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 Wsock32.lib ..\lib_release\vio.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386
# SUBTRACT BASE LINK32 /debug
-# 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_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_pro/mysqld.exe" /libpath:"..\lib_release"
+# 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_release\vio.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_pro/mysqld.exe" /libpath:"..\lib_release"
# SUBTRACT LINK32 /debug
!ELSEIF "$(CFG)" == "mysqld - Win32 classic nt"
@@ -251,9 +251,9 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# 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 Wsock32.lib ..\lib_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386
+# 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 Wsock32.lib ..\lib_release\vio.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386
# SUBTRACT BASE LINK32 /debug
-# 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_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_classic/mysqld-nt.exe" /libpath:"..\lib_release"
+# 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_release\vio.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_classic/mysqld-nt.exe" /libpath:"..\lib_release"
# SUBTRACT LINK32 /debug
!ELSEIF "$(CFG)" == "mysqld - Win32 pro nt"
@@ -279,9 +279,9 @@ BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# 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 Wsock32.lib ..\lib_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386
+# 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 Wsock32.lib ..\lib_release\vio.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib /nologo /subsystem:console /pdb:none /machine:I386
# SUBTRACT BASE LINK32 /debug
-# 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_release\vio.lib ..\lib_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_pro/mysqld-nt.exe" /libpath:"..\lib_release"
+# 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_release\vio.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innodb.lib ..\lib_release\zlib.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../client_pro/mysqld-nt.exe" /libpath:"..\lib_release"
# SUBTRACT LINK32 /debug
!ENDIF
@@ -463,14 +463,6 @@ SOURCE=.\ha_innodb.cpp
# End Source File
# Begin Source File
-SOURCE=.\ha_isam.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ha_isammrg.cpp
-# End Source File
-# Begin Source File
-
SOURCE=.\ha_myisam.cpp
# End Source File
# Begin Source File
@@ -1088,8 +1080,16 @@ SOURCE=.\mf_iocache.cpp
!ELSEIF "$(CFG)" == "mysqld - Win32 pro nt"
-!ENDIF
+!ENDIF
+
+# End Source File
+# Begin Source File
+SOURCE=.\my_decimal.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\my_time.c
# End Source File
# Begin Source File
@@ -1199,7 +1199,7 @@ SOURCE=.\pack.c
# End Source File
# Begin Source File
-SOURCE=.\my_time.c
+SOURCE=.\parse_file.cpp
# End Source File
# Begin Source File
@@ -1262,6 +1262,10 @@ SOURCE=.\protocol.cpp
# End Source File
# Begin Source File
+SOURCE=.\protocol_cursor.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\records.cpp
!IF "$(CFG)" == "mysqld - Win32 Release"
@@ -1302,6 +1306,26 @@ SOURCE=.\slave.cpp
# End Source File
# Begin Source File
+SOURCE=.\sp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sp_cache.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sp_head.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sp_pcontext.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sp_rcontext.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\spatial.cpp
# End Source File
# Begin Source File
@@ -1814,6 +1838,10 @@ SOURCE=.\sql_test.cpp
# End Source File
# Begin Source File
+SOURCE=.\sql_trigger.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\sql_udf.cpp
# End Source File
# Begin Source File
@@ -1845,8 +1873,12 @@ SOURCE=.\sql_update.cpp
!ELSEIF "$(CFG)" == "mysqld - Win32 pro nt"
-!ENDIF
+!ENDIF
+
+# End Source File
+# Begin Source File
+SOURCE=.\sql_view.cpp
# End Source File
# Begin Source File
diff --git a/VC++Files/sql/mysqldmax.dsp b/VC++Files/sql/mysqldmax.dsp
index a7ed1b918c7..2711b274da0 100644
--- a/VC++Files/sql/mysqldmax.dsp
+++ b/VC++Files/sql/mysqldmax.dsp
@@ -51,7 +51,7 @@ BSC32=bscmake.exe
# 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 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 /machine:I386
-# 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_release\isam.lib ..\lib_release\merge.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innobase-opt.lib ..\lib_release\libdb32s.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"LIBC" /out:"../client_release/mysqld-max-opt.exe"
+# 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_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\innobase-opt.lib ..\lib_release\libdb32s.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /nodefaultlib:"LIBC" /out:"../client_release/mysqld-max-opt.exe"
!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
@@ -75,7 +75,7 @@ BSC32=bscmake.exe
# 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 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\isam.lib ..\lib_debug\merge.lib ..\lib_debug\mysys.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap.lib ..\lib_release\innobase-opt.lib ..\lib_release\libdb32s.lib /nologo /subsystem:console /incremental:no /pdb:"debug/mysqld.pdb" /debug /machine:I386 /nodefaultlib:"LIBC" /out:"../client_debug/mysqld-max.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\mysys.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap.lib ..\lib_release\innobase-opt.lib ..\lib_release\libdb32s.lib /nologo /subsystem:console /incremental:no /pdb:"debug/mysqld.pdb" /debug /machine:I386 /nodefaultlib:"LIBC" /out:"../client_debug/mysqld-max.exe" /pdbtype:sept
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
@@ -100,7 +100,7 @@ BSC32=bscmake.exe
# 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 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 /machine:I386
-# 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_release\isam.lib ..\lib_release\merge.lib ..\lib_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib ..\lib_release\innobase-nt.lib ..\lib_release\libdb32s.lib /nologo /subsystem:console /pdb:"NT/mysqld-nt.pdb" /map:"NT/mysqld-nt.map" /machine:I386 /nodefaultlib:"LIBC" /out:"../client_release/mysqld-max-nt.exe"
+# 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_release\myisam.lib ..\lib_release\myisammrg.lib ..\lib_release\mysys.lib ..\lib_release\strings.lib ..\lib_release\regex.lib ..\lib_release\heap.lib ..\lib_release\zlib.lib ..\lib_release\innobase-nt.lib ..\lib_release\libdb32s.lib /nologo /subsystem:console /pdb:"NT/mysqld-nt.pdb" /map:"NT/mysqld-nt.map" /machine:I386 /nodefaultlib:"LIBC" /out:"../client_release/mysqld-max-nt.exe"
# SUBTRACT LINK32 /pdb:none
!ENDIF
@@ -204,14 +204,6 @@ SOURCE=.\ha_innobase.cpp
# End Source File
# Begin Source File
-SOURCE=.\ha_isam.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ha_isammrg.cpp
-# End Source File
-# Begin Source File
-
SOURCE=.\ha_myisam.cpp
# End Source File
# Begin Source File
diff --git a/VC++Files/strings/strings.dsp b/VC++Files/strings/strings.dsp
index c8f3208e822..320cdaf2132 100644
--- a/VC++Files/strings/strings.dsp
+++ b/VC++Files/strings/strings.dsp
@@ -113,10 +113,18 @@ SOURCE=".\ctype-bin.c"
# End Source File
# Begin Source File
+SOURCE=".\ctype-cp932.c"
+# End Source File
+# Begin Source File
+
SOURCE=".\ctype-czech.c"
# End Source File
# Begin Source File
+SOURCE=".\ctype-eucjpms.c"
+# End Source File
+# Begin Source File
+
SOURCE=".\ctype-euc_kr.c"
# End Source File
# Begin Source File
@@ -177,6 +185,10 @@ SOURCE=.\ctype.c
# End Source File
# Begin Source File
+SOURCE=.\decimal.c
+# End Source File
+# Begin Source File
+
SOURCE=.\int2str.c
# End Source File
# Begin Source File
diff --git a/VC++Files/strings/strings_ia64.dsp b/VC++Files/strings/strings_ia64.dsp
index 6449b2b1355..a34a238dfdc 100644
--- a/VC++Files/strings/strings_ia64.dsp
+++ b/VC++Files/strings/strings_ia64.dsp
@@ -112,6 +112,10 @@ SOURCE=".\ctype-bin.c"
# End Source File
# Begin Source File
+SOURCE=".\ctype-cp932.c"
+# End Source File
+# Begin Source File
+
SOURCE=".\ctype-czech.c"
# End Source File
# Begin Source File
@@ -120,6 +124,10 @@ SOURCE=".\ctype-euc_kr.c"
# End Source File
# Begin Source File
+SOURCE=".\ctype-eucjpms.c"
+# End Source File
+# Begin Source File
+
SOURCE=".\ctype-extra.c"
# End Source File
# Begin Source File
diff --git a/VC++Files/test1/mysql_thr.c b/VC++Files/test1/mysql_thr.c
index fac5c37a9af..c2743cb8e4c 100644
--- a/VC++Files/test1/mysql_thr.c
+++ b/VC++Files/test1/mysql_thr.c
@@ -167,6 +167,7 @@ pthread_handler_decl(test_thread,arg)
perror("");
goto end;
}
+ mysql.reconnect= 1;
if (mysql_query(&mysql,"select 1") < 0)
{
fprintf(stderr,"Query failed (%s)\n",mysql_error(&mysql));
diff --git a/VC++Files/winmysqladmin/main.cpp b/VC++Files/winmysqladmin/main.cpp
index dfb2004a780..150bc669c74 100644
--- a/VC++Files/winmysqladmin/main.cpp
+++ b/VC++Files/winmysqladmin/main.cpp
@@ -1337,6 +1337,7 @@ void __fastcall TForm1::IsMySQLInit(void)
}
}
+ MySQL->reconnect= 1;
}
@@ -1348,6 +1349,7 @@ void __fastcall TForm1::IsMySQLInit(void)
MySQL = mysql_init(MySQL);
if(mysql_real_connect(MySQL,host,user,password , 0, 0, NULL, 0))
IsConnect = true;
+ MySQL->reconnect= 1;
}
}
}
diff --git a/VC++Files/winmysqladmin/mysql.h b/VC++Files/winmysqladmin/mysql.h
index f01b55f5d3f..734d78efea0 100644
--- a/VC++Files/winmysqladmin/mysql.h
+++ b/VC++Files/winmysqladmin/mysql.h
@@ -145,7 +145,7 @@ typedef struct st_mysql {
unsigned long thread_id; /* Id for connection in server */
my_ulonglong affected_rows;
my_ulonglong insert_id; /* id if insert on table with NEXTNR */
- my_ulonglong extra_info; /* Used by mysqlshow */
+ my_ulonglong extra_info; /* Not used */
unsigned long packet_length;
enum mysql_status status;
MYSQL_FIELD *fields;
diff --git a/VC++Files/winmysqladmin/winmysqladmin.cpp b/VC++Files/winmysqladmin/winmysqladmin.cpp
index 591b7518fa3..a4fbe590196 100644
--- a/VC++Files/winmysqladmin/winmysqladmin.cpp
+++ b/VC++Files/winmysqladmin/winmysqladmin.cpp
@@ -9,8 +9,6 @@ USEFORM("db.cpp", dbfrm);
USELIB("lib\mysqlclient.lib");
USELIB("lib\myisammrg.lib");
USELIB("lib\heap.lib");
-USELIB("lib\isam.lib");
-USELIB("lib\merge.lib");
USELIB("lib\myisam.lib");
USELIB("lib\mysys.lib");
USELIB("lib\regex.lib");
diff --git a/acinclude.m4 b/acinclude.m4
deleted file mode 100644
index f868489f2d2..00000000000
--- a/acinclude.m4
+++ /dev/null
@@ -1,1990 +0,0 @@
-# Local macros for automake & autoconf
-
-
-AC_DEFUN([MYSQL_CHECK_READLINE_DECLARES_HIST_ENTRY], [
- AC_CACHE_CHECK([HIST_ENTRY is declared in readline/readline.h], mysql_cv_hist_entry_declared,
- AC_TRY_COMPILE(
- [
- #include "stdio.h"
- #include "readline/readline.h"
- ],
- [
- HIST_ENTRY entry;
- ],
- [
- mysql_cv_hist_entry_declared=yes
- AC_DEFINE_UNQUOTED(HAVE_HIST_ENTRY, [1],
- [HIST_ENTRY is defined in the outer libeditreadline])
- ],
- [mysql_cv_libedit_interface=no]
- )
- )
-])
-
-AC_DEFUN([MYSQL_CHECK_LIBEDIT_INTERFACE], [
- AC_CACHE_CHECK([libedit variant of rl_completion_entry_function], mysql_cv_libedit_interface,
- AC_TRY_COMPILE(
- [
- #include "stdio.h"
- #include "readline/readline.h"
- ],
- [
- char res= *(*rl_completion_entry_function)(0,0);
- completion_matches(0,0);
- ],
- [
- mysql_cv_libedit_interface=yes
- AC_DEFINE_UNQUOTED([USE_LIBEDIT_INTERFACE], [1],
- [used libedit interface (can we dereference result of rl_completion_entry_function)])
- ],
- [mysql_cv_libedit_interface=no]
- )
- )
-])
-
-AC_DEFUN([MYSQL_CHECK_NEW_RL_INTERFACE], [
- AC_CACHE_CHECK([defined rl_compentry_func_t and rl_completion_func_t], mysql_cv_new_rl_interface,
- AC_TRY_COMPILE(
- [
- #include "stdio.h"
- #include "readline/readline.h"
- ],
- [
- rl_completion_func_t *func1= (rl_completion_func_t*)0;
- rl_compentry_func_t *func2= (rl_compentry_func_t*)0;
- ],
- [
- mysql_cv_new_rl_interface=yes
- AC_DEFINE_UNQUOTED([USE_NEW_READLINE_INTERFACE], [1],
- [used new readline interface (are rl_completion_func_t and rl_compentry_func_t defined)])
- ],
- [mysql_cv_new_rl_interface=no]
- )
- )
-])
-
-# A local version of AC_CHECK_SIZEOF that includes sys/types.h
-dnl MYSQL_CHECK_SIZEOF(TYPE [, CROSS-SIZE])
-AC_DEFUN([MYSQL_CHECK_SIZEOF],
-[changequote(<<, >>)dnl
-dnl The name to #define.
-define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl
-dnl The cache variable name.
-define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl
-changequote([, ])dnl
-AC_MSG_CHECKING(size of $1)
-AC_CACHE_VAL(AC_CV_NAME,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#endif
-main()
-{
- FILE *f=fopen("conftestval", "w");
- if (!f) exit(1);
- fprintf(f, "%d\n", sizeof($1));
- exit(0);
-}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$2], , , AC_CV_NAME=$2))])dnl
-AC_MSG_RESULT($AC_CV_NAME)
-AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [ ])
-undefine([AC_TYPE_NAME])dnl
-undefine([AC_CV_NAME])dnl
-])
-
-#---START: Used in for client configure
-AC_DEFUN([MYSQL_TYPE_ACCEPT],
-[ac_save_CXXFLAGS="$CXXFLAGS"
-AC_CACHE_CHECK([base type of last arg to accept], mysql_cv_btype_last_arg_accept,
-AC_LANG_PUSH(C++)
-if test "$ac_cv_prog_gxx" = "yes"
-then
- # Add -Werror, remove -fbranch-probabilities (Bug #268)
- CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'`
-fi
-mysql_cv_btype_last_arg_accept=none
-[AC_TRY_COMPILE([#if defined(inline)
-#undef inline
-#endif
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-],
-[int a = accept(1, (struct sockaddr *) 0, (socklen_t *) 0); return (a != 0);],
-mysql_cv_btype_last_arg_accept=socklen_t)]
-if test "$mysql_cv_btype_last_arg_accept" = "none"; then
-[AC_TRY_COMPILE([#if defined(inline)
-#undef inline
-#endif
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-],
-[int a = accept(1, (struct sockaddr *) 0, (size_t *) 0); return (a != 0);],
-mysql_cv_btype_last_arg_accept=size_t)]
-fi
-if test "$mysql_cv_btype_last_arg_accept" = "none"; then
-mysql_cv_btype_last_arg_accept=int
-fi)
-AC_LANG_POP(C++)
-AC_DEFINE_UNQUOTED([SOCKET_SIZE_TYPE], [$mysql_cv_btype_last_arg_accept],
- [The base type of the last arg to accept])
-CXXFLAGS="$ac_save_CXXFLAGS"
-])
-#---END:
-
-dnl Find type of qsort
-AC_DEFUN([MYSQL_TYPE_QSORT],
-[AC_CACHE_CHECK([return type of qsort], mysql_cv_type_qsort,
-[AC_TRY_COMPILE([#include <stdlib.h>
-#ifdef __cplusplus
-extern "C"
-#endif
-void qsort(void *base, size_t nel, size_t width,
- int (*compar) (const void *, const void *));
-],
-[int i;], mysql_cv_type_qsort=void, mysql_cv_type_qsort=int)])
-AC_DEFINE_UNQUOTED([RETQSORTTYPE], [$mysql_cv_type_qsort],
- [The return type of qsort (int or void).])
-if test "$mysql_cv_type_qsort" = "void"
-then
- AC_DEFINE_UNQUOTED([QSORT_TYPE_IS_VOID], [1], [qsort returns void])
-fi
-])
-
-#---START: Figure out whether to use 'struct rlimit' or 'struct rlimit64'
-AC_DEFUN([MYSQL_TYPE_STRUCT_RLIMIT],
-[ac_save_CXXFLAGS="$CXXFLAGS"
-AC_CACHE_CHECK([struct type to use with setrlimit], mysql_cv_btype_struct_rlimit,
-AC_LANG_PUSH(C++)
-if test "$ac_cv_prog_gxx" = "yes"
-then
- # Add -Werror, remove -fbranch-probabilities (Bug #268)
- CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'`
-fi
-mysql_cv_btype_struct_rlimit=none
-[AC_TRY_COMPILE([#if defined(inline)
-#undef inline
-#endif
-#include <stdlib.h>
-#include <sys/resource.h>
-],
-[struct rlimit64 rl; setrlimit(RLIMIT_CORE, &rl);],
-mysql_cv_btype_struct_rlimit="struct rlimit64")]
-if test "$mysql_cv_btype_struct_rlimit" = "none"; then
-mysql_cv_btype_struct_rlimit="struct rlimit"
-fi)
-AC_LANG_POP(C++)
-AC_DEFINE_UNQUOTED([STRUCT_RLIMIT], [$mysql_cv_btype_struct_rlimit],
- [The struct rlimit type to use with setrlimit])
-CXXFLAGS="$ac_save_CXXFLAGS"
-])
-#---END:
-
-AC_DEFUN([MYSQL_TIMESPEC_TS],
-[AC_CACHE_CHECK([if struct timespec has a ts_sec member], mysql_cv_timespec_ts,
-[AC_TRY_COMPILE([#include <pthread.h>
-#ifdef __cplusplus
-extern "C"
-#endif
-],
-[struct timespec abstime;
-
-abstime.ts_sec = time(NULL)+1;
-abstime.ts_nsec = 0;
-], mysql_cv_timespec_ts=yes, mysql_cv_timespec_ts=no)])
-if test "$mysql_cv_timespec_ts" = "yes"
-then
- AC_DEFINE([HAVE_TIMESPEC_TS_SEC], [1],
- [Timespec has a ts_sec instead of tv_sev])
-fi
-])
-
-AC_DEFUN([MYSQL_TZNAME],
-[AC_CACHE_CHECK([if we have tzname variable], mysql_cv_tzname,
-[AC_TRY_COMPILE([#include <time.h>
-#ifdef __cplusplus
-extern "C"
-#endif
-],
-[ tzset();
- return tzname[0] != 0;
-], mysql_cv_tzname=yes, mysql_cv_tzname=no)])
-if test "$mysql_cv_tzname" = "yes"
-then
- AC_DEFINE([HAVE_TZNAME], [1], [Have the tzname variable])
-fi
-])
-
-
-dnl Define zlib paths to point at bundled zlib
-
-AC_DEFUN([MYSQL_USE_BUNDLED_ZLIB], [
-ZLIB_INCLUDES="-I\$(top_srcdir)/zlib"
-ZLIB_LIBS="\$(top_builddir)/zlib/libz.la"
-dnl Omit -L$pkglibdir as it's always in the list of mysql_config deps.
-ZLIB_DEPS="-lz"
-zlib_dir="zlib"
-AC_SUBST([zlib_dir])
-mysql_cv_compress="yes"
-])
-
-dnl Auxiliary macro to check for zlib at given path
-
-AC_DEFUN([MYSQL_CHECK_ZLIB_DIR], [
-save_INCLUDES="$INCLUDES"
-save_LIBS="$LIBS"
-INCLUDES="$INCLUDES $ZLIB_INCLUDES"
-LIBS="$LIBS $ZLIB_LIBS"
-AC_CACHE_VAL([mysql_cv_compress],
- [AC_TRY_LINK([#include <zlib.h>],
- [return compress(0, (unsigned long*) 0, "", 0);],
- [mysql_cv_compress="yes"
- AC_MSG_RESULT([ok])],
- [mysql_cv_compress="no"])
- ])
-INCLUDES="$save_INCLUDES"
-LIBS="$save_LIBS"
-])
-
-dnl MYSQL_CHECK_ZLIB_WITH_COMPRESS
-dnl ------------------------------------------------------------------------
-dnl @synopsis MYSQL_CHECK_ZLIB_WITH_COMPRESS
-dnl
-dnl Provides the following configure options:
-dnl --with-zlib-dir=DIR
-dnl Possible DIR values are:
-dnl - "no" - the macro will disable use of compression functions
-dnl - "bundled" - means use zlib bundled along with MySQL sources
-dnl - empty, or not specified - the macro will try default system
-dnl library (if present), and in case of error will fall back to
-dnl bundled zlib
-dnl - zlib location prefix - given location prefix, the macro expects
-dnl to find the library headers in $prefix/include, and binaries in
-dnl $prefix/lib. If zlib headers or binaries weren't found at $prefix, the
-dnl macro bails out with error.
-dnl
-dnl If the library was found, this function #defines HAVE_COMPRESS
-dnl and configure variables ZLIB_INCLUDES (i.e. -I/path/to/zlib/include),
-dnl ZLIB_LIBS (i. e. -L/path/to/zlib/lib -lz) and ZLIB_DEPS which is
-dnl used in mysql_config and is always the same as ZLIB_LIBS except to
-dnl when we use the bundled zlib. In the latter case ZLIB_LIBS points to the
-dnl build dir ($top_builddir/zlib), while mysql_config must point to the
-dnl installation dir ($pkglibdir), so ZLIB_DEPS is set to point to
-dnl $pkglibdir.
-
-AC_DEFUN([MYSQL_CHECK_ZLIB_WITH_COMPRESS], [
-AC_MSG_CHECKING([for zlib compression library])
-case $SYSTEM_TYPE in
-*netware* | *modesto*)
- AC_MSG_RESULT(ok)
- AC_DEFINE([HAVE_COMPRESS], [1], [Define to enable compression support])
- ;;
- *)
- AC_ARG_WITH([zlib-dir],
- AC_HELP_STRING([--with-zlib-dir=DIR],
- [Provide MySQL with a custom location of
- compression library. Given DIR, zlib library is
- assumed to be in $DIR/lib and header files
- in $DIR/include. Specify "bundled" to use
- bundled zlib.]),
- [mysql_zlib_dir=${withval}],
- [mysql_zlib_dir=""])
- case "$mysql_zlib_dir" in
- "no")
- mysql_cv_compress="no"
- AC_MSG_RESULT([disabled])
- ;;
- "bundled")
- MYSQL_USE_BUNDLED_ZLIB
- AC_MSG_RESULT([using bundled zlib])
- ;;
- "")
- ZLIB_INCLUDES=""
- ZLIB_LIBS="-lz"
- MYSQL_CHECK_ZLIB_DIR
- if test "$mysql_cv_compress" = "no"; then
- MYSQL_USE_BUNDLED_ZLIB
- AC_MSG_RESULT([system-wide zlib not found, using one bundled with MySQL])
- fi
- ;;
- *)
- if test -f "$mysql_zlib_dir/lib/libz.a" -a \
- -f "$mysql_zlib_dir/include/zlib.h"; then
- ZLIB_INCLUDES="-I$mysql_zlib_dir/include"
- ZLIB_LIBS="-L$mysql_zlib_dir/lib -lz"
- MYSQL_CHECK_ZLIB_DIR
- fi
- if test "x$mysql_cv_compress" != "xyes"; then
- AC_MSG_ERROR([headers or binaries were not found in $mysql_zlib_dir/{include,lib}])
- fi
- ;;
- esac
- if test "$mysql_cv_compress" = "yes"; then
- if test "x$ZLIB_DEPS" = "x"; then
- ZLIB_DEPS="$ZLIB_LIBS"
- fi
- AC_SUBST([ZLIB_LIBS])
- AC_SUBST([ZLIB_DEPS])
- AC_SUBST([ZLIB_INCLUDES])
- AC_DEFINE([HAVE_COMPRESS], [1], [Define to enable compression support])
- fi
- ;;
-esac
-])
-
-dnl ------------------------------------------------------------------------
-
-#---START: Used in for client configure
-AC_DEFUN([MYSQL_CHECK_ULONG],
-[AC_MSG_CHECKING(for type ulong)
-AC_CACHE_VAL(ac_cv_ulong,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-main()
-{
- ulong foo;
- foo++;
- exit(0);
-}], ac_cv_ulong=yes, ac_cv_ulong=no, ac_cv_ulong=no)])
-AC_MSG_RESULT($ac_cv_ulong)
-if test "$ac_cv_ulong" = "yes"
-then
- AC_DEFINE([HAVE_ULONG], [1], [system headers define ulong])
-fi
-])
-
-AC_DEFUN([MYSQL_CHECK_UCHAR],
-[AC_MSG_CHECKING(for type uchar)
-AC_CACHE_VAL(ac_cv_uchar,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-main()
-{
- uchar foo;
- foo++;
- exit(0);
-}], ac_cv_uchar=yes, ac_cv_uchar=no, ac_cv_uchar=no)])
-AC_MSG_RESULT($ac_cv_uchar)
-if test "$ac_cv_uchar" = "yes"
-then
- AC_DEFINE([HAVE_UCHAR], [1], [system headers define uchar])
-fi
-])
-
-AC_DEFUN([MYSQL_CHECK_UINT],
-[AC_MSG_CHECKING(for type uint)
-AC_CACHE_VAL(ac_cv_uint,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-main()
-{
- uint foo;
- foo++;
- exit(0);
-}], ac_cv_uint=yes, ac_cv_uint=no, ac_cv_uint=no)])
-AC_MSG_RESULT($ac_cv_uint)
-if test "$ac_cv_uint" = "yes"
-then
- AC_DEFINE([HAVE_UINT], [1], [system headers define uint])
-fi
-])
-
-
-AC_DEFUN([MYSQL_CHECK_IN_ADDR_T],
-[AC_MSG_CHECKING(for type in_addr_t)
-AC_CACHE_VAL(ac_cv_in_addr_t,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-int main(int argc, char **argv)
-{
- in_addr_t foo;
- exit(0);
-}], ac_cv_in_addr_t=yes, ac_cv_in_addr_t=no, ac_cv_in_addr_t=no)])
-AC_MSG_RESULT($ac_cv_in_addr_t)
-if test "$ac_cv_in_addr_t" = "yes"
-then
- AC_DEFINE([HAVE_IN_ADDR_T], [1], [system headers define in_addr_t])
-fi
-])
-
-
-AC_DEFUN([MYSQL_PTHREAD_YIELD],
-[AC_CACHE_CHECK([if pthread_yield takes zero arguments], ac_cv_pthread_yield_zero_arg,
-[AC_TRY_LINK([#define _GNU_SOURCE
-#include <pthread.h>
-#ifdef __cplusplus
-extern "C"
-#endif
-],
-[
- pthread_yield();
-], ac_cv_pthread_yield_zero_arg=yes, ac_cv_pthread_yield_zero_arg=yeso)])
-if test "$ac_cv_pthread_yield_zero_arg" = "yes"
-then
- AC_DEFINE([HAVE_PTHREAD_YIELD_ZERO_ARG], [1],
- [pthread_yield that doesn't take any arguments])
-fi
-]
-[AC_CACHE_CHECK([if pthread_yield takes 1 argument], ac_cv_pthread_yield_one_arg,
-[AC_TRY_LINK([#define _GNU_SOURCE
-#include <pthread.h>
-#ifdef __cplusplus
-extern "C"
-#endif
-],
-[
- pthread_yield(0);
-], ac_cv_pthread_yield_one_arg=yes, ac_cv_pthread_yield_one_arg=no)])
-if test "$ac_cv_pthread_yield_one_arg" = "yes"
-then
- AC_DEFINE([HAVE_PTHREAD_YIELD_ONE_ARG], [1],
- [pthread_yield function with one argument])
-fi
-]
-)
-
-
-
-#---END:
-
-AC_DEFUN([MYSQL_CHECK_FP_EXCEPT],
-[AC_MSG_CHECKING(for type fp_except)
-AC_CACHE_VAL(ac_cv_fp_except,
-[AC_TRY_RUN([#include <stdio.h>
-#include <sys/types.h>
-#include <ieeefp.h>
-main()
-{
- fp_except foo;
- foo++;
- exit(0);
-}], ac_cv_fp_except=yes, ac_cv_fp_except=no, ac_cv_fp_except=no)])
-AC_MSG_RESULT($ac_cv_fp_except)
-if test "$ac_cv_fp_except" = "yes"
-then
- AC_DEFINE([HAVE_FP_EXCEPT], [1], [fp_except from ieeefp.h])
-fi
-])
-
-# From fileutils-3.14/aclocal.m4
-
-# @defmac AC_PROG_CC_STDC
-# @maindex PROG_CC_STDC
-# @ovindex CC
-# If the C compiler in not in ANSI C mode by default, try to add an option
-# to output variable @code{CC} to make it so. This macro tries various
-# options that select ANSI C on some system or another. It considers the
-# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
-# handles function prototypes correctly.
-#
-# Patched by monty to only check if __STDC__ is defined. With the original
-# check it's impossible to get things to work with the Sunpro compiler from
-# Workshop 4.2
-#
-# If you use this macro, you should check after calling it whether the C
-# compiler has been set to accept ANSI C; if not, the shell variable
-# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source
-# code in ANSI C, you can make an un-ANSIfied copy of it by using the
-# program @code{ansi2knr}, which comes with Ghostscript.
-# @end defmac
-
-AC_DEFUN([AM_PROG_CC_STDC],
-[AC_REQUIRE([AC_PROG_CC])
-AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
-AC_CACHE_VAL(am_cv_prog_cc_stdc,
-[am_cv_prog_cc_stdc=no
-ac_save_CC="$CC"
-# Don't try gcc -ansi; that turns off useful extensions and
-# breaks some systems' header files.
-# AIX -qlanglvl=ansi
-# Ultrix and OSF/1 -std1
-# HP-UX -Aa -D_HPUX_SOURCE
-# SVR4 -Xc -D__EXTENSIONS__
-# removed "-Xc -D__EXTENSIONS__" beacause sun c++ does not like it.
-for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE"
-do
- CC="$ac_save_CC $ac_arg"
- AC_TRY_COMPILE(
-[#if !defined(__STDC__)
-choke me
-#endif
-/* DYNIX/ptx V4.1.3 can't compile sys/stat.h with -Xc -D__EXTENSIONS__. */
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-], [
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};],
-[am_cv_prog_cc_stdc="$ac_arg"; break])
-done
-CC="$ac_save_CC"
-])
-AC_MSG_RESULT($am_cv_prog_cc_stdc)
-case "x$am_cv_prog_cc_stdc" in
- x|xno) ;;
- *) CC="$CC $am_cv_prog_cc_stdc" ;;
-esac
-])
-
-#
-# Check to make sure that the build environment is sane.
-#
-
-AC_DEFUN([AM_SANITY_CHECK],
-[AC_MSG_CHECKING([whether build environment is sane])
-sleep 1
-echo timestamp > conftestfile
-# Do this in a subshell so we don't clobber the current shell's
-# arguments. FIXME: maybe try `-L' hack like GETLOADAVG test?
-if (set X `ls -t $srcdir/configure conftestfile`; test "[$]2" = conftestfile)
-then
- # Ok.
- :
-else
- AC_MSG_ERROR([newly created file is older than distributed files!
-Check your system clock])
-fi
-rm -f conftest*
-AC_MSG_RESULT(yes)])
-
-# Orginal from bash-2.0 aclocal.m4, Changed to use termcap last by monty.
-
-AC_DEFUN([MYSQL_CHECK_LIB_TERMCAP],
-[
-AC_CACHE_VAL(mysql_cv_termcap_lib,
-[AC_CHECK_LIB(ncurses, tgetent, mysql_cv_termcap_lib=libncurses,
- [AC_CHECK_LIB(curses, tgetent, mysql_cv_termcap_lib=libcurses,
- [AC_CHECK_LIB(termcap, tgetent, mysql_cv_termcap_lib=libtermcap,
- mysql_cv_termcap_lib=NOT_FOUND)])])])
-AC_MSG_CHECKING(for termcap functions library)
-if test "$mysql_cv_termcap_lib" = "NOT_FOUND"; then
-AC_MSG_ERROR([No curses/termcap library found])
-elif test "$mysql_cv_termcap_lib" = "libtermcap"; then
-TERMCAP_LIB=-ltermcap
-elif test "$mysql_cv_termcap_lib" = "libncurses"; then
-TERMCAP_LIB=-lncurses
-else
-TERMCAP_LIB=-lcurses
-fi
-AC_MSG_RESULT($TERMCAP_LIB)
-])
-
-dnl Check type of signal routines (posix, 4.2bsd, 4.1bsd or v7)
-AC_DEFUN([MYSQL_SIGNAL_CHECK],
-[AC_REQUIRE([AC_TYPE_SIGNAL])
-AC_MSG_CHECKING(for type of signal functions)
-AC_CACHE_VAL(mysql_cv_signal_vintage,
-[
- AC_TRY_LINK([#include <signal.h>],[
- sigset_t ss;
- struct sigaction sa;
- sigemptyset(&ss); sigsuspend(&ss);
- sigaction(SIGINT, &sa, (struct sigaction *) 0);
- sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0);
- ], mysql_cv_signal_vintage=posix,
- [
- AC_TRY_LINK([#include <signal.h>], [
- int mask = sigmask(SIGINT);
- sigsetmask(mask); sigblock(mask); sigpause(mask);
- ], mysql_cv_signal_vintage=4.2bsd,
- [
- AC_TRY_LINK([
- #include <signal.h>
- RETSIGTYPE foo() { }], [
- int mask = sigmask(SIGINT);
- sigset(SIGINT, foo); sigrelse(SIGINT);
- sighold(SIGINT); sigpause(SIGINT);
- ], mysql_cv_signal_vintage=svr3, mysql_cv_signal_vintage=v7
- )]
- )]
-)
-])
-AC_MSG_RESULT($mysql_cv_signal_vintage)
-if test "$mysql_cv_signal_vintage" = posix; then
-AC_DEFINE(HAVE_POSIX_SIGNALS, [1],
- [Signal handling is POSIX (sigset/sighold, etc)])
-elif test "$mysql_cv_signal_vintage" = "4.2bsd"; then
-AC_DEFINE([HAVE_BSD_SIGNALS], [1], [BSD style signals])
-elif test "$mysql_cv_signal_vintage" = svr3; then
-AC_DEFINE(HAVE_USG_SIGHOLD, [1], [sighold() is present and usable])
-fi
-])
-
-AC_DEFUN([MYSQL_CHECK_GETPW_FUNCS],
-[AC_MSG_CHECKING(whether programs are able to redeclare getpw functions)
-AC_CACHE_VAL(mysql_cv_can_redecl_getpw,
-[AC_TRY_COMPILE([#include <sys/types.h>
-#include <pwd.h>
-extern struct passwd *getpwent();], [struct passwd *z; z = getpwent();],
- mysql_cv_can_redecl_getpw=yes,mysql_cv_can_redecl_getpw=no)])
-AC_MSG_RESULT($mysql_cv_can_redecl_getpw)
-if test "$mysql_cv_can_redecl_getpw" = "no"; then
-AC_DEFINE(HAVE_GETPW_DECLS, [1], [getpwent() declaration present])
-fi
-])
-
-AC_DEFUN([MYSQL_HAVE_TIOCGWINSZ],
-[AC_MSG_CHECKING(for TIOCGWINSZ in sys/ioctl.h)
-AC_CACHE_VAL(mysql_cv_tiocgwinsz_in_ioctl,
-[AC_TRY_COMPILE([#include <sys/types.h>
-#include <sys/ioctl.h>], [int x = TIOCGWINSZ;],
- mysql_cv_tiocgwinsz_in_ioctl=yes,mysql_cv_tiocgwinsz_in_ioctl=no)])
-AC_MSG_RESULT($mysql_cv_tiocgwinsz_in_ioctl)
-if test "$mysql_cv_tiocgwinsz_in_ioctl" = "yes"; then
-AC_DEFINE([GWINSZ_IN_SYS_IOCTL], [1],
- [READLINE: your system defines TIOCGWINSZ in sys/ioctl.h.])
-fi
-])
-
-AC_DEFUN([MYSQL_HAVE_FIONREAD],
-[AC_MSG_CHECKING(for FIONREAD in sys/ioctl.h)
-AC_CACHE_VAL(mysql_cv_fionread_in_ioctl,
-[AC_TRY_COMPILE([#include <sys/types.h>
-#include <sys/ioctl.h>], [int x = FIONREAD;],
- mysql_cv_fionread_in_ioctl=yes,mysql_cv_fionread_in_ioctl=no)])
-AC_MSG_RESULT($mysql_cv_fionread_in_ioctl)
-if test "$mysql_cv_fionread_in_ioctl" = "yes"; then
-AC_DEFINE([FIONREAD_IN_SYS_IOCTL], [1], [Do we have FIONREAD])
-fi
-])
-
-AC_DEFUN([MYSQL_HAVE_TIOCSTAT],
-[AC_MSG_CHECKING(for TIOCSTAT in sys/ioctl.h)
-AC_CACHE_VAL(mysql_cv_tiocstat_in_ioctl,
-[AC_TRY_COMPILE([#include <sys/types.h>
-#include <sys/ioctl.h>], [int x = TIOCSTAT;],
- mysql_cv_tiocstat_in_ioctl=yes,mysql_cv_tiocstat_in_ioctl=no)])
-AC_MSG_RESULT($mysql_cv_tiocstat_in_ioctl)
-if test "$mysql_cv_tiocstat_in_ioctl" = "yes"; then
-AC_DEFINE(TIOCSTAT_IN_SYS_IOCTL, [1],
- [declaration of TIOCSTAT in sys/ioctl.h])
-fi
-])
-
-AC_DEFUN([MYSQL_STRUCT_DIRENT_D_INO],
-[AC_REQUIRE([AC_HEADER_DIRENT])
-AC_MSG_CHECKING(if struct dirent has a d_ino member)
-AC_CACHE_VAL(mysql_cv_dirent_has_dino,
-[AC_TRY_COMPILE([
-#include <stdio.h>
-#include <sys/types.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if defined(HAVE_DIRENT_H)
-# include <dirent.h>
-#else
-# define dirent direct
-# ifdef HAVE_SYS_NDIR_H
-# include <sys/ndir.h>
-# endif /* SYSNDIR */
-# ifdef HAVE_SYS_DIR_H
-# include <sys/dir.h>
-# endif /* SYSDIR */
-# ifdef HAVE_NDIR_H
-# include <ndir.h>
-# endif
-#endif /* HAVE_DIRENT_H */
-],[
-struct dirent d; int z; z = d.d_ino;
-], mysql_cv_dirent_has_dino=yes, mysql_cv_dirent_has_dino=no)])
-AC_MSG_RESULT($mysql_cv_dirent_has_dino)
-if test "$mysql_cv_dirent_has_dino" = "yes"; then
-AC_DEFINE(STRUCT_DIRENT_HAS_D_INO, [1],
- [d_ino member present in struct dirent])
-fi
-])
-
-AC_DEFUN([MYSQL_STRUCT_DIRENT_D_NAMLEN],
-[AC_REQUIRE([AC_HEADER_DIRENT])
-AC_MSG_CHECKING(if struct dirent has a d_namlen member)
-AC_CACHE_VAL(mysql_cv_dirent_has_dnamlen,
-[AC_TRY_COMPILE([
-#include <stdio.h>
-#include <sys/types.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#if defined(HAVE_DIRENT_H)
-# include <dirent.h>
-#else
-# define dirent direct
-# ifdef HAVE_SYS_NDIR_H
-# include <sys/ndir.h>
-# endif /* SYSNDIR */
-# ifdef HAVE_SYS_DIR_H
-# include <sys/dir.h>
-# endif /* SYSDIR */
-# ifdef HAVE_NDIR_H
-# include <ndir.h>
-# endif
-#endif /* HAVE_DIRENT_H */
-],[
-struct dirent d; int z; z = (int)d.d_namlen;
-], mysql_cv_dirent_has_dnamlen=yes, mysql_cv_dirent_has_dnamlen=no)])
-AC_MSG_RESULT($mysql_cv_dirent_has_dnamlen)
-if test "$mysql_cv_dirent_has_dnamlen" = "yes"; then
-AC_DEFINE(STRUCT_DIRENT_HAS_D_NAMLEN, [1],
- [d_namlen member present in struct dirent])
-fi
-])
-
-
-AC_DEFUN([MYSQL_TYPE_SIGHANDLER],
-[AC_MSG_CHECKING([whether signal handlers are of type void])
-AC_CACHE_VAL(mysql_cv_void_sighandler,
-[AC_TRY_COMPILE([#include <sys/types.h>
-#include <signal.h>
-#ifdef signal
-#undef signal
-#endif
-#ifdef __cplusplus
-extern "C"
-#endif
-void (*signal ()) ();],
-[int i;], mysql_cv_void_sighandler=yes, mysql_cv_void_sighandler=no)])dnl
-AC_MSG_RESULT($mysql_cv_void_sighandler)
-if test "$mysql_cv_void_sighandler" = "yes"; then
-AC_DEFINE(VOID_SIGHANDLER, [1], [sighandler type is void (*signal ()) ();])
-fi
-])
-
-AC_DEFUN([MYSQL_CXX_BOOL],
-[
-AC_REQUIRE([AC_PROG_CXX])
-AC_MSG_CHECKING(if ${CXX} supports bool types)
-AC_CACHE_VAL(mysql_cv_have_bool,
-[
-AC_LANG_SAVE
-AC_LANG_CPLUSPLUS
-AC_TRY_COMPILE(,[bool b = true;],
-mysql_cv_have_bool=yes,
-mysql_cv_have_bool=no)
-AC_LANG_RESTORE
-])
-AC_MSG_RESULT($mysql_cv_have_bool)
-if test "$mysql_cv_have_bool" = yes; then
-AC_DEFINE([HAVE_BOOL], [1], [bool is not defined by all C++ compilators])
-fi
-])dnl
-
-AC_DEFUN([MYSQL_STACK_DIRECTION],
- [AC_CACHE_CHECK(stack direction for C alloca, ac_cv_c_stack_direction,
- [AC_TRY_RUN([#include <stdlib.h>
- int find_stack_direction ()
- {
- static char *addr = 0;
- auto char dummy;
- if (addr == 0)
- {
- addr = &dummy;
- return find_stack_direction ();
- }
- else
- return (&dummy > addr) ? 1 : -1;
- }
- int main ()
- {
- exit (find_stack_direction() < 0);
- }], ac_cv_c_stack_direction=1, ac_cv_c_stack_direction=-1,
- ac_cv_c_stack_direction=0)])
- AC_DEFINE_UNQUOTED(STACK_DIRECTION, $ac_cv_c_stack_direction)
-])dnl
-
-AC_DEFUN([MYSQL_FUNC_ALLOCA],
-[
-# Since we have heard that alloca fails on IRIX never define it on a
-# SGI machine
-if test ! "$host_vendor" = "sgi"
-then
- AC_REQUIRE_CPP()dnl Set CPP; we run AC_EGREP_CPP conditionally.
- # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
- # for constant arguments. Useless!
- AC_CACHE_CHECK([for working alloca.h], ac_cv_header_alloca_h,
- [AC_TRY_LINK([#include <alloca.h>], [char *p = alloca(2 * sizeof(int));],
- ac_cv_header_alloca_h=yes, ac_cv_header_alloca_h=no)])
- if test "$ac_cv_header_alloca_h" = "yes"
- then
- AC_DEFINE(HAVE_ALLOCA, 1)
- fi
-
- AC_CACHE_CHECK([for alloca], ac_cv_func_alloca_works,
- [AC_TRY_LINK([
- #ifdef __GNUC__
- # define alloca __builtin_alloca
- #else
- # if HAVE_ALLOCA_H
- # include <alloca.h>
- # else
- # ifdef _AIX
- #pragma alloca
- # else
- # ifndef alloca /* predefined by HP cc +Olibcalls */
- char *alloca ();
- # endif
- # endif
- # endif
- #endif
- ], [char *p = (char *) alloca(1);],
- ac_cv_func_alloca_works=yes, ac_cv_func_alloca_works=no)])
- if test "$ac_cv_func_alloca_works" = "yes"; then
- AC_DEFINE([HAVE_ALLOCA], [1], [If we have a working alloca() implementation])
- fi
-
- if test "$ac_cv_func_alloca_works" = "no"; then
- # The SVR3 libPW and SVR4 libucb both contain incompatible functions
- # that cause trouble. Some versions do not even contain alloca or
- # contain a buggy version. If you still want to use their alloca,
- # use ar to extract alloca.o from them instead of compiling alloca.c.
- ALLOCA=alloca.o
- AC_DEFINE(C_ALLOCA, 1)
-
- AC_CACHE_CHECK(whether alloca needs Cray hooks, ac_cv_os_cray,
- [AC_EGREP_CPP(webecray,
- [#if defined(CRAY) && ! defined(CRAY2)
- webecray
- #else
- wenotbecray
- #endif
- ], ac_cv_os_cray=yes, ac_cv_os_cray=no)])
- if test "$ac_cv_os_cray" = "yes"; then
- for ac_func in _getb67 GETB67 getb67; do
- AC_CHECK_FUNC($ac_func, [AC_DEFINE_UNQUOTED(CRAY_STACKSEG_END, $ac_func)
- break])
- done
- fi
- fi
- AC_SUBST(ALLOCA)dnl
-else
- AC_MSG_RESULT("Skipped alloca tests")
-fi
-])
-
-AC_DEFUN([MYSQL_CHECK_LONGLONG_TO_FLOAT],
-[
-AC_MSG_CHECKING(if conversion of longlong to float works)
-AC_CACHE_VAL(ac_cv_conv_longlong_to_float,
-[AC_TRY_RUN([#include <stdio.h>
-typedef long long longlong;
-main()
-{
- longlong ll=1;
- float f;
- FILE *file=fopen("conftestval", "w");
- f = (float) ll;
- fprintf(file,"%g\n",f);
- fclose(file);
- exit (0);
-}], ac_cv_conv_longlong_to_float=`cat conftestval`, ac_cv_conv_longlong_to_float=0, ifelse([$2], , , ac_cv_conv_longlong_to_float=$2))])dnl
-if test "$ac_cv_conv_longlong_to_float" = "1" -o "$ac_cv_conv_longlong_to_float" = "yes"
-then
- ac_cv_conv_longlong_to_float=yes
-else
- ac_cv_conv_longlong_to_float=no
-fi
-AC_MSG_RESULT($ac_cv_conv_longlong_to_float)
-])
-
-AC_DEFUN([MYSQL_CHECK_CPU],
-[AC_CACHE_CHECK([if compiler supports optimizations for current cpu],
-mysql_cv_cpu,[
-
-ac_save_CFLAGS="$CFLAGS"
-if test -r /proc/cpuinfo ; then
- cpuinfo="cat /proc/cpuinfo"
- cpu_family=`$cpuinfo | grep 'cpu family' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1`
- cpu_vendor=`$cpuinfo | grep 'vendor_id' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1`
-fi
-if test "$cpu_vendor" = "AuthenticAMD"; then
- if test $cpu_family -ge 6; then
- cpu_set="athlon pentiumpro k5 pentium i486 i386";
- elif test $cpu_family -eq 5; then
- cpu_set="k5 pentium i486 i386";
- elif test $cpu_family -eq 4; then
- cpu_set="i486 i386"
- else
- cpu_set="i386"
- fi
-elif test "$cpu_vendor" = "GenuineIntel"; then
- if test $cpu_family -ge 6; then
- cpu_set="pentiumpro pentium i486 i386";
- elif test $cpu_family -eq 5; then
- cpu_set="pentium i486 i386";
- elif test $cpu_family -eq 4; then
- cpu_set="i486 i386"
- else
- cpu_set="i386"
- fi
-fi
-
-for ac_arg in $cpu_set;
-do
- CFLAGS="$ac_save_CFLAGS -mcpu=$ac_arg -march=$ac_arg -DCPU=$ac_arg"
- AC_TRY_COMPILE([],[int i],mysql_cv_cpu=$ac_arg; break;, mysql_cv_cpu="unknown")
-done
-
-if test "$mysql_cv_cpu" = "unknown"
-then
- CFLAGS="$ac_save_CFLAGS"
- AC_MSG_RESULT(none)
-else
- AC_MSG_RESULT($mysql_cv_cpu)
-fi
-]]))
-
-AC_DEFUN([MYSQL_CHECK_VIO], [
- AC_ARG_WITH([vio],
- [ --with-vio Include the Virtual IO support],
- [vio="$withval"],
- [vio=no])
-
- if test "$vio" = "yes"
- then
- vio_dir="vio"
- vio_libs="../vio/libvio.la"
- AC_DEFINE(HAVE_VIO, 1)
- else
- vio_dir=""
- vio_libs=""
- fi
- AC_SUBST([vio_dir])
- AC_SUBST([vio_libs])
-])
-
-AC_DEFUN([MYSQL_FIND_OPENSSL], [
- incs="$1"
- libs="$2"
- case "$incs---$libs" in
- ---)
- for d in /usr/ssl/include /usr/local/ssl/include /usr/include \
-/usr/include/ssl /opt/ssl/include /opt/openssl/include \
-/usr/local/ssl/include /usr/local/include /usr/freeware/include ; do
- if test -f $d/openssl/ssl.h ; then
- OPENSSL_INCLUDE=-I$d
- fi
- done
-
- for d in /usr/ssl/lib /usr/local/ssl/lib /usr/lib/openssl \
-/usr/lib /usr/lib64 /opt/ssl/lib /opt/openssl/lib \
-/usr/freeware/lib32 /usr/local/lib/ ; do
- if test -f $d/libssl.a || test -f $d/libssl.so || test -f $d/libssl.dylib ; then
- OPENSSL_LIB=$d
- fi
- done
- ;;
- ---* | *---)
- AC_MSG_ERROR([if either 'includes' or 'libs' is specified, both must be specified])
- ;;
- * )
- if test -f $incs/openssl/ssl.h ; then
- OPENSSL_INCLUDE=-I$incs
- fi
- if test -f $libs/libssl.a || test -f $libs/libssl.so || test -f $libs/libssl.dylib ; then
- OPENSSL_LIB=$libs
- fi
- ;;
- esac
-
- # On RedHat 9 we need kerberos to compile openssl
- for d in /usr/kerberos/include
- do
- if test -f $d/krb5.h ; then
- OPENSSL_KERBEROS_INCLUDE="$d"
- fi
- done
-
-
- if test -z "$OPENSSL_LIB" -o -z "$OPENSSL_INCLUDE" ; then
- echo "Could not find an installation of OpenSSL"
- if test -n "$OPENSSL_LIB" ; then
- if test "$TARGET_LINUX" = "true"; then
- echo "Looks like you've forgotten to install OpenSSL development RPM"
- fi
- fi
- exit 1
- fi
-
-])
-
-AC_DEFUN([MYSQL_CHECK_OPENSSL], [
-AC_MSG_CHECKING(for OpenSSL)
- AC_ARG_WITH([openssl],
- [ --with-openssl[=DIR] Include the OpenSSL support],
- [openssl="$withval"],
- [openssl=no])
-
- AC_ARG_WITH([openssl-includes],
- [
- --with-openssl-includes=DIR
- Find OpenSSL headers in DIR],
- [openssl_includes="$withval"],
- [openssl_includes=""])
-
- AC_ARG_WITH([openssl-libs],
- [
- --with-openssl-libs=DIR
- Find OpenSSL libraries in DIR],
- [openssl_libs="$withval"],
- [openssl_libs=""])
-
- if test "$openssl" != "no"
- then
- if test "$openssl" != "yes"
- then
- if test -z "$openssl_includes"
- then
- openssl_includes="$openssl/include"
- fi
- if test -z "$openssl_libs"
- then
- openssl_libs="$openssl/lib"
- fi
- fi
- MYSQL_FIND_OPENSSL([$openssl_includes], [$openssl_libs])
- #force VIO use
- vio_dir="vio"
- vio_libs="../vio/libvio.la"
- AC_DEFINE([HAVE_VIO], [1], [Virtual IO])
- AC_MSG_RESULT(yes)
- openssl_libs="-L$OPENSSL_LIB -lssl -lcrypto"
- # Don't set openssl_includes to /usr/include as this gives us a lot of
- # compiler warnings when using gcc 3.x
- openssl_includes=""
- if test "$OPENSSL_INCLUDE" != "-I/usr/include"
- then
- openssl_includes="$OPENSSL_INCLUDE"
- fi
- if test "$OPENSSL_KERBEROS_INCLUDE"
- then
- openssl_includes="$openssl_includes -I$OPENSSL_KERBEROS_INCLUDE"
- fi
- AC_DEFINE([HAVE_OPENSSL], [1], [OpenSSL])
-
- # openssl-devel-0.9.6 requires dlopen() and we can't link staticly
- # on many platforms (We should actually test this here, but it's quite
- # hard) to do as we are doing libtool for linking.
- using_static=""
- case "$CLIENT_EXTRA_LDFLAGS $MYSQLD_EXTRA_LDFLAGS" in
- *-all-static*) using_static="yes" ;;
- esac
- if test "$using_static" = "yes"
- then
- echo "You can't use the --all-static link option when using openssl."
- exit 1
- fi
- else
- AC_MSG_RESULT(no)
- if test ! -z "$openssl_includes"
- then
- AC_MSG_ERROR(Can't have --with-openssl-includes without --with-openssl);
- fi
- if test ! -z "$openssl_libs"
- then
- AC_MSG_ERROR(Can't have --with-openssl-libs without --with-openssl);
- fi
- fi
- AC_SUBST(openssl_libs)
- AC_SUBST(openssl_includes)
-])
-
-
-dnl ---------------------------------------------------------------------------
-dnl Macro: MYSQL_CHECK_BIG_TABLES
-dnl Sets BIG_TABLES if --with-big-tables is used
-dnl ---------------------------------------------------------------------------
-AC_DEFUN([MYSQL_CHECK_BIG_TABLES], [
- AC_ARG_WITH([big-tables],
- [
- --with-big-tables Support tables with more than 4 G rows even on 32 bit platforms],
- [bigtables="$withval"],
- [bigtables=no])
- AC_MSG_CHECKING([for big tables support])
-
- case "$bigtables" in
- yes )
- AC_DEFINE([BIG_TABLES], [1], [Support big tables])
- AC_MSG_RESULT([yes])
- ;;
- * )
- AC_MSG_RESULT([no])
- ;;
- esac
-
-])
-dnl ---------------------------------------------------------------------------
-dnl END OF MYSQL_CHECK_BIG_TABLES SECTION
-dnl ---------------------------------------------------------------------------
-
-
-AC_DEFUN([MYSQL_CHECK_MYSQLFS], [
- AC_ARG_WITH([mysqlfs],
- [
- --with-mysqlfs Include the corba-based MySQL file system],
- [mysqlfs="$withval"],
- [mysqlfs=no])
-
-dnl Call MYSQL_CHECK_ORBIT even if mysqlfs == no, so that @orbit_*@
-dnl get substituted.
- MYSQL_CHECK_ORBIT
-
- AC_MSG_CHECKING(if we should build MySQLFS)
- fs_dirs=""
- if test "$mysqlfs" = "yes"
- then
- if test -n "$orbit_exec_prefix"
- then
- fs_dirs=fs
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT(disabled because ORBIT, the CORBA ORB, was not found)
- fi
- else
- AC_MSG_RESULT([no])
- fi
- AC_SUBST([fs_dirs])
-])
-
-AC_DEFUN([MYSQL_CHECK_ORBIT], [
-AC_MSG_CHECKING(for ORBit)
-orbit_config_path=`which orbit-config`
-if test -n "$orbit_config_path" -a $? = 0
-then
- orbit_exec_prefix=`orbit-config --exec-prefix`
- orbit_includes=`orbit-config --cflags server`
- orbit_libs=`orbit-config --libs server`
- orbit_idl="$orbit_exec_prefix/bin/orbit-idl"
- AC_MSG_RESULT(found!)
- AC_DEFINE([HAVE_ORBIT], [1], [ORBIT])
-else
- orbit_exec_prefix=
- orbit_includes=
- orbit_libs=
- orbit_idl=
- AC_MSG_RESULT(not found)
-fi
-AC_SUBST(orbit_includes)
-AC_SUBST(orbit_libs)
-AC_SUBST(orbit_idl)
-])
-
-AC_DEFUN([MYSQL_CHECK_ISAM], [
- AC_ARG_WITH([isam], [
- --with-isam Enable the ISAM table type],
- [with_isam="$withval"],
- [with_isam=no])
-
- isam_libs=
- if test X"$with_isam" = X"yes"
- then
- AC_DEFINE([HAVE_ISAM], [1], [Using old ISAM tables])
- isam_libs="\$(top_builddir)/isam/libnisam.a\
- \$(top_builddir)/merge/libmerge.a"
- fi
- AC_SUBST(isam_libs)
-])
-
-
-dnl ---------------------------------------------------------------------------
-dnl Macro: MYSQL_CHECK_BDB
-dnl Sets HAVE_BERKELEY_DB if inst library is found
-dnl Makes sure db version is correct.
-dnl Looks in $srcdir for Berkeley distribution if not told otherwise
-dnl ---------------------------------------------------------------------------
-
-AC_DEFUN([MYSQL_CHECK_BDB], [
- AC_ARG_WITH([berkeley-db],
- [
- --with-berkeley-db[=DIR]
- Use BerkeleyDB located in DIR],
- [bdb="$withval"],
- [bdb=no])
-
- AC_ARG_WITH([berkeley-db-includes],
- [
- --with-berkeley-db-includes=DIR
- Find Berkeley DB headers in DIR],
- [bdb_includes="$withval"],
- [bdb_includes=default])
-
- AC_ARG_WITH([berkeley-db-libs],
- [
- --with-berkeley-db-libs=DIR
- Find Berkeley DB libraries in DIR],
- [bdb_libs="$withval"],
- [bdb_libs=default])
-
- AC_MSG_CHECKING([for BerkeleyDB])
-
-dnl SORT OUT THE SUPPLIED ARGUMENTS TO DETERMINE WHAT TO DO
-dnl echo "DBG1: bdb='$bdb'; incl='$bdb_includes'; lib='$bdb_libs'"
- have_berkeley_db=no
- case "$bdb" in
- no )
- mode=no
- AC_MSG_RESULT([no])
- ;;
- yes | default )
- case "$bdb_includes---$bdb_libs" in
- default---default )
- mode=search-$bdb
- AC_MSG_RESULT([searching...])
- ;;
- default---* | *---default | yes---* | *---yes )
- AC_MSG_ERROR([if either 'includes' or 'libs' is specified, both must be specified])
- ;;
- * )
- mode=supplied-two
- AC_MSG_RESULT([supplied])
- ;;
- esac
- ;;
- * )
- mode=supplied-one
- AC_MSG_RESULT([supplied])
- ;;
- esac
-
-dnl echo "DBG2: [$mode] bdb='$bdb'; incl='$bdb_includes'; lib='$bdb_libs'"
-
- case $mode in
- no )
- bdb_includes=
- bdb_libs=
- bdb_libs_with_path=
- ;;
- supplied-two )
- MYSQL_CHECK_INSTALLED_BDB([$bdb_includes], [$bdb_libs])
- case $bdb_dir_ok in
- installed ) mode=yes ;;
- * ) AC_MSG_ERROR([didn't find valid BerkeleyDB: $bdb_dir_ok]) ;;
- esac
- ;;
- supplied-one )
- MYSQL_CHECK_BDB_DIR([$bdb])
- case $bdb_dir_ok in
- source ) mode=compile ;;
- installed ) mode=yes ;;
- * ) AC_MSG_ERROR([didn't find valid BerkeleyDB: $bdb_dir_ok]) ;;
- esac
- ;;
- search-* )
- MYSQL_SEARCH_FOR_BDB
- case $bdb_dir_ok in
- source ) mode=compile ;;
- installed ) mode=yes ;;
- * )
- # not found
- case $mode in
- *-yes ) AC_MSG_ERROR([no suitable BerkeleyDB found]) ;;
- * ) mode=no ;;
- esac
- bdb_includes=
- bdb_libs=
- bdb_libs_with_path=
- ;;
- esac
- ;;
- *)
- AC_MSG_ERROR([impossible case condition '$mode': please report this to bugs@lists.mysql.com])
- ;;
- esac
-
-dnl echo "DBG3: [$mode] bdb='$bdb'; incl='$bdb_includes'; lib='$bdb_libs'"
- case $mode in
- no )
- AC_MSG_RESULT([Not using Berkeley DB])
- ;;
- yes )
- have_berkeley_db="yes"
- AC_MSG_RESULT([Using Berkeley DB in '$bdb_includes'])
- ;;
- compile )
- have_berkeley_db="$bdb"
- AC_MSG_RESULT([Compiling Berekeley DB in '$have_berkeley_db'])
- ;;
- * )
- AC_MSG_ERROR([impossible case condition '$mode': please report this to bugs@lists.mysql.com])
- ;;
- esac
-
- AC_SUBST(bdb_includes)
- AC_SUBST(bdb_libs)
- AC_SUBST(bdb_libs_with_path)
-])
-
-AC_DEFUN([MYSQL_CHECK_INSTALLED_BDB], [
-dnl echo ["MYSQL_CHECK_INSTALLED_BDB ($1) ($2)"]
- inc="$1"
- lib="$2"
- if test -f "$inc/db.h"
- then
- MYSQL_CHECK_BDB_VERSION([$inc/db.h],
- [.*#define[ ]*], [[ ][ ]*])
-
- if test X"$bdb_version_ok" = Xyes; then
- save_LDFLAGS="$LDFLAGS"
- LDFLAGS="-L$lib $LDFLAGS"
- AC_CHECK_LIB(db,db_env_create, [
- bdb_dir_ok=installed
- MYSQL_TOP_BUILDDIR([inc])
- MYSQL_TOP_BUILDDIR([lib])
- bdb_includes="-I$inc"
- bdb_libs="-L$lib -ldb"
- bdb_libs_with_path="$lib/libdb.a"
- ])
- LDFLAGS="$save_LDFLAGS"
- else
- bdb_dir_ok="$bdb_version_ok"
- fi
- else
- bdb_dir_ok="no db.h file in '$inc'"
- fi
-])
-
-AC_DEFUN([MYSQL_CHECK_BDB_DIR], [
-dnl ([$bdb])
-dnl echo ["MYSQL_CHECK_BDB_DIR ($1)"]
- dir="$1"
-
- MYSQL_CHECK_INSTALLED_BDB([$dir/include], [$dir/lib])
-
- if test X"$bdb_dir_ok" != Xinstalled; then
- # test to see if it's a source dir
- rel="$dir/dist/RELEASE"
- if test -f "$rel"; then
- MYSQL_CHECK_BDB_VERSION([$rel], [], [=])
- if test X"$bdb_version_ok" = Xyes; then
- bdb_dir_ok=source
- bdb="$dir"
- MYSQL_TOP_BUILDDIR([dir])
- bdb_includes="-I$dir/build_unix"
- bdb_libs="-L$dir/build_unix -ldb"
- bdb_libs_with_path="$dir/build_unix/libdb.a"
- else
- bdb_dir_ok="$bdb_version_ok"
- fi
- else
- bdb_dir_ok="'$dir' doesn't look like a BDB directory ($bdb_dir_ok)"
- fi
- fi
-])
-
-AC_DEFUN([MYSQL_SEARCH_FOR_BDB], [
-dnl echo ["MYSQL_SEARCH_FOR_BDB"]
- bdb_dir_ok="no BerkeleyDB found"
-
- for test_dir in $srcdir/bdb $srcdir/db-*.*.* /usr/local/BerkeleyDB*; do
-dnl echo "-----------> Looking at ($test_dir; `cd $test_dir && pwd`)"
- MYSQL_CHECK_BDB_DIR([$test_dir])
- if test X"$bdb_dir_ok" = Xsource || test X"$bdb_dir_ok" = Xinstalled; then
-dnl echo "-----------> Found it ($bdb), ($srcdir)"
-dnl This is needed so that 'make distcheck' works properly (VPATH build).
-dnl VPATH build won't work if bdb is not under the source tree; but in
-dnl that case, hopefully people will just make and install inside the
-dnl tree, or install BDB first, and then use the installed version.
- case "$bdb" in
- "$srcdir/"* ) bdb=`echo "$bdb" | sed -e "s,^$srcdir/,,"` ;;
- esac
- break
- fi
- done
-])
-
-dnl MYSQL_CHECK_BDB_VERSION takes 3 arguments:
-dnl 1) the file to look in
-dnl 2) the search pattern before DB_VERSION_XXX
-dnl 3) the search pattern between DB_VERSION_XXX and the number
-dnl It assumes that the number is the last thing on the line
-AC_DEFUN([MYSQL_CHECK_BDB_VERSION], [
- db_major=`sed -e '/^[$2]DB_VERSION_MAJOR[$3]/ !d' -e 's///' [$1]`
- db_minor=`sed -e '/^[$2]DB_VERSION_MINOR[$3]/ !d' -e 's///' [$1]`
- db_patch=`sed -e '/^[$2]DB_VERSION_PATCH[$3]/ !d' -e 's///' [$1]`
- test -z "$db_major" && db_major=0
- test -z "$db_minor" && db_minor=0
- test -z "$db_patch" && db_patch=0
-
- # This is ugly, but about as good as it can get
-# mysql_bdb=
-# if test $db_major -eq 3 && test $db_minor -eq 2 && test $db_patch -eq 3
-# then
-# mysql_bdb=h
-# elif test $db_major -eq 3 && test $db_minor -eq 2 && test $db_patch -eq 9
-# then
-# want_bdb_version="3.2.9a" # hopefully this will stay up-to-date
-# mysql_bdb=a
-# fi
-
-dnl RAM:
-want_bdb_version="4.1.24"
-bdb_version_ok=yes
-
-# if test -n "$mysql_bdb" && \
-# grep "DB_VERSION_STRING.*:.*$mysql_bdb: " [$1] > /dev/null
-# then
-# bdb_version_ok=yes
-# else
-# bdb_version_ok="invalid version $db_major.$db_minor.$db_patch"
-# bdb_version_ok="$bdb_version_ok (must be version 3.2.3h or $want_bdb_version)"
-# fi
-])
-
-AC_DEFUN([MYSQL_TOP_BUILDDIR], [
- case "$[$1]" in
- /* ) ;; # don't do anything with an absolute path
- "$srcdir"/* )
- # If BDB is under the source directory, we need to look under the
- # build directory for bdb/build_unix.
- # NOTE: I'm being lazy, and assuming the user did not specify
- # something like --with-berkeley-db=bdb (it would be missing "./").
- [$1]="\$(top_builddir)/"`echo "$[$1]" | sed -e "s,^$srcdir/,,"`
- ;;
- * )
- AC_MSG_ERROR([The BDB directory must be directly under the MySQL source directory, or be specified using the full path. ('$srcdir'; '$[$1]')])
- ;;
- esac
- if test X"$[$1]" != "/"
- then
- [$1]=`echo $[$1] | sed -e 's,/$,,'`
- fi
-])
-
-dnl ---------------------------------------------------------------------------
-dnl END OF MYSQL_CHECK_BDB SECTION
-dnl ---------------------------------------------------------------------------
-
-dnl ---------------------------------------------------------------------------
-dnl Macro: MYSQL_CHECK_INNODB
-dnl Sets HAVE_INNOBASE_DB if --with-innodb is used
-dnl ---------------------------------------------------------------------------
-
-AC_DEFUN([MYSQL_CHECK_INNODB], [
- AC_ARG_WITH([innodb],
- [
- --without-innodb Do not include the InnoDB table handler],
- [innodb="$withval"],
- [innodb=yes])
-
- AC_MSG_CHECKING([for Innodb])
-
- have_innodb=no
- innodb_includes=
- innodb_libs=
- case "$innodb" in
- yes )
- AC_MSG_RESULT([Using Innodb])
- AC_DEFINE([HAVE_INNOBASE_DB], [1], [Using Innobase DB])
- have_innodb="yes"
- innodb_includes="-I../innobase/include"
- innodb_system_libs=""
-dnl Some libs are listed several times, in order for gcc to sort out
-dnl circular references.
- innodb_libs="\
- \$(top_builddir)/innobase/usr/libusr.a\
- \$(top_builddir)/innobase/srv/libsrv.a\
- \$(top_builddir)/innobase/dict/libdict.a\
- \$(top_builddir)/innobase/que/libque.a\
- \$(top_builddir)/innobase/srv/libsrv.a\
- \$(top_builddir)/innobase/ibuf/libibuf.a\
- \$(top_builddir)/innobase/row/librow.a\
- \$(top_builddir)/innobase/pars/libpars.a\
- \$(top_builddir)/innobase/btr/libbtr.a\
- \$(top_builddir)/innobase/trx/libtrx.a\
- \$(top_builddir)/innobase/read/libread.a\
- \$(top_builddir)/innobase/usr/libusr.a\
- \$(top_builddir)/innobase/buf/libbuf.a\
- \$(top_builddir)/innobase/ibuf/libibuf.a\
- \$(top_builddir)/innobase/eval/libeval.a\
- \$(top_builddir)/innobase/log/liblog.a\
- \$(top_builddir)/innobase/fsp/libfsp.a\
- \$(top_builddir)/innobase/fut/libfut.a\
- \$(top_builddir)/innobase/fil/libfil.a\
- \$(top_builddir)/innobase/lock/liblock.a\
- \$(top_builddir)/innobase/mtr/libmtr.a\
- \$(top_builddir)/innobase/page/libpage.a\
- \$(top_builddir)/innobase/rem/librem.a\
- \$(top_builddir)/innobase/thr/libthr.a\
- \$(top_builddir)/innobase/sync/libsync.a\
- \$(top_builddir)/innobase/data/libdata.a\
- \$(top_builddir)/innobase/mach/libmach.a\
- \$(top_builddir)/innobase/ha/libha.a\
- \$(top_builddir)/innobase/dyn/libdyn.a\
- \$(top_builddir)/innobase/mem/libmem.a\
- \$(top_builddir)/innobase/sync/libsync.a\
- \$(top_builddir)/innobase/ut/libut.a\
- \$(top_builddir)/innobase/os/libos.a\
- \$(top_builddir)/innobase/ut/libut.a"
-
- AC_CHECK_LIB(rt, aio_read, [innodb_system_libs="-lrt"])
- ;;
- * )
- AC_MSG_RESULT([Not using Innodb])
- ;;
- esac
-
- AC_SUBST(innodb_includes)
- AC_SUBST(innodb_libs)
- AC_SUBST(innodb_system_libs)
-])
-
-dnl ---------------------------------------------------------------------------
-dnl END OF MYSQL_CHECK_INNODB SECTION
-dnl ---------------------------------------------------------------------------
-
-dnl ---------------------------------------------------------------------------
-dnl Macro: MYSQL_CHECK_EXAMPLEDB
-dnl Sets HAVE_EXAMPLE_DB if --with-example-storage-engine is used
-dnl ---------------------------------------------------------------------------
-AC_DEFUN([MYSQL_CHECK_EXAMPLEDB], [
- AC_ARG_WITH([example-storage-engine],
- [
- --with-example-storage-engine
- Enable the Example Storage Engine],
- [exampledb="$withval"],
- [exampledb=no])
- AC_MSG_CHECKING([for example storage engine])
-
- case "$exampledb" in
- yes )
- AC_DEFINE([HAVE_EXAMPLE_DB], [1], [Builds Example DB])
- AC_MSG_RESULT([yes])
- [exampledb=yes]
- ;;
- * )
- AC_MSG_RESULT([no])
- [exampledb=no]
- ;;
- esac
-
-])
-dnl ---------------------------------------------------------------------------
-dnl END OF MYSQL_CHECK_EXAMPLE SECTION
-dnl ---------------------------------------------------------------------------
-
-dnl ---------------------------------------------------------------------------
-dnl Macro: MYSQL_CHECK_BLACKHOLEDB
-dnl Sets HAVE_BLACKHOLE_DB if --with-blackhole-storage-engine is used
-dnl ---------------------------------------------------------------------------
-AC_DEFUN([MYSQL_CHECK_BLACKHOLEDB], [
- AC_ARG_WITH([blackhole-storage-engine],
- [
- --with-blackhole-storage-engine
- Enable the Blackhole Storage Engine],
- [blackholedb="$withval"],
- [blackholedb=no])
- AC_MSG_CHECKING([for blackhole storage engine])
-
- case "$blackholedb" in
- yes )
- AC_DEFINE([HAVE_BLACKHOLE_DB], [1], [Builds Blackhole Storage Engine])
- AC_MSG_RESULT([yes])
- [blackholedb=yes]
- ;;
- * )
- AC_MSG_RESULT([no])
- [blackholedb=no]
- ;;
- esac
-
-])
-dnl ---------------------------------------------------------------------------
-dnl END OF MYSQL_CHECK_BLACKHOLE SECTION
-dnl ---------------------------------------------------------------------------
-
-dnl ---------------------------------------------------------------------------
-dnl Macro: MYSQL_CHECK_ARCHIVEDB
-dnl Sets HAVE_ARCHIVE_DB if --with-archive-storage-engine is used
-dnl ---------------------------------------------------------------------------
-AC_DEFUN([MYSQL_CHECK_ARCHIVEDB], [
- AC_ARG_WITH([archive-storage-engine],
- [
- --with-archive-storage-engine
- Enable the Archive Storage Engine],
- [archivedb="$withval"],
- [archivedb=no])
- AC_MSG_CHECKING([for archive storage engine])
-
- case "$archivedb" in
- yes )
- AC_DEFINE([HAVE_ARCHIVE_DB], [1], [Builds Archive Storage Engine])
- AC_MSG_RESULT([yes])
- [archivedb=yes]
- ;;
- * )
- AC_MSG_RESULT([no])
- [archivedb=no]
- ;;
- esac
-
-])
-dnl ---------------------------------------------------------------------------
-dnl END OF MYSQL_CHECK_ARCHIVE SECTION
-dnl ---------------------------------------------------------------------------
-
-dnl ---------------------------------------------------------------------------
-dnl Macro: MYSQL_CHECK_CSVDB
-dnl Sets HAVE_CSV_DB if --with-csv-storage-engine is used
-dnl ---------------------------------------------------------------------------
-AC_DEFUN([MYSQL_CHECK_CSVDB], [
- AC_ARG_WITH([csv-storage-engine],
- [
- --with-csv-storage-engine
- Enable the CSV Storage Engine],
- [csvdb="$withval"],
- [csvdb=no])
- AC_MSG_CHECKING([for csv storage engine])
-
- case "$csvdb" in
- yes )
- AC_DEFINE([HAVE_CSV_DB], [1], [Builds the CSV Storage Engine])
- AC_MSG_RESULT([yes])
- [csvdb=yes]
- ;;
- * )
- AC_MSG_RESULT([no])
- [csvdb=no]
- ;;
- esac
-
-])
-dnl ---------------------------------------------------------------------------
-dnl END OF MYSQL_CHECK_CSV SECTION
-dnl ---------------------------------------------------------------------------
-
-
-dnl ---------------------------------------------------------------------------
-dnl Macro: MYSQL_CHECK_NDBCLUSTER
-dnl Sets HAVE_NDBCLUSTER_DB if --with-ndbcluster is used
-dnl ---------------------------------------------------------------------------
-
-AC_DEFUN([MYSQL_CHECK_NDB_OPTIONS], [
- AC_ARG_WITH([ndb-sci],
- AC_HELP_STRING([--with-ndb-sci=DIR],
- [Provide MySQL with a custom location of
- sci library. Given DIR, sci library is
- assumed to be in $DIR/lib and header files
- in $DIR/include.]),
- [mysql_sci_dir=${withval}],
- [mysql_sci_dir=""])
-
- case "$mysql_sci_dir" in
- "no" )
- have_ndb_sci=no
- AC_MSG_RESULT([-- not including sci transporter])
- ;;
- * )
- if test -f "$mysql_sci_dir/lib/libsisci.a" -a \
- -f "$mysql_sci_dir/include/sisci_api.h"; then
- NDB_SCI_INCLUDES="-I$mysql_sci_dir/include"
- NDB_SCI_LIBS="-L$mysql_sci_dir/lib -lsisci"
- AC_MSG_RESULT([-- including sci transporter])
- AC_DEFINE([NDB_SCI_TRANSPORTER], [1],
- [Including Ndb Cluster DB sci transporter])
- AC_SUBST(NDB_SCI_INCLUDES)
- AC_SUBST(NDB_SCI_LIBS)
- have_ndb_sci="yes"
- AC_MSG_RESULT([found sci transporter in $mysql_sci_dir/{include, lib}])
- else
- AC_MSG_RESULT([could not find sci transporter in $mysql_sci_dir/{include, lib}])
- fi
- ;;
- esac
-
- AC_ARG_WITH([ndb-test],
- [
- --with-ndb-test Include the NDB Cluster ndbapi test programs],
- [ndb_test="$withval"],
- [ndb_test=no])
- AC_ARG_WITH([ndb-docs],
- [
- --with-ndb-docs Include the NDB Cluster ndbapi and mgmapi documentation],
- [ndb_docs="$withval"],
- [ndb_docs=no])
- AC_ARG_WITH([ndb-port],
- [
- --with-ndb-port Port for NDB Cluster management server],
- [ndb_port="$withval"],
- [ndb_port="default"])
- AC_ARG_WITH([ndb-port-base],
- [
- --with-ndb-port-base Base port for NDB Cluster transporters],
- [ndb_port_base="$withval"],
- [ndb_port_base="default"])
- AC_ARG_WITH([ndb-debug],
- [
- --without-ndb-debug Disable special ndb debug features],
- [ndb_debug="$withval"],
- [ndb_debug="default"])
- AC_ARG_WITH([ndb-ccflags],
- [
- --with-ndb-ccflags Extra CC options for ndb compile],
- [ndb_cxxflags_fix="$ndb_cxxflags_fix $withval"],
- [ndb_cxxflags_fix=$ndb_cxxflags_fix])
-
- AC_MSG_CHECKING([for NDB Cluster options])
- AC_MSG_RESULT([])
-
- have_ndb_test=no
- case "$ndb_test" in
- yes )
- AC_MSG_RESULT([-- including ndbapi test programs])
- have_ndb_test="yes"
- ;;
- * )
- AC_MSG_RESULT([-- not including ndbapi test programs])
- ;;
- esac
-
- have_ndb_docs=no
- case "$ndb_docs" in
- yes )
- AC_MSG_RESULT([-- including ndbapi and mgmapi documentation])
- have_ndb_docs="yes"
- ;;
- * )
- AC_MSG_RESULT([-- not including ndbapi and mgmapi documentation])
- ;;
- esac
-
- case "$ndb_debug" in
- yes )
- AC_MSG_RESULT([-- including ndb extra debug options])
- have_ndb_debug="yes"
- ;;
- full )
- AC_MSG_RESULT([-- including ndb extra extra debug options])
- have_ndb_debug="full"
- ;;
- no )
- AC_MSG_RESULT([-- not including ndb extra debug options])
- have_ndb_debug="no"
- ;;
- * )
- have_ndb_debug="default"
- ;;
- esac
-
- AC_MSG_RESULT([done.])
-])
-
-AC_DEFUN([MYSQL_CHECK_NDBCLUSTER], [
- AC_ARG_WITH([ndbcluster],
- [
- --with-ndbcluster Include the NDB Cluster table handler],
- [ndbcluster="$withval"],
- [ndbcluster=no])
-
- AC_MSG_CHECKING([for NDB Cluster])
-
- have_ndbcluster=no
- ndbcluster_includes=
- ndbcluster_libs=
- ndb_mgmclient_libs=
- case "$ndbcluster" in
- yes )
- AC_MSG_RESULT([Using NDB Cluster])
- AC_DEFINE([HAVE_NDBCLUSTER_DB], [1], [Using Ndb Cluster DB])
- have_ndbcluster="yes"
- ndbcluster_includes="-I../ndb/include -I../ndb/include/ndbapi"
- ndbcluster_libs="\$(top_builddir)/ndb/src/.libs/libndbclient.a"
- ndbcluster_system_libs=""
- ndb_mgmclient_libs="\$(top_builddir)/ndb/src/mgmclient/libndbmgmclient.la"
- MYSQL_CHECK_NDB_OPTIONS
- ;;
- * )
- AC_MSG_RESULT([Not using NDB Cluster])
- ;;
- esac
-
- AM_CONDITIONAL([HAVE_NDBCLUSTER_DB], [ test "$have_ndbcluster" = "yes" ])
- AC_SUBST(ndbcluster_includes)
- AC_SUBST(ndbcluster_libs)
- AC_SUBST(ndbcluster_system_libs)
- AC_SUBST(ndb_mgmclient_libs)
-])
-
-dnl ---------------------------------------------------------------------------
-dnl END OF MYSQL_CHECK_NDBCLUSTER SECTION
-dnl ---------------------------------------------------------------------------
-
-
-dnl By default, many hosts won't let programs access large files;
-dnl one must use special compiler options to get large-file access to work.
-dnl For more details about this brain damage please see:
-dnl http://www.sas.com/standards/large.file/x_open.20Mar96.html
-
-dnl Written by Paul Eggert <eggert@twinsun.com>.
-
-dnl Internal subroutine of AC_SYS_LARGEFILE.
-dnl AC_SYS_LARGEFILE_FLAGS(FLAGSNAME)
-AC_DEFUN([AC_SYS_LARGEFILE_FLAGS],
- [AC_CACHE_CHECK([for $1 value to request large file support],
- ac_cv_sys_largefile_$1,
- [if ($GETCONF LFS_$1) >conftest.1 2>conftest.2 && test ! -s conftest.2
- then
- ac_cv_sys_largefile_$1=`cat conftest.1`
- else
- ac_cv_sys_largefile_$1=no
- ifelse($1, CFLAGS,
- [case "$host_os" in
- # HP-UX 10.20 requires -D__STDC_EXT__ with gcc 2.95.1.
-changequote(, )dnl
- hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
-changequote([, ])dnl
- if test "$GCC" = yes; then
- case `$CC --version 2>/dev/null` in
- 2.95.*) ac_cv_sys_largefile_CFLAGS=-D__STDC_EXT__ ;;
- esac
- fi
- ;;
- # IRIX 6.2 and later require cc -n32.
-changequote(, )dnl
- irix6.[2-9]* | irix6.1[0-9]* | irix[7-9].* | irix[1-9][0-9]*)
-changequote([, ])dnl
- if test "$GCC" != yes; then
- ac_cv_sys_largefile_CFLAGS=-n32
- fi
- esac
- if test "$ac_cv_sys_largefile_CFLAGS" != no; then
- ac_save_CC="$CC"
- CC="$CC $ac_cv_sys_largefile_CFLAGS"
- AC_TRY_LINK(, , , ac_cv_sys_largefile_CFLAGS=no)
- CC="$ac_save_CC"
- fi])
- fi
- rm -f conftest*])])
-
-dnl Internal subroutine of AC_SYS_LARGEFILE.
-dnl AC_SYS_LARGEFILE_SPACE_APPEND(VAR, VAL)
-AC_DEFUN([AC_SYS_LARGEFILE_SPACE_APPEND],
- [case $2 in
- no) ;;
- ?*)
- case "[$]$1" in
- '') $1=$2 ;;
- *) $1=[$]$1' '$2 ;;
- esac ;;
- esac])
-
-dnl Internal subroutine of AC_SYS_LARGEFILE.
-dnl AC_SYS_LARGEFILE_MACRO_VALUE(C-MACRO, CACHE-VAR, COMMENT, CODE-TO-SET-DEFAULT)
-AC_DEFUN([AC_SYS_LARGEFILE_MACRO_VALUE],
- [AC_CACHE_CHECK([for $1], $2,
- [$2=no
-changequote(, )dnl
- for ac_flag in $ac_cv_sys_largefile_CFLAGS no; do
- case "$ac_flag" in
- -D$1)
- $2=1 ;;
- -D$1=*)
- $2=`expr " $ac_flag" : '[^=]*=\(.*\)'` ;;
- esac
- done
- $4
-changequote([, ])dnl
- ])
- if test "[$]$2" != no; then
- AC_DEFINE_UNQUOTED([$1], [$]$2, [$3])
- fi])
-
-AC_DEFUN([MYSQL_SYS_LARGEFILE],
- [AC_REQUIRE([AC_CANONICAL_HOST])
- AC_ARG_ENABLE(largefile,
- [ --disable-largefile Omit support for large files])
- if test "$enable_largefile" != no; then
- AC_CHECK_TOOL(GETCONF, getconf)
- AC_SYS_LARGEFILE_FLAGS(CFLAGS)
- AC_SYS_LARGEFILE_FLAGS(LDFLAGS)
- AC_SYS_LARGEFILE_FLAGS(LIBS)
-
- for ac_flag in $ac_cv_sys_largefile_CFLAGS no; do
- case "$ac_flag" in
- no) ;;
- -D_FILE_OFFSET_BITS=*) ;;
- -D_LARGEFILE_SOURCE | -D_LARGEFILE_SOURCE=*) ;;
- -D_LARGE_FILES | -D_LARGE_FILES=*) ;;
- -D?* | -I?*)
- AC_SYS_LARGEFILE_SPACE_APPEND(CPPFLAGS, "$ac_flag") ;;
- *)
- AC_SYS_LARGEFILE_SPACE_APPEND(CFLAGS, "$ac_flag") ;;
- esac
- done
- AC_SYS_LARGEFILE_SPACE_APPEND(LDFLAGS, "$ac_cv_sys_largefile_LDFLAGS")
- AC_SYS_LARGEFILE_SPACE_APPEND(LIBS, "$ac_cv_sys_largefile_LIBS")
-
- AC_SYS_LARGEFILE_MACRO_VALUE(_FILE_OFFSET_BITS,
- ac_cv_sys_file_offset_bits,
- [Number of bits in a file offset, on hosts where this is settable.],
- [case "$host_os" in
- # HP-UX 10.20 and later
- hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
- ac_cv_sys_file_offset_bits=64 ;;
- # We can't declare _FILE_OFFSET_BITS here as this will cause
- # compile errors as AC_PROG_CC adds include files in confdefs.h
- # We solve this (until autoconf is fixed) by instead declaring it
- # as define instead
- solaris2.[8,9])
- CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64"
- CXXFLAGS="$CXXFLAGS -D_FILE_OFFSET_BITS=64"
- ac_cv_sys_file_offset_bits=no ;;
- esac])
- AC_SYS_LARGEFILE_MACRO_VALUE(_LARGEFILE_SOURCE,
- ac_cv_sys_largefile_source,
- [makes fseeko etc. visible, on some hosts.],
- [case "$host_os" in
- # HP-UX 10.20 and later
- hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
- ac_cv_sys_largefile_source=1 ;;
- esac])
- AC_SYS_LARGEFILE_MACRO_VALUE(_LARGE_FILES,
- ac_cv_sys_large_files,
- [Large files support on AIX-style hosts.],
- [case "$host_os" in
- # AIX 4.2 and later
- aix4.[2-9]* | aix4.1[0-9]* | aix[5-9].* | aix[1-9][0-9]*)
- ac_cv_sys_large_files=1 ;;
- esac])
- fi
- ])
-
-
-# Local version of _AC_PROG_CXX_EXIT_DECLARATION that does not
-# include #stdlib.h as default as this breaks things on Solaris
-# (Conflicts with pthreads and big file handling)
-
-m4_define([_AC_PROG_CXX_EXIT_DECLARATION],
-[for ac_declaration in \
- ''\
- 'extern "C" void std::exit (int) throw (); using std::exit;' \
- 'extern "C" void std::exit (int); using std::exit;' \
- 'extern "C" void exit (int) throw ();' \
- 'extern "C" void exit (int);' \
- 'void exit (int);' \
- '#include <stdlib.h>'
-do
- _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$ac_declaration
-@%:@include <stdlib.h>],
- [exit (42);])],
- [],
- [continue])
- _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$ac_declaration],
- [exit (42);])],
- [break])
-done
-rm -f conftest*
-if test -n "$ac_declaration"; then
- echo '#ifdef __cplusplus' >>confdefs.h
- echo $ac_declaration >>confdefs.h
- echo '#endif' >>confdefs.h
-fi
-])# _AC_PROG_CXX_EXIT_DECLARATION
-
-dnl ---------------------------------------------------------------------------
-
diff --git a/client/Makefile.am b/client/Makefile.am
index da13c3e9763..58dcebfd852 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -18,12 +18,13 @@
#AUTOMAKE_OPTIONS = nostdinc
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \
- $(openssl_includes)
+ $(openssl_includes) -I$(top_builddir)/include
LIBS = @CLIENT_LIBS@
LDADD= @CLIENT_EXTRA_LDFLAGS@ \
$(top_builddir)/libmysql/libmysqlclient.la
bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \
- mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen
+ mysqldump mysqlimport mysqltest mysqlbinlog \
+ mysqltestmanagerc mysqltestmanager-pwgen
noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \
client_priv.h
mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc
@@ -32,9 +33,11 @@ mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS)
mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS)
mysqltest_SOURCES= mysqltest.c $(top_srcdir)/mysys/my_getsystime.c
mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD)
-mysqlbinlog_SOURCES = mysqlbinlog.cc ../mysys/mf_tempdir.c
-mysqlmanagerc_SOURCES = mysqlmanagerc.c
-sql_src=log_event.h log_event.cc
+mysqlbinlog_SOURCES = mysqlbinlog.cc $(top_srcdir)/mysys/mf_tempdir.c
+mysqltestmanagerc_SOURCES = mysqlmanagerc.c
+mysqltestmanager_pwgen_SOURCES = mysqlmanager-pwgen.c
+sql_src=log_event.h mysql_priv.h log_event.cc my_decimal.h my_decimal.cc
+strings_src=decimal.c
# Fix for mit-threads
DEFS = -DUNDEF_THREADS_HACK
@@ -43,7 +46,11 @@ link_sources:
for f in $(sql_src) ; do \
rm -f $(srcdir)/$$f; \
@LN_CP_F@ $(top_srcdir)/sql/$$f $(srcdir)/$$f; \
- done;
+ done; \
+ for f in $(strings_src) ; do \
+ rm -f $(srcdir)/$$f; \
+ @LN_CP_F@ $(top_srcdir)/strings/$$f $(srcdir)/$$f; \
+ done;
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/client/mysql.cc b/client/mysql.cc
index f27db0de8d8..5282f74453d 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -44,7 +44,7 @@
#include <locale.h>
#endif
-const char *VER= "14.7";
+const char *VER= "14.10";
/* Don't try to make a nice table if the data is too big */
#define MAX_COLUMN_LENGTH 1024
@@ -144,6 +144,7 @@ static char *current_host,*current_db,*current_user=0,*opt_password=0,
*current_prompt=0, *delimiter_str= 0,
*default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
static char *histfile;
+static char *histfile_tmp;
static String glob_buffer,old_buffer;
static String processed_prompt;
static char *full_username=0,*part_username=0,*default_prompt=0;
@@ -154,6 +155,8 @@ static char mysql_charsets_dir[FN_REFLEN+1];
static const char *xmlmeta[] = {
"&", "&amp;",
"<", "&lt;",
+ ">", "&gt;",
+ "\"", "&quot;",
0, 0
};
static const char *day_names[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
@@ -232,7 +235,7 @@ static COMMANDS commands[] = {
{ "connect",'r', com_connect,1,
"Reconnect to the server. Optional arguments are db and host." },
{ "delimiter", 'd', com_delimiter, 1,
- "Set query delimiter. " },
+ "Set statement delimiter. NOTE: Takes the rest of the line as new delimiter." },
#ifdef USE_POPEN
{ "edit", 'e', com_edit, 0, "Edit command with $EDITOR."},
#endif
@@ -442,6 +445,13 @@ int main(int argc,char *argv[])
if (verbose)
tee_fprintf(stdout, "Reading history-file %s\n",histfile);
read_history(histfile);
+ if (!(histfile_tmp= (char*) my_malloc((uint) strlen(histfile) + 5,
+ MYF(MY_WME))))
+ {
+ fprintf(stderr, "Couldn't allocate memory for temp histfile!\n");
+ exit(1);
+ }
+ sprintf(histfile_tmp, "%s.TMP", histfile);
}
}
#endif
@@ -470,7 +480,8 @@ sig_handler mysql_end(int sig)
/* write-history */
if (verbose)
tee_fprintf(stdout, "Writing history-file %s\n",histfile);
- write_history(histfile);
+ if (!write_history(histfile_tmp))
+ my_rename(histfile_tmp, histfile, MYF(MY_WME));
}
batch_readline_end(status.line_buff);
completion_hash_free(&ht);
@@ -485,6 +496,7 @@ sig_handler mysql_end(int sig)
my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
my_free(histfile,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(histfile_tmp,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
@@ -1041,7 +1053,12 @@ static COMMANDS *find_command (char *name,char cmd_char)
{
while (my_isspace(charset_info,*name))
name++;
- if (strstr(name, delimiter) || strstr(name, "\\g"))
+ /*
+ As special case we allow row that starts with word delimiter
+ to be able to change delimiter if someone has delimiter 'delimiter'.
+ */
+ if (strstr(name, "\\g") || (strstr(name, delimiter) &&
+ strncmp(name, "delimiter", 9)))
return ((COMMANDS *) 0);
if ((end=strcont(name," \t")))
{
@@ -2144,13 +2161,11 @@ print_table_data_xml(MYSQL_RES *result)
(void) tee_fputs("\n <row>\n", PAGER);
for (uint i=0; i < mysql_num_fields(result); i++)
{
- tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
- (fields[i].name[0] ? fields[i].name :
- " &nbsp; ") : "NULL"));
+ tee_fprintf(PAGER, "\t<field name=\"");
+ xmlencode_print(fields[i].name, (uint) strlen(fields[i].name));
+ tee_fprintf(PAGER, "\">");
xmlencode_print(cur[i], lengths[i]);
- tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
- (fields[i].name[0] ? fields[i].name :
- " &nbsp; ") : "NULL"));
+ tee_fprintf(PAGER, "</field>\n");
}
(void) tee_fputs(" </row>\n", PAGER);
}
@@ -2807,6 +2822,8 @@ sql_real_connect(char *host,char *database,char *user,char *password,
connected=1;
#ifndef EMBEDDED_LIBRARY
mysql.reconnect=info_flag ? 1 : 0; // We want to know if this happens
+#else
+ mysql.reconnect= 1;
#endif
#ifdef HAVE_READLINE
build_completion_hash(rehash, 1);
diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc
index 0da7d5b3acf..c6274e499ab 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -228,8 +228,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
switch(optid) {
#ifdef __NETWARE__
case 'a':
- setscreenmode(SCR_AUTOCLOSE_ON_EXIT); // auto close the screen /
- break;
+ setscreenmode(SCR_AUTOCLOSE_ON_EXIT); // auto close the screen /
+ break;
#endif
case 'c':
opt_count_iterations= 1;
@@ -431,6 +431,7 @@ static my_bool sql_connect(MYSQL *mysql, uint wait)
if (mysql_real_connect(mysql,host,user,opt_password,NullS,tcp_port,
unix_port, 0))
{
+ mysql->reconnect= 1;
if (info)
{
fputs("\n",stderr);
@@ -726,7 +727,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
void (*func) (MYSQL_RES*, MYSQL_ROW, uint);
new_line = 1;
- if (mysql_query(mysql, "show status") ||
+ if (mysql_query(mysql, "show /*!50002 GLOBAL */ status") ||
!(res = mysql_store_result(mysql)))
{
my_printf_error(0, "unable to show status; error: '%s'", MYF(ME_BELL),
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 0b15ad893e2..59c90f59e8e 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -14,10 +14,27 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/*
+
+ TODO: print the catalog (some USE catalog.db ????).
+
+ Standalone program to read a MySQL binary log (or relay log);
+ can read files produced by 3.23, 4.x, 5.0 servers.
+
+ Can read binlogs from 3.23/4.x/5.0 and relay logs from 4.x/5.0.
+ Should be able to read any file of these categories, even with
+ --start-position.
+ An important fact: the Format_desc event of the log is at most the 3rd event
+ of the log; if it is the 3rd then there is this combination:
+ Format_desc_of_slave, Rotate_of_master, Format_desc_of_master.
+*/
+
#define MYSQL_CLIENT
#undef MYSQL_SERVER
#include "client_priv.h"
#include <my_time.h>
+/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
+#include "mysql_priv.h"
#include "log_event.h"
#define BIN_LOG_HEADER_SIZE 4
@@ -66,6 +83,14 @@ static MYSQL* mysql = NULL;
static const char* dirname_for_local_load= 0;
static bool stop_passed= 0;
+/*
+ check_header() will set the pointer below.
+ Why do we need here a pointer on an event instead of an event ?
+ This is because the event will be created (alloced) in read_log_event()
+ (which returns a pointer) in check_header().
+*/
+Format_description_log_event* description_event;
+
static int dump_local_log_entries(const char* logname);
static int dump_remote_log_entries(const char* logname);
static int dump_log_entries(const char* logname);
@@ -78,6 +103,22 @@ class Load_log_processor
{
char target_dir_name[FN_REFLEN];
int target_dir_name_len;
+
+ /*
+ When we see first event corresponding to some LOAD DATA statement in
+ binlog, we create temporary file to store data to be loaded.
+ We add name of this file to file_names array using its file_id as index.
+ If we have Create_file event (i.e. we have binary log in pre-5.0.3
+ format) we also store save event object to be able which is needed to
+ emit LOAD DATA statement when we will meet Exec_load_data event.
+ If we have Begin_load_query event we simply store 0 in
+ File_name_record::event field.
+ */
+ struct File_name_record
+ {
+ char *fname;
+ Create_file_log_event *event;
+ };
DYNAMIC_ARRAY file_names;
/*
@@ -119,7 +160,7 @@ public:
int init()
{
- return init_dynamic_array(&file_names,sizeof(Create_file_log_event*),
+ return init_dynamic_array(&file_names, sizeof(File_name_record),
100,100 CALLER_INFO);
}
@@ -136,33 +177,91 @@ public:
}
void destroy()
{
- Create_file_log_event **ptr= (Create_file_log_event**)file_names.buffer;
- Create_file_log_event **end= ptr + file_names.elements;
+ File_name_record *ptr= (File_name_record *)file_names.buffer;
+ File_name_record *end= ptr + file_names.elements;
for (; ptr<end; ptr++)
{
- if (*ptr)
+ if (ptr->fname)
{
- my_free((char*)(*ptr)->fname,MYF(MY_WME));
- delete *ptr;
- *ptr= 0;
+ my_free(ptr->fname, MYF(MY_WME));
+ delete ptr->event;
+ bzero((char *)ptr, sizeof(File_name_record));
}
}
}
+
+ /*
+ Obtain Create_file event for LOAD DATA statement by its file_id.
+
+ SYNOPSIS
+ grab_event()
+ file_id - file_id identifiying LOAD DATA statement
+
+ DESCRIPTION
+ Checks whenever we have already seen Create_file event for this file_id.
+ If yes then returns pointer to it and removes it from array describing
+ active temporary files. Since this moment caller is responsible for
+ freeing memory occupied by this event and associated file name.
+
+ RETURN VALUES
+ Pointer to Create_file event or 0 if there was no such event
+ with this file_id.
+ */
Create_file_log_event *grab_event(uint file_id)
{
+ File_name_record *ptr;
+ Create_file_log_event *res;
+
if (file_id >= file_names.elements)
return 0;
- Create_file_log_event **ptr=
- (Create_file_log_event**)file_names.buffer + file_id;
- Create_file_log_event *res= *ptr;
- *ptr= 0;
+ ptr= dynamic_element(&file_names, file_id, File_name_record*);
+ if ((res= ptr->event))
+ bzero((char *)ptr, sizeof(File_name_record));
+ return res;
+ }
+
+ /*
+ Obtain file name of temporary file for LOAD DATA statement by its file_id.
+
+ SYNOPSIS
+ grab_fname()
+ file_id - file_id identifiying LOAD DATA statement
+
+ DESCRIPTION
+ Checks whenever we have already seen Begin_load_query event for this
+ file_id. If yes then returns file name of corresponding temporary file.
+ Removes record about this file from the array of active temporary files.
+ Since this moment caller is responsible for freeing memory occupied by
+ this name.
+
+ RETURN VALUES
+ String with name of temporary file or 0 if we have not seen Begin_load_query
+ event with this file_id.
+ */
+ char *grab_fname(uint file_id)
+ {
+ File_name_record *ptr;
+ char *res= 0;
+
+ if (file_id >= file_names.elements)
+ return 0;
+ ptr= dynamic_element(&file_names, file_id, File_name_record*);
+ if (!ptr->event)
+ {
+ res= ptr->fname;
+ bzero((char *)ptr, sizeof(File_name_record));
+ }
return res;
}
int process(Create_file_log_event *ce);
+ int process(Begin_load_query_log_event *ce);
int process(Append_block_log_event *ae);
File prepare_new_file_for_old_format(Load_log_event *le, char *filename);
int load_old_format_file(NET* net, const char *server_fname,
uint server_fname_len, File file);
+ int process_first_event(const char *bname, uint blen, const char *block,
+ uint block_len, uint file_id,
+ Create_file_log_event *ce);
};
@@ -240,22 +339,42 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname,
}
-int Load_log_processor::process(Create_file_log_event *ce)
+/*
+ Process first event in the sequence of events representing LOAD DATA
+ statement.
+
+ SYNOPSIS
+ process_first_event()
+ bname - base name for temporary file to be created
+ blen - base name length
+ block - first block of data to be loaded
+ block_len - first block length
+ file_id - identifies LOAD DATA statement
+ ce - pointer to Create_file event object if we are processing
+ this type of event.
+
+ DESCRIPTION
+ Creates temporary file to be used in LOAD DATA and writes first block of
+ data to it. Registers its file name (and optional Create_file event)
+ in the array of active temporary files.
+
+ RETURN VALUES
+ 0 - success
+ non-0 - error
+*/
+
+int Load_log_processor::process_first_event(const char *bname, uint blen,
+ const char *block, uint block_len,
+ uint file_id,
+ Create_file_log_event *ce)
{
- const char *bname= ce->fname+dirname_length(ce->fname);
- uint blen= ce->fname_len - (bname-ce->fname);
uint full_len= target_dir_name_len + blen + 9 + 9 + 1;
int error= 0;
char *fname, *ptr;
File file;
- DBUG_ENTER("Load_log_processor::process");
+ File_name_record rec;
+ DBUG_ENTER("Load_log_processor::process_first_event");
- if (set_dynamic(&file_names,(gptr)&ce,ce->file_id))
- {
- sql_print_error("Could not construct local filename %s%s",
- target_dir_name,bname);
- DBUG_RETURN(-1);
- }
if (!(fname= my_malloc(full_len,MYF(MY_WME))))
DBUG_RETURN(-1);
@@ -263,7 +382,7 @@ int Load_log_processor::process(Create_file_log_event *ce)
ptr= fname + target_dir_name_len;
memcpy(ptr,bname,blen);
ptr+= blen;
- ptr+= my_sprintf(ptr,(ptr,"-%x",ce->file_id));
+ ptr+= my_sprintf(ptr, (ptr, "-%x", file_id));
if ((file= create_unique_file(fname,ptr)) < 0)
{
@@ -271,9 +390,21 @@ int Load_log_processor::process(Create_file_log_event *ce)
target_dir_name,bname);
DBUG_RETURN(-1);
}
- ce->set_fname_outside_temp_buf(fname,strlen(fname));
- if (my_write(file,(byte*) ce->block,ce->block_len,MYF(MY_WME|MY_NABP)))
+ rec.fname= fname;
+ rec.event= ce;
+
+ if (set_dynamic(&file_names, (gptr)&rec, file_id))
+ {
+ sql_print_error("Could not construct local filename %s%s",
+ target_dir_name, bname);
+ DBUG_RETURN(-1);
+ }
+
+ if (ce)
+ ce->set_fname_outside_temp_buf(fname, strlen(fname));
+
+ if (my_write(file, (byte*)block, block_len, MYF(MY_WME|MY_NABP)))
error= -1;
if (my_close(file, MYF(MY_WME)))
error= -1;
@@ -281,19 +412,35 @@ int Load_log_processor::process(Create_file_log_event *ce)
}
+int Load_log_processor::process(Create_file_log_event *ce)
+{
+ const char *bname= ce->fname + dirname_length(ce->fname);
+ uint blen= ce->fname_len - (bname-ce->fname);
+
+ return process_first_event(bname, blen, ce->block, ce->block_len,
+ ce->file_id, ce);
+}
+
+
+int Load_log_processor::process(Begin_load_query_log_event *blqe)
+{
+ return process_first_event("SQL_LOAD_MB", 11, blqe->block, blqe->block_len,
+ blqe->file_id, 0);
+}
+
+
int Load_log_processor::process(Append_block_log_event *ae)
{
DBUG_ENTER("Load_log_processor::process");
- Create_file_log_event* ce= ((ae->file_id < file_names.elements) ?
- *((Create_file_log_event**)file_names.buffer +
- ae->file_id) :
- 0);
+ const char* fname= ((ae->file_id < file_names.elements) ?
+ dynamic_element(&file_names, ae->file_id,
+ File_name_record*)->fname : 0);
- if (ce)
+ if (fname)
{
File file;
int error= 0;
- if (((file= my_open(ce->fname,
+ if (((file= my_open(fname,
O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0))
DBUG_RETURN(-1);
if (my_write(file,(byte*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP)))
@@ -305,8 +452,8 @@ int Load_log_processor::process(Append_block_log_event *ae)
/*
There is no Create_file event (a bad binlog or a big
- --position). Assuming it's a big --position, we just do nothing and
- print a warning.
+ --start-position). Assuming it's a big --start-position, we just do
+ nothing and print a warning.
*/
fprintf(stderr,"Warning: ignoring Append_block as there is no \
Create_file event for file_id: %u\n",ae->file_id);
@@ -316,30 +463,57 @@ Create_file event for file_id: %u\n",ae->file_id);
Load_log_processor load_processor;
+
+static bool check_database(const char *log_dbname)
+{
+ return one_database &&
+ (log_dbname != NULL) &&
+ strcmp(log_dbname, database);
+}
+
+
/*
+ Process an event
+
+ SYNOPSIS
+ process_event()
+
RETURN
0 ok and continue
1 error and terminate
-1 ok and terminate
-
+
TODO
This function returns 0 even in some error cases. This should be changed.
*/
-int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
+
+
+
+int process_event(LAST_EVENT_INFO *last_event_info, Log_event *ev,
+ my_off_t pos)
{
char ll_buff[21];
+ Log_event_type ev_type= ev->get_type_code();
DBUG_ENTER("process_event");
+ /*
+ Format events are not concerned by --offset and such, we always need to
+ read them to be able to process the wanted events.
+ */
if ((rec_count >= offset) &&
- ((my_time_t)(ev->when) >= start_datetime))
+ ((my_time_t)(ev->when) >= start_datetime) ||
+ (ev_type == FORMAT_DESCRIPTION_EVENT))
{
- /*
- We have found an event after start_datetime, from now on print
- everything (in case the binlog has timestamps increasing and decreasing,
- we do this to avoid cutting the middle).
- */
- start_datetime= 0;
- offset= 0; // print everything and protect against cycling rec_count
+ if (ev_type != FORMAT_DESCRIPTION_EVENT)
+ {
+ /*
+ We have found an event after start_datetime, from now on print
+ everything (in case the binlog has timestamps increasing and
+ decreasing, we do this to avoid cutting the middle).
+ */
+ start_datetime= 0;
+ offset= 0; // print everything and protect against cycling rec_count
+ }
if (((my_time_t)(ev->when) >= stop_datetime)
|| (pos >= stop_position_mot))
{
@@ -349,31 +523,23 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
if (!short_form)
fprintf(result_file, "# at %s\n",llstr(pos,ll_buff));
- switch (ev->get_type_code()) {
+ switch (ev_type) {
case QUERY_EVENT:
- if (one_database)
- {
- const char * log_dbname = ((Query_log_event*)ev)->db;
- if ((log_dbname != NULL) && (strcmp(log_dbname, database)))
- goto end;
- }
- ev->print(result_file, short_form, last_db);
+ if (check_database(((Query_log_event*)ev)->db))
+ goto end;
+ ev->print(result_file, short_form, last_event_info);
break;
case CREATE_FILE_EVENT:
{
Create_file_log_event* ce= (Create_file_log_event*)ev;
- if (one_database)
- {
- /*
- We test if this event has to be ignored. If yes, we don't save
- this event; this will have the good side-effect of ignoring all
- related Append_block and Exec_load.
- Note that Load event from 3.23 is not tested.
- */
- const char * log_dbname = ce->db;
- if ((log_dbname != NULL) && (strcmp(log_dbname, database)))
- goto end; // Next event
- }
+ /*
+ We test if this event has to be ignored. If yes, we don't save
+ this event; this will have the good side-effect of ignoring all
+ related Append_block and Exec_load.
+ Note that Load event from 3.23 is not tested.
+ */
+ if (check_database(ce->db))
+ goto end; // Next event
/*
We print the event, but with a leading '#': this is just to inform
the user of the original command; the command we want to execute
@@ -381,8 +547,9 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT'
below.
*/
- ce->print(result_file, short_form, last_db, TRUE);
- if (!old_format)
+ ce->print(result_file, short_form, last_event_info, TRUE);
+ // If this binlog is not 3.23 ; why this test??
+ if (description_event->binlog_version >= 3)
{
if (load_processor.process(ce))
break; // Error
@@ -391,23 +558,23 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
break;
}
case APPEND_BLOCK_EVENT:
- ev->print(result_file, short_form, last_db);
+ ev->print(result_file, short_form, last_event_info);
if (load_processor.process((Append_block_log_event*) ev))
break; // Error
break;
case EXEC_LOAD_EVENT:
{
- ev->print(result_file, short_form, last_db);
+ ev->print(result_file, short_form, last_event_info);
Execute_load_log_event *exv= (Execute_load_log_event*)ev;
Create_file_log_event *ce= load_processor.grab_event(exv->file_id);
/*
if ce is 0, it probably means that we have not seen the Create_file
- event (a bad binlog, or most probably --position is after the
+ event (a bad binlog, or most probably --start-position is after the
Create_file event). Print a warning comment.
*/
if (ce)
{
- ce->print(result_file, short_form, last_db, TRUE);
+ ce->print(result_file, short_form, last_event_info, TRUE);
my_free((char*)ce->fname,MYF(MY_WME));
delete ce;
}
@@ -416,8 +583,46 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
Create_file event for file_id: %u\n",exv->file_id);
break;
}
+ case FORMAT_DESCRIPTION_EVENT:
+ delete description_event;
+ description_event= (Format_description_log_event*) ev;
+ ev->print(result_file, short_form, last_event_info);
+ /*
+ We don't want this event to be deleted now, so let's hide it (I
+ (Guilhem) should later see if this triggers a non-serious Valgrind
+ error). Not serious error, because we will free description_event
+ later.
+ */
+ ev= 0;
+ break;
+ case BEGIN_LOAD_QUERY_EVENT:
+ ev->print(result_file, short_form, last_event_info);
+ load_processor.process((Begin_load_query_log_event*) ev);
+ break;
+ case EXECUTE_LOAD_QUERY_EVENT:
+ {
+ Execute_load_query_log_event *exlq= (Execute_load_query_log_event*)ev;
+ char *fname= load_processor.grab_fname(exlq->file_id);
+
+ if (check_database(exlq->db))
+ {
+ if (fname)
+ my_free(fname, MYF(MY_WME));
+ goto end;
+ }
+
+ if (fname)
+ {
+ exlq->print(result_file, short_form, last_event_info, fname);
+ my_free(fname, MYF(MY_WME));
+ }
+ else
+ fprintf(stderr,"Warning: ignoring Execute_load_query as there is no \
+Begin_load_query event for file_id: %u\n", exlq->file_id);
+ break;
+ }
default:
- ev->print(result_file, short_form, last_db);
+ ev->print(result_file, short_form, last_event_info);
}
}
@@ -431,6 +636,15 @@ end:
static struct my_option my_long_options[] =
{
+ /*
+ mysqlbinlog needs charsets knowledge, to be able to convert a charset
+ number found in binlog to a charset name (to be able to print things
+ like this:
+ SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`;
+ */
+ {"character-sets-dir", OPT_CHARSETS_DIR,
+ "Directory where character sets are.", (gptr*) &charsets_dir,
+ (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifndef DBUG_OFF
{"debug", '#', "Output debug log.", (gptr*) &default_dbug_option,
(gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
@@ -565,7 +779,7 @@ static void die(const char* fmt, ...)
static void print_version()
{
- printf("%s Ver 3.0 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
+ printf("%s Ver 3.1 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
NETWARE_SET_SCREEN_MODE(1);
}
@@ -701,6 +915,7 @@ static MYSQL* safe_connect()
mysql_close(local_mysql);
die("failed on connect: %s", errmsg);
}
+ local_mysql->reconnect= 1;
return local_mysql;
}
@@ -712,12 +927,17 @@ static int dump_log_entries(const char* logname)
}
-static int check_master_version(MYSQL* mysql)
+/*
+ This is not as smart as check_header() (used for local log); it will not work
+ for a binlog which mixes format. TODO: fix this.
+*/
+static int check_master_version(MYSQL* mysql,
+ Format_description_log_event
+ **description_event)
{
MYSQL_RES* res = 0;
MYSQL_ROW row;
const char* version;
- int old_format = 0;
if (mysql_query(mysql, "SELECT VERSION()") ||
!(res = mysql_store_result(mysql)))
@@ -743,11 +963,18 @@ static int check_master_version(MYSQL* mysql)
switch (*version) {
case '3':
- old_format = 1;
+ *description_event= new Format_description_log_event(1);
break;
case '4':
+ *description_event= new Format_description_log_event(3);
case '5':
- old_format = 0;
+ /*
+ The server is soon going to send us its Format_description log
+ event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
+ So we first assume that this is 4.0 (which is enough to read the
+ Format_desc event if one comes).
+ */
+ *description_event= new Format_description_log_event(3);
break;
default:
sql_print_error("Master reported unrecognized MySQL version '%s'",
@@ -757,18 +984,17 @@ static int check_master_version(MYSQL* mysql)
return 1;
}
mysql_free_result(res);
- return old_format;
+ return 0;
}
static int dump_remote_log_entries(const char* logname)
+
{
char buf[128];
- char last_db[FN_REFLEN+1] = "";
- ulong len;
- uint logname_len;
+ LAST_EVENT_INFO last_event_info;
+ uint len, logname_len;
NET* net;
- int old_format;
int error= 0;
my_off_t old_off= start_position_mot;
char fname[FN_REFLEN+1];
@@ -781,7 +1007,18 @@ static int dump_remote_log_entries(const char* logname)
*/
mysql= safe_connect();
net= &mysql->net;
- old_format = check_master_version(mysql);
+
+ if (check_master_version(mysql, &description_event))
+ {
+ fprintf(stderr, "Could not find server version");
+ DBUG_RETURN(1);
+ }
+ if (!description_event || !description_event->is_valid())
+ {
+ fprintf(stderr, "Invalid Format_description log event; \
+could be out of memory");
+ DBUG_RETURN(1);
+ }
/*
COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
@@ -810,6 +1047,8 @@ static int dump_remote_log_entries(const char* logname)
for (;;)
{
const char *error_msg;
+ Log_event *ev;
+
len = net_safe_read(mysql);
if (len == packet_error)
{
@@ -822,9 +1061,9 @@ static int dump_remote_log_entries(const char* logname)
break; // end of data
DBUG_PRINT("info",( "len= %u, net->read_pos[5] = %d\n",
len, net->read_pos[5]));
- Log_event *ev = Log_event::read_log_event((const char*) net->read_pos + 1 ,
- len - 1, &error_msg, old_format);
- if (!ev)
+ if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
+ len - 1, &error_msg,
+ description_event)))
{
fprintf(stderr, "Could not construct log event object\n");
error= 1;
@@ -832,25 +1071,27 @@ static int dump_remote_log_entries(const char* logname)
}
Log_event_type type= ev->get_type_code();
- if (!old_format || ( type != LOAD_EVENT && type != CREATE_FILE_EVENT))
+ if (description_event->binlog_version >= 3 ||
+ (type != LOAD_EVENT && type != CREATE_FILE_EVENT))
{
- if (ev->get_type_code() == ROTATE_EVENT)
+ /*
+ If this is a Rotate event, maybe it's the end of the requested binlog;
+ in this case we are done (stop transfer).
+ This is suitable for binlogs, not relay logs (but for now we don't read
+ relay logs remotely because the server is not able to do that). If one
+ day we read relay logs remotely, then we will have a problem with the
+ detection below: relay logs contain Rotate events which are about the
+ binlogs, so which would trigger the end-detection below.
+ */
+ if (type == ROTATE_EVENT)
{
Rotate_log_event *rev= (Rotate_log_event *)ev;
/*
- mysqld is sending us all its binlogs after the requested one, but we
- don't want them.
If this is a fake Rotate event, and not about our log, we can stop
transfer. If this a real Rotate event (so it's not about our log,
it's in our log describing the next log), we print it (because it's
part of our log) and then we will stop when we receive the fake one
soon.
- This is suitable for binlogs, not relay logs (but for now we don't
- read relay logs remotely because the server is not able to do
- that). If one day we read relay logs remotely, then we will have a
- problem with the detection below: relay logs contain Rotate events
- which are about the binlogs, so which would trigger the end-detection
- below.
*/
if (rev->when == 0)
{
@@ -873,7 +1114,7 @@ static int dump_remote_log_entries(const char* logname)
len= 1; // fake Rotate, so don't increment old_off
}
}
- if ((error= process_event(last_db,ev,old_off,old_format)))
+ if ((error= process_event(&last_event_info,ev,old_off)))
{
error= ((error < 0) ? 0 : 1);
goto err;
@@ -885,64 +1126,135 @@ static int dump_remote_log_entries(const char* logname)
const char *old_fname= le->fname;
uint old_len= le->fname_len;
File file;
-
+
if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
{
error= 1;
goto err;
}
-
- if ((error= process_event(last_db,ev,old_off,old_format)))
+
+ if ((error= process_event(&last_event_info,ev,old_off)))
{
- my_close(file,MYF(MY_WME));
+ my_close(file,MYF(MY_WME));
error= ((error < 0) ? 0 : 1);
goto err;
}
- if (load_processor.load_old_format_file(net,old_fname,old_len,file))
+ error= load_processor.load_old_format_file(net,old_fname,old_len,file);
+ my_close(file,MYF(MY_WME));
+ if (error)
{
- my_close(file,MYF(MY_WME));
error= 1;
goto err;
}
- my_close(file,MYF(MY_WME));
}
-
/*
Let's adjust offset for remote log as for local log to produce
similar text.
*/
old_off+= len-1;
}
+
err:
mysql_close(mysql);
DBUG_RETURN(error);
}
-static int check_header(IO_CACHE* file)
+static void check_header(IO_CACHE* file,
+ Format_description_log_event **description_event)
{
byte header[BIN_LOG_HEADER_SIZE];
byte buf[PROBE_HEADER_LEN];
- int old_format=0;
- DBUG_ENTER("check_header");
+ my_off_t tmp_pos, pos;
- my_off_t pos = my_b_tell(file);
+ *description_event= new Format_description_log_event(3);
+ pos= my_b_tell(file);
my_b_seek(file, (my_off_t)0);
if (my_b_read(file, header, sizeof(header)))
die("Failed reading header; Probably an empty file");
if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
die("File is not a binary log file");
- if (!my_b_read(file, buf, sizeof(buf)))
+
+ /*
+ Imagine we are running with --start-position=1000. We still need
+ to know the binlog format's. So we still need to find, if there is
+ one, the Format_desc event, or to know if this is a 3.23
+ binlog. So we need to first read the first events of the log,
+ those around offset 4. Even if we are reading a 3.23 binlog from
+ the start (no --start-position): we need to know the header length
+ (which is 13 in 3.23, 19 in 4.x) to be able to successfully print
+ the first event (Start_log_event_v3). So even in this case, we
+ need to "probe" the first bytes of the log *before* we do a real
+ read_log_event(). Because read_log_event() needs to know the
+ header's length to work fine.
+ */
+ for(;;)
{
- if (buf[4] == START_EVENT)
+ tmp_pos= my_b_tell(file); /* should be 4 the first time */
+ if (my_b_read(file, buf, sizeof(buf)))
{
- uint event_len;
- event_len = uint4korr(buf + EVENT_LEN_OFFSET);
- old_format = (event_len < (LOG_EVENT_HEADER_LEN + START_HEADER_LEN));
+ if (file->error)
+ die("\
+Could not read entry at offset %lu : Error in log format or read error",
+ tmp_pos);
+ /*
+ Otherwise this is just EOF : this log currently contains 0-2
+ events. Maybe it's going to be filled in the next
+ milliseconds; then we are going to have a problem if this a
+ 3.23 log (imagine we are locally reading a 3.23 binlog which
+ is being written presently): we won't know it in
+ read_log_event() and will fail(). Similar problems could
+ happen with hot relay logs if --start-position is used (but a
+ --start-position which is posterior to the current size of the log).
+ These are rare problems anyway (reading a hot log + when we
+ read the first events there are not all there yet + when we
+ read a bit later there are more events + using a strange
+ --start-position).
+ */
+ break;
+ }
+ else
+ {
+ DBUG_PRINT("info",("buf[4]=%d", buf[4]));
+ /* always test for a Start_v3, even if no --start-position */
+ if (buf[4] == START_EVENT_V3) /* This is 3.23 or 4.x */
+ {
+ if (uint4korr(buf + EVENT_LEN_OFFSET) <
+ (LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
+ {
+ /* This is 3.23 (format 1) */
+ delete *description_event;
+ *description_event= new Format_description_log_event(1);
+ }
+ break;
+ }
+ else if (tmp_pos >= start_position)
+ break;
+ else if (buf[4] == FORMAT_DESCRIPTION_EVENT) /* This is 5.0 */
+ {
+ my_b_seek(file, tmp_pos); /* seek back to event's start */
+ if (!(*description_event= (Format_description_log_event*)
+ Log_event::read_log_event(file, *description_event)))
+ /* EOF can't be hit here normally, so it's a real error */
+ die("Could not read a Format_description_log_event event \
+at offset %lu ; this could be a log format error or read error",
+ tmp_pos);
+ DBUG_PRINT("info",("Setting description_event"));
+ }
+ else if (buf[4] == ROTATE_EVENT)
+ {
+ my_b_seek(file, tmp_pos); /* seek back to event's start */
+ if (!Log_event::read_log_event(file, *description_event))
+ /* EOF can't be hit here normally, so it's a real error */
+ die("Could not read a Rotate_log_event event \
+at offset %lu ; this could be a log format error or read error",
+ tmp_pos);
+ }
+ else
+ break;
}
}
my_b_seek(file, pos);
- DBUG_RETURN(old_format);
}
@@ -950,13 +1262,10 @@ static int dump_local_log_entries(const char* logname)
{
File fd = -1;
IO_CACHE cache,*file= &cache;
- char last_db[FN_REFLEN+1];
+ LAST_EVENT_INFO last_event_info;
byte tmp_buff[BIN_LOG_HEADER_SIZE];
- bool old_format = 0;
int error= 0;
- last_db[0]= 0;
-
if (logname && logname[0] != '-')
{
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
@@ -965,65 +1274,67 @@ static int dump_local_log_entries(const char* logname)
MYF(MY_WME | MY_NABP)))
{
my_close(fd, MYF(MY_WME));
- exit(1);
+ return 1;
}
- old_format = check_header(file);
+ check_header(file, &description_event);
}
- else
+ else // reading from stdin;
{
- if (init_io_cache(file, fileno(result_file), 0, READ_CACHE, (my_off_t) 0,
+ if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
return 1;
- old_format = check_header(file);
+ check_header(file, &description_event);
if (start_position)
{
- /* skip 'start_position' characters from stdout */
+ /* skip 'start_position' characters from stdin */
byte buff[IO_SIZE];
my_off_t length,tmp;
for (length= start_position_mot ; length > 0 ; length-=tmp)
{
tmp=min(length,sizeof(buff));
if (my_b_read(file, buff, (uint) tmp))
- {
- error= 1;
- goto end;
- }
+ {
+ error= 1;
+ goto end;
+ }
}
}
- file->pos_in_file= start_position_mot;
- file->seek_not_done=0;
}
- if (!start_position)
+ if (!description_event || !description_event->is_valid())
+ die("Invalid Format_description log event; could be out of memory");
+
+ if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
{
- // Skip header
- if (my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
- {
- error= 1;
- goto end;
- }
+ error= 1;
+ goto end;
}
-
for (;;)
{
char llbuff[21];
my_off_t old_off = my_b_tell(file);
- Log_event* ev = Log_event::read_log_event(file, old_format);
+ Log_event* ev = Log_event::read_log_event(file, description_event);
if (!ev)
{
- if (file->error)
+ /*
+ if binlog wasn't closed properly ("in use" flag is set) don't complain
+ about a corruption, but treat it as EOF and move to the next binlog.
+ */
+ if (description_event->flags & LOG_EVENT_BINLOG_IN_USE_F)
+ file->error= 0;
+ else if (file->error)
{
- fprintf(stderr,
- "Could not read entry at offset %s:"
- "Error in log format or read error\n",
- llstr(old_off,llbuff));
- error= 1;
+ fprintf(stderr,
+ "Could not read entry at offset %s:"
+ "Error in log format or read error\n",
+ llstr(old_off,llbuff));
+ error= 1;
}
// file->error == 0 means EOF, that's OK, we break in this case
break;
}
- if ((error= process_event(last_db,ev,old_off,false)))
+ if ((error= process_event(&last_event_info,ev,old_off)))
{
if (error < 0)
error= 0;
@@ -1035,6 +1346,7 @@ end:
if (fd >= 0)
my_close(fd, MYF(MY_WME));
end_io_cache(file);
+ delete description_event;
return error;
}
@@ -1085,6 +1397,14 @@ int main(int argc, char** argv)
fprintf(result_file,
"/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
+ /*
+ In mysqlbinlog|mysql, don't want mysql to be disconnected after each
+ transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
+ */
+ fprintf(result_file,
+ "/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,"
+ "COMPLETION_TYPE=0*/;\n");
+
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
(--argc >= 0) && !stop_passed ; )
{
@@ -1099,6 +1419,13 @@ int main(int argc, char** argv)
start_position= BIN_LOG_HEADER_SIZE;
}
+ /*
+ Issue a ROLLBACK in case the last printed binlog was crashed and had half
+ of transaction.
+ */
+ fprintf(result_file,
+ "ROLLBACK;\n"
+ "/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;\n");
if (disable_log_bin)
fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
@@ -1120,8 +1447,14 @@ int main(int argc, char** argv)
*/
#ifdef __WIN__
+#include "my_decimal.h"
+#include "decimal.c"
+#include "my_decimal.cpp"
#include "log_event.cpp"
#else
+#include "my_decimal.h"
+#include "decimal.c"
+#include "my_decimal.cc"
#include "log_event.cc"
#endif
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index 07f3f25b50c..c767f1c89b7 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -629,6 +629,7 @@ static int dbConnect(char *host, char *user, char *passwd)
DBerror(&mysql_connection, "when trying to connect");
return 1;
}
+ mysql_connection.reconnect= 1;
return 0;
} /* dbConnect */
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 2573c812067..b07a36aa7ad 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -37,7 +37,7 @@
** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov
*/
-#define DUMP_VERSION "10.9"
+#define DUMP_VERSION "10.10"
#include <my_global.h>
#include <my_sys.h>
@@ -116,6 +116,8 @@ static const char *mysql_universal_client_charset=
static char *default_charset;
static CHARSET_INFO *charset_info= &my_charset_latin1;
const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
+/* do we met VIEWs during tables scaning */
+my_bool was_views= 0;
const char *compatible_mode_names[]=
{
@@ -376,7 +378,7 @@ static struct my_option my_long_options[] =
(gptr*) &where, (gptr*) &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"xml", 'X', "Dump a database as well formed XML.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
- { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+ {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
static const char *load_default_groups[]= { "mysqldump","client",0 };
@@ -394,6 +396,8 @@ static int dump_all_databases();
static char *quote_name(const char *name, char *buff, my_bool force);
static const char *check_if_ignore_table(const char *table_name);
static char *primary_key_fields(const char *table_name);
+static my_bool get_view_structure(char *table, char* db);
+static my_bool dump_all_views_in_db(char *database);
#include <help_start.h>
@@ -773,16 +777,16 @@ static int get_options(int *argc, char ***argv)
/*
-** DBerror -- prints mysql error message and exits the program.
+** DB_error -- prints mysql error message and exits the program.
*/
-static void DBerror(MYSQL *mysql, const char *when)
+static void DB_error(MYSQL *mysql, const char *when)
{
- DBUG_ENTER("DBerror");
+ DBUG_ENTER("DB_error");
my_printf_error(0,"Got error: %d: %s %s", MYF(0),
mysql_errno(mysql), mysql_error(mysql), when);
safe_exit(EX_MYSQLERR);
DBUG_VOID_RETURN;
-} /* DBerror */
+} /* DB_error */
/*
@@ -858,7 +862,7 @@ static int dbConnect(char *host, char *user,char *passwd)
NULL,opt_mysql_port,opt_mysql_unix_port,
0)))
{
- DBerror(&mysql_connection, "when trying to connect");
+ DB_error(&mysql_connection, "when trying to connect");
return 1;
}
/*
@@ -1089,7 +1093,7 @@ static void print_xml_row(FILE *xml_file, const char *row_name,
number of fields in table, 0 if error
*/
-static uint getTableStructure(char *table, char* db)
+static uint get_table_structure(char *table, char *db)
{
MYSQL_RES *tableRes;
MYSQL_ROW row;
@@ -1100,7 +1104,7 @@ static uint getTableStructure(char *table, char* db)
char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
char table_buff2[NAME_LEN*2+3];
FILE *sql_file = md_result_file;
- DBUG_ENTER("getTableStructure");
+ DBUG_ENTER("get_table_structure");
delayed= opt_delayed ? " DELAYED " : "";
@@ -1126,6 +1130,7 @@ static uint getTableStructure(char *table, char* db)
{
/* Make an sql-file, if path was given iow. option -T was given */
char buff[20+FN_REFLEN];
+ MYSQL_FIELD *field;
my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
if (mysql_query_with_error_report(sock, 0, buff))
@@ -1159,8 +1164,16 @@ static uint getTableStructure(char *table, char* db)
check_io(sql_file);
}
- tableRes=mysql_store_result(sock);
- row=mysql_fetch_row(tableRes);
+ tableRes= mysql_store_result(sock);
+ field= mysql_fetch_field_direct(tableRes, 0);
+ if (strcmp(field->name, "View") == 0)
+ {
+ if (verbose)
+ fprintf(stderr, "-- It's a view, skipped\n");
+ was_views= 1;
+ DBUG_RETURN(0);
+ }
+ row= mysql_fetch_row(tableRes);
fprintf(sql_file, "%s;\n", row[1]);
check_io(sql_file);
mysql_free_result(tableRes);
@@ -1309,6 +1322,14 @@ static uint getTableStructure(char *table, char* db)
my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
if (mysql_query_with_error_report(sock, &tableRes, buff))
{
+ if (mysql_errno(sock) == ER_WRONG_OBJECT)
+ {
+ /* it is VIEW */
+ fputs("\t\t<options Comment=\"view\" />\n", sql_file);
+ goto continue_xml;
+ }
+ fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
+ my_progname, result_table, mysql_error(sock));
if (path)
my_fclose(sql_file, MYF(MY_WME));
safe_exit(EX_MYSQLERR);
@@ -1375,10 +1396,9 @@ static uint getTableStructure(char *table, char* db)
/* Get MySQL specific create options */
if (create_options)
{
- char show_name_buff[FN_REFLEN];
+ char show_name_buff[NAME_LEN*2+2+24];
/* Check memory for quote_for_like() */
- DBUG_ASSERT(2*sizeof(table) < sizeof(show_name_buff));
my_snprintf(buff, sizeof(buff), "show table status like %s",
quote_for_like(table, show_name_buff));
@@ -1416,6 +1436,7 @@ static uint getTableStructure(char *table, char* db)
}
mysql_free_result(tableRes); /* Is always safe to free */
}
+continue_xml:
if (!opt_xml)
fputs(";\n", sql_file);
else
@@ -1436,7 +1457,7 @@ static uint getTableStructure(char *table, char* db)
my_fclose(sql_file, MYF(MY_WME));
}
DBUG_RETURN(numFields);
-} /* getTableStructure */
+} /* get_table_structure */
static char *add_load_option(char *ptr,const char *object,
@@ -1502,10 +1523,12 @@ static char *alloc_query_str(ulong size)
return query;
}
+
/*
-** dumpTable saves database contents as a series of INSERT statements.
+** dump_table saves database contents as a series of INSERT statements.
*/
-static void dumpTable(uint numFields, char *table)
+
+static void dump_table(uint numFields, char *table)
{
char query_buf[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3];
char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
@@ -1571,7 +1594,7 @@ static void dumpTable(uint numFields, char *table)
}
if (mysql_real_query(sock, query, (uint) (end - query)))
{
- DBerror(sock, "when executing 'SELECT INTO OUTFILE'");
+ DB_error(sock, "when executing 'SELECT INTO OUTFILE'");
return;
}
}
@@ -1618,13 +1641,13 @@ static void dumpTable(uint numFields, char *table)
check_io(md_result_file);
}
if (mysql_query_with_error_report(sock, 0, query))
- DBerror(sock, "when retrieving data from server");
+ DB_error(sock, "when retrieving data from server");
if (quick)
res=mysql_use_result(sock);
else
res=mysql_store_result(sock);
if (!res)
- DBerror(sock, "when retrieving data from server");
+ DB_error(sock, "when retrieving data from server");
if (verbose)
fprintf(stderr, "-- Retrieving rows...\n");
if (mysql_num_fields(res) != numFields)
@@ -1697,12 +1720,13 @@ static void dumpTable(uint numFields, char *table)
we'll dump in hex only BLOB columns.
*/
is_blob= (opt_hex_blob && field->charsetnr == 63 &&
- (field->type == FIELD_TYPE_STRING ||
- field->type == FIELD_TYPE_VAR_STRING ||
- field->type == FIELD_TYPE_BLOB ||
- field->type == FIELD_TYPE_LONG_BLOB ||
- field->type == FIELD_TYPE_MEDIUM_BLOB ||
- field->type == FIELD_TYPE_TINY_BLOB)) ? 1 : 0;
+ (field->type == MYSQL_TYPE_STRING ||
+ field->type == MYSQL_TYPE_VAR_STRING ||
+ field->type == MYSQL_TYPE_VARCHAR ||
+ field->type == MYSQL_TYPE_BLOB ||
+ field->type == MYSQL_TYPE_LONG_BLOB ||
+ field->type == MYSQL_TYPE_MEDIUM_BLOB ||
+ field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0;
if (extended_insert)
{
ulong length = lengths[i];
@@ -1924,7 +1948,7 @@ err:
my_free(query, MYF(MY_ALLOW_ZERO_PTR));
safe_exit(error);
return;
-} /* dumpTable */
+} /* dump_table */
static char *getTableName(int reset)
@@ -1964,6 +1988,21 @@ static int dump_all_databases()
if (dump_all_tables_in_db(row[0]))
result=1;
}
+ if (was_views)
+ {
+ if (mysql_query(sock, "SHOW DATABASES") ||
+ !(tableres = mysql_store_result(sock)))
+ {
+ my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
+ MYF(0), mysql_error(sock));
+ return 1;
+ }
+ while ((row = mysql_fetch_row(tableres)))
+ {
+ if (dump_all_views_in_db(row[0]))
+ result=1;
+ }
+ }
return result;
}
/* dump_all_databases */
@@ -1972,20 +2011,33 @@ static int dump_all_databases()
static int dump_databases(char **db_names)
{
int result=0;
- for ( ; *db_names ; db_names++)
+ char **db;
+ for (db= db_names ; *db ; db++)
{
- if (dump_all_tables_in_db(*db_names))
+ if (dump_all_tables_in_db(*db))
result=1;
}
+ if (!result && was_views)
+ {
+ for (db= db_names ; *db ; db++)
+ {
+ if (dump_all_views_in_db(*db))
+ result=1;
+ }
+ }
return result;
} /* dump_databases */
static int init_dumping(char *database)
{
+ if (mysql_get_server_version(sock) >= 50003 &&
+ !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
+ return 1;
+
if (mysql_select_db(sock, database))
{
- DBerror(sock, "when selecting the database");
+ DB_error(sock, "when selecting the database");
return 1; /* If --force */
}
if (!path && !opt_xml)
@@ -2073,14 +2125,14 @@ static int dump_all_tables_in_db(char *database)
dynstr_append(&query, " READ /*!32311 LOCAL */,");
}
if (numrows && mysql_real_query(sock, query.str, query.length-1))
- DBerror(sock, "when using LOCK TABLES");
+ DB_error(sock, "when using LOCK TABLES");
/* We shall continue here, if --force was given */
dynstr_free(&query);
}
if (flush_logs)
{
if (mysql_refresh(sock, REFRESH_LOG))
- DBerror(sock, "when doing refresh");
+ DB_error(sock, "when doing refresh");
/* We shall continue here, if --force was given */
}
while ((table= getTableName(0)))
@@ -2088,9 +2140,9 @@ static int dump_all_tables_in_db(char *database)
char *end= strmov(afterdot, table);
if (include_table(hash_key, end - hash_key))
{
- numrows = getTableStructure(table, database);
+ numrows = get_table_structure(table, database);
if (!dFlag && numrows > 0)
- dumpTable(numrows,table);
+ dump_table(numrows,table);
my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
order_by= 0;
}
@@ -2107,6 +2159,61 @@ static int dump_all_tables_in_db(char *database)
/*
+ dump structure of views of database
+
+ SYNOPSIS
+ dump_all_views_in_db()
+ database database name
+
+ RETURN
+ 0 OK
+ 1 ERROR
+*/
+
+static my_bool dump_all_views_in_db(char *database)
+{
+ char *table;
+ uint numrows;
+ char table_buff[NAME_LEN*2+3];
+
+ if (init_dumping(database))
+ return 1;
+ if (opt_xml)
+ print_xml_tag1(md_result_file, "", "database name=", database, "\n");
+ if (lock_tables)
+ {
+ DYNAMIC_STRING query;
+ init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
+ for (numrows= 0 ; (table= getTableName(1)); numrows++)
+ {
+ dynstr_append(&query, quote_name(table, table_buff, 1));
+ dynstr_append(&query, " READ /*!32311 LOCAL */,");
+ }
+ if (numrows && mysql_real_query(sock, query.str, query.length-1))
+ DB_error(sock, "when using LOCK TABLES");
+ /* We shall continue here, if --force was given */
+ dynstr_free(&query);
+ }
+ if (flush_logs)
+ {
+ if (mysql_refresh(sock, REFRESH_LOG))
+ DB_error(sock, "when doing refresh");
+ /* We shall continue here, if --force was given */
+ }
+ while ((table= getTableName(0)))
+ get_view_structure(table, database);
+ if (opt_xml)
+ {
+ fputs("</database>\n", md_result_file);
+ check_io(md_result_file);
+ }
+ if (lock_tables)
+ mysql_query(sock,"UNLOCK TABLES");
+ return 0;
+} /* dump_all_tables_in_db */
+
+
+/*
get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
table name from the server for the table name given on the command line.
we do this because the table name given on the command line may be a
@@ -2121,7 +2228,7 @@ static int get_actual_table_name(const char *old_table_name,
int buf_size)
{
int retval;
- MYSQL_RES *tableRes;
+ MYSQL_RES *table_res;
MYSQL_ROW row;
char query[50 + 2*NAME_LEN];
char show_name_buff[FN_REFLEN];
@@ -2137,18 +2244,22 @@ static int get_actual_table_name(const char *old_table_name,
safe_exit(EX_MYSQLERR);
}
- tableRes= mysql_store_result( sock );
retval = 1;
- if (tableRes != NULL)
+
+ if ((table_res= mysql_store_result(sock)))
{
- my_ulonglong numRows = mysql_num_rows(tableRes);
- if (numRows > 0)
- {
- row= mysql_fetch_row( tableRes );
- strmake(new_table_name, row[0], buf_size-1);
- retval = 0;
- }
- mysql_free_result(tableRes);
+ my_ulonglong num_rows= mysql_num_rows(table_res);
+ if (num_rows > 0)
+ {
+ /*
+ Return first row
+ TODO: Return all matching rows
+ */
+ row= mysql_fetch_row(table_res);
+ strmake(new_table_name, row[0], buf_size-1);
+ retval= 0;
+ }
+ mysql_free_result(table_res);
}
return retval;
}
@@ -2157,6 +2268,7 @@ 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;
char table_buff[NAME_LEN*+3];
if (init_dumping(db))
@@ -2164,7 +2276,6 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
if (lock_tables)
{
DYNAMIC_STRING query;
- int i;
init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
for (i=0 ; i < tables ; i++)
@@ -2173,32 +2284,37 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
dynstr_append(&query, " READ /*!32311 LOCAL */,");
}
if (mysql_real_query(sock, query.str, query.length-1))
- DBerror(sock, "when doing LOCK TABLES");
+ DB_error(sock, "when doing LOCK TABLES");
/* We shall countinue here, if --force was given */
dynstr_free(&query);
}
if (flush_logs)
{
if (mysql_refresh(sock, REFRESH_LOG))
- DBerror(sock, "when doing refresh");
+ DB_error(sock, "when doing refresh");
/* We shall countinue here, if --force was given */
}
if (opt_xml)
print_xml_tag1(md_result_file, "", "database name=", db, "\n");
- for (; tables > 0 ; tables-- , table_names++)
+ for (i=0 ; i < tables ; i++)
{
- char new_table_name[NAME_LEN];
+ char new_table_name[NAME_LEN];
- /* the table name passed on commandline may be wrong case */
- if (!get_actual_table_name( *table_names, new_table_name, sizeof(new_table_name) ))
- {
- numrows = getTableStructure(new_table_name, db);
- if (!dFlag && numrows > 0)
- dumpTable(numrows, new_table_name);
- }
+ /* 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;
}
+ if (was_views)
+ {
+ for (i=0 ; i < tables ; i++)
+ get_view_structure(table_names[i], db);
+ }
if (opt_xml)
{
fputs("</database>\n", md_result_file);
@@ -2410,9 +2526,14 @@ static const char *check_if_ignore_table(const char *table_name)
mysql_free_result(res);
return 0; /* assume table is ok */
}
- if (strcmp(row[1], (result= "MRG_MyISAM")) &&
- strcmp(row[1], (result= "MRG_ISAM")))
- result= 0;
+ if (!(row[1]))
+ result= "VIEW";
+ else
+ {
+ if (strcmp(row[1], (result= "MRG_MyISAM")) &&
+ strcmp(row[1], (result= "MRG_ISAM")))
+ result= 0;
+ }
mysql_free_result(res);
return result;
}
@@ -2493,6 +2614,100 @@ cleanup:
}
+/*
+ Getting VIEW structure
+
+ SYNOPSIS
+ get_view_structure()
+ table view name
+ db db name
+
+ RETURN
+ 0 OK
+ 1 ERROR
+*/
+
+static my_bool get_view_structure(char *table, char* db)
+{
+ MYSQL_RES *table_res;
+ MYSQL_ROW row;
+ MYSQL_FIELD *field;
+ char *result_table, *opt_quoted_table;
+ char table_buff[NAME_LEN*2+3];
+ char table_buff2[NAME_LEN*2+3];
+ char buff[20+FN_REFLEN];
+ FILE *sql_file = md_result_file;
+ DBUG_ENTER("get_view_structure");
+
+ if (tFlag)
+ DBUG_RETURN(0);
+
+ if (verbose)
+ fprintf(stderr, "-- Retrieving view structure for table %s...\n", table);
+
+ sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
+ (opt_quoted || opt_keywords));
+ result_table= quote_name(table, table_buff, 1);
+ opt_quoted_table= quote_name(table, table_buff2, 0);
+
+ sprintf(buff,"show create table %s", result_table);
+ if (mysql_query(sock, buff))
+ {
+ fprintf(stderr, "%s: Can't get CREATE TABLE for view %s (%s)\n",
+ my_progname, result_table, mysql_error(sock));
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
+ }
+
+ if (path)
+ {
+ char filename[FN_REFLEN], tmp_path[FN_REFLEN];
+ convert_dirname(tmp_path,path,NullS);
+ sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
+ O_WRONLY, MYF(MY_WME));
+ if (!sql_file) /* If file couldn't be opened */
+ {
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(1);
+ }
+ write_header(sql_file, db);
+ }
+ table_res= mysql_store_result(sock);
+ field= mysql_fetch_field_direct(table_res, 0);
+ if (strcmp(field->name, "View") != 0)
+ {
+ if (verbose)
+ fprintf(stderr, "-- It's base table, skipped\n");
+ DBUG_RETURN(0);
+ }
+
+ if (!opt_xml && opt_comments)
+ {
+ fprintf(sql_file, "\n--\n-- View structure for view %s\n--\n\n",
+ result_table);
+ check_io(sql_file);
+ }
+ if (opt_drop)
+ {
+ fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table);
+ check_io(sql_file);
+ }
+
+ row= mysql_fetch_row(table_res);
+ fprintf(sql_file, "%s;\n", row[1]);
+ check_io(sql_file);
+ mysql_free_result(table_res);
+
+ if (sql_file != md_result_file)
+ {
+ fputs("\n", sql_file);
+ write_footer(sql_file);
+ my_fclose(sql_file, MYF(MY_WME));
+ }
+ DBUG_RETURN(0);
+}
+
+
int main(int argc, char **argv)
{
compatible_mode_normal_str[0]= 0;
diff --git a/client/mysqlimport.c b/client/mysqlimport.c
index fae84be610a..3552f03fb27 100644
--- a/client/mysqlimport.c
+++ b/client/mysqlimport.c
@@ -388,6 +388,7 @@ static MYSQL *db_connect(char *host, char *database, char *user, char *passwd)
ignore_errors=0; /* NO RETURN FROM db_error */
db_error(&mysql_connection);
}
+ mysql_connection.reconnect= 0;
if (verbose)
fprintf(stdout, "Selecting database %s\n", database);
if (mysql_select_db(sock, database))
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
index ee478058cdc..5631d296a54 100644
--- a/client/mysqlshow.c
+++ b/client/mysqlshow.c
@@ -28,7 +28,8 @@
#include <sslopt-vars.h>
static my_string host=0,opt_password=0,user=0;
-static my_bool opt_show_keys=0,opt_compress=0,opt_status=0, tty_password=0;
+static my_bool opt_show_keys= 0, opt_compress= 0, opt_status= 0,
+ tty_password= 0, opt_table_type= 0;
static uint opt_verbose=0;
static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
@@ -125,6 +126,7 @@ int main(int argc, char **argv)
fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql));
exit(1);
}
+ mysql.reconnect= 1;
switch (argc)
{
@@ -192,6 +194,9 @@ static struct my_option my_long_options[] =
"Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
+ {"show-table-type", 't', "Show table type column.",
+ (gptr*) &opt_table_type, (gptr*) &opt_table_type, 0, GET_BOOL,
+ NO_ARG, 0, 0, 0, 0, 0, 0},
{"socket", 'S', "Socket file to use for connection.",
(gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -417,7 +422,7 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
{
const char *header;
uint head_length, counter = 0;
- char query[255], rows[64], fields[16];
+ char query[255], rows[NAME_LEN], fields[16];
MYSQL_FIELD *field;
MYSQL_RES *result;
MYSQL_ROW row, rrow;
@@ -428,7 +433,20 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
mysql_error(mysql));
return 1;
}
- if (!(result=mysql_list_tables(mysql,table)))
+ if (table)
+ {
+ /*
+ We just hijack the 'rows' variable for a bit to store the escaped
+ table name
+ */
+ mysql_escape_string(rows, table, sizeof(rows));
+ my_snprintf(query, sizeof(query), "show%s tables like '%s'",
+ opt_table_type ? " full" : "", rows);
+ }
+ else
+ my_snprintf(query, sizeof(query), "show%s tables",
+ opt_table_type ? " full" : "");
+ if (mysql_query(mysql, query) || !(result= mysql_store_result(mysql)))
{
fprintf(stderr,"%s: Cannot list tables in %s: %s\n",my_progname,db,
mysql_error(mysql));
@@ -445,12 +463,27 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
if (head_length < field->max_length)
head_length=field->max_length;
- if (!opt_verbose)
- print_header(header,head_length,NullS);
- else if (opt_verbose == 1)
- print_header(header,head_length,"Columns",8,NullS);
+ if (opt_table_type)
+ {
+ if (!opt_verbose)
+ print_header(header,head_length,"table_type",10,NullS);
+ else if (opt_verbose == 1)
+ print_header(header,head_length,"table_type",10,"Columns",8,NullS);
+ else
+ {
+ print_header(header,head_length,"table_type",10,"Columns",8,
+ "Total Rows",10,NullS);
+ }
+ }
else
- print_header(header,head_length,"Columns",8, "Total Rows",10,NullS);
+ {
+ if (!opt_verbose)
+ print_header(header,head_length,NullS);
+ else if (opt_verbose == 1)
+ print_header(header,head_length,"Columns",8,NullS);
+ else
+ print_header(header,head_length,"Columns",8, "Total Rows",10,NullS);
+ }
while ((row = mysql_fetch_row(result)))
{
@@ -499,17 +532,31 @@ list_tables(MYSQL *mysql,const char *db,const char *table)
strmov(rows,"N/A");
}
}
- if (!opt_verbose)
- print_row(row[0],head_length,NullS);
- else if (opt_verbose == 1)
- print_row(row[0],head_length, fields,8, NullS);
- else
- print_row(row[0],head_length, fields,8, rows,10, NullS);
+ if (opt_table_type)
+ {
+ if (!opt_verbose)
+ print_row(row[0],head_length,row[1],10,NullS);
+ else if (opt_verbose == 1)
+ print_row(row[0],head_length,row[1],10,fields,8,NullS);
+ else
+ print_row(row[0],head_length,row[1],10,fields,8,rows,10,NullS);
+ }
+ else
+ {
+ if (!opt_verbose)
+ print_row(row[0],head_length,NullS);
+ else if (opt_verbose == 1)
+ print_row(row[0],head_length, fields,8, NullS);
+ else
+ print_row(row[0],head_length, fields,8, rows,10, NullS);
+ }
}
print_trailer(head_length,
- (opt_verbose > 0 ? 8 : 0),
- (opt_verbose > 1 ? 10 :0),
+ (opt_table_type ? 10 : opt_verbose > 0 ? 8 : 0),
+ (opt_table_type ? (opt_verbose > 0 ? 8 : 0)
+ : (opt_verbose > 1 ? 10 :0)),
+ !opt_table_type ? 0 : opt_verbose > 1 ? 10 :0,
0);
if (counter && opt_verbose)
@@ -564,6 +611,7 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
char query[1024],*end;
MYSQL_RES *result;
MYSQL_ROW row;
+ ulong rows;
if (mysql_select_db(mysql,db))
{
@@ -571,6 +619,17 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
mysql_error(mysql));
return 1;
}
+ sprintf(query,"select count(*) from `%s`", table);
+ if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
+ {
+ fprintf(stderr,"%s: Cannot get record count for db: %s, table: %s: %s\n",
+ my_progname,db,table,mysql_error(mysql));
+ return 1;
+ }
+ row = mysql_fetch_row(result);
+ rows = (ulong) strtoull(row[0], (char**) 0, 10);
+ mysql_free_result(result);
+
end=strmov(strmov(strmov(query,"show /*!32332 FULL */ columns from `"),table),"`");
if (wild && wild[0])
strxmov(end," like '",wild,"'",NullS);
@@ -581,8 +640,8 @@ list_fields(MYSQL *mysql,const char *db,const char *table,
return 1;
}
- printf("Database: %s Table: %s Rows: %lu", db,table,
- (ulong) mysql->extra_info);
+ printf("Database: %s Table: %s Rows: %lu", db, table, rows);
+
if (wild && wild[0])
printf(" Wildcard: %s",wild);
putchar('\n');
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 3eab182a74d..4991e565594 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -123,6 +123,17 @@ typedef struct
} code;
} match_err;
+typedef struct
+{
+ const char *name;
+ long code;
+} st_error;
+
+static st_error global_error[] = {
+#include <mysqld_ername.h>
+ { 0, 0 }
+};
+
static match_err global_expected_errno[MAX_EXPECTED_ERRORS];
static uint global_expected_errors;
@@ -242,6 +253,7 @@ VAR var_reg[10];
/*Perl/shell-like variable registers */
HASH var_hash;
my_bool disable_query_log=0, disable_result_log=0, disable_warnings=0;
+my_bool disable_ps_warnings= 0;
my_bool disable_info= 1; /* By default off */
my_bool abort_on_error= 1;
@@ -272,6 +284,7 @@ Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER,
Q_WAIT_FOR_SLAVE_TO_STOP,
Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
+Q_ENABLE_PS_WARNINGS, Q_DISABLE_PS_WARNINGS,
Q_ENABLE_INFO, Q_DISABLE_INFO,
Q_ENABLE_METADATA, Q_DISABLE_METADATA,
Q_EXEC, Q_DELIMITER,
@@ -280,6 +293,7 @@ Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS,
Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL,
Q_START_TIMER, Q_END_TIMER,
Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL,
+Q_EXIT,
Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
Q_UNKNOWN, /* Unknown command. */
@@ -349,6 +363,8 @@ const char *command_names[]=
"wait_for_slave_to_stop",
"enable_warnings",
"disable_warnings",
+ "enable_ps_warnings",
+ "disable_ps_warnings",
"enable_info",
"disable_info",
"enable_metadata",
@@ -366,6 +382,7 @@ const char *command_names[]=
"character_set",
"disable_ps_protocol",
"enable_ps_protocol",
+ "exit",
"disable_reconnect",
"enable_reconnect",
0
@@ -438,6 +455,10 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
#endif
static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
int len);
+static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
+static int normal_handle_error(const char *query, struct st_query *q,
+ MYSQL *mysql, DYNAMIC_STRING *ds);
+static int normal_handle_no_error(struct st_query *q);
static void do_eval(DYNAMIC_STRING* query_eval, const char* query)
{
@@ -624,6 +645,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname)
{
DBUG_PRINT("info",("Size differs: result size: %u file size: %u",
ds->length, stat_info.st_size));
+ DBUG_PRINT("info",("result: '%s'", ds->str));
DBUG_RETURN(2);
}
if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME))))
@@ -670,6 +692,7 @@ static int check_result(DYNAMIC_STRING* ds, const char* fname,
{
int error = 0;
int res=dyn_string_cmp(ds, fname);
+ DBUG_ENTER("check_result");
if (res && require_option)
abort_not_supported_test();
@@ -689,7 +712,7 @@ static int check_result(DYNAMIC_STRING* ds, const char* fname,
}
if (error)
reject_dump(fname, ds->str, ds->length);
- return error;
+ DBUG_RETURN(error);
}
@@ -781,7 +804,7 @@ int var_set(const char *var_name, const char *var_name_end,
}
else
v = var_reg + digit;
- return eval_expr(v, var_val, (const char**)&var_val_end);
+ DBUG_RETURN(eval_expr(v, var_val, (const char**)&var_val_end));
}
@@ -952,7 +975,7 @@ static void do_exec(struct st_query* q)
ds= &ds_res;
while (fgets(buf, sizeof(buf), res_file))
- replace_dynstr_append_mem(ds, buf, strlen(buf));
+ replace_dynstr_append(ds, buf);
}
error= pclose(res_file);
@@ -1337,6 +1360,7 @@ static uint get_errcodes(match_err *to,struct st_query* q)
{
char* p= q->first_argument;
uint count= 0;
+
DBUG_ENTER("get_errcodes");
if (!*p)
@@ -1347,19 +1371,41 @@ static uint get_errcodes(match_err *to,struct st_query* q)
if (*p == 'S')
{
/* SQLSTATE string */
- int i;
- p++;
- for (i = 0; my_isalnum(charset_info, *p) && i < SQLSTATE_LENGTH; p++, i++)
- to[count].code.sqlstate[i]= *p;
- to[count].code.sqlstate[i]= '\0';
+ char *end= ++p + SQLSTATE_LENGTH;
+ char *to_ptr= to[count].code.sqlstate;
+
+ for (; my_isalnum(charset_info, *p) && p != end; p++)
+ *to_ptr++= *p;
+ *to_ptr= 0;
+
to[count].type= ERR_SQLSTATE;
}
+ else if (*p == 'E')
+ {
+ /* SQL error as string */
+ st_error *e= global_error;
+ char *start= p++;
+
+ for (; *p == '_' || my_isalnum(charset_info, *p); p++)
+ ;
+ for (; e->name; e++)
+ {
+ if (!strncmp(start, e->name, (int) (p - start)))
+ {
+ to[count].code.errnum= (uint) e->code;
+ to[count].type= ERR_ERRNO;
+ break;
+ }
+ }
+ if (!e->name)
+ die("Unknown SQL error '%s'\n", start);
+ }
else
{
long val;
- p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val);
- if (p == NULL)
- die("Invalid argument in %s\n", q->query);
+
+ if (!(p= str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val)))
+ die("Invalid argument in %s\n", q->query);
to[count].code.errnum= (uint) val;
to[count].type= ERR_ERRNO;
}
@@ -1614,6 +1660,29 @@ void init_manager()
}
#endif
+
+/*
+ Connect to a server doing several retries if needed.
+
+ SYNOPSIS
+ safe_connect()
+ con - connection structure to be used
+ host, user, pass, - connection parameters
+ db, port, sock
+
+ NOTE
+ This function will try to connect to the given server MAX_CON_TRIES
+ times and sleep CON_RETRY_SLEEP seconds between attempts before
+ finally giving up. This helps in situation when the client starts
+ before the server (which happens sometimes).
+ It will ignore any errors during these retries. One should use
+ connect_n_handle_errors() if he expects a connection error and wants
+ handle as if it was an error from a usual statement.
+
+ RETURN VALUE
+ 0 - success, non-0 - failure
+*/
+
int safe_connect(MYSQL* con, const char* host, const char* user,
const char* pass,
const char* db, int port, const char* sock)
@@ -1630,10 +1699,129 @@ int safe_connect(MYSQL* con, const char* host, const char* user,
}
sleep(CON_RETRY_SLEEP);
}
+ /*
+ TODO: change this to 0 in future versions, but the 'kill' test relies on
+ existing behavior
+ */
+ con->reconnect= 1;
return con_error;
}
+/*
+ Connect to a server and handle connection errors in case when they occur.
+
+ SYNOPSIS
+ connect_n_handle_errors()
+ q - context of connect "query" (command)
+ con - connection structure to be used
+ host, user, pass, - connection parameters
+ db, port, sock
+ create_conn - out parameter, set to zero if connection was
+ not established and is not touched otherwise
+
+ DESCRIPTION
+ This function will try to establish a connection to server and handle
+ possible errors in the same manner as if "connect" was usual SQL-statement
+ (If error is expected it will ignore it once it occurs and log the
+ "statement" to the query log).
+ Unlike safe_connect() it won't do several attempts.
+
+ RETURN VALUE
+ 0 - success, non-0 - failure
+*/
+
+int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host,
+ const char* user, const char* pass,
+ const char* db, int port, const char* sock,
+ int* create_conn)
+{
+ DYNAMIC_STRING ds_tmp, *ds;
+ int error= 0;
+
+ /*
+ Altough we ignore --require or --result before connect() command we still
+ need to handle record_file because of "@result_file sql-command" syntax.
+ */
+ if (q->record_file[0])
+ {
+ init_dynamic_string(&ds_tmp, "", 16384, 65536);
+ ds= &ds_tmp;
+ }
+ else
+ ds= &ds_res;
+
+ if (!disable_query_log)
+ {
+ /*
+ It is nice to have connect() statement logged in result file
+ in this case.
+ QQ: Should we do this only if we are expecting an error ?
+ */
+ char port_buff[22]; /* This should be enough for any int */
+ char *port_end;
+ dynstr_append_mem(ds, "connect(", 8);
+ replace_dynstr_append(ds, host);
+ dynstr_append_mem(ds, ",", 1);
+ replace_dynstr_append(ds, user);
+ dynstr_append_mem(ds, ",", 1);
+ replace_dynstr_append(ds, pass);
+ dynstr_append_mem(ds, ",", 1);
+ if (db)
+ replace_dynstr_append(ds, db);
+ dynstr_append_mem(ds, ",", 1);
+ port_end= int10_to_str(port, port_buff, 10);
+ replace_dynstr_append_mem(ds, port_buff, port_end - port_buff);
+ dynstr_append_mem(ds, ",", 1);
+ if (sock)
+ replace_dynstr_append(ds, sock);
+ dynstr_append_mem(ds, ")", 1);
+ dynstr_append_mem(ds, delimiter, delimiter_length);
+ dynstr_append_mem(ds, "\n", 1);
+ }
+ if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
+ CLIENT_MULTI_STATEMENTS))
+ {
+ error= normal_handle_error("connect", q, con, ds);
+ *create_conn= 0;
+ goto err;
+ }
+ else if (normal_handle_no_error(q))
+ {
+ /*
+ Fail if there was no error but we expected it.
+ We also don't want to have connection in this case.
+ */
+ mysql_close(con);
+ *create_conn= 0;
+ error= 1;
+ goto err;
+ }
+
+ /*
+ TODO: change this to 0 in future versions, but the 'kill' test relies on
+ existing behavior
+ */
+ con->reconnect= 1;
+
+ if (record)
+ {
+ if (!q->record_file[0] && !result_file)
+ die("At line %u: Missing result file", start_lineno);
+ if (!result_file)
+ str_to_file(q->record_file, ds->str, ds->length);
+ }
+ else if (q->record_file[0])
+ error|= check_result(ds, q->record_file, q->require_file);
+
+err:
+ free_replace();
+ if (ds == &ds_tmp)
+ dynstr_free(&ds_tmp);
+ return error;
+}
+
+
int do_connect(struct st_query* q)
{
char* con_name, *con_user,*con_pass, *con_host, *con_port_str,
@@ -1642,6 +1830,8 @@ int do_connect(struct st_query* q)
char buff[FN_REFLEN];
int con_port;
int free_con_sock = 0;
+ int error= 0;
+ int create_conn= 1;
DBUG_ENTER("do_connect");
DBUG_PRINT("enter",("connect: %s",p));
@@ -1706,18 +1896,28 @@ int do_connect(struct st_query* q)
/* Special database to allow one to connect without a database name */
if (con_db && !strcmp(con_db,"*NO-ONE*"))
con_db=0;
- if ((safe_connect(&next_con->mysql, con_host,
- con_user, con_pass,
- con_db, con_port, con_sock ? con_sock: 0)))
- die("Could not open connection '%s': %s", con_name,
- mysql_error(&next_con->mysql));
- if (!(next_con->name = my_strdup(con_name, MYF(MY_WME))))
- die(NullS);
- cur_con = next_con++;
+ if (q->abort_on_error)
+ {
+ if ((safe_connect(&next_con->mysql, con_host, con_user, con_pass,
+ con_db, con_port, con_sock ? con_sock: 0)))
+ die("Could not open connection '%s': %s", con_name,
+ mysql_error(&next_con->mysql));
+ }
+ else
+ error= connect_n_handle_errors(q, &next_con->mysql, con_host, con_user,
+ con_pass, con_db, con_port, con_sock,
+ &create_conn);
+
+ if (create_conn)
+ {
+ if (!(next_con->name= my_strdup(con_name, MYF(MY_WME))))
+ die(NullS);
+ cur_con= next_con++;
+ }
if (free_con_sock)
my_free(con_sock, MYF(MY_WME));
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -1844,7 +2044,10 @@ int read_line(char* buf, int size)
cur_file--;
lineno--;
if (cur_file == file_stack)
+ {
+ DBUG_PRINT("info", ("end of file"));
DBUG_RETURN(1);
+ }
continue;
}
@@ -2014,7 +2217,6 @@ int read_query(struct st_query** q_ptr)
q->query_buf= q->query= 0;
if (read_line(read_query_buf, sizeof(read_query_buf)))
{
- DBUG_PRINT("warning",("too long query"));
DBUG_RETURN(1);
}
DBUG_PRINT("info", ("query: %s", read_query_buf));
@@ -2195,6 +2397,8 @@ void usage()
#include <help_end.h>
+#include <help_end.h>
+
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
@@ -2359,6 +2563,13 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
dynstr_append_mem(ds, val, len);
}
+/* Append zero-terminated string to ds, with optional replace */
+
+static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val)
+{
+ replace_dynstr_append_mem(ds, val, strlen(val));
+}
+
/*
Append all results to the dynamic string separated with '\t'
@@ -2505,93 +2716,14 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
(!(last_result= res= mysql_store_result(mysql)) &&
mysql_field_count(mysql)))
{
- if (q->require_file)
- {
- abort_not_supported_test();
- }
- if (q->abort_on_error)
- die("At line %u: query '%s' failed: %d: %s", start_lineno, query,
- mysql_errno(mysql), mysql_error(mysql));
- else
- {
- for (i=0 ; (uint) i < q->expected_errors ; i++)
- {
- if (((q->expected_errno[i].type == ERR_ERRNO) &&
- (q->expected_errno[i].code.errnum == mysql_errno(mysql))) ||
- ((q->expected_errno[i].type == ERR_SQLSTATE) &&
- (strcmp(q->expected_errno[i].code.sqlstate,mysql_sqlstate(mysql)) == 0)))
- {
- if (i == 0 && q->expected_errors == 1)
- {
- /* Only log error if there is one possible error */
- dynstr_append_mem(ds,"ERROR ",6);
- replace_dynstr_append_mem(ds, mysql_sqlstate(mysql),
- strlen(mysql_sqlstate(mysql)));
- dynstr_append_mem(ds, ": ", 2);
- replace_dynstr_append_mem(ds,mysql_error(mysql),
- strlen(mysql_error(mysql)));
- dynstr_append_mem(ds,"\n",1);
- }
- /* Don't log error if we may not get an error */
- else if (q->expected_errno[0].type == ERR_SQLSTATE ||
- (q->expected_errno[0].type == ERR_ERRNO &&
- q->expected_errno[0].code.errnum != 0))
- dynstr_append(ds,"Got one of the listed errors\n");
- goto end; /* Ok */
- }
- }
- DBUG_PRINT("info",("i: %d expected_errors: %d", i,
- q->expected_errors));
- dynstr_append_mem(ds, "ERROR ",6);
- replace_dynstr_append_mem(ds, mysql_sqlstate(mysql),
- strlen(mysql_sqlstate(mysql)));
- dynstr_append_mem(ds,": ",2);
- replace_dynstr_append_mem(ds, mysql_error(mysql),
- strlen(mysql_error(mysql)));
- dynstr_append_mem(ds,"\n",1);
- if (i)
- {
- if (q->expected_errno[0].type == ERR_ERRNO)
- verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
- q->query, mysql_errno(mysql), q->expected_errno[0].code.errnum);
- else
- verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...",
- q->query, mysql_sqlstate(mysql), q->expected_errno[0].code.sqlstate);
- error= 1;
- goto end;
- }
- verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql),
- mysql_error(mysql));
- /*
- if we do not abort on error, failure to run the query does
- not fail the whole test case
- */
- goto end;
- }
- /*{
- verbose_msg("failed in mysql_store_result for query '%s' (%d)", query,
- mysql_errno(mysql));
- error = 1;
- goto end;
- }*/
- }
-
- 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 */
- verbose_msg("query '%s' succeeded - should have failed with errno %d...",
- q->query, q->expected_errno[0].code.errnum);
- error = 1;
+ if (normal_handle_error(query, q, mysql, ds))
+ error= 1;
goto end;
}
- else if (q->expected_errno[0].type == ERR_SQLSTATE &&
- strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
+
+ if (normal_handle_no_error(q))
{
- /* SQLSTATE we wanted was != "00000", i.e. not an expected success */
- verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...",
- q->query, q->expected_errno[0].code.sqlstate);
- error = 1;
+ error= 1;
goto end;
}
@@ -2611,16 +2743,20 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
{
if (i)
dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append_mem(ds, field[i].name,
- strlen(field[i].name));
+ replace_dynstr_append(ds, field[i].name);
}
dynstr_append_mem(ds, "\n", 1);
}
append_result(ds, res);
}
- /* Add all warnings to the result */
- if (!disable_warnings && mysql_warning_count(mysql))
+ /*
+ Add all warnings to the result. We can't do this if we are in
+ the middle of processing results from multi-statement, because
+ this will break protocol.
+ */
+ if (!disable_warnings && !mysql_more_results(mysql) &&
+ mysql_warning_count(mysql))
{
MYSQL_RES *warn_res=0;
uint count= mysql_warning_count(mysql);
@@ -2689,6 +2825,136 @@ end:
}
+/*
+ Handle errors which occurred after execution of conventional (non-prepared)
+ statement.
+
+ SYNOPSIS
+ normal_handle_error()
+ query - query string
+ q - query context
+ mysql - connection through which query was sent to server
+ ds - dynamic string which is used for output buffer
+
+ NOTE
+ If there is an unexpected error this function will abort mysqltest
+ immediately.
+
+ RETURN VALUE
+ 0 - OK
+ 1 - Some other error was expected.
+*/
+
+static int normal_handle_error(const char *query, struct st_query *q,
+ MYSQL *mysql, DYNAMIC_STRING *ds)
+{
+ uint i;
+
+ DBUG_ENTER("normal_handle_error");
+
+ if (q->require_file)
+ abort_not_supported_test();
+
+ if (q->abort_on_error)
+ die("At line %u: query '%s' failed: %d: %s", start_lineno, query,
+ mysql_errno(mysql), mysql_error(mysql));
+ else
+ {
+ for (i= 0 ; (uint) i < q->expected_errors ; i++)
+ {
+ if (((q->expected_errno[i].type == ERR_ERRNO) &&
+ (q->expected_errno[i].code.errnum == mysql_errno(mysql))) ||
+ ((q->expected_errno[i].type == ERR_SQLSTATE) &&
+ (strcmp(q->expected_errno[i].code.sqlstate, mysql_sqlstate(mysql)) == 0)))
+ {
+ if (q->expected_errors == 1)
+ {
+ /* Only log error if there is one possible error */
+ dynstr_append_mem(ds, "ERROR ", 6);
+ replace_dynstr_append(ds, mysql_sqlstate(mysql));
+ dynstr_append_mem(ds, ": ", 2);
+ replace_dynstr_append(ds, mysql_error(mysql));
+ dynstr_append_mem(ds,"\n",1);
+ }
+ /* Don't log error if we may not get an error */
+ else if (q->expected_errno[0].type == ERR_SQLSTATE ||
+ (q->expected_errno[0].type == ERR_ERRNO &&
+ q->expected_errno[0].code.errnum != 0))
+ dynstr_append(ds,"Got one of the listed errors\n");
+ /* OK */
+ DBUG_RETURN(0);
+ }
+ }
+
+ DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors));
+
+ dynstr_append_mem(ds, "ERROR ",6);
+ replace_dynstr_append(ds, mysql_sqlstate(mysql));
+ dynstr_append_mem(ds, ": ", 2);
+ replace_dynstr_append(ds, mysql_error(mysql));
+ dynstr_append_mem(ds, "\n", 1);
+
+ if (i)
+ {
+ if (q->expected_errno[0].type == ERR_ERRNO)
+ verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
+ q->query, mysql_errno(mysql),
+ q->expected_errno[0].code.errnum);
+ else
+ verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...",
+ q->query, mysql_sqlstate(mysql),
+ q->expected_errno[0].code.sqlstate);
+ DBUG_RETURN(1);
+ }
+
+ /*
+ If we do not abort on error, failure to run the query does not fail the
+ whole test case.
+ */
+ verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql),
+ mysql_error(mysql));
+ DBUG_RETURN(0);
+ }
+ return 0; /* Keep compiler happy */
+}
+
+
+/*
+ Handle absence of errors after execution of convetional statement.
+
+ SYNOPSIS
+ normal_handle_error()
+ q - context of query
+
+ RETURN VALUE
+ 0 - OK
+ 1 - Some error was expected from this query.
+*/
+
+static int normal_handle_no_error(struct st_query *q)
+{
+ DBUG_ENTER("normal_handle_no_error");
+
+ 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 */
+ verbose_msg("query '%s' succeeded - should have failed with errno %d...",
+ q->query, q->expected_errno[0].code.errnum);
+ DBUG_RETURN(1);
+ }
+ else if (q->expected_errno[0].type == ERR_SQLSTATE &&
+ strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
+ {
+ /* SQLSTATE we wanted was != "00000", i.e. not an expected success */
+ verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...",
+ q->query, q->expected_errno[0].code.sqlstate);
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(0);
+}
+
/****************************************************************************\
* If --ps-protocol run ordinary statements using prepared statemnt C API
\****************************************************************************/
@@ -2778,7 +3044,8 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
/* We may have got warnings already, collect them if any */
/* FIXME we only want this if the statement succeeds I think */
- run_query_stmt_handle_warnings(mysql, ds);
+ if (!disable_ps_warnings)
+ run_query_stmt_handle_warnings(mysql, ds);
/*
No need to call mysql_stmt_bind_param() because we have no
@@ -2882,8 +3149,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
{
if (col_idx)
dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append_mem(ds, field[col_idx].name,
- strlen(field[col_idx].name));
+ replace_dynstr_append(ds, field[col_idx].name);
}
dynstr_append_mem(ds, "\n", 1);
}
@@ -2899,7 +3165,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
/* Allocate array with bind structs, lengths and NULL flags */
bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
- MYF(MY_WME | MY_FAE));
+ MYF(MY_WME | MY_FAE | MY_ZEROFILL));
length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long),
MYF(MY_WME | MY_FAE));
is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
@@ -3106,6 +3372,13 @@ static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds)
if (!disable_warnings && (count= mysql_warning_count(mysql)))
{
+ /*
+ If one day we will support execution of multi-statements
+ through PS API we should not issue SHOW WARNINGS until
+ we have not read all results...
+ */
+ DBUG_ASSERT(!mysql_more_results(mysql));
+
if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0)
{
MYSQL_RES *warn_res= mysql_store_result(mysql);
@@ -3151,11 +3424,9 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q,
{
/* Only log error if there is one possible error */
dynstr_append_mem(ds,"ERROR ",6);
- replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt),
- strlen(mysql_stmt_sqlstate(stmt)));
+ replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt));
dynstr_append_mem(ds, ": ", 2);
- replace_dynstr_append_mem(ds,mysql_stmt_error(stmt),
- strlen(mysql_stmt_error(stmt)));
+ replace_dynstr_append(ds,mysql_stmt_error(stmt));
dynstr_append_mem(ds,"\n",1);
}
/* Don't log error if we may not get an error */
@@ -3169,11 +3440,9 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q,
DBUG_PRINT("info",("i: %d expected_errors: %d", i,
q->expected_errors));
dynstr_append_mem(ds, "ERROR ",6);
- replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt),
- strlen(mysql_stmt_sqlstate(stmt)));
+ replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt));
dynstr_append_mem(ds,": ",2);
- replace_dynstr_append_mem(ds, mysql_stmt_error(stmt),
- strlen(mysql_stmt_error(stmt)));
+ replace_dynstr_append(ds, mysql_stmt_error(stmt));
dynstr_append_mem(ds,"\n",1);
if (i)
{
@@ -3355,8 +3624,8 @@ static void init_var_hash(MYSQL *mysql)
if (hash_init(&var_hash, charset_info,
1024, 0, 0, get_var_key, var_free, MYF(0)))
die("Variable hash initialization failed");
- if (opt_big_test)
- my_hash_insert(&var_hash, (byte*) var_init(0,"BIG_TEST", 0, "1",0));
+ my_hash_insert(&var_hash, (byte*) var_init(0,"BIG_TEST", 0,
+ (opt_big_test) ? "1" : "0", 0));
v= var_init(0,"MAX_TABLES", 0, (sizeof(ulong) == 4) ? "31" : "62",0);
my_hash_insert(&var_hash, (byte*) v);
v= var_init(0,"SERVER_VERSION", 0, mysql_get_server_info(mysql), 0);
@@ -3371,12 +3640,9 @@ int main(int argc, char **argv)
{
int error = 0;
struct st_query *q;
- my_bool require_file=0, q_send_flag=0;
+ my_bool require_file=0, q_send_flag=0, abort_flag= 0;
char save_file[FN_REFLEN];
MY_INIT(argv[0]);
- {
- DBUG_ENTER("main");
- DBUG_PROCESS(argv[0]);
/* Use all time until exit if no explicit 'start_timer' */
timer_start= timer_now();
@@ -3403,6 +3669,8 @@ int main(int argc, char **argv)
*block_ok = 1;
init_dynamic_string(&ds_res, "", 0, 65536);
parse_args(argc, argv);
+
+ DBUG_PRINT("info",("result_file: '%s'", result_file ? result_file : ""));
if (mysql_server_init(embedded_server_arg_count,
embedded_server_args,
(char**) embedded_server_groups))
@@ -3447,7 +3715,7 @@ int main(int argc, char **argv)
*/
var_set_errno(-1);
- while (!read_query(&q))
+ while (!abort_flag && !read_query(&q))
{
int current_line_inc = 1, processed = 0;
if (q->type == Q_UNKNOWN || q->type == Q_COMMENT_WITH_COMMAND)
@@ -3456,7 +3724,9 @@ int main(int argc, char **argv)
{
processed = 1;
switch (q->type) {
- case Q_CONNECT: do_connect(q); break;
+ case Q_CONNECT:
+ error|= do_connect(q);
+ break;
case Q_CONNECTION: select_connection(q->first_argument); break;
case Q_DISCONNECT:
case Q_DIRTY_CLOSE:
@@ -3472,6 +3742,8 @@ int main(int argc, char **argv)
case Q_DISABLE_RESULT_LOG: disable_result_log=1; break;
case Q_ENABLE_WARNINGS: disable_warnings=0; break;
case Q_DISABLE_WARNINGS: disable_warnings=1; break;
+ case Q_ENABLE_PS_WARNINGS: disable_ps_warnings=0; break;
+ case Q_DISABLE_PS_WARNINGS: disable_ps_warnings=1; break;
case Q_ENABLE_INFO: disable_info=0; break;
case Q_DISABLE_INFO: disable_info=1; break;
case Q_ENABLE_METADATA: display_metadata=1; break;
@@ -3522,6 +3794,12 @@ int main(int argc, char **argv)
if (q->query == q->query_buf)
q->query += q->first_word_len + 1;
display_result_vertically= (q->type==Q_QUERY_VERTICAL);
+ if (save_file[0])
+ {
+ strmov(q->record_file,save_file);
+ q->require_file=require_file;
+ save_file[0]=0;
+ }
error|= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND);
display_result_vertically= old_display_result_vertically;
break;
@@ -3634,6 +3912,9 @@ int main(int argc, char **argv)
cur_con->mysql.reconnect= 1;
break;
+ case Q_EXIT:
+ abort_flag= 1;
+ break;
default: processed = 0; break;
}
}
@@ -3674,7 +3955,6 @@ int main(int argc, char **argv)
my_end(MY_CHECK_ERROR);
exit(error ? 1 : 0);
return error ? 1 : 0; /* Keep compiler happy */
- }
}
diff --git a/client/sql_string.cc b/client/sql_string.cc
index 9dcf19dad1d..0424723d97f 100644
--- a/client/sql_string.cc
+++ b/client/sql_string.cc
@@ -28,6 +28,11 @@
#include <floatingpoint.h>
#endif
+/*
+ The following extern declarations are ok as these are interface functions
+ required by the string function
+*/
+
extern gptr sql_alloc(unsigned size);
extern void sql_element_free(void *ptr);
@@ -97,14 +102,7 @@ bool String::set(longlong num, CHARSET_INFO *cs)
if (alloc(l))
return TRUE;
- if (cs->cset->snprintf == my_snprintf_8bit)
- {
- str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr);
- }
- else
- {
- str_length=cs->cset->snprintf(cs,Ptr,l,"%d",num);
- }
+ str_length=(uint32) (cs->cset->longlong10_to_str)(cs,Ptr,l,-10,num);
str_charset=cs;
return FALSE;
}
@@ -115,14 +113,7 @@ bool String::set(ulonglong num, CHARSET_INFO *cs)
if (alloc(l))
return TRUE;
- if (cs->cset->snprintf == my_snprintf_8bit)
- {
- str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr);
- }
- else
- {
- str_length=cs->cset->snprintf(cs,Ptr,l,"%d",num);
- }
+ str_length=(uint32) (cs->cset->longlong10_to_str)(cs,Ptr,l,10,num);
str_charset=cs;
return FALSE;
}
@@ -130,12 +121,13 @@ bool String::set(ulonglong num, CHARSET_INFO *cs)
bool String::set(double num,uint decimals, CHARSET_INFO *cs)
{
char buff[331];
+ uint dummy_errors;
str_charset=cs;
if (decimals >= NOT_FIXED_DEC)
{
- sprintf(buff,"%.14g",num); // Enough for a DATETIME
- return copy(buff, (uint32) strlen(buff), &my_charset_latin1, cs);
+ uint32 len= my_sprintf(buff,(buff, "%.14g",num));// Enough for a DATETIME
+ return copy(buff, len, &my_charset_latin1, cs, &dummy_errors);
}
#ifdef HAVE_FCONVERT
int decpt,sign;
@@ -150,7 +142,8 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs)
buff[0]='-';
pos=buff;
}
- return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs);
+ uint dummy_errors;
+ return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs, &dummy_errors);
}
if (alloc((uint32) ((uint32) decpt+3+decimals)))
return TRUE;
@@ -200,7 +193,8 @@ end:
#else
sprintf(buff,"%.*f",(int) decimals,num);
#endif
- return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs);
+ return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs,
+ &dummy_errors);
#endif
}
@@ -237,55 +231,163 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs)
return FALSE;
}
-/* Copy with charset convertion */
-bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *from, CHARSET_INFO *to)
+
+/*
+ Checks that the source string can be just copied to the destination string
+ without conversion.
+
+ SYNPOSIS
+
+ needs_conversion()
+ arg_length Length of string to copy.
+ from_cs Character set to copy from
+ to_cs Character set to copy to
+ uint32 *offset Returns number of unaligned characters.
+
+ RETURN
+ 0 No conversion needed
+ 1 Either character set conversion or adding leading zeros
+ (e.g. for UCS-2) must be done
+*/
+
+bool String::needs_conversion(uint32 arg_length,
+ CHARSET_INFO *from_cs,
+ CHARSET_INFO *to_cs,
+ uint32 *offset)
+{
+ *offset= 0;
+ if ((to_cs == &my_charset_bin) ||
+ (to_cs == from_cs) ||
+ my_charset_same(from_cs, to_cs) ||
+ ((from_cs == &my_charset_bin) &&
+ (!(*offset=(arg_length % to_cs->mbminlen)))))
+ return FALSE;
+ return TRUE;
+}
+
+
+/*
+ Copy a multi-byte character sets with adding leading zeros.
+
+ SYNOPSIS
+
+ copy_aligned()
+ str String to copy
+ arg_length Length of string. This should NOT be dividable with
+ cs->mbminlen.
+ offset arg_length % cs->mb_minlength
+ cs Character set for 'str'
+
+ NOTES
+ For real multi-byte, ascii incompatible charactser sets,
+ like UCS-2, add leading zeros if we have an incomplete character.
+ Thus,
+ SELECT _ucs2 0xAA
+ will automatically be converted into
+ SELECT _ucs2 0x00AA
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool String::copy_aligned(const char *str,uint32 arg_length, uint32 offset,
+ CHARSET_INFO *cs)
{
- uint32 new_length=to->mbmaxlen*arg_length;
- int cnvres;
- my_wc_t wc;
- const uchar *s=(const uchar *)str;
- const uchar *se=s+arg_length;
- uchar *d, *de;
+ /* How many bytes are in incomplete character */
+ offset= cs->mbmaxlen - offset; /* How many zeros we should prepend */
+ DBUG_ASSERT(offset && offset != cs->mbmaxlen);
- if (alloc(new_length))
+ uint32 aligned_length= arg_length + offset;
+ if (alloc(aligned_length))
return TRUE;
+
+ /*
+ Note, this is only safe for little-endian UCS-2.
+ If we add big-endian UCS-2 sometimes, this code
+ will be more complicated. But it's OK for now.
+ */
+ bzero((char*) Ptr, offset);
+ memcpy(Ptr + offset, str, arg_length);
+ Ptr[aligned_length]=0;
+ /* str_length is always >= 0 as arg_length is != 0 */
+ str_length= aligned_length;
+ str_charset= cs;
+ return FALSE;
+}
+
- d=(uchar *)Ptr;
- de=d+new_length;
+bool String::set_or_copy_aligned(const char *str,uint32 arg_length,
+ CHARSET_INFO *cs)
+{
+ /* How many bytes are in incomplete character */
+ uint32 offset= (arg_length % cs->mbminlen);
- for (str_length=new_length ; s < se && d < de ; )
+ if (!offset) /* All characters are complete, just copy */
{
- if ((cnvres=from->cset->mb_wc(from,&wc,s,se)) > 0 )
- {
- s+=cnvres;
- }
- else if (cnvres==MY_CS_ILSEQ)
- {
- s++;
- wc='?';
- }
- else
- break;
+ set(str, arg_length, cs);
+ return FALSE;
+ }
+ return copy_aligned(str, arg_length, offset, cs);
+}
-outp:
- if((cnvres=to->cset->wc_mb(to,wc,d,de)) >0 )
- {
- d+=cnvres;
- }
- else if (cnvres==MY_CS_ILUNI && wc!='?')
- {
- wc='?';
- goto outp;
- }
- else
- break;
+ /* Copy with charset convertion */
+
+bool String::copy(const char *str, uint32 arg_length,
+ CHARSET_INFO *from_cs, CHARSET_INFO *to_cs, uint *errors)
+{
+ uint32 offset;
+ if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
+ {
+ *errors= 0;
+ return copy(str, arg_length, to_cs);
+ }
+ if ((from_cs == &my_charset_bin) && offset)
+ {
+ *errors= 0;
+ return copy_aligned(str, arg_length, offset, to_cs);
}
- Ptr[new_length]=0;
- length((uint32) (d-(uchar *)Ptr));
- str_charset=to;
+ uint32 new_length= to_cs->mbmaxlen*arg_length;
+ if (alloc(new_length))
+ return TRUE;
+ str_length=copy_and_convert((char*) Ptr, new_length, to_cs,
+ str, arg_length, from_cs, errors);
+ str_charset=to_cs;
return FALSE;
}
+
+/*
+ Set a string to the value of a latin1-string, keeping the original charset
+
+ SYNOPSIS
+ copy_or_set()
+ str String of a simple charset (latin1)
+ arg_length Length of string
+
+ IMPLEMENTATION
+ If string object is of a simple character set, set it to point to the
+ given string.
+ If not, make a copy and convert it to the new character set.
+
+ RETURN
+ 0 ok
+ 1 Could not allocate result buffer
+
+*/
+
+bool String::set_ascii(const char *str, uint32 arg_length)
+{
+ if (str_charset->mbminlen == 1)
+ {
+ set(str, arg_length, str_charset);
+ return 0;
+ }
+ uint dummy_errors;
+ return copy(str, arg_length, &my_charset_latin1, str_charset, &dummy_errors);
+}
+
+
/* This is used by mysql.cc */
bool String::fill(uint32 max_length,char fill_char)
@@ -320,11 +422,34 @@ bool String::append(const String &s)
return FALSE;
}
+
+/*
+ Append an ASCII string to the a string of the current character set
+*/
+
bool String::append(const char *s,uint32 arg_length)
{
- if (!arg_length) // Default argument
- if (!(arg_length= (uint32) strlen(s)))
- return FALSE;
+ if (!arg_length)
+ return FALSE;
+
+ /*
+ For an ASCII incompatible string, e.g. UCS-2, we need to convert
+ */
+ if (str_charset->mbminlen > 1)
+ {
+ uint32 add_length=arg_length * str_charset->mbmaxlen;
+ uint dummy_errors;
+ if (realloc(str_length+ add_length))
+ return TRUE;
+ str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
+ s, arg_length, &my_charset_latin1,
+ &dummy_errors);
+ return FALSE;
+ }
+
+ /*
+ For an ASCII compatinble string we can just append.
+ */
if (realloc(str_length+arg_length))
return TRUE;
memcpy(Ptr+str_length,s,arg_length);
@@ -332,6 +457,46 @@ bool String::append(const char *s,uint32 arg_length)
return FALSE;
}
+
+/*
+ Append a 0-terminated ASCII string
+*/
+
+bool String::append(const char *s)
+{
+ return append(s, strlen(s));
+}
+
+
+/*
+ Append a string in the given charset to the string
+ with character set recoding
+*/
+
+bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs)
+{
+ uint32 dummy_offset;
+
+ if (needs_conversion(arg_length, cs, str_charset, &dummy_offset))
+ {
+ uint32 add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen;
+ uint dummy_errors;
+ if (realloc(str_length + add_length))
+ return TRUE;
+ str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
+ s, arg_length, cs, &dummy_errors);
+ }
+ else
+ {
+ if (realloc(str_length + arg_length))
+ return TRUE;
+ memcpy(Ptr + str_length, s, arg_length);
+ str_length+= arg_length;
+ }
+ return FALSE;
+}
+
+
#ifdef TO_BE_REMOVED
bool String::append(FILE* file, uint32 arg_length, myf my_flags)
{
@@ -360,48 +525,33 @@ bool String::append(IO_CACHE* file, uint32 arg_length)
return FALSE;
}
-uint32 String::numchars()
+bool String::append_with_prefill(const char *s,uint32 arg_length,
+ uint32 full_length, char fill_char)
{
-#ifdef USE_MB
- register uint32 n=0,mblen;
- register const char *mbstr=Ptr;
- register const char *end=mbstr+str_length;
- if (use_mb(str_charset))
+ int t_length= arg_length > full_length ? arg_length : full_length;
+
+ if (realloc(str_length + t_length))
+ return TRUE;
+ t_length= full_length - arg_length;
+ if (t_length > 0)
{
- while (mbstr < end) {
- if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
- else ++mbstr;
- ++n;
- }
- return n;
+ bfill(Ptr+str_length, t_length, fill_char);
+ str_length=str_length + t_length;
}
- else
-#endif
- return str_length;
+ append(s, arg_length);
+ return FALSE;
+}
+
+uint32 String::numchars()
+{
+ return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length);
}
int String::charpos(int i,uint32 offset)
{
-#ifdef USE_MB
- register uint32 mblen;
- register const char *mbstr=Ptr+offset;
- register const char *end=Ptr+str_length;
- if (use_mb(str_charset))
- {
- if (i<=0) return i;
- while (i && mbstr < end) {
- if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
- else ++mbstr;
- --i;
- }
- if ( INT_MAX32-i <= (int) (mbstr-Ptr-offset))
- return INT_MAX32;
- else
- return (int) ((mbstr-Ptr-offset)+i);
- }
- else
-#endif
+ if (i <= 0)
return i;
+ return str_charset->cset->charpos(str_charset,Ptr+offset,Ptr+str_length,i);
}
int String::strstr(const String &s,uint32 offset)
@@ -432,40 +582,6 @@ skip:
}
/*
- Search after a string without regarding to case
- This needs to be replaced when we have character sets per string
-*/
-
-int String::strstr_case(const String &s,uint32 offset)
-{
- if (s.length()+offset <= str_length)
- {
- if (!s.length())
- return ((int) offset); // Empty string is always found
-
- register const char *str = Ptr+offset;
- register const char *search=s.ptr();
- const char *end=Ptr+str_length-s.length()+1;
- const char *search_end=s.ptr()+s.length();
-skip:
- while (str != end)
- {
- if (str_charset->sort_order[*str++] == str_charset->sort_order[*search])
- {
- register char *i,*j;
- i=(char*) str; j=(char*) search+1;
- while (j != search_end)
- if (str_charset->sort_order[*i++] !=
- str_charset->sort_order[*j++])
- goto skip;
- return (int) (str-Ptr) -1;
- }
- }
- }
- return -1;
-}
-
-/*
** Search string from end. Offset is offset to the end of string
*/
@@ -504,14 +620,20 @@ skip:
bool String::replace(uint32 offset,uint32 arg_length,const String &to)
{
- long diff = (long) to.length()-(long) arg_length;
+ return replace(offset,arg_length,to.ptr(),to.length());
+}
+
+bool String::replace(uint32 offset,uint32 arg_length,
+ const char *to,uint32 length)
+{
+ long diff = (long) length-(long) arg_length;
if (offset+arg_length <= str_length)
{
if (diff < 0)
{
- if (to.length())
- memcpy(Ptr+offset,to.ptr(),to.length());
- bmove(Ptr+offset+to.length(),Ptr+offset+arg_length,
+ if (length)
+ memcpy(Ptr+offset,to,length);
+ bmove(Ptr+offset+length,Ptr+offset+arg_length,
str_length-offset-arg_length);
}
else
@@ -523,14 +645,15 @@ bool String::replace(uint32 offset,uint32 arg_length,const String &to)
bmove_upp(Ptr+str_length+diff,Ptr+str_length,
str_length-offset-arg_length);
}
- if (to.length())
- memcpy(Ptr+offset,to.ptr(),to.length());
+ if (length)
+ memcpy(Ptr+offset,to,length);
}
str_length+=(uint32) diff;
}
return FALSE;
}
+
// added by Holyfoot for "geometry" needs
int String::reserve(uint32 space_needed, uint32 grow_by)
{
@@ -542,9 +665,8 @@ int String::reserve(uint32 space_needed, uint32 grow_by)
return FALSE;
}
-void String::qs_append(const char *str)
+void String::qs_append(const char *str, uint32 len)
{
- int len = (int)strlen(str);
memcpy(Ptr + str_length, str, len + 1);
str_length += len;
}
@@ -552,8 +674,7 @@ void String::qs_append(const char *str)
void String::qs_append(double d)
{
char *buff = Ptr + str_length;
- sprintf(buff,"%.14g", d);
- str_length += (int)strlen(buff);
+ str_length+= my_sprintf(buff, (buff, "%.14g", d));
}
void String::qs_append(double *d)
@@ -563,90 +684,70 @@ void String::qs_append(double *d)
qs_append(ld);
}
-void String::qs_append(const char &c)
+void String::qs_append(int i)
{
- Ptr[str_length] = c;
- str_length += sizeof(c);
+ char *buff= Ptr + str_length;
+ char *end= int10_to_str(i, buff, -10);
+ str_length+= (int) (end-buff);
}
-
-int sortcmp(const String *x,const String *y)
+void String::qs_append(uint i)
{
- const char *s= x->ptr();
- const char *t= y->ptr();
- uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
-
- if (use_strnxfrm(x->str_charset))
- {
-#ifndef CMP_ENDSPACE
- while (x_len && my_isspace(x->str_charset,s[x_len-1]))
- x_len--;
- while (y_len && my_isspace(x->str_charset,t[y_len-1]))
- y_len--;
-#endif
- return my_strnncoll(x->str_charset,
- (unsigned char *)s,x_len,(unsigned char *)t,y_len);
- }
- else
- {
- x_len-=len; // For easy end space test
- y_len-=len;
- if (x->str_charset->sort_order)
- {
- while (len--)
- {
- if (x->str_charset->sort_order[(uchar) *s++] !=
- x->str_charset->sort_order[(uchar) *t++])
- return ((int) x->str_charset->sort_order[(uchar) s[-1]] -
- (int) x->str_charset->sort_order[(uchar) t[-1]]);
- }
- }
- else
- {
- while (len--)
- {
- if (*s++ != *t++)
- return ((int) s[-1] - (int) t[-1]);
- }
- }
-#ifndef CMP_ENDSPACE
- /* Don't compare end space in strings */
- {
- if (y_len)
- {
- const char *end=t+y_len;
- for (; t != end ; t++)
- if (!my_isspace(x->str_charset,*t))
- return -1;
- }
- else
- {
- const char *end=s+x_len;
- for (; s != end ; s++)
- if (!my_isspace(x->str_charset,*s))
- return 1;
- }
- return 0;
- }
-#else
- return (int) (x_len-y_len);
-#endif /* CMP_ENDSPACE */
- }
+ char *buff= Ptr + str_length;
+ char *end= int10_to_str(i, buff, 10);
+ str_length+= (int) (end-buff);
}
+/*
+ Compare strings according to collation, without end space.
+
+ SYNOPSIS
+ sortcmp()
+ s First string
+ t Second string
+ cs Collation
+
+ NOTE:
+ Normally this is case sensitive comparison
-int stringcmp(const String *x,const String *y)
+ RETURN
+ < 0 s < t
+ 0 s == t
+ > 0 s > t
+*/
+
+
+int sortcmp(const String *s,const String *t, CHARSET_INFO *cs)
{
- const char *s= x->ptr();
- const char *t= y->ptr();
- uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
+ return cs->coll->strnncollsp(cs,
+ (unsigned char *) s->ptr(),s->length(),
+ (unsigned char *) t->ptr(),t->length(), 0);
+}
- while (len--)
- {
- if (*s++ != *t++)
- return ((int) (uchar) s[-1] - (int) (uchar) t[-1]);
- }
- return (int) (x_len-y_len);
+
+/*
+ Compare strings byte by byte. End spaces are also compared.
+
+ SYNOPSIS
+ stringcmp()
+ s First string
+ t Second string
+
+ NOTE:
+ Strings are compared as a stream of unsigned chars
+
+ RETURN
+ < 0 s < t
+ 0 s == t
+ > 0 s > t
+*/
+
+
+int stringcmp(const String *s,const String *t)
+{
+ uint32 s_len=s->length(),t_len=t->length(),len=min(s_len,t_len);
+ int cmp= memcmp(s->ptr(), t->ptr(), len);
+ return (cmp) ? cmp : (int) (s_len - t_len);
}
@@ -668,4 +769,124 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
}
+/****************************************************************************
+ Help functions
+****************************************************************************/
+/*
+ copy a string from one character set to another
+
+ SYNOPSIS
+ copy_and_convert()
+ to Store result here
+ to_cs Character set of result string
+ from Copy from here
+ from_length Length of from string
+ from_cs From character set
+
+ NOTES
+ 'to' must be big enough as form_length * to_cs->mbmaxlen
+
+ RETURN
+ length of bytes copied to 'to'
+*/
+
+
+uint32
+copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length, CHARSET_INFO *from_cs,
+ uint *errors)
+{
+ int cnvres;
+ my_wc_t wc;
+ const uchar *from_end= (const uchar*) from+from_length;
+ char *to_start= to;
+ uchar *to_end= (uchar*) to+to_length;
+ int (*mb_wc)(struct charset_info_st *, my_wc_t *, const uchar *,
+ const uchar *) = from_cs->cset->mb_wc;
+ int (*wc_mb)(struct charset_info_st *, my_wc_t, uchar *s, uchar *e)=
+ to_cs->cset->wc_mb;
+ uint error_count= 0;
+
+ while (1)
+ {
+ if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from,
+ from_end)) > 0)
+ from+= cnvres;
+ else if (cnvres == MY_CS_ILSEQ)
+ {
+ error_count++;
+ from++;
+ wc= '?';
+ }
+ else
+ break; // Impossible char.
+
+outp:
+ if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
+ to+= cnvres;
+ else if (cnvres == MY_CS_ILUNI && wc != '?')
+ {
+ error_count++;
+ wc= '?';
+ goto outp;
+ }
+ else
+ break;
+ }
+ *errors= error_count;
+ return (uint32) (to - to_start);
+}
+
+
+void String::print(String *str)
+{
+ char *st= (char*)Ptr, *end= st+str_length;
+ for (; st < end; st++)
+ {
+ uchar c= *st;
+ switch (c)
+ {
+ case '\\':
+ str->append("\\\\", 2);
+ break;
+ case '\0':
+ str->append("\\0", 2);
+ break;
+ case '\'':
+ str->append("\\'", 2);
+ break;
+ case '\n':
+ str->append("\\n", 2);
+ break;
+ case '\r':
+ str->append("\\r", 2);
+ break;
+ case 26: //Ctrl-Z
+ str->append("\\z", 2);
+ break;
+ default:
+ str->append(c);
+ }
+ }
+}
+
+
+/*
+ Exchange state of this object and argument.
+
+ SYNOPSIS
+ String::swap()
+
+ RETURN
+ Target string will contain state of this object and vice versa.
+*/
+
+void String::swap(String &s)
+{
+ swap_variables(char *, Ptr, s.Ptr);
+ swap_variables(uint32, str_length, s.str_length);
+ swap_variables(uint32, Alloced_length, s.Alloced_length);
+ swap_variables(bool, alloced, s.alloced);
+ swap_variables(CHARSET_INFO*, str_charset, s.str_charset);
+}
diff --git a/client/sql_string.h b/client/sql_string.h
index aec40466d2b..2debeb61787 100644
--- a/client/sql_string.h
+++ b/client/sql_string.h
@@ -25,9 +25,11 @@
#endif
class String;
-int sortcmp(const String *a,const String *b);
-int stringcmp(const String *a,const String *b);
+int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
+uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length,
+ CHARSET_INFO *from_cs, uint *errors);
class String
{
@@ -39,12 +41,12 @@ public:
String()
{
Ptr=0; str_length=Alloced_length=0; alloced=0;
- str_charset= &my_charset_latin1;
+ str_charset= &my_charset_bin;
}
String(uint32 length_arg)
{
alloced=0; Alloced_length=0; (void) real_alloc(length_arg);
- str_charset= &my_charset_latin1;
+ str_charset= &my_charset_bin;
}
String(const char *str, CHARSET_INFO *cs)
{
@@ -67,12 +69,15 @@ public:
Alloced_length=str.Alloced_length; alloced=0;
str_charset=str.str_charset;
}
- static void *operator new(size_t size) { return (void*) sql_alloc((uint) size); }
- static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
- { sql_element_free(ptr_arg); }
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
+ static void operator delete(void *ptr_arg,size_t size)
+ { TRASH(ptr_arg, size); }
+ static void operator delete(void *ptr_arg, MEM_ROOT *mem_root)
+ { /* never called */ }
~String() { free(); }
- inline void set_charset(CHARSET_INFO *charset) { str_charset=charset; }
+ inline void set_charset(CHARSET_INFO *charset) { str_charset= charset; }
inline CHARSET_INFO *charset() const { return str_charset; }
inline uint32 length() const { return str_length;}
inline uint32 alloced_length() const { return Alloced_length;}
@@ -103,6 +108,7 @@ public:
void set(String &str,uint32 offset,uint32 arg_length)
{
+ DBUG_ASSERT(&str != this);
free();
Ptr=(char*) str.ptr()+offset; str_length=arg_length; alloced=0;
if (str.Alloced_length)
@@ -123,6 +129,7 @@ public:
Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0;
str_charset=cs;
}
+ bool set_ascii(const char *str, uint32 arg_length);
inline void set_quick(char *str,uint32 arg_length, CHARSET_INFO *cs)
{
if (!alloced)
@@ -134,6 +141,34 @@ public:
bool set(longlong num, CHARSET_INFO *cs);
bool set(ulonglong num, CHARSET_INFO *cs);
bool set(double num,uint decimals, CHARSET_INFO *cs);
+
+ /*
+ PMG 2004.11.12
+ This is a method that works the same as perl's "chop". It simply
+ drops the last character of a string. This is useful in the case
+ of the federated storage handler where I'm building a unknown
+ number, list of values and fields to be used in a sql insert
+ statement to be run on the remote server, and have a comma after each.
+ When the list is complete, I "chop" off the trailing comma
+
+ ex.
+ String stringobj;
+ stringobj.append("VALUES ('foo', 'fi', 'fo',");
+ stringobj.chop();
+ stringobj.append(")");
+
+ In this case, the value of string was:
+
+ VALUES ('foo', 'fi', 'fo',
+ VALUES ('foo', 'fi', 'fo'
+ VALUES ('foo', 'fi', 'fo')
+
+ */
+ inline void chop()
+ {
+ Ptr[str_length--]= '\0';
+ }
+
inline void free()
{
if (alloced)
@@ -175,6 +210,11 @@ public:
{
if (&s != this)
{
+ /*
+ It is forbidden to do assignments like
+ some_string = substring_of_that_string
+ */
+ DBUG_ASSERT(!s.uses_buffer_owned_by(this));
free();
Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
alloced=0;
@@ -185,13 +225,24 @@ public:
bool copy(); // Alloc string if not alloced
bool copy(const String &s); // Allocate new string
bool copy(const char *s,uint32 arg_length, CHARSET_INFO *cs); // Allocate new string
- bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom, CHARSET_INFO *csto);
+ static bool needs_conversion(uint32 arg_length,
+ CHARSET_INFO *cs_from, CHARSET_INFO *cs_to,
+ uint32 *offset);
+ bool copy_aligned(const char *s, uint32 arg_length, uint32 offset,
+ CHARSET_INFO *cs);
+ bool set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs);
+ bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom,
+ CHARSET_INFO *csto, uint *errors);
bool append(const String &s);
- bool append(const char *s,uint32 arg_length=0);
+ bool append(const char *s);
+ bool append(const char *s,uint32 arg_length);
+ bool append(const char *s,uint32 arg_length, CHARSET_INFO *cs);
bool append(IO_CACHE* file, uint32 arg_length);
+ bool append_with_prefill(const char *s, uint32 arg_length,
+ uint32 full_length, char fill_char);
int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
- int strstr_case(const String &s,uint32 offset=0);
int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
+ bool replace(uint32 offset,uint32 arg_length,const char *to,uint32 length);
bool replace(uint32 offset,uint32 arg_length,const String &to);
inline bool append(char chr)
{
@@ -211,7 +262,7 @@ public:
void strip_sp();
inline void caseup() { my_caseup(str_charset,Ptr,str_length); }
inline void casedn() { my_casedn(str_charset,Ptr,str_length); }
- friend int sortcmp(const String *a,const String *b);
+ friend int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
friend int stringcmp(const String *a,const String *b);
friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
uint32 numchars();
@@ -228,11 +279,11 @@ public:
q_*** methods writes values of parameters itself
qs_*** methods writes string representation of value
*/
- void q_append(const char &c)
+ void q_append(const char c)
{
Ptr[str_length++] = c;
}
- void q_append(const uint32 &n)
+ void q_append(const uint32 n)
{
int4store(Ptr + str_length, n);
str_length += 4;
@@ -253,13 +304,53 @@ public:
str_length += data_len;
}
- void WriteAtPosition(int position, uint32 value)
+ void write_at_position(int position, uint32 value)
{
int4store(Ptr + position,value);
}
- void qs_append(const char *str);
+ void qs_append(const char *str, uint32 len);
void qs_append(double d);
void qs_append(double *d);
- void qs_append(const char &c);
+ inline void qs_append(const char c)
+ {
+ Ptr[str_length]= c;
+ str_length++;
+ }
+ void qs_append(int i);
+ void qs_append(uint i);
+
+ /* Inline (general) functions used by the protocol functions */
+
+ inline char *prep_append(uint32 arg_length, uint32 step_alloc)
+ {
+ uint32 new_length= arg_length + str_length;
+ if (new_length > Alloced_length)
+ {
+ if (realloc(new_length + step_alloc))
+ return 0;
+ }
+ uint32 old_length= str_length;
+ str_length+= arg_length;
+ return Ptr+ old_length; /* Area to use */
+ }
+
+ inline bool append(const char *s, uint32 arg_length, uint32 step_alloc)
+ {
+ uint32 new_length= arg_length + str_length;
+ if (new_length > Alloced_length && realloc(new_length + step_alloc))
+ return TRUE;
+ memcpy(Ptr+str_length, s, arg_length);
+ str_length+= arg_length;
+ return FALSE;
+ }
+ void print(String *print);
+
+ /* Swap two string objects. Efficient way to exchange data without memcpy. */
+ void swap(String &s);
+
+ inline bool uses_buffer_owned_by(const String *s) const
+ {
+ return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->str_length);
+ }
};
diff --git a/config/ac-macros/alloca.m4 b/config/ac-macros/alloca.m4
new file mode 100644
index 00000000000..8c730dd671f
--- /dev/null
+++ b/config/ac-macros/alloca.m4
@@ -0,0 +1,68 @@
+AC_DEFUN([MYSQL_FUNC_ALLOCA],
+[
+# Since we have heard that alloca fails on IRIX never define it on a
+# SGI machine
+if test ! "$host_vendor" = "sgi"
+then
+ AC_REQUIRE_CPP()dnl Set CPP; we run AC_EGREP_CPP conditionally.
+ # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+ # for constant arguments. Useless!
+ AC_CACHE_CHECK([for working alloca.h], ac_cv_header_alloca_h,
+ [AC_TRY_LINK([#include <alloca.h>], [char *p = alloca(2 * sizeof(int));],
+ ac_cv_header_alloca_h=yes, ac_cv_header_alloca_h=no)])
+ if test "$ac_cv_header_alloca_h" = "yes"
+ then
+ AC_DEFINE(HAVE_ALLOCA, 1)
+ fi
+
+ AC_CACHE_CHECK([for alloca], ac_cv_func_alloca_works,
+ [AC_TRY_LINK([
+ #ifdef __GNUC__
+ # define alloca __builtin_alloca
+ #else
+ # if HAVE_ALLOCA_H
+ # include <alloca.h>
+ # else
+ # ifdef _AIX
+ #pragma alloca
+ # else
+ # ifndef alloca /* predefined by HP cc +Olibcalls */
+ char *alloca ();
+ # endif
+ # endif
+ # endif
+ #endif
+ ], [char *p = (char *) alloca(1);],
+ ac_cv_func_alloca_works=yes, ac_cv_func_alloca_works=no)])
+ if test "$ac_cv_func_alloca_works" = "yes"; then
+ AC_DEFINE([HAVE_ALLOCA], [1], [If we have a working alloca() implementation])
+ fi
+
+ if test "$ac_cv_func_alloca_works" = "no"; then
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+ # that cause trouble. Some versions do not even contain alloca or
+ # contain a buggy version. If you still want to use their alloca,
+ # use ar to extract alloca.o from them instead of compiling alloca.c.
+ ALLOCA=alloca.o
+ AC_DEFINE(C_ALLOCA, 1)
+
+ AC_CACHE_CHECK(whether alloca needs Cray hooks, ac_cv_os_cray,
+ [AC_EGREP_CPP(webecray,
+ [#if defined(CRAY) && ! defined(CRAY2)
+ webecray
+ #else
+ wenotbecray
+ #endif
+ ], ac_cv_os_cray=yes, ac_cv_os_cray=no)])
+ if test "$ac_cv_os_cray" = "yes"; then
+ for ac_func in _getb67 GETB67 getb67; do
+ AC_CHECK_FUNC($ac_func, [AC_DEFINE_UNQUOTED(CRAY_STACKSEG_END, $ac_func)
+ break])
+ done
+ fi
+ fi
+ AC_SUBST(ALLOCA)dnl
+else
+ AC_MSG_RESULT("Skipped alloca tests")
+fi
+])
diff --git a/config/ac-macros/character_sets.m4 b/config/ac-macros/character_sets.m4
new file mode 100644
index 00000000000..3ecc4bb5a03
--- /dev/null
+++ b/config/ac-macros/character_sets.m4
@@ -0,0 +1,431 @@
+dnl In order to add new charset, you must add charset name to
+dnl this CHARSETS_AVAILABLE list and sql/share/charsets/Index.xml.
+dnl If the character set uses strcoll or other special handling,
+dnl you must also create strings/ctype-$charset_name.c
+
+AC_DIVERT_PUSH(0)
+
+define(CHARSETS_AVAILABLE0,binary)
+define(CHARSETS_AVAILABLE1,armscii8 ascii big5 cp1250 cp1251 cp1256 cp1257)
+define(CHARSETS_AVAILABLE2,cp850 cp852 cp866 cp932 dec8 eucjpms euckr gb2312 gbk geostd8)
+define(CHARSETS_AVAILABLE3,greek hebrew hp8 keybcs2 koi8r koi8u)
+define(CHARSETS_AVAILABLE4,latin1 latin2 latin5 latin7 macce macroman)
+define(CHARSETS_AVAILABLE5,sjis swe7 tis620 ucs2 ujis utf8)
+
+DEFAULT_CHARSET=latin1
+CHARSETS_AVAILABLE="CHARSETS_AVAILABLE0 CHARSETS_AVAILABLE1 CHARSETS_AVAILABLE2 CHARSETS_AVAILABLE3 CHARSETS_AVAILABLE4 CHARSETS_AVAILABLE5"
+CHARSETS_COMPLEX="big5 cp1250 cp932 eucjpms euckr gb2312 gbk latin1 latin2 sjis tis620 ucs2 ujis utf8"
+
+AC_DIVERT_POP
+
+AC_ARG_WITH(charset,
+ [ --with-charset=CHARSET
+ Default character set, use one of:
+ CHARSETS_AVAILABLE0
+ CHARSETS_AVAILABLE1
+ CHARSETS_AVAILABLE2
+ CHARSETS_AVAILABLE3
+ CHARSETS_AVAILABLE4
+ CHARSETS_AVAILABLE5],
+ [default_charset="$withval"],
+ [default_charset="$DEFAULT_CHARSET"])
+
+AC_ARG_WITH(collation,
+ [ --with-collation=COLLATION
+ Default collation],
+ [default_collation="$withval"],
+ [default_collation="default"])
+
+
+AC_ARG_WITH(extra-charsets,
+ [ --with-extra-charsets=CHARSET[,CHARSET,...]
+ Use charsets in addition to default (none, complex,
+ all, or a list selected from the above sets)],
+ [extra_charsets="$withval"],
+ [extra_charsets="none"])
+
+
+AC_MSG_CHECKING("character sets")
+
+CHARSETS="$default_charset latin1 utf8"
+
+if test "$extra_charsets" = no; then
+ CHARSETS="$CHARSETS"
+elif test "$extra_charsets" = none; then
+ CHARSETS="$CHARSETS"
+elif test "$extra_charsets" = complex; then
+ CHARSETS="$CHARSETS $CHARSETS_COMPLEX"
+ AC_DEFINE([DEFINE_ALL_CHARACTER_SETS],1,[all charsets are available])
+elif test "$extra_charsets" = all; then
+ CHARSETS="$CHARSETS $CHARSETS_AVAILABLE"
+ AC_DEFINE([DEFINE_ALL_CHARACTER_SETS],1,[all charsets are available])
+else
+ EXTRA_CHARSETS=`echo $extra_charsets | sed -e 's/,/ /g'`
+ CHARSETS="$CHARSETS $EXTRA_CHARSETS"
+fi
+
+for cs in $CHARSETS
+do
+ case $cs in
+ armscii8)
+ AC_DEFINE(HAVE_CHARSET_armscii8, 1,
+ [Define to enable charset armscii8])
+ ;;
+ ascii)
+ AC_DEFINE(HAVE_CHARSET_ascii, 1,
+ [Define to enable ascii character set])
+ ;;
+ big5)
+ AC_DEFINE(HAVE_CHARSET_big5, 1, [Define to enable charset big5])
+ AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, [1], [ ])
+ ;;
+ binary)
+ ;;
+ cp1250)
+ AC_DEFINE(HAVE_CHARSET_cp1250, 1, [Define to enable cp1250])
+ ;;
+ cp1251)
+ AC_DEFINE(HAVE_CHARSET_cp1251, 1, [Define to enable charset cp1251])
+ ;;
+ cp1256)
+ AC_DEFINE(HAVE_CHARSET_cp1256, 1, [Define to enable charset cp1256])
+ ;;
+ cp1257)
+ AC_DEFINE(HAVE_CHARSET_cp1257, 1, [Define to enable charset cp1257])
+ ;;
+ cp850)
+ AC_DEFINE(HAVE_CHARSET_cp850, 1, [Define to enable charset cp850])
+ ;;
+ cp852)
+ AC_DEFINE(HAVE_CHARSET_cp852, 1, [Define to enable charset cp852])
+ ;;
+ cp866)
+ AC_DEFINE(HAVE_CHARSET_cp866, 1, [Define to enable charset cp866])
+ ;;
+ cp932)
+ AC_DEFINE(HAVE_CHARSET_cp932, 1, [Define to enable charset cp932])
+ AC_DEFINE([USE_MB], 1, [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, 1)
+ ;;
+ dec8)
+ AC_DEFINE(HAVE_CHARSET_dec8, 1, [Define to enable charset dec8])
+ ;;
+ eucjpms)
+ AC_DEFINE(HAVE_CHARSET_eucjpms, 1, [Define to enable charset eucjpms])
+ AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, 1)
+ ;;
+ euckr)
+ AC_DEFINE(HAVE_CHARSET_euckr, 1, [Define to enable charset euckr])
+ AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, 1)
+ ;;
+ gb2312)
+ AC_DEFINE(HAVE_CHARSET_gb2312, 1, [Define to enable charset gb2312])
+ AC_DEFINE([USE_MB], 1, [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, 1)
+ ;;
+ gbk)
+ AC_DEFINE(HAVE_CHARSET_gbk, 1, [Define to enable charset gbk])
+ AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, 1)
+ ;;
+ geostd8)
+ AC_DEFINE(HAVE_CHARSET_geostd8, 1, [Define to enable charset geostd8])
+ ;;
+ greek)
+ AC_DEFINE(HAVE_CHARSET_greek, 1, [Define to enable charset greek])
+ ;;
+ hebrew)
+ AC_DEFINE(HAVE_CHARSET_hebrew, 1, [Define to enable charset hebrew])
+ ;;
+ hp8)
+ AC_DEFINE(HAVE_CHARSET_hp8, 1, [Define to enable charset hp8])
+ ;;
+ keybcs2)
+ AC_DEFINE(HAVE_CHARSET_keybcs2, 1, [Define to enable charset keybcs2])
+ ;;
+ koi8r)
+ AC_DEFINE(HAVE_CHARSET_koi8r, 1, [Define to enable charset koi8r])
+ ;;
+ koi8u)
+ AC_DEFINE(HAVE_CHARSET_koi8u, 1, [Define to enable charset koi8u])
+ ;;
+ latin1)
+ AC_DEFINE(HAVE_CHARSET_latin1, 1, [Define to enable charset latin1])
+ ;;
+ latin2)
+ AC_DEFINE(HAVE_CHARSET_latin2, 1, [Define to enable charset latin2])
+ ;;
+ latin5)
+ AC_DEFINE(HAVE_CHARSET_latin5, 1, [Define to enable charset latin5])
+ ;;
+ latin7)
+ AC_DEFINE(HAVE_CHARSET_latin7, 1, [Define to enable charset latin7])
+ ;;
+ macce)
+ AC_DEFINE(HAVE_CHARSET_macce, 1, [Define to enable charset macce])
+ ;;
+ macroman)
+ AC_DEFINE(HAVE_CHARSET_macroman, 1,
+ [Define to enable charset macroman])
+ ;;
+ sjis)
+ AC_DEFINE(HAVE_CHARSET_sjis, 1, [Define to enable charset sjis])
+ AC_DEFINE([USE_MB], 1, [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, 1)
+ ;;
+ swe7)
+ AC_DEFINE(HAVE_CHARSET_swe7, 1, [Define to enable charset swe7])
+ ;;
+ tis620)
+ AC_DEFINE(HAVE_CHARSET_tis620, 1, [Define to enable charset tis620])
+ ;;
+ ucs2)
+ AC_DEFINE(HAVE_CHARSET_ucs2, 1, [Define to enable charset ucs2])
+ AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, 1)
+ ;;
+ ujis)
+ AC_DEFINE(HAVE_CHARSET_ujis, 1, [Define to enable charset ujis])
+ AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, 1)
+ ;;
+ utf8)
+ AC_DEFINE(HAVE_CHARSET_utf8, 1, [Define to enable ut8])
+ AC_DEFINE([USE_MB], 1, [Use multi-byte character routines])
+ AC_DEFINE(USE_MB_IDENT, 1)
+ ;;
+ *)
+ AC_MSG_ERROR([Charset '$cs' not available. (Available are: $CHARSETS_AVAILABLE).
+ See the Installation chapter in the Reference Manual.]);
+ esac
+done
+
+
+ default_charset_collations=""
+
+case $default_charset in
+ armscii8)
+ default_charset_default_collation="armscii8_general_ci"
+ default_charset_collations="armscii8_general_ci armscii8_bin"
+ ;;
+ ascii)
+ default_charset_default_collation="ascii_general_ci"
+ default_charset_collations="ascii_general_ci ascii_bin"
+ ;;
+ big5)
+ default_charset_default_collation="big5_chinese_ci"
+ default_charset_collations="big5_chinese_ci big5_bin"
+ ;;
+ binary)
+ default_charset_default_collation="binary"
+ default_charset_collations="binary"
+ ;;
+ cp1250)
+ default_charset_default_collation="cp1250_general_ci"
+ default_charset_collations="cp1250_general_ci cp1250_czech_cs cp1250_bin"
+ ;;
+ cp1251)
+ default_charset_default_collation="cp1251_general_ci"
+ default_charset_collations="cp1251_general_ci cp1251_general_cs cp1251_bin cp1251_bulgarian_ci cp1251_ukrainian_ci"
+ ;;
+ cp1256)
+ default_charset_default_collation="cp1256_general_ci"
+ default_charset_collations="cp1256_general_ci cp1256_bin"
+ ;;
+ cp1257)
+ default_charset_default_collation="cp1257_general_ci"
+ default_charset_collations="cp1257_general_ci cp1257_lithuanian_ci cp1257_bin"
+ ;;
+ cp850)
+ default_charset_default_collation="cp850_general_ci"
+ default_charset_collations="cp850_general_ci cp850_bin"
+ ;;
+ cp852)
+ default_charset_default_collation="cp852_general_ci"
+ default_charset_collations="cp852_general_ci cp852_bin"
+ ;;
+ cp866)
+ default_charset_default_collation="cp866_general_ci"
+ default_charset_collations="cp866_general_ci cp866_bin"
+ ;;
+ cp932)
+ default_charset_default_collation="cp932_japanese_ci"
+ default_charset_collations="cp932_japanese_ci cp932_bin"
+ ;;
+ dec8)
+ default_charset_default_collation="dec8_swedish_ci"
+ default_charset_collations="dec8_swedish_ci dec8_bin"
+ ;;
+ eucjpms)
+ default_charset_default_collation="eucjpms_japanese_ci"
+ default_charset_collations="eucjpms_japanese_ci ujis_bin"
+ ;;
+ euckr)
+ default_charset_default_collation="euckr_korean_ci"
+ default_charset_collations="euckr_korean_ci euckr_bin"
+ ;;
+ gb2312)
+ default_charset_default_collation="gb2312_chinese_ci"
+ default_charset_collations="gb2312_chinese_ci gb2312_bin"
+ ;;
+ gbk)
+ default_charset_default_collation="gbk_chinese_ci"
+ default_charset_collations="gbk_chinese_ci gbk_bin"
+ ;;
+ geostd8)
+ default_charset_default_collation="geostd8_general_ci"
+ default_charset_collations="geostd8_general_ci geostd8_bin"
+ ;;
+ greek)
+ default_charset_default_collation="greek_general_ci"
+ default_charset_collations="greek_general_ci greek_bin"
+ ;;
+ hebrew)
+ default_charset_default_collation="hebrew_general_ci"
+ default_charset_collations="hebrew_general_ci hebrew_bin"
+ ;;
+ hp8)
+ default_charset_default_collation="hp8_english_ci"
+ default_charset_collations="hp8_english_ci hp8_bin"
+ ;;
+ keybcs2)
+ default_charset_default_collation="keybcs2_general_ci"
+ default_charset_collations="keybcs2_general_ci keybcs2_bin"
+ ;;
+ koi8r)
+ default_charset_default_collation="koi8r_general_ci"
+ default_charset_collations="koi8r_general_ci koi8r_bin"
+ ;;
+ koi8u)
+ default_charset_default_collation="koi8u_general_ci"
+ default_charset_collations="koi8u_general_ci koi8u_bin"
+ ;;
+ latin1)
+ default_charset_default_collation="latin1_swedish_ci"
+ default_charset_collations="latin1_general_ci latin1_general_cs latin1_bin latin1_german1_ci latin1_german2_ci latin1_danish_ci latin1_spanish_ci latin1_swedish_ci"
+ ;;
+ latin2)
+ default_charset_default_collation="latin2_general_ci"
+ default_charset_collations="latin2_general_ci latin2_bin latin2_czech_cs latin2_hungarian_ci latin2_croatian_ci"
+ ;;
+ latin5)
+ default_charset_default_collation="latin5_turkish_ci"
+ default_charset_collations="latin5_turkish_ci latin5_bin"
+ ;;
+ latin7)
+ default_charset_default_collation="latin7_general_ci"
+ default_charset_collations="latin7_general_ci latin7_general_cs latin7_bin latin7_estonian_cs"
+ ;;
+ macce)
+ default_charset_default_collation="macce_general_ci"
+ default_charset_collations="macce_general_ci macce_bin"
+ ;;
+ macroman)
+ default_charset_default_collation="macroman_general_ci"
+ default_charset_collations="macroman_general_ci macroman_bin"
+ ;;
+ sjis)
+ default_charset_default_collation="sjis_japanese_ci"
+ default_charset_collations="sjis_japanese_ci sjis_bin"
+ ;;
+ swe7)
+ default_charset_default_collation="swe7_swedish_ci"
+ default_charset_collations="swe7_swedish_ci swe7_bin"
+ ;;
+ tis620)
+ default_charset_default_collation="tis620_thai_ci"
+ default_charset_collations="tis620_thai_ci tis620_bin"
+ ;;
+ ucs2)
+ default_charset_default_collation="ucs2_general_ci"
+ define(UCSC1, ucs2_general_ci ucs2_bin)
+ define(UCSC2, ucs2_czech_ci ucs2_danish_ci)
+ define(UCSC3, ucs2_estonian_ci ucs2_icelandic_ci)
+ define(UCSC4, ucs2_latvian_ci ucs2_lithuanian_ci)
+ define(UCSC5, ucs2_persian_ci ucs2_polish_ci ucs2_romanian_ci)
+ define(UCSC6, ucs2_slovak_ci ucs2_slovenian_ci)
+ define(UCSC7, ucs2_spanish2_ci ucs2_spanish_ci)
+ define(UCSC8, ucs2_swedish_ci ucs2_turkish_ci)
+ define(UCSC9, ucs2_unicode_ci)
+ UCSC="UCSC1 UCSC2 UCSC3 UCSC4 UCSC5 UCSC6 UCSC7 UCSC8 UCSC9"
+ default_charset_collations="$UCSC"
+ ;;
+ ujis)
+ default_charset_default_collation="ujis_japanese_ci"
+ default_charset_collations="ujis_japanese_ci ujis_bin"
+ ;;
+ utf8)
+ default_charset_default_collation="utf8_general_ci"
+ if test "$default_collation" = "utf8_general_cs"; then
+ # For those who explicitly desire "utf8_general_cs", support it,
+ # and then also set the CPP switch enabling that code.
+ UTFC="utf8_general_cs"
+ AC_DEFINE([HAVE_UTF8_GENERAL_CS], [1], [certain Japanese customer])
+ else
+ define(UTFC1, utf8_general_ci utf8_bin)
+ define(UTFC2, utf8_czech_ci utf8_danish_ci)
+ define(UTFC3, utf8_estonian_ci utf8_icelandic_ci)
+ define(UTFC4, utf8_latvian_ci utf8_lithuanian_ci)
+ define(UTFC5, utf8_persian_ci utf8_polish_ci utf8_romanian_ci)
+ define(UTFC6, utf8_slovak_ci utf8_slovenian_ci)
+ define(UTFC7, utf8_spanish2_ci utf8_spanish_ci)
+ define(UTFC8, utf8_swedish_ci utf8_turkish_ci)
+ define(UTFC9, utf8_unicode_ci)
+ UTFC="UTFC1 UTFC2 UTFC3 UTFC4 UTFC5 UTFC6 UTFC7 UTFC8 UTFC9"
+ fi
+ default_charset_collations="$UTFC"
+ ;;
+ *)
+ AC_MSG_ERROR([Charset $cs not available. (Available are: $CHARSETS_AVAILABLE).
+ See the Installation chapter in the Reference Manual.]);
+esac
+
+if test "$default_collation" = default; then
+ default_collation=$default_charset_default_collation
+fi
+
+valid_default_collation=no
+for cl in $default_charset_collations
+do
+ if test x"$cl" = x"$default_collation"
+ then
+ valid_default_collation=yes
+ break
+ fi
+done
+
+if test x$valid_default_collation = xyes
+then
+ AC_MSG_RESULT([default: $default_charset, collation: $default_collation; compiled in: $CHARSETS])
+else
+ AC_MSG_ERROR([
+ Collation $default_collation is not valid for character set $default_charset.
+ Valid collations are: $default_charset_collations.
+ See the Installation chapter in the Reference Manual.
+ ]);
+fi
+
+AC_DEFINE_UNQUOTED([MYSQL_DEFAULT_CHARSET_NAME], ["$default_charset"],
+ [Define the default charset name])
+AC_DEFINE_UNQUOTED([MYSQL_DEFAULT_COLLATION_NAME], ["$default_collation"],
+ [Define the default charset name])
+
+# Shall we build the UCA-based Unicode collations
+AC_ARG_WITH(uca,
+ [ --without-uca Skip building of the national Unicode collations.],
+ [with_uca=$withval],
+ [with_uca=yes]
+)
+
+AC_MSG_CHECKING([whether to compile national Unicode collations])
+
+if test "$with_uca" = "yes"
+then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_UCA_COLLATIONS], [1], [national Unicode collations])
+else
+ AC_MSG_RESULT(no)
+fi
diff --git a/config/ac-macros/check_cpu.m4 b/config/ac-macros/check_cpu.m4
new file mode 100644
index 00000000000..d551f47769e
--- /dev/null
+++ b/config/ac-macros/check_cpu.m4
@@ -0,0 +1,47 @@
+AC_DEFUN([MYSQL_CHECK_CPU],
+[AC_CACHE_CHECK([if compiler supports optimizations for current cpu],
+mysql_cv_cpu,[
+
+ac_save_CFLAGS="$CFLAGS"
+if test -r /proc/cpuinfo ; then
+ cpuinfo="cat /proc/cpuinfo"
+ cpu_family=`$cpuinfo | grep 'cpu family' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1`
+ cpu_vendor=`$cpuinfo | grep 'vendor_id' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1`
+fi
+if test "$cpu_vendor" = "AuthenticAMD"; then
+ if test $cpu_family -ge 6; then
+ cpu_set="athlon pentiumpro k5 pentium i486 i386";
+ elif test $cpu_family -eq 5; then
+ cpu_set="k5 pentium i486 i386";
+ elif test $cpu_family -eq 4; then
+ cpu_set="i486 i386"
+ else
+ cpu_set="i386"
+ fi
+elif test "$cpu_vendor" = "GenuineIntel"; then
+ if test $cpu_family -ge 6; then
+ cpu_set="pentiumpro pentium i486 i386";
+ elif test $cpu_family -eq 5; then
+ cpu_set="pentium i486 i386";
+ elif test $cpu_family -eq 4; then
+ cpu_set="i486 i386"
+ else
+ cpu_set="i386"
+ fi
+fi
+
+for ac_arg in $cpu_set;
+do
+ CFLAGS="$ac_save_CFLAGS -mcpu=$ac_arg -march=$ac_arg -DCPU=$ac_arg"
+ AC_TRY_COMPILE([],[int i],mysql_cv_cpu=$ac_arg; break;, mysql_cv_cpu="unknown")
+done
+
+if test "$mysql_cv_cpu" = "unknown"
+then
+ CFLAGS="$ac_save_CFLAGS"
+ AC_MSG_RESULT(none)
+else
+ AC_MSG_RESULT($mysql_cv_cpu)
+fi
+])])
+
diff --git a/config/ac-macros/compiler_flag.m4 b/config/ac-macros/compiler_flag.m4
new file mode 100644
index 00000000000..a236f61a198
--- /dev/null
+++ b/config/ac-macros/compiler_flag.m4
@@ -0,0 +1,40 @@
+# option, cache_name, variable,
+# code to execute if yes, code to exectute if fail
+AC_DEFUN([AC_SYS_COMPILER_FLAG],
+[
+ AC_MSG_CHECKING($1)
+ OLD_CFLAGS="[$]CFLAGS"
+ AC_CACHE_VAL(mysql_cv_option_$2,
+ [
+ CFLAGS="[$]OLD_CFLAGS $1"
+ AC_TRY_RUN([int main(){exit(0);}],mysql_cv_option_$2=yes,mysql_cv_option_$2=no,mysql_cv_option_$2=no)
+ ])
+
+ CFLAGS="[$]OLD_CFLAGS"
+
+ if test x"[$]mysql_cv_option_$2" = "xyes" ; then
+ $3="[$]$3 $1"
+ AC_MSG_RESULT(yes)
+ $5
+ else
+ AC_MSG_RESULT(no)
+ $4
+ fi
+])
+
+# arch, option, cache_name, variable
+AC_DEFUN([AC_SYS_CPU_COMPILER_FLAG],
+[
+ if test "`uname -m 2>/dev/null`" = "$1" ; then
+ AC_SYS_COMPILER_FLAG($2,$3,$4)
+ fi
+])
+
+# os, option, cache_name, variable
+AC_DEFUN([AC_SYS_OS_COMPILER_FLAG],
+[
+ if test "x$mysql_cv_sys_os" = "x$1" ; then
+ AC_SYS_COMPILER_FLAG($2,$3,$4)
+ fi
+])
+
diff --git a/config/ac-macros/ha_archive.m4 b/config/ac-macros/ha_archive.m4
new file mode 100644
index 00000000000..2d2558ea600
--- /dev/null
+++ b/config/ac-macros/ha_archive.m4
@@ -0,0 +1,29 @@
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_ARCHIVEDB
+dnl Sets HAVE_ARCHIVE_DB if --with-archive-storage-engine is used
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([MYSQL_CHECK_ARCHIVEDB], [
+ AC_ARG_WITH([archive-storage-engine],
+ [
+ --with-archive-storage-engine
+ Enable the Archive Storage Engine],
+ [archivedb="$withval"],
+ [archivedb=no])
+ AC_MSG_CHECKING([for archive storage engine])
+
+ case "$archivedb" in
+ yes )
+ AC_DEFINE([HAVE_ARCHIVE_DB], [1], [Builds Archive Storage Engine])
+ AC_MSG_RESULT([yes])
+ [archivedb=yes]
+ ;;
+ * )
+ AC_MSG_RESULT([no])
+ [archivedb=no]
+ ;;
+ esac
+
+])
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_ARCHIVE SECTION
+dnl ---------------------------------------------------------------------------
diff --git a/config/ac-macros/ha_berkeley.m4 b/config/ac-macros/ha_berkeley.m4
new file mode 100644
index 00000000000..732c7730816
--- /dev/null
+++ b/config/ac-macros/ha_berkeley.m4
@@ -0,0 +1,267 @@
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_BDB
+dnl Sets HAVE_BERKELEY_DB if inst library is found
+dnl Makes sure db version is correct.
+dnl Looks in $srcdir for Berkeley distribution if not told otherwise
+dnl ---------------------------------------------------------------------------
+
+AC_DEFUN([MYSQL_CHECK_BDB], [
+ AC_ARG_WITH([berkeley-db],
+ [
+ --with-berkeley-db[=DIR]
+ Use BerkeleyDB located in DIR],
+ [bdb="$withval"],
+ [bdb=no])
+
+ AC_ARG_WITH([berkeley-db-includes],
+ [
+ --with-berkeley-db-includes=DIR
+ Find Berkeley DB headers in DIR],
+ [bdb_includes="$withval"],
+ [bdb_includes=default])
+
+ AC_ARG_WITH([berkeley-db-libs],
+ [
+ --with-berkeley-db-libs=DIR
+ Find Berkeley DB libraries in DIR],
+ [bdb_libs="$withval"],
+ [bdb_libs=default])
+
+ AC_MSG_CHECKING([for BerkeleyDB])
+
+dnl SORT OUT THE SUPPLIED ARGUMENTS TO DETERMINE WHAT TO DO
+dnl echo "DBG1: bdb='$bdb'; incl='$bdb_includes'; lib='$bdb_libs'"
+ have_berkeley_db=no
+ case "$bdb" in
+ no )
+ mode=no
+ AC_MSG_RESULT([no])
+ ;;
+ yes | default )
+ case "$bdb_includes---$bdb_libs" in
+ default---default )
+ mode=search-$bdb
+ AC_MSG_RESULT([searching...])
+ ;;
+ default---* | *---default | yes---* | *---yes )
+ AC_MSG_ERROR([if either 'includes' or 'libs' is specified, both must be specified])
+ ;;
+ * )
+ mode=supplied-two
+ AC_MSG_RESULT([supplied])
+ ;;
+ esac
+ ;;
+ * )
+ mode=supplied-one
+ AC_MSG_RESULT([supplied])
+ ;;
+ esac
+
+dnl echo "DBG2: [$mode] bdb='$bdb'; incl='$bdb_includes'; lib='$bdb_libs'"
+
+ case $mode in
+ no )
+ bdb_includes=
+ bdb_libs=
+ bdb_libs_with_path=
+ ;;
+ supplied-two )
+ MYSQL_CHECK_INSTALLED_BDB([$bdb_includes], [$bdb_libs])
+ case $bdb_dir_ok in
+ installed ) mode=yes ;;
+ * ) AC_MSG_ERROR([didn't find valid BerkeleyDB: $bdb_dir_ok]) ;;
+ esac
+ ;;
+ supplied-one )
+ MYSQL_CHECK_BDB_DIR([$bdb])
+ case $bdb_dir_ok in
+ source ) mode=compile ;;
+ installed ) mode=yes ;;
+ * ) AC_MSG_ERROR([didn't find valid BerkeleyDB: $bdb_dir_ok]) ;;
+ esac
+ ;;
+ search-* )
+ MYSQL_SEARCH_FOR_BDB
+ case $bdb_dir_ok in
+ source ) mode=compile ;;
+ installed ) mode=yes ;;
+ * )
+ # not found
+ case $mode in
+ *-yes ) AC_MSG_ERROR([no suitable BerkeleyDB found]) ;;
+ * ) mode=no ;;
+ esac
+ bdb_includes=
+ bdb_libs=
+ bdb_libs_with_path=
+ ;;
+ esac
+ ;;
+ *)
+ AC_MSG_ERROR([impossible case condition '$mode': please report this to bugs@lists.mysql.com])
+ ;;
+ esac
+
+dnl echo "DBG3: [$mode] bdb='$bdb'; incl='$bdb_includes'; lib='$bdb_libs'"
+ case $mode in
+ no )
+ AC_MSG_RESULT([Not using Berkeley DB])
+ ;;
+ yes )
+ have_berkeley_db="yes"
+ AC_MSG_RESULT([Using Berkeley DB in '$bdb_includes'])
+ ;;
+ compile )
+ have_berkeley_db="$bdb"
+ AC_MSG_RESULT([Compiling Berekeley DB in '$have_berkeley_db'])
+ ;;
+ * )
+ AC_MSG_ERROR([impossible case condition '$mode': please report this to bugs@lists.mysql.com])
+ ;;
+ esac
+
+ AC_SUBST(bdb_includes)
+ AC_SUBST(bdb_libs)
+ AC_SUBST(bdb_libs_with_path)
+])
+
+AC_DEFUN([MYSQL_CHECK_INSTALLED_BDB], [
+dnl echo ["MYSQL_CHECK_INSTALLED_BDB ($1) ($2)"]
+ inc="$1"
+ lib="$2"
+ if test -f "$inc/db.h"
+ then
+ MYSQL_CHECK_BDB_VERSION([$inc/db.h],
+ [.*#define[ ]*], [[ ][ ]*])
+
+ if test X"$bdb_version_ok" = Xyes; then
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="-L$lib $LDFLAGS"
+ AC_CHECK_LIB(db,db_env_create, [
+ bdb_dir_ok=installed
+ MYSQL_TOP_BUILDDIR([inc])
+ MYSQL_TOP_BUILDDIR([lib])
+ bdb_includes="-I$inc"
+ bdb_libs="-L$lib -ldb"
+ bdb_libs_with_path="$lib/libdb.a"
+ ])
+ LDFLAGS="$save_LDFLAGS"
+ else
+ bdb_dir_ok="$bdb_version_ok"
+ fi
+ else
+ bdb_dir_ok="no db.h file in '$inc'"
+ fi
+])
+
+AC_DEFUN([MYSQL_CHECK_BDB_DIR], [
+dnl ([$bdb])
+dnl echo ["MYSQL_CHECK_BDB_DIR ($1)"]
+ dir="$1"
+
+ MYSQL_CHECK_INSTALLED_BDB([$dir/include], [$dir/lib])
+
+ if test X"$bdb_dir_ok" != Xinstalled; then
+ # test to see if it's a source dir
+ rel="$dir/dist/RELEASE"
+ if test -f "$rel"; then
+ MYSQL_CHECK_BDB_VERSION([$rel], [], [=])
+ if test X"$bdb_version_ok" = Xyes; then
+ bdb_dir_ok=source
+ bdb="$dir"
+ MYSQL_TOP_BUILDDIR([dir])
+ bdb_includes="-I$dir/build_unix"
+ bdb_libs="-L$dir/build_unix -ldb"
+ bdb_libs_with_path="$dir/build_unix/libdb.a"
+ else
+ bdb_dir_ok="$bdb_version_ok"
+ fi
+ else
+ bdb_dir_ok="'$dir' doesn't look like a BDB directory ($bdb_dir_ok)"
+ fi
+ fi
+])
+
+AC_DEFUN([MYSQL_SEARCH_FOR_BDB], [
+dnl echo ["MYSQL_SEARCH_FOR_BDB"]
+ bdb_dir_ok="no BerkeleyDB found"
+
+ for test_dir in $srcdir/bdb $srcdir/db-*.*.* /usr/local/BerkeleyDB*; do
+dnl echo "-----------> Looking at ($test_dir; `cd $test_dir && pwd`)"
+ MYSQL_CHECK_BDB_DIR([$test_dir])
+ if test X"$bdb_dir_ok" = Xsource || test X"$bdb_dir_ok" = Xinstalled; then
+dnl echo "-----------> Found it ($bdb), ($srcdir)"
+dnl This is needed so that 'make distcheck' works properly (VPATH build).
+dnl VPATH build won't work if bdb is not under the source tree; but in
+dnl that case, hopefully people will just make and install inside the
+dnl tree, or install BDB first, and then use the installed version.
+ case "$bdb" in
+ "$srcdir/"* ) bdb=`echo "$bdb" | sed -e "s,^$srcdir/,,"` ;;
+ esac
+ break
+ fi
+ done
+])
+
+dnl MYSQL_CHECK_BDB_VERSION takes 3 arguments:
+dnl 1) the file to look in
+dnl 2) the search pattern before DB_VERSION_XXX
+dnl 3) the search pattern between DB_VERSION_XXX and the number
+dnl It assumes that the number is the last thing on the line
+AC_DEFUN([MYSQL_CHECK_BDB_VERSION], [
+ db_major=`sed -e '/^[$2]DB_VERSION_MAJOR[$3]/ !d' -e 's///' [$1]`
+ db_minor=`sed -e '/^[$2]DB_VERSION_MINOR[$3]/ !d' -e 's///' [$1]`
+ db_patch=`sed -e '/^[$2]DB_VERSION_PATCH[$3]/ !d' -e 's///' [$1]`
+ test -z "$db_major" && db_major=0
+ test -z "$db_minor" && db_minor=0
+ test -z "$db_patch" && db_patch=0
+
+ # This is ugly, but about as good as it can get
+# mysql_bdb=
+# if test $db_major -eq 3 && test $db_minor -eq 2 && test $db_patch -eq 3
+# then
+# mysql_bdb=h
+# elif test $db_major -eq 3 && test $db_minor -eq 2 && test $db_patch -eq 9
+# then
+# want_bdb_version="3.2.9a" # hopefully this will stay up-to-date
+# mysql_bdb=a
+# fi
+
+dnl RAM:
+want_bdb_version="4.1.24"
+bdb_version_ok=yes
+
+# if test -n "$mysql_bdb" && \
+# grep "DB_VERSION_STRING.*:.*$mysql_bdb: " [$1] > /dev/null
+# then
+# bdb_version_ok=yes
+# else
+# bdb_version_ok="invalid version $db_major.$db_minor.$db_patch"
+# bdb_version_ok="$bdb_version_ok (must be version 3.2.3h or $want_bdb_version)"
+# fi
+])
+
+AC_DEFUN([MYSQL_TOP_BUILDDIR], [
+ case "$[$1]" in
+ /* ) ;; # don't do anything with an absolute path
+ "$srcdir"/* )
+ # If BDB is under the source directory, we need to look under the
+ # build directory for bdb/build_unix.
+ # NOTE: I'm being lazy, and assuming the user did not specify
+ # something like --with-berkeley-db=bdb (it would be missing "./").
+ [$1]="\$(top_builddir)/"`echo "$[$1]" | sed -e "s,^$srcdir/,,"`
+ ;;
+ * )
+ AC_MSG_ERROR([The BDB directory must be directly under the MySQL source directory, or be specified using the full path. ('$srcdir'; '$[$1]')])
+ ;;
+ esac
+ if test X"$[$1]" != "/"
+ then
+ [$1]=`echo $[$1] | sed -e 's,/$,,'`
+ fi
+])
+
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_BDB SECTION
+dnl ---------------------------------------------------------------------------
diff --git a/config/ac-macros/ha_blackhole.m4 b/config/ac-macros/ha_blackhole.m4
new file mode 100644
index 00000000000..cc4d360f5a8
--- /dev/null
+++ b/config/ac-macros/ha_blackhole.m4
@@ -0,0 +1,29 @@
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_BLACKHOLEDB
+dnl Sets HAVE_BLACKHOLE_DB if --with-blackhole-storage-engine is used
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([MYSQL_CHECK_BLACKHOLEDB], [
+ AC_ARG_WITH([blackhole-storage-engine],
+ [
+ --with-blackhole-storage-engine
+ Enable the Blackhole Storage Engine],
+ [blackholedb="$withval"],
+ [blackholedb=no])
+ AC_MSG_CHECKING([for blackhole storage engine])
+
+ case "$blackholedb" in
+ yes )
+ AC_DEFINE([HAVE_BLACKHOLE_DB], [1], [Builds Blackhole Storage Engine])
+ AC_MSG_RESULT([yes])
+ [blackholedb=yes]
+ ;;
+ * )
+ AC_MSG_RESULT([no])
+ [blackholedb=no]
+ ;;
+ esac
+
+])
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_BLACKHOLE SECTION
+dnl ---------------------------------------------------------------------------
diff --git a/config/ac-macros/ha_example.m4 b/config/ac-macros/ha_example.m4
new file mode 100644
index 00000000000..f8067931ce6
--- /dev/null
+++ b/config/ac-macros/ha_example.m4
@@ -0,0 +1,30 @@
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_EXAMPLEDB
+dnl Sets HAVE_EXAMPLE_DB if --with-example-storage-engine is used
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([MYSQL_CHECK_EXAMPLEDB], [
+ AC_ARG_WITH([example-storage-engine],
+ [
+ --with-example-storage-engine
+ Enable the Example Storage Engine],
+ [exampledb="$withval"],
+ [exampledb=no])
+ AC_MSG_CHECKING([for example storage engine])
+
+ case "$exampledb" in
+ yes )
+ AC_DEFINE([HAVE_EXAMPLE_DB], [1], [Builds Example DB])
+ AC_MSG_RESULT([yes])
+ [exampledb=yes]
+ ;;
+ * )
+ AC_MSG_RESULT([no])
+ [exampledb=no]
+ ;;
+ esac
+
+])
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_EXAMPLE SECTION
+dnl ---------------------------------------------------------------------------
+
diff --git a/config/ac-macros/ha_federated.m4 b/config/ac-macros/ha_federated.m4
new file mode 100644
index 00000000000..4383a9d8d55
--- /dev/null
+++ b/config/ac-macros/ha_federated.m4
@@ -0,0 +1,29 @@
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_FEDERATED
+dnl Sets HAVE_FEDERATED if --with-federated-storage-engine is used
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([MYSQL_CHECK_FEDERATED], [
+ AC_ARG_WITH([federated-storage-engine],
+ [
+ --with-federated-storage-engine
+ Enable the MySQL Storage Engine],
+ [federateddb="$withval"],
+ [federateddb=no])
+ AC_MSG_CHECKING([for MySQL federated storage engine])
+
+ case "$federateddb" in
+ yes )
+ AC_DEFINE([HAVE_FEDERATED_DB], [1], [Define to enable Federated Handler])
+ AC_MSG_RESULT([yes])
+ [federateddb=yes]
+ ;;
+ * )
+ AC_MSG_RESULT([no])
+ [federateddb=no]
+ ;;
+ esac
+
+])
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_FEDERATED SECTION
+dnl ---------------------------------------------------------------------------
diff --git a/config/ac-macros/ha_innodb.m4 b/config/ac-macros/ha_innodb.m4
new file mode 100644
index 00000000000..17f0fab3e90
--- /dev/null
+++ b/config/ac-macros/ha_innodb.m4
@@ -0,0 +1,77 @@
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_INNODB
+dnl Sets HAVE_INNOBASE_DB if --with-innodb is used
+dnl ---------------------------------------------------------------------------
+
+AC_DEFUN([MYSQL_CHECK_INNODB], [
+ AC_ARG_WITH([innodb],
+ [
+ --without-innodb Do not include the InnoDB table handler],
+ [innodb="$withval"],
+ [innodb=yes])
+
+ AC_MSG_CHECKING([for Innodb])
+
+ have_innodb=no
+ innodb_includes=
+ innodb_libs=
+ case "$innodb" in
+ yes )
+ AC_MSG_RESULT([Using Innodb])
+ AC_DEFINE([HAVE_INNOBASE_DB], [1], [Using Innobase DB])
+ have_innodb="yes"
+ innodb_includes="-I../innobase/include"
+ innodb_system_libs=""
+dnl Some libs are listed several times, in order for gcc to sort out
+dnl circular references.
+ innodb_libs="\
+ \$(top_builddir)/innobase/usr/libusr.a\
+ \$(top_builddir)/innobase/srv/libsrv.a\
+ \$(top_builddir)/innobase/dict/libdict.a\
+ \$(top_builddir)/innobase/que/libque.a\
+ \$(top_builddir)/innobase/srv/libsrv.a\
+ \$(top_builddir)/innobase/ibuf/libibuf.a\
+ \$(top_builddir)/innobase/row/librow.a\
+ \$(top_builddir)/innobase/pars/libpars.a\
+ \$(top_builddir)/innobase/btr/libbtr.a\
+ \$(top_builddir)/innobase/trx/libtrx.a\
+ \$(top_builddir)/innobase/read/libread.a\
+ \$(top_builddir)/innobase/usr/libusr.a\
+ \$(top_builddir)/innobase/buf/libbuf.a\
+ \$(top_builddir)/innobase/ibuf/libibuf.a\
+ \$(top_builddir)/innobase/eval/libeval.a\
+ \$(top_builddir)/innobase/log/liblog.a\
+ \$(top_builddir)/innobase/fsp/libfsp.a\
+ \$(top_builddir)/innobase/fut/libfut.a\
+ \$(top_builddir)/innobase/fil/libfil.a\
+ \$(top_builddir)/innobase/lock/liblock.a\
+ \$(top_builddir)/innobase/mtr/libmtr.a\
+ \$(top_builddir)/innobase/page/libpage.a\
+ \$(top_builddir)/innobase/rem/librem.a\
+ \$(top_builddir)/innobase/thr/libthr.a\
+ \$(top_builddir)/innobase/sync/libsync.a\
+ \$(top_builddir)/innobase/data/libdata.a\
+ \$(top_builddir)/innobase/mach/libmach.a\
+ \$(top_builddir)/innobase/ha/libha.a\
+ \$(top_builddir)/innobase/dyn/libdyn.a\
+ \$(top_builddir)/innobase/mem/libmem.a\
+ \$(top_builddir)/innobase/sync/libsync.a\
+ \$(top_builddir)/innobase/ut/libut.a\
+ \$(top_builddir)/innobase/os/libos.a\
+ \$(top_builddir)/innobase/ut/libut.a"
+
+ AC_CHECK_LIB(rt, aio_read, [innodb_system_libs="-lrt"])
+ ;;
+ * )
+ AC_MSG_RESULT([Not using Innodb])
+ ;;
+ esac
+
+ AC_SUBST(innodb_includes)
+ AC_SUBST(innodb_libs)
+ AC_SUBST(innodb_system_libs)
+])
+
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_INNODB SECTION
+dnl ---------------------------------------------------------------------------
diff --git a/config/ac-macros/ha_ndbcluster.m4 b/config/ac-macros/ha_ndbcluster.m4
new file mode 100644
index 00000000000..dc5e0e73558
--- /dev/null
+++ b/config/ac-macros/ha_ndbcluster.m4
@@ -0,0 +1,154 @@
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_NDBCLUSTER
+dnl Sets HAVE_NDBCLUSTER_DB if --with-ndbcluster is used
+dnl ---------------------------------------------------------------------------
+
+AC_DEFUN([MYSQL_CHECK_NDB_OPTIONS], [
+ AC_ARG_WITH([ndb-sci],
+ AC_HELP_STRING([--with-ndb-sci=DIR],
+ [Provide MySQL with a custom location of
+ sci library. Given DIR, sci library is
+ assumed to be in $DIR/lib and header files
+ in $DIR/include.]),
+ [mysql_sci_dir=${withval}],
+ [mysql_sci_dir=""])
+
+ case "$mysql_sci_dir" in
+ "no" )
+ have_ndb_sci=no
+ AC_MSG_RESULT([-- not including sci transporter])
+ ;;
+ * )
+ if test -f "$mysql_sci_dir/lib/libsisci.a" -a \
+ -f "$mysql_sci_dir/include/sisci_api.h"; then
+ NDB_SCI_INCLUDES="-I$mysql_sci_dir/include"
+ NDB_SCI_LIBS="-L$mysql_sci_dir/lib -lsisci"
+ AC_MSG_RESULT([-- including sci transporter])
+ AC_DEFINE([NDB_SCI_TRANSPORTER], [1],
+ [Including Ndb Cluster DB sci transporter])
+ AC_SUBST(NDB_SCI_INCLUDES)
+ AC_SUBST(NDB_SCI_LIBS)
+ have_ndb_sci="yes"
+ AC_MSG_RESULT([found sci transporter in $mysql_sci_dir/{include, lib}])
+ else
+ AC_MSG_RESULT([could not find sci transporter in $mysql_sci_dir/{include, lib}])
+ fi
+ ;;
+ esac
+
+ AC_ARG_WITH([ndb-test],
+ [
+ --with-ndb-test Include the NDB Cluster ndbapi test programs],
+ [ndb_test="$withval"],
+ [ndb_test=no])
+ AC_ARG_WITH([ndb-docs],
+ [
+ --with-ndb-docs Include the NDB Cluster ndbapi and mgmapi documentation],
+ [ndb_docs="$withval"],
+ [ndb_docs=no])
+ AC_ARG_WITH([ndb-port],
+ [
+ --with-ndb-port Port for NDB Cluster management server],
+ [ndb_port="$withval"],
+ [ndb_port="default"])
+ AC_ARG_WITH([ndb-port-base],
+ [
+ --with-ndb-port-base Base port for NDB Cluster transporters],
+ [ndb_port_base="$withval"],
+ [ndb_port_base="default"])
+ AC_ARG_WITH([ndb-debug],
+ [
+ --without-ndb-debug Disable special ndb debug features],
+ [ndb_debug="$withval"],
+ [ndb_debug="default"])
+ AC_ARG_WITH([ndb-ccflags],
+ [
+ --with-ndb-ccflags Extra CC options for ndb compile],
+ [ndb_cxxflags_fix="$ndb_cxxflags_fix $withval"],
+ [ndb_cxxflags_fix=$ndb_cxxflags_fix])
+
+ AC_MSG_CHECKING([for NDB Cluster options])
+ AC_MSG_RESULT([])
+
+ have_ndb_test=no
+ case "$ndb_test" in
+ yes )
+ AC_MSG_RESULT([-- including ndbapi test programs])
+ have_ndb_test="yes"
+ ;;
+ * )
+ AC_MSG_RESULT([-- not including ndbapi test programs])
+ ;;
+ esac
+
+ have_ndb_docs=no
+ case "$ndb_docs" in
+ yes )
+ AC_MSG_RESULT([-- including ndbapi and mgmapi documentation])
+ have_ndb_docs="yes"
+ ;;
+ * )
+ AC_MSG_RESULT([-- not including ndbapi and mgmapi documentation])
+ ;;
+ esac
+
+ case "$ndb_debug" in
+ yes )
+ AC_MSG_RESULT([-- including ndb extra debug options])
+ have_ndb_debug="yes"
+ ;;
+ full )
+ AC_MSG_RESULT([-- including ndb extra extra debug options])
+ have_ndb_debug="full"
+ ;;
+ no )
+ AC_MSG_RESULT([-- not including ndb extra debug options])
+ have_ndb_debug="no"
+ ;;
+ * )
+ have_ndb_debug="default"
+ ;;
+ esac
+
+ AC_MSG_RESULT([done.])
+])
+
+AC_DEFUN([MYSQL_CHECK_NDBCLUSTER], [
+ AC_ARG_WITH([ndbcluster],
+ [
+ --with-ndbcluster Include the NDB Cluster table handler],
+ [ndbcluster="$withval"],
+ [ndbcluster=no])
+
+ AC_MSG_CHECKING([for NDB Cluster])
+
+ have_ndbcluster=no
+ ndbcluster_includes=
+ ndbcluster_libs=
+ ndb_mgmclient_libs=
+ case "$ndbcluster" in
+ yes )
+ AC_MSG_RESULT([Using NDB Cluster])
+ AC_DEFINE([HAVE_NDBCLUSTER_DB], [1], [Using Ndb Cluster DB])
+ have_ndbcluster="yes"
+ ndbcluster_includes="-I../ndb/include -I../ndb/include/ndbapi"
+ ndbcluster_libs="\$(top_builddir)/ndb/src/.libs/libndbclient.a"
+ ndbcluster_system_libs=""
+ ndb_mgmclient_libs="\$(top_builddir)/ndb/src/mgmclient/libndbmgmclient.la"
+ MYSQL_CHECK_NDB_OPTIONS
+ ;;
+ * )
+ AC_MSG_RESULT([Not using NDB Cluster])
+ ;;
+ esac
+
+ AM_CONDITIONAL([HAVE_NDBCLUSTER_DB], [ test "$have_ndbcluster" = "yes" ])
+ AC_SUBST(ndbcluster_includes)
+ AC_SUBST(ndbcluster_libs)
+ AC_SUBST(ndbcluster_system_libs)
+ AC_SUBST(ndb_mgmclient_libs)
+])
+
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_NDBCLUSTER SECTION
+dnl ---------------------------------------------------------------------------
diff --git a/config/ac-macros/ha_tina.m4 b/config/ac-macros/ha_tina.m4
new file mode 100644
index 00000000000..fe6e382ce20
--- /dev/null
+++ b/config/ac-macros/ha_tina.m4
@@ -0,0 +1,29 @@
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_CSVDB
+dnl Sets HAVE_CSV_DB if --with-csv-storage-engine is used
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([MYSQL_CHECK_CSVDB], [
+ AC_ARG_WITH([csv-storage-engine],
+ [
+ --with-csv-storage-engine
+ Enable the CSV Storage Engine],
+ [csvdb="$withval"],
+ [csvdb=no])
+ AC_MSG_CHECKING([for csv storage engine])
+
+ case "$csvdb" in
+ yes )
+ AC_DEFINE([HAVE_CSV_DB], [1], [Builds the CSV Storage Engine])
+ AC_MSG_RESULT([yes])
+ [csvdb=yes]
+ ;;
+ * )
+ AC_MSG_RESULT([no])
+ [csvdb=no]
+ ;;
+ esac
+
+])
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_CSV SECTION
+dnl ---------------------------------------------------------------------------
diff --git a/config/ac-macros/large_file.m4 b/config/ac-macros/large_file.m4
new file mode 100644
index 00000000000..00c2fdf614e
--- /dev/null
+++ b/config/ac-macros/large_file.m4
@@ -0,0 +1,140 @@
+
+dnl By default, many hosts won't let programs access large files;
+dnl one must use special compiler options to get large-file access to work.
+dnl For more details about this brain damage please see:
+dnl http://www.sas.com/standards/large.file/x_open.20Mar96.html
+
+dnl Written by Paul Eggert <eggert@twinsun.com>.
+
+dnl Internal subroutine of AC_SYS_LARGEFILE.
+dnl AC_SYS_LARGEFILE_FLAGS(FLAGSNAME)
+AC_DEFUN([AC_SYS_LARGEFILE_FLAGS],
+ [AC_CACHE_CHECK([for $1 value to request large file support],
+ ac_cv_sys_largefile_$1,
+ [if ($GETCONF LFS_$1) >conftest.1 2>conftest.2 && test ! -s conftest.2
+ then
+ ac_cv_sys_largefile_$1=`cat conftest.1`
+ else
+ ac_cv_sys_largefile_$1=no
+ ifelse($1, CFLAGS,
+ [case "$host_os" in
+ # HP-UX 10.20 requires -D__STDC_EXT__ with gcc 2.95.1.
+changequote(, )dnl
+ hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
+changequote([, ])dnl
+ if test "$GCC" = yes; then
+ case `$CC --version 2>/dev/null` in
+ 2.95.*) ac_cv_sys_largefile_CFLAGS=-D__STDC_EXT__ ;;
+ esac
+ fi
+ ;;
+ # IRIX 6.2 and later require cc -n32.
+changequote(, )dnl
+ irix6.[2-9]* | irix6.1[0-9]* | irix[7-9].* | irix[1-9][0-9]*)
+changequote([, ])dnl
+ if test "$GCC" != yes; then
+ ac_cv_sys_largefile_CFLAGS=-n32
+ fi
+ esac
+ if test "$ac_cv_sys_largefile_CFLAGS" != no; then
+ ac_save_CC="$CC"
+ CC="$CC $ac_cv_sys_largefile_CFLAGS"
+ AC_TRY_LINK(, , , ac_cv_sys_largefile_CFLAGS=no)
+ CC="$ac_save_CC"
+ fi])
+ fi
+ rm -f conftest*])])
+
+dnl Internal subroutine of AC_SYS_LARGEFILE.
+dnl AC_SYS_LARGEFILE_SPACE_APPEND(VAR, VAL)
+AC_DEFUN([AC_SYS_LARGEFILE_SPACE_APPEND],
+ [case $2 in
+ no) ;;
+ ?*)
+ case "[$]$1" in
+ '') $1=$2 ;;
+ *) $1=[$]$1' '$2 ;;
+ esac ;;
+ esac])
+
+dnl Internal subroutine of AC_SYS_LARGEFILE.
+dnl AC_SYS_LARGEFILE_MACRO_VALUE(C-MACRO, CACHE-VAR, COMMENT, CODE-TO-SET-DEFAULT)
+AC_DEFUN([AC_SYS_LARGEFILE_MACRO_VALUE],
+ [AC_CACHE_CHECK([for $1], $2,
+ [$2=no
+changequote(, )dnl
+ for ac_flag in $ac_cv_sys_largefile_CFLAGS no; do
+ case "$ac_flag" in
+ -D$1)
+ $2=1 ;;
+ -D$1=*)
+ $2=`expr " $ac_flag" : '[^=]*=\(.*\)'` ;;
+ esac
+ done
+ $4
+changequote([, ])dnl
+ ])
+ if test "[$]$2" != no; then
+ AC_DEFINE_UNQUOTED([$1], [$]$2, [$3])
+ fi])
+
+AC_DEFUN([MYSQL_SYS_LARGEFILE],
+ [AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_ARG_ENABLE(largefile,
+ [ --disable-largefile Omit support for large files])
+ if test "$enable_largefile" != no; then
+ AC_CHECK_TOOL(GETCONF, getconf)
+ AC_SYS_LARGEFILE_FLAGS(CFLAGS)
+ AC_SYS_LARGEFILE_FLAGS(LDFLAGS)
+ AC_SYS_LARGEFILE_FLAGS(LIBS)
+
+ for ac_flag in $ac_cv_sys_largefile_CFLAGS no; do
+ case "$ac_flag" in
+ no) ;;
+ -D_FILE_OFFSET_BITS=*) ;;
+ -D_LARGEFILE_SOURCE | -D_LARGEFILE_SOURCE=*) ;;
+ -D_LARGE_FILES | -D_LARGE_FILES=*) ;;
+ -D?* | -I?*)
+ AC_SYS_LARGEFILE_SPACE_APPEND(CPPFLAGS, "$ac_flag") ;;
+ *)
+ AC_SYS_LARGEFILE_SPACE_APPEND(CFLAGS, "$ac_flag") ;;
+ esac
+ done
+ AC_SYS_LARGEFILE_SPACE_APPEND(LDFLAGS, "$ac_cv_sys_largefile_LDFLAGS")
+ AC_SYS_LARGEFILE_SPACE_APPEND(LIBS, "$ac_cv_sys_largefile_LIBS")
+
+ AC_SYS_LARGEFILE_MACRO_VALUE(_FILE_OFFSET_BITS,
+ ac_cv_sys_file_offset_bits,
+ [Number of bits in a file offset, on hosts where this is settable.],
+ [case "$host_os" in
+ # HP-UX 10.20 and later
+ hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
+ ac_cv_sys_file_offset_bits=64 ;;
+ # We can't declare _FILE_OFFSET_BITS here as this will cause
+ # compile errors as AC_PROG_CC adds include files in confdefs.h
+ # We solve this (until autoconf is fixed) by instead declaring it
+ # as define instead
+ solaris2.[8,9])
+ CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64"
+ CXXFLAGS="$CXXFLAGS -D_FILE_OFFSET_BITS=64"
+ ac_cv_sys_file_offset_bits=no ;;
+ esac])
+ AC_SYS_LARGEFILE_MACRO_VALUE(_LARGEFILE_SOURCE,
+ ac_cv_sys_largefile_source,
+ [makes fseeko etc. visible, on some hosts.],
+ [case "$host_os" in
+ # HP-UX 10.20 and later
+ hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
+ ac_cv_sys_largefile_source=1 ;;
+ esac])
+ AC_SYS_LARGEFILE_MACRO_VALUE(_LARGE_FILES,
+ ac_cv_sys_large_files,
+ [Large files support on AIX-style hosts.],
+ [case "$host_os" in
+ # AIX 4.2 and later
+ aix4.[2-9]* | aix4.1[0-9]* | aix[5-9].* | aix[1-9][0-9]*)
+ ac_cv_sys_large_files=1 ;;
+ esac])
+ fi
+ ])
+
diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4
new file mode 100644
index 00000000000..d75dedafa2a
--- /dev/null
+++ b/config/ac-macros/misc.m4
@@ -0,0 +1,695 @@
+# Local macros for automake & autoconf
+
+# A local version of AC_CHECK_SIZEOF that includes sys/types.h
+dnl MYSQL_CHECK_SIZEOF(TYPE [, CROSS-SIZE])
+AC_DEFUN([MYSQL_CHECK_SIZEOF],
+[changequote(<<, >>)dnl
+dnl The name to #define.
+define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl
+dnl The cache variable name.
+define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl
+changequote([, ])dnl
+AC_MSG_CHECKING(size of $1)
+AC_CACHE_VAL(AC_CV_NAME,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof($1));
+ exit(0);
+}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$2], , , AC_CV_NAME=$2))])dnl
+AC_MSG_RESULT($AC_CV_NAME)
+AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [ ])
+undefine([AC_TYPE_NAME])dnl
+undefine([AC_CV_NAME])dnl
+])
+
+#---START: Used in for client configure
+AC_DEFUN([MYSQL_TYPE_ACCEPT],
+[ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([base type of last arg to accept], mysql_cv_btype_last_arg_accept,
+AC_LANG_PUSH(C++)
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ # Add -Werror, remove -fbranch-probabilities (Bug #268)
+ CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'`
+fi
+mysql_cv_btype_last_arg_accept=none
+[AC_TRY_COMPILE([#if defined(inline)
+#undef inline
+#endif
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+],
+[int a = accept(1, (struct sockaddr *) 0, (socklen_t *) 0); return (a != 0);],
+mysql_cv_btype_last_arg_accept=socklen_t)]
+if test "$mysql_cv_btype_last_arg_accept" = "none"; then
+[AC_TRY_COMPILE([#if defined(inline)
+#undef inline
+#endif
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+],
+[int a = accept(1, (struct sockaddr *) 0, (size_t *) 0); return (a != 0);],
+mysql_cv_btype_last_arg_accept=size_t)]
+fi
+if test "$mysql_cv_btype_last_arg_accept" = "none"; then
+mysql_cv_btype_last_arg_accept=int
+fi)
+AC_LANG_POP(C++)
+AC_DEFINE_UNQUOTED([SOCKET_SIZE_TYPE], [$mysql_cv_btype_last_arg_accept],
+ [The base type of the last arg to accept])
+CXXFLAGS="$ac_save_CXXFLAGS"
+])
+#---END:
+
+dnl Find type of qsort
+AC_DEFUN([MYSQL_TYPE_QSORT],
+[AC_CACHE_CHECK([return type of qsort], mysql_cv_type_qsort,
+[AC_TRY_COMPILE([#include <stdlib.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+void qsort(void *base, size_t nel, size_t width,
+ int (*compar) (const void *, const void *));
+],
+[int i;], mysql_cv_type_qsort=void, mysql_cv_type_qsort=int)])
+AC_DEFINE_UNQUOTED([RETQSORTTYPE], [$mysql_cv_type_qsort],
+ [The return type of qsort (int or void).])
+if test "$mysql_cv_type_qsort" = "void"
+then
+ AC_DEFINE_UNQUOTED([QSORT_TYPE_IS_VOID], [1], [qsort returns void])
+fi
+])
+
+#---START: Figure out whether to use 'struct rlimit' or 'struct rlimit64'
+AC_DEFUN([MYSQL_TYPE_STRUCT_RLIMIT],
+[ac_save_CXXFLAGS="$CXXFLAGS"
+AC_CACHE_CHECK([struct type to use with setrlimit], mysql_cv_btype_struct_rlimit,
+AC_LANG_PUSH(C++)
+if test "$ac_cv_prog_gxx" = "yes"
+then
+ # Add -Werror, remove -fbranch-probabilities (Bug #268)
+ CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'`
+fi
+mysql_cv_btype_struct_rlimit=none
+[AC_TRY_COMPILE([#if defined(inline)
+#undef inline
+#endif
+#include <stdlib.h>
+#include <sys/resource.h>
+],
+[struct rlimit64 rl; setrlimit(RLIMIT_CORE, &rl);],
+mysql_cv_btype_struct_rlimit="struct rlimit64")]
+if test "$mysql_cv_btype_struct_rlimit" = "none"; then
+mysql_cv_btype_struct_rlimit="struct rlimit"
+fi)
+AC_LANG_POP(C++)
+AC_DEFINE_UNQUOTED([STRUCT_RLIMIT], [$mysql_cv_btype_struct_rlimit],
+ [The struct rlimit type to use with setrlimit])
+CXXFLAGS="$ac_save_CXXFLAGS"
+])
+#---END:
+
+AC_DEFUN([MYSQL_TIMESPEC_TS],
+[AC_CACHE_CHECK([if struct timespec has a ts_sec member], mysql_cv_timespec_ts,
+[AC_TRY_COMPILE([#include <pthread.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+],
+[struct timespec abstime;
+
+abstime.ts_sec = time(NULL)+1;
+abstime.ts_nsec = 0;
+], mysql_cv_timespec_ts=yes, mysql_cv_timespec_ts=no)])
+if test "$mysql_cv_timespec_ts" = "yes"
+then
+ AC_DEFINE([HAVE_TIMESPEC_TS_SEC], [1],
+ [Timespec has a ts_sec instead of tv_sev])
+fi
+])
+
+AC_DEFUN([MYSQL_TZNAME],
+[AC_CACHE_CHECK([if we have tzname variable], mysql_cv_tzname,
+[AC_TRY_COMPILE([#include <time.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+],
+[ tzset();
+ return tzname[0] != 0;
+], mysql_cv_tzname=yes, mysql_cv_tzname=no)])
+if test "$mysql_cv_tzname" = "yes"
+then
+ AC_DEFINE([HAVE_TZNAME], [1], [Have the tzname variable])
+fi
+])
+
+
+#---START: Used in for client configure
+AC_DEFUN([MYSQL_CHECK_ULONG],
+[AC_MSG_CHECKING(for type ulong)
+AC_CACHE_VAL(ac_cv_ulong,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ ulong foo;
+ foo++;
+ exit(0);
+}], ac_cv_ulong=yes, ac_cv_ulong=no, ac_cv_ulong=no)])
+AC_MSG_RESULT($ac_cv_ulong)
+if test "$ac_cv_ulong" = "yes"
+then
+ AC_DEFINE([HAVE_ULONG], [1], [system headers define ulong])
+fi
+])
+
+AC_DEFUN([MYSQL_CHECK_UCHAR],
+[AC_MSG_CHECKING(for type uchar)
+AC_CACHE_VAL(ac_cv_uchar,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ uchar foo;
+ foo++;
+ exit(0);
+}], ac_cv_uchar=yes, ac_cv_uchar=no, ac_cv_uchar=no)])
+AC_MSG_RESULT($ac_cv_uchar)
+if test "$ac_cv_uchar" = "yes"
+then
+ AC_DEFINE([HAVE_UCHAR], [1], [system headers define uchar])
+fi
+])
+
+AC_DEFUN([MYSQL_CHECK_UINT],
+[AC_MSG_CHECKING(for type uint)
+AC_CACHE_VAL(ac_cv_uint,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+ uint foo;
+ foo++;
+ exit(0);
+}], ac_cv_uint=yes, ac_cv_uint=no, ac_cv_uint=no)])
+AC_MSG_RESULT($ac_cv_uint)
+if test "$ac_cv_uint" = "yes"
+then
+ AC_DEFINE([HAVE_UINT], [1], [system headers define uint])
+fi
+])
+
+
+AC_DEFUN([MYSQL_CHECK_IN_ADDR_T],
+[AC_MSG_CHECKING(for type in_addr_t)
+AC_CACHE_VAL(ac_cv_in_addr_t,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int main(int argc, char **argv)
+{
+ in_addr_t foo;
+ exit(0);
+}], ac_cv_in_addr_t=yes, ac_cv_in_addr_t=no, ac_cv_in_addr_t=no)])
+AC_MSG_RESULT($ac_cv_in_addr_t)
+if test "$ac_cv_in_addr_t" = "yes"
+then
+ AC_DEFINE([HAVE_IN_ADDR_T], [1], [system headers define in_addr_t])
+fi
+])
+
+
+AC_DEFUN([MYSQL_PTHREAD_YIELD],
+[AC_CACHE_CHECK([if pthread_yield takes zero arguments], ac_cv_pthread_yield_zero_arg,
+[AC_TRY_LINK([#define _GNU_SOURCE
+#include <pthread.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+],
+[
+ pthread_yield();
+], ac_cv_pthread_yield_zero_arg=yes, ac_cv_pthread_yield_zero_arg=yeso)])
+if test "$ac_cv_pthread_yield_zero_arg" = "yes"
+then
+ AC_DEFINE([HAVE_PTHREAD_YIELD_ZERO_ARG], [1],
+ [pthread_yield that doesn't take any arguments])
+fi
+]
+[AC_CACHE_CHECK([if pthread_yield takes 1 argument], ac_cv_pthread_yield_one_arg,
+[AC_TRY_LINK([#define _GNU_SOURCE
+#include <pthread.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+],
+[
+ pthread_yield(0);
+], ac_cv_pthread_yield_one_arg=yes, ac_cv_pthread_yield_one_arg=no)])
+if test "$ac_cv_pthread_yield_one_arg" = "yes"
+then
+ AC_DEFINE([HAVE_PTHREAD_YIELD_ONE_ARG], [1],
+ [pthread_yield function with one argument])
+fi
+]
+)
+
+
+
+#---END:
+
+AC_DEFUN([MYSQL_CHECK_FP_EXCEPT],
+[AC_MSG_CHECKING(for type fp_except)
+AC_CACHE_VAL(ac_cv_fp_except,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+#include <ieeefp.h>
+main()
+{
+ fp_except foo;
+ foo++;
+ exit(0);
+}], ac_cv_fp_except=yes, ac_cv_fp_except=no, ac_cv_fp_except=no)])
+AC_MSG_RESULT($ac_cv_fp_except)
+if test "$ac_cv_fp_except" = "yes"
+then
+ AC_DEFINE([HAVE_FP_EXCEPT], [1], [fp_except from ieeefp.h])
+fi
+])
+
+# From fileutils-3.14/aclocal.m4
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so. This macro tries various
+# options that select ANSI C on some system or another. It considers the
+# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
+# handles function prototypes correctly.
+#
+# Patched by monty to only check if __STDC__ is defined. With the original
+# check it's impossible to get things to work with the Sunpro compiler from
+# Workshop 4.2
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN([AM_PROG_CC_STDC],
+[AC_REQUIRE([AC_PROG_CC])
+AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(am_cv_prog_cc_stdc,
+[am_cv_prog_cc_stdc=no
+ac_save_CC="$CC"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+# removed "-Xc -D__EXTENSIONS__" beacause sun c++ does not like it.
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE"
+do
+ CC="$ac_save_CC $ac_arg"
+ AC_TRY_COMPILE(
+[#if !defined(__STDC__)
+choke me
+#endif
+/* DYNIX/ptx V4.1.3 can't compile sys/stat.h with -Xc -D__EXTENSIONS__. */
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+], [
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};],
+[am_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CC="$ac_save_CC"
+])
+AC_MSG_RESULT($am_cv_prog_cc_stdc)
+case "x$am_cv_prog_cc_stdc" in
+ x|xno) ;;
+ *) CC="$CC $am_cv_prog_cc_stdc" ;;
+esac
+])
+
+# Orginal from bash-2.0 aclocal.m4, Changed to use termcap last by monty.
+
+AC_DEFUN([MYSQL_CHECK_LIB_TERMCAP],
+[
+AC_CACHE_VAL(mysql_cv_termcap_lib,
+[AC_CHECK_LIB(ncurses, tgetent, mysql_cv_termcap_lib=libncurses,
+ [AC_CHECK_LIB(curses, tgetent, mysql_cv_termcap_lib=libcurses,
+ [AC_CHECK_LIB(termcap, tgetent, mysql_cv_termcap_lib=libtermcap,
+ mysql_cv_termcap_lib=NOT_FOUND)])])])
+AC_MSG_CHECKING(for termcap functions library)
+if test "$mysql_cv_termcap_lib" = "NOT_FOUND"; then
+AC_MSG_ERROR([No curses/termcap library found])
+elif test "$mysql_cv_termcap_lib" = "libtermcap"; then
+TERMCAP_LIB=-ltermcap
+elif test "$mysql_cv_termcap_lib" = "libncurses"; then
+TERMCAP_LIB=-lncurses
+else
+TERMCAP_LIB=-lcurses
+fi
+AC_MSG_RESULT($TERMCAP_LIB)
+])
+
+dnl Check type of signal routines (posix, 4.2bsd, 4.1bsd or v7)
+AC_DEFUN([MYSQL_SIGNAL_CHECK],
+[AC_REQUIRE([AC_TYPE_SIGNAL])
+AC_MSG_CHECKING(for type of signal functions)
+AC_CACHE_VAL(mysql_cv_signal_vintage,
+[
+ AC_TRY_LINK([#include <signal.h>],[
+ sigset_t ss;
+ struct sigaction sa;
+ sigemptyset(&ss); sigsuspend(&ss);
+ sigaction(SIGINT, &sa, (struct sigaction *) 0);
+ sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0);
+ ], mysql_cv_signal_vintage=posix,
+ [
+ AC_TRY_LINK([#include <signal.h>], [
+ int mask = sigmask(SIGINT);
+ sigsetmask(mask); sigblock(mask); sigpause(mask);
+ ], mysql_cv_signal_vintage=4.2bsd,
+ [
+ AC_TRY_LINK([
+ #include <signal.h>
+ RETSIGTYPE foo() { }], [
+ int mask = sigmask(SIGINT);
+ sigset(SIGINT, foo); sigrelse(SIGINT);
+ sighold(SIGINT); sigpause(SIGINT);
+ ], mysql_cv_signal_vintage=svr3, mysql_cv_signal_vintage=v7
+ )]
+ )]
+)
+])
+AC_MSG_RESULT($mysql_cv_signal_vintage)
+if test "$mysql_cv_signal_vintage" = posix; then
+AC_DEFINE(HAVE_POSIX_SIGNALS, [1],
+ [Signal handling is POSIX (sigset/sighold, etc)])
+elif test "$mysql_cv_signal_vintage" = "4.2bsd"; then
+AC_DEFINE([HAVE_BSD_SIGNALS], [1], [BSD style signals])
+elif test "$mysql_cv_signal_vintage" = svr3; then
+AC_DEFINE(HAVE_USG_SIGHOLD, [1], [sighold() is present and usable])
+fi
+])
+
+AC_DEFUN([MYSQL_CHECK_GETPW_FUNCS],
+[AC_MSG_CHECKING(whether programs are able to redeclare getpw functions)
+AC_CACHE_VAL(mysql_cv_can_redecl_getpw,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <pwd.h>
+extern struct passwd *getpwent();], [struct passwd *z; z = getpwent();],
+ mysql_cv_can_redecl_getpw=yes,mysql_cv_can_redecl_getpw=no)])
+AC_MSG_RESULT($mysql_cv_can_redecl_getpw)
+if test "$mysql_cv_can_redecl_getpw" = "no"; then
+AC_DEFINE(HAVE_GETPW_DECLS, [1], [getpwent() declaration present])
+fi
+])
+
+AC_DEFUN([MYSQL_HAVE_TIOCGWINSZ],
+[AC_MSG_CHECKING(for TIOCGWINSZ in sys/ioctl.h)
+AC_CACHE_VAL(mysql_cv_tiocgwinsz_in_ioctl,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/ioctl.h>], [int x = TIOCGWINSZ;],
+ mysql_cv_tiocgwinsz_in_ioctl=yes,mysql_cv_tiocgwinsz_in_ioctl=no)])
+AC_MSG_RESULT($mysql_cv_tiocgwinsz_in_ioctl)
+if test "$mysql_cv_tiocgwinsz_in_ioctl" = "yes"; then
+AC_DEFINE([GWINSZ_IN_SYS_IOCTL], [1],
+ [READLINE: your system defines TIOCGWINSZ in sys/ioctl.h.])
+fi
+])
+
+AC_DEFUN([MYSQL_HAVE_FIONREAD],
+[AC_MSG_CHECKING(for FIONREAD in sys/ioctl.h)
+AC_CACHE_VAL(mysql_cv_fionread_in_ioctl,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/ioctl.h>], [int x = FIONREAD;],
+ mysql_cv_fionread_in_ioctl=yes,mysql_cv_fionread_in_ioctl=no)])
+AC_MSG_RESULT($mysql_cv_fionread_in_ioctl)
+if test "$mysql_cv_fionread_in_ioctl" = "yes"; then
+AC_DEFINE([FIONREAD_IN_SYS_IOCTL], [1], [Do we have FIONREAD])
+fi
+])
+
+AC_DEFUN([MYSQL_HAVE_TIOCSTAT],
+[AC_MSG_CHECKING(for TIOCSTAT in sys/ioctl.h)
+AC_CACHE_VAL(mysql_cv_tiocstat_in_ioctl,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/ioctl.h>], [int x = TIOCSTAT;],
+ mysql_cv_tiocstat_in_ioctl=yes,mysql_cv_tiocstat_in_ioctl=no)])
+AC_MSG_RESULT($mysql_cv_tiocstat_in_ioctl)
+if test "$mysql_cv_tiocstat_in_ioctl" = "yes"; then
+AC_DEFINE(TIOCSTAT_IN_SYS_IOCTL, [1],
+ [declaration of TIOCSTAT in sys/ioctl.h])
+fi
+])
+
+AC_DEFUN([MYSQL_STRUCT_DIRENT_D_INO],
+[AC_REQUIRE([AC_HEADER_DIRENT])
+AC_MSG_CHECKING(if struct dirent has a d_ino member)
+AC_CACHE_VAL(mysql_cv_dirent_has_dino,
+[AC_TRY_COMPILE([
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+#else
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* SYSNDIR */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* SYSDIR */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif /* HAVE_DIRENT_H */
+],[
+struct dirent d; int z; z = d.d_ino;
+], mysql_cv_dirent_has_dino=yes, mysql_cv_dirent_has_dino=no)])
+AC_MSG_RESULT($mysql_cv_dirent_has_dino)
+if test "$mysql_cv_dirent_has_dino" = "yes"; then
+AC_DEFINE(STRUCT_DIRENT_HAS_D_INO, [1],
+ [d_ino member present in struct dirent])
+fi
+])
+
+AC_DEFUN([MYSQL_STRUCT_DIRENT_D_NAMLEN],
+[AC_REQUIRE([AC_HEADER_DIRENT])
+AC_MSG_CHECKING(if struct dirent has a d_namlen member)
+AC_CACHE_VAL(mysql_cv_dirent_has_dnamlen,
+[AC_TRY_COMPILE([
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+#else
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* SYSNDIR */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* SYSDIR */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif /* HAVE_DIRENT_H */
+],[
+struct dirent d; int z; z = (int)d.d_namlen;
+], mysql_cv_dirent_has_dnamlen=yes, mysql_cv_dirent_has_dnamlen=no)])
+AC_MSG_RESULT($mysql_cv_dirent_has_dnamlen)
+if test "$mysql_cv_dirent_has_dnamlen" = "yes"; then
+AC_DEFINE(STRUCT_DIRENT_HAS_D_NAMLEN, [1],
+ [d_namlen member present in struct dirent])
+fi
+])
+
+
+AC_DEFUN([MYSQL_TYPE_SIGHANDLER],
+[AC_MSG_CHECKING([whether signal handlers are of type void])
+AC_CACHE_VAL(mysql_cv_void_sighandler,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C"
+#endif
+void (*signal ()) ();],
+[int i;], mysql_cv_void_sighandler=yes, mysql_cv_void_sighandler=no)])dnl
+AC_MSG_RESULT($mysql_cv_void_sighandler)
+if test "$mysql_cv_void_sighandler" = "yes"; then
+AC_DEFINE(VOID_SIGHANDLER, [1], [sighandler type is void (*signal ()) ();])
+fi
+])
+
+AC_DEFUN([MYSQL_CXX_BOOL],
+[
+AC_REQUIRE([AC_PROG_CXX])
+AC_MSG_CHECKING(if ${CXX} supports bool types)
+AC_CACHE_VAL(mysql_cv_have_bool,
+[
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+AC_TRY_COMPILE(,[bool b = true;],
+mysql_cv_have_bool=yes,
+mysql_cv_have_bool=no)
+AC_LANG_RESTORE
+])
+AC_MSG_RESULT($mysql_cv_have_bool)
+if test "$mysql_cv_have_bool" = yes; then
+AC_DEFINE([HAVE_BOOL], [1], [bool is not defined by all C++ compilators])
+fi
+])dnl
+
+AC_DEFUN([MYSQL_STACK_DIRECTION],
+ [AC_CACHE_CHECK(stack direction for C alloca, ac_cv_c_stack_direction,
+ [AC_TRY_RUN([#include <stdlib.h>
+ int find_stack_direction ()
+ {
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+ }
+ int main ()
+ {
+ exit (find_stack_direction() < 0);
+ }], ac_cv_c_stack_direction=1, ac_cv_c_stack_direction=-1,
+ ac_cv_c_stack_direction=0)])
+ AC_DEFINE_UNQUOTED(STACK_DIRECTION, $ac_cv_c_stack_direction)
+])dnl
+
+AC_DEFUN([MYSQL_CHECK_LONGLONG_TO_FLOAT],
+[
+AC_MSG_CHECKING(if conversion of longlong to float works)
+AC_CACHE_VAL(ac_cv_conv_longlong_to_float,
+[AC_TRY_RUN([#include <stdio.h>
+typedef long long longlong;
+main()
+{
+ longlong ll=1;
+ float f;
+ FILE *file=fopen("conftestval", "w");
+ f = (float) ll;
+ fprintf(file,"%g\n",f);
+ fclose(file);
+ exit (0);
+}], ac_cv_conv_longlong_to_float=`cat conftestval`, ac_cv_conv_longlong_to_float=0, ifelse([$2], , , ac_cv_conv_longlong_to_float=$2))])dnl
+if test "$ac_cv_conv_longlong_to_float" = "1" -o "$ac_cv_conv_longlong_to_float" = "yes"
+then
+ ac_cv_conv_longlong_to_float=yes
+else
+ ac_cv_conv_longlong_to_float=no
+fi
+AC_MSG_RESULT($ac_cv_conv_longlong_to_float)
+])
+
+AC_DEFUN([MYSQL_CHECK_VIO], [
+dnl
+dnl we always use vio: no need for special defines
+dnl
+ AC_DEFINE([HAVE_VIO_READ_BUFF], [1],
+ [Define to enable buffered read. This works only if syscalls
+ read/recv return as soon as there is some data in the kernel
+ buffer, no matter how big the given buffer is.])
+])
+
+# Local version of _AC_PROG_CXX_EXIT_DECLARATION that does not
+# include #stdlib.h as default as this breaks things on Solaris
+# (Conflicts with pthreads and big file handling)
+
+m4_define([_AC_PROG_CXX_EXIT_DECLARATION],
+[for ac_declaration in \
+ ''\
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);' \
+ '#include <stdlib.h>'
+do
+ _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$ac_declaration
+@%:@include <stdlib.h>],
+ [exit (42);])],
+ [],
+ [continue])
+ _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$ac_declaration],
+ [exit (42);])],
+ [break])
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+])# _AC_PROG_CXX_EXIT_DECLARATION
+
+dnl ---------------------------------------------------------------------------
+
+
+dnl ---------------------------------------------------------------------------
+dnl Macro: MYSQL_CHECK_BIG_TABLES
+dnl Sets BIG_TABLES if --with-big-tables is used
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([MYSQL_CHECK_BIG_TABLES], [
+ AC_ARG_WITH([big-tables],
+ [
+ --with-big-tables Support tables with more than 4 G rows even on 32 bit platforms],
+ [bigtables="$withval"],
+ [bigtables=no])
+ AC_MSG_CHECKING([for big tables support])
+
+ case "$bigtables" in
+ yes )
+ AC_DEFINE([BIG_TABLES], [1], [Support big tables])
+ AC_MSG_RESULT([yes])
+ ;;
+ * )
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+
+])
+dnl ---------------------------------------------------------------------------
+dnl END OF MYSQL_CHECK_BIG_TABLES SECTION
+dnl ---------------------------------------------------------------------------
+
diff --git a/config/ac-macros/openssl.m4 b/config/ac-macros/openssl.m4
new file mode 100644
index 00000000000..aa46dd45360
--- /dev/null
+++ b/config/ac-macros/openssl.m4
@@ -0,0 +1,133 @@
+AC_DEFUN([MYSQL_FIND_OPENSSL], [
+ incs="$1"
+ libs="$2"
+ case "$incs---$libs" in
+ ---)
+ for d in /usr/ssl/include /usr/local/ssl/include /usr/include \
+/usr/include/ssl /opt/ssl/include /opt/openssl/include \
+/usr/local/ssl/include /usr/local/include /usr/freeware/include ; do
+ if test -f $d/openssl/ssl.h ; then
+ OPENSSL_INCLUDE=-I$d
+ fi
+ done
+
+ for d in /usr/ssl/lib /usr/local/ssl/lib /usr/lib/openssl \
+/usr/lib /usr/lib64 /opt/ssl/lib /opt/openssl/lib \
+/usr/freeware/lib32 /usr/local/lib/ ; do
+ if test -f $d/libssl.a || test -f $d/libssl.so || test -f $d/libssl.dylib ; then
+ OPENSSL_LIB=$d
+ fi
+ done
+ ;;
+ ---* | *---)
+ AC_MSG_ERROR([if either 'includes' or 'libs' is specified, both must be specified])
+ ;;
+ * )
+ if test -f $incs/openssl/ssl.h ; then
+ OPENSSL_INCLUDE=-I$incs
+ fi
+ if test -f $libs/libssl.a || test -f $libs/libssl.so || test -f $libs/libssl.dylib ; then
+ OPENSSL_LIB=$libs
+ fi
+ ;;
+ esac
+
+ # On RedHat 9 we need kerberos to compile openssl
+ for d in /usr/kerberos/include
+ do
+ if test -f $d/krb5.h ; then
+ OPENSSL_KERBEROS_INCLUDE="$d"
+ fi
+ done
+
+
+ if test -z "$OPENSSL_LIB" -o -z "$OPENSSL_INCLUDE" ; then
+ echo "Could not find an installation of OpenSSL"
+ if test -n "$OPENSSL_LIB" ; then
+ if test "$TARGET_LINUX" = "true"; then
+ echo "Looks like you've forgotten to install OpenSSL development RPM"
+ fi
+ fi
+ exit 1
+ fi
+
+])
+
+AC_DEFUN([MYSQL_CHECK_OPENSSL], [
+AC_MSG_CHECKING(for OpenSSL)
+ AC_ARG_WITH([openssl],
+ [ --with-openssl[=DIR] Include the OpenSSL support],
+ [openssl="$withval"],
+ [openssl=no])
+
+ AC_ARG_WITH([openssl-includes],
+ [
+ --with-openssl-includes=DIR
+ Find OpenSSL headers in DIR],
+ [openssl_includes="$withval"],
+ [openssl_includes=""])
+
+ AC_ARG_WITH([openssl-libs],
+ [
+ --with-openssl-libs=DIR
+ Find OpenSSL libraries in DIR],
+ [openssl_libs="$withval"],
+ [openssl_libs=""])
+
+ if test "$openssl" != "no"
+ then
+ if test "$openssl" != "yes"
+ then
+ if test -z "$openssl_includes"
+ then
+ openssl_includes="$openssl/include"
+ fi
+ if test -z "$openssl_libs"
+ then
+ openssl_libs="$openssl/lib"
+ fi
+ fi
+ MYSQL_FIND_OPENSSL([$openssl_includes], [$openssl_libs])
+ #force VIO use
+ AC_MSG_RESULT(yes)
+ openssl_libs="-L$OPENSSL_LIB -lssl -lcrypto"
+ # Don't set openssl_includes to /usr/include as this gives us a lot of
+ # compiler warnings when using gcc 3.x
+ openssl_includes=""
+ if test "$OPENSSL_INCLUDE" != "-I/usr/include"
+ then
+ openssl_includes="$OPENSSL_INCLUDE"
+ fi
+ if test "$OPENSSL_KERBEROS_INCLUDE"
+ then
+ openssl_includes="$openssl_includes -I$OPENSSL_KERBEROS_INCLUDE"
+ fi
+ AC_DEFINE([HAVE_OPENSSL], [1], [OpenSSL])
+
+ # openssl-devel-0.9.6 requires dlopen() and we can't link staticly
+ # on many platforms (We should actually test this here, but it's quite
+ # hard) to do as we are doing libtool for linking.
+ using_static=""
+ case "$CLIENT_EXTRA_LDFLAGS $MYSQLD_EXTRA_LDFLAGS" in
+ *-all-static*) using_static="yes" ;;
+ esac
+ if test "$using_static" = "yes"
+ then
+ echo "You can't use the --all-static link option when using openssl."
+ exit 1
+ fi
+ NON_THREADED_CLIENT_LIBS="$NON_THREADED_CLIENT_LIBS $openssl_libs"
+ else
+ AC_MSG_RESULT(no)
+ if test ! -z "$openssl_includes"
+ then
+ AC_MSG_ERROR(Can't have --with-openssl-includes without --with-openssl);
+ fi
+ if test ! -z "$openssl_libs"
+ then
+ AC_MSG_ERROR(Can't have --with-openssl-libs without --with-openssl);
+ fi
+ fi
+ AC_SUBST(openssl_libs)
+ AC_SUBST(openssl_includes)
+])
diff --git a/config/ac-macros/readline.m4 b/config/ac-macros/readline.m4
new file mode 100644
index 00000000000..79c6479d15d
--- /dev/null
+++ b/config/ac-macros/readline.m4
@@ -0,0 +1,61 @@
+AC_DEFUN([MYSQL_CHECK_READLINE_DECLARES_HIST_ENTRY], [
+ AC_CACHE_CHECK([HIST_ENTRY is declared in readline/readline.h], mysql_cv_hist_entry_declared,
+ AC_TRY_COMPILE(
+ [
+ #include "stdio.h"
+ #include "readline/readline.h"
+ ],
+ [
+ HIST_ENTRY entry;
+ ],
+ [
+ mysql_cv_hist_entry_declared=yes
+ AC_DEFINE_UNQUOTED(HAVE_HIST_ENTRY, [1],
+ [HIST_ENTRY is defined in the outer libeditreadline])
+ ],
+ [mysql_cv_libedit_interface=no]
+ )
+ )
+])
+
+AC_DEFUN([MYSQL_CHECK_LIBEDIT_INTERFACE], [
+ AC_CACHE_CHECK([libedit variant of rl_completion_entry_function], mysql_cv_libedit_interface,
+ AC_TRY_COMPILE(
+ [
+ #include "stdio.h"
+ #include "readline/readline.h"
+ ],
+ [
+ char res= *(*rl_completion_entry_function)(0,0);
+ completion_matches(0,0);
+ ],
+ [
+ mysql_cv_libedit_interface=yes
+ AC_DEFINE_UNQUOTED([USE_LIBEDIT_INTERFACE], [1],
+ [used libedit interface (can we dereference result of rl_completion_entry_function)])
+ ],
+ [mysql_cv_libedit_interface=no]
+ )
+ )
+])
+
+AC_DEFUN([MYSQL_CHECK_NEW_RL_INTERFACE], [
+ AC_CACHE_CHECK([defined rl_compentry_func_t and rl_completion_func_t], mysql_cv_new_rl_interface,
+ AC_TRY_COMPILE(
+ [
+ #include "stdio.h"
+ #include "readline/readline.h"
+ ],
+ [
+ rl_completion_func_t *func1= (rl_completion_func_t*)0;
+ rl_compentry_func_t *func2= (rl_compentry_func_t*)0;
+ ],
+ [
+ mysql_cv_new_rl_interface=yes
+ AC_DEFINE_UNQUOTED([USE_NEW_READLINE_INTERFACE], [1],
+ [used new readline interface (are rl_completion_func_t and rl_compentry_func_t defined)])
+ ],
+ [mysql_cv_new_rl_interface=no]
+ )
+ )
+])
diff --git a/config/ac-macros/zlib.m4 b/config/ac-macros/zlib.m4
new file mode 100644
index 00000000000..94a26f33dd3
--- /dev/null
+++ b/config/ac-macros/zlib.m4
@@ -0,0 +1,116 @@
+dnl Define zlib paths to point at bundled zlib
+
+AC_DEFUN([MYSQL_USE_BUNDLED_ZLIB], [
+ZLIB_INCLUDES="-I\$(top_srcdir)/zlib"
+ZLIB_LIBS="\$(top_builddir)/zlib/libz.la"
+dnl Omit -L$pkglibdir as it's always in the list of mysql_config deps.
+ZLIB_DEPS="-lz"
+zlib_dir="zlib"
+AC_SUBST([zlib_dir])
+mysql_cv_compress="yes"
+])
+
+dnl Auxiliary macro to check for zlib at given path
+
+AC_DEFUN([MYSQL_CHECK_ZLIB_DIR], [
+save_INCLUDES="$INCLUDES"
+save_LIBS="$LIBS"
+INCLUDES="$INCLUDES $ZLIB_INCLUDES"
+LIBS="$LIBS $ZLIB_LIBS"
+AC_CACHE_VAL([mysql_cv_compress],
+ [AC_TRY_LINK([#include <zlib.h>],
+ [return compress(0, (unsigned long*) 0, "", 0);],
+ [mysql_cv_compress="yes"
+ AC_MSG_RESULT([ok])],
+ [mysql_cv_compress="no"])
+ ])
+INCLUDES="$save_INCLUDES"
+LIBS="$save_LIBS"
+])
+
+dnl MYSQL_CHECK_ZLIB_WITH_COMPRESS
+dnl ------------------------------------------------------------------------
+dnl @synopsis MYSQL_CHECK_ZLIB_WITH_COMPRESS
+dnl
+dnl Provides the following configure options:
+dnl --with-zlib-dir=DIR
+dnl Possible DIR values are:
+dnl - "no" - the macro will disable use of compression functions
+dnl - "bundled" - means use zlib bundled along with MySQL sources
+dnl - empty, or not specified - the macro will try default system
+dnl library (if present), and in case of error will fall back to
+dnl bundled zlib
+dnl - zlib location prefix - given location prefix, the macro expects
+dnl to find the library headers in $prefix/include, and binaries in
+dnl $prefix/lib. If zlib headers or binaries weren't found at $prefix, the
+dnl macro bails out with error.
+dnl
+dnl If the library was found, this function #defines HAVE_COMPRESS
+dnl and configure variables ZLIB_INCLUDES (i.e. -I/path/to/zlib/include),
+dnl ZLIB_LIBS (i. e. -L/path/to/zlib/lib -lz) and ZLIB_DEPS which is
+dnl used in mysql_config and is always the same as ZLIB_LIBS except to
+dnl when we use the bundled zlib. In the latter case ZLIB_LIBS points to the
+dnl build dir ($top_builddir/zlib), while mysql_config must point to the
+dnl installation dir ($pkglibdir), so ZLIB_DEPS is set to point to
+dnl $pkglibdir.
+
+AC_DEFUN([MYSQL_CHECK_ZLIB_WITH_COMPRESS], [
+AC_MSG_CHECKING([for zlib compression library])
+case $SYSTEM_TYPE in
+*netware* | *modesto*)
+ AC_MSG_RESULT(ok)
+ AC_DEFINE([HAVE_COMPRESS], [1], [Define to enable compression support])
+ ;;
+ *)
+ AC_ARG_WITH([zlib-dir],
+ AC_HELP_STRING([--with-zlib-dir=DIR],
+ [Provide MySQL with a custom location of
+ compression library. Given DIR, zlib binary is
+ assumed to be in $DIR/lib and header files
+ in $DIR/include.]),
+ [mysql_zlib_dir=${withval}],
+ [mysql_zlib_dir=""])
+ case "$mysql_zlib_dir" in
+ "no")
+ mysql_cv_compress="no"
+ AC_MSG_RESULT([disabled])
+ ;;
+ "bundled")
+ MYSQL_USE_BUNDLED_ZLIB
+ AC_MSG_RESULT([using bundled zlib])
+ ;;
+ "")
+ ZLIB_INCLUDES=""
+ ZLIB_LIBS="-lz"
+ MYSQL_CHECK_ZLIB_DIR
+ if test "$mysql_cv_compress" = "no"; then
+ MYSQL_USE_BUNDLED_ZLIB
+ AC_MSG_RESULT([system-wide zlib not found, using one bundled with MySQL])
+ fi
+ ;;
+ *)
+ if test -f "$mysql_zlib_dir/lib/libz.a" -a \
+ -f "$mysql_zlib_dir/include/zlib.h"; then
+ ZLIB_INCLUDES="-I$mysql_zlib_dir/include"
+ ZLIB_LIBS="-L$mysql_zlib_dir/lib -lz"
+ MYSQL_CHECK_ZLIB_DIR
+ fi
+ if test "x$mysql_cv_compress" != "xyes"; then
+ AC_MSG_ERROR([headers or binaries were not found in $mysql_zlib_dir/{include,lib}])
+ fi
+ ;;
+ esac
+ if test "$mysql_cv_compress" = "yes"; then
+ if test "x$ZLIB_DEPS" = "x"; then
+ ZLIB_DEPS="$ZLIB_LIBS"
+ fi
+ AC_SUBST([ZLIB_LIBS])
+ AC_SUBST([ZLIB_DEPS])
+ AC_SUBST([ZLIB_INCLUDES])
+ AC_DEFINE([HAVE_COMPRESS], [1], [Define to enable compression support])
+ fi
+ ;;
+esac
+])
+
+dnl ------------------------------------------------------------------------
diff --git a/configure.in b/configure.in
index 6efdc56d450..e3dba45ca19 100644
--- a/configure.in
+++ b/configure.in
@@ -1,11 +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_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
-# The Docs Makefile.am parses this line!
-# remember to also change ndb version below and update version.c in ndb
-AM_INIT_AUTOMAKE(mysql, 4.1.12)
+# Don't forget to also update the NDB lines below.
+AM_INIT_AUTOMAKE(mysql, 5.0.6-beta)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
@@ -14,10 +15,10 @@ DOT_FRM_VERSION=6
SHARED_LIB_VERSION=14:0:0
# ndb version
-NDB_VERSION_MAJOR=4
-NDB_VERSION_MINOR=1
-NDB_VERSION_BUILD=12
-NDB_VERSION_STATUS=""
+NDB_VERSION_MAJOR=5
+NDB_VERSION_MINOR=0
+NDB_VERSION_BUILD=6
+NDB_VERSION_STATUS="beta"
# Set all version vars based on $VERSION. How do we do this more elegant ?
# Remember that regexps needs to quote [ and ] since this is run through m4
@@ -29,33 +30,31 @@ MYSQL_VERSION_ID=`echo $MYSQL_NO_DASH_VERSION. | sed -e 's/[[^0-9.]]//g; s/\./
MYSQL_TCP_PORT_DEFAULT=3306
MYSQL_UNIX_ADDR_DEFAULT="/tmp/mysql.sock"
+dnl Include m4
+sinclude(config/ac-macros/alloca.m4)
+sinclude(config/ac-macros/check_cpu.m4)
+sinclude(config/ac-macros/character_sets.m4)
+sinclude(config/ac-macros/compiler_flag.m4)
+sinclude(config/ac-macros/ha_archive.m4)
+sinclude(config/ac-macros/ha_berkeley.m4)
+sinclude(config/ac-macros/ha_blackhole.m4)
+sinclude(config/ac-macros/ha_example.m4)
+sinclude(config/ac-macros/ha_federated.m4)
+sinclude(config/ac-macros/ha_innodb.m4)
+sinclude(config/ac-macros/ha_ndbcluster.m4)
+sinclude(config/ac-macros/ha_tina.m4)
+sinclude(config/ac-macros/large_file.m4)
+sinclude(config/ac-macros/misc.m4)
+sinclude(config/ac-macros/openssl.m4)
+sinclude(config/ac-macros/readline.m4)
+sinclude(config/ac-macros/zlib.m4)
+
# Remember to add a directory sql/share/LANGUAGE
AVAILABLE_LANGUAGES="\
czech danish dutch english estonian french german greek hungarian \
-italian japanese japanese-sjis korean norwegian norwegian-ny polish portuguese \
+italian japanese korean norwegian norwegian-ny polish portuguese \
romanian russian serbian slovak spanish swedish ukrainian"
-# Generate make rules for all error messages
-AVAILABLE_LANGUAGES_ERRORS=
-AVAILABLE_LANGUAGES_ERRORS_RULES=$srcdir/ac_available_languages_fragment
-rm -f $AVAILABLE_LANGUAGES_ERRORS_RULES
-for i in $AVAILABLE_LANGUAGES
-do
- AVAILABLE_LANGUAGES_ERRORS="$AVAILABLE_LANGUAGES_ERRORS $i/errmsg.sys"
- case $host_os in
- netware* | modesto*)
- echo "$i/errmsg.sys: $i/errmsg.txt
- \$(top_builddir)/extra/comp_err.linux -C\$(srcdir)/charsets/ $i/errmsg.txt $i/errmsg.sys" \
- >> $AVAILABLE_LANGUAGES_ERRORS_RULES
- ;;
- *)
- echo "$i/errmsg.sys: $i/errmsg.txt
- \$(top_builddir)/extra/comp_err -C\$(srcdir)/charsets/ $i/errmsg.txt $i/errmsg.sys" \
- >> $AVAILABLE_LANGUAGES_ERRORS_RULES
- ;;
- esac
-done
-
#####
#####
@@ -71,7 +70,6 @@ AC_DEFINE_UNQUOTED([DOT_FRM_VERSION], [$DOT_FRM_VERSION],
AC_SUBST(SHARED_LIB_VERSION)
AC_SUBST(AVAILABLE_LANGUAGES)
AC_SUBST(AVAILABLE_LANGUAGES_ERRORS)
-AC_SUBST_FILE(AVAILABLE_LANGUAGES_ERRORS_RULES)
AC_SUBST([NDB_VERSION_MAJOR])
AC_SUBST([NDB_VERSION_MINOR])
@@ -118,14 +116,11 @@ AC_SUBST(SAVE_LDFLAGS)
AC_SUBST(SAVE_CXXLDFLAGS)
AC_SUBST(CXXLDFLAGS)
-AC_PREREQ(2.58)dnl Minimum Autoconf version required.
-
#AC_ARG_PROGRAM # Automaticly invoked by AM_INIT_AUTOMAKE
+
AM_SANITY_CHECK
# This is needed is SUBDIRS is set
AC_PROG_MAKE_SET
-# This generates rules for webpage generation for the MySQL homepage.
-AM_CONDITIONAL(LOCAL, test -d ../web/SitePages)
# This is need before AC_PROG_CC
#
@@ -272,48 +267,6 @@ AC_TRY_RUN([
;;
esac
-
-# option, cache_name, variable,
-# code to execute if yes, code to exectute if fail
-AC_DEFUN([AC_SYS_COMPILER_FLAG],
-[
- AC_MSG_CHECKING($1)
- OLD_CFLAGS="[$]CFLAGS"
- AC_CACHE_VAL(mysql_cv_option_$2,
- [
- CFLAGS="[$]OLD_CFLAGS $1"
- AC_TRY_RUN([int main(){exit(0);}],mysql_cv_option_$2=yes,mysql_cv_option_$2=no,mysql_cv_option_$2=no)
- ])
-
- CFLAGS="[$]OLD_CFLAGS"
-
- if test x"[$]mysql_cv_option_$2" = "xyes" ; then
- $3="[$]$3 $1"
- AC_MSG_RESULT(yes)
- $5
- else
- AC_MSG_RESULT(no)
- $4
- fi
-])
-
-# arch, option, cache_name, variable
-AC_DEFUN([AC_SYS_CPU_COMPILER_FLAG],
-[
- if test "`uname -m 2>/dev/null`" = "$1" ; then
- AC_SYS_COMPILER_FLAG($2,$3,$4)
- fi
-])
-
-# os, option, cache_name, variable
-AC_DEFUN([AC_SYS_OS_COMPILER_FLAG],
-[
- if test "x$mysql_cv_sys_os" = "x$1" ; then
- AC_SYS_COMPILER_FLAG($2,$3,$4)
- fi
-])
-
-# We need some special hacks when running slowaris
AC_PATH_PROG(uname_prog, uname, no)
# We should go through this and put all the explictly system dependent
@@ -382,8 +335,7 @@ AC_SUBST(LD)
AC_SUBST(INSTALL_SCRIPT)
export CC CXX CFLAGS LD LDFLAGS AR
-
-ndb_cxxflags_fix=
+echo "GXX: $GXX"
if test "$GXX" = "yes"
then
# mysqld requires -fno-implicit-templates.
@@ -391,16 +343,16 @@ then
# mysqld doesn't use run-time-type-checking, so we disable it.
CXXFLAGS="$CXXFLAGS -fno-implicit-templates -fno-exceptions -fno-rtti"
- # If you are using 'gcc' 3.0 (not g++) to compile C++ programs on Linux,
- # we will gets some problems when linking static programs.
- # The following code is used to fix this problem.
-
+ #CXX_VERNO=`echo $CXX_VERSION | sed -e 's/[[^0-9. ]]//g; s/^ *//g; s/ .*//g'`
+ echo "CXX: $CXX"
if echo $CXX | grep gcc > /dev/null 2>&1
then
- if $CXX -v 2>&1 | grep 'version 3' > /dev/null 2>&1
- then
- CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL"
- fi
+ echo "Setting CXXFLAGS"
+ # If you are using 'gcc' 3.0 (not g++) to compile C++ programs on Linux,
+ # we will gets some problems when linking static programs.
+ # The following code is used to fix this problem.
+ CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL"
+ echo "Using MYSYS_NEW for static linking with gcc"
fi
fi
@@ -479,35 +431,35 @@ PS=$ac_cv_path_PS
# Linux style
if $PS p $$ 2> /dev/null | grep $0 > /dev/null
then
- FIND_PROC="$PS p \$\$PID | grep mysqld > /dev/null"
+ FIND_PROC="$PS p \$\$PID | grep \$\$MYSQLD > /dev/null"
# Solaris
elif $PS -fp $$ 2> /dev/null | grep $0 > /dev/null
then
- FIND_PROC="$PS -p \$\$PID | grep mysqld > /dev/null"
+ FIND_PROC="$PS -p \$\$PID | grep \$\$MYSQLD > /dev/null"
# BSD style
elif $PS -uaxww 2> /dev/null | grep $0 > /dev/null
then
- FIND_PROC="$PS -uaxww | grep mysqld | grep \" \$\$PID \" > /dev/null"
+ FIND_PROC="$PS -uaxww | grep \$\$MYSQLD | grep \" \$\$PID \" > /dev/null"
# SysV style
elif $PS -ef 2> /dev/null | grep $0 > /dev/null
then
- FIND_PROC="$PS -ef | grep mysqld | grep \" \$\$PID \" > /dev/null"
+ FIND_PROC="$PS -ef | grep \$\$MYSQLD | grep \" \$\$PID \" > /dev/null"
# Do anybody use this?
elif $PS $$ 2> /dev/null | grep $0 > /dev/null
then
- FIND_PROC="$PS \$\$PID | grep mysqld > /dev/null"
+ FIND_PROC="$PS \$\$PID | grep \$\$MYSQLD > /dev/null"
else
case $SYSTEM_TYPE in
*freebsd*)
- FIND_PROC="$PS p \$\$PID | grep mysqld > /dev/null"
+ FIND_PROC="$PS p \$\$PID | grep \$\$MYSQLD > /dev/null"
;;
*darwin*)
- FIND_PROC="$PS -uaxww | grep mysqld | grep \" \$\$PID \" > /dev/null"
+ FIND_PROC="$PS -uaxww | grep \$\$MYSQLD | grep \" \$\$PID \" > /dev/null"
;;
*cygwin*)
- FIND_PROC="$PS -e | grep mysqld | grep \" \$\$PID \" > /dev/null"
+ FIND_PROC="$PS -e | grep \$\$MYSQLD | grep \" \$\$PID \" > /dev/null"
;;
- *netware* | *modesto*)
+ *netware*)
FIND_PROC=
;;
*)
@@ -627,18 +579,6 @@ AC_ARG_WITH(server-suffix,
)
AC_SUBST(MYSQL_SERVER_SUFFIX)
-# Set flags if we wants to have MIT threads.
-AC_ARG_WITH(mit-threads,
- [ --with-mit-threads Always use included thread lib.],
- [ with_mit_threads=$withval ],
- [ with_mit_threads=no ]
- )
-
-if test "$with_mit_threads" = "yes"
-then
- enable_largefile="no" # Will not work on Linux.
-fi
-
# Set flags if we want to force to use pthreads
AC_ARG_WITH(pthread,
[ --with-pthread Force use of pthread library.],
@@ -695,20 +635,6 @@ else
fi
-AC_MSG_CHECKING(if we should use RAID)
-AC_ARG_WITH(raid,
- [ --with-raid Enable RAID Support],
- [ USE_RAID=$withval ],
- [ USE_RAID=no ]
- )
-if test "$USE_RAID" = "yes"
-then
- AC_MSG_RESULT([yes])
- AC_DEFINE([USE_RAID], [1], [Use MySQL RAID])
-else
- AC_MSG_RESULT([no])
-fi
-
# Use this to set the place used for unix socket used to local communication.
AC_ARG_WITH(unix-socket-path,
[ --with-unix-socket-path=SOCKET
@@ -772,7 +698,8 @@ AC_CHECK_HEADERS(fcntl.h float.h floatingpoint.h ieeefp.h limits.h \
strings.h string.h synch.h sys/mman.h sys/socket.h netinet/in.h arpa/inet.h \
sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \
unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h \
- sys/ioctl.h malloc.h sys/malloc.h linux/config.h sys/resource.h sys/param.h)
+ sys/ioctl.h malloc.h sys/malloc.h sys/ipc.h sys/shm.h linux/config.h \
+ sys/resource.h sys/param.h)
#--------------------------------------------------------------------
# Check for system libraries. Adds the library to $LIBS
@@ -799,6 +726,22 @@ AC_CHECK_FUNC(crypt, AC_DEFINE([HAVE_CRYPT], [1], [crypt]))
AC_CHECK_FUNC(sem_init, , AC_CHECK_LIB(posix4, sem_init))
MYSQL_CHECK_ZLIB_WITH_COMPRESS
+# For large pages support
+if test "$TARGET_LINUX" = "true"
+then
+ # For SHM_HUGETLB on Linux
+ AC_CHECK_DECLS(SHM_HUGETLB,
+ AC_DEFINE([HAVE_LARGE_PAGES], [1],
+ [Define if you have large pages support])
+ AC_DEFINE([HUGETLB_USE_PROC_MEMINFO], [1],
+ [Define if /proc/meminfo shows the huge page size (Linux only)])
+ , ,
+ [
+#include <sys/shm.h>
+ ]
+ )
+fi
+
#--------------------------------------------------------------------
# Check for TCP wrapper support
#--------------------------------------------------------------------
@@ -886,7 +829,7 @@ int main()
[ USE_PSTACK=no ])
pstack_libs=
pstack_dirs=
- if test "$USE_PSTACK" = yes -a "$TARGET_LINUX" = "true" -a "$BASE_MACHINE_TYPE" = "i386" -a "$with_mit_threads" = "no"
+ if test "$USE_PSTACK" = yes -a "$TARGET_LINUX" = "true" -a "$BASE_MACHINE_TYPE" = "i386"
then
have_libiberty= have_libbfd=
my_save_LIBS="$LIBS"
@@ -971,6 +914,7 @@ esac
MAX_C_OPTIMIZE="-O3"
MAX_CXX_OPTIMIZE="-O3"
+ndb_cxxflags_fix=
case $SYSTEM_TYPE-$MACHINE_TYPE-$ac_cv_prog_gcc in
# workaround for Sun Forte/x86 see BUG#4681
*solaris*-i?86-no)
@@ -1268,7 +1212,7 @@ esac
with_posix_threads="no"
# Search thread lib on Linux
-if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
+if test "$with_named_thread" = "no"
then
AC_MSG_CHECKING("Linux threads")
if test "$TARGET_LINUX" = "true"
@@ -1531,7 +1475,7 @@ then
fi
# Hack for Siemens UNIX
-if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
+if test "$with_named_thread" = "no"
then
AC_MSG_CHECKING("Siemens threads")
if test -f /usr/lib/libxnet.so -a "$SYSTEM_TYPE" = "sni-sysv4"
@@ -1559,7 +1503,7 @@ fi
# Hack for Solaris >= 2.5
# We want both the new and the old interface
-if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no"
+if test "$with_named_thread" = "no"
then
AC_MSG_CHECKING("Solaris threads")
if test -f /usr/lib/libpthread.so -a -f /usr/lib/libthread.so
@@ -1577,14 +1521,21 @@ if test "$with_named_thread" != "no"
then
LIBS="$with_named_thread $LIBS $with_named_thread"
with_posix_threads="yes"
- with_mit_threads="no"
AC_MSG_RESULT("$with_named_thread")
else
AC_MSG_RESULT("no")
- if test "$with_mit_threads" = "no"
+ # pthread_create is in standard libraries (As in BSDI 3.0)
+ AC_MSG_CHECKING("for pthread_create in -libc");
+ AC_TRY_LINK(
+ [#include <pthread.h>],
+ [ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
+ with_posix_threads=yes, with_posix_threads=no)
+ AC_MSG_RESULT("$with_posix_threads")
+ if test "$with_posix_threads" = "no"
then
- # pthread_create is in standard libraries (As in BSDI 3.0)
- AC_MSG_CHECKING("for pthread_create in -libc");
+ AC_MSG_CHECKING("for pthread_create in -lpthread");
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS -lpthread"
AC_TRY_LINK(
[#include <pthread.h>],
[ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
@@ -1592,39 +1543,23 @@ else
AC_MSG_RESULT("$with_posix_threads")
if test "$with_posix_threads" = "no"
then
- AC_MSG_CHECKING("for pthread_create in -lpthread");
- ac_save_LIBS="$LIBS"
- LIBS="$LIBS -lpthread"
+ LIBS=" $ac_save_LIBS -lpthreads"
+ AC_MSG_CHECKING("for pthread_create in -lpthreads");
AC_TRY_LINK(
[#include <pthread.h>],
- [ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
+ [ pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
with_posix_threads=yes, with_posix_threads=no)
AC_MSG_RESULT("$with_posix_threads")
if test "$with_posix_threads" = "no"
then
- LIBS=" $ac_save_LIBS -lpthreads"
- AC_MSG_CHECKING("for pthread_create in -lpthreads");
+ # This is for FreeBSD
+ LIBS="$ac_save_LIBS -pthread"
+ AC_MSG_CHECKING("for pthread_create in -pthread");
AC_TRY_LINK(
[#include <pthread.h>],
[ pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
with_posix_threads=yes, with_posix_threads=no)
AC_MSG_RESULT("$with_posix_threads")
- if test "$with_posix_threads" = "no"
- then
- # This is for FreeBSD
- LIBS="$ac_save_LIBS -pthread"
- AC_MSG_CHECKING("for pthread_create in -pthread");
- AC_TRY_LINK(
- [#include <pthread.h>],
- [ pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ],
- with_posix_threads=yes, with_posix_threads=no)
- AC_MSG_RESULT("$with_posix_threads")
- if test "$with_posix_threads" = "no"
- then
- with_mit_threads="yes"
- LIBS="$ac_save_LIBS"
- fi
- fi
fi
fi
fi
@@ -1664,7 +1599,7 @@ AC_SUBST(LIBDL)
# System characteristics
case $SYSTEM_TYPE in
- *netware* | *modesto*) ;;
+ *netware*) ;;
*)
AC_SYS_RESTARTABLE_SYSCALLS
;;
@@ -1694,10 +1629,12 @@ else
fi
if expr "$SYSTEM_TYPE" : ".*netware.*" > /dev/null; then
- DEBUG_CFLAGS="$DEBUG_CFLAGS -DDEBUG -sym internal,codeview4"
- DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -DDEBUG -sym internal,codeview4"
- OPTIMIZE_CFLAGS="$OPTIMIZE_CFLAGS -DNDEBUG"
- OPTIMIZE_CXXFLAGS="$OPTIMIZE_CXXFLAGS -DNDEBUG"
+ DEBUG_CFLAGS="-g -DDEBUG -sym internal,codeview4"
+ DEBUG_CXXFLAGS="-g -DDEBUG -sym internal,codeview4"
+ DEBUG_OPTIMIZE_CC="-DDEBUG"
+ DEBUG_OPTIMIZE_CXX="-DDEBUG"
+ OPTIMIZE_CFLAGS="-O3 -DNDEBUG"
+ OPTIMIZE_CXXFLAGS="-O3 -DNDEBUG"
fi
AC_ARG_WITH(debug,
@@ -1712,8 +1649,8 @@ then
elif test "$with_debug" = "full"
then
# Full debug. Very slow in some cases
- CFLAGS="$DEBUG_CFLAGS -DDBUG_ON -DSAFE_MUTEX -DSAFEMALLOC -DUNIV_DEBUG $CFLAGS"
- CXXFLAGS="$DEBUG_CXXFLAGS -DDBUG_ON -DSAFE_MUTEX -DSAFEMALLOC -DUNIV_DEBUG $CXXFLAGS"
+ CFLAGS="$DEBUG_CFLAGS -DDBUG_ON -DSAFE_MUTEX -DSAFEMALLOC $CFLAGS"
+ CXXFLAGS="$DEBUG_CXXFLAGS -DDBUG_ON -DSAFE_MUTEX -DSAFEMALLOC $CXXFLAGS"
else
# Optimized version. No debug
CFLAGS="$OPTIMIZE_CFLAGS -DDBUG_OFF $CFLAGS"
@@ -1800,6 +1737,7 @@ examine config.log for possible errors. If you want to report this, use
'scripts/mysqlbug' and include at least the last 20 rows from config.log!])
fi
AC_CHECK_SIZEOF(char*, 4)
+AC_CHECK_SIZEOF(short, 2)
AC_CHECK_SIZEOF(int, 4)
if test "$ac_cv_sizeof_int" -eq 0
then
@@ -1945,7 +1883,7 @@ if test "$GCC" != "yes"; then
AC_SYS_COMPILER_FLAG(-nolib_inline,nolib_inline,CFLAGS,[],[])
fi
-AC_FUNC_MMAP
+#AC_FUNC_MMAP
AC_TYPE_SIGNAL
MYSQL_TYPE_QSORT
AC_FUNC_UTIME_NULL
@@ -1956,7 +1894,7 @@ AC_CHECK_FUNCS(alarm bcmp bfill bmove bzero chsize cuserid fchmod fcntl \
getcwd gethostbyaddr_r gethostbyname_r getpass getpassphrase getpwnam \
getpwuid getrlimit getrusage getwd gmtime_r index initgroups isnan \
localtime_r locking longjmp lrand48 madvise mallinfo memcpy memmove \
- mkstemp mlockall perror poll pread pthread_attr_create \
+ mkstemp mlockall perror poll pread pthread_attr_create mmap getpagesize \
pthread_attr_getstacksize pthread_attr_setprio pthread_attr_setschedparam \
pthread_attr_setstacksize pthread_condattr_create pthread_getsequence_np \
pthread_key_delete pthread_rwlock_rdlock pthread_setprio \
@@ -2111,11 +2049,9 @@ then
fi
-if test "$with_mit_threads" = "no"
-then
- # Check definition of pthread_getspecific
- AC_CACHE_CHECK("args to pthread_getspecific", mysql_cv_getspecific_args,
- AC_TRY_COMPILE(
+# Check definition of pthread_getspecific
+AC_CACHE_CHECK("args to pthread_getspecific", mysql_cv_getspecific_args,
+AC_TRY_COMPILE(
[#if !defined(SCO) && !defined(__osf__) && !defined(_REENTRANT)
#define _REENTRANT
#endif
@@ -2148,7 +2084,6 @@ mysql_cv_mutex_init_args=POSIX, mysql_cv_mutex_init_args=other))
AC_DEFINE([HAVE_NONPOSIX_PTHREAD_MUTEX_INIT], [1],
[For some non posix threads])
fi
-fi
#---END:
#---START: Used in for client configure
@@ -2311,10 +2246,20 @@ then
tools_dirs="tools"
fi
fi
+
+AC_ARG_WITH([mysqlmanager],
+ AC_HELP_STRING([--with-mysqlmanager], [Build the mysqlmanager binary: yes/no (default: build if server is built.)]),
+ [if test "x${withval}" != "xno"; then
+ tools_dirs="$tools_dirs server-tools"
+ fi],
+ [if test "x${with_server}" == "xyes"; then
+ tools_dirs="$tools_dirs server-tools"
+ fi]
+)
+
AC_SUBST(tools_dirs)
#MYSQL_CHECK_CPU
-MYSQL_CHECK_MYSQLFS
MYSQL_CHECK_VIO
MYSQL_CHECK_OPENSSL
@@ -2471,424 +2416,7 @@ AC_SUBST(readline_basedir)
AC_SUBST(readline_link)
AC_SUBST(readline_h_ln_cmd)
-
-dnl In order to add new charset, you must add charset name to
-dnl this CHARSETS_AVAILABLE list and sql/share/charsets/Index.xml.
-dnl If the character set uses strcoll or other special handling,
-dnl you must also create strings/ctype-$charset_name.c
-
-AC_DIVERT_PUSH(0)
-
-define(CHARSETS_AVAILABLE0,binary)
-define(CHARSETS_AVAILABLE1,armscii8 ascii big5 cp1250 cp1251 cp1256 cp1257)
-define(CHARSETS_AVAILABLE2,cp850 cp852 cp866 dec8 euckr gb2312 gbk geostd8)
-define(CHARSETS_AVAILABLE3,greek hebrew hp8 keybcs2 koi8r koi8u)
-define(CHARSETS_AVAILABLE4,latin1 latin2 latin5 latin7 macce macroman)
-define(CHARSETS_AVAILABLE5,sjis swe7 tis620 ucs2 ujis utf8)
-
-DEFAULT_CHARSET=latin1
-CHARSETS_AVAILABLE="CHARSETS_AVAILABLE0 CHARSETS_AVAILABLE1 CHARSETS_AVAILABLE2 CHARSETS_AVAILABLE3 CHARSETS_AVAILABLE4 CHARSETS_AVAILABLE5"
-CHARSETS_COMPLEX="big5 cp1250 euckr gb2312 gbk latin1 latin2 sjis tis620 ucs2 ujis utf8"
-
-AC_DIVERT_POP
-
-AC_ARG_WITH(charset,
- [ --with-charset=CHARSET
- Default character set, use one of:
- CHARSETS_AVAILABLE0
- CHARSETS_AVAILABLE1
- CHARSETS_AVAILABLE2
- CHARSETS_AVAILABLE3
- CHARSETS_AVAILABLE4
- CHARSETS_AVAILABLE5],
- [default_charset="$withval"],
- [default_charset="$DEFAULT_CHARSET"])
-
-AC_ARG_WITH(collation,
- [ --with-collation=COLLATION
- Default collation],
- [default_collation="$withval"],
- [default_collation="default"])
-
-
-AC_ARG_WITH(extra-charsets,
- [ --with-extra-charsets=CHARSET[,CHARSET,...]
- Use charsets in addition to default (none, complex,
- all, or a list selected from the above sets)],
- [extra_charsets="$withval"],
- [extra_charsets="none"])
-
-
-AC_MSG_CHECKING("character sets")
-
-CHARSETS="$default_charset latin1 utf8"
-
-if test "$extra_charsets" = no; then
- CHARSETS="$CHARSETS"
-elif test "$extra_charsets" = none; then
- CHARSETS="$CHARSETS"
-elif test "$extra_charsets" = complex; then
- CHARSETS="$CHARSETS $CHARSETS_COMPLEX"
- AC_DEFINE([DEFINE_ALL_CHARACTER_SETS],1,[all charsets are available])
-elif test "$extra_charsets" = all; then
- CHARSETS="$CHARSETS $CHARSETS_AVAILABLE"
- AC_DEFINE([DEFINE_ALL_CHARACTER_SETS],1,[all charsets are available])
-else
- EXTRA_CHARSETS=`echo $extra_charsets | sed -e 's/,/ /g'`
- CHARSETS="$CHARSETS $EXTRA_CHARSETS"
-fi
-
-for cs in $CHARSETS
-do
- case $cs in
- armscii8)
- AC_DEFINE(HAVE_CHARSET_armscii8, 1,
- [Define to enable charset armscii8])
- ;;
- ascii)
- AC_DEFINE(HAVE_CHARSET_ascii, 1,
- [Define to enable ascii character set])
- ;;
- big5)
- AC_DEFINE(HAVE_CHARSET_big5, 1, [Define to enable charset big5])
- AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
- AC_DEFINE(USE_MB_IDENT, [1], [ ])
- ;;
- binary)
- ;;
- cp1250)
- AC_DEFINE(HAVE_CHARSET_cp1250, 1, [Define to enable cp1250])
- ;;
- cp1251)
- AC_DEFINE(HAVE_CHARSET_cp1251, 1, [Define to enable charset cp1251])
- ;;
- cp1256)
- AC_DEFINE(HAVE_CHARSET_cp1256, 1, [Define to enable charset cp1256])
- ;;
- cp1257)
- AC_DEFINE(HAVE_CHARSET_cp1257, 1, [Define to enable charset cp1257])
- ;;
- cp850)
- AC_DEFINE(HAVE_CHARSET_cp850, 1, [Define to enable charset cp850])
- ;;
- cp852)
- AC_DEFINE(HAVE_CHARSET_cp852, 1, [Define to enable charset cp852])
- ;;
- cp866)
- AC_DEFINE(HAVE_CHARSET_cp866, 1, [Define to enable charset cp866])
- ;;
- dec8)
- AC_DEFINE(HAVE_CHARSET_dec8, 1, [Define to enable charset dec8])
- ;;
- euckr)
- AC_DEFINE(HAVE_CHARSET_euckr, 1, [Define to enable charset euckr])
- AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
- AC_DEFINE(USE_MB_IDENT, 1)
- ;;
- gb2312)
- AC_DEFINE(HAVE_CHARSET_gb2312, 1, [Define to enable charset gb2312])
- AC_DEFINE([USE_MB], 1, [Use multi-byte character routines])
- AC_DEFINE(USE_MB_IDENT, 1)
- ;;
- gbk)
- AC_DEFINE(HAVE_CHARSET_gbk, 1, [Define to enable charset gbk])
- AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
- AC_DEFINE(USE_MB_IDENT, 1)
- ;;
- geostd8)
- AC_DEFINE(HAVE_CHARSET_geostd8, 1, [Define to enable charset geostd8])
- ;;
- greek)
- AC_DEFINE(HAVE_CHARSET_greek, 1, [Define to enable charset greek])
- ;;
- hebrew)
- AC_DEFINE(HAVE_CHARSET_hebrew, 1, [Define to enable charset hebrew])
- ;;
- hp8)
- AC_DEFINE(HAVE_CHARSET_hp8, 1, [Define to enable charset hp8])
- ;;
- keybcs2)
- AC_DEFINE(HAVE_CHARSET_keybcs2, 1, [Define to enable charset keybcs2])
- ;;
- koi8r)
- AC_DEFINE(HAVE_CHARSET_koi8r, 1, [Define to enable charset koi8r])
- ;;
- koi8u)
- AC_DEFINE(HAVE_CHARSET_koi8u, 1, [Define to enable charset koi8u])
- ;;
- latin1)
- AC_DEFINE(HAVE_CHARSET_latin1, 1, [Define to enable charset latin1])
- ;;
- latin2)
- AC_DEFINE(HAVE_CHARSET_latin2, 1, [Define to enable charset latin2])
- ;;
- latin5)
- AC_DEFINE(HAVE_CHARSET_latin5, 1, [Define to enable charset latin5])
- ;;
- latin7)
- AC_DEFINE(HAVE_CHARSET_latin7, 1, [Define to enable charset latin7])
- ;;
- macce)
- AC_DEFINE(HAVE_CHARSET_macce, 1, [Define to enable charset macce])
- ;;
- macroman)
- AC_DEFINE(HAVE_CHARSET_macroman, 1,
- [Define to enable charset macroman])
- ;;
- sjis)
- AC_DEFINE(HAVE_CHARSET_sjis, 1, [Define to enable charset sjis])
- AC_DEFINE([USE_MB], 1, [Use multi-byte character routines])
- AC_DEFINE(USE_MB_IDENT, 1)
- ;;
- swe7)
- AC_DEFINE(HAVE_CHARSET_swe7, 1, [Define to enable charset swe7])
- ;;
- tis620)
- AC_DEFINE(HAVE_CHARSET_tis620, 1, [Define to enable charset tis620])
- ;;
- ucs2)
- AC_DEFINE(HAVE_CHARSET_ucs2, 1, [Define to enable charset ucs2])
- AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
- AC_DEFINE(USE_MB_IDENT, 1)
- ;;
- ujis)
- AC_DEFINE(HAVE_CHARSET_ujis, 1, [Define to enable charset ujis])
- AC_DEFINE([USE_MB], [1], [Use multi-byte character routines])
- AC_DEFINE(USE_MB_IDENT, 1)
- ;;
- utf8)
- AC_DEFINE(HAVE_CHARSET_utf8, 1, [Define to enable ut8])
- AC_DEFINE([USE_MB], 1, [Use multi-byte character routines])
- AC_DEFINE(USE_MB_IDENT, 1)
- ;;
- *)
- AC_MSG_ERROR([Charset '$cs' not available. (Available are: $CHARSETS_AVAILABLE).
- See the Installation chapter in the Reference Manual.]);
- esac
-done
-
-
- default_charset_collations=""
-
-case $default_charset in
- armscii8)
- default_charset_default_collation="armscii8_general_ci"
- default_charset_collations="armscii8_general_ci armscii8_bin"
- ;;
- ascii)
- default_charset_default_collation="ascii_general_ci"
- default_charset_collations="ascii_general_ci ascii_bin"
- ;;
- big5)
- default_charset_default_collation="big5_chinese_ci"
- default_charset_collations="big5_chinese_ci big5_bin"
- ;;
- binary)
- default_charset_default_collation="binary"
- default_charset_collations="binary"
- ;;
- cp1250)
- default_charset_default_collation="cp1250_general_ci"
- default_charset_collations="cp1250_general_ci cp1250_czech_cs cp1250_bin"
- ;;
- cp1251)
- default_charset_default_collation="cp1251_general_ci"
- default_charset_collations="cp1251_general_ci cp1251_general_cs cp1251_bin cp1251_bulgarian_ci cp1251_ukrainian_ci"
- ;;
- cp1256)
- default_charset_default_collation="cp1256_general_ci"
- default_charset_collations="cp1256_general_ci cp1256_bin"
- ;;
- cp1257)
- default_charset_default_collation="cp1257_general_ci"
- default_charset_collations="cp1257_general_ci cp1257_lithuanian_ci cp1257_bin"
- ;;
- cp850)
- default_charset_default_collation="cp850_general_ci"
- default_charset_collations="cp850_general_ci cp850_bin"
- ;;
- cp852)
- default_charset_default_collation="cp852_general_ci"
- default_charset_collations="cp852_general_ci cp852_bin"
- ;;
- cp866)
- default_charset_default_collation="cp866_general_ci"
- default_charset_collations="cp866_general_ci cp866_bin"
- ;;
- dec8)
- default_charset_default_collation="dec8_swedish_ci"
- default_charset_collations="dec8_swedish_ci dec8_bin"
- ;;
- euckr)
- default_charset_default_collation="euckr_korean_ci"
- default_charset_collations="euckr_korean_ci euckr_bin"
- ;;
- gb2312)
- default_charset_default_collation="gb2312_chinese_ci"
- default_charset_collations="gb2312_chinese_ci gb2312_bin"
- ;;
- gbk)
- default_charset_default_collation="gbk_chinese_ci"
- default_charset_collations="gbk_chinese_ci gbk_bin"
- ;;
- geostd8)
- default_charset_default_collation="geostd8_general_ci"
- default_charset_collations="geostd8_general_ci geostd8_bin"
- ;;
- greek)
- default_charset_default_collation="greek_general_ci"
- default_charset_collations="greek_general_ci greek_bin"
- ;;
- hebrew)
- default_charset_default_collation="hebrew_general_ci"
- default_charset_collations="hebrew_general_ci hebrew_bin"
- ;;
- hp8)
- default_charset_default_collation="hp8_english_ci"
- default_charset_collations="hp8_english_ci hp8_bin"
- ;;
- keybcs2)
- default_charset_default_collation="keybcs2_general_ci"
- default_charset_collations="keybcs2_general_ci keybcs2_bin"
- ;;
- koi8r)
- default_charset_default_collation="koi8r_general_ci"
- default_charset_collations="koi8r_general_ci koi8r_bin"
- ;;
- koi8u)
- default_charset_default_collation="koi8u_general_ci"
- default_charset_collations="koi8u_general_ci koi8u_bin"
- ;;
- latin1)
- default_charset_default_collation="latin1_swedish_ci"
- default_charset_collations="latin1_general_ci latin1_general_cs latin1_bin latin1_german1_ci latin1_german2_ci latin1_danish_ci latin1_spanish_ci latin1_swedish_ci"
- ;;
- latin2)
- default_charset_default_collation="latin2_general_ci"
- default_charset_collations="latin2_general_ci latin2_bin latin2_czech_cs latin2_hungarian_ci latin2_croatian_ci"
- ;;
- latin5)
- default_charset_default_collation="latin5_turkish_ci"
- default_charset_collations="latin5_turkish_ci latin5_bin"
- ;;
- latin7)
- default_charset_default_collation="latin7_general_ci"
- default_charset_collations="latin7_general_ci latin7_general_cs latin7_bin latin7_estonian_cs"
- ;;
- macce)
- default_charset_default_collation="macce_general_ci"
- default_charset_collations="macce_general_ci macce_bin"
- ;;
- macroman)
- default_charset_default_collation="macroman_general_ci"
- default_charset_collations="macroman_general_ci macroman_bin"
- ;;
- sjis)
- default_charset_default_collation="sjis_japanese_ci"
- default_charset_collations="sjis_japanese_ci sjis_bin"
- ;;
- swe7)
- default_charset_default_collation="swe7_swedish_ci"
- default_charset_collations="swe7_swedish_ci swe7_bin"
- ;;
- tis620)
- default_charset_default_collation="tis620_thai_ci"
- default_charset_collations="tis620_thai_ci tis620_bin"
- ;;
- ucs2)
- default_charset_default_collation="ucs2_general_ci"
- define(UCSC1, ucs2_general_ci ucs2_bin)
- define(UCSC2, ucs2_czech_ci ucs2_danish_ci)
- define(UCSC3, ucs2_estonian_ci ucs2_icelandic_ci)
- define(UCSC4, ucs2_latvian_ci ucs2_lithuanian_ci)
- define(UCSC5, ucs2_persian_ci ucs2_polish_ci ucs2_romanian_ci)
- define(UCSC6, ucs2_slovak_ci ucs2_slovenian_ci)
- define(UCSC7, ucs2_spanish2_ci ucs2_spanish_ci)
- define(UCSC8, ucs2_swedish_ci ucs2_turkish_ci)
- define(UCSC9, ucs2_unicode_ci)
- UCSC="UCSC1 UCSC2 UCSC3 UCSC4 UCSC5 UCSC6 UCSC7 UCSC8 UCSC9"
- default_charset_collations="$UCSC"
- ;;
- ujis)
- default_charset_default_collation="ujis_japanese_ci"
- default_charset_collations="ujis_japanese_ci ujis_bin"
- ;;
- utf8)
- default_charset_default_collation="utf8_general_ci"
- if test "$default_collation" = "utf8_general_cs"; then
- # For those who explicitly desire "utf8_general_cs", support it,
- # and then also set the CPP switch enabling that code.
- UTFC="utf8_general_cs"
- AC_DEFINE([HAVE_UTF8_GENERAL_CS], [1], [certain Japanese customer])
- else
- define(UTFC1, utf8_general_ci utf8_bin)
- define(UTFC2, utf8_czech_ci utf8_danish_ci)
- define(UTFC3, utf8_estonian_ci utf8_icelandic_ci)
- define(UTFC4, utf8_latvian_ci utf8_lithuanian_ci)
- define(UTFC5, utf8_persian_ci utf8_polish_ci utf8_romanian_ci)
- define(UTFC6, utf8_slovak_ci utf8_slovenian_ci)
- define(UTFC7, utf8_spanish2_ci utf8_spanish_ci)
- define(UTFC8, utf8_swedish_ci utf8_turkish_ci)
- define(UTFC9, utf8_unicode_ci)
- UTFC="UTFC1 UTFC2 UTFC3 UTFC4 UTFC5 UTFC6 UTFC7 UTFC8 UTFC9"
- fi
- default_charset_collations="$UTFC"
- ;;
- *)
- AC_MSG_ERROR([Charset $cs not available. (Available are: $CHARSETS_AVAILABLE).
- See the Installation chapter in the Reference Manual.]);
-esac
-
-if test "$default_collation" = default; then
- default_collation=$default_charset_default_collation
-fi
-
-valid_default_collation=no
-for cl in $default_charset_collations
-do
- if test x"$cl" = x"$default_collation"
- then
- valid_default_collation=yes
- break
- fi
-done
-
-if test x$valid_default_collation = xyes
-then
- AC_MSG_RESULT([default: $default_charset, collation: $default_collation; compiled in: $CHARSETS])
-else
- AC_MSG_ERROR([
- Collation $default_collation is not valid for character set $default_charset.
- Valid collations are: $default_charset_collations.
- See the Installation chapter in the Reference Manual.
- ]);
-fi
-
-AC_DEFINE_UNQUOTED([MYSQL_DEFAULT_CHARSET_NAME], ["$default_charset"],
- [Define the default charset name])
-AC_DEFINE_UNQUOTED([MYSQL_DEFAULT_COLLATION_NAME], ["$default_collation"],
- [Define the default charset name])
-
-
-# Shall we build the UCA-based Unicode collations
-AC_ARG_WITH(uca,
- [ --without-uca Skip building of the national Unicode collations.],
- [with_uca=$withval],
- [with_uca=yes]
-)
-
-AC_MSG_CHECKING([whether to compile national Unicode collations])
-
-if test "$with_uca" = "yes"
-then
- AC_MSG_RESULT(yes)
- AC_DEFINE([HAVE_UCA_COLLATIONS], [1], [national Unicode collations])
-else
- AC_MSG_RESULT(no)
-fi
-
MYSQL_CHECK_BIG_TABLES
-MYSQL_CHECK_ISAM
MYSQL_CHECK_BDB
MYSQL_CHECK_INNODB
MYSQL_CHECK_EXAMPLEDB
@@ -2896,6 +2424,7 @@ MYSQL_CHECK_ARCHIVEDB
MYSQL_CHECK_CSVDB
MYSQL_CHECK_BLACKHOLEDB
MYSQL_CHECK_NDBCLUSTER
+MYSQL_CHECK_FEDERATED
# If we have threads generate some library functions and test programs
sql_server_dirs=
@@ -2942,24 +2471,16 @@ then
AC_DEFINE([THREAD], [1],
[Define if you want to have threaded code. This may be undef on client code])
# Avoid _PROGRAMS names
- THREAD_LPROGRAMS="test_thr_alarm\$(EXEEXT) test_thr_lock\$(EXEEXT)"
- AC_SUBST(THREAD_LPROGRAMS)
THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o"
AC_SUBST(THREAD_LOBJECTS)
server_scripts="mysqld_safe mysql_install_db"
- sql_server_dirs="strings dbug mysys extra regex"
+ sql_server_dirs="strings mysys dbug extra regex"
#
# Configuration for optional table handlers
#
- if test X"$have_isam" != Xno
- then
- sql_server_dirs="$sql_server_dirs isam merge"
- AC_CONFIG_FILES(isam/Makefile merge/Makefile)
- fi
-
if test X"$have_berkeley_db" != Xno; then
if test X"$have_berkeley_db" != Xyes; then
# we must build berkeley db from source
@@ -3062,28 +2583,6 @@ esac
#
sql_server_dirs="$sql_server_dirs myisam myisammrg heap vio sql"
- if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes"
- then
- # MIT user level threads
- thread_dirs="mit-pthreads"
- AC_DEFINE([HAVE_mit_thread], [1], [Do we use user level threads])
- MT_INCLUDES="-I\$(top_srcdir)/mit-pthreads/include"
- AC_SUBST(MT_INCLUDES)
- if test -n "$OVERRIDE_MT_LD_ADD"
- then
- MT_LD_ADD="$OVERRIDE_MT_LD_ADD"
- else
- MT_LD_ADD="-L \$(top_srcdir)/mit-pthreads/obj/ -lpthread"
- fi
- AC_SUBST(MT_LD_ADD)
- echo ""
- echo "Configuring MIT Pthreads"
- # We will never install so installation paths are not needed.
- (cd mit-pthreads && sh ./configure) || exit 1
- echo "End of MIT Pthreads configuration"
- echo ""
- LIBS="$MT_LD_ADD $LIBS"
- fi
fi
# IMPORTANT - do not modify LIBS past this line - this hack is the only way
@@ -3111,12 +2610,6 @@ do
done
AC_SUBST(sql_union_dirs)
-#if test "$with_posix_threads" = "no" -o "$with_mit_threads" = "yes"
-#then
- # MIT pthreads does now support connecting with unix sockets
- # AC_DEFINE([HAVE_THREADS_WITHOUT_SOCKETS], [], [MIT pthreads does not support connecting with unix sockets])
-#fi
-
# Some usefull subst
AC_SUBST(CC)
AC_SUBST(GXX)
@@ -3131,6 +2624,7 @@ case $SYSTEM_TYPE in
;;
esac
+
if test X"$have_ndbcluster" = Xyes
then
MAKE_BINARY_DISTRIBUTION_OPTIONS="$MAKE_BINARY_DISTRIBUTION_OPTIONS --with-ndbcluster"
@@ -3168,12 +2662,6 @@ then
fi
AC_SUBST([ndb_port])
-if test X"$ndb_port_base" = Xdefault
-then
- ndb_port_base="2202"
-fi
-AC_SUBST([ndb_port_base])
-
ndb_transporter_opt_objs=""
if test "$ac_cv_func_shmget" = "yes" &&
test "$ac_cv_func_shmat" = "yes" &&
@@ -3212,11 +2700,26 @@ then
fi
AC_SUBST([ndb_bin_am_ldflags])
AC_SUBST([ndb_opt_subdirs])
+
+NDB_SIZEOF_CHARP="$ac_cv_sizeof_charp"
+NDB_SIZEOF_CHAR="$ac_cv_sizeof_char"
+NDB_SIZEOF_SHORT="$ac_cv_sizeof_short"
+NDB_SIZEOF_INT="$ac_cv_sizeof_int"
+NDB_SIZEOF_LONG="$ac_cv_sizeof_long"
+NDB_SIZEOF_LONG_LONG="$ac_cv_sizeof_long_long"
+AC_SUBST([NDB_SIZEOF_CHARP])
+AC_SUBST([NDB_SIZEOF_CHAR])
+AC_SUBST([NDB_SIZEOF_SHORT])
+AC_SUBST([NDB_SIZEOF_INT])
+AC_SUBST([NDB_SIZEOF_LONG])
+AC_SUBST([NDB_SIZEOF_LONG_LONG])
+
AC_CONFIG_FILES(ndb/Makefile ndb/include/Makefile dnl
ndb/src/Makefile ndb/src/common/Makefile dnl
ndb/docs/Makefile dnl
ndb/tools/Makefile dnl
- ndb/src/common/debugger/Makefile ndb/src/common/debugger/signaldata/Makefile dnl
+ ndb/src/common/debugger/Makefile dnl
+ ndb/src/common/debugger/signaldata/Makefile dnl
ndb/src/common/portlib/Makefile dnl
ndb/src/common/util/Makefile dnl
ndb/src/common/logger/Makefile dnl
@@ -3255,6 +2758,7 @@ AC_CONFIG_FILES(ndb/Makefile ndb/include/Makefile dnl
ndb/test/tools/Makefile dnl
ndb/test/run-test/Makefile mysql-test/ndb/Makefile dnl
ndb/include/ndb_version.h ndb/include/ndb_global.h dnl
+ ndb/include/ndb_types.h dnl
)
fi
@@ -3272,6 +2776,7 @@ AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl
sql-common/Makefile SSL/Makefile dnl
dbug/Makefile scripts/Makefile dnl
include/Makefile sql-bench/Makefile tools/Makefile dnl
+ server-tools/Makefile server-tools/instance-manager/Makefile dnl
tests/Makefile Docs/Makefile support-files/Makefile dnl
support-files/MacOSX/Makefile mysql-test/Makefile dnl
netware/Makefile dnl
diff --git a/dbug/Makefile.am b/dbug/Makefile.am
index bd512ee1d1d..0810b13cceb 100644
--- a/dbug/Makefile.am
+++ b/dbug/Makefile.am
@@ -15,43 +15,50 @@
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA
-INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include
-LDADD = libdbug.a ../strings/libmystrings.a
-pkglib_LIBRARIES = libdbug.a
-noinst_HEADERS = dbug_long.h
-libdbug_a_SOURCES = dbug.c sanity.c
-EXTRA_DIST = example1.c example2.c example3.c \
- user.r monty.doc readme.prof \
- main.c factorial.c dbug_analyze.c
+INCLUDES = -I$(top_srcdir)/include
+LDADD = libdbug.a ../mysys/libmysys.a ../strings/libmystrings.a
+pkglib_LIBRARIES = libdbug.a
+noinst_HEADERS = dbug_long.h
+libdbug_a_SOURCES = dbug.c sanity.c
+EXTRA_DIST = example1.c example2.c example3.c \
+ user.r monty.doc readme.prof dbug_add_tags.pl \
+ my_main.c main.c factorial.c dbug_analyze.c
+NROFF_INC = example1.r example2.r example3.r main.r \
+ factorial.r output1.r output2.r output3.r \
+ output4.r output5.r
+CLEANFILES = $(NROFF_INC) user.t user.ps
+
# Must be linked with libs that are not compiled yet
-extra_progs: factorial dbug_analyze
+noinst_PROGRAMS = factorial dbug_analyze
+factorial_SOURCES = my_main.c factorial.c
+dbug_analyze_SOURCES = dbug_analyze.c
-factorial: main.o factorial.o
- @rm -f factorial
- $(LINK) main.o factorial.o -lmysys
+all: user.t user.ps
-dbug_analyze: dbug_analyze.o
- @rm -f dbug_analyze
- $(LINK) dbug_analyze.o -lmysys
+user.t: user.r $(NROFF_INC)
+ -nroff -mm user.r > $@
-user.t: user.r $(NROFF_INC)
- nroff -cm user.r > $@
+user.ps: user.r $(NROFF_INC)
+ -groff -mm user.r > $@
-output1.r: $(PROGRAM)
- factorial 1 2 3 4 5 | cat > $@
+output1.r: factorial
+ ./factorial 1 2 3 4 5 | cat > $@
-output2.r: $(PROGRAM)
- factorial -\#t:o 2 3 | cat >$@
+output2.r: factorial
+ ./factorial -\#t:o 2 3 | cat >$@
-output3.r: $(PROGRAM)
- factorial -\#d:t:o 3 | cat >$@
+output3.r: factorial
+ ./factorial -\#d:t:o 3 | cat >$@
-output4.r: $(PROGRAM)
- factorial -\#d,result:o 4 | cat >$@
+output4.r: factorial
+ ./factorial -\#d,result:o 4 | cat >$@
-output5.r: $(PROGRAM)
- factorial -\#d:f,factorial:F:L:o 3 | cat >$@
+output5.r: factorial
+ ./factorial -\#d:f,factorial:F:L:o 3 | cat >$@
+.c.r:
+ @RM@ -f $@
+ @SED@ -e 's!\\!\\\\!g' $< > $@
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/dbug/dbug.c b/dbug/dbug.c
index 02175f8b091..91b7e7b6c4c 100644
--- a/dbug/dbug.c
+++ b/dbug/dbug.c
@@ -21,8 +21,7 @@
* all copies and derivative works. Thank you. *
* *
* The author makes no warranty of any kind with respect to this *
- * product and explicitly disclaims any implied warranties of mer- *ct_lex.table_list.first=0;
- thd->lex.selec
+ * product and explicitly disclaims any implied warranties of mer- *
* chantability or fitness for any particular purpose. *
* *
******************************************************************************
@@ -60,8 +59,8 @@
*
* Michael Widenius:
* DBUG_DUMP - To dump a block of memory.
- * PUSH_FLAG "O" - To be used insted of "o" if we don't
- * want flushing (for slow systems)
+ * PUSH_FLAG "O" - To be used insted of "o" if we
+ * want flushing after each write
* PUSH_FLAG "A" - as 'O', but we will append to the out file instead
* of creating a new one.
* Check of malloc on entry/exit (option "S")
@@ -938,7 +937,7 @@ void _db_doprnt_ (const char *format,...)
/*
* FUNCTION
*
- * _db_dump_ dump a string until '\0' is found
+ * _db_dump_ dump a string in hex
*
* SYNOPSIS
*
@@ -979,7 +978,7 @@ uint length)
{
fprintf(_db_fp_, "%s: ", state->func);
}
- sprintf(dbuff,"%s: Memory: %lx Bytes: (%d)\n",
+ sprintf(dbuff,"%s: Memory: 0x%lx Bytes: (%d)\n",
keyword,(ulong) memory, length);
(void) fputs(dbuff,_db_fp_);
@@ -1230,6 +1229,33 @@ static BOOLEAN DoProfile ()
}
#endif
+/*
+ * FUNCTION
+ *
+ * _db_strict_keyword_ test keyword for member of keyword list
+ *
+ * SYNOPSIS
+ *
+ * BOOLEAN _db_strict_keyword_ (keyword)
+ * char *keyword;
+ *
+ * DESCRIPTION
+ *
+ * Similar to _db_keyword_, but keyword is NOT accepted if keyword list
+ * is empty. Used in DBUG_EXECUTE_IF() - for actions that must not be
+ * executed by default.
+ *
+ * Returns TRUE if keyword accepted, FALSE otherwise.
+ *
+ */
+
+BOOLEAN _db_strict_keyword_ (
+const char *keyword)
+{
+ if (stack -> keywords == NULL)
+ return FALSE;
+ return _db_keyword_ (keyword);
+}
/*
* FUNCTION
diff --git a/dbug/dbug_analyze.c b/dbug/dbug_analyze.c
index de228c64aa5..1db056d549c 100644
--- a/dbug/dbug_analyze.c
+++ b/dbug/dbug_analyze.c
@@ -51,6 +51,7 @@
#include <my_global.h>
#include <m_string.h>
+#include <my_pthread.h>
static char *my_name;
static int verbose;
@@ -246,7 +247,7 @@ char *m_name;
modules[n_items].m_stkuse = 0;
DBUG_RETURN (n_items++);
}
- while (cmp = strcmp (m_name,modules[ind].name)) {
+ while ((cmp = strcmp (m_name,modules[ind].name))) {
if (cmp < 0) { /* In left subtree */
if (s_table[ind].lchild == MAXPROCS) {
/* Add as left child */
@@ -392,7 +393,7 @@ FILE *inf;
}
break;
default:
- fprintf (stderr, "unknown record type '%s'\n", buf[0]);
+ fprintf (stderr, "unknown record type '%c'\n", buf[0]);
break;
}
next_line:;
@@ -450,10 +451,11 @@ FILE *outf;
unsigned long int sum_calls, sum_time;
{
DBUG_ENTER ("out_trailer");
- if (verbose) {
- fprintf (outf, "======\t==========\t===========\t==========\t========\n");
- fprintf (outf, "%6d\t%10.2f\t%11d\t%10.2f\t\t%-15s\n",
- sum_calls, 100.0, sum_time, 100.0, "Totals");
+ if (verbose)
+ {
+ fprintf(outf, "======\t==========\t===========\t==========\t========\n");
+ fprintf(outf, "%6ld\t%10.2f\t%11ld\t%10.2f\t\t%-15s\n",
+ sum_calls, 100.0, sum_time, 100.0, "Totals");
}
DBUG_VOID_RETURN;
}
@@ -488,16 +490,16 @@ unsigned long int *called, *timed;
import = (unsigned int) (per_time * per_calls);
if (verbose) {
- fprintf (outf, "%6d\t%10.2f\t%11d\t%10.2f %10d\t%-15s\n",
+ fprintf (outf, "%6d\t%10.2f\t%11ld\t%10.2f %10d\t%-15s\n",
calls, per_calls, time, per_time, import, name);
} else {
ms_per_call = time;
ms_per_call /= calls;
ftime = time;
ftime /= 1000;
- fprintf (outf, "%8.2f%8.3f%8u%8.3f%8.2f%8u%8u %-s\n",
- per_time, ftime, calls, ms_per_call, per_calls, import,
- stkuse, name);
+ fprintf(outf, "%8.2f%8.3f%8u%8.3f%8.2f%8u%8lu %-s\n",
+ per_time, ftime, calls, ms_per_call, per_calls, import,
+ stkuse, name);
}
*called = calls;
*timed = time;
@@ -572,6 +574,11 @@ int main (int argc, char **argv)
FILE *infile;
FILE *outfile = {stdout};
+#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
+ pthread_init(); /* Must be called before DBUG_ENTER */
+#endif
+ my_thread_global_init();
+ {
DBUG_ENTER ("main");
DBUG_PROCESS (argv[0]);
my_name = argv[0];
@@ -601,6 +608,7 @@ int main (int argc, char **argv)
output (outfile);
DBUG_RETURN (EX_OK);
}
+}
#ifdef MSDOS
diff --git a/dbug/dbug_long.h b/dbug/dbug_long.h
index 07266b51553..829df181ef1 100644
--- a/dbug/dbug_long.h
+++ b/dbug/dbug_long.h
@@ -1,3 +1,4 @@
+#error This file is not used in MySQL - see ../include/my_dbug.h instead
/******************************************************************************
* *
* N O T I C E *
diff --git a/dbug/example1.c b/dbug/example1.c
index e468f065796..7b3c3fcd63d 100644
--- a/dbug/example1.c
+++ b/dbug/example1.c
@@ -1,6 +1,3 @@
-
-#include <my_global.h>
-
main (argc, argv)
int argc;
char *argv[];
diff --git a/dbug/example2.c b/dbug/example2.c
index 5e5f14f0e7e..75fc1321b13 100644
--- a/dbug/example2.c
+++ b/dbug/example2.c
@@ -1,6 +1,3 @@
-
-#include <my_global.h>
-
int debug = 0;
main (argc, argv)
diff --git a/dbug/example3.c b/dbug/example3.c
index f177c07425d..c035cdfffa0 100644
--- a/dbug/example3.c
+++ b/dbug/example3.c
@@ -1,6 +1,3 @@
-
-#include <my_global.h>
-
main (argc, argv)
int argc;
char *argv[];
diff --git a/dbug/main.c b/dbug/main.c
index da56c00feb3..00e80c8ba31 100644
--- a/dbug/main.c
+++ b/dbug/main.c
@@ -1,33 +1,24 @@
-#ifdef DBUG_OFF /* We are testing dbug */
-#undef DBUG_OFF
-#endif
-
-#include <my_global.h> /* This includes dbug.h */
+#include <dbug.h>
int main (argc, argv)
int argc;
char *argv[];
{
- register int result, ix;
+ int result, ix;
extern int factorial(int);
-#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
- pthread_init(); /* Must be called before DBUG_ENTER */
-#endif
- {
- DBUG_ENTER ("main");
- DBUG_PROCESS (argv[0]);
- for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
- switch (argv[ix][1]) {
- case '#':
- DBUG_PUSH (&(argv[ix][2]));
- break;
- }
- }
- for (; ix < argc; ix++) {
- DBUG_PRINT ("args", ("argv[%d] = %s", ix, argv[ix]));
- result = factorial (atoi(argv[ix]));
- printf ("%d\n", result);
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+ for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
+ switch (argv[ix][1]) {
+ case '#':
+ DBUG_PUSH (&(argv[ix][2]));
+ break;
}
- DBUG_RETURN (0);
}
+ for (; ix < argc; ix++) {
+ DBUG_PRINT ("args", ("argv[%d] = %s", ix, argv[ix]));
+ result = factorial (atoi(argv[ix]));
+ printf ("%d\n", result);
+ }
+ DBUG_RETURN (0);
}
diff --git a/dbug/monty.doc b/dbug/monty.doc
index 1c102e1c31e..bd4096951d2 100644
--- a/dbug/monty.doc
+++ b/dbug/monty.doc
@@ -15,6 +15,6 @@ All changes that I or other people at MySQL AB have done to all files
in the dbug library (Mainly in dbug.c, dbug_analyze.c, dbug_long.h,
dbug.h) are put in public domain, as the rest of the dbug.c library)
-To my knowledge, all code in dbug library are in public domain.
+To my knowledge, all code in dbug library is in public domain.
Michael Widenius
diff --git a/dbug/my_main.c b/dbug/my_main.c
new file mode 100644
index 00000000000..90af23b42b9
--- /dev/null
+++ b/dbug/my_main.c
@@ -0,0 +1,39 @@
+/*
+ this is modified version of the original example main.c
+ fixed so that it could compile and run in MySQL source tree
+*/
+
+#ifdef DBUG_OFF /* We are testing dbug */
+#undef DBUG_OFF
+#endif
+
+#include <my_global.h> /* This includes dbug.h */
+
+int main (argc, argv)
+int argc;
+char *argv[];
+{
+ register int result, ix;
+ extern int factorial(int);
+#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
+ pthread_init(); /* Must be called before DBUG_ENTER */
+#endif
+ my_thread_global_init();
+ {
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+ for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
+ switch (argv[ix][1]) {
+ case '#':
+ DBUG_PUSH (&(argv[ix][2]));
+ break;
+ }
+ }
+ for (; ix < argc; ix++) {
+ DBUG_PRINT ("args", ("argv[%d] = %s", ix, argv[ix]));
+ result = factorial (atoi(argv[ix]));
+ printf ("%d\n", result);
+ }
+ DBUG_RETURN (0);
+ }
+}
diff --git a/dbug/user.r b/dbug/user.r
index e8321243962..198f88cf272 100644
--- a/dbug/user.r
+++ b/dbug/user.r
@@ -1,8 +1,13 @@
.\" @(#)user.r 1.13 10/29/86
.\"
+.\" 2004-10-29: documented features implemented since 10/29/86
+.\" formatting cleanup
+.\" - Sergei Golubchik
+.\"
.\" DBUG (Macro Debugger Package) nroff source
.\"
.\" nroff -mm user.r >user.t
+.\" groff -mm user.r >user.ps
.\"
.\" ===================================================
.\"
@@ -196,7 +201,9 @@ Figure 1 is an example of this type of primitive debugging
technique.
.DS I N
.SP 2
+\fC
.so example1.r
+\fR
.SP 2
.ll -5
.ce
@@ -222,7 +229,9 @@ C preprocessor.
Figure 2 is an example of all three techniques.
.DS I N
.SP 2
+\fC
.so example2.r
+\fR
.SP 2
.ll -5
.ce
@@ -255,7 +264,9 @@ like an arbitrary and unreasonable restriction.
Figure 3 is an example of this usage.
.DS I N
.SP 2
+\fC
.so example3.r
+\fR
.SP 2
.ll -5
.ce
@@ -281,7 +292,9 @@ program is implemented recursively.
Figure 4 is the main function for this factorial program.
.DS I N
.SP 2
+\fC
.so main.r
+\fR
.SP 2
.ll -5
.ce
@@ -346,7 +359,7 @@ All of these macros will be fully explained in subsequent sections.
To use the debugger, the factorial program is invoked with a command
line of the form:
.DS CB N
-factorial -#d:t 1 2 3
+\fCfactorial -#d:t 1 2 3
.DE
The
.B main
@@ -364,7 +377,7 @@ The factorial function is then called three times, with the arguments
Note that the DBUG_PRINT takes exactly
.B two
arguments, with the second argument (a format string and list
-of printable values) enclosed in parenthesis.
+of printable values) enclosed in parentheses.
.P
Debug control strings consist of a header, the "-#", followed
by a colon separated list of debugger arguments.
@@ -373,6 +386,7 @@ by an optional comma separated list of arguments specific
to the given flag.
Some examples are:
.DS CB N
+\fC
-#d:t:o
-#d,in,out:f,main:F:L
.DE
@@ -391,7 +405,9 @@ Note that this is not necessarily the best way to do factorials
and error conditions are ignored completely.
.DS I N
.SP 2
+\fC
.so factorial.r
+\fR
.SP 2
.ll -5
.ce
@@ -421,7 +437,7 @@ To build the factorial program on a
system, compile and
link with the command:
.DS CB N
-cc -o factorial main.c factorial.c -ldbug
+\fCcc -o factorial main.c factorial.c -ldbug
.DE
The "-ldbug" argument tells the loader to link in the
runtime support modules for the
@@ -429,18 +445,20 @@ runtime support modules for the
package.
Executing the factorial program with a command of the form:
.DS CB N
-factorial 1 2 3 4 5
+\fCfactorial 1 2 3 4 5
.DE
generates the output shown in figure 6.
.DS I N
.SP 2
+\fC
.so output1.r
+\fR
.SP 2
.ll -5
.ce
Figure 6
.ce
-factorial 1 2 3 4 5
+\fCfactorial 1 2 3 4 5
.ll +5
.SP 2
.DE
@@ -449,16 +467,18 @@ factorial 1 2 3 4 5
Function level tracing is enabled by passing the debugger
the 't' flag in the debug control string.
Figure 7 is the output resulting from the command
-"factorial\ -#t:o\ 3\ 2".
+"factorial\ -#t:o\ 2\ 3".
.DS I N
.SP 2
+\fC
.so output2.r
+\fR
.SP 2
.ll -5
.ce
Figure 7
.ce
-factorial -#t:o 3 2
+\fCfactorial -#t:o 2 3
.ll +5
.SP 2
.DE
@@ -510,7 +530,7 @@ output instead, via the 'o' flag character.
Note that no 'o' implies the default (standard error), a 'o'
with no arguments means standard output, and a 'o'
with an argument means used the named file.
-I.E, "factorial\ -#t:o,logfile\ 3\ 2" would write the trace
+i.e, "factorial\ -#t:o,logfile\ 3\ 2" would write the trace
output in "logfile".
Because of
.B UNIX
@@ -555,7 +575,7 @@ The second argument to a
.B DBUG_PRINT
macro is a standard printf style
format string and one or more arguments to print, all
-enclosed in parenthesis so that they collectively become a single macro
+enclosed in parentheses so that they collectively become a single macro
argument.
This is how variable numbers of printf arguments are supported.
Also note that no explicit newline is required at the end of the format string.
@@ -566,13 +586,15 @@ to a single macro with a huge format string.
Figure 8 shows the output for default tracing and debug.
.DS I N
.SP 2
+\fC
.so output3.r
+\fR
.SP 2
.ll -5
.ce
Figure 8
.ce
-factorial -#d:t:o 3
+\fCfactorial -#d:t:o 3
.ll +5
.SP 2
.DE
@@ -591,13 +613,15 @@ To demonstrate selection of specific macros for output, figure
the debug control string "-#d,result:o".
.DS I N
.SP 2
+\fC
.so output4.r
+\fR
.SP 2
.ll -5
.ce
Figure 9
.ce
-factorial -#d,result:o 4
+\fCfactorial -#d,result:o 4
.ll +5
.SP 2
.DE
@@ -613,13 +637,15 @@ The 'F' flag enables printing of the source file name and the 'L'
flag enables printing of the source file line number.
.DS I N
.SP 2
+\fC
.so output5.r
+\fR
.SP 2
.ll -5
.ce
Figure 10
.ce
-factorial -#d:f,factorial:F:L:o 3
+\fCfactorial -#d:f,factorial:F:L:o 3
.ll +5
.SP 2
.DE
@@ -671,7 +697,7 @@ will cause warning messages from the
.I dbug
package runtime support module.
.SP 1
-EX:\ DBUG_ENTER\ ("main");
+EX:\ \fCDBUG_ENTER\ ("main");\fR
.SP 1
.LI DBUG_RETURN\
Used at each exit point of a function containing a
@@ -693,16 +719,16 @@ DBUG_ENTER
macro, and the compiler will complain
if the macros are actually used (expanded).
.SP 1
-EX:\ DBUG_RETURN\ (value);
+EX:\ \fCDBUG_RETURN\ (value);\fR
.br
-EX:\ DBUG_VOID_RETURN;
+EX:\ \fCDBUG_VOID_RETURN;\fR
.SP 1
.LI DBUG_PROCESS\
Used to name the current process being executed.
A typical argument for this macro is "argv[0]", though
it will be perfectly happy with any other string.
.SP 1
-EX:\ DBUG_PROCESS\ (argv[0]);
+EX:\ \fCDBUG_PROCESS\ (argv[0]);\fR
.SP 1
.LI DBUG_PUSH\
Sets a new debugger state by pushing the current
@@ -720,11 +746,11 @@ The proper usage is to pass a pointer to the first character
.B after
the "-#" string.
.SP 1
-EX:\ DBUG_PUSH\ (\&(argv[i][2]));
+EX:\ \fCDBUG_PUSH\ (\&(argv[i][2]));\fR
.br
-EX:\ DBUG_PUSH\ ("d:t");
+EX:\ \fCDBUG_PUSH\ ("d:t");\fR
.br
-EX:\ DBUG_PUSH\ ("");
+EX:\ \fCDBUG_PUSH\ ("");\fR
.SP 1
.LI DBUG_POP\
Restores the previous debugger state by popping the state stack.
@@ -734,7 +760,7 @@ The
DBUG_POP
macro has no arguments.
.SP 1
-EX:\ DBUG_POP\ ();
+EX:\ \fCDBUG_POP\ ();\fR
.SP 1
.LI DBUG_FILE\
The
@@ -744,7 +770,7 @@ stream.
It is used in the same manner as the symbols "stdout" and "stderr"
in the standard I/O package.
.SP 1
-EX:\ fprintf\ (DBUG_FILE,\ "Doing my own I/O!\n");
+EX:\ \fCfprintf\ (DBUG_FILE,\ "Doing\ my\ own\ I/O!\\n");\fR
.SP 1
.LI DBUG_EXECUTE\
The DBUG_EXECUTE macro is used to execute any arbitrary C code.
@@ -754,9 +780,19 @@ This macro must be used cautiously because, like the
DBUG_PRINT
macro,
it is automatically selected by default whenever the 'd' flag has
-no argument list (I.E., a "-#d:t" control string).
+no argument list (i.e., a "-#d:t" control string).
+.SP 1
+EX:\ \fCDBUG_EXECUTE\ ("status",\ print_status\ ());\fR
+.SP 1
+.LI DBUG_EXECUTE_IF\
+Works like DBUG_EXECUTE macro, but the code is
+.B not
+executed "by default", if the keyword is not explicitly listed in
+the 'd' flag. Used to conditionally execute "dangerous" actions, e.g
+to crash the program testing how recovery works, or to introduce an
+artificial delay checking for race conditions.
.SP 1
-EX:\ DBUG_EXECUTE\ ("abort",\ abort\ ());
+EX:\ \fCDBUG_EXECUTE_IF\ ("crashme",\ abort\ ());\fR
.SP 1
.LI DBUG_N\
These macros, where N is in the range 2-5, are currently obsolete
@@ -771,22 +807,32 @@ and the corresponding argument list.
Note that the format string and argument list are all one macro argument
and
.B must
-be enclosed in parenthesis.
+be enclosed in parentheses.
.SP 1
-EX:\ DBUG_PRINT\ ("eof",\ ("end\ of\ file\ found"));
+EX:\ \fCDBUG_PRINT\ ("eof",\ ("end\ of\ file\ found"));\fR
.br
-EX:\ DBUG_PRINT\ ("type",\ ("type\ is\ %x", type));
+EX:\ \fCDBUG_PRINT\ ("type",\ ("type\ is\ %x", type));\fR
.br
-EX:\ DBUG_PRINT\ ("stp",\ ("%x\ ->\ %s", stp, stp\ ->\ name));
+EX:\ \fCDBUG_PRINT\ ("stp",\ ("%x\ ->\ %s", stp, stp\ ->\ name));\fR
+.SP 1
+.LI DBUG_DUMP\
+Used to dump a memory block in hex via the "fprintf" library function on the
+current debug stream, DBUG_FILE.
+The first argument is a debug keyword, the second is a pointer to
+a memory to dump, the third is a number of bytes to dump.
+.SP 1
+EX: \fCDBUG_DBUG\ ("net",\ packet,\ len);\fR
+.SP 1
.LI DBUG_SETJMP\
Used in place of the setjmp() function to first save the current
debugger state and then execute the standard setjmp call.
-This allows to the debugger to restore it's state when the
+This allows to the debugger to restore its state when the
DBUG_LONGJMP macro is used to invoke the standard longjmp() call.
Currently all instances of DBUG_SETJMP must occur within the
same function and at the same function nesting level.
.SP 1
-EX:\ DBUG_SETJMP\ (env);
+EX: \fCDBUG_SETJMP\ (env);\fR
+.SP 1
.LI DBUG_LONGJMP\
Used in place of the longjmp() function to first restore the
previous debugger state at the time of the last DBUG_SETJMP
@@ -797,7 +843,45 @@ It would be possible to maintain separate DBUG_SETJMP and DBUG_LONGJMP
pairs by having the debugger runtime support module use the first
argument to differentiate the pairs.
.SP 1
-EX:\ DBUG_LONGJMP\ (env,val);
+EX: \fCDBUG_LONGJMP\ (env,val);\fR
+.SP 1
+.LI DBUG_LOCK_FILE\
+Used in multi-threaded environment to lock DBUG_FILE stream.
+It can be used, for example, in functions that need to write something to a
+debug stream more than in one fprintf() call and want to ensure that no other
+thread will write something in between.
+.SP 1
+EX:\fC
+.br
+ DBUG_LOCK_FILE;
+.br
+ fprintf (DBUG_FILE, "a=[");
+.br
+ for (int i=0; i < a_length; i++)
+.br
+ fprintf (DBUG_FILE, "0x%03x ", a[i]);
+.br
+ fprintf (DBUG_FILE, "]");
+.br
+ DBUG_UNLOCK_FILE;\fR
+.SP 1
+.LI DBUG_UNLOCK_FILE\
+Unlocks DBUG_FILE stream, that was locked with a DBUG_LOCK_FILE.
+.LI DBUG_ASSERT\
+This macro just does a regular assert(). The difference is that it will be
+disabled by DBUG_OFF togeher with the
+.I dbug
+library. So there will be no need to disable asserts separately with NDEBUG.
+.SP 1
+EX:\ \fCDBUG_ASSERT(\ a\ >\ 0\ );\fR
+.SP 1
+.LI DBUG_OUTPUT\
+In multi-threaded environment disables (or enables) any
+.I dbug
+output from the current thread.
+.SP 1
+EX:\ \fCDBUG_OUTPUT(\ 0\ );\fR
+.SP 1
.LE
.SK
@@ -815,6 +899,18 @@ and the flag characters which enable or disable them.
Argument lists enclosed in '[' and ']' are optional.
.SP 2
.BL 22
+.LI a[,file]
+Redirect the debugger output stream and append it to the specified file.
+The default output stream is stderr.
+A null argument list causes output to be redirected to stdout.
+Double the colon, if you want it in the path
+.SP 1
+EX: \fCa,C::\\tmp\\log\fR
+.LI A[,file]
+Like 'a[,file]' but ensure that data are written after each write
+(this typically implies flush or close/reopen). It helps to get
+a complete log file in case of crashes. This mode is implied in
+multi-threaded environment.
.LI d[,keywords]
Enable output from macros with specified keywords.
A null list of keywords implies that all keywords are selected.
@@ -828,6 +924,14 @@ A null list of functions implies that all functions are selected.
.LI F
Mark each debugger output line with the name of the source file
containing the macro causing the output.
+.LI i
+Mark each debugger output line with the PID of the current process.
+.LI g,[functions]
+Enable profiling for the specified list of functions.
+By default profiling is enabled for all functions.
+See
+.B PROFILING\ WITH\ DBUG
+below.
.LI L
Mark each debugger output line with the source file line number of
the macro causing the output.
@@ -838,9 +942,9 @@ Sequentially number each debugger output line starting at 1.
This is useful for reference purposes when debugger output is
interspersed with program output.
.LI o[,file]
-Redirect the debugger output stream to the specified file.
-The default output stream is stderr.
-A null argument list causes output to be redirected to stdout.
+Like 'a[,file]' but overwrite old file, do not append.
+.LI O[,file]
+Like 'A[,file]' but overwrite old file, do not append.
.LI p[,processes]
Limit debugger actions to the specified processes.
A null list implies all processes.
@@ -865,6 +969,14 @@ Most useful with
.B DBUG_PUSH
macros used to temporarily alter the
debugger state.
+.LI S
+When compiled with
+.I safemalloc
+this flag forces "sanity" memory checks (for overwrites/underwrites)
+on each
+.B DBUG_ENTER
+and
+.B DBUG_RETURN.
.LI t[,N]
Enable function control flow tracing.
The maximum nesting depth is specified by N, and defaults to
@@ -872,6 +984,76 @@ The maximum nesting depth is specified by N, and defaults to
.LE
.SK
.B
+PROFILING WITH DBUG
+.R
+
+.P
+With
+.I dbug
+one can do profiling in a machine independent fashion,
+without a need for profiled version of system libraries.
+For this,
+.I dbug
+can write out a file
+called
+.B dbugmon.out
+(by default). This is an ascii file containing lines of the form:
+.DS CB N
+\fC<function-name> E <time-entered>
+<function-name> X <time-exited>
+.DE
+
+.P
+A second program (\fBanalyze\fR) reads this file, and produces a report on
+standard output.
+
+.P
+Profiling is enabled through the
+.B g
+flag. It can take a list of
+function names for which profiling is enabled. By default, it
+profiles all functions.
+
+.P
+The profile file is opened for appending. This
+is in order that one can run a program several times, and get the
+sum total of all the times, etc.
+
+.P
+An example of the report generated follows:
+.DS CB N
+\fC
+ Profile of Execution
+ Execution times are in milliseconds
+
+ Calls Time
+ ----- ----
+ Times Percentage Time Spent Percentage
+Function Called of total in Function of total Importance
+======== ====== ========== =========== ========== ==========
+factorial 5 83.33 30 100.00 8333
+main 1 16.67 0 0.00 0
+======== ====== ========== =========== ==========
+Totals 6 100.00 30 100.00
+.DE
+.P
+As you can see, it's quite self-evident. The
+.B Importance
+column is a
+metric obtained by multiplying the percentage of the calls and the percentage
+of the time. Functions with higher 'importance' benefit the most from
+being sped up.
+
+.P
+As a limitation - setjmp/longjmp, or child processes, are ignored
+for the time being. Also, profiling does not work
+in a multi-threaded environment.
+
+.P
+Profiling code is (c) Binayak Banerjee.
+
+.SK
+.B
HINTS AND MISCELLANEOUS
.R
@@ -934,4 +1116,4 @@ The most common problem is multiply allocated memory.
.\" .DE nroff dident like this. davida 900108
.CS
-
+.\" vim:filetype=nroff
diff --git a/extra/Makefile.am b/extra/Makefile.am
index aec7ad7dda5..dac6bf0fc0b 100644
--- a/extra/Makefile.am
+++ b/extra/Makefile.am
@@ -14,12 +14,32 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include \
- @ndbcluster_includes@ -I$(top_srcdir)/sql
+INCLUDES = -I$(top_srcdir)/include \
+ @ndbcluster_includes@ -I$(top_srcdir)/sql \
+ -I$(top_builddir)/include
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a
+BUILT_SOURCES= $(top_builddir)/include/mysqld_error.h \
+ $(top_builddir)/include/sql_state.h \
+ $(top_builddir)/include/mysqld_ername.h
+pkginclude_HEADERS= $(BUILT_SOURCES)
+CLEANFILES = $(BUILT_SOURCES)
+
+# This will build mysqld_error.h and sql_state.h
+$(top_builddir)/include/mysqld_error.h: comp_err
+ $(top_builddir)/extra/comp_err \
+ --charset=$(top_srcdir)/sql/share/charsets \
+ --out-dir=$(top_builddir)/sql/share/ \
+ --header_file=$(top_builddir)/include/mysqld_error.h \
+ --name_file=$(top_builddir)/include/mysqld_ername.h \
+ --state_file=$(top_builddir)/include/sql_state.h \
+ --in_file=$(top_srcdir)/sql/share/errmsg.txt
+$(top_builddir)/include/mysqld_ername.h: $(top_builddir)/include/mysqld_error.h
+$(top_builddir)/include/sql_state.h: $(top_builddir)/include/mysqld_error.h
+
bin_PROGRAMS = replace comp_err perror resolveip my_print_defaults \
resolve_stack_dump mysql_waitpid
+noinst_PROGRAMS = charset2html
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/mysys/charset2html.c b/extra/charset2html.c
index 96862ff16a1..96862ff16a1 100644
--- a/mysys/charset2html.c
+++ b/extra/charset2html.c
diff --git a/extra/comp_err.c b/extra/comp_err.c
index 6c7fad6a270..85833999d5c 100644
--- a/extra/comp_err.c
+++ b/extra/comp_err.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB
+/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,287 +14,932 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Saves all errmesg in a header file, updated by me, in a compact file */
+/*
+ Written by Anjuta Widenius
+*/
+
+/*
+ Creates one include file and multiple language-error message files from one
+ multi-language text file.
+*/
#include <my_global.h>
#include <m_ctype.h>
#include <my_sys.h>
#include <m_string.h>
+#include <my_getopt.h>
+#include <assert.h>
+#include <my_dir.h>
-#define MAXLENGTH 1000
#define MAX_ROWS 1000
-#define MAX_FILES 10
-#define MAX_CHARSET_NAME 64
+#define HEADER_LENGTH 32 /* Length of header in errmsg.sys */
+#define DEFAULT_CHARSET_DIR "../sql/share/charsets"
+#define ER_PREFIX "ER_"
+#define WARN_PREFIX "WARN_"
+static char *OUTFILE= (char*) "errmsg.sys";
+static char *HEADERFILE= (char*) "mysqld_error.h";
+static char *NAMEFILE= (char*) "mysqld_ername.h";
+static char *STATEFILE= (char*) "sql_state.h";
+static char *TXTFILE= (char*) "../sql/share/errmsg.txt";
+static char *DATADIRECTORY= (char*) "../sql/share/";
+static char *default_dbug_option= (char*) "d:t:O,/tmp/comp_err.trace";
+
+/* Header for errmsg.sys files */
+uchar file_head[]= { 254, 254, 2, 1 };
+/* Store positions to each error message row to store in errmsg.sys header */
+uint file_pos[MAX_ROWS];
+
+const char *empty_string= ""; /* For empty states */
+/*
+ Default values for command line options. See getopt structure for defintions
+ for these.
+*/
+
+const char *default_language= "eng";
+int er_offset= 1000;
+my_bool info_flag= 0;
+
+/* Storage of one error message row (for one language) */
+
+struct message
+{
+ char *lang_short_name;
+ char *text;
+};
-int row_count;
-uint file_pos[MAX_ROWS],file_row_pos[MAX_FILES];
-my_string saved_row[MAX_ROWS];
-uchar file_head[]= { 254,254,2,1 };
-char charset_name[MAX_CHARSET_NAME];
-static void get_options(int *argc,char **argv[]);
-static int count_rows(FILE *from,pchar c, pchar c2);
-static int remember_rows(FILE *from,pchar c);
-static int copy_rows(FILE *to);
+/* Storage for languages and charsets (from start of error text file) */
+
+struct languages
+{
+ char *lang_long_name; /* full name of the language */
+ char *lang_short_name; /* abbreviation of the lang. */
+ char *charset; /* Character set name */
+ struct languages *next_lang; /* Pointer to next language */
+};
- /* Functions defined in this file */
+/* Name, code and texts (for all lang) for one error message */
-int main(int argc,char *argv[])
+struct errors
{
- uint csnum= 0;
- int i,error,files,length;
- uchar head[32];
- FILE *from,*to;
- MY_INIT(argv[0]);
-
- get_options(&argc,&argv);
- error=1;
- row_count=files=0;
+ const char *er_name; /* Name of the error (ER_HASHCK) */
+ int d_code; /* Error code number */
+ const char *sql_code1; /* sql state */
+ const char *sql_code2; /* ODBC state */
+ struct errors *next_error; /* Pointer to next error */
+ DYNAMIC_ARRAY msg; /* All language texts for this error */
+};
+
- to=0;
- for ( ; argc-- > 1 ; argv++)
+static struct my_option my_long_options[]=
+{
+#ifdef DBUG_OFF
+ {"debug", '#', "This is a non-debug version. Catch this and exit",
+ 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#else
+ {"debug", '#', "Output debug log", (gptr *) & default_dbug_option,
+ (gptr *) & default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"debug-info", 'T', "Print some debug info at exit.", (gptr *) & info_flag,
+ (gptr *) & info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG,
+ NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Prints version", 0, 0, 0, GET_NO_ARG,
+ NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"charset", 'C', "Charset dir", (gptr *) & charsets_dir,
+ (gptr *) & charsets_dir,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"in_file", 'F', "Input file", (gptr *) & TXTFILE, (gptr *) & TXTFILE,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"out_dir", 'D', "Output base directory", (gptr *) & DATADIRECTORY,
+ (gptr *) & DATADIRECTORY,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"out_file", 'O', "Output filename (errmsg.sys)", (gptr *) & OUTFILE,
+ (gptr *) & OUTFILE, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"header_file", 'H', "mysqld_error.h file ", (gptr *) & HEADERFILE,
+ (gptr *) & HEADERFILE, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"name_file", 'N', "mysqld_ername.h file ", (gptr *) & NAMEFILE,
+ (gptr *) & NAMEFILE, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"state_file", 'S', "sql_state.h file", (gptr *) & STATEFILE,
+ (gptr *) & STATEFILE, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+static struct languages *parse_charset_string(char *str);
+static struct errors *parse_error_string(char *ptr, int er_count);
+static struct message *parse_message_string(struct message *new_message,
+ char *str);
+static struct message *find_message(struct errors *err, const char *lang);
+static int parse_input_file(const char *file_name, struct errors **top_error,
+ struct languages **top_language);
+static int get_options(int *argc, char ***argv);
+static void print_version(void);
+static void usage(void);
+static my_bool get_one_option(int optid, const struct my_option *opt,
+ char *argument);
+static char *parse_text_line(char *pos);
+static int copy_rows(FILE * to, char *row, int row_nr, long start_pos);
+static char *parse_default_language(char *str);
+static uint parse_error_offset(char *str);
+
+static char *skip_delimiters(char *str);
+static char *get_word(char **str);
+static char *find_end_of_word(char *str);
+static void clean_up(struct languages *lang_head, struct errors *error_head);
+static int create_header_files(struct errors *error_head);
+static int create_sys_files(struct languages *lang_head,
+ struct errors *error_head, uint row_count);
+
+
+int main(int argc, char *argv[])
+{
+ MY_INIT(argv[0]);
{
- file_row_pos[files++] = row_count;
+ uint row_count;
+ struct errors *error_head;
+ struct languages *lang_head;
+ DBUG_ENTER("main");
- if ((from = fopen(*argv,"r")) == NULL)
+ charsets_dir= DEFAULT_CHARSET_DIR;
+ if (get_options(&argc, &argv))
+ DBUG_RETURN(1);
+ if (!(row_count= parse_input_file(TXTFILE, &error_head, &lang_head)))
{
- fprintf(stderr,"Can't open file '%s'\n",*argv);
- return(1);
+ fprintf(stderr, "Failed to parse input file %s\n", TXTFILE);
+ DBUG_RETURN(1);
}
-
- VOID(count_rows(from,'"','{')); /* Calculate start-info */
- if (!charset_name[0])
+ if (lang_head == NULL || error_head == NULL)
{
- fprintf(stderr,"Character set is not specified in '%s'\n",*argv);
- fclose(from);
- goto end;
+ fprintf(stderr, "Failed to parse input file %s\n", TXTFILE);
+ DBUG_RETURN(1);
}
- if (!(csnum= get_charset_number(charset_name, MY_CS_PRIMARY)))
+ if (create_header_files(error_head))
{
- fprintf(stderr,"Unknown character '%s' in '%s'\n",charset_name, *argv);
- fclose(from);
- goto end;
+ fprintf(stderr, "Failed to create header files\n");
+ DBUG_RETURN(1);
}
-
- if (remember_rows(from,'}') < 0) /* Remember rows */
+ if (create_sys_files(lang_head, error_head, row_count))
{
- fprintf(stderr,"Can't find textrows in '%s'\n",*argv);
- fclose(from);
- goto end;
+ fprintf(stderr, "Failed to create sys files\n");
+ DBUG_RETURN(1);
}
- fclose(from);
+ clean_up(lang_head, error_head);
+ my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
+ DBUG_RETURN(0);
}
+}
- if ((to=my_fopen(*argv,O_WRONLY | FILE_BINARY,MYF(0))) == NULL)
+
+static int create_header_files(struct errors *error_head)
+{
+ uint er_last;
+ FILE *er_definef, *sql_statef, *er_namef;
+ struct errors *tmp_error;
+ DBUG_ENTER("create_header_files");
+ LINT_INIT(er_last);
+
+ if (!(er_definef= my_fopen(HEADERFILE, O_WRONLY, MYF(MY_WME))))
+ {
+ DBUG_RETURN(1);
+ }
+ if (!(sql_statef= my_fopen(STATEFILE, O_WRONLY, MYF(MY_WME))))
{
- fprintf(stderr,"Can't create file '%s'\n",*argv);
- return(1);
+ my_fclose(er_definef, MYF(0));
+ DBUG_RETURN(1);
+ }
+ if (!(er_namef= my_fopen(NAMEFILE, O_WRONLY, MYF(MY_WME))))
+ {
+ my_fclose(er_definef, MYF(0));
+ my_fclose(sql_statef, MYF(0));
+ DBUG_RETURN(1);
}
- fseek(to,(long) (32+row_count*2),0);
- if (copy_rows(to))
- goto end;
+ fprintf(er_definef, "/* Autogenerated file, please don't edit */\n\n");
+ fprintf(sql_statef, "/* Autogenerated file, please don't edit */\n\n");
+ fprintf(er_namef, "/* Autogenerated file, please don't edit */\n\n");
- length=ftell(to)-32-row_count*2;
+ fprintf(er_definef, "#define ER_ERROR_FIRST %d\n", error_head->d_code);
- bzero((gptr) head,32); /* Save Header & pointers */
- bmove((byte*) head,(byte*) file_head,4);
- head[4]=files;
- int2store(head+6,length);
- int2store(head+8,row_count);
- for (i=0 ; i<files ; i++)
+ for (tmp_error= error_head; tmp_error; tmp_error= tmp_error->next_error)
{
- int2store(head+10+i+i,file_row_pos[i]);
+ /*
+ generating mysqld_error.h
+ fprintf() will automaticly add \r on windows
+ */
+ fprintf(er_definef, "#define %s %d\n", tmp_error->er_name,
+ tmp_error->d_code);
+ er_last= tmp_error->d_code;
+
+ /* generating sql_state.h file */
+ if (tmp_error->sql_code1[0] || tmp_error->sql_code2[0])
+ fprintf(sql_statef,
+ "%-40s,\"%s\", \"%s\",\n", tmp_error->er_name,
+ tmp_error->sql_code1, tmp_error->sql_code2);
+ /*generating er_name file */
+ fprintf(er_namef, "{ \"%s\", %d },\n", tmp_error->er_name,
+ tmp_error->d_code);
+
}
- head[30]= csnum;
-
- fseek(to,0l,0);
- if (fwrite(head,1,32,to) != 32)
- goto end;
+ /* finishing off with mysqld_error.h */
+ fprintf(er_definef, "#define ER_ERROR_LAST %d\n", er_last);
+ my_fclose(er_definef, MYF(0));
+ my_fclose(sql_statef, MYF(0));
+ my_fclose(er_namef, MYF(0));
+ DBUG_RETURN(0);
+}
+
- for (i=0 ; i<row_count ; i++)
+static int create_sys_files(struct languages *lang_head,
+ struct errors *error_head, uint row_count)
+{
+ FILE *to;
+ uint csnum= 0, length, i, row_nr;
+ uchar head[32];
+ char outfile[FN_REFLEN], *outfile_end;
+ long start_pos;
+ struct message *tmp;
+ struct languages *tmp_lang;
+ struct errors *tmp_error;
+
+ MY_STAT stat_info;
+ DBUG_ENTER("create_sys_files");
+
+ /*
+ going over all languages and assembling corresponding error messages
+ */
+ for (tmp_lang= lang_head; tmp_lang; tmp_lang= tmp_lang->next_lang)
{
- int2store(head,file_pos[i]);
- if (fwrite(head,1,2,to) != 2)
- goto end;
- }
- error=0;
- printf("Found %d messages in language file %s\n",row_count,*argv);
- end:
- if (to)
- fclose(to);
- if (error)
- fprintf(stderr,"Can't update messagefile %s, errno: %d\n",*argv,errno);
+ /* setting charset name */
+ if (!(csnum= get_charset_number(tmp_lang->charset, MY_CS_PRIMARY)))
+ {
+ fprintf(stderr, "Unknown charset '%s' in '%s'\n", tmp_lang->charset,
+ TXTFILE);
+ DBUG_RETURN(1);
+ }
+
+ outfile_end= strxmov(outfile, DATADIRECTORY,
+ tmp_lang->lang_long_name, NullS);
+ if (!my_stat(outfile, &stat_info,MYF(0)))
+ {
+ if (my_mkdir(outfile, 0777,MYF(0)) < 0)
+ {
+ fprintf(stderr, "Can't create output directory for %s\n",
+ outfile);
+ DBUG_RETURN(1);
+ }
+ }
+
+ strxmov(outfile_end, FN_ROOTDIR, OUTFILE, NullS);
- exit(error);
- return(0);
-} /* main */
+ if (!(to= my_fopen(outfile, O_WRONLY | FILE_BINARY, MYF(MY_WME))))
+ DBUG_RETURN(1);
+ /* 2 is for 2 bytes to store row position / error message */
+ start_pos= (long) (HEADER_LENGTH + row_count * 2);
+ fseek(to, start_pos, 0);
+ row_nr= 0;
+ for (tmp_error= error_head; tmp_error; tmp_error= tmp_error->next_error)
+ {
+ /* dealing with messages */
+ tmp= find_message(tmp_error, tmp_lang->lang_short_name);
- /* Read options */
+ if (!tmp)
+ {
+ fprintf(stderr,
+ "Did not find message for %s neither in %s nor in default "
+ "language\n", tmp_error->er_name, tmp_lang->lang_short_name);
+ goto err;
+ }
+ if (copy_rows(to, tmp->text, row_nr, start_pos))
+ {
+ fprintf(stderr, "Failed to copy rows to %s\n", outfile);
+ goto err;
+ }
+ row_nr++;
+ }
-static void get_options(register int *argc,register char **argv[])
-{
- int help=0;
- char *pos,*progname;
-
- progname= (*argv)[0];
- while (--*argc >0 && *(pos = *(++*argv)) == '-' ) {
- while (*++pos)
- switch(*pos) {
- case '#':
- DBUG_PUSH (++pos);
- *(pos--) = '\0'; /* Skippa argument */
- break;
- case 'V':
- printf("%s (Compile errormessage) Ver 1.3\n",progname);
- break;
- case 'C':
- charsets_dir= pos+1;
- *(pos--)= '\0';
- break;
- case 'I':
- case '?':
- printf(" %s (Compile errormessage) Ver 1.3\n",progname);
- puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
- printf("Usage: %s [-?] [-I] [-V] fromfile[s] tofile\n",progname);
- puts("Options: -Info -Version\n");
- help=1;
- break;
- default:
- fprintf(stderr,"illegal option: -%c\n",*pos);
- fprintf(stderr,"legal options: -?IV\n");
- break;
+ /* continue with header of the errmsg.sys file */
+ length= ftell(to) - HEADER_LENGTH - row_count * 2;
+ bzero((gptr) head, HEADER_LENGTH);
+ bmove((byte *) head, (byte *) file_head, 4);
+ head[4]= 1;
+ int2store(head + 6, length);
+ int2store(head + 8, row_count);
+ head[30]= csnum;
+
+ my_fseek(to, 0l, MY_SEEK_SET, MYF(0));
+ if (my_fwrite(to, (byte*) head, HEADER_LENGTH, MYF(MY_WME | MY_FNABP)))
+ goto err;
+
+ for (i= 0; i < row_count; i++)
+ {
+ int2store(head, file_pos[i]);
+ if (my_fwrite(to, (byte*) head, 2, MYF(MY_WME | MY_FNABP)))
+ goto err;
}
+ my_fclose(to, MYF(0));
}
- if (*argc < 2)
+ DBUG_RETURN(0);
+
+err:
+ my_fclose(to, MYF(0));
+ DBUG_RETURN(1);
+}
+
+
+static void clean_up(struct languages *lang_head, struct errors *error_head)
+{
+ struct languages *tmp_lang, *next_language;
+ struct errors *tmp_error, *next_error;
+ uint count, i;
+
+ my_free((gptr) default_language, MYF(0));
+
+ for (tmp_lang= lang_head; tmp_lang; tmp_lang= next_language)
{
- if (!help)
- printf("Usage: %s [-?] [-I] [-V] fromfile[s] tofile\n",progname);
- exit(-1);
+ next_language= tmp_lang->next_lang;
+ my_free(tmp_lang->lang_short_name, MYF(0));
+ my_free(tmp_lang->lang_long_name, MYF(0));
+ my_free(tmp_lang->charset, MYF(0));
+ my_free((gptr) tmp_lang, MYF(0));
}
- return;
-} /* get_options */
+ for (tmp_error= error_head; tmp_error; tmp_error= next_error)
+ {
+ next_error= tmp_error->next_error;
+ count= (tmp_error->msg).elements;
+ for (i= 0; i < count; i++)
+ {
+ struct message *tmp;
+ tmp= dynamic_element(&tmp_error->msg, i, struct message*);
+ my_free((gptr) tmp->lang_short_name, MYF(0));
+ my_free((gptr) tmp->text, MYF(0));
+ }
+
+ delete_dynamic(&tmp_error->msg);
+ if (tmp_error->sql_code1[0])
+ my_free((gptr) tmp_error->sql_code1, MYF(0));
+ if (tmp_error->sql_code2[0])
+ my_free((gptr) tmp_error->sql_code2, MYF(0));
+ my_free((gptr) tmp_error->er_name, MYF(0));
+ my_free((gptr) tmp_error, MYF(0));
+ }
+}
- /* Count rows in from-file until row that start with char is found */
-static int count_rows(FILE *from, pchar c, pchar c2)
+static int parse_input_file(const char *file_name, struct errors **top_error,
+ struct languages **top_lang)
{
- int count;
- long pos;
- char rad[MAXLENGTH];
- DBUG_ENTER("count_rows");
-
- pos=ftell(from); count=0;
-
- charset_name[0]= '\0';
- while (fgets(rad,MAXLENGTH,from) != NULL)
+ FILE *file;
+ char *str, buff[1000];
+ struct errors *current_error= 0, **tail_error= top_error;
+ struct message current_message;
+ int rcount= 0;
+ DBUG_ENTER("parse_input_file");
+
+ if (!(file= my_fopen(file_name, O_RDONLY | O_SHARE, MYF(MY_WME))))
+ DBUG_RETURN(0);
+
+ while ((str= fgets(buff, sizeof(buff), file)))
{
- if (!strncmp(rad,"character-set=",14))
+ if (is_prefix(str, "language"))
+ {
+ if (!(*top_lang= parse_charset_string(str)))
+ {
+ fprintf(stderr, "Failed to parse the charset string!\n");
+ DBUG_RETURN(0);
+ }
+ continue;
+ }
+ if (is_prefix(str, "start-error-number"))
+ {
+ if (!(er_offset= parse_error_offset(str)))
+ {
+ fprintf(stderr, "Failed to parse the error offset string!\n");
+ DBUG_RETURN(0);
+ }
+ continue;
+ }
+ if (is_prefix(str, "default-language"))
+ {
+ if (!(default_language= parse_default_language(str)))
+ {
+ DBUG_PRINT("info", ("default_slang: %s", default_language));
+ fprintf(stderr,
+ "Failed to parse the default language line. Aborting\n");
+ DBUG_RETURN(0);
+ }
+ continue;
+ }
+
+ if (*str == '\t' || *str == ' ')
{
- char *b= rad+14, *e;
- for (e=b ; e[0] && e-b < MAX_CHARSET_NAME &&
- e[0] != ' ' && e[0] != '\r' &&
- e[0] != '\n' && e[0] != '\t' ; e++);
- e[0]= '\0';
- strcpy(charset_name, b);
+ /* New error message in another language for previous error */
+ if (!current_error)
+ {
+ fprintf(stderr, "Error in the input file format\n");
+ DBUG_RETURN(0);
+ }
+ if (!parse_message_string(&current_message, str))
+ {
+ fprintf(stderr, "Failed to parse message string for error '%s'",
+ current_error->er_name);
+ DBUG_RETURN(0);
+ }
+ if (insert_dynamic(&current_error->msg, (byte *) & current_message))
+ DBUG_RETURN(0);
+ continue;
}
- if (rad[0] == c || rad[0] == c2)
- break;
- count++;
- pos=ftell(from);
+ if (is_prefix(str, ER_PREFIX) || is_prefix(str, WARN_PREFIX))
+ {
+ if (!(current_error= parse_error_string(str, rcount)))
+ {
+ fprintf(stderr, "Failed to parse the error name string\n");
+ DBUG_RETURN(0);
+ }
+ rcount++; /* Count number of unique errors */
+
+ /* add error to the list */
+ *tail_error= current_error;
+ tail_error= &current_error->next_error;
+ continue;
+ }
+ if (*str == '#' || *str == '\n')
+ continue; /* skip comment or empty lines */
+
+ fprintf(stderr, "Wrong input file format. Stop!\nLine: %s\n", str);
+ DBUG_RETURN(0);
+ }
+ *tail_error= 0; /* Mark end of list */
+
+ my_fclose(file, MYF(0));
+ DBUG_RETURN(rcount);
+}
+
+
+static uint parse_error_offset(char *str)
+{
+ char *soffset, *end;
+ int error;
+ uint ioffset;
+
+ DBUG_ENTER("parse_error_offset");
+ /* skipping the "start-error-number" keyword and spaces after it */
+ str= find_end_of_word(str);
+ str= skip_delimiters(str);
+
+ if (!*str)
+ DBUG_RETURN(0); /* Unexpected EOL: No error number after the keyword */
+
+ /* reading the error offset */
+ if (!(soffset= get_word(&str)))
+ DBUG_RETURN(0); /* OOM: Fatal error */
+ DBUG_PRINT("info", ("default_error_offset: %s", soffset));
+
+ /* skipping space(s) and/or tabs after the error offset */
+ str= skip_delimiters(str);
+ DBUG_PRINT("info", ("str: %s", str));
+ if (*str)
+ {
+ /* The line does not end with the error offset -> error! */
+ fprintf(stderr, "The error offset line does not end with an error offset");
+ DBUG_RETURN(0);
}
- fseek(from,pos,0); /* Position to beginning of last row */
- DBUG_PRINT("exit",("count: %d",count));
- DBUG_RETURN(count);
-} /* count_rows */
+ DBUG_PRINT("info", ("str: %s", str));
+
+ end= 0;
+ ioffset= (uint) my_strtoll10(soffset, &end, &error);
+ my_free((gptr) soffset, MYF(0));
+ DBUG_RETURN(ioffset);
+}
- /* Read rows and remember them until row that start with char */
- /* Converts row as a C-compiler would convert a textstring */
+/* Parsing of the default language line. e.g. "default-lanuage eng" */
-static int remember_rows(FILE* from, pchar c)
+static char *parse_default_language(char *str)
{
- int i,nr,start_count,found_end;
- char row[MAXLENGTH],*pos;
- DBUG_ENTER("remember_rows");
+ char *slang;
+
+ DBUG_ENTER("parse_default_language");
+ /* skipping the "default_language" keyword */
+ str= find_end_of_word(str);
+ /* skipping space(s) and/or tabs after the keyword */
+ str= skip_delimiters(str);
+ if (!*str)
+ {
+ fprintf(stderr,
+ "Unexpected EOL: No short language name after the keyword\n");
+ DBUG_RETURN(0);
+ }
+
+ /* reading the short language tag */
+ if (!(slang= get_word(&str)))
+ DBUG_RETURN(0); /* OOM: Fatal error */
+ DBUG_PRINT("info", ("default_slang: %s", slang));
- start_count=row_count; found_end=0;
- while (fgets(row,MAXLENGTH,from) != NULL)
+ str= skip_delimiters(str);
+ DBUG_PRINT("info", ("str: %s", str));
+ if (*str)
{
- if (row[0] == c)
+ fprintf(stderr,
+ "The default language line does not end with short language "
+ "name\n");
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("info", ("str: %s", str));
+ DBUG_RETURN(slang);
+}
+
+
+/*
+ For given error finds message on given language, if does not exist,
+ returns english.
+*/
+
+static struct message *find_message(struct errors *err, const char *lang)
+{
+ struct message *tmp, *return_val= 0;
+ uint i, count;
+ DBUG_ENTER("find_message");
+
+ count= (err->msg).elements;
+ for (i= 0; i < count; i++)
+ {
+ tmp= dynamic_element(&err->msg, i, struct message*);
+
+ if (!strcmp(tmp->lang_short_name, lang))
+ DBUG_RETURN(tmp);
+ if (!strcmp(tmp->lang_short_name, default_language))
{
- found_end=1;
- break;
+ DBUG_ASSERT(tmp->text[0] != 0);
+ return_val= tmp;
}
- for (pos=row ; *pos ;)
+ }
+ DBUG_RETURN(return_val);
+}
+
+
+/*
+ Skips spaces and or tabs till the beginning of the next word
+ Returns pointer to the beginning of the first character of the word
+*/
+
+static char *skip_delimiters(char *str)
+{
+ DBUG_ENTER("skip_delimiters");
+ for (;
+ *str == ' ' || *str == ',' || *str == '\t' || *str == '\r' ||
+ *str == '\n' || *str == '='; str++)
+ ;
+ DBUG_RETURN(str);
+}
+
+
+/*
+ Skips all characters till meets with space, or tab, or EOL
+*/
+
+static char *find_end_of_word(char *str)
+{
+ DBUG_ENTER("find_end_of_word");
+ for (;
+ *str != ' ' && *str != '\t' && *str != '\n' && *str != '\r' && *str &&
+ *str != ',' && *str != ';' && *str != '='; str++)
+ ;
+ DBUG_RETURN(str);
+}
+
+
+/* Read the word starting from *str */
+
+static char *get_word(char **str)
+{
+ char *start= *str;
+ DBUG_ENTER("get_word");
+
+ *str= find_end_of_word(start);
+ DBUG_RETURN(my_strdup_with_length(start, (uint) (*str - start),
+ MYF(MY_WME | MY_FAE)));
+}
+
+
+/*
+ Parsing the string with short_lang - message text. Code - to
+ remember to which error does the text belong
+*/
+
+static struct message *parse_message_string(struct message *new_message,
+ char *str)
+{
+ char *start;
+
+ DBUG_ENTER("parse_message_string");
+ DBUG_PRINT("enter", ("str: %s", str));
+
+ /*skip space(s) and/or tabs in the beginning */
+ while (*str == ' ' || *str == '\t' || *str == '\n')
+ str++;
+
+ if (!*str)
+ {
+ /* It was not a message line, but an empty line. */
+ DBUG_PRINT("info", ("str: %s", str));
+ DBUG_RETURN(0);
+ }
+
+ /* reading the short lang */
+ start= str;
+ while (*str != ' ' && *str != '\t' && *str)
+ str++;
+ if (!(new_message->lang_short_name=
+ my_strdup_with_length(start, (uint) (str - start),
+ MYF(MY_WME | MY_FAE))))
+ DBUG_RETURN(0); /* Fatal error */
+ DBUG_PRINT("info", ("msg_slang: %s", new_message->lang_short_name));
+
+ /*skip space(s) and/or tabs after the lang */
+ while (*str == ' ' || *str == '\t' || *str == '\n')
+ str++;
+
+ if (*str != '"')
+ {
+ fprintf(stderr, "Unexpected EOL");
+ DBUG_PRINT("info", ("str: %s", str));
+ DBUG_RETURN(0);
+ }
+
+ /* reading the text */
+ start= str + 1;
+ str= parse_text_line(start);
+
+ if (!(new_message->text= my_strdup_with_length(start, (uint) (str - start),
+ MYF(MY_WME | MY_FAE))))
+ DBUG_RETURN(0); /* Fatal error */
+ DBUG_PRINT("info", ("msg_text: %s", new_message->text));
+
+ DBUG_RETURN(new_message);
+}
+
+
+/*
+ Parsing the string with error name and codes; returns the pointer to
+ the errors struct
+*/
+
+static struct errors *parse_error_string(char *str, int er_count)
+{
+ struct errors *new_error;
+ char *start;
+ DBUG_ENTER("parse_error_string");
+ DBUG_PRINT("enter", ("str: %s", str));
+
+ /* create a new a element */
+ new_error= (struct errors *) my_malloc(sizeof(*new_error), MYF(MY_WME));
+
+ if (my_init_dynamic_array(&new_error->msg, sizeof(struct message), 0, 0))
+ DBUG_RETURN(0); /* OOM: Fatal error */
+
+ /* getting the error name */
+ start= str;
+ str= skip_delimiters(str);
+
+ if (!(new_error->er_name= get_word(&str)))
+ DBUG_RETURN(0); /* OOM: Fatal error */
+ DBUG_PRINT("info", ("er_name: %s", new_error->er_name));
+
+ str= skip_delimiters(str);
+
+ /* getting the code1 */
+
+ new_error->d_code= er_offset + er_count;
+ DBUG_PRINT("info", ("d_code: %d", new_error->d_code));
+
+ str= skip_delimiters(str);
+
+ /* if we reached EOL => no more codes, but this can happen */
+ if (!*str)
+ {
+ new_error->sql_code1= empty_string;
+ new_error->sql_code2= empty_string;
+ DBUG_PRINT("info", ("str: %s", str));
+ DBUG_RETURN(new_error);
+ }
+
+ /* getting the sql_code 1 */
+
+ if (!(new_error->sql_code1= get_word(&str)))
+ DBUG_RETURN(0); /* OOM: Fatal error */
+ DBUG_PRINT("info", ("sql_code1: %s", new_error->sql_code1));
+
+ str= skip_delimiters(str);
+
+ /* if we reached EOL => no more codes, but this can happen */
+ if (!*str)
+ {
+ new_error->sql_code2= empty_string;
+ DBUG_PRINT("info", ("str: %s", str));
+ DBUG_RETURN(new_error);
+ }
+
+ /* getting the sql_code 2 */
+ if (!(new_error->sql_code2= get_word(&str)))
+ DBUG_RETURN(0); /* OOM: Fatal error */
+ DBUG_PRINT("info", ("sql_code2: %s", new_error->sql_code2));
+
+ str= skip_delimiters(str);
+ if (*str)
+ {
+ fprintf(stderr, "The error line did not end with sql/odbc code!");
+ DBUG_RETURN(0);
+ }
+
+ DBUG_RETURN(new_error);
+}
+
+
+/*
+ Parsing the string with charset/full lang name/short lang name;
+ returns pointer to the language structure
+*/
+
+static struct languages *parse_charset_string(char *str)
+{
+ struct languages *head=0, *new_lang;
+ DBUG_ENTER("parse_charset_string");
+ DBUG_PRINT("enter", ("str: %s", str));
+
+ /* skip over keyword */
+ str= find_end_of_word(str);
+ if (!*str)
+ {
+ /* unexpected EOL */
+ DBUG_PRINT("info", ("str: %s", str));
+ DBUG_RETURN(0);
+ }
+
+ str= skip_delimiters(str);
+ if (!(*str != ';' && *str))
+ DBUG_RETURN(0);
+
+ do
+ {
+ /*creating new element of the linked list */
+ new_lang= (struct languages *) my_malloc(sizeof(*new_lang), MYF(MY_WME));
+ new_lang->next_lang= head;
+ head= new_lang;
+
+ /* get the full language name */
+
+ if (!(new_lang->lang_long_name= get_word(&str)))
+ DBUG_RETURN(0); /* OOM: Fatal error */
+
+ DBUG_PRINT("info", ("long_name: %s", new_lang->lang_long_name));
+
+ /* getting the short name for language */
+ str= skip_delimiters(str);
+ if (!*str)
+ DBUG_RETURN(0); /* Error: No space or tab */
+
+ if (!(new_lang->lang_short_name= get_word(&str)))
+ DBUG_RETURN(0); /* OOM: Fatal error */
+ DBUG_PRINT("info", ("short_name: %s", new_lang->lang_short_name));
+
+ /* getting the charset name */
+ str= skip_delimiters(str);
+ if (!(new_lang->charset= get_word(&str)))
+ DBUG_RETURN(0); /* Fatal error */
+ DBUG_PRINT("info", ("charset: %s", new_lang->charset));
+
+ /* skipping space, tub or "," */
+ str= skip_delimiters(str);
+ }
+ while (*str != ';' && *str);
+
+ DBUG_PRINT("info", ("long name: %s", new_lang->lang_long_name));
+ DBUG_RETURN(head);
+}
+
+
+/* Read options */
+
+static void print_version(void)
+{
+ DBUG_ENTER("print_version");
+ printf("%s (Compile errormessage) Ver %s\n", my_progname, "2.0");
+ DBUG_VOID_RETURN;
+}
+
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)),
+ char *argument __attribute__ ((unused)))
+{
+ DBUG_ENTER("get_one_option");
+ switch (optid) {
+ case 'V':
+ print_version();
+ exit(0);
+ break;
+ case '?':
+ usage();
+ exit(0);
+ break;
+ case '#':
+ DBUG_PUSH(argument ? argument : default_dbug_option);
+ break;
+ }
+ DBUG_RETURN(0);
+}
+
+
+static void usage(void)
+{
+ DBUG_ENTER("usage");
+ print_version();
+ printf("This software comes with ABSOLUTELY NO WARRANTY. This is free "
+ "software,\nand you are welcome to modify and redistribute it under "
+ "the GPL license\nUsage:\n");
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+ DBUG_VOID_RETURN;
+}
+
+
+static int get_options(int *argc, char ***argv)
+{
+ int ho_error;
+ DBUG_ENTER("get_options");
+
+ if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
+ DBUG_RETURN(ho_error);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Read rows and remember them until row that start with char Converts
+ row as a C-compiler would convert a textstring
+*/
+
+static char *parse_text_line(char *pos)
+{
+ int i, nr;
+ char *row= pos;
+ DBUG_ENTER("parse_text_line");
+
+ while (*pos)
+ {
+ if (*pos == '\\')
{
- if (*pos == '\\')
- {
- switch (*++pos) {
- case '\\':
- case '"':
- VOID(strmov(pos-1,pos));
- break;
- case 'n':
- pos[-1]='\n';
- VOID(strmov(pos,pos+1));
- break;
- default:
- if (*pos >= '0' && *pos <'8')
- {
- nr=0;
- for (i=0 ; i<3 && (*pos >= '0' && *pos <'8' ) ; i++)
- nr=nr*8+ (*(pos++) -'0');
- pos-=i;
- pos[-1]=nr;
- VOID(strmov(pos,pos+i));
- }
- else if (*pos)
- VOID(strmov(pos-1,pos)); /* Remove '\' */
+ switch (*++pos) {
+ case '\\':
+ case '"':
+ VOID(strmov(pos - 1, pos));
+ break;
+ case 'n':
+ pos[-1]= '\n';
+ VOID(strmov(pos, pos + 1));
+ break;
+ default:
+ if (*pos >= '0' && *pos < '8')
+ {
+ nr= 0;
+ for (i= 0; i < 3 && (*pos >= '0' && *pos < '8'); i++)
+ nr= nr * 8 + (*(pos++) - '0');
+ pos -= i;
+ pos[-1]= nr;
+ VOID(strmov(pos, pos + i));
}
+ else if (*pos)
+ VOID(strmov(pos - 1, pos)); /* Remove '\' */
}
- else pos++;
}
- while (pos >row+1 && *pos != '"')
- pos--;
-
- if (!(saved_row[row_count] = (my_string) my_malloc((uint) (pos-row),
- MYF(MY_WME))))
- DBUG_RETURN(-1);
- *pos=0;
- VOID(strmov(saved_row[row_count],row+1));
- row_count++;
+ else
+ pos++;
}
- if (row_count-start_count == 0 && ! found_end)
- DBUG_RETURN(-1); /* Found nothing */
- DBUG_RETURN(row_count-start_count);
-} /* remember_rows */
+ while (pos > row + 1 && *pos != '"')
+ pos--;
+ *pos= 0;
+ DBUG_RETURN(pos);
+}
- /* Copy rows from memory to file and remember position */
+/* Copy rows from memory to file and remember position */
-
-static int copy_rows(FILE *to)
+static int copy_rows(FILE *to, char *row, int row_nr, long start_pos)
{
- int row_nr;
- long start_pos;
DBUG_ENTER("copy_rows");
- start_pos=ftell(to);
- for (row_nr =0 ; row_nr < row_count; row_nr++)
+ file_pos[row_nr]= (int) (ftell(to) - start_pos);
+ if (fputs(row, to) == EOF || fputc('\0', to) == EOF)
{
- file_pos[row_nr]= (int) (ftell(to)-start_pos);
- if (fputs(saved_row[row_nr],to) == EOF || fputc('\0',to) == EOF)
- {
- fprintf(stderr,"Can't write to outputfile\n");
- DBUG_RETURN(1);
- }
- my_free((gptr) saved_row[row_nr],MYF(0));
+ fprintf(stderr, "Can't write to outputfile\n");
+ DBUG_RETURN(1);
}
+
DBUG_RETURN(0);
-} /* copy_rows */
+}
diff --git a/extra/perror.c b/extra/perror.c
index 6e632b20d96..d68f5230e4a 100644
--- a/extra/perror.c
+++ b/extra/perror.c
@@ -250,7 +250,8 @@ int main(int argc,char *argv[])
'Unknown Error' (without regard to case).
*/
if (msg &&
- my_strnncoll(&my_charset_latin1, msg, 13, "Unknown Error", 13) &&
+ my_strnncoll(&my_charset_latin1, (const uchar*) msg, 13,
+ (const uchar*) "Unknown Error", 13) &&
(!unknown_error || strcmp(msg, unknown_error)))
{
found=1;
diff --git a/heap/Makefile.am b/heap/Makefile.am
index ec631148dce..2262fa3d5b1 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 = @MT_INCLUDES@ -I$(top_srcdir)/include
+INCLUDES = -I$(top_srcdir)/include
LDADD = libheap.a ../mysys/libmysys.a ../dbug/libdbug.a \
../strings/libmystrings.a
pkglib_LIBRARIES = libheap.a
diff --git a/heap/_check.c b/heap/_check.c
index a745aee48bf..4316a9926f7 100644
--- a/heap/_check.c
+++ b/heap/_check.c
@@ -123,7 +123,7 @@ static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records,
blength, records))
!= i)
{
- DBUG_PRINT("error",("Record in wrong link: Link %d Record: %lx Record-link %d", i,hash_info->ptr_to_rec,rec_link));
+ DBUG_PRINT("error",("Record in wrong link: Link %d Record: 0x%lx Record-link %d", i,hash_info->ptr_to_rec,rec_link));
error=1;
}
else
@@ -180,7 +180,7 @@ static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records,
key_length, SEARCH_FIND | SEARCH_SAME, &not_used))
{
error= 1;
- DBUG_PRINT("error",("Record in wrong link: key: %d Record: %lx\n",
+ DBUG_PRINT("error",("Record in wrong link: key: %d Record: 0x%lx\n",
keynr, recpos));
}
else
diff --git a/heap/heapdef.h b/heap/heapdef.h
index 083765334ab..68d9405138f 100644
--- a/heap/heapdef.h
+++ b/heap/heapdef.h
@@ -86,7 +86,8 @@ extern ulong hp_mask(ulong hashnr,ulong buffmax,ulong maxlength);
extern void hp_movelink(HASH_INFO *pos,HASH_INFO *next_link,
HASH_INFO *newlink);
extern int hp_rec_key_cmp(HP_KEYDEF *keydef,const byte *rec1,
- const byte *rec2);
+ const byte *rec2,
+ my_bool diff_if_only_endspace_difference);
extern int hp_key_cmp(HP_KEYDEF *keydef,const byte *rec,
const byte *key);
extern void hp_make_key(HP_KEYDEF *keydef,byte *key,const byte *rec);
@@ -94,6 +95,7 @@ extern uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
const byte *rec, byte *recpos);
extern uint hp_rb_key_length(HP_KEYDEF *keydef, const byte *key);
extern uint hp_rb_null_key_length(HP_KEYDEF *keydef, const byte *key);
+extern uint hp_rb_var_key_length(HP_KEYDEF *keydef, const byte *key);
extern my_bool hp_if_null_in_key(HP_KEYDEF *keyinfo, const byte *record);
extern int hp_close(register HP_INFO *info);
extern void hp_clear(HP_SHARE *info);
diff --git a/heap/hp_create.c b/heap/hp_create.c
index af32fefea1b..8fcf7dde000 100644
--- a/heap/hp_create.c
+++ b/heap/hp_create.c
@@ -76,9 +76,38 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
case HA_KEYTYPE_UINT24:
case HA_KEYTYPE_INT8:
keyinfo->seg[j].flag|= HA_SWAP_KEY;
+ break;
+ case HA_KEYTYPE_VARBINARY1:
+ /* Case-insensitiveness is handled in coll->hash_sort */
+ keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
+ /* fall_through */
+ case HA_KEYTYPE_VARTEXT1:
+ if (!my_binary_compare(keyinfo->seg[j].charset))
+ keyinfo->flag|= HA_END_SPACE_KEY;
+ keyinfo->flag|= HA_VAR_LENGTH_KEY;
+ /* Save number of bytes used to store length */
+ keyinfo->seg[j].bit_start= 1;
+ break;
+ case HA_KEYTYPE_VARBINARY2:
+ /* Case-insensitiveness is handled in coll->hash_sort */
+ /* fall_through */
+ case HA_KEYTYPE_VARTEXT2:
+ if (!my_binary_compare(keyinfo->seg[j].charset))
+ keyinfo->flag|= HA_END_SPACE_KEY;
+ keyinfo->flag|= HA_VAR_LENGTH_KEY;
+ /* Save number of bytes used to store length */
+ keyinfo->seg[j].bit_start= 2;
+ /*
+ Make future comparison simpler by only having to check for
+ one type
+ */
+ keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
+ break;
default:
break;
}
+ if (keyinfo->seg[j].flag & HA_END_SPACE_ARE_EQUAL)
+ keyinfo->flag|= HA_END_SPACE_KEY;
}
keyinfo->length= length;
length+= keyinfo->rb_tree.size_of_element +
@@ -89,7 +118,9 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
{
key_segs++; /* additional HA_KEYTYPE_END segment */
- if (keyinfo->flag & HA_NULL_PART_KEY)
+ if (keyinfo->flag & HA_VAR_LENGTH_KEY)
+ keyinfo->get_key_length= hp_rb_var_key_length;
+ else if (keyinfo->flag & HA_NULL_PART_KEY)
keyinfo->get_key_length= hp_rb_null_key_length;
else
keyinfo->get_key_length= hp_rb_key_length;
@@ -137,6 +168,8 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
keyinfo->write_key= hp_write_key;
keyinfo->hash_buckets= 0;
}
+ if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
+ share->auto_key= i + 1;
}
share->min_records= min_records;
share->max_records= max_records;
diff --git a/heap/hp_delete.c b/heap/hp_delete.c
index 9cf8b8936b6..5287533ae0a 100644
--- a/heap/hp_delete.c
+++ b/heap/hp_delete.c
@@ -24,7 +24,7 @@ int heap_delete(HP_INFO *info, const byte *record)
HP_SHARE *share=info->s;
HP_KEYDEF *keydef, *end, *p_lastinx;
DBUG_ENTER("heap_delete");
- DBUG_PRINT("enter",("info: %lx record: %lx",info,record));
+ DBUG_PRINT("enter",("info: %lx record: 0x%lx",info,record));
test_active(info);
@@ -123,7 +123,7 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
while (pos->ptr_to_rec != recpos)
{
- if (flag && !hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec))
+ if (flag && !hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec, 0))
last_ptr=pos; /* Previous same key */
gpos=pos;
if (!(pos=pos->next_key))
@@ -139,7 +139,7 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
/* Save for heap_rnext/heap_rprev */
info->current_hash_ptr=last_ptr;
info->current_ptr = last_ptr ? last_ptr->ptr_to_rec : 0;
- DBUG_PRINT("info",("Corrected current_ptr to point at: %lx",
+ DBUG_PRINT("info",("Corrected current_ptr to point at: 0x%lx",
info->current_ptr));
}
empty=pos;
diff --git a/heap/hp_hash.c b/heap/hp_hash.c
index ee5b4958e62..52a250bd7af 100644
--- a/heap/hp_hash.c
+++ b/heap/hp_hash.c
@@ -255,6 +255,9 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
if (*pos) /* Found null */
{
nr^= (nr << 1) | 1;
+ /* Add key pack length (2) to key for VARCHAR segments */
+ if (seg->type == HA_KEYTYPE_VARTEXT1)
+ key+= 2;
continue;
}
pos++;
@@ -262,14 +265,30 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
if (seg->type == HA_KEYTYPE_TEXT)
{
CHARSET_INFO *cs= seg->charset;
- uint char_length= (uint) ((uchar*) key - pos);
+ uint length= seg->length;
if (cs->mbmaxlen > 1)
{
- uint length= char_length;
+ uint char_length;
char_length= my_charpos(cs, pos, pos + length, length/cs->mbmaxlen);
- set_if_smaller(char_length, length); /* QQ: ok to remove? */
+ set_if_smaller(length, char_length);
}
- cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
+ cs->coll->hash_sort(cs, pos, length, &nr, &nr2);
+ }
+ else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
+ {
+ CHARSET_INFO *cs= seg->charset;
+ uint pack_length= 2; /* Key packing is constant */
+ uint length= uint2korr(pos);
+ if (cs->mbmaxlen > 1)
+ {
+ uint char_length;
+ char_length= my_charpos(cs, pos +pack_length,
+ pos +pack_length + length,
+ seg->length/cs->mbmaxlen);
+ set_if_smaller(length, char_length);
+ }
+ cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
+ key+= pack_length;
}
else
{
@@ -280,6 +299,7 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
}
}
}
+ DBUG_PRINT("exit", ("hash: 0x%lx", nr));
return((ulong) nr);
}
@@ -287,7 +307,6 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
{
- /*register*/
ulong nr=1, nr2=4;
HA_KEYSEG *seg,*endseg;
@@ -314,6 +333,21 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
}
cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
}
+ else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
+ {
+ CHARSET_INFO *cs= seg->charset;
+ uint pack_length= seg->bit_start;
+ uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
+ if (cs->mbmaxlen > 1)
+ {
+ uint char_length;
+ char_length= my_charpos(cs, pos + pack_length,
+ pos + pack_length + length,
+ seg->length/cs->mbmaxlen);
+ set_if_smaller(length, char_length);
+ }
+ cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
+ }
else
{
for (; pos < end ; pos++)
@@ -323,7 +357,8 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
}
}
}
- return((ulong) nr);
+ DBUG_PRINT("exit", ("hash: 0x%lx", nr));
+ return(nr);
}
#else
@@ -358,6 +393,9 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
if (*pos)
{
nr^= (nr << 1) | 1;
+ /* Add key pack length (2) to key for VARCHAR segments */
+ if (seg->type == HA_KEYTYPE_VARTEXT1)
+ key+= 2;
continue;
}
pos++;
@@ -366,6 +404,14 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
{
seg->charset->hash_sort(seg->charset,pos,((uchar*)key)-pos,&nr,NULL);
}
+ else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
+ {
+ uint pack_length= 2; /* Key packing is constant */
+ uint length= uint2korr(pos);
+ seg->charset->hash_sort(seg->charset, pos+pack_length, length, &nr,
+ NULL);
+ key+= pack_length;
+ }
else
{
for ( ; pos < (uchar*) key ; pos++)
@@ -375,7 +421,8 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
}
}
}
- return((ulong) nr);
+ DBUG_PRINT("exit", ("hash: 0x%lx", nr));
+ return(nr);
}
/* Calc hashvalue for a key in a record */
@@ -387,7 +434,7 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
{
- uchar *pos=(uchar*) rec+seg->start,*end=pos+seg->length;
+ uchar *pos=(uchar*) rec+seg->start;
if (seg->null_bit)
{
if (rec[seg->null_pos] & seg->null_bit)
@@ -400,8 +447,16 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
{
seg->charset->hash_sort(seg->charset,pos,((uchar*)key)-pos,&nr,NULL);
}
+ else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
+ {
+ uint pack_length= seg->bit_start;
+ uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
+ seg->charset->hash_sort(seg->charset, pos+pack_length,
+ length, &nr, NULL);
+ }
else
{
+ uchar *end= pos+seg->length;
for ( ; pos < end ; pos++)
{
nr *=16777619;
@@ -409,15 +464,35 @@ ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
}
}
}
- return((ulong) nr);
+ DBUG_PRINT("exit", ("hash: 0x%lx", nr));
+ return(nr);
}
#endif
- /* Compare keys for two records. Returns 0 if they are identical */
+/*
+ Compare keys for two records. Returns 0 if they are identical
+
+ SYNOPSIS
+ hp_rec_key_cmp()
+ keydef Key definition
+ rec1 Record to compare
+ rec2 Other record to compare
+ diff_if_only_endspace_difference
+ Different number of end space is significant
+
+ NOTES
+ diff_if_only_endspace_difference is used to allow us to insert
+ 'a' and 'a ' when there is an an unique key.
-int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
+ RETURN
+ 0 Key is identical
+ <> 0 Key differes
+*/
+
+int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2,
+ my_bool diff_if_only_endspace_difference)
{
HA_KEYSEG *seg,*endseg;
@@ -442,9 +517,9 @@ int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
{
uint char_length= seg->length / cs->mbmaxlen;
char_length1= my_charpos(cs, pos1, pos1 + seg->length, char_length);
- set_if_smaller(char_length1, seg->length); /* QQ: ok to remove? */
+ set_if_smaller(char_length1, seg->length);
char_length2= my_charpos(cs, pos2, pos2 + seg->length, char_length);
- set_if_smaller(char_length2, seg->length); /* QQ: ok to remove? */
+ set_if_smaller(char_length2, seg->length);
}
else
{
@@ -452,7 +527,42 @@ int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
}
if (seg->charset->coll->strnncollsp(seg->charset,
pos1,char_length1,
- pos2,char_length2))
+ pos2,char_length2, 0))
+ return 1;
+ }
+ else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
+ {
+ uchar *pos1= (uchar*) rec1 + seg->start;
+ uchar *pos2= (uchar*) rec2 + seg->start;
+ uint char_length1, char_length2;
+ uint pack_length= seg->bit_start;
+ CHARSET_INFO *cs= seg->charset;
+ if (pack_length == 1)
+ {
+ char_length1= (uint) *(uchar*) pos1++;
+ char_length2= (uint) *(uchar*) pos2++;
+ }
+ else
+ {
+ char_length1= uint2korr(pos1);
+ char_length2= uint2korr(pos2);
+ pos1+= 2;
+ pos2+= 2;
+ }
+ if (cs->mbmaxlen > 1)
+ {
+ uint char_length= seg->length / cs->mbmaxlen;
+ char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length);
+ set_if_smaller(char_length1, seg->length);
+ char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length);
+ set_if_smaller(char_length2, seg->length);
+ }
+
+ if (cs->coll->strnncollsp(seg->charset,
+ pos1, char_length1,
+ pos2, char_length2,
+ seg->flag & HA_END_SPACE_ARE_EQUAL ?
+ 0 : diff_if_only_endspace_difference))
return 1;
}
else
@@ -480,7 +590,12 @@ int hp_key_cmp(HP_KEYDEF *keydef, const byte *rec, const byte *key)
if (found_null != (int) *key++)
return 1;
if (found_null)
+ {
+ /* Add key pack length (2) to key for VARCHAR segments */
+ if (seg->type == HA_KEYTYPE_VARTEXT1)
+ key+= 2;
continue;
+ }
}
if (seg->type == HA_KEYTYPE_TEXT)
{
@@ -504,7 +619,34 @@ int hp_key_cmp(HP_KEYDEF *keydef, const byte *rec, const byte *key)
if (seg->charset->coll->strnncollsp(seg->charset,
(uchar*) pos, char_length_rec,
- (uchar*) key, char_length_key))
+ (uchar*) key, char_length_key, 0))
+ return 1;
+ }
+ else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
+ {
+ uchar *pos= (uchar*) rec + seg->start;
+ CHARSET_INFO *cs= seg->charset;
+ uint pack_length= seg->bit_start;
+ uint char_length_rec= (pack_length == 1 ? (uint) *(uchar*) pos :
+ uint2korr(pos));
+ /* Key segments are always packed with 2 bytes */
+ uint char_length_key= uint2korr(key);
+ pos+= pack_length;
+ key+= 2; /* skip key pack length */
+ if (cs->mbmaxlen > 1)
+ {
+ uint char_length= seg->length / cs->mbmaxlen;
+ char_length_key= my_charpos(cs, key, key + char_length_key,
+ char_length);
+ set_if_smaller(char_length_key, seg->length);
+ char_length_rec= my_charpos(cs, pos, pos + char_length_rec,
+ char_length);
+ set_if_smaller(char_length_rec, seg->length);
+ }
+
+ if (cs->coll->strnncollsp(seg->charset,
+ (uchar*) pos, char_length_rec,
+ (uchar*) key, char_length_key, 0))
return 1;
}
else
@@ -536,11 +678,20 @@ void hp_make_key(HP_KEYDEF *keydef, byte *key, const byte *rec)
char_length / cs->mbmaxlen);
set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
}
+ if (seg->type == HA_KEYTYPE_VARTEXT1)
+ char_length+= seg->bit_start; /* Copy also length */
memcpy(key,rec+seg->start,(size_t) char_length);
key+= char_length;
}
}
+#define FIX_LENGTH(cs, pos, length, char_length) \
+ do { \
+ if (length > char_length) \
+ char_length= my_charpos(cs, pos, pos+length, char_length); \
+ set_if_smaller(char_length,length); \
+ } while(0)
+
uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
const byte *rec, byte *recpos)
@@ -593,6 +744,26 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
}
continue;
}
+
+ if (seg->flag & HA_VAR_LENGTH_PART)
+ {
+ uchar *pos= (uchar*) rec + seg->start;
+ uint length= seg->length;
+ uint pack_length= seg->bit_start;
+ uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
+ uint2korr(pos));
+ CHARSET_INFO *cs= seg->charset;
+ char_length= length/cs->mbmaxlen;
+
+ pos+= pack_length; /* Skip VARCHAR length */
+ set_if_smaller(length,tmp_length);
+ FIX_LENGTH(cs, pos, length, char_length);
+ store_key_length_inc(key,char_length);
+ memcpy((byte*) key,(byte*) pos,(size_t) char_length);
+ key+= char_length;
+ continue;
+ }
+
char_length= seg->length;
if (seg->charset->mbmaxlen > 1)
{
@@ -643,6 +814,23 @@ uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
}
continue;
}
+ if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
+ {
+ /* Length of key-part used with heap_rkey() always 2 */
+ uint tmp_length=uint2korr(old);
+ uint length= seg->length;
+ CHARSET_INFO *cs= seg->charset;
+ char_length= length/cs->mbmaxlen;
+
+ k_len-= 2+length;
+ old+= 2;
+ set_if_smaller(length,tmp_length); /* Safety */
+ FIX_LENGTH(cs, old, length, char_length);
+ store_key_length_inc(key,char_length);
+ memcpy((byte*) key, old,(size_t) char_length);
+ key+= char_length;
+ continue;
+ }
char_length= seg->length;
if (seg->charset->mbmaxlen > 1)
{
@@ -682,6 +870,27 @@ uint hp_rb_null_key_length(HP_KEYDEF *keydef, const byte *key)
return key - start_key;
}
+
+uint hp_rb_var_key_length(HP_KEYDEF *keydef, const byte *key)
+{
+ const byte *start_key= key;
+ HA_KEYSEG *seg, *endseg;
+
+ for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
+ {
+ uint length= seg->length;
+ if (seg->null_bit && !*key++)
+ continue;
+ if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
+ {
+ get_key_length(length, key);
+ }
+ key+= length;
+ }
+ return key - start_key;
+}
+
+
/*
Test if any of the key parts are NULL.
Return:
diff --git a/heap/hp_open.c b/heap/hp_open.c
index 1fa832208fb..fd937229b0d 100644
--- a/heap/hp_open.c
+++ b/heap/hp_open.c
@@ -63,7 +63,7 @@ HP_INFO *heap_open(const char *name, int mode)
#ifndef DBUG_OFF
info->opt_flag= READ_CHECK_USED; /* Check when changing */
#endif
- DBUG_PRINT("exit",("heap: %lx reclength: %d records_in_block: %d",
+ DBUG_PRINT("exit",("heap: 0x%lx reclength: %d records_in_block: %d",
info,share->reclength,share->block.records_in_block));
DBUG_RETURN(info);
}
@@ -82,7 +82,7 @@ HP_SHARE *hp_find_named_heap(const char *name)
info= (HP_SHARE*) pos->data;
if (!strcmp(name, info->name))
{
- DBUG_PRINT("exit", ("Old heap_database: %lx",info));
+ DBUG_PRINT("exit", ("Old heap_database: 0x%lx",info));
DBUG_RETURN(info);
}
}
diff --git a/heap/hp_rkey.c b/heap/hp_rkey.c
index 2c23d9d721e..f5f22a877a1 100644
--- a/heap/hp_rkey.c
+++ b/heap/hp_rkey.c
@@ -23,7 +23,7 @@ int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
HP_SHARE *share= info->s;
HP_KEYDEF *keyinfo= share->keydef + inx;
DBUG_ENTER("heap_rkey");
- DBUG_PRINT("enter",("base: %lx inx: %d",info,inx));
+ DBUG_PRINT("enter",("base: 0x%lx inx: %d",info,inx));
if ((uint) inx >= share->keys)
{
@@ -64,7 +64,7 @@ int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
info->update= 0;
DBUG_RETURN(my_errno);
}
- if (!(keyinfo->flag & HA_NOSAME))
+ if (!(keyinfo->flag & HA_NOSAME) || (keyinfo->flag & HA_END_SPACE_KEY))
memcpy(info->lastkey, key, (size_t) keyinfo->length);
}
memcpy(record, pos, (size_t) share->reclength);
diff --git a/heap/hp_rrnd.c b/heap/hp_rrnd.c
index cce3ce24e51..4daa3a06377 100644
--- a/heap/hp_rrnd.c
+++ b/heap/hp_rrnd.c
@@ -29,7 +29,7 @@ int heap_rrnd(register HP_INFO *info, byte *record, byte *pos)
{
HP_SHARE *share=info->s;
DBUG_ENTER("heap_rrnd");
- DBUG_PRINT("enter",("info: %lx pos: %lx",info,pos));
+ DBUG_PRINT("enter",("info: 0x%lx pos: %lx",info,pos));
info->lastinx= -1;
if (!(info->current_ptr= pos))
@@ -44,7 +44,7 @@ int heap_rrnd(register HP_INFO *info, byte *record, byte *pos)
}
info->update=HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV;
memcpy(record,info->current_ptr,(size_t) share->reclength);
- DBUG_PRINT("exit",("found record at %lx",info->current_ptr));
+ DBUG_PRINT("exit",("found record at 0x%lx",info->current_ptr));
info->current_hash_ptr=0; /* Can't use rnext */
DBUG_RETURN(0);
} /* heap_rrnd */
@@ -64,7 +64,7 @@ int heap_rrnd_old(register HP_INFO *info, byte *record, ulong pos)
{
HP_SHARE *share=info->s;
DBUG_ENTER("heap_rrnd");
- DBUG_PRINT("enter",("info: %lx pos: %ld",info,pos));
+ DBUG_PRINT("enter",("info: 0x%lx pos: %ld",info,pos));
info->lastinx= -1;
if (pos == (ulong) -1)
@@ -98,7 +98,7 @@ end:
}
info->update=HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV;
memcpy(record,info->current_ptr,(size_t) share->reclength);
- DBUG_PRINT("exit",("found record at %lx",info->current_ptr));
+ DBUG_PRINT("exit",("found record at 0x%lx",info->current_ptr));
info->current_hash_ptr=0; /* Can't use rnext */
DBUG_RETURN(0);
} /* heap_rrnd */
diff --git a/heap/hp_update.c b/heap/hp_update.c
index 2ed0edf08de..2f4ea75f9aa 100644
--- a/heap/hp_update.c
+++ b/heap/hp_update.c
@@ -37,7 +37,7 @@ int heap_update(HP_INFO *info, const byte *old, const byte *heap_new)
p_lastinx= share->keydef + info->lastinx;
for (keydef= share->keydef, end= keydef + share->keys; keydef < end; keydef++)
{
- if (hp_rec_key_cmp(keydef, old, heap_new))
+ if (hp_rec_key_cmp(keydef, old, heap_new, 0))
{
if ((*keydef->delete_key)(info, keydef, old, pos, keydef == p_lastinx) ||
(*keydef->write_key)(info, keydef, heap_new, pos))
@@ -74,7 +74,7 @@ int heap_update(HP_INFO *info, const byte *old, const byte *heap_new)
}
while (keydef >= share->keydef)
{
- if (hp_rec_key_cmp(keydef, old, heap_new))
+ if (hp_rec_key_cmp(keydef, old, heap_new, 0))
{
if ((*keydef->delete_key)(info, keydef, heap_new, pos, 0) ||
(*keydef->write_key)(info, keydef, old, pos))
diff --git a/heap/hp_write.c b/heap/hp_write.c
index 808fe6608b1..a60d32eecb6 100644
--- a/heap/hp_write.c
+++ b/heap/hp_write.c
@@ -105,7 +105,7 @@ int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *record,
custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
if (keyinfo->flag & HA_NOSAME)
{
- custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME;
+ custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME | SEARCH_UPDATE;
keyinfo->rb_tree.flag= TREE_NO_DUPS;
}
else
@@ -138,7 +138,7 @@ static byte *next_free_record_pos(HP_SHARE *info)
pos=info->del_link;
info->del_link= *((byte**) pos);
info->deleted--;
- DBUG_PRINT("exit",("Used old position: %lx",pos));
+ DBUG_PRINT("exit",("Used old position: 0x%lx",pos));
DBUG_RETURN(pos);
}
if (!(block_pos=(info->records % info->block.records_in_block)))
@@ -370,7 +370,7 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
pos=empty;
do
{
- if (! hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec))
+ if (! hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec, 1))
{
DBUG_RETURN(my_errno=HA_ERR_FOUND_DUPP_KEY);
}
diff --git a/include/Makefile.am b/include/Makefile.am
index 0c845900a4f..5f426843950 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -17,31 +17,26 @@
BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h
pkginclude_HEADERS = my_dbug.h m_string.h my_sys.h my_list.h my_xml.h \
- mysql.h mysql_com.h mysqld_error.h mysql_embed.h \
+ mysql.h mysql_com.h mysql_embed.h \
my_semaphore.h my_pthread.h my_no_pthread.h raid.h \
errmsg.h my_global.h my_net.h my_alloc.h \
my_getopt.h sslopt-longopts.h my_dir.h typelib.h \
sslopt-vars.h sslopt-case.h sql_common.h keycache.h \
- sql_state.h mysql_time.h $(BUILT_SOURCES)
+ mysql_time.h $(BUILT_SOURCES)
noinst_HEADERS = config-win.h config-os2.h config-netware.h \
- nisam.h heap.h merge.h my_bitmap.h\
+ heap.h my_bitmap.h\
myisam.h myisampack.h myisammrg.h ft_global.h\
mysys_err.h my_base.h help_start.h help_end.h \
my_nosys.h my_alarm.h queues.h rijndael.h sha1.h \
my_aes.h my_tree.h hash.h thr_alarm.h \
thr_lock.h t_ctype.h violite.h md5.h \
- mysql_version.h.in my_handler.h my_time.h
+ mysql_version.h.in my_handler.h my_time.h decimal.h
# mysql_version.h are generated
-SUPERCLEANFILES = mysql_version.h my_config.h
+CLEANFILES = mysql_version.h my_config.h readline
# Some include files that may be moved and patched by configure
-DISTCLEANFILES = sched.h $(SUPERCLEANFILES)
-
-clean:
- $(RM) -fr readline
-distclean:
- $(RM) -fr readline
+DISTCLEANFILES = sched.h $(CLEANFILES)
all-local: my_config.h
diff --git a/include/config-netware.h b/include/config-netware.h
index c48aff70f3b..4a6dc3b1bb9 100644
--- a/include/config-netware.h
+++ b/include/config-netware.h
@@ -45,6 +45,7 @@ extern "C" {
#undef HAVE_SCHED_H
#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
diff --git a/include/config-win.h b/include/config-win.h
index b3865c1fda7..a4f81a0ec6a 100644
--- a/include/config-win.h
+++ b/include/config-win.h
@@ -321,7 +321,7 @@ inline double ulonglong2double(ulonglong value)
#define HAVE_QUERY_CACHE
#define SPRINTF_RETURNS_INT
#define HAVE_SETFILEPOINTER
-#define HAVE_VIO
+#define HAVE_VIO_READ_BUFF
#ifdef NOT_USED
#define HAVE_SNPRINTF /* Gave link error */
@@ -349,6 +349,9 @@ inline double ulonglong2double(ulonglong value)
#define SHAREDIR "share"
#define DEFAULT_CHARSET_HOME "C:/mysql/"
#endif
+#ifndef DEFAULT_HOME_ENV
+#define DEFAULT_HOME_ENV MYSQL_HOME
+#endif
/* File name handling */
@@ -360,6 +363,7 @@ inline double ulonglong2double(ulonglong value)
#define DO_NOT_REMOVE_THREAD_WRAPPERS
#define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V))
+#define thread_safe_decrement(V,L) InterlockedDecrement((long*) &(V))
/* The following is only used for statistics, so it should be good enough */
#ifdef __NT__ /* This should also work on Win98 but .. */
#define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C))
@@ -373,6 +377,7 @@ inline double ulonglong2double(ulonglong value)
#define statistic_add(V,C,L) (V)+=(C)
#endif
#define statistic_increment(V,L) thread_safe_increment((V),(L))
+#define statistic_decrement(V,L) thread_safe_decrement((V),(L))
#define shared_memory_buffer_length 16000
#define default_shared_memory_base_name "MYSQL"
@@ -386,6 +391,7 @@ inline double ulonglong2double(ulonglong value)
/* #undef HAVE_CHARSET_armscii8 */
/* #undef HAVE_CHARSET_ascii */
#define HAVE_CHARSET_big5 1
+#define HAVE_CHARSET_cp932
#define HAVE_CHARSET_cp1250 1
/* #undef HAVE_CHARSET_cp1251 */
/* #undef HAVE_CHARSET_cp1256 */
@@ -394,6 +400,7 @@ inline double ulonglong2double(ulonglong value)
/* #undef HAVE_CHARSET_cp852 */
/* #undef HAVE_CHARSET_cp866 */
/* #undef HAVE_CHARSET_dec8 */
+#define HAVE_CHARSET_eucjpms 1
#define HAVE_CHARSET_euckr 1
#define HAVE_CHARSET_gb2312 1
#define HAVE_CHARSET_gbk 1
diff --git a/include/decimal.h b/include/decimal.h
new file mode 100644
index 00000000000..7b49841ca88
--- /dev/null
+++ b/include/decimal.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 2000 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _decimal_h
+#define _decimal_h
+
+typedef enum
+{TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR}
+ decimal_round_mode;
+typedef int32 decimal_digit_t;
+
+typedef struct st_decimal_t {
+ int intg, frac, len;
+ my_bool sign;
+ decimal_digit_t *buf;
+} decimal_t;
+
+int internal_str2dec(const char *from, decimal_t *to, char **end,
+ my_bool fixed);
+int decimal2string(decimal_t *from, char *to, int *to_len,
+ int fixed_precision, int fixed_decimals,
+ char filler);
+int decimal2ulonglong(decimal_t *from, ulonglong *to);
+int ulonglong2decimal(ulonglong from, decimal_t *to);
+int decimal2longlong(decimal_t *from, longlong *to);
+int longlong2decimal(longlong from, decimal_t *to);
+int decimal2double(decimal_t *from, double *to);
+int double2decimal(double from, decimal_t *to);
+void decimal_optimize_fraction(decimal_t *from);
+int decimal2bin(decimal_t *from, char *to, int precision, int scale);
+int bin2decimal(char *from, decimal_t *to, int precision, int scale);
+
+int decimal_size(int precision, int scale);
+int decimal_bin_size(int precision, int scale);
+int decimal_result_size(decimal_t *from1, decimal_t *from2, char op,
+ int param);
+
+int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to);
+int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to);
+int decimal_cmp(decimal_t *from1, decimal_t *from2);
+int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to);
+int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to,
+ int scale_incr);
+int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to);
+int decimal_round(decimal_t *from, decimal_t *to, int new_scale,
+ decimal_round_mode mode);
+int decimal_is_zero(decimal_t *from);
+void max_decimal(int precision, int frac, decimal_t *to);
+
+#define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0)
+#define string2decimal_fixed(A,B,C) internal_str2dec((A), (B), (C), 1)
+
+/* set a decimal_t to zero */
+
+#define decimal_make_zero(dec) do { \
+ (dec)->buf[0]=0; \
+ (dec)->intg=1; \
+ (dec)->frac=0; \
+ (dec)->sign=0; \
+ } while(0)
+
+/*
+ returns the length of the buffer to hold string representation
+ of the decimal (including decimal dot, possible sign and \0)
+*/
+
+#define decimal_string_size(dec) (((dec)->intg ? (dec)->intg : 1) + \
+ (dec)->frac + ((dec)->frac > 0) + 2)
+
+/* negate a decimal */
+#define decimal_neg(dec) do { (dec)->sign^=1; } while(0)
+
+/*
+ conventions:
+
+ decimal_smth() == 0 -- everything's ok
+ decimal_smth() <= 1 -- result is usable, but precision loss is possible
+ decimal_smth() <= 2 -- result can be unusable, most significant digits
+ could've been lost
+ decimal_smth() > 2 -- no result was generated
+*/
+
+#define E_DEC_OK 0
+#define E_DEC_TRUNCATED 1
+#define E_DEC_OVERFLOW 2
+#define E_DEC_DIV_ZERO 4
+#define E_DEC_BAD_NUM 8
+#define E_DEC_OOM 16
+
+#define E_DEC_ERROR 31
+#define E_DEC_FATAL_ERROR 30
+
+#endif
+
diff --git a/include/errmsg.h b/include/errmsg.h
index 96977227666..ae3b04b4f3a 100644
--- a/include/errmsg.h
+++ b/include/errmsg.h
@@ -21,6 +21,7 @@
extern "C" {
#endif
void init_client_errs(void);
+void finish_client_errs(void);
extern const char *client_errors[]; /* Error messages */
#ifdef __cplusplus
}
@@ -35,6 +36,9 @@ extern const char *client_errors[]; /* Error messages */
#endif
#define CLIENT_ERRMAP 2 /* Errormap used by my_error() */
+/* Do not add error numbers before CR_ERROR_FIRST. */
+/* If necessary to add lower numbers, change CR_ERROR_FIRST accordingly. */
+#define CR_ERROR_FIRST 2000 /*Copy first error nr.*/
#define CR_UNKNOWN_ERROR 2000
#define CR_SOCKET_CREATE_ERROR 2001
#define CR_CONNECTION_ERROR 2002
@@ -91,3 +95,6 @@ extern const char *client_errors[]; /* Error messages */
#define CR_FETCH_CANCELED 2050
#define CR_NO_DATA 2051
#define CR_NO_STMT_METADATA 2052
+#define CR_ERROR_LAST /*Copy last error nr:*/ 2052
+/* Add error numbers before CR_ERROR_LAST and change it accordingly. */
+
diff --git a/include/m_ctype.h b/include/m_ctype.h
index aab39156de1..61524dc4ddd 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -85,7 +85,7 @@ enum my_lex_states
{
MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT,
MY_LEX_IDENT_SEP, MY_LEX_IDENT_START,
- MY_LEX_REAL, MY_LEX_HEX_NUMBER,
+ MY_LEX_REAL, MY_LEX_HEX_NUMBER, MY_LEX_BIN_NUMBER,
MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END,
MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL,
MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE,
@@ -106,9 +106,11 @@ typedef struct my_collation_handler_st
int (*strnncoll)(struct charset_info_st *,
const uchar *, uint, const uchar *, uint, my_bool);
int (*strnncollsp)(struct charset_info_st *,
- const uchar *, uint, const uchar *, uint);
+ const uchar *, uint, const uchar *, uint,
+ my_bool diff_if_only_endspace_difference);
int (*strnxfrm)(struct charset_info_st *,
uchar *, uint, const uchar *, uint);
+ uint (*strnxfrmlen)(struct charset_info_st *, uint);
my_bool (*like_range)(struct charset_info_st *,
const char *s, uint s_length,
pchar w_prefix, pchar w_one, pchar w_many,
@@ -185,7 +187,7 @@ typedef struct my_charset_handler_st
int base, char **e, int *err);
double (*strntod)(struct charset_info_st *, char *s, uint l, char **e,
int *err);
- longlong (*my_strtoll10)(struct charset_info_st *cs,
+ longlong (*strtoll10)(struct charset_info_st *cs,
const char *nptr, char **endptr, int *error);
ulong (*scan)(struct charset_info_st *, const char *b, const char *e,
int sq);
@@ -230,6 +232,10 @@ typedef struct charset_info_st
extern CHARSET_INFO my_charset_bin;
extern CHARSET_INFO my_charset_big5_chinese_ci;
extern CHARSET_INFO my_charset_big5_bin;
+extern CHARSET_INFO my_charset_cp932_japanese_ci;
+extern CHARSET_INFO my_charset_cp932_bin;
+extern CHARSET_INFO my_charset_eucjpms_japanese_ci;
+extern CHARSET_INFO my_charset_eucjpms_bin;
extern CHARSET_INFO my_charset_euckr_korean_ci;
extern CHARSET_INFO my_charset_euckr_bin;
extern CHARSET_INFO my_charset_gb2312_chinese_ci;
@@ -255,12 +261,14 @@ extern CHARSET_INFO my_charset_cp1250_czech_ci;
/* declarations for simple charsets */
extern int my_strnxfrm_simple(CHARSET_INFO *, uchar *, uint, const uchar *,
- uint);
+ uint);
+uint my_strnxfrmlen_simple(CHARSET_INFO *, uint);
extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, uint,
const uchar *, uint, my_bool);
extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, uint,
- const uchar *, uint);
+ const uchar *, uint,
+ my_bool diff_if_only_endspace_difference);
extern void my_hash_sort_simple(CHARSET_INFO *cs,
const uchar *key, uint len,
diff --git a/include/merge.h b/include/merge.h
deleted file mode 100644
index 97cea5fabb1..00000000000
--- a/include/merge.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright (C) 2000 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* This file should be included when using merge_isam_funktions */
-/* Author: Michael Widenius */
-
-#ifndef _merge_h
-#define _merge_h
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _my_base_h
-#include <my_base.h>
-#endif
-#ifndef _nisam_h
-#include <nisam.h>
-#endif
-
-#define MRG_NAME_EXT ".MRG"
-
- /* Param to/from mrg_info */
-
-typedef struct st_mrg_info /* Struct from h_info */
-{
- ulonglong records; /* Records in database */
- ulonglong deleted; /* Deleted records in database */
- ulonglong recpos; /* Pos for last used record */
- ulonglong data_file_length;
- uint reclength; /* Recordlength */
- int errkey; /* With key was dupplicated on err */
- uint options; /* HA_OPTION_... used */
-} MERGE_INFO;
-
-typedef struct st_mrg_table_info
-{
- N_INFO *table;
- ulonglong file_offset;
-} MRG_TABLE;
-
-typedef struct st_merge
-{
- MRG_TABLE *open_tables,*current_table,*end_table,*last_used_table;
- ulonglong records; /* records in tables */
- ulonglong del; /* Removed records */
- ulonglong data_file_length;
- uint tables,options,reclength;
- my_bool cache_in_use;
- LIST open_list;
-} MRG_INFO;
-
-typedef ulong mrg_off_t;
-
- /* Prototypes for merge-functions */
-
-extern int mrg_close(MRG_INFO *file);
-extern int mrg_delete(MRG_INFO *file,const byte *buff);
-extern MRG_INFO *mrg_open(const char *name,int mode,int wait_if_locked);
-extern int mrg_panic(enum ha_panic_function function);
-extern int mrg_rfirst(MRG_INFO *file,byte *buf,int inx);
-extern int mrg_rkey(MRG_INFO *file,byte *buf,int inx,const byte *key,
- uint key_len, enum ha_rkey_function search_flag);
-extern int mrg_rrnd(MRG_INFO *file,byte *buf, mrg_off_t pos);
-extern int mrg_rsame(MRG_INFO *file,byte *record,int inx);
-extern int mrg_update(MRG_INFO *file,const byte *old,const byte *new_rec);
-extern int mrg_info(MRG_INFO *file,MERGE_INFO *x,int flag);
-extern int mrg_lock_database(MRG_INFO *file,int lock_type);
-extern int mrg_create(const char *name,const char **table_names);
-extern int mrg_extra(MRG_INFO *file,enum ha_extra_function function);
-extern ha_rows mrg_records_in_range(MRG_INFO *info,int inx,
- const byte *start_key,uint start_key_len,
- enum ha_rkey_function start_search_flag,
- const byte *end_key,uint end_key_len,
- enum ha_rkey_function end_search_flag);
-
-extern mrg_off_t mrg_position(MRG_INFO *info);
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/include/my_base.h b/include/my_base.h
index d702ec45140..25fa683744e 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -146,7 +146,13 @@ enum ha_extra_function {
On-the-fly switching between unique and non-unique key inserting.
*/
HA_EXTRA_CHANGE_KEY_TO_UNIQUE,
- HA_EXTRA_CHANGE_KEY_TO_DUP
+ HA_EXTRA_CHANGE_KEY_TO_DUP,
+ /*
+ When using HA_EXTRA_KEYREAD, overwrite only key member fields and keep
+ other fields intact. When this is off (by default) InnoDB will use memcpy
+ to overwrite entire row.
+ */
+ HA_EXTRA_KEYREAD_PRESERVE_FIELDS
};
/* The following is parameter to ha_panic() */
@@ -175,8 +181,13 @@ enum ha_base_keytype {
HA_KEYTYPE_INT24=12,
HA_KEYTYPE_UINT24=13,
HA_KEYTYPE_INT8=14,
- HA_KEYTYPE_VARTEXT=15, /* Key is sorted as letters */
- HA_KEYTYPE_VARBINARY=16 /* Key is sorted as unsigned chars */
+ /* Varchar (0-255 bytes) with length packed with 1 byte */
+ HA_KEYTYPE_VARTEXT1=15, /* Key is sorted as letters */
+ HA_KEYTYPE_VARBINARY1=16, /* Key is sorted as unsigned chars */
+ /* Varchar (0-65535 bytes) with length packed with 2 bytes */
+ HA_KEYTYPE_VARTEXT2=17, /* Key is sorted as letters */
+ HA_KEYTYPE_VARBINARY2=18, /* Key is sorted as unsigned chars */
+ HA_KEYTYPE_BIT=19
};
#define HA_MAX_KEYTYPE 31 /* Must be log2-1 */
@@ -207,7 +218,7 @@ enum ha_base_keytype {
/*
Key has a part that can have end space. If this is an unique key
we have to handle it differently from other unique keys as we can find
- many matching rows for one key (becaue end space are not compared)
+ many matching rows for one key (because end space are not compared)
*/
#define HA_END_SPACE_KEY 4096
@@ -215,12 +226,18 @@ enum ha_base_keytype {
#define HA_SPACE_PACK 1 /* Pack space in key-seg */
#define HA_PART_KEY_SEG 4 /* Used by MySQL for part-key-cols */
-#define HA_VAR_LENGTH 8
+#define HA_VAR_LENGTH_PART 8
#define HA_NULL_PART 16
#define HA_BLOB_PART 32
#define HA_SWAP_KEY 64
#define HA_REVERSE_SORT 128 /* Sort key in reverse order */
#define HA_NO_SORT 256 /* do not bother sorting on this keyseg */
+/*
+ End space in unique/varchar are considered equal. (Like 'a' and 'a ')
+ Only needed for internal temporary tables.
+*/
+#define HA_END_SPACE_ARE_EQUAL 512
+#define HA_BIT_PART 1024
/* optionbits for database */
#define HA_OPTION_PACK_RECORD 1
@@ -256,6 +273,9 @@ enum ha_base_keytype {
/* Errorcodes given by functions */
/* opt_sum_query() assumes these codes are > 1 */
+/* Do not add error numbers before HA_ERR_FIRST. */
+/* If necessary to add lower numbers, change HA_ERR_FIRST accordingly. */
+#define HA_ERR_FIRST 120 /*Copy first error nr.*/
#define HA_ERR_KEY_NOT_FOUND 120 /* Didn't find key on read or update */
#define HA_ERR_FOUND_DUPP_KEY 121 /* Dupplicate key on write */
#define HA_ERR_RECORD_CHANGED 123 /* Uppdate with is recoverable */
@@ -292,6 +312,11 @@ enum ha_base_keytype {
#define HA_ERR_TABLE_EXIST 156 /* The table existed in storage engine */
#define HA_ERR_NO_CONNECTION 157 /* Could not connect to storage engine */
#define HA_ERR_NULL_IN_SPATIAL 158 /* NULLs are not supported in spatial index */
+#define HA_ERR_TABLE_DEF_CHANGED 159 /* The table changed in storage engine */
+
+#define HA_ERR_LAST 159 /*Copy last error nr.*/
+/* Add error numbers before HA_ERR_LAST and change it accordingly. */
+#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
/* Other constants */
@@ -354,6 +379,15 @@ enum data_file_type {
/* For key ranges */
+#define NO_MIN_RANGE 1
+#define NO_MAX_RANGE 2
+#define NEAR_MIN 4
+#define NEAR_MAX 8
+#define UNIQUE_RANGE 16
+#define EQ_RANGE 32
+#define NULL_RANGE 64
+#define GEOM_FLAG 128
+
typedef struct st_key_range
{
const byte *key;
@@ -361,6 +395,14 @@ typedef struct st_key_range
enum ha_rkey_function flag;
} key_range;
+typedef struct st_key_multi_range
+{
+ key_range start_key;
+ key_range end_key;
+ char *ptr; /* Free to use by caller (ptr to row etc) */
+ uint range_flag; /* key range flags see above */
+} KEY_MULTI_RANGE;
+
/* For number of records */
#ifdef BIG_TABLES
@@ -380,4 +422,6 @@ typedef ulong ha_rows;
#define MAX_FILE_SIZE LONGLONG_MAX
#endif
+#define HA_VARCHAR_PACKLENGTH(field_length) ((field_length) < 256 ? 1 :2)
+
#endif /* _my_base_h */
diff --git a/include/my_bitmap.h b/include/my_bitmap.h
index a4511bf3414..4caa3b85456 100644
--- a/include/my_bitmap.h
+++ b/include/my_bitmap.h
@@ -24,7 +24,7 @@
typedef struct st_bitmap
{
uchar *bitmap;
- uint bitmap_size;
+ uint bitmap_size; /* number of bytes occupied by the above */
/*
mutex will be acquired for the duration of each bitmap operation if
thread_safe flag in bitmap_init was set. Otherwise, we optimize by not
@@ -46,6 +46,8 @@ 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 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);
extern void bitmap_clear_all(MY_BITMAP *map);
extern void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit);
extern void bitmap_free(MY_BITMAP *map);
diff --git a/include/my_dbug.h b/include/my_dbug.h
index 711ece4335c..cf32102b34b 100644
--- a/include/my_dbug.h
+++ b/include/my_dbug.h
@@ -25,6 +25,7 @@ extern int _db_on_,_no_db_;
extern FILE *_db_fp_;
extern char *_db_process_;
extern int _db_keyword_(const char *keyword);
+extern int _db_strict_keyword_(const char *keyword);
extern void _db_setjmp_(void);
extern void _db_longjmp_(void);
extern void _db_push_(const char *control);
@@ -69,12 +70,15 @@ extern void _db_unlock_file();
#define DBUG_UNLOCK_FILE { _db_unlock_file(); }
#define DBUG_OUTPUT(A) { _db_output_(A); }
#define DBUG_ASSERT(A) assert(A)
+#define DBUG_EXECUTE_IF(keyword,a1) \
+ {if (_db_on_) {if (_db_strict_keyword_ (keyword)) { a1 }}}
#else /* No debugger */
#define DBUG_ENTER(a1)
#define DBUG_RETURN(a1) return(a1)
#define DBUG_VOID_RETURN return
#define DBUG_EXECUTE(keyword,a1) {}
+#define DBUG_EXECUTE_IF(keyword,a1) {}
#define DBUG_PRINT(keyword,arglist) {}
#define DBUG_PUSH(a1) {}
#define DBUG_POP() {}
diff --git a/include/my_global.h b/include/my_global.h
index bf6f3b52c4b..e816d52cc71 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -121,6 +121,38 @@
#define __STDC_EXT__ 1 /* To get large file support on hpux */
#endif
+/*
+ Solaris 9 include file <sys/feature_tests.h> refers to X/Open document
+
+ System Interfaces and Headers, Issue 5
+
+ saying we should define _XOPEN_SOURCE=500 to get POSIX.1c prototypes,
+ but apparently other systems (namely FreeBSD) don't agree.
+
+ On a newer Solaris 10, the above file recognizes also _XOPEN_SOURCE=600.
+ Furthermore, it tests that if a program requires older standard
+ (_XOPEN_SOURCE<600 or _POSIX_C_SOURCE<200112L) it cannot be
+ run on a new compiler (that defines _STDC_C99) and issues an #error.
+ It's also an #error if a program requires new standard (_XOPEN_SOURCE=600
+ or _POSIX_C_SOURCE=200112L) and a compiler does not define _STDC_C99.
+
+ To add more to this mess, Sun Studio C compiler defines _STDC_C99 while
+ C++ compiler does not!
+
+ So, in a desperate attempt to get correct prototypes for both
+ C and C++ code, we define either _XOPEN_SOURCE=600 or _XOPEN_SOURCE=500
+ depending on the compiler's announced C standard support.
+
+ Cleaner solutions are welcome.
+*/
+#ifdef __sun
+#if __STDC_VERSION__ - 0 >= 199901L
+#define _XOPEN_SOURCE 600
+#else
+#define _XOPEN_SOURCE 500
+#endif
+#endif
+
#if defined(THREAD) && !defined(__WIN__) && !defined(OS2)
#ifndef _POSIX_PTHREAD_SEMANTICS
#define _POSIX_PTHREAD_SEMANTICS /* We want posix threads */
@@ -677,6 +709,7 @@ typedef SOCKET_SIZE_TYPE size_socket;
#define UINT_MAX16 0xFFFF
#define INT_MIN8 (~0x7F)
#define INT_MAX8 0x7F
+#define UINT_MAX8 0xFF
/* From limits.h instead */
#ifndef DBL_MIN
@@ -692,6 +725,17 @@ typedef SOCKET_SIZE_TYPE size_socket;
#define isinf(X) 0
#endif
+/* Define missing math constants. */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_E
+#define M_E 2.7182818284590452354
+#endif
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+
/*
Max size that must be added to a so that we know Size to make
adressable obj.
@@ -755,7 +799,7 @@ typedef long int32;
#endif
typedef unsigned long uint32; /* Short for unsigned integer >= 32 bits */
#else
-error "Neither int or long is of 4 bytes width"
+#error "Neither int or long is of 4 bytes width"
#endif
#if !defined(HAVE_ULONG) && !defined(TARGET_OS_LINUX) && !defined(__USE_MISC)
diff --git a/include/my_handler.h b/include/my_handler.h
index 18a6234d3f6..cad15d5471f 100644
--- a/include/my_handler.h
+++ b/include/my_handler.h
@@ -25,15 +25,17 @@
typedef struct st_HA_KEYSEG /* Key-portion */
{
+ CHARSET_INFO *charset;
+ uint32 start; /* Start of key in record */
+ uint32 null_pos; /* position to NULL indicator */
+ uint16 bit_pos; /* Position to bit part */
+ uint16 flag;
+ uint16 length; /* Keylength */
uint8 type; /* Type of key (for sort) */
uint8 language;
uint8 null_bit; /* bitmask to test for NULL */
uint8 bit_start,bit_end; /* if bit field */
- uint16 flag;
- uint16 length; /* Keylength */
- uint32 start; /* Start of key in record */
- uint32 null_pos; /* position to NULL indicator */
- CHARSET_INFO *charset;
+ uint8 bit_length; /* Length of bit part */
} HA_KEYSEG;
#define get_key_length(length,key) \
@@ -57,6 +59,28 @@ typedef struct st_HA_KEYSEG /* Key-portion */
{ length=mi_uint2korr((key)+1); (key)+=3; length_pack=3; } \
}
+#define store_key_length_inc(key,length) \
+{ if ((length) < 255) \
+ { *(key)++=(length); } \
+ else \
+ { *(key)=255; mi_int2store((key)+1,(length)); (key)+=3; } \
+}
+
+#define get_rec_bits(bit_ptr, bit_ofs, bit_len) \
+ (((((uint16) (bit_ptr)[1] << 8) | (uint16) (bit_ptr)[0]) >> (bit_ofs)) & \
+ ((1 << (bit_len)) - 1))
+
+#define set_rec_bits(bits, bit_ptr, bit_ofs, bit_len) \
+{ \
+ (bit_ptr)[0]= ((bit_ptr)[0] & ((1 << (bit_ofs)) - 1)) | \
+ ((bits) << (bit_ofs)); \
+ if ((bit_ofs) + (bit_len) > 8) \
+ (bit_ptr)[1]= ((bits) & ((1 << (bit_len)) - 1)) >> (8 - (bit_ofs)); \
+}
+
+#define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \
+ set_rec_bits(0, bit_ptr, bit_ofs, bit_len)
+
extern int mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
my_bool, my_bool);
extern int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
diff --git a/include/my_net.h b/include/my_net.h
index 7b42afa1f3a..71914964e46 100644
--- a/include/my_net.h
+++ b/include/my_net.h
@@ -72,6 +72,11 @@ C_MODE_START
#define in_addr_t uint32
#endif
+/* On some operating systems (e.g. Solaris) INADDR_NONE is not defined */
+#ifndef INADDR_NONE
+#define INADDR_NONE -1 /* Error value from inet_addr */
+#endif
+
/* Thread safe or portable version of some functions */
void my_inet_ntoa(struct in_addr in, char *buf);
diff --git a/include/my_pthread.h b/include/my_pthread.h
index fde62655c5f..47a38d1a642 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -676,21 +676,25 @@ extern pthread_t shutdown_th, main_th, signal_th;
#ifndef thread_safe_increment
#ifdef HAVE_ATOMIC_ADD
-#define thread_safe_increment(V,L) atomic_add(1,(atomic_t*) &V);
-#define thread_safe_add(V,C,L) atomic_add((C),(atomic_t*) &V);
-#define thread_safe_sub(V,C,L) atomic_sub((C),(atomic_t*) &V);
+#define thread_safe_increment(V,L) atomic_inc((atomic_t*) &V)
+#define thread_safe_decrement(V,L) atomic_dec((atomic_t*) &V)
+#define thread_safe_add(V,C,L) atomic_add((C),(atomic_t*) &V)
+#define thread_safe_sub(V,C,L) atomic_sub((C),(atomic_t*) &V)
#else
#define thread_safe_increment(V,L) \
- pthread_mutex_lock((L)); (V)++; pthread_mutex_unlock((L));
-#define thread_safe_add(V,C,L) \
- pthread_mutex_lock((L)); (V)+=(C); pthread_mutex_unlock((L));
+ (pthread_mutex_lock((L)), (V)++, pthread_mutex_unlock((L)))
+#define thread_safe_decrement(V,L) \
+ (pthread_mutex_lock((L)), (V)--, pthread_mutex_unlock((L)))
+#define thread_safe_add(V,C,L) (pthread_mutex_lock((L)), (V)+=(C), pthread_mutex_unlock((L)))
#define thread_safe_sub(V,C,L) \
- pthread_mutex_lock((L)); (V)-=(C); pthread_mutex_unlock((L));
+ (pthread_mutex_lock((L)), (V)-=(C), pthread_mutex_unlock((L)))
#endif /* HAVE_ATOMIC_ADD */
#ifdef SAFE_STATISTICS
#define statistic_increment(V,L) thread_safe_increment((V),(L))
+#define statistic_decrement(V,L) thread_safe_decrement((V),(L))
#define statistic_add(V,C,L) thread_safe_add((V),(C),(L))
#else
+#define statistic_decrement(V,L) (V)--
#define statistic_increment(V,L) (V)++
#define statistic_add(V,C,L) (V)+=(C)
#endif /* SAFE_STATISTICS */
diff --git a/include/my_sys.h b/include/my_sys.h
index 7ead643a9c6..e2f9444c52a 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -43,8 +43,6 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MYSYS_PROGRAM_DONT_USE_CURSES() { error_handler_hook = my_message_no_curses; mysys_uses_curses=0;}
#define MY_INIT(name); { my_progname= name; my_init(); }
-#define MAXMAPS (4) /* Number of error message maps */
-#define ERRMOD (1000) /* Max number of errors in a map */
#define ERRMSGSIZE (SC_MAXWIDTH) /* Max length of a error message */
#define NRERRBUFFS (2) /* Buffers for parameters */
#define MY_FILE_ERROR ((uint) ~0)
@@ -56,11 +54,10 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_FAE 8 /* Fatal if any error */
#define MY_WME 16 /* Write message on error */
#define MY_WAIT_IF_FULL 32 /* Wait and try again if disk full error */
-#define MY_RAID 64 /* Support for RAID (not the "Johnson&Johnson"-s one ;) */
-#define MY_FULL_IO 512 /* For my_read - loop intil I/O
- is complete
- */
-#define MY_DONT_CHECK_FILESIZE 128 /* Option to init_io_cache() */
+#define MY_IGNORE_BADFD 32 /* my_sync: ignore 'bad descriptor' errors */
+#define MY_RAID 64 /* Support for RAID */
+#define MY_FULL_IO 512 /* For my_read - loop intil I/O is complete */
+#define MY_DONT_CHECK_FILESIZE 128 /* Option to init_io_cache() */
#define MY_LINK_WARNING 32 /* my_redel() gives warning if links */
#define MY_COPYTIME 64 /* my_redel() copys time */
#define MY_DELETE_OLD 256 /* my_create_with_symlink() */
@@ -74,7 +71,7 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */
#define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */
#define MY_THREADSAFE 128 /* pread/pwrite: Don't allow interrupts */
-#define MY_DONT_OVERWRITE_FILE 1024 /* my_copy; Don't overwrite file */
+#define MY_DONT_OVERWRITE_FILE 1024 /* my_copy: Don't overwrite file */
#define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */
#define MY_GIVE_INFO 2 /* Give time info about process*/
@@ -121,6 +118,13 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_ERRNO_EDOM 33
#define MY_ERRNO_ERANGE 34
+ /* Bits for get_date timeflag */
+#define GETDATE_DATE_TIME 1
+#define GETDATE_SHORT_DATE 2
+#define GETDATE_HHMMSSTIME 4
+#define GETDATE_GMT 8
+#define GETDATE_FIXEDLENGTH 16
+
/* defines when allocating data */
#ifdef SAFEMALLOC
#define my_malloc(SZ,FLAG) _mymalloc((SZ), __FILE__, __LINE__, FLAG )
@@ -131,6 +135,7 @@ extern int NEAR my_errno; /* Last error in mysys */
#define my_memdup(A,B,C) _my_memdup((A),(B), __FILE__,__LINE__,C)
#define my_strdup(A,C) _my_strdup((A), __FILE__,__LINE__,C)
#define my_strdup_with_length(A,B,C) _my_strdup_with_length((A),(B),__FILE__,__LINE__,C)
+#define TRASH(A,B) bfill(A, B, 0x8F)
#define QUICK_SAFEMALLOC sf_malloc_quick=1
#define NORMAL_SAFEMALLOC sf_malloc_quick=0
extern uint sf_malloc_prehunc,sf_malloc_endhunc,sf_malloc_quick;
@@ -157,8 +162,19 @@ extern char *my_strdup_with_length(const byte *from, uint length,
#define CALLER_INFO_PROTO /* nothing */
#define CALLER_INFO /* nothing */
#define ORIG_CALLER_INFO /* nothing */
+#define TRASH(A,B) /* nothing */
#endif
+#ifdef HAVE_LARGE_PAGES
+extern uint my_get_large_page_size(void);
+extern gptr my_large_malloc(uint size, myf my_flags);
+extern void my_large_free(gptr ptr, myf my_flags);
+#else
+#define my_get_large_page_size() (0)
+#define my_large_malloc(A,B) my_malloc_lock((A),(B))
+#define my_large_free(A,B) my_free_lock((A),(B))
+#endif /* HAVE_LARGE_PAGES */
+
#ifdef HAVE_ALLOCA
#if defined(_AIX) && !defined(__GNUC__) && !defined(_AIX43)
#pragma alloca
@@ -196,7 +212,6 @@ void __CDECL hfree(void *ptr);
extern int errno; /* declare errno */
#endif
#endif /* #ifndef errno */
-extern const char ** NEAR my_errmsg[];
extern char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
extern char *home_dir; /* Home directory for user */
extern char *my_progname; /* program-name (printed in errors) */
@@ -206,6 +221,11 @@ extern int (*fatal_error_handler_hook)(uint my_err, const char *str,
myf MyFlags);
extern uint my_file_limit;
+#ifdef HAVE_LARGE_PAGES
+extern my_bool my_use_large_pages;
+extern uint my_large_page_size;
+#endif
+
/* charsets */
extern CHARSET_INFO *default_charset_info;
extern CHARSET_INFO *all_charsets[256];
@@ -240,6 +260,8 @@ extern char wild_many,wild_one,wild_prefix;
extern const char *charsets_dir;
extern char *defaults_extra_file;
+extern my_bool timed_mutexes;
+
typedef struct wild_file_pack /* Struct to hold info when selecting files */
{
uint wilds; /* How many wildcards */
@@ -501,12 +523,17 @@ typedef int (*qsort2_cmp)(const void *, const void *, const void *);
/* tell write offset in the SEQ_APPEND cache */
my_off_t my_b_append_tell(IO_CACHE* info);
+my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */
#define my_b_bytes_in_cache(info) (uint) (*(info)->current_end - \
*(info)->current_pos)
typedef uint32 ha_checksum;
+/* Define the type of function to be passed to process_default_option_files */
+typedef int (*Process_option_func)(void *ctx, const char *group_name,
+ const char *option);
+
#include <my_alloc.h>
/* Prototypes for mysys and my_func functions */
@@ -583,6 +610,8 @@ extern int my_error _VARARGS((int nr,myf MyFlags, ...));
extern int my_printf_error _VARARGS((uint my_err, const char *format,
myf MyFlags, ...)
__attribute__ ((format (printf, 2, 4))));
+extern int my_error_register(const char **errmsgs, int first, int last);
+extern const char **my_error_unregister(int first, int last);
extern int my_message(uint my_err, const char *str,myf MyFlags);
extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags);
extern int my_message_curses(uint my_err, const char *str,myf MyFlags);
@@ -655,6 +684,8 @@ extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements,
extern qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size,
qsort2_cmp cmp, void *cmp_argument);
extern qsort2_cmp get_ptr_compare(uint);
+void my_store_ptr(byte *buff, uint pack_length, my_off_t pos);
+my_off_t my_get_ptr(byte *ptr, uint pack_length);
extern int init_io_cache(IO_CACHE *info,File file,uint cachesize,
enum cache_type type,my_off_t seek_offset,
pbool use_async_io, myf cache_myflags);
@@ -700,7 +731,8 @@ File create_temp_file(char *to, const char *dir, const char *pfx,
#define my_init_dynamic_array(A,B,C,D) init_dynamic_array(A,B,C,D CALLER_INFO)
#define my_init_dynamic_array_ci(A,B,C,D) init_dynamic_array(A,B,C,D ORIG_CALLER_INFO)
extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size,
- uint init_alloc,uint alloc_increment CALLER_INFO_PROTO);
+ uint init_alloc,uint alloc_increment
+ CALLER_INFO_PROTO);
extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,gptr element);
extern byte *alloc_dynamic(DYNAMIC_ARRAY *array);
extern byte *pop_dynamic(DYNAMIC_ARRAY*);
@@ -746,6 +778,9 @@ extern void get_defaults_files(int argc, char **argv,
char **defaults, char **extra_defaults);
extern int load_defaults(const char *conf_file, const char **groups,
int *argc, char ***argv);
+extern int my_search_option_files(const char *conf_file, int *argc,
+ char ***argv, uint *args_used,
+ Process_option_func func, void *func_ctx);
extern void free_defaults(char **argv);
extern void print_defaults(const char *conf_file, const char **groups);
extern my_bool my_compress(byte *, ulong *, ulong *);
@@ -754,6 +789,7 @@ extern byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen);
extern ha_checksum my_checksum(ha_checksum crc, const byte *mem, uint count);
extern uint my_bit_log2(ulong value);
extern uint my_count_bits(ulonglong v);
+extern uint my_count_bits_ushort(ushort v);
extern void my_sleep(ulong m_seconds);
extern ulong crc32(ulong crc, const uchar *buf, uint len);
extern uint my_set_max_open_files(uint files);
@@ -762,6 +798,39 @@ void my_free_open_file_info(void);
ulonglong my_getsystime(void);
my_bool my_gethwaddr(uchar *to);
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+
+#ifndef MAP_NOSYNC
+#define MAP_NOSYNC 0
+#endif
+
+#define my_mmap(a,b,c,d,e,f) mmap(a,b,c,d,e,f)
+#ifdef HAVE_GETPAGESIZE
+#define my_getpagesize() getpagesize()
+#else
+/* qnx ? */
+#define my_getpagesize() 8192
+#endif
+#define my_munmap(a,b) munmap((a),(b))
+
+#else
+/* not a complete set of mmap() flags, but only those that nesessary */
+#define PROT_READ 1
+#define PROT_WRITE 2
+#define MAP_SHARED 0x0001
+#define MAP_NOSYNC 0x0800
+#define MAP_FAILED ((void *)-1)
+#define MS_SYNC 0x0000
+#define HAVE_MMAP
+
+int my_getpagesize(void);
+void *my_mmap(void *, size_t, int, int, int, my_off_t);
+int my_munmap(void *, size_t);
+#endif
+
+int my_msync(int, void *, size_t, int);
+
/* character sets */
extern uint get_charset_number(const char *cs_name, uint cs_flags);
extern uint get_collation_number(const char *name);
@@ -776,9 +845,14 @@ extern char *get_charsets_dir(char *buf);
extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2);
extern my_bool init_compiled_charsets(myf flags);
extern void add_compiled_collation(CHARSET_INFO *cs);
-extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to,
+extern ulong escape_string_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);
+extern void thd_increment_net_big_packet_count(ulong length);
+
#ifdef __WIN__
extern my_bool have_tcpip; /* Is set if tcpip is used */
diff --git a/include/my_time.h b/include/my_time.h
index 94701e159c4..8058df8fe4e 100644
--- a/include/my_time.h
+++ b/include/my_time.h
@@ -41,17 +41,30 @@ typedef long my_time_t;
#define YY_PART_YEAR 70
/* Flags to str_to_datetime */
-#define TIME_FUZZY_DATE 1
-#define TIME_DATETIME_ONLY 2
+#define TIME_FUZZY_DATE 1
+#define TIME_DATETIME_ONLY 2
+/* Must be same as MODE_NO_ZERO_IN_DATE */
+#define TIME_NO_ZERO_IN_DATE (65536L*2*2*2*2*2*2*2)
+/* Must be same as MODE_NO_ZERO_DATE */
+#define TIME_NO_ZERO_DATE (TIME_NO_ZERO_IN_DATE*2)
+#define TIME_INVALID_DATES (TIME_NO_ZERO_DATE*2)
enum enum_mysql_timestamp_type
str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
uint flags, int *was_cut);
+longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res,
+ my_bool fuzzy_date, int *was_cut);
+ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *time);
+ulonglong TIME_to_ulonglong_date(const MYSQL_TIME *time);
+ulonglong TIME_to_ulonglong_time(const MYSQL_TIME *time);
+ulonglong TIME_to_ulonglong(const MYSQL_TIME *time);
+
bool str_to_time(const char *str,uint length, MYSQL_TIME *l_time,
int *was_cut);
long calc_daynr(uint year,uint month,uint day);
+uint calc_days_in_year(uint year);
void init_time(void);
diff --git a/include/myisam.h b/include/myisam.h
index 6d097770646..e0eb8715aef 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -107,12 +107,13 @@ typedef struct st_mi_create_info
} MI_CREATE_INFO;
struct st_myisam_info; /* For referense */
+struct st_mi_isam_share;
typedef struct st_myisam_info MI_INFO;
-
struct st_mi_s_param;
typedef struct st_mi_keydef /* Key definition with open & info */
{
+ struct st_mi_isam_share *share; /* Pointer to base (set in mi_open) */
uint16 keysegs; /* Number of key-segment */
uint16 flag; /* NOSAME, PACK_USED */
@@ -339,8 +340,8 @@ typedef struct st_mi_check_param
ha_checksum key_crc[MI_MAX_POSSIBLE_KEY];
ulong rec_per_key_part[MI_MAX_KEY_SEG*MI_MAX_POSSIBLE_KEY];
void *thd;
- char *db_name,*table_name;
- char *op_name;
+ const char *db_name, *table_name;
+ const char *op_name;
} MI_CHECK;
typedef struct st_sort_ft_buf
diff --git a/include/mysql.h b/include/mysql.h
index d8a56126756..24f1961a260 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -145,7 +145,8 @@ enum mysql_option
MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT,
MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT,
MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
- MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH
+ MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
+ MYSQL_REPORT_DATA_TRUNCATION
};
struct st_mysql_options {
@@ -186,6 +187,8 @@ struct st_mysql_options {
char *client_ip;
/* Refuse client connecting to server if it uses old (pre-4.1.1) protocol */
my_bool secure_auth;
+ /* 0 - never report, 1 - always report (default) */
+ my_bool report_data_truncation;
/* function pointers for local infile support */
int (*local_infile_init)(void **, const char *, void *);
@@ -228,7 +231,7 @@ typedef struct st_mysql
MEM_ROOT field_alloc;
my_ulonglong affected_rows;
my_ulonglong insert_id; /* id if insert on table with NEXTNR */
- my_ulonglong extra_info; /* Used by mysqlshow */
+ my_ulonglong extra_info; /* Not used */
unsigned long thread_id; /* Id for connection in server */
unsigned long packet_length;
unsigned int port;
@@ -548,26 +551,91 @@ enum enum_mysql_stmt_state
};
-/* bind structure */
+/*
+ This structure is used to define bind information, and
+ internally by the client library.
+ Public members with their descriptions are listed below
+ (conventionally `On input' refers to the binds given to
+ mysql_stmt_bind_param, `On output' refers to the binds given
+ to mysql_stmt_bind_result):
+
+ buffer_type - One of the MYSQL_* types, used to describe
+ the host language type of buffer.
+ On output: if column type is different from
+ buffer_type, column value is automatically converted
+ to buffer_type before it is stored in the buffer.
+ buffer - On input: points to the buffer with input data.
+ On output: points to the buffer capable to store
+ output data.
+ The type of memory pointed by buffer must correspond
+ to buffer_type. See the correspondence table in
+ the comment to mysql_stmt_bind_param.
+
+ The two above members are mandatory for any kind of bind.
+
+ buffer_length - the length of the buffer. You don't have to set
+ it for any fixed length buffer: float, double,
+ int, etc. It must be set however for variable-length
+ types, such as BLOBs or STRINGs.
+
+ length - On input: in case when lengths of input values
+ are different for each execute, you can set this to
+ point at a variable containining value length. This
+ way the value length can be different in each execute.
+ If length is not NULL, buffer_length is not used.
+ Note, length can even point at buffer_length if
+ you keep bind structures around while fetching:
+ this way you can change buffer_length before
+ each execution, everything will work ok.
+ On output: if length is set, mysql_stmt_fetch will
+ write column length into it.
+
+ is_null - On input: points to a boolean variable that should
+ be set to TRUE for NULL values.
+ This member is useful only if your data may be
+ NULL in some but not all cases.
+ If your data is never NULL, is_null should be set to 0.
+ If your data is always NULL, set buffer_type
+ to MYSQL_TYPE_NULL, and is_null will not be used.
+
+ is_unsigned - On input: used to signify that values provided for one
+ of numeric types are unsigned.
+ On output describes signedness of the output buffer.
+ If, taking into account is_unsigned flag, column data
+ is out of range of the output buffer, data for this column
+ is regarded truncated. Note that this has no correspondence
+ to the sign of result set column, if you need to find it out
+ use mysql_stmt_result_metadata.
+ error - where to write a truncation error if it is present.
+ possible error value is:
+ 0 no truncation
+ 1 value is out of range or buffer is too small
+
+ Please note that MYSQL_BIND also has internals members.
+*/
+
typedef struct st_mysql_bind
{
unsigned long *length; /* output length pointer */
my_bool *is_null; /* Pointer to null indicator */
void *buffer; /* buffer to get/put data */
+ /* set this if you want to track data truncations happened during fetch */
+ my_bool *error;
enum enum_field_types buffer_type; /* buffer type */
- unsigned long buffer_length; /* buffer length, must be set for str/binary */
-
- /* Following are for internal use. Set by mysql_stmt_bind_param */
- unsigned char *inter_buffer; /* for the current data position */
+ /* output buffer length, must be set when fetching str/binary */
+ unsigned long buffer_length;
+ unsigned char *row_ptr; /* for the current data position */
unsigned long offset; /* offset position for char/binary fetch */
- unsigned long internal_length; /* Used if length is 0 */
+ unsigned long length_value; /* Used if length is 0 */
unsigned int param_number; /* For null count and error messages */
unsigned int pack_length; /* Internal length for packed data */
+ my_bool error_value; /* used if error is 0 */
my_bool is_unsigned; /* set if integer type is unsigned */
my_bool long_data_used; /* If used with mysql_send_long_data */
- my_bool internal_is_null; /* Used if is_null is 0 */
+ my_bool is_null_value; /* Used if is_null is 0 */
void (*store_param_func)(NET *net, struct st_mysql_bind *param);
- void (*fetch_result)(struct st_mysql_bind *, unsigned char **row);
+ void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *,
+ unsigned char **row);
void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *,
unsigned char **row);
} MYSQL_BIND;
@@ -594,6 +662,12 @@ typedef struct st_mysql_stmt
int (*read_row_func)(struct st_mysql_stmt *stmt,
unsigned char **row);
unsigned long stmt_id; /* Id for prepared statement */
+ unsigned long flags; /* i.e. type of cursor to open */
+ /*
+ Copied from mysql->server_status after execute/fetch to know
+ server-side cursor status for this statement.
+ */
+ unsigned int server_status;
unsigned int last_errno; /* error code */
unsigned int param_count; /* input parameter count */
unsigned int field_count; /* number of columns in result set */
@@ -603,7 +677,7 @@ typedef struct st_mysql_stmt
/* Types of input parameters should be sent to server */
my_bool send_types_to_server;
my_bool bind_param_done; /* input buffers were supplied */
- my_bool bind_result_done; /* output buffers were supplied */
+ unsigned char bind_result_done; /* output buffers were supplied */
/* mysql_stmt_close() had to cancel this result */
my_bool unbuffered_fetch_cancelled;
/*
@@ -622,7 +696,12 @@ enum enum_stmt_attr_type
In the new API we do that only by request because it slows down
mysql_stmt_store_result sufficiently.
*/
- STMT_ATTR_UPDATE_MAX_LENGTH
+ STMT_ATTR_UPDATE_MAX_LENGTH,
+ /*
+ unsigned long with combination of cursor flags (read only, for update,
+ etc)
+ */
+ STMT_ATTR_CURSOR_TYPE
};
@@ -704,7 +783,8 @@ void STDCALL mysql_close(MYSQL *sock);
/* status return codes */
-#define MYSQL_NO_DATA 100
+#define MYSQL_NO_DATA 100
+#define MYSQL_DATA_TRUNCATED 101
#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 56c7f7d2ab5..5a7b99fc3d8 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -36,6 +36,11 @@
#define MYSQL_SERVICENAME "MySQL"
#endif /* __WIN__ */
+/*
+ You should add new commands to the end of this list, otherwise old
+ servers won't be able to handle them as 'unsupported'.
+*/
+
enum enum_server_command
{
COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST,
@@ -44,7 +49,7 @@ enum enum_server_command
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_RESET_STMT, COM_SET_OPTION, COM_FETCH,
/* don't forget to update const char *command_name[] in sql_parse.cc */
/* Must be last */
@@ -77,6 +82,7 @@ enum enum_server_command
#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */
#define TIMESTAMP_FLAG 1024 /* Field is a timestamp */
#define SET_FLAG 2048 /* field is a set */
+#define NO_DEFAULT_VALUE_FLAG 4096 /* Field doesn't have default value */
#define NUM_FLAG 32768 /* Field is num (for clients) */
#define PART_KEY_FLAG 16384 /* Intern; Part of some key */
#define GROUP_FLAG 32768 /* Intern: Group field */
@@ -130,6 +136,17 @@ enum enum_server_command
#define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */
#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.
+*/
+#define SERVER_STATUS_CURSOR_EXISTS 64
+/*
+ This flag is sent with last row of read-only cursor, in reply to
+ COM_FETCH command.
+*/
+#define SERVER_STATUS_LAST_ROW_SENT 128
#define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */
#define MYSQL_ERRMSG_SIZE 512
@@ -137,6 +154,8 @@ enum enum_server_command
#define NET_WRITE_TIMEOUT 60 /* Timeout on write */
#define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */
+#define ONLY_KILL_QUERY 1
+
struct st_vio; /* Only C */
typedef struct st_vio Vio;
@@ -167,7 +186,13 @@ typedef struct st_net {
unsigned int *return_status;
unsigned char reading_or_writing;
char save_char;
- my_bool no_send_ok;
+ my_bool no_send_ok; /* For SPs and other things that do multiple stmts */
+ my_bool no_send_eof; /* For SPs' first version read-only cursors */
+ /*
+ Set if OK packet is already sent, and we do not need to send error
+ messages
+ */
+ my_bool no_send_error;
/*
Pointer to query object in query cache, do not equal NULL (0) for
queries in cache that have not stored its results yet
@@ -190,7 +215,9 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24,
MYSQL_TYPE_DATE, MYSQL_TYPE_TIME,
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
- MYSQL_TYPE_NEWDATE,
+ MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ MYSQL_TYPE_BIT,
+ MYSQL_TYPE_NEWDECIMAL=246,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
MYSQL_TYPE_TINY_BLOB=249,
@@ -206,6 +233,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
/* For backward compatibility */
#define CLIENT_MULTI_QUERIES CLIENT_MULTI_STATEMENTS
#define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL
+#define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL
#define FIELD_TYPE_TINY MYSQL_TYPE_TINY
#define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT
#define FIELD_TYPE_LONG MYSQL_TYPE_LONG
@@ -231,6 +259,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
#define FIELD_TYPE_CHAR MYSQL_TYPE_TINY
#define FIELD_TYPE_INTERVAL MYSQL_TYPE_ENUM
#define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY
+#define FIELD_TYPE_BIT MYSQL_TYPE_BIT
/* Shutdown/kill enums and constants */
@@ -265,6 +294,16 @@ enum mysql_enum_shutdown_level {
KILL_CONNECTION= 255
};
+
+enum enum_cursor_type
+{
+ CURSOR_TYPE_NO_CURSOR= 0,
+ CURSOR_TYPE_READ_ONLY= 1,
+ CURSOR_TYPE_FOR_UPDATE= 2,
+ CURSOR_TYPE_SCROLLABLE= 4
+};
+
+
/* options for mysql_set_option */
enum enum_mysql_set_option
{
@@ -310,7 +349,8 @@ struct rand_struct {
/* The following is for user defined functions */
-enum Item_result {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT};
+enum Item_result {STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT,
+ DECIMAL_RESULT};
typedef struct st_udf_args
{
@@ -319,6 +359,8 @@ typedef struct st_udf_args
char **args; /* Pointer to argument */
unsigned long *lengths; /* Length of string arguments */
char *maybe_null; /* Set to 1 for all maybe_null args */
+ char **attributes; /* Pointer to attribute name */
+ unsigned long *attribute_lengths; /* Length of attribute arguments */
} UDF_ARGS;
/* This holds information about the result */
diff --git a/include/mysql_embed.h b/include/mysql_embed.h
index 603af8e83b8..311d95eda73 100644
--- a/include/mysql_embed.h
+++ b/include/mysql_embed.h
@@ -24,7 +24,6 @@
#undef HAVE_PSTACK /* No stacktrace */
#undef HAVE_DLOPEN /* No udf functions */
#undef HAVE_OPENSSL
-#undef HAVE_ISAM
#undef HAVE_SMEM /* No shared memory */
#undef HAVE_NDBCLUSTER_DB /* No NDB cluster */
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
deleted file mode 100644
index 776869ff045..00000000000
--- a/include/mysqld_error.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/* Copyright (C) 2000 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Definefile for error messagenumbers */
-
-#define ER_HASHCHK 1000
-#define ER_NISAMCHK 1001
-#define ER_NO 1002
-#define ER_YES 1003
-#define ER_CANT_CREATE_FILE 1004
-#define ER_CANT_CREATE_TABLE 1005
-#define ER_CANT_CREATE_DB 1006
-#define ER_DB_CREATE_EXISTS 1007
-#define ER_DB_DROP_EXISTS 1008
-#define ER_DB_DROP_DELETE 1009
-#define ER_DB_DROP_RMDIR 1010
-#define ER_CANT_DELETE_FILE 1011
-#define ER_CANT_FIND_SYSTEM_REC 1012
-#define ER_CANT_GET_STAT 1013
-#define ER_CANT_GET_WD 1014
-#define ER_CANT_LOCK 1015
-#define ER_CANT_OPEN_FILE 1016
-#define ER_FILE_NOT_FOUND 1017
-#define ER_CANT_READ_DIR 1018
-#define ER_CANT_SET_WD 1019
-#define ER_CHECKREAD 1020
-#define ER_DISK_FULL 1021
-#define ER_DUP_KEY 1022
-#define ER_ERROR_ON_CLOSE 1023
-#define ER_ERROR_ON_READ 1024
-#define ER_ERROR_ON_RENAME 1025
-#define ER_ERROR_ON_WRITE 1026
-#define ER_FILE_USED 1027
-#define ER_FILSORT_ABORT 1028
-#define ER_FORM_NOT_FOUND 1029
-#define ER_GET_ERRNO 1030
-#define ER_ILLEGAL_HA 1031
-#define ER_KEY_NOT_FOUND 1032
-#define ER_NOT_FORM_FILE 1033
-#define ER_NOT_KEYFILE 1034
-#define ER_OLD_KEYFILE 1035
-#define ER_OPEN_AS_READONLY 1036
-#define ER_OUTOFMEMORY 1037
-#define ER_OUT_OF_SORTMEMORY 1038
-#define ER_UNEXPECTED_EOF 1039
-#define ER_CON_COUNT_ERROR 1040
-#define ER_OUT_OF_RESOURCES 1041
-#define ER_BAD_HOST_ERROR 1042
-#define ER_HANDSHAKE_ERROR 1043
-#define ER_DBACCESS_DENIED_ERROR 1044
-#define ER_ACCESS_DENIED_ERROR 1045
-#define ER_NO_DB_ERROR 1046
-#define ER_UNKNOWN_COM_ERROR 1047
-#define ER_BAD_NULL_ERROR 1048
-#define ER_BAD_DB_ERROR 1049
-#define ER_TABLE_EXISTS_ERROR 1050
-#define ER_BAD_TABLE_ERROR 1051
-#define ER_NON_UNIQ_ERROR 1052
-#define ER_SERVER_SHUTDOWN 1053
-#define ER_BAD_FIELD_ERROR 1054
-#define ER_WRONG_FIELD_WITH_GROUP 1055
-#define ER_WRONG_GROUP_FIELD 1056
-#define ER_WRONG_SUM_SELECT 1057
-#define ER_WRONG_VALUE_COUNT 1058
-#define ER_TOO_LONG_IDENT 1059
-#define ER_DUP_FIELDNAME 1060
-#define ER_DUP_KEYNAME 1061
-#define ER_DUP_ENTRY 1062
-#define ER_WRONG_FIELD_SPEC 1063
-#define ER_PARSE_ERROR 1064
-#define ER_EMPTY_QUERY 1065
-#define ER_NONUNIQ_TABLE 1066
-#define ER_INVALID_DEFAULT 1067
-#define ER_MULTIPLE_PRI_KEY 1068
-#define ER_TOO_MANY_KEYS 1069
-#define ER_TOO_MANY_KEY_PARTS 1070
-#define ER_TOO_LONG_KEY 1071
-#define ER_KEY_COLUMN_DOES_NOT_EXITS 1072
-#define ER_BLOB_USED_AS_KEY 1073
-#define ER_TOO_BIG_FIELDLENGTH 1074
-#define ER_WRONG_AUTO_KEY 1075
-#define ER_READY 1076
-#define ER_NORMAL_SHUTDOWN 1077
-#define ER_GOT_SIGNAL 1078
-#define ER_SHUTDOWN_COMPLETE 1079
-#define ER_FORCING_CLOSE 1080
-#define ER_IPSOCK_ERROR 1081
-#define ER_NO_SUCH_INDEX 1082
-#define ER_WRONG_FIELD_TERMINATORS 1083
-#define ER_BLOBS_AND_NO_TERMINATED 1084
-#define ER_TEXTFILE_NOT_READABLE 1085
-#define ER_FILE_EXISTS_ERROR 1086
-#define ER_LOAD_INFO 1087
-#define ER_ALTER_INFO 1088
-#define ER_WRONG_SUB_KEY 1089
-#define ER_CANT_REMOVE_ALL_FIELDS 1090
-#define ER_CANT_DROP_FIELD_OR_KEY 1091
-#define ER_INSERT_INFO 1092
-#define ER_UPDATE_TABLE_USED 1093
-#define ER_NO_SUCH_THREAD 1094
-#define ER_KILL_DENIED_ERROR 1095
-#define ER_NO_TABLES_USED 1096
-#define ER_TOO_BIG_SET 1097
-#define ER_NO_UNIQUE_LOGFILE 1098
-#define ER_TABLE_NOT_LOCKED_FOR_WRITE 1099
-#define ER_TABLE_NOT_LOCKED 1100
-#define ER_BLOB_CANT_HAVE_DEFAULT 1101
-#define ER_WRONG_DB_NAME 1102
-#define ER_WRONG_TABLE_NAME 1103
-#define ER_TOO_BIG_SELECT 1104
-#define ER_UNKNOWN_ERROR 1105
-#define ER_UNKNOWN_PROCEDURE 1106
-#define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107
-#define ER_WRONG_PARAMETERS_TO_PROCEDURE 1108
-#define ER_UNKNOWN_TABLE 1109
-#define ER_FIELD_SPECIFIED_TWICE 1110
-#define ER_INVALID_GROUP_FUNC_USE 1111
-#define ER_UNSUPPORTED_EXTENSION 1112
-#define ER_TABLE_MUST_HAVE_COLUMNS 1113
-#define ER_RECORD_FILE_FULL 1114
-#define ER_UNKNOWN_CHARACTER_SET 1115
-#define ER_TOO_MANY_TABLES 1116
-#define ER_TOO_MANY_FIELDS 1117
-#define ER_TOO_BIG_ROWSIZE 1118
-#define ER_STACK_OVERRUN 1119
-#define ER_WRONG_OUTER_JOIN 1120
-#define ER_NULL_COLUMN_IN_INDEX 1121
-#define ER_CANT_FIND_UDF 1122
-#define ER_CANT_INITIALIZE_UDF 1123
-#define ER_UDF_NO_PATHS 1124
-#define ER_UDF_EXISTS 1125
-#define ER_CANT_OPEN_LIBRARY 1126
-#define ER_CANT_FIND_DL_ENTRY 1127
-#define ER_FUNCTION_NOT_DEFINED 1128
-#define ER_HOST_IS_BLOCKED 1129
-#define ER_HOST_NOT_PRIVILEGED 1130
-#define ER_PASSWORD_ANONYMOUS_USER 1131
-#define ER_PASSWORD_NOT_ALLOWED 1132
-#define ER_PASSWORD_NO_MATCH 1133
-#define ER_UPDATE_INFO 1134
-#define ER_CANT_CREATE_THREAD 1135
-#define ER_WRONG_VALUE_COUNT_ON_ROW 1136
-#define ER_CANT_REOPEN_TABLE 1137
-#define ER_INVALID_USE_OF_NULL 1138
-#define ER_REGEXP_ERROR 1139
-#define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140
-#define ER_NONEXISTING_GRANT 1141
-#define ER_TABLEACCESS_DENIED_ERROR 1142
-#define ER_COLUMNACCESS_DENIED_ERROR 1143
-#define ER_ILLEGAL_GRANT_FOR_TABLE 1144
-#define ER_GRANT_WRONG_HOST_OR_USER 1145
-#define ER_NO_SUCH_TABLE 1146
-#define ER_NONEXISTING_TABLE_GRANT 1147
-#define ER_NOT_ALLOWED_COMMAND 1148
-#define ER_SYNTAX_ERROR 1149
-#define ER_DELAYED_CANT_CHANGE_LOCK 1150
-#define ER_TOO_MANY_DELAYED_THREADS 1151
-#define ER_ABORTING_CONNECTION 1152
-#define ER_NET_PACKET_TOO_LARGE 1153
-#define ER_NET_READ_ERROR_FROM_PIPE 1154
-#define ER_NET_FCNTL_ERROR 1155
-#define ER_NET_PACKETS_OUT_OF_ORDER 1156
-#define ER_NET_UNCOMPRESS_ERROR 1157
-#define ER_NET_READ_ERROR 1158
-#define ER_NET_READ_INTERRUPTED 1159
-#define ER_NET_ERROR_ON_WRITE 1160
-#define ER_NET_WRITE_INTERRUPTED 1161
-#define ER_TOO_LONG_STRING 1162
-#define ER_TABLE_CANT_HANDLE_BLOB 1163
-#define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164
-#define ER_DELAYED_INSERT_TABLE_LOCKED 1165
-#define ER_WRONG_COLUMN_NAME 1166
-#define ER_WRONG_KEY_COLUMN 1167
-#define ER_WRONG_MRG_TABLE 1168
-#define ER_DUP_UNIQUE 1169
-#define ER_BLOB_KEY_WITHOUT_LENGTH 1170
-#define ER_PRIMARY_CANT_HAVE_NULL 1171
-#define ER_TOO_MANY_ROWS 1172
-#define ER_REQUIRES_PRIMARY_KEY 1173
-#define ER_NO_RAID_COMPILED 1174
-#define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175
-#define ER_KEY_DOES_NOT_EXITS 1176
-#define ER_CHECK_NO_SUCH_TABLE 1177
-#define ER_CHECK_NOT_IMPLEMENTED 1178
-#define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179
-#define ER_ERROR_DURING_COMMIT 1180
-#define ER_ERROR_DURING_ROLLBACK 1181
-#define ER_ERROR_DURING_FLUSH_LOGS 1182
-#define ER_ERROR_DURING_CHECKPOINT 1183
-#define ER_NEW_ABORTING_CONNECTION 1184
-#define ER_DUMP_NOT_IMPLEMENTED 1185
-#define ER_FLUSH_MASTER_BINLOG_CLOSED 1186
-#define ER_INDEX_REBUILD 1187
-#define ER_MASTER 1188
-#define ER_MASTER_NET_READ 1189
-#define ER_MASTER_NET_WRITE 1190
-#define ER_FT_MATCHING_KEY_NOT_FOUND 1191
-#define ER_LOCK_OR_ACTIVE_TRANSACTION 1192
-#define ER_UNKNOWN_SYSTEM_VARIABLE 1193
-#define ER_CRASHED_ON_USAGE 1194
-#define ER_CRASHED_ON_REPAIR 1195
-#define ER_WARNING_NOT_COMPLETE_ROLLBACK 1196
-#define ER_TRANS_CACHE_FULL 1197
-#define ER_SLAVE_MUST_STOP 1198
-#define ER_SLAVE_NOT_RUNNING 1199
-#define ER_BAD_SLAVE 1200
-#define ER_MASTER_INFO 1201
-#define ER_SLAVE_THREAD 1202
-#define ER_TOO_MANY_USER_CONNECTIONS 1203
-#define ER_SET_CONSTANTS_ONLY 1204
-#define ER_LOCK_WAIT_TIMEOUT 1205
-#define ER_LOCK_TABLE_FULL 1206
-#define ER_READ_ONLY_TRANSACTION 1207
-#define ER_DROP_DB_WITH_READ_LOCK 1208
-#define ER_CREATE_DB_WITH_READ_LOCK 1209
-#define ER_WRONG_ARGUMENTS 1210
-#define ER_NO_PERMISSION_TO_CREATE_USER 1211
-#define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212
-#define ER_LOCK_DEADLOCK 1213
-#define ER_TABLE_CANT_HANDLE_FT 1214
-#define ER_CANNOT_ADD_FOREIGN 1215
-#define ER_NO_REFERENCED_ROW 1216
-#define ER_ROW_IS_REFERENCED 1217
-#define ER_CONNECT_TO_MASTER 1218
-#define ER_QUERY_ON_MASTER 1219
-#define ER_ERROR_WHEN_EXECUTING_COMMAND 1220
-#define ER_WRONG_USAGE 1221
-#define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1222
-#define ER_CANT_UPDATE_WITH_READLOCK 1223
-#define ER_MIXING_NOT_ALLOWED 1224
-#define ER_DUP_ARGUMENT 1225
-#define ER_USER_LIMIT_REACHED 1226
-#define ER_SPECIFIC_ACCESS_DENIED_ERROR 1227
-#define ER_LOCAL_VARIABLE 1228
-#define ER_GLOBAL_VARIABLE 1229
-#define ER_NO_DEFAULT 1230
-#define ER_WRONG_VALUE_FOR_VAR 1231
-#define ER_WRONG_TYPE_FOR_VAR 1232
-#define ER_VAR_CANT_BE_READ 1233
-#define ER_CANT_USE_OPTION_HERE 1234
-#define ER_NOT_SUPPORTED_YET 1235
-#define ER_MASTER_FATAL_ERROR_READING_BINLOG 1236
-#define ER_SLAVE_IGNORED_TABLE 1237
-#define ER_INCORRECT_GLOBAL_LOCAL_VAR 1238
-#define ER_WRONG_FK_DEF 1239
-#define ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1240
-#define ER_OPERAND_COLUMNS 1241
-#define ER_SUBQUERY_NO_1_ROW 1242
-#define ER_UNKNOWN_STMT_HANDLER 1243
-#define ER_CORRUPT_HELP_DB 1244
-#define ER_CYCLIC_REFERENCE 1245
-#define ER_AUTO_CONVERT 1246
-#define ER_ILLEGAL_REFERENCE 1247
-#define ER_DERIVED_MUST_HAVE_ALIAS 1248
-#define ER_SELECT_REDUCED 1249
-#define ER_TABLENAME_NOT_ALLOWED_HERE 1250
-#define ER_NOT_SUPPORTED_AUTH_MODE 1251
-#define ER_SPATIAL_CANT_HAVE_NULL 1252
-#define ER_COLLATION_CHARSET_MISMATCH 1253
-#define ER_SLAVE_WAS_RUNNING 1254
-#define ER_SLAVE_WAS_NOT_RUNNING 1255
-#define ER_TOO_BIG_FOR_UNCOMPRESS 1256
-#define ER_ZLIB_Z_MEM_ERROR 1257
-#define ER_ZLIB_Z_BUF_ERROR 1258
-#define ER_ZLIB_Z_DATA_ERROR 1259
-#define ER_CUT_VALUE_GROUP_CONCAT 1260
-#define ER_WARN_TOO_FEW_RECORDS 1261
-#define ER_WARN_TOO_MANY_RECORDS 1262
-#define ER_WARN_NULL_TO_NOTNULL 1263
-#define ER_WARN_DATA_OUT_OF_RANGE 1264
-#define ER_WARN_DATA_TRUNCATED 1265
-#define ER_WARN_USING_OTHER_HANDLER 1266
-#define ER_CANT_AGGREGATE_2COLLATIONS 1267
-#define ER_DROP_USER 1268
-#define ER_REVOKE_GRANTS 1269
-#define ER_CANT_AGGREGATE_3COLLATIONS 1270
-#define ER_CANT_AGGREGATE_NCOLLATIONS 1271
-#define ER_VARIABLE_IS_NOT_STRUCT 1272
-#define ER_UNKNOWN_COLLATION 1273
-#define ER_SLAVE_IGNORED_SSL_PARAMS 1274
-#define ER_SERVER_IS_IN_SECURE_AUTH_MODE 1275
-#define ER_WARN_FIELD_RESOLVED 1276
-#define ER_BAD_SLAVE_UNTIL_COND 1277
-#define ER_MISSING_SKIP_SLAVE 1278
-#define ER_UNTIL_COND_IGNORED 1279
-#define ER_WRONG_NAME_FOR_INDEX 1280
-#define ER_WRONG_NAME_FOR_CATALOG 1281
-#define ER_WARN_QC_RESIZE 1282
-#define ER_BAD_FT_COLUMN 1283
-#define ER_UNKNOWN_KEY_CACHE 1284
-#define ER_WARN_HOSTNAME_WONT_WORK 1285
-#define ER_UNKNOWN_STORAGE_ENGINE 1286
-#define ER_WARN_DEPRECATED_SYNTAX 1287
-#define ER_NON_UPDATABLE_TABLE 1288
-#define ER_FEATURE_DISABLED 1289
-#define ER_OPTION_PREVENTS_STATEMENT 1290
-#define ER_DUPLICATED_VALUE_IN_TYPE 1291
-#define ER_TRUNCATED_WRONG_VALUE 1292
-#define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293
-#define ER_INVALID_ON_UPDATE 1294
-#define ER_UNSUPPORTED_PS 1295
-#define ER_GET_ERRMSG 1296
-#define ER_GET_TEMPORARY_ERRMSG 1297
-#define ER_UNKNOWN_TIME_ZONE 1298
-#define ER_WARN_INVALID_TIMESTAMP 1299
-#define ER_INVALID_CHARACTER_STRING 1300
-#define ER_WARN_ALLOWED_PACKET_OVERFLOWED 1301
-#define ER_CONFLICTING_DECLARATIONS 1302
-#define ER_ERROR_MESSAGES 303
diff --git a/include/mysys_err.h b/include/mysys_err.h
index 19106dc3553..341e6950792 100644
--- a/include/mysys_err.h
+++ b/include/mysys_err.h
@@ -20,14 +20,20 @@
extern "C" {
#endif
-#define GLOB 0 /* Error maps */
-#define GLOBERRS 29 /* Max number of error messages in map's */
-#define EE(X) globerrs[ X ] /* Defines to add error to right map */
+#define GLOBERRS (EE_ERROR_LAST - EE_ERROR_FIRST + 1) /* Nr of global errors */
+#define EE(X) (globerrs[(X) - EE_ERROR_FIRST])
extern const char * NEAR globerrs[]; /* my_error_messages is here */
/* Error message numbers in global map */
-#define EE_FILENOTFOUND 0
+/*
+ Do not add error numbers before EE_ERROR_FIRST.
+ If necessary to add lower numbers, change EE_ERROR_FIRST accordingly.
+
+ We start with error 1 to not confuse peoples with 'error 0'
+*/
+
+#define EE_ERROR_FIRST 1 /*Copy first error nr.*/
#define EE_CANTCREATEFILE 1
#define EE_READ 2
#define EE_WRITE 3
@@ -55,6 +61,9 @@ extern const char * NEAR globerrs[]; /* my_error_messages is here */
#define EE_REALPATH 26
#define EE_SYNC 27
#define EE_UNKNOWN_COLLATION 28
+#define EE_FILENOTFOUND 29
+#define EE_ERROR_LAST 29 /*Copy last error nr.*/
+/* Add error numbers before EE_ERROR_LAST and change it accordingly. */
/* exit codes for all MySQL programs */
diff --git a/include/nisam.h b/include/nisam.h
deleted file mode 100644
index e8f29991a4e..00000000000
--- a/include/nisam.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/* Copyright (C) 2000 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* This file should be included when using nisam_funktions */
-/* Author: Michael Widenius */
-
-#ifndef _nisam_h
-#define _nisam_h
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _my_base_h
-#include <my_base.h>
-#endif
- /* defines used by nisam-funktions */
-
-#define N_MAXKEY 16 /* Max allowed keys */
-#define N_MAXKEY_SEG 16 /* Max segments for key */
-#define N_MAX_KEY_LENGTH 256 /* May be increased up to 500 */
-#define N_MAX_KEY_BUFF (N_MAX_KEY_LENGTH+N_MAXKEY_SEG+sizeof(double)-1)
-#define N_MAX_POSSIBLE_KEY_BUFF 500+9
-
-#define N_NAME_IEXT ".ISM"
-#define N_NAME_DEXT ".ISD"
-#define NI_POS_ERROR (~ (ulong) 0)
-
-
- /* Param to/from nisam_info */
-
-typedef struct st_n_isaminfo /* Struct from h_info */
-{
- ulong records; /* Records in database */
- ulong deleted; /* Deleted records in database */
- ulong recpos; /* Pos for last used record */
- ulong newrecpos; /* Pos if we write new record */
- ulong dupp_key_pos; /* Position to record with dupp key */
- ulong data_file_length, /* Length of data file */
- max_data_file_length,
- index_file_length,
- max_index_file_length,
- delete_length;
- uint reclength; /* Recordlength */
- uint mean_reclength; /* Mean recordlength (if packed) */
- uint keys; /* How many keys used */
- uint options; /* HA_OPTION_... used */
- int errkey, /* With key was dupplicated on err */
- sortkey; /* clustered by this key */
- File filenr; /* (uniq) filenr for datafile */
- time_t create_time; /* When table was created */
- time_t isamchk_time;
- time_t update_time;
- ulong *rec_per_key; /* for sql optimizing */
-} N_ISAMINFO;
-
-
- /* Info saved on file for each info-part */
-
-#ifdef __WATCOMC__
-#pragma pack(2)
-#define uint uint16 /* Same format as in MSDOS */
-#endif
-
-#ifdef __ZTC__
-#pragma ZTC align 2
-#define uint uint16 /* Same format as in MSDOS */
-#endif
-
-typedef struct st_n_save_keyseg /* Key-portion */
-{
- uint8 type; /* Typ av nyckel (f|r sort) */
- uint8 flag; /* HA_DIFF_LENGTH */
- uint16 start; /* Start of key in record */
- uint16 length; /* Keylength */
-} N_SAVE_KEYSEG;
-
-typedef struct st_n_save_keydef /* Key definition with create & info */
-{
- uint8 flag; /* NOSAME, PACK_USED */
- uint8 keysegs; /* Number of key-segment */
- uint16 block_length; /* Length of keyblock (auto) */
- uint16 keylength; /* Tot length of keyparts (auto) */
- uint16 minlength; /* min length of (packed) key (auto) */
- uint16 maxlength; /* max length of (packed) key (auto) */
-} N_SAVE_KEYDEF;
-
-typedef struct st_n_save_recinfo /* Info of record */
-{
- int16 type; /* en_fieldtype */
- uint16 length; /* length of field */
-} N_SAVE_RECINFO;
-
-
-#ifdef __ZTC__
-#pragma ZTC align
-#undef uint
-#endif
-
-#ifdef __WATCOMC__
-#pragma pack()
-#undef uint
-#endif
-
-
-struct st_isam_info; /* For referense */
-
-#ifndef ISAM_LIBRARY
-typedef struct st_isam_info N_INFO;
-#endif
-
-typedef struct st_n_keyseg /* Key-portion */
-{
- N_SAVE_KEYSEG base;
-} N_KEYSEG;
-
-
-typedef struct st_n_keydef /* Key definition with open & info */
-{
- N_SAVE_KEYDEF base;
- N_KEYSEG seg[N_MAXKEY_SEG+1];
- int (*bin_search)(struct st_isam_info *info,struct st_n_keydef *keyinfo,
- uchar *page,uchar *key,
- uint key_len,uint comp_flag,uchar * *ret_pos,
- uchar *buff);
- uint (*get_key)(struct st_n_keydef *keyinfo,uint nod_flag,uchar * *page,
- uchar *key);
-} N_KEYDEF;
-
-
-typedef struct st_decode_tree /* Decode huff-table */
-{
- uint16 *table;
- uint quick_table_bits;
- byte *intervalls;
-} DECODE_TREE;
-
-
-struct st_bit_buff;
-
-typedef struct st_n_recinfo /* Info of record */
-{
- N_SAVE_RECINFO base;
-#ifndef NOT_PACKED_DATABASES
- void (*unpack)(struct st_n_recinfo *rec,struct st_bit_buff *buff,
- uchar *start,uchar *end);
- enum en_fieldtype base_type;
- uint space_length_bits,pack_type;
- DECODE_TREE *huff_tree;
-#endif
-} N_RECINFO;
-
-
-extern my_string nisam_log_filename; /* Name of logfile */
-extern uint nisam_block_size;
-extern my_bool nisam_flush;
-
- /* Prototypes for nisam-functions */
-
-extern int nisam_close(struct st_isam_info *file);
-extern int nisam_delete(struct st_isam_info *file,const byte *buff);
-extern struct st_isam_info *nisam_open(const char *name,int mode,
- uint wait_if_locked);
-extern int nisam_panic(enum ha_panic_function function);
-extern int nisam_rfirst(struct st_isam_info *file,byte *buf,int inx);
-extern int nisam_rkey(struct st_isam_info *file,byte *buf,int inx,
- const byte *key,
- uint key_len, enum ha_rkey_function search_flag);
-extern int nisam_rlast(struct st_isam_info *file,byte *buf,int inx);
-extern int nisam_rnext(struct st_isam_info *file,byte *buf,int inx);
-extern int nisam_rprev(struct st_isam_info *file,byte *buf,int inx);
-extern int nisam_rrnd(struct st_isam_info *file,byte *buf,ulong pos);
-extern int nisam_rsame(struct st_isam_info *file,byte *record,int inx);
-extern int nisam_rsame_with_pos(struct st_isam_info *file,byte *record,
- int inx,ulong pos);
-extern int nisam_update(struct st_isam_info *file,const byte *old,
- const byte *new_record);
-extern int nisam_write(struct st_isam_info *file,const byte *buff);
-extern int nisam_info(struct st_isam_info *file,N_ISAMINFO *x,int flag);
-extern ulong nisam_position(struct st_isam_info *info);
-extern int nisam_lock_database(struct st_isam_info *file,int lock_type);
-extern int nisam_create(const char *name,uint keys,N_KEYDEF *keyinfo,
- N_RECINFO *recinfo,ulong records,
- ulong reloc,uint flags,uint options,
- ulong data_file_length);
-extern int nisam_extra(struct st_isam_info *file,
- enum ha_extra_function function);
-extern ulong nisam_records_in_range(struct st_isam_info *info,int inx,
- const byte *start_key,uint start_key_len,
- enum ha_rkey_function start_search_flag,
- const byte *end_key,uint end_key_len,
- enum ha_rkey_function end_search_flag);
-extern int nisam_log(int activate_log);
-extern int nisam_is_changed(struct st_isam_info *info);
-extern uint _calc_blob_length(uint length , const byte *pos);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/include/queues.h b/include/queues.h
index ac15b09719b..02ab768198e 100644
--- a/include/queues.h
+++ b/include/queues.h
@@ -53,6 +53,7 @@ int resize_queue(QUEUE *queue, uint max_elements);
void delete_queue(QUEUE *queue);
void queue_insert(QUEUE *queue,byte *element);
byte *queue_remove(QUEUE *queue,uint idx);
+#define queue_remove_all(queue) { (queue)->elements= 0; }
void _downheap(QUEUE *queue,uint idx);
void queue_fix(QUEUE *queue);
#define is_queue_inited(queue) ((queue)->root != 0)
diff --git a/include/sql_state.h b/include/sql_state.h
deleted file mode 100644
index 52a359405e1..00000000000
--- a/include/sql_state.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/* Copyright (C) 2000-2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- This file includes a mapping from mysql_errno.h to sql_state (as used by
- MyODBC) and jdbc_state.
- It's suitable to include into a C struct for further processing
-
- The first column is the mysqld server error (declared in mysqld_error.h),
- the second column is the ODBC state (which the 4.1 server sends out by
- default) and the last is the state used by the JDBC driver.
- If the last column is "" then it means that the JDBC driver is using the
- ODBC state.
-
- The errors in this file are sorted in the same order as in mysqld_error.h
- to allow one to do binary searches for the sqlstate.
-*/
-
-ER_DUP_KEY, "23000", "",
-ER_OUTOFMEMORY, "HY001", "S1001",
-ER_OUT_OF_SORTMEMORY, "HY001", "S1001",
-ER_CON_COUNT_ERROR, "08004", "",
-ER_BAD_HOST_ERROR, "08S01", "",
-ER_HANDSHAKE_ERROR, "08S01", "",
-ER_DBACCESS_DENIED_ERROR, "42000", "",
-ER_ACCESS_DENIED_ERROR, "28000", "",
-ER_NO_DB_ERROR, "3D000", "",
-ER_UNKNOWN_COM_ERROR, "08S01", "",
-ER_BAD_NULL_ERROR, "23000", "",
-ER_BAD_DB_ERROR, "42000", "",
-ER_TABLE_EXISTS_ERROR, "42S01", "",
-ER_BAD_TABLE_ERROR, "42S02", "",
-ER_NON_UNIQ_ERROR, "23000", "",
-ER_SERVER_SHUTDOWN, "08S01", "",
-ER_BAD_FIELD_ERROR, "42S22", "S0022",
-ER_WRONG_FIELD_WITH_GROUP, "42000", "S1009",
-ER_WRONG_GROUP_FIELD, "42000", "S1009",
-ER_WRONG_SUM_SELECT, "42000", "S1009",
-ER_WRONG_VALUE_COUNT, "21S01", "",
-ER_TOO_LONG_IDENT, "42000", "S1009",
-ER_DUP_FIELDNAME, "42S21", "S1009",
-ER_DUP_KEYNAME, "42000", "S1009",
-ER_DUP_ENTRY, "23000", "S1009",
-ER_WRONG_FIELD_SPEC, "42000", "S1009",
-ER_PARSE_ERROR, "42000", "",
-ER_EMPTY_QUERY, "42000" , "",
-ER_NONUNIQ_TABLE, "42000", "S1009",
-ER_INVALID_DEFAULT, "42000", "S1009",
-ER_MULTIPLE_PRI_KEY, "42000", "S1009",
-ER_TOO_MANY_KEYS, "42000", "S1009",
-ER_TOO_MANY_KEY_PARTS, "42000", "S1009",
-ER_TOO_LONG_KEY, "42000", "S1009",
-ER_KEY_COLUMN_DOES_NOT_EXITS, "42000", "S1009",
-ER_BLOB_USED_AS_KEY, "42000", "S1009",
-ER_TOO_BIG_FIELDLENGTH, "42000", "S1009",
-ER_WRONG_AUTO_KEY, "42000", "S1009",
-ER_FORCING_CLOSE, "08S01", "",
-ER_IPSOCK_ERROR, "08S01", "",
-ER_NO_SUCH_INDEX, "42S12", "S1009",
-ER_WRONG_FIELD_TERMINATORS, "42000", "S1009",
-ER_BLOBS_AND_NO_TERMINATED, "42000", "S1009",
-ER_CANT_REMOVE_ALL_FIELDS, "42000", "",
-ER_CANT_DROP_FIELD_OR_KEY, "42000", "",
-ER_BLOB_CANT_HAVE_DEFAULT, "42000", "",
-ER_WRONG_DB_NAME, "42000", "",
-ER_WRONG_TABLE_NAME, "42000", "",
-ER_TOO_BIG_SELECT, "42000", "",
-ER_UNKNOWN_PROCEDURE, "42000", "",
-ER_WRONG_PARAMCOUNT_TO_PROCEDURE, "42000", "",
-ER_UNKNOWN_TABLE, "42S02", "",
-ER_FIELD_SPECIFIED_TWICE, "42000", "",
-ER_UNSUPPORTED_EXTENSION, "42000", "",
-ER_TABLE_MUST_HAVE_COLUMNS, "42000", "",
-ER_UNKNOWN_CHARACTER_SET, "42000", "",
-ER_TOO_BIG_ROWSIZE, "42000", "",
-ER_WRONG_OUTER_JOIN, "42000", "",
-ER_NULL_COLUMN_IN_INDEX, "42000", "",
-ER_PASSWORD_ANONYMOUS_USER, "42000", "",
-ER_PASSWORD_NOT_ALLOWED, "42000", "",
-ER_PASSWORD_NO_MATCH, "42000", "",
-ER_WRONG_VALUE_COUNT_ON_ROW, "21S01", "",
-ER_INVALID_USE_OF_NULL, "42000", "",
-ER_REGEXP_ERROR, "42000", "",
-ER_MIX_OF_GROUP_FUNC_AND_FIELDS,"42000", "",
-ER_NONEXISTING_GRANT, "42000", "",
-ER_TABLEACCESS_DENIED_ERROR, "42000", "",
-ER_COLUMNACCESS_DENIED_ERROR, "42000", "",
-ER_ILLEGAL_GRANT_FOR_TABLE, "42000", "",
-ER_GRANT_WRONG_HOST_OR_USER, "42000", "",
-ER_NO_SUCH_TABLE, "42S02", "",
-ER_NONEXISTING_TABLE_GRANT, "42000", "",
-ER_NOT_ALLOWED_COMMAND, "42000", "",
-ER_SYNTAX_ERROR, "42000", "",
-ER_ABORTING_CONNECTION, "08S01", "",
-ER_NET_PACKET_TOO_LARGE, "08S01", "",
-ER_NET_READ_ERROR_FROM_PIPE, "08S01", "",
-ER_NET_FCNTL_ERROR, "08S01", "",
-ER_NET_PACKETS_OUT_OF_ORDER, "08S01", "",
-ER_NET_UNCOMPRESS_ERROR, "08S01", "",
-ER_NET_READ_ERROR, "08S01", "",
-ER_NET_READ_INTERRUPTED, "08S01", "",
-ER_NET_ERROR_ON_WRITE, "08S01", "",
-ER_NET_WRITE_INTERRUPTED, "08S01", "",
-ER_TOO_LONG_STRING, "42000", "",
-ER_TABLE_CANT_HANDLE_BLOB, "42000", "",
-ER_TABLE_CANT_HANDLE_AUTO_INCREMENT, "42000", "",
-ER_WRONG_COLUMN_NAME, "42000", "",
-ER_WRONG_KEY_COLUMN, "42000", "",
-ER_DUP_UNIQUE, "23000", "",
-ER_BLOB_KEY_WITHOUT_LENGTH, "42000", "",
-ER_PRIMARY_CANT_HAVE_NULL, "42000", "",
-ER_TOO_MANY_ROWS, "42000", "",
-ER_REQUIRES_PRIMARY_KEY, "42000", "",
-ER_CHECK_NO_SUCH_TABLE, "42000", "",
-ER_CHECK_NOT_IMPLEMENTED, "42000", "",
-ER_CANT_DO_THIS_DURING_AN_TRANSACTION, "25000", "",
-ER_NEW_ABORTING_CONNECTION, "08S01", "",
-ER_MASTER_NET_READ, "08S01", "",
-ER_MASTER_NET_WRITE, "08S01", "",
-ER_TOO_MANY_USER_CONNECTIONS, "42000", "",
-ER_READ_ONLY_TRANSACTION, "25000", "",
-ER_NO_PERMISSION_TO_CREATE_USER,"42000", "",
-ER_LOCK_DEADLOCK, "40001", "",
-ER_NO_REFERENCED_ROW, "23000", "",
-ER_ROW_IS_REFERENCED, "23000", "",
-ER_CONNECT_TO_MASTER, "08S01", "",
-ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,"21000", "",
-ER_USER_LIMIT_REACHED, "42000", "",
-ER_NO_DEFAULT, "42000", "",
-ER_WRONG_VALUE_FOR_VAR, "42000", "",
-ER_WRONG_TYPE_FOR_VAR, "42000", "",
-ER_CANT_USE_OPTION_HERE, "42000", "",
-ER_NOT_SUPPORTED_YET, "42000", "",
-ER_WRONG_FK_DEF, "42000", "",
-ER_OPERAND_COLUMNS, "21000", "",
-ER_SUBQUERY_NO_1_ROW, "21000", "",
-ER_ILLEGAL_REFERENCE, "42S22", "",
-ER_DERIVED_MUST_HAVE_ALIAS, "42000", "",
-ER_SELECT_REDUCED, "01000", "",
-ER_TABLENAME_NOT_ALLOWED_HERE, "42000", "",
-ER_NOT_SUPPORTED_AUTH_MODE, "08004", "",
-ER_SPATIAL_CANT_HAVE_NULL, "42000", "",
-ER_COLLATION_CHARSET_MISMATCH, "42000", "",
-ER_WARN_TOO_FEW_RECORDS, "01000", "",
-ER_WARN_TOO_MANY_RECORDS, "01000", "",
-ER_WARN_NULL_TO_NOTNULL, "01000", "",
-ER_WARN_DATA_OUT_OF_RANGE, "01000", "",
-ER_WARN_DATA_TRUNCATED, "01000", "",
-ER_WRONG_NAME_FOR_INDEX, "42000", "",
-ER_WRONG_NAME_FOR_CATALOG, "42000", "",
-ER_UNKNOWN_STORAGE_ENGINE, "42000", "",
diff --git a/include/violite.h b/include/violite.h
index b89b01f95f4..97784694e79 100644
--- a/include/violite.h
+++ b/include/violite.h
@@ -37,7 +37,12 @@ enum enum_vio_type
VIO_TYPE_SSL, VIO_TYPE_SHARED_MEMORY
};
-Vio* vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost);
+
+#define VIO_LOCALHOST 1 /* a localhost connection */
+#define VIO_BUFFERED_READ 2 /* use buffered read */
+#define VIO_READ_BUFFER_SIZE 16384 /* size of read buffer */
+
+Vio* vio_new(my_socket sd, enum enum_vio_type type, uint flags);
#ifdef __WIN__
Vio* vio_new_win32pipe(HANDLE hPipe);
Vio* vio_new_win32shared_memory(NET *net,HANDLE handle_file_map,
@@ -57,8 +62,9 @@ int vio_close_pipe(Vio * vio);
void vio_delete(Vio* vio);
int vio_close(Vio* vio);
void vio_reset(Vio* vio, enum enum_vio_type type,
- my_socket sd, HANDLE hPipe, my_bool localhost);
+ my_socket sd, HANDLE hPipe, uint flags);
int vio_read(Vio *vio, gptr buf, int size);
+int vio_read_buff(Vio *vio, gptr buf, int size);
int vio_write(Vio *vio, const gptr buf, int size);
int vio_blocking(Vio *vio, my_bool onoff, my_bool *old_mode);
my_bool vio_is_blocking(Vio *vio);
@@ -135,7 +141,7 @@ int vio_close_shared_memory(Vio * vio);
}
#endif
-#if defined(HAVE_VIO) && !defined(DONT_MAP_VIO)
+#if !defined(DONT_MAP_VIO)
#define vio_delete(vio) (vio)->viodelete(vio)
#define vio_errno(vio) (vio)->vioerrno(vio)
#define vio_read(vio, buf, size) ((vio)->read)(vio,buf,size)
@@ -150,7 +156,7 @@ int vio_close_shared_memory(Vio * vio);
#define vio_peer_addr(vio, buf, prt) (vio)->peer_addr(vio, buf, prt)
#define vio_in_addr(vio, in) (vio)->in_addr(vio, in)
#define vio_timeout(vio, seconds) (vio)->timeout(vio, seconds)
-#endif /* defined(HAVE_VIO) && !defined(DONT_MAP_VIO) */
+#endif /* !defined(DONT_MAP_VIO) */
/* This enumerator is used in parser - should be always visible */
enum SSL_type
@@ -175,7 +181,10 @@ struct st_vio
struct sockaddr_in remote; /* Remote internet address */
enum enum_vio_type type; /* Type of connection */
char desc[30]; /* String description */
-#ifdef HAVE_VIO
+ char *read_buffer; /* buffer for vio_read_buff */
+ char *read_pos; /* start of unfetched data in the
+ read buffer */
+ char *read_end; /* end of unfetched data */
/* function pointers. They are similar for socket/SSL/whatever */
void (*viodelete)(Vio*);
int (*vioerrno)(Vio*);
@@ -203,6 +212,5 @@ struct st_vio
char *shared_memory_pos;
NET *net;
#endif /* HAVE_SMEM */
-#endif /* HAVE_VIO */
};
#endif /* vio_violite_h_ */
diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c
index ae967e0525e..1744fc36f4d 100644
--- a/innobase/btr/btr0btr.c
+++ b/innobase/btr/btr0btr.c
@@ -86,15 +86,6 @@ btr_page_create(
page_t* page, /* in: page to be created */
dict_tree_t* tree, /* in: index tree */
mtr_t* mtr); /* in: mtr */
-/******************************************************************
-Sets the child node file address in a node pointer. */
-UNIV_INLINE
-void
-btr_node_ptr_set_child_page_no(
-/*===========================*/
- rec_t* rec, /* in: node pointer record */
- ulint page_no, /* in: child node address */
- mtr_t* mtr); /* in: mtr */
/****************************************************************
Returns the upper level node pointer to a page. It is assumed that
mtr holds an x-latch on the tree. */
@@ -128,7 +119,10 @@ btr_page_insert_fits(
rec_t* split_rec, /* in: suggestion for first record
on upper half-page, or NULL if
tuple should be first */
- dtuple_t* tuple); /* in: tuple to insert */
+ const ulint* offsets, /* in: rec_get_offsets(
+ split_rec, cursor->index) */
+ dtuple_t* tuple, /* in: tuple to insert */
+ mem_heap_t* heap); /* in: temporary memory heap */
/******************************************************************
Gets the root node of a tree and x-latches it. */
@@ -143,11 +137,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);
return(root);
}
@@ -194,6 +190,7 @@ btr_get_prev_user_rec(
MTR_MEMO_PAGE_S_FIX))
|| (mtr_memo_contains(mtr, buf_block_align(prev_page),
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));
@@ -246,6 +243,7 @@ btr_get_next_user_rec(
|| (mtr_memo_contains(mtr, buf_block_align(next_page),
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);
@@ -267,7 +265,8 @@ btr_page_create(
{
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX));
- page_create(page, mtr);
+ page_create(page, mtr,
+ UT_LIST_GET_FIRST(tree->tree_indexes)->table->comp);
buf_block_align(page)->check_index_page_at_flush = TRUE;
btr_page_set_index_id(page, tree->id, mtr);
@@ -503,20 +502,21 @@ UNIV_INLINE
void
btr_node_ptr_set_child_page_no(
/*===========================*/
- rec_t* rec, /* in: node pointer record */
- ulint page_no, /* in: child node address */
- mtr_t* mtr) /* in: mtr */
+ rec_t* rec, /* in: node pointer record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint page_no,/* in: child node address */
+ mtr_t* mtr) /* in: mtr */
{
- ulint n_fields;
byte* field;
ulint len;
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
ut_ad(0 < btr_page_get_level(buf_frame_align(rec), mtr));
-
- n_fields = rec_get_n_fields(rec);
+ ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
/* The child address is in the last field */
- field = rec_get_nth_field(rec, n_fields - 1, &len);
+ field = rec_get_nth_field(rec, offsets,
+ rec_offs_n_fields(offsets) - 1, &len);
ut_ad(len == 4);
@@ -529,16 +529,18 @@ static
page_t*
btr_node_ptr_get_child(
/*===================*/
- /* out: child page, x-latched */
- rec_t* node_ptr, /* in: node pointer */
- mtr_t* mtr) /* in: mtr */
+ /* out: child page, x-latched */
+ rec_t* node_ptr,/* in: node pointer */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ mtr_t* mtr) /* in: mtr */
{
ulint page_no;
ulint space;
page_t* page;
-
+
+ ut_ad(rec_offs_validate(node_ptr, NULL, offsets));
space = buf_frame_get_space_id(node_ptr);
- page_no = btr_node_ptr_get_child_page_no(node_ptr);
+ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
@@ -564,6 +566,10 @@ btr_page_get_father_for_rec(
dtuple_t* tuple;
btr_cur_t cursor;
rec_t* node_ptr;
+ dict_index_t* index;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
MTR_MEMO_X_LOCK));
@@ -576,18 +582,21 @@ btr_page_get_father_for_rec(
tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap,
btr_page_get_level(page, mtr));
+ index = UT_LIST_GET_FIRST(tree->tree_indexes);
/* In the following, we choose just any index from the tree as the
first parameter for btr_cur_search_to_nth_level. */
-
- btr_cur_search_to_nth_level(UT_LIST_GET_FIRST(tree->tree_indexes),
+
+ btr_cur_search_to_nth_level(index,
btr_page_get_level(page, mtr) + 1,
tuple, PAGE_CUR_LE,
BTR_CONT_MODIFY_TREE, &cursor, 0, mtr);
node_ptr = btr_cur_get_rec(&cursor);
+ offsets = rec_get_offsets(node_ptr, index, offsets,
+ ULINT_UNDEFINED, &heap);
- if (btr_node_ptr_get_child_page_no(node_ptr) !=
+ if (btr_node_ptr_get_child_page_no(node_ptr, offsets) !=
buf_frame_get_page_no(page)) {
fputs("InnoDB: Dump of the child page:\n", stderr);
buf_page_print(buf_frame_align(page));
@@ -595,17 +604,22 @@ btr_page_get_father_for_rec(
buf_page_print(buf_frame_align(node_ptr));
fputs("InnoDB: Corruption of an index tree: table ", stderr);
- ut_print_name(stderr, NULL,
- UT_LIST_GET_FIRST(tree->tree_indexes)->table_name);
+ ut_print_name(stderr, NULL, index->table_name);
fputs(", index ", stderr);
- ut_print_name(stderr, NULL,
- UT_LIST_GET_FIRST(tree->tree_indexes)->name);
+ ut_print_name(stderr, NULL, index->name);
fprintf(stderr, ",\n"
"InnoDB: father ptr page no %lu, child page no %lu\n",
- (ulong) btr_node_ptr_get_child_page_no(node_ptr),
+ (ulong)
+ btr_node_ptr_get_child_page_no(node_ptr, offsets),
(ulong) buf_frame_get_page_no(page));
- page_rec_print(page_rec_get_next(page_get_infimum_rec(page)));
- page_rec_print(node_ptr);
+ offsets = rec_get_offsets(page_rec_get_next(
+ page_get_infimum_rec(page)), index,
+ offsets, ULINT_UNDEFINED, &heap);
+ page_rec_print(page_rec_get_next(page_get_infimum_rec(page)),
+ offsets);
+ offsets = rec_get_offsets(node_ptr, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ page_rec_print(node_ptr, offsets);
fputs(
"InnoDB: You should dump + drop + reimport the table to fix the\n"
@@ -614,7 +628,7 @@ btr_page_get_father_for_rec(
"InnoDB: forcing recovery. Then dump + drop + reimport.\n", stderr);
}
- ut_a(btr_node_ptr_get_child_page_no(node_ptr) ==
+ ut_a(btr_node_ptr_get_child_page_no(node_ptr, offsets) ==
buf_frame_get_page_no(page));
mem_heap_free(heap);
@@ -649,6 +663,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 */
mtr_t* mtr) /* in: mini-transaction handle */
{
ulint page_no;
@@ -716,7 +731,7 @@ btr_create(
}
/* Create a new index page on the the allocated segment page */
- page = page_create(frame, mtr);
+ page = page_create(frame, mtr, comp);
buf_block_align(page)->check_index_page_at_flush = TRUE;
/* Set the index id of the page */
@@ -821,12 +836,14 @@ static
void
btr_page_reorganize_low(
/*====================*/
- ibool recovery,/* in: TRUE if called in recovery: locks should not
- be updated, i.e., there cannot exist locks on the
- page, and a hash index should not be dropped: it
- cannot exist */
- page_t* page, /* in: page to be reorganized */
- mtr_t* mtr) /* in: mtr */
+ ibool recovery,/* in: TRUE if called in recovery:
+ locks should not be updated, i.e.,
+ there cannot exist locks on the
+ page, and a hash index should not be
+ dropped: it cannot exist */
+ page_t* page, /* in: page to be reorganized */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
page_t* new_page;
ulint log_mode;
@@ -841,7 +858,9 @@ btr_page_reorganize_low(
max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
/* Write the log record */
- mlog_write_initial_log_record(page, MLOG_PAGE_REORGANIZE, mtr);
+ mlog_open_and_write_index(mtr, page, index, index->table->comp
+ ? MLOG_COMP_PAGE_REORGANIZE
+ : MLOG_PAGE_REORGANIZE, 0);
/* Turn logging off */
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
@@ -858,14 +877,14 @@ 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);
+ page_create(page, mtr, index->table->comp);
buf_block_align(page)->check_index_page_at_flush = TRUE;
/* Copy the records from the temporary space to the recreated page;
do not copy the lock bits yet */
page_copy_rec_list_end_no_locks(page, new_page,
- page_get_infimum_rec(new_page), mtr);
+ page_get_infimum_rec(new_page), index, mtr);
/* Copy max trx id to recreated page */
page_set_max_trx_id(page, page_get_max_trx_id(new_page));
@@ -901,10 +920,11 @@ Reorganizes an index page. */
void
btr_page_reorganize(
/*================*/
- page_t* page, /* in: page to be reorganized */
- mtr_t* mtr) /* in: mtr */
+ page_t* page, /* in: page to be reorganized */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
- btr_page_reorganize_low(FALSE, page, mtr);
+ btr_page_reorganize_low(FALSE, page, index, mtr);
}
/***************************************************************
@@ -913,18 +933,20 @@ Parses a redo log record of reorganizing a page. */
byte*
btr_parse_page_reorganize(
/*======================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr __attribute__((unused)), /* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
+ /* out: end of log record or NULL */
+ byte* ptr, /* in: buffer */
+ byte* end_ptr __attribute__((unused)),
+ /* in: buffer end */
+ dict_index_t* index, /* in: record descriptor */
+ page_t* page, /* in: page or NULL */
+ mtr_t* mtr) /* in: mtr or NULL */
{
ut_ad(ptr && end_ptr);
/* The record is empty, except for the record initial part */
if (page) {
- btr_page_reorganize_low(TRUE, page, mtr);
+ btr_page_reorganize_low(TRUE, page, index, mtr);
}
return(ptr);
@@ -946,7 +968,7 @@ btr_page_empty(
/* Recreate the page: note that global data on page (possible
segment headers, next page-field, etc.) is preserved intact */
- page_create(page, mtr);
+ page_create(page, mtr, page_is_comp(page));
buf_block_align(page)->check_index_page_at_flush = TRUE;
}
@@ -1011,7 +1033,7 @@ btr_root_raise_and_insert(
/* Move the records from root to the new page */
page_move_rec_list_end(new_page, root, page_get_infimum_rec(root),
- mtr);
+ cursor->index, mtr);
/* If this is a pessimistic insert which is actually done to
perform a pessimistic update then we have stored the lock
information of the record to be inserted on the infimum of the
@@ -1031,7 +1053,7 @@ btr_root_raise_and_insert(
node_ptr = dict_tree_build_node_ptr(tree, rec, new_page_no, heap,
level);
/* Reorganize the root to get free space */
- btr_page_reorganize(root, mtr);
+ btr_page_reorganize(root, cursor->index, mtr);
page_cursor = btr_cur_get_page_cur(cursor);
@@ -1039,7 +1061,8 @@ btr_root_raise_and_insert(
page_cur_set_before_first(root, page_cursor);
- node_ptr_rec = page_cur_tuple_insert(page_cursor, node_ptr, mtr);
+ node_ptr_rec = page_cur_tuple_insert(page_cursor, node_ptr,
+ cursor->index, mtr);
ut_ad(node_ptr_rec);
@@ -1047,7 +1070,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, mtr);
+ btr_set_min_rec_mark(node_ptr_rec, cursor->index->table->comp, mtr);
/* Free the memory heap */
mem_heap_free(heap);
@@ -1060,7 +1083,8 @@ btr_root_raise_and_insert(
ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes),
new_page);
/* Reposition the cursor to the child node */
- page_cur_search(new_page, tuple, PAGE_CUR_LE, page_cursor);
+ page_cur_search(new_page, cursor->index, tuple,
+ PAGE_CUR_LE, page_cursor);
/* Split the child and insert tuple */
return(btr_page_split_and_insert(cursor, tuple, mtr));
@@ -1190,11 +1214,13 @@ btr_page_get_sure_split_rec(
rec_t* rec;
rec_t* next_rec;
ulint n;
-
+ mem_heap_t* heap;
+ ulint* offsets;
+
page = btr_cur_get_page(cursor);
- insert_size = rec_get_converted_size(tuple);
- free_space = page_get_free_space_of_empty();
+ insert_size = rec_get_converted_size(cursor->index, tuple);
+ free_space = page_get_free_space_of_empty(cursor->index->table->comp);
/* free_space is now the free space of a created new page */
@@ -1208,6 +1234,9 @@ btr_page_get_sure_split_rec(
ins_rec = btr_cur_get_rec(cursor);
rec = page_get_infimum_rec(page);
+ heap = NULL;
+ offsets = NULL;
+
/* We start to include records to the left half, and when the
space reserved by them exceeds half of total_space, then if
the included records fit on the left page, they will be put there
@@ -1230,7 +1259,9 @@ btr_page_get_sure_split_rec(
/* Include tuple */
incl_data += insert_size;
} else {
- incl_data += rec_get_size(rec);
+ offsets = rec_get_offsets(rec, cursor->index,
+ offsets, ULINT_UNDEFINED, &heap);
+ incl_data += rec_offs_size(offsets);
}
n++;
@@ -1252,11 +1283,16 @@ btr_page_get_sure_split_rec(
next_rec = page_rec_get_next(rec);
}
if (next_rec != page_get_supremum_rec(page)) {
-
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(next_rec);
}
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(rec);
}
}
@@ -1275,7 +1311,10 @@ btr_page_insert_fits(
rec_t* split_rec, /* in: suggestion for first record
on upper half-page, or NULL if
tuple to be inserted should be first */
- dtuple_t* tuple) /* in: tuple to insert */
+ const ulint* offsets, /* in: rec_get_offsets(
+ split_rec, cursor->index) */
+ dtuple_t* tuple, /* in: tuple to insert */
+ mem_heap_t* heap) /* in: temporary memory heap */
{
page_t* page;
ulint insert_size;
@@ -1284,11 +1323,19 @@ btr_page_insert_fits(
ulint total_n_recs;
rec_t* rec;
rec_t* end_rec;
+ ulint* offs;
page = btr_cur_get_page(cursor);
-
- insert_size = rec_get_converted_size(tuple);
- free_space = page_get_free_space_of_empty();
+
+ ut_ad(!split_rec == !offsets);
+ ut_ad(!offsets
+ || cursor->index->table->comp == 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 is now the free space of a created new page */
@@ -1303,7 +1350,7 @@ btr_page_insert_fits(
rec = page_rec_get_next(page_get_infimum_rec(page));
end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
- } else if (cmp_dtuple_rec(tuple, split_rec) >= 0) {
+ } else if (cmp_dtuple_rec(tuple, split_rec, offsets) >= 0) {
rec = page_rec_get_next(page_get_infimum_rec(page));
end_rec = split_rec;
@@ -1321,11 +1368,16 @@ btr_page_insert_fits(
return(TRUE);
}
+ offs = NULL;
+
while (rec != end_rec) {
/* In this loop we calculate the amount of reserved
space after rec is removed from page. */
- total_data -= rec_get_size(rec);
+ offs = rec_get_offsets(rec, cursor->index, offs,
+ ULINT_UNDEFINED, &heap);
+
+ total_data -= rec_offs_size(offs);
total_n_recs--;
if (total_data + page_dir_calc_reserved_space(total_n_recs)
@@ -1411,6 +1463,10 @@ btr_attach_half_pages(
MTR_MEMO_PAGE_X_FIX));
ut_ad(mtr_memo_contains(mtr, buf_block_align(new_page),
MTR_MEMO_PAGE_X_FIX));
+ ut_a(page_is_comp(page) == page_is_comp(new_page));
+
+ /* Create a memory heap where the data tuple is stored */
+ heap = mem_heap_create(1024);
/* Based on split direction, decide upper and lower pages */
if (direction == FSP_DOWN) {
@@ -1426,7 +1482,12 @@ btr_attach_half_pages(
/* Replace the address of the old child node (= page) with the
address of the new lower half */
- btr_node_ptr_set_child_page_no(node_ptr, lower_page_no, mtr);
+ btr_node_ptr_set_child_page_no(node_ptr,
+ rec_get_offsets(node_ptr,
+ UT_LIST_GET_FIRST(tree->tree_indexes),
+ NULL, ULINT_UNDEFINED, &heap),
+ lower_page_no, mtr);
+ mem_heap_empty(heap);
} else {
lower_page_no = buf_frame_get_page_no(page);
upper_page_no = buf_frame_get_page_no(new_page);
@@ -1434,9 +1495,6 @@ btr_attach_half_pages(
upper_page = new_page;
}
- /* Create a memory heap where the data tuple is stored */
- heap = mem_heap_create(100);
-
/* Get the level of the split pages */
level = btr_page_get_level(page, mtr);
@@ -1465,6 +1523,7 @@ btr_attach_half_pages(
if (prev_page_no != FIL_NULL) {
prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
+ ut_a(page_is_comp(prev_page) == page_is_comp(page));
btr_page_set_next(prev_page, lower_page_no, mtr);
}
@@ -1472,6 +1531,7 @@ btr_attach_half_pages(
if (next_page_no != FIL_NULL) {
next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr);
+ ut_a(page_is_comp(next_page) == page_is_comp(page));
btr_page_set_prev(next_page, upper_page_no, mtr);
}
@@ -1522,7 +1582,15 @@ btr_page_split_and_insert(
ibool insert_will_fit;
ulint n_iterations = 0;
rec_t* rec;
+ mem_heap_t* heap;
+ ulint n_uniq;
+ ulint* offsets;
+
+ heap = mem_heap_create(1024);
+ n_uniq = dict_index_get_n_unique_in_tree(cursor->index);
func_start:
+ mem_heap_empty(heap);
+ offsets = NULL;
tree = btr_cur_get_tree(cursor);
ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
@@ -1574,9 +1642,10 @@ func_start:
first_rec = split_rec;
move_limit = split_rec;
} else {
- buf = mem_alloc(rec_get_converted_size(tuple));
+ buf = mem_alloc(rec_get_converted_size(cursor->index, tuple));
- first_rec = rec_convert_dtuple_to_rec(buf, tuple);
+ first_rec = rec_convert_dtuple_to_rec(buf,
+ cursor->index, tuple);
move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
}
@@ -1593,7 +1662,16 @@ func_start:
We can then move the records after releasing the tree latch,
thus reducing the tree latch contention. */
- insert_will_fit = btr_page_insert_fits(cursor, split_rec, tuple);
+ if (split_rec) {
+ offsets = rec_get_offsets(split_rec, cursor->index, offsets,
+ n_uniq, &heap);
+
+ insert_will_fit = btr_page_insert_fits(cursor,
+ split_rec, offsets, tuple, heap);
+ } else {
+ insert_will_fit = btr_page_insert_fits(cursor,
+ NULL, NULL, tuple, heap);
+ }
if (insert_will_fit && (btr_page_get_level(page, mtr) == 0)) {
@@ -1605,7 +1683,8 @@ func_start:
if (direction == FSP_DOWN) {
/* fputs("Split left\n", stderr); */
- page_move_rec_list_start(new_page, page, move_limit, mtr);
+ page_move_rec_list_start(new_page, page, move_limit,
+ cursor->index, mtr);
left_page = new_page;
right_page = page;
@@ -1613,7 +1692,8 @@ func_start:
} else {
/* fputs("Split right\n", stderr); */
- page_move_rec_list_end(new_page, page, move_limit, mtr);
+ page_move_rec_list_end(new_page, page, move_limit,
+ cursor->index, mtr);
left_page = page;
right_page = new_page;
@@ -1626,19 +1706,25 @@ func_start:
if (split_rec == NULL) {
insert_page = right_page;
- } else if (cmp_dtuple_rec(tuple, first_rec) >= 0) {
-
- insert_page = right_page;
} else {
- insert_page = left_page;
+ offsets = rec_get_offsets(first_rec, cursor->index,
+ offsets, n_uniq, &heap);
+
+ if (cmp_dtuple_rec(tuple, first_rec, offsets) >= 0) {
+
+ insert_page = right_page;
+ } else {
+ insert_page = left_page;
+ }
}
/* 7. Reposition the cursor for insert and try insertion */
page_cursor = btr_cur_get_page_cur(cursor);
- page_cur_search(insert_page, tuple, PAGE_CUR_LE, page_cursor);
+ page_cur_search(insert_page, cursor->index, tuple,
+ PAGE_CUR_LE, page_cursor);
- rec = page_cur_tuple_insert(page_cursor, tuple, mtr);
+ rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr);
if (rec != NULL) {
/* Insert fit on the page: update the free bits for the
@@ -1650,15 +1736,17 @@ func_start:
/* fprintf(stderr, "Split and insert done %lu %lu\n",
buf_frame_get_page_no(left_page),
buf_frame_get_page_no(right_page)); */
+ mem_heap_free(heap);
return(rec);
}
/* 8. If insert did not fit, try page reorganization */
- btr_page_reorganize(insert_page, mtr);
+ btr_page_reorganize(insert_page, cursor->index, mtr);
- page_cur_search(insert_page, tuple, PAGE_CUR_LE, page_cursor);
- rec = page_cur_tuple_insert(page_cursor, tuple, mtr);
+ page_cur_search(insert_page, cursor->index, tuple,
+ PAGE_CUR_LE, page_cursor);
+ rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr);
if (rec == NULL) {
/* The insert did not fit on the page: loop back to the
@@ -1688,6 +1776,7 @@ func_start:
ut_ad(page_validate(left_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
ut_ad(page_validate(right_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
+ mem_heap_free(heap);
return(rec);
}
@@ -1721,6 +1810,7 @@ btr_level_list_remove(
if (prev_page_no != FIL_NULL) {
prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
+ ut_a(page_is_comp(prev_page) == page_is_comp(page));
btr_page_set_next(prev_page, next_page_no, mtr);
}
@@ -1728,6 +1818,7 @@ btr_level_list_remove(
if (next_page_no != FIL_NULL) {
next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr);
+ ut_a(page_is_comp(next_page) == page_is_comp(page));
btr_page_set_prev(next_page, prev_page_no, mtr);
}
@@ -1741,9 +1832,11 @@ void
btr_set_min_rec_mark_log(
/*=====================*/
rec_t* rec, /* in: record */
+ ibool comp, /* TRUE=compact record format */
mtr_t* mtr) /* in: mtr */
{
- mlog_write_initial_log_record(rec, MLOG_REC_MIN_MARK, 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);
@@ -1759,6 +1852,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 */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
@@ -1772,7 +1866,7 @@ btr_parse_set_min_rec_mark(
if (page) {
rec = page + mach_read_from_2(ptr);
- btr_set_min_rec_mark(rec, mtr);
+ btr_set_min_rec_mark(rec, comp, mtr);
}
return(ptr + 2);
@@ -1785,15 +1879,16 @@ void
btr_set_min_rec_mark(
/*=================*/
rec_t* rec, /* in: record */
+ ibool comp, /* in: TRUE=compact page format */
mtr_t* mtr) /* in: mtr */
{
ulint info_bits;
- info_bits = rec_get_info_bits(rec);
+ info_bits = rec_get_info_bits(rec, comp);
- rec_set_info_bits(rec, info_bits | REC_INFO_MIN_REC_FLAG);
+ rec_set_info_bits(rec, comp, info_bits | REC_INFO_MIN_REC_FLAG);
- btr_set_min_rec_mark_log(rec, mtr);
+ btr_set_min_rec_mark_log(rec, comp, mtr);
}
/*****************************************************************
@@ -1842,18 +1937,19 @@ btr_lift_page_up(
record from the page should be removed */
mtr_t* mtr) /* in: mtr */
{
- rec_t* node_ptr;
- page_t* father_page;
- ulint page_level;
-
+ page_t* father_page;
+ ulint page_level;
+ dict_index_t* index;
+
ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX));
- node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
- father_page = buf_frame_align(node_ptr);
+ father_page = buf_frame_align(
+ btr_page_get_father_node_ptr(tree, page, mtr));
page_level = btr_page_get_level(page, mtr);
+ index = UT_LIST_GET_FIRST(tree->tree_indexes);
btr_search_drop_page_hash_index(page);
@@ -1862,7 +1958,7 @@ btr_lift_page_up(
/* Move records to the father */
page_copy_rec_list_end(father_page, page, page_get_infimum_rec(page),
- mtr);
+ index, mtr);
lock_update_copy_and_discard(father_page, page);
btr_page_set_level(father_page, page_level, mtr);
@@ -1871,10 +1967,8 @@ btr_lift_page_up(
btr_page_free(tree, page, mtr);
/* We play safe and reset the free bits for the father */
- ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes),
- father_page);
- ut_ad(page_validate(father_page,
- UT_LIST_GET_FIRST(tree->tree_indexes)));
+ ibuf_reset_free_bits(index, father_page);
+ ut_ad(page_validate(father_page, index));
ut_ad(btr_check_node_ptr(tree, father_page, mtr));
}
@@ -1914,9 +2008,11 @@ btr_compress(
ulint max_ins_size;
ulint max_ins_size_reorg;
ulint level;
-
+ ibool comp = cursor->index->table->comp;
+
page = btr_cur_get_page(cursor);
tree = btr_cur_get_tree(cursor);
+ ut_a(comp == page_is_comp(page));
ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
MTR_MEMO_X_LOCK));
@@ -1932,7 +2028,9 @@ btr_compress(
right_page_no); */
node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
+ ut_ad(!comp || rec_get_status(node_ptr) == REC_STATUS_NODE_PTR);
father_page = buf_frame_align(node_ptr);
+ ut_a(comp == page_is_comp(father_page));
/* Decide the page to which we try to merge and which will inherit
the locks */
@@ -1957,6 +2055,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));
max_ins_size_reorg = page_get_max_insert_size_after_reorganize(
merge_page, n_recs);
@@ -1975,7 +2074,7 @@ btr_compress(
/* We have to reorganize merge_page */
- btr_page_reorganize(merge_page, mtr);
+ btr_page_reorganize(merge_page, cursor->index, mtr);
max_ins_size = page_get_max_insert_size(merge_page, n_recs);
@@ -1999,11 +2098,19 @@ btr_compress(
if (is_left) {
btr_node_ptr_delete(tree, page, mtr);
} else {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
/* Replace the address of the old child node (= page) with the
address of the merge page to the right */
- btr_node_ptr_set_child_page_no(node_ptr, right_page_no, mtr);
-
+ btr_node_ptr_set_child_page_no(node_ptr,
+ rec_get_offsets(node_ptr, cursor->index,
+ offsets_, ULINT_UNDEFINED, &heap),
+ right_page_no, mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
btr_node_ptr_delete(tree, merge_page, mtr);
}
@@ -2012,14 +2119,14 @@ btr_compress(
orig_pred = page_rec_get_prev(
page_get_supremum_rec(merge_page));
page_copy_rec_list_start(merge_page, page,
- page_get_supremum_rec(page), mtr);
+ page_get_supremum_rec(page), cursor->index, mtr);
lock_update_merge_left(merge_page, orig_pred, page);
} else {
orig_succ = page_rec_get_next(
page_get_infimum_rec(merge_page));
page_copy_rec_list_end(merge_page, page,
- page_get_infimum_rec(page), mtr);
+ page_get_infimum_rec(page), cursor->index, mtr);
lock_update_merge_right(orig_succ, page);
}
@@ -2133,6 +2240,7 @@ btr_discard_page(
return;
}
+ ut_a(page_is_comp(merge_page) == page_is_comp(page));
btr_search_drop_page_hash_index(page);
if (left_page_no == FIL_NULL && btr_page_get_level(page, mtr) > 0) {
@@ -2144,7 +2252,8 @@ btr_discard_page(
ut_ad(node_ptr != page_get_supremum_rec(merge_page));
- btr_set_min_rec_mark(node_ptr, mtr);
+ btr_set_min_rec_mark(node_ptr,
+ cursor->index->table->comp, mtr);
}
btr_node_ptr_delete(tree, page, mtr);
@@ -2215,6 +2324,8 @@ btr_print_recursive(
page_t* page, /* in: index page */
ulint width, /* in: print this many entries from start
and end */
+ mem_heap_t** heap, /* in/out: heap for rec_get_offsets() */
+ ulint** offsets,/* in/out: buffer for rec_get_offsets() */
mtr_t* mtr) /* in: mtr */
{
page_cur_t cursor;
@@ -2223,14 +2334,16 @@ btr_print_recursive(
mtr_t mtr2;
rec_t* node_ptr;
page_t* child;
-
+ dict_index_t* index;
+
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX));
fprintf(stderr, "NODE ON LEVEL %lu page number %lu\n",
(ulong) btr_page_get_level(page, mtr),
(ulong) buf_frame_get_page_no(page));
- page_print(page, width, width);
+ index = UT_LIST_GET_FIRST(tree->tree_indexes);
+ page_print(page, index, width, width);
n_recs = page_get_n_recs(page);
@@ -2249,9 +2362,12 @@ btr_print_recursive(
node_ptr = page_cur_get_rec(&cursor);
- child = btr_node_ptr_get_child(node_ptr, &mtr2);
-
- btr_print_recursive(tree, child, width, &mtr2);
+ *offsets = rec_get_offsets(node_ptr, index, *offsets,
+ ULINT_UNDEFINED, heap);
+ child = btr_node_ptr_get_child(node_ptr,
+ *offsets, &mtr2);
+ btr_print_recursive(tree, child, width,
+ heap, offsets, &mtr2);
mtr_commit(&mtr2);
}
@@ -2270,8 +2386,12 @@ btr_print_tree(
ulint width) /* in: print this many entries from start
and end */
{
- mtr_t mtr;
- page_t* root;
+ mtr_t mtr;
+ page_t* root;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
fputs("--------------------------\n"
"INDEX TREE PRINT\n", stderr);
@@ -2280,7 +2400,10 @@ btr_print_tree(
root = btr_root_get(tree, &mtr);
- btr_print_recursive(tree, root, width, &mtr);
+ btr_print_recursive(tree, root, width, &heap, &offsets, &mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
mtr_commit(&mtr);
@@ -2323,7 +2446,10 @@ btr_check_node_ptr(
page_rec_get_next(page_get_infimum_rec(page)),
0, heap, btr_page_get_level(page, mtr));
- ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr) == 0);
+ ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr,
+ rec_get_offsets(node_ptr,
+ dict_tree_find_index(tree, node_ptr),
+ NULL, ULINT_UNDEFINED, &heap)) == 0);
mem_heap_free(heap);
@@ -2360,10 +2486,14 @@ btr_index_rec_validate(
should print hex dump of record
and page on error */
{
- ulint len;
- ulint n;
- ulint i;
- page_t* page;
+ ulint len;
+ ulint n;
+ ulint i;
+ page_t* page;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
page = buf_frame_align(rec);
@@ -2377,36 +2507,35 @@ btr_index_rec_validate(
n = dict_index_get_n_fields(index);
- if (rec_get_n_fields(rec) != n) {
+ if (!index->table->comp && 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(rec), (ulong) n);
+ (ulong) rec_get_n_fields_old(rec), (ulong) n);
- if (!dump_on_error) {
+ if (dump_on_error) {
+ buf_page_print(page);
- return(FALSE);
+ fputs("InnoDB: corrupt record ", stderr);
+ rec_print_old(stderr, rec);
+ putc('\n', stderr);
}
-
- buf_page_print(page);
-
- fputs("InnoDB: corrupt record ", stderr);
- rec_print(stderr, rec);
- putc('\n', stderr);
-
return(FALSE);
}
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
for (i = 0; i < n; i++) {
dtype_t* type = dict_index_get_nth_type(index, i);
+ ulint fixed_size = dtype_get_fixed_size(type);
- rec_get_nth_field(rec, i, &len);
+ rec_get_nth_field(rec, offsets, i, &len);
/* Note that prefix indexes are not fixed size even when
their type is CHAR. */
if ((dict_index_get_nth_field(index, i)->prefix_len == 0
- && len != UNIV_SQL_NULL && dtype_is_fixed_size(type)
- && len != dtype_get_fixed_size(type))
+ && len != UNIV_SQL_NULL && fixed_size
+ && len != fixed_size)
||
(dict_index_get_nth_field(index, i)->prefix_len > 0
&& len != UNIV_SQL_NULL
@@ -2418,21 +2547,23 @@ btr_index_rec_validate(
"InnoDB: field %lu len is %lu, should be %lu\n",
(ulong) i, (ulong) len, (ulong) dtype_get_fixed_size(type));
- if (!dump_on_error) {
-
- return(FALSE);
- }
-
- buf_page_print(page);
-
- fputs("InnoDB: corrupt record ", stderr);
- rec_print(stderr, rec);
- putc('\n', stderr);
+ if (dump_on_error) {
+ buf_page_print(page);
+ fputs("InnoDB: corrupt record ", stderr);
+ rec_print_new(stderr, rec, offsets);
+ putc('\n', stderr);
+ }
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(FALSE);
}
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(TRUE);
}
@@ -2527,15 +2658,18 @@ btr_validate_level(
page_t* right_father_page;
rec_t* node_ptr;
rec_t* right_node_ptr;
+ rec_t* rec;
ulint right_page_no;
ulint left_page_no;
page_cur_t cursor;
- mem_heap_t* heap;
dtuple_t* node_ptr_tuple;
ibool ret = TRUE;
dict_index_t* index;
mtr_t mtr;
-
+ mem_heap_t* heap = mem_heap_create(256);
+ ulint* offsets = NULL;
+ ulint* offsets2= NULL;
+
mtr_start(&mtr);
mtr_x_lock(dict_tree_get_lock(tree), &mtr);
@@ -2544,6 +2678,8 @@ btr_validate_level(
space = buf_frame_get_space_id(page);
+ index = UT_LIST_GET_FIRST(tree->tree_indexes);
+
while (level != btr_page_get_level(page, &mtr)) {
ut_a(btr_page_get_level(page, &mtr) > 0);
@@ -2552,14 +2688,16 @@ btr_validate_level(
page_cur_move_to_next(&cursor);
node_ptr = page_cur_get_rec(&cursor);
- page = btr_node_ptr_get_child(node_ptr, &mtr);
+ offsets = rec_get_offsets(node_ptr, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ page = btr_node_ptr_get_child(node_ptr, offsets, &mtr);
}
- index = UT_LIST_GET_FIRST(tree->tree_indexes);
-
/* Now we are on the desired level. Loop through the pages on that
level. */
loop:
+ mem_heap_empty(heap);
+ offsets = offsets2 = NULL;
mtr_x_lock(dict_tree_get_lock(tree), &mtr);
/* Check ordering etc. of records */
@@ -2588,12 +2726,19 @@ loop:
(buf_frame_get_page_no(page) == dict_tree_get_page(tree))));
if (right_page_no != FIL_NULL) {
-
+ rec_t* right_rec;
right_page = btr_page_get(space, right_page_no, RW_X_LATCH,
&mtr);
- if (cmp_rec_rec(page_rec_get_prev(page_get_supremum_rec(page)),
- page_rec_get_next(page_get_infimum_rec(right_page)),
- UT_LIST_GET_FIRST(tree->tree_indexes)) >= 0) {
+ ut_a(page_is_comp(right_page) == page_is_comp(page));
+ rec = page_rec_get_prev(page_get_supremum_rec(page));
+ right_rec = page_rec_get_next(
+ page_get_infimum_rec(right_page));
+ offsets = rec_get_offsets(rec, index,
+ offsets, ULINT_UNDEFINED, &heap);
+ offsets2 = rec_get_offsets(right_rec, index,
+ offsets2, ULINT_UNDEFINED, &heap);
+ if (cmp_rec_rec(rec, right_rec, offsets, offsets2, index)
+ >= 0) {
btr_validate_report2(index, level, page, right_page);
@@ -2604,12 +2749,13 @@ loop:
buf_page_print(right_page);
fputs("InnoDB: record ", stderr);
- rec_print(stderr, page_rec_get_prev(
- page_get_supremum_rec(page)));
+ rec = page_rec_get_prev(page_get_supremum_rec(page));
+ rec_print(stderr, rec, index);
putc('\n', stderr);
fputs("InnoDB: record ", stderr);
- rec_print(stderr, page_rec_get_next(
- page_get_infimum_rec(right_page)));
+ rec = page_rec_get_next(page_get_infimum_rec(
+ right_page));
+ rec_print(stderr, rec, index);
putc('\n', stderr);
ret = FALSE;
@@ -2618,7 +2764,8 @@ 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))));
+ page_rec_get_next(page_get_infimum_rec(page)),
+ index->table->comp));
}
if (buf_frame_get_page_no(page) != dict_tree_get_page(tree)) {
@@ -2627,12 +2774,14 @@ loop:
node_ptr = btr_page_get_father_node_ptr(tree, page, &mtr);
father_page = buf_frame_align(node_ptr);
+ offsets = rec_get_offsets(node_ptr, index,
+ offsets, ULINT_UNDEFINED, &heap);
- if (btr_node_ptr_get_child_page_no(node_ptr) !=
+ if (btr_node_ptr_get_child_page_no(node_ptr, offsets) !=
buf_frame_get_page_no(page)
|| node_ptr != btr_page_get_father_for_rec(tree, page,
- page_rec_get_prev(page_get_supremum_rec(page)),
- &mtr)) {
+ page_rec_get_prev(page_get_supremum_rec(page)),
+ &mtr)) {
btr_validate_report1(index, level, page);
fputs("InnoDB: node pointer to the page is wrong\n",
@@ -2642,17 +2791,18 @@ loop:
buf_page_print(page);
fputs("InnoDB: node ptr ", stderr);
- rec_print(stderr, node_ptr);
+ rec_print_new(stderr, node_ptr, offsets);
fprintf(stderr, "\n"
"InnoDB: node ptr child page n:o %lu\n",
- (unsigned long) btr_node_ptr_get_child_page_no(node_ptr));
+ (unsigned long) btr_node_ptr_get_child_page_no(
+ node_ptr, offsets));
fputs("InnoDB: record on page ", stderr);
- rec_print(stderr,
- btr_page_get_father_for_rec(tree, page,
- page_rec_get_prev(page_get_supremum_rec(page)),
- &mtr));
+ rec = btr_page_get_father_for_rec(tree, page,
+ page_rec_get_prev(page_get_supremum_rec(page)),
+ &mtr);
+ rec_print(stderr, rec, index);
putc('\n', stderr);
ret = FALSE;
@@ -2660,7 +2810,8 @@ loop:
}
if (btr_page_get_level(page, &mtr) > 0) {
- heap = mem_heap_create(256);
+ offsets = rec_get_offsets(node_ptr, index,
+ offsets, ULINT_UNDEFINED, &heap);
node_ptr_tuple = dict_tree_build_node_ptr(
tree,
@@ -2669,7 +2820,10 @@ loop:
0, heap,
btr_page_get_level(page, &mtr));
- if (cmp_dtuple_rec(node_ptr_tuple, node_ptr) != 0) {
+ if (cmp_dtuple_rec(node_ptr_tuple, node_ptr,
+ offsets)) {
+ rec_t* first_rec = page_rec_get_next(
+ page_get_infimum_rec(page));
btr_validate_report1(index, level, page);
@@ -2679,18 +2833,14 @@ loop:
fputs("InnoDB: Error: node ptrs differ"
" on levels > 0\n"
"InnoDB: node ptr ", stderr);
- rec_print(stderr, node_ptr);
+ rec_print_new(stderr, node_ptr, offsets);
fputs("InnoDB: first rec ", stderr);
- rec_print(stderr, page_rec_get_next(
- page_get_infimum_rec(page)));
+ rec_print(stderr, first_rec, index);
putc('\n', stderr);
ret = FALSE;
- mem_heap_free(heap);
goto node_ptr_fails;
}
-
- mem_heap_free(heap);
}
if (left_page_no == FIL_NULL) {
@@ -2701,7 +2851,7 @@ loop:
if (right_page_no == FIL_NULL) {
ut_a(node_ptr == page_rec_get_prev(
- page_get_supremum_rec(father_page)));
+ page_get_supremum_rec(father_page)));
ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL);
}
@@ -2771,13 +2921,16 @@ node_ptr_fails:
mtr_commit(&mtr);
if (right_page_no != FIL_NULL) {
+ ibool comp = page_is_comp(page);
mtr_start(&mtr);
page = btr_page_get(space, right_page_no, RW_X_LATCH, &mtr);
+ ut_a(page_is_comp(page) == comp);
goto loop;
}
+ mem_heap_free(heap);
return(ret);
}
diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c
index 48de5644908..e093c911f22 100644
--- a/innobase/btr/btr0cur.c
+++ b/innobase/btr/btr0cur.c
@@ -73,8 +73,9 @@ static
void
btr_cur_unmark_extern_fields(
/*=========================*/
- rec_t* rec, /* in: record in a clustered index */
- mtr_t* mtr); /* in: mtr */
+ rec_t* rec, /* in: record in a clustered index */
+ mtr_t* mtr, /* in: mtr */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/***********************************************************************
Adds path information to the cursor for the current page, for which
the binary search has been performed. */
@@ -96,6 +97,7 @@ btr_rec_free_updated_extern_fields(
dict_index_t* index, /* in: index of rec; the index tree MUST be
X-latched */
rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
upd_t* update, /* in: update vector */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
@@ -108,9 +110,10 @@ static
ulint
btr_rec_get_externally_stored_len(
/*==============================*/
- /* out: externally stored part, in units of a
- database page */
- rec_t* rec); /* in: record */
+ /* out: externally stored part,
+ in units of a database page */
+ rec_t* rec, /* in: record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/*==================== B-TREE SEARCH =========================*/
@@ -137,11 +140,13 @@ btr_cur_latch_leaves(
if (latch_mode == BTR_SEARCH_LEAF) {
get_page = btr_page_get(space, page_no, RW_S_LATCH, mtr);
+ ut_a(page_is_comp(get_page) == page_is_comp(page));
buf_block_align(get_page)->check_index_page_at_flush = TRUE;
} else if (latch_mode == BTR_MODIFY_LEAF) {
get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
+ ut_a(page_is_comp(get_page) == page_is_comp(page));
buf_block_align(get_page)->check_index_page_at_flush = TRUE;
} else if (latch_mode == BTR_MODIFY_TREE) {
@@ -152,11 +157,13 @@ btr_cur_latch_leaves(
if (left_page_no != FIL_NULL) {
get_page = btr_page_get(space, left_page_no,
RW_X_LATCH, mtr);
+ ut_a(page_is_comp(get_page) == page_is_comp(page));
buf_block_align(get_page)->check_index_page_at_flush =
TRUE;
}
get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
+ ut_a(page_is_comp(get_page) == page_is_comp(page));
buf_block_align(get_page)->check_index_page_at_flush = TRUE;
right_page_no = btr_page_get_next(page, mtr);
@@ -176,11 +183,14 @@ btr_cur_latch_leaves(
if (left_page_no != FIL_NULL) {
cursor->left_page = btr_page_get(space, left_page_no,
RW_S_LATCH, mtr);
+ ut_a(page_is_comp(cursor->left_page) ==
+ page_is_comp(page));
buf_block_align(
cursor->left_page)->check_index_page_at_flush = TRUE;
}
get_page = btr_page_get(space, page_no, RW_S_LATCH, mtr);
+ ut_a(page_is_comp(get_page) == page_is_comp(page));
buf_block_align(get_page)->check_index_page_at_flush = TRUE;
} else if (latch_mode == BTR_MODIFY_PREV) {
@@ -191,11 +201,14 @@ btr_cur_latch_leaves(
if (left_page_no != FIL_NULL) {
cursor->left_page = btr_page_get(space, left_page_no,
RW_X_LATCH, mtr);
+ ut_a(page_is_comp(cursor->left_page) ==
+ page_is_comp(page));
buf_block_align(
cursor->left_page)->check_index_page_at_flush = TRUE;
}
get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
+ ut_a(page_is_comp(get_page) == page_is_comp(page));
buf_block_align(get_page)->check_index_page_at_flush = TRUE;
} else {
ut_error;
@@ -261,6 +274,10 @@ btr_cur_search_to_nth_level(
#ifdef BTR_CUR_ADAPT
btr_search_t* info;
#endif
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
/* Currently, PAGE_CUR_LE is the only search mode used for searches
ending to upper levels */
@@ -379,7 +396,7 @@ btr_cur_search_to_nth_level(
page_mode = mode;
break;
}
-
+
/* Loop and search until we arrive at the desired level */
for (;;) {
@@ -414,7 +431,9 @@ retry_page_get:
cursor->thr)) {
/* Insertion to the insert buffer succeeded */
cursor->flag = BTR_CUR_INSERT_TO_IBUF;
-
+ if (heap) {
+ mem_heap_free(heap);
+ }
return;
}
@@ -470,9 +489,9 @@ retry_page_get:
page_mode = mode;
}
- page_cur_search_with_match(page, tuple, page_mode, &up_match,
- &up_bytes, &low_match, &low_bytes,
- page_cursor);
+ page_cur_search_with_match(page, index, tuple, page_mode,
+ &up_match, &up_bytes,
+ &low_match, &low_bytes, page_cursor);
if (estimate) {
btr_cur_add_path_info(cursor, height, root_height);
}
@@ -486,7 +505,9 @@ retry_page_get:
if (level > 0) {
/* x-latch the page */
- btr_page_get(space, page_no, RW_X_LATCH, mtr);
+ ut_a(page_is_comp(btr_page_get(space,
+ page_no, RW_X_LATCH, mtr))
+ == index->table->comp);
}
break;
@@ -498,9 +519,14 @@ retry_page_get:
guess = NULL;
node_ptr = page_cur_get_rec(page_cursor);
-
+ offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
/* Go to the child node */
- page_no = btr_node_ptr_get_child_page_no(node_ptr);
+ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
+ }
+
+ if (heap) {
+ mem_heap_free(heap);
}
if (level == 0) {
@@ -552,6 +578,10 @@ btr_cur_open_at_index_side(
rec_t* node_ptr;
ulint estimate;
ulint savepoint;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
estimate = latch_mode & BTR_ESTIMATE;
latch_mode = latch_mode & ~BTR_ESTIMATE;
@@ -576,7 +606,7 @@ btr_cur_open_at_index_side(
page_no = dict_tree_get_page(tree);
height = ULINT_UNDEFINED;
-
+
for (;;) {
page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL,
BUF_GET,
@@ -645,9 +675,14 @@ btr_cur_open_at_index_side(
height--;
node_ptr = page_cur_get_rec(page_cursor);
-
+ offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
/* Go to the child node */
- page_no = btr_node_ptr_get_child_page_no(node_ptr);
+ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
+ }
+
+ if (heap) {
+ mem_heap_free(heap);
}
}
@@ -669,6 +704,10 @@ btr_cur_open_at_rnd_pos(
ulint space;
ulint height;
rec_t* node_ptr;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
tree = index->tree;
@@ -717,9 +756,14 @@ btr_cur_open_at_rnd_pos(
height--;
node_ptr = page_cur_get_rec(page_cursor);
-
+ offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
/* Go to the child node */
- page_no = btr_node_ptr_get_child_page_no(node_ptr);
+ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
+ }
+
+ if (heap) {
+ mem_heap_free(heap);
}
}
@@ -758,18 +802,20 @@ btr_cur_insert_if_possible(
page_cursor = btr_cur_get_page_cur(cursor);
/* Now, try the insert */
- rec = page_cur_tuple_insert(page_cursor, tuple, mtr);
+ rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr);
if (!rec) {
/* If record did not fit, reorganize */
- btr_page_reorganize(page, mtr);
+ btr_page_reorganize(page, cursor->index, mtr);
*reorg = TRUE;
- page_cur_search(page, tuple, PAGE_CUR_LE, page_cursor);
+ page_cur_search(page, cursor->index, tuple,
+ PAGE_CUR_LE, page_cursor);
- rec = page_cur_tuple_insert(page_cursor, tuple, mtr);
+ rec = page_cur_tuple_insert(page_cursor, tuple,
+ cursor->index, mtr);
}
return(rec);
@@ -887,8 +933,6 @@ btr_cur_optimistic_insert(
ibool reorg;
ibool inherit;
ulint rec_size;
- ulint data_size;
- ulint extra_size;
ulint type;
ulint err;
@@ -914,13 +958,11 @@ btr_cur_optimistic_insert(
calculate_sizes_again:
/* Calculate the record size when entry is converted to a record */
- data_size = dtuple_get_data_size(entry);
- extra_size = rec_get_converted_extra_size(data_size,
- dtuple_get_n_fields(entry));
- rec_size = data_size + extra_size;
+ rec_size = rec_get_converted_size(index, entry);
- if ((rec_size >= page_get_free_space_of_empty() / 2)
- || (rec_size >= REC_MAX_DATA_SIZE)) {
+ if (rec_size >=
+ ut_min(page_get_free_space_of_empty(index->table->comp) / 2,
+ REC_MAX_DATA_SIZE)) {
/* The record is so big that we have to store some fields
externally on separate database pages */
@@ -983,19 +1025,19 @@ calculate_sizes_again:
/* Now, try the insert */
- *rec = page_cur_insert_rec_low(page_cursor, entry, data_size,
- NULL, mtr);
+ *rec = page_cur_insert_rec_low(page_cursor, entry, index,
+ NULL, NULL, mtr);
if (!(*rec)) {
/* If the record did not fit, reorganize */
- btr_page_reorganize(page, mtr);
+ btr_page_reorganize(page, index, mtr);
ut_ad(page_get_max_insert_size(page, 1) == max_size);
reorg = TRUE;
- page_cur_search(page, entry, PAGE_CUR_LE, page_cursor);
+ page_cur_search(page, index, entry, PAGE_CUR_LE, page_cursor);
- *rec = page_cur_tuple_insert(page_cursor, entry, mtr);
+ *rec = page_cur_tuple_insert(page_cursor, entry, index, mtr);
if (!*rec) {
fputs("InnoDB: Error: cannot insert tuple ", stderr);
@@ -1123,9 +1165,9 @@ btr_cur_pessimistic_insert(
}
}
- if ((rec_get_converted_size(entry)
- >= page_get_free_space_of_empty() / 2)
- || (rec_get_converted_size(entry) >= REC_MAX_DATA_SIZE)) {
+ if (rec_get_converted_size(index, entry) >=
+ ut_min(page_get_free_space_of_empty(index->table->comp) / 2,
+ REC_MAX_DATA_SIZE)) {
/* The record is so big that we have to store some fields
externally on separate database pages */
@@ -1212,8 +1254,16 @@ btr_cur_upd_lock_and_undo(
err = DB_SUCCESS;
if (!(flags & BTR_NO_LOCKING_FLAG)) {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
err = lock_clust_rec_modify_check_and_lock(flags, rec, index,
- thr);
+ rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap), thr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
if (err != DB_SUCCESS) {
return(err);
@@ -1243,14 +1293,17 @@ btr_cur_update_in_place_log(
mtr_t* mtr) /* in: mtr */
{
byte* log_ptr;
+ ut_ad(flags < 256);
- log_ptr = mlog_open(mtr, 30 + MLOG_BUF_MARGIN);
+ log_ptr = mlog_open_and_write_index(mtr, rec, index, index->table->comp
+ ? MLOG_COMP_REC_UPDATE_IN_PLACE
+ : MLOG_REC_UPDATE_IN_PLACE,
+ 1 + DATA_ROLL_PTR_LEN + 14 + 2 + MLOG_BUF_MARGIN);
- log_ptr = mlog_write_initial_log_record_fast(rec,
- MLOG_REC_UPDATE_IN_PLACE, log_ptr, mtr);
-
- mach_write_to_1(log_ptr, flags);
- log_ptr++;
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash recovery */
+ return;
+ }
/* The code below assumes index is a clustered index: change index to
the clustered index if we are updating a secondary index record (or we
@@ -1259,6 +1312,9 @@ btr_cur_update_in_place_log(
index = dict_table_get_first_index(index->table);
+ mach_write_to_1(log_ptr, flags);
+ log_ptr++;
+
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));
@@ -1273,10 +1329,11 @@ Parses a redo log record of updating a record in-place. */
byte*
btr_cur_parse_update_in_place(
/*==========================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page) /* in: page or NULL */
+ /* out: end of log record or NULL */
+ byte* ptr, /* in: buffer */
+ byte* end_ptr,/* in: buffer end */
+ page_t* page, /* in: page or NULL */
+ dict_index_t* index) /* in: index corresponding to page */
{
ulint flags;
rec_t* rec;
@@ -1286,6 +1343,7 @@ btr_cur_parse_update_in_place(
dulint roll_ptr;
ulint rec_offset;
mem_heap_t* heap;
+ ulint* offsets;
if (end_ptr < ptr + 1) {
@@ -1333,11 +1391,14 @@ btr_cur_parse_update_in_place(
/* We do not need to reserve btr_search_latch, as the page is only
being recovered, and there cannot be a hash index to it. */
+ offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
+
if (!(flags & BTR_KEEP_SYS_FLAG)) {
- row_upd_rec_sys_fields_in_recovery(rec, pos, trx_id, roll_ptr);
+ row_upd_rec_sys_fields_in_recovery(rec, offsets,
+ pos, trx_id, roll_ptr);
}
- row_upd_rec_in_place(rec, update);
+ row_upd_rec_in_place(rec, offsets, update);
mem_heap_free(heap);
@@ -1369,14 +1430,20 @@ btr_cur_update_in_place(
dulint roll_ptr = ut_dulint_zero;
trx_t* trx;
ibool was_delete_marked;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
rec = btr_cur_get_rec(cursor);
index = cursor->index;
trx = thr_get_trx(thr);
-
+ heap = mem_heap_create(100);
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
if (btr_cur_print_record_ops && thr) {
btr_cur_trx_report(trx, index, "update ");
- rec_print(stderr, rec);
+ rec_print_new(stderr, rec, offsets);
}
/* Do lock checking and undo logging */
@@ -1384,6 +1451,9 @@ btr_cur_update_in_place(
thr, &roll_ptr);
if (err != DB_SUCCESS) {
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
@@ -1405,15 +1475,15 @@ btr_cur_update_in_place(
}
if (!(flags & BTR_KEEP_SYS_FLAG)) {
- row_upd_rec_sys_fields(rec, index, trx, roll_ptr);
+ row_upd_rec_sys_fields(rec, index, offsets, trx, roll_ptr);
}
/* FIXME: in a mixed tree, all records may not have enough ordering
fields for btr search: */
- was_delete_marked = rec_get_deleted_flag(rec);
-
- row_upd_rec_in_place(rec, update);
+ was_delete_marked = rec_get_deleted_flag(rec, index->table->comp);
+
+ row_upd_rec_in_place(rec, offsets, update);
if (block->is_hashed) {
rw_lock_x_unlock(&btr_search_latch);
@@ -1421,13 +1491,16 @@ 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)) {
+ if (was_delete_marked && !rec_get_deleted_flag(rec, index->table->comp)) {
/* The new updated record owns its possible externally
stored fields */
- btr_cur_unmark_extern_fields(rec, mtr);
+ btr_cur_unmark_extern_fields(rec, mtr, offsets);
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(DB_SUCCESS);
}
@@ -1469,24 +1542,28 @@ btr_cur_optimistic_update(
mem_heap_t* heap;
ibool reorganized = FALSE;
ulint i;
-
+ ulint* offsets;
+
page = btr_cur_get_page(cursor);
rec = btr_cur_get_rec(cursor);
index = cursor->index;
+ heap = mem_heap_create(1024);
+ offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
+
if (btr_cur_print_record_ops && thr) {
btr_cur_trx_report(thr_get_trx(thr), index, "update ");
- rec_print(stderr, rec);
+ rec_print_new(stderr, rec, offsets);
}
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_X_FIX));
- if (!row_upd_changes_field_size_or_external(rec, index, update)) {
+ if (!row_upd_changes_field_size_or_external(index, offsets, update)) {
/* The simplest and the most common case: the update does not
change the size of any field and none of the updated fields is
externally stored in rec or update */
-
+ mem_heap_free(heap);
return(btr_cur_update_in_place(flags, cursor, update,
cmpl_info, thr, mtr));
}
@@ -1497,29 +1574,30 @@ btr_cur_optimistic_update(
/* Externally stored fields are treated in pessimistic
update */
+ mem_heap_free(heap);
return(DB_OVERFLOW);
}
}
- if (rec_contains_externally_stored_field(btr_cur_get_rec(cursor))) {
+ if (rec_offs_any_extern(offsets)) {
/* Externally stored fields are treated in pessimistic
update */
+ mem_heap_free(heap);
return(DB_OVERFLOW);
}
page_cursor = btr_cur_get_page_cur(cursor);
- heap = mem_heap_create(1024);
-
new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
NULL);
- old_rec_size = rec_get_size(rec);
- new_rec_size = rec_get_converted_size(new_entry);
+ 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() / 2) {
+ if (new_rec_size >=
+ page_get_free_space_of_empty(index->table->comp) / 2) {
mem_heap_free(heap);
@@ -1570,7 +1648,7 @@ btr_cur_optimistic_update(
btr_search_update_hash_on_delete(cursor);
- page_cur_delete_rec(page_cursor, mtr);
+ page_cur_delete_rec(page_cursor, index, offsets, mtr);
page_cur_move_to_prev(page_cursor);
@@ -1587,11 +1665,13 @@ btr_cur_optimistic_update(
ut_a(rec); /* <- We calculated above the insert would fit */
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, index->table->comp)) {
/* The new inserted record owns its possible externally
stored fields */
- btr_cur_unmark_extern_fields(rec, mtr);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ btr_cur_unmark_extern_fields(rec, mtr, offsets);
}
/* Restore the old explicit lock state on the record */
@@ -1690,6 +1770,7 @@ btr_cur_pessimistic_update(
ulint* ext_vect;
ulint n_ext_vect;
ulint reserve_flag;
+ ulint* offsets = NULL;
*big_rec = NULL;
@@ -1743,6 +1824,7 @@ btr_cur_pessimistic_update(
}
heap = mem_heap_create(1024);
+ offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
trx = thr_get_trx(thr);
@@ -1767,28 +1849,29 @@ btr_cur_pessimistic_update(
ut_a(big_rec_vec == NULL);
- btr_rec_free_updated_extern_fields(index, rec, update,
- TRUE, mtr);
+ btr_rec_free_updated_extern_fields(index, rec, offsets,
+ update, TRUE, mtr);
}
/* We have to set appropriate extern storage bits in the new
record to be inserted: we have to remember which fields were such */
- ext_vect = mem_heap_alloc(heap, sizeof(ulint) * rec_get_n_fields(rec));
- n_ext_vect = btr_push_update_extern_fields(ext_vect, rec, update);
-
- if ((rec_get_converted_size(new_entry) >=
- page_get_free_space_of_empty() / 2)
- || (rec_get_converted_size(new_entry) >= REC_MAX_DATA_SIZE)) {
+ 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));
+ 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)) {
big_rec_vec = dtuple_convert_big_rec(index, new_entry,
ext_vect, n_ext_vect);
if (big_rec_vec == NULL) {
- mem_heap_free(heap);
-
err = DB_TOO_BIG_RECORD;
-
goto return_after_reservations;
}
}
@@ -1808,7 +1891,7 @@ btr_cur_pessimistic_update(
btr_search_update_hash_on_delete(cursor);
- page_cur_delete_rec(page_cursor, mtr);
+ page_cur_delete_rec(page_cursor, index, offsets, mtr);
page_cur_move_to_prev(page_cursor);
@@ -1817,21 +1900,22 @@ btr_cur_pessimistic_update(
ut_a(rec || optim_err != DB_UNDERFLOW);
if (rec) {
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
lock_rec_restore_from_page_infimum(rec, page);
- rec_set_field_extern_bits(rec, ext_vect, n_ext_vect, mtr);
+ rec_set_field_extern_bits(rec, index,
+ ext_vect, n_ext_vect, mtr);
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
/* The new inserted record owns its possible externally
stored fields */
-
- btr_cur_unmark_extern_fields(rec, mtr);
+ btr_cur_unmark_extern_fields(rec, mtr, offsets);
}
btr_cur_compress_if_useful(cursor, mtr);
err = DB_SUCCESS;
- mem_heap_free(heap);
-
goto return_after_reservations;
}
@@ -1856,13 +1940,14 @@ btr_cur_pessimistic_update(
ut_a(err == DB_SUCCESS);
ut_a(dummy_big_rec == NULL);
- rec_set_field_extern_bits(rec, ext_vect, n_ext_vect, mtr);
+ rec_set_field_extern_bits(rec, index, ext_vect, n_ext_vect, mtr);
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
/* The new inserted record owns its possible externally
stored fields */
- btr_cur_unmark_extern_fields(rec, mtr);
+ btr_cur_unmark_extern_fields(rec, mtr, offsets);
}
lock_rec_restore_from_page_infimum(rec, page);
@@ -1876,9 +1961,8 @@ btr_cur_pessimistic_update(
btr_cur_pess_upd_restore_supremum(rec, mtr);
}
- mem_heap_free(heap);
-
return_after_reservations:
+ mem_heap_free(heap);
if (n_extents > 0) {
fil_space_release_free_extents(cursor->index->space,
@@ -1908,11 +1992,18 @@ btr_cur_del_mark_set_clust_rec_log(
mtr_t* mtr) /* in: mtr */
{
byte* log_ptr;
+ ut_ad(flags < 256);
+ ut_ad(val <= 1);
- log_ptr = mlog_open(mtr, 30);
+ log_ptr = mlog_open_and_write_index(mtr, rec, index, index->table->comp
+ ? MLOG_COMP_REC_CLUST_DELETE_MARK
+ : MLOG_REC_CLUST_DELETE_MARK,
+ 1 + 1 + DATA_ROLL_PTR_LEN + 14 + 2);
- log_ptr = mlog_write_initial_log_record_fast(rec,
- MLOG_REC_CLUST_DELETE_MARK, log_ptr, mtr);
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash recovery */
+ return;
+ }
mach_write_to_1(log_ptr, flags);
log_ptr++;
@@ -1934,10 +2025,11 @@ index record. */
byte*
btr_cur_parse_del_mark_set_clust_rec(
/*=================================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page) /* in: page or NULL */
+ /* 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 */
{
ulint flags;
ibool val;
@@ -1978,15 +2070,24 @@ btr_cur_parse_del_mark_set_clust_rec(
rec = page + offset;
if (!(flags & BTR_KEEP_SYS_FLAG)) {
- row_upd_rec_sys_fields_in_recovery(rec, pos, trx_id,
- roll_ptr);
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ row_upd_rec_sys_fields_in_recovery(rec,
+ rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap),
+ pos, trx_id, roll_ptr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
/* We do not need to reserve btr_search_latch, as the page
is only being recovered, and there cannot be a hash index to
it. */
- rec_set_deleted_flag(rec, val);
+ rec_set_deleted_flag(rec, index->table->comp, val);
}
return(ptr);
@@ -2015,22 +2116,31 @@ btr_cur_del_mark_set_clust_rec(
ulint err;
rec_t* rec;
trx_t* trx;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
rec = btr_cur_get_rec(cursor);
index = cursor->index;
-
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
if (btr_cur_print_record_ops && thr) {
btr_cur_trx_report(thr_get_trx(thr), index, "del mark ");
- rec_print(stderr, rec);
+ rec_print_new(stderr, rec, offsets);
}
ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(rec_get_deleted_flag(rec) == FALSE);
+ ut_ad(rec_get_deleted_flag(rec, index->table->comp) == FALSE);
- err = lock_clust_rec_modify_check_and_lock(flags, rec, index, thr);
+ err = lock_clust_rec_modify_check_and_lock(flags,
+ rec, index, offsets, thr);
if (err != DB_SUCCESS) {
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
@@ -2039,6 +2149,9 @@ btr_cur_del_mark_set_clust_rec(
&roll_ptr);
if (err != DB_SUCCESS) {
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
@@ -2048,13 +2161,12 @@ btr_cur_del_mark_set_clust_rec(
rw_lock_x_lock(&btr_search_latch);
}
- rec_set_deleted_flag(rec, val);
+ rec_set_deleted_flag(rec, index->table->comp, val);
trx = thr_get_trx(thr);
if (!(flags & BTR_KEEP_SYS_FLAG)) {
-
- row_upd_rec_sys_fields(rec, index, trx, roll_ptr);
+ row_upd_rec_sys_fields(rec, index, offsets, trx, roll_ptr);
}
if (block->is_hashed) {
@@ -2063,6 +2175,9 @@ 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) {
+ mem_heap_free(heap);
+ }
return(DB_SUCCESS);
}
@@ -2073,16 +2188,24 @@ UNIV_INLINE
void
btr_cur_del_mark_set_sec_rec_log(
/*=============================*/
- rec_t* rec, /* in: record */
- ibool val, /* in: value to set */
- mtr_t* mtr) /* in: mtr */
+ 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(mtr, 30);
+ 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_write_initial_log_record_fast(rec,
- MLOG_REC_SEC_DELETE_MARK, log_ptr, mtr);
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash recovery:
+ in that case mlog_open returns NULL */
+ return;
+ }
mach_write_to_1(log_ptr, val);
log_ptr++;
@@ -2100,10 +2223,11 @@ index record. */
byte*
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 */
- page_t* page) /* in: page or NULL */
+ /* 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 offset;
@@ -2129,7 +2253,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, val);
+ rec_set_deleted_flag(rec, index->table->comp, val);
}
return(ptr);
@@ -2158,7 +2282,7 @@ btr_cur_del_mark_set_sec_rec(
if (btr_cur_print_record_ops && thr) {
btr_cur_trx_report(thr_get_trx(thr), cursor->index,
"del mark ");
- rec_print(stderr, rec);
+ rec_print(stderr, rec, cursor->index);
}
err = lock_sec_rec_modify_check_and_lock(flags, rec, cursor->index,
@@ -2174,13 +2298,13 @@ btr_cur_del_mark_set_sec_rec(
rw_lock_x_lock(&btr_search_latch);
}
- rec_set_deleted_flag(rec, val);
+ rec_set_deleted_flag(rec, cursor->index->table->comp, val);
if (block->is_hashed) {
rw_lock_x_unlock(&btr_search_latch);
}
- btr_cur_del_mark_set_sec_rec_log(rec, val, mtr);
+ btr_cur_del_mark_set_sec_rec_log(rec, cursor->index, val, mtr);
return(DB_SUCCESS);
}
@@ -2192,15 +2316,16 @@ used by the insert buffer insert merge mechanism. */
void
btr_cur_del_unmark_for_ibuf(
/*========================*/
- rec_t* rec, /* in: record to delete unmark */
- mtr_t* mtr) /* in: mtr */
+ 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, FALSE);
+ rec_set_deleted_flag(rec, index->table->comp, FALSE);
- btr_cur_del_mark_set_sec_rec_log(rec, FALSE, mtr);
+ btr_cur_del_mark_set_sec_rec_log(rec, index, FALSE, mtr);
}
/*==================== B-TREE RECORD REMOVE =========================*/
@@ -2279,8 +2404,14 @@ btr_cur_optimistic_delete(
successor of the deleted record */
mtr_t* mtr) /* in: mtr */
{
- page_t* page;
- ulint max_ins_size;
+ page_t* page;
+ ulint max_ins_size;
+ rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ ibool no_compress_needed;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_page(cursor)),
MTR_MEMO_PAGE_X_FIX));
@@ -2290,27 +2421,34 @@ btr_cur_optimistic_delete(
ut_ad(btr_page_get_level(page, mtr) == 0);
- if (rec_contains_externally_stored_field(btr_cur_get_rec(cursor))) {
+ rec = btr_cur_get_rec(cursor);
+ offsets = rec_get_offsets(rec, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
- return(FALSE);
- }
+ no_compress_needed = !rec_offs_any_extern(offsets)
+ && btr_cur_can_delete_without_compress(
+ cursor, rec_offs_size(offsets), mtr);
- if (btr_cur_can_delete_without_compress(cursor, mtr)) {
+ if (no_compress_needed) {
- lock_update_delete(btr_cur_get_rec(cursor));
+ lock_update_delete(rec);
btr_search_update_hash_on_delete(cursor);
max_ins_size = page_get_max_insert_size_after_reorganize(page,
1);
- page_cur_delete_rec(btr_cur_get_page_cur(cursor), mtr);
+ page_cur_delete_rec(btr_cur_get_page_cur(cursor),
+ cursor->index, offsets, mtr);
ibuf_update_free_bits_low(cursor->index, page, max_ins_size,
mtr);
- return(TRUE);
}
- return(FALSE);
+ if (heap) {
+ mem_heap_free(heap);
+ }
+
+ return(no_compress_needed);
}
/*****************************************************************
@@ -2350,6 +2488,7 @@ btr_cur_pessimistic_delete(
ibool success;
ibool ret = FALSE;
mem_heap_t* heap;
+ ulint* offsets;
page = btr_cur_get_page(cursor);
tree = btr_cur_get_tree(cursor);
@@ -2375,8 +2514,21 @@ btr_cur_pessimistic_delete(
}
}
- btr_rec_free_externally_stored_fields(cursor->index,
- btr_cur_get_rec(cursor), in_rollback, mtr);
+ heap = mem_heap_create(1024);
+ rec = btr_cur_get_rec(cursor);
+
+ offsets = rec_get_offsets(rec, cursor->index,
+ NULL, ULINT_UNDEFINED, &heap);
+
+ /* 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
+ ? !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))
@@ -2393,8 +2545,6 @@ btr_cur_pessimistic_delete(
goto return_after_reservations;
}
- rec = btr_cur_get_rec(cursor);
-
lock_update_delete(rec);
if ((btr_page_get_level(page, mtr) > 0)
@@ -2406,7 +2556,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), mtr);
+ btr_set_min_rec_mark(page_rec_get_next(rec),
+ cursor->index->table->comp, mtr);
} else {
/* Otherwise, if we delete the leftmost node pointer
on a page, we have to change the father node pointer
@@ -2415,8 +2566,6 @@ btr_cur_pessimistic_delete(
btr_node_ptr_delete(tree, page, mtr);
- heap = mem_heap_create(256);
-
node_ptr = dict_tree_build_node_ptr(
tree, page_rec_get_next(rec),
buf_frame_get_page_no(page),
@@ -2425,20 +2574,20 @@ btr_cur_pessimistic_delete(
btr_insert_on_non_leaf_level(tree,
btr_page_get_level(page, mtr) + 1,
node_ptr, mtr);
-
- mem_heap_free(heap);
}
}
btr_search_update_hash_on_delete(cursor);
- page_cur_delete_rec(btr_cur_get_page_cur(cursor), mtr);
+ page_cur_delete_rec(btr_cur_get_page_cur(cursor), cursor->index,
+ offsets, mtr);
ut_ad(btr_check_node_ptr(tree, page, mtr));
*err = DB_SUCCESS;
return_after_reservations:
+ mem_heap_free(heap);
if (ret == FALSE) {
ret = btr_cur_compress_if_useful(cursor, mtr);
@@ -2663,6 +2812,13 @@ btr_estimate_number_of_different_key_vals(
ulint j;
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_;
n_cols = dict_index_get_n_unique(index);
@@ -2697,10 +2853,16 @@ btr_estimate_number_of_different_key_vals(
while (rec != page_get_supremum_rec(page)
&& page_rec_get_next(rec)
!= page_get_supremum_rec(page)) {
+ rec_t* next_rec = page_rec_get_next(rec);
matched_fields = 0;
matched_bytes = 0;
+ offsets1 = rec_get_offsets(rec, index, offsets1,
+ ULINT_UNDEFINED, &heap);
+ offsets2 = rec_get_offsets(next_rec, index, offsets2,
+ n_cols, &heap);
- cmp_rec_rec_with_match(rec, page_rec_get_next(rec),
+ cmp_rec_rec_with_match(rec, next_rec,
+ offsets1, offsets2,
index, &matched_fields,
&matched_bytes);
@@ -2712,7 +2874,8 @@ btr_estimate_number_of_different_key_vals(
}
total_external_size +=
- btr_rec_get_externally_stored_len(rec);
+ btr_rec_get_externally_stored_len(
+ rec, offsets1);
rec = page_rec_get_next(rec);
}
@@ -2736,8 +2899,11 @@ btr_estimate_number_of_different_key_vals(
}
}
+ offsets1 = rec_get_offsets(rec, index, offsets1,
+ ULINT_UNDEFINED, &heap);
total_external_size +=
- btr_rec_get_externally_stored_len(rec);
+ btr_rec_get_externally_stored_len(rec,
+ offsets1);
mtr_commit(&mtr);
}
@@ -2778,6 +2944,9 @@ btr_estimate_number_of_different_key_vals(
}
mem_free(n_diff);
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
@@ -2788,9 +2957,10 @@ static
ulint
btr_rec_get_externally_stored_len(
/*==============================*/
- /* out: externally stored part, in units of a
- database page */
- rec_t* rec) /* in: record */
+ /* out: externally stored part,
+ in units of a database page */
+ rec_t* rec, /* in: record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
ulint n_fields;
byte* data;
@@ -2799,17 +2969,13 @@ btr_rec_get_externally_stored_len(
ulint total_extern_len = 0;
ulint i;
- if (rec_get_data_size(rec) <= REC_1BYTE_OFFS_LIMIT) {
-
- return(0);
- }
-
- n_fields = rec_get_n_fields(rec);
+ ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
+ n_fields = rec_offs_n_fields(offsets);
for (i = 0; i < n_fields; i++) {
- if (rec_get_nth_field_extern_bit(rec, i)) {
+ if (rec_offs_nth_extern(offsets, i)) {
- data = rec_get_nth_field(rec, i, &local_len);
+ data = rec_get_nth_field(rec, offsets, i, &local_len);
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
@@ -2830,16 +2996,17 @@ static
void
btr_cur_set_ownership_of_extern_field(
/*==================================*/
- rec_t* rec, /* in: clustered index record */
- ulint i, /* in: field number */
- ibool val, /* in: value to set */
- mtr_t* mtr) /* in: mtr */
+ rec_t* rec, /* in: clustered index record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint i, /* in: field number */
+ ibool val, /* in: value to set */
+ mtr_t* mtr) /* in: mtr */
{
byte* data;
ulint local_len;
ulint byte_val;
- data = rec_get_nth_field(rec, i, &local_len);
+ data = rec_get_nth_field(rec, offsets, i, &local_len);
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
@@ -2866,19 +3033,22 @@ to free the field. */
void
btr_cur_mark_extern_inherited_fields(
/*=================================*/
- rec_t* rec, /* in: record in a clustered index */
- upd_t* update, /* in: update vector */
- mtr_t* mtr) /* in: mtr */
+ rec_t* rec, /* in: record in a clustered index */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ upd_t* update, /* in: update vector */
+ mtr_t* mtr) /* in: mtr */
{
ibool is_updated;
ulint n;
ulint j;
ulint i;
-
- n = rec_get_n_fields(rec);
+
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
+ n = rec_offs_n_fields(offsets);
for (i = 0; i < n; i++) {
- if (rec_get_nth_field_extern_bit(rec, i)) {
+ if (rec_offs_nth_extern(offsets, i)) {
/* Check it is not in updated fields */
is_updated = FALSE;
@@ -2894,8 +3064,8 @@ btr_cur_mark_extern_inherited_fields(
}
if (!is_updated) {
- btr_cur_set_ownership_of_extern_field(rec, i,
- FALSE, mtr);
+ btr_cur_set_ownership_of_extern_field(rec,
+ offsets, i, FALSE, mtr);
}
}
}
@@ -2967,18 +3137,20 @@ static
void
btr_cur_unmark_extern_fields(
/*=========================*/
- rec_t* rec, /* in: record in a clustered index */
- mtr_t* mtr) /* in: mtr */
+ rec_t* rec, /* in: record in a clustered index */
+ mtr_t* mtr, /* in: mtr */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
ulint n;
ulint i;
- n = rec_get_n_fields(rec);
+ ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
+ n = rec_offs_n_fields(offsets);
for (i = 0; i < n; i++) {
- if (rec_get_nth_field_extern_bit(rec, i)) {
-
- btr_cur_set_ownership_of_extern_field(rec, i,
+ if (rec_offs_nth_extern(offsets, i)) {
+
+ btr_cur_set_ownership_of_extern_field(rec, offsets, i,
TRUE, mtr);
}
}
@@ -3028,10 +3200,10 @@ ulint
btr_push_update_extern_fields(
/*==========================*/
/* out: number of values stored in ext_vect */
- ulint* ext_vect, /* in: array of ulints, must be preallocated
+ ulint* ext_vect,/* in: array of ulints, must be preallocated
to have space for all fields in rec */
- rec_t* rec, /* in: record */
- upd_t* update) /* in: update vector or NULL */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ upd_t* update) /* in: update vector or NULL */
{
ulint n_pushed = 0;
ibool is_updated;
@@ -3054,10 +3226,10 @@ btr_push_update_extern_fields(
}
}
- n = rec_get_n_fields(rec);
+ n = rec_offs_n_fields(offsets);
for (i = 0; i < n; i++) {
- if (rec_get_nth_field_extern_bit(rec, i)) {
+ if (rec_offs_nth_extern(offsets, i)) {
/* Check it is not in updated fields */
is_updated = FALSE;
@@ -3119,6 +3291,7 @@ btr_store_big_rec_extern_fields(
dict_index_t* index, /* in: index of rec; the index tree
MUST be X-latched */
rec_t* rec, /* in: record */
+ const ulint* offsets, /* in: rec_get_offsets(rec, index) */
big_rec_t* big_rec_vec, /* in: vector containing fields
to be stored externally */
mtr_t* local_mtr __attribute__((unused))) /* in: mtr
@@ -3139,6 +3312,7 @@ btr_store_big_rec_extern_fields(
ulint i;
mtr_t mtr;
+ ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(mtr_memo_contains(local_mtr, dict_tree_get_lock(index->tree),
MTR_MEMO_X_LOCK));
ut_ad(mtr_memo_contains(local_mtr, buf_block_align(rec),
@@ -3152,8 +3326,8 @@ btr_store_big_rec_extern_fields(
for (i = 0; i < big_rec_vec->n_fields; i++) {
- data = rec_get_nth_field(rec, big_rec_vec->fields[i].field_no,
- &local_len);
+ data = rec_get_nth_field(rec, offsets,
+ big_rec_vec->fields[i].field_no, &local_len);
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
extern_len = big_rec_vec->fields[i].len;
@@ -3254,7 +3428,7 @@ btr_store_big_rec_extern_fields(
/* Set the bit denoting that this field
in rec is stored externally */
- rec_set_nth_field_extern_bit(rec,
+ rec_set_nth_field_extern_bit(rec, index,
big_rec_vec->fields[i].field_no,
TRUE, &mtr);
}
@@ -3407,6 +3581,7 @@ btr_rec_free_externally_stored_fields(
dict_index_t* index, /* in: index of the data, the index
tree MUST be X-latched */
rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
inherited fields */
@@ -3419,21 +3594,18 @@ btr_rec_free_externally_stored_fields(
ulint len;
ulint i;
+ ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(mtr_memo_contains(mtr, buf_block_align(rec),
MTR_MEMO_PAGE_X_FIX));
- if (rec_get_data_size(rec) <= REC_1BYTE_OFFS_LIMIT) {
-
- return;
- }
-
/* Free possible externally stored fields in the record */
- n_fields = rec_get_n_fields(rec);
+ ut_ad(index->table->comp == rec_offs_comp(offsets));
+ n_fields = rec_offs_n_fields(offsets);
for (i = 0; i < n_fields; i++) {
- if (rec_get_nth_field_extern_bit(rec, i)) {
+ if (rec_offs_nth_extern(offsets, i)) {
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field(rec, offsets, i, &len);
btr_free_externally_stored_field(index, data, len,
do_not_free_inherited, mtr);
}
@@ -3450,6 +3622,7 @@ btr_rec_free_updated_extern_fields(
dict_index_t* index, /* in: index of rec; the index tree MUST be
X-latched */
rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
upd_t* update, /* in: update vector */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
@@ -3463,13 +3636,10 @@ btr_rec_free_updated_extern_fields(
ulint len;
ulint i;
+ ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(mtr_memo_contains(mtr, buf_block_align(rec),
MTR_MEMO_PAGE_X_FIX));
- if (rec_get_data_size(rec) <= REC_1BYTE_OFFS_LIMIT) {
- return;
- }
-
/* Free possible externally stored fields in the record */
n_fields = upd_get_n_fields(update);
@@ -3477,9 +3647,10 @@ btr_rec_free_updated_extern_fields(
for (i = 0; i < n_fields; i++) {
ufield = upd_get_nth_field(update, i);
- if (rec_get_nth_field_extern_bit(rec, ufield->field_no)) {
+ if (rec_offs_nth_extern(offsets, ufield->field_no)) {
- data = rec_get_nth_field(rec, ufield->field_no, &len);
+ data = rec_get_nth_field(rec, offsets,
+ ufield->field_no, &len);
btr_free_externally_stored_field(index, data, len,
do_not_free_inherited, mtr);
}
@@ -3583,7 +3754,8 @@ byte*
btr_rec_copy_externally_stored_field(
/*=================================*/
/* out: the field copied to heap */
- rec_t* rec, /* in: record */
+ rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint no, /* in: field number */
ulint* len, /* out: length of the field */
mem_heap_t* heap) /* in: mem heap */
@@ -3591,7 +3763,8 @@ btr_rec_copy_externally_stored_field(
ulint local_len;
byte* data;
- ut_a(rec_get_nth_field_extern_bit(rec, no));
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_a(rec_offs_nth_extern(offsets, no));
/* An externally stored field can contain some initial
data from the field, and in the last 20 bytes it has the
@@ -3602,7 +3775,7 @@ btr_rec_copy_externally_stored_field(
limit so that field offsets are stored in two bytes, and
the extern bit is available in those two bytes. */
- data = rec_get_nth_field(rec, no, &local_len);
+ data = rec_get_nth_field(rec, offsets, no, &local_len);
return(btr_copy_externally_stored_field(len, data, local_len, heap));
}
diff --git a/innobase/btr/btr0pcur.c b/innobase/btr/btr0pcur.c
index 0dcf6c2f3fc..74feff8653c 100644
--- a/innobase/btr/btr0pcur.c
+++ b/innobase/btr/btr0pcur.c
@@ -46,12 +46,12 @@ btr_pcur_free_for_mysql(
mem_free(cursor->old_rec_buf);
- cursor->old_rec = NULL;
cursor->old_rec_buf = NULL;
}
cursor->btr_cur.page_cur.rec = NULL;
cursor->old_rec = NULL;
+ cursor->old_n_fields = 0;
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
cursor->latch_mode = BTR_NO_LATCHES;
@@ -134,9 +134,10 @@ btr_pcur_store_position(
cursor->old_stored = BTR_PCUR_OLD_STORED;
cursor->old_rec = dict_tree_copy_rec_order_prefix(tree, rec,
- &(cursor->old_rec_buf),
- &(cursor->buf_size));
-
+ &cursor->old_n_fields,
+ &cursor->old_rec_buf,
+ &cursor->buf_size);
+
cursor->block_when_stored = buf_block_align(page);
cursor->modify_clock = buf_frame_get_modify_clock(page);
}
@@ -167,6 +168,8 @@ btr_pcur_copy_stored_position(
pcur_receive->old_rec = pcur_receive->old_rec_buf
+ (pcur_donate->old_rec - pcur_donate->old_rec_buf);
}
+
+ pcur_receive->old_n_fields = pcur_donate->old_n_fields;
}
/******************************************************************
@@ -236,6 +239,7 @@ btr_pcur_restore_position(
}
ut_a(cursor->old_rec);
+ ut_a(cursor->old_n_fields);
page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor));
@@ -250,17 +254,31 @@ btr_pcur_restore_position(
buf_page_dbg_add_level(page, SYNC_TREE_NODE);
#endif /* UNIV_SYNC_DEBUG */
if (cursor->rel_pos == BTR_PCUR_ON) {
-
+#ifdef UNIV_DEBUG
+ rec_t* rec;
+ ulint* offsets1;
+ ulint* offsets2;
+ dict_index_t* index;
+#endif /* UNIV_DEBUG */
cursor->latch_mode = latch_mode;
-
- ut_ad(cmp_rec_rec(cursor->old_rec,
- btr_pcur_get_rec(cursor),
- dict_tree_find_index(
- btr_cur_get_tree(
+#ifdef UNIV_DEBUG
+ rec = btr_pcur_get_rec(cursor);
+ index = dict_tree_find_index(
+ btr_cur_get_tree(
btr_pcur_get_btr_cur(cursor)),
- btr_pcur_get_rec(cursor)))
- == 0);
+ rec);
+
+ heap = mem_heap_create(256);
+ offsets1 = rec_get_offsets(cursor->old_rec,
+ index, NULL,
+ cursor->old_n_fields, &heap);
+ offsets2 = rec_get_offsets(rec, index, NULL,
+ cursor->old_n_fields, &heap);
+ ut_ad(cmp_rec_rec(cursor->old_rec,
+ rec, offsets1, offsets2, index) == 0);
+ mem_heap_free(heap);
+#endif /* UNIV_DEBUG */
return(TRUE);
}
@@ -273,7 +291,8 @@ btr_pcur_restore_position(
heap = mem_heap_create(256);
tree = btr_cur_get_tree(btr_pcur_get_btr_cur(cursor));
- tuple = dict_tree_build_data_tuple(tree, cursor->old_rec, heap);
+ tuple = dict_tree_build_data_tuple(tree, cursor->old_rec,
+ cursor->old_n_fields, heap);
/* Save the old search mode of the cursor */
old_mode = cursor->search_mode;
@@ -295,7 +314,10 @@ btr_pcur_restore_position(
if (cursor->rel_pos == BTR_PCUR_ON
&& btr_pcur_is_on_user_rec(cursor, mtr)
- && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor))) {
+ && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor),
+ rec_get_offsets(btr_pcur_get_rec(cursor),
+ btr_pcur_get_btr_cur(cursor)->index,
+ NULL, ULINT_UNDEFINED, &heap))) {
/* We have to store the NEW value for the modify clock, since
the cursor can now be on a different page! But we can retain
@@ -384,6 +406,7 @@ btr_pcur_move_to_next_page(
ut_ad(next_page_no != FIL_NULL);
next_page = btr_page_get(space, next_page_no, cursor->latch_mode, mtr);
+ ut_a(page_is_comp(next_page) == page_is_comp(page));
buf_block_align(next_page)->check_index_page_at_flush = TRUE;
btr_leaf_page_release(page, cursor->latch_mode, mtr);
diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c
index 9384168df88..97fdce2df75 100644
--- a/innobase/btr/btr0sea.c
+++ b/innobase/btr/btr0sea.c
@@ -411,11 +411,17 @@ btr_search_update_hash_ref(
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|| rw_lock_own(&(block->lock), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
+ ut_ad(buf_block_align(btr_cur_get_rec(cursor)) == block);
+ ut_a(!block->is_hashed || block->index == cursor->index);
+
if (block->is_hashed
&& (info->n_hash_potential > 0)
&& (block->curr_n_fields == info->n_fields)
&& (block->curr_n_bytes == info->n_bytes)
&& (block->curr_side == info->side)) {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
rec = btr_cur_get_rec(cursor);
@@ -425,10 +431,13 @@ btr_search_update_hash_ref(
}
tree_id = ((cursor->index)->tree)->id;
-
- fold = rec_fold(rec, block->curr_n_fields,
- block->curr_n_bytes, tree_id);
-
+ 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) {
+ mem_heap_free(heap);
+ }
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
@@ -535,15 +544,20 @@ 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;
- int cmp;
-
+ page_t* page;
+ rec_t* rec;
+ rec_t* prev_rec;
+ rec_t* next_rec;
+ ulint n_unique;
+ ulint match;
+ ulint bytes;
+ int cmp;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ ibool success = FALSE;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
n_unique = dict_index_get_n_unique_in_tree(cursor->index);
rec = btr_cur_get_rec(cursor);
@@ -554,45 +568,43 @@ btr_search_check_guess(
match = 0;
bytes = 0;
- cmp = page_cmp_dtuple_rec_with_match(tuple, rec, &match, &bytes);
+ offsets = rec_get_offsets(rec, cursor->index, offsets,
+ n_unique, &heap);
+ cmp = page_cmp_dtuple_rec_with_match(tuple, rec,
+ offsets, &match, &bytes);
if (mode == PAGE_CUR_GE) {
if (cmp == 1) {
-
- return(FALSE);
+ goto exit_func;
}
cursor->up_match = match;
if (match >= n_unique) {
-
- return(TRUE);
+ success = TRUE;
+ goto exit_func;
}
} else if (mode == PAGE_CUR_LE) {
if (cmp == -1) {
-
- return(FALSE);
+ goto exit_func;
}
cursor->low_match = match;
} else if (mode == PAGE_CUR_G) {
if (cmp != -1) {
-
- return(FALSE);
+ goto exit_func;
}
} else if (mode == PAGE_CUR_L) {
if (cmp != 1) {
-
- return(FALSE);
+ goto exit_func;
}
}
if (can_only_compare_to_cursor_rec) {
/* Since we could not determine if our guess is right just by
looking at the record under the cursor, return FALSE */
-
- return(FALSE);
+ goto exit_func;
}
match = 0;
@@ -605,30 +617,21 @@ btr_search_check_guess(
prev_rec = page_rec_get_prev(rec);
if (prev_rec == page_get_infimum_rec(page)) {
-
- if (btr_page_get_prev(page, mtr) != FIL_NULL) {
-
- return(FALSE);
- }
-
- return(TRUE);
+ success = btr_page_get_prev(page, mtr) == FIL_NULL;
+ goto exit_func;
}
+ offsets = rec_get_offsets(prev_rec, cursor->index, offsets,
+ n_unique, &heap);
cmp = page_cmp_dtuple_rec_with_match(tuple, prev_rec,
- &match, &bytes);
+ offsets, &match, &bytes);
if (mode == PAGE_CUR_GE) {
- if (cmp != 1) {
-
- return(FALSE);
- }
+ success = cmp == 1;
} else {
- if (cmp == -1) {
-
- return(FALSE);
- }
+ success = cmp != -1;
}
- return(TRUE);
+ goto exit_func;
}
ut_ad(rec != page_get_supremum_rec(page));
@@ -636,34 +639,30 @@ btr_search_check_guess(
next_rec = page_rec_get_next(rec);
if (next_rec == page_get_supremum_rec(page)) {
-
if (btr_page_get_next(page, mtr) == FIL_NULL) {
cursor->up_match = 0;
-
- return(TRUE);
+ success = TRUE;
}
- return(FALSE);
+ goto exit_func;
}
- cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec, &match, &bytes);
-
+ 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) {
- if (cmp != -1) {
-
- return(FALSE);
- }
-
+ success = cmp == -1;
cursor->up_match = match;
} else {
- if (cmp == 1) {
-
- return(FALSE);
- }
+ success = cmp != 1;
}
-
- return(TRUE);
+exit_func:
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(success);
}
/**********************************************************************
@@ -926,6 +925,8 @@ btr_search_drop_page_hash_index(
ulint n_recs;
ulint* folds;
ulint i;
+ mem_heap_t* heap;
+ ulint* offsets;
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
@@ -973,10 +974,10 @@ btr_search_drop_page_hash_index(
rec = page_rec_get_next(rec);
if (rec != sup) {
- ut_a(n_fields <= rec_get_n_fields(rec));
+ ut_a(n_fields <= rec_get_n_fields(rec, block->index));
if (n_bytes > 0) {
- ut_a(n_fields < rec_get_n_fields(rec));
+ ut_a(n_fields < rec_get_n_fields(rec, block->index));
}
}
@@ -984,11 +985,15 @@ btr_search_drop_page_hash_index(
prev_fold = 0;
+ heap = NULL;
+ offsets = NULL;
+
while (rec != sup) {
/* FIXME: in a mixed tree, not all records may have enough
ordering fields: */
-
- fold = rec_fold(rec, n_fields, n_bytes, tree_id);
+ offsets = rec_get_offsets(rec, block->index,
+ offsets, n_fields + (n_bytes > 0), &heap);
+ fold = rec_fold(rec, offsets, n_fields, n_bytes, tree_id);
if (fold == prev_fold && prev_fold != 0) {
@@ -1005,6 +1010,10 @@ next_rec:
prev_fold = fold;
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
+
rw_lock_x_lock(&btr_search_latch);
for (i = 0; i < n_cached; i++) {
@@ -1013,6 +1022,7 @@ next_rec:
}
block->is_hashed = FALSE;
+ block->index = NULL;
rw_lock_x_unlock(&btr_search_latch);
@@ -1069,8 +1079,7 @@ static
void
btr_search_build_page_hash_index(
/*=============================*/
- dict_index_t* index, /* in: index for which to build, or NULL if
- not known */
+ dict_index_t* index, /* in: index for which to build */
page_t* page, /* in: index page, s- or x-latched */
ulint n_fields,/* in: hash this many full fields */
ulint n_bytes,/* in: hash this many bytes from the next
@@ -1090,7 +1099,13 @@ btr_search_build_page_hash_index(
ulint* folds;
rec_t** recs;
ulint i;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ ut_ad(index);
+
block = buf_block_align(page);
table = btr_search_sys->hash_index;
@@ -1127,9 +1142,9 @@ btr_search_build_page_hash_index(
return;
}
- if (index && (dict_index_get_n_unique_in_tree(index) < n_fields
+ if (dict_index_get_n_unique_in_tree(index) < n_fields
|| (dict_index_get_n_unique_in_tree(index) == n_fields
- && n_bytes > 0))) {
+ && n_bytes > 0)) {
return;
}
@@ -1148,18 +1163,20 @@ btr_search_build_page_hash_index(
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) {
- ut_a(n_fields <= rec_get_n_fields(rec));
+ ut_a(n_fields <= rec_offs_n_fields(offsets));
if (n_bytes > 0) {
- ut_a(n_fields < rec_get_n_fields(rec));
+ ut_a(n_fields < rec_offs_n_fields(offsets));
}
}
/* FIXME: in a mixed tree, all records may not have enough ordering
fields: */
-
- fold = rec_fold(rec, n_fields, n_bytes, tree_id);
+ fold = rec_fold(rec, offsets, n_fields, n_bytes, tree_id);
if (side == BTR_SEARCH_LEFT_SIDE) {
@@ -1183,7 +1200,10 @@ btr_search_build_page_hash_index(
break;
}
- next_fold = rec_fold(next_rec, n_fields, n_bytes, tree_id);
+ offsets = rec_get_offsets(next_rec, index, offsets,
+ n_fields + (n_bytes > 0), &heap);
+ next_fold = rec_fold(next_rec, offsets, n_fields,
+ n_bytes, tree_id);
if (fold != next_fold) {
/* Insert an entry into the hash index */
@@ -1211,13 +1231,7 @@ btr_search_build_page_hash_index(
if (block->is_hashed && ((block->curr_n_fields != n_fields)
|| (block->curr_n_bytes != n_bytes)
|| (block->curr_side != side))) {
-
- rw_lock_x_unlock(&btr_search_latch);
-
- mem_free(folds);
- mem_free(recs);
-
- return;
+ goto exit_func;
}
block->is_hashed = TRUE;
@@ -1226,16 +1240,21 @@ btr_search_build_page_hash_index(
block->curr_n_fields = n_fields;
block->curr_n_bytes = n_bytes;
block->curr_side = side;
+ block->index = index;
for (i = 0; i < n_cached; i++) {
ha_insert_for_fold(table, folds[i], recs[i]);
}
+exit_func:
rw_lock_x_unlock(&btr_search_latch);
mem_free(folds);
mem_free(recs);
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
/************************************************************************
@@ -1247,10 +1266,13 @@ parameters as page (this often happens when a page is split). */
void
btr_search_move_or_delete_hash_entries(
/*===================================*/
- page_t* new_page, /* in: records are copied to this page */
- page_t* page) /* in: index page from which records were
- copied, and the copied records will be deleted
- from this page */
+ page_t* new_page, /* in: records are copied
+ to this page */
+ page_t* page, /* in: index page from which
+ records were copied, and the
+ copied records will be deleted
+ from this page */
+ dict_index_t* index) /* in: record descriptor */
{
buf_block_t* block;
buf_block_t* new_block;
@@ -1260,11 +1282,14 @@ btr_search_move_or_delete_hash_entries(
block = buf_block_align(page);
new_block = buf_block_align(new_page);
+ ut_a(page_is_comp(page) == page_is_comp(new_page));
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
+ ut_a(!new_block->is_hashed || new_block->index == index);
+ ut_a(!block->is_hashed || block->index == index);
rw_lock_s_lock(&btr_search_latch);
@@ -1290,8 +1315,8 @@ btr_search_move_or_delete_hash_entries(
rw_lock_s_unlock(&btr_search_latch);
ut_a(n_fields + n_bytes > 0);
-
- btr_search_build_page_hash_index(NULL, new_page, n_fields,
+
+ btr_search_build_page_hash_index(index, new_page, n_fields,
n_bytes, side);
ut_a(n_fields == block->curr_n_fields);
ut_a(n_bytes == block->curr_n_bytes);
@@ -1319,6 +1344,9 @@ btr_search_update_hash_on_delete(
ulint fold;
dulint tree_id;
ibool found;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ mem_heap_t* heap = NULL;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
rec = btr_cur_get_rec(cursor);
@@ -1333,14 +1361,18 @@ btr_search_update_hash_on_delete(
return;
}
+ ut_a(block->index == cursor->index);
ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
table = btr_search_sys->hash_index;
tree_id = cursor->index->tree->id;
-
- fold = rec_fold(rec, block->curr_n_fields, block->curr_n_bytes,
- tree_id);
+ 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) {
+ mem_heap_free(heap);
+ }
rw_lock_x_lock(&btr_search_latch);
found = ha_search_and_delete_if_found(table, fold, rec);
@@ -1376,6 +1408,8 @@ btr_search_update_hash_node_on_insert(
return;
}
+ ut_a(block->index == cursor->index);
+
rw_lock_x_lock(&btr_search_latch);
if ((cursor->flag == BTR_CUR_HASH)
@@ -1420,7 +1454,11 @@ btr_search_update_hash_on_insert(
ulint n_fields;
ulint n_bytes;
ulint side;
- ibool locked = FALSE;
+ ibool locked = FALSE;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
table = btr_search_sys->hash_index;
@@ -1439,6 +1477,8 @@ btr_search_update_hash_on_insert(
return;
}
+ ut_a(block->index == cursor->index);
+
tree_id = ((cursor->index)->tree)->id;
n_fields = block->curr_n_fields;
@@ -1449,15 +1489,21 @@ btr_search_update_hash_on_insert(
next_rec = page_rec_get_next(ins_rec);
page = buf_frame_align(rec);
-
- ins_fold = rec_fold(ins_rec, n_fields, n_bytes, tree_id);
+ 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)) {
- next_fold = rec_fold(next_rec, n_fields, n_bytes, tree_id);
+ 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)) {
- fold = rec_fold(rec, n_fields, n_bytes, tree_id);
+ 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);
} else {
if (side == BTR_SEARCH_LEFT_SIDE) {
@@ -1527,6 +1573,9 @@ check_next_rec:
}
function_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
if (locked) {
rw_lock_x_unlock(&btr_search_latch);
}
@@ -1546,6 +1595,10 @@ btr_search_validate(void)
ulint n_page_dumps = 0;
ibool ok = TRUE;
ulint i;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
rw_lock_x_lock(&btr_search_latch);
@@ -1555,9 +1608,14 @@ btr_search_validate(void)
while (node != NULL) {
block = buf_block_align(node->data);
page = buf_frame_align(node->data);
+ offsets = rec_get_offsets((rec_t*) node->data,
+ block->index, offsets,
+ block->curr_n_fields
+ + (block->curr_n_bytes > 0), &heap);
if (!block->is_hashed
|| node->fold != rec_fold((rec_t*)(node->data),
+ offsets,
block->curr_n_fields,
block->curr_n_bytes,
btr_page_get_index_id(page))) {
@@ -1573,12 +1631,14 @@ btr_search_validate(void)
(ulong) ut_dulint_get_low(btr_page_get_index_id(page)),
(ulong) node->fold,
(ulong) rec_fold((rec_t*)(node->data),
+ offsets,
block->curr_n_fields,
block->curr_n_bytes,
btr_page_get_index_id(page)));
fputs("InnoDB: Record ", stderr);
- rec_print(stderr, (rec_t*)(node->data));
+ rec_print_new(stderr, (rec_t*)node->data,
+ offsets);
fprintf(stderr, "\nInnoDB: on that page."
"Page mem address %p, is hashed %lu, n fields %lu, n bytes %lu\n"
"side %lu\n",
@@ -1602,6 +1662,9 @@ btr_search_validate(void)
}
rw_lock_x_unlock(&btr_search_latch);
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(ok);
}
diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c
index 699ad5fb42e..89f851709db 100644
--- a/innobase/buf/buf0buf.c
+++ b/innobase/buf/buf0buf.c
@@ -331,33 +331,43 @@ buf_page_is_corrupted(
}
}
#endif
- old_checksum = buf_calc_page_old_checksum(read_buf);
-
- old_checksum_field = mach_read_from_4(read_buf + UNIV_PAGE_SIZE
+
+ /* If we use checksums validation, make additional check before returning
+ TRUE to ensure that the checksum is not equal to BUF_NO_CHECKSUM_MAGIC which
+ might be stored by InnoDB with checksums disabled.
+ Otherwise, skip checksum calculation and return FALSE */
+
+ if (srv_use_checksums) {
+ old_checksum = buf_calc_page_old_checksum(read_buf);
+
+ old_checksum_field = mach_read_from_4(read_buf + UNIV_PAGE_SIZE
- FIL_PAGE_END_LSN_OLD_CHKSUM);
- /* There are 2 valid formulas for old_checksum_field:
- 1. Very old versions of InnoDB only stored 8 byte lsn to the start
- and the end of the page.
- 2. Newer InnoDB versions store the old formula checksum there. */
+ /* There are 2 valid formulas for old_checksum_field:
+ 1. Very old versions of InnoDB only stored 8 byte lsn to the start
+ and the end of the page.
+ 2. Newer InnoDB versions store the old formula checksum there. */
- if (old_checksum_field != mach_read_from_4(read_buf + FIL_PAGE_LSN)
- && old_checksum_field != old_checksum) {
+ if (old_checksum_field != mach_read_from_4(read_buf + FIL_PAGE_LSN)
+ && old_checksum_field != old_checksum
+ && old_checksum_field != BUF_NO_CHECKSUM_MAGIC) {
- return(TRUE);
- }
+ return(TRUE);
+ }
- checksum = buf_calc_page_new_checksum(read_buf);
- checksum_field = mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM);
+ checksum = buf_calc_page_new_checksum(read_buf);
+ checksum_field = mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM);
- /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
- (always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
+ /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
+ (always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
- if (checksum_field != 0 && checksum_field != checksum) {
-
- return(TRUE);
- }
+ if (checksum_field != 0 && checksum_field != checksum
+ && checksum_field != BUF_NO_CHECKSUM_MAGIC) {
+ return(TRUE);
+ }
+ }
+
return(FALSE);
}
@@ -379,8 +389,10 @@ buf_page_print(
ut_print_buf(stderr, read_buf, UNIV_PAGE_SIZE);
fputs("InnoDB: End of page dump\n", stderr);
- checksum = buf_calc_page_new_checksum(read_buf);
- old_checksum = buf_calc_page_old_checksum(read_buf);
+ checksum = srv_use_checksums ?
+ buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
+ old_checksum = srv_use_checksums ?
+ buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -460,6 +472,7 @@ buf_block_init(
block->file_page_was_freed = FALSE;
block->check_index_page_at_flush = FALSE;
+ block->index = NULL;
block->in_free_list = FALSE;
block->in_LRU_list = FALSE;
@@ -547,7 +560,7 @@ buf_pool_init(
}
/*----------------------------------------*/
} else {
- buf_pool->frame_mem = ut_malloc_low(
+ buf_pool->frame_mem = os_mem_alloc_large(
UNIV_PAGE_SIZE * (n_frames + 1),
TRUE, FALSE);
}
@@ -1535,6 +1548,7 @@ buf_page_init(
block->offset = offset;
block->check_index_page_at_flush = FALSE;
+ block->index = NULL;
block->lock_hash_val = lock_rec_hash(space, offset);
block->lock_mutex = NULL;
@@ -2137,6 +2151,31 @@ buf_print(void)
}
/*************************************************************************
+Returns the number of latched pages in the buffer pool. */
+
+ulint
+buf_get_latched_pages_number(void)
+{
+ buf_block_t* block;
+ ulint i;
+ ulint fixed_pages_number = 0;
+
+ mutex_enter(&(buf_pool->mutex));
+
+ for (i = 0; i < buf_pool->curr_size; i++) {
+
+ block = buf_pool_get_nth_block(buf_pool, i);
+
+ if (((block->buf_fix_count != 0) || (block->io_fix != 0)) &&
+ block->magic_n == BUF_BLOCK_MAGIC_N )
+ fixed_pages_number++;
+ }
+
+ mutex_exit(&(buf_pool->mutex));
+ return fixed_pages_number;
+}
+
+/*************************************************************************
Returns the number of pending buf pool ios. */
ulint
diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c
index 4df0e9962fb..592ed972376 100644
--- a/innobase/buf/buf0flu.c
+++ b/innobase/buf/buf0flu.c
@@ -281,6 +281,10 @@ buf_flush_buffered_writes(void)
}
}
+ /* increment the doublewrite flushed pages counter */
+ srv_dblwr_pages_written+= trx_doublewrite->first_free;
+ srv_dblwr_writes++;
+
if (trx_doublewrite->first_free > TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
len = TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE;
} else {
@@ -452,7 +456,8 @@ buf_flush_init_for_writing(
/* Store the new formula checksum */
mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM,
- buf_calc_page_new_checksum(page));
+ srv_use_checksums ?
+ buf_calc_page_new_checksum(page) : BUF_NO_CHECKSUM_MAGIC);
/* We overwrite the first 4 bytes of the end lsn field to store
the old formula checksum. Since it depends also on the field
@@ -460,7 +465,8 @@ buf_flush_init_for_writing(
new formula checksum. */
mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
- buf_calc_page_old_checksum(page));
+ srv_use_checksums ?
+ buf_calc_page_old_checksum(page) : BUF_NO_CHECKSUM_MAGIC);
}
/************************************************************************
@@ -909,6 +915,9 @@ buf_flush_batch(
(ulong) page_count);
}
+ if (page_count != ULINT_UNDEFINED)
+ srv_buf_pool_flushed+= page_count;
+
return(page_count);
}
diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c
index 05e92933edf..18c4f8c10fb 100644
--- a/innobase/buf/buf0lru.c
+++ b/innobase/buf/buf0lru.c
@@ -465,6 +465,7 @@ loop:
/* No free block was found: try to flush the LRU list */
buf_flush_free_margin();
+ ++srv_buf_pool_wait_free;
os_aio_simulated_wake_handler_threads();
diff --git a/innobase/buf/buf0rea.c b/innobase/buf/buf0rea.c
index 055eede5c1a..d9dc2ca93f5 100644
--- a/innobase/buf/buf0rea.c
+++ b/innobase/buf/buf0rea.c
@@ -20,6 +20,10 @@ Created 11/5/1995 Heikki Tuuri
#include "os0file.h"
#include "srv0start.h"
+extern ulint srv_read_ahead_rnd;
+extern ulint srv_read_ahead_seq;
+extern ulint srv_buf_pool_reads;
+
/* The size in blocks of the area where the random read-ahead algorithm counts
the accessed pages when deciding whether to read-ahead */
#define BUF_READ_AHEAD_RANDOM_AREA BUF_READ_AHEAD_AREA
@@ -291,6 +295,7 @@ buf_read_ahead_random(
(ulong) count);
}
+ ++srv_read_ahead_rnd;
return(count);
}
@@ -323,6 +328,7 @@ buf_read_page(
count2 = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space,
tablespace_version, offset);
+ srv_buf_pool_reads+= count2;
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -575,6 +581,7 @@ buf_read_ahead_linear(
(ulong) space, (ulong) offset, (ulong) count);
}
+ ++srv_read_ahead_seq;
return(count);
}
diff --git a/innobase/data/data0data.c b/innobase/data/data0data.c
index 97ec1a1acd9..5f74dde8710 100644
--- a/innobase/data/data0data.c
+++ b/innobase/data/data0data.c
@@ -500,7 +500,7 @@ dtuple_convert_big_rec(
ut_a(dtuple_check_typed_no_assert(entry));
- size = rec_get_converted_size(entry);
+ size = rec_get_converted_size(index, entry);
if (size > 1000000000) {
fprintf(stderr,
@@ -524,9 +524,10 @@ dtuple_convert_big_rec(
n_fields = 0;
- while ((rec_get_converted_size(entry)
- >= page_get_free_space_of_empty() / 2)
- || rec_get_converted_size(entry) >= REC_MAX_DATA_SIZE) {
+ while (rec_get_converted_size(index, entry)
+ >= ut_min(page_get_free_space_of_empty(
+ index->table->comp) / 2,
+ REC_MAX_DATA_SIZE)) {
longest = 0;
for (i = dict_index_get_n_unique_in_tree(index);
@@ -545,9 +546,7 @@ dtuple_convert_big_rec(
}
}
- if (!is_externally_stored
- && dict_index_get_nth_type(index, i)->mtype
- == DATA_BLOB) {
+ if (!is_externally_stored) {
dfield = dtuple_get_nth_field(entry, i);
diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c
index dab14df4240..3fcd666b5a5 100644
--- a/innobase/data/data0type.c
+++ b/innobase/data/data0type.c
@@ -41,57 +41,37 @@ 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};
+dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0, 0, 0};
dtype_t* dtype_binary = &dtype_binary_val;
/*************************************************************************
-Checks if a string type has to be compared by the MySQL comparison functions.
-InnoDB internally only handles binary byte string comparisons, as well as
-latin1_swedish_ci strings. For example, UTF-8 strings have to be compared
-by MySQL. */
-
-ibool
-dtype_str_needs_mysql_cmp(
-/*======================*/
- /* out: TRUE if a string type that requires
- comparison with MySQL functions */
- dtype_t* dtype) /* in: type struct */
-{
- if (dtype->mtype == DATA_MYSQL
- || dtype->mtype == DATA_VARMYSQL
- || (dtype->mtype == DATA_BLOB
- && 0 == (dtype->prtype & DATA_BINARY_TYPE)
- && dtype_get_charset_coll(dtype->prtype) !=
- data_mysql_latin1_swedish_charset_coll)) {
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/*************************************************************************
-For the documentation of this function, see innobase_get_at_most_n_mbchars()
-in ha_innodb.cc. */
+Determine how many bytes the first n characters of the given string occupy.
+If the string is shorter than n characters, returns the number of bytes
+the characters in the string occupy. */
ulint
dtype_get_at_most_n_mbchars(
/*========================*/
- dtype_t* dtype,
- ulint prefix_len,
- ulint data_len,
- const char* str)
+ /* out: length of the prefix,
+ in bytes */
+ const dtype_t* dtype, /* in: data type */
+ ulint prefix_len, /* in: length of the requested
+ prefix, in characters, multiplied by
+ dtype_get_mbmaxlen(dtype) */
+ ulint data_len, /* in: length of str (in bytes) */
+ const char* str) /* in: the string whose prefix
+ length is being determined */
{
+#ifndef UNIV_HOTBACKUP
ut_a(data_len != UNIV_SQL_NULL);
+ ut_a(!(prefix_len % dtype->mbmaxlen));
- if (dtype_str_needs_mysql_cmp(dtype)) {
+ if (dtype->mbminlen != dtype->mbmaxlen) {
return(innobase_get_at_most_n_mbchars(
dtype_get_charset_coll(dtype->prtype),
prefix_len, data_len, str));
}
- /* We assume here that the string types that InnoDB itself can compare
- are single-byte charsets! */
-
if (prefix_len < data_len) {
return(prefix_len);
@@ -99,6 +79,12 @@ dtype_get_at_most_n_mbchars(
}
return(data_len);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/*************************************************************************
@@ -206,9 +192,11 @@ dtype_validate(
ut_a((type->mtype >= DATA_VARCHAR) && (type->mtype <= DATA_MYSQL));
if (type->mtype == DATA_SYS) {
- ut_a(type->prtype <= DATA_MIX_ID);
+ ut_a((type->prtype & DATA_MYSQL_TYPE_MASK) < DATA_N_SYS_COLS);
}
+ ut_a(type->mbminlen <= type->mbmaxlen);
+
return(TRUE);
}
diff --git a/innobase/dict/dict0boot.c b/innobase/dict/dict0boot.c
index f156cf67a18..0f6d55c9341 100644
--- a/innobase/dict/dict0boot.c
+++ b/innobase/dict/dict0boot.c
@@ -158,7 +158,7 @@ dict_hdr_create(
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
- DICT_HDR_SPACE, DICT_TABLES_ID, mtr);
+ DICT_HDR_SPACE, DICT_TABLES_ID, FALSE, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -168,7 +168,7 @@ dict_hdr_create(
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_UNIQUE, DICT_HDR_SPACE,
- DICT_TABLE_IDS_ID, mtr);
+ DICT_TABLE_IDS_ID, FALSE, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -178,7 +178,7 @@ dict_hdr_create(
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
- DICT_HDR_SPACE, DICT_COLUMNS_ID, mtr);
+ DICT_HDR_SPACE, DICT_COLUMNS_ID, FALSE, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -188,7 +188,7 @@ dict_hdr_create(
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
- DICT_HDR_SPACE, DICT_INDEXES_ID, mtr);
+ DICT_HDR_SPACE, DICT_INDEXES_ID, FALSE, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -198,7 +198,7 @@ dict_hdr_create(
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
- DICT_HDR_SPACE, DICT_FIELDS_ID, mtr);
+ DICT_HDR_SPACE, DICT_FIELDS_ID, FALSE, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -223,6 +223,7 @@ dict_boot(void)
dict_index_t* index;
dict_hdr_t* dict_hdr;
mtr_t mtr;
+ ibool success;
mtr_start(&mtr);
@@ -254,7 +255,7 @@ dict_boot(void)
/* Insert into the dictionary cache the descriptions of the basic
system tables */
/*-------------------------*/
- table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE,8);
+ table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, FALSE);
dict_mem_table_add_col(table, "NAME", DATA_BINARY, 0, 0, 0);
dict_mem_table_add_col(table, "ID", DATA_BINARY, 0, 0, 0);
@@ -275,22 +276,22 @@ dict_boot(void)
dict_mem_index_add_field(index, "NAME", 0, 0);
- index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_TABLES,
- MLOG_4BYTES, &mtr);
index->id = DICT_TABLES_ID;
- ut_a(dict_index_add_to_cache(table, index));
+ success = dict_index_add_to_cache(table, index, mtr_read_ulint(
+ dict_hdr + DICT_HDR_TABLES, MLOG_4BYTES, &mtr));
+ ut_a(success);
/*-------------------------*/
index = dict_mem_index_create("SYS_TABLES", "ID_IND",
DICT_HDR_SPACE, DICT_UNIQUE, 1);
dict_mem_index_add_field(index, "ID", 0, 0);
- index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_TABLE_IDS,
- MLOG_4BYTES, &mtr);
index->id = DICT_TABLE_IDS_ID;
- ut_a(dict_index_add_to_cache(table, index));
+ success = dict_index_add_to_cache(table, index, mtr_read_ulint(
+ dict_hdr + DICT_HDR_TABLE_IDS, MLOG_4BYTES, &mtr));
+ ut_a(success);
/*-------------------------*/
- table = dict_mem_table_create("SYS_COLUMNS",DICT_HDR_SPACE,7);
+ table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, FALSE);
dict_mem_table_add_col(table, "TABLE_ID", DATA_BINARY,0,0,0);
dict_mem_table_add_col(table, "POS", DATA_INT, 0, 4, 0);
@@ -311,12 +312,12 @@ dict_boot(void)
dict_mem_index_add_field(index, "TABLE_ID", 0, 0);
dict_mem_index_add_field(index, "POS", 0, 0);
- index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_COLUMNS,
- MLOG_4BYTES, &mtr);
index->id = DICT_COLUMNS_ID;
- ut_a(dict_index_add_to_cache(table, index));
+ success = dict_index_add_to_cache(table, index, mtr_read_ulint(
+ dict_hdr + DICT_HDR_COLUMNS, MLOG_4BYTES, &mtr));
+ ut_a(success);
/*-------------------------*/
- table = dict_mem_table_create("SYS_INDEXES",DICT_HDR_SPACE,7);
+ table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, FALSE);
dict_mem_table_add_col(table, "TABLE_ID", DATA_BINARY, 0,0,0);
dict_mem_table_add_col(table, "ID", DATA_BINARY, 0, 0, 0);
@@ -333,6 +334,9 @@ dict_boot(void)
#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2
#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2"
#endif
+#if DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2
+#error "DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2"
+#endif
table->id = DICT_INDEXES_ID;
dict_table_add_to_cache(table);
@@ -344,12 +348,12 @@ dict_boot(void)
dict_mem_index_add_field(index, "TABLE_ID", 0, 0);
dict_mem_index_add_field(index, "ID", 0, 0);
- index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_INDEXES,
- MLOG_4BYTES, &mtr);
index->id = DICT_INDEXES_ID;
- ut_a(dict_index_add_to_cache(table, index));
+ success = dict_index_add_to_cache(table, index, mtr_read_ulint(
+ dict_hdr + DICT_HDR_INDEXES, MLOG_4BYTES, &mtr));
+ ut_a(success);
/*-------------------------*/
- table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE,3);
+ table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, FALSE);
dict_mem_table_add_col(table, "INDEX_ID", DATA_BINARY, 0,0,0);
dict_mem_table_add_col(table, "POS", DATA_INT, 0, 4, 0);
@@ -365,10 +369,10 @@ dict_boot(void)
dict_mem_index_add_field(index, "INDEX_ID", 0, 0);
dict_mem_index_add_field(index, "POS", 0, 0);
- index->page_no = mtr_read_ulint(dict_hdr + DICT_HDR_FIELDS,
- MLOG_4BYTES, &mtr);
index->id = DICT_FIELDS_ID;
- ut_a(dict_index_add_to_cache(table, index));
+ success = dict_index_add_to_cache(table, index, mtr_read_ulint(
+ dict_hdr + DICT_HDR_FIELDS, MLOG_4BYTES, &mtr));
+ ut_a(success);
mtr_commit(&mtr);
/*-------------------------*/
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c
index d9e89316613..1f12386e413 100644
--- a/innobase/dict/dict0crea.c
+++ b/innobase/dict/dict0crea.c
@@ -63,8 +63,8 @@ dict_create_sys_tables_tuple(
dfield = dtuple_get_nth_field(entry, 2);
ptr = mem_heap_alloc(heap, 4);
- mach_write_to_4(ptr, table->n_def);
-
+ mach_write_to_4(ptr, table->n_def
+ | ((ulint) table->comp << 31));
dfield_set_data(dfield, ptr, 4);
/* 5: TYPE -----------------------------*/
dfield = dtuple_get_nth_field(entry, 3);
@@ -82,16 +82,6 @@ dict_create_sys_tables_tuple(
dfield_set_data(dfield, ptr, 8);
/* 7: MIX_LEN --------------------------*/
- /* Track corruption reported on mailing list Jan 14, 2005 */
- if (table->mix_len != 0 && table->mix_len != 0x80000000) {
- fprintf(stderr,
-"InnoDB: Error: mix_len is %lu in table %s\n", (ulong)table->mix_len,
- table->name);
- mem_analyze_corruption((byte*)&(table->mix_len));
-
- ut_error;
- }
-
dfield = dtuple_get_nth_field(entry, 5);
ptr = mem_heap_alloc(heap, 4);
@@ -219,6 +209,8 @@ dict_build_table_def_step(
const char* path_or_name;
ibool is_path;
mtr_t mtr;
+ ulint i;
+ ulint row_len;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -230,6 +222,15 @@ dict_build_table_def_step(
thr_get_trx(thr)->table_id = table->id;
+ row_len = 0;
+ for (i = 0; i < table->n_def; i++) {
+ row_len += dtype_get_min_size(dict_col_get_type(
+ &table->cols[i]));
+ }
+ if (row_len > BTR_PAGE_MAX_REC_SIZE) {
+ return(DB_TOO_BIG_RECORD);
+ }
+
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
cluster_table = dict_table_get_low(table->cluster_name);
@@ -554,9 +555,7 @@ dict_build_index_def_step(
table in the same tablespace */
index->space = table->space;
-
- index->page_no = FIL_NULL;
-
+ node->page_no = FIL_NULL;
row = dict_create_sys_indexes_tuple(index, node->heap);
node->ind_row = row;
@@ -634,18 +633,18 @@ dict_create_index_tree_step(
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
- index->page_no = btr_create(index->type, index->space, index->id,
- &mtr);
+ node->page_no = btr_create(index->type, index->space, index->id,
+ table->comp, &mtr);
/* printf("Created a new index tree in space %lu root page %lu\n",
index->space, index->page_no); */
page_rec_write_index_page_no(btr_pcur_get_rec(&pcur),
DICT_SYS_INDEXES_PAGE_NO_FIELD,
- index->page_no, &mtr);
+ node->page_no, &mtr);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
- if (index->page_no == FIL_NULL) {
+ if (node->page_no == FIL_NULL) {
return(DB_OUT_OF_FILE_SPACE);
}
@@ -671,8 +670,9 @@ dict_drop_index_tree(
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */
-
- ptr = rec_get_nth_field(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);
+
+ ut_a(!dict_sys->sys_indexes->comp);
+ ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);
ut_ad(len == 4);
@@ -684,8 +684,9 @@ dict_drop_index_tree(
return;
}
- ptr = rec_get_nth_field(rec, DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
-
+ ptr = rec_get_nth_field_old(rec,
+ DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
+
ut_ad(len == 4);
space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
@@ -710,8 +711,132 @@ dict_drop_index_tree(
root_page_no); */
btr_free_root(space, root_page_no, mtr);
+ page_rec_write_index_page_no(rec,
+ DICT_SYS_INDEXES_PAGE_NO_FIELD, FIL_NULL, mtr);
+}
+
+/***********************************************************************
+Truncates the index tree associated with a row in SYS_INDEXES table. */
+
+ulint
+dict_truncate_index_tree(
+/*=====================*/
+ /* out: new root page number, or
+ FIL_NULL on failure */
+ dict_table_t* table, /* in: the table the index belongs to */
+ rec_t* rec, /* in: record in the clustered index of
+ SYS_INDEXES table */
+ mtr_t* mtr) /* in: mtr having the latch
+ on the record page. The mtr may be
+ committed and restarted in this call. */
+{
+ ulint root_page_no;
+ ulint space;
+ ulint type;
+ dulint index_id;
+ byte* ptr;
+ ulint len;
+ ibool comp;
+ dict_index_t* index;
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+#endif /* UNIV_SYNC_DEBUG */
+
+ ut_a(!dict_sys->sys_indexes->comp);
+ ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);
+
+ ut_ad(len == 4);
+
+ root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
+
+ if (root_page_no == FIL_NULL) {
+ /* The tree has been freed. */
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Trying to TRUNCATE"
+ " a missing index of table %s!\n", table->name);
+ return(FIL_NULL);
+ }
+
+ ptr = rec_get_nth_field_old(rec,
+ DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
+
+ ut_ad(len == 4);
+
+ space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
+
+ if (!fil_tablespace_exists_in_mem(space)) {
+ /* It is a single table tablespace and the .ibd file is
+ missing: do nothing */
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Trying to TRUNCATE"
+ " a missing .ibd file of table %s!\n", table->name);
+ return(FIL_NULL);
+ }
+
+ ptr = rec_get_nth_field_old(rec,
+ DICT_SYS_INDEXES_TYPE_FIELD, &len);
+ ut_ad(len == 4);
+ type = mach_read_from_4(ptr);
+
+ ptr = rec_get_nth_field_old(rec, 1, &len);
+ ut_ad(len == 8);
+ index_id = mach_read_from_8(ptr);
+
+ /* We free all the pages but the root page first; this operation
+ may span several mini-transactions */
+
+ btr_free_but_not_root(space, root_page_no);
+
+ /* Then we free the root page in the same mini-transaction where
+ we create the b-tree and write its new root page number to the
+ appropriate field in the SYS_INDEXES record: this mini-transaction
+ marks the B-tree totally truncated */
+
+ comp = page_is_comp(btr_page_get(
+ space, root_page_no, RW_X_LATCH, mtr));
+
+ btr_free_root(space, root_page_no, mtr);
+ /* We will temporarily write FIL_NULL to the PAGE_NO field
+ in SYS_INDEXES, so that the database will not get into an
+ inconsistent state in case it crashes between the mtr_commit()
+ below and the following mtr_commit() call. */
page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
FIL_NULL, mtr);
+
+ /* We will need to commit the mini-transaction in order to avoid
+ deadlocks in the btr_create() call, because otherwise we would
+ be freeing and allocating pages in the same mini-transaction. */
+ mtr_commit(mtr);
+ /* mtr_commit() will invalidate rec. */
+ rec = NULL;
+ mtr_start(mtr);
+
+ /* Find the index corresponding to this SYS_INDEXES record. */
+ for (index = UT_LIST_GET_FIRST(table->indexes);
+ index;
+ index = UT_LIST_GET_NEXT(indexes, index)) {
+ if (!ut_dulint_cmp(index->id, index_id)) {
+ break;
+ }
+ }
+
+ root_page_no = btr_create(type, space, index_id, comp, mtr);
+ if (index) {
+ index->tree->page = root_page_no;
+ } else {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Index %lu %lu of table %s is missing\n"
+ "InnoDB: from the data dictionary during TRUNCATE!\n",
+ ut_dulint_get_high(index_id),
+ ut_dulint_get_low(index_id),
+ table->name);
+ }
+
+ return(root_page_no);
}
/*************************************************************************
@@ -770,6 +895,7 @@ ind_create_graph_create(
node->index = index;
node->state = INDEX_BUILD_INDEX_DEF;
+ node->page_no = FIL_NULL;
node->heap = mem_heap_create(256);
node->ind_def = ins_node_create(INS_DIRECT,
@@ -989,7 +1115,8 @@ dict_create_index_step(
if (node->state == INDEX_ADD_TO_CACHE) {
- success = dict_index_add_to_cache(node->table, node->index);
+ success = dict_index_add_to_cache(node->table, node->index,
+ node->page_no);
ut_a(success);
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index b0327f77fd3..0c39defeada 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -53,6 +53,7 @@ rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
/* Identifies generated InnoDB foreign key names */
static char dict_ibfk[] = "_ibfk_";
+#ifndef UNIV_HOTBACKUP
/**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively.
@@ -76,6 +77,7 @@ void
innobase_casedn_str(
/*================*/
char* a); /* in/out: string to put in lower case */
+#endif /* !UNIV_HOTBACKUP */
/**************************************************************************
Adds a column to the data dictionary hash table. */
@@ -824,23 +826,22 @@ dict_table_add_to_cache(
system columns. */
dict_mem_table_add_col(table, "DB_ROW_ID", DATA_SYS,
- DATA_ROW_ID, 0, 0);
+ DATA_ROW_ID | DATA_NOT_NULL, DATA_ROW_ID_LEN, 0);
#if DATA_ROW_ID != 0
#error "DATA_ROW_ID != 0"
#endif
dict_mem_table_add_col(table, "DB_TRX_ID", DATA_SYS,
- DATA_TRX_ID, 0, 0);
+ DATA_TRX_ID | DATA_NOT_NULL, DATA_TRX_ID_LEN, 0);
#if DATA_TRX_ID != 1
#error "DATA_TRX_ID != 1"
#endif
dict_mem_table_add_col(table, "DB_ROLL_PTR", DATA_SYS,
- DATA_ROLL_PTR, 0, 0);
+ DATA_ROLL_PTR | DATA_NOT_NULL, DATA_ROLL_PTR_LEN, 0);
#if DATA_ROLL_PTR != 2
#error "DATA_ROLL_PTR != 2"
#endif
-
dict_mem_table_add_col(table, "DB_MIX_ID", DATA_SYS,
- DATA_MIX_ID, 0, 0);
+ DATA_MIX_ID | DATA_NOT_NULL, DATA_MIX_ID_LEN, 0);
#if DATA_MIX_ID != 3
#error "DATA_MIX_ID != 3"
#endif
@@ -1385,8 +1386,9 @@ dict_index_add_to_cache(
/*====================*/
/* out: TRUE if success */
dict_table_t* table, /* in: table on which the index is */
- dict_index_t* index) /* in, own: index; NOTE! The index memory
+ dict_index_t* index, /* in, own: index; NOTE! The index memory
object is freed in this function! */
+ ulint page_no)/* in: root page number of the index */
{
dict_index_t* new_index;
dict_tree_t* tree;
@@ -1472,10 +1474,9 @@ dict_index_add_to_cache(
tree = dict_index_get_tree(
UT_LIST_GET_FIRST(cluster->indexes));
new_index->tree = tree;
- new_index->page_no = tree->page;
} else {
/* Create an index tree memory object for the index */
- tree = dict_tree_create(new_index);
+ tree = dict_tree_create(new_index, page_no);
ut_ad(tree);
new_index->tree = tree;
@@ -1598,7 +1599,7 @@ dict_index_find_cols(
/***********************************************************************
Adds a column to index. */
-UNIV_INLINE
+
void
dict_index_add_col(
/*===============*/
@@ -1614,6 +1615,34 @@ dict_index_add_col(
field = dict_index_get_nth_field(index, index->n_def - 1);
field->col = col;
+ field->fixed_len = dtype_get_fixed_size(&col->type);
+
+ if (prefix_len && field->fixed_len > prefix_len) {
+ field->fixed_len = prefix_len;
+ }
+
+ /* Long fixed-length fields that need external storage are treated as
+ variable-length fields, so that the extern flag can be embedded in
+ the length word. */
+
+ if (field->fixed_len > DICT_MAX_COL_PREFIX_LEN) {
+ field->fixed_len = 0;
+ }
+
+ if (!(dtype_get_prtype(&col->type) & DATA_NOT_NULL)) {
+ index->n_nullable++;
+ }
+
+ if (index->n_def > 1) {
+ const dict_field_t* field2 =
+ dict_index_get_nth_field(index, index->n_def - 2);
+ field->fixed_offs = (!field2->fixed_len ||
+ field2->fixed_offs == ULINT_UNDEFINED)
+ ? ULINT_UNDEFINED
+ : field2->fixed_len + field2->fixed_offs;
+ } else {
+ field->fixed_offs = 0;
+ }
}
/***********************************************************************
@@ -1732,7 +1761,6 @@ dict_index_build_internal_clust(
new_index->n_user_defined_cols = index->n_fields;
new_index->id = index->id;
- new_index->page_no = index->page_no;
if (table->type != DICT_TABLE_ORDINARY) {
/* The index is mixed: copy common key prefix fields */
@@ -1911,7 +1939,6 @@ dict_index_build_internal_non_clust(
new_index->n_user_defined_cols = index->n_fields;
new_index->id = index->id;
- new_index->page_no = index->page_no;
/* Copy fields from index to new_index */
dict_index_copy(new_index, index, 0, index->n_fields);
@@ -2080,6 +2107,7 @@ dict_foreign_find_index(
dict_index_t* types_idx)/* in: NULL or an index to whose types the
column types must match */
{
+#ifndef UNIV_HOTBACKUP
dict_index_t* index;
const char* col_name;
ulint i;
@@ -2124,6 +2152,12 @@ dict_foreign_find_index(
}
return(NULL);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/**************************************************************************
@@ -2462,7 +2496,7 @@ dict_scan_id(
my_isspace(). Only after that, convert id names to UTF-8. */
b = (byte*)(*id);
- id_len = strlen(b);
+ id_len = strlen((char*) b);
if (id_len >= 3 && b[id_len - 1] == 0xA0
&& b[id_len - 2] == 0xC2) {
@@ -2491,6 +2525,7 @@ dict_scan_col(
const char** name) /* out,own: the column name; NULL if no name
was scannable */
{
+#ifndef UNIV_HOTBACKUP
dict_col_t* col;
ulint i;
@@ -2524,6 +2559,12 @@ dict_scan_col(
}
return(ptr);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/*************************************************************************
@@ -2541,6 +2582,7 @@ dict_scan_table_name(
const char** ref_name)/* out,own: the table name;
NULL if no name was scannable */
{
+#ifndef UNIV_HOTBACKUP
const char* database_name = NULL;
ulint database_name_len = 0;
const char* table_name = NULL;
@@ -2622,6 +2664,12 @@ dict_scan_table_name(
*table = dict_table_get_low(ref);
return(ptr);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/*************************************************************************
@@ -3570,9 +3618,10 @@ dict_tree_t*
dict_tree_create(
/*=============*/
/* out, own: created tree */
- dict_index_t* index) /* in: the index for which to create: in the
+ dict_index_t* index, /* in: the index for which to create: in the
case of a mixed tree, this should be the
index of the cluster object */
+ ulint page_no)/* in: root page number of the index */
{
dict_tree_t* tree;
@@ -3582,7 +3631,7 @@ dict_tree_create(
tree->type = index->type;
tree->space = index->space;
- tree->page = index->page_no;
+ tree->page = page_no;
tree->id = index->id;
@@ -3636,9 +3685,10 @@ dict_tree_find_index_low(
&& (table->type != DICT_TABLE_ORDINARY)) {
/* Get the mix id of the record */
+ ut_a(!table->comp);
mix_id = mach_dulint_read_compressed(
- rec_get_nth_field(rec, table->mix_len, &len));
+ rec_get_nth_field_old(rec, table->mix_len, &len));
while (ut_dulint_cmp(table->mix_id, mix_id) != 0) {
@@ -3717,6 +3767,29 @@ dict_tree_find_index_for_tuple(
return(index);
}
+/***********************************************************************
+Checks if a table which is a mixed cluster member owns a record. */
+
+ibool
+dict_is_mixed_table_rec(
+/*====================*/
+ /* out: TRUE if the record belongs to this
+ table */
+ dict_table_t* table, /* in: table in a mixed cluster */
+ rec_t* rec) /* in: user record in the clustered index */
+{
+ byte* mix_id_field;
+ ulint len;
+
+ ut_ad(!table->comp);
+
+ mix_id_field = rec_get_nth_field_old(rec,
+ table->mix_len, &len);
+
+ return(len == table->mix_id_len
+ && !ut_memcmp(table->mix_id_buf, mix_id_field, len));
+}
+
/**************************************************************************
Checks that a tuple has n_fields_cmp value in a sensible range, so that
no comparison can occur with the page number field in a node pointer. */
@@ -3771,7 +3844,8 @@ dict_tree_build_node_ptr(
on non-leaf levels we remove the last field, which
contains the page number of the child page */
- n_unique = rec_get_n_fields(rec);
+ ut_a(!ind->table->comp);
+ n_unique = rec_get_n_fields_old(rec);
if (level > 0) {
ut_a(n_unique > 1);
@@ -3800,9 +3874,11 @@ dict_tree_build_node_ptr(
field = dtuple_get_nth_field(tuple, n_unique);
dfield_set_data(field, buf, 4);
- dtype_set(dfield_get_type(field), DATA_SYS_CHILD, 0, 0, 0);
+ dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4, 0);
- rec_copy_prefix_to_dtuple(tuple, rec, n_unique, heap);
+ rec_copy_prefix_to_dtuple(tuple, rec, ind, n_unique, heap);
+ dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple) |
+ REC_STATUS_NODE_PTR);
ut_ad(dtuple_check_typed(tuple));
@@ -3819,27 +3895,26 @@ dict_tree_copy_rec_order_prefix(
/* out: pointer to the prefix record */
dict_tree_t* tree, /* in: index tree */
rec_t* rec, /* in: record for which to copy prefix */
+ ulint* n_fields,/* out: number of fields copied */
byte** buf, /* in/out: memory buffer for the copied prefix,
or NULL */
ulint* buf_size)/* in/out: buffer size */
{
- dict_index_t* ind;
- rec_t* order_rec;
- ulint n_fields;
-
- ind = dict_tree_find_index_low(tree, rec);
+ dict_index_t* index;
+ ulint n;
- n_fields = dict_index_get_n_unique_in_tree(ind);
-
- if (tree->type & DICT_UNIVERSAL) {
+ index = dict_tree_find_index_low(tree, rec);
- n_fields = rec_get_n_fields(rec);
+ if (tree->type & DICT_UNIVERSAL) {
+ ut_a(!index->table->comp);
+ n = rec_get_n_fields_old(rec);
+ } else {
+ n = dict_index_get_n_unique_in_tree(index);
}
- order_rec = rec_copy_prefix_to_buf(rec, n_fields, buf, buf_size);
-
- return(order_rec);
-}
+ *n_fields = n;
+ return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
+}
/**************************************************************************
Builds a typed data tuple out of a physical record. */
@@ -3850,21 +3925,21 @@ dict_tree_build_data_tuple(
/* out, own: data tuple */
dict_tree_t* tree, /* in: index tree */
rec_t* rec, /* in: record for which to build data tuple */
+ ulint n_fields,/* in: number of data fields */
mem_heap_t* heap) /* in: memory heap where tuple created */
{
dtuple_t* tuple;
dict_index_t* ind;
- ulint n_fields;
ind = dict_tree_find_index_low(tree, rec);
- n_fields = rec_get_n_fields(rec);
+ ut_ad(ind->table->comp || n_fields <= rec_get_n_fields_old(rec));
tuple = dtuple_create(heap, n_fields);
dict_index_copy_types(tuple, ind, n_fields);
- rec_copy_prefix_to_dtuple(tuple, rec, n_fields, heap);
+ rec_copy_prefix_to_dtuple(tuple, rec, ind, n_fields, heap);
ut_ad(dtuple_check_typed(tuple));
@@ -3882,6 +3957,27 @@ dict_index_calc_min_rec_len(
ulint sum = 0;
ulint i;
+ if (index->table->comp) {
+ ulint nullable = 0;
+ sum = REC_N_NEW_EXTRA_BYTES;
+ for (i = 0; i < dict_index_get_n_fields(index); i++) {
+ dtype_t*t = dict_index_get_nth_type(index, i);
+ ulint size = dtype_get_fixed_size(t);
+ sum += size;
+ if (!size) {
+ size = dtype_get_len(t);
+ sum += size < 128 ? 1 : 2;
+ }
+ if (!(dtype_get_prtype(t) & DATA_NOT_NULL))
+ nullable++;
+ }
+
+ /* round the NULL flags up to full bytes */
+ sum += (nullable + 7) / 8;
+
+ return(sum);
+ }
+
for (i = 0; i < dict_index_get_n_fields(index); i++) {
sum += dtype_get_fixed_size(dict_index_get_nth_type(index, i));
}
@@ -3892,7 +3988,7 @@ dict_index_calc_min_rec_len(
sum += dict_index_get_n_fields(index);
}
- sum += REC_N_EXTRA_BYTES;
+ sum += REC_N_OLD_EXTRA_BYTES;
return(sum);
}
diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c
index 0d58823a2ea..9bafcf33553 100644
--- a/innobase/dict/dict0load.c
+++ b/innobase/dict/dict0load.c
@@ -8,6 +8,9 @@ Created 4/24/1996 Heikki Tuuri
*******************************************************/
#include "dict0load.h"
+#ifndef UNIV_HOTBACKUP
+#include "mysql_version.h"
+#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_NONINL
#include "dict0load.ic"
@@ -55,6 +58,7 @@ dict_get_first_table_name_in_db(
sys_tables = dict_table_get_low("SYS_TABLES");
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
+ ut_a(!sys_tables->comp);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -77,7 +81,7 @@ loop:
return(NULL);
}
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
if (len < strlen(name)
|| ut_memcmp(name, field, strlen(name)) != 0) {
@@ -90,7 +94,7 @@ loop:
return(NULL);
}
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, sys_tables->comp)) {
/* We found one */
@@ -163,9 +167,9 @@ loop:
return;
}
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, sys_tables->comp)) {
/* We found one */
@@ -180,7 +184,7 @@ loop:
if (table == NULL) {
fputs("InnoDB: Failed to load table ", stderr);
- ut_print_namel(stderr, NULL, field, len);
+ ut_print_namel(stderr, NULL, (char*) field, len);
putc('\n', stderr);
} else {
/* The table definition was corrupt if there
@@ -231,6 +235,7 @@ dict_check_tablespaces_and_store_max_id(
sys_tables = dict_table_get_low("SYS_TABLES");
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
+ ut_a(!sys_tables->comp);
btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
TRUE, &mtr);
@@ -257,15 +262,15 @@ loop:
return;
}
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, sys_tables->comp)) {
/* We found one */
char* name = mem_strdupl((char*) field, len);
- field = rec_get_nth_field(rec, 9, &len);
+ field = rec_get_nth_field_old(rec, 9, &len);
ut_a(len == 4);
space_id = mach_read_from_4(field);
@@ -338,6 +343,7 @@ dict_load_columns(
sys_columns = dict_table_get_low("SYS_COLUMNS");
sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
+ ut_a(!sys_columns->comp);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -356,28 +362,27 @@ dict_load_columns(
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
- ut_a(!rec_get_deleted_flag(rec));
-
- field = rec_get_nth_field(rec, 0, &len);
+ ut_a(!rec_get_deleted_flag(rec, sys_columns->comp));
+
+ field = rec_get_nth_field_old(rec, 0, &len);
ut_ad(len == 8);
ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0);
- field = rec_get_nth_field(rec, 1, &len);
+ field = rec_get_nth_field_old(rec, 1, &len);
ut_ad(len == 4);
ut_a(i == mach_read_from_4(field));
ut_a(0 == ut_strcmp("NAME",
dict_field_get_col(
- dict_index_get_nth_field(
- dict_table_get_first_index(sys_columns), 4))->name));
+ dict_index_get_nth_field(sys_index, 4))->name));
- field = rec_get_nth_field(rec, 4, &len);
+ field = rec_get_nth_field_old(rec, 4, &len);
name = mem_heap_strdupl(heap, (char*) field, len);
- field = rec_get_nth_field(rec, 5, &len);
+ field = rec_get_nth_field_old(rec, 5, &len);
mtype = mach_read_from_4(field);
- field = rec_get_nth_field(rec, 6, &len);
+ field = rec_get_nth_field_old(rec, 6, &len);
prtype = mach_read_from_4(field);
if (dtype_is_non_binary_string_type(mtype, prtype)
@@ -389,15 +394,14 @@ dict_load_columns(
data_mysql_default_charset_coll);
}
- field = rec_get_nth_field(rec, 7, &len);
+ field = rec_get_nth_field_old(rec, 7, &len);
col_len = mach_read_from_4(field);
ut_a(0 == ut_strcmp("PREC",
dict_field_get_col(
- dict_index_get_nth_field(
- dict_table_get_first_index(sys_columns), 8))->name));
+ dict_index_get_nth_field(sys_index, 8))->name));
- field = rec_get_nth_field(rec, 8, &len);
+ field = rec_get_nth_field_old(rec, 8, &len);
prec = mach_read_from_4(field);
dict_mem_table_add_col(table, name, mtype, prtype, col_len,
@@ -462,6 +466,7 @@ dict_load_fields(
sys_fields = dict_table_get_low("SYS_FIELDS");
sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
+ ut_a(!sys_fields->comp);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -479,15 +484,15 @@ dict_load_fields(
rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
- if (rec_get_deleted_flag(rec)) {
+ if (rec_get_deleted_flag(rec, sys_fields->comp)) {
dict_load_report_deleted_index(table->name, i);
}
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
ut_ad(len == 8);
ut_a(ut_memcmp(buf, field, len) == 0);
- field = rec_get_nth_field(rec, 1, &len);
+ field = rec_get_nth_field_old(rec, 1, &len);
ut_a(len == 4);
/* The next field stores the field position in the index
@@ -513,10 +518,9 @@ dict_load_fields(
ut_a(0 == ut_strcmp("COL_NAME",
dict_field_get_col(
- dict_index_get_nth_field(
- dict_table_get_first_index(sys_fields), 4))->name));
+ dict_index_get_nth_field(sys_index, 4))->name));
- field = rec_get_nth_field(rec, 4, &len);
+ field = rec_get_nth_field_old(rec, 4, &len);
dict_mem_index_add_field(index,
mem_heap_strdupl(heap, (char*) field, len), 0, prefix_len);
@@ -575,6 +579,7 @@ dict_load_indexes(
sys_indexes = dict_table_get_low("SYS_INDEXES");
sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
+ ut_a(!sys_indexes->comp);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -595,14 +600,14 @@ dict_load_indexes(
rec = btr_pcur_get_rec(&pcur);
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
ut_ad(len == 8);
if (ut_memcmp(buf, field, len) != 0) {
break;
}
- if (rec_get_deleted_flag(rec)) {
+ if (rec_get_deleted_flag(rec, table->comp)) {
dict_load_report_deleted_index(table->name,
ULINT_UNDEFINED);
@@ -612,33 +617,31 @@ dict_load_indexes(
return(FALSE);
}
- field = rec_get_nth_field(rec, 1, &len);
+ field = rec_get_nth_field_old(rec, 1, &len);
ut_ad(len == 8);
id = mach_read_from_8(field);
ut_a(0 == ut_strcmp("NAME",
dict_field_get_col(
- dict_index_get_nth_field(
- dict_table_get_first_index(sys_indexes), 4))->name));
-
- field = rec_get_nth_field(rec, 4, &name_len);
+ dict_index_get_nth_field(sys_index, 4))->name));
+
+ field = rec_get_nth_field_old(rec, 4, &name_len);
name_buf = mem_heap_strdupl(heap, (char*) field, name_len);
- field = rec_get_nth_field(rec, 5, &len);
+ field = rec_get_nth_field_old(rec, 5, &len);
n_fields = mach_read_from_4(field);
- field = rec_get_nth_field(rec, 6, &len);
+ field = rec_get_nth_field_old(rec, 6, &len);
type = mach_read_from_4(field);
- field = rec_get_nth_field(rec, 7, &len);
+ field = rec_get_nth_field_old(rec, 7, &len);
space = mach_read_from_4(field);
ut_a(0 == ut_strcmp("PAGE_NO",
dict_field_get_col(
- dict_index_get_nth_field(
- dict_table_get_first_index(sys_indexes), 8))->name));
+ dict_index_get_nth_field(sys_index, 8))->name));
- field = rec_get_nth_field(rec, 8, &len);
+ field = rec_get_nth_field_old(rec, 8, &len);
page_no = mach_read_from_4(field);
if (page_no == FIL_NULL) {
@@ -680,12 +683,10 @@ dict_load_indexes(
} else {
index = dict_mem_index_create(table->name, name_buf,
space, type, n_fields);
- index->page_no = page_no;
index->id = id;
dict_load_fields(table, index, heap);
-
- dict_index_add_to_cache(table, index);
+ dict_index_add_to_cache(table, index, page_no);
}
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
@@ -741,6 +742,7 @@ dict_load_table(
sys_tables = dict_table_get_low("SYS_TABLES");
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
+ ut_a(!sys_tables->comp);
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -753,7 +755,7 @@ dict_load_table(
rec = btr_pcur_get_rec(&pcur);
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
- || rec_get_deleted_flag(rec)) {
+ || rec_get_deleted_flag(rec, sys_tables->comp)) {
/* Not found */
btr_pcur_close(&pcur);
@@ -763,11 +765,10 @@ dict_load_table(
return(NULL);
}
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
/* Check if the table name in record is the searched one */
if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
- err_exit:
btr_pcur_close(&pcur);
mtr_commit(&mtr);
mem_heap_free(heap);
@@ -777,10 +778,9 @@ dict_load_table(
ut_a(0 == ut_strcmp("SPACE",
dict_field_get_col(
- dict_index_get_nth_field(
- dict_table_get_first_index(sys_tables), 9))->name));
+ dict_index_get_nth_field(sys_index, 9))->name));
- field = rec_get_nth_field(rec, 9, &len);
+ field = rec_get_nth_field_old(rec, 9, &len);
space = mach_read_from_4(field);
/* Check if the tablespace exists and has the right name */
@@ -812,49 +812,44 @@ dict_load_table(
ut_a(0 == ut_strcmp("N_COLS",
dict_field_get_col(
- dict_index_get_nth_field(
- dict_table_get_first_index(sys_tables), 4))->name));
+ dict_index_get_nth_field(sys_index, 4))->name));
- field = rec_get_nth_field(rec, 4, &len);
+ field = rec_get_nth_field_old(rec, 4, &len);
n_cols = mach_read_from_4(field);
- if (n_cols & 0x80000000UL) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: table %s is in the new compact format\n"
- "InnoDB: of MySQL 5.0.3 or later\n", name);
- goto err_exit;
- }
- table = dict_mem_table_create(name, space, n_cols);
+ /* The high-order bit of N_COLS is the "compact format" flag. */
+ table = dict_mem_table_create(name, space,
+ n_cols & ~0x80000000UL,
+ !!(n_cols & 0x80000000UL));
table->ibd_file_missing = ibd_file_missing;
ut_a(0 == ut_strcmp("ID",
dict_field_get_col(
- dict_index_get_nth_field(
- dict_table_get_first_index(sys_tables), 3))->name));
+ dict_index_get_nth_field(sys_index, 3))->name));
- field = rec_get_nth_field(rec, 3, &len);
+ field = rec_get_nth_field_old(rec, 3, &len);
table->id = mach_read_from_8(field);
- field = rec_get_nth_field(rec, 5, &len);
+ field = rec_get_nth_field_old(rec, 5, &len);
table->type = mach_read_from_4(field);
if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
ut_error;
#if 0 /* clustered tables have not been implemented yet */
- field = rec_get_nth_field(rec, 6, &len);
+ field = rec_get_nth_field_old(rec, 6, &len);
table->mix_id = mach_read_from_8(field);
- field = rec_get_nth_field(rec, 8, &len);
+ field = rec_get_nth_field_old(rec, 8, &len);
table->cluster_name = mem_heap_strdupl(heap, (char*) field, len);
#endif
}
if ((table->type == DICT_TABLE_CLUSTER)
|| (table->type == DICT_TABLE_CLUSTER_MEMBER)) {
-
- field = rec_get_nth_field(rec, 7, &len);
+
+ field = rec_get_nth_field_old(rec, 7, &len);
+ ut_a(len == 4);
table->mix_len = mach_read_from_4(field);
}
@@ -933,6 +928,7 @@ dict_load_table_on_id(
sys_tables = dict_sys->sys_tables;
sys_table_ids = dict_table_get_next_index(
dict_table_get_first_index(sys_tables));
+ ut_a(!sys_tables->comp);
heap = mem_heap_create(256);
tuple = dtuple_create(heap, 1);
@@ -949,7 +945,7 @@ dict_load_table_on_id(
rec = btr_pcur_get_rec(&pcur);
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
- || rec_get_deleted_flag(rec)) {
+ || rec_get_deleted_flag(rec, sys_tables->comp)) {
/* Not found */
btr_pcur_close(&pcur);
@@ -964,7 +960,7 @@ dict_load_table_on_id(
table ID and NAME */
rec = btr_pcur_get_rec(&pcur);
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
ut_ad(len == 8);
/* Check if the table id in record is the one searched for */
@@ -978,7 +974,7 @@ dict_load_table_on_id(
}
/* Now we get the table name from the record */
- field = rec_get_nth_field(rec, 1, &len);
+ field = rec_get_nth_field_old(rec, 1, &len);
/* Load the table definition to memory */
table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len));
@@ -1046,6 +1042,7 @@ dict_load_foreign_cols(
sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
+ ut_a(!sys_foreign_cols->comp);
tuple = dtuple_create(foreign->heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -1060,21 +1057,21 @@ dict_load_foreign_cols(
rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
- ut_a(!rec_get_deleted_flag(rec));
-
- field = rec_get_nth_field(rec, 0, &len);
+ ut_a(!rec_get_deleted_flag(rec, sys_foreign_cols->comp));
+
+ field = rec_get_nth_field_old(rec, 0, &len);
ut_a(len == ut_strlen(id));
ut_a(ut_memcmp(id, field, len) == 0);
- field = rec_get_nth_field(rec, 1, &len);
+ field = rec_get_nth_field_old(rec, 1, &len);
ut_a(len == 4);
ut_a(i == mach_read_from_4(field));
- field = rec_get_nth_field(rec, 4, &len);
+ field = rec_get_nth_field_old(rec, 4, &len);
foreign->foreign_col_names[i] =
mem_heap_strdupl(foreign->heap, (char*) field, len);
- field = rec_get_nth_field(rec, 5, &len);
+ field = rec_get_nth_field_old(rec, 5, &len);
foreign->referenced_col_names[i] =
mem_heap_strdupl(foreign->heap, (char*) field, len);
@@ -1118,6 +1115,7 @@ dict_load_foreign(
sys_foreign = dict_table_get_low("SYS_FOREIGN");
sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
+ ut_a(!sys_foreign->comp);
tuple = dtuple_create(heap2, 1);
dfield = dtuple_get_nth_field(tuple, 0);
@@ -1130,7 +1128,7 @@ dict_load_foreign(
rec = btr_pcur_get_rec(&pcur);
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
- || rec_get_deleted_flag(rec)) {
+ || rec_get_deleted_flag(rec, sys_foreign->comp)) {
/* Not found */
fprintf(stderr,
@@ -1144,7 +1142,7 @@ dict_load_foreign(
return(DB_ERROR);
}
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
/* Check if the id in record is the searched one */
if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
@@ -1167,7 +1165,8 @@ dict_load_foreign(
foreign = dict_mem_foreign_create();
- foreign->n_fields = mach_read_from_4(rec_get_nth_field(rec, 5, &len));
+ foreign->n_fields =
+ mach_read_from_4(rec_get_nth_field_old(rec, 5, &len));
ut_a(len == 4);
@@ -1178,11 +1177,11 @@ dict_load_foreign(
foreign->id = mem_heap_strdup(foreign->heap, id);
- field = rec_get_nth_field(rec, 3, &len);
+ field = rec_get_nth_field_old(rec, 3, &len);
foreign->foreign_table_name =
mem_heap_strdupl(foreign->heap, (char*) field, len);
-
- field = rec_get_nth_field(rec, 4, &len);
+
+ field = rec_get_nth_field_old(rec, 4, &len);
foreign->referenced_table_name =
mem_heap_strdupl(foreign->heap, (char*) field, len);
@@ -1250,6 +1249,7 @@ dict_load_foreigns(
return(DB_ERROR);
}
+ ut_a(!sys_foreign->comp);
mtr_start(&mtr);
/* Get the secondary index based on FOR_NAME from table
@@ -1281,7 +1281,7 @@ loop:
name and a foreign constraint ID */
rec = btr_pcur_get_rec(&pcur);
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
/* Check if the table name in the record is the one searched for; the
following call does the comparison in the latin1_swedish_ci
@@ -1304,13 +1304,13 @@ loop:
goto next_rec;
}
- if (rec_get_deleted_flag(rec)) {
+ if (rec_get_deleted_flag(rec, sys_foreign->comp)) {
goto next_rec;
}
/* Now we get a foreign key constraint id */
- field = rec_get_nth_field(rec, 1, &len);
+ field = rec_get_nth_field_old(rec, 1, &len);
id = mem_heap_strdupl(heap, (char*) field, len);
btr_pcur_store_position(&pcur, &mtr);
diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c
index 1d45585aac1..48b9f28d292 100644
--- a/innobase/dict/dict0mem.c
+++ b/innobase/dict/dict0mem.c
@@ -35,7 +35,8 @@ dict_mem_table_create(
the table is placed; this parameter is
ignored if the table is made a member of
a cluster */
- ulint n_cols) /* in: number of columns */
+ ulint n_cols, /* in: number of columns */
+ ibool comp) /* in: TRUE=compact page format */
{
dict_table_t* table;
mem_heap_t* heap;
@@ -54,6 +55,7 @@ dict_mem_table_create(
table->space = space;
table->ibd_file_missing = FALSE;
table->tablespace_discarded = FALSE;
+ table->comp = comp;
table->n_def = 0;
table->n_cols = n_cols + DATA_N_SYS_COLS;
table->mem_fix = 0;
@@ -110,7 +112,8 @@ dict_mem_cluster_create(
{
dict_table_t* cluster;
- cluster = dict_mem_table_create(name, space, n_cols);
+ /* Clustered tables cannot work with the compact record format. */
+ cluster = dict_mem_table_create(name, space, n_cols, FALSE);
cluster->type = DICT_TABLE_CLUSTER;
cluster->mix_len = mix_len;
@@ -197,7 +200,7 @@ dict_mem_index_create(
index->name = mem_heap_strdup(heap, index_name);
index->table_name = table_name;
index->table = NULL;
- index->n_def = 0;
+ index->n_def = index->n_nullable = 0;
index->n_fields = n_fields;
index->fields = mem_heap_alloc(heap, 1 + n_fields
* sizeof(dict_field_t));
diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c
index 9d5def718a6..8600f583dbd 100644
--- a/innobase/fil/fil0fil.c
+++ b/innobase/fil/fil0fil.c
@@ -89,6 +89,9 @@ but in the MySQL Embedded Server Library and ibbackup it is not the default
directory, and we must set the base file path explicitly */
const char* fil_path_to_mysql_datadir = ".";
+/* The number of fsyncs done to the log */
+ulint fil_n_log_flushes = 0;
+
ulint fil_n_pending_log_flushes = 0;
ulint fil_n_pending_tablespace_flushes = 0;
@@ -517,7 +520,7 @@ fil_node_open_file(
if (size_bytes < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
fprintf(stderr,
"InnoDB: Error: the size of single-table tablespace file %s\n"
-"InnoDB: is only %lu %lu, should be at least %lu!", node->name,
+"InnoDB: is only %lu %lu, should be at least %lu!\n", node->name,
(ulong) size_high,
(ulong) size_low, (ulong) (4 * UNIV_PAGE_SIZE));
@@ -687,8 +690,8 @@ fil_try_to_close_file_in_LRU(
ut_print_filename(stderr, node->name);
fprintf(stderr,
", because mod_count %ld != fl_count %ld\n",
- (ulong) node->modification_counter,
- (ulong) node->flush_counter);
+ (long) node->modification_counter,
+ (long) node->flush_counter);
}
node = UT_LIST_GET_PREV(LRU, node);
@@ -1652,30 +1655,38 @@ fil_op_write_log(
mtr_t* mtr) /* in: mini-transaction handle */
{
byte* log_ptr;
+ ulint len;
+
+ log_ptr = mlog_open(mtr, 11 + 2);
+
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash recovery:
+ in that case mlog_open returns NULL */
+ return;
+ }
- log_ptr = mlog_open(mtr, 30);
-
log_ptr = mlog_write_initial_log_record_for_file_op(type, space_id, 0,
log_ptr, mtr);
/* Let us store the strings as null-terminated for easier readability
and handling */
- mach_write_to_2(log_ptr, ut_strlen(name) + 1);
+ len = strlen(name) + 1;
+
+ mach_write_to_2(log_ptr, len);
log_ptr += 2;
-
mlog_close(mtr, log_ptr);
- mlog_catenate_string(mtr, (byte*) name, ut_strlen(name) + 1);
+ mlog_catenate_string(mtr, (byte*) name, len);
if (type == MLOG_FILE_RENAME) {
- log_ptr = mlog_open(mtr, 30);
- mach_write_to_2(log_ptr, ut_strlen(new_name) + 1);
+ ulint len = strlen(new_name) + 1;
+ log_ptr = mlog_open(mtr, 2 + len);
+ ut_a(log_ptr);
+ mach_write_to_2(log_ptr, len);
log_ptr += 2;
-
mlog_close(mtr, log_ptr);
- mlog_catenate_string(mtr, (byte*) new_name,
- ut_strlen(new_name) + 1);
+ mlog_catenate_string(mtr, (byte*) new_name, len);
}
}
#endif
@@ -2612,12 +2623,12 @@ fil_open_single_table_tablespace(
fputs("!\n"
"InnoDB: Have you moved InnoDB .ibd files around without using the\n"
"InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?\n"
-"InnoDB: It is also possible that this is a table created with\n"
-"InnoDB: CREATE TEMPORARY TABLE, and MySQL removed the .ibd file for this.\n"
+"InnoDB: It is also possible that this is a temporary table #sql...,\n"
+"InnoDB: and MySQL removed the .ibd file for this.\n"
"InnoDB: Please refer to\n"
"InnoDB:"
" http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
-"InnoDB: how to resolve the issue.\n", stderr);
+"InnoDB: for how to resolve the issue.\n", stderr);
mem_free(filepath);
@@ -2657,7 +2668,7 @@ fil_open_single_table_tablespace(
"InnoDB: Please refer to\n"
"InnoDB:"
" http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
-"InnoDB: how to resolve the issue.\n", (ulong) space_id, (ulong) id);
+"InnoDB: for how to resolve the issue.\n", (ulong) space_id, (ulong) id);
ret = FALSE;
@@ -3292,7 +3303,7 @@ fil_space_for_table_exists_in_mem(
ut_print_filename(stderr, name);
fprintf(stderr, "\n"
"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
-"InnoDB: but tablespace with that id does not exist. There is\n"
+"InnoDB: but a tablespace with that id does not exist. There is\n"
"InnoDB: a tablespace of name %s and id %lu, though. Have\n"
"InnoDB: you deleted or moved .ibd files?\n",
(ulong) id, namespace->name,
@@ -3303,7 +3314,7 @@ fil_space_for_table_exists_in_mem(
"InnoDB: Please refer to\n"
"InnoDB:"
" http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
-"InnoDB: how to resolve the issue.\n", stderr);
+"InnoDB: for how to resolve the issue.\n", stderr);
mem_free(path);
mutex_exit(&(system->mutex));
@@ -3317,7 +3328,7 @@ fil_space_for_table_exists_in_mem(
ut_print_filename(stderr, name);
fprintf(stderr, "\n"
"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
-"InnoDB: but tablespace with that id has name %s.\n"
+"InnoDB: but the tablespace with that id has name %s.\n"
"InnoDB: Have you deleted or moved .ibd files?\n", (ulong) id, space->name);
if (namespace != NULL) {
@@ -3817,6 +3828,12 @@ fil_io(
mode = OS_AIO_NORMAL;
}
+ if (type == OS_FILE_READ) {
+ srv_data_read+= len;
+ } else if (type == OS_FILE_WRITE) {
+ srv_data_written+= len;
+ }
+
/* Reserve the fil_system mutex and make sure that we can open at
least one file while holding it, if the file is not already open */
@@ -4102,6 +4119,7 @@ fil_flush(
fil_n_pending_tablespace_flushes++;
} else {
fil_n_pending_log_flushes++;
+ fil_n_log_flushes++;
}
#ifdef __WIN__
if (node->is_raw_disk) {
diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c
index e1621cc2765..ef8e70646c6 100644
--- a/innobase/fsp/fsp0fsp.c
+++ b/innobase/fsp/fsp0fsp.c
@@ -910,7 +910,7 @@ fsp_header_init(
if (space == 0) {
fsp_fill_free_list(FALSE, space, header, mtr);
btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, space,
- ut_dulint_add(DICT_IBUF_ID_MIN, space), mtr);
+ ut_dulint_add(DICT_IBUF_ID_MIN, space), FALSE, mtr);
} else {
fsp_fill_free_list(TRUE, space, header, mtr);
}
diff --git a/innobase/ibuf/ibuf0ibuf.c b/innobase/ibuf/ibuf0ibuf.c
index 2191cdc0ee6..5ad61e2590f 100644
--- a/innobase/ibuf/ibuf0ibuf.c
+++ b/innobase/ibuf/ibuf0ibuf.c
@@ -46,7 +46,7 @@ Note that contary to what we planned in the 1990's, there will only be one
insert buffer tree, and that is in the system tablespace of InnoDB.
1. The first field is the space id.
-2. The second field is a one-byte marker which differentiates records from
+2. The second field is a one-byte marker (0) which differentiates records from
the < 4.1.x storage format.
3. The third field is the page number.
4. The fourth field contains the type info, where we have also added 2 bytes to
@@ -55,7 +55,14 @@ insert buffer tree, and that is in the system tablespace of InnoDB.
can use in the binary search on the index page in the ibuf merge phase.
5. The rest of the fields contain the fields of the actual index record.
-*/
+In versions >= 5.0.3:
+
+The first byte of the fourth field is an additional marker (0) if the record
+is in the compact format. The presence of this marker can be detected by
+looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE.
+
+The high-order bit of the character set field in the type info is the
+"nullable" flag for the field. */
/* PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
@@ -525,8 +532,8 @@ ibuf_data_init_for_space(
ibuf_exit();
sprintf(buf, "SYS_IBUF_TABLE_%lu", (ulong) space);
-
- table = dict_mem_table_create(buf, space, 2);
+ /* use old-style record format for the insert buffer */
+ table = dict_mem_table_create(buf, space, 2, FALSE);
dict_mem_table_add_col(table, "PAGE_NO", DATA_BINARY, 0, 0, 0);
dict_mem_table_add_col(table, "TYPES", DATA_BINARY, 0, 0, 0);
@@ -541,11 +548,9 @@ ibuf_data_init_for_space(
dict_mem_index_add_field(index, "PAGE_NO", 0, 0);
dict_mem_index_add_field(index, "TYPES", 0, 0);
- index->page_no = FSP_IBUF_TREE_ROOT_PAGE_NO;
-
index->id = ut_dulint_add(DICT_IBUF_ID_MIN, space);
- dict_index_add_to_cache(table, index);
+ dict_index_add_to_cache(table, index, FSP_IBUF_TREE_ROOT_PAGE_NO);
data->index = dict_table_get_first_index(table);
@@ -1049,20 +1054,20 @@ ibuf_rec_get_page_no(
ulint len;
ut_ad(ibuf_inside());
- ut_ad(rec_get_n_fields(rec) > 2);
+ ut_ad(rec_get_n_fields_old(rec) > 2);
- field = rec_get_nth_field(rec, 1, &len);
+ field = rec_get_nth_field_old(rec, 1, &len);
if (len == 1) {
/* This is of the >= 4.1.x record format */
ut_a(trx_sys_multiple_tablespace_format);
- field = rec_get_nth_field(rec, 2, &len);
+ field = rec_get_nth_field_old(rec, 2, &len);
} else {
ut_a(trx_doublewrite_must_reset_space_ids);
ut_a(!trx_sys_multiple_tablespace_format);
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
}
ut_a(len == 4);
@@ -1084,15 +1089,15 @@ ibuf_rec_get_space(
ulint len;
ut_ad(ibuf_inside());
- ut_ad(rec_get_n_fields(rec) > 2);
+ ut_ad(rec_get_n_fields_old(rec) > 2);
- field = rec_get_nth_field(rec, 1, &len);
+ field = rec_get_nth_field_old(rec, 1, &len);
if (len == 1) {
/* This is of the >= 4.1.x record format */
ut_a(trx_sys_multiple_tablespace_format);
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
ut_a(len == 4);
return(mach_read_from_4(field));
@@ -1105,6 +1110,162 @@ ibuf_rec_get_space(
}
/************************************************************************
+Creates a dummy index for inserting a record to a non-clustered index.
+*/
+static
+dict_index_t*
+ibuf_dummy_index_create(
+/*====================*/
+ /* out: dummy index */
+ ulint n, /* in: number of fields */
+ ibool comp) /* in: TRUE=use compact record format */
+{
+ dict_table_t* table;
+ dict_index_t* index;
+ table = dict_mem_table_create("IBUF_DUMMY",
+ DICT_HDR_SPACE, n, comp);
+ index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY",
+ DICT_HDR_SPACE, 0, n);
+ index->table = table;
+ /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
+ index->cached = TRUE;
+ return(index);
+}
+/************************************************************************
+Add a column to the dummy index */
+static
+void
+ibuf_dummy_index_add_col(
+/*====================*/
+ dict_index_t* index, /* in: dummy index */
+ dtype_t* type, /* in: the data type of the column */
+ ulint len) /* in: length of the column */
+{
+ ulint i = index->table->n_def;
+ dict_mem_table_add_col(index->table, "DUMMY",
+ dtype_get_mtype(type),
+ dtype_get_prtype(type),
+ dtype_get_len(type),
+ dtype_get_prec(type));
+ dict_index_add_col(index,
+ dict_table_get_nth_col(index->table, i), 0, len);
+}
+/************************************************************************
+Deallocates a dummy index for inserting a record to a non-clustered index.
+*/
+static
+void
+ibuf_dummy_index_free(
+/*====================*/
+ dict_index_t* index) /* in: dummy index */
+{
+ dict_table_t* table = index->table;
+ mem_heap_free(index->heap);
+ mutex_free(&(table->autoinc_mutex));
+ mem_heap_free(table->heap);
+}
+
+/*************************************************************************
+Builds the entry to insert into a non-clustered index when we have the
+corresponding record in an ibuf index. */
+static
+dtuple_t*
+ibuf_build_entry_from_ibuf_rec(
+/*===========================*/
+ /* out, own: entry to insert to
+ a non-clustered index; NOTE that
+ as we copy pointers to fields in
+ ibuf_rec, the caller must hold a
+ latch to the ibuf_rec page as long
+ as the entry is used! */
+ rec_t* ibuf_rec, /* in: record in an insert buffer */
+ mem_heap_t* heap, /* in: heap where built */
+ dict_index_t** pindex) /* out, own: dummy index that
+ describes the entry */
+{
+ dtuple_t* tuple;
+ dfield_t* field;
+ ulint n_fields;
+ byte* types;
+ const byte* data;
+ ulint len;
+ ulint i;
+ dict_index_t* index;
+
+ data = rec_get_nth_field_old(ibuf_rec, 1, &len);
+
+ if (len > 1) {
+ /* This a < 4.1.x format record */
+
+ ut_a(trx_doublewrite_must_reset_space_ids);
+ ut_a(!trx_sys_multiple_tablespace_format);
+
+ n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
+ tuple = dtuple_create(heap, n_fields);
+ types = rec_get_nth_field_old(ibuf_rec, 1, &len);
+
+ ut_a(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
+
+ for (i = 0; i < n_fields; i++) {
+ field = dtuple_get_nth_field(tuple, i);
+
+ data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
+
+ dfield_set_data(field, data, len);
+
+ dtype_read_for_order_and_null_size(
+ dfield_get_type(field),
+ types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
+ }
+
+ *pindex = ibuf_dummy_index_create(n_fields, FALSE);
+ return(tuple);
+ }
+
+ /* This a >= 4.1.x format record */
+
+ ut_a(trx_sys_multiple_tablespace_format);
+ ut_a(*data == 0);
+ ut_a(rec_get_n_fields_old(ibuf_rec) > 4);
+
+ n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
+
+ tuple = dtuple_create(heap, n_fields);
+
+ types = rec_get_nth_field_old(ibuf_rec, 3, &len);
+
+ ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1);
+ index = ibuf_dummy_index_create(n_fields,
+ len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
+
+ if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
+ /* compact record format */
+ len--;
+ ut_a(*types == 0);
+ types++;
+ }
+
+ ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
+
+ for (i = 0; i < n_fields; i++) {
+ field = dtuple_get_nth_field(tuple, i);
+
+ data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
+
+ dfield_set_data(field, data, len);
+
+ dtype_new_read_for_order_and_null_size(
+ dfield_get_type(field),
+ types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
+
+ ibuf_dummy_index_add_col(index, dfield_get_type(field), len);
+ }
+
+ *pindex = index;
+ return(tuple);
+}
+
+/************************************************************************
Returns the space taken by a stored non-clustered index entry if converted to
an index record. */
static
@@ -1125,43 +1286,60 @@ ibuf_rec_get_volume(
ulint i;
ut_ad(ibuf_inside());
- ut_ad(rec_get_n_fields(ibuf_rec) > 2);
-
- data = rec_get_nth_field(ibuf_rec, 1, &len);
+ ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
+
+ data = rec_get_nth_field_old(ibuf_rec, 1, &len);
if (len > 1) {
- /* < 4.1.x format record */
+ /* < 4.1.x format record */
ut_a(trx_doublewrite_must_reset_space_ids);
ut_a(!trx_sys_multiple_tablespace_format);
- n_fields = rec_get_n_fields(ibuf_rec) - 2;
+ n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
- types = rec_get_nth_field(ibuf_rec, 1, &len);
+ types = rec_get_nth_field_old(ibuf_rec, 1, &len);
ut_ad(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
} else {
- /* >= 4.1.x format record */
+ /* >= 4.1.x format record */
ut_a(trx_sys_multiple_tablespace_format);
- new_format = TRUE;
+ ut_a(*data == 0);
+
+ types = rec_get_nth_field_old(ibuf_rec, 3, &len);
+
+ ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1);
+ if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
+ /* compact record format */
+ ulint volume;
+ dict_index_t* dummy_index;
+ mem_heap_t* heap = mem_heap_create(500);
+ dtuple_t* entry =
+ ibuf_build_entry_from_ibuf_rec(
+ ibuf_rec, heap, &dummy_index);
+ volume = rec_get_converted_size(dummy_index, entry);
+ ibuf_dummy_index_free(dummy_index);
+ mem_heap_free(heap);
+ return(volume + page_dir_calc_reserved_space(1));
+ }
- n_fields = rec_get_n_fields(ibuf_rec) - 4;
+ n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
- types = rec_get_nth_field(ibuf_rec, 3, &len);
+ new_format = TRUE;
}
for (i = 0; i < n_fields; i++) {
if (new_format) {
- data = rec_get_nth_field(ibuf_rec, i + 4, &len);
+ data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
dtype_new_read_for_order_and_null_size(&dtype,
- types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
+ types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
} else {
- data = rec_get_nth_field(ibuf_rec, i + 2, &len);
+ data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
dtype_read_for_order_and_null_size(&dtype,
- types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
+ types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
}
if (len == UNIV_SQL_NULL) {
@@ -1187,6 +1365,7 @@ ibuf_entry_build(
must be kept because we copy pointers to its
fields */
dtuple_t* entry, /* in: entry for a non-clustered index */
+ ibool comp, /* in: flag: TRUE=compact record format */
ulint space, /* in: space id */
ulint page_no,/* in: index page number where entry should
be inserted */
@@ -1202,11 +1381,14 @@ ibuf_entry_build(
/* Starting from 4.1.x, we have to build a tuple whose
(1) first field is the space id,
- (2) the second field a single marker byte to tell that this
+ (2) the second field a single marker byte (0) to tell that this
is a new format record,
(3) the third contains the page number, and
(4) the fourth contains the relevent type information of each data
- field,
+ field; the length of this field % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE is
+ (a) 0 for b-trees in the old format, and
+ (b) 1 for b-trees in the compact format, the first byte of the field
+ being the marker (0);
(5) and the rest of the fields are copied from entry. All fields
in the tuple are ordered like the type binary in our insert buffer
tree. */
@@ -1247,10 +1429,15 @@ ibuf_entry_build(
dfield_set_data(field, buf, 4);
+ ut_ad(comp == 0 || comp == 1);
/* Store the type info in buf2, and add the fields from entry to
tuple */
buf2 = mem_heap_alloc(heap, n_fields
- * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
+ * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
+ + comp);
+ if (comp) {
+ *buf2++ = 0; /* write the compact format indicator */
+ }
for (i = 0; i < n_fields; i++) {
/* We add 4 below because we have the 4 extra fields at the
start of an ibuf record */
@@ -1268,8 +1455,13 @@ ibuf_entry_build(
field = dtuple_get_nth_field(tuple, 3);
+ if (comp) {
+ buf2--;
+ }
+
dfield_set_data(field, buf2, n_fields
- * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
+ * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
+ + comp);
/* Set all the types in the new tuple binary */
dtuple_set_types_binary(tuple, n_fields + 4);
@@ -1278,88 +1470,6 @@ ibuf_entry_build(
}
/*************************************************************************
-Builds the entry to insert into a non-clustered index when we have the
-corresponding record in an ibuf index. */
-static
-dtuple_t*
-ibuf_build_entry_from_ibuf_rec(
-/*===========================*/
- /* out, own: entry to insert to
- a non-clustered index; NOTE that
- as we copy pointers to fields in
- ibuf_rec, the caller must hold a
- latch to the ibuf_rec page as long
- as the entry is used! */
- rec_t* ibuf_rec, /* in: record in an insert buffer */
- mem_heap_t* heap) /* in: heap where built */
-{
- dtuple_t* tuple;
- dfield_t* field;
- ulint n_fields;
- byte* types;
- byte* data;
- ulint len;
- ulint i;
-
- data = rec_get_nth_field(ibuf_rec, 1, &len);
-
- if (len > 1) {
- /* This a < 4.1.x format record */
-
- ut_a(trx_doublewrite_must_reset_space_ids);
- ut_a(!trx_sys_multiple_tablespace_format);
-
- n_fields = rec_get_n_fields(ibuf_rec) - 2;
- tuple = dtuple_create(heap, n_fields);
- types = rec_get_nth_field(ibuf_rec, 1, &len);
-
- ut_a(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
-
- for (i = 0; i < n_fields; i++) {
- field = dtuple_get_nth_field(tuple, i);
-
- data = rec_get_nth_field(ibuf_rec, i + 2, &len);
-
- dfield_set_data(field, data, len);
-
- dtype_read_for_order_and_null_size(
- dfield_get_type(field),
- types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
- }
-
- return(tuple);
- }
-
- /* This a >= 4.1.x format record */
-
- ut_a(trx_sys_multiple_tablespace_format);
-
- ut_a(rec_get_n_fields(ibuf_rec) > 4);
-
- n_fields = rec_get_n_fields(ibuf_rec) - 4;
-
- tuple = dtuple_create(heap, n_fields);
-
- types = rec_get_nth_field(ibuf_rec, 3, &len);
-
- ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
-
- for (i = 0; i < n_fields; i++) {
- field = dtuple_get_nth_field(tuple, i);
-
- data = rec_get_nth_field(ibuf_rec, i + 4, &len);
-
- dfield_set_data(field, data, len);
-
- dtype_new_read_for_order_and_null_size(
- dfield_get_type(field),
- types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
- }
-
- return(tuple);
-}
-
-/*************************************************************************
Builds a search tuple used to search buffered inserts for an index page.
This is for < 4.1.x format records */
static
@@ -2047,8 +2157,7 @@ loop:
mutex_exit(&ibuf_mutex);
sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur),
- space_ids, space_versions, page_nos,
- &n_stored);
+ space_ids, space_versions, page_nos, &n_stored);
#ifdef UNIV_IBUF_DEBUG
/* fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
sync, n_stored, sum_sizes); */
@@ -2344,6 +2453,7 @@ ibuf_update_max_tablespace_id(void)
ibuf_data = fil_space_get_ibuf_data(0);
ibuf_index = ibuf_data->index;
+ ut_a(!ibuf_index->table->comp);
ibuf_enter();
@@ -2360,7 +2470,7 @@ ibuf_update_max_tablespace_id(void)
} else {
rec = btr_pcur_get_rec(&pcur);
- field = rec_get_nth_field(rec, 0, &len);
+ field = rec_get_nth_field_old(rec, 0, &len);
ut_a(len == 4);
@@ -2479,7 +2589,7 @@ ibuf_insert_low(
ibuf_enter();
}
- entry_size = rec_get_converted_size(entry);
+ entry_size = rec_get_converted_size(index, entry);
heap = mem_heap_create(512);
@@ -2487,7 +2597,8 @@ ibuf_insert_low(
the first fields and the type information for other fields, and which
will be inserted to the insert buffer. */
- ibuf_entry = ibuf_entry_build(entry, space, page_no, heap);
+ ibuf_entry = ibuf_entry_build(entry, index->table->comp,
+ space, page_no, heap);
/* Open a cursor to the insert buffer tree to calculate if we can add
the new entry to it without exceeding the free space limit for the
@@ -2532,8 +2643,8 @@ ibuf_insert_low(
do_merge = TRUE;
ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur),
- space_ids, space_versions, page_nos,
- &n_stored);
+ space_ids, space_versions,
+ page_nos, &n_stored);
goto function_exit;
}
@@ -2656,8 +2767,8 @@ ibuf_insert(
ut_a(!(index->type & DICT_CLUSTERED));
- if (rec_get_converted_size(entry)
- >= page_get_free_space_of_empty() / 2) {
+ if (rec_get_converted_size(index, entry)
+ >= page_get_free_space_of_empty(index->table->comp) / 2) {
return(FALSE);
}
@@ -2692,6 +2803,7 @@ ibuf_insert_to_index_page(
dtuple_t* entry, /* in: buffered entry to insert */
page_t* page, /* in: index page where the buffered entry
should be placed */
+ dict_index_t* index, /* in: record descriptor */
mtr_t* mtr) /* in: mtr */
{
page_cur_t page_cur;
@@ -2703,13 +2815,20 @@ ibuf_insert_to_index_page(
ut_ad(ibuf_inside());
ut_ad(dtuple_check_typed(entry));
- if (rec_get_n_fields(page_rec_get_next(page_get_infimum_rec(page)))
- != dtuple_get_n_fields(entry)) {
-
- fprintf(stderr,
+ if (index->table->comp != page_is_comp(page)) {
+ 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");
+"InnoDB: but the 'compact' flag does not match!\n", stderr);
+ goto dump;
+ }
+
+ rec = page_rec_get_next(page_get_infimum_rec(page));
+ if (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);
+ dump:
buf_page_print(page);
dtuple_print(stderr, entry);
@@ -2723,31 +2842,34 @@ ibuf_insert_to_index_page(
return;
}
- low_match = page_cur_search(page, entry, PAGE_CUR_LE, &page_cur);
+ low_match = page_cur_search(page, index, entry,
+ PAGE_CUR_LE, &page_cur);
if (low_match == dtuple_get_n_fields(entry)) {
rec = page_cur_get_rec(&page_cur);
- btr_cur_del_unmark_for_ibuf(rec, mtr);
+ btr_cur_del_unmark_for_ibuf(rec, index, mtr);
} else {
- rec = page_cur_tuple_insert(&page_cur, entry, mtr);
+ rec = page_cur_tuple_insert(&page_cur, entry, index, mtr);
if (rec == NULL) {
/* If the record did not fit, reorganize */
- btr_page_reorganize(page, mtr);
+ btr_page_reorganize(page, index, mtr);
- page_cur_search(page, entry, PAGE_CUR_LE, &page_cur);
+ page_cur_search(page, index, entry,
+ PAGE_CUR_LE, &page_cur);
/* This time the record must fit */
- if (!page_cur_tuple_insert(&page_cur, entry, mtr)) {
+ if (!page_cur_tuple_insert(&page_cur, entry,
+ index, mtr)) {
ut_print_timestamp(stderr);
fprintf(stderr,
"InnoDB: Error: Insert buffer insert fails; page free %lu, dtuple size %lu\n",
(ulong) page_get_max_insert_size(page, 1),
- (ulong) rec_get_converted_size(entry));
+ (ulong) rec_get_converted_size(index, entry));
fputs("InnoDB: Cannot insert index record ",
stderr);
dtuple_print(stderr, entry);
@@ -2836,11 +2958,12 @@ ibuf_delete_rec(
"InnoDB: ibuf record inserted to page %lu\n", (ulong) page_no);
fflush(stderr);
- rec_print(stderr, btr_pcur_get_rec(pcur));
- rec_print(stderr, pcur->old_rec);
+ rec_print_old(stderr, btr_pcur_get_rec(pcur));
+ rec_print_old(stderr, pcur->old_rec);
dtuple_print(stderr, search_tuple);
- rec_print(stderr, page_rec_get_next(btr_pcur_get_rec(pcur)));
+ rec_print_old(stderr,
+ page_rec_get_next(btr_pcur_get_rec(pcur)));
fflush(stderr);
btr_pcur_commit_specify_mtr(pcur, mtr);
@@ -3075,7 +3198,7 @@ loop:
if (corruption_noticed) {
fputs("InnoDB: Discarding record\n ", stderr);
- rec_print(stderr, ibuf_rec);
+ rec_print_old(stderr, ibuf_rec);
fputs("\n from the insert buffer!\n\n", stderr);
} else if (page) {
/* Now we have at pcur a record which should be
@@ -3083,19 +3206,22 @@ loop:
copies pointers to fields in ibuf_rec, and we must
keep the latch to the ibuf_rec page until the
insertion is finished! */
-
- dulint max_trx_id = page_get_max_trx_id(
+ dict_index_t* dummy_index;
+ dulint max_trx_id = page_get_max_trx_id(
buf_frame_align(ibuf_rec));
page_update_max_trx_id(page, max_trx_id);
- entry = ibuf_build_entry_from_ibuf_rec(ibuf_rec, heap);
+ entry = ibuf_build_entry_from_ibuf_rec(ibuf_rec,
+ heap, &dummy_index);
#ifdef UNIV_IBUF_DEBUG
- volume += rec_get_converted_size(entry)
+ volume += rec_get_converted_size(dummy_index, entry)
+ page_dir_calc_reserved_space(1);
ut_a(volume <= 4 * UNIV_PAGE_SIZE
/ IBUF_PAGE_SIZE_PER_FREE_SPACE);
#endif
- ibuf_insert_to_index_page(entry, page, &mtr);
+ ibuf_insert_to_index_page(entry, page,
+ dummy_index, &mtr);
+ ibuf_dummy_index_free(dummy_index);
}
n_inserts++;
diff --git a/innobase/include/Makefile.am b/innobase/include/Makefile.am
index 102d25566da..eb1e3b72877 100644
--- a/innobase/include/Makefile.am
+++ b/innobase/include/Makefile.am
@@ -49,7 +49,7 @@ noinst_HEADERS = btr0btr.h btr0btr.ic btr0cur.h btr0cur.ic \
thr0loc.h thr0loc.ic trx0purge.h trx0purge.ic trx0rec.h \
trx0rec.ic trx0roll.h trx0roll.ic trx0rseg.h trx0rseg.ic \
trx0sys.h trx0sys.ic trx0trx.h trx0trx.ic trx0types.h \
- trx0undo.h trx0undo.ic univ.i \
+ trx0undo.h trx0undo.ic trx0xa.h univ.i \
usr0sess.h usr0sess.ic usr0types.h ut0byte.h ut0byte.ic \
ut0dbg.h ut0lst.h ut0mem.h ut0mem.ic ut0rnd.h ut0rnd.ic \
ut0sort.h ut0ut.h ut0ut.ic
diff --git a/innobase/include/btr0btr.h b/innobase/include/btr0btr.h
index 8606fcd2a5c..0b19e64d4e0 100644
--- a/innobase/include/btr0btr.h
+++ b/innobase/include/btr0btr.h
@@ -155,7 +155,8 @@ ulint
btr_node_ptr_get_child_page_no(
/*===========================*/
/* out: child node address */
- rec_t* rec); /* in: node pointer record */
+ rec_t* rec, /* in: node pointer record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/****************************************************************
Creates the root node for a new index tree. */
@@ -167,6 +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 */
mtr_t* mtr); /* in: mini-transaction handle */
/****************************************************************
Frees a B-tree except the root page, which MUST be freed after this
@@ -210,8 +212,9 @@ Reorganizes an index page. */
void
btr_page_reorganize(
/*================*/
- page_t* page, /* in: page to be reorganized */
- mtr_t* mtr); /* in: mtr */
+ page_t* page, /* in: page to be reorganized */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr); /* in: mtr */
/*****************************************************************
Decides if the page should be split at the convergence point of
inserts converging to left. */
@@ -273,6 +276,7 @@ void
btr_set_min_rec_mark(
/*=================*/
rec_t* rec, /* in: record */
+ ibool comp, /* in: TRUE=compact page format */
mtr_t* mtr); /* in: mtr */
/*****************************************************************
Deletes on the upper level the node pointer to a page. */
@@ -332,6 +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 */
page_t* page, /* in: page or NULL */
mtr_t* mtr); /* in: mtr or NULL */
/***************************************************************
@@ -340,11 +345,12 @@ Parses a redo log record of reorganizing a page. */
byte*
btr_parse_page_reorganize(
/*======================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
+ /* 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 */
+ mtr_t* mtr); /* in: mtr or NULL */
/******************************************************************
Gets the number of pages in a B-tree. */
diff --git a/innobase/include/btr0btr.ic b/innobase/include/btr0btr.ic
index b0aa0756307..1d1f97d3668 100644
--- a/innobase/include/btr0btr.ic
+++ b/innobase/include/btr0btr.ic
@@ -183,17 +183,18 @@ ulint
btr_node_ptr_get_child_page_no(
/*===========================*/
/* out: child node address */
- rec_t* rec) /* in: node pointer record */
+ rec_t* rec, /* in: node pointer record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
- ulint n_fields;
byte* field;
ulint len;
ulint page_no;
- n_fields = rec_get_n_fields(rec);
+ ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
/* The child address is in the last field */
- field = rec_get_nth_field(rec, n_fields - 1, &len);
+ field = rec_get_nth_field(rec, offsets,
+ rec_offs_n_fields(offsets) - 1, &len);
ut_ad(len == 4);
diff --git a/innobase/include/btr0cur.h b/innobase/include/btr0cur.h
index f1334656d53..0a8d8ceaeb7 100644
--- a/innobase/include/btr0cur.h
+++ b/innobase/include/btr0cur.h
@@ -34,7 +34,7 @@ page_cur_t*
btr_cur_get_page_cur(
/*=================*/
/* out: pointer to page cursor component */
- btr_cur_t* cursor); /* in: tree cursor */
+ btr_cur_t* cursor);/* in: tree cursor */
/*************************************************************
Returns the record pointer of a tree cursor. */
UNIV_INLINE
@@ -42,14 +42,14 @@ rec_t*
btr_cur_get_rec(
/*============*/
/* out: pointer to record */
- btr_cur_t* cursor); /* in: tree cursor */
+ btr_cur_t* cursor);/* in: tree cursor */
/*************************************************************
Invalidates a tree cursor by setting record pointer to NULL. */
UNIV_INLINE
void
btr_cur_invalidate(
/*===============*/
- btr_cur_t* cursor); /* in: tree cursor */
+ btr_cur_t* cursor);/* in: tree cursor */
/*************************************************************
Returns the page of a tree cursor. */
UNIV_INLINE
@@ -57,7 +57,7 @@ page_t*
btr_cur_get_page(
/*=============*/
/* out: pointer to page */
- btr_cur_t* cursor); /* in: tree cursor */
+ btr_cur_t* cursor);/* in: tree cursor */
/*************************************************************
Returns the tree of a cursor. */
UNIV_INLINE
@@ -65,7 +65,7 @@ dict_tree_t*
btr_cur_get_tree(
/*=============*/
/* out: tree */
- btr_cur_t* cursor); /* in: tree cursor */
+ btr_cur_t* cursor);/* in: tree cursor */
/*************************************************************
Positions a tree cursor at a given record. */
UNIV_INLINE
@@ -283,8 +283,9 @@ only used by the insert buffer insert merge mechanism. */
void
btr_cur_del_unmark_for_ibuf(
/*========================*/
- rec_t* rec, /* in: record to delete unmark */
- mtr_t* mtr); /* in: mtr */
+ 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
that mtr holds an x-latch on the tree and on the cursor page. To avoid
@@ -361,10 +362,11 @@ Parses a redo log record of updating a record in-place. */
byte*
btr_cur_parse_update_in_place(
/*==========================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page); /* in: page or NULL */
+ /* out: end of log record or NULL */
+ byte* ptr, /* in: buffer */
+ byte* end_ptr,/* in: buffer end */
+ page_t* page, /* in: page or NULL */
+ dict_index_t* index); /* in: index corresponding to page */
/********************************************************************
Parses the redo log record for delete marking or unmarking of a clustered
index record. */
@@ -372,10 +374,11 @@ index record. */
byte*
btr_cur_parse_del_mark_set_clust_rec(
/*=================================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page); /* in: page or NULL */
+ /* 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 */
/********************************************************************
Parses the redo log record for delete marking or unmarking of a secondary
index record. */
@@ -383,10 +386,11 @@ index record. */
byte*
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 */
- page_t* page); /* in: page or NULL */
+ /* 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. */
@@ -417,9 +421,10 @@ to free the field. */
void
btr_cur_mark_extern_inherited_fields(
/*=================================*/
- rec_t* rec, /* in: record in a clustered index */
- upd_t* update, /* in: update vector */
- mtr_t* mtr); /* in: mtr */
+ rec_t* rec, /* in: record in a clustered index */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ upd_t* update, /* in: update vector */
+ mtr_t* mtr); /* in: mtr */
/***********************************************************************
The complement of the previous function: in an update entry may inherit
some externally stored fields from a record. We must mark them as inherited
@@ -456,6 +461,7 @@ btr_store_big_rec_extern_fields(
dict_index_t* index, /* in: index of rec; the index tree
MUST be X-latched */
rec_t* rec, /* in: record */
+ const ulint* offsets, /* in: rec_get_offsets(rec, index) */
big_rec_t* big_rec_vec, /* in: vector containing fields
to be stored externally */
mtr_t* local_mtr); /* in: mtr containing the latch to
@@ -496,6 +502,7 @@ btr_rec_free_externally_stored_fields(
dict_index_t* index, /* in: index of the data, the index
tree MUST be X-latched */
rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
inherited fields */
@@ -510,6 +517,7 @@ btr_rec_copy_externally_stored_field(
/*=================================*/
/* out: the field copied to heap */
rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint no, /* in: field number */
ulint* len, /* out: length of the field */
mem_heap_t* heap); /* in: mem heap */
@@ -540,10 +548,10 @@ ulint
btr_push_update_extern_fields(
/*==========================*/
/* out: number of values stored in ext_vect */
- ulint* ext_vect, /* in: array of ulints, must be preallocated
- to have place for all fields in rec */
- rec_t* rec, /* in: record */
- upd_t* update); /* in: update vector */
+ ulint* ext_vect,/* in: array of ulints, must be preallocated
+ to have space for all fields in rec */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ upd_t* update);/* in: update vector or NULL */
/*######################################################################*/
diff --git a/innobase/include/btr0cur.ic b/innobase/include/btr0cur.ic
index a3a04b60c45..dcad3e9e14d 100644
--- a/innobase/include/btr0cur.ic
+++ b/innobase/include/btr0cur.ic
@@ -134,17 +134,15 @@ btr_cur_can_delete_without_compress(
/* out: TRUE if can be deleted without
recommended compression */
btr_cur_t* cursor, /* in: btr cursor */
+ ulint rec_size,/* in: rec_get_size(btr_cur_get_rec(cursor))*/
mtr_t* mtr) /* in: mtr */
{
- ulint rec_size;
page_t* page;
ut_ad(mtr_memo_contains(mtr, buf_block_align(
btr_cur_get_page(cursor)),
MTR_MEMO_PAGE_X_FIX));
- rec_size = rec_get_size(btr_cur_get_rec(cursor));
-
page = btr_cur_get_page(cursor);
if ((page_get_data_size(page) - rec_size < BTR_CUR_PAGE_COMPRESS_LIMIT)
diff --git a/innobase/include/btr0pcur.h b/innobase/include/btr0pcur.h
index 9339eb5d0ee..eb3822aab7a 100644
--- a/innobase/include/btr0pcur.h
+++ b/innobase/include/btr0pcur.h
@@ -462,6 +462,7 @@ struct btr_pcur_struct{
contains an initial segment of the
latest record cursor was positioned
either on, before, or after */
+ ulint old_n_fields; /* number of fields in old_rec */
ulint rel_pos; /* BTR_PCUR_ON, BTR_PCUR_BEFORE, or
BTR_PCUR_AFTER, depending on whether
cursor was on, before, or after the
diff --git a/innobase/include/btr0sea.h b/innobase/include/btr0sea.h
index ce4140ecf92..78e88a24083 100644
--- a/innobase/include/btr0sea.h
+++ b/innobase/include/btr0sea.h
@@ -77,8 +77,10 @@ parameters as page (this often happens when a page is split). */
void
btr_search_move_or_delete_hash_entries(
/*===================================*/
- page_t* new_page, /* in: records are copied to this page */
- page_t* page); /* in: index page */
+ page_t* new_page, /* in: records are copied
+ to this page */
+ page_t* page, /* in: index page */
+ dict_index_t* index); /* in: record descriptor */
/************************************************************************
Drops a page hash index. */
@@ -129,8 +131,8 @@ Validates the search system. */
ibool
btr_search_validate(void);
-/*=====================*/
-
+/*======================*/
+ /* out: TRUE if ok */
/* Search info directions */
#define BTR_SEA_NO_DIRECTION 1
diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h
index 53599d03c73..5ee323f1b1e 100644
--- a/innobase/include/buf0buf.h
+++ b/innobase/include/buf0buf.h
@@ -52,11 +52,15 @@ Created 11/5/1995 Heikki Tuuri
/* Modes for buf_page_get_known_nowait */
#define BUF_MAKE_YOUNG 51
#define BUF_KEEP_OLD 52
+/* Magic value to use instead of checksums when they are disabled */
+#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL
extern buf_pool_t* buf_pool; /* The buffer pool of the database */
extern ibool buf_debug_prints;/* If this is set TRUE, the program
prints info whenever read or flush
occurs */
+extern ulint srv_buf_pool_write_requests; /* variable to count write request
+ issued */
/************************************************************************
Creates the buffer pool. */
@@ -496,6 +500,12 @@ void
buf_print(void);
/*============*/
/*************************************************************************
+Returns the number of latched pages in the buffer pool. */
+
+ulint
+buf_get_latched_pages_number(void);
+/*==============================*/
+/*************************************************************************
Returns the number of pending buf pool ios. */
ulint
@@ -731,6 +741,8 @@ struct buf_block_struct{
buffer pool which are index pages,
but this flag is not set because
we do not keep track of all pages */
+ dict_index_t* index; /* index for which the adaptive
+ hash index has been created */
/* 2. Page flushing fields */
UT_LIST_NODE_T(buf_block_t) flush_list;
diff --git a/innobase/include/buf0flu.ic b/innobase/include/buf0flu.ic
index d6dbdcc0865..9a8a021e029 100644
--- a/innobase/include/buf0flu.ic
+++ b/innobase/include/buf0flu.ic
@@ -61,6 +61,8 @@ buf_flush_note_modification(
ut_ad(ut_dulint_cmp(block->oldest_modification,
mtr->start_lsn) <= 0);
}
+
+ ++srv_buf_pool_write_requests;
}
/************************************************************************
diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h
index 02c874836fd..a4d2c1a2e1d 100644
--- a/innobase/include/data0type.h
+++ b/innobase/include/data0type.h
@@ -24,7 +24,11 @@ extern dtype_t* dtype_binary;
/*-------------------------------------------*/
/* The 'MAIN TYPE' of a column */
#define DATA_VARCHAR 1 /* character varying of the
- latin1_swedish_ci charset-collation */
+ latin1_swedish_ci charset-collation; note
+ that the MySQL format for this, DATA_BINARY,
+ DATA_VARMYSQL, is also affected by whether the
+ 'precise type' contains
+ DATA_MYSQL_TRUE_VARCHAR */
#define DATA_CHAR 2 /* fixed length character of the
latin1_swedish_ci charset-collation */
#define DATA_FIXBINARY 3 /* binary string of fixed length */
@@ -32,7 +36,9 @@ extern dtype_t* dtype_binary;
#define DATA_BLOB 5 /* binary large object, or a TEXT type;
if prtype & DATA_BINARY_TYPE == 0, then this is
actually a TEXT column (or a BLOB created
- with < 4.0.14) */
+ with < 4.0.14; since column prefix indexes
+ came only in 4.0.14, the missing flag in BLOBs
+ created before that does not cause any harm) */
#define DATA_INT 6 /* integer: can be any size 1 - 8 bytes */
#define DATA_SYS_CHILD 7 /* address of the child page in node pointer */
#define DATA_SYS 8 /* system column */
@@ -102,6 +108,8 @@ columns, and for them the precise type is usually not used at all.
#define DATA_MYSQL_TYPE_MASK 255 /* AND with this mask to extract the MySQL
type from the precise type */
+#define DATA_MYSQL_TRUE_VARCHAR 15 /* MySQL type code for the >= 5.0.3
+ format true VARCHAR */
/* Precise data types for system columns and the length of those columns;
NOTE: the values must run from 0 up in the order given! All codes must
@@ -134,6 +142,10 @@ be less than 256 */
In earlier versions this was set for some
BLOB columns.
*/
+#define DATA_LONG_TRUE_VARCHAR 4096 /* this is ORed to the precise data
+ type when the column is true VARCHAR where
+ MySQL uses 2 bytes to store the data len;
+ for shorter VARCHARs MySQL uses only 1 byte */
/*-------------------------------------------*/
/* This many bytes we need to store the type information affecting the
@@ -145,28 +157,31 @@ store the charset-collation number; one byte is left unused, though */
#define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6
/*************************************************************************
-Checks if a string type has to be compared by the MySQL comparison functions.
-InnoDB internally only handles binary byte string comparisons, as well as
-latin1_swedish_ci strings. For example, UTF-8 strings have to be compared
-by MySQL. */
-
-ibool
-dtype_str_needs_mysql_cmp(
-/*======================*/
- /* out: TRUE if a string type that requires
- comparison with MySQL functions */
- dtype_t* dtype); /* in: type struct */
+Gets the MySQL type code from a dtype. */
+UNIV_INLINE
+ulint
+dtype_get_mysql_type(
+/*=================*/
+ /* out: MySQL type code; this is NOT an InnoDB
+ type code! */
+ dtype_t* type); /* in: type struct */
/*************************************************************************
-For the documentation of this function, see innobase_get_at_most_n_mbchars()
-in ha_innodb.cc. */
+Determine how many bytes the first n characters of the given string occupy.
+If the string is shorter than n characters, returns the number of bytes
+the characters in the string occupy. */
ulint
dtype_get_at_most_n_mbchars(
/*========================*/
- dtype_t* dtype,
- ulint prefix_len,
- ulint data_len,
- const char* str);
+ /* out: length of the prefix,
+ in bytes */
+ const dtype_t* dtype, /* in: data type */
+ ulint prefix_len, /* in: length of the requested
+ prefix, in characters, multiplied by
+ dtype_get_mbmaxlen(dtype) */
+ ulint data_len, /* in: length of str (in bytes) */
+ const char* str); /* in: the string whose prefix
+ length is being determined */
/*************************************************************************
Checks if a data main type is a string type. Also a BLOB is considered a
string type. */
@@ -271,6 +286,24 @@ dtype_get_prec(
/*===========*/
dtype_t* type);
/*************************************************************************
+Gets the minimum length of a character, in bytes. */
+UNIV_INLINE
+ulint
+dtype_get_mbminlen(
+/*===============*/
+ /* out: minimum length of a char, in bytes,
+ or 0 if this is not a character type */
+ const dtype_t* type); /* in: type */
+/*************************************************************************
+Gets the maximum length of a character, in bytes. */
+UNIV_INLINE
+ulint
+dtype_get_mbmaxlen(
+/*===============*/
+ /* out: maximum length of a char, in bytes,
+ or 0 if this is not a character type */
+ const dtype_t* type); /* in: type */
+/*************************************************************************
Gets the padding character code for the type. */
UNIV_INLINE
ulint
@@ -288,6 +321,14 @@ dtype_get_fixed_size(
/* out: fixed size, or 0 */
dtype_t* type); /* in: type */
/***************************************************************************
+Returns the minimum size of a data type. */
+UNIV_INLINE
+ulint
+dtype_get_min_size(
+/*===============*/
+ /* out: minimum size */
+ const dtype_t* type); /* in: type */
+/***************************************************************************
Returns a stored SQL NULL size for a type. For fixed length types it is
the fixed length of the type, otherwise 0. */
UNIV_INLINE
@@ -352,16 +393,34 @@ dtype_print(
/*========*/
dtype_t* type); /* in: type */
-/* Structure for an SQL data type */
+/* Structure for an SQL data type.
+If you add fields to this structure, be sure to initialize them everywhere.
+This structure is initialized in the following functions:
+dtype_set()
+dtype_read_for_order_and_null_size()
+dtype_new_read_for_order_and_null_size()
+sym_tab_add_null_lit() */
struct dtype_struct{
ulint mtype; /* main data type */
- ulint prtype; /* precise type; MySQL data type */
-
- /* the remaining two fields do not affect alphabetical ordering: */
-
- ulint len; /* length */
+ ulint prtype; /* precise type; MySQL data type, charset code,
+ flags to indicate nullability, signedness,
+ whether this is a binary string, whether this
+ is a true VARCHAR where MySQL uses 2 bytes to
+ store the length */
+
+ /* the remaining fields do not affect alphabetical ordering: */
+
+ ulint len; /* length; for MySQL data this is
+ field->pack_length(), except that for a
+ >= 5.0.3 type true VARCHAR this is the
+ maximum byte length of the string data
+ (in addition to the string, MySQL uses 1 or
+ 2 bytes to store the string length) */
ulint prec; /* precision */
+
+ ulint mbminlen; /* minimum length of a character, in bytes */
+ ulint mbmaxlen; /* maximum length of a character, in bytes */
};
#ifndef UNIV_NONINL
diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic
index 946b646ffbf..a87a08ca582 100644
--- a/innobase/include/data0type.ic
+++ b/innobase/include/data0type.ic
@@ -8,6 +8,61 @@ Created 1/16/1996 Heikki Tuuri
#include "mach0data.h"
+/**********************************************************************
+Get the variable length bounds of the given character set.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+extern
+void
+innobase_get_cset_width(
+/*====================*/
+ ulint cset, /* in: MySQL charset-collation code */
+ ulint* mbminlen, /* out: minimum length of a char (in bytes) */
+ ulint* mbmaxlen); /* out: maximum length of a char (in bytes) */
+
+/*************************************************************************
+Gets the MySQL charset-collation code for MySQL string types. */
+UNIV_INLINE
+ulint
+dtype_get_charset_coll(
+/*===================*/
+ ulint prtype) /* in: precise data type */
+{
+ return((prtype >> 16) & 0xFFUL);
+}
+
+/*************************************************************************
+Gets the MySQL type code from a dtype. */
+UNIV_INLINE
+ulint
+dtype_get_mysql_type(
+/*=================*/
+ /* out: MySQL type code; this is NOT an InnoDB
+ type code! */
+ dtype_t* type) /* in: type struct */
+{
+ return(type->prtype & 0xFFUL);
+}
+
+/*************************************************************************
+Sets the mbminlen and mbmaxlen members of a data type structure. */
+UNIV_INLINE
+void
+dtype_set_mblen(
+/*============*/
+ dtype_t* type) /* in/out: type struct */
+{
+ ut_ad(type);
+ if (dtype_is_string_type(type->mtype)) {
+ innobase_get_cset_width(dtype_get_charset_coll(type->prtype),
+ &type->mbminlen, &type->mbmaxlen);
+ ut_ad(type->mbminlen <= type->mbmaxlen);
+ } else {
+ type->mbminlen = type->mbmaxlen = 0;
+ }
+}
+
/*************************************************************************
Sets a data type structure. */
UNIV_INLINE
@@ -28,6 +83,7 @@ dtype_set(
type->len = len;
type->prec = prec;
+ dtype_set_mblen(type);
ut_ad(dtype_validate(type));
}
@@ -72,17 +128,6 @@ dtype_get_prtype(
}
/*************************************************************************
-Gets the MySQL charset-collation code for MySQL string types. */
-UNIV_INLINE
-ulint
-dtype_get_charset_coll(
-/*===================*/
- ulint prtype) /* in: precise data type */
-{
- return((prtype >> 16) & 0xFFUL);
-}
-
-/*************************************************************************
Gets the type length. */
UNIV_INLINE
ulint
@@ -109,6 +154,33 @@ dtype_get_prec(
}
/*************************************************************************
+Gets the minimum length of a character, in bytes. */
+UNIV_INLINE
+ulint
+dtype_get_mbminlen(
+/*===============*/
+ /* out: minimum length of a char, in bytes,
+ or 0 if this is not a character type */
+ const dtype_t* type) /* in: type */
+{
+ ut_ad(type);
+ return(type->mbminlen);
+}
+/*************************************************************************
+Gets the maximum length of a character, in bytes. */
+UNIV_INLINE
+ulint
+dtype_get_mbmaxlen(
+/*===============*/
+ /* out: maximum length of a char, in bytes,
+ or 0 if this is not a character type */
+ const dtype_t* type) /* in: type */
+{
+ ut_ad(type);
+ return(type->mbmaxlen);
+}
+
+/*************************************************************************
Gets the padding character code for the type. */
UNIV_INLINE
ulint
@@ -123,10 +195,12 @@ dtype_get_pad_char(
|| type->mtype == DATA_BINARY
|| type->mtype == DATA_FIXBINARY
|| type->mtype == DATA_MYSQL
- || type->mtype == DATA_VARMYSQL) {
+ || type->mtype == DATA_VARMYSQL
+ || (type->mtype == DATA_BLOB
+ && (type->prtype & DATA_BINARY_TYPE) == 0)) {
/* Space is the padding character for all char and binary
- strings */
+ strings, and starting from 5.0.3, also for TEXT strings. */
return((ulint)' ');
}
@@ -149,8 +223,10 @@ dtype_new_store_for_order_and_null_size(
bytes where we store the info */
dtype_t* type) /* in: type struct */
{
- ut_ad(6 == DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
-
+#if 6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
+#error "6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE"
+#endif
+
buf[0] = (byte)(type->mtype & 0xFFUL);
if (type->prtype & DATA_BINARY_TYPE) {
@@ -166,10 +242,12 @@ dtype_new_store_for_order_and_null_size(
mach_write_to_2(buf + 2, type->len & 0xFFFFUL);
+ ut_ad(dtype_get_charset_coll(type->prtype) < 256);
mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype));
- /* Note that the second last byte is left unused, because the
- charset-collation code is always < 256 */
+ if (type->prtype & DATA_NOT_NULL) {
+ buf[4] |= 128;
+ }
}
/**************************************************************************
@@ -196,6 +274,7 @@ dtype_read_for_order_and_null_size(
type->prtype = dtype_form_prtype(type->prtype,
data_mysql_default_charset_coll);
+ dtype_set_mblen(type);
}
/**************************************************************************
@@ -211,20 +290,26 @@ dtype_new_read_for_order_and_null_size(
{
ulint charset_coll;
- ut_ad(6 == DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
+#if 6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
+#error "6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE"
+#endif
type->mtype = buf[0] & 63;
type->prtype = buf[1];
if (buf[0] & 128) {
- type->prtype = type->prtype | DATA_BINARY_TYPE;
+ type->prtype |= DATA_BINARY_TYPE;
+ }
+
+ if (buf[4] & 128) {
+ type->prtype |= DATA_NOT_NULL;
}
type->len = mach_read_from_2(buf + 2);
mach_read_from_2(buf + 4);
- charset_coll = mach_read_from_2(buf + 4);
+ charset_coll = mach_read_from_2(buf + 4) & 0x7fff;
if (dtype_is_string_type(type->mtype)) {
ut_a(charset_coll < 256);
@@ -241,8 +326,10 @@ dtype_new_read_for_order_and_null_size(
type->prtype = dtype_form_prtype(type->prtype, charset_coll);
}
+ dtype_set_mblen(type);
}
+#ifndef UNIV_HOTBACKUP
/***************************************************************************
Returns the size of a fixed size data type, 0 if not a fixed size type. */
UNIV_INLINE
@@ -257,23 +344,127 @@ dtype_get_fixed_size(
mtype = dtype_get_mtype(type);
switch (mtype) {
+ case DATA_SYS:
+#ifdef UNIV_DEBUG
+ switch (type->prtype & DATA_MYSQL_TYPE_MASK) {
+ default:
+ ut_ad(0);
+ return(0);
+ case DATA_ROW_ID:
+ ut_ad(type->len == DATA_ROW_ID_LEN);
+ break;
+ case DATA_TRX_ID:
+ ut_ad(type->len == DATA_TRX_ID_LEN);
+ break;
+ case DATA_ROLL_PTR:
+ ut_ad(type->len == DATA_ROLL_PTR_LEN);
+ break;
+ case DATA_MIX_ID:
+ ut_ad(type->len == DATA_MIX_ID_LEN);
+ break;
+ }
+#endif /* UNIV_DEBUG */
case DATA_CHAR:
case DATA_FIXBINARY:
case DATA_INT:
case DATA_FLOAT:
case DATA_DOUBLE:
- case DATA_MYSQL:
return(dtype_get_len(type));
-
- case DATA_SYS: if (type->prtype == DATA_ROW_ID) {
- return(DATA_ROW_ID_LEN);
- } else if (type->prtype == DATA_TRX_ID) {
- return(DATA_TRX_ID_LEN);
- } else if (type->prtype == DATA_ROLL_PTR) {
- return(DATA_ROLL_PTR_LEN);
+ case DATA_MYSQL:
+ if (type->prtype & DATA_BINARY_TYPE) {
+ return(dtype_get_len(type));
} else {
+ /* We play it safe here and ask MySQL for
+ mbminlen and mbmaxlen. Although
+ type->mbminlen and type->mbmaxlen are
+ initialized if and only if type->prtype
+ is (in one of the 3 functions in this file),
+ it could be that none of these functions
+ has been called. */
+
+ ulint mbminlen, mbmaxlen;
+
+ innobase_get_cset_width(
+ dtype_get_charset_coll(type->prtype),
+ &mbminlen, &mbmaxlen);
+
+ if (type->mbminlen != mbminlen
+ || type->mbmaxlen != mbmaxlen) {
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: "
+ "mbminlen=%lu, "
+ "mbmaxlen=%lu, "
+ "type->mbminlen=%lu, "
+ "type->mbmaxlen=%lu\n",
+ (ulong) mbminlen,
+ (ulong) mbmaxlen,
+ (ulong) type->mbminlen,
+ (ulong) type->mbmaxlen);
+ }
+ if (mbminlen == mbmaxlen) {
+ return(dtype_get_len(type));
+ }
+ }
+ /* fall through for variable-length charsets */
+ case DATA_VARCHAR:
+ case DATA_BINARY:
+ case DATA_DECIMAL:
+ case DATA_VARMYSQL:
+ case DATA_BLOB:
+ return(0);
+ default: ut_error;
+ }
+
+ return(0);
+}
+
+/***************************************************************************
+Returns the size of a fixed size data type, 0 if not a fixed size type. */
+UNIV_INLINE
+ulint
+dtype_get_min_size(
+/*===============*/
+ /* out: minimum size */
+ const dtype_t* type) /* in: type */
+{
+ switch (type->mtype) {
+ case DATA_SYS:
+#ifdef UNIV_DEBUG
+ switch (type->prtype & DATA_MYSQL_TYPE_MASK) {
+ default:
+ ut_ad(0);
return(0);
+ case DATA_ROW_ID:
+ ut_ad(type->len == DATA_ROW_ID_LEN);
+ break;
+ case DATA_TRX_ID:
+ ut_ad(type->len == DATA_TRX_ID_LEN);
+ break;
+ case DATA_ROLL_PTR:
+ ut_ad(type->len == DATA_ROLL_PTR_LEN);
+ break;
+ case DATA_MIX_ID:
+ ut_ad(type->len == DATA_MIX_ID_LEN);
+ break;
+ }
+#endif /* UNIV_DEBUG */
+ case DATA_CHAR:
+ case DATA_FIXBINARY:
+ case DATA_INT:
+ case DATA_FLOAT:
+ case DATA_DOUBLE:
+ return(type->len);
+ case DATA_MYSQL:
+ if ((type->prtype & DATA_BINARY_TYPE)
+ || type->mbminlen == type->mbmaxlen) {
+ return(type->len);
}
+ /* this is a variable-length character set */
+ ut_a(type->mbminlen > 0);
+ ut_a(type->mbmaxlen > type->mbminlen);
+ ut_a(type->len % type->mbmaxlen == 0);
+ return(type->len * type->mbminlen / type->mbmaxlen);
case DATA_VARCHAR:
case DATA_BINARY:
case DATA_DECIMAL:
@@ -285,6 +476,7 @@ dtype_get_fixed_size(
return(0);
}
+#endif /* !UNIV_HOTBACKUP */
/***************************************************************************
Returns a stored SQL NULL size for a type. For fixed length types it is
diff --git a/innobase/include/dict0boot.h b/innobase/include/dict0boot.h
index 35eff5af29a..86702cbca05 100644
--- a/innobase/include/dict0boot.h
+++ b/innobase/include/dict0boot.h
@@ -119,6 +119,7 @@ dict_create(void);
clustered index */
#define DICT_SYS_INDEXES_PAGE_NO_FIELD 8
#define DICT_SYS_INDEXES_SPACE_NO_FIELD 7
+#define DICT_SYS_INDEXES_TYPE_FIELD 6
/* When a row id which is zero modulo this number (which must be a power of
two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is
diff --git a/innobase/include/dict0crea.h b/innobase/include/dict0crea.h
index 8b6944fc605..5dd571be59c 100644
--- a/innobase/include/dict0crea.h
+++ b/innobase/include/dict0crea.h
@@ -54,6 +54,20 @@ dict_create_index_step(
/* out: query thread to run next or NULL */
que_thr_t* thr); /* in: query thread */
/***********************************************************************
+Truncates the index tree associated with a row in SYS_INDEXES table. */
+
+ulint
+dict_truncate_index_tree(
+/*=====================*/
+ /* out: new root page number, or
+ FIL_NULL on failure */
+ dict_table_t* table, /* in: the table the index belongs to */
+ rec_t* rec, /* in: record in the clustered index of
+ SYS_INDEXES table */
+ mtr_t* mtr); /* in: mtr having the latch
+ on the record page. The mtr may be
+ committed and restarted in this call. */
+/***********************************************************************
Drops the index tree associated with a row in SYS_INDEXES table. */
void
@@ -142,6 +156,7 @@ struct ind_node_struct{
/*----------------------*/
/* Local storage for this graph node */
ulint state; /* node execution state */
+ ulint page_no;/* root page number of the index */
dict_table_t* table; /* table which owns the index */
dtuple_t* ind_row;/* index definition row built */
ulint field_no;/* next field definition to insert */
diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h
index 3333385ec56..d9cda402bac 100644
--- a/innobase/include/dict0dict.h
+++ b/innobase/include/dict0dict.h
@@ -516,8 +516,9 @@ dict_index_add_to_cache(
/*====================*/
/* out: TRUE if success */
dict_table_t* table, /* in: table on which the index is */
- dict_index_t* index); /* in, own: index; NOTE! The index memory
+ dict_index_t* index, /* in, own: index; NOTE! The index memory
object is freed in this function! */
+ ulint page_no);/* in: root page number of the index */
/************************************************************************
Gets the number of fields in the internal representation of an index,
including fields added by the dictionary system. */
@@ -647,6 +648,16 @@ dict_index_get_sys_col_pos(
dict_index_t* index, /* in: index */
ulint type); /* in: DATA_ROW_ID, ... */
/***********************************************************************
+Adds a column to index. */
+
+void
+dict_index_add_col(
+/*===============*/
+ dict_index_t* index, /* in: index */
+ dict_col_t* col, /* in: column */
+ ulint order, /* in: order criterion */
+ ulint prefix_len); /* in: column prefix length */
+/***********************************************************************
Copies types of fields contained in index to tuple. */
void
@@ -655,18 +666,6 @@ dict_index_copy_types(
dtuple_t* tuple, /* in: data tuple */
dict_index_t* index, /* in: index */
ulint n_fields); /* in: number of field types to copy */
-/************************************************************************
-Gets the value of a system column in a clustered index record. The clustered
-index must contain the system column: if the index is unique, row id is
-not contained there! */
-UNIV_INLINE
-dulint
-dict_index_rec_get_sys_col(
-/*=======================*/
- /* out: system column value */
- dict_index_t* index, /* in: clustered index describing the record */
- ulint type, /* in: column type: DATA_ROLL_PTR, ... */
- rec_t* rec); /* in: record */
/*************************************************************************
Gets the index tree where the index is stored. */
UNIV_INLINE
@@ -696,9 +695,10 @@ dict_tree_t*
dict_tree_create(
/*=============*/
/* out, own: created tree */
- dict_index_t* index); /* in: the index for which to create: in the
+ dict_index_t* index, /* in: the index for which to create: in the
case of a mixed tree, this should be the
index of the cluster object */
+ ulint page_no);/* in: root page number of the index */
/**************************************************************************
Frees an index tree struct. */
@@ -728,7 +728,7 @@ dict_tree_find_index_for_tuple(
dtuple_t* tuple); /* in: tuple for which to find index */
/***********************************************************************
Checks if a table which is a mixed cluster member owns a record. */
-UNIV_INLINE
+
ibool
dict_is_mixed_table_rec(
/*====================*/
@@ -778,6 +778,7 @@ dict_tree_copy_rec_order_prefix(
/* out: pointer to the prefix record */
dict_tree_t* tree, /* in: index tree */
rec_t* rec, /* in: record for which to copy prefix */
+ ulint* n_fields,/* out: number of fields copied */
byte** buf, /* in/out: memory buffer for the copied prefix,
or NULL */
ulint* buf_size);/* in/out: buffer size */
@@ -790,6 +791,7 @@ dict_tree_build_data_tuple(
/* out, own: data tuple */
dict_tree_t* tree, /* in: index tree */
rec_t* rec, /* in: record for which to build data tuple */
+ ulint n_fields,/* in: number of data fields */
mem_heap_t* heap); /* in: memory heap where tuple created */
/*************************************************************************
Gets the space id of the root of the index tree. */
diff --git a/innobase/include/dict0dict.ic b/innobase/include/dict0dict.ic
index 85e4aaf1a05..928a693f860 100644
--- a/innobase/include/dict0dict.ic
+++ b/innobase/include/dict0dict.ic
@@ -9,7 +9,6 @@ Created 1/8/1996 Heikki Tuuri
#include "dict0load.h"
#include "trx0undo.h"
#include "trx0sys.h"
-#include "rem0rec.h"
/*************************************************************************
Gets the column data type. */
@@ -168,7 +167,7 @@ dict_table_get_sys_col(
col = dict_table_get_nth_col(table, table->n_cols
- DATA_N_SYS_COLS + sys);
ut_ad(col->type.mtype == DATA_SYS);
- ut_ad(col->type.prtype == sys);
+ ut_ad(col->type.prtype == (sys | DATA_NOT_NULL));
return(col);
}
@@ -312,49 +311,6 @@ dict_index_get_sys_col_pos(
dict_table_get_sys_col_no(index->table, type)));
}
-/************************************************************************
-Gets the value of a system column in a clustered index record. The clustered
-index must contain the system column: if the index is unique, row id is
-not contained there! */
-UNIV_INLINE
-dulint
-dict_index_rec_get_sys_col(
-/*=======================*/
- /* out: system column value */
- dict_index_t* index, /* in: clustered index describing the record */
- ulint type, /* in: column type: DATA_ROLL_PTR, ... */
- rec_t* rec) /* in: record */
-{
- ulint pos;
- byte* field;
- ulint len;
-
- ut_ad(index);
- ut_ad(index->type & DICT_CLUSTERED);
-
- pos = dict_index_get_sys_col_pos(index, type);
-
- ut_ad(pos != ULINT_UNDEFINED);
-
- field = rec_get_nth_field(rec, pos, &len);
-
- if (type == DATA_ROLL_PTR) {
- ut_ad(len == 7);
-
- return(trx_read_roll_ptr(field));
- } else if (type == DATA_TRX_ID) {
-
- return(trx_read_trx_id(field));
- } else if (type == DATA_MIX_ID) {
-
- return(mach_dulint_read_compressed(field));
- } else {
- ut_a(type == DATA_ROW_ID);
-
- return(mach_read_from_6(field));
- }
-}
-
/*************************************************************************
Gets the index tree where the index is stored. */
UNIV_INLINE
@@ -662,28 +618,3 @@ dict_table_get_index(
return(index);
}
-
-/***********************************************************************
-Checks if a table which is a mixed cluster member owns a record. */
-UNIV_INLINE
-ibool
-dict_is_mixed_table_rec(
-/*====================*/
- /* out: TRUE if the record belongs to this
- table */
- dict_table_t* table, /* in: table in a mixed cluster */
- rec_t* rec) /* in: user record in the clustered index */
-{
- byte* mix_id_field;
- ulint len;
-
- mix_id_field = rec_get_nth_field(rec, table->mix_len, &len);
-
- if ((len != table->mix_id_len)
- || (0 != ut_memcmp(table->mix_id_buf, mix_id_field, len))) {
-
- return(FALSE);
- }
-
- return(TRUE);
-}
diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h
index 1e496a25477..ff6c4ec9b28 100644
--- a/innobase/include/dict0mem.h
+++ b/innobase/include/dict0mem.h
@@ -54,7 +54,8 @@ dict_mem_table_create(
of the table is placed; this parameter
is ignored if the table is made
a member of a cluster */
- ulint n_cols); /* in: number of columns */
+ ulint n_cols, /* in: number of columns */
+ ibool comp); /* in: TRUE=compact page format */
/**************************************************************************
Creates a cluster memory object. */
@@ -171,6 +172,13 @@ struct dict_field_struct{
DICT_MAX_COL_PREFIX_LEN; NOTE that
in the UTF-8 charset, MySQL sets this
to 3 * the prefix len in UTF-8 chars */
+ ulint fixed_len; /* 0 or the fixed length of the
+ column if smaller than
+ DICT_MAX_COL_PREFIX_LEN */
+ ulint fixed_offs; /* offset to the field, or
+ ULINT_UNDEFINED if it is not fixed
+ within the record (due to preceding
+ variable-length fields) */
};
/* Data structure for an index tree */
@@ -210,7 +218,6 @@ struct dict_index_struct{
const char* table_name; /* table name */
dict_table_t* table; /* back pointer to table */
ulint space; /* space where the index tree is placed */
- ulint page_no;/* page number of the index tree root */
ulint trx_id_offset;/* position of the the trx id column
in a clustered index record, if the fields
before it are known to be of a fixed size,
@@ -225,6 +232,7 @@ struct dict_index_struct{
ulint n_def; /* number of fields defined so far */
ulint n_fields;/* number of fields in the index */
dict_field_t* fields; /* array of field descriptions */
+ ulint n_nullable;/* number of nullable fields */
UT_LIST_NODE_T(dict_index_t)
indexes;/* list of indexes of the table */
dict_tree_t* tree; /* index tree struct */
@@ -320,6 +328,7 @@ struct dict_table_struct{
ibool tablespace_discarded;/* this flag is set TRUE when the
user calls DISCARD TABLESPACE on this table,
and reset to FALSE in IMPORT TABLESPACE */
+ ibool comp; /* flag: TRUE=compact page format */
hash_node_t name_hash; /* hash chain node */
hash_node_t id_hash; /* hash chain node */
ulint n_def; /* number of columns defined so far */
diff --git a/innobase/include/fil0fil.h b/innobase/include/fil0fil.h
index c1a127aadca..aa1ec5c25a5 100644
--- a/innobase/include/fil0fil.h
+++ b/innobase/include/fil0fil.h
@@ -89,6 +89,8 @@ extern fil_addr_t fil_addr_null;
#define FIL_TABLESPACE 501
#define FIL_LOG 502
+extern ulint fil_n_log_flushes;
+
extern ulint fil_n_pending_log_flushes;
extern ulint fil_n_pending_tablespace_flushes;
diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h
index 1fd7492d517..710c945375c 100644
--- a/innobase/include/lock0lock.h
+++ b/innobase/include/lock0lock.h
@@ -47,7 +47,8 @@ lock_sec_rec_some_has_impl_off_kernel(
/* out: transaction which has the x-lock, or
NULL */
rec_t* rec, /* in: user record */
- dict_index_t* index); /* in: secondary index */
+ dict_index_t* index, /* in: secondary index */
+ const ulint* offsets);/* in: rec_get_offsets(rec, index) */
/*************************************************************************
Checks if some transaction has an implicit x-lock on a record in a clustered
index. */
@@ -58,7 +59,8 @@ lock_clust_rec_some_has_impl(
/* out: transaction which has the x-lock, or
NULL */
rec_t* rec, /* in: user record */
- dict_index_t* index); /* in: clustered index */
+ dict_index_t* index, /* in: clustered index */
+ const ulint* offsets);/* in: rec_get_offsets(rec, index) */
/*****************************************************************
Resets the lock bits for a single record. Releases transactions
waiting for lock requests here. */
@@ -275,6 +277,7 @@ lock_clust_rec_modify_check_and_lock(
does nothing */
rec_t* rec, /* in: record which should be modified */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
que_thr_t* thr); /* in: query thread */
/*************************************************************************
Checks if locks of other transactions prevent an immediate modify
@@ -308,6 +311,7 @@ lock_sec_rec_read_check_and_lock(
which should be read or passed over by a read
cursor */
dict_index_t* index, /* in: secondary index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
ulint mode, /* in: mode of the lock which the read cursor
should set on records: LOCK_S or LOCK_X; the
latter is possible in SELECT FOR UPDATE */
@@ -333,6 +337,34 @@ lock_clust_rec_read_check_and_lock(
which should be read or passed over by a read
cursor */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
+ ulint mode, /* in: mode of the lock which the read cursor
+ should set on records: LOCK_S or LOCK_X; the
+ latter is possible in SELECT FOR UPDATE */
+ ulint gap_mode,/* in: LOCK_ORDINARY, LOCK_GAP, or
+ LOCK_REC_NOT_GAP */
+ que_thr_t* thr); /* in: query thread */
+/*************************************************************************
+Checks if locks of other transactions prevent an immediate read, or passing
+over by a read cursor, of a clustered index record. If they do, first tests
+if the query thread should anyway be suspended for some reason; if not, then
+puts the transaction and the query thread to the lock wait state and inserts a
+waiting request for a record lock to the lock queue. Sets the requested mode
+lock on the record. This is an alternative version of
+lock_clust_rec_read_check_and_lock() that does not require the parameter
+"offsets". */
+
+ulint
+lock_clust_rec_read_check_and_lock_alt(
+/*===================================*/
+ /* 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 */
+ rec_t* rec, /* in: user record or page supremum record
+ which should be read or passed over by a read
+ cursor */
+ dict_index_t* index, /* in: clustered index */
ulint mode, /* in: mode of the lock which the read cursor
should set on records: LOCK_S or LOCK_X; the
latter is possible in SELECT FOR UPDATE */
@@ -350,6 +382,7 @@ lock_clust_rec_cons_read_sees(
rec_t* rec, /* in: user record which should be read or
passed over by a read cursor */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
read_view_t* view); /* in: consistent read view */
/*************************************************************************
Checks that a non-clustered index record is seen in a consistent read. */
@@ -499,6 +532,7 @@ lock_check_trx_id_sanity(
dulint trx_id, /* in: trx id */
rec_t* rec, /* in: user record */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets, /* in: rec_get_offsets(rec, index) */
ibool has_kernel_mutex);/* in: TRUE if the caller owns the
kernel mutex */
/*************************************************************************
@@ -509,7 +543,8 @@ lock_rec_queue_validate(
/*====================*/
/* out: TRUE if ok */
rec_t* rec, /* in: record to look at */
- dict_index_t* index); /* in: index, or NULL if not known */
+ dict_index_t* index, /* in: index, or NULL if not known */
+ const ulint* offsets);/* in: rec_get_offsets(rec, index) */
/*************************************************************************
Prints info of a table lock. */
@@ -577,6 +612,8 @@ extern lock_sys_t* lock_sys;
#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/lock0lock.ic b/innobase/include/lock0lock.ic
index fabc9256401..c7a71bb45d8 100644
--- a/innobase/include/lock0lock.ic
+++ b/innobase/include/lock0lock.ic
@@ -60,7 +60,8 @@ lock_clust_rec_some_has_impl(
/* out: transaction which has the x-lock, or
NULL */
rec_t* rec, /* in: user record */
- dict_index_t* index) /* in: clustered index */
+ dict_index_t* index, /* in: clustered index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
dulint trx_id;
@@ -70,7 +71,7 @@ lock_clust_rec_some_has_impl(
ut_ad(index->type & DICT_CLUSTERED);
ut_ad(page_rec_is_user_rec(rec));
- trx_id = row_get_rec_trx_id(rec, index);
+ trx_id = row_get_rec_trx_id(rec, index, offsets);
if (trx_is_active(trx_id)) {
/* The modifying or inserting transaction is active */
diff --git a/innobase/include/mtr0log.h b/innobase/include/mtr0log.h
index 9c9c6f696e8..c0636ea1e1e 100644
--- a/innobase/include/mtr0log.h
+++ b/innobase/include/mtr0log.h
@@ -11,6 +11,7 @@ Created 12/7/1995 Heikki Tuuri
#include "univ.i"
#include "mtr0mtr.h"
+#include "dict0types.h"
/************************************************************
Writes 1 - 4 bytes to a file page buffered in the buffer pool.
@@ -173,6 +174,38 @@ mlog_parse_string(
byte* page); /* in: page where to apply the log record, or NULL */
+/************************************************************
+Opens a buffer for mlog, writes the initial log record and,
+if needed, the field lengths of an index. Reserves space
+for further log entries. The log entry must be closed with
+mtr_close(). */
+
+byte*
+mlog_open_and_write_index(
+/*======================*/
+ /* out: buffer, NULL if log mode
+ MTR_LOG_NONE */
+ mtr_t* mtr, /* in: mtr */
+ byte* rec, /* in: index record or page */
+ dict_index_t* index, /* in: record descriptor */
+ byte type, /* in: log item type */
+ ulint size); /* in: requested buffer size in bytes
+ (if 0, calls mlog_close() and returns NULL) */
+
+/************************************************************
+Parses a log record written by mlog_open_and_write_index. */
+
+byte*
+mlog_parse_index(
+/*=============*/
+ /* out: parsed record end,
+ NULL if not a complete record */
+ byte* ptr, /* in: buffer */
+ byte* end_ptr,/* in: buffer end */
+ /* out: new value of log_ptr */
+ ibool comp, /* in: TRUE=compact record format */
+ dict_index_t** index); /* out, own: dummy index */
+
/* Insert, update, and maybe other functions may use this value to define an
extra mlog buffer size for variable size data */
#define MLOG_BUF_MARGIN 256
diff --git a/innobase/include/mtr0mtr.h b/innobase/include/mtr0mtr.h
index e8c68a91dad..071279d5259 100644
--- a/innobase/include/mtr0mtr.h
+++ b/innobase/include/mtr0mtr.h
@@ -102,7 +102,31 @@ flag value must give the length also! */
file rename */
#define MLOG_FILE_DELETE ((byte)35) /* log record about an .ibd
file deletion */
-#define MLOG_BIGGEST_TYPE ((byte)35) /* biggest value (used in
+#define MLOG_COMP_REC_MIN_MARK ((byte)36) /* mark a compact index record
+ as the predefined minimum
+ record */
+#define MLOG_COMP_PAGE_CREATE ((byte)37) /* create a compact
+ index page */
+#define MLOG_COMP_REC_INSERT ((byte)38) /* compact record insert */
+#define MLOG_COMP_REC_CLUST_DELETE_MARK ((byte)39)
+ /* mark compact clustered index
+ record deleted */
+#define MLOG_COMP_REC_SEC_DELETE_MARK ((byte)40)/* mark compact secondary index
+ record deleted */
+#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
+ from a page */
+#define MLOG_COMP_LIST_END_DELETE ((byte)43) /* delete compact record list
+ end on index page */
+#define MLOG_COMP_LIST_START_DELETE ((byte)44) /* delete compact record list
+ start on index page */
+#define MLOG_COMP_LIST_END_COPY_CREATED ((byte)45)
+ /* copy compact record list end
+ to a new created index page */
+#define MLOG_COMP_PAGE_REORGANIZE ((byte)46) /* reorganize an index page */
+
+#define MLOG_BIGGEST_TYPE ((byte)46) /* biggest value (used in
asserts) */
/*******************************************************************
diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h
index ebc014df9fd..f55c345537e 100644
--- a/innobase/include/os0file.h
+++ b/innobase/include/os0file.h
@@ -24,6 +24,9 @@ extern ibool os_aio_print_debug;
extern ulint os_file_n_pending_preads;
extern ulint os_file_n_pending_pwrites;
+extern ulint os_n_pending_reads;
+extern ulint os_n_pending_writes;
+
#ifdef __WIN__
/* We define always WIN_ASYNC_IO, and check at run-time whether
diff --git a/innobase/include/os0proc.h b/innobase/include/os0proc.h
index d0d3cf82e38..b0b72e18675 100644
--- a/innobase/include/os0proc.h
+++ b/innobase/include/os0proc.h
@@ -12,6 +12,11 @@ Created 9/30/1995 Heikki Tuuri
#include "univ.i"
+#ifdef UNIV_LINUX
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif
+
typedef void* os_process_t;
typedef unsigned long int os_process_id_t;
@@ -27,6 +32,10 @@ page size of an Intel x86 processor. We cannot use AWE with 2 MB or 4 MB
pages. */
#define OS_AWE_X86_PAGE_SIZE 4096
+extern ibool os_use_large_pages;
+/* Large page size. This may be a boot-time option on some platforms */
+extern ulint os_large_page_size;
+
/********************************************************************
Windows AWE support. Tries to enable the "lock pages in memory" privilege for
the current process so that the current process can allocate memory-locked
@@ -103,6 +112,25 @@ os_mem_alloc_nocache(
/* out: allocated memory */
ulint n); /* in: number of bytes */
/********************************************************************
+Allocates large pages memory. */
+
+void*
+os_mem_alloc_large(
+/*=================*/
+ /* out: allocated memory */
+ ulint n, /* in: number of bytes */
+ ibool set_to_zero, /* in: TRUE if allocated memory should be set
+ to zero if UNIV_SET_MEM_TO_ZERO is defined */
+ ibool assert_on_error); /* in: if TRUE, we crash mysqld if the memory
+ cannot be allocated */
+/********************************************************************
+Frees large pages memory. */
+
+void
+os_mem_free_large(
+/*=================*/
+void *ptr); /* in: number of bytes */
+/********************************************************************
Sets the priority boost for threads released from waiting within the current
process. */
diff --git a/innobase/include/page0cur.h b/innobase/include/page0cur.h
index c85669ed4df..4fc62f37db7 100644
--- a/innobase/include/page0cur.h
+++ b/innobase/include/page0cur.h
@@ -128,7 +128,8 @@ page_cur_tuple_insert(
/* out: pointer to record if succeed, NULL
otherwise */
page_cur_t* cursor, /* in: a page cursor */
- dtuple_t* tuple, /* in: pointer to a data tuple */
+ dtuple_t* tuple, /* in: pointer to a data tuple */
+ dict_index_t* index, /* in: record descriptor */
mtr_t* mtr); /* in: mini-transaction handle */
/***************************************************************
Inserts a record next to page cursor. Returns pointer to inserted record if
@@ -142,6 +143,8 @@ page_cur_rec_insert(
otherwise */
page_cur_t* cursor, /* in: a page cursor */
rec_t* rec, /* in: record to insert */
+ dict_index_t* index, /* in: record descriptor */
+ ulint* offsets,/* in: rec_get_offsets(rec, index) */
mtr_t* mtr); /* in: mini-transaction handle */
/***************************************************************
Inserts a record next to page cursor. Returns pointer to inserted record if
@@ -155,9 +158,10 @@ page_cur_insert_rec_low(
/* out: pointer to record if succeed, NULL
otherwise */
page_cur_t* cursor, /* in: a page cursor */
- dtuple_t* tuple, /* in: pointer to a data tuple or NULL */
- ulint data_size,/* in: data size of tuple */
- rec_t* rec, /* in: pointer to a physical record or NULL */
+ dtuple_t* tuple, /* in: pointer to a data tuple or NULL */
+ dict_index_t* index, /* in: record descriptor */
+ rec_t* rec, /* in: pointer to a physical record or NULL */
+ ulint* offsets,/* in: rec_get_offsets(rec, index) or NULL */
mtr_t* mtr); /* in: mini-transaction handle */
/*****************************************************************
Copies records from page to a newly created page, from a given record onward,
@@ -166,10 +170,11 @@ including that record. Infimum and supremum records are not copied. */
void
page_copy_rec_list_end_to_created_page(
/*===================================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: first record to copy */
- mtr_t* mtr); /* in: mtr */
+ page_t* new_page, /* in: index page to copy to */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: first record to copy */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr); /* in: mtr */
/***************************************************************
Deletes a record at the page cursor. The cursor is moved to the
next record after the deleted one. */
@@ -177,8 +182,10 @@ next record after the deleted one. */
void
page_cur_delete_rec(
/*================*/
- page_cur_t* cursor, /* in: a page cursor */
- mtr_t* mtr); /* in: mini-transaction handle */
+ page_cur_t* cursor, /* in: a page cursor */
+ dict_index_t* index, /* in: record descriptor */
+ const ulint* offsets,/* in: rec_get_offsets(cursor->rec, index) */
+ mtr_t* mtr); /* in: mini-transaction handle */
/********************************************************************
Searches the right position for a page cursor. */
UNIV_INLINE
@@ -187,6 +194,7 @@ page_cur_search(
/*============*/
/* out: number of matched fields on the left */
page_t* page, /* in: index page */
+ dict_index_t* index, /* in: record descriptor */
dtuple_t* tuple, /* in: data tuple */
ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
or PAGE_CUR_GE */
@@ -198,6 +206,7 @@ void
page_cur_search_with_match(
/*=======================*/
page_t* page, /* in: index page */
+ dict_index_t* index, /* in: record descriptor */
dtuple_t* tuple, /* in: data tuple */
ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
or PAGE_CUR_GE */
@@ -229,34 +238,37 @@ Parses a log record of a record insert on a page. */
byte*
page_cur_parse_insert_rec(
/*======================*/
- /* out: end of log record or NULL */
- ibool is_short,/* in: TRUE if short inserts */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
+ /* out: end of log record or NULL */
+ ibool is_short,/* in: TRUE if short inserts */
+ byte* ptr, /* in: buffer */
+ byte* end_ptr,/* in: buffer end */
+ dict_index_t* index, /* in: record descriptor */
+ page_t* page, /* in: page or NULL */
+ mtr_t* mtr); /* in: mtr or NULL */
/**************************************************************
Parses a log record of copying a record list end to a new created page. */
byte*
page_parse_copy_rec_list_to_created_page(
/*=====================================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
+ /* 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 */
+ mtr_t* mtr); /* in: mtr or NULL */
/***************************************************************
Parses log record of a record delete on a page. */
byte*
page_cur_parse_delete_rec(
/*======================*/
- /* out: pointer to record end or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
+ /* out: pointer to record end 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 */
+ mtr_t* mtr); /* in: mtr or NULL */
/* Index page cursor */
diff --git a/innobase/include/page0cur.ic b/innobase/include/page0cur.ic
index 39f8ab11513..e99d799b372 100644
--- a/innobase/include/page0cur.ic
+++ b/innobase/include/page0cur.ic
@@ -143,7 +143,7 @@ UNIV_INLINE
void
page_cur_move_to_prev(
/*==================*/
- page_cur_t* cur) /* in: cursor; must not before first */
+ page_cur_t* cur) /* in: page cursor, not before first */
{
ut_ad(!page_cur_is_before_first(cur));
@@ -158,6 +158,7 @@ page_cur_search(
/*============*/
/* out: number of matched fields on the left */
page_t* page, /* in: index page */
+ dict_index_t* index, /* in: record descriptor */
dtuple_t* tuple, /* in: data tuple */
ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
or PAGE_CUR_GE */
@@ -170,7 +171,7 @@ page_cur_search(
ut_ad(dtuple_check_typed(tuple));
- page_cur_search_with_match(page, tuple, mode,
+ page_cur_search_with_match(page, index, tuple, mode,
&up_matched_fields,
&up_matched_bytes,
&low_matched_fields,
@@ -190,16 +191,11 @@ page_cur_tuple_insert(
/* out: pointer to record if succeed, NULL
otherwise */
page_cur_t* cursor, /* in: a page cursor */
- dtuple_t* tuple, /* in: pointer to a data tuple */
+ dtuple_t* tuple, /* in: pointer to a data tuple */
+ dict_index_t* index, /* in: record descriptor */
mtr_t* mtr) /* in: mini-transaction handle */
{
- ulint data_size;
-
- ut_ad(dtuple_check_typed(tuple));
-
- data_size = dtuple_get_data_size(tuple);
-
- return(page_cur_insert_rec_low(cursor, tuple, data_size, NULL, mtr));
+ return(page_cur_insert_rec_low(cursor, tuple, index, NULL, NULL, mtr));
}
/***************************************************************
@@ -214,8 +210,11 @@ page_cur_rec_insert(
otherwise */
page_cur_t* cursor, /* in: a page cursor */
rec_t* rec, /* in: record to insert */
+ dict_index_t* index, /* in: record descriptor */
+ ulint* offsets,/* in: rec_get_offsets(rec, index) */
mtr_t* mtr) /* in: mini-transaction handle */
{
- return(page_cur_insert_rec_low(cursor, NULL, 0, rec, mtr));
+ return(page_cur_insert_rec_low(cursor, NULL, index, rec,
+ offsets, mtr));
}
diff --git a/innobase/include/page0page.h b/innobase/include/page0page.h
index 969313614e3..144c297b811 100644
--- a/innobase/include/page0page.h
+++ b/innobase/include/page0page.h
@@ -37,7 +37,8 @@ typedef byte page_header_t;
/*-----------------------------*/
#define PAGE_N_DIR_SLOTS 0 /* number of slots in page directory */
#define PAGE_HEAP_TOP 2 /* pointer to record heap top */
-#define PAGE_N_HEAP 4 /* number of records in the heap */
+#define PAGE_N_HEAP 4 /* number of records in the heap,
+ bit 15=flag: new-style compact page format */
#define PAGE_FREE 6 /* pointer to start of page free record list */
#define PAGE_GARBAGE 8 /* number of bytes in deleted records */
#define PAGE_LAST_INSERT 10 /* pointer to the last inserted record, or
@@ -79,15 +80,24 @@ typedef byte page_header_t;
#define PAGE_DATA (PAGE_HEADER + 36 + 2 * FSEG_HEADER_SIZE)
/* start of data on the page */
-#define PAGE_INFIMUM (PAGE_DATA + 1 + REC_N_EXTRA_BYTES)
- /* offset of the page infimum record on the
- page */
-#define PAGE_SUPREMUM (PAGE_DATA + 2 + 2 * REC_N_EXTRA_BYTES + 8)
- /* offset of the page supremum record on the
- page */
-#define PAGE_SUPREMUM_END (PAGE_SUPREMUM + 9)
+#define PAGE_OLD_INFIMUM (PAGE_DATA + 1 + REC_N_OLD_EXTRA_BYTES)
+ /* offset of the page infimum record on an
+ old-style page */
+#define PAGE_OLD_SUPREMUM (PAGE_DATA + 2 + 2 * REC_N_OLD_EXTRA_BYTES + 8)
+ /* offset of the page supremum record on an
+ old-style page */
+#define PAGE_OLD_SUPREMUM_END (PAGE_OLD_SUPREMUM + 9)
/* offset of the page supremum record end on
- the page */
+ an old-style page */
+#define PAGE_NEW_INFIMUM (PAGE_DATA + REC_N_NEW_EXTRA_BYTES)
+ /* offset of the page infimum record on a
+ new-style compact page */
+#define PAGE_NEW_SUPREMUM (PAGE_DATA + 2 * REC_N_NEW_EXTRA_BYTES + 8)
+ /* offset of the page supremum record on a
+ new-style compact page */
+#define PAGE_NEW_SUPREMUM_END (PAGE_NEW_SUPREMUM + 8)
+ /* offset of the page supremum record end on
+ a new-style compact page */
/*-----------------------------*/
/* Directions of cursor movement */
@@ -233,6 +243,7 @@ page_cmp_dtuple_rec_with_match(
be page infimum or supremum, in which case
matched-parameter values below are not
affected */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint* matched_fields, /* in/out: number of already completely
matched fields; when function returns
contains the value for current comparison */
@@ -259,6 +270,22 @@ page_rec_get_n_recs_before(
/* out: number of records */
rec_t* rec); /* in: the physical record */
/*****************************************************************
+Gets the number of records in the heap. */
+UNIV_INLINE
+ulint
+page_dir_get_n_heap(
+/*================*/
+ /* out: number of user records */
+ page_t* page); /* in: index page */
+/*****************************************************************
+Sets the number of records in the heap. */
+UNIV_INLINE
+void
+page_dir_set_n_heap(
+/*================*/
+ page_t* page, /* in: index page */
+ ulint n_heap);/* in: number of records */
+/*****************************************************************
Gets the number of dir slots in directory. */
UNIV_INLINE
ulint
@@ -267,6 +294,15 @@ page_dir_get_n_slots(
/* out: number of slots */
page_t* page); /* in: index page */
/*****************************************************************
+Sets the number of dir slots in directory. */
+UNIV_INLINE
+void
+page_dir_set_n_slots(
+/*=================*/
+ /* out: number of slots */
+ page_t* page, /* in: index page */
+ ulint n_slots);/* in: number of slots */
+/*****************************************************************
Gets pointer to nth directory slot. */
UNIV_INLINE
page_dir_slot_t*
@@ -333,7 +369,16 @@ ulint
page_dir_find_owner_slot(
/*=====================*/
/* out: the directory slot number */
- rec_t* rec); /* in: the physical record */
+ rec_t* rec); /* in: the physical record */
+/****************************************************************
+Determine whether the page is in new-style compact format. */
+UNIV_INLINE
+ibool
+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 */
/****************************************************************
Gets the pointer to the next record on the page. */
UNIV_INLINE
@@ -359,9 +404,10 @@ UNIV_INLINE
rec_t*
page_rec_get_prev(
/*==============*/
- /* out: pointer to previous record */
- rec_t* rec); /* in: pointer to record, must not be page
- infimum */
+ /* 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
@@ -446,9 +492,11 @@ page_get_max_insert_size_after_reorganize(
Calculates free space if a page is emptied. */
UNIV_INLINE
ulint
-page_get_free_space_of_empty(void);
-/*==============================*/
- /* out: free space */
+page_get_free_space_of_empty(
+/*=========================*/
+ /* out: free space */
+ ibool comp) /* in: TRUE=compact page format */
+ __attribute__((const));
/****************************************************************
Returns the sum of the sizes of the records in the record list
excluding the infimum and supremum records. */
@@ -464,20 +512,23 @@ Allocates a block of memory from an index page. */
byte*
page_mem_alloc(
/*===========*/
- /* out: pointer to start of allocated
- buffer, or NULL if allocation fails */
- page_t* page, /* in: index page */
- ulint need, /* in: number of bytes needed */
- ulint* heap_no);/* out: this contains the heap number
- of the allocated record if allocation succeeds */
+ /* out: pointer to start of allocated
+ buffer, or NULL if allocation fails */
+ page_t* page, /* in: index page */
+ ulint need, /* in: number of bytes needed */
+ dict_index_t* index, /* in: record descriptor */
+ ulint* heap_no);/* out: this contains the heap number
+ of the allocated record
+ if allocation succeeds */
/****************************************************************
Puts a record to free list. */
UNIV_INLINE
void
page_mem_free(
/*==========*/
- page_t* page, /* in: index page */
- rec_t* rec); /* in: pointer to the (origin of) record */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: pointer to the (origin of) record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/**************************************************************
The index page creation function. */
@@ -487,7 +538,8 @@ page_create(
/* out: pointer to the page */
buf_frame_t* frame, /* in: a buffer frame where the page is
created */
- mtr_t* mtr); /* in: mini-transaction handle */
+ mtr_t* mtr, /* in: mini-transaction handle */
+ ibool comp); /* in: TRUE=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. */
@@ -495,10 +547,11 @@ touch the lock table and max trx id on page. */
void
page_copy_rec_list_end_no_locks(
/*============================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- mtr_t* mtr); /* in: mtr */
+ page_t* new_page, /* in: index page to copy to */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr); /* in: mtr */
/*****************************************************************
Copies records from page to new_page, from the given record onward,
including that record. Infimum and supremum records are not copied.
@@ -507,10 +560,11 @@ The records are copied to the start of the record list on new_page. */
void
page_copy_rec_list_end(
/*===================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- mtr_t* mtr); /* in: mtr */
+ page_t* new_page, /* in: index page to copy to */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr); /* in: mtr */
/*****************************************************************
Copies records from page to new_page, up to the given record, NOT
including that record. Infimum and supremum records are not copied.
@@ -519,10 +573,11 @@ The records are copied to the end of the record list on new_page. */
void
page_copy_rec_list_start(
/*=====================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- mtr_t* mtr); /* in: mtr */
+ page_t* new_page, /* in: index page to copy to */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr); /* in: mtr */
/*****************************************************************
Deletes records from a page from a given record onward, including that record.
The infimum and supremum records are not deleted. */
@@ -530,14 +585,15 @@ The infimum and supremum records are not deleted. */
void
page_delete_rec_list_end(
/*=====================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- ulint n_recs, /* in: number of records to delete, or ULINT_UNDEFINED
- if not known */
- ulint size, /* in: the sum of the sizes of the records in the end
- of the chain to delete, or ULINT_UNDEFINED if not
- known */
- mtr_t* mtr); /* in: mtr */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ ulint n_recs, /* in: number of records to delete,
+ or ULINT_UNDEFINED if not known */
+ ulint size, /* in: the sum of the sizes of the
+ records in the end of the chain to
+ delete, or ULINT_UNDEFINED if not known */
+ mtr_t* mtr); /* in: mtr */
/*****************************************************************
Deletes records from page, up to the given record, NOT including
that record. Infimum and supremum records are not deleted. */
@@ -545,9 +601,10 @@ that record. Infimum and supremum records are not deleted. */
void
page_delete_rec_list_start(
/*=======================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- mtr_t* mtr); /* in: mtr */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr); /* in: mtr */
/*****************************************************************
Moves record list end to another page. Moved records include
split_rec. */
@@ -555,10 +612,11 @@ split_rec. */
void
page_move_rec_list_end(
/*===================*/
- page_t* new_page, /* in: index page where to move */
- page_t* page, /* in: index page */
- rec_t* split_rec, /* in: first record to move */
- mtr_t* mtr); /* in: mtr */
+ page_t* new_page, /* in: index page where to move */
+ page_t* page, /* in: index page */
+ rec_t* split_rec, /* in: first record to move */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr); /* in: mtr */
/*****************************************************************
Moves record list start to another page. Moved records do not include
split_rec. */
@@ -566,10 +624,11 @@ split_rec. */
void
page_move_rec_list_start(
/*=====================*/
- page_t* new_page, /* in: index page where to move */
- page_t* page, /* in: index page */
- rec_t* split_rec, /* in: first record not to move */
- mtr_t* mtr); /* in: mtr */
+ page_t* new_page, /* in: index page where to move */
+ page_t* page, /* in: index page */
+ rec_t* split_rec, /* in: first record not to move */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr); /* in: mtr */
/********************************************************************
Splits a directory slot which owns too many records. */
@@ -595,13 +654,16 @@ Parses a log record of a record list end or start deletion. */
byte*
page_parse_delete_rec_list(
/*=======================*/
- /* out: end of log record or NULL */
- byte type, /* in: MLOG_LIST_END_DELETE or
- MLOG_LIST_START_DELETE */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
+ /* out: end of log record or NULL */
+ byte type, /* in: MLOG_LIST_END_DELETE,
+ MLOG_LIST_START_DELETE,
+ MLOG_COMP_LIST_END_DELETE or
+ MLOG_COMP_LIST_START_DELETE */
+ byte* ptr, /* in: buffer */
+ byte* end_ptr,/* in: buffer end */
+ dict_index_t* index, /* in: record descriptor */
+ page_t* page, /* in: page or NULL */
+ mtr_t* mtr); /* in: mtr or NULL */
/***************************************************************
Parses a redo log record of creating a page. */
@@ -611,6 +673,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 */
page_t* page, /* in: page or NULL */
mtr_t* mtr); /* in: mtr or NULL */
/****************************************************************
@@ -620,7 +683,8 @@ the index page context. */
void
page_rec_print(
/*===========*/
- rec_t* rec);
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets);/* in: record descriptor */
/*******************************************************************
This is used to print the contents of the directory for
debugging purposes. */
@@ -637,8 +701,9 @@ debugging purposes. */
void
page_print_list(
/*============*/
- page_t* page, /* in: index page */
- ulint pr_n); /* in: print n first and n last entries */
+ page_t* page, /* in: index page */
+ dict_index_t* index, /* in: dictionary index of the page */
+ ulint pr_n); /* in: print n first and n last entries */
/*******************************************************************
Prints the info in a page header. */
@@ -653,9 +718,12 @@ debugging purposes. */
void
page_print(
/*======*/
- page_t* page, /* in: index page */
- ulint dn, /* in: print dn first and last entries in directory */
- ulint rn); /* in: print rn first and last records on page */
+ page_t* page, /* in: index page */
+ dict_index_t* index, /* in: dictionary index of the page */
+ ulint dn, /* in: print dn first and last entries
+ in directory */
+ ulint rn); /* in: print rn first and last records
+ in directory */
/*******************************************************************
The following is used to validate a record on a page. This function
differs from rec_validate as it can also check the n_owned field and
@@ -664,8 +732,9 @@ the heap_no field. */
ibool
page_rec_validate(
/*==============*/
- /* out: TRUE if ok */
- rec_t* rec); /* in: record on the page */
+ /* out: TRUE if ok */
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/*******************************************************************
Checks that the first directory slot points to the infimum record and
the last to the supremum. This function is intended to track if the
diff --git a/innobase/include/page0page.ic b/innobase/include/page0page.ic
index c7bf78040e9..bc0805ca30c 100644
--- a/innobase/include/page0page.ic
+++ b/innobase/include/page0page.ic
@@ -73,7 +73,8 @@ page_header_set_field(
{
ut_ad(page);
ut_ad(field <= PAGE_N_RECS);
- ut_ad(val < UNIV_PAGE_SIZE);
+ ut_ad(field == PAGE_N_HEAP || val < UNIV_PAGE_SIZE);
+ ut_ad(field != PAGE_N_HEAP || (val & 0x7fff) < UNIV_PAGE_SIZE);
mach_write_to_2(page + PAGE_HEADER + field, val);
}
@@ -152,6 +153,19 @@ page_header_reset_last_insert(
}
/****************************************************************
+Determine whether the page is in new-style compact format. */
+UNIV_INLINE
+ibool
+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 */
+{
+ return(!!(page_header_get_field(page, PAGE_N_HEAP) & 0x8000));
+}
+
+/****************************************************************
Gets the first record on the page. */
UNIV_INLINE
rec_t*
@@ -162,7 +176,11 @@ page_get_infimum_rec(
{
ut_ad(page);
- return(page + PAGE_INFIMUM);
+ if (page_is_comp(page)) {
+ return(page + PAGE_NEW_INFIMUM);
+ } else {
+ return(page + PAGE_OLD_INFIMUM);
+ }
}
/****************************************************************
@@ -176,7 +194,11 @@ page_get_supremum_rec(
{
ut_ad(page);
- return(page + PAGE_SUPREMUM);
+ if (page_is_comp(page)) {
+ return(page + PAGE_NEW_SUPREMUM);
+ } else {
+ return(page + PAGE_OLD_SUPREMUM);
+ }
}
/****************************************************************
@@ -309,6 +331,7 @@ page_cmp_dtuple_rec_with_match(
be page infimum or supremum, in which case
matched-parameter values below are not
affected */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint* matched_fields, /* in/out: number of already completely
matched fields; when function returns
contains the value for current comparison */
@@ -320,6 +343,7 @@ page_cmp_dtuple_rec_with_match(
page_t* page;
ut_ad(dtuple_check_typed(dtuple));
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
page = buf_frame_align(rec);
@@ -328,7 +352,7 @@ page_cmp_dtuple_rec_with_match(
} else if (rec == page_get_supremum_rec(page)) {
return(-1);
} else {
- return(cmp_dtuple_rec_with_match(dtuple, rec,
+ return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
matched_fields,
matched_bytes));
}
@@ -358,6 +382,45 @@ page_dir_get_n_slots(
{
return(page_header_get_field(page, PAGE_N_DIR_SLOTS));
}
+/*****************************************************************
+Sets the number of dir slots in directory. */
+UNIV_INLINE
+void
+page_dir_set_n_slots(
+/*=================*/
+ /* out: number of slots */
+ page_t* page, /* in: index page */
+ ulint n_slots)/* in: number of slots */
+{
+ page_header_set_field(page, PAGE_N_DIR_SLOTS, n_slots);
+}
+
+/*****************************************************************
+Gets the number of records in the heap. */
+UNIV_INLINE
+ulint
+page_dir_get_n_heap(
+/*================*/
+ /* out: number of user records */
+ page_t* page) /* in: index page */
+{
+ return(page_header_get_field(page, PAGE_N_HEAP) & 0x7fff);
+}
+
+/*****************************************************************
+Sets the number of records in the heap. */
+UNIV_INLINE
+void
+page_dir_set_n_heap(
+/*================*/
+ page_t* page, /* in: index page */
+ ulint n_heap) /* in: number of records */
+{
+ ut_ad(n_heap < 0x8000);
+
+ page_header_set_field(page, PAGE_N_HEAP, n_heap | (0x8000 &
+ page_header_get_field(page, PAGE_N_HEAP)));
+}
/*****************************************************************
Gets pointer to nth directory slot. */
@@ -369,7 +432,7 @@ page_dir_get_nth_slot(
page_t* page, /* in: index page */
ulint n) /* in: position */
{
- ut_ad(page_header_get_field(page, PAGE_N_DIR_SLOTS) > n);
+ ut_ad(page_dir_get_n_slots(page) > n);
return(page + UNIV_PAGE_SIZE - PAGE_DIR
- (n + 1) * PAGE_DIR_SLOT_SIZE);
@@ -431,7 +494,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)));
+ return(rec_get_n_owned(page_dir_slot_get_rec(slot),
+ page_is_comp(buf_frame_align(slot))));
}
/*******************************************************************
@@ -444,7 +508,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), n);
+ rec_set_n_owned(page_dir_slot_get_rec(slot),
+ page_is_comp(buf_frame_align(slot)), n);
}
/****************************************************************
@@ -477,7 +542,7 @@ page_rec_get_next(
page = buf_frame_align(rec);
- offs = rec_get_next_offs(rec);
+ offs = rec_get_next_offs(rec, page_is_comp(page));
if (offs >= UNIV_PAGE_SIZE) {
fprintf(stderr,
@@ -513,6 +578,7 @@ page_rec_set_next(
infimum */
{
page_t* page;
+ ulint offs;
ut_ad(page_rec_check(rec));
ut_a((next == NULL)
@@ -523,11 +589,13 @@ page_rec_set_next(
ut_ad(rec != page_get_supremum_rec(page));
ut_ad(next != page_get_infimum_rec(page));
- if (next == NULL) {
- rec_set_next_offs(rec, 0);
+ if (next) {
+ offs = (ulint) (next - page);
} else {
- rec_set_next_offs(rec, (ulint)(next - page));
+ offs = 0;
}
+
+ rec_set_next_offs(rec, page_is_comp(page), offs);
}
/****************************************************************
@@ -545,6 +613,7 @@ page_rec_get_prev(
rec_t* rec2;
rec_t* prev_rec = NULL;
page_t* page;
+ ibool comp;
ut_ad(page_rec_check(rec));
@@ -559,6 +628,7 @@ 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;
@@ -579,9 +649,12 @@ 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) == 0) {
+ while (rec_get_n_owned(rec, comp) == 0) {
rec = page_rec_get_next(rec);
}
@@ -601,7 +674,9 @@ page_get_data_size(
ulint ret;
ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP)
- - PAGE_SUPREMUM_END
+ - (page_is_comp(page)
+ ? PAGE_NEW_SUPREMUM_END
+ : PAGE_OLD_SUPREMUM_END)
- page_header_get_field(page, PAGE_GARBAGE));
ut_ad(ret < UNIV_PAGE_SIZE);
@@ -613,12 +688,13 @@ page_get_data_size(
Calculates free space if a page is emptied. */
UNIV_INLINE
ulint
-page_get_free_space_of_empty(void)
-/*==============================*/
+page_get_free_space_of_empty(
+/*=========================*/
/* out: free space */
+ ibool comp) /* in: TRUE=compact page layout */
{
return((ulint)(UNIV_PAGE_SIZE
- - PAGE_SUPREMUM_END
+ - (comp ? PAGE_NEW_SUPREMUM_END : PAGE_OLD_SUPREMUM_END)
- PAGE_DIR
- 2 * PAGE_DIR_SLOT_SIZE));
}
@@ -640,13 +716,16 @@ page_get_max_insert_size(
{
ulint occupied;
ulint free_space;
+ ibool comp;
+
+ comp = page_is_comp(page);
occupied = page_header_get_field(page, PAGE_HEAP_TOP)
- - PAGE_SUPREMUM_END
+ - (comp ? PAGE_NEW_SUPREMUM_END : PAGE_OLD_SUPREMUM_END)
+ page_dir_calc_reserved_space(
- n_recs + (page_header_get_field(page, PAGE_N_HEAP) - 2));
+ n_recs + page_dir_get_n_heap(page) - 2);
- free_space = page_get_free_space_of_empty();
+ free_space = page_get_free_space_of_empty(comp);
/* Above the 'n_recs +' part reserves directory space for the new
inserted records; the '- 2' excludes page infimum and supremum
@@ -673,11 +752,14 @@ 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();
+ free_space = page_get_free_space_of_empty(comp);
if (occupied > free_space) {
@@ -693,21 +775,33 @@ UNIV_INLINE
void
page_mem_free(
/*==========*/
- page_t* page, /* in: index page */
- rec_t* rec) /* in: pointer to the (origin of) record */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: pointer to the (origin of) record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
- rec_t* free;
- ulint garbage;
+ rec_t* free;
+ ulint garbage;
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
free = page_header_get_ptr(page, PAGE_FREE);
page_rec_set_next(rec, free);
page_header_set_ptr(page, PAGE_FREE, rec);
+#if 0 /* It's better not to destroy the user's data. */
+
+ /* Clear the data bytes of the deleted record in order to improve
+ the compression ratio of the page and to make it easier to read
+ page dumps in corruption reports. The extra bytes of the record
+ cannot be cleared, because page_mem_alloc() needs them in order
+ to determine the size of the deleted record. */
+ memset(rec, 0, rec_offs_data_size(offsets));
+#endif
+
garbage = page_header_get_field(page, PAGE_GARBAGE);
page_header_set_field(page, PAGE_GARBAGE,
- garbage + rec_get_size(rec));
+ garbage + rec_offs_size(offsets));
}
#ifdef UNIV_MATERIALIZE
diff --git a/innobase/include/que0que.h b/innobase/include/que0que.h
index e1874edcaf2..4113e52d425 100644
--- a/innobase/include/que0que.h
+++ b/innobase/include/que0que.h
@@ -359,6 +359,8 @@ struct que_thr_struct{
the control came */
ulint resource; /* resource usage of the query thread
thus far */
+ ulint lock_state; /* lock state of thread (table or
+ row) */
};
#define QUE_THR_MAGIC_N 8476583
@@ -482,6 +484,11 @@ struct que_fork_struct{
#define QUE_THR_SUSPENDED 7
#define QUE_THR_ERROR 8
+/* Query thread lock states */
+#define QUE_THR_LOCK_NOLOCK 0
+#define QUE_THR_LOCK_ROW 1
+#define QUE_THR_LOCK_TABLE 2
+
/* From where the cursor position is counted */
#define QUE_CUR_NOT_DEFINED 1
#define QUE_CUR_START 2
diff --git a/innobase/include/rem0cmp.h b/innobase/include/rem0cmp.h
index 712e263350e..1b1ee26b809 100644
--- a/innobase/include/rem0cmp.h
+++ b/innobase/include/rem0cmp.h
@@ -90,6 +90,7 @@ cmp_dtuple_rec_with_match(
dtuple in some of the common fields, or which
has an equal number or more fields than
dtuple */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint* matched_fields, /* in/out: number of already completely
matched fields; when function returns,
contains the value for current comparison */
@@ -107,7 +108,8 @@ cmp_dtuple_rec(
less than rec, respectively; see the comments
for cmp_dtuple_rec_with_match */
dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec); /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/******************************************************************
Checks if a dtuple is a prefix of a record. The last field in dtuple
is allowed to be a prefix of the corresponding field in the record. */
@@ -116,23 +118,9 @@ ibool
cmp_dtuple_is_prefix_of_rec(
/*========================*/
/* out: TRUE if prefix */
- dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec); /* in: physical record */
-/******************************************************************
-Compares a prefix of a data tuple to a prefix of a physical record for
-equality. If there are less fields in rec than parameter n_fields, FALSE
-is returned. NOTE that n_fields_cmp of dtuple does not affect this
-comparison. */
-
-ibool
-cmp_dtuple_rec_prefix_equal(
-/*========================*/
- /* out: TRUE if equal */
dtuple_t* dtuple, /* in: data tuple */
rec_t* rec, /* in: physical record */
- ulint n_fields); /* in: number of fields which should be
- compared; must not exceed the number of
- fields in dtuple */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/*****************************************************************
This function is used to compare two physical records. Only the common
first fields are compared, and if an externally stored field is
@@ -146,6 +134,8 @@ cmp_rec_rec_with_match(
first fields are compared */
rec_t* rec1, /* in: physical record */
rec_t* rec2, /* in: physical record */
+ const ulint* offsets1,/* in: rec_get_offsets(rec1, index) */
+ const ulint* offsets2,/* in: rec_get_offsets(rec2, index) */
dict_index_t* index, /* in: data dictionary index */
ulint* matched_fields, /* in/out: number of already completely
matched fields; when the function returns,
@@ -167,6 +157,8 @@ cmp_rec_rec(
first fields are compared */
rec_t* rec1, /* in: physical record */
rec_t* rec2, /* in: physical record */
+ const ulint* offsets1,/* in: rec_get_offsets(rec1, index) */
+ const ulint* offsets2,/* in: rec_get_offsets(rec2, index) */
dict_index_t* index); /* in: data dictionary index */
diff --git a/innobase/include/rem0cmp.ic b/innobase/include/rem0cmp.ic
index 75cb3ef04e8..b86534e0a6a 100644
--- a/innobase/include/rem0cmp.ic
+++ b/innobase/include/rem0cmp.ic
@@ -57,10 +57,13 @@ cmp_rec_rec(
first fields are compared */
rec_t* rec1, /* in: physical record */
rec_t* rec2, /* in: physical record */
+ const ulint* offsets1,/* in: rec_get_offsets(rec1, index) */
+ const ulint* offsets2,/* in: rec_get_offsets(rec2, index) */
dict_index_t* index) /* in: data dictionary index */
{
ulint match_f = 0;
ulint match_b = 0;
- return(cmp_rec_rec_with_match(rec1, rec2, index, &match_f, &match_b));
+ return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index,
+ &match_f, &match_b));
}
diff --git a/innobase/include/rem0rec.h b/innobase/include/rem0rec.h
index 86bf263170f..134c37c8030 100644
--- a/innobase/include/rem0rec.h
+++ b/innobase/include/rem0rec.h
@@ -23,9 +23,23 @@ Created 5/30/1994 Heikki Tuuri
info bits of a record */
#define REC_INFO_MIN_REC_FLAG 0x10UL
-/* Number of extra bytes in a record, in addition to the data and the
-offsets */
-#define REC_N_EXTRA_BYTES 6
+/* Number of extra bytes in an old-style record,
+in addition to the data and the offsets */
+#define REC_N_OLD_EXTRA_BYTES 6
+/* Number of extra bytes in a new-style record,
+in addition to the data and the offsets */
+#define REC_N_NEW_EXTRA_BYTES 5
+
+/* Record status values */
+#define REC_STATUS_ORDINARY 0
+#define REC_STATUS_NODE_PTR 1
+#define REC_STATUS_INFIMUM 2
+#define REC_STATUS_SUPREMUM 3
+
+/* Number of elements that should be initially allocated for the
+offsets[] array, first passed to rec_get_offsets() */
+#define REC_OFFS_NORMAL_SIZE 100
+#define REC_OFFS_SMALL_SIZE 10
/**********************************************************
The following function is used to get the offset of the
@@ -36,7 +50,8 @@ rec_get_next_offs(
/*==============*/
/* out: the page offset of the next
chained record */
- rec_t* rec); /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ ibool comp); /* in: TRUE=compact page format */
/**********************************************************
The following function is used to set the next record offset field
of the record. */
@@ -45,17 +60,28 @@ void
rec_set_next_offs(
/*==============*/
rec_t* rec, /* in: physical record */
+ ibool comp, /* in: TRUE=compact page format */
ulint next); /* in: offset of the next record */
/**********************************************************
The following function is used to get the number of fields
-in the record. */
+in an old-style record. */
UNIV_INLINE
ulint
-rec_get_n_fields(
-/*=============*/
+rec_get_n_fields_old(
+/*=================*/
/* out: number of data fields */
rec_t* rec); /* in: physical record */
/**********************************************************
+The following function is used to get the number of fields
+in a record. */
+UNIV_INLINE
+ulint
+rec_get_n_fields(
+/*=============*/
+ /* out: number of data fields */
+ rec_t* rec, /* in: physical record */
+ dict_index_t* index); /* in: record descriptor */
+/**********************************************************
The following function is used to get the number of records
owned by the previous directory record. */
UNIV_INLINE
@@ -63,7 +89,8 @@ ulint
rec_get_n_owned(
/*============*/
/* out: number of owned records */
- rec_t* rec); /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ ibool comp); /* in: TRUE=compact page format */
/**********************************************************
The following function is used to set the number of owned
records. */
@@ -72,6 +99,7 @@ void
rec_set_n_owned(
/*============*/
rec_t* rec, /* in: physical record */
+ ibool comp, /* in: TRUE=compact page format */
ulint n_owned); /* in: the number of owned */
/**********************************************************
The following function is used to retrieve the info bits of
@@ -81,7 +109,8 @@ ulint
rec_get_info_bits(
/*==============*/
/* out: info bits */
- rec_t* rec); /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ ibool comp); /* in: TRUE=compact page format */
/**********************************************************
The following function is used to set the info bits of a record. */
UNIV_INLINE
@@ -89,15 +118,47 @@ void
rec_set_info_bits(
/*==============*/
rec_t* rec, /* in: physical record */
+ ibool comp, /* in: TRUE=compact page format */
ulint bits); /* in: info bits */
/**********************************************************
-Gets the value of the deleted falg in info bits. */
+The following function retrieves the status bits of a new-style record. */
UNIV_INLINE
-ibool
-rec_info_bits_get_deleted_flag(
-/*===========================*/
- /* out: TRUE if deleted flag set */
- ulint info_bits); /* in: info bits from a record */
+ulint
+rec_get_status(
+/*===========*/
+ /* out: status bits */
+ rec_t* rec); /* in: physical record */
+
+/**********************************************************
+The following function is used to set the status bits of a new-style record. */
+UNIV_INLINE
+void
+rec_set_status(
+/*===========*/
+ rec_t* rec, /* in: physical record */
+ ulint bits); /* in: info bits */
+
+/**********************************************************
+The following function is used to retrieve the info and status
+bits of a record. (Only compact records have status bits.) */
+UNIV_INLINE
+ulint
+rec_get_info_and_status_bits(
+/*=========================*/
+ /* out: info bits */
+ rec_t* rec, /* in: physical record */
+ ibool comp); /* in: TRUE=compact page format */
+/**********************************************************
+The following function is used to set the info and status
+bits of a record. (Only compact records have status bits.) */
+UNIV_INLINE
+void
+rec_set_info_and_status_bits(
+/*=========================*/
+ rec_t* rec, /* in: physical record */
+ ibool comp, /* in: TRUE=compact page format */
+ ulint bits); /* in: info bits */
+
/**********************************************************
The following function tells if record is delete marked. */
UNIV_INLINE
@@ -105,7 +166,8 @@ ibool
rec_get_deleted_flag(
/*=================*/
/* out: TRUE if delete marked */
- rec_t* rec); /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ ibool comp); /* in: TRUE=compact page format */
/**********************************************************
The following function is used to set the deleted bit. */
UNIV_INLINE
@@ -113,8 +175,25 @@ 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 */
/**********************************************************
+The following function tells if a new-style record is a node pointer. */
+UNIV_INLINE
+ibool
+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
@@ -122,7 +201,8 @@ ulint
rec_get_heap_no(
/*=============*/
/* out: heap order number */
- rec_t* rec); /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ ibool comp); /* in: TRUE=compact page format */
/**********************************************************
The following function is used to set the heap number
field in the record. */
@@ -131,6 +211,7 @@ void
rec_set_heap_no(
/*=============*/
rec_t* rec, /* in: physical record */
+ ibool comp, /* in: TRUE=compact page format */
ulint heap_no);/* in: the heap number */
/**********************************************************
The following function is used to test whether the data offsets
@@ -141,31 +222,65 @@ rec_get_1byte_offs_flag(
/*====================*/
/* out: TRUE if 1-byte form */
rec_t* rec); /* in: physical record */
+/**********************************************************
+The following function determines the offsets to each field
+in the record. It can reuse a previously allocated array. */
+
+ulint*
+rec_get_offsets_func(
+/*=================*/
+ /* out: the new offsets */
+ rec_t* rec, /* in: physical record */
+ dict_index_t* index, /* in: record descriptor */
+ ulint* offsets,/* in: array consisting of offsets[0]
+ allocated elements, or an array from
+ rec_get_offsets(), or NULL */
+ ulint n_fields,/* in: maximum number of initialized fields
+ (ULINT_UNDEFINED if all fields) */
+ mem_heap_t** heap, /* in/out: memory heap */
+ const char* file, /* in: file name where called */
+ ulint line); /* in: line number where called */
+
+#define rec_get_offsets(rec,index,offsets,n,heap) \
+ rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__)
+
+/****************************************************************
+Validates offsets returned by rec_get_offsets(). */
+UNIV_INLINE
+ibool
+rec_offs_validate(
+/*==============*/
+ /* out: TRUE if valid */
+ rec_t* rec, /* in: record or NULL */
+ dict_index_t* index, /* in: record descriptor or NULL */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
+/****************************************************************
+Updates debug data in offsets, in order to avoid bogus
+rec_offs_validate() failures. */
+UNIV_INLINE
+void
+rec_offs_make_valid(
+/*================*/
+ rec_t* rec, /* in: record */
+ dict_index_t* index,/* in: record descriptor */
+ ulint* offsets);/* in: array returned by rec_get_offsets() */
+
/****************************************************************
The following function is used to get a pointer to the nth
-data field in the record. */
+data field in an old-style record. */
byte*
-rec_get_nth_field(
-/*==============*/
+rec_get_nth_field_old(
+/*==================*/
/* out: pointer to the field */
rec_t* rec, /* in: record */
ulint n, /* in: index of the field */
ulint* len); /* out: length of the field; UNIV_SQL_NULL
if SQL null */
/****************************************************************
-Return field length or UNIV_SQL_NULL. */
-UNIV_INLINE
-ulint
-rec_get_nth_field_len(
-/*==================*/
- /* out: length of the field; UNIV_SQL_NULL if SQL
- null */
- rec_t* rec, /* in: record */
- ulint n); /* in: index of the field */
-/****************************************************************
-Gets the physical size of a field. Also an SQL null may have a field of
-size > 0, if the data type is of a fixed size. */
+Gets the physical size of an old-style field.
+Also an SQL null may have a field of size > 0,
+if the data type is of a fixed size. */
UNIV_INLINE
ulint
rec_get_nth_field_size(
@@ -173,131 +288,185 @@ rec_get_nth_field_size(
/* out: field size in bytes */
rec_t* rec, /* in: record */
ulint n); /* in: index of the field */
-/***************************************************************
-Gets the value of the ith field extern storage bit. If it is TRUE
-it means that the field is stored on another page. */
+/****************************************************************
+The following function is used to get a pointer to the nth
+data field in an old-style record. */
+UNIV_INLINE
+byte*
+rec_get_nth_field(
+/*==============*/
+ /* out: pointer to the field */
+ rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint n, /* in: index of the field */
+ ulint* len); /* out: length of the field; UNIV_SQL_NULL
+ if SQL null */
+/**********************************************************
+Determine if the offsets are for a record in the new
+compact format. */
UNIV_INLINE
ibool
-rec_get_nth_field_extern_bit(
-/*=========================*/
- /* in: TRUE or FALSE */
- rec_t* rec, /* in: record */
- ulint i); /* in: ith field */
+rec_offs_comp(
+/*==========*/
+ /* out: TRUE if compact format */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
+/**********************************************************
+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 */
+/**********************************************************
+Returns TRUE if the extern bit is set in nth field of rec. */
+UNIV_INLINE
+ibool
+rec_offs_nth_extern(
+/*================*/
+ /* out: TRUE if externally stored */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint n); /* in: nth field */
+/**********************************************************
+Gets the physical size of a field. */
+UNIV_INLINE
+ulint
+rec_offs_nth_size(
+/*==============*/
+ /* out: length of field */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint n); /* in: nth field */
+
/**********************************************************
Returns TRUE if the extern bit is set in any of the fields
of rec. */
UNIV_INLINE
ibool
-rec_contains_externally_stored_field(
-/*=================================*/
- /* out: TRUE if a field is stored externally */
- rec_t* rec); /* in: record */
+rec_offs_any_extern(
+/*================*/
+ /* out: TRUE if a field is stored externally */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/***************************************************************
Sets the value of the ith field extern storage bit. */
-
+UNIV_INLINE
void
rec_set_nth_field_extern_bit(
/*=========================*/
- rec_t* rec, /* in: record */
- ulint i, /* in: ith field */
- ibool val, /* in: value to set */
- mtr_t* mtr); /* in: mtr holding an X-latch to the page where
- rec is, or NULL; in the NULL case we do not
- write to log about the change */
+ rec_t* rec, /* in: record */
+ dict_index_t* index, /* in: record descriptor */
+ ulint i, /* in: ith field */
+ ibool val, /* in: value to set */
+ mtr_t* mtr); /* in: mtr holding an X-latch to the page
+ where rec is, or NULL; in the NULL case
+ we do not write to log about the change */
/***************************************************************
Sets TRUE the extern storage bits of fields mentioned in an array. */
void
rec_set_field_extern_bits(
/*======================*/
- rec_t* rec, /* in: record */
- ulint* vec, /* in: array of field numbers */
- ulint n_fields, /* in: number of fields numbers */
- mtr_t* mtr); /* in: mtr holding an X-latch to the page
- where rec is, or NULL; in the NULL case we
- do not write to log about the change */
-/****************************************************************
-The following function is used to get a copy of the nth
-data field in the record to a buffer. */
-UNIV_INLINE
-void
-rec_copy_nth_field(
-/*===============*/
- void* buf, /* in: pointer to the buffer */
- rec_t* rec, /* in: record */
- ulint n, /* in: index of the field */
- ulint* len); /* out: length of the field; UNIV_SQL_NULL if SQL
- null */
+ rec_t* rec, /* in: record */
+ dict_index_t* index, /* in: record descriptor */
+ const ulint* vec, /* in: array of field numbers */
+ ulint n_fields,/* in: number of fields numbers */
+ mtr_t* mtr); /* in: mtr holding an X-latch to the page
+ where rec is, or NULL; in the NULL case
+ we do not write to log about the change */
/***************************************************************
-This is used to modify the value of an already existing field in
-a physical record. The previous value must have exactly the same
-size as the new value. If len is UNIV_SQL_NULL then the field is
-treated as SQL null. */
+This is used to modify the value of an already existing field in a record.
+The previous value must have exactly the same size as the new value. If len
+is UNIV_SQL_NULL then the field is treated as an SQL null for old-style
+records. For new-style records, len must not be UNIV_SQL_NULL. */
UNIV_INLINE
void
rec_set_nth_field(
/*==============*/
- rec_t* rec, /* in: record */
- ulint n, /* in: index of the field */
- void* data, /* in: pointer to the data if not SQL null */
- ulint len); /* in: length of the data or UNIV_SQL_NULL.
- If not SQL null, must have the same length as the
- previous value. If SQL null, previous value must be
- SQL null. */
+ rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint n, /* in: index number of the field */
+ const void* data, /* in: pointer to the data if not SQL null */
+ ulint len); /* in: length of the data or UNIV_SQL_NULL.
+ If not SQL null, must have the same
+ length as the previous value.
+ If SQL null, previous value must be
+ SQL null. */
/**************************************************************
-The following function returns the data size of a physical
+The following function returns the data size of an old-style physical
record, that is the sum of field lengths. SQL null fields
are counted as length 0 fields. The value returned by the function
is the distance from record origin to record end in bytes. */
UNIV_INLINE
ulint
-rec_get_data_size(
-/*==============*/
- /* out: size */
+rec_get_data_size_old(
+/*==================*/
+ /* out: size */
rec_t* rec); /* in: physical record */
/**************************************************************
+The following function returns the number of fields in a record. */
+UNIV_INLINE
+ulint
+rec_offs_n_fields(
+/*===============*/
+ /* out: number of fields */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
+/**************************************************************
+The following function returns the data size of a physical
+record, that is the sum of field lengths. SQL null fields
+are counted as length 0 fields. The value returned by the function
+is the distance from record origin to record end in bytes. */
+UNIV_INLINE
+ulint
+rec_offs_data_size(
+/*===============*/
+ /* out: size */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
+/**************************************************************
Returns the total size of record minus data size of record.
The value returned by the function is the distance from record
start to record origin in bytes. */
UNIV_INLINE
ulint
-rec_get_extra_size(
-/*===============*/
- /* out: size */
- rec_t* rec); /* in: physical record */
-/**************************************************************
+rec_offs_extra_size(
+/*================*/
+ /* out: size */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
+/**************************************************************
Returns the total size of a physical record. */
UNIV_INLINE
ulint
-rec_get_size(
-/*=========*/
- /* out: size */
- rec_t* rec); /* in: physical record */
+rec_offs_size(
+/*==========*/
+ /* out: size */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/**************************************************************
Returns a pointer to the start of the record. */
UNIV_INLINE
byte*
rec_get_start(
/*==========*/
- /* out: pointer to start */
- rec_t* rec); /* in: pointer to record */
+ /* out: pointer to start */
+ rec_t* rec, /* in: pointer to record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/**************************************************************
Returns a pointer to the end of the record. */
UNIV_INLINE
byte*
rec_get_end(
/*========*/
- /* out: pointer to end */
- rec_t* rec); /* in: pointer to record */
+ /* out: pointer to end */
+ rec_t* rec, /* in: pointer to record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/*******************************************************************
Copies a physical record to a buffer. */
UNIV_INLINE
rec_t*
rec_copy(
/*=====*/
- /* out: pointer to the origin of the copied record */
- void* buf, /* in: buffer */
- rec_t* rec); /* in: physical record */
+ /* out: pointer to the origin of the copy */
+ void* buf, /* in: buffer */
+ const rec_t* rec, /* in: physical record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/******************************************************************
Copies the first n fields of a physical record to a new physical record in
a buffer. */
@@ -305,49 +474,43 @@ a buffer. */
rec_t*
rec_copy_prefix_to_buf(
/*===================*/
- /* out, own: copied record */
- rec_t* rec, /* in: physical record */
- ulint n_fields, /* in: number of fields to copy */
- byte** buf, /* in/out: memory buffer for the copied prefix,
- or NULL */
- ulint* buf_size); /* in/out: buffer size */
+ /* out, own: copied record */
+ rec_t* rec, /* in: physical record */
+ dict_index_t* index, /* in: record descriptor */
+ ulint n_fields, /* in: number of fields to copy */
+ byte** buf, /* in/out: memory buffer
+ for the copied prefix, or NULL */
+ ulint* buf_size); /* in/out: buffer size */
/****************************************************************
Folds a prefix of a physical record to a ulint. */
UNIV_INLINE
ulint
rec_fold(
/*=====*/
- /* out: the folded value */
- rec_t* rec, /* in: the physical record */
- ulint n_fields, /* in: number of complete fields to fold */
- ulint n_bytes, /* in: number of bytes to fold in an
- incomplete last field */
- dulint tree_id); /* in: index tree id */
+ /* out: the folded value */
+ rec_t* rec, /* in: the physical record */
+ const ulint* offsets, /* in: array returned by
+ rec_get_offsets() */
+ ulint n_fields, /* in: number of complete
+ fields to fold */
+ ulint n_bytes, /* in: number of bytes to fold
+ in an incomplete last field */
+ dulint tree_id); /* in: index tree id */
/*************************************************************
Builds a physical record out of a data tuple and stores it beginning from
address destination. */
-UNIV_INLINE
+
rec_t*
rec_convert_dtuple_to_rec(
/*======================*/
- /* out: pointer to the origin of physical
- record */
- byte* destination, /* in: start address of the physical record */
- dtuple_t* dtuple); /* in: data tuple */
-/*************************************************************
-Builds a physical record out of a data tuple and stores it beginning from
-address destination. */
-
-rec_t*
-rec_convert_dtuple_to_rec_low(
-/*==========================*/
- /* out: pointer to the origin of physical
- record */
- byte* destination, /* in: start address of the physical record */
- dtuple_t* dtuple, /* in: data tuple */
- ulint data_size); /* in: data size of dtuple */
+ /* out: pointer to the origin
+ of physical record */
+ byte* buf, /* in: start address of the
+ physical record */
+ dict_index_t* index, /* in: record descriptor */
+ dtuple_t* dtuple);/* in: data tuple */
/**************************************************************
-Returns the extra size of a physical record if we know its
+Returns the extra size of an old-style physical record if we know its
data size and number of fields. */
UNIV_INLINE
ulint
@@ -355,7 +518,8 @@ rec_get_converted_extra_size(
/*=========================*/
/* out: extra size */
ulint data_size, /* in: data size */
- ulint n_fields); /* in: number of fields */
+ ulint n_fields) /* in: number of fields */
+ __attribute__((const));
/**************************************************************
The following function returns the size of a data tuple when converted to
a physical record. */
@@ -364,6 +528,7 @@ ulint
rec_get_converted_size(
/*===================*/
/* out: size */
+ dict_index_t* index, /* in: record descriptor */
dtuple_t* dtuple);/* in: data tuple */
/******************************************************************
Copies the first n fields of a physical record to a data tuple.
@@ -374,6 +539,7 @@ rec_copy_prefix_to_dtuple(
/*======================*/
dtuple_t* tuple, /* in: data tuple */
rec_t* rec, /* in: physical record */
+ dict_index_t* index, /* in: record descriptor */
ulint n_fields, /* in: number of fields to copy */
mem_heap_t* heap); /* in: memory heap */
/*******************************************************************
@@ -382,16 +548,35 @@ Validates the consistency of a physical record. */
ibool
rec_validate(
/*=========*/
- /* out: TRUE if ok */
- rec_t* rec); /* in: physical record */
+ /* out: TRUE if ok */
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
+/*******************************************************************
+Prints an old-style physical record. */
+
+void
+rec_print_old(
+/*==========*/
+ FILE* file, /* in: file where to print */
+ rec_t* rec); /* in: physical record */
+/*******************************************************************
+Prints a physical record. */
+
+void
+rec_print_new(
+/*==========*/
+ FILE* file, /* in: file where to print */
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/*******************************************************************
Prints a physical record. */
void
rec_print(
/*======*/
- FILE* file, /* in: file where to print */
- rec_t* rec); /* in: physical record */
+ FILE* file, /* in: file where to print */
+ rec_t* rec, /* in: physical record */
+ dict_index_t* index); /* in: record descriptor */
#define REC_INFO_BITS 6 /* This is single byte bit-field */
diff --git a/innobase/include/rem0rec.ic b/innobase/include/rem0rec.ic
index c36bf8f6d6e..2593fb8edeb 100644
--- a/innobase/include/rem0rec.ic
+++ b/innobase/include/rem0rec.ic
@@ -8,9 +8,19 @@ Created 5/30/1994 Heikki Tuuri
#include "mach0data.h"
#include "ut0byte.h"
+#include "dict0dict.h"
-/* Offsets of the bit-fields in the record. NOTE! In the table the most
-significant bytes and bits are written below less significant.
+/* Compact flag ORed to the extra size returned by rec_get_offsets() */
+#define REC_OFFS_COMPACT ((ulint) 1 << 31)
+/* SQL NULL flag in offsets returned by rec_get_offsets() */
+#define REC_OFFS_SQL_NULL ((ulint) 1 << 31)
+/* External flag in offsets returned by rec_get_offsets() */
+#define REC_OFFS_EXTERNAL ((ulint) 1 << 30)
+/* Mask for offsets returned by rec_get_offsets() */
+#define REC_OFFS_MASK (REC_OFFS_EXTERNAL - 1)
+
+/* Offsets of the bit-fields in an old-style record. NOTE! In the table the
+most significant bytes and bits are written below less significant.
(1) byte offset (2) bit usage within byte
downward from
@@ -25,6 +35,35 @@ significant bytes and bits are written below less significant.
4 bits info bits
*/
+/* Offsets of the bit-fields in a new-style record. NOTE! In the table the
+most significant bytes and bits are written below less significant.
+
+ (1) byte offset (2) bit usage within byte
+ downward from
+ origin -> 1 8 bits relative offset of next record
+ 2 8 bits relative offset of next record
+ the relative offset is an unsigned 16-bit
+ integer:
+ (offset_of_next_record
+ - offset_of_this_record) mod 64Ki,
+ where mod is the modulo as a non-negative
+ number;
+ we can calculate the the offset of the next
+ record with the formula:
+ relative_offset + offset_of_this_record
+ mod UNIV_PAGE_SIZE
+ 3 3 bits status:
+ 000=conventional record
+ 001=node pointer record (inside B-tree)
+ 010=infimum record
+ 011=supremum record
+ 1xx=reserved
+ 5 bits heap number
+ 4 8 bits heap number
+ 5 4 bits n_owned
+ 4 bits info bits
+*/
+
/* We list the byte offsets from the origin of the record, the mask,
and the shift needed to obtain each bit-field of the record. */
@@ -32,22 +71,30 @@ and the shift needed to obtain each bit-field of the record. */
#define REC_NEXT_MASK 0xFFFFUL
#define REC_NEXT_SHIFT 0
-#define REC_SHORT 3 /* This is single byte bit-field */
-#define REC_SHORT_MASK 0x1UL
-#define REC_SHORT_SHIFT 0
+#define REC_OLD_SHORT 3 /* This is single byte bit-field */
+#define REC_OLD_SHORT_MASK 0x1UL
+#define REC_OLD_SHORT_SHIFT 0
+
+#define REC_OLD_N_FIELDS 4
+#define REC_OLD_N_FIELDS_MASK 0x7FEUL
+#define REC_OLD_N_FIELDS_SHIFT 1
-#define REC_N_FIELDS 4
-#define REC_N_FIELDS_MASK 0x7FEUL
-#define REC_N_FIELDS_SHIFT 1
+#define REC_NEW_STATUS 3 /* This is single byte bit-field */
+#define REC_NEW_STATUS_MASK 0x7UL
+#define REC_NEW_STATUS_SHIFT 0
-#define REC_HEAP_NO 5
+#define REC_OLD_HEAP_NO 5
+#define REC_NEW_HEAP_NO 4
#define REC_HEAP_NO_MASK 0xFFF8UL
#define REC_HEAP_NO_SHIFT 3
-#define REC_N_OWNED 6 /* This is single byte bit-field */
+#define REC_OLD_N_OWNED 6 /* This is single byte bit-field */
+#define REC_NEW_N_OWNED 5 /* This is single byte bit-field */
#define REC_N_OWNED_MASK 0xFUL
#define REC_N_OWNED_SHIFT 0
+#define REC_OLD_INFO_BITS 6 /* This is single byte bit-field */
+#define REC_NEW_INFO_BITS 5 /* This is single byte bit-field */
#define REC_INFO_BITS_MASK 0xF0UL
#define REC_INFO_BITS_SHIFT 0
@@ -65,26 +112,24 @@ a field stored to another page: */
#define REC_2BYTE_EXTERN_MASK 0x4000UL
-/****************************************************************
-Return field length or UNIV_SQL_NULL. */
-UNIV_INLINE
-ulint
-rec_get_nth_field_len(
-/*==================*/
- /* out: length of the field; UNIV_SQL_NULL if SQL
- null */
- rec_t* rec, /* in: record */
- ulint n) /* in: index of the field */
-{
- ulint len;
-
- rec_get_nth_field(rec, n, &len);
-
- return(len);
-}
+#if REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) \
+ ^ REC_OLD_N_FIELDS_MASK << (8 * (REC_OLD_N_FIELDS - 4)) \
+ ^ REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) \
+ ^ REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) \
+ ^ REC_INFO_BITS_MASK << (8 * (REC_OLD_INFO_BITS - 3)) \
+ ^ 0xFFFFFFFFUL
+# error "sum of old-style masks != 0xFFFFFFFFUL"
+#endif
+#if REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) \
+ ^ REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) \
+ ^ REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) \
+ ^ REC_INFO_BITS_MASK << (8 * (REC_NEW_INFO_BITS - 3)) \
+ ^ 0xFFFFFFUL
+# error "sum of new-style masks != 0xFFFFFFUL"
+#endif
/***************************************************************
-Sets the value of the ith field SQL null bit. */
+Sets the value of the ith field SQL null bit of an old-style record. */
void
rec_set_nth_field_null_bit(
@@ -93,8 +138,8 @@ rec_set_nth_field_null_bit(
ulint i, /* in: ith field */
ibool val); /* in: value to set */
/***************************************************************
-Sets a record field to SQL null. The physical size of the field is not
-changed. */
+Sets an old-style record field to SQL null.
+The physical size of the field is not changed. */
void
rec_set_nth_field_sql_null(
@@ -102,6 +147,32 @@ rec_set_nth_field_sql_null(
rec_t* rec, /* in: record */
ulint n); /* in: index of the field */
+/***************************************************************
+Sets the value of the ith field extern storage bit of an old-style record. */
+
+void
+rec_set_nth_field_extern_bit_old(
+/*=============================*/
+ rec_t* rec, /* in: old-style record */
+ ulint i, /* in: ith field */
+ ibool val, /* in: value to set */
+ mtr_t* mtr); /* in: mtr holding an X-latch to the page where
+ rec is, or NULL; in the NULL case we do not
+ write to log about the change */
+/***************************************************************
+Sets the value of the ith field extern storage bit of a new-style record. */
+
+void
+rec_set_nth_field_extern_bit_new(
+/*=============================*/
+ rec_t* rec, /* in: record */
+ dict_index_t* index, /* in: record descriptor */
+ ulint ith, /* in: ith field */
+ ibool val, /* in: value to set */
+ mtr_t* mtr); /* in: mtr holding an X-latch to the page
+ where rec is, or NULL; in the NULL case
+ we do not write to log about the change */
+
/**********************************************************
Gets a bit field from within 1 byte. */
UNIV_INLINE
@@ -131,7 +202,7 @@ rec_set_bit_field_1(
ulint shift) /* in: shift right applied after masking */
{
ut_ad(rec);
- ut_ad(offs <= REC_N_EXTRA_BYTES);
+ ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
ut_ad(mask);
ut_ad(mask <= 0xFFUL);
ut_ad(((mask >> shift) << shift) == mask);
@@ -171,30 +242,14 @@ rec_set_bit_field_2(
ulint shift) /* in: shift right applied after masking */
{
ut_ad(rec);
- ut_ad(offs <= REC_N_EXTRA_BYTES);
+ ut_ad(offs <= REC_N_OLD_EXTRA_BYTES);
ut_ad(mask > 0xFFUL);
ut_ad(mask <= 0xFFFFUL);
ut_ad((mask >> shift) & 1);
ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1)));
ut_ad(((mask >> shift) << shift) == mask);
ut_ad(((val << shift) & mask) == (val << shift));
-#ifdef UNIV_DEBUG
- {
- ulint m;
-
- /* The following assertion checks that the masks of currently
- defined bit-fields in bytes 3-6 do not overlap. */
- m = (ulint)((REC_SHORT_MASK << (8 * (REC_SHORT - 3)))
- + (REC_N_FIELDS_MASK << (8 * (REC_N_FIELDS - 4)))
- + (REC_HEAP_NO_MASK << (8 * (REC_HEAP_NO - 4)))
- + (REC_N_OWNED_MASK << (8 * (REC_N_OWNED - 3)))
- + (REC_INFO_BITS_MASK << (8 * (REC_INFO_BITS - 3))));
- if (m != ut_dbg_zero + 0xFFFFFFFFUL) {
- fprintf(stderr, "Sum of masks %lx\n", m);
- ut_error;
- }
- }
-#endif
+
mach_write_to_2(rec - offs,
(mach_read_from_2(rec - offs) & ~mask)
| (val << shift));
@@ -207,18 +262,46 @@ UNIV_INLINE
ulint
rec_get_next_offs(
/*==============*/
- /* out: the page offset of the next chained record */
- rec_t* rec) /* in: physical record */
+ /* 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 ret;
-
- ut_ad(rec);
-
- ret = rec_get_bit_field_2(rec, REC_NEXT, REC_NEXT_MASK,
- REC_NEXT_SHIFT);
- ut_ad(ret < UNIV_PAGE_SIZE);
+ ulint field_value;
+
+ ut_ad(REC_NEXT_MASK == 0xFFFFUL);
+ ut_ad(REC_NEXT_SHIFT == 0);
+
+ field_value = mach_read_from_2(rec - REC_NEXT);
+
+ if (comp) {
+#if UNIV_PAGE_SIZE <= 32768
+ /* Note that for 64 KiB pages, field_value can 'wrap around'
+ and the debug assertion is not valid */
+
+ /* In the following assertion, field_value is interpreted
+ as signed 16-bit integer in 2's complement arithmetics.
+ If all platforms defined int16_t in the standard headers,
+ the expression could be written simpler as
+ (int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE
+ */
+ ut_ad((field_value >= 32768
+ ? field_value - 65536
+ : field_value)
+ + ut_align_offset(rec, UNIV_PAGE_SIZE)
+ < UNIV_PAGE_SIZE);
+#endif
+ if (field_value == 0) {
+
+ return(0);
+ }
+
+ return(ut_align_offset(rec + field_value, UNIV_PAGE_SIZE));
+ } else {
+ ut_ad(field_value < UNIV_PAGE_SIZE);
- return(ret);
+ return(field_value);
+ }
}
/**********************************************************
@@ -229,21 +312,42 @@ void
rec_set_next_offs(
/*==============*/
rec_t* rec, /* in: physical record */
- ulint next) /* in: offset of the next record */
+ ibool comp, /* in: TRUE=compact page format */
+ ulint next) /* in: offset of the next record, or 0 if none */
{
ut_ad(rec);
ut_ad(UNIV_PAGE_SIZE > next);
+ ut_ad(REC_NEXT_MASK == 0xFFFFUL);
+ ut_ad(REC_NEXT_SHIFT == 0);
+
+ if (comp) {
+ ulint field_value;
+
+ if (next) {
+ /* The following two statements calculate
+ next - offset_of_rec mod 64Ki, where mod is the modulo
+ as a non-negative number */
+
+ field_value = (ulint)((lint)next
+ - (lint)ut_align_offset(rec, UNIV_PAGE_SIZE));
+ field_value &= REC_NEXT_MASK;
+ } else {
+ field_value = 0;
+ }
- rec_set_bit_field_2(rec, next, REC_NEXT, REC_NEXT_MASK,
- REC_NEXT_SHIFT);
+ mach_write_to_2(rec - REC_NEXT, field_value);
+ } else {
+ mach_write_to_2(rec - REC_NEXT, next);
+ }
}
/**********************************************************
-The following function is used to get the number of fields in the record. */
+The following function is used to get the number of fields
+in an old-style record. */
UNIV_INLINE
ulint
-rec_get_n_fields(
-/*=============*/
+rec_get_n_fields_old(
+/*=================*/
/* out: number of data fields */
rec_t* rec) /* in: physical record */
{
@@ -251,8 +355,8 @@ rec_get_n_fields(
ut_ad(rec);
- ret = rec_get_bit_field_2(rec, REC_N_FIELDS, REC_N_FIELDS_MASK,
- REC_N_FIELDS_SHIFT);
+ ret = rec_get_bit_field_2(rec, REC_OLD_N_FIELDS,
+ REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);
ut_ad(ret <= REC_MAX_N_FIELDS);
ut_ad(ret > 0);
@@ -260,12 +364,12 @@ rec_get_n_fields(
}
/**********************************************************
-The following function is used to set the number of fields field in the
-record. */
+The following function is used to set the number of fields
+in an old-style record. */
UNIV_INLINE
void
-rec_set_n_fields(
-/*=============*/
+rec_set_n_fields_old(
+/*=================*/
rec_t* rec, /* in: physical record */
ulint n_fields) /* in: the number of fields */
{
@@ -273,8 +377,58 @@ rec_set_n_fields(
ut_ad(n_fields <= REC_MAX_N_FIELDS);
ut_ad(n_fields > 0);
- rec_set_bit_field_2(rec, n_fields, REC_N_FIELDS, REC_N_FIELDS_MASK,
- REC_N_FIELDS_SHIFT);
+ rec_set_bit_field_2(rec, n_fields, REC_OLD_N_FIELDS,
+ REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);
+}
+
+/**********************************************************
+The following function retrieves the status bits of a new-style record. */
+UNIV_INLINE
+ulint
+rec_get_status(
+/*===========*/
+ /* out: status bits */
+ rec_t* rec) /* in: physical record */
+{
+ ulint ret;
+
+ ut_ad(rec);
+
+ ret = rec_get_bit_field_1(rec, REC_NEW_STATUS,
+ REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
+ ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0);
+
+ return(ret);
+}
+
+/**********************************************************
+The following function is used to get the number of fields
+in a record. */
+UNIV_INLINE
+ulint
+rec_get_n_fields(
+/*=============*/
+ /* out: number of data fields */
+ rec_t* rec, /* in: physical record */
+ dict_index_t* index) /* in: record descriptor */
+{
+ ut_ad(rec);
+ ut_ad(index);
+ if (!index->table->comp) {
+ return(rec_get_n_fields_old(rec));
+ }
+ switch (rec_get_status(rec)) {
+ case REC_STATUS_ORDINARY:
+ return(dict_index_get_n_fields(index));
+ case REC_STATUS_NODE_PTR:
+ return(dict_index_get_n_unique_in_tree(index) + 1);
+ case REC_STATUS_INFIMUM:
+ case REC_STATUS_SUPREMUM:
+ return(1);
+ default:
+ ut_error;
+ return(ULINT_UNDEFINED);
+ }
}
/**********************************************************
@@ -285,14 +439,16 @@ ulint
rec_get_n_owned(
/*============*/
/* out: number of owned records */
- rec_t* rec) /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ ibool comp) /* in: TRUE=compact page format */
{
ulint ret;
ut_ad(rec);
- ret = rec_get_bit_field_1(rec, REC_N_OWNED, REC_N_OWNED_MASK,
- REC_N_OWNED_SHIFT);
+ ret = rec_get_bit_field_1(rec,
+ comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
+ REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
ut_ad(ret <= REC_MAX_N_OWNED);
return(ret);
@@ -305,13 +461,15 @@ void
rec_set_n_owned(
/*============*/
rec_t* rec, /* in: physical record */
+ ibool comp, /* in: TRUE=compact page format */
ulint n_owned) /* in: the number of owned */
{
ut_ad(rec);
ut_ad(n_owned <= REC_MAX_N_OWNED);
- rec_set_bit_field_1(rec, n_owned, REC_N_OWNED, REC_N_OWNED_MASK,
- REC_N_OWNED_SHIFT);
+ rec_set_bit_field_1(rec, n_owned,
+ comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED,
+ REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
}
/**********************************************************
@@ -321,14 +479,16 @@ ulint
rec_get_info_bits(
/*==============*/
/* out: info bits */
- rec_t* rec) /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ ibool comp) /* in: TRUE=compact page format */
{
ulint ret;
ut_ad(rec);
- ret = rec_get_bit_field_1(rec, REC_INFO_BITS, REC_INFO_BITS_MASK,
- REC_INFO_BITS_SHIFT);
+ ret = rec_get_bit_field_1(rec,
+ comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
+ REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
ut_ad((ret & ~REC_INFO_BITS_MASK) == 0);
return(ret);
@@ -341,30 +501,78 @@ void
rec_set_info_bits(
/*==============*/
rec_t* rec, /* in: physical record */
+ ibool comp, /* in: TRUE=compact page format */
ulint bits) /* in: info bits */
{
ut_ad(rec);
ut_ad((bits & ~REC_INFO_BITS_MASK) == 0);
- rec_set_bit_field_1(rec, bits, REC_INFO_BITS, REC_INFO_BITS_MASK,
- REC_INFO_BITS_SHIFT);
+ rec_set_bit_field_1(rec, bits,
+ comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS,
+ REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
}
/**********************************************************
-Gets the value of the deleted flag in info bits. */
+The following function is used to set the status bits of a new-style record. */
UNIV_INLINE
-ibool
-rec_info_bits_get_deleted_flag(
-/*===========================*/
- /* out: TRUE if deleted flag set */
- ulint info_bits) /* in: info bits from a record */
+void
+rec_set_status(
+/*===========*/
+ rec_t* rec, /* in: physical record */
+ ulint bits) /* in: info bits */
{
- if (info_bits & REC_INFO_DELETED_FLAG) {
+ ut_ad(rec);
+ ut_ad((bits & ~REC_NEW_STATUS_MASK) == 0);
- return(TRUE);
- }
+ rec_set_bit_field_1(rec, bits, REC_NEW_STATUS,
+ REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
+}
- return(FALSE);
+/**********************************************************
+The following function is used to retrieve the info and status
+bits of a record. (Only compact records have status bits.) */
+UNIV_INLINE
+ulint
+rec_get_info_and_status_bits(
+/*=========================*/
+ /* out: info bits */
+ rec_t* rec, /* in: physical record */
+ ibool comp) /* in: TRUE=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) {
+ bits = rec_get_info_bits(rec, TRUE) | rec_get_status(rec);
+ } else {
+ bits = rec_get_info_bits(rec, FALSE);
+ ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
+ }
+ return(bits);
+}
+/**********************************************************
+The following function is used to set the info and status
+bits of a record. (Only compact records have status bits.) */
+UNIV_INLINE
+void
+rec_set_info_and_status_bits(
+/*=========================*/
+ rec_t* rec, /* in: physical record */
+ ibool comp, /* in: TRUE=compact page format */
+ ulint bits) /* in: info 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) {
+ rec_set_status(rec, bits & REC_NEW_STATUS_MASK);
+ } else {
+ ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)));
+ }
+ rec_set_info_bits(rec, comp, bits & ~REC_NEW_STATUS_MASK);
}
/**********************************************************
@@ -374,9 +582,10 @@ ibool
rec_get_deleted_flag(
/*=================*/
/* out: TRUE if delete marked */
- rec_t* rec) /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ ibool comp) /* in: TRUE=compact page format */
{
- if (REC_INFO_DELETED_FLAG & rec_get_info_bits(rec)) {
+ if (REC_INFO_DELETED_FLAG & rec_get_info_bits(rec, comp)) {
return(TRUE);
}
@@ -391,6 +600,7 @@ 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 old_val;
@@ -399,7 +609,7 @@ rec_set_deleted_flag(
ut_ad(TRUE == 1);
ut_ad(flag <= TRUE);
- old_val = rec_get_info_bits(rec);
+ old_val = rec_get_info_bits(rec, comp);
if (flag) {
new_val = REC_INFO_DELETED_FLAG | old_val;
@@ -407,7 +617,39 @@ rec_set_deleted_flag(
new_val = ~REC_INFO_DELETED_FLAG & old_val;
}
- rec_set_info_bits(rec, new_val);
+ rec_set_info_bits(rec, comp, new_val);
+}
+
+/**********************************************************
+The following function tells if a new-style record is a node pointer. */
+UNIV_INLINE
+ibool
+rec_get_node_ptr_flag(
+/*=================*/
+ /* out: TRUE if node pointer */
+ rec_t* rec) /* in: physical record */
+{
+ return(REC_STATUS_NODE_PTR == rec_get_status(rec));
+}
+
+/**********************************************************
+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);
}
/**********************************************************
@@ -418,14 +660,16 @@ ulint
rec_get_heap_no(
/*=============*/
/* out: heap order number */
- rec_t* rec) /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ ibool comp) /* in: TRUE=compact page format */
{
ulint ret;
ut_ad(rec);
- ret = rec_get_bit_field_2(rec, REC_HEAP_NO, REC_HEAP_NO_MASK,
- REC_HEAP_NO_SHIFT);
+ ret = rec_get_bit_field_2(rec,
+ comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
+ REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
ut_ad(ret <= REC_MAX_HEAP_NO);
return(ret);
@@ -438,12 +682,14 @@ void
rec_set_heap_no(
/*=============*/
rec_t* rec, /* in: physical record */
+ ibool comp, /* in: TRUE=compact page format */
ulint heap_no)/* in: the heap number */
{
ut_ad(heap_no <= REC_MAX_HEAP_NO);
- rec_set_bit_field_2(rec, heap_no, REC_HEAP_NO, REC_HEAP_NO_MASK,
- REC_HEAP_NO_SHIFT);
+ rec_set_bit_field_2(rec, heap_no,
+ comp ? REC_NEW_HEAP_NO : REC_OLD_HEAP_NO,
+ REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT);
}
/**********************************************************
@@ -456,10 +702,12 @@ rec_get_1byte_offs_flag(
/* out: TRUE if 1-byte form */
rec_t* rec) /* in: physical record */
{
- ut_ad(TRUE == 1);
+#if TRUE != 1
+#error "TRUE != 1"
+#endif
- return(rec_get_bit_field_1(rec, REC_SHORT, REC_SHORT_MASK,
- REC_SHORT_SHIFT));
+ return(rec_get_bit_field_1(rec, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
+ REC_OLD_SHORT_SHIFT));
}
/**********************************************************
@@ -471,11 +719,13 @@ rec_set_1byte_offs_flag(
rec_t* rec, /* in: physical record */
ibool flag) /* in: TRUE if 1byte form */
{
- ut_ad(TRUE == 1);
+#if TRUE != 1
+#error "TRUE != 1"
+#endif
ut_ad(flag <= TRUE);
- rec_set_bit_field_1(rec, flag, REC_SHORT, REC_SHORT_MASK,
- REC_SHORT_SHIFT);
+ rec_set_bit_field_1(rec, flag, REC_OLD_SHORT, REC_OLD_SHORT_MASK,
+ REC_OLD_SHORT_SHIFT);
}
/**********************************************************
@@ -492,9 +742,9 @@ rec_1_get_field_end_info(
ulint n) /* in: field index */
{
ut_ad(rec_get_1byte_offs_flag(rec));
- ut_ad(n < rec_get_n_fields(rec));
+ ut_ad(n < rec_get_n_fields_old(rec));
- return(mach_read_from_1(rec - (REC_N_EXTRA_BYTES + n + 1)));
+ return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1)));
}
/**********************************************************
@@ -511,68 +761,289 @@ rec_2_get_field_end_info(
ulint n) /* in: field index */
{
ut_ad(!rec_get_1byte_offs_flag(rec));
- ut_ad(n < rec_get_n_fields(rec));
+ ut_ad(n < rec_get_n_fields_old(rec));
- return(mach_read_from_2(rec - (REC_N_EXTRA_BYTES + 2 * n + 2)));
+ return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2)));
}
-/***************************************************************
-Gets the value of the ith field extern storage bit. If it is TRUE
-it means that the field is stored on another page. */
+#ifdef UNIV_DEBUG
+/* Length of the rec_get_offsets() header */
+# define REC_OFFS_HEADER_SIZE 4
+#else /* UNIV_DEBUG */
+/* Length of the rec_get_offsets() header */
+# define REC_OFFS_HEADER_SIZE 2
+#endif /* UNIV_DEBUG */
+
+/* Get the base address of offsets. The extra_size is stored at
+this position, and following positions hold the end offsets of
+the fields. */
+#define rec_offs_base(offsets) (offsets + REC_OFFS_HEADER_SIZE)
+
+/**************************************************************
+The following function returns the number of allocated elements
+for an array of offsets. */
+UNIV_INLINE
+ulint
+rec_offs_get_n_alloc(
+/*=================*/
+ /* out: number of elements */
+ const ulint* offsets)/* in: array for rec_get_offsets() */
+{
+ ulint n_alloc;
+ ut_ad(offsets);
+ n_alloc = offsets[0];
+ ut_ad(n_alloc > 0);
+ return(n_alloc);
+}
+
+/**************************************************************
+The following function sets the number of allocated elements
+for an array of offsets. */
+UNIV_INLINE
+void
+rec_offs_set_n_alloc(
+/*=================*/
+ ulint* offsets, /* in: array for rec_get_offsets() */
+ ulint n_alloc) /* in: number of elements */
+{
+ ut_ad(offsets);
+ ut_ad(n_alloc > 0);
+ offsets[0] = n_alloc;
+}
+
+/**************************************************************
+The following function returns the number of fields in a record. */
+UNIV_INLINE
+ulint
+rec_offs_n_fields(
+/*===============*/
+ /* out: number of fields */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
+{
+ ulint n_fields;
+ ut_ad(offsets);
+ n_fields = offsets[1];
+ ut_ad(n_fields > 0);
+ ut_ad(n_fields <= REC_MAX_N_FIELDS);
+ ut_ad(n_fields + REC_OFFS_HEADER_SIZE
+ <= rec_offs_get_n_alloc(offsets));
+ return(n_fields);
+}
+
+/****************************************************************
+Validates offsets returned by rec_get_offsets(). */
UNIV_INLINE
ibool
-rec_get_nth_field_extern_bit(
-/*=========================*/
- /* in: TRUE or FALSE */
- rec_t* rec, /* in: record */
- ulint i) /* in: ith field */
+rec_offs_validate(
+/*==============*/
+ /* out: TRUE if valid */
+ rec_t* rec, /* in: record or NULL */
+ dict_index_t* index, /* in: record descriptor or NULL */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
- ulint info;
+ ulint i = rec_offs_n_fields(offsets);
+ ulint last = ULINT_MAX;
+ ibool comp = (*rec_offs_base(offsets) & REC_OFFS_COMPACT) != 0;
+
+ if (rec) {
+ ut_ad((ulint) rec == offsets[2]);
+ if (!comp) {
+ ut_a(rec_get_n_fields_old(rec) >= i);
+ }
+ }
+ if (index) {
+ ulint max_n_fields;
+ ut_ad((ulint) index == offsets[3]);
+ max_n_fields = ut_max(
+ dict_index_get_n_fields(index),
+ dict_index_get_n_unique_in_tree(index) + 1);
+ if (comp && rec) {
+ switch (rec_get_status(rec)) {
+ case REC_STATUS_ORDINARY:
+ break;
+ case REC_STATUS_NODE_PTR:
+ max_n_fields =
+ dict_index_get_n_unique_in_tree(index) + 1;
+ break;
+ case REC_STATUS_INFIMUM:
+ case REC_STATUS_SUPREMUM:
+ max_n_fields = 1;
+ break;
+ default:
+ ut_error;
+ }
+ }
+ /* index->n_def == 0 for dummy indexes if !comp */
+ ut_a(!comp || index->n_def);
+ ut_a(!index->n_def || i <= max_n_fields);
+ }
+ while (i--) {
+ ulint curr = rec_offs_base(offsets)[1 + i] & REC_OFFS_MASK;
+ ut_a(curr <= last);
+ last = curr;
+ }
+ return(TRUE);
+}
+/****************************************************************
+Updates debug data in offsets, in order to avoid bogus
+rec_offs_validate() failures. */
+UNIV_INLINE
+void
+rec_offs_make_valid(
+/*================*/
+ rec_t* rec __attribute__((unused)),
+ /* in: record */
+ dict_index_t* index __attribute__((unused)),
+ /* in: record descriptor */
+ ulint* offsets __attribute__((unused)))
+ /* in: array returned by rec_get_offsets() */
+{
+#ifdef UNIV_DEBUG
+ ut_ad(rec_get_n_fields(rec, index) >= rec_offs_n_fields(offsets));
+ offsets[2] = (ulint) rec;
+ offsets[3] = (ulint) index;
+#endif /* UNIV_DEBUG */
+}
- if (rec_get_1byte_offs_flag(rec)) {
+/****************************************************************
+The following function is used to get a pointer to the nth
+data field in an old-style record. */
+UNIV_INLINE
+byte*
+rec_get_nth_field(
+/*==============*/
+ /* out: pointer to the field */
+ rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint n, /* in: index of the field */
+ ulint* len) /* out: length of the field; UNIV_SQL_NULL
+ if SQL null */
+{
+ byte* field;
+ ulint length;
+ ut_ad(rec);
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_ad(n < rec_offs_n_fields(offsets));
+ ut_ad(len);
- return(FALSE);
+ if (n == 0) {
+ field = rec;
+ } else {
+ field = rec + (rec_offs_base(offsets)[n] & REC_OFFS_MASK);
}
- info = rec_2_get_field_end_info(rec, i);
+ length = rec_offs_base(offsets)[1 + n];
- if (info & REC_2BYTE_EXTERN_MASK) {
- return(TRUE);
+ if (length & REC_OFFS_SQL_NULL) {
+ length = UNIV_SQL_NULL;
+ } else {
+ length &= REC_OFFS_MASK;
+ length -= field - rec;
}
- return(FALSE);
+ *len = length;
+ return(field);
}
/**********************************************************
-Returns TRUE if the extern bit is set in any of the fields
-of rec. */
+Determine if the offsets are for a record in the new
+compact format. */
UNIV_INLINE
ibool
-rec_contains_externally_stored_field(
-/*=================================*/
- /* out: TRUE if a field is stored externally */
- rec_t* rec) /* in: record */
+rec_offs_comp(
+/*==========*/
+ /* out: TRUE if compact format */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
- ulint n;
- ulint i;
-
- if (rec_get_1byte_offs_flag(rec)) {
-
- return(FALSE);
- }
+ ut_ad(rec_offs_validate(NULL, NULL, offsets));
+ return((*rec_offs_base(offsets) & REC_OFFS_COMPACT) != 0);
+}
- n = rec_get_n_fields(rec);
+/**********************************************************
+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. */
+UNIV_INLINE
+ibool
+rec_offs_nth_extern(
+/*================*/
+ /* out: TRUE 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);
+}
- for (i = 0; i < n; i++) {
- if (rec_get_nth_field_extern_bit(rec, i)) {
+/**********************************************************
+Gets the physical size of a field. */
+UNIV_INLINE
+ulint
+rec_offs_nth_size(
+/*==============*/
+ /* out: length of field */
+ 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_base(offsets)[n])
+ & REC_OFFS_MASK);
+}
+/**********************************************************
+Returns TRUE if the extern bit is set in any of the fields
+of an old-style record. */
+UNIV_INLINE
+ibool
+rec_offs_any_extern(
+/*================*/
+ /* out: TRUE if a field is stored externally */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
+{
+ ulint i;
+ for (i = rec_offs_n_fields(offsets); i--; ) {
+ if (rec_offs_nth_extern(offsets, i)) {
return(TRUE);
}
}
-
return(FALSE);
}
+/***************************************************************
+Sets the value of the ith field extern storage bit. */
+UNIV_INLINE
+void
+rec_set_nth_field_extern_bit(
+/*=========================*/
+ rec_t* rec, /* in: record */
+ dict_index_t* index, /* in: record descriptor */
+ ulint i, /* in: ith field */
+ ibool val, /* in: value to set */
+ mtr_t* mtr) /* in: mtr holding an X-latch to the page
+ where rec is, or NULL; in the NULL case
+ we do not write to log about the change */
+{
+ if (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);
+ }
+}
+
/**********************************************************
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
@@ -589,9 +1060,9 @@ rec_1_get_prev_field_end_info(
ulint n) /* in: field index */
{
ut_ad(rec_get_1byte_offs_flag(rec));
- ut_ad(n <= rec_get_n_fields(rec));
+ ut_ad(n <= rec_get_n_fields_old(rec));
- return(mach_read_from_1(rec - (REC_N_EXTRA_BYTES + n)));
+ return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n)));
}
/**********************************************************
@@ -608,9 +1079,9 @@ rec_2_get_prev_field_end_info(
ulint n) /* in: field index */
{
ut_ad(!rec_get_1byte_offs_flag(rec));
- ut_ad(n <= rec_get_n_fields(rec));
+ ut_ad(n <= rec_get_n_fields_old(rec));
- return(mach_read_from_2(rec - (REC_N_EXTRA_BYTES + 2 * n)));
+ return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n)));
}
/**********************************************************
@@ -625,9 +1096,9 @@ rec_1_set_field_end_info(
ulint info) /* in: value to set */
{
ut_ad(rec_get_1byte_offs_flag(rec));
- ut_ad(n < rec_get_n_fields(rec));
+ ut_ad(n < rec_get_n_fields_old(rec));
- mach_write_to_1(rec - (REC_N_EXTRA_BYTES + n + 1), info);
+ mach_write_to_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1), info);
}
/**********************************************************
@@ -642,9 +1113,9 @@ rec_2_set_field_end_info(
ulint info) /* in: value to set */
{
ut_ad(!rec_get_1byte_offs_flag(rec));
- ut_ad(n < rec_get_n_fields(rec));
+ ut_ad(n < rec_get_n_fields_old(rec));
- mach_write_to_2(rec - (REC_N_EXTRA_BYTES + 2 * n + 2), info);
+ mach_write_to_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2), info);
}
/**********************************************************
@@ -659,7 +1130,7 @@ rec_1_get_field_start_offs(
ulint n) /* in: field index */
{
ut_ad(rec_get_1byte_offs_flag(rec));
- ut_ad(n <= rec_get_n_fields(rec));
+ ut_ad(n <= rec_get_n_fields_old(rec));
if (n == 0) {
@@ -682,7 +1153,7 @@ rec_2_get_field_start_offs(
ulint n) /* in: field index */
{
ut_ad(!rec_get_1byte_offs_flag(rec));
- ut_ad(n <= rec_get_n_fields(rec));
+ ut_ad(n <= rec_get_n_fields_old(rec));
if (n == 0) {
@@ -707,7 +1178,7 @@ rec_get_field_start_offs(
ulint n) /* in: field index */
{
ut_ad(rec);
- ut_ad(n <= rec_get_n_fields(rec));
+ ut_ad(n <= rec_get_n_fields_old(rec));
if (n == 0) {
@@ -723,8 +1194,9 @@ rec_get_field_start_offs(
}
/****************************************************************
-Gets the physical size of a field. Also an SQL null may have a field of
-size > 0, if the data type is of a fixed size. */
+Gets the physical size of an old-style field.
+Also an SQL null may have a field of size > 0,
+if the data type is of a fixed size. */
UNIV_INLINE
ulint
rec_get_nth_field_size(
@@ -744,133 +1216,134 @@ rec_get_nth_field_size(
return(next_os - os);
}
-/****************************************************************
-The following function is used to get a copy of the nth data field in a
-record to a buffer. */
-UNIV_INLINE
-void
-rec_copy_nth_field(
-/*===============*/
- void* buf, /* in: pointer to the buffer */
- rec_t* rec, /* in: record */
- ulint n, /* in: index of the field */
- ulint* len) /* out: length of the field; UNIV_SQL_NULL if SQL
- null */
-{
- byte* ptr;
-
- ut_ad(buf && rec && len);
-
- ptr = rec_get_nth_field(rec, n, len);
-
- if (*len == UNIV_SQL_NULL) {
-
- return;
- }
-
- ut_memcpy(buf, ptr, *len);
-}
-
/***************************************************************
This is used to modify the value of an already existing field in a record.
The previous value must have exactly the same size as the new value. If len
-is UNIV_SQL_NULL then the field is treated as an SQL null. */
+is UNIV_SQL_NULL then the field is treated as an SQL null for old-style
+records. For new-style records, len must not be UNIV_SQL_NULL. */
UNIV_INLINE
void
rec_set_nth_field(
/*==============*/
- rec_t* rec, /* in: record */
- ulint n, /* in: index of the field */
- void* data, /* in: pointer to the data if not SQL null */
- ulint len) /* in: length of the data or UNIV_SQL_NULL */
+ rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint n, /* in: index number of the field */
+ const void* data, /* in: pointer to the data
+ if not SQL null */
+ ulint len) /* in: length of the data or UNIV_SQL_NULL.
+ If not SQL null, must have the same
+ length as the previous value.
+ If SQL null, previous value must be
+ SQL null. */
{
byte* data2;
ulint len2;
- ut_ad((len == UNIV_SQL_NULL)
- || (rec_get_nth_field_size(rec, n) == len));
-
+ ut_ad(rec);
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+
if (len == UNIV_SQL_NULL) {
+ ut_ad(!rec_offs_comp(offsets));
rec_set_nth_field_sql_null(rec, n);
return;
}
- data2 = rec_get_nth_field(rec, n, &len2);
-
- ut_memcpy(data2, data, len);
-
+ data2 = rec_get_nth_field(rec, offsets, n, &len2);
if (len2 == UNIV_SQL_NULL) {
-
+ ut_ad(!rec_offs_comp(offsets));
rec_set_nth_field_null_bit(rec, n, FALSE);
+ ut_ad(len == rec_get_nth_field_size(rec, n));
+ } else {
+ ut_ad(len2 == len);
}
+
+ ut_memcpy(data2, data, len);
}
/**************************************************************
-The following function returns the data size of a physical
+The following function returns the data size of an old-style physical
record, that is the sum of field lengths. SQL null fields
are counted as length 0 fields. The value returned by the function
is the distance from record origin to record end in bytes. */
UNIV_INLINE
ulint
-rec_get_data_size(
-/*==============*/
- /* out: size */
+rec_get_data_size_old(
+/*==================*/
+ /* out: size */
rec_t* rec) /* in: physical record */
{
ut_ad(rec);
- return(rec_get_field_start_offs(rec, rec_get_n_fields(rec)));
+ return(rec_get_field_start_offs(rec, rec_get_n_fields_old(rec)));
}
/**************************************************************
-Returns the total size of record minus data size of record. The value
-returned by the function is the distance from record start to record origin
-in bytes. */
+The following function sets the number of fields in offsets. */
+UNIV_INLINE
+void
+rec_offs_set_n_fields(
+/*==================*/
+ ulint* offsets, /* in: array returned by rec_get_offsets() */
+ ulint n_fields) /* in: number of fields */
+{
+ ut_ad(offsets);
+ ut_ad(n_fields > 0);
+ ut_ad(n_fields <= REC_MAX_N_FIELDS);
+ ut_ad(n_fields + REC_OFFS_HEADER_SIZE
+ <= rec_offs_get_n_alloc(offsets));
+ offsets[1] = n_fields;
+}
+
+/**************************************************************
+The following function returns the data size of a physical
+record, that is the sum of field lengths. SQL null fields
+are counted as length 0 fields. The value returned by the function
+is the distance from record origin to record end in bytes. */
UNIV_INLINE
ulint
-rec_get_extra_size(
+rec_offs_data_size(
/*===============*/
- /* out: size */
- rec_t* rec) /* in: physical record */
+ /* out: size */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
- ulint n_fields;
-
- ut_ad(rec);
-
- n_fields = rec_get_n_fields(rec);
+ ulint size;
- if (rec_get_1byte_offs_flag(rec)) {
-
- return(REC_N_EXTRA_BYTES + n_fields);
- }
+ ut_ad(rec_offs_validate(NULL, NULL, offsets));
+ size = rec_offs_base(offsets)[rec_offs_n_fields(offsets)]
+ & REC_OFFS_MASK;
+ ut_ad(size < UNIV_PAGE_SIZE);
+ return(size);
+}
- return(REC_N_EXTRA_BYTES + 2 * n_fields);
+/**************************************************************
+Returns the total size of record minus data size of record. The value
+returned by the function is the distance from record start to record origin
+in bytes. */
+UNIV_INLINE
+ulint
+rec_offs_extra_size(
+/*================*/
+ /* out: size */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
+{
+ ulint size;
+ ut_ad(rec_offs_validate(NULL, NULL, offsets));
+ size = *rec_offs_base(offsets) & ~REC_OFFS_COMPACT;
+ ut_ad(size < UNIV_PAGE_SIZE);
+ return(size);
}
-/**************************************************************
+/**************************************************************
Returns the total size of a physical record. */
UNIV_INLINE
ulint
-rec_get_size(
-/*=========*/
- /* out: size */
- rec_t* rec) /* in: physical record */
+rec_offs_size(
+/*==========*/
+ /* out: size */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
- ulint n_fields;
-
- ut_ad(rec);
-
- n_fields = rec_get_n_fields(rec);
-
- if (rec_get_1byte_offs_flag(rec)) {
-
- return(REC_N_EXTRA_BYTES + n_fields
- + rec_1_get_field_start_offs(rec, n_fields));
- }
-
- return(REC_N_EXTRA_BYTES + 2 * n_fields
- + rec_2_get_field_start_offs(rec, n_fields));
+ return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets));
}
/**************************************************************
@@ -879,10 +1352,11 @@ UNIV_INLINE
byte*
rec_get_end(
/*========*/
- /* out: pointer to end */
- rec_t* rec) /* in: pointer to record */
+ /* out: pointer to end */
+ rec_t* rec, /* in: pointer to record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
- return(rec + rec_get_data_size(rec));
+ return(rec + rec_offs_data_size(offsets));
}
/**************************************************************
@@ -891,10 +1365,11 @@ UNIV_INLINE
byte*
rec_get_start(
/*==========*/
- /* out: pointer to start */
- rec_t* rec) /* in: pointer to record */
+ /* out: pointer to start */
+ rec_t* rec, /* in: pointer to record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
- return(rec - rec_get_extra_size(rec));
+ return(rec - rec_offs_extra_size(offsets));
}
/*******************************************************************
@@ -903,18 +1378,20 @@ UNIV_INLINE
rec_t*
rec_copy(
/*=====*/
- /* out: pointer to the origin of the copied record */
- void* buf, /* in: buffer */
- rec_t* rec) /* in: physical record */
+ /* out: pointer to the origin of the copy */
+ void* buf, /* in: buffer */
+ const rec_t* rec, /* in: physical record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
ulint extra_len;
ulint data_len;
ut_ad(rec && buf);
- ut_ad(rec_validate(rec));
+ ut_ad(rec_offs_validate((rec_t*) rec, NULL, offsets));
+ ut_ad(rec_validate((rec_t*) rec, offsets));
- extra_len = rec_get_extra_size(rec);
- data_len = rec_get_data_size(rec);
+ extra_len = rec_offs_extra_size(offsets);
+ data_len = rec_offs_data_size(offsets);
ut_memcpy(buf, rec - extra_len, extra_len + data_len);
@@ -922,8 +1399,8 @@ rec_copy(
}
/**************************************************************
-Returns the extra size of a physical record if we know its data size and
-the number of fields. */
+Returns the extra size of an old-style physical record if we know its
+data size and number of fields. */
UNIV_INLINE
ulint
rec_get_converted_extra_size(
@@ -934,28 +1411,51 @@ rec_get_converted_extra_size(
{
if (data_size <= REC_1BYTE_OFFS_LIMIT) {
- return(REC_N_EXTRA_BYTES + n_fields);
+ return(REC_N_OLD_EXTRA_BYTES + n_fields);
}
- return(REC_N_EXTRA_BYTES + 2 * n_fields);
+ return(REC_N_OLD_EXTRA_BYTES + 2 * n_fields);
}
/**************************************************************
The following function returns the size of a data tuple when converted to
+a new-style physical record. */
+
+ulint
+rec_get_converted_size_new(
+/*=======================*/
+ /* out: size */
+ dict_index_t* index, /* in: record descriptor */
+ dtuple_t* dtuple);/* in: data tuple */
+/**************************************************************
+The following function returns the size of a data tuple when converted to
a physical record. */
UNIV_INLINE
ulint
rec_get_converted_size(
/*===================*/
/* out: size */
+ dict_index_t* index, /* in: record descriptor */
dtuple_t* dtuple) /* in: data tuple */
{
ulint data_size;
ulint extra_size;
-
+
+ ut_ad(index);
ut_ad(dtuple);
ut_ad(dtuple_check_typed(dtuple));
+ ut_ad(index->type & DICT_UNIVERSAL
+ || dtuple_get_n_fields(dtuple) ==
+ (((dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK)
+ == REC_STATUS_NODE_PTR)
+ ? dict_index_get_n_unique_in_tree(index) + 1
+ : dict_index_get_n_fields(index)));
+
+ if (index->table->comp) {
+ return(rec_get_converted_size_new(index, dtuple));
+ }
+
data_size = dtuple_get_data_size(dtuple);
extra_size = rec_get_converted_extra_size(
@@ -971,12 +1471,15 @@ UNIV_INLINE
ulint
rec_fold(
/*=====*/
- /* out: the folded value */
- rec_t* rec, /* in: the physical record */
- ulint n_fields, /* in: number of complete fields to fold */
- ulint n_bytes, /* in: number of bytes to fold in an
- incomplete last field */
- dulint tree_id) /* in: index tree id */
+ /* out: the folded value */
+ rec_t* rec, /* in: the physical record */
+ const ulint* offsets, /* in: array returned by
+ rec_get_offsets() */
+ ulint n_fields, /* in: number of complete
+ fields to fold */
+ ulint n_bytes, /* in: number of bytes to fold
+ in an incomplete last field */
+ dulint tree_id) /* in: index tree id */
{
ulint i;
byte* data;
@@ -984,12 +1487,13 @@ rec_fold(
ulint fold;
ulint n_fields_rec;
- ut_ad(rec_validate(rec));
- ut_ad(n_fields <= rec_get_n_fields(rec));
- ut_ad((n_fields < rec_get_n_fields(rec)) || (n_bytes == 0));
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_ad(rec_validate((rec_t*) rec, offsets));
ut_ad(n_fields + n_bytes > 0);
-
- n_fields_rec = rec_get_n_fields(rec);
+
+ n_fields_rec = rec_offs_n_fields(offsets);
+ ut_ad(n_fields <= n_fields_rec);
+ ut_ad(n_fields < n_fields_rec || n_bytes == 0);
if (n_fields > n_fields_rec) {
n_fields = n_fields_rec;
@@ -1002,7 +1506,7 @@ rec_fold(
fold = ut_fold_dulint(tree_id);
for (i = 0; i < n_fields; i++) {
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field(rec, offsets, i, &len);
if (len != UNIV_SQL_NULL) {
fold = ut_fold_ulint_pair(fold,
@@ -1011,7 +1515,7 @@ rec_fold(
}
if (n_bytes > 0) {
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field(rec, offsets, i, &len);
if (len != UNIV_SQL_NULL) {
if (len > n_bytes) {
@@ -1025,19 +1529,3 @@ rec_fold(
return(fold);
}
-
-/*************************************************************
-Builds a physical record out of a data tuple and stores it beginning from
-the address destination. */
-UNIV_INLINE
-rec_t*
-rec_convert_dtuple_to_rec(
-/*======================*/
- /* out: pointer to the origin of physical
- record */
- byte* destination, /* in: start address of the physical record */
- dtuple_t* dtuple) /* in: data tuple */
-{
- return(rec_convert_dtuple_to_rec_low(destination, dtuple,
- dtuple_get_data_size(dtuple)));
-}
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index 13773ed380d..e44d689b88b 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -22,36 +22,6 @@ Created 9/17/2000 Heikki Tuuri
typedef struct row_prebuilt_struct row_prebuilt_t;
/***********************************************************************
-Stores a variable-length field (like VARCHAR) length to dest, in the
-MySQL format. */
-UNIV_INLINE
-byte*
-row_mysql_store_var_len(
-/*====================*/
- /* out: dest + 2 */
- byte* dest, /* in: where to store */
- ulint len); /* in: length, must fit in two bytes */
-/***********************************************************************
-Reads a MySQL format variable-length field (like VARCHAR) length and
-returns pointer to the field data. */
-UNIV_INLINE
-byte*
-row_mysql_read_var_ref(
-/*===================*/
- /* out: field + 2 */
- ulint* len, /* out: variable-length field length */
- byte* field); /* in: field */
-/***********************************************************************
-Reads a MySQL format variable-length field (like VARCHAR) length and
-returns pointer to the field data. */
-
-byte*
-row_mysql_read_var_ref_noninline(
-/*=============================*/
- /* out: field + 2 */
- ulint* len, /* out: variable-length field length */
- byte* field); /* in: field */
-/***********************************************************************
Frees the blob heap in prebuilt when no longer needed. */
void
@@ -60,6 +30,30 @@ row_mysql_prebuilt_free_blob_heap(
row_prebuilt_t* prebuilt); /* in: prebuilt struct of a
ha_innobase:: table handle */
/***********************************************************************
+Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
+format. */
+
+byte*
+row_mysql_store_true_var_len(
+/*=========================*/
+ /* out: pointer to the data, we skip the 1 or 2 bytes
+ at the start that are used to store the len */
+ byte* dest, /* in: where to store */
+ ulint len, /* in: length, must fit in two bytes */
+ ulint lenlen);/* in: storage length of len: either 1 or 2 bytes */
+/***********************************************************************
+Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
+returns a pointer to the data. */
+
+byte*
+row_mysql_read_true_varchar(
+/*========================*/
+ /* out: pointer to the data, we skip the 1 or 2 bytes
+ at the start that are used to store the len */
+ ulint* len, /* out: variable-length field length */
+ byte* field, /* in: field in the MySQL format */
+ ulint lenlen);/* in: storage length of len: either 1 or 2 bytes */
+/***********************************************************************
Stores a reference to a BLOB in the MySQL format. */
void
@@ -83,23 +77,40 @@ row_mysql_read_blob_ref(
ulint col_len); /* in: BLOB reference length (not BLOB
length) */
/******************************************************************
-Stores a non-SQL-NULL field given in the MySQL format in the Innobase
-format. */
-UNIV_INLINE
-void
+Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
+The counterpart of this function is row_sel_field_store_in_mysql_format() in
+row0sel.c. */
+
+byte*
row_mysql_store_col_in_innobase_format(
/*===================================*/
- dfield_t* dfield, /* in/out: dfield */
- byte* buf, /* in/out: buffer for the converted
- value */
+ /* out: up to which byte we used
+ buf in the conversion */
+ dfield_t* dfield, /* in/out: dfield where dtype
+ information must be already set when
+ this function is called! */
+ byte* buf, /* in/out: buffer for a converted
+ integer value; this must be at least
+ col_len long then! */
+ ibool row_format_col, /* TRUE if the mysql_data is from
+ a MySQL row, FALSE if from a MySQL
+ key value;
+ in MySQL, a true VARCHAR storage
+ format differs in a row and in a
+ key value: in a key value the length
+ is always stored in 2 bytes! */
byte* mysql_data, /* in: MySQL column value, not
SQL NULL; NOTE that dfield may also
get a pointer to mysql_data,
therefore do not discard this as long
as dfield is used! */
- ulint col_len, /* in: MySQL column length */
- ulint type, /* in: data type */
- ulint is_unsigned); /* in: != 0 if unsigned integer type */
+ ulint col_len, /* in: MySQL column length; NOTE that
+ this is the storage length of the
+ column in the MySQL format row, not
+ 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 */
/********************************************************************
Handles user errors and lock waits detected by the database engine. */
@@ -239,6 +250,17 @@ 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. */
+
+int
+row_unlock_for_mysql(
+/*=================*/
+ /* out: error code or DB_SUCCESS */
+ row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
+ handle */
+
/*************************************************************************
Creates an query graph node of 'update' type to be used in the MySQL
interface. */
@@ -352,6 +374,15 @@ row_get_background_drop_list_len_low(void);
/*======================================*/
/* out: how many tables in list */
/*************************************************************************
+Truncates a table for MySQL. */
+
+int
+row_truncate_table_for_mysql(
+/*=========================*/
+ /* out: error code or DB_SUCCESS */
+ dict_table_t* table, /* in: table handle */
+ trx_t* trx); /* in: transaction handle */
+/*************************************************************************
Drops a table for MySQL. If the name of the dropped table ends to
characters INNODB_MONITOR, then this also stops printing of monitor
output by the master thread. */
@@ -436,8 +467,22 @@ struct mysql_row_templ_struct {
zero if column cannot be NULL */
ulint type; /* column type in Innobase mtype
numbers DATA_CHAR... */
+ ulint mysql_type; /* MySQL type code; this is always
+ < 256 */
+ ulint mysql_length_bytes; /* if mysql_type
+ == DATA_MYSQL_TRUE_VARCHAR, this tells
+ whether we should use 1 or 2 bytes to
+ store the MySQL true VARCHAR data
+ length at the start of row in the MySQL
+ format (NOTE that the MySQL key value
+ format always uses 2 bytes for the data
+ len) */
ulint charset; /* MySQL charset-collation code
of the column, or zero */
+ ulint mbminlen; /* minimum length of a char, in bytes,
+ or zero if not a char type */
+ ulint mbmaxlen; /* maximum length of a char, in bytes,
+ or zero if not a char type */
ulint is_unsigned; /* if a column type is an integer
type and this field is != 0, then
it is an unsigned integer type */
@@ -569,6 +614,10 @@ struct row_prebuilt_struct {
allocated mem buf start, because
there is a 4 byte magic number at the
start and at the end */
+ ibool keep_other_fields_on_keyread; /* when using fetch
+ cache with HA_EXTRA_KEYREAD, don't
+ overwrite other fields in mysql row
+ row buffer.*/
ulint fetch_cache_first;/* position of the first not yet
fetched row in fetch_cache */
ulint n_fetch_cached; /* number of not yet fetched rows
diff --git a/innobase/include/row0mysql.ic b/innobase/include/row0mysql.ic
index fc922b52d0a..aa8a70d8761 100644
--- a/innobase/include/row0mysql.ic
+++ b/innobase/include/row0mysql.ic
@@ -5,122 +5,3 @@ MySQL interface for Innobase
Created 1/23/2001 Heikki Tuuri
*******************************************************/
-
-/***********************************************************************
-Stores a variable-length field (like VARCHAR) length to dest, in the
-MySQL format. No real var implemented in MySQL yet! */
-UNIV_INLINE
-byte*
-row_mysql_store_var_len(
-/*====================*/
- /* out: dest + 2 */
- byte* dest, /* in: where to store */
- ulint len __attribute__((unused))) /* in: length, must fit in two
- bytes */
-{
- ut_ad(len < 256 * 256);
-/*
- mach_write_to_2_little_endian(dest, len);
-
- return(dest + 2);
-*/
- return(dest); /* No real var implemented in MySQL yet! */
-}
-
-/***********************************************************************
-Reads a MySQL format variable-length field (like VARCHAR) length and
-returns pointer to the field data. No real var implemented in MySQL yet! */
-UNIV_INLINE
-byte*
-row_mysql_read_var_ref(
-/*===================*/
- /* out: field + 2 */
- ulint* len, /* out: variable-length field length; does not work
- yet! */
- byte* field) /* in: field */
-{
-/*
- *len = mach_read_from_2_little_endian(field);
-
- return(field + 2);
-*/
- UT_NOT_USED(len);
-
- return(field); /* No real var implemented in MySQL yet! */
-}
-
-/******************************************************************
-Stores a non-SQL-NULL field given in the MySQL format in the Innobase
-format. */
-UNIV_INLINE
-void
-row_mysql_store_col_in_innobase_format(
-/*===================================*/
- dfield_t* dfield, /* in/out: dfield */
- byte* buf, /* in/out: buffer for the converted
- value; this must be at least col_len
- long! */
- byte* mysql_data, /* in: MySQL column value, not
- SQL NULL; NOTE that dfield may also
- get a pointer to mysql_data,
- therefore do not discard this as long
- as dfield is used! */
- ulint col_len, /* in: MySQL column length */
- ulint type, /* in: data type */
- ulint is_unsigned) /* in: != 0 if unsigned integer type */
-{
- byte* ptr = mysql_data;
-
- if (type == DATA_INT) {
- /* Store integer data in Innobase in a big-endian format,
- sign bit negated */
-
- ptr = buf + col_len;
-
- for (;;) {
- ptr--;
- *ptr = *mysql_data;
- if (ptr == buf) {
- break;
- }
- mysql_data++;
- }
-
- if (!is_unsigned) {
- *ptr = (byte) (*ptr ^ 128);
- }
- } else if (type == DATA_VARCHAR || type == DATA_VARMYSQL
- || type == DATA_BINARY) {
- /* Remove trailing spaces. */
-
- /* Handle UCS2 strings differently. As no new
- collations will be introduced in 4.1, we hardcode the
- charset-collation codes here. In 5.0, the logic will
- be based on mbminlen. */
- ulint cset = dtype_get_charset_coll(
- dtype_get_prtype(dfield_get_type(dfield)));
- ptr = row_mysql_read_var_ref(&col_len, mysql_data);
- if (cset == 35/*ucs2_general_ci*/
- || cset == 90/*ucs2_bin*/
- || (cset >= 128/*ucs2_unicode_ci*/
- && cset <= 144/*ucs2_persian_ci*/)) {
- /* space=0x0020 */
- /* Trim "half-chars", just in case. */
- col_len &= ~1;
-
- while (col_len >= 2 && ptr[col_len - 2] == 0x00
- && ptr[col_len - 1] == 0x20) {
- col_len -= 2;
- }
- } else {
- /* space=0x20 */
- while (col_len > 0 && ptr[col_len - 1] == 0x20) {
- col_len--;
- }
- }
- } else if (type == DATA_BLOB) {
- ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
- }
-
- dfield_set_data(dfield, ptr, col_len);
-}
diff --git a/innobase/include/row0row.h b/innobase/include/row0row.h
index 951e211fb37..782973d8f5d 100644
--- a/innobase/include/row0row.h
+++ b/innobase/include/row0row.h
@@ -27,7 +27,8 @@ row_get_rec_trx_id(
/*===============*/
/* out: value of the field */
rec_t* rec, /* in: record */
- dict_index_t* index); /* in: clustered index */
+ dict_index_t* index, /* in: clustered index */
+ const ulint* offsets);/* in: rec_get_offsets(rec, index) */
/*************************************************************************
Reads the roll pointer field from a clustered index record. */
UNIV_INLINE
@@ -36,7 +37,8 @@ row_get_rec_roll_ptr(
/*=================*/
/* out: value of the field */
rec_t* rec, /* in: record */
- dict_index_t* index); /* in: clustered index */
+ dict_index_t* index, /* in: clustered index */
+ const ulint* offsets);/* in: rec_get_offsets(rec, index) */
/*************************************************************************
Writes the trx id field to a clustered index record. */
UNIV_INLINE
@@ -45,7 +47,8 @@ row_set_rec_trx_id(
/*===============*/
rec_t* rec, /* in: record */
dict_index_t* index, /* in: clustered index */
- dulint trx_id); /* in: value of the field */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
+ dulint trx_id);/* in: value of the field */
/*************************************************************************
Sets the roll pointer field in a clustered index record. */
UNIV_INLINE
@@ -54,6 +57,7 @@ row_set_rec_roll_ptr(
/*=================*/
rec_t* rec, /* in: record */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
dulint roll_ptr);/* in: value of the field */
/*********************************************************************
When an insert to a table is performed, this function builds the entry which
@@ -90,6 +94,9 @@ row_build(
the buffer page of this record must be
at least s-latched and the latch held
as long as the row dtuple is used! */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index)
+ or NULL, in which case this function
+ will invoke rec_get_offsets() */
mem_heap_t* heap); /* in: memory heap from which the memory
needed is allocated */
/***********************************************************************
@@ -175,14 +182,15 @@ UNIV_INLINE
void
row_build_row_ref_fast(
/*===================*/
- dtuple_t* ref, /* in: typed data tuple where the reference
- is built */
- ulint* map, /* in: array of field numbers in rec telling
- how ref should be built from the fields of
- rec */
- rec_t* rec); /* in: record in the index; must be preserved
- while ref is used, as we do not copy field
- values to heap */
+ dtuple_t* ref, /* in: typed data tuple where the
+ reference is built */
+ const ulint* map, /* in: array of field numbers in rec
+ telling how ref should be built from
+ the fields of rec */
+ rec_t* rec, /* in: record in the index; must be
+ preserved while ref is used, as we do
+ not copy field values to heap */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/*******************************************************************
Searches the clustered index record for a row, if we have the row
reference. */
diff --git a/innobase/include/row0row.ic b/innobase/include/row0row.ic
index 8e5121f5a96..85410beacf0 100644
--- a/innobase/include/row0row.ic
+++ b/innobase/include/row0row.ic
@@ -20,7 +20,8 @@ row_get_rec_sys_field(
/* out: value of the field */
ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
rec_t* rec, /* in: record */
- dict_index_t* index); /* in: clustered index */
+ dict_index_t* index, /* in: clustered index */
+ const ulint* offsets);/* in: rec_get_offsets(rec, index) */
/*************************************************************************
Sets the trx id or roll ptr field in a clustered index record: this function
is slower than the specialized inline functions. */
@@ -32,6 +33,7 @@ row_set_rec_sys_field(
ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
dulint val); /* in: value to set */
/*************************************************************************
@@ -42,18 +44,21 @@ row_get_rec_trx_id(
/*===============*/
/* out: value of the field */
rec_t* rec, /* in: record */
- dict_index_t* index) /* in: clustered index */
+ dict_index_t* index, /* in: clustered index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
ulint offset;
ut_ad(index->type & DICT_CLUSTERED);
+ ut_ad(rec_offs_validate(rec, index, offsets));
offset = index->trx_id_offset;
if (offset) {
return(trx_read_trx_id(rec + offset));
} else {
- return(row_get_rec_sys_field(DATA_TRX_ID, rec, index));
+ return(row_get_rec_sys_field(DATA_TRX_ID,
+ rec, index, offsets));
}
}
@@ -65,18 +70,21 @@ row_get_rec_roll_ptr(
/*=================*/
/* out: value of the field */
rec_t* rec, /* in: record */
- dict_index_t* index) /* in: clustered index */
+ dict_index_t* index, /* in: clustered index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
ulint offset;
ut_ad(index->type & DICT_CLUSTERED);
+ ut_ad(rec_offs_validate(rec, index, offsets));
offset = index->trx_id_offset;
if (offset) {
return(trx_read_roll_ptr(rec + offset + DATA_TRX_ID_LEN));
} else {
- return(row_get_rec_sys_field(DATA_ROLL_PTR, rec, index));
+ return(row_get_rec_sys_field(DATA_ROLL_PTR,
+ rec, index, offsets));
}
}
@@ -88,18 +96,21 @@ row_set_rec_trx_id(
/*===============*/
rec_t* rec, /* in: record */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
dulint trx_id) /* in: value of the field */
{
ulint offset;
ut_ad(index->type & DICT_CLUSTERED);
+ ut_ad(rec_offs_validate(rec, index, offsets));
offset = index->trx_id_offset;
if (offset) {
trx_write_trx_id(rec + offset, trx_id);
} else {
- row_set_rec_sys_field(DATA_TRX_ID, rec, index, trx_id);
+ row_set_rec_sys_field(DATA_TRX_ID,
+ rec, index, offsets, trx_id);
}
}
@@ -111,18 +122,21 @@ row_set_rec_roll_ptr(
/*=================*/
rec_t* rec, /* in: record */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
dulint roll_ptr)/* in: value of the field */
{
ulint offset;
ut_ad(index->type & DICT_CLUSTERED);
+ ut_ad(rec_offs_validate(rec, index, offsets));
offset = index->trx_id_offset;
if (offset) {
trx_write_roll_ptr(rec + offset + DATA_TRX_ID_LEN, roll_ptr);
} else {
- row_set_rec_sys_field(DATA_ROLL_PTR, rec, index, roll_ptr);
+ row_set_rec_sys_field(DATA_ROLL_PTR,
+ rec, index, offsets, roll_ptr);
}
}
@@ -133,14 +147,15 @@ UNIV_INLINE
void
row_build_row_ref_fast(
/*===================*/
- dtuple_t* ref, /* in: typed data tuple where the reference
- is built */
- ulint* map, /* in: array of field numbers in rec telling
- how ref should be built from the fields of
- rec */
- rec_t* rec) /* in: record in the index; must be preserved
- while ref is used, as we do not copy field
- values to heap */
+ dtuple_t* ref, /* in: typed data tuple where the
+ reference is built */
+ const ulint* map, /* in: array of field numbers in rec
+ telling how ref should be built from
+ the fields of rec */
+ rec_t* rec, /* in: record in the index; must be
+ preserved while ref is used, as we do
+ not copy field values to heap */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
dfield_t* dfield;
byte* field;
@@ -149,6 +164,7 @@ row_build_row_ref_fast(
ulint field_no;
ulint i;
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
ref_len = dtuple_get_n_fields(ref);
for (i = 0; i < ref_len; i++) {
@@ -158,7 +174,8 @@ row_build_row_ref_fast(
if (field_no != ULINT_UNDEFINED) {
- field = rec_get_nth_field(rec, field_no, &len);
+ field = rec_get_nth_field(rec, offsets,
+ field_no, &len);
dfield_set_data(dfield, field, len);
}
}
diff --git a/innobase/include/row0upd.h b/innobase/include/row0upd.h
index 28210364833..673e0511153 100644
--- a/innobase/include/row0upd.h
+++ b/innobase/include/row0upd.h
@@ -80,6 +80,7 @@ row_upd_rec_sys_fields(
/*===================*/
rec_t* rec, /* in: record */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
trx_t* trx, /* in: transaction */
dulint roll_ptr);/* in: roll ptr of the undo log record */
/*************************************************************************
@@ -124,8 +125,8 @@ row_upd_changes_field_size_or_external(
/* out: TRUE if the update changes the size of
some field in index or the field is external
in rec or update */
- rec_t* rec, /* in: record in index */
dict_index_t* index, /* in: index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
upd_t* update);/* in: update vector */
/***************************************************************
Replaces the new column values stored in the update vector to the record
@@ -135,8 +136,9 @@ a clustered index */
void
row_upd_rec_in_place(
/*=================*/
- rec_t* rec, /* in/out: record where replaced */
- upd_t* update);/* in: update vector */
+ rec_t* rec, /* in/out: record where replaced */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ upd_t* update);/* in: update vector */
/*******************************************************************
Builds an update vector from those fields which in a secondary index entry
differ from a record that has the equal ordering fields. NOTE: we compare
@@ -274,10 +276,11 @@ recovery. */
void
row_upd_rec_sys_fields_in_recovery(
/*===============================*/
- rec_t* rec, /* in: record */
- ulint pos, /* in: TRX_ID position in rec */
- dulint trx_id, /* in: transaction id */
- dulint roll_ptr);/* in: roll ptr of the undo log record */
+ rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint pos, /* in: TRX_ID position in rec */
+ dulint trx_id, /* in: transaction id */
+ dulint roll_ptr);/* in: roll ptr of the undo log record */
/*************************************************************************
Parses the log data written by row_upd_index_write_log. */
diff --git a/innobase/include/row0upd.ic b/innobase/include/row0upd.ic
index a124228a0de..e2d81a39cfa 100644
--- a/innobase/include/row0upd.ic
+++ b/innobase/include/row0upd.ic
@@ -106,15 +106,17 @@ row_upd_rec_sys_fields(
/*===================*/
rec_t* rec, /* in: record */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
trx_t* trx, /* in: transaction */
dulint roll_ptr)/* in: roll ptr of the undo log record */
{
ut_ad(index->type & DICT_CLUSTERED);
+ ut_ad(rec_offs_validate(rec, index, offsets));
#ifdef UNIV_SYNC_DEBUG
ut_ad(!buf_block_align(rec)->is_hashed
|| rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- row_set_rec_trx_id(rec, index, trx->id);
- row_set_rec_roll_ptr(rec, index, roll_ptr);
+ row_set_rec_trx_id(rec, index, offsets, trx->id);
+ row_set_rec_roll_ptr(rec, index, offsets, roll_ptr);
}
diff --git a/innobase/include/row0vers.h b/innobase/include/row0vers.h
index 30cf82144e9..079d841f7f3 100644
--- a/innobase/include/row0vers.h
+++ b/innobase/include/row0vers.h
@@ -30,7 +30,8 @@ row_vers_impl_x_locked_off_kernel(
transaction; NOTE that the kernel mutex is
temporarily released! */
rec_t* rec, /* in: record in a secondary index */
- dict_index_t* index); /* in: the secondary index */
+ dict_index_t* index, /* in: the secondary index */
+ const ulint* offsets);/* in: rec_get_offsets(rec, index) */
/*********************************************************************
Finds out if we must preserve a delete marked earlier version of a clustered
index record, because it is >= the purge view. */
@@ -78,7 +79,11 @@ row_vers_build_for_consistent_read(
mtr_t* mtr, /* in: mtr holding the latch on rec; it will
also hold the latch on purge_view */
dict_index_t* index, /* in: the clustered index */
+ ulint** offsets,/* in/out: offsets returned by
+ rec_get_offsets(rec, index) */
read_view_t* view, /* in: the consistent read view */
+ mem_heap_t** offset_heap,/* in/out: memory heap from which
+ the offsets are allocated */
mem_heap_t* in_heap,/* in: memory heap from which the memory for
old_vers is allocated; memory for possible
intermediate versions is allocated and freed
diff --git a/innobase/include/row0vers.ic b/innobase/include/row0vers.ic
index 5ece47c35d1..ab1e264635b 100644
--- a/innobase/include/row0vers.ic
+++ b/innobase/include/row0vers.ic
@@ -11,73 +11,3 @@ Created 2/6/1997 Heikki Tuuri
#include "read0read.h"
#include "page0page.h"
#include "log0recv.h"
-
-/*************************************************************************
-Fetches the trx id of a clustered index record or version. */
-UNIV_INLINE
-dulint
-row_vers_get_trx_id(
-/*================*/
- /* out: trx id or ut_dulint_zero if the
- clustered index record not found */
- rec_t* rec, /* in: clustered index record, or an old
- version of it */
- dict_table_t* table) /* in: table */
-{
- return(row_get_rec_trx_id(rec, dict_table_get_first_index(table)));
-}
-
-/*************************************************************************
-Checks if a consistent read can be performed immediately on the index
-record, or if an older version is needed. */
-UNIV_INLINE
-ibool
-row_vers_clust_rec_sees_older(
-/*==========================*/
- /* out: FALSE if can read immediately */
- rec_t* rec, /* in: record which should be read or passed
- over by a read cursor */
- dict_index_t* index, /* in: clustered index */
- read_view_t* view) /* in: read view */
-{
- ut_ad(index->type & DICT_CLUSTERED);
-
- if (read_view_sees_trx_id(view, row_get_rec_trx_id(rec, index))) {
-
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-/*************************************************************************
-Checks if a secondary index record can be read immediately by a consistent
-read, or if an older version may be needed. To be sure, we will have to
-look in the clustered index. */
-UNIV_INLINE
-ibool
-row_vers_sec_rec_may_see_older(
-/*===========================*/
- /* out: FALSE if can be read immediately */
- rec_t* rec, /* in: record which should be read or passed */
- dict_index_t* index __attribute__((unused)),/* in: secondary index */
- read_view_t* view) /* in: read view */
-{
- page_t* page;
-
- ut_ad(!(index->type & DICT_CLUSTERED));
-
- page = buf_frame_align(rec);
-
- if ((ut_dulint_cmp(page_get_max_trx_id(page), view->up_limit_id) >= 0)
- || recv_recovery_is_on()) {
-
- /* It may be that the record was inserted or modified by a
- transaction the view should not see: we have to look in the
- clustered index */
-
- return(TRUE);
- }
-
- return(FALSE);
-}
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 4e9e25844aa..4a1833a1a21 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -93,20 +93,23 @@ extern ulint srv_max_n_open_files;
extern ulint srv_max_dirty_pages_pct;
extern ulint srv_force_recovery;
-extern ulint srv_thread_concurrency;
+extern ulong srv_thread_concurrency;
extern ulint srv_max_n_threads;
extern lint srv_conc_n_threads;
-extern ibool srv_fast_shutdown;
-extern ibool srv_very_fast_shutdown; /* if this TRUE, do not flush the
+extern ulint srv_fast_shutdown; /* If this is 1, do not do a
+ purge and index buffer merge.
+ If this 2, do not even flush the
buffer pool to data files at the
- shutdown; we effectively 'crash'
- InnoDB */
+ shutdown: we effectively 'crash'
+ InnoDB (but lose no committed
+ transactions). */
extern ibool srv_innodb_status;
extern ibool srv_use_doublewrite_buf;
+extern ibool srv_use_checksums;
extern ibool srv_set_thread_priorities;
extern int srv_query_thread_priority;
@@ -131,7 +134,9 @@ extern ibool srv_print_innodb_table_monitor;
extern ibool srv_lock_timeout_and_monitor_active;
extern ibool srv_error_monitor_active;
-extern ulint srv_n_spin_wait_rounds;
+extern ulong srv_n_spin_wait_rounds;
+extern ulong srv_n_free_tickets_to_enter;
+extern ulong srv_thread_sleep_delay;
extern ulint srv_spin_wait_delay;
extern ibool srv_priority_boost;
@@ -183,6 +188,63 @@ i/o handler thread */
extern const char* srv_io_thread_op_info[];
extern const char* srv_io_thread_function[];
+/* the number of the log write requests done */
+extern ulint srv_log_write_requests;
+
+/* the number of physical writes to the log performed */
+extern ulint srv_log_writes;
+
+/* amount of data written to the log files in bytes */
+extern ulint srv_os_log_written;
+
+/* amount of writes being done to the log files */
+extern ulint srv_os_log_pending_writes;
+
+/* we increase this counter, when there we don't have enough space in the
+log buffer and have to flush it */
+extern ulint srv_log_waits;
+
+/* variable that counts amount of data read in total (in bytes) */
+extern ulint srv_data_read;
+
+/* here we count the amount of data written in total (in bytes) */
+extern ulint srv_data_written;
+
+/* this variable counts the amount of times, when the doublewrite buffer
+was flushed */
+extern ulint srv_dblwr_writes;
+
+/* here we store the number of pages that have been flushed to the
+doublewrite buffer */
+extern ulint srv_dblwr_pages_written;
+
+/* in this variable we store the number of write requests issued */
+extern ulint srv_buf_pool_write_requests;
+
+/* here we store the number of times when we had to wait for a free page
+in the buffer pool. It happens when the buffer pool is full and we need
+to make a flush, in order to be able to read or create a page. */
+extern ulint srv_buf_pool_wait_free;
+
+/* variable to count the number of pages that were written from the
+buffer pool to disk */
+extern ulint srv_buf_pool_flushed;
+
+/* variable to count the number of buffer pool reads that led to the
+reading of a disk page */
+extern ulint srv_buf_pool_reads;
+
+/* variable to count the number of sequential read-aheads were done */
+extern ulint srv_read_ahead_seq;
+
+/* variable to count the number of random read-aheads were done */
+extern ulint srv_read_ahead_rnd;
+
+/* In this structure we store status variables to be passed to MySQL */
+typedef struct export_var_struct export_struc;
+
+extern export_struc export_vars;
+
typedef struct srv_sys_struct srv_sys_t;
/* The server system */
@@ -233,6 +295,12 @@ srv_boot(void);
/*==========*/
/* out: DB_SUCCESS or error code */
/*************************************************************************
+Initializes the server. */
+
+void
+srv_init(void);
+/*==========*/
+/*************************************************************************
Frees the OS fast mutex created in srv_boot(). */
void
@@ -399,7 +467,12 @@ void
srv_printf_innodb_monitor(
/*======================*/
FILE* file); /* in: output stream */
+/************************************************************************
+Function to pass InnoDB status variables to MySQL */
+void
+srv_export_innodb_status(void);
+/*=====================*/
/* Types for the threads existing in the system. Threads of types 4 - 9
are called utility threads. Note that utility threads are mainly disk
@@ -425,6 +498,53 @@ typedef struct srv_slot_struct srv_slot_t;
/* Thread table is an array of slots */
typedef srv_slot_t srv_table_t;
+/* In this structure we store status variables to be passed to MySQL */
+struct export_var_struct{
+ ulint innodb_data_pending_reads;
+ ulint innodb_data_pending_writes;
+ ulint innodb_data_pending_fsyncs;
+ ulint innodb_data_fsyncs;
+ ulint innodb_data_read;
+ ulint innodb_data_writes;
+ ulint innodb_data_written;
+ ulint innodb_data_reads;
+ ulint innodb_buffer_pool_pages_total;
+ ulint innodb_buffer_pool_pages_data;
+ ulint innodb_buffer_pool_pages_dirty;
+ ulint innodb_buffer_pool_pages_misc;
+ ulint innodb_buffer_pool_pages_free;
+ ulint innodb_buffer_pool_pages_latched;
+ ulint innodb_buffer_pool_read_requests;
+ ulint innodb_buffer_pool_reads;
+ ulint innodb_buffer_pool_wait_free;
+ ulint innodb_buffer_pool_pages_flushed;
+ ulint innodb_buffer_pool_write_requests;
+ ulint innodb_buffer_pool_read_ahead_seq;
+ ulint innodb_buffer_pool_read_ahead_rnd;
+ ulint innodb_dblwr_pages_written;
+ ulint innodb_dblwr_writes;
+ ulint innodb_log_waits;
+ ulint innodb_log_write_requests;
+ ulint innodb_log_writes;
+ ulint innodb_os_log_written;
+ ulint innodb_os_log_fsyncs;
+ ulint innodb_os_log_pending_writes;
+ ulint innodb_os_log_pending_fsyncs;
+ ulint innodb_page_size;
+ ulint innodb_pages_created;
+ ulint innodb_pages_read;
+ ulint innodb_pages_written;
+ ulint innodb_row_lock_waits;
+ ulint innodb_row_lock_current_waits;
+ ib_longlong innodb_row_lock_time;
+ ulint innodb_row_lock_time_avg;
+ ulint innodb_row_lock_time_max;
+ ulint innodb_rows_read;
+ ulint innodb_rows_inserted;
+ ulint innodb_rows_updated;
+ ulint innodb_rows_deleted;
+};
+
/* The server system struct */
struct srv_sys_struct{
os_event_t operational; /* created threads must wait for the
@@ -433,6 +553,10 @@ struct srv_sys_struct{
srv_table_t* threads; /* server thread table */
UT_LIST_BASE_NODE_T(que_thr_t)
tasks; /* task queue */
+ dict_index_t* dummy_ind1; /* dummy index for old-style
+ supremum and infimum records */
+ dict_index_t* dummy_ind2; /* dummy index for new-style
+ supremum and infimum records */
};
extern ulint srv_n_threads_active[];
diff --git a/innobase/include/srv0start.h b/innobase/include/srv0start.h
index 8df0f97c4ff..d24f119c0b0 100644
--- a/innobase/include/srv0start.h
+++ b/innobase/include/srv0start.h
@@ -53,6 +53,16 @@ srv_parse_log_group_home_dirs(
error */
char* str, /* in: character string */
char*** log_group_home_dirs); /* out, own: log group home dirs */
+/*************************************************************************
+Adds a slash or a backslash to the end of a string if it is missing
+and the string is not empty. */
+
+char*
+srv_add_path_separator_if_needed(
+/*=============================*/
+ /* out: string which has the separator if the
+ string is not empty */
+ char* str); /* in: null-terminated character string */
/********************************************************************
Starts Innobase and creates a new database if database files
are not found and the user wants. Server parameters are
diff --git a/innobase/include/sync0rw.h b/innobase/include/sync0rw.h
index 9a988a03e92..911c8ac3f4a 100644
--- a/innobase/include/sync0rw.h
+++ b/innobase/include/sync0rw.h
@@ -61,8 +61,8 @@ Creates, or rather, initializes an rw-lock object in a specified memory
location (which must be appropriately aligned). The rw-lock is initialized
to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
is necessary only if the memory block containing it is freed. */
-
-#define rw_lock_create(L) rw_lock_create_func((L), __FILE__, __LINE__)
+#define rw_lock_create(L) rw_lock_create_func((L), __FILE__, __LINE__, #L)
+
/*=====================*/
/**********************************************************************
Creates, or rather, initializes an rw-lock object in a specified memory
@@ -75,7 +75,8 @@ rw_lock_create_func(
/*================*/
rw_lock_t* lock, /* in: pointer to memory */
const char* cfile_name, /* in: file name where created */
- ulint cline); /* in: file line where created */
+ ulint cline, /* in: file line where created */
+ const char* cmutex_name); /* in: mutex name */
/**********************************************************************
Calling this function is obligatory only if the memory buffer containing
the rw-lock is freed. Removes an rw-lock object from the global list. The
diff --git a/innobase/include/sync0sync.h b/innobase/include/sync0sync.h
index 8e0ec715b12..c798c047fa3 100644
--- a/innobase/include/sync0sync.h
+++ b/innobase/include/sync0sync.h
@@ -17,6 +17,10 @@ Created 9/5/1995 Heikki Tuuri
#include "os0sync.h"
#include "sync0arr.h"
+#ifndef UNIV_HOTBACKUP
+extern my_bool timed_mutexes;
+#endif /* UNIV_HOTBACKUP */
+
/**********************************************************************
Initializes the synchronization data structures. */
@@ -35,8 +39,7 @@ location (which must be appropriately aligned). The mutex is initialized
in the reset state. Explicit freeing of the mutex with mutex_free is
necessary only if the memory block containing it is freed. */
-
-#define mutex_create(M) mutex_create_func((M), __FILE__, __LINE__)
+#define mutex_create(M) mutex_create_func((M), __FILE__, __LINE__, #M)
/*===================*/
/**********************************************************************
Creates, or rather, initializes a mutex object in a specified memory
@@ -49,7 +52,8 @@ mutex_create_func(
/*==============*/
mutex_t* mutex, /* in: pointer to memory */
const char* cfile_name, /* in: file name where created */
- ulint cline); /* in: file line where created */
+ ulint cline, /* in: file line where created */
+ const char* cmutex_name); /* in: mutex name */
/**********************************************************************
Calling this function is obligatory only if the memory buffer containing
the mutex is freed. Removes a mutex object from the mutex list. The mutex
@@ -413,6 +417,8 @@ or row lock! */
/*------------------------------------- Insert buffer tree */
#define SYNC_IBUF_BITMAP_MUTEX 351
#define SYNC_IBUF_BITMAP 350
+/*------------------------------------- MySQL query cache mutex */
+/*------------------------------------- MySQL binlog mutex */
/*-------------------------------*/
#define SYNC_KERNEL 300
#define SYNC_REC_LOCK 299
@@ -471,6 +477,17 @@ struct mutex_struct {
const char* cfile_name;/* File name where mutex created */
ulint cline; /* Line where created */
ulint magic_n;
+#ifndef UNIV_HOTBACKUP
+ ulong count_using; /* count of times mutex used */
+ ulong count_spin_loop; /* count of spin loops */
+ ulong count_spin_rounds; /* count of spin rounds */
+ ulong count_os_wait; /* count of os_wait */
+ ulong count_os_yield; /* count of os_wait */
+ ulonglong lspent_time; /* mutex os_wait timer msec */
+ ulonglong lmax_spent_time; /* mutex os_wait timer msec */
+ const char* cmutex_name;/* mutex name */
+ ulint mutex_type;/* 0 - usual mutex 1 - rw_lock mutex */
+#endif /* !UNIV_HOTBACKUP */
};
#define MUTEX_MAGIC_N (ulint)979585
@@ -504,6 +521,13 @@ extern ibool sync_order_checks_on;
/* This variable is set to TRUE when sync_init is called */
extern ibool sync_initialized;
+/* Global list of database mutexes (not OS mutexes) created. */
+UT_LIST_BASE_NODE_T(mutex_t) mutex_list;
+
+/* Mutex protecting the mutex_list variable */
+mutex_t mutex_list_mutex;
+
+
#ifndef UNIV_NONINL
#include "sync0sync.ic"
#endif
diff --git a/innobase/include/sync0sync.ic b/innobase/include/sync0sync.ic
index aaf5e1fd9e9..b3fde61db5e 100644
--- a/innobase/include/sync0sync.ic
+++ b/innobase/include/sync0sync.ic
@@ -249,8 +249,13 @@ mutex_enter_func(
/* Note that we do not peek at the value of lock_word before trying
the atomic test_and_set; we could peek, and possibly save time. */
+
+#ifndef UNIV_HOTBACKUP
+ mutex->count_using++;
+#endif /* UNIV_HOTBACKUP */
- if (!mutex_test_and_set(mutex)) {
+ if (!mutex_test_and_set(mutex))
+ {
#ifdef UNIV_SYNC_DEBUG
mutex_set_debug_info(mutex, file_name, line);
#endif
@@ -258,4 +263,5 @@ mutex_enter_func(
}
mutex_spin_wait(mutex, file_name, line);
+
}
diff --git a/innobase/include/trx0rec.h b/innobase/include/trx0rec.h
index 9d7f41cd94e..4387ce1a61e 100644
--- a/innobase/include/trx0rec.h
+++ b/innobase/include/trx0rec.h
@@ -246,6 +246,7 @@ trx_undo_prev_version_build(
index_rec page and purge_view */
rec_t* rec, /* in: version of a clustered index record */
dict_index_t* index, /* in: clustered index */
+ ulint* offsets,/* in: rec_get_offsets(rec, index) */
mem_heap_t* heap, /* in: memory heap from which the memory
needed is allocated */
rec_t** old_vers);/* out, own: previous version, or NULL if
diff --git a/innobase/include/trx0roll.h b/innobase/include/trx0roll.h
index 6004551f456..944142a299d 100644
--- a/innobase/include/trx0roll.h
+++ b/innobase/include/trx0roll.h
@@ -104,11 +104,20 @@ trx_rollback(
/***********************************************************************
Rollback or clean up transactions which have no user session. If the
transaction already was committed, then we clean up a possible insert
-undo log. If the transaction was not yet committed, then we roll it back. */
+undo log. If the transaction was not yet committed, then we roll it back.
+Note: this is done in a background thread. */
-void
-trx_rollback_or_clean_all_without_sess(void);
-/*========================================*/
+#ifndef __WIN__
+void*
+#else
+ulint
+#endif
+trx_rollback_or_clean_all_without_sess(
+/*===================================*/
+ /* out: a dummy parameter */
+ void* arg __attribute__((unused)));
+ /* in: a dummy parameter required by
+ os_thread_create */
/********************************************************************
Finishes a transaction rollback. */
@@ -216,6 +225,21 @@ trx_savepoint_for_mysql(
position corresponding to this
connection at the time of the
savepoint */
+
+/***********************************************************************
+Releases a named savepoint. Savepoints which
+were set after this savepoint are deleted. */
+
+ulint
+trx_release_savepoint_for_mysql(
+/*================================*/
+ /* out: if no savepoint
+ of the name found then
+ DB_NO_SAVEPOINT,
+ otherwise DB_SUCCESS */
+ trx_t* trx, /* in: transaction handle */
+ const char* savepoint_name); /* in: savepoint name */
+
/***********************************************************************
Frees savepoint structs. */
diff --git a/innobase/include/trx0sys.ic b/innobase/include/trx0sys.ic
index 8f455e554ea..24610bef827 100644
--- a/innobase/include/trx0sys.ic
+++ b/innobase/include/trx0sys.ic
@@ -315,7 +315,7 @@ trx_is_active(
}
if (ut_dulint_cmp(trx_id, trx_sys->max_trx_id) >= 0) {
-
+
/* There must be corruption: we return TRUE because this
function is only called by lock_clust_rec_some_has_impl()
and row_vers_impl_x_locked_off_kernel() and they have
@@ -325,8 +325,9 @@ trx_is_active(
}
trx = trx_get_on_id(trx_id);
- if (trx && (trx->conc_state == TRX_ACTIVE)) {
-
+ if (trx && (trx->conc_state == TRX_ACTIVE ||
+ trx->conc_state == TRX_PREPARED)) {
+
return(TRUE);
}
diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h
index 905b25447a8..d46613c3a68 100644
--- a/innobase/include/trx0trx.h
+++ b/innobase/include/trx0trx.h
@@ -16,6 +16,7 @@ Created 3/26/1996 Heikki Tuuri
#include "que0types.h"
#include "mem0mem.h"
#include "read0types.h"
+#include "trx0xa.h"
extern ulint trx_n_mysql_transactions;
@@ -157,6 +158,32 @@ trx_commit_for_mysql(
/* out: 0 or error number */
trx_t* trx); /* in: trx handle */
/**************************************************************************
+Does the transaction prepare for MySQL. */
+
+ulint
+trx_prepare_for_mysql(
+/*=================*/
+ /* out: 0 or error number */
+ trx_t* trx); /* in: trx handle */
+/**************************************************************************
+This function is used to find number of prepared transactions and
+their transaction objects for a recovery. */
+
+int
+trx_recover_for_mysql(
+/*==================*/
+ /* out: number of prepared transactions */
+ XID* xid_list, /* in/out: prepared transactions */
+ ulint len); /* in: number of slots in xid_list */
+/***********************************************************************
+This function is used to commit one X/Open XA distributed transaction
+which is in the prepared state */
+trx_t *
+trx_get_trx_by_xid(
+/*===============*/
+ /* out: trx or NULL */
+ XID* xid); /* in: X/Open XA transaction identification */
+/**************************************************************************
If required, flushes the log to disk if we called trx_commit_for_mysql()
with trx->flush_log_later == TRUE. */
@@ -339,6 +366,14 @@ struct trx_struct{
if we can use the insert buffer for
them, we set this FALSE */
dulint id; /* transaction id */
+ XID xid; /* X/Open XA transaction
+ identification to identify a
+ transaction branch */
+ ibool support_xa; /* normally we do the XA two-phase
+ commit steps, but by setting this to
+ FALSE, one can save CPU time and about
+ 150 bytes in the undo log size as then
+ we skip XA steps */
dulint no; /* transaction serialization number ==
max trx id when the transaction is
moved to COMMITTED_IN_MEMORY state */
@@ -355,12 +390,17 @@ struct trx_struct{
dulint commit_lsn; /* lsn at the time of the commit */
ibool dict_operation; /* TRUE if the trx is used to create
a table, create an index, or drop a
- table */
+ table. This is a hint that the table
+ may need to be dropped in crash
+ recovery. */
dulint table_id; /* table id if the preceding field is
TRUE */
/*------------------------------*/
- void* mysql_thd; /* MySQL thread handle corresponding
- to this trx, or NULL */
+ int active_trans; /* 1 - if a transaction in MySQL
+ is active. 2 - if prepare_commit_mutex
+ was taken */
+ void* mysql_thd; /* MySQL thread handle corresponding
+ to this trx, or NULL */
char** mysql_query_str;/* pointer to the field in mysqld_thd
which contains the pointer to the
current SQL query string */
@@ -442,9 +482,15 @@ 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 */
UT_LIST_NODE_T(trx_t)
trx_list; /* list of transactions */
UT_LIST_NODE_T(trx_t)
@@ -560,6 +606,7 @@ struct trx_struct{
#define TRX_NOT_STARTED 1
#define TRX_ACTIVE 2
#define TRX_COMMITTED_IN_MEMORY 3
+#define TRX_PREPARED 4 /* Support for 2PC/XA */
/* Transaction execution states when trx state is TRX_ACTIVE */
#define TRX_QUE_RUNNING 1 /* transaction is running */
diff --git a/innobase/include/trx0undo.h b/innobase/include/trx0undo.h
index 20002076cc3..bd7337e4f90 100644
--- a/innobase/include/trx0undo.h
+++ b/innobase/include/trx0undo.h
@@ -14,6 +14,7 @@ Created 3/26/1996 Heikki Tuuri
#include "mtr0mtr.h"
#include "trx0sys.h"
#include "page0types.h"
+#include "trx0xa.h"
/***************************************************************************
Builds a roll pointer dulint. */
@@ -36,7 +37,7 @@ trx_undo_decode_roll_ptr(
ibool* is_insert, /* out: TRUE if insert undo log */
ulint* rseg_id, /* out: rollback segment id */
ulint* page_no, /* out: page number */
- ulint* offset); /* out: offset of the undo entry within page */
+ ulint* offset); /* out: offset of the undo entry within page */
/***************************************************************************
Returns TRUE if the roll pointer is of the insert type. */
UNIV_INLINE
@@ -239,6 +240,18 @@ trx_undo_set_state_at_finish(
trx_t* trx, /* in: transaction */
trx_undo_t* undo, /* in: undo log memory copy */
mtr_t* mtr); /* in: mtr */
+/**********************************************************************
+Sets the state of the undo log segment at a transaction prepare. */
+
+page_t*
+trx_undo_set_state_at_prepare(
+/*==========================*/
+ /* out: undo log segment header page,
+ x-latched */
+ trx_t* trx, /* in: transaction */
+ trx_undo_t* undo, /* in: undo log memory copy */
+ mtr_t* mtr); /* in: mtr */
+
/**************************************************************************
Adds the update undo log header as the first in the history list, and
frees the memory object, or puts it to the list of cached update undo log
@@ -295,7 +308,6 @@ trx_undo_parse_discard_latest(
page_t* page, /* in: page or NULL */
mtr_t* mtr); /* in: mtr or NULL */
-
/* Types of an undo log segment */
#define TRX_UNDO_INSERT 1 /* contains undo entries for inserts */
#define TRX_UNDO_UPDATE 2 /* contains undo entries for updates
@@ -310,6 +322,8 @@ trx_undo_parse_discard_latest(
#define TRX_UNDO_TO_PURGE 4 /* update undo segment will not be
reused: it can be freed in purge when
all undo data in it is removed */
+#define TRX_UNDO_PREPARED 5 /* contains an undo log of an
+ prepared transaction */
/* Transaction undo log memory object; this is protected by the undo_mutex
in the corresponding transaction object */
@@ -332,6 +346,8 @@ struct trx_undo_struct{
field */
dulint trx_id; /* id of the trx assigned to the undo
log */
+ XID xid; /* X/Open XA transaction
+ identification */
ibool dict_operation; /* TRUE if a dict operation trx */
dulint table_id; /* if a dict operation, then the table
id */
@@ -386,7 +402,8 @@ struct trx_undo_struct{
#define TRX_UNDO_PAGE_HDR_SIZE (6 + FLST_NODE_SIZE)
/* An update undo segment with just one page can be reused if it has
-< this number bytes used */
+< this number bytes used; we must leave space at least for one new undo
+log header on the page */
#define TRX_UNDO_PAGE_REUSE_LIMIT (3 * UNIV_PAGE_SIZE / 4)
@@ -436,7 +453,10 @@ page of an update undo log segment. */
log start, and therefore this is not
necessarily the same as this log
header end offset */
-#define TRX_UNDO_DICT_OPERATION 20 /* TRUE if the transaction is a table
+#define TRX_UNDO_XID_EXISTS 20 /* TRUE if undo log header includes
+ X/Open XA transaction identification
+ XID */
+#define TRX_UNDO_DICT_TRANS 21 /* TRUE if the transaction is a table
create, index create, or drop
transaction: in recovery
the transaction cannot be rolled back
@@ -452,7 +472,25 @@ page of an update undo log segment. */
#define TRX_UNDO_HISTORY_NODE 34 /* If the log is put to the history
list, the file list node is here */
/*-------------------------------------------------------------*/
-#define TRX_UNDO_LOG_HDR_SIZE (34 + FLST_NODE_SIZE)
+#define TRX_UNDO_LOG_OLD_HDR_SIZE (34 + FLST_NODE_SIZE)
+
+/* Note: the writing of the undo log old header is coded by a log record
+MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE. The appending of an XID to the
+header is logged separately. In this sense, the XID is not really a member
+of the undo log header. TODO: do not append the XID to the log header if XA
+is not needed by the user. The XID wastes about 150 bytes of space in every
+undo log. In the history list we may have millions of undo logs, which means
+quite a large overhead. */
+
+/* X/Open XA Transaction Identification (XID) */
+
+#define TRX_UNDO_XA_FORMAT (TRX_UNDO_LOG_OLD_HDR_SIZE)
+#define TRX_UNDO_XA_TRID_LEN (TRX_UNDO_XA_FORMAT + 4)
+#define TRX_UNDO_XA_BQUAL_LEN (TRX_UNDO_XA_TRID_LEN + 4)
+#define TRX_UNDO_XA_XID (TRX_UNDO_XA_BQUAL_LEN + 4)
+/*--------------------------------------------------------------*/
+#define TRX_UNDO_LOG_XA_HDR_SIZE (TRX_UNDO_XA_XID + XIDDATASIZE)
+ /* Total size of the header with the XA XID */
#ifndef UNIV_NONINL
#include "trx0undo.ic"
diff --git a/innobase/include/trx0xa.h b/innobase/include/trx0xa.h
new file mode 100644
index 00000000000..34b7a2f95a8
--- /dev/null
+++ b/innobase/include/trx0xa.h
@@ -0,0 +1,182 @@
+/*
+ * Start of xa.h header
+ *
+ * Define a symbol to prevent multiple inclusions of this header file
+ */
+#ifndef XA_H
+#define XA_H
+
+/*
+ * Transaction branch identification: XID and NULLXID:
+ */
+#ifndef XIDDATASIZE
+
+#define XIDDATASIZE 128 /* size in bytes */
+#define MAXGTRIDSIZE 64 /* maximum size in bytes of gtrid */
+#define MAXBQUALSIZE 64 /* maximum size in bytes of bqual */
+
+struct xid_t {
+ long formatID; /* format identifier */
+ long gtrid_length; /* value from 1 through 64 */
+ long bqual_length; /* value from 1 through 64 */
+ char data[XIDDATASIZE];
+};
+typedef struct xid_t XID;
+#endif
+/*
+ * A value of -1 in formatID means that the XID is null.
+ */
+
+
+#ifdef NOTDEFINED
+/* Let us comment this out to remove compiler errors!!!!!!!!!!!! */
+
+/*
+ * Declarations of routines by which RMs call TMs:
+ */
+extern int ax_reg __P((int, XID *, long));
+extern int ax_unreg __P((int, long));
+
+/*
+ * XA Switch Data Structure
+ */
+#define RMNAMESZ 32 /* length of resource manager name, */
+ /* including the null terminator */
+#define MAXINFOSIZE 256 /* maximum size in bytes of xa_info */
+ /* strings, including the null
+ terminator */
+
+
+struct xa_switch_t {
+ char name[RMNAMESZ]; /* name of resource manager */
+ long flags; /* resource manager specific options */
+ long version; /* must be 0 */
+ int (*xa_open_entry) /* xa_open function pointer */
+ __P((char *, int, long));
+ int (*xa_close_entry) /* xa_close function pointer */
+ __P((char *, int, long));
+ int (*xa_start_entry) /* xa_start function pointer */
+ __P((XID *, int, long));
+ int (*xa_end_entry) /* xa_end function pointer */
+ __P((XID *, int, long));
+ int (*xa_rollback_entry) /* xa_rollback function pointer */
+ __P((XID *, int, long));
+ int (*xa_prepare_entry) /* xa_prepare function pointer */
+ __P((XID *, int, long));
+ int (*xa_commit_entry) /* xa_commit function pointer */
+ __P((XID *, int, long));
+ int (*xa_recover_entry) /* xa_recover function pointer */
+ __P((XID *, long, int, long));
+ int (*xa_forget_entry) /* xa_forget function pointer */
+ __P((XID *, int, long));
+ int (*xa_complete_entry) /* xa_complete function pointer */
+ __P((int *, int *, int, long));
+};
+#endif /* NOTDEFINED */
+
+
+/*
+ * Flag definitions for the RM switch
+ */
+#define TMNOFLAGS 0x00000000L /* no resource manager features
+ selected */
+#define TMREGISTER 0x00000001L /* resource manager dynamically
+ registers */
+#define TMNOMIGRATE 0x00000002L /* resource manager does not support
+ association migration */
+#define TMUSEASYNC 0x00000004L /* resource manager supports
+ asynchronous operations */
+/*
+ * Flag definitions for xa_ and ax_ routines
+ */
+/* use TMNOFLAGGS, defined above, when not specifying other flags */
+#define TMASYNC 0x80000000L /* perform routine asynchronously */
+#define TMONEPHASE 0x40000000L /* caller is using one-phase commit
+ optimisation */
+#define TMFAIL 0x20000000L /* dissociates caller and marks
+ transaction branch rollback-only */
+#define TMNOWAIT 0x10000000L /* return if blocking condition
+ exists */
+#define TMRESUME 0x08000000L /* caller is resuming association with
+ suspended transaction branch */
+#define TMSUCCESS 0x04000000L /* dissociate caller from transaction
+ branch */
+#define TMSUSPEND 0x02000000L /* caller is suspending, not ending,
+ association */
+#define TMSTARTRSCAN 0x01000000L /* start a recovery scan */
+#define TMENDRSCAN 0x00800000L /* end a recovery scan */
+#define TMMULTIPLE 0x00400000L /* wait for any asynchronous
+ operation */
+#define TMJOIN 0x00200000L /* caller is joining existing
+ transaction branch */
+#define TMMIGRATE 0x00100000L /* caller intends to perform
+ migration */
+
+/*
+ * ax_() return codes (transaction manager reports to resource manager)
+ */
+#define TM_JOIN 2 /* caller is joining existing
+ transaction branch */
+#define TM_RESUME 1 /* caller is resuming association with
+ suspended transaction branch */
+#define TM_OK 0 /* normal execution */
+#define TMER_TMERR -1 /* an error occurred in the transaction
+ manager */
+#define TMER_INVAL -2 /* invalid arguments were given */
+#define TMER_PROTO -3 /* routine invoked in an improper
+ context */
+
+/*
+ * xa_() return codes (resource manager reports to transaction manager)
+ */
+#define XA_RBBASE 100 /* The inclusive lower bound of the
+ rollback codes */
+#define XA_RBROLLBACK XA_RBBASE /* The rollback was caused by an
+ unspecified reason */
+#define XA_RBCOMMFAIL XA_RBBASE+1 /* The rollback was caused by a
+ communication failure */
+#define XA_RBDEADLOCK XA_RBBASE+2 /* A deadlock was detected */
+#define XA_RBINTEGRITY XA_RBBASE+3 /* A condition that violates the
+ integrity of the resources was
+ detected */
+#define XA_RBOTHER XA_RBBASE+4 /* The resource manager rolled back the
+ transaction branch for a reason not
+ on this list */
+#define XA_RBPROTO XA_RBBASE+5 /* A protocol error occurred in the
+ resource manager */
+#define XA_RBTIMEOUT XA_RBBASE+6 /* A transaction branch took too long */
+#define XA_RBTRANSIENT XA_RBBASE+7 /* May retry the transaction branch */
+#define XA_RBEND XA_RBTRANSIENT /* The inclusive upper bound of the
+ rollback codes */
+#define XA_NOMIGRATE 9 /* resumption must occur where
+ suspension occurred */
+#define XA_HEURHAZ 8 /* the transaction branch may have
+ been heuristically completed */
+#define XA_HEURCOM 7 /* the transaction branch has been
+ heuristically committed */
+#define XA_HEURRB 6 /* the transaction branch has been
+ heuristically rolled back */
+#define XA_HEURMIX 5 /* the transaction branch has been
+ heuristically committed and rolled
+ back */
+#define XA_RETRY 4 /* routine returned with no effect and
+ may be re-issued */
+#define XA_RDONLY 3 /* the transaction branch was read-only
+ and has been committed */
+#define XA_OK 0 /* normal execution */
+#define XAER_ASYNC -2 /* asynchronous operation already
+ outstanding */
+#define XAER_RMERR -3 /* a resource manager error occurred in
+ the transaction branch */
+#define XAER_NOTA -4 /* the XID is not valid */
+#define XAER_INVAL -5 /* invalid arguments were given */
+#define XAER_PROTO -6 /* routine invoked in an improper
+ context */
+#define XAER_RMFAIL -7 /* resource manager unavailable */
+#define XAER_DUPID -8 /* the XID already exists */
+#define XAER_OUTSIDE -9 /* resource manager doing work outside
+ transaction */
+#endif /* ifndef XA_H */
+/*
+ * End of xa.h header
+ */
diff --git a/innobase/include/univ.i b/innobase/include/univ.i
index 625978ffc38..8158c198e21 100644
--- a/innobase/include/univ.i
+++ b/innobase/include/univ.i
@@ -88,6 +88,7 @@ memory is read outside the allocated blocks. */
#define UNIV_SEARCH_DEBUG
#define UNIV_SYNC_PERF_STAT
#define UNIV_SEARCH_PERF_STAT
+#define UNIV_SRV_PRINT_LATCH_WAITS;
*/
#define UNIV_LIGHT_MEM_DEBUG
diff --git a/innobase/include/ut0byte.h b/innobase/include/ut0byte.h
index a62c2e2e318..22d488abeaf 100644
--- a/innobase/include/ut0byte.h
+++ b/innobase/include/ut0byte.h
@@ -208,7 +208,20 @@ ut_align_down(
/*==========*/
/* out: aligned pointer */
void* ptr, /* in: pointer */
- ulint align_no); /* in: align by this number */
+ ulint align_no) /* in: align by this number */
+ __attribute__((const));
+/*************************************************************
+The following function computes the offset of a pointer from the nearest
+aligned address. */
+UNIV_INLINE
+ulint
+ut_align_offset(
+/*==========*/
+ /* out: distance from aligned
+ pointer */
+ const void* ptr, /* in: pointer */
+ ulint align_no) /* in: align by this number */
+ __attribute__((const));
/*********************************************************************
Gets the nth bit of a ulint. */
UNIV_INLINE
diff --git a/innobase/include/ut0byte.ic b/innobase/include/ut0byte.ic
index 5a70dcf12a8..e141de3aa3f 100644
--- a/innobase/include/ut0byte.ic
+++ b/innobase/include/ut0byte.ic
@@ -335,6 +335,27 @@ ut_align_down(
return((void*)((((ulint)ptr)) & ~(align_no - 1)));
}
+/*************************************************************
+The following function computes the offset of a pointer from the nearest
+aligned address. */
+UNIV_INLINE
+ulint
+ut_align_offset(
+/*============*/
+ /* out: distance from
+ aligned pointer */
+ const void* ptr, /* in: pointer */
+ ulint align_no) /* in: align by this number */
+{
+ ut_ad(align_no > 0);
+ ut_ad(((align_no - 1) & align_no) == 0);
+ ut_ad(ptr);
+
+ ut_ad(sizeof(void*) == sizeof(ulint));
+
+ return(((ulint)ptr) & (align_no - 1));
+}
+
/*********************************************************************
Gets the nth bit of a ulint. */
UNIV_INLINE
diff --git a/innobase/include/ut0ut.h b/innobase/include/ut0ut.h
index dee8785c9e7..8938957cd12 100644
--- a/innobase/include/ut0ut.h
+++ b/innobase/include/ut0ut.h
@@ -139,6 +139,14 @@ ib_time_t
ut_time(void);
/*=========*/
/**************************************************************
+Returns system time. */
+
+void
+ut_usectime(
+/*========*/
+ ulint* sec, /* out: seconds since the Epoch */
+ ulint* ms); /* out: microseconds since the Epoch+*sec */
+/**************************************************************
Returns the difference of two times in seconds. */
double
diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c
index 29a274261f8..512f487b3f5 100644
--- a/innobase/lock/lock0lock.c
+++ b/innobase/lock/lock0lock.c
@@ -424,12 +424,15 @@ lock_check_trx_id_sanity(
/* out: TRUE if ok */
dulint trx_id, /* in: trx id */
rec_t* rec, /* in: user record */
- dict_index_t* index, /* in: clustered index */
+ dict_index_t* index, /* in: index */
+ const ulint* offsets, /* in: rec_get_offsets(rec, index) */
ibool has_kernel_mutex)/* in: TRUE if the caller owns the
kernel mutex */
{
ibool is_ok = TRUE;
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
if (!has_kernel_mutex) {
mutex_enter(&kernel_mutex);
}
@@ -442,7 +445,7 @@ lock_check_trx_id_sanity(
fputs(" InnoDB: Error: transaction id associated"
" with record\n",
stderr);
- rec_print(stderr, rec);
+ rec_print_new(stderr, rec, offsets);
fputs("InnoDB: in ", stderr);
dict_index_name_print(stderr, NULL, index);
fprintf(stderr, "\n"
@@ -474,18 +477,20 @@ lock_clust_rec_cons_read_sees(
rec_t* rec, /* in: user record which should be read or
passed over by a read cursor */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
read_view_t* view) /* in: consistent read view */
{
dulint trx_id;
ut_ad(index->type & DICT_CLUSTERED);
ut_ad(page_rec_is_user_rec(rec));
+ ut_ad(rec_offs_validate(rec, index, offsets));
/* NOTE that we call this function while holding the search
system latch. To obey the latching order we must NOT reserve the
kernel mutex here! */
- trx_id = row_get_rec_trx_id(rec, index);
+ trx_id = row_get_rec_trx_id(rec, index, offsets);
if (read_view_sees_trx_id(view, trx_id)) {
@@ -689,7 +694,7 @@ lock_is_table_exclusive(
trx_t* trx) /* in: transaction */
{
lock_t* lock;
- bool ok = FALSE;
+ ibool ok = FALSE;
ut_ad(table && trx);
@@ -1256,6 +1261,7 @@ 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
@@ -1271,7 +1277,7 @@ lock_rec_get_next(
return(NULL);
}
- if (lock_rec_get_nth_bit(lock, rec_get_heap_no(rec))) {
+ if (lock_rec_get_nth_bit(lock, rec_get_heap_no(rec, comp))) {
return(lock);
}
@@ -1288,15 +1294,17 @@ 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))) {
+ if (lock_rec_get_nth_bit(lock, rec_get_heap_no(rec, comp))) {
break;
}
@@ -1463,6 +1471,7 @@ 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;
@@ -1492,7 +1501,7 @@ lock_rec_has_expl(
return(lock);
}
- lock = lock_rec_get_next(rec, lock);
+ lock = lock_rec_get_next(rec, comp, lock);
}
return(NULL);
@@ -1511,6 +1520,7 @@ 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 */
{
@@ -1535,7 +1545,7 @@ lock_rec_other_has_expl_req(
return(lock);
}
- lock = lock_rec_get_next(rec, lock);
+ lock = lock_rec_get_next(rec, comp, lock);
}
return(NULL);
@@ -1556,12 +1566,13 @@ 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,
@@ -1570,7 +1581,7 @@ lock_rec_other_has_conflicting(
return(lock);
}
- lock = lock_rec_get_next(rec, lock);
+ lock = lock_rec_get_next(rec, comp, lock);
}
return(NULL);
@@ -1596,8 +1607,7 @@ lock_rec_find_similar_on_page(
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
- heap_no = rec_get_heap_no(rec);
-
+ heap_no = rec_get_heap_no(rec, page_is_comp(buf_frame_align(rec)));
lock = lock_rec_get_first_on_page(rec);
while (lock != NULL) {
@@ -1624,7 +1634,8 @@ lock_sec_rec_some_has_impl_off_kernel(
/* out: transaction which has the x-lock, or
NULL */
rec_t* rec, /* in: user record */
- dict_index_t* index) /* in: secondary index */
+ dict_index_t* index, /* in: secondary index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
page_t* page;
@@ -1633,6 +1644,7 @@ lock_sec_rec_some_has_impl_off_kernel(
#endif /* UNIV_SYNC_DEBUG */
ut_ad(!(index->type & DICT_CLUSTERED));
ut_ad(page_rec_is_user_rec(rec));
+ ut_ad(rec_offs_validate(rec, index, offsets));
page = buf_frame_align(rec);
@@ -1652,8 +1664,8 @@ lock_sec_rec_some_has_impl_off_kernel(
/* Ok, in this case it is possible that some transaction has an
implicit x-lock. We have to look in the clustered index. */
- if (!lock_check_trx_id_sanity(page_get_max_trx_id(page), rec, index,
- TRUE)) {
+ if (!lock_check_trx_id_sanity(page_get_max_trx_id(page),
+ rec, index, offsets, TRUE)) {
buf_page_print(page);
/* The page is corrupt: try to avoid a crash by returning
@@ -1661,7 +1673,7 @@ lock_sec_rec_some_has_impl_off_kernel(
return(NULL);
}
- return(row_vers_impl_x_locked_off_kernel(rec, index));
+ return(row_vers_impl_x_locked_off_kernel(rec, index, offsets));
}
/*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/
@@ -1695,7 +1707,7 @@ lock_rec_create(
page = buf_frame_align(rec);
space = buf_frame_get_space_id(page);
page_no = buf_frame_get_page_no(page);
- heap_no = rec_get_heap_no(rec);
+ heap_no = rec_get_heap_no(rec, page_is_comp(page));
/* If rec is the supremum record, then we reset the gap and
LOCK_REC_NOT_GAP bits, as all locks on the supremum are
@@ -1708,8 +1720,7 @@ lock_rec_create(
}
/* Make lock bitmap bigger by a safety margin */
- n_bits = page_header_get_field(page, PAGE_N_HEAP)
- + LOCK_PAGE_BITMAP_MARGIN;
+ n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN;
n_bytes = 1 + n_bits / 8;
lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes);
@@ -1740,6 +1751,9 @@ lock_rec_create(
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;
+
if (type_mode & LOCK_WAIT) {
lock_set_lock_and_trx_wait(lock, trx);
@@ -1811,7 +1825,8 @@ lock_rec_enqueue_waiting(
if (lock_deadlock_occurs(lock, trx)) {
lock_reset_lock_and_trx_wait(lock);
- lock_rec_reset_nth_bit(lock, rec_get_heap_no(rec));
+ lock_rec_reset_nth_bit(lock, rec_get_heap_no(rec,
+ page_is_comp(buf_frame_align(rec))));
return(DB_DEADLOCK);
}
@@ -1861,7 +1876,7 @@ lock_rec_add_to_queue(
lock_t* lock;
lock_t* similar_lock = NULL;
ulint heap_no;
- page_t* page;
+ page_t* page = buf_frame_align(rec);
ibool somebody_waits = FALSE;
#ifdef UNIV_SYNC_DEBUG
@@ -1869,15 +1884,15 @@ lock_rec_add_to_queue(
#endif /* UNIV_SYNC_DEBUG */
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, trx));
+ || !lock_rec_other_has_expl_req(LOCK_X, 0, LOCK_WAIT,
+ rec, page_is_comp(page), 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, trx));
+ || !lock_rec_other_has_expl_req(LOCK_S, 0, LOCK_WAIT,
+ rec, page_is_comp(page), trx));
type_mode = type_mode | LOCK_REC;
- page = buf_frame_align(rec);
-
/* If rec is the supremum record, then we can reset the gap bit, as
all locks on the supremum are automatically of the gap type, and we
try to avoid unnecessary memory consumption of a new record lock
@@ -1894,7 +1909,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);
+ heap_no = rec_get_heap_no(rec, page_is_comp(page));
lock = lock_rec_get_first_on_page(rec);
while (lock != NULL) {
@@ -1914,6 +1929,15 @@ 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);
@@ -1945,6 +1969,7 @@ lock_rec_lock_fast(
{
lock_t* lock;
ulint heap_no;
+ trx_t* trx;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
@@ -1959,13 +1984,16 @@ 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);
+ heap_no = rec_get_heap_no(rec, page_is_comp(buf_frame_align(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, thr_get_trx(thr));
+ lock_rec_create(mode, rec, index, trx);
}
return(TRUE);
@@ -1976,13 +2004,23 @@ lock_rec_lock_fast(
return(FALSE);
}
- if (lock->trx != thr_get_trx(thr)
+ if (lock->trx != trx
|| lock->type_mode != (mode | LOCK_REC)
|| lock_rec_get_n_bits(lock) <= heap_no) {
return(FALSE);
}
if (!impl) {
+
+ /* 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;
+ }
+
lock_rec_set_nth_bit(lock, heap_no);
}
@@ -2027,7 +2065,8 @@ lock_rec_lock_slow(
trx = thr_get_trx(thr);
- if (lock_rec_has_expl(mode, rec, trx)) {
+ if (lock_rec_has_expl(mode, rec,
+ page_is_comp(buf_frame_align(rec)), trx)) {
/* The trx already has a strong enough lock on rec: do
nothing */
@@ -2168,7 +2207,8 @@ 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) {
+ } 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);
}
@@ -2343,12 +2383,14 @@ 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 */
- heap_no = rec_get_heap_no(rec);
+ comp = page_is_comp(buf_frame_align(rec));
+ heap_no = rec_get_heap_no(rec, comp);
lock = lock_rec_get_first(rec);
@@ -2359,7 +2401,7 @@ lock_rec_reset_and_release_wait(
lock_rec_reset_nth_bit(lock, heap_no);
}
- lock = lock_rec_get_next(rec, lock);
+ lock = lock_rec_get_next(rec, comp, lock);
}
}
@@ -2377,12 +2419,13 @@ 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));
while (lock != NULL) {
if (!lock_rec_get_insert_intention(lock)) {
@@ -2392,7 +2435,7 @@ lock_rec_inherit_to_gap(
heir, lock->index, lock->trx);
}
- lock = lock_rec_get_next(rec, lock);
+ lock = lock_rec_get_next(rec, comp, lock);
}
}
@@ -2409,12 +2452,13 @@ 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)
@@ -2426,7 +2470,7 @@ lock_rec_inherit_to_gap_if_gap_lock(
heir, lock->index, lock->trx);
}
- lock = lock_rec_get_next(rec, lock);
+ lock = lock_rec_get_next(rec, comp, lock);
}
}
@@ -2439,7 +2483,8 @@ 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 */
+ rec_t* donator, /* in: record which gives locks */
+ ibool comp) /* in: TRUE=compact page format */
{
lock_t* lock;
ulint heap_no;
@@ -2449,7 +2494,7 @@ lock_rec_move(
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
- heap_no = rec_get_heap_no(donator);
+ heap_no = rec_get_heap_no(donator, comp);
lock = lock_rec_get_first(donator);
@@ -2469,7 +2514,7 @@ lock_rec_move(
lock_rec_add_to_queue(type_mode, receiver, lock->index,
lock->trx);
- lock = lock_rec_get_next(donator, lock);
+ lock = lock_rec_get_next(donator, comp, lock);
}
ut_ad(lock_rec_get_first(donator) == NULL);
@@ -2495,6 +2540,7 @@ lock_move_reorganize_page(
UT_LIST_BASE_NODE_T(lock_t) old_locks;
mem_heap_t* heap = NULL;
rec_t* sup;
+ ibool comp;
lock_mutex_enter_kernel();
@@ -2535,6 +2581,9 @@ lock_move_reorganize_page(
lock = UT_LIST_GET_FIRST(old_locks);
+ comp = page_is_comp(page);
+ ut_ad(comp == page_is_comp(old_page));
+
while (lock) {
/* NOTE: we copy also the locks set on the infimum and
supremum of the page; the infimum may carry locks if an
@@ -2546,12 +2595,12 @@ lock_move_reorganize_page(
/* Set locks according to old locks */
for (;;) {
- ut_ad(0 == ut_memcmp(page_cur_get_rec(&cur1),
+ ut_ad(comp || 0 == ut_memcmp(page_cur_get_rec(&cur1),
page_cur_get_rec(&cur2),
- rec_get_data_size(
+ rec_get_data_size_old(
page_cur_get_rec(&cur2))));
-
- old_heap_no = rec_get_heap_no(page_cur_get_rec(&cur2));
+ old_heap_no = rec_get_heap_no(page_cur_get_rec(&cur2),
+ comp);
if (lock_rec_get_nth_bit(lock, old_heap_no)) {
@@ -2610,6 +2659,7 @@ lock_move_rec_list_end(
ulint heap_no;
rec_t* sup;
ulint type_mode;
+ ibool comp;
lock_mutex_enter_kernel();
@@ -2623,6 +2673,8 @@ lock_move_rec_list_end(
lock = lock_rec_get_first_on_page(page);
+ comp = page_is_comp(page);
+
while (lock != NULL) {
page_cur_position(rec, &cur1);
@@ -2638,13 +2690,12 @@ lock_move_rec_list_end(
reset the lock bits on the old */
while (page_cur_get_rec(&cur1) != sup) {
-
- ut_ad(0 == ut_memcmp(page_cur_get_rec(&cur1),
+ ut_ad(comp || 0 == ut_memcmp(page_cur_get_rec(&cur1),
page_cur_get_rec(&cur2),
- rec_get_data_size(
+ rec_get_data_size_old(
page_cur_get_rec(&cur2))));
-
- heap_no = rec_get_heap_no(page_cur_get_rec(&cur1));
+ heap_no = rec_get_heap_no(page_cur_get_rec(&cur1),
+ comp);
if (lock_rec_get_nth_bit(lock, heap_no)) {
type_mode = lock->type_mode;
@@ -2694,12 +2745,15 @@ lock_move_rec_list_start(
page_cur_t cur2;
ulint heap_no;
ulint type_mode;
+ ibool comp;
ut_a(new_page);
lock_mutex_enter_kernel();
lock = lock_rec_get_first_on_page(page);
+ comp = page_is_comp(page);
+ ut_ad(comp == page_is_comp(new_page));
while (lock != NULL) {
@@ -2713,13 +2767,12 @@ lock_move_rec_list_start(
reset the lock bits on the old */
while (page_cur_get_rec(&cur1) != rec) {
-
- ut_ad(0 == ut_memcmp(page_cur_get_rec(&cur1),
+ ut_ad(comp || 0 == ut_memcmp(page_cur_get_rec(&cur1),
page_cur_get_rec(&cur2),
- rec_get_data_size(
+ rec_get_data_size_old(
page_cur_get_rec(&cur2))));
-
- heap_no = rec_get_heap_no(page_cur_get_rec(&cur1));
+ heap_no = rec_get_heap_no(page_cur_get_rec(&cur1),
+ comp);
if (lock_rec_get_nth_bit(lock, heap_no)) {
type_mode = lock->type_mode;
@@ -2759,13 +2812,16 @@ lock_update_split_right(
page_t* right_page, /* in: right page */
page_t* left_page) /* in: left page */
{
+ ibool comp;
lock_mutex_enter_kernel();
-
+ comp = page_is_comp(left_page);
+ ut_ad(comp == page_is_comp(right_page));
+
/* Move the locks on the supremum of the left page to the supremum
of the right page */
lock_rec_move(page_get_supremum_rec(right_page),
- page_get_supremum_rec(left_page));
+ page_get_supremum_rec(left_page), comp);
/* Inherit the locks to the supremum of left page from the successor
of the infimum on right page */
@@ -2819,13 +2875,16 @@ lock_update_root_raise(
page_t* new_page, /* in: index page to which copied */
page_t* root) /* in: root page */
{
+ ibool comp;
lock_mutex_enter_kernel();
-
+ comp = page_is_comp(root);
+ ut_ad(comp == page_is_comp(new_page));
+
/* Move the locks on the supremum of the root to the supremum
of new_page */
lock_rec_move(page_get_supremum_rec(new_page),
- page_get_supremum_rec(root));
+ page_get_supremum_rec(root), comp);
lock_mutex_exit_kernel();
}
@@ -2839,13 +2898,16 @@ 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;
lock_mutex_enter_kernel();
-
+ comp = page_is_comp(page);
+ ut_ad(comp == page_is_comp(new_page));
+
/* Move the locks on the supremum of the old page to the supremum
of new_page */
lock_rec_move(page_get_supremum_rec(new_page),
- page_get_supremum_rec(page));
+ page_get_supremum_rec(page), comp);
lock_rec_free_all_from_discard_page(page);
lock_mutex_exit_kernel();
@@ -2883,8 +2945,11 @@ lock_update_merge_left(
page_t* right_page) /* in: merged index page which will be
discarded */
{
+ ibool comp;
lock_mutex_enter_kernel();
-
+ comp = page_is_comp(left_page);
+ ut_ad(comp == page_is_comp(right_page));
+
if (page_rec_get_next(orig_pred) != page_get_supremum_rec(left_page)) {
/* Inherit the locks on the supremum of the left page to the
@@ -2904,7 +2969,7 @@ lock_update_merge_left(
of the left page */
lock_rec_move(page_get_supremum_rec(left_page),
- page_get_supremum_rec(right_page));
+ page_get_supremum_rec(right_page), comp);
lock_rec_free_all_from_discard_page(right_page);
@@ -3031,12 +3096,14 @@ lock_rec_store_on_page_infimum(
bits are reset on the record */
{
page_t* page;
+ ibool comp;
page = buf_frame_align(rec);
+ comp = page_is_comp(page);
lock_mutex_enter_kernel();
- lock_rec_move(page_get_infimum_rec(page), rec);
+ lock_rec_move(page_get_infimum_rec(page), rec, comp);
lock_mutex_exit_kernel();
}
@@ -3053,9 +3120,12 @@ lock_rec_restore_from_page_infimum(
whose infimum stored the lock state; lock bits are
reset on the infimum */
{
+ ibool comp;
lock_mutex_enter_kernel();
-
- lock_rec_move(rec, page_get_infimum_rec(page));
+ comp = page_is_comp(page);
+ ut_ad(comp == page_is_comp(buf_frame_align(rec)));
+
+ lock_rec_move(rec, page_get_infimum_rec(page), comp);
lock_mutex_exit_kernel();
}
@@ -3352,6 +3422,10 @@ lock_table_create(
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);
@@ -3389,7 +3463,11 @@ lock_table_remove_low(
}
if (lock_get_type(lock) == LOCK_TABLE_EXP) {
- lock->trx->n_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);
@@ -3523,7 +3601,8 @@ lock_table(
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,
+ if LOCK_TABLE_EXP|LOCK_TABLE_TRANSACTIONAL
+ bits are set,
creates an explicit table lock */
dict_table_t* table, /* in: database table in dictionary cache */
ulint mode, /* in: lock mode */
@@ -3539,7 +3618,8 @@ lock_table(
return(DB_SUCCESS);
}
- ut_a(flags == 0 || flags == LOCK_TABLE_EXP);
+ ut_a(flags == 0 || flags == LOCK_TABLE_EXP ||
+ flags == LOCK_TABLE_TRANSACTIONAL);
trx = thr_get_trx(thr);
@@ -3562,7 +3642,7 @@ lock_table(
/* Another trx has a request on the table in an incompatible
mode: this trx may have to wait */
- err = lock_table_enqueue_waiting(mode, table, thr);
+ err = lock_table_enqueue_waiting(mode | flags, table, thr);
lock_mutex_exit_kernel();
@@ -3653,7 +3733,8 @@ lock_table_dequeue(
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_EXP ||
+ lock_get_type(in_lock) == LOCK_TABLE_TRANSACTIONAL);
lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, in_lock);
@@ -3757,7 +3838,9 @@ lock_release_off_kernel(
}
lock_table_dequeue(lock);
- if (lock_get_type(lock) == LOCK_TABLE_EXP) {
+
+ 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);
}
@@ -3781,6 +3864,7 @@ lock_release_off_kernel(
ut_a(trx->auto_inc_lock == NULL);
ut_a(trx->n_lock_table_exp == 0);
+ ut_a(trx->n_lock_table_transactional == 0);
}
/*************************************************************************
@@ -3846,6 +3930,7 @@ lock_release_tables_off_kernel(
}
ut_a(trx->n_lock_table_exp == 0);
+ ut_a(trx->n_lock_table_transactional == 0);
}
/*************************************************************************
@@ -3959,11 +4044,15 @@ lock_table_print(
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_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);
}
+
fputs("TABLE LOCK table ", file);
ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name);
fprintf(file, " trx id %lu %lu",
@@ -3999,11 +4088,15 @@ lock_rec_print(
FILE* file, /* in: file where to print */
lock_t* lock) /* in: record type lock */
{
- page_t* page;
- ulint space;
- ulint page_no;
- ulint i;
- mtr_t mtr;
+ page_t* page;
+ ulint space;
+ ulint page_no;
+ ulint i;
+ mtr_t mtr;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
@@ -4082,8 +4175,11 @@ lock_rec_print(
fprintf(file, "Record lock, heap no %lu ", (ulong) i);
if (page) {
- rec_print(file,
- page_find_rec_with_heap_no(page, i));
+ rec_t* rec
+ = page_find_rec_with_heap_no(page, i);
+ offsets = rec_get_offsets(rec, lock->index,
+ offsets, ULINT_UNDEFINED, &heap);
+ rec_print_new(file, rec, offsets);
}
putc('\n', file);
@@ -4091,8 +4187,11 @@ lock_rec_print(
}
mtr_commit(&mtr);
-}
-
+ if (heap) {
+ mem_heap_free(heap);
+ }
+}
+
/*************************************************************************
Calculates the number of record lock structs in the record lock hash table. */
static
@@ -4121,7 +4220,8 @@ lock_get_n_rec_locks(void)
return(n_locks);
}
-
+
+#ifndef UNIV_HOTBACKUP
/*************************************************************************
Prints info of locks for all transactions. */
@@ -4340,6 +4440,7 @@ lock_table_queue_validate(
while (lock) {
ut_a(((lock->trx)->conc_state == TRX_ACTIVE)
+ || ((lock->trx)->conc_state == TRX_PREPARED)
|| ((lock->trx)->conc_state == TRX_COMMITTED_IN_MEMORY));
if (!lock_get_wait(lock)) {
@@ -4368,12 +4469,16 @@ lock_rec_queue_validate(
/*====================*/
/* out: TRUE if ok */
rec_t* rec, /* in: record to look at */
- dict_index_t* index) /* in: index, or NULL if not known */
+ dict_index_t* index, /* in: index, or NULL if not known */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
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));
lock_mutex_enter_kernel();
@@ -4383,6 +4488,7 @@ lock_rec_queue_validate(
while (lock) {
ut_a(lock->trx->conc_state == TRX_ACTIVE
+ || lock->trx->conc_state == TRX_PREPARED
|| lock->trx->conc_state
== TRX_COMMITTED_IN_MEMORY);
@@ -4396,7 +4502,7 @@ lock_rec_queue_validate(
ut_a(lock->index == index);
}
- lock = lock_rec_get_next(rec, lock);
+ lock = lock_rec_get_next(rec, comp, lock);
}
lock_mutex_exit_kernel();
@@ -4406,13 +4512,13 @@ lock_rec_queue_validate(
if (index && (index->type & DICT_CLUSTERED)) {
- impl_trx = lock_clust_rec_some_has_impl(rec, index);
+ 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, impl_trx)) {
+ LOCK_WAIT, rec, comp, impl_trx)) {
ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, rec,
- impl_trx));
+ comp, impl_trx));
}
}
@@ -4422,13 +4528,14 @@ lock_rec_queue_validate(
next function call: we have to release lock table mutex
to obey the latching order */
- impl_trx = lock_sec_rec_some_has_impl_off_kernel(rec, index);
+ impl_trx = lock_sec_rec_some_has_impl_off_kernel(
+ rec, index, offsets);
if (impl_trx && lock_rec_other_has_expl_req(LOCK_S, 0,
- LOCK_WAIT, rec, impl_trx)) {
+ LOCK_WAIT, rec, comp, impl_trx)) {
- ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, rec,
- impl_trx));
+ ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
+ rec, comp, impl_trx));
}
}
@@ -4436,6 +4543,7 @@ lock_rec_queue_validate(
while (lock) {
ut_a(lock->trx->conc_state == TRX_ACTIVE
+ || lock->trx->conc_state == TRX_PREPARED
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
ut_a(trx_in_trx_list(lock->trx));
@@ -4447,10 +4555,10 @@ lock_rec_queue_validate(
if (lock_get_mode(lock) == LOCK_S) {
ut_a(!lock_rec_other_has_expl_req(LOCK_X,
- 0, 0, rec, lock->trx));
+ 0, 0, rec, comp, lock->trx));
} else {
ut_a(!lock_rec_other_has_expl_req(LOCK_S,
- 0, 0, rec, lock->trx));
+ 0, 0, rec, comp, lock->trx));
}
} else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
@@ -4458,7 +4566,7 @@ lock_rec_queue_validate(
ut_a(lock_rec_has_to_wait_in_queue(lock));
}
- lock = lock_rec_get_next(rec, lock);
+ lock = lock_rec_get_next(rec, comp, lock);
}
lock_mutex_exit_kernel();
@@ -4480,10 +4588,14 @@ lock_rec_validate_page(
page_t* page;
lock_t* lock;
rec_t* rec;
- ulint nth_lock = 0;
- ulint nth_bit = 0;
+ ulint nth_lock = 0;
+ ulint nth_bit = 0;
ulint i;
mtr_t mtr;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
#ifdef UNIV_SYNC_DEBUG
ut_ad(!mutex_own(&kernel_mutex));
@@ -4515,6 +4627,7 @@ loop:
ut_a(trx_in_trx_list(lock->trx));
ut_a(lock->trx->conc_state == TRX_ACTIVE
+ || lock->trx->conc_state == TRX_PREPARED
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
for (i = nth_bit; i < lock_rec_get_n_bits(lock); i++) {
@@ -4523,13 +4636,15 @@ loop:
index = lock->index;
rec = page_find_rec_with_heap_no(page, i);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
fprintf(stderr,
"Validating %lu %lu\n", (ulong) space, (ulong) page_no);
lock_mutex_exit_kernel();
- lock_rec_queue_validate(rec, index);
+ lock_rec_queue_validate(rec, index, offsets);
lock_mutex_enter_kernel();
@@ -4549,6 +4664,9 @@ function_exit:
mtr_commit(&mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(TRUE);
}
@@ -4628,7 +4746,7 @@ lock_validate(void)
return(TRUE);
}
-
+#endif /* !UNIV_HOTBACKUP */
/*============ RECORD LOCK CHECKS FOR ROW OPERATIONS ====================*/
/*************************************************************************
@@ -4721,8 +4839,22 @@ lock_rec_insert_check_and_lock(
page_update_max_trx_id(buf_frame_align(rec),
thr_get_trx(thr)->id);
}
-
- ut_ad(lock_rec_queue_validate(next_rec, index));
+
+#ifdef UNIV_DEBUG
+ {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ const ulint* offsets;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ offsets = rec_get_offsets(next_rec, index, offsets_,
+ ULINT_UNDEFINED, &heap);
+ ut_ad(lock_rec_queue_validate(next_rec, index, offsets));
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ }
+#endif /* UNIV_DEBUG */
return(err);
}
@@ -4736,7 +4868,8 @@ void
lock_rec_convert_impl_to_expl(
/*==========================*/
rec_t* rec, /* in: user record on page */
- dict_index_t* index) /* in: index of record */
+ dict_index_t* index, /* in: index of record */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
trx_t* impl_trx;
@@ -4744,11 +4877,14 @@ lock_rec_convert_impl_to_expl(
ut_ad(mutex_own(&kernel_mutex));
#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);
if (index->type & DICT_CLUSTERED) {
- impl_trx = lock_clust_rec_some_has_impl(rec, index);
+ impl_trx = lock_clust_rec_some_has_impl(rec, index, offsets);
} else {
- impl_trx = lock_sec_rec_some_has_impl_off_kernel(rec, index);
+ impl_trx = lock_sec_rec_some_has_impl_off_kernel(
+ rec, index, offsets);
}
if (impl_trx) {
@@ -4756,7 +4892,7 @@ lock_rec_convert_impl_to_expl(
record, set one for it */
if (!lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, rec,
- impl_trx)) {
+ index->table->comp, impl_trx)) {
lock_rec_add_to_queue(LOCK_REC | LOCK_X
| LOCK_REC_NOT_GAP, rec, index,
@@ -4782,17 +4918,19 @@ lock_clust_rec_modify_check_and_lock(
does nothing */
rec_t* rec, /* in: record which should be modified */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
que_thr_t* thr) /* in: query thread */
{
ulint err;
-
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ ut_ad(index->type & DICT_CLUSTERED);
+
if (flags & BTR_NO_LOCKING_FLAG) {
return(DB_SUCCESS);
}
- ut_ad(index->type & DICT_CLUSTERED);
-
lock_mutex_enter_kernel();
ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
@@ -4800,13 +4938,13 @@ lock_clust_rec_modify_check_and_lock(
/* If a transaction has no explicit x-lock set on the record, set one
for it */
- lock_rec_convert_impl_to_expl(rec, index);
+ lock_rec_convert_impl_to_expl(rec, index, offsets);
err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP, rec, index, thr);
lock_mutex_exit_kernel();
- ut_ad(lock_rec_queue_validate(rec, index));
+ ut_ad(lock_rec_queue_validate(rec, index, offsets));
return(err);
}
@@ -4850,8 +4988,22 @@ lock_sec_rec_modify_check_and_lock(
err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP, rec, index, thr);
lock_mutex_exit_kernel();
-
- ut_ad(lock_rec_queue_validate(rec, index));
+
+#ifdef UNIV_DEBUG
+ {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ const ulint* offsets;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ offsets = rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap);
+ ut_ad(lock_rec_queue_validate(rec, index, offsets));
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ }
+#endif /* UNIV_DEBUG */
if (err == DB_SUCCESS) {
/* Update the page max trx id field */
@@ -4878,6 +5030,7 @@ lock_sec_rec_read_check_and_lock(
which should be read or passed over by a read
cursor */
dict_index_t* index, /* in: secondary index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
ulint mode, /* in: mode of the lock which the read cursor
should set on records: LOCK_S or LOCK_X; the
latter is possible in SELECT FOR UPDATE */
@@ -4889,6 +5042,7 @@ lock_sec_rec_read_check_and_lock(
ut_ad(!(index->type & DICT_CLUSTERED));
ut_ad(page_rec_is_user_rec(rec) || page_rec_is_supremum(rec));
+ ut_ad(rec_offs_validate(rec, index, offsets));
if (flags & BTR_NO_LOCKING_FLAG) {
@@ -4911,14 +5065,14 @@ lock_sec_rec_read_check_and_lock(
|| recv_recovery_is_on())
&& !page_rec_is_supremum(rec)) {
- lock_rec_convert_impl_to_expl(rec, index);
+ lock_rec_convert_impl_to_expl(rec, index, offsets);
}
err = lock_rec_lock(FALSE, mode | gap_mode, rec, index, thr);
lock_mutex_exit_kernel();
- ut_ad(lock_rec_queue_validate(rec, index));
+ ut_ad(lock_rec_queue_validate(rec, index, offsets));
return(err);
}
@@ -4942,6 +5096,7 @@ lock_clust_rec_read_check_and_lock(
which should be read or passed over by a read
cursor */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
ulint mode, /* in: mode of the lock which the read cursor
should set on records: LOCK_S or LOCK_X; the
latter is possible in SELECT FOR UPDATE */
@@ -4955,6 +5110,8 @@ lock_clust_rec_read_check_and_lock(
ut_ad(page_rec_is_user_rec(rec) || page_rec_is_supremum(rec));
ut_ad(gap_mode == LOCK_ORDINARY || gap_mode == LOCK_GAP
|| gap_mode == LOCK_REC_NOT_GAP);
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
if (flags & BTR_NO_LOCKING_FLAG) {
return(DB_SUCCESS);
@@ -4969,14 +5126,57 @@ lock_clust_rec_read_check_and_lock(
if (!page_rec_is_supremum(rec)) {
- lock_rec_convert_impl_to_expl(rec, index);
+ lock_rec_convert_impl_to_expl(rec, index, offsets);
}
err = lock_rec_lock(FALSE, mode | gap_mode, rec, index, thr);
lock_mutex_exit_kernel();
- ut_ad(lock_rec_queue_validate(rec, index));
-
+ ut_ad(lock_rec_queue_validate(rec, index, offsets));
+
return(err);
}
+/*************************************************************************
+Checks if locks of other transactions prevent an immediate read, or passing
+over by a read cursor, of a clustered index record. If they do, first tests
+if the query thread should anyway be suspended for some reason; if not, then
+puts the transaction and the query thread to the lock wait state and inserts a
+waiting request for a record lock to the lock queue. Sets the requested mode
+lock on the record. This is an alternative version of
+lock_clust_rec_read_check_and_lock() that does not require the parameter
+"offsets". */
+
+ulint
+lock_clust_rec_read_check_and_lock_alt(
+/*===================================*/
+ /* 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 */
+ rec_t* rec, /* in: user record or page supremum record
+ which should be read or passed over by a read
+ cursor */
+ dict_index_t* index, /* in: clustered index */
+ ulint mode, /* in: mode of the lock which the read cursor
+ should set on records: LOCK_S or LOCK_X; the
+ latter is possible in SELECT FOR UPDATE */
+ ulint gap_mode,/* in: LOCK_ORDINARY, LOCK_GAP, or
+ LOCK_REC_NOT_GAP */
+ que_thr_t* thr) /* in: query thread */
+{
+ mem_heap_t* tmp_heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ ulint ret;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &tmp_heap);
+ ret = lock_clust_rec_read_check_and_lock(flags, rec, index,
+ offsets, mode, gap_mode, thr);
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
+ return(ret);
+}
diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c
index e08adb013b5..560f51401ac 100644
--- a/innobase/log/log0log.c
+++ b/innobase/log/log0log.c
@@ -24,6 +24,32 @@ Created 12/9/1995 Heikki Tuuri
#include "trx0sys.h"
#include "trx0trx.h"
+/*
+General philosophy of InnoDB redo-logs:
+
+1) Every change to a contents of a data page must be done
+through mtr, which in mtr_commit() writes log records
+to the InnoDB redo log.
+
+2) Normally these changes are performed using a mlog_write_ulint()
+or similar function.
+
+3) In some page level operations only a code number of a
+c-function and its parameters are written to the log to
+reduce the size of the log.
+
+ 3a) You should not add parameters to these kind of functions
+ (e.g. trx_undo_header_create(), trx_undo_insert_header_reuse())
+
+ 3b) You should not add such functionality which either change
+ working when compared with the old or are dependent on data
+ outside of the page. These kind of functions should implement
+ self-contained page transformation and it should be unchanged
+ if you don't have very essential reasons to change log
+ semantics or format.
+
+*/
+
/* Current free limit of space 0; protected by the log sys mutex; 0 means
uninitialized */
ulint log_fsp_current_free_limit = 0;
@@ -190,6 +216,8 @@ loop:
log_buffer_flush_to_disk();
+ srv_log_waits++;
+
ut_ad(++count < 50);
goto loop;
@@ -292,6 +320,8 @@ part_loop:
if (str_len > 0) {
goto part_loop;
}
+
+ srv_log_write_requests++;
}
/****************************************************************
@@ -1112,11 +1142,15 @@ log_group_file_header_flush(
if (log_do_write) {
log_sys->n_log_ios++;
+ srv_os_log_pending_writes++;
+
fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id,
dest_offset / UNIV_PAGE_SIZE,
dest_offset % UNIV_PAGE_SIZE,
OS_FILE_LOG_BLOCK_SIZE,
buf, group);
+
+ srv_os_log_pending_writes--;
}
}
@@ -1181,6 +1215,8 @@ loop:
log_group_file_header_flush(group,
next_offset / group->file_size, start_lsn);
+ srv_os_log_written+= OS_FILE_LOG_BLOCK_SIZE;
+ srv_log_writes++;
}
if ((next_offset % group->file_size) + len > group->file_size) {
@@ -1225,9 +1261,16 @@ loop:
if (log_do_write) {
log_sys->n_log_ios++;
+ srv_os_log_pending_writes++;
+
fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id,
next_offset / UNIV_PAGE_SIZE,
next_offset % UNIV_PAGE_SIZE, write_len, buf, group);
+
+ srv_os_log_pending_writes--;
+
+ srv_os_log_written+= write_len;
+ srv_log_writes++;
}
if (write_len < len) {
@@ -3004,7 +3047,10 @@ loop:
mutex_enter(&kernel_mutex);
- /* Check that there are no longer transactions */
+ /* Check that there are no longer transactions. We need this wait even
+ for the 'very fast' shutdown, because the InnoDB layer may have
+ committed or prepared transactions and we don't want to lose them. */
+
if (trx_n_mysql_transactions > 0
|| UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
@@ -3013,6 +3059,21 @@ loop:
goto loop;
}
+ if (srv_fast_shutdown == 2) {
+ /* In this fastest shutdown we do not flush the buffer pool:
+ it is essentially a 'crash' of the InnoDB server.
+ Make sure that the log is all flushed to disk, so that
+ we can recover all committed transactions in a crash
+ recovery.
+ We must not write the lsn stamps to the data files, since at a
+ startup InnoDB deduces from the stamps if the previous
+ shutdown was clean. */
+
+ log_buffer_flush_to_disk();
+ return; /* We SKIP ALL THE REST !! */
+ }
+
+
/* Check that the master thread is suspended */
if (srv_n_threads_active[SRV_MASTER] != 0) {
@@ -3049,24 +3110,13 @@ loop:
log_archive_all();
#endif /* UNIV_LOG_ARCHIVE */
- if (!srv_very_fast_shutdown) {
- /* In a 'very fast' shutdown we do not flush the buffer pool:
- it is essentially a 'crash' of the InnoDB server. */
-
log_make_checkpoint_at(ut_dulint_max, TRUE);
- } else {
- /* Make sure that the log is all flushed to disk, so that
- we can recover all committed transactions in a crash
- recovery */
- log_buffer_flush_to_disk();
- }
mutex_enter(&(log_sys->mutex));
lsn = log_sys->lsn;
- if ((ut_dulint_cmp(lsn, log_sys->last_checkpoint_lsn) != 0
- && !srv_very_fast_shutdown)
+ if ((ut_dulint_cmp(lsn, log_sys->last_checkpoint_lsn) != 0)
#ifdef UNIV_LOG_ARCHIVE
|| (srv_log_archive_on
&& ut_dulint_cmp(lsn,
@@ -3115,7 +3165,7 @@ loop:
completely flushed to disk! (We do not call fil_write... if the
'very fast' shutdown is enabled.) */
- if (!srv_very_fast_shutdown && !buf_all_freed()) {
+ if (!buf_all_freed()) {
goto loop;
}
@@ -3138,7 +3188,7 @@ loop:
/* Make some checks that the server really is quiet */
ut_a(srv_n_threads_active[SRV_MASTER] == 0);
- ut_a(srv_very_fast_shutdown || buf_all_freed());
+ ut_a(buf_all_freed());
ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
if (ut_dulint_cmp(lsn, srv_start_lsn) < 0) {
@@ -3153,15 +3203,7 @@ loop:
srv_shutdown_lsn = lsn;
- if (!srv_very_fast_shutdown) {
- /* In a 'very fast' shutdown we do not flush the buffer pool:
- it is essentially a 'crash' of the InnoDB server. Then we must
- not write the lsn stamps to the data files, since at a
- startup InnoDB deduces from the stamps if the previous
- shutdown was clean. */
-
fil_write_flushed_lsn_to_data_files(lsn, arch_log_no);
- }
fil_flush_file_spaces(FIL_TABLESPACE);
@@ -3169,7 +3211,7 @@ loop:
/* Make some checks that the server really is quiet */
ut_a(srv_n_threads_active[SRV_MASTER] == 0);
- ut_a(srv_very_fast_shutdown || buf_all_freed());
+ ut_a(buf_all_freed());
ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
}
diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c
index ddb33de6fa6..6597122f104 100644
--- a/innobase/log/log0recv.c
+++ b/innobase/log/log0recv.c
@@ -756,81 +756,124 @@ recv_parse_or_apply_log_rec_body(
mtr_t* mtr) /* in: mtr or NULL; should be non-NULL if and only if
page is non-NULL */
{
- byte* new_ptr;
-
- if (type <= MLOG_8BYTES) {
- new_ptr = mlog_parse_nbytes(type, ptr, end_ptr, page);
-
- } else if (type == MLOG_REC_INSERT) {
- new_ptr = page_cur_parse_insert_rec(FALSE, ptr, end_ptr, page,
- mtr);
- } else if (type == MLOG_REC_CLUST_DELETE_MARK) {
- new_ptr = btr_cur_parse_del_mark_set_clust_rec(ptr, end_ptr,
- page);
- } else if (type == MLOG_REC_SEC_DELETE_MARK) {
- new_ptr = btr_cur_parse_del_mark_set_sec_rec(ptr, end_ptr,
- page);
- } else if (type == MLOG_REC_UPDATE_IN_PLACE) {
- new_ptr = btr_cur_parse_update_in_place(ptr, end_ptr, page);
-
- } else if ((type == MLOG_LIST_END_DELETE)
- || (type == MLOG_LIST_START_DELETE)) {
- new_ptr = page_parse_delete_rec_list(type, ptr, end_ptr, page,
- mtr);
- } else if (type == MLOG_LIST_END_COPY_CREATED) {
- new_ptr = page_parse_copy_rec_list_to_created_page(ptr,
- end_ptr, page, mtr);
- } else if (type == MLOG_PAGE_REORGANIZE) {
- new_ptr = btr_parse_page_reorganize(ptr, end_ptr, page, mtr);
-
- } else if (type == MLOG_PAGE_CREATE) {
- new_ptr = page_parse_create(ptr, end_ptr, page, mtr);
-
- } else if (type == MLOG_UNDO_INSERT) {
- new_ptr = trx_undo_parse_add_undo_rec(ptr, end_ptr, page);
-
- } else if (type == MLOG_UNDO_ERASE_END) {
- new_ptr = trx_undo_parse_erase_page_end(ptr, end_ptr, page,
- mtr);
- } else if (type == MLOG_UNDO_INIT) {
- new_ptr = trx_undo_parse_page_init(ptr, end_ptr, page, mtr);
-
- } else if (type == MLOG_UNDO_HDR_DISCARD) {
- new_ptr = trx_undo_parse_discard_latest(ptr, end_ptr, page,
- mtr);
- } else if ((type == MLOG_UNDO_HDR_CREATE)
- || (type == MLOG_UNDO_HDR_REUSE)) {
- new_ptr = trx_undo_parse_page_header(type, ptr, end_ptr, page,
- mtr);
- } else if (type == MLOG_REC_MIN_MARK) {
- new_ptr = btr_parse_set_min_rec_mark(ptr, end_ptr, page, mtr);
-
- } else if (type == MLOG_REC_DELETE) {
- new_ptr = page_cur_parse_delete_rec(ptr, end_ptr, page, mtr);
-
- } else if (type == MLOG_IBUF_BITMAP_INIT) {
- new_ptr = ibuf_parse_bitmap_init(ptr, end_ptr, page, mtr);
-
- } else if (type == MLOG_INIT_FILE_PAGE) {
- new_ptr = fsp_parse_init_file_page(ptr, end_ptr, page);
-
- } else if (type == MLOG_WRITE_STRING) {
- new_ptr = mlog_parse_string(ptr, end_ptr, page);
-
- } else if (type == MLOG_FILE_CREATE
- || type == MLOG_FILE_RENAME
- || type == MLOG_FILE_DELETE) {
- new_ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, FALSE,
+ dict_index_t* index = NULL;
+
+ switch (type) {
+ case MLOG_1BYTE: case MLOG_2BYTES: case MLOG_4BYTES: case MLOG_8BYTES:
+ ptr = mlog_parse_nbytes(type, ptr, end_ptr, page);
+ break;
+ case MLOG_REC_INSERT: case MLOG_COMP_REC_INSERT:
+ if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
+ type == MLOG_COMP_REC_INSERT, &index))) {
+ ptr = page_cur_parse_insert_rec(FALSE, ptr, end_ptr,
+ index, page, mtr);
+ }
+ break;
+ 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))) {
+ 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);
+ }
+ 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))) {
+ ptr = btr_cur_parse_update_in_place(ptr, end_ptr,
+ page, index);
+ }
+ break;
+ case MLOG_LIST_END_DELETE: case MLOG_COMP_LIST_END_DELETE:
+ case MLOG_LIST_START_DELETE: case MLOG_COMP_LIST_START_DELETE:
+ if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
+ type == MLOG_COMP_LIST_END_DELETE
+ || type == MLOG_COMP_LIST_START_DELETE, &index))) {
+ ptr = page_parse_delete_rec_list(type, ptr, end_ptr,
+ index, page, mtr);
+ }
+ break;
+ 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))) {
+ ptr = page_parse_copy_rec_list_to_created_page(ptr,
+ end_ptr, index, page, mtr);
+ }
+ break;
+ case MLOG_PAGE_REORGANIZE: case MLOG_COMP_PAGE_REORGANIZE:
+ if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
+ type == MLOG_COMP_PAGE_REORGANIZE, &index))) {
+ ptr = btr_parse_page_reorganize(ptr, end_ptr, index,
+ page, mtr);
+ }
+ break;
+ case MLOG_PAGE_CREATE: case MLOG_COMP_PAGE_CREATE:
+ ptr = page_parse_create(ptr, end_ptr,
+ type == MLOG_COMP_PAGE_CREATE, page, mtr);
+ break;
+ case MLOG_UNDO_INSERT:
+ ptr = trx_undo_parse_add_undo_rec(ptr, end_ptr, page);
+ break;
+ case MLOG_UNDO_ERASE_END:
+ ptr = trx_undo_parse_erase_page_end(ptr, end_ptr, page, mtr);
+ break;
+ case MLOG_UNDO_INIT:
+ ptr = trx_undo_parse_page_init(ptr, end_ptr, page, mtr);
+ break;
+ case MLOG_UNDO_HDR_DISCARD:
+ ptr = trx_undo_parse_discard_latest(ptr, end_ptr, page, mtr);
+ break;
+ case MLOG_UNDO_HDR_CREATE:
+ case MLOG_UNDO_HDR_REUSE:
+ ptr = trx_undo_parse_page_header(type, ptr, end_ptr,
+ page, mtr);
+ break;
+ case MLOG_REC_MIN_MARK: case MLOG_COMP_REC_MIN_MARK:
+ ptr = btr_parse_set_min_rec_mark(ptr, end_ptr,
+ type == MLOG_COMP_REC_MIN_MARK, page, mtr);
+ break;
+ case MLOG_REC_DELETE: case MLOG_COMP_REC_DELETE:
+ if (NULL != (ptr = mlog_parse_index(ptr, end_ptr,
+ type == MLOG_COMP_REC_DELETE, &index))) {
+ ptr = page_cur_parse_delete_rec(ptr, end_ptr,
+ index, page, mtr);
+ }
+ break;
+ case MLOG_IBUF_BITMAP_INIT:
+ ptr = ibuf_parse_bitmap_init(ptr, end_ptr, page, mtr);
+ break;
+ case MLOG_INIT_FILE_PAGE:
+ ptr = fsp_parse_init_file_page(ptr, end_ptr, page);
+ break;
+ case MLOG_WRITE_STRING:
+ ptr = mlog_parse_string(ptr, end_ptr, page);
+ break;
+ case MLOG_FILE_CREATE:
+ case MLOG_FILE_RENAME:
+ case MLOG_FILE_DELETE:
+ ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, FALSE,
ULINT_UNDEFINED);
- } else {
- new_ptr = NULL;
-
+ break;
+ default:
+ ptr = NULL;
recv_sys->found_corrupt_log = TRUE;
}
- ut_ad(!page || new_ptr);
+ ut_ad(!page || ptr);
+ if (index) {
+ dict_table_t* table = index->table;
+ mem_heap_free(index->heap);
+ mutex_free(&(table->autoinc_mutex));
+ mem_heap_free(table->heap);
+ }
- return(new_ptr);
+ return(ptr);
}
/*************************************************************************
@@ -1394,7 +1437,7 @@ loop:
/* This page is allocated from the buffer pool and used in the function
below */
-page_t* recv_backup_application_page = NULL;
+static page_t* recv_backup_application_page = NULL;
/***********************************************************************
Applies log records in the hash table to a backup. */
@@ -2853,11 +2896,8 @@ void
recv_recovery_from_checkpoint_finish(void)
/*======================================*/
{
- /* Rollback the uncommitted transactions which have no user session */
-
- if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
- trx_rollback_or_clean_all_without_sess();
- }
+ int i;
+ os_thread_id_t recovery_thread_id;
/* Apply the hashed log records to the respective file pages */
@@ -2890,9 +2930,17 @@ recv_recovery_from_checkpoint_finish(void)
/* Free the resources of the recovery system */
recv_recovery_on = FALSE;
+
#ifndef UNIV_LOG_DEBUG
recv_sys_free();
#endif
+ if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
+ /* Rollback the uncommitted transactions which have no user
+ session */
+
+ os_thread_create(trx_rollback_or_clean_all_without_sess,
+ (void *)&i, &recovery_thread_id);
+ }
}
/**********************************************************
diff --git a/innobase/mtr/mtr0log.c b/innobase/mtr/mtr0log.c
index 82baa8905ba..4f826f242e8 100644
--- a/innobase/mtr/mtr0log.c
+++ b/innobase/mtr/mtr0log.c
@@ -384,3 +384,161 @@ mlog_parse_string(
return(ptr + len);
}
+
+/************************************************************
+Opens a buffer for mlog, writes the initial log record and,
+if needed, the field lengths of an index. */
+
+byte*
+mlog_open_and_write_index(
+/*======================*/
+ /* out: buffer, NULL if log mode
+ MTR_LOG_NONE */
+ mtr_t* mtr, /* in: mtr */
+ byte* rec, /* in: index record or page */
+ dict_index_t* index, /* in: record descriptor */
+ byte type, /* in: log item type */
+ ulint size) /* in: requested buffer size in bytes
+ (if 0, calls mlog_close() and returns NULL) */
+{
+ byte* log_ptr;
+ const byte* log_start;
+ const byte* log_end;
+
+ if (!index->table->comp) {
+ log_start = log_ptr = mlog_open(mtr, 11 + size);
+ if (!log_ptr) {
+ return(NULL); /* logging is disabled */
+ }
+ log_ptr = mlog_write_initial_log_record_fast(rec, type,
+ log_ptr, mtr);
+ log_end = log_ptr + 11 + size;
+ } else {
+ ulint i;
+ ulint n = dict_index_get_n_fields(index);
+ /* total size needed */
+ ulint total = 11 + size + (n + 2) * 2;
+ ulint alloc = total;
+ /* allocate at most DYN_ARRAY_DATA_SIZE at a time */
+ if (alloc > DYN_ARRAY_DATA_SIZE) {
+ alloc = DYN_ARRAY_DATA_SIZE;
+ }
+ log_start = log_ptr = mlog_open(mtr, alloc);
+ if (!log_ptr) {
+ return(NULL); /* logging is disabled */
+ }
+ log_end = log_ptr + alloc;
+ log_ptr = mlog_write_initial_log_record_fast(rec, type,
+ log_ptr, mtr);
+ mach_write_to_2(log_ptr, n);
+ log_ptr += 2;
+ mach_write_to_2(log_ptr,
+ dict_index_get_n_unique_in_tree(index));
+ log_ptr += 2;
+ for (i = 0; i < n; i++) {
+ dict_field_t* field;
+ dtype_t* type;
+ ulint len;
+ field = dict_index_get_nth_field(index, i);
+ type = dict_col_get_type(dict_field_get_col(field));
+ len = field->fixed_len;
+ ut_ad(len < 0x7fff);
+ if (len == 0 && (dtype_get_len(type) > 255
+ || dtype_get_mtype(type) == DATA_BLOB)) {
+ /* variable-length field
+ with maximum length > 255 */
+ len = 0x7fff;
+ }
+ if (dtype_get_prtype(type) & DATA_NOT_NULL) {
+ len |= 0x8000;
+ }
+ if (log_ptr + 2 > log_end) {
+ mlog_close(mtr, log_ptr);
+ ut_a(total > (ulint) (log_ptr - log_start));
+ total -= log_ptr - log_start;
+ alloc = total;
+ if (alloc > DYN_ARRAY_DATA_SIZE) {
+ alloc = DYN_ARRAY_DATA_SIZE;
+ }
+ log_start = log_ptr = mlog_open(mtr, alloc);
+ if (!log_ptr) {
+ return(NULL); /* logging is disabled */
+ }
+ log_end = log_ptr + alloc;
+ }
+ mach_write_to_2(log_ptr, len);
+ log_ptr += 2;
+ }
+ }
+ if (size == 0) {
+ mlog_close(mtr, log_ptr);
+ log_ptr = NULL;
+ } else if (log_ptr + size > log_end) {
+ mlog_close(mtr, log_ptr);
+ log_ptr = mlog_open(mtr, size);
+ }
+ return(log_ptr);
+}
+
+/************************************************************
+Parses a log record written by mlog_open_and_write_index. */
+
+byte*
+mlog_parse_index(
+/*=============*/
+ /* out: parsed record end,
+ NULL if not a complete record */
+ byte* ptr, /* in: buffer */
+ byte* end_ptr,/* in: buffer end */
+ /* out: new value of log_ptr */
+ ibool comp, /* in: TRUE=compact record format */
+ dict_index_t** index) /* out, own: dummy index */
+{
+ ulint i, n, n_uniq;
+ dict_table_t* table;
+ dict_index_t* ind;
+
+ if (comp) {
+ if (end_ptr < ptr + 4) {
+ return(NULL);
+ }
+ n = mach_read_from_2(ptr);
+ ptr += 2;
+ n_uniq = mach_read_from_2(ptr);
+ ut_ad(n_uniq <= n);
+ if (end_ptr < ptr + (n + 1) * 2) {
+ return(NULL);
+ }
+ } else {
+ n = n_uniq = 1;
+ }
+ table = dict_mem_table_create("LOG_DUMMY", DICT_HDR_SPACE, n, comp);
+ ind = dict_mem_index_create("LOG_DUMMY", "LOG_DUMMY",
+ DICT_HDR_SPACE, 0, n);
+ ind->table = table;
+ ind->n_uniq = n_uniq;
+ if (n_uniq != n) {
+ ind->type = DICT_CLUSTERED;
+ }
+ /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
+ ind->cached = TRUE;
+ if (comp) {
+ for (i = 0; i < n; i++) {
+ ulint len = mach_read_from_2(ptr += 2);
+ /* The high-order bit of len is the NOT NULL flag;
+ the rest is 0 or 0x7fff for variable-length fields,
+ and 1..0x7ffe for fixed-length fields. */
+ dict_mem_table_add_col(table, "DUMMY",
+ ((len + 1) & 0x7fff) <= 1
+ ? DATA_BINARY
+ : DATA_FIXBINARY,
+ len & 0x8000 ? DATA_NOT_NULL : 0,
+ len & 0x7fff, 0);
+ dict_index_add_col(ind,
+ dict_table_get_nth_col(table, i), 0, 0);
+ }
+ ptr += 2;
+ }
+ *index = ind;
+ return(ptr);
+}
diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c
index 15f5bf40e51..9df26150160 100644
--- a/innobase/os/os0file.c
+++ b/innobase/os/os0file.c
@@ -15,6 +15,13 @@ Created 10/21/1995 Heikki Tuuri
#include "fil0fil.h"
#include "buf0buf.h"
+#if defined(UNIV_HOTBACKUP) && defined(__WIN__)
+/* Add includes for the _stat() call to compile on Windows */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#endif /* UNIV_HOTBACKUP */
+
#undef HAVE_FDATASYNC
#ifdef POSIX_ASYNC_IO
@@ -155,6 +162,10 @@ os_mutex_t os_file_count_mutex;
ulint os_file_n_pending_preads = 0;
ulint os_file_n_pending_pwrites = 0;
+/* These are not protected by any mutex */
+ulint os_n_pending_writes = 0;
+ulint os_n_pending_reads = 0;
+
/***************************************************************************
Gets the operating system version. Currently works only on Windows. */
@@ -1703,7 +1714,7 @@ os_file_set_size(
}
/* Print about progress for each 100 MB written */
- if ((offset + n_bytes) / (ib_longlong)(100 * 1024 * 1024)
+ if ((ib_longlong) (offset + n_bytes) / (ib_longlong)(100 * 1024 * 1024)
!= offset / (ib_longlong)(100 * 1024 * 1024)) {
fprintf(stderr, " %lu00",
@@ -2078,8 +2089,12 @@ try_again:
goto error_handling;
}
+ os_n_pending_reads++;
+
ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
+ os_n_pending_reads--;
+
os_mutex_exit(os_file_seek_mutexes[i]);
if (ret && len == n) {
@@ -2092,8 +2107,12 @@ try_again:
os_bytes_read_since_printout += n;
try_again:
+ os_n_pending_reads++;
+
ret = os_file_pread(file, buf, n, offset, offset_high);
+ os_n_pending_reads--;
+
if ((ulint)ret == n) {
return(TRUE);
@@ -2181,8 +2200,12 @@ try_again:
goto error_handling;
}
+ os_n_pending_reads++;
+
ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
+ os_n_pending_reads--;
+
os_mutex_exit(os_file_seek_mutexes[i]);
if (ret && len == n) {
@@ -2195,8 +2218,12 @@ try_again:
os_bytes_read_since_printout += n;
try_again:
+ os_n_pending_reads++;
+
ret = os_file_pread(file, buf, n, offset, offset_high);
+ os_n_pending_reads--;
+
if ((ulint)ret == n) {
return(TRUE);
@@ -2278,7 +2305,11 @@ retry:
return(FALSE);
}
+ os_n_pending_writes++;
+
ret = WriteFile(file, buf, (DWORD) n, &len, NULL);
+
+ os_n_pending_writes--;
/* Always do fsync to reduce the probability that when the OS crashes,
a database page is only partially physically written to disk. */
@@ -2339,8 +2370,12 @@ retry:
#else
ssize_t ret;
+ os_n_pending_writes++;
+
ret = os_file_pwrite(file, buf, n, offset, offset_high);
+ os_n_pending_writes--;
+
if ((ulint)ret == n) {
return(TRUE);
diff --git a/innobase/os/os0proc.c b/innobase/os/os0proc.c
index 2f155788420..167aed93de7 100644
--- a/innobase/os/os0proc.c
+++ b/innobase/os/os0proc.c
@@ -69,6 +69,10 @@ byte* os_awe_window;
ulint os_awe_window_size;
#endif
+ibool os_use_large_pages;
+/* Large page size. This may be a boot-time option on some platforms */
+ulint os_large_page_size;
+
/********************************************************************
Windows AWE support. Tries to enable the "lock pages in memory" privilege for
the current process so that the current process can allocate memory-locked
@@ -516,6 +520,89 @@ os_mem_alloc_nocache(
}
/********************************************************************
+Allocates large pages memory. */
+
+void*
+os_mem_alloc_large(
+/*=================*/
+ /* out: allocated memory */
+ ulint n, /* in: number of bytes */
+ ibool set_to_zero, /* in: TRUE if allocated memory should be set
+ to zero if UNIV_SET_MEM_TO_ZERO is defined */
+ ibool assert_on_error) /* in: if TRUE, we crash mysqld if the memory
+ cannot be allocated */
+{
+#ifdef HAVE_LARGE_PAGES
+ ulint size;
+ int shmid;
+ void *ptr = NULL;
+ struct shmid_ds buf;
+
+ if (!os_use_large_pages || !os_large_page_size) {
+ goto skip;
+ }
+
+#ifdef UNIV_LINUX
+ /* Align block size to os_large_page_size */
+ size = ((n - 1) & ~(os_large_page_size - 1)) + os_large_page_size;
+
+ shmid = shmget(IPC_PRIVATE, (size_t)size, SHM_HUGETLB | SHM_R | SHM_W);
+ if (shmid < 0) {
+ fprintf(stderr, "InnoDB: HugeTLB: Warning: Failed to allocate %lu bytes. "
+ "errno %d\n", n, errno);
+ } else {
+ ptr = shmat(shmid, NULL, 0);
+ if (ptr == (void *)-1) {
+ fprintf(stderr, "InnoDB: HugeTLB: Warning: Failed to attach shared memory "
+ "segment, errno %d\n", errno);
+ }
+ /*
+ Remove the shared memory segment so that it will be automatically freed
+ after memory is detached or process exits
+ */
+ shmctl(shmid, IPC_RMID, &buf);
+ }
+#endif
+
+ if (ptr) {
+ if (set_to_zero) {
+#ifdef UNIV_SET_MEM_TO_ZERO
+ memset(ptr, '\0', size);
+#endif
+ }
+
+ return(ptr);
+ }
+
+ fprintf(stderr, "InnoDB HugeTLB: Warning: Using conventional memory pool\n");
+skip:
+#endif /* HAVE_LARGE_PAGES */
+
+ return(ut_malloc_low(n, set_to_zero, assert_on_error));
+}
+
+/********************************************************************
+Frees large pages memory. */
+
+void
+os_mem_free_large(
+/*=================*/
+ void *ptr) /* in: number of bytes */
+{
+#ifdef HAVE_LARGE_PAGES
+ if (os_use_large_pages && os_large_page_size
+#ifdef UNIV_LINUX
+ && !shmdt(ptr)
+#endif
+ ) {
+ return;
+ }
+#endif
+
+ ut_free(ptr);
+}
+
+/********************************************************************
Sets the priority boost for threads released from waiting within the current
process. */
diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c
index 0278e3b2b66..847d0ee1cc7 100644
--- a/innobase/os/os0thread.c
+++ b/innobase/os/os0thread.c
@@ -88,7 +88,7 @@ os_thread_create(
/*=============*/
/* out: handle to the thread */
#ifndef __WIN__
- os_posix_f_t start_f,
+ os_posix_f_t start_f,
#else
ulint (*start_f)(void*), /* in: pointer to function
from which to start */
diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c
index 459ab986610..7738f5a34f0 100644
--- a/innobase/page/page0cur.c
+++ b/innobase/page/page0cur.c
@@ -29,7 +29,9 @@ UNIV_INLINE
ibool
page_cur_try_search_shortcut(
/*=========================*/
+ /* out: TRUE on success */
page_t* page, /* in: index page */
+ dict_index_t* index, /* in: record descriptor */
dtuple_t* tuple, /* in: data tuple */
ulint* iup_matched_fields,
/* in/out: already matched fields in upper
@@ -55,9 +57,17 @@ page_cur_try_search_shortcut(
#ifdef UNIV_SEARCH_DEBUG
page_cur_t cursor2;
#endif
+ ibool success = FALSE;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
ut_ad(dtuple_check_typed(tuple));
rec = page_header_get_ptr(page, PAGE_LAST_INSERT);
+ offsets = rec_get_offsets(rec, index, offsets,
+ dtuple_get_n_fields(tuple), &heap);
ut_ad(rec);
ut_ad(page_rec_is_user_rec(rec));
@@ -69,26 +79,26 @@ page_cur_try_search_shortcut(
up_match = low_match;
up_bytes = low_bytes;
- cmp = page_cmp_dtuple_rec_with_match(tuple, rec, &low_match,
+ cmp = page_cmp_dtuple_rec_with_match(tuple, rec, offsets, &low_match,
&low_bytes);
if (cmp == -1) {
-
- return(FALSE);
+ goto exit_func;
}
next_rec = page_rec_get_next(rec);
+ offsets = rec_get_offsets(next_rec, index, offsets,
+ dtuple_get_n_fields(tuple), &heap);
- cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec, &up_match,
- &up_bytes);
+ cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec, offsets,
+ &up_match, &up_bytes);
if (cmp != -1) {
-
- return(FALSE);
+ goto exit_func;
}
cursor->rec = rec;
#ifdef UNIV_SEARCH_DEBUG
- page_cur_search_with_match(page, tuple, PAGE_CUR_DBG,
+ page_cur_search_with_match(page, index, tuple, PAGE_CUR_DBG,
iup_matched_fields,
iup_matched_bytes,
ilow_matched_fields,
@@ -117,7 +127,12 @@ page_cur_try_search_shortcut(
#ifdef UNIV_SEARCH_PERF_STAT
page_cur_short_succ++;
#endif
- return(TRUE);
+ success = TRUE;
+exit_func:
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(success);
}
#endif
@@ -130,22 +145,24 @@ static
ibool
page_cur_rec_field_extends(
/*=======================*/
- /* out: TRUE if rec field extends tuple
- field */
- dtuple_t* tuple, /* in: data tuple */
- rec_t* rec, /* in: record */
- ulint n) /* in: compare nth field */
+ /* out: TRUE if rec field
+ extends tuple field */
+ dtuple_t* tuple, /* in: data tuple */
+ rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint n) /* in: compare nth field */
{
dtype_t* type;
dfield_t* dfield;
byte* rec_f;
ulint rec_f_len;
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
dfield = dtuple_get_nth_field(tuple, n);
type = dfield_get_type(dfield);
- rec_f = rec_get_nth_field(rec, n, &rec_f_len);
+ rec_f = rec_get_nth_field(rec, offsets, n, &rec_f_len);
if (type->mtype == DATA_VARCHAR
|| type->mtype == DATA_CHAR
@@ -176,6 +193,7 @@ void
page_cur_search_with_match(
/*=======================*/
page_t* page, /* in: index page */
+ dict_index_t* index, /* in: record descriptor */
dtuple_t* tuple, /* in: data tuple */
ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
or PAGE_CUR_GE */
@@ -212,6 +230,11 @@ page_cur_search_with_match(
ulint dbg_matched_fields;
ulint dbg_matched_bytes;
#endif
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
ut_ad(page && tuple && iup_matched_fields && iup_matched_bytes
&& ilow_matched_fields && ilow_matched_bytes && cursor);
ut_ad(dtuple_validate(tuple));
@@ -229,7 +252,7 @@ page_cur_search_with_match(
&& (page_header_get_ptr(page, PAGE_LAST_INSERT))
&& (page_header_get_field(page, PAGE_DIRECTION) == PAGE_RIGHT)) {
- if (page_cur_try_search_shortcut(page, tuple,
+ if (page_cur_try_search_shortcut(page, index, tuple,
iup_matched_fields,
iup_matched_bytes,
ilow_matched_fields,
@@ -279,7 +302,10 @@ page_cur_search_with_match(
low_matched_fields, low_matched_bytes,
up_matched_fields, up_matched_bytes);
- cmp = cmp_dtuple_rec_with_match(tuple, mid_rec,
+ offsets = rec_get_offsets(mid_rec, index, offsets,
+ dtuple_get_n_fields_cmp(tuple), &heap);
+
+ cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets,
&cur_matched_fields,
&cur_matched_bytes);
if (cmp == 1) {
@@ -288,10 +314,9 @@ page_cur_search_with_match(
low_matched_bytes = cur_matched_bytes;
} else if (cmp == -1) {
-
if (mode == PAGE_CUR_LE_OR_EXTENDS
&& page_cur_rec_field_extends(tuple, mid_rec,
- cur_matched_fields)) {
+ offsets, cur_matched_fields)) {
low = mid;
low_matched_fields = cur_matched_fields;
low_matched_bytes = cur_matched_bytes;
@@ -329,7 +354,10 @@ page_cur_search_with_match(
low_matched_fields, low_matched_bytes,
up_matched_fields, up_matched_bytes);
- cmp = cmp_dtuple_rec_with_match(tuple, mid_rec,
+ offsets = rec_get_offsets(mid_rec, index, offsets,
+ dtuple_get_n_fields_cmp(tuple), &heap);
+
+ cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets,
&cur_matched_fields,
&cur_matched_bytes);
if (cmp == 1) {
@@ -340,7 +368,7 @@ page_cur_search_with_match(
} else if (cmp == -1) {
if (mode == PAGE_CUR_LE_OR_EXTENDS
&& page_cur_rec_field_extends(tuple, mid_rec,
- cur_matched_fields)) {
+ offsets, cur_matched_fields)) {
low_rec = mid_rec;
low_matched_fields = cur_matched_fields;
low_matched_bytes = cur_matched_bytes;
@@ -368,7 +396,9 @@ page_cur_search_with_match(
dbg_matched_fields = 0;
dbg_matched_bytes = 0;
- dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, low_rec,
+ offsets = rec_get_offsets(low_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, low_rec, offsets,
&dbg_matched_fields,
&dbg_matched_bytes);
if (mode == PAGE_CUR_G) {
@@ -390,7 +420,9 @@ page_cur_search_with_match(
dbg_matched_fields = 0;
dbg_matched_bytes = 0;
- dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, up_rec,
+ offsets = rec_get_offsets(up_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, up_rec, offsets,
&dbg_matched_fields,
&dbg_matched_bytes);
if (mode == PAGE_CUR_G) {
@@ -419,6 +451,9 @@ 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) {
+ mem_heap_free(heap);
+ }
}
/***************************************************************
@@ -463,10 +498,12 @@ static
void
page_cur_insert_rec_write_log(
/*==========================*/
- rec_t* insert_rec, /* in: inserted physical record */
- ulint rec_size, /* in: insert_rec size */
- rec_t* cursor_rec, /* in: record the cursor is pointing to */
- mtr_t* mtr) /* in: mini-transaction handle */
+ rec_t* insert_rec, /* in: inserted physical record */
+ ulint rec_size, /* in: insert_rec size */
+ rec_t* cursor_rec, /* in: record the
+ cursor is pointing to */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mini-transaction handle */
{
ulint cur_rec_size;
ulint extra_size;
@@ -476,22 +513,36 @@ page_cur_insert_rec_write_log(
byte* cur_ptr;
ulint extra_info_yes;
byte* log_ptr;
+ byte* log_end;
ulint i;
ut_a(rec_size < UNIV_PAGE_SIZE);
- ut_ad(rec_size == rec_get_size(insert_rec));
- log_ptr = mlog_open(mtr, 30 + MLOG_BUF_MARGIN);
+ {
+ mem_heap_t* heap = NULL;
+ ulint cur_offs_[REC_OFFS_NORMAL_SIZE];
+ ulint ins_offs_[REC_OFFS_NORMAL_SIZE];
- if (log_ptr == NULL) {
+ ulint* cur_offs;
+ ulint* ins_offs;
- return;
- }
+ *cur_offs_ = (sizeof cur_offs_) / sizeof *cur_offs_;
+ *ins_offs_ = (sizeof ins_offs_) / sizeof *ins_offs_;
- extra_size = rec_get_extra_size(insert_rec);
+ cur_offs = rec_get_offsets(cursor_rec, index, cur_offs_,
+ ULINT_UNDEFINED, &heap);
+ ins_offs = rec_get_offsets(insert_rec, index, ins_offs_,
+ ULINT_UNDEFINED, &heap);
- cur_extra_size = rec_get_extra_size(cursor_rec);
- cur_rec_size = rec_get_size(cursor_rec);
+ extra_size = rec_offs_extra_size(ins_offs);
+ cur_extra_size = rec_offs_extra_size(cur_offs);
+ ut_ad(rec_size == rec_offs_size(ins_offs));
+ cur_rec_size = rec_offs_size(cur_offs);
+
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ }
ins_ptr = insert_rec - extra_size;
@@ -514,7 +565,9 @@ page_cur_insert_rec_write_log(
ins_ptr++;
cur_ptr++;
} else if ((i < extra_size)
- && (i >= extra_size - REC_N_EXTRA_BYTES)) {
+ && (i >= extra_size - (index->table->comp
+ ? REC_N_NEW_EXTRA_BYTES
+ : REC_N_OLD_EXTRA_BYTES))) {
i = extra_size;
ins_ptr = insert_rec;
cur_ptr = cursor_rec;
@@ -525,16 +578,35 @@ page_cur_insert_rec_write_log(
}
if (mtr_get_log_mode(mtr) != MTR_LOG_SHORT_INSERTS) {
-
- log_ptr = mlog_write_initial_log_record_fast(insert_rec,
- MLOG_REC_INSERT, log_ptr, mtr);
+
+ log_ptr = mlog_open_and_write_index(mtr, insert_rec, index,
+ index->table->comp
+ ? MLOG_COMP_REC_INSERT : MLOG_REC_INSERT,
+ 2 + 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN);
+
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash
+ recovery: in that case mlog_open returns NULL */
+ return;
+ }
+
+ log_end = &log_ptr[2 + 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
/* Write the cursor rec offset as a 2-byte ulint */
mach_write_to_2(log_ptr, cursor_rec
- buf_frame_align(cursor_rec));
log_ptr += 2;
+ } else {
+ log_ptr = mlog_open(mtr, 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN);
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash
+ recovery: in that case mlog_open returns NULL */
+ return;
+ }
+ log_end = &log_ptr[5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
}
- if ((rec_get_info_bits(insert_rec) != rec_get_info_bits(cursor_rec))
+ if ((rec_get_info_and_status_bits(insert_rec, index->table->comp) !=
+ rec_get_info_and_status_bits(cursor_rec, index->table->comp))
|| (extra_size != cur_extra_size)
|| (rec_size != cur_rec_size)) {
@@ -549,7 +621,9 @@ page_cur_insert_rec_write_log(
+ extra_info_yes);
if (extra_info_yes) {
/* Write the info bits */
- mach_write_to_1(log_ptr, rec_get_info_bits(insert_rec));
+ mach_write_to_1(log_ptr,
+ rec_get_info_and_status_bits(insert_rec,
+ index->table->comp));
log_ptr++;
/* Write the record origin offset */
@@ -565,17 +639,15 @@ page_cur_insert_rec_write_log(
/* Write to the log the inserted index record end segment which
differs from the cursor record */
- if (rec_size - i < MLOG_BUF_MARGIN) {
- ut_memcpy(log_ptr, ins_ptr, rec_size - i);
- log_ptr += rec_size - i;
- }
-
- mlog_close(mtr, log_ptr);
+ rec_size -= i;
- ut_a(rec_size - i < UNIV_PAGE_SIZE);
-
- if (rec_size - i >= MLOG_BUF_MARGIN) {
- mlog_catenate_string(mtr, ins_ptr, rec_size - i);
+ if (log_ptr + rec_size <= log_end) {
+ memcpy(log_ptr, ins_ptr, rec_size);
+ mlog_close(mtr, log_ptr + rec_size);
+ } else {
+ mlog_close(mtr, log_ptr);
+ ut_a(rec_size < UNIV_PAGE_SIZE);
+ mlog_catenate_string(mtr, ins_ptr, rec_size);
}
}
@@ -585,12 +657,13 @@ Parses a log record of a record insert on a page. */
byte*
page_cur_parse_insert_rec(
/*======================*/
- /* out: end of log record or NULL */
- ibool is_short,/* in: TRUE if short inserts */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
+ /* out: end of log record or NULL */
+ ibool is_short,/* in: TRUE if short inserts */
+ byte* ptr, /* in: buffer */
+ byte* end_ptr,/* in: buffer end */
+ dict_index_t* index, /* in: record descriptor */
+ page_t* page, /* in: page or NULL */
+ mtr_t* mtr) /* in: mtr or NULL */
{
ulint extra_info_yes;
ulint offset = 0; /* remove warning */
@@ -601,8 +674,12 @@ page_cur_parse_insert_rec(
byte buf1[1024];
byte* buf;
byte* ptr2 = ptr;
- ulint info_bits = 0; /* remove warning */
+ ulint info_and_status_bits = 0; /* remove warning */
page_cur_t cursor;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
if (!is_short) {
/* Read the cursor rec offset as a 2-byte ulint */
@@ -648,7 +725,7 @@ page_cur_parse_insert_rec(
return(NULL);
}
- info_bits = mach_read_from_1(ptr);
+ info_and_status_bits = mach_read_from_1(ptr);
ptr++;
ptr = mach_parse_compressed(ptr, end_ptr, &origin_offset);
@@ -689,11 +766,15 @@ page_cur_parse_insert_rec(
cursor_rec = page + offset;
}
+ offsets = rec_get_offsets(cursor_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
if (extra_info_yes == 0) {
- info_bits = rec_get_info_bits(cursor_rec);
- origin_offset = rec_get_extra_size(cursor_rec);
- mismatch_index = rec_get_size(cursor_rec) - end_seg_len;
- }
+ info_and_status_bits = rec_get_info_and_status_bits(
+ cursor_rec, index->table->comp);
+ origin_offset = rec_offs_extra_size(offsets);
+ mismatch_index = rec_offs_size(offsets) - end_seg_len;
+ }
if (mismatch_index + end_seg_len < sizeof buf1) {
buf = buf1;
@@ -705,11 +786,12 @@ page_cur_parse_insert_rec(
if (mismatch_index >= UNIV_PAGE_SIZE) {
fprintf(stderr,
- "Is short %lu, info_bits %lu, offset %lu, "
+ "Is short %lu, info_and_status_bits %lu, offset %lu, "
"o_offset %lu\n"
"mismatch index %lu, end_seg_len %lu\n"
"parsed len %lu\n",
- (ulong) is_short, (ulong) info_bits, (ulong) offset,
+ (ulong) is_short, (ulong) info_and_status_bits,
+ (ulong) offset,
(ulong) origin_offset,
(ulong) mismatch_index, (ulong) end_seg_len,
(ulong) (ptr - ptr2));
@@ -722,20 +804,27 @@ page_cur_parse_insert_rec(
ut_error;
}
- ut_memcpy(buf, rec_get_start(cursor_rec), mismatch_index);
+ ut_memcpy(buf, rec_get_start(cursor_rec, offsets), mismatch_index);
ut_memcpy(buf + mismatch_index, ptr, end_seg_len);
- rec_set_info_bits(buf + origin_offset, info_bits);
+ rec_set_info_and_status_bits(buf + origin_offset, index->table->comp,
+ info_and_status_bits);
page_cur_position(cursor_rec, &cursor);
- page_cur_rec_insert(&cursor, buf + origin_offset, mtr);
+ offsets = rec_get_offsets(buf + origin_offset, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ page_cur_rec_insert(&cursor, buf + origin_offset, index, offsets, mtr);
if (buf != buf1) {
mem_free(buf);
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
+
return(ptr + end_seg_len);
}
@@ -751,68 +840,85 @@ page_cur_insert_rec_low(
/* out: pointer to record if succeed, NULL
otherwise */
page_cur_t* cursor, /* in: a page cursor */
- dtuple_t* tuple, /* in: pointer to a data tuple or NULL */
- ulint data_size,/* in: data size of tuple */
- rec_t* rec, /* in: pointer to a physical record or NULL */
+ dtuple_t* tuple, /* in: pointer to a data tuple or NULL */
+ dict_index_t* index, /* in: record descriptor */
+ rec_t* rec, /* in: pointer to a physical record or NULL */
+ ulint* offsets,/* in: rec_get_offsets(rec, index) or NULL */
mtr_t* mtr) /* in: mini-transaction handle */
{
- byte* insert_buf = NULL;
- ulint rec_size;
- byte* page; /* the relevant page */
- rec_t* last_insert; /* cursor position at previous insert */
- rec_t* insert_rec; /* inserted record */
- ulint heap_no; /* heap number of the inserted record */
- rec_t* current_rec; /* current record after which the
- new record is inserted */
- rec_t* next_rec; /* next record after current before
- the insertion */
- ulint owner_slot; /* the slot which owns the inserted record */
- rec_t* owner_rec;
- ulint n_owned;
-
+ byte* insert_buf = NULL;
+ ulint rec_size;
+ byte* page; /* the relevant page */
+ rec_t* last_insert; /* cursor position at previous insert */
+ rec_t* insert_rec; /* inserted record */
+ ulint heap_no; /* heap number of the inserted record */
+ rec_t* current_rec; /* current record after which the
+ new record is inserted */
+ rec_t* next_rec; /* next record after current before
+ the insertion */
+ ulint owner_slot; /* the slot which owns the
+ inserted record */
+ rec_t* owner_rec;
+ ulint n_owned;
+ mem_heap_t* heap = NULL;
+ ibool comp = index->table->comp;
+
ut_ad(cursor && mtr);
ut_ad(tuple || rec);
ut_ad(!(tuple && rec));
ut_ad(rec || dtuple_check_typed(tuple));
- ut_ad(rec || (dtuple_get_data_size(tuple) == data_size));
page = page_cur_get_page(cursor);
+ ut_ad(page_is_comp(page) == comp);
+
ut_ad(cursor->rec != page_get_supremum_rec(page));
/* 1. Get the size of the physical record in the page */
if (tuple != NULL) {
- rec_size = data_size + rec_get_converted_extra_size(
- data_size,
- dtuple_get_n_fields(tuple));
+ rec_size = rec_get_converted_size(index, tuple);
} else {
- rec_size = rec_get_size(rec);
+ if (!offsets) {
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ }
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ rec_size = rec_offs_size(offsets);
}
/* 2. Try to find suitable space from page memory management */
- insert_buf = page_mem_alloc(page, rec_size, &heap_no);
+ insert_buf = page_mem_alloc(page, rec_size, index, &heap_no);
if (insert_buf == NULL) {
-
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(NULL);
}
/* 3. Create the record */
if (tuple != NULL) {
- insert_rec = rec_convert_dtuple_to_rec_low(insert_buf, tuple,
- data_size);
+ insert_rec = rec_convert_dtuple_to_rec(insert_buf,
+ index, tuple);
+ offsets = rec_get_offsets(insert_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
} else {
- insert_rec = rec_copy(insert_buf, rec);
+ insert_rec = rec_copy(insert_buf, rec, offsets);
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ rec_offs_make_valid(insert_rec, index, offsets);
}
ut_ad(insert_rec);
- ut_ad(rec_size == rec_get_size(insert_rec));
+ ut_ad(rec_size == rec_offs_size(offsets));
/* 4. Insert the record in the linked list of records */
-
current_rec = cursor->rec;
+ ut_ad(!comp || rec_get_status(current_rec) <= REC_STATUS_INFIMUM);
+ ut_ad(!comp || rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
+
next_rec = page_rec_get_next(current_rec);
+ ut_ad(!comp || rec_get_status(next_rec) != REC_STATUS_INFIMUM);
page_rec_set_next(insert_rec, next_rec);
page_rec_set_next(current_rec, insert_rec);
@@ -821,12 +927,15 @@ page_cur_insert_rec_low(
/* 5. Set the n_owned field in the inserted record to zero,
and set the heap_no field */
- rec_set_n_owned(insert_rec, 0);
- rec_set_heap_no(insert_rec, heap_no);
+ rec_set_n_owned(insert_rec, comp, 0);
+ rec_set_heap_no(insert_rec, comp, heap_no);
/* 6. Update the last insertion info in page header */
last_insert = page_header_get_ptr(page, PAGE_LAST_INSERT);
+ ut_ad(!last_insert || !comp
+ || rec_get_node_ptr_flag(last_insert)
+ == rec_get_node_ptr_flag(insert_rec));
if (last_insert == NULL) {
page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
@@ -855,8 +964,8 @@ page_cur_insert_rec_low(
/* 7. It remains to update the owner record. */
owner_rec = page_rec_find_owner_rec(insert_rec);
- n_owned = rec_get_n_owned(owner_rec);
- rec_set_n_owned(owner_rec, n_owned + 1);
+ n_owned = rec_get_n_owned(owner_rec, comp);
+ rec_set_n_owned(owner_rec, comp, n_owned + 1);
/* 8. Now we have incremented the n_owned field of the owner
record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED,
@@ -868,8 +977,12 @@ page_cur_insert_rec_low(
}
/* 9. Write log record of the insert */
- page_cur_insert_rec_write_log(insert_rec, rec_size, current_rec, mtr);
+ page_cur_insert_rec_write_log(insert_rec, rec_size, current_rec,
+ index, mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(insert_rec);
}
@@ -879,17 +992,19 @@ UNIV_INLINE
byte*
page_copy_rec_list_to_created_page_write_log(
/*=========================================*/
- /* out: 4-byte field where to write the log data
- length */
- page_t* page, /* in: index page */
- mtr_t* mtr) /* in: mtr */
+ /* out: 4-byte field where to
+ write the log data length */
+ page_t* page, /* in: index page */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
byte* log_ptr;
-
- mlog_write_initial_log_record(page, MLOG_LIST_END_COPY_CREATED, mtr);
-
- log_ptr = mlog_open(mtr, 4);
+ log_ptr = mlog_open_and_write_index(mtr, page, index,
+ index->table->comp
+ ? MLOG_COMP_LIST_END_COPY_CREATED
+ : MLOG_LIST_END_COPY_CREATED, 4);
+ ut_a(log_ptr);
mlog_close(mtr, log_ptr + 4);
return(log_ptr);
@@ -901,11 +1016,12 @@ Parses a log record of copying a record list end to a new created page. */
byte*
page_parse_copy_rec_list_to_created_page(
/*=====================================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
+ /* 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 */
+ mtr_t* mtr) /* in: mtr or NULL */
{
byte* rec_end;
ulint log_data_len;
@@ -931,7 +1047,8 @@ page_parse_copy_rec_list_to_created_page(
}
while (ptr < rec_end) {
- ptr = page_cur_parse_insert_rec(TRUE, ptr, end_ptr, page, mtr);
+ ptr = page_cur_parse_insert_rec(TRUE, ptr, end_ptr,
+ index, page, mtr);
}
ut_a(ptr == rec_end);
@@ -950,10 +1067,11 @@ including that record. Infimum and supremum records are not copied. */
void
page_copy_rec_list_end_to_created_page(
/*===================================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: first record to copy */
- mtr_t* mtr) /* in: mtr */
+ page_t* new_page, /* in: index page to copy to */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: first record to copy */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
page_dir_slot_t* slot = 0; /* remove warning */
byte* heap_top;
@@ -966,9 +1084,15 @@ page_copy_rec_list_end_to_created_page(
ulint log_mode;
byte* log_ptr;
ulint log_data_len;
+ ibool comp = page_is_comp(page);
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
- ut_ad(page_header_get_field(new_page, PAGE_N_HEAP) == 2);
+ ut_ad(page_dir_get_n_heap(new_page) == 2);
ut_ad(page != new_page);
+ ut_ad(comp == page_is_comp(new_page));
if (rec == page_get_infimum_rec(page)) {
@@ -983,12 +1107,13 @@ page_copy_rec_list_end_to_created_page(
#ifdef UNIV_DEBUG
/* To pass the debug tests we have to set these dummy values
in the debug version */
- page_header_set_field(new_page, PAGE_N_DIR_SLOTS, UNIV_PAGE_SIZE / 2);
+ page_dir_set_n_slots(new_page, UNIV_PAGE_SIZE / 2);
page_header_set_ptr(new_page, PAGE_HEAP_TOP,
new_page + UNIV_PAGE_SIZE - 1);
#endif
- log_ptr = page_copy_rec_list_to_created_page_write_log(new_page, mtr);
+ log_ptr = page_copy_rec_list_to_created_page_write_log(new_page,
+ index, mtr);
log_data_len = dyn_array_get_data_size(&(mtr->log));
@@ -997,22 +1122,27 @@ page_copy_rec_list_end_to_created_page(
log_mode = mtr_set_log_mode(mtr, MTR_LOG_SHORT_INSERTS);
prev_rec = page_get_infimum_rec(new_page);
- heap_top = new_page + PAGE_SUPREMUM_END;
+ if (comp) {
+ heap_top = new_page + PAGE_NEW_SUPREMUM_END;
+ } else {
+ heap_top = new_page + PAGE_OLD_SUPREMUM_END;
+ }
count = 0;
slot_index = 0;
n_recs = 0;
/* should be do ... until, comment by Jani */
while (rec != page_get_supremum_rec(page)) {
-
- insert_rec = rec_copy(heap_top, rec);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ insert_rec = rec_copy(heap_top, rec, offsets);
- rec_set_next_offs(prev_rec, insert_rec - new_page);
+ rec_set_next_offs(prev_rec, comp, insert_rec - new_page);
- rec_set_n_owned(insert_rec, 0);
- rec_set_heap_no(insert_rec, 2 + n_recs);
+ rec_set_n_owned(insert_rec, comp, 0);
+ rec_set_heap_no(insert_rec, comp, 2 + n_recs);
- rec_size = rec_get_size(insert_rec);
+ rec_size = rec_offs_size(offsets);
heap_top = heap_top + rec_size;
@@ -1034,7 +1164,7 @@ page_copy_rec_list_end_to_created_page(
}
page_cur_insert_rec_write_log(insert_rec, rec_size, prev_rec,
- mtr);
+ index, mtr);
prev_rec = insert_rec;
rec = page_rec_get_next(rec);
}
@@ -1056,22 +1186,27 @@ page_copy_rec_list_end_to_created_page(
slot_index--;
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
+
log_data_len = dyn_array_get_data_size(&(mtr->log)) - log_data_len;
ut_a(log_data_len < 100 * UNIV_PAGE_SIZE);
mach_write_to_4(log_ptr, log_data_len);
- rec_set_next_offs(insert_rec, PAGE_SUPREMUM);
+ rec_set_next_offs(insert_rec, comp,
+ comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM);
slot = page_dir_get_nth_slot(new_page, 1 + slot_index);
page_dir_slot_set_rec(slot, page_get_supremum_rec(new_page));
page_dir_slot_set_n_owned(slot, count + 1);
- page_header_set_field(new_page, PAGE_N_DIR_SLOTS, 2 + slot_index);
+ page_dir_set_n_slots(new_page, 2 + slot_index);
page_header_set_ptr(new_page, PAGE_HEAP_TOP, heap_top);
- page_header_set_field(new_page, PAGE_N_HEAP, 2 + n_recs);
+ page_dir_set_n_heap(new_page, 2 + n_recs);
page_header_set_field(new_page, PAGE_N_RECS, n_recs);
page_header_set_ptr(new_page, PAGE_LAST_INSERT, NULL);
@@ -1089,14 +1224,27 @@ UNIV_INLINE
void
page_cur_delete_rec_write_log(
/*==========================*/
- rec_t* cursor_rec, /* in: record to be deleted */
- mtr_t* mtr) /* in: mini-transaction handle */
+ rec_t* rec, /* in: record to be deleted */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mini-transaction handle */
{
- mlog_write_initial_log_record(cursor_rec, MLOG_REC_DELETE, mtr);
+ byte* log_ptr;
+
+ log_ptr = mlog_open_and_write_index(mtr, rec, index,
+ index->table->comp
+ ? MLOG_COMP_REC_DELETE
+ : MLOG_REC_DELETE, 2);
+
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash recovery:
+ in that case mlog_open returns NULL */
+ return;
+ }
/* Write the cursor rec offset as a 2-byte ulint */
- mlog_catenate_ulint(mtr, cursor_rec - buf_frame_align(cursor_rec),
- MLOG_2BYTES);
+ mach_write_to_2(log_ptr, rec - buf_frame_align(rec));
+
+ mlog_close(mtr, log_ptr + 2);
}
/***************************************************************
@@ -1105,11 +1253,12 @@ Parses log record of a record delete on a page. */
byte*
page_cur_parse_delete_rec(
/*======================*/
- /* out: pointer to record end or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
+ /* out: pointer to record end 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 */
+ mtr_t* mtr) /* in: mtr or NULL */
{
ulint offset;
page_cur_t cursor;
@@ -1126,9 +1275,19 @@ page_cur_parse_delete_rec(
ut_a(offset <= UNIV_PAGE_SIZE);
if (page) {
- page_cur_position(page + offset, &cursor);
-
- page_cur_delete_rec(&cursor, mtr);
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ rec_t* rec = page + offset;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ page_cur_position(rec, &cursor);
+
+ page_cur_delete_rec(&cursor, index,
+ rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap), mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
return(ptr);
@@ -1142,6 +1301,8 @@ void
page_cur_delete_rec(
/*================*/
page_cur_t* cursor, /* in: a page cursor */
+ dict_index_t* index, /* in: record descriptor */
+ const ulint* offsets,/* in: rec_get_offsets(cursor->rec, index) */
mtr_t* mtr) /* in: mini-transaction handle */
{
page_dir_slot_t* cur_dir_slot;
@@ -1158,6 +1319,7 @@ page_cur_delete_rec(
page = page_cur_get_page(cursor);
current_rec = cursor->rec;
+ ut_ad(rec_offs_validate(current_rec, index, offsets));
/* The record must not be the supremum or infimum record. */
ut_ad(current_rec != page_get_supremum_rec(page));
@@ -1169,7 +1331,7 @@ page_cur_delete_rec(
cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot);
/* 0. Write the log record */
- page_cur_delete_rec_write_log(current_rec, mtr);
+ page_cur_delete_rec_write_log(current_rec, index, mtr);
/* 1. Reset the last insert info in the page header and increment
the modify clock for the frame */
@@ -1223,7 +1385,7 @@ page_cur_delete_rec(
page_dir_slot_set_n_owned(cur_dir_slot, cur_n_owned - 1);
/* 6. Free the memory occupied by the record */
- page_mem_free(page, current_rec);
+ page_mem_free(page, current_rec, offsets);
/* 7. Now we have decremented the number of owned records of the slot.
If the number drops below PAGE_DIR_SLOT_MIN_N_OWNED, we balance the
diff --git a/innobase/page/page0page.c b/innobase/page/page0page.c
index 343f300fc77..f3217e91f58 100644
--- a/innobase/page/page0page.c
+++ b/innobase/page/page0page.c
@@ -18,6 +18,8 @@ Created 2/2/1994 Heikki Tuuri
#include "fut0lst.h"
#include "btr0sea.h"
#include "buf0buf.h"
+#include "srv0srv.h"
+#include "btr0btr.h"
/* THE INDEX PAGE
==============
@@ -75,10 +77,14 @@ page_dir_find_owner_slot(
page_t* page;
page_dir_slot_t* slot;
rec_t* original_rec = rec;
+ ibool comp;
ut_ad(page_rec_check(rec));
- while (rec_get_n_owned(rec) == 0) {
+ 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);
}
@@ -96,14 +102,22 @@ page_dir_find_owner_slot(
"InnoDB: Original record ",
(ulong) buf_frame_get_page_no(page));
- rec_print(stderr, original_rec);
+ if (comp) {
+ fputs("(compact record)", stderr);
+ } else {
+ rec_print_old(stderr, original_rec);
+ }
fprintf(stderr, "\n"
"InnoDB: on that page. Steps %lu.\n", (ulong) steps);
fputs(
"InnoDB: Cannot find the dir slot for record ",
stderr);
- rec_print(stderr, rec);
+ if (comp) {
+ fputs("(compact record)", stderr);
+ } else {
+ rec_print_old(stderr, rec);
+ }
fputs("\n"
"InnoDB: on that page!\n", stderr);
@@ -136,14 +150,15 @@ page_dir_slot_check(
page = buf_frame_align(slot);
- n_slots = page_header_get_field(page, PAGE_N_DIR_SLOTS);
+ n_slots = page_dir_get_n_slots(page);
ut_a(slot <= page_dir_get_nth_slot(page, 0));
ut_a(slot >= page_dir_get_nth_slot(page, n_slots - 1));
- ut_a(page_rec_check(page + mach_read_from_2(slot)));
+ ut_a(page_rec_check(page_dir_slot_get_rec(slot)));
- n_owned = rec_get_n_owned(page + mach_read_from_2(slot));
+ n_owned = rec_get_n_owned(page_dir_slot_get_rec(slot),
+ page_is_comp(page));
if (slot == page_dir_get_nth_slot(page, 0)) {
ut_a(n_owned == 1);
@@ -194,12 +209,14 @@ Allocates a block of memory from an index page. */
byte*
page_mem_alloc(
/*===========*/
- /* out: pointer to start of allocated
- buffer, or NULL if allocation fails */
- page_t* page, /* in: index page */
- ulint need, /* in: number of bytes needed */
- ulint* heap_no)/* out: this contains the heap number
- of the allocated record if allocation succeeds */
+ /* out: pointer to start of allocated
+ buffer, or NULL if allocation fails */
+ page_t* page, /* in: index page */
+ ulint need, /* in: number of bytes needed */
+ dict_index_t* index, /* in: record descriptor */
+ ulint* heap_no)/* out: this contains the heap number
+ of the allocated record
+ if allocation succeeds */
{
rec_t* rec;
byte* block;
@@ -213,18 +230,37 @@ page_mem_alloc(
rec = page_header_get_ptr(page, PAGE_FREE);
- if (rec && (rec_get_size(rec) >= need)) {
+ if (rec) {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
+ if (rec_offs_size(offsets) >= need) {
+ page_header_set_ptr(page, PAGE_FREE,
+ page_rec_get_next(rec));
- page_header_set_ptr(page, PAGE_FREE, page_rec_get_next(rec));
+ garbage = page_header_get_field(page, PAGE_GARBAGE);
+ ut_ad(garbage >= need);
- garbage = page_header_get_field(page, PAGE_GARBAGE);
- ut_ad(garbage >= need);
+ page_header_set_field(page, PAGE_GARBAGE,
+ garbage - need);
- page_header_set_field(page, PAGE_GARBAGE, garbage - need);
+ *heap_no = rec_get_heap_no(rec, page_is_comp(page));
- *heap_no = rec_get_heap_no(rec);
+ block = rec_get_start(rec, offsets);
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(block);
+ }
- return(rec_get_start(rec));
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
/* Could not find space from the free list, try top of heap */
@@ -235,9 +271,9 @@ page_mem_alloc(
block = page_header_get_ptr(page, PAGE_HEAP_TOP);
page_header_set_ptr(page, PAGE_HEAP_TOP, block + need);
- *heap_no = page_header_get_field(page, PAGE_N_HEAP);
+ *heap_no = page_dir_get_n_heap(page);
- page_header_set_field(page, PAGE_N_HEAP, 1 + *heap_no);
+ page_dir_set_n_heap(page, 1 + *heap_no);
return(block);
}
@@ -253,9 +289,11 @@ page_create_write_log(
/*==================*/
buf_frame_t* frame, /* in: a buffer frame where the page is
created */
- mtr_t* mtr) /* in: mini-transaction handle */
+ mtr_t* mtr, /* in: mini-transaction handle */
+ ibool comp) /* in: TRUE=compact page format */
{
- mlog_write_initial_log_record(frame, MLOG_PAGE_CREATE, mtr);
+ mlog_write_initial_log_record(frame,
+ comp ? MLOG_COMP_PAGE_CREATE : MLOG_PAGE_CREATE, mtr);
}
/***************************************************************
@@ -267,6 +305,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 */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
@@ -275,7 +314,7 @@ page_parse_create(
/* The record is empty, except for the record initial part */
if (page) {
- page_create(page, mtr);
+ page_create(page, mtr, comp);
}
return(ptr);
@@ -290,7 +329,8 @@ page_create(
/* out: pointer to the page */
buf_frame_t* frame, /* in: a buffer frame where the page is
created */
- mtr_t* mtr) /* in: mini-transaction handle */
+ mtr_t* mtr, /* in: mini-transaction handle */
+ ibool comp) /* in: TRUE=compact page format */
{
page_dir_slot_t* slot;
mem_heap_t* heap;
@@ -300,6 +340,10 @@ page_create(
rec_t* infimum_rec;
rec_t* supremum_rec;
page_t* page;
+ dict_index_t* index;
+ ulint* offsets;
+
+ index = comp ? srv_sys->dummy_ind2 : srv_sys->dummy_ind1;
ut_ad(frame && mtr);
ut_ad(PAGE_BTR_IBUF_FREE_LIST + FLST_BASE_NODE_SIZE
@@ -311,7 +355,7 @@ page_create(
buf_frame_modify_clock_inc(frame);
/* 2. WRITE LOG INFORMATION */
- page_create_write_log(frame, mtr);
+ page_create_write_log(frame, mtr, comp);
page = frame;
@@ -323,51 +367,61 @@ page_create(
/* Create first a data tuple for infimum record */
tuple = dtuple_create(heap, 1);
+ dtuple_set_info_bits(tuple, REC_STATUS_INFIMUM);
field = dtuple_get_nth_field(tuple, 0);
- dfield_set_data(field, "infimum", sizeof "infimum");
- dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 20, 0);
-
+ dfield_set_data(field, "infimum", 8);
+ dtype_set(dfield_get_type(field),
+ DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, 8, 0);
/* Set the corresponding physical record to its place in the page
record heap */
heap_top = page + PAGE_DATA;
- infimum_rec = rec_convert_dtuple_to_rec(heap_top, tuple);
+ infimum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple);
+
+ ut_a(infimum_rec ==
+ page + (comp ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
+
+ rec_set_n_owned(infimum_rec, comp, 1);
+ rec_set_heap_no(infimum_rec, comp, 0);
+ offsets = rec_get_offsets(infimum_rec, index, NULL,
+ ULINT_UNDEFINED, &heap);
+
+ heap_top = rec_get_end(infimum_rec, offsets);
- ut_a(infimum_rec == page + PAGE_INFIMUM);
-
- rec_set_n_owned(infimum_rec, 1);
- rec_set_heap_no(infimum_rec, 0);
-
- heap_top = rec_get_end(infimum_rec);
-
/* Create then a tuple for supremum */
tuple = dtuple_create(heap, 1);
+ dtuple_set_info_bits(tuple, REC_STATUS_SUPREMUM);
field = dtuple_get_nth_field(tuple, 0);
- dfield_set_data(field, "supremum", sizeof "supremum");
- dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 20, 0);
+ dfield_set_data(field, "supremum", 9 - comp);
+ dtype_set(dfield_get_type(field),
+ DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, 9 - comp, 0);
- supremum_rec = rec_convert_dtuple_to_rec(heap_top, tuple);
+ supremum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple);
- ut_a(supremum_rec == page + PAGE_SUPREMUM);
+ ut_a(supremum_rec ==
+ page + (comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM));
- rec_set_n_owned(supremum_rec, 1);
- rec_set_heap_no(supremum_rec, 1);
-
- heap_top = rec_get_end(supremum_rec);
+ rec_set_n_owned(supremum_rec, comp, 1);
+ rec_set_heap_no(supremum_rec, comp, 1);
- ut_ad(heap_top == page + PAGE_SUPREMUM_END);
+ offsets = rec_get_offsets(supremum_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ heap_top = rec_get_end(supremum_rec, offsets);
+
+ ut_ad(heap_top ==
+ page + (comp ? PAGE_NEW_SUPREMUM_END : PAGE_OLD_SUPREMUM_END));
mem_heap_free(heap);
- /* 4. INITIALIZE THE PAGE HEADER */
+ /* 4. INITIALIZE THE PAGE */
page_header_set_field(page, PAGE_N_DIR_SLOTS, 2);
page_header_set_ptr(page, PAGE_HEAP_TOP, heap_top);
- page_header_set_field(page, PAGE_N_HEAP, 2);
+ page_header_set_field(page, PAGE_N_HEAP, comp ? 0x8002 : 2);
page_header_set_ptr(page, PAGE_FREE, NULL);
page_header_set_field(page, PAGE_GARBAGE, 0);
page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
@@ -375,7 +429,9 @@ page_create(
page_header_set_field(page, PAGE_N_DIRECTION, 0);
page_header_set_field(page, PAGE_N_RECS, 0);
page_set_max_trx_id(page, ut_dulint_zero);
-
+ memset(heap_top, 0, UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START
+ - (heap_top - page));
+
/* 5. SET POINTERS IN RECORDS AND DIR SLOTS */
/* Set the slots to point to infimum and supremum. */
@@ -388,8 +444,8 @@ page_create(
/* Set the next pointers in infimum and supremum */
- rec_set_next_offs(infimum_rec, (ulint)(supremum_rec - page));
- rec_set_next_offs(supremum_rec, 0);
+ rec_set_next_offs(infimum_rec, comp, (ulint)(supremum_rec - page));
+ rec_set_next_offs(supremum_rec, comp, 0);
return(page);
}
@@ -401,14 +457,19 @@ touch the lock table and max trx id on page. */
void
page_copy_rec_list_end_no_locks(
/*============================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- mtr_t* mtr) /* in: mtr */
+ page_t* new_page, /* in: index page to copy to */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
page_cur_t cur1;
page_cur_t cur2;
rec_t* sup;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
page_cur_position(rec, &cur1);
@@ -416,8 +477,11 @@ page_copy_rec_list_end_no_locks(
page_cur_move_to_next(&cur1);
}
-
- ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == PAGE_INFIMUM);
+
+ ut_a(index->table->comp == page_is_comp(page));
+ ut_a(index->table->comp == page_is_comp(new_page));
+ ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
+ (index->table->comp ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
page_cur_set_before_first(new_page, &cur2);
@@ -426,8 +490,11 @@ page_copy_rec_list_end_no_locks(
sup = page_get_supremum_rec(page);
while (sup != page_cur_get_rec(&cur1)) {
- if (!page_cur_rec_insert(&cur2,
- page_cur_get_rec(&cur1), mtr)) {
+ rec_t* cur1_rec = page_cur_get_rec(&cur1);
+ offsets = rec_get_offsets(cur1_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ if (!page_cur_rec_insert(&cur2, cur1_rec, index,
+ offsets, mtr)) {
/* Track an assertion failure reported on the mailing
list on June 18th, 2003 */
@@ -446,7 +513,11 @@ page_copy_rec_list_end_no_locks(
page_cur_move_to_next(&cur1);
page_cur_move_to_next(&cur2);
}
-}
+
+ if (heap) {
+ mem_heap_free(heap);
+ }
+}
/*****************************************************************
Copies records from page to new_page, from a given record onward,
@@ -456,16 +527,18 @@ The records are copied to the start of the record list on new_page. */
void
page_copy_rec_list_end(
/*===================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- mtr_t* mtr) /* in: mtr */
+ page_t* new_page, /* in: index page to copy to */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
- if (page_header_get_field(new_page, PAGE_N_HEAP) == 2) {
+ if (page_dir_get_n_heap(new_page) == 2) {
page_copy_rec_list_end_to_created_page(new_page, page, rec,
- mtr);
+ index, mtr);
} else {
- page_copy_rec_list_end_no_locks(new_page, page, rec, mtr);
+ page_copy_rec_list_end_no_locks(new_page, page, rec,
+ index, mtr);
}
/* Update the lock table, MAX_TRX_ID, and possible hash index */
@@ -474,7 +547,7 @@ page_copy_rec_list_end(
page_update_max_trx_id(new_page, page_get_max_trx_id(page));
- btr_search_move_or_delete_hash_entries(new_page, page);
+ btr_search_move_or_delete_hash_entries(new_page, page, index);
}
/*****************************************************************
@@ -485,14 +558,19 @@ The records are copied to the end of the record list on new_page. */
void
page_copy_rec_list_start(
/*=====================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- mtr_t* mtr) /* in: mtr */
+ page_t* new_page, /* in: index page to copy to */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
page_cur_t cur1;
page_cur_t cur2;
rec_t* old_end;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
page_cur_set_before_first(page, &cur1);
@@ -510,8 +588,13 @@ page_copy_rec_list_start(
/* Copy records from the original page to the new page */
while (page_cur_get_rec(&cur1) != rec) {
- ut_a(
- page_cur_rec_insert(&cur2, page_cur_get_rec(&cur1), mtr));
+ rec_t* ins_rec;
+ rec_t* cur1_rec = page_cur_get_rec(&cur1);
+ offsets = rec_get_offsets(cur1_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ ins_rec = page_cur_rec_insert(&cur2, cur1_rec, index,
+ offsets, mtr);
+ ut_a(ins_rec);
page_cur_move_to_next(&cur1);
page_cur_move_to_next(&cur2);
@@ -523,8 +606,12 @@ page_copy_rec_list_start(
page_update_max_trx_id(new_page, page_get_max_trx_id(page));
- btr_search_move_or_delete_hash_entries(new_page, page);
-}
+ btr_search_move_or_delete_hash_entries(new_page, page, index);
+
+ if (heap) {
+ mem_heap_free(heap);
+ }
+}
/**************************************************************
Writes a log record of a record list end or start deletion. */
@@ -532,18 +619,25 @@ UNIV_INLINE
void
page_delete_rec_list_write_log(
/*===========================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- byte type, /* in: operation type: MLOG_LIST_END_DELETE, ... */
- mtr_t* mtr) /* in: mtr */
+ 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:
+ MLOG_LIST_END_DELETE, ... */
+ mtr_t* mtr) /* in: mtr */
{
- ut_ad((type == MLOG_LIST_END_DELETE)
- || (type == MLOG_LIST_START_DELETE));
-
- mlog_write_initial_log_record(page, type, mtr);
-
- /* Write the parameter as a 2-byte ulint */
- mlog_catenate_ulint(mtr, rec - page, MLOG_2BYTES);
+ byte* log_ptr;
+ ut_ad(type == MLOG_LIST_END_DELETE
+ || type == MLOG_LIST_START_DELETE
+ || type == MLOG_COMP_LIST_END_DELETE
+ || type == MLOG_COMP_LIST_START_DELETE);
+
+ log_ptr = mlog_open_and_write_index(mtr, page, index, type, 2);
+ if (log_ptr) {
+ /* Write the parameter as a 2-byte ulint */
+ mach_write_to_2(log_ptr, rec - page);
+ mlog_close(mtr, log_ptr + 2);
+ }
}
/**************************************************************
@@ -552,18 +646,23 @@ Parses a log record of a record list end or start deletion. */
byte*
page_parse_delete_rec_list(
/*=======================*/
- /* out: end of log record or NULL */
- byte type, /* in: MLOG_LIST_END_DELETE or
- MLOG_LIST_START_DELETE */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
+ /* out: end of log record or NULL */
+ byte type, /* in: MLOG_LIST_END_DELETE,
+ MLOG_LIST_START_DELETE,
+ MLOG_COMP_LIST_END_DELETE or
+ MLOG_COMP_LIST_START_DELETE */
+ byte* ptr, /* in: buffer */
+ byte* end_ptr,/* in: buffer end */
+ dict_index_t* index, /* in: record descriptor */
+ page_t* page, /* in: page or NULL */
+ mtr_t* mtr) /* in: mtr or NULL */
{
ulint offset;
- ut_ad((type == MLOG_LIST_END_DELETE)
- || (type == MLOG_LIST_START_DELETE));
+ ut_ad(type == MLOG_LIST_END_DELETE
+ || type == MLOG_LIST_START_DELETE
+ || type == MLOG_COMP_LIST_END_DELETE
+ || type == MLOG_COMP_LIST_START_DELETE);
/* Read the record offset as a 2-byte ulint */
@@ -580,11 +679,12 @@ page_parse_delete_rec_list(
return(ptr);
}
- if (type == MLOG_LIST_END_DELETE) {
- page_delete_rec_list_end(page, page + offset, ULINT_UNDEFINED,
- ULINT_UNDEFINED, mtr);
+ if (type == MLOG_LIST_END_DELETE
+ || type == MLOG_COMP_LIST_END_DELETE) {
+ page_delete_rec_list_end(page, page + offset, index,
+ ULINT_UNDEFINED, ULINT_UNDEFINED, mtr);
} else {
- page_delete_rec_list_start(page, page + offset, mtr);
+ page_delete_rec_list_start(page, page + offset, index, mtr);
}
return(ptr);
@@ -597,14 +697,15 @@ The infimum and supremum records are not deleted. */
void
page_delete_rec_list_end(
/*=====================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- ulint n_recs, /* in: number of records to delete, or ULINT_UNDEFINED
- if not known */
- ulint size, /* in: the sum of the sizes of the records in the end
- of the chain to delete, or ULINT_UNDEFINED if not
- known */
- mtr_t* mtr) /* in: mtr */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ ulint n_recs, /* in: number of records to delete,
+ or ULINT_UNDEFINED if not known */
+ ulint size, /* in: the sum of the sizes of the
+ records in the end of the chain to
+ delete, or ULINT_UNDEFINED if not known */
+ mtr_t* mtr) /* in: mtr */
{
page_dir_slot_t* slot;
ulint slot_index;
@@ -615,10 +716,12 @@ page_delete_rec_list_end(
ulint count;
ulint n_owned;
rec_t* sup;
+ ibool comp;
/* Reset the last insert info in the page header and increment
the modify clock for the frame */
+ ut_ad(size == ULINT_UNDEFINED || size < UNIV_PAGE_SIZE);
page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
/* The page gets invalid for optimistic searches: increment the
@@ -632,7 +735,9 @@ page_delete_rec_list_end(
rec = page_rec_get_next(rec);
}
- page_delete_rec_list_write_log(page, rec, MLOG_LIST_END_DELETE, mtr);
+ comp = page_is_comp(page);
+ page_delete_rec_list_write_log(page, rec, index,
+ comp ? MLOG_COMP_LIST_END_DELETE : MLOG_LIST_END_DELETE, mtr);
if (rec == sup) {
@@ -644,19 +749,36 @@ page_delete_rec_list_end(
last_rec = page_rec_get_prev(sup);
if ((size == ULINT_UNDEFINED) || (n_recs == ULINT_UNDEFINED)) {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
/* Calculate the sum of sizes and the number of records */
size = 0;
n_recs = 0;
rec2 = rec;
while (rec2 != sup) {
- size += rec_get_size(rec2);
+ ulint s;
+ offsets = rec_get_offsets(rec2, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ s = rec_offs_size(offsets);
+ ut_ad(rec2 - page + s - rec_offs_extra_size(offsets)
+ < UNIV_PAGE_SIZE);
+ ut_ad(size + s < UNIV_PAGE_SIZE);
+ size += s;
n_recs++;
rec2 = page_rec_get_next(rec2);
}
+
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
+ ut_ad(size < UNIV_PAGE_SIZE);
+
/* Update the page directory; there is no need to balance the number
of the records owned by the supremum record, as it is allowed to be
less than PAGE_DIR_SLOT_MIN_N_OWNED */
@@ -664,15 +786,15 @@ page_delete_rec_list_end(
rec2 = rec;
count = 0;
- while (rec_get_n_owned(rec2) == 0) {
+ while (rec_get_n_owned(rec2, comp) == 0) {
count++;
rec2 = page_rec_get_next(rec2);
}
- ut_ad(rec_get_n_owned(rec2) - count > 0);
+ ut_ad(rec_get_n_owned(rec2, comp) - count > 0);
- n_owned = rec_get_n_owned(rec2) - count;
+ n_owned = rec_get_n_owned(rec2, comp) - count;
slot_index = page_dir_find_owner_slot(rec2);
slot = page_dir_get_nth_slot(page, slot_index);
@@ -680,7 +802,7 @@ page_delete_rec_list_end(
page_dir_slot_set_rec(slot, sup);
page_dir_slot_set_n_owned(slot, n_owned);
- page_header_set_field(page, PAGE_N_DIR_SLOTS, slot_index + 1);
+ page_dir_set_n_slots(page, slot_index + 1);
/* Remove the record chain segment from the record chain */
page_rec_set_next(prev_rec, page_get_supremum_rec(page));
@@ -706,14 +828,26 @@ that record. Infimum and supremum records are not deleted. */
void
page_delete_rec_list_start(
/*=======================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- mtr_t* mtr) /* in: mtr */
+ page_t* page, /* in: index page */
+ rec_t* rec, /* in: record on page */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
page_cur_t cur1;
ulint log_mode;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ mem_heap_t* heap = NULL;
+ byte type;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ if (index->table->comp) {
+ type = MLOG_COMP_LIST_START_DELETE;
+ } else {
+ type = MLOG_LIST_START_DELETE;
+ }
- page_delete_rec_list_write_log(page, rec, MLOG_LIST_START_DELETE, mtr);
+ page_delete_rec_list_write_log(page, rec, index, type, mtr);
page_cur_set_before_first(page, &cur1);
@@ -729,8 +863,13 @@ page_delete_rec_list_start(
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
while (page_cur_get_rec(&cur1) != rec) {
+ offsets = rec_get_offsets(page_cur_get_rec(&cur1), index,
+ offsets, ULINT_UNDEFINED, &heap);
+ page_cur_delete_rec(&cur1, index, offsets, mtr);
+ }
- page_cur_delete_rec(&cur1, mtr);
+ if (heap) {
+ mem_heap_free(heap);
}
/* Restore log mode */
@@ -745,10 +884,11 @@ split_rec. */
void
page_move_rec_list_end(
/*===================*/
- page_t* new_page, /* in: index page where to move */
- page_t* page, /* in: index page */
- rec_t* split_rec, /* in: first record to move */
- mtr_t* mtr) /* in: mtr */
+ page_t* new_page, /* in: index page where to move */
+ page_t* page, /* in: index page */
+ rec_t* split_rec, /* in: first record to move */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
ulint old_data_size;
ulint new_data_size;
@@ -758,15 +898,15 @@ page_move_rec_list_end(
old_data_size = page_get_data_size(new_page);
old_n_recs = page_get_n_recs(new_page);
- page_copy_rec_list_end(new_page, page, split_rec, mtr);
+ page_copy_rec_list_end(new_page, page, split_rec, index, mtr);
new_data_size = page_get_data_size(new_page);
new_n_recs = page_get_n_recs(new_page);
ut_ad(new_data_size >= old_data_size);
- page_delete_rec_list_end(page, split_rec, new_n_recs - old_n_recs,
- new_data_size - old_data_size, mtr);
+ page_delete_rec_list_end(page, split_rec, index,
+ new_n_recs - old_n_recs, new_data_size - old_data_size, mtr);
}
/*****************************************************************
@@ -776,14 +916,15 @@ split_rec. */
void
page_move_rec_list_start(
/*=====================*/
- page_t* new_page, /* in: index page where to move */
- page_t* page, /* in: index page */
- rec_t* split_rec, /* in: first record not to move */
- mtr_t* mtr) /* in: mtr */
+ page_t* new_page, /* in: index page where to move */
+ page_t* page, /* in: index page */
+ rec_t* split_rec, /* in: first record not to move */
+ dict_index_t* index, /* in: record descriptor */
+ mtr_t* mtr) /* in: mtr */
{
- page_copy_rec_list_start(new_page, page, split_rec, mtr);
+ page_copy_rec_list_start(new_page, page, split_rec, index, mtr);
- page_delete_rec_list_start(page, split_rec, mtr);
+ page_delete_rec_list_start(page, split_rec, index, mtr);
}
/***************************************************************************
@@ -801,7 +942,7 @@ page_rec_write_index_page_no(
byte* data;
ulint len;
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field_old(rec, i, &len);
ut_ad(len == 4);
@@ -885,7 +1026,7 @@ page_dir_add_slots(
ut_ad(start < n_slots - 1);
/* Update the page header */
- page_header_set_field(page, PAGE_N_DIR_SLOTS, n_slots + n);
+ page_dir_set_n_slots(page, n_slots + n);
/* Move slots up */
@@ -1006,8 +1147,8 @@ page_dir_balance_slot(
old_rec = page_dir_slot_get_rec(slot);
new_rec = page_rec_get_next(old_rec);
- rec_set_n_owned(old_rec, 0);
- rec_set_n_owned(new_rec, n_owned + 1);
+ rec_set_n_owned(old_rec, page_is_comp(page), 0);
+ rec_set_n_owned(new_rec, page_is_comp(page), n_owned + 1);
page_dir_slot_set_rec(slot, new_rec);
@@ -1080,13 +1221,15 @@ page_rec_get_n_recs_before(
rec_t* slot_rec;
page_t* page;
ulint i;
+ ibool comp;
lint n = 0;
ut_ad(page_rec_check(rec));
page = buf_frame_align(rec);
-
- while (rec_get_n_owned(rec) == 0) {
+ comp = page_is_comp(page);
+
+ while (rec_get_n_owned(rec, comp) == 0) {
rec = page_rec_get_next(rec);
n--;
@@ -1096,7 +1239,7 @@ page_rec_get_n_recs_before(
slot = page_dir_get_nth_slot(page, i);
slot_rec = page_dir_slot_get_rec(slot);
- n += rec_get_n_owned(slot_rec);
+ n += rec_get_n_owned(slot_rec, comp);
if (rec == slot_rec) {
@@ -1118,17 +1261,21 @@ the index page context. */
void
page_rec_print(
/*===========*/
- rec_t* rec)
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets)/* in: record descriptor */
{
- rec_print(stderr, rec);
+ ibool comp = page_is_comp(buf_frame_align(rec));
+
+ 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",
- (ulong) rec_get_n_owned(rec),
- (ulong) rec_get_heap_no(rec),
- (ulong) rec_get_next_offs(rec));
+ (ulong) rec_get_n_owned(rec, comp),
+ (ulong) rec_get_heap_no(rec, comp),
+ (ulong) rec_get_next_offs(rec, comp));
page_rec_check(rec);
- rec_validate(rec);
+ rec_validate(rec, offsets);
}
/*******************************************************************
@@ -1176,12 +1323,19 @@ debugging purposes. */
void
page_print_list(
/*============*/
- page_t* page, /* in: index page */
- ulint pr_n) /* in: print n first and n last entries */
+ page_t* page, /* in: index page */
+ dict_index_t* index, /* in: dictionary index of the page */
+ ulint pr_n) /* in: print n first and n last entries */
{
page_cur_t cur;
ulint count;
ulint n_recs;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ ut_a(page_is_comp(page) == index->table->comp);
fprintf(stderr,
"--------------------------------\n"
@@ -1193,7 +1347,9 @@ page_print_list(
page_cur_set_before_first(page, &cur);
count = 0;
for (;;) {
- page_rec_print(cur.rec);
+ offsets = rec_get_offsets(cur.rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ page_rec_print(cur.rec, offsets);
if (count == pr_n) {
break;
@@ -1213,7 +1369,9 @@ page_print_list(
page_cur_move_to_next(&cur);
if (count + pr_n >= n_recs) {
- page_rec_print(cur.rec);
+ offsets = rec_get_offsets(cur.rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ page_rec_print(cur.rec, offsets);
}
count++;
}
@@ -1222,6 +1380,10 @@ page_print_list(
"Total of %lu records \n"
"--------------------------------\n",
(ulong) (count + 1));
+
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
/*******************************************************************
@@ -1235,14 +1397,15 @@ page_header_print(
fprintf(stderr,
"--------------------------------\n"
"PAGE HEADER INFO\n"
- "Page address %p, n records %lu\n"
+ "Page address %p, n records %lu (%s)\n"
"n dir slots %lu, heap top %lu\n"
"Page n heap %lu, free %lu, garbage %lu\n"
"Page last insert %lu, direction %lu, n direction %lu\n",
page, (ulong) page_header_get_field(page, PAGE_N_RECS),
+ page_is_comp(page) ? "compact format" : "original format",
(ulong) page_header_get_field(page, PAGE_N_DIR_SLOTS),
(ulong) page_header_get_field(page, PAGE_HEAP_TOP),
- (ulong) page_header_get_field(page, PAGE_N_HEAP),
+ (ulong) page_dir_get_n_heap(page),
(ulong) page_header_get_field(page, PAGE_FREE),
(ulong) page_header_get_field(page, PAGE_GARBAGE),
(ulong) page_header_get_field(page, PAGE_LAST_INSERT),
@@ -1257,13 +1420,16 @@ debugging purposes. */
void
page_print(
/*======*/
- page_t* page, /* in: index page */
- ulint dn, /* in: print dn first and last entries in directory */
- ulint rn) /* in: print rn first and last records on page */
+ page_t* page, /* in: index page */
+ dict_index_t* index, /* in: dictionary index of the page */
+ ulint dn, /* in: print dn first and last entries
+ in directory */
+ ulint rn) /* in: print rn first and last records
+ in directory */
{
page_header_print(page);
page_dir_print(page, dn);
- page_print_list(page, rn);
+ page_print_list(page, index, rn);
}
/*******************************************************************
@@ -1274,20 +1440,24 @@ the heap_no field. */
ibool
page_rec_validate(
/*==============*/
- /* out: TRUE if ok */
- rec_t* rec) /* in: record on the page */
+ /* out: TRUE if ok */
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
ulint n_owned;
ulint heap_no;
- page_t* page;
+ page_t* page;
+ ibool comp;
page = buf_frame_align(rec);
+ comp = page_is_comp(page);
+ ut_a(comp == rec_offs_comp(offsets));
page_rec_check(rec);
- rec_validate(rec);
+ rec_validate(rec, offsets);
- n_owned = rec_get_n_owned(rec);
- heap_no = rec_get_heap_no(rec);
+ n_owned = rec_get_n_owned(rec, comp);
+ heap_no = rec_get_heap_no(rec, comp);
if (!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED)) {
fprintf(stderr,
@@ -1296,11 +1466,11 @@ page_rec_validate(
return(FALSE);
}
- if (!(heap_no < page_header_get_field(page, PAGE_N_HEAP))) {
+ if (!(heap_no < page_dir_get_n_heap(page))) {
fprintf(stderr,
"InnoDB: Heap no of rec %lu too big %lu %lu\n",
(ulong)(rec - page), (ulong) heap_no,
- (ulong) page_header_get_field(page, PAGE_N_HEAP));
+ (ulong) page_dir_get_n_heap(page));
return(FALSE);
}
@@ -1358,6 +1528,7 @@ page_simple_validate(
ulint count;
ulint own_count;
ibool ret = FALSE;
+ ibool comp = page_is_comp(page);
/* Check first that the record heap and the directory do not
overlap. */
@@ -1404,13 +1575,13 @@ page_simple_validate(
goto func_exit;
}
- if (rec_get_n_owned(rec) != 0) {
+ if (rec_get_n_owned(rec, comp) != 0) {
/* This is a record pointed to by a dir slot */
- if (rec_get_n_owned(rec) != own_count) {
+ if (rec_get_n_owned(rec, comp) != own_count) {
fprintf(stderr,
"InnoDB: Wrong owned count %lu, %lu, rec %lu\n",
- (ulong) rec_get_n_owned(rec),
+ (ulong) rec_get_n_owned(rec, comp),
(ulong) own_count,
(ulong)(rec - page));
@@ -1438,11 +1609,11 @@ page_simple_validate(
break;
}
- if (rec_get_next_offs(rec) < FIL_PAGE_DATA
- || rec_get_next_offs(rec) >= UNIV_PAGE_SIZE) {
+ if (rec_get_next_offs(rec, comp) < FIL_PAGE_DATA
+ || rec_get_next_offs(rec, comp) >= UNIV_PAGE_SIZE) {
fprintf(stderr,
"InnoDB: Next record offset nonsensical %lu for rec %lu\n",
- (ulong) rec_get_next_offs(rec),
+ (ulong) rec_get_next_offs(rec, comp),
(ulong)(rec - page));
goto func_exit;
@@ -1461,7 +1632,7 @@ page_simple_validate(
own_count++;
}
- if (rec_get_n_owned(rec) == 0) {
+ if (rec_get_n_owned(rec, comp) == 0) {
fprintf(stderr, "InnoDB: n owned is zero in a supremum rec\n");
goto func_exit;
@@ -1514,10 +1685,10 @@ page_simple_validate(
rec = page_rec_get_next(rec);
}
- if (page_header_get_field(page, PAGE_N_HEAP) != count + 1) {
+ if (page_dir_get_n_heap(page) != count + 1) {
fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
- (ulong) page_header_get_field(page, PAGE_N_HEAP),
+ (ulong) page_dir_get_n_heap(page),
(ulong) (count + 1));
goto func_exit;
@@ -1549,17 +1720,24 @@ page_validate(
ulint slot_no;
ulint data_size;
rec_t* rec;
- rec_t* old_rec = NULL;
+ rec_t* old_rec = NULL;
ulint offs;
ulint n_slots;
- ibool ret = FALSE;
+ ibool ret = FALSE;
ulint i;
-
+ ibool comp = page_is_comp(page);
+ ulint* offsets = NULL;
+ ulint* old_offsets = NULL;
+
+ if (comp != index->table->comp) {
+ fputs("InnoDB: 'compact format' flag mismatch\n", stderr);
+ goto func_exit2;
+ }
if (!page_simple_validate(page)) {
goto func_exit2;
}
- heap = mem_heap_create(UNIV_PAGE_SIZE);
+ heap = mem_heap_create(UNIV_PAGE_SIZE + 200);
/* The following buffer is used to check that the
records in the page record heap do not overlap */
@@ -1599,22 +1777,33 @@ page_validate(
for (;;) {
rec = cur.rec;
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
+ if (comp && page_rec_is_user_rec(rec)
+ && rec_get_node_ptr_flag(rec)
+ != (ibool)
+ (btr_page_get_level_low(page) != 0)) {
+ fputs("InnoDB: node_ptr flag mismatch\n", stderr);
+ goto func_exit;
+ }
- if (!page_rec_validate(rec)) {
+ if (!page_rec_validate(rec, offsets)) {
goto func_exit;
}
/* Check that the records are in the ascending order */
if ((count >= 2) && (!page_cur_is_after_last(&cur))) {
- if (!(1 == cmp_rec_rec(rec, old_rec, index))) {
+ if (!(1 == cmp_rec_rec(rec, old_rec,
+ offsets, old_offsets, index))) {
fprintf(stderr,
"InnoDB: Records in wrong order on page %lu",
(ulong) buf_frame_get_page_no(page));
dict_index_name_print(stderr, NULL, index);
fputs("\nInnoDB: previous record ", stderr);
- rec_print(stderr, old_rec);
+ rec_print_new(stderr, old_rec, old_offsets);
fputs("\nInnoDB: record ", stderr);
- rec_print(stderr, rec);
+ rec_print_new(stderr, rec, offsets);
putc('\n', stderr);
goto func_exit;
@@ -1624,12 +1813,12 @@ page_validate(
if ((rec != page_get_supremum_rec(page))
&& (rec != page_get_infimum_rec(page))) {
- data_size += rec_get_size(rec);
+ data_size += rec_offs_size(offsets);
}
- offs = rec_get_start(rec) - page;
+ offs = rec_get_start(rec, offsets) - page;
- for (i = 0; i < rec_get_size(rec); i++) {
+ for (i = 0; i < rec_offs_size(offsets); i++) {
if (!buf[offs + i] == 0) {
/* No other record may overlap this */
@@ -1641,12 +1830,12 @@ page_validate(
buf[offs + i] = 1;
}
- if (rec_get_n_owned(rec) != 0) {
+ if (rec_get_n_owned(rec, comp) != 0) {
/* This is a record pointed to by a dir slot */
- if (rec_get_n_owned(rec) != own_count) {
+ if (rec_get_n_owned(rec, comp) != own_count) {
fprintf(stderr,
"InnoDB: Wrong owned count %lu, %lu\n",
- (ulong) rec_get_n_owned(rec),
+ (ulong) rec_get_n_owned(rec, comp),
(ulong) own_count);
goto func_exit;
}
@@ -1671,11 +1860,11 @@ page_validate(
break;
}
- if (rec_get_next_offs(rec) < FIL_PAGE_DATA
- || rec_get_next_offs(rec) >= UNIV_PAGE_SIZE) {
+ if (rec_get_next_offs(rec, comp) < FIL_PAGE_DATA
+ || rec_get_next_offs(rec, comp) >= UNIV_PAGE_SIZE) {
fprintf(stderr,
"InnoDB: Next record offset wrong %lu\n",
- (ulong) rec_get_next_offs(rec));
+ (ulong) rec_get_next_offs(rec, comp));
goto func_exit;
}
@@ -1683,9 +1872,15 @@ page_validate(
page_cur_move_to_next(&cur);
own_count++;
old_rec = rec;
+ /* set old_offsets to offsets; recycle offsets */
+ {
+ ulint* offs = old_offsets;
+ old_offsets = offsets;
+ offsets = offs;
+ }
}
- if (rec_get_n_owned(rec) == 0) {
+ if (rec_get_n_owned(rec, comp) == 0) {
fputs("InnoDB: n owned is zero\n", stderr);
goto func_exit;
}
@@ -1714,15 +1909,17 @@ page_validate(
rec = page_header_get_ptr(page, PAGE_FREE);
while (rec != NULL) {
- if (!page_rec_validate(rec)) {
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ if (!page_rec_validate(rec, offsets)) {
goto func_exit;
}
count++;
- offs = rec_get_start(rec) - page;
+ offs = rec_get_start(rec, offsets) - page;
- for (i = 0; i < rec_get_size(rec); i++) {
+ for (i = 0; i < rec_offs_size(offsets); i++) {
if (buf[offs + i] != 0) {
fputs(
@@ -1736,9 +1933,9 @@ page_validate(
rec = page_rec_get_next(rec);
}
- if (page_header_get_field(page, PAGE_N_HEAP) != count + 1) {
+ if (page_dir_get_n_heap(page) != count + 1) {
fprintf(stderr, "InnoDB: N heap is wrong %lu %lu\n",
- (ulong) page_header_get_field(page, PAGE_N_HEAP),
+ (ulong) page_dir_get_n_heap(page),
(ulong) count + 1);
goto func_exit;
}
@@ -1775,7 +1972,7 @@ page_find_rec_with_heap_no(
page_cur_set_before_first(page, &cur);
for (;;) {
- if (rec_get_heap_no(cur.rec) == heap_no) {
+ if (rec_get_heap_no(cur.rec, page_is_comp(page)) == heap_no) {
return(cur.rec);
}
diff --git a/innobase/pars/pars0pars.c b/innobase/pars/pars0pars.c
index 16d630dd318..c62184abd85 100644
--- a/innobase/pars/pars0pars.c
+++ b/innobase/pars/pars0pars.c
@@ -1514,8 +1514,11 @@ pars_create_table(
n_cols = que_node_list_get_len(column_defs);
- table = dict_mem_table_create(table_sym->name, 0, n_cols);
-
+ /* As the InnoDB SQL parser is for internal use only,
+ for creating some system tables, this function will only
+ create tables in the old (not compact) record format. */
+ table = dict_mem_table_create(table_sym->name, 0, n_cols, FALSE);
+
if (not_fit_in_memory != NULL) {
table->does_not_fit_in_memory = TRUE;
}
diff --git a/innobase/pars/pars0sym.c b/innobase/pars/pars0sym.c
index 194e6677183..8ade5579e47 100644
--- a/innobase/pars/pars0sym.c
+++ b/innobase/pars/pars0sym.c
@@ -220,7 +220,7 @@ sym_tab_add_id(
node->resolved = FALSE;
node->indirection = NULL;
- node->name = mem_heap_strdupl(sym_tab->heap, name, len + 1);
+ node->name = mem_heap_strdupl(sym_tab->heap, (char*) name, len + 1);
node->name_len = len;
UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node);
diff --git a/innobase/que/que0que.c b/innobase/que/que0que.c
index 22878dec27f..a0a6adf9b83 100644
--- a/innobase/que/que0que.c
+++ b/innobase/que/que0que.c
@@ -163,6 +163,7 @@ que_thr_create(
thr->run_node = NULL;
thr->resource = 0;
+ thr->lock_state = QUE_THR_LOCK_NOLOCK;
UT_LIST_ADD_LAST(thrs, parent->thrs, thr);
diff --git a/innobase/read/read0read.c b/innobase/read/read0read.c
index 889612deef4..0c4a037508e 100644
--- a/innobase/read/read0read.c
+++ b/innobase/read/read0read.c
@@ -153,10 +153,11 @@ read_view_open_now(
/* No active transaction should be visible, except cr_trx */
while (trx) {
- if (trx != cr_trx && trx->conc_state == TRX_ACTIVE) {
+ if (trx != cr_trx && (trx->conc_state == TRX_ACTIVE ||
+ trx->conc_state == TRX_PREPARED)) {
read_view_set_nth_trx_id(view, n, trx->id);
-
+
n++;
/* NOTE that a transaction whose trx number is <
@@ -164,7 +165,7 @@ read_view_open_now(
in the middle of its commit! Note that when a
transaction starts, we initialize trx->no to
ut_dulint_max. */
-
+
if (ut_dulint_cmp(view->low_limit_no, trx->no) > 0) {
view->low_limit_no = trx->no;
diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c
index f2dc8a7021a..74348b865a8 100644
--- a/innobase/rem/rem0cmp.c
+++ b/innobase/rem/rem0cmp.c
@@ -51,6 +51,7 @@ cmp_debug_dtuple_rec_with_match(
dtuple in some of the common fields, or which
has an equal number or more fields than
dtuple */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint* matched_fields);/* in/out: number of already
completely matched fields; when function
returns, contains the value for current
@@ -412,6 +413,7 @@ cmp_dtuple_rec_with_match(
dtuple in some of the common fields, or which
has an equal number or more fields than
dtuple */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint* matched_fields, /* in/out: number of already completely
matched fields; when function returns,
contains the value for current comparison */
@@ -441,12 +443,13 @@ cmp_dtuple_rec_with_match(
ut_ad(dtuple && rec && matched_fields && matched_bytes);
ut_ad(dtuple_check_typed(dtuple));
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
cur_field = *matched_fields;
cur_bytes = *matched_bytes;
ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple));
- ut_ad(cur_field <= rec_get_n_fields(rec));
+ ut_ad(cur_field <= rec_offs_n_fields(offsets));
/* Match fields in a loop; stop if we run out of fields in dtuple
or find an externally stored field */
@@ -458,7 +461,8 @@ cmp_dtuple_rec_with_match(
dtuple_f_len = dfield_get_len(dtuple_field);
- rec_b_ptr = rec_get_nth_field(rec, cur_field, &rec_f_len);
+ rec_b_ptr = rec_get_nth_field(rec, offsets,
+ cur_field, &rec_f_len);
/* If we have matched yet 0 bytes, it may be that one or
both the fields are SQL null, or the record or dtuple may be
@@ -468,7 +472,8 @@ cmp_dtuple_rec_with_match(
if (cur_bytes == 0) {
if (cur_field == 0) {
- if (rec_get_info_bits(rec)
+ if (rec_get_info_bits(rec,
+ rec_offs_comp(offsets))
& REC_INFO_MIN_REC_FLAG) {
if (dtuple_get_info_bits(dtuple)
@@ -490,7 +495,7 @@ cmp_dtuple_rec_with_match(
}
}
- if (rec_get_nth_field_extern_bit(rec, cur_field)) {
+ if (rec_offs_nth_extern(offsets, cur_field)) {
/* We do not compare to an externally
stored field */
@@ -622,7 +627,7 @@ cmp_dtuple_rec_with_match(
up to the common fields */
order_resolved:
ut_ad((ret >= - 1) && (ret <= 1));
- ut_ad(ret == cmp_debug_dtuple_rec_with_match(dtuple, rec,
+ ut_ad(ret == cmp_debug_dtuple_rec_with_match(dtuple, rec, offsets,
matched_fields));
ut_ad(*matched_fields == cur_field); /* In the debug version, the
above cmp_debug_... sets
@@ -643,13 +648,15 @@ cmp_dtuple_rec(
less than rec, respectively; see the comments
for cmp_dtuple_rec_with_match */
dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec) /* in: physical record */
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
ulint matched_fields = 0;
ulint matched_bytes = 0;
- return(cmp_dtuple_rec_with_match(dtuple, rec, &matched_fields,
- &matched_bytes));
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+ return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
+ &matched_fields, &matched_bytes));
}
/******************************************************************
@@ -660,22 +667,24 @@ ibool
cmp_dtuple_is_prefix_of_rec(
/*========================*/
/* out: TRUE if prefix */
- dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec) /* in: physical record */
+ dtuple_t* dtuple, /* in: data tuple */
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
ulint n_fields;
ulint matched_fields = 0;
ulint matched_bytes = 0;
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
n_fields = dtuple_get_n_fields(dtuple);
- if (n_fields > rec_get_n_fields(rec)) {
+ if (n_fields > rec_offs_n_fields(offsets)) {
return(FALSE);
}
- cmp_dtuple_rec_with_match(dtuple, rec, &matched_fields,
- &matched_bytes);
+ cmp_dtuple_rec_with_match(dtuple, rec, offsets,
+ &matched_fields, &matched_bytes);
if (matched_fields == n_fields) {
return(TRUE);
@@ -690,42 +699,6 @@ cmp_dtuple_is_prefix_of_rec(
return(FALSE);
}
-/******************************************************************
-Compares a prefix of a data tuple to a prefix of a physical record for
-equality. If there are less fields in rec than parameter n_fields, FALSE
-is returned. NOTE that n_fields_cmp of dtuple does not affect this
-comparison. */
-
-ibool
-cmp_dtuple_rec_prefix_equal(
-/*========================*/
- /* out: TRUE if equal */
- dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec, /* in: physical record */
- ulint n_fields) /* in: number of fields which should be
- compared; must not exceed the number of
- fields in dtuple */
-{
- ulint matched_fields = 0;
- ulint matched_bytes = 0;
-
- ut_ad(n_fields <= dtuple_get_n_fields(dtuple));
-
- if (rec_get_n_fields(rec) < n_fields) {
-
- return(FALSE);
- }
-
- cmp_dtuple_rec_with_match(dtuple, rec, &matched_fields,
- &matched_bytes);
- if (matched_fields >= n_fields) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
/*****************************************************************
This function is used to compare two physical records. Only the common
first fields are compared, and if an externally stored field is
@@ -739,6 +712,8 @@ cmp_rec_rec_with_match(
first fields are compared */
rec_t* rec1, /* in: physical record */
rec_t* rec2, /* in: physical record */
+ const ulint* offsets1,/* in: rec_get_offsets(rec1, index) */
+ const ulint* offsets2,/* in: rec_get_offsets(rec2, index) */
dict_index_t* index, /* in: data dictionary index */
ulint* matched_fields, /* in/out: number of already completely
matched fields; when the function returns,
@@ -765,17 +740,21 @@ cmp_rec_rec_with_match(
ulint cur_bytes; /* number of already matched bytes in current
field */
int ret = 3333; /* return value */
+ ibool comp;
ut_ad(rec1 && rec2 && index);
+ ut_ad(rec_offs_validate(rec1, index, offsets1));
+ ut_ad(rec_offs_validate(rec2, index, offsets2));
+ ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2));
- rec1_n_fields = rec_get_n_fields(rec1);
- rec2_n_fields = rec_get_n_fields(rec2);
+ comp = rec_offs_comp(offsets1);
+ rec1_n_fields = rec_offs_n_fields(offsets1);
+ rec2_n_fields = rec_offs_n_fields(offsets2);
cur_field = *matched_fields;
cur_bytes = *matched_bytes;
- /* Match fields in a loop; stop if we run out of fields in either
- record */
+ /* Match fields in a loop */
while ((cur_field < rec1_n_fields) && (cur_field < rec2_n_fields)) {
@@ -787,17 +766,19 @@ cmp_rec_rec_with_match(
dict_index_get_nth_field(index, cur_field)));
}
- rec1_b_ptr = rec_get_nth_field(rec1, cur_field, &rec1_f_len);
- rec2_b_ptr = rec_get_nth_field(rec2, cur_field, &rec2_f_len);
-
+ rec1_b_ptr = rec_get_nth_field(rec1, offsets1,
+ cur_field, &rec1_f_len);
+ rec2_b_ptr = rec_get_nth_field(rec2, offsets2,
+ cur_field, &rec2_f_len);
+
if (cur_bytes == 0) {
if (cur_field == 0) {
/* Test if rec is the predefined minimum
record */
- if (rec_get_info_bits(rec1)
+ if (rec_get_info_bits(rec1, comp)
& REC_INFO_MIN_REC_FLAG) {
- if (rec_get_info_bits(rec2)
+ if (rec_get_info_bits(rec2, comp)
& REC_INFO_MIN_REC_FLAG) {
ret = 0;
} else {
@@ -806,7 +787,7 @@ cmp_rec_rec_with_match(
goto order_resolved;
- } else if (rec_get_info_bits(rec2)
+ } else if (rec_get_info_bits(rec2, comp)
& REC_INFO_MIN_REC_FLAG) {
ret = 1;
@@ -815,8 +796,8 @@ cmp_rec_rec_with_match(
}
}
- if (rec_get_nth_field_extern_bit(rec1, cur_field)
- || rec_get_nth_field_extern_bit(rec2, cur_field)) {
+ if (rec_offs_nth_extern(offsets1, cur_field)
+ || rec_offs_nth_extern(offsets2, cur_field)) {
/* We do not compare to an externally
stored field */
@@ -971,6 +952,7 @@ cmp_debug_dtuple_rec_with_match(
dtuple in some of the common fields, or which
has an equal number or more fields than
dtuple */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint* matched_fields) /* in/out: number of already
completely matched fields; when function
returns, contains the value for current
@@ -990,14 +972,16 @@ cmp_debug_dtuple_rec_with_match(
ut_ad(dtuple && rec && matched_fields);
ut_ad(dtuple_check_typed(dtuple));
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
ut_ad(*matched_fields <= dtuple_get_n_fields_cmp(dtuple));
- ut_ad(*matched_fields <= rec_get_n_fields(rec));
+ ut_ad(*matched_fields <= rec_offs_n_fields(offsets));
cur_field = *matched_fields;
if (cur_field == 0) {
- if (rec_get_info_bits(rec) & REC_INFO_MIN_REC_FLAG) {
+ 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) {
@@ -1027,9 +1011,10 @@ cmp_debug_dtuple_rec_with_match(
dtuple_f_data = dfield_get_data(dtuple_field);
dtuple_f_len = dfield_get_len(dtuple_field);
- rec_f_data = rec_get_nth_field(rec, cur_field, &rec_f_len);
+ rec_f_data = rec_get_nth_field(rec, offsets,
+ cur_field, &rec_f_len);
- if (rec_get_nth_field_extern_bit(rec, cur_field)) {
+ if (rec_offs_nth_extern(offsets, cur_field)) {
/* We do not compare to an externally stored field */
ret = 0;
diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c
index 1db89241dff..542c746209b 100644
--- a/innobase/rem/rem0rec.c
+++ b/innobase/rem/rem0rec.c
@@ -15,8 +15,8 @@ Created 5/30/1994 Heikki Tuuri
#include "mtr0mtr.h"
#include "mtr0log.h"
-/* PHYSICAL RECORD
- ===============
+/* PHYSICAL RECORD (OLD STYLE)
+ ===========================
The physical record, which is the data type of all the records
found in index pages of the database, has the following format
@@ -39,7 +39,7 @@ represented on a higher text line):
| 10 bits giving the number of fields in this record |
| 1 bit which is set to 1 if the offsets above are given in
one byte format, 0 if in two byte format |
-| two bytes giving the pointer to the next record in the page |
+| two bytes giving an absolute pointer to the next record in the page |
ORIGIN of the record
| first field of data |
...
@@ -55,9 +55,50 @@ The offsets of the data fields are given as one-byte
(if there are less than 127 bytes of data in the record)
or two-byte unsigned integers. The most significant bit
is not part of the offset, instead it indicates the SQL-null
-if the bit is set to 1.
+if the bit is set to 1. */
-CANONICAL COORDINATES. A record can be seen as a single
+/* PHYSICAL RECORD (NEW STYLE)
+ ===========================
+
+The physical record, which is the data type of all the records
+found in index pages of the database, has the following format
+(lower addresses and more significant bits inside a byte are below
+represented on a higher text line):
+
+| length of the last non-null variable-length field of data:
+ if the maximum length is 255, one byte; otherwise,
+ 0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
+ length=128..16383, extern storage flag) |
+...
+| length of first variable-length field of data |
+| SQL-null flags (1 bit per nullable field), padded to full bytes |
+| 4 bits used to delete mark a record, and mark a predefined
+ minimum record in alphabetical order |
+| 4 bits giving the number of records owned by this record
+ (this term is explained in page0page.h) |
+| 13 bits giving the order number of this record in the
+ heap of the index page |
+| 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
+ 010=infimum, 011=supremum, 1xx=reserved |
+| two bytes giving a relative pointer to the next record in the page |
+ORIGIN of the record
+| first field of data |
+...
+| last field of data |
+
+The origin of the record is the start address of the first field
+of data. The offsets are given relative to the origin.
+The offsets of the data fields are stored in an inverted
+order because then the offset of the first fields are near the
+origin, giving maybe a better processor cache hit rate in searches.
+
+The offsets of the data fields are given as one-byte
+(if there are less than 127 bytes of data in the record)
+or two-byte unsigned integers. The most significant bit
+is not part of the offset, instead it indicates the SQL-null
+if the bit is set to 1. */
+
+/* CANONICAL COORDINATES. A record can be seen as a single
string of 'characters' in the following way: catenate the bytes
in each field, in the order of fields. An SQL-null field
is taken to be an empty sequence of bytes. Then after
@@ -86,13 +127,237 @@ the corresponding canonical strings have the same property. */
ulint rec_dummy; /* this is used to fool compiler in
rec_validate */
+/*******************************************************************
+Validates the consistency of an old-style physical record. */
+static
+ibool
+rec_validate_old(
+/*=============*/
+ /* out: TRUE if ok */
+ rec_t* rec); /* in: physical record */
+
+/**********************************************************
+The following function determines the offsets to each field in the
+record. The offsets are written to a previously allocated array of
+ulint, where rec_offs_n_fields(offsets) has been initialized to the
+number of fields in the record. The rest of the array will be
+initialized by this function. rec_offs_base(offsets)[0] will be set
+to the extra size (if REC_OFFS_COMPACT is set, the record is in the
+new format), and rec_offs_base(offsets)[1..n_fields] will be set to
+offsets past the end of fields 0..n_fields, or to the beginning of
+fields 1..n_fields+1. When the high-order bit of the offset at [i+1]
+is set (REC_OFFS_SQL_NULL), the field i is NULL. When the second
+high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
+field i is being stored externally. */
+static
+void
+rec_init_offsets(
+/*=============*/
+ /* out: the offsets */
+ rec_t* rec, /* in: physical record */
+ dict_index_t* index, /* in: record descriptor */
+ 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) {
+ 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) {
+ case REC_STATUS_INFIMUM:
+ case REC_STATUS_SUPREMUM:
+ /* the field is 8 bytes long */
+ rec_offs_base(offsets)[0] =
+ REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
+ rec_offs_base(offsets)[1] = 8;
+ return;
+ case REC_STATUS_NODE_PTR:
+ n_node_ptr_field =
+ dict_index_get_n_unique_in_tree(index);
+ break;
+ case REC_STATUS_ORDINARY:
+ break;
+ }
+
+ nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
+ lens = nulls - (index->n_nullable + 7) / 8;
+ offs = 0;
+ null_mask = 1;
+
+ /* read the lengths of fields 0..n */
+ for (; i < n_fields; i++) {
+ ibool is_null = FALSE, is_external = FALSE;
+ ulint len;
+ if (i == n_node_ptr_field) {
+ len = 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)) {
+ /* nullable field => read the null flag */
+ is_null = (*nulls & null_mask) != 0;
+ null_mask <<= 1;
+ if (null_mask == 0x100) {
+ nulls--;
+ null_mask = 1;
+ }
+ }
+
+ if (is_null) {
+ /* No length is stored for NULL fields. */
+ len = 0;
+ } else if (!field->fixed_len) {
+ /* Variable-length field: read the length */
+ len = *lens--;
+ if (dtype_get_len(type) > 255
+ || dtype_get_mtype(type) == DATA_BLOB) {
+ if (len & 0x80) {
+ /* 1exxxxxxx xxxxxxxx */
+ is_external = !!(len & 0x40);
+ len &= 0x3f;
+ len <<= 8;
+ len |= *lens--;
+ }
+ }
+ } else {
+ len = 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;
+ }
+
+ *rec_offs_base(offsets) =
+ (rec - (lens + 1)) | REC_OFFS_COMPACT;
+ } else {
+ /* 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;
+ *rec_offs_base(offsets) = offs;
+ /* Determine offsets to fields */
+ for (; i < n_fields; i++) {
+ 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;
+ }
+ } else {
+ offs += 2 * n_fields;
+ *rec_offs_base(offsets) = offs;
+ /* Determine offsets to fields */
+ for (; i < n_fields; i++) {
+ offs = rec_2_get_field_end_info(rec, i);
+ if (offs & REC_2BYTE_SQL_NULL_MASK) {
+ offs &= ~REC_2BYTE_SQL_NULL_MASK;
+ offs |= REC_OFFS_SQL_NULL;
+ }
+ if (offs & REC_2BYTE_EXTERN_MASK) {
+ offs &= ~REC_2BYTE_EXTERN_MASK;
+ offs |= REC_OFFS_EXTERNAL;
+ }
+ rec_offs_base(offsets)[1 + i] = offs;
+ }
+ }
+ }
+}
+
+/**********************************************************
+The following function determines the offsets to each field
+in the record. It can reuse a previously returned array. */
+
+ulint*
+rec_get_offsets_func(
+/*=================*/
+ /* out: the new offsets */
+ rec_t* rec, /* in: physical record */
+ dict_index_t* index, /* in: record descriptor */
+ ulint* offsets,/* in: array consisting of offsets[0]
+ allocated elements, or an array from
+ rec_get_offsets(), or NULL */
+ ulint n_fields,/* in: maximum number of initialized fields
+ (ULINT_UNDEFINED if all fields) */
+ mem_heap_t** heap, /* in/out: memory heap */
+ const char* file, /* in: file name where called */
+ ulint line) /* in: line number where called */
+{
+ ulint n;
+ ulint size;
+
+ ut_ad(rec);
+ ut_ad(index);
+ ut_ad(heap);
+
+ if (index->table->comp) {
+ switch (rec_get_status(rec)) {
+ case REC_STATUS_ORDINARY:
+ n = dict_index_get_n_fields(index);
+ break;
+ case REC_STATUS_NODE_PTR:
+ n = dict_index_get_n_unique_in_tree(index) + 1;
+ break;
+ case REC_STATUS_INFIMUM:
+ case REC_STATUS_SUPREMUM:
+ /* infimum or supremum record */
+ n = 1;
+ break;
+ default:
+ ut_error;
+ return(NULL);
+ }
+ } else {
+ n = rec_get_n_fields_old(rec);
+ }
+
+ if (n_fields < n) {
+ n = n_fields;
+ }
+
+ size = n + (1 + REC_OFFS_HEADER_SIZE);
+
+ if (!offsets || rec_offs_get_n_alloc(offsets) < size) {
+ if (!*heap) {
+ *heap = mem_heap_create_func(size * sizeof(ulint),
+ NULL, MEM_HEAP_DYNAMIC, file, line);
+ }
+ offsets = mem_heap_alloc(*heap, size * sizeof(ulint));
+ rec_offs_set_n_alloc(offsets, size);
+ }
+
+ rec_offs_set_n_fields(offsets, n);
+ rec_init_offsets(rec, index, offsets);
+ return(offsets);
+}
+
/****************************************************************
-The following function is used to get a pointer to the nth data field in a
-record. */
+The following function is used to get a pointer to the nth
+data field in an old-style record. */
byte*
-rec_get_nth_field(
-/*==============*/
+rec_get_nth_field_old(
+/*==================*/
/* out: pointer to the field */
rec_t* rec, /* in: record */
ulint n, /* in: index of the field */
@@ -103,9 +368,9 @@ rec_get_nth_field(
ulint next_os;
ut_ad(rec && len);
- ut_ad(n < rec_get_n_fields(rec));
+ ut_ad(n < rec_get_n_fields_old(rec));
- if (n > 1024) {
+ if (n > REC_MAX_N_FIELDS) {
fprintf(stderr, "Error: trying to access field %lu in rec\n",
(ulong) n);
ut_error;
@@ -150,8 +415,78 @@ rec_get_nth_field(
return(rec + os);
}
+/**************************************************************
+The following function returns the size of a data tuple when converted to
+a new-style physical record. */
+
+ulint
+rec_get_converted_size_new(
+/*=======================*/
+ /* out: size */
+ dict_index_t* index, /* in: record descriptor */
+ dtuple_t* dtuple) /* in: data tuple */
+{
+ ulint size = REC_N_NEW_EXTRA_BYTES
+ + (index->n_nullable + 7) / 8;
+ dict_field_t* field;
+ dtype_t* type;
+ ulint i;
+ ulint n_fields;
+ ut_ad(index && dtuple);
+ ut_ad(index->table->comp);
+
+ switch (dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK) {
+ case REC_STATUS_ORDINARY:
+ n_fields = dict_index_get_n_fields(index);
+ ut_ad(n_fields == dtuple_get_n_fields(dtuple));
+ break;
+ case REC_STATUS_NODE_PTR:
+ n_fields = dict_index_get_n_unique_in_tree(index);
+ ut_ad(n_fields + 1 == dtuple_get_n_fields(dtuple));
+ ut_ad(dtuple_get_nth_field(dtuple, n_fields)->len == 4);
+ size += 4; /* child page number */
+ break;
+ case REC_STATUS_INFIMUM:
+ case REC_STATUS_SUPREMUM:
+ /* infimum or supremum record, 8 bytes */
+ return(size + 8); /* no extra data needed */
+ default:
+ ut_a(0);
+ return(ULINT_UNDEFINED);
+ }
+
+ /* read the lengths of fields 0..n */
+ for (i = 0; i < n_fields; i++) {
+ ulint len = dtuple_get_nth_field(dtuple, i)->len;
+ field = dict_index_get_nth_field(index, i);
+ type = dict_col_get_type(dict_field_get_col(field));
+ ut_ad(len != UNIV_SQL_NULL ||
+ !(dtype_get_prtype(type) & DATA_NOT_NULL));
+
+ if (len == UNIV_SQL_NULL) {
+ /* No length is stored for NULL fields. */
+ continue;
+ }
+
+ ut_ad(len <= dtype_get_len(type)
+ || dtype_get_mtype(type) == DATA_BLOB);
+ ut_ad(!field->fixed_len || len == field->fixed_len);
+
+ if (field->fixed_len) {
+ } else if (len < 128 || (dtype_get_len(type) < 256
+ && dtype_get_mtype(type) != DATA_BLOB)) {
+ size++;
+ } else {
+ size += 2;
+ }
+ size += len;
+ }
+
+ return(size);
+}
+
/***************************************************************
-Sets the value of the ith field SQL null bit. */
+Sets the value of the ith field SQL null bit of an old-style record. */
void
rec_set_nth_field_null_bit(
@@ -189,12 +524,12 @@ rec_set_nth_field_null_bit(
}
/***************************************************************
-Sets the value of the ith field extern storage bit. */
+Sets the value of the ith field extern storage bit of an old-style record. */
void
-rec_set_nth_field_extern_bit(
-/*=========================*/
- rec_t* rec, /* in: record */
+rec_set_nth_field_extern_bit_old(
+/*=============================*/
+ rec_t* rec, /* in: old-style record */
ulint i, /* in: ith field */
ibool val, /* in: value to set */
mtr_t* mtr) /* in: mtr holding an X-latch to the page where
@@ -204,7 +539,7 @@ rec_set_nth_field_extern_bit(
ulint info;
ut_a(!rec_get_1byte_offs_flag(rec));
- ut_a(i < rec_get_n_fields(rec));
+ ut_a(i < rec_get_n_fields_old(rec));
info = rec_2_get_field_end_info(rec, i);
@@ -215,36 +550,117 @@ rec_set_nth_field_extern_bit(
}
if (mtr) {
- mlog_write_ulint(rec - REC_N_EXTRA_BYTES - 2 * (i + 1), info,
- MLOG_2BYTES, mtr);
+ mlog_write_ulint(rec - REC_N_OLD_EXTRA_BYTES - 2 * (i + 1),
+ info, MLOG_2BYTES, mtr);
} else {
rec_2_set_field_end_info(rec, i, info);
}
}
/***************************************************************
+Sets the value of the ith field extern storage bit of a new-style record. */
+
+void
+rec_set_nth_field_extern_bit_new(
+/*=============================*/
+ rec_t* rec, /* in: record */
+ dict_index_t* index, /* in: record descriptor */
+ ulint ith, /* in: ith field */
+ ibool val, /* in: value to set */
+ mtr_t* mtr) /* in: mtr holding an X-latch to the page
+ where rec is, or NULL; in the NULL case
+ we do not write to log about the change */
+{
+ byte* nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
+ byte* lens = nulls - (index->n_nullable + 7) / 8;
+ dict_field_t* field;
+ dtype_t* type;
+ ulint i;
+ ulint n_fields;
+ ulint null_mask = 1;
+ ut_ad(rec && index);
+ ut_ad(index->table->comp);
+ ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
+
+ n_fields = dict_index_get_n_fields(index);
+
+ ut_ad(ith < n_fields);
+
+ /* 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);
+ 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. */
+ ut_ad(i != ith);
+ continue;
+ }
+ len = *lens--;
+ if (dtype_get_len(type) > 255
+ || dtype_get_mtype(type) == DATA_BLOB) {
+ if (len & 0x80) { /* 1exxxxxx: 2-byte length */
+ if (i == ith) {
+ if (!val == !(len & 0x20)) {
+ return; /* no change */
+ }
+ /* toggle the extern bit */
+ len ^= 0x40;
+ if (mtr) {
+ mlog_write_ulint(lens + 1, len,
+ MLOG_1BYTE, mtr);
+ } else {
+ lens[1] = (byte) len;
+ }
+ return;
+ }
+ lens--;
+ } else {
+ /* short fields cannot be external */
+ ut_ad(i != ith);
+ }
+ } else {
+ /* short fields cannot be external */
+ ut_ad(i != ith);
+ }
+ }
+}
+
+/***************************************************************
Sets TRUE the extern storage bits of fields mentioned in an array. */
void
rec_set_field_extern_bits(
/*======================*/
- rec_t* rec, /* in: record */
- ulint* vec, /* in: array of field numbers */
- ulint n_fields, /* in: number of fields numbers */
- mtr_t* mtr) /* in: mtr holding an X-latch to the page
- where rec is, or NULL; in the NULL case we
- do not write to log about the change */
+ rec_t* rec, /* in: record */
+ dict_index_t* index, /* in: record descriptor */
+ const ulint* vec, /* in: array of field numbers */
+ ulint n_fields,/* in: number of fields numbers */
+ mtr_t* mtr) /* in: mtr holding an X-latch to the
+ page where rec is, or NULL;
+ in the NULL case we do not write
+ to log about the change */
{
ulint i;
for (i = 0; i < n_fields; i++) {
- rec_set_nth_field_extern_bit(rec, vec[i], TRUE, mtr);
+ rec_set_nth_field_extern_bit(rec, index, vec[i], TRUE, mtr);
}
}
/***************************************************************
-Sets a record field to SQL null. The physical size of the field is not
-changed. */
+Sets an old-style record field to SQL null.
+The physical size of the field is not changed. */
void
rec_set_nth_field_sql_null(
@@ -262,20 +678,20 @@ rec_set_nth_field_sql_null(
}
/*************************************************************
-Builds a physical record out of a data tuple and stores it beginning from
-address destination. */
-
-rec_t*
-rec_convert_dtuple_to_rec_low(
+Builds an old-style physical record out of a data tuple and
+stores it beginning from the start of the given buffer. */
+static
+rec_t*
+rec_convert_dtuple_to_rec_old(
/*==========================*/
- /* out: pointer to the origin of physical
- record */
- byte* destination, /* in: start address of the physical record */
- dtuple_t* dtuple, /* in: data tuple */
- ulint data_size) /* in: data size of dtuple */
+ /* out: pointer to the origin of
+ physical record */
+ byte* buf, /* in: start address of the physical record */
+ dtuple_t* dtuple)/* in: data tuple */
{
dfield_t* field;
ulint n_fields;
+ ulint data_size;
rec_t* rec;
ulint end_offset;
ulint ored_offset;
@@ -283,24 +699,25 @@ rec_convert_dtuple_to_rec_low(
ulint len;
ulint i;
- ut_ad(destination && dtuple);
+ ut_ad(buf && dtuple);
ut_ad(dtuple_validate(dtuple));
ut_ad(dtuple_check_typed(dtuple));
- ut_ad(dtuple_get_data_size(dtuple) == data_size);
n_fields = dtuple_get_n_fields(dtuple);
+ data_size = dtuple_get_data_size(dtuple);
ut_ad(n_fields > 0);
/* Calculate the offset of the origin in the physical record */
- rec = destination + rec_get_converted_extra_size(data_size, n_fields);
+ rec = buf + rec_get_converted_extra_size(data_size, n_fields);
/* Store the number of fields */
- rec_set_n_fields(rec, n_fields);
+ rec_set_n_fields_old(rec, n_fields);
/* Set the info bits of the record */
- rec_set_info_bits(rec, dtuple_get_info_bits(dtuple));
+ rec_set_info_bits(rec, FALSE,
+ dtuple_get_info_bits(dtuple) & REC_INFO_BITS_MASK);
/* Store the data and the offsets */
@@ -361,11 +778,201 @@ rec_convert_dtuple_to_rec_low(
}
}
- ut_ad(rec_validate(rec));
+ return(rec);
+}
+
+/*************************************************************
+Builds a new-style physical record out of a data tuple and
+stores it beginning from the start of the given buffer. */
+static
+rec_t*
+rec_convert_dtuple_to_rec_new(
+/*==========================*/
+ /* out: pointer to the origin
+ of physical record */
+ byte* buf, /* in: start address of the physical record */
+ dict_index_t* index, /* in: record descriptor */
+ dtuple_t* dtuple) /* in: data tuple */
+{
+ dfield_t* field;
+ dtype_t* type;
+ rec_t* rec = buf + REC_N_NEW_EXTRA_BYTES;
+ byte* end;
+ byte* nulls;
+ byte* lens;
+ ulint len;
+ ulint i;
+ ulint fixed_len;
+ ulint null_mask = 1;
+ const ulint n_fields = dtuple_get_n_fields(dtuple);
+ const ulint status = dtuple_get_info_bits(dtuple)
+ & REC_NEW_STATUS_MASK;
+ ut_ad(index->table->comp);
+
+ ut_ad(n_fields > 0);
+ switch (status) {
+ case REC_STATUS_ORDINARY:
+ ut_ad(n_fields <= dict_index_get_n_fields(index));
+ break;
+ case REC_STATUS_NODE_PTR:
+ ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1);
+ break;
+ case REC_STATUS_INFIMUM:
+ case REC_STATUS_SUPREMUM:
+ ut_ad(n_fields == 1);
+ goto init;
+ default:
+ ut_a(0);
+ return(0);
+ }
+
+ /* Calculate the offset of the origin in the physical record.
+ We must loop over all fields to do this. */
+ rec += (index->n_nullable + 7) / 8;
+
+ for (i = 0; i < n_fields; i++) {
+ 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)) {
+ if (len == UNIV_SQL_NULL)
+ continue;
+ }
+ /* only nullable fields can be null */
+ ut_ad(len != UNIV_SQL_NULL);
+ if (fixed_len) {
+ ut_ad(len == fixed_len);
+ } else {
+ ut_ad(len <= dtype_get_len(type)
+ || dtype_get_mtype(type) == DATA_BLOB);
+ rec++;
+ if (len >= 128 && (dtype_get_len(type) >= 256
+ || dtype_get_mtype(type) == DATA_BLOB)) {
+ rec++;
+ }
+ }
+ }
+
+init:
+ end = rec;
+ nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
+ lens = nulls - (index->n_nullable + 7) / 8;
+ /* clear the SQL-null flags */
+ memset (lens + 1, 0, nulls - lens);
+
+ /* Set the info bits of the record */
+ rec_set_status(rec, status);
+
+ rec_set_info_bits(rec, TRUE,
+ dtuple_get_info_bits(dtuple) & REC_INFO_BITS_MASK);
+
+ /* Store the data and the offsets */
+
+ for (i = 0; i < n_fields; i++) {
+ 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);
+ goto copy;
+ }
+ 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);
+ ut_ad(*nulls < null_mask);
+ /* set the null flag if necessary */
+ if (len == UNIV_SQL_NULL) {
+ *nulls |= null_mask;
+ }
+ 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);
+ if (fixed_len) {
+ ut_ad(len == fixed_len);
+ } else {
+ ut_ad(len <= dtype_get_len(type)
+ || dtype_get_mtype(type) == DATA_BLOB);
+ if (len < 128 || (dtype_get_len(type) < 256
+ && dtype_get_mtype(type) != DATA_BLOB)) {
+ *lens-- = (byte) len;
+ }
+ else {
+ /* the extern bits will be set later */
+ ut_ad(len < 16384);
+ *lens-- = (byte) (len >> 8) | 0x80;
+ *lens-- = (byte) len;
+ }
+ }
+ copy:
+ memcpy(end, dfield_get_data(field), len);
+ end += len;
+ }
return(rec);
}
+/*************************************************************
+Builds a physical record out of a data tuple and
+stores it beginning from the start of the given buffer. */
+
+rec_t*
+rec_convert_dtuple_to_rec(
+/*======================*/
+ /* out: pointer to the origin
+ of physical record */
+ byte* buf, /* in: start address of the
+ physical record */
+ dict_index_t* index, /* in: record descriptor */
+ dtuple_t* dtuple) /* in: data tuple */
+{
+ rec_t* rec;
+
+ ut_ad(buf && index && dtuple);
+ ut_ad(dtuple_validate(dtuple));
+ ut_ad(dtuple_check_typed(dtuple));
+
+ if (index->table->comp) {
+ rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
+ } else {
+ rec = rec_convert_dtuple_to_rec_old(buf, dtuple);
+ }
+
+#ifdef UNIV_DEBUG
+ {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ const ulint* offsets;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ offsets = rec_get_offsets(rec, index,
+ offsets_, ULINT_UNDEFINED, &heap);
+ ut_ad(rec_validate(rec, offsets));
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ }
+#endif /* UNIV_DEBUG */
+ return(rec);
+}
+
/******************************************************************
Copies the first n fields of a physical record to a data tuple. The fields
are copied to the memory heap. */
@@ -375,6 +982,7 @@ rec_copy_prefix_to_dtuple(
/*======================*/
dtuple_t* tuple, /* in: data tuple */
rec_t* rec, /* in: physical record */
+ dict_index_t* index, /* in: record descriptor */
ulint n_fields, /* in: number of fields to copy */
mem_heap_t* heap) /* in: memory heap */
{
@@ -383,16 +991,22 @@ rec_copy_prefix_to_dtuple(
ulint len;
byte* buf = NULL;
ulint i;
-
- ut_ad(rec_validate(rec));
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
+
+ ut_ad(rec_validate(rec, offsets));
ut_ad(dtuple_check_typed(tuple));
- dtuple_set_info_bits(tuple, rec_get_info_bits(rec));
+ dtuple_set_info_bits(tuple,
+ rec_get_info_bits(rec, index->table->comp));
for (i = 0; i < n_fields; i++) {
field = dtuple_get_nth_field(tuple, i);
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field(rec, offsets, i, &len);
if (len != UNIV_SQL_NULL) {
buf = mem_heap_alloc(heap, len);
@@ -405,32 +1019,28 @@ rec_copy_prefix_to_dtuple(
}
/******************************************************************
-Copies the first n fields of a physical record to a new physical record in
-a buffer. */
-
+Copies the first n fields of an old-style physical record
+to a new physical record in a buffer. */
+static
rec_t*
-rec_copy_prefix_to_buf(
-/*===================*/
+rec_copy_prefix_to_buf_old(
+/*=======================*/
/* out, own: copied record */
rec_t* rec, /* in: physical record */
ulint n_fields, /* in: number of fields to copy */
+ ulint area_end, /* in: end of the prefix data */
byte** buf, /* in/out: memory buffer for the copied prefix,
or NULL */
ulint* buf_size) /* in/out: buffer size */
{
rec_t* copy_rec;
ulint area_start;
- ulint area_end;
ulint prefix_len;
- ut_ad(rec_validate(rec));
-
- area_end = rec_get_field_start_offs(rec, n_fields);
-
if (rec_get_1byte_offs_flag(rec)) {
- area_start = REC_N_EXTRA_BYTES + n_fields;
+ area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
} else {
- area_start = REC_N_EXTRA_BYTES + 2 * n_fields;
+ area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
}
prefix_len = area_start + area_end;
@@ -448,17 +1058,114 @@ rec_copy_prefix_to_buf(
copy_rec = *buf + area_start;
- rec_set_n_fields(copy_rec, n_fields);
+ rec_set_n_fields_old(copy_rec, n_fields);
return(copy_rec);
}
-/*******************************************************************
-Validates the consistency of a physical record. */
+/******************************************************************
+Copies the first n fields of a physical record to a new physical record in
+a buffer. */
+
+rec_t*
+rec_copy_prefix_to_buf(
+/*===================*/
+ /* out, own: copied record */
+ rec_t* rec, /* in: physical record */
+ dict_index_t* index, /* in: record descriptor */
+ ulint n_fields, /* in: number of fields to copy */
+ byte** buf, /* in/out: memory buffer
+ 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;
+ dict_field_t* field;
+ dtype_t* type;
+ ulint i;
+ ulint prefix_len = 0;
+ ibool is_null;
+ ulint null_mask = 1;
+ ulint status;
+
+ if (!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),
+ buf, buf_size));
+ }
+
+ status = rec_get_status(rec);
+
+ switch (status) {
+ case REC_STATUS_ORDINARY:
+ ut_ad(n_fields <= dict_index_get_n_fields(index));
+ break;
+ case REC_STATUS_NODE_PTR:
+ /* it doesn't make sense to copy the child page number field */
+ ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
+ break;
+ case REC_STATUS_INFIMUM:
+ case REC_STATUS_SUPREMUM:
+ /* infimum or supremum record: no sense to copy anything */
+ default:
+ ut_a(0);
+ return(NULL);
+ }
+
+ /* 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) {
+ /* nullable field => read the null flag */
+ is_null = !!(*nulls & null_mask);
+ null_mask <<= 1;
+ if (null_mask == 0x100)
+ nulls--, null_mask = 1;
+ }
+
+ if (is_null) {
+ } else if (field->fixed_len) {
+ prefix_len += field->fixed_len;
+ } else {
+ ulint len = *lens--;
+ if (dtype_get_len(type) > 255
+ || dtype_get_mtype(type) == DATA_BLOB) {
+ if (len & 0x80) {
+ /* 1exxxxxx */
+ len &= 0x3f;
+ len <<= 8;
+ len |= *lens--;
+ }
+ }
+ prefix_len += len;
+ }
+ }
+
+ prefix_len += rec - (lens + 1);
+
+ if ((*buf == NULL) || (*buf_size < prefix_len)) {
+ if (*buf != NULL) {
+ mem_free(*buf);
+ }
+
+ *buf = mem_alloc(prefix_len);
+ *buf_size = prefix_len;
+ }
+ memcpy(*buf, lens + 1, prefix_len);
+
+ return(*buf + (rec - (lens + 1)));
+}
+
+/*******************************************************************
+Validates the consistency of an old-style physical record. */
+static
ibool
-rec_validate(
-/*=========*/
+rec_validate_old(
+/*=============*/
/* out: TRUE if ok */
rec_t* rec) /* in: physical record */
{
@@ -470,7 +1177,7 @@ rec_validate(
ulint i;
ut_a(rec);
- n_fields = rec_get_n_fields(rec);
+ n_fields = rec_get_n_fields_old(rec);
if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
@@ -479,7 +1186,7 @@ rec_validate(
}
for (i = 0; i < n_fields; i++) {
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field_old(rec, i, &len);
if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
fprintf(stderr,
@@ -499,45 +1206,167 @@ rec_validate(
}
}
- if (len_sum != (ulint)(rec_get_end(rec) - rec)) {
+ if (len_sum != rec_get_data_size_old(rec)) {
+ fprintf(stderr,
+ "InnoDB: Error: record len should be %lu, len %lu\n",
+ (ulong) len_sum,
+ rec_get_data_size_old(rec));
+ return(FALSE);
+ }
+
+ rec_dummy = sum; /* This is here only to fool the compiler */
+
+ return(TRUE);
+}
+
+/*******************************************************************
+Validates the consistency of a physical record. */
+
+ibool
+rec_validate(
+/*=========*/
+ /* out: TRUE if ok */
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
+{
+ const byte* data;
+ ulint len;
+ ulint n_fields;
+ ulint len_sum = 0;
+ ulint sum = 0;
+ ulint i;
+
+ ut_a(rec);
+ n_fields = rec_offs_n_fields(offsets);
+
+ if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
+ fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
+ (ulong) n_fields);
+ return(FALSE);
+ }
+
+ ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
+
+ for (i = 0; i < n_fields; i++) {
+ data = rec_get_nth_field(rec, offsets, i, &len);
+
+ if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
+ fprintf(stderr,
+ "InnoDB: Error: record field %lu len %lu\n", (ulong) i,
+ (ulong) len);
+ return(FALSE);
+ }
+
+ if (len != UNIV_SQL_NULL) {
+ len_sum += len;
+ sum += *(data + len -1); /* dereference the
+ end of the field to
+ cause a memory trap
+ if possible */
+ } else if (!rec_offs_comp(offsets)) {
+ len_sum += rec_get_nth_field_size(rec, i);
+ }
+ }
+
+ if (len_sum != (ulint)(rec_get_end(rec, offsets) - rec)) {
fprintf(stderr,
"InnoDB: Error: record len should be %lu, len %lu\n",
(ulong) len_sum,
- (ulong) (rec_get_end(rec) - rec));
+ (ulong) (rec_get_end(rec, offsets) - rec));
return(FALSE);
}
rec_dummy = sum; /* This is here only to fool the compiler */
+ if (!rec_offs_comp(offsets)) {
+ ut_a(rec_validate_old(rec));
+ }
+
return(TRUE);
}
/*******************************************************************
+Prints an old-style physical record. */
+
+void
+rec_print_old(
+/*==========*/
+ FILE* file, /* in: file where to print */
+ rec_t* rec) /* in: physical record */
+{
+ const byte* data;
+ ulint len;
+ ulint n;
+ ulint i;
+
+ ut_ad(rec);
+
+ n = rec_get_n_fields_old(rec);
+
+ fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
+ " %u-byte offsets; info bits %lu\n",
+ (ulong) n,
+ rec_get_1byte_offs_flag(rec) ? 1 : 2,
+ (ulong) rec_get_info_bits(rec, FALSE));
+
+ for (i = 0; i < n; i++) {
+
+ data = rec_get_nth_field_old(rec, i, &len);
+
+ fprintf(file, " %lu:", (ulong) i);
+
+ if (len != UNIV_SQL_NULL) {
+ if (len <= 30) {
+
+ ut_print_buf(file, data, len);
+ } else {
+ ut_print_buf(file, data, 30);
+
+ fputs("...(truncated)", file);
+ }
+ } else {
+ fprintf(file, " SQL NULL, size %lu ",
+ rec_get_nth_field_size(rec, i));
+ }
+ putc(';', file);
+ }
+
+ putc('\n', file);
+
+ rec_validate_old(rec);
+}
+
+/*******************************************************************
Prints a physical record. */
void
-rec_print(
-/*======*/
- FILE* file, /* in: file where to print */
- rec_t* rec) /* in: physical record */
+rec_print_new(
+/*==========*/
+ FILE* file, /* in: file where to print */
+ rec_t* rec, /* in: physical record */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
- byte* data;
- ulint len;
- ulint n;
- ulint i;
+ const byte* data;
+ ulint len;
+ ulint i;
+
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+
+ if (!rec_offs_comp(offsets)) {
+ rec_print_old(file, rec);
+ return;
+ }
ut_ad(rec);
-
- n = rec_get_n_fields(rec);
fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
- " 1-byte offs %s; info bits %lu\n",
- (ulong) n, rec_get_1byte_offs_flag(rec) ? "TRUE" : "FALSE",
- (ulong) rec_get_info_bits(rec));
+ " compact format; info bits %lu\n",
+ (ulong) rec_offs_n_fields(offsets),
+ (ulong) rec_get_info_bits(rec, TRUE));
- for (i = 0; i < n; i++) {
+ for (i = 0; i < rec_offs_n_fields(offsets); i++) {
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field(rec, offsets, i, &len);
fprintf(file, " %lu:", (ulong) i);
@@ -551,14 +1380,40 @@ rec_print(
fputs("...(truncated)", file);
}
} else {
- fprintf(file, " SQL NULL, size %lu ",
- (ulong) rec_get_nth_field_size(rec, i));
-
+ fputs(" SQL NULL", file);
}
putc(';', file);
}
putc('\n', file);
- rec_validate(rec);
+ rec_validate(rec, offsets);
+}
+
+/*******************************************************************
+Prints a physical record. */
+
+void
+rec_print(
+/*======*/
+ FILE* file, /* in: file where to print */
+ rec_t* rec, /* in: physical record */
+ dict_index_t* index) /* in: record descriptor */
+{
+ ut_ad(index);
+
+ if (!index->table->comp) {
+ rec_print_old(file, rec);
+ return;
+ } else {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ rec_print_new(file, rec, rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap));
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ }
}
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 5ca1ee51cbd..303fe5749bc 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -256,7 +256,7 @@ row_ins_sec_index_entry_by_modify(
rec = btr_cur_get_rec(cursor);
ut_ad((cursor->index->type & DICT_CLUSTERED) == 0);
- ut_ad(rec_get_deleted_flag(rec));
+ ut_ad(rec_get_deleted_flag(rec, cursor->index->table->comp));
/* We know that in the alphabetical ordering, entry and rec are
identified. But in their binary form there may be differences if
@@ -321,7 +321,7 @@ row_ins_clust_index_entry_by_modify(
rec = btr_cur_get_rec(cursor);
- ut_ad(rec_get_deleted_flag(rec));
+ ut_ad(rec_get_deleted_flag(rec, cursor->index->table->comp));
heap = mem_heap_create(1024);
@@ -478,6 +478,8 @@ row_ins_cascade_calc_update_vec(
if (parent_ufield->field_no == parent_field_no) {
+ ulint fixed_size;
+
/* A field in the parent index record is
updated. Let us make the update vector
field for the child table. */
@@ -517,22 +519,26 @@ row_ins_cascade_calc_update_vec(
need to pad with spaces the new value of the
child column */
- if (dtype_is_fixed_size(type)
+ 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? */
+
+ if (fixed_size
&& ufield->new_val.len != UNIV_SQL_NULL
- && ufield->new_val.len
- < dtype_get_fixed_size(type)) {
+ && ufield->new_val.len < fixed_size) {
ufield->new_val.data =
mem_heap_alloc(heap,
- dtype_get_fixed_size(type));
- ufield->new_val.len =
- dtype_get_fixed_size(type);
+ 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),
- dtype_get_fixed_size(type));
+ fixed_size);
ut_memcpy(ufield->new_val.data,
parent_ufield->new_val.data,
parent_ufield->new_val.len);
@@ -594,7 +600,7 @@ row_ins_foreign_report_err(
ut_print_name(ef, trx, foreign->foreign_index->name);
if (rec) {
fputs(", there is a record:\n", ef);
- rec_print(ef, rec);
+ rec_print(ef, rec, foreign->foreign_index);
} else {
fputs(", the record is not available\n", ef);
}
@@ -649,7 +655,7 @@ row_ins_foreign_report_add_err(
}
if (rec) {
- rec_print(ef, rec);
+ rec_print(ef, rec, foreign->foreign_index);
}
putc('\n', ef);
@@ -711,7 +717,6 @@ row_ins_foreign_check_on_constraint(
dict_index_t* index;
dict_index_t* clust_index;
dtuple_t* ref;
- mem_heap_t* tmp_heap;
mem_heap_t* upd_vec_heap = NULL;
rec_t* rec;
rec_t* clust_rec;
@@ -720,14 +725,17 @@ row_ins_foreign_check_on_constraint(
ulint err;
ulint i;
trx_t* trx;
+ mem_heap_t* tmp_heap = NULL;
-
ut_a(thr && foreign && pcur && mtr);
trx = thr_get_trx(thr);
/* Since we are going to delete or update a row, we have to invalidate
- the MySQL query cache for table */
+ the MySQL query cache for table. A deadlock of threads is not possible
+ here because the caller of this function does not hold any latches with
+ the sync0sync.h rank above the kernel mutex. The query cache mutex has
+ a rank just above the kernel mutex. */
row_ins_invalidate_query_cache(thr, table->name);
@@ -821,7 +829,7 @@ row_ins_foreign_check_on_constraint(
err = DB_ROW_IS_REFERENCED;
row_ins_foreign_report_err(
-(char*)"Trying a too deep cascaded delete or update\n",
+"Trying a too deep cascaded delete or update\n",
thr, foreign, btr_pcur_get_rec(pcur), entry);
goto nonstandard_exit_func;
@@ -853,8 +861,6 @@ row_ins_foreign_check_on_constraint(
PAGE_CUR_LE, BTR_SEARCH_LEAF,
cascade->pcur, 0, mtr);
- mem_heap_free(tmp_heap);
-
clust_rec = btr_pcur_get_rec(cascade->pcur);
if (!page_rec_is_user_rec(clust_rec)
@@ -868,10 +874,10 @@ row_ins_foreign_check_on_constraint(
fputs("\n"
"InnoDB: record ", stderr);
- rec_print(stderr, rec);
+ rec_print(stderr, rec, index);
fputs("\n"
"InnoDB: clustered record ", stderr);
- rec_print(stderr, clust_rec);
+ rec_print(stderr, clust_rec, clust_index);
fputs("\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr);
@@ -889,9 +895,9 @@ row_ins_foreign_check_on_constraint(
/* Here it suffices to use a LOCK_REC_NOT_GAP type lock;
we already have a normal shared lock on the appropriate
gap if the search criterion was not unique */
-
- err = lock_clust_rec_read_check_and_lock(0, clust_rec,
- clust_index, LOCK_X, LOCK_REC_NOT_GAP, thr);
+
+ err = lock_clust_rec_read_check_and_lock_alt(0, clust_rec,
+ clust_index, LOCK_X, LOCK_REC_NOT_GAP, thr);
}
if (err != DB_SUCCESS) {
@@ -899,7 +905,7 @@ row_ins_foreign_check_on_constraint(
goto nonstandard_exit_func;
}
- if (rec_get_deleted_flag(clust_rec)) {
+ if (rec_get_deleted_flag(clust_rec, table->comp)) {
/* This can happen if there is a circular reference of
rows such that cascading delete comes to delete a row
already in the process of being delete marked */
@@ -1008,6 +1014,10 @@ row_ins_foreign_check_on_constraint(
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
+
if (upd_vec_heap) {
mem_heap_free(upd_vec_heap);
}
@@ -1015,6 +1025,9 @@ row_ins_foreign_check_on_constraint(
return(err);
nonstandard_exit_func:
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
if (upd_vec_heap) {
mem_heap_free(upd_vec_heap);
@@ -1042,16 +1055,19 @@ row_ins_set_shared_rec_lock(
LOCK_REC_NOT_GAP type lock */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
que_thr_t* thr) /* in: query thread */
{
ulint err;
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
if (index->type & DICT_CLUSTERED) {
- err = lock_clust_rec_read_check_and_lock(0, rec, index, LOCK_S,
- type, thr);
+ err = lock_clust_rec_read_check_and_lock(0,
+ rec, index, offsets, LOCK_S, type, thr);
} else {
- err = lock_sec_rec_read_check_and_lock(0, rec, index, LOCK_S,
- type, thr);
+ err = lock_sec_rec_read_check_and_lock(0,
+ rec, index, offsets, LOCK_S, type, thr);
}
return(err);
@@ -1069,16 +1085,19 @@ row_ins_set_exclusive_rec_lock(
LOCK_REC_NOT_GAP type lock */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
que_thr_t* thr) /* in: query thread */
{
ulint err;
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
if (index->type & DICT_CLUSTERED) {
- err = lock_clust_rec_read_check_and_lock(0, rec, index, LOCK_X,
- type, thr);
+ err = lock_clust_rec_read_check_and_lock(0,
+ rec, index, offsets, LOCK_X, type, thr);
} else {
- err = lock_sec_rec_read_check_and_lock(0, rec, index, LOCK_X,
- type, thr);
+ err = lock_sec_rec_read_check_and_lock(0,
+ rec, index, offsets, LOCK_X, type, thr);
}
return(err);
@@ -1117,7 +1136,11 @@ row_ins_check_foreign_constraint(
ulint err;
ulint i;
mtr_t mtr;
- trx_t* trx = thr_get_trx(thr);
+ trx_t* trx = thr_get_trx(thr);
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
run_again:
#ifdef UNIV_SYNC_DEBUG
@@ -1129,8 +1152,7 @@ run_again:
if (trx->check_foreigns == FALSE) {
/* The user has suppressed foreign key checks currently for
this session */
-
- return(DB_SUCCESS);
+ goto exit_func;
}
/* If any of the foreign key fields in entry is SQL NULL, we
@@ -1141,7 +1163,7 @@ run_again:
if (UNIV_SQL_NULL == dfield_get_len(
dtuple_get_nth_field(entry, i))) {
- return(DB_SUCCESS);
+ goto exit_func;
}
}
@@ -1164,8 +1186,8 @@ run_again:
with each foreign key constraint, one after
another, and the user has problems predicting in
which order they are performed. */
-
- return(DB_SUCCESS);
+
+ goto exit_func;
}
}
@@ -1199,10 +1221,10 @@ run_again:
fputs("\nor its .ibd file does not currently exist!\n", ef);
mutex_exit(&dict_foreign_err_mutex);
- return(DB_NO_REFERENCED_ROW);
+ err = DB_NO_REFERENCED_ROW;
}
- return(DB_SUCCESS);
+ goto exit_func;
}
ut_a(check_table && check_index);
@@ -1240,10 +1262,13 @@ run_again:
goto next_rec;
}
+ offsets = rec_get_offsets(rec, check_index,
+ offsets, ULINT_UNDEFINED, &heap);
+
if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
-
+
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, rec,
- check_index, thr);
+ check_index, offsets, thr);
if (err != DB_SUCCESS) {
break;
@@ -1252,13 +1277,14 @@ run_again:
goto next_rec;
}
- cmp = cmp_dtuple_rec(entry, rec);
+ cmp = cmp_dtuple_rec(entry, rec, offsets);
if (cmp == 0) {
- if (rec_get_deleted_flag(rec)) {
+ if (rec_get_deleted_flag(rec,
+ rec_offs_comp(offsets))) {
err = row_ins_set_shared_rec_lock(
- LOCK_ORDINARY,
- rec, check_index, thr);
+ LOCK_ORDINARY, rec,
+ check_index, offsets, thr);
if (err != DB_SUCCESS) {
break;
@@ -1269,9 +1295,9 @@ run_again:
into gaps */
err = row_ins_set_shared_rec_lock(
- LOCK_REC_NOT_GAP,
- rec, check_index, thr);
-
+ LOCK_REC_NOT_GAP, rec,
+ check_index, offsets, thr);
+
if (err != DB_SUCCESS) {
break;
@@ -1307,7 +1333,7 @@ run_again:
if (cmp < 0) {
err = row_ins_set_shared_rec_lock(LOCK_GAP,
- rec, check_index, thr);
+ rec, check_index, offsets, thr);
if (err != DB_SUCCESS) {
break;
@@ -1365,6 +1391,10 @@ do_possible_lock_wait:
err = trx->error_state;
}
+exit_func:
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
@@ -1462,19 +1492,23 @@ row_ins_dupl_error_with_rec(
that the caller already has a record lock on
the record! */
dtuple_t* entry, /* in: entry to insert */
- dict_index_t* index) /* in: index */
+ dict_index_t* index, /* in: index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
ulint matched_fields;
ulint matched_bytes;
ulint n_unique;
ulint i;
-
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
n_unique = dict_index_get_n_unique(index);
matched_fields = 0;
matched_bytes = 0;
- cmp_dtuple_rec_with_match(entry, rec, &matched_fields, &matched_bytes);
+ cmp_dtuple_rec_with_match(entry, rec, offsets,
+ &matched_fields, &matched_bytes);
if (matched_fields < n_unique) {
@@ -1495,7 +1529,7 @@ row_ins_dupl_error_with_rec(
}
}
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, index->table->comp)) {
return(TRUE);
}
@@ -1517,6 +1551,7 @@ row_ins_scan_sec_index_for_duplicate(
dtuple_t* entry, /* in: index entry */
que_thr_t* thr) /* in: query thread */
{
+#ifndef UNIV_HOTBACKUP
ulint n_unique;
ulint i;
int cmp;
@@ -1527,7 +1562,11 @@ row_ins_scan_sec_index_for_duplicate(
ibool moved;
mtr_t mtr;
trx_t* trx;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
n_unique = dict_index_get_n_unique(index);
/* If the secondary index is unique, but one of the fields in the
@@ -1567,6 +1606,9 @@ row_ins_scan_sec_index_for_duplicate(
trx = thr_get_trx(thr);
ut_ad(trx);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
if (innobase_query_is_update()) {
/* If the SQL-query will update or replace
@@ -1574,12 +1616,12 @@ row_ins_scan_sec_index_for_duplicate(
duplicates ( REPLACE, LOAD DATAFILE REPLACE,
INSERT ON DUPLICATE KEY UPDATE). */
- err = row_ins_set_exclusive_rec_lock(
- LOCK_ORDINARY,rec,index,thr);
+ err = row_ins_set_exclusive_rec_lock(LOCK_ORDINARY,
+ rec, index, offsets, thr);
} else {
- err = row_ins_set_shared_rec_lock(
- LOCK_ORDINARY, rec, index,thr);
+ err = row_ins_set_shared_rec_lock(LOCK_ORDINARY,
+ rec, index, offsets, thr);
}
if (err != DB_SUCCESS) {
@@ -1592,10 +1634,11 @@ row_ins_scan_sec_index_for_duplicate(
goto next_rec;
}
- cmp = cmp_dtuple_rec(entry, rec);
+ cmp = cmp_dtuple_rec(entry, rec, offsets);
if (cmp == 0) {
- if (row_ins_dupl_error_with_rec(rec, entry, index)) {
+ if (row_ins_dupl_error_with_rec(rec, entry,
+ index, offsets)) {
err = DB_DUPLICATE_KEY;
thr_get_trx(thr)->error_info = index;
@@ -1617,12 +1660,21 @@ next_rec:
}
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
mtr_commit(&mtr);
/* Restore old value */
dtuple_set_n_fields_cmp(entry, n_fields_cmp);
return(err);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/*******************************************************************
@@ -1642,11 +1694,16 @@ row_ins_duplicate_error_in_clust(
que_thr_t* thr, /* in: query thread */
mtr_t* mtr) /* in: mtr */
{
+#ifndef UNIV_HOTBACKUP
ulint err;
rec_t* rec;
page_t* page;
ulint n_unique;
- trx_t* trx = thr_get_trx(thr);
+ trx_t* trx = thr_get_trx(thr);
+ mem_heap_t*heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
UT_NOT_USED(mtr);
@@ -1674,6 +1731,8 @@ row_ins_duplicate_error_in_clust(
page = buf_frame_align(rec);
if (rec != page_get_infimum_rec(page)) {
+ offsets = rec_get_offsets(rec, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
/* We set a lock on the possible duplicate: this
is needed in logical logging of MySQL to make
@@ -1689,23 +1748,23 @@ row_ins_duplicate_error_in_clust(
err = row_ins_set_exclusive_rec_lock(
LOCK_REC_NOT_GAP,rec,cursor->index,
- thr);
+ offsets, thr);
} else {
err = row_ins_set_shared_rec_lock(
LOCK_REC_NOT_GAP,rec, cursor->index,
- thr);
+ offsets, thr);
}
if (err != DB_SUCCESS) {
-
- return(err);
+ goto func_exit;
}
if (row_ins_dupl_error_with_rec(rec, entry,
- cursor->index)) {
+ cursor->index, offsets)) {
trx->error_info = cursor->index;
- return(DB_DUPLICATE_KEY);
+ err = DB_DUPLICATE_KEY;
+ goto func_exit;
}
}
}
@@ -1716,7 +1775,8 @@ row_ins_duplicate_error_in_clust(
page = buf_frame_align(rec);
if (rec != page_get_supremum_rec(page)) {
-
+ offsets = rec_get_offsets(rec, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
if (innobase_query_is_update()) {
@@ -1726,32 +1786,41 @@ row_ins_duplicate_error_in_clust(
INSERT ON DUPLICATE KEY UPDATE). */
err = row_ins_set_exclusive_rec_lock(
- LOCK_REC_NOT_GAP,
- rec,cursor->index,thr);
+ LOCK_REC_NOT_GAP, rec,
+ cursor->index, offsets, thr);
} else {
err = row_ins_set_shared_rec_lock(
- LOCK_REC_NOT_GAP,rec,
- cursor->index, thr);
+ LOCK_REC_NOT_GAP, rec,
+ cursor->index, offsets, thr);
}
if (err != DB_SUCCESS) {
-
- return(err);
+ goto func_exit;
}
if (row_ins_dupl_error_with_rec(rec, entry,
- cursor->index)) {
+ cursor->index, offsets)) {
trx->error_info = cursor->index;
- return(DB_DUPLICATE_KEY);
+ err = DB_DUPLICATE_KEY;
+ goto func_exit;
}
+ mem_heap_free(heap);
}
ut_a(!(cursor->index->type & DICT_CLUSTERED));
/* This should never happen */
}
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+func_exit:
+ return(err);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/*******************************************************************
@@ -1833,7 +1902,11 @@ row_ins_index_entry_low(
ulint n_unique;
big_rec_t* big_rec = NULL;
mtr_t mtr;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
log_free_check();
mtr_start(&mtr);
@@ -1865,8 +1938,8 @@ row_ins_index_entry_low(
buf_frame_align(btr_cur_get_rec(&cursor))));
if (!page_rec_is_supremum(first_rec)) {
- ut_a((rec_get_n_fields(first_rec))
- == dtuple_get_n_fields(entry));
+ ut_a(rec_get_n_fields(first_rec, index)
+ == dtuple_get_n_fields(entry));
}
n_unique = dict_index_get_n_unique(index);
@@ -1944,7 +2017,7 @@ row_ins_index_entry_low(
if (err == DB_SUCCESS) {
if (ext_vec) {
- rec_set_field_extern_bits(insert_rec,
+ rec_set_field_extern_bits(insert_rec, index,
ext_vec, n_ext_vec, &mtr);
}
}
@@ -1954,14 +2027,18 @@ function_exit:
mtr_commit(&mtr);
if (big_rec) {
+ rec_t* rec;
mtr_start(&mtr);
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
BTR_MODIFY_TREE, &cursor, 0, &mtr);
+ rec = btr_cur_get_rec(&cursor);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
+ err = btr_store_big_rec_extern_fields(index, rec,
+ offsets, big_rec, &mtr);
- err = btr_store_big_rec_extern_fields(index,
- btr_cur_get_rec(&cursor),
- big_rec, &mtr);
if (modify) {
dtuple_big_rec_free(big_rec);
} else {
@@ -1971,6 +2048,9 @@ function_exit:
mtr_commit(&mtr);
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 9410f2ce7cc..7f78a5b723b 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -106,20 +106,6 @@ row_mysql_delay_if_needed(void)
}
/***********************************************************************
-Reads a MySQL format variable-length field (like VARCHAR) length and
-returns pointer to the field data. */
-
-byte*
-row_mysql_read_var_ref_noninline(
-/*=============================*/
- /* out: field + 2 */
- ulint* len, /* out: variable-length field length */
- byte* field) /* in: field */
-{
- return(row_mysql_read_var_ref(len, field));
-}
-
-/***********************************************************************
Frees the blob heap in prebuilt when no longer needed. */
void
@@ -133,6 +119,61 @@ row_mysql_prebuilt_free_blob_heap(
}
/***********************************************************************
+Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
+format. */
+
+byte*
+row_mysql_store_true_var_len(
+/*=========================*/
+ /* out: pointer to the data, we skip the 1 or 2 bytes
+ at the start that are used to store the len */
+ byte* dest, /* in: where to store */
+ ulint len, /* in: length, must fit in two bytes */
+ ulint lenlen) /* in: storage length of len: either 1 or 2 bytes */
+{
+ if (lenlen == 2) {
+ ut_a(len < 256 * 256);
+
+ mach_write_to_2_little_endian(dest, len);
+
+ return(dest + 2);
+ }
+
+ ut_a(lenlen == 1);
+ ut_a(len < 256);
+
+ mach_write_to_1(dest, len);
+
+ return(dest + 1);
+}
+
+/***********************************************************************
+Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
+returns a pointer to the data. */
+
+byte*
+row_mysql_read_true_varchar(
+/*========================*/
+ /* out: pointer to the data, we skip the 1 or 2 bytes
+ at the start that are used to store the len */
+ ulint* len, /* out: variable-length field length */
+ byte* field, /* in: field in the MySQL format */
+ ulint lenlen) /* in: storage length of len: either 1 or 2 bytes */
+{
+ if (lenlen == 2) {
+ *len = mach_read_from_2_little_endian(field);
+
+ return(field + 2);
+ }
+
+ ut_a(lenlen == 1);
+
+ *len = mach_read_from_1(field);
+
+ return(field + 1);
+}
+
+/***********************************************************************
Stores a reference to a BLOB in the MySQL format. */
void
@@ -191,15 +232,177 @@ row_mysql_read_blob_ref(
}
/******************************************************************
-Convert a row in the MySQL format to a row in the Innobase format. */
+Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
+The counterpart of this function is row_sel_field_store_in_mysql_format() in
+row0sel.c. */
+
+byte*
+row_mysql_store_col_in_innobase_format(
+/*===================================*/
+ /* out: up to which byte we used
+ buf in the conversion */
+ dfield_t* dfield, /* in/out: dfield where dtype
+ information must be already set when
+ this function is called! */
+ byte* buf, /* in/out: buffer for a converted
+ integer value; this must be at least
+ col_len long then! */
+ ibool row_format_col, /* TRUE if the mysql_data is from
+ a MySQL row, FALSE if from a MySQL
+ key value;
+ in MySQL, a true VARCHAR storage
+ format differs in a row and in a
+ key value: in a key value the length
+ is always stored in 2 bytes! */
+ byte* mysql_data, /* in: MySQL column value, not
+ SQL NULL; NOTE that dfield may also
+ get a pointer to mysql_data,
+ therefore do not discard this as long
+ as dfield is used! */
+ ulint col_len, /* in: MySQL column length; NOTE that
+ this is the storage length of the
+ column in the MySQL format row, not
+ 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 */
+{
+ byte* ptr = mysql_data;
+ dtype_t* dtype;
+ ulint type;
+ ulint lenlen;
+
+ dtype = dfield_get_type(dfield);
+
+ type = dtype->mtype;
+
+ if (type == DATA_INT) {
+ /* Store integer data in Innobase in a big-endian format,
+ sign bit negated if the data is a signed integer. In MySQL,
+ integers are stored in a little-endian format. */
+
+ ptr = buf + col_len;
+
+ for (;;) {
+ ptr--;
+ *ptr = *mysql_data;
+ if (ptr == buf) {
+ break;
+ }
+ mysql_data++;
+ }
+
+ if (!(dtype->prtype & DATA_UNSIGNED)) {
+
+ *ptr = (byte) (*ptr ^ 128);
+ }
+
+ buf += col_len;
+ } else if ((type == DATA_VARCHAR
+ || type == DATA_VARMYSQL
+ || type == DATA_BINARY)) {
+
+ if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
+ /* The length of the actual data is stored to 1 or 2
+ bytes at the start of the field */
+
+ if (row_format_col) {
+ if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
+ lenlen = 2;
+ } else {
+ lenlen = 1;
+ }
+ } else {
+ /* In a MySQL key value, lenlen is always 2 */
+ lenlen = 2;
+ }
+
+ ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
+ lenlen);
+ } else {
+ /* Remove trailing spaces from old style VARCHAR
+ columns. */
+
+ /* Handle UCS2 strings differently. */
+ ulint mbminlen = dtype_get_mbminlen(dtype);
+
+ ptr = mysql_data;
+
+ if (mbminlen == 2) {
+ /* space=0x0020 */
+ /* Trim "half-chars", just in case. */
+ col_len &= ~1;
+
+ while (col_len >= 2 && ptr[col_len - 2] == 0x00
+ && ptr[col_len - 1] == 0x20) {
+ col_len -= 2;
+ }
+ } else {
+ ut_a(mbminlen == 1);
+ /* space=0x20 */
+ while (col_len > 0
+ && ptr[col_len - 1] == 0x20) {
+ col_len--;
+ }
+ }
+ }
+ } else if (comp && type == DATA_MYSQL
+ && dtype_get_mbminlen(dtype) == 1
+ && dtype_get_mbmaxlen(dtype) > 1) {
+ /* In some cases we strip trailing spaces from UTF-8 and other
+ multibyte charsets, from FIXED-length CHAR columns, to save
+ space. UTF-8 would otherwise normally use 3 * the string length
+ bytes to store a latin1 string! */
+
+ /* We assume that this CHAR field is encoded in a
+ variable-length character set where spaces have
+ 1:1 correspondence to 0x20 bytes, such as UTF-8.
+
+ Consider a CHAR(n) field, a field of n characters.
+ It will contain between n * mbminlen and n * mbmaxlen bytes.
+ We will try to truncate it to n bytes by stripping
+ space padding. If the field contains single-byte
+ characters only, it will be truncated to n characters.
+ Consider a CHAR(5) field containing the string ".a "
+ where "." denotes a 3-byte character represented by
+ the bytes "$%&". After our stripping, the string will
+ be stored as "$%&a " (5 bytes). The string ".abc "
+ will be stored as "$%&abc" (6 bytes).
+
+ The space padding will be restored in row0sel.c, function
+ row_sel_field_store_in_mysql_format(). */
+
+ ulint n_chars;
+
+ ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
+
+ n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
+
+ /* Strip space padding. */
+ while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
+ col_len--;
+ }
+ } else if (type == DATA_BLOB && row_format_col) {
+
+ ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
+ }
+
+ dfield_set_data(dfield, ptr, col_len);
+
+ return(buf);
+}
+
+/******************************************************************
+Convert a row in the MySQL format to a row in the Innobase format. Note that
+the function to convert a MySQL format key value to an InnoDB dtuple is
+row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
static
void
row_mysql_convert_row_to_innobase(
/*==============================*/
dtuple_t* row, /* in/out: Innobase row where the
field type information is already
- copied there, or will be copied
- later */
+ copied there! */
row_prebuilt_t* prebuilt, /* in: prebuilt struct where template
must be of type ROW_MYSQL_WHOLE_ROW */
byte* mysql_rec) /* in: row in the MySQL format;
@@ -236,9 +439,10 @@ row_mysql_convert_row_to_innobase(
row_mysql_store_col_in_innobase_format(dfield,
prebuilt->ins_upd_rec_buff
+ templ->mysql_col_offset,
+ TRUE, /* MySQL row format data */
mysql_rec + templ->mysql_col_offset,
templ->mysql_col_len,
- templ->type, templ->is_unsigned);
+ prebuilt->table->comp);
next_column:
;
}
@@ -260,6 +464,7 @@ row_mysql_handle_errors(
que_thr_t* thr, /* in: query thread */
trx_savept_t* savept) /* in: savepoint or NULL */
{
+#ifndef UNIV_HOTBACKUP
ulint err;
handle_new_error:
@@ -359,6 +564,12 @@ handle_new_error:
trx->error_state = DB_SUCCESS;
return(FALSE);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/************************************************************************
@@ -421,6 +632,9 @@ row_create_prebuilt(
clust_index = dict_table_get_first_index(table);
+ /* Make sure that search_tuple is long enough for clustered index */
+ ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
+
ref_len = dict_index_get_n_unique(clust_index);
ref = dtuple_create(heap, ref_len);
@@ -583,7 +797,8 @@ static
dtuple_t*
row_get_prebuilt_insert_row(
/*========================*/
- /* out: prebuilt dtuple */
+ /* out: prebuilt dtuple; the column
+ type information is also set in it */
row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
handle */
{
@@ -773,6 +988,7 @@ row_unlock_tables_for_mysql(
lock_release_tables_off_kernel(trx);
mutex_exit(&kernel_mutex);
}
+
/*************************************************************************
Sets a table lock on the table mentioned in prebuilt. */
@@ -784,7 +1000,7 @@ 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 or a
prebuilt->select_lock_type */
ulint mode) /* in: lock mode of table */
{
@@ -822,8 +1038,14 @@ run_again:
if (table) {
err = lock_table(0, table, mode, thr);
} else {
- err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
- prebuilt->select_lock_type, thr);
+ 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);
+ }
}
trx->error_state = err;
@@ -946,8 +1168,12 @@ run_again:
if (err != DB_SUCCESS) {
que_thr_stop_for_mysql(thr);
+/* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
+
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
&savept);
+ thr->lock_state= QUE_THR_LOCK_NOLOCK;
+
if (was_lock_wait) {
goto run_again;
}
@@ -1193,9 +1419,11 @@ run_again:
return((int) err);
}
-
+
+ thr->lock_state= QUE_THR_LOCK_ROW;
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
&savept);
+ thr->lock_state= QUE_THR_LOCK_NOLOCK;;
if (was_lock_wait) {
goto run_again;
}
@@ -1224,6 +1452,57 @@ run_again:
return((int) err);
}
+/*************************************************************************
+Does an unlock of a row for MySQL. */
+
+int
+row_unlock_for_mysql(
+/*=================*/
+ /* out: error code or DB_SUCCESS */
+ row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
+ handle */
+{
+ rec_t* rec;
+ btr_pcur_t* cur = prebuilt->pcur;
+ trx_t* trx = prebuilt->trx;
+ mtr_t mtr;
+
+ ut_ad(prebuilt && trx);
+ ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
+
+ trx->op_info = "unlock_row";
+
+ if (srv_locks_unsafe_for_binlog) {
+ if (trx->trx_create_lock == TRUE) {
+
+ 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);
+
+ if (rec) {
+
+ 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;
+ }
+
+ trx->trx_create_lock = FALSE;
+ mtr_commit(&mtr);
+ }
+
+ }
+
+ trx->op_info = "";
+
+ return(DB_SUCCESS);
+}
+
/**************************************************************************
Does a cascaded delete or set null in a foreign key operation. */
@@ -2012,6 +2291,7 @@ row_add_table_to_background_drop_list(
return(TRUE);
}
+#ifndef UNIV_HOTBACKUP
/*************************************************************************
Discards the tablespace of a table which stored in an .ibd file. Discarding
means that this function deletes the .ibd file and assigns a new table id for
@@ -2362,6 +2642,302 @@ funct_exit:
}
/*************************************************************************
+Truncates a table for MySQL. */
+
+int
+row_truncate_table_for_mysql(
+/*=========================*/
+ /* out: error code or DB_SUCCESS */
+ dict_table_t* table, /* in: table handle */
+ trx_t* trx) /* in: transaction handle */
+{
+ dict_foreign_t* foreign;
+ ulint err;
+ mem_heap_t* heap;
+ byte* buf;
+ dtuple_t* tuple;
+ dfield_t* dfield;
+ dict_index_t* sys_index;
+ btr_pcur_t pcur;
+ mtr_t mtr;
+ dulint new_id;
+ char* sql;
+ que_thr_t* thr;
+ que_t* graph = NULL;
+
+/* How do we prevent crashes caused by ongoing operations on the table? Old
+operations could try to access non-existent pages.
+
+1) SQL queries, INSERT, SELECT, ...: we must get an exclusive MySQL table lock
+on the table before we can do TRUNCATE TABLE. Then there are no running
+queries on the table. This is guaranteed, because in
+ha_innobase::store_lock(), we do not weaken the TL_WRITE lock requested
+by MySQL when executing SQLCOM_TRUNCATE.
+2) Purge and rollback: we assign a new table id for the table. Since purge and
+rollback look for the table based on the table id, they see the table as
+'dropped' and discard their operations.
+3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE, so we do not
+have to remove insert buffer records, as the insert buffer works at a low
+level. If a freed page is later reallocated, the allocator will remove
+the ibuf entries for it.
+
+TODO: when we truncate *.ibd files (analogous to DISCARD TABLESPACE), we
+will have to remove we remove all entries for the table in the insert
+buffer tree!
+
+4) Linear readahead and random readahead: we use the same method as in 3) to
+discard ongoing operations. (This will only be relevant for TRUNCATE TABLE
+by DISCARD TABLESPACE.)
+5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we
+do not allow the TRUNCATE. We also reserve the data dictionary latch. */
+
+ static const char renumber_tablespace_proc[] =
+ "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
+ "old_id CHAR;\n"
+ "new_id CHAR;\n"
+ "old_id_low INT;\n"
+ "old_id_high INT;\n"
+ "new_id_low INT;\n"
+ "new_id_high INT;\n"
+ "BEGIN\n"
+ "old_id_high := %lu;\n"
+ "old_id_low := %lu;\n"
+ "new_id_high := %lu;\n"
+ "new_id_low := %lu;\n"
+ "old_id := CONCAT(TO_BINARY(old_id_high, 4), TO_BINARY(old_id_low, 4));\n"
+ "new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n"
+ "UPDATE SYS_TABLES SET ID = new_id\n"
+ "WHERE ID = old_id;\n"
+ "UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n"
+ "WHERE TABLE_ID = old_id;\n"
+ "UPDATE SYS_INDEXES SET TABLE_ID = new_id\n"
+ "WHERE TABLE_ID = old_id;\n"
+ "COMMIT WORK;\n"
+ "END;\n";
+
+ ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
+ ut_ad(table);
+
+ if (srv_created_new_raw) {
+ fputs(
+ "InnoDB: A new raw disk partition was initialized or\n"
+ "InnoDB: innodb_force_recovery is on: we do not allow\n"
+ "InnoDB: database modifications by the user. Shut down\n"
+ "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n"
+ "InnoDB: with raw, and innodb_force_... is removed.\n",
+ stderr);
+
+ return(DB_ERROR);
+ }
+
+ trx->op_info = "truncating table";
+
+ trx_start_if_not_started(trx);
+
+ /* Serialize data dictionary operations with dictionary mutex:
+ no deadlocks can occur then in these operations */
+
+ ut_a(trx->dict_operation_lock_mode == 0);
+ /* Prevent foreign key checks etc. while we are truncating the
+ table */
+
+ row_mysql_lock_data_dictionary(trx);
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+ ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+ /* Check if the table is referenced by foreign key constraints from
+ some other table (not the table itself) */
+
+ foreign = UT_LIST_GET_FIRST(table->referenced_list);
+
+ while (foreign && foreign->foreign_table == table) {
+ foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
+ }
+
+ if (foreign && trx->check_foreigns) {
+ FILE* ef = dict_foreign_err_file;
+
+ /* We only allow truncating a referenced table if
+ FOREIGN_KEY_CHECKS is set to 0 */
+
+ mutex_enter(&dict_foreign_err_mutex);
+ rewind(ef);
+ ut_print_timestamp(ef);
+
+ fputs(" Cannot truncate table ", ef);
+ ut_print_name(ef, trx, table->name);
+ fputs(" by DROP+CREATE\n"
+ "InnoDB: because it is referenced by ", ef);
+ ut_print_name(ef, trx, foreign->foreign_table_name);
+ putc('\n', ef);
+ mutex_exit(&dict_foreign_err_mutex);
+
+ err = DB_ERROR;
+ goto funct_exit;
+ }
+
+ /* TODO: could we replace the counter n_foreign_key_checks_running
+ with lock checks on the table? Acquire here an exclusive lock on the
+ table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
+ they can cope with the table having been truncated here? Foreign key
+ checks take an IS or IX lock on the table. */
+
+ if (table->n_foreign_key_checks_running > 0) {
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: Cannot truncate table ", stderr);
+ ut_print_name(stderr, trx, table->name);
+ fputs(" by DROP+CREATE\n"
+"InnoDB: because there is a foreign key check running on it.\n",
+ stderr);
+ err = DB_ERROR;
+
+ goto funct_exit;
+ }
+
+ /* Remove any locks there are on the table or its records */
+
+ lock_reset_all_on_table(table);
+
+ trx->table_id = table->id;
+
+ /* scan SYS_INDEXES for all indexes of the table */
+ heap = mem_heap_create(800);
+
+ tuple = dtuple_create(heap, 1);
+ dfield = dtuple_get_nth_field(tuple, 0);
+
+ buf = mem_heap_alloc(heap, 8);
+ mach_write_to_8(buf, table->id);
+
+ dfield_set_data(dfield, buf, 8);
+ sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
+ dict_index_copy_types(tuple, sys_index, 1);
+
+ mtr_start(&mtr);
+ btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
+ BTR_MODIFY_LEAF, &pcur, &mtr);
+ for (;;) {
+ rec_t* rec;
+ const byte* field;
+ ulint len;
+ ulint root_page_no;
+
+ if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
+ /* The end of SYS_INDEXES has been reached. */
+ break;
+ }
+
+ rec = btr_pcur_get_rec(&pcur);
+
+ field = rec_get_nth_field_old(rec, 0, &len);
+ ut_ad(len == 8);
+
+ if (memcmp(buf, field, len) != 0) {
+ /* End of indexes for the table (TABLE_ID mismatch). */
+ break;
+ }
+
+ if (rec_get_deleted_flag(rec, FALSE)) {
+ /* The index has been dropped. */
+ goto next_rec;
+ }
+
+ btr_pcur_store_position(&pcur, &mtr);
+
+ /* This call may commit and restart mtr. */
+ root_page_no = dict_truncate_index_tree(table, rec, &mtr);
+
+ btr_pcur_restore_position(BTR_MODIFY_LEAF, &pcur, &mtr);
+ rec = btr_pcur_get_rec(&pcur);
+
+ if (root_page_no != FIL_NULL) {
+ page_rec_write_index_page_no(rec,
+ DICT_SYS_INDEXES_PAGE_NO_FIELD,
+ root_page_no, &mtr);
+ /* We will need to commit and restart the
+ mini-transaction in order to avoid deadlocks.
+ The dict_truncate_index_tree() call has allocated
+ a page in this mini-transaction, and the rest of
+ this loop could latch another index page. */
+ mtr_commit(&mtr);
+ mtr_start(&mtr);
+ btr_pcur_restore_position(BTR_MODIFY_LEAF,
+ &pcur, &mtr);
+ }
+
+ next_rec:
+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+ }
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+
+ new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
+
+ mem_heap_empty(heap);
+ sql = mem_heap_alloc(heap, (sizeof renumber_tablespace_proc) + 40);
+ sprintf(sql, renumber_tablespace_proc,
+ (ulong) ut_dulint_get_high(table->id),
+ (ulong) ut_dulint_get_low(table->id),
+ (ulong) ut_dulint_get_high(new_id),
+ (ulong) ut_dulint_get_low(new_id));
+
+ graph = pars_sql(sql);
+
+ ut_a(graph);
+
+ mem_heap_free(heap);
+
+ graph->trx = trx;
+ trx->graph = NULL;
+
+ graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
+
+ thr = que_fork_start_command(graph);
+ ut_a(thr);
+
+ que_run_threads(thr);
+
+ que_graph_free(graph);
+
+ err = trx->error_state;
+
+ if (err != DB_SUCCESS) {
+ trx->error_state = DB_SUCCESS;
+ trx_general_rollback_for_mysql(trx, FALSE, NULL);
+ trx->error_state = DB_SUCCESS;
+ ut_print_timestamp(stderr);
+fputs(" InnoDB: Unable to assign a new identifier to table ", stderr);
+ ut_print_name(stderr, trx, table->name);
+ fputs("\n"
+"InnoDB: after truncating it. Background processes may corrupt the table!\n",
+ stderr);
+ err = DB_ERROR;
+ } else {
+ dict_table_change_id_in_cache(table, new_id);
+ }
+
+ dict_table_autoinc_initialize(table, 0);
+ dict_update_statistics(table);
+
+ trx_commit_for_mysql(trx);
+
+funct_exit:
+
+ row_mysql_unlock_data_dictionary(trx);
+
+ trx->op_info = "";
+
+ srv_wake_master_thread();
+
+ return((int) err);
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/*************************************************************************
Drops a table for MySQL. If the name of the table to be dropped is equal
with one of the predefined magic table names, then this also stops printing
the corresponding monitor output by the master thread. */
@@ -2756,7 +3332,9 @@ funct_exit:
trx->op_info = "";
+#ifndef UNIV_HOTBACKUP
srv_wake_master_thread();
+#endif /* !UNIV_HOTBACKUP */
return((int) err);
}
@@ -3012,8 +3590,9 @@ row_rename_table_for_mysql(
"InnoDB: data dictionary though MySQL is trying to rename the table.\n"
"InnoDB: Have you copied the .frm file of the table to the\n"
"InnoDB: MySQL database directory from another database?\n"
- "InnoDB: You can look for further help from section 15.1 of\n"
- "InnoDB: http://www.innodb.com/ibman.php\n", stderr);
+ "InnoDB: You can look for further help from\n"
+ "InnoDB: http://dev.mysql.com/doc/mysql/en/"
+ "InnoDB_troubleshooting_datadict.html\n", stderr);
goto funct_exit;
}
@@ -3025,8 +3604,9 @@ row_rename_table_for_mysql(
ut_print_name(stderr, trx, old_name);
fputs(
" does not have an .ibd file in the database directory.\n"
- "InnoDB: You can look for further help from section 15.1 of\n"
- "InnoDB: http://www.innodb.com/ibman.php\n", stderr);
+ "InnoDB: You can look for further help from\n"
+ "InnoDB: http://dev.mysql.com/doc/mysql/en/"
+ "InnoDB_troubleshooting_datadict.html\n", stderr);
goto funct_exit;
}
@@ -3290,18 +3870,21 @@ row_scan_and_check_index(
ulint* n_rows) /* out: number of entries seen in the
current consistent read */
{
- mem_heap_t* heap;
- dtuple_t* prev_entry = NULL;
+ dtuple_t* prev_entry = NULL;
ulint matched_fields;
ulint matched_bytes;
byte* buf;
ulint ret;
rec_t* rec;
- ibool is_ok = TRUE;
+ ibool is_ok = TRUE;
int cmp;
ibool contains_null;
ulint i;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
*n_rows = 0;
buf = mem_alloc(UNIV_PAGE_SIZE);
@@ -3341,8 +3924,10 @@ loop:
if (prev_entry != NULL) {
matched_fields = 0;
matched_bytes = 0;
-
- cmp = cmp_dtuple_rec_with_match(prev_entry, rec,
+
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
&matched_fields,
&matched_bytes);
contains_null = FALSE;
@@ -3371,7 +3956,7 @@ loop:
dtuple_print(stderr, prev_entry);
fputs("\n"
"InnoDB: record ", stderr);
- rec_print(stderr, rec);
+ rec_print_new(stderr, rec, offsets);
putc('\n', stderr);
is_ok = FALSE;
} else if ((index->type & DICT_UNIQUE)
@@ -3385,6 +3970,7 @@ loop:
}
mem_heap_empty(heap);
+ offsets = offsets_;
prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
diff --git a/innobase/row/row0purge.c b/innobase/row/row0purge.c
index f7e01169b9d..5893e016011 100644
--- a/innobase/row/row0purge.c
+++ b/innobase/row/row0purge.c
@@ -99,6 +99,10 @@ row_purge_remove_clust_if_poss_low(
ibool success;
ulint err;
mtr_t mtr;
+ rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
index = dict_table_get_first_index(node->table);
@@ -117,15 +121,24 @@ row_purge_remove_clust_if_poss_low(
return(TRUE);
}
+ rec = btr_pcur_get_rec(pcur);
+
if (0 != ut_dulint_cmp(node->roll_ptr,
- row_get_rec_roll_ptr(btr_pcur_get_rec(pcur), index))) {
-
+ row_get_rec_roll_ptr(rec, index, rec_get_offsets(
+ rec, index, offsets_, ULINT_UNDEFINED, &heap)))) {
+ if (heap) {
+ mem_heap_free(heap);
+ }
/* Someone else has modified the record later: do not remove */
btr_pcur_commit_specify_mtr(pcur, &mtr);
return(TRUE);
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
+
if (mode == BTR_MODIFY_LEAF) {
success = btr_cur_optimistic_delete(btr_cur, &mtr);
} else {
diff --git a/innobase/row/row0row.c b/innobase/row/row0row.c
index 38714b0c49b..a6d3f1d5ab0 100644
--- a/innobase/row/row0row.c
+++ b/innobase/row/row0row.c
@@ -37,17 +37,18 @@ row_get_rec_sys_field(
/* out: value of the field */
ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
rec_t* rec, /* in: record */
- dict_index_t* index) /* in: clustered index */
+ dict_index_t* index, /* in: clustered index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
- ulint pos;
- byte* field;
- ulint len;
+ ulint pos;
+ byte* field;
+ ulint len;
ut_ad(index->type & DICT_CLUSTERED);
pos = dict_index_get_sys_col_pos(index, type);
- field = rec_get_nth_field(rec, pos, &len);
+ field = rec_get_nth_field(rec, offsets, pos, &len);
if (type == DATA_TRX_ID) {
@@ -70,6 +71,7 @@ row_set_rec_sys_field(
ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
dulint val) /* in: value to set */
{
ulint pos;
@@ -77,10 +79,11 @@ row_set_rec_sys_field(
ulint len;
ut_ad(index->type & DICT_CLUSTERED);
+ ut_ad(rec_offs_validate(rec, index, offsets));
pos = dict_index_get_sys_col_pos(index, type);
- field = rec_get_nth_field(rec, pos, &len);
+ field = rec_get_nth_field(rec, offsets, pos, &len);
if (type == DATA_TRX_ID) {
@@ -182,6 +185,9 @@ row_build(
the buffer page of this record must be
at least s-latched and the latch held
as long as the row dtuple is used! */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index)
+ or NULL, in which case this function
+ will invoke rec_get_offsets() */
mem_heap_t* heap) /* in: memory heap from which the memory
needed is allocated */
{
@@ -196,14 +202,26 @@ row_build(
ulint row_len;
byte* buf;
ulint i;
-
+ mem_heap_t* tmp_heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
ut_ad(index && rec && heap);
ut_ad(index->type & DICT_CLUSTERED);
+ if (!offsets) {
+ offsets = rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &tmp_heap);
+ } else {
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ }
+
if (type != ROW_COPY_POINTERS) {
/* Take a copy of rec to heap */
- buf = mem_heap_alloc(heap, rec_get_size(rec));
- rec = rec_copy(buf, rec);
+ buf = mem_heap_alloc(heap, rec_offs_size(offsets));
+ rec = rec_copy(buf, rec, offsets);
+ /* Avoid a debug assertion in rec_offs_validate(). */
+ rec_offs_make_valid(rec, index, (ulint*) offsets);
}
table = index->table;
@@ -211,11 +229,9 @@ row_build(
row = dtuple_create(heap, row_len);
- dtuple_set_info_bits(row, rec_get_info_bits(rec));
-
- n_fields = dict_index_get_n_fields(index);
+ dtuple_set_info_bits(row, rec_get_info_bits(rec, table->comp));
- ut_ad(n_fields == rec_get_n_fields(rec));
+ n_fields = rec_offs_n_fields(offsets);
dict_table_copy_types(row, table);
@@ -227,13 +243,13 @@ row_build(
col = dict_field_get_col(ind_field);
dfield = dtuple_get_nth_field(row,
dict_col_get_no(col));
- field = rec_get_nth_field(rec, i, &len);
+ field = rec_get_nth_field(rec, offsets, i, &len);
if (type == ROW_COPY_ALSO_EXTERNALS
- && rec_get_nth_field_extern_bit(rec, i)) {
+ && rec_offs_nth_extern(offsets, i)) {
field = btr_rec_copy_externally_stored_field(
- rec, i, &len, heap);
+ rec, offsets, i, &len, heap);
}
dfield_set_data(dfield, field, len);
@@ -242,6 +258,10 @@ row_build(
ut_ad(dtuple_check_typed(row));
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
+
return(row);
}
@@ -276,16 +296,25 @@ row_rec_to_index_entry(
ulint len;
ulint rec_len;
byte* buf;
-
+ mem_heap_t* tmp_heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
ut_ad(rec && heap && index);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &tmp_heap);
+
if (type == ROW_COPY_DATA) {
/* Take a copy of rec to heap */
- buf = mem_heap_alloc(heap, rec_get_size(rec));
- rec = rec_copy(buf, rec);
+ buf = mem_heap_alloc(heap, rec_offs_size(offsets));
+ rec = rec_copy(buf, rec, offsets);
+ /* Avoid a debug assertion in rec_offs_validate(). */
+ rec_offs_make_valid(rec, index, offsets);
}
- rec_len = rec_get_n_fields(rec);
+ rec_len = rec_offs_n_fields(offsets);
entry = dtuple_create(heap, rec_len);
@@ -295,17 +324,21 @@ row_rec_to_index_entry(
dict_index_copy_types(entry, index, rec_len);
- dtuple_set_info_bits(entry, rec_get_info_bits(rec));
+ dtuple_set_info_bits(entry,
+ rec_get_info_bits(rec, rec_offs_comp(offsets)));
for (i = 0; i < rec_len; i++) {
dfield = dtuple_get_nth_field(entry, i);
- field = rec_get_nth_field(rec, i, &len);
+ field = rec_get_nth_field(rec, offsets, i, &len);
dfield_set_data(dfield, field, len);
}
ut_ad(dtuple_check_typed(entry));
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
return(entry);
}
@@ -345,15 +378,24 @@ row_build_row_ref(
byte* buf;
ulint clust_col_prefix_len;
ulint i;
-
+ mem_heap_t* tmp_heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
ut_ad(index && rec && heap);
-
+
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &tmp_heap);
+
if (type == ROW_COPY_DATA) {
/* Take a copy of rec to heap */
- buf = mem_heap_alloc(heap, rec_get_size(rec));
+ buf = mem_heap_alloc(heap, rec_offs_size(offsets));
- rec = rec_copy(buf, rec);
+ rec = rec_copy(buf, rec, offsets);
+ /* Avoid a debug assertion in rec_offs_validate(). */
+ rec_offs_make_valid(rec, index, offsets);
}
table = index->table;
@@ -373,7 +415,7 @@ row_build_row_ref(
ut_a(pos != ULINT_UNDEFINED);
- field = rec_get_nth_field(rec, pos, &len);
+ field = rec_get_nth_field(rec, offsets, pos, &len);
dfield_set_data(dfield, field, len);
@@ -391,12 +433,15 @@ row_build_row_ref(
dfield_set_len(dfield,
dtype_get_at_most_n_mbchars(
dfield_get_type(dfield),
- clust_col_prefix_len, len, field));
+ clust_col_prefix_len, len, (char*) field));
}
}
}
ut_ad(dtuple_check_typed(ref));
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
return(ref);
}
@@ -427,7 +472,11 @@ row_build_row_ref_in_tuple(
ulint pos;
ulint clust_col_prefix_len;
ulint i;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
ut_a(ref && index && rec);
if (!index->table) {
@@ -446,7 +495,9 @@ row_build_row_ref_in_tuple(
fputs("InnoDB: clust index for table ", stderr);
goto notfound;
}
-
+
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
ref_len = dict_index_get_n_unique(clust_index);
ut_ad(ref_len == dtuple_get_n_fields(ref));
@@ -459,8 +510,8 @@ row_build_row_ref_in_tuple(
pos = dict_index_get_nth_field_pos(index, clust_index, i);
ut_a(pos != ULINT_UNDEFINED);
-
- field = rec_get_nth_field(rec, pos, &len);
+
+ field = rec_get_nth_field(rec, offsets, pos, &len);
dfield_set_data(dfield, field, len);
@@ -478,12 +529,15 @@ row_build_row_ref_in_tuple(
dfield_set_len(dfield,
dtype_get_at_most_n_mbchars(
dfield_get_type(dfield),
- clust_col_prefix_len, len, field));
+ clust_col_prefix_len, len, (char*) field));
}
}
}
ut_ad(dtuple_check_typed(ref));
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
/***********************************************************************
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index f8218e08297..94cf82d6a3d 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -78,8 +78,20 @@ row_sel_sec_rec_is_for_clust_rec(
ulint n;
ulint i;
dtype_t* cur_type;
+ mem_heap_t* heap = NULL;
+ ulint clust_offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint sec_offsets_[REC_OFFS_SMALL_SIZE];
+ ulint* clust_offs = clust_offsets_;
+ ulint* sec_offs = sec_offsets_;
+ ibool is_equal = TRUE;
- UT_NOT_USED(clust_index);
+ *clust_offsets_ = (sizeof clust_offsets_) / sizeof *clust_offsets_;
+ *sec_offsets_ = (sizeof sec_offsets_) / sizeof *sec_offsets_;
+
+ clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs,
+ ULINT_UNDEFINED, &heap);
+ sec_offs = rec_get_offsets(sec_rec, sec_index, sec_offs,
+ ULINT_UNDEFINED, &heap);
n = dict_index_get_n_ordering_defined_by_user(sec_index);
@@ -87,10 +99,10 @@ row_sel_sec_rec_is_for_clust_rec(
ifield = dict_index_get_nth_field(sec_index, i);
col = dict_field_get_col(ifield);
- clust_field = rec_get_nth_field(clust_rec,
+ clust_field = rec_get_nth_field(clust_rec, clust_offs,
dict_col_get_clust_pos(col),
&clust_len);
- sec_field = rec_get_nth_field(sec_rec, i, &sec_len);
+ sec_field = rec_get_nth_field(sec_rec, sec_offs, i, &sec_len);
if (ifield->prefix_len > 0
&& clust_len != UNIV_SQL_NULL) {
@@ -101,17 +113,22 @@ row_sel_sec_rec_is_for_clust_rec(
clust_len = dtype_get_at_most_n_mbchars(
cur_type,
ifield->prefix_len,
- clust_len, clust_field);
+ clust_len, (char*) clust_field);
}
if (0 != cmp_data_data(dict_col_get_type(col),
clust_field, clust_len,
sec_field, sec_len)) {
- return(FALSE);
+ is_equal = FALSE;
+ goto func_exit;
}
}
- return(TRUE);
+func_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(is_equal);
}
/*************************************************************************
@@ -266,6 +283,7 @@ row_sel_fetch_columns(
dict_index_t* index, /* in: record index */
rec_t* rec, /* in: record in a clustered or non-clustered
index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
sym_node_t* column) /* in: first column in a column list, or
NULL */
{
@@ -275,6 +293,8 @@ row_sel_fetch_columns(
byte* data;
ulint len;
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
if (index->type & DICT_CLUSTERED) {
index_type = SYM_CLUST_FIELD_NO;
} else {
@@ -286,7 +306,7 @@ row_sel_fetch_columns(
if (field_no != ULINT_UNDEFINED) {
- data = rec_get_nth_field(rec, field_no, &len);
+ data = rec_get_nth_field(rec, offsets, field_no, &len);
if (column->copy_val) {
eval_node_copy_and_alloc_val(column, data,
@@ -491,6 +511,10 @@ row_sel_build_prev_vers(
read_view_t* read_view, /* in: read view */
plan_t* plan, /* in: plan node for table */
rec_t* rec, /* in: record in a clustered index */
+ ulint** offsets, /* in/out: offsets returned by
+ rec_get_offsets(rec, plan->index) */
+ mem_heap_t** offset_heap, /* in/out: memory heap from which
+ the offsets are allocated */
rec_t** old_vers, /* out: old version, or NULL if the
record does not exist in the view:
i.e., it was freshly inserted
@@ -506,8 +530,8 @@ row_sel_build_prev_vers(
}
err = row_vers_build_for_consistent_read(rec, mtr, plan->index,
- read_view, plan->old_vers_heap,
- old_vers);
+ offsets, read_view, offset_heap,
+ plan->old_vers_heap, old_vers);
return(err);
}
@@ -601,8 +625,16 @@ row_sel_get_clust_rec(
rec_t* clust_rec;
rec_t* old_vers;
ulint err;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
+ offsets = rec_get_offsets(rec,
+ btr_pcur_get_btr_cur(&plan->pcur)->index,
+ offsets, ULINT_UNDEFINED, &heap);
- row_build_row_ref_fast(plan->clust_ref, plan->clust_map, rec);
+ row_build_row_ref_fast(plan->clust_ref, plan->clust_map, rec, offsets);
index = dict_table_get_first_index(plan->table);
@@ -619,7 +651,7 @@ row_sel_get_clust_rec(
|| btr_pcur_get_low_match(&(plan->clust_pcur))
< dict_index_get_n_unique(index)) {
- ut_a(rec_get_deleted_flag(rec));
+ ut_a(rec_get_deleted_flag(rec, plan->table->comp));
ut_a(node->read_view);
/* In a rare case it is possible that no clust rec is found
@@ -636,29 +668,30 @@ row_sel_get_clust_rec(
goto func_exit;
}
+ offsets = rec_get_offsets(clust_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
if (!node->read_view) {
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
- we lock only the record, i.e. next-key locking is
- not used.
- */
+ we lock only the record, i.e., next-key locking is
+ not used. */
+ ulint lock_type;
if (srv_locks_unsafe_for_binlog) {
- err = lock_clust_rec_read_check_and_lock(0,
- clust_rec,
- index, node->row_lock_mode,
- LOCK_REC_NOT_GAP, thr);
+ lock_type = LOCK_REC_NOT_GAP;
} else {
- err = lock_clust_rec_read_check_and_lock(0,
- clust_rec,
- index, node->row_lock_mode,
- LOCK_ORDINARY, thr);
+ lock_type = LOCK_ORDINARY;
}
+ err = lock_clust_rec_read_check_and_lock(0,
+ clust_rec, index, offsets,
+ node->row_lock_mode, lock_type, thr);
+
if (err != DB_SUCCESS) {
- return(err);
+ goto err_exit;
}
} else {
/* This is a non-locking consistent read: if necessary, fetch
@@ -666,22 +699,21 @@ row_sel_get_clust_rec(
old_vers = NULL;
- if (!lock_clust_rec_cons_read_sees(clust_rec, index,
+ if (!lock_clust_rec_cons_read_sees(clust_rec, index, offsets,
node->read_view)) {
err = row_sel_build_prev_vers(node->read_view, plan,
- clust_rec, &old_vers, mtr);
+ clust_rec, &offsets, &heap,
+ &old_vers, mtr);
if (err != DB_SUCCESS) {
- return(err);
+ goto err_exit;
}
clust_rec = old_vers;
if (clust_rec == NULL) {
- *out_rec = clust_rec;
-
- return(DB_SUCCESS);
+ goto func_exit;
}
}
@@ -698,24 +730,26 @@ row_sel_get_clust_rec(
visit through secondary index records that would not really
exist in our snapshot. */
- if ((old_vers || rec_get_deleted_flag(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;
- *out_rec = clust_rec;
-
- return(DB_SUCCESS);
+ goto func_exit;
}
}
/* Fetch the columns needed in test conditions */
-
- row_sel_fetch_columns(index, clust_rec,
+
+ row_sel_fetch_columns(index, clust_rec, offsets,
UT_LIST_GET_FIRST(plan->columns));
func_exit:
*out_rec = clust_rec;
-
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+err_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(err);
}
/*************************************************************************
@@ -727,6 +761,7 @@ sel_set_rec_lock(
/* out: DB_SUCCESS or error code */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
ulint mode, /* in: lock mode */
ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or LOC_REC_NOT_GAP */
que_thr_t* thr) /* in: query thread */
@@ -744,11 +779,11 @@ sel_set_rec_lock(
}
if (index->type & DICT_CLUSTERED) {
- err = lock_clust_rec_read_check_and_lock(0, rec, index, mode,
- type, thr);
+ err = lock_clust_rec_read_check_and_lock(0,
+ rec, index, offsets, mode, type, thr);
} else {
- err = lock_sec_rec_read_check_and_lock(0, rec, index, mode,
- type, thr);
+ err = lock_sec_rec_read_check_and_lock(0,
+ rec, index, offsets, mode, type, thr);
}
return(err);
@@ -956,6 +991,11 @@ row_sel_try_search_shortcut(
{
dict_index_t* index;
rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ ulint ret;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
index = plan->index;
@@ -989,36 +1029,46 @@ row_sel_try_search_shortcut(
/* This is a non-locking consistent read: if necessary, fetch
a previous version of the record */
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
if (index->type & DICT_CLUSTERED) {
- if (!lock_clust_rec_cons_read_sees(rec, index,
+ if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
node->read_view)) {
- return(SEL_RETRY);
+ ret = SEL_RETRY;
+ goto func_exit;
}
} else if (!lock_sec_rec_cons_read_sees(rec, index, node->read_view)) {
- return(SEL_RETRY);
+ ret = SEL_RETRY;
+ goto func_exit;
}
/* Test deleted flag. Fetch the columns needed in test conditions. */
-
- row_sel_fetch_columns(index, rec, UT_LIST_GET_FIRST(plan->columns));
- if (rec_get_deleted_flag(rec)) {
+ row_sel_fetch_columns(index, rec, offsets,
+ UT_LIST_GET_FIRST(plan->columns));
- return(SEL_EXHAUSTED);
+ if (rec_get_deleted_flag(rec, plan->table->comp)) {
+
+ ret = SEL_EXHAUSTED;
+ goto func_exit;
}
/* Test the rest of search conditions */
if (!row_sel_test_other_conds(plan)) {
- return(SEL_EXHAUSTED);
+ ret = SEL_EXHAUSTED;
+ goto func_exit;
}
ut_ad(plan->pcur.latch_mode == node->latch_mode);
plan->n_rows_fetched++;
-
+func_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(SEL_FOUND);
}
@@ -1067,7 +1117,11 @@ row_sel(
to the next non-clustered record */
ulint found_flag;
ulint err;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
ut_ad(thr->run_node == node);
search_latch_locked = FALSE;
@@ -1218,22 +1272,23 @@ rec_loop:
if (!consistent_read) {
/* If innodb_locks_unsafe_for_binlog option is used,
- we lock only the record, i.e. next-key locking is
- not used.
- */
+ we lock only the record, i.e., next-key locking is
+ not used. */
+
+ rec_t* next_rec = page_rec_get_next(rec);
+ ulint lock_type;
+ offsets = rec_get_offsets(next_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
if (srv_locks_unsafe_for_binlog) {
- err = sel_set_rec_lock(page_rec_get_next(rec),
- index,
- node->row_lock_mode,
- LOCK_REC_NOT_GAP, thr);
+ lock_type = LOCK_REC_NOT_GAP;
} else {
- err = sel_set_rec_lock(page_rec_get_next(rec),
- index,
- node->row_lock_mode,
- LOCK_ORDINARY, thr);
+ lock_type = LOCK_ORDINARY;
}
+ err = sel_set_rec_lock(next_rec, index, offsets,
+ node->row_lock_mode, lock_type, thr);
+
if (err != DB_SUCCESS) {
/* Note that in this case we will store in pcur
the PREDECESSOR of the record we are waiting
@@ -1260,18 +1315,22 @@ rec_loop:
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
- we lock only the record, i.e. next-key locking is
- not used.
- */
+ we lock only the record, i.e., next-key locking is
+ not used. */
+
+ ulint lock_type;
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
if (srv_locks_unsafe_for_binlog) {
- err = sel_set_rec_lock(rec, index, node->row_lock_mode,
- LOCK_REC_NOT_GAP, thr);
+ lock_type = LOCK_REC_NOT_GAP;
} else {
- err = sel_set_rec_lock(rec, index, node->row_lock_mode,
- LOCK_ORDINARY, thr);
+ lock_type = LOCK_ORDINARY;
}
+ err = sel_set_rec_lock(rec, index, offsets,
+ node->row_lock_mode, lock_type, thr);
+
if (err != DB_SUCCESS) {
goto lock_wait_or_error;
@@ -1334,6 +1393,7 @@ rec_loop:
/* PHASE 3: Get previous version in a consistent read */
cons_read_requires_clust_rec = FALSE;
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
if (consistent_read) {
/* This is a non-locking consistent read: if necessary, fetch
@@ -1341,19 +1401,24 @@ rec_loop:
if (index->type & DICT_CLUSTERED) {
- if (!lock_clust_rec_cons_read_sees(rec, index,
+ if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
node->read_view)) {
err = row_sel_build_prev_vers(node->read_view,
- plan, rec, &old_vers,
- &mtr);
+ plan, rec,
+ &offsets, &heap,
+ &old_vers, &mtr);
if (err != DB_SUCCESS) {
goto lock_wait_or_error;
}
if (old_vers == NULL) {
+ offsets = rec_get_offsets(
+ rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
row_sel_fetch_columns(index, rec,
+ offsets,
UT_LIST_GET_FIRST(plan->columns));
if (!row_sel_test_end_conds(plan)) {
@@ -1376,7 +1441,8 @@ rec_loop:
/* Fetch the columns needed in test conditions */
- row_sel_fetch_columns(index, rec, UT_LIST_GET_FIRST(plan->columns));
+ row_sel_fetch_columns(index, rec, offsets,
+ UT_LIST_GET_FIRST(plan->columns));
/* Test the selection end conditions: these can only contain columns
which already are found in the index, even though the index might be
@@ -1391,7 +1457,8 @@ rec_loop:
goto table_exhausted;
}
- if (rec_get_deleted_flag(rec) && !cons_read_requires_clust_rec) {
+ if (rec_get_deleted_flag(rec, plan->table->comp)
+ && !cons_read_requires_clust_rec) {
/* The record is delete marked: we can skip it if this is
not a consistent read which might see an earlier version
@@ -1434,7 +1501,7 @@ rec_loop:
goto next_rec;
}
- if (rec_get_deleted_flag(clust_rec)) {
+ if (rec_get_deleted_flag(clust_rec, plan->table->comp)) {
/* The record is delete marked: we can skip it */
@@ -1592,8 +1659,9 @@ next_table_no_mtr:
if (search_latch_locked) {
rw_lock_s_unlock(&btr_search_latch);
}
-
- return(DB_SUCCESS);
+
+ err = DB_SUCCESS;
+ goto func_exit;
}
node->fetch_table++;
@@ -1626,6 +1694,7 @@ table_exhausted:
table_exhausted_no_mtr:
if (node->fetch_table == 0) {
+ err = DB_SUCCESS;
if (node->is_aggregate && !node->aggregate_already_fetched) {
@@ -1639,7 +1708,7 @@ table_exhausted_no_mtr:
rw_lock_s_unlock(&btr_search_latch);
}
- return(DB_SUCCESS);
+ goto func_exit;
}
node->state = SEL_NODE_NO_MORE_ROWS;
@@ -1650,7 +1719,7 @@ table_exhausted_no_mtr:
rw_lock_s_unlock(&btr_search_latch);
}
- return(DB_SUCCESS);
+ goto func_exit;
}
node->fetch_table--;
@@ -1674,8 +1743,8 @@ stop_for_a_while:
mtr_commit(&mtr);
ut_ad(sync_thread_levels_empty_gen(TRUE));
-
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+ goto func_exit;
commit_mtr_for_a_while:
/* Stores the cursor position and commits &mtr; this is used if
@@ -1710,6 +1779,10 @@ lock_wait_or_error:
ut_ad(sync_thread_levels_empty_gen(TRUE));
+func_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
@@ -1945,7 +2018,8 @@ Converts a key value stored in MySQL format to an Innobase dtuple. The last
field of the key value may be just a prefix of a fixed length field: hence
the parameter key_len. But currently we do not allow search keys where the
last field is only a prefix of the full key field len and print a warning if
-such appears. */
+such appears. A counterpart of this function is
+ha_innobase::store_key_val_for_row() in ha_innodb.cc. */
void
row_sel_convert_mysql_key_to_innobase(
@@ -2026,10 +2100,10 @@ row_sel_convert_mysql_key_to_innobase(
type = dfield_get_type(dfield)->mtype;
/* Calculate data length and data field total length */
-
+
if (type == DATA_BLOB) {
/* The key field is a column prefix of a BLOB or
- TEXT type column */
+ TEXT */
ut_a(field->prefix_len > 0);
@@ -2045,11 +2119,12 @@ row_sel_convert_mysql_key_to_innobase(
data_len = key_ptr[data_offset]
+ 256 * key_ptr[data_offset + 1];
data_field_len = data_offset + 2 + field->prefix_len;
+
data_offset += 2;
-
- type = DATA_CHAR; /* now that we know the length, we
- store the column value like it would
- be a fixed char field */
+
+ /* Now that we know the length, we store the column
+ value like it would be a fixed char field */
+
} else if (field->prefix_len > 0) {
/* Looks like MySQL pads unused end bytes in the
prefix with space. Therefore, also in UTF-8, it is ok
@@ -2069,14 +2144,32 @@ row_sel_convert_mysql_key_to_innobase(
data_field_len = data_offset + data_len;
}
+ if (dtype_get_mysql_type(dfield_get_type(dfield))
+ == DATA_MYSQL_TRUE_VARCHAR
+ && dfield_get_type(dfield)->mtype != DATA_INT) {
+ /* In a MySQL key value format, a true VARCHAR is
+ always preceded by 2 bytes of a length field.
+ dfield_get_type(dfield)->len returns the maximum
+ 'payload' len in bytes. That does not include the
+ 2 bytes that tell the actual data length.
+
+ We added the check != DATA_INT to make sure we do
+ not treat MySQL ENUM or SET as a true VARCHAR! */
+
+ data_len += 2;
+ data_field_len += 2;
+ }
+
/* Storing may use at most data_len bytes of buf */
if (!is_null) {
row_mysql_store_col_in_innobase_format(
- dfield, buf, key_ptr + data_offset,
- data_len, type,
- dfield_get_type(dfield)->prtype
- & DATA_UNSIGNED);
+ dfield,
+ buf,
+ FALSE, /* MySQL key value format col */
+ key_ptr + data_offset,
+ data_len,
+ index->table->comp);
buf += data_len;
}
@@ -2133,11 +2226,16 @@ row_sel_store_row_id_to_prebuilt(
/*=============================*/
row_prebuilt_t* prebuilt, /* in: prebuilt */
rec_t* index_rec, /* in: record */
- dict_index_t* index) /* in: index of the record */
+ dict_index_t* index, /* in: index of the record */
+ const ulint* offsets) /* in: rec_get_offsets
+ (index_rec, index) */
{
byte* data;
ulint len;
- data = rec_get_nth_field(index_rec,
+
+ ut_ad(rec_offs_validate(index_rec, index, offsets));
+
+ data = rec_get_nth_field(index_rec, offsets,
dict_index_get_sys_col_pos(index, DATA_ROW_ID), &len);
if (len != DATA_ROW_ID_LEN) {
@@ -2146,8 +2244,8 @@ row_sel_store_row_id_to_prebuilt(
dict_index_name_print(stderr, prebuilt->trx, index);
fprintf(stderr, "\n"
"InnoDB: Field number %lu, record:\n",
- (ulong) dict_index_get_sys_col_pos(index, DATA_ROW_ID));
- rec_print(stderr, index_rec);
+ (ulong) dict_index_get_sys_col_pos(index, DATA_ROW_ID));
+ rec_print_new(stderr, index_rec, offsets);
putc('\n', stderr);
ut_error;
}
@@ -2156,8 +2254,9 @@ row_sel_store_row_id_to_prebuilt(
}
/******************************************************************
-Stores a non-SQL-NULL field in the MySQL format. */
-UNIV_INLINE
+Stores a non-SQL-NULL field in the MySQL format. The counterpart of this
+function is row_mysql_store_col_in_innobase_format() in row0mysql.c. */
+static
void
row_sel_field_store_in_mysql_format(
/*================================*/
@@ -2165,17 +2264,19 @@ row_sel_field_store_in_mysql_format(
are not in themselves stored here: the caller must
allocate and copy the BLOB into buffer before, and pass
the pointer to the BLOB in 'data' */
- ulint col_len,/* in: MySQL column length */
+ const mysql_row_templ_t* templ, /* in: MySQL column template.
+ Its following fields are referenced:
+ type, is_unsigned, mysql_col_len, mbminlen, mbmaxlen */
byte* data, /* in: data to store */
- ulint len, /* in: length of the data */
- ulint type, /* in: data type */
- ulint is_unsigned)/* in: != 0 if an unsigned integer type */
+ ulint len) /* in: length of the data */
{
byte* ptr;
+ byte* field_end;
+ byte* pad_ptr;
ut_ad(len != UNIV_SQL_NULL);
- if (type == DATA_INT) {
+ if (templ->type == DATA_INT) {
/* Convert integer data from Innobase to a little-endian
format, sign bit restored to normal */
@@ -2190,31 +2291,103 @@ row_sel_field_store_in_mysql_format(
data++;
}
- if (!is_unsigned) {
+ if (!templ->is_unsigned) {
dest[len - 1] = (byte) (dest[len - 1] ^ 128);
}
- ut_ad(col_len == len);
- } else if (type == DATA_VARCHAR || type == DATA_VARMYSQL
- || type == DATA_BINARY) {
- /* Store the length of the data to the first two bytes of
- dest; does not do anything yet because MySQL has
- no real vars! */
+ ut_ad(templ->mysql_col_len == len);
+ } else if (templ->type == DATA_VARCHAR
+ || templ->type == DATA_VARMYSQL
+ || templ->type == DATA_BINARY) {
+
+ field_end = dest + templ->mysql_col_len;
+
+ if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
+ /* This is a >= 5.0.3 type true VARCHAR. Store the
+ length of the data to the first byte or the first
+ two bytes of dest. */
- dest = row_mysql_store_var_len(dest, len);
- ut_memcpy(dest, data, len);
+ dest = row_mysql_store_true_var_len(dest, len,
+ templ->mysql_length_bytes);
+ }
- /* ut_ad(col_len >= len + 2); No real var implemented in
- MySQL yet! */
+ /* Copy the actual data */
+ ut_memcpy(dest, data, len);
- } else if (type == DATA_BLOB) {
+ /* Pad with trailing spaces. We pad with spaces also the
+ unused end of a >= 5.0.3 true VARCHAR column, just in case
+ MySQL expects its contents to be deterministic. */
+
+ pad_ptr = dest + len;
+
+ ut_ad(templ->mbminlen <= templ->mbmaxlen);
+
+ /* We handle UCS2 charset strings differently. */
+ if (templ->mbminlen == 2) {
+ /* A space char is two bytes, 0x0020 in UCS2 */
+
+ if (len & 1) {
+ /* A 0x20 has been stripped from the column.
+ Pad it back. */
+
+ if (pad_ptr < field_end) {
+ *pad_ptr = 0x20;
+ pad_ptr++;
+ }
+ }
+
+ /* Pad the rest of the string with 0x0020 */
+
+ while (pad_ptr < field_end) {
+ *pad_ptr = 0x00;
+ pad_ptr++;
+ *pad_ptr = 0x20;
+ pad_ptr++;
+ }
+ } else {
+ ut_ad(templ->mbminlen == 1);
+ /* space=0x20 */
+
+ memset(pad_ptr, 0x20, field_end - pad_ptr);
+ }
+ } else if (templ->type == DATA_BLOB) {
/* Store a pointer to the BLOB buffer to dest: the BLOB was
already copied to the buffer in row_sel_store_mysql_rec */
- row_mysql_store_blob_ref(dest, col_len, data, len);
+ row_mysql_store_blob_ref(dest, templ->mysql_col_len, data,
+ len);
+ } else if (templ->type == DATA_MYSQL) {
+ memcpy(dest, data, len);
+
+ ut_a(templ->mysql_col_len >= len);
+ ut_a(templ->mbmaxlen >= templ->mbminlen);
+
+ ut_a(templ->mbmaxlen > templ->mbminlen
+ || templ->mysql_col_len == len);
+ /* The following assertion would fail for old tables
+ containing UTF-8 ENUM columns due to Bug #9526. */
+ ut_ad(!templ->mbmaxlen
+ || !(templ->mysql_col_len % templ->mbmaxlen));
+ ut_a(len * templ->mbmaxlen >= templ->mysql_col_len);
+
+ if (templ->mbminlen != templ->mbmaxlen) {
+ /* Pad with spaces. This undoes the stripping
+ done in row0mysql.ic, function
+ row_mysql_store_col_in_innobase_format(). */
+
+ memset(dest + len, 0x20, templ->mysql_col_len - len);
+ }
} else {
- ut_memcpy(dest, data, len);
- ut_ad(col_len == len);
+ ut_a(templ->type == DATA_CHAR
+ || templ->type == DATA_FIXBINARY
+ /*|| templ->type == DATA_SYS_CHILD
+ || templ->type == DATA_SYS*/
+ || templ->type == DATA_FLOAT
+ || templ->type == DATA_DOUBLE
+ || templ->type == DATA_DECIMAL);
+ ut_ad(templ->mysql_col_len == len);
+
+ memcpy(dest, data, len);
}
}
@@ -2233,9 +2406,11 @@ row_sel_store_mysql_rec(
case) */
byte* mysql_rec, /* out: row in the MySQL format */
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
- rec_t* rec) /* in: Innobase record in the index
+ rec_t* rec, /* in: Innobase record in the index
which was described in prebuilt's
template */
+ const ulint* offsets) /* in: array returned by
+ rec_get_offsets() */
{
mysql_row_templ_t* templ;
mem_heap_t* extern_field_heap = NULL;
@@ -2246,24 +2421,21 @@ row_sel_store_mysql_rec(
ulint i;
ut_ad(prebuilt->mysql_template);
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
if (prebuilt->blob_heap != NULL) {
mem_heap_free(prebuilt->blob_heap);
prebuilt->blob_heap = NULL;
}
- /* MySQL assumes that all columns have the SQL NULL bit set unless it
- is a nullable column with a non-NULL value */
-
- memset(mysql_rec, 0xFF, prebuilt->null_bitmap_len);
-
for (i = 0; i < prebuilt->n_template; i++) {
templ = prebuilt->mysql_template + i;
- data = rec_get_nth_field(rec, templ->rec_field_no, &len);
+ data = rec_get_nth_field(rec, offsets,
+ templ->rec_field_no, &len);
- if (rec_get_nth_field_extern_bit(rec, templ->rec_field_no)) {
+ if (rec_offs_nth_extern(offsets, templ->rec_field_no)) {
/* Copy an externally stored field to the temporary
heap */
@@ -2277,7 +2449,7 @@ row_sel_store_mysql_rec(
causes an assert */
data = btr_rec_copy_externally_stored_field(rec,
- templ->rec_field_no, &len,
+ offsets, templ->rec_field_no, &len,
extern_field_heap);
ut_a(len != UNIV_SQL_NULL);
@@ -2329,46 +2501,7 @@ row_sel_store_mysql_rec(
row_sel_field_store_in_mysql_format(
mysql_rec + templ->mysql_col_offset,
- templ->mysql_col_len, data, len,
- templ->type, templ->is_unsigned);
-
- if (templ->type == DATA_VARCHAR
- || templ->type == DATA_VARMYSQL
- || templ->type == DATA_BINARY) {
- /* Pad with trailing spaces */
- data = mysql_rec + templ->mysql_col_offset;
-
- /* Handle UCS2 strings differently. As no new
- collations will be introduced in 4.1, we
- hardcode the charset-collation codes here.
- 5.0 will use a different approach. */
- if (templ->charset == 35
- || templ->charset == 90
- || (templ->charset >= 128
- && templ->charset <= 144)) {
- /* space=0x0020 */
- ulint col_len = templ->mysql_col_len;
-
- ut_a(!(col_len & 1));
- if (len & 1) {
- /* A 0x20 has been stripped
- from the column.
- Pad it back. */
- goto pad_0x20;
- }
- /* Pad the rest of the string
- with 0x0020 */
- while (len < col_len) {
- data[len++] = 0x00;
- pad_0x20:
- data[len++] = 0x20;
- }
- } else {
- /* space=0x20 */
- memset(data + len, 0x20,
- templ->mysql_col_len - len);
- }
- }
+ templ, data, len);
/* Cleanup */
if (extern_field_heap) {
@@ -2389,6 +2522,8 @@ row_sel_store_mysql_rec(
bug number 154 in the MySQL bug database: GROUP BY
and DISTINCT could treat NULL values inequal. */
+ 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
@@ -2403,15 +2538,8 @@ row_sel_store_mysql_rec(
pad_char = '\0';
}
- /* Handle UCS2 strings differently. As no new
- collations will be introduced in 4.1,
- we hardcode the charset-collation codes here.
- 5.0 will use a different approach. */
- if (pad_char != '\0'
- && (templ->charset == 35
- || templ->charset == 90
- || (templ->charset >= 128
- && templ->charset <= 144))) {
+ /* 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));
@@ -2424,6 +2552,7 @@ row_sel_store_mysql_rec(
len -= 2;
}
} else {
+ ut_ad(!pad_char || templ->mbminlen == 1);
memset(mysql_rec + templ->mysql_col_offset,
pad_char, templ->mysql_col_len);
}
@@ -2444,6 +2573,10 @@ row_sel_build_prev_vers_for_mysql(
dict_index_t* clust_index, /* in: clustered index */
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
rec_t* rec, /* in: record in a clustered index */
+ ulint** offsets, /* in/out: offsets returned by
+ rec_get_offsets(rec, clust_index) */
+ mem_heap_t** offset_heap, /* in/out: memory heap from which
+ the offsets are allocated */
rec_t** old_vers, /* out: old version, or NULL if the
record does not exist in the view:
i.e., it was freshly inserted
@@ -2459,8 +2592,8 @@ row_sel_build_prev_vers_for_mysql(
}
err = row_vers_build_for_consistent_read(rec, mtr, clust_index,
- read_view, prebuilt->old_vers_heap,
- old_vers);
+ offsets, read_view, offset_heap,
+ prebuilt->old_vers_heap, old_vers);
return(err);
}
@@ -2484,6 +2617,10 @@ row_sel_get_clust_rec_for_mysql(
it, NULL if the old version did not exist
in the read view, i.e., it was a fresh
inserted version */
+ ulint** offsets,/* out: offsets returned by
+ rec_get_offsets(out_rec, clust_index) */
+ mem_heap_t** offset_heap,/* in/out: memory heap from which
+ the offsets are allocated */
mtr_t* mtr) /* in: mtr used to get access to the
non-clustered record; the same mtr is used to
access the clustered index */
@@ -2525,9 +2662,8 @@ row_sel_get_clust_rec_for_mysql(
clustered index record did not exist in the read view of
trx. */
- if (!rec_get_deleted_flag(rec)
+ if (!rec_get_deleted_flag(rec, sec_index->table->comp)
|| prebuilt->select_lock_type != LOCK_NONE) {
-
ut_print_timestamp(stderr);
fputs(" InnoDB: error clustered record"
" for sec rec not found\n"
@@ -2535,10 +2671,10 @@ row_sel_get_clust_rec_for_mysql(
dict_index_name_print(stderr, trx, sec_index);
fputs("\n"
"InnoDB: sec index record ", stderr);
- rec_print(stderr, rec);
+ rec_print(stderr, rec, sec_index);
fputs("\n"
"InnoDB: clust index record ", stderr);
- rec_print(stderr, clust_rec);
+ rec_print(stderr, clust_rec, clust_index);
putc('\n', stderr);
trx_print(stderr, trx);
@@ -2551,18 +2687,21 @@ row_sel_get_clust_rec_for_mysql(
goto func_exit;
}
+ *offsets = rec_get_offsets(clust_rec, clust_index, *offsets,
+ ULINT_UNDEFINED, offset_heap);
+
if (prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a lock on the index record; we are searching
the clust rec with a unique condition, hence
we set a LOCK_REC_NOT_GAP type lock */
err = lock_clust_rec_read_check_and_lock(0, clust_rec,
- clust_index,
+ clust_index, *offsets,
prebuilt->select_lock_type,
LOCK_REC_NOT_GAP, thr);
if (err != DB_SUCCESS) {
- return(err);
+ goto err_exit;
}
} else {
/* This is a non-locking consistent read: if necessary, fetch
@@ -2575,16 +2714,17 @@ row_sel_get_clust_rec_for_mysql(
if (trx->isolation_level > TRX_ISO_READ_UNCOMMITTED
&& !lock_clust_rec_cons_read_sees(clust_rec, clust_index,
- trx->read_view)) {
+ *offsets, trx->read_view)) {
err = row_sel_build_prev_vers_for_mysql(
trx->read_view, clust_index,
prebuilt, clust_rec,
+ offsets, offset_heap,
&old_vers, mtr);
if (err != DB_SUCCESS) {
- return(err);
+ goto err_exit;
}
clust_rec = old_vers;
@@ -2603,7 +2743,8 @@ row_sel_get_clust_rec_for_mysql(
visit through secondary index records that would not really
exist in our snapshot. */
- if (clust_rec && (old_vers || rec_get_deleted_flag(rec))
+ if (clust_rec && (old_vers
+ || rec_get_deleted_flag(rec, sec_index->table->comp))
&& !row_sel_sec_rec_is_for_clust_rec(rec, sec_index,
clust_rec, clust_index)) {
clust_rec = NULL;
@@ -2625,7 +2766,9 @@ func_exit:
btr_pcur_store_position(prebuilt->clust_pcur, mtr);
}
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+err_exit:
+ return(err);
}
/************************************************************************
@@ -2702,10 +2845,40 @@ row_sel_pop_cached_row_for_mysql(
row */
row_prebuilt_t* prebuilt) /* in: prebuilt struct */
{
- ut_ad(prebuilt->n_fetch_cached > 0);
-
- ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first],
- prebuilt->mysql_row_len);
+ ulint i;
+ mysql_row_templ_t* templ;
+ byte* cached_rec;
+ ut_ad(prebuilt->n_fetch_cached > 0);
+
+ if (prebuilt->keep_other_fields_on_keyread)
+ {
+ /* Copy cache record field by field, don't touch fields that
+ are not covered by current key */
+ cached_rec =
+ prebuilt->fetch_cache[prebuilt->fetch_cache_first];
+
+ for (i = 0; i < prebuilt->n_template; i++) {
+ templ = prebuilt->mysql_template + i;
+ ut_memcpy(
+ buf + templ->mysql_col_offset,
+ cached_rec + templ->mysql_col_offset,
+ templ->mysql_col_len);
+ /* Copy NULL bit of the current field from cached_rec
+ to buf */
+ if (templ->mysql_null_bit_mask)
+ {
+ buf[templ->mysql_null_byte_offset] ^=
+ (buf[templ->mysql_null_byte_offset] ^
+ cached_rec[templ->mysql_null_byte_offset]) &
+ (byte)templ->mysql_null_bit_mask;
+ }
+ }
+ }
+ else
+ {
+ ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first],
+ prebuilt->mysql_row_len);
+ }
prebuilt->n_fetch_cached--;
prebuilt->fetch_cache_first++;
@@ -2721,12 +2894,14 @@ void
row_sel_push_cache_row_for_mysql(
/*=============================*/
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
- rec_t* rec) /* in: record to push */
+ rec_t* rec, /* in: record to push */
+ const ulint* offsets) /* in: rec_get_offsets() */
{
byte* buf;
ulint i;
ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE);
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
ut_a(!prebuilt->templ_contains_blob);
if (prebuilt->fetch_cache[0] == NULL) {
@@ -2750,9 +2925,11 @@ row_sel_push_cache_row_for_mysql(
ut_ad(prebuilt->fetch_cache_first == 0);
- ut_a(row_sel_store_mysql_rec(
+ if (!row_sel_store_mysql_rec(
prebuilt->fetch_cache[prebuilt->n_fetch_cached],
- prebuilt, rec));
+ prebuilt, rec, offsets)) {
+ ut_error;
+ }
prebuilt->n_fetch_cached++;
}
@@ -2769,6 +2946,8 @@ row_sel_try_search_shortcut_for_mysql(
/* out: SEL_FOUND, SEL_EXHAUSTED, SEL_RETRY */
rec_t** out_rec,/* out: record if found */
row_prebuilt_t* prebuilt,/* in: prebuilt struct */
+ ulint** offsets,/* in/out: for rec_get_offsets(*out_rec) */
+ mem_heap_t** heap, /* in/out: heap for rec_get_offsets() */
mtr_t* mtr) /* in: started mtr */
{
dict_index_t* index = prebuilt->index;
@@ -2806,13 +2985,17 @@ row_sel_try_search_shortcut_for_mysql(
/* This is a non-locking consistent read: if necessary, fetch
a previous version of the record */
-
- if (!lock_clust_rec_cons_read_sees(rec, index, trx->read_view)) {
+
+ *offsets = rec_get_offsets(rec, index, *offsets,
+ ULINT_UNDEFINED, heap);
+
+ if (!lock_clust_rec_cons_read_sees(rec, index,
+ *offsets, trx->read_view)) {
return(SEL_RETRY);
}
- if (rec_get_deleted_flag(rec)) {
+ if (rec_get_deleted_flag(rec, index->table->comp)) {
return(SEL_EXHAUSTED);
}
@@ -2869,7 +3052,6 @@ row_search_for_mysql(
ibool moved;
ibool cons_read_requires_clust_rec;
ibool was_lock_wait;
- ulint ret;
ulint shortcut;
ibool unique_search = FALSE;
ibool unique_search_from_clust_index = FALSE;
@@ -2881,10 +3063,15 @@ row_search_for_mysql(
level is <= TRX_ISO_READ_COMMITTED,
then this is set to FALSE */
ibool success;
+ ibool comp;
ulint cnt = 0;
ulint next_offs;
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());
@@ -2993,9 +3180,8 @@ row_search_for_mysql(
prebuilt->n_rows_fetched++;
srv_n_rows_read++;
- trx->op_info = "";
-
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+ goto func_exit;
}
if (prebuilt->fetch_cache_first > 0
@@ -3004,9 +3190,9 @@ row_search_for_mysql(
/* The previous returned row was popped from the fetch
cache, but the cache was not full at the time of the
popping: no more rows can exist in the result set */
-
- trx->op_info = "";
- return(DB_RECORD_NOT_FOUND);
+
+ err = DB_RECORD_NOT_FOUND;
+ goto func_exit;
}
prebuilt->n_rows_fetched++;
@@ -3050,8 +3236,8 @@ row_search_for_mysql(
if (direction != 0 && !prebuilt->used_in_HANDLER) {
- trx->op_info = "";
- return(DB_RECORD_NOT_FOUND);
+ err = DB_RECORD_NOT_FOUND;
+ goto func_exit;
}
}
@@ -3101,13 +3287,14 @@ row_search_for_mysql(
}
#endif
shortcut = row_sel_try_search_shortcut_for_mysql(&rec,
- prebuilt, &mtr);
+ prebuilt, &offsets, &heap, &mtr);
if (shortcut == SEL_FOUND) {
#ifdef UNIV_SEARCH_DEBUG
- ut_a(0 == cmp_dtuple_rec(search_tuple, rec));
+ ut_a(0 == cmp_dtuple_rec(search_tuple,
+ rec, offsets));
#endif
if (!row_sel_store_mysql_rec(buf, prebuilt,
- rec)) {
+ rec, offsets)) {
err = DB_TOO_BIG_RECORD;
/* We let the main loop to do the
@@ -3131,12 +3318,10 @@ row_search_for_mysql(
trx->has_search_latch = FALSE;
}
- trx->op_info = "";
-
/* NOTE that we do NOT store the cursor
position */
-
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+ goto func_exit;
} else if (shortcut == SEL_EXHAUSTED) {
@@ -3154,12 +3339,11 @@ row_search_for_mysql(
trx->has_search_latch = FALSE;
}
- trx->op_info = "";
-
/* NOTE that we do NOT store the cursor
position */
- return(DB_RECORD_NOT_FOUND);
+ err = DB_RECORD_NOT_FOUND;
+ goto func_exit;
}
shortcut_fails_too_big_rec:
mtr_commit(&mtr);
@@ -3274,6 +3458,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)));
/*
fputs("Using ", stderr);
dict_index_name_print(stderr, index);
@@ -3301,8 +3487,10 @@ 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 == FALSE) {
- err = sel_set_rec_lock(rec, index,
+ 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) {
@@ -3322,9 +3510,11 @@ rec_loop:
/* Do sanity checks in case our cursor has bumped into page
corruption */
- next_offs = rec_get_next_offs(rec);
+ next_offs = rec_get_next_offs(rec, comp);
- if (next_offs >= UNIV_PAGE_SIZE || next_offs < PAGE_SUPREMUM) {
+ if (next_offs >= UNIV_PAGE_SIZE
+ || next_offs <
+ (ulint) (comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM)) {
if (srv_force_recovery == 0 || moves_up == FALSE) {
ut_print_timestamp(stderr);
@@ -3369,9 +3559,11 @@ rec_loop:
}
}
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
if (srv_force_recovery > 0) {
- if (!rec_validate(rec) || !btr_index_rec_validate(rec, index,
- FALSE)) {
+ 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: ",
@@ -3399,7 +3591,7 @@ rec_loop:
/* fputs("Comparing rec and search tuple\n", stderr); */
- if (0 != cmp_dtuple_rec(search_tuple, rec)) {
+ if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
if (prebuilt->select_lock_type != LOCK_NONE
&& set_also_gap_locks) {
@@ -3411,6 +3603,7 @@ rec_loop:
if (srv_locks_unsafe_for_binlog == FALSE) {
err = sel_set_rec_lock(rec, index,
+ offsets,
prebuilt->select_lock_type,
LOCK_GAP, thr);
if (err != DB_SUCCESS) {
@@ -3423,7 +3616,7 @@ rec_loop:
btr_pcur_store_position(pcur, &mtr);
- ret = DB_RECORD_NOT_FOUND;
+ err = DB_RECORD_NOT_FOUND;
/* ut_print_name(stderr, index->name);
fputs(" record not found 3\n", stderr); */
@@ -3432,7 +3625,7 @@ rec_loop:
} else if (match_mode == ROW_SEL_EXACT_PREFIX) {
- if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec)) {
+ if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) {
if (prebuilt->select_lock_type != LOCK_NONE
&& set_also_gap_locks) {
@@ -3444,6 +3637,7 @@ rec_loop:
if (srv_locks_unsafe_for_binlog == FALSE) {
err = sel_set_rec_lock(rec, index,
+ offsets,
prebuilt->select_lock_type,
LOCK_GAP, thr);
if (err != DB_SUCCESS) {
@@ -3456,7 +3650,7 @@ rec_loop:
btr_pcur_store_position(pcur, &mtr);
- ret = DB_RECORD_NOT_FOUND;
+ err = DB_RECORD_NOT_FOUND;
/* ut_print_name(stderr, index->name);
fputs(" record not found 4\n", stderr); */
@@ -3475,27 +3669,48 @@ rec_loop:
is a non-delete marked record, then it is enough to lock its
existence with LOCK_REC_NOT_GAP. */
+ ulint lock_type;
+
if (!set_also_gap_locks
- || (unique_search && !rec_get_deleted_flag(rec))) {
- err = sel_set_rec_lock(rec, index,
- prebuilt->select_lock_type,
- LOCK_REC_NOT_GAP, thr);
+ || (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
+ we lock only the record, i.e., next-key locking is
not used. */
- if (srv_locks_unsafe_for_binlog) {
- err = sel_set_rec_lock(rec, index,
- prebuilt->select_lock_type,
- LOCK_REC_NOT_GAP, thr);
+ if (srv_locks_unsafe_for_binlog) {
+ lock_type = LOCK_REC_NOT_GAP;
} else {
- err = sel_set_rec_lock(rec, index,
- prebuilt->select_lock_type,
- LOCK_ORDINARY, thr);
- }
+ lock_type = LOCK_ORDINARY;
+ }
}
-
+
+ /* If we are doing a 'greater or equal than a primary key
+ value' search from a clustered index, and we find a record
+ that has that exact primary key value, then there is no need
+ to lock the gap before the record, because no insert in the
+ gap can be in our search range. That is, no phantom row can
+ appear that way.
+
+ An example: if col1 is the primary key, the search is WHERE
+ col1 >= 100, and we find a record where col1 = 100, then no
+ need to lock the gap before that record. */
+
+ if (index == clust_index
+ && mode == PAGE_CUR_GE
+ && direction == 0
+ && dtuple_get_n_fields_cmp(search_tuple)
+ == dict_index_get_n_unique(index)
+ && 0 == cmp_dtuple_rec(search_tuple, rec, offsets)) {
+
+ lock_type = LOCK_REC_NOT_GAP;
+ }
+
+ err = sel_set_rec_lock(rec, index, offsets,
+ prebuilt->select_lock_type,
+ lock_type, thr);
+
if (err != DB_SUCCESS) {
goto lock_wait_or_error;
@@ -3518,11 +3733,12 @@ rec_loop:
if (srv_force_recovery < 5
&& !lock_clust_rec_cons_read_sees(rec, index,
- trx->read_view)) {
+ offsets, trx->read_view)) {
err = row_sel_build_prev_vers_for_mysql(
trx->read_view, clust_index,
prebuilt, rec,
+ &offsets, &heap,
&old_vers, &mtr);
if (err != DB_SUCCESS) {
@@ -3551,7 +3767,8 @@ rec_loop:
}
}
- if (rec_get_deleted_flag(rec) && !cons_read_requires_clust_rec) {
+ if (rec_get_deleted_flag(rec, comp)
+ && !cons_read_requires_clust_rec) {
/* The record is delete-marked: we can skip it if this is
not a consistent read which might see an earlier version
@@ -3565,6 +3782,12 @@ 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 && (cons_read_requires_clust_rec
|| prebuilt->need_to_access_clustered)) {
@@ -3574,7 +3797,8 @@ rec_loop:
mtr_has_extra_clust_latch = TRUE;
err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec,
- thr, &clust_rec, &mtr);
+ thr, &clust_rec,
+ &offsets, &heap, &mtr);
if (err != DB_SUCCESS) {
goto lock_wait_or_error;
@@ -3587,7 +3811,7 @@ rec_loop:
goto next_rec;
}
- if (rec_get_deleted_flag(clust_rec)) {
+ if (rec_get_deleted_flag(clust_rec, comp)) {
/* The record is delete marked: we can skip it */
@@ -3596,11 +3820,18 @@ rec_loop:
if (prebuilt->need_to_access_clustered) {
rec = clust_rec;
+ ut_ad(rec_offs_validate(rec, clust_index, offsets));
+ } else {
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
}
}
/* We found a qualifying row */
-
+ ut_ad(rec_offs_validate(rec,
+ rec == clust_rec ? clust_index : index,
+ offsets));
+
if (prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD
&& prebuilt->select_lock_type == LOCK_NONE
&& !prebuilt->templ_contains_blob
@@ -3618,7 +3849,7 @@ rec_loop:
not cache rows because there the cursor is a scrollable
cursor. */
- row_sel_push_cache_row_for_mysql(prebuilt, rec);
+ row_sel_push_cache_row_for_mysql(prebuilt, rec, offsets);
if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) {
@@ -3628,11 +3859,13 @@ rec_loop:
goto next_rec;
} else {
if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
- ut_memcpy(buf + 4, rec - rec_get_extra_size(rec),
- rec_get_size(rec));
- mach_write_to_4(buf, rec_get_extra_size(rec) + 4);
+ memcpy(buf + 4, rec - rec_offs_extra_size(offsets),
+ rec_offs_size(offsets));
+ mach_write_to_4(buf,
+ rec_offs_extra_size(offsets) + 4);
} else {
- if (!row_sel_store_mysql_rec(buf, prebuilt, rec)) {
+ if (!row_sel_store_mysql_rec(buf, prebuilt,
+ rec, offsets)) {
err = DB_TOO_BIG_RECORD;
goto lock_wait_or_error;
@@ -3640,8 +3873,13 @@ rec_loop:
}
if (prebuilt->clust_index_was_generated) {
+ if (rec != index_rec) {
+ offsets = rec_get_offsets(
+ index_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ }
row_sel_store_row_id_to_prebuilt(prebuilt, index_rec,
- index);
+ index, offsets);
}
}
got_row:
@@ -3661,7 +3899,7 @@ got_row:
btr_pcur_store_position(pcur, &mtr);
}
- ret = DB_SUCCESS;
+ err = DB_SUCCESS;
goto normal_return;
@@ -3700,9 +3938,9 @@ next_rec:
btr_pcur_store_position(pcur, &mtr);
if (match_mode != 0) {
- ret = DB_RECORD_NOT_FOUND;
+ err = DB_RECORD_NOT_FOUND;
} else {
- ret = DB_END_OF_INDEX;
+ err = DB_END_OF_INDEX;
}
goto normal_return;
@@ -3726,8 +3964,10 @@ 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;
+
if (was_lock_wait) {
mtr_start(&mtr);
@@ -3741,9 +3981,7 @@ lock_wait_or_error:
/* fputs("Using ", stderr);
dict_index_name_print(stderr, index);
fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
- trx->op_info = "";
-
- return(err);
+ goto func_exit;
normal_return:
/*-------------------------------------------------------------*/
@@ -3754,19 +3992,22 @@ normal_return:
if (prebuilt->n_fetch_cached > 0) {
row_sel_pop_cached_row_for_mysql(buf, prebuilt);
- ret = DB_SUCCESS;
+ err = DB_SUCCESS;
}
/* fputs("Using ", stderr);
dict_index_name_print(stderr, index);
fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
- if (ret == DB_SUCCESS) {
+ if (err == DB_SUCCESS) {
srv_n_rows_read++;
}
+func_exit:
trx->op_info = "";
-
- return(ret);
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(err);
}
/***********************************************************************
diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c
index e16d696314b..1cade0f304f 100644
--- a/innobase/row/row0umod.c
+++ b/innobase/row/row0umod.c
@@ -438,7 +438,7 @@ row_undo_mod_del_unmark_sec_and_undo_update(
dtuple_print(stderr, entry);
fputs("\n"
"InnoDB: record ", stderr);
- rec_print(stderr, btr_pcur_get_rec(&pcur));
+ rec_print(stderr, btr_pcur_get_rec(&pcur), index);
putc('\n', stderr);
trx_print(stderr, trx);
fputs("\n"
diff --git a/innobase/row/row0undo.c b/innobase/row/row0undo.c
index bc3cc8ea9f3..abe73cbe705 100644
--- a/innobase/row/row0undo.c
+++ b/innobase/row/row0undo.c
@@ -151,6 +151,10 @@ row_undo_search_clust_to_pcur(
mtr_t mtr;
ibool ret;
rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
mtr_start(&mtr);
@@ -161,8 +165,11 @@ row_undo_search_clust_to_pcur(
rec = btr_pcur_get_rec(&(node->pcur));
+ offsets = rec_get_offsets(rec, clust_index, offsets,
+ ULINT_UNDEFINED, &heap);
+
if (!found || 0 != ut_dulint_cmp(node->roll_ptr,
- row_get_rec_roll_ptr(rec, clust_index))) {
+ row_get_rec_roll_ptr(rec, clust_index, offsets))) {
/* We must remove the reservation on the undo log record
BEFORE releasing the latch on the clustered index page: this
@@ -175,7 +182,7 @@ row_undo_search_clust_to_pcur(
ret = FALSE;
} else {
node->row = row_build(ROW_COPY_DATA, clust_index, rec,
- node->heap);
+ offsets, node->heap);
btr_pcur_store_position(&(node->pcur), &mtr);
ret = TRUE;
@@ -183,6 +190,9 @@ row_undo_search_clust_to_pcur(
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(ret);
}
diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c
index 9192f6dc692..3305724a89b 100644
--- a/innobase/row/row0upd.c
+++ b/innobase/row/row0upd.c
@@ -301,19 +301,20 @@ recovery. */
void
row_upd_rec_sys_fields_in_recovery(
/*===============================*/
- rec_t* rec, /* in: record */
- ulint pos, /* in: TRX_ID position in rec */
- dulint trx_id, /* in: transaction id */
- dulint roll_ptr)/* in: roll ptr of the undo log record */
+ rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint pos, /* in: TRX_ID position in rec */
+ dulint trx_id, /* in: transaction id */
+ dulint roll_ptr)/* in: roll ptr of the undo log record */
{
byte* field;
ulint len;
- field = rec_get_nth_field(rec, pos, &len);
+ field = rec_get_nth_field(rec, offsets, pos, &len);
ut_ad(len == DATA_TRX_ID_LEN);
trx_write_trx_id(field, trx_id);
- field = rec_get_nth_field(rec, pos + 1, &len);
+ field = rec_get_nth_field(rec, offsets, pos + 1, &len);
ut_ad(len == DATA_ROLL_PTR_LEN);
trx_write_roll_ptr(field, roll_ptr);
}
@@ -361,8 +362,8 @@ row_upd_changes_field_size_or_external(
/* out: TRUE if the update changes the size of
some field in index or the field is external
in rec or update */
- rec_t* rec, /* in: record in index */
dict_index_t* index, /* in: index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
upd_t* update) /* in: update vector */
{
upd_field_t* upd_field;
@@ -372,6 +373,7 @@ row_upd_changes_field_size_or_external(
ulint n_fields;
ulint i;
+ ut_ad(rec_offs_validate(NULL, index, offsets));
n_fields = upd_get_n_fields(update);
for (i = 0; i < n_fields; i++) {
@@ -380,7 +382,7 @@ row_upd_changes_field_size_or_external(
new_val = &(upd_field->new_val);
new_len = new_val->len;
- if (new_len == UNIV_SQL_NULL) {
+ if (new_len == UNIV_SQL_NULL && !rec_offs_comp(offsets)) {
/* A bug fixed on Dec 31st, 2004: we looked at the
SQL NULL size from the wrong field! We may backport
this fix also to 4.0. The merge to 5.0 will be made
@@ -391,14 +393,14 @@ row_upd_changes_field_size_or_external(
upd_field->field_no));
}
- old_len = rec_get_nth_field_size(rec, upd_field->field_no);
-
+ old_len = rec_offs_nth_size(offsets, upd_field->field_no);
+
if (old_len != new_len) {
return(TRUE);
}
- if (rec_get_nth_field_extern_bit(rec, upd_field->field_no)) {
+ if (rec_offs_nth_extern(offsets, upd_field->field_no)) {
return(TRUE);
}
@@ -420,15 +422,18 @@ a clustered index */
void
row_upd_rec_in_place(
/*=================*/
- rec_t* rec, /* in/out: record where replaced */
- upd_t* update) /* in: update vector */
+ rec_t* rec, /* in/out: record where replaced */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ upd_t* update) /* in: update vector */
{
upd_field_t* upd_field;
dfield_t* new_val;
ulint n_fields;
ulint i;
- rec_set_info_bits(rec, update->info_bits);
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+
+ rec_set_info_bits(rec, rec_offs_comp(offsets), update->info_bits);
n_fields = upd_get_n_fields(update);
@@ -436,7 +441,7 @@ row_upd_rec_in_place(
upd_field = upd_get_nth_field(update, i);
new_val = &(upd_field->new_val);
- rec_set_nth_field(rec, upd_field->field_no,
+ rec_set_nth_field(rec, offsets, upd_field->field_no,
dfield_get_data(new_val),
dfield_get_len(new_val));
}
@@ -701,6 +706,9 @@ row_upd_build_sec_rec_difference_binary(
upd_t* update;
ulint n_diff;
ulint i;
+ ulint offsets_[REC_OFFS_SMALL_SIZE];
+ const ulint* offsets;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
/* This function is used only for a secondary index */
ut_a(0 == (index->type & DICT_CLUSTERED));
@@ -708,10 +716,12 @@ row_upd_build_sec_rec_difference_binary(
update = upd_create(dtuple_get_n_fields(entry), heap);
n_diff = 0;
+ offsets = rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap);
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field(rec, offsets, i, &len);
dfield = dtuple_get_nth_field(entry, i);
@@ -774,6 +784,9 @@ row_upd_build_difference_binary(
ulint trx_id_pos;
ibool extern_bit;
ulint i;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ const ulint* offsets;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
/* This function is used only for a clustered index */
ut_a(index->type & DICT_CLUSTERED);
@@ -785,9 +798,12 @@ row_upd_build_difference_binary(
roll_ptr_pos = dict_index_get_sys_col_pos(index, DATA_ROLL_PTR);
trx_id_pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
+ offsets = rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap);
+
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field(rec, offsets, i, &len);
dfield = dtuple_get_nth_field(entry, i);
@@ -799,7 +815,7 @@ row_upd_build_difference_binary(
goto skip_compare;
}
- extern_bit = rec_get_nth_field_extern_bit(rec, i);
+ extern_bit = rec_offs_nth_extern(offsets, i);
if (extern_bit != upd_ext_vec_contains(ext_vec, n_ext_vec, i)
|| !dfield_data_is_binary_equal(dfield, len, data)) {
@@ -1123,6 +1139,7 @@ void
row_upd_copy_columns(
/*=================*/
rec_t* rec, /* in: record in a clustered index */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
sym_node_t* column) /* in: first column in a column list, or
NULL */
{
@@ -1130,7 +1147,7 @@ row_upd_copy_columns(
ulint len;
while (column) {
- data = rec_get_nth_field(rec,
+ data = rec_get_nth_field(rec, offsets,
column->field_nos[SYM_CLUST_FIELD_NO],
&len);
eval_node_copy_and_alloc_val(column, data, len);
@@ -1177,7 +1194,11 @@ row_upd_store_row(
dict_index_t* clust_index;
upd_t* update;
rec_t* rec;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ const ulint* offsets;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES);
if (node->row != NULL) {
@@ -1189,10 +1210,12 @@ row_upd_store_row(
rec = btr_pcur_get_rec(node->pcur);
- node->row = row_build(ROW_COPY_DATA, clust_index, rec, node->heap);
-
+ offsets = rec_get_offsets(rec, clust_index, offsets_,
+ ULINT_UNDEFINED, &heap);
+ node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
+ node->heap);
node->ext_vec = mem_heap_alloc(node->heap, sizeof(ulint)
- * rec_get_n_fields(rec));
+ * rec_offs_n_fields(offsets));
if (node->is_delete) {
update = NULL;
} else {
@@ -1200,7 +1223,10 @@ row_upd_store_row(
}
node->n_ext_vec = btr_push_update_extern_fields(node->ext_vec,
- rec, update);
+ offsets, update);
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
/***************************************************************
@@ -1253,7 +1279,7 @@ row_upd_sec_index_entry(
dtuple_print(stderr, entry);
fputs("\n"
"InnoDB: record ", stderr);
- rec_print(stderr, rec);
+ rec_print(stderr, rec, index);
putc('\n', stderr);
trx_print(stderr, trx);
@@ -1265,7 +1291,7 @@ row_upd_sec_index_entry(
delete marked if we return after a lock wait in
row_ins_index_entry below */
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, index->table->comp)) {
err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
thr, &mtr);
if (err == DB_SUCCESS && check_ref) {
@@ -1353,7 +1379,7 @@ row_upd_clust_rec_by_insert(
a foreign key constraint */
mtr_t* mtr) /* in: mtr; gets committed here */
{
- mem_heap_t* heap;
+ mem_heap_t* heap = NULL;
btr_pcur_t* pcur;
btr_cur_t* btr_cur;
trx_t* trx;
@@ -1370,12 +1396,13 @@ row_upd_clust_rec_by_insert(
btr_cur = btr_pcur_get_btr_cur(pcur);
if (node->state != UPD_NODE_INSERT_CLUSTERED) {
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
btr_cur, TRUE, thr, mtr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);
-
return(err);
}
@@ -1385,7 +1412,9 @@ row_upd_clust_rec_by_insert(
record is removed from the index tree, or updated. */
btr_cur_mark_extern_inherited_fields(btr_cur_get_rec(btr_cur),
- node->update, mtr);
+ rec_get_offsets(btr_cur_get_rec(btr_cur),
+ dict_table_get_first_index(table), offsets_,
+ ULINT_UNDEFINED, &heap), node->update, mtr);
if (check_ref) {
/* NOTE that the following call loses
the position of pcur ! */
@@ -1394,7 +1423,9 @@ row_upd_clust_rec_by_insert(
index, thr, mtr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);
-
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
}
@@ -1403,10 +1434,11 @@ row_upd_clust_rec_by_insert(
mtr_commit(mtr);
+ if (!heap) {
+ heap = mem_heap_create(500);
+ }
node->state = UPD_NODE_INSERT_CLUSTERED;
- heap = mem_heap_create(500);
-
entry = row_build_index_entry(node->row, index, heap);
row_upd_index_replace_new_col_vals(entry, index, node->update, NULL);
@@ -1458,7 +1490,8 @@ row_upd_clust_rec(
pcur = node->pcur;
btr_cur = btr_pcur_get_btr_cur(pcur);
- ut_ad(FALSE == rec_get_deleted_flag(btr_pcur_get_rec(pcur)));
+ ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
+ index->table->comp));
/* Try optimistic updating of the record, keeping changes within
the page; we do not check locks because we assume the x-lock on the
@@ -1494,7 +1527,8 @@ row_upd_clust_rec(
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
- ut_ad(FALSE == rec_get_deleted_flag(btr_pcur_get_rec(pcur)));
+ ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
+ index->table->comp));
err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
&big_rec, node->update,
@@ -1502,12 +1536,22 @@ row_upd_clust_rec(
mtr_commit(mtr);
if (err == DB_SUCCESS && big_rec) {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ rec_t* rec;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
mtr_start(mtr);
+
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
-
- err = btr_store_big_rec_extern_fields(index,
- btr_cur_get_rec(btr_cur),
- big_rec, mtr);
+ rec = btr_cur_get_rec(btr_cur);
+ err = btr_store_big_rec_extern_fields(index, rec,
+ rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap),
+ big_rec, mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
mtr_commit(mtr);
}
@@ -1591,7 +1635,12 @@ row_upd_clust_step(
ulint err;
mtr_t* mtr;
mtr_t mtr_buf;
-
+ rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ const ulint* offsets;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
index = dict_table_get_first_index(node->table);
check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
@@ -1647,14 +1696,16 @@ row_upd_clust_step(
}
}
+ rec = btr_pcur_get_rec(pcur);
+ offsets = rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap);
+
if (!node->has_clust_rec_x_lock) {
err = lock_clust_rec_modify_check_and_lock(0,
- btr_pcur_get_rec(pcur),
- index, thr);
+ rec, index, offsets, thr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);
-
- return(err);
+ goto exit_func;
}
}
@@ -1663,14 +1714,14 @@ row_upd_clust_step(
if (node->is_delete) {
err = row_upd_del_mark_clust_rec(node, index, thr, check_ref,
mtr);
- if (err != DB_SUCCESS) {
-
- return(err);
+ if (err == DB_SUCCESS) {
+ node->state = UPD_NODE_UPDATE_ALL_SEC;
+ node->index = dict_table_get_next_index(index);
+ }
+ exit_func:
+ if (heap) {
+ mem_heap_free(heap);
}
-
- node->state = UPD_NODE_UPDATE_ALL_SEC;
- node->index = dict_table_get_next_index(index);
-
return(err);
}
@@ -1680,16 +1731,18 @@ row_upd_clust_step(
if (!node->in_mysql_interface) {
/* Copy the necessary columns from clust_rec and calculate the
new values to set */
-
- row_upd_copy_columns(btr_pcur_get_rec(pcur),
+ row_upd_copy_columns(rec, offsets,
UT_LIST_GET_FIRST(node->columns));
row_upd_eval_new_vals(node->update);
}
+
+ if (heap) {
+ mem_heap_free(heap);
+ }
if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
err = row_upd_clust_rec(node, index, thr, mtr);
-
return(err);
}
@@ -1941,6 +1994,9 @@ row_upd_in_place_in_select(
btr_pcur_t* pcur;
btr_cur_t* btr_cur;
ulint err;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
ut_ad(sel_node->select_will_do_update);
ut_ad(sel_node->latch_mode == BTR_MODIFY_LEAF);
@@ -1956,11 +2012,17 @@ row_upd_in_place_in_select(
/* Copy the necessary columns from clust_rec and calculate the new
values to set */
- row_upd_copy_columns(btr_pcur_get_rec(pcur),
- UT_LIST_GET_FIRST(node->columns));
+ row_upd_copy_columns(btr_pcur_get_rec(pcur), rec_get_offsets(
+ btr_pcur_get_rec(pcur), btr_cur->index, offsets_,
+ ULINT_UNDEFINED, &heap),
+ UT_LIST_GET_FIRST(node->columns));
+ if (heap) {
+ mem_heap_free(heap);
+ }
row_upd_eval_new_vals(node->update);
- ut_ad(FALSE == rec_get_deleted_flag(btr_pcur_get_rec(pcur)));
+ ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
+ btr_cur->index->table->comp));
ut_ad(node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE);
ut_ad(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE);
diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c
index bc17ede89e3..36f6c27636d 100644
--- a/innobase/row/row0vers.c
+++ b/innobase/row/row0vers.c
@@ -41,10 +41,12 @@ row_vers_impl_x_locked_off_kernel(
transaction; NOTE that the kernel mutex is
temporarily released! */
rec_t* rec, /* in: record in a secondary index */
- dict_index_t* index) /* in: the secondary index */
+ dict_index_t* index, /* in: the secondary index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
dict_index_t* clust_index;
rec_t* clust_rec;
+ ulint* clust_offsets;
rec_t* version;
rec_t* prev_version;
dulint trx_id;
@@ -59,6 +61,7 @@ row_vers_impl_x_locked_off_kernel(
ibool rec_del;
ulint err;
mtr_t mtr;
+ ibool comp;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
@@ -96,29 +99,33 @@ row_vers_impl_x_locked_off_kernel(
return(NULL);
}
- trx_id = row_get_rec_trx_id(clust_rec, clust_index);
+ heap = mem_heap_create(1024);
+ clust_offsets = rec_get_offsets(clust_rec, clust_index, NULL,
+ ULINT_UNDEFINED, &heap);
+ trx_id = row_get_rec_trx_id(clust_rec, clust_index, clust_offsets);
mtr_s_lock(&(purge_sys->latch), &mtr);
mutex_enter(&kernel_mutex);
+ trx = NULL;
if (!trx_is_active(trx_id)) {
/* The transaction that modified or inserted clust_rec is no
longer active: no implicit lock on rec */
-
- mtr_commit(&mtr);
-
- return(NULL);
+ goto exit_func;
}
- if (!lock_check_trx_id_sanity(trx_id, clust_rec, clust_index, TRUE)) {
+ if (!lock_check_trx_id_sanity(trx_id, clust_rec, clust_index,
+ clust_offsets, TRUE)) {
/* Corruption noticed: try to avoid a crash by returning */
-
- mtr_commit(&mtr);
-
- return(NULL);
+ goto exit_func;
}
+ comp = index->table->comp;
+ 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)));
+
/* 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
a different state (delete marked or unmarked, or have different field
@@ -128,11 +135,10 @@ row_vers_impl_x_locked_off_kernel(
different state, then the trx_id transaction has not yet had time to
modify rec, and does not necessarily have an implicit x-lock on rec. */
- rec_del = rec_get_deleted_flag(rec);
+ rec_del = rec_get_deleted_flag(rec, comp);
trx = NULL;
version = clust_rec;
- heap = NULL;
for (;;) {
mutex_exit(&kernel_mutex);
@@ -146,18 +152,17 @@ row_vers_impl_x_locked_off_kernel(
heap2 = heap;
heap = mem_heap_create(1024);
-
err = trx_undo_prev_version_build(clust_rec, &mtr, version,
- clust_index, heap,
- &prev_version);
- if (heap2) {
- mem_heap_free(heap2); /* version was stored in heap2,
- if heap2 != NULL */
- }
+ clust_index, clust_offsets, heap,
+ &prev_version);
+ mem_heap_free(heap2); /* free version and clust_offsets */
if (prev_version) {
+ clust_offsets = rec_get_offsets(prev_version,
+ clust_index, NULL,
+ ULINT_UNDEFINED, &heap);
row = row_build(ROW_COPY_POINTERS, clust_index,
- prev_version, heap);
+ prev_version, clust_offsets, heap);
entry = row_build_index_entry(row, index, heap);
}
@@ -189,11 +194,11 @@ row_vers_impl_x_locked_off_kernel(
if prev_version would require rec to be in a different
state. */
- vers_del = rec_get_deleted_flag(prev_version);
+ vers_del = rec_get_deleted_flag(prev_version, comp);
/* We check if entry and rec are identified in the alphabetical
ordering */
- if (0 == cmp_dtuple_rec(entry, rec)) {
+ if (0 == cmp_dtuple_rec(entry, rec, offsets)) {
/* The delete marks of rec and prev_version should be
equal for rec to be in the state required by
prev_version */
@@ -211,7 +216,7 @@ row_vers_impl_x_locked_off_kernel(
dtuple_set_types_binary(entry,
dtuple_get_n_fields(entry));
- if (0 != cmp_dtuple_rec(entry, rec)) {
+ if (0 != cmp_dtuple_rec(entry, rec, offsets)) {
trx = trx_get_on_id(trx_id);
@@ -226,7 +231,8 @@ row_vers_impl_x_locked_off_kernel(
break;
}
- prev_trx_id = row_get_rec_trx_id(prev_version, clust_index);
+ prev_trx_id = row_get_rec_trx_id(prev_version, clust_index,
+ clust_offsets);
if (0 != ut_dulint_cmp(trx_id, prev_trx_id)) {
/* The versions modified by the trx_id transaction end
@@ -238,6 +244,7 @@ row_vers_impl_x_locked_off_kernel(
version = prev_version;
}/* for (;;) */
+exit_func:
mtr_commit(&mtr);
mem_heap_free(heap);
@@ -297,12 +304,14 @@ row_vers_old_has_index_entry(
rec_t* version;
rec_t* prev_version;
dict_index_t* clust_index;
+ ulint* clust_offsets;
mem_heap_t* heap;
mem_heap_t* heap2;
dtuple_t* row;
dtuple_t* entry;
ulint err;
-
+ ibool comp;
+
ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX)
|| mtr_memo_contains(mtr, buf_block_align(rec),
MTR_MEMO_PAGE_S_FIX));
@@ -313,10 +322,15 @@ row_vers_old_has_index_entry(
clust_index = dict_table_get_first_index(index->table);
- if (also_curr && !rec_get_deleted_flag(rec)) {
+ comp = index->table->comp;
+ ut_ad(comp == page_is_comp(buf_frame_align(rec)));
+ heap = mem_heap_create(1024);
+ clust_offsets = rec_get_offsets(rec, clust_index, NULL,
+ ULINT_UNDEFINED, &heap);
- heap = mem_heap_create(1024);
- row = row_build(ROW_COPY_POINTERS, clust_index, rec, heap);
+ if (also_curr && !rec_get_deleted_flag(rec, comp)) {
+ row = row_build(ROW_COPY_POINTERS, clust_index,
+ rec, clust_offsets, heap);
entry = row_build_index_entry(row, index, heap);
/* NOTE that we cannot do the comparison as binary
@@ -331,24 +345,17 @@ row_vers_old_has_index_entry(
return(TRUE);
}
-
- mem_heap_free(heap);
}
version = rec;
- heap = NULL;
for (;;) {
heap2 = heap;
heap = mem_heap_create(1024);
-
err = trx_undo_prev_version_build(rec, mtr, version,
- clust_index, heap,
- &prev_version);
- if (heap2) {
- mem_heap_free(heap2); /* version was stored in heap2,
- if heap2 != NULL */
- }
+ clust_index, clust_offsets, heap,
+ &prev_version);
+ mem_heap_free(heap2); /* free version and clust_offsets */
if (err != DB_SUCCESS || !prev_version) {
/* Versions end here */
@@ -358,9 +365,12 @@ row_vers_old_has_index_entry(
return(FALSE);
}
- if (!rec_get_deleted_flag(prev_version)) {
+ clust_offsets = rec_get_offsets(prev_version, clust_index,
+ NULL, ULINT_UNDEFINED, &heap);
+
+ if (!rec_get_deleted_flag(prev_version, comp)) {
row = row_build(ROW_COPY_POINTERS, clust_index,
- prev_version, heap);
+ prev_version, clust_offsets, heap);
entry = row_build_index_entry(row, index, heap);
/* NOTE that we cannot do the comparison as binary
@@ -396,7 +406,11 @@ row_vers_build_for_consistent_read(
of this records */
mtr_t* mtr, /* in: mtr holding the latch on rec */
dict_index_t* index, /* in: the clustered index */
+ ulint** offsets,/* in/out: offsets returned by
+ rec_get_offsets(rec, index) */
read_view_t* view, /* in: the consistent read view */
+ mem_heap_t** offset_heap,/* in/out: memory heap from which
+ the offsets are allocated */
mem_heap_t* in_heap,/* in: memory heap from which the memory for
old_vers is allocated; memory for possible
intermediate versions is allocated and freed
@@ -408,8 +422,7 @@ row_vers_build_for_consistent_read(
rec_t* version;
rec_t* prev_version;
dulint prev_trx_id;
- mem_heap_t* heap;
- mem_heap_t* heap2;
+ mem_heap_t* heap = NULL;
byte* buf;
ulint err;
@@ -420,21 +433,23 @@ row_vers_build_for_consistent_read(
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */
- ut_ad(!read_view_sees_trx_id(view, row_get_rec_trx_id(rec, index)));
+
+ ut_ad(rec_offs_validate(rec, index, *offsets));
+
+ ut_ad(!read_view_sees_trx_id(view,
+ row_get_rec_trx_id(rec, index, *offsets)));
rw_lock_s_lock(&(purge_sys->latch));
version = rec;
- heap = NULL;
for (;;) {
- heap2 = heap;
+ mem_heap_t* heap2 = heap;
heap = mem_heap_create(1024);
err = trx_undo_prev_version_build(rec, mtr, version, index,
- heap, &prev_version);
+ *offsets, heap, &prev_version);
if (heap2) {
- mem_heap_free(heap2); /* version was stored in heap2,
- if heap2 != NULL */
+ mem_heap_free(heap2); /* free version */
}
if (err != DB_SUCCESS) {
@@ -449,16 +464,19 @@ row_vers_build_for_consistent_read(
break;
}
- prev_trx_id = row_get_rec_trx_id(prev_version, index);
+ *offsets = rec_get_offsets(prev_version, index, *offsets,
+ ULINT_UNDEFINED, offset_heap);
+ prev_trx_id = row_get_rec_trx_id(prev_version, index,
+ *offsets);
if (read_view_sees_trx_id(view, prev_trx_id)) {
/* The view already sees this version: we can copy
it to in_heap and return */
- buf = mem_heap_alloc(in_heap, rec_get_size(
- prev_version));
- *old_vers = rec_copy(buf, prev_version);
+ buf = mem_heap_alloc(in_heap, rec_offs_size(*offsets));
+ *old_vers = rec_copy(buf, prev_version, *offsets);
+ rec_offs_make_valid(*old_vers, index, *offsets);
err = DB_SUCCESS;
break;
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index a60e9e5a5f7..a4bfdb6162d 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -44,6 +44,7 @@ Created 10/8/1995 Heikki Tuuri
#include "buf0flu.h"
#include "btr0sea.h"
#include "dict0load.h"
+#include "dict0boot.h"
#include "srv0start.h"
#include "row0mysql.h"
@@ -186,6 +187,61 @@ that during a time of heavy update/insert activity. */
ulong srv_max_buf_pool_modified_pct = 90;
+/* variable counts amount of data read in total (in bytes) */
+ulint srv_data_read = 0;
+
+/* here we count the amount of data written in total (in bytes) */
+ulint srv_data_written = 0;
+
+/* the number of the log write requests done */
+ulint srv_log_write_requests = 0;
+
+/* the number of physical writes to the log performed */
+ulint srv_log_writes = 0;
+
+/* amount of data written to the log files in bytes */
+ulint srv_os_log_written = 0;
+
+/* amount of writes being done to the log files */
+ulint srv_os_log_pending_writes = 0;
+
+/* we increase this counter, when there we don't have enough space in the
+log buffer and have to flush it */
+ulint srv_log_waits = 0;
+
+/* this variable counts the amount of times, when the doublewrite buffer
+was flushed */
+ulint srv_dblwr_writes = 0;
+
+/* here we store the number of pages that have been flushed to the
+doublewrite buffer */
+ulint srv_dblwr_pages_written = 0;
+
+/* in this variable we store the number of write requests issued */
+ulint srv_buf_pool_write_requests = 0;
+
+/* here we store the number of times when we had to wait for a free page
+in the buffer pool. It happens when the buffer pool is full and we need
+to make a flush, in order to be able to read or create a page. */
+ulint srv_buf_pool_wait_free = 0;
+
+/* variable to count the number of pages that were written from buffer
+pool to the disk */
+ulint srv_buf_pool_flushed = 0;
+
+/* variable to count the number of buffer pool reads that led to the
+reading of a disk page */
+ulint srv_buf_pool_reads = 0;
+
+/* variable to count the number of sequential read-aheads */
+ulint srv_read_ahead_seq = 0;
+
+/* variable to count the number of random read-aheads */
+ulint srv_read_ahead_rnd = 0;
+
+/* structure to pass status variables to MySQL */
+export_struc export_vars;
+
/* If the following is != 0 we do not allow inserts etc. This protects
the user from forgetting the innodb_force_recovery keyword to my.cnf */
@@ -204,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. */
-ulint srv_thread_concurrency = 8;
+ulong srv_thread_concurrency = 8;
os_fast_mutex_t srv_conc_mutex; /* this mutex protects srv_conc data
structures */
@@ -241,22 +297,20 @@ srv_conc_slot_t* srv_conc_slots; /* array of wait
/* Number of times a thread is allowed to enter InnoDB within the same
SQL query after it has once got the ticket at srv_conc_enter_innodb */
-#define SRV_FREE_TICKETS_TO_ENTER 500
-
+#define SRV_FREE_TICKETS_TO_ENTER srv_n_free_tickets_to_enter
+#define SRV_THREAD_SLEEP_DELAY srv_thread_sleep_delay
/*-----------------------*/
-/* If the following is set TRUE then we do not run purge and insert buffer
-merge to completion before shutdown */
-
-ibool srv_fast_shutdown = FALSE;
+/* If the following is set to 1 then we do not run purge and insert buffer
+merge to completion before shutdown. If it is set to 2, do not even flush the
+buffer pool to data files at the shutdown: we effectively 'crash'
+InnoDB (but lose no committed transactions). */
+ulint srv_fast_shutdown = 0;
-ibool srv_very_fast_shutdown = FALSE; /* if this TRUE, do not flush the
- buffer pool to data files at the
- shutdown; we effectively 'crash'
- InnoDB */
/* Generate a innodb_status.<pid> file */
ibool srv_innodb_status = FALSE;
ibool srv_use_doublewrite_buf = TRUE;
+ibool srv_use_checksums = TRUE;
ibool srv_set_thread_priorities = TRUE;
int srv_query_thread_priority = 0;
@@ -267,7 +321,9 @@ ibool srv_use_awe = FALSE;
ibool srv_use_adaptive_hash_indexes = TRUE;
/*-------------------------------------------*/
-ulint srv_n_spin_wait_rounds = 20;
+ulong srv_n_spin_wait_rounds = 20;
+ulong srv_n_free_tickets_to_enter = 500;
+ulong srv_thread_sleep_delay = 10000;
ulint srv_spin_wait_delay = 5;
ibool srv_priority_boost = TRUE;
@@ -286,6 +342,12 @@ static ulint srv_n_rows_updated_old = 0;
static ulint srv_n_rows_deleted_old = 0;
static ulint srv_n_rows_read_old = 0;
+ulint srv_n_lock_wait_count = 0;
+ulint srv_n_lock_wait_current_count = 0;
+ib_longlong srv_n_lock_wait_time = 0;
+ulint srv_n_lock_max_wait_time = 0;
+
+
/*
Set the following to 0 if you want InnoDB to write messages on
stderr on startup/shutdown
@@ -780,13 +842,14 @@ srv_get_thread_type(void)
/*************************************************************************
Initializes the server. */
-static
+
void
srv_init(void)
/*==========*/
{
srv_conc_slot_t* conc_slot;
srv_slot_t* slot;
+ dict_table_t* table;
ulint i;
srv_sys = mem_alloc(sizeof(srv_sys_t));
@@ -836,6 +899,31 @@ srv_init(void)
UT_LIST_INIT(srv_sys->tasks);
+ /* create dummy table and index for old-style infimum and supremum */
+ table = dict_mem_table_create("SYS_DUMMY1",
+ DICT_HDR_SPACE, 1, FALSE);
+ dict_mem_table_add_col(table, "DUMMY", DATA_CHAR,
+ DATA_ENGLISH | DATA_NOT_NULL, 8, 0);
+
+ srv_sys->dummy_ind1 = dict_mem_index_create("SYS_DUMMY1",
+ "SYS_DUMMY1", DICT_HDR_SPACE, 0, 1);
+ dict_index_add_col(srv_sys->dummy_ind1,
+ dict_table_get_nth_col(table, 0), 0, 0);
+ srv_sys->dummy_ind1->table = table;
+ /* create dummy table and index for new-style infimum and supremum */
+ table = dict_mem_table_create("SYS_DUMMY2",
+ DICT_HDR_SPACE, 1, TRUE);
+ dict_mem_table_add_col(table, "DUMMY", DATA_CHAR,
+ DATA_ENGLISH | DATA_NOT_NULL, 8, 0);
+ srv_sys->dummy_ind2 = dict_mem_index_create("SYS_DUMMY2",
+ "SYS_DUMMY2", DICT_HDR_SPACE, 0, 1);
+ dict_index_add_col(srv_sys->dummy_ind2,
+ dict_table_get_nth_col(table, 0), 0, 0);
+ srv_sys->dummy_ind2->table = table;
+
+ /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
+ srv_sys->dummy_ind1->cached = srv_sys->dummy_ind2->cached = TRUE;
+
/* Init the server concurrency restriction data structures */
os_fast_mutex_init(&srv_conc_mutex);
@@ -935,8 +1023,8 @@ retry:
return;
}
- /* If the transaction is not holding resources, let it sleep for 50
- milliseconds, and try again then */
+ /* If the transaction is not holding resources,
+ let it sleep for SRV_THREAD_SLEEP_DELAY microseconds, and try again then */
if (!has_slept && !trx->has_search_latch
&& NULL == UT_LIST_GET_FIRST(trx->trx_locks)) {
@@ -955,8 +1043,10 @@ retry:
situations of lots of thread switches. Simply put some
threads aside for a while to reduce the number of thread
switches. */
-
- os_thread_sleep(10000);
+ if (SRV_THREAD_SLEEP_DELAY > 0)
+ {
+ os_thread_sleep(SRV_THREAD_SLEEP_DELAY);
+ }
trx->op_info = "";
@@ -1216,6 +1306,7 @@ srv_boot(void)
return(DB_SUCCESS);
}
+#ifndef UNIV_HOTBACKUP
/*************************************************************************
Reserves a slot in the thread table for the current MySQL OS thread.
NOTE! The kernel mutex has to be reserved by the caller! */
@@ -1274,6 +1365,7 @@ srv_table_reserve_slot_for_mysql(void)
return(slot);
}
+#endif /* !UNIV_HOTBACKUP */
/*******************************************************************
Puts a MySQL OS thread to wait for a lock to be released. If an error
@@ -1288,13 +1380,19 @@ srv_suspend_mysql_thread(
que_thr_t* thr) /* in: query thread associated with the MySQL
OS thread */
{
+#ifndef UNIV_HOTBACKUP
srv_slot_t* slot;
os_event_t event;
double wait_time;
trx_t* trx;
ibool had_dict_lock = FALSE;
ibool was_declared_inside_innodb = FALSE;
-
+ ib_longlong start_time = 0;
+ ib_longlong finish_time;
+ ulint diff_time;
+ ulint sec;
+ ulint ms;
+
#ifdef UNIV_SYNC_DEBUG
ut_ad(!mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
@@ -1337,6 +1435,13 @@ srv_suspend_mysql_thread(
slot->suspend_time = ut_time();
+ if (thr->lock_state == QUE_THR_LOCK_ROW) {
+ srv_n_lock_wait_count++;
+ srv_n_lock_wait_current_count++;
+
+ ut_usectime(&sec, &ms);
+ start_time = (ib_longlong)sec * 1000000 + ms;
+ }
/* Wake the lock timeout monitor thread, if it is suspended */
os_event_set(srv_lock_timeout_thread_event);
@@ -1387,7 +1492,20 @@ srv_suspend_mysql_thread(
slot->in_use = FALSE;
wait_time = ut_difftime(ut_time(), slot->suspend_time);
-
+
+ if (thr->lock_state == QUE_THR_LOCK_ROW) {
+ ut_usectime(&sec, &ms);
+ finish_time = (ib_longlong)sec * 1000000 + ms;
+
+ diff_time = (ulint) (finish_time - start_time);
+
+ srv_n_lock_wait_current_count--;
+ srv_n_lock_wait_time = srv_n_lock_wait_time + diff_time;
+ if (diff_time > srv_n_lock_max_wait_time) {
+ srv_n_lock_max_wait_time = diff_time;
+ }
+ }
+
if (trx->was_chosen_as_deadlock_victim) {
trx->error_state = DB_DEADLOCK;
@@ -1401,6 +1519,12 @@ srv_suspend_mysql_thread(
trx->error_state = DB_LOCK_WAIT_TIMEOUT;
}
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/************************************************************************
@@ -1413,6 +1537,7 @@ srv_release_mysql_thread_if_suspended(
que_thr_t* thr) /* in: query thread associated with the
MySQL OS thread */
{
+#ifndef UNIV_HOTBACKUP
srv_slot_t* slot;
ulint i;
@@ -1434,8 +1559,15 @@ srv_release_mysql_thread_if_suspended(
}
/* not found */
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
+#ifndef UNIV_HOTBACKUP
/**********************************************************************
Refreshes the values used to calculate per-second averages. */
static
@@ -1604,19 +1736,80 @@ srv_printf_innodb_monitor(
(srv_n_rows_read - srv_n_rows_read_old)
/ time_elapsed);
- srv_n_rows_inserted_old = srv_n_rows_inserted;
+ srv_n_rows_inserted_old = srv_n_rows_inserted;
srv_n_rows_updated_old = srv_n_rows_updated;
srv_n_rows_deleted_old = srv_n_rows_deleted;
srv_n_rows_read_old = srv_n_rows_read;
- fputs("----------------------------\n"
+ fputs("----------------------------\n"
"END OF INNODB MONITOR OUTPUT\n"
"============================\n", file);
-
mutex_exit(&srv_innodb_monitor_mutex);
fflush(file);
}
+/**********************************************************************
+Function to pass InnoDB status variables to MySQL */
+
+void
+srv_export_innodb_status(void)
+{
+
+ mutex_enter(&srv_innodb_monitor_mutex);
+ export_vars.innodb_data_pending_reads= os_n_pending_reads;
+ export_vars.innodb_data_pending_writes= os_n_pending_writes;
+ export_vars.innodb_data_pending_fsyncs=
+ fil_n_pending_log_flushes + fil_n_pending_tablespace_flushes;
+ export_vars.innodb_data_fsyncs= os_n_fsyncs;
+ export_vars.innodb_data_read= srv_data_read;
+ export_vars.innodb_data_reads= os_n_file_reads;
+ export_vars.innodb_data_writes= os_n_file_writes;
+ export_vars.innodb_data_written= srv_data_written;
+ export_vars.innodb_buffer_pool_read_requests= buf_pool->n_page_gets;
+ export_vars.innodb_buffer_pool_write_requests= srv_buf_pool_write_requests;
+ export_vars.innodb_buffer_pool_wait_free= srv_buf_pool_wait_free;
+ export_vars.innodb_buffer_pool_pages_flushed= srv_buf_pool_flushed;
+ export_vars.innodb_buffer_pool_reads= srv_buf_pool_reads;
+ export_vars.innodb_buffer_pool_read_ahead_rnd= srv_read_ahead_rnd;
+ export_vars.innodb_buffer_pool_read_ahead_seq= srv_read_ahead_seq;
+ export_vars.innodb_buffer_pool_pages_data= UT_LIST_GET_LEN(buf_pool->LRU);
+ export_vars.innodb_buffer_pool_pages_dirty= UT_LIST_GET_LEN(buf_pool->flush_list);
+ export_vars.innodb_buffer_pool_pages_free= UT_LIST_GET_LEN(buf_pool->free);
+ export_vars.innodb_buffer_pool_pages_latched= buf_get_latched_pages_number();
+ export_vars.innodb_buffer_pool_pages_total= buf_pool->curr_size;
+ export_vars.innodb_buffer_pool_pages_misc= buf_pool->max_size -
+ UT_LIST_GET_LEN(buf_pool->LRU) - UT_LIST_GET_LEN(buf_pool->free);
+ export_vars.innodb_page_size= UNIV_PAGE_SIZE;
+ export_vars.innodb_log_waits= srv_log_waits;
+ export_vars.innodb_os_log_written= srv_os_log_written;
+ export_vars.innodb_os_log_fsyncs= fil_n_log_flushes;
+ export_vars.innodb_os_log_pending_fsyncs= fil_n_pending_log_flushes;
+ export_vars.innodb_os_log_pending_writes= srv_os_log_pending_writes;
+ export_vars.innodb_log_write_requests= srv_log_write_requests;
+ export_vars.innodb_log_writes= srv_log_writes;
+ export_vars.innodb_dblwr_pages_written= srv_dblwr_pages_written;
+ export_vars.innodb_dblwr_writes= srv_dblwr_writes;
+ export_vars.innodb_pages_created= buf_pool->n_pages_created;
+ export_vars.innodb_pages_read= buf_pool->n_pages_read;
+ export_vars.innodb_pages_written= buf_pool->n_pages_written;
+ export_vars.innodb_row_lock_waits= srv_n_lock_wait_count;
+ export_vars.innodb_row_lock_current_waits= srv_n_lock_wait_current_count;
+ export_vars.innodb_row_lock_time= srv_n_lock_wait_time / 10000;
+ if (srv_n_lock_wait_count > 0) {
+ export_vars.innodb_row_lock_time_avg = (ulint)
+ (srv_n_lock_wait_time / 10000 / srv_n_lock_wait_count);
+ } else {
+ export_vars.innodb_row_lock_time_avg = 0;
+ }
+ export_vars.innodb_row_lock_time_max= srv_n_lock_max_wait_time / 10000;
+ export_vars.innodb_rows_read= srv_n_rows_read;
+ export_vars.innodb_rows_inserted= srv_n_rows_inserted;
+ export_vars.innodb_rows_updated= srv_n_rows_updated;
+ export_vars.innodb_rows_deleted= srv_n_rows_deleted;
+ mutex_exit(&srv_innodb_monitor_mutex);
+
+}
+
/*************************************************************************
A thread which wakes up threads whose lock wait may have lasted too long.
This also prints the info output by various InnoDB monitors. */
@@ -2275,11 +2468,11 @@ background_loop:
flush_loop:
srv_main_thread_op_info = "flushing buffer pool pages";
- if (!srv_very_fast_shutdown) {
+ if (srv_fast_shutdown < 2) {
n_pages_flushed =
buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max);
} else {
- /* In a 'very fast' shutdown we do not flush the buffer pool
+ /* In the fastest shutdown we do not flush the buffer pool
to data files: we set n_pages_flushed to 0 artificially. */
n_pages_flushed = 0;
@@ -2399,3 +2592,4 @@ suspend_thread:
return(0);
#endif
}
+#endif /* !UNIV_HOTBACKUP */
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index 62df7301cc9..e136aee43e8 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -479,7 +479,6 @@ srv_normalize_path_for_win(
Adds a slash or a backslash to the end of a string if it is missing
and the string is not empty. */
-static
char*
srv_add_path_separator_if_needed(
/*=============================*/
@@ -531,6 +530,7 @@ srv_calc_high32(
return(file_size >> (32 - UNIV_PAGE_SIZE_SHIFT));
}
+#ifndef UNIV_HOTBACKUP
/*************************************************************************
Creates or opens the log files and closes them. */
static
@@ -1477,15 +1477,13 @@ NetWare. */
fsp_header_inc_size(0, sum_of_new_sizes, &mtr);
mtr_commit(&mtr);
- }
- if (recv_needed_recovery) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Flushing modified pages from the buffer pool...\n");
- }
+ /* Immediately write the log record about increased tablespace
+ size to disk, so that it is durable even if mysqld would crash
+ quickly */
- log_make_checkpoint_at(ut_dulint_max, TRUE);
+ log_buffer_flush_to_disk();
+ }
#ifdef UNIV_LOG_ARCHIVE
/* Archiving is always off under MySQL */
@@ -1731,6 +1729,15 @@ innobase_shutdown_for_mysql(void)
The step 1 is the real InnoDB shutdown. The remaining steps 2 - ...
just free data structures after the shutdown. */
+
+ if (srv_fast_shutdown == 2) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: MySQL has requested a very fast shutdown without flushing "
+"the InnoDB buffer pool to data files. At the next mysqld startup "
+"InnoDB will do a crash recovery!\n");
+ }
+
#ifdef __NETWARE__
if(!panic_shutdown)
#endif
@@ -1747,6 +1754,13 @@ innobase_shutdown_for_mysql(void)
srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS;
+ /* In a 'very fast' shutdown, we do not need to wait for these threads
+ to die; all which counts is that we flushed the log; a 'very fast'
+ shutdown is essentially a crash. */
+
+ if (srv_fast_shutdown)
+ return((int) DB_SUCCESS);
+
/* All threads end up waiting for certain events. Put those events
to the signaled state. Then the threads will exit themselves in
os_thread_event_wait(). */
@@ -1855,4 +1869,5 @@ void set_panic_flag_for_netware()
extern ibool panic_shutdown;
panic_shutdown = TRUE;
}
-#endif
+#endif /* __NETWARE__ */
+#endif /* !UNIV_HOTBACKUP */
diff --git a/innobase/sync/sync0rw.c b/innobase/sync/sync0rw.c
index 77757685208..973b46fdd50 100644
--- a/innobase/sync/sync0rw.c
+++ b/innobase/sync/sync0rw.c
@@ -90,7 +90,8 @@ rw_lock_create_func(
/*================*/
rw_lock_t* lock, /* in: pointer to memory */
const char* cfile_name, /* in: file name where created */
- ulint cline) /* in: file line where created */
+ ulint cline, /* in: file line where created */
+ const char* cmutex_name) /* in: mutex name */
{
/* If this is the very first time a synchronization
object is created, then the following call initializes
@@ -101,7 +102,11 @@ rw_lock_create_func(
lock->mutex.cfile_name = cfile_name;
lock->mutex.cline = cline;
-
+#ifndef UNIV_HOTBACKUP
+ lock->mutex.cmutex_name = cmutex_name;
+ lock->mutex.mutex_type = 1;
+#endif /* !UNIV_HOTBACKUP */
+
rw_lock_set_waiters(lock, 0);
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
lock->writer_count = 0;
diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c
index 86306e49cac..e604912e996 100644
--- a/innobase/sync/sync0sync.c
+++ b/innobase/sync/sync0sync.c
@@ -129,11 +129,6 @@ sync_array_t* sync_primary_wait_array;
/* This variable is set to TRUE when sync_init is called */
ibool sync_initialized = FALSE;
-/* Global list of database mutexes (not OS mutexes) created. */
-UT_LIST_BASE_NODE_T(mutex_t) mutex_list;
-
-/* Mutex protecting the mutex_list variable */
-mutex_t mutex_list_mutex;
typedef struct sync_level_struct sync_level_t;
typedef struct sync_thread_struct sync_thread_t;
@@ -202,7 +197,8 @@ mutex_create_func(
/*==============*/
mutex_t* mutex, /* in: pointer to memory */
const char* cfile_name, /* in: file name where created */
- ulint cline) /* in: file line where created */
+ ulint cline, /* in: file line where created */
+ const char* cmutex_name) /* in: mutex name */
{
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
mutex_reset_lock_word(mutex);
@@ -219,6 +215,17 @@ mutex_create_func(
mutex->level = SYNC_LEVEL_NONE;
mutex->cfile_name = cfile_name;
mutex->cline = cline;
+#ifndef UNIV_HOTBACKUP
+ mutex->cmutex_name= cmutex_name;
+ mutex->count_using= 0;
+ mutex->mutex_type= 0;
+ mutex->lspent_time= 0;
+ mutex->lmax_spent_time= 0;
+ mutex->count_spin_loop= 0;
+ mutex->count_spin_rounds= 0;
+ mutex->count_os_wait= 0;
+ mutex->count_os_yield= 0;
+#endif /* !UNIV_HOTBACKUP */
/* Check that lock_word is aligned; this is important on Intel */
ut_ad(((ulint)(&(mutex->lock_word))) % 4 == 0);
@@ -355,135 +362,188 @@ for the mutex before suspending the thread. */
void
mutex_spin_wait(
/*============*/
- mutex_t* mutex, /* in: pointer to mutex */
- const char* file_name, /* in: file name where
- mutex requested */
- ulint line) /* in: line where requested */
+ mutex_t* mutex, /* in: pointer to mutex */
+ const char* file_name, /* in: file name where
+ mutex requested */
+ ulint line) /* in: line where requested */
{
- ulint index; /* index of the reserved wait cell */
- ulint i; /* spin round count */
-
- ut_ad(mutex);
+ ulint index; /* index of the reserved wait cell */
+ ulint i; /* spin round count */
+#ifndef UNIV_HOTBACKUP
+ ib_longlong lstart_time = 0, lfinish_time; /* for timing os_wait */
+ ulint ltime_diff;
+ ulint sec;
+ ulint ms;
+ uint timer_started = 0;
+#endif /* !UNIV_HOTBACKUP */
+ ut_ad(mutex);
mutex_loop:
- i = 0;
+ i = 0;
- /* Spin waiting for the lock word to become zero. Note that we do not
- have to assume that the read access to the lock word is atomic, as the
- actual locking is always committed with atomic test-and-set. In
- reality, however, all processors probably have an atomic read of a
- memory word. */
-
-spin_loop:
- mutex_spin_wait_count++;
-
- while (mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS) {
-
- if (srv_spin_wait_delay) {
- ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
- }
-
- i++;
- }
+/* Spin waiting for the lock word to become zero. Note that we do not
+ have to assume that the read access to the lock word is atomic, as the
+ actual locking is always committed with atomic test-and-set. In
+ reality, however, all processors probably have an atomic read of a
+ memory word. */
- if (i == SYNC_SPIN_ROUNDS) {
- os_thread_yield();
- }
+spin_loop:
+#ifndef UNIV_HOTBACKUP
+ mutex_spin_wait_count++;
+ mutex->count_spin_loop++;
+#endif /* !UNIV_HOTBACKUP */
+
+ while (mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS)
+ {
+ if (srv_spin_wait_delay)
+ {
+ ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
+ }
+
+ i++;
+ }
+
+ if (i == SYNC_SPIN_ROUNDS)
+ {
+#ifndef UNIV_HOTBACKUP
+ mutex->count_os_yield++;
+ if (timed_mutexes == 1 && timer_started==0)
+ {
+ ut_usectime(&sec, &ms);
+ lstart_time= (ib_longlong)sec * 1000000 + ms;
+ timer_started = 1;
+ }
+#endif /* !UNIV_HOTBACKUP */
+ os_thread_yield();
+ }
+
+#ifdef UNIV_SRV_PRINT_LATCH_WAITS
+ fprintf(stderr,
+ "Thread %lu spin wait mutex at %p cfile %s cline %lu rnds %lu\n",
+ (ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
+ mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
+#endif
- if (srv_print_latch_waits) {
- fprintf(stderr,
- "Thread %lu spin wait mutex at %p cfile %s cline %lu rnds %lu\n",
- (ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
- mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
- }
+ mutex_spin_round_count += i;
- mutex_spin_round_count += i;
+#ifndef UNIV_HOTBACKUP
+ mutex->count_spin_rounds += i;
+#endif /* !UNIV_HOTBACKUP */
- if (mutex_test_and_set(mutex) == 0) {
- /* Succeeded! */
+ if (mutex_test_and_set(mutex) == 0)
+ {
+ /* Succeeded! */
#ifdef UNIV_SYNC_DEBUG
- mutex_set_debug_info(mutex, file_name, line);
+ mutex_set_debug_info(mutex, file_name, line);
#endif
- return;
- }
+ goto finish_timing;
+ }
- /* We may end up with a situation where lock_word is
- 0 but the OS fast mutex is still reserved. On FreeBSD
- the OS does not seem to schedule a thread which is constantly
- calling pthread_mutex_trylock (in mutex_test_and_set
- implementation). Then we could end up spinning here indefinitely.
- The following 'i++' stops this infinite spin. */
+ /* We may end up with a situation where lock_word is
+ 0 but the OS fast mutex is still reserved. On FreeBSD
+ the OS does not seem to schedule a thread which is constantly
+ calling pthread_mutex_trylock (in mutex_test_and_set
+ implementation). Then we could end up spinning here indefinitely.
+ The following 'i++' stops this infinite spin. */
- i++;
-
- if (i < SYNC_SPIN_ROUNDS) {
+ i++;
- goto spin_loop;
- }
+ if (i < SYNC_SPIN_ROUNDS)
+ {
+ goto spin_loop;
+ }
- sync_array_reserve_cell(sync_primary_wait_array, mutex,
- SYNC_MUTEX,
- file_name, line,
- &index);
+ sync_array_reserve_cell(sync_primary_wait_array, mutex,
+ SYNC_MUTEX, file_name, line, &index);
- mutex_system_call_count++;
+ mutex_system_call_count++;
- /* The memory order of the array reservation and the change in the
- waiters field is important: when we suspend a thread, we first
- reserve the cell and then set waiters field to 1. When threads are
- released in mutex_exit, the waiters field is first set to zero and
- then the event is set to the signaled state. */
-
- mutex_set_waiters(mutex, 1);
+ /* The memory order of the array reservation and the change in the
+ waiters field is important: when we suspend a thread, we first
+ reserve the cell and then set waiters field to 1. When threads are
+ released in mutex_exit, the waiters field is first set to zero and
+ then the event is set to the signaled state. */
- /* Try to reserve still a few times */
- for (i = 0; i < 4; i++) {
- if (mutex_test_and_set(mutex) == 0) {
+ mutex_set_waiters(mutex, 1);
- /* Succeeded! Free the reserved wait cell */
+ /* Try to reserve still a few times */
+ for (i = 0; i < 4; i++)
+ {
+ if (mutex_test_and_set(mutex) == 0)
+ {
+ /* Succeeded! Free the reserved wait cell */
+
+ sync_array_free_cell(sync_primary_wait_array, index);
- sync_array_free_cell(sync_primary_wait_array, index);
-
#ifdef UNIV_SYNC_DEBUG
- mutex_set_debug_info(mutex, file_name, line);
+ mutex_set_debug_info(mutex, file_name, line);
#endif
- if (srv_print_latch_waits) {
- fprintf(stderr,
- "Thread %lu spin wait succeeds at 2:"
- " mutex at %p\n",
- (ulong) os_thread_pf(os_thread_get_curr_id()),
- mutex);
- }
-
- return;
+#ifdef UNIV_SRV_PRINT_LATCH_WAITS
+ fprintf(stderr, "Thread %lu spin wait succeeds at 2:"
+ " mutex at %p\n",
+ (ulong) os_thread_pf(os_thread_get_curr_id()),
+ mutex);
+#endif
- /* Note that in this case we leave the waiters field
- set to 1. We cannot reset it to zero, as we do not know
- if there are other waiters. */
- }
- }
+ goto finish_timing;
- /* Now we know that there has been some thread holding the mutex
- after the change in the wait array and the waiters field was made.
- Now there is no risk of infinite wait on the event. */
+ /* Note that in this case we leave the waiters field
+ set to 1. We cannot reset it to zero, as we do not know
+ if there are other waiters. */
+ }
+ }
- if (srv_print_latch_waits) {
- fprintf(stderr,
- "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n",
- (ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
- mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
- }
-
- mutex_system_call_count++;
- mutex_os_wait_count++;
+ /* Now we know that there has been some thread holding the mutex
+ after the change in the wait array and the waiters field was made.
+Now there is no risk of infinite wait on the event. */
- sync_array_wait_event(sync_primary_wait_array, index);
+#ifdef UNIV_SRV_PRINT_LATCH_WAITS
+ fprintf(stderr,
+ "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n",
+ (ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
+ mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
+#endif
- goto mutex_loop;
+ mutex_system_call_count++;
+ mutex_os_wait_count++;
+
+#ifndef UNIV_HOTBACKUP
+ mutex->count_os_wait++;
+ /*
+ !!!!! Sometimes os_wait can be called without os_thread_yield
+ */
+
+ if (timed_mutexes == 1 && timer_started==0)
+ {
+ ut_usectime(&sec, &ms);
+ lstart_time= (ib_longlong)sec * 1000000 + ms;
+ timer_started = 1;
+ }
+#endif /* !UNIV_HOTBACKUP */
+
+ sync_array_wait_event(sync_primary_wait_array, index);
+ goto mutex_loop;
+
+finish_timing:
+#ifndef UNIV_HOTBACKUP
+ if (timed_mutexes == 1 && timer_started==1)
+ {
+ ut_usectime(&sec, &ms);
+ lfinish_time= (ib_longlong)sec * 1000000 + ms;
+
+ ltime_diff= (ulint) (lfinish_time - lstart_time);
+ mutex->lspent_time += ltime_diff;
+ if (mutex->lmax_spent_time < ltime_diff)
+ {
+ mutex->lmax_spent_time= ltime_diff;
+ }
+ }
+#endif /* !UNIV_HOTBACKUP */
+ return;
}
/**********************************************************************
@@ -555,6 +615,7 @@ mutex_set_level(
mutex->level = level;
}
+
#ifdef UNIV_SYNC_DEBUG
/**********************************************************************
Checks that the current thread owns the mutex. Works only in the debug
diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c
index fe429d1cc62..fcb7582ce73 100644
--- a/innobase/trx/trx0rec.c
+++ b/innobase/trx/trx0rec.c
@@ -38,16 +38,18 @@ trx_undof_page_add_undo_rec_log(
ulint new_free, /* in: end offset of the entry */
mtr_t* mtr) /* in: mtr */
{
- byte* log_ptr;
- ulint len;
+ byte* log_ptr;
+ const byte* log_end;
+ ulint len;
- log_ptr = mlog_open(mtr, 30 + MLOG_BUF_MARGIN);
+ log_ptr = mlog_open(mtr, 11 + 13 + MLOG_BUF_MARGIN);
if (log_ptr == NULL) {
return;
}
+ log_end = &log_ptr[11 + 13 + MLOG_BUF_MARGIN];
log_ptr = mlog_write_initial_log_record_fast(undo_page,
MLOG_UNDO_INSERT, log_ptr, mtr);
len = new_free - old_free - 4;
@@ -55,14 +57,11 @@ trx_undof_page_add_undo_rec_log(
mach_write_to_2(log_ptr, len);
log_ptr += 2;
- if (len < 256) {
- ut_memcpy(log_ptr, undo_page + old_free + 2, len);
- log_ptr += len;
- }
-
- mlog_close(mtr, log_ptr);
-
- if (len >= MLOG_BUF_MARGIN) {
+ if (log_ptr + len <= log_end) {
+ memcpy(log_ptr, undo_page + old_free + 2, len);
+ mlog_close(mtr, log_ptr + len);
+ } else {
+ mlog_close(mtr, log_ptr);
mlog_catenate_string(mtr, undo_page + old_free + 2, len);
}
}
@@ -404,6 +403,7 @@ trx_undo_page_report_modify(
delete marking is done */
rec_t* rec, /* in: clustered index record which
has NOT yet been modified */
+ const ulint* offsets, /* in: rec_get_offsets(rec, index) */
upd_t* update, /* in: update vector which tells the
columns to be updated; in the case of
a delete, this should be set to NULL */
@@ -430,6 +430,7 @@ trx_undo_page_report_modify(
ulint i;
ut_a(index->type & DICT_CLUSTERED);
+ ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_TYPE) == TRX_UNDO_UPDATE);
table = index->table;
@@ -454,7 +455,7 @@ trx_undo_page_report_modify(
/* Store first some general parameters to the undo log */
if (update) {
- if (rec_get_deleted_flag(rec)) {
+ if (rec_get_deleted_flag(rec, table->comp)) {
type_cmpl = TRX_UNDO_UPD_DEL_REC;
} else {
type_cmpl = TRX_UNDO_UPD_EXIST_REC;
@@ -479,14 +480,20 @@ trx_undo_page_report_modify(
/*----------------------------------------*/
/* Store the state of the info bits */
- bits = rec_get_info_bits(rec);
+ bits = rec_get_info_bits(rec, table->comp);
mach_write_to_1(ptr, bits);
ptr += 1;
/* Store the values of the system columns */
- trx_id = dict_index_rec_get_sys_col(index, DATA_TRX_ID, rec);
+ field = rec_get_nth_field(rec, offsets,
+ dict_index_get_sys_col_pos(index, DATA_TRX_ID), &len);
+ ut_ad(len == DATA_TRX_ID_LEN);
+ trx_id = trx_read_trx_id(field);
+ field = rec_get_nth_field(rec, offsets,
+ dict_index_get_sys_col_pos(index, DATA_ROLL_PTR), &len);
+ ut_ad(len == DATA_ROLL_PTR_LEN);
+ roll_ptr = trx_read_roll_ptr(field);
- roll_ptr = dict_index_rec_get_sys_col(index, DATA_ROLL_PTR, rec);
len = mach_dulint_write_compressed(ptr, trx_id);
ptr += len;
@@ -499,7 +506,7 @@ trx_undo_page_report_modify(
for (i = 0; i < dict_index_get_n_unique(index); i++) {
- field = rec_get_nth_field(rec, i, &flen);
+ field = rec_get_nth_field(rec, offsets, i, &flen);
if (trx_undo_left(undo_page, ptr) < 4) {
@@ -547,14 +554,14 @@ trx_undo_page_report_modify(
ptr += len;
/* Save the old value of field */
- field = rec_get_nth_field(rec, pos, &flen);
+ field = rec_get_nth_field(rec, offsets, pos, &flen);
if (trx_undo_left(undo_page, ptr) < 5) {
return(0);
}
- if (rec_get_nth_field_extern_bit(rec, pos)) {
+ if (rec_offs_nth_extern(offsets, pos)) {
/* If a field has external storage, we add to
flen the flag */
@@ -631,7 +638,7 @@ trx_undo_page_report_modify(
ptr += len;
/* Save the old value of field */
- field = rec_get_nth_field(rec, pos, &flen);
+ field = rec_get_nth_field(rec, offsets, pos, &flen);
if (trx_undo_left(undo_page, ptr) < 5) {
@@ -1008,7 +1015,11 @@ trx_undo_report_row_operation(
ibool is_insert;
trx_rseg_t* rseg;
mtr_t mtr;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+
ut_a(index->type & DICT_CLUSTERED);
if (flags & BTR_NO_UNDO_LOG_FLAG) {
@@ -1019,7 +1030,6 @@ trx_undo_report_row_operation(
}
ut_ad(thr);
- ut_a(index->type & DICT_CLUSTERED);
ut_ad((op_type != TRX_UNDO_INSERT_OP)
|| (clust_entry && !update && !rec));
@@ -1079,9 +1089,10 @@ trx_undo_report_row_operation(
index, clust_entry,
&mtr);
} else {
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
offset = trx_undo_page_report_modify(undo_page, trx,
- index, rec, update,
- cmpl_info, &mtr);
+ index, rec, offsets, update, cmpl_info, &mtr);
}
if (offset == 0) {
@@ -1123,7 +1134,9 @@ trx_undo_report_row_operation(
mutex_exit(&(trx->undo_mutex));
mtr_commit(&mtr);
-
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(DB_OUT_OF_FILE_SPACE);
}
}
@@ -1140,6 +1153,9 @@ trx_undo_report_row_operation(
*roll_ptr = trx_undo_build_roll_ptr(is_insert, rseg->id, page_no,
offset);
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(DB_SUCCESS);
}
@@ -1236,6 +1252,7 @@ trx_undo_prev_version_build(
index_rec page and purge_view */
rec_t* rec, /* in: version of a clustered index record */
dict_index_t* index, /* in: clustered index */
+ ulint* offsets,/* in: rec_get_offsets(rec, index) */
mem_heap_t* heap, /* in: memory heap from which the memory
needed is allocated */
rec_t** old_vers)/* out, own: previous version, or NULL if
@@ -1258,7 +1275,6 @@ trx_undo_prev_version_build(
ibool dummy_extern;
byte* buf;
ulint err;
-
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */
@@ -1266,21 +1282,23 @@ trx_undo_prev_version_build(
MTR_MEMO_PAGE_S_FIX) ||
mtr_memo_contains(index_mtr, buf_block_align(index_rec),
MTR_MEMO_PAGE_X_FIX));
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
if (!(index->type & DICT_CLUSTERED)) {
fprintf(stderr, "InnoDB: Error: trying to access"
" update undo rec for non-clustered index %s\n"
"InnoDB: Submit a detailed bug report to"
" http://bugs.mysql.com\n"
"InnoDB: index record ", index->name);
- rec_print(stderr, index_rec);
+ rec_print(stderr, index_rec, index);
fputs("\n"
"InnoDB: record version ", stderr);
- rec_print(stderr, rec);
+ rec_print_new(stderr, rec, offsets);
putc('\n', stderr);
return(DB_ERROR);
}
- roll_ptr = row_get_rec_roll_ptr(rec, index);
+ roll_ptr = row_get_rec_roll_ptr(rec, index, offsets);
old_roll_ptr = roll_ptr;
*old_vers = NULL;
@@ -1292,7 +1310,7 @@ trx_undo_prev_version_build(
return(DB_SUCCESS);
}
- rec_trx_id = row_get_rec_trx_id(rec, index);
+ rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
err = trx_undo_get_undo_rec(roll_ptr, rec_trx_id, &undo_rec, heap);
@@ -1341,10 +1359,10 @@ trx_undo_prev_version_build(
ut_print_buf(stderr, undo_rec, 150);
fputs("\n"
"InnoDB: index record ", stderr);
- rec_print(stderr, index_rec);
+ rec_print(stderr, index_rec, index);
fputs("\n"
"InnoDB: record version ", stderr);
- rec_print(stderr, rec);
+ rec_print_new(stderr, rec, offsets);
fprintf(stderr, "\n"
"InnoDB: Record trx id %lu %lu, update rec trx id %lu %lu\n"
"InnoDB: Roll ptr in rec %lu %lu, in update rec %lu %lu\n",
@@ -1358,11 +1376,10 @@ trx_undo_prev_version_build(
(ulong) ut_dulint_get_low(roll_ptr));
trx_purge_sys_print();
-
return(DB_ERROR);
}
- if (row_upd_changes_field_size_or_external(rec, index, update)) {
+ if (row_upd_changes_field_size_or_external(index, offsets, update)) {
ulint* ext_vect;
ulint n_ext_vect;
@@ -1372,27 +1389,28 @@ trx_undo_prev_version_build(
those fields that update updates to become externally stored
fields. Store the info to ext_vect: */
- ext_vect = mem_alloc(sizeof(ulint) * rec_get_n_fields(rec));
- n_ext_vect = btr_push_update_extern_fields(ext_vect, rec,
+ ext_vect = mem_alloc(sizeof(ulint)
+ * rec_offs_n_fields(offsets));
+ n_ext_vect = btr_push_update_extern_fields(ext_vect, offsets,
update);
entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec,
heap);
row_upd_index_replace_new_col_vals(entry, index, update, heap);
- buf = mem_heap_alloc(heap, rec_get_converted_size(entry));
+ buf = mem_heap_alloc(heap,
+ rec_get_converted_size(index, entry));
- *old_vers = rec_convert_dtuple_to_rec(buf, entry);
+ *old_vers = rec_convert_dtuple_to_rec(buf, index, entry);
/* Now set the extern bits in the old version of the record */
- rec_set_field_extern_bits(*old_vers, ext_vect, n_ext_vect,
- NULL);
+ rec_set_field_extern_bits(*old_vers, index,
+ ext_vect, n_ext_vect, NULL);
mem_free(ext_vect);
} else {
- buf = mem_heap_alloc(heap, rec_get_size(rec));
-
- *old_vers = rec_copy(buf, rec);
-
- row_upd_rec_in_place(*old_vers, update);
+ buf = mem_heap_alloc(heap, rec_offs_size(offsets));
+ *old_vers = rec_copy(buf, rec, offsets);
+ rec_offs_make_valid(*old_vers, index, offsets);
+ row_upd_rec_in_place(*old_vers, offsets, update);
}
return(DB_SUCCESS);
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index eb7c7f43f03..69f7a99187f 100644
--- a/innobase/trx/trx0roll.c
+++ b/innobase/trx/trx0roll.c
@@ -30,9 +30,13 @@ Created 3/26/1996 Heikki Tuuri
/* This many pages must be undone before a truncate is tried within rollback */
#define TRX_ROLL_TRUNC_THRESHOLD 1
+/* In crash recovery, the current trx to be rolled back */
+trx_t* trx_roll_crash_recv_trx = NULL;
+
/* In crash recovery we set this to the undo n:o of the current trx to be
rolled back. Then we can print how many % the rollback has progressed. */
ib_longlong trx_roll_max_undo_no;
+
/* Auxiliary variable which tells the previous progress % we printed */
ulint trx_roll_progress_printed_pct;
@@ -48,6 +52,7 @@ trx_general_rollback_for_mysql(
trx_savept_t* savept) /* in: pointer to savepoint undo number, if
partial rollback requested */
{
+#ifndef UNIV_HOTBACKUP
mem_heap_t* heap;
que_thr_t* thr;
roll_node_t* roll_node;
@@ -99,6 +104,12 @@ trx_general_rollback_for_mysql(
srv_active_wake_master_thread();
return((int) trx->error_state);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/***********************************************************************
@@ -313,6 +324,51 @@ trx_savepoint_for_mysql(
}
/***********************************************************************
+Releases a named savepoint. Savepoints which
+were set after this savepoint are deleted. */
+
+ulint
+trx_release_savepoint_for_mysql(
+/*============================*/
+ /* out: if no savepoint
+ of the name found then
+ DB_NO_SAVEPOINT,
+ otherwise DB_SUCCESS */
+ trx_t* trx, /* in: transaction handle */
+ const char* savepoint_name) /* in: savepoint name */
+{
+ trx_named_savept_t* savep;
+
+ savep = UT_LIST_GET_FIRST(trx->trx_savepoints);
+
+ while (savep != NULL) {
+ if (0 == ut_strcmp(savep->name, savepoint_name)) {
+ /* Found */
+ break;
+ }
+ savep = UT_LIST_GET_NEXT(trx_savepoints, savep);
+ }
+
+ if (savep == NULL) {
+
+ return(DB_NO_SAVEPOINT);
+ }
+
+ /* We can now free all savepoints strictly later than this one */
+
+ trx_roll_savepoints_free(trx, savep);
+
+ /* Now we can free this savepoint too */
+
+ UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep);
+
+ mem_free(savep->name);
+ mem_free(savep);
+
+ return(DB_SUCCESS);
+}
+
+/***********************************************************************
Returns a transaction savepoint taken at this point in time. */
trx_savept_t
@@ -331,11 +387,20 @@ trx_savept_take(
/***********************************************************************
Rollback or clean up transactions which have no user session. If the
transaction already was committed, then we clean up a possible insert
-undo log. If the transaction was not yet committed, then we roll it back. */
+undo log. If the transaction was not yet committed, then we roll it back.
+Note: this is done in a background thread. */
-void
-trx_rollback_or_clean_all_without_sess(void)
-/*========================================*/
+#ifndef __WIN__
+void*
+#else
+ulint
+#endif
+trx_rollback_or_clean_all_without_sess(
+/*===================================*/
+ /* out: a dummy parameter */
+ void* arg __attribute__((unused)))
+ /* in: a dummy parameter required by
+ os_thread_create */
{
mem_heap_t* heap;
que_fork_t* fork;
@@ -360,9 +425,9 @@ trx_rollback_or_clean_all_without_sess(void)
if (UT_LIST_GET_FIRST(trx_sys->trx_list)) {
fprintf(stderr,
- "InnoDB: Starting rollback of uncommitted transactions\n");
+"InnoDB: Starting in background the rollback of uncommitted transactions\n");
} else {
- return;
+ goto leave_function;
}
loop:
heap = mem_heap_create(512);
@@ -371,24 +436,32 @@ loop:
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
- while (trx && (trx->sess || (trx->conc_state == TRX_NOT_STARTED))) {
+ while (trx) {
+ if ((trx->sess || (trx->conc_state == TRX_NOT_STARTED))) {
+ trx = UT_LIST_GET_NEXT(trx_list, trx);
+ } else if (trx->conc_state == TRX_PREPARED) {
- trx = UT_LIST_GET_NEXT(trx_list, trx);
+ trx->sess = trx_dummy_sess;
+ trx = UT_LIST_GET_NEXT(trx_list, trx);
+ } else {
+ break;
+ }
}
mutex_exit(&kernel_mutex);
if (trx == NULL) {
+ ut_print_timestamp(stderr);
fprintf(stderr,
- "InnoDB: Rollback of uncommitted transactions completed\n");
+ " InnoDB: Rollback of non-prepared transactions completed\n");
mem_heap_free(heap);
-
- return;
+
+ goto leave_function;
}
trx->sess = trx_dummy_sess;
-
+
if (trx->conc_state == TRX_COMMITTED_IN_MEMORY) {
fprintf(stderr, "InnoDB: Cleaning up trx with id %lu %lu\n",
(ulong) ut_dulint_get_high(trx->id),
@@ -417,21 +490,28 @@ loop:
ut_a(thr == que_fork_start_command(fork));
+ trx_roll_crash_recv_trx = trx;
trx_roll_max_undo_no = ut_conv_dulint_to_longlong(trx->undo_no);
trx_roll_progress_printed_pct = 0;
rows_to_undo = trx_roll_max_undo_no;
+
if (rows_to_undo > 1000000000) {
rows_to_undo = rows_to_undo / 1000000;
unit = "M";
}
+ ut_print_timestamp(stderr);
fprintf(stderr,
-"InnoDB: Rolling back trx with id %lu %lu, %lu%s rows to undo",
+" InnoDB: Rolling back trx with id %lu %lu, %lu%s rows to undo\n",
(ulong) ut_dulint_get_high(trx->id),
(ulong) ut_dulint_get_low(trx->id),
(ulong) rows_to_undo, unit);
mutex_exit(&kernel_mutex);
+ trx->mysql_thread_id = os_thread_get_curr_id();
+
+ trx->mysql_process_no = os_proc_get_number();
+
if (trx->dict_operation) {
row_mysql_lock_data_dictionary(trx);
}
@@ -446,7 +526,7 @@ loop:
fprintf(stderr,
"InnoDB: Waiting for rollback of trx id %lu to end\n",
- (ulong) ut_dulint_get_low(trx->id));
+ (ulong) ut_dulint_get_low(trx->id));
os_thread_sleep(100000);
mutex_enter(&kernel_mutex);
@@ -485,7 +565,23 @@ loop:
(ulong) ut_dulint_get_low(trx->id));
mem_heap_free(heap);
+ trx_roll_crash_recv_trx = NULL;
+
goto loop;
+
+leave_function:
+ /* We count the number of threads in os_thread_exit(). A created
+ thread should always use that to exit and not use return() to exit. */
+
+ os_thread_exit(NULL);
+
+ /* The following is dummy code to keep the compiler happy: */
+
+#ifndef __WIN__
+ return(NULL);
+#else
+ return(0);
+#endif
}
/***********************************************************************
@@ -846,16 +942,17 @@ try_again:
ut_ad(ut_dulint_cmp(ut_dulint_add(undo_no, 1), trx->undo_no) == 0);
/* We print rollback progress info if we are in a crash recovery
- and the transaction has at least 1000 row operations to undo */
+ and the transaction has at least 1000 row operations to undo. */
+
+ if (trx == trx_roll_crash_recv_trx && trx_roll_max_undo_no > 1000) {
- if (srv_is_being_started && trx_roll_max_undo_no > 1000) {
- progress_pct = 100 - (ulint)
+ progress_pct = 100 - (ulint)
((ut_conv_dulint_to_longlong(undo_no) * 100)
/ trx_roll_max_undo_no);
if (progress_pct != trx_roll_progress_printed_pct) {
if (trx_roll_progress_printed_pct == 0) {
fprintf(stderr,
- "\nInnoDB: Progress in percents: %lu", (ulong) progress_pct);
+"\nInnoDB: Progress in percents: %lu", (ulong) progress_pct);
} else {
fprintf(stderr,
" %lu", (ulong) progress_pct);
diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c
index 51e193d563b..68fe6d5079a 100644
--- a/innobase/trx/trx0sys.c
+++ b/innobase/trx/trx0sys.c
@@ -125,6 +125,22 @@ trx_doublewrite_init(
}
/********************************************************************
+Frees the doublewrite buffer. */
+static
+void
+trx_doublewrite_free(void)
+/*======================*/
+{
+ mutex_free(&(trx_doublewrite->mutex));
+
+ mem_free(trx_doublewrite->buf_block_arr);
+ ut_free(trx_doublewrite->write_buf_unaligned);
+
+ mem_free(trx_doublewrite);
+ trx_doublewrite = NULL;
+}
+
+/********************************************************************
Marks the trx sys header when we have successfully upgraded to the >= 4.1.x
multiple tablespace format. */
@@ -512,6 +528,9 @@ trx_sys_doublewrite_init_or_restore_pages(
fil_flush_file_spaces(FIL_TABLESPACE);
+ if (!srv_use_doublewrite_buf)
+ trx_doublewrite_free();
+
leave_func:
ut_free(unaligned_read_buf);
}
@@ -888,8 +907,12 @@ trx_sys_init_at_db_start(void)
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
for (;;) {
- rows_to_undo +=
+
+ if ( trx->conc_state != TRX_PREPARED) {
+ rows_to_undo +=
ut_conv_dulint_to_longlong(trx->undo_no);
+ }
+
trx = UT_LIST_GET_NEXT(trx_list, trx);
if (!trx) {
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index 13575a3cedd..cdda1dd4dee 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -24,6 +24,7 @@ Created 3/26/1996 Heikki Tuuri
#include "thr0loc.h"
#include "btr0sea.h"
#include "os0proc.h"
+#include "trx0xa.h"
/* Copy of the prototype for innobase_mysql_print_thd: this
copy MUST be equal to the one in mysql/sql/ha_innodb.cc ! */
@@ -92,6 +93,8 @@ trx_create(
trx->id = ut_dulint_zero;
trx->no = ut_dulint_max;
+ trx->support_xa = TRUE;
+
trx->check_foreigns = TRUE;
trx->check_unique_secondary = TRUE;
@@ -156,10 +159,15 @@ trx_create(
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;
+ /* Set X/Open XA transaction identification to NULL */
+ memset(&trx->xid, 0, sizeof(trx->xid));
+ trx->xid.formatID = -1;
+
return(trx);
}
@@ -302,6 +310,7 @@ 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);
@@ -430,13 +439,36 @@ trx_lists_init_at_db_start(void)
trx = trx_create(NULL);
trx->id = undo->trx_id;
-
+ trx->xid = undo->xid;
trx->insert_undo = undo;
trx->rseg = rseg;
if (undo->state != TRX_UNDO_ACTIVE) {
- trx->conc_state = TRX_COMMITTED_IN_MEMORY;
+ /* Prepared transactions are left in
+ the prepared state waiting for a
+ commit or abort decision from MySQL */
+
+ if (undo->state == TRX_UNDO_PREPARED) {
+
+ fprintf(stderr,
+"InnoDB: Transaction %lu %lu was in the XA prepared state.\n",
+ ut_dulint_get_high(trx->id),
+ ut_dulint_get_low(trx->id));
+
+ if (srv_force_recovery == 0) {
+
+ trx->conc_state = TRX_PREPARED;
+ } else {
+ fprintf(stderr,
+"InnoDB: Since innodb_force_recovery > 0, we will rollback it anyway.\n");
+
+ trx->conc_state = TRX_ACTIVE;
+ }
+ } else {
+ trx->conc_state =
+ TRX_COMMITTED_IN_MEMORY;
+ }
/* We give a dummy value for the trx no;
this should have no relevance since purge
@@ -479,10 +511,34 @@ trx_lists_init_at_db_start(void)
trx = trx_create(NULL);
trx->id = undo->trx_id;
+ trx->xid = undo->xid;
if (undo->state != TRX_UNDO_ACTIVE) {
- trx->conc_state =
- TRX_COMMITTED_IN_MEMORY;
+
+ /* Prepared transactions are left in
+ the prepared state waiting for a
+ commit or abort decision from MySQL */
+
+ if (undo->state == TRX_UNDO_PREPARED) {
+ fprintf(stderr,
+"InnoDB: Transaction %lu %lu was in the XA prepared state.\n",
+ ut_dulint_get_high(trx->id),
+ ut_dulint_get_low(trx->id));
+
+ if (srv_force_recovery == 0) {
+
+ trx->conc_state = TRX_PREPARED;
+ } else {
+ fprintf(stderr,
+"InnoDB: Since innodb_force_recovery > 0, we will rollback it anyway.\n");
+
+ trx->conc_state = TRX_ACTIVE;
+ }
+ } else {
+ trx->conc_state =
+ TRX_COMMITTED_IN_MEMORY;
+ }
+
/* We give a dummy value for the trx
number */
@@ -750,7 +806,8 @@ trx_commit_off_kernel(
mutex_enter(&kernel_mutex);
}
- ut_ad(trx->conc_state == TRX_ACTIVE);
+ ut_ad(trx->conc_state == TRX_ACTIVE
+ || trx->conc_state == TRX_PREPARED);
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
@@ -782,9 +839,6 @@ trx_commit_off_kernel(
trx->read_view = NULL;
}
-/* fprintf(stderr, "Trx %lu commit finished\n",
- ut_dulint_get_low(trx->id)); */
-
if (must_flush_log) {
mutex_exit(&kernel_mutex);
@@ -829,14 +883,15 @@ trx_commit_off_kernel(
/* Do nothing */
} else if (srv_flush_log_at_trx_commit == 1) {
if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
- /* Write the log but do not flush it to disk */
+ /* Write the log but do not flush it to disk */
- log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
+ log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
+ FALSE);
} else {
- /* Write the log to the log files AND flush
- them to disk */
+ /* Write the log to the log files AND flush
+ them to disk */
- log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
+ log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
}
} else if (srv_flush_log_at_trx_commit == 2) {
@@ -1609,20 +1664,24 @@ trx_print(
(ulong) ut_dulint_get_high(trx->id),
(ulong) ut_dulint_get_low(trx->id));
- switch (trx->conc_state) {
+ switch (trx->conc_state) {
case TRX_NOT_STARTED:
fputs(", not started", f);
break;
case TRX_ACTIVE:
fprintf(f, ", ACTIVE %lu sec",
(ulong)difftime(time(NULL), trx->start_time));
- break;
+ break;
+ case TRX_PREPARED:
+ fprintf(f, ", ACTIVE (PREPARED) %lu sec",
+ (ulong)difftime(time(NULL), trx->start_time));
+ break;
case TRX_COMMITTED_IN_MEMORY:
fputs(", COMMITTED IN MEMORY", f);
break;
default:
fprintf(f, " state %lu", (ulong) trx->conc_state);
- }
+ }
#ifdef UNIV_LINUX
fprintf(f, ", process no %lu", trx->mysql_process_no);
@@ -1647,10 +1706,15 @@ trx_print(
putc('\n', f);
if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
+ fprintf(f, "mysql tables in use %lu, locked %lu\n",
+ (ulong) trx->n_mysql_tables_in_use,
+ (ulong) trx->mysql_n_tables_locked);
+ }
- fprintf(f, "mysql tables in use %lu, locked %lu\n",
- (ulong) trx->n_mysql_tables_in_use,
- (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;
@@ -1696,3 +1760,266 @@ trx_print(
innobase_mysql_print_thd(f, trx->mysql_thd);
}
}
+
+/********************************************************************
+Prepares a transaction. */
+
+void
+trx_prepare_off_kernel(
+/*===================*/
+ trx_t* trx) /* in: transaction */
+{
+ page_t* update_hdr_page;
+ trx_rseg_t* rseg;
+ ibool must_flush_log = FALSE;
+ dulint lsn;
+ mtr_t mtr;
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(mutex_own(&kernel_mutex));
+#endif /* UNIV_SYNC_DEBUG */
+
+ rseg = trx->rseg;
+
+ if (trx->insert_undo != NULL || trx->update_undo != NULL) {
+
+ mutex_exit(&kernel_mutex);
+
+ mtr_start(&mtr);
+
+ must_flush_log = TRUE;
+
+ /* Change the undo log segment states from TRX_UNDO_ACTIVE
+ to TRX_UNDO_PREPARED: these modifications to the file data
+ structure define the transaction as prepared in the
+ file-based world, at the serialization point of lsn. */
+
+ mutex_enter(&(rseg->mutex));
+
+ if (trx->insert_undo != NULL) {
+
+ /* It is not necessary to obtain trx->undo_mutex here
+ because only a single OS thread is allowed to do the
+ transaction prepare for this transaction. */
+
+ trx_undo_set_state_at_prepare(trx, trx->insert_undo,
+ &mtr);
+ }
+
+ if (trx->update_undo) {
+ update_hdr_page = trx_undo_set_state_at_prepare(trx,
+ trx->update_undo, &mtr);
+ }
+
+ mutex_exit(&(rseg->mutex));
+
+ /*--------------*/
+ mtr_commit(&mtr); /* This mtr commit makes the
+ transaction prepared in the file-based
+ world */
+ /*--------------*/
+ lsn = mtr.end_lsn;
+
+ mutex_enter(&kernel_mutex);
+ }
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(mutex_own(&kernel_mutex));
+#endif /* UNIV_SYNC_DEBUG */
+
+ /*--------------------------------------*/
+ trx->conc_state = TRX_PREPARED;
+ /*--------------------------------------*/
+
+ if (must_flush_log) {
+ /* Depending on the my.cnf options, we may now write the log
+ buffer to the log files, making the prepared state of the
+ transaction durable if the OS does not crash. We may also
+ flush the log files to disk, making the prepared state of the
+ transaction durable also at an OS crash or a power outage.
+
+ The idea in InnoDB's group prepare is that a group of
+ transactions gather behind a trx doing a physical disk write
+ to log files, and when that physical write has been completed,
+ one of those transactions does a write which prepares the whole
+ group. Note that this group prepare will only bring benefit if
+ there are > 2 users in the database. Then at least 2 users can
+ gather behind one doing the physical log write to disk.
+
+ TODO: find out if MySQL holds some mutex when calling this.
+ That would spoil our group prepare algorithm. */
+
+ mutex_exit(&kernel_mutex);
+
+ if (srv_flush_log_at_trx_commit == 0) {
+ /* Do nothing */
+ } else if (srv_flush_log_at_trx_commit == 1) {
+ if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
+ /* Write the log but do not flush it to disk */
+
+ log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
+ FALSE);
+ } else {
+ /* Write the log to the log files AND flush
+ them to disk */
+
+ log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
+ }
+ } else if (srv_flush_log_at_trx_commit == 2) {
+
+ /* Write the log but do not flush it to disk */
+
+ log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
+ } else {
+ ut_error;
+ }
+
+ mutex_enter(&kernel_mutex);
+ }
+}
+
+/**************************************************************************
+Does the transaction prepare for MySQL. */
+
+ulint
+trx_prepare_for_mysql(
+/*====-=============*/
+ /* out: 0 or error number */
+ trx_t* trx) /* in: trx handle */
+{
+ /* Because we do not do the prepare by sending an Innobase
+ sig to the transaction, we must here make sure that trx has been
+ started. */
+
+ ut_a(trx);
+
+ trx->op_info = "preparing";
+
+ trx_start_if_not_started(trx);
+
+ mutex_enter(&kernel_mutex);
+
+ trx_prepare_off_kernel(trx);
+
+ mutex_exit(&kernel_mutex);
+
+ trx->op_info = "";
+
+ return(0);
+}
+
+/**************************************************************************
+This function is used to find number of prepared transactions and
+their transaction objects for a recovery. */
+
+int
+trx_recover_for_mysql(
+/*==================*/
+ /* out: number of prepared transactions
+ stored in xid_list */
+ XID* xid_list, /* in/out: prepared transactions */
+ ulint len) /* in: number of slots in xid_list */
+{
+ trx_t* trx;
+ int count = 0;
+
+ ut_ad(xid_list);
+ ut_ad(len);
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Starting recovery for XA transactions...\n");
+
+ /* We should set those transactions which are in the prepared state
+ to the xid_list */
+
+ mutex_enter(&kernel_mutex);
+
+ trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
+
+ while (trx) {
+ if (trx->conc_state == TRX_PREPARED) {
+ xid_list[count] = trx->xid;
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Transaction %lu %lu in prepared state after recovery\n",
+ (ulong) ut_dulint_get_high(trx->id),
+ (ulong) ut_dulint_get_low(trx->id));
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Transaction contains changes to %lu rows\n",
+ (ulong)ut_conv_dulint_to_longlong(trx->undo_no));
+
+ count++;
+
+ if ((uint)count == len ) {
+ break;
+ }
+ }
+
+ trx = UT_LIST_GET_NEXT(trx_list, trx);
+ }
+
+ mutex_exit(&kernel_mutex);
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: %d transactions in prepared state after recovery\n",
+ count);
+
+ return (count);
+}
+
+/***********************************************************************
+This function is used to find one X/Open XA distributed transaction
+which is in the prepared state */
+
+trx_t*
+trx_get_trx_by_xid(
+/*===============*/
+ /* out: trx or NULL */
+ XID* xid) /* in: X/Open XA transaction identification */
+{
+ trx_t* trx;
+
+ if (xid == NULL) {
+
+ return (NULL);
+ }
+
+ mutex_enter(&kernel_mutex);
+
+ trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
+
+ while (trx) {
+ /* Compare two X/Open XA transaction id's: their
+ length should be the same and binary comparison
+ of gtrid_lenght+bqual_length bytes should be
+ the same */
+
+ if (xid->gtrid_length == trx->xid.gtrid_length &&
+ xid->bqual_length == trx->xid.bqual_length &&
+ memcmp(xid->data, trx->xid.data,
+ xid->gtrid_length +
+ xid->bqual_length) == 0) {
+ break;
+ }
+
+ trx = UT_LIST_GET_NEXT(trx_list, trx);
+ }
+
+ mutex_exit(&kernel_mutex);
+
+ if (trx) {
+ if (trx->conc_state != TRX_PREPARED) {
+
+ return(NULL);
+ }
+
+ return(trx);
+ } else {
+ return(NULL);
+ }
+}
diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c
index 8d1518753dd..bb314dd35e9 100644
--- a/innobase/trx/trx0undo.c
+++ b/innobase/trx/trx0undo.c
@@ -19,6 +19,7 @@ Created 3/26/1996 Heikki Tuuri
#include "srv0srv.h"
#include "trx0rec.h"
#include "trx0purge.h"
+#include "trx0xa.h"
/* How should the old versions in the history list be managed?
----------------------------------------------------------
@@ -97,10 +98,13 @@ trx_undo_mem_create(
TRX_UNDO_UPDATE */
dulint trx_id, /* in: id of the trx for which the undo log
is created */
+ XID* xid, /* in: X/Open XA transaction identification*/
ulint page_no,/* in: undo log header page number */
- ulint offset); /* in: undo log header byte offset on page */
+ ulint offset);/* in: undo log header byte offset on page */
/*******************************************************************
-Initializes a cached insert undo log header page for new use. */
+Initializes a cached insert undo log header page for new use. NOTE that this
+function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
+the operation of this function! */
static
ulint
trx_undo_insert_header_reuse(
@@ -181,7 +185,8 @@ trx_undo_get_prev_rec(
/* We have to go to the previous undo log page to look for the
previous record */
- return(trx_undo_get_prev_rec_from_prev_page(rec, page_no, offset, mtr));
+ return(trx_undo_get_prev_rec_from_prev_page(rec, page_no, offset,
+ mtr));
}
/***************************************************************************
@@ -473,15 +478,17 @@ trx_undo_header_create_log(
}
/*******************************************************************
-Creates a new undo log header in file. */
+Creates a new undo log header in file. NOTE that this function has its own
+log record type MLOG_UNDO_HDR_CREATE. You must NOT change the operation of
+this function! */
static
ulint
trx_undo_header_create(
/*===================*/
/* out: header byte offset on page */
page_t* undo_page, /* in: undo log segment header page,
- x-latched; it is assumed that there is
- TRX_UNDO_LOG_HDR_SIZE bytes free space
+ x-latched; it is assumed that there are
+ TRX_UNDO_LOG_XA_HDR_SIZE bytes free space
on it */
dulint trx_id, /* in: transaction id */
mtr_t* mtr) /* in: mtr */
@@ -503,9 +510,9 @@ trx_undo_header_create(
log_hdr = undo_page + free;
- new_free = free + TRX_UNDO_LOG_HDR_SIZE;
+ new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
- ut_ad(new_free <= UNIV_PAGE_SIZE);
+ ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
@@ -530,16 +537,102 @@ trx_undo_header_create(
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
- mach_write_to_2(log_hdr + TRX_UNDO_DICT_OPERATION, FALSE);
-
+ mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
+ mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
+
mach_write_to_2(log_hdr + TRX_UNDO_NEXT_LOG, 0);
mach_write_to_2(log_hdr + TRX_UNDO_PREV_LOG, prev_log);
-
+
+ /* Write the log record about the header creation */
trx_undo_header_create_log(undo_page, trx_id, mtr);
return(free);
}
+/************************************************************************
+Write X/Open XA Transaction Identification (XID) to undo log header */
+static
+void
+trx_undo_write_xid(
+/*===============*/
+ trx_ulogf_t* log_hdr,/* in: undo log header */
+ 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_TRID_LEN, xid->gtrid_length,
+ MLOG_4BYTES, mtr);
+
+ mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN, xid->bqual_length,
+ MLOG_4BYTES, mtr);
+
+ mlog_write_string(log_hdr + TRX_UNDO_XA_XID, xid->data,
+ XIDDATASIZE, mtr);
+}
+
+/************************************************************************
+Read X/Open XA Transaction Identification (XID) from undo log header */
+static
+void
+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->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);
+
+ for (i = 0; i < XIDDATASIZE; i++) {
+ xid->data[i] = (char)mach_read_from_1(log_hdr +
+ TRX_UNDO_XA_XID + i);
+ }
+}
+
+/*******************************************************************
+Adds space for the XA XID after an undo log old-style header. */
+static
+void
+trx_undo_header_add_space_for_xid(
+/*==============================*/
+ page_t* undo_page,/* in: undo log segment header page */
+ trx_ulogf_t* log_hdr,/* in: undo log header */
+ mtr_t* mtr) /* in: mtr */
+{
+ trx_upagef_t* page_hdr;
+ ulint free;
+ ulint new_free;
+
+ page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
+
+ free = mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE);
+
+ /* free is now the end offset of the old style undo log header */
+
+ ut_a(free == (ulint)(log_hdr - undo_page) + TRX_UNDO_LOG_OLD_HDR_SIZE);
+
+ new_free = free + (TRX_UNDO_LOG_XA_HDR_SIZE
+ - TRX_UNDO_LOG_OLD_HDR_SIZE);
+
+ /* Add space for a XID after the header, update the free offset
+ fields on the undo log page and in the undo log header */
+
+ mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_START, new_free,
+ MLOG_2BYTES, mtr);
+
+ mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE, new_free,
+ MLOG_2BYTES, mtr);
+
+ mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, new_free,
+ MLOG_2BYTES, mtr);
+}
+
/**************************************************************************
Writes the mtr log entry of an undo log header reuse. */
UNIV_INLINE
@@ -590,7 +683,9 @@ trx_undo_parse_page_header(
}
/*******************************************************************
-Initializes a cached insert undo log header page for new use. */
+Initializes a cached insert undo log header page for new use. NOTE that this
+function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
+the operation of this function! */
static
ulint
trx_undo_insert_header_reuse(
@@ -614,9 +709,11 @@ trx_undo_insert_header_reuse(
free = TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE;
+ ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
+
log_hdr = undo_page + free;
- new_free = free + TRX_UNDO_LOG_HDR_SIZE;
+ new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
/* Insert undo data is not needed after commit: we may free all
the space on the page */
@@ -636,8 +733,10 @@ trx_undo_insert_header_reuse(
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
- mach_write_to_2(log_hdr + TRX_UNDO_DICT_OPERATION, FALSE);
+ mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
+ mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
+ /* Write the log record MLOG_UNDO_HDR_REUSE */
trx_undo_insert_header_reuse_log(undo_page, trx_id, mtr);
return(free);
@@ -800,7 +899,6 @@ trx_undo_free_page(
list */
ulint space, /* in: space */
ulint hdr_page_no, /* in: header page number */
- ulint hdr_offset, /* in: header offset */
ulint page_no, /* in: page number to free: must not be the
header page */
mtr_t* mtr) /* in: mtr which does not have a latch to any
@@ -813,7 +911,6 @@ trx_undo_free_page(
trx_rsegf_t* rseg_header;
ulint hist_size;
- UT_NOT_USED(hdr_offset);
ut_a(hdr_page_no != page_no);
#ifdef UNIV_SYNC_DEBUG
ut_ad(!mutex_own(&kernel_mutex));
@@ -870,8 +967,7 @@ trx_undo_free_page_in_rollback(
#endif /* UNIV_SYNC_DEBUG */
last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space,
- undo->hdr_page_no, undo->hdr_offset,
- page_no, mtr);
+ undo->hdr_page_no, page_no, mtr);
undo->last_page_no = last_page_no;
undo->size--;
@@ -1039,7 +1135,7 @@ loop:
trx_undo_empty_header_page(space, hdr_page_no, hdr_offset,
&mtr);
} else {
- trx_undo_free_page(rseg, TRUE, space, hdr_page_no, hdr_offset,
+ trx_undo_free_page(rseg, TRUE, space, hdr_page_no,
page_no, &mtr);
}
@@ -1123,7 +1219,9 @@ trx_undo_mem_create_at_db_start(
fil_addr_t last_addr;
page_t* last_page;
trx_undo_rec_t* rec;
-
+ XID xid;
+ ibool xid_exists = FALSE;
+
if (id >= TRX_RSEG_N_SLOTS) {
fprintf(stderr,
"InnoDB: Error: undo->id is %lu\n", (ulong) id);
@@ -1145,15 +1243,30 @@ trx_undo_mem_create_at_db_start(
undo_header = undo_page + offset;
trx_id = mtr_read_dulint(undo_header + TRX_UNDO_TRX_ID, mtr);
+
+ xid_exists = mtr_read_ulint(undo_header + TRX_UNDO_XID_EXISTS,
+ MLOG_1BYTE, mtr);
+
+ /* Read X/Open XA transaction identification if it exists, or
+ set it to NULL. */
+
+ memset(&xid, 0, sizeof(xid));
+ xid.formatID = -1;
+
+ if (xid_exists == TRUE) {
+ trx_undo_read_xid(undo_header, &xid);
+ }
+
mutex_enter(&(rseg->mutex));
- undo = trx_undo_mem_create(rseg, id, type, trx_id, page_no, offset);
-
+ undo = trx_undo_mem_create(rseg, id, type, trx_id, &xid,
+ page_no, offset);
mutex_exit(&(rseg->mutex));
- undo->dict_operation = mtr_read_ulint(
- undo_header + TRX_UNDO_DICT_OPERATION,
- MLOG_2BYTES, mtr);
+ undo->dict_operation = mtr_read_ulint(
+ undo_header + TRX_UNDO_DICT_TRANS,
+ MLOG_1BYTE, mtr);
+
undo->table_id = mtr_read_dulint(undo_header + TRX_UNDO_TABLE_ID, mtr);
undo->state = state;
undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr);
@@ -1272,7 +1385,8 @@ trx_undo_mem_create(
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
TRX_UNDO_UPDATE */
dulint trx_id, /* in: id of the trx for which the undo log
- is created */
+ is created */
+ XID* xid, /* in: X/Open transaction identification */
ulint page_no,/* in: undo log header page number */
ulint offset) /* in: undo log header byte offset on page */
{
@@ -1295,6 +1409,7 @@ trx_undo_mem_create(
undo->state = TRX_UNDO_ACTIVE;
undo->del_marks = FALSE;
undo->trx_id = trx_id;
+ undo->xid = *xid;
undo->dict_operation = FALSE;
@@ -1322,6 +1437,7 @@ trx_undo_mem_init_for_reuse(
trx_undo_t* undo, /* in: undo log to init */
dulint trx_id, /* in: id of the trx for which the undo log
is created */
+ XID* xid, /* in: X/Open XA transaction identification*/
ulint offset) /* in: undo log header byte offset on page */
{
#ifdef UNIV_SYNC_DEBUG
@@ -1339,6 +1455,7 @@ trx_undo_mem_init_for_reuse(
undo->state = TRX_UNDO_ACTIVE;
undo->del_marks = FALSE;
undo->trx_id = trx_id;
+ undo->xid = *xid;
undo->dict_operation = FALSE;
@@ -1371,11 +1488,13 @@ trx_undo_create(
/*============*/
/* out: undo log object, NULL if did not
succeed: out of space */
+ trx_t* trx, /* in: transaction */
trx_rseg_t* rseg, /* in: rollback segment memory copy */
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
TRX_UNDO_UPDATE */
dulint trx_id, /* in: id of the trx for which the undo log
is created */
+ XID* xid, /* in: X/Open transaction identification*/
mtr_t* mtr) /* in: mtr */
{
trx_rsegf_t* rseg_header;
@@ -1410,10 +1529,15 @@ trx_undo_create(
page_no = buf_frame_get_page_no(undo_page);
- offset = trx_undo_header_create(undo_page, trx_id, mtr);
+ offset = trx_undo_header_create(undo_page, trx_id, mtr);
- undo = trx_undo_mem_create(rseg, id, type, trx_id, page_no, offset);
-
+ if (trx->support_xa) {
+ trx_undo_header_add_space_for_xid(undo_page,
+ undo_page + offset, mtr);
+ }
+
+ undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
+ page_no, offset);
return(undo);
}
@@ -1427,11 +1551,13 @@ trx_undo_reuse_cached(
/*==================*/
/* out: the undo log memory object, NULL if
none cached */
+ trx_t* trx, /* in: transaction */
trx_rseg_t* rseg, /* in: rollback segment memory object */
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
TRX_UNDO_UPDATE */
dulint trx_id, /* in: id of the trx for which the undo log
is used */
+ XID* xid, /* in: X/Open XA transaction identification */
mtr_t* mtr) /* in: mtr */
{
trx_undo_t* undo;
@@ -1476,15 +1602,25 @@ trx_undo_reuse_cached(
if (type == TRX_UNDO_INSERT) {
offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
+
+ if (trx->support_xa) {
+ trx_undo_header_add_space_for_xid(undo_page,
+ undo_page + offset, mtr);
+ }
} else {
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_TYPE)
== TRX_UNDO_UPDATE);
offset = trx_undo_header_create(undo_page, trx_id, mtr);
+
+ if (trx->support_xa) {
+ trx_undo_header_add_space_for_xid(undo_page,
+ undo_page + offset, mtr);
+ }
}
- trx_undo_mem_init_for_reuse(undo, trx_id, offset);
+ trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
return(undo);
}
@@ -1506,9 +1642,10 @@ trx_undo_mark_as_dict_operation(
hdr_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
- mlog_write_ulint(hdr_page + undo->hdr_offset + TRX_UNDO_DICT_OPERATION,
- trx->dict_operation, MLOG_2BYTES, mtr);
-
+ mlog_write_ulint(hdr_page + undo->hdr_offset +
+ TRX_UNDO_DICT_TRANS,
+ trx->dict_operation, MLOG_1BYTE, mtr);
+
mlog_write_dulint(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID,
trx->table_id, mtr);
@@ -1548,11 +1685,11 @@ trx_undo_assign_undo(
#endif /* UNIV_SYNC_DEBUG */
mutex_enter(&(rseg->mutex));
- undo = trx_undo_reuse_cached(rseg, type, trx->id, &mtr);
-
+ undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, &trx->xid,
+ &mtr);
if (undo == NULL) {
- undo = trx_undo_create(rseg, type, trx->id, &mtr);
-
+ undo = trx_undo_create(trx, rseg, type, trx->id, &trx->xid,
+ &mtr);
if (undo == NULL) {
/* Did not succeed */
@@ -1632,6 +1769,57 @@ trx_undo_set_state_at_finish(
return(undo_page);
}
+/**********************************************************************
+Sets the state of the undo log segment at a transaction prepare. */
+
+page_t*
+trx_undo_set_state_at_prepare(
+/*==========================*/
+ /* out: undo log segment header page,
+ x-latched */
+ trx_t* trx, /* in: transaction */
+ trx_undo_t* undo, /* in: undo log memory copy */
+ mtr_t* mtr) /* in: mtr */
+{
+ trx_usegf_t* seg_hdr;
+ trx_upagef_t* page_hdr;
+ trx_ulogf_t* undo_header;
+ page_t* undo_page;
+ ulint offset;
+
+ ut_ad(trx && undo && mtr);
+
+ if (undo->id >= TRX_RSEG_N_SLOTS) {
+ fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
+ (ulong) undo->id);
+ mem_analyze_corruption((byte*)undo);
+ ut_error;
+ }
+
+ undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
+
+ seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
+ page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
+
+ /*------------------------------*/
+ undo->state = TRX_UNDO_PREPARED;
+ undo->xid = trx->xid;
+ /*------------------------------*/
+
+ mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, undo->state,
+ MLOG_2BYTES, mtr);
+
+ offset = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
+ undo_header = undo_page + offset;
+
+ mlog_write_ulint(undo_header + TRX_UNDO_XID_EXISTS,
+ TRUE, MLOG_1BYTE, mtr);
+
+ trx_undo_write_xid(undo_header, &undo->xid, mtr);
+
+ return(undo_page);
+}
+
/**************************************************************************
Adds the update undo log header as the first in the history list, and
frees the memory object, or puts it to the list of cached update undo log
diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c
index 18ee53a354c..3e8fd79a739 100644
--- a/innobase/ut/ut0mem.c
+++ b/innobase/ut/ut0mem.c
@@ -92,6 +92,8 @@ retry:
"InnoDB: ulimits of your operating system.\n"
"InnoDB: On FreeBSD check you have compiled the OS with\n"
"InnoDB: a big enough maximum process size.\n"
+ "InnoDB: Note that in most 32-bit computers the process\n"
+ "InnoDB: memory space is limited to 2 GB or 4 GB.\n"
"InnoDB: We keep retrying the allocation for 60 seconds...\n",
(ulong) n, (ulong) ut_total_allocated_memory,
#ifdef __WIN__
diff --git a/innobase/ut/ut0ut.c b/innobase/ut/ut0ut.c
index 2a2db9442b3..1be5939303a 100644
--- a/innobase/ut/ut0ut.c
+++ b/innobase/ut/ut0ut.c
@@ -74,6 +74,28 @@ ut_time(void)
}
/**************************************************************
+Returns system time. */
+
+void
+ut_usectime(
+/*========*/
+ ulint* sec, /* out: seconds since the Epoch */
+ ulint* ms) /* out: microseconds since the Epoch+*sec */
+{
+#ifdef __WIN__
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ *sec = (ulint) st.wSecond;
+ *ms = (ulint) st.wMilliseconds;
+#else
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ *sec = (ulint) tv.tv_sec;
+ *ms = (ulint) tv.tv_usec;
+#endif
+}
+
+/**************************************************************
Returns the difference of two times in seconds. */
double
@@ -394,7 +416,11 @@ ut_print_namel(
{
const char* s = name;
const char* e = s + namelen;
+#ifdef UNIV_HOTBACKUP
+ int q = '"';
+#else
int q = mysql_get_identifier_quote_char(trx, name, namelen);
+#endif
if (q == EOF) {
fwrite(name, 1, namelen, f);
return;
diff --git a/isam/.cvsignore b/isam/.cvsignore
deleted file mode 100644
index dc55807a96b..00000000000
--- a/isam/.cvsignore
+++ /dev/null
@@ -1,10 +0,0 @@
-.deps
-.libs
-Makefile
-Makefile.in
-isamchk
-isamlog
-pack_isam
-test1
-test2
-test3
diff --git a/isam/ChangeLog b/isam/ChangeLog
deleted file mode 100644
index 4a9e3e03954..00000000000
--- a/isam/ChangeLog
+++ /dev/null
@@ -1,186 +0,0 @@
-2000-04-26 Michael Widenius <monty@mysql.com>
-
-* Fixed bug when doing read_next after a delete/insert which balanced key
- pages (In this case one internal buffer was wrongly reused)
-
-1999-11-23 Michael Widenius <monty@monty.pp.sci.fi>
-
-* Changed prefix from ni_ to nisam_ to avoid problems on MacOS X.
-
-1999-08-17 Michael Widenius <monty@tik.pp.sci.fi>
-
-* Changed last parameter to mi_open() to be a bit flag instead of an int.
-
-1998-10-01 Michael Widenius <monty@monty.pp.sci.fi>
-
-* Fixed bug in key packing when using some USE_STRCOLL character sets.
-
-Thu Aug 20 23:17:41 1998 Michael Widenius <monty@bitch.pp.sci.fi>
-
-* isamchk.c: Sometimes isamchk --sort-table caused isamchk to die.
-
-1998-06-28 Michael Widenius <monty@monty.pp.sci.fi>
-
-* Fixed some possible race conditions when using with MySQL and
- many reopen/close of the same tables under heavy load!
-* Changed isamchk to re-pack records when doing a repair to make it more safer.
-
-Thu Mar 12 21:44:08 1998 Michael Widenius <monty@monty.pp.sci.fi>
-
-* Added a safty test to _ni_rec_unpack.
-
-Wed Nov 26 01:52:55 1997 <monty@monty.pp.sci.fi>
-
-* Fixed small problem when reading delete-marked records with rkey, rnext and
- rprev. In normal applications this should never happen.
-
-Thu Nov 20 14:01:21 1997 <monty@monty.pp.sci.fi>
-
-* Fixed range key bug when using compressed key where the first part wasn't
- compressed.
-* Converted everything to use prototypes.
-
-Mon Sep 29 13:16:27 1997 <monty@monty.pp.sci.fi>
-
-* Fixed problem with isamchk and compressed records files with record_reflength
- < 4 (Gave wrong key when using isamchk -rq).
-
-Fri Sep 26 16:06:37 1997 <monty@monty.pp.sci.fi>
-
-* Fixed bug in range calculation.
-
-Thu Aug 14 14:44:33 1997 <monty@monty.pp.sci.fi>
-
-* Removed a couple of unnecessary seeks from 'delete static record'
-
-Tue Jul 1 22:04:16 1997 <monty@monty.pp.sci.fi>
-
-* Added checking of 'wrong packed records' when using 'isamchk -e' or
- isamchk -ro.
-
-Fri Feb 7 22:22:28 1997 Michael Widenius <monty@bitch.sci.fi>
-
-* Fixed use of packed tables with threads (One static variable left)
-
-Thu Jan 23 09:05:22 1997 Michael Widenius <monty@bitch.sci.fi>
-
-* Changed create to detect keys > 127 and not pack them. Now one can
- define keys with a length of up to (nisam_block_size-18)/2
- by changeing N_MAX_KEY_LENGTH.
-
-Fri Jan 10 21:01:44 1997 Michael Widenius <monty@bitch.sci.fi>
-
-* added signed chars as key type.
-
-Fri Apr 26 14:31:05 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
-
-* create.c: All keyfile blocks are now IO_SIZE big (for better keycashing).
-
-Tue Mar 12 22:42:52 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
-
-* isamchk.c: Changed to print info if system table
-* write.c: Don't allow more than 1 record in system table.
-
-Fri Feb 2 16:40:32 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
-
-* isamchk.c; Check that delete-link-chain is ok before trying to delete with 'q'.
-
-Thu Jan 11 13:21:23 1996 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
-
-* All same isam files now shares a structure to allow many opens off the same
- file
-
-Sat Nov 25 12:33:53 1995 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
-
-* All functions now used my_errno instead of errno
-
-Mon Oct 23 12:32:02 1995 Michael Widenius <monty@bitch.clinet.fi (Michael Widenius)>
-
-* isamchk.c: Don't print that database should be fixed on automatic rep.
-
-Sun Aug 27 20:13:56 1995 Michael Widenius <monty@bitch.analytikerna.se (Michael Widenius)>
-
-* _dynrec.c added flush_io_cash() if someone did a read when using
- WRITE CASHING.
-
-Thu Apr 20 01:41:24 1995 Michael Widenius (monty@bitch)
-
-* fixed errno when got error of 'key-not-found' when updateing or
- deleting record.
-
-Tue Jan 17 19:37:48 1995 Michael Widenius (monty@bitch)
-
-* isamchk can now unpack databases.
-* prolinted all files.
-
-Fri May 27 15:01:06 1994 Michael Widenius (monty@bitch)
-
-* Don't lock packed databases.
-
-Sat Apr 16 22:41:23 1994 Michael Widenius (monty@bitch)
-
-* Added new function read_rsame_with_pos.
-
-Wed Mar 30 15:52:19 1994 Michael Widenius (monty@bitch)
-
-* Added creation and recover date to indexfile and isamchk.
-
-Sat Mar 26 15:03:37 1994 Michael Widenius (monty@bitch)
-
-* change is_panic() to close all files on ha_panic(write) on systems
- (VMS) with can't open one file twice.
-
-Fri Feb 4 21:09:56 1994 Michael Widenius (monty@bitch)
-
-* READ_CASH on packed files now makes them mem-mapped if possibly
-
-Sat Sep 18 14:56:32 1993 Michael Widenius (monty at bitch)
-
-* changed _search to use pointer to buffer when reading keys.
-
-Mon Aug 16 19:45:29 1993 Michael Widenius (monty at bitch)
-
-* isamchk and packisam resolves symbolic links before file is used.
- This forces temp-files on same disk as orginal file and rename
- of temp-files dosen't destroy symbolic links.
-
-Mon May 31 18:26:08 1993 Michael Widenius (monty at bitch)
-
-* Added crc-check of records when packing for safe test if pack ok.
-
-Tue Mar 2 19:16:00 1993 Michael Widenius (monty@bitch)
-
-* Added logging of records with ni_log().
-
-Fri Jan 29 00:56:58 1993 Michael Widenius (monty@bitch)
-
-* Fixed bug in _read_rnd_static_record ; A lock was made for
- each record even if it was in cash.
-
-Sun Nov 15 12:51:36 1992 Michael Widenius (monty@bitch)
-
-* last change breaked _dynrec, when not compileing with dbug.
-
-Fri Nov 6 03:46:38 1992 Michael Widenius (monty@bitch)
-
-* Fixed bugg when using packed records and reclength < 8 byte.
-
-Wed Oct 28 22:23:32 1992 Michael Widenius (monty@bitch)
-
-* Changed _cash.c to use io_cash to allow use of aioread.
-
-Fri Oct 23 00:45:53 1992 Michael Widenius (monty@bitch)
-
-* Added MY_WAIT_IF_FULL to pack_isam.
-
-Sat Oct 17 14:51:15 1992 Michael Widenius (monty@bitch)
-
-* Added use of subset of keys (isamchk -k#)
-
-Mon Oct 5 21:53:18 1992 Michael Widenius (monty@bitch)
-
-* Remove reloc of database ; Gives only problems with isamchk.
-
-Mon Aug 17 03:17:09 1992 Michael Widenius (monty@bitch)
-
-* Changed isam to use io_cash instead of rec_cash
diff --git a/isam/Makefile.am b/isam/Makefile.am
deleted file mode 100644
index 6d9e4176d43..00000000000
--- a/isam/Makefile.am
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include
-LDADD = @CLIENT_EXTRA_LDFLAGS@ libnisam.a ../mysys/libmysys.a \
- ../dbug/libdbug.a ../strings/libmystrings.a
-pkglib_LIBRARIES = libnisam.a
-bin_PROGRAMS = isamchk isamlog pack_isam
-isamchk_DEPENDENCIES= $(LIBRARIES)
-isamlog_DEPENDENCIES= $(LIBRARIES)
-pack_isam_DEPENDENCIES= $(LIBRARIES)
-noinst_PROGRAMS = test1 test2 test3
-noinst_HEADERS = isamdef.h
-test1_DEPENDENCIES= $(LIBRARIES)
-test2_DEPENDENCIES= $(LIBRARIES)
-test3_DEPENDENCIES= $(LIBRARIES)
-libnisam_a_SOURCES = open.c extra.c info.c rkey.c rnext.c \
- _search.c _page.c _key.c _locking.c \
- rrnd.c _cache.c _statrec.c _packrec.c \
- _dynrec.c update.c write.c delete.c \
- rprev.c rfirst.c rlast.c rsame.c rsamepos.c \
- panic.c close.c create.c range.c _dbug.c \
- log.c changed.c static.c
-isamchk_SOURCES = isamchk.c sort.c
-CLEANFILES = test?.IS? isam.log
-
-# Move to automake rules ?
-prolint:; plparse -b -u -hF1 "-width(0,0)" "-format=%f:%l:\s%t:%n\s%m" \
- "-elib(????)" "+elib(?3??)" my.lnt $(nisam_SOURCES)
-
-# Don't update the files from bitkeeper
-%::SCCS/s.%
diff --git a/isam/_cache.c b/isam/_cache.c
deleted file mode 100644
index bca9a699a85..00000000000
--- a/isam/_cache.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Functions for read record cacheing with nisam */
-/* Used instead of my_b_read() to allow for no-cacheed seeks */
-
-#include "isamdef.h"
-
-#define READING_NEXT 1
-#define READING_HEADER 2
-
- /* Copy block from cache if it`s in it. If re_read_if_possibly is */
- /* set read to cache (if after current file-position) else read to */
- /* buff */
-
-int _nisam_read_cache(IO_CACHE *info, byte *buff, ulong pos, uint length,
- int flag)
-{
- uint read_length,in_buff_length;
- ulong offset;
- char *in_buff_pos;
-
- if (pos < info->pos_in_file)
- {
- read_length= (uint) min((ulong) length,(ulong) (info->pos_in_file-pos));
- info->seek_not_done=1;
- VOID(my_seek(info->file,pos,MY_SEEK_SET,MYF(0)));
- if (my_read(info->file,buff,read_length,MYF(MY_NABP)))
- return 1;
- if (!(length-=read_length))
- return 0;
- pos+=read_length;
- buff+=read_length;
- }
- if ((offset=pos - (ulong) info->pos_in_file) <
- (ulong) (info->read_end - info->request_pos))
- {
- in_buff_pos=info->request_pos+(uint) offset;
- in_buff_length= min(length,(uint) (info->read_end-in_buff_pos));
- memcpy(buff,info->request_pos+(uint) offset,(size_t) in_buff_length);
- if (!(length-=in_buff_length))
- return 0;
- pos+=in_buff_length;
- buff+=in_buff_length;
- }
- else
- in_buff_length=0;
- if (flag & READING_NEXT)
- {
- if (pos != ((info)->pos_in_file +
- (uint) ((info)->read_end - (info)->request_pos)))
- {
- info->pos_in_file=pos; /* Force start here */
- info->read_pos=info->read_end=info->request_pos; /* Everything used */
- info->seek_not_done=1;
- }
- else
- info->read_pos=info->read_end; /* All block used */
- if (!(*info->read_function)(info,buff,length))
- return 0;
- if (!(flag & READING_HEADER) || info->error == -1 ||
- (uint) info->error+in_buff_length < 3)
- return 1;
- if (BLOCK_INFO_HEADER_LENGTH < in_buff_length + (uint) info->error)
- bzero(buff+info->error,BLOCK_INFO_HEADER_LENGTH - in_buff_length -
- (uint) info->error);
- return 0;
- }
- info->seek_not_done=1;
- VOID(my_seek(info->file,pos,MY_SEEK_SET,MYF(0)));
- if ((read_length=my_read(info->file,buff,length,MYF(0))) == length)
- return 0;
- if (!(flag & READING_HEADER) || (int) read_length == -1 ||
- read_length+in_buff_length < 3)
- return 1;
- bzero(buff+read_length,BLOCK_INFO_HEADER_LENGTH - in_buff_length -
- read_length);
- return 0;
-} /* _nisam_read_cache */
diff --git a/isam/_dbug.c b/isam/_dbug.c
deleted file mode 100644
index 0a52dbbc916..00000000000
--- a/isam/_dbug.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Support rutiner with are using with dbug */
-
-#include "isamdef.h"
-
- /* Print a key in user understandable format */
-
-void _nisam_print_key(FILE *stream, register N_KEYSEG *keyseg, const uchar *key)
-{
- int flag;
- short int s_1;
- long int l_1;
- float f_1;
- double d_1;
- uchar *end;
-
- VOID(fputs("Key: \"",stream));
- flag=0;
- for (; keyseg->base.type ;keyseg++)
- {
- if (flag++)
- VOID(putc('-',stream));
- end= (uchar*) key+ keyseg->base.length;
- switch (keyseg->base.type) {
- case HA_KEYTYPE_BINARY:
- if (!(keyseg->base.flag & HA_SPACE_PACK) && keyseg->base.length == 1)
- { /* packed binary digit */
- VOID(fprintf(stream,"%d",(uint) *key++));
- break;
- }
- /* fall through */
- case HA_KEYTYPE_TEXT:
- case HA_KEYTYPE_NUM:
- if (keyseg->base.flag & HA_SPACE_PACK)
- {
- VOID(fprintf(stream,"%.*s",(int) *key,key+1));
- key+= (int) *key+1;
- }
- else
- {
- VOID(fprintf(stream,"%.*s",(int) keyseg->base.length,key));
- key=end;
- }
- break;
- case HA_KEYTYPE_INT8:
- VOID(fprintf(stream,"%d",(int) *((signed char*) key)));
- key=end;
- break;
- case HA_KEYTYPE_SHORT_INT:
- shortget(s_1,key);
- VOID(fprintf(stream,"%d",(int) s_1));
- key=end;
- break;
- case HA_KEYTYPE_USHORT_INT:
- {
- ushort u_1;
- ushortget(u_1,key);
- VOID(fprintf(stream,"%u",(uint) u_1));
- key=end;
- break;
- }
- case HA_KEYTYPE_LONG_INT:
- longget(l_1,key);
- VOID(fprintf(stream,"%ld",l_1));
- key=end;
- break;
- case HA_KEYTYPE_ULONG_INT:
- longget(l_1,key);
- VOID(fprintf(stream,"%lu",(ulong) l_1));
- key=end;
- break;
- case HA_KEYTYPE_INT24:
- VOID(fprintf(stream,"%ld",(long) sint3korr(key)));
- key=end;
- break;
- case HA_KEYTYPE_UINT24:
- VOID(fprintf(stream,"%ld",(long) uint3korr(key)));
- key=end;
- break;
- case HA_KEYTYPE_FLOAT:
- bmove((byte*) &f_1,(byte*) key,(int) sizeof(float));
- VOID(fprintf(stream,"%g",(double) f_1));
- key=end;
- break;
- case HA_KEYTYPE_DOUBLE:
- doubleget(d_1,key);
- VOID(fprintf(stream,"%g",d_1));
- key=end;
- break;
-#ifdef HAVE_LONG_LONG
- case HA_KEYTYPE_LONGLONG:
- {
- char buff[21];
- longlong tmp;
- longlongget(tmp,key);
- longlong2str(tmp,buff,-10);
- VOID(fprintf(stream,"%s",buff));
- key=end;
- break;
- }
- case HA_KEYTYPE_ULONGLONG:
- {
- char buff[21];
- longlong tmp;
- longlongget(tmp,key);
- longlong2str(tmp,buff,10);
- VOID(fprintf(stream,"%s",buff));
- key=end;
- break;
- }
-#endif
- default: break; /* This never happens */
- }
- }
- VOID(fputs("\n",stream));
- return;
-} /* print_key */
diff --git a/isam/_dynrec.c b/isam/_dynrec.c
deleted file mode 100644
index 25fe01e23f2..00000000000
--- a/isam/_dynrec.c
+++ /dev/null
@@ -1,1247 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
- /* Functions to handle space-packed-records and blobs */
-
-#include "isamdef.h"
-
-/* Enough for comparing if number is zero */
-static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-static int write_dynamic_record(N_INFO *info,const byte *record,
- uint reclength);
-static int _nisam_find_writepos(N_INFO *info,uint reclength,ulong *filepos,
- uint *length);
-static int update_dynamic_record(N_INFO *info,ulong filepos,byte *record,
- uint reclength);
-static int delete_dynamic_record(N_INFO *info,ulong filepos,
- uint second_read);
-static int _nisam_cmp_buffer(File file, const byte *buff, ulong filepos,
- uint length);
-
-#ifdef THREAD
-/* Play it safe; We have a small stack when using threads */
-#undef my_alloca
-#undef my_afree
-#define my_alloca(A) my_malloc((A),MYF(0))
-#define my_afree(A) my_free((A),MYF(0))
-#endif
-
- /* Interface function from N_INFO */
-
-int _nisam_write_dynamic_record(N_INFO *info, const byte *record)
-{
- uint reclength=_nisam_rec_pack(info,info->rec_buff,record);
- return (write_dynamic_record(info,info->rec_buff,reclength));
-}
-
-int _nisam_update_dynamic_record(N_INFO *info, ulong pos, const byte *record)
-{
- uint length=_nisam_rec_pack(info,info->rec_buff,record);
- return (update_dynamic_record(info,pos,info->rec_buff,length));
-}
-
-int _nisam_write_blob_record(N_INFO *info, const byte *record)
-{
- byte *rec_buff;
- int error;
- uint reclength,extra;
-
- extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
- DYN_DELETE_BLOCK_HEADER;
- if (!(rec_buff=(byte*) my_alloca(info->s->base.pack_reclength+
- _calc_total_blob_length(info,record)+
- extra)))
- return(-1);
- reclength=_nisam_rec_pack(info,rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
- record);
- error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
- reclength);
- my_afree(rec_buff);
- return(error);
-}
-
-
-int _nisam_update_blob_record(N_INFO *info, ulong pos, const byte *record)
-{
- byte *rec_buff;
- int error;
- uint reclength,extra;
-
- extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
- DYN_DELETE_BLOCK_HEADER;
- if (!(rec_buff=(byte*) my_alloca(info->s->base.pack_reclength+
- _calc_total_blob_length(info,record)+
- extra)))
- return(-1);
- reclength=_nisam_rec_pack(info,rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
- record);
- error=update_dynamic_record(info,pos,
- rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
- reclength);
- my_afree(rec_buff);
- return(error);
-}
-
-int _nisam_delete_dynamic_record(N_INFO *info)
-{
- return delete_dynamic_record(info,info->lastpos,0);
-}
-
-
- /* Write record to data-file */
-
-static int write_dynamic_record(N_INFO *info, const byte *record,
- uint reclength)
-{
- int flag;
- uint length;
- ulong filepos;
- DBUG_ENTER("write_dynamic_record");
-
- flag=0;
- while (reclength)
- {
- if (_nisam_find_writepos(info,reclength,&filepos,&length))
- goto err;
- if (_nisam_write_part_record(info,filepos,length,info->s->state.dellink,
- (byte**) &record,&reclength,&flag))
- goto err;
- }
-
- DBUG_RETURN(0);
- err:
- DBUG_RETURN(1);
-}
-
-
- /* Get a block for data ; The given data-area must be used !! */
-
-static int _nisam_find_writepos(N_INFO *info,
- uint reclength, /* record length */
- ulong *filepos, /* Return file pos */
- uint *length) /* length of block at filepos */
-{
- BLOCK_INFO block_info;
- DBUG_ENTER("_nisam_find_writepos");
-
- if (info->s->state.dellink != NI_POS_ERROR)
- {
- *filepos=info->s->state.dellink;
- block_info.second_read=0;
- info->rec_cache.seek_not_done=1;
-
- if (!(_nisam_get_block_info(&block_info,info->dfile,
- info->s->state.dellink) & BLOCK_DELETED))
- {
- my_errno=HA_ERR_WRONG_IN_RECORD;
- DBUG_RETURN(-1);
- }
- info->s->state.dellink=block_info.next_filepos;
- info->s->state.del--;
- info->s->state.empty-= block_info.block_len;
- *length= block_info.block_len;
- }
- else
- {
- if (info->s->state.data_file_length > info->s->base.max_data_file_length)
- {
- my_errno=HA_ERR_RECORD_FILE_FULL;
- DBUG_RETURN(-1);
- }
- *filepos=info->s->state.data_file_length; /* New block last */
- if ((*length=reclength+3 + test(reclength > 65532)) <
- info->s->base.min_block_length)
- *length=info->s->base.min_block_length;
- info->s->state.data_file_length+= *length;
- info->s->state.splitt++;
- info->update|=HA_STATE_WRITE_AT_END;
- }
- DBUG_RETURN(0);
-} /* _nisam_find_writepos */
-
-
- /* Write a block to datafile */
-
-int _nisam_write_part_record(N_INFO *info,
- ulong filepos, /* points at empty block */
- uint length, /* length of block */
- ulong next_filepos, /* Next empty block */
- byte **record, /* pointer to record ptr */
- uint *reclength, /* length of *record */
- int *flag) /* *flag == 0 if header */
-{
- uint head_length,res_length,extra_length,long_block,del_length;
- byte *pos,*record_end;
- uchar temp[N_SPLITT_LENGTH+DYN_DELETE_BLOCK_HEADER];
- DBUG_ENTER("_nisam_write_part_record");
-
- res_length=extra_length=0;
- if (length > *reclength + N_SPLITT_LENGTH)
- { /* Splitt big block */
- res_length=length- *reclength - 3 - N_EXTEND_BLOCK_LENGTH;
- length-= res_length; /* Use this for first part */
- }
- long_block= (length < 65535L && *reclength < 65535L) ? 0 : 1;
- if (length-long_block == *reclength+3 || length == *reclength + 4)
- { /* Exact what we need */
- temp[0]=(uchar) (1+ *flag); /* 1, or 9 */
- if (long_block)
- {
- int3store(temp+1,*reclength);
- }
- else
- {
- int2store(temp+1,*reclength);
- }
- head_length=3+long_block;
- if (length-long_block == *reclength+4)
- {
- length--;
- temp[0]++; /* 2 or 10 */
- extra_length++; /* One empty */
- }
- }
- else if (length-long_block*2 < *reclength+5)
- { /* To short block */
- if (next_filepos == NI_POS_ERROR)
- next_filepos=info->s->state.dellink != NI_POS_ERROR ?
- info->s->state.dellink : info->s->state.data_file_length;
- if (*flag == 0) /* First block */
- {
- head_length=5+4+long_block*2;
- temp[0]=4;
- if (long_block)
- {
- int3store(temp+1,*reclength);
- int3store(temp+4,length-head_length);
- int4store((byte*) temp+7,next_filepos);
- }
- else
- {
- int2store(temp+1,*reclength);
- int2store(temp+3,length-head_length);
- int4store((byte*) temp+5,next_filepos);
- }
- }
- else
- {
- head_length=3+4+long_block;
- temp[0]=12;
- if (long_block)
- {
- int3store(temp+1,length-head_length);
- int4store((byte*) temp+4,next_filepos);
- }
- else
- {
- int2store(temp+1,length-head_length);
- int4store((byte*) temp+3,next_filepos);
- }
- }
- }
- else
- { /* Block with empty info last */
- head_length=5+long_block*2;
- temp[0]= (uchar) (3+ *flag); /* 3 or 11 */
- if (long_block)
- {
- int3store(temp+1,*reclength);
- int3store(temp+4,length-7);
- }
- else
- {
- int2store(temp+1,*reclength);
- int2store(temp+3,length-5);
- }
- extra_length= length- *reclength-head_length;
- length= *reclength+head_length; /* Write only what is needed */
- }
- temp[0]+=(uchar) (long_block*4);
- DBUG_DUMP("header",(byte*) temp,head_length);
-
- /* Make a long block for one write */
- record_end= *record+length-head_length;
- del_length=(res_length ? DYN_DELETE_BLOCK_HEADER : 0);
- bmove((byte*) (*record-head_length),(byte*) temp,head_length);
- memcpy(temp,record_end,(size_t) (extra_length+del_length));
- bzero((byte*) record_end,extra_length);
- if (res_length)
- {
- pos=record_end+extra_length;
- pos[0]= '\0';
- int3store(pos+1,res_length);
- int4store(pos+4,info->s->state.dellink);
- info->s->state.dellink= filepos+length+extra_length;
- info->s->state.del++;
- info->s->state.empty+=res_length;
- info->s->state.splitt++;
- }
- if (info->opt_flag & WRITE_CACHE_USED && info->update & HA_STATE_WRITE_AT_END)
- {
- if (my_b_write(&info->rec_cache,(byte*) *record-head_length,
- length+extra_length+del_length))
- goto err;
- }
- else
- {
- info->rec_cache.seek_not_done=1;
- if (my_pwrite(info->dfile,(byte*) *record-head_length,length+extra_length+
- del_length,filepos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
- goto err;
- }
- memcpy(record_end,temp,(size_t) (extra_length+del_length));
- *record=record_end;
- *reclength-=(length-head_length);
- *flag=8;
-
- DBUG_RETURN(0);
-err:
- DBUG_PRINT("exit",("errno: %d",my_errno));
- DBUG_RETURN(1);
-} /*_nisam_write_part_record */
-
-
- /* update record from datafile */
-
-static int update_dynamic_record(N_INFO *info, ulong filepos, byte *record, uint reclength)
-{
- int flag;
- uint error,length;
- BLOCK_INFO block_info;
- DBUG_ENTER("update_dynamic_record");
-
- flag=block_info.second_read=0;
- while (reclength > 0)
- {
- if (filepos != info->s->state.dellink)
- {
- block_info.next_filepos= NI_POS_ERROR;
- if ((error=_nisam_get_block_info(&block_info,info->dfile,filepos))
- & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
- BLOCK_FATAL_ERROR))
- {
- if (!(error & BLOCK_FATAL_ERROR))
- my_errno=HA_ERR_WRONG_IN_RECORD;
- goto err;
- }
- length=(uint) (block_info.filepos-filepos) + block_info.block_len;
- }
- else
- {
- if (_nisam_find_writepos(info,reclength,&filepos,&length))
- goto err;
- }
- if (_nisam_write_part_record(info,filepos,length,block_info.next_filepos,
- &record,&reclength,&flag))
- goto err;
- if ((filepos=block_info.next_filepos) == NI_POS_ERROR)
- filepos=info->s->state.dellink;
- }
-
- if (block_info.next_filepos != NI_POS_ERROR)
- if (delete_dynamic_record(info,block_info.next_filepos,1))
- goto err;
- DBUG_RETURN(0);
-err:
- DBUG_RETURN(1);
-}
-
- /* Delete datarecord from database */
- /* info->rec_cache.seek_not_done is updated in cmp_record */
-
-static int delete_dynamic_record(N_INFO *info, ulong filepos, uint second_read)
-{
- uint length,b_type;
- BLOCK_INFO block_info;
- DBUG_ENTER("delete_dynamic_record");
-
- block_info.second_read=second_read;
- do
- {
- if ((b_type=_nisam_get_block_info(&block_info,info->dfile,filepos))
- & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
- BLOCK_FATAL_ERROR) ||
- (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
- N_MIN_BLOCK_LENGTH)
- {
- my_errno=HA_ERR_WRONG_IN_RECORD;
- DBUG_RETURN(1);
- }
- block_info.header[0]=0;
- length=(uint) (block_info.filepos-filepos) +block_info.block_len;
- int3store(block_info.header+1,length);
- int4store(block_info.header+4,info->s->state.dellink);
- if (my_pwrite(info->dfile,(byte*) block_info.header,8,filepos,
- MYF(MY_NABP)))
- DBUG_RETURN(1);
- info->s->state.dellink = filepos;
- info->s->state.del++;
- info->s->state.empty+=length;
- filepos=block_info.next_filepos;
- } while (!(b_type & BLOCK_LAST));
- DBUG_RETURN(0);
-}
-
-
- /* Pack a record. Return new reclength */
-
-uint _nisam_rec_pack(N_INFO *info, register byte *to, register const byte *from)
-{
- uint length,new_length,flag,bit,i;
- char *pos,*end,*startpos,*packpos;
- enum en_fieldtype type;
- reg3 N_RECINFO *rec;
- N_BLOB *blob;
- DBUG_ENTER("_nisam_rec_pack");
-
- flag=0 ; bit=1;
- startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
- rec=info->s->rec;
-
- for (i=info->s->base.fields ; i-- > 0; from+= (rec++)->base.length)
- {
- length=(uint) rec->base.length;
- if ((type = (enum en_fieldtype) rec->base.type) != FIELD_NORMAL)
- {
- if (type == FIELD_BLOB)
- {
- if (!blob->length)
- flag|=bit;
- else
- {
- char *temp_pos;
- memcpy((byte*) to,from,(size_t) length);
- memcpy_fixed(&temp_pos,from+length,sizeof(char*));
- memcpy(to+length,temp_pos,(size_t) blob->length);
- to+=length+blob->length;
- }
- blob++;
- from+=sizeof(char*); /* Skip blob-pointer */
- }
- else if (type == FIELD_SKIP_ZERO)
- {
- if (memcmp((byte*) from,zero_string,length) == 0)
- flag|=bit;
- else
- {
- memcpy((byte*) to,from,(size_t) length); to+=length;
- }
- }
- else if (type == FIELD_SKIP_ENDSPACE ||
- type == FIELD_SKIP_PRESPACE)
- {
- pos= (byte*) from; end= (byte*) from + length;
- if (type == FIELD_SKIP_ENDSPACE)
- { /* Pack trailing spaces */
- while (end > from && *(end-1) == ' ')
- end--;
- }
- else
- { /* Pack pref-spaces */
- while (pos < end && *pos == ' ')
- pos++;
- }
- new_length=(uint) (end-pos);
- if (new_length +1 + test(rec->base.length > 255 && new_length > 127)
- < length)
- {
- if (rec->base.length > 255 && new_length > 127)
- {
- to[0]=(char) ((new_length & 127)+128);
- to[1]=(char) (new_length >> 7);
- to+=2;
- }
- else
- *to++= (char) new_length;
- memcpy((byte*) to,pos,(size_t) new_length); to+=new_length;
- flag|=bit;
- }
- else
- {
- memcpy(to,from,(size_t) length); to+=length;
- }
- }
- else if (type == FIELD_ZERO)
- continue; /* Don't store this */
- else
- {
- memcpy(to,from,(size_t) length); to+=length;
- continue; /* Normal field */
- }
- if ((bit= bit << 1) >= 256)
- {
- *packpos++ = (char) (uchar) flag;
- bit=1; flag=0;
- }
- }
- else
- {
- memcpy(to,from,(size_t) length); to+=length;
- }
- }
- if (bit != 1)
- *packpos= (char) (uchar) flag;
- DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
- DBUG_RETURN((uint) (to-startpos));
-} /* _nisam_rec_pack */
-
-
-
-/*
-** Check if a record was correctly packed. Used only by isamchk
-** Returns 0 if record is ok.
-*/
-
-my_bool _nisam_rec_check(N_INFO *info,const char *from)
-{
- uint length,new_length,flag,bit,i;
- char *pos,*end,*packpos,*to;
- enum en_fieldtype type;
- reg3 N_RECINFO *rec;
- DBUG_ENTER("_nisam_rec_check");
-
- packpos=info->rec_buff; to= info->rec_buff+info->s->base.pack_bits;
- rec=info->s->rec;
- flag= *packpos; bit=1;
-
- for (i=info->s->base.fields ; i-- > 0; from+= (rec++)->base.length)
- {
- length=(uint) rec->base.length;
- if ((type = (enum en_fieldtype) rec->base.type) != FIELD_NORMAL)
- {
- if (type == FIELD_BLOB)
- {
- uint blob_length= _calc_blob_length(length,from);
- if (!blob_length && !(flag & bit))
- goto err;
- if (blob_length)
- to+=length+ blob_length;
- from+=sizeof(char*);
- }
- else if (type == FIELD_SKIP_ZERO)
- {
- if (memcmp((byte*) from,zero_string,length) == 0)
- {
- if (!(flag & bit))
- goto err;
- }
- else
- to+=length;
- }
- else if (type == FIELD_SKIP_ENDSPACE ||
- type == FIELD_SKIP_PRESPACE)
- {
- pos= (byte*) from; end= (byte*) from + length;
- if (type == FIELD_SKIP_ENDSPACE)
- { /* Pack trailing spaces */
- while (end > from && *(end-1) == ' ')
- end--;
- }
- else
- { /* Pack pre-spaces */
- while (pos < end && *pos == ' ')
- pos++;
- }
- new_length=(uint) (end-pos);
- if (new_length +1 + test(rec->base.length > 255 && new_length > 127)
- < length)
- {
- if (!(flag & bit))
- goto err;
- if (rec->base.length > 255 && new_length > 127)
- {
- if (to[0] != (char) ((new_length & 127)+128) ||
- to[1] != (char) (new_length >> 7))
- goto err;
- to+=2;
- }
- else if (*to++ != (char) new_length)
- goto err;
- to+=new_length;
- }
- else
- to+=length;
- }
- else
- {
- if (type != FIELD_ZERO)
- to+=length; /* Not packed field */
- continue;
- }
- if ((bit= bit << 1) >= 256)
- {
- flag= *++packpos;
- bit=1;
- }
- }
- else
- {
- to+=length;
- }
- }
- if (bit != 1)
- *packpos= (char) (uchar) flag;
- if (info->packed_length == (uint) (to - info->rec_buff) &&
- (bit == 1 || !(flag & ~(bit - 1))))
- DBUG_RETURN(0);
-
- err:
- DBUG_RETURN(1);
-}
-
-
-
- /* Unpacks a record */
- /* Returns -1 and my_errno =HA_ERR_RECORD_DELETED if reclength isn't */
- /* right. Returns reclength (>0) if ok */
-
-uint _nisam_rec_unpack(register N_INFO *info, register byte *to, byte *from,
- uint found_length)
-{
- uint flag,bit,length,rec_length,min_pack_length;
- enum en_fieldtype type;
- byte *from_end,*to_end,*packpos;
- reg3 N_RECINFO *rec,*end_field;
- DBUG_ENTER("_nisam_rec_unpack");
-
- to_end=to + info->s->base.reclength;
- from_end=from+found_length;
- flag= (uchar) *from; bit=1; packpos=from;
- if (found_length < info->s->base.min_pack_length)
- goto err;
- from+= info->s->base.pack_bits;
- min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
-
- for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
- rec < end_field ; to+= rec_length, rec++)
- {
- rec_length=rec->base.length;
- if ((type = (enum en_fieldtype) rec->base.type) != FIELD_NORMAL)
- {
- if (type == FIELD_ZERO)
- continue; /* Skip this */
- if (flag & bit)
- {
- if (type == FIELD_BLOB)
- {
- bzero((byte*) to,rec_length+sizeof(char*));
- to+=sizeof(char*);
- }
- else if (type == FIELD_SKIP_ZERO)
- bzero((byte*) to,rec_length);
- else if (type == FIELD_SKIP_ENDSPACE ||
- type == FIELD_SKIP_PRESPACE)
- {
- if (rec->base.length > 255 && *from & 128)
- {
- if (from + 1 >= from_end)
- goto err;
- length= (*from & 127)+ ((uint) (uchar) *(from+1) << 7); from+=2;
- }
- else
- {
- if (from == from_end)
- goto err;
- length= (uchar) *from++;
- }
- min_pack_length--;
- if (length >= rec_length ||
- min_pack_length + length > (uint) (from_end - from))
- goto err;
- if (type == FIELD_SKIP_ENDSPACE)
- {
- memcpy(to,(byte*) from,(size_t) length);
- bfill((byte*) to+length,rec_length-length,' ');
- }
- else
- {
- bfill((byte*) to,rec_length-length,' ');
- memcpy(to+rec_length-length,(byte*) from,(size_t) length);
- }
- from+=length;
- }
- }
- else if (type == FIELD_BLOB)
- {
- ulong blob_length=_calc_blob_length(rec_length,from);
- if ((ulong) (from_end-from) - rec_length < blob_length ||
- min_pack_length > (uint) (from_end -(from+rec_length+blob_length)))
- goto err;
- memcpy((byte*) to,(byte*) from,(size_t) rec_length);
- from+=rec_length;
- /* memcpy crasches alpha egcs 1.1.2 */
- bmove((byte*) to+rec_length,(byte*) &from,sizeof(char*));
- from+=blob_length;
- to+=sizeof(char*);
- }
- else
- {
- if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
- min_pack_length--;
- if (min_pack_length + rec_length > (uint) (from_end - from))
- goto err;
- memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
- }
- if ((bit= bit << 1) >= 256)
- {
- flag= (uchar) *++packpos; bit=1;
- }
- }
- else
- {
- if (min_pack_length > (uint) (from_end - from))
- goto err;
- min_pack_length-=rec_length;
- memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
- }
- }
- if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
- DBUG_RETURN((info->packed_length=found_length));
- err:
- my_errno=HA_ERR_RECORD_DELETED;
- DBUG_PRINT("error",("to_end: %lx -> %lx from_end: %lx -> %lx",
- to,to_end,from,from_end));
- DBUG_DUMP("from",(byte*) info->rec_buff,info->s->base.min_pack_length);
- DBUG_RETURN(MY_FILE_ERROR);
-} /* _nisam_rec_unpack */
-
-
- /* Calc length of blob. Update info in blobs->length */
-
-uint _calc_total_blob_length(N_INFO *info, const byte *record)
-{
- uint i,length;
- N_BLOB *blob;
-
- for (i=length=0, blob= info->blobs; i++ < info->s->base.blobs ; blob++)
- {
- blob->length=_calc_blob_length(blob->pack_length,record + blob->offset);
- length+=blob->length;
- }
- return length;
-}
-
-
-uint _calc_blob_length(uint length, const byte *pos)
-{
- switch (length) {
- case 1:
- return (uint) (uchar) *pos;
- case 2:
- {
- short j; shortget(j,pos);
- return (uint) (unsigned short) j;
- }
-#ifdef MSDOS
- break; /* skip microsoft warning */
-#endif
- case 3:
- return uint3korr(pos);
- case 4:
- {
- long j; longget(j,pos);
- return (uint) j;
- }
-#ifdef MSDOS
- break;
-#endif
- default:
- break;
- }
- return 0; /* Impossible */
-}
-
- /* Read record from datafile */
- /* Returns 0 if ok, -1 if error */
-
-int _nisam_read_dynamic_record(N_INFO *info, ulong filepos, byte *buf)
-{
- int flag;
- uint b_type,left_length;
- byte *to;
- BLOCK_INFO block_info;
- File file;
- DBUG_ENTER("ni_read_dynamic_record");
-
- if (filepos != NI_POS_ERROR)
- {
- LINT_INIT(to);
- LINT_INIT(left_length);
- file=info->dfile;
- block_info.next_filepos=filepos; /* for easyer loop */
- flag=block_info.second_read=0;
- do
- {
- if (info->opt_flag & WRITE_CACHE_USED &&
- info->rec_cache.pos_in_file <= block_info.next_filepos &&
- flush_io_cache(&info->rec_cache))
- goto err;
- info->rec_cache.seek_not_done=1;
- if ((b_type=_nisam_get_block_info(&block_info,file,
- block_info.next_filepos))
- & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
- BLOCK_FATAL_ERROR))
- {
- if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
- my_errno=HA_ERR_RECORD_DELETED;
- goto err;
- }
- if (flag == 0) /* First block */
- {
- flag=1;
- if (block_info.rec_len > (uint) info->s->base.max_pack_length)
- goto panic;
- if (info->s->base.blobs)
- {
- if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
- goto err;
- }
- else
- to= info->rec_buff;
- left_length=block_info.rec_len;
- }
- if (left_length < block_info.data_len || ! block_info.data_len)
- goto panic; /* Wrong linked record */
- if (my_pread(file,(byte*) to,block_info.data_len,block_info.filepos,
- MYF(MY_NABP)))
- goto panic;
- left_length-=block_info.data_len;
- to+=block_info.data_len;
- } while (left_length);
-
- info->update|= HA_STATE_AKTIV; /* We have a aktive record */
- VOID(_nisam_writeinfo(info,0));
- DBUG_RETURN(_nisam_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
- MY_FILE_ERROR ? 0 : -1);
- }
- VOID(_nisam_writeinfo(info,0));
- DBUG_RETURN(-1); /* Wrong data to read */
-
-panic:
- my_errno=HA_ERR_WRONG_IN_RECORD;
-err:
- VOID(_nisam_writeinfo(info,0));
- DBUG_RETURN(-1);
-}
-
-
-byte *fix_rec_buff_for_blob(N_INFO *info, uint length)
-{
- uint extra;
- if (! info->rec_buff || length > info->alloced_rec_buff_length)
- {
- byte *newptr;
- extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
- DYN_DELETE_BLOCK_HEADER;
- if (!(newptr=(byte*) my_realloc((gptr) info->rec_alloc,length+extra,
- MYF(MY_ALLOW_ZERO_PTR))))
- return newptr;
- info->rec_alloc=newptr;
- info->rec_buff=newptr+ALIGN_SIZE(DYN_DELETE_BLOCK_HEADER);
- info->alloced_rec_buff_length=length;
- }
- return info->rec_buff;
-}
-
-
- /* Compare of record one disk with packed record in memory */
-
-int _nisam_cmp_dynamic_record(register N_INFO *info, register const byte *record)
-{
- uint flag,reclength,b_type;
- ulong filepos;
- byte *buffer;
- BLOCK_INFO block_info;
- DBUG_ENTER("_nisam_cmp_dynamic_record");
-
- /* We are going to do changes; dont let anybody disturb */
- dont_break(); /* Dont allow SIGHUP or SIGINT */
-
- if (info->opt_flag & WRITE_CACHE_USED)
- {
- info->update&= ~HA_STATE_WRITE_AT_END;
- if (flush_io_cache(&info->rec_cache))
- DBUG_RETURN(-1);
- }
- info->rec_cache.seek_not_done=1;
-
- /* If nobody have touched the database we don't have to test rec */
-
- buffer=info->rec_buff;
- if ((info->opt_flag & READ_CHECK_USED))
- { /* If check isn't disabled */
- if (info->s->base.blobs)
- {
- if (!(buffer=(byte*) my_alloca(info->s->base.pack_reclength+
- _calc_total_blob_length(info,record))))
- DBUG_RETURN(-1);
- }
- reclength=_nisam_rec_pack(info,buffer,record);
- record= buffer;
-
- filepos=info->lastpos;
- flag=block_info.second_read=0;
- block_info.next_filepos=filepos;
- while (reclength > 0)
- {
- if ((b_type=_nisam_get_block_info(&block_info,info->dfile,
- block_info.next_filepos))
- & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
- BLOCK_FATAL_ERROR))
- {
- if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
- my_errno=HA_ERR_RECORD_CHANGED;
- goto err;
- }
- if (flag == 0) /* First block */
- {
- flag=1;
- if (reclength != block_info.rec_len)
- {
- my_errno=HA_ERR_RECORD_CHANGED;
- goto err;
- }
- } else if (reclength < block_info.data_len)
- {
- my_errno=HA_ERR_WRONG_IN_RECORD;
- goto err;
- }
- reclength-=block_info.data_len;
- if (_nisam_cmp_buffer(info->dfile,record,block_info.filepos,
- block_info.data_len))
- {
- my_errno=HA_ERR_RECORD_CHANGED;
- goto err;
- }
- flag=1;
- record+=block_info.data_len;
- }
- }
- my_errno=0;
- err:
- if (buffer != info->rec_buff)
- my_afree((gptr) buffer);
- DBUG_RETURN(my_errno);
-}
-
-
- /* Compare file to buffert */
-
-static int _nisam_cmp_buffer(File file, const byte *buff, ulong filepos, uint length)
-{
- uint next_length;
- char temp_buff[IO_SIZE*2];
- DBUG_ENTER("_nisam_cmp_buffer");
-
- VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
- next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
-
- while (length > IO_SIZE*2)
- {
- if (my_read(file,temp_buff,next_length,MYF(MY_NABP)))
- goto err;
- if (memcmp((byte*) buff,temp_buff,next_length))
- DBUG_RETURN(1);
- buff+=next_length;
- length-= next_length;
- next_length=IO_SIZE*2;
- }
- if (my_read(file,temp_buff,length,MYF(MY_NABP)))
- goto err;
- DBUG_RETURN(memcmp((byte*) buff,temp_buff,length));
-err:
- DBUG_RETURN(1);
-}
-
-
-int _nisam_read_rnd_dynamic_record(N_INFO *info, byte *buf, register ulong filepos, int skipp_deleted_blocks)
-{
- int flag,info_read,fatal_errcode;
- uint left_len,b_type;
- byte *to;
- BLOCK_INFO block_info;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("_nisam_read_rnd_dynamic_record");
-
- info_read=0;
- fatal_errcode= -1;
- LINT_INIT(to);
-
-#ifndef NO_LOCKING
- if (info->lock_type == F_UNLCK)
- {
-#ifndef UNSAFE_LOCKING
- if (share->r_locks == 0 && share->w_locks == 0)
- {
- if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
- MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
- DBUG_RETURN(fatal_errcode);
- }
-#else
- info->tmp_lock_type=F_RDLCK;
-#endif
- }
- else
- info_read=1; /* memory-keyinfoblock is ok */
-#endif /* !NO_LOCKING */
-
- flag=block_info.second_read=0;
- left_len=1;
- do
- {
- if (filepos >= share->state.data_file_length)
- {
-#ifndef NO_LOCKING
- if (!info_read)
- { /* Check if changed */
- info_read=1;
- info->rec_cache.seek_not_done=1;
- if (my_pread(share->kfile,(char*) &share->state.header,
- share->state_length, 0L,MYF(MY_NABP)))
- goto err;
- }
- if (filepos >= share->state.data_file_length)
-#endif
- {
- my_errno= HA_ERR_END_OF_FILE;
- goto err;
- }
- }
- if (info->opt_flag & READ_CACHE_USED)
- {
- if (_nisam_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
- sizeof(block_info.header),
- test(!flag && skipp_deleted_blocks) | 2))
- goto err;
- b_type=_nisam_get_block_info(&block_info,-1,filepos);
- }
- else
- {
- if (info->opt_flag & WRITE_CACHE_USED &&
- info->rec_cache.pos_in_file <= filepos &&
- flush_io_cache(&info->rec_cache))
- DBUG_RETURN(-1);
- info->rec_cache.seek_not_done=1;
- b_type=_nisam_get_block_info(&block_info,info->dfile,filepos);
- }
-
- if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
- BLOCK_FATAL_ERROR))
- {
- if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
- && skipp_deleted_blocks)
- {
- filepos=block_info.filepos+block_info.block_len;
- block_info.second_read=0;
- continue; /* Search after next_record */
- }
- if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
- {
- my_errno=HA_ERR_RECORD_DELETED;
- info->lastpos=block_info.filepos;
- info->nextpos=block_info.filepos+block_info.block_len;
- fatal_errcode=1;
- }
- goto err;
- }
- if (flag == 0) /* First block */
- {
- if (block_info.rec_len > (uint) share->base.max_pack_length)
- goto panic;
- info->lastpos=filepos;
- if (share->base.blobs)
- {
- if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
- goto err;
- }
- else
- to= info->rec_buff;
- left_len=block_info.rec_len;
- }
- if (left_len < block_info.data_len)
- goto panic; /* Wrong linked record */
-
- if (info->opt_flag & READ_CACHE_USED)
- {
- if (_nisam_read_cache(&info->rec_cache,(byte*) to,block_info.filepos,
- block_info.data_len,
- test(!flag && skipp_deleted_blocks)))
- goto err;
- }
- else
- {
- VOID(my_seek(info->dfile,block_info.filepos,MY_SEEK_SET,MYF(0)));
- if (my_read(info->dfile,(byte*) to,block_info.data_len,MYF(MY_NABP)))
- goto err;
- }
- if (flag++ == 0)
- {
- info->nextpos=block_info.filepos+block_info.block_len;
- skipp_deleted_blocks=0;
- }
- left_len-=block_info.data_len;
- to+=block_info.data_len;
- filepos=block_info.next_filepos;
- } while (left_len);
-
- info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
- VOID(_nisam_writeinfo(info,0));
- if (_nisam_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
- MY_FILE_ERROR)
- DBUG_RETURN(0);
- DBUG_RETURN(fatal_errcode); /* Wrong record */
-
-panic:
- my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
-err:
- VOID(_nisam_writeinfo(info,0));
- DBUG_RETURN(fatal_errcode);
-}
-
-
- /* Read and process header from a dynamic-record-file */
-
-uint _nisam_get_block_info(BLOCK_INFO *info, File file, ulong filepos)
-{
- uint return_val=0,length;
- uchar *header=info->header;
-
- if (file >= 0)
- {
- VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
- if ((length=my_read(file,(char*) header,BLOCK_INFO_HEADER_LENGTH,MYF(0)))
- == MY_FILE_ERROR)
- return BLOCK_FATAL_ERROR;
- if (length != BLOCK_INFO_HEADER_LENGTH)
- { /* Test if short block */
- if (length < 3)
- {
- my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */
- return BLOCK_FATAL_ERROR;
- }
- bzero((byte*) header+length,BLOCK_INFO_HEADER_LENGTH-length);
- }
- }
- DBUG_DUMP("header",(byte*) header,BLOCK_INFO_HEADER_LENGTH);
- if (info->second_read)
- {
- if (info->header[0] <= 8)
- return_val=BLOCK_SYNC_ERROR;
- }
- else
- {
- if (info->header[0] > 8)
- return_val=BLOCK_SYNC_ERROR;
- }
- info->next_filepos= (ulong) NI_POS_ERROR; /* Dummy ifall no next block */
-
- switch (info->header[0]) {
- case 0:
- if ((info->block_len=(uint) uint3korr(header+1)) < N_MIN_BLOCK_LENGTH)
- return BLOCK_FATAL_ERROR;
- info->filepos=filepos;
- info->next_filepos=uint4korr(header+4);
- if (info->next_filepos == (uint32) ~0) /* Fix for 64 bit long */
- info->next_filepos=NI_POS_ERROR;
- return return_val | BLOCK_DELETED; /* Deleted block */
- case 1:
- info->rec_len=info->data_len=info->block_len=uint2korr(header+1);
- info->filepos=filepos+3;
- return return_val | BLOCK_FIRST | BLOCK_LAST;
- case 2:
- info->block_len=(info->rec_len=info->data_len=uint2korr(header+1))+1;
- info->filepos=filepos+3;
- return return_val | BLOCK_FIRST | BLOCK_LAST;
- case 3:
- info->rec_len=info->data_len=uint2korr(header+1);
- info->block_len=uint2korr(header+3);
- info->filepos=filepos+5;
- return return_val | BLOCK_FIRST | BLOCK_LAST;
- case 4:
- info->rec_len=uint2korr(header+1);
- info->block_len=info->data_len=uint2korr(header+3);
- info->next_filepos=uint4korr(header+5);
- info->second_read=1;
- info->filepos=filepos+9;
- return return_val | BLOCK_FIRST;
-#if defined(_MSC_VER) || !defined(__WIN__)
- case 5:
- info->rec_len=info->data_len=info->block_len=uint3korr(header+1);
- info->filepos=filepos+4;
- return return_val | BLOCK_FIRST | BLOCK_LAST;
- case 6:
- info->block_len=(info->rec_len=info->data_len=uint3korr(header+1))+1;
- info->filepos=filepos+4;
- return return_val | BLOCK_FIRST | BLOCK_LAST;
- case 7:
- info->rec_len=info->data_len=uint3korr(header+1);
- info->block_len=uint3korr(header+4);
- info->filepos=filepos+7;
- return return_val | BLOCK_FIRST | BLOCK_LAST;
- case 8:
- info->rec_len=uint3korr(header+1);
- info->block_len=info->data_len=uint3korr(header+4);
- info->next_filepos=uint4korr(header+7);
- info->second_read=1;
- info->filepos=filepos+11;
- return return_val | BLOCK_FIRST;
-#endif
- case 9:
- info->data_len=info->block_len=uint2korr(header+1);
- info->filepos=filepos+3;
- return return_val | BLOCK_LAST;
- case 10:
- info->block_len=(info->data_len=uint2korr(header+1))+1;
- info->filepos=filepos+3;
- return return_val | BLOCK_LAST;
- case 11:
- info->data_len=uint2korr(header+1);
- info->block_len=uint2korr(header+3);
- info->filepos=filepos+5;
- return return_val | BLOCK_LAST;
- case 12:
- info->data_len=info->block_len=uint2korr(header+1);
- info->next_filepos=uint4korr(header+3);
- info->second_read=1;
- info->filepos=filepos+7;
- return return_val;
-#if defined(_MSC_VER) || !defined(__WIN__)
- case 13:
- info->data_len=info->block_len=uint3korr(header+1);
- info->filepos=filepos+4;
- return return_val | BLOCK_LAST;
- case 14:
- info->block_len=(info->data_len=uint3korr(header+1))+1;
- info->filepos=filepos+4;
- return return_val | BLOCK_LAST;
- case 15:
- info->data_len=uint3korr(header+1);
- info->block_len=uint3korr(header+4);
- info->filepos=filepos+7;
- return return_val | BLOCK_LAST;
- case 16:
- info->data_len=info->block_len=uint3korr(header+1);
- info->next_filepos=uint4korr(header+4);
- info->second_read=1;
- info->filepos=filepos+8;
- return return_val;
-#endif
- default:
- my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */
- return BLOCK_ERROR;
- }
-}
diff --git a/isam/_key.c b/isam/_key.c
deleted file mode 100644
index 65d6885869e..00000000000
--- a/isam/_key.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Functions to handle keys */
-
-#include "isamdef.h"
-#include "m_ctype.h"
-
-static void _nisam_put_key_in_record(N_INFO *info,uint keynr,byte *record);
-
- /* Make a intern key from a record */
- /* If ascii key convert according to sortorder */
- /* Ret: Length of key */
-
-uint _nisam_make_key(register N_INFO *info, uint keynr, uchar *key, const char *record, ulong filepos)
-{
- uint length;
- byte *pos,*end;
- uchar *start;
- reg1 N_KEYSEG *keyseg;
- enum ha_base_keytype type;
- DBUG_ENTER("_nisam_make_key");
-
- start=key;
- for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->base.type ;keyseg++)
- {
- type=(enum ha_base_keytype) keyseg->base.type;
- if (keyseg->base.flag & HA_SPACE_PACK)
- {
- pos= (byte*) record+keyseg->base.start; end=pos+keyseg->base.length;
- if (type != HA_KEYTYPE_NUM)
- {
- while (end > pos && end[-1] == ' ')
- end--;
- }
- else
- {
- while (pos < end && pos[0] == ' ')
- pos++;
- }
- *key++= (uchar) (length=(uint) (end-pos));
- memcpy((byte*) key,(byte*) pos,(size_t) length);
- if (!use_strnxfrm(default_charset_info))
- {
- if (type == HA_KEYTYPE_TEXT)
- my_strnxfrm(default_charset_info,(uchar*) key, length,
- (uchar*) key, length);
- }
- key+=length;
- }
- else
- {
- memcpy((byte*) key,(byte*) record+keyseg->base.start,
- (size_t) keyseg->base.length);
- if (!use_strnxfrm(default_charset_info))
- {
- if (type == HA_KEYTYPE_TEXT)
- my_strnxfrm(default_charset_info,(uchar*) key,
- (uint) keyseg->base.length,
- (uchar*) key,
- (uint) keyseg->base.length);
- }
-#ifdef NAN_TEST
- else if (type == HA_KEYTYPE_FLOAT)
- {
- float nr;
- bmove((byte*) &nr,(byte*) key,sizeof(float));
- if (nr == (float) FLT_MAX)
- {
- nr= (float) FLT_MAX;
- bmove((byte*) key,(byte*) &nr,sizeof(float));
- }
- }
- else if (type == HA_KEYTYPE_DOUBLE)
- {
- double nr;
- bmove((byte*) &nr,(byte*) key,sizeof(double));
- if (nr == DBL_MAX)
- {
- nr=DBL_MAX;
- bmove((byte*) key,(byte*) &nr,sizeof(double));
- }
- }
-#endif
- key+= keyseg->base.length;
- }
- }
- _nisam_dpointer(info,key,filepos);
- DBUG_PRINT("exit",("keynr: %d",keynr));
- DBUG_DUMP("key",(byte*) start,(uint) (key-start)+keyseg->base.length);
- DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,info->s->keyinfo[keynr].seg,start););
- DBUG_RETURN((uint) (key-start)); /* Return keylength */
-} /* _nisam_make_key */
-
-
- /* Pack a key to intern format from given format (c_rkey) */
- /* if key_length is set returns new length of key */
-
-uint _nisam_pack_key(register N_INFO *info, uint keynr, uchar *key, uchar *old, uint key_length)
-
-
-
- /* Length of used key */
-{
- int k_length;
- uint length;
- uchar *pos,*end;
- reg1 N_KEYSEG *keyseg;
- enum ha_base_keytype type;
- DBUG_ENTER("_nisam_pack_key");
-
- if ((k_length=(int) key_length) <= 0)
- k_length=N_MAX_KEY_BUFF;
-
- for (keyseg=info->s->keyinfo[keynr].seg ;
- keyseg->base.type && k_length >0;
- k_length-=keyseg->base.length, old+=keyseg->base.length, keyseg++)
- {
- length=min((uint) keyseg->base.length,(uint) k_length);
- type=(enum ha_base_keytype) keyseg->base.type;
- if (keyseg->base.flag & HA_SPACE_PACK)
- {
- pos=old; end=pos+length;
- if (type != HA_KEYTYPE_NUM)
- {
- while (end > pos && end[-1] == ' ')
- end--;
- }
- else
- {
- while (pos < end && pos[0] == ' ')
- pos++;
- }
- *key++ = (uchar) (length=(uint) (end-pos));
- memcpy((byte*) key,pos,(size_t) length);
- }
- else
- memcpy((byte*) key,old,(size_t) length);
- if (!use_strnxfrm(default_charset_info))
- {
- if (type == HA_KEYTYPE_TEXT)
- my_strnxfrm(default_charset_info,(uchar*) key,length,
- (uchar*) key,length);
- }
- key+= length;
- }
- if (!keyseg->base.type)
- {
- if (k_length >= 0) /* Hole key */
- key_length=0;
- }
- else
- { /* Part-key ; fill with null */
- length= (uint) -k_length; /* unused part of last key */
- do
- {
- length+= (keyseg->base.flag & HA_SPACE_PACK) ? 1 :
- keyseg->base.length;
- keyseg++;
- } while (keyseg->base.type);
- bzero((byte*) key,length);
- }
- DBUG_RETURN(key_length); /* Return part-keylength */
-} /* _nisam_pack_key */
-
-
- /* Put a key in record */
- /* Used when only-keyread is wanted */
-
-static void _nisam_put_key_in_record(register N_INFO *info, uint keynr, byte *record)
-{
- uint length;
- reg2 byte *key;
- byte *pos;
- reg1 N_KEYSEG *keyseg;
- DBUG_ENTER("_nisam_put_key_in_record");
-
- key=(byte*) info->lastkey;
- for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->base.type ;keyseg++)
- {
- if (keyseg->base.flag & HA_SPACE_PACK)
- {
- length= (uint) (uchar) *key++;
- pos= record+keyseg->base.start;
- if (keyseg->base.type != (int) HA_KEYTYPE_NUM)
- {
- memcpy(pos,key,(size_t) length);
- bfill(pos+length,keyseg->base.length-length,' ');
- }
- else
- {
- bfill(pos,keyseg->base.length-length,' ');
- memcpy(pos+keyseg->base.length-length,key,(size_t) length);
- }
- key+=length;
- }
- else
- {
- memcpy(record+keyseg->base.start,(byte*) key,
- (size_t) keyseg->base.length);
- key+= keyseg->base.length;
- }
- }
- DBUG_VOID_RETURN;
-} /* _nisam_put_key_in_record */
-
-
- /* Here when key reads are used */
-
-int _nisam_read_key_record(N_INFO *info, ulong filepos, byte *buf)
-{
- VOID(_nisam_writeinfo(info,0));
- if (filepos != NI_POS_ERROR)
- {
- if (info->lastinx >= 0)
- { /* Read only key */
- _nisam_put_key_in_record(info,(uint) info->lastinx,buf);
- info->update|= HA_STATE_AKTIV; /* We should find a record */
- return 0;
- }
- my_errno=HA_ERR_WRONG_INDEX;
- return(-1);
- }
- return(-1); /* Wrong data to read */
-}
diff --git a/isam/_locking.c b/isam/_locking.c
deleted file mode 100644
index e19804549e5..00000000000
--- a/isam/_locking.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- locking of isam-tables.
- reads info from a isam-table. Must be first request before doing any furter
- calls to any isamfunktion. Is used to allow many process use the same
- isamdatabase.
- */
-
-#include "isamdef.h"
-#ifdef __WIN__
-#include <errno.h>
-#endif
-
- /* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
-
-int nisam_lock_database(N_INFO *info, int lock_type)
-{
- int error;
- uint count;
- ISAM_SHARE *share;
- uint flag;
- DBUG_ENTER("nisam_lock_database");
-
- flag=error=0;
-#ifndef NO_LOCKING
- share=info->s;
- if (share->base.options & HA_OPTION_READ_ONLY_DATA ||
- info->lock_type == lock_type)
- DBUG_RETURN(0);
- pthread_mutex_lock(&share->intern_lock);
- switch (lock_type) {
- case F_UNLCK:
- if (info->lock_type == F_RDLCK)
- count= --share->r_locks;
- else
- count= --share->w_locks;
- if (info->lock_type == F_WRLCK && !share->w_locks &&
- flush_key_blocks(dflt_key_cache,share->kfile,FLUSH_KEEP))
- error=my_errno;
- if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
- if (end_io_cache(&info->rec_cache))
- error=my_errno;
-
- if (!count)
- {
- if (share->changed && !share->w_locks)
- {
- share->state.process= share->last_process=share->this_process;
- share->state.loop= info->last_loop= ++info->this_loop;
- share->state.uniq= info->last_uniq= info->this_uniq;
- if (my_pwrite(share->kfile,(char*) &share->state.header,
- share->state_length,0L,MYF(MY_NABP)))
- error=my_errno;
- share->changed=0;
-#ifdef __WIN__
- if (nisam_flush)
- {
- _commit(share->kfile);
- _commit(info->dfile);
- }
- else
- share->not_flushed=1;
-#endif
- }
- if (share->r_locks)
- { /* Only read locks left */
- flag=1;
- if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
- MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
- error=my_errno;
- }
- else if (!share->w_locks)
- { /* No more locks */
- flag=1;
- if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
- MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
- error=my_errno;
- }
- }
- info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
- info->lock_type= F_UNLCK;
- break;
- case F_RDLCK:
- if (info->lock_type == F_WRLCK)
- { /* Change RW to READONLY */
- if (share->w_locks == 1)
- {
- flag=1;
- if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
- MYF(MY_SEEK_NOT_DONE)))
- {
- error=my_errno;
- break;
- }
- }
- share->w_locks--;
- share->r_locks++;
- info->lock_type=lock_type;
- break;
- }
- if (!share->r_locks && !share->w_locks)
- {
- flag=1;
-#ifdef HAVE_FCNTL
- if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
- {
- error=my_errno;
- break;
- }
- if (my_pread(share->kfile,
- (char*) &share->state.header,share->state_length,0L,
- MYF(MY_NABP)))
- {
- error=my_errno;
- VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
- my_errno=error;
- break;
- }
-#else
- VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
- if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
- {
- error=my_errno;
- break;
- }
- if (my_read(share->kfile,
- (char*) &share->state.header,share->state_length,
- MYF(MY_NABP)))
- {
- error=my_errno;
- VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,info->lock_wait));
- my_errno=error;
- break;
- }
-#endif
- }
- VOID(_nisam_test_if_changed(info));
- share->r_locks++;
- info->lock_type=lock_type;
- break;
- case F_WRLCK:
- if (info->lock_type == F_RDLCK)
- { /* Change RW to READONLY */
- if (share->r_locks == 1)
- {
- flag=1;
- if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
- MYF(info->lock_wait | MY_SEEK_NOT_DONE)))
- {
- error=my_errno;
- break;
- }
- share->r_locks--;
- share->w_locks++;
- info->lock_type=lock_type;
- break;
- }
- }
- if (!(share->base.options & HA_OPTION_READ_ONLY_DATA) && !share->w_locks)
- {
- flag=1;
- VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
- if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
- {
- error=my_errno;
- break;
- }
- if (!share->r_locks)
- {
- if (my_read(share->kfile,
- (char*) &share->state.header,share->state_length,
- MYF(MY_NABP)))
- {
- error=my_errno;
- VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,info->lock_wait));
- my_errno=error;
- break;
- }
- }
- }
- VOID(_nisam_test_if_changed(info));
- info->lock_type=lock_type;
- share->w_locks++;
- break;
- default:
- break; /* Impossible */
- }
- pthread_mutex_unlock(&share->intern_lock);
-#if defined(FULL_LOG) || defined(_lint)
- lock_type|=(int) (flag << 8); /* Set bit to set if real lock */
- nisam_log_command(LOG_LOCK,info,(byte*) &lock_type,sizeof(lock_type),
- error);
-#endif
-#endif
- DBUG_RETURN(error);
-} /* nisam_lock_database */
-
-
- /* Is used before access to database is granted */
-
-int _nisam_readinfo(register N_INFO *info, int lock_type, int check_keybuffer)
-{
- ISAM_SHARE *share;
- DBUG_ENTER("_nisam_readinfo");
-
- share=info->s;
- if (info->lock_type == F_UNLCK)
- {
- if (!share->r_locks && !share->w_locks)
- {
-#ifndef HAVE_FCNTL
- VOID(my_seek(share->kfile,0L,MY_SEEK_SET,MYF(0)));
-#endif
-#ifndef NO_LOCKING
-#ifdef UNSAFE_LOCKING
- if ((info->tmp_lock_type=lock_type) != F_RDLCK)
-#endif
- if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,info->lock_wait))
- DBUG_RETURN(1);
-#endif
-#ifdef HAVE_FCNTL
- if (my_pread(share->kfile,
- (char*) &share->state.header,share->state_length,0L,
- MYF(MY_NABP)))
-#else
- if (my_read(share->kfile,
- (char*) &share->state.header,share->state_length,
- MYF(MY_NABP)))
-#endif
- {
-#ifndef NO_LOCKING
- int error=my_errno;
- VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
- MYF(MY_SEEK_NOT_DONE)));
- my_errno=error;
-#endif
- DBUG_RETURN(1);
- }
- }
- if (check_keybuffer)
- VOID(_nisam_test_if_changed(info));
- }
- else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
- {
- my_errno=EACCES; /* Not allowed to change */
- DBUG_RETURN(-1); /* when have read_lock() */
- }
- DBUG_RETURN(0);
-} /* _nisam_readinfo */
-
-
- /* Every isam-function that uppdates the isam-database must! end */
- /* with this request */
- /* ARGSUSED */
-
-int _nisam_writeinfo(register N_INFO *info, uint flags)
-{
- int error,olderror;
- ISAM_SHARE *share;
- DBUG_ENTER("_nisam_writeinfo");
-
- error=0;
- share=info->s;
- if (share->r_locks == 0 && share->w_locks == 0)
- {
- olderror=my_errno; /* Remember last error */
- if (flags)
- { /* Two threads can't be here */
- share->state.process= share->last_process= share->this_process;
- share->state.loop= info->last_loop= ++info->this_loop;
- share->state.uniq= info->last_uniq= info->this_uniq;
- if ((error=my_pwrite(share->kfile,(char*) &share->state.header,
- share->state_length,0L,MYF(MY_NABP)) != 0))
- olderror=my_errno;
-#ifdef __WIN__
- if (nisam_flush)
- {
- _commit(share->kfile);
- _commit(info->dfile);
- }
-#endif
- }
- if (flags != 2)
- {
-#ifndef NO_LOCKING
-#ifdef UNSAFE_LOCKING
- if (info->tmp_lock_type != F_RDLCK)
-#endif
- {
- if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
- MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
- DBUG_RETURN(1);
- }
-#endif
- }
- my_errno=olderror;
- }
- else if (flags)
- share->changed= 1; /* Mark keyfile changed */
- DBUG_RETURN(error);
-} /* _nisam_writeinfo */
-
-
- /* Test if someone has changed the database */
- /* (Should be called after readinfo) */
-
-int _nisam_test_if_changed(register N_INFO *info)
-{
-#ifndef NO_LOCKING
- {
- ISAM_SHARE *share=info->s;
- if (share->state.process != share->last_process ||
- share->state.loop != info->last_loop ||
- share->state.uniq != info->last_uniq)
- { /* Keyfile has changed */
- if (share->state.process != share->this_process)
- VOID(flush_key_blocks(dflt_key_cache,share->kfile,FLUSH_RELEASE));
- share->last_process=share->state.process;
- info->last_loop= share->state.loop;
- info->last_uniq= share->state.uniq;
- info->update|= HA_STATE_WRITTEN; /* Must use file on next */
- info->data_changed= 1; /* For nisam_is_changed */
- return 1;
- }
- }
-#endif
- return (!(info->update & HA_STATE_AKTIV) ||
- (info->update & (HA_STATE_WRITTEN | HA_STATE_DELETED |
- HA_STATE_KEY_CHANGED)));
-} /* _nisam_test_if_changed */
diff --git a/isam/_packrec.c b/isam/_packrec.c
deleted file mode 100644
index 74a45852e63..00000000000
--- a/isam/_packrec.c
+++ /dev/null
@@ -1,1184 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
- /* Functions to compressed records */
-
-#include "isamdef.h"
-
-#define IS_CHAR ((uint) 32768) /* Bit if char (not offset) in tree */
-
-#if INT_MAX > 65536L
-#define BITS_SAVED 32
-#define MAX_QUICK_TABLE_BITS 9 /* Because we may shift in 24 bits */
-#else
-#define BITS_SAVED 16
-#define MAX_QUICK_TABLE_BITS 6
-#endif
-
-#define get_bit(BU) ((BU)->bits ? \
- (BU)->current_byte & ((bit_type) 1 << --(BU)->bits) :\
- (fill_buffer(BU), (BU)->bits= BITS_SAVED-1,\
- (BU)->current_byte & ((bit_type) 1 << (BITS_SAVED-1))))
-#define skipp_to_next_byte(BU) ((BU)->bits&=~7)
-#define get_bits(BU,count) (((BU)->bits >= count) ? (((BU)->current_byte >> ((BU)->bits-=count)) & mask[count]) : fill_and_get_bits(BU,count))
-
-#define decode_bytes_test_bit(bit) \
- if (low_byte & (1 << (7-bit))) \
- pos++; \
- if (*pos & IS_CHAR) \
- { bits-=(bit+1); break; } \
- pos+= *pos
-
-
- static void read_huff_table(BIT_BUFF *bit_buff,DECODE_TREE *decode_tree,
- uint16 **decode_table,byte **intervall_buff,
- uint16 *tmp_buff);
-static void make_quick_table(uint16 *to_table,uint16 *decode_table,
- uint *next_free,uint value,uint bits,
- uint max_bits);
-static void fill_quick_table(uint16 *table,uint bits, uint max_bits,
- uint value);
-static uint copy_decode_table(uint16 *to_pos,uint offset,
- uint16 *decode_table);
-static uint find_longest_bitstream(uint16 *table);
-static void (*get_unpack_function(N_RECINFO *rec))(N_RECINFO *field,
- BIT_BUFF *buff,
- uchar *to,
- uchar *end);
-static void uf_zerofill_skipp_zero(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_skipp_zero(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_space_normal(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_space_endspace_selected(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to, uchar *end);
-static void uf_endspace_selected(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_space_endspace(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_endspace(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_space_prespace_selected(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to, uchar *end);
-static void uf_prespace_selected(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_space_prespace(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_prespace(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_zerofill_normal(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_constant(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_intervall(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void uf_zero(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static void decode_bytes(N_RECINFO *rec,BIT_BUFF *bit_buff,
- uchar *to,uchar *end);
-static uint decode_pos(BIT_BUFF *bit_buff,DECODE_TREE *decode_tree);
-static void init_bit_buffer(BIT_BUFF *bit_buff,char *buffer,uint length);
-static uint fill_and_get_bits(BIT_BUFF *bit_buff,uint count);
-static void fill_buffer(BIT_BUFF *bit_buff);
-static uint max_bit(uint value);
-#ifdef HAVE_MMAP
-static void _nisam_mempack_get_block_info(BLOCK_INFO *info,uint ref_length,
- uchar *header);
-#endif
-
-static uint mask[]=
-{
- 0x00000000,
- 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
- 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
- 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
- 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
-#if BITS_SAVED > 16
- 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
- 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
- 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
- 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
-#endif
- };
-
-
- /* Read all packed info, allocate memory and fix field structs */
-
-my_bool _nisam_read_pack_info(N_INFO *info, pbool fix_keys)
-{
- File file;
- int diff_length;
- uint i,trees,huff_tree_bits,rec_reflength,length;
- uint16 *decode_table,*tmp_buff;
- ulong elements,intervall_length;
- char *disk_cache,*intervall_buff;
- uchar header[32];
- ISAM_SHARE *share=info->s;
- BIT_BUFF bit_buff;
- DBUG_ENTER("_nisam_read_pack_info");
-
- if (nisam_quick_table_bits < 4)
- nisam_quick_table_bits=4;
- else if (nisam_quick_table_bits > MAX_QUICK_TABLE_BITS)
- nisam_quick_table_bits=MAX_QUICK_TABLE_BITS;
-
- file=info->dfile;
- my_errno=0;
- if (my_read(file,(byte*) header,sizeof(header),MYF(MY_NABP)))
- {
- if (!my_errno)
- my_errno=HA_ERR_END_OF_FILE;
- DBUG_RETURN(1);
- }
- if (memcmp((byte*) header,(byte*) nisam_pack_file_magic,4))
- {
- my_errno=HA_ERR_WRONG_IN_RECORD;
- DBUG_RETURN(1);
- }
- share->pack.header_length=uint4korr(header+4);
- share->min_pack_length=(uint) uint4korr(header+8);
- share->max_pack_length=(uint) uint4korr(header+12);
- set_if_bigger(share->base.pack_reclength,share->max_pack_length);
- elements=uint4korr(header+16);
- intervall_length=uint4korr(header+20);
- trees=uint2korr(header+24);
- share->pack.ref_length=header[26];
- rec_reflength=header[27];
- diff_length=(int) rec_reflength - (int) share->base.rec_reflength;
- if (fix_keys)
- share->rec_reflength=rec_reflength;
- share->base.min_block_length=share->min_pack_length+share->pack.ref_length;
-
- if (!(share->decode_trees=(DECODE_TREE*)
- my_malloc((uint) (trees*sizeof(DECODE_TREE)+
- intervall_length*sizeof(byte)),
- MYF(MY_WME))))
- DBUG_RETURN(1);
- intervall_buff=(byte*) (share->decode_trees+trees);
-
- length=(uint) (elements*2+trees*(1 << nisam_quick_table_bits));
- if (!(share->decode_tables=(uint16*)
- my_malloc((length+512)*sizeof(uint16)+
- (uint) (share->pack.header_length+7),
- MYF(MY_WME | MY_ZEROFILL))))
- {
- my_free((gptr) share->decode_trees,MYF(0));
- DBUG_RETURN(1);
- }
- tmp_buff=share->decode_tables+length;
- disk_cache=(byte*) (tmp_buff+512);
-
- if (my_read(file,disk_cache,
- (uint) (share->pack.header_length-sizeof(header)),
- MYF(MY_NABP)))
- {
- my_free((gptr) share->decode_trees,MYF(0));
- my_free((gptr) share->decode_tables,MYF(0));
- DBUG_RETURN(1);
- }
-
- huff_tree_bits=max_bit(trees ? trees-1 : 0);
- init_bit_buffer(&bit_buff,disk_cache,
- (uint) (share->pack.header_length-sizeof(header)));
- /* Read new info for each field */
- for (i=0 ; i < share->base.fields ; i++)
- {
- share->rec[i].base_type=(enum en_fieldtype) get_bits(&bit_buff,4);
- share->rec[i].pack_type=(uint) get_bits(&bit_buff,4);
- share->rec[i].space_length_bits=get_bits(&bit_buff,4);
- share->rec[i].huff_tree=share->decode_trees+(uint) get_bits(&bit_buff,
- huff_tree_bits);
- share->rec[i].unpack=get_unpack_function(share->rec+i);
- }
- skipp_to_next_byte(&bit_buff);
- decode_table=share->decode_tables;
- for (i=0 ; i < trees ; i++)
- read_huff_table(&bit_buff,share->decode_trees+i,&decode_table,
- &intervall_buff,tmp_buff);
- decode_table=(uint16*)
- my_realloc((gptr) share->decode_tables,
- (uint) ((byte*) decode_table - (byte*) share->decode_tables),
- MYF(MY_HOLD_ON_ERROR));
- {
- my_ptrdiff_t diff=PTR_BYTE_DIFF(decode_table,share->decode_tables);
- share->decode_tables=decode_table;
- for (i=0 ; i < trees ; i++)
- share->decode_trees[i].table=ADD_TO_PTR(share->decode_trees[i].table,
- diff, uint16*);
- }
-
- /* Fix record-ref-length for keys */
- if (fix_keys)
- {
- for (i=0 ; i < share->base.keys ; i++)
- {
- share->keyinfo[i].base.keylength+=(uint16) diff_length;
- share->keyinfo[i].base.minlength+=(uint16) diff_length;
- share->keyinfo[i].base.maxlength+=(uint16) diff_length;
- share->keyinfo[i].seg[share->keyinfo[i].base.keysegs].base.length=
- (uint16) rec_reflength;
- }
- }
-
- if (bit_buff.error || bit_buff.pos < bit_buff.end)
- { /* info_length was wrong */
- my_errno=HA_ERR_WRONG_IN_RECORD;
- my_free((gptr) share->decode_trees,MYF(0));
- my_free((gptr) share->decode_tables,MYF(0));
- DBUG_RETURN(1);
- }
- DBUG_RETURN(0);
-}
-
-
- /* Read on huff-code-table from datafile */
-
-static void read_huff_table(BIT_BUFF *bit_buff, DECODE_TREE *decode_tree,
- uint16 **decode_table, byte **intervall_buff,
- uint16 *tmp_buff)
-{
- uint min_chr,elements,char_bits,offset_bits,size,intervall_length,table_bits,
- next_free_offset;
- uint16 *ptr,*end;
-
- LINT_INIT(ptr);
- if (!get_bits(bit_buff,1))
- {
- min_chr=get_bits(bit_buff,8);
- elements=get_bits(bit_buff,9);
- char_bits=get_bits(bit_buff,5);
- offset_bits=get_bits(bit_buff,5);
- intervall_length=0;
- ptr=tmp_buff;
- }
- else
- {
- min_chr=0;
- elements=get_bits(bit_buff,15);
- intervall_length=get_bits(bit_buff,16);
- char_bits=get_bits(bit_buff,5);
- offset_bits=get_bits(bit_buff,5);
- decode_tree->quick_table_bits=0;
- ptr= *decode_table;
- }
- size=elements*2-2;
-
- for (end=ptr+size ; ptr < end ; ptr++)
- {
- if (get_bit(bit_buff))
- *ptr= (uint16) get_bits(bit_buff,offset_bits);
- else
- *ptr= (uint16) (IS_CHAR + (get_bits(bit_buff,char_bits) + min_chr));
- }
- skipp_to_next_byte(bit_buff);
-
- decode_tree->table= *decode_table;
- decode_tree->intervalls= *intervall_buff;
- if (! intervall_length)
- {
- table_bits=find_longest_bitstream(tmp_buff);
- if (table_bits > nisam_quick_table_bits)
- table_bits=nisam_quick_table_bits;
- next_free_offset= (1 << table_bits);
- make_quick_table(*decode_table,tmp_buff,&next_free_offset,0,table_bits,
- table_bits);
- (*decode_table)+= next_free_offset;
- decode_tree->quick_table_bits=table_bits;
- }
- else
- {
- (*decode_table)=end;
- bit_buff->pos-= bit_buff->bits/8;
- memcpy(*intervall_buff,bit_buff->pos,(size_t) intervall_length);
- (*intervall_buff)+=intervall_length;
- bit_buff->pos+=intervall_length;
- bit_buff->bits=0;
- }
- return;
-}
-
-
-static void make_quick_table(uint16 *to_table, uint16 *decode_table, uint *next_free_offset, uint value, uint bits, uint max_bits)
-{
- if (!bits--)
- {
- to_table[value]= (uint16) *next_free_offset;
- *next_free_offset=copy_decode_table(to_table, *next_free_offset,
- decode_table);
- return;
- }
- if (!(*decode_table & IS_CHAR))
- {
- make_quick_table(to_table,decode_table+ *decode_table,
- next_free_offset,value,bits,max_bits);
- }
- else
- fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
- decode_table++;
- value|= (1 << bits);
- if (!(*decode_table & IS_CHAR))
- {
- make_quick_table(to_table,decode_table+ *decode_table,
- next_free_offset,value,bits,max_bits);
- }
- else
- fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
- return;
-}
-
-
-static void fill_quick_table(uint16 *table, uint bits, uint max_bits, uint value)
-{
- uint16 *end;
- value|=(max_bits-bits) << 8;
- for (end=table+ (1 << bits) ;
- table < end ;
- *table++ = (uint16) value | IS_CHAR) ;
-}
-
-
-static uint copy_decode_table(uint16 *to_pos, uint offset, uint16 *decode_table)
-{
- uint prev_offset;
- prev_offset= offset;
-
- if (!(*decode_table & IS_CHAR))
- {
- to_pos[offset]=2;
- offset=copy_decode_table(to_pos,offset+2,decode_table+ *decode_table);
- }
- else
- {
- to_pos[offset]= *decode_table;
- offset+=2;
- }
- decode_table++;
-
- if (!(*decode_table & IS_CHAR))
- {
- to_pos[prev_offset+1]=(uint16) (offset-prev_offset-1);
- offset=copy_decode_table(to_pos,offset,decode_table+ *decode_table);
- }
- else
- to_pos[prev_offset+1]= *decode_table;
- return offset;
-}
-
-
-static uint find_longest_bitstream(uint16 *table)
-{
- uint length=1,length2;
- if (!(*table & IS_CHAR))
- length=find_longest_bitstream(table+ *table)+1;
- table++;
- if (!(*table & IS_CHAR))
- {
- length2=find_longest_bitstream(table+ *table)+1;
- length=max(length,length2);
- }
- return length;
-}
-
-
- /* Read record from datafile */
- /* Returns length of packed record, -1 if error */
-
-int _nisam_read_pack_record(N_INFO *info, ulong filepos, byte *buf)
-{
- BLOCK_INFO block_info;
- File file;
- DBUG_ENTER("_nisam_read_pack_record");
-
- if (filepos == NI_POS_ERROR)
- DBUG_RETURN(-1); /* _search() didn't find record */
-
- file=info->dfile;
- if (_nisam_pack_get_block_info(&block_info,info->s->pack.ref_length,file,
- filepos))
- goto err;
- if (my_read(file,(byte*) info->rec_buff,block_info.rec_len,MYF(MY_NABP)))
- goto panic;
- info->update|= HA_STATE_AKTIV;
- DBUG_RETURN(_nisam_pack_rec_unpack(info,buf,info->rec_buff,
- block_info.rec_len));
-panic:
- my_errno=HA_ERR_WRONG_IN_RECORD;
-err:
- DBUG_RETURN(-1);
-}
-
-
-
-int _nisam_pack_rec_unpack(register N_INFO *info, register byte *to,
- byte *from, uint reclength)
-{
- byte *end_field;
- reg3 N_RECINFO *end;
- N_RECINFO *current_field;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("_nisam_pack_rec_unpack");
-
- init_bit_buffer(&info->bit_buff,from,reclength);
-
- for (current_field=share->rec, end=current_field+share->base.fields ;
- current_field < end ;
- current_field++,to=end_field)
- {
- end_field=to+current_field->base.length;
- (*current_field->unpack)(current_field,&info->bit_buff,(uchar*) to,
- (uchar*) end_field);
- }
- if (! info->bit_buff.error &&
- info->bit_buff.pos - info->bit_buff.bits/8 == info->bit_buff.end)
- DBUG_RETURN(0);
- my_errno=HA_ERR_WRONG_IN_RECORD;
- info->update&= ~HA_STATE_AKTIV;
- DBUG_RETURN(-1);
-} /* _nisam_pack_rec_unpack */
-
-
- /* Return function to unpack field */
-
-static void (*get_unpack_function(N_RECINFO *rec))(N_RECINFO *, BIT_BUFF *, uchar *, uchar *)
-{
- switch (rec->base_type) {
- case FIELD_SKIP_ZERO:
- if (rec->pack_type & PACK_TYPE_ZERO_FILL)
- return &uf_zerofill_skipp_zero;
- return &uf_skipp_zero;
- case FIELD_NORMAL:
- if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
- return &uf_space_normal;
- if (rec->pack_type & PACK_TYPE_ZERO_FILL)
- return &uf_zerofill_normal;
- return &decode_bytes;
- case FIELD_SKIP_ENDSPACE:
- if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
- {
- if (rec->pack_type & PACK_TYPE_SELECTED)
- return &uf_space_endspace_selected;
- return &uf_space_endspace;
- }
- if (rec->pack_type & PACK_TYPE_SELECTED)
- return &uf_endspace_selected;
- return &uf_endspace;
- case FIELD_SKIP_PRESPACE:
- if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
- {
- if (rec->pack_type & PACK_TYPE_SELECTED)
- return &uf_space_prespace_selected;
- return &uf_space_prespace;
- }
- if (rec->pack_type & PACK_TYPE_SELECTED)
- return &uf_prespace_selected;
- return &uf_prespace;
- case FIELD_CONSTANT:
- return &uf_constant;
- case FIELD_INTERVALL:
- return &uf_intervall;
- case FIELD_ZERO:
- return &uf_zero;
- case FIELD_BLOB: /* Write this sometimes.. */
- case FIELD_LAST:
- default:
- return 0; /* This should never happend */
- }
-}
-
- /* De different functions to unpack a field */
-
-static void uf_zerofill_skipp_zero(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- if (get_bit(bit_buff))
- bzero((char*) to,(uint) (end-to));
- else
- {
-#ifdef WORDS_BIGENDIAN
- bzero((char*) to,rec->space_length_bits);
- decode_bytes(rec,bit_buff,to+rec->space_length_bits,end);
-#else
- end-=rec->space_length_bits;
- decode_bytes(rec,bit_buff,to,end);
- bzero((byte*) end,rec->space_length_bits);
-#endif
- }
-}
-
-static void uf_skipp_zero(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- if (get_bit(bit_buff))
- bzero((char*) to,(uint) (end-to));
- else
- decode_bytes(rec,bit_buff,to,end);
-}
-
-static void uf_space_normal(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- if (get_bit(bit_buff))
- bfill((byte*) to,(end-to),' ');
- else
- decode_bytes(rec,bit_buff,to,end);
-}
-
-static void uf_space_endspace_selected(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- uint spaces;
- if (get_bit(bit_buff))
- bfill((byte*) to,(end-to),' ');
- else
- {
- if (get_bit(bit_buff))
- {
- if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
- {
- bit_buff->error=1;
- return;
- }
- if (to+spaces != end)
- decode_bytes(rec,bit_buff,to,end-spaces);
- bfill((byte*) end-spaces,spaces,' ');
- }
- else
- decode_bytes(rec,bit_buff,to,end);
- }
-}
-
-static void uf_endspace_selected(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- uint spaces;
- if (get_bit(bit_buff))
- {
- if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
- {
- bit_buff->error=1;
- return;
- }
- if (to+spaces != end)
- decode_bytes(rec,bit_buff,to,end-spaces);
- bfill((byte*) end-spaces,spaces,' ');
- }
- else
- decode_bytes(rec,bit_buff,to,end);
-}
-
-static void uf_space_endspace(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- uint spaces;
- if (get_bit(bit_buff))
- bfill((byte*) to,(end-to),' ');
- else
- {
- if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
- {
- bit_buff->error=1;
- return;
- }
- if (to+spaces != end)
- decode_bytes(rec,bit_buff,to,end-spaces);
- bfill((byte*) end-spaces,spaces,' ');
- }
-}
-
-static void uf_endspace(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to,
- uchar *end)
-{
- uint spaces;
- if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
- {
- bit_buff->error=1;
- return;
- }
- if (to+spaces != end)
- decode_bytes(rec,bit_buff,to,end-spaces);
- bfill((byte*) end-spaces,spaces,' ');
-}
-
-static void uf_space_prespace_selected(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- uint spaces;
- if (get_bit(bit_buff))
- bfill((byte*) to,(end-to),' ');
- else
- {
- if (get_bit(bit_buff))
- {
- if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
- {
- bit_buff->error=1;
- return;
- }
- bfill((byte*) to,spaces,' ');
- if (to+spaces != end)
- decode_bytes(rec,bit_buff,to+spaces,end);
- }
- else
- decode_bytes(rec,bit_buff,to,end);
- }
-}
-
-
-static void uf_prespace_selected(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- uint spaces;
- if (get_bit(bit_buff))
- {
- if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
- {
- bit_buff->error=1;
- return;
- }
- bfill((byte*) to,spaces,' ');
- if (to+spaces != end)
- decode_bytes(rec,bit_buff,to+spaces,end);
- }
- else
- decode_bytes(rec,bit_buff,to,end);
-}
-
-
-static void uf_space_prespace(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- uint spaces;
- if (get_bit(bit_buff))
- bfill((byte*) to,(end-to),' ');
- else
- {
- if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
- {
- bit_buff->error=1;
- return;
- }
- bfill((byte*) to,spaces,' ');
- if (to+spaces != end)
- decode_bytes(rec,bit_buff,to+spaces,end);
- }
-}
-
-static void uf_prespace(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- uint spaces;
- if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
- {
- bit_buff->error=1;
- return;
- }
- bfill((byte*) to,spaces,' ');
- if (to+spaces != end)
- decode_bytes(rec,bit_buff,to+spaces,end);
-}
-
-static void uf_zerofill_normal(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
-#ifdef WORDS_BIGENDIAN
- bzero((char*) to,rec->space_length_bits);
- decode_bytes(rec,bit_buff,(uchar*) to+rec->space_length_bits,end);
-#else
- end-=rec->space_length_bits;
- decode_bytes(rec,bit_buff,(uchar*) to,end);
- bzero((byte*) end,rec->space_length_bits);
-#endif
-}
-
-static void uf_constant(N_RECINFO *rec,
- BIT_BUFF *bit_buff __attribute__((unused)),
- uchar *to, uchar *end)
-{
- memcpy(to,rec->huff_tree->intervalls,(size_t) (end-to));
-}
-
-static void uf_intervall(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- reg1 uint field_length=(uint) (end-to);
- memcpy(to,rec->huff_tree->intervalls+field_length*decode_pos(bit_buff,
- rec->huff_tree),
- (size_t) field_length);
-}
-
-
-/*ARGSUSED*/
-static void uf_zero(N_RECINFO *rec __attribute__((unused)),
- BIT_BUFF *bit_buff __attribute__((unused)),
- uchar *to, uchar *end)
-{
- bzero((char*) to,(uint) (end-to));
-}
-
-
- /* Functions to decode of buffer of bits */
-
-#if BITS_SAVED == 64
-
-static void decode_bytes(rec,bit_buff,to,end)
-N_RECINFO *rec;
-BIT_BUFF *bit_buff;
-uchar *to,*end;
-{
- reg1 uint bits,low_byte;
- reg3 uint16 *pos;
- reg4 uint table_bits,table_and;
- DECODE_TREE *decode_tree;
-
- decode_tree=rec->decode_tree;
- bits=bit_buff->bits; /* Save in reg for quicker access */
- table_bits=decode_tree->quick_table_bits;
- table_and= (1 << table_bits)-1;
-
- do
- {
- if (bits <= 32)
- {
- if (bit_buff->pos > bit_buff->end+4)
- return; /* Can't be right */
- bit_buff->current_byte= (bit_buff->current_byte << 32) +
- ((((uint) bit_buff->pos[3])) +
- (((uint) bit_buff->pos[2]) << 8) +
- (((uint) bit_buff->pos[1]) << 16) +
- (((uint) bit_buff->pos[0]) << 24));
- bit_buff->pos+=4;
- bits+=32;
- }
- /* First use info in quick_table */
- low_byte=(uint) (bit_buff->current_byte >> (bits - table_bits)) & table_and;
- low_byte=decode_tree->table[low_byte];
- if (low_byte & IS_CHAR)
- {
- *to++ = (low_byte & 255); /* Found char in quick table */
- bits-= ((low_byte >> 8) & 31); /* Remove bits used */
- }
- else
- { /* Map through rest of decode-table */
- pos=decode_tree->table+low_byte;
- bits-=table_bits;
- for (;;)
- {
- low_byte=(uint) (bit_buff->current_byte >> (bits-8));
- decode_bytes_test_bit(0);
- decode_bytes_test_bit(1);
- decode_bytes_test_bit(2);
- decode_bytes_test_bit(3);
- decode_bytes_test_bit(4);
- decode_bytes_test_bit(5);
- decode_bytes_test_bit(6);
- decode_bytes_test_bit(7);
- bits-=8;
- }
- *to++ = *pos;
- }
- } while (to != end);
-
- bit_buff->bits=bits;
- return;
-}
-
-#else
-
-static void decode_bytes(N_RECINFO *rec, BIT_BUFF *bit_buff, uchar *to, uchar *end)
-{
- reg1 uint bits,low_byte;
- reg3 uint16 *pos;
- reg4 uint table_bits,table_and;
- DECODE_TREE *decode_tree;
-
- decode_tree=rec->huff_tree;
- bits=bit_buff->bits; /* Save in reg for quicker access */
- table_bits=decode_tree->quick_table_bits;
- table_and= (1 << table_bits)-1;
-
- do
- {
- if (bits < table_bits)
- {
- if (bit_buff->pos > bit_buff->end+1)
- return; /* Can't be right */
-#if BITS_SAVED == 32
- bit_buff->current_byte= (bit_buff->current_byte << 24) +
- (((uint) ((uchar) bit_buff->pos[2]))) +
- (((uint) ((uchar) bit_buff->pos[1])) << 8) +
- (((uint) ((uchar) bit_buff->pos[0])) << 16);
- bit_buff->pos+=3;
- bits+=24;
-#else
- if (bits) /* We must have at leasts 9 bits */
- {
- bit_buff->current_byte= (bit_buff->current_byte << 8) +
- (uint) ((uchar) bit_buff->pos[0]);
- bit_buff->pos++;
- bits+=8;
- }
- else
- {
- bit_buff->current_byte= ((uint) ((uchar) bit_buff->pos[0]) << 8) +
- ((uint) ((uchar) bit_buff->pos[1]));
- bit_buff->pos+=2;
- bits+=16;
- }
-#endif
- }
- /* First use info in quick_table */
- low_byte=(bit_buff->current_byte >> (bits - table_bits)) & table_and;
- low_byte=decode_tree->table[low_byte];
- if (low_byte & IS_CHAR)
- {
- *to++ = (low_byte & 255); /* Found char in quick table */
- bits-= ((low_byte >> 8) & 31); /* Remove bits used */
- }
- else
- { /* Map through rest of decode-table */
- pos=decode_tree->table+low_byte;
- bits-=table_bits;
- for (;;)
- {
- if (bits < 8)
- { /* We don't need to check end */
-#if BITS_SAVED == 32
- bit_buff->current_byte= (bit_buff->current_byte << 24) +
- (((uint) ((uchar) bit_buff->pos[2]))) +
- (((uint) ((uchar) bit_buff->pos[1])) << 8) +
- (((uint) ((uchar) bit_buff->pos[0])) << 16);
- bit_buff->pos+=3;
- bits+=24;
-#else
- bit_buff->current_byte= (bit_buff->current_byte << 8) +
- (uint) ((uchar) bit_buff->pos[0]);
- bit_buff->pos+=1;
- bits+=8;
-#endif
- }
- low_byte=(uint) (bit_buff->current_byte >> (bits-8));
- decode_bytes_test_bit(0);
- decode_bytes_test_bit(1);
- decode_bytes_test_bit(2);
- decode_bytes_test_bit(3);
- decode_bytes_test_bit(4);
- decode_bytes_test_bit(5);
- decode_bytes_test_bit(6);
- decode_bytes_test_bit(7);
- bits-=8;
- }
- *to++ = (uchar) *pos;
- }
- } while (to != end);
-
- bit_buff->bits=bits;
- return;
-}
-#endif /* BIT_SAVED == 64 */
-
-
-static uint decode_pos(BIT_BUFF *bit_buff, DECODE_TREE *decode_tree)
-{
- uint16 *pos=decode_tree->table;
- for (;;)
- {
- if (get_bit(bit_buff))
- pos++;
- if (*pos & IS_CHAR)
- return (uint) (*pos & ~IS_CHAR);
- pos+= *pos;
- }
-}
-
-
-int _nisam_read_rnd_pack_record(N_INFO *info, byte *buf,
- register ulong filepos,
- int skipp_deleted_blocks)
-{
- uint b_type;
- BLOCK_INFO block_info;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("_nisam_read_rnd_pack_record");
-
- if (filepos >= share->state.data_file_length)
- {
- my_errno= HA_ERR_END_OF_FILE;
- goto err;
- }
-
- if (info->opt_flag & READ_CACHE_USED)
- {
- if (_nisam_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
- share->pack.ref_length, skipp_deleted_blocks))
- goto err;
- b_type=_nisam_pack_get_block_info(&block_info,share->pack.ref_length,-1,
- filepos);
- }
- else
- b_type=_nisam_pack_get_block_info(&block_info,share->pack.ref_length,
- info->dfile,filepos);
- if (b_type)
- goto err;
-#ifndef DBUG_OFF
- if (block_info.rec_len > share->max_pack_length)
- {
- my_errno=HA_ERR_WRONG_IN_RECORD;
- goto err;
- }
-#endif
- if (info->opt_flag & READ_CACHE_USED)
- {
- if (_nisam_read_cache(&info->rec_cache,(byte*) info->rec_buff,
- block_info.filepos, block_info.rec_len,
- skipp_deleted_blocks))
- goto err;
- }
- else
- {
- if (my_read(info->dfile,(byte*) info->rec_buff,block_info.rec_len,
- MYF(MY_NABP)))
- goto err;
- }
- info->packed_length=block_info.rec_len;
- info->lastpos=filepos;
- info->nextpos=block_info.filepos+block_info.rec_len;
- info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
-
- DBUG_RETURN (_nisam_pack_rec_unpack(info,buf,info->rec_buff,
- block_info.rec_len));
-err:
- DBUG_RETURN(-1);
-}
-
-
- /* Read and process header from a huff-record-file */
-
-uint _nisam_pack_get_block_info(BLOCK_INFO *info, uint ref_length, File file,
- ulong filepos)
-{
- uchar *header=info->header;
-
- if (file >= 0)
- {
- VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
- if (my_read(file,(char*) header,ref_length,MYF(MY_NABP)))
- return BLOCK_FATAL_ERROR;
- }
- DBUG_DUMP("header",(byte*) header,ref_length);
-
- switch (ref_length) {
- case 1:
- info->rec_len=header[0];
- info->filepos=filepos+1;
- break;
- case 2:
- info->rec_len=uint2korr(header);
- info->filepos=filepos+2;
- break;
- case 3:
- info->rec_len=(uint) (uint3korr(header));
- info->filepos=filepos+3;
- break;
- default: break;
- }
- return 0;
-}
-
-
- /* routines for bit buffer */
- /* Buffer must be 6 byte bigger */
-static void init_bit_buffer(BIT_BUFF *bit_buff, char *buffer, uint length)
-{
- bit_buff->pos=(uchar*) buffer;
- bit_buff->end=(uchar*) buffer+length;
- bit_buff->bits=bit_buff->error=0;
- bit_buff->current_byte=0; /* Avoid purify errors */
-}
-
-static uint fill_and_get_bits(BIT_BUFF *bit_buff, uint count)
-{
- uint tmp;
- count-=bit_buff->bits;
- tmp=(bit_buff->current_byte & mask[bit_buff->bits]) << count;
- fill_buffer(bit_buff);
- bit_buff->bits=BITS_SAVED - count;
- return tmp+(bit_buff->current_byte >> (BITS_SAVED - count));
-}
-
- /* Fill in empty bit_buff->current_byte from buffer */
- /* Sets bit_buff->error if buffer is exhausted */
-
-static void fill_buffer(BIT_BUFF *bit_buff)
-{
- if (bit_buff->pos >= bit_buff->end)
- {
- bit_buff->error= 1;
- bit_buff->current_byte=0;
- return;
- }
-#if BITS_SAVED == 64
- bit_buff->current_byte= ((((uint) ((uchar) bit_buff->pos[7]))) +
- (((uint) ((uchar) bit_buff->pos[6])) << 8) +
- (((uint) ((uchar) bit_buff->pos[5])) << 16) +
- (((uint) ((uchar) bit_buff->pos[4])) << 24) +
- ((ulonglong)
- ((((uint) ((uchar) bit_buff->pos[3]))) +
- (((uint) ((uchar) bit_buff->pos[2])) << 8) +
- (((uint) ((uchar) bit_buff->pos[1])) << 16) +
- (((uint) ((uchar) bit_buff->pos[0])) << 24)) << 32));
- bit_buff->pos+=8;
-#else
-#if BITS_SAVED == 32
- bit_buff->current_byte= (((uint) ((uchar) bit_buff->pos[3])) +
- (((uint) ((uchar) bit_buff->pos[2])) << 8) +
- (((uint) ((uchar) bit_buff->pos[1])) << 16) +
- (((uint) ((uchar) bit_buff->pos[0])) << 24));
- bit_buff->pos+=4;
-#else
- bit_buff->current_byte= (uint) (((uint) ((uchar) bit_buff->pos[1]))+
- (((uint) ((uchar) bit_buff->pos[0])) << 8));
- bit_buff->pos+=2;
-#endif
-#endif
-}
-
- /* Get number of bits neaded to represent value */
-
-static uint max_bit(register uint value)
-{
- reg2 uint power=1;
-
- while ((value>>=1))
- power++;
- return (power);
-}
-
-
-/*****************************************************************************
- Some redefined functions to handle files when we are using memmap
-*****************************************************************************/
-
-#ifdef HAVE_MMAP
-
-#include <sys/mman.h>
-
-static int _nisam_read_mempack_record(N_INFO *info,ulong filepos,byte *buf);
-static int _nisam_read_rnd_mempack_record(N_INFO*, byte *,ulong, int);
-
-#ifndef MAP_NORESERVE
-#define MAP_NORESERVE 0 /* For irix */
-#endif
-#ifndef MAP_FAILED
-#define MAP_FAILED -1
-#endif
-
-my_bool _nisam_memmap_file(N_INFO *info)
-{
- byte *file_map;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("_nisam_memmap_file");
-
- if (!info->s->file_map)
- {
- if (my_seek(info->dfile,0L,MY_SEEK_END,MYF(0)) <
- share->state.data_file_length+MEMMAP_EXTRA_MARGIN)
- {
- DBUG_PRINT("warning",("File isn't extended for memmap"));
- DBUG_RETURN(0);
- }
- file_map=(byte*)
- mmap(0,share->state.data_file_length+MEMMAP_EXTRA_MARGIN,PROT_READ,
- MAP_SHARED | MAP_NORESERVE,info->dfile,0L);
- if (file_map == (byte*) MAP_FAILED)
- {
- DBUG_PRINT("warning",("mmap failed: errno: %d",errno));
- my_errno=errno;
- DBUG_RETURN(0);
- }
- info->s->file_map=file_map;
- }
- info->opt_flag|= MEMMAP_USED;
- info->read_record=share->read_record=_nisam_read_mempack_record;
- share->read_rnd=_nisam_read_rnd_mempack_record;
- DBUG_RETURN(1);
-}
-
-
-void _nisam_unmap_file(N_INFO *info)
-{
- if (info->s->file_map)
- (void) munmap((caddr_t) info->s->file_map,
- (size_t) info->s->state.data_file_length+
- MEMMAP_EXTRA_MARGIN);
-}
-
-
-static void _nisam_mempack_get_block_info(BLOCK_INFO *info, uint ref_length,
- uchar *header)
-{
- if (ref_length == 1) /* This is most usual */
- info->rec_len=header[0];
- else if (ref_length == 2)
- info->rec_len=uint2korr(header);
- else
- info->rec_len=(uint) (uint3korr(header));
-}
-
-
-static int _nisam_read_mempack_record(N_INFO *info, ulong filepos, byte *buf)
-{
- BLOCK_INFO block_info;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("ni_read_mempack_record");
-
- if (filepos == NI_POS_ERROR)
- DBUG_RETURN(-1); /* _search() didn't find record */
-
- _nisam_mempack_get_block_info(&block_info,share->pack.ref_length,
- (uchar*) share->file_map+filepos);
- DBUG_RETURN(_nisam_pack_rec_unpack(info,buf,share->file_map+
- share->pack.ref_length+filepos,
- block_info.rec_len));
-}
-
-
-/*ARGSUSED*/
-static int _nisam_read_rnd_mempack_record(N_INFO *info, byte *buf,
- register ulong filepos,
- int skipp_deleted_blocks
- __attribute__((unused)))
-{
- BLOCK_INFO block_info;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("_nisam_read_rnd_mempack_record");
-
- if (filepos >= share->state.data_file_length)
- {
- my_errno=HA_ERR_END_OF_FILE;
- goto err;
- }
-
- _nisam_mempack_get_block_info(&block_info,share->pack.ref_length,
- (uchar*) share->file_map+filepos);
-#ifndef DBUG_OFF
- if (block_info.rec_len > info->s->max_pack_length)
- {
- my_errno=HA_ERR_WRONG_IN_RECORD;
- goto err;
- }
-#endif
- info->packed_length=block_info.rec_len;
- info->lastpos=filepos;
- info->nextpos=filepos+share->pack.ref_length+block_info.rec_len;
- info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
-
- DBUG_RETURN (_nisam_pack_rec_unpack(info,buf,share->file_map+
- share->pack.ref_length+filepos,
- block_info.rec_len));
-err:
- DBUG_RETURN(-1);
-}
-
-#endif /* HAVE_MMAP */
diff --git a/isam/_page.c b/isam/_page.c
deleted file mode 100644
index e31115e624f..00000000000
--- a/isam/_page.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* L{ser och skriver nyckelblock */
-
-#include "isamdef.h"
-#ifdef __WIN__
-#include <errno.h>
-#endif
-
- /* Fetch a key-page in memory */
-
-uchar *_nisam_fetch_keypage(register N_INFO *info, N_KEYDEF *keyinfo,
- my_off_t page, uchar *buff, int return_buffer)
-{
- uchar *tmp;
- tmp=(uchar*) key_cache_read(dflt_key_cache,
- info->s->kfile,page,DFLT_INIT_HITS,(byte*) buff,
- (uint) keyinfo->base.block_length,
- (uint) keyinfo->base.block_length,
- return_buffer);
- if (tmp == info->buff)
- {
- info->update|=HA_STATE_BUFF_SAVED;
- info->int_pos=(ulong) page;
- info->buff_used=1;
- }
- else
- {
- info->update&= ~HA_STATE_BUFF_SAVED;
- if (tmp)
- info->int_pos=(ulong) page;
- else
- {
- info->int_pos=NI_POS_ERROR;
- DBUG_PRINT("error",("Got errno: %d from key_cache_read",my_errno));
- my_errno=HA_ERR_CRASHED;
- }
- }
- return tmp;
-} /* _nisam_fetch_keypage */
-
-
- /* Write a key-page on disk */
-
-int _nisam_write_keypage(register N_INFO *info, register N_KEYDEF *keyinfo,
- my_off_t page, uchar *buff)
-{
- reg3 uint length;
-#ifndef QQ /* Safety check */
- if (page < info->s->base.keystart ||
- page+keyinfo->base.block_length > info->s->state.key_file_length ||
- page & (nisam_block_size-1))
- {
- DBUG_PRINT("error",("Trying to write outside key region: %lu",
- (long) page));
- my_errno=EINVAL;
- return(-1);
- }
- DBUG_PRINT("page",("write page at: %lu",(long) page,buff));
- DBUG_DUMP("buff",(byte*) buff,getint(buff));
-#endif
-
- if ((length=keyinfo->base.block_length) > IO_SIZE*2 &&
- info->s->state.key_file_length != page+length)
- length= ((getint(buff)+IO_SIZE-1) & (uint) ~(IO_SIZE-1));
-#ifdef HAVE_purify
- {
- length=getint(buff);
- bzero((byte*) buff+length,keyinfo->base.block_length-length);
- length=keyinfo->base.block_length;
- }
-#endif
- return (key_cache_write(dflt_key_cache,
- info->s->kfile,page,DFLT_INIT_HITS,
- (byte*) buff,length,
- (uint) keyinfo->base.block_length,
- (int) (info->lock_type != F_UNLCK)));
-} /* nisam_write_keypage */
-
-
- /* Remove page from disk */
-
-int _nisam_dispose(register N_INFO *info, N_KEYDEF *keyinfo, my_off_t pos)
-{
- uint keynr= (uint) (keyinfo - info->s->keyinfo);
- ulong old_link; /* ulong is ok here */
- DBUG_ENTER("_nisam_dispose");
-
- old_link=info->s->state.key_del[keynr];
- info->s->state.key_del[keynr]=(ulong) pos;
- DBUG_RETURN(key_cache_write(dflt_key_cache,
- info->s->kfile,pos,DFLT_INIT_HITS,
- (byte*) &old_link,
- sizeof(long),
- (uint) keyinfo->base.block_length,
- (int) (info->lock_type != F_UNLCK)));
-} /* _nisam_dispose */
-
-
- /* Make new page on disk */
-
-ulong _nisam_new(register N_INFO *info, N_KEYDEF *keyinfo)
-{
- uint keynr= (uint) (keyinfo - info->s->keyinfo);
- ulong pos;
- DBUG_ENTER("_nisam_new");
-
- if ((pos=info->s->state.key_del[keynr]) == NI_POS_ERROR)
- {
- if (info->s->state.key_file_length >= info->s->base.max_key_file_length)
- {
- my_errno=HA_ERR_INDEX_FILE_FULL;
- DBUG_RETURN(NI_POS_ERROR);
- }
- pos=info->s->state.key_file_length;
- info->s->state.key_file_length+= keyinfo->base.block_length;
- }
- else
- {
- if (!key_cache_read(dflt_key_cache,
- info->s->kfile,pos,DFLT_INIT_HITS,
- (byte*) &info->s->state.key_del[keynr],
- (uint) sizeof(long),
- (uint) keyinfo->base.block_length,0))
- pos= NI_POS_ERROR;
- }
- DBUG_PRINT("exit",("Pos: %d",pos));
- DBUG_RETURN(pos);
-} /* _nisam_new */
diff --git a/isam/_search.c b/isam/_search.c
deleted file mode 100644
index fbffd6786e1..00000000000
--- a/isam/_search.c
+++ /dev/null
@@ -1,889 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* S|ker efter positionen f|r en nyckel samt d{rmedh|rande funktioner */
-
-#include "isamdef.h"
-#include "m_ctype.h"
-
-#define CMP(a,b) (a<b ? -1 : a == b ? 0 : 1)
-
- /* Check index */
-
-int _nisam_check_index(N_INFO *info, int inx)
-{
- if (inx == -1) /* Use last index */
- inx=info->lastinx;
- if (inx >= (int) info->s->state.keys || inx < 0)
- {
- my_errno=HA_ERR_WRONG_INDEX;
- return -1;
- }
- if (info->lastinx != inx) /* Index changed */
- {
- info->lastinx = inx;
- info->lastpos = NI_POS_ERROR;
- info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) |
- HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
- }
- if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
- return(-1);
- return(inx);
-} /* ni_check_index */
-
-
- /* S|ker reda p} positionen f|r ett record p} basen av en nyckel */
- /* Positionen l{ggs i info->lastpos */
- /* Returns -1 if not found and 1 if search at upper levels */
-
-int _nisam_search(register N_INFO *info, register N_KEYDEF *keyinfo, uchar *key, uint key_len, uint nextflag, register ulong pos)
-{
- int error,flag;
- uint nod_flag;
- uchar *keypos,*maxpos;
- uchar lastkey[N_MAX_KEY_BUFF],*buff;
- DBUG_ENTER("_nisam_search");
- DBUG_PRINT("enter",("pos: %ld nextflag: %d lastpos: %ld",
- pos,nextflag,info->lastpos));
-
- if (pos == NI_POS_ERROR)
- {
- my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
- info->lastpos= NI_POS_ERROR;
- if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST)))
- DBUG_RETURN(-1); /* Not found ; return error */
- DBUG_RETURN(1); /* Search at upper levels */
- }
-
- if (!(buff=_nisam_fetch_keypage(info,keyinfo,pos,info->buff,
- test(!(nextflag & SEARCH_SAVE_BUFF)))))
- goto err;
- DBUG_DUMP("page",(byte*) buff,getint(buff));
-
- flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
- &keypos,lastkey);
- nod_flag=test_if_nod(buff);
- maxpos=buff+getint(buff)-1;
-
- if (flag)
- {
- if ((error=_nisam_search(info,keyinfo,key,key_len,nextflag,
- _nisam_kpos(nod_flag,keypos))) <= 0)
- DBUG_RETURN(error);
-
- if (flag >0)
- {
- if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) &&
- keypos == buff+2+nod_flag)
- DBUG_RETURN(1); /* Bigger than key */
- }
- else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
- DBUG_RETURN(1); /* Smaller than key */
- }
- else
- {
- if (nextflag & SEARCH_FIND && (!(keyinfo->base.flag & HA_NOSAME)
- || key_len) && nod_flag)
- {
- if ((error=_nisam_search(info,keyinfo,key,key_len,SEARCH_FIND,
- _nisam_kpos(nod_flag,keypos))) >= 0 ||
- my_errno != HA_ERR_KEY_NOT_FOUND)
- DBUG_RETURN(error);
- info->int_pos= NI_POS_ERROR; /* Buffer not in memory */
- }
- }
- if (pos != info->int_pos)
- {
- uchar *old_buff=buff;
- if (!(buff=_nisam_fetch_keypage(info,keyinfo,pos,info->buff,
- test(!(nextflag & SEARCH_SAVE_BUFF)))))
- goto err;
- keypos=buff+(keypos-old_buff);
- maxpos=buff+(maxpos-old_buff);
- }
-
- if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
- {
- keypos=_nisam_get_last_key(info,keyinfo,buff,lastkey,keypos);
- if (!(nextflag & SEARCH_SMALLER) &&
- _nisam_key_cmp(keyinfo->seg, lastkey, key, key_len, SEARCH_FIND))
- {
- my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
- goto err;
- }
- }
-
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey));
- VOID(_nisam_move_key(keyinfo,info->lastkey,lastkey));
- info->lastpos=_nisam_dpos(info,nod_flag,keypos);
- info->int_keypos=info->buff+ (keypos-buff);
- info->int_maxpos=info->buff+ (maxpos-buff);
- info->page_changed=0;
- info->buff_used= (info->buff != buff);
- info->last_search_keypage=info->int_pos;
-
- DBUG_PRINT("exit",("found key at %ld",info->lastpos));
- DBUG_RETURN(0);
-err:
- DBUG_PRINT("exit",("Error: %d",my_errno));
- info->lastpos= NI_POS_ERROR;
- DBUG_RETURN (-1);
-} /* _nisam_search */
-
-
- /* Search after key in page-block */
- /* If packed key puts smaller or identical key in buff */
- /* ret_pos point to where find or bigger key starts */
- /* ARGSUSED */
-
-int _nisam_bin_search(N_INFO *info, register N_KEYDEF *keyinfo, uchar *page,
- uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
- uchar *buff __attribute__((unused)))
-{
- reg4 int start,mid,end;
- int flag;
- uint totlength,nod_flag;
- DBUG_ENTER("_nisam_bin_search");
-
- LINT_INIT(flag);
- totlength=keyinfo->base.keylength+(nod_flag=test_if_nod(page));
- start=0; mid=1;
- end= (int) ((getint(page)-2-nod_flag)/totlength-1);
- DBUG_PRINT("test",("getint: %d end: %d",getint(page),end));
- page+=2+nod_flag;
-
- while (start != end)
- {
- mid= (start+end)/2;
- if ((flag=_nisam_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
- comp_flag))
- >= 0)
- end=mid;
- else
- start=mid+1;
- }
- if (mid != start)
- flag=_nisam_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
- comp_flag);
- if (flag < 0)
- start++; /* point at next, bigger key */
- *ret_pos=page+(uint) start*totlength;
- DBUG_PRINT("exit",("flag: %d keypos: %d",flag,start));
- DBUG_RETURN(flag);
-} /* _nisam_bin_search */
-
-
- /* Used instead of _nisam_bin_search() when key is packed */
- /* Puts smaller or identical key in buff */
- /* Key is searched sequentially */
-
-int _nisam_seq_search(N_INFO *info, register N_KEYDEF *keyinfo, uchar *page, uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, uchar *buff)
-{
- int flag;
- uint nod_flag,length;
- uchar t_buff[N_MAX_KEY_BUFF],*end;
- DBUG_ENTER("_nisam_seq_search");
-
- LINT_INIT(flag); LINT_INIT(length);
- end= page+getint(page);
- nod_flag=test_if_nod(page);
- page+=2+nod_flag;
- *ret_pos=page;
- while (page < end)
- {
- length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
- if ((flag=_nisam_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag)) >= 0)
- break;
-#ifdef EXTRA_DEBUG
- DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d",page,t_buff,flag));
-#endif
- memcpy(buff,t_buff,length);
- *ret_pos=page;
- }
- if (flag == 0)
- memcpy(buff,t_buff,length); /* Result is first key */
- DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos));
- DBUG_RETURN(flag);
-} /* _nisam_seq_search */
-
-
- /* Get pos to a key_block */
-
-ulong _nisam_kpos(uint nod_flag, uchar *after_key)
-{
- after_key-=nod_flag;
- switch (nod_flag) {
- case 3:
- return uint3korr(after_key)*512L;
- case 2:
- return uint2korr(after_key)*512L;
- case 1:
- return (uint) (*after_key)*512L;
- case 0: /* At leaf page */
- default: /* Impossible */
- return(NI_POS_ERROR);
- }
-} /* _kpos */
-
-
- /* Save pos to a key_block */
-
-void _nisam_kpointer(register N_INFO *info, register uchar *buff, ulong pos)
-{
- pos/=512L;
- switch (info->s->base.key_reflength) {
- case 3: int3store(buff,pos); break;
- case 2: int2store(buff,(uint) pos); break;
- case 1: buff[0]= (uchar) pos; break;
- default: abort(); /* impossible */
- }
-} /* _nisam_kpointer */
-
-
- /* Calc pos to a data-record */
-
-ulong _nisam_dpos(N_INFO *info, uint nod_flag, uchar *after_key)
-{
- ulong pos;
- after_key-=(nod_flag + info->s->rec_reflength);
- switch (info->s->rec_reflength) {
- case 4:
- pos= (ulong) uint4korr(after_key);
- break;
- case 3:
- pos= (ulong) uint3korr(after_key);
- break;
- case 2:
- pos= (ulong) uint2korr(after_key);
- break;
- default:
- pos=0L; /* Shut compiler up */
- }
- return (info->s->base.options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
- pos*info->s->base.reclength;
-}
-
- /* save pos to record */
-
-void _nisam_dpointer(N_INFO *info, uchar *buff, ulong pos)
-{
- if (!(info->s->base.options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
- pos/=info->s->base.reclength;
-
- switch (info->s->rec_reflength) {
- case 4: int4store(buff,pos); break;
- case 3: int3store(buff,pos); break;
- case 2: int2store(buff,(uint) pos); break;
- default: abort(); /* Impossible */
- }
-} /* _nisam_dpointer */
-
-
- /*
- ** Compare two keys with is bigger
- ** Returns <0, 0, >0 acording to with is bigger
- ** Key_length specifies length of key to use. Number-keys can't
- ** be splitted
- ** If flag <> SEARCH_FIND compare also position
- */
-int _nisam_key_cmp(register N_KEYSEG *keyseg, register uchar *a, register uchar *b, uint key_length, uint nextflag)
-{
- reg4 int flag,length_diff;
- int16 s_1,s_2;
- int32 l_1,l_2;
- uint32 u_1,u_2;
- float f_1,f_2;
- double d_1,d_2;
- reg5 uchar *end;
-
- if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST))
- || key_length == 0)
- key_length=N_MAX_KEY_BUFF*2;
-
- for ( ; (int) key_length >0 ; key_length-= (keyseg++)->base.length)
- {
- end= a+ min(keyseg->base.length,key_length);
- switch ((enum ha_base_keytype) keyseg->base.type) {
- case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
- case HA_KEYTYPE_BINARY:
- if (keyseg->base.flag & HA_SPACE_PACK)
- {
- uchar *as, *bs;
- int length,b_length;
-
- as=a++; bs=b++;
- length= (length_diff= ((int) *as - (b_length= (int) *bs))) < 0 ?
- (int) *as : b_length;
- end= a+ min(key_length,(uint) length);
-
- if (use_strnxfrm(default_charset_info)) {
- if (((enum ha_base_keytype) keyseg->base.type) == HA_KEYTYPE_BINARY)
- {
- while (a < end)
- if ((flag= (int) *a++ - (int) *b++))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- }
- else
- {
- if ((flag = my_strnncoll(default_charset_info,
- a, (int) (end-a), b, b_length)))
- return (keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag;
- b+= (uint) (end-a);
- a=end;
- }
- }
- else
- {
- while (a < end)
- if ((flag= (int) *a++ - (int) *b++))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- }
- if (key_length < (uint) keyseg->base.length)
- { /* key_part */
- if (length_diff)
- {
- if (length_diff < 0 || (uint) *as <= key_length)
- return ((keyseg->base.flag & HA_REVERSE_SORT) ?
- -length_diff : length_diff);
- for (length= (int) key_length-b_length; length-- > 0 ;)
- {
- if (*a++ != ' ')
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -1 : 1);
- }
- }
- if (nextflag & SEARCH_NO_FIND) /* Find record after key */
- return (nextflag & SEARCH_BIGGER) ? -1 : 1;
- return 0;
- }
- else
- {
- if (length_diff)
- return ((keyseg->base.flag & HA_REVERSE_SORT) ?
- -length_diff : length_diff);
- }
- a=as+ (uint) *as+1 ; b= bs+ b_length+1; /* to next key */
- }
- else
- {
- if (use_strnxfrm(default_charset_info)) {
- if (((enum ha_base_keytype) keyseg->base.type) == HA_KEYTYPE_BINARY)
- {
- while (a < end)
- if ((flag= (int) *a++ - (int) *b++))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- }
- else
- {
- if ((flag = my_strnncoll(default_charset_info,
- a, (int) (end-a), b, (int) (end-a))))
- return (keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag;
- b+= (uint) (end-a);
- a=end;
- }
- }
- else
- {
- while (a < end)
- if ((flag= (int) *a++ - (int) *b++))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- }
- }
- break;
- case HA_KEYTYPE_INT8:
- {
- int i_1= (int) *((signed char*) a);
- int i_2= (int) *((signed char*) b);
- if ((flag = CMP(i_1,i_2)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b++;
- break;
- }
- case HA_KEYTYPE_SHORT_INT:
- shortget(s_1,a);
- shortget(s_2,b);
- if ((flag = CMP(s_1,s_2)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+= 2; /* sizeof(short int); */
- break;
- case HA_KEYTYPE_USHORT_INT:
- {
- uint16 us_1,us_2;
- ushortget(us_1,a);
- ushortget(us_2,b);
- if ((flag = CMP(us_1,us_2)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+=2; /* sizeof(short int); */
- break;
- }
- case HA_KEYTYPE_LONG_INT:
- longget(l_1,a);
- longget(l_2,b);
- if ((flag = CMP(l_1,l_2)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+= 4; /* sizeof(long int); */
- break;
- case HA_KEYTYPE_ULONG_INT:
- ulongget(u_1,a);
- ulongget(u_2,b);
- if ((flag = CMP(u_1,u_2)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+= 4; /* sizeof(long int); */
- break;
- case HA_KEYTYPE_INT24:
- l_1=sint3korr(a);
- l_2=sint3korr(b);
- if ((flag = CMP(l_1,l_2)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+= 3;
- break;
- case HA_KEYTYPE_UINT24:
- l_1=(long) uint3korr(a);
- l_2=(long) uint3korr(b);
- if ((flag = CMP(l_1,l_2)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+= 3;
- break;
- case HA_KEYTYPE_FLOAT:
- bmove((byte*) &f_1,(byte*) a,(int) sizeof(float));
- bmove((byte*) &f_2,(byte*) b,(int) sizeof(float));
- if ((flag = CMP(f_1,f_2)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+= sizeof(float);
- break;
- case HA_KEYTYPE_DOUBLE:
- doubleget(d_1,a);
- doubleget(d_2,b);
- if ((flag = CMP(d_1,d_2)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+= sizeof(double);
- break;
- case HA_KEYTYPE_NUM: /* Numeric key */
- {
- int swap_flag=keyseg->base.flag & HA_REVERSE_SORT;
- if (keyseg->base.flag & HA_SPACE_PACK)
- {
- int alength,blength;
-
- if (swap_flag)
- swap_variables(uchar*, a, b);
- alength= *a++; blength= *b++;
- if ((flag=(int) (keyseg->base.length-key_length)) < 0)
- flag=0;
- if (alength != blength+flag)
- {
- if ((alength > blength+flag && *a != '-') ||
- (alength < blength+flag && *b == '-'))
- return 1;
- else
- return -1;
- }
- if (*a == '-' && *b == '-')
- {
- swap_flag=1;
- swap_variables(uchar*, a, b);
- }
- end=a+alength;
- while (a < end)
- if (*a++ != *b++)
- {
- a--; b--;
- if (my_isdigit(default_charset_info, (char) *a) &&
- my_isdigit(default_charset_info, (char) *b))
- return ((int) *a - (int) *b);
- if (*a == '-' || my_isdigit(default_charset_info,(char) *b))
- return (-1);
- if (*b == '-' || *b++ == ' ' ||
- my_isdigit(default_charset_info,(char) *a))
- return (1);
- if (*a++ == ' ')
- return (-1);
- }
- }
- else
- {
- for ( ; a < end && *a == ' ' && *b == ' ' ; a++, b++) ;
- if (*a == '-' && *b == '-')
- swap_flag=1;
- if (swap_flag)
- {
- end=b+(int) (end-a);
- swap_variables(uchar*, a, b);
- }
- while (a < end)
- if (*a++ != *b++)
- {
- a--; b--;
- if (my_isdigit(default_charset_info,(char) *a) &&
- my_isdigit(default_charset_info,(char) *b))
- return ((int) *a - (int) *b);
- if (*a == '-' || my_isdigit(default_charset_info,(char) *b))
- return (-1);
- if (*b == '-' || *b++ == ' ' ||
- my_isdigit(default_charset_info,(char) *a))
- return (1);
- if (*a++ == ' ')
- return -1;
- }
- }
- if (swap_flag)
- swap_variables(uchar*, a, b);
- break;
- }
-#ifdef HAVE_LONG_LONG
- case HA_KEYTYPE_LONGLONG:
- {
- longlong ll_a,ll_b;
- longlongget(ll_a,a);
- longlongget(ll_b,b);
- if ((flag = CMP(ll_a,ll_b)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+= sizeof(longlong);
- break;
- }
- case HA_KEYTYPE_ULONGLONG:
- {
- ulonglong ll_a,ll_b;
- longlongget(ll_a,a);
- longlongget(ll_b,b);
- if ((flag = CMP(ll_a,ll_b)))
- return ((keyseg->base.flag & HA_REVERSE_SORT) ? -flag : flag);
- a= end;
- b+= sizeof(ulonglong);
- break;
- }
-#endif
- case HA_KEYTYPE_END: /* Ready */
- case HA_KEYTYPE_VARTEXT: /* Impossible */
- case HA_KEYTYPE_VARBINARY: /* Impossible */
- goto end;
- }
- }
-end:
- if (!(nextflag & SEARCH_FIND))
- {
- if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
- return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
- LINT_INIT(l_1); LINT_INIT(l_2);
- switch (keyseg->base.length) {
- case 4:
- u_1= (ulong) uint4korr(a);
- u_2= (ulong) uint4korr(b);
- break;
- case 3:
- u_1= (ulong) uint3korr(a);
- u_2= (ulong) uint3korr(b);
- break;
- case 2:
- u_1= (ulong) uint2korr(a);
- u_2= (ulong) uint2korr(b);
- break;
- default: abort(); /* Impossible */
- }
- flag = CMP(u_1,u_2);
-
- if (nextflag & SEARCH_SAME)
- return (flag); /* read same */
- if (nextflag & SEARCH_BIGGER)
- return (flag <= 0 ? -1 : 1); /* read next */
- return (flag < 0 ? -1 : 1); /* read previous */
- }
- return 0;
-} /* _nisam_key_cmp */
-
-
- /* Get key from key-block */
- /* page points at previous key; its advanced to point at next key */
- /* key should contain previous key */
- /* Returns length of found key + pointers */
- /* nod_flag is a flag if we are on nod */
-
-uint _nisam_get_key(register N_KEYDEF *keyinfo, uint nod_flag,
- register uchar **page, register uchar *key)
-{
- reg1 N_KEYSEG *keyseg;
- uchar *start,*start_key;
- uint length,c_length;
-
- LINT_INIT(start);
- start_key=key; c_length=0;
- for (keyseg=keyinfo->seg ; keyseg->base.type ;keyseg++)
- {
- if (keyseg->base.flag & (HA_SPACE_PACK | HA_PACK_KEY))
- {
- start=key;
- if (keyseg->base.flag & HA_SPACE_PACK)
- key++;
- if ((length= *(*page)++) & 128)
- {
- key+= (c_length=(length & 127));
- if (c_length == 0) /* Same key */
- {
- key+= *start; /* Same diff_key as prev */
- length=0;
- }
- else
- {
- if (keyseg->base.flag & HA_SPACE_PACK)
- length= *(*page)++;
- else
- length=keyseg->base.length-length+128; /* Rest of key */
- /* Prevent core dumps if wrong data formats */
- if (length > keyseg->base.length)
- length=0;
- }
- }
- }
- else
- length=keyseg->base.length;
- memcpy((byte*) key,(byte*) *page,(size_t) length); key+=length;
- if (keyseg->base.flag & HA_SPACE_PACK)
- *start= (uchar) ((key-start)-1);
- *page+=length;
- }
- length=keyseg->base.length+nod_flag;
- bmove((byte*) key,(byte*) *page,length);
- *page+=length;
- return((uint) (key-start_key)+keyseg->base.length);
-} /* _nisam_get_key */
-
-
- /* same as _nisam_get_key but used with fixed length keys */
-
-uint _nisam_get_static_key(register N_KEYDEF *keyinfo, uint nod_flag, register uchar **page, register uchar *key)
-{
- memcpy((byte*) key,(byte*) *page,
- (size_t) (keyinfo->base.keylength+nod_flag));
- *page+=keyinfo->base.keylength+nod_flag;
- return(keyinfo->base.keylength);
-} /* _nisam_get_static_key */
-
-
- /* Get last key from key-block, starting from keypos */
- /* Return pointer to where keystarts */
-
-uchar *_nisam_get_last_key(N_INFO *info, N_KEYDEF *keyinfo, uchar *keypos, uchar *lastkey, uchar *endpos)
-{
- uint nod_flag;
- uchar *lastpos;
-
- nod_flag=test_if_nod(keypos);
- if (! (keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)))
- {
- lastpos=endpos-keyinfo->base.keylength-nod_flag;
- if (lastpos > keypos)
- bmove((byte*) lastkey,(byte*) lastpos,keyinfo->base.keylength+nod_flag);
- }
- else
- {
- lastpos=0 ; keypos+=2+nod_flag;
- lastkey[0]=0;
- while (keypos < endpos)
- {
- lastpos=keypos;
- VOID(_nisam_get_key(keyinfo,nod_flag,&keypos,lastkey));
- }
- }
- return lastpos;
-} /* _nisam_get_last_key */
-
-
- /* Calculate length of key */
-
-uint _nisam_keylength(N_KEYDEF *keyinfo, register uchar *key)
-{
- reg1 N_KEYSEG *keyseg;
- uchar *start;
-
- if (! (keyinfo->base.flag & HA_SPACE_PACK_USED))
- return (keyinfo->base.keylength);
-
- start=key;
- for (keyseg=keyinfo->seg ; keyseg->base.type ; keyseg++)
- {
- if (keyseg->base.flag & HA_SPACE_PACK)
- key+= *key+1;
- else
- key+= keyseg->base.length;
- }
- return((uint) (key-start)+keyseg->base.length);
-} /* _nisam_keylength */
-
-
- /* Move a key */
-
-uchar *_nisam_move_key(N_KEYDEF *keyinfo, uchar *to, uchar *from)
-{
- reg1 uint length;
- memcpy((byte*) to, (byte*) from,
- (size_t) (length=_nisam_keylength(keyinfo,from)));
- return to+length;
-}
-
- /* Find next/previous record with same key */
- /* This can't be used when database is touched after last read */
-
-int _nisam_search_next(register N_INFO *info, register N_KEYDEF *keyinfo,
- uchar *key, uint nextflag, ulong pos)
-{
- int error;
- uint nod_flag;
- uchar lastkey[N_MAX_KEY_BUFF];
- DBUG_ENTER("_nisam_search_next");
- DBUG_PRINT("enter",("nextflag: %d lastpos: %d int_keypos: %lx",
- nextflag,info->lastpos,info->int_keypos));
- DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,keyinfo->seg,key););
-
- if ((nextflag & SEARCH_BIGGER && info->int_keypos >= info->int_maxpos) ||
- info->int_pos == NI_POS_ERROR || info->page_changed)
- DBUG_RETURN(_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
- pos));
-
- if (info->buff_used)
- {
- if (!_nisam_fetch_keypage(info,keyinfo,info->last_search_keypage,
- info->buff,0))
- {
- info->lastpos= NI_POS_ERROR;
- DBUG_RETURN(-1);
- }
- info->buff_used=0;
- }
-
- /* Last used buffer is in info->buff */
-
- nod_flag=test_if_nod(info->buff);
- VOID(_nisam_move_key(keyinfo,lastkey,key));
-
- if (nextflag & SEARCH_BIGGER) /* Next key */
- {
- ulong tmp_pos=_nisam_kpos(nod_flag,info->int_keypos);
- if (tmp_pos != NI_POS_ERROR)
- {
- if ((error=_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
- tmp_pos)) <=0)
- DBUG_RETURN(error);
- }
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&info->int_keypos,lastkey));
- }
- else /* Previous key */
- {
- info->int_keypos=_nisam_get_last_key(info,keyinfo,info->buff,lastkey,
- info->int_keypos);
- if (info->int_keypos == info->buff+2)
- DBUG_RETURN(_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
- pos));
- if ((error=_nisam_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF,
- _nisam_kpos(nod_flag,info->int_keypos))) <= 0)
- DBUG_RETURN(error);
- }
-
- info->int_keypos=_nisam_get_last_key(info,keyinfo,info->buff,lastkey,
- info->int_keypos);
- VOID(_nisam_move_key(keyinfo,info->lastkey,lastkey));
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&info->int_keypos,info->lastkey));
- info->lastpos=_nisam_dpos(info,nod_flag,info->int_keypos);
- DBUG_PRINT("exit",("found key at %d",info->lastpos));
- DBUG_RETURN(0);
-} /* _nisam_search_next */
-
-
- /* S|ker reda p} positionen f|r f|rsta recordet i ett index */
- /* Positionen l{ggs i info->lastpos */
-
-int _nisam_search_first(register N_INFO *info, register N_KEYDEF *keyinfo, register ulong pos)
-{
- uint nod_flag;
- uchar *page;
- DBUG_ENTER("_nisam_search_first");
-
- if (pos == NI_POS_ERROR)
- {
- my_errno=HA_ERR_KEY_NOT_FOUND;
- info->lastpos= NI_POS_ERROR;
- DBUG_RETURN(-1);
- }
-
- do
- {
- if (!_nisam_fetch_keypage(info,keyinfo,pos,info->buff,0))
- {
- info->lastpos= NI_POS_ERROR;
- DBUG_RETURN(-1);
- }
- nod_flag=test_if_nod(info->buff);
- page=info->buff+2+nod_flag;
- } while ((pos=_nisam_kpos(nod_flag,page)) != NI_POS_ERROR);
-
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&page,info->lastkey));
- info->int_keypos=page; info->int_maxpos=info->buff+getint(info->buff)-1;
- info->lastpos=_nisam_dpos(info,nod_flag,page);
- info->page_changed=info->buff_used=0;
- info->last_search_keypage=info->int_pos;
-
- DBUG_PRINT("exit",("found key at %d",info->lastpos));
- DBUG_RETURN(0);
-} /* _nisam_search_first */
-
-
- /* S|ker reda p} positionen f|r sista recordet i ett index */
- /* Positionen l{ggs i info->lastpos */
-
-int _nisam_search_last(register N_INFO *info, register N_KEYDEF *keyinfo, register ulong pos)
-{
- uint nod_flag;
- uchar *buff,*page;
- DBUG_ENTER("_nisam_search_last");
-
- if (pos == NI_POS_ERROR)
- {
- my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
- info->lastpos= NI_POS_ERROR;
- DBUG_RETURN(-1);
- }
-
- buff=info->buff;
- do
- {
- if (!_nisam_fetch_keypage(info,keyinfo,pos,buff,0))
- {
- info->lastpos= NI_POS_ERROR;
- DBUG_RETURN(-1);
- }
- page= buff+getint(buff);
- nod_flag=test_if_nod(buff);
- } while ((pos=_nisam_kpos(nod_flag,page)) != NI_POS_ERROR);
-
- VOID(_nisam_get_last_key(info,keyinfo,buff,info->lastkey,page));
- info->lastpos=_nisam_dpos(info,nod_flag,page);
- info->int_keypos=info->int_maxpos=page;
- info->page_changed=info->buff_used=0;
- info->last_search_keypage=info->int_pos;
-
- DBUG_PRINT("exit",("found key at %d",info->lastpos));
- DBUG_RETURN(0);
-} /* _nisam_search_last */
diff --git a/isam/_statrec.c b/isam/_statrec.c
deleted file mode 100644
index 9dbc948440f..00000000000
--- a/isam/_statrec.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
- /* Functions to handle fixed-length-records */
-
-#include "isamdef.h"
-
-
-int _nisam_write_static_record(N_INFO *info, const byte *record)
-{
- uchar temp[4]; /* Not sizeof(long) */
-
- if (info->s->state.dellink != NI_POS_ERROR)
- {
- ulong filepos=info->s->state.dellink;
- info->rec_cache.seek_not_done=1; /* We have done a seek */
- VOID(my_seek(info->dfile,info->s->state.dellink+1,MY_SEEK_SET,MYF(0)));
-
- if (my_read(info->dfile,(char*) &temp[0],sizeof(temp), MYF(MY_NABP)))
- goto err;
- info->s->state.dellink=uint4korr(temp);
- if (info->s->state.dellink == (uint32) ~0) /* Fix for 64 bit long */
- info->s->state.dellink=NI_POS_ERROR;
- info->s->state.del--;
- info->s->state.empty-=info->s->base.reclength;
- VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0)));
- if (my_write(info->dfile, (char*) record, info->s->base.reclength,
- MYF(MY_NABP)))
- goto err;
- }
- else
- {
- if (info->s->state.data_file_length > info->s->base.max_data_file_length)
- {
- my_errno=HA_ERR_RECORD_FILE_FULL;
- return(2);
- }
- if (info->opt_flag & WRITE_CACHE_USED)
- { /* Cash in use */
- if (my_b_write(&info->rec_cache, (byte*) record, info->s->base.reclength))
- goto err;
- }
- else
- {
- info->rec_cache.seek_not_done=1; /* We have done a seek */
- VOID(my_seek(info->dfile,info->s->state.data_file_length,
- MY_SEEK_SET,MYF(0)));
- if (my_write(info->dfile,(char*) record,info->s->base.reclength,
- MYF(MY_NABP | MY_WAIT_IF_FULL)))
- goto err;
- }
- info->s->state.data_file_length+=info->s->base.reclength;
- info->s->state.splitt++;
- }
- return 0;
- err:
- return 1;
-}
-
-int _nisam_update_static_record(N_INFO *info, ulong pos, const byte *record)
-{
- info->rec_cache.seek_not_done=1; /* We have done a seek */
- VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0)));
- return (my_write(info->dfile,(char*) record,info->s->base.reclength,
- MYF(MY_NABP)) != 0);
-}
-
-
-int _nisam_delete_static_record(N_INFO *info)
-{
- uchar temp[5]; /* 1+sizeof(uint32) */
-
- info->s->state.del++;
- info->s->state.empty+=info->s->base.reclength;
- temp[0]= '\0'; /* Mark that record is deleted */
- int4store(temp+1,info->s->state.dellink);
- info->s->state.dellink = info->lastpos;
- info->rec_cache.seek_not_done=1;
- VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0)));
- return (my_write(info->dfile,(byte*) temp,(uint) sizeof(temp),
- MYF(MY_NABP)) != 0);
-}
-
-
-int _nisam_cmp_static_record(register N_INFO *info, register const byte *old)
-{
- DBUG_ENTER("_nisam_rectest");
-
- /* We are going to do changes; dont let anybody disturb */
- dont_break(); /* Dont allow SIGHUP or SIGINT */
-
- if (info->opt_flag & WRITE_CACHE_USED)
- {
- if (flush_io_cache(&info->rec_cache))
- {
- DBUG_RETURN(-1);
- }
- info->rec_cache.seek_not_done=1; /* We have done a seek */
- }
-
- if ((info->opt_flag & READ_CHECK_USED))
- { /* If check isn't disabled */
- info->rec_cache.seek_not_done=1; /* We have done a seek */
- VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0)));
- if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength,
- MYF(MY_NABP)))
- DBUG_RETURN(-1);
- if (memcmp((byte*) info->rec_buff, (byte*) old,
- (uint) info->s->base.reclength))
- {
- DBUG_DUMP("read",old,info->s->base.reclength);
- DBUG_DUMP("disk",info->rec_buff,info->s->base.reclength);
- my_errno=HA_ERR_RECORD_CHANGED; /* Record have changed */
- DBUG_RETURN(1);
- }
- }
- DBUG_RETURN(0);
-}
-
- /* Read a fixed-length-record */
- /* Returns 0 if Ok. */
- /* 1 if record is deleted */
- /* MY_FILE_ERROR on read-error or locking-error */
-
-int _nisam_read_static_record(register N_INFO *info, register ulong pos,
- register byte *record)
-{
- int error;
-
- if (pos != NI_POS_ERROR)
- {
- if (info->opt_flag & WRITE_CACHE_USED &&
- info->rec_cache.pos_in_file <= pos &&
- flush_io_cache(&info->rec_cache))
- return(-1);
- info->rec_cache.seek_not_done=1; /* We have done a seek */
-
- error=my_pread(info->dfile,(char*) record,info->s->base.reclength,
- pos,MYF(MY_NABP)) != 0;
- if (info->s->r_locks == 0 && info->s->w_locks == 0)
- VOID(_nisam_writeinfo(info,0));
- if (! error)
- {
- if (!*record) return(1); /* Record is deleted */
- info->update|= HA_STATE_AKTIV; /* Record is read */
- my_errno=HA_ERR_RECORD_DELETED;
- return(0);
- }
- return(-1); /* Error on read */
- }
- VOID(_nisam_writeinfo(info,0)); /* No such record */
- return(-1);
-} /* _nisam_read_record */
-
-
-int _nisam_read_rnd_static_record(N_INFO *info, byte *buf,
- register ulong filepos,
- int skipp_deleted_blocks)
-{
- int locked,error,cache_read;
- uint cache_length;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("_nisam_read_rnd_static_record");
-
- cache_read=0;
- LINT_INIT(cache_length);
- if (info->opt_flag & WRITE_CACHE_USED &&
- (info->rec_cache.pos_in_file <= filepos || skipp_deleted_blocks) &&
- flush_io_cache(&info->rec_cache))
- DBUG_RETURN(-1);
- if (info->opt_flag & READ_CACHE_USED)
- { /* Cash in use */
- if (filepos == my_b_tell(&info->rec_cache) &&
- (skipp_deleted_blocks || !filepos))
- {
- cache_read=1; /* Read record using cache */
- cache_length=(uint) (info->rec_cache.read_end - info->rec_cache.read_pos);
- }
- else
- info->rec_cache.seek_not_done=1; /* Filepos is changed */
- }
-#ifndef NO_LOCKING
- locked=0;
- if (info->lock_type == F_UNLCK)
- {
- if (filepos >= share->state.data_file_length)
- { /* Test if new records */
- if (_nisam_readinfo(info,F_RDLCK,0))
- DBUG_RETURN(-1);
- locked=1;
- }
- else
- { /* We don't nead new info */
-#ifndef UNSAFE_LOCKING
- if ((! cache_read || share->base.reclength > cache_length) &&
- share->r_locks == 0 && share->w_locks == 0)
- { /* record not in cache */
- if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
- MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
- DBUG_RETURN(-1);
- locked=1;
- }
-#else
- info->tmp_lock_type=F_RDLCK;
-#endif
- }
- }
-#endif
- if (filepos >= share->state.data_file_length)
- {
-#ifndef NO_LOCKING
- DBUG_PRINT("test",("filepos: %ld (%ld) records: %ld del: %ld",
- filepos/share->base.reclength,filepos,
- share->state.records, share->state.del));
- VOID(_nisam_writeinfo(info,0));
-#endif
- my_errno=HA_ERR_END_OF_FILE;
- DBUG_RETURN(-1);
- }
- info->lastpos= filepos;
- info->nextpos= filepos+share->base.reclength;
-
- if (! cache_read) /* No cacheing */
- {
- error=_nisam_read_static_record(info,filepos,buf);
- if (error > 0)
- my_errno=HA_ERR_RECORD_DELETED;
- DBUG_RETURN(error);
- }
-
- /* Read record with cacheing */
- error=my_b_read(&info->rec_cache,(byte*) buf,share->base.reclength);
-
-#ifndef NO_LOCKING
- if (locked)
- VOID(_nisam_writeinfo(info,0)); /* Unlock keyfile */
-#endif
- if (!error)
- {
- if (!buf[0])
- { /* Record is removed */
- my_errno=HA_ERR_RECORD_DELETED;
- DBUG_RETURN(1);
- }
- /* Found and may be updated */
- info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
- DBUG_RETURN(0);
- }
- if (info->rec_cache.error != -1 || my_errno == 0)
- my_errno=HA_ERR_WRONG_IN_RECORD;
- DBUG_RETURN(-1); /* Something wrong (EOF?) */
-}
diff --git a/isam/close.c b/isam/close.c
deleted file mode 100644
index 37425653a5d..00000000000
--- a/isam/close.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* close a isam-database */
-
-#include "isamdef.h"
-
-int nisam_close(register N_INFO *info)
-{
- int error=0,flag;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("nisam_close");
- DBUG_PRINT("enter",("base: %lx reopen: %u locks: %u",
- info,(uint) share->reopen,
- (uint) (share->w_locks+share->r_locks)));
-
- pthread_mutex_lock(&THR_LOCK_isam);
- if (info->lock_type == F_EXTRA_LCK)
- info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */
-
-#ifndef NO_LOCKING
- if (info->lock_type != F_UNLCK)
- VOID(nisam_lock_database(info,F_UNLCK));
-#else
- info->lock_type=F_UNLCK;
- share->w_locks--;
- if (_nisam_writeinfo(info,test(share->changed)))
- error=my_errno;
-#endif
- pthread_mutex_lock(&share->intern_lock);
-
- if (share->base.options & HA_OPTION_READ_ONLY_DATA)
- share->r_locks--;
- if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
- {
- if (end_io_cache(&info->rec_cache))
- error=my_errno;
- info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
- }
- flag= !--share->reopen;
- nisam_open_list=list_delete(nisam_open_list,&info->open_list);
- pthread_mutex_unlock(&share->intern_lock);
-
- if (flag)
- {
- if (share->kfile >= 0 &&
- flush_key_blocks(dflt_key_cache,share->kfile,FLUSH_RELEASE))
- error=my_errno;
- if (share->kfile >= 0 && my_close(share->kfile,MYF(0)))
- error = my_errno;
-#ifdef HAVE_MMAP
- _nisam_unmap_file(info);
-#endif
- if (share->decode_trees)
- {
- my_free((gptr) share->decode_trees,MYF(0));
- my_free((gptr) share->decode_tables,MYF(0));
- }
-#ifdef THREAD
- thr_lock_delete(&share->lock);
- VOID(pthread_mutex_destroy(&share->intern_lock));
-#endif
- my_free((gptr) info->s,MYF(0));
- }
- pthread_mutex_unlock(&THR_LOCK_isam);
- if (info->dfile >= 0 && my_close(info->dfile,MYF(0)))
- error = my_errno;
-
- nisam_log_command(LOG_CLOSE,info,NULL,0,error);
- my_free((gptr) info->rec_alloc,MYF(0));
- my_free((gptr) info,MYF(0));
-
- if (error)
- {
- my_errno=error;
- DBUG_RETURN(-1);
- }
- DBUG_RETURN(0);
-} /* nisam_close */
diff --git a/isam/create.c b/isam/create.c
deleted file mode 100644
index 204d3157d00..00000000000
--- a/isam/create.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Skapar en isam-databas */
-
-#include "isamdef.h"
-#if defined(MSDOS) || defined(__WIN__)
-#ifdef __WIN__
-#include <fcntl.h>
-#else
-#include <process.h> /* Prototype for getpid */
-#endif
-#endif
-
- /*
- ** Old options is used when recreating database, from isamchk
- ** Note that the minimun reclength that MySQL allows for static rows
- ** are 5. (Will be fixed in the next generation)
- */
-
-int nisam_create(const char *name,uint keys,N_KEYDEF *keyinfo,
- N_RECINFO *recinfo,
- ulong records,ulong reloc, uint flags,uint old_options,
- ulong data_file_length)
-{
- register uint i,j;
- File dfile,file;
- int errpos,save_errno;
- uint fields,length,max_key_length,packed,pointer,reclength,min_pack_length,
- key_length,info_length,key_segs,options,min_key_length_skipp,max_block,
- base_pos;
- char buff[max(FN_REFLEN,512)];
- ulong tot_length,pack_reclength;
- enum en_fieldtype type;
- ISAM_SHARE share;
- N_KEYDEF *keydef;
- N_KEYSEG *keyseg;
- N_RECINFO *rec;
- DBUG_ENTER("nisam_create");
-
- LINT_INIT(dfile);
- pthread_mutex_lock(&THR_LOCK_isam);
- errpos=0;
- options=0;
- base_pos=512; /* Enough for N_STATE_INFO */
- bzero((byte*) &share,sizeof(share));
- if ((file = my_create(fn_format(buff,name,"",N_NAME_IEXT,4),0,
- O_RDWR | O_EXCL | O_NOFOLLOW,MYF(MY_WME))) < 0)
- goto err;
- errpos=1;
- VOID(fn_format(buff,name,"",N_NAME_DEXT,2+4));
- if (!(flags & HA_DONT_TOUCH_DATA))
- {
- if ((dfile = my_create(buff,0,O_RDWR | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
- goto err;
- errpos=2;
- }
- else if (!(old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
- options=old_options & (HA_OPTION_COMPRESS_RECORD |
- HA_OPTION_READ_ONLY_DATA | HA_OPTION_PACK_RECORD);
- if (reloc > records)
- reloc=records; /* Check if wrong parameter */
-
- /* Start by checking fields and field-types used */
- reclength=0;
- for (rec=recinfo, fields=packed=min_pack_length=0, pack_reclength=0L;
- rec->base.type != (int) FIELD_LAST;
- rec++,fields++)
- {
- reclength+=rec->base.length;
- if ((type=(enum en_fieldtype) rec->base.type))
- {
- packed++;
- if (type == FIELD_BLOB)
- {
- share.base.blobs++;
- rec->base.length-= sizeof(char*); /* Don't calc pointer */
- if (pack_reclength != NI_POS_ERROR)
- {
- if (rec->base.length == 4)
- pack_reclength= (ulong) NI_POS_ERROR;
- else
- pack_reclength+=sizeof(char*)+(1 << (rec->base.length*8));
- }
- }
- else if (type == FIELD_SKIP_PRESPACE ||
- type == FIELD_SKIP_ENDSPACE)
- {
- if (pack_reclength != NI_POS_ERROR)
- pack_reclength+= rec->base.length > 255 ? 2 : 1;
- min_pack_length++;
- }
- else if (type == FIELD_ZERO)
- packed--;
- else if (type != FIELD_SKIP_ZERO)
- {
- min_pack_length+=rec->base.length;
- packed--; /* Not a pack record type */
- }
- }
- else
- min_pack_length+=rec->base.length;
- }
- if ((packed & 7) == 1)
- { /* Bad packing, try to remove a zero-field */
- while (rec != recinfo)
- {
- rec--;
- if (rec->base.type == (int) FIELD_SKIP_ZERO && rec->base.length == 1)
- {
- rec->base.type=(int) FIELD_NORMAL;
- packed--;
- min_pack_length++;
- break;
- }
- }
- }
- if (packed && !(options & HA_OPTION_COMPRESS_RECORD))
- options|=HA_OPTION_PACK_RECORD; /* Must use packed records */
-
- packed=(packed+7)/8;
- if (pack_reclength != NI_POS_ERROR)
- pack_reclength+= reclength+packed;
- min_pack_length+=packed;
-
- if (options & HA_OPTION_COMPRESS_RECORD)
- {
- if (data_file_length >= (1L << 24))
- pointer=4;
- else if (data_file_length >= (1L << 16))
- pointer=3;
- else
- pointer=2;
- }
- else if (((records == 0L && pack_reclength < 255) ||
- options & HA_OPTION_PACK_RECORD) ||
- records >= (ulong) 16000000L ||
- pack_reclength == (ulong) NI_POS_ERROR ||
- ((options & HA_OPTION_PACK_RECORD) &&
- pack_reclength+4 >= (ulong) 14000000L/records))
- pointer=4;
- else if (records == 0L || records >= (ulong) 65000L ||
- ((options & HA_OPTION_PACK_RECORD) &&
- pack_reclength+4 >= (ulong) 60000L/records))
- pointer=3;
- else
- pointer=2;
-
- max_block=max_key_length=0; tot_length=key_segs=0;
- for (i=0, keydef=keyinfo ; i < keys ; i++ , keydef++)
- {
- share.state.key_root[i]= share.state.key_del[i]= NI_POS_ERROR;
- share.base.rec_per_key[i]= (keydef->base.flag & HA_NOSAME) ? 1L : 0L;
- min_key_length_skipp=length=0;
- key_length=pointer;
-
- if (keydef->base.flag & HA_PACK_KEY &&
- keydef->seg[0].base.length > 127)
- keydef->base.flag&= ~HA_PACK_KEY; /* Can't pack long keys */
- if (keydef->base.flag & HA_PACK_KEY)
- {
- if ((keydef->seg[0].base.flag & HA_SPACE_PACK) &&
- keydef->seg[0].base.type == (int) HA_KEYTYPE_NUM)
- keydef->seg[0].base.flag&= ~HA_SPACE_PACK;
- if (!(keydef->seg[0].base.flag & HA_SPACE_PACK))
- length++;
- keydef->seg[0].base.flag|=HA_PACK_KEY; /* for easyer intern test */
- options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
- if (!(keydef->seg[0].base.flag & HA_SPACE_PACK))
- min_key_length_skipp+=keydef->seg[0].base.length;
- }
- keydef->base.keysegs=0;
- for (keyseg=keydef->seg ; keyseg->base.type ; keyseg++)
- {
- keydef->base.keysegs++;
- if (keyseg->base.length > 127)
- keyseg->base.flag&= ~(HA_SPACE_PACK | HA_PACK_KEY);
- if (keyseg->base.flag & HA_SPACE_PACK)
- {
- keydef->base.flag |= HA_SPACE_PACK_USED;
- options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
- length++;
- min_key_length_skipp+=keyseg->base.length;
- }
- key_length+= keyseg->base.length;
- }
- bzero((gptr) keyseg,sizeof(keyseg[0]));
- keyseg->base.length=(uint16) pointer; /* Last key part is pointer */
- key_segs+=keydef->base.keysegs;
- length+=key_length;
- keydef->base.block_length=nisam_block_size;
- keydef->base.keylength= (uint16) key_length;
- keydef->base.minlength= (uint16) (length-min_key_length_skipp);
- keydef->base.maxlength= (uint16) length;
-
- if ((uint) keydef->base.block_length > max_block)
- max_block=(uint) keydef->base.block_length;
- if (length > max_key_length)
- max_key_length= length;
- tot_length+= (records/(ulong) (((uint) keydef->base.block_length-5)/
- (length*2)))*
- (ulong) keydef->base.block_length;
- }
- info_length=(uint) (base_pos+sizeof(N_BASE_INFO)+keys*sizeof(N_SAVE_KEYDEF)+
- (keys+key_segs)*sizeof(N_SAVE_KEYSEG)+
- fields*sizeof(N_SAVE_RECINFO));
-
- bmove(share.state.header.file_version,(byte*) nisam_file_magic,4);
- old_options=options| (old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
- HA_OPTION_COMPRESS_RECORD |
- HA_OPTION_TEMP_COMPRESS_RECORD: 0);
- int2store(share.state.header.options,old_options);
- int2store(share.state.header.header_length,info_length);
- int2store(share.state.header.state_info_length,sizeof(N_STATE_INFO));
- int2store(share.state.header.base_info_length,sizeof(N_BASE_INFO));
- int2store(share.state.header.base_pos,base_pos);
-
- share.state.dellink = NI_POS_ERROR;
- share.state.process= (ulong) getpid();
- share.state.uniq= (ulong) file;
- share.state.loop= 0;
- share.state.version= (ulong) time((time_t*) 0);
- share.base.options=options;
- share.base.rec_reflength=pointer;
- share.base.key_reflength=((!tot_length || tot_length > 30000000L) ? 3 :
- tot_length > 120000L ? 2 : 1);
- share.base.keys= share.state.keys = keys;
- share.base.keystart = share.state.key_file_length=MY_ALIGN(info_length,
- nisam_block_size);
- share.base.max_block=max_block;
- share.base.max_key_length=(uint) ALIGN_SIZE(max_key_length+4);
- share.base.records=records;
- share.base.reloc=reloc;
- share.base.reclength=reclength;
- share.base.pack_reclength=
- (uint) (reclength+packed-share.base.blobs*sizeof(char*));
- share.base.max_pack_length=pack_reclength;
- share.base.min_pack_length=min_pack_length;
- share.base.pack_bits=packed;
- share.base.fields=fields;
- share.base.pack_fields=packed;
- share.base.sortkey= (ushort) ~0;
- share.base.max_data_file_length= (pointer == 4) ? (ulong) ~0L :
- (options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
- (ulong) (1L << (pointer*8)) :
- (pointer == 3 && reclength >= 256L) ? (ulong) NI_POS_ERROR :
- ((ulong) reclength * (1L << (pointer*8)));
- share.base.max_key_file_length= (share.base.key_reflength == 3 ?
- NI_POS_ERROR :
- (ulong)
- (1L << (share.base.key_reflength*8))*512);
- share.base.min_block_length=
- (share.base.pack_reclength+3 < N_EXTEND_BLOCK_LENGTH &&
- ! share.base.blobs) ?
- max(share.base.pack_reclength,N_MIN_BLOCK_LENGTH) :
- N_EXTEND_BLOCK_LENGTH;
- if (! (flags & HA_DONT_TOUCH_DATA))
- share.base.create_time= (long) time((time_t*) 0);
-
- bzero(buff,base_pos);
- if (my_write(file,(char*) &share.state,sizeof(N_STATE_INFO),MYF(MY_NABP)) ||
- my_write(file,buff,base_pos-sizeof(N_STATE_INFO),MYF(MY_NABP)) ||
- my_write(file,(char*) &share.base,sizeof(N_BASE_INFO),MYF(MY_NABP)))
- goto err;
-
- for (i=0 ; i < share.base.keys ; i++)
- {
- if (my_write(file,(char*) &keyinfo[i].base,sizeof(N_SAVE_KEYDEF),
- MYF(MY_NABP)))
- goto err;
- for (j=0 ; j <= keyinfo[i].base.keysegs ; j++)
- {
- if (my_write(file,(char*) &keyinfo[i].seg[j].base,sizeof(N_SAVE_KEYSEG),
- MYF(MY_NABP)))
- goto err;
- }
- }
- for (i=0 ; i < share.base.fields ; i++)
- if (my_write(file,(char*) &recinfo[i].base, (uint) sizeof(N_SAVE_RECINFO),
- MYF(MY_NABP)))
- goto err;
-
- /* Enlarge files */
- if (my_chsize(file, (ulong) share.base.keystart, 0, MYF(0)))
- goto err;
-
- if (! (flags & HA_DONT_TOUCH_DATA))
- {
-#ifdef USE_RELOC
- if (my_chsize(dfile, share.base.min_pack_length*reloc, 0, MYF(0)))
- goto err;
-#endif
- errpos=1;
- if (my_close(dfile,MYF(0)))
- goto err;
- }
- errpos=0;
- pthread_mutex_unlock(&THR_LOCK_isam);
- if (my_close(file,MYF(0)))
- goto err;
- DBUG_RETURN(0);
-
-err:
- pthread_mutex_unlock(&THR_LOCK_isam);
- save_errno=my_errno;
- switch (errpos) {
- case 2:
- VOID(my_close(dfile,MYF(0)));
- /* fall through */
- case 1:
- VOID(my_close(file,MYF(0)));
- }
- my_errno=save_errno; /* R{tt felkod tillbaka */
- DBUG_RETURN(-1);
-} /* nisam_create */
diff --git a/isam/delete.c b/isam/delete.c
deleted file mode 100644
index 5aa542561c1..00000000000
--- a/isam/delete.c
+++ /dev/null
@@ -1,615 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Tar bort ett record fr}n en isam-databas */
-
-#include "isamdef.h"
-#ifdef __WIN__
-#include <errno.h>
-#endif
-#include <assert.h>
-
-static int d_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,ulong page,
- uchar *anc_buff);
-static int del(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,uchar *anc_buff,
- ulong leaf_page,uchar *leaf_buff,uchar *keypos,
- ulong next_block,uchar *ret_key);
-static int underflow(N_INFO *info,N_KEYDEF *keyinfo,uchar *anc_buff,
- ulong leaf_page, uchar *leaf_buff,uchar *keypos);
-static uint remove_key(N_KEYDEF *keyinfo,uint nod_flag,uchar *keypos,
- uchar *lastkey,uchar *page_end);
-
-
-int nisam_delete(N_INFO *info,const byte *record)
-{
- uint i;
- uchar *old_key;
- int save_errno;
- uint32 lastpos;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("nisam_delete");
-
- /* Test if record is in datafile */
-
- if (!(info->update & HA_STATE_AKTIV))
- {
- my_errno=HA_ERR_KEY_NOT_FOUND; /* No database read */
- DBUG_RETURN(-1);
- }
- if (share->base.options & HA_OPTION_READ_ONLY_DATA)
- {
- my_errno=EACCES;
- DBUG_RETURN(-1);
- }
-#ifndef NO_LOCKING
- if (_nisam_readinfo(info,F_WRLCK,1)) DBUG_RETURN(-1);
-#endif
- if ((*share->compare_record)(info,record))
- goto err; /* Fel vid kontroll-l{sning */
-
- /* Remove all keys from the .ISAM file */
-
- old_key=info->lastkey+share->base.max_key_length;
- for (i=0 ; i < share->state.keys ; i++ )
- {
- VOID(_nisam_make_key(info,i,old_key,record,info->lastpos));
- if (_nisam_ck_delete(info,i,old_key)) goto err;
- }
-
- if ((*share->delete_record)(info))
- goto err; /* Remove record from database */
-
- info->update= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_DELETED;
- share->state.records--;
-
- lastpos= (uint32) info->lastpos;
- nisam_log_command(LOG_DELETE,info,(byte*) &lastpos,sizeof(lastpos),0);
- VOID(_nisam_writeinfo(info,1));
- allow_break(); /* Allow SIGHUP & SIGINT */
- DBUG_RETURN(0);
-
-err:
- save_errno=my_errno;
- lastpos= (uint32) info->lastpos;
- nisam_log_command(LOG_DELETE,info,(byte*) &lastpos, sizeof(lastpos),0);
- VOID(_nisam_writeinfo(info,1));
- info->update|=HA_STATE_WRITTEN; /* Buffer changed */
- allow_break(); /* Allow SIGHUP & SIGINT */
- my_errno=save_errno;
- if (save_errno == HA_ERR_KEY_NOT_FOUND)
- my_errno=HA_ERR_CRASHED;
-
- DBUG_RETURN(-1);
-} /* nisam_delete */
-
-
- /* Tar bort en nyckel till isam-nyckelfilen */
-
-int _nisam_ck_delete(register N_INFO *info, uint keynr, uchar *key)
-{
- int error;
- uint nod_flag;
- ulong old_root;
- uchar *root_buff;
- N_KEYDEF *keyinfo;
- DBUG_ENTER("_nisam_ck_delete");
-
- if ((old_root=info->s->state.key_root[keynr]) == NI_POS_ERROR)
- {
- my_errno=HA_ERR_CRASHED;
- DBUG_RETURN(-1);
- }
- keyinfo=info->s->keyinfo+keynr;
- if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
- N_MAX_KEY_BUFF*2)))
- DBUG_RETURN(-1);
- if (!_nisam_fetch_keypage(info,keyinfo,old_root,root_buff,0))
- {
- error= -1;
- goto err;
- }
- if ((error=d_search(info,keyinfo,key,old_root,root_buff)) >0)
- {
- if (error == 2)
- {
- DBUG_PRINT("test",("Enlarging of root when deleting"));
- error=_nisam_enlarge_root(info,keynr,key);
- }
- else
- {
- error=0;
- if (getint(root_buff) <= (nod_flag=test_if_nod(root_buff))+3)
- {
- if (nod_flag)
- info->s->state.key_root[keynr]=_nisam_kpos(nod_flag,
- root_buff+2+nod_flag);
- else
- info->s->state.key_root[keynr]= NI_POS_ERROR;
- if (_nisam_dispose(info,keyinfo,old_root))
- error= -1;
- }
- }
- }
-err:
- my_afree((gptr) root_buff);
- DBUG_RETURN(error);
-} /* _nisam_ck_delete */
-
-
- /* Tar bort en nyckel under root */
- /* Returnerar 1 om nuvarande buffert minskade */
- /* Returnerar 2 om nuvarande buffert |kar */
-
-static int d_search(register N_INFO *info, register N_KEYDEF *keyinfo, uchar *key, ulong page, uchar *anc_buff)
-{
- int flag,ret_value,save_flag;
- uint length,nod_flag;
- uchar *leaf_buff,*keypos,*next_keypos;
- ulong leaf_page,next_block;
- uchar lastkey[N_MAX_KEY_BUFF];
- DBUG_ENTER("d_search");
- DBUG_DUMP("page",(byte*) anc_buff,getint(anc_buff));
-
- flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,0,SEARCH_SAME,&keypos,
- lastkey);
- nod_flag=test_if_nod(anc_buff);
-
- leaf_buff=0;
- LINT_INIT(leaf_page);
- if (nod_flag)
- {
- leaf_page=_nisam_kpos(nod_flag,keypos);
- if (!(leaf_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
- N_MAX_KEY_BUFF*2)))
- {
- my_errno=ENOMEM;
- DBUG_RETURN(-1);
- }
- if (!_nisam_fetch_keypage(info,keyinfo,leaf_page,leaf_buff,0))
- goto err;
- }
-
- if (flag != 0)
- {
- if (!nod_flag)
- {
- my_errno=HA_ERR_CRASHED; /* This should newer happend */
- goto err;
- }
- save_flag=0;
- ret_value=d_search(info,keyinfo,key,leaf_page,leaf_buff);
- }
- else
- { /* Found key */
- next_keypos=keypos; /* Find where next block is */
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&next_keypos,lastkey));
- next_block=_nisam_kpos(nod_flag,next_keypos);
- length=getint(anc_buff);
- length-= remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length);
- putint(anc_buff,length,nod_flag);
- if (!nod_flag)
- { /* On leaf page */
- if (_nisam_write_keypage(info,keyinfo,page,anc_buff))
- DBUG_RETURN(-1);
- DBUG_RETURN(length <= (uint) keyinfo->base.block_length/2);
- }
- save_flag=1;
- ret_value=del(info,keyinfo,key,anc_buff,leaf_page,leaf_buff,keypos,
- next_block,lastkey);
- }
- if (ret_value >0)
- {
- save_flag=1;
- if (ret_value == 1)
- ret_value= underflow(info,keyinfo,anc_buff,leaf_page,leaf_buff,keypos);
- else
- { /* This happens only with packed keys */
- DBUG_PRINT("test",("Enlarging of key when deleting"));
- VOID(_nisam_get_last_key(info,keyinfo,anc_buff,lastkey,keypos));
- ret_value=_nisam_insert(info,keyinfo,key,anc_buff,keypos,lastkey,
- (uchar*) 0,(uchar*) 0,0L);
- }
- }
- if (ret_value == 0 && getint(anc_buff) > keyinfo->base.block_length)
- {
- save_flag=1;
- ret_value=_nisam_splitt_page(info,keyinfo,key,anc_buff,lastkey) | 2;
- }
- if (save_flag)
- ret_value|=_nisam_write_keypage(info,keyinfo,page,anc_buff);
- else
- {
- DBUG_DUMP("page",(byte*) anc_buff,getint(anc_buff));
- }
- my_afree((byte*) leaf_buff);
- DBUG_RETURN(ret_value);
-err:
- my_afree((byte*) leaf_buff);
- DBUG_PRINT("exit",("Error: %d",my_errno));
- DBUG_RETURN (-1);
-} /* d_search */
-
-
- /* Remove a key that has a page-reference */
-
-static int del(register N_INFO *info, register N_KEYDEF *keyinfo, uchar *key,
- uchar *anc_buff, ulong leaf_page, uchar *leaf_buff,
- uchar *keypos, /* Pos to where deleted key was */
- ulong next_block,
- uchar *ret_key) /* key before keypos in anc_buff */
-{
- int ret_value,length;
- uint a_length,nod_flag;
- ulong next_page;
- uchar keybuff[N_MAX_KEY_BUFF],*endpos,*next_buff,*key_start;
- ISAM_SHARE *share=info->s;
- S_PARAM s_temp;
- DBUG_ENTER("del");
- DBUG_PRINT("enter",("leaf_page: %ld keypos: %lx",leaf_page,keypos));
- DBUG_DUMP("leaf_buff",(byte*) leaf_buff,getint(leaf_buff));
-
- endpos=leaf_buff+getint(leaf_buff);
- key_start=_nisam_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos);
-
- if ((nod_flag=test_if_nod(leaf_buff)))
- {
- next_page= _nisam_kpos(nod_flag,endpos);
- if (!(next_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
- N_MAX_KEY_BUFF)))
- DBUG_RETURN(-1);
- if (!_nisam_fetch_keypage(info,keyinfo,next_page,next_buff,0))
- ret_value= -1;
- else
- {
- DBUG_DUMP("next_page",(byte*) next_buff,getint(next_buff));
- if ((ret_value=del(info,keyinfo,key,anc_buff,next_page,next_buff,
- keypos,next_block,ret_key)) >0)
- {
- endpos=leaf_buff+getint(leaf_buff);
- if (ret_value == 1)
- {
- ret_value=underflow(info,keyinfo,leaf_buff,next_page,
- next_buff,endpos);
- if (ret_value == 0 && getint(leaf_buff) > keyinfo->base.block_length)
- {
- ret_value=_nisam_splitt_page(info,keyinfo,key,leaf_buff,ret_key) | 2;
- }
- }
- else
- {
- DBUG_PRINT("test",("Inserting of key when deleting"));
- VOID(_nisam_get_last_key(info,keyinfo,leaf_buff,keybuff,endpos));
- ret_value=_nisam_insert(info,keyinfo,key,leaf_buff,endpos,keybuff,
- (uchar*) 0,(uchar*) 0,0L);
- }
- }
- if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
- goto err;
- }
- my_afree((byte*) next_buff);
- DBUG_RETURN(ret_value);
- }
-
- /* Remove last key from leaf page */
-
- putint(leaf_buff,key_start-leaf_buff,nod_flag);
- if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
- goto err;
-
- /* Place last key in ancestor page on deleted key position */
-
- a_length=getint(anc_buff);
- endpos=anc_buff+a_length;
- VOID(_nisam_get_last_key(info,keyinfo,anc_buff,ret_key,keypos));
- length=_nisam_get_pack_key_length(keyinfo,share->base.key_reflength,
- keypos == endpos ? (uchar*) 0 : keypos,
- ret_key,keybuff,&s_temp);
- if (length > 0)
- bmove_upp((byte*) endpos+length,(byte*) endpos,(uint) (endpos-keypos));
- else
- bmove(keypos,keypos-length, (int) (endpos-keypos)+length);
- _nisam_store_key(keyinfo,keypos,&s_temp);
- /* Save pointer to next leaf */
- VOID((*keyinfo->get_key)(keyinfo,share->base.key_reflength,&keypos,ret_key));
- _nisam_kpointer(info,keypos - share->base.key_reflength,next_block);
- putint(anc_buff,a_length+length,share->base.key_reflength);
-
- DBUG_RETURN( getint(leaf_buff) <= (uint) keyinfo->base.block_length/2 );
-err:
- DBUG_RETURN(-1);
-} /* del */
-
-
- /* Balances adjacent pages if underflow occours */
-
-static int underflow(register N_INFO *info, register N_KEYDEF *keyinfo,
- uchar *anc_buff,
- ulong leaf_page, /* Ancestor page and underflow page */
- uchar *leaf_buff,
- uchar *keypos) /* Position to pos after key */
-{
- int t_length;
- uint length,anc_length,buff_length,leaf_length,p_length,s_length,nod_flag;
- ulong next_page;
- uchar anc_key[N_MAX_KEY_BUFF],leaf_key[N_MAX_KEY_BUFF],
- *buff,*endpos,*next_keypos,*half_pos,*temp_pos;
- S_PARAM s_temp;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("underflow");
- DBUG_PRINT("enter",("leaf_page: %ld keypos: %lx",leaf_page,keypos));
- DBUG_DUMP("anc_buff",(byte*) anc_buff,getint(anc_buff));
- DBUG_DUMP("leaf_buff",(byte*) leaf_buff,getint(leaf_buff));
-
- buff=info->buff;
- next_keypos=keypos;
- nod_flag=test_if_nod(leaf_buff);
- p_length=2+nod_flag;
- anc_length=getint(anc_buff);
- leaf_length=getint(leaf_buff);
- info->page_changed=1;
-
- if ((keypos < anc_buff+anc_length && (share->rnd++ & 1)) ||
- keypos == anc_buff+2+share->base.key_reflength)
- { /* Use page right of anc-page */
- DBUG_PRINT("test",("use right page"));
-
- VOID((*keyinfo->get_key)(keyinfo,share->base.key_reflength,&next_keypos,
- buff));
- next_page= _nisam_kpos(share->base.key_reflength,next_keypos);
- if (!_nisam_fetch_keypage(info,keyinfo,next_page,buff,0))
- goto err;
- buff_length=getint(buff);
- DBUG_DUMP("next",(byte*) buff,buff_length);
-
- /* find keys to make a big key-page */
- bmove((byte*) next_keypos-share->base.key_reflength,(byte*) buff+2,
- share->base.key_reflength);
- VOID(_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,next_keypos));
- VOID(_nisam_get_last_key(info,keyinfo,leaf_buff,leaf_key,
- leaf_buff+leaf_length));
-
- /* merge pages and put parting key from anc_buff between */
- t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag,buff+p_length,
- (leaf_length == nod_flag+2 ?
- (uchar*) 0 : leaf_key),
- anc_key,&s_temp);
- length=buff_length-p_length;
- endpos=buff+length+leaf_length+t_length;
- bmove_upp((byte*) endpos, (byte*) buff+buff_length,length);
- memcpy((byte*) buff, (byte*) leaf_buff,(size_t) leaf_length);
- _nisam_store_key(keyinfo,buff+leaf_length,&s_temp);
- buff_length=(uint) (endpos-buff);
- putint(buff,buff_length,nod_flag);
-
- /* remove key from anc_buff */
-
- s_length=remove_key(keyinfo,share->base.key_reflength,keypos,anc_key,
- anc_buff+anc_length);
- putint(anc_buff,(anc_length-=s_length),share->base.key_reflength);
-
- if (buff_length <= keyinfo->base.block_length)
- { /* Keys in one page */
- memcpy((byte*) leaf_buff,(byte*) buff,(size_t) buff_length);
- if (_nisam_dispose(info,keyinfo,next_page))
- goto err;
- }
- else
- { /* Page is full */
- VOID(_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,keypos));
- half_pos=_nisam_find_half_pos(info,keyinfo,buff,leaf_key);
- length=(uint) (half_pos-buff);
- memcpy((byte*) leaf_buff,(byte*) buff,(size_t) length);
- putint(leaf_buff,length,nod_flag);
- endpos=anc_buff+anc_length;
-
- /* Correct new keypointer to leaf_page */
- length=(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key);
- _nisam_kpointer(info,leaf_key+length,next_page);
- /* Save key in anc_buff */
- t_length=(int) _nisam_get_pack_key_length(keyinfo,
- share->base.key_reflength,
- keypos == endpos ?
- (uchar*) 0 : keypos,
- anc_key,leaf_key,&s_temp);
- if (t_length >= 0)
- bmove_upp((byte*) endpos+t_length,(byte*) endpos,
- (uint) (endpos-keypos));
- else
- bmove(keypos,keypos-t_length,(uint) (endpos-keypos)+t_length);
- _nisam_store_key(keyinfo,keypos,&s_temp);
- putint(anc_buff,(anc_length+=t_length),share->base.key_reflength);
-
- /* Store new page */
- if (nod_flag)
- bmove((byte*) buff+2,(byte*) half_pos-nod_flag,(size_t) nod_flag);
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key));
- t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag,(uchar*) 0,
- (uchar*) 0, leaf_key,&s_temp);
- s_temp.n_length= *half_pos; /* For _nisam_store_key */
- length=(uint) ((buff+getint(buff))-half_pos);
- bmove((byte*) buff+p_length+t_length,(byte*) half_pos,(size_t) length);
- _nisam_store_key(keyinfo,buff+p_length,&s_temp);
- putint(buff,length+t_length+p_length,nod_flag);
-
- if (_nisam_write_keypage(info,keyinfo,next_page,buff))
- goto err;
- }
- if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
- goto err;
- DBUG_RETURN(anc_length <= (uint) keyinfo->base.block_length/2);
- }
-
- DBUG_PRINT("test",("use left page"));
-
- keypos=_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,keypos);
- next_page= _nisam_kpos(share->base.key_reflength,keypos);
- if (!_nisam_fetch_keypage(info,keyinfo,next_page,buff,0))
- goto err;
- buff_length=getint(buff);
- endpos=buff+buff_length;
- DBUG_DUMP("prev",(byte*) buff,buff_length);
-
- /* find keys to make a big key-page */
- bmove((byte*) next_keypos - share->base.key_reflength,(byte*) leaf_buff+2,
- share->base.key_reflength);
- next_keypos=keypos;
- VOID((*keyinfo->get_key)(keyinfo,share->base.key_reflength,&next_keypos,
- anc_key));
- VOID(_nisam_get_last_key(info,keyinfo,buff,leaf_key,endpos));
-
- /* merge pages and put parting key from anc_buff between */
- t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag,
- leaf_buff+p_length,
- (leaf_length == nod_flag+2 ?
- (uchar*) 0 : leaf_key),
- anc_key,&s_temp);
- if (t_length >= 0)
- bmove((byte*) endpos+t_length,(byte*) leaf_buff+p_length,
- (size_t) (leaf_length-p_length));
- else /* We gained space */
- bmove((byte*) endpos,(byte*) leaf_buff+((int) p_length-t_length),
- (size_t) (leaf_length-p_length+t_length));
-
- _nisam_store_key(keyinfo,endpos,&s_temp);
- buff_length=buff_length+leaf_length-p_length+t_length;
- putint(buff,buff_length,nod_flag);
-
- /* remove key from anc_buff */
- s_length=remove_key(keyinfo,share->base.key_reflength,keypos,anc_key,
- anc_buff+anc_length);
- putint(anc_buff,(anc_length-=s_length),share->base.key_reflength);
-
- if (buff_length <= keyinfo->base.block_length)
- { /* Keys in one page */
- if (_nisam_dispose(info,keyinfo,leaf_page))
- goto err;
- }
- else
- { /* Page is full */
- VOID(_nisam_get_last_key(info,keyinfo,anc_buff,anc_key,keypos));
- endpos=half_pos=_nisam_find_half_pos(info,keyinfo,buff,leaf_key);
-
- /* Correct new keypointer to leaf_page */
- length=(*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key);
- _nisam_kpointer(info,leaf_key+length,leaf_page);
- /* Save key in anc_buff */
- DBUG_DUMP("anc_buff",(byte*) anc_buff,anc_length);
- DBUG_DUMP("key",(byte*) leaf_key,16);
-
- temp_pos=anc_buff+anc_length;
- t_length=(int) _nisam_get_pack_key_length(keyinfo,
- share->base.key_reflength,
- keypos == temp_pos ? (uchar*) 0
- : keypos,
- anc_key,leaf_key,&s_temp);
- if (t_length > 0)
- bmove_upp((byte*) temp_pos+t_length,(byte*) temp_pos,
- (uint) (temp_pos-keypos));
- else
- bmove(keypos,keypos-t_length,(uint) (temp_pos-keypos)+t_length);
- _nisam_store_key(keyinfo,keypos,&s_temp);
- putint(anc_buff,(anc_length+=t_length),share->base.key_reflength);
-
- /* Store new page */
- if (nod_flag)
- bmove((byte*) leaf_buff+2,(byte*) half_pos-nod_flag,(size_t) nod_flag);
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&half_pos,leaf_key));
- t_length=(int) _nisam_get_pack_key_length(keyinfo,nod_flag, (uchar*) 0,
- (uchar*) 0, leaf_key, &s_temp);
- s_temp.n_length= *half_pos; /* For _nisam_store_key */
- length=(uint) ((buff+buff_length)-half_pos);
- bmove((byte*) leaf_buff+p_length+t_length,(byte*) half_pos,
- (size_t) length);
- _nisam_store_key(keyinfo,leaf_buff+p_length,&s_temp);
- putint(leaf_buff,length+t_length+p_length,nod_flag);
- putint(buff,endpos-buff,nod_flag);
- if (_nisam_write_keypage(info,keyinfo,leaf_page,leaf_buff))
- goto err;
- }
- if (_nisam_write_keypage(info,keyinfo,next_page,buff))
- goto err;
- DBUG_RETURN(anc_length <= (uint) keyinfo->base.block_length/2);
-err:
- DBUG_RETURN(-1);
-} /* underflow */
-
-
- /* remove a key from packed buffert */
- /* returns how many chars was removed */
-
-static uint remove_key(N_KEYDEF *keyinfo, uint nod_flag,
- uchar *keypos, /* Where key starts */
- uchar *lastkey, /* key to be removed */
- uchar *page_end) /* End of page */
-{
- int r_length,s_length,first,diff_flag;
- uchar *start;
- DBUG_ENTER("remove_key");
- DBUG_PRINT("enter",("keypos: %lx page_end: %lx",keypos,page_end));
-
- start=keypos;
- if (!(keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)))
- s_length=(int) (keyinfo->base.keylength+nod_flag);
- else
- { /* Let keypos point at next key */
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey));
- s_length=(uint) (keypos-start);
- if (keyinfo->base.flag & HA_PACK_KEY)
- {
- diff_flag= (keyinfo->seg[0].base.flag & HA_SPACE_PACK);
- first= *start;
- if (keypos != page_end && *keypos & 128 && first != 128)
- { /* Referens length */
- if ((r_length= *keypos++ & 127) == 0)
- { /* Same key after */
- if (first & 128)
- start++; /* Skip ref length */
- if (diff_flag)
- start+= *start+1; /* Skip key length */
- else
- start+=keyinfo->seg[0].base.length- (first & 127);
- s_length=(uint)(keypos-start); /* Remove pntrs and next-key-flag */
- }
- else if (! (first & 128))
- { /* Deleted key was not compressed */
- if (diff_flag)
- {
- *start= (uchar) (r_length+ *keypos);
- start+=r_length+1; /* Let ref-part remain */
- s_length=(uint) (keypos-start)+1; /* Skip everything between */
- }
- else
- {
- start+=r_length+1; /* Let ref-part remain */
- s_length=(uint) (keypos-start); /* Skip everything between */
- }
- }
- else if ((first & 127) < r_length)
- { /* mid-part of key is used */
- r_length-=(first & 127);
- start++; /* Ref remains the same */
- if (diff_flag)
- *start++= (uchar) (*keypos++ + r_length);
- start+= r_length;
- s_length=(uint) (keypos-start); /* Skip everything between */
- }
- }
- }
- }
- bmove((byte*) start,(byte*) start+s_length,
- (uint) (page_end-start-s_length));
- DBUG_RETURN((uint) s_length);
-} /* remove_key */
diff --git a/isam/extra.c b/isam/extra.c
deleted file mode 100644
index 421404311c8..00000000000
--- a/isam/extra.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Extra functions we want to do with a database */
-/* - Set flags for quicker databasehandler */
-/* - Set databasehandler to normal */
-/* - Reset recordpointers as after open database */
-
-#include "isamdef.h"
-#ifdef HAVE_MMAP
-#include <sys/mman.h>
-#endif
-#ifdef __WIN__
-#include <errno.h>
-#endif
-
- /* set extra flags for database */
-
-int nisam_extra(N_INFO *info, enum ha_extra_function function)
-{
- int error=0;
- DBUG_ENTER("nisam_extra");
-
- switch (function) {
- case HA_EXTRA_RESET:
- if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
- {
- info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
- error=end_io_cache(&info->rec_cache);
- }
- info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
-
- case HA_EXTRA_RESET_STATE:
- info->lastinx= 0; /* Use first index as def */
- info->int_pos=info->lastpos= NI_POS_ERROR;
- info->page_changed=1;
- /* Next/prev gives first/last */
- if (info->opt_flag & READ_CACHE_USED)
- {
- VOID(flush_io_cache(&info->rec_cache));
- reinit_io_cache(&info->rec_cache,READ_CACHE,0,
- (pbool) (info->lock_type != F_UNLCK),
- (pbool) test(info->update & HA_STATE_ROW_CHANGED));
- }
- info->update=((info->update & HA_STATE_CHANGED) |
- HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
- break;
- case HA_EXTRA_CACHE:
-#ifndef NO_LOCKING
- if (info->lock_type == F_UNLCK && (info->options & HA_OPTION_PACK_RECORD))
- {
- error=1; /* Not possibly if not locked */
- my_errno=EACCES;
- break;
- }
-#endif
-#if defined(HAVE_MMAP) && defined(HAVE_MADVICE)
- if ((info->options & HA_OPTION_COMPRESS_RECORD))
- {
- pthread_mutex_lock(&info->s->intern_lock);
- if (_nisam_memmap_file(info))
- {
- /* We don't nead MADV_SEQUENTIAL if small file */
- madvise(info->s->file_map,info->s->state.data_file_length,
- info->s->state.data_file_length <= RECORD_CACHE_SIZE*16 ?
- MADV_RANDOM : MADV_SEQUENTIAL);
- pthread_mutex_unlock(&info->s->intern_lock);
- break;
- }
- pthread_mutex_unlock(&info->s->intern_lock);
- }
-#endif
- if (info->opt_flag & WRITE_CACHE_USED)
- {
- info->opt_flag&= ~WRITE_CACHE_USED;
- if ((error=end_io_cache(&info->rec_cache)))
- break;
- }
- if (!(info->opt_flag &
- (READ_CACHE_USED | WRITE_CACHE_USED | MEMMAP_USED)))
- {
- if (!(init_io_cache(&info->rec_cache,info->dfile,
- (uint) min(info->s->state.data_file_length+1,
- my_default_record_cache_size),
- READ_CACHE,0L,(pbool) (info->lock_type != F_UNLCK),
- MYF(MY_WAIT_IF_FULL))))
- {
- info->opt_flag|=READ_CACHE_USED;
- info->update&= ~HA_STATE_ROW_CHANGED;
- }
- /* info->rec_cache.end_of_file=info->s->state.data_file_length; */
- }
- break;
- case HA_EXTRA_REINIT_CACHE:
- if (info->opt_flag & READ_CACHE_USED)
- {
- reinit_io_cache(&info->rec_cache,READ_CACHE,info->nextpos,
- (pbool) (info->lock_type != F_UNLCK),
- (pbool) test(info->update & HA_STATE_ROW_CHANGED));
- info->update&= ~HA_STATE_ROW_CHANGED;
- /* info->rec_cache.end_of_file=info->s->state.data_file_length; */
- }
- break;
- case HA_EXTRA_WRITE_CACHE:
-#ifndef NO_LOCKING
- if (info->lock_type == F_UNLCK)
- {
- error=1; /* Not possibly if not locked */
- break;
- }
-#endif
- if (!(info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)))
- {
- if (!(init_io_cache(&info->rec_cache,info->dfile,0,
- WRITE_CACHE,info->s->state.data_file_length,
- (pbool) (info->lock_type != F_UNLCK),
- MYF(MY_WAIT_IF_FULL))))
- {
- info->opt_flag|=WRITE_CACHE_USED;
- info->update&= ~HA_STATE_ROW_CHANGED;
- }
- }
- break;
- case HA_EXTRA_PREPARE_FOR_UPDATE:
- if (info->s->data_file_type != DYNAMIC_RECORD)
- break;
- /* Remove read/write cache if dynamic rows */
- case HA_EXTRA_NO_CACHE:
- if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
- {
- info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
- error=end_io_cache(&info->rec_cache);
- }
-#if defined(HAVE_MMAP) && defined(HAVE_MADVICE)
- if (info->opt_flag & MEMMAP_USED)
- madvise(info->s->file_map,info->s->state.data_file_length,MADV_RANDOM);
-#endif
- break;
- case HA_EXTRA_FLUSH_CACHE:
- if (info->opt_flag & WRITE_CACHE_USED)
- error=flush_io_cache(&info->rec_cache);
- break;
- case HA_EXTRA_NO_READCHECK:
- info->opt_flag&= ~READ_CHECK_USED; /* No readcheck */
- break;
- case HA_EXTRA_READCHECK:
- info->opt_flag|= READ_CHECK_USED;
- break;
- case HA_EXTRA_KEYREAD: /* Read only keys to record */
- case HA_EXTRA_REMEMBER_POS:
- info->opt_flag |= REMEMBER_OLD_POS;
- bmove((byte*) info->lastkey+info->s->base.max_key_length*2,
- (byte*) info->lastkey,info->s->base.max_key_length);
- info->save_update= info->update;
- info->save_lastinx= info->lastinx;
- info->save_lastpos= info->lastpos;
- if (function == HA_EXTRA_REMEMBER_POS)
- break;
- /* fall through */
- case HA_EXTRA_KEYREAD_CHANGE_POS:
- info->opt_flag |= KEY_READ_USED;
- info->read_record=_nisam_read_key_record;
- break;
- case HA_EXTRA_NO_KEYREAD:
- case HA_EXTRA_RESTORE_POS:
- if (info->opt_flag & REMEMBER_OLD_POS)
- {
- bmove((byte*) info->lastkey,
- (byte*) info->lastkey+info->s->base.max_key_length*2,
- info->s->base.max_key_length);
- info->update= info->save_update | HA_STATE_WRITTEN;
- info->lastinx= info->save_lastinx;
- info->lastpos= info->save_lastpos;
- }
- info->read_record= info->s->read_record;
- info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
- break;
- case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes */
- info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
- break;
- case HA_EXTRA_WAIT_LOCK:
- info->lock_wait=0;
- break;
- case HA_EXTRA_NO_WAIT_LOCK:
- info->lock_wait=MY_DONT_WAIT;
- break;
- case HA_EXTRA_NO_KEYS:
-#ifndef NO_LOCKING
- if (info->lock_type == F_UNLCK)
- {
- error=1; /* Not possibly if not lock */
- break;
- }
-#endif
- info->s->state.keys=0;
- info->s->state.key_file_length=info->s->base.keystart;
- info->s->changed=1; /* Update on close */
- break;
- case HA_EXTRA_FORCE_REOPEN:
- case HA_EXTRA_PREPARE_FOR_DELETE:
- pthread_mutex_lock(&THR_LOCK_isam);
- info->s->last_version= 0L; /* Impossible version */
-#ifdef __WIN__
- /* Close the isam and data files as Win32 can't drop an open table */
- if (flush_key_blocks(dflt_key_cache, info->s->kfile, FLUSH_RELEASE))
- error=my_errno;
- if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
- {
- info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
- error=end_io_cache(&info->rec_cache);
- }
- if (info->lock_type != F_UNLCK && ! info->was_locked)
- {
- info->was_locked=info->lock_type;
- if (nisam_lock_database(info,F_UNLCK))
- error=my_errno;
- }
- if (info->s->kfile >= 0 && my_close(info->s->kfile,MYF(0)))
- error=my_errno;
- {
- LIST *list_element ;
- for (list_element=nisam_open_list ;
- list_element ;
- list_element=list_element->next)
- {
- N_INFO *tmpinfo=(N_INFO*) list_element->data;
- if (tmpinfo->s == info->s)
- {
- if (tmpinfo->dfile >= 0 && my_close(tmpinfo->dfile,MYF(0)))
- error = my_errno;
- tmpinfo->dfile=-1;
- }
- }
- }
- info->s->kfile=-1; /* Files aren't open anymore */
-#endif
- pthread_mutex_unlock(&THR_LOCK_isam);
- break;
- case HA_EXTRA_FLUSH:
- if (info->s->not_flushed)
- {
- info->s->not_flushed=0;
- if (my_sync(info->s->kfile, MYF(0)))
- error= my_errno;
- if (my_sync(info->dfile, MYF(0)))
- error= my_errno;
- }
- break;
- case HA_EXTRA_NORMAL: /* Theese isn't in use */
- case HA_EXTRA_QUICK:
- case HA_EXTRA_KEY_CACHE:
- case HA_EXTRA_NO_KEY_CACHE:
- default:
- break;
- }
- nisam_log_command(LOG_EXTRA,info,(byte*) &function,sizeof(function),error);
- DBUG_RETURN(error);
-} /* nisam_extra */
diff --git a/isam/info.c b/isam/info.c
deleted file mode 100644
index a23494e4876..00000000000
--- a/isam/info.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Ger tillbaka en struct med information om isam-filen */
-
-#include "isamdef.h"
-#ifdef __WIN__
-#include <sys/stat.h>
-#endif
-
-ulong nisam_position(N_INFO *info)
-{
- return info->lastpos;
-}
-
- /* If flag == 1 one only gets pos of last record */
- /* if flag == 2 one get current info (no sync from database */
-
-int nisam_info(N_INFO *info, register N_ISAMINFO *x, int flag)
-{
- struct stat state;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("nisam_info");
-
- x->recpos = info->lastpos;
- if (flag & (HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE |
- HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK))
- {
-#ifndef NO_LOCKING
- if (!(flag & HA_STATUS_NO_LOCK))
- {
- pthread_mutex_lock(&share->intern_lock);
- VOID(_nisam_readinfo(info,F_RDLCK,0));
- VOID(_nisam_writeinfo(info,0));
- pthread_mutex_unlock(&share->intern_lock);
- }
-#endif
- x->records = share->state.records;
- x->deleted = share->state.del;
- x->delete_length= share->state.empty;
- x->keys = share->state.keys;
- x->reclength = share->base.reclength;
- x->mean_reclength= share->state.records ?
- (share->state.data_file_length-share->state.empty)/share->state.records :
- share->min_pack_length;
- x->data_file_length=share->state.data_file_length;
- x->max_data_file_length=share->base.max_data_file_length;
- x->index_file_length=share->state.key_file_length;
- x->max_index_file_length=share->base.max_key_file_length;
- x->filenr = info->dfile;
- x->errkey = info->errkey;
- x->dupp_key_pos= info->dupp_key_pos;
- x->options = share->base.options;
- x->create_time=share->base.create_time;
- x->isamchk_time=share->base.isamchk_time;
- x->rec_per_key=share->base.rec_per_key;
- if ((flag & HA_STATUS_TIME) && !fstat(info->dfile,&state))
- x->update_time=state.st_mtime;
- else
- x->update_time=0;
- x->sortkey= -1; /* No clustering */
- }
- DBUG_RETURN(0);
-} /* nisam_info */
diff --git a/isam/isamchk.c b/isam/isamchk.c
deleted file mode 100644
index 5dd20c14063..00000000000
--- a/isam/isamchk.c
+++ /dev/null
@@ -1,3424 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Descript, check and repair of ISAM tables */
-
-#include "isamdef.h"
-
-#include <m_ctype.h>
-#include <stdarg.h>
-#include <my_getopt.h>
-#ifdef HAVE_SYS_VADVICE_H
-#include <sys/vadvise.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-SET_STACK_SIZE(9000) /* Minimum stack size for program */
-
-#define T_VERBOSE 1
-#define T_SILENT 2
-#define T_DESCRIPT 4
-#define T_EXTEND 8
-#define T_INFO 16
-#define T_REP 32
-#define T_OPT 64 /* Not currently used */
-#define T_FORCE_CREATE 128
-#define T_WRITE_LOOP 256
-#define T_UNPACK 512
-#define T_STATISTICS 1024
-#define T_VERY_SILENT 2048
-#define T_SORT_RECORDS 4096
-#define T_SORT_INDEX 8192
-#define T_WAIT_FOREVER 16384
-#define T_REP_BY_SORT 32768L
-
-
-#define O_NEW_INDEX 1 /* Bits set in out_flag */
-#define O_NEW_DATA 2
-
-#if defined(_MSC_VER) && !defined(__WIN__)
-#define USE_BUFFER_INIT 250L*1024L
-#define READ_BUFFER_INIT ((uint) 32768-MALLOC_OVERHEAD)
-#define SORT_BUFFER_INIT (uint) (65536L-MALLOC_OVERHEAD)
-#define MIN_SORT_BUFFER (1024*16-MALLOC_OVERHEAD)
-#else
-#define USE_BUFFER_INIT (((1024L*512L-MALLOC_OVERHEAD)/IO_SIZE)*IO_SIZE)
-#define READ_BUFFER_INIT (1024L*256L-MALLOC_OVERHEAD)
-#define SORT_BUFFER_INIT (2048L*1024L-MALLOC_OVERHEAD)
-#define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD)
-#endif
-
-#define NEED_MEM ((uint) 10*4*(IO_SIZE+32)+32) /* Nead for recursion */
-#define MAXERR 20
-#define BUFFERS_WHEN_SORTING 16 /* Alloc for sort-key-tree */
-#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
-#define INDEX_TMP_EXT ".TMM"
-#define DATA_TMP_EXT ".TMD"
-#define MYF_RW MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL)
-
-#define UPDATE_TIME 1
-#define UPDATE_STAT 2
-#define UPDATE_SORT 4
-
-typedef struct st_isam_sort_key_blocks { /* Used when sorting */
- uchar *buff,*end_pos;
- uchar lastkey[N_MAX_POSSIBLE_KEY_BUFF];
- uint last_length;
- int inited;
-} ISAM_SORT_KEY_BLOCKS;
-
-typedef struct st_isam_sort_info {
- N_INFO *info;
- enum data_file_type new_data_file_type;
- ISAM_SORT_KEY_BLOCKS *key_block,*key_block_end;
- uint key,find_length;
- ulong pos,max_pos,filepos,start_recpos,filelength,dupp,max_records,unique,
- buff_length;
- my_bool fix_datafile;
- char *record,*buff;
- N_KEYDEF *keyinfo;
- N_KEYSEG *keyseg;
-} ISAM_SORT_INFO;
-
-enum ic_options {OPT_CHARSETS_DIR_IC=256, OPT_KEY_BUFFER_SIZE,
- OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE,
- OPT_SORT_BUFFER_SIZE, OPT_SORT_KEY_BLOCKS,
- OPT_DECODE_BITS};
-
-static ulong use_buffers=0,read_buffer_length=0,write_buffer_length=0,
- sort_buffer_length=0,sort_key_blocks=0,crc=0,unique_count=0;
-static uint testflag=0,out_flag=0,warning_printed=0,error_printed=0,
- verbose=0,opt_follow_links=1;
-static my_bool rep_quick= 0;
-static uint opt_sort_key=0,total_files=0,max_level=0,max_key=N_MAXKEY;
-static ulong keydata=0,totaldata=0,key_blocks=0;
-static ulong new_file_pos=0,record_checksum=0,key_file_blocks=0,decode_bits;
-static ulong total_records=0,total_deleted=0;
-static ulong search_after_block=NI_POS_ERROR;
-static byte *record_buff;
-static char **defaults_alloc;
-static const char *type_names[]=
-{ "?","text","binary", "short", "long", "float",
- "double","number","unsigned short",
- "unsigned long","longlong","ulonglong","int24",
- "uint24","int8","?",},
- *packed_txt="packed ",
- *diff_txt="stripped ",
- *field_pack[]={"","no endspace", "no prespace",
- "no zeros", "blob", "constant", "table-lookup",
- "always zero","?","?",};
-
-static char temp_filename[FN_REFLEN], *isam_file_name, *default_charset;
-static IO_CACHE read_cache;
-static ISAM_SORT_INFO sort_info;
-static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
-
-static const char *load_default_groups[]= { "isamchk",0 };
-
- /* Functions defined in this file */
-
-extern int main(int argc,char * *argv);
-extern void print_error _VARARGS((const char *fmt,...));
-static void print_warning _VARARGS((const char *fmt,...));
-static void print_info _VARARGS((const char *fmt,...));
-static int nisamchk(char *filename);
-static void get_options(int *argc,char * * *argv);
-static int chk_del(N_INFO *info,uint testflag);
-static int check_k_link(N_INFO *info,uint nr);
-static int chk_size(N_INFO *info);
-static int chk_key(N_INFO *info);
-static int chk_index(N_INFO *info, N_KEYDEF *keyinfo, ulong page, uchar *buff,
- ulong *keys, uint level);
-static uint isam_key_length(N_INFO *info,N_KEYDEF *keyinfo);
-static unsigned long calc_checksum(ulong count);
-static int chk_data_link(N_INFO *info,int extend);
-static int rep(N_INFO *info,char *name);
-static int writekeys(N_INFO *info,byte *buff,ulong filepos);
-static void descript(N_INFO *info,char *name);
-static int movepoint(N_INFO *info,byte *record,ulong oldpos,ulong newpos,
- uint prot_key);
-static void lock_memory(void);
-static int flush_blocks(File file);
-static int sort_records(N_INFO *,my_string,uint,int);
-static int sort_index(N_INFO *info,my_string name);
-static int sort_record_index(N_INFO *info,N_KEYDEF *keyinfo,ulong page,
- uchar *buff,uint sortkey,File new_file);
-static int sort_one_index(N_INFO *info,N_KEYDEF *keyinfo,uchar *buff,
- File new_file);
-static int change_to_newfile(const char * filename,const char * old_ext,
- const char * new_ext);
-static int lock_file(File file,ulong start,int lock_type,const char* filetype,
- const char *filename);
-static int filecopy(File to,File from,ulong start,ulong length,
- const char * type);
-
-static void print_version(void);
-static int rep_by_sort(N_INFO *info,my_string name);
-static int sort_key_read(void *key);
-static int sort_get_next_record(void);
-static int sort_write_record(void);
-static int sort_key_cmp(const void *not_used, const void *a,const void *b);
-static int sort_key_write(const void *a);
-static ulong get_record_for_key(N_INFO *info,N_KEYDEF *keyinfo,
- uchar *key);
-static int sort_insert_key(reg1 ISAM_SORT_KEY_BLOCKS *key_block,uchar *key,
- ulong prev_block);
-static int sort_delete_record(void);
-static void usage(void);
-static int flush_pending_blocks(void);
-static ISAM_SORT_KEY_BLOCKS *alloc_key_blocks(uint blocks,uint buffer_length);
-static int test_if_almost_full(N_INFO *info);
-static int recreate_database(N_INFO **info,char *filename);
-static void save_integer(byte *pos,uint pack_length,ulong value);
-static int write_data_suffix(N_INFO *info);
-static int update_state_info(N_INFO *info,uint update);
-
-
- /* Main program */
-
-int main( int argc, char **argv)
-{
- int error;
- MY_INIT(argv[0]);
-
-#ifdef __EMX__
- _wildcard (&argc, &argv);
-#endif
-
- get_options(&argc,(char***) &argv);
- nisam_quick_table_bits=(uint) decode_bits;
- error=0;
- while (--argc >= 0)
- {
- error|= nisamchk(*(argv++));
- VOID(fflush(stdout));
- VOID(fflush(stderr));
- if ((error_printed | warning_printed) && (testflag & T_FORCE_CREATE) &&
- (!(testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
- T_SORT_INDEX))))
- {
- testflag|=T_REP;
- error|=nisamchk(argv[-1]);
- testflag&= ~T_REP;
- VOID(fflush(stdout));
- VOID(fflush(stderr));
- }
- if (argc && (!(testflag & T_SILENT) || testflag & T_INFO))
- {
- puts("\n---------\n");
- VOID(fflush(stdout));
- }
- }
- if (total_files > 1)
- { /* Only if descript */
- if (!(testflag & T_SILENT) || testflag & T_INFO)
- puts("\n---------\n");
- printf("\nTotal of all %d ISAM-files:\nData records: %8lu Deleted blocks: %8lu\n",total_files,total_records,total_deleted);
- }
- free_defaults(defaults_alloc);
- my_end(testflag & T_INFO ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
- exit(error);
-#ifndef _lint
- return 0; /* No compiler warning */
-#endif
-} /* main */
-
-
-static struct my_option my_long_options[] =
-{
- {"analyze", 'a',
- "Analyze distribution of keys. Will make some joins in MySQL faster.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"character-sets-dir", OPT_CHARSETS_DIR_IC,
- "Directory where character sets are", (gptr*) &charsets_dir,
- (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#ifndef DBUG_OFF
- {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#endif
- {"default-character-set", 'C', "Set the default character set",
- (gptr*) &default_charset, (gptr*) &default_charset, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"description", 'd', "Prints some information about table.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"extend-check", 'e',
- "Check the table VERY thoroughly. One need to use this only in extreme cases, because isamchk should normally find all errors even without this switch.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"information", 'i', "Print statistics information about the table",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"force", 'f',
- "Overwrite old temporary files. If one uses -f when checking tables (running isamchk without -r), isamchk will automatically restart with -r on any wrong table.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
- 0, 0, 0, 0, 0},
- {"keys-used", 'k',
- "Used with '-r'. Tell ISAM to update only the first # keys. This can be used to get faster inserts!",
- (gptr*) &max_key, (gptr*) &max_key, 0, GET_UINT, REQUIRED_ARG, N_MAXKEY, 0,
- 0, 0, 0, 0},
- {"no-symlinks", 'l',
- "Do not follow symbolic links when repairing. Normally isamchk repairs the table a symlink points at.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"quick", 'q',
- "Used with -r to get a faster repair. (The data file isn't touched.) One can give a second '-q' to force isamchk to modify the original datafile.",
- (gptr*) &rep_quick, (gptr*) &rep_quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
- 0},
- {"recover", 'r',
- "Can fix almost anything except unique keys that aren't unique.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"safe-recover", 'o',
- "Uses old recovery method; slower than '-r' but can handle a couple of cases that '-r' cannot handle.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"set-variable", 'O',
- "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"block-search", 'b', "For debugging.", (gptr*) &search_after_block,
- (gptr*) &search_after_block, 0, GET_ULONG, REQUIRED_ARG,
- (longlong) NI_POS_ERROR, 0, 0, 0, 0, 0},
- {"silent", 's',
- "Only print errors. One can use two -s to make isamchk very silent.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"sort-index", 'S',
- "Sort index blocks. This speeds up 'read-next' in applications.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"sort-records", 'R',
- "Sort records according to an index. This makes your data much more localized and may speed up things (It may be VERY slow to do a sort the first time!)",
- (gptr*) &opt_sort_key, (gptr*) &opt_sort_key, 0, GET_UINT, REQUIRED_ARG,
- 0, 0, (N_MAXKEY - 1), 1, 0, 0},
- {"unpack", 'u', "Unpack file packed with pack_isam.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"verbose", 'v',
- "Print more information. This can be used with -d and -e. Use many -v for more verbosity!",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"version", 'V', "Print version and exit.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"wait", 'w', "Wait if table is locked.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"key_buffer_size", OPT_KEY_BUFFER_SIZE, "", (gptr*) &use_buffers,
- (gptr*) &use_buffers, 0, GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT,
- (long) MALLOC_OVERHEAD, (long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE,
- 0},
- {"read_buffer_size", OPT_READ_BUFFER_SIZE, "",
- (gptr*) &read_buffer_length, (gptr*) &read_buffer_length, 0, GET_ULONG,
- REQUIRED_ARG, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
- (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
- {"write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
- (gptr*) &write_buffer_length, (gptr*) &write_buffer_length, 0, GET_ULONG,
- REQUIRED_ARG, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD, (long) ~0L,
- (long) MALLOC_OVERHEAD, (long) 1L, 0},
- {"sort_buffer_size", OPT_SORT_BUFFER_SIZE, "",
- (gptr*) &sort_buffer_length, (gptr*) &sort_buffer_length, 0, GET_ULONG,
- REQUIRED_ARG, (long) SORT_BUFFER_INIT,
- (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD), (long) ~0L,
- (long) MALLOC_OVERHEAD, (long) 1L, 0},
- {"sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
- (gptr*) &sort_key_blocks, (gptr*) &sort_key_blocks, 0, GET_ULONG,
- REQUIRED_ARG, BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
- {"decode_bits", OPT_DECODE_BITS, "",
- (gptr*) &decode_bits, (gptr*) &decode_bits, 0, GET_ULONG, REQUIRED_ARG,
- 9L, 4L, 17L, 0L, 1L, 0},
- {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
-};
-
-#include <help_start.h>
-
-static void print_version(void)
-{
- printf("%s Ver 6.01 for %s at %s\n", my_progname, SYSTEM_TYPE,
- MACHINE_TYPE);
- NETWARE_SET_SCREEN_MODE(1);
-}
-
-
-static void usage(void)
-{
- print_version();
- puts("MySQL AB, by Monty, for your professional use");
- puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
- puts("Description, check and repair of ISAM tables.");
- puts("Used without options all tables on the command will be checked for errors");
- printf("Usage: %s [OPTIONS] tables[.ISM]\n", my_progname);
- my_print_help(my_long_options);
- print_defaults("my", load_default_groups);
- my_print_variables(my_long_options);
-}
-
-#include <help_end.h>
-
- /* Check table */
-
-static int nisamchk(my_string filename)
-{
- int error,lock_type,recreate;
- N_INFO *info;
- File datafile;
- char fixed_name[FN_REFLEN];
- ISAM_SHARE *share;
- DBUG_ENTER("nisamchk");
-
- out_flag=error=warning_printed=error_printed=recreate=0;
- datafile=0;
- isam_file_name=filename; /* For error messages */
- if (!(info=nisam_open(filename,
- (testflag & T_DESCRIPT) ? O_RDONLY : O_RDWR,
- (testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED :
- (testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED :
- HA_OPEN_ABORT_IF_LOCKED)))
- {
- /* Avoid twice printing of isam file name */
- error_printed=1;
- switch (my_errno) {
- case HA_ERR_CRASHED:
- print_error("'%s' is not a ISAM-table",filename);
- break;
- case HA_ERR_OLD_FILE:
- print_error("'%s' is a old type of ISAM-table", filename);
- break;
- case HA_ERR_END_OF_FILE:
- print_error("Couldn't read compleat header from '%s'", filename);
- break;
- case EAGAIN:
- print_error("'%s' is locked. Use -w to wait until unlocked",filename);
- break;
- case ENOENT:
- print_error("File '%s' doesn't exist",filename);
- break;
- case EACCES:
- print_error("You don't have permission to use '%s'",filename);
- break;
- default:
- print_error("%d when opening ISAM-table '%s'",
- my_errno,filename);
- break;
- }
- DBUG_RETURN(1);
- }
- share=info->s;
- share->base.options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
- share->r_locks=0;
- if ((testflag & (T_REP_BY_SORT | T_REP | T_STATISTICS |
- T_SORT_RECORDS | T_SORT_INDEX)) &&
- ((testflag & T_UNPACK && share->data_file_type == COMPRESSED_RECORD) ||
- share->state_length != sizeof(share->state) ||
- uint2korr(share->state.header.base_info_length) !=
- sizeof(share->base) ||
- (max_key && ! share->state.keys && share->base.keys) ||
- test_if_almost_full(info) ||
- info->s->state.header.file_version[3] != nisam_file_magic[3]))
- {
- if (recreate_database(&info,filename))
- {
- VOID(fprintf(stderr,
- "ISAM-table '%s' is not fixed because of errors\n",
- filename));
- return(-1);
- }
- recreate=1;
- if (!(testflag & (T_REP | T_REP_BY_SORT)))
- {
- testflag|=T_REP_BY_SORT; /* if only STATISTICS */
- if (!(testflag & T_SILENT))
- printf("- '%s' has old table-format. Recreating index\n",filename);
- if (!rep_quick)
- rep_quick=1;
- }
- share=info->s;
- share->r_locks=0;
- }
-
- if (testflag & T_DESCRIPT)
- {
- total_files++;
- total_records+=share->state.records; total_deleted+=share->state.del;
- descript(info,filename);
- }
- else
- {
- if (testflag & (T_REP+T_REP_BY_SORT+T_OPT+T_SORT_RECORDS+T_SORT_INDEX))
- lock_type = F_WRLCK; /* table is changed */
- else
- lock_type= F_RDLCK;
- if (info->lock_type == F_RDLCK)
- info->lock_type=F_UNLCK; /* Read only table */
- if (_nisam_readinfo(info,lock_type,0))
- {
- print_error("Can't lock indexfile of '%s', error: %d",
- filename,my_errno);
- error_printed=0;
- goto end2;
- }
- share->w_locks++; /* Mark (for writeinfo) */
- if (lock_file(info->dfile,0L,lock_type,"datafile of",filename))
- goto end;
- info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
- info->tmp_lock_type=lock_type;
- datafile=info->dfile;
- if (testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX))
- {
- if (testflag & (T_REP+T_REP_BY_SORT))
- share->state.keys=min(share->base.keys,max_key);
- VOID(fn_format(fixed_name,filename,"",N_NAME_IEXT,
- 4+ (opt_follow_links ? 16 : 0)));
-
- if (rep_quick && (error=chk_del(info,testflag & ~T_VERBOSE)))
- print_error("Quick-recover aborted; Run recovery without switch 'q'");
- else
- {
- if (testflag & T_REP_BY_SORT &&
- (share->state.keys || (rep_quick && !max_key && ! recreate)))
- error=rep_by_sort(info,fixed_name);
- else if (testflag & (T_REP | T_REP_BY_SORT))
- error=rep(info,fixed_name);
- }
- if (!error && testflag & T_SORT_RECORDS)
- {
- if (out_flag & O_NEW_DATA)
- { /* Change temp file to org file */
- VOID(lock_file(datafile,0L,F_UNLCK,"datafile of",filename));
- VOID(my_close(datafile,MYF(MY_WME))); /* Close old file */
- VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */
- error|=change_to_newfile(fixed_name,N_NAME_DEXT,DATA_TMP_EXT);
- if ((info->dfile=my_open(fn_format(temp_filename,fixed_name,"",
- N_NAME_DEXT,2+4),
- O_RDWR | O_SHARE,
- MYF(MY_WME))) <= 0 ||
- lock_file(info->dfile,0L,F_WRLCK,"datafile",temp_filename))
- error=1;
- out_flag&= ~O_NEW_DATA; /* We are using new datafile */
- read_cache.file=info->dfile;
- }
- if (! error)
- error=sort_records(info,fixed_name,opt_sort_key,
- test(!(testflag & T_REP)));
- datafile=info->dfile; /* This is now locked */
- }
- if (!error && testflag & T_SORT_INDEX)
- error=sort_index(info,fixed_name);
- }
- else
- {
- if (!(testflag & T_SILENT) || testflag & T_INFO)
- printf("Checking ISAM file: %s\n",filename);
- if (!(testflag & T_SILENT))
- printf("Data records: %7ld Deleted blocks: %7ld\n",
- share->state.records,share->state.del);
- share->state.keys=min(share->state.keys,max_key);
- error =chk_size(info);
- error|=chk_del(info,testflag);
- error|=chk_key(info);
- if (!rep_quick)
- {
- if (testflag & T_EXTEND)
- VOID(init_key_cache(dflt_key_cache,KEY_CACHE_BLOCK_SIZE,
- use_buffers,0,0));
- VOID(init_io_cache(&read_cache,datafile,(uint) read_buffer_length,
- READ_CACHE,share->pack.header_length,1,
- MYF(MY_WME)));
- lock_memory();
- error|=chk_data_link(info,testflag & T_EXTEND);
- error|=flush_blocks(share->kfile);
- VOID(end_io_cache(&read_cache));
- }
- }
- }
-end:
- if (!(testflag & T_DESCRIPT))
- {
- if (info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED))
- error|=update_state_info(info,
- ((testflag & (T_REP | T_REP_BY_SORT)) ?
- UPDATE_TIME | UPDATE_STAT : 0) |
- ((testflag & T_SORT_RECORDS) ?
- UPDATE_SORT : 0));
- VOID(lock_file(share->kfile,0L,F_UNLCK,"indexfile",filename));
- if (datafile > 0)
- VOID(lock_file(datafile,0L,F_UNLCK,"datafile of",filename));
- info->update&= ~(HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- }
- share->w_locks--;
-end2:
- if (datafile && datafile != info->dfile)
- VOID(my_close(datafile,MYF(MY_WME)));
- if (nisam_close(info))
- {
- print_error("%d when closing ISAM-table '%s'",my_errno,filename);
- DBUG_RETURN(1);
- }
- if (error == 0)
- {
- if (out_flag & O_NEW_DATA)
- error|=change_to_newfile(fixed_name,N_NAME_DEXT,DATA_TMP_EXT);
- if (out_flag & O_NEW_INDEX)
- error|=change_to_newfile(fixed_name,N_NAME_IEXT,INDEX_TMP_EXT);
- }
- VOID(fflush(stdout)); VOID(fflush(stderr));
- if (error_printed)
- {
- if (testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX))
- VOID(fprintf(stderr,
- "ISAM-table '%s' is not fixed because of errors\n",
- filename));
- else if (! (error_printed & 2) && !(testflag & T_FORCE_CREATE))
- VOID(fprintf(stderr,
- "ISAM-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
- filename));
- }
- else if (warning_printed &&
- ! (testflag & (T_REP+T_REP_BY_SORT+T_SORT_RECORDS+T_SORT_INDEX+
- T_FORCE_CREATE)))
- VOID(fprintf(stderr, "ISAM-table '%s' is useable but should be fixed\n",
- filename));
- VOID(fflush(stderr));
- DBUG_RETURN(error);
-} /* nisamchk */
-
-
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-
-{
- switch(optid) {
- case 'a':
- testflag|= T_STATISTICS;
- break;
- case 's': /* silent */
- if (testflag & T_SILENT)
- testflag|=T_VERY_SILENT;
- testflag|= T_SILENT;
- testflag&= ~T_WRITE_LOOP;
- break;
- case 'w':
- testflag|= T_WAIT_FOREVER;
- break;
- case 'd': /* description if isam-file */
- testflag|= T_DESCRIPT;
- break;
- case 'e': /* extend check */
- testflag|= T_EXTEND;
- break;
- case 'i':
- testflag|= T_INFO;
- break;
- case 'f':
- tmpfile_createflag= O_RDWR | O_TRUNC;
- testflag|=T_FORCE_CREATE;
- break;
- case 'l':
- opt_follow_links=0;
- break;
- case 'r': /* Repair table */
- testflag= (testflag & ~T_REP) | T_REP_BY_SORT;
- break;
- case 'o':
- testflag= (testflag & ~T_REP_BY_SORT) | T_REP;
- my_disable_async_io=1; /* More safety */
- break;
- case 'u':
- testflag|= T_UNPACK | T_REP_BY_SORT;
- break;
- case 'v': /* Verbose */
- testflag|= T_VERBOSE;
- verbose++;
- break;
- case 'R': /* Sort records */
- testflag|= T_SORT_RECORDS;
- if (opt_sort_key >= N_MAXKEY)
- {
- fprintf(stderr,
- "The value of the sort key is bigger than max key: %d.\n",
- N_MAXKEY);
- exit(1);
- }
- break;
- case 'S': /* Sort index */
- testflag|= T_SORT_INDEX;
- break;
- case '#':
- DBUG_PUSH(argument ? argument : "d:t:o,/tmp/isamchk.trace");
- break;
- case 'V':
- print_version();
- exit(0);
- case '?':
- usage();
- exit(0);
- }
- return 0;
-}
-
- /* Read options */
-
-static void get_options(register int *argc, register char ***argv)
-{
- int ho_error;
-
- load_defaults("my",load_default_groups,argc,argv);
- defaults_alloc= *argv;
- if (isatty(fileno(stdout)))
- testflag|=T_WRITE_LOOP;
-
- if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
- exit(ho_error);
-
- if (*argc == 0)
- {
- usage();
- exit(-1);
- }
- if ((testflag & T_UNPACK) && (rep_quick || (testflag & T_SORT_RECORDS)))
- {
- VOID(fprintf(stderr,
- "%s: --unpack can't be used with --quick or --sort-records\n",
- my_progname));
- exit(1);
- }
- if (default_charset)
- {
- if (!(default_charset_info= get_charset_by_name(default_charset, MYF(MY_WME))))
- exit(1);
- }
- return;
-} /* get options */
-
-
- /* Check delete links */
-
-static int chk_del( reg1 N_INFO *info, uint test_flag)
-{
- reg2 ulong i;
- uint j,delete_link_length;
- ulong empty,next_link;
- uchar buff[8];
- DBUG_ENTER("chk_del");
- if (!(test_flag & T_SILENT)) puts("- check delete-chain");
-
- record_checksum=0L;
- key_file_blocks=info->s->base.keystart;
- for (j =0 ; j < info->s->state.keys ; j++)
- if (check_k_link(info,j))
- goto wrong;
- delete_link_length=(info->s->base.options & HA_OPTION_PACK_RECORD) ? 8 : 5;
-
- next_link=info->s->state.dellink;
- if (info->s->state.del == 0)
- {
- if (test_flag & T_VERBOSE)
- {
- puts("No recordlinks");
- }
- }
- else
- {
- if (test_flag & T_VERBOSE)
- printf("Recordlinks: ");
- empty=0;
- for (i= info->s->state.del ; i > 0L && next_link != NI_POS_ERROR ; i--)
- {
- if (test_flag & T_VERBOSE) printf("%10lu",next_link);
- if (next_link >= info->s->state.data_file_length)
- goto wrong;
- if (my_pread(info->dfile,(char*) buff,delete_link_length,
- next_link,MYF(MY_NABP)))
- {
- if (test_flag & T_VERBOSE) puts("");
- print_error("Can't read delete-link at filepos: %lu",
- (ulong) next_link);
- DBUG_RETURN(1);
- }
- if (*buff != '\0')
- {
- if (test_flag & T_VERBOSE) puts("");
- print_error("Record at pos: %lu is not remove-marked",
- (ulong) next_link);
- goto wrong;
- }
- if (info->s->base.options & HA_OPTION_PACK_RECORD)
- {
- next_link=uint4korr(buff+4);
- empty+=uint3korr(buff+1);
- }
- else
- {
- record_checksum+=next_link;
- next_link=uint4korr(buff+1);
- empty+=info->s->base.reclength;
- }
- if (next_link == (uint32) ~0) /* Fix for 64 bit long */
- next_link=NI_POS_ERROR;
- }
- if (empty != info->s->state.empty)
- {
- if (test_flag & T_VERBOSE) puts("");
- print_warning("Not used space is supposed to be: %lu but is: %lu",
- (ulong) info->s->state.empty,(ulong) empty);
- info->s->state.empty=empty;
- }
- if (i != 0 || next_link != NI_POS_ERROR)
- goto wrong;
-
- if (test_flag & T_VERBOSE) puts("\n");
- }
- DBUG_RETURN(0);
-wrong:
- if (test_flag & T_VERBOSE) puts("");
- print_error("delete-link-chain corrupted");
- DBUG_RETURN(1);
-} /* chk_del */
-
-
- /* Kontrollerar l{nkarna i nyckelfilen */
-
-static int check_k_link( register N_INFO *info, uint nr)
-{
- ulong next_link,records;
- DBUG_ENTER("check_k_link");
-
- if (testflag & T_VERBOSE)
- printf("index %2d: ",nr+1);
-
- next_link=info->s->state.key_del[nr];
- records= (info->s->state.key_file_length /
- info->s->keyinfo[nr].base.block_length);
- while (next_link != NI_POS_ERROR && records > 0)
- {
- if (testflag & T_VERBOSE) printf("%10lu",next_link);
- if (next_link > info->s->state.key_file_length ||
- next_link & (info->s->blocksize-1))
- DBUG_RETURN(1);
- if (my_pread(info->s->kfile,(char*) &next_link,sizeof(long),next_link,
- MYF(MY_NABP)))
- DBUG_RETURN(1);
- records--;
- key_file_blocks+=info->s->keyinfo[nr].base.block_length;
- }
- if (testflag & T_VERBOSE)
- {
- if (next_link != NI_POS_ERROR)
- printf("%10lu\n",next_link);
- else
- puts("");
- }
- DBUG_RETURN (next_link != NI_POS_ERROR);
-} /* check_k_link */
-
-
- /* Kontrollerar storleken p} filerna */
-
-static int chk_size(register N_INFO *info)
-{
- int error=0;
- register my_off_t skr,size;
- DBUG_ENTER("chk_size");
-
- if (!(testflag & T_SILENT)) puts("- check file-size");
-
- size=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0));
- if ((skr=(my_off_t) info->s->state.key_file_length) != size)
- {
- if (skr > size)
- {
- error=1;
- print_error("Size of indexfile is: %-8lu Should be: %lu",
- (ulong) size, (ulong) skr);
- }
- else
- print_warning("Size of indexfile is: %-8lu Should be: %lu",
- (ulong) size,(ulong) skr);
- }
- if (!(testflag & T_VERY_SILENT) &&
- ! (info->s->base.options & HA_OPTION_COMPRESS_RECORD) &&
- info->s->state.key_file_length >
- (ulong) (ulong_to_double(info->s->base.max_key_file_length)*0.9))
- print_warning("Keyfile is almost full, %10lu of %10lu used",
- info->s->state.key_file_length,
- info->s->base.max_key_file_length-1);
-
- size=my_seek(info->dfile,0L,MY_SEEK_END,MYF(0));
- skr=(my_off_t) info->s->state.data_file_length;
- if (info->s->base.options & HA_OPTION_COMPRESS_RECORD)
- skr+= MEMMAP_EXTRA_MARGIN;
-#ifdef USE_RELOC
- if (info->data_file_type == STATIC_RECORD &&
- skr < (my_off_t) info->s->base.reloc*info->s->base.min_pack_length)
- skr=(my_off_t) info->s->base.reloc*info->s->base.min_pack_length;
-#endif
- if (skr != size)
- {
- info->s->state.data_file_length=(ulong) size; /* Skip other errors */
- if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN)
- {
- error=1;
- print_error("Size of datafile is: %-8lu Should be: %lu",
- (ulong) size,(ulong) skr);
- }
- else
- {
- print_warning("Size of datafile is: %-8lu Should be: %lu",
- (ulong) size,(ulong) skr);
-
- }
- }
- if (!(testflag & T_VERY_SILENT) &&
- !(info->s->base.options & HA_OPTION_COMPRESS_RECORD) &&
- info->s->state.data_file_length >
- (ulong) (ulong_to_double(info->s->base.max_data_file_length)*0.9))
- print_warning("Datafile is almost full, %10lu of %10lu used",
- info->s->state.data_file_length,
- info->s->base.max_data_file_length-1);
- DBUG_RETURN(error);
-} /* chk_size */
-
-
- /* Kontrollerar nycklarna */
-
-static int chk_key( register N_INFO *info)
-{
- uint key;
- ulong keys,all_keydata,all_totaldata,key_totlength,length,
- init_checksum,old_record_checksum;
- ISAM_SHARE *share=info->s;
- N_KEYDEF *keyinfo;
- DBUG_ENTER("chk_key");
-
- if (!(testflag & T_SILENT)) puts("- check index reference");
-
- all_keydata=all_totaldata=key_totlength=old_record_checksum=0;
- init_checksum=record_checksum;
- if (!(share->base.options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
- old_record_checksum=calc_checksum(share->state.records+share->state.del-1)*
- share->base.reclength;
- for (key= 0,keyinfo= &share->keyinfo[0]; key < share->state.keys ;
- key++,keyinfo++)
- {
- record_checksum=init_checksum;
- unique_count=0L;
- if ((!(testflag & T_SILENT)) && share->state.keys >1)
- printf ("- check data record references index: %d\n",key+1);
- if (share->state.key_root[key] == NI_POS_ERROR &&
- share->state.records == 0)
- continue;
- if (!_nisam_fetch_keypage(info,keyinfo,share->state.key_root[key],info->buff,
- 0))
- {
- print_error("Can't read indexpage from filepos: %lu",
- (ulong) share->state.key_root[key]);
- DBUG_RETURN(-1);
- }
- key_file_blocks+=keyinfo->base.block_length;
- keys=keydata=totaldata=key_blocks=0; max_level=0;
- if (chk_index(info,keyinfo,share->state.key_root[key],info->buff,&keys,1))
- DBUG_RETURN(-1);
- if (keys != share->state.records)
- {
- print_error("Found %lu keys of %lu",(ulong) keys,
- (ulong) share->state.records);
- DBUG_RETURN(-1);
- }
- if (!key && (share->base.options &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
- old_record_checksum=record_checksum;
- else if (old_record_checksum != record_checksum)
- {
- if (key)
- print_error("Key %u doesn't point at same records that key 1",
- key+1);
- else
- print_error("Key 1 doesn't point at all records");
- DBUG_RETURN(-1);
- }
- length=(ulong) isam_key_length(info,keyinfo)*keys + key_blocks*2;
- if (testflag & T_INFO && totaldata != 0L && keys != 0L)
- printf("Key: %2d: Keyblocks used: %3d%% Packed: %4d%% Max levels: %2d\n",
- key+1,
- (int) (keydata*100.0/totaldata),
- (int) ((long) (length-keydata)*100.0/(double) length),
- max_level);
- all_keydata+=keydata; all_totaldata+=totaldata; key_totlength+=length;
- share->base.rec_per_key[key]=
- unique_count ? ((share->state.records+unique_count/2)/
- unique_count) : 1L;
- }
- if (testflag & T_INFO)
- {
- if (all_totaldata != 0L && share->state.keys != 1)
- printf("Total: Keyblocks used: %3d%% Packed: %4d%%\n\n",
- (int) (all_keydata*100.0/all_totaldata),
- (int) ((long) (key_totlength-all_keydata)*100.0/
- (double) key_totlength));
- else if (all_totaldata != 0L && share->state.keys)
- puts("");
- }
- if (key_file_blocks != share->state.key_file_length)
- print_warning("Some data are unreferenced in keyfile");
- record_checksum-=init_checksum; /* Remove delete links */
- if (testflag & T_STATISTICS)
- DBUG_RETURN(update_state_info(info,UPDATE_STAT));
- DBUG_RETURN(0);
-} /* chk_key */
-
-
- /* Check if index is ok */
-
-static int chk_index(N_INFO *info, N_KEYDEF *keyinfo, ulong page, uchar *buff,
- ulong *keys,uint level)
-{
- int flag;
- uint used_length,comp_flag,nod_flag;
- uchar key[N_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*endpos;
- ulong next_page,record;
- DBUG_ENTER("chk_index");
- DBUG_DUMP("buff",(byte*) buff,getint(buff));
-
- if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->base.block_length)))
- {
- print_error("Not Enough memory");
- DBUG_RETURN(-1);
- }
-
- if (keyinfo->base.flag & HA_NOSAME)
- comp_flag=SEARCH_FIND; /* Not dupplicates */
- else
- comp_flag=SEARCH_SAME; /* Keys in positionorder */
- nod_flag=test_if_nod(buff);
- used_length=getint(buff);
- keypos=buff+2+nod_flag;
- endpos=buff+used_length;
-
- keydata+=used_length; totaldata+=keyinfo->base.block_length; /* INFO */
- key_blocks++;
- if (level > max_level)
- max_level=level;
-
- if (used_length > keyinfo->base.block_length)
- {
- print_error("Wrong pageinfo at page: %lu",(ulong) page);
- goto err;
- }
- for ( ;; )
- {
- if (nod_flag)
- {
- next_page=_nisam_kpos(nod_flag,keypos);
- if (next_page > info->s->state.key_file_length ||
- (nod_flag && (next_page & (info->s->blocksize -1))))
- {
- my_off_t max_length=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0));
- print_error("Wrong pagepointer: %lu at page: %lu",
- (ulong) next_page,(ulong) page);
-
- if (next_page+info->s->blocksize > max_length)
- goto err;
- info->s->state.key_file_length=(ulong) (max_length &
- ~ (my_off_t)
- (info->s->blocksize-1));
- }
- if (!_nisam_fetch_keypage(info,keyinfo,next_page,temp_buff,0))
- {
- print_error("Can't read key from filepos: %lu",(ulong) next_page);
- goto err;
- }
- key_file_blocks+=keyinfo->base.block_length;
- if (chk_index(info,keyinfo,next_page,temp_buff,keys,level+1))
- goto err;
- }
- if (keypos >= endpos ||
- (*keyinfo->get_key)(keyinfo,nod_flag,&keypos,key) == 0)
- break;
- if ((*keys)++ &&
- (flag=_nisam_key_cmp(keyinfo->seg,info->lastkey,key,0,comp_flag)) >=0)
- {
- DBUG_DUMP("old",(byte*) info->lastkey,
- _nisam_keylength(keyinfo,info->lastkey));
- DBUG_DUMP("new",(byte*) key,_nisam_keylength(keyinfo,key));
-
- if (comp_flag == SEARCH_FIND && flag == 0)
- print_error("Found dupplicated key at page %lu",(ulong) page);
- else
- print_error("Key in wrong position at page %lu",(ulong) page);
- goto err;
- }
- if (testflag & T_STATISTICS)
- {
- if (*keys == 1L ||
- _nisam_key_cmp(keyinfo->seg,info->lastkey,key,0,SEARCH_FIND))
- unique_count++;
- }
- VOID(_nisam_move_key(keyinfo,(uchar*) info->lastkey,key));
- record= _nisam_dpos(info,nod_flag,keypos);
- if (record >= info->s->state.data_file_length)
- {
- print_error("Found key at page %lu that points to record outside datafile",page);
- DBUG_PRINT("test",("page: %lu record: %lu filelength: %lu",
- (ulong) page,(ulong) record,
- (ulong) info->s->state.data_file_length));
- DBUG_DUMP("key",(byte*) info->lastkey,info->s->base.max_key_length);
- goto err;
- }
- record_checksum+=record;
- }
- if (keypos != endpos)
- {
- print_error("Keyblock size at page %lu is not correct. Block length: %d key length: %d",(ulong) page, used_length, (keypos - buff));
- goto err;
- }
- my_afree((byte*) temp_buff);
- DBUG_RETURN(0);
- err:
- my_afree((byte*) temp_buff);
- DBUG_RETURN(1);
-} /* chk_index */
-
-
- /* Calculate a checksum of 1+2+3+4...N = N*(N+1)/2 without overflow */
-
-static ulong calc_checksum(count)
-ulong count;
-{
- ulong sum,a,b;
- DBUG_ENTER("calc_checksum");
-
- sum=0;
- a=count; b=count+1;
- if (a & 1)
- b>>=1;
- else
- a>>=1;
- while (b)
- {
- if (b & 1)
- sum+=a;
- a<<=1; b>>=1;
- }
- DBUG_PRINT("exit",("sum: %lx",sum));
- DBUG_RETURN(sum);
-} /* calc_checksum */
-
-
- /* Calc length of key in normal isam */
-
-static uint isam_key_length( N_INFO *info, reg1 N_KEYDEF *keyinfo)
-{
- uint length;
- N_KEYSEG *keyseg;
- DBUG_ENTER("isam_key_length");
-
- length= info->s->rec_reflength;
- for (keyseg=keyinfo->seg ; keyseg->base.type ; keyseg++)
- length+= keyseg->base.length;
-
- DBUG_PRINT("exit",("length: %d",length));
- DBUG_RETURN(length);
-} /* key_length */
-
-
- /* Check that record-link is ok */
-
-static int chk_data_link(info,extend)
-reg1 N_INFO *info;
-int extend;
-{
- int error,got_error,flag;
- uint key,left_length,b_type;
- ulong records,del_blocks,used,empty,pos,splitts,start_recpos,
- del_length,link_used,intern_record_checksum,start_block;
- byte *record,*to;
- N_KEYDEF *keyinfo;
- BLOCK_INFO block_info;
- DBUG_ENTER("chk_data_link");
-
- if (! (info->s->base.options & (HA_OPTION_PACK_RECORD |
- HA_OPTION_COMPRESS_RECORD)) &&
- ! extend)
- DBUG_RETURN(0);
-
- if (!(testflag & T_SILENT))
- {
- if (extend)
- puts("- check records and index references");
- else
- puts("- check record links");
- }
-
- if (!(record= (byte*) my_alloca(info->s->base.reclength)))
- {
- print_error("Not Enough memory");
- DBUG_RETURN(-1);
- }
- records=used=link_used=splitts=del_blocks=del_length=
- intern_record_checksum=crc=0L;
- LINT_INIT(left_length); LINT_INIT(start_recpos); LINT_INIT(to);
- got_error=error=0;
- empty=pos=info->s->pack.header_length;
-
- while (pos < info->s->state.data_file_length)
- {
- switch (info->s->data_file_type) {
- case STATIC_RECORD:
- if (my_b_read(&read_cache,(byte*) record,info->s->base.reclength))
- goto err;
- start_recpos=pos;
- pos+=info->s->base.reclength;
- splitts++;
- if (*record == '\0')
- {
- del_blocks++;
- del_length+=info->s->base.reclength;
- continue; /* Record removed */
- }
- used+=info->s->base.reclength;
- break;
- case DYNAMIC_RECORD:
- flag=block_info.second_read=0;
- block_info.next_filepos=pos;
- do
- {
- if (_nisam_read_cache(&read_cache,(byte*) block_info.header,
- (start_block=block_info.next_filepos),
- sizeof(block_info.header),test(! flag) | 2))
- goto err;
- b_type=_nisam_get_block_info(&block_info,-1,start_block);
- if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
- BLOCK_FATAL_ERROR))
- {
- if (b_type & BLOCK_SYNC_ERROR)
- {
- if (flag)
- {
- print_error("Unexpected byte: %d at link: %lu",
- (int) block_info.header[0],(ulong) start_block);
- goto err2;
- }
- pos=block_info.filepos+block_info.block_len;
- goto next;
- }
- if (b_type & BLOCK_DELETED)
- {
- if (block_info.block_len < info->s->base.min_block_length ||
- block_info.block_len-4 > (uint) info->s->base.max_pack_length)
- {
- print_error("Deleted block with impossible length %u at %lu",
- block_info.block_len,(ulong) pos);
- goto err2;
- }
- del_blocks++;
- del_length+=block_info.block_len;
- pos=block_info.filepos+block_info.block_len;
- splitts++;
- goto next;
- }
- print_error("Wrong bytesec: %d-%d-%d at linkstart: %lu",
- block_info.header[0],block_info.header[1],
- block_info.header[2],(ulong) start_block);
- goto err2;
- }
- if (info->s->state.data_file_length < block_info.filepos+
- block_info.block_len)
- {
- print_error("Recordlink that points outside datafile at %lu",
- (ulong) pos);
- got_error=1;
- break;
- }
- splitts++;
- if (!flag++) /* First block */
- {
- start_recpos=pos;
- pos=block_info.filepos+block_info.block_len;
- if (block_info.rec_len > (uint) info->s->base.max_pack_length)
- {
- print_error("Found too long record at %lu",(ulong) start_recpos);
- got_error=1;
- break;
- }
- if (info->s->base.blobs)
- {
- if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
- {
- print_error("Not enough memory for blob at %lu",
- (ulong) start_recpos);
- got_error=1;
- break;
- }
- }
- else
- to= info->rec_buff;
- left_length=block_info.rec_len;
- }
- if (left_length < block_info.data_len)
- {
- print_error("Found too long record at %lu",(ulong) start_recpos);
- got_error=1; break;
- }
- if (_nisam_read_cache(&read_cache,(byte*) to,block_info.filepos,
- (uint) block_info.data_len, test(flag == 1)))
- goto err;
- to+=block_info.data_len;
- link_used+= block_info.filepos-start_block;
- used+= block_info.filepos - start_block + block_info.data_len;
- empty+=block_info.block_len-block_info.data_len;
- left_length-=block_info.data_len;
- if (left_length)
- {
- if (b_type & BLOCK_LAST)
- {
- print_error("Record link to short for record at %lu",
- (ulong) start_recpos);
- got_error=1;
- break;
- }
- if (info->s->state.data_file_length < block_info.next_filepos)
- {
- print_error("Found next-recordlink that points outside datafile at %lu",
- (ulong) block_info.filepos);
- got_error=1;
- break;
- }
- }
- } while (left_length);
- if (! got_error)
- {
- if (_nisam_rec_unpack(info,record,info->rec_buff,block_info.rec_len) ==
- MY_FILE_ERROR)
- {
- print_error("Found wrong record at %lu",(ulong) start_recpos);
- got_error=1;
- }
- if (testflag & (T_EXTEND | T_VERBOSE))
- {
- if (_nisam_rec_check(info,record))
- {
- print_error("Found wrong packed record at %lu",
- (ulong) start_recpos);
- got_error=1;
- }
- }
- }
- else if (!flag)
- pos=block_info.filepos+block_info.block_len;
- break;
- case COMPRESSED_RECORD:
- if (_nisam_read_cache(&read_cache,(byte*) block_info.header,pos, 3,1))
- goto err;
- start_recpos=pos;
- splitts++;
- VOID(_nisam_pack_get_block_info(&block_info,info->s->pack.ref_length,-1,
- start_recpos));
- pos=start_recpos+info->s->pack.ref_length+block_info.rec_len;
- if (block_info.rec_len < (uint) info->s->min_pack_length ||
- block_info.rec_len > (uint) info->s->max_pack_length)
- {
- print_error("Found block with wrong recordlength: %d at %lu",
- block_info.rec_len,(ulong) start_recpos);
- got_error=1;
- break;
- }
- if (_nisam_read_cache(&read_cache,(byte*) info->rec_buff,
- block_info.filepos, block_info.rec_len,1))
- goto err;
- if (_nisam_pack_rec_unpack(info,record,info->rec_buff,block_info.rec_len))
- {
- print_error("Found wrong record at %lu",(ulong) start_recpos);
- got_error=1;
- }
- crc^=_nisam_checksum(record,info->s->base.reclength);
- link_used+=info->s->pack.ref_length;
- used+=block_info.rec_len+info->s->pack.ref_length;
- }
- if (! got_error)
- {
- intern_record_checksum+=start_recpos;
- records++;
- if (testflag & T_WRITE_LOOP && records % WRITE_COUNT == 0)
- {
- printf("%lu\r",(ulong) records); VOID(fflush(stdout));
- }
-
- if (extend)
- {
- for (key=0,keyinfo= info->s->keyinfo; key<info->s->state.keys;
- key++,keyinfo++)
- {
- VOID(_nisam_make_key(info,key,info->lastkey,record,start_recpos));
- if (_nisam_search(info,keyinfo,info->lastkey,0,SEARCH_SAME,
- info->s->state.key_root[key]))
- {
- print_error("Record at: %10lu Can't find key for index: %2d",
- start_recpos,key+1);
- if (error++ > MAXERR || !(testflag & T_VERBOSE))
- goto err2;
- }
- }
- }
- }
- else
- {
- got_error=0;
- if (error++ > MAXERR || !(testflag & T_VERBOSE))
- goto err2;
- }
- next:; /* Next record */
- }
- if (testflag & T_WRITE_LOOP)
- {
- VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
- }
- if (records != info->s->state.records)
- {
- print_error("Record-count is not ok; is %-10lu Should be: %lu",
- (ulong) records,(ulong) info->s->state.records);
- error=1;
- }
- else if (record_checksum != intern_record_checksum && info->s->state.keys)
- {
- print_error("Keypointers and records don't match");
- error=1;
- }
- if (used+empty+del_length != info->s->state.data_file_length)
- {
- print_warning("Found %lu record-data and %lu unused data and %lu deleted-data\nTotal %lu, Should be: %lu",
- (ulong) used,(ulong) empty,(ulong) del_length,
- (ulong) (used+empty+del_length),
- (ulong) info->s->state.data_file_length);
- }
- if (del_blocks != info->s->state.del)
- {
- print_warning("Found %10lu deleted blocks Should be: %lu",
- (ulong) del_blocks,(ulong) info->s->state.del);
- }
- if (splitts != info->s->state.splitt)
- {
- print_warning("Found %10lu parts Should be: %lu parts",
- (ulong) splitts,(ulong) info->s->state.splitt);
- }
- if ((info->s->base.options & HA_OPTION_COMPRESS_RECORD) &&
- crc != info->s->state.uniq)
- print_warning("Wrong checksum for records; Restore uncompressed table");
-
- if (testflag & T_INFO)
- {
- if (warning_printed || error_printed)
- puts("");
- if (used != 0 && ! error_printed)
- {
- printf("Records:%17lu M.recordlength:%8lu Packed:%14.0f%%\n",
- records, (used-link_used)/records,
- (info->s->base.blobs ? 0 :
- (ulong_to_double(info->s->base.reclength*records)-used)/
- ulong_to_double(info->s->base.reclength*records)*100.0));
- printf("Recordspace used:%8.0f%% Empty space:%11d%% Blocks/Record: %6.2f\n",
- (ulong_to_double(used-link_used)/ulong_to_double(used-link_used+empty)*100.0),
- (!records ? 100 : (int) (ulong_to_double(del_length+empty)/used*100.0)),
- ulong_to_double(splitts - del_blocks) / records);
- }
- printf("Record blocks:%12lu Delete blocks:%10lu\n",
- splitts-del_blocks,del_blocks);
- printf("Record data: %12lu Deleted data :%10lu\n",
- used-link_used,del_length);
- printf("Lost space: %12lu Linkdata: %10lu\n",
- empty,link_used);
- }
- my_afree((gptr) record);
- DBUG_RETURN (error);
- err:
- print_error("got error: %d when reading datafile",my_errno);
- err2:
- my_afree((gptr) record);
- DBUG_RETURN(1);
-} /* chk_data_link */
-
-
- /* Recover old table by reading each record and writing all keys */
- /* Save new datafile-name in temp_filename */
-
-static int rep(info,name)
-reg1 N_INFO *info;
-my_string name;
-{
- int error,got_error;
- uint i;
- ulong start_records,new_header_length,del;
- File new_file;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("rep");
-
- start_records=share->state.records;
- new_header_length=(testflag & T_UNPACK) ? 0L : share->pack.header_length;
- got_error=1;
- new_file= -1;
- if (!(testflag & T_SILENT))
- {
- printf("- recovering ISAM-table '%s'\n",name);
- printf("Data records: %lu\n",(ulong) share->state.records);
- }
-
- VOID(init_key_cache(dflt_key_cache,KEY_CACHE_BLOCK_SIZE,use_buffers,0,0));
- if (init_io_cache(&read_cache,info->dfile,(uint) read_buffer_length,
- READ_CACHE,share->pack.header_length,1,MYF(MY_WME)))
- goto err;
- if (!rep_quick)
- if (init_io_cache(&info->rec_cache,-1,(uint) write_buffer_length,
- WRITE_CACHE, new_header_length, 1,
- MYF(MY_WME | MY_WAIT_IF_FULL)))
- goto err;
- info->opt_flag|=WRITE_CACHE_USED;
- sort_info.start_recpos=0;
- sort_info.buff=0; sort_info.buff_length=0;
- if (!(sort_info.record=(byte*) my_alloca((uint) share->base.reclength)))
- {
- print_error("Not Enough memory");
- goto err;
- }
-
- if (!rep_quick)
- {
- if ((new_file=my_create(fn_format(temp_filename,name,"",DATA_TMP_EXT,
- 2+4),
- 0,tmpfile_createflag,MYF(0))) < 0)
- {
- print_error("Can't create new tempfile: '%s'",temp_filename);
- goto err;
- }
- if (filecopy(new_file,info->dfile,0L,new_header_length,"datafile-header"))
- goto err;
- share->state.dellink= NI_POS_ERROR;
- info->rec_cache.file=new_file;
- if (testflag & T_UNPACK)
- share->base.options&= ~HA_OPTION_COMPRESS_RECORD;
- }
-
- sort_info.info=info;
- sort_info.pos=sort_info.max_pos=share->pack.header_length;
- sort_info.filepos=new_header_length;
- read_cache.end_of_file=sort_info.filelength=(ulong)
- my_seek(info->dfile,0L,MY_SEEK_END,MYF(0));
- sort_info.dupp=0;
- sort_info.fix_datafile= (my_bool) (! rep_quick);
- sort_info.max_records=LONG_MAX;
- if ((sort_info.new_data_file_type=share->data_file_type) ==
- COMPRESSED_RECORD && testflag & T_UNPACK)
- {
- if (share->base.options & HA_OPTION_PACK_RECORD)
- sort_info.new_data_file_type = DYNAMIC_RECORD;
- else
- sort_info.new_data_file_type = STATIC_RECORD;
- }
-
- del=share->state.del;
- share->state.records=share->state.del=share->state.empty=
- share->state.splitt=0;
- info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- for (i=0 ; i < N_MAXKEY ; i++)
- share->state.key_del[i]=share->state.key_root[i]= NI_POS_ERROR;
- share->state.key_file_length=share->base.keystart;
-
- lock_memory(); /* Everything is alloced */
- while (!(error=sort_get_next_record()))
- {
- if (writekeys(info,(byte*) sort_info.record,sort_info.filepos))
- {
- if (my_errno != HA_ERR_FOUND_DUPP_KEY) goto err;
- DBUG_DUMP("record",(byte*) sort_info.record,share->base.pack_reclength);
- print_info("Dupplicate key %2d for record at %10lu against new record at %10lu",info->errkey+1,sort_info.start_recpos,info->int_pos);
- if (testflag & T_VERBOSE)
- {
- VOID(_nisam_make_key(info,(uint) info->errkey,info->lastkey,
- sort_info.record,0L));
- _nisam_print_key(stdout,share->keyinfo[info->errkey].seg,info->lastkey);
- }
- sort_info.dupp++;
- if (rep_quick == 1)
- {
- error_printed=1;
- goto err;
- }
- continue;
- }
- if (sort_write_record())
- goto err;
- }
- if (error > 0 || write_data_suffix(info) ||
- flush_io_cache(&info->rec_cache) || read_cache.error < 0)
- goto err;
-
- if (testflag & T_WRITE_LOOP)
- {
- VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
- }
- if (my_chsize(share->kfile, share->state.key_file_length, 0, MYF(0)))
- {
- print_warning("Can't change size of indexfile, error: %d",my_errno);
- goto err;
- }
-
- if (rep_quick && del+sort_info.dupp != share->state.del)
- {
- print_error("Couldn't fix table with quick recovery: Found wrong number of deleted records");
- print_error("Run recovery again without -q");
- got_error=1;
- goto err;
- }
-
- if (!rep_quick)
- {
- info->dfile=new_file;
- share->state.data_file_length=sort_info.filepos;
- share->state.splitt=share->state.records; /* Only hole records */
- out_flag|=O_NEW_DATA; /* Data in new file */
- share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
- }
- else
- share->state.data_file_length=sort_info.max_pos;
-
- if (!(testflag & T_SILENT))
- {
- if (start_records != share->state.records)
- printf("Data records: %lu\n",(ulong) share->state.records);
- if (sort_info.dupp)
- print_warning("%lu records have been removed",(ulong) sort_info.dupp);
- }
-
- got_error=0;
-err:
- if (got_error)
- {
- if (! error_printed)
- print_error("%d for record at pos %lu",my_errno,
- (ulong) sort_info.start_recpos);
- if (new_file >= 0)
- {
- VOID(my_close(new_file,MYF(0)));
- VOID(my_delete(temp_filename,MYF(MY_WME)));
- }
- }
- if (sort_info.record)
- {
- my_afree(sort_info.record);
- }
- my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
- VOID(end_io_cache(&read_cache));
- info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
- VOID(end_io_cache(&info->rec_cache));
- got_error|=flush_blocks(share->kfile);
- if (!got_error && testflag & T_UNPACK)
- {
- share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
- share->pack.header_length=0;
- share->data_file_type=sort_info.new_data_file_type;
- }
- DBUG_RETURN(got_error);
-} /* rep */
-
-
- /* Uppdaterar nyckelfilen i samband med reparation */
-
-static int writekeys(register N_INFO *info,byte *buff,ulong filepos)
-{
- register uint i;
- uchar *key;
- DBUG_ENTER("writekeys");
-
- key=info->lastkey+info->s->base.max_key_length;
- for (i=0 ; i < info->s->state.keys ; i++)
- {
- VOID(_nisam_make_key(info,i,key,buff,filepos));
- if (_nisam_ck_write(info,i,key)) goto err;
- }
- DBUG_RETURN(0);
-
- err:
- if (my_errno == HA_ERR_FOUND_DUPP_KEY)
- {
- info->errkey=(int) i; /* This key was found */
- while ( i-- > 0 )
- {
- VOID(_nisam_make_key(info,i,key,buff,filepos));
- if (_nisam_ck_delete(info,i,key)) break;
- }
- }
- DBUG_PRINT("error",("errno: %d",my_errno));
- DBUG_RETURN(-1);
-} /* writekeys */
-
-
- /* Write info about table */
-
-static void descript(info,name)
-reg1 N_INFO *info;
-my_string name;
-{
- uint key,field,start,len;
- reg3 N_KEYDEF *keyinfo;
- reg2 N_KEYSEG *keyseg;
- reg4 const char *text;
- char buff[40],length[10],*pos,*end;
- enum en_fieldtype type;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("describe");
-
- printf("\nISAM file: %s\n",name);
- if (testflag & T_VERBOSE)
- {
- printf("Isam-version: %d\n",(int) share->state.header.file_version[3]);
- if (share->base.create_time)
- {
- get_date(buff,1,share->base.create_time);
- printf("Creation time: %s\n",buff);
- }
- if (share->base.isamchk_time)
- {
- get_date(buff,1,share->base.isamchk_time);
- printf("Recover time: %s\n",buff);
- }
- }
- printf("Data records: %10lu Deleted blocks: %10lu\n",
- share->state.records,share->state.del);
- if (testflag & T_SILENT)
- DBUG_VOID_RETURN; /* This is enough */
-
- if (testflag & T_VERBOSE)
- {
-#ifdef USE_RELOC
- printf("Init-relocation: %10lu\n",share->base.reloc);
-#endif
- printf("Datafile Parts: %10lu Deleted data: %10lu\n",
- share->state.splitt,share->state.empty);
- printf("Datafile pointer (bytes):%6d Keyfile pointer (bytes):%6d\n",
- share->rec_reflength,share->base.key_reflength);
- if (info->s->base.reloc == 1L && info->s->base.records == 1L)
- puts("This is a one-record table");
- else
- {
- if (share->base.max_data_file_length != NI_POS_ERROR ||
- share->base.max_key_file_length != NI_POS_ERROR)
- printf("Max datafile length: %10lu Max keyfile length: %10lu\n",
- share->base.max_data_file_length-1,
- share->base.max_key_file_length-1);
- }
- }
-
- printf("Recordlength: %10d\n",(int) share->base.reclength);
- VOID(fputs("Record format: ",stdout));
- if (share->base.options & HA_OPTION_COMPRESS_RECORD)
- puts("Compressed");
- else if (share->base.options & HA_OPTION_PACK_RECORD)
- puts("Packed");
- else
- puts("Fixed length");
- if (share->state.keys != share->base.keys)
- printf("Using only %d keys of %d possibly keys\n",share->state.keys,
- share->base.keys);
-
- puts("\ntable description:");
- printf("Key Start Len Index Type");
- if (testflag & T_VERBOSE)
- printf(" Root Blocksize Rec/key");
- VOID(putchar('\n'));
-
- for (key=0, keyinfo= &share->keyinfo[0] ; key < share->base.keys;
- key++,keyinfo++)
- {
- keyseg=keyinfo->seg;
- if (keyinfo->base.flag & HA_NOSAME) text="unique ";
- else text="multip.";
-
- pos=buff;
- if (keyseg->base.flag & HA_REVERSE_SORT)
- *pos++ = '-';
- pos=strmov(pos,type_names[keyseg->base.type]);
- *pos++ = ' ';
- *pos=0;
- if (keyinfo->base.flag & HA_PACK_KEY)
- pos=strmov(pos,packed_txt);
- if (keyseg->base.flag & HA_SPACE_PACK)
- pos=strmov(pos,diff_txt);
- printf("%-4d%-6d%-3d %-8s%-21s",
- key+1,keyseg->base.start+1,keyseg->base.length,text,buff);
- if (testflag & T_VERBOSE)
- printf(" %9ld %9d %9ld",
- share->state.key_root[key],keyinfo->base.block_length,
- share->base.rec_per_key[key]);
- VOID(putchar('\n'));
- while ((++keyseg)->base.type)
- {
- pos=buff;
- if (keyseg->base.flag & HA_REVERSE_SORT)
- *pos++ = '-';
- pos=strmov(pos,type_names[keyseg->base.type]);
- *pos++= ' ';
- if (keyseg->base.flag & HA_SPACE_PACK)
- pos=strmov(pos,diff_txt);
- *pos=0;
- printf(" %-6d%-3d %-24s\n",
- keyseg->base.start+1,keyseg->base.length,buff);
- }
- }
- if (verbose > 1)
- {
- printf("\nField Start Length Type");
- if (share->base.options & HA_OPTION_COMPRESS_RECORD)
- printf(" Huff tree Bits");
- VOID(putchar('\n'));
- if (verbose > 2 && share->base.pack_bits)
- printf("- %-7d%-35s\n",share->base.pack_bits,"bit field");
-
- start=1;
- for (field=0 ; field < share->base.fields ; field++)
- {
- if (share->base.options & HA_OPTION_COMPRESS_RECORD)
- type=share->rec[field].base_type;
- else
- type=(enum en_fieldtype) share->rec[field].base.type;
- end=strmov(buff,field_pack[type]);
-#ifndef NOT_PACKED_DATABASES
- if (share->base.options & HA_OPTION_COMPRESS_RECORD)
- {
- if (share->rec[field].pack_type & PACK_TYPE_SELECTED)
- end=strmov(end,", not_always");
- if (share->rec[field].pack_type & PACK_TYPE_SPACE_FIELDS)
- end=strmov(end,", no empty");
- if (share->rec[field].pack_type & PACK_TYPE_ZERO_FILL)
- {
- sprintf(end,", zerofill(%d)",share->rec[field].space_length_bits);
- end=strend(end);
- }
- }
- if (buff[0] == ',')
- strmov(buff,buff+2);
-#endif
- len=(uint) (int10_to_str((long) share->rec[field].base.length,length,10) -
- length);
- if (type == FIELD_BLOB)
- {
- length[len]='+';
- VOID(int10_to_str((long) sizeof(char*),length+len+1,10));
- }
- printf("%-6d%-6d%-7s%-35s",field+1,start,length,buff);
-#ifndef NOT_PACKED_DATABASES
- if (share->base.options & HA_OPTION_COMPRESS_RECORD)
- {
- if (share->rec[field].huff_tree)
- printf("%3d %2d",
- (uint) (share->rec[field].huff_tree-share->decode_trees)+1,
- share->rec[field].huff_tree->quick_table_bits);
- }
-#endif
- VOID(putchar('\n'));
- start+=share->rec[field].base.length;
- if (type == FIELD_BLOB)
- start+=sizeof(char*);
- }
- }
- DBUG_VOID_RETURN;
-} /* describe */
-
-
- /* Change all key-pointers that points to a records */
-
-static int movepoint(info,record,oldpos,newpos,prot_key)
-register N_INFO *info;
-byte *record;
-ulong oldpos,newpos;
-uint prot_key;
-{
- register uint i;
- uchar *key;
- DBUG_ENTER("movepoint");
-
- key=info->lastkey+info->s->base.max_key_length;
- for (i=0 ; i < info->s->state.keys; i++)
- {
- if (i != prot_key)
- {
- VOID(_nisam_make_key(info,i,key,record,oldpos));
- if (info->s->keyinfo[i].base.flag & HA_NOSAME)
- { /* Change pointer direct */
- uint nod_flag;
- N_KEYDEF *keyinfo;
- keyinfo=info->s->keyinfo+i;
- if (_nisam_search(info,keyinfo,key,USE_HOLE_KEY,
- (uint) (SEARCH_SAME | SEARCH_SAVE_BUFF),
- info->s->state.key_root[i]))
- DBUG_RETURN(-1);
- nod_flag=test_if_nod(info->buff);
- _nisam_dpointer(info,info->int_keypos-nod_flag-
- info->s->rec_reflength,newpos);
- if (_nisam_write_keypage(info,keyinfo,info->int_pos,info->buff))
- DBUG_RETURN(-1);
- }
- else
- { /* Change old key to new */
- if (_nisam_ck_delete(info,i,key))
- DBUG_RETURN(-1);
- VOID(_nisam_make_key(info,i,key,record,newpos));
- if (_nisam_ck_write(info,i,key))
- DBUG_RETURN(-1);
- }
- }
- }
- DBUG_RETURN(0);
-} /* movepoint */
-
-
- /* Tell system that we want all memory for our cache */
-
-static void lock_memory(void)
-{
-#ifdef SUN_OS /* Key-cacheing thrases on sun 4.1 */
- int success;
-
- success = mlockall(MCL_CURRENT); /* or plock(DATLOCK); */
-
- if (geteuid() == 0 && success != 0)
- print_warning("Failed to lock memory. errno %d",my_errno);
-#endif
-} /* lock_memory */
-
-
- /* Flush all changed blocks to disk */
-
-static int flush_blocks(file)
-File file;
-{
- if (flush_key_blocks(dflt_key_cache,file,FLUSH_RELEASE))
- {
- print_error("%d when trying to write bufferts",my_errno);
- return(1);
- }
- end_key_cache(dflt_key_cache,1);
- return 0;
-} /* flush_blocks */
-
-
- /* Sort records according to one key */
-
-static int sort_records(info,name,sort_key,write_info)
-register N_INFO *info;
-my_string name;
-uint sort_key;
-int write_info;
-{
- int got_error;
- uint key;
- N_KEYDEF *keyinfo;
- File new_file;
- uchar *temp_buff;
- ulong old_record_count;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("sort_records");
-
- keyinfo= &share->keyinfo[sort_key];
- got_error=1;
- temp_buff=0; record_buff=0;
- new_file= -1;
-
- if (sort_key >= share->state.keys)
- {
- print_error("Can't sort table '%s' on key %d. It has only %d keys",
- name,sort_key+1,share->state.keys);
- error_printed=0;
- DBUG_RETURN(-1);
- }
- if (!(testflag & T_SILENT))
- {
- printf("- Sorting records in ISAM-table '%s'\n",name);
- if (write_info)
- printf("Data records: %7lu Deleted: %7lu\n",
- share->state.records,share->state.del);
- }
- if (share->state.key_root[sort_key] == NI_POS_ERROR)
- DBUG_RETURN(0); /* Nothing to do */
-
- init_key_cache(dflt_key_cache,KEY_CACHE_BLOCK_SIZE,use_buffers, 0, 0);
- if (init_io_cache(&info->rec_cache,-1,(uint) write_buffer_length,
- WRITE_CACHE,share->pack.header_length,1,
- MYF(MY_WME | MY_WAIT_IF_FULL)))
- goto err;
- info->opt_flag|=WRITE_CACHE_USED;
-
- if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->base.block_length)))
- {
- print_error("Not Enough memory");
- goto err;
- }
- if (!(record_buff=(byte*) my_alloca((uint) share->base.reclength)))
- {
- print_error("Not Enough memory");
- goto err;
- }
- if ((new_file=my_create(fn_format(temp_filename,name,"",DATA_TMP_EXT,2+4),
- 0,tmpfile_createflag,MYF(0))) <= 0)
- {
- print_error("Can't create new tempfile: '%s'",temp_filename);
- goto err;
- }
- if (filecopy(new_file,info->dfile,0L,share->pack.header_length,
- "datafile-header"))
- goto err;
- info->rec_cache.file=new_file; /* Use this file for cacheing*/
-
- lock_memory();
- for (key=0 ; key < share->state.keys ; key++)
- share->keyinfo[key].base.flag|= HA_SORT_ALLOWS_SAME;
-
- if (my_pread(share->kfile,(byte*) temp_buff,
- (uint) keyinfo->base.block_length,
- share->state.key_root[sort_key],
- MYF(MY_NABP+MY_WME)))
- {
- print_error("Can't read indexpage from filepos: %lu",
- (ulong) share->state.key_root[sort_key]);
- goto err;
- }
-
- /* Setup param for sort_write_record */
- bzero((char*) &sort_info,sizeof(sort_info));
- sort_info.info=info;
- sort_info.new_data_file_type=share->data_file_type;
- sort_info.fix_datafile=1;
- sort_info.filepos=share->pack.header_length;
- sort_info.record=record_buff;
- old_record_count=share->state.records;
- share->state.records=0;
-
- if (sort_record_index(info,keyinfo,share->state.key_root[sort_key],temp_buff,
- sort_key,new_file) ||
- write_data_suffix(info) ||
- flush_io_cache(&info->rec_cache))
- goto err;
-
- if (share->state.records != old_record_count)
- {
- print_error("found %lu of %lu records",
- (ulong) share->state.records,(ulong) old_record_count);
- goto err;
- }
-
- /* Put same locks as old file */
- if (lock_file(new_file,0L,F_WRLCK,"tempfile",temp_filename))
- goto err;
- VOID(lock_file(info->dfile,0L,F_UNLCK,"datafile of",name));
- VOID(my_close(info->dfile,MYF(MY_WME)));
- out_flag|=O_NEW_DATA; /* Data in new file */
-
- info->dfile=new_file; /* Use new indexfile */
- share->state.del=share->state.empty=0;
- share->state.dellink= NI_POS_ERROR;
- share->state.data_file_length=sort_info.filepos;
- share->state.splitt=share->state.records; /* Only hole records */
- share->state.version=(ulong) time((time_t*) 0);
-
- info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
-
- if (testflag & T_WRITE_LOOP)
- {
- VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
- }
- got_error=0;
-
-err:
- if (got_error && new_file >= 0)
- {
- VOID(my_close(new_file,MYF(MY_WME)));
- VOID(my_delete(temp_filename,MYF(MY_WME)));
- }
- if (temp_buff)
- {
- my_afree((gptr) temp_buff);
- }
- if (record_buff)
- {
- my_afree(record_buff);
- }
- info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
- VOID(end_io_cache(&info->rec_cache));
- share->base.sortkey=sort_key;
- DBUG_RETURN(flush_blocks(share->kfile) | got_error);
-} /* sort_records */
-
-
- /* Sort records recursive using one index */
-
-static int sort_record_index(info,keyinfo,page,buff,sort_key,new_file)
-N_INFO *info;
-N_KEYDEF *keyinfo;
-ulong page;
-uchar *buff;
-uint sort_key;
-File new_file;
-{
- uint nod_flag,used_length;
- uchar *temp_buff,*keypos,*endpos;
- ulong next_page,rec_pos;
- uchar lastkey[N_MAX_KEY_BUFF];
- DBUG_ENTER("sort_record_index");
-
- nod_flag=test_if_nod(buff);
- temp_buff=0;
-
- if (nod_flag)
- {
- if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->base.block_length)))
- {
- print_error("Not Enough memory");
- DBUG_RETURN(-1);
- }
- }
- used_length=getint(buff);
- keypos=buff+2+nod_flag;
- endpos=buff+used_length;
- for ( ;; )
- {
- _sanity(__FILE__,__LINE__);
- if (nod_flag)
- {
- next_page=_nisam_kpos(nod_flag,keypos);
- if (my_pread(info->s->kfile,(byte*) temp_buff,
- (uint) keyinfo->base.block_length, next_page,
- MYF(MY_NABP+MY_WME)))
- {
- print_error("Can't read keys from filepos: %lu",(ulong) next_page);
- goto err;
- }
- if (sort_record_index(info,keyinfo,next_page,temp_buff,sort_key,
- new_file))
- goto err;
- }
- _sanity(__FILE__,__LINE__);
- if (keypos >= endpos ||
- (*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey) == 0)
- break;
- rec_pos= _nisam_dpos(info,nod_flag,keypos);
-
- if ((*info->s->read_rnd)(info,record_buff,rec_pos,0))
- {
- print_error("%d when reading datafile",my_errno);
- goto err;
- }
- if (rec_pos != sort_info.filepos)
- {
- _nisam_dpointer(info,keypos-nod_flag-info->s->rec_reflength,
- sort_info.filepos);
- if (movepoint(info,record_buff,rec_pos,sort_info.filepos,sort_key))
- {
- print_error("%d when updating key-pointers",my_errno);
- goto err;
- }
- }
- if (sort_write_record())
- goto err;
- }
- bzero((byte*) buff+used_length,keyinfo->base.block_length-used_length);
- if (my_pwrite(info->s->kfile,(byte*) buff,(uint) keyinfo->base.block_length,
- page,MYF_RW))
- {
- print_error("%d when updating keyblock",my_errno);
- goto err;
- }
- if (temp_buff)
- my_afree((gptr) temp_buff);
- DBUG_RETURN(0);
-err:
- if (temp_buff)
- my_afree((gptr) temp_buff);
- DBUG_RETURN(1);
-} /* sort_record_index */
-
-
- /* Sort index for more efficent reads */
-
-static int sort_index(info,name)
-register N_INFO *info;
-my_string name;
-{
- reg2 uint key;
- reg1 N_KEYDEF *keyinfo;
- File new_file;
- ulong index_pos[N_MAXKEY];
- DBUG_ENTER("sort_index");
-
- if (!(testflag & T_SILENT))
- printf("- Sorting index for ISAM-table '%s'\n",name);
-
- if ((new_file=my_create(fn_format(temp_filename,name,"",INDEX_TMP_EXT,2+4),
- 0,tmpfile_createflag,MYF(0))) <= 0)
- {
- print_error("Can't create new tempfile: '%s'",temp_filename);
- DBUG_RETURN(-1);
- }
- if (filecopy(new_file,info->s->kfile,0L,(ulong) info->s->base.keystart,
- "headerblock"))
- goto err;
-
- new_file_pos=info->s->base.keystart;
- for (key= 0,keyinfo= &info->s->keyinfo[0]; key < info->s->state.keys ;
- key++,keyinfo++)
- {
- if (info->s->state.key_root[key] != NI_POS_ERROR)
- {
- index_pos[key]=new_file_pos; /* Write first block here */
- if (!_nisam_fetch_keypage(info,keyinfo,info->s->state.key_root[key],
- info->buff,0))
- {
- print_error("Can't read indexpage from filepos: %lu",
- (ulong) info->s->state.key_root[key]);
- goto err;
- }
- if (sort_one_index(info,keyinfo,info->buff,new_file))
- goto err;
- }
- else
- index_pos[key]= NI_POS_ERROR; /* No blocks */
- }
-
- /* Put same locks as old file */
- if (lock_file(new_file,0L,F_WRLCK,"tempfile",temp_filename))
- goto err;
- info->s->state.version=(ulong) time((time_t*) 0);
- VOID(_nisam_writeinfo(info,1)); /* This unlocks table */
- VOID(my_close(info->s->kfile,MYF(MY_WME)));
- out_flag|=O_NEW_INDEX; /* Data in new file */
-
- info->s->kfile=new_file;
- info->s->state.key_file_length=new_file_pos;
- info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- for (key=0 ; key < info->s->state.keys ; key++)
- {
- info->s->state.key_root[key]=index_pos[key];
- info->s->state.key_del[key]= NI_POS_ERROR;
- }
- DBUG_RETURN(0);
-
-err:
- VOID(my_close(new_file,MYF(MY_WME)));
- VOID(my_delete(temp_filename,MYF(MY_WME)));
- DBUG_RETURN(-1);
-} /* sort_index */
-
-
- /* Sort records recursive using one index */
-
-static int sort_one_index(info,keyinfo,buff,new_file)
-N_INFO *info;
-N_KEYDEF *keyinfo;
-uchar *buff;
-File new_file;
-{
- uint length,nod_flag,used_length;
- uchar *temp_buff,*keypos,*endpos;
- ulong new_page_pos,next_page;
- DBUG_ENTER("sort_one_index");
-
- temp_buff=0;
- new_page_pos=new_file_pos;
- new_file_pos+=keyinfo->base.block_length;
-
- if ((nod_flag=test_if_nod(buff)))
- {
- if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->base.block_length)))
- {
- print_error("Not Enough memory");
- DBUG_RETURN(-1);
- }
-
- used_length=getint(buff);
- keypos=buff+2+nod_flag;
- endpos=buff+used_length;
- for ( ;; )
- {
- if (nod_flag)
- {
- next_page=_nisam_kpos(nod_flag,keypos);
- _nisam_kpointer(info,keypos-nod_flag,new_file_pos); /* Save new pos */
- if (!_nisam_fetch_keypage(info,keyinfo,next_page,temp_buff,0))
- {
- print_error("Can't read keys from filepos: %lu",
- (ulong) next_page);
- goto err;
- }
- if (sort_one_index(info,keyinfo,temp_buff,new_file))
- goto err;
- }
- if (keypos >= endpos ||
- ((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,info->lastkey)) == 0)
- break;
- }
- my_afree((gptr) temp_buff);
- }
-
- /* Fill block with zero and write it to new file */
-
- length=getint(buff);
- bzero((byte*) buff+length,keyinfo->base.block_length-length);
- if (my_pwrite(new_file,(byte*) buff,(uint) keyinfo->base.block_length,
- new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
- {
- print_error("Can't write indexblock, error: %d",my_errno);
- goto err;
- }
- DBUG_RETURN(0);
-err:
- if (temp_buff)
- my_afree((gptr) temp_buff);
- DBUG_RETURN(1);
-} /* sort_one_index */
-
-
- /* Change to use new file */
- /* Copy stats from old file to new file, deletes orginal and */
- /* changes new file name to old file name */
-
-static int change_to_newfile(filename,old_ext,new_ext)
-const char *filename,*old_ext,*new_ext;
-{
- char old_filename[FN_REFLEN],new_filename[FN_REFLEN];
-
- return my_redel(fn_format(old_filename,filename,"",old_ext,2+4),
- fn_format(new_filename,filename,"",new_ext,2+4),
- MYF(MY_WME+MY_LINK_WARNING));
-} /* change_to_newfile */
-
-
- /* Locks a hole file */
- /* Gives error-message if file can't be locked */
-
-static int lock_file(file,start,lock_type,filetype,filename)
-File file;
-ulong start;
-int lock_type;
-const char *filetype,*filename;
-{
-#ifndef NO_LOCKING
- if (my_lock(file,lock_type,start,F_TO_EOF,
- testflag & T_WAIT_FOREVER ? MYF(MY_SEEK_NOT_DONE) :
- MYF(MY_SEEK_NOT_DONE | MY_DONT_WAIT)))
- {
- print_error(" %d when %s %s '%s'",my_errno,
- lock_type == F_UNLCK ? "unlocking": "locking",
- filetype,filename);
- error_printed=2; /* Don't give that data is crashed */
- return 1;
- }
-#endif
- return 0;
-} /* lock_file */
-
-
- /* Copy a block between two files */
-
-static int filecopy(File to,File from,ulong start,ulong length,
- const char *type)
-{
- char tmp_buff[IO_SIZE],*buff;
- ulong buff_length;
- DBUG_ENTER("filecopy");
-
- buff_length=min(write_buffer_length,length);
- if (!(buff=my_malloc(buff_length,MYF(0))))
- {
- buff=tmp_buff; buff_length=IO_SIZE;
- }
-
- VOID(my_seek(from,start,MY_SEEK_SET,MYF(0)));
- while (length > buff_length)
- {
- if (my_read(from,(byte*) buff,buff_length,MYF(MY_NABP)) ||
- my_write(to,(byte*) buff,buff_length,MYF(MY_NABP | MY_WAIT_IF_FULL)))
- goto err;
- length-= buff_length;
- }
- if (my_read(from,(byte*) buff,(uint) length,MYF(MY_NABP)) ||
- my_write(to,(byte*) buff,(uint) length,MYF(MY_NABP | MY_WAIT_IF_FULL)))
- goto err;
- if (buff != tmp_buff)
- my_free(buff,MYF(0));
- DBUG_RETURN(0);
-err:
- if (buff != tmp_buff)
- my_free(buff,MYF(0));
- print_error("Can't copy %s to tempfile, error %d",type,my_errno);
- DBUG_RETURN(1);
-}
-
-
- /* Fix table using sorting */
- /* saves new table in temp_filename */
-
-static int rep_by_sort(info,name)
-reg1 N_INFO *info;
-my_string name;
-{
- int got_error;
- uint i,length;
- ulong start_records,new_header_length,del;
- File new_file;
- SORT_PARAM sort_param;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("rep_by_sort");
-
- start_records=share->state.records;
- got_error=1;
- new_file= -1;
- new_header_length=(testflag & T_UNPACK) ? 0 : share->pack.header_length;
- if (!(testflag & T_SILENT))
- {
- printf("- recovering ISAM-table '%s'\n",name);
- printf("Data records: %lu\n",(ulong) start_records);
- }
- bzero((char*) &sort_info,sizeof(sort_info));
- if (!(sort_info.key_block=alloc_key_blocks((uint) sort_key_blocks,
- share->base.max_block))
- || init_io_cache(&read_cache,info->dfile,(uint) read_buffer_length,
- READ_CACHE,share->pack.header_length,1,MYF(MY_WME)) ||
- (! rep_quick &&
- init_io_cache(&info->rec_cache,info->dfile,(uint) write_buffer_length,
- WRITE_CACHE,new_header_length,1,
- MYF(MY_WME | MY_WAIT_IF_FULL))))
- goto err;
- sort_info.key_block_end=sort_info.key_block+sort_key_blocks;
- info->opt_flag|=WRITE_CACHE_USED;
- info->rec_cache.file=info->dfile; /* for sort_delete_record */
-
- if (!(sort_info.record=(byte*) my_alloca((uint) share->base.reclength)))
- {
- print_error("Not enough memory for extra record");
- goto err;
- }
- if (!rep_quick)
- {
- if ((new_file=my_create(fn_format(temp_filename,name,"",DATA_TMP_EXT,
- 2+4),
- 0,tmpfile_createflag,MYF(0))) < 0)
- {
- print_error("Can't create new tempfile: '%s'",temp_filename);
- goto err;
- }
- if (filecopy(new_file,info->dfile,0L,new_header_length,"datafile-header"))
- goto err;
- if (testflag & T_UNPACK)
- share->base.options&= ~HA_OPTION_COMPRESS_RECORD;
- share->state.dellink= NI_POS_ERROR;
- info->rec_cache.file=new_file;
- }
-
- info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- for (i=0 ; i < N_MAXKEY ; i++)
- share->state.key_del[i]=share->state.key_root[i]= NI_POS_ERROR;
- share->state.key_file_length=share->base.keystart;
-
- sort_info.info=info;
- if ((sort_info.new_data_file_type=share->data_file_type) ==
- COMPRESSED_RECORD && testflag & T_UNPACK)
- {
- if (share->base.options & HA_OPTION_PACK_RECORD)
- sort_info.new_data_file_type = DYNAMIC_RECORD;
- else
- sort_info.new_data_file_type = STATIC_RECORD;
- }
-
- sort_info.filepos=new_header_length;
- sort_info.dupp=0;
- read_cache.end_of_file=sort_info.filelength=
- (ulong) my_seek(read_cache.file,0L,MY_SEEK_END,MYF(0));
-
- if (share->data_file_type == DYNAMIC_RECORD)
- length=max(share->base.min_pack_length+1,share->base.min_block_length);
- else if (share->data_file_type == COMPRESSED_RECORD)
- length=share->base.min_block_length;
- else
- length=share->base.reclength;
- sort_param.max_records=sort_info.max_records=sort_info.filelength/length+1;
- sort_param.key_cmp=sort_key_cmp;
- sort_param.key_write=sort_key_write;
- sort_param.key_read=sort_key_read;
- sort_param.lock_in_memory=lock_memory;
- del=share->state.del;
-
- for (sort_info.key=0 ; sort_info.key < share->state.keys ; sort_info.key++)
- {
- if ((!(testflag & T_SILENT)))
- printf ("- Fixing index %d\n",sort_info.key+1);
- sort_info.max_pos=sort_info.pos=share->pack.header_length;
- sort_info.keyinfo=share->keyinfo+sort_info.key;
- sort_info.keyseg=sort_info.keyinfo->seg;
- sort_info.fix_datafile= (my_bool) (sort_info.key == 0 && ! rep_quick);
- sort_info.unique=0;
- sort_param.key_length=share->rec_reflength;
- for (i=0 ; sort_info.keyseg[i].base.type ; i++)
- sort_param.key_length+=sort_info.keyseg[i].base.length+
- (sort_info.keyseg[i].base.flag & HA_SPACE_PACK ? 1 : 0);
- share->state.records=share->state.del=share->state.empty=share->state.splitt=0;
-
- if (_create_index_by_sort(&sort_param,
- (pbool) (!(testflag & T_VERBOSE)),
- (uint) sort_buffer_length))
- goto err;
- /* Set for next loop */
- sort_param.max_records=sort_info.max_records=share->state.records;
- share->base.rec_per_key[sort_info.key]=
- sort_info.unique ? ((sort_info.max_records+sort_info.unique/2)/
- sort_info.unique)
- : 1L;
-
- if (sort_info.fix_datafile)
- {
- info->dfile=new_file;
- share->state.data_file_length=sort_info.filepos;
- share->state.splitt=share->state.records; /* Only hole records */
- share->state.version=(ulong) time((time_t*) 0);
- out_flag|=O_NEW_DATA; /* Data in new file */
- read_cache.end_of_file=sort_info.filepos;
- if (write_data_suffix(info) || end_io_cache(&info->rec_cache))
- goto err;
- share->data_file_type=sort_info.new_data_file_type;
- share->pack.header_length=new_header_length;
- }
- else
- share->state.data_file_length=sort_info.max_pos;
-
- if (flush_pending_blocks())
- goto err;
-
- read_cache.file=info->dfile; /* re-init read cache */
- reinit_io_cache(&read_cache,READ_CACHE,share->pack.header_length,1,1);
- }
-
- if (testflag & T_WRITE_LOOP)
- {
- VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
- }
-
- if (rep_quick && del+sort_info.dupp != share->state.del)
- {
- print_error("Couldn't fix table with quick recovery: Found wrong number of deleted records");
- print_error("Run recovery again without -q");
- got_error=1;
- goto err;
- }
-
- if (rep_quick != 1)
- {
- ulong skr=share->state.data_file_length+
- (share->base.options & HA_OPTION_COMPRESS_RECORD ?
- MEMMAP_EXTRA_MARGIN : 0);
-#ifdef USE_RELOC
- if (share->data_file_type == STATIC_RECORD &&
- skr < share->base.reloc*share->base.min_pack_length)
- skr=share->base.reloc*share->base.min_pack_length;
-#endif
- if (skr != sort_info.filelength)
- if (my_chsize(info->dfile, skr, 0, MYF(0)))
- print_warning("Can't change size of datafile, error: %d",my_errno);
- }
- if (my_chsize(share->kfile, share->state.key_file_length, 0, MYF(0)))
- print_warning("Can't change size of indexfile, error: %d",my_errno);
-
- if (!(testflag & T_SILENT))
- {
- if (start_records != share->state.records)
- printf("Data records: %lu\n",(ulong) share->state.records);
- if (sort_info.dupp)
- print_warning("%lu records have been removed",(ulong) sort_info.dupp);
- }
- got_error=0;
-
-err:
- if (got_error)
- {
- if (! error_printed)
- print_error("%d when fixing table",my_errno);
- if (new_file >= 0)
- {
- VOID(end_io_cache(&info->rec_cache));
- VOID(my_close(new_file,MYF(0)));
- VOID(my_delete(temp_filename,MYF(MY_WME)));
- }
- }
- if (sort_info.key_block)
- my_free((gptr) sort_info.key_block,MYF(0));
- if (sort_info.record)
- {
- my_afree(sort_info.record);
- }
- VOID(end_io_cache(&read_cache));
- VOID(end_io_cache(&info->rec_cache));
- info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
- if (!got_error && testflag & T_UNPACK)
- {
- share->state.header.options[0]&= (uchar) ~HA_OPTION_COMPRESS_RECORD;
- share->pack.header_length=0;
- }
- DBUG_RETURN(got_error);
-} /* rep_by_sort */
-
-
- /* Read next record and return next key */
-
-static int sort_key_read(key)
-void *key;
-{
- int error;
- N_INFO *info;
- DBUG_ENTER("sort_key_read");
-
- info=sort_info.info;
-
- if ((error=sort_get_next_record()))
- DBUG_RETURN(error);
- if (info->s->state.records == sort_info.max_records)
- {
- print_error("Found too many records; Can`t continue");
- DBUG_RETURN(1);
- }
- VOID(_nisam_make_key(info,sort_info.key,key,sort_info.record,
- sort_info.filepos));
- DBUG_RETURN(sort_write_record());
-} /* sort_key_read */
-
-
- /* Read next record from file using parameters in sort_info */
- /* Return -1 if end of file, 0 if ok and > 0 if error */
-
-static int sort_get_next_record()
-{
- int searching;
- uint found_record,b_type,left_length;
- ulong pos;
- byte *to;
- BLOCK_INFO block_info;
- N_INFO *info;
- ISAM_SHARE *share;
- DBUG_ENTER("sort_get_next_record");
-
- info=sort_info.info;
- share=info->s;
- switch (share->data_file_type) {
- case STATIC_RECORD:
- for (;;)
- {
- if (my_b_read(&read_cache,sort_info.record,share->base.reclength))
- DBUG_RETURN(-1);
- sort_info.start_recpos=sort_info.pos;
- if (!sort_info.fix_datafile)
- sort_info.filepos=sort_info.pos;
- sort_info.max_pos=(sort_info.pos+=share->base.reclength);
- share->state.splitt++;
- if (*sort_info.record)
- DBUG_RETURN(0);
- if (!sort_info.fix_datafile)
- {
- share->state.del++;
- share->state.empty+=share->base.reclength;
- }
- }
- case DYNAMIC_RECORD:
- LINT_INIT(to);
- pos=sort_info.pos;
- searching=(sort_info.fix_datafile && (testflag & T_EXTEND));
- for (;;)
- {
- found_record=block_info.second_read= 0;
- left_length=1;
- do
- {
- if (pos > sort_info.max_pos)
- sort_info.max_pos=pos;
- if (found_record && pos == search_after_block)
- print_info("Block: %lu used by record at %lu",
- search_after_block,
- sort_info.start_recpos);
- if (_nisam_read_cache(&read_cache,(byte*) block_info.header,pos,
- BLOCK_INFO_HEADER_LENGTH, test(! found_record) | 2))
- {
- if (found_record)
- {
- print_info("Can't read whole record at %lu (errno: %d)",
- (ulong) sort_info.start_recpos,errno);
- goto try_next;
- }
- DBUG_RETURN(-1);
- }
- if (searching && ! sort_info.fix_datafile)
- {
- error_printed=1;
- DBUG_RETURN(1); /* Something wrong with data */
- }
- if (((b_type=_nisam_get_block_info(&block_info,-1,pos)) &
- (BLOCK_ERROR | BLOCK_FATAL_ERROR)) ||
- ((b_type & BLOCK_FIRST) &&
- (block_info.rec_len < (uint) share->base.min_pack_length ||
- block_info.rec_len > (uint) share->base.max_pack_length)))
- {
- uint i;
- if (testflag & T_VERBOSE || searching == 0)
- print_info("Wrong bytesec: %3d-%3d-%3d at %10lu; Skipped",
- block_info.header[0],block_info.header[1],
- block_info.header[2],pos);
- if (found_record)
- goto try_next;
- block_info.second_read=0;
- searching=1;
- for (i=1 ; i < 11 ; i++) /* Skip from read string */
- if (block_info.header[i] >= 1 && block_info.header[i] <= 16)
- break;
- pos+=(ulong) i;
- continue;
- }
- if (block_info.block_len+ (uint) (block_info.filepos-pos) <
- share->base.min_block_length ||
- block_info.block_len-4 > (uint) share->base.max_pack_length)
- {
- if (!searching)
- print_info("Found block with impossible length %u at %lu; Skipped",
- block_info.block_len+ (uint) (block_info.filepos-pos),
- (ulong) pos);
- if (found_record)
- goto try_next;
- searching=1;
- pos++;
- block_info.second_read=0;
- continue;
- }
- if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
- {
- if (!sort_info.fix_datafile && (b_type & BLOCK_DELETED))
- {
- share->state.empty+=block_info.block_len;
- share->state.del++;
- share->state.splitt++;
- }
- if (found_record)
- goto try_next;
- /* Check if impossible big deleted block */
- if (block_info.block_len > share->base.max_pack_length +4)
- searching=1;
- if (searching)
- pos++;
- else
- pos=block_info.filepos+block_info.block_len;
- block_info.second_read=0;
- continue;
- }
-
- share->state.splitt++;
- if (! found_record++)
- {
- sort_info.find_length=left_length=block_info.rec_len;
- sort_info.start_recpos=pos;
- if (!sort_info.fix_datafile)
- sort_info.filepos=sort_info.start_recpos;
- if (sort_info.fix_datafile && (testflag & T_EXTEND))
- sort_info.pos=block_info.filepos+1;
- else
- sort_info.pos=block_info.filepos+block_info.block_len;
- if (share->base.blobs)
- {
- if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
- {
- print_error("Not enough memory for blob at %lu",
- (ulong) sort_info.start_recpos);
- DBUG_RETURN(-1);
- }
- }
- else
- to= info->rec_buff;
- }
- if (left_length < block_info.data_len || ! block_info.data_len)
- {
- print_info("Found block with too small length at %lu; Skipped",
- (ulong) sort_info.start_recpos);
- goto try_next;
- }
- if (block_info.filepos + block_info.data_len > read_cache.end_of_file)
- {
- print_info("Found block that points outside data file at %lu",
- (ulong) sort_info.start_recpos);
- goto try_next;
- }
- if (_nisam_read_cache(&read_cache,to,block_info.filepos,
- block_info.data_len, test(found_record == 1)))
- {
- print_info("Read error for block at: %lu (error: %d); Skipped",
- (ulong) block_info.filepos,my_errno);
- goto try_next;
- }
- left_length-=block_info.data_len;
- to+=block_info.data_len;
- pos=block_info.next_filepos;
- if (pos == NI_POS_ERROR && left_length)
- {
- print_info("Wrong block with wrong total length starting at %lu",
- (ulong) sort_info.start_recpos);
- goto try_next;
- }
- if (pos + BLOCK_INFO_HEADER_LENGTH > read_cache.end_of_file)
- {
- print_info("Found link that points at %lu (outside data file) at %lu",
- (ulong) pos,(ulong) sort_info.start_recpos);
- goto try_next;
- }
- } while (left_length);
-
- if (_nisam_rec_unpack(info,sort_info.record,info->rec_buff,
- sort_info.find_length) != MY_FILE_ERROR)
- {
- if (read_cache.error < 0)
- DBUG_RETURN(1);
- if ((testflag & (T_EXTEND | T_REP)) || searching)
- {
- if (_nisam_rec_check(info, sort_info.record))
- {
- print_info("Found wrong packed record at %lu",
- (ulong) sort_info.start_recpos);
- goto try_next;
- }
- }
- DBUG_RETURN(0);
- }
- if (!searching)
- {
- print_info("Found wrong packed record at %lu",
- (ulong) sort_info.start_recpos);
- }
- try_next:
- pos=sort_info.start_recpos+1;
- searching=1;
- }
- case COMPRESSED_RECORD:
- for (searching=0 ;; searching=1, sort_info.pos++)
- {
- if (_nisam_read_cache(&read_cache,(byte*) block_info.header,sort_info.pos,
- share->pack.ref_length,1))
- DBUG_RETURN(-1);
- if (searching && ! sort_info.fix_datafile)
- {
- error_printed=1;
- DBUG_RETURN(1); /* Something wrong with data */
- }
- sort_info.start_recpos=sort_info.pos;
- VOID(_nisam_pack_get_block_info(&block_info,share->pack.ref_length,-1,
- sort_info.pos));
- if (!block_info.rec_len &&
- sort_info.pos + MEMMAP_EXTRA_MARGIN == read_cache.end_of_file)
- DBUG_RETURN(-1);
- if (block_info.rec_len < (uint) share->min_pack_length ||
- block_info.rec_len > (uint) share->max_pack_length)
- {
- if (! searching)
- print_info("Found block with wrong recordlength: %d at %lu\n",
- block_info.rec_len, (ulong) sort_info.pos);
- continue;
- }
- if (_nisam_read_cache(&read_cache,(byte*) info->rec_buff,
- block_info.filepos, block_info.rec_len,1))
- {
- if (! searching)
- print_info("Couldn't read hole record from %lu",
- (ulong) sort_info.pos);
- continue;
- }
- if (_nisam_pack_rec_unpack(info,sort_info.record,info->rec_buff,
- block_info.rec_len))
- {
- if (! searching)
- print_info("Found wrong record at %lu",(ulong) sort_info.pos);
- continue;
- }
- if (!sort_info.fix_datafile)
- sort_info.filepos=sort_info.pos;
- sort_info.max_pos=(sort_info.pos+=share->pack.ref_length+
- block_info.rec_len);
- share->state.splitt++;
- info->packed_length=block_info.rec_len;
- DBUG_RETURN(0);
- }
- }
- DBUG_RETURN(1); /* Impossible */
-}
-
-
- /* Write record to new file */
-
-static int sort_write_record()
-{
- int flag;
- uint block_length,reclength;
- byte *from;
- uchar *block_buff[3];
- N_INFO *info;
- ISAM_SHARE *share;
- DBUG_ENTER("sort_write_record");
-
- info=sort_info.info;
- share=info->s;
- if (sort_info.fix_datafile)
- {
- switch (sort_info.new_data_file_type) {
- case STATIC_RECORD:
- if (my_b_write(&info->rec_cache,sort_info.record, share->base.reclength))
- {
- print_error("%d when writing to datafile",my_errno);
- DBUG_RETURN(1);
- }
- sort_info.filepos+=share->base.reclength;
- break;
- case DYNAMIC_RECORD:
- if (! info->blobs)
- from=info->rec_buff;
- else
- {
- /* must be sure that local buffer is big enough */
- reclength=info->s->base.pack_reclength+
- _calc_total_blob_length(info,sort_info.record)+
- ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
- DYN_DELETE_BLOCK_HEADER;
- if (sort_info.buff_length < reclength)
- {
- if (!(sort_info.buff=my_realloc(sort_info.buff, (uint) reclength,
- MYF(MY_FREE_ON_ERROR |
- MY_ALLOW_ZERO_PTR))))
- DBUG_RETURN(1);
- sort_info.buff_length=reclength;
- }
- from=sort_info.buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER);
- }
- reclength=_nisam_rec_pack(info,from,sort_info.record);
- block_length=reclength+ 3 +test(reclength > 65532L);
- if (block_length < share->base.min_block_length)
- block_length=share->base.min_block_length;
- flag=0;
- info->update|=HA_STATE_WRITE_AT_END;
- if (_nisam_write_part_record(info,0L,block_length,NI_POS_ERROR,
- &from,&reclength,&flag))
- {
- print_error("%d when writing to datafile",my_errno);
- DBUG_RETURN(1);
- }
- sort_info.filepos+=block_length;
- break;
- case COMPRESSED_RECORD:
- reclength=info->packed_length;
- save_integer((byte*) block_buff,share->pack.ref_length,reclength);
- if (my_b_write(&info->rec_cache,(byte*) block_buff,share->pack.ref_length)
- || my_b_write(&info->rec_cache,(byte*) info->rec_buff,reclength))
- {
- print_error("%d when writing to datafile",my_errno);
- DBUG_RETURN(1);
- }
- sort_info.filepos+=reclength+share->pack.ref_length;
- break;
- }
- }
- share->state.records++;
- if (testflag & T_WRITE_LOOP && share->state.records % WRITE_COUNT == 0)
- {
- printf("%lu\r",(ulong) share->state.records); VOID(fflush(stdout));
- }
- DBUG_RETURN(0);
-} /* sort_write_record */
-
-
- /* Compare two keys from _create_index_by_sort */
-
-static int sort_key_cmp(const void *not_used __attribute__((unused)),
- const void *a,const void *b)
-{
- return (_nisam_key_cmp(sort_info.keyseg,*((uchar**) a),*((uchar**) b),0,
- SEARCH_SAME));
-} /* sort_key_cmp */
-
-
-static int sort_key_write( const void *a)
-{
- int cmp=sort_info.key_block->inited ?
- _nisam_key_cmp(sort_info.keyseg,sort_info.key_block->lastkey,(uchar*) a,
- 0,SEARCH_FIND) : -1L;
- if ((sort_info.keyinfo->base.flag & HA_NOSAME) &&
- cmp == 0)
- {
- sort_info.dupp++;
- print_warning("Dupplicate key for record at %10lu against record at %10lu",
- sort_info.info->lastpos=get_record_for_key(sort_info.info,
- sort_info.keyinfo,
- (uchar*) a),
- get_record_for_key(sort_info.info,sort_info.keyinfo,
- sort_info.key_block->lastkey));
- if (testflag & T_VERBOSE)
- _nisam_print_key(stdout,sort_info.keyseg,(uchar*) a);
- return(sort_delete_record());
- }
- if (cmp)
- sort_info.unique++;
-#ifndef DBUG_OFF
- if (cmp > 0)
- {
- print_error("Fatal intern error: Keys are not in order from sort");
- return(1);
- }
-#endif
- return (sort_insert_key(sort_info.key_block,(uchar*) a,NI_POS_ERROR));
-} /* sort_key_write */
-
-
- /* get pointer to record from a key */
-
-static ulong get_record_for_key( N_INFO *info, N_KEYDEF *keyinfo, uchar *key)
-{
- return _nisam_dpos(info,0,key+_nisam_keylength(keyinfo,key));
-} /* get_record_for_key */
-
-
- /* Insert a key in sort-key-blocks */
-
-static int sort_insert_key(reg1 ISAM_SORT_KEY_BLOCKS *key_block,
- uchar *key, ulong prev_block)
-{
- uint a_length,t_length,nod_flag;
- ulong filepos;
- uchar *anc_buff,*lastkey;
- S_PARAM s_temp;
- N_INFO *info;
- DBUG_ENTER("sort_insert_key");
-
- anc_buff=key_block->buff;
- info=sort_info.info;
- lastkey=key_block->lastkey;
- nod_flag= (key_block == sort_info.key_block ? 0 :
- sort_info.info->s->base.key_reflength);
-
- if (!key_block->inited)
- {
- key_block->inited=1;
- if (key_block == sort_info.key_block_end)
- {
- print_error("To many keyblocklevels; Try increasing sort_key_blocks");
- DBUG_RETURN(1);
- }
- a_length=2+nod_flag;
- key_block->end_pos=anc_buff+2;
- lastkey=0; /* No previous key in block */
- }
- else
- a_length=getint(anc_buff);
-
- /* Save pointer to previous block */
- if (nod_flag)
- _nisam_kpointer(info,key_block->end_pos,prev_block);
-
- t_length=_nisam_get_pack_key_length(sort_info.keyinfo,nod_flag,
- (uchar*) 0,lastkey,key,&s_temp);
- _nisam_store_key(sort_info.keyinfo,key_block->end_pos+nod_flag,&s_temp);
- a_length+=t_length;
- putint(anc_buff,a_length,nod_flag);
- key_block->end_pos+=t_length;
- if (a_length <= sort_info.keyinfo->base.block_length)
- {
- VOID(_nisam_move_key(sort_info.keyinfo,key_block->lastkey,key));
- key_block->last_length=a_length-t_length;
- DBUG_RETURN(0);
- }
-
- /* Fill block with end-zero and write filled block */
- putint(anc_buff,key_block->last_length,nod_flag);
- bzero((byte*) anc_buff+key_block->last_length,
- sort_info.keyinfo->base.block_length- key_block->last_length);
- if ((filepos=_nisam_new(info,sort_info.keyinfo)) == NI_POS_ERROR)
- return 1;
- if (my_pwrite(info->s->kfile,(byte*) anc_buff,
- (uint) sort_info.keyinfo->base.block_length,filepos,MYF_RW))
- DBUG_RETURN(1);
- DBUG_DUMP("buff",(byte*) anc_buff,getint(anc_buff));
-
- /* Write separator-key to block in next level */
- if (sort_insert_key(key_block+1,key_block->lastkey,filepos))
- DBUG_RETURN(1);
-
- /* clear old block and write new key in it */
- key_block->inited=0;
- DBUG_RETURN(sort_insert_key(key_block,key,prev_block));
-} /* sort_insert_key */
-
-
- /* Delete record when we found a dupplicated key */
-
-static int sort_delete_record()
-{
- uint i;
- int old_file,error;
- uchar *key;
- N_INFO *info;
- DBUG_ENTER("sort_delete_record");
-
- if (rep_quick == 1)
- {
- VOID(fputs("Quick-recover aborted; Run recovery without switch 'q' or with switch -qq\n",stderr));
- error_printed=1;
- DBUG_RETURN(1);
- }
- info=sort_info.info;
- if (info->s->base.options & HA_OPTION_COMPRESS_RECORD)
- {
- VOID(fputs("Recover aborted; Can't run standard recovery on compressed tables\nwith errors in data-file\nUse switch '--safe-recover' to fix it\n",stderr));
- error_printed=1;
- DBUG_RETURN(1);
- }
-
- old_file=info->dfile;
- info->dfile=info->rec_cache.file;
- if (sort_info.key)
- {
- key=info->lastkey+info->s->base.max_key_length;
- if ((*info->s->read_rnd)(info,sort_info.record,info->lastpos,0) < 0)
- {
- print_error("Can't read record to be removed");
- info->dfile=old_file;
- DBUG_RETURN(1);
- }
-
- for (i=0 ; i < sort_info.key ; i++)
- {
- VOID(_nisam_make_key(info,i,key,sort_info.record,info->lastpos));
- if (_nisam_ck_delete(info,i,key))
- {
- print_error("Can't delete key %d from record to be removed",i+1);
- info->dfile=old_file;
- DBUG_RETURN(1);
- }
- }
- }
- error=flush_io_cache(&info->rec_cache) || (*info->s->delete_record)(info);
- info->dfile=old_file; /* restore actual value */
- info->s->state.records--;
- DBUG_RETURN(error);
-} /* sort_delete_record */
-
-
- /* Fix all pending blocks and flush everything to disk */
-
-static int flush_pending_blocks()
-{
- uint nod_flag,length;
- ulong filepos;
- N_INFO *info;
- ISAM_SORT_KEY_BLOCKS *key_block;
- DBUG_ENTER("flush_pending_blocks");
-
- filepos= NI_POS_ERROR; /* if empty file */
- info=sort_info.info;
- nod_flag=0;
- for (key_block=sort_info.key_block ; key_block->inited ; key_block++)
- {
- key_block->inited=0;
- length=getint(key_block->buff);
- if (nod_flag)
- _nisam_kpointer(info,key_block->end_pos,filepos);
- if ((filepos=_nisam_new(info,sort_info.keyinfo)) == NI_POS_ERROR)
- DBUG_RETURN(1);
- bzero((byte*) key_block->buff+length,
- sort_info.keyinfo->base.block_length-length);
- if (my_pwrite(info->s->kfile,(byte*) key_block->buff,
- (uint) sort_info.keyinfo->base.block_length,filepos,MYF_RW))
- DBUG_RETURN(1);
- DBUG_DUMP("buff",(byte*) key_block->buff,length);
- nod_flag=1;
- }
- info->s->state.key_root[sort_info.key]=filepos; /* Last is root for tree */
- DBUG_RETURN(0);
-} /* flush_pending_blocks */
-
-
- /* alloc space and pointers for key_blocks */
-
-static ISAM_SORT_KEY_BLOCKS *alloc_key_blocks(uint blocks, uint buffer_length)
-{
- reg1 uint i;
- ISAM_SORT_KEY_BLOCKS *block;
- DBUG_ENTER("alloc_key_blocks");
-
- if (!(block=(ISAM_SORT_KEY_BLOCKS*) my_malloc((sizeof(ISAM_SORT_KEY_BLOCKS)+
- buffer_length+IO_SIZE)*blocks,
- MYF(0))))
- {
- print_error("Not Enough memory for sort-key-blocks");
- return(0);
- }
- for (i=0 ; i < blocks ; i++)
- {
- block[i].inited=0;
- block[i].buff=(uchar*) (block+blocks)+(buffer_length+IO_SIZE)*i;
- }
- DBUG_RETURN(block);
-} /* alloc_key_blocks */
-
-
- /* print warnings and errors */
- /* VARARGS */
-
-static void print_info(const char * fmt,...)
-{
- va_list args;
-
- va_start(args,fmt);
- VOID(vfprintf(stdout, fmt, args));
- VOID(fputc('\n',stdout));
- va_end(args);
- return;
-}
-
-/* VARARGS */
-
-static void print_warning(const char * fmt,...)
-{
- va_list args;
- DBUG_ENTER("print_warning");
-
- if (!warning_printed && !error_printed)
- {
- fflush(stdout);
- if (testflag & T_SILENT)
- fprintf(stderr,"%s: ISAM file %s\n",my_progname,isam_file_name);
- }
- warning_printed=1;
- va_start(args,fmt);
- fprintf(stderr,"%s: warning: ",my_progname);
- VOID(vfprintf(stderr, fmt, args));
- VOID(fputc('\n',stderr));
- va_end(args);
- DBUG_VOID_RETURN;
-}
-
-/* VARARGS */
-
-void print_error(const char *fmt,...)
-{
- va_list args;
- DBUG_ENTER("print_error");
- DBUG_PRINT("enter",("format: %s",fmt));
-
- if (!warning_printed && !error_printed)
- {
- fflush(stdout);
- if (testflag & T_SILENT)
- fprintf(stderr,"%s: ISAM file %s\n",my_progname,isam_file_name);
- }
- error_printed|=1;
- va_start(args,fmt);
- fprintf(stderr,"%s: error: ",my_progname);
- VOID(vfprintf(stderr, fmt, args));
- VOID(fputc('\n',stderr));
- va_end(args);
- DBUG_VOID_RETURN;
-}
-
- /* Check if file is almost full */
-
-static int test_if_almost_full(N_INFO *info)
-{
- double diff= 0.9;
- if (info->s->base.options & HA_OPTION_COMPRESS_RECORD)
- { /* Fix problem with pack_isam */
- diff=1.0;
- if (info->s->base.rec_reflength == 4)
- info->s->base.max_data_file_length= (uint32) ~0L;
- else
- info->s->base.max_data_file_length=
- 1L << (info->s->base.rec_reflength);
- }
- return (my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0)) >
- (ulong) (info->s->base.max_key_file_length*diff) ||
- my_seek(info->dfile,0L,MY_SEEK_END,MYF(0)) >
- (ulong) (info->s->base.max_data_file_length*diff));
-}
-
- /* Recreate table with bigger more alloced record-data */
-
-static int recreate_database(N_INFO **org_info, char *filename)
-{
- int error;
- N_INFO info;
- ISAM_SHARE share;
- N_KEYDEF *keyinfo;
- N_RECINFO *recinfo,*rec,*end;
- uint unpack;
- ulong max_records;
- char name[FN_REFLEN];
-
- error=1; /* Default error */
- info= **org_info;
- share= *(*org_info)->s;
- unpack= (share.base.options & HA_OPTION_COMPRESS_RECORD) &&
- (testflag & T_UNPACK);
- if (!(keyinfo=(N_KEYDEF*) my_alloca(sizeof(N_KEYDEF)*share.base.keys)))
- return 0;
- memcpy((byte*) keyinfo,(byte*) share.keyinfo,
- (size_t) (sizeof(N_KEYDEF)*share.base.keys));
- if (!(recinfo=(N_RECINFO*)
- my_alloca(sizeof(N_RECINFO)*(share.base.fields+1))))
- {
- my_afree((gptr) keyinfo);
- return 1;
- }
- memcpy((byte*) recinfo,(byte*) share.rec,
- (size_t) (sizeof(N_RECINFO)*(share.base.fields+1)));
- for (rec=recinfo,end=recinfo+share.base.fields; rec != end ; rec++)
- {
- if (rec->base.type == (int) FIELD_BLOB)
- rec->base.length+=sizeof(char*);
- else if (unpack && !(share.base.options & HA_OPTION_PACK_RECORD))
- rec->base.type=(int) FIELD_NORMAL;
- }
-
- if (share.base.options & HA_OPTION_COMPRESS_RECORD)
- share.base.records=max_records=share.state.records;
- else if (share.base.min_pack_length)
- max_records=(ulong) (my_seek(info.dfile,0L,MY_SEEK_END,MYF(0)) /
- (ulong) share.base.min_pack_length);
- else
- max_records=0;
- unpack= (share.base.options & HA_OPTION_COMPRESS_RECORD) &&
- (testflag & T_UNPACK);
- share.base.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
- VOID(nisam_close(*org_info));
- if (nisam_create(fn_format(name,filename,"",N_NAME_IEXT,
- 4+ (opt_follow_links ? 16 : 0)),
- share.base.keys,keyinfo,recinfo,
- max(max_records,share.base.records),share.base.reloc,
- HA_DONT_TOUCH_DATA,
- share.base.options |
- (unpack ? HA_OPTION_TEMP_COMPRESS_RECORD
- : 0),
- (ulong) my_seek(info.dfile,0L,MY_SEEK_END,MYF(0))))
- {
- print_error("Got error %d when trying to recreate indexfile",my_errno);
- goto end;
- }
- *org_info=nisam_open(name,O_RDWR,
- (testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED :
- (testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED :
- HA_OPEN_ABORT_IF_LOCKED);
- if (!*org_info)
- {
- print_error("Got error %d when trying to open re-created indexfile",
- my_errno);
- goto end;
- }
- /* We are modifing */
- (*org_info)->s->base.options&= ~HA_OPTION_READ_ONLY_DATA;
- VOID(_nisam_readinfo(*org_info,F_WRLCK,0));
- (*org_info)->s->state.records=share.state.records;
- if (share.base.create_time)
- (*org_info)->s->base.create_time=share.base.create_time;
- (*org_info)->s->state.uniq=(*org_info)->this_uniq=
- share.state.uniq;
- (*org_info)->s->state.del=share.state.del;
- (*org_info)->s->state.dellink=share.state.dellink;
- (*org_info)->s->state.empty=share.state.empty;
- (*org_info)->s->state.data_file_length=share.state.data_file_length;
- if (update_state_info(*org_info,UPDATE_TIME | UPDATE_STAT))
- goto end;
- error=0;
-end:
- my_afree((gptr) keyinfo);
- my_afree((gptr) recinfo);
- return error;
-}
-
- /* Store long in 1,2,3 or 4 bytes */
-
-static void save_integer( byte *pos, uint pack_length, ulong value)
-{
- switch (pack_length) {
- case 4: int4store(pos,value); break;
- case 3: int3store(pos,value); break;
- case 2: int2store(pos,(uint) value); break;
- case 1: pos[0]= (char) (uchar) value; break;
- default: break;
- }
- return;
-}
-
- /* write suffix to data file if neaded */
-
-static int write_data_suffix( N_INFO *info)
-{
- if (info->s->base.options & HA_OPTION_COMPRESS_RECORD &&
- sort_info.fix_datafile)
- {
- char buff[MEMMAP_EXTRA_MARGIN];
- bzero(buff,sizeof(buff));
- if (my_b_write(&info->rec_cache,buff,sizeof(buff)))
- {
- print_error("%d when writing to datafile",my_errno);
- return 1;
- }
- read_cache.end_of_file+=sizeof(buff);
- }
- return 0;
-}
-
-
- /* Update state and isamchk_time of indexfile */
-
-static int update_state_info( N_INFO *info, uint update)
-{
- ISAM_SHARE *share=info->s;
- uint base_pos=uint2korr(info->s->state.header.base_pos);
-
- if (update & (UPDATE_STAT | UPDATE_SORT | UPDATE_TIME))
- {
- if (offsetof(N_BASE_INFO,rec_per_key) >
- uint2korr(share->state.header.base_info_length))
- {
- VOID(fputs("Internal error: Trying to change base of old table\n",
- stderr));
- }
- else
- {
- if (update & UPDATE_TIME)
- {
- share->base.isamchk_time= (long) time((time_t*) 0);
- if (!share->base.create_time)
- share->base.create_time=share->base.isamchk_time;
- if (my_pwrite(share->kfile,(gptr) &share->base.create_time,
- sizeof(long)*2,
- base_pos+offsetof(N_BASE_INFO,create_time),
- MYF(MY_NABP)))
- goto err;
- }
- if (update & (UPDATE_STAT | UPDATE_SORT))
- {
- if (my_pwrite(share->kfile,(gptr) share->base.rec_per_key,
- sizeof(long)*share->state.keys+sizeof(uint),
- base_pos+offsetof(N_BASE_INFO,rec_per_key),
- MYF(MY_NABP)))
- goto err;
- }
- }
- }
- { /* Force update of status */
- int error;
- uint r_locks=share->r_locks,w_locks=share->w_locks;
- share->r_locks=share->w_locks=0;
- error=_nisam_writeinfo(info,2);
- share->r_locks=r_locks; share->w_locks=w_locks;
- if (!error)
- return 0;
- }
-err:
- print_error("%d when updating keyfile",my_errno);
- return 1;
-}
diff --git a/isam/isamdef.h b/isam/isamdef.h
deleted file mode 100644
index 7d89730fe32..00000000000
--- a/isam/isamdef.h
+++ /dev/null
@@ -1,418 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Denna fil includeras i alla isam-filer */
-
-#define ISAM_LIBRARY
-#include <nisam.h> /* Structs & some defines */
-#ifdef THREAD
-#include <my_pthread.h>
-#include <thr_lock.h>
-#else
-#include <my_no_pthread.h>
-#endif
-#include <keycache.h>
-
-#ifdef my_write
-#undef my_write /* We want test if disk full */
-#endif
-#undef HA_SORT_ALLOWS_SAME
-#define HA_SORT_ALLOWS_SAME 128 /* Can't be > 128 in NISAM */
-
-#ifdef __WATCOMC__
-#pragma pack(2)
-#define uint uint16 /* Same format as in MSDOS */
-#endif
-#ifdef __ZTC__
-#pragma ZTC align 2
-#define uint uint16 /* Same format as in MSDOS */
-#endif
-#if defined(__WIN__) && defined(_MSC_VER)
-#pragma pack(push,isamdef,2)
-#define uint uint16
-#endif
-
-typedef struct st_state_info
-{
- struct { /* Fileheader */
- uchar file_version[4];
- uchar options[2];
- uchar header_length[2];
- uchar state_info_length[2];
- uchar base_info_length[2];
- uchar base_pos[2];
- uchar not_used[2];
- } header;
-
- ulong records; /* Antal record i databasen */
- ulong del; /* Antalet borttagna poster */
- ulong dellink; /* L{nk till n{sta borttagna */
- ulong key_file_length;
- ulong data_file_length;
- ulong splitt; /* Antal splittrade delar */
- ulong empty; /* Outnyttjat utrymme */
- ulong process; /* Vem som senast uppdatera */
- ulong loop; /* not used anymore */
- ulong uniq; /* Unik nr i denna process */
- ulong key_root[N_MAXKEY]; /* Pekare till rootblocken */
- ulong key_del[N_MAXKEY]; /* Del-l{nkar f|r n-block */
- ulong sec_index_changed; /* Updated when new sec_index */
- ulong sec_index_used; /* 1 bit for each sec index in use */
- ulong version; /* timestamp of create */
- uint keys; /* Keys in use for database */
-} N_STATE_INFO;
-
-
-typedef struct st_base_info
-{
- ulong keystart; /* Var nycklarna b|rjar */
- ulong records,reloc; /* Parameter vid skapandet */
- ulong max_pack_length; /* Max possibly length of packed rec.*/
- ulong max_data_file_length;
- ulong max_key_file_length;
- uint reclength; /* length of unpacked record */
- uint options; /* Options used */
- uint pack_reclength; /* Length of full packed rec. */
- uint min_pack_length;
- uint min_block_length;
- uint rec_reflength; /* = 2 or 3 or 4 */
- uint key_reflength; /* = 2 or 3 or 4 */
- uint keys; /* Keys defined for database */
- uint blobs; /* Number of blobs */
- uint max_block; /* Max blockl{ngd anv{nd */
- uint max_key_length; /* L{ngsta nyckel-l{ngden */
- uint fields, /* Antal f{lt i databasen */
- pack_fields, /* Packade f{lt i databasen */
- pack_bits; /* Length of packed bits */
- time_t create_time; /* Time when created database */
- time_t isamchk_time; /* Time for last recover */
- ulong rec_per_key[N_MAXKEY]; /* for sql optimizing */
- uint sortkey; /* sorted by this key */
-} N_BASE_INFO;
-
-
-#ifdef __ZTC__
-#pragma ZTC align
-#undef uint
-#endif
-#ifdef __WATCOMC__
-#pragma pack()
-#undef uint
-#endif
-#if defined(__WIN__) && defined(_MSC_VER)
-#pragma pack(pop,isamdef)
-#undef uint
-#endif
-
- /* Structs used intern in database */
-
-typedef struct st_n_blob /* Info of record */
-{
- uint offset; /* Offset to blob in record */
- uint pack_length; /* Type of packed length */
- uint length; /* Calc:ed for each record */
-} N_BLOB;
-
-
-typedef struct st_isam_pack {
- ulong header_length;
- uint ref_length;
-} N_PACK;
-
-
-typedef struct st_isam_share { /* Shared between opens */
- N_STATE_INFO state;
- N_BASE_INFO base;
- N_KEYDEF *keyinfo; /* Nyckelinfo */
- N_RECINFO *rec; /* Pointer till recdata */
- N_PACK pack; /* Data about packed records */
- N_BLOB *blobs; /* Pointer to blobs */
- char *filename; /* Name of indexfile */
- byte *file_map; /* mem-map of file if possible */
- ulong this_process; /* processid */
- ulong last_process; /* For table-change-check */
- ulong last_version; /* Version on start */
- uint rec_reflength; /* rec_reflength in use now */
- int kfile; /* Shared keyfile */
- int mode; /* mode of file on open */
- int reopen; /* How many times reopened */
- uint state_length;
- uint w_locks,r_locks; /* Number of read/write locks */
- uint min_pack_length; /* Theese is used by packed data */
- uint max_pack_length;
- uint blocksize; /* blocksize of keyfile */
- my_bool changed,not_flushed; /* If changed since lock */
- int rnd; /* rnd-counter */
- DECODE_TREE *decode_trees;
- uint16 *decode_tables;
- enum data_file_type data_file_type;
- int (*read_record)(struct st_isam_info*, ulong, byte*);
- int (*write_record)(struct st_isam_info*, const byte*);
- int (*update_record)(struct st_isam_info*, ulong, const byte*);
- int (*delete_record)(struct st_isam_info*);
- int (*read_rnd)(struct st_isam_info*, byte*, ulong, int);
- int (*compare_record)(struct st_isam_info*, const byte *);
-#ifdef THREAD
- THR_LOCK lock;
- pthread_mutex_t intern_lock; /* Locking for use with _locking */
-#endif
-} ISAM_SHARE;
-
-
-typedef uint bit_type;
-
-typedef struct st_bit_buff { /* Used for packing of record */
- bit_type current_byte;
- uint bits;
- uchar *pos,*end;
- uint error;
-} BIT_BUFF;
-
-
-typedef struct st_isam_info {
- ISAM_SHARE *s; /* Shared between open:s */
- N_BLOB *blobs; /* Pointer to blobs */
- int dfile; /* The datafile */
- BIT_BUFF bit_buff;
- uint options;
- uint opt_flag; /* Optim. for space/speed */
- uint update; /* If file changed since open */
- char *filename; /* parameter to open filename */
- ulong this_uniq; /* uniq filenumber or thread */
- ulong last_uniq; /* last uniq number */
- ulong this_loop; /* counter for this open */
- ulong last_loop; /* last used counter */
- ulong lastpos, /* Last record position */
- nextpos; /* Position to next record */
- ulong int_pos; /* Intern variabel */
- ulong dupp_key_pos; /* Position to record with dupp key */
- ulong last_search_keypage;
- ulong save_lastpos;
- uint packed_length; /* Length of found, packed record */
- uint alloced_rec_buff_length; /* Max recordlength malloced */
- uchar *buff, /* Temp area for key */
- *lastkey; /* Last used search key */
- byte *rec_buff, /* Tempbuff for recordpack */
- *rec_alloc; /* Malloced area for record */
- uchar *int_keypos, /* Intern variabel */
- *int_maxpos; /* Intern variabel */
- int lastinx; /* Last used index */
- int errkey; /* Got last error on this key */
- uint data_changed; /* Somebody has changed data */
- int lock_type; /* How database was locked */
- int tmp_lock_type; /* When locked by readinfo */
- int was_locked; /* Was locked in panic */
- myf lock_wait; /* is 0 or MY_DONT_WAIT */
- my_bool page_changed;
- my_bool buff_used;
- uint save_update; /* When using KEY_READ */
- int save_lastinx;
- int (*read_record)(struct st_isam_info*, ulong, byte*);
- LIST open_list;
- IO_CACHE rec_cache; /* When cacheing records */
-#ifdef THREAD
- THR_LOCK_DATA lock;
-#endif
-} N_INFO;
-
-
- /* Some defines used by isam-funktions */
-
-#define USE_HOLE_KEY 0 /* Use hole key in _nisam_search() */
-#define F_EXTRA_LCK -1
-
- /* bits in opt_flag */
-#define MEMMAP_USED 32
-#define REMEMBER_OLD_POS 64
-
-#define getint(x) ((uint) (uint16) *((int16*) (x)) & 32767)
-#define putint(x,y,nod) (*((uint16*) (x))= ((nod ? (uint16) 32768 : 0)+(uint16) (y)))
-#ifdef WORDS_BIGENDIAN
-#define test_if_nod(x) (x[0] & 128 ? info->s->base.key_reflength : 0)
-#else
-#define test_if_nod(x) (x[1] & 128 ? info->s->base.key_reflength : 0)
-#endif
-
-#define N_MIN_BLOCK_LENGTH 8 /* Because of delete-link */
-#define N_EXTEND_BLOCK_LENGTH 20 /* Don't use to small record-blocks */
-#define N_SPLITT_LENGTH ((N_EXTEND_BLOCK_LENGTH+3)*2)
-#define MAX_DYN_BLOCK_HEADER 11 /* Max prefix of record-block */
-#define DYN_DELETE_BLOCK_HEADER 8 /* length of delete-block-header */
-#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
-#define INDEX_BLOCK_MARGIN 16 /* Safety margin for .ISM tables */
-
-#define PACK_TYPE_SELECTED 1 /* Bits in field->pack_type */
-#define PACK_TYPE_SPACE_FIELDS 2
-#define PACK_TYPE_ZERO_FILL 4
-
-#ifdef THREAD
-extern pthread_mutex_t THR_LOCK_isam;
-#endif
-
- /* Some extern variables */
-
-extern LIST *nisam_open_list;
-extern uchar NEAR nisam_file_magic[],NEAR nisam_pack_file_magic[];
-extern uint NEAR nisam_read_vec[],nisam_quick_table_bits;
-extern File nisam_log_file;
-
- /* This is used by _nisam_get_pack_key_length och _nisam_store_key */
-
-typedef struct st_s_param
-{
- uint ref_length,key_length,
- n_ref_length,
- n_length,
- totlength,
- part_of_prev_key,prev_length;
- uchar *key, *prev_key;
-} S_PARAM;
-
- /* Prototypes for intern functions */
-
-extern int _nisam_read_dynamic_record(N_INFO *info,ulong filepos,byte *buf);
-extern int _nisam_write_dynamic_record(N_INFO*, const byte*);
-extern int _nisam_update_dynamic_record(N_INFO*, ulong, const byte*);
-extern int _nisam_delete_dynamic_record(N_INFO *info);
-extern int _nisam_cmp_dynamic_record(N_INFO *info,const byte *record);
-extern int _nisam_read_rnd_dynamic_record(N_INFO *, byte *,ulong, int);
-extern int _nisam_write_blob_record(N_INFO*, const byte*);
-extern int _nisam_update_blob_record(N_INFO*, ulong, const byte*);
-extern int _nisam_read_static_record(N_INFO *info,ulong filepos,byte *buf);
-extern int _nisam_write_static_record(N_INFO*, const byte*);
-extern int _nisam_update_static_record(N_INFO*, ulong, const byte*);
-extern int _nisam_delete_static_record(N_INFO *info);
-extern int _nisam_cmp_static_record(N_INFO *info,const byte *record);
-extern int _nisam_read_rnd_static_record(N_INFO*, byte *,ulong, int);
-extern int _nisam_ck_write(N_INFO *info,uint keynr,uchar *key);
-extern int _nisam_enlarge_root(N_INFO *info,uint keynr,uchar *key);
-extern int _nisam_insert(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
- uchar *anc_buff,uchar *key_pos,uchar *key_buff,
- uchar *father_buff, uchar *father_keypos,
- ulong father_page);
-extern int _nisam_splitt_page(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
- uchar *buff,uchar *key_buff);
-extern uchar *_nisam_find_half_pos(N_INFO *info,N_KEYDEF *keyinfo,uchar *page,
- uchar *key);
-extern uint _nisam_get_pack_key_length(N_KEYDEF *keyinfo,uint nod_flag,
- uchar *key_pos,uchar *key_buff,
- uchar *key, S_PARAM *s_temp);
-extern void _nisam_store_key(N_KEYDEF *keyinfo,uchar *key_pos,
- S_PARAM *s_temp);
-extern int _nisam_ck_delete(N_INFO *info,uint keynr,uchar *key);
-extern int _nisam_readinfo(N_INFO *info,int lock_flag,int check_keybuffer);
-extern int _nisam_writeinfo(N_INFO *info, uint flag);
-extern int _nisam_test_if_changed(N_INFO *info);
-extern int _nisam_check_index(N_INFO *info,int inx);
-extern int _nisam_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,uint key_len,uint nextflag,ulong pos);
-extern int _nisam_bin_search(struct st_isam_info *info,N_KEYDEF *keyinfo,uchar *page,uchar *key,uint key_len,uint comp_flag,uchar * *ret_pos,uchar *buff);
-extern int _nisam_seq_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *page,uchar *key,uint key_len,uint comp_flag,uchar * *ret_pos,uchar *buff);
-extern ulong _nisam_kpos(uint nod_flag,uchar *after_key);
-extern void _nisam_kpointer(N_INFO *info,uchar *buff,ulong pos);
-extern ulong _nisam_dpos(N_INFO *info, uint nod_flag,uchar *after_key);
-extern void _nisam_dpointer(N_INFO *info, uchar *buff,ulong pos);
-extern int _nisam_key_cmp(N_KEYSEG *keyseg,uchar *a,uchar *b,
- uint key_length,uint nextflag);
-extern uint _nisam_get_key(N_KEYDEF *keyinfo,uint nod_flag,uchar * *page,uchar *key);
-extern uint _nisam_get_static_key(N_KEYDEF *keyinfo,uint nod_flag,uchar * *page,uchar *key);
-extern uchar *_nisam_get_last_key(N_INFO *info,N_KEYDEF *keyinfo,uchar *keypos,uchar *lastkey,uchar *endpos);
-extern uint _nisam_keylength(N_KEYDEF *keyinfo,uchar *key);
-extern uchar *_nisam_move_key(N_KEYDEF *keyinfo,uchar *to,uchar *from);
-extern int _nisam_search_next(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,uint nextflag,ulong pos);
-extern int _nisam_search_first(N_INFO *info,N_KEYDEF *keyinfo,ulong pos);
-extern int _nisam_search_last(N_INFO *info,N_KEYDEF *keyinfo,ulong pos);
-extern uchar *_nisam_fetch_keypage(N_INFO *info,N_KEYDEF *keyinfo,my_off_t page,
- uchar *buff,int return_buffer);
-extern int _nisam_write_keypage(N_INFO *info,N_KEYDEF *keyinfo,my_off_t page,
- uchar *buff);
-extern int _nisam_dispose(N_INFO *info,N_KEYDEF *keyinfo,my_off_t pos);
-extern ulong _nisam_new(N_INFO *info,N_KEYDEF *keyinfo);
-extern uint _nisam_make_key(N_INFO *info,uint keynr,uchar *key,
- const char *record,ulong filepos);
-extern uint _nisam_pack_key(N_INFO *info,uint keynr,uchar *key,uchar *old,uint key_length);
-extern int _nisam_read_key_record(N_INFO *info,ulong filepos,byte *buf);
-extern int _nisam_read_cache(IO_CACHE *info,byte *buff,ulong pos,
- uint length,int re_read_if_possibly);
-extern byte *fix_rec_buff_for_blob(N_INFO *info,uint blob_length);
-extern uint _nisam_rec_unpack(N_INFO *info,byte *to,byte *from,
- uint reclength);
-my_bool _nisam_rec_check(N_INFO *info,const char *from);
-extern int _nisam_write_part_record(N_INFO *info,ulong filepos,uint length,
- ulong next_filepos,byte **record,
- uint *reclength,int *flag);
-extern void _nisam_print_key(FILE *stream,N_KEYSEG *keyseg,const uchar *key);
-extern my_bool _nisam_read_pack_info(N_INFO *info,pbool fix_keys);
-extern int _nisam_read_pack_record(N_INFO *info,ulong filepos,byte *buf);
-extern int _nisam_read_rnd_pack_record(N_INFO*, byte *,ulong, int);
-extern int _nisam_pack_rec_unpack(N_INFO *info,byte *to,byte *from,
- uint reclength);
-extern ulong _nisam_checksum(const byte *mem, uint count);
-
-typedef struct st_sortinfo {
- uint key_length;
- ulong max_records;
- int (*key_cmp)(const void *, const void *, const void *);
- int (*key_read)(void *buff);
- int (*key_write)(const void *buff);
- void (*lock_in_memory)(void);
-} SORT_PARAM;
-
-int _create_index_by_sort(SORT_PARAM *info,pbool no_messages,
- uint sortbuff_size);
-
-#define BLOCK_INFO_HEADER_LENGTH 11
-
-typedef struct st_block_info { /* Parameter to _nisam_get_block_info */
- uchar header[BLOCK_INFO_HEADER_LENGTH];
- uint rec_len;
- uint data_len;
- uint block_len;
- ulong filepos; /* Must be ulong on Alpha! */
- ulong next_filepos;
- uint second_read;
-} BLOCK_INFO;
-
- /* bits in return from _nisam_get_block_info */
-
-#define BLOCK_FIRST 1
-#define BLOCK_LAST 2
-#define BLOCK_DELETED 4
-#define BLOCK_ERROR 8 /* Wrong data */
-#define BLOCK_SYNC_ERROR 16 /* Right data at wrong place */
-#define BLOCK_FATAL_ERROR 32 /* hardware-error */
-
-enum nisam_log_commands {
- LOG_OPEN,LOG_WRITE,LOG_UPDATE,LOG_DELETE,LOG_CLOSE,LOG_EXTRA,LOG_LOCK
-};
-
-#define nisam_log_simple(a,b,c,d) if (nisam_log_file >= 0) _nisam_log(a,b,c,d)
-#define nisam_log_command(a,b,c,d,e) if (nisam_log_file >= 0) _nisam_log_command(a,b,c,d,e)
-#define nisam_log_record(a,b,c,d,e) if (nisam_log_file >= 0) _nisam_log_record(a,b,c,d,e)
-
-extern uint _nisam_get_block_info(BLOCK_INFO *,File, ulong);
-extern uint _nisam_rec_pack(N_INFO *info,byte *to,const byte *from);
-extern uint _nisam_pack_get_block_info(BLOCK_INFO *, uint, File, ulong);
-extern uint _calc_total_blob_length(N_INFO *info,const byte *record);
-extern void _nisam_log(enum nisam_log_commands command,N_INFO *info,
- const byte *buffert,uint length);
-extern void _nisam_log_command(enum nisam_log_commands command,
- N_INFO *info, const byte *buffert,
- uint length, int result);
-extern void _nisam_log_record(enum nisam_log_commands command,N_INFO *info,
- const byte *record,ulong filepos,
- int result);
-extern my_bool _nisam_memmap_file(N_INFO *info);
-extern void _nisam_unmap_file(N_INFO *info);
diff --git a/isam/isamlog.c b/isam/isamlog.c
deleted file mode 100644
index 5cc204b26aa..00000000000
--- a/isam/isamlog.c
+++ /dev/null
@@ -1,853 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* write whats in isam.log */
-
-#ifndef USE_MY_FUNC
-#define USE_MY_FUNC
-#endif
-
-#include "isamdef.h"
-#include <my_tree.h>
-#include <stdarg.h>
-#ifdef HAVE_GETRUSAGE
-#include <sys/resource.h>
-#endif
-
-#define FILENAME(A) (A ? A->show_name : "Unknown")
-
-struct isamlog_file_info {
- long process;
- int filenr,id;
- my_string name,show_name,record;
- N_INFO *isam;
- bool closed,used;
- ulong accessed;
-};
-
-struct test_if_open_param {
- my_string name;
- int max_id;
-};
-
-struct st_access_param
-{
- ulong min_accessed;
- struct isamlog_file_info *found;
-};
-
-#define NO_FILEPOS (ulong) ~0L
-
-extern int main(int argc,char * *argv);
-static void get_options(int *argc,char ***argv);
-static int examine_log(my_string file_name,char **table_names);
-static int read_string(IO_CACHE *file,gptr *to,uint length);
-static int file_info_compare(void *a,void *b);
-static int test_if_open(struct isamlog_file_info *key,element_count count,
- struct test_if_open_param *param);
-static void fix_blob_pointers(N_INFO *isam,byte *record);
-static uint set_maximum_open_files(uint);
-static int test_when_accessed(struct isamlog_file_info *key,element_count count,
- struct st_access_param *access_param);
-static void file_info_free(struct isamlog_file_info *info);
-static int close_some_file(TREE *tree);
-static int reopen_closed_file(TREE *tree,struct isamlog_file_info *file_info);
-static int find_record_with_key(struct isamlog_file_info *file_info,
- byte *record);
-static void printf_log(const char *str,...);
-static bool cmp_filename(struct isamlog_file_info *file_info,my_string name);
-
-static uint verbose=0,update=0,test_info=0,max_files=0,re_open_count=0,
- recover=0,prefix_remove=0,opt_processes=0;
-static my_string log_filename=0,filepath=0,write_filename=0,record_pos_file=0;
-static ulong com_count[10][3],number_of_commands=(ulong) ~0L,start_offset=0,
- record_pos= NO_FILEPOS,isamlog_filepos,isamlog_process;
-static const char *command_name[]=
-{"open","write","update","delete","close","extra","lock","re-open",NullS};
-
-
-int main(int argc, char **argv)
-{
- int error,i,first;
- ulong total_count,total_error,total_recover;
- MY_INIT(argv[0]);
-
- log_filename=nisam_log_filename;
- get_options(&argc,&argv);
- /* Nr of isam-files */
- max_files=(set_maximum_open_files(min(max_files,8))-6)/2;
-
- if (update)
- printf("Trying to %s ISAM files according to log '%s'\n",
- (recover ? "recover" : "update"),log_filename);
- error= examine_log(log_filename,argv);
- if (update && ! error)
- puts("Tables updated successfully");
- total_count=total_error=total_recover=0;
- for (i=first=0 ; command_name[i] ; i++)
- {
- if (com_count[i][0])
- {
- if (!first++)
- {
- if (verbose || update)
- puts("");
- puts("Commands Used count Errors Recover errors");
- }
- printf("%-12s%9ld%10ld%17ld\n",command_name[i],com_count[i][0],
- com_count[i][1],com_count[i][2]);
- total_count+=com_count[i][0];
- total_error+=com_count[i][1];
- total_recover+=com_count[i][2];
- }
- }
- if (total_count)
- printf("%-12s%9ld%10ld%17ld\n","Total",total_count,total_error,
- total_recover);
- if (re_open_count)
- printf("Had to do %d re-open because of too few possibly open files\n",
- re_open_count);
- VOID(nisam_panic(HA_PANIC_CLOSE));
- my_end(test_info ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
- exit(error);
- return 0; /* No compiler warning */
-} /* main */
-
-
-static void get_options(register int *argc, register char ***argv)
-{
- int help,version;
- const char *pos,*usage;
- char option;
-
- help=0;
- usage="Usage: %s [-?iruvIPV] [-c #] [-f #] [-F filepath/] [-o #] [-R file recordpos] [-w write_file] [log-filename [table ...]] \n";
- pos= "";
-
- while (--*argc > 0 && *(pos = *(++*argv)) == '-' ) {
- while (*++pos)
- {
- version=0;
- switch((option=*pos)) {
- case '#':
- DBUG_PUSH (++pos);
- pos=" "; /* Skip rest of arg */
- break;
- case 'c':
- if (! *++pos)
- {
- if (!--*argc)
- goto err;
- else
- pos= *(++*argv);
- }
- number_of_commands=(ulong) atol(pos);
- pos=" ";
- break;
- case 'u':
- update=1;
- break;
- case 'f':
- if (! *++pos)
- {
- if (!--*argc)
- goto err;
- else
- pos= *(++*argv);
- }
- max_files=(uint) atoi(pos);
- pos=" ";
- break;
- case 'i':
- test_info=1;
- break;
- case 'o':
- if (! *++pos)
- {
- if (!--*argc)
- goto err;
- else
- pos= *(++*argv);
- }
- start_offset=(ulong) atol(pos);
- pos=" ";
- break;
- case 'p':
- if (! *++pos)
- {
- if (!--*argc)
- goto err;
- else
- pos= *(++*argv);
- }
- prefix_remove=atoi(pos);
- break;
- case 'r':
- update=1;
- recover++;
- break;
- case 'P':
- opt_processes=1;
- break;
- case 'R':
- if (! *++pos)
- {
- if (!--*argc)
- goto err;
- else
- pos= *(++*argv);
- }
- record_pos_file=(char*) pos;
- if (!--*argc)
- goto err;
- record_pos=(ulong) atol(*(++*argv));
- pos= " ";
- break;
- case 'v':
- verbose++;
- break;
- case 'w':
- if (! *++pos)
- {
- if (!--*argc)
- goto err;
- else
- pos= *(++*argv);
- }
- write_filename=(char*) pos;
- pos=" ";
- break;
- case 'F':
- if (! *++pos)
- {
- if (!--*argc)
- goto err;
- else
- pos= *(++*argv);
- }
- filepath= (char*) pos;
- pos=" ";
- break;
- case 'V':
- version=1;
- /* Fall through */
- case 'I':
- case '?':
- printf("%s Ver 3.3 for %s at %s\n",my_progname,SYSTEM_TYPE,
- MACHINE_TYPE);
- puts("By Monty, for your professional use\n");
- if (version)
- break;
- puts("Write info about whats in a ISAM log file.");
- printf("If no file name is given %s is used\n",log_filename);
- puts("");
- printf(usage,my_progname);
- puts("");
- puts("Options: -? or -I \"Info\" -V \"version\" -c \"do only # commands\"");
- puts(" -f \"max open files\" -F \"filepath\" -i \"extra info\"");
- puts(" -o \"offset\" -p # \"remove # components from path\"");
- puts(" -r \"recover\" -R \"file recordposition\"");
- puts(" -u \"update\" -v \"verbose\" -w \"write file\"");
- puts(" -P \"processes\"");
- puts("\nOne can give a second and a third '-v' for more verbose.");
- puts("Normaly one does a update (-u).");
- puts("If a recover is done all writes and all possibly updates and deletes is done\nand errors are only counted.");
- puts("If one gives table names as arguments only these tables will be updated\n");
- help=1;
- break;
- default:
- printf("illegal option: \"-%c\"\n",*pos);
- break;
- }
- }
- }
- if (! *argc)
- {
- if (help)
- exit(0);
- (*argv)++;
- }
- if (*argc >= 1)
- {
- log_filename=(char*) pos;
- (*argc)--;
- (*argv)++;
- }
- return;
- err:
- VOID(fprintf(stderr,"option \"%c\" used without or with wrong argument\n",
- option));
- exit(1);
-}
-
-
-static int examine_log(my_string file_name, char **table_names)
-{
- uint command,result,files_open;
- ulong access_time,length;
- uint32 filepos;
- int lock_command,ni_result;
- char isam_file_name[FN_REFLEN];
- uchar head[20];
- gptr buff;
- struct test_if_open_param open_param;
- IO_CACHE cache;
- File file;
- FILE *write_file;
- enum ha_extra_function extra_command;
- TREE tree;
- struct isamlog_file_info file_info,*curr_file_info;
- char llbuff[22],llbuff2[22];
- DBUG_ENTER("examine_log");
-
- if ((file=my_open(file_name,O_RDONLY,MYF(MY_WME))) < 0)
- DBUG_RETURN(1);
- write_file=0;
- if (write_filename)
- {
- if (!(write_file=my_fopen(write_filename,O_WRONLY,MYF(MY_WME))))
- {
- my_close(file,MYF(0));
- DBUG_RETURN(1);
- }
- }
-
- init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0));
- bzero((gptr) com_count,sizeof(com_count));
- init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1,
- (tree_element_free) file_info_free, NULL);
- VOID(init_key_cache(dflt_key_cache,KEY_CACHE_BLOCK_SIZE,KEY_CACHE_SIZE,
- 0,0));
- files_open=0; access_time=0;
- while (access_time++ != number_of_commands &&
- !my_b_read(&cache,(byte*) head,9))
- {
- isamlog_filepos=my_b_tell(&cache)-9L;
- file_info.filenr=uint2korr(head+1);
- isamlog_process=file_info.process=(long) uint4korr(head+3);
- if (!opt_processes)
- file_info.process=0;
- result=uint2korr(head+7);
- if ((curr_file_info=(struct isamlog_file_info*)
- tree_search(&tree, &file_info, tree.custom_arg)))
- {
- curr_file_info->accessed=access_time;
- if (update && curr_file_info->used && curr_file_info->closed)
- {
- if (reopen_closed_file(&tree,curr_file_info))
- {
- command=sizeof(com_count)/sizeof(com_count[0][0])/3;
- result=0;
- goto com_err;
- }
- }
- }
- command=(uint) head[0];
- if (command < sizeof(com_count)/sizeof(com_count[0][0])/3 &&
- (!table_names[0] || (curr_file_info && curr_file_info->used)))
- {
- com_count[command][0]++;
- if (result)
- com_count[command][1]++;
- }
- switch ((enum nisam_log_commands) command) {
- case LOG_OPEN:
- if (!table_names[0])
- {
- com_count[command][0]--; /* Must be counted explicite */
- if (result)
- com_count[command][1]--;
- }
-
- if (curr_file_info)
- printf("\nWarning: %s is opened with same process and filenumber\nMaybe you should use the -P option ?\n",
- curr_file_info->show_name);
- if (my_b_read(&cache,(byte*) head,2))
- goto err;
- file_info.name=0;
- file_info.show_name=0;
- file_info.record=0;
- if (read_string(&cache,(gptr*) &file_info.name,(uint) uint2korr(head)))
- goto err;
- {
- uint i;
- char *pos,*to;
-
- /* Fix if old DOS files to new format */
- for (pos=file_info.name; (pos=strchr(pos,'\\')) ; pos++)
- *pos= '/';
-
- pos=file_info.name;
- for (i=0 ; i < prefix_remove ; i++)
- {
- char *next;
- if (!(next=strchr(pos,'/')))
- break;
- pos=next+1;
- }
- to=isam_file_name;
- if (filepath)
- to=convert_dirname(isam_file_name, filepath, NullS);
- strmov(to,pos);
- fn_ext(isam_file_name)[0]=0; /* Remove extension */
- }
- open_param.name=file_info.name;
- open_param.max_id=0;
- VOID(tree_walk(&tree,(tree_walk_action) test_if_open,(void*) &open_param,
- left_root_right));
- file_info.id=open_param.max_id+1;
- file_info.show_name=my_memdup(isam_file_name,
- (uint) strlen(isam_file_name)+6,
- MYF(MY_WME));
- if (file_info.id > 1)
- sprintf(strend(file_info.show_name),"<%d>",file_info.id);
- file_info.closed=1;
- file_info.accessed=access_time;
- file_info.used=1;
- if (table_names[0])
- {
- char **name;
- file_info.used=0;
- for (name=table_names ; *name ; name++)
- {
- if (!strcmp(*name,isam_file_name))
- file_info.used=1; /* Update/log only this */
- }
- }
- if (update && file_info.used)
- {
- if (files_open >= max_files)
- {
- if (close_some_file(&tree))
- goto com_err;
- files_open--;
- }
- if (!(file_info.isam= nisam_open(isam_file_name,O_RDWR,
- HA_OPEN_WAIT_IF_LOCKED)))
- goto com_err;
- if (!(file_info.record=my_malloc(file_info.isam->s->base.reclength,
- MYF(MY_WME))))
- goto end;
- files_open++;
- file_info.closed=0;
- }
- VOID(tree_insert(&tree, (gptr) &file_info, 0, tree.custom_arg));
- if (file_info.used)
- {
- if (verbose && !record_pos_file)
- printf_log("%s: open -> %d",file_info.show_name, file_info.filenr);
- com_count[command][0]++;
- if (result)
- com_count[command][1]++;
- }
- break;
- case LOG_CLOSE:
- if (verbose && !record_pos_file &&
- (!table_names[0] || (curr_file_info && curr_file_info->used)))
- printf_log("%s: %s -> %d",FILENAME(curr_file_info),
- command_name[command],result);
- if (curr_file_info)
- {
- if (!curr_file_info->closed)
- files_open--;
- VOID(tree_delete(&tree, (gptr) curr_file_info, tree.custom_arg));
- }
- break;
- case LOG_EXTRA:
- if (my_b_read(&cache,(byte*) head,sizeof(extra_command)))
- goto err;
- memcpy_fixed(&extra_command,head,sizeof(extra_command));
- if (verbose && !record_pos_file &&
- (!table_names[0] || (curr_file_info && curr_file_info->used)))
- printf_log("%s: %s(%d) -> %d",FILENAME(curr_file_info),
- command_name[command], (int) extra_command,result);
- if (update && curr_file_info && !curr_file_info->closed)
- {
- if (nisam_extra(curr_file_info->isam,extra_command) != (int) result)
- {
- fflush(stdout);
- VOID(fprintf(stderr,
- "Warning: error %d, expected %d on command %s at %s\n",
- my_errno,result,command_name[command],
- llstr(isamlog_filepos,llbuff)));
- fflush(stderr);
- }
- }
- break;
- case LOG_DELETE:
- if (my_b_read(&cache,(byte*) head,sizeof(filepos)))
- goto err;
- memcpy_fixed(&filepos,head,sizeof(filepos));
- if (verbose && (!record_pos_file ||
- ((record_pos == filepos || record_pos == NO_FILEPOS) &&
- !cmp_filename(curr_file_info,record_pos_file))) &&
- (!table_names[0] || (curr_file_info && curr_file_info->used)))
- printf_log("%s: %s at %ld -> %d",FILENAME(curr_file_info),
- command_name[command],(long) filepos,result);
- if (update && curr_file_info && !curr_file_info->closed)
- {
- if (nisam_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
- {
- if (!recover)
- goto com_err;
- com_count[command][2]++; /* Mark error */
- }
- ni_result=nisam_delete(curr_file_info->isam,curr_file_info->record);
- if ((ni_result == 0 && result) ||
- (ni_result && (uint) my_errno != result))
- {
- if (!recover)
- goto com_err;
- if (ni_result)
- com_count[command][2]++; /* Mark error */
- if (verbose)
- printf_log("error: Got result %d from mi_delete instead of %d",
- ni_result, result);
- }
- }
- break;
- case LOG_WRITE:
- case LOG_UPDATE:
- if (my_b_read(&cache,(byte*) head,8))
- goto err;
- filepos=uint4korr(head);
- length=uint4korr(head+4);
- buff=0;
- if (read_string(&cache,&buff,(uint) length))
- goto err;
- if ((!record_pos_file ||
- ((record_pos == filepos || record_pos == NO_FILEPOS) &&
- !cmp_filename(curr_file_info,record_pos_file))) &&
- (!table_names[0] || (curr_file_info && curr_file_info->used)))
- {
- if (write_file &&
- (my_fwrite(write_file,buff,length,MYF(MY_WAIT_IF_FULL | MY_NABP))))
- goto end;
- if (verbose)
- printf_log("%s: %s at %ld, length=%ld -> %d",
- FILENAME(curr_file_info),
- command_name[command], filepos,length,result);
- }
- if (update && curr_file_info && !curr_file_info->closed)
- {
- if (curr_file_info->isam->s->base.blobs)
- fix_blob_pointers(curr_file_info->isam,buff);
- if ((enum nisam_log_commands) command == LOG_UPDATE)
- {
- if (nisam_rrnd(curr_file_info->isam,curr_file_info->record,filepos))
- {
- if (!recover)
- {
- result=0;
- goto com_err;
- }
- if (verbose)
- printf_log("error: Didn't find row to update with mi_rrnd");
- if (recover == 1 || result ||
- find_record_with_key(curr_file_info,buff))
- {
- com_count[command][2]++; /* Mark error */
- break;
- }
- }
- ni_result=nisam_update(curr_file_info->isam,curr_file_info->record,
- buff);
- if ((ni_result == 0 && result) ||
- (ni_result && (uint) my_errno != result))
- {
- if (!recover)
- goto com_err;
- if (verbose)
- printf_log("error: Got result %d from mi_update instead of %d",
- ni_result, result);
- if (ni_result)
- com_count[command][2]++; /* Mark error */
- }
- }
- else
- {
- ni_result=nisam_write(curr_file_info->isam,buff);
- if ((ni_result == 0 && result) ||
- (ni_result && (uint) my_errno != result))
- {
- if (!recover)
- goto com_err;
- if (ni_result)
- com_count[command][2]++; /* Mark error */
- }
- if (! recover && filepos != curr_file_info->isam->lastpos)
- {
- printf("error: Wrote at position: %s, should have been %s",
- llstr(curr_file_info->isam->lastpos,llbuff),
- llstr(filepos,llbuff2));
- goto end;
- }
- }
- }
- my_free(buff,MYF(0));
- break;
- case LOG_LOCK:
- if (my_b_read(&cache,(byte*) head,sizeof(lock_command)))
- goto err;
- memcpy_fixed(&lock_command,head,sizeof(lock_command));
- if (verbose && !record_pos_file &&
- (!table_names[0] || (curr_file_info && curr_file_info->used)))
- printf_log("%s: %s(%d) -> %d\n",FILENAME(curr_file_info),
- command_name[command],lock_command,result);
- if (update && curr_file_info && !curr_file_info->closed)
- {
- if (nisam_lock_database(curr_file_info->isam,lock_command) !=
- (int) result)
- goto com_err;
- }
- break;
- default:
- VOID(fprintf(stderr,
- "Error: found unknown command %d in logfile, aborted\n",
- command));
- fflush(stderr);
- goto end;
- }
- }
- end_key_cache(dflt_key_cache,1);
- delete_tree(&tree);
- VOID(end_io_cache(&cache));
- VOID(my_close(file,MYF(0)));
- if (write_file && my_fclose(write_file,MYF(MY_WME)))
- DBUG_RETURN(1);
- DBUG_RETURN(0);
-
- err:
- fflush(stdout);
- VOID(fprintf(stderr,"Got error %d when reading from logfile\n",my_errno));
- fflush(stderr);
- goto end;
- com_err:
- fflush(stdout);
- VOID(fprintf(stderr,"Got error %d, expected %d on command %s at %s\n",
- my_errno,result,command_name[command],
- llstr(isamlog_filepos,llbuff)));
- fflush(stderr);
- end:
- end_key_cache(dflt_key_cache,1);
- delete_tree(&tree);
- VOID(end_io_cache(&cache));
- VOID(my_close(file,MYF(0)));
- if (write_file)
- VOID(my_fclose(write_file,MYF(MY_WME)));
- DBUG_RETURN(1);
-}
-
-
-static int read_string(IO_CACHE *file, reg1 gptr *to, reg2 uint length)
-{
- DBUG_ENTER("read_string");
-
- if (*to)
- my_free((gptr) *to,MYF(0));
- if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
- my_b_read(file,(byte*) *to,length))
- {
- if (*to)
- my_free(*to,MYF(0));
- *to= 0;
- DBUG_RETURN(1);
- }
- *((char*) *to+length)= '\0';
- DBUG_RETURN (0);
-} /* read_string */
-
-
-static int file_info_compare(void *a, void *b)
-{
- long lint;
-
- if ((lint=((struct isamlog_file_info*) a)->process -
- ((struct isamlog_file_info*) b)->process))
- return lint < 0L ? -1 : 1;
- return (((struct isamlog_file_info*) a)->filenr -
- ((struct isamlog_file_info*) b)->filenr);
-}
-
- /* ARGSUSED */
-
-static int test_if_open (struct isamlog_file_info *key,
- element_count count __attribute__((unused)),
- struct test_if_open_param *param)
-{
- if (!strcmp(key->name,param->name) && key->id > param->max_id)
- param->max_id=key->id;
- return 0;
-}
-
-
-static void fix_blob_pointers( N_INFO *info, byte *record)
-{
- byte *pos;
- N_BLOB *blob,*end;
-
- pos=record+info->s->base.reclength;
- for (end=info->blobs+info->s->base.blobs, blob= info->blobs;
- blob != end ;
- blob++)
- {
- bmove(record+blob->offset+blob->pack_length,&pos,sizeof(char*));
- pos+=_calc_blob_length(blob->pack_length,record+blob->offset);
- }
-}
-
-static uint set_maximum_open_files(uint maximum_files)
-{
-#if defined(HAVE_GETRUSAGE) && defined(RLIMIT_NOFILE)
- struct rlimit rlimit;
- int old_max;
-
- if (maximum_files > MY_NFILE)
- maximum_files=MY_NFILE; /* Don't crash my_open */
-
- if (!getrlimit(RLIMIT_NOFILE,&rlimit))
- {
- old_max=rlimit.rlim_max;
- if (maximum_files && (int) maximum_files > old_max)
- rlimit.rlim_max=maximum_files;
- rlimit.rlim_cur=rlimit.rlim_max;
- if (setrlimit(RLIMIT_NOFILE,&rlimit))
- {
- if (old_max != (int) maximum_files)
- { /* Set as much as we can */
- rlimit.rlim_max=rlimit.rlim_cur=old_max;
- setrlimit(RLIMIT_NOFILE,&rlimit);
- }
- }
- getrlimit(RLIMIT_NOFILE,&rlimit); /* Read if broken setrlimit */
- if (maximum_files && maximum_files < rlimit.rlim_cur)
- VOID(fprintf(stderr,"Warning: Error from setrlimit: Max open files is %d\n",old_max));
- return rlimit.rlim_cur;
- }
-#endif
- return min(maximum_files,MY_NFILE);
-}
-
- /* close the file with hasn't been accessed for the longest time */
- /* ARGSUSED */
-
-static int test_when_accessed (struct isamlog_file_info *key,
- element_count count __attribute__((unused)),
- struct st_access_param *access_param)
-{
- if (key->accessed < access_param->min_accessed && ! key->closed)
- {
- access_param->min_accessed=key->accessed;
- access_param->found=key;
- }
- return 0;
-}
-
-
-static void file_info_free(struct isamlog_file_info *fileinfo)
-{
- DBUG_ENTER("file_info_free");
- if (update)
- {
- if (!fileinfo->closed)
- VOID(nisam_close(fileinfo->isam));
- if (fileinfo->record)
- my_free(fileinfo->record,MYF(0));
- }
- my_free(fileinfo->name,MYF(0));
- my_free(fileinfo->show_name,MYF(0));
- DBUG_VOID_RETURN;
-}
-
-
-
-static int close_some_file(TREE *tree)
-{
- struct st_access_param access_param;
-
- access_param.min_accessed=LONG_MAX;
- access_param.found=0;
-
- VOID(tree_walk(tree,(tree_walk_action) test_when_accessed,
- (void*) &access_param,left_root_right));
- if (!access_param.found)
- return 1; /* No open file that is possibly to close */
- if (nisam_close(access_param.found->isam))
- return 1;
- access_param.found->closed=1;
- return 0;
-}
-
-
-static int reopen_closed_file(TREE *tree, struct isamlog_file_info *fileinfo)
-{
- char name[FN_REFLEN];
- if (close_some_file(tree))
- return 1; /* No file to close */
- strmov(name,fileinfo->show_name);
- if (fileinfo->id > 1)
- *strrchr(name,'<')='\0'; /* Remove "<id>" */
-
- if (!(fileinfo->isam= nisam_open(name,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
- return 1;
- fileinfo->closed=0;
- re_open_count++;
- return 0;
-}
-
- /* Try to find record with uniq key */
-
-static int find_record_with_key(struct isamlog_file_info *file_info,
- byte *record)
-{
- uint key;
- N_INFO *info=file_info->isam;
- uchar tmp_key[N_MAX_KEY_BUFF];
-
- for (key=0 ; key < info->s->state.keys ; key++)
- {
- if (info->s->keyinfo[key].base.flag & HA_NOSAME)
- {
- VOID(_nisam_make_key(info,key,tmp_key,record,0L));
- return nisam_rkey(info,file_info->record,(int) key,(char*) tmp_key,0,
- HA_READ_KEY_EXACT);
- }
- }
- return 1;
-}
-
-
-static void printf_log(const char *format,...)
-{
- char llbuff[21];
- va_list args;
- va_start(args,format);
- if (verbose > 2)
- printf("%9s:",llstr(isamlog_filepos,llbuff));
- if (verbose > 1)
- printf("%5ld ",isamlog_process); /* Write process number */
- (void) vprintf((char*) format,args);
- putchar('\n');
- va_end(args);
-}
-
-
-static bool cmp_filename(struct isamlog_file_info *file_info,my_string name)
-{
- if (!file_info)
- return 1;
- return strcmp(file_info->name,name) ? 1 : 0;
-}
diff --git a/isam/log.c b/isam/log.c
deleted file mode 100644
index 78b56690401..00000000000
--- a/isam/log.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Logging of isamcommands and records on logfile */
-
-#include "isamdef.h"
-#if defined(MSDOS) || defined(__WIN__)
-#include <errno.h>
-#include <fcntl.h>
-#ifndef __WIN__
-#include <process.h>
-#endif
-#endif
-#ifdef VMS
-#include <processes.h>
-#endif
-
-#ifdef THREAD
-#undef GETPID
-#define GETPID() (log_type == 1 ? getpid() : (long) my_thread_id());
-#else
-#define GETPID() getpid()
-#endif
-
- /* Activate logging if flag is 1 and reset logging if flag is 0 */
-
-static int log_type=0;
-
-int nisam_log(int activate_log)
-{
- int error=0;
- char buff[FN_REFLEN];
- DBUG_ENTER("nisam_log");
-
- log_type=activate_log;
- if (activate_log)
- {
- if (nisam_log_file < 0)
- {
- if ((nisam_log_file = my_create(fn_format(buff,nisam_log_filename,
- "",".log",4),
- 0,(O_RDWR | O_BINARY | O_APPEND),MYF(0)))
- < 0)
- DBUG_RETURN(1);
- }
- }
- else if (nisam_log_file >= 0)
- {
- error=my_close(nisam_log_file,MYF(0));
- nisam_log_file= -1;
- }
- DBUG_RETURN(error);
-}
-
-
- /* Logging of records and commands on logfile */
- /* All logs starts with command(1) dfile(2) process(4) result(2) */
-
-void _nisam_log(enum nisam_log_commands command, N_INFO *info, const byte *buffert, uint length)
-{
- char buff[11];
- int error,old_errno;
- ulong pid=(ulong) GETPID();
- old_errno=my_errno;
- bzero(buff,sizeof(buff));
- buff[0]=(char) command;
- int2store(buff+1,info->dfile);
- int4store(buff+3,pid);
- int2store(buff+9,length);
-
- pthread_mutex_lock(&THR_LOCK_isam);
- error=my_lock(nisam_log_file,F_WRLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
- VOID(my_write(nisam_log_file,buff,sizeof(buff),MYF(0)));
- VOID(my_write(nisam_log_file,buffert,length,MYF(0)));
- if (!error)
- error=my_lock(nisam_log_file,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
- pthread_mutex_unlock(&THR_LOCK_isam);
- my_errno=old_errno;
-}
-
-
-void _nisam_log_command(enum nisam_log_commands command, N_INFO *info, const byte *buffert, uint length, int result)
-{
- char buff[9];
- int error,old_errno;
- ulong pid=(ulong) GETPID();
-
- old_errno=my_errno;
- buff[0]=(char) command;
- int2store(buff+1,info->dfile);
- int4store(buff+3,pid);
- int2store(buff+7,result);
- pthread_mutex_lock(&THR_LOCK_isam);
- error=my_lock(nisam_log_file,F_WRLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
- VOID(my_write(nisam_log_file,buff,sizeof(buff),MYF(0)));
- if (buffert)
- VOID(my_write(nisam_log_file,buffert,length,MYF(0)));
- if (!error)
- error=my_lock(nisam_log_file,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
- pthread_mutex_unlock(&THR_LOCK_isam);
- my_errno=old_errno;
-}
-
-
-void _nisam_log_record(enum nisam_log_commands command, N_INFO *info, const byte *record, ulong filepos, int result)
-{
- char buff[17],*pos;
- int error,old_errno;
- uint length;
- ulong pid=(ulong) GETPID();
-
- old_errno=my_errno;
- if (!info->s->base.blobs)
- length=info->s->base.reclength;
- else
- length=info->s->base.reclength+ _calc_total_blob_length(info,record);
- buff[0]=(char) command;
- int2store(buff+1,info->dfile);
- int4store(buff+3,pid);
- int2store(buff+7,result);
- int4store(buff+9,filepos);
- int4store(buff+13,length);
- pthread_mutex_lock(&THR_LOCK_isam);
- error=my_lock(nisam_log_file,F_WRLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
- VOID(my_write(nisam_log_file,buff,sizeof(buff),MYF(0)));
- VOID(my_write(nisam_log_file,(byte*) record,info->s->base.reclength,MYF(0)));
- if (info->s->base.blobs)
- {
- N_BLOB *blob,*end;
-
- for (end=info->blobs+info->s->base.blobs, blob= info->blobs;
- blob != end ;
- blob++)
- {
- bmove(&pos,record+blob->offset+blob->pack_length,sizeof(char*));
- VOID(my_write(nisam_log_file,pos,blob->length,MYF(0)));
- }
- }
- if (!error)
- error=my_lock(nisam_log_file,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE));
- pthread_mutex_unlock(&THR_LOCK_isam);
- my_errno=old_errno;
-}
diff --git a/isam/make-ccc b/isam/make-ccc
deleted file mode 100755
index d9a95dbc14b..00000000000
--- a/isam/make-ccc
+++ /dev/null
@@ -1,3 +0,0 @@
-ccc -DHAVE_CONFIG_H -I. -I. -I.. -I./../include -I../include -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c _cache.c _dbug.c _dynrec.c _key.c _locking.c _packrec.c _page.c _search.c _statrec.c changed.c close.c create.c delete.c extra.c info.c log.c open.c panic.c range.c rfirst.c rkey.c rlast.c rnext.c rprev.c rrnd.c rsame.c rsamepos.c static.c update.c write.c
-rm libnisam.a
-ar -cr libnisam.a _cache.o
diff --git a/isam/open.c b/isam/open.c
deleted file mode 100644
index be62fd86192..00000000000
--- a/isam/open.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* open a isam-database */
-
-#include "isamdef.h"
-#if defined(MSDOS) || defined(__WIN__)
-#ifdef __WIN__
-#include <fcntl.h>
-#else
-#include <process.h> /* Prototype for getpid */
-#endif
-#endif
-#ifdef VMS
-#include "static.c"
-#endif
-
-static void setup_functions(ISAM_SHARE *info);
-static void setup_key_functions(N_KEYDEF *keyinfo);
-
-#define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
- pos+=size;}
-
-/******************************************************************************
-** Return the shared struct if the table is already open.
-** In MySQL the server will handle version issues.
-******************************************************************************/
-
-static N_INFO *test_if_reopen(char *filename)
-{
- LIST *pos;
-
- for (pos=nisam_open_list ; pos ; pos=pos->next)
- {
- N_INFO *info=(N_INFO*) pos->data;
- ISAM_SHARE *share=info->s;
- if (!strcmp(share->filename,filename) && share->last_version)
- return info;
- }
- return 0;
-}
-
-
-/******************************************************************************
- open a isam database.
- By default exit with error if database is locked
- if handle_locking & HA_OPEN_WAIT_IF_LOCKED then wait if database is locked
- if handle_locking & HA_OPEN_IGNORE_IF_LOCKED then continue, but count-vars
- in st_i_info may be wrong. count-vars are automaticly fixed after next
- isam request.
-******************************************************************************/
-
-
-N_INFO *nisam_open(const char *name, int mode, uint handle_locking)
-{
- int lock_error,kfile,open_mode,save_errno;
- uint i,j,len,errpos,head_length,base_pos,offset,info_length,extra;
- char name_buff[FN_REFLEN],*disk_cache,*disk_pos;
- N_INFO info,*m_info,*old_info;
- ISAM_SHARE share_buff,*share;
- DBUG_ENTER("nisam_open");
-
- LINT_INIT(m_info);
- kfile= -1;
- lock_error=1;
- errpos=0;
- head_length=sizeof(share_buff.state.header);
- bzero((byte*) &info,sizeof(info));
-
- VOID(fn_format(name_buff,name,"",N_NAME_IEXT,4+16+32));
- pthread_mutex_lock(&THR_LOCK_isam);
- if (!(old_info=test_if_reopen(name_buff)))
- {
- share= &share_buff;
- bzero((gptr) &share_buff,sizeof(share_buff));
-
- if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
- {
- if ((errno != EROFS && errno != EACCES) ||
- mode != O_RDONLY ||
- (kfile=my_open(name_buff,(open_mode=O_RDONLY) | O_SHARE,MYF(0))) < 0)
- goto err;
- }
- errpos=1;
- if (my_read(kfile,(char*) share->state.header.file_version,head_length,
- MYF(MY_NABP)))
- goto err;
-
- if (memcmp((byte*) share->state.header.file_version,
- (byte*) nisam_file_magic, 3) ||
- share->state.header.file_version[3] == 0 ||
- (uchar) share->state.header.file_version[3] > 3)
- {
- DBUG_PRINT("error",("Wrong header in %s",name_buff));
- DBUG_DUMP("error_dump",(char*) share->state.header.file_version,
- head_length);
- my_errno=HA_ERR_CRASHED;
- goto err;
- }
- if (uint2korr(share->state.header.options) &
- ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
- HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
- HA_OPTION_TEMP_COMPRESS_RECORD))
- {
- DBUG_PRINT("error",("wrong options: 0x%lx",
- uint2korr(share->state.header.options)));
- my_errno=HA_ERR_OLD_FILE;
- goto err;
- }
- info_length=uint2korr(share->state.header.header_length);
- base_pos=uint2korr(share->state.header.base_pos);
- if (!(disk_cache=(char*) my_alloca(info_length)))
- {
- my_errno=ENOMEM;
- goto err;
- }
- errpos=2;
-
- VOID(my_seek(kfile,0L,MY_SEEK_SET,MYF(0)));
-#ifndef NO_LOCKING
- if (!(handle_locking & HA_OPEN_TMP_TABLE))
- {
- if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
- MYF(handle_locking & HA_OPEN_WAIT_IF_LOCKED ?
- 0 : MY_DONT_WAIT))) &&
- !(handle_locking & HA_OPEN_IGNORE_IF_LOCKED))
- goto err;
- }
-#endif
- errpos=3;
- if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
- goto err;
- len=uint2korr(share->state.header.state_info_length);
- if (len != sizeof(N_STATE_INFO))
- {
- DBUG_PRINT("warning",
- ("saved_state_info_length: %d base_info_length: %d",
- len,sizeof(N_STATE_INFO)));
- }
- if (len > sizeof(N_STATE_INFO))
- len=sizeof(N_STATE_INFO);
- share->state_length=len;
- memcpy(&share->state.header.file_version[0],disk_cache,(size_t) len);
- len=uint2korr(share->state.header.base_info_length);
- if (len != sizeof(N_BASE_INFO))
- {
- DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d",
- len,sizeof(N_BASE_INFO)));
- if (len <= offsetof(N_BASE_INFO,sortkey))
- share->base.sortkey=(ushort) ~0;
- }
- memcpy((char*) (byte*) &share->base,disk_cache+base_pos,
- (size_t) min(len,sizeof(N_BASE_INFO)));
- disk_pos=disk_cache+base_pos+len;
- share->base.options=uint2korr(share->state.header.options);
- if (share->base.max_key_length > N_MAX_KEY_BUFF)
- {
- my_errno=HA_ERR_UNSUPPORTED;
- goto err;
- }
- if (share->base.options & HA_OPTION_COMPRESS_RECORD)
- share->base.max_key_length+=2; /* For safety */
-
- if (!my_multi_malloc(MY_WME,
- &share,sizeof(*share),
- &share->keyinfo,share->base.keys*sizeof(N_KEYDEF),
- &share->rec,(share->base.fields+1)*sizeof(N_RECINFO),
- &share->blobs,sizeof(N_BLOB)*share->base.blobs,
- &share->filename,strlen(name_buff)+1,
- NullS))
- goto err;
- errpos=4;
- *share=share_buff;
- strmov(share->filename,name_buff);
-
- /* Fix key in used if old nisam-database */
- if (share->state_length <= offsetof(N_STATE_INFO,keys))
- share->state.keys=share->base.keys;
-
- share->blocksize=min(IO_SIZE,nisam_block_size);
- for (i=0 ; i < share->base.keys ; i++)
- {
- get_next_element(&share->keyinfo[i].base,disk_pos,sizeof(N_SAVE_KEYDEF));
- setup_key_functions(share->keyinfo+i);
- set_if_smaller(share->blocksize,share->keyinfo[i].base.block_length);
- for (j=0 ; j <= share->keyinfo[i].base.keysegs ; j++)
- {
- get_next_element(&share->keyinfo[i].seg[j],disk_pos,
- sizeof(N_SAVE_KEYSEG));
- }
- }
- if (!share->blocksize)
- {
- my_errno=HA_ERR_CRASHED;
- goto err;
- }
-
- for (i=j=offset=0 ; i < share->base.fields ; i++)
- {
- get_next_element(&share->rec[i].base,disk_pos,sizeof(N_SAVE_RECINFO));
-#ifndef NOT_PACKED_DATABASES
- share->rec[i].pack_type=0;
- share->rec[i].huff_tree=0;
-#endif
- if (share->rec[i].base.type == (int) FIELD_BLOB)
- {
- share->blobs[j].pack_length=share->rec[i].base.length;
- share->blobs[j].offset=offset;
- j++;
- offset+=sizeof(char*);
- }
- offset+=share->rec[i].base.length;
- }
- share->rec[i].base.type=(int) FIELD_LAST;
-
-#ifndef NO_LOCKING
- if (! lock_error)
- {
- VOID(my_lock(kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
- lock_error=1; /* Database unlocked */
- }
-#endif
-
- if ((info.dfile=my_open(fn_format(name_buff,name,"",N_NAME_DEXT,2+4),
- mode | O_SHARE,
- MYF(MY_WME))) < 0)
- goto err;
- errpos=5;
-
- share->kfile=kfile;
- share->mode=open_mode;
- share->this_process=(ulong) getpid();
- share->rnd= (int) share->this_process; /* rnd-counter for splitts */
-#ifndef DBUG_OFF
- share->rnd=0; /* To make things repeatable */
-#endif
- share->last_process= share->state.process;
- if (!(share->last_version=share->state.version))
- share->last_version=1; /* Safety */
- share->rec_reflength=share->base.rec_reflength; /* May be changed */
-
- share->data_file_type=STATIC_RECORD;
- if (share->base.options & HA_OPTION_COMPRESS_RECORD)
- {
- share->data_file_type = COMPRESSED_RECORD;
- share->base.options|= HA_OPTION_READ_ONLY_DATA;
- info.s=share;
- if (_nisam_read_pack_info(&info,
- (pbool) test(!(share->base.options &
- (HA_OPTION_PACK_RECORD |
- HA_OPTION_TEMP_COMPRESS_RECORD)))))
- goto err;
- }
- else if (share->base.options & HA_OPTION_PACK_RECORD)
- share->data_file_type = DYNAMIC_RECORD;
- my_afree((gptr) disk_cache);
- setup_functions(share);
-#ifdef THREAD
- thr_lock_init(&share->lock);
- VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
-#endif
- }
- else
- {
- share= old_info->s;
- if (mode == O_RDWR && share->mode == O_RDONLY)
- {
- my_errno=EACCES; /* Can't open in write mode*/
- goto err;
- }
- if ((info.dfile=my_open(fn_format(name_buff,old_info->filename,"",
- N_NAME_DEXT,2+4),
- mode | O_SHARE,MYF(MY_WME))) < 0)
- {
- my_errno=errno;
- goto err;
- }
- errpos=5;
- }
-
- /* alloc and set up private structure parts */
- if (!my_multi_malloc(MY_WME,
- &m_info,sizeof(N_INFO),
- &info.blobs,sizeof(N_BLOB)*share->base.blobs,
- &info.buff,(share->base.max_block*2+
- share->base.max_key_length),
- &info.lastkey,share->base.max_key_length*3+1,
- &info.filename,strlen(name)+1,
- NullS))
- goto err;
- errpos=6;
- strmov(info.filename,name);
- memcpy(info.blobs,share->blobs,sizeof(N_BLOB)*share->base.blobs);
-
- info.s=share;
- info.lastpos= NI_POS_ERROR;
- info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
- info.opt_flag=READ_CHECK_USED;
- info.alloced_rec_buff_length=share->base.pack_reclength;
- info.this_uniq= (ulong) info.dfile; /* Uniq number in process */
- info.this_loop=0; /* Update counter */
- info.last_uniq= share->state.uniq;
- info.last_loop= share->state.loop;
- info.options=share->base.options |
- (mode == O_RDONLY ? HA_OPTION_READ_ONLY_DATA : 0);
- info.lock_type=F_UNLCK;
- info.errkey= -1;
- pthread_mutex_lock(&share->intern_lock);
- info.read_record=share->read_record;
- share->reopen++;
- if (share->base.options & HA_OPTION_READ_ONLY_DATA)
- {
- info.lock_type=F_RDLCK;
- share->r_locks++;
- info.this_uniq=share->state.uniq; /* Row checksum */
- }
-#ifndef NO_LOCKING
- if (handle_locking & HA_OPEN_TMP_TABLE)
-#endif
- {
- share->w_locks++; /* We don't have to update status */
- info.lock_type=F_WRLCK;
- }
- pthread_mutex_unlock(&share->intern_lock);
-
- /* Allocate buffer for one record */
-
- extra=0;
- if (share->base.options & HA_OPTION_PACK_RECORD)
- extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
- DYN_DELETE_BLOCK_HEADER;
- if (!(info.rec_alloc=(byte*) my_malloc(share->base.pack_reclength+extra+
- 6,
- MYF(MY_WME | MY_ZEROFILL))))
- goto err;
- if (extra)
- info.rec_buff=info.rec_alloc+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER);
- else
- info.rec_buff=info.rec_alloc;
-
- *m_info=info;
-#ifdef THREAD
- thr_lock_data_init(&share->lock,&m_info->lock,NULL);
-#endif
-
- m_info->open_list.data=(void*) m_info;
- nisam_open_list=list_add(nisam_open_list,&m_info->open_list);
-
- pthread_mutex_unlock(&THR_LOCK_isam);
- nisam_log_simple(LOG_OPEN,m_info,share->filename,
- (uint) strlen(share->filename));
- DBUG_RETURN(m_info);
-
-err:
- save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
- switch (errpos) {
- case 6:
- my_free((gptr) m_info,MYF(0));
- /* fall through */
- case 5:
- VOID(my_close(info.dfile,MYF(0)));
- if (old_info)
- break; /* Don't remove open table */
- /* fall through */
- case 4:
- my_free((gptr) share,MYF(0));
- /* fall through */
- case 3:
-#ifndef NO_LOCKING
- if (! lock_error)
- VOID(my_lock(kfile, F_UNLCK, 0L, F_TO_EOF, MYF(MY_SEEK_NOT_DONE)));
-#endif
- /* fall through */
- case 2:
- my_afree((gptr) disk_cache);
- /* fall through */
- case 1:
- VOID(my_close(kfile,MYF(0)));
- /* fall through */
- case 0:
- default:
- break;
- }
- pthread_mutex_unlock(&THR_LOCK_isam);
- my_errno=save_errno;
- DBUG_RETURN (NULL);
-} /* nisam_open */
-
-
- /* Set up functions in structs */
-
-static void setup_functions(register ISAM_SHARE *share)
-{
- if (share->base.options & HA_OPTION_COMPRESS_RECORD)
- {
- share->read_record=_nisam_read_pack_record;
- share->read_rnd=_nisam_read_rnd_pack_record;
- }
- else if (share->base.options & HA_OPTION_PACK_RECORD)
- {
- share->read_record=_nisam_read_dynamic_record;
- share->read_rnd=_nisam_read_rnd_dynamic_record;
- share->delete_record=_nisam_delete_dynamic_record;
- share->compare_record=_nisam_cmp_dynamic_record;
-
- /* add bits used to pack data to pack_reclength for faster allocation */
- share->base.pack_reclength+= share->base.pack_bits;
- if (share->base.blobs)
- {
- share->update_record=_nisam_update_blob_record;
- share->write_record=_nisam_write_blob_record;
- }
- else
- {
- share->write_record=_nisam_write_dynamic_record;
- share->update_record=_nisam_update_dynamic_record;
- }
- }
- else
- {
- share->read_record=_nisam_read_static_record;
- share->read_rnd=_nisam_read_rnd_static_record;
- share->delete_record=_nisam_delete_static_record;
- share->compare_record=_nisam_cmp_static_record;
- share->update_record=_nisam_update_static_record;
- share->write_record=_nisam_write_static_record;
- }
- return;
-}
-
-
-static void setup_key_functions(register N_KEYDEF *keyinfo)
-{
- if (keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED))
- {
- keyinfo->bin_search=_nisam_seq_search;
- keyinfo->get_key=_nisam_get_key;
- }
- else
- {
- keyinfo->bin_search=_nisam_bin_search;
- keyinfo->get_key=_nisam_get_static_key;
- }
- return;
-}
-
-/*
- Calculate a long checksum for a memoryblock. Used to verify pack_isam
-
- SYNOPSIS
- checksum()
- mem Pointer to memory block
- count Count of bytes
-*/
-
-ulong _nisam_checksum(const byte *mem, uint count)
-{
- ulong crc;
- for (crc= 0; count-- ; mem++)
- crc= ((crc << 1) + *((uchar*) mem)) +
- test(crc & ((ulong) 1L << (8*sizeof(ulong)-1)));
- return crc;
-}
-
diff --git a/isam/pack_isam.c b/isam/pack_isam.c
deleted file mode 100644
index 0134e0411b2..00000000000
--- a/isam/pack_isam.c
+++ /dev/null
@@ -1,2046 +0,0 @@
-/* Copyright (C) 1979-2002 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 */
-
-/* Pack isam file */
-
-#ifndef USE_MY_FUNC
-#define USE_MY_FUNC /* We nead at least my_malloc */
-#endif
-
-#include "isamdef.h"
-#include <queues.h>
-#include <my_tree.h>
-#include "mysys_err.h"
-#ifdef MSDOS
-#include <io.h>
-#endif
-#ifndef __GNU_LIBRARY__
-#define __GNU_LIBRARY__ /* Skip warnings in getopt.h */
-#endif
-#include <my_getopt.h>
-
-#if INT_MAX > 32767
-#define BITS_SAVED 32
-#else
-#define BITS_SAVED 16
-#endif
-
-#define IS_OFFSET ((uint) 32768) /* Bit if offset or char in tree */
-#define HEAD_LENGTH 32
-#define ALLOWED_JOIN_DIFF 256 /* Diff allowed to join trees */
-
-#define DATA_TMP_EXT ".TMD"
-#define OLD_EXT ".OLD"
-#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
-
-struct st_file_buffer {
- File file;
- char *buffer,*pos,*end;
- my_off_t pos_in_file;
- int bits;
- uint bytes;
-};
-
-struct st_huff_tree;
-struct st_huff_element;
-
-typedef struct st_huff_counts {
- uint field_length,max_zero_fill;
- uint pack_type;
- uint max_end_space,max_pre_space,length_bits,min_space;
- enum en_fieldtype field_type;
- struct st_huff_tree *tree; /* Tree for field */
- my_off_t counts[256];
- my_off_t end_space[8];
- my_off_t pre_space[8];
- my_off_t tot_end_space,tot_pre_space,zero_fields,empty_fields,bytes_packed;
- TREE int_tree;
- byte *tree_buff;
- byte *tree_pos;
-} HUFF_COUNTS;
-
-typedef struct st_huff_element HUFF_ELEMENT;
-
-struct st_huff_element {
- my_off_t count;
- union un_element {
- struct st_nod {
- HUFF_ELEMENT *left,*right;
- } nod;
- struct st_leaf {
- HUFF_ELEMENT *null;
- uint element_nr; /* Number of element */
- } leaf;
- } a;
-};
-
-
-typedef struct st_huff_tree {
- HUFF_ELEMENT *root,*element_buffer;
- HUFF_COUNTS *counts;
- uint tree_number;
- uint elements;
- my_off_t bytes_packed;
- uint tree_pack_length;
- uint min_chr,max_chr,char_bits,offset_bits,max_offset,height;
- ulong *code;
- uchar *code_len;
-} HUFF_TREE;
-
-
-typedef struct st_isam_mrg {
- N_INFO **file,**current,**end;
- uint count;
- uint min_pack_length; /* Theese is used by packed data */
- uint max_pack_length;
- uint ref_length;
- my_off_t records;
-} MRG_INFO;
-
-
-extern int main(int argc,char * *argv);
-static void get_options(int *argc,char ***argv);
-static N_INFO *open_isam_file(char *name,int mode);
-static bool open_isam_files(MRG_INFO *mrg,char **names,uint count);
-static int compress(MRG_INFO *file,char *join_name);
-static HUFF_COUNTS *init_huff_count(N_INFO *info,my_off_t records);
-static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees,
- uint trees,
- HUFF_COUNTS *huff_counts,
- uint fields);
-static int compare_tree(const uchar *s,const uchar *t);
-static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts);
-static void check_counts(HUFF_COUNTS *huff_counts,uint trees,
- my_off_t records);
-static int test_space_compress(HUFF_COUNTS *huff_counts,my_off_t records,
- uint max_space_length,my_off_t *space_counts,
- my_off_t tot_space_count,
- enum en_fieldtype field_type);
-static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts,uint trees);
-static int make_huff_tree(HUFF_TREE *tree,HUFF_COUNTS *huff_counts);
-static int compare_huff_elements(void *not_used, byte *a,byte *b);
-static int save_counts_in_queue(byte *key,element_count count,
- HUFF_TREE *tree);
-static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,uint flag);
-static uint join_same_trees(HUFF_COUNTS *huff_counts,uint trees);
-static int make_huff_decode_table(HUFF_TREE *huff_tree,uint trees);
-static void make_traverse_code_tree(HUFF_TREE *huff_tree,
- HUFF_ELEMENT *element,uint size,
- ulong code);
-static int write_header(MRG_INFO *isam_file, uint header_length,uint trees,
- my_off_t tot_elements,my_off_t filelength);
-static void write_field_info(HUFF_COUNTS *counts, uint fields,uint trees);
-static my_off_t write_huff_tree(HUFF_TREE *huff_tree,uint trees);
-static uint *make_offset_code_tree(HUFF_TREE *huff_tree,
- HUFF_ELEMENT *element,
- uint *offset);
-static uint max_bit(uint value);
-static int compress_isam_file(MRG_INFO *file,HUFF_COUNTS *huff_counts);
-static char *make_new_name(char *new_name,char *old_name);
-static char *make_old_name(char *new_name,char *old_name);
-static void init_file_buffer(File file,pbool read_buffer);
-static int flush_buffer(uint neaded_length);
-static void end_file_buffer(void);
-static void write_bits(ulong value,uint bits);
-static void flush_bits(void);
-static void save_integer(byte *pos,uint pack_length,my_off_t value);
-static void save_state(N_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
- ulong crc);
-static int save_state_mrg(File file,MRG_INFO *isam_file,my_off_t new_length,
- ulong crc);
-static int mrg_close(MRG_INFO *mrg);
-static int mrg_rrnd(MRG_INFO *info,byte *buf);
-static void mrg_reset(MRG_INFO *mrg);
-
-
-static int error_on_write=0,test_only=0,verbose=0,silent=0,
- write_loop=0,force_pack=0,isamchk_neaded=0;
-static my_bool backup, opt_wait;
-static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
-static uint tree_buff_length=8196-MALLOC_OVERHEAD,force_pack_ref_length;
-static char tmp_dir[FN_REFLEN]={0},*join_table;
-static my_off_t intervall_length;
-static ulong crc;
-static struct st_file_buffer file_buffer;
-static QUEUE queue;
-static HUFF_COUNTS *global_count;
-static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-static const char *load_default_groups[]= { "pack_isam",0 };
-
- /* The main program */
-
-int main(int argc, char **argv)
-{
- int error,ok;
- MRG_INFO merge;
- MY_INIT(argv[0]);
-
- load_defaults("my",load_default_groups,&argc,&argv);
- get_options(&argc,&argv);
-
- error=ok=isamchk_neaded=0;
- if (join_table)
- { /* Join files into one */
- if (open_isam_files(&merge,argv,(uint) argc) ||
- compress(&merge,join_table))
- error=1;
- }
- else while (argc--)
- {
- N_INFO *isam_file;
- if (!(isam_file=open_isam_file(*argv++,O_RDWR)))
- error=1;
- else
- {
- merge.file= &isam_file;
- merge.current=0;
- merge.count=1;
- if (compress(&merge,0))
- error=1;
- else
- ok=1;
- }
- }
- if (ok && isamchk_neaded && !silent)
- puts("Remember to run isamchk -rq on compressed databases");
- VOID(fflush(stdout)); VOID(fflush(stderr));
- my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
- exit(error ? 2 : 0);
-#ifndef _lint
- return 0; /* No compiler warning */
-#endif
-}
-
-
-static struct my_option my_long_options[] =
-{
- {"backup", 'b', "Make a backup of the table as table_name.OLD",
- (gptr*) &backup, (gptr*) &backup, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'",
- 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"force", 'f',
- "Force packing of table even if it's gets bigger or tempfile exists.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"join", 'j',
- "Join all given tables into 'new_table_name'. All tables MUST have the identical layout.",
- (gptr*) &join_table, (gptr*) &join_table, 0, GET_STR, REQUIRED_ARG, 0, 0,
- 0, 0, 0, 0},
- {"help", '?', "Display this help and exit.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"packlength", 'p', "Force storage size of recordlength (1, 2 or 3)",
- (gptr*) &force_pack_ref_length, (gptr*) &force_pack_ref_length, 0,
- GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"silent", 's', "Be more silent.",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0 ,0},
- {"tmpdir", 'T', "Use temporary directory to store temporary table",
- (gptr*) &tmp_dir, (gptr*) &tmp_dir, 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",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0 ,0},
- {"version", 'V', "output version information and exit",
- 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0 ,0},
- {"wait", 'w', "Wait and retry if table is in use", (gptr*) &opt_wait,
- (gptr*) &opt_wait, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
-};
-
-
-#include <help_start.h>
-
-static void print_version(void)
-{
- printf("%s Ver 5.10 for %s on %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
-}
-
-static void usage(void)
-{
- print_version();
- puts("Copyright (C) 2002 MySQL AB");
- puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
- puts("and you are welcome to modify and redistribute it under the GPL license\n");
-
- puts("Pack a ISAM-table to take much smaller space");
- puts("Keys are not updated, so you must run isamchk -rq on any table");
- puts("that has keys after you have compressed it");
- puts("You should give the .ISM file as the filename argument");
-
- printf("\nUsage: %s [OPTIONS] filename...\n", my_progname);
- my_print_help(my_long_options);
- print_defaults("my", load_default_groups);
- my_print_variables(my_long_options);
-}
-
-#include <help_end.h>
-
-
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- uint length;
-
- switch(optid) {
- case 'f':
- force_pack= 1;
- tmpfile_createflag= O_RDWR | O_TRUNC;
- break;
- case 'p':
- if (force_pack_ref_length > 3)
- force_pack_ref_length= 0;
- break;
- case 's':
- write_loop= verbose= 0;
- silent= 1;
- break;
- case 't':
- test_only= verbose= 1;
- break;
- case 'T':
- length=(uint) (strmov(tmp_dir, argument) - tmp_dir);
- if (length != dirname_length(tmp_dir))
- {
- tmp_dir[length]= FN_LIBCHAR;
- tmp_dir[length + 1]= 0;
- }
- break;
- case 'v':
- verbose= 1;
- silent= 0;
- break;
- case '#':
- DBUG_PUSH(argument ? argument : "d:t:o");
- break;
- case 'V': print_version(); exit(0);
- case 'I':
- case '?':
- usage();
- exit(0);
- }
- return 0;
-}
-
- /* reads options */
- /* Initiates DEBUG - but no debugging here ! */
-
-static void get_options(int *argc, char ***argv)
-{
- int ho_error;
-
- if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
- exit(ho_error);
-
- my_progname= argv[0][0];
- if (isatty(fileno(stdout)))
- write_loop=1;
-
- if (!*argc)
- {
- usage();
- exit(1);
- }
- if (join_table)
- {
- backup=0; /* Not needed */
- tmp_dir[0]=0;
- }
- return;
-}
-
-
-static N_INFO *open_isam_file(char *name,int mode)
-{
- N_INFO *isam_file;
- ISAM_SHARE *share;
- DBUG_ENTER("open_isam_file");
-
- if (!(isam_file=nisam_open(name,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));
- DBUG_RETURN(0);
- }
- share=isam_file->s;
- if (share->base.blobs)
- {
- VOID(fprintf(stderr,"%s has blobs, can't pack it\n",name));
- VOID(nisam_close(isam_file));
- DBUG_RETURN(0);
- }
- if (share->base.options & HA_OPTION_COMPRESS_RECORD && !join_table)
- {
- if (!force_pack)
- {
- VOID(fprintf(stderr,"%s is already compressed\n",name));
- VOID(nisam_close(isam_file));
- DBUG_RETURN(0);
- }
- if (verbose)
- puts("Recompressing already compressed table");
- share->base.options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
- }
- if (! force_pack && share->state.records != 0 &&
- (share->state.records <= 1 ||
- share->state.data_file_length < 1024) && ! join_table)
- {
- VOID(fprintf(stderr,"%s is too small to compress\n",name));
- VOID(nisam_close(isam_file));
- DBUG_RETURN(0);
- }
- VOID(nisam_lock_database(isam_file,F_WRLCK));
- DBUG_RETURN(isam_file);
-}
-
-
-static bool open_isam_files(MRG_INFO *mrg,char **names,uint count)
-{
- uint i,j;
- mrg->count=0;
- mrg->current=0;
- mrg->file=(N_INFO**) my_malloc(sizeof(N_INFO*)*count,MYF(MY_FAE));
- for (i=0; i < count ; i++)
- {
- if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY)))
- goto error;
- }
- /* Check that files are identical */
- for (j=0 ; j < count-1 ; j++)
- {
- N_RECINFO *m1,*m2,*end;
- if (mrg->file[j]->s->base.reclength != mrg->file[j+1]->s->base.reclength ||
- mrg->file[j]->s->base.fields != mrg->file[j+1]->s->base.fields)
- goto diff_file;
- m1=mrg->file[j]->s->rec;
- end=m1+mrg->file[j]->s->base.fields;
- m2=mrg->file[j+1]->s->rec;
- for ( ; m1 != end ; m1++,m2++)
- {
- if ((m1->base.type != m2->base.type && ! force_pack) ||
- m1->base.length != m2->base.length)
- goto diff_file;
- }
- }
- mrg->count=count;
- return 0;
-
- diff_file:
- fprintf(stderr,"%s: Tables '%s' and '%s' are not identical\n",
- my_progname,names[j],names[j+1]);
- error:
- while (i--)
- nisam_close(mrg->file[i]);
- return 1;
-}
-
-
-static int compress(MRG_INFO *mrg,char *result_table)
-{
- int error;
- File new_file,join_isam_file;
- N_INFO *isam_file;
- ISAM_SHARE *share;
- char org_name[FN_REFLEN],new_name[FN_REFLEN],temp_name[FN_REFLEN];
- uint i,header_length,fields,trees,used_trees;
- my_off_t old_length,new_length,tot_elements;
- HUFF_COUNTS *huff_counts;
- HUFF_TREE *huff_trees;
- DBUG_ENTER("compress");
-
- isam_file=mrg->file[0]; /* Take this as an example */
- share=isam_file->s;
- new_file=join_isam_file= -1;
- trees=fields=0;
- huff_trees=0;
- huff_counts=0;
-
- /* Create temporary or join file */
-
- if (backup)
- VOID(fn_format(org_name,isam_file->filename,"",N_NAME_DEXT,2));
- else
- VOID(fn_format(org_name,isam_file->filename,"",N_NAME_DEXT,2+4+16));
- if (!test_only && result_table)
- {
- /* Make a new indexfile based on first file in list */
- uint length;
- char *buff;
- strmov(org_name,result_table); /* Fix error messages */
- VOID(fn_format(new_name,result_table,"",N_NAME_IEXT,2));
- if ((join_isam_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME)))
- < 0)
- goto err;
- length=share->base.keystart;
- if (!(buff=my_malloc(length,MYF(MY_WME))))
- goto err;
- if (my_pread(share->kfile,buff,length,0L,MYF(MY_WME | MY_NABP)) ||
- my_write(join_isam_file,buff,length,
- MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
- {
- my_free(buff,MYF(0));
- goto err;
- }
- my_free(buff,MYF(0));
- VOID(fn_format(new_name,result_table,"",N_NAME_DEXT,2));
- }
- else if (!tmp_dir[0])
- VOID(make_new_name(new_name,org_name));
- else
- VOID(fn_format(new_name,org_name,tmp_dir,DATA_TMP_EXT,1+2+4));
- if (!test_only &&
- (new_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME))) < 0)
- goto err;
-
- /* Start calculating statistics */
-
- mrg->records=0;
- for (i=0 ; i < mrg->count ; i++)
- mrg->records+=mrg->file[i]->s->state.records;
- if (write_loop || verbose)
- {
- 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;
- if (write_loop || verbose)
- printf("- Calculating statistics\n");
- if (get_statistic(mrg,huff_counts))
- goto err;
- NORMAL_SAFEMALLOC;
- old_length=0;
- for (i=0; i < mrg->count ; i++)
- old_length+= (mrg->file[i]->s->state.data_file_length -
- mrg->file[i]->s->state.empty);
-
- if (init_queue(&queue,256,0,0,compare_huff_elements,0))
- goto err;
- check_counts(huff_counts,fields,mrg->records);
- huff_trees=make_huff_trees(huff_counts,trees);
- if ((int) (used_trees=join_same_trees(huff_counts,trees)) < 0)
- goto err;
- if (make_huff_decode_table(huff_trees,fields))
- goto err;
-
- init_file_buffer(new_file,0);
- 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_info(huff_counts,fields,used_trees);
- if (!(tot_elements=write_huff_tree(huff_trees,trees)))
- goto err;
- header_length=(uint) file_buffer.pos_in_file+
- (uint) (file_buffer.pos-file_buffer.buffer);
-
- /* Compress file */
- if (write_loop || verbose)
- printf("- Compressing file\n");
- error=compress_isam_file(mrg,huff_counts);
- new_length=file_buffer.pos_in_file;
- if (!error && !test_only)
- {
- char buff[MEMMAP_EXTRA_MARGIN]; /* End marginal for memmap */
- bzero(buff,sizeof(buff));
- error=my_write(file_buffer.file,buff,sizeof(buff),
- MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
- }
- if (!error)
- error=write_header(mrg,header_length,used_trees,tot_elements,
- new_length);
- end_file_buffer();
-
- if (verbose && mrg->records)
- printf("Min record length: %6d Max length: %6d Mean total length: %6lu\n",
- mrg->min_pack_length,mrg->max_pack_length,
- (ulong) (new_length/mrg->records));
-
- if (!test_only)
- {
- error|=my_close(new_file,MYF(MY_WME));
- if (!result_table)
- {
- error|=my_close(isam_file->dfile,MYF(MY_WME));
- isam_file->dfile= -1; /* Tell nisam_close file is closed */
- }
- }
-
- free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
- if (! test_only && ! error)
- {
- if (result_table)
- {
- error=save_state_mrg(join_isam_file,mrg,new_length,crc);
- }
- else
- {
- if (backup)
- {
- if (my_rename(org_name,make_old_name(temp_name,isam_file->filename),
- MYF(MY_WME)))
- error=1;
- else
- {
- if (tmp_dir[0])
- {
- if (!(error=my_copy(new_name,org_name,MYF(MY_WME))))
- VOID(my_delete(new_name,MYF(MY_WME)));
- }
- else
- error=my_rename(new_name,org_name,MYF(MY_WME));
- if (!error)
- VOID(my_copystat(temp_name,org_name,MYF(MY_COPYTIME)));
- }
- }
- else
- {
- if (tmp_dir[0])
- {
-
- if (!(error=my_copy(new_name,org_name,
- MYF(MY_WME | MY_HOLD_ORIGINAL_MODES
- | MY_COPYTIME))))
- VOID(my_delete(new_name,MYF(MY_WME)));
- }
- else
- error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME));
- }
- if (! error)
- save_state(isam_file,mrg,new_length,crc);
- }
- }
- error|=mrg_close(mrg);
- if (join_isam_file >= 0)
- error|=my_close(join_isam_file,MYF(MY_WME));
- if (error)
- {
- VOID(fprintf(stderr,"Aborting: %s is not compressed\n",org_name));
- DBUG_RETURN(-1);
- }
- if (write_loop || verbose)
- {
- if (old_length)
- printf("%.4g%% \n",
- my_off_t2double(old_length-new_length)*100.0/
- my_off_t2double(old_length));
- else
- puts("Empty file saved in compressed format");
- }
- DBUG_RETURN(0);
-
- err:
- free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
- if (new_file >= 0)
- VOID(my_close(new_file,MYF(0)));
- if (join_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));
- DBUG_RETURN(-1);
-}
-
- /* Init a huff_count-struct for each field and init it */
-
-static HUFF_COUNTS *init_huff_count(N_INFO *info,my_off_t records)
-{
- reg2 uint i;
- reg1 HUFF_COUNTS *count;
- if ((count = (HUFF_COUNTS*) my_malloc(info->s->base.fields*sizeof(HUFF_COUNTS),
- MYF(MY_ZEROFILL | MY_WME))))
- {
- for (i=0 ; i < info->s->base.fields ; i++)
- {
- enum en_fieldtype type;
- count[i].field_length=info->s->rec[i].base.length;
- type= count[i].field_type= (enum en_fieldtype) info->s->rec[i].base.type;
- if (type == FIELD_INTERVALL ||
- type == FIELD_CONSTANT ||
- type == FIELD_ZERO)
- type = FIELD_NORMAL;
- if (count[i].field_length <= 8 &&
- (type == FIELD_NORMAL ||
- type == FIELD_SKIP_ZERO))
- count[i].max_zero_fill= count[i].field_length;
- init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0,
- NULL, NULL);
- if (records)
- count[i].tree_pos=count[i].tree_buff =
- my_malloc(count[i].field_length > 1 ? tree_buff_length : 2,
- MYF(MY_WME));
- }
- }
- return count;
-}
-
-
- /* Free memory used by counts and trees */
-
-static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees, uint trees, HUFF_COUNTS *huff_counts, uint fields)
-{
- register uint i;
-
- if (huff_trees)
- {
- for (i=0 ; i < trees ; i++)
- {
- if (huff_trees[i].element_buffer)
- my_free((gptr) huff_trees[i].element_buffer,MYF(0));
- if (huff_trees[i].code)
- my_free((gptr) huff_trees[i].code,MYF(0));
- }
- my_free((gptr) huff_trees,MYF(0));
- }
- if (huff_counts)
- {
- for (i=0 ; i < fields ; i++)
- {
- if (huff_counts[i].tree_buff)
- {
- my_free((gptr) huff_counts[i].tree_buff,MYF(0));
- delete_tree(&huff_counts[i].int_tree);
- }
- }
- my_free((gptr) huff_counts,MYF(0));
- }
- delete_queue(&queue); /* This is safe to free */
- return;
-}
-
- /* Read through old file and gather some statistics */
-
-static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
-{
- int error;
- uint length,reclength;
- byte *record,*pos,*next_pos,*end_pos,*start_pos;
- my_off_t record_count;
- HUFF_COUNTS *count,*end_count;
- TREE_ELEMENT *element;
- DBUG_ENTER("get_statistic");
-
- reclength=mrg->file[0]->s->base.reclength;
- record=(byte*) my_alloca(reclength);
- end_count=huff_counts+mrg->file[0]->s->base.fields;
- record_count=crc=0;
-
- mrg_reset(mrg);
- while ((error=mrg_rrnd(mrg,record)) >= 0)
- {
- if (! error)
- {
- crc^=_nisam_checksum(record,reclength);
- for (pos=record,count=huff_counts ;
- count < end_count ;
- count++,
- pos=next_pos)
- {
- next_pos=end_pos=(start_pos=pos)+count->field_length;
-
- /* Put value in tree if there is room for it */
- 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->field_length == 1 &&
- count->int_tree.elements_in_tree > 1)))
- {
- delete_tree(&count->int_tree);
- my_free(count->tree_buff,MYF(0));
- count->tree_buff=0;
- }
- else
- {
- if (element->count == 1)
- { /* New element */
- memcpy(count->tree_pos,pos,(size_t) count->field_length);
- tree_set_pointer(element,count->tree_pos);
- count->tree_pos+=count->field_length;
- }
- }
- }
-
- /* Save character counters and space-counts and zero-field-counts */
- if (count->field_type == FIELD_NORMAL ||
- count->field_type == FIELD_SKIP_ENDSPACE)
- {
- for ( ; end_pos > pos ; end_pos--)
- if (end_pos[-1] != ' ')
- break;
- if (end_pos == pos)
- {
- count->empty_fields++;
- count->max_zero_fill=0;
- continue;
- }
- length= (uint) (next_pos-end_pos);
- count->tot_end_space+=length;
- if (length < 8)
- count->end_space[length]++;
- if (count->max_end_space < length)
- count->max_end_space = length;
- }
- if (count->field_type == FIELD_NORMAL ||
- count->field_type == FIELD_SKIP_PRESPACE)
- {
- for (pos=start_pos; pos < end_pos ; pos++)
- if (pos[0] != ' ')
- break;
- if (end_pos == pos)
- {
- count->empty_fields++;
- count->max_zero_fill=0;
- continue;
- }
- length= (uint) (pos-start_pos);
- count->tot_pre_space+=length;
- if (length < 8)
- count->pre_space[length]++;
- if (count->max_pre_space < length)
- count->max_pre_space = length;
- }
- if (count->field_length <= 8 &&
- (count->field_type == FIELD_NORMAL ||
- count->field_type == FIELD_SKIP_ZERO))
- {
- uint i;
- if (!memcmp((byte*) start_pos,zero_string,count->field_length))
- {
- count->zero_fields++;
- continue;
- }
-#ifdef BYTE_ORDER_HIGH_FIRST
- for (i =0 ; i < count->max_zero_fill && ! start_pos[i] ; i++) ;
- if (i < count->max_zero_fill)
- count->max_zero_fill=i;
-#else
- 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;
-#endif
- }
- for (pos=start_pos ; pos < end_pos ; pos++)
- count->counts[(uchar) *pos]++;
- }
- record_count++;
- if (write_loop && record_count % WRITE_COUNT == 0)
- {
- printf("%lu\r",(ulong) record_count); VOID(fflush(stdout));
- }
- }
- }
- if (write_loop)
- {
- printf(" \r"); VOID(fflush(stdout));
- }
- mrg->records=record_count;
- my_afree((gptr) record);
- DBUG_RETURN(0);
-}
-
-static int compare_huff_elements(void *not_used __attribute__((unused)),
- byte *a, byte *b)
-{
- return *((my_off_t*) a) < *((my_off_t*) b) ? -1 :
- (*((my_off_t*) a) == *((my_off_t*) b) ? 0 : 1);
-}
-
- /* Check each tree if we should use pre-space-compress, end-space-
- compress, empty-field-compress or zero-field-compress */
-
-static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records)
-{
- uint space_fields,fill_zero_fields,field_count[(int) FIELD_ZERO+1];
- my_off_t old_length,new_length,length;
- DBUG_ENTER("check_counts");
-
- bzero((gptr) field_count,sizeof(field_count));
- space_fields=fill_zero_fields=0;
-
- for (; trees-- ; huff_counts++)
- {
- huff_counts->field_type=FIELD_NORMAL;
- huff_counts->pack_type=0;
-
- if (huff_counts->zero_fields || ! records)
- {
- my_off_t old_space_count;
- if (huff_counts->zero_fields == records)
- {
- huff_counts->field_type= FIELD_ZERO;
- huff_counts->bytes_packed=0;
- huff_counts->counts[0]=0;
- goto found_pack;
- }
- 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;
- old_length=calc_packed_length(huff_counts,0)+records/8;
- length=huff_counts->zero_fields*huff_counts->field_length;
- huff_counts->counts[0]+=length;
- new_length=calc_packed_length(huff_counts,0);
- if (old_length < new_length && huff_counts->field_length > 1)
- {
- huff_counts->field_type=FIELD_SKIP_ZERO;
- huff_counts->counts[0]-=length;
- huff_counts->bytes_packed=old_length- records/8;
- goto found_pack;
- }
- huff_counts->counts[' ']=old_space_count;
- }
- huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
- if (huff_counts->empty_fields)
- {
- if (huff_counts->field_length > 2 &&
- huff_counts->empty_fields + (records - huff_counts->empty_fields)*
- (1+max_bit(max(huff_counts->max_pre_space,
- huff_counts->max_end_space))) <
- records * max_bit(huff_counts->field_length))
- {
- huff_counts->pack_type |= PACK_TYPE_SPACE_FIELDS;
- }
- else
- {
- length=huff_counts->empty_fields*huff_counts->field_length;
- if (huff_counts->tot_end_space || ! huff_counts->tot_pre_space)
- {
- huff_counts->tot_end_space+=length;
- huff_counts->max_end_space=huff_counts->field_length;
- if (huff_counts->field_length < 8)
- huff_counts->end_space[huff_counts->field_length]+=
- huff_counts->empty_fields;
- }
- else
- {
- huff_counts->tot_pre_space+=length;
- huff_counts->max_pre_space=huff_counts->field_length;
- if (huff_counts->field_length < 8)
- huff_counts->pre_space[huff_counts->field_length]+=
- huff_counts->empty_fields;
- }
- }
- }
- if (huff_counts->tot_end_space)
- {
- huff_counts->counts[' ']+=huff_counts->tot_pre_space;
- if (test_space_compress(huff_counts,records,huff_counts->max_end_space,
- huff_counts->end_space,
- huff_counts->tot_end_space,FIELD_SKIP_ENDSPACE))
- goto found_pack;
- huff_counts->counts[' ']-=huff_counts->tot_pre_space;
- }
- if (huff_counts->tot_pre_space)
- {
- if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
- huff_counts->pre_space,
- huff_counts->tot_pre_space,FIELD_SKIP_PRESPACE))
- goto found_pack;
- }
-
- found_pack: /* Found field-packing */
-
- /* Test if we can use zero-fill */
-
- if (huff_counts->max_zero_fill &&
- (huff_counts->field_type == FIELD_NORMAL ||
- huff_counts->field_type == FIELD_SKIP_ZERO))
- {
- huff_counts->counts[0]-=huff_counts->max_zero_fill*
- (huff_counts->field_type == FIELD_SKIP_ZERO ?
- records - huff_counts->zero_fields : records);
- huff_counts->pack_type|=PACK_TYPE_ZERO_FILL;
- huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
- }
-
- /* Test if intervall-field is better */
-
- if (huff_counts->tree_buff)
- {
- HUFF_TREE tree;
-
- tree.element_buffer=0;
- if (!make_huff_tree(&tree,huff_counts) &&
- tree.bytes_packed+tree.tree_pack_length < huff_counts->bytes_packed)
- {
- if (tree.elements == 1)
- huff_counts->field_type=FIELD_CONSTANT;
- else
- huff_counts->field_type=FIELD_INTERVALL;
- huff_counts->pack_type=0;
- }
- else
- {
- my_free((gptr) huff_counts->tree_buff,MYF(0));
- delete_tree(&huff_counts->int_tree);
- huff_counts->tree_buff=0;
- }
- if (tree.element_buffer)
- my_free((gptr) tree.element_buffer,MYF(0));
- }
- if (huff_counts->pack_type & PACK_TYPE_SPACE_FIELDS)
- space_fields++;
- if (huff_counts->pack_type & PACK_TYPE_ZERO_FILL)
- fill_zero_fields++;
- field_count[huff_counts->field_type]++;
- }
- if (verbose)
- printf("\nnormal: %3d empty-space: %3d empty-zero: %3d empty-fill: %3d\npre-space: %3d end-space: %3d table-lookup: %3d zero: %3d\n",
- field_count[FIELD_NORMAL],space_fields,
- field_count[FIELD_SKIP_ZERO],fill_zero_fields,
- field_count[FIELD_SKIP_PRESPACE],
- field_count[FIELD_SKIP_ENDSPACE],
- field_count[FIELD_INTERVALL],
- field_count[FIELD_ZERO]);
- DBUG_VOID_RETURN;
-}
-
- /* Test if we can use space-compression and empty-field-compression */
-
-static int
-test_space_compress(HUFF_COUNTS *huff_counts, my_off_t records,
- uint max_space_length, my_off_t *space_counts,
- my_off_t tot_space_count, enum en_fieldtype field_type)
-{
- int min_pos;
- uint length_bits,i;
- my_off_t space_count,min_space_count,min_pack,new_length,skipp;
-
- length_bits=max_bit(max_space_length);
-
- /* Default no end_space-packing */
- space_count=huff_counts->counts[(uint) ' '];
- min_space_count= (huff_counts->counts[(uint) ' ']+= tot_space_count);
- min_pack=calc_packed_length(huff_counts,0);
- min_pos= -2;
- huff_counts->counts[(uint) ' ']=space_count;
-
- /* Test with allways space-count */
- new_length=huff_counts->bytes_packed+length_bits*records/8;
- if (new_length+1 < min_pack)
- {
- min_pos= -1;
- min_pack=new_length;
- min_space_count=space_count;
- }
- /* Test with length-flag */
- for (skipp=0L, i=0 ; i < 8 ; i++)
- {
- if (space_counts[i])
- {
- if (i)
- huff_counts->counts[(uint) ' ']+=space_counts[i];
- skipp+=huff_counts->pre_space[i];
- new_length=calc_packed_length(huff_counts,0)+
- (records+(records-skipp)*(1+length_bits))/8;
- if (new_length < min_pack)
- {
- min_pos=(int) i;
- min_pack=new_length;
- min_space_count=huff_counts->counts[(uint) ' '];
- }
- }
- }
-
- huff_counts->counts[(uint) ' ']=min_space_count;
- huff_counts->bytes_packed=min_pack;
- switch (min_pos) {
- case -2:
- return(0); /* No space-compress */
- case -1: /* Always space-count */
- huff_counts->field_type=field_type;
- huff_counts->min_space=0;
- huff_counts->length_bits=max_bit(max_space_length);
- break;
- default:
- huff_counts->field_type=field_type;
- huff_counts->min_space=(uint) min_pos;
- huff_counts->pack_type|=PACK_TYPE_SELECTED;
- huff_counts->length_bits=max_bit(max_space_length);
- break;
- }
- return(1); /* Using space-compress */
-}
-
-
- /* Make a huff_tree of each huff_count */
-
-static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts, uint trees)
-{
- uint tree;
- HUFF_TREE *huff_tree;
- DBUG_ENTER("make_huff_trees");
-
- if (!(huff_tree=(HUFF_TREE*) my_malloc(trees*sizeof(HUFF_TREE),
- MYF(MY_WME | MY_ZEROFILL))))
- DBUG_RETURN(0);
-
- for (tree=0 ; tree < trees ; tree++)
- {
- if (make_huff_tree(huff_tree+tree,huff_counts+tree))
- {
- while (tree--)
- my_free((gptr) huff_tree[tree].element_buffer,MYF(0));
- my_free((gptr) huff_tree,MYF(0));
- DBUG_RETURN(0);
- }
- }
- DBUG_RETURN(huff_tree);
-}
-
- /* Update huff_tree according to huff_counts->counts or
- huff_counts->tree_buff */
-
-static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
-{
- uint i,found,bits_packed,first,last;
- my_off_t bytes_packed;
- HUFF_ELEMENT *a,*b,*new;
-
- first=last=0;
- if (huff_counts->tree_buff)
- {
- found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) /
- huff_counts->field_length;
- first=0; last=found-1;
- }
- else
- {
- for (i=found=0 ; i < 256 ; i++)
- {
- if (huff_counts->counts[i])
- {
- if (! found++)
- first=i;
- last=i;
- }
- }
- if (found < 2)
- found=2;
- }
-
- if (queue.max_elements < found)
- {
- delete_queue(&queue);
- if (init_queue(&queue,found,0,0,compare_huff_elements,0))
- return -1;
- }
-
- if (!huff_tree->element_buffer)
- {
- if (!(huff_tree->element_buffer=
- (HUFF_ELEMENT*) my_malloc(found*2*sizeof(HUFF_ELEMENT),MYF(MY_WME))))
- return 1;
- }
- else
- {
- HUFF_ELEMENT *temp;
- if (!(temp=
- (HUFF_ELEMENT*) my_realloc((gptr) huff_tree->element_buffer,
- found*2*sizeof(HUFF_ELEMENT),
- MYF(MY_WME))))
- return 1;
- huff_tree->element_buffer=temp;
- }
-
- huff_counts->tree=huff_tree;
- huff_tree->counts=huff_counts;
- huff_tree->min_chr=first;
- huff_tree->max_chr=last;
- huff_tree->char_bits=max_bit(last-first);
- huff_tree->offset_bits=max_bit(found-1)+1;
-
- if (huff_counts->tree_buff)
- {
- huff_tree->elements=0;
- 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);
- }
- else
- {
- huff_tree->elements=found;
- huff_tree->tree_pack_length=(9+9+5+5+
- (huff_tree->char_bits+1)*found+
- (huff_tree->offset_bits+1)*
- (found-2)+7)/8;
-
- for (i=first, found=0 ; i <= last ; i++)
- {
- if (huff_counts->counts[i])
- {
- new=huff_tree->element_buffer+(found++);
- new->count=huff_counts->counts[i];
- new->a.leaf.null=0;
- new->a.leaf.element_nr=i;
- queue.root[found]=(byte*) new;
- }
- }
- while (found < 2)
- { /* Our huff_trees request at least 2 elements */
- new=huff_tree->element_buffer+(found++);
- new->count=0;
- new->a.leaf.null=0;
- if (last)
- new->a.leaf.element_nr=huff_tree->min_chr=last-1;
- else
- new->a.leaf.element_nr=huff_tree->max_chr=last+1;
- queue.root[found]=(byte*) new;
- }
- }
- queue.elements=found;
-
- for (i=found/2 ; i > 0 ; i--)
- _downheap(&queue,i);
- bytes_packed=0; bits_packed=0;
- for (i=1 ; i < found ; i++)
- {
- a=(HUFF_ELEMENT*) queue_remove(&queue,0);
- b=(HUFF_ELEMENT*) queue.root[1];
- new=huff_tree->element_buffer+found+i;
- new->count=a->count+b->count;
- bits_packed+=(uint) (new->count & 7);
- bytes_packed+=new->count/8;
- new->a.nod.left=a; /* lesser in left */
- new->a.nod.right=b;
- queue.root[1]=(byte*) new;
- queue_replaced(&queue);
- }
- huff_tree->root=(HUFF_ELEMENT*) queue.root[1];
- huff_tree->bytes_packed=bytes_packed+(bits_packed+7)/8;
- return 0;
-}
-
-static int compare_tree(register const uchar *s, register const uchar *t)
-{
- uint length;
- for (length=global_count->field_length; length-- ;)
- if (*s++ != *t++)
- return (int) s[-1] - (int) t[-1];
- return 0;
-}
-
- /* Used by make_huff_tree to save intervall-counts in queue */
-
-static int save_counts_in_queue(byte *key, element_count count, HUFF_TREE *tree)
-{
- HUFF_ELEMENT *new;
-
- new=tree->element_buffer+(tree->elements++);
- new->count=count;
- new->a.leaf.null=0;
- new->a.leaf.element_nr= (uint) (key- tree->counts->tree_buff) /
- tree->counts->field_length;
- queue.root[tree->elements]=(byte*) new;
- return 0;
-}
-
-
- /* Calculate length of file if given counts should be used */
- /* Its actually a faster version of make_huff_tree */
-
-static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts, uint add_tree_lenght)
-{
- uint i,found,bits_packed,first,last;
- my_off_t bytes_packed;
- HUFF_ELEMENT element_buffer[256];
- DBUG_ENTER("calc_packed_length");
-
- first=last=0;
- for (i=found=0 ; i < 256 ; i++)
- {
- if (huff_counts->counts[i])
- {
- if (! found++)
- first=i;
- last=i;
- queue.root[found]=(byte*) &huff_counts->counts[i];
- }
- }
- if (!found)
- DBUG_RETURN(0); /* Empty tree */
- if (found < 2)
- queue.root[++found]=(byte*) &huff_counts->counts[last ? 0 : 1];
-
- queue.elements=found;
-
- bytes_packed=0; bits_packed=0;
- 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;
- for (i=(found+1)/2 ; i > 0 ; i--)
- _downheap(&queue,i);
- for (i=0 ; i < found-1 ; i++)
- {
- HUFF_ELEMENT *a,*b,*new;
- a=(HUFF_ELEMENT*) queue_remove(&queue,0);
- b=(HUFF_ELEMENT*) queue.root[1];
- new=element_buffer+i;
- new->count=a->count+b->count;
- bits_packed+=(uint) (new->count & 7);
- bytes_packed+=new->count/8;
- queue.root[1]=(byte*) new;
- queue_replaced(&queue);
- }
- DBUG_RETURN(bytes_packed+(bits_packed+7)/8);
-}
-
-
- /* Remove trees that don't give any compression */
-
-static uint join_same_trees(HUFF_COUNTS *huff_counts, uint trees)
-{
- uint k,tree_number;
- HUFF_COUNTS count,*i,*j,*last_count;
-
- last_count=huff_counts+trees;
- for (tree_number=0, i=huff_counts ; i < last_count ; i++)
- {
- if (!i->tree->tree_number)
- {
- i->tree->tree_number= ++tree_number;
- if (i->tree_buff)
- continue; /* Don't join intervall */
- for (j=i+1 ; j < last_count ; j++)
- {
- if (! j->tree->tree_number && ! j->tree_buff)
- {
- for (k=0 ; k < 256 ; k++)
- count.counts[k]=i->counts[k]+j->counts[k];
- if (calc_packed_length(&count,1) <=
- i->tree->bytes_packed + j->tree->bytes_packed+
- i->tree->tree_pack_length+j->tree->tree_pack_length+
- ALLOWED_JOIN_DIFF)
- {
- memcpy((byte*) i->counts,(byte*) count.counts,
- sizeof(count.counts[0])*256);
- my_free((gptr) j->tree->element_buffer,MYF(0));
- j->tree->element_buffer=0;
- j->tree=i->tree;
- bmove((byte*) i->counts,(byte*) count.counts,
- sizeof(count.counts[0])*256);
- if (make_huff_tree(i->tree,i))
- return (uint) -1;
- }
- }
- }
- }
- }
- if (verbose)
- printf("Original trees: %d After join: %d\n",trees,tree_number);
- return tree_number; /* Return trees left */
-}
-
-
- /* Fill in huff_tree decode tables */
-
-static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
-{
- uint elements;
- for ( ; trees-- ; huff_tree++)
- {
- if (huff_tree->tree_number > 0)
- {
- elements=huff_tree->counts->tree_buff ? huff_tree->elements : 256;
- if (!(huff_tree->code =
- (ulong*) my_malloc(elements*
- (sizeof(ulong)+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);
- }
- }
- return 0;
-}
-
-
-static void make_traverse_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
- uint size, ulong 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;
- }
- 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));
- }
- return;
-}
-
-
- /* Write header to new packed data file */
-
-static int write_header(MRG_INFO *mrg,uint head_length,uint trees,
- my_off_t tot_elements,my_off_t filelength)
-{
- byte *buff=file_buffer.pos;
-
- bzero(buff,HEAD_LENGTH);
- memcpy(buff,nisam_pack_file_magic,4);
- int4store(buff+4,head_length);
- int4store(buff+8, mrg->min_pack_length);
- int4store(buff+12,mrg->max_pack_length);
- int4store(buff+16,tot_elements);
- int4store(buff+20,intervall_length);
- int2store(buff+24,trees);
- buff[26]=(char) mrg->ref_length;
- /* Save record pointer length */
- buff[27]= (uchar) (filelength >= (1L << 24) ? 4 :
- filelength >= (1L << 16) ? 3 : 2);
- if (test_only)
- return 0;
- VOID(my_seek(file_buffer.file,0L,MY_SEEK_SET,MYF(0)));
- return my_write(file_buffer.file,file_buffer.pos,HEAD_LENGTH,
- MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
-}
-
- /* Write fieldinfo to new packed file */
-
-static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees)
-{
- reg1 uint i;
- uint huff_tree_bits;
- huff_tree_bits=max_bit(trees ? trees-1 : 0);
-
- for (i=0 ; i++ < fields ; counts++)
- {
- write_bits((ulong) (int) counts->field_type,4);
- write_bits(counts->pack_type,4);
- if (counts->pack_type & PACK_TYPE_ZERO_FILL)
- write_bits(counts->max_zero_fill,4);
- else
- write_bits(counts->length_bits,4);
- write_bits((ulong) counts->tree->tree_number-1,huff_tree_bits);
- }
- flush_bits();
- return;
-}
-
- /* Write all huff_trees to new datafile. Return tot count of
- elements in all trees
- Returns 0 on error */
-
-static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
-{
- uint i,int_length;
- uint *packed_tree,*offset,length;
- my_off_t elements;
-
- for (i=length=0 ; i < trees ; i++)
- if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length)
- length=huff_tree[i].elements;
- if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2)))
- {
- my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2);
- return 0;
- }
-
- intervall_length=0;
- for (elements=0; trees-- ; huff_tree++)
- {
- if (huff_tree->tree_number == 0)
- continue; /* Deleted tree */
- elements+=huff_tree->elements;
- huff_tree->max_offset=2;
- if (huff_tree->elements <= 1)
- offset=packed_tree;
- else
- offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree);
- huff_tree->offset_bits=max_bit(huff_tree->max_offset);
- if (huff_tree->max_offset >= IS_OFFSET)
- { /* This should be impossible */
- VOID(fprintf(stderr,"Tree offset got too big: %d, aborted\n",
- huff_tree->max_offset));
- my_afree((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
- if (!huff_tree->counts->tree_buff)
- {
- write_bits(0,1);
- write_bits(huff_tree->min_chr,8);
- write_bits(huff_tree->elements,9);
- write_bits(huff_tree->char_bits,5);
- write_bits(huff_tree->offset_bits,5);
- int_length=0;
- }
- else
- {
- int_length=(uint) (huff_tree->counts->tree_pos -
- huff_tree->counts->tree_buff);
- write_bits(1,1);
- write_bits(huff_tree->elements,15);
- write_bits(int_length,16);
- write_bits(huff_tree->char_bits,5);
- write_bits(huff_tree->offset_bits,5);
- intervall_length+=int_length;
- }
- 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);
-
- for (i=0 ; i < length ; i++)
- {
- if (packed_tree[i] & IS_OFFSET)
- write_bits(packed_tree[i] - IS_OFFSET+ ((ulong) 1L << huff_tree->offset_bits),
- huff_tree->offset_bits+1);
- else
- write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1);
- }
- flush_bits();
- if (huff_tree->counts->tree_buff)
- {
- for (i=0 ; i < int_length ; i++)
- write_bits((uint) (uchar) huff_tree->counts->tree_buff[i],8);
- }
- flush_bits();
- }
- my_afree((gptr) packed_tree);
- return elements;
-}
-
-
-static uint *make_offset_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
- uint *offset)
-{
- uint *prev_offset;
-
- prev_offset= offset;
- if (!element->a.nod.left->a.leaf.null)
- {
- offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
- offset+=2;
- }
- else
- {
- prev_offset[0]= IS_OFFSET+2;
- offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2);
- }
- if (!element->a.nod.right->a.leaf.null)
- {
- prev_offset[1]=element->a.nod.right->a.leaf.element_nr;
- return offset;
- }
- else
- {
- uint temp=(uint) (offset-prev_offset-1);
- prev_offset[1]= IS_OFFSET+ temp;
- if (huff_tree->max_offset < temp)
- huff_tree->max_offset = temp;
- return make_offset_code_tree(huff_tree,element->a.nod.right,offset);
- }
-}
-
- /* Get number of bits neaded to represent value */
-
-static uint max_bit(register uint value)
-{
- reg2 uint power=1;
-
- while ((value>>=1))
- power++;
- return (power);
-}
-
-
-static int compress_isam_file(MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
-{
- int error;
- uint i,max_calc_length,pack_ref_length,min_record_length,max_record_length,
- intervall,field_length;
- my_off_t record_count,max_allowed_length;
- ulong length;
- byte *record,*pos,*end_pos,*record_pos,*start_pos;
- HUFF_COUNTS *count,*end_count;
- HUFF_TREE *tree;
- N_INFO *isam_file=mrg->file[0];
- DBUG_ENTER("compress_isam_file");
-
- 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;
-
- for (i=max_calc_length=0 ; i < isam_file->s->base.fields ; i++)
- {
- if (!(huff_counts[i].pack_type & PACK_TYPE_ZERO_FILL))
- huff_counts[i].max_zero_fill=0;
- if (huff_counts[i].field_type == FIELD_CONSTANT ||
- huff_counts[i].field_type == FIELD_ZERO)
- continue;
- if (huff_counts[i].field_type == FIELD_INTERVALL)
- max_calc_length+=huff_counts[i].tree->height;
- else
- max_calc_length+=
- (huff_counts[i].field_length - huff_counts[i].max_zero_fill)*
- huff_counts[i].tree->height+huff_counts[i].length_bits;
- }
- max_calc_length/=8;
- if (max_calc_length <= 255)
- pack_ref_length=1;
- else if (max_calc_length <= 65535)
- pack_ref_length=2;
- else
- pack_ref_length=3;
- if (force_pack_ref_length)
- pack_ref_length=force_pack_ref_length;
- max_allowed_length= 1L << (pack_ref_length*8);
- record_count=0;
-
- mrg_reset(mrg);
- while ((error=mrg_rrnd(mrg,record)) >= 0)
- {
- if (! error)
- {
- if (flush_buffer(max_calc_length+pack_ref_length))
- break;
- record_pos=file_buffer.pos;
- file_buffer.pos+=pack_ref_length;
- for (start_pos=record, count= huff_counts; count < end_count ; count++)
- {
- end_pos=start_pos+(field_length=count->field_length);
- tree=count->tree;
-
- if (count->pack_type & PACK_TYPE_SPACE_FIELDS)
- {
- for (pos=start_pos ; *pos == ' ' && pos < end_pos; pos++) ;
- if (pos == end_pos)
- {
- write_bits(1,1);
- start_pos=end_pos;
- continue;
- }
- write_bits(0,1);
- }
-
-#ifdef BYTE_ORDER_HIGH_FIRST
- start_pos+=count->max_zero_fill;
-#else
- end_pos-=count->max_zero_fill;
-#endif
- field_length-=count->max_zero_fill;
-
- switch(count->field_type) {
- case FIELD_SKIP_ZERO:
- if (!memcmp((byte*) start_pos,zero_string,field_length))
- {
- write_bits(1,1);
- start_pos=end_pos;
- break;
- }
- write_bits(0,1);
- /* Fall through */
- case FIELD_NORMAL:
- for ( ; start_pos < end_pos ; 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);
- if (count->pack_type & PACK_TYPE_SELECTED)
- {
- if (length > count->min_space)
- {
- write_bits(1,1);
- write_bits(length,count->length_bits);
- }
- else
- {
- write_bits(0,1);
- pos=end_pos;
- }
- }
- else
- write_bits(length,count->length_bits);
- for ( ; start_pos < pos ; 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);
- if (count->pack_type & PACK_TYPE_SELECTED)
- {
- if (length > count->min_space)
- {
- write_bits(1,1);
- write_bits(length,count->length_bits);
- }
- else
- {
- pos=start_pos;
- write_bits(0,1);
- }
- }
- else
- write_bits(length,count->length_bits);
- for (start_pos=pos ; start_pos < end_pos ; start_pos++)
- write_bits(tree->code[(uchar) *start_pos],
- (uint) tree->code_len[(uchar) *start_pos]);
- break;
- case FIELD_CONSTANT:
- case FIELD_ZERO:
- start_pos=end_pos;
- break;
- case FIELD_INTERVALL:
- global_count=count;
- pos=(byte*) tree_search(&count->int_tree, start_pos,
- count->int_tree.custom_arg);
- intervall=(uint) (pos - count->tree_buff)/field_length;
- write_bits(tree->code[intervall],(uint) tree->code_len[intervall]);
- start_pos=end_pos;
- break;
- case FIELD_BLOB:
- VOID(fprintf(stderr,"Can't pack files with blobs. Aborting\n"));
- DBUG_RETURN(1);
- case FIELD_LAST:
- case FIELD_VARCHAR:
- case FIELD_CHECK:
- abort(); /* Impossible */
- }
-#ifndef BYTE_ORDER_HIGH_FIRST
- start_pos+=count->max_zero_fill;
-#endif
- }
- flush_bits();
- length=(ulong) (file_buffer.pos-record_pos)-pack_ref_length;
- save_integer(record_pos,pack_ref_length,length);
- if (length < (ulong) min_record_length)
- min_record_length=(uint) length;
- if (length > (ulong) max_record_length)
- {
- max_record_length=(uint) length;
- if (max_record_length >= max_allowed_length)
- {
- fprintf(stderr,
- "Error: Found record with packed-length: %d, max is: %lu\n",
- max_record_length, (ulong) max_allowed_length);
- error=1;
- break;
- }
- }
- if (write_loop && ++record_count % WRITE_COUNT == 0)
- {
- printf("%lu\r",(ulong) record_count); VOID(fflush(stdout));
- }
- }
- else if (my_errno != HA_ERR_RECORD_DELETED)
- break;
- }
- if (error < 0)
- {
- error=0;
- if (my_errno != HA_ERR_END_OF_FILE)
- {
- fprintf(stderr,"%s: Got error %d reading records\n",my_progname,my_errno);
- error= 1;
- }
- }
-
- my_afree((gptr) record);
- mrg->ref_length=pack_ref_length;
- mrg->min_pack_length=max_record_length ? min_record_length : 0;
- mrg->max_pack_length=max_record_length;
- if (verbose && max_record_length &&
- max_record_length < max_allowed_length/256)
- printf("Record-length is %d bytes, could have been %d bytes\nYou can change this by using -p=%d next time you pack this file\n",
- pack_ref_length,
- max_record_length/256+1,
- max_record_length/256+1);
- DBUG_RETURN(error || error_on_write || flush_buffer((uint) ~0));
-}
-
-
-static char *make_new_name(char *new_name, char *old_name)
-{
- return fn_format(new_name,old_name,"",DATA_TMP_EXT,2+4);
-}
-
-static char *make_old_name(char *new_name, char *old_name)
-{
- return fn_format(new_name,old_name,"",OLD_EXT,2+4);
-}
-
- /* rutines for bit writing buffer */
-
-static void init_file_buffer(File file, pbool read_buffer)
-{
- file_buffer.file=file;
- file_buffer.buffer=my_malloc(ALIGN_SIZE(RECORD_CACHE_SIZE),MYF(MY_WME));
- file_buffer.end=file_buffer.buffer+ALIGN_SIZE(RECORD_CACHE_SIZE)-4;
- file_buffer.pos_in_file=0;
- error_on_write=0;
- if (read_buffer)
- {
-
- file_buffer.pos=file_buffer.end;
- file_buffer.bits=0;
- }
- else
- {
- file_buffer.pos=file_buffer.buffer;
- file_buffer.bits=BITS_SAVED;
- }
- file_buffer.bytes=0;
-}
-
-
-static int flush_buffer(uint neaded_length)
-{
- uint length;
- if ((uint) (file_buffer.end - file_buffer.pos) > neaded_length)
- return 0;
- length=(uint) (file_buffer.pos-file_buffer.buffer);
- file_buffer.pos=file_buffer.buffer;
- file_buffer.pos_in_file+=length;
- if (test_only)
- return 0;
- return (error_on_write|=test(my_write(file_buffer.file,file_buffer.buffer,
- length,
- MYF(MY_WME | MY_NABP |
- MY_WAIT_IF_FULL))));
-}
-
-static void end_file_buffer(void)
-{
- my_free((gptr) file_buffer.buffer,MYF(0));
-}
-
- /* output `bits` low bits of `value' */
-
-static void write_bits (register ulong value, register uint bits)
-{
- if ((file_buffer.bits-=(int) bits) >= 0)
- {
- file_buffer.bytes|=value << file_buffer.bits;
- }
- else
- {
- reg3 uint byte_buff;
- bits= (uint) -file_buffer.bits;
- byte_buff=file_buffer.bytes | (uint) (value >> bits);
-#if BITS_SAVED == 32
- *file_buffer.pos++= (byte) (byte_buff >> 24) ;
- *file_buffer.pos++= (byte) (byte_buff >> 16) ;
-#endif
- *file_buffer.pos++= (byte) (byte_buff >> 8) ;
- *file_buffer.pos++= (byte) byte_buff;
-
- value&=((ulong) 1L << bits)-1;
-#if BITS_SAVED == 16
- if (bits >= sizeof(uint))
- {
- bits-=8;
- *file_buffer.pos++= (uchar) (value >> bits);
- value&= ((ulong) 1L << bits)-1;
- if (bits >= sizeof(uint))
- {
- bits-=8;
- *file_buffer.pos++= (uchar) (value >> bits);
- value&= ((ulong) 1L << bits)-1;
- }
- }
-#endif
- if (file_buffer.pos >= file_buffer.end)
- VOID(flush_buffer((uint) ~0));
- file_buffer.bits=(int) (BITS_SAVED - bits);
- file_buffer.bytes=(uint) (value << (BITS_SAVED - bits));
- }
- return;
-}
-
- /* Flush bits in bit_buffer to buffer */
-
-static void flush_bits (void)
-{
- uint bits,byte_buff;
-
- bits=(file_buffer.bits) & ~7;
- byte_buff = file_buffer.bytes >> bits;
- bits=BITS_SAVED - bits;
- while (bits > 0)
- {
- bits-=8;
- *file_buffer.pos++= (byte) (uchar) (byte_buff >> bits) ;
- }
- file_buffer.bits=BITS_SAVED;
- file_buffer.bytes=0;
- return;
-}
-
- /* Store long in 1,2,3,4 or 5 bytes */
-
-static void save_integer(byte *pos, uint pack_length, my_off_t value)
-{
- switch (pack_length) {
- case 5: int5store(pos,(ulonglong) value); break;
- default: int4store(pos,(ulong) value); break;
- case 3: int3store(pos,(ulong) value); break;
- case 2: int2store(pos,(uint) value); break;
- case 1: pos[0]= (byte) (uchar) value; break;
- }
- return;
-}
-
-
-/****************************************************************************
-** functions to handle the joined files
-****************************************************************************/
-
-static void save_state(N_INFO *isam_file,MRG_INFO *mrg,my_off_t new_length,
- ulong crc)
-{
- ISAM_SHARE *share=isam_file->s;
- uint options=uint2korr(share->state.header.options);
- DBUG_ENTER("save_state");
-
- options|= HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA;
- int2store(share->state.header.options,options);
-
- share->state.data_file_length=(ulong) new_length;
- share->state.del=share->state.empty=0;
- share->state.dellink= (ulong) NI_POS_ERROR;
- share->state.splitt=(ulong) mrg->records;
- share->state.version=(ulong) time((time_t*) 0);
- share->state.keys=0;
- share->state.key_file_length=share->base.keystart;
-
- isam_file->update|=(HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- isam_file->this_uniq=crc; /* Save crc here */
- share->changed=1; /* Force write of header */
- VOID(my_chsize(share->kfile, share->state.key_file_length, 0,
- MYF(0)));
- if (share->state.keys != share->base.keys)
- isamchk_neaded=1;
- DBUG_VOID_RETURN;
-}
-
-
-static int save_state_mrg(File file,MRG_INFO *mrg,my_off_t new_length,
- ulong crc)
-{
- N_STATE_INFO state;
- N_INFO *isam_file=mrg->file[0];
- uint options;
- DBUG_ENTER("save_state_mrg");
-
- memcpy(&state,&isam_file->s->state,sizeof(state));
- options= (uint2korr(state.header.options) | HA_OPTION_COMPRESS_RECORD |
- HA_OPTION_READ_ONLY_DATA);
- int2store(state.header.options,options);
- state.data_file_length=(ulong) new_length;
- state.del=state.empty=0;
- state.dellink= (ulong) NI_POS_ERROR;
- state.records=state.splitt=(ulong) mrg->records;
- state.version=(ulong) time((time_t*) 0);
- state.keys=0;
- state.key_file_length=isam_file->s->base.keystart;
- state.uniq=crc;
- if (state.keys != isam_file->s->base.keys)
- isamchk_neaded=1;
- DBUG_RETURN (my_pwrite(file,(char*) &state.header,
- isam_file->s->state_length,0L,
- MYF(MY_NABP | MY_WME)) != 0);
-}
-
-
-/* reset for mrg_rrnd */
-
-static void mrg_reset(MRG_INFO *mrg)
-{
- if (mrg->current)
- {
- nisam_extra(*mrg->current,HA_EXTRA_NO_CACHE);
- mrg->current=0;
- }
-}
-
-static int mrg_rrnd(MRG_INFO *info,byte *buf)
-{
- int error;
- N_INFO *isam_info;
- my_off_t filepos;
-
- if (!info->current)
- {
- isam_info= *(info->current=info->file);
- info->end=info->current+info->count;
- nisam_extra(isam_info,HA_EXTRA_RESET);
- nisam_extra(isam_info,HA_EXTRA_CACHE);
- filepos=isam_info->s->pack.header_length;
- }
- else
- {
- isam_info= *info->current;
- filepos= isam_info->nextpos;
- }
-
- for (;;)
- {
- isam_info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- if ((error=(*isam_info->s->read_rnd)(isam_info,(byte*) buf,
- (ulong) filepos, 1)) >= 0 ||
- my_errno != HA_ERR_END_OF_FILE)
- return (error);
- nisam_extra(isam_info,HA_EXTRA_NO_CACHE);
- if (info->current+1 == info->end)
- return(-1);
- info->current++;
- isam_info= *info->current;
- filepos=isam_info->s->pack.header_length;
- nisam_extra(isam_info,HA_EXTRA_RESET);
- nisam_extra(isam_info,HA_EXTRA_CACHE);
- }
-}
-
-
-static int mrg_close(MRG_INFO *mrg)
-{
- uint i;
- int error=0;
- for (i=0 ; i < mrg->count ; i++)
- error|=nisam_close(mrg->file[i]);
- return error;
-}
diff --git a/isam/panic.c b/isam/panic.c
deleted file mode 100644
index 7af979a5104..00000000000
--- a/isam/panic.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include "isamdef.h"
-
- /* if flag == HA_PANIC_CLOSE then all misam files are closed */
- /* if flag == HA_PANIC_WRITE then all misam files are unlocked and
- all changed data in single user misam is written to file */
- /* if flag == HA_PANIC_READ then all misam files that was locked when
- nisam_panic(HA_PANIC_WRITE) was done is locked. A ni_readinfo() is
- done for all single user files to get changes in database */
-
-
-int nisam_panic(enum ha_panic_function flag)
-{
- int error=0;
- LIST *list_element,*next_open;
- N_INFO *info;
- DBUG_ENTER("nisam_panic");
-
- pthread_mutex_lock(&THR_LOCK_isam);
- for (list_element=nisam_open_list ; list_element ; list_element=next_open)
- {
- next_open=list_element->next; /* Save if close */
- info=(N_INFO*) list_element->data;
- switch (flag) {
- case HA_PANIC_CLOSE:
- pthread_mutex_unlock(&THR_LOCK_isam); /* Not exactly right... */
- if (nisam_close(info))
- error=my_errno;
- pthread_mutex_lock(&THR_LOCK_isam);
- break;
- case HA_PANIC_WRITE: /* Do this to free databases */
-#ifdef CANT_OPEN_FILES_TWICE
- if (info->s->base.options & HA_OPTION_READ_ONLY_DATA)
- break;
-#endif
- if (flush_key_blocks(dflt_key_cache,info->s->kfile,FLUSH_RELEASE))
- error=my_errno;
- if (info->opt_flag & WRITE_CACHE_USED)
- if (flush_io_cache(&info->rec_cache))
- error=my_errno;
- if (info->opt_flag & READ_CACHE_USED)
- {
- if (flush_io_cache(&info->rec_cache))
- error=my_errno;
- reinit_io_cache(&info->rec_cache,READ_CACHE,0,
- (pbool) (info->lock_type != F_UNLCK),1);
- }
-#ifndef NO_LOCKING
- if (info->lock_type != F_UNLCK && ! info->was_locked)
- {
- info->was_locked=info->lock_type;
- if (nisam_lock_database(info,F_UNLCK))
- error=my_errno;
- }
-#else
- {
- int save_status=info->s->w_locks; /* Only w_locks! */
- info->s->w_locks=0;
- if (_nisam_writeinfo(info, test(info->update & HA_STATE_CHANGED)))
- error=my_errno;
- info->s->w_locks=save_status;
- info->update&= ~HA_STATE_CHANGED; /* Not changed */
- }
-#endif /* NO_LOCKING */
-#ifdef CANT_OPEN_FILES_TWICE
- if (info->s->kfile >= 0 && my_close(info->s->kfile,MYF(0)))
- error = my_errno;
- if (info->dfile >= 0 && my_close(info->dfile,MYF(0)))
- error = my_errno;
- info->s->kfile=info->dfile= -1; /* Files aren't open anymore */
- break;
-#endif
- case HA_PANIC_READ: /* Restore to before WRITE */
-#ifdef CANT_OPEN_FILES_TWICE
- { /* Open closed files */
- char name_buff[FN_REFLEN];
- if (info->s->kfile < 0)
- if ((info->s->kfile= my_open(fn_format(name_buff,info->filename,"",
- N_NAME_IEXT,4),info->mode,
- MYF(MY_WME))) < 0)
- error = my_errno;
- if (info->dfile < 0)
- {
- if ((info->dfile= my_open(fn_format(name_buff,info->filename,"",
- N_NAME_DEXT,4),info->mode,
- MYF(MY_WME))) < 0)
- error = my_errno;
- info->rec_cache.file=info->dfile;
- }
- }
-#endif
-#ifndef NO_LOCKING
- if (info->was_locked)
- {
- if (nisam_lock_database(info, info->was_locked))
- error=my_errno;
- info->was_locked=0;
- }
-#else
- {
- int lock_type,w_locks;
- lock_type=info->lock_type ; w_locks=info->s->w_locks;
- info->lock_type=0; info->s->w_locks=0;
- if (_nisam_readinfo(info,0,1)) /* Read changed data */
- error=my_errno;
- info->lock_type=lock_type; info->s->w_locks=w_locks;
- }
- /* Don't use buffer when doing next */
- info->update|=HA_STATE_WRITTEN;
-#endif /* NO_LOCKING */
- break;
- }
- }
- if (flag == HA_PANIC_CLOSE)
- VOID(nisam_log(0)); /* Close log if neaded */
- pthread_mutex_unlock(&THR_LOCK_isam);
- if (!error) DBUG_RETURN(0);
- my_errno=error;
- DBUG_RETURN(-1);
-} /* nisam_panic */
diff --git a/isam/range.c b/isam/range.c
deleted file mode 100644
index 3b79b6d93a9..00000000000
--- a/isam/range.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Gives a approximated number of how many records there is between two keys.
- Used when optimizing querries.
- */
-
-#include "isamdef.h"
-
-static ulong _nisam_record_pos(N_INFO *info,const byte *key,uint key_len,
- enum ha_rkey_function search_flag);
-static double _nisam_search_pos(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
- uint key_len,uint nextflag,ulong pos);
-static uint _nisam_keynr(N_INFO *info,N_KEYDEF *keyinfo,uchar *page,
- uchar *keypos,uint *ret_max_key);
-
-
- /* If start_key = 0 assume read from start */
- /* If end_key = 0 assume read to end */
- /* Returns NI_POS_ERROR on error */
-
-ulong nisam_records_in_range(N_INFO *info, int inx, const byte *start_key,
- uint start_key_len,
- enum ha_rkey_function start_search_flag,
- const byte *end_key, uint end_key_len,
- enum ha_rkey_function end_search_flag)
-{
- ulong start_pos,end_pos;
- DBUG_ENTER("nisam_records_in_range");
-
- if ((inx = _nisam_check_index(info,inx)) < 0)
- DBUG_RETURN(NI_POS_ERROR);
-
-#ifndef NO_LOCKING
- if (_nisam_readinfo(info,F_RDLCK,1))
- DBUG_RETURN(NI_POS_ERROR);
-#endif
- info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- start_pos= (start_key ?
- _nisam_record_pos(info,start_key,start_key_len,start_search_flag) :
- 0L);
- end_pos= (end_key ?
- _nisam_record_pos(info,end_key,end_key_len,end_search_flag) :
- info->s->state.records+1L);
- VOID(_nisam_writeinfo(info,0));
- if (start_pos == NI_POS_ERROR || end_pos == NI_POS_ERROR)
- DBUG_RETURN(NI_POS_ERROR);
- DBUG_PRINT("info",("records: %ld",end_pos-start_pos));
- DBUG_RETURN(end_pos < start_pos ? 0L :
- (end_pos == start_pos ? 1L : end_pos-start_pos));
-}
-
-
- /* Find relative position (in records) for key in index-tree */
-
-static ulong _nisam_record_pos(N_INFO *info, const byte *key, uint key_len,
- enum ha_rkey_function search_flag)
-{
- uint inx=(uint) info->lastinx;
- N_KEYDEF *keyinfo=info->s->keyinfo+inx;
- uchar *key_buff;
- double pos;
-
- DBUG_ENTER("_nisam_record_pos");
- DBUG_PRINT("enter",("search_flag: %d",search_flag));
-
- if (key_len >= (keyinfo->base.keylength-info->s->rec_reflength)
- && !(keyinfo->base.flag & HA_SPACE_PACK_USED))
- key_len=USE_HOLE_KEY;
- key_buff=info->lastkey+info->s->base.max_key_length;
- key_len=_nisam_pack_key(info,inx,key_buff,(uchar*) key,key_len);
- DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,keyinfo->seg,
- (uchar*) key_buff););
- pos=_nisam_search_pos(info,keyinfo,key_buff,key_len,
- nisam_read_vec[search_flag] | SEARCH_SAVE_BUFF,
- info->s->state.key_root[inx]);
- if (pos >= 0.0)
- {
- DBUG_PRINT("exit",("pos: %ld",(ulong) (pos*info->s->state.records)));
- DBUG_RETURN((ulong) (pos*info->s->state.records+0.5));
- }
- DBUG_RETURN(NI_POS_ERROR);
-}
-
-
- /* This is a modified version of _nisam_search */
- /* Returns offset for key in indextable (decimal 0.0 <= x <= 1.0) */
-
-static double _nisam_search_pos(register N_INFO *info, register N_KEYDEF *keyinfo,
- uchar *key, uint key_len, uint nextflag,
- register ulong pos)
-{
- int flag;
- uint nod_flag,keynr,max_keynr;
- uchar *keypos,*buff;
- double offset;
- DBUG_ENTER("_nisam_search_pos");
-
- if (pos == NI_POS_ERROR)
- DBUG_RETURN(0.5);
-
- if (!(buff=_nisam_fetch_keypage(info,keyinfo,pos,info->buff,1)))
- goto err;
- flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
- &keypos,info->lastkey);
- nod_flag=test_if_nod(buff);
- keynr=_nisam_keynr(info,keyinfo,buff,keypos,&max_keynr);
-
- if (flag)
- {
- /*
- ** Didn't found match. keypos points at next (bigger) key
- * Try to find a smaller, better matching key.
- ** Matches keynr + [0-1]
- */
- if ((offset=_nisam_search_pos(info,keyinfo,key,key_len,nextflag,
- _nisam_kpos(nod_flag,keypos))) < 0)
- DBUG_RETURN(offset);
- }
- else
- {
- /*
- ** Found match. Keypos points at the start of the found key
- ** Matches keynr+1
- */
- offset=1.0; /* Matches keynr+1 */
- if (nextflag & SEARCH_FIND && (!(keyinfo->base.flag & HA_NOSAME)
- || key_len) && nod_flag)
- {
- /*
- ** There may be identical keys in the tree. Try to match on of those.
- ** Matches keynr + [0-1]
- */
- if ((offset=_nisam_search_pos(info,keyinfo,key,key_len,SEARCH_FIND,
- _nisam_kpos(nod_flag,keypos))) < 0)
- DBUG_RETURN(offset); /* Read error */
- }
- }
- DBUG_PRINT("info",("keynr: %d offset: %g max_keynr: %d nod: %d flag: %d",
- keynr,offset,max_keynr,nod_flag,flag));
- DBUG_RETURN((keynr+offset)/(max_keynr+1));
-err:
- DBUG_PRINT("exit",("Error: %d",my_errno));
- DBUG_RETURN (-1.0);
-}
-
-
- /* Get keynummer of current key and max number of keys in nod */
-
-static uint _nisam_keynr(N_INFO *info, register N_KEYDEF *keyinfo, uchar *page, uchar *keypos, uint *ret_max_key)
-{
- uint nod_flag,keynr,max_key;
- uchar t_buff[N_MAX_KEY_BUFF],*end;
-
- end= page+getint(page);
- nod_flag=test_if_nod(page);
- page+=2+nod_flag;
-
- if (!(keyinfo->base.flag &
- (HA_PACK_KEY | HA_SPACE_PACK | HA_SPACE_PACK_USED)))
- {
- *ret_max_key= (uint) (end-page)/(keyinfo->base.keylength+nod_flag);
- return (uint) (keypos-page)/(keyinfo->base.keylength+nod_flag);
- }
-
- max_key=keynr=0;
- while (page < end)
- {
- t_buff[0]=0; /* Don't move packed key */
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff));
- max_key++;
- if (page == keypos)
- keynr=max_key;
- }
- *ret_max_key=max_key;
- return(keynr);
-}
diff --git a/isam/rfirst.c b/isam/rfirst.c
deleted file mode 100644
index cc1cbee92bf..00000000000
--- a/isam/rfirst.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* L{ser f|rsta posten som har samma isam-nyckel */
-
-#include "isamdef.h"
-
- /*
- L{ser f|rsta posten med samma isamnyckel som f|reg}ende l{sning.
- Man kan ha gjort write, update eller delete p} f|reg}ende post.
- OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
- posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
- */
-
-int nisam_rfirst(N_INFO *info, byte *buf, int inx)
-{
- DBUG_ENTER("nisam_rfirst");
- info->lastpos= NI_POS_ERROR;
- info->update|= HA_STATE_PREV_FOUND;
- DBUG_RETURN(nisam_rnext(info,buf,inx));
-} /* nisam_rfirst */
diff --git a/isam/rkey.c b/isam/rkey.c
deleted file mode 100644
index bbe4576418b..00000000000
--- a/isam/rkey.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* L{ser p} basen av en isam_nyckel */
-
-#include "isamdef.h"
-
-
- /* Read a record using key */
- /* Ordinary search_flag is 0 ; Give error if no record with key */
-
-int nisam_rkey(N_INFO *info, byte *buf, int inx, const byte *key, uint key_len, enum ha_rkey_function search_flag)
-{
- uchar *key_buff;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("nisam_rkey");
- DBUG_PRINT("enter",("base: %lx inx: %d search_flag: %d",
- info,inx,search_flag));
-
- if ((inx = _nisam_check_index(info,inx)) < 0)
- DBUG_RETURN(-1);
- info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- if (key_len >= (share->keyinfo[inx].base.keylength - share->rec_reflength)
- && !(info->s->keyinfo[inx].base.flag & HA_SPACE_PACK_USED))
- key_len=USE_HOLE_KEY;
- key_buff=info->lastkey+info->s->base.max_key_length;
- key_len=_nisam_pack_key(info,(uint) inx,key_buff,(uchar*) key,key_len);
- DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,share->keyinfo[inx].seg,
- (uchar*) key););
-
-#ifndef NO_LOCKING
- if (_nisam_readinfo(info,F_RDLCK,1))
- goto err;
-#endif
-
- VOID(_nisam_search(info,info->s->keyinfo+inx,key_buff,key_len,
- nisam_read_vec[search_flag],info->s->state.key_root[inx]));
- if ((*info->read_record)(info,info->lastpos,buf) >= 0)
- {
- info->update|= HA_STATE_AKTIV; /* Record is read */
- DBUG_RETURN(0);
- }
-
- info->lastpos = NI_POS_ERROR; /* Didn't find key */
- VOID(_nisam_move_key(info->s->keyinfo+inx,info->lastkey,key_buff));
- if (search_flag == HA_READ_AFTER_KEY)
- info->update|=HA_STATE_NEXT_FOUND; /* Previous gives last row */
-err:
- DBUG_RETURN(-1);
-} /* nisam_rkey */
diff --git a/isam/rlast.c b/isam/rlast.c
deleted file mode 100644
index a91f1f1011b..00000000000
--- a/isam/rlast.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* L{ser sista posten som har samma isam-nyckel */
-
-#include "isamdef.h"
-
- /*
- L{ser sista posten med samma isamnyckel som f|reg}ende l{sning.
- Man kan ha gjort write, update eller delete p} f|reg}ende post.
- OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
- posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
- */
-
-int nisam_rlast(N_INFO *info, byte *buf, int inx)
-{
- DBUG_ENTER("nisam_rlast");
- info->lastpos= NI_POS_ERROR;
- info->update|= HA_STATE_NEXT_FOUND;
- DBUG_RETURN(nisam_rprev(info,buf,inx));
-} /* nisam_rlast */
diff --git a/isam/rnext.c b/isam/rnext.c
deleted file mode 100644
index be26098c901..00000000000
--- a/isam/rnext.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* L{ser n{sta post med samma isam-nyckel */
-
-#include "isamdef.h"
-
- /*
- L{ser n{sta post med samma isamnyckel som f|reg}ende l{sning.
- Man kan ha gjort write, update eller delete p} f|reg}ende post.
- OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
- posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
- */
-
-int nisam_rnext(N_INFO *info, byte *buf, int inx)
-{
- int error,changed;
- uint flag;
- DBUG_ENTER("nisam_rnext");
-
- if ((inx = _nisam_check_index(info,inx)) < 0)
- DBUG_RETURN(-1);
- flag=SEARCH_BIGGER; /* Read next */
- if (info->lastpos == NI_POS_ERROR && info->update & HA_STATE_PREV_FOUND)
- flag=0; /* Read first */
-
-#ifndef NO_LOCKING
- if (_nisam_readinfo(info,F_RDLCK,1)) DBUG_RETURN(-1);
-#endif
- changed=_nisam_test_if_changed(info);
- if (!flag)
- error=_nisam_search_first(info,info->s->keyinfo+inx,
- info->s->state.key_root[inx]);
- else if (!changed)
- error=_nisam_search_next(info,info->s->keyinfo+inx,info->lastkey,flag,
- info->s->state.key_root[inx]);
- else
- error=_nisam_search(info,info->s->keyinfo+inx,info->lastkey,0,flag,
- info->s->state.key_root[inx]);
-
- /* Don't clear if database-changed */
- info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED |
- HA_STATE_BUFF_SAVED);
- info->update|= HA_STATE_NEXT_FOUND;
-
- if (error && my_errno == HA_ERR_KEY_NOT_FOUND)
- my_errno=HA_ERR_END_OF_FILE;
- if ((*info->read_record)(info,info->lastpos,buf) >=0)
- {
- info->update|= HA_STATE_AKTIV; /* Record is read */
- DBUG_RETURN(0);
- }
- DBUG_RETURN(-1);
-} /* nisam_rnext */
diff --git a/isam/rprev.c b/isam/rprev.c
deleted file mode 100644
index 0997a04fbbe..00000000000
--- a/isam/rprev.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* L{ser f|reg}ende post med samma isam-nyckel */
-
-#include "isamdef.h"
-
- /*
- L{ser f|reg}ende post med samma isamnyckel som f|reg}ende l{sning.
- Man kan ha gjort write, update eller delete p} f|reg}ende post.
- OBS! [ven om man {ndrade isamnyckeln p} f|reg}ende post l{ses
- posten i avseende p} f|reg}ende isam-nyckel-l{sning !!
- */
-
-int nisam_rprev(N_INFO *info, byte *buf, int inx)
-{
- int error,changed;
- register uint flag;
- DBUG_ENTER("nisam_rprev");
-
- if ((inx = _nisam_check_index(info,inx)) < 0)
- DBUG_RETURN(-1);
- flag=SEARCH_SMALLER; /* Read previous */
- if (info->lastpos == NI_POS_ERROR && info->update & HA_STATE_NEXT_FOUND)
- flag=0; /* Read last */
-
-#ifndef NO_LOCKING
- if (_nisam_readinfo(info,F_RDLCK,1)) DBUG_RETURN(-1);
-#endif
- changed=_nisam_test_if_changed(info);
- if (!flag)
- error=_nisam_search_last(info,info->s->keyinfo+inx,info->s->state.key_root[inx]);
- else if (!changed)
- error=_nisam_search_next(info,info->s->keyinfo+inx,info->lastkey,flag,
- info->s->state.key_root[inx]);
- else
- error=_nisam_search(info,info->s->keyinfo+inx,info->lastkey,0,flag,
- info->s->state.key_root[inx]);
-
- info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED |
- HA_STATE_BUFF_SAVED);
- info->update|= HA_STATE_PREV_FOUND;
- if (error && my_errno == HA_ERR_KEY_NOT_FOUND)
- my_errno=HA_ERR_END_OF_FILE;
- if ((*info->read_record)(info,info->lastpos,buf) >=0)
- {
- info->update|= HA_STATE_AKTIV; /* Record is read */
- DBUG_RETURN(0);
- }
- DBUG_RETURN(-1);
-} /* nisam_rprev */
diff --git a/isam/rrnd.c b/isam/rrnd.c
deleted file mode 100644
index 16b3ab1b859..00000000000
--- a/isam/rrnd.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Read a record with random-access. The position to the record must
- get by N_INFO. The next record can be read with pos= -1 */
-
-
-#include "isamdef.h"
-
-/*
- If filepos == NI_POS_ERROR, read next
- Returns:
- 0 = Ok.
- 1 = Row was deleted
- -1 = EOF (check errno to verify)
-*/
-
-int nisam_rrnd(N_INFO *info, byte *buf, register ulong filepos)
-{
- int skipp_deleted_blocks;
- DBUG_ENTER("nisam_rrnd");
-
- skipp_deleted_blocks=0;
-
- if (filepos == NI_POS_ERROR)
- {
- skipp_deleted_blocks=1;
- if (info->lastpos == NI_POS_ERROR) /* First read ? */
- filepos= info->s->pack.header_length; /* Read first record */
- else
- filepos= info->nextpos;
- }
-
- info->lastinx= -1; /* Can't forward or backward */
- /* Init all but update-flag */
- info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
-
- if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
- DBUG_RETURN(my_errno);
-
- DBUG_RETURN ((*info->s->read_rnd)(info,buf,filepos,skipp_deleted_blocks));
-}
diff --git a/isam/rsame.c b/isam/rsame.c
deleted file mode 100644
index 9a2a03da054..00000000000
--- a/isam/rsame.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* L{ser nuvarande record med direktl{sning */
-/* Klarar b}de poster l{sta med nyckel och rrnd. */
-
-#include "isamdef.h"
-
- /* Funktionen ger som resultat:
- 0 = Ok.
- 1 = Posten borttagen
- -1 = EOF (eller motsvarande: se errno) */
-
-
-int nisam_rsame(N_INFO *info, byte *record, int inx)
-
-
- /* If inx >= 0 find record using key */
-{
- DBUG_ENTER("nisam_rsame");
-
- if (inx >= (int) info->s->state.keys || inx < -1)
- {
- my_errno=HA_ERR_WRONG_INDEX;
- DBUG_RETURN(-1);
- }
- if (info->lastpos == NI_POS_ERROR || info->update & HA_STATE_DELETED)
- {
- my_errno=HA_ERR_KEY_NOT_FOUND; /* No current record */
- DBUG_RETURN(-1);
- }
- info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
-
- /* L{s record fr}n datafilen */
-
-#ifndef NO_LOCKING
- if (_nisam_readinfo(info,F_RDLCK,1))
- DBUG_RETURN(-1);
-#endif
-
- if (inx >= 0)
- {
- info->lastinx=inx;
- VOID(_nisam_make_key(info,(uint) inx,info->lastkey,record,info->lastpos));
- VOID(_nisam_search(info,info->s->keyinfo+inx,info->lastkey,0,SEARCH_SAME,
- info->s->state.key_root[inx]));
- }
-
- if ((*info->read_record)(info,info->lastpos,record) == 0)
- DBUG_RETURN(0);
- if (my_errno == HA_ERR_RECORD_DELETED)
- {
- my_errno=HA_ERR_KEY_NOT_FOUND;
- DBUG_RETURN(1);
- }
- DBUG_RETURN(-1);
-} /* nisam_rsame */
diff --git a/isam/rsamepos.c b/isam/rsamepos.c
deleted file mode 100644
index c64ac492d1a..00000000000
--- a/isam/rsamepos.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* read record through position and fix key-position */
-/* As nisam_rsame but supply a position */
-
-#include "isamdef.h"
-
-
- /*
- ** If inx >= 0 update index pointer
- ** Returns one of the following values:
- ** 0 = Ok.
- ** 1 = Record deleted
- ** -1 = EOF (or something similar. More information in my_errno)
- */
-
-int nisam_rsame_with_pos(N_INFO *info, byte *record, int inx, ulong filepos)
-{
- DBUG_ENTER("nisam_rsame_with_pos");
-
- if (inx >= (int) info->s->state.keys || inx < -1)
- {
- my_errno=HA_ERR_WRONG_INDEX;
- DBUG_RETURN(-1);
- }
-
- info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
- if ((*info->s->read_rnd)(info,record,filepos,0))
- {
- if (my_errno == HA_ERR_RECORD_DELETED)
- {
- my_errno=HA_ERR_KEY_NOT_FOUND;
- DBUG_RETURN(1);
- }
- DBUG_RETURN(-1);
- }
- info->lastpos=filepos;
- info->lastinx=inx;
- if (inx >= 0)
- {
- VOID(_nisam_make_key(info,(uint) inx,info->lastkey,record,info->lastpos));
- info->update|=HA_STATE_KEY_CHANGED; /* Don't use indexposition */
- }
- DBUG_RETURN(0);
-} /* nisam_rsame_pos */
diff --git a/isam/sort.c b/isam/sort.c
deleted file mode 100644
index 5d13f8085d2..00000000000
--- a/isam/sort.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Creates a index for a database by reading keys, sorting them and outputing
- them in sorted order through SORT_INFO functions.
-*/
-
-#include "isamdef.h"
-#if defined(MSDOS) || defined(__WIN__)
-#include <fcntl.h>
-#else
-#include <stddef.h>
-#endif
-#include <queues.h>
-
- /* static variabels */
-
-#define MERGEBUFF 15
-#define MERGEBUFF2 31
-#define MIN_SORT_MEMORY (4096-MALLOC_OVERHEAD)
-#define MYF_RW MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL)
-
-typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
- my_off_t file_pos; /* Position var bufferten finns */
- ulong count; /* Antal nycklar i bufferten */
- uchar *base,*key; /* Pekare inom sort_key - indexdel */
- uint mem_count; /* Antal nycklar kvar i minnet */
- uint max_keys; /* Max keys in buffert */
-} BUFFPEK;
-
-extern void print_error _VARARGS((const char *fmt,...));
-
- /* functions defined in this file */
-
-static ulong NEAR_F find_all_keys(SORT_PARAM *info,uint keys,
- uchar * *sort_keys,
- BUFFPEK *buffpek,int *maxbuffer,
- FILE **tempfile, my_string tempname);
-static int NEAR_F write_keys(SORT_PARAM *info,uchar * *sort_keys,
- uint count, BUFFPEK *buffpek,FILE **tempfile,
- my_string tempname);
-static int NEAR_F write_index(SORT_PARAM *info,uchar * *sort_keys,
- uint count);
-static int NEAR_F merge_many_buff(SORT_PARAM *info,uint keys,
- uchar * *sort_keys,
- BUFFPEK *buffpek,int *maxbuffer,
- FILE * *t_file, my_string tempname);
-static uint NEAR_F read_to_buffer(FILE *fromfile,BUFFPEK *buffpek,
- uint sort_length);
-static int NEAR_F merge_buffers(SORT_PARAM *info,uint keys,FILE *from_file,
- FILE *to_file, uchar * *sort_keys,
- BUFFPEK *lastbuff,BUFFPEK *Fb,
- BUFFPEK *Tb);
-static int NEAR_F merge_index(SORT_PARAM *,uint,uchar **,BUFFPEK *, int,
- FILE *);
-static char **make_char_array(uint fields,uint length,myf my_flag);
-static FILE *opentemp(my_string name);
-static void closetemp(char *name,FILE *stream);
-
-
- /* Creates a index of sorted keys */
- /* Returns 0 if everything went ok */
-
-int _create_index_by_sort(info,no_messages,sortbuff_size)
-SORT_PARAM *info;
-pbool no_messages;
-uint sortbuff_size;
-{
- int error,maxbuffer,skr;
- uint memavl,old_memavl,keys,sort_length;
- BUFFPEK *buffpek;
- char tempname[FN_REFLEN];
- ulong records;
- uchar **sort_keys;
- FILE *tempfile;
- DBUG_ENTER("_create_index_by_sort");
-
- tempfile=0; buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1;
- maxbuffer=1;
-
- memavl=max(sortbuff_size,MIN_SORT_MEMORY);
- records= info->max_records;
- sort_length= info->key_length;
- LINT_INIT(keys);
-
- while (memavl >= MIN_SORT_MEMORY)
- {
- if ((records+1)*(sort_length+sizeof(char*)) < (ulong) memavl)
- keys= records+1;
- else
- do
- {
- skr=maxbuffer;
- if (memavl < sizeof(BUFFPEK)*(uint) maxbuffer ||
- (keys=(memavl-sizeof(BUFFPEK)*(uint) maxbuffer)/
- (sort_length+sizeof(char*))) <= 1)
- {
- print_error("Sortbuffer to small");
- goto err;
- }
- }
- while ((maxbuffer= (int) (records/(keys-1)+1)) != skr);
-
- if ((sort_keys= (uchar **) make_char_array(keys,sort_length,MYF(0))))
- {
- if ((buffpek = (BUFFPEK*) my_malloc((uint) (sizeof(BUFFPEK)*
- (uint) maxbuffer),
- MYF(0))))
- break;
- else
- {
- my_free((gptr) sort_keys,MYF(0));
- sort_keys= 0;
- }
- }
- old_memavl=memavl;
- if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY)
- memavl=MIN_SORT_MEMORY;
- }
- if (memavl < MIN_SORT_MEMORY)
- {
- print_error("Sortbuffer to small");
- goto err;
- }
- (*info->lock_in_memory)(); /* Everything is allocated */
-
- if (!no_messages)
- printf(" - Searching for keys, allocating buffer for %d keys\n",keys);
-
- if ((records=find_all_keys(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile,
- tempname))
- == (ulong) -1)
- goto err;
- if (maxbuffer == 0)
- {
- if (!no_messages)
- printf(" - Dumping %lu keys\n",records);
- if (write_index(info,sort_keys,(uint) records))
- goto err;
- }
- else
- {
- keys=(keys*(sort_length+sizeof(char*)))/sort_length;
- if (maxbuffer >= MERGEBUFF2)
- {
- if (!no_messages)
- printf(" - Merging %lu keys\n",records);
- if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile,
- tempname))
- goto err;
- }
- if (!no_messages)
- puts(" - Last merge and dumping keys");
- if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,tempfile))
- goto err;
- }
- error =0;
-
-err:
- if (sort_keys)
- my_free((gptr) sort_keys,MYF(0));
- if (buffpek)
- my_free((gptr) buffpek,MYF(0));
- if (tempfile)
- closetemp(tempname,tempfile);
-
- DBUG_RETURN(error ? -1 : 0);
-} /* _create_index_by_sort */
-
-
- /* Search after all keys and place them in a temp. file */
-
-static ulong NEAR_F find_all_keys(info,keys,sort_keys,buffpek,maxbuffer,
- tempfile,tempname)
-SORT_PARAM *info;
-uint keys;
-uchar **sort_keys;
-BUFFPEK *buffpek;
-int *maxbuffer;
-FILE **tempfile;
-my_string tempname;
-{
- int error;
- uint index,indexpos;
- DBUG_ENTER("find_all_keys");
-
- index=indexpos=error=0;
-
- while (!(error=(*info->key_read)(sort_keys[index])))
- {
- if ((uint) ++index == keys)
- {
- if (indexpos >= (uint) *maxbuffer ||
- write_keys(info,sort_keys,index-1,buffpek+indexpos,tempfile,
- tempname))
- DBUG_RETURN(NI_POS_ERROR);
- memcpy(sort_keys[0],sort_keys[index-1],(size_t) info->key_length);
- index=1; indexpos++;
- }
- }
- if (error > 0)
- DBUG_RETURN(NI_POS_ERROR); /* Aborted by get_key */
- if (indexpos)
- if (indexpos >= (uint) *maxbuffer ||
- write_keys(info,sort_keys,index,buffpek+indexpos,tempfile,tempname))
- DBUG_RETURN(NI_POS_ERROR);
- *maxbuffer=(int) indexpos;
- DBUG_RETURN(indexpos*(keys-1)+index);
-} /* find_all_keys */
-
-
- /* Write all keys in memory to file for later merge */
-
-static int NEAR_F write_keys(info,sort_keys,count,buffpek,tempfile,tempname)
-SORT_PARAM *info;
-reg1 uchar **sort_keys;
-uint count;
-BUFFPEK *buffpek;
-reg2 FILE **tempfile;
-my_string tempname;
-{
- DBUG_ENTER("write_keys");
-
- qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
- NullS);
- if (! *tempfile && ! (*tempfile=opentemp(tempname)))
- DBUG_RETURN(1);
- buffpek->file_pos=my_ftell(*tempfile,MYF(0));
- buffpek->count=count;
- while (count--)
- if (my_fwrite(*tempfile,(byte*)*sort_keys++,info->key_length,MYF_RW))
- DBUG_RETURN(1);
- DBUG_RETURN(0);
-} /* write_keys */
-
-
- /* Write index */
-
-static int NEAR_F write_index(info,sort_keys,count)
-SORT_PARAM *info;
-reg1 uchar **sort_keys;
-reg2 uint count;
-{
- DBUG_ENTER("write_index");
-
- qsort2((gptr) sort_keys,(size_t) count,sizeof(byte*),
- (qsort2_cmp) info->key_cmp, NullS);
- while (count--)
- if ((*info->key_write)(*sort_keys++))
- DBUG_RETURN(-1);
- DBUG_RETURN(0);
-} /* write_index */
-
-
- /* Merge buffers to make < MERGEBUFF2 buffers */
-
-static int NEAR_F merge_many_buff(info,keys,sort_keys,buffpek,maxbuffer,t_file,
- t_name)
-SORT_PARAM *info;
-uint keys;
-uchar **sort_keys;
-int *maxbuffer;
-BUFFPEK *buffpek;
-FILE **t_file;
-my_string t_name;
-{
- register int i;
- FILE *from_file,*to_file,*temp;
- FILE *t_file2;
- char t_name2[FN_REFLEN];
- BUFFPEK *lastbuff;
- DBUG_ENTER("merge_many_buff");
-
- if (!(t_file2=opentemp(t_name2)))
- DBUG_RETURN(1);
-
- from_file= *t_file ; to_file= t_file2;
- while (*maxbuffer >= MERGEBUFF2)
- {
- lastbuff=buffpek;
- for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
- {
- if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++,
- buffpek+i,buffpek+i+MERGEBUFF-1))
- break;
- }
- if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++,
- buffpek+i,buffpek+ *maxbuffer))
- break;
- *maxbuffer= (int) (lastbuff-buffpek)-1;
- temp=from_file; from_file=to_file; to_file=temp;
- VOID(my_fseek(to_file,0L,MY_SEEK_SET,MYF(0)));
- }
- if (to_file == *t_file)
- {
- closetemp(t_name,to_file);
- *t_file=t_file2;
- VOID(strmov(t_name,t_name2));
- }
- else closetemp(t_name2,to_file);
-
- DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
-} /* merge_many_buff */
-
-
- /* Read data to buffer */
- /* This returns (uint) -1 if something goes wrong */
-
-static uint NEAR_F read_to_buffer(fromfile,buffpek,sort_length)
-FILE *fromfile;
-BUFFPEK *buffpek;
-uint sort_length;
-{
- register uint count;
- uint length;
-
- if ((count=(uint) min((ulong) buffpek->max_keys,buffpek->count)))
- {
- VOID(my_fseek(fromfile,buffpek->file_pos,MY_SEEK_SET,MYF(0)));
- if (my_fread(fromfile,(byte*) buffpek->base,
- (length= sort_length*count),MYF_RW))
- return((uint) -1);
- buffpek->key=buffpek->base;
- buffpek->file_pos+= length; /* New filepos */
- buffpek->count-= count;
- buffpek->mem_count= count;
- }
- return (count*sort_length);
-} /* read_to_buffer */
-
-
- /* Merge buffers to one buffer */
- /* If to_file == 0 then use info->key_write */
-
-static int NEAR_F merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff,
- Fb,Tb)
-SORT_PARAM *info;
-uint keys;
-FILE *from_file,*to_file;
-uchar **sort_keys;
-BUFFPEK *lastbuff,*Fb,*Tb;
-{
- int error;
- uint sort_length,maxcount;
- ulong count;
- my_off_t to_start_filepos;
- uchar *strpos;
- BUFFPEK *buffpek,**refpek;
- QUEUE queue;
- DBUG_ENTER("merge_buffers");
-
- count=error=0;
- maxcount=keys/((uint) (Tb-Fb) +1);
- sort_length=info->key_length;
-
- LINT_INIT(to_start_filepos);
- if (to_file)
- to_start_filepos=my_ftell(to_file,MYF(0));
- strpos=(uchar*) sort_keys;
-
- if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
- (int (*)(void *, byte *,byte *)) info->key_cmp,0))
- DBUG_RETURN(1);
-
- for (buffpek= Fb ; buffpek <= Tb && error != -1 ; buffpek++)
- {
- count+= buffpek->count;
- buffpek->base= strpos;
- buffpek->max_keys=maxcount;
- strpos+= (uint) (error=(int) read_to_buffer(from_file,buffpek,
- sort_length));
- queue_insert(&queue,(void*) buffpek);
- }
- if (error == -1)
- goto err;
-
- while (queue.elements > 1)
- {
- for (;;)
- {
- buffpek=(BUFFPEK*) queue_top(&queue);
- if (to_file)
- {
- if (my_fwrite(to_file,(byte*) buffpek->key,(uint) sort_length,
- MYF_RW | MY_WAIT_IF_FULL))
- {
- error=1; goto err;
- }
- }
- else
- {
- if ((*info->key_write)((void*) buffpek->key))
- {
- error=1; goto err;
- }
- }
- buffpek->key+=sort_length;
- if (! --buffpek->mem_count)
- {
- if (!(error=(int) read_to_buffer(from_file,buffpek,sort_length)))
- {
- uchar *base=buffpek->base;
- uint max_keys=buffpek->max_keys;
-
- VOID(queue_remove(&queue,0));
-
- /* Put room used by buffer to use in other buffer */
- for (refpek= (BUFFPEK**) &queue_top(&queue);
- refpek <= (BUFFPEK**) &queue_end(&queue);
- refpek++)
- {
- buffpek= *refpek;
- if (buffpek->base+buffpek->max_keys*sort_length == base)
- {
- buffpek->max_keys+=max_keys;
- break;
- }
- else if (base+max_keys*sort_length == buffpek->base)
- {
- buffpek->base=base;
- buffpek->max_keys+=max_keys;
- break;
- }
- }
- break; /* One buffer have been removed */
- }
- }
- queue_replaced(&queue); /* Top element has been replaced */
- }
- }
- buffpek=(BUFFPEK*) queue_top(&queue);
- buffpek->base=(uchar *) sort_keys;
- buffpek->max_keys=keys;
- do
- {
- if (to_file)
- {
- if (my_fwrite(to_file,(byte*) buffpek->key,
- (uint) (sort_length*buffpek->mem_count),
- MYF_RW | MY_WAIT_IF_FULL))
- {
- error=1; goto err;
- }
- }
- else
- {
- register uchar *end;
- strpos= buffpek->key;
- for (end=strpos+buffpek->mem_count*sort_length;
- strpos != end ;
- strpos+=sort_length)
- {
- if ((*info->key_write)((void*) strpos))
- {
- error=1; goto err;
- }
- }
- }
- }
- while ((error=(int) read_to_buffer(from_file,buffpek,sort_length)) != -1 &&
- error != 0);
-
- lastbuff->count=count;
- if (to_file)
- lastbuff->file_pos=to_start_filepos; /* New block starts here */
-err:
- delete_queue(&queue);
- DBUG_RETURN(error);
-} /* merge_buffers */
-
-
- /* Do a merge to output-file (save only positions) */
-
-static int NEAR_F merge_index(info,keys,sort_keys,buffpek,maxbuffer,tempfile)
-SORT_PARAM *info;
-uint keys;
-uchar **sort_keys;
-BUFFPEK *buffpek;
-int maxbuffer;
-FILE *tempfile;
-{
- DBUG_ENTER("merge_index");
- if (merge_buffers(info,keys,tempfile,(FILE*) 0,sort_keys,buffpek,buffpek,
- buffpek+maxbuffer))
- DBUG_RETURN(1);
- DBUG_RETURN(0);
-} /* merge_index */
-
-
- /* Make a pointer of arrays to keys */
-
-static char **make_char_array(fields,length,my_flag)
-register uint fields;
-uint length;
-myf my_flag;
-{
- register char **pos;
- char **old_pos,*char_pos;
- DBUG_ENTER("make_char_array");
-
- if ((old_pos= (char**) my_malloc( fields*(length+sizeof(char*)), my_flag)))
- {
- pos=old_pos; char_pos=((char*) (pos+fields)) -length;
- while (fields--)
- *(pos++) = (char_pos+= length);
- }
-
- DBUG_RETURN(old_pos);
-} /* make_char_array */
-
-
- /* |ppnar en tempor{rfil som kommer att raderas efter anv{nding */
-
-static FILE *opentemp(name)
-my_string name;
-{
- FILE *stream;
- reg1 my_string str_pos;
- DBUG_ENTER("opentemp");
-
- if (!(str_pos=my_tempnam(NullS,"ST",MYF(MY_WME))))
- DBUG_RETURN(0);
- VOID(strmov(name,str_pos));
- (*free)(str_pos); /* Inte via vanliga malloc */
-
- stream=my_fopen(name,(int) (O_RDWR | FILE_BINARY | O_CREAT | O_TEMPORARY),
- MYF(MY_WME));
-#if O_TEMPORARY == 0 && !defined(CANT_DELETE_OPEN_FILES)
- VOID(my_delete(name,MYF(MY_WME | ME_NOINPUT)));
-#endif
- DBUG_PRINT("exit",("stream: %lx",stream));
- DBUG_RETURN (stream);
-} /* opentemp */
-
-
-static void closetemp(char *name __attribute__((unused)) ,FILE *stream)
-{
- DBUG_ENTER("closetemp");
-
- if (stream)
- VOID(my_fclose(stream,MYF(MY_WME)));
-#ifdef CANT_DELETE_OPEN_FILES
- if (name)
- VOID(my_delete(name,MYF(MY_WME)));
-#endif
- DBUG_VOID_RETURN;
-} /* closetemp */
diff --git a/isam/static.c b/isam/static.c
deleted file mode 100644
index 0a8dc809ad7..00000000000
--- a/isam/static.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Static variables for ISAM library. All definied here for easy making of
- a shared library
-*/
-
-#ifndef _global_h
-#include "isamdef.h"
-#endif
-
-LIST *nisam_open_list=0;
-uchar NEAR nisam_file_magic[]=
-{ (uchar) 254, (uchar) 254,'\005', '\002', };
-uchar NEAR nisam_pack_file_magic[]=
-{ (uchar) 254, (uchar) 254,'\006', '\001', };
-my_string nisam_log_filename= (char*) "isam.log";
-File nisam_log_file= -1;
-uint nisam_quick_table_bits=9;
-uint nisam_block_size=1024; /* Best by test */
-my_bool nisam_flush=0;
-
-/* read_vec[] is used for converting between P_READ_KEY.. and SEARCH_ */
-/* Position is , == , >= , <= , > , < */
-
-uint NEAR nisam_read_vec[]=
-{
- SEARCH_FIND, SEARCH_FIND | SEARCH_BIGGER, SEARCH_FIND | SEARCH_SMALLER,
- SEARCH_NO_FIND | SEARCH_BIGGER, SEARCH_NO_FIND | SEARCH_SMALLER,
- SEARCH_FIND, SEARCH_LAST,SEARCH_LAST | SEARCH_SMALLER
-};
diff --git a/isam/test1.c b/isam/test1.c
deleted file mode 100644
index b9f4d8242c3..00000000000
--- a/isam/test1.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include "isamdef.h"
-
-static void get_options(int argc, char *argv[]);
-
-static int rec_pointer_size=0,verbose=0,remove_ant=0,pack_keys=1,flags[50],
- packed_field=FIELD_SKIP_PRESPACE;
-
-int main(int argc, char *argv[])
-{
- N_INFO *file;
- int i,j,error,deleted,found;
- char record[128],key[32],*filename,read_record[128];
- N_KEYDEF keyinfo[10];
- N_RECINFO recinfo[10];
- MY_INIT(argv[0]);
-
- filename= (char*) "test1";
- my_init();
- get_options(argc,argv);
- keyinfo[0].seg[0].base.type=HA_KEYTYPE_NUM;
- keyinfo[0].seg[0].base.flag=(uint8) (pack_keys ?
- HA_PACK_KEY | HA_SPACE_PACK : 0);
- keyinfo[0].seg[0].base.start=0;
- keyinfo[0].seg[0].base.length=6;
- keyinfo[0].seg[1].base.type=HA_KEYTYPE_END;
- keyinfo[0].base.flag = (uint8) (pack_keys ?
- HA_NOSAME | HA_PACK_KEY : HA_NOSAME);
-
- recinfo[0].base.type=packed_field; recinfo[0].base.length=6;
- recinfo[1].base.type=FIELD_NORMAL; recinfo[1].base.length=24;
- recinfo[2].base.type=FIELD_LAST;
-
- deleted=0;
- bzero((byte*) flags,sizeof(flags));
-
- printf("- Creating isam-file\n");
- if (nisam_create(filename,1,keyinfo,recinfo,
- (ulong) (rec_pointer_size ? (1L << (rec_pointer_size*8))/40 :
- 0),10l,0,0,0L))
- goto err;
- if (!(file=nisam_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
- goto err;
- printf("- Writing key:s\n");
- strmov(record," ..... key"); strappend(record,30,' ');
-
- my_errno=0;
- for (i=49 ; i>=1 ; i-=2 )
- {
- j=i%25 +1;
- sprintf(key,"%6d",j);
- bmove(record,key,6);
- error=nisam_write(file,record);
- flags[j]=1;
- if (verbose || error)
- printf("J= %2d nisam_write: %d errno: %d\n", j,error,my_errno);
- }
- if (nisam_close(file)) goto err;
- printf("- Reopening file\n");
- if (!(file=nisam_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) goto err;
- printf("- Removing keys\n");
- for (i=1 ; i<=10 ; i++)
- {
- if (i == remove_ant) { VOID(nisam_close(file)) ; exit(0) ; }
- sprintf(key,"%6d",(j=(int) ((rand() & 32767)/32767.*25)));
- my_errno=0;
- if ((error = nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)))
- {
- if (verbose || (flags[j] == 1 ||
- (error && my_errno != HA_ERR_KEY_NOT_FOUND)))
- printf("key: %s nisam_rkey: %3d errno: %3d\n",key,error,my_errno);
- }
- else
- {
- error=nisam_delete(file,read_record);
- if (verbose || error)
- printf("key: %s nisam_delete: %3d errno: %3d\n",key,error,my_errno);
- flags[j]=0;
- if (! error)
- deleted++;
- }
- }
- printf("- Reading records with key\n");
- for (i=1 ; i<=25 ; i++)
- {
- sprintf(key,"%6d",i);
- bmove(record,key,6);
- my_errno=0;
- error=nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT);
- if (verbose ||
- (error == 0 && flags[i] != 1) ||
- (error && (flags[i] != 0 || my_errno != HA_ERR_KEY_NOT_FOUND)))
- {
- printf("key: %s nisam_rkey: %3d errno: %3d record: %s\n",
- key,error,my_errno,record+1);
- }
- }
-
- printf("- Reading records with position\n");
- for (i=1,found=0 ; i <= 30 ; i++)
- {
- my_errno=0;
- if ((error=nisam_rrnd(file,read_record,i == 1 ? 0L : NI_POS_ERROR)) == -1)
- {
- if (found != 25-deleted)
- printf("Found only %d of %d records\n",found,25-deleted);
- break;
- }
- if (!error)
- found++;
- if (verbose || (error != 0 && error != 1))
- {
- printf("pos: %2d nisam_rrnd: %3d errno: %3d record: %s\n",
- i-1,error,my_errno,read_record+1);
- }
- }
- if (nisam_close(file)) goto err;
- my_end(MY_CHECK_ERROR);
-
- exit(0);
-err:
- printf("got error: %3d when using nisam-database\n",my_errno);
- exit(1);
- return 0; /* skip warning */
-} /* main */
-
-
- /* l{ser optioner */
- /* OBS! intierar endast DEBUG - ingen debuggning h{r ! */
-
-static void get_options(int argc, char *argv[])
-{
- char *pos;
-
- while (--argc >0 && *(pos = *(++argv)) == '-' ) {
- switch(*++pos) {
- case 'R': /* Length of record pointer */
- rec_pointer_size=atoi(++pos);
- if (rec_pointer_size > 3)
- rec_pointer_size=0;
- break;
- case 'P':
- pack_keys=0; /* Don't use packed key */
- break;
- case 'S':
- packed_field=FIELD_NORMAL; /* static-size record*/
- break;
- case 'v': /* verbose */
- verbose=1;
- break;
- case 'm':
- remove_ant=atoi(++pos);
- break;
- case 'V':
- printf("isamtest1 Ver 1.0 \n");
- exit(0);
- case '#':
- DEBUGGER_ON;
- DBUG_PUSH (++pos);
- break;
- }
- }
- return;
-} /* get options */
diff --git a/isam/test2.c b/isam/test2.c
deleted file mode 100644
index 4b22f2d679c..00000000000
--- a/isam/test2.c
+++ /dev/null
@@ -1,841 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Test av isam-databas: stor test */
-
-#ifndef USE_MY_FUNC /* We want to be able to dbug this !! */
-#define USE_MY_FUNC
-#endif
-#ifdef DBUG_OFF
-#undef DBUG_OFF
-#endif
-#ifndef SAFEMALLOC
-#define SAFEMALLOC
-#endif
-
-#include "isamdef.h"
-
-#define STANDAR_LENGTH 37
-#define NISAM_KEYS 6
-#if !defined(MSDOS) && !defined(labs)
-#define labs(a) abs(a)
-#endif
-
-static void get_options(int argc, char *argv[]);
-static uint rnd(uint max_value);
-static void fix_length(byte *record,uint length);
-static void put_blob_in_record(char *blob_pos,char **blob_buffer);
-static void copy_key(struct st_isam_info *info,uint inx,
- uchar *record,uchar *key);
-
-static int verbose=0,testflag=0,pack_type=HA_SPACE_PACK,
- first_key=0,async_io=0,key_cacheing=0,write_cacheing=0,locking=0,
- rec_pointer_size=0,pack_fields=1,use_log=0;
-static uint keys=NISAM_KEYS,recant=1000;
-static uint use_blob=0;
-static uint16 key1[1000],key3[5000];
-static char record[300],record2[300],key[100],key2[100],
- read_record[300],read_record2[300],read_record3[300];
-
-
- /* Test program */
-
-int main(int argc, char *argv[])
-{
- uint i;
- int j,n1,n2,n3,error,k;
- uint write_count,update,dupp_keys,opt_delete,start,length,blob_pos,
- reclength,ant;
- ulong lastpos,range_records,records;
- N_INFO *file;
- N_KEYDEF keyinfo[10];
- N_RECINFO recinfo[10];
- N_ISAMINFO info;
- char *filename,*blob_buffer;
- MY_INIT(argv[0]);
-
- filename= (char*) "test2.ISM";
- get_options(argc,argv);
- if (! async_io)
- my_disable_async_io=1;
-
- reclength=STANDAR_LENGTH+60+(use_blob ? 8 : 0);
- blob_pos=STANDAR_LENGTH+60;
- keyinfo[0].seg[0].base.start=0;
- keyinfo[0].seg[0].base.length=6;
- keyinfo[0].seg[0].base.type=HA_KEYTYPE_TEXT;
- keyinfo[0].seg[0].base.flag=(uint8) pack_type;
- keyinfo[0].seg[1].base.type=0;
- keyinfo[0].base.flag = (uint8) (pack_type ? HA_PACK_KEY : 0);
- keyinfo[1].seg[0].base.start=7;
- keyinfo[1].seg[0].base.length=6;
- keyinfo[1].seg[0].base.type=HA_KEYTYPE_BINARY;
- keyinfo[1].seg[0].base.flag=0;
- keyinfo[1].seg[1].base.start=0; /* Tv}delad nyckel */
- keyinfo[1].seg[1].base.length=6;
- keyinfo[1].seg[1].base.type=HA_KEYTYPE_NUM;
- keyinfo[1].seg[1].base.flag=HA_REVERSE_SORT;
- keyinfo[1].seg[2].base.type=0;
- keyinfo[1].base.flag =0;
- keyinfo[2].seg[0].base.start=12;
- keyinfo[2].seg[0].base.length=8;
- keyinfo[2].seg[0].base.type=HA_KEYTYPE_BINARY;
- keyinfo[2].seg[0].base.flag=HA_REVERSE_SORT;
- keyinfo[2].seg[1].base.type=0;
- keyinfo[2].base.flag =HA_NOSAME;
- keyinfo[3].seg[0].base.start=0;
- keyinfo[3].seg[0].base.length=reclength-(use_blob ? 8 : 0);
- keyinfo[3].seg[0].base.type=HA_KEYTYPE_TEXT;
- keyinfo[3].seg[0].base.flag=(uint8) pack_type;
- keyinfo[3].seg[1].base.type=0;
- keyinfo[3].base.flag = (uint8) (pack_type ? HA_PACK_KEY : 0);
- keyinfo[4].seg[0].base.start=0;
- keyinfo[4].seg[0].base.length=5;
- keyinfo[4].seg[0].base.type=HA_KEYTYPE_TEXT;
- keyinfo[4].seg[0].base.flag=0;
- keyinfo[4].seg[1].base.type=0;
- keyinfo[4].base.flag = (uint8) (pack_type ? HA_PACK_KEY : 0);
- keyinfo[5].seg[0].base.start=0;
- keyinfo[5].seg[0].base.length=4;
- keyinfo[5].seg[0].base.type=HA_KEYTYPE_TEXT;
- keyinfo[5].seg[0].base.flag=(uint8) pack_type;
- keyinfo[5].seg[1].base.type=0;
- keyinfo[5].base.flag = (uint8) (pack_type ? HA_PACK_KEY : 0);
-
- recinfo[0].base.type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
- recinfo[0].base.length=7;
- recinfo[1].base.type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
- recinfo[1].base.length=5;
- recinfo[2].base.type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
- recinfo[2].base.length=9;
- recinfo[3].base.type=FIELD_NORMAL;
- recinfo[3].base.length=STANDAR_LENGTH-7-5-9-4;
- recinfo[4].base.type=pack_fields ? FIELD_SKIP_ZERO : 0;
- recinfo[4].base.length=4;
- recinfo[5].base.type=pack_fields ? FIELD_SKIP_ENDSPACE : 0;
- recinfo[5].base.length=60;
- if (use_blob)
- {
- recinfo[6].base.type=FIELD_BLOB;
- recinfo[6].base.length=4+sizeof(char*); /* 4 byte ptr, 4 byte length */
- recinfo[7].base.type= FIELD_LAST;
- }
- else
- recinfo[6].base.type= FIELD_LAST;
-
- write_count=update=dupp_keys=opt_delete=0;
- blob_buffer=0;
-
- for (i=999 ; i>0 ; i--) key1[i]=0;
- for (i=4999 ; i>0 ; i--) key3[i]=0;
-
- printf("- Creating isam-file\n");
- /* DBUG_PUSH(""); */
- my_delete(filename,MYF(0)); /* Remove old locks under gdb */
- file= 0;
- if (nisam_create(filename,keys,&keyinfo[first_key],&recinfo[0],
- (ulong) (rec_pointer_size ? (1L << (rec_pointer_size*8))/
- reclength : 0),100l,0,0,0L))
- goto err;
- if (use_log)
- nisam_log(1);
- if (!(file=nisam_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
- goto err;
- printf("- Writing key:s\n");
- if (key_cacheing)
- init_key_cache(dflt_key_cache,512,IO_SIZE*16,0,0); /* Use a small cache */
- if (locking)
- nisam_lock_database(file,F_WRLCK);
- if (write_cacheing)
- nisam_extra(file,HA_EXTRA_WRITE_CACHE);
-
- for (i=0 ; i < recant ; i++)
- {
- n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
- sprintf(record,"%6d:%4d:%8d:Pos: %4d ",n1,n2,n3,write_count);
- longstore(record+STANDAR_LENGTH-4,(long) i);
- fix_length(record,(uint) STANDAR_LENGTH+rnd(60));
- put_blob_in_record(record+blob_pos,&blob_buffer);
- DBUG_PRINT("test",("record: %d",i));
-
- if (nisam_write(file,record))
- {
- if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
- {
- printf("Error: %d in write at record: %d\n",my_errno,i);
- goto err;
- }
- if (verbose) printf(" Double key: %d\n",n3);
- }
- else
- {
- if (key3[n3] == 1 && first_key <3 && first_key+keys >= 3)
- {
- printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
- goto err;
- }
- write_count++; key1[n1]++; key3[n3]=1;
- }
-
- /* Check if we can find key without flushing database */
- if (i == recant/2)
- {
- for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
- if (!j)
- for (j=999 ; j>0 && key1[j] == 0 ; j--) ;
- sprintf(key,"%6d",j);
- if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
- {
- printf("Test in loop: Can't find key: \"%s\"\n",key);
- goto err;
- }
- }
- }
- if (testflag==1) goto end;
-
- if (write_cacheing)
- if (nisam_extra(file,HA_EXTRA_NO_CACHE))
- {
- puts("got error from nisam_extra(HA_EXTRA_NO_CACHE)");
- goto end;
- }
-
- printf("- Delete\n");
- for (i=0 ; i<recant/10 ; i++)
- {
- for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
- if (j != 0)
- {
- sprintf(key,"%6d",j);
- if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
- {
- printf("can't find key1: \"%s\"\n",key);
- goto err;
- }
- if (nisam_delete(file,read_record))
- {
- printf("error: %d; can't delete record: \"%s\"\n", my_errno,read_record);
- goto err;
- }
- opt_delete++;
- key1[atoi(read_record+keyinfo[0].seg[0].base.start)]--;
- key3[atoi(read_record+keyinfo[2].seg[0].base.start)]=0;
- }
- }
- if (testflag==2) goto end;
-
- printf("- Update\n");
- for (i=0 ; i<recant/10 ; i++)
- {
- n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
- sprintf(record2,"%6d:%4d:%8d:XXX: %4d ",n1,n2,n3,update);
- longstore(record2+STANDAR_LENGTH-4,(long) i);
- fix_length(record2,(uint) STANDAR_LENGTH+rnd(60));
-
- for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
- if (j != 0)
- {
- sprintf(key,"%6d",j);
- if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT))
- {
- printf("can't find key1: \"%s\"\n",key);
- goto err;
- }
- if (use_blob)
- {
- if (i & 1)
- put_blob_in_record(record+blob_pos,&blob_buffer);
- else
- bmove(record+blob_pos,read_record+blob_pos,8);
- }
- if (nisam_update(file,read_record,record2))
- {
- if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
- {
- printf("error: %d; can't update:\nFrom: \"%s\"\nTo: \"%s\"\n",
- my_errno,read_record,record2);
- goto err;
- }
- if (verbose)
- printf("Double key when tried to update:\nFrom: \"%s\"\nTo: \"%s\"\n",record,record2);
- }
- else
- {
- key1[atoi(read_record+keyinfo[0].seg[0].base.start)]--;
- key3[atoi(read_record+keyinfo[2].seg[0].base.start)]=0;
- key1[n1]++; key3[n3]=1;
- update++;
- }
- }
- }
- if (testflag==3) goto end;
-
- printf("- Same key: first - next -> last - prev -> first\n");
- DBUG_PRINT("progpos",("first - next -> last - prev -> first"));
- for (i=999, dupp_keys=j=0 ; i>0 ; i--)
- {
- if (key1[i] >dupp_keys) { dupp_keys=key1[i]; j=i; }
- }
- sprintf(key,"%6d",j);
- if (verbose) printf(" Using key: \"%s\" Keys: %d\n",key,dupp_keys);
- if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) goto err;
- if (nisam_rsame(file,read_record2,-1)) goto err;
- if (memcmp(read_record,read_record2,reclength) != 0)
- {
- printf("nisam_rsame didn't find same record\n");
- goto end;
- }
- nisam_info(file,&info,0);
- if (nisam_rfirst(file,read_record2,0) ||
- nisam_rsame_with_pos(file,read_record2,0,info.recpos) ||
- memcmp(read_record,read_record2,reclength) != 0)
- {
- printf("nisam_rsame_with_pos didn't find same record\n");
- goto end;
- }
- {
- int skr=nisam_rnext(file,read_record2,0);
- if ((skr && my_errno != HA_ERR_END_OF_FILE) ||
- nisam_rprev(file,read_record2,-1) ||
- memcmp(read_record,read_record2,reclength) != 0)
- {
- printf("nisam_rsame_with_pos lost position\n");
- goto end;
- }
- }
- ant=1;
- start=keyinfo[0].seg[0].base.start; length=keyinfo[0].seg[0].base.length;
- while (nisam_rnext(file,read_record2,0) == 0 &&
- memcmp(read_record2+start,key,length) == 0) ant++;
- if (ant != dupp_keys)
- {
- printf("next: I can only find: %d keys of %d\n",ant,dupp_keys);
- goto end;
- }
- ant=0;
- while (nisam_rprev(file,read_record3,0) == 0 &&
- bcmp(read_record3+start,key,length) == 0) ant++;
- if (ant != dupp_keys)
- {
- printf("prev: I can only find: %d records of %d\n",ant,dupp_keys);
- goto end;
- }
-
- printf("- All keys: first - next -> last - prev -> first\n");
- DBUG_PRINT("progpos",("All keys: first - next -> last - prev -> first"));
- ant=1;
- if (nisam_rfirst(file,read_record,0))
- {
- printf("Can't find first record\n");
- goto end;
- }
- while (nisam_rnext(file,read_record3,0) == 0 && ant < write_count+10)
- ant++;
- if (ant != write_count - opt_delete)
- {
- printf("next: I found: %d records of %d\n",ant,write_count - opt_delete);
- goto end;
- }
- if (nisam_rlast(file,read_record2,0) ||
- bcmp(read_record2,read_record3,reclength))
- {
- printf("Can't find last record\n");
- DBUG_DUMP("record2",(byte*) read_record2,reclength);
- DBUG_DUMP("record3",(byte*) read_record3,reclength);
- goto end;
- }
- ant=1;
- while (nisam_rprev(file,read_record3,0) == 0 && ant < write_count+10)
- ant++;
- if (ant != write_count - opt_delete)
- {
- printf("prev: I found: %d records of %d\n",ant,write_count);
- goto end;
- }
- if (bcmp(read_record,read_record3,reclength))
- {
- printf("Can't find first record\n");
- goto end;
- }
-
- printf("- Test if: Read first - next - prev - prev - next == first\n");
- DBUG_PRINT("progpos",("- Read first - next - prev - prev - next == first"));
- if (nisam_rfirst(file,read_record,0) ||
- nisam_rnext(file,read_record3,0) ||
- nisam_rprev(file,read_record3,0) ||
- nisam_rprev(file,read_record3,0) == 0 ||
- nisam_rnext(file,read_record3,0))
- goto err;
- if (bcmp(read_record,read_record3,reclength) != 0)
- printf("Can't find first record\n");
-
- printf("- Test if: Read last - prev - next - next - prev == last\n");
- DBUG_PRINT("progpos",("Read last - prev - next - next - prev == last"));
- if (nisam_rlast(file,read_record2,0) ||
- nisam_rprev(file,read_record3,0) ||
- nisam_rnext(file,read_record3,0) ||
- nisam_rnext(file,read_record3,0) == 0 ||
- nisam_rprev(file,read_record3,0))
- goto err;
- if (bcmp(read_record2,read_record3,reclength))
- printf("Can't find last record\n");
-
- puts("- Test read key-part");
- strmov(key2,key);
- for(i=strlen(key2) ; i-- > 1 ;)
- {
- key2[i]=0;
- if (nisam_rkey(file,read_record,0,key2,(uint) i,HA_READ_KEY_EXACT)) goto err;
- if (bcmp(read_record+start,key,(uint) i))
- {
- puts("Didn't find right record");
- goto end;
- }
- }
- if (dupp_keys > 2)
- {
- printf("- Read key (first) - next - delete - next -> last\n");
- DBUG_PRINT("progpos",("first - next - delete - next -> last"));
- if (nisam_rkey(file,read_record,0,key,0,HA_READ_KEY_EXACT)) goto err;
- if (nisam_rnext(file,read_record3,0)) goto err;
- if (nisam_delete(file,read_record3)) goto err;
- opt_delete++;
- ant=1;
- while (nisam_rnext(file,read_record3,0) == 0 &&
- bcmp(read_record3+start,key,length) == 0) ant++;
- if (ant != dupp_keys-1)
- {
- printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-1);
- goto end;
- }
- }
- if (dupp_keys>4)
- {
- printf("- Read last of key - prev - delete - prev -> first\n");
- DBUG_PRINT("progpos",("last - prev - delete - prev -> first"));
- if (nisam_rprev(file,read_record3,0)) goto err;
- if (nisam_rprev(file,read_record3,0)) goto err;
- if (nisam_delete(file,read_record3)) goto err;
- opt_delete++;
- ant=1;
- while (nisam_rprev(file,read_record3,0) == 0 &&
- bcmp(read_record3+start,key,length) == 0) ant++;
- if (ant != dupp_keys-2)
- {
- printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-2);
- goto end;
- }
- }
- if (dupp_keys > 6)
- {
- printf("- Read first - delete - next -> last\n");
- DBUG_PRINT("progpos",("first - delete - next -> last"));
- if (nisam_rkey(file,read_record3,0,key,0,HA_READ_KEY_EXACT)) goto err;
- if (nisam_delete(file,read_record3)) goto err;
- opt_delete++;
- ant=1;
- if (nisam_rnext(file,read_record,0))
- goto err; /* Skall finnas poster */
- while (nisam_rnext(file,read_record3,0) == 0 &&
- bcmp(read_record3+start,key,length) == 0) ant++;
- if (ant != dupp_keys-3)
- {
- printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-3);
- goto end;
- }
-
- printf("- Read last - delete - prev -> first\n");
- DBUG_PRINT("progpos",("last - delete - prev -> first"));
- if (nisam_rprev(file,read_record3,0)) goto err;
- if (nisam_delete(file,read_record3)) goto err;
- opt_delete++;
- ant=0;
- while (nisam_rprev(file,read_record3,0) == 0 &&
- bcmp(read_record3+start,key,length) == 0) ant++;
- if (ant != dupp_keys-4)
- {
- printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-4);
- goto end;
- }
- }
-
- puts("- Test if: Read rrnd - same");
- DBUG_PRINT("progpos",("Read rrnd - same"));
- for (i=0 ; i < write_count ; i++)
- {
- if (nisam_rrnd(file,read_record,i == 0 ? 0L : NI_POS_ERROR) == 0)
- break;
- }
- if (i == write_count)
- goto err;
-
- bmove(read_record2,read_record,reclength);
- for (i=2 ; i-- > 0 ;)
- {
- if (nisam_rsame(file,read_record2,(int) i)) goto err;
- if (bcmp(read_record,read_record2,reclength) != 0)
- {
- printf("is_rsame didn't find same record\n");
- goto end;
- }
- }
- puts("- Test nisam_records_in_range");
- nisam_info(file,&info,HA_STATUS_VARIABLE);
- for (i=0 ; i < info.keys ; i++)
- {
- if (nisam_rfirst(file,read_record,(int) i) ||
- nisam_rlast(file,read_record2,(int) i))
- goto err;
- copy_key(file,(uint) i,(uchar*) read_record,(uchar*) key);
- copy_key(file,(uint) i,(uchar*) read_record2,(uchar*) key2);
- range_records=nisam_records_in_range(file,(int) i,key,0,HA_READ_KEY_EXACT,
- key2,0,HA_READ_AFTER_KEY);
- if (range_records < info.records*8/10 ||
- range_records > info.records*12/10)
- {
- printf("ni_records_range returned %lu; Should be about %lu\n",
- range_records,info.records);
- goto end;
- }
- if (verbose)
- {
- printf("ni_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n",
- range_records,info.records,
- labs((long) range_records - (long) info.records)*100.0/
- info.records);
-
- }
- }
- for (i=0 ; i < 5 ; i++)
- {
- for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
- for (k=rnd(1000) ; k>0 && key1[k] == 0 ; k--) ;
- if (j != 0 && k != 0)
- {
- if (j > k)
- swap_variables(int, j, k);
- sprintf(key,"%6d",j);
- sprintf(key2,"%6d",k);
- range_records=nisam_records_in_range(file,0,key,0,HA_READ_AFTER_KEY,
- key2,0,HA_READ_BEFORE_KEY);
- records=0;
- for (j++ ; j < k ; j++)
- records+=key1[j];
- if ((long) range_records < (long) records*7/10-2 ||
- (long) range_records > (long) records*13/10+2)
- {
- printf("ni_records_range returned %ld; Should be about %ld\n",
- range_records,records);
- goto end;
- }
- if (verbose && records)
- {
- printf("ni_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n",
- range_records,records,
- labs((long) range_records-(long) records)*100.0/records);
-
- }
- }
- }
-
- printf("- nisam_info\n");
- nisam_info(file,&info,0);
- if (info.records != write_count-opt_delete || info.deleted > opt_delete + update
- || info.keys != keys)
- {
- puts("Wrong info from nisam_info");
- printf("Got: records: %ld opt_delete: %ld i_keys: %d\n",
- info.records,info.deleted,info.keys);
- }
- if (verbose)
- {
- char buff[80];
- get_date(buff,3,info.create_time);
- printf("info: Created %s\n",buff);
- get_date(buff,3,info.isamchk_time);
- printf("info: checked %s\n",buff);
- get_date(buff,3,info.update_time);
- printf("info: Modified %s\n",buff);
- }
-
- nisam_panic(HA_PANIC_WRITE);
- nisam_panic(HA_PANIC_READ);
- if (nisam_is_changed(file))
- puts("Warning: nisam_is_changed reported that datafile was changed");
-
- printf("- nisam_extra(CACHE) + nisam_rrnd.... + nisam_extra(NO_CACHE)\n");
- if (nisam_extra(file,HA_EXTRA_RESET) || nisam_extra(file,HA_EXTRA_CACHE))
- {
- if (locking || (!use_blob && !pack_fields))
- {
- puts("got error from nisam_extra(HA_EXTRA_CACHE)");
- goto end;
- }
- }
- ant=0;
- while ((error=nisam_rrnd(file,record,NI_POS_ERROR)) >= 0 &&
- ant < write_count + 10)
- ant+= error ? 0 : 1;
- if (ant != write_count-opt_delete)
- {
- printf("rrnd with cache: I can only find: %d records of %d\n",
- ant,write_count-opt_delete);
- goto end;
- }
- if (nisam_extra(file,HA_EXTRA_NO_CACHE))
- {
- puts("got error from nisam_extra(HA_EXTRA_NO_CACHE)");
- goto end;
- }
-
- if (testflag == 4) goto end;
-
- printf("- Removing keys\n");
- lastpos = NI_POS_ERROR;
- /* DBUG_POP(); */
- nisam_extra(file,HA_EXTRA_RESET);
- while ((error=nisam_rrnd(file,read_record,NI_POS_ERROR)) >=0)
- {
- nisam_info(file,&info,1);
- if (lastpos >= info.recpos && lastpos != NI_POS_ERROR)
- {
- printf("nisam_rrnd didn't advance filepointer; old: %ld, new: %ld\n",
- lastpos,info.recpos);
- goto err;
- }
- lastpos=info.recpos;
- if (error == 0)
- {
- if (nisam_rsame(file,read_record,-1))
- {
- printf("can't find record %lx\n",info.recpos);
- goto err;
- }
- if (use_blob)
- {
- ulong blob_length,pos;
- uchar *ptr;
- longget(blob_length,read_record+blob_pos+4);
- ptr=(uchar*) blob_length;
- longget(blob_length,read_record+blob_pos);
- for (pos=0 ; pos < blob_length ; pos++)
- {
- if (ptr[pos] != (uchar) (blob_length+pos))
- {
- printf("found blob with wrong info at %ld\n",lastpos);
- use_blob=0;
- break;
- }
- }
- }
- if (nisam_delete(file,read_record))
- {
- printf("can't delete record: %s\n",read_record);
- goto err;
- }
- opt_delete++;
- }
- }
- if (my_errno != HA_ERR_END_OF_FILE && my_errno != HA_ERR_RECORD_DELETED)
- printf("error: %d from nisam_rrnd\n",my_errno);
- if (write_count != opt_delete)
- {
- printf("Deleted only %d of %d records\n",write_count,opt_delete);
- goto err;
- }
-end:
- if (nisam_close(file))
- goto err;
- nisam_panic(HA_PANIC_CLOSE); /* Should close log */
- printf("\nFollowing test have been made:\n");
- printf("Write records: %d\nUpdate records: %d\nSame-key-read: %d\nDelete records: %d\n", write_count,update,dupp_keys,opt_delete);
- if (rec_pointer_size)
- printf("Record pointer size: %d\n",rec_pointer_size);
- if (key_cacheing)
- puts("Key cacheing used");
- if (write_cacheing)
- puts("Write cacheing used");
- if (async_io && locking)
- puts("Asyncron io with locking used");
- else if (locking)
- puts("Locking used");
- if (use_blob)
- puts("blobs used");
- end_key_cache(dflt_key_cache,1);
- if (blob_buffer)
- my_free(blob_buffer,MYF(0));
- my_end(MY_CHECK_ERROR | MY_GIVE_INFO);
- return(0);
-err:
- printf("got error: %d when using NISAM-database\n",my_errno);
- if (file)
- VOID(nisam_close(file));
- return(1);
-} /* main */
-
-
- /* l{ser optioner */
- /* OBS! intierar endast DEBUG - ingen debuggning h{r ! */
-
-static void get_options( int argc, char *argv[])
-{
- char *pos,*progname;
- DEBUGGER_OFF;
-
- progname= argv[0];
-
- while (--argc >0 && *(pos = *(++argv)) == '-' ) {
- switch(*++pos) {
- case 'b':
- if (*++pos)
- nisam_block_size= MY_ALIGN(atoi(pos),512);
- set_if_bigger(nisam_block_size,8192); /* Max block size */
- set_if_smaller(nisam_block_size,1024);
- break;
- case 'B':
- use_blob=1;
- break;
- case 'K': /* Use key cacheing */
- key_cacheing=1;
- break;
- case 'W': /* Use write cacheing */
- write_cacheing=1;
- if (*++pos)
- my_default_record_cache_size=atoi(pos);
- break;
- case 'i':
- if (*++pos)
- srand(atoi(pos));
- break;
- case 'l':
- use_log=1;
- break;
- case 'L':
- locking=1;
- break;
- case 'A': /* use asyncron io */
- async_io=1;
- if (*++pos)
- my_default_record_cache_size=atoi(pos);
- break;
- case 'v': /* verbose */
- verbose=1;
- break;
- case 'm': /* records */
- recant=atoi(++pos);
- break;
- case 'f':
- if ((first_key=atoi(++pos)) <0 || first_key >= NISAM_KEYS)
- first_key=0;
- break;
- case 'k':
- if ((keys=(uint) atoi(++pos)) < 1 ||
- keys > (uint) (NISAM_KEYS-first_key))
- keys=NISAM_KEYS-first_key;
- break;
- case 'P':
- pack_type=0; /* Don't use DIFF_LENGTH */
- break;
- case 'R': /* Length of record pointer */
- rec_pointer_size=atoi(++pos);
- if (rec_pointer_size > 3)
- rec_pointer_size=0;
- break;
- case 'S':
- pack_fields=0; /* Static-length-records */
- break;
- case 't':
- testflag=atoi(++pos); /* testmod */
- break;
- case '?':
- case 'I':
- case 'V':
- printf("%s Ver 1.4 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
- puts("TCX Datakonsult AB, by Monty, for your professional use\n");
- printf("Usage: %s [-?ABIKLPRSVWltv] [-b#] [-k#] [-f#] [-m#] [-t#]\n",progname);
- exit(0);
- case '#':
- DEBUGGER_ON;
- DBUG_PUSH (++pos);
- break;
- default:
- printf("Illegal option: '%c'\n",*pos);
- break;
- }
- }
- return;
-} /* get options */
-
- /* Ge ett randomv{rde inom ett intervall 0 <=x <= n */
-
-static uint rnd( uint max_value)
-{
- return (uint) ((rand() & 32767)/32767.0*max_value);
-} /* rnd */
-
-
- /* G|r en record av skiftande length */
-
-static void fix_length( byte *rec, uint length)
-{
- bmove(rec+STANDAR_LENGTH,
- "0123456789012345678901234567890123456789012345678901234567890",
- length-STANDAR_LENGTH);
- strfill(rec+length,STANDAR_LENGTH+60-length,' ');
-} /* fix_length */
-
-
- /* Put maybe a blob in record */
-
-static void put_blob_in_record(char *blob_pos, char **blob_buffer)
-{
- ulong i,length;
- if (use_blob)
- {
- if (rnd(10) == 0)
- {
- if (! *blob_buffer &&
- !(*blob_buffer=my_malloc((uint) use_blob,MYF(MY_WME))))
- {
- use_blob=0;
- return;
- }
- length=rnd(use_blob);
- for (i=0 ; i < length ; i++)
- (*blob_buffer)[i]=(char) (length+i);
- longstore(blob_pos,length);
- bmove(blob_pos+4,(char*) blob_buffer,sizeof(char*));
- }
- else
- {
- longstore(blob_pos,0);
- }
- }
- return;
-}
-
-
-static void copy_key( N_INFO *info, uint inx, uchar *rec, uchar *key_buff)
-{
- N_KEYSEG *keyseg;
-
- for (keyseg=info->s->keyinfo[inx].seg ; keyseg->base.type ; keyseg++)
- {
- memcpy(key_buff,rec+keyseg->base.start,(size_t) keyseg->base.length);
- key_buff+=keyseg->base.length;
- }
- return;
-}
diff --git a/isam/test3.c b/isam/test3.c
deleted file mode 100644
index 9195fcbf1b6..00000000000
--- a/isam/test3.c
+++ /dev/null
@@ -1,494 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Test av locking */
-
-#ifndef __NETWARE__
-
-#include "nisam.h"
-#include <sys/types.h>
-#include <keycache.h>
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
-#endif
-
-
-#if defined(HAVE_LRAND48)
-#define rnd(X) (lrand48() % X)
-#define rnd_init(X) srand48(X)
-#else
-#define rnd(X) (random() % X)
-#define rnd_init(X) srandom(X)
-#endif
-
-
-const char *filename= "test3.ISM";
-uint tests=10,forks=10,key_cacheing=0,use_log=0;
-
-static void get_options(int argc, char *argv[]);
-void start_test(int id);
-int test_read(N_INFO *,int),test_write(N_INFO *,int,int),
- test_update(N_INFO *,int,int),test_rrnd(N_INFO *,int);
-
-struct record {
- char id[8];
- uint32 nr;
- char text[10];
-} record;
-
-
-int main(int argc,char **argv)
-{
- int status,wait_ret;
- uint i;
- N_KEYDEF keyinfo[10];
- N_RECINFO recinfo[10];
- MY_INIT(argv[0]);
-
- get_options(argc,argv);
-
- keyinfo[0].seg[0].base.start=0;
- keyinfo[0].seg[0].base.length=8;
- keyinfo[0].seg[0].base.type=HA_KEYTYPE_TEXT;
- keyinfo[0].seg[0].base.flag=HA_SPACE_PACK;
- keyinfo[0].seg[1].base.type=0;
- keyinfo[0].base.flag = (uint8) HA_PACK_KEY;
- keyinfo[1].seg[0].base.start=8;
- keyinfo[1].seg[0].base.length=sizeof(uint32);
- keyinfo[1].seg[0].base.type=HA_KEYTYPE_LONG_INT;
- keyinfo[1].seg[0].base.flag=0;
- keyinfo[1].seg[1].base.type=0;
- keyinfo[1].base.flag =HA_NOSAME;
-
- recinfo[0].base.type=0;
- recinfo[0].base.length=sizeof(record.id);
- recinfo[1].base.type=0;
- recinfo[1].base.length=sizeof(record.nr);
- recinfo[2].base.type=0;
- recinfo[2].base.length=sizeof(record.text);
- recinfo[3].base.type=FIELD_LAST;
-
- puts("- Creating isam-file");
- my_delete(filename,MYF(0)); /* Remove old locks under gdb */
- if (nisam_create(filename,2,&keyinfo[0],&recinfo[0],10000,0,0,0,0L))
- exit(1);
-
- rnd_init(0);
- printf("- Starting %d processes\n",forks); fflush(stdout);
- for (i=0 ; i < forks; i++)
- {
- if (!fork())
- {
- start_test(i+1);
- sleep(1);
- return 0;
- }
- VOID(rnd(1));
- }
-
- for (i=0 ; i < forks ; i++)
- while ((wait_ret=wait(&status)) && wait_ret == -1);
- return 0;
-}
-
-
-static void get_options(argc,argv)
-int argc;
-char *argv[];
-{
- char *pos,*progname;
- DEBUGGER_OFF;
-
- progname= argv[0];
-
- while (--argc >0 && *(pos = *(++argv)) == '-' ) {
- switch(*++pos) {
- case 'l':
- use_log=1;
- break;
- case 'f':
- forks=atoi(++pos);
- break;
- case 't':
- tests=atoi(++pos);
- break;
- case 'K': /* Use key cacheing */
- key_cacheing=1;
- break;
- case 'A': /* All flags */
- use_log=key_cacheing=1;
- break;
- case '?':
- case 'I':
- case 'V':
- printf("%s Ver 1.0 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
- puts("TCX Datakonsult AB, by Monty, for your professional use\n");
- puts("Test av locking with threads\n");
- printf("Usage: %s [-?lKA] [-f#] [-t#]\n",progname);
- exit(0);
- case '#':
- DEBUGGER_ON;
- DBUG_PUSH (++pos);
- break;
- default:
- printf("Illegal option: '%c'\n",*pos);
- break;
- }
- }
- return;
-}
-
-
-void start_test(int id)
-{
- uint i;
- int error,lock_type;
- N_ISAMINFO isam_info;
- N_INFO *file,*file1,*file2,*lock;
-
- if (use_log)
- nisam_log(1);
- if (!(file1=nisam_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)) ||
- !(file2=nisam_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
- {
- fprintf(stderr,"Can't open isam-file: %s\n",filename);
- exit(1);
- }
- if (key_cacheing && rnd(2) == 0)
- init_key_cache(dflt_key_cache,512,65536L,0,0);
- printf("Process %d, pid: %d\n",id,(int) getpid()); fflush(stdout);
-
- for (error=i=0 ; i < tests && !error; i++)
- {
- file= (rnd(2) == 1) ? file1 : file2;
- lock=0 ; lock_type=0;
- if (rnd(10) == 0)
- {
- if (nisam_lock_database(lock=(rnd(2) ? file1 : file2),
- lock_type=(rnd(2) == 0 ? F_RDLCK : F_WRLCK)))
- {
- fprintf(stderr,"%2d: start: Can't lock table %d\n",id,my_errno);
- error=1;
- break;
- }
- }
- switch (rnd(4)) {
- case 0: error=test_read(file,id); break;
- case 1: error=test_rrnd(file,id); break;
- case 2: error=test_write(file,id,lock_type); break;
- case 3: error=test_update(file,id,lock_type); break;
- }
- if (lock)
- nisam_lock_database(lock,F_UNLCK);
- }
- if (!error)
- {
- nisam_info(file1,&isam_info,0);
- printf("%2d: End of test. Records: %ld Deleted: %ld\n",
- id,isam_info.records,isam_info.deleted);
- fflush(stdout);
- }
-
- nisam_close(file1);
- nisam_close(file2);
- if (use_log)
- nisam_log(0);
- if (error)
- {
- printf("%2d: Aborted\n",id); fflush(stdout);
- exit(1);
- }
-}
-
-
-int test_read(N_INFO *file,int id)
-{
- uint i,lock,found,next,prev;
- ulong find;
-
- lock=0;
- if (rnd(2) == 0)
- {
- lock=1;
- if (nisam_lock_database(file,F_RDLCK))
- {
- fprintf(stderr,"%2d: Can't lock table %d\n",id,my_errno);
- return 1;
- }
- }
-
- found=next=prev=0;
- for (i=0 ; i < 100 ; i++)
- {
- find=rnd(100000);
- if (!nisam_rkey(file,record.id,1,(byte*) &find,
- sizeof(find),HA_READ_KEY_EXACT))
- found++;
- else
- {
- if (my_errno != HA_ERR_KEY_NOT_FOUND)
- {
- fprintf(stderr,"%2d: Got error %d from read in read\n",id,my_errno);
- return 1;
- }
- else if (!nisam_rnext(file,record.id,1))
- next++;
- else
- {
- if (my_errno != HA_ERR_END_OF_FILE)
- {
- fprintf(stderr,"%2d: Got error %d from rnext in read\n",id,my_errno);
- return 1;
- }
- else if (!nisam_rprev(file,record.id,1))
- prev++;
- else
- {
- if (my_errno != HA_ERR_END_OF_FILE)
- {
- fprintf(stderr,"%2d: Got error %d from rnext in read\n",
- id,my_errno);
- return 1;
- }
- }
- }
- }
- }
- if (lock)
- {
- if (nisam_lock_database(file,F_UNLCK))
- {
- fprintf(stderr,"%2d: Can't unlock table\n",id);
- return 1;
- }
- }
- printf("%2d: read: found: %5d next: %5d prev: %5d\n",
- id,found,next,prev);
- fflush(stdout);
- return 0;
-}
-
-
-int test_rrnd(N_INFO *file,int id)
-{
- uint count,lock;
-
- lock=0;
- if (rnd(2) == 0)
- {
- lock=1;
- if (nisam_lock_database(file,F_RDLCK))
- {
- fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
- nisam_close(file);
- return 1;
- }
- if (rnd(2) == 0)
- nisam_extra(file,HA_EXTRA_CACHE);
- }
-
- count=0;
- if (nisam_rrnd(file,record.id,0L))
- {
- if (my_errno == HA_ERR_END_OF_FILE)
- goto end;
- fprintf(stderr,"%2d: Can't read first record (%d)\n",id,my_errno);
- return 1;
- }
- for (count=1 ; !nisam_rrnd(file,record.id,NI_POS_ERROR) ;count++) ;
- if (my_errno != HA_ERR_END_OF_FILE)
- {
- fprintf(stderr,"%2d: Got error %d from rrnd\n",id,my_errno);
- return 1;
- }
-
-end:
- if (lock)
- {
- nisam_extra(file,HA_EXTRA_NO_CACHE);
- if (nisam_lock_database(file,F_UNLCK))
- {
- fprintf(stderr,"%2d: Can't unlock table\n",id);
- exit(0);
- }
- }
- printf("%2d: rrnd: %5d\n",id,count); fflush(stdout);
- return 0;
-}
-
-
-int test_write(N_INFO *file,int id,int lock_type)
-{
- uint i,tries,count,lock;
-
- lock=0;
- if (rnd(2) == 0 || lock_type == F_RDLCK)
- {
- lock=1;
- if (nisam_lock_database(file,F_WRLCK))
- {
- if (lock_type == F_RDLCK && my_errno == EDEADLK)
- {
- printf("%2d: write: deadlock\n",id); fflush(stdout);
- return 0;
- }
- fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
- nisam_close(file);
- return 1;
- }
- if (rnd(2) == 0)
- nisam_extra(file,HA_EXTRA_WRITE_CACHE);
- }
-
- sprintf(record.id,"%7d",(int) getpid());
- strmov(record.text,"Testing...");
-
- tries=(uint) rnd(100)+10;
- for (i=count=0 ; i < tries ; i++)
- {
- record.nr=rnd(80000)+20000;
- if (!nisam_write(file,record.id))
- count++;
- else
- {
- if (my_errno != HA_ERR_FOUND_DUPP_KEY)
- {
- fprintf(stderr,"%2d: Got error %d (errno %d) from write\n",id,my_errno,
- errno);
- return 1;
- }
- }
- }
- if (lock)
- {
- nisam_extra(file,HA_EXTRA_NO_CACHE);
- if (nisam_lock_database(file,F_UNLCK))
- {
- fprintf(stderr,"%2d: Can't unlock table\n",id);
- exit(0);
- }
- }
- printf("%2d: write: %5d\n",id,count); fflush(stdout);
- return 0;
-}
-
-
-int test_update(N_INFO *file,int id,int lock_type)
-{
- uint i,lock,found,next,prev,update;
- ulong find;
- struct record new_record;
-
- lock=0;
- if (rnd(2) == 0 || lock_type == F_RDLCK)
- {
- lock=1;
- if (nisam_lock_database(file,F_WRLCK))
- {
- if (lock_type == F_RDLCK && my_errno == EDEADLK)
- {
- printf("%2d: write: deadlock\n",id); fflush(stdout);
- return 0;
- }
- fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
- return 1;
- }
- }
- bzero((char*) &new_record,sizeof(new_record));
- strmov(new_record.text,"Updated");
-
- found=next=prev=update=0;
- for (i=0 ; i < 100 ; i++)
- {
- find=rnd(100000);
- if (!nisam_rkey(file,record.id,1,(byte*) &find,
- sizeof(find),HA_READ_KEY_EXACT))
- found++;
- else
- {
- if (my_errno != HA_ERR_KEY_NOT_FOUND)
- {
- fprintf(stderr,"%2d: Got error %d from read in update\n",id,my_errno);
- return 1;
- }
- else if (!nisam_rnext(file,record.id,1))
- next++;
- else
- {
- if (my_errno != HA_ERR_END_OF_FILE)
- {
- fprintf(stderr,"%2d: Got error %d from rnext in update\n",
- id,my_errno);
- return 1;
- }
- else if (!nisam_rprev(file,record.id,1))
- prev++;
- else
- {
- if (my_errno != HA_ERR_END_OF_FILE)
- {
- fprintf(stderr,"%2d: Got error %d from rnext in update\n",
- id,my_errno);
- return 1;
- }
- continue;
- }
- }
- }
- memcpy_fixed(new_record.id,record.id,sizeof(record.id));
- new_record.nr=rnd(20000)+40000;
- if (!nisam_update(file,record.id,new_record.id))
- update++;
- else
- {
- if (my_errno != HA_ERR_RECORD_CHANGED &&
- my_errno != HA_ERR_RECORD_DELETED &&
- my_errno != HA_ERR_FOUND_DUPP_KEY)
- {
- fprintf(stderr,"%2d: Got error %d from update\n",id,my_errno);
- return 1;
- }
- }
- }
- if (lock)
- {
- if (nisam_lock_database(file,F_UNLCK))
- {
- fprintf(stderr,"Can't unlock table,id, error%d\n",my_errno);
- return 1;
- }
- }
- printf("%2d: update: %5d\n",id,update); fflush(stdout);
- return 0;
-}
-
-#else /* __NETWARE__ */
-
-#include <stdio.h>
-
-main()
-{
- fprintf(stderr,"this test has not been ported to NetWare\n");
- return 0;
-}
-
-#endif /* __NETWARE__ */
diff --git a/isam/test_all b/isam/test_all
deleted file mode 100755
index 5de37e44585..00000000000
--- a/isam/test_all
+++ /dev/null
@@ -1,30 +0,0 @@
-echo "test2 -L -K -W -P"
-test2 -L -K -W -P
-echo "test2 -L -K -W -P -A"
-test2 -L -K -W -P -A
-echo "test2 -L -K -W -P -S -R1 -m500"
-test2 -L -K -W -P -S -R1 -m500
-echo "test2 -L -K -R1 -m2000 ; Should give error 135"
-test2 -L -K -R1 -m2000
-echo "test2 -L -K -P -S -R3 -m50 -b1000000"
-test2 -L -K -P -S -R3 -m50 -b1000000
-echo "test2 -L -B"
-test2 -L -B
-echo "test2 -L -K -W -P -m50 -l"
-test2 -L -K -W -P -m50 -l
-isamlog
-echo "test2 -L -K -W -P -m50 -l -b100"
-test2 -L -K -W -P -m50 -l -b100
-isamlog
-echo "time test2"
-time test2
-echo "time test2 -K"
-time test2 -K
-echo "time test2 -L"
-time test2 -L
-echo "time test2 -L -K"
-time test2 -L -K
-echo "time test2 -L -K -W"
-time test2 -L -K -W
-echo "time test2 -L -K -W -S"
-time test2 -L -K -W -S
diff --git a/isam/test_all.res b/isam/test_all.res
deleted file mode 100644
index 5de37e44585..00000000000
--- a/isam/test_all.res
+++ /dev/null
@@ -1,30 +0,0 @@
-echo "test2 -L -K -W -P"
-test2 -L -K -W -P
-echo "test2 -L -K -W -P -A"
-test2 -L -K -W -P -A
-echo "test2 -L -K -W -P -S -R1 -m500"
-test2 -L -K -W -P -S -R1 -m500
-echo "test2 -L -K -R1 -m2000 ; Should give error 135"
-test2 -L -K -R1 -m2000
-echo "test2 -L -K -P -S -R3 -m50 -b1000000"
-test2 -L -K -P -S -R3 -m50 -b1000000
-echo "test2 -L -B"
-test2 -L -B
-echo "test2 -L -K -W -P -m50 -l"
-test2 -L -K -W -P -m50 -l
-isamlog
-echo "test2 -L -K -W -P -m50 -l -b100"
-test2 -L -K -W -P -m50 -l -b100
-isamlog
-echo "time test2"
-time test2
-echo "time test2 -K"
-time test2 -K
-echo "time test2 -L"
-time test2 -L
-echo "time test2 -L -K"
-time test2 -L -K
-echo "time test2 -L -K -W"
-time test2 -L -K -W
-echo "time test2 -L -K -W -S"
-time test2 -L -K -W -S
diff --git a/isam/update.c b/isam/update.c
deleted file mode 100644
index b3b676f967d..00000000000
--- a/isam/update.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Uppdaterare nuvarande record i en pisam-databas */
-
-#include "isamdef.h"
-#ifdef __WIN__
-#include <errno.h>
-#endif
-
- /* Updaterar senaste l{sta record i databasen */
-
-int nisam_update(register N_INFO *info, const byte *oldrec, const byte *newrec)
-{
- int flag,key_changed,save_errno;
- reg3 ulong pos;
- uint i,length;
- uchar old_key[N_MAX_KEY_BUFF],*new_key;
- DBUG_ENTER("nisam_update");
-
- LINT_INIT(save_errno);
- if (!(info->update & HA_STATE_AKTIV))
- {
- my_errno=HA_ERR_KEY_NOT_FOUND;
- DBUG_RETURN(-1);
- }
- if (info->s->base.options & HA_OPTION_READ_ONLY_DATA)
- {
- my_errno=EACCES;
- DBUG_RETURN(-1);
- }
- pos=info->lastpos;
-#ifndef NO_LOCKING
- if (_nisam_readinfo(info,F_WRLCK,1)) DBUG_RETURN(-1);
-#endif
- if ((*info->s->compare_record)(info,oldrec))
- {
- save_errno=my_errno;
- goto err_end; /* Record has changed */
- }
- if (info->s->state.key_file_length >=
- info->s->base.max_key_file_length -
- info->s->blocksize* INDEX_BLOCK_MARGIN *info->s->state.keys)
- {
- save_errno=HA_ERR_INDEX_FILE_FULL;
- goto err_end;
- }
-
- /* Flyttar de element i isamfilen som m}ste flyttas */
-
- new_key=info->lastkey+info->s->base.max_key_length;
- key_changed=HA_STATE_KEY_CHANGED; /* We changed current database */
- /* Remove key that didn't change */
- for (i=0 ; i < info->s->state.keys ; i++)
- {
- length=_nisam_make_key(info,i,new_key,newrec,pos);
- if (length != _nisam_make_key(info,i,old_key,oldrec,pos) ||
- memcmp((byte*) old_key,(byte*) new_key,length))
- {
- if ((int) i == info->lastinx)
- key_changed|=HA_STATE_WRITTEN; /* Mark that keyfile changed */
- if (_nisam_ck_delete(info,i,old_key)) goto err;
- if (_nisam_ck_write(info,i,new_key)) goto err;
- }
- }
-
- if ((*info->s->update_record)(info,pos,newrec))
- goto err;
-
- info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV |
- key_changed);
- nisam_log_record(LOG_UPDATE,info,newrec,info->lastpos,0);
- VOID(_nisam_writeinfo(info,test(key_changed)));
- allow_break(); /* Allow SIGHUP & SIGINT */
- DBUG_RETURN(0);
-
-err:
- DBUG_PRINT("error",("key: %d errno: %d",i,my_errno));
- save_errno=my_errno;
- if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
- {
- info->errkey= (int) i;
- flag=0;
- do
- {
- length=_nisam_make_key(info,i,new_key,newrec,pos);
- if (length != _nisam_make_key(info,i,old_key,oldrec,pos) ||
- memcmp((byte*) old_key,(byte*) new_key,length))
- {
- if ((flag++ && _nisam_ck_delete(info,i,new_key)) ||
- _nisam_ck_write(info,i,old_key))
- break;
- }
- } while (i-- != 0);
- }
- info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV |
- key_changed);
- err_end:
- nisam_log_record(LOG_UPDATE,info,newrec,info->lastpos,save_errno);
- VOID(_nisam_writeinfo(info,1));
- allow_break(); /* Allow SIGHUP & SIGINT */
- my_errno=(save_errno == HA_ERR_KEY_NOT_FOUND) ? HA_ERR_CRASHED : save_errno;
- DBUG_RETURN(-1);
-} /* nisam_update */
diff --git a/isam/write.c b/isam/write.c
deleted file mode 100644
index f2c0d8dbc45..00000000000
--- a/isam/write.c
+++ /dev/null
@@ -1,840 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Skriver ett record till en isam-databas */
-
-#include "isamdef.h"
-#ifdef __WIN__
-#include <errno.h>
-#endif
-
- /* Functions declared in this file */
-
-static int w_search(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
- ulong pos, uchar *father_buff, uchar *father_keypos,
- ulong father_page);
-static int _nisam_balance_page(N_INFO *info,N_KEYDEF *keyinfo,uchar *key,
- uchar *curr_buff,uchar *father_buff,
- uchar *father_keypos,ulong father_page);
-
-
- /* Write new record to database */
-
-int nisam_write(N_INFO *info, const byte *record)
-{
- uint i;
- ulong filepos;
- uchar *buff;
- DBUG_ENTER("nisam_write");
- DBUG_PRINT("enter",("isam: %d data: %d",info->s->kfile,info->dfile));
-
- if (info->s->base.options & HA_OPTION_READ_ONLY_DATA)
- {
- my_errno=EACCES;
- DBUG_RETURN(-1);
- }
-#ifndef NO_LOCKING
- if (_nisam_readinfo(info,F_WRLCK,1)) DBUG_RETURN(-1);
-#endif
- dont_break(); /* Dont allow SIGHUP or SIGINT */
-#if !defined(NO_LOCKING) && defined(USE_RECORD_LOCK)
- if (!info->locked && my_lock(info->dfile,F_WRLCK,0L,F_TO_EOF,
- MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
- goto err;
-#endif
- filepos= ((info->s->state.dellink != NI_POS_ERROR) ?
- info->s->state.dellink :
- info->s->state.data_file_length);
-
- if (info->s->base.reloc == 1L && info->s->base.records == 1L &&
- info->s->state.records == 1L)
- { /* System file */
- my_errno=HA_ERR_RECORD_FILE_FULL;
- goto err2;
- }
- if (info->s->state.key_file_length >=
- info->s->base.max_key_file_length -
- info->s->blocksize* INDEX_BLOCK_MARGIN *info->s->state.keys)
- {
- my_errno=HA_ERR_INDEX_FILE_FULL;
- goto err2;
- }
-
- /* Write all keys to indextree */
- buff=info->lastkey+info->s->base.max_key_length;
- for (i=0 ; i < info->s->state.keys ; i++)
- {
- VOID(_nisam_make_key(info,i,buff,record,filepos));
- if (_nisam_ck_write(info,i,buff)) goto err;
- }
-
- if ((*info->s->write_record)(info,record))
- goto err;
-
- info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED |HA_STATE_AKTIV |
- HA_STATE_WRITTEN);
- info->s->state.records++;
- info->lastpos=filepos;
- nisam_log_record(LOG_WRITE,info,record,filepos,0);
- VOID(_nisam_writeinfo(info,1));
- allow_break(); /* Allow SIGHUP & SIGINT */
- DBUG_RETURN(0);
-
-err:
- if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
- {
- info->errkey= (int) i;
- while ( i-- > 0)
- {
- VOID(_nisam_make_key(info,i,buff,record,filepos));
- if (_nisam_ck_delete(info,i,buff))
- break;
- }
- }
- info->update=(HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_WRITTEN);
-err2:
- nisam_log_record(LOG_WRITE,info,record,filepos,my_errno);
- VOID(_nisam_writeinfo(info,1));
- allow_break(); /* Allow SIGHUP & SIGINT */
- DBUG_RETURN(-1);
-} /* nisam_write */
-
-
- /* Write one key to btree */
-
-int _nisam_ck_write(register N_INFO *info, uint keynr, uchar *key)
-{
- int error;
- DBUG_ENTER("_nisam_ck_write");
-
- if ((error=w_search(info,info->s->keyinfo+keynr,key,
- info->s->state.key_root[keynr], (uchar *) 0, (uchar*) 0,
- 0L)) > 0)
- error=_nisam_enlarge_root(info,keynr,key);
- DBUG_RETURN(error);
-} /* _nisam_ck_write */
-
-
- /* Make a new root with key as only pointer */
-
-int _nisam_enlarge_root(register N_INFO *info, uint keynr, uchar *key)
-{
- uint t_length,nod_flag;
- reg2 N_KEYDEF *keyinfo;
- S_PARAM s_temp;
- ISAM_SHARE *share=info->s;
- DBUG_ENTER("_nisam_enlarge_root");
-
- info->page_changed=1;
- nod_flag= (share->state.key_root[keynr] != NI_POS_ERROR) ?
- share->base.key_reflength : 0;
- _nisam_kpointer(info,info->buff+2,share->state.key_root[keynr]); /* if nod */
- keyinfo=share->keyinfo+keynr;
- t_length=_nisam_get_pack_key_length(keyinfo,nod_flag,(uchar*) 0,(uchar*) 0,
- key,&s_temp);
- putint(info->buff,t_length+2+nod_flag,nod_flag);
- _nisam_store_key(keyinfo,info->buff+2+nod_flag,&s_temp);
- if ((share->state.key_root[keynr]= _nisam_new(info,keyinfo)) ==
- NI_POS_ERROR ||
- _nisam_write_keypage(info,keyinfo,share->state.key_root[keynr],info->buff))
- DBUG_RETURN(-1);
- DBUG_RETURN(0);
-} /* _nisam_enlarge_root */
-
-
- /* S|ker reda p} vart nyckeln skall s{ttas och placerar den dit */
- /* Returnerar -1 om fel ; 0 om ok. 1 om nyckel propagerar upp}t */
-
-static int w_search(register N_INFO *info, register N_KEYDEF *keyinfo,
- uchar *key, ulong page, uchar *father_buff,
- uchar *father_keypos, ulong father_page)
-{
- int error,flag;
- uint comp_flag,nod_flag;
- uchar *temp_buff,*keypos;
- uchar keybuff[N_MAX_KEY_BUFF];
- DBUG_ENTER("w_search");
- DBUG_PRINT("enter",("page: %ld",page));
-
- if (page == NI_POS_ERROR)
- DBUG_RETURN(1); /* No key, make new */
-
- if (keyinfo->base.flag & HA_SORT_ALLOWS_SAME)
- comp_flag=SEARCH_BIGGER; /* Put after same key */
- else if (keyinfo->base.flag & HA_NOSAME)
- comp_flag=SEARCH_FIND; /* No dupplicates */
- else
- comp_flag=SEARCH_SAME; /* Keys in rec-pos order */
-
- if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->base.block_length+
- N_MAX_KEY_BUFF)))
- DBUG_RETURN(-1);
- if (!_nisam_fetch_keypage(info,keyinfo,page,temp_buff,0))
- goto err;
-
- flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,0,comp_flag,&keypos,
- keybuff);
- nod_flag=test_if_nod(temp_buff);
- if (flag == 0)
- {
- my_errno=HA_ERR_FOUND_DUPP_KEY;
- /* get position to record with dupplicated key */
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff));
- info->dupp_key_pos=_nisam_dpos(info,test_if_nod(temp_buff),keypos);
- my_afree((byte*) temp_buff);
- DBUG_RETURN(-1);
- }
- if ((error=w_search(info,keyinfo,key,_nisam_kpos(nod_flag,keypos),
- temp_buff,keypos,page)) >0)
- {
- error=_nisam_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
- father_keypos,father_page);
- if (_nisam_write_keypage(info,keyinfo,page,temp_buff))
- goto err;
- }
- my_afree((byte*) temp_buff);
- DBUG_RETURN(error);
-err:
- my_afree((byte*) temp_buff);
- DBUG_PRINT("exit",("Error: %d",my_errno));
- DBUG_RETURN (-1);
-} /* w_search */
-
-
- /* Insert new key at right of key_pos */
- /* Returns 2 if key contains key to upper level */
-
-int _nisam_insert(register N_INFO *info, register N_KEYDEF *keyinfo,
- uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
- uchar *father_buff, uchar *father_key_pos, ulong father_page)
-{
- uint a_length,t_length,nod_flag;
- uchar *endpos;
- int key_offset;
- S_PARAM s_temp;
- DBUG_ENTER("_nisam_insert");
- DBUG_PRINT("enter",("key_pos: %lx",key_pos));
- DBUG_EXECUTE("key",_nisam_print_key(DBUG_FILE,keyinfo->seg,key););
-
- nod_flag=test_if_nod(anc_buff);
- a_length=getint(anc_buff);
- endpos= anc_buff+ a_length;
- t_length=_nisam_get_pack_key_length(keyinfo,nod_flag,
- (key_pos == endpos ? (uchar*) 0 : key_pos),
- (key_pos == anc_buff+2+nod_flag ?
- (uchar*) 0 : key_buff),key,&s_temp);
-#ifndef DBUG_OFF
- if (key_pos != anc_buff+2+nod_flag)
- DBUG_DUMP("prev_key",(byte*) key_buff,_nisam_keylength(keyinfo,key_buff));
- if (keyinfo->base.flag & HA_PACK_KEY)
- {
- DBUG_PRINT("test",("t_length: %d ref_len: %d",
- t_length,s_temp.ref_length));
- DBUG_PRINT("test",("n_ref_len: %d n_length: %d key: %lx",
- s_temp.n_ref_length,s_temp.n_length,s_temp.key));
- }
-#endif
- key_offset = (uint)(endpos-key_pos);
- if((int) t_length < 0)
- key_offset += (int) t_length;
- if (key_offset < 0)
- {
- DBUG_PRINT("error",("Found a bug: negative key_offset %d\n", key_offset));
- DBUG_RETURN(-1);
- }
- if ((int) t_length >= 0) /* t_length is almost always > 0 */
- bmove_upp((byte*) endpos+t_length,(byte*) endpos,(uint)key_offset );
- else
- {
- /* This may happen if a key was deleted and the next key could be
- compressed better than before */
- DBUG_DUMP("anc_buff",(byte*) anc_buff,a_length);
-
- bmove(key_pos,key_pos - (int) t_length,(uint)key_offset);
- }
- _nisam_store_key(keyinfo,key_pos,&s_temp);
- a_length+=t_length;
- putint(anc_buff,a_length,nod_flag);
- if (a_length <= keyinfo->base.block_length)
- DBUG_RETURN(0); /* There is room on page */
-
- /* Page is full */
-
- if (!(keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)) &&
- father_buff)
- DBUG_RETURN(_nisam_balance_page(info,keyinfo,key,anc_buff,father_buff,
- father_key_pos,father_page));
- DBUG_RETURN(_nisam_splitt_page(info,keyinfo,key,anc_buff,key_buff));
-} /* _nisam_insert */
-
-
- /* splitt a full page in two and assign emerging item to key */
-
-int _nisam_splitt_page(register N_INFO *info, register N_KEYDEF *keyinfo,
- uchar *key, uchar *buff, uchar *key_buff)
-{
- uint length,a_length,key_ref_length,t_length,nod_flag;
- uchar *key_pos,*pos;
- ulong new_pos;
- S_PARAM s_temp;
- DBUG_ENTER("ni_splitt_page");
- DBUG_DUMP("buff",(byte*) buff,getint(buff));
-
- nod_flag=test_if_nod(buff);
- key_ref_length=2+nod_flag;
- key_pos=_nisam_find_half_pos(info,keyinfo,buff,key_buff);
- length=(uint) (key_pos-buff);
- a_length=getint(buff);
- putint(buff,length,nod_flag);
- info->page_changed=1;
-
- /* Correct new page pointer */
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff));
- if (nod_flag)
- {
- DBUG_PRINT("test",("Splitting nod"));
- pos=key_pos-nod_flag;
- memcpy((byte*) info->buff+2,(byte*) pos,(size_t) nod_flag);
- }
-
- /* Move midle item to key and pointer to new page */
- if ((new_pos=_nisam_new(info,keyinfo)) == NI_POS_ERROR)
- DBUG_RETURN(-1);
- _nisam_kpointer(info,_nisam_move_key(keyinfo,key,key_buff),new_pos);
-
- /* Store new page */
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff));
- t_length=_nisam_get_pack_key_length(keyinfo,nod_flag,(uchar *) 0, (uchar*) 0,
- key_buff, &s_temp);
- s_temp.n_length= *key_pos; /* Needed by ni_store_key */
- length=(uint) ((buff+a_length)-key_pos);
- memcpy((byte*) info->buff+key_ref_length+t_length,(byte*) key_pos,
- (size_t) length);
- _nisam_store_key(keyinfo,info->buff+key_ref_length,&s_temp);
- putint(info->buff,length+t_length+key_ref_length,nod_flag);
-
- if (_nisam_write_keypage(info,keyinfo,new_pos,info->buff))
- DBUG_RETURN(-1);
- DBUG_DUMP("key",(byte*) key,_nisam_keylength(keyinfo,key));
- DBUG_RETURN(2); /* Middle key up */
-} /* _nisam_splitt_page */
-
-
- /* find out how much more room a key will take */
-
-#ifdef QQ
-uint _nisam_get_pack_key_length(N_KEYDEF *keyinfo, uint nod_flag, uchar *key_pos, uchar *key_buff, uchar *key, S_PARAM *s_temp)
-
- /* If nod: Length of nod-pointer */
- /* Position to pos after key in buff */
- /* Last key before current key */
- /* Current key */
- /* How next key will be packed */
-{
- reg1 N_KEYSEG *keyseg;
- int length;
- uint key_length,ref_length,n_length,diff_flag,same_length;
- uchar *start,*end,*key_end;
-
- s_temp->key=key;
- if (!(keyinfo->base.flag & HA_PACK_KEY))
- return (s_temp->totlength=_nisam_keylength(keyinfo,key)+nod_flag);
- s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
- s_temp->prev_length=0;
-
- same_length=0; keyseg=keyinfo->seg;
- key_length=_nisam_keylength(keyinfo,key)+nod_flag;
-
- if (keyseg->base.flag & HA_SPACE_PACK)
- {
- diff_flag=1;
- end=key_end= key+ *key+1;
- if (key_buff)
- {
- if (*key == *key_buff && *key)
- same_length=1; /* Don't use key-pack if length == 0 */
- else if (*key > *key_buff)
- end=key+ *key_buff+1;
- key_buff++;
- }
- key++;
- }
- else
- {
- diff_flag=0;
- key_end=end= key+keyseg->base.length;
- }
-
- start=key;
- if (key_buff)
- while (key < end && *key == *key_buff)
- {
- key++; key_buff++;
- }
-
- s_temp->key=key; s_temp->key_length= (uint) (key_end-key);
-
- if (same_length && key == key_end)
- {
- s_temp->ref_length=128;
- length=(int) key_length-(int)(key_end-start); /* Same as prev key */
- if (key_pos)
- {
- s_temp->n_length= *key_pos;
- key_pos=0; /* Can't combine with next */
- }
- }
- else
- {
- if (start != key)
- { /* Starts as prev key */
- s_temp->ref_length= (uint) (key-start)+128;
- length=(int) (1+key_length-(uint) (key-start));
- }
- else
- length=(int) (key_length+ (1-diff_flag)); /* Not packed key */
- }
- s_temp->totlength=(uint) length;
-
- DBUG_PRINT("test",("tot_length: %d length: %d uniq_key_length: %d",
- key_length,length,s_temp->key_length));
-
- /* If something after that is not 0 length test if we can combine */
-
- if (key_pos && (n_length= *key_pos))
- {
- key_pos++;
- ref_length=0;
- if (n_length & 128)
- {
- if ((ref_length=n_length & 127))
- if (diff_flag)
- n_length= *key_pos++; /* Length of key-part */
- else
- n_length=keyseg->base.length - ref_length;
- }
- else
- if (*start == *key_pos && diff_flag && start != key_end)
- length++; /* One new pos for ref.len */
-
- DBUG_PRINT("test",("length: %d key_pos: %lx",length,key_pos));
- if (n_length != 128)
- { /* Not same key after */
- key=start+ref_length;
- while (n_length > 0 && key < key_end && *key == *key_pos)
- {
- key++; key_pos++;
- ref_length++;
- n_length--;
- length--; /* We gained one char */
- }
-
- if (n_length == 0 && diff_flag)
- {
- n_length=128; /* Same as prev key */
- length--; /* We don't need key-length */
- }
- else if (ref_length)
- s_temp->n_ref_length=ref_length | 128;
- }
- s_temp->n_length=n_length;
- }
- return (uint) length;
-} /* _nisam_get_pack_key_length */
-
-#else
-
-uint
-_nisam_get_pack_key_length(N_KEYDEF *keyinfo,
- uint nod_flag, /* If nod: Length of nod-pointer */
- uchar *key_pos, /* Position to pos after key in buff */
- uchar *key_buff,/* Last key before current key */
- uchar *key, /* Current key */
- S_PARAM *s_temp/* How next key will be packed */
- )
-{
- reg1 N_KEYSEG *keyseg;
- int length;
- uint key_length,ref_length,n_length,diff_flag,same_length,org_key_length=0;
- uchar *start,*end,*key_end;
-
- s_temp->key=key;
- if (!(keyinfo->base.flag & HA_PACK_KEY))
- return (s_temp->totlength=_nisam_keylength(keyinfo,key)+nod_flag);
- s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
-
- same_length=0; keyseg=keyinfo->seg;
- key_length=_nisam_keylength(keyinfo,key)+nod_flag;
- s_temp->prev_key=key_buff;
-
- if (keyseg->base.flag & HA_SPACE_PACK)
- {
- diff_flag=1;
- end=key_end= key+ *key+1;
- if (key_buff)
- {
- org_key_length= (uint) *key_buff;
- if (*key == *key_buff && *key)
- same_length=1; /* Don't use key-pack if length == 0 */
- else if (*key > *key_buff)
- end=key+ org_key_length+1;
- key_buff++;
- }
- key++;
- }
- else
- {
- diff_flag=0;
- key_end=end= key+(org_key_length=keyseg->base.length);
- }
-
- start=key;
- if (key_buff)
- while (key < end && *key == *key_buff)
- {
- key++; key_buff++;
- }
-
- s_temp->key=key; s_temp->key_length= (uint) (key_end-key);
-
- if (same_length && key == key_end)
- {
- s_temp->ref_length=128;
- length=(int) key_length-(int)(key_end-start); /* Same as prev key */
- if (key_pos)
- { /* Can't combine with next */
- s_temp->n_length= *key_pos; /* Needed by _nisam_store_key */
- key_pos=0;
- }
- }
- else
- {
- if (start != key)
- { /* Starts as prev key */
- s_temp->ref_length= (uint) (key-start)+128;
- length=(int) (1+key_length-(uint) (key-start));
- }
- else
- length=(int) (key_length+ (1-diff_flag)); /* Not packed key */
- }
- s_temp->totlength=(uint) length;
- s_temp->prev_length=0;
- DBUG_PRINT("test",("tot_length: %d length: %d uniq_key_length: %d",
- key_length,length,s_temp->key_length));
-
- /* If something after that is not 0 length test if we can combine */
-
- if (key_pos && (n_length= *key_pos++))
- {
- if (n_length == 128)
- {
- /*
- We put a different key between two identical keys
- Extend next key to have same prefix as this key
- */
- if (s_temp->ref_length)
- { /* make next key longer */
- s_temp->part_of_prev_key= s_temp->ref_length;
- s_temp->prev_length= org_key_length - (s_temp->ref_length-128);
- s_temp->n_length= s_temp->prev_length;
- s_temp->prev_key+= diff_flag + (s_temp->ref_length - 128);
- length+= s_temp->prev_length+diff_flag;
- }
- else
- { /* Can't use prev key */
- s_temp->part_of_prev_key=0;
- s_temp->prev_length= org_key_length;
- s_temp->n_length= org_key_length;
- s_temp->prev_key+= diff_flag; /* To start of key */
- length+= org_key_length;
- }
- return (uint) length;
- }
-
- if (n_length & 128)
- {
- ref_length=n_length & 127;
- if (diff_flag) /* If SPACE_PACK */
- n_length= *key_pos++; /* Length of key-part */
- else
- n_length=keyseg->base.length - ref_length;
-
- /* Test if new keys has fewer characters that match the previous key */
- if (!s_temp->ref_length)
- { /* Can't use prev key */
- s_temp->part_of_prev_key= 0;
- s_temp->prev_length= ref_length;
- s_temp->n_length= n_length+ref_length;
- s_temp->prev_key+= diff_flag; /* To start of key */
- return (uint) length+ref_length-diff_flag;
- }
- if (ref_length+128 > s_temp->ref_length)
- {
- /* We must copy characters from the original key to the next key */
- s_temp->part_of_prev_key= s_temp->ref_length;
- s_temp->prev_length= ref_length+128 - s_temp->ref_length;
- s_temp->n_length= n_length + s_temp->prev_length;
- s_temp->prev_key+= diff_flag + s_temp->ref_length -128;
- return (uint) length + s_temp->prev_length;
- }
- }
- else
- {
- ref_length=0;
- if (*start == *key_pos && diff_flag && start != key_end)
- length++; /* One new pos for ref.len */
- }
- DBUG_PRINT("test",("length: %d key_pos: %lx",length,key_pos));
-
- key=start+ref_length;
- while (n_length > 0 && key < key_end && *key == *key_pos)
- {
- key++; key_pos++;
- ref_length++;
- n_length--;
- length--; /* We gained one char */
- }
-
- if (n_length == 0 && diff_flag)
- {
- n_length=128; /* Same as prev key */
- length--; /* We don't need key-length */
- }
- else if (ref_length)
- s_temp->n_ref_length=ref_length | 128;
- s_temp->n_length=n_length;
- }
- return (uint) length;
-} /* _nisam_get_pack_key_length */
-#endif
-
-
- /* store a key in page-buffert */
-
-void _nisam_store_key(N_KEYDEF *keyinfo, register uchar *key_pos,
- register S_PARAM *s_temp)
-{
- uint length;
- uchar *start;
-
- if (! (keyinfo->base.flag & HA_PACK_KEY))
- {
- memcpy((byte*) key_pos,(byte*) s_temp->key,(size_t) s_temp->totlength);
- return;
- }
- start=key_pos;
- if ((*key_pos=(uchar) s_temp->ref_length))
- key_pos++;
- if (s_temp->ref_length == 0 ||
- (s_temp->ref_length > 128 &&
- (keyinfo->seg[0].base.flag & HA_SPACE_PACK)))
- *key_pos++= (uchar) s_temp->key_length;
- bmove((byte*) key_pos,(byte*) s_temp->key,
- (length=s_temp->totlength-(uint) (key_pos-start)));
- key_pos+=length;
-
- if (s_temp->prev_length)
- {
- /* Extend next key because new key didn't have same prefix as prev key */
- if (s_temp->part_of_prev_key)
- *key_pos++ = s_temp->part_of_prev_key;
- if (keyinfo->seg[0].base.flag & HA_SPACE_PACK)
- *key_pos++= s_temp->n_length;
- memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
- return;
- }
-
- if ((*key_pos = (uchar) s_temp->n_ref_length))
- {
- if (! (keyinfo->seg[0].base.flag & HA_SPACE_PACK))
- return; /* Don't save keylength */
- key_pos++; /* Store ref for next key */
- }
- *key_pos = (uchar) s_temp->n_length;
- return;
-} /* _nisam_store_key */
-
-
- /* Calculate how to much to move to split a page in two */
- /* Returns pointer and key for get_key() to get mid key */
- /* There is at last 2 keys after pointer in buff */
-
-uchar *_nisam_find_half_pos(N_INFO *info, N_KEYDEF *keyinfo, uchar *page, uchar *key)
-{
- uint keys,length,key_ref_length,nod_flag;
- uchar *end,*lastpos;
- DBUG_ENTER("_nisam_find_half_pos");
-
- nod_flag=test_if_nod(page);
- key_ref_length=2+nod_flag;
- length=getint(page)-key_ref_length;
- page+=key_ref_length;
- if (!(keyinfo->base.flag & (HA_PACK_KEY | HA_SPACE_PACK_USED)))
- {
- keys=(length/(keyinfo->base.keylength+nod_flag))/2;
- DBUG_RETURN(page+keys*(keyinfo->base.keylength+nod_flag));
- }
-
- end=page+length/2-key_ref_length; /* This is aprox. half */
- *key='\0';
- do
- {
- lastpos=page;
- VOID((*keyinfo->get_key)(keyinfo,nod_flag,&page,key));
- } while (page < end);
-
- DBUG_PRINT("exit",("returns: %lx page: %lx half: %lx",lastpos,page,end));
- DBUG_RETURN(lastpos);
-} /* _nisam_find_half_pos */
-
-
- /* Balance page with not packed keys with page on right/left */
- /* returns 0 if balance was done */
-
-static int _nisam_balance_page(register N_INFO *info, N_KEYDEF *keyinfo,
- uchar *key, uchar *curr_buff, uchar *father_buff,
- uchar *father_key_pos, ulong father_page)
-{
- my_bool right;
- uint k_length,father_length,father_keylength,nod_flag,curr_keylength,
- right_length,left_length,new_right_length,new_left_length,extra_length,
- length,keys;
- uchar *pos,*buff,*extra_buff;
- ulong next_page,new_pos;
- byte tmp_part_key[N_MAX_KEY_BUFF];
- DBUG_ENTER("_nisam_balance_page");
-
- k_length=keyinfo->base.keylength;
- father_length=getint(father_buff);
- father_keylength=k_length+info->s->base.key_reflength;
- nod_flag=test_if_nod(curr_buff);
- curr_keylength=k_length+nod_flag;
- info->page_changed=1;
-
- if ((father_key_pos != father_buff+father_length && (info->s->rnd++ & 1)) ||
- father_key_pos == father_buff+2+info->s->base.key_reflength)
- {
- right=1;
- next_page= _nisam_kpos(info->s->base.key_reflength,
- father_key_pos+father_keylength);
- buff=info->buff;
- DBUG_PRINT("test",("use right page: %lu",next_page));
- }
- else
- {
- right=0;
- father_key_pos-=father_keylength;
- next_page= _nisam_kpos(info->s->base.key_reflength,father_key_pos);
- /* Fix that curr_buff is to left */
- buff=curr_buff; curr_buff=info->buff;
- DBUG_PRINT("test",("use left page: %lu",next_page));
- } /* father_key_pos ptr to parting key */
-
- if (!_nisam_fetch_keypage(info,keyinfo,next_page,info->buff,0))
- goto err;
- DBUG_DUMP("next",(byte*) info->buff,getint(info->buff));
-
- /* Test if there is room to share keys */
-
- left_length=getint(curr_buff);
- right_length=getint(buff);
- keys=(left_length+right_length-4-nod_flag*2)/curr_keylength;
-
- if ((right ? right_length : left_length) + curr_keylength <=
- keyinfo->base.block_length)
- { /* Merge buffs */
- new_left_length=2+nod_flag+(keys/2)*curr_keylength;
- new_right_length=2+nod_flag+((keys+1)/2)*curr_keylength;
- putint(curr_buff,new_left_length,nod_flag);
- putint(buff,new_right_length,nod_flag);
-
- if (left_length < new_left_length)
- { /* Move keys buff -> leaf */
- pos=curr_buff+left_length;
- memcpy((byte*) pos,(byte*) father_key_pos, (size_t) k_length);
- memcpy((byte*) pos+k_length, (byte*) buff+2,
- (size_t) (length=new_left_length - left_length - k_length));
- pos=buff+2+length;
- memcpy((byte*) father_key_pos,(byte*) pos,(size_t) k_length);
- bmove((byte*) buff+2,(byte*) pos+k_length,new_right_length);
- }
- else
- { /* Move keys -> buff */
-
- bmove_upp((byte*) buff+new_right_length,(byte*) buff+right_length,
- right_length-2);
- length=new_right_length-right_length-k_length;
- memcpy((byte*) buff+2+length,father_key_pos,(size_t) k_length);
- pos=curr_buff+new_left_length;
- memcpy((byte*) father_key_pos,(byte*) pos,(size_t) k_length);
- memcpy((byte*) buff+2,(byte*) pos+k_length,(size_t) length);
- }
-
- if (_nisam_write_keypage(info,keyinfo,next_page,info->buff) ||
- _nisam_write_keypage(info,keyinfo,father_page,father_buff))
- goto err;
- DBUG_RETURN(0);
- }
-
- /* curr_buff[] and buff[] are full, lets splitt and make new nod */
-
- extra_buff=info->buff+info->s->base.max_block;
- new_left_length=new_right_length=2+nod_flag+(keys+1)/3*curr_keylength;
- if (keys == 5) /* Too few keys to balance */
- new_left_length-=curr_keylength;
- extra_length=nod_flag+left_length+right_length-new_left_length-new_right_length-curr_keylength;
- DBUG_PRINT("info",("left_length: %d right_length: %d new_left_length: %d new_right_length: %d extra_length: %d",
- left_length, right_length,
- new_left_length, new_right_length,
- extra_length));
- putint(curr_buff,new_left_length,nod_flag);
- putint(buff,new_right_length,nod_flag);
- putint(extra_buff,extra_length+2,nod_flag);
-
- /* move first largest keys to new page */
- pos=buff+right_length-extra_length;
- memcpy((byte*) extra_buff+2,pos,(size_t) extra_length);
-
- /* Save new parting key */
- memcpy(tmp_part_key, pos-k_length,k_length);
-
- /* Make place for new keys */
- bmove_upp((byte*) buff+new_right_length,(byte*) pos-k_length,
- right_length-extra_length-k_length-2);
- /* Copy keys from left page */
- pos= curr_buff+new_left_length;
- memcpy((byte*) buff+2,(byte*) pos+k_length,
- (size_t) (length=left_length-new_left_length-k_length));
- /* Copy old parting key */
- memcpy((byte*) buff+2+length,father_key_pos,(size_t) k_length);
-
- /* Move new parting keys up */
- memcpy((byte*) (right ? key : father_key_pos),pos, (size_t) k_length);
- memcpy((byte*) (right ? father_key_pos : key), tmp_part_key, k_length);
-
- if ((new_pos=_nisam_new(info,keyinfo)) == NI_POS_ERROR)
- goto err;
- _nisam_kpointer(info,key+k_length,new_pos);
- if (_nisam_write_keypage(info,keyinfo,(right ? new_pos : next_page),
- info->buff) ||
- _nisam_write_keypage(info,keyinfo,(right ? next_page : new_pos),extra_buff))
- goto err;
-
- DBUG_RETURN(1); /* Middle key up */
-
-err:
- DBUG_RETURN(-1);
-} /* _nisam_balance_page */
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
index 72ff44ecef3..0670a0befa8 100644
--- a/libmysql/Makefile.am
+++ b/libmysql/Makefile.am
@@ -23,7 +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@
+INCLUDES = -I$(top_srcdir)/include $(openssl_includes) @ZLIB_INCLUDES@ \
+ -I$(top_builddir)/include
include $(srcdir)/Makefile.shared
diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared
index 23a8201cbf6..204c833dd21 100644
--- a/libmysql/Makefile.shared
+++ b/libmysql/Makefile.shared
@@ -42,7 +42,7 @@ mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \
bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \
strtoull.lo strtoll.lo llstr.lo my_vsnprintf.lo \
ctype.lo ctype-simple.lo ctype-bin.lo ctype-mb.lo \
- ctype-big5.lo ctype-czech.lo ctype-euc_kr.lo \
+ ctype-big5.lo ctype-czech.lo ctype-cp932.lo ctype-eucjpms.lo ctype-euc_kr.lo \
ctype-win1250ch.lo ctype-utf8.lo ctype-extra.lo \
ctype-ucs2.lo ctype-gb2312.lo ctype-gbk.lo \
ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo \
@@ -65,8 +65,9 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
my_compress.lo array.lo my_once.lo list.lo my_net.lo \
charset.lo charset-def.lo hash.lo mf_iocache.lo \
mf_iocache2.lo my_seek.lo my_sleep.lo \
- my_pread.lo mf_cache.lo md5.lo sha1.lo\
- my_getopt.lo my_gethostbyname.lo my_port.lo
+ my_pread.lo mf_cache.lo md5.lo sha1.lo \
+ my_getopt.lo my_gethostbyname.lo my_port.lo \
+ my_rename.lo
sqlobjects = net.lo
sql_cmn_objects = pack.lo client.lo my_time.lo
@@ -81,6 +82,7 @@ CLEANFILES = $(target_libadd) $(SHLIBOBJS) \
$(target)
DEFS = -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DDEFAULT_HOME_ENV=MYSQL_HOME \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" $(target_defs)
# The automatic dependencies miss this
diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h
index f53f054a28d..e0f093aa7c9 100644
--- a/libmysql/client_settings.h
+++ b/libmysql/client_settings.h
@@ -21,7 +21,7 @@ extern my_string mysql_unix_port;
CLIENT_TRANSACTIONS | \
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION)
-sig_handler pipe_sig_handler(int sig);
+sig_handler my_pipe_sig_handler(int sig);
void read_user_name(char *name);
my_bool handle_local_infile(MYSQL *mysql, const char *net_filename);
@@ -32,7 +32,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename);
#if !defined(__WIN__) && defined(SIGPIPE) && !defined(THREAD)
#define init_sigpipe_variables sig_return old_signal_handler=(sig_return) 0;
-#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler)
+#define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE, my_pipe_sig_handler)
#define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler);
#else
#define init_sigpipe_variables
@@ -43,7 +43,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename);
void mysql_read_default_options(struct st_mysql_options *options,
const char *filename,const char *group);
void mysql_detach_stmt_list(LIST **stmt_list);
-MYSQL * STDCALL
+MYSQL *
cli_mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,ulong client_flag);
diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c
index 5fa94e5ff0d..90ad3aefaca 100644
--- a/libmysql/errmsg.c
+++ b/libmysql/errmsg.c
@@ -205,7 +205,33 @@ const char *client_errors[]=
#endif
+/*
+ Register client error messages for use with my_error().
+
+ SYNOPSIS
+ init_client_errs()
+
+ RETURN
+ void
+*/
+
void init_client_errs(void)
{
- my_errmsg[CLIENT_ERRMAP] = &client_errors[0];
+ (void) my_error_register(client_errors, CR_ERROR_FIRST, CR_ERROR_LAST);
+}
+
+
+/*
+ Unregister client error messages.
+
+ SYNOPSIS
+ finish_client_errs()
+
+ RETURN
+ void
+*/
+
+void finish_client_errs(void)
+{
+ (void) my_error_unregister(CR_ERROR_FIRST, CR_ERROR_LAST);
}
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index c663dab7476..bf797dfd580 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -92,7 +92,7 @@ my_bool net_flush(NET *net);
#define unsigned_field(A) ((A)->flags & UNSIGNED_FLAG)
static void append_wild(char *to,char *end,const char *wild);
-sig_handler pipe_sig_handler(int sig);
+sig_handler my_pipe_sig_handler(int sig);
static my_bool mysql_client_init= 0;
static my_bool org_my_init_done= 0;
@@ -186,6 +186,7 @@ void STDCALL mysql_server_end()
}
else
mysql_thread_end();
+ finish_client_errs();
free_charsets();
mysql_client_init= org_my_init_done= 0;
}
@@ -294,11 +295,11 @@ mysql_debug(const char *debug __attribute__((unused)))
**************************************************************************/
sig_handler
-pipe_sig_handler(int sig __attribute__((unused)))
+my_pipe_sig_handler(int sig __attribute__((unused)))
{
DBUG_PRINT("info",("Hit by signal %d",sig));
#ifdef DONT_REMEMBER_SIGNAL
- (void) signal(SIGPIPE,pipe_sig_handler);
+ (void) signal(SIGPIPE, my_pipe_sig_handler);
#endif
}
@@ -319,6 +320,7 @@ my_bool STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
DBUG_ENTER("mysql_master_send_query");
if (!master->net.vio && !mysql_real_connect(master,0,0,0,0,0,0,0))
DBUG_RETURN(1);
+ master->reconnect= 1;
mysql->last_used_con = master;
DBUG_RETURN(simple_command(master, COM_QUERY, q, length, 1));
}
@@ -353,6 +355,7 @@ my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
if (!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0,
0,0,0,0))
DBUG_RETURN(1);
+ slave_to_use->reconnect= 1;
DBUG_RETURN(simple_command(slave_to_use, COM_QUERY, q, length, 1));
}
@@ -450,6 +453,7 @@ static my_bool get_slaves_from_master(MYSQL* mysql)
expand_error(mysql, CR_PROBE_MASTER_CONNECT);
DBUG_RETURN(1);
}
+ mysql->reconnect= 1;
if (mysql_query(mysql, "SHOW SLAVE HOSTS") ||
!(res = mysql_store_result(mysql)))
@@ -617,6 +621,7 @@ mysql_connect(MYSQL *mysql,const char *host,
if (mysql->free_me)
my_free((gptr) mysql,MYF(0));
}
+ mysql->reconnect= 1;
DBUG_RETURN(res);
}
}
@@ -1112,25 +1117,6 @@ mysql_fetch_field(MYSQL_RES *result)
/**************************************************************************
- Get column lengths of the current row
- If one uses mysql_use_result, res->lengths contains the length information,
- else the lengths are calculated from the offset between pointers.
-**************************************************************************/
-
-ulong * STDCALL
-mysql_fetch_lengths(MYSQL_RES *res)
-{
- MYSQL_ROW column;
-
- if (!(column=res->current_row))
- return 0; /* Something is wrong */
- if (res->data)
- (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
- return res->lengths;
-}
-
-
-/**************************************************************************
Move to a specific row and column
**************************************************************************/
@@ -1590,14 +1576,14 @@ mysql_hex_string(char *to, const char *from, ulong length)
ulong STDCALL
mysql_escape_string(char *to,const char *from,ulong length)
{
- return escape_string_for_mysql(default_charset_info, to, from, length);
+ return escape_string_for_mysql(default_charset_info, to, 0, from, length);
}
ulong STDCALL
mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
ulong length)
{
- return escape_string_for_mysql(mysql->charset, to, from, length);
+ return escape_string_for_mysql(mysql->charset, to, 0, from, length);
}
@@ -1728,6 +1714,7 @@ myodbc_remove_escape(MYSQL *mysql,char *name)
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);
/*
@@ -1735,6 +1722,7 @@ static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row);
STMT_ATTR_UPDATE_MAX_LENGTH attribute is set.
*/
static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data);
+static my_bool setup_one_fetch_function(MYSQL_BIND *bind, MYSQL_FIELD *field);
/*
Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
@@ -1758,6 +1746,20 @@ static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data);
#define MAX_DOUBLE_STRING_REP_LENGTH 331
+/* A macro to check truncation errors */
+
+#define IS_TRUNCATED(value, is_unsigned, min, max, umax) \
+ ((is_unsigned) ? (((value) > (umax) || (value) < 0) ? 1 : 0) : \
+ (((value) > (max) || (value) < (min)) ? 1 : 0))
+
+#define BIND_RESULT_DONE 1
+/*
+ We report truncations only if at least one of MYSQL_BIND::error
+ pointers is set. In this case stmt->bind_result_done |-ed with
+ this flag.
+*/
+#define REPORT_DATA_TRUNCATION 2
+
/**************** Misc utility functions ****************************/
/*
@@ -1858,12 +1860,14 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
{
uchar *pos;
uint field_count, param_count;
+ ulong packet_length;
MYSQL_DATA *fields_data;
- DBUG_ENTER("read_prepare_result");
+ DBUG_ENTER("cli_read_prepare_result");
mysql= mysql->last_used_con;
- if (net_safe_read(mysql) == packet_error)
+ if ((packet_length= net_safe_read(mysql)) == packet_error)
DBUG_RETURN(1);
+ mysql->warning_count= 0;
pos= (uchar*) mysql->net.read_pos;
stmt->stmt_id= uint4korr(pos+1); pos+= 5;
@@ -1871,6 +1875,8 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
field_count= uint2korr(pos); pos+= 2;
/* Number of placeholders in the statement */
param_count= uint2korr(pos); pos+= 2;
+ if (packet_length >= 12)
+ mysql->warning_count= uint2korr(pos+1);
if (param_count != 0)
{
@@ -1887,7 +1893,6 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS;
- mysql->extra_info= net_field_length_ll(&pos);
if (!(fields_data= (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,7)))
DBUG_RETURN(1);
if (!(stmt->fields= unpack_fields(fields_data,&stmt->mem_root,
@@ -1895,9 +1900,10 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
mysql->server_capabilities)))
DBUG_RETURN(1);
}
- stmt->field_count= (uint) field_count;
+ stmt->field_count= field_count;
stmt->param_count= (ulong) param_count;
- mysql->warning_count= 0;
+ DBUG_PRINT("exit",("field_count: %u param_count: %u warning_count: %u",
+ field_count, param_count, (uint) mysql->warning_count));
DBUG_RETURN(0);
}
@@ -2131,6 +2137,7 @@ static void update_stmt_fields(MYSQL_STMT *stmt)
MYSQL_FIELD *field= stmt->mysql->fields;
MYSQL_FIELD *field_end= field + stmt->field_count;
MYSQL_FIELD *stmt_field= stmt->fields;
+ MYSQL_BIND *bind= stmt->bind_result_done ? stmt->bind : 0;
DBUG_ASSERT(stmt->field_count == stmt->mysql->field_count);
@@ -2141,6 +2148,11 @@ static void update_stmt_fields(MYSQL_STMT *stmt)
stmt_field->type = field->type;
stmt_field->flags = field->flags;
stmt_field->decimals = field->decimals;
+ if (bind)
+ {
+ /* Ignore return value: it should be 0 if bind_result succeeded. */
+ (void) setup_one_fetch_function(bind++, stmt_field);
+ }
}
}
@@ -2443,11 +2455,11 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
char buff[4 /* size of stmt id */ +
5 /* execution flags */];
DBUG_ENTER("execute");
- DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length));
+ DBUG_DUMP("packet", packet, length);
mysql->last_used_con= mysql;
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
- buff[4]= (char) 0; /* no flags */
+ buff[4]= (char) stmt->flags;
int4store(buff+5, 1); /* iteration count */
if (cli_advanced_command(mysql, COM_EXECUTE, buff, sizeof(buff),
packet, length, 1) ||
@@ -2457,6 +2469,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
DBUG_RETURN(1);
}
stmt->affected_rows= mysql->affected_rows;
+ stmt->server_status= mysql->server_status;
stmt->insert_id= mysql->insert_id;
DBUG_RETURN(0);
}
@@ -2627,6 +2640,59 @@ error:
return rc;
}
+
+/*
+ Fetch statement row using server side cursor.
+
+ SYNOPSIS
+ stmt_read_row_from_cursor()
+
+ RETURN VALUE
+ 0 success
+ 1 error
+ MYSQL_NO_DATA end of data
+*/
+
+static int
+stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row)
+{
+ if (stmt->data_cursor)
+ return stmt_read_row_buffered(stmt, row);
+ if (stmt->server_status & SERVER_STATUS_LAST_ROW_SENT)
+ stmt->server_status &= ~SERVER_STATUS_LAST_ROW_SENT;
+ else
+ {
+ MYSQL *mysql= stmt->mysql;
+ NET *net= &mysql->net;
+ MYSQL_DATA *result= &stmt->result;
+ char buff[4 /* statement id */ +
+ 4 /* number of rows to fetch */];
+
+ free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
+ result->data= NULL;
+ result->rows= 0;
+ /* Send row request to the server */
+ int4store(buff, stmt->stmt_id);
+ int4store(buff + 4, 1); /* number of rows to fetch */
+ if (cli_advanced_command(mysql, COM_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;
+
+ stmt->data_cursor= result->data;
+ return stmt_read_row_buffered(stmt, row);
+ }
+ *row= 0;
+ return MYSQL_NO_DATA;
+}
+
+
/*
Default read row function to not SIGSEGV in client in
case of wrong sequence of API calls.
@@ -2668,6 +2734,9 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt,
case STMT_ATTR_UPDATE_MAX_LENGTH:
stmt->update_max_length= value ? *(const my_bool*) value : 0;
break;
+ case STMT_ATTR_CURSOR_TYPE:
+ stmt->flags= value ? *(const unsigned long *) value : 0;
+ break;
default:
return TRUE;
}
@@ -2683,6 +2752,9 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt,
case STMT_ATTR_UPDATE_MAX_LENGTH:
*(unsigned long *) value= stmt->update_max_length;
break;
+ case STMT_ATTR_CURSOR_TYPE:
+ *(unsigned long *) value= stmt->flags;
+ break;
default:
return TRUE;
}
@@ -2786,9 +2858,28 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
stmt->state= MYSQL_STMT_EXECUTE_DONE;
if (stmt->field_count)
{
- stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
- stmt->unbuffered_fetch_cancelled= FALSE;
- stmt->read_row_func= stmt_read_row_unbuffered;
+ if (stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
+ {
+ mysql->status= MYSQL_STATUS_READY;
+ stmt->read_row_func= stmt_read_row_from_cursor;
+ }
+ else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
+ {
+ /*
+ This is a single-row result set, a result set with no rows, EXPLAIN,
+ SHOW VARIABLES, or some other command which either a) bypasses the
+ cursors framework in the server and writes rows directly to the
+ network or b) is more efficient if all (few) result set rows are
+ precached on client and server's resources are freed.
+ */
+ DBUG_RETURN(mysql_stmt_store_result(stmt));
+ }
+ else
+ {
+ stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
+ stmt->unbuffered_fetch_cancelled= FALSE;
+ stmt->read_row_func= stmt_read_row_unbuffered;
+ }
}
DBUG_RETURN(0);
}
@@ -3102,8 +3193,11 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
param->store_param_func= store_param_str;
/*
For variable length types user must set either length or
@@ -3353,6 +3447,7 @@ static void fetch_string_with_conversion(MYSQL_BIND *param, char *value,
{
char *buffer= (char *)param->buffer;
int err= 0;
+ char *endptr= value + length;
/*
This function should support all target buffer types: the rest
@@ -3363,45 +3458,48 @@ static void fetch_string_with_conversion(MYSQL_BIND *param, char *value,
break;
case MYSQL_TYPE_TINY:
{
- uchar data= (uchar) my_strntol(&my_charset_latin1, value, length, 10,
- NULL, &err);
- *buffer= data;
+ longlong data= my_strtoll10(value, &endptr, &err);
+ *param->error= (IS_TRUNCATED(data, param->is_unsigned,
+ INT_MIN8, INT_MAX8, UINT_MAX8) || err > 0);
+ *buffer= (uchar) data;
break;
}
case MYSQL_TYPE_SHORT:
{
- short data= (short) my_strntol(&my_charset_latin1, value, length, 10,
- NULL, &err);
- shortstore(buffer, data);
+ longlong data= my_strtoll10(value, &endptr, &err);
+ *param->error= (IS_TRUNCATED(data, param->is_unsigned,
+ INT_MIN16, INT_MAX16, UINT_MAX16) || err > 0);
+ shortstore(buffer, (short) data);
break;
}
case MYSQL_TYPE_LONG:
{
- int32 data= (int32)my_strntol(&my_charset_latin1, value, length, 10,
- NULL, &err);
- longstore(buffer, data);
+ longlong data= my_strtoll10(value, &endptr, &err);
+ *param->error= (IS_TRUNCATED(data, param->is_unsigned,
+ INT_MIN32, INT_MAX32, UINT_MAX32) || err > 0);
+ longstore(buffer, (int32) data);
break;
}
case MYSQL_TYPE_LONGLONG:
{
- longlong data= my_strntoll(&my_charset_latin1, value, length, 10,
- NULL, &err);
+ longlong data= my_strtoll10(value, &endptr, &err);
+ *param->error= param->is_unsigned ? err != 0 :
+ (err > 0 || (err == 0 && data < 0));
longlongstore(buffer, data);
break;
}
case MYSQL_TYPE_FLOAT:
{
- char *end_not_used;
- float data = (float) my_strntod(&my_charset_latin1, value, length,
- &end_not_used, &err);
- floatstore(buffer, data);
+ double data= my_strntod(&my_charset_latin1, value, length, &endptr, &err);
+ float fdata= (float) data;
+ *param->error= (fdata != data) | test(err);
+ floatstore(buffer, fdata);
break;
}
case MYSQL_TYPE_DOUBLE:
{
- char *end_not_used;
- double data= my_strntod(&my_charset_latin1, value, length, &end_not_used,
- &err);
+ double data= my_strntod(&my_charset_latin1, value, length, &endptr, &err);
+ *param->error= test(err);
doublestore(buffer, data);
break;
}
@@ -3409,6 +3507,7 @@ static void fetch_string_with_conversion(MYSQL_BIND *param, char *value,
{
MYSQL_TIME *tm= (MYSQL_TIME *)buffer;
str_to_time(value, length, tm, &err);
+ *param->error= test(err);
break;
}
case MYSQL_TYPE_DATE:
@@ -3416,13 +3515,17 @@ static void fetch_string_with_conversion(MYSQL_BIND *param, char *value,
case MYSQL_TYPE_TIMESTAMP:
{
MYSQL_TIME *tm= (MYSQL_TIME *)buffer;
- str_to_datetime(value, length, tm, 0, &err);
+ (void) str_to_datetime(value, length, tm, 0, &err);
+ *param->error= test(err) && (param->buffer_type == MYSQL_TYPE_DATE &&
+ tm->time_type != MYSQL_TIMESTAMP_DATE);
break;
}
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
default:
{
/*
@@ -3443,6 +3546,7 @@ static void fetch_string_with_conversion(MYSQL_BIND *param, char *value,
copy_length= 0;
if (copy_length < param->buffer_length)
buffer[copy_length]= '\0';
+ *param->error= copy_length > param->buffer_length;
/*
param->length will always contain length of entire column;
number of copied bytes may be way different:
@@ -3465,44 +3569,78 @@ static void fetch_string_with_conversion(MYSQL_BIND *param, char *value,
*/
static void fetch_long_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
- longlong value)
+ longlong value, my_bool is_unsigned)
{
char *buffer= (char *)param->buffer;
- uint field_is_unsigned= field->flags & UNSIGNED_FLAG;
switch (param->buffer_type) {
case MYSQL_TYPE_NULL: /* do nothing */
break;
case MYSQL_TYPE_TINY:
+ *param->error= IS_TRUNCATED(value, param->is_unsigned,
+ INT_MIN8, INT_MAX8, UINT_MAX8);
*(uchar *)param->buffer= (uchar) value;
break;
case MYSQL_TYPE_SHORT:
- shortstore(buffer, value);
+ *param->error= IS_TRUNCATED(value, param->is_unsigned,
+ INT_MIN16, INT_MAX16, UINT_MAX16);
+ shortstore(buffer, (short) value);
break;
case MYSQL_TYPE_LONG:
- longstore(buffer, value);
+ *param->error= IS_TRUNCATED(value, param->is_unsigned,
+ INT_MIN32, INT_MAX32, UINT_MAX32);
+ longstore(buffer, (int32) value);
break;
case MYSQL_TYPE_LONGLONG:
longlongstore(buffer, value);
+ *param->error= param->is_unsigned != is_unsigned && value < 0;
break;
case MYSQL_TYPE_FLOAT:
{
- float data= field_is_unsigned ? (float) ulonglong2double(value) :
- (float) value;
+ /*
+ We need to store data in the buffer before the truncation check to
+ workaround Intel FPU executive precision feature.
+ (See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for details)
+ AFAIU it does not guarantee to work.
+ */
+ float data;
+ if (is_unsigned)
+ data= (float) ulonglong2double(value);
+ else
+ data= (float) value;
floatstore(buffer, data);
+ *param->error= is_unsigned ?
+ ((ulonglong) value) != ((ulonglong) (*(float*) buffer)) :
+ ((longlong) value) != ((longlong) (*(float*) buffer));
break;
}
case MYSQL_TYPE_DOUBLE:
{
- double data= field_is_unsigned ? ulonglong2double(value) :
- (double) value;
+ double data;
+ if (is_unsigned)
+ data= ulonglong2double(value);
+ else
+ data= (double)value;
doublestore(buffer, data);
+ *param->error= is_unsigned ?
+ ((ulonglong) value) != ((ulonglong) (*(double*) buffer)) :
+ ((longlong) value) != ((longlong) (*(double*) buffer));
+ break;
+ }
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ {
+ int error;
+ value= number_to_datetime(value, (MYSQL_TIME *) buffer, 1, &error);
+ *param->error= test(error);
break;
}
default:
{
char buff[22]; /* Enough for longlong */
- char *end= longlong10_to_str(value, buff, field_is_unsigned ? 10: -10);
+ char *end= longlong10_to_str(value, buff, is_unsigned ? 10: -10);
/* Resort to string conversion which supports all typecodes */
uint length= (uint) (end-buff);
@@ -3519,7 +3657,6 @@ static void fetch_long_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
}
}
-
/*
Convert double/float column to supplied buffer of any type.
@@ -3536,29 +3673,73 @@ static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
double value, int width)
{
char *buffer= (char *)param->buffer;
+ double val64 = (value < 0 ? -floor(-value) : floor(value));
switch (param->buffer_type) {
case MYSQL_TYPE_NULL: /* do nothing */
break;
case MYSQL_TYPE_TINY:
- *buffer= (uchar)value;
+ /*
+ We need to _store_ data in the buffer before the truncation check to
+ workaround Intel FPU executive precision feature.
+ (See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for details)
+ Sic: AFAIU it does not guarantee to work.
+ */
+ if (param->is_unsigned)
+ *buffer= (uint8) value;
+ else
+ *buffer= (int8) value;
+ *param->error= val64 != (param->is_unsigned ? (double)((uint8) *buffer) :
+ (double)((int8) *buffer));
break;
case MYSQL_TYPE_SHORT:
- shortstore(buffer, (short)value);
+ if (param->is_unsigned)
+ {
+ ushort data= (ushort) value;
+ shortstore(buffer, data);
+ }
+ else
+ {
+ short data= (short) value;
+ shortstore(buffer, data);
+ }
+ *param->error= val64 != (param->is_unsigned ? (double) (*(ushort*) buffer):
+ (double) (*(short*) buffer));
break;
case MYSQL_TYPE_LONG:
- longstore(buffer, (long)value);
- break;
+ if (param->is_unsigned)
+ {
+ uint32 data= (uint32) value;
+ longstore(buffer, data);
+ }
+ else
+ {
+ int32 data= (int32) value;
+ longstore(buffer, data);
+ }
+ *param->error= val64 != (param->is_unsigned ? (double) (*(uint32*) buffer):
+ (double) (*(int32*) buffer));
+ break;
case MYSQL_TYPE_LONGLONG:
- {
- longlong val= (longlong) value;
- longlongstore(buffer, val);
+ if (param->is_unsigned)
+ {
+ ulonglong data= (ulonglong) value;
+ longlongstore(buffer, data);
+ }
+ else
+ {
+ longlong data= (longlong) value;
+ longlongstore(buffer, data);
+ }
+ *param->error= val64 != (param->is_unsigned ?
+ ulonglong2double(*(ulonglong*) buffer) :
+ (double) (*(longlong*) buffer));
break;
- }
case MYSQL_TYPE_FLOAT:
{
float data= (float) value;
floatstore(buffer, data);
+ *param->error= (*(float*) buffer) != value;
break;
}
case MYSQL_TYPE_DOUBLE:
@@ -3612,18 +3793,47 @@ static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
*/
static void fetch_datetime_with_conversion(MYSQL_BIND *param,
+ MYSQL_FIELD *field,
MYSQL_TIME *time)
{
switch (param->buffer_type) {
case MYSQL_TYPE_NULL: /* do nothing */
break;
case MYSQL_TYPE_DATE:
+ *(MYSQL_TIME *)(param->buffer)= *time;
+ *param->error= time->time_type != MYSQL_TIMESTAMP_DATE;
+ break;
case MYSQL_TYPE_TIME:
+ *(MYSQL_TIME *)(param->buffer)= *time;
+ *param->error= time->time_type != MYSQL_TIMESTAMP_TIME;
+ break;
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
- /* XXX: should we copy only relevant members here? */
*(MYSQL_TIME *)(param->buffer)= *time;
+ /* No error: time and date are compatible with datetime */
+ break;
+ case MYSQL_TYPE_YEAR:
+ shortstore(param->buffer, time->year);
+ *param->error= 1;
break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ {
+ ulonglong value= TIME_to_ulonglong(time);
+ fetch_float_with_conversion(param, field,
+ ulonglong2double(value), DBL_DIG);
+ break;
+ }
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ {
+ longlong value= (longlong) TIME_to_ulonglong(time);
+ fetch_long_with_conversion(param, field, value, TRUE);
+ break;
+ }
default:
{
/*
@@ -3669,7 +3879,7 @@ static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
/* sic: we need to cast to 'signed char' as 'char' may be unsigned */
longlong data= field_is_unsigned ? (longlong) value :
(longlong) (signed char) value;
- fetch_long_with_conversion(param, field, data);
+ fetch_long_with_conversion(param, field, data, 0);
*row+= 1;
break;
}
@@ -3679,7 +3889,7 @@ static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
short value= sint2korr(*row);
longlong data= field_is_unsigned ? (longlong) (unsigned short) value :
(longlong) value;
- fetch_long_with_conversion(param, field, data);
+ fetch_long_with_conversion(param, field, data, 0);
*row+= 2;
break;
}
@@ -3689,14 +3899,15 @@ static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
int32 value= sint4korr(*row);
longlong data= field_is_unsigned ? (longlong) (uint32) value :
(longlong) value;
- fetch_long_with_conversion(param, field, data);
+ fetch_long_with_conversion(param, field, data, 0);
*row+= 4;
break;
}
case MYSQL_TYPE_LONGLONG:
{
longlong value= (longlong)sint8korr(*row);
- fetch_long_with_conversion(param, field, value);
+ fetch_long_with_conversion(param, field, value,
+ field->flags & UNSIGNED_FLAG);
*row+= 8;
break;
}
@@ -3721,7 +3932,7 @@ static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
MYSQL_TIME tm;
read_binary_date(&tm, row);
- fetch_datetime_with_conversion(param, &tm);
+ fetch_datetime_with_conversion(param, field, &tm);
break;
}
case MYSQL_TYPE_TIME:
@@ -3729,7 +3940,7 @@ static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
MYSQL_TIME tm;
read_binary_time(&tm, row);
- fetch_datetime_with_conversion(param, &tm);
+ fetch_datetime_with_conversion(param, field, &tm);
break;
}
case MYSQL_TYPE_DATETIME:
@@ -3738,7 +3949,7 @@ static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
MYSQL_TIME tm;
read_binary_datetime(&tm, row);
- fetch_datetime_with_conversion(param, &tm);
+ fetch_datetime_with_conversion(param, field, &tm);
break;
}
default:
@@ -3771,34 +3982,51 @@ static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
none
*/
-static void fetch_result_tinyint(MYSQL_BIND *param, uchar **row)
+static void fetch_result_tinyint(MYSQL_BIND *param, MYSQL_FIELD *field,
+ uchar **row)
{
- *(uchar *)param->buffer= **row;
+ my_bool field_is_unsigned= test(field->flags & UNSIGNED_FLAG);
+ uchar data= **row;
+ *(uchar *)param->buffer= data;
+ *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX8;
(*row)++;
}
-static void fetch_result_short(MYSQL_BIND *param, uchar **row)
+static void fetch_result_short(MYSQL_BIND *param, MYSQL_FIELD *field,
+ uchar **row)
{
- short value = (short)sint2korr(*row);
- shortstore(param->buffer, value);
+ my_bool field_is_unsigned= test(field->flags & UNSIGNED_FLAG);
+ ushort data= (ushort) sint2korr(*row);
+ shortstore(param->buffer, data);
+ *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX16;
*row+= 2;
}
-static void fetch_result_int32(MYSQL_BIND *param, uchar **row)
+static void fetch_result_int32(MYSQL_BIND *param,
+ MYSQL_FIELD *field __attribute__((unused)),
+ uchar **row)
{
- int32 value= (int32)sint4korr(*row);
- longstore(param->buffer, value);
+ my_bool field_is_unsigned= test(field->flags & UNSIGNED_FLAG);
+ uint32 data= (uint32) sint4korr(*row);
+ longstore(param->buffer, data);
+ *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX32;
*row+= 4;
}
-static void fetch_result_int64(MYSQL_BIND *param, uchar **row)
+static void fetch_result_int64(MYSQL_BIND *param,
+ MYSQL_FIELD *field __attribute__((unused)),
+ uchar **row)
{
- longlong value= (longlong)sint8korr(*row);
- longlongstore(param->buffer, value);
+ my_bool field_is_unsigned= test(field->flags & UNSIGNED_FLAG);
+ ulonglong data= (ulonglong) sint8korr(*row);
+ *param->error= param->is_unsigned != field_is_unsigned && data > LONGLONG_MAX;
+ longlongstore(param->buffer, data);
*row+= 8;
}
-static void fetch_result_float(MYSQL_BIND *param, uchar **row)
+static void fetch_result_float(MYSQL_BIND *param,
+ MYSQL_FIELD *field __attribute__((unused)),
+ uchar **row)
{
float value;
float4get(value,*row);
@@ -3806,7 +4034,9 @@ static void fetch_result_float(MYSQL_BIND *param, uchar **row)
*row+= 4;
}
-static void fetch_result_double(MYSQL_BIND *param, uchar **row)
+static void fetch_result_double(MYSQL_BIND *param,
+ MYSQL_FIELD *field __attribute__((unused)),
+ uchar **row)
{
double value;
float8get(value,*row);
@@ -3814,34 +4044,45 @@ static void fetch_result_double(MYSQL_BIND *param, uchar **row)
*row+= 8;
}
-static void fetch_result_time(MYSQL_BIND *param, uchar **row)
+static void fetch_result_time(MYSQL_BIND *param,
+ MYSQL_FIELD *field __attribute__((unused)),
+ uchar **row)
{
MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
read_binary_time(tm, row);
}
-static void fetch_result_date(MYSQL_BIND *param, uchar **row)
+static void fetch_result_date(MYSQL_BIND *param,
+ MYSQL_FIELD *field __attribute__((unused)),
+ uchar **row)
{
MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
read_binary_date(tm, row);
}
-static void fetch_result_datetime(MYSQL_BIND *param, uchar **row)
+static void fetch_result_datetime(MYSQL_BIND *param,
+ MYSQL_FIELD *field __attribute__((unused)),
+ uchar **row)
{
MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
read_binary_datetime(tm, row);
}
-static void fetch_result_bin(MYSQL_BIND *param, uchar **row)
+static void fetch_result_bin(MYSQL_BIND *param,
+ MYSQL_FIELD *field __attribute__((unused)),
+ uchar **row)
{
ulong length= net_field_length(row);
ulong copy_length= min(length, param->buffer_length);
memcpy(param->buffer, (char *)*row, copy_length);
*param->length= length;
+ *param->error= copy_length < length;
*row+= length;
}
-static void fetch_result_str(MYSQL_BIND *param, uchar **row)
+static void fetch_result_str(MYSQL_BIND *param,
+ MYSQL_FIELD *field __attribute__((unused)),
+ uchar **row)
{
ulong length= net_field_length(row);
ulong copy_length= min(length, param->buffer_length);
@@ -3850,6 +4091,7 @@ static void fetch_result_str(MYSQL_BIND *param, uchar **row)
if (copy_length != param->buffer_length)
((uchar *)param->buffer)[copy_length]= '\0';
*param->length= length; /* return total length */
+ *param->error= copy_length < length;
*row+= length;
}
@@ -3891,6 +4133,220 @@ static void skip_result_string(MYSQL_BIND *param __attribute__((unused)),
/*
+ Check that two field types are binary compatible i. e.
+ have equal representation in the binary protocol and
+ require client-side buffers of the same type.
+
+ SYNOPSIS
+ is_binary_compatible()
+ type1 parameter type supplied by user
+ type2 field type, obtained from result set metadata
+
+ RETURN
+ TRUE or FALSE
+*/
+
+static my_bool is_binary_compatible(enum enum_field_types type1,
+ enum enum_field_types type2)
+{
+ static const enum enum_field_types
+ range1[]= { MYSQL_TYPE_SHORT, MYSQL_TYPE_YEAR, MYSQL_TYPE_NULL },
+ range2[]= { MYSQL_TYPE_INT24, MYSQL_TYPE_LONG, MYSQL_TYPE_NULL },
+ range3[]= { MYSQL_TYPE_DATETIME, MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_NULL },
+ range4[]= { MYSQL_TYPE_ENUM, MYSQL_TYPE_SET, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB,
+ MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_STRING, MYSQL_TYPE_GEOMETRY,
+ MYSQL_TYPE_DECIMAL, MYSQL_TYPE_NULL };
+ static const enum enum_field_types
+ *range_list[]= { range1, range2, range3, range4 },
+ **range_list_end= range_list + sizeof(range_list)/sizeof(*range_list);
+ const enum enum_field_types **range, *type;
+
+ if (type1 == type2)
+ return TRUE;
+ for (range= range_list; range != range_list_end; ++range)
+ {
+ /* check that both type1 and type2 are in the same range */
+ bool type1_found= FALSE, type2_found= FALSE;
+ for (type= *range; *type != MYSQL_TYPE_NULL; type++)
+ {
+ type1_found|= type1 == *type;
+ type2_found|= type2 == *type;
+ }
+ if (type1_found || type2_found)
+ return type1_found && type2_found;
+ }
+ return FALSE;
+}
+
+
+/*
+ Setup a fetch function for one column of a result set.
+
+ SYNOPSIS
+ setup_one_fetch_function()
+ param output buffer descriptor
+ field column descriptor
+
+ DESCRIPTION
+ When user binds result set buffers or when result set
+ metadata is changed, we need to setup fetch (and possibly
+ conversion) functions for all columns of the result set.
+ In addition to that here we set up skip_result function, used
+ to update result set metadata in case when
+ STMT_ATTR_UPDATE_MAX_LENGTH attribute is set.
+ Notice that while fetch_result is chosen depending on both
+ field->type and param->type, skip_result depends on field->type
+ only.
+
+ RETURN
+ TRUE fetch function for this typecode was not found (typecode
+ is not supported by the client library)
+ FALSE success
+*/
+
+static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field)
+{
+ /* Setup data copy functions for the different supported types */
+ switch (param->buffer_type) {
+ case MYSQL_TYPE_NULL: /* for dummy binds */
+ /*
+ It's not binary compatible with anything the server can return:
+ no need to setup fetch_result, as it'll be reset anyway
+ */
+ *param->length= 0;
+ break;
+ case MYSQL_TYPE_TINY:
+ param->fetch_result= fetch_result_tinyint;
+ *param->length= 1;
+ break;
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_YEAR:
+ param->fetch_result= fetch_result_short;
+ *param->length= 2;
+ break;
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONG:
+ param->fetch_result= fetch_result_int32;
+ *param->length= 4;
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ param->fetch_result= fetch_result_int64;
+ *param->length= 8;
+ break;
+ case MYSQL_TYPE_FLOAT:
+ param->fetch_result= fetch_result_float;
+ *param->length= 4;
+ break;
+ case MYSQL_TYPE_DOUBLE:
+ param->fetch_result= fetch_result_double;
+ *param->length= 8;
+ break;
+ case MYSQL_TYPE_TIME:
+ param->fetch_result= fetch_result_time;
+ *param->length= sizeof(MYSQL_TIME);
+ break;
+ case MYSQL_TYPE_DATE:
+ param->fetch_result= fetch_result_date;
+ *param->length= sizeof(MYSQL_TIME);
+ break;
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ param->fetch_result= fetch_result_datetime;
+ *param->length= sizeof(MYSQL_TIME);
+ break;
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_BIT:
+ DBUG_ASSERT(param->buffer_length != 0);
+ param->fetch_result= fetch_result_bin;
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ DBUG_ASSERT(param->buffer_length != 0);
+ param->fetch_result= fetch_result_str;
+ break;
+ default:
+ return TRUE;
+ }
+ if (! is_binary_compatible(param->buffer_type, field->type))
+ param->fetch_result= fetch_result_with_conversion;
+
+ /* Setup skip_result functions (to calculate max_length) */
+ param->skip_result= skip_result_fixed;
+ switch (field->type) {
+ case MYSQL_TYPE_NULL: /* for dummy binds */
+ param->pack_length= 0;
+ field->max_length= 0;
+ break;
+ case MYSQL_TYPE_TINY:
+ param->pack_length= 1;
+ field->max_length= 4; /* as in '-127' */
+ break;
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_SHORT:
+ param->pack_length= 2;
+ field->max_length= 6; /* as in '-32767' */
+ break;
+ case MYSQL_TYPE_INT24:
+ field->max_length= 9; /* as in '16777216' or in '-8388607' */
+ param->pack_length= 4;
+ break;
+ case MYSQL_TYPE_LONG:
+ field->max_length= 11; /* '-2147483647' */
+ param->pack_length= 4;
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ field->max_length= 21; /* '18446744073709551616' */
+ param->pack_length= 8;
+ break;
+ case MYSQL_TYPE_FLOAT:
+ param->pack_length= 4;
+ field->max_length= MAX_DOUBLE_STRING_REP_LENGTH;
+ break;
+ case MYSQL_TYPE_DOUBLE:
+ param->pack_length= 8;
+ field->max_length= MAX_DOUBLE_STRING_REP_LENGTH;
+ break;
+ case MYSQL_TYPE_TIME:
+ field->max_length= 15; /* 19:23:48.123456 */
+ param->skip_result= skip_result_with_length;
+ case MYSQL_TYPE_DATE:
+ field->max_length= 10; /* 2003-11-11 */
+ param->skip_result= skip_result_with_length;
+ break;
+ break;
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ param->skip_result= skip_result_with_length;
+ field->max_length= MAX_DATE_STRING_REP_LENGTH;
+ break;
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_GEOMETRY:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_BIT:
+ param->skip_result= skip_result_string;
+ break;
+ default:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
Setup the bind buffers for resultset processing
*/
@@ -3929,142 +4385,30 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
This is to make the execute code easier
*/
if (!param->is_null)
- param->is_null= &param->internal_is_null;
+ param->is_null= &param->is_null_value;
if (!param->length)
- param->length= &param->internal_length;
+ param->length= &param->length_value;
+
+ if (!param->error)
+ param->error= &param->error_value;
param->param_number= param_count++;
param->offset= 0;
- /* Setup data copy functions for the different supported types */
- switch (param->buffer_type) {
- case MYSQL_TYPE_NULL: /* for dummy binds */
- *param->length= 0;
- break;
- case MYSQL_TYPE_TINY:
- param->fetch_result= fetch_result_tinyint;
- *param->length= 1;
- break;
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_YEAR:
- param->fetch_result= fetch_result_short;
- *param->length= 2;
- break;
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_LONG:
- param->fetch_result= fetch_result_int32;
- *param->length= 4;
- break;
- case MYSQL_TYPE_LONGLONG:
- param->fetch_result= fetch_result_int64;
- *param->length= 8;
- break;
- case MYSQL_TYPE_FLOAT:
- param->fetch_result= fetch_result_float;
- *param->length= 4;
- break;
- case MYSQL_TYPE_DOUBLE:
- param->fetch_result= fetch_result_double;
- *param->length= 8;
- break;
- case MYSQL_TYPE_TIME:
- param->fetch_result= fetch_result_time;
- *param->length= sizeof(MYSQL_TIME);
- break;
- case MYSQL_TYPE_DATE:
- param->fetch_result= fetch_result_date;
- *param->length= sizeof(MYSQL_TIME);
- break;
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- param->fetch_result= fetch_result_datetime;
- *param->length= sizeof(MYSQL_TIME);
- break;
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- DBUG_ASSERT(param->buffer_length != 0);
- param->fetch_result= fetch_result_bin;
- break;
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- DBUG_ASSERT(param->buffer_length != 0);
- param->fetch_result= fetch_result_str;
- break;
- default:
- strmov(stmt->sqlstate, unknown_sqlstate);
- sprintf(stmt->last_error,
- ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
- param->buffer_type, param_count);
- DBUG_RETURN(1);
- }
-
- /* Setup skip_result functions (to calculate max_length) */
- param->skip_result= skip_result_fixed;
- switch (field->type) {
- case MYSQL_TYPE_NULL: /* for dummy binds */
- param->pack_length= 0;
- field->max_length= 0;
- break;
- case MYSQL_TYPE_TINY:
- param->pack_length= 1;
- field->max_length= 4; /* as in '-127' */
- break;
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_SHORT:
- param->pack_length= 2;
- field->max_length= 6; /* as in '-32767' */
- break;
- case MYSQL_TYPE_INT24:
- field->max_length= 9; /* as in '16777216' or in '-8388607' */
- param->pack_length= 4;
- break;
- case MYSQL_TYPE_LONG:
- field->max_length= 11; /* '-2147483647' */
- param->pack_length= 4;
- break;
- case MYSQL_TYPE_LONGLONG:
- field->max_length= 21; /* '18446744073709551616' */
- param->pack_length= 8;
- break;
- case MYSQL_TYPE_FLOAT:
- param->pack_length= 4;
- field->max_length= MAX_DOUBLE_STRING_REP_LENGTH;
- break;
- case MYSQL_TYPE_DOUBLE:
- param->pack_length= 8;
- field->max_length= MAX_DOUBLE_STRING_REP_LENGTH;
- break;
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- param->skip_result= skip_result_with_length;
- field->max_length= MAX_DATE_STRING_REP_LENGTH;
- break;
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_GEOMETRY:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- param->skip_result= skip_result_string;
- break;
- default:
+ if (setup_one_fetch_function(param, field))
+ {
strmov(stmt->sqlstate, unknown_sqlstate);
sprintf(stmt->last_error,
- ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
- field->type, param_count);
+ ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
+ field->type, param_count);
DBUG_RETURN(1);
}
}
- stmt->bind_result_done= TRUE;
+ stmt->bind_result_done= BIND_RESULT_DONE;
+ if (stmt->mysql->options.report_data_truncation)
+ stmt->bind_result_done|= REPORT_DATA_TRUNCATION;
+
DBUG_RETURN(0);
}
@@ -4078,6 +4422,7 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
MYSQL_BIND *bind, *end;
MYSQL_FIELD *field;
uchar *null_ptr, bit;
+ int truncation_count= 0;
/*
Precondition: if stmt->field_count is zero or row is NULL, read_row_*
function must return no data.
@@ -4100,26 +4445,25 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
bind < end ;
bind++, field++)
{
+ *bind->error= 0;
if (*null_ptr & bit)
{
/*
- We should set both inter_buffer and is_null to be able to see
+ We should set both row_ptr and is_null to be able to see
nulls in mysql_stmt_fetch_column. This is because is_null may point
to user data which can be overwritten between mysql_stmt_fetch and
mysql_stmt_fetch_column, and in this case nullness of column will be
lost. See mysql_stmt_fetch_column for details.
*/
- bind->inter_buffer= NULL;
+ bind->row_ptr= NULL;
*bind->is_null= 1;
}
else
{
*bind->is_null= 0;
- bind->inter_buffer= row;
- if (field->type == bind->buffer_type)
- (*bind->fetch_result)(bind, &row);
- else
- fetch_result_with_conversion(bind, field, &row);
+ bind->row_ptr= row;
+ (*bind->fetch_result)(bind, field, &row);
+ truncation_count+= *bind->error;
}
if (!((bit<<=1) & 255))
{
@@ -4127,6 +4471,8 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
null_ptr++;
}
}
+ if (truncation_count && (stmt->bind_result_done & REPORT_DATA_TRUNCATION))
+ return MYSQL_DATA_TRUNCATED;
return 0;
}
@@ -4153,7 +4499,7 @@ int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
DBUG_ENTER("mysql_stmt_fetch");
if ((rc= (*stmt->read_row_func)(stmt, &row)) ||
- (rc= stmt_fetch_row(stmt, row)))
+ ((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;
@@ -4200,17 +4546,20 @@ int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind,
DBUG_RETURN(1);
}
- if (param->inter_buffer)
+ if (!bind->error)
+ bind->error= &bind->error_value;
+ *bind->error= 0;
+ if (param->row_ptr)
{
MYSQL_FIELD *field= stmt->fields+column;
- uchar *row= param->inter_buffer;
+ uchar *row= param->row_ptr;
bind->offset= offset;
if (bind->is_null)
*bind->is_null= 0;
if (bind->length) /* Set the length if non char/binary types */
*bind->length= *param->length;
else
- bind->length= &param->internal_length; /* Needed for fetch_result() */
+ bind->length= &param->length_value; /* Needed for fetch_result() */
fetch_result_with_conversion(bind, field, &row);
}
else
diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def
index c5579e9ec2b..5d88497e561 100644
--- a/libmysql/libmysql.def
+++ b/libmysql/libmysql.def
@@ -146,4 +146,6 @@ EXPORTS
mysql_rpl_query_type
mysql_slave_query
mysql_embedded
+ mysql_server_init
+ mysql_server_end
get_defaults_files
diff --git a/libmysql_r/Makefile.am b/libmysql_r/Makefile.am
index 0a5c380ff35..1a69dbb804a 100644
--- a/libmysql_r/Makefile.am
+++ b/libmysql_r/Makefile.am
@@ -24,9 +24,8 @@ target = libmysqlclient_r.la
target_defs = -DDONT_USE_RAID -DMYSQL_CLIENT @LIB_EXTRA_CCFLAGS@
LIBS = @LIBS@ @ZLIB_LIBS@ @openssl_libs@
-INCLUDES = @MT_INCLUDES@ \
- -I$(top_srcdir)/include $(openssl_includes) @ZLIB_INCLUDES@
-
+INCLUDES = -I$(top_srcdir)/include $(openssl_includes) @ZLIB_INCLUDES@ \
+ -I$(top_builddir)/include
## 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 4cf2c3f67a7..5d3b365042f 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -25,8 +25,10 @@ DEFS = -DEMBEDDED_LIBRARY -DMYSQL_SERVER \
-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\""
-INCLUDES= @MT_INCLUDES@ @bdb_includes@ -I$(top_srcdir)/include \
- -I$(top_srcdir)/sql -I$(top_srcdir)/sql/examples -I$(top_srcdir)/regex \
+INCLUDES= @bdb_includes@ -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
@@ -40,7 +42,7 @@ sqlexamplessources = ha_example.cc ha_archive.cc ha_tina.cc
noinst_HEADERS = embedded_priv.h emb_qcache.h
sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
- ha_innodb.cc ha_berkeley.cc ha_heap.cc ha_isam.cc ha_isammrg.cc \
+ ha_innodb.cc ha_berkeley.cc ha_heap.cc ha_federated.cc \
ha_myisam.cc ha_myisammrg.cc handler.cc sql_handler.cc \
hostname.cc init.cc password.c \
item.cc item_buff.cc item_cmpfunc.cc item_create.cc \
@@ -58,7 +60,9 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
- spatial.cc gstream.cc sql_help.cc tztime.cc \
+ spatial.cc gstream.cc sql_help.cc tztime.cc protocol_cursor.cc \
+ sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
+ parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
ha_blackhole.cc
libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources)
diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am
index 278aa66b328..071a133ca2d 100644
--- a/libmysqld/examples/Makefile.am
+++ b/libmysqld/examples/Makefile.am
@@ -14,10 +14,11 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-noinst_PROGRAMS = mysql
-bin_PROGRAMS = mysqltest_embedded mysql_client_test_embedded
-client_sources = $(mysqltest_embedded_SOURCES) $(mysql_SOURCES)
-tests_sources= $(mysql_client_test_embedded_SOURCES)
+noinst_PROGRAMS = mysql
+bin_PROGRAMS = mysqltest_embedded mysql_client_test_embedded
+client_sources = $(mysqltest_embedded_SOURCES) $(mysql_SOURCES)
+tests_sources = $(mysql_client_test_embedded_SOURCES)
+CLEANFILES = $(client_sources) $(tests_sources)
link_sources:
for f in $(client_sources); do \
@@ -30,9 +31,9 @@ link_sources:
done;
DEFS = -DEMBEDDED_LIBRARY
-INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include -I$(srcdir) \
+INCLUDES = -I$(top_srcdir)/include -I$(srcdir) \
-I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \
- $(openssl_includes)
+ -I$(top_builddir)/include $(openssl_includes)
LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @innodb_system_libs@ @LIBDL@ $(CXXLDFLAGS)
@@ -45,11 +46,7 @@ mysql_SOURCES = mysql.cc readline.cc completion_hash.cc \
mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD)
mysql_client_test_embedded_LINK = $(CXXLINK)
-mysql_client_test_embedded_SOURCES = mysql_client_test.c
-
-clean:
- rm -f $(client_sources)
- rm -f $(tests_sources)
+mysql_client_test_embedded_SOURCES = mysql_client_test.c
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/libmysqld/examples/builder-sample/emb_samples.cpp b/libmysqld/examples/builder-sample/emb_samples.cpp
index 4dfde111f84..411de26149b 100644
--- a/libmysqld/examples/builder-sample/emb_samples.cpp
+++ b/libmysqld/examples/builder-sample/emb_samples.cpp
@@ -109,6 +109,7 @@ bool __fastcall TForm1::connect_server()
ret_value = true;
is_server_started = true;
}
+ MySQL->reconnect= 1;
return ret_value;
}
//---------------------------------------------------------------------------
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index 15fe3a03390..74a1c8c7922 100644
--- a/libmysqld/lib_sql.cc
+++ b/libmysqld/lib_sql.cc
@@ -28,10 +28,6 @@ extern "C"
extern unsigned long max_allowed_packet, net_buffer_length;
}
-static int fake_argc= 1;
-static char *fake_argv[]= {(char *)"", 0};
-static const char *fake_groups[] = { "server", "embedded", 0 };
-
#if defined (__WIN__)
#include "../sql/mysqld.cpp"
#else
@@ -618,7 +614,7 @@ static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
}
-bool Protocol::send_fields(List<Item> *list, uint flag)
+bool Protocol::send_fields(List<Item> *list, uint flags)
{
List_iterator_fast<Item> it(*list);
Item *item;
@@ -683,7 +679,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
if (INTERNAL_NUM_FIELD(client_field))
client_field->flags|= NUM_FLAG;
- if (flag & 2)
+ if (flags & (int) Protocol::SEND_DEFAULTS)
{
char buff[80];
String tmp(buff, sizeof(buff), default_charset_info), *res;
@@ -709,15 +705,10 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
DBUG_RETURN(prepare_for_send(list));
err:
- send_error(thd, ER_OUT_OF_RESOURCES); /* purecov: inspected */
+ my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
-bool Protocol::send_records_num(List<Item> *list, ulonglong records)
-{
- return false;
-}
-
bool Protocol::write()
{
if (!thd->mysql) // bootstrap file handling
diff --git a/libmysqld/libmysqld.def b/libmysqld/libmysqld.def
index ea3133594f5..0612141a60d 100644
--- a/libmysqld/libmysqld.def
+++ b/libmysqld/libmysqld.def
@@ -1,6 +1,6 @@
LIBRARY LIBMYSQLD
-DESCRIPTION 'MySQL 4.1 Embedded Server Library'
-VERSION 4.1
+DESCRIPTION 'MySQL 5.0 Embedded Server Library'
+VERSION 5.0
EXPORTS
_dig_vec_upper
_dig_vec_lower
@@ -158,3 +158,5 @@ EXPORTS
mysql_stmt_attr_set
mysql_stmt_field_count
get_defaults_files
+ my_charset_bin
+ my_charset_same
diff --git a/libmysqld/libmysqld.rc b/libmysqld/libmysqld.rc
index 5b6142faddf..5b6142faddf 100755..100644
--- a/libmysqld/libmysqld.rc
+++ b/libmysqld/libmysqld.rc
diff --git a/libmysqld/resource.h b/libmysqld/resource.h
index f770fe490a6..f770fe490a6 100755..100644
--- a/libmysqld/resource.h
+++ b/libmysqld/resource.h
diff --git a/man/Makefile.am b/man/Makefile.am
index 539c43dfed6..8d18165191a 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -17,11 +17,11 @@
## Process this file with automake to create Makefile.in
-man_MANS = mysql.1 isamchk.1 isamlog.1 mysql_zap.1 mysqlaccess.1 \
+man_MANS = mysql.1 mysql_zap.1 mysqlaccess.1 \
mysqladmin.1 mysqld.1 mysqld_multi.1 mysqldump.1 mysqlshow.1 \
perror.1 replace.1 mysqld_safe.1 mysql_fix_privilege_tables.1
-EXTRA_DIST = mysql.1.in isamchk.1.in isamlog.1.in mysql_zap.1.in \
+EXTRA_DIST = mysql.1.in mysql_zap.1.in \
mysqlaccess.1.in mysqladmin.1.in mysqld.1.in mysqld_multi.1.in \
mysqldump.1.in mysqlshow.1.in perror.1.in replace.1.in mysqlman.1.in \
mysqld_safe.1.in mysql_fix_privilege_tables.1.in
diff --git a/man/isamchk.1.in b/man/isamchk.1.in
deleted file mode 100644
index d908e8af3ee..00000000000
--- a/man/isamchk.1.in
+++ /dev/null
@@ -1,145 +0,0 @@
-.TH isamchk 1 "19 December 2000" "MySQL @MYSQL_BASE_VERSION@" "MySQL database"
-.SH NAME
-.BR isamchk
- \- Description, check and repair of ISAM tables.
-Used without options all tables on the command will be checked for errors
-.SH USAGE
-isamchk [OPTIONS] tables[.ISM]
-.SH SYNOPSIS
-.B isamchk
-.RB [ \-a | \-\-analyze ]
-.RB [ \-# | \-\-debug=... ]
-.RB [ \-\-character\-sets\-dir=...]
-.RB [ \-C | \-\-default\-character\-set=...]
-.RB [ \-d | \-\-description ]
-.RB [ \-e | \-\-extend\-check ]
-.RB [ \-f | \-\-force ]
-.RB [ \-? | \-\-help ]
-.RB [ \-i | \-\-information ]
-.RB [ \-k | \-\-keys\-used=# ]
-.RB [ \-l | \-\-no\-symlinks]
-.RB [ \-q | \-\-quick ]
-.RB [ \-r | \-\-recover ]
-.RB [ \-o | \-\-safe\-recover ]
-.RB [ \-O | "\-\-set\-variable var=option"]
-.RB [ \-s | \-\-silent ]
-.RB [ \-S | \-\-sort\-index ]
-.RB [ \-R | \-\-sort\-records=#]
-.RB [ \-u | \-\-unpack ]
-.RB [ \-v | \-\-verbose ]
-.RB [ \-V | \-\-version ]
-.RB [ \-w | \-\-wait ]
-.SH DESCRIPTION
-.TP
-.BR \-a | \-\-analyze
-Analyze distribution of keys. Will make some joins in
-MySQL faster.
-.TP
-.BR \-# | \-\-debug=...
-Output debug log. Often this is 'd:t:o ,filename`
-.TP
-.BR \-\-character\-sets\-dir=...
-Directory where character sets are
-.TP
-.BR \-C | \-\-default\-character\-set=...
-Set the default character set
-.TP
-.BR \-d | \-\-description
-Prints some information about table.
-.TP
-.BR \-e | \-\-extend\-check
-Check the table VERY thoroughly. One need use this
-only in extreme cases as isamchk should normally find
-all errors even without this switch
-.TP
-.BR \-f | \-\-force
-Overwrite old temporary files.
-If one uses \-f when checking tables (running isamchk
-without \-r), isamchk will automatically restart with
-\-r on any wrong table.
-.TP
-.BR \-? | \-\-help
-Display help and exit.
-.TP
-.BR \-i | \-\-information
-Print statistics information about the table
-.TP
-.BR \-k | \-\-keys\-used=#
-Used with '\-r'. Tell ISAM to update only the first
-# keys. This can be used to get faster inserts!
-.TP
-.BR \-l | \-\-no\-symlinks
-Do not follow symbolic links when repairing. Normally
-isamchk repairs the table a symlink points at.
-.TP
-.BR \-q | \-\-quick
-Used with \-r to get a faster repair. (The data file
-isn't touched.) One can give a second '\-q' to force
-isamchk to modify the original datafile.
-.TP
-.BR \-r | \-\-recover
-Can fix almost anything except unique keys that aren't
-unique.
-.TP
-.BR \-o | \-\-safe\-recover
-Uses old recovery method; slower than '\-r' but can
-handle a couple of cases that '\-r' cannot handle.
-.TP
-.BR \-O | " \-\-set\-variable var=option "
-Change the value of a variable.
-.TP
-.BR \-s | \-\-silent
-Only print errors. One can use two \-s to make isamchk
-very silent
-.TP
-.BR \-S | \-\-sort\-index
-Sort index blocks. This speeds up 'read\-next' in
-applications
-.TP
-.BR \-R | \-\-sort\-records=#
-Sort records according to an index. This makes your
-data much more localized and may speed up things
-(It may be VERY slow to do a sort the first time!)
-.TP
-.BR \-u | \-\-unpack
-Unpack file packed with pack_isam.
-.TP
-.BR \-v | \-\-verbose
-Print more information. This can be used with
-\-d and \-e. Use many \-v for more verbosity!
-.TP
-.BR \-V | \-\-version
-Print version and exit.
-.TP
-.BR \-w | \-\-wait
-Wait if table is locked.
-.SH "SEE ALSO"
-isamlog(1),
-mysql(1),
-mysqlaccess(1),
-mysqladmin(1),
-mysqld(1),
-mysqld_multi(1),
-mysqld_safe(1),
-mysqldump(1),
-mysql_fix_privilege_tables(1),
-mysqlshow(1),
-mysql_zap(1),
-perror(1),
-replace(1)
-.P
-For more information please refer to the MySQL reference
-manual, which may already be installed locally and which
-is also available online at http://dev.mysql.com/doc/mysql/en
-.SH BUGS
-Please refer to http://bugs.mysql.com/ to report bugs.
-.SH AUTHOR
-Ver 1.0, distribution @MYSQL_NO_DASH_VERSION@
-Michael (Monty) Widenius (monty@mysql.com),
-MySQL AB (http://www.mysql.com/).
-This software comes with no warranty.
-Manual page by L. (Kill-9) Pedersen
-(kill-9@kill\-9.dk), Mercurmedia Data Model Architect /
-system developer (http://www.mercurmedia.com)
-
-.\" end of man page
diff --git a/man/isamlog.1.in b/man/isamlog.1.in
deleted file mode 100644
index 5f69e70297a..00000000000
--- a/man/isamlog.1.in
+++ /dev/null
@@ -1,107 +0,0 @@
-.TH isamlog 1 "19 December 2000" "MySQL @MYSQL_BASE_VERSION@" "MySQL database"
-.SH NAME
-isamlog - Write info about whats in a nisam log file.
-.SH USAGE
-isamlog [-?iruvIV] [-c #] [-f #] [-F filepath/] [-o #] [-R file recordpos] [-w write_file] [log-filename [table ...]]
-.SH SYNOPSIS
-.B isamlog
-.RB [ -? | -I ]
-.RB [ -V ]
-.RB [ -c ]
-.RB [ -f ]
-.RB [ -F ]
-.RB [ -i ]
-.RB [ -o ]
-.RB [ "-p #" ]
-.RB [ -r ]
-.RB [ -R ]
-.RB [ -u ]
-.RB [ -v ]
-.RB [ -w ]
-.SH DESCRIPTION
-.TP
-.BR isamlog
-.TP
-.BR -? | -I
-info
-.TP
-.BR -V
-version
-.TP
-.BR -c
-do only # commands
-.TP
-.BR -f
-max open files
-.TP
-.BR -F
-file path
-.TP
-.BR -i
-extra info
-.TP
-.BR -o
-offset
-.TP
-.BR "-p #"
-remove # components from path
-.TP
-.BR -r
-recover
-.TP
-.BR -R
-file recordposition
-.TP
-.BR -u
-update
-.TP
-.BR -v
-verbose
-.TP
-.BR -w
-write file
-.SH NOTE
-If no file name is given isam.log is used
-One can give a second and a third '-v' for more verbose.
-Normaly one does a update (-u).
-If a recover is done all writes and all possibly updates and deletes is done
-and errors are only counted.
-If one gives table names as arguments only these tables will be updated
-
-
-
-.SH "SEE ALSO"
-isamchk(1),
-mysql(1),
-mysqlaccess(1),
-mysqladmin(1),
-mysqld(1),
-mysqld_multi(1),
-mysqld_safe(1),
-mysqldump(1),
-mysql_fix_privilege_tables(1),
-mysqlshow(1),
-mysql_zap(1),
-perror(1),
-replace(1)
-.P
-For more information please refer to the MySQL reference
-manual, which may already be installed locally and which
-is also available online at http://dev.mysql.com/doc/mysql/en
-.SH BUGS
-Please refer to http://bugs.mysql.com/ to report bugs.
-
-.SH AUTHOR
-
-Ver 1.0, distribution @MYSQL_NO_DASH_VERSION@
-Michael (Monty) Widenius (monty@mysql.com),
-MySQL AB (http://www.mysql.com/).
-This software comes with no warranty.
-Manual page by L. (Kill-9) Pedersen
-(kill-9@kill-9.dk), Mercurmedia Data Model Architect /
-system developer (http://www.mercurmedia.com)
-
-
-.\" end of man page
-
-
diff --git a/merge/.cvsignore b/merge/.cvsignore
deleted file mode 100644
index e9955884756..00000000000
--- a/merge/.cvsignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.deps
-Makefile
-Makefile.in
diff --git a/merge/Makefile.am b/merge/Makefile.am
deleted file mode 100644
index 25e15e9c6ec..00000000000
--- a/merge/Makefile.am
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include
-pkglib_LIBRARIES = libmerge.a
-noinst_HEADERS = mrg_def.h
-libmerge_a_SOURCES = mrg_open.c mrg_extra.c mrg_info.c mrg_locking.c \
- mrg_rrnd.c mrg_update.c mrg_delete.c mrg_rsame.c \
- mrg_panic.c mrg_close.c mrg_create.c mrg_static.c
-
-# Don't update the files from bitkeeper
-%::SCCS/s.%
diff --git a/merge/make-ccc b/merge/make-ccc
deleted file mode 100755
index 3f37c33638f..00000000000
--- a/merge/make-ccc
+++ /dev/null
@@ -1,3 +0,0 @@
-ccc -I./../include -I../include -DDBUG_OFF -fast -O3 -c _locking.c close.c create.c delete.c extra.c info.c open.c panic.c rrnd.c rsame.c static.c update.c
-rm libmerge.a
-ar -cr libmerge.a _locking.o
diff --git a/merge/mrg_close.c b/merge/mrg_close.c
deleted file mode 100644
index e835fd06e47..00000000000
--- a/merge/mrg_close.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* close a isam-database */
-
-#include "mrg_def.h"
-
-int mrg_close(register MRG_INFO *info)
-{
- int error=0,new_error;
- MRG_TABLE *file;
- DBUG_ENTER("mrg_close");
-
- for (file=info->open_tables ; file != info->end_table ; file++)
- if ((new_error=nisam_close(file->table)))
- error=new_error;
- pthread_mutex_lock(&THR_LOCK_open);
- mrg_open_list=list_delete(mrg_open_list,&info->open_list);
- pthread_mutex_unlock(&THR_LOCK_open);
- my_free((gptr) info,MYF(0));
- if (error)
- {
- my_errno=error;
- DBUG_RETURN(-1);
- }
- DBUG_RETURN(0);
-}
diff --git a/merge/mrg_create.c b/merge/mrg_create.c
deleted file mode 100644
index 3508b7967f4..00000000000
--- a/merge/mrg_create.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Create a MERGE-file */
-
-#include "mrg_def.h"
-
- /* create file named 'name' and save filenames in it
- table_names should be NULL or a vector of string-pointers with
- a NULL-pointer last
- */
-
-int mrg_create(const char *name, const char**table_names)
-{
- int save_errno;
- uint errpos;
- File file;
- char buff[FN_REFLEN],*end;
- DBUG_ENTER("mrg_create");
-
- errpos=0;
- if ((file = my_create(fn_format(buff,name,"",MRG_NAME_EXT,4),0,
- O_RDWR | O_EXCL | O_NOFOLLOW,MYF(MY_WME))) < 0)
- goto err;
- errpos=1;
- if (table_names)
- for ( ; *table_names ; table_names++)
- {
- strmov(buff,*table_names);
- fn_same(buff,name,4);
- *(end=strend(buff))='\n';
- if (my_write(file,*table_names,(uint) (end-buff+1),
- MYF(MY_WME | MY_NABP)))
- goto err;
- }
- if (my_close(file,MYF(0)))
- goto err;
- DBUG_RETURN(0);
-
-err:
- save_errno=my_errno;
- switch (errpos) {
- case 1:
- VOID(my_close(file,MYF(0)));
- }
- my_errno=save_errno; /* Return right errocode */
- DBUG_RETURN(-1);
-} /* mrg_create */
diff --git a/merge/mrg_extra.c b/merge/mrg_extra.c
deleted file mode 100644
index d37b1aaa03c..00000000000
--- a/merge/mrg_extra.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Extra functions we want to do with a database
- - All flags, exept record-cache-flags, are set in all used databases
- record-cache-flags are set in mrg_rrnd when we are changing database.
-*/
-
-#include "mrg_def.h"
-
-int mrg_extra(
-MRG_INFO *info,
-enum ha_extra_function function)
-{
- MRG_TABLE *file;
-
- if (function == HA_EXTRA_CACHE)
- info->cache_in_use=1;
- else
- {
- if (function == HA_EXTRA_NO_CACHE || function == HA_EXTRA_RESET)
- info->cache_in_use=0;
- if (function == HA_EXTRA_RESET || function == HA_EXTRA_RESET_STATE)
- {
- info->current_table=0;
- info->last_used_table=info->open_tables;
- }
- for (file=info->open_tables ; file != info->end_table ; file++)
- nisam_extra(file->table,function);
- }
- return 0;
-}
diff --git a/merge/mrg_info.c b/merge/mrg_info.c
deleted file mode 100644
index 57f22276487..00000000000
--- a/merge/mrg_info.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include "mrg_def.h"
-
-ulong mrg_position(MRG_INFO *info)
-{
- MRG_TABLE *current_table;
-
- if (!(current_table = info->current_table) &&
- info->open_tables != info->end_table)
- current_table = info->open_tables;
- return (current_table ?
- (ulong) (current_table->table->lastpos +
- current_table->file_offset) :
- ~(ulong) 0);
-}
-
- /* If flag != 0 one only gets pos of last record */
-
-int mrg_info(MRG_INFO *info,register MERGE_INFO *x,int flag)
-{
- MRG_TABLE *current_table;
- DBUG_ENTER("mrg_info");
-
- if (!(current_table = info->current_table) &&
- info->open_tables != info->end_table)
- current_table = info->open_tables;
- x->recpos = info->current_table ?
- info->current_table->table->lastpos + info->current_table->file_offset :
- (ulong) -1L;
- if (flag != HA_STATUS_POS)
- {
- x->records = info->records;
- x->deleted = info->del;
- x->data_file_length = info->data_file_length;
- x->reclength = info->reclength;
- if (current_table)
- x->errkey = current_table->table->errkey;
- else
- { /* No tables in MRG */
- x->errkey=0;
- }
- x->options = info->options;
- }
- DBUG_RETURN(0);
-}
diff --git a/merge/mrg_open.c b/merge/mrg_open.c
deleted file mode 100644
index 6bf75392131..00000000000
--- a/merge/mrg_open.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* open a MERGE-database */
-
-#include "mrg_def.h"
-#include <stddef.h>
-#include <errno.h>
-#ifdef VMS
-#include "static.c"
-#endif
-
-/* open a MERGE-database.
-
- if handle_locking is 0 then exit with error if some database is locked
- if handle_locking is 1 then wait if database is locked
-*/
-
-
-MRG_INFO *mrg_open(
-const char *name,
-int mode,
-int handle_locking)
-{
- int save_errno,i,errpos;
- uint files,dir_length,length, options;
- ulonglong file_offset;
- char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
- MRG_INFO info,*m_info;
- File fd;
- IO_CACHE file;
- N_INFO *isam,*last_isam;
- DBUG_ENTER("mrg_open");
-
- LINT_INIT(last_isam);
- isam=0;
- errpos=files=0;
- bzero((gptr) &info,sizeof(info));
- bzero((char*) &file,sizeof(file));
- if ((fd=my_open(fn_format(name_buff,name,"",MRG_NAME_EXT,4),
- O_RDONLY | O_SHARE,MYF(0))) < 0 ||
- init_io_cache(&file, fd, IO_SIZE, READ_CACHE, 0, 0,
- MYF(MY_WME | MY_NABP)))
- goto err;
- errpos=1;
- dir_length=dirname_part(name_buff,name);
- info.reclength=0;
- while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
- {
- if ((end=buff+length)[-1] == '\n')
- end[-1]='\0';
- if (buff[0] && buff[0] != '#') /* Skip empty lines and comments */
- {
- last_isam=isam;
- if (!test_if_hard_path(buff))
- {
- VOID(strmake(name_buff+dir_length,buff,
- sizeof(name_buff)-1-dir_length));
- VOID(cleanup_dirname(buff,name_buff));
- }
- if (!(isam=nisam_open(buff,mode,test(handle_locking))))
- goto err;
- files++;
- }
- last_isam=isam;
- if (info.reclength && info.reclength != isam->s->base.reclength)
- {
- my_errno=HA_ERR_WRONG_IN_RECORD;
- goto err;
- }
- info.reclength=isam->s->base.reclength;
- }
- if (!(m_info= (MRG_INFO*) my_malloc(sizeof(MRG_INFO)+files*sizeof(MRG_TABLE),
- MYF(MY_WME))))
- goto err;
- *m_info=info;
- m_info->open_tables=(MRG_TABLE *) (m_info+1);
- m_info->tables=files;
-
- options= (uint) ~0;
- for (i=files ; i-- > 0 ; )
- {
- m_info->open_tables[i].table=isam;
- m_info->options|=isam->s->base.options;
- options&=isam->s->base.options;
- m_info->records+=isam->s->state.records;
- m_info->del+=isam->s->state.del;
- m_info->data_file_length=isam->s->state.data_file_length;
- if (i)
- isam=(N_INFO*) (isam->open_list.next->data);
- }
- /* Don't force readonly if not all tables are readonly */
- if (! (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA)))
- m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA);
-
- /* Fix fileinfo for easyer debugging (actually set by rrnd) */
- file_offset=0;
- for (i=0 ; (uint) i < files ; i++)
- {
- m_info->open_tables[i].file_offset=(my_off_t) file_offset;
- file_offset+=m_info->open_tables[i].table->s->state.data_file_length;
- }
- if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
- {
- my_errno=HA_ERR_RECORD_FILE_FULL;
- my_free((char*) m_info,MYF(0));
- goto err;
- }
-
- m_info->end_table=m_info->open_tables+files;
- m_info->last_used_table=m_info->open_tables;
-
- VOID(my_close(fd,MYF(0)));
- end_io_cache(&file);
- m_info->open_list.data=(void*) m_info;
- pthread_mutex_lock(&THR_LOCK_open);
- mrg_open_list=list_add(mrg_open_list,&m_info->open_list);
- pthread_mutex_unlock(&THR_LOCK_open);
- DBUG_RETURN(m_info);
-
-err:
- save_errno=my_errno;
- switch (errpos) {
- case 1:
- VOID(my_close(fd,MYF(0)));
- end_io_cache(&file);
- for (i=files ; i-- > 0 ; )
- {
- isam=last_isam;
- if (i)
- last_isam=(N_INFO*) (isam->open_list.next->data);
- nisam_close(isam);
- }
- }
- my_errno=save_errno;
- DBUG_RETURN (NULL);
-}
diff --git a/merge/mrg_panic.c b/merge/mrg_panic.c
deleted file mode 100644
index e9ad1974d8f..00000000000
--- a/merge/mrg_panic.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include "mrg_def.h"
-
- /* if flag == HA_PANIC_CLOSE then all misam files are closed */
- /* if flag == HA_PANIC_WRITE then all misam files are unlocked and
- all changed data in single user misam is written to file */
- /* if flag == HA_PANIC_READ then all misam files that was locked when
- nisam_panic(HA_PANIC_WRITE) was done is locked. A ni_readinfo() is
- done for all single user files to get changes in database */
-
-
-int mrg_panic(
-enum ha_panic_function flag)
-{
- int error=0;
- LIST *list_element,*next_open;
- MRG_INFO *info;
- DBUG_ENTER("mrg_panic");
-
- for (list_element=mrg_open_list ; list_element ; list_element=next_open)
- {
- next_open=list_element->next; /* Save if close */
- info=(MRG_INFO*) list_element->data;
- if (flag == HA_PANIC_CLOSE && mrg_close(info))
- error=my_errno;
- }
- if (mrg_open_list && flag != HA_PANIC_CLOSE)
- DBUG_RETURN(nisam_panic(flag));
- if (!error) DBUG_RETURN(0);
- my_errno=error;
- DBUG_RETURN(-1);
-}
diff --git a/merge/mrg_rrnd.c b/merge/mrg_rrnd.c
deleted file mode 100644
index 206427d74d4..00000000000
--- a/merge/mrg_rrnd.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Read a record with random-access. The position to the record must
- get by mrg_info(). The next record can be read with pos= -1 */
-
-
-#include "mrg_def.h"
-
-static MRG_TABLE *find_table(MRG_TABLE *start,MRG_TABLE *end,mrg_off_t pos);
-
-/*
- If filepos == -1, read next
- Returns same as nisam_rrnd:
- 0 = Ok.
- 1 = Record deleted.
- -1 = EOF (or something, errno should be HA_ERR_END_OF_FILE)
-*/
-
-int mrg_rrnd(MRG_INFO *info,byte *buf,mrg_off_t filepos)
-{
- int error;
- N_INFO *isam_info;
-
- if (filepos == ~(mrg_off_t) 0) /* Can't use HA_POS_ERROR */
- {
- if (!info->current_table)
- {
- if (info->open_tables == info->end_table)
- { /* No tables */
- my_errno=HA_ERR_END_OF_FILE;
- return -1;
- }
- isam_info=(info->current_table=info->open_tables)->table;
- if (info->cache_in_use)
- nisam_extra(isam_info,HA_EXTRA_CACHE);
- filepos=isam_info->s->pack.header_length;
- isam_info->lastinx= (uint) -1; /* Can't forward or backward */
- }
- else
- {
- isam_info=info->current_table->table;
- filepos= isam_info->nextpos;
- }
-
- for (;;)
- {
- isam_info->update&= HA_STATE_CHANGED;
- if ((error=(*isam_info->s->read_rnd)(isam_info,(byte*) buf,
- filepos,1)) >= 0 ||
- my_errno != HA_ERR_END_OF_FILE)
- return (error);
- if (info->cache_in_use)
- nisam_extra(info->current_table->table,HA_EXTRA_NO_CACHE);
- if (info->current_table+1 == info->end_table)
- return(-1);
- info->current_table++;
- info->last_used_table=info->current_table;
- if (info->cache_in_use)
- nisam_extra(info->current_table->table,HA_EXTRA_CACHE);
- info->current_table->file_offset=
- info->current_table[-1].file_offset+
- info->current_table[-1].table->s->state.data_file_length;
-
- isam_info=info->current_table->table;
- filepos=isam_info->s->pack.header_length;
- isam_info->lastinx= (uint) -1;
- }
- }
- info->current_table=find_table(info->open_tables,
- info->end_table-1,filepos);
- isam_info=info->current_table->table;
- isam_info->update&= HA_STATE_CHANGED;
- return ((*isam_info->s->read_rnd)(isam_info,(byte*) buf,
- (ulong) (filepos -
- info->current_table->file_offset),
- 0));
-}
-
-
- /* Find which table to use according to file-pos */
-
-static MRG_TABLE *find_table(MRG_TABLE *start,MRG_TABLE *end,mrg_off_t pos)
-{
- MRG_TABLE *mid;
-
- while (start != end)
- {
- mid=start+((uint) (end-start)+1)/2;
- if (mid->file_offset > pos)
- end=mid-1;
- else
- start=mid;
- }
- return start;
-}
diff --git a/merge/mrg_rsame.c b/merge/mrg_rsame.c
deleted file mode 100644
index ee840bc3060..00000000000
--- a/merge/mrg_rsame.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include "mrg_def.h"
-
-
-int mrg_rsame(
-MRG_INFO *info,
-byte *record,
-int inx) /* not used, should be 0 */
-{
- if (inx)
- {
- my_errno=HA_ERR_WRONG_INDEX;
- return(-1);
- }
- if (!info->current_table)
- {
- my_errno=HA_ERR_NO_ACTIVE_RECORD;
- return(-1);
- }
- return nisam_rsame(info->current_table->table,record,inx);
-}
diff --git a/merge/mrg_update.c b/merge/mrg_update.c
deleted file mode 100644
index a6650267f36..00000000000
--- a/merge/mrg_update.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Update last read record */
-
-#include "mrg_def.h"
-
-int mrg_update(
-register MRG_INFO *info,
-const byte *oldrec, const byte *newrec)
-{
- if (!info->current_table)
- {
- my_errno=HA_ERR_NO_ACTIVE_RECORD;
- return(-1);
- }
- return nisam_update(info->current_table->table,oldrec,newrec);
-}
diff --git a/myisam/Makefile.am b/myisam/Makefile.am
index 0b8a25e3404..c61647b25f7 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 = @MT_INCLUDES@ -I$(top_srcdir)/include
+INCLUDES = -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 62c68322595..530f0d56c4c 100644
--- a/myisam/ft_boolean_search.c
+++ b/myisam/ft_boolean_search.c
@@ -68,7 +68,7 @@ struct st_ftb_expr
my_off_t docid[2];
float weight;
float cur_weight;
- byte *quot, *qend;
+ LIST *phrase; /* phrase words */
uint yesses; /* number of "yes" words matched */
uint nos; /* number of "no" words matched */
uint ythresh; /* number of "yes" words in expr */
@@ -132,20 +132,22 @@ static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b)
}
static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
- FTB_EXPR *up, uint depth)
+ FTB_EXPR *up, uint depth, byte *up_quot)
{
byte res;
FTB_PARAM param;
FT_WORD w;
FTB_WORD *ftbw;
FTB_EXPR *ftbe;
+ FT_WORD *phrase_word;
+ LIST *phrase_list;
uint extra=HA_FT_WLEN+ftb->info->s->rec_reflength; /* just a shortcut */
if (ftb->state != UNINITIALIZED)
return;
param.prev=' ';
- param.quot=up->quot;
+ param.quot= up_quot;
while ((res=ft_get_word(ftb->charset,start,end,&w,&param)))
{
int r=param.plusminus;
@@ -172,6 +174,14 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
if (param.yesno > 0) up->ythresh++;
queue_insert(& ftb->queue, (byte *)ftbw);
ftb->with_scan|=(param.trunc & FTB_FLAG_TRUNC);
+ case 4: /* not indexed word (stopword or too short/long) */
+ if (! up_quot) break;
+ phrase_word= (FT_WORD *)alloc_root(&ftb->mem_root, sizeof(FT_WORD));
+ phrase_list= (LIST *)alloc_root(&ftb->mem_root, sizeof(LIST));
+ phrase_word->pos= w.pos;
+ phrase_word->len= w.len;
+ phrase_list->data= (void *)phrase_word;
+ up->phrase= list_add(up->phrase, phrase_list);
break;
case 2: /* left bracket */
ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR));
@@ -182,13 +192,14 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
ftbe->up=up;
ftbe->ythresh=ftbe->yweaks=0;
ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR;
- if ((ftbe->quot=param.quot)) ftb->with_scan|=2;
+ ftbe->phrase= NULL;
+ if (param.quot) ftb->with_scan|=2;
if (param.yesno > 0) up->ythresh++;
- _ftb_parse_query(ftb, start, end, ftbe, depth+1);
+ _ftb_parse_query(ftb, start, end, ftbe, depth+1, param.quot);
param.quot=0;
break;
case 3: /* right bracket */
- if (up->quot) up->qend=param.quot;
+ if (up_quot) up->phrase= list_reverse(up->phrase);
return;
}
}
@@ -211,6 +222,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
uint off, extra=HA_FT_WLEN+info->s->base.rec_reflength;
byte *lastkey_buf=ftbw->word+ftbw->off;
+ LINT_INIT(off);
if (ftbw->flags & FTB_FLAG_TRUNC)
lastkey_buf+=ftbw->len;
@@ -409,12 +421,12 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
ftbe->weight=1;
ftbe->flags=FTB_FLAG_YES;
ftbe->nos=1;
- ftbe->quot=0;
ftbe->up=0;
ftbe->ythresh=ftbe->yweaks=0;
ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR;
+ ftbe->phrase= NULL;
ftb->root=ftbe;
- _ftb_parse_query(ftb, &query, query+query_len, ftbe, 0);
+ _ftb_parse_query(ftb, &query, query+query_len, ftbe, 0, NULL);
ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root,
sizeof(FTB_WORD *)*ftb->queue.elements);
memcpy(ftb->list, ftb->queue.root+1, sizeof(FTB_WORD *)*ftb->queue.elements);
@@ -430,29 +442,45 @@ err:
}
-/* returns 1 if str0 ~= /\bstr1\b/ */
-static int _ftb_strstr(const byte *s0, const byte *e0,
- const byte *s1, const byte *e1,
- CHARSET_INFO *cs)
+/*
+ Checks if given buffer matches phrase list.
+
+ SYNOPSIS
+ _ftb_check_phrase()
+ s0 start of buffer
+ e0 end of buffer
+ phrase broken into list phrase
+ cs charset info
+
+ RETURN VALUE
+ 1 is returned if phrase found, 0 else.
+*/
+
+static int _ftb_check_phrase(const byte *s0, const byte *e0,
+ LIST *phrase, CHARSET_INFO *cs)
{
- const byte *p0= s0;
- my_bool s_after= true_word_char(cs, s1[0]);
- my_bool e_before= true_word_char(cs, e1[-1]);
- uint p0_len;
- my_match_t m[2];
+ FT_WORD h_word;
+ const byte *h_start= s0;
+ DBUG_ENTER("_ftb_strstr");
+ DBUG_ASSERT(phrase);
- while (p0 < e0)
+ while (ft_simple_get_word(cs, (byte **)&h_start, e0, &h_word, FALSE))
{
- if (cs->coll->instr(cs, p0, e0 - p0, s1, e1 - s1, m, 2) != 2)
- return(0);
- if ((!s_after || p0 + m[1].beg == s0 || !true_word_char(cs, p0[m[1].beg-1])) &&
- (!e_before || p0 + m[1].end == e0 || !true_word_char(cs, p0[m[1].end])))
- return(1);
- p0+= m[1].beg;
- p0+= (p0_len= my_mbcharlen(cs, *(uchar *)p0)) ? p0_len : 1;
+ FT_WORD *n_word;
+ LIST *phrase_element= phrase;
+ const byte *h_start1= h_start;
+ for (;;)
+ {
+ n_word= (FT_WORD *)phrase_element->data;
+ if (my_strnncoll(cs, h_word.pos, h_word.len, n_word->pos, n_word->len))
+ break;
+ if (! (phrase_element= phrase_element->next))
+ DBUG_RETURN(1);
+ if (! ft_simple_get_word(cs, (byte **)&h_start1, e0, &h_word, FALSE))
+ DBUG_RETURN(0);
+ }
}
-
- return(0);
+ DBUG_RETURN(0);
}
@@ -483,7 +511,7 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_
{
yn=ftbe->flags;
weight=ftbe->cur_weight*ftbe->weight;
- if (mode && ftbe->quot)
+ if (mode && ftbe->phrase)
{
int not_found=1;
@@ -492,8 +520,8 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_
{
if (!ftsi.pos)
continue;
- not_found = ! _ftb_strstr(ftsi.pos, ftsi.pos+ftsi.len,
- ftbe->quot, ftbe->qend, ftb->charset);
+ not_found = ! _ftb_check_phrase(ftsi.pos, ftsi.pos+ftsi.len,
+ ftbe->phrase, ftb->charset);
}
if (not_found) break;
} /* ftbe->quot */
@@ -641,8 +669,8 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
continue;
end=ftsi.pos+ftsi.len;
- while (ft_simple_get_word(ftb->charset,
- (byte **) &ftsi.pos, (byte *) end, &word))
+ while (ft_simple_get_word(ftb->charset, (byte **) &ftsi.pos,
+ (byte *) end, &word, TRUE))
{
int a, b, c;
for (a=0, b=ftb->queue.elements, c=(a+b)/2; b-a>1; c=(a+b)/2)
diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c
index 0b1e68b0d70..2fad2363ae2 100644
--- a/myisam/ft_parser.c
+++ b/myisam/ft_parser.c
@@ -93,12 +93,14 @@ my_bool ft_boolean_check_syntax_string(const byte *str)
return 0;
}
-/* returns:
- * 0 - eof
- * 1 - word found
- * 2 - left bracket
- * 3 - right bracket
- */
+/*
+ RETURN VALUE
+ 0 - eof
+ 1 - word found
+ 2 - left bracket
+ 3 - right bracket
+ 4 - stopword found
+*/
byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
FT_WORD *word, FTB_PARAM *param)
{
@@ -161,6 +163,11 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
*start=doc;
return 1;
}
+ else if (length) /* make sure length > 0 (if start contains spaces only) */
+ {
+ *start= doc;
+ return 4;
+ }
}
if (param->quot)
{
@@ -170,18 +177,19 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
return 0;
}
-byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end,
- FT_WORD *word)
+byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, const byte *end,
+ FT_WORD *word, my_bool skip_stopwords)
{
byte *doc= *start;
uint mwc, length, mbl;
DBUG_ENTER("ft_simple_get_word");
- while (doc<end)
+ do
{
- for (;doc<end;doc++)
+ for (;; doc++)
{
- if (true_word_char(cs,*doc)) break;
+ if (doc >= end) DBUG_RETURN(0);
+ if (true_word_char(cs, *doc)) break;
}
mwc= length= 0;
@@ -193,13 +201,14 @@ byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end,
word->len= (uint)(doc-word->pos) - mwc;
- if (length >= ft_min_word_len && length < ft_max_word_len &&
- !is_stopword(word->pos, word->len))
+ if (skip_stopwords == FALSE ||
+ (length >= ft_min_word_len && length < ft_max_word_len &&
+ !is_stopword(word->pos, word->len)))
{
*start= doc;
DBUG_RETURN(1);
}
- }
+ } while (doc < end);
DBUG_RETURN(0);
}
@@ -217,7 +226,7 @@ int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc)
FT_WORD w;
DBUG_ENTER("ft_parse");
- while (ft_simple_get_word(wtree->custom_arg, &doc,end,&w))
+ while (ft_simple_get_word(wtree->custom_arg, &doc, end, &w, TRUE))
{
if (with_alloc)
{
diff --git a/myisam/ft_static.c b/myisam/ft_static.c
index 994a94d0c49..e221950f445 100644
--- a/myisam/ft_static.c
+++ b/myisam/ft_static.c
@@ -25,23 +25,25 @@ char ft_boolean_syntax[]="+ -><()~*:\"\"&|";
const HA_KEYSEG ft_keysegs[FT_SEGS]={
{
- HA_KEYTYPE_VARTEXT, /* type */
- 63, /* language (will be overwritten) */
- 0, 0, 0, /* null_bit, bit_start, bit_end */
- HA_VAR_LENGTH | HA_PACK_KEY, /* flag */
- HA_FT_MAXBYTELEN, /* length */
- HA_FT_WLEN, /* start */
- 0, /* null_pos */
- NULL /* charset */
- },
- {
-/*
- Note, this (and the last HA_KEYTYPE_END) segment should NOT
- be packed in any way, otherwise w_search() won't be able to
- update key entry 'in vivo'
-*/
- HA_FT_WTYPE, 63, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, 0, 0, NULL
- }
+ 0, /* charset */
+ HA_FT_WLEN, /* start */
+ 0, /* null_pos */
+ 0, /* Bit pos */
+ HA_VAR_LENGTH_PART | HA_PACK_KEY, /* flag */
+ HA_FT_MAXBYTELEN, /* length */
+ HA_KEYTYPE_VARTEXT2, /* type */
+ 63, /* language (will be overwritten) */
+ 0, /* null_bit */
+ 2, 0, 0 /* bit_start, bit_end, bit_length */
+},
+{
+ /*
+ Note, this (and the last HA_KEYTYPE_END) segment should NOT
+ be packed in any way, otherwise w_search() won't be able to
+ update key entry 'in vivo'
+ */
+ 0, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, HA_FT_WTYPE, 63, 0, 0, 0, 0
+}
};
const struct _ft_vft _ft_vft_nlq = {
diff --git a/myisam/ft_stopwords.c b/myisam/ft_stopwords.c
index a4bce6ad4e8..ab51afb0e82 100644
--- a/myisam/ft_stopwords.c
+++ b/myisam/ft_stopwords.c
@@ -81,7 +81,7 @@ int ft_init_stopwords()
goto err0;
len=my_read(fd, buffer, len, MYF(MY_WME));
end=start+len;
- while (ft_simple_get_word(default_charset_info, &start, end, &w))
+ while (ft_simple_get_word(default_charset_info, &start, end, &w, TRUE))
{
if (ft_add_stopword(my_strdup_with_length(w.pos, w.len, MYF(0))))
goto err1;
diff --git a/myisam/ft_test1.c b/myisam/ft_test1.c
index f4884f8ca39..14be9aa1e8c 100644
--- a/myisam/ft_test1.c
+++ b/myisam/ft_test1.c
@@ -79,24 +79,24 @@ static int run_test(const char *filename)
recinfo[0].length= (extra_field == FIELD_BLOB ? 4 + mi_portable_sizeof_char_ptr :
extra_length);
if (extra_field == FIELD_VARCHAR)
- recinfo[0].length+=2;
+ recinfo[0].length+= HA_VARCHAR_PACKLENGTH(extra_length);
recinfo[1].type=key_field;
recinfo[1].length= (key_field == FIELD_BLOB ? 4+mi_portable_sizeof_char_ptr :
key_length);
if (key_field == FIELD_VARCHAR)
- recinfo[1].length+=2;
+ recinfo[1].length+= HA_VARCHAR_PACKLENGTH(key_length);
/* Define a key over the first column */
keyinfo[0].seg=keyseg;
keyinfo[0].keysegs=1;
keyinfo[0].seg[0].type= key_type;
- keyinfo[0].seg[0].flag= (key_field == FIELD_BLOB)?HA_BLOB_PART:
- (key_field == FIELD_VARCHAR)?HA_VAR_LENGTH:0;
+ keyinfo[0].seg[0].flag= (key_field == FIELD_BLOB) ? HA_BLOB_PART:
+ (key_field == FIELD_VARCHAR) ? HA_VAR_LENGTH_PART:0;
keyinfo[0].seg[0].start=recinfo[0].length;
keyinfo[0].seg[0].length=key_length;
keyinfo[0].seg[0].null_bit= 0;
keyinfo[0].seg[0].null_pos=0;
- keyinfo[0].seg[0].language=MY_CHARSET_CURRENT;
+ keyinfo[0].seg[0].language= default_charset_info->number;
keyinfo[0].flag = (no_fulltext?HA_PACK_KEY:HA_FULLTEXT);
if (!silent)
@@ -155,33 +155,42 @@ static int run_test(const char *filename)
if (!silent)
printf("- Reading rows with key\n");
for (i=0 ; i < NQUERIES ; i++)
- { FT_DOCLIST *result;
+ {
+ FT_DOCLIST *result;
result=ft_nlq_init_search(file,0,(char*) query[i],strlen(query[i]),1);
- if(!result) {
+ if(!result)
+ {
printf("Query %d: `%s' failed with errno %3d\n",i,query[i],my_errno);
continue;
}
printf("Query %d: `%s'. Found: %d. Top five documents:\n",
- i,query[i],result->ndocs);
- for(j=0;j<5;j++) { double w; int err;
- err=ft_nlq_read_next(result, read_record);
- if(err==HA_ERR_END_OF_FILE) {
- printf("No more matches!\n");
- break;
- } else if (err) {
- printf("ft_read_next %d failed with errno %3d\n",j,my_errno);
- break;
- }
- w=ft_nlq_get_relevance(result);
- if(key_field == FIELD_VARCHAR) {
- uint l;
- char *p;
- p=recinfo[0].length+read_record;
- l=uint2korr(p);
- printf("%10.7f: %.*s\n",w,(int) l,p+2);
- } else
- printf("%10.7f: %.*s\n",w,recinfo[1].length,
- recinfo[0].length+read_record);
+ i,query[i],result->ndocs);
+ for (j=0;j<5;j++)
+ {
+ double w; int err;
+ err= ft_nlq_read_next(result, read_record);
+ if (err==HA_ERR_END_OF_FILE)
+ {
+ printf("No more matches!\n");
+ break;
+ }
+ else if (err)
+ {
+ printf("ft_read_next %d failed with errno %3d\n",j,my_errno);
+ break;
+ }
+ w=ft_nlq_get_relevance(result);
+ if (key_field == FIELD_VARCHAR)
+ {
+ uint l;
+ char *p;
+ p=recinfo[0].length+read_record;
+ l=uint2korr(p);
+ printf("%10.7f: %.*s\n",w,(int) l,p+2);
+ }
+ else
+ printf("%10.7f: %.*s\n",w,recinfo[1].length,
+ recinfo[0].length+read_record);
}
ft_nlq_close_search(result);
}
@@ -215,9 +224,14 @@ void create_record(char *pos, int n)
else if (recinfo[0].type == FIELD_VARCHAR)
{
uint tmp;
- strnmov(pos+2,data[n].f0,keyinfo[0].seg[0].length);
- tmp=strlen(pos+2);
- int2store(pos,tmp);
+ /* -1 is here because pack_length is stored in seg->length */
+ uint pack_length= HA_VARCHAR_PACKLENGTH(keyinfo[0].seg[0].length-1);
+ strnmov(pos+pack_length,data[n].f0,keyinfo[0].seg[0].length);
+ tmp=strlen(pos+pack_length);
+ if (pack_length == 1)
+ *pos= (char) tmp;
+ else
+ int2store(pos,tmp);
pos+=recinfo[0].length;
}
else
@@ -239,9 +253,14 @@ void create_record(char *pos, int n)
else if (recinfo[1].type == FIELD_VARCHAR)
{
uint tmp;
- strnmov(pos+2,data[n].f2,keyinfo[0].seg[0].length);
- tmp=strlen(pos+2);
- int2store(pos,tmp);
+ /* -1 is here because pack_length is stored in seg->length */
+ uint pack_length= HA_VARCHAR_PACKLENGTH(keyinfo[0].seg[0].length-1);
+ strnmov(pos+pack_length,data[n].f2,keyinfo[0].seg[0].length);
+ tmp=strlen(pos+1);
+ if (pack_length == 1)
+ *pos= (char) tmp;
+ else
+ int2store(pos,tmp);
pos+=recinfo[1].length;
}
else
diff --git a/myisam/ft_update.c b/myisam/ft_update.c
index beccc062270..b8cd925bf4f 100644
--- a/myisam/ft_update.c
+++ b/myisam/ft_update.c
@@ -58,29 +58,27 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
DBUG_ENTER("_mi_ft_segiterator");
if (!ftsi->num)
- {
DBUG_RETURN(0);
- }
- else
- ftsi->num--;
+
+ ftsi->num--;
if (!ftsi->seg)
- {
DBUG_RETURN(1);
- }
- else
- ftsi->seg--;
+
+ ftsi->seg--;
if (ftsi->seg->null_bit &&
(ftsi->rec[ftsi->seg->null_pos] & ftsi->seg->null_bit))
{
- ftsi->pos=0;
- DBUG_RETURN(1);
+ ftsi->pos=0;
+ DBUG_RETURN(1);
}
ftsi->pos= ftsi->rec+ftsi->seg->start;
- if (ftsi->seg->flag & HA_VAR_LENGTH)
+ if (ftsi->seg->flag & HA_VAR_LENGTH_PART)
{
- ftsi->len=uint2korr(ftsi->pos);
- ftsi->pos+=2; /* Skip VARCHAR length */
+ uint pack_length= (ftsi->seg->bit_start);
+ ftsi->len= (pack_length == 1 ? (uint) *(uchar*) ftsi->pos :
+ uint2korr(ftsi->pos));
+ ftsi->pos+= pack_length; /* Skip VARCHAR length */
DBUG_RETURN(1);
}
if (ftsi->seg->flag & HA_BLOB_PART)
@@ -296,9 +294,11 @@ uint _ft_make_key(MI_INFO *info, uint keynr, byte *keybuf, FT_WORD *wptr,
DBUG_RETURN(_mi_make_key(info,keynr,(uchar*) keybuf,buf,filepos));
}
+
/*
convert key value to ft2
*/
+
uint _mi_ft_convert_to_ft2(MI_INFO *info, uint keynr, uchar *key)
{
my_off_t root;
@@ -316,9 +316,12 @@ uint _mi_ft_convert_to_ft2(MI_INFO *info, uint keynr, uchar *key)
get_key_full_length_rdonly(key_length, key);
while (_mi_ck_delete(info, keynr, key, key_length) == 0)
- /* nothing to do here.
- _mi_ck_delete() will populate info->ft1_to_ft2 with deleted keys
- */;
+ {
+ /*
+ nothing to do here.
+ _mi_ck_delete() will populate info->ft1_to_ft2 with deleted keys
+ */
+ }
/* creating pageful of keys */
mi_putint(info->buff,length+2,0);
diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h
index ddb9fbfead2..91c679a1e58 100644
--- a/myisam/ftdefs.h
+++ b/myisam/ftdefs.h
@@ -112,7 +112,8 @@ int is_stopword(char *word, uint len);
uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t);
byte ft_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *, FTB_PARAM *);
-byte ft_simple_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *);
+byte ft_simple_get_word(CHARSET_INFO *, byte **, const byte *,
+ FT_WORD *, my_bool);
typedef struct _st_ft_seg_iterator {
uint num, len;
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index f710d3a8454..2949b39183d 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -281,7 +281,8 @@ int chk_size(MI_CHECK *param, register MI_INFO *info)
size=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0));
if ((skr=(my_off_t) info->state->key_file_length) != size)
{
- if (skr > size)
+ /* Don't give error if file generated by myisampack */
+ if (skr > size && info->s->state.key_map)
{
error=1;
mi_check_print_error(param,
@@ -2043,7 +2044,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
sort_param.key_length+=keyseg[i].length;
if (keyseg[i].flag & HA_SPACE_PACK)
sort_param.key_length+=get_pack_length(keyseg[i].length);
- if (keyseg[i].flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ if (keyseg[i].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
sort_param.key_length+=2 + test(keyseg[i].length >= 127);
if (keyseg[i].flag & HA_NULL_PART)
sort_param.key_length++;
@@ -2452,7 +2453,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
sort_param[i].key_length+=keyseg->length;
if (keyseg->flag & HA_SPACE_PACK)
sort_param[i].key_length+=get_pack_length(keyseg->length);
- if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
sort_param[i].key_length+=2 + test(keyseg->length >= 127);
if (keyseg->flag & HA_NULL_PART)
sort_param[i].key_length++;
diff --git a/myisam/mi_checksum.c b/myisam/mi_checksum.c
index 95338434211..33a51068fb0 100644
--- a/myisam/mi_checksum.c
+++ b/myisam/mi_checksum.c
@@ -40,8 +40,12 @@ ha_checksum mi_checksum(MI_INFO *info, const byte *buf)
}
case FIELD_VARCHAR:
{
- length=uint2korr(buf);
- pos=buf+2;
+ uint pack_length= HA_VARCHAR_PACKLENGTH(rec->length-1);
+ if (pack_length == 1)
+ length= (ulong) *(uchar*) buf;
+ else
+ length= uint2korr(buf);
+ pos= buf+pack_length;
break;
}
default:
diff --git a/myisam/mi_create.c b/myisam/mi_create.c
index d363f3d5b67..8635d6bcf36 100644
--- a/myisam/mi_create.c
+++ b/myisam/mi_create.c
@@ -43,7 +43,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
myf create_flag;
uint fields,length,max_key_length,packed,pointer,real_length_diff,
key_length,info_length,key_segs,options,min_key_length_skip,
- base_pos,varchar_count,long_varchar_count,varchar_length,
+ base_pos,long_varchar_count,varchar_length,
max_key_block_length,unique_key_parts,fulltext_keys,offset;
ulong reclength, real_reclength,min_pack_length;
char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr;
@@ -99,7 +99,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
/* Start by checking fields and field-types used */
- reclength=varchar_count=varchar_length=long_varchar_count=packed=
+ reclength=varchar_length=long_varchar_count=packed=
min_pack_length=pack_reclength=0;
for (rec=recinfo, fields=0 ;
fields != columns ;
@@ -130,14 +130,15 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
}
else if (type == FIELD_VARCHAR)
{
- varchar_count++;
- varchar_length+=rec->length-2;
+ varchar_length+= rec->length-1; /* Used for min_pack_length */
packed--;
- pack_reclength+=1;
- if (test(rec->length > 257))
- { /* May be packed on 3 bytes */
+ pack_reclength++;
+ min_pack_length++;
+ /* We must test for 257 as length includes pack-length */
+ if (test(rec->length >= 257))
+ {
long_varchar_count++;
- pack_reclength+=2;
+ pack_reclength+= 2; /* May be packed on 3 bytes */
}
}
else if (type != FIELD_SKIP_ZERO)
@@ -169,12 +170,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
/* We can't use checksum with static length rows */
if (!(options & HA_OPTION_PACK_RECORD))
options&= ~HA_OPTION_CHECKSUM;
- if (options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))
- min_pack_length+=varchar_count; /* Min length to pack */
- else
- {
- min_pack_length+=varchar_length+2*varchar_count;
- }
+ if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
+ min_pack_length+= varchar_length;
if (flags & HA_CREATE_TMP_TABLE)
{
options|= HA_OPTION_TMP_TABLE;
@@ -223,7 +220,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
reclength=pointer+1; /* reserve place for delete link */
}
else
- reclength+=long_varchar_count; /* We need space for this! */
+ reclength+= long_varchar_count; /* We need space for varchar! */
max_key_length=0; tot_length=0 ; key_segs=0;
fulltext_keys=0;
@@ -264,7 +261,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
j++, keyseg++)
{
if (keyseg->type != HA_KEYTYPE_BINARY &&
- keyseg->type != HA_KEYTYPE_VARBINARY)
+ keyseg->type != HA_KEYTYPE_VARBINARY1 &&
+ keyseg->type != HA_KEYTYPE_VARBINARY2)
{
my_errno=HA_WRONG_CREATE_OPTION;
goto err;
@@ -279,8 +277,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
goto err;
#endif /*HAVE_SPATIAL*/
}
- else
- if (keydef->flag & HA_FULLTEXT)
+ else if (keydef->flag & HA_FULLTEXT)
{
keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY;
options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
@@ -289,11 +286,22 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
j++, keyseg++)
{
if (keyseg->type != HA_KEYTYPE_TEXT &&
- keyseg->type != HA_KEYTYPE_VARTEXT)
+ keyseg->type != HA_KEYTYPE_VARTEXT1 &&
+ keyseg->type != HA_KEYTYPE_VARTEXT2)
{
my_errno=HA_WRONG_CREATE_OPTION;
goto err;
}
+ if (!(keyseg->flag & HA_BLOB_PART) &&
+ (keyseg->type == HA_KEYTYPE_VARTEXT1 ||
+ keyseg->type == HA_KEYTYPE_VARTEXT2))
+ {
+ /* Make a flag that this is a VARCHAR */
+ keyseg->flag|= HA_VAR_LENGTH_PART;
+ /* Store in bit_start number of bytes used to pack the length */
+ keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1)?
+ 1 : 2);
+ }
}
fulltext_keys++;
@@ -314,7 +322,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
/* Only use HA_PACK_KEY when first segment is a variable length key */
if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART |
- HA_VAR_LENGTH)))
+ HA_VAR_LENGTH_PART)))
{
/* pack relative to previous key */
keydef->flag&= ~HA_PACK_KEY;
@@ -348,12 +356,27 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
case HA_KEYTYPE_UINT24:
case HA_KEYTYPE_INT8:
keyseg->flag|= HA_SWAP_KEY;
- /* fall through */
+ break;
+ case HA_KEYTYPE_VARTEXT1:
+ case HA_KEYTYPE_VARTEXT2:
+ case HA_KEYTYPE_VARBINARY1:
+ case HA_KEYTYPE_VARBINARY2:
+ if (!(keyseg->flag & HA_BLOB_PART))
+ {
+ /* Make a flag that this is a VARCHAR */
+ keyseg->flag|= HA_VAR_LENGTH_PART;
+ /* Store in bit_start number of bytes used to pack the length */
+ keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
+ keyseg->type == HA_KEYTYPE_VARBINARY1) ?
+ 1 : 2);
+ }
+ break;
default:
break;
}
if (keyseg->flag & HA_SPACE_PACK)
{
+ DBUG_ASSERT(!(keyseg->flag & HA_VAR_LENGTH_PART));
keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY;
options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
length++; /* At least one length byte */
@@ -364,8 +387,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
length+=2;
}
}
- if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART))
+ if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
{
+ DBUG_ASSERT(!test_all_bits(keyseg->flag,
+ (HA_VAR_LENGTH_PART | HA_BLOB_PART)));
keydef->flag|=HA_VAR_LENGTH_KEY;
length++; /* At least one length byte */
options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
@@ -620,10 +645,12 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
{
HA_KEYSEG sseg;
sseg.type=SPTYPE;
- sseg.language= 7;
+ sseg.language= 7; /* Binary */
sseg.null_bit=0;
sseg.bit_start=0;
sseg.bit_end=0;
+ sseg.bit_length= 0;
+ sseg.bit_pos= 0;
sseg.length=SPLEN;
sseg.null_pos=0;
sseg.start=j*SPLEN;
@@ -656,11 +683,31 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
/* Save unique definition */
for (i=0 ; i < share.state.header.uniques ; i++)
{
+ HA_KEYSEG *keyseg_end;
+ keyseg= uniquedefs[i].seg;
if (mi_uniquedef_write(file, &uniquedefs[i]))
goto err;
- for (j=0 ; j < uniquedefs[i].keysegs ; j++)
+ for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs;
+ keyseg < keyseg_end;
+ keyseg++)
{
- if (mi_keyseg_write(file, &uniquedefs[i].seg[j]))
+ switch (keyseg->type) {
+ case HA_KEYTYPE_VARTEXT1:
+ case HA_KEYTYPE_VARTEXT2:
+ case HA_KEYTYPE_VARBINARY1:
+ case HA_KEYTYPE_VARBINARY2:
+ if (!(keyseg->flag & HA_BLOB_PART))
+ {
+ keyseg->flag|= HA_VAR_LENGTH_PART;
+ keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
+ keyseg->type == HA_KEYTYPE_VARBINARY1) ?
+ 1 : 2);
+ }
+ break;
+ default:
+ break;
+ }
+ if (mi_keyseg_write(file, keyseg))
goto err;
}
}
diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c
index 02d1c7d05d6..e782d21afe7 100644
--- a/myisam/mi_dbug.c
+++ b/myisam/mi_dbug.c
@@ -131,9 +131,21 @@ void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg,
key=end;
break;
}
+ case HA_KEYTYPE_BIT:
+ {
+ uint i;
+ fputs("0x",stream);
+ for (i=0 ; i < keyseg->length ; i++)
+ fprintf(stream, "%02x", (uint) *key++);
+ key= end;
+ break;
+ }
+
#endif
- case HA_KEYTYPE_VARTEXT: /* VARCHAR and TEXT */
- case HA_KEYTYPE_VARBINARY: /* VARBINARY and BLOB */
+ case HA_KEYTYPE_VARTEXT1: /* VARCHAR and TEXT */
+ case HA_KEYTYPE_VARTEXT2: /* VARCHAR and TEXT */
+ case HA_KEYTYPE_VARBINARY1: /* VARBINARY and BLOB */
+ case HA_KEYTYPE_VARBINARY2: /* VARBINARY and BLOB */
{
uint tmp_length;
get_key_length(tmp_length,key);
diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c
index b964cb35dd8..cc4a17182f7 100644
--- a/myisam/mi_delete.c
+++ b/myisam/mi_delete.c
@@ -45,6 +45,12 @@ int mi_delete(MI_INFO *info,const byte *record)
/* Test if record is in datafile */
+ DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage",
+ mi_print_error(info->s, HA_ERR_CRASHED);
+ DBUG_RETURN(my_errno= HA_ERR_CRASHED););
+ DBUG_EXECUTE_IF("my_error_test_undefined_error",
+ mi_print_error(info->s, INT_MAX);
+ DBUG_RETURN(my_errno= INT_MAX););
if (!(info->update & HA_STATE_AKTIV))
{
DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); /* No database read */
@@ -109,13 +115,19 @@ err:
mi_sizestore(lastpos,info->lastpos);
myisam_log_command(MI_LOG_DELETE,info,(byte*) lastpos, sizeof(lastpos),0);
if (save_errno != HA_ERR_RECORD_CHANGED)
+ {
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info); /* mark table crashed */
+ }
VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
info->update|=HA_STATE_WRITTEN; /* Buffer changed */
allow_break(); /* Allow SIGHUP & SIGINT */
my_errno=save_errno;
if (save_errno == HA_ERR_KEY_NOT_FOUND)
+ {
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
+ }
DBUG_RETURN(my_errno);
} /* mi_delete */
@@ -142,6 +154,7 @@ static int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo,
if ((old_root=*root) == HA_OFFSET_ERROR)
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
DBUG_RETURN(my_errno=HA_ERR_CRASHED);
}
if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
@@ -253,7 +266,12 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
my_off_t root;
uchar *kpos=keypos;
- tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&kpos,lastkey);
+ if (!(tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&kpos,lastkey)))
+ {
+ mi_print_error(info->s, HA_ERR_CRASHED);
+ my_errno= HA_ERR_CRASHED;
+ DBUG_RETURN(-1);
+ }
root=_mi_dpos(info,nod_flag,kpos);
if (subkeys == -1)
{
@@ -302,6 +320,7 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (!nod_flag)
{
DBUG_PRINT("error",("Didn't find key"));
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED; /* This should newer happend */
goto err;
}
@@ -313,13 +332,10 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
{ /* Found key */
uint tmp;
length=mi_getint(anc_buff);
- tmp=remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length,
- &next_block);
- if (tmp == 0)
- {
- DBUG_PRINT("exit",("Return: %d",0));
- DBUG_RETURN(0);
- }
+ if (!(tmp= remove_key(keyinfo,nod_flag,keypos,lastkey,anc_buff+length,
+ &next_block)))
+ goto err;
+
length-= tmp;
mi_putint(anc_buff,length,nod_flag);
@@ -368,6 +384,7 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
my_afree((byte*) leaf_buff);
DBUG_PRINT("exit",("Return: %d",ret_value));
DBUG_RETURN(ret_value);
+
err:
my_afree((byte*) leaf_buff);
DBUG_PRINT("exit",("Error: %d",my_errno));
@@ -559,10 +576,10 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo,
/* remove key from anc_buff */
- s_length=remove_key(keyinfo,key_reflength,keypos,anc_key,
- anc_buff+anc_length,(my_off_t *) 0);
- if (!s_length)
+ if (!(s_length=remove_key(keyinfo,key_reflength,keypos,anc_key,
+ anc_buff+anc_length,(my_off_t *) 0)))
goto err;
+
anc_length-=s_length;
mi_putint(anc_buff,anc_length,key_reflength);
@@ -668,10 +685,10 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo,
mi_putint(buff,buff_length,nod_flag);
/* remove key from anc_buff */
- s_length=remove_key(keyinfo,key_reflength,keypos,anc_key,
- anc_buff+anc_length,(my_off_t *) 0);
- if (!s_length)
+ if (!(s_length= remove_key(keyinfo,key_reflength,keypos,anc_key,
+ anc_buff+anc_length,(my_off_t *) 0)))
goto err;
+
anc_length-=s_length;
mi_putint(anc_buff,anc_length,key_reflength);
@@ -731,6 +748,7 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (_mi_write_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,buff))
goto err;
DBUG_RETURN(anc_length <= (uint) keyinfo->block_length/2);
+
err:
DBUG_RETURN(-1);
} /* underflow */
@@ -768,6 +786,7 @@ static uint remove_key(MI_KEYDEF *keyinfo, uint nod_flag,
/* Calculate length of key */
if (!(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey))
DBUG_RETURN(0); /* Error */
+
if (next_block && nod_flag)
*next_block= _mi_kpos(nod_flag,keypos);
s_length=(int) (keypos-start);
diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c
index 43783ca2d36..3a4dafade23 100644
--- a/myisam/mi_dynrec.c
+++ b/myisam/mi_dynrec.c
@@ -768,11 +768,21 @@ uint _mi_rec_pack(MI_INFO *info, register byte *to, register const byte *from)
}
else if (type == FIELD_VARCHAR)
{
- uint tmp_length=uint2korr(from);
- store_key_length_inc(to,tmp_length);
- memcpy(to,from+2,tmp_length);
- to+=tmp_length;
- continue;
+ uint pack_length= HA_VARCHAR_PACKLENGTH(rec->length -1);
+ uint tmp_length;
+ if (pack_length == 1)
+ {
+ tmp_length= (uint) *(uchar*) from;
+ *to++= *from;
+ }
+ else
+ {
+ tmp_length= uint2korr(from);
+ store_key_length_inc(to,tmp_length);
+ }
+ memcpy(to, from+pack_length,tmp_length);
+ to+= tmp_length;
+ continue;
}
else
{
@@ -878,9 +888,20 @@ my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *rec_buff,
}
else if (type == FIELD_VARCHAR)
{
- uint tmp_length=uint2korr(record);
- to+=get_pack_length(tmp_length)+tmp_length;
- continue;
+ uint pack_length= HA_VARCHAR_PACKLENGTH(rec->length -1);
+ uint tmp_length;
+ if (pack_length == 1)
+ {
+ tmp_length= (uint) *(uchar*) record;
+ to+= 1+ tmp_length;
+ continue;
+ }
+ else
+ {
+ tmp_length= uint2korr(record);
+ to+= get_pack_length(tmp_length)+tmp_length;
+ }
+ continue;
}
else
{
@@ -894,9 +915,7 @@ my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *rec_buff,
}
}
else
- {
- to+=length;
- }
+ to+= length;
}
if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) ||
(bit != 1 && (flag & ~(bit - 1))))
@@ -944,13 +963,27 @@ ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
{
if (type == FIELD_VARCHAR)
{
- get_key_length(length,from);
- if (length > rec_length-2)
- goto err;
- int2store(to,length);
- memcpy(to+2,from,length);
- from+=length;
- continue;
+ uint pack_length= HA_VARCHAR_PACKLENGTH(rec_length-1);
+ if (pack_length == 1)
+ {
+ length= (uint) *(uchar*) from;
+ if (length > rec_length-1)
+ goto err;
+ *to= *from++;
+ }
+ else
+ {
+ get_key_length(length, from);
+ if (length > rec_length-2)
+ goto err;
+ int2store(to,length);
+ }
+ if (from+length > from_end)
+ goto err;
+ memcpy(to+pack_length, from, length);
+ from+= length;
+ min_pack_length--;
+ continue;
}
if (flag & bit)
{
@@ -1018,15 +1051,17 @@ ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
if (min_pack_length > (uint) (from_end - from))
goto err;
min_pack_length-=rec_length;
- memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
+ memcpy(to, (byte*) from, (size_t) rec_length);
+ from+=rec_length;
}
}
if (info->s->calc_checksum)
from++;
if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
DBUG_RETURN(found_length);
+
err:
- my_errno=HA_ERR_RECORD_DELETED;
+ my_errno= HA_ERR_WRONG_IN_RECORD;
DBUG_PRINT("error",("to_end: %lx -> %lx from_end: %lx -> %lx",
to,to_end,from,from_end));
DBUG_DUMP("from",(byte*) info->rec_buff,info->s->base.min_pack_length);
diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c
index 4b011ca424f..ba32bb9115a 100644
--- a/myisam/mi_extra.c
+++ b/myisam/mi_extra.c
@@ -15,7 +15,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "myisamdef.h"
-#ifdef HAVE_MMAP
+#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
@@ -186,7 +186,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
if (info->opt_flag & WRITE_CACHE_USED)
{
if ((error=flush_io_cache(&info->rec_cache)))
+ {
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info); /* Fatal error found */
+ }
}
break;
case HA_EXTRA_NO_READCHECK:
@@ -285,6 +288,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
{
error=my_errno;
share->changed=1;
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info); /* Fatal error found */
}
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
@@ -339,6 +343,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
if (error)
{
share->changed=1;
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info); /* Fatal error found */
}
}
diff --git a/myisam/mi_info.c b/myisam/mi_info.c
index cf63ef63618..bdece9c2ee3 100644
--- a/myisam/mi_info.c
+++ b/myisam/mi_info.c
@@ -105,3 +105,36 @@ int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag)
}
DBUG_RETURN(0);
}
+
+
+/*
+ Write a message to the error log.
+
+ SYNOPSIS
+ mi_report_error()
+ file_name Name of table file (e.g. index_file_name).
+ errcode Error number.
+
+ DESCRIPTION
+ This function supplies my_error() with a table name. Most error
+ messages need one. Since string arguments in error messages are limited
+ to 64 characters by convention, we ensure that in case of truncation,
+ that the end of the index file path is in the message. This contains
+ the most valuable information (the table name and the database name).
+
+ RETURN
+ void
+*/
+
+void mi_report_error(int errcode, const char *file_name)
+{
+ size_t lgt;
+ DBUG_ENTER("mi_report_error");
+ DBUG_PRINT("enter",("errcode %d, table '%s'", errcode, file_name));
+
+ if ((lgt= strlen(file_name)) > 64)
+ file_name+= lgt - 64;
+ my_error(errcode, MYF(ME_NOREFRESH), file_name);
+ DBUG_VOID_RETURN;
+}
+
diff --git a/myisam/mi_key.c b/myisam/mi_key.c
index 3545756779f..d7d10e116aa 100644
--- a/myisam/mi_key.c
+++ b/myisam/mi_key.c
@@ -34,10 +34,20 @@
static int _mi_put_key_in_record(MI_INFO *info,uint keynr,byte *record);
- /*
- ** Make a intern key from a record
- ** Ret: Length of key
- */
+/*
+ Make a intern key from a record
+
+ SYNOPSIS
+ _mi_make_key()
+ info MyiSAM handler
+ keynr key number
+ key Store created key here
+ record Record
+ filepos Position to record in the data file
+
+ RETURN
+ Length of key
+*/
uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
const byte *record, my_off_t filepos)
@@ -82,6 +92,19 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
length);
pos= (byte*) record+keyseg->start;
+ if (type == HA_KEYTYPE_BIT)
+ {
+ if (keyseg->bit_length)
+ {
+ uchar bits= get_rec_bits((uchar*) record + keyseg->bit_pos,
+ keyseg->bit_start, keyseg->bit_length);
+ *key++= bits;
+ length--;
+ }
+ memcpy((byte*) key, pos, length);
+ key+= length;
+ continue;
+ }
if (keyseg->flag & HA_SPACE_PACK)
{
end=pos+length;
@@ -102,10 +125,12 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
key+=char_length;
continue;
}
- if (keyseg->flag & HA_VAR_LENGTH)
+ if (keyseg->flag & HA_VAR_LENGTH_PART)
{
- uint tmp_length=uint2korr(pos);
- pos+=2; /* Skip VARCHAR length */
+ uint pack_length= keyseg->bit_start;
+ uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
+ uint2korr(pos));
+ pos+= pack_length; /* Skip VARCHAR length */
set_if_smaller(length,tmp_length);
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
@@ -161,7 +186,7 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
FIX_LENGTH(cs, pos, length, char_length);
memcpy((byte*) key, pos, char_length);
if (length > char_length)
- cs->cset->fill(cs, key+char_length, length-char_length, ' ');
+ cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
key+= length;
}
_mi_dpointer(info,key,filepos);
@@ -216,8 +241,11 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
if (!(*key++= (char) 1-*old++)) /* Copy null marker */
{
k_length-=length;
- if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART))
+ if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
+ {
k_length-=2; /* Skip length */
+ old+= 2;
+ }
continue; /* Found NULL */
}
}
@@ -244,7 +272,7 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
key+= char_length;
continue;
}
- else if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART))
+ else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
{
/* Length of key-part used with mi_rkey() always 2 */
uint tmp_length=uint2korr(pos);
@@ -271,7 +299,7 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
FIX_LENGTH(cs, pos, length, char_length);
memcpy((byte*) key, pos, char_length);
if (length > char_length)
- cs->cset->fill(cs,key+char_length, length-char_length, ' ');
+ cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
key+= length;
k_length-=length;
}
@@ -333,6 +361,26 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
}
record[keyseg->null_pos]&= ~keyseg->null_bit;
}
+ if (keyseg->type == HA_KEYTYPE_BIT)
+ {
+ uint length= keyseg->length;
+
+ if (keyseg->bit_length)
+ {
+ uchar bits= *key++;
+ set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
+ keyseg->bit_length);
+ length--;
+ }
+ else
+ {
+ clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
+ keyseg->bit_length);
+ }
+ memcpy(record + keyseg->start, (byte*) key, length);
+ key+= length;
+ continue;
+ }
if (keyseg->flag & HA_SPACE_PACK)
{
uint length;
@@ -356,7 +404,7 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
continue;
}
- if (keyseg->flag & HA_VAR_LENGTH)
+ if (keyseg->flag & HA_VAR_LENGTH_PART)
{
uint length;
get_key_length(length,key);
@@ -364,7 +412,13 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
if (length > keyseg->length || key+length > key_end)
goto err;
#endif
- memcpy(record+keyseg->start,(byte*) key, length);
+ /* Store key length */
+ if (keyseg->bit_start == 1)
+ *(uchar*) (record+keyseg->start)= (uchar) length;
+ else
+ int2store(record+keyseg->start, length);
+ /* And key data */
+ memcpy(record+keyseg->start + keyseg->bit_start, (byte*) key, length);
key+= length;
}
else if (keyseg->flag & HA_BLOB_PART)
@@ -426,6 +480,7 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf)
{ /* Read only key */
if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
return -1;
}
diff --git a/myisam/mi_keycache.c b/myisam/mi_keycache.c
index 99a2fd6db15..fb13f3703a2 100644
--- a/myisam/mi_keycache.c
+++ b/myisam/mi_keycache.c
@@ -79,6 +79,7 @@ int mi_assign_to_key_cache(MI_INFO *info,
if (flush_key_blocks(share->key_cache, share->kfile, FLUSH_RELEASE))
{
error= my_errno;
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info); /* Mark that table must be checked */
}
diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c
index 66950f62321..789d74680ef 100644
--- a/myisam/mi_locking.c
+++ b/myisam/mi_locking.c
@@ -66,6 +66,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
share->kfile,FLUSH_KEEP))
{
error=my_errno;
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info); /* Mark that table must be checked */
}
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
@@ -73,6 +74,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
if (end_io_cache(&info->rec_cache))
{
error=my_errno;
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info);
}
}
@@ -98,7 +100,10 @@ int mi_lock_database(MI_INFO *info, int lock_type)
else
share->not_flushed=1;
if (error)
+ {
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info);
+ }
}
if (info->lock_type != F_EXTRA_LCK)
{
@@ -285,6 +290,7 @@ void mi_update_status(void* param)
{
if (end_io_cache(&info->rec_cache))
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info);
}
info->opt_flag&= ~WRITE_CACHE_USED;
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index 2c85a03c6f4..d65a46a92fb 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -106,6 +106,12 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
share_buff.state.key_del=key_del;
share_buff.key_cache= multi_key_cache_search(name_buff, strlen(name_buff));
+ DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open",
+ if (strstr(name, "/t1"))
+ {
+ my_errno= HA_ERR_CRASHED;
+ goto err;
+ });
if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
{
if ((errno != EROFS && errno != EACCES) ||
@@ -302,6 +308,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
HA_KEYSEG *pos=share->keyparts;
for (i=0 ; i < keys ; i++)
{
+ share->keyinfo[i].share= share;
disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]);
disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
end_pos);
@@ -313,7 +320,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
{
disk_pos=mi_keyseg_read(disk_pos, pos);
- if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT)
+ if (pos->type == HA_KEYTYPE_TEXT ||
+ pos->type == HA_KEYTYPE_VARTEXT1 ||
+ pos->type == HA_KEYTYPE_VARTEXT2)
{
if (!pos->language)
pos->charset=default_charset_info;
@@ -388,7 +397,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
{
disk_pos=mi_keyseg_read(disk_pos, pos);
- if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT)
+ if (pos->type == HA_KEYTYPE_TEXT ||
+ pos->type == HA_KEYTYPE_VARTEXT1 ||
+ pos->type == HA_KEYTYPE_VARTEXT2)
{
if (!pos->language)
pos->charset=default_charset_info;
@@ -596,6 +607,10 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
err:
save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
+ if ((save_errno == HA_ERR_CRASHED) ||
+ (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
+ (save_errno == HA_ERR_CRASHED_ON_REPAIR))
+ mi_report_error(save_errno, name);
switch (errpos) {
case 6:
my_free((gptr) m_info,MYF(0));
@@ -1042,18 +1057,21 @@ int mi_keyseg_write(File file, const HA_KEYSEG *keyseg)
{
uchar buff[HA_KEYSEG_SIZE];
uchar *ptr=buff;
-
- *ptr++ =keyseg->type;
- *ptr++ =keyseg->language;
- *ptr++ =keyseg->null_bit;
- *ptr++ =keyseg->bit_start;
- *ptr++ =keyseg->bit_end;
- *ptr++ =0; /* Not used */
+ ulong pos;
+
+ *ptr++= keyseg->type;
+ *ptr++= keyseg->language;
+ *ptr++= keyseg->null_bit;
+ *ptr++= keyseg->bit_start;
+ *ptr++= keyseg->bit_end;
+ *ptr++= keyseg->bit_length;
mi_int2store(ptr,keyseg->flag); ptr+=2;
mi_int2store(ptr,keyseg->length); ptr+=2;
mi_int4store(ptr,keyseg->start); ptr+=4;
- mi_int4store(ptr,keyseg->null_pos); ptr+=4;
-
+ pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
+ mi_int4store(ptr, pos);
+ ptr+=4;
+
return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP));
}
@@ -1065,12 +1083,19 @@ char *mi_keyseg_read(char *ptr, HA_KEYSEG *keyseg)
keyseg->null_bit = *ptr++;
keyseg->bit_start = *ptr++;
keyseg->bit_end = *ptr++;
- ptr++;
+ keyseg->bit_length = *ptr++;
keyseg->flag = mi_uint2korr(ptr); ptr +=2;
keyseg->length = mi_uint2korr(ptr); ptr +=2;
keyseg->start = mi_uint4korr(ptr); ptr +=4;
keyseg->null_pos = mi_uint4korr(ptr); ptr +=4;
keyseg->charset=0; /* Will be filled in later */
+ if (keyseg->null_bit)
+ keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == 7));
+ else
+ {
+ keyseg->bit_pos= (uint16)keyseg->null_pos;
+ keyseg->null_pos= 0;
+ }
return ptr;
}
@@ -1210,7 +1235,10 @@ int mi_enable_indexes(MI_INFO *info)
if (share->state.state.data_file_length ||
(share->state.state.key_file_length != share->base.keystart))
+ {
+ mi_print_error(info->s, HA_ERR_CRASHED);
error= HA_ERR_CRASHED;
+ }
else
share->state.key_map= ((ulonglong) 1L << share->base.keys) - 1;
return error;
diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c
index 1a71d43a7f1..4b512dd89dd 100644
--- a/myisam/mi_packrec.c
+++ b/myisam/mi_packrec.c
@@ -91,8 +91,10 @@ static void uf_zero(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_blob(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end);
-static void uf_varchar(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
- uchar *to, uchar *end);
+static void uf_varchar1(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_varchar2(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
static void decode_bytes(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static uint decode_pos(MI_BIT_BUFF *bit_buff,MI_DECODE_TREE *decode_tree);
@@ -515,14 +517,16 @@ static void (*get_unpack_function(MI_COLUMNDEF *rec))
case FIELD_BLOB:
return &uf_blob;
case FIELD_VARCHAR:
- return &uf_varchar;
+ if (rec->length <= 256) /* 255 + 1 byte length */
+ return &uf_varchar1;
+ return &uf_varchar2;
case FIELD_LAST:
default:
return 0; /* This should never happend */
}
}
- /* De different functions to unpack a field */
+ /* The different functions to unpack a field */
static void uf_zerofill_skip_zero(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end)
@@ -766,7 +770,22 @@ static void uf_blob(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
}
}
-static void uf_varchar(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+
+static void uf_varchar1(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end __attribute__((unused)))
+{
+ if (get_bit(bit_buff))
+ to[0]= 0; /* Zero lengths */
+ else
+ {
+ ulong length=get_bits(bit_buff,rec->space_length_bits);
+ *to= (uchar) length;
+ decode_bytes(rec,bit_buff,to+1,to+1+length);
+ }
+}
+
+
+static void uf_varchar2(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end __attribute__((unused)))
{
if (get_bit(bit_buff))
@@ -1162,11 +1181,12 @@ static uint max_bit(register uint value)
/*****************************************************************************
Some redefined functions to handle files when we are using memmap
*****************************************************************************/
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
#ifdef HAVE_MMAP
-#include <sys/mman.h>
-
static int _mi_read_mempack_record(MI_INFO *info,my_off_t filepos,byte *buf);
static int _mi_read_rnd_mempack_record(MI_INFO*, byte *,my_off_t, my_bool);
@@ -1192,7 +1212,7 @@ my_bool _mi_memmap_file(MI_INFO *info)
DBUG_RETURN(0);
}
file_map=(byte*)
- mmap(0,share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN,PROT_READ,
+ my_mmap(0,(size_t)(share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN),PROT_READ,
MAP_SHARED | MAP_NORESERVE,info->dfile,0L);
if (file_map == (byte*) MAP_FAILED)
{
@@ -1211,7 +1231,7 @@ my_bool _mi_memmap_file(MI_INFO *info)
void _mi_unmap_file(MI_INFO *info)
{
- VOID(munmap((caddr_t) info->s->file_map,
+ VOID(my_munmap(info->s->file_map,
(size_t) info->s->state.state.data_file_length+
MEMMAP_EXTRA_MARGIN));
}
diff --git a/myisam/mi_page.c b/myisam/mi_page.c
index 16713c87e10..5240c063fba 100644
--- a/myisam/mi_page.c
+++ b/myisam/mi_page.c
@@ -40,6 +40,7 @@ uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo,
{
DBUG_PRINT("error",("Got errno: %d from key_cache_read",my_errno));
info->last_keypage=HA_OFFSET_ERROR;
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_RETURN(0);
}
@@ -51,6 +52,7 @@ uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo,
(ulong) page, page_size));
DBUG_DUMP("page", (char*) tmp, keyinfo->block_length);
info->last_keypage = HA_OFFSET_ERROR;
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno = HA_ERR_CRASHED;
tmp = 0;
}
diff --git a/myisam/mi_range.c b/myisam/mi_range.c
index 1e0fd42334e..e78f3b11625 100644
--- a/myisam/mi_range.c
+++ b/myisam/mi_range.c
@@ -172,9 +172,9 @@ static double _mi_search_pos(register MI_INFO *info,
if (flag == MI_FOUND_WRONG_KEY)
DBUG_RETURN(-1); /* error */
/*
- ** Didn't found match. keypos points at next (bigger) key
- * Try to find a smaller, better matching key.
- ** Matches keynr + [0-1]
+ Didn't found match. keypos points at next (bigger) key
+ Try to find a smaller, better matching key.
+ Matches keynr + [0-1]
*/
if (flag > 0 && ! nod_flag)
offset= 1.0;
@@ -185,8 +185,8 @@ static double _mi_search_pos(register MI_INFO *info,
else
{
/*
- ** Found match. Keypos points at the start of the found key
- ** Matches keynr+1
+ Found match. Keypos points at the start of the found key
+ Matches keynr+1
*/
offset=1.0; /* Matches keynr+1 */
if ((nextflag & SEARCH_FIND) && nod_flag &&
@@ -194,8 +194,8 @@ static double _mi_search_pos(register MI_INFO *info,
key_len != USE_WHOLE_KEY))
{
/*
- ** There may be identical keys in the tree. Try to match on of those.
- ** Matches keynr + [0-1]
+ There may be identical keys in the tree. Try to match on of those.
+ Matches keynr + [0-1]
*/
if ((offset=_mi_search_pos(info,keyinfo,key,key_len,SEARCH_FIND,
_mi_kpos(nod_flag,keypos))) < 0)
@@ -213,7 +213,8 @@ err:
/* Get keynummer of current key and max number of keys in nod */
-static uint _mi_keynr(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, uchar *keypos, uint *ret_max_key)
+static uint _mi_keynr(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
+ uchar *keypos, uint *ret_max_key)
{
uint nod_flag,keynr,max_key;
uchar t_buff[MI_MAX_KEY_BUFF],*end;
@@ -222,7 +223,7 @@ static uint _mi_keynr(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, u
nod_flag=mi_test_if_nod(page);
page+=2+nod_flag;
- if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY| HA_BINARY_PACK_KEY)))
+ if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
{
*ret_max_key= (uint) (end-page)/(keyinfo->keylength+nod_flag);
return (uint) (keypos-page)/(keyinfo->keylength+nod_flag);
diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c
index 12db00337ee..635a7eb2c48 100644
--- a/myisam/mi_rkey.c
+++ b/myisam/mi_rkey.c
@@ -78,6 +78,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
case HA_KEY_ALG_RTREE:
if (rtree_find_first(info,inx,key_buff,use_key_length,nextflag) < 0)
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
goto err;
}
diff --git a/myisam/mi_search.c b/myisam/mi_search.c
index 390e32b679d..c669a8be8f8 100644
--- a/myisam/mi_search.c
+++ b/myisam/mi_search.c
@@ -159,6 +159,7 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos));
DBUG_RETURN(0);
+
err:
DBUG_PRINT("exit",("Error: %d",my_errno));
info->lastpos= HA_OFFSET_ERROR;
@@ -256,6 +257,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
if (length == 0 || page > end)
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_PRINT("error",("Found wrong key: length: %u page: %p end: %p",
length, page, end));
@@ -386,7 +388,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
if (!(*from++))
continue;
}
- if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
+ if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
{
get_key_length(l,from);
}
@@ -402,6 +404,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
if (page > end)
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_PRINT("error",("Found wrong key: length: %u page: %p end: %p",
length, page, end));
@@ -447,7 +450,8 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
if (len < cmplen)
{
if ((keyinfo->seg->type != HA_KEYTYPE_TEXT &&
- keyinfo->seg->type != HA_KEYTYPE_VARTEXT))
+ keyinfo->seg->type != HA_KEYTYPE_VARTEXT1 &&
+ keyinfo->seg->type != HA_KEYTYPE_VARTEXT2))
my_flag= -1;
else
{
@@ -781,6 +785,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
{
if (length > (uint) keyseg->length)
{
+ mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
return 0; /* Error */
}
@@ -796,6 +801,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
("Found too long null packed key: %u of %u at %p",
length, keyseg->length, *page_pos));
DBUG_DUMP("key",(char*) *page_pos,16);
+ mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
return 0;
}
@@ -852,6 +858,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
DBUG_PRINT("error",("Found too long packed key: %u of %u at %p",
length, keyseg->length, *page_pos));
DBUG_DUMP("key",(char*) *page_pos,16);
+ mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
return 0; /* Error */
}
@@ -865,7 +872,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
continue;
}
if (keyseg->flag &
- (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
+ (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
{
uchar *tmp=page;
get_key_length(length,tmp);
@@ -907,6 +914,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
DBUG_PRINT("error",("Found too long binary packed key: %u of %u at %p",
length, keyinfo->maxlength, *page_pos));
DBUG_DUMP("key",(char*) *page_pos,16);
+ mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
return 0; /* Wrong key */
}
@@ -930,7 +938,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
if (!(*key++ = *from++))
continue; /* Null part */
}
- if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK))
+ if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
{
/* Get length of dynamic length key part */
if (from == from_end) { from=page; from_end=page_end; }
@@ -968,6 +976,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
if (from_end != page_end)
{
DBUG_PRINT("error",("Error when unpacking key"));
+ mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
return 0; /* Error */
}
@@ -1002,6 +1011,7 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
if (*return_key_length == 0)
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_RETURN(0);
}
@@ -1039,6 +1049,7 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
if (*return_key_length == 0)
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_RETURN(1);
}
@@ -1079,6 +1090,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
if (*return_key_length == 0)
{
DBUG_PRINT("error",("Couldn't find last key: page: %p", page));
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_RETURN(0);
}
@@ -1105,7 +1117,7 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
if (keyseg->flag & HA_NULL_PART)
if (!*key++)
continue;
- if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH))
+ if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))
{
uint length;
get_key_length(length,key);
@@ -1137,7 +1149,7 @@ uint _mi_keylength_part(MI_KEYDEF *keyinfo, register uchar *key,
if (keyseg->flag & HA_NULL_PART)
if (!*key++)
continue;
- if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH))
+ if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))
{
uint length;
get_key_length(length,key);
@@ -1269,8 +1281,10 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo,
page=info->buff+2+nod_flag;
} while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
- info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,
- info->lastkey);
+ if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,
+ info->lastkey)))
+ DBUG_RETURN(-1); /* Crashed */
+
info->int_keypos=page; info->int_maxpos=info->buff+mi_getint(info->buff)-1;
info->int_nod_flag=nod_flag;
info->int_keytree_version=keyinfo->version;
@@ -1405,7 +1419,8 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
sort_order=0;
if ((keyinfo->flag & HA_FULLTEXT) &&
((keyseg->type == HA_KEYTYPE_TEXT) ||
- (keyseg->type == HA_KEYTYPE_VARTEXT)) &&
+ (keyseg->type == HA_KEYTYPE_VARTEXT1) ||
+ (keyseg->type == HA_KEYTYPE_VARTEXT2)) &&
!use_strnxfrm(keyseg->charset))
sort_order=keyseg->charset->sort_order;
diff --git a/myisam/mi_test1.c b/myisam/mi_test1.c
index 77c4d3dfbad..aa6cd98ac8e 100644
--- a/myisam/mi_test1.c
+++ b/myisam/mi_test1.c
@@ -75,11 +75,11 @@ static int run_test(const char *filename)
recinfo[1].length= (key_field == FIELD_BLOB ? 4+mi_portable_sizeof_char_ptr :
key_length);
if (key_field == FIELD_VARCHAR)
- recinfo[1].length+=2;
+ recinfo[1].length+= HA_VARCHAR_PACKLENGTH(key_length);;
recinfo[2].type=extra_field;
recinfo[2].length= (extra_field == FIELD_BLOB ? 4 + mi_portable_sizeof_char_ptr : 24);
if (extra_field == FIELD_VARCHAR)
- recinfo[2].length+=2;
+ recinfo[2].length+= HA_VARCHAR_PACKLENGTH(recinfo[2].length);
if (opt_unique)
{
recinfo[3].type=FIELD_CHECK;
@@ -88,6 +88,9 @@ static int run_test(const char *filename)
rec_length=recinfo[0].length+recinfo[1].length+recinfo[2].length+
recinfo[3].length;
+ if (key_type == HA_KEYTYPE_VARTEXT1 &&
+ key_length > 255)
+ key_type= HA_KEYTYPE_VARTEXT2;
/* Define a key over the first column */
keyinfo[0].seg=keyseg;
@@ -134,7 +137,7 @@ static int run_test(const char *filename)
uniqueseg[1].flag|= HA_BLOB_PART;
}
else if (extra_field == FIELD_VARCHAR)
- uniqueseg[1].flag|= HA_VAR_LENGTH;
+ uniqueseg[1].flag|= HA_VAR_LENGTH_PART;
}
else
uniques=0;
@@ -330,7 +333,8 @@ static void create_key_part(char *key,uint rownr)
{
sprintf(key,"%*d",keyinfo[0].seg[0].length,rownr);
}
- else if (keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT)
+ else if (keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT1 ||
+ keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT2)
{ /* Alpha record */
/* Create a key that may be easily packed */
bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B');
@@ -372,7 +376,7 @@ static void create_key(char *key,uint rownr)
}
*key++=0;
}
- if (keyinfo[0].seg[0].flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ if (keyinfo[0].seg[0].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
{
uint tmp;
create_key_part(key+2,rownr);
@@ -410,11 +414,14 @@ static void create_record(char *record,uint rownr)
}
else if (recinfo[1].type == FIELD_VARCHAR)
{
- uint tmp;
- create_key_part(pos+2,rownr);
- tmp=strlen(pos+2);
- int2store(pos,tmp);
- pos+=recinfo[1].length;
+ uint tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1);
+ create_key_part(pos+pack_length,rownr);
+ tmp= strlen(pos+pack_length);
+ if (pack_length == 1)
+ *(uchar*) pos= (uchar) tmp;
+ else
+ int2store(pos,tmp);
+ pos+= recinfo[1].length;
}
else
{
@@ -434,10 +441,13 @@ static void create_record(char *record,uint rownr)
}
else if (recinfo[2].type == FIELD_VARCHAR)
{
- uint tmp;
- sprintf(pos+2,"... row: %d", rownr);
- tmp=strlen(pos+2);
- int2store(pos,tmp);
+ uint tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1);
+ sprintf(pos+pack_length, "... row: %d", rownr);
+ tmp= strlen(pos+pack_length);
+ if (pack_length == 1)
+ *(uchar*) pos= (uchar) tmp;
+ else
+ int2store(pos,tmp);
}
else
{
@@ -466,8 +476,9 @@ static void update_record(char *record)
}
else if (recinfo[1].type == FIELD_VARCHAR)
{
- uint length=uint2korr(pos);
- my_casedn(default_charset_info,pos+2,length);
+ uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1);
+ uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos);
+ my_casedn(default_charset_info,pos+pack_length,length);
pos+=recinfo[1].length;
}
else
@@ -493,10 +504,14 @@ static void update_record(char *record)
else if (recinfo[2].type == FIELD_VARCHAR)
{
/* Second field is longer than 10 characters */
- uint length=uint2korr(pos);
- bfill(pos+2+length,recinfo[2].length-length-2,'.');
- length=recinfo[2].length-2;
- int2store(pos,length);
+ uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1);
+ uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos);
+ bfill(pos+pack_length+length,recinfo[2].length-length-pack_length,'.');
+ length=recinfo[2].length-pack_length;
+ if (pack_length == 1)
+ *(uchar*) pos= (uchar) length;
+ else
+ int2store(pos,length);
}
else
{
@@ -519,12 +534,12 @@ static struct my_option my_long_options[] =
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"insert_rows", 'i', "Undocumented", (gptr*) &insert_count,
(gptr*) &insert_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0},
- {"key_alpha", 'a', "Undocumented",
+ {"key_alpha", 'a', "Use a key of type HA_KEYTYPE_TEXT",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"key_binary_pack", 'B', "Undocumented",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"key_blob", 'b', "Undocumented",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"key_cache", 'K', "Undocumented", (gptr*) &key_cacheing,
(gptr*) &key_cacheing, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"key_length", 'k', "Undocumented", (gptr*) &key_length, (gptr*) &key_length,
@@ -535,9 +550,9 @@ static struct my_option my_long_options[] =
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"key_space_pack", 'p', "Undocumented",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"key_varchar", 'w', "Undocumented",
+ {"key_varchar", 'w', "Test VARCHAR keys",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"null_fields", 'N', "Undocumented",
+ {"null_fields", 'N', "Define fields with NULL",
(gptr*) &null_fields, (gptr*) &null_fields, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
{"row_fixed_size", 'S', "Undocumented",
@@ -604,7 +619,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
key_field=FIELD_BLOB; /* blob key */
extra_field= FIELD_BLOB;
pack_seg|= HA_BLOB_PART;
- key_type= HA_KEYTYPE_VARTEXT;
+ key_type= HA_KEYTYPE_VARTEXT1;
break;
case 'k':
if (key_length < 4 || key_length > MI_MAX_KEY_LENGTH)
@@ -616,11 +631,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case 'w':
key_field=FIELD_VARCHAR; /* varchar keys */
extra_field= FIELD_VARCHAR;
- key_type= HA_KEYTYPE_VARTEXT;
- pack_seg|= HA_VAR_LENGTH;
+ key_type= HA_KEYTYPE_VARTEXT1;
+ pack_seg|= HA_VAR_LENGTH_PART;
create_flag|= HA_PACK_RECORD;
break;
- case 'K': /* Use key cacheing */
+ case 'K': /* Use key cacheing */
key_cacheing=1;
break;
case 'V':
diff --git a/myisam/mi_test3.c b/myisam/mi_test3.c
index 27d23317b5c..be4277cc65c 100644
--- a/myisam/mi_test3.c
+++ b/myisam/mi_test3.c
@@ -67,6 +67,7 @@ int main(int argc,char **argv)
bzero((char*) keyinfo,sizeof(keyinfo));
bzero((char*) recinfo,sizeof(recinfo));
+ bzero((char*) keyseg,sizeof(keyseg));
keyinfo[0].seg= &keyseg[0][0];
keyinfo[0].seg[0].start=0;
keyinfo[0].seg[0].length=8;
diff --git a/myisam/mi_test_all.res b/myisam/mi_test_all.res
index 94355bf1aa2..16b517d3f76 100644
--- a/myisam/mi_test_all.res
+++ b/myisam/mi_test_all.res
@@ -1,3 +1,6 @@
+myisamchk: MyISAM file test1
+myisamchk: warning: Size of indexfile is: 1024 Should be: 2048
+MyISAM-table 'test1' is usable but should be fixed
mi_test2 -s -L -K -R1 -m2000 ; Should give error 135
Error: 135 in write at record: 1105
got error: 135 when using MyISAM-database
@@ -5,46 +8,46 @@ myisamchk: MyISAM file test2
myisamchk: warning: Datafile is almost full, 65532 of 65534 used
MyISAM-table 'test2' is usable but should be fixed
Commands Used count Errors Recover errors
-open 17 0 0
-write 850 0 0
-update 85 0 0
-delete 850 0 0
-close 17 0 0
-extra 102 0 0
-Total 1921 0 0
+open 1 0 0
+write 50 0 0
+update 5 0 0
+delete 50 0 0
+close 1 0 0
+extra 6 0 0
+Total 113 0 0
Commands Used count Errors Recover errors
-open 18 0 0
-write 900 0 0
-update 90 0 0
-delete 900 0 0
-close 18 0 0
-extra 108 0 0
-Total 2034 0 0
+open 2 0 0
+write 100 0 0
+update 10 0 0
+delete 100 0 0
+close 2 0 0
+extra 12 0 0
+Total 226 0 0
-real 0m1.054s
-user 0m0.410s
-sys 0m0.640s
+real 0m0.791s
+user 0m0.137s
+sys 0m0.117s
-real 0m1.077s
-user 0m0.550s
-sys 0m0.530s
+real 0m0.659s
+user 0m0.252s
+sys 0m0.102s
-real 0m1.100s
-user 0m0.420s
-sys 0m0.680s
+real 0m0.571s
+user 0m0.188s
+sys 0m0.098s
-real 0m0.783s
-user 0m0.590s
-sys 0m0.200s
+real 0m1.111s
+user 0m0.236s
+sys 0m0.037s
-real 0m0.764s
-user 0m0.560s
-sys 0m0.210s
+real 0m0.621s
+user 0m0.242s
+sys 0m0.022s
-real 0m0.699s
-user 0m0.570s
-sys 0m0.130s
+real 0m0.698s
+user 0m0.248s
+sys 0m0.021s
-real 0m0.991s
-user 0m0.630s
-sys 0m0.350s
+real 0m0.683s
+user 0m0.265s
+sys 0m0.079s
diff --git a/myisam/mi_unique.c b/myisam/mi_unique.c
index ad685f4cbdc..f2d5f01be25 100644
--- a/myisam/mi_unique.c
+++ b/myisam/mi_unique.c
@@ -93,10 +93,12 @@ ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record)
}
}
pos= record+keyseg->start;
- if (keyseg->flag & HA_VAR_LENGTH)
+ if (keyseg->flag & HA_VAR_LENGTH_PART)
{
- uint tmp_length=uint2korr(pos);
- pos+=2; /* Skip VARCHAR length */
+ uint pack_length= keyseg->bit_start;
+ uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
+ uint2korr(pos));
+ pos+= pack_length; /* Skip VARCHAR length */
set_if_smaller(length,tmp_length);
}
else if (keyseg->flag & HA_BLOB_PART)
@@ -107,7 +109,8 @@ ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record)
length=tmp_length; /* The whole blob */
}
end= pos+length;
- if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT)
+ if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT1 ||
+ type == HA_KEYTYPE_VARTEXT2)
{
keyseg->charset->coll->hash_sort(keyseg->charset,
(const uchar*) pos, length, &seed1,
@@ -136,7 +139,8 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b,
for (keyseg=def->seg ; keyseg < def->end ; keyseg++)
{
enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
- uint length=keyseg->length;
+ uint a_length, b_length;
+ a_length= b_length= keyseg->length;
/* If part is NULL it's regarded as different */
if (keyseg->null_bit)
@@ -154,43 +158,59 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b,
}
pos_a= a+keyseg->start;
pos_b= b+keyseg->start;
- if (keyseg->flag & HA_VAR_LENGTH)
+ if (keyseg->flag & HA_VAR_LENGTH_PART)
{
- uint tmp_length=uint2korr(pos_a);
- if (tmp_length != uint2korr(pos_b))
- return 1;
- pos_a+=2; /* Skip VARCHAR length */
- pos_b+=2;
- set_if_smaller(length,tmp_length);
+ uint pack_length= keyseg->bit_start;
+ if (pack_length == 1)
+ {
+ a_length= (uint) *(uchar*) pos_a++;
+ b_length= (uint) *(uchar*) pos_b++;
+ }
+ else
+ {
+ a_length= uint2korr(pos_a);
+ b_length= uint2korr(pos_b);
+ pos_a+= 2; /* Skip VARCHAR length */
+ pos_b+= 2;
+ }
+ set_if_smaller(a_length, keyseg->length); /* Safety */
+ set_if_smaller(b_length, keyseg->length); /* safety */
}
else if (keyseg->flag & HA_BLOB_PART)
{
- /* Only compare 'length' characters if length<> 0 */
- uint a_length= _mi_calc_blob_length(keyseg->bit_start,pos_a);
- uint b_length= _mi_calc_blob_length(keyseg->bit_start,pos_b);
+ /* Only compare 'length' characters if length != 0 */
+ a_length= _mi_calc_blob_length(keyseg->bit_start,pos_a);
+ b_length= _mi_calc_blob_length(keyseg->bit_start,pos_b);
/* Check that a and b are of equal length */
- if (length && a_length > length)
- a_length=length;
- if (!length || length > b_length)
- length=b_length;
- if (length != a_length)
- return 1;
- /* Both strings are at least 'length' long */
+ if (keyseg->length)
+ {
+ /*
+ This is used in some cases when we are not interested in comparing
+ the whole length of the blob.
+ */
+ set_if_smaller(a_length, keyseg->length);
+ set_if_smaller(b_length, keyseg->length);
+ }
memcpy_fixed((byte*) &pos_a,pos_a+keyseg->bit_start,sizeof(char*));
memcpy_fixed((byte*) &pos_b,pos_b+keyseg->bit_start,sizeof(char*));
}
- if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT)
+ if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT1 ||
+ type == HA_KEYTYPE_VARTEXT2)
{
- if (mi_compare_text(keyseg->charset, (uchar *) pos_a, length,
- (uchar *) pos_b, length, 0, 0))
- return 1;
+ if (mi_compare_text(keyseg->charset, (uchar *) pos_a, a_length,
+ (uchar *) pos_b, b_length, 0, 1))
+ return 1;
}
else
{
- end= pos_a+length;
+ if (a_length != b_length)
+ return 1;
+ end= pos_a+a_length;
while (pos_a != end)
+ {
if (*pos_a++ != *pos_b++)
return 1;
+ }
}
}
return 0;
diff --git a/myisam/mi_update.c b/myisam/mi_update.c
index f62be133ed9..cda60694008 100644
--- a/myisam/mi_update.c
+++ b/myisam/mi_update.c
@@ -34,6 +34,9 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
LINT_INIT(changed);
LINT_INIT(old_checksum);
+ DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage",
+ mi_print_error(info->s, HA_ERR_CRASHED);
+ DBUG_RETURN(my_errno= HA_ERR_CRASHED););
if (!(info->update & HA_STATE_AKTIV))
{
DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND);
@@ -205,7 +208,10 @@ err:
} while (i-- != 0);
}
else
+ {
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info);
+ }
info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_ROW_CHANGED |
key_changed);
@@ -214,6 +220,9 @@ err:
VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
allow_break(); /* Allow SIGHUP & SIGINT */
if (save_errno == HA_ERR_KEY_NOT_FOUND)
+ {
+ mi_print_error(info->s, HA_ERR_CRASHED);
save_errno=HA_ERR_CRASHED;
+ }
DBUG_RETURN(my_errno=save_errno);
} /* mi_update */
diff --git a/myisam/mi_write.c b/myisam/mi_write.c
index cd9e73fba22..5d7e245c58f 100644
--- a/myisam/mi_write.c
+++ b/myisam/mi_write.c
@@ -52,6 +52,9 @@ int mi_write(MI_INFO *info, byte *record)
DBUG_ENTER("mi_write");
DBUG_PRINT("enter",("isam: %d data: %d",info->s->kfile,info->dfile));
+ DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage",
+ mi_print_error(info->s, HA_ERR_CRASHED);
+ DBUG_RETURN(my_errno= HA_ERR_CRASHED););
if (share->options & HA_OPTION_READ_ONLY_DATA)
{
DBUG_RETURN(my_errno=EACCES);
@@ -203,7 +206,10 @@ err:
}
}
else
+ {
+ mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info);
+ }
info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
my_errno=save_errno;
err2:
@@ -249,7 +255,7 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
comp_flag=SEARCH_BIGGER; /* Put after same key */
else if (keyinfo->flag & (HA_NOSAME|HA_FULLTEXT))
{
- comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No dupplicates */
+ comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No duplicates */
if (keyinfo->flag & HA_NULL_ARE_EQUAL)
comp_flag|= SEARCH_NULL_ARE_EQUAL;
}
@@ -348,6 +354,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length);
else
dupp_key_pos= HA_OFFSET_ERROR;
+
if (keyinfo->flag & HA_FULLTEXT)
{
uint off;
@@ -478,6 +485,7 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
{
if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_RETURN(-1);
}
@@ -487,6 +495,7 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
{
if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
{
+ mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_RETURN(-1);
}
@@ -582,6 +591,7 @@ int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo,
&after_key);
if (!key_pos)
DBUG_RETURN(-1);
+
length=(uint) (key_pos-buff);
a_length=mi_getint(buff);
mi_putint(buff,length,nod_flag);
@@ -602,6 +612,7 @@ int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo,
/* Store new page */
if (!(*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff))
DBUG_RETURN(-1);
+
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar *) 0,
(uchar*) 0, (uchar*) 0,
key_buff, &s_temp);
@@ -708,6 +719,7 @@ static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
memcpy(key, key_buff, length); /* previous key */
if (!(length=(*keyinfo->get_key)(keyinfo,0,&page,key_buff)))
{
+ mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_RETURN(0);
}
diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c
index d53e589e205..519e123e9da 100644
--- a/myisam/myisamchk.c
+++ b/myisam/myisamchk.c
@@ -50,7 +50,7 @@ static int stopwords_inited= 0;
static MY_TMPDIR myisamchk_tmpdir;
static const char *type_names[]=
-{ "?","char","binary", "short", "long", "float",
+{ "impossible","char","binary", "short", "long", "float",
"double","number","unsigned short",
"unsigned long","longlong","ulonglong","int24",
"uint24","int8","varchar", "varbin","?",
@@ -1699,11 +1699,11 @@ err:
sorting
*/
-static my_bool not_killed= 0;
+static int not_killed= 0;
-volatile my_bool *killed_ptr(MI_CHECK *param __attribute__((unused)))
+volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
{
- return &not_killed; /* always NULL */
+ return &not_killed; /* always NULL */
}
/* print warnings and errors */
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
index a41bcf5449b..a2d3dedf6df 100644
--- a/myisam/myisamdef.h
+++ b/myisam/myisamdef.h
@@ -356,6 +356,8 @@ typedef struct st_mi_sort_param
#define mi_mark_crashed_on_repair(x) { (x)->s->state.changed|=STATE_CRASHED|STATE_CRASHED_ON_REPAIR ; (x)->update|= HA_STATE_CHANGED; }
#define mi_is_crashed(x) ((x)->s->state.changed & STATE_CRASHED)
#define mi_is_crashed_on_repair(x) ((x)->s->state.changed & STATE_CRASHED_ON_REPAIR)
+#define mi_print_error(SHARE, ERRNO) \
+ mi_report_error((ERRNO), (SHARE)->index_file_name)
/* Functions to store length of space packed keys, VARCHAR or BLOB keys */
@@ -667,6 +669,7 @@ extern void _myisam_log_command(enum myisam_log_commands command,
extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info,
const byte *record,my_off_t filepos,
int result);
+extern void mi_report_error(int errcode, const char *file_name);
extern my_bool _mi_memmap_file(MI_INFO *info);
extern void _mi_unmap_file(MI_INFO *info);
extern uint save_pack_length(byte *block_buff,ulong length);
@@ -712,7 +715,7 @@ int mi_open_keyfile(MYISAM_SHARE *share);
void mi_setup_functions(register MYISAM_SHARE *share);
/* Functions needed by mi_check */
-volatile my_bool *killed_ptr(MI_CHECK *param);
+volatile int *killed_ptr(MI_CHECK *param);
void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_warning _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_info _VARARGS((MI_CHECK *param, const char *fmt,...));
diff --git a/myisam/myisampack.c b/myisam/myisampack.c
index 88f38be3c54..74bb541b220 100644
--- a/myisam/myisampack.c
+++ b/myisam/myisampack.c
@@ -748,7 +748,8 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
static_row_size=1;
for (count=huff_counts ; count < end_count ; count++)
{
- if (count->field_type == FIELD_BLOB || count->field_type == FIELD_VARCHAR)
+ if (count->field_type == FIELD_BLOB ||
+ count->field_type == FIELD_VARCHAR)
{
static_row_size=0;
break;
@@ -849,9 +850,11 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
}
else if (count->field_type == FIELD_VARCHAR)
{
- length=uint2korr(start_pos);
- pos=start_pos+2;
- end_pos=start_pos+length;
+ uint pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1);
+ length= (pack_length == 1 ? (uint) *(uchar*) start_pos :
+ uint2korr(start_pos));
+ pos= start_pos+pack_length;
+ end_pos= pos+length;
set_if_bigger(count->max_length,length);
}
if (count->field_length <= 8 &&
@@ -1833,17 +1836,19 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
}
case FIELD_VARCHAR:
{
- ulong col_length= uint2korr(start_pos);
+ uint pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1);
+ ulong col_length= (pack_length == 1 ? (uint) *(uchar*) start_pos :
+ uint2korr(start_pos));
if (!col_length)
{
write_bits(1,1); /* Empty varchar */
}
else
{
- byte *end=start_pos+2+col_length;
+ byte *end=start_pos+pack_length+col_length;
write_bits(0,1);
write_bits(col_length,count->length_bits);
- for (start_pos+=2 ; start_pos < end ; start_pos++)
+ for (start_pos+=pack_length ; start_pos < end ; start_pos++)
write_bits(tree->code[(uchar) *start_pos],
(uint) tree->code_len[(uchar) *start_pos]);
}
diff --git a/myisam/sort.c b/myisam/sort.c
index 7c6efa9a05b..9d2af2e8c70 100644
--- a/myisam/sort.c
+++ b/myisam/sort.c
@@ -860,7 +860,8 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
uchar *strpos;
BUFFPEK *buffpek,**refpek;
QUEUE queue;
- volatile my_bool *killed= killed_ptr(info->sort_info->param);
+ volatile int *killed= killed_ptr(info->sort_info->param);
+
DBUG_ENTER("merge_buffers");
count=error=0;
diff --git a/myisammrg/Makefile.am b/myisammrg/Makefile.am
index b5b1260385b..6975fab6770 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 = @MT_INCLUDES@ -I$(top_srcdir)/include
+INCLUDES = -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/myisammrg/myrg_static.c b/myisammrg/myrg_static.c
index b21b834ac24..9e76cbae07b 100644
--- a/myisammrg/myrg_static.c
+++ b/myisammrg/myrg_static.c
@@ -27,4 +27,4 @@ LIST *myrg_open_list=0;
static const char *merge_insert_methods[] =
{ "FIRST", "LAST", NullS };
TYPELIB merge_insert_method= { array_elements(merge_insert_methods)-1,"",
- merge_insert_methods};
+ merge_insert_methods, 0};
diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am
index 75adc45d73a..9963074daf5 100644
--- a/mysql-test/Makefile.am
+++ b/mysql-test/Makefile.am
@@ -32,7 +32,7 @@ endif
benchdir_root= $(prefix)
testdir = $(benchdir_root)/mysql-test
-EXTRA_SCRIPTS = mysql-test-run.sh mysql-test-run.pl install_test_db.sh
+EXTRA_SCRIPTS = mysql-test-run.sh mysql-test-run.pl install_test_db.sh valgrind.supp
EXTRA_DIST = $(EXTRA_SCRIPTS)
test_SCRIPTS = mysql-test-run install_test_db
test_DATA = std_data/client-key.pem std_data/client-cert.pem std_data/cacert.pem
@@ -47,17 +47,19 @@ 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/*.test $(srcdir)/t/*.opt $(srcdir)/t/*.sh $(srcdir)/t/*.slave-mi $(distdir)/t
+ $(INSTALL_DATA) $(srcdir)/t/*.test $(distdir)/t
+ -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(distdir)/t
+ $(INSTALL_DATA) $(srcdir)/t/*.opt $(srcdir)/t/*.sh $(srcdir)/t/*.slave-mi $(distdir)/t
$(INSTALL_DATA) $(srcdir)/include/*.inc $(distdir)/include
$(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.require $(distdir)/r
$(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.dat $(srcdir)/std_data/*.000001 $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.pem $(distdir)/std_data
+ $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(distdir)/lib
$(INSTALL_DATA) $(srcdir)/lib/*.pl $(distdir)/lib
-
install-data-local:
$(mkinstalldirs) \
$(DESTDIR)$(testdir)/t \
@@ -67,6 +69,7 @@ install-data-local:
$(DESTDIR)$(testdir)/lib
$(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(testdir)
$(INSTALL_DATA) $(srcdir)/t/*.test $(DESTDIR)$(testdir)/t
+ -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.opt $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.sh $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.slave-mi $(DESTDIR)$(testdir)/t
@@ -78,6 +81,7 @@ install-data-local:
$(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.pem $(DESTDIR)$(testdir)/std_data
+ $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(DESTDIR)$(testdir)/lib
$(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib
diff --git a/mysql-test/create-test-result b/mysql-test/create-test-result
index b9be2300976..ad19cdf08a1 100755
--- a/mysql-test/create-test-result
+++ b/mysql-test/create-test-result
@@ -6,7 +6,7 @@
# to start mysqld yourself and run mysqltest -r
RESULT_DIR=r
-if [ -z $EDITOR] ; then
+if [ -z "$EDITOR" ] ; then
EDITOR=vi
fi
@@ -24,7 +24,7 @@ function usage()
test_name=$1
-[ -z $test_name ] && usage
+[ -z "$test_name" ] && usage
result_file=$RESULT_DIR/$test_name.result
reject_file=$RESULT_DIR/$test_name.reject
diff --git a/mysql-test/include/big_test.inc b/mysql-test/include/big_test.inc
new file mode 100644
index 00000000000..6b149540c96
--- /dev/null
+++ b/mysql-test/include/big_test.inc
@@ -0,0 +1,4 @@
+--require r/big_test.require
+disable_query_log;
+eval select $BIG_TEST as using_big_test;
+enable_query_log;
diff --git a/mysql-test/include/have_cp932.inc b/mysql-test/include/have_cp932.inc
new file mode 100644
index 00000000000..b500dac0bbe
--- /dev/null
+++ b/mysql-test/include/have_cp932.inc
@@ -0,0 +1,4 @@
+-- require r/have_cp932.require
+disable_query_log;
+show collation like "cp932_japanese_ci";
+enable_query_log;
diff --git a/mysql-test/include/have_eucjpms.inc b/mysql-test/include/have_eucjpms.inc
new file mode 100644
index 00000000000..a5e1a5ac547
--- /dev/null
+++ b/mysql-test/include/have_eucjpms.inc
@@ -0,0 +1,4 @@
+-- require r/have_eucjpms.require
+disable_query_log;
+show collation like "eucjpms_japanese_ci";
+enable_query_log;
diff --git a/mysql-test/include/have_federated_db.inc b/mysql-test/include/have_federated_db.inc
new file mode 100644
index 00000000000..e4cf1366fda
--- /dev/null
+++ b/mysql-test/include/have_federated_db.inc
@@ -0,0 +1,4 @@
+-- require r/have_federated_db.require
+disable_query_log;
+show variables like "have_federated_engine";
+enable_query_log;
diff --git a/mysql-test/include/have_isam.inc b/mysql-test/include/have_isam.inc
deleted file mode 100644
index 830170c921f..00000000000
--- a/mysql-test/include/have_isam.inc
+++ /dev/null
@@ -1,4 +0,0 @@
--- require r/have_isam.require
-disable_query_log;
-show variables like "have_isam";
-enable_query_log;
diff --git a/mysql-test/include/have_ndb.inc b/mysql-test/include/have_ndb.inc
index 9b85197abe8..28fcf18cb16 100644
--- a/mysql-test/include/have_ndb.inc
+++ b/mysql-test/include/have_ndb.inc
@@ -3,6 +3,4 @@
disable_query_log;
show variables like "have_ndbcluster";
enable_query_log;
-#connect (server1,127.0.0.1,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
-#connect (server2,127.0.0.1,root,,test,$MASTER_MYPORT1,$MASTER_MYSOCK1);
-#connection server1;
+
diff --git a/mysql-test/include/ndb_default_cluster.inc b/mysql-test/include/ndb_default_cluster.inc
new file mode 100644
index 00000000000..2f900b6a0b4
--- /dev/null
+++ b/mysql-test/include/ndb_default_cluster.inc
@@ -0,0 +1,4 @@
+-- require r/ndb_default_cluster.require
+disable_query_log;
+show status like "Ndb_connected_host";
+enable_query_log;
diff --git a/mysql-test/include/ps_conv.inc b/mysql-test/include/ps_conv.inc
index 0a5bec26fe7..0b6e27619e6 100644
--- a/mysql-test/include/ps_conv.inc
+++ b/mysql-test/include/ps_conv.inc
@@ -104,7 +104,7 @@ drop table t5 ;
# 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,
-# c17 year, c18 bit, c19 bool, c20 char,
+# c17 year, c18 tinyint, c19 bool, c20 char,
# c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
# c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
# c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
diff --git a/mysql-test/include/ps_create.inc b/mysql-test/include/ps_create.inc
index dfc9c494b46..306ed3f1cac 100644
--- a/mysql-test/include/ps_create.inc
+++ b/mysql-test/include/ps_create.inc
@@ -34,7 +34,7 @@ eval create table t9
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,
- c17 year, c18 bit, c19 bool, c20 char,
+ c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
diff --git a/mysql-test/include/ps_modify.inc b/mysql-test/include/ps_modify.inc
index eb6820934f3..04b9734240b 100644
--- a/mysql-test/include/ps_modify.inc
+++ b/mysql-test/include/ps_modify.inc
@@ -59,7 +59,6 @@ execute stmt1 using @arg00;
select a,b from t1 where b=@arg00;
## truncate a table
---error 1295
prepare stmt1 from 'truncate table t1' ;
diff --git a/mysql-test/include/system_db_struct.inc b/mysql-test/include/system_db_struct.inc
index 5a7aa26c65a..c66590b2fd8 100644
--- a/mysql-test/include/system_db_struct.inc
+++ b/mysql-test/include/system_db_struct.inc
@@ -10,3 +10,5 @@ show create table user;
show create table func;
show create table tables_priv;
show create table columns_priv;
+show create table procs_priv;
+show create table proc;
diff --git a/mysql-test/include/testdb_only.inc b/mysql-test/include/testdb_only.inc
new file mode 100644
index 00000000000..ddc3f123d45
--- /dev/null
+++ b/mysql-test/include/testdb_only.inc
@@ -0,0 +1,30 @@
+#################### include/testdb_only.inc ######################
+# #
+# We must prevent to work on databases created by customers, #
+# because we DROP/CREATE/MODIFY objects with sometimes common #
+# names like STAFF, EMPLOYEE etc. #
+# #
+# Therefore we check the environment variable USE_RUNNING_SERVER. #
+# USE_RUNNING_SERVER is exported by "mysql-test-run" and could #
+# contain the following values: #
+# 0 -- mysql-test-run was started without the --extern option #
+# That means the test will be performed within the test #
+# area 'mysql-test/var/...' . #
+# 1 -- mysql-test-run was started with the --extern option #
+# That means the test will be performed by an already #
+# running server and data modifications will most probably #
+# outside of the common test area 'mysql-test/var/...' . #
+# #
+# If USE_RUNNING_SERVER is not 0 the test will be skipped. #
+# #
+###################################################################
+
+--disable_query_log
+eval set @USE_RUNNING_SERVER= '$USE_RUNNING_SERVER';
+--require r/testdb_only.require
+SELECT 'use extern server'
+ AS "Variable_name ",
+ IF(@USE_RUNNING_SERVER= '1','YES',
+ IF(@USE_RUNNING_SERVER= '0','NO','UNEXPECTED'))
+ AS "Value" ;
+--enable_query_log
diff --git a/mysql-test/include/varchar.inc b/mysql-test/include/varchar.inc
new file mode 100644
index 00000000000..13b4315f2b8
--- /dev/null
+++ b/mysql-test/include/varchar.inc
@@ -0,0 +1,238 @@
+# Initialise
+--disable_warnings
+drop table if exists t1,t2,t3;
+--enable_warnings
+
+disable_query_log;
+select "--- Testing varchar ---";
+enable_query_log;
+
+#
+# Simple basic test that endspace is saved
+#
+
+create table t1 (v varchar(10), c char(10), t text);
+insert into t1 values('+ ', '+ ', '+ ');
+set @a=repeat(' ',20);
+insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
+select concat('*',v,'*',c,'*',t,'*') from t1;
+
+# Check how columns are copied
+show create table t1;
+create table t2 like t1;
+show create table t2;
+create table t3 select * from t1;
+show create table t3;
+alter table t1 modify c varchar(10);
+show create table t1;
+alter table t1 modify v char(10);
+show create table t1;
+alter table t1 modify t varchar(10);
+show create table t1;
+select concat('*',v,'*',c,'*',t,'*') from t1;
+drop table t1,t2,t3;
+
+#
+# Testing of keys
+#
+create table t1 (v varchar(10), c char(10), t text, key(v), key(c), key(t(10)));
+show create table t1;
+disable_query_log;
+let $1=10;
+while ($1)
+{
+ let $2=27;
+ eval set @space=repeat(' ',10-$1);
+ while ($2)
+ {
+ eval set @char=char(ascii('a')+$2-1);
+ insert into t1 values(concat(@char,@space),concat(@char,@space),concat(@char,@space));
+ dec $2;
+ }
+ dec $1;
+}
+enable_query_log;
+select count(*) from t1;
+insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1)));
+select count(*) from t1 where v='a';
+select count(*) from t1 where c='a';
+select count(*) from t1 where t='a';
+select count(*) from t1 where v='a ';
+select count(*) from t1 where c='a ';
+select count(*) from t1 where t='a ';
+select count(*) from t1 where v between 'a' and 'a ';
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+select count(*) from t1 where v like 'a%';
+select count(*) from t1 where c like 'a%';
+select count(*) from t1 where t like 'a%';
+select count(*) from t1 where v like 'a %';
+# Test results differ for BDB, see comments in bdb.test
+# and they are also different from MySAM test results.
+--replace_column 9 #
+explain select count(*) from t1 where v='a ';
+--replace_column 9 #
+explain select count(*) from t1 where c='a ';
+--replace_column 9 #
+explain select count(*) from t1 where t='a ';
+--replace_column 9 #
+explain select count(*) from t1 where v like 'a%';
+--replace_column 9 #
+explain select count(*) from t1 where v between 'a' and 'a ';
+--replace_column 9 #
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+
+--error 1062
+alter table t1 add unique(v);
+alter table t1 add key(v);
+select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a';
+--replace_column 6 # 9 #
+explain select * from t1 where v='a';
+
+# GROUP BY
+
+select v,count(*) from t1 group by v limit 10;
+select v,count(t) from t1 group by v limit 10;
+select v,count(c) from t1 group by v limit 10;
+select sql_big_result v,count(t) from t1 group by v limit 10;
+select sql_big_result v,count(c) from t1 group by v limit 10;
+select c,count(*) from t1 group by c limit 10;
+select c,count(t) from t1 group by c limit 10;
+select sql_big_result c,count(t) from t1 group by c limit 10;
+select t,count(*) from t1 group by t limit 10;
+select t,count(t) from t1 group by t limit 10;
+select sql_big_result t,count(t) from t1 group by t limit 10;
+
+#
+# Test varchar > 255 bytes
+#
+
+alter table t1 modify v varchar(300), drop key v, drop key v_2, add key v (v);
+show create table t1;
+select count(*) from t1 where v='a';
+select count(*) from t1 where v='a ';
+select count(*) from t1 where v between 'a' and 'a ';
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+select count(*) from t1 where v like 'a%';
+select count(*) from t1 where v like 'a %';
+--replace_column 9 #
+explain select count(*) from t1 where v='a ';
+--replace_column 9 #
+explain select count(*) from t1 where v like 'a%';
+--replace_column 9 #
+explain select count(*) from t1 where v between 'a' and 'a ';
+--replace_column 9 #
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+--replace_column 9 #
+explain select * from t1 where v='a';
+
+# GROUP BY
+
+select v,count(*) from t1 group by v limit 10;
+select v,count(t) from t1 group by v limit 10;
+select sql_big_result v,count(t) from t1 group by v limit 10;
+
+#
+# Test varchar > 255 bytes, key < 255
+#
+
+alter table t1 drop key v, add key v (v(30));
+show create table t1;
+select count(*) from t1 where v='a';
+select count(*) from t1 where v='a ';
+select count(*) from t1 where v between 'a' and 'a ';
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+select count(*) from t1 where v like 'a%';
+select count(*) from t1 where v like 'a %';
+--replace_column 9 #
+explain select count(*) from t1 where v='a ';
+--replace_column 9 #
+explain select count(*) from t1 where v like 'a%';
+--replace_column 9 #
+explain select count(*) from t1 where v between 'a' and 'a ';
+--replace_column 9 #
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+--replace_column 9 #
+explain select * from t1 where v='a';
+
+# GROUP BY
+
+select v,count(*) from t1 group by v limit 10;
+select v,count(t) from t1 group by v limit 10;
+select sql_big_result v,count(t) from t1 group by v limit 10;
+
+#
+# Test varchar > 512 (special case for GROUP BY becasue of
+# CONVERT_IF_BIGGER_TO_BLOB define)
+#
+
+alter table t1 modify v varchar(600), drop key v, add key v (v);
+show create table t1;
+select v,count(*) from t1 group by v limit 10;
+select v,count(t) from t1 group by v limit 10;
+select sql_big_result v,count(t) from t1 group by v limit 10;
+
+drop table t1;
+
+#
+# Test unique keys
+#
+
+create table t1 (a char(10), unique (a));
+insert into t1 values ('a ');
+--error 1062
+insert into t1 values ('a ');
+
+alter table t1 modify a varchar(10);
+--error 1062
+insert into t1 values ('a '),('a '),('a '),('a ');
+--error 1062
+insert into t1 values ('a ');
+--error 1062
+insert into t1 values ('a ');
+--error 1062
+insert into t1 values ('a ');
+update t1 set a='a ' where a like 'a%';
+select concat(a,'.') from t1;
+update t1 set a='abc ' where a like 'a ';
+select concat(a,'.') from t1;
+update t1 set a='a ' where a like 'a %';
+select concat(a,'.') from t1;
+update t1 set a='a ' where a like 'a ';
+select concat(a,'.') from t1;
+drop table t1;
+
+#
+# test show create table
+#
+
+create table t1 (v varchar(10), c char(10), t text, key(v(5)), key(c(5)), key(t(5)));
+show create table t1;
+drop table t1;
+create table t1 (v char(10) character set utf8);
+show create table t1;
+drop table t1;
+
+create table t1 (v varchar(10), c char(10)) row_format=fixed;
+show create table t1;
+insert into t1 values('a','a'),('a ','a ');
+select concat('*',v,'*',c,'*') from t1;
+drop table t1;
+
+#
+# Test long varchars
+#
+
+create table t1 (v varchar(65530), key(v(10)));
+insert into t1 values(repeat('a',65530));
+select length(v) from t1 where v=repeat('a',65530);
+drop table t1;
+
+#
+# Bug #9489: problem with hash indexes
+#
+
+create table t1(a int, b varchar(12), key ba(b, a));
+insert into t1 values (1, 'A'), (20, NULL);
+explain select * from t1 where a=20 and b is null;
+select * from t1 where a=20 and b is null;
+drop table t1;
diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql
index 902af0b0842..97fa6fb955c 100644
--- a/mysql-test/lib/init_db.sql
+++ b/mysql-test/lib/init_db.sql
@@ -16,6 +16,11 @@ CREATE TABLE db (
Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
PRIMARY KEY Host (Host,Db,User),
KEY User (User)
) engine=MyISAM
@@ -23,8 +28,8 @@ CHARACTER SET utf8 COLLATE utf8_bin
comment='Database privileges';
-INSERT INTO db VALUES ('%','test' ,'','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y');
-INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y');
+INSERT INTO db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N');
+INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N');
CREATE TABLE host (
@@ -42,6 +47,8 @@ CREATE TABLE host (
Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
PRIMARY KEY Host (Host,Db)
) engine=MyISAM
CHARACTER SET utf8 COLLATE utf8_bin
@@ -73,6 +80,11 @@ CREATE TABLE user (
Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
+ Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
ssl_cipher BLOB NOT NULL,
x509_issuer BLOB NOT NULL,
@@ -80,15 +92,16 @@ CREATE TABLE user (
max_questions int(11) unsigned DEFAULT 0 NOT NULL,
max_updates int(11) unsigned DEFAULT 0 NOT NULL,
max_connections int(11) unsigned DEFAULT 0 NOT NULL,
+ max_user_connections int(11) unsigned DEFAULT 0 NOT NULL,
PRIMARY KEY Host (Host,User)
) engine=MyISAM
CHARACTER SET utf8 COLLATE utf8_bin
comment='Users and global privileges';
-INSERT INTO user VALUES ('localhost' ,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);
-INSERT INTO user VALUES ('@HOSTNAME@%','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);
-REPLACE INTO user VALUES ('127.0.0.1' ,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);
+INSERT INTO user VALUES ('localhost' ,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
+INSERT INTO user VALUES ('@HOSTNAME@%' ,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
+REPLACE INTO user VALUES ('127.0.0.1' ,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
INSERT INTO user (host,user) VALUES ('localhost','');
INSERT INTO user (host,user) VALUES ('@HOSTNAME@%','');
@@ -135,11 +148,11 @@ comment='Column privileges';
CREATE TABLE help_topic (
help_topic_id int unsigned not null,
- name varchar(64) not null,
+ name char(64) not null,
help_category_id smallint unsigned not null,
description text not null,
example text not null,
- url varchar(128) not null,
+ url char(128) not null,
primary key (help_topic_id),
unique index (name)
) engine=MyISAM
@@ -149,9 +162,9 @@ comment='help topics';
CREATE TABLE help_category (
help_category_id smallint unsigned not null,
- name varchar(64) not null,
+ name char(64) not null,
parent_category_id smallint unsigned null,
- url varchar(128) not null,
+ url char(128) not null,
primary key (help_category_id),unique index (name)
) engine=MyISAM
CHARACTER SET utf8
@@ -160,7 +173,7 @@ comment='help categories';
CREATE TABLE help_keyword (
help_keyword_id int unsigned not null,
- name varchar(64) not null,
+ name char(64) not null,
primary key (help_keyword_id),unique index (name)
) engine=MyISAM
CHARACTER SET utf8
@@ -468,3 +481,74 @@ INSERT INTO time_zone_leap_second (
,(662688015, 16) ,(709948816, 17) ,(741484817, 18)
,(773020818, 19) ,(820454419, 20) ,(867715220, 21)
,(915148821, 22);
+
+
+CREATE TABLE procs_priv (
+ Host char(60) binary DEFAULT '' NOT NULL,
+ Db char(64) binary DEFAULT '' NOT NULL,
+ User char(16) binary DEFAULT '' NOT NULL,
+ Routine_name char(64) binary DEFAULT '' NOT NULL,
+ Grantor char(77) DEFAULT '' NOT NULL,
+ Timestamp timestamp(14),
+ Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
+ PRIMARY KEY (Host,Db,User,Routine_name),
+ KEY Grantor (Grantor)
+) engine=MyISAM
+CHARACTER SET utf8 COLLATE utf8_bin
+comment='Procedure privileges';
+
+
+CREATE TABLE proc (
+ db char(64) binary 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,
+ 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,
+ created timestamp,
+ modified timestamp,
+ 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'
+ ) DEFAULT 0 NOT NULL,
+ comment char(64) binary DEFAULT '' NOT NULL,
+ PRIMARY KEY (db,name,type)
+) comment='Stored Procedures';
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 5a188dc6927..ae4136b5494 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -1046,10 +1046,8 @@ sub ndbcluster_install () {
}
mtr_report("Install ndbcluster");
my $ndbcluster_opts= $opt_bench ? "" : "--small";
- my $ndbcluster_port_base= $opt_ndbcluster_port + 2;
if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster",
["--port=$opt_ndbcluster_port",
- "--port-base=$ndbcluster_port_base",
"--data-dir=$glob_mysql_test_dir/var",
$ndbcluster_opts,
"--initial"],
@@ -1090,7 +1088,6 @@ sub ndbcluster_stop () {
{
return;
}
- my $ndbcluster_port_base= $opt_ndbcluster_port + 2;
# FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null
mtr_run("$glob_mysql_test_dir/ndb/ndbcluster",
["--port=$opt_ndbcluster_port",
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 8522ac5d955..5fb4d99d4f4 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -188,7 +188,7 @@ FAST_START=""
MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp
SLAVE_LOAD_TMPDIR=../../var/tmp #needs to be same length to test logging
RES_SPACE=" "
-MYSQLD_SRC_DIRS="strings mysys include extra regex isam merge myisam \
+MYSQLD_SRC_DIRS="strings mysys include extra regex myisam \
myisammrg heap sql"
MY_LOG_DIR="$MYSQL_TEST_DIR/var/log"
#
@@ -198,6 +198,13 @@ LD_LIBRARY_PATH="$BASEDIR/lib:$BASEDIR/libmysql/.libs:$BASEDIR/zlib/.libs:$LD_LI
DYLD_LIBRARY_PATH="$BASEDIR/lib:$BASEDIR/libmysql/.libs:$BASEDIR/zlib/.libs:$DYLD_LIBRARY_PATH"
export LD_LIBRARY_PATH DYLD_LIBRARY_PATH
+#
+# Allow anyone in the group to see the generated database files
+#
+UMASK=0660
+UMASK_DIR=0770
+export UMASK UMASK_DIR
+
MASTER_RUNNING=0
MASTER1_RUNNING=0
MASTER_MYPORT=9306
@@ -215,8 +222,9 @@ FAILED_CASES=
EXTRA_MASTER_OPT=""
EXTRA_MYSQL_TEST_OPT=""
EXTRA_MYSQLDUMP_OPT=""
+EXTRA_MYSQLSHOW_OPT=""
EXTRA_MYSQLBINLOG_OPT=""
-USE_RUNNING_SERVER=""
+USE_RUNNING_SERVER=0
USE_NDBCLUSTER=@USE_NDBCLUSTER@
USE_RUNNING_NDBCLUSTER=""
USE_PURIFY=""
@@ -250,12 +258,12 @@ while test $# -gt 0; do
--embedded-server)
USE_EMBEDDED_SERVER=1
USE_MANAGER=0 NO_SLAVE=1
- USE_RUNNING_SERVER=""
+ USE_RUNNING_SERVER=0
TEST_MODE="$TEST_MODE embedded" ;;
--purify)
USE_PURIFY=1
USE_MANAGER=0
- USE_RUNNING_SERVER=""
+ USE_RUNNING_SERVER=0
TEST_MODE="$TEST_MODE purify" ;;
--user=*) DBUSER=`$ECHO "$1" | $SED -e "s;--user=;;"` ;;
--force) FORCE=1 ;;
@@ -266,8 +274,8 @@ while test $# -gt 0; do
MASTER_MYSQLD=`$ECHO "$1" | $SED -e "s;--master-binary=;;"` ;;
--slave-binary=*)
SLAVE_MYSQLD=`$ECHO "$1" | $SED -e "s;--slave-binary=;;"` ;;
- --local) USE_RUNNING_SERVER="" ;;
- --extern) USE_RUNNING_SERVER="1" ;;
+ --local) USE_RUNNING_SERVER=0 ;;
+ --extern) USE_RUNNING_SERVER=1 ;;
--with-ndbcluster)
USE_NDBCLUSTER="--ndbcluster" ;;
--ndb-connectstring=*)
@@ -304,7 +312,7 @@ while test $# -gt 0; do
--no-manager | --skip-manager) USE_MANAGER=0 ;;
--manager)
USE_MANAGER=1
- USE_RUNNING_SERVER=
+ USE_RUNNING_SERVER=0
;;
--start-and-exit)
START_AND_EXIT=1
@@ -373,7 +381,7 @@ while test $# -gt 0; do
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb"
# This needs to be checked properly
# USE_MANAGER=1
- USE_RUNNING_SERVER=""
+ USE_RUNNING_SERVER=0
;;
--client-gdb )
if [ x$BINARY_DIST = x1 ] ; then
@@ -386,7 +394,7 @@ while test $# -gt 0; do
--manual-gdb )
DO_GDB=1
MANUAL_GDB=1
- USE_RUNNING_SERVER=""
+ USE_RUNNING_SERVER=0
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --gdb"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb"
;;
@@ -395,7 +403,7 @@ while test $# -gt 0; do
$ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --ddd option"
fi
DO_DDD=1
- USE_RUNNING_SERVER=""
+ USE_RUNNING_SERVER=0
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --gdb"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb"
;;
@@ -408,12 +416,12 @@ while test $# -gt 0; do
fi
# >=2.1.2 requires the --tool option, some versions write to stdout, some to stderr
valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck"
- VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16"
+ VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16 --suppressions=$CWD/valgrind.supp"
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-safemalloc --skip-bdb"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-safemalloc --skip-bdb"
SLEEP_TIME_AFTER_RESTART=10
SLEEP_TIME_FOR_DELETE=60
- USE_RUNNING_SERVER=""
+ USE_RUNNING_SERVER=0
if test "$1" = "--valgrind-all"
then
VALGRIND="$VALGRIND -v --show-reachable=yes"
@@ -436,7 +444,7 @@ while test $# -gt 0; do
STRACE_CLIENT=1
;;
--debug)
- EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \
+ EXTRA_MASTER_MYSQLD_TRACE=" \
--debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/master.trace"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT \
--debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/slave.trace"
@@ -444,6 +452,8 @@ while test $# -gt 0; do
--debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqltest.trace"
EXTRA_MYSQLDUMP_OPT="$EXTRA_MYSQLDUMP_OPT \
--debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqldump.trace"
+ EXTRA_MYSQLSHOW_OPT="$EXTRA_MYSQLSHOW_OPT \
+ --debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqlshow.trace"
EXTRA_MYSQLBINLOG_OPT="$EXTRA_MYSQLBINLOG_OPT \
--debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqlbinlog.trace"
EXTRA_MYSQL_CLIENT_TEST_OPT="--debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysql_client_test.trace"
@@ -451,6 +461,9 @@ while test $# -gt 0; do
--fast)
FAST_START=1
;;
+ --use-old-data)
+ USE_OLD_DATA=1;
+ ;;
-- ) shift; break ;;
--* ) $ECHO "Unrecognized option: $1"; exit 1 ;;
* ) break ;;
@@ -488,10 +501,9 @@ SLAVE_MYERR="$MYSQL_TEST_DIR/var/log/slave.err"
CURRENT_TEST="$MYSQL_TEST_DIR/var/log/current_test"
SMALL_SERVER="--key_buffer_size=1M --sort_buffer=256K --max_heap_table_size=1M"
-export MASTER_MYPORT MASTER_MYPORT1 SLAVE_MYPORT MYSQL_TCP_PORT MASTER_MYSOCK MASTER_MYSOCK1
+export MASTER_MYPORT SLAVE_MYPORT MYSQL_TCP_PORT MASTER_MYSOCK MASTER_MYSOCK1
-NDBCLUSTER_BASE_PORT=`expr $NDBCLUSTER_PORT + 2`
-NDBCLUSTER_OPTS="--port=$NDBCLUSTER_PORT --port-base=$NDBCLUSTER_BASE_PORT --data-dir=$MYSQL_TEST_DIR/var --ndb_mgm-extra-opts=$NDB_MGM_EXTRA_OPTS --ndb_mgmd-extra-opts=$NDB_MGMD_EXTRA_OPTS --ndbd-extra-opts=$NDBD_EXTRA_OPTS"
+NDBCLUSTER_OPTS="--port=$NDBCLUSTER_PORT --data-dir=$MYSQL_TEST_DIR/var --ndb_mgm-extra-opts=$NDB_MGM_EXTRA_OPTS --ndb_mgmd-extra-opts=$NDB_MGMD_EXTRA_OPTS --ndbd-extra-opts=$NDBD_EXTRA_OPTS"
NDB_BACKUP_DIR=$MYSQL_TEST_DIR/var/ndbcluster-$NDBCLUSTER_PORT
NDB_TOOLS_OUTPUT=$MYSQL_TEST_DIR/var/log/ndb_tools.log
@@ -545,6 +557,11 @@ if [ x$SOURCE_DIST = x1 ] ; then
else
MYSQL_DUMP="$BASEDIR/client/mysqldump"
fi
+ if [ -f "$BASEDIR/client/.libs/mysqlshow" ] ; then
+ MYSQL_SHOW="$BASEDIR/client/.libs/mysqlshow"
+ else
+ MYSQL_SHOW="$BASEDIR/client/mysqlshow"
+ fi
if [ -f "$BASEDIR/client/.libs/mysqlbinlog" ] ; then
MYSQL_BINLOG="$BASEDIR/client/.libs/mysqlbinlog"
else
@@ -557,9 +574,9 @@ if [ x$SOURCE_DIST = x1 ] ; then
CLIENT_BINDIR="$BASEDIR/client"
MYSQLADMIN="$CLIENT_BINDIR/mysqladmin"
WAIT_PID="$BASEDIR/extra/mysql_waitpid"
- MYSQL_MANAGER_CLIENT="$CLIENT_BINDIR/mysqlmanagerc"
- MYSQL_MANAGER="$BASEDIR/tools/mysqlmanager"
- MYSQL_MANAGER_PWGEN="$CLIENT_BINDIR/mysqlmanager-pwgen"
+ MYSQL_MANAGER_CLIENT="$CLIENT_BINDIR/mysqltestmanagerc"
+ MYSQL_MANAGER="$BASEDIR/tools/mysqltestmanager"
+ MYSQL_MANAGER_PWGEN="$CLIENT_BINDIR/mysqltestmanager-pwgen"
MYSQL="$CLIENT_BINDIR/mysql"
LANGUAGE="$BASEDIR/sql/share/english/"
CHARSETSDIR="$BASEDIR/sql/share/charsets"
@@ -616,12 +633,13 @@ else
fi
MYSQL_TEST="$CLIENT_BINDIR/mysqltest"
MYSQL_DUMP="$CLIENT_BINDIR/mysqldump"
+ MYSQL_SHOW="$CLIENT_BINDIR/mysqlshow"
MYSQL_BINLOG="$CLIENT_BINDIR/mysqlbinlog"
MYSQLADMIN="$CLIENT_BINDIR/mysqladmin"
WAIT_PID="$CLIENT_BINDIR/mysql_waitpid"
- MYSQL_MANAGER="$CLIENT_BINDIR/mysqlmanager"
- MYSQL_MANAGER_CLIENT="$CLIENT_BINDIR/mysqlmanagerc"
- MYSQL_MANAGER_PWGEN="$CLIENT_BINDIR/mysqlmanager-pwgen"
+ MYSQL_MANAGER="$CLIENT_BINDIR/mysqltestmanager"
+ MYSQL_MANAGER_CLIENT="$CLIENT_BINDIR/mysqltestmanagerc"
+ MYSQL_MANAGER_PWGEN="$CLIENT_BINDIR/mysqltestmanager-pwgen"
MYSQL="$CLIENT_BINDIR/mysql"
INSTALL_DB="./install_test_db --bin"
MYSQL_FIX_SYSTEM_TABLES="$CLIENT_BINDIR/mysql_fix_privilege_tables"
@@ -667,9 +685,9 @@ fi
if [ -z "$1" ]
then
- USE_RUNNING_SERVER=""
+ USE_RUNNING_SERVER=0
fi
-if [ -n "$USE_RUNNING_SERVER" ]
+if [ $USE_RUNNING_SERVER -eq 1 ]
then
MASTER_MYSOCK=$LOCAL_SOCKET;
DBUSER=${DBUSER:-test}
@@ -686,10 +704,11 @@ fi
MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --socket=$MASTER_MYSOCK --port=$MYSQL_TCP_PORT --silent $EXTRA_MYSQL_CLIENT_TEST_OPT"
MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT"
-MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR $EXTRA_MYSQLBINLOG_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"
MYSQL_FIX_SYSTEM_TABLES="$MYSQL_FIX_SYSTEM_TABLES --no-defaults --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD --basedir=$BASEDIR --bindir=$CLIENT_BINDIR --verbose"
MYSQL="$MYSQL --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD"
-export MYSQL MYSQL_DUMP MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES
+export MYSQL MYSQL_DUMP MYSQL_SHOW MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES
export CLIENT_BINDIR MYSQL_CLIENT_TEST CHARSETSDIR
export NDB_TOOLS_DIR
export NDB_MGM
@@ -720,6 +739,8 @@ if [ -n "$DO_CLIENT_GDB" -o -n "$DO_GDB" ] ; then
XTERM=`which xterm`
fi
+export MYSQL MYSQL_DUMP MYSQL_SHOW MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES CLIENT_BINDIR MASTER_MYSOCK
+
#++
# Function Definitions
#--
@@ -830,6 +851,7 @@ report_current_test () {
fi
}
+
report_stats () {
if [ $TOT_FAIL = 0 ]; then
$ECHO "All $TOT_TEST tests were successful."
@@ -848,7 +870,7 @@ report_stats () {
$ECHO "http://www.mysql.com/doc/en/MySQL_test_suite.html"
fi
- if test -z "$USE_RUNNING_SERVER"
+ if [ $USE_RUNNING_SERVER -eq 0 ]
then
# Report if there was any fatal warnings/errors in the log files
@@ -880,12 +902,14 @@ report_stats () {
mysql_install_db () {
$ECHO "Removing Stale Files"
- $RM -rf $MASTER_MYDDIR $MASTER_MYDDIR"1" $SLAVE_MYDDIR $MY_LOG_DIR/*
- $ECHO "Installing Master Databases"
- $INSTALL_DB
- if [ $? != 0 ]; then
+ if [ -z "$USE_OLD_DATA" ]; then
+ $RM -rf $MASTER_MYDDIR $MASTER_MYDDIR"1"
+ $ECHO "Installing Master Databases"
+ $INSTALL_DB
+ if [ $? != 0 ]; then
error "Could not install master test DBs"
- exit 1
+ exit 1
+ fi
fi
if [ ! -z "$USE_NDBCLUSTER" ]
then
@@ -897,6 +921,7 @@ mysql_install_db () {
fi
fi
$ECHO "Installing Slave Databases"
+ $RM -rf $SLAVE_MYDDIR $MY_LOG_DIR/*
$INSTALL_DB -slave
if [ $? != 0 ]; then
error "Could not install slave test DBs"
@@ -1132,6 +1157,10 @@ start_master()
this_master_myport=$MASTER_MYPORT
NOT_FIRST_MASTER_EXTRA_OPTS=""
fi
+ if [ -n "$EXTRA_MASTER_MYSQLD_TRACE" ]
+ then
+ CURR_MASTER_MYSQLD_TRACE="$EXTRA_MASTER_MYSQLD_TRACE$1"
+ fi
if [ -z "$DO_BENCH" ]
then
master_args="--no-defaults --log-bin=$MYSQL_TEST_DIR/var/log/master-bin$1 \
@@ -1150,12 +1179,12 @@ start_master()
--default-character-set=$CHARACTER_SET \
--tmpdir=$MYSQL_TMP_DIR \
--language=$LANGUAGE \
- --innodb_data_file_path=ibdata1:50M \
+ --innodb_data_file_path=ibdata1:128M:autoextend \
--open-files-limit=1024 \
$MASTER_40_ARGS \
$SMALL_SERVER \
$EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT \
- $NOT_FIRST_MASTER_EXTRA_OPTS"
+ $NOT_FIRST_MASTER_EXTRA_OPTS $CURR_MASTER_MYSQLD_TRACE"
else
master_args="--no-defaults --log-bin=$MYSQL_TEST_DIR/var/log/master-bin$1 \
--server-id=$id --rpl-recovery-rank=1 \
@@ -1171,7 +1200,7 @@ start_master()
$USE_NDBCLUSTER \
--tmpdir=$MYSQL_TMP_DIR \
--language=$LANGUAGE \
- --innodb_data_file_path=ibdata1:50M \
+ --innodb_data_file_path=ibdata1:128M:autoextend \
$MASTER_40_ARGS \
$SMALL_SERVER \
$EXTRA_MASTER_OPT $EXTRA_MASTER_MYSQLD_OPT \
@@ -1432,18 +1461,21 @@ stop_master ()
mysql_stop ()
{
- $ECHO "Ending Tests"
- $ECHO "Shutting-down MySQL daemon"
- $ECHO ""
- stop_master
- stop_master 1
- $ECHO "Master shutdown finished"
- stop_slave
- stop_slave 1
- stop_slave 2
- $ECHO "Slave shutdown finished"
- stop_ndbcluster
- return 1
+ if [ "$MASTER_RUNNING" = 1 ]
+ then
+ $ECHO "Ending Tests"
+ $ECHO "Shutting-down MySQL daemon"
+ $ECHO ""
+ stop_master
+ stop_master 1
+ $ECHO "Master shutdown finished"
+ stop_slave
+ stop_slave 1
+ stop_slave 2
+ $ECHO "Slave shutdown finished"
+ stop_ndbcluster
+ fi
+ return 1
}
mysql_restart ()
@@ -1471,13 +1503,7 @@ run_testcase ()
tsrcdir=$TESTDIR/$tname-src
result_file="r/$tname.result"
echo $tname > $CURRENT_TEST
- SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0`
- if [ -f "$TESTDIR/$tname.disabled" ]
- then
- comment=`$CAT $TESTDIR/$tname.disabled`;
- disable_test $tname "$comment"
- return
- fi
+ SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0 \& \( $tname : federated \) = 0`
if [ "$USE_MANAGER" = 1 ] ; then
many_slaves=`$EXPR \( \( $tname : rpl_failsafe \) != 0 \) \| \( \( $tname : rpl_chain_temp_table \) != 0 \)`
fi
@@ -1507,6 +1533,22 @@ run_testcase ()
return
fi
+# if [ -f "$TESTDIR/$tname.disabled" ]
+# then
+# comment=`$CAT $TESTDIR/$tname.disabled`;
+# disable_test $tname "$comment"
+# return
+# fi
+ if [ -f "$TESTDIR/disabled.def" ] ; then
+ comment=`$GREP "^$tname *: *" $TESTDIR/disabled.def`;
+ if [ -n "$comment" ]
+ then
+ comment=`echo $comment | sed 's/^[^:]*: *//'`
+ disable_test $tname "$comment"
+ return
+ fi
+ fi
+
if [ "x$USE_EMBEDDED_SERVER" != "x1" ] ; then
# Stop all slave threads, so that we don't have useless reconnection
# attempts and error messages in case the slave and master servers restart.
@@ -1529,7 +1571,7 @@ run_testcase ()
done
fi
- if [ -z "$USE_RUNNING_SERVER" ] ;
+ if [ $USE_RUNNING_SERVER -eq 0 ] ;
then
if [ -f $master_opt_file ] ;
then
@@ -1671,7 +1713,7 @@ run_testcase ()
if [ x$FORCE != x1 ] ; then
$ECHO "Aborting: $tname failed in $TEST_MODE mode. To continue, re-run with '--force'."
$ECHO
- if [ -z "$DO_GDB" ] && [ -z "$USE_RUNNING_SERVER" ] && \
+ if [ -z "$DO_GDB" ] && [ $USE_RUNNING_SERVER -eq 0 ] && \
[ -z "$DO_DDD" ] && [ -z "$USE_EMBEDDED_SERVER" ]
then
mysql_stop
@@ -1680,13 +1722,11 @@ run_testcase ()
exit 1
fi
FAILED_CASES="$FAILED_CASES $tname"
- if [ -z "$DO_GDB" ] && [ -z "$USE_RUNNING_SERVER" ] && \
+ if [ -z "$DO_GDB" ] && [ $USE_RUNNING_SERVER -eq 0 ] && \
[ -z "$DO_DDD" ] && [ -z "$USE_EMBEDDED_SERVER" ]
then
mysql_restart
fi
- $ECHO "Resuming Tests"
- $ECHO ""
fi
fi
fi
@@ -1701,7 +1741,7 @@ run_testcase ()
[ "$DO_GCOV" ] && gcov_prepare
[ "$DO_GPROF" ] && gprof_prepare
-if [ -z "$USE_RUNNING_SERVER" ]
+if [ $USE_RUNNING_SERVER -eq 0 ]
then
if [ -z "$FAST_START" ]
then
@@ -1710,7 +1750,7 @@ then
$MYSQLADMIN --no-defaults --socket=$MASTER_MYSOCK1 -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
$MYSQLADMIN --no-defaults --socket=$SLAVE_MYSOCK -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
$MYSQLADMIN --no-defaults --host=$hostname --port=$MASTER_MYPORT -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
- $MYSQLADMIN --no-defaults --host=$hostname --port=$MASTER_MYPORT+1 -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
+ $MYSQLADMIN --no-defaults --host=$hostname --port=`expr $MASTER_MYPORT+1` -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
$MYSQLADMIN --no-defaults --host=$hostname --port=$SLAVE_MYPORT -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
$MYSQLADMIN --no-defaults --host=$hostname --port=`expr $SLAVE_MYPORT + 1` -u root -O connect_timeout=5 -O shutdown_timeout=20 shutdown > /dev/null 2>&1
sleep_until_file_deleted 0 $MASTER_MYPID
@@ -1761,6 +1801,9 @@ fi
$ECHO "Starting Tests"
+# Some test cases need USE_RUNNING_SERVER
+export USE_RUNNING_SERVER
+
#
# This can probably be deleted
#
@@ -1833,7 +1876,7 @@ fi
$ECHO $DASH72
$ECHO
-if [ -z "$DO_GDB" ] && [ -z "$USE_RUNNING_SERVER" ] && [ -z "$DO_DDD" ]
+if [ -z "$DO_GDB" ] && [ $USE_RUNNING_SERVER -eq 0 ] && [ -z "$DO_DDD" ]
then
mysql_stop
fi
diff --git a/mysql-test/mysql_test_run_new.c b/mysql-test/mysql_test_run_new.c
index 40e45a92851..41cd4706e0b 100644
--- a/mysql-test/mysql_test_run_new.c
+++ b/mysql-test/mysql_test_run_new.c
@@ -1507,9 +1507,12 @@ void setup(char *file __attribute__((unused)))
static char env_CHARSETSDIR[FN_REFLEN*2];
static char env_MYSQL[FN_REFLEN*2];
static char env_MYSQL_FIX_SYSTEM_TABLES[FN_REFLEN*2];
- static char env_NDB_TOOLS_DIR[FN_REFLEN*2];
static char env_CLIENT_BINDIR[FN_REFLEN*2];
static char env_MYSQL_CLIENT_TEST[FN_REFLEN*2];
+ static char env_NDB_TOOLS_DIR[FN_REFLEN*2];
+ static char env_NDB_MGM[FN_REFLEN*2];
+ static char env_NDB_BACKUP_DIR[FN_REFLEN*2];
+ static char env_NDB_TOOLS_OUTPUT[FN_REFLEN*2];
snprintf(env_MYSQL_TEST_DIR,FN_REFLEN*2,
"MYSQL_TEST_DIR=%s",mysql_test_dir);
@@ -1549,9 +1552,6 @@ void setup(char *file __attribute__((unused)))
base_dir,master_port, master_socket, base_dir, bin_dir);
putenv(env_MYSQL_FIX_SYSTEM_TABLES);
- snprintf(env_NDB_TOOLS_DIR, FN_REFLEN*2,
- "NDB_TOOLS_DIR=%s/ndb/tools", base_dir);
- putenv(env_NDB_TOOLS_DIR);
snprintf(env_CLIENT_BINDIR, FN_REFLEN*2,
"CLIENT_BINDIR=%s", bin_dir);
@@ -1563,6 +1563,30 @@ void setup(char *file __attribute__((unused)))
base_dir, master_socket, master_port);
putenv(env_MYSQL_CLIENT_TEST);
+ // NDB
+
+ snprintf(env_NDB_TOOLS_DIR, FN_REFLEN*2,
+ "NDB_TOOLS_DIR=%s/ndb/tools", base_dir);
+ putenv(env_NDB_TOOLS_DIR);
+
+ snprintf(env_NDB_MGM, FN_REFLEN*2,
+ "NDB_MGM=%s/ndb/src/mgmclient/ndb_mgm", base_dir);
+ putenv(env_NDB_MGM);
+
+ //NDBCLUSTER_PORT=9350
+ snprintf(env_NDB_BACKUP_DIR, FN_REFLEN*2,
+ "NDB_BACKUP_DIR=%s/var/ndbcluster-%i", mysql_test_dir, 9350);
+ putenv(env_NDB_BACKUP_DIR);
+
+ snprintf(env_NDB_TOOLS_OUTPUT, FN_REFLEN*2,
+ "NDB_TOOLS_OUTPUT=%s/var/log/ndb_tools.log", mysql_test_dir);
+ putenv(env_NDB_TOOLS_OUTPUT);
+
+ putenv((char *)"NDB_STATUS_OK=1");
+
+// NDB_MGM="$BASEDIR/ndb/src/mgmclient/ndb_mgm"
+// NDB_BACKUP_DIR=$MYSQL_TEST_DIR/var/ndbcluster-$NDBCLUSTER_PORT
+// NDB_TOOLS_OUTPUT=$MYSQL_TEST_DIR/var/log/ndb_tools.log
}
#endif
diff --git a/mysql-test/ndb/Makefile.am b/mysql-test/ndb/Makefile.am
index 502ccee099e..178e40fb19a 100644
--- a/mysql-test/ndb/Makefile.am
+++ b/mysql-test/ndb/Makefile.am
@@ -14,7 +14,6 @@ SUFFIXES = .sh
@RM@ -f $@ $@-t
@SED@ \
-e 's!@''ndb_port''@!$(ndb_port)!g' \
- -e 's!@''ndb_port_base''@!$(ndb_port_base)!g' \
-e 's!@''ndbbindir''@!$(ndbbindir)!g' \
-e 's!@''ndbtoolsdir''@!$(ndbtoolsdir)!g' \
$< > $@-t
diff --git a/mysql-test/ndb/basic.result b/mysql-test/ndb/basic.result
index 5ebd20a7f83..9d2b18881b9 100644
--- a/mysql-test/ndb/basic.result
+++ b/mysql-test/ndb/basic.result
@@ -26,17 +26,17 @@ CONNECT [<connectstring>] Connect to management server (reconnect i
QUIT Quit management client
<severity> = ALERT | CRITICAL | ERROR | WARNING | INFO | DEBUG
-<category> = STARTUP | SHUTDOWN | STATISTICS | CHECKPOINT | NODERESTART | CONNECTION | INFO | ERROR | GREP | DEBUG | BACKUP
+<category> = STARTUP | SHUTDOWN | STATISTICS | CHECKPOINT | NODERESTART | CONNECTION | INFO | ERROR | CONGESTION | DEBUG | BACKUP
<level> = 0 - 15
<id> = ALL | Any database node id
Connected to Management Server at: localhost:1186
-Node 1: started (Version 4.1.9)
-Node 2: started (Version 4.1.9)
+Node 1: started (Version 5.0.3)
+Node 2: started (Version 5.0.3)
-Node 1: started (Version 4.1.9)
+Node 1: started (Version 5.0.3)
-Node 2: started (Version 4.1.9)
+Node 2: started (Version 5.0.3)
Executing CLUSTERLOG on node 1 OK!
Executing CLUSTERLOG on node 2 OK!
diff --git a/mysql-test/ndb/ndb_config_2_node.ini b/mysql-test/ndb/ndb_config_2_node.ini
index c831a5c7ffa..a6a56376f33 100644
--- a/mysql-test/ndb/ndb_config_2_node.ini
+++ b/mysql-test/ndb/ndb_config_2_node.ini
@@ -15,6 +15,7 @@ HostName= CHOOSE_HOSTNAME_1 # hostname is a valid network adress
HostName= CHOOSE_HOSTNAME_2 # hostname is a valid network adress
[ndb_mgmd]
+HostName= CHOOSE_HOSTNAME_1 # hostname is a valid network adress
DataDir= CHOOSE_FILESYSTEM #
PortNumber= CHOOSE_PORT_MGM
@@ -25,6 +26,3 @@ PortNumber= CHOOSE_PORT_MGM
[mysqld]
[mysqld]
-
-[tcp default]
-PortNumber= CHOOSE_PORT_TRANSPORTER
diff --git a/mysql-test/ndb/ndb_range_bounds.pl b/mysql-test/ndb/ndb_range_bounds.pl
index 75b7f8a33e1..abe1ea28298 100644
--- a/mysql-test/ndb/ndb_range_bounds.pl
+++ b/mysql-test/ndb/ndb_range_bounds.pl
@@ -1,138 +1,218 @@
#
# test range scan bounds
-# output to mysql-test/t/ndb_range_bounds.test
-#
-# give option --all to generate all cases
+# give option --all to test all cases
+# set MYSQL_HOME to installation top
#
use strict;
use integer;
use Getopt::Long;
+use DBI;
my $opt_all = 0;
my $opt_cnt = 5;
-GetOptions("all" => \$opt_all, "cnt=i" => \$opt_cnt)
- or die "options are: --all --cnt=N";
+my $opt_verbose = 0;
+GetOptions("all" => \$opt_all, "cnt=i" => \$opt_cnt, "verbose" => \$opt_verbose)
+ or die "options are: --all --cnt=N --verbose";
-my $table = 't';
+my $mysql_home = $ENV{MYSQL_HOME};
+defined($mysql_home) or die "no MYSQL_HOME";
+my $dsn = "dbi:mysql:database=test;host=localhost;mysql_read_default_file=$mysql_home/var/my.cnf";
+my $opts = { RaiseError => 0, PrintError => 0, AutoCommit => 1, };
-print <<EOF;
---source include/have_ndb.inc
+my $dbh;
+my $sth;
+my $sql;
---disable_warnings
-drop table if exists $table;
---enable_warnings
+$dbh = DBI->connect($dsn, "root", undef, $opts) or die $DBI::errstr;
-# test range scan bounds
-# generated by mysql-test/ndb/ndb_range_bounds.pl
-# all selects must return 0
+my $table = 't';
-EOF
+$sql = "drop table if exists $table";
+$dbh->do($sql) or die $DBI::errstr;
-sub cut ($$@) {
- my($op, $key, @v) = @_;
+sub cut ($$$) {
+ my($op, $key, $val) = @_;
$op = '==' if $op eq '=';
- my(@w);
- eval "\@w = grep(\$_ $op $key, \@v)";
+ my(@w) = @$val;
+ eval "\@w = grep(\$_ $op $key, \@w)";
$@ and die $@;
- return @w;
+ return [ @w ];
}
-sub mkdummy (\@) {
+sub mkdummy ($) {
my ($val) = @_;
return {
'dummy' => 1,
'exp' => '9 = 9',
- 'cnt' => scalar @$val,
+ 'res' => $val,
};
}
-sub mkone ($$$\@) {
+sub mkone ($$$$) {
my($col, $op, $key, $val) = @_;
- my $cnt = scalar cut($op, $key, @$val);
+ my $res = cut($op, $key, $val);
return {
'exp' => "$col $op $key",
- 'cnt' => $cnt,
+ 'res' => $res,
};
}
-sub mktwo ($$$$$\@) {
+sub mktwo ($$$$$$) {
my($col, $op1, $key1, $op2, $key2, $val) = @_;
- my $cnt = scalar cut($op2, $key2, cut($op1, $key1, @$val));
+ my $res = cut($op2, $key2, cut($op1, $key1, $val));
return {
'exp' => "$col $op1 $key1 and $col $op2 $key2",
- 'cnt' => $cnt,
+ 'res' => $res,
};
}
-sub mkall ($$$\@) {
+sub mkall ($$$$) {
my($col, $key1, $key2, $val) = @_;
my @a = ();
- my $p = mkdummy(@$val);
+ my $p = mkdummy($val);
push(@a, $p) if $opt_all;
my @ops = qw(< <= = >= >);
for my $op (@ops) {
- my $p = mkone($col, $op, $key1, @$val);
- push(@a, $p) if $opt_all || $p->{cnt} != 0;
+ my $p = mkone($col, $op, $key1, $val);
+ push(@a, $p) if $opt_all || @{$p->{res}} != 0;
}
my @ops1 = $opt_all ? @ops : qw(= >= >);
my @ops2 = $opt_all ? @ops : qw(<= <);
for my $op1 (@ops1) {
for my $op2 (@ops2) {
- my $p = mktwo($col, $op1, $key1, $op2, $key2, @$val);
- push(@a, $p) if $opt_all || $p->{cnt} != 0;
+ my $p = mktwo($col, $op1, $key1, $op2, $key2, $val);
+ push(@a, $p) if $opt_all || @{$p->{res}} != 0;
}
}
+ warn scalar(@a)." cases\n" if $opt_verbose;
return \@a;
}
+my $casecnt = 0;
+
+sub verify ($$$) {
+ my($sql, $ord, $res) = @_;
+ warn "$sql\n" if $opt_verbose;
+ $sth = $dbh->prepare($sql) or die "prepare: $sql: $DBI::errstr";
+ $sth->execute() or die "execute: $sql: $DBI::errstr";
+ #
+ # BUG: execute can return success on error so check again
+ #
+ $sth->err and die "execute: $sql: $DBI::errstr";
+ my @out = ();
+ for my $b (@{$res->[0]}) {
+ for my $c (@{$res->[1]}) {
+ for my $d (@{$res->[2]}) {
+ push(@out, [$b, $c, $d]);
+ }
+ }
+ }
+ if ($ord) {
+ @out = sort {
+ $ord * ($a->[0] - $b->[0]) ||
+ $ord * ($a->[1] - $b->[1]) ||
+ $ord * ($a->[2] - $b->[2]) ||
+ 0
+ } @out;
+ }
+ my $cnt = scalar @out;
+ my $n = 0;
+ while (1) {
+ my $row = $sth->fetchrow_arrayref;
+ $row || last;
+ @$row == 3 or die "bad row: $sql: @$row";
+ for my $v (@$row) {
+ $v =~ s/^\s+|\s+$//g;
+ $v =~ /^\d+$/ or die "bad value: $sql: $v";
+ }
+ if ($ord) {
+ my $out = $out[$n];
+ $row->[0] == $out->[0] &&
+ $row->[1] == $out->[1] &&
+ $row->[2] == $out->[2] or
+ die "$sql: row $n: got row @$row != @$out";
+ }
+ $n++;
+ }
+ $sth->err and die "fetch: $sql: $DBI::errstr";
+ $n == $cnt or die "verify: $sql: got row count $n != $cnt";
+ $casecnt++;
+}
+
for my $nn ("bcd", "") {
my %nn;
for my $x (qw(b c d)) {
$nn{$x} = $nn =~ /$x/ ? "not null" : "null";
}
- print <<EOF;
+ warn "create table\n";
+ $sql = <<EOF;
create table $table (
a int primary key,
b int $nn{b},
c int $nn{c},
d int $nn{d},
index (b, c, d)
-) engine=ndb;
+) engine=ndb
EOF
+ $dbh->do($sql) or die $DBI::errstr;
+ warn "insert\n";
+ $sql = "insert into $table values(?, ?, ?, ?)";
+ $sth = $dbh->prepare($sql) or die $DBI::errstr;
my @val = (0..($opt_cnt-1));
my $v0 = 0;
for my $v1 (@val) {
for my $v2 (@val) {
for my $v3 (@val) {
- print "insert into $table values($v0, $v1, $v2, $v3);\n";
+ $sth->bind_param(1, $v0) or die $DBI::errstr;
+ $sth->bind_param(2, $v1) or die $DBI::errstr;
+ $sth->bind_param(3, $v2) or die $DBI::errstr;
+ $sth->bind_param(4, $v3) or die $DBI::errstr;
+ $sth->execute or die $DBI::errstr;
$v0++;
}
}
}
+ warn "generate cases\n";
my $key1 = 1;
my $key2 = 3;
- my $a1 = mkall('b', $key1, $key2, @val);
- my $a2 = mkall('c', $key1, $key2, @val);
- my $a3 = mkall('d', $key1, $key2, @val);
- for my $p1 (@$a1) {
- my $cnt1 = $p1->{cnt} * @val * @val;
- print "select count(*) - $cnt1 from $table";
- print " where $p1->{exp};\n";
- for my $p2 (@$a2) {
- my $cnt2 = $p1->{cnt} * $p2->{cnt} * @val;
- print "select count(*) - $cnt2 from $table";
- print " where $p1->{exp} and $p2->{exp};\n";
- for my $p3 (@$a3) {
- my $cnt3 = $p1->{cnt} * $p2->{cnt} * $p3->{cnt};
- print "select count(*) - $cnt3 from $table";
- print " where $p1->{exp} and $p2->{exp} and $p3->{exp};\n";
+ my $a1 = mkall('b', $key1, $key2, \@val);
+ my $a2 = mkall('c', $key1, $key2, \@val);
+ my $a3 = mkall('d', $key1, $key2, \@val);
+ warn "select\n";
+ for my $ord (0, +1, -1) {
+ my $orderby =
+ $ord == 0 ? "" :
+ $ord == +1 ? " order by b, c, d" :
+ $ord == -1 ? " order by b desc, c desc, d desc" : die "not here";
+ for my $p1 (@$a1) {
+ my $res = [ $p1->{res}, \@val, \@val ];
+ $sql = "select b, c, d from $table" .
+ " where $p1->{exp}" .
+ $orderby;
+ verify($sql, $ord, $res);
+ for my $p2 (@$a2) {
+ my $res = [ $p1->{res}, $p2->{res}, \@val ];
+ $sql = "select b, c, d from $table" .
+ " where $p1->{exp} and $p2->{exp}" .
+ $orderby;
+ verify($sql, $ord, $res);
+ for my $p3 (@$a3) {
+ my $res = [ $p1->{res}, $p2->{res}, $p3->{res} ];
+ $sql = "select b, c, d from $table" .
+ " where $p1->{exp} and $p2->{exp} and $p3->{exp}" .
+ $orderby;
+ verify($sql, $ord, $res);
+ }
}
}
}
- print <<EOF;
-drop table $table;
-EOF
+ warn "drop table\n";
+ $sql = "drop table $table";
+ $dbh->do($sql) or die $DBI::errstr;
}
+warn "verified $casecnt cases\n";
+warn "done\n";
+
# vim: set sw=2:
diff --git a/mysql-test/ndb/ndbcluster.sh b/mysql-test/ndb/ndbcluster.sh
index 16bb3a9b122..c09c013552e 100644
--- a/mysql-test/ndb/ndbcluster.sh
+++ b/mysql-test/ndb/ndbcluster.sh
@@ -6,7 +6,6 @@
# configurable parameters, make sure to change in mysqlcluterd as well
port=@ndb_port@
-port_base=@ndb_port_base@
fsdir=`pwd`
# end configurable parameters
@@ -96,7 +95,7 @@ while test $# -gt 0; do
port=`echo "$1" | sed -e "s;--port=;;"`
;;
--port-base=*)
- port_base=`echo "$1" | sed -e "s;--port-base=;;"`
+ $ECHO "--port-base option depricated. Ignored."
;;
--ndb_mgm-extra-opts=*)
NDB_MGM_EXTRA_OPTS=`echo "$1" | sed -e "s;--ndb_mgm-extra-opts=;;"`
@@ -192,7 +191,6 @@ if [ $initial_ndb ] ; then
-e s,"CHOOSE_HOSTNAME_".*,"$ndb_host",g \
-e s,"CHOOSE_FILESYSTEM","$fs_ndb",g \
-e s,"CHOOSE_PORT_MGM","$ndb_mgmd_port",g \
- -e s,"CHOOSE_PORT_TRANSPORTER","$port_base",g \
< ndb/ndb_config_2_node.ini \
> "$fs_ndb/config.ini"
fi
diff --git a/mysql-test/ndb/restart.test b/mysql-test/ndb/restart.test
index 6ea9e919368..4b4584dd739 100644
--- a/mysql-test/ndb/restart.test
+++ b/mysql-test/ndb/restart.test
@@ -8,5 +8,5 @@ sleep 5
all clusterlog connection=8
sleep 1
1 restart
-sleep 5
+sleep 10
clusterlog on all
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index 222477cece9..88b04b292ea 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -52,9 +52,9 @@ KEY NAME (NAME));
ALTER TABLE t1 CHANGE NAME NAME CHAR(80) not null;
SHOW FULL COLUMNS FROM t1;
Field Type Collation Null Key Default Extra Privileges Comment
-GROUP_ID int(10) unsigned NULL PRI 0 #
-LANG_ID smallint(5) unsigned NULL PRI 0 #
-NAME char(80) latin1_swedish_ci MUL #
+GROUP_ID int(10) unsigned NULL NO PRI 0 #
+LANG_ID smallint(5) unsigned NULL NO PRI 0 #
+NAME char(80) latin1_swedish_ci NO MUL #
DROP TABLE t1;
create table t1 (n int);
insert into t1 values(9),(3),(12),(10);
@@ -179,7 +179,7 @@ alter table t1 rename t2;
alter table t2 rename t1, add c char(10) comment "no comment";
show columns from t1;
Field Type Null Key Default Extra
-i int(10) unsigned PRI NULL auto_increment
+i int(10) unsigned NO PRI NULL auto_increment
c char(10) YES NULL
drop table t1;
create table t1 (a int, b int);
@@ -456,7 +456,7 @@ ALTER TABLE t1 DROP PRIMARY KEY;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` int(11) default NULL,
UNIQUE KEY `b` (`b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result
index 09c606b5a04..a56902e8ae7 100644
--- a/mysql-test/r/analyse.result
+++ b/mysql-test/r/analyse.result
@@ -36,16 +36,16 @@ create table t2 select * from t1 where 0=1 procedure analyse();
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `Field_name` binary(255) NOT NULL default '',
- `Min_value` binary(255) default NULL,
- `Max_value` binary(255) default NULL,
+ `Field_name` varbinary(255) NOT NULL default '',
+ `Min_value` varbinary(255) default NULL,
+ `Max_value` varbinary(255) default NULL,
`Min_length` bigint(11) NOT NULL default '0',
`Max_length` bigint(11) NOT NULL default '0',
`Empties_or_zeros` bigint(11) NOT NULL default '0',
`Nulls` bigint(11) NOT NULL default '0',
- `Avg_value_or_avg_length` binary(255) NOT NULL default '',
- `Std` binary(255) default NULL,
- `Optimal_fieldtype` binary(64) NOT NULL default ''
+ `Avg_value_or_avg_length` varbinary(255) NOT NULL default '',
+ `Std` varbinary(255) default NULL,
+ `Optimal_fieldtype` varbinary(64) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t1 where 0=1 procedure analyse();
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
@@ -55,16 +55,16 @@ create table t2 select * from t1 where 0=1 procedure analyse();
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `Field_name` binary(255) NOT NULL default '',
- `Min_value` binary(255) default NULL,
- `Max_value` binary(255) default NULL,
+ `Field_name` varbinary(255) NOT NULL default '',
+ `Min_value` varbinary(255) default NULL,
+ `Max_value` varbinary(255) default NULL,
`Min_length` bigint(11) NOT NULL default '0',
`Max_length` bigint(11) NOT NULL default '0',
`Empties_or_zeros` bigint(11) NOT NULL default '0',
`Nulls` bigint(11) NOT NULL default '0',
- `Avg_value_or_avg_length` binary(255) NOT NULL default '',
- `Std` binary(255) default NULL,
- `Optimal_fieldtype` binary(64) NOT NULL default ''
+ `Avg_value_or_avg_length` varbinary(255) NOT NULL default '',
+ `Std` varbinary(255) default NULL,
+ `Optimal_fieldtype` varbinary(64) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t2;
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
@@ -78,16 +78,16 @@ create table t2 select * from t1 where 0=1 procedure analyse();
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `Field_name` binary(255) NOT NULL default '',
- `Min_value` binary(255) default NULL,
- `Max_value` binary(255) default NULL,
+ `Field_name` varbinary(255) NOT NULL default '',
+ `Min_value` varbinary(255) default NULL,
+ `Max_value` varbinary(255) default NULL,
`Min_length` bigint(11) NOT NULL default '0',
`Max_length` bigint(11) NOT NULL default '0',
`Empties_or_zeros` bigint(11) NOT NULL default '0',
`Nulls` bigint(11) NOT NULL default '0',
- `Avg_value_or_avg_length` binary(255) NOT NULL default '',
- `Std` binary(255) default NULL,
- `Optimal_fieldtype` binary(64) NOT NULL default ''
+ `Avg_value_or_avg_length` varbinary(255) NOT NULL default '',
+ `Std` varbinary(255) default NULL,
+ `Optimal_fieldtype` varbinary(64) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t2;
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
@@ -102,3 +102,10 @@ select * from t1 procedure analyse();
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
test.t1.v " \\ 1 19 0 0 3.7619 NULL ENUM('"','""','"c','\'\0\\"','\'','\'\'','\'b','a\0\0\0b','a\0','a""""b','a\'\'\'\'b','abc','abc\'def\\hij"klm\0opq','a\\\\\\\\b','b\'','c"','d\\','The\ZEnd','\\','\\d','\\\\') NOT NULL
drop table t1;
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select * from t1 procedure analyse();
+Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
+test.t1.df 1.1 2.2 8 8 0 0 1.650000000 0.302500000 ENUM('1.1','2.2') NOT NULL
+drop table t1;
diff --git a/mysql-test/r/ansi.result b/mysql-test/r/ansi.result
index 212d28f918b..00a526df8ea 100644
--- a/mysql-test/r/ansi.result
+++ b/mysql-test/r/ansi.result
@@ -2,7 +2,7 @@ drop table if exists t1;
set sql_mode="MySQL40";
select @@sql_mode;
@@sql_mode
-NO_FIELD_OPTIONS,MYSQL40
+NO_FIELD_OPTIONS,MYSQL40,HIGH_NOT_PRECEDENCE
set @@sql_mode="ANSI";
select @@sql_mode;
@@sql_mode
diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result
index 993fe7e4213..793e50cf653 100644
--- a/mysql-test/r/archive.result
+++ b/mysql-test/r/archive.result
@@ -184,6 +184,22 @@ fld1 fld3
250503 heaving
250504 population
250505 bomb
+create table t3 engine=archive select * from t2;
+select * from t3 where fld3='bonfire';
+auto fld1 companynr fld3 fld4 fld5 fld6
+1191 068504 00 bonfire corresponds positively
+select count(*) from t3;
+count(*)
+1199
+rename table t3 to t4;
+Warnings:
+Error 7 Error on rename of './test/t3.ARN' to './test/t4.ARN' (Errcode: 2)
+select * from t4 where fld3='bonfire';
+auto fld1 companynr fld3 fld4 fld5 fld6
+1191 068504 00 bonfire corresponds positively
+select count(*) from t4;
+count(*)
+1199
INSERT INTO t2 VALUES (1,000001,00,'Omaha','teethe','neat','');
INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W');
INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring','');
@@ -2601,18 +2617,2423 @@ 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
-create table t3 engine=archive select * from t2;
-select * from t3 where fld3='bonfire';
+REPAIR TABLE t2;
+Table Op Msg_type Msg_text
+test.t2 repair 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
-select count(*) from t3;
-count(*)
-1203
-rename table t3 to t4;
-select * from t4 where fld3='bonfire';
+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
+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
+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
-select count(*) from t4;
-count(*)
-1203
+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
+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
+INSERT DELAYED INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','');
drop table t1, t2, t4;
diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result
index 428b2769fdb..13007c30607 100644
--- a/mysql-test/r/auto_increment.result
+++ b/mysql-test/r/auto_increment.result
@@ -163,7 +163,7 @@ last_insert_id()
255
insert into t1 set i = null;
Warnings:
-Warning 1264 Data truncated; out of range for column 'i' at row 1
+Warning 1264 Out of range value adjusted for column 'i' at row 1
select last_insert_id();
last_insert_id()
255
@@ -232,7 +232,7 @@ a b
delete from t1 where a=0;
update t1 set a=NULL where b=6;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 4
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 4
update t1 set a=300 where b=7;
SET SQL_MODE='';
insert into t1(a,b)values(NULL,8);
@@ -274,7 +274,7 @@ a b
delete from t1 where a=0;
update t1 set a=NULL where b=13;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 9
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 9
update t1 set a=500 where b=14;
select * from t1 order by b;
a b
diff --git a/mysql-test/r/backup.result b/mysql-test/r/backup.result
index e53c3c3eb55..c7b4b1c4155 100644
--- a/mysql-test/r/backup.result
+++ b/mysql-test/r/backup.result
@@ -5,6 +5,8 @@ backup table t4 to '../bogus';
Table Op Msg_type Msg_text
test.t4 backup error Failed copying .frm file (errno: X)
test.t4 backup status Operation failed
+Warnings:
+Error 1 Can't create/write to file 'MYSQL_TEST_DIR/var/bogus/t4.frm' (Errcode: X)
backup table t4 to '../tmp';
Table Op Msg_type Msg_text
test.t4 backup status OK
@@ -12,6 +14,8 @@ backup table t4 to '../tmp';
Table Op Msg_type Msg_text
test.t4 backup error Failed copying .frm file (errno: X)
test.t4 backup status Operation failed
+Warnings:
+Error 1 Can't create/write to file 'MYSQL_TEST_DIR/var/tmp/t4.frm' (Errcode: X)
drop table t4;
restore table t4 from '../tmp';
Table Op Msg_type Msg_text
@@ -28,6 +32,8 @@ drop table t1;
restore table t1 from '../bogus';
Table Op Msg_type Msg_text
t1 restore error Failed copying .frm file
+Warnings:
+Error 29 File 'MYSQL_TEST_DIR/var/bogus/t1.frm' not found (Errcode: X)
restore table t1 from '../tmp';
Table Op Msg_type Msg_text
test.t1 restore status OK
diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result
index 6da3dbb929d..876da3cb964 100644
--- a/mysql-test/r/bdb.result
+++ b/mysql-test/r/bdb.result
@@ -140,13 +140,13 @@ id parent_id level
1015 102 2
explain select level from t1 where level=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref level level 1 const 1 Using where; Using index
+1 SIMPLE t1 ref level level 1 const X Using index
explain select level,id from t1 where level=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref level level 1 const 1 Using where; Using index
+1 SIMPLE t1 ref level level 1 const X Using index
explain select level,id,parent_id from t1 where level=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref level level 1 const 1 Using where
+1 SIMPLE t1 ref level level 1 const X
select level,id from t1 where level=1;
level id
1 1002
@@ -625,7 +625,7 @@ id parent_id level
1016 102 2
explain select level from t1 where level=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref level level 1 const 1 Using where; Using index
+1 SIMPLE t1 ref level level 1 const X Using index
select level,id from t1 where level=1;
level id
1 1004
@@ -1284,3 +1284,609 @@ SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterd");
id
4
DROP TABLE t1;
+create temporary table t1 (a int, primary key(a)) engine=bdb;
+select * from t1;
+a
+alter table t1 add b int;
+select * from t1;
+a b
+drop table t1;
+set storage_engine=bdb;
+drop table if exists t1,t2,t3;
+--- Testing varchar ---
+--- Testing varchar ---
+create table t1 (v varchar(10), c char(10), t text);
+insert into t1 values('+ ', '+ ', '+ ');
+set @a=repeat(' ',20);
+insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
+Warnings:
+Note 1265 Data truncated for column 'v' at row 1
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+ *+*+ *
+*+ *+*+ *
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+create table t2 like t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+create table t3 select * from t1;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+alter table t1 modify c varchar(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` text
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+alter table t1 modify v char(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` text
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+alter table t1 modify t varchar(10);
+Warnings:
+Note 1265 Data truncated for column 't' at row 2
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` varchar(10) default NULL
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+*+*+ *
+*+*+*+ *
+drop table t1,t2,t3;
+create table t1 (v varchar(10), c char(10), t text, key(v), key(c), key(t(10)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `v` (`v`),
+ KEY `c` (`c`),
+ KEY `t` (`t`(10))
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+select count(*) from t1;
+count(*)
+270
+insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1)));
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where c='a';
+count(*)
+10
+select count(*) from t1 where t='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where c='a ';
+count(*)
+10
+select count(*) from t1 where t='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where c like 'a%';
+count(*)
+11
+select count(*) from t1 where t like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const # Using where
+explain select count(*) from t1 where c='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref c c 11 const # Using where
+explain select count(*) from t1 where t='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range t t 13 NULL # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where
+alter table t1 add unique(v);
+ERROR 23000: Duplicate entry '{ ' for key 1
+alter table t1 add key(v);
+select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a';
+qq
+*a*a*a*
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v,v_2 # 13 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(c) from t1 group by v limit 10;
+v count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(c) from t1 group by v limit 10;
+v count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(*) from t1 group by c limit 10;
+c count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(*) from t1 group by t limit 10;
+t count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(t) from t1 group by t limit 10;
+t count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result t,count(t) from t1 group by t limit 10;
+t count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 modify v varchar(300), drop key v, drop key v_2, add key v (v);
+Warnings:
+Warning 1071 Specified key was too long; max key length is 255 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(300) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`(255))
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 258 const # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 258 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 258 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 258 NULL # Using where
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 258 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 drop key v, add key v (v(30));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(300) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`(30))
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 modify v varchar(600), drop key v, add key v (v);
+Warnings:
+Warning 1071 Specified key was too long; max key length is 255 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(600) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`(255))
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+drop table t1;
+create table t1 (a char(10), unique (a));
+insert into t1 values ('a ');
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a' for key 1
+alter table t1 modify a varchar(10);
+insert into t1 values ('a '),('a '),('a '),('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+update t1 set a='a ' where a like 'a%';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='abc ' where a like 'a ';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='a ' where a like 'a %';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='a ' where a like 'a ';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+drop table t1;
+create table t1 (v varchar(10), c char(10), t text, key(v(5)), key(c(5)), key(t(5)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `v` (`v`(5)),
+ KEY `c` (`c`(5)),
+ KEY `t` (`t`(5))
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v char(10) character set utf8);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) character set utf8 default NULL
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v varchar(10), c char(10)) row_format=fixed;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED
+insert into t1 values('a','a'),('a ','a ');
+select concat('*',v,'*',c,'*') from t1;
+concat('*',v,'*',c,'*')
+*a*a*
+*a *a*
+drop table t1;
+create table t1 (v varchar(65530), key(v(10)));
+insert into t1 values(repeat('a',65530));
+select length(v) from t1 where v=repeat('a',65530);
+length(v)
+65530
+drop table t1;
+create table t1(a int, b varchar(12), key ba(b, a));
+insert into t1 values (1, 'A'), (20, NULL);
+explain select * from t1 where a=20 and b is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref ba ba 20 const,const 1 Using where
+select * from t1 where a=20 and b is null;
+a b
+20 NULL
+drop table t1;
+create table t1 (v varchar(65530), key(v));
+Warnings:
+Warning 1071 Specified key was too long; max key length is 255 bytes
+drop table if exists t1;
+create table t1 (v varchar(65536));
+Warnings:
+Note 1246 Converting column 'v' from VARCHAR to TEXT
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` mediumtext
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v varchar(65530) character set utf8);
+Warnings:
+Note 1246 Converting column 'v' from VARCHAR to TEXT
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` mediumtext character set utf8
+) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1
+drop table t1;
+set storage_engine=MyISAM;
diff --git a/mysql-test/r/bench_count_distinct.result b/mysql-test/r/bench_count_distinct.result
index fcc0c0948b3..62312870f59 100644
--- a/mysql-test/r/bench_count_distinct.result
+++ b/mysql-test/r/bench_count_distinct.result
@@ -7,5 +7,5 @@ explain extended select count(distinct n) from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL n 4 NULL 200 Using index
Warnings:
-Note 1003 select count(distinct test.t1.n) AS `count(distinct n)` from test.t1
+Note 1003 select count(distinct `test`.`t1`.`n`) AS `count(distinct n)` from `test`.`t1`
drop table t1;
diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result
index eb3d0da3f23..a0c8f317db2 100644
--- a/mysql-test/r/bigint.result
+++ b/mysql-test/r/bigint.result
@@ -7,7 +7,7 @@ select 9223372036854775807,-009223372036854775808;
9223372036854775807 -9223372036854775808
select +9999999999999999999,-9999999999999999999;
9999999999999999999 -9999999999999999999
-9999999999999999999 -10000000000000000000
+9999999999999999999 -9999999999999999999
select cast(9223372036854775808 as unsigned)+1;
cast(9223372036854775808 as unsigned)+1
9223372036854775809
@@ -16,7 +16,7 @@ select 9223372036854775808+1;
9223372036854775809
select -(0-3),round(-(0-3)), round(9999999999999999999);
-(0-3) round(-(0-3)) round(9999999999999999999)
-3 3 10000000000000000000
+3 3 9999999999999999999
create table t1 (a bigint unsigned not null, primary key(a));
insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612);
select * from t1;
@@ -87,6 +87,8 @@ drop table t1;
SELECT '0x8000000000000001'+0;
'0x8000000000000001'+0
0
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: '0x8000000000000001'
create table t1 (
value64 bigint unsigned not null,
value32 integer not null,
@@ -126,3 +128,20 @@ t2.value64=t1.value64;
value64 value32 value64 value32
9223372036854775807 2 9223372036854775807 4
drop table t1, t2;
+create table t1 select 1 as 'a';
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(1) NOT NULL default '0'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 select 9223372036854775809 as 'a';
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(19) unsigned NOT NULL default '0'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select * from t1;
+a
+9223372036854775809
+drop table t1;
diff --git a/mysql-test/r/binlog.result b/mysql-test/r/binlog.result
new file mode 100644
index 00000000000..5d5b78abe29
--- /dev/null
+++ b/mysql-test/r/binlog.result
@@ -0,0 +1,135 @@
+drop table if exists t1, t2;
+reset master;
+create table t1 (a int) engine=bdb;
+create table t2 (a int) engine=innodb;
+begin;
+insert t1 values (5);
+commit;
+begin;
+insert t2 values (5);
+commit;
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query 1 # use `test`; create table t1 (a int) engine=bdb
+master-bin.000001 # Query 1 # use `test`; create table t2 (a int) engine=innodb
+master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # use `test`; insert t1 values (5)
+master-bin.000001 # Query 1 # use `test`; COMMIT
+master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # use `test`; insert t2 values (5)
+master-bin.000001 # Xid 1 # COMMIT /* xid=11 */
+drop table t1,t2;
+reset master;
+create table t1 (n int) engine=innodb;
+begin;
+commit;
+drop table t1;
+show binlog events in 'master-bin.000001' from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query 1 # use `test`; create table t1 (n int) engine=innodb
+master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(100 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(99 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(98 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(97 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(96 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(95 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(94 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(93 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(92 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(91 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(90 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(89 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(88 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(87 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(86 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(85 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(84 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(83 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(82 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(81 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(80 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(79 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(78 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(77 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(76 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(75 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(74 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(73 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(72 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(71 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(70 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(69 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(68 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(67 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(66 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(65 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(64 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(63 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(62 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(61 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(60 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(59 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(58 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(57 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(56 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(55 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(54 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(53 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(52 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(51 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(50 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(49 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(48 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(47 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(46 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(45 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(44 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(43 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(42 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(41 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(40 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(39 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(38 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(37 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(36 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(35 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(34 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(33 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(32 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(31 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(30 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(29 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(28 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(27 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(26 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(25 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(24 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(23 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(22 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(21 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(20 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(19 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(18 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(17 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(16 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(15 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(14 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(13 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(12 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(11 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(10 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(9 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(8 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(7 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(6 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(5 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(4 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(3 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(2 + 4)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(1 + 4)
+master-bin.000001 # Xid 1 # COMMIT /* xid=18 */
+master-bin.000001 # Rotate 1 # master-bin.000002;pos=4
+show binlog events in 'master-bin.000002' from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 # Query 1 # use `test`; drop table t1
diff --git a/mysql-test/r/blackhole.result b/mysql-test/r/blackhole.result
index 4b779094376..66752b11655 100644
--- a/mysql-test/r/blackhole.result
+++ b/mysql-test/r/blackhole.result
@@ -73,7 +73,7 @@ explain extended select * from t1 where MATCH(a,b) AGAINST ("collections");
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 fulltext a a 0 1 Using where
Warnings:
-Note 1003 select test.t1.a AS `a`,test.t1.b AS `b` from test.t1 where (match test.t1.a,test.t1.b against (_latin1'collections'))
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (match `test`.`t1`.`a`,`test`.`t1`.`b` against (_latin1'collections'))
select * from t1 where MATCH(a,b) AGAINST ("indexes");
a b
Full-text indexes are called collections
diff --git a/mysql-test/r/bool.result b/mysql-test/r/bool.result
index a054eceec0c..184046a2d6f 100644
--- a/mysql-test/r/bool.result
+++ b/mysql-test/r/bool.result
@@ -33,6 +33,24 @@ a
SELECT * FROM t1 where (1 AND a) IS NULL;
a
NULL
+set sql_mode='high_not_precedence';
+select * from t1 where not a between 2 and 3;
+a
+set sql_mode=default;
+select * from t1 where not a between 2 and 3;
+a
+0
+1
+select a, a is false, a is true, a is unknown from t1;
+a a is false a is true a is unknown
+0 1 0 0
+1 0 1 0
+NULL 0 0 1
+select a, a is not false, a is not true, a is not unknown from t1;
+a a is not false a is not true a is not unknown
+0 0 1 1
+1 1 0 1
+NULL 1 1 0
SET @a=0, @b=0;
SELECT * FROM t1 WHERE NULL AND (@a:=@a+1);
a
diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result
index 541560afd36..1ca913e1259 100644
--- a/mysql-test/r/case.result
+++ b/mysql-test/r/case.result
@@ -66,7 +66,7 @@ explain extended select case a when 1 then 2 when 2 then 3 else 0 end as fcase,
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
Warnings:
-Note 1003 select (case test.t1.a when 1 then 2 when 2 then 3 else 0 end) AS `fcase`,count(0) AS `count(*)` from test.t1 group by (case test.t1.a when 1 then 2 when 2 then 3 else 0 end)
+Note 1003 select (case `test`.`t1`.`a` when 1 then 2 when 2 then 3 else 0 end) AS `fcase`,count(0) AS `count(*)` from `test`.`t1` group by (case `test`.`t1`.`a` when 1 then 2 when 2 then 3 else 0 end)
select case a when 1 then "one" when 2 then "two" else "nothing" end as fcase, count(*) from t1 group by fcase;
fcase count(*)
nothing 2
@@ -91,20 +91,26 @@ CASE WHEN 1 THEN 'a' ELSE 1.0 END AS c5,
CASE WHEN 1 THEN 1.0 ELSE 'a' END AS c6,
CASE WHEN 1 THEN 1 ELSE 1.0 END AS c7,
CASE WHEN 1 THEN 1.0 ELSE 1 END AS c8,
-CASE WHEN 1 THEN 1.0 END AS c9
+CASE WHEN 1 THEN 1.0 END AS c9,
+CASE WHEN 1 THEN 0.1e1 else 0.1 END AS c10,
+CASE WHEN 1 THEN 0.1e1 else 1 END AS c11,
+CASE WHEN 1 THEN 0.1e1 else '1' END AS c12
;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `c1` char(1) character set latin1 collate latin1_danish_ci NOT NULL default '',
- `c2` char(1) character set latin1 collate latin1_danish_ci NOT NULL default '',
- `c3` binary(1) NOT NULL default '',
- `c4` binary(1) NOT NULL default '',
- `c5` binary(3) NOT NULL default '',
- `c6` binary(3) NOT NULL default '',
- `c7` double(3,1) NOT NULL default '0.0',
- `c8` double(3,1) NOT NULL default '0.0',
- `c9` double(3,1) default NULL
+ `c1` varchar(1) character set latin1 collate latin1_danish_ci NOT NULL default '',
+ `c2` varchar(1) character set latin1 collate latin1_danish_ci NOT NULL default '',
+ `c3` varbinary(1) NOT NULL default '',
+ `c4` varbinary(1) NOT NULL default '',
+ `c5` varbinary(4) NOT NULL default '',
+ `c6` varbinary(4) NOT NULL default '',
+ `c7` decimal(5,1) NOT NULL default '0.0',
+ `c8` decimal(5,1) NOT NULL default '0.0',
+ `c9` decimal(5,1) default NULL,
+ `c10` double NOT NULL default '0',
+ `c11` double NOT NULL default '0',
+ `c12` varbinary(5) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
SELECT CASE
@@ -141,16 +147,16 @@ COALESCE('a' COLLATE latin1_bin,'b');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select coalesce(1) AS `COALESCE(1)`,coalesce(1.0) AS `COALESCE(1.0)`,coalesce(_latin1'a') AS `COALESCE('a')`,coalesce(1,1.0) AS `COALESCE(1,1.0)`,coalesce(1,_latin1'1') AS `COALESCE(1,'1')`,coalesce(1.1,_latin1'1') AS `COALESCE(1.1,'1')`,coalesce((_latin1'a' collate _latin1'latin1_bin'),_latin1'b') AS `COALESCE('a' COLLATE latin1_bin,'b')`
+Note 1003 select coalesce(1) AS `COALESCE(1)`,coalesce(1.0) AS `COALESCE(1.0)`,coalesce(_latin1'a') AS `COALESCE('a')`,coalesce(1,1.0) AS `COALESCE(1,1.0)`,coalesce(1,_latin1'1') AS `COALESCE(1,'1')`,coalesce(1.1,_latin1'1') AS `COALESCE(1.1,'1')`,coalesce((_latin1'a' collate latin1_bin),_latin1'b') AS `COALESCE('a' COLLATE latin1_bin,'b')`
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`COALESCE(1)` int(1) NOT NULL default '0',
- `COALESCE(1.0)` double(3,1) NOT NULL default '0.0',
- `COALESCE('a')` char(1) NOT NULL default '',
- `COALESCE(1,1.0)` double(3,1) NOT NULL default '0.0',
- `COALESCE(1,'1')` binary(1) NOT NULL default '',
- `COALESCE(1.1,'1')` binary(3) NOT NULL default '',
- `COALESCE('a' COLLATE latin1_bin,'b')` char(1) character set latin1 collate latin1_bin NOT NULL default ''
+ `COALESCE(1.0)` decimal(5,1) NOT NULL default '0.0',
+ `COALESCE('a')` varchar(1) NOT NULL default '',
+ `COALESCE(1,1.0)` decimal(5,1) NOT NULL default '0.0',
+ `COALESCE(1,'1')` varbinary(1) NOT NULL default '',
+ `COALESCE(1.1,'1')` varbinary(4) NOT NULL default '',
+ `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;
diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result
index 7cd0934f7a3..c5fa5d076cc 100644
--- a/mysql-test/r/cast.result
+++ b/mysql-test/r/cast.result
@@ -4,6 +4,9 @@ CAST(1-2 AS UNSIGNED)
select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER);
CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER)
-1
+select CAST('10 ' as unsigned integer);
+CAST('10 ' as unsigned integer)
+10
select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1;
cast(-5 as unsigned) | 1 cast(-5 as unsigned) & -1
18446744073709551611 18446744073709551611
@@ -39,6 +42,15 @@ cast("1:2:3" as TIME)
select CONVERT("2004-01-22 21:45:33",DATE);
CONVERT("2004-01-22 21:45:33",DATE)
2004-01-22
+select 10+'10';
+10+'10'
+20
+select 10.0+'10';
+10.0+'10'
+20
+select 10E+0+'10';
+10E+0+'10'
+20
select CONVERT(DATE "2004-01-22 21:45:33" USING latin1);
CONVERT(DATE "2004-01-22 21:45:33" USING latin1)
2004-01-22 21:45:33
@@ -48,12 +60,43 @@ CONVERT(DATE "2004-01-22 21:45:33",CHAR)
select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4));
CONVERT(DATE "2004-01-22 21:45:33",CHAR(4))
2004
+Warnings:
+Warning 1292 Truncated incorrect CHAR(4) value: '2004-01-22 21:45:33'
select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4));
CONVERT(DATE "2004-01-22 21:45:33",BINARY(4))
2004
+Warnings:
+Warning 1292 Truncated incorrect CHAR(4) value: '2004-01-22 21:45:33'
select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4));
CAST(DATE "2004-01-22 21:45:33" AS BINARY(4))
2004
+Warnings:
+Warning 1292 Truncated incorrect CHAR(4) value: '2004-01-22 21:45:33'
+select cast('-10a' as signed integer);
+cast('-10a' as signed integer)
+-10
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: '-10a'
+select cast('a10' as unsigned integer);
+cast('a10' as unsigned integer)
+0
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: 'a10'
+select 10+'a';
+10+'a'
+10
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'a'
+select 10.0+cast('a' as decimal);
+10.0+cast('a' as decimal)
+10.00
+Warnings:
+Warning 1292 Truncated incorrect DECIMAL value: 'a'
+select 10E+0+'a';
+10E+0+'a'
+10
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'a'
select cast('18446744073709551616' as unsigned);
cast('18446744073709551616' as unsigned)
18446744073709551615
@@ -100,7 +143,7 @@ create table t1 select cast(_koi8r'ÔÅÓÔ' as char character set cp1251) as t;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `t` char(4) character set cp1251 NOT NULL default ''
+ `t` varchar(4) character set cp1251 NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select
@@ -111,23 +154,34 @@ cast(_latin1'a ' AS char(2)) as c4,
cast(_latin1'a' AS char(2)) as c5;
c1 c2 c3 c4 c5
ab a ab a a
+Warnings:
+Warning 1292 Truncated incorrect CHAR(2) value: 'abc'
+Warning 1292 Truncated incorrect CHAR(2) value: 'a '
+select cast(1000 as CHAR(3));
+cast(1000 as CHAR(3))
+100
+Warnings:
+Warning 1292 Truncated incorrect CHAR(3) value: '1000'
create table t1 select
cast(_latin1'ab' AS char) as c1,
cast(_latin1'a ' AS char) as c2,
cast(_latin1'abc' AS char(2)) as c3,
cast(_latin1'a ' AS char(2)) as c4,
cast(_latin1'a' AS char(2)) as c5;
+Warnings:
+Warning 1292 Truncated incorrect CHAR(2) value: 'abc'
+Warning 1292 Truncated incorrect CHAR(2) value: 'a '
select * from t1;
c1 c2 c3 c4 c5
-ab a ab a a
+ab a ab a a
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `c1` binary(2) NOT NULL default '',
- `c2` binary(2) NOT NULL default '',
- `c3` binary(2) NOT NULL default '',
- `c4` binary(2) NOT NULL default '',
- `c5` binary(2) NOT NULL default ''
+ `c1` varbinary(2) NOT NULL default '',
+ `c2` varbinary(2) NOT NULL default '',
+ `c3` varbinary(2) NOT NULL default '',
+ `c4` varbinary(2) NOT NULL default '',
+ `c5` varbinary(2) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select
@@ -138,23 +192,29 @@ cast(_koi8r'Æ ' AS nchar(2)) as c4,
cast(_koi8r'Æ' AS nchar(2)) as c5;
c1 c2 c3 c4 c5
фг ф фг ф ф
+Warnings:
+Warning 1292 Truncated incorrect CHAR(4) value: 'фгх'
+Warning 1292 Truncated incorrect CHAR(3) value: 'Ñ„ '
create table t1 select
cast(_koi8r'ÆÇ' AS nchar) as c1,
cast(_koi8r'Æ ' AS nchar) as c2,
cast(_koi8r'ÆÇÈ' AS nchar(2)) as c3,
cast(_koi8r'Æ ' AS nchar(2)) as c4,
cast(_koi8r'Æ' AS nchar(2)) as c5;
+Warnings:
+Warning 1292 Truncated incorrect CHAR(4) value: 'фгх'
+Warning 1292 Truncated incorrect CHAR(3) value: 'Ñ„ '
select * from t1;
c1 c2 c3 c4 c5
-фг ф фг ф ф
+фг ф фг ф ф
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `c1` char(2) character set utf8 NOT NULL default '',
- `c2` char(2) character set utf8 NOT NULL default '',
- `c3` char(2) character set utf8 NOT NULL default '',
- `c4` char(2) character set utf8 NOT NULL default '',
- `c5` char(2) character set utf8 NOT NULL default ''
+ `c1` varchar(2) character set utf8 NOT NULL default '',
+ `c2` varchar(2) character set utf8 NOT NULL default '',
+ `c3` varchar(2) character set utf8 NOT NULL default '',
+ `c4` varchar(2) character set utf8 NOT NULL default '',
+ `c5` varchar(2) character set utf8 NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (a binary(10), b char(10) character set koi8r);
@@ -199,6 +259,10 @@ a CAST(a AS CHAR(3))
aac aac
aab aab
aaa aaa
+Warnings:
+Warning 1292 Truncated incorrect CHAR(2) value: 'aaa'
+Warning 1292 Truncated incorrect CHAR(2) value: 'aab'
+Warning 1292 Truncated incorrect CHAR(2) value: 'aac'
SELECT a, CAST(a AS UNSIGNED) FROM t1 ORDER BY CAST(a AS CHAR) ;
a CAST(a AS UNSIGNED)
aaa 3
@@ -209,6 +273,10 @@ a CAST(a AS CHAR(2))
aaa aa
aab aa
aac aa
+Warnings:
+Warning 1292 Truncated incorrect CHAR(2) value: 'aaa'
+Warning 1292 Truncated incorrect CHAR(2) value: 'aab'
+Warning 1292 Truncated incorrect CHAR(2) value: 'aac'
DROP TABLE t1;
select date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour);
date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour)
@@ -252,3 +320,25 @@ cast(repeat('1',20) as signed)
-7335632962598440505
Warnings:
Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement
+select cast('1.2' as decimal(3,2));
+cast('1.2' as decimal(3,2))
+1.20
+select 1e18 * cast('1.2' as decimal(3,2));
+1e18 * cast('1.2' as decimal(3,2))
+1.2e+18
+select cast(cast('1.2' as decimal(3,2)) as signed);
+cast(cast('1.2' as decimal(3,2)) as signed)
+1
+set @v1=1e18;
+select cast(@v1 as decimal(22, 2));
+cast(@v1 as decimal(22, 2))
+1000000000000000000.00
+select cast(-1e18 as decimal(22,2));
+cast(-1e18 as decimal(22,2))
+-1000000000000000000.00
+create table t1(s1 time);
+insert into t1 values ('11:11:11');
+select cast(s1 as decimal(7,2)) from t1;
+cast(s1 as decimal(7,2))
+111111.00
+drop table t1;
diff --git a/mysql-test/r/client_xml.result b/mysql-test/r/client_xml.result
new file mode 100644
index 00000000000..a4164148159
--- /dev/null
+++ b/mysql-test/r/client_xml.result
@@ -0,0 +1,74 @@
+create table t1 (
+`a&b` int,
+`a<b` int,
+`a>b` text
+);
+insert into t1 values (1, 2, 'a&b a<b a>b');
+<?xml version="1.0"?>
+
+<resultset statement="select * from t1
+">
+ <row>
+ <field name="a&amp;b">1</field>
+ <field name="a&lt;b">2</field>
+ <field name="a&gt;b">a&amp;b a&lt;b a&gt;b</field>
+ </row>
+</resultset>
+<?xml version="1.0"?>
+<mysqldump>
+<database name="test">
+ <table_structure name="t1">
+ <field Field="a&amp;b" Type="int(11)" Null="YES" Key="" Extra="" />
+ <field Field="a&lt;b" Type="int(11)" Null="YES" Key="" Extra="" />
+ <field Field="a&gt;b" Type="text" Null="YES" Key="" Extra="" />
+ </table_structure>
+ <table_data name="t1">
+ <row>
+ <field name="a&amp;b">1</field>
+ <field name="a&lt;b">2</field>
+ <field name="a&gt;b">a&amp;b a&lt;b a&gt;b</field>
+ </row>
+ </table_data>
+</database>
+</mysqldump>
+<?xml version="1.0"?>
+
+<resultset statement="select count(*) from t1
+">
+ <row>
+ <field name="count(*)">1</field>
+ </row>
+</resultset>
+<?xml version="1.0"?>
+
+<resultset statement="select 1 &lt; 2 from dual
+">
+ <row>
+ <field name="1 &lt; 2">1</field>
+ </row>
+</resultset>
+<?xml version="1.0"?>
+
+<resultset statement="select 1 &gt; 2 from dual
+">
+ <row>
+ <field name="1 &gt; 2">0</field>
+ </row>
+</resultset>
+<?xml version="1.0"?>
+
+<resultset statement="select 1 &amp; 3 from dual
+">
+ <row>
+ <field name="1 &amp; 3">1</field>
+ </row>
+</resultset>
+<?xml version="1.0"?>
+
+<resultset statement="select null from dual
+">
+ <row>
+ <field name="NULL">NULL</field>
+ </row>
+</resultset>
+drop table t1;
diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result
index edf30e7f6e4..fef813371c8 100644
--- a/mysql-test/r/connect.result
+++ b/mysql-test/r/connect.result
@@ -8,6 +8,8 @@ help_keyword
help_relation
help_topic
host
+proc
+procs_priv
tables_priv
time_zone
time_zone_leap_second
@@ -29,6 +31,8 @@ help_keyword
help_relation
help_topic
host
+proc
+procs_priv
tables_priv
time_zone
time_zone_leap_second
@@ -54,6 +58,8 @@ help_keyword
help_relation
help_topic
host
+proc
+procs_priv
tables_priv
time_zone
time_zone_leap_second
diff --git a/mysql-test/r/count_distinct.result b/mysql-test/r/count_distinct.result
index 16460580d6c..1bc1ad6a31e 100644
--- a/mysql-test/r/count_distinct.result
+++ b/mysql-test/r/count_distinct.result
@@ -53,3 +53,10 @@ select count(distinct f) from t1;
count(distinct f)
0
drop table t1;
+create table t1 (a char(3), b char(20), primary key (a, b));
+insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English');
+select count(distinct a) from t1 group by b;
+count(distinct a)
+1
+1
+drop table t1;
diff --git a/mysql-test/r/count_distinct2.result b/mysql-test/r/count_distinct2.result
index 131e3b325ec..b92665b5c56 100644
--- a/mysql-test/r/count_distinct2.result
+++ b/mysql-test/r/count_distinct2.result
@@ -116,7 +116,7 @@ count(distinct n)
5000
show status like 'Created_tmp_disk_tables';
Variable_name Value
-Created_tmp_disk_tables 1
+Created_tmp_disk_tables 0
drop table t1;
create table t1 (s text);
flush status;
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index 92c825f547d..4f4400b4a9b 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -11,7 +11,7 @@ create table t1 (b char(0) not null);
create table if not exists t1 (b char(0) not null);
insert into t1 values (""),(null);
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'b' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'b' at row 2
select * from t1;
b
@@ -44,12 +44,24 @@ create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
ERROR 42000: Incorrect table name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int);
ERROR 42000: Identifier name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' is too long
-create table test (a datetime default now());
+create table t1 (a datetime default now());
ERROR 42000: Invalid default value for 'a'
-create table test (a datetime on update now());
+create table t1 (a datetime on update now());
ERROR HY000: Invalid ON UPDATE clause for 'a' column
-create table test (a int default 100 auto_increment);
+create table t1 (a int default 100 auto_increment);
ERROR 42000: Invalid default value for 'a'
+create table t1 (a tinyint default 1000);
+ERROR 42000: Invalid default value for 'a'
+create table t1 (a varchar(5) default 'abcdef');
+ERROR 42000: Invalid default value for 'a'
+create table t1 (a varchar(5) default 'abcde');
+insert into t1 values();
+select * from t1;
+a
+abcde
+alter table t1 alter column a set default 'abcdef';
+ERROR 42000: Invalid default value for 'a'
+drop table t1;
create table 1ea10 (1a20 int,1e int);
insert into 1ea10 values(1,1);
select 1ea10.1a20,1e+ 1e+10 from 1ea10;
@@ -100,12 +112,12 @@ drop table t2;
create table t2 select now() as a , curtime() as b, curdate() as c , 1+1 as d , 1.0 + 1 as e , 33333333333333333 + 3 as f;
describe t2;
Field Type Null Key Default Extra
-a datetime 0000-00-00 00:00:00
-b time 00:00:00
-c date 0000-00-00
-d bigint(17) 0
-e double(18,1) 0.0
-f bigint(17) 0
+a datetime NO 0000-00-00 00:00:00
+b time NO 00:00:00
+c date NO 0000-00-00
+d int(2) NO 0
+e decimal(6,1) NO 0.0
+f bigint(18) NO 0
drop table t2;
create table t2 select CAST("2001-12-29" AS DATE) as d, CAST("20:45:11" AS TIME) as t, CAST("2001-12-29 20:45:11" AS DATETIME) as dt;
describe t2;
@@ -152,7 +164,7 @@ create table t1 (a int not null, b int, primary key(a), key (b), key (b), key (b
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` int(11) default NULL,
PRIMARY KEY (`a`),
KEY `b` (`b`),
@@ -198,25 +210,25 @@ drop table if exists t1;
SET SESSION storage_engine="heap";
SELECT @@storage_engine;
@@storage_engine
-HEAP
+MEMORY
CREATE TABLE t1 (a int not null);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0'
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ `a` int(11) NOT NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
drop table t1;
SET SESSION storage_engine="gemini";
ERROR 42000: Unknown table engine 'gemini'
SELECT @@storage_engine;
@@storage_engine
-HEAP
+MEMORY
CREATE TABLE t1 (a int not null);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0'
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ `a` int(11) NOT NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
SET SESSION storage_engine=default;
drop table t1;
create table t1 ( k1 varchar(2), k2 int, primary key(k1,k2));
@@ -255,11 +267,15 @@ drop table t1;
create table t1 (a int not null, b int, primary key (a));
insert into t1 values (1,1);
create table if not exists t1 select 2;
+Warnings:
+Warning 1364 Field 'a' doesn't have a default value
select * from t1;
a b
1 1
0 2
create table if not exists t1 select 3 as 'a',4 as 'b';
+Warnings:
+Warning 1364 Field 'a' doesn't have a default value
create table if not exists t1 select 3 as 'a',3 as 'b';
ERROR 23000: Duplicate entry '3' for key 1
select * from t1;
@@ -291,14 +307,14 @@ create table t3 like t1;
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
- `id` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
`name` char(20) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t3;
id name
create table if not exists t3 like t1;
Warnings:
-Warning 1050 Table 't3' already exists
+Note 1050 Table 't3' already exists
select @@warning_count;
@@warning_count
1
@@ -306,7 +322,7 @@ create temporary table t3 like t2;
show create table t3;
Table Create Table
t3 CREATE TEMPORARY TABLE `t3` (
- `id` int(11) NOT NULL default '0'
+ `id` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t3;
id
@@ -314,7 +330,7 @@ drop table t3;
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
- `id` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
`name` char(20) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t3;
@@ -326,14 +342,14 @@ create temporary table t3 like mysqltest.t3;
show create table t3;
Table Create Table
t3 CREATE TEMPORARY TABLE `t3` (
- `id` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
`name` char(20) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
create table t2 like t3;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
`name` char(20) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t2;
@@ -355,25 +371,25 @@ drop database mysqltest;
SET SESSION storage_engine="heap";
SELECT @@storage_engine;
@@storage_engine
-HEAP
+MEMORY
CREATE TABLE t1 (a int not null);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0'
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ `a` int(11) NOT NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
drop table t1;
SET SESSION storage_engine="gemini";
ERROR 42000: Unknown table engine 'gemini'
SELECT @@storage_engine;
@@storage_engine
-HEAP
+MEMORY
CREATE TABLE t1 (a int not null);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0'
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ `a` int(11) NOT NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
SET SESSION storage_engine=default;
drop table t1;
create table t1(a int,b int,c int unsigned,d date,e char,f datetime,g time,h blob);
@@ -412,13 +428,13 @@ from t1;
explain t2;
Field Type Null Key Default Extra
a int(11) YES NULL
-b bigint(11) 0
-c bigint(10) 0
+b bigint(11) NO 0
+c bigint(10) NO 0
d date YES NULL
-e char(1)
+e varchar(1) NO
f datetime YES NULL
g time YES NULL
-h longblob
+h varbinary(23) NO
dd time YES NULL
select * from t2;
a b c d e f g h dd
@@ -437,14 +453,14 @@ t2 CREATE TABLE `t2` (
`ifnull(e,e)` bigint(20) default NULL,
`ifnull(f,f)` float(3,2) default NULL,
`ifnull(g,g)` double(4,3) default NULL,
- `ifnull(h,h)` decimal(5,4) default NULL,
+ `ifnull(h,h)` decimal(6,4) default NULL,
`ifnull(i,i)` year(4) default NULL,
`ifnull(j,j)` date default NULL,
`ifnull(k,k)` datetime NOT NULL default '0000-00-00 00:00:00',
`ifnull(l,l)` datetime default NULL,
- `ifnull(m,m)` char(1) default NULL,
- `ifnull(n,n)` char(3) default NULL,
- `ifnull(o,o)` char(10) default NULL
+ `ifnull(m,m)` varchar(1) default NULL,
+ `ifnull(n,n)` varchar(3) default NULL,
+ `ifnull(o,o)` varchar(10) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1,t2;
create table t1(str varchar(10) default 'def',strnull varchar(10),intg int default '10',rel double default '3.14');
diff --git a/mysql-test/r/ctype_collate.result b/mysql-test/r/ctype_collate.result
index cdf890f2c6c..66266d40fb3 100644
--- a/mysql-test/r/ctype_collate.result
+++ b/mysql-test/r/ctype_collate.result
@@ -484,11 +484,11 @@ ERROR HY000: Unknown collation: 'koi8r'
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `latin1_f` char(32) NOT NULL default ''
+ `latin1_f` char(32) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SHOW FIELDS FROM t1;
Field Type Null Key Default Extra
-latin1_f char(32)
+latin1_f char(32) NO
ALTER TABLE t1 CHANGE latin1_f
latin1_f CHAR(32) CHARACTER SET latin1 COLLATE latin1_bin;
SHOW CREATE TABLE t1;
diff --git a/mysql-test/r/ctype_cp932.result b/mysql-test/r/ctype_cp932.result
new file mode 100755
index 00000000000..2661ff5e3c9
--- /dev/null
+++ b/mysql-test/r/ctype_cp932.result
@@ -0,0 +1,11337 @@
+drop table if exists t1;
+drop table if exists t2;
+drop table if exists t3;
+drop table if exists t4;
+set names cp932;
+set character_set_database = cp932;
+CREATE TABLE t1(c1 CHAR(1)) DEFAULT CHARACTER SET = cp932;
+INSERT INTO t1 VALUES
+(0x05),(0x7E),(0x815C),(0x815F),(0x8160),(0x8161),(0x817C),(0x8191),(0x8192),(0x81CA);
+INSERT INTO t1 VALUES
+(0x8740),(0x8741),(0x8742),(0x8743),(0x8744),(0x8745),(0x8746),(0x8747),
+(0x8748),(0x8749),(0x874A),(0x874B),(0x874C),(0x874D),(0x874E),(0x874F),
+(0x8750),(0x8751),(0x8752),(0x8753),(0x8754),(0x8755),(0x8756),(0x8757),
+(0x8758),(0x8759),(0x875A),(0x875B),(0x875C),(0x875D),(0x875F),
+(0x8760),(0x8761),(0x8762),(0x8763),(0x8764),(0x8765),(0x8766),(0x8767),
+(0x8768),(0x8769),(0x876A),(0x876B),(0x876C),(0x876D),(0x876E),(0x876F),
+(0x8770),(0x8771),(0x8772),(0x8773),(0x8774),(0x8775),(0x877E),
+(0x8780),(0x8781),(0x8782),(0x8783),(0x8784),(0x8785),(0x8786),(0x8787),
+(0x8788),(0x8789),(0x878A),(0x878B),(0x878C),(0x878D),(0x878E),(0x878F),
+(0x8790),(0x8791),(0x8792),(0x8793),(0x8794),(0x8795),(0x8796),(0x8797),
+(0x8798),(0x8799),(0x879A),(0x879B),(0x879C);
+INSERT INTO t1 VALUES
+(0xED40),(0xED41),(0xED42),(0xED43),(0xED44),(0xED45),(0xED46),(0xED47),
+(0xED48),(0xED49),(0xED4A),(0xED4B),(0xED4C),(0xED4D),(0xED4E),(0xED4F),
+(0xED50),(0xED51),(0xED52),(0xED53),(0xED54),(0xED55),(0xED56),(0xED57),
+(0xED58),(0xED59),(0xED5A),(0xED5B),(0xED5C),(0xED5D),(0xED5E),(0xED5F),
+(0xED60),(0xED61),(0xED62),(0xED63),(0xED64),(0xED65),(0xED66),(0xED67),
+(0xED68),(0xED69),(0xED6A),(0xED6B),(0xED6C),(0xED6D),(0xED6E),(0xED6F),
+(0xED70),(0xED71),(0xED72),(0xED73),(0xED74),(0xED75),(0xED76),(0xED77),
+(0xED78),(0xED79),(0xED7A),(0xED7B),(0xED7C),(0xED7D),(0xED7E),
+(0xED80),(0xED81),(0xED82),(0xED83),(0xED84),(0xED85),(0xED86),(0xED87),
+(0xED88),(0xED89),(0xED8A),(0xED8B),(0xED8C),(0xED8D),(0xED8E),(0xED8F),
+(0xED90),(0xED91),(0xED92),(0xED93),(0xED94),(0xED95),(0xED96),(0xED97),
+(0xED98),(0xED99),(0xED9A),(0xED9B),(0xED9C),(0xED9D),(0xED9E),(0xED9F),
+(0xEDA0),(0xEDA1),(0xEDA2),(0xEDA3),(0xEDA4),(0xEDA5),(0xEDA6),(0xEDA7),
+(0xEDA8),(0xEDA9),(0xEDAA),(0xEDAB),(0xEDAC),(0xEDAD),(0xEDAE),(0xEDAF),
+(0xEDB0),(0xEDB1),(0xEDB2),(0xEDB3),(0xEDB4),(0xEDB5),(0xEDB6),(0xEDB7),
+(0xEDB8),(0xEDB9),(0xEDBA),(0xEDBB),(0xEDBC),(0xEDBD),(0xEDBE),(0xEDBF),
+(0xEDC0),(0xEDC1),(0xEDC2),(0xEDC3),(0xEDC4),(0xEDC5),(0xEDC6),(0xEDC7),
+(0xEDC8),(0xEDC9),(0xEDCA),(0xEDCB),(0xEDCC),(0xEDCD),(0xEDCE),(0xEDCF),
+(0xEDD0),(0xEDD1),(0xEDD2),(0xEDD3),(0xEDD4),(0xEDD5),(0xEDD6),(0xEDD7),
+(0xEDD8),(0xEDD9),(0xEDDA),(0xEDDB),(0xEDDC),(0xEDDD),(0xEDDE),(0xEDDF),
+(0xEDE0),(0xEDE1),(0xEDE2),(0xEDE3),(0xEDE4),(0xEDE5),(0xEDE6),(0xEDE7),
+(0xEDE8),(0xEDE9),(0xEDEA),(0xEDEB),(0xEDEC),(0xEDED),(0xEDEE),(0xEDEF),
+(0xEDF0),(0xEDF1),(0xEDF2),(0xEDF3),(0xEDF4),(0xEDF5),(0xEDF6),(0xEDF7),
+(0xEDF8),(0xEDF9),(0xEDFA),(0xEDFB),(0xEDFC),
+(0xEE40),(0xEE41),(0xEE42),(0xEE43),(0xEE44),(0xEE45),(0xEE46),(0xEE47),
+(0xEE48),(0xEE49),(0xEE4A),(0xEE4B),(0xEE4C),(0xEE4D),(0xEE4E),(0xEE4F),
+(0xEE50),(0xEE51),(0xEE52),(0xEE53),(0xEE54),(0xEE55),(0xEE56),(0xEE57),
+(0xEE58),(0xEE59),(0xEE5A),(0xEE5B),(0xEE5C),(0xEE5D),(0xEE5E),(0xEE5F),
+(0xEE60),(0xEE61),(0xEE62),(0xEE63),(0xEE64),(0xEE65),(0xEE66),(0xEE67),
+(0xEE68),(0xEE69),(0xEE6A),(0xEE6B),(0xEE6C),(0xEE6D),(0xEE6E),(0xEE6F),
+(0xEE70),(0xEE71),(0xEE72),(0xEE73),(0xEE74),(0xEE75),(0xEE76),(0xEE77),
+(0xEE78),(0xEE79),(0xEE7A),(0xEE7B),(0xEE7C),(0xEE7D),(0xEE7E),
+(0xEE80),(0xEE81),(0xEE82),(0xEE83),(0xEE84),(0xEE85),(0xEE86),(0xEE87),
+(0xEE88),(0xEE89),(0xEE8A),(0xEE8B),(0xEE8C),(0xEE8D),(0xEE8E),(0xEE8F),
+(0xEE90),(0xEE91),(0xEE92),(0xEE93),(0xEE94),(0xEE95),(0xEE96),(0xEE97),
+(0xEE98),(0xEE99),(0xEE9A),(0xEE9B),(0xEE9C),(0xEE9D),(0xEE9E),(0xEE9F),
+(0xEEA0),(0xEEA1),(0xEEA2),(0xEEA3),(0xEEA4),(0xEEA5),(0xEEA6),(0xEEA7),
+(0xEEA8),(0xEEA9),(0xEEAA),(0xEEAB),(0xEEAC),(0xEEAD),(0xEEAE),(0xEEAF),
+(0xEEB0),(0xEEB1),(0xEEB2),(0xEEB3),(0xEEB4),(0xEEB5),(0xEEB6),(0xEEB7),
+(0xEEB8),(0xEEB9),(0xEEBA),(0xEEBB),(0xEEBC),(0xEEBD),(0xEEBE),(0xEEBF),
+(0xEEC0),(0xEEC1),(0xEEC2),(0xEEC3),(0xEEC4),(0xEEC5),(0xEEC6),(0xEEC7),
+(0xEEC8),(0xEEC9),(0xEECA),(0xEECB),(0xEECC),(0xEECD),(0xEECE),(0xEECF),
+(0xEED0),(0xEED1),(0xEED2),(0xEED3),(0xEED4),(0xEED5),(0xEED6),(0xEED7),
+(0xEED8),(0xEED9),(0xEEDA),(0xEEDB),(0xEEDC),(0xEEDD),(0xEEDE),(0xEEDF),
+(0xEEE0),(0xEEE1),(0xEEE2),(0xEEE3),(0xEEE4),(0xEEE5),(0xEEE6),(0xEEE7),
+(0xEEE8),(0xEEE9),(0xEEEA),(0xEEEB),(0xEEEC),(0xEEEF),
+(0xEEF0),(0xEEF1),(0xEEF2),(0xEEF3),(0xEEF4),(0xEEF5),(0xEEF6),(0xEEF7),
+(0xEEF8),(0xEEF9),(0xEEFA),(0xEEFB),(0xEEFC);
+INSERT INTO t1 VALUES
+(0xFA40),(0xFA41),(0xFA42),(0xFA43),(0xFA44),(0xFA45),(0xFA46),(0xFA47),
+(0xFA48),(0xFA49),(0xFA4A),(0xFA4B),(0xFA4C),(0xFA4D),(0xFA4E),(0xFA4F),
+(0xFA50),(0xFA51),(0xFA52),(0xFA53),(0xFA54),(0xFA55),(0xFA56),(0xFA57),
+(0xFA58),(0xFA59),(0xFA5A),(0xFA5B),(0xFA5C),(0xFA5D),(0xFA5E),(0xFA5F),
+(0xFA60),(0xFA61),(0xFA62),(0xFA63),(0xFA64),(0xFA65),(0xFA66),(0xFA67),
+(0xFA68),(0xFA69),(0xFA6A),(0xFA6B),(0xFA6C),(0xFA6D),(0xFA6E),(0xFA6F),
+(0xFA70),(0xFA71),(0xFA72),(0xFA73),(0xFA74),(0xFA75),(0xFA76),(0xFA77),
+(0xFA78),(0xFA79),(0xFA7A),(0xFA7B),(0xFA7C),(0xFA7D),(0xFA7E),
+(0xFA80),(0xFA81),(0xFA82),(0xFA83),(0xFA84),(0xFA85),(0xFA86),(0xFA87),
+(0xFA88),(0xFA89),(0xFA8A),(0xFA8B),(0xFA8C),(0xFA8D),(0xFA8E),(0xFA8F),
+(0xFA90),(0xFA91),(0xFA92),(0xFA93),(0xFA94),(0xFA95),(0xFA96),(0xFA97),
+(0xFA98),(0xFA99),(0xFA9A),(0xFA9B),(0xFA9C),(0xFA9D),(0xFA9E),(0xFA9F),
+(0xFAA0),(0xFAA1),(0xFAA2),(0xFAA3),(0xFAA4),(0xFAA5),(0xFAA6),(0xFAA7),
+(0xFAA8),(0xFAA9),(0xFAAA),(0xFAAB),(0xFAAC),(0xFAAD),(0xFAAE),(0xFAAF),
+(0xFAB0),(0xFAB1),(0xFAB2),(0xFAB3),(0xFAB4),(0xFAB5),(0xFAB6),(0xFAB7),
+(0xFAB8),(0xFAB9),(0xFABA),(0xFABB),(0xFABC),(0xFABD),(0xFABE),(0xFABF),
+(0xFAC0),(0xFAC1),(0xFAC2),(0xFAC3),(0xFAC4),(0xFAC5),(0xFAC6),(0xFAC7),
+(0xFAC8),(0xFAC9),(0xFACA),(0xFACB),(0xFACC),(0xFACD),(0xFACE),(0xFACF),
+(0xFAD0),(0xFAD1),(0xFAD2),(0xFAD3),(0xFAD4),(0xFAD5),(0xFAD6),(0xFAD7),
+(0xFAD8),(0xFAD9),(0xFADA),(0xFADB),(0xFADC),(0xFADD),(0xFADE),(0xFADF),
+(0xFAE0),(0xFAE1),(0xFAE2),(0xFAE3),(0xFAE4),(0xFAE5),(0xFAE6),(0xFAE7),
+(0xFAE8),(0xFAE9),(0xFAEA),(0xFAEB),(0xFAEC),(0xFAED),(0xFAEE),(0xFAEF),
+(0xFAF0),(0xFAF1),(0xFAF2),(0xFAF3),(0xFAF4),(0xFAF5),(0xFAF6),(0xFAF7),
+(0xFAF8),(0xFAF9),(0xFAFA),(0xFAFB),(0xFAFC),
+(0xFB40),(0xFB41),(0xFB42),(0xFB43),(0xFB44),(0xFB45),(0xFB46),(0xFB47),
+(0xFB48),(0xFB49),(0xFB4A),(0xFB4B),(0xFB4C),(0xFB4D),(0xFB4E),(0xFB4F),
+(0xFB50),(0xFB51),(0xFB52),(0xFB53),(0xFB54),(0xFB55),(0xFB56),(0xFB57),
+(0xFB58),(0xFB59),(0xFB5A),(0xFB5B),(0xFB5C),(0xFB5D),(0xFB5E),(0xFB5F),
+(0xFB60),(0xFB61),(0xFB62),(0xFB63),(0xFB64),(0xFB65),(0xFB66),(0xFB67),
+(0xFB68),(0xFB69),(0xFB6A),(0xFB6B),(0xFB6C),(0xFB6D),(0xFB6E),(0xFB6F),
+(0xFB70),(0xFB71),(0xFB72),(0xFB73),(0xFB74),(0xFB75),(0xFB76),(0xFB77),
+(0xFB78),(0xFB79),(0xFB7A),(0xFB7B),(0xFB7C),(0xFB7D),(0xFB7E),
+(0xFB80),(0xFB81),(0xFB82),(0xFB83),(0xFB84),(0xFB85),(0xFB86),(0xFB87),
+(0xFB88),(0xFB89),(0xFB8A),(0xFB8B),(0xFB8C),(0xFB8D),(0xFB8E),(0xFB8F),
+(0xFB90),(0xFB91),(0xFB92),(0xFB93),(0xFB94),(0xFB95),(0xFB96),(0xFB97),
+(0xFB98),(0xFB99),(0xFB9A),(0xFB9B),(0xFB9C),(0xFB9D),(0xFB9E),(0xFB9F),
+(0xFBA0),(0xFBA1),(0xFBA2),(0xFBA3),(0xFBA4),(0xFBA5),(0xFBA6),(0xFBA7),
+(0xFBA8),(0xFBA9),(0xFBAA),(0xFBAB),(0xFBAC),(0xFBAD),(0xFBAE),(0xFBAF),
+(0xFBB0),(0xFBB1),(0xFBB2),(0xFBB3),(0xFBB4),(0xFBB5),(0xFBB6),(0xFBB7),
+(0xFBB8),(0xFBB9),(0xFBBA),(0xFBBB),(0xFBBC),(0xFBBD),(0xFBBE),(0xFBBF),
+(0xFBC0),(0xFBC1),(0xFBC2),(0xFBC3),(0xFBC4),(0xFBC5),(0xFBC6),(0xFBC7),
+(0xFBC8),(0xFBC9),(0xFBCA),(0xFBCB),(0xFBCC),(0xFBCD),(0xFBCE),(0xFBCF),
+(0xFBD0),(0xFBD1),(0xFBD2),(0xFBD3),(0xFBD4),(0xFBD5),(0xFBD6),(0xFBD7),
+(0xFBD8),(0xFBD9),(0xFBDA),(0xFBDB),(0xFBDC),(0xFBDD),(0xFBDE),(0xFBDF),
+(0xFBE0),(0xFBE1),(0xFBE2),(0xFBE3),(0xFBE4),(0xFBE5),(0xFBE6),(0xFBE7),
+(0xFBE8),(0xFBE9),(0xFBEA),(0xFBEB),(0xFBEC),(0xFBED),(0xFBEE),(0xFBEF),
+(0xFBF0),(0xFBF1),(0xFBF2),(0xFBF3),(0xFBF4),(0xFBF5),(0xFBF6),(0xFBF7),
+(0xFBF8),(0xFBF9),(0xFBFA),(0xFBFB),(0xFBFC),
+(0xFC40),(0xFC41),(0xFC42),(0xFC43),(0xFC44),(0xFC45),(0xFC46),(0xFC47),
+(0xFC48),(0xFC49),(0xFC4A),(0xFC4B);
+INSERT INTO t1 VALUES
+(0xF040),(0xF041),(0xF042),(0xF043),(0xF044),(0xF045),(0xF046),(0xF047),
+(0xF048),(0xF049),(0xF04A),(0xF04B),(0xF04C),(0xF04D),(0xF04E),(0xF04F),
+(0xF050),(0xF051),(0xF052),(0xF053),(0xF054),(0xF055),(0xF056),(0xF057),
+(0xF058),(0xF059),(0xF05A),(0xF05B),(0xF05C),(0xF05D),(0xF05E),(0xF05F),
+(0xF060),(0xF061),(0xF062),(0xF063),(0xF064),(0xF065),(0xF066),(0xF067),
+(0xF068),(0xF069),(0xF06A),(0xF06B),(0xF06C),(0xF06D),(0xF06E),(0xF06F),
+(0xF070),(0xF071),(0xF072),(0xF073),(0xF074),(0xF075),(0xF076),(0xF077),
+(0xF078),(0xF079),(0xF07A),(0xF07B),(0xF07C),(0xF07D),(0xF07E),
+(0xF080),(0xF081),(0xF082),(0xF083),(0xF084),(0xF085),(0xF086),(0xF087),
+(0xF088),(0xF089),(0xF08A),(0xF08B),(0xF08C),(0xF08D),(0xF08E),(0xF08F),
+(0xF090),(0xF091),(0xF092),(0xF093),(0xF094),(0xF095),(0xF096),(0xF097),
+(0xF098),(0xF099),(0xF09A),(0xF09B),(0xF09C),(0xF09D),(0xF09E),(0xF09F),
+(0xF0A0),(0xF0A1),(0xF0A2),(0xF0A3),(0xF0A4),(0xF0A5),(0xF0A6),(0xF0A7),
+(0xF0A8),(0xF0A9),(0xF0AA),(0xF0AB),(0xF0AC),(0xF0AD),(0xF0AE),(0xF0AF),
+(0xF0B0),(0xF0B1),(0xF0B2),(0xF0B3),(0xF0B4),(0xF0B5),(0xF0B6),(0xF0B7),
+(0xF0B8),(0xF0B9),(0xF0BA),(0xF0BB),(0xF0BC),(0xF0BD),(0xF0BE),(0xF0BF),
+(0xF0C0),(0xF0C1),(0xF0C2),(0xF0C3),(0xF0C4),(0xF0C5),(0xF0C6),(0xF0C7),
+(0xF0C8),(0xF0C9),(0xF0CA),(0xF0CB),(0xF0CC),(0xF0CD),(0xF0CE),(0xF0CF),
+(0xF0D0),(0xF0D1),(0xF0D2),(0xF0D3),(0xF0D4),(0xF0D5),(0xF0D6),(0xF0D7),
+(0xF0D8),(0xF0D9),(0xF0DA),(0xF0DB),(0xF0DC),(0xF0DD),(0xF0DE),(0xF0DF),
+(0xF0E0),(0xF0E1),(0xF0E2),(0xF0E3),(0xF0E4),(0xF0E5),(0xF0E6),(0xF0E7),
+(0xF0E8),(0xF0E9),(0xF0EA),(0xF0EB),(0xF0EC),(0xF0ED),(0xF0EE),(0xF0EF),
+(0xF0F0),(0xF0F1),(0xF0F2),(0xF0F3),(0xF0F4),(0xF0F5),(0xF0F6),(0xF0F7),
+(0xF0F8),(0xF0F9),(0xF0FA),(0xF0FB),(0xF0FC),
+(0xF140),(0xF141),(0xF142),(0xF143),(0xF144),(0xF145),(0xF146),(0xF147),
+(0xF148),(0xF149),(0xF14A),(0xF14B),(0xF14C),(0xF14D),(0xF14E),(0xF14F),
+(0xF150),(0xF151),(0xF152),(0xF153),(0xF154),(0xF155),(0xF156),(0xF157),
+(0xF158),(0xF159),(0xF15A),(0xF15B),(0xF15C),(0xF15D),(0xF15E),(0xF15F),
+(0xF160),(0xF161),(0xF162),(0xF163),(0xF164),(0xF165),(0xF166),(0xF167),
+(0xF168),(0xF169),(0xF16A),(0xF16B),(0xF16C),(0xF16D),(0xF16E),(0xF16F),
+(0xF170),(0xF171),(0xF172),(0xF173),(0xF174),(0xF175),(0xF176),(0xF177),
+(0xF178),(0xF179),(0xF17A),(0xF17B),(0xF17C),(0xF17D),(0xF17E),
+(0xF180),(0xF181),(0xF182),(0xF183),(0xF184),(0xF185),(0xF186),(0xF187),
+(0xF188),(0xF189),(0xF18A),(0xF18B),(0xF18C),(0xF18D),(0xF18E),(0xF18F),
+(0xF190),(0xF191),(0xF192),(0xF193),(0xF194),(0xF195),(0xF196),(0xF197),
+(0xF198),(0xF199),(0xF19A),(0xF19B),(0xF19C),(0xF19D),(0xF19E),(0xF19F),
+(0xF1A0),(0xF1A1),(0xF1A2),(0xF1A3),(0xF1A4),(0xF1A5),(0xF1A6),(0xF1A7),
+(0xF1A8),(0xF1A9),(0xF1AA),(0xF1AB),(0xF1AC),(0xF1AD),(0xF1AE),(0xF1AF),
+(0xF1B0),(0xF1B1),(0xF1B2),(0xF1B3),(0xF1B4),(0xF1B5),(0xF1B6),(0xF1B7),
+(0xF1B8),(0xF1B9),(0xF1BA),(0xF1BB),(0xF1BC),(0xF1BD),(0xF1BE),(0xF1BF),
+(0xF1C0),(0xF1C1),(0xF1C2),(0xF1C3),(0xF1C4),(0xF1C5),(0xF1C6),(0xF1C7),
+(0xF1C8),(0xF1C9),(0xF1CA),(0xF1CB),(0xF1CC),(0xF1CD),(0xF1CE),(0xF1CF),
+(0xF1D0),(0xF1D1),(0xF1D2),(0xF1D3),(0xF1D4),(0xF1D5),(0xF1D6),(0xF1D7),
+(0xF1D8),(0xF1D9),(0xF1DA),(0xF1DB),(0xF1DC),(0xF1DD),(0xF1DE),(0xF1DF),
+(0xF1E0),(0xF1E1),(0xF1E2),(0xF1E3),(0xF1E4),(0xF1E5),(0xF1E6),(0xF1E7),
+(0xF1E8),(0xF1E9),(0xF1EA),(0xF1EB),(0xF1EC),(0xF1ED),(0xF1EE),(0xF1EF),
+(0xF1F0),(0xF1F1),(0xF1F2),(0xF1F3),(0xF1F4),(0xF1F5),(0xF1F6),(0xF1F7),
+(0xF1F8),(0xF1F9),(0xF1FA),(0xF1FB),(0xF1FC),
+(0xF240),(0xF241),(0xF242),(0xF243),(0xF244),(0xF245),(0xF246),(0xF247),
+(0xF248),(0xF249),(0xF24A),(0xF24B),(0xF24C),(0xF24D),(0xF24E),(0xF24F),
+(0xF250),(0xF251),(0xF252),(0xF253),(0xF254),(0xF255),(0xF256),(0xF257),
+(0xF258),(0xF259),(0xF25A),(0xF25B),(0xF25C),(0xF25D),(0xF25E),(0xF25F),
+(0xF260),(0xF261),(0xF262),(0xF263),(0xF264),(0xF265),(0xF266),(0xF267),
+(0xF268),(0xF269),(0xF26A),(0xF26B),(0xF26C),(0xF26D),(0xF26E),(0xF26F),
+(0xF270),(0xF271),(0xF272),(0xF273),(0xF274),(0xF275),(0xF276),(0xF277),
+(0xF278),(0xF279),(0xF27A),(0xF27B),(0xF27C),(0xF27D),(0xF27E),
+(0xF280),(0xF281),(0xF282),(0xF283),(0xF284),(0xF285),(0xF286),(0xF287),
+(0xF288),(0xF289),(0xF28A),(0xF28B),(0xF28C),(0xF28D),(0xF28E),(0xF28F),
+(0xF290),(0xF291),(0xF292),(0xF293),(0xF294),(0xF295),(0xF296),(0xF297),
+(0xF298),(0xF299),(0xF29A),(0xF29B),(0xF29C),(0xF29D),(0xF29E),(0xF29F),
+(0xF2A0),(0xF2A1),(0xF2A2),(0xF2A3),(0xF2A4),(0xF2A5),(0xF2A6),(0xF2A7),
+(0xF2A8),(0xF2A9),(0xF2AA),(0xF2AB),(0xF2AC),(0xF2AD),(0xF2AE),(0xF2AF),
+(0xF2B0),(0xF2B1),(0xF2B2),(0xF2B3),(0xF2B4),(0xF2B5),(0xF2B6),(0xF2B7),
+(0xF2B8),(0xF2B9),(0xF2BA),(0xF2BB),(0xF2BC),(0xF2BD),(0xF2BE),(0xF2BF),
+(0xF2C0),(0xF2C1),(0xF2C2),(0xF2C3),(0xF2C4),(0xF2C5),(0xF2C6),(0xF2C7),
+(0xF2C8),(0xF2C9),(0xF2CA),(0xF2CB),(0xF2CC),(0xF2CD),(0xF2CE),(0xF2CF),
+(0xF2D0),(0xF2D1),(0xF2D2),(0xF2D3),(0xF2D4),(0xF2D5),(0xF2D6),(0xF2D7),
+(0xF2D8),(0xF2D9),(0xF2DA),(0xF2DB),(0xF2DC),(0xF2DD),(0xF2DE),(0xF2DF),
+(0xF2E0),(0xF2E1),(0xF2E2),(0xF2E3),(0xF2E4),(0xF2E5),(0xF2E6),(0xF2E7),
+(0xF2E8),(0xF2E9),(0xF2EA),(0xF2EB),(0xF2EC),(0xF2ED),(0xF2EE),(0xF2EF),
+(0xF2F0),(0xF2F1),(0xF2F2),(0xF2F3),(0xF2F4),(0xF2F5),(0xF2F6),(0xF2F7),
+(0xF2F8),(0xF2F9),(0xF2FA),(0xF2FB),(0xF2FC),
+(0xF340),(0xF341),(0xF342),(0xF343),(0xF344),(0xF345),(0xF346),(0xF347),
+(0xF348),(0xF349),(0xF34A),(0xF34B),(0xF34C),(0xF34D),(0xF34E),(0xF34F),
+(0xF350),(0xF351),(0xF352),(0xF353),(0xF354),(0xF355),(0xF356),(0xF357),
+(0xF358),(0xF359),(0xF35A),(0xF35B),(0xF35C),(0xF35D),(0xF35E),(0xF35F),
+(0xF360),(0xF361),(0xF362),(0xF363),(0xF364),(0xF365),(0xF366),(0xF367),
+(0xF368),(0xF369),(0xF36A),(0xF36B),(0xF36C),(0xF36D),(0xF36E),(0xF36F),
+(0xF370),(0xF371),(0xF372),(0xF373),(0xF374),(0xF375),(0xF376),(0xF377),
+(0xF378),(0xF379),(0xF37A),(0xF37B),(0xF37C),(0xF37D),(0xF37E),
+(0xF380),(0xF381),(0xF382),(0xF383),(0xF384),(0xF385),(0xF386),(0xF387),
+(0xF388),(0xF389),(0xF38A),(0xF38B),(0xF38C),(0xF38D),(0xF38E),(0xF38F),
+(0xF390),(0xF391),(0xF392),(0xF393),(0xF394),(0xF395),(0xF396),(0xF397),
+(0xF398),(0xF399),(0xF39A),(0xF39B),(0xF39C),(0xF39D),(0xF39E),(0xF39F),
+(0xF3A0),(0xF3A1),(0xF3A2),(0xF3A3),(0xF3A4),(0xF3A5),(0xF3A6),(0xF3A7),
+(0xF3A8),(0xF3A9),(0xF3AA),(0xF3AB),(0xF3AC),(0xF3AD),(0xF3AE),(0xF3AF),
+(0xF3B0),(0xF3B1),(0xF3B2),(0xF3B3),(0xF3B4),(0xF3B5),(0xF3B6),(0xF3B7),
+(0xF3B8),(0xF3B9),(0xF3BA),(0xF3BB),(0xF3BC),(0xF3BD),(0xF3BE),(0xF3BF),
+(0xF3C0),(0xF3C1),(0xF3C2),(0xF3C3),(0xF3C4),(0xF3C5),(0xF3C6),(0xF3C7),
+(0xF3C8),(0xF3C9),(0xF3CA),(0xF3CB),(0xF3CC),(0xF3CD),(0xF3CE),(0xF3CF),
+(0xF3D0),(0xF3D1),(0xF3D2),(0xF3D3),(0xF3D4),(0xF3D5),(0xF3D6),(0xF3D7),
+(0xF3D8),(0xF3D9),(0xF3DA),(0xF3DB),(0xF3DC),(0xF3DD),(0xF3DE),(0xF3DF),
+(0xF3E0),(0xF3E1),(0xF3E2),(0xF3E3),(0xF3E4),(0xF3E5),(0xF3E6),(0xF3E7),
+(0xF3E8),(0xF3E9),(0xF3EA),(0xF3EB),(0xF3EC),(0xF3ED),(0xF3EE),(0xF3EF),
+(0xF3F0),(0xF3F1),(0xF3F2),(0xF3F3),(0xF3F4),(0xF3F5),(0xF3F6),(0xF3F7),
+(0xF3F8),(0xF3F9),(0xF3FA),(0xF3FB),(0xF3FC),
+(0xF440),(0xF441),(0xF442),(0xF443),(0xF444),(0xF445),(0xF446),(0xF447),
+(0xF448),(0xF449),(0xF44A),(0xF44B),(0xF44C),(0xF44D),(0xF44E),(0xF44F),
+(0xF450),(0xF451),(0xF452),(0xF453),(0xF454),(0xF455),(0xF456),(0xF457),
+(0xF458),(0xF459),(0xF45A),(0xF45B),(0xF45C),(0xF45D),(0xF45E),(0xF45F),
+(0xF460),(0xF461),(0xF462),(0xF463),(0xF464),(0xF465),(0xF466),(0xF467),
+(0xF468),(0xF469),(0xF46A),(0xF46B),(0xF46C),(0xF46D),(0xF46E),(0xF46F),
+(0xF470),(0xF471),(0xF472),(0xF473),(0xF474),(0xF475),(0xF476),(0xF477),
+(0xF478),(0xF479),(0xF47A),(0xF47B),(0xF47C),(0xF47D),(0xF47E),
+(0xF480),(0xF481),(0xF482),(0xF483),(0xF484),(0xF485),(0xF486),(0xF487),
+(0xF488),(0xF489),(0xF48A),(0xF48B),(0xF48C),(0xF48D),(0xF48E),(0xF48F),
+(0xF490),(0xF491),(0xF492),(0xF493),(0xF494),(0xF495),(0xF496),(0xF497),
+(0xF498),(0xF499),(0xF49A),(0xF49B),(0xF49C),(0xF49D),(0xF49E),(0xF49F),
+(0xF4A0),(0xF4A1),(0xF4A2),(0xF4A3),(0xF4A4),(0xF4A5),(0xF4A6),(0xF4A7),
+(0xF4A8),(0xF4A9),(0xF4AA),(0xF4AB),(0xF4AC),(0xF4AD),(0xF4AE),(0xF4AF),
+(0xF4B0),(0xF4B1),(0xF4B2),(0xF4B3),(0xF4B4),(0xF4B5),(0xF4B6),(0xF4B7),
+(0xF4B8),(0xF4B9),(0xF4BA),(0xF4BB),(0xF4BC),(0xF4BD),(0xF4BE),(0xF4BF),
+(0xF4C0),(0xF4C1),(0xF4C2),(0xF4C3),(0xF4C4),(0xF4C5),(0xF4C6),(0xF4C7),
+(0xF4C8),(0xF4C9),(0xF4CA),(0xF4CB),(0xF4CC),(0xF4CD),(0xF4CE),(0xF4CF),
+(0xF4D0),(0xF4D1),(0xF4D2),(0xF4D3),(0xF4D4),(0xF4D5),(0xF4D6),(0xF4D7),
+(0xF4D8),(0xF4D9),(0xF4DA),(0xF4DB),(0xF4DC),(0xF4DD),(0xF4DE),(0xF4DF),
+(0xF4E0),(0xF4E1),(0xF4E2),(0xF4E3),(0xF4E4),(0xF4E5),(0xF4E6),(0xF4E7),
+(0xF4E8),(0xF4E9),(0xF4EA),(0xF4EB),(0xF4EC),(0xF4ED),(0xF4EE),(0xF4EF),
+(0xF4F0),(0xF4F1),(0xF4F2),(0xF4F3),(0xF4F4),(0xF4F5),(0xF4F6),(0xF4F7),
+(0xF4F8),(0xF4F9),(0xF4FA),(0xF4FB),(0xF4FC),
+(0xF540),(0xF541),(0xF542),(0xF543),(0xF544),(0xF545),(0xF546),(0xF547),
+(0xF548),(0xF549),(0xF54A),(0xF54B),(0xF54C),(0xF54D),(0xF54E),(0xF54F),
+(0xF550),(0xF551),(0xF552),(0xF553),(0xF554),(0xF555),(0xF556),(0xF557),
+(0xF558),(0xF559),(0xF55A),(0xF55B),(0xF55C),(0xF55D),(0xF55E),(0xF55F),
+(0xF560),(0xF561),(0xF562),(0xF563),(0xF564),(0xF565),(0xF566),(0xF567),
+(0xF568),(0xF569),(0xF56A),(0xF56B),(0xF56C),(0xF56D),(0xF56E),(0xF56F),
+(0xF570),(0xF571),(0xF572),(0xF573),(0xF574),(0xF575),(0xF576),(0xF577),
+(0xF578),(0xF579),(0xF57A),(0xF57B),(0xF57C),(0xF57D),(0xF57E),
+(0xF580),(0xF581),(0xF582),(0xF583),(0xF584),(0xF585),(0xF586),(0xF587),
+(0xF588),(0xF589),(0xF58A),(0xF58B),(0xF58C),(0xF58D),(0xF58E),(0xF58F),
+(0xF590),(0xF591),(0xF592),(0xF593),(0xF594),(0xF595),(0xF596),(0xF597),
+(0xF598),(0xF599),(0xF59A),(0xF59B),(0xF59C),(0xF59D),(0xF59E),(0xF59F),
+(0xF5A0),(0xF5A1),(0xF5A2),(0xF5A3),(0xF5A4),(0xF5A5),(0xF5A6),(0xF5A7),
+(0xF5A8),(0xF5A9),(0xF5AA),(0xF5AB),(0xF5AC),(0xF5AD),(0xF5AE),(0xF5AF),
+(0xF5B0),(0xF5B1),(0xF5B2),(0xF5B3),(0xF5B4),(0xF5B5),(0xF5B6),(0xF5B7),
+(0xF5B8),(0xF5B9),(0xF5BA),(0xF5BB),(0xF5BC),(0xF5BD),(0xF5BE),(0xF5BF),
+(0xF5C0),(0xF5C1),(0xF5C2),(0xF5C3),(0xF5C4),(0xF5C5),(0xF5C6),(0xF5C7),
+(0xF5C8),(0xF5C9),(0xF5CA),(0xF5CB),(0xF5CC),(0xF5CD),(0xF5CE),(0xF5CF),
+(0xF5D0),(0xF5D1),(0xF5D2),(0xF5D3),(0xF5D4),(0xF5D5),(0xF5D6),(0xF5D7),
+(0xF5D8),(0xF5D9),(0xF5DA),(0xF5DB),(0xF5DC),(0xF5DD),(0xF5DE),(0xF5DF),
+(0xF5E0),(0xF5E1),(0xF5E2),(0xF5E3),(0xF5E4),(0xF5E5),(0xF5E6),(0xF5E7),
+(0xF5E8),(0xF5E9),(0xF5EA),(0xF5EB),(0xF5EC),(0xF5ED),(0xF5EE),(0xF5EF),
+(0xF5F0),(0xF5F1),(0xF5F2),(0xF5F3),(0xF5F4),(0xF5F5),(0xF5F6),(0xF5F7),
+(0xF5F8),(0xF5F9),(0xF5FA),(0xF5FB),(0xF5FC),
+(0xF640),(0xF641),(0xF642),(0xF643),(0xF644),(0xF645),(0xF646),(0xF647),
+(0xF648),(0xF649),(0xF64A),(0xF64B),(0xF64C),(0xF64D),(0xF64E),(0xF64F),
+(0xF650),(0xF651),(0xF652),(0xF653),(0xF654),(0xF655),(0xF656),(0xF657),
+(0xF658),(0xF659),(0xF65A),(0xF65B),(0xF65C),(0xF65D),(0xF65E),(0xF65F),
+(0xF660),(0xF661),(0xF662),(0xF663),(0xF664),(0xF665),(0xF666),(0xF667),
+(0xF668),(0xF669),(0xF66A),(0xF66B),(0xF66C),(0xF66D),(0xF66E),(0xF66F),
+(0xF670),(0xF671),(0xF672),(0xF673),(0xF674),(0xF675),(0xF676),(0xF677),
+(0xF678),(0xF679),(0xF67A),(0xF67B),(0xF67C),(0xF67D),(0xF67E),
+(0xF680),(0xF681),(0xF682),(0xF683),(0xF684),(0xF685),(0xF686),(0xF687),
+(0xF688),(0xF689),(0xF68A),(0xF68B),(0xF68C),(0xF68D),(0xF68E),(0xF68F),
+(0xF690),(0xF691),(0xF692),(0xF693),(0xF694),(0xF695),(0xF696),(0xF697),
+(0xF698),(0xF699),(0xF69A),(0xF69B),(0xF69C),(0xF69D),(0xF69E),(0xF69F),
+(0xF6A0),(0xF6A1),(0xF6A2),(0xF6A3),(0xF6A4),(0xF6A5),(0xF6A6),(0xF6A7),
+(0xF6A8),(0xF6A9),(0xF6AA),(0xF6AB),(0xF6AC),(0xF6AD),(0xF6AE),(0xF6AF),
+(0xF6B0),(0xF6B1),(0xF6B2),(0xF6B3),(0xF6B4),(0xF6B5),(0xF6B6),(0xF6B7),
+(0xF6B8),(0xF6B9),(0xF6BA),(0xF6BB),(0xF6BC),(0xF6BD),(0xF6BE),(0xF6BF),
+(0xF6C0),(0xF6C1),(0xF6C2),(0xF6C3),(0xF6C4),(0xF6C5),(0xF6C6),(0xF6C7),
+(0xF6C8),(0xF6C9),(0xF6CA),(0xF6CB),(0xF6CC),(0xF6CD),(0xF6CE),(0xF6CF),
+(0xF6D0),(0xF6D1),(0xF6D2),(0xF6D3),(0xF6D4),(0xF6D5),(0xF6D6),(0xF6D7),
+(0xF6D8),(0xF6D9),(0xF6DA),(0xF6DB),(0xF6DC),(0xF6DD),(0xF6DE),(0xF6DF),
+(0xF6E0),(0xF6E1),(0xF6E2),(0xF6E3),(0xF6E4),(0xF6E5),(0xF6E6),(0xF6E7),
+(0xF6E8),(0xF6E9),(0xF6EA),(0xF6EB),(0xF6EC),(0xF6ED),(0xF6EE),(0xF6EF),
+(0xF6F0),(0xF6F1),(0xF6F2),(0xF6F3),(0xF6F4),(0xF6F5),(0xF6F6),(0xF6F7),
+(0xF6F8),(0xF6F9),(0xF6FA),(0xF6FB),(0xF6FC),
+(0xF740),(0xF741),(0xF742),(0xF743),(0xF744),(0xF745),(0xF746),(0xF747),
+(0xF748),(0xF749),(0xF74A),(0xF74B),(0xF74C),(0xF74D),(0xF74E),(0xF74F),
+(0xF750),(0xF751),(0xF752),(0xF753),(0xF754),(0xF755),(0xF756),(0xF757),
+(0xF758),(0xF759),(0xF75A),(0xF75B),(0xF75C),(0xF75D),(0xF75E),(0xF75F),
+(0xF760),(0xF761),(0xF762),(0xF763),(0xF764),(0xF765),(0xF766),(0xF767),
+(0xF768),(0xF769),(0xF76A),(0xF76B),(0xF76C),(0xF76D),(0xF76E),(0xF76F),
+(0xF770),(0xF771),(0xF772),(0xF773),(0xF774),(0xF775),(0xF776),(0xF777),
+(0xF778),(0xF779),(0xF77A),(0xF77B),(0xF77C),(0xF77D),(0xF77E),
+(0xF780),(0xF781),(0xF782),(0xF783),(0xF784),(0xF785),(0xF786),(0xF787),
+(0xF788),(0xF789),(0xF78A),(0xF78B),(0xF78C),(0xF78D),(0xF78E),(0xF78F),
+(0xF790),(0xF791),(0xF792),(0xF793),(0xF794),(0xF795),(0xF796),(0xF797),
+(0xF798),(0xF799),(0xF79A),(0xF79B),(0xF79C),(0xF79D),(0xF79E),(0xF79F),
+(0xF7A0),(0xF7A1),(0xF7A2),(0xF7A3),(0xF7A4),(0xF7A5),(0xF7A6),(0xF7A7),
+(0xF7A8),(0xF7A9),(0xF7AA),(0xF7AB),(0xF7AC),(0xF7AD),(0xF7AE),(0xF7AF),
+(0xF7B0),(0xF7B1),(0xF7B2),(0xF7B3),(0xF7B4),(0xF7B5),(0xF7B6),(0xF7B7),
+(0xF7B8),(0xF7B9),(0xF7BA),(0xF7BB),(0xF7BC),(0xF7BD),(0xF7BE),(0xF7BF),
+(0xF7C0),(0xF7C1),(0xF7C2),(0xF7C3),(0xF7C4),(0xF7C5),(0xF7C6),(0xF7C7),
+(0xF7C8),(0xF7C9),(0xF7CA),(0xF7CB),(0xF7CC),(0xF7CD),(0xF7CE),(0xF7CF),
+(0xF7D0),(0xF7D1),(0xF7D2),(0xF7D3),(0xF7D4),(0xF7D5),(0xF7D6),(0xF7D7),
+(0xF7D8),(0xF7D9),(0xF7DA),(0xF7DB),(0xF7DC),(0xF7DD),(0xF7DE),(0xF7DF),
+(0xF7E0),(0xF7E1),(0xF7E2),(0xF7E3),(0xF7E4),(0xF7E5),(0xF7E6),(0xF7E7),
+(0xF7E8),(0xF7E9),(0xF7EA),(0xF7EB),(0xF7EC),(0xF7ED),(0xF7EE),(0xF7EF),
+(0xF7F0),(0xF7F1),(0xF7F2),(0xF7F3),(0xF7F4),(0xF7F5),(0xF7F6),(0xF7F7),
+(0xF7F8),(0xF7F9),(0xF7FA),(0xF7FB),(0xF7FC),
+(0xF840),(0xF841),(0xF842),(0xF843),(0xF844),(0xF845),(0xF846),(0xF847),
+(0xF848),(0xF849),(0xF84A),(0xF84B),(0xF84C),(0xF84D),(0xF84E),(0xF84F),
+(0xF850),(0xF851),(0xF852),(0xF853),(0xF854),(0xF855),(0xF856),(0xF857),
+(0xF858),(0xF859),(0xF85A),(0xF85B),(0xF85C),(0xF85D),(0xF85E),(0xF85F),
+(0xF860),(0xF861),(0xF862),(0xF863),(0xF864),(0xF865),(0xF866),(0xF867),
+(0xF868),(0xF869),(0xF86A),(0xF86B),(0xF86C),(0xF86D),(0xF86E),(0xF86F),
+(0xF870),(0xF871),(0xF872),(0xF873),(0xF874),(0xF875),(0xF876),(0xF877),
+(0xF878),(0xF879),(0xF87A),(0xF87B),(0xF87C),(0xF87D),(0xF87E),
+(0xF880),(0xF881),(0xF882),(0xF883),(0xF884),(0xF885),(0xF886),(0xF887),
+(0xF888),(0xF889),(0xF88A),(0xF88B),(0xF88C),(0xF88D),(0xF88E),(0xF88F),
+(0xF890),(0xF891),(0xF892),(0xF893),(0xF894),(0xF895),(0xF896),(0xF897),
+(0xF898),(0xF899),(0xF89A),(0xF89B),(0xF89C),(0xF89D),(0xF89E),(0xF89F),
+(0xF8A0),(0xF8A1),(0xF8A2),(0xF8A3),(0xF8A4),(0xF8A5),(0xF8A6),(0xF8A7),
+(0xF8A8),(0xF8A9),(0xF8AA),(0xF8AB),(0xF8AC),(0xF8AD),(0xF8AE),(0xF8AF),
+(0xF8B0),(0xF8B1),(0xF8B2),(0xF8B3),(0xF8B4),(0xF8B5),(0xF8B6),(0xF8B7),
+(0xF8B8),(0xF8B9),(0xF8BA),(0xF8BB),(0xF8BC),(0xF8BD),(0xF8BE),(0xF8BF),
+(0xF8C0),(0xF8C1),(0xF8C2),(0xF8C3),(0xF8C4),(0xF8C5),(0xF8C6),(0xF8C7),
+(0xF8C8),(0xF8C9),(0xF8CA),(0xF8CB),(0xF8CC),(0xF8CD),(0xF8CE),(0xF8CF),
+(0xF8D0),(0xF8D1),(0xF8D2),(0xF8D3),(0xF8D4),(0xF8D5),(0xF8D6),(0xF8D7),
+(0xF8D8),(0xF8D9),(0xF8DA),(0xF8DB),(0xF8DC),(0xF8DD),(0xF8DE),(0xF8DF),
+(0xF8E0),(0xF8E1),(0xF8E2),(0xF8E3),(0xF8E4),(0xF8E5),(0xF8E6),(0xF8E7),
+(0xF8E8),(0xF8E9),(0xF8EA),(0xF8EB),(0xF8EC),(0xF8ED),(0xF8EE),(0xF8EF),
+(0xF8F0),(0xF8F1),(0xF8F2),(0xF8F3),(0xF8F4),(0xF8F5),(0xF8F6),(0xF8F7),
+(0xF8F8),(0xF8F9),(0xF8FA),(0xF8FB),(0xF8FC),
+(0xF940),(0xF941),(0xF942),(0xF943),(0xF944),(0xF945),(0xF946),(0xF947),
+(0xF948),(0xF949),(0xF94A),(0xF94B),(0xF94C),(0xF94D),(0xF94E),(0xF94F),
+(0xF950),(0xF951),(0xF952),(0xF953),(0xF954),(0xF955),(0xF956),(0xF957),
+(0xF958),(0xF959),(0xF95A),(0xF95B),(0xF95C),(0xF95D),(0xF95E),(0xF95F),
+(0xF960),(0xF961),(0xF962),(0xF963),(0xF964),(0xF965),(0xF966),(0xF967),
+(0xF968),(0xF969),(0xF96A),(0xF96B),(0xF96C),(0xF96D),(0xF96E),(0xF96F),
+(0xF970),(0xF971),(0xF972),(0xF973),(0xF974),(0xF975),(0xF976),(0xF977),
+(0xF978),(0xF979),(0xF97A),(0xF97B),(0xF97C),(0xF97D),(0xF97E),
+(0xF980),(0xF981),(0xF982),(0xF983),(0xF984),(0xF985),(0xF986),(0xF987),
+(0xF988),(0xF989),(0xF98A),(0xF98B),(0xF98C),(0xF98D),(0xF98E),(0xF98F),
+(0xF990),(0xF991),(0xF992),(0xF993),(0xF994),(0xF995),(0xF996),(0xF997),
+(0xF998),(0xF999),(0xF99A),(0xF99B),(0xF99C),(0xF99D),(0xF99E),(0xF99F),
+(0xF9A0),(0xF9A1),(0xF9A2),(0xF9A3),(0xF9A4),(0xF9A5),(0xF9A6),(0xF9A7),
+(0xF9A8),(0xF9A9),(0xF9AA),(0xF9AB),(0xF9AC),(0xF9AD),(0xF9AE),(0xF9AF),
+(0xF9B0),(0xF9B1),(0xF9B2),(0xF9B3),(0xF9B4),(0xF9B5),(0xF9B6),(0xF9B7),
+(0xF9B8),(0xF9B9),(0xF9BA),(0xF9BB),(0xF9BC),(0xF9BD),(0xF9BE),(0xF9BF),
+(0xF9C0),(0xF9C1),(0xF9C2),(0xF9C3),(0xF9C4),(0xF9C5),(0xF9C6),(0xF9C7),
+(0xF9C8),(0xF9C9),(0xF9CA),(0xF9CB),(0xF9CC),(0xF9CD),(0xF9CE),(0xF9CF),
+(0xF9D0),(0xF9D1),(0xF9D2),(0xF9D3),(0xF9D4),(0xF9D5),(0xF9D6),(0xF9D7),
+(0xF9D8),(0xF9D9),(0xF9DA),(0xF9DB),(0xF9DC),(0xF9DD),(0xF9DE),(0xF9DF),
+(0xF9E0),(0xF9E1),(0xF9E2),(0xF9E3),(0xF9E4),(0xF9E5),(0xF9E6),(0xF9E7),
+(0xF9E8),(0xF9E9),(0xF9EA),(0xF9EB),(0xF9EC),(0xF9ED),(0xF9EE),(0xF9EF),
+(0xF9F0),(0xF9F1),(0xF9F2),(0xF9F3),(0xF9F4),(0xF9F5),(0xF9F6),(0xF9F7),
+(0xF9F8),(0xF9F9),(0xF9FA),(0xF9FB),(0xF9FC);
+SELECT HEX(c1) FROM t1;
+HEX(c1)
+05
+7E
+815C
+815F
+8160
+8161
+817C
+8191
+8192
+81CA
+8740
+8741
+8742
+8743
+8744
+8745
+8746
+8747
+8748
+8749
+874A
+874B
+874C
+874D
+874E
+874F
+8750
+8751
+8752
+8753
+8754
+8755
+8756
+8757
+8758
+8759
+875A
+875B
+875C
+875D
+875F
+8760
+8761
+8762
+8763
+8764
+8765
+8766
+8767
+8768
+8769
+876A
+876B
+876C
+876D
+876E
+876F
+8770
+8771
+8772
+8773
+8774
+8775
+877E
+8780
+8781
+8782
+8783
+8784
+8785
+8786
+8787
+8788
+8789
+878A
+878B
+878C
+878D
+878E
+878F
+8790
+8791
+8792
+8793
+8794
+8795
+8796
+8797
+8798
+8799
+879A
+879B
+879C
+ED40
+ED41
+ED42
+ED43
+ED44
+ED45
+ED46
+ED47
+ED48
+ED49
+ED4A
+ED4B
+ED4C
+ED4D
+ED4E
+ED4F
+ED50
+ED51
+ED52
+ED53
+ED54
+ED55
+ED56
+ED57
+ED58
+ED59
+ED5A
+ED5B
+ED5C
+ED5D
+ED5E
+ED5F
+ED60
+ED61
+ED62
+ED63
+ED64
+ED65
+ED66
+ED67
+ED68
+ED69
+ED6A
+ED6B
+ED6C
+ED6D
+ED6E
+ED6F
+ED70
+ED71
+ED72
+ED73
+ED74
+ED75
+ED76
+ED77
+ED78
+ED79
+ED7A
+ED7B
+ED7C
+ED7D
+ED7E
+ED80
+ED81
+ED82
+ED83
+ED84
+ED85
+ED86
+ED87
+ED88
+ED89
+ED8A
+ED8B
+ED8C
+ED8D
+ED8E
+ED8F
+ED90
+ED91
+ED92
+ED93
+ED94
+ED95
+ED96
+ED97
+ED98
+ED99
+ED9A
+ED9B
+ED9C
+ED9D
+ED9E
+ED9F
+EDA0
+EDA1
+EDA2
+EDA3
+EDA4
+EDA5
+EDA6
+EDA7
+EDA8
+EDA9
+EDAA
+EDAB
+EDAC
+EDAD
+EDAE
+EDAF
+EDB0
+EDB1
+EDB2
+EDB3
+EDB4
+EDB5
+EDB6
+EDB7
+EDB8
+EDB9
+EDBA
+EDBB
+EDBC
+EDBD
+EDBE
+EDBF
+EDC0
+EDC1
+EDC2
+EDC3
+EDC4
+EDC5
+EDC6
+EDC7
+EDC8
+EDC9
+EDCA
+EDCB
+EDCC
+EDCD
+EDCE
+EDCF
+EDD0
+EDD1
+EDD2
+EDD3
+EDD4
+EDD5
+EDD6
+EDD7
+EDD8
+EDD9
+EDDA
+EDDB
+EDDC
+EDDD
+EDDE
+EDDF
+EDE0
+EDE1
+EDE2
+EDE3
+EDE4
+EDE5
+EDE6
+EDE7
+EDE8
+EDE9
+EDEA
+EDEB
+EDEC
+EDED
+EDEE
+EDEF
+EDF0
+EDF1
+EDF2
+EDF3
+EDF4
+EDF5
+EDF6
+EDF7
+EDF8
+EDF9
+EDFA
+EDFB
+EDFC
+EE40
+EE41
+EE42
+EE43
+EE44
+EE45
+EE46
+EE47
+EE48
+EE49
+EE4A
+EE4B
+EE4C
+EE4D
+EE4E
+EE4F
+EE50
+EE51
+EE52
+EE53
+EE54
+EE55
+EE56
+EE57
+EE58
+EE59
+EE5A
+EE5B
+EE5C
+EE5D
+EE5E
+EE5F
+EE60
+EE61
+EE62
+EE63
+EE64
+EE65
+EE66
+EE67
+EE68
+EE69
+EE6A
+EE6B
+EE6C
+EE6D
+EE6E
+EE6F
+EE70
+EE71
+EE72
+EE73
+EE74
+EE75
+EE76
+EE77
+EE78
+EE79
+EE7A
+EE7B
+EE7C
+EE7D
+EE7E
+EE80
+EE81
+EE82
+EE83
+EE84
+EE85
+EE86
+EE87
+EE88
+EE89
+EE8A
+EE8B
+EE8C
+EE8D
+EE8E
+EE8F
+EE90
+EE91
+EE92
+EE93
+EE94
+EE95
+EE96
+EE97
+EE98
+EE99
+EE9A
+EE9B
+EE9C
+EE9D
+EE9E
+EE9F
+EEA0
+EEA1
+EEA2
+EEA3
+EEA4
+EEA5
+EEA6
+EEA7
+EEA8
+EEA9
+EEAA
+EEAB
+EEAC
+EEAD
+EEAE
+EEAF
+EEB0
+EEB1
+EEB2
+EEB3
+EEB4
+EEB5
+EEB6
+EEB7
+EEB8
+EEB9
+EEBA
+EEBB
+EEBC
+EEBD
+EEBE
+EEBF
+EEC0
+EEC1
+EEC2
+EEC3
+EEC4
+EEC5
+EEC6
+EEC7
+EEC8
+EEC9
+EECA
+EECB
+EECC
+EECD
+EECE
+EECF
+EED0
+EED1
+EED2
+EED3
+EED4
+EED5
+EED6
+EED7
+EED8
+EED9
+EEDA
+EEDB
+EEDC
+EEDD
+EEDE
+EEDF
+EEE0
+EEE1
+EEE2
+EEE3
+EEE4
+EEE5
+EEE6
+EEE7
+EEE8
+EEE9
+EEEA
+EEEB
+EEEC
+EEEF
+EEF0
+EEF1
+EEF2
+EEF3
+EEF4
+EEF5
+EEF6
+EEF7
+EEF8
+EEF9
+EEFA
+EEFB
+EEFC
+FA40
+FA41
+FA42
+FA43
+FA44
+FA45
+FA46
+FA47
+FA48
+FA49
+FA4A
+FA4B
+FA4C
+FA4D
+FA4E
+FA4F
+FA50
+FA51
+FA52
+FA53
+FA54
+FA55
+FA56
+FA57
+FA58
+FA59
+FA5A
+FA5B
+FA5C
+FA5D
+FA5E
+FA5F
+FA60
+FA61
+FA62
+FA63
+FA64
+FA65
+FA66
+FA67
+FA68
+FA69
+FA6A
+FA6B
+FA6C
+FA6D
+FA6E
+FA6F
+FA70
+FA71
+FA72
+FA73
+FA74
+FA75
+FA76
+FA77
+FA78
+FA79
+FA7A
+FA7B
+FA7C
+FA7D
+FA7E
+FA80
+FA81
+FA82
+FA83
+FA84
+FA85
+FA86
+FA87
+FA88
+FA89
+FA8A
+FA8B
+FA8C
+FA8D
+FA8E
+FA8F
+FA90
+FA91
+FA92
+FA93
+FA94
+FA95
+FA96
+FA97
+FA98
+FA99
+FA9A
+FA9B
+FA9C
+FA9D
+FA9E
+FA9F
+FAA0
+FAA1
+FAA2
+FAA3
+FAA4
+FAA5
+FAA6
+FAA7
+FAA8
+FAA9
+FAAA
+FAAB
+FAAC
+FAAD
+FAAE
+FAAF
+FAB0
+FAB1
+FAB2
+FAB3
+FAB4
+FAB5
+FAB6
+FAB7
+FAB8
+FAB9
+FABA
+FABB
+FABC
+FABD
+FABE
+FABF
+FAC0
+FAC1
+FAC2
+FAC3
+FAC4
+FAC5
+FAC6
+FAC7
+FAC8
+FAC9
+FACA
+FACB
+FACC
+FACD
+FACE
+FACF
+FAD0
+FAD1
+FAD2
+FAD3
+FAD4
+FAD5
+FAD6
+FAD7
+FAD8
+FAD9
+FADA
+FADB
+FADC
+FADD
+FADE
+FADF
+FAE0
+FAE1
+FAE2
+FAE3
+FAE4
+FAE5
+FAE6
+FAE7
+FAE8
+FAE9
+FAEA
+FAEB
+FAEC
+FAED
+FAEE
+FAEF
+FAF0
+FAF1
+FAF2
+FAF3
+FAF4
+FAF5
+FAF6
+FAF7
+FAF8
+FAF9
+FAFA
+FAFB
+FAFC
+FB40
+FB41
+FB42
+FB43
+FB44
+FB45
+FB46
+FB47
+FB48
+FB49
+FB4A
+FB4B
+FB4C
+FB4D
+FB4E
+FB4F
+FB50
+FB51
+FB52
+FB53
+FB54
+FB55
+FB56
+FB57
+FB58
+FB59
+FB5A
+FB5B
+FB5C
+FB5D
+FB5E
+FB5F
+FB60
+FB61
+FB62
+FB63
+FB64
+FB65
+FB66
+FB67
+FB68
+FB69
+FB6A
+FB6B
+FB6C
+FB6D
+FB6E
+FB6F
+FB70
+FB71
+FB72
+FB73
+FB74
+FB75
+FB76
+FB77
+FB78
+FB79
+FB7A
+FB7B
+FB7C
+FB7D
+FB7E
+FB80
+FB81
+FB82
+FB83
+FB84
+FB85
+FB86
+FB87
+FB88
+FB89
+FB8A
+FB8B
+FB8C
+FB8D
+FB8E
+FB8F
+FB90
+FB91
+FB92
+FB93
+FB94
+FB95
+FB96
+FB97
+FB98
+FB99
+FB9A
+FB9B
+FB9C
+FB9D
+FB9E
+FB9F
+FBA0
+FBA1
+FBA2
+FBA3
+FBA4
+FBA5
+FBA6
+FBA7
+FBA8
+FBA9
+FBAA
+FBAB
+FBAC
+FBAD
+FBAE
+FBAF
+FBB0
+FBB1
+FBB2
+FBB3
+FBB4
+FBB5
+FBB6
+FBB7
+FBB8
+FBB9
+FBBA
+FBBB
+FBBC
+FBBD
+FBBE
+FBBF
+FBC0
+FBC1
+FBC2
+FBC3
+FBC4
+FBC5
+FBC6
+FBC7
+FBC8
+FBC9
+FBCA
+FBCB
+FBCC
+FBCD
+FBCE
+FBCF
+FBD0
+FBD1
+FBD2
+FBD3
+FBD4
+FBD5
+FBD6
+FBD7
+FBD8
+FBD9
+FBDA
+FBDB
+FBDC
+FBDD
+FBDE
+FBDF
+FBE0
+FBE1
+FBE2
+FBE3
+FBE4
+FBE5
+FBE6
+FBE7
+FBE8
+FBE9
+FBEA
+FBEB
+FBEC
+FBED
+FBEE
+FBEF
+FBF0
+FBF1
+FBF2
+FBF3
+FBF4
+FBF5
+FBF6
+FBF7
+FBF8
+FBF9
+FBFA
+FBFB
+FBFC
+FC40
+FC41
+FC42
+FC43
+FC44
+FC45
+FC46
+FC47
+FC48
+FC49
+FC4A
+FC4B
+F040
+F041
+F042
+F043
+F044
+F045
+F046
+F047
+F048
+F049
+F04A
+F04B
+F04C
+F04D
+F04E
+F04F
+F050
+F051
+F052
+F053
+F054
+F055
+F056
+F057
+F058
+F059
+F05A
+F05B
+F05C
+F05D
+F05E
+F05F
+F060
+F061
+F062
+F063
+F064
+F065
+F066
+F067
+F068
+F069
+F06A
+F06B
+F06C
+F06D
+F06E
+F06F
+F070
+F071
+F072
+F073
+F074
+F075
+F076
+F077
+F078
+F079
+F07A
+F07B
+F07C
+F07D
+F07E
+F080
+F081
+F082
+F083
+F084
+F085
+F086
+F087
+F088
+F089
+F08A
+F08B
+F08C
+F08D
+F08E
+F08F
+F090
+F091
+F092
+F093
+F094
+F095
+F096
+F097
+F098
+F099
+F09A
+F09B
+F09C
+F09D
+F09E
+F09F
+F0A0
+F0A1
+F0A2
+F0A3
+F0A4
+F0A5
+F0A6
+F0A7
+F0A8
+F0A9
+F0AA
+F0AB
+F0AC
+F0AD
+F0AE
+F0AF
+F0B0
+F0B1
+F0B2
+F0B3
+F0B4
+F0B5
+F0B6
+F0B7
+F0B8
+F0B9
+F0BA
+F0BB
+F0BC
+F0BD
+F0BE
+F0BF
+F0C0
+F0C1
+F0C2
+F0C3
+F0C4
+F0C5
+F0C6
+F0C7
+F0C8
+F0C9
+F0CA
+F0CB
+F0CC
+F0CD
+F0CE
+F0CF
+F0D0
+F0D1
+F0D2
+F0D3
+F0D4
+F0D5
+F0D6
+F0D7
+F0D8
+F0D9
+F0DA
+F0DB
+F0DC
+F0DD
+F0DE
+F0DF
+F0E0
+F0E1
+F0E2
+F0E3
+F0E4
+F0E5
+F0E6
+F0E7
+F0E8
+F0E9
+F0EA
+F0EB
+F0EC
+F0ED
+F0EE
+F0EF
+F0F0
+F0F1
+F0F2
+F0F3
+F0F4
+F0F5
+F0F6
+F0F7
+F0F8
+F0F9
+F0FA
+F0FB
+F0FC
+F140
+F141
+F142
+F143
+F144
+F145
+F146
+F147
+F148
+F149
+F14A
+F14B
+F14C
+F14D
+F14E
+F14F
+F150
+F151
+F152
+F153
+F154
+F155
+F156
+F157
+F158
+F159
+F15A
+F15B
+F15C
+F15D
+F15E
+F15F
+F160
+F161
+F162
+F163
+F164
+F165
+F166
+F167
+F168
+F169
+F16A
+F16B
+F16C
+F16D
+F16E
+F16F
+F170
+F171
+F172
+F173
+F174
+F175
+F176
+F177
+F178
+F179
+F17A
+F17B
+F17C
+F17D
+F17E
+F180
+F181
+F182
+F183
+F184
+F185
+F186
+F187
+F188
+F189
+F18A
+F18B
+F18C
+F18D
+F18E
+F18F
+F190
+F191
+F192
+F193
+F194
+F195
+F196
+F197
+F198
+F199
+F19A
+F19B
+F19C
+F19D
+F19E
+F19F
+F1A0
+F1A1
+F1A2
+F1A3
+F1A4
+F1A5
+F1A6
+F1A7
+F1A8
+F1A9
+F1AA
+F1AB
+F1AC
+F1AD
+F1AE
+F1AF
+F1B0
+F1B1
+F1B2
+F1B3
+F1B4
+F1B5
+F1B6
+F1B7
+F1B8
+F1B9
+F1BA
+F1BB
+F1BC
+F1BD
+F1BE
+F1BF
+F1C0
+F1C1
+F1C2
+F1C3
+F1C4
+F1C5
+F1C6
+F1C7
+F1C8
+F1C9
+F1CA
+F1CB
+F1CC
+F1CD
+F1CE
+F1CF
+F1D0
+F1D1
+F1D2
+F1D3
+F1D4
+F1D5
+F1D6
+F1D7
+F1D8
+F1D9
+F1DA
+F1DB
+F1DC
+F1DD
+F1DE
+F1DF
+F1E0
+F1E1
+F1E2
+F1E3
+F1E4
+F1E5
+F1E6
+F1E7
+F1E8
+F1E9
+F1EA
+F1EB
+F1EC
+F1ED
+F1EE
+F1EF
+F1F0
+F1F1
+F1F2
+F1F3
+F1F4
+F1F5
+F1F6
+F1F7
+F1F8
+F1F9
+F1FA
+F1FB
+F1FC
+F240
+F241
+F242
+F243
+F244
+F245
+F246
+F247
+F248
+F249
+F24A
+F24B
+F24C
+F24D
+F24E
+F24F
+F250
+F251
+F252
+F253
+F254
+F255
+F256
+F257
+F258
+F259
+F25A
+F25B
+F25C
+F25D
+F25E
+F25F
+F260
+F261
+F262
+F263
+F264
+F265
+F266
+F267
+F268
+F269
+F26A
+F26B
+F26C
+F26D
+F26E
+F26F
+F270
+F271
+F272
+F273
+F274
+F275
+F276
+F277
+F278
+F279
+F27A
+F27B
+F27C
+F27D
+F27E
+F280
+F281
+F282
+F283
+F284
+F285
+F286
+F287
+F288
+F289
+F28A
+F28B
+F28C
+F28D
+F28E
+F28F
+F290
+F291
+F292
+F293
+F294
+F295
+F296
+F297
+F298
+F299
+F29A
+F29B
+F29C
+F29D
+F29E
+F29F
+F2A0
+F2A1
+F2A2
+F2A3
+F2A4
+F2A5
+F2A6
+F2A7
+F2A8
+F2A9
+F2AA
+F2AB
+F2AC
+F2AD
+F2AE
+F2AF
+F2B0
+F2B1
+F2B2
+F2B3
+F2B4
+F2B5
+F2B6
+F2B7
+F2B8
+F2B9
+F2BA
+F2BB
+F2BC
+F2BD
+F2BE
+F2BF
+F2C0
+F2C1
+F2C2
+F2C3
+F2C4
+F2C5
+F2C6
+F2C7
+F2C8
+F2C9
+F2CA
+F2CB
+F2CC
+F2CD
+F2CE
+F2CF
+F2D0
+F2D1
+F2D2
+F2D3
+F2D4
+F2D5
+F2D6
+F2D7
+F2D8
+F2D9
+F2DA
+F2DB
+F2DC
+F2DD
+F2DE
+F2DF
+F2E0
+F2E1
+F2E2
+F2E3
+F2E4
+F2E5
+F2E6
+F2E7
+F2E8
+F2E9
+F2EA
+F2EB
+F2EC
+F2ED
+F2EE
+F2EF
+F2F0
+F2F1
+F2F2
+F2F3
+F2F4
+F2F5
+F2F6
+F2F7
+F2F8
+F2F9
+F2FA
+F2FB
+F2FC
+F340
+F341
+F342
+F343
+F344
+F345
+F346
+F347
+F348
+F349
+F34A
+F34B
+F34C
+F34D
+F34E
+F34F
+F350
+F351
+F352
+F353
+F354
+F355
+F356
+F357
+F358
+F359
+F35A
+F35B
+F35C
+F35D
+F35E
+F35F
+F360
+F361
+F362
+F363
+F364
+F365
+F366
+F367
+F368
+F369
+F36A
+F36B
+F36C
+F36D
+F36E
+F36F
+F370
+F371
+F372
+F373
+F374
+F375
+F376
+F377
+F378
+F379
+F37A
+F37B
+F37C
+F37D
+F37E
+F380
+F381
+F382
+F383
+F384
+F385
+F386
+F387
+F388
+F389
+F38A
+F38B
+F38C
+F38D
+F38E
+F38F
+F390
+F391
+F392
+F393
+F394
+F395
+F396
+F397
+F398
+F399
+F39A
+F39B
+F39C
+F39D
+F39E
+F39F
+F3A0
+F3A1
+F3A2
+F3A3
+F3A4
+F3A5
+F3A6
+F3A7
+F3A8
+F3A9
+F3AA
+F3AB
+F3AC
+F3AD
+F3AE
+F3AF
+F3B0
+F3B1
+F3B2
+F3B3
+F3B4
+F3B5
+F3B6
+F3B7
+F3B8
+F3B9
+F3BA
+F3BB
+F3BC
+F3BD
+F3BE
+F3BF
+F3C0
+F3C1
+F3C2
+F3C3
+F3C4
+F3C5
+F3C6
+F3C7
+F3C8
+F3C9
+F3CA
+F3CB
+F3CC
+F3CD
+F3CE
+F3CF
+F3D0
+F3D1
+F3D2
+F3D3
+F3D4
+F3D5
+F3D6
+F3D7
+F3D8
+F3D9
+F3DA
+F3DB
+F3DC
+F3DD
+F3DE
+F3DF
+F3E0
+F3E1
+F3E2
+F3E3
+F3E4
+F3E5
+F3E6
+F3E7
+F3E8
+F3E9
+F3EA
+F3EB
+F3EC
+F3ED
+F3EE
+F3EF
+F3F0
+F3F1
+F3F2
+F3F3
+F3F4
+F3F5
+F3F6
+F3F7
+F3F8
+F3F9
+F3FA
+F3FB
+F3FC
+F440
+F441
+F442
+F443
+F444
+F445
+F446
+F447
+F448
+F449
+F44A
+F44B
+F44C
+F44D
+F44E
+F44F
+F450
+F451
+F452
+F453
+F454
+F455
+F456
+F457
+F458
+F459
+F45A
+F45B
+F45C
+F45D
+F45E
+F45F
+F460
+F461
+F462
+F463
+F464
+F465
+F466
+F467
+F468
+F469
+F46A
+F46B
+F46C
+F46D
+F46E
+F46F
+F470
+F471
+F472
+F473
+F474
+F475
+F476
+F477
+F478
+F479
+F47A
+F47B
+F47C
+F47D
+F47E
+F480
+F481
+F482
+F483
+F484
+F485
+F486
+F487
+F488
+F489
+F48A
+F48B
+F48C
+F48D
+F48E
+F48F
+F490
+F491
+F492
+F493
+F494
+F495
+F496
+F497
+F498
+F499
+F49A
+F49B
+F49C
+F49D
+F49E
+F49F
+F4A0
+F4A1
+F4A2
+F4A3
+F4A4
+F4A5
+F4A6
+F4A7
+F4A8
+F4A9
+F4AA
+F4AB
+F4AC
+F4AD
+F4AE
+F4AF
+F4B0
+F4B1
+F4B2
+F4B3
+F4B4
+F4B5
+F4B6
+F4B7
+F4B8
+F4B9
+F4BA
+F4BB
+F4BC
+F4BD
+F4BE
+F4BF
+F4C0
+F4C1
+F4C2
+F4C3
+F4C4
+F4C5
+F4C6
+F4C7
+F4C8
+F4C9
+F4CA
+F4CB
+F4CC
+F4CD
+F4CE
+F4CF
+F4D0
+F4D1
+F4D2
+F4D3
+F4D4
+F4D5
+F4D6
+F4D7
+F4D8
+F4D9
+F4DA
+F4DB
+F4DC
+F4DD
+F4DE
+F4DF
+F4E0
+F4E1
+F4E2
+F4E3
+F4E4
+F4E5
+F4E6
+F4E7
+F4E8
+F4E9
+F4EA
+F4EB
+F4EC
+F4ED
+F4EE
+F4EF
+F4F0
+F4F1
+F4F2
+F4F3
+F4F4
+F4F5
+F4F6
+F4F7
+F4F8
+F4F9
+F4FA
+F4FB
+F4FC
+F540
+F541
+F542
+F543
+F544
+F545
+F546
+F547
+F548
+F549
+F54A
+F54B
+F54C
+F54D
+F54E
+F54F
+F550
+F551
+F552
+F553
+F554
+F555
+F556
+F557
+F558
+F559
+F55A
+F55B
+F55C
+F55D
+F55E
+F55F
+F560
+F561
+F562
+F563
+F564
+F565
+F566
+F567
+F568
+F569
+F56A
+F56B
+F56C
+F56D
+F56E
+F56F
+F570
+F571
+F572
+F573
+F574
+F575
+F576
+F577
+F578
+F579
+F57A
+F57B
+F57C
+F57D
+F57E
+F580
+F581
+F582
+F583
+F584
+F585
+F586
+F587
+F588
+F589
+F58A
+F58B
+F58C
+F58D
+F58E
+F58F
+F590
+F591
+F592
+F593
+F594
+F595
+F596
+F597
+F598
+F599
+F59A
+F59B
+F59C
+F59D
+F59E
+F59F
+F5A0
+F5A1
+F5A2
+F5A3
+F5A4
+F5A5
+F5A6
+F5A7
+F5A8
+F5A9
+F5AA
+F5AB
+F5AC
+F5AD
+F5AE
+F5AF
+F5B0
+F5B1
+F5B2
+F5B3
+F5B4
+F5B5
+F5B6
+F5B7
+F5B8
+F5B9
+F5BA
+F5BB
+F5BC
+F5BD
+F5BE
+F5BF
+F5C0
+F5C1
+F5C2
+F5C3
+F5C4
+F5C5
+F5C6
+F5C7
+F5C8
+F5C9
+F5CA
+F5CB
+F5CC
+F5CD
+F5CE
+F5CF
+F5D0
+F5D1
+F5D2
+F5D3
+F5D4
+F5D5
+F5D6
+F5D7
+F5D8
+F5D9
+F5DA
+F5DB
+F5DC
+F5DD
+F5DE
+F5DF
+F5E0
+F5E1
+F5E2
+F5E3
+F5E4
+F5E5
+F5E6
+F5E7
+F5E8
+F5E9
+F5EA
+F5EB
+F5EC
+F5ED
+F5EE
+F5EF
+F5F0
+F5F1
+F5F2
+F5F3
+F5F4
+F5F5
+F5F6
+F5F7
+F5F8
+F5F9
+F5FA
+F5FB
+F5FC
+F640
+F641
+F642
+F643
+F644
+F645
+F646
+F647
+F648
+F649
+F64A
+F64B
+F64C
+F64D
+F64E
+F64F
+F650
+F651
+F652
+F653
+F654
+F655
+F656
+F657
+F658
+F659
+F65A
+F65B
+F65C
+F65D
+F65E
+F65F
+F660
+F661
+F662
+F663
+F664
+F665
+F666
+F667
+F668
+F669
+F66A
+F66B
+F66C
+F66D
+F66E
+F66F
+F670
+F671
+F672
+F673
+F674
+F675
+F676
+F677
+F678
+F679
+F67A
+F67B
+F67C
+F67D
+F67E
+F680
+F681
+F682
+F683
+F684
+F685
+F686
+F687
+F688
+F689
+F68A
+F68B
+F68C
+F68D
+F68E
+F68F
+F690
+F691
+F692
+F693
+F694
+F695
+F696
+F697
+F698
+F699
+F69A
+F69B
+F69C
+F69D
+F69E
+F69F
+F6A0
+F6A1
+F6A2
+F6A3
+F6A4
+F6A5
+F6A6
+F6A7
+F6A8
+F6A9
+F6AA
+F6AB
+F6AC
+F6AD
+F6AE
+F6AF
+F6B0
+F6B1
+F6B2
+F6B3
+F6B4
+F6B5
+F6B6
+F6B7
+F6B8
+F6B9
+F6BA
+F6BB
+F6BC
+F6BD
+F6BE
+F6BF
+F6C0
+F6C1
+F6C2
+F6C3
+F6C4
+F6C5
+F6C6
+F6C7
+F6C8
+F6C9
+F6CA
+F6CB
+F6CC
+F6CD
+F6CE
+F6CF
+F6D0
+F6D1
+F6D2
+F6D3
+F6D4
+F6D5
+F6D6
+F6D7
+F6D8
+F6D9
+F6DA
+F6DB
+F6DC
+F6DD
+F6DE
+F6DF
+F6E0
+F6E1
+F6E2
+F6E3
+F6E4
+F6E5
+F6E6
+F6E7
+F6E8
+F6E9
+F6EA
+F6EB
+F6EC
+F6ED
+F6EE
+F6EF
+F6F0
+F6F1
+F6F2
+F6F3
+F6F4
+F6F5
+F6F6
+F6F7
+F6F8
+F6F9
+F6FA
+F6FB
+F6FC
+F740
+F741
+F742
+F743
+F744
+F745
+F746
+F747
+F748
+F749
+F74A
+F74B
+F74C
+F74D
+F74E
+F74F
+F750
+F751
+F752
+F753
+F754
+F755
+F756
+F757
+F758
+F759
+F75A
+F75B
+F75C
+F75D
+F75E
+F75F
+F760
+F761
+F762
+F763
+F764
+F765
+F766
+F767
+F768
+F769
+F76A
+F76B
+F76C
+F76D
+F76E
+F76F
+F770
+F771
+F772
+F773
+F774
+F775
+F776
+F777
+F778
+F779
+F77A
+F77B
+F77C
+F77D
+F77E
+F780
+F781
+F782
+F783
+F784
+F785
+F786
+F787
+F788
+F789
+F78A
+F78B
+F78C
+F78D
+F78E
+F78F
+F790
+F791
+F792
+F793
+F794
+F795
+F796
+F797
+F798
+F799
+F79A
+F79B
+F79C
+F79D
+F79E
+F79F
+F7A0
+F7A1
+F7A2
+F7A3
+F7A4
+F7A5
+F7A6
+F7A7
+F7A8
+F7A9
+F7AA
+F7AB
+F7AC
+F7AD
+F7AE
+F7AF
+F7B0
+F7B1
+F7B2
+F7B3
+F7B4
+F7B5
+F7B6
+F7B7
+F7B8
+F7B9
+F7BA
+F7BB
+F7BC
+F7BD
+F7BE
+F7BF
+F7C0
+F7C1
+F7C2
+F7C3
+F7C4
+F7C5
+F7C6
+F7C7
+F7C8
+F7C9
+F7CA
+F7CB
+F7CC
+F7CD
+F7CE
+F7CF
+F7D0
+F7D1
+F7D2
+F7D3
+F7D4
+F7D5
+F7D6
+F7D7
+F7D8
+F7D9
+F7DA
+F7DB
+F7DC
+F7DD
+F7DE
+F7DF
+F7E0
+F7E1
+F7E2
+F7E3
+F7E4
+F7E5
+F7E6
+F7E7
+F7E8
+F7E9
+F7EA
+F7EB
+F7EC
+F7ED
+F7EE
+F7EF
+F7F0
+F7F1
+F7F2
+F7F3
+F7F4
+F7F5
+F7F6
+F7F7
+F7F8
+F7F9
+F7FA
+F7FB
+F7FC
+F840
+F841
+F842
+F843
+F844
+F845
+F846
+F847
+F848
+F849
+F84A
+F84B
+F84C
+F84D
+F84E
+F84F
+F850
+F851
+F852
+F853
+F854
+F855
+F856
+F857
+F858
+F859
+F85A
+F85B
+F85C
+F85D
+F85E
+F85F
+F860
+F861
+F862
+F863
+F864
+F865
+F866
+F867
+F868
+F869
+F86A
+F86B
+F86C
+F86D
+F86E
+F86F
+F870
+F871
+F872
+F873
+F874
+F875
+F876
+F877
+F878
+F879
+F87A
+F87B
+F87C
+F87D
+F87E
+F880
+F881
+F882
+F883
+F884
+F885
+F886
+F887
+F888
+F889
+F88A
+F88B
+F88C
+F88D
+F88E
+F88F
+F890
+F891
+F892
+F893
+F894
+F895
+F896
+F897
+F898
+F899
+F89A
+F89B
+F89C
+F89D
+F89E
+F89F
+F8A0
+F8A1
+F8A2
+F8A3
+F8A4
+F8A5
+F8A6
+F8A7
+F8A8
+F8A9
+F8AA
+F8AB
+F8AC
+F8AD
+F8AE
+F8AF
+F8B0
+F8B1
+F8B2
+F8B3
+F8B4
+F8B5
+F8B6
+F8B7
+F8B8
+F8B9
+F8BA
+F8BB
+F8BC
+F8BD
+F8BE
+F8BF
+F8C0
+F8C1
+F8C2
+F8C3
+F8C4
+F8C5
+F8C6
+F8C7
+F8C8
+F8C9
+F8CA
+F8CB
+F8CC
+F8CD
+F8CE
+F8CF
+F8D0
+F8D1
+F8D2
+F8D3
+F8D4
+F8D5
+F8D6
+F8D7
+F8D8
+F8D9
+F8DA
+F8DB
+F8DC
+F8DD
+F8DE
+F8DF
+F8E0
+F8E1
+F8E2
+F8E3
+F8E4
+F8E5
+F8E6
+F8E7
+F8E8
+F8E9
+F8EA
+F8EB
+F8EC
+F8ED
+F8EE
+F8EF
+F8F0
+F8F1
+F8F2
+F8F3
+F8F4
+F8F5
+F8F6
+F8F7
+F8F8
+F8F9
+F8FA
+F8FB
+F8FC
+F940
+F941
+F942
+F943
+F944
+F945
+F946
+F947
+F948
+F949
+F94A
+F94B
+F94C
+F94D
+F94E
+F94F
+F950
+F951
+F952
+F953
+F954
+F955
+F956
+F957
+F958
+F959
+F95A
+F95B
+F95C
+F95D
+F95E
+F95F
+F960
+F961
+F962
+F963
+F964
+F965
+F966
+F967
+F968
+F969
+F96A
+F96B
+F96C
+F96D
+F96E
+F96F
+F970
+F971
+F972
+F973
+F974
+F975
+F976
+F977
+F978
+F979
+F97A
+F97B
+F97C
+F97D
+F97E
+F980
+F981
+F982
+F983
+F984
+F985
+F986
+F987
+F988
+F989
+F98A
+F98B
+F98C
+F98D
+F98E
+F98F
+F990
+F991
+F992
+F993
+F994
+F995
+F996
+F997
+F998
+F999
+F99A
+F99B
+F99C
+F99D
+F99E
+F99F
+F9A0
+F9A1
+F9A2
+F9A3
+F9A4
+F9A5
+F9A6
+F9A7
+F9A8
+F9A9
+F9AA
+F9AB
+F9AC
+F9AD
+F9AE
+F9AF
+F9B0
+F9B1
+F9B2
+F9B3
+F9B4
+F9B5
+F9B6
+F9B7
+F9B8
+F9B9
+F9BA
+F9BB
+F9BC
+F9BD
+F9BE
+F9BF
+F9C0
+F9C1
+F9C2
+F9C3
+F9C4
+F9C5
+F9C6
+F9C7
+F9C8
+F9C9
+F9CA
+F9CB
+F9CC
+F9CD
+F9CE
+F9CF
+F9D0
+F9D1
+F9D2
+F9D3
+F9D4
+F9D5
+F9D6
+F9D7
+F9D8
+F9D9
+F9DA
+F9DB
+F9DC
+F9DD
+F9DE
+F9DF
+F9E0
+F9E1
+F9E2
+F9E3
+F9E4
+F9E5
+F9E6
+F9E7
+F9E8
+F9E9
+F9EA
+F9EB
+F9EC
+F9ED
+F9EE
+F9EF
+F9F0
+F9F1
+F9F2
+F9F3
+F9F4
+F9F5
+F9F6
+F9F7
+F9F8
+F9F9
+F9FA
+F9FB
+F9FC
+CREATE TABLE t2 SELECT CONVERT(c1 USING ucs2) AS c1 FROM t1;
+SELECT HEX(c1) FROM t2;
+HEX(c1)
+0005
+007E
+2015
+FF3C
+FF5E
+2225
+FF0D
+FFE0
+FFE1
+FFE2
+2460
+2461
+2462
+2463
+2464
+2465
+2466
+2467
+2468
+2469
+246A
+246B
+246C
+246D
+246E
+246F
+2470
+2471
+2472
+2473
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+3349
+3314
+3322
+334D
+3318
+3327
+3303
+3336
+3351
+3357
+330D
+3326
+3323
+332B
+334A
+333B
+339C
+339D
+339E
+338E
+338F
+33C4
+33A1
+337B
+301D
+301F
+2116
+33CD
+2121
+32A4
+32A5
+32A6
+32A7
+32A8
+3231
+3232
+3239
+337E
+337D
+337C
+2252
+2261
+222B
+222E
+2211
+221A
+22A5
+2220
+221F
+22BF
+2235
+2229
+222A
+7E8A
+891C
+9348
+9288
+84DC
+4FC9
+70BB
+6631
+68C8
+92F9
+66FB
+5F45
+4E28
+4EE1
+4EFC
+4F00
+4F03
+4F39
+4F56
+4F92
+4F8A
+4F9A
+4F94
+4FCD
+5040
+5022
+4FFF
+501E
+5046
+5070
+5042
+5094
+50F4
+50D8
+514A
+5164
+519D
+51BE
+51EC
+5215
+529C
+52A6
+52C0
+52DB
+5300
+5307
+5324
+5372
+5393
+53B2
+53DD
+FA0E
+549C
+548A
+54A9
+54FF
+5586
+5759
+5765
+57AC
+57C8
+57C7
+FA0F
+FA10
+589E
+58B2
+590B
+5953
+595B
+595D
+5963
+59A4
+59BA
+5B56
+5BC0
+752F
+5BD8
+5BEC
+5C1E
+5CA6
+5CBA
+5CF5
+5D27
+5D53
+FA11
+5D42
+5D6D
+5DB8
+5DB9
+5DD0
+5F21
+5F34
+5F67
+5FB7
+5FDE
+605D
+6085
+608A
+60DE
+60D5
+6120
+60F2
+6111
+6137
+6130
+6198
+6213
+62A6
+63F5
+6460
+649D
+64CE
+654E
+6600
+6615
+663B
+6609
+662E
+661E
+6624
+6665
+6657
+6659
+FA12
+6673
+6699
+66A0
+66B2
+66BF
+66FA
+670E
+F929
+6766
+67BB
+6852
+67C0
+6801
+6844
+68CF
+FA13
+6968
+FA14
+6998
+69E2
+6A30
+6A6B
+6A46
+6A73
+6A7E
+6AE2
+6AE4
+6BD6
+6C3F
+6C5C
+6C86
+6C6F
+6CDA
+6D04
+6D87
+6D6F
+6D96
+6DAC
+6DCF
+6DF8
+6DF2
+6DFC
+6E39
+6E5C
+6E27
+6E3C
+6EBF
+6F88
+6FB5
+6FF5
+7005
+7007
+7028
+7085
+70AB
+710F
+7104
+715C
+7146
+7147
+FA15
+71C1
+71FE
+72B1
+72BE
+7324
+FA16
+7377
+73BD
+73C9
+73D6
+73E3
+73D2
+7407
+73F5
+7426
+742A
+7429
+742E
+7462
+7489
+749F
+7501
+756F
+7682
+769C
+769E
+769B
+76A6
+FA17
+7746
+52AF
+7821
+784E
+7864
+787A
+7930
+FA18
+FA19
+FA1A
+7994
+FA1B
+799B
+7AD1
+7AE7
+FA1C
+7AEB
+7B9E
+FA1D
+7D48
+7D5C
+7DB7
+7DA0
+7DD6
+7E52
+7F47
+7FA1
+FA1E
+8301
+8362
+837F
+83C7
+83F6
+8448
+84B4
+8553
+8559
+856B
+FA1F
+85B0
+FA20
+FA21
+8807
+88F5
+8A12
+8A37
+8A79
+8AA7
+8ABE
+8ADF
+FA22
+8AF6
+8B53
+8B7F
+8CF0
+8CF4
+8D12
+8D76
+FA23
+8ECF
+FA24
+FA25
+9067
+90DE
+FA26
+9115
+9127
+91DA
+91D7
+91DE
+91ED
+91EE
+91E4
+91E5
+9206
+9210
+920A
+923A
+9240
+923C
+924E
+9259
+9251
+9239
+9267
+92A7
+9277
+9278
+92E7
+92D7
+92D9
+92D0
+FA27
+92D5
+92E0
+92D3
+9325
+9321
+92FB
+FA28
+931E
+92FF
+931D
+9302
+9370
+9357
+93A4
+93C6
+93DE
+93F8
+9431
+9445
+9448
+9592
+F9DC
+FA29
+969D
+96AF
+9733
+973B
+9743
+974D
+974F
+9751
+9755
+9857
+9865
+FA2A
+FA2B
+9927
+FA2C
+999E
+9A4E
+9AD9
+9ADC
+9B75
+9B72
+9B8F
+9BB1
+9BBB
+9C00
+9D70
+9D6B
+FA2D
+9E19
+9ED1
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+FFE2
+FFE4
+FF07
+FF02
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+FFE2
+FFE4
+FF07
+FF02
+3231
+2116
+2121
+2235
+7E8A
+891C
+9348
+9288
+84DC
+4FC9
+70BB
+6631
+68C8
+92F9
+66FB
+5F45
+4E28
+4EE1
+4EFC
+4F00
+4F03
+4F39
+4F56
+4F92
+4F8A
+4F9A
+4F94
+4FCD
+5040
+5022
+4FFF
+501E
+5046
+5070
+5042
+5094
+50F4
+50D8
+514A
+5164
+519D
+51BE
+51EC
+5215
+529C
+52A6
+52C0
+52DB
+5300
+5307
+5324
+5372
+5393
+53B2
+53DD
+FA0E
+549C
+548A
+54A9
+54FF
+5586
+5759
+5765
+57AC
+57C8
+57C7
+FA0F
+FA10
+589E
+58B2
+590B
+5953
+595B
+595D
+5963
+59A4
+59BA
+5B56
+5BC0
+752F
+5BD8
+5BEC
+5C1E
+5CA6
+5CBA
+5CF5
+5D27
+5D53
+FA11
+5D42
+5D6D
+5DB8
+5DB9
+5DD0
+5F21
+5F34
+5F67
+5FB7
+5FDE
+605D
+6085
+608A
+60DE
+60D5
+6120
+60F2
+6111
+6137
+6130
+6198
+6213
+62A6
+63F5
+6460
+649D
+64CE
+654E
+6600
+6615
+663B
+6609
+662E
+661E
+6624
+6665
+6657
+6659
+FA12
+6673
+6699
+66A0
+66B2
+66BF
+66FA
+670E
+F929
+6766
+67BB
+6852
+67C0
+6801
+6844
+68CF
+FA13
+6968
+FA14
+6998
+69E2
+6A30
+6A6B
+6A46
+6A73
+6A7E
+6AE2
+6AE4
+6BD6
+6C3F
+6C5C
+6C86
+6C6F
+6CDA
+6D04
+6D87
+6D6F
+6D96
+6DAC
+6DCF
+6DF8
+6DF2
+6DFC
+6E39
+6E5C
+6E27
+6E3C
+6EBF
+6F88
+6FB5
+6FF5
+7005
+7007
+7028
+7085
+70AB
+710F
+7104
+715C
+7146
+7147
+FA15
+71C1
+71FE
+72B1
+72BE
+7324
+FA16
+7377
+73BD
+73C9
+73D6
+73E3
+73D2
+7407
+73F5
+7426
+742A
+7429
+742E
+7462
+7489
+749F
+7501
+756F
+7682
+769C
+769E
+769B
+76A6
+FA17
+7746
+52AF
+7821
+784E
+7864
+787A
+7930
+FA18
+FA19
+FA1A
+7994
+FA1B
+799B
+7AD1
+7AE7
+FA1C
+7AEB
+7B9E
+FA1D
+7D48
+7D5C
+7DB7
+7DA0
+7DD6
+7E52
+7F47
+7FA1
+FA1E
+8301
+8362
+837F
+83C7
+83F6
+8448
+84B4
+8553
+8559
+856B
+FA1F
+85B0
+FA20
+FA21
+8807
+88F5
+8A12
+8A37
+8A79
+8AA7
+8ABE
+8ADF
+FA22
+8AF6
+8B53
+8B7F
+8CF0
+8CF4
+8D12
+8D76
+FA23
+8ECF
+FA24
+FA25
+9067
+90DE
+FA26
+9115
+9127
+91DA
+91D7
+91DE
+91ED
+91EE
+91E4
+91E5
+9206
+9210
+920A
+923A
+9240
+923C
+924E
+9259
+9251
+9239
+9267
+92A7
+9277
+9278
+92E7
+92D7
+92D9
+92D0
+FA27
+92D5
+92E0
+92D3
+9325
+9321
+92FB
+FA28
+931E
+92FF
+931D
+9302
+9370
+9357
+93A4
+93C6
+93DE
+93F8
+9431
+9445
+9448
+9592
+F9DC
+FA29
+969D
+96AF
+9733
+973B
+9743
+974D
+974F
+9751
+9755
+9857
+9865
+FA2A
+FA2B
+9927
+FA2C
+999E
+9A4E
+9AD9
+9ADC
+9B75
+9B72
+9B8F
+9BB1
+9BBB
+9C00
+9D70
+9D6B
+FA2D
+9E19
+9ED1
+E000
+E001
+E002
+E003
+E004
+E005
+E006
+E007
+E008
+E009
+E00A
+E00B
+E00C
+E00D
+E00E
+E00F
+E010
+E011
+E012
+E013
+E014
+E015
+E016
+E017
+E018
+E019
+E01A
+E01B
+E01C
+E01D
+E01E
+E01F
+E020
+E021
+E022
+E023
+E024
+E025
+E026
+E027
+E028
+E029
+E02A
+E02B
+E02C
+E02D
+E02E
+E02F
+E030
+E031
+E032
+E033
+E034
+E035
+E036
+E037
+E038
+E039
+E03A
+E03B
+E03C
+E03D
+E03E
+E03F
+E040
+E041
+E042
+E043
+E044
+E045
+E046
+E047
+E048
+E049
+E04A
+E04B
+E04C
+E04D
+E04E
+E04F
+E050
+E051
+E052
+E053
+E054
+E055
+E056
+E057
+E058
+E059
+E05A
+E05B
+E05C
+E05D
+E05E
+E05F
+E060
+E061
+E062
+E063
+E064
+E065
+E066
+E067
+E068
+E069
+E06A
+E06B
+E06C
+E06D
+E06E
+E06F
+E070
+E071
+E072
+E073
+E074
+E075
+E076
+E077
+E078
+E079
+E07A
+E07B
+E07C
+E07D
+E07E
+E07F
+E080
+E081
+E082
+E083
+E084
+E085
+E086
+E087
+E088
+E089
+E08A
+E08B
+E08C
+E08D
+E08E
+E08F
+E090
+E091
+E092
+E093
+E094
+E095
+E096
+E097
+E098
+E099
+E09A
+E09B
+E09C
+E09D
+E09E
+E09F
+E0A0
+E0A1
+E0A2
+E0A3
+E0A4
+E0A5
+E0A6
+E0A7
+E0A8
+E0A9
+E0AA
+E0AB
+E0AC
+E0AD
+E0AE
+E0AF
+E0B0
+E0B1
+E0B2
+E0B3
+E0B4
+E0B5
+E0B6
+E0B7
+E0B8
+E0B9
+E0BA
+E0BB
+E0BC
+E0BD
+E0BE
+E0BF
+E0C0
+E0C1
+E0C2
+E0C3
+E0C4
+E0C5
+E0C6
+E0C7
+E0C8
+E0C9
+E0CA
+E0CB
+E0CC
+E0CD
+E0CE
+E0CF
+E0D0
+E0D1
+E0D2
+E0D3
+E0D4
+E0D5
+E0D6
+E0D7
+E0D8
+E0D9
+E0DA
+E0DB
+E0DC
+E0DD
+E0DE
+E0DF
+E0E0
+E0E1
+E0E2
+E0E3
+E0E4
+E0E5
+E0E6
+E0E7
+E0E8
+E0E9
+E0EA
+E0EB
+E0EC
+E0ED
+E0EE
+E0EF
+E0F0
+E0F1
+E0F2
+E0F3
+E0F4
+E0F5
+E0F6
+E0F7
+E0F8
+E0F9
+E0FA
+E0FB
+E0FC
+E0FD
+E0FE
+E0FF
+E100
+E101
+E102
+E103
+E104
+E105
+E106
+E107
+E108
+E109
+E10A
+E10B
+E10C
+E10D
+E10E
+E10F
+E110
+E111
+E112
+E113
+E114
+E115
+E116
+E117
+E118
+E119
+E11A
+E11B
+E11C
+E11D
+E11E
+E11F
+E120
+E121
+E122
+E123
+E124
+E125
+E126
+E127
+E128
+E129
+E12A
+E12B
+E12C
+E12D
+E12E
+E12F
+E130
+E131
+E132
+E133
+E134
+E135
+E136
+E137
+E138
+E139
+E13A
+E13B
+E13C
+E13D
+E13E
+E13F
+E140
+E141
+E142
+E143
+E144
+E145
+E146
+E147
+E148
+E149
+E14A
+E14B
+E14C
+E14D
+E14E
+E14F
+E150
+E151
+E152
+E153
+E154
+E155
+E156
+E157
+E158
+E159
+E15A
+E15B
+E15C
+E15D
+E15E
+E15F
+E160
+E161
+E162
+E163
+E164
+E165
+E166
+E167
+E168
+E169
+E16A
+E16B
+E16C
+E16D
+E16E
+E16F
+E170
+E171
+E172
+E173
+E174
+E175
+E176
+E177
+E178
+E179
+E17A
+E17B
+E17C
+E17D
+E17E
+E17F
+E180
+E181
+E182
+E183
+E184
+E185
+E186
+E187
+E188
+E189
+E18A
+E18B
+E18C
+E18D
+E18E
+E18F
+E190
+E191
+E192
+E193
+E194
+E195
+E196
+E197
+E198
+E199
+E19A
+E19B
+E19C
+E19D
+E19E
+E19F
+E1A0
+E1A1
+E1A2
+E1A3
+E1A4
+E1A5
+E1A6
+E1A7
+E1A8
+E1A9
+E1AA
+E1AB
+E1AC
+E1AD
+E1AE
+E1AF
+E1B0
+E1B1
+E1B2
+E1B3
+E1B4
+E1B5
+E1B6
+E1B7
+E1B8
+E1B9
+E1BA
+E1BB
+E1BC
+E1BD
+E1BE
+E1BF
+E1C0
+E1C1
+E1C2
+E1C3
+E1C4
+E1C5
+E1C6
+E1C7
+E1C8
+E1C9
+E1CA
+E1CB
+E1CC
+E1CD
+E1CE
+E1CF
+E1D0
+E1D1
+E1D2
+E1D3
+E1D4
+E1D5
+E1D6
+E1D7
+E1D8
+E1D9
+E1DA
+E1DB
+E1DC
+E1DD
+E1DE
+E1DF
+E1E0
+E1E1
+E1E2
+E1E3
+E1E4
+E1E5
+E1E6
+E1E7
+E1E8
+E1E9
+E1EA
+E1EB
+E1EC
+E1ED
+E1EE
+E1EF
+E1F0
+E1F1
+E1F2
+E1F3
+E1F4
+E1F5
+E1F6
+E1F7
+E1F8
+E1F9
+E1FA
+E1FB
+E1FC
+E1FD
+E1FE
+E1FF
+E200
+E201
+E202
+E203
+E204
+E205
+E206
+E207
+E208
+E209
+E20A
+E20B
+E20C
+E20D
+E20E
+E20F
+E210
+E211
+E212
+E213
+E214
+E215
+E216
+E217
+E218
+E219
+E21A
+E21B
+E21C
+E21D
+E21E
+E21F
+E220
+E221
+E222
+E223
+E224
+E225
+E226
+E227
+E228
+E229
+E22A
+E22B
+E22C
+E22D
+E22E
+E22F
+E230
+E231
+E232
+E233
+E234
+E235
+E236
+E237
+E238
+E239
+E23A
+E23B
+E23C
+E23D
+E23E
+E23F
+E240
+E241
+E242
+E243
+E244
+E245
+E246
+E247
+E248
+E249
+E24A
+E24B
+E24C
+E24D
+E24E
+E24F
+E250
+E251
+E252
+E253
+E254
+E255
+E256
+E257
+E258
+E259
+E25A
+E25B
+E25C
+E25D
+E25E
+E25F
+E260
+E261
+E262
+E263
+E264
+E265
+E266
+E267
+E268
+E269
+E26A
+E26B
+E26C
+E26D
+E26E
+E26F
+E270
+E271
+E272
+E273
+E274
+E275
+E276
+E277
+E278
+E279
+E27A
+E27B
+E27C
+E27D
+E27E
+E27F
+E280
+E281
+E282
+E283
+E284
+E285
+E286
+E287
+E288
+E289
+E28A
+E28B
+E28C
+E28D
+E28E
+E28F
+E290
+E291
+E292
+E293
+E294
+E295
+E296
+E297
+E298
+E299
+E29A
+E29B
+E29C
+E29D
+E29E
+E29F
+E2A0
+E2A1
+E2A2
+E2A3
+E2A4
+E2A5
+E2A6
+E2A7
+E2A8
+E2A9
+E2AA
+E2AB
+E2AC
+E2AD
+E2AE
+E2AF
+E2B0
+E2B1
+E2B2
+E2B3
+E2B4
+E2B5
+E2B6
+E2B7
+E2B8
+E2B9
+E2BA
+E2BB
+E2BC
+E2BD
+E2BE
+E2BF
+E2C0
+E2C1
+E2C2
+E2C3
+E2C4
+E2C5
+E2C6
+E2C7
+E2C8
+E2C9
+E2CA
+E2CB
+E2CC
+E2CD
+E2CE
+E2CF
+E2D0
+E2D1
+E2D2
+E2D3
+E2D4
+E2D5
+E2D6
+E2D7
+E2D8
+E2D9
+E2DA
+E2DB
+E2DC
+E2DD
+E2DE
+E2DF
+E2E0
+E2E1
+E2E2
+E2E3
+E2E4
+E2E5
+E2E6
+E2E7
+E2E8
+E2E9
+E2EA
+E2EB
+E2EC
+E2ED
+E2EE
+E2EF
+E2F0
+E2F1
+E2F2
+E2F3
+E2F4
+E2F5
+E2F6
+E2F7
+E2F8
+E2F9
+E2FA
+E2FB
+E2FC
+E2FD
+E2FE
+E2FF
+E300
+E301
+E302
+E303
+E304
+E305
+E306
+E307
+E308
+E309
+E30A
+E30B
+E30C
+E30D
+E30E
+E30F
+E310
+E311
+E312
+E313
+E314
+E315
+E316
+E317
+E318
+E319
+E31A
+E31B
+E31C
+E31D
+E31E
+E31F
+E320
+E321
+E322
+E323
+E324
+E325
+E326
+E327
+E328
+E329
+E32A
+E32B
+E32C
+E32D
+E32E
+E32F
+E330
+E331
+E332
+E333
+E334
+E335
+E336
+E337
+E338
+E339
+E33A
+E33B
+E33C
+E33D
+E33E
+E33F
+E340
+E341
+E342
+E343
+E344
+E345
+E346
+E347
+E348
+E349
+E34A
+E34B
+E34C
+E34D
+E34E
+E34F
+E350
+E351
+E352
+E353
+E354
+E355
+E356
+E357
+E358
+E359
+E35A
+E35B
+E35C
+E35D
+E35E
+E35F
+E360
+E361
+E362
+E363
+E364
+E365
+E366
+E367
+E368
+E369
+E36A
+E36B
+E36C
+E36D
+E36E
+E36F
+E370
+E371
+E372
+E373
+E374
+E375
+E376
+E377
+E378
+E379
+E37A
+E37B
+E37C
+E37D
+E37E
+E37F
+E380
+E381
+E382
+E383
+E384
+E385
+E386
+E387
+E388
+E389
+E38A
+E38B
+E38C
+E38D
+E38E
+E38F
+E390
+E391
+E392
+E393
+E394
+E395
+E396
+E397
+E398
+E399
+E39A
+E39B
+E39C
+E39D
+E39E
+E39F
+E3A0
+E3A1
+E3A2
+E3A3
+E3A4
+E3A5
+E3A6
+E3A7
+E3A8
+E3A9
+E3AA
+E3AB
+E3AC
+E3AD
+E3AE
+E3AF
+E3B0
+E3B1
+E3B2
+E3B3
+E3B4
+E3B5
+E3B6
+E3B7
+E3B8
+E3B9
+E3BA
+E3BB
+E3BC
+E3BD
+E3BE
+E3BF
+E3C0
+E3C1
+E3C2
+E3C3
+E3C4
+E3C5
+E3C6
+E3C7
+E3C8
+E3C9
+E3CA
+E3CB
+E3CC
+E3CD
+E3CE
+E3CF
+E3D0
+E3D1
+E3D2
+E3D3
+E3D4
+E3D5
+E3D6
+E3D7
+E3D8
+E3D9
+E3DA
+E3DB
+E3DC
+E3DD
+E3DE
+E3DF
+E3E0
+E3E1
+E3E2
+E3E3
+E3E4
+E3E5
+E3E6
+E3E7
+E3E8
+E3E9
+E3EA
+E3EB
+E3EC
+E3ED
+E3EE
+E3EF
+E3F0
+E3F1
+E3F2
+E3F3
+E3F4
+E3F5
+E3F6
+E3F7
+E3F8
+E3F9
+E3FA
+E3FB
+E3FC
+E3FD
+E3FE
+E3FF
+E400
+E401
+E402
+E403
+E404
+E405
+E406
+E407
+E408
+E409
+E40A
+E40B
+E40C
+E40D
+E40E
+E40F
+E410
+E411
+E412
+E413
+E414
+E415
+E416
+E417
+E418
+E419
+E41A
+E41B
+E41C
+E41D
+E41E
+E41F
+E420
+E421
+E422
+E423
+E424
+E425
+E426
+E427
+E428
+E429
+E42A
+E42B
+E42C
+E42D
+E42E
+E42F
+E430
+E431
+E432
+E433
+E434
+E435
+E436
+E437
+E438
+E439
+E43A
+E43B
+E43C
+E43D
+E43E
+E43F
+E440
+E441
+E442
+E443
+E444
+E445
+E446
+E447
+E448
+E449
+E44A
+E44B
+E44C
+E44D
+E44E
+E44F
+E450
+E451
+E452
+E453
+E454
+E455
+E456
+E457
+E458
+E459
+E45A
+E45B
+E45C
+E45D
+E45E
+E45F
+E460
+E461
+E462
+E463
+E464
+E465
+E466
+E467
+E468
+E469
+E46A
+E46B
+E46C
+E46D
+E46E
+E46F
+E470
+E471
+E472
+E473
+E474
+E475
+E476
+E477
+E478
+E479
+E47A
+E47B
+E47C
+E47D
+E47E
+E47F
+E480
+E481
+E482
+E483
+E484
+E485
+E486
+E487
+E488
+E489
+E48A
+E48B
+E48C
+E48D
+E48E
+E48F
+E490
+E491
+E492
+E493
+E494
+E495
+E496
+E497
+E498
+E499
+E49A
+E49B
+E49C
+E49D
+E49E
+E49F
+E4A0
+E4A1
+E4A2
+E4A3
+E4A4
+E4A5
+E4A6
+E4A7
+E4A8
+E4A9
+E4AA
+E4AB
+E4AC
+E4AD
+E4AE
+E4AF
+E4B0
+E4B1
+E4B2
+E4B3
+E4B4
+E4B5
+E4B6
+E4B7
+E4B8
+E4B9
+E4BA
+E4BB
+E4BC
+E4BD
+E4BE
+E4BF
+E4C0
+E4C1
+E4C2
+E4C3
+E4C4
+E4C5
+E4C6
+E4C7
+E4C8
+E4C9
+E4CA
+E4CB
+E4CC
+E4CD
+E4CE
+E4CF
+E4D0
+E4D1
+E4D2
+E4D3
+E4D4
+E4D5
+E4D6
+E4D7
+E4D8
+E4D9
+E4DA
+E4DB
+E4DC
+E4DD
+E4DE
+E4DF
+E4E0
+E4E1
+E4E2
+E4E3
+E4E4
+E4E5
+E4E6
+E4E7
+E4E8
+E4E9
+E4EA
+E4EB
+E4EC
+E4ED
+E4EE
+E4EF
+E4F0
+E4F1
+E4F2
+E4F3
+E4F4
+E4F5
+E4F6
+E4F7
+E4F8
+E4F9
+E4FA
+E4FB
+E4FC
+E4FD
+E4FE
+E4FF
+E500
+E501
+E502
+E503
+E504
+E505
+E506
+E507
+E508
+E509
+E50A
+E50B
+E50C
+E50D
+E50E
+E50F
+E510
+E511
+E512
+E513
+E514
+E515
+E516
+E517
+E518
+E519
+E51A
+E51B
+E51C
+E51D
+E51E
+E51F
+E520
+E521
+E522
+E523
+E524
+E525
+E526
+E527
+E528
+E529
+E52A
+E52B
+E52C
+E52D
+E52E
+E52F
+E530
+E531
+E532
+E533
+E534
+E535
+E536
+E537
+E538
+E539
+E53A
+E53B
+E53C
+E53D
+E53E
+E53F
+E540
+E541
+E542
+E543
+E544
+E545
+E546
+E547
+E548
+E549
+E54A
+E54B
+E54C
+E54D
+E54E
+E54F
+E550
+E551
+E552
+E553
+E554
+E555
+E556
+E557
+E558
+E559
+E55A
+E55B
+E55C
+E55D
+E55E
+E55F
+E560
+E561
+E562
+E563
+E564
+E565
+E566
+E567
+E568
+E569
+E56A
+E56B
+E56C
+E56D
+E56E
+E56F
+E570
+E571
+E572
+E573
+E574
+E575
+E576
+E577
+E578
+E579
+E57A
+E57B
+E57C
+E57D
+E57E
+E57F
+E580
+E581
+E582
+E583
+E584
+E585
+E586
+E587
+E588
+E589
+E58A
+E58B
+E58C
+E58D
+E58E
+E58F
+E590
+E591
+E592
+E593
+E594
+E595
+E596
+E597
+E598
+E599
+E59A
+E59B
+E59C
+E59D
+E59E
+E59F
+E5A0
+E5A1
+E5A2
+E5A3
+E5A4
+E5A5
+E5A6
+E5A7
+E5A8
+E5A9
+E5AA
+E5AB
+E5AC
+E5AD
+E5AE
+E5AF
+E5B0
+E5B1
+E5B2
+E5B3
+E5B4
+E5B5
+E5B6
+E5B7
+E5B8
+E5B9
+E5BA
+E5BB
+E5BC
+E5BD
+E5BE
+E5BF
+E5C0
+E5C1
+E5C2
+E5C3
+E5C4
+E5C5
+E5C6
+E5C7
+E5C8
+E5C9
+E5CA
+E5CB
+E5CC
+E5CD
+E5CE
+E5CF
+E5D0
+E5D1
+E5D2
+E5D3
+E5D4
+E5D5
+E5D6
+E5D7
+E5D8
+E5D9
+E5DA
+E5DB
+E5DC
+E5DD
+E5DE
+E5DF
+E5E0
+E5E1
+E5E2
+E5E3
+E5E4
+E5E5
+E5E6
+E5E7
+E5E8
+E5E9
+E5EA
+E5EB
+E5EC
+E5ED
+E5EE
+E5EF
+E5F0
+E5F1
+E5F2
+E5F3
+E5F4
+E5F5
+E5F6
+E5F7
+E5F8
+E5F9
+E5FA
+E5FB
+E5FC
+E5FD
+E5FE
+E5FF
+E600
+E601
+E602
+E603
+E604
+E605
+E606
+E607
+E608
+E609
+E60A
+E60B
+E60C
+E60D
+E60E
+E60F
+E610
+E611
+E612
+E613
+E614
+E615
+E616
+E617
+E618
+E619
+E61A
+E61B
+E61C
+E61D
+E61E
+E61F
+E620
+E621
+E622
+E623
+E624
+E625
+E626
+E627
+E628
+E629
+E62A
+E62B
+E62C
+E62D
+E62E
+E62F
+E630
+E631
+E632
+E633
+E634
+E635
+E636
+E637
+E638
+E639
+E63A
+E63B
+E63C
+E63D
+E63E
+E63F
+E640
+E641
+E642
+E643
+E644
+E645
+E646
+E647
+E648
+E649
+E64A
+E64B
+E64C
+E64D
+E64E
+E64F
+E650
+E651
+E652
+E653
+E654
+E655
+E656
+E657
+E658
+E659
+E65A
+E65B
+E65C
+E65D
+E65E
+E65F
+E660
+E661
+E662
+E663
+E664
+E665
+E666
+E667
+E668
+E669
+E66A
+E66B
+E66C
+E66D
+E66E
+E66F
+E670
+E671
+E672
+E673
+E674
+E675
+E676
+E677
+E678
+E679
+E67A
+E67B
+E67C
+E67D
+E67E
+E67F
+E680
+E681
+E682
+E683
+E684
+E685
+E686
+E687
+E688
+E689
+E68A
+E68B
+E68C
+E68D
+E68E
+E68F
+E690
+E691
+E692
+E693
+E694
+E695
+E696
+E697
+E698
+E699
+E69A
+E69B
+E69C
+E69D
+E69E
+E69F
+E6A0
+E6A1
+E6A2
+E6A3
+E6A4
+E6A5
+E6A6
+E6A7
+E6A8
+E6A9
+E6AA
+E6AB
+E6AC
+E6AD
+E6AE
+E6AF
+E6B0
+E6B1
+E6B2
+E6B3
+E6B4
+E6B5
+E6B6
+E6B7
+E6B8
+E6B9
+E6BA
+E6BB
+E6BC
+E6BD
+E6BE
+E6BF
+E6C0
+E6C1
+E6C2
+E6C3
+E6C4
+E6C5
+E6C6
+E6C7
+E6C8
+E6C9
+E6CA
+E6CB
+E6CC
+E6CD
+E6CE
+E6CF
+E6D0
+E6D1
+E6D2
+E6D3
+E6D4
+E6D5
+E6D6
+E6D7
+E6D8
+E6D9
+E6DA
+E6DB
+E6DC
+E6DD
+E6DE
+E6DF
+E6E0
+E6E1
+E6E2
+E6E3
+E6E4
+E6E5
+E6E6
+E6E7
+E6E8
+E6E9
+E6EA
+E6EB
+E6EC
+E6ED
+E6EE
+E6EF
+E6F0
+E6F1
+E6F2
+E6F3
+E6F4
+E6F5
+E6F6
+E6F7
+E6F8
+E6F9
+E6FA
+E6FB
+E6FC
+E6FD
+E6FE
+E6FF
+E700
+E701
+E702
+E703
+E704
+E705
+E706
+E707
+E708
+E709
+E70A
+E70B
+E70C
+E70D
+E70E
+E70F
+E710
+E711
+E712
+E713
+E714
+E715
+E716
+E717
+E718
+E719
+E71A
+E71B
+E71C
+E71D
+E71E
+E71F
+E720
+E721
+E722
+E723
+E724
+E725
+E726
+E727
+E728
+E729
+E72A
+E72B
+E72C
+E72D
+E72E
+E72F
+E730
+E731
+E732
+E733
+E734
+E735
+E736
+E737
+E738
+E739
+E73A
+E73B
+E73C
+E73D
+E73E
+E73F
+E740
+E741
+E742
+E743
+E744
+E745
+E746
+E747
+E748
+E749
+E74A
+E74B
+E74C
+E74D
+E74E
+E74F
+E750
+E751
+E752
+E753
+E754
+E755
+E756
+E757
+CREATE TABLE t3 SELECT CONVERT(c1 USING cp932) AS c1 FROM t2;
+SELECT HEX(c1) FROM t3;
+HEX(c1)
+05
+7E
+815C
+815F
+8160
+8161
+817C
+8191
+8192
+81CA
+8740
+8741
+8742
+8743
+8744
+8745
+8746
+8747
+8748
+8749
+874A
+874B
+874C
+874D
+874E
+874F
+8750
+8751
+8752
+8753
+8754
+8755
+8756
+8757
+8758
+8759
+875A
+875B
+875C
+875D
+875F
+8760
+8761
+8762
+8763
+8764
+8765
+8766
+8767
+8768
+8769
+876A
+876B
+876C
+876D
+876E
+876F
+8770
+8771
+8772
+8773
+8774
+8775
+877E
+8780
+8781
+8782
+8783
+8784
+8785
+8786
+8787
+8788
+8789
+878A
+878B
+878C
+878D
+878E
+878F
+81E0
+81DF
+81E7
+8793
+8794
+81E3
+81DB
+81DA
+8798
+8799
+81E6
+81BF
+81BE
+FA5C
+FA5D
+FA5E
+FA5F
+FA60
+FA61
+FA62
+FA63
+FA64
+FA65
+FA66
+FA67
+FA68
+FA69
+FA6A
+FA6B
+FA6C
+FA6D
+FA6E
+FA6F
+FA70
+FA71
+FA72
+FA73
+FA74
+FA75
+FA76
+FA77
+FA78
+FA79
+FA7A
+FA7B
+FA7C
+FA7D
+FA7E
+FA80
+FA81
+FA82
+FA83
+FA84
+FA85
+FA86
+FA87
+FA88
+FA89
+FA8A
+FA8B
+FA8C
+FA8D
+FA8E
+FA8F
+FA90
+FA91
+FA92
+FA93
+FA94
+FA95
+FA96
+FA97
+FA98
+FA99
+FA9A
+FA9B
+FA9C
+FA9D
+FA9E
+FA9F
+FAA0
+FAA1
+FAA2
+FAA3
+FAA4
+FAA5
+FAA6
+FAA7
+FAA8
+FAA9
+FAAA
+FAAB
+FAAC
+FAAD
+FAAE
+FAAF
+FAB0
+FAB1
+FAB2
+FAB3
+FAB4
+FAB5
+FAB6
+FAB7
+FAB8
+FAB9
+FABA
+FABB
+FABC
+FABD
+FABE
+FABF
+FAC0
+FAC1
+FAC2
+FAC3
+FAC4
+FAC5
+FAC6
+FAC7
+FAC8
+FAC9
+FACA
+FACB
+FACC
+FACD
+FACE
+FACF
+FAD0
+FAD1
+FAD2
+FAD3
+FAD4
+FAD5
+FAD6
+FAD7
+FAD8
+FAD9
+FADA
+FADB
+FADC
+FADD
+FADE
+FADF
+FAE0
+FAE1
+FAE2
+FAE3
+FAE4
+FAE5
+FAE6
+FAE7
+FAE8
+FAE9
+FAEA
+FAEB
+FAEC
+FAED
+FAEE
+FAEF
+FAF0
+FAF1
+FAF2
+FAF3
+FAF4
+FAF5
+FAF6
+FAF7
+FAF8
+FAF9
+FAFA
+FAFB
+FAFC
+FB40
+FB41
+FB42
+FB43
+FB44
+FB45
+FB46
+FB47
+FB48
+FB49
+FB4A
+FB4B
+FB4C
+FB4D
+FB4E
+FB4F
+FB50
+FB51
+FB52
+FB53
+FB54
+FB55
+FB56
+FB57
+FB58
+FB59
+FB5A
+FB5B
+FB5C
+FB5D
+FB5E
+FB5F
+FB60
+FB61
+FB62
+FB63
+FB64
+FB65
+FB66
+FB67
+FB68
+FB69
+FB6A
+FB6B
+FB6C
+FB6D
+FB6E
+FB6F
+FB70
+FB71
+FB72
+FB73
+FB74
+FB75
+FB76
+FB77
+FB78
+FB79
+FB7A
+FB7B
+FB7C
+FB7D
+FB7E
+FB80
+FB81
+FB82
+FB83
+FB84
+FB85
+FB86
+FB87
+FB88
+FB89
+FB8A
+FB8B
+FB8C
+FB8D
+FB8E
+FB8F
+FB90
+FB91
+FB92
+FB93
+FB94
+FB95
+FB96
+FB97
+FB98
+FB99
+FB9A
+FB9B
+FB9C
+FB9D
+FB9E
+FB9F
+FBA0
+FBA1
+FBA2
+FBA3
+FBA4
+FBA5
+FBA6
+FBA7
+FBA8
+FBA9
+FBAA
+FBAB
+FBAC
+FBAD
+FBAE
+FBAF
+FBB0
+FBB1
+FBB2
+FBB3
+FBB4
+FBB5
+FBB6
+FBB7
+FBB8
+FBB9
+FBBA
+FBBB
+FBBC
+FBBD
+FBBE
+FBBF
+FBC0
+FBC1
+FBC2
+FBC3
+FBC4
+FBC5
+FBC6
+FBC7
+FBC8
+FBC9
+FBCA
+FBCB
+FBCC
+FBCD
+FBCE
+FBCF
+FBD0
+FBD1
+FBD2
+FBD3
+FBD4
+FBD5
+FBD6
+FBD7
+FBD8
+FBD9
+FBDA
+FBDB
+FBDC
+FBDD
+FBDE
+FBDF
+FBE0
+FBE1
+FBE2
+FBE3
+FBE4
+FBE5
+FBE6
+FBE7
+FBE8
+FBE9
+FBEA
+FBEB
+FBEC
+FBED
+FBEE
+FBEF
+FBF0
+FBF1
+FBF2
+FBF3
+FBF4
+FBF5
+FBF6
+FBF7
+FBF8
+FBF9
+FBFA
+FBFB
+FBFC
+FC40
+FC41
+FC42
+FC43
+FC44
+FC45
+FC46
+FC47
+FC48
+FC49
+FC4A
+FC4B
+FA40
+FA41
+FA42
+FA43
+FA44
+FA45
+FA46
+FA47
+FA48
+FA49
+81CA
+FA55
+FA56
+FA57
+FA40
+FA41
+FA42
+FA43
+FA44
+FA45
+FA46
+FA47
+FA48
+FA49
+8754
+8755
+8756
+8757
+8758
+8759
+875A
+875B
+875C
+875D
+81CA
+FA55
+FA56
+FA57
+878A
+8782
+8784
+81E6
+FA5C
+FA5D
+FA5E
+FA5F
+FA60
+FA61
+FA62
+FA63
+FA64
+FA65
+FA66
+FA67
+FA68
+FA69
+FA6A
+FA6B
+FA6C
+FA6D
+FA6E
+FA6F
+FA70
+FA71
+FA72
+FA73
+FA74
+FA75
+FA76
+FA77
+FA78
+FA79
+FA7A
+FA7B
+FA7C
+FA7D
+FA7E
+FA80
+FA81
+FA82
+FA83
+FA84
+FA85
+FA86
+FA87
+FA88
+FA89
+FA8A
+FA8B
+FA8C
+FA8D
+FA8E
+FA8F
+FA90
+FA91
+FA92
+FA93
+FA94
+FA95
+FA96
+FA97
+FA98
+FA99
+FA9A
+FA9B
+FA9C
+FA9D
+FA9E
+FA9F
+FAA0
+FAA1
+FAA2
+FAA3
+FAA4
+FAA5
+FAA6
+FAA7
+FAA8
+FAA9
+FAAA
+FAAB
+FAAC
+FAAD
+FAAE
+FAAF
+FAB0
+FAB1
+FAB2
+FAB3
+FAB4
+FAB5
+FAB6
+FAB7
+FAB8
+FAB9
+FABA
+FABB
+FABC
+FABD
+FABE
+FABF
+FAC0
+FAC1
+FAC2
+FAC3
+FAC4
+FAC5
+FAC6
+FAC7
+FAC8
+FAC9
+FACA
+FACB
+FACC
+FACD
+FACE
+FACF
+FAD0
+FAD1
+FAD2
+FAD3
+FAD4
+FAD5
+FAD6
+FAD7
+FAD8
+FAD9
+FADA
+FADB
+FADC
+FADD
+FADE
+FADF
+FAE0
+FAE1
+FAE2
+FAE3
+FAE4
+FAE5
+FAE6
+FAE7
+FAE8
+FAE9
+FAEA
+FAEB
+FAEC
+FAED
+FAEE
+FAEF
+FAF0
+FAF1
+FAF2
+FAF3
+FAF4
+FAF5
+FAF6
+FAF7
+FAF8
+FAF9
+FAFA
+FAFB
+FAFC
+FB40
+FB41
+FB42
+FB43
+FB44
+FB45
+FB46
+FB47
+FB48
+FB49
+FB4A
+FB4B
+FB4C
+FB4D
+FB4E
+FB4F
+FB50
+FB51
+FB52
+FB53
+FB54
+FB55
+FB56
+FB57
+FB58
+FB59
+FB5A
+FB5B
+FB5C
+FB5D
+FB5E
+FB5F
+FB60
+FB61
+FB62
+FB63
+FB64
+FB65
+FB66
+FB67
+FB68
+FB69
+FB6A
+FB6B
+FB6C
+FB6D
+FB6E
+FB6F
+FB70
+FB71
+FB72
+FB73
+FB74
+FB75
+FB76
+FB77
+FB78
+FB79
+FB7A
+FB7B
+FB7C
+FB7D
+FB7E
+FB80
+FB81
+FB82
+FB83
+FB84
+FB85
+FB86
+FB87
+FB88
+FB89
+FB8A
+FB8B
+FB8C
+FB8D
+FB8E
+FB8F
+FB90
+FB91
+FB92
+FB93
+FB94
+FB95
+FB96
+FB97
+FB98
+FB99
+FB9A
+FB9B
+FB9C
+FB9D
+FB9E
+FB9F
+FBA0
+FBA1
+FBA2
+FBA3
+FBA4
+FBA5
+FBA6
+FBA7
+FBA8
+FBA9
+FBAA
+FBAB
+FBAC
+FBAD
+FBAE
+FBAF
+FBB0
+FBB1
+FBB2
+FBB3
+FBB4
+FBB5
+FBB6
+FBB7
+FBB8
+FBB9
+FBBA
+FBBB
+FBBC
+FBBD
+FBBE
+FBBF
+FBC0
+FBC1
+FBC2
+FBC3
+FBC4
+FBC5
+FBC6
+FBC7
+FBC8
+FBC9
+FBCA
+FBCB
+FBCC
+FBCD
+FBCE
+FBCF
+FBD0
+FBD1
+FBD2
+FBD3
+FBD4
+FBD5
+FBD6
+FBD7
+FBD8
+FBD9
+FBDA
+FBDB
+FBDC
+FBDD
+FBDE
+FBDF
+FBE0
+FBE1
+FBE2
+FBE3
+FBE4
+FBE5
+FBE6
+FBE7
+FBE8
+FBE9
+FBEA
+FBEB
+FBEC
+FBED
+FBEE
+FBEF
+FBF0
+FBF1
+FBF2
+FBF3
+FBF4
+FBF5
+FBF6
+FBF7
+FBF8
+FBF9
+FBFA
+FBFB
+FBFC
+FC40
+FC41
+FC42
+FC43
+FC44
+FC45
+FC46
+FC47
+FC48
+FC49
+FC4A
+FC4B
+F040
+F041
+F042
+F043
+F044
+F045
+F046
+F047
+F048
+F049
+F04A
+F04B
+F04C
+F04D
+F04E
+F04F
+F050
+F051
+F052
+F053
+F054
+F055
+F056
+F057
+F058
+F059
+F05A
+F05B
+F05C
+F05D
+F05E
+F05F
+F060
+F061
+F062
+F063
+F064
+F065
+F066
+F067
+F068
+F069
+F06A
+F06B
+F06C
+F06D
+F06E
+F06F
+F070
+F071
+F072
+F073
+F074
+F075
+F076
+F077
+F078
+F079
+F07A
+F07B
+F07C
+F07D
+F07E
+F080
+F081
+F082
+F083
+F084
+F085
+F086
+F087
+F088
+F089
+F08A
+F08B
+F08C
+F08D
+F08E
+F08F
+F090
+F091
+F092
+F093
+F094
+F095
+F096
+F097
+F098
+F099
+F09A
+F09B
+F09C
+F09D
+F09E
+F09F
+F0A0
+F0A1
+F0A2
+F0A3
+F0A4
+F0A5
+F0A6
+F0A7
+F0A8
+F0A9
+F0AA
+F0AB
+F0AC
+F0AD
+F0AE
+F0AF
+F0B0
+F0B1
+F0B2
+F0B3
+F0B4
+F0B5
+F0B6
+F0B7
+F0B8
+F0B9
+F0BA
+F0BB
+F0BC
+F0BD
+F0BE
+F0BF
+F0C0
+F0C1
+F0C2
+F0C3
+F0C4
+F0C5
+F0C6
+F0C7
+F0C8
+F0C9
+F0CA
+F0CB
+F0CC
+F0CD
+F0CE
+F0CF
+F0D0
+F0D1
+F0D2
+F0D3
+F0D4
+F0D5
+F0D6
+F0D7
+F0D8
+F0D9
+F0DA
+F0DB
+F0DC
+F0DD
+F0DE
+F0DF
+F0E0
+F0E1
+F0E2
+F0E3
+F0E4
+F0E5
+F0E6
+F0E7
+F0E8
+F0E9
+F0EA
+F0EB
+F0EC
+F0ED
+F0EE
+F0EF
+F0F0
+F0F1
+F0F2
+F0F3
+F0F4
+F0F5
+F0F6
+F0F7
+F0F8
+F0F9
+F0FA
+F0FB
+F0FC
+F140
+F141
+F142
+F143
+F144
+F145
+F146
+F147
+F148
+F149
+F14A
+F14B
+F14C
+F14D
+F14E
+F14F
+F150
+F151
+F152
+F153
+F154
+F155
+F156
+F157
+F158
+F159
+F15A
+F15B
+F15C
+F15D
+F15E
+F15F
+F160
+F161
+F162
+F163
+F164
+F165
+F166
+F167
+F168
+F169
+F16A
+F16B
+F16C
+F16D
+F16E
+F16F
+F170
+F171
+F172
+F173
+F174
+F175
+F176
+F177
+F178
+F179
+F17A
+F17B
+F17C
+F17D
+F17E
+F180
+F181
+F182
+F183
+F184
+F185
+F186
+F187
+F188
+F189
+F18A
+F18B
+F18C
+F18D
+F18E
+F18F
+F190
+F191
+F192
+F193
+F194
+F195
+F196
+F197
+F198
+F199
+F19A
+F19B
+F19C
+F19D
+F19E
+F19F
+F1A0
+F1A1
+F1A2
+F1A3
+F1A4
+F1A5
+F1A6
+F1A7
+F1A8
+F1A9
+F1AA
+F1AB
+F1AC
+F1AD
+F1AE
+F1AF
+F1B0
+F1B1
+F1B2
+F1B3
+F1B4
+F1B5
+F1B6
+F1B7
+F1B8
+F1B9
+F1BA
+F1BB
+F1BC
+F1BD
+F1BE
+F1BF
+F1C0
+F1C1
+F1C2
+F1C3
+F1C4
+F1C5
+F1C6
+F1C7
+F1C8
+F1C9
+F1CA
+F1CB
+F1CC
+F1CD
+F1CE
+F1CF
+F1D0
+F1D1
+F1D2
+F1D3
+F1D4
+F1D5
+F1D6
+F1D7
+F1D8
+F1D9
+F1DA
+F1DB
+F1DC
+F1DD
+F1DE
+F1DF
+F1E0
+F1E1
+F1E2
+F1E3
+F1E4
+F1E5
+F1E6
+F1E7
+F1E8
+F1E9
+F1EA
+F1EB
+F1EC
+F1ED
+F1EE
+F1EF
+F1F0
+F1F1
+F1F2
+F1F3
+F1F4
+F1F5
+F1F6
+F1F7
+F1F8
+F1F9
+F1FA
+F1FB
+F1FC
+F240
+F241
+F242
+F243
+F244
+F245
+F246
+F247
+F248
+F249
+F24A
+F24B
+F24C
+F24D
+F24E
+F24F
+F250
+F251
+F252
+F253
+F254
+F255
+F256
+F257
+F258
+F259
+F25A
+F25B
+F25C
+F25D
+F25E
+F25F
+F260
+F261
+F262
+F263
+F264
+F265
+F266
+F267
+F268
+F269
+F26A
+F26B
+F26C
+F26D
+F26E
+F26F
+F270
+F271
+F272
+F273
+F274
+F275
+F276
+F277
+F278
+F279
+F27A
+F27B
+F27C
+F27D
+F27E
+F280
+F281
+F282
+F283
+F284
+F285
+F286
+F287
+F288
+F289
+F28A
+F28B
+F28C
+F28D
+F28E
+F28F
+F290
+F291
+F292
+F293
+F294
+F295
+F296
+F297
+F298
+F299
+F29A
+F29B
+F29C
+F29D
+F29E
+F29F
+F2A0
+F2A1
+F2A2
+F2A3
+F2A4
+F2A5
+F2A6
+F2A7
+F2A8
+F2A9
+F2AA
+F2AB
+F2AC
+F2AD
+F2AE
+F2AF
+F2B0
+F2B1
+F2B2
+F2B3
+F2B4
+F2B5
+F2B6
+F2B7
+F2B8
+F2B9
+F2BA
+F2BB
+F2BC
+F2BD
+F2BE
+F2BF
+F2C0
+F2C1
+F2C2
+F2C3
+F2C4
+F2C5
+F2C6
+F2C7
+F2C8
+F2C9
+F2CA
+F2CB
+F2CC
+F2CD
+F2CE
+F2CF
+F2D0
+F2D1
+F2D2
+F2D3
+F2D4
+F2D5
+F2D6
+F2D7
+F2D8
+F2D9
+F2DA
+F2DB
+F2DC
+F2DD
+F2DE
+F2DF
+F2E0
+F2E1
+F2E2
+F2E3
+F2E4
+F2E5
+F2E6
+F2E7
+F2E8
+F2E9
+F2EA
+F2EB
+F2EC
+F2ED
+F2EE
+F2EF
+F2F0
+F2F1
+F2F2
+F2F3
+F2F4
+F2F5
+F2F6
+F2F7
+F2F8
+F2F9
+F2FA
+F2FB
+F2FC
+F340
+F341
+F342
+F343
+F344
+F345
+F346
+F347
+F348
+F349
+F34A
+F34B
+F34C
+F34D
+F34E
+F34F
+F350
+F351
+F352
+F353
+F354
+F355
+F356
+F357
+F358
+F359
+F35A
+F35B
+F35C
+F35D
+F35E
+F35F
+F360
+F361
+F362
+F363
+F364
+F365
+F366
+F367
+F368
+F369
+F36A
+F36B
+F36C
+F36D
+F36E
+F36F
+F370
+F371
+F372
+F373
+F374
+F375
+F376
+F377
+F378
+F379
+F37A
+F37B
+F37C
+F37D
+F37E
+F380
+F381
+F382
+F383
+F384
+F385
+F386
+F387
+F388
+F389
+F38A
+F38B
+F38C
+F38D
+F38E
+F38F
+F390
+F391
+F392
+F393
+F394
+F395
+F396
+F397
+F398
+F399
+F39A
+F39B
+F39C
+F39D
+F39E
+F39F
+F3A0
+F3A1
+F3A2
+F3A3
+F3A4
+F3A5
+F3A6
+F3A7
+F3A8
+F3A9
+F3AA
+F3AB
+F3AC
+F3AD
+F3AE
+F3AF
+F3B0
+F3B1
+F3B2
+F3B3
+F3B4
+F3B5
+F3B6
+F3B7
+F3B8
+F3B9
+F3BA
+F3BB
+F3BC
+F3BD
+F3BE
+F3BF
+F3C0
+F3C1
+F3C2
+F3C3
+F3C4
+F3C5
+F3C6
+F3C7
+F3C8
+F3C9
+F3CA
+F3CB
+F3CC
+F3CD
+F3CE
+F3CF
+F3D0
+F3D1
+F3D2
+F3D3
+F3D4
+F3D5
+F3D6
+F3D7
+F3D8
+F3D9
+F3DA
+F3DB
+F3DC
+F3DD
+F3DE
+F3DF
+F3E0
+F3E1
+F3E2
+F3E3
+F3E4
+F3E5
+F3E6
+F3E7
+F3E8
+F3E9
+F3EA
+F3EB
+F3EC
+F3ED
+F3EE
+F3EF
+F3F0
+F3F1
+F3F2
+F3F3
+F3F4
+F3F5
+F3F6
+F3F7
+F3F8
+F3F9
+F3FA
+F3FB
+F3FC
+F440
+F441
+F442
+F443
+F444
+F445
+F446
+F447
+F448
+F449
+F44A
+F44B
+F44C
+F44D
+F44E
+F44F
+F450
+F451
+F452
+F453
+F454
+F455
+F456
+F457
+F458
+F459
+F45A
+F45B
+F45C
+F45D
+F45E
+F45F
+F460
+F461
+F462
+F463
+F464
+F465
+F466
+F467
+F468
+F469
+F46A
+F46B
+F46C
+F46D
+F46E
+F46F
+F470
+F471
+F472
+F473
+F474
+F475
+F476
+F477
+F478
+F479
+F47A
+F47B
+F47C
+F47D
+F47E
+F480
+F481
+F482
+F483
+F484
+F485
+F486
+F487
+F488
+F489
+F48A
+F48B
+F48C
+F48D
+F48E
+F48F
+F490
+F491
+F492
+F493
+F494
+F495
+F496
+F497
+F498
+F499
+F49A
+F49B
+F49C
+F49D
+F49E
+F49F
+F4A0
+F4A1
+F4A2
+F4A3
+F4A4
+F4A5
+F4A6
+F4A7
+F4A8
+F4A9
+F4AA
+F4AB
+F4AC
+F4AD
+F4AE
+F4AF
+F4B0
+F4B1
+F4B2
+F4B3
+F4B4
+F4B5
+F4B6
+F4B7
+F4B8
+F4B9
+F4BA
+F4BB
+F4BC
+F4BD
+F4BE
+F4BF
+F4C0
+F4C1
+F4C2
+F4C3
+F4C4
+F4C5
+F4C6
+F4C7
+F4C8
+F4C9
+F4CA
+F4CB
+F4CC
+F4CD
+F4CE
+F4CF
+F4D0
+F4D1
+F4D2
+F4D3
+F4D4
+F4D5
+F4D6
+F4D7
+F4D8
+F4D9
+F4DA
+F4DB
+F4DC
+F4DD
+F4DE
+F4DF
+F4E0
+F4E1
+F4E2
+F4E3
+F4E4
+F4E5
+F4E6
+F4E7
+F4E8
+F4E9
+F4EA
+F4EB
+F4EC
+F4ED
+F4EE
+F4EF
+F4F0
+F4F1
+F4F2
+F4F3
+F4F4
+F4F5
+F4F6
+F4F7
+F4F8
+F4F9
+F4FA
+F4FB
+F4FC
+F540
+F541
+F542
+F543
+F544
+F545
+F546
+F547
+F548
+F549
+F54A
+F54B
+F54C
+F54D
+F54E
+F54F
+F550
+F551
+F552
+F553
+F554
+F555
+F556
+F557
+F558
+F559
+F55A
+F55B
+F55C
+F55D
+F55E
+F55F
+F560
+F561
+F562
+F563
+F564
+F565
+F566
+F567
+F568
+F569
+F56A
+F56B
+F56C
+F56D
+F56E
+F56F
+F570
+F571
+F572
+F573
+F574
+F575
+F576
+F577
+F578
+F579
+F57A
+F57B
+F57C
+F57D
+F57E
+F580
+F581
+F582
+F583
+F584
+F585
+F586
+F587
+F588
+F589
+F58A
+F58B
+F58C
+F58D
+F58E
+F58F
+F590
+F591
+F592
+F593
+F594
+F595
+F596
+F597
+F598
+F599
+F59A
+F59B
+F59C
+F59D
+F59E
+F59F
+F5A0
+F5A1
+F5A2
+F5A3
+F5A4
+F5A5
+F5A6
+F5A7
+F5A8
+F5A9
+F5AA
+F5AB
+F5AC
+F5AD
+F5AE
+F5AF
+F5B0
+F5B1
+F5B2
+F5B3
+F5B4
+F5B5
+F5B6
+F5B7
+F5B8
+F5B9
+F5BA
+F5BB
+F5BC
+F5BD
+F5BE
+F5BF
+F5C0
+F5C1
+F5C2
+F5C3
+F5C4
+F5C5
+F5C6
+F5C7
+F5C8
+F5C9
+F5CA
+F5CB
+F5CC
+F5CD
+F5CE
+F5CF
+F5D0
+F5D1
+F5D2
+F5D3
+F5D4
+F5D5
+F5D6
+F5D7
+F5D8
+F5D9
+F5DA
+F5DB
+F5DC
+F5DD
+F5DE
+F5DF
+F5E0
+F5E1
+F5E2
+F5E3
+F5E4
+F5E5
+F5E6
+F5E7
+F5E8
+F5E9
+F5EA
+F5EB
+F5EC
+F5ED
+F5EE
+F5EF
+F5F0
+F5F1
+F5F2
+F5F3
+F5F4
+F5F5
+F5F6
+F5F7
+F5F8
+F5F9
+F5FA
+F5FB
+F5FC
+F640
+F641
+F642
+F643
+F644
+F645
+F646
+F647
+F648
+F649
+F64A
+F64B
+F64C
+F64D
+F64E
+F64F
+F650
+F651
+F652
+F653
+F654
+F655
+F656
+F657
+F658
+F659
+F65A
+F65B
+F65C
+F65D
+F65E
+F65F
+F660
+F661
+F662
+F663
+F664
+F665
+F666
+F667
+F668
+F669
+F66A
+F66B
+F66C
+F66D
+F66E
+F66F
+F670
+F671
+F672
+F673
+F674
+F675
+F676
+F677
+F678
+F679
+F67A
+F67B
+F67C
+F67D
+F67E
+F680
+F681
+F682
+F683
+F684
+F685
+F686
+F687
+F688
+F689
+F68A
+F68B
+F68C
+F68D
+F68E
+F68F
+F690
+F691
+F692
+F693
+F694
+F695
+F696
+F697
+F698
+F699
+F69A
+F69B
+F69C
+F69D
+F69E
+F69F
+F6A0
+F6A1
+F6A2
+F6A3
+F6A4
+F6A5
+F6A6
+F6A7
+F6A8
+F6A9
+F6AA
+F6AB
+F6AC
+F6AD
+F6AE
+F6AF
+F6B0
+F6B1
+F6B2
+F6B3
+F6B4
+F6B5
+F6B6
+F6B7
+F6B8
+F6B9
+F6BA
+F6BB
+F6BC
+F6BD
+F6BE
+F6BF
+F6C0
+F6C1
+F6C2
+F6C3
+F6C4
+F6C5
+F6C6
+F6C7
+F6C8
+F6C9
+F6CA
+F6CB
+F6CC
+F6CD
+F6CE
+F6CF
+F6D0
+F6D1
+F6D2
+F6D3
+F6D4
+F6D5
+F6D6
+F6D7
+F6D8
+F6D9
+F6DA
+F6DB
+F6DC
+F6DD
+F6DE
+F6DF
+F6E0
+F6E1
+F6E2
+F6E3
+F6E4
+F6E5
+F6E6
+F6E7
+F6E8
+F6E9
+F6EA
+F6EB
+F6EC
+F6ED
+F6EE
+F6EF
+F6F0
+F6F1
+F6F2
+F6F3
+F6F4
+F6F5
+F6F6
+F6F7
+F6F8
+F6F9
+F6FA
+F6FB
+F6FC
+F740
+F741
+F742
+F743
+F744
+F745
+F746
+F747
+F748
+F749
+F74A
+F74B
+F74C
+F74D
+F74E
+F74F
+F750
+F751
+F752
+F753
+F754
+F755
+F756
+F757
+F758
+F759
+F75A
+F75B
+F75C
+F75D
+F75E
+F75F
+F760
+F761
+F762
+F763
+F764
+F765
+F766
+F767
+F768
+F769
+F76A
+F76B
+F76C
+F76D
+F76E
+F76F
+F770
+F771
+F772
+F773
+F774
+F775
+F776
+F777
+F778
+F779
+F77A
+F77B
+F77C
+F77D
+F77E
+F780
+F781
+F782
+F783
+F784
+F785
+F786
+F787
+F788
+F789
+F78A
+F78B
+F78C
+F78D
+F78E
+F78F
+F790
+F791
+F792
+F793
+F794
+F795
+F796
+F797
+F798
+F799
+F79A
+F79B
+F79C
+F79D
+F79E
+F79F
+F7A0
+F7A1
+F7A2
+F7A3
+F7A4
+F7A5
+F7A6
+F7A7
+F7A8
+F7A9
+F7AA
+F7AB
+F7AC
+F7AD
+F7AE
+F7AF
+F7B0
+F7B1
+F7B2
+F7B3
+F7B4
+F7B5
+F7B6
+F7B7
+F7B8
+F7B9
+F7BA
+F7BB
+F7BC
+F7BD
+F7BE
+F7BF
+F7C0
+F7C1
+F7C2
+F7C3
+F7C4
+F7C5
+F7C6
+F7C7
+F7C8
+F7C9
+F7CA
+F7CB
+F7CC
+F7CD
+F7CE
+F7CF
+F7D0
+F7D1
+F7D2
+F7D3
+F7D4
+F7D5
+F7D6
+F7D7
+F7D8
+F7D9
+F7DA
+F7DB
+F7DC
+F7DD
+F7DE
+F7DF
+F7E0
+F7E1
+F7E2
+F7E3
+F7E4
+F7E5
+F7E6
+F7E7
+F7E8
+F7E9
+F7EA
+F7EB
+F7EC
+F7ED
+F7EE
+F7EF
+F7F0
+F7F1
+F7F2
+F7F3
+F7F4
+F7F5
+F7F6
+F7F7
+F7F8
+F7F9
+F7FA
+F7FB
+F7FC
+F840
+F841
+F842
+F843
+F844
+F845
+F846
+F847
+F848
+F849
+F84A
+F84B
+F84C
+F84D
+F84E
+F84F
+F850
+F851
+F852
+F853
+F854
+F855
+F856
+F857
+F858
+F859
+F85A
+F85B
+F85C
+F85D
+F85E
+F85F
+F860
+F861
+F862
+F863
+F864
+F865
+F866
+F867
+F868
+F869
+F86A
+F86B
+F86C
+F86D
+F86E
+F86F
+F870
+F871
+F872
+F873
+F874
+F875
+F876
+F877
+F878
+F879
+F87A
+F87B
+F87C
+F87D
+F87E
+F880
+F881
+F882
+F883
+F884
+F885
+F886
+F887
+F888
+F889
+F88A
+F88B
+F88C
+F88D
+F88E
+F88F
+F890
+F891
+F892
+F893
+F894
+F895
+F896
+F897
+F898
+F899
+F89A
+F89B
+F89C
+F89D
+F89E
+F89F
+F8A0
+F8A1
+F8A2
+F8A3
+F8A4
+F8A5
+F8A6
+F8A7
+F8A8
+F8A9
+F8AA
+F8AB
+F8AC
+F8AD
+F8AE
+F8AF
+F8B0
+F8B1
+F8B2
+F8B3
+F8B4
+F8B5
+F8B6
+F8B7
+F8B8
+F8B9
+F8BA
+F8BB
+F8BC
+F8BD
+F8BE
+F8BF
+F8C0
+F8C1
+F8C2
+F8C3
+F8C4
+F8C5
+F8C6
+F8C7
+F8C8
+F8C9
+F8CA
+F8CB
+F8CC
+F8CD
+F8CE
+F8CF
+F8D0
+F8D1
+F8D2
+F8D3
+F8D4
+F8D5
+F8D6
+F8D7
+F8D8
+F8D9
+F8DA
+F8DB
+F8DC
+F8DD
+F8DE
+F8DF
+F8E0
+F8E1
+F8E2
+F8E3
+F8E4
+F8E5
+F8E6
+F8E7
+F8E8
+F8E9
+F8EA
+F8EB
+F8EC
+F8ED
+F8EE
+F8EF
+F8F0
+F8F1
+F8F2
+F8F3
+F8F4
+F8F5
+F8F6
+F8F7
+F8F8
+F8F9
+F8FA
+F8FB
+F8FC
+F940
+F941
+F942
+F943
+F944
+F945
+F946
+F947
+F948
+F949
+F94A
+F94B
+F94C
+F94D
+F94E
+F94F
+F950
+F951
+F952
+F953
+F954
+F955
+F956
+F957
+F958
+F959
+F95A
+F95B
+F95C
+F95D
+F95E
+F95F
+F960
+F961
+F962
+F963
+F964
+F965
+F966
+F967
+F968
+F969
+F96A
+F96B
+F96C
+F96D
+F96E
+F96F
+F970
+F971
+F972
+F973
+F974
+F975
+F976
+F977
+F978
+F979
+F97A
+F97B
+F97C
+F97D
+F97E
+F980
+F981
+F982
+F983
+F984
+F985
+F986
+F987
+F988
+F989
+F98A
+F98B
+F98C
+F98D
+F98E
+F98F
+F990
+F991
+F992
+F993
+F994
+F995
+F996
+F997
+F998
+F999
+F99A
+F99B
+F99C
+F99D
+F99E
+F99F
+F9A0
+F9A1
+F9A2
+F9A3
+F9A4
+F9A5
+F9A6
+F9A7
+F9A8
+F9A9
+F9AA
+F9AB
+F9AC
+F9AD
+F9AE
+F9AF
+F9B0
+F9B1
+F9B2
+F9B3
+F9B4
+F9B5
+F9B6
+F9B7
+F9B8
+F9B9
+F9BA
+F9BB
+F9BC
+F9BD
+F9BE
+F9BF
+F9C0
+F9C1
+F9C2
+F9C3
+F9C4
+F9C5
+F9C6
+F9C7
+F9C8
+F9C9
+F9CA
+F9CB
+F9CC
+F9CD
+F9CE
+F9CF
+F9D0
+F9D1
+F9D2
+F9D3
+F9D4
+F9D5
+F9D6
+F9D7
+F9D8
+F9D9
+F9DA
+F9DB
+F9DC
+F9DD
+F9DE
+F9DF
+F9E0
+F9E1
+F9E2
+F9E3
+F9E4
+F9E5
+F9E6
+F9E7
+F9E8
+F9E9
+F9EA
+F9EB
+F9EC
+F9ED
+F9EE
+F9EF
+F9F0
+F9F1
+F9F2
+F9F3
+F9F4
+F9F5
+F9F6
+F9F7
+F9F8
+F9F9
+F9FA
+F9FB
+F9FC
+CREATE TABLE t4 SELECT CONVERT(c1 USING eucjpms) AS c1 FROM t1;
+SELECT HEX(c1) FROM t4;
+HEX(c1)
+05
+7E
+A1BD
+A1C0
+A1C1
+A1C2
+A1DD
+A1F1
+A1F2
+A2CC
+ADA1
+ADA2
+ADA3
+ADA4
+ADA5
+ADA6
+ADA7
+ADA8
+ADA9
+ADAA
+ADAB
+ADAC
+ADAD
+ADAE
+ADAF
+ADB0
+ADB1
+ADB2
+ADB3
+ADB4
+ADB5
+ADB6
+ADB7
+ADB8
+ADB9
+ADBA
+ADBB
+ADBC
+ADBD
+ADBE
+ADC0
+ADC1
+ADC2
+ADC3
+ADC4
+ADC5
+ADC6
+ADC7
+ADC8
+ADC9
+ADCA
+ADCB
+ADCC
+ADCD
+ADCE
+ADCF
+ADD0
+ADD1
+ADD2
+ADD3
+ADD4
+ADD5
+ADD6
+ADDF
+ADE0
+ADE1
+ADE2
+ADE3
+ADE4
+ADE5
+ADE6
+ADE7
+ADE8
+ADE9
+ADEA
+ADEB
+ADEC
+ADED
+ADEE
+ADEF
+A2E2
+A2E1
+A2E9
+ADF3
+ADF4
+A2E5
+A2DD
+A2DC
+ADF8
+ADF9
+A2E8
+A2C1
+A2C0
+8FD4E3
+8FDCDF
+8FE4E9
+8FE3F8
+8FD9A1
+8FB1BB
+8FF4AE
+8FC2AD
+8FC3FC
+8FE4D0
+8FC2BF
+8FBCF4
+8FB0A9
+8FB0C8
+8FF4AF
+8FB0D2
+8FB0D4
+8FB0E3
+8FB0EE
+8FB1A7
+8FB1A3
+8FB1AC
+8FB1A9
+8FB1BE
+8FB1DF
+8FB1D8
+8FB1C8
+8FB1D7
+8FB1E3
+8FB1F4
+8FB1E1
+8FB2A3
+8FF4B0
+8FB2BB
+8FB2E6
+8FB2ED
+8FB2F5
+8FB2FC
+8FF4B1
+8FB3B5
+8FB3D8
+8FB3DB
+8FB3E5
+8FB3EE
+8FB3FB
+8FF4B2
+8FF4B3
+8FB4C0
+8FB4C7
+8FB4D0
+8FB4DE
+8FF4B4
+8FB5AA
+8FF4B5
+8FB5AF
+8FB5C4
+8FB5E8
+8FF4B6
+8FB7C2
+8FB7E4
+8FB7E8
+8FB7E7
+8FF4B7
+8FF4B8
+8FF4B9
+8FB8CE
+8FB8E1
+8FB8F5
+8FB8F7
+8FB8F8
+8FB8FC
+8FB9AF
+8FB9B7
+8FBABE
+8FBADB
+8FCDAA
+8FBAE1
+8FF4BA
+8FBAEB
+8FBBB3
+8FBBB8
+8FF4BB
+8FBBCA
+8FF4BC
+8FF4BD
+8FBBD0
+8FBBDE
+8FBBF4
+8FBBF5
+8FBBF9
+8FBCE4
+8FBCED
+8FBCFE
+8FF4BE
+8FBDC2
+8FBDE7
+8FF4BF
+8FBDF0
+8FBEB0
+8FBEAC
+8FF4C0
+8FBEB3
+8FBEBD
+8FBECD
+8FBEC9
+8FBEE4
+8FBFA8
+8FBFC9
+8FC0C4
+8FC0E4
+8FC0F4
+8FC1A6
+8FF4C1
+8FC1F5
+8FC1FC
+8FF4C2
+8FC1F8
+8FC2AB
+8FC2A1
+8FC2A5
+8FF4C3
+8FC2B8
+8FC2BA
+8FF4C4
+8FC2C4
+8FC2D2
+8FC2D7
+8FC2DB
+8FC2DE
+8FC2ED
+8FC2F0
+8FF4C5
+8FC3A1
+8FC3B5
+8FC3C9
+8FC3B9
+8FF4C6
+8FC3D8
+8FC3FE
+8FF4C7
+8FC4CC
+8FF4C8
+8FC4D9
+8FC4EA
+8FC4FD
+8FF4C9
+8FC5A7
+8FC5B5
+8FC5B6
+8FF4CA
+8FC5D5
+8FC6B8
+8FC6D7
+8FC6E0
+8FC6EA
+8FC6E3
+8FC7A1
+8FC7AB
+8FC7C7
+8FC7C3
+8FC7CB
+8FC7CF
+8FC7D9
+8FF4CB
+8FF4CC
+8FC7E6
+8FC7EE
+8FC7FC
+8FC7EB
+8FC7F0
+8FC8B1
+8FC8E5
+8FC8F8
+8FC9A6
+8FC9AB
+8FC9AD
+8FF4CD
+8FC9CA
+8FC9D3
+8FC9E9
+8FC9E3
+8FC9FC
+8FC9F4
+8FC9F5
+8FF4CE
+8FCAB3
+8FCABD
+8FCAEF
+8FCAF1
+8FCBAE
+8FF4CF
+8FCBCA
+8FCBE6
+8FCBEA
+8FCBF0
+8FCBF4
+8FCBEE
+8FCCA5
+8FCBF9
+8FCCAB
+8FCCAE
+8FCCAD
+8FCCB2
+8FCCC2
+8FCCD0
+8FCCD9
+8FF4D0
+8FCDBB
+8FF4D1
+8FCEBB
+8FF4D2
+8FCEBA
+8FCEC3
+8FF4D3
+8FCEF2
+8FB3DD
+8FCFD5
+8FCFE2
+8FCFE9
+8FCFED
+8FF4D4
+8FF4D5
+8FF4D6
+8FF4D7
+8FD0E5
+8FF4D8
+8FD0E9
+8FD1E8
+8FF4D9
+8FF4DA
+8FD1EC
+8FD2BB
+8FF4DB
+8FD3E1
+8FD3E8
+8FD4A7
+8FF4DC
+8FF4DD
+8FD4D4
+8FD4F2
+8FD5AE
+8FF4DE
+8FD7DE
+8FF4DF
+8FD8A2
+8FD8B7
+8FD8C1
+8FD8D1
+8FD8F4
+8FD9C6
+8FD9C8
+8FD9D1
+8FF4E0
+8FF4E1
+8FF4E2
+8FF4E3
+8FF4E4
+8FDCD3
+8FDDC8
+8FDDD4
+8FDDEA
+8FDDFA
+8FDEA4
+8FDEB0
+8FF4E5
+8FDEB5
+8FDECB
+8FF4E6
+8FDFB9
+8FF4E7
+8FDFC3
+8FF4E8
+8FF4E9
+8FE0D9
+8FF4EA
+8FF4EB
+8FE1E2
+8FF4EC
+8FF4ED
+8FF4EE
+8FE2C7
+8FE3A8
+8FE3A6
+8FE3A9
+8FE3AF
+8FE3B0
+8FE3AA
+8FE3AB
+8FE3BC
+8FE3C1
+8FE3BF
+8FE3D5
+8FE3D8
+8FE3D6
+8FE3DF
+8FE3E3
+8FE3E1
+8FE3D4
+8FE3E9
+8FE4A6
+8FE3F1
+8FE3F2
+8FE4CB
+8FE4C1
+8FE4C3
+8FE4BE
+8FF4EF
+8FE4C0
+8FE4C7
+8FE4BF
+8FE4E0
+8FE4DE
+8FE4D1
+8FF4F0
+8FE4DC
+8FE4D2
+8FE4DB
+8FE4D4
+8FE4FA
+8FE4EF
+8FE5B3
+8FE5BF
+8FE5C9
+8FE5D0
+8FE5E2
+8FE5EA
+8FE5EB
+8FF4F1
+8FF4F2
+8FF4F3
+8FE6E8
+8FE6EF
+8FE7AC
+8FF4F4
+8FE7AE
+8FF4F5
+8FE7B1
+8FF4F6
+8FE7B2
+8FE8B1
+8FE8B6
+8FF4F7
+8FF4F8
+8FE8DD
+8FF4F9
+8FF4FA
+8FE9D1
+8FF4FB
+8FE9ED
+8FEACD
+8FF4FC
+8FEADB
+8FEAE6
+8FEAEA
+8FEBA5
+8FEBFB
+8FEBFA
+8FF4FD
+8FECD6
+8FF4FE
+8FF3F3
+8FF3F4
+8FF3F5
+8FF3F6
+8FF3F7
+8FF3F8
+8FF3F9
+8FF3FA
+8FF3FB
+8FF3FC
+A2CC
+8FA2C3
+8FF4A9
+8FF4AA
+8FF3F3
+8FF3F4
+8FF3F5
+8FF3F6
+8FF3F7
+8FF3F8
+8FF3F9
+8FF3FA
+8FF3FB
+8FF3FC
+ADB5
+ADB6
+ADB7
+ADB8
+ADB9
+ADBA
+ADBB
+ADBC
+ADBD
+ADBE
+A2CC
+8FA2C3
+8FF4A9
+8FF4AA
+ADEA
+ADE2
+ADE4
+A2E8
+8FD4E3
+8FDCDF
+8FE4E9
+8FE3F8
+8FD9A1
+8FB1BB
+8FF4AE
+8FC2AD
+8FC3FC
+8FE4D0
+8FC2BF
+8FBCF4
+8FB0A9
+8FB0C8
+8FF4AF
+8FB0D2
+8FB0D4
+8FB0E3
+8FB0EE
+8FB1A7
+8FB1A3
+8FB1AC
+8FB1A9
+8FB1BE
+8FB1DF
+8FB1D8
+8FB1C8
+8FB1D7
+8FB1E3
+8FB1F4
+8FB1E1
+8FB2A3
+8FF4B0
+8FB2BB
+8FB2E6
+8FB2ED
+8FB2F5
+8FB2FC
+8FF4B1
+8FB3B5
+8FB3D8
+8FB3DB
+8FB3E5
+8FB3EE
+8FB3FB
+8FF4B2
+8FF4B3
+8FB4C0
+8FB4C7
+8FB4D0
+8FB4DE
+8FF4B4
+8FB5AA
+8FF4B5
+8FB5AF
+8FB5C4
+8FB5E8
+8FF4B6
+8FB7C2
+8FB7E4
+8FB7E8
+8FB7E7
+8FF4B7
+8FF4B8
+8FF4B9
+8FB8CE
+8FB8E1
+8FB8F5
+8FB8F7
+8FB8F8
+8FB8FC
+8FB9AF
+8FB9B7
+8FBABE
+8FBADB
+8FCDAA
+8FBAE1
+8FF4BA
+8FBAEB
+8FBBB3
+8FBBB8
+8FF4BB
+8FBBCA
+8FF4BC
+8FF4BD
+8FBBD0
+8FBBDE
+8FBBF4
+8FBBF5
+8FBBF9
+8FBCE4
+8FBCED
+8FBCFE
+8FF4BE
+8FBDC2
+8FBDE7
+8FF4BF
+8FBDF0
+8FBEB0
+8FBEAC
+8FF4C0
+8FBEB3
+8FBEBD
+8FBECD
+8FBEC9
+8FBEE4
+8FBFA8
+8FBFC9
+8FC0C4
+8FC0E4
+8FC0F4
+8FC1A6
+8FF4C1
+8FC1F5
+8FC1FC
+8FF4C2
+8FC1F8
+8FC2AB
+8FC2A1
+8FC2A5
+8FF4C3
+8FC2B8
+8FC2BA
+8FF4C4
+8FC2C4
+8FC2D2
+8FC2D7
+8FC2DB
+8FC2DE
+8FC2ED
+8FC2F0
+8FF4C5
+8FC3A1
+8FC3B5
+8FC3C9
+8FC3B9
+8FF4C6
+8FC3D8
+8FC3FE
+8FF4C7
+8FC4CC
+8FF4C8
+8FC4D9
+8FC4EA
+8FC4FD
+8FF4C9
+8FC5A7
+8FC5B5
+8FC5B6
+8FF4CA
+8FC5D5
+8FC6B8
+8FC6D7
+8FC6E0
+8FC6EA
+8FC6E3
+8FC7A1
+8FC7AB
+8FC7C7
+8FC7C3
+8FC7CB
+8FC7CF
+8FC7D9
+8FF4CB
+8FF4CC
+8FC7E6
+8FC7EE
+8FC7FC
+8FC7EB
+8FC7F0
+8FC8B1
+8FC8E5
+8FC8F8
+8FC9A6
+8FC9AB
+8FC9AD
+8FF4CD
+8FC9CA
+8FC9D3
+8FC9E9
+8FC9E3
+8FC9FC
+8FC9F4
+8FC9F5
+8FF4CE
+8FCAB3
+8FCABD
+8FCAEF
+8FCAF1
+8FCBAE
+8FF4CF
+8FCBCA
+8FCBE6
+8FCBEA
+8FCBF0
+8FCBF4
+8FCBEE
+8FCCA5
+8FCBF9
+8FCCAB
+8FCCAE
+8FCCAD
+8FCCB2
+8FCCC2
+8FCCD0
+8FCCD9
+8FF4D0
+8FCDBB
+8FF4D1
+8FCEBB
+8FF4D2
+8FCEBA
+8FCEC3
+8FF4D3
+8FCEF2
+8FB3DD
+8FCFD5
+8FCFE2
+8FCFE9
+8FCFED
+8FF4D4
+8FF4D5
+8FF4D6
+8FF4D7
+8FD0E5
+8FF4D8
+8FD0E9
+8FD1E8
+8FF4D9
+8FF4DA
+8FD1EC
+8FD2BB
+8FF4DB
+8FD3E1
+8FD3E8
+8FD4A7
+8FF4DC
+8FF4DD
+8FD4D4
+8FD4F2
+8FD5AE
+8FF4DE
+8FD7DE
+8FF4DF
+8FD8A2
+8FD8B7
+8FD8C1
+8FD8D1
+8FD8F4
+8FD9C6
+8FD9C8
+8FD9D1
+8FF4E0
+8FF4E1
+8FF4E2
+8FF4E3
+8FF4E4
+8FDCD3
+8FDDC8
+8FDDD4
+8FDDEA
+8FDDFA
+8FDEA4
+8FDEB0
+8FF4E5
+8FDEB5
+8FDECB
+8FF4E6
+8FDFB9
+8FF4E7
+8FDFC3
+8FF4E8
+8FF4E9
+8FE0D9
+8FF4EA
+8FF4EB
+8FE1E2
+8FF4EC
+8FF4ED
+8FF4EE
+8FE2C7
+8FE3A8
+8FE3A6
+8FE3A9
+8FE3AF
+8FE3B0
+8FE3AA
+8FE3AB
+8FE3BC
+8FE3C1
+8FE3BF
+8FE3D5
+8FE3D8
+8FE3D6
+8FE3DF
+8FE3E3
+8FE3E1
+8FE3D4
+8FE3E9
+8FE4A6
+8FE3F1
+8FE3F2
+8FE4CB
+8FE4C1
+8FE4C3
+8FE4BE
+8FF4EF
+8FE4C0
+8FE4C7
+8FE4BF
+8FE4E0
+8FE4DE
+8FE4D1
+8FF4F0
+8FE4DC
+8FE4D2
+8FE4DB
+8FE4D4
+8FE4FA
+8FE4EF
+8FE5B3
+8FE5BF
+8FE5C9
+8FE5D0
+8FE5E2
+8FE5EA
+8FE5EB
+8FF4F1
+8FF4F2
+8FF4F3
+8FE6E8
+8FE6EF
+8FE7AC
+8FF4F4
+8FE7AE
+8FF4F5
+8FE7B1
+8FF4F6
+8FE7B2
+8FE8B1
+8FE8B6
+8FF4F7
+8FF4F8
+8FE8DD
+8FF4F9
+8FF4FA
+8FE9D1
+8FF4FB
+8FE9ED
+8FEACD
+8FF4FC
+8FEADB
+8FEAE6
+8FEAEA
+8FEBA5
+8FEBFB
+8FEBFA
+8FF4FD
+8FECD6
+8FF4FE
+F5A1
+F5A2
+F5A3
+F5A4
+F5A5
+F5A6
+F5A7
+F5A8
+F5A9
+F5AA
+F5AB
+F5AC
+F5AD
+F5AE
+F5AF
+F5B0
+F5B1
+F5B2
+F5B3
+F5B4
+F5B5
+F5B6
+F5B7
+F5B8
+F5B9
+F5BA
+F5BB
+F5BC
+F5BD
+F5BE
+F5BF
+F5C0
+F5C1
+F5C2
+F5C3
+F5C4
+F5C5
+F5C6
+F5C7
+F5C8
+F5C9
+F5CA
+F5CB
+F5CC
+F5CD
+F5CE
+F5CF
+F5D0
+F5D1
+F5D2
+F5D3
+F5D4
+F5D5
+F5D6
+F5D7
+F5D8
+F5D9
+F5DA
+F5DB
+F5DC
+F5DD
+F5DE
+F5DF
+F5E0
+F5E1
+F5E2
+F5E3
+F5E4
+F5E5
+F5E6
+F5E7
+F5E8
+F5E9
+F5EA
+F5EB
+F5EC
+F5ED
+F5EE
+F5EF
+F5F0
+F5F1
+F5F2
+F5F3
+F5F4
+F5F5
+F5F6
+F5F7
+F5F8
+F5F9
+F5FA
+F5FB
+F5FC
+F5FD
+F5FE
+F6A1
+F6A2
+F6A3
+F6A4
+F6A5
+F6A6
+F6A7
+F6A8
+F6A9
+F6AA
+F6AB
+F6AC
+F6AD
+F6AE
+F6AF
+F6B0
+F6B1
+F6B2
+F6B3
+F6B4
+F6B5
+F6B6
+F6B7
+F6B8
+F6B9
+F6BA
+F6BB
+F6BC
+F6BD
+F6BE
+F6BF
+F6C0
+F6C1
+F6C2
+F6C3
+F6C4
+F6C5
+F6C6
+F6C7
+F6C8
+F6C9
+F6CA
+F6CB
+F6CC
+F6CD
+F6CE
+F6CF
+F6D0
+F6D1
+F6D2
+F6D3
+F6D4
+F6D5
+F6D6
+F6D7
+F6D8
+F6D9
+F6DA
+F6DB
+F6DC
+F6DD
+F6DE
+F6DF
+F6E0
+F6E1
+F6E2
+F6E3
+F6E4
+F6E5
+F6E6
+F6E7
+F6E8
+F6E9
+F6EA
+F6EB
+F6EC
+F6ED
+F6EE
+F6EF
+F6F0
+F6F1
+F6F2
+F6F3
+F6F4
+F6F5
+F6F6
+F6F7
+F6F8
+F6F9
+F6FA
+F6FB
+F6FC
+F6FD
+F6FE
+F7A1
+F7A2
+F7A3
+F7A4
+F7A5
+F7A6
+F7A7
+F7A8
+F7A9
+F7AA
+F7AB
+F7AC
+F7AD
+F7AE
+F7AF
+F7B0
+F7B1
+F7B2
+F7B3
+F7B4
+F7B5
+F7B6
+F7B7
+F7B8
+F7B9
+F7BA
+F7BB
+F7BC
+F7BD
+F7BE
+F7BF
+F7C0
+F7C1
+F7C2
+F7C3
+F7C4
+F7C5
+F7C6
+F7C7
+F7C8
+F7C9
+F7CA
+F7CB
+F7CC
+F7CD
+F7CE
+F7CF
+F7D0
+F7D1
+F7D2
+F7D3
+F7D4
+F7D5
+F7D6
+F7D7
+F7D8
+F7D9
+F7DA
+F7DB
+F7DC
+F7DD
+F7DE
+F7DF
+F7E0
+F7E1
+F7E2
+F7E3
+F7E4
+F7E5
+F7E6
+F7E7
+F7E8
+F7E9
+F7EA
+F7EB
+F7EC
+F7ED
+F7EE
+F7EF
+F7F0
+F7F1
+F7F2
+F7F3
+F7F4
+F7F5
+F7F6
+F7F7
+F7F8
+F7F9
+F7FA
+F7FB
+F7FC
+F7FD
+F7FE
+F8A1
+F8A2
+F8A3
+F8A4
+F8A5
+F8A6
+F8A7
+F8A8
+F8A9
+F8AA
+F8AB
+F8AC
+F8AD
+F8AE
+F8AF
+F8B0
+F8B1
+F8B2
+F8B3
+F8B4
+F8B5
+F8B6
+F8B7
+F8B8
+F8B9
+F8BA
+F8BB
+F8BC
+F8BD
+F8BE
+F8BF
+F8C0
+F8C1
+F8C2
+F8C3
+F8C4
+F8C5
+F8C6
+F8C7
+F8C8
+F8C9
+F8CA
+F8CB
+F8CC
+F8CD
+F8CE
+F8CF
+F8D0
+F8D1
+F8D2
+F8D3
+F8D4
+F8D5
+F8D6
+F8D7
+F8D8
+F8D9
+F8DA
+F8DB
+F8DC
+F8DD
+F8DE
+F8DF
+F8E0
+F8E1
+F8E2
+F8E3
+F8E4
+F8E5
+F8E6
+F8E7
+F8E8
+F8E9
+F8EA
+F8EB
+F8EC
+F8ED
+F8EE
+F8EF
+F8F0
+F8F1
+F8F2
+F8F3
+F8F4
+F8F5
+F8F6
+F8F7
+F8F8
+F8F9
+F8FA
+F8FB
+F8FC
+F8FD
+F8FE
+F9A1
+F9A2
+F9A3
+F9A4
+F9A5
+F9A6
+F9A7
+F9A8
+F9A9
+F9AA
+F9AB
+F9AC
+F9AD
+F9AE
+F9AF
+F9B0
+F9B1
+F9B2
+F9B3
+F9B4
+F9B5
+F9B6
+F9B7
+F9B8
+F9B9
+F9BA
+F9BB
+F9BC
+F9BD
+F9BE
+F9BF
+F9C0
+F9C1
+F9C2
+F9C3
+F9C4
+F9C5
+F9C6
+F9C7
+F9C8
+F9C9
+F9CA
+F9CB
+F9CC
+F9CD
+F9CE
+F9CF
+F9D0
+F9D1
+F9D2
+F9D3
+F9D4
+F9D5
+F9D6
+F9D7
+F9D8
+F9D9
+F9DA
+F9DB
+F9DC
+F9DD
+F9DE
+F9DF
+F9E0
+F9E1
+F9E2
+F9E3
+F9E4
+F9E5
+F9E6
+F9E7
+F9E8
+F9E9
+F9EA
+F9EB
+F9EC
+F9ED
+F9EE
+F9EF
+F9F0
+F9F1
+F9F2
+F9F3
+F9F4
+F9F5
+F9F6
+F9F7
+F9F8
+F9F9
+F9FA
+F9FB
+F9FC
+F9FD
+F9FE
+FAA1
+FAA2
+FAA3
+FAA4
+FAA5
+FAA6
+FAA7
+FAA8
+FAA9
+FAAA
+FAAB
+FAAC
+FAAD
+FAAE
+FAAF
+FAB0
+FAB1
+FAB2
+FAB3
+FAB4
+FAB5
+FAB6
+FAB7
+FAB8
+FAB9
+FABA
+FABB
+FABC
+FABD
+FABE
+FABF
+FAC0
+FAC1
+FAC2
+FAC3
+FAC4
+FAC5
+FAC6
+FAC7
+FAC8
+FAC9
+FACA
+FACB
+FACC
+FACD
+FACE
+FACF
+FAD0
+FAD1
+FAD2
+FAD3
+FAD4
+FAD5
+FAD6
+FAD7
+FAD8
+FAD9
+FADA
+FADB
+FADC
+FADD
+FADE
+FADF
+FAE0
+FAE1
+FAE2
+FAE3
+FAE4
+FAE5
+FAE6
+FAE7
+FAE8
+FAE9
+FAEA
+FAEB
+FAEC
+FAED
+FAEE
+FAEF
+FAF0
+FAF1
+FAF2
+FAF3
+FAF4
+FAF5
+FAF6
+FAF7
+FAF8
+FAF9
+FAFA
+FAFB
+FAFC
+FAFD
+FAFE
+FBA1
+FBA2
+FBA3
+FBA4
+FBA5
+FBA6
+FBA7
+FBA8
+FBA9
+FBAA
+FBAB
+FBAC
+FBAD
+FBAE
+FBAF
+FBB0
+FBB1
+FBB2
+FBB3
+FBB4
+FBB5
+FBB6
+FBB7
+FBB8
+FBB9
+FBBA
+FBBB
+FBBC
+FBBD
+FBBE
+FBBF
+FBC0
+FBC1
+FBC2
+FBC3
+FBC4
+FBC5
+FBC6
+FBC7
+FBC8
+FBC9
+FBCA
+FBCB
+FBCC
+FBCD
+FBCE
+FBCF
+FBD0
+FBD1
+FBD2
+FBD3
+FBD4
+FBD5
+FBD6
+FBD7
+FBD8
+FBD9
+FBDA
+FBDB
+FBDC
+FBDD
+FBDE
+FBDF
+FBE0
+FBE1
+FBE2
+FBE3
+FBE4
+FBE5
+FBE6
+FBE7
+FBE8
+FBE9
+FBEA
+FBEB
+FBEC
+FBED
+FBEE
+FBEF
+FBF0
+FBF1
+FBF2
+FBF3
+FBF4
+FBF5
+FBF6
+FBF7
+FBF8
+FBF9
+FBFA
+FBFB
+FBFC
+FBFD
+FBFE
+FCA1
+FCA2
+FCA3
+FCA4
+FCA5
+FCA6
+FCA7
+FCA8
+FCA9
+FCAA
+FCAB
+FCAC
+FCAD
+FCAE
+FCAF
+FCB0
+FCB1
+FCB2
+FCB3
+FCB4
+FCB5
+FCB6
+FCB7
+FCB8
+FCB9
+FCBA
+FCBB
+FCBC
+FCBD
+FCBE
+FCBF
+FCC0
+FCC1
+FCC2
+FCC3
+FCC4
+FCC5
+FCC6
+FCC7
+FCC8
+FCC9
+FCCA
+FCCB
+FCCC
+FCCD
+FCCE
+FCCF
+FCD0
+FCD1
+FCD2
+FCD3
+FCD4
+FCD5
+FCD6
+FCD7
+FCD8
+FCD9
+FCDA
+FCDB
+FCDC
+FCDD
+FCDE
+FCDF
+FCE0
+FCE1
+FCE2
+FCE3
+FCE4
+FCE5
+FCE6
+FCE7
+FCE8
+FCE9
+FCEA
+FCEB
+FCEC
+FCED
+FCEE
+FCEF
+FCF0
+FCF1
+FCF2
+FCF3
+FCF4
+FCF5
+FCF6
+FCF7
+FCF8
+FCF9
+FCFA
+FCFB
+FCFC
+FCFD
+FCFE
+FDA1
+FDA2
+FDA3
+FDA4
+FDA5
+FDA6
+FDA7
+FDA8
+FDA9
+FDAA
+FDAB
+FDAC
+FDAD
+FDAE
+FDAF
+FDB0
+FDB1
+FDB2
+FDB3
+FDB4
+FDB5
+FDB6
+FDB7
+FDB8
+FDB9
+FDBA
+FDBB
+FDBC
+FDBD
+FDBE
+FDBF
+FDC0
+FDC1
+FDC2
+FDC3
+FDC4
+FDC5
+FDC6
+FDC7
+FDC8
+FDC9
+FDCA
+FDCB
+FDCC
+FDCD
+FDCE
+FDCF
+FDD0
+FDD1
+FDD2
+FDD3
+FDD4
+FDD5
+FDD6
+FDD7
+FDD8
+FDD9
+FDDA
+FDDB
+FDDC
+FDDD
+FDDE
+FDDF
+FDE0
+FDE1
+FDE2
+FDE3
+FDE4
+FDE5
+FDE6
+FDE7
+FDE8
+FDE9
+FDEA
+FDEB
+FDEC
+FDED
+FDEE
+FDEF
+FDF0
+FDF1
+FDF2
+FDF3
+FDF4
+FDF5
+FDF6
+FDF7
+FDF8
+FDF9
+FDFA
+FDFB
+FDFC
+FDFD
+FDFE
+FEA1
+FEA2
+FEA3
+FEA4
+FEA5
+FEA6
+FEA7
+FEA8
+FEA9
+FEAA
+FEAB
+FEAC
+FEAD
+FEAE
+FEAF
+FEB0
+FEB1
+FEB2
+FEB3
+FEB4
+FEB5
+FEB6
+FEB7
+FEB8
+FEB9
+FEBA
+FEBB
+FEBC
+FEBD
+FEBE
+FEBF
+FEC0
+FEC1
+FEC2
+FEC3
+FEC4
+FEC5
+FEC6
+FEC7
+FEC8
+FEC9
+FECA
+FECB
+FECC
+FECD
+FECE
+FECF
+FED0
+FED1
+FED2
+FED3
+FED4
+FED5
+FED6
+FED7
+FED8
+FED9
+FEDA
+FEDB
+FEDC
+FEDD
+FEDE
+FEDF
+FEE0
+FEE1
+FEE2
+FEE3
+FEE4
+FEE5
+FEE6
+FEE7
+FEE8
+FEE9
+FEEA
+FEEB
+FEEC
+FEED
+FEEE
+FEEF
+FEF0
+FEF1
+FEF2
+FEF3
+FEF4
+FEF5
+FEF6
+FEF7
+FEF8
+FEF9
+FEFA
+FEFB
+FEFC
+FEFD
+FEFE
+8FF5A1
+8FF5A2
+8FF5A3
+8FF5A4
+8FF5A5
+8FF5A6
+8FF5A7
+8FF5A8
+8FF5A9
+8FF5AA
+8FF5AB
+8FF5AC
+8FF5AD
+8FF5AE
+8FF5AF
+8FF5B0
+8FF5B1
+8FF5B2
+8FF5B3
+8FF5B4
+8FF5B5
+8FF5B6
+8FF5B7
+8FF5B8
+8FF5B9
+8FF5BA
+8FF5BB
+8FF5BC
+8FF5BD
+8FF5BE
+8FF5BF
+8FF5C0
+8FF5C1
+8FF5C2
+8FF5C3
+8FF5C4
+8FF5C5
+8FF5C6
+8FF5C7
+8FF5C8
+8FF5C9
+8FF5CA
+8FF5CB
+8FF5CC
+8FF5CD
+8FF5CE
+8FF5CF
+8FF5D0
+8FF5D1
+8FF5D2
+8FF5D3
+8FF5D4
+8FF5D5
+8FF5D6
+8FF5D7
+8FF5D8
+8FF5D9
+8FF5DA
+8FF5DB
+8FF5DC
+8FF5DD
+8FF5DE
+8FF5DF
+8FF5E0
+8FF5E1
+8FF5E2
+8FF5E3
+8FF5E4
+8FF5E5
+8FF5E6
+8FF5E7
+8FF5E8
+8FF5E9
+8FF5EA
+8FF5EB
+8FF5EC
+8FF5ED
+8FF5EE
+8FF5EF
+8FF5F0
+8FF5F1
+8FF5F2
+8FF5F3
+8FF5F4
+8FF5F5
+8FF5F6
+8FF5F7
+8FF5F8
+8FF5F9
+8FF5FA
+8FF5FB
+8FF5FC
+8FF5FD
+8FF5FE
+8FF6A1
+8FF6A2
+8FF6A3
+8FF6A4
+8FF6A5
+8FF6A6
+8FF6A7
+8FF6A8
+8FF6A9
+8FF6AA
+8FF6AB
+8FF6AC
+8FF6AD
+8FF6AE
+8FF6AF
+8FF6B0
+8FF6B1
+8FF6B2
+8FF6B3
+8FF6B4
+8FF6B5
+8FF6B6
+8FF6B7
+8FF6B8
+8FF6B9
+8FF6BA
+8FF6BB
+8FF6BC
+8FF6BD
+8FF6BE
+8FF6BF
+8FF6C0
+8FF6C1
+8FF6C2
+8FF6C3
+8FF6C4
+8FF6C5
+8FF6C6
+8FF6C7
+8FF6C8
+8FF6C9
+8FF6CA
+8FF6CB
+8FF6CC
+8FF6CD
+8FF6CE
+8FF6CF
+8FF6D0
+8FF6D1
+8FF6D2
+8FF6D3
+8FF6D4
+8FF6D5
+8FF6D6
+8FF6D7
+8FF6D8
+8FF6D9
+8FF6DA
+8FF6DB
+8FF6DC
+8FF6DD
+8FF6DE
+8FF6DF
+8FF6E0
+8FF6E1
+8FF6E2
+8FF6E3
+8FF6E4
+8FF6E5
+8FF6E6
+8FF6E7
+8FF6E8
+8FF6E9
+8FF6EA
+8FF6EB
+8FF6EC
+8FF6ED
+8FF6EE
+8FF6EF
+8FF6F0
+8FF6F1
+8FF6F2
+8FF6F3
+8FF6F4
+8FF6F5
+8FF6F6
+8FF6F7
+8FF6F8
+8FF6F9
+8FF6FA
+8FF6FB
+8FF6FC
+8FF6FD
+8FF6FE
+8FF7A1
+8FF7A2
+8FF7A3
+8FF7A4
+8FF7A5
+8FF7A6
+8FF7A7
+8FF7A8
+8FF7A9
+8FF7AA
+8FF7AB
+8FF7AC
+8FF7AD
+8FF7AE
+8FF7AF
+8FF7B0
+8FF7B1
+8FF7B2
+8FF7B3
+8FF7B4
+8FF7B5
+8FF7B6
+8FF7B7
+8FF7B8
+8FF7B9
+8FF7BA
+8FF7BB
+8FF7BC
+8FF7BD
+8FF7BE
+8FF7BF
+8FF7C0
+8FF7C1
+8FF7C2
+8FF7C3
+8FF7C4
+8FF7C5
+8FF7C6
+8FF7C7
+8FF7C8
+8FF7C9
+8FF7CA
+8FF7CB
+8FF7CC
+8FF7CD
+8FF7CE
+8FF7CF
+8FF7D0
+8FF7D1
+8FF7D2
+8FF7D3
+8FF7D4
+8FF7D5
+8FF7D6
+8FF7D7
+8FF7D8
+8FF7D9
+8FF7DA
+8FF7DB
+8FF7DC
+8FF7DD
+8FF7DE
+8FF7DF
+8FF7E0
+8FF7E1
+8FF7E2
+8FF7E3
+8FF7E4
+8FF7E5
+8FF7E6
+8FF7E7
+8FF7E8
+8FF7E9
+8FF7EA
+8FF7EB
+8FF7EC
+8FF7ED
+8FF7EE
+8FF7EF
+8FF7F0
+8FF7F1
+8FF7F2
+8FF7F3
+8FF7F4
+8FF7F5
+8FF7F6
+8FF7F7
+8FF7F8
+8FF7F9
+8FF7FA
+8FF7FB
+8FF7FC
+8FF7FD
+8FF7FE
+8FF8A1
+8FF8A2
+8FF8A3
+8FF8A4
+8FF8A5
+8FF8A6
+8FF8A7
+8FF8A8
+8FF8A9
+8FF8AA
+8FF8AB
+8FF8AC
+8FF8AD
+8FF8AE
+8FF8AF
+8FF8B0
+8FF8B1
+8FF8B2
+8FF8B3
+8FF8B4
+8FF8B5
+8FF8B6
+8FF8B7
+8FF8B8
+8FF8B9
+8FF8BA
+8FF8BB
+8FF8BC
+8FF8BD
+8FF8BE
+8FF8BF
+8FF8C0
+8FF8C1
+8FF8C2
+8FF8C3
+8FF8C4
+8FF8C5
+8FF8C6
+8FF8C7
+8FF8C8
+8FF8C9
+8FF8CA
+8FF8CB
+8FF8CC
+8FF8CD
+8FF8CE
+8FF8CF
+8FF8D0
+8FF8D1
+8FF8D2
+8FF8D3
+8FF8D4
+8FF8D5
+8FF8D6
+8FF8D7
+8FF8D8
+8FF8D9
+8FF8DA
+8FF8DB
+8FF8DC
+8FF8DD
+8FF8DE
+8FF8DF
+8FF8E0
+8FF8E1
+8FF8E2
+8FF8E3
+8FF8E4
+8FF8E5
+8FF8E6
+8FF8E7
+8FF8E8
+8FF8E9
+8FF8EA
+8FF8EB
+8FF8EC
+8FF8ED
+8FF8EE
+8FF8EF
+8FF8F0
+8FF8F1
+8FF8F2
+8FF8F3
+8FF8F4
+8FF8F5
+8FF8F6
+8FF8F7
+8FF8F8
+8FF8F9
+8FF8FA
+8FF8FB
+8FF8FC
+8FF8FD
+8FF8FE
+8FF9A1
+8FF9A2
+8FF9A3
+8FF9A4
+8FF9A5
+8FF9A6
+8FF9A7
+8FF9A8
+8FF9A9
+8FF9AA
+8FF9AB
+8FF9AC
+8FF9AD
+8FF9AE
+8FF9AF
+8FF9B0
+8FF9B1
+8FF9B2
+8FF9B3
+8FF9B4
+8FF9B5
+8FF9B6
+8FF9B7
+8FF9B8
+8FF9B9
+8FF9BA
+8FF9BB
+8FF9BC
+8FF9BD
+8FF9BE
+8FF9BF
+8FF9C0
+8FF9C1
+8FF9C2
+8FF9C3
+8FF9C4
+8FF9C5
+8FF9C6
+8FF9C7
+8FF9C8
+8FF9C9
+8FF9CA
+8FF9CB
+8FF9CC
+8FF9CD
+8FF9CE
+8FF9CF
+8FF9D0
+8FF9D1
+8FF9D2
+8FF9D3
+8FF9D4
+8FF9D5
+8FF9D6
+8FF9D7
+8FF9D8
+8FF9D9
+8FF9DA
+8FF9DB
+8FF9DC
+8FF9DD
+8FF9DE
+8FF9DF
+8FF9E0
+8FF9E1
+8FF9E2
+8FF9E3
+8FF9E4
+8FF9E5
+8FF9E6
+8FF9E7
+8FF9E8
+8FF9E9
+8FF9EA
+8FF9EB
+8FF9EC
+8FF9ED
+8FF9EE
+8FF9EF
+8FF9F0
+8FF9F1
+8FF9F2
+8FF9F3
+8FF9F4
+8FF9F5
+8FF9F6
+8FF9F7
+8FF9F8
+8FF9F9
+8FF9FA
+8FF9FB
+8FF9FC
+8FF9FD
+8FF9FE
+8FFAA1
+8FFAA2
+8FFAA3
+8FFAA4
+8FFAA5
+8FFAA6
+8FFAA7
+8FFAA8
+8FFAA9
+8FFAAA
+8FFAAB
+8FFAAC
+8FFAAD
+8FFAAE
+8FFAAF
+8FFAB0
+8FFAB1
+8FFAB2
+8FFAB3
+8FFAB4
+8FFAB5
+8FFAB6
+8FFAB7
+8FFAB8
+8FFAB9
+8FFABA
+8FFABB
+8FFABC
+8FFABD
+8FFABE
+8FFABF
+8FFAC0
+8FFAC1
+8FFAC2
+8FFAC3
+8FFAC4
+8FFAC5
+8FFAC6
+8FFAC7
+8FFAC8
+8FFAC9
+8FFACA
+8FFACB
+8FFACC
+8FFACD
+8FFACE
+8FFACF
+8FFAD0
+8FFAD1
+8FFAD2
+8FFAD3
+8FFAD4
+8FFAD5
+8FFAD6
+8FFAD7
+8FFAD8
+8FFAD9
+8FFADA
+8FFADB
+8FFADC
+8FFADD
+8FFADE
+8FFADF
+8FFAE0
+8FFAE1
+8FFAE2
+8FFAE3
+8FFAE4
+8FFAE5
+8FFAE6
+8FFAE7
+8FFAE8
+8FFAE9
+8FFAEA
+8FFAEB
+8FFAEC
+8FFAED
+8FFAEE
+8FFAEF
+8FFAF0
+8FFAF1
+8FFAF2
+8FFAF3
+8FFAF4
+8FFAF5
+8FFAF6
+8FFAF7
+8FFAF8
+8FFAF9
+8FFAFA
+8FFAFB
+8FFAFC
+8FFAFD
+8FFAFE
+8FFBA1
+8FFBA2
+8FFBA3
+8FFBA4
+8FFBA5
+8FFBA6
+8FFBA7
+8FFBA8
+8FFBA9
+8FFBAA
+8FFBAB
+8FFBAC
+8FFBAD
+8FFBAE
+8FFBAF
+8FFBB0
+8FFBB1
+8FFBB2
+8FFBB3
+8FFBB4
+8FFBB5
+8FFBB6
+8FFBB7
+8FFBB8
+8FFBB9
+8FFBBA
+8FFBBB
+8FFBBC
+8FFBBD
+8FFBBE
+8FFBBF
+8FFBC0
+8FFBC1
+8FFBC2
+8FFBC3
+8FFBC4
+8FFBC5
+8FFBC6
+8FFBC7
+8FFBC8
+8FFBC9
+8FFBCA
+8FFBCB
+8FFBCC
+8FFBCD
+8FFBCE
+8FFBCF
+8FFBD0
+8FFBD1
+8FFBD2
+8FFBD3
+8FFBD4
+8FFBD5
+8FFBD6
+8FFBD7
+8FFBD8
+8FFBD9
+8FFBDA
+8FFBDB
+8FFBDC
+8FFBDD
+8FFBDE
+8FFBDF
+8FFBE0
+8FFBE1
+8FFBE2
+8FFBE3
+8FFBE4
+8FFBE5
+8FFBE6
+8FFBE7
+8FFBE8
+8FFBE9
+8FFBEA
+8FFBEB
+8FFBEC
+8FFBED
+8FFBEE
+8FFBEF
+8FFBF0
+8FFBF1
+8FFBF2
+8FFBF3
+8FFBF4
+8FFBF5
+8FFBF6
+8FFBF7
+8FFBF8
+8FFBF9
+8FFBFA
+8FFBFB
+8FFBFC
+8FFBFD
+8FFBFE
+8FFCA1
+8FFCA2
+8FFCA3
+8FFCA4
+8FFCA5
+8FFCA6
+8FFCA7
+8FFCA8
+8FFCA9
+8FFCAA
+8FFCAB
+8FFCAC
+8FFCAD
+8FFCAE
+8FFCAF
+8FFCB0
+8FFCB1
+8FFCB2
+8FFCB3
+8FFCB4
+8FFCB5
+8FFCB6
+8FFCB7
+8FFCB8
+8FFCB9
+8FFCBA
+8FFCBB
+8FFCBC
+8FFCBD
+8FFCBE
+8FFCBF
+8FFCC0
+8FFCC1
+8FFCC2
+8FFCC3
+8FFCC4
+8FFCC5
+8FFCC6
+8FFCC7
+8FFCC8
+8FFCC9
+8FFCCA
+8FFCCB
+8FFCCC
+8FFCCD
+8FFCCE
+8FFCCF
+8FFCD0
+8FFCD1
+8FFCD2
+8FFCD3
+8FFCD4
+8FFCD5
+8FFCD6
+8FFCD7
+8FFCD8
+8FFCD9
+8FFCDA
+8FFCDB
+8FFCDC
+8FFCDD
+8FFCDE
+8FFCDF
+8FFCE0
+8FFCE1
+8FFCE2
+8FFCE3
+8FFCE4
+8FFCE5
+8FFCE6
+8FFCE7
+8FFCE8
+8FFCE9
+8FFCEA
+8FFCEB
+8FFCEC
+8FFCED
+8FFCEE
+8FFCEF
+8FFCF0
+8FFCF1
+8FFCF2
+8FFCF3
+8FFCF4
+8FFCF5
+8FFCF6
+8FFCF7
+8FFCF8
+8FFCF9
+8FFCFA
+8FFCFB
+8FFCFC
+8FFCFD
+8FFCFE
+8FFDA1
+8FFDA2
+8FFDA3
+8FFDA4
+8FFDA5
+8FFDA6
+8FFDA7
+8FFDA8
+8FFDA9
+8FFDAA
+8FFDAB
+8FFDAC
+8FFDAD
+8FFDAE
+8FFDAF
+8FFDB0
+8FFDB1
+8FFDB2
+8FFDB3
+8FFDB4
+8FFDB5
+8FFDB6
+8FFDB7
+8FFDB8
+8FFDB9
+8FFDBA
+8FFDBB
+8FFDBC
+8FFDBD
+8FFDBE
+8FFDBF
+8FFDC0
+8FFDC1
+8FFDC2
+8FFDC3
+8FFDC4
+8FFDC5
+8FFDC6
+8FFDC7
+8FFDC8
+8FFDC9
+8FFDCA
+8FFDCB
+8FFDCC
+8FFDCD
+8FFDCE
+8FFDCF
+8FFDD0
+8FFDD1
+8FFDD2
+8FFDD3
+8FFDD4
+8FFDD5
+8FFDD6
+8FFDD7
+8FFDD8
+8FFDD9
+8FFDDA
+8FFDDB
+8FFDDC
+8FFDDD
+8FFDDE
+8FFDDF
+8FFDE0
+8FFDE1
+8FFDE2
+8FFDE3
+8FFDE4
+8FFDE5
+8FFDE6
+8FFDE7
+8FFDE8
+8FFDE9
+8FFDEA
+8FFDEB
+8FFDEC
+8FFDED
+8FFDEE
+8FFDEF
+8FFDF0
+8FFDF1
+8FFDF2
+8FFDF3
+8FFDF4
+8FFDF5
+8FFDF6
+8FFDF7
+8FFDF8
+8FFDF9
+8FFDFA
+8FFDFB
+8FFDFC
+8FFDFD
+8FFDFE
+8FFEA1
+8FFEA2
+8FFEA3
+8FFEA4
+8FFEA5
+8FFEA6
+8FFEA7
+8FFEA8
+8FFEA9
+8FFEAA
+8FFEAB
+8FFEAC
+8FFEAD
+8FFEAE
+8FFEAF
+8FFEB0
+8FFEB1
+8FFEB2
+8FFEB3
+8FFEB4
+8FFEB5
+8FFEB6
+8FFEB7
+8FFEB8
+8FFEB9
+8FFEBA
+8FFEBB
+8FFEBC
+8FFEBD
+8FFEBE
+8FFEBF
+8FFEC0
+8FFEC1
+8FFEC2
+8FFEC3
+8FFEC4
+8FFEC5
+8FFEC6
+8FFEC7
+8FFEC8
+8FFEC9
+8FFECA
+8FFECB
+8FFECC
+8FFECD
+8FFECE
+8FFECF
+8FFED0
+8FFED1
+8FFED2
+8FFED3
+8FFED4
+8FFED5
+8FFED6
+8FFED7
+8FFED8
+8FFED9
+8FFEDA
+8FFEDB
+8FFEDC
+8FFEDD
+8FFEDE
+8FFEDF
+8FFEE0
+8FFEE1
+8FFEE2
+8FFEE3
+8FFEE4
+8FFEE5
+8FFEE6
+8FFEE7
+8FFEE8
+8FFEE9
+8FFEEA
+8FFEEB
+8FFEEC
+8FFEED
+8FFEEE
+8FFEEF
+8FFEF0
+8FFEF1
+8FFEF2
+8FFEF3
+8FFEF4
+8FFEF5
+8FFEF6
+8FFEF7
+8FFEF8
+8FFEF9
+8FFEFA
+8FFEFB
+8FFEFC
+8FFEFD
+8FFEFE
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
+SET collation_connection='cp932_japanese_ci';
+create table t1 select repeat('a',4000) a;
+delete from t1;
+insert into t1 values ('a'), ('a '), ('a\t');
+select collation(a),hex(a) from t1 order by a;
+collation(a) hex(a)
+cp932_japanese_ci 6109
+cp932_japanese_ci 61
+cp932_japanese_ci 6120
+drop table t1;
+SET collation_connection='cp932_bin';
+create table t1 select repeat('a',4000) a;
+delete from t1;
+insert into t1 values ('a'), ('a '), ('a\t');
+select collation(a),hex(a) from t1 order by a;
+collation(a) hex(a)
+cp932_bin 6109
+cp932_bin 61
+cp932_bin 6120
+drop table t1;
diff --git a/mysql-test/r/ctype_eucjpms.result b/mysql-test/r/ctype_eucjpms.result
new file mode 100755
index 00000000000..a07ff9b28be
--- /dev/null
+++ b/mysql-test/r/ctype_eucjpms.result
@@ -0,0 +1,9807 @@
+drop table if exists t1;
+drop table if exists t2;
+drop table if exists t3;
+drop table if exists t4;
+set names eucjpms;
+set character_set_database = eucjpms;
+CREATE TABLE t1(c1 CHAR(1)) DEFAULT CHARACTER SET = eucjpms;
+INSERT INTO t1 VALUES
+(0x5C),(0x7E),(0xA1B1),(0xA1BD),(0xA1C0),(0xA1C1),(0xA1C2),(0xA1DD),(0xA1F1),(0xA1F2),(0xA1EF),(0xA2CC),(0x8FA2B7),(0x8FA2C3);
+INSERT INTO t1 VALUES
+(0xADA1),(0xADA2),(0xADA3),(0xADA4),(0xADA5),(0xADA6),(0xADA7),(0xADA8),
+(0xADA9),(0xADAA),(0xADAB),(0xADAC),(0xADAD),(0xADAE),(0xADAF),(0xADB0),
+(0xADB1),(0xADB2),(0xADB3),(0xADB4),(0xADB5),(0xADB6),(0xADB7),(0xADB8),
+(0xADB9),(0xADBA),(0xADBB),(0xADBC),(0xADBD),(0xADBE),(0xADC0),(0xADC1),
+(0xADC2),(0xADC3),(0xADC4),(0xADC5),(0xADC6),(0xADC7),(0xADC8),(0xADC9),
+(0xADCA),(0xADCB),(0xADCC),(0xADCD),(0xADCE),(0xADCF),(0xADD0),(0xADD1),
+(0xADD2),(0xADD3),(0xADD4),(0xADD5),(0xADD6),(0xADDF),(0xADE0),(0xADE1),
+(0xADE2),(0xADE3),(0xADE4),(0xADE5),(0xADE6),(0xADE7),(0xADE8),(0xADE9),
+(0xADEA),(0xADEB),(0xADEC),(0xADED),(0xADEE),(0xADEF),(0xADF0),(0xADF1),
+(0xADF2),(0xADF3),(0xADF4),(0xADF5),(0xADF6),(0xADF7),(0xADF8),(0xADF9),
+(0xADFA),(0xADFB),(0xADFC);
+INSERT INTO t1 VALUES
+(0x8FF3F3),(0x8FF3F4),(0x8FF3F5),(0x8FF3F6),(0x8FF3F7),(0x8FF3F8),(0x8FF3F9),(0x8FF3FA),
+(0x8FF3FB),(0x8FF3FC),(0x8FF3FD),(0x8FF3FE),(0x8FF4A1),(0x8FF4A2),(0x8FF4A3),(0x8FF4A4),
+(0x8FF4A5),(0x8FF4A6),(0x8FF4A7),(0x8FF4A8),(0xA2CC),(0x8FA2C3),(0x8FF4A9),(0x8FF4AA),
+(0x8FF4AB),(0x8FF4AC),(0x8FF4AD),(0xA2E8),(0x8FD4E3),(0x8FDCDF),(0x8FE4E9),(0x8FE3F8),
+(0x8FD9A1),(0x8FB1BB),(0x8FF4AE),(0x8FC2AD),(0x8FC3FC),(0x8FE4D0),(0x8FC2BF),(0x8FBCF4),
+(0x8FB0A9),(0x8FB0C8),(0x8FF4AF),(0x8FB0D2),(0x8FB0D4),(0x8FB0E3),(0x8FB0EE),(0x8FB1A7),
+(0x8FB1A3),(0x8FB1AC),(0x8FB1A9),(0x8FB1BE),(0x8FB1DF),(0x8FB1D8),(0x8FB1C8),(0x8FB1D7),
+(0x8FB1E3),(0x8FB1F4),(0x8FB1E1),(0x8FB2A3),(0x8FF4B0),(0x8FB2BB),(0x8FB2E6),(0x8FB2ED),
+(0x8FB2F5),(0x8FB2FC),(0x8FF4B1),(0x8FB3B5),(0x8FB3D8),(0x8FB3DB),(0x8FB3E5),(0x8FB3EE),
+(0x8FB3FB),(0x8FF4B2),(0x8FF4B3),(0x8FB4C0),(0x8FB4C7),(0x8FB4D0),(0x8FB4DE),(0x8FF4B4),
+(0x8FB5AA),(0x8FF4B5),(0x8FB5AF),(0x8FB5C4),(0x8FB5E8),(0x8FF4B6),(0x8FB7C2),(0x8FB7E4),
+(0x8FB7E8),(0x8FB7E7),(0x8FF4B7),(0x8FF4B8),(0x8FF4B9),(0x8FB8CE),(0x8FB8E1),(0x8FB8F5),
+(0x8FB8F7),(0x8FB8F8),(0x8FB8FC),(0x8FB9AF),(0x8FB9B7),(0x8FBABE),(0x8FBADB),(0x8FCDAA),
+(0x8FBAE1),(0x8FF4BA),(0x8FBAEB),(0x8FBBB3),(0x8FBBB8),(0x8FF4BB),(0x8FBBCA),(0x8FF4BC),
+(0x8FF4BD),(0x8FBBD0),(0x8FBBDE),(0x8FBBF4),(0x8FBBF5),(0x8FBBF9),(0x8FBCE4),(0x8FBCED),
+(0x8FBCFE),(0x8FF4BE),(0x8FBDC2),(0x8FBDE7),(0x8FF4BF),(0x8FBDF0),(0x8FBEB0),(0x8FBEAC),
+(0x8FF4C0),(0x8FBEB3),(0x8FBEBD),(0x8FBECD),(0x8FBEC9),(0x8FBEE4),(0x8FBFA8),(0x8FBFC9),
+(0x8FC0C4),(0x8FC0E4),(0x8FC0F4),(0x8FC1A6),(0x8FF4C1),(0x8FC1F5),(0x8FC1FC),(0x8FF4C2),
+(0x8FC1F8),(0x8FC2AB),(0x8FC2A1),(0x8FC2A5),(0x8FF4C3),(0x8FC2B8),(0x8FC2BA),(0x8FF4C4),
+(0x8FC2C4),(0x8FC2D2),(0x8FC2D7),(0x8FC2DB),(0x8FC2DE),(0x8FC2ED),(0x8FC2F0),(0x8FF4C5),
+(0x8FC3A1),(0x8FC3B5),(0x8FC3C9),(0x8FC3B9),(0x8FF4C6),(0x8FC3D8),(0x8FC3FE),(0x8FF4C7),
+(0x8FC4CC),(0x8FF4C8),(0x8FC4D9),(0x8FC4EA),(0x8FC4FD),(0x8FF4C9),(0x8FC5A7),(0x8FC5B5),
+(0x8FC5B6),(0x8FF4CA),(0x8FC5D5),(0x8FC6B8),(0x8FC6D7),(0x8FC6E0),(0x8FC6EA),(0x8FC6E3),
+(0x8FC7A1),(0x8FC7AB),(0x8FC7C7),(0x8FC7C3),(0x8FC7CB),(0x8FC7CF),(0x8FC7D9),(0x8FF4CB),
+(0x8FF4CC),(0x8FC7E6),(0x8FC7EE),(0x8FC7FC),(0x8FC7EB),(0x8FC7F0),(0x8FC8B1),(0x8FC8E5),
+(0x8FC8F8),(0x8FC9A6),(0x8FC9AB),(0x8FC9AD),(0x8FF4CD),(0x8FC9CA),(0x8FC9D3),(0x8FC9E9),
+(0x8FC9E3),(0x8FC9FC),(0x8FC9F4),(0x8FC9F5),(0x8FF4CE),(0x8FCAB3),(0x8FCABD),(0x8FCAEF),
+(0x8FCAF1),(0x8FCBAE),(0x8FF4CF),(0x8FCBCA),(0x8FCBE6),(0x8FCBEA),(0x8FCBF0),(0x8FCBF4),
+(0x8FCBEE),(0x8FCCA5),(0x8FCBF9),(0x8FCCAB),(0x8FCCAE),(0x8FCCAD),(0x8FCCB2),(0x8FCCC2),
+(0x8FCCD0),(0x8FCCD9),(0x8FF4D0),(0x8FCDBB),(0x8FF4D1),(0x8FCEBB),(0x8FF4D2),(0x8FCEBA),
+(0x8FCEC3),(0x8FF4D3),(0x8FCEF2),(0x8FB3DD),(0x8FCFD5),(0x8FCFE2),(0x8FCFE9),(0x8FCFED),
+(0x8FF4D4),(0x8FF4D5),(0x8FF4D6),(0x8FF4D7),(0x8FD0E5),(0x8FF4D8),(0x8FD0E9),(0x8FD1E8),
+(0x8FF4D9),(0x8FF4DA),(0x8FD1EC),(0x8FD2BB),(0x8FF4DB),(0x8FD3E1),(0x8FD3E8),(0x8FD4A7),
+(0x8FF4DC),(0x8FF4DD),(0x8FD4D4),(0x8FD4F2),(0x8FD5AE),(0x8FF4DE),(0x8FD7DE),(0x8FF4DF),
+(0x8FD8A2),(0x8FD8B7),(0x8FD8C1),(0x8FD8D1),(0x8FD8F4),(0x8FD9C6),(0x8FD9C8),(0x8FD9D1),
+(0x8FF4E0),(0x8FF4E1),(0x8FF4E2),(0x8FF4E3),(0x8FF4E4),(0x8FDCD3),(0x8FDDC8),(0x8FDDD4),
+(0x8FDDEA),(0x8FDDFA),(0x8FDEA4),(0x8FDEB0),(0x8FF4E5),(0x8FDEB5),(0x8FDECB),(0x8FF4E6),
+(0x8FDFB9),(0x8FF4E7),(0x8FDFC3),(0x8FF4E8),(0x8FF4E9),(0x8FE0D9),(0x8FF4EA),(0x8FF4EB),
+(0x8FE1E2),(0x8FF4EC),(0x8FF4ED),(0x8FF4EE),(0x8FE2C7),(0x8FE3A8),(0x8FE3A6),(0x8FE3A9),
+(0x8FE3AF),(0x8FE3B0),(0x8FE3AA),(0x8FE3AB),(0x8FE3BC),(0x8FE3C1),(0x8FE3BF),(0x8FE3D5),
+(0x8FE3D8),(0x8FE3D6),(0x8FE3DF),(0x8FE3E3),(0x8FE3E1),(0x8FE3D4),(0x8FE3E9),(0x8FE4A6),
+(0x8FE3F1),(0x8FE3F2),(0x8FE4CB),(0x8FE4C1),(0x8FE4C3),(0x8FE4BE),(0x8FF4EF),(0x8FE4C0),
+(0x8FE4C7),(0x8FE4BF),(0x8FE4E0),(0x8FE4DE),(0x8FE4D1),(0x8FF4F0),(0x8FE4DC),(0x8FE4D2),
+(0x8FE4DB),(0x8FE4D4),(0x8FE4FA),(0x8FE4EF),(0x8FE5B3),(0x8FE5BF),(0x8FE5C9),(0x8FE5D0),
+(0x8FE5E2),(0x8FE5EA),(0x8FE5EB),(0x8FF4F1),(0x8FF4F2),(0x8FF4F3),(0x8FE6E8),(0x8FE6EF),
+(0x8FE7AC),(0x8FF4F4),(0x8FE7AE),(0x8FF4F5),(0x8FE7B1),(0x8FF4F6),(0x8FE7B2),(0x8FE8B1),
+(0x8FE8B6),(0x8FF4F7),(0x8FF4F8),(0x8FE8DD),(0x8FF4F9),(0x8FF4FA),(0x8FE9D1),(0x8FF4FB),
+(0x8FE9ED),(0x8FEACD),(0x8FF4FC),(0x8FEADB),(0x8FEAE6),(0x8FEAEA),(0x8FEBA5),(0x8FEBFB),
+(0x8FEBFA),(0x8FF4FD),(0x8FECD6),(0x8FF4FE);
+INSERT INTO t1 VALUES
+(0xF5A1),(0xF5A2),(0xF5A3),(0xF5A4),(0xF5A5),(0xF5A6),(0xF5A7),(0xF5A8),
+(0xF5A9),(0xF5AA),(0xF5AB),(0xF5AC),(0xF5AD),(0xF5AE),(0xF5AF),(0xF5B0),
+(0xF5B1),(0xF5B2),(0xF5B3),(0xF5B4),(0xF5B5),(0xF5B6),(0xF5B7),(0xF5B8),
+(0xF5B9),(0xF5BA),(0xF5BB),(0xF5BC),(0xF5BD),(0xF5BE),(0xF5BF),(0xF5C0),
+(0xF5C1),(0xF5C2),(0xF5C3),(0xF5C4),(0xF5C5),(0xF5C6),(0xF5C7),(0xF5C8),
+(0xF5C9),(0xF5CA),(0xF5CB),(0xF5CC),(0xF5CD),(0xF5CE),(0xF5CF),(0xF5D0),
+(0xF5D1),(0xF5D2),(0xF5D3),(0xF5D4),(0xF5D5),(0xF5D6),(0xF5D7),(0xF5D8),
+(0xF5D9),(0xF5DA),(0xF5DB),(0xF5DC),(0xF5DD),(0xF5DE),(0xF5DF),(0xF5E0),
+(0xF5E1),(0xF5E2),(0xF5E3),(0xF5E4),(0xF5E5),(0xF5E6),(0xF5E7),(0xF5E8),
+(0xF5E9),(0xF5EA),(0xF5EB),(0xF5EC),(0xF5ED),(0xF5EE),(0xF5EF),(0xF5F0),
+(0xF5F1),(0xF5F2),(0xF5F3),(0xF5F4),(0xF5F5),(0xF5F6),(0xF5F7),(0xF5F8),
+(0xF5F9),(0xF5FA),(0xF5FB),(0xF5FC),(0xF5FD),(0xF5FE),
+(0xF6A1),(0xF6A2),(0xF6A3),(0xF6A4),(0xF6A5),(0xF6A6),(0xF6A7),(0xF6A8),
+(0xF6A9),(0xF6AA),(0xF6AB),(0xF6AC),(0xF6AD),(0xF6AE),(0xF6AF),(0xF6B0),
+(0xF6B1),(0xF6B2),(0xF6B3),(0xF6B4),(0xF6B5),(0xF6B6),(0xF6B7),(0xF6B8),
+(0xF6B9),(0xF6BA),(0xF6BB),(0xF6BC),(0xF6BD),(0xF6BE),(0xF6BF),(0xF6C0),
+(0xF6C1),(0xF6C2),(0xF6C3),(0xF6C4),(0xF6C5),(0xF6C6),(0xF6C7),(0xF6C8),
+(0xF6C9),(0xF6CA),(0xF6CB),(0xF6CC),(0xF6CD),(0xF6CE),(0xF6CF),(0xF6D0),
+(0xF6D1),(0xF6D2),(0xF6D3),(0xF6D4),(0xF6D5),(0xF6D6),(0xF6D7),(0xF6D8),
+(0xF6D9),(0xF6DA),(0xF6DB),(0xF6DC),(0xF6DD),(0xF6DE),(0xF6DF),(0xF6E0),
+(0xF6E1),(0xF6E2),(0xF6E3),(0xF6E4),(0xF6E5),(0xF6E6),(0xF6E7),(0xF6E8),
+(0xF6E9),(0xF6EA),(0xF6EB),(0xF6EC),(0xF6ED),(0xF6EE),(0xF6EF),(0xF6F0),
+(0xF6F1),(0xF6F2),(0xF6F3),(0xF6F4),(0xF6F5),(0xF6F6),(0xF6F7),(0xF6F8),
+(0xF6F9),(0xF6FA),(0xF6FB),(0xF6FC),(0xF6FD),(0xF6FE),
+(0xF7A1),(0xF7A2),(0xF7A3),(0xF7A4),(0xF7A5),(0xF7A6),(0xF7A7),(0xF7A8),
+(0xF7A9),(0xF7AA),(0xF7AB),(0xF7AC),(0xF7AD),(0xF7AE),(0xF7AF),(0xF7B0),
+(0xF7B1),(0xF7B2),(0xF7B3),(0xF7B4),(0xF7B5),(0xF7B6),(0xF7B7),(0xF7B8),
+(0xF7B9),(0xF7BA),(0xF7BB),(0xF7BC),(0xF7BD),(0xF7BE),(0xF7BF),(0xF7C0),
+(0xF7C1),(0xF7C2),(0xF7C3),(0xF7C4),(0xF7C5),(0xF7C6),(0xF7C7),(0xF7C8),
+(0xF7C9),(0xF7CA),(0xF7CB),(0xF7CC),(0xF7CD),(0xF7CE),(0xF7CF),(0xF7D0),
+(0xF7D1),(0xF7D2),(0xF7D3),(0xF7D4),(0xF7D5),(0xF7D6),(0xF7D7),(0xF7D8),
+(0xF7D9),(0xF7DA),(0xF7DB),(0xF7DC),(0xF7DD),(0xF7DE),(0xF7DF),(0xF7E0),
+(0xF7E1),(0xF7E2),(0xF7E3),(0xF7E4),(0xF7E5),(0xF7E6),(0xF7E7),(0xF7E8),
+(0xF7E9),(0xF7EA),(0xF7EB),(0xF7EC),(0xF7ED),(0xF7EE),(0xF7EF),(0xF7F0),
+(0xF7F1),(0xF7F2),(0xF7F3),(0xF7F4),(0xF7F5),(0xF7F6),(0xF7F7),(0xF7F8),
+(0xF7F9),(0xF7FA),(0xF7FB),(0xF7FC),(0xF7FD),(0xF7FE),
+(0xF8A1),(0xF8A2),(0xF8A3),(0xF8A4),(0xF8A5),(0xF8A6),(0xF8A7),(0xF8A8),
+(0xF8A9),(0xF8AA),(0xF8AB),(0xF8AC),(0xF8AD),(0xF8AE),(0xF8AF),(0xF8B0),
+(0xF8B1),(0xF8B2),(0xF8B3),(0xF8B4),(0xF8B5),(0xF8B6),(0xF8B7),(0xF8B8),
+(0xF8B9),(0xF8BA),(0xF8BB),(0xF8BC),(0xF8BD),(0xF8BE),(0xF8BF),(0xF8C0),
+(0xF8C1),(0xF8C2),(0xF8C3),(0xF8C4),(0xF8C5),(0xF8C6),(0xF8C7),(0xF8C8),
+(0xF8C9),(0xF8CA),(0xF8CB),(0xF8CC),(0xF8CD),(0xF8CE),(0xF8CF),(0xF8D0),
+(0xF8D1),(0xF8D2),(0xF8D3),(0xF8D4),(0xF8D5),(0xF8D6),(0xF8D7),(0xF8D8),
+(0xF8D9),(0xF8DA),(0xF8DB),(0xF8DC),(0xF8DD),(0xF8DE),(0xF8DF),(0xF8E0),
+(0xF8E1),(0xF8E2),(0xF8E3),(0xF8E4),(0xF8E5),(0xF8E6),(0xF8E7),(0xF8E8),
+(0xF8E9),(0xF8EA),(0xF8EB),(0xF8EC),(0xF8ED),(0xF8EE),(0xF8EF),(0xF8F0),
+(0xF8F1),(0xF8F2),(0xF8F3),(0xF8F4),(0xF8F5),(0xF8F6),(0xF8F7),(0xF8F8),
+(0xF8F9),(0xF8FA),(0xF8FB),(0xF8FC),(0xF8FD),(0xF8FE),
+(0xF9A1),(0xF9A2),(0xF9A3),(0xF9A4),(0xF9A5),(0xF9A6),(0xF9A7),(0xF9A8),
+(0xF9A9),(0xF9AA),(0xF9AB),(0xF9AC),(0xF9AD),(0xF9AE),(0xF9AF),(0xF9B0),
+(0xF9B1),(0xF9B2),(0xF9B3),(0xF9B4),(0xF9B5),(0xF9B6),(0xF9B7),(0xF9B8),
+(0xF9B9),(0xF9BA),(0xF9BB),(0xF9BC),(0xF9BD),(0xF9BE),(0xF9BF),(0xF9C0),
+(0xF9C1),(0xF9C2),(0xF9C3),(0xF9C4),(0xF9C5),(0xF9C6),(0xF9C7),(0xF9C8),
+(0xF9C9),(0xF9CA),(0xF9CB),(0xF9CC),(0xF9CD),(0xF9CE),(0xF9CF),(0xF9D0),
+(0xF9D1),(0xF9D2),(0xF9D3),(0xF9D4),(0xF9D5),(0xF9D6),(0xF9D7),(0xF9D8),
+(0xF9D9),(0xF9DA),(0xF9DB),(0xF9DC),(0xF9DD),(0xF9DE),(0xF9DF),(0xF9E0),
+(0xF9E1),(0xF9E2),(0xF9E3),(0xF9E4),(0xF9E5),(0xF9E6),(0xF9E7),(0xF9E8),
+(0xF9E9),(0xF9EA),(0xF9EB),(0xF9EC),(0xF9ED),(0xF9EE),(0xF9EF),(0xF9F0),
+(0xF9F1),(0xF9F2),(0xF9F3),(0xF9F4),(0xF9F5),(0xF9F6),(0xF9F7),(0xF9F8),
+(0xF9F9),(0xF9FA),(0xF9FB),(0xF9FC),(0xF9FD),(0xF9FE),
+(0xFAA1),(0xFAA2),(0xFAA3),(0xFAA4),(0xFAA5),(0xFAA6),(0xFAA7),(0xFAA8),
+(0xFAA9),(0xFAAA),(0xFAAB),(0xFAAC),(0xFAAD),(0xFAAE),(0xFAAF),(0xFAB0),
+(0xFAB1),(0xFAB2),(0xFAB3),(0xFAB4),(0xFAB5),(0xFAB6),(0xFAB7),(0xFAB8),
+(0xFAB9),(0xFABA),(0xFABB),(0xFABC),(0xFABD),(0xFABE),(0xFABF),(0xFAC0),
+(0xFAC1),(0xFAC2),(0xFAC3),(0xFAC4),(0xFAC5),(0xFAC6),(0xFAC7),(0xFAC8),
+(0xFAC9),(0xFACA),(0xFACB),(0xFACC),(0xFACD),(0xFACE),(0xFACF),(0xFAD0),
+(0xFAD1),(0xFAD2),(0xFAD3),(0xFAD4),(0xFAD5),(0xFAD6),(0xFAD7),(0xFAD8),
+(0xFAD9),(0xFADA),(0xFADB),(0xFADC),(0xFADD),(0xFADE),(0xFADF),(0xFAE0),
+(0xFAE1),(0xFAE2),(0xFAE3),(0xFAE4),(0xFAE5),(0xFAE6),(0xFAE7),(0xFAE8),
+(0xFAE9),(0xFAEA),(0xFAEB),(0xFAEC),(0xFAED),(0xFAEE),(0xFAEF),(0xFAF0),
+(0xFAF1),(0xFAF2),(0xFAF3),(0xFAF4),(0xFAF5),(0xFAF6),(0xFAF7),(0xFAF8),
+(0xFAF9),(0xFAFA),(0xFAFB),(0xFAFC),(0xFAFD),(0xFAFE),
+(0xFBA1),(0xFBA2),(0xFBA3),(0xFBA4),(0xFBA5),(0xFBA6),(0xFBA7),(0xFBA8),
+(0xFBA9),(0xFBAA),(0xFBAB),(0xFBAC),(0xFBAD),(0xFBAE),(0xFBAF),(0xFBB0),
+(0xFBB1),(0xFBB2),(0xFBB3),(0xFBB4),(0xFBB5),(0xFBB6),(0xFBB7),(0xFBB8),
+(0xFBB9),(0xFBBA),(0xFBBB),(0xFBBC),(0xFBBD),(0xFBBE),(0xFBBF),(0xFBC0),
+(0xFBC1),(0xFBC2),(0xFBC3),(0xFBC4),(0xFBC5),(0xFBC6),(0xFBC7),(0xFBC8),
+(0xFBC9),(0xFBCA),(0xFBCB),(0xFBCC),(0xFBCD),(0xFBCE),(0xFBCF),(0xFBD0),
+(0xFBD1),(0xFBD2),(0xFBD3),(0xFBD4),(0xFBD5),(0xFBD6),(0xFBD7),(0xFBD8),
+(0xFBD9),(0xFBDA),(0xFBDB),(0xFBDC),(0xFBDD),(0xFBDE),(0xFBDF),(0xFBE0),
+(0xFBE1),(0xFBE2),(0xFBE3),(0xFBE4),(0xFBE5),(0xFBE6),(0xFBE7),(0xFBE8),
+(0xFBE9),(0xFBEA),(0xFBEB),(0xFBEC),(0xFBED),(0xFBEE),(0xFBEF),(0xFBF0),
+(0xFBF1),(0xFBF2),(0xFBF3),(0xFBF4),(0xFBF5),(0xFBF6),(0xFBF7),(0xFBF8),
+(0xFBF9),(0xFBFA),(0xFBFB),(0xFBFC),(0xFBFD),(0xFBFE),
+(0xFCA1),(0xFCA2),(0xFCA3),(0xFCA4),(0xFCA5),(0xFCA6),(0xFCA7),(0xFCA8),
+(0xFCA9),(0xFCAA),(0xFCAB),(0xFCAC),(0xFCAD),(0xFCAE),(0xFCAF),(0xFCB0),
+(0xFCB1),(0xFCB2),(0xFCB3),(0xFCB4),(0xFCB5),(0xFCB6),(0xFCB7),(0xFCB8),
+(0xFCB9),(0xFCBA),(0xFCBB),(0xFCBC),(0xFCBD),(0xFCBE),(0xFCBF),(0xFCC0),
+(0xFCC1),(0xFCC2),(0xFCC3),(0xFCC4),(0xFCC5),(0xFCC6),(0xFCC7),(0xFCC8),
+(0xFCC9),(0xFCCA),(0xFCCB),(0xFCCC),(0xFCCD),(0xFCCE),(0xFCCF),(0xFCD0),
+(0xFCD1),(0xFCD2),(0xFCD3),(0xFCD4),(0xFCD5),(0xFCD6),(0xFCD7),(0xFCD8),
+(0xFCD9),(0xFCDA),(0xFCDB),(0xFCDC),(0xFCDD),(0xFCDE),(0xFCDF),(0xFCE0),
+(0xFCE1),(0xFCE2),(0xFCE3),(0xFCE4),(0xFCE5),(0xFCE6),(0xFCE7),(0xFCE8),
+(0xFCE9),(0xFCEA),(0xFCEB),(0xFCEC),(0xFCED),(0xFCEE),(0xFCEF),(0xFCF0),
+(0xFCF1),(0xFCF2),(0xFCF3),(0xFCF4),(0xFCF5),(0xFCF6),(0xFCF7),(0xFCF8),
+(0xFCF9),(0xFCFA),(0xFCFB),(0xFCFC),(0xFCFD),(0xFCFE),
+(0xFDA1),(0xFDA2),(0xFDA3),(0xFDA4),(0xFDA5),(0xFDA6),(0xFDA7),(0xFDA8),
+(0xFDA9),(0xFDAA),(0xFDAB),(0xFDAC),(0xFDAD),(0xFDAE),(0xFDAF),(0xFDB0),
+(0xFDB1),(0xFDB2),(0xFDB3),(0xFDB4),(0xFDB5),(0xFDB6),(0xFDB7),(0xFDB8),
+(0xFDB9),(0xFDBA),(0xFDBB),(0xFDBC),(0xFDBD),(0xFDBE),(0xFDBF),(0xFDC0),
+(0xFDC1),(0xFDC2),(0xFDC3),(0xFDC4),(0xFDC5),(0xFDC6),(0xFDC7),(0xFDC8),
+(0xFDC9),(0xFDCA),(0xFDCB),(0xFDCC),(0xFDCD),(0xFDCE),(0xFDCF),(0xFDD0),
+(0xFDD1),(0xFDD2),(0xFDD3),(0xFDD4),(0xFDD5),(0xFDD6),(0xFDD7),(0xFDD8),
+(0xFDD9),(0xFDDA),(0xFDDB),(0xFDDC),(0xFDDD),(0xFDDE),(0xFDDF),(0xFDE0),
+(0xFDE1),(0xFDE2),(0xFDE3),(0xFDE4),(0xFDE5),(0xFDE6),(0xFDE7),(0xFDE8),
+(0xFDE9),(0xFDEA),(0xFDEB),(0xFDEC),(0xFDED),(0xFDEE),(0xFDEF),(0xFDF0),
+(0xFDF1),(0xFDF2),(0xFDF3),(0xFDF4),(0xFDF5),(0xFDF6),(0xFDF7),(0xFDF8),
+(0xFDF9),(0xFDFA),(0xFDFB),(0xFDFC),(0xFDFD),(0xFDFE),
+(0xFEA1),(0xFEA2),(0xFEA3),(0xFEA4),(0xFEA5),(0xFEA6),(0xFEA7),(0xFEA8),
+(0xFEA9),(0xFEAA),(0xFEAB),(0xFEAC),(0xFEAD),(0xFEAE),(0xFEAF),(0xFEB0),
+(0xFEB1),(0xFEB2),(0xFEB3),(0xFEB4),(0xFEB5),(0xFEB6),(0xFEB7),(0xFEB8),
+(0xFEB9),(0xFEBA),(0xFEBB),(0xFEBC),(0xFEBD),(0xFEBE),(0xFEBF),(0xFEC0),
+(0xFEC1),(0xFEC2),(0xFEC3),(0xFEC4),(0xFEC5),(0xFEC6),(0xFEC7),(0xFEC8),
+(0xFEC9),(0xFECA),(0xFECB),(0xFECC),(0xFECD),(0xFECE),(0xFECF),(0xFED0),
+(0xFED1),(0xFED2),(0xFED3),(0xFED4),(0xFED5),(0xFED6),(0xFED7),(0xFED8),
+(0xFED9),(0xFEDA),(0xFEDB),(0xFEDC),(0xFEDD),(0xFEDE),(0xFEDF),(0xFEE0),
+(0xFEE1),(0xFEE2),(0xFEE3),(0xFEE4),(0xFEE5),(0xFEE6),(0xFEE7),(0xFEE8),
+(0xFEE9),(0xFEEA),(0xFEEB),(0xFEEC),(0xFEED),(0xFEEE),(0xFEEF),(0xFEF0),
+(0xFEF1),(0xFEF2),(0xFEF3),(0xFEF4),(0xFEF5),(0xFEF6),(0xFEF7),(0xFEF8),
+(0xFEF9),(0xFEFA),(0xFEFB),(0xFEFC),(0xFEFD),(0xFEFE),
+(0x8FF5A1),(0x8FF5A2),(0x8FF5A3),(0x8FF5A4),(0x8FF5A5),(0x8FF5A6),(0x8FF5A7),(0x8FF5A8),
+(0x8FF5A9),(0x8FF5AA),(0x8FF5AB),(0x8FF5AC),(0x8FF5AD),(0x8FF5AE),(0x8FF5AF),(0x8FF5B0),
+(0x8FF5B1),(0x8FF5B2),(0x8FF5B3),(0x8FF5B4),(0x8FF5B5),(0x8FF5B6),(0x8FF5B7),(0x8FF5B8),
+(0x8FF5B9),(0x8FF5BA),(0x8FF5BB),(0x8FF5BC),(0x8FF5BD),(0x8FF5BE),(0x8FF5BF),(0x8FF5C0),
+(0x8FF5C1),(0x8FF5C2),(0x8FF5C3),(0x8FF5C4),(0x8FF5C5),(0x8FF5C6),(0x8FF5C7),(0x8FF5C8),
+(0x8FF5C9),(0x8FF5CA),(0x8FF5CB),(0x8FF5CC),(0x8FF5CD),(0x8FF5CE),(0x8FF5CF),(0x8FF5D0),
+(0x8FF5D1),(0x8FF5D2),(0x8FF5D3),(0x8FF5D4),(0x8FF5D5),(0x8FF5D6),(0x8FF5D7),(0x8FF5D8),
+(0x8FF5D9),(0x8FF5DA),(0x8FF5DB),(0x8FF5DC),(0x8FF5DD),(0x8FF5DE),(0x8FF5DF),(0x8FF5E0),
+(0x8FF5E1),(0x8FF5E2),(0x8FF5E3),(0x8FF5E4),(0x8FF5E5),(0x8FF5E6),(0x8FF5E7),(0x8FF5E8),
+(0x8FF5E9),(0x8FF5EA),(0x8FF5EB),(0x8FF5EC),(0x8FF5ED),(0x8FF5EE),(0x8FF5EF),(0x8FF5F0),
+(0x8FF5F1),(0x8FF5F2),(0x8FF5F3),(0x8FF5F4),(0x8FF5F5),(0x8FF5F6),(0x8FF5F7),(0x8FF5F8),
+(0x8FF5F9),(0x8FF5FA),(0x8FF5FB),(0x8FF5FC),(0x8FF5FD),(0x8FF5FE),
+(0x8FF6A1),(0x8FF6A2),(0x8FF6A3),(0x8FF6A4),(0x8FF6A5),(0x8FF6A6),(0x8FF6A7),(0x8FF6A8),
+(0x8FF6A9),(0x8FF6AA),(0x8FF6AB),(0x8FF6AC),(0x8FF6AD),(0x8FF6AE),(0x8FF6AF),(0x8FF6B0),
+(0x8FF6B1),(0x8FF6B2),(0x8FF6B3),(0x8FF6B4),(0x8FF6B5),(0x8FF6B6),(0x8FF6B7),(0x8FF6B8),
+(0x8FF6B9),(0x8FF6BA),(0x8FF6BB),(0x8FF6BC),(0x8FF6BD),(0x8FF6BE),(0x8FF6BF),(0x8FF6C0),
+(0x8FF6C1),(0x8FF6C2),(0x8FF6C3),(0x8FF6C4),(0x8FF6C5),(0x8FF6C6),(0x8FF6C7),(0x8FF6C8),
+(0x8FF6C9),(0x8FF6CA),(0x8FF6CB),(0x8FF6CC),(0x8FF6CD),(0x8FF6CE),(0x8FF6CF),(0x8FF6D0),
+(0x8FF6D1),(0x8FF6D2),(0x8FF6D3),(0x8FF6D4),(0x8FF6D5),(0x8FF6D6),(0x8FF6D7),(0x8FF6D8),
+(0x8FF6D9),(0x8FF6DA),(0x8FF6DB),(0x8FF6DC),(0x8FF6DD),(0x8FF6DE),(0x8FF6DF),(0x8FF6E0),
+(0x8FF6E1),(0x8FF6E2),(0x8FF6E3),(0x8FF6E4),(0x8FF6E5),(0x8FF6E6),(0x8FF6E7),(0x8FF6E8),
+(0x8FF6E9),(0x8FF6EA),(0x8FF6EB),(0x8FF6EC),(0x8FF6ED),(0x8FF6EE),(0x8FF6EF),(0x8FF6F0),
+(0x8FF6F1),(0x8FF6F2),(0x8FF6F3),(0x8FF6F4),(0x8FF6F5),(0x8FF6F6),(0x8FF6F7),(0x8FF6F8),
+(0x8FF6F9),(0x8FF6FA),(0x8FF6FB),(0x8FF6FC),(0x8FF6FD),(0x8FF6FE),
+(0x8FF7A1),(0x8FF7A2),(0x8FF7A3),(0x8FF7A4),(0x8FF7A5),(0x8FF7A6),(0x8FF7A7),(0x8FF7A8),
+(0x8FF7A9),(0x8FF7AA),(0x8FF7AB),(0x8FF7AC),(0x8FF7AD),(0x8FF7AE),(0x8FF7AF),(0x8FF7B0),
+(0x8FF7B1),(0x8FF7B2),(0x8FF7B3),(0x8FF7B4),(0x8FF7B5),(0x8FF7B6),(0x8FF7B7),(0x8FF7B8),
+(0x8FF7B9),(0x8FF7BA),(0x8FF7BB),(0x8FF7BC),(0x8FF7BD),(0x8FF7BE),(0x8FF7BF),(0x8FF7C0),
+(0x8FF7C1),(0x8FF7C2),(0x8FF7C3),(0x8FF7C4),(0x8FF7C5),(0x8FF7C6),(0x8FF7C7),(0x8FF7C8),
+(0x8FF7C9),(0x8FF7CA),(0x8FF7CB),(0x8FF7CC),(0x8FF7CD),(0x8FF7CE),(0x8FF7CF),(0x8FF7D0),
+(0x8FF7D1),(0x8FF7D2),(0x8FF7D3),(0x8FF7D4),(0x8FF7D5),(0x8FF7D6),(0x8FF7D7),(0x8FF7D8),
+(0x8FF7D9),(0x8FF7DA),(0x8FF7DB),(0x8FF7DC),(0x8FF7DD),(0x8FF7DE),(0x8FF7DF),(0x8FF7E0),
+(0x8FF7E1),(0x8FF7E2),(0x8FF7E3),(0x8FF7E4),(0x8FF7E5),(0x8FF7E6),(0x8FF7E7),(0x8FF7E8),
+(0x8FF7E9),(0x8FF7EA),(0x8FF7EB),(0x8FF7EC),(0x8FF7ED),(0x8FF7EE),(0x8FF7EF),(0x8FF7F0),
+(0x8FF7F1),(0x8FF7F2),(0x8FF7F3),(0x8FF7F4),(0x8FF7F5),(0x8FF7F6),(0x8FF7F7),(0x8FF7F8),
+(0x8FF7F9),(0x8FF7FA),(0x8FF7FB),(0x8FF7FC),(0x8FF7FD),(0x8FF7FE),
+(0x8FF8A1),(0x8FF8A2),(0x8FF8A3),(0x8FF8A4),(0x8FF8A5),(0x8FF8A6),(0x8FF8A7),(0x8FF8A8),
+(0x8FF8A9),(0x8FF8AA),(0x8FF8AB),(0x8FF8AC),(0x8FF8AD),(0x8FF8AE),(0x8FF8AF),(0x8FF8B0),
+(0x8FF8B1),(0x8FF8B2),(0x8FF8B3),(0x8FF8B4),(0x8FF8B5),(0x8FF8B6),(0x8FF8B7),(0x8FF8B8),
+(0x8FF8B9),(0x8FF8BA),(0x8FF8BB),(0x8FF8BC),(0x8FF8BD),(0x8FF8BE),(0x8FF8BF),(0x8FF8C0),
+(0x8FF8C1),(0x8FF8C2),(0x8FF8C3),(0x8FF8C4),(0x8FF8C5),(0x8FF8C6),(0x8FF8C7),(0x8FF8C8),
+(0x8FF8C9),(0x8FF8CA),(0x8FF8CB),(0x8FF8CC),(0x8FF8CD),(0x8FF8CE),(0x8FF8CF),(0x8FF8D0),
+(0x8FF8D1),(0x8FF8D2),(0x8FF8D3),(0x8FF8D4),(0x8FF8D5),(0x8FF8D6),(0x8FF8D7),(0x8FF8D8),
+(0x8FF8D9),(0x8FF8DA),(0x8FF8DB),(0x8FF8DC),(0x8FF8DD),(0x8FF8DE),(0x8FF8DF),(0x8FF8E0),
+(0x8FF8E1),(0x8FF8E2),(0x8FF8E3),(0x8FF8E4),(0x8FF8E5),(0x8FF8E6),(0x8FF8E7),(0x8FF8E8),
+(0x8FF8E9),(0x8FF8EA),(0x8FF8EB),(0x8FF8EC),(0x8FF8ED),(0x8FF8EE),(0x8FF8EF),(0x8FF8F0),
+(0x8FF8F1),(0x8FF8F2),(0x8FF8F3),(0x8FF8F4),(0x8FF8F5),(0x8FF8F6),(0x8FF8F7),(0x8FF8F8),
+(0x8FF8F9),(0x8FF8FA),(0x8FF8FB),(0x8FF8FC),(0x8FF8FD),(0x8FF8FE),
+(0x8FF9A1),(0x8FF9A2),(0x8FF9A3),(0x8FF9A4),(0x8FF9A5),(0x8FF9A6),(0x8FF9A7),(0x8FF9A8),
+(0x8FF9A9),(0x8FF9AA),(0x8FF9AB),(0x8FF9AC),(0x8FF9AD),(0x8FF9AE),(0x8FF9AF),(0x8FF9B0),
+(0x8FF9B1),(0x8FF9B2),(0x8FF9B3),(0x8FF9B4),(0x8FF9B5),(0x8FF9B6),(0x8FF9B7),(0x8FF9B8),
+(0x8FF9B9),(0x8FF9BA),(0x8FF9BB),(0x8FF9BC),(0x8FF9BD),(0x8FF9BE),(0x8FF9BF),(0x8FF9C0),
+(0x8FF9C1),(0x8FF9C2),(0x8FF9C3),(0x8FF9C4),(0x8FF9C5),(0x8FF9C6),(0x8FF9C7),(0x8FF9C8),
+(0x8FF9C9),(0x8FF9CA),(0x8FF9CB),(0x8FF9CC),(0x8FF9CD),(0x8FF9CE),(0x8FF9CF),(0x8FF9D0),
+(0x8FF9D1),(0x8FF9D2),(0x8FF9D3),(0x8FF9D4),(0x8FF9D5),(0x8FF9D6),(0x8FF9D7),(0x8FF9D8),
+(0x8FF9D9),(0x8FF9DA),(0x8FF9DB),(0x8FF9DC),(0x8FF9DD),(0x8FF9DE),(0x8FF9DF),(0x8FF9E0),
+(0x8FF9E1),(0x8FF9E2),(0x8FF9E3),(0x8FF9E4),(0x8FF9E5),(0x8FF9E6),(0x8FF9E7),(0x8FF9E8),
+(0x8FF9E9),(0x8FF9EA),(0x8FF9EB),(0x8FF9EC),(0x8FF9ED),(0x8FF9EE),(0x8FF9EF),(0x8FF9F0),
+(0x8FF9F1),(0x8FF9F2),(0x8FF9F3),(0x8FF9F4),(0x8FF9F5),(0x8FF9F6),(0x8FF9F7),(0x8FF9F8),
+(0x8FF9F9),(0x8FF9FA),(0x8FF9FB),(0x8FF9FC),(0x8FF9FD),(0x8FF9FE),
+(0x8FFAA1),(0x8FFAA2),(0x8FFAA3),(0x8FFAA4),(0x8FFAA5),(0x8FFAA6),(0x8FFAA7),(0x8FFAA8),
+(0x8FFAA9),(0x8FFAAA),(0x8FFAAB),(0x8FFAAC),(0x8FFAAD),(0x8FFAAE),(0x8FFAAF),(0x8FFAB0),
+(0x8FFAB1),(0x8FFAB2),(0x8FFAB3),(0x8FFAB4),(0x8FFAB5),(0x8FFAB6),(0x8FFAB7),(0x8FFAB8),
+(0x8FFAB9),(0x8FFABA),(0x8FFABB),(0x8FFABC),(0x8FFABD),(0x8FFABE),(0x8FFABF),(0x8FFAC0),
+(0x8FFAC1),(0x8FFAC2),(0x8FFAC3),(0x8FFAC4),(0x8FFAC5),(0x8FFAC6),(0x8FFAC7),(0x8FFAC8),
+(0x8FFAC9),(0x8FFACA),(0x8FFACB),(0x8FFACC),(0x8FFACD),(0x8FFACE),(0x8FFACF),(0x8FFAD0),
+(0x8FFAD1),(0x8FFAD2),(0x8FFAD3),(0x8FFAD4),(0x8FFAD5),(0x8FFAD6),(0x8FFAD7),(0x8FFAD8),
+(0x8FFAD9),(0x8FFADA),(0x8FFADB),(0x8FFADC),(0x8FFADD),(0x8FFADE),(0x8FFADF),(0x8FFAE0),
+(0x8FFAE1),(0x8FFAE2),(0x8FFAE3),(0x8FFAE4),(0x8FFAE5),(0x8FFAE6),(0x8FFAE7),(0x8FFAE8),
+(0x8FFAE9),(0x8FFAEA),(0x8FFAEB),(0x8FFAEC),(0x8FFAED),(0x8FFAEE),(0x8FFAEF),(0x8FFAF0),
+(0x8FFAF1),(0x8FFAF2),(0x8FFAF3),(0x8FFAF4),(0x8FFAF5),(0x8FFAF6),(0x8FFAF7),(0x8FFAF8),
+(0x8FFAF9),(0x8FFAFA),(0x8FFAFB),(0x8FFAFC),(0x8FFAFD),(0x8FFAFE),
+(0x8FFBA1),(0x8FFBA2),(0x8FFBA3),(0x8FFBA4),(0x8FFBA5),(0x8FFBA6),(0x8FFBA7),(0x8FFBA8),
+(0x8FFBA9),(0x8FFBAA),(0x8FFBAB),(0x8FFBAC),(0x8FFBAD),(0x8FFBAE),(0x8FFBAF),(0x8FFBB0),
+(0x8FFBB1),(0x8FFBB2),(0x8FFBB3),(0x8FFBB4),(0x8FFBB5),(0x8FFBB6),(0x8FFBB7),(0x8FFBB8),
+(0x8FFBB9),(0x8FFBBA),(0x8FFBBB),(0x8FFBBC),(0x8FFBBD),(0x8FFBBE),(0x8FFBBF),(0x8FFBC0),
+(0x8FFBC1),(0x8FFBC2),(0x8FFBC3),(0x8FFBC4),(0x8FFBC5),(0x8FFBC6),(0x8FFBC7),(0x8FFBC8),
+(0x8FFBC9),(0x8FFBCA),(0x8FFBCB),(0x8FFBCC),(0x8FFBCD),(0x8FFBCE),(0x8FFBCF),(0x8FFBD0),
+(0x8FFBD1),(0x8FFBD2),(0x8FFBD3),(0x8FFBD4),(0x8FFBD5),(0x8FFBD6),(0x8FFBD7),(0x8FFBD8),
+(0x8FFBD9),(0x8FFBDA),(0x8FFBDB),(0x8FFBDC),(0x8FFBDD),(0x8FFBDE),(0x8FFBDF),(0x8FFBE0),
+(0x8FFBE1),(0x8FFBE2),(0x8FFBE3),(0x8FFBE4),(0x8FFBE5),(0x8FFBE6),(0x8FFBE7),(0x8FFBE8),
+(0x8FFBE9),(0x8FFBEA),(0x8FFBEB),(0x8FFBEC),(0x8FFBED),(0x8FFBEE),(0x8FFBEF),(0x8FFBF0),
+(0x8FFBF1),(0x8FFBF2),(0x8FFBF3),(0x8FFBF4),(0x8FFBF5),(0x8FFBF6),(0x8FFBF7),(0x8FFBF8),
+(0x8FFBF9),(0x8FFBFA),(0x8FFBFB),(0x8FFBFC),(0x8FFBFD),(0x8FFBFE),
+(0x8FFCA1),(0x8FFCA2),(0x8FFCA3),(0x8FFCA4),(0x8FFCA5),(0x8FFCA6),(0x8FFCA7),(0x8FFCA8),
+(0x8FFCA9),(0x8FFCAA),(0x8FFCAB),(0x8FFCAC),(0x8FFCAD),(0x8FFCAE),(0x8FFCAF),(0x8FFCB0),
+(0x8FFCB1),(0x8FFCB2),(0x8FFCB3),(0x8FFCB4),(0x8FFCB5),(0x8FFCB6),(0x8FFCB7),(0x8FFCB8),
+(0x8FFCB9),(0x8FFCBA),(0x8FFCBB),(0x8FFCBC),(0x8FFCBD),(0x8FFCBE),(0x8FFCBF),(0x8FFCC0),
+(0x8FFCC1),(0x8FFCC2),(0x8FFCC3),(0x8FFCC4),(0x8FFCC5),(0x8FFCC6),(0x8FFCC7),(0x8FFCC8),
+(0x8FFCC9),(0x8FFCCA),(0x8FFCCB),(0x8FFCCC),(0x8FFCCD),(0x8FFCCE),(0x8FFCCF),(0x8FFCD0),
+(0x8FFCD1),(0x8FFCD2),(0x8FFCD3),(0x8FFCD4),(0x8FFCD5),(0x8FFCD6),(0x8FFCD7),(0x8FFCD8),
+(0x8FFCD9),(0x8FFCDA),(0x8FFCDB),(0x8FFCDC),(0x8FFCDD),(0x8FFCDE),(0x8FFCDF),(0x8FFCE0),
+(0x8FFCE1),(0x8FFCE2),(0x8FFCE3),(0x8FFCE4),(0x8FFCE5),(0x8FFCE6),(0x8FFCE7),(0x8FFCE8),
+(0x8FFCE9),(0x8FFCEA),(0x8FFCEB),(0x8FFCEC),(0x8FFCED),(0x8FFCEE),(0x8FFCEF),(0x8FFCF0),
+(0x8FFCF1),(0x8FFCF2),(0x8FFCF3),(0x8FFCF4),(0x8FFCF5),(0x8FFCF6),(0x8FFCF7),(0x8FFCF8),
+(0x8FFCF9),(0x8FFCFA),(0x8FFCFB),(0x8FFCFC),(0x8FFCFD),(0x8FFCFE),
+(0x8FFDA1),(0x8FFDA2),(0x8FFDA3),(0x8FFDA4),(0x8FFDA5),(0x8FFDA6),(0x8FFDA7),(0x8FFDA8),
+(0x8FFDA9),(0x8FFDAA),(0x8FFDAB),(0x8FFDAC),(0x8FFDAD),(0x8FFDAE),(0x8FFDAF),(0x8FFDB0),
+(0x8FFDB1),(0x8FFDB2),(0x8FFDB3),(0x8FFDB4),(0x8FFDB5),(0x8FFDB6),(0x8FFDB7),(0x8FFDB8),
+(0x8FFDB9),(0x8FFDBA),(0x8FFDBB),(0x8FFDBC),(0x8FFDBD),(0x8FFDBE),(0x8FFDBF),(0x8FFDC0),
+(0x8FFDC1),(0x8FFDC2),(0x8FFDC3),(0x8FFDC4),(0x8FFDC5),(0x8FFDC6),(0x8FFDC7),(0x8FFDC8),
+(0x8FFDC9),(0x8FFDCA),(0x8FFDCB),(0x8FFDCC),(0x8FFDCD),(0x8FFDCE),(0x8FFDCF),(0x8FFDD0),
+(0x8FFDD1),(0x8FFDD2),(0x8FFDD3),(0x8FFDD4),(0x8FFDD5),(0x8FFDD6),(0x8FFDD7),(0x8FFDD8),
+(0x8FFDD9),(0x8FFDDA),(0x8FFDDB),(0x8FFDDC),(0x8FFDDD),(0x8FFDDE),(0x8FFDDF),(0x8FFDE0),
+(0x8FFDE1),(0x8FFDE2),(0x8FFDE3),(0x8FFDE4),(0x8FFDE5),(0x8FFDE6),(0x8FFDE7),(0x8FFDE8),
+(0x8FFDE9),(0x8FFDEA),(0x8FFDEB),(0x8FFDEC),(0x8FFDED),(0x8FFDEE),(0x8FFDEF),(0x8FFDF0),
+(0x8FFDF1),(0x8FFDF2),(0x8FFDF3),(0x8FFDF4),(0x8FFDF5),(0x8FFDF6),(0x8FFDF7),(0x8FFDF8),
+(0x8FFDF9),(0x8FFDFA),(0x8FFDFB),(0x8FFDFC),(0x8FFDFD),(0x8FFDFE),
+(0x8FFEA1),(0x8FFEA2),(0x8FFEA3),(0x8FFEA4),(0x8FFEA5),(0x8FFEA6),(0x8FFEA7),(0x8FFEA8),
+(0x8FFEA9),(0x8FFEAA),(0x8FFEAB),(0x8FFEAC),(0x8FFEAD),(0x8FFEAE),(0x8FFEAF),(0x8FFEB0),
+(0x8FFEB1),(0x8FFEB2),(0x8FFEB3),(0x8FFEB4),(0x8FFEB5),(0x8FFEB6),(0x8FFEB7),(0x8FFEB8),
+(0x8FFEB9),(0x8FFEBA),(0x8FFEBB),(0x8FFEBC),(0x8FFEBD),(0x8FFEBE),(0x8FFEBF),(0x8FFEC0),
+(0x8FFEC1),(0x8FFEC2),(0x8FFEC3),(0x8FFEC4),(0x8FFEC5),(0x8FFEC6),(0x8FFEC7),(0x8FFEC8),
+(0x8FFEC9),(0x8FFECA),(0x8FFECB),(0x8FFECC),(0x8FFECD),(0x8FFECE),(0x8FFECF),(0x8FFED0),
+(0x8FFED1),(0x8FFED2),(0x8FFED3),(0x8FFED4),(0x8FFED5),(0x8FFED6),(0x8FFED7),(0x8FFED8),
+(0x8FFED9),(0x8FFEDA),(0x8FFEDB),(0x8FFEDC),(0x8FFEDD),(0x8FFEDE),(0x8FFEDF),(0x8FFEE0),
+(0x8FFEE1),(0x8FFEE2),(0x8FFEE3),(0x8FFEE4),(0x8FFEE5),(0x8FFEE6),(0x8FFEE7),(0x8FFEE8),
+(0x8FFEE9),(0x8FFEEA),(0x8FFEEB),(0x8FFEEC),(0x8FFEED),(0x8FFEEE),(0x8FFEEF),(0x8FFEF0),
+(0x8FFEF1),(0x8FFEF2),(0x8FFEF3),(0x8FFEF4),(0x8FFEF5),(0x8FFEF6),(0x8FFEF7),(0x8FFEF8),
+(0x8FFEF9),(0x8FFEFA),(0x8FFEFB),(0x8FFEFC),(0x8FFEFD),(0x8FFEFE);
+SELECT HEX(c1) FROM t1;
+HEX(c1)
+5C
+7E
+A1B1
+A1BD
+A1C0
+A1C1
+A1C2
+A1DD
+A1F1
+A1F2
+A1EF
+A2CC
+8FA2B7
+8FA2C3
+ADA1
+ADA2
+ADA3
+ADA4
+ADA5
+ADA6
+ADA7
+ADA8
+ADA9
+ADAA
+ADAB
+ADAC
+ADAD
+ADAE
+ADAF
+ADB0
+ADB1
+ADB2
+ADB3
+ADB4
+ADB5
+ADB6
+ADB7
+ADB8
+ADB9
+ADBA
+ADBB
+ADBC
+ADBD
+ADBE
+ADC0
+ADC1
+ADC2
+ADC3
+ADC4
+ADC5
+ADC6
+ADC7
+ADC8
+ADC9
+ADCA
+ADCB
+ADCC
+ADCD
+ADCE
+ADCF
+ADD0
+ADD1
+ADD2
+ADD3
+ADD4
+ADD5
+ADD6
+ADDF
+ADE0
+ADE1
+ADE2
+ADE3
+ADE4
+ADE5
+ADE6
+ADE7
+ADE8
+ADE9
+ADEA
+ADEB
+ADEC
+ADED
+ADEE
+ADEF
+ADF0
+ADF1
+ADF2
+ADF3
+ADF4
+ADF5
+ADF6
+ADF7
+ADF8
+ADF9
+ADFA
+ADFB
+ADFC
+8FF3F3
+8FF3F4
+8FF3F5
+8FF3F6
+8FF3F7
+8FF3F8
+8FF3F9
+8FF3FA
+8FF3FB
+8FF3FC
+8FF3FD
+8FF3FE
+8FF4A1
+8FF4A2
+8FF4A3
+8FF4A4
+8FF4A5
+8FF4A6
+8FF4A7
+8FF4A8
+A2CC
+8FA2C3
+8FF4A9
+8FF4AA
+8FF4AB
+8FF4AC
+8FF4AD
+A2E8
+8FD4E3
+8FDCDF
+8FE4E9
+8FE3F8
+8FD9A1
+8FB1BB
+8FF4AE
+8FC2AD
+8FC3FC
+8FE4D0
+8FC2BF
+8FBCF4
+8FB0A9
+8FB0C8
+8FF4AF
+8FB0D2
+8FB0D4
+8FB0E3
+8FB0EE
+8FB1A7
+8FB1A3
+8FB1AC
+8FB1A9
+8FB1BE
+8FB1DF
+8FB1D8
+8FB1C8
+8FB1D7
+8FB1E3
+8FB1F4
+8FB1E1
+8FB2A3
+8FF4B0
+8FB2BB
+8FB2E6
+8FB2ED
+8FB2F5
+8FB2FC
+8FF4B1
+8FB3B5
+8FB3D8
+8FB3DB
+8FB3E5
+8FB3EE
+8FB3FB
+8FF4B2
+8FF4B3
+8FB4C0
+8FB4C7
+8FB4D0
+8FB4DE
+8FF4B4
+8FB5AA
+8FF4B5
+8FB5AF
+8FB5C4
+8FB5E8
+8FF4B6
+8FB7C2
+8FB7E4
+8FB7E8
+8FB7E7
+8FF4B7
+8FF4B8
+8FF4B9
+8FB8CE
+8FB8E1
+8FB8F5
+8FB8F7
+8FB8F8
+8FB8FC
+8FB9AF
+8FB9B7
+8FBABE
+8FBADB
+8FCDAA
+8FBAE1
+8FF4BA
+8FBAEB
+8FBBB3
+8FBBB8
+8FF4BB
+8FBBCA
+8FF4BC
+8FF4BD
+8FBBD0
+8FBBDE
+8FBBF4
+8FBBF5
+8FBBF9
+8FBCE4
+8FBCED
+8FBCFE
+8FF4BE
+8FBDC2
+8FBDE7
+8FF4BF
+8FBDF0
+8FBEB0
+8FBEAC
+8FF4C0
+8FBEB3
+8FBEBD
+8FBECD
+8FBEC9
+8FBEE4
+8FBFA8
+8FBFC9
+8FC0C4
+8FC0E4
+8FC0F4
+8FC1A6
+8FF4C1
+8FC1F5
+8FC1FC
+8FF4C2
+8FC1F8
+8FC2AB
+8FC2A1
+8FC2A5
+8FF4C3
+8FC2B8
+8FC2BA
+8FF4C4
+8FC2C4
+8FC2D2
+8FC2D7
+8FC2DB
+8FC2DE
+8FC2ED
+8FC2F0
+8FF4C5
+8FC3A1
+8FC3B5
+8FC3C9
+8FC3B9
+8FF4C6
+8FC3D8
+8FC3FE
+8FF4C7
+8FC4CC
+8FF4C8
+8FC4D9
+8FC4EA
+8FC4FD
+8FF4C9
+8FC5A7
+8FC5B5
+8FC5B6
+8FF4CA
+8FC5D5
+8FC6B8
+8FC6D7
+8FC6E0
+8FC6EA
+8FC6E3
+8FC7A1
+8FC7AB
+8FC7C7
+8FC7C3
+8FC7CB
+8FC7CF
+8FC7D9
+8FF4CB
+8FF4CC
+8FC7E6
+8FC7EE
+8FC7FC
+8FC7EB
+8FC7F0
+8FC8B1
+8FC8E5
+8FC8F8
+8FC9A6
+8FC9AB
+8FC9AD
+8FF4CD
+8FC9CA
+8FC9D3
+8FC9E9
+8FC9E3
+8FC9FC
+8FC9F4
+8FC9F5
+8FF4CE
+8FCAB3
+8FCABD
+8FCAEF
+8FCAF1
+8FCBAE
+8FF4CF
+8FCBCA
+8FCBE6
+8FCBEA
+8FCBF0
+8FCBF4
+8FCBEE
+8FCCA5
+8FCBF9
+8FCCAB
+8FCCAE
+8FCCAD
+8FCCB2
+8FCCC2
+8FCCD0
+8FCCD9
+8FF4D0
+8FCDBB
+8FF4D1
+8FCEBB
+8FF4D2
+8FCEBA
+8FCEC3
+8FF4D3
+8FCEF2
+8FB3DD
+8FCFD5
+8FCFE2
+8FCFE9
+8FCFED
+8FF4D4
+8FF4D5
+8FF4D6
+8FF4D7
+8FD0E5
+8FF4D8
+8FD0E9
+8FD1E8
+8FF4D9
+8FF4DA
+8FD1EC
+8FD2BB
+8FF4DB
+8FD3E1
+8FD3E8
+8FD4A7
+8FF4DC
+8FF4DD
+8FD4D4
+8FD4F2
+8FD5AE
+8FF4DE
+8FD7DE
+8FF4DF
+8FD8A2
+8FD8B7
+8FD8C1
+8FD8D1
+8FD8F4
+8FD9C6
+8FD9C8
+8FD9D1
+8FF4E0
+8FF4E1
+8FF4E2
+8FF4E3
+8FF4E4
+8FDCD3
+8FDDC8
+8FDDD4
+8FDDEA
+8FDDFA
+8FDEA4
+8FDEB0
+8FF4E5
+8FDEB5
+8FDECB
+8FF4E6
+8FDFB9
+8FF4E7
+8FDFC3
+8FF4E8
+8FF4E9
+8FE0D9
+8FF4EA
+8FF4EB
+8FE1E2
+8FF4EC
+8FF4ED
+8FF4EE
+8FE2C7
+8FE3A8
+8FE3A6
+8FE3A9
+8FE3AF
+8FE3B0
+8FE3AA
+8FE3AB
+8FE3BC
+8FE3C1
+8FE3BF
+8FE3D5
+8FE3D8
+8FE3D6
+8FE3DF
+8FE3E3
+8FE3E1
+8FE3D4
+8FE3E9
+8FE4A6
+8FE3F1
+8FE3F2
+8FE4CB
+8FE4C1
+8FE4C3
+8FE4BE
+8FF4EF
+8FE4C0
+8FE4C7
+8FE4BF
+8FE4E0
+8FE4DE
+8FE4D1
+8FF4F0
+8FE4DC
+8FE4D2
+8FE4DB
+8FE4D4
+8FE4FA
+8FE4EF
+8FE5B3
+8FE5BF
+8FE5C9
+8FE5D0
+8FE5E2
+8FE5EA
+8FE5EB
+8FF4F1
+8FF4F2
+8FF4F3
+8FE6E8
+8FE6EF
+8FE7AC
+8FF4F4
+8FE7AE
+8FF4F5
+8FE7B1
+8FF4F6
+8FE7B2
+8FE8B1
+8FE8B6
+8FF4F7
+8FF4F8
+8FE8DD
+8FF4F9
+8FF4FA
+8FE9D1
+8FF4FB
+8FE9ED
+8FEACD
+8FF4FC
+8FEADB
+8FEAE6
+8FEAEA
+8FEBA5
+8FEBFB
+8FEBFA
+8FF4FD
+8FECD6
+8FF4FE
+F5A1
+F5A2
+F5A3
+F5A4
+F5A5
+F5A6
+F5A7
+F5A8
+F5A9
+F5AA
+F5AB
+F5AC
+F5AD
+F5AE
+F5AF
+F5B0
+F5B1
+F5B2
+F5B3
+F5B4
+F5B5
+F5B6
+F5B7
+F5B8
+F5B9
+F5BA
+F5BB
+F5BC
+F5BD
+F5BE
+F5BF
+F5C0
+F5C1
+F5C2
+F5C3
+F5C4
+F5C5
+F5C6
+F5C7
+F5C8
+F5C9
+F5CA
+F5CB
+F5CC
+F5CD
+F5CE
+F5CF
+F5D0
+F5D1
+F5D2
+F5D3
+F5D4
+F5D5
+F5D6
+F5D7
+F5D8
+F5D9
+F5DA
+F5DB
+F5DC
+F5DD
+F5DE
+F5DF
+F5E0
+F5E1
+F5E2
+F5E3
+F5E4
+F5E5
+F5E6
+F5E7
+F5E8
+F5E9
+F5EA
+F5EB
+F5EC
+F5ED
+F5EE
+F5EF
+F5F0
+F5F1
+F5F2
+F5F3
+F5F4
+F5F5
+F5F6
+F5F7
+F5F8
+F5F9
+F5FA
+F5FB
+F5FC
+F5FD
+F5FE
+F6A1
+F6A2
+F6A3
+F6A4
+F6A5
+F6A6
+F6A7
+F6A8
+F6A9
+F6AA
+F6AB
+F6AC
+F6AD
+F6AE
+F6AF
+F6B0
+F6B1
+F6B2
+F6B3
+F6B4
+F6B5
+F6B6
+F6B7
+F6B8
+F6B9
+F6BA
+F6BB
+F6BC
+F6BD
+F6BE
+F6BF
+F6C0
+F6C1
+F6C2
+F6C3
+F6C4
+F6C5
+F6C6
+F6C7
+F6C8
+F6C9
+F6CA
+F6CB
+F6CC
+F6CD
+F6CE
+F6CF
+F6D0
+F6D1
+F6D2
+F6D3
+F6D4
+F6D5
+F6D6
+F6D7
+F6D8
+F6D9
+F6DA
+F6DB
+F6DC
+F6DD
+F6DE
+F6DF
+F6E0
+F6E1
+F6E2
+F6E3
+F6E4
+F6E5
+F6E6
+F6E7
+F6E8
+F6E9
+F6EA
+F6EB
+F6EC
+F6ED
+F6EE
+F6EF
+F6F0
+F6F1
+F6F2
+F6F3
+F6F4
+F6F5
+F6F6
+F6F7
+F6F8
+F6F9
+F6FA
+F6FB
+F6FC
+F6FD
+F6FE
+F7A1
+F7A2
+F7A3
+F7A4
+F7A5
+F7A6
+F7A7
+F7A8
+F7A9
+F7AA
+F7AB
+F7AC
+F7AD
+F7AE
+F7AF
+F7B0
+F7B1
+F7B2
+F7B3
+F7B4
+F7B5
+F7B6
+F7B7
+F7B8
+F7B9
+F7BA
+F7BB
+F7BC
+F7BD
+F7BE
+F7BF
+F7C0
+F7C1
+F7C2
+F7C3
+F7C4
+F7C5
+F7C6
+F7C7
+F7C8
+F7C9
+F7CA
+F7CB
+F7CC
+F7CD
+F7CE
+F7CF
+F7D0
+F7D1
+F7D2
+F7D3
+F7D4
+F7D5
+F7D6
+F7D7
+F7D8
+F7D9
+F7DA
+F7DB
+F7DC
+F7DD
+F7DE
+F7DF
+F7E0
+F7E1
+F7E2
+F7E3
+F7E4
+F7E5
+F7E6
+F7E7
+F7E8
+F7E9
+F7EA
+F7EB
+F7EC
+F7ED
+F7EE
+F7EF
+F7F0
+F7F1
+F7F2
+F7F3
+F7F4
+F7F5
+F7F6
+F7F7
+F7F8
+F7F9
+F7FA
+F7FB
+F7FC
+F7FD
+F7FE
+F8A1
+F8A2
+F8A3
+F8A4
+F8A5
+F8A6
+F8A7
+F8A8
+F8A9
+F8AA
+F8AB
+F8AC
+F8AD
+F8AE
+F8AF
+F8B0
+F8B1
+F8B2
+F8B3
+F8B4
+F8B5
+F8B6
+F8B7
+F8B8
+F8B9
+F8BA
+F8BB
+F8BC
+F8BD
+F8BE
+F8BF
+F8C0
+F8C1
+F8C2
+F8C3
+F8C4
+F8C5
+F8C6
+F8C7
+F8C8
+F8C9
+F8CA
+F8CB
+F8CC
+F8CD
+F8CE
+F8CF
+F8D0
+F8D1
+F8D2
+F8D3
+F8D4
+F8D5
+F8D6
+F8D7
+F8D8
+F8D9
+F8DA
+F8DB
+F8DC
+F8DD
+F8DE
+F8DF
+F8E0
+F8E1
+F8E2
+F8E3
+F8E4
+F8E5
+F8E6
+F8E7
+F8E8
+F8E9
+F8EA
+F8EB
+F8EC
+F8ED
+F8EE
+F8EF
+F8F0
+F8F1
+F8F2
+F8F3
+F8F4
+F8F5
+F8F6
+F8F7
+F8F8
+F8F9
+F8FA
+F8FB
+F8FC
+F8FD
+F8FE
+F9A1
+F9A2
+F9A3
+F9A4
+F9A5
+F9A6
+F9A7
+F9A8
+F9A9
+F9AA
+F9AB
+F9AC
+F9AD
+F9AE
+F9AF
+F9B0
+F9B1
+F9B2
+F9B3
+F9B4
+F9B5
+F9B6
+F9B7
+F9B8
+F9B9
+F9BA
+F9BB
+F9BC
+F9BD
+F9BE
+F9BF
+F9C0
+F9C1
+F9C2
+F9C3
+F9C4
+F9C5
+F9C6
+F9C7
+F9C8
+F9C9
+F9CA
+F9CB
+F9CC
+F9CD
+F9CE
+F9CF
+F9D0
+F9D1
+F9D2
+F9D3
+F9D4
+F9D5
+F9D6
+F9D7
+F9D8
+F9D9
+F9DA
+F9DB
+F9DC
+F9DD
+F9DE
+F9DF
+F9E0
+F9E1
+F9E2
+F9E3
+F9E4
+F9E5
+F9E6
+F9E7
+F9E8
+F9E9
+F9EA
+F9EB
+F9EC
+F9ED
+F9EE
+F9EF
+F9F0
+F9F1
+F9F2
+F9F3
+F9F4
+F9F5
+F9F6
+F9F7
+F9F8
+F9F9
+F9FA
+F9FB
+F9FC
+F9FD
+F9FE
+FAA1
+FAA2
+FAA3
+FAA4
+FAA5
+FAA6
+FAA7
+FAA8
+FAA9
+FAAA
+FAAB
+FAAC
+FAAD
+FAAE
+FAAF
+FAB0
+FAB1
+FAB2
+FAB3
+FAB4
+FAB5
+FAB6
+FAB7
+FAB8
+FAB9
+FABA
+FABB
+FABC
+FABD
+FABE
+FABF
+FAC0
+FAC1
+FAC2
+FAC3
+FAC4
+FAC5
+FAC6
+FAC7
+FAC8
+FAC9
+FACA
+FACB
+FACC
+FACD
+FACE
+FACF
+FAD0
+FAD1
+FAD2
+FAD3
+FAD4
+FAD5
+FAD6
+FAD7
+FAD8
+FAD9
+FADA
+FADB
+FADC
+FADD
+FADE
+FADF
+FAE0
+FAE1
+FAE2
+FAE3
+FAE4
+FAE5
+FAE6
+FAE7
+FAE8
+FAE9
+FAEA
+FAEB
+FAEC
+FAED
+FAEE
+FAEF
+FAF0
+FAF1
+FAF2
+FAF3
+FAF4
+FAF5
+FAF6
+FAF7
+FAF8
+FAF9
+FAFA
+FAFB
+FAFC
+FAFD
+FAFE
+FBA1
+FBA2
+FBA3
+FBA4
+FBA5
+FBA6
+FBA7
+FBA8
+FBA9
+FBAA
+FBAB
+FBAC
+FBAD
+FBAE
+FBAF
+FBB0
+FBB1
+FBB2
+FBB3
+FBB4
+FBB5
+FBB6
+FBB7
+FBB8
+FBB9
+FBBA
+FBBB
+FBBC
+FBBD
+FBBE
+FBBF
+FBC0
+FBC1
+FBC2
+FBC3
+FBC4
+FBC5
+FBC6
+FBC7
+FBC8
+FBC9
+FBCA
+FBCB
+FBCC
+FBCD
+FBCE
+FBCF
+FBD0
+FBD1
+FBD2
+FBD3
+FBD4
+FBD5
+FBD6
+FBD7
+FBD8
+FBD9
+FBDA
+FBDB
+FBDC
+FBDD
+FBDE
+FBDF
+FBE0
+FBE1
+FBE2
+FBE3
+FBE4
+FBE5
+FBE6
+FBE7
+FBE8
+FBE9
+FBEA
+FBEB
+FBEC
+FBED
+FBEE
+FBEF
+FBF0
+FBF1
+FBF2
+FBF3
+FBF4
+FBF5
+FBF6
+FBF7
+FBF8
+FBF9
+FBFA
+FBFB
+FBFC
+FBFD
+FBFE
+FCA1
+FCA2
+FCA3
+FCA4
+FCA5
+FCA6
+FCA7
+FCA8
+FCA9
+FCAA
+FCAB
+FCAC
+FCAD
+FCAE
+FCAF
+FCB0
+FCB1
+FCB2
+FCB3
+FCB4
+FCB5
+FCB6
+FCB7
+FCB8
+FCB9
+FCBA
+FCBB
+FCBC
+FCBD
+FCBE
+FCBF
+FCC0
+FCC1
+FCC2
+FCC3
+FCC4
+FCC5
+FCC6
+FCC7
+FCC8
+FCC9
+FCCA
+FCCB
+FCCC
+FCCD
+FCCE
+FCCF
+FCD0
+FCD1
+FCD2
+FCD3
+FCD4
+FCD5
+FCD6
+FCD7
+FCD8
+FCD9
+FCDA
+FCDB
+FCDC
+FCDD
+FCDE
+FCDF
+FCE0
+FCE1
+FCE2
+FCE3
+FCE4
+FCE5
+FCE6
+FCE7
+FCE8
+FCE9
+FCEA
+FCEB
+FCEC
+FCED
+FCEE
+FCEF
+FCF0
+FCF1
+FCF2
+FCF3
+FCF4
+FCF5
+FCF6
+FCF7
+FCF8
+FCF9
+FCFA
+FCFB
+FCFC
+FCFD
+FCFE
+FDA1
+FDA2
+FDA3
+FDA4
+FDA5
+FDA6
+FDA7
+FDA8
+FDA9
+FDAA
+FDAB
+FDAC
+FDAD
+FDAE
+FDAF
+FDB0
+FDB1
+FDB2
+FDB3
+FDB4
+FDB5
+FDB6
+FDB7
+FDB8
+FDB9
+FDBA
+FDBB
+FDBC
+FDBD
+FDBE
+FDBF
+FDC0
+FDC1
+FDC2
+FDC3
+FDC4
+FDC5
+FDC6
+FDC7
+FDC8
+FDC9
+FDCA
+FDCB
+FDCC
+FDCD
+FDCE
+FDCF
+FDD0
+FDD1
+FDD2
+FDD3
+FDD4
+FDD5
+FDD6
+FDD7
+FDD8
+FDD9
+FDDA
+FDDB
+FDDC
+FDDD
+FDDE
+FDDF
+FDE0
+FDE1
+FDE2
+FDE3
+FDE4
+FDE5
+FDE6
+FDE7
+FDE8
+FDE9
+FDEA
+FDEB
+FDEC
+FDED
+FDEE
+FDEF
+FDF0
+FDF1
+FDF2
+FDF3
+FDF4
+FDF5
+FDF6
+FDF7
+FDF8
+FDF9
+FDFA
+FDFB
+FDFC
+FDFD
+FDFE
+FEA1
+FEA2
+FEA3
+FEA4
+FEA5
+FEA6
+FEA7
+FEA8
+FEA9
+FEAA
+FEAB
+FEAC
+FEAD
+FEAE
+FEAF
+FEB0
+FEB1
+FEB2
+FEB3
+FEB4
+FEB5
+FEB6
+FEB7
+FEB8
+FEB9
+FEBA
+FEBB
+FEBC
+FEBD
+FEBE
+FEBF
+FEC0
+FEC1
+FEC2
+FEC3
+FEC4
+FEC5
+FEC6
+FEC7
+FEC8
+FEC9
+FECA
+FECB
+FECC
+FECD
+FECE
+FECF
+FED0
+FED1
+FED2
+FED3
+FED4
+FED5
+FED6
+FED7
+FED8
+FED9
+FEDA
+FEDB
+FEDC
+FEDD
+FEDE
+FEDF
+FEE0
+FEE1
+FEE2
+FEE3
+FEE4
+FEE5
+FEE6
+FEE7
+FEE8
+FEE9
+FEEA
+FEEB
+FEEC
+FEED
+FEEE
+FEEF
+FEF0
+FEF1
+FEF2
+FEF3
+FEF4
+FEF5
+FEF6
+FEF7
+FEF8
+FEF9
+FEFA
+FEFB
+FEFC
+FEFD
+FEFE
+8FF5A1
+8FF5A2
+8FF5A3
+8FF5A4
+8FF5A5
+8FF5A6
+8FF5A7
+8FF5A8
+8FF5A9
+8FF5AA
+8FF5AB
+8FF5AC
+8FF5AD
+8FF5AE
+8FF5AF
+8FF5B0
+8FF5B1
+8FF5B2
+8FF5B3
+8FF5B4
+8FF5B5
+8FF5B6
+8FF5B7
+8FF5B8
+8FF5B9
+8FF5BA
+8FF5BB
+8FF5BC
+8FF5BD
+8FF5BE
+8FF5BF
+8FF5C0
+8FF5C1
+8FF5C2
+8FF5C3
+8FF5C4
+8FF5C5
+8FF5C6
+8FF5C7
+8FF5C8
+8FF5C9
+8FF5CA
+8FF5CB
+8FF5CC
+8FF5CD
+8FF5CE
+8FF5CF
+8FF5D0
+8FF5D1
+8FF5D2
+8FF5D3
+8FF5D4
+8FF5D5
+8FF5D6
+8FF5D7
+8FF5D8
+8FF5D9
+8FF5DA
+8FF5DB
+8FF5DC
+8FF5DD
+8FF5DE
+8FF5DF
+8FF5E0
+8FF5E1
+8FF5E2
+8FF5E3
+8FF5E4
+8FF5E5
+8FF5E6
+8FF5E7
+8FF5E8
+8FF5E9
+8FF5EA
+8FF5EB
+8FF5EC
+8FF5ED
+8FF5EE
+8FF5EF
+8FF5F0
+8FF5F1
+8FF5F2
+8FF5F3
+8FF5F4
+8FF5F5
+8FF5F6
+8FF5F7
+8FF5F8
+8FF5F9
+8FF5FA
+8FF5FB
+8FF5FC
+8FF5FD
+8FF5FE
+8FF6A1
+8FF6A2
+8FF6A3
+8FF6A4
+8FF6A5
+8FF6A6
+8FF6A7
+8FF6A8
+8FF6A9
+8FF6AA
+8FF6AB
+8FF6AC
+8FF6AD
+8FF6AE
+8FF6AF
+8FF6B0
+8FF6B1
+8FF6B2
+8FF6B3
+8FF6B4
+8FF6B5
+8FF6B6
+8FF6B7
+8FF6B8
+8FF6B9
+8FF6BA
+8FF6BB
+8FF6BC
+8FF6BD
+8FF6BE
+8FF6BF
+8FF6C0
+8FF6C1
+8FF6C2
+8FF6C3
+8FF6C4
+8FF6C5
+8FF6C6
+8FF6C7
+8FF6C8
+8FF6C9
+8FF6CA
+8FF6CB
+8FF6CC
+8FF6CD
+8FF6CE
+8FF6CF
+8FF6D0
+8FF6D1
+8FF6D2
+8FF6D3
+8FF6D4
+8FF6D5
+8FF6D6
+8FF6D7
+8FF6D8
+8FF6D9
+8FF6DA
+8FF6DB
+8FF6DC
+8FF6DD
+8FF6DE
+8FF6DF
+8FF6E0
+8FF6E1
+8FF6E2
+8FF6E3
+8FF6E4
+8FF6E5
+8FF6E6
+8FF6E7
+8FF6E8
+8FF6E9
+8FF6EA
+8FF6EB
+8FF6EC
+8FF6ED
+8FF6EE
+8FF6EF
+8FF6F0
+8FF6F1
+8FF6F2
+8FF6F3
+8FF6F4
+8FF6F5
+8FF6F6
+8FF6F7
+8FF6F8
+8FF6F9
+8FF6FA
+8FF6FB
+8FF6FC
+8FF6FD
+8FF6FE
+8FF7A1
+8FF7A2
+8FF7A3
+8FF7A4
+8FF7A5
+8FF7A6
+8FF7A7
+8FF7A8
+8FF7A9
+8FF7AA
+8FF7AB
+8FF7AC
+8FF7AD
+8FF7AE
+8FF7AF
+8FF7B0
+8FF7B1
+8FF7B2
+8FF7B3
+8FF7B4
+8FF7B5
+8FF7B6
+8FF7B7
+8FF7B8
+8FF7B9
+8FF7BA
+8FF7BB
+8FF7BC
+8FF7BD
+8FF7BE
+8FF7BF
+8FF7C0
+8FF7C1
+8FF7C2
+8FF7C3
+8FF7C4
+8FF7C5
+8FF7C6
+8FF7C7
+8FF7C8
+8FF7C9
+8FF7CA
+8FF7CB
+8FF7CC
+8FF7CD
+8FF7CE
+8FF7CF
+8FF7D0
+8FF7D1
+8FF7D2
+8FF7D3
+8FF7D4
+8FF7D5
+8FF7D6
+8FF7D7
+8FF7D8
+8FF7D9
+8FF7DA
+8FF7DB
+8FF7DC
+8FF7DD
+8FF7DE
+8FF7DF
+8FF7E0
+8FF7E1
+8FF7E2
+8FF7E3
+8FF7E4
+8FF7E5
+8FF7E6
+8FF7E7
+8FF7E8
+8FF7E9
+8FF7EA
+8FF7EB
+8FF7EC
+8FF7ED
+8FF7EE
+8FF7EF
+8FF7F0
+8FF7F1
+8FF7F2
+8FF7F3
+8FF7F4
+8FF7F5
+8FF7F6
+8FF7F7
+8FF7F8
+8FF7F9
+8FF7FA
+8FF7FB
+8FF7FC
+8FF7FD
+8FF7FE
+8FF8A1
+8FF8A2
+8FF8A3
+8FF8A4
+8FF8A5
+8FF8A6
+8FF8A7
+8FF8A8
+8FF8A9
+8FF8AA
+8FF8AB
+8FF8AC
+8FF8AD
+8FF8AE
+8FF8AF
+8FF8B0
+8FF8B1
+8FF8B2
+8FF8B3
+8FF8B4
+8FF8B5
+8FF8B6
+8FF8B7
+8FF8B8
+8FF8B9
+8FF8BA
+8FF8BB
+8FF8BC
+8FF8BD
+8FF8BE
+8FF8BF
+8FF8C0
+8FF8C1
+8FF8C2
+8FF8C3
+8FF8C4
+8FF8C5
+8FF8C6
+8FF8C7
+8FF8C8
+8FF8C9
+8FF8CA
+8FF8CB
+8FF8CC
+8FF8CD
+8FF8CE
+8FF8CF
+8FF8D0
+8FF8D1
+8FF8D2
+8FF8D3
+8FF8D4
+8FF8D5
+8FF8D6
+8FF8D7
+8FF8D8
+8FF8D9
+8FF8DA
+8FF8DB
+8FF8DC
+8FF8DD
+8FF8DE
+8FF8DF
+8FF8E0
+8FF8E1
+8FF8E2
+8FF8E3
+8FF8E4
+8FF8E5
+8FF8E6
+8FF8E7
+8FF8E8
+8FF8E9
+8FF8EA
+8FF8EB
+8FF8EC
+8FF8ED
+8FF8EE
+8FF8EF
+8FF8F0
+8FF8F1
+8FF8F2
+8FF8F3
+8FF8F4
+8FF8F5
+8FF8F6
+8FF8F7
+8FF8F8
+8FF8F9
+8FF8FA
+8FF8FB
+8FF8FC
+8FF8FD
+8FF8FE
+8FF9A1
+8FF9A2
+8FF9A3
+8FF9A4
+8FF9A5
+8FF9A6
+8FF9A7
+8FF9A8
+8FF9A9
+8FF9AA
+8FF9AB
+8FF9AC
+8FF9AD
+8FF9AE
+8FF9AF
+8FF9B0
+8FF9B1
+8FF9B2
+8FF9B3
+8FF9B4
+8FF9B5
+8FF9B6
+8FF9B7
+8FF9B8
+8FF9B9
+8FF9BA
+8FF9BB
+8FF9BC
+8FF9BD
+8FF9BE
+8FF9BF
+8FF9C0
+8FF9C1
+8FF9C2
+8FF9C3
+8FF9C4
+8FF9C5
+8FF9C6
+8FF9C7
+8FF9C8
+8FF9C9
+8FF9CA
+8FF9CB
+8FF9CC
+8FF9CD
+8FF9CE
+8FF9CF
+8FF9D0
+8FF9D1
+8FF9D2
+8FF9D3
+8FF9D4
+8FF9D5
+8FF9D6
+8FF9D7
+8FF9D8
+8FF9D9
+8FF9DA
+8FF9DB
+8FF9DC
+8FF9DD
+8FF9DE
+8FF9DF
+8FF9E0
+8FF9E1
+8FF9E2
+8FF9E3
+8FF9E4
+8FF9E5
+8FF9E6
+8FF9E7
+8FF9E8
+8FF9E9
+8FF9EA
+8FF9EB
+8FF9EC
+8FF9ED
+8FF9EE
+8FF9EF
+8FF9F0
+8FF9F1
+8FF9F2
+8FF9F3
+8FF9F4
+8FF9F5
+8FF9F6
+8FF9F7
+8FF9F8
+8FF9F9
+8FF9FA
+8FF9FB
+8FF9FC
+8FF9FD
+8FF9FE
+8FFAA1
+8FFAA2
+8FFAA3
+8FFAA4
+8FFAA5
+8FFAA6
+8FFAA7
+8FFAA8
+8FFAA9
+8FFAAA
+8FFAAB
+8FFAAC
+8FFAAD
+8FFAAE
+8FFAAF
+8FFAB0
+8FFAB1
+8FFAB2
+8FFAB3
+8FFAB4
+8FFAB5
+8FFAB6
+8FFAB7
+8FFAB8
+8FFAB9
+8FFABA
+8FFABB
+8FFABC
+8FFABD
+8FFABE
+8FFABF
+8FFAC0
+8FFAC1
+8FFAC2
+8FFAC3
+8FFAC4
+8FFAC5
+8FFAC6
+8FFAC7
+8FFAC8
+8FFAC9
+8FFACA
+8FFACB
+8FFACC
+8FFACD
+8FFACE
+8FFACF
+8FFAD0
+8FFAD1
+8FFAD2
+8FFAD3
+8FFAD4
+8FFAD5
+8FFAD6
+8FFAD7
+8FFAD8
+8FFAD9
+8FFADA
+8FFADB
+8FFADC
+8FFADD
+8FFADE
+8FFADF
+8FFAE0
+8FFAE1
+8FFAE2
+8FFAE3
+8FFAE4
+8FFAE5
+8FFAE6
+8FFAE7
+8FFAE8
+8FFAE9
+8FFAEA
+8FFAEB
+8FFAEC
+8FFAED
+8FFAEE
+8FFAEF
+8FFAF0
+8FFAF1
+8FFAF2
+8FFAF3
+8FFAF4
+8FFAF5
+8FFAF6
+8FFAF7
+8FFAF8
+8FFAF9
+8FFAFA
+8FFAFB
+8FFAFC
+8FFAFD
+8FFAFE
+8FFBA1
+8FFBA2
+8FFBA3
+8FFBA4
+8FFBA5
+8FFBA6
+8FFBA7
+8FFBA8
+8FFBA9
+8FFBAA
+8FFBAB
+8FFBAC
+8FFBAD
+8FFBAE
+8FFBAF
+8FFBB0
+8FFBB1
+8FFBB2
+8FFBB3
+8FFBB4
+8FFBB5
+8FFBB6
+8FFBB7
+8FFBB8
+8FFBB9
+8FFBBA
+8FFBBB
+8FFBBC
+8FFBBD
+8FFBBE
+8FFBBF
+8FFBC0
+8FFBC1
+8FFBC2
+8FFBC3
+8FFBC4
+8FFBC5
+8FFBC6
+8FFBC7
+8FFBC8
+8FFBC9
+8FFBCA
+8FFBCB
+8FFBCC
+8FFBCD
+8FFBCE
+8FFBCF
+8FFBD0
+8FFBD1
+8FFBD2
+8FFBD3
+8FFBD4
+8FFBD5
+8FFBD6
+8FFBD7
+8FFBD8
+8FFBD9
+8FFBDA
+8FFBDB
+8FFBDC
+8FFBDD
+8FFBDE
+8FFBDF
+8FFBE0
+8FFBE1
+8FFBE2
+8FFBE3
+8FFBE4
+8FFBE5
+8FFBE6
+8FFBE7
+8FFBE8
+8FFBE9
+8FFBEA
+8FFBEB
+8FFBEC
+8FFBED
+8FFBEE
+8FFBEF
+8FFBF0
+8FFBF1
+8FFBF2
+8FFBF3
+8FFBF4
+8FFBF5
+8FFBF6
+8FFBF7
+8FFBF8
+8FFBF9
+8FFBFA
+8FFBFB
+8FFBFC
+8FFBFD
+8FFBFE
+8FFCA1
+8FFCA2
+8FFCA3
+8FFCA4
+8FFCA5
+8FFCA6
+8FFCA7
+8FFCA8
+8FFCA9
+8FFCAA
+8FFCAB
+8FFCAC
+8FFCAD
+8FFCAE
+8FFCAF
+8FFCB0
+8FFCB1
+8FFCB2
+8FFCB3
+8FFCB4
+8FFCB5
+8FFCB6
+8FFCB7
+8FFCB8
+8FFCB9
+8FFCBA
+8FFCBB
+8FFCBC
+8FFCBD
+8FFCBE
+8FFCBF
+8FFCC0
+8FFCC1
+8FFCC2
+8FFCC3
+8FFCC4
+8FFCC5
+8FFCC6
+8FFCC7
+8FFCC8
+8FFCC9
+8FFCCA
+8FFCCB
+8FFCCC
+8FFCCD
+8FFCCE
+8FFCCF
+8FFCD0
+8FFCD1
+8FFCD2
+8FFCD3
+8FFCD4
+8FFCD5
+8FFCD6
+8FFCD7
+8FFCD8
+8FFCD9
+8FFCDA
+8FFCDB
+8FFCDC
+8FFCDD
+8FFCDE
+8FFCDF
+8FFCE0
+8FFCE1
+8FFCE2
+8FFCE3
+8FFCE4
+8FFCE5
+8FFCE6
+8FFCE7
+8FFCE8
+8FFCE9
+8FFCEA
+8FFCEB
+8FFCEC
+8FFCED
+8FFCEE
+8FFCEF
+8FFCF0
+8FFCF1
+8FFCF2
+8FFCF3
+8FFCF4
+8FFCF5
+8FFCF6
+8FFCF7
+8FFCF8
+8FFCF9
+8FFCFA
+8FFCFB
+8FFCFC
+8FFCFD
+8FFCFE
+8FFDA1
+8FFDA2
+8FFDA3
+8FFDA4
+8FFDA5
+8FFDA6
+8FFDA7
+8FFDA8
+8FFDA9
+8FFDAA
+8FFDAB
+8FFDAC
+8FFDAD
+8FFDAE
+8FFDAF
+8FFDB0
+8FFDB1
+8FFDB2
+8FFDB3
+8FFDB4
+8FFDB5
+8FFDB6
+8FFDB7
+8FFDB8
+8FFDB9
+8FFDBA
+8FFDBB
+8FFDBC
+8FFDBD
+8FFDBE
+8FFDBF
+8FFDC0
+8FFDC1
+8FFDC2
+8FFDC3
+8FFDC4
+8FFDC5
+8FFDC6
+8FFDC7
+8FFDC8
+8FFDC9
+8FFDCA
+8FFDCB
+8FFDCC
+8FFDCD
+8FFDCE
+8FFDCF
+8FFDD0
+8FFDD1
+8FFDD2
+8FFDD3
+8FFDD4
+8FFDD5
+8FFDD6
+8FFDD7
+8FFDD8
+8FFDD9
+8FFDDA
+8FFDDB
+8FFDDC
+8FFDDD
+8FFDDE
+8FFDDF
+8FFDE0
+8FFDE1
+8FFDE2
+8FFDE3
+8FFDE4
+8FFDE5
+8FFDE6
+8FFDE7
+8FFDE8
+8FFDE9
+8FFDEA
+8FFDEB
+8FFDEC
+8FFDED
+8FFDEE
+8FFDEF
+8FFDF0
+8FFDF1
+8FFDF2
+8FFDF3
+8FFDF4
+8FFDF5
+8FFDF6
+8FFDF7
+8FFDF8
+8FFDF9
+8FFDFA
+8FFDFB
+8FFDFC
+8FFDFD
+8FFDFE
+8FFEA1
+8FFEA2
+8FFEA3
+8FFEA4
+8FFEA5
+8FFEA6
+8FFEA7
+8FFEA8
+8FFEA9
+8FFEAA
+8FFEAB
+8FFEAC
+8FFEAD
+8FFEAE
+8FFEAF
+8FFEB0
+8FFEB1
+8FFEB2
+8FFEB3
+8FFEB4
+8FFEB5
+8FFEB6
+8FFEB7
+8FFEB8
+8FFEB9
+8FFEBA
+8FFEBB
+8FFEBC
+8FFEBD
+8FFEBE
+8FFEBF
+8FFEC0
+8FFEC1
+8FFEC2
+8FFEC3
+8FFEC4
+8FFEC5
+8FFEC6
+8FFEC7
+8FFEC8
+8FFEC9
+8FFECA
+8FFECB
+8FFECC
+8FFECD
+8FFECE
+8FFECF
+8FFED0
+8FFED1
+8FFED2
+8FFED3
+8FFED4
+8FFED5
+8FFED6
+8FFED7
+8FFED8
+8FFED9
+8FFEDA
+8FFEDB
+8FFEDC
+8FFEDD
+8FFEDE
+8FFEDF
+8FFEE0
+8FFEE1
+8FFEE2
+8FFEE3
+8FFEE4
+8FFEE5
+8FFEE6
+8FFEE7
+8FFEE8
+8FFEE9
+8FFEEA
+8FFEEB
+8FFEEC
+8FFEED
+8FFEEE
+8FFEEF
+8FFEF0
+8FFEF1
+8FFEF2
+8FFEF3
+8FFEF4
+8FFEF5
+8FFEF6
+8FFEF7
+8FFEF8
+8FFEF9
+8FFEFA
+8FFEFB
+8FFEFC
+8FFEFD
+8FFEFE
+CREATE TABLE t2 SELECT CONVERT(c1 USING ucs2) AS c1 FROM t1;
+SELECT HEX(c1) FROM t2;
+HEX(c1)
+005C
+007E
+FFE3
+2015
+FF3C
+FF5E
+2225
+FF0D
+FFE0
+FFE1
+FFE5
+FFE2
+FF5E
+FFE4
+2460
+2461
+2462
+2463
+2464
+2465
+2466
+2467
+2468
+2469
+246A
+246B
+246C
+246D
+246E
+246F
+2470
+2471
+2472
+2473
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+3349
+3314
+3322
+334D
+3318
+3327
+3303
+3336
+3351
+3357
+330D
+3326
+3323
+332B
+334A
+333B
+339C
+339D
+339E
+338E
+338F
+33C4
+33A1
+337B
+301D
+301F
+2116
+33CD
+2121
+32A4
+32A5
+32A6
+32A7
+32A8
+3231
+3232
+3239
+337E
+337D
+337C
+2252
+2261
+222B
+222E
+2211
+221A
+22A5
+2220
+221F
+22BF
+2235
+2229
+222A
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+FFE2
+FFE4
+FF07
+FF02
+3231
+2116
+2121
+2235
+7E8A
+891C
+9348
+9288
+84DC
+4FC9
+70BB
+6631
+68C8
+92F9
+66FB
+5F45
+4E28
+4EE1
+4EFC
+4F00
+4F03
+4F39
+4F56
+4F92
+4F8A
+4F9A
+4F94
+4FCD
+5040
+5022
+4FFF
+501E
+5046
+5070
+5042
+5094
+50F4
+50D8
+514A
+5164
+519D
+51BE
+51EC
+5215
+529C
+52A6
+52C0
+52DB
+5300
+5307
+5324
+5372
+5393
+53B2
+53DD
+FA0E
+549C
+548A
+54A9
+54FF
+5586
+5759
+5765
+57AC
+57C8
+57C7
+FA0F
+FA10
+589E
+58B2
+590B
+5953
+595B
+595D
+5963
+59A4
+59BA
+5B56
+5BC0
+752F
+5BD8
+5BEC
+5C1E
+5CA6
+5CBA
+5CF5
+5D27
+5D53
+FA11
+5D42
+5D6D
+5DB8
+5DB9
+5DD0
+5F21
+5F34
+5F67
+5FB7
+5FDE
+605D
+6085
+608A
+60DE
+60D5
+6120
+60F2
+6111
+6137
+6130
+6198
+6213
+62A6
+63F5
+6460
+649D
+64CE
+654E
+6600
+6615
+663B
+6609
+662E
+661E
+6624
+6665
+6657
+6659
+FA12
+6673
+6699
+66A0
+66B2
+66BF
+66FA
+670E
+F929
+6766
+67BB
+6852
+67C0
+6801
+6844
+68CF
+FA13
+6968
+FA14
+6998
+69E2
+6A30
+6A6B
+6A46
+6A73
+6A7E
+6AE2
+6AE4
+6BD6
+6C3F
+6C5C
+6C86
+6C6F
+6CDA
+6D04
+6D87
+6D6F
+6D96
+6DAC
+6DCF
+6DF8
+6DF2
+6DFC
+6E39
+6E5C
+6E27
+6E3C
+6EBF
+6F88
+6FB5
+6FF5
+7005
+7007
+7028
+7085
+70AB
+710F
+7104
+715C
+7146
+7147
+FA15
+71C1
+71FE
+72B1
+72BE
+7324
+FA16
+7377
+73BD
+73C9
+73D6
+73E3
+73D2
+7407
+73F5
+7426
+742A
+7429
+742E
+7462
+7489
+749F
+7501
+756F
+7682
+769C
+769E
+769B
+76A6
+FA17
+7746
+52AF
+7821
+784E
+7864
+787A
+7930
+FA18
+FA19
+FA1A
+7994
+FA1B
+799B
+7AD1
+7AE7
+FA1C
+7AEB
+7B9E
+FA1D
+7D48
+7D5C
+7DB7
+7DA0
+7DD6
+7E52
+7F47
+7FA1
+FA1E
+8301
+8362
+837F
+83C7
+83F6
+8448
+84B4
+8553
+8559
+856B
+FA1F
+85B0
+FA20
+FA21
+8807
+88F5
+8A12
+8A37
+8A79
+8AA7
+8ABE
+8ADF
+FA22
+8AF6
+8B53
+8B7F
+8CF0
+8CF4
+8D12
+8D76
+FA23
+8ECF
+FA24
+FA25
+9067
+90DE
+FA26
+9115
+9127
+91DA
+91D7
+91DE
+91ED
+91EE
+91E4
+91E5
+9206
+9210
+920A
+923A
+9240
+923C
+924E
+9259
+9251
+9239
+9267
+92A7
+9277
+9278
+92E7
+92D7
+92D9
+92D0
+FA27
+92D5
+92E0
+92D3
+9325
+9321
+92FB
+FA28
+931E
+92FF
+931D
+9302
+9370
+9357
+93A4
+93C6
+93DE
+93F8
+9431
+9445
+9448
+9592
+F9DC
+FA29
+969D
+96AF
+9733
+973B
+9743
+974D
+974F
+9751
+9755
+9857
+9865
+FA2A
+FA2B
+9927
+FA2C
+999E
+9A4E
+9AD9
+9ADC
+9B75
+9B72
+9B8F
+9BB1
+9BBB
+9C00
+9D70
+9D6B
+FA2D
+9E19
+9ED1
+E000
+E001
+E002
+E003
+E004
+E005
+E006
+E007
+E008
+E009
+E00A
+E00B
+E00C
+E00D
+E00E
+E00F
+E010
+E011
+E012
+E013
+E014
+E015
+E016
+E017
+E018
+E019
+E01A
+E01B
+E01C
+E01D
+E01E
+E01F
+E020
+E021
+E022
+E023
+E024
+E025
+E026
+E027
+E028
+E029
+E02A
+E02B
+E02C
+E02D
+E02E
+E02F
+E030
+E031
+E032
+E033
+E034
+E035
+E036
+E037
+E038
+E039
+E03A
+E03B
+E03C
+E03D
+E03E
+E03F
+E040
+E041
+E042
+E043
+E044
+E045
+E046
+E047
+E048
+E049
+E04A
+E04B
+E04C
+E04D
+E04E
+E04F
+E050
+E051
+E052
+E053
+E054
+E055
+E056
+E057
+E058
+E059
+E05A
+E05B
+E05C
+E05D
+E05E
+E05F
+E060
+E061
+E062
+E063
+E064
+E065
+E066
+E067
+E068
+E069
+E06A
+E06B
+E06C
+E06D
+E06E
+E06F
+E070
+E071
+E072
+E073
+E074
+E075
+E076
+E077
+E078
+E079
+E07A
+E07B
+E07C
+E07D
+E07E
+E07F
+E080
+E081
+E082
+E083
+E084
+E085
+E086
+E087
+E088
+E089
+E08A
+E08B
+E08C
+E08D
+E08E
+E08F
+E090
+E091
+E092
+E093
+E094
+E095
+E096
+E097
+E098
+E099
+E09A
+E09B
+E09C
+E09D
+E09E
+E09F
+E0A0
+E0A1
+E0A2
+E0A3
+E0A4
+E0A5
+E0A6
+E0A7
+E0A8
+E0A9
+E0AA
+E0AB
+E0AC
+E0AD
+E0AE
+E0AF
+E0B0
+E0B1
+E0B2
+E0B3
+E0B4
+E0B5
+E0B6
+E0B7
+E0B8
+E0B9
+E0BA
+E0BB
+E0BC
+E0BD
+E0BE
+E0BF
+E0C0
+E0C1
+E0C2
+E0C3
+E0C4
+E0C5
+E0C6
+E0C7
+E0C8
+E0C9
+E0CA
+E0CB
+E0CC
+E0CD
+E0CE
+E0CF
+E0D0
+E0D1
+E0D2
+E0D3
+E0D4
+E0D5
+E0D6
+E0D7
+E0D8
+E0D9
+E0DA
+E0DB
+E0DC
+E0DD
+E0DE
+E0DF
+E0E0
+E0E1
+E0E2
+E0E3
+E0E4
+E0E5
+E0E6
+E0E7
+E0E8
+E0E9
+E0EA
+E0EB
+E0EC
+E0ED
+E0EE
+E0EF
+E0F0
+E0F1
+E0F2
+E0F3
+E0F4
+E0F5
+E0F6
+E0F7
+E0F8
+E0F9
+E0FA
+E0FB
+E0FC
+E0FD
+E0FE
+E0FF
+E100
+E101
+E102
+E103
+E104
+E105
+E106
+E107
+E108
+E109
+E10A
+E10B
+E10C
+E10D
+E10E
+E10F
+E110
+E111
+E112
+E113
+E114
+E115
+E116
+E117
+E118
+E119
+E11A
+E11B
+E11C
+E11D
+E11E
+E11F
+E120
+E121
+E122
+E123
+E124
+E125
+E126
+E127
+E128
+E129
+E12A
+E12B
+E12C
+E12D
+E12E
+E12F
+E130
+E131
+E132
+E133
+E134
+E135
+E136
+E137
+E138
+E139
+E13A
+E13B
+E13C
+E13D
+E13E
+E13F
+E140
+E141
+E142
+E143
+E144
+E145
+E146
+E147
+E148
+E149
+E14A
+E14B
+E14C
+E14D
+E14E
+E14F
+E150
+E151
+E152
+E153
+E154
+E155
+E156
+E157
+E158
+E159
+E15A
+E15B
+E15C
+E15D
+E15E
+E15F
+E160
+E161
+E162
+E163
+E164
+E165
+E166
+E167
+E168
+E169
+E16A
+E16B
+E16C
+E16D
+E16E
+E16F
+E170
+E171
+E172
+E173
+E174
+E175
+E176
+E177
+E178
+E179
+E17A
+E17B
+E17C
+E17D
+E17E
+E17F
+E180
+E181
+E182
+E183
+E184
+E185
+E186
+E187
+E188
+E189
+E18A
+E18B
+E18C
+E18D
+E18E
+E18F
+E190
+E191
+E192
+E193
+E194
+E195
+E196
+E197
+E198
+E199
+E19A
+E19B
+E19C
+E19D
+E19E
+E19F
+E1A0
+E1A1
+E1A2
+E1A3
+E1A4
+E1A5
+E1A6
+E1A7
+E1A8
+E1A9
+E1AA
+E1AB
+E1AC
+E1AD
+E1AE
+E1AF
+E1B0
+E1B1
+E1B2
+E1B3
+E1B4
+E1B5
+E1B6
+E1B7
+E1B8
+E1B9
+E1BA
+E1BB
+E1BC
+E1BD
+E1BE
+E1BF
+E1C0
+E1C1
+E1C2
+E1C3
+E1C4
+E1C5
+E1C6
+E1C7
+E1C8
+E1C9
+E1CA
+E1CB
+E1CC
+E1CD
+E1CE
+E1CF
+E1D0
+E1D1
+E1D2
+E1D3
+E1D4
+E1D5
+E1D6
+E1D7
+E1D8
+E1D9
+E1DA
+E1DB
+E1DC
+E1DD
+E1DE
+E1DF
+E1E0
+E1E1
+E1E2
+E1E3
+E1E4
+E1E5
+E1E6
+E1E7
+E1E8
+E1E9
+E1EA
+E1EB
+E1EC
+E1ED
+E1EE
+E1EF
+E1F0
+E1F1
+E1F2
+E1F3
+E1F4
+E1F5
+E1F6
+E1F7
+E1F8
+E1F9
+E1FA
+E1FB
+E1FC
+E1FD
+E1FE
+E1FF
+E200
+E201
+E202
+E203
+E204
+E205
+E206
+E207
+E208
+E209
+E20A
+E20B
+E20C
+E20D
+E20E
+E20F
+E210
+E211
+E212
+E213
+E214
+E215
+E216
+E217
+E218
+E219
+E21A
+E21B
+E21C
+E21D
+E21E
+E21F
+E220
+E221
+E222
+E223
+E224
+E225
+E226
+E227
+E228
+E229
+E22A
+E22B
+E22C
+E22D
+E22E
+E22F
+E230
+E231
+E232
+E233
+E234
+E235
+E236
+E237
+E238
+E239
+E23A
+E23B
+E23C
+E23D
+E23E
+E23F
+E240
+E241
+E242
+E243
+E244
+E245
+E246
+E247
+E248
+E249
+E24A
+E24B
+E24C
+E24D
+E24E
+E24F
+E250
+E251
+E252
+E253
+E254
+E255
+E256
+E257
+E258
+E259
+E25A
+E25B
+E25C
+E25D
+E25E
+E25F
+E260
+E261
+E262
+E263
+E264
+E265
+E266
+E267
+E268
+E269
+E26A
+E26B
+E26C
+E26D
+E26E
+E26F
+E270
+E271
+E272
+E273
+E274
+E275
+E276
+E277
+E278
+E279
+E27A
+E27B
+E27C
+E27D
+E27E
+E27F
+E280
+E281
+E282
+E283
+E284
+E285
+E286
+E287
+E288
+E289
+E28A
+E28B
+E28C
+E28D
+E28E
+E28F
+E290
+E291
+E292
+E293
+E294
+E295
+E296
+E297
+E298
+E299
+E29A
+E29B
+E29C
+E29D
+E29E
+E29F
+E2A0
+E2A1
+E2A2
+E2A3
+E2A4
+E2A5
+E2A6
+E2A7
+E2A8
+E2A9
+E2AA
+E2AB
+E2AC
+E2AD
+E2AE
+E2AF
+E2B0
+E2B1
+E2B2
+E2B3
+E2B4
+E2B5
+E2B6
+E2B7
+E2B8
+E2B9
+E2BA
+E2BB
+E2BC
+E2BD
+E2BE
+E2BF
+E2C0
+E2C1
+E2C2
+E2C3
+E2C4
+E2C5
+E2C6
+E2C7
+E2C8
+E2C9
+E2CA
+E2CB
+E2CC
+E2CD
+E2CE
+E2CF
+E2D0
+E2D1
+E2D2
+E2D3
+E2D4
+E2D5
+E2D6
+E2D7
+E2D8
+E2D9
+E2DA
+E2DB
+E2DC
+E2DD
+E2DE
+E2DF
+E2E0
+E2E1
+E2E2
+E2E3
+E2E4
+E2E5
+E2E6
+E2E7
+E2E8
+E2E9
+E2EA
+E2EB
+E2EC
+E2ED
+E2EE
+E2EF
+E2F0
+E2F1
+E2F2
+E2F3
+E2F4
+E2F5
+E2F6
+E2F7
+E2F8
+E2F9
+E2FA
+E2FB
+E2FC
+E2FD
+E2FE
+E2FF
+E300
+E301
+E302
+E303
+E304
+E305
+E306
+E307
+E308
+E309
+E30A
+E30B
+E30C
+E30D
+E30E
+E30F
+E310
+E311
+E312
+E313
+E314
+E315
+E316
+E317
+E318
+E319
+E31A
+E31B
+E31C
+E31D
+E31E
+E31F
+E320
+E321
+E322
+E323
+E324
+E325
+E326
+E327
+E328
+E329
+E32A
+E32B
+E32C
+E32D
+E32E
+E32F
+E330
+E331
+E332
+E333
+E334
+E335
+E336
+E337
+E338
+E339
+E33A
+E33B
+E33C
+E33D
+E33E
+E33F
+E340
+E341
+E342
+E343
+E344
+E345
+E346
+E347
+E348
+E349
+E34A
+E34B
+E34C
+E34D
+E34E
+E34F
+E350
+E351
+E352
+E353
+E354
+E355
+E356
+E357
+E358
+E359
+E35A
+E35B
+E35C
+E35D
+E35E
+E35F
+E360
+E361
+E362
+E363
+E364
+E365
+E366
+E367
+E368
+E369
+E36A
+E36B
+E36C
+E36D
+E36E
+E36F
+E370
+E371
+E372
+E373
+E374
+E375
+E376
+E377
+E378
+E379
+E37A
+E37B
+E37C
+E37D
+E37E
+E37F
+E380
+E381
+E382
+E383
+E384
+E385
+E386
+E387
+E388
+E389
+E38A
+E38B
+E38C
+E38D
+E38E
+E38F
+E390
+E391
+E392
+E393
+E394
+E395
+E396
+E397
+E398
+E399
+E39A
+E39B
+E39C
+E39D
+E39E
+E39F
+E3A0
+E3A1
+E3A2
+E3A3
+E3A4
+E3A5
+E3A6
+E3A7
+E3A8
+E3A9
+E3AA
+E3AB
+E3AC
+E3AD
+E3AE
+E3AF
+E3B0
+E3B1
+E3B2
+E3B3
+E3B4
+E3B5
+E3B6
+E3B7
+E3B8
+E3B9
+E3BA
+E3BB
+E3BC
+E3BD
+E3BE
+E3BF
+E3C0
+E3C1
+E3C2
+E3C3
+E3C4
+E3C5
+E3C6
+E3C7
+E3C8
+E3C9
+E3CA
+E3CB
+E3CC
+E3CD
+E3CE
+E3CF
+E3D0
+E3D1
+E3D2
+E3D3
+E3D4
+E3D5
+E3D6
+E3D7
+E3D8
+E3D9
+E3DA
+E3DB
+E3DC
+E3DD
+E3DE
+E3DF
+E3E0
+E3E1
+E3E2
+E3E3
+E3E4
+E3E5
+E3E6
+E3E7
+E3E8
+E3E9
+E3EA
+E3EB
+E3EC
+E3ED
+E3EE
+E3EF
+E3F0
+E3F1
+E3F2
+E3F3
+E3F4
+E3F5
+E3F6
+E3F7
+E3F8
+E3F9
+E3FA
+E3FB
+E3FC
+E3FD
+E3FE
+E3FF
+E400
+E401
+E402
+E403
+E404
+E405
+E406
+E407
+E408
+E409
+E40A
+E40B
+E40C
+E40D
+E40E
+E40F
+E410
+E411
+E412
+E413
+E414
+E415
+E416
+E417
+E418
+E419
+E41A
+E41B
+E41C
+E41D
+E41E
+E41F
+E420
+E421
+E422
+E423
+E424
+E425
+E426
+E427
+E428
+E429
+E42A
+E42B
+E42C
+E42D
+E42E
+E42F
+E430
+E431
+E432
+E433
+E434
+E435
+E436
+E437
+E438
+E439
+E43A
+E43B
+E43C
+E43D
+E43E
+E43F
+E440
+E441
+E442
+E443
+E444
+E445
+E446
+E447
+E448
+E449
+E44A
+E44B
+E44C
+E44D
+E44E
+E44F
+E450
+E451
+E452
+E453
+E454
+E455
+E456
+E457
+E458
+E459
+E45A
+E45B
+E45C
+E45D
+E45E
+E45F
+E460
+E461
+E462
+E463
+E464
+E465
+E466
+E467
+E468
+E469
+E46A
+E46B
+E46C
+E46D
+E46E
+E46F
+E470
+E471
+E472
+E473
+E474
+E475
+E476
+E477
+E478
+E479
+E47A
+E47B
+E47C
+E47D
+E47E
+E47F
+E480
+E481
+E482
+E483
+E484
+E485
+E486
+E487
+E488
+E489
+E48A
+E48B
+E48C
+E48D
+E48E
+E48F
+E490
+E491
+E492
+E493
+E494
+E495
+E496
+E497
+E498
+E499
+E49A
+E49B
+E49C
+E49D
+E49E
+E49F
+E4A0
+E4A1
+E4A2
+E4A3
+E4A4
+E4A5
+E4A6
+E4A7
+E4A8
+E4A9
+E4AA
+E4AB
+E4AC
+E4AD
+E4AE
+E4AF
+E4B0
+E4B1
+E4B2
+E4B3
+E4B4
+E4B5
+E4B6
+E4B7
+E4B8
+E4B9
+E4BA
+E4BB
+E4BC
+E4BD
+E4BE
+E4BF
+E4C0
+E4C1
+E4C2
+E4C3
+E4C4
+E4C5
+E4C6
+E4C7
+E4C8
+E4C9
+E4CA
+E4CB
+E4CC
+E4CD
+E4CE
+E4CF
+E4D0
+E4D1
+E4D2
+E4D3
+E4D4
+E4D5
+E4D6
+E4D7
+E4D8
+E4D9
+E4DA
+E4DB
+E4DC
+E4DD
+E4DE
+E4DF
+E4E0
+E4E1
+E4E2
+E4E3
+E4E4
+E4E5
+E4E6
+E4E7
+E4E8
+E4E9
+E4EA
+E4EB
+E4EC
+E4ED
+E4EE
+E4EF
+E4F0
+E4F1
+E4F2
+E4F3
+E4F4
+E4F5
+E4F6
+E4F7
+E4F8
+E4F9
+E4FA
+E4FB
+E4FC
+E4FD
+E4FE
+E4FF
+E500
+E501
+E502
+E503
+E504
+E505
+E506
+E507
+E508
+E509
+E50A
+E50B
+E50C
+E50D
+E50E
+E50F
+E510
+E511
+E512
+E513
+E514
+E515
+E516
+E517
+E518
+E519
+E51A
+E51B
+E51C
+E51D
+E51E
+E51F
+E520
+E521
+E522
+E523
+E524
+E525
+E526
+E527
+E528
+E529
+E52A
+E52B
+E52C
+E52D
+E52E
+E52F
+E530
+E531
+E532
+E533
+E534
+E535
+E536
+E537
+E538
+E539
+E53A
+E53B
+E53C
+E53D
+E53E
+E53F
+E540
+E541
+E542
+E543
+E544
+E545
+E546
+E547
+E548
+E549
+E54A
+E54B
+E54C
+E54D
+E54E
+E54F
+E550
+E551
+E552
+E553
+E554
+E555
+E556
+E557
+E558
+E559
+E55A
+E55B
+E55C
+E55D
+E55E
+E55F
+E560
+E561
+E562
+E563
+E564
+E565
+E566
+E567
+E568
+E569
+E56A
+E56B
+E56C
+E56D
+E56E
+E56F
+E570
+E571
+E572
+E573
+E574
+E575
+E576
+E577
+E578
+E579
+E57A
+E57B
+E57C
+E57D
+E57E
+E57F
+E580
+E581
+E582
+E583
+E584
+E585
+E586
+E587
+E588
+E589
+E58A
+E58B
+E58C
+E58D
+E58E
+E58F
+E590
+E591
+E592
+E593
+E594
+E595
+E596
+E597
+E598
+E599
+E59A
+E59B
+E59C
+E59D
+E59E
+E59F
+E5A0
+E5A1
+E5A2
+E5A3
+E5A4
+E5A5
+E5A6
+E5A7
+E5A8
+E5A9
+E5AA
+E5AB
+E5AC
+E5AD
+E5AE
+E5AF
+E5B0
+E5B1
+E5B2
+E5B3
+E5B4
+E5B5
+E5B6
+E5B7
+E5B8
+E5B9
+E5BA
+E5BB
+E5BC
+E5BD
+E5BE
+E5BF
+E5C0
+E5C1
+E5C2
+E5C3
+E5C4
+E5C5
+E5C6
+E5C7
+E5C8
+E5C9
+E5CA
+E5CB
+E5CC
+E5CD
+E5CE
+E5CF
+E5D0
+E5D1
+E5D2
+E5D3
+E5D4
+E5D5
+E5D6
+E5D7
+E5D8
+E5D9
+E5DA
+E5DB
+E5DC
+E5DD
+E5DE
+E5DF
+E5E0
+E5E1
+E5E2
+E5E3
+E5E4
+E5E5
+E5E6
+E5E7
+E5E8
+E5E9
+E5EA
+E5EB
+E5EC
+E5ED
+E5EE
+E5EF
+E5F0
+E5F1
+E5F2
+E5F3
+E5F4
+E5F5
+E5F6
+E5F7
+E5F8
+E5F9
+E5FA
+E5FB
+E5FC
+E5FD
+E5FE
+E5FF
+E600
+E601
+E602
+E603
+E604
+E605
+E606
+E607
+E608
+E609
+E60A
+E60B
+E60C
+E60D
+E60E
+E60F
+E610
+E611
+E612
+E613
+E614
+E615
+E616
+E617
+E618
+E619
+E61A
+E61B
+E61C
+E61D
+E61E
+E61F
+E620
+E621
+E622
+E623
+E624
+E625
+E626
+E627
+E628
+E629
+E62A
+E62B
+E62C
+E62D
+E62E
+E62F
+E630
+E631
+E632
+E633
+E634
+E635
+E636
+E637
+E638
+E639
+E63A
+E63B
+E63C
+E63D
+E63E
+E63F
+E640
+E641
+E642
+E643
+E644
+E645
+E646
+E647
+E648
+E649
+E64A
+E64B
+E64C
+E64D
+E64E
+E64F
+E650
+E651
+E652
+E653
+E654
+E655
+E656
+E657
+E658
+E659
+E65A
+E65B
+E65C
+E65D
+E65E
+E65F
+E660
+E661
+E662
+E663
+E664
+E665
+E666
+E667
+E668
+E669
+E66A
+E66B
+E66C
+E66D
+E66E
+E66F
+E670
+E671
+E672
+E673
+E674
+E675
+E676
+E677
+E678
+E679
+E67A
+E67B
+E67C
+E67D
+E67E
+E67F
+E680
+E681
+E682
+E683
+E684
+E685
+E686
+E687
+E688
+E689
+E68A
+E68B
+E68C
+E68D
+E68E
+E68F
+E690
+E691
+E692
+E693
+E694
+E695
+E696
+E697
+E698
+E699
+E69A
+E69B
+E69C
+E69D
+E69E
+E69F
+E6A0
+E6A1
+E6A2
+E6A3
+E6A4
+E6A5
+E6A6
+E6A7
+E6A8
+E6A9
+E6AA
+E6AB
+E6AC
+E6AD
+E6AE
+E6AF
+E6B0
+E6B1
+E6B2
+E6B3
+E6B4
+E6B5
+E6B6
+E6B7
+E6B8
+E6B9
+E6BA
+E6BB
+E6BC
+E6BD
+E6BE
+E6BF
+E6C0
+E6C1
+E6C2
+E6C3
+E6C4
+E6C5
+E6C6
+E6C7
+E6C8
+E6C9
+E6CA
+E6CB
+E6CC
+E6CD
+E6CE
+E6CF
+E6D0
+E6D1
+E6D2
+E6D3
+E6D4
+E6D5
+E6D6
+E6D7
+E6D8
+E6D9
+E6DA
+E6DB
+E6DC
+E6DD
+E6DE
+E6DF
+E6E0
+E6E1
+E6E2
+E6E3
+E6E4
+E6E5
+E6E6
+E6E7
+E6E8
+E6E9
+E6EA
+E6EB
+E6EC
+E6ED
+E6EE
+E6EF
+E6F0
+E6F1
+E6F2
+E6F3
+E6F4
+E6F5
+E6F6
+E6F7
+E6F8
+E6F9
+E6FA
+E6FB
+E6FC
+E6FD
+E6FE
+E6FF
+E700
+E701
+E702
+E703
+E704
+E705
+E706
+E707
+E708
+E709
+E70A
+E70B
+E70C
+E70D
+E70E
+E70F
+E710
+E711
+E712
+E713
+E714
+E715
+E716
+E717
+E718
+E719
+E71A
+E71B
+E71C
+E71D
+E71E
+E71F
+E720
+E721
+E722
+E723
+E724
+E725
+E726
+E727
+E728
+E729
+E72A
+E72B
+E72C
+E72D
+E72E
+E72F
+E730
+E731
+E732
+E733
+E734
+E735
+E736
+E737
+E738
+E739
+E73A
+E73B
+E73C
+E73D
+E73E
+E73F
+E740
+E741
+E742
+E743
+E744
+E745
+E746
+E747
+E748
+E749
+E74A
+E74B
+E74C
+E74D
+E74E
+E74F
+E750
+E751
+E752
+E753
+E754
+E755
+E756
+E757
+CREATE TABLE t3 SELECT CONVERT(c1 USING eucjpms) AS c1 FROM t2;
+SELECT HEX(c1) FROM t3;
+HEX(c1)
+5C
+7E
+A1B1
+A1BD
+A1C0
+A1C1
+A1C2
+A1DD
+A1F1
+A1F2
+A1EF
+A2CC
+A1C1
+8FA2C3
+ADA1
+ADA2
+ADA3
+ADA4
+ADA5
+ADA6
+ADA7
+ADA8
+ADA9
+ADAA
+ADAB
+ADAC
+ADAD
+ADAE
+ADAF
+ADB0
+ADB1
+ADB2
+ADB3
+ADB4
+ADB5
+ADB6
+ADB7
+ADB8
+ADB9
+ADBA
+ADBB
+ADBC
+ADBD
+ADBE
+ADC0
+ADC1
+ADC2
+ADC3
+ADC4
+ADC5
+ADC6
+ADC7
+ADC8
+ADC9
+ADCA
+ADCB
+ADCC
+ADCD
+ADCE
+ADCF
+ADD0
+ADD1
+ADD2
+ADD3
+ADD4
+ADD5
+ADD6
+ADDF
+ADE0
+ADE1
+ADE2
+ADE3
+ADE4
+ADE5
+ADE6
+ADE7
+ADE8
+ADE9
+ADEA
+ADEB
+ADEC
+ADED
+ADEE
+ADEF
+A2E2
+A2E1
+A2E9
+ADF3
+ADF4
+A2E5
+A2DD
+A2DC
+ADF8
+ADF9
+A2E8
+A2C1
+A2C0
+8FF3F3
+8FF3F4
+8FF3F5
+8FF3F6
+8FF3F7
+8FF3F8
+8FF3F9
+8FF3FA
+8FF3FB
+8FF3FC
+ADB5
+ADB6
+ADB7
+ADB8
+ADB9
+ADBA
+ADBB
+ADBC
+ADBD
+ADBE
+A2CC
+8FA2C3
+8FF4A9
+8FF4AA
+ADEA
+ADE2
+ADE4
+A2E8
+8FD4E3
+8FDCDF
+8FE4E9
+8FE3F8
+8FD9A1
+8FB1BB
+8FF4AE
+8FC2AD
+8FC3FC
+8FE4D0
+8FC2BF
+8FBCF4
+8FB0A9
+8FB0C8
+8FF4AF
+8FB0D2
+8FB0D4
+8FB0E3
+8FB0EE
+8FB1A7
+8FB1A3
+8FB1AC
+8FB1A9
+8FB1BE
+8FB1DF
+8FB1D8
+8FB1C8
+8FB1D7
+8FB1E3
+8FB1F4
+8FB1E1
+8FB2A3
+8FF4B0
+8FB2BB
+8FB2E6
+8FB2ED
+8FB2F5
+8FB2FC
+8FF4B1
+8FB3B5
+8FB3D8
+8FB3DB
+8FB3E5
+8FB3EE
+8FB3FB
+8FF4B2
+8FF4B3
+8FB4C0
+8FB4C7
+8FB4D0
+8FB4DE
+8FF4B4
+8FB5AA
+8FF4B5
+8FB5AF
+8FB5C4
+8FB5E8
+8FF4B6
+8FB7C2
+8FB7E4
+8FB7E8
+8FB7E7
+8FF4B7
+8FF4B8
+8FF4B9
+8FB8CE
+8FB8E1
+8FB8F5
+8FB8F7
+8FB8F8
+8FB8FC
+8FB9AF
+8FB9B7
+8FBABE
+8FBADB
+8FCDAA
+8FBAE1
+8FF4BA
+8FBAEB
+8FBBB3
+8FBBB8
+8FF4BB
+8FBBCA
+8FF4BC
+8FF4BD
+8FBBD0
+8FBBDE
+8FBBF4
+8FBBF5
+8FBBF9
+8FBCE4
+8FBCED
+8FBCFE
+8FF4BE
+8FBDC2
+8FBDE7
+8FF4BF
+8FBDF0
+8FBEB0
+8FBEAC
+8FF4C0
+8FBEB3
+8FBEBD
+8FBECD
+8FBEC9
+8FBEE4
+8FBFA8
+8FBFC9
+8FC0C4
+8FC0E4
+8FC0F4
+8FC1A6
+8FF4C1
+8FC1F5
+8FC1FC
+8FF4C2
+8FC1F8
+8FC2AB
+8FC2A1
+8FC2A5
+8FF4C3
+8FC2B8
+8FC2BA
+8FF4C4
+8FC2C4
+8FC2D2
+8FC2D7
+8FC2DB
+8FC2DE
+8FC2ED
+8FC2F0
+8FF4C5
+8FC3A1
+8FC3B5
+8FC3C9
+8FC3B9
+8FF4C6
+8FC3D8
+8FC3FE
+8FF4C7
+8FC4CC
+8FF4C8
+8FC4D9
+8FC4EA
+8FC4FD
+8FF4C9
+8FC5A7
+8FC5B5
+8FC5B6
+8FF4CA
+8FC5D5
+8FC6B8
+8FC6D7
+8FC6E0
+8FC6EA
+8FC6E3
+8FC7A1
+8FC7AB
+8FC7C7
+8FC7C3
+8FC7CB
+8FC7CF
+8FC7D9
+8FF4CB
+8FF4CC
+8FC7E6
+8FC7EE
+8FC7FC
+8FC7EB
+8FC7F0
+8FC8B1
+8FC8E5
+8FC8F8
+8FC9A6
+8FC9AB
+8FC9AD
+8FF4CD
+8FC9CA
+8FC9D3
+8FC9E9
+8FC9E3
+8FC9FC
+8FC9F4
+8FC9F5
+8FF4CE
+8FCAB3
+8FCABD
+8FCAEF
+8FCAF1
+8FCBAE
+8FF4CF
+8FCBCA
+8FCBE6
+8FCBEA
+8FCBF0
+8FCBF4
+8FCBEE
+8FCCA5
+8FCBF9
+8FCCAB
+8FCCAE
+8FCCAD
+8FCCB2
+8FCCC2
+8FCCD0
+8FCCD9
+8FF4D0
+8FCDBB
+8FF4D1
+8FCEBB
+8FF4D2
+8FCEBA
+8FCEC3
+8FF4D3
+8FCEF2
+8FB3DD
+8FCFD5
+8FCFE2
+8FCFE9
+8FCFED
+8FF4D4
+8FF4D5
+8FF4D6
+8FF4D7
+8FD0E5
+8FF4D8
+8FD0E9
+8FD1E8
+8FF4D9
+8FF4DA
+8FD1EC
+8FD2BB
+8FF4DB
+8FD3E1
+8FD3E8
+8FD4A7
+8FF4DC
+8FF4DD
+8FD4D4
+8FD4F2
+8FD5AE
+8FF4DE
+8FD7DE
+8FF4DF
+8FD8A2
+8FD8B7
+8FD8C1
+8FD8D1
+8FD8F4
+8FD9C6
+8FD9C8
+8FD9D1
+8FF4E0
+8FF4E1
+8FF4E2
+8FF4E3
+8FF4E4
+8FDCD3
+8FDDC8
+8FDDD4
+8FDDEA
+8FDDFA
+8FDEA4
+8FDEB0
+8FF4E5
+8FDEB5
+8FDECB
+8FF4E6
+8FDFB9
+8FF4E7
+8FDFC3
+8FF4E8
+8FF4E9
+8FE0D9
+8FF4EA
+8FF4EB
+8FE1E2
+8FF4EC
+8FF4ED
+8FF4EE
+8FE2C7
+8FE3A8
+8FE3A6
+8FE3A9
+8FE3AF
+8FE3B0
+8FE3AA
+8FE3AB
+8FE3BC
+8FE3C1
+8FE3BF
+8FE3D5
+8FE3D8
+8FE3D6
+8FE3DF
+8FE3E3
+8FE3E1
+8FE3D4
+8FE3E9
+8FE4A6
+8FE3F1
+8FE3F2
+8FE4CB
+8FE4C1
+8FE4C3
+8FE4BE
+8FF4EF
+8FE4C0
+8FE4C7
+8FE4BF
+8FE4E0
+8FE4DE
+8FE4D1
+8FF4F0
+8FE4DC
+8FE4D2
+8FE4DB
+8FE4D4
+8FE4FA
+8FE4EF
+8FE5B3
+8FE5BF
+8FE5C9
+8FE5D0
+8FE5E2
+8FE5EA
+8FE5EB
+8FF4F1
+8FF4F2
+8FF4F3
+8FE6E8
+8FE6EF
+8FE7AC
+8FF4F4
+8FE7AE
+8FF4F5
+8FE7B1
+8FF4F6
+8FE7B2
+8FE8B1
+8FE8B6
+8FF4F7
+8FF4F8
+8FE8DD
+8FF4F9
+8FF4FA
+8FE9D1
+8FF4FB
+8FE9ED
+8FEACD
+8FF4FC
+8FEADB
+8FEAE6
+8FEAEA
+8FEBA5
+8FEBFB
+8FEBFA
+8FF4FD
+8FECD6
+8FF4FE
+F5A1
+F5A2
+F5A3
+F5A4
+F5A5
+F5A6
+F5A7
+F5A8
+F5A9
+F5AA
+F5AB
+F5AC
+F5AD
+F5AE
+F5AF
+F5B0
+F5B1
+F5B2
+F5B3
+F5B4
+F5B5
+F5B6
+F5B7
+F5B8
+F5B9
+F5BA
+F5BB
+F5BC
+F5BD
+F5BE
+F5BF
+F5C0
+F5C1
+F5C2
+F5C3
+F5C4
+F5C5
+F5C6
+F5C7
+F5C8
+F5C9
+F5CA
+F5CB
+F5CC
+F5CD
+F5CE
+F5CF
+F5D0
+F5D1
+F5D2
+F5D3
+F5D4
+F5D5
+F5D6
+F5D7
+F5D8
+F5D9
+F5DA
+F5DB
+F5DC
+F5DD
+F5DE
+F5DF
+F5E0
+F5E1
+F5E2
+F5E3
+F5E4
+F5E5
+F5E6
+F5E7
+F5E8
+F5E9
+F5EA
+F5EB
+F5EC
+F5ED
+F5EE
+F5EF
+F5F0
+F5F1
+F5F2
+F5F3
+F5F4
+F5F5
+F5F6
+F5F7
+F5F8
+F5F9
+F5FA
+F5FB
+F5FC
+F5FD
+F5FE
+F6A1
+F6A2
+F6A3
+F6A4
+F6A5
+F6A6
+F6A7
+F6A8
+F6A9
+F6AA
+F6AB
+F6AC
+F6AD
+F6AE
+F6AF
+F6B0
+F6B1
+F6B2
+F6B3
+F6B4
+F6B5
+F6B6
+F6B7
+F6B8
+F6B9
+F6BA
+F6BB
+F6BC
+F6BD
+F6BE
+F6BF
+F6C0
+F6C1
+F6C2
+F6C3
+F6C4
+F6C5
+F6C6
+F6C7
+F6C8
+F6C9
+F6CA
+F6CB
+F6CC
+F6CD
+F6CE
+F6CF
+F6D0
+F6D1
+F6D2
+F6D3
+F6D4
+F6D5
+F6D6
+F6D7
+F6D8
+F6D9
+F6DA
+F6DB
+F6DC
+F6DD
+F6DE
+F6DF
+F6E0
+F6E1
+F6E2
+F6E3
+F6E4
+F6E5
+F6E6
+F6E7
+F6E8
+F6E9
+F6EA
+F6EB
+F6EC
+F6ED
+F6EE
+F6EF
+F6F0
+F6F1
+F6F2
+F6F3
+F6F4
+F6F5
+F6F6
+F6F7
+F6F8
+F6F9
+F6FA
+F6FB
+F6FC
+F6FD
+F6FE
+F7A1
+F7A2
+F7A3
+F7A4
+F7A5
+F7A6
+F7A7
+F7A8
+F7A9
+F7AA
+F7AB
+F7AC
+F7AD
+F7AE
+F7AF
+F7B0
+F7B1
+F7B2
+F7B3
+F7B4
+F7B5
+F7B6
+F7B7
+F7B8
+F7B9
+F7BA
+F7BB
+F7BC
+F7BD
+F7BE
+F7BF
+F7C0
+F7C1
+F7C2
+F7C3
+F7C4
+F7C5
+F7C6
+F7C7
+F7C8
+F7C9
+F7CA
+F7CB
+F7CC
+F7CD
+F7CE
+F7CF
+F7D0
+F7D1
+F7D2
+F7D3
+F7D4
+F7D5
+F7D6
+F7D7
+F7D8
+F7D9
+F7DA
+F7DB
+F7DC
+F7DD
+F7DE
+F7DF
+F7E0
+F7E1
+F7E2
+F7E3
+F7E4
+F7E5
+F7E6
+F7E7
+F7E8
+F7E9
+F7EA
+F7EB
+F7EC
+F7ED
+F7EE
+F7EF
+F7F0
+F7F1
+F7F2
+F7F3
+F7F4
+F7F5
+F7F6
+F7F7
+F7F8
+F7F9
+F7FA
+F7FB
+F7FC
+F7FD
+F7FE
+F8A1
+F8A2
+F8A3
+F8A4
+F8A5
+F8A6
+F8A7
+F8A8
+F8A9
+F8AA
+F8AB
+F8AC
+F8AD
+F8AE
+F8AF
+F8B0
+F8B1
+F8B2
+F8B3
+F8B4
+F8B5
+F8B6
+F8B7
+F8B8
+F8B9
+F8BA
+F8BB
+F8BC
+F8BD
+F8BE
+F8BF
+F8C0
+F8C1
+F8C2
+F8C3
+F8C4
+F8C5
+F8C6
+F8C7
+F8C8
+F8C9
+F8CA
+F8CB
+F8CC
+F8CD
+F8CE
+F8CF
+F8D0
+F8D1
+F8D2
+F8D3
+F8D4
+F8D5
+F8D6
+F8D7
+F8D8
+F8D9
+F8DA
+F8DB
+F8DC
+F8DD
+F8DE
+F8DF
+F8E0
+F8E1
+F8E2
+F8E3
+F8E4
+F8E5
+F8E6
+F8E7
+F8E8
+F8E9
+F8EA
+F8EB
+F8EC
+F8ED
+F8EE
+F8EF
+F8F0
+F8F1
+F8F2
+F8F3
+F8F4
+F8F5
+F8F6
+F8F7
+F8F8
+F8F9
+F8FA
+F8FB
+F8FC
+F8FD
+F8FE
+F9A1
+F9A2
+F9A3
+F9A4
+F9A5
+F9A6
+F9A7
+F9A8
+F9A9
+F9AA
+F9AB
+F9AC
+F9AD
+F9AE
+F9AF
+F9B0
+F9B1
+F9B2
+F9B3
+F9B4
+F9B5
+F9B6
+F9B7
+F9B8
+F9B9
+F9BA
+F9BB
+F9BC
+F9BD
+F9BE
+F9BF
+F9C0
+F9C1
+F9C2
+F9C3
+F9C4
+F9C5
+F9C6
+F9C7
+F9C8
+F9C9
+F9CA
+F9CB
+F9CC
+F9CD
+F9CE
+F9CF
+F9D0
+F9D1
+F9D2
+F9D3
+F9D4
+F9D5
+F9D6
+F9D7
+F9D8
+F9D9
+F9DA
+F9DB
+F9DC
+F9DD
+F9DE
+F9DF
+F9E0
+F9E1
+F9E2
+F9E3
+F9E4
+F9E5
+F9E6
+F9E7
+F9E8
+F9E9
+F9EA
+F9EB
+F9EC
+F9ED
+F9EE
+F9EF
+F9F0
+F9F1
+F9F2
+F9F3
+F9F4
+F9F5
+F9F6
+F9F7
+F9F8
+F9F9
+F9FA
+F9FB
+F9FC
+F9FD
+F9FE
+FAA1
+FAA2
+FAA3
+FAA4
+FAA5
+FAA6
+FAA7
+FAA8
+FAA9
+FAAA
+FAAB
+FAAC
+FAAD
+FAAE
+FAAF
+FAB0
+FAB1
+FAB2
+FAB3
+FAB4
+FAB5
+FAB6
+FAB7
+FAB8
+FAB9
+FABA
+FABB
+FABC
+FABD
+FABE
+FABF
+FAC0
+FAC1
+FAC2
+FAC3
+FAC4
+FAC5
+FAC6
+FAC7
+FAC8
+FAC9
+FACA
+FACB
+FACC
+FACD
+FACE
+FACF
+FAD0
+FAD1
+FAD2
+FAD3
+FAD4
+FAD5
+FAD6
+FAD7
+FAD8
+FAD9
+FADA
+FADB
+FADC
+FADD
+FADE
+FADF
+FAE0
+FAE1
+FAE2
+FAE3
+FAE4
+FAE5
+FAE6
+FAE7
+FAE8
+FAE9
+FAEA
+FAEB
+FAEC
+FAED
+FAEE
+FAEF
+FAF0
+FAF1
+FAF2
+FAF3
+FAF4
+FAF5
+FAF6
+FAF7
+FAF8
+FAF9
+FAFA
+FAFB
+FAFC
+FAFD
+FAFE
+FBA1
+FBA2
+FBA3
+FBA4
+FBA5
+FBA6
+FBA7
+FBA8
+FBA9
+FBAA
+FBAB
+FBAC
+FBAD
+FBAE
+FBAF
+FBB0
+FBB1
+FBB2
+FBB3
+FBB4
+FBB5
+FBB6
+FBB7
+FBB8
+FBB9
+FBBA
+FBBB
+FBBC
+FBBD
+FBBE
+FBBF
+FBC0
+FBC1
+FBC2
+FBC3
+FBC4
+FBC5
+FBC6
+FBC7
+FBC8
+FBC9
+FBCA
+FBCB
+FBCC
+FBCD
+FBCE
+FBCF
+FBD0
+FBD1
+FBD2
+FBD3
+FBD4
+FBD5
+FBD6
+FBD7
+FBD8
+FBD9
+FBDA
+FBDB
+FBDC
+FBDD
+FBDE
+FBDF
+FBE0
+FBE1
+FBE2
+FBE3
+FBE4
+FBE5
+FBE6
+FBE7
+FBE8
+FBE9
+FBEA
+FBEB
+FBEC
+FBED
+FBEE
+FBEF
+FBF0
+FBF1
+FBF2
+FBF3
+FBF4
+FBF5
+FBF6
+FBF7
+FBF8
+FBF9
+FBFA
+FBFB
+FBFC
+FBFD
+FBFE
+FCA1
+FCA2
+FCA3
+FCA4
+FCA5
+FCA6
+FCA7
+FCA8
+FCA9
+FCAA
+FCAB
+FCAC
+FCAD
+FCAE
+FCAF
+FCB0
+FCB1
+FCB2
+FCB3
+FCB4
+FCB5
+FCB6
+FCB7
+FCB8
+FCB9
+FCBA
+FCBB
+FCBC
+FCBD
+FCBE
+FCBF
+FCC0
+FCC1
+FCC2
+FCC3
+FCC4
+FCC5
+FCC6
+FCC7
+FCC8
+FCC9
+FCCA
+FCCB
+FCCC
+FCCD
+FCCE
+FCCF
+FCD0
+FCD1
+FCD2
+FCD3
+FCD4
+FCD5
+FCD6
+FCD7
+FCD8
+FCD9
+FCDA
+FCDB
+FCDC
+FCDD
+FCDE
+FCDF
+FCE0
+FCE1
+FCE2
+FCE3
+FCE4
+FCE5
+FCE6
+FCE7
+FCE8
+FCE9
+FCEA
+FCEB
+FCEC
+FCED
+FCEE
+FCEF
+FCF0
+FCF1
+FCF2
+FCF3
+FCF4
+FCF5
+FCF6
+FCF7
+FCF8
+FCF9
+FCFA
+FCFB
+FCFC
+FCFD
+FCFE
+FDA1
+FDA2
+FDA3
+FDA4
+FDA5
+FDA6
+FDA7
+FDA8
+FDA9
+FDAA
+FDAB
+FDAC
+FDAD
+FDAE
+FDAF
+FDB0
+FDB1
+FDB2
+FDB3
+FDB4
+FDB5
+FDB6
+FDB7
+FDB8
+FDB9
+FDBA
+FDBB
+FDBC
+FDBD
+FDBE
+FDBF
+FDC0
+FDC1
+FDC2
+FDC3
+FDC4
+FDC5
+FDC6
+FDC7
+FDC8
+FDC9
+FDCA
+FDCB
+FDCC
+FDCD
+FDCE
+FDCF
+FDD0
+FDD1
+FDD2
+FDD3
+FDD4
+FDD5
+FDD6
+FDD7
+FDD8
+FDD9
+FDDA
+FDDB
+FDDC
+FDDD
+FDDE
+FDDF
+FDE0
+FDE1
+FDE2
+FDE3
+FDE4
+FDE5
+FDE6
+FDE7
+FDE8
+FDE9
+FDEA
+FDEB
+FDEC
+FDED
+FDEE
+FDEF
+FDF0
+FDF1
+FDF2
+FDF3
+FDF4
+FDF5
+FDF6
+FDF7
+FDF8
+FDF9
+FDFA
+FDFB
+FDFC
+FDFD
+FDFE
+FEA1
+FEA2
+FEA3
+FEA4
+FEA5
+FEA6
+FEA7
+FEA8
+FEA9
+FEAA
+FEAB
+FEAC
+FEAD
+FEAE
+FEAF
+FEB0
+FEB1
+FEB2
+FEB3
+FEB4
+FEB5
+FEB6
+FEB7
+FEB8
+FEB9
+FEBA
+FEBB
+FEBC
+FEBD
+FEBE
+FEBF
+FEC0
+FEC1
+FEC2
+FEC3
+FEC4
+FEC5
+FEC6
+FEC7
+FEC8
+FEC9
+FECA
+FECB
+FECC
+FECD
+FECE
+FECF
+FED0
+FED1
+FED2
+FED3
+FED4
+FED5
+FED6
+FED7
+FED8
+FED9
+FEDA
+FEDB
+FEDC
+FEDD
+FEDE
+FEDF
+FEE0
+FEE1
+FEE2
+FEE3
+FEE4
+FEE5
+FEE6
+FEE7
+FEE8
+FEE9
+FEEA
+FEEB
+FEEC
+FEED
+FEEE
+FEEF
+FEF0
+FEF1
+FEF2
+FEF3
+FEF4
+FEF5
+FEF6
+FEF7
+FEF8
+FEF9
+FEFA
+FEFB
+FEFC
+FEFD
+FEFE
+8FF5A1
+8FF5A2
+8FF5A3
+8FF5A4
+8FF5A5
+8FF5A6
+8FF5A7
+8FF5A8
+8FF5A9
+8FF5AA
+8FF5AB
+8FF5AC
+8FF5AD
+8FF5AE
+8FF5AF
+8FF5B0
+8FF5B1
+8FF5B2
+8FF5B3
+8FF5B4
+8FF5B5
+8FF5B6
+8FF5B7
+8FF5B8
+8FF5B9
+8FF5BA
+8FF5BB
+8FF5BC
+8FF5BD
+8FF5BE
+8FF5BF
+8FF5C0
+8FF5C1
+8FF5C2
+8FF5C3
+8FF5C4
+8FF5C5
+8FF5C6
+8FF5C7
+8FF5C8
+8FF5C9
+8FF5CA
+8FF5CB
+8FF5CC
+8FF5CD
+8FF5CE
+8FF5CF
+8FF5D0
+8FF5D1
+8FF5D2
+8FF5D3
+8FF5D4
+8FF5D5
+8FF5D6
+8FF5D7
+8FF5D8
+8FF5D9
+8FF5DA
+8FF5DB
+8FF5DC
+8FF5DD
+8FF5DE
+8FF5DF
+8FF5E0
+8FF5E1
+8FF5E2
+8FF5E3
+8FF5E4
+8FF5E5
+8FF5E6
+8FF5E7
+8FF5E8
+8FF5E9
+8FF5EA
+8FF5EB
+8FF5EC
+8FF5ED
+8FF5EE
+8FF5EF
+8FF5F0
+8FF5F1
+8FF5F2
+8FF5F3
+8FF5F4
+8FF5F5
+8FF5F6
+8FF5F7
+8FF5F8
+8FF5F9
+8FF5FA
+8FF5FB
+8FF5FC
+8FF5FD
+8FF5FE
+8FF6A1
+8FF6A2
+8FF6A3
+8FF6A4
+8FF6A5
+8FF6A6
+8FF6A7
+8FF6A8
+8FF6A9
+8FF6AA
+8FF6AB
+8FF6AC
+8FF6AD
+8FF6AE
+8FF6AF
+8FF6B0
+8FF6B1
+8FF6B2
+8FF6B3
+8FF6B4
+8FF6B5
+8FF6B6
+8FF6B7
+8FF6B8
+8FF6B9
+8FF6BA
+8FF6BB
+8FF6BC
+8FF6BD
+8FF6BE
+8FF6BF
+8FF6C0
+8FF6C1
+8FF6C2
+8FF6C3
+8FF6C4
+8FF6C5
+8FF6C6
+8FF6C7
+8FF6C8
+8FF6C9
+8FF6CA
+8FF6CB
+8FF6CC
+8FF6CD
+8FF6CE
+8FF6CF
+8FF6D0
+8FF6D1
+8FF6D2
+8FF6D3
+8FF6D4
+8FF6D5
+8FF6D6
+8FF6D7
+8FF6D8
+8FF6D9
+8FF6DA
+8FF6DB
+8FF6DC
+8FF6DD
+8FF6DE
+8FF6DF
+8FF6E0
+8FF6E1
+8FF6E2
+8FF6E3
+8FF6E4
+8FF6E5
+8FF6E6
+8FF6E7
+8FF6E8
+8FF6E9
+8FF6EA
+8FF6EB
+8FF6EC
+8FF6ED
+8FF6EE
+8FF6EF
+8FF6F0
+8FF6F1
+8FF6F2
+8FF6F3
+8FF6F4
+8FF6F5
+8FF6F6
+8FF6F7
+8FF6F8
+8FF6F9
+8FF6FA
+8FF6FB
+8FF6FC
+8FF6FD
+8FF6FE
+8FF7A1
+8FF7A2
+8FF7A3
+8FF7A4
+8FF7A5
+8FF7A6
+8FF7A7
+8FF7A8
+8FF7A9
+8FF7AA
+8FF7AB
+8FF7AC
+8FF7AD
+8FF7AE
+8FF7AF
+8FF7B0
+8FF7B1
+8FF7B2
+8FF7B3
+8FF7B4
+8FF7B5
+8FF7B6
+8FF7B7
+8FF7B8
+8FF7B9
+8FF7BA
+8FF7BB
+8FF7BC
+8FF7BD
+8FF7BE
+8FF7BF
+8FF7C0
+8FF7C1
+8FF7C2
+8FF7C3
+8FF7C4
+8FF7C5
+8FF7C6
+8FF7C7
+8FF7C8
+8FF7C9
+8FF7CA
+8FF7CB
+8FF7CC
+8FF7CD
+8FF7CE
+8FF7CF
+8FF7D0
+8FF7D1
+8FF7D2
+8FF7D3
+8FF7D4
+8FF7D5
+8FF7D6
+8FF7D7
+8FF7D8
+8FF7D9
+8FF7DA
+8FF7DB
+8FF7DC
+8FF7DD
+8FF7DE
+8FF7DF
+8FF7E0
+8FF7E1
+8FF7E2
+8FF7E3
+8FF7E4
+8FF7E5
+8FF7E6
+8FF7E7
+8FF7E8
+8FF7E9
+8FF7EA
+8FF7EB
+8FF7EC
+8FF7ED
+8FF7EE
+8FF7EF
+8FF7F0
+8FF7F1
+8FF7F2
+8FF7F3
+8FF7F4
+8FF7F5
+8FF7F6
+8FF7F7
+8FF7F8
+8FF7F9
+8FF7FA
+8FF7FB
+8FF7FC
+8FF7FD
+8FF7FE
+8FF8A1
+8FF8A2
+8FF8A3
+8FF8A4
+8FF8A5
+8FF8A6
+8FF8A7
+8FF8A8
+8FF8A9
+8FF8AA
+8FF8AB
+8FF8AC
+8FF8AD
+8FF8AE
+8FF8AF
+8FF8B0
+8FF8B1
+8FF8B2
+8FF8B3
+8FF8B4
+8FF8B5
+8FF8B6
+8FF8B7
+8FF8B8
+8FF8B9
+8FF8BA
+8FF8BB
+8FF8BC
+8FF8BD
+8FF8BE
+8FF8BF
+8FF8C0
+8FF8C1
+8FF8C2
+8FF8C3
+8FF8C4
+8FF8C5
+8FF8C6
+8FF8C7
+8FF8C8
+8FF8C9
+8FF8CA
+8FF8CB
+8FF8CC
+8FF8CD
+8FF8CE
+8FF8CF
+8FF8D0
+8FF8D1
+8FF8D2
+8FF8D3
+8FF8D4
+8FF8D5
+8FF8D6
+8FF8D7
+8FF8D8
+8FF8D9
+8FF8DA
+8FF8DB
+8FF8DC
+8FF8DD
+8FF8DE
+8FF8DF
+8FF8E0
+8FF8E1
+8FF8E2
+8FF8E3
+8FF8E4
+8FF8E5
+8FF8E6
+8FF8E7
+8FF8E8
+8FF8E9
+8FF8EA
+8FF8EB
+8FF8EC
+8FF8ED
+8FF8EE
+8FF8EF
+8FF8F0
+8FF8F1
+8FF8F2
+8FF8F3
+8FF8F4
+8FF8F5
+8FF8F6
+8FF8F7
+8FF8F8
+8FF8F9
+8FF8FA
+8FF8FB
+8FF8FC
+8FF8FD
+8FF8FE
+8FF9A1
+8FF9A2
+8FF9A3
+8FF9A4
+8FF9A5
+8FF9A6
+8FF9A7
+8FF9A8
+8FF9A9
+8FF9AA
+8FF9AB
+8FF9AC
+8FF9AD
+8FF9AE
+8FF9AF
+8FF9B0
+8FF9B1
+8FF9B2
+8FF9B3
+8FF9B4
+8FF9B5
+8FF9B6
+8FF9B7
+8FF9B8
+8FF9B9
+8FF9BA
+8FF9BB
+8FF9BC
+8FF9BD
+8FF9BE
+8FF9BF
+8FF9C0
+8FF9C1
+8FF9C2
+8FF9C3
+8FF9C4
+8FF9C5
+8FF9C6
+8FF9C7
+8FF9C8
+8FF9C9
+8FF9CA
+8FF9CB
+8FF9CC
+8FF9CD
+8FF9CE
+8FF9CF
+8FF9D0
+8FF9D1
+8FF9D2
+8FF9D3
+8FF9D4
+8FF9D5
+8FF9D6
+8FF9D7
+8FF9D8
+8FF9D9
+8FF9DA
+8FF9DB
+8FF9DC
+8FF9DD
+8FF9DE
+8FF9DF
+8FF9E0
+8FF9E1
+8FF9E2
+8FF9E3
+8FF9E4
+8FF9E5
+8FF9E6
+8FF9E7
+8FF9E8
+8FF9E9
+8FF9EA
+8FF9EB
+8FF9EC
+8FF9ED
+8FF9EE
+8FF9EF
+8FF9F0
+8FF9F1
+8FF9F2
+8FF9F3
+8FF9F4
+8FF9F5
+8FF9F6
+8FF9F7
+8FF9F8
+8FF9F9
+8FF9FA
+8FF9FB
+8FF9FC
+8FF9FD
+8FF9FE
+8FFAA1
+8FFAA2
+8FFAA3
+8FFAA4
+8FFAA5
+8FFAA6
+8FFAA7
+8FFAA8
+8FFAA9
+8FFAAA
+8FFAAB
+8FFAAC
+8FFAAD
+8FFAAE
+8FFAAF
+8FFAB0
+8FFAB1
+8FFAB2
+8FFAB3
+8FFAB4
+8FFAB5
+8FFAB6
+8FFAB7
+8FFAB8
+8FFAB9
+8FFABA
+8FFABB
+8FFABC
+8FFABD
+8FFABE
+8FFABF
+8FFAC0
+8FFAC1
+8FFAC2
+8FFAC3
+8FFAC4
+8FFAC5
+8FFAC6
+8FFAC7
+8FFAC8
+8FFAC9
+8FFACA
+8FFACB
+8FFACC
+8FFACD
+8FFACE
+8FFACF
+8FFAD0
+8FFAD1
+8FFAD2
+8FFAD3
+8FFAD4
+8FFAD5
+8FFAD6
+8FFAD7
+8FFAD8
+8FFAD9
+8FFADA
+8FFADB
+8FFADC
+8FFADD
+8FFADE
+8FFADF
+8FFAE0
+8FFAE1
+8FFAE2
+8FFAE3
+8FFAE4
+8FFAE5
+8FFAE6
+8FFAE7
+8FFAE8
+8FFAE9
+8FFAEA
+8FFAEB
+8FFAEC
+8FFAED
+8FFAEE
+8FFAEF
+8FFAF0
+8FFAF1
+8FFAF2
+8FFAF3
+8FFAF4
+8FFAF5
+8FFAF6
+8FFAF7
+8FFAF8
+8FFAF9
+8FFAFA
+8FFAFB
+8FFAFC
+8FFAFD
+8FFAFE
+8FFBA1
+8FFBA2
+8FFBA3
+8FFBA4
+8FFBA5
+8FFBA6
+8FFBA7
+8FFBA8
+8FFBA9
+8FFBAA
+8FFBAB
+8FFBAC
+8FFBAD
+8FFBAE
+8FFBAF
+8FFBB0
+8FFBB1
+8FFBB2
+8FFBB3
+8FFBB4
+8FFBB5
+8FFBB6
+8FFBB7
+8FFBB8
+8FFBB9
+8FFBBA
+8FFBBB
+8FFBBC
+8FFBBD
+8FFBBE
+8FFBBF
+8FFBC0
+8FFBC1
+8FFBC2
+8FFBC3
+8FFBC4
+8FFBC5
+8FFBC6
+8FFBC7
+8FFBC8
+8FFBC9
+8FFBCA
+8FFBCB
+8FFBCC
+8FFBCD
+8FFBCE
+8FFBCF
+8FFBD0
+8FFBD1
+8FFBD2
+8FFBD3
+8FFBD4
+8FFBD5
+8FFBD6
+8FFBD7
+8FFBD8
+8FFBD9
+8FFBDA
+8FFBDB
+8FFBDC
+8FFBDD
+8FFBDE
+8FFBDF
+8FFBE0
+8FFBE1
+8FFBE2
+8FFBE3
+8FFBE4
+8FFBE5
+8FFBE6
+8FFBE7
+8FFBE8
+8FFBE9
+8FFBEA
+8FFBEB
+8FFBEC
+8FFBED
+8FFBEE
+8FFBEF
+8FFBF0
+8FFBF1
+8FFBF2
+8FFBF3
+8FFBF4
+8FFBF5
+8FFBF6
+8FFBF7
+8FFBF8
+8FFBF9
+8FFBFA
+8FFBFB
+8FFBFC
+8FFBFD
+8FFBFE
+8FFCA1
+8FFCA2
+8FFCA3
+8FFCA4
+8FFCA5
+8FFCA6
+8FFCA7
+8FFCA8
+8FFCA9
+8FFCAA
+8FFCAB
+8FFCAC
+8FFCAD
+8FFCAE
+8FFCAF
+8FFCB0
+8FFCB1
+8FFCB2
+8FFCB3
+8FFCB4
+8FFCB5
+8FFCB6
+8FFCB7
+8FFCB8
+8FFCB9
+8FFCBA
+8FFCBB
+8FFCBC
+8FFCBD
+8FFCBE
+8FFCBF
+8FFCC0
+8FFCC1
+8FFCC2
+8FFCC3
+8FFCC4
+8FFCC5
+8FFCC6
+8FFCC7
+8FFCC8
+8FFCC9
+8FFCCA
+8FFCCB
+8FFCCC
+8FFCCD
+8FFCCE
+8FFCCF
+8FFCD0
+8FFCD1
+8FFCD2
+8FFCD3
+8FFCD4
+8FFCD5
+8FFCD6
+8FFCD7
+8FFCD8
+8FFCD9
+8FFCDA
+8FFCDB
+8FFCDC
+8FFCDD
+8FFCDE
+8FFCDF
+8FFCE0
+8FFCE1
+8FFCE2
+8FFCE3
+8FFCE4
+8FFCE5
+8FFCE6
+8FFCE7
+8FFCE8
+8FFCE9
+8FFCEA
+8FFCEB
+8FFCEC
+8FFCED
+8FFCEE
+8FFCEF
+8FFCF0
+8FFCF1
+8FFCF2
+8FFCF3
+8FFCF4
+8FFCF5
+8FFCF6
+8FFCF7
+8FFCF8
+8FFCF9
+8FFCFA
+8FFCFB
+8FFCFC
+8FFCFD
+8FFCFE
+8FFDA1
+8FFDA2
+8FFDA3
+8FFDA4
+8FFDA5
+8FFDA6
+8FFDA7
+8FFDA8
+8FFDA9
+8FFDAA
+8FFDAB
+8FFDAC
+8FFDAD
+8FFDAE
+8FFDAF
+8FFDB0
+8FFDB1
+8FFDB2
+8FFDB3
+8FFDB4
+8FFDB5
+8FFDB6
+8FFDB7
+8FFDB8
+8FFDB9
+8FFDBA
+8FFDBB
+8FFDBC
+8FFDBD
+8FFDBE
+8FFDBF
+8FFDC0
+8FFDC1
+8FFDC2
+8FFDC3
+8FFDC4
+8FFDC5
+8FFDC6
+8FFDC7
+8FFDC8
+8FFDC9
+8FFDCA
+8FFDCB
+8FFDCC
+8FFDCD
+8FFDCE
+8FFDCF
+8FFDD0
+8FFDD1
+8FFDD2
+8FFDD3
+8FFDD4
+8FFDD5
+8FFDD6
+8FFDD7
+8FFDD8
+8FFDD9
+8FFDDA
+8FFDDB
+8FFDDC
+8FFDDD
+8FFDDE
+8FFDDF
+8FFDE0
+8FFDE1
+8FFDE2
+8FFDE3
+8FFDE4
+8FFDE5
+8FFDE6
+8FFDE7
+8FFDE8
+8FFDE9
+8FFDEA
+8FFDEB
+8FFDEC
+8FFDED
+8FFDEE
+8FFDEF
+8FFDF0
+8FFDF1
+8FFDF2
+8FFDF3
+8FFDF4
+8FFDF5
+8FFDF6
+8FFDF7
+8FFDF8
+8FFDF9
+8FFDFA
+8FFDFB
+8FFDFC
+8FFDFD
+8FFDFE
+8FFEA1
+8FFEA2
+8FFEA3
+8FFEA4
+8FFEA5
+8FFEA6
+8FFEA7
+8FFEA8
+8FFEA9
+8FFEAA
+8FFEAB
+8FFEAC
+8FFEAD
+8FFEAE
+8FFEAF
+8FFEB0
+8FFEB1
+8FFEB2
+8FFEB3
+8FFEB4
+8FFEB5
+8FFEB6
+8FFEB7
+8FFEB8
+8FFEB9
+8FFEBA
+8FFEBB
+8FFEBC
+8FFEBD
+8FFEBE
+8FFEBF
+8FFEC0
+8FFEC1
+8FFEC2
+8FFEC3
+8FFEC4
+8FFEC5
+8FFEC6
+8FFEC7
+8FFEC8
+8FFEC9
+8FFECA
+8FFECB
+8FFECC
+8FFECD
+8FFECE
+8FFECF
+8FFED0
+8FFED1
+8FFED2
+8FFED3
+8FFED4
+8FFED5
+8FFED6
+8FFED7
+8FFED8
+8FFED9
+8FFEDA
+8FFEDB
+8FFEDC
+8FFEDD
+8FFEDE
+8FFEDF
+8FFEE0
+8FFEE1
+8FFEE2
+8FFEE3
+8FFEE4
+8FFEE5
+8FFEE6
+8FFEE7
+8FFEE8
+8FFEE9
+8FFEEA
+8FFEEB
+8FFEEC
+8FFEED
+8FFEEE
+8FFEEF
+8FFEF0
+8FFEF1
+8FFEF2
+8FFEF3
+8FFEF4
+8FFEF5
+8FFEF6
+8FFEF7
+8FFEF8
+8FFEF9
+8FFEFA
+8FFEFB
+8FFEFC
+8FFEFD
+8FFEFE
+CREATE TABLE t4 SELECT CONVERT(c1 USING cp932) AS c1 FROM t1;
+SELECT HEX(c1) FROM t4;
+HEX(c1)
+5C
+7E
+8150
+815C
+815F
+8160
+8161
+817C
+8191
+8192
+818F
+81CA
+8160
+FA55
+8740
+8741
+8742
+8743
+8744
+8745
+8746
+8747
+8748
+8749
+874A
+874B
+874C
+874D
+874E
+874F
+8750
+8751
+8752
+8753
+8754
+8755
+8756
+8757
+8758
+8759
+875A
+875B
+875C
+875D
+875F
+8760
+8761
+8762
+8763
+8764
+8765
+8766
+8767
+8768
+8769
+876A
+876B
+876C
+876D
+876E
+876F
+8770
+8771
+8772
+8773
+8774
+8775
+877E
+8780
+8781
+8782
+8783
+8784
+8785
+8786
+8787
+8788
+8789
+878A
+878B
+878C
+878D
+878E
+878F
+81E0
+81DF
+81E7
+8793
+8794
+81E3
+81DB
+81DA
+8798
+8799
+81E6
+81BF
+81BE
+FA40
+FA41
+FA42
+FA43
+FA44
+FA45
+FA46
+FA47
+FA48
+FA49
+8754
+8755
+8756
+8757
+8758
+8759
+875A
+875B
+875C
+875D
+81CA
+FA55
+FA56
+FA57
+878A
+8782
+8784
+81E6
+FA5C
+FA5D
+FA5E
+FA5F
+FA60
+FA61
+FA62
+FA63
+FA64
+FA65
+FA66
+FA67
+FA68
+FA69
+FA6A
+FA6B
+FA6C
+FA6D
+FA6E
+FA6F
+FA70
+FA71
+FA72
+FA73
+FA74
+FA75
+FA76
+FA77
+FA78
+FA79
+FA7A
+FA7B
+FA7C
+FA7D
+FA7E
+FA80
+FA81
+FA82
+FA83
+FA84
+FA85
+FA86
+FA87
+FA88
+FA89
+FA8A
+FA8B
+FA8C
+FA8D
+FA8E
+FA8F
+FA90
+FA91
+FA92
+FA93
+FA94
+FA95
+FA96
+FA97
+FA98
+FA99
+FA9A
+FA9B
+FA9C
+FA9D
+FA9E
+FA9F
+FAA0
+FAA1
+FAA2
+FAA3
+FAA4
+FAA5
+FAA6
+FAA7
+FAA8
+FAA9
+FAAA
+FAAB
+FAAC
+FAAD
+FAAE
+FAAF
+FAB0
+FAB1
+FAB2
+FAB3
+FAB4
+FAB5
+FAB6
+FAB7
+FAB8
+FAB9
+FABA
+FABB
+FABC
+FABD
+FABE
+FABF
+FAC0
+FAC1
+FAC2
+FAC3
+FAC4
+FAC5
+FAC6
+FAC7
+FAC8
+FAC9
+FACA
+FACB
+FACC
+FACD
+FACE
+FACF
+FAD0
+FAD1
+FAD2
+FAD3
+FAD4
+FAD5
+FAD6
+FAD7
+FAD8
+FAD9
+FADA
+FADB
+FADC
+FADD
+FADE
+FADF
+FAE0
+FAE1
+FAE2
+FAE3
+FAE4
+FAE5
+FAE6
+FAE7
+FAE8
+FAE9
+FAEA
+FAEB
+FAEC
+FAED
+FAEE
+FAEF
+FAF0
+FAF1
+FAF2
+FAF3
+FAF4
+FAF5
+FAF6
+FAF7
+FAF8
+FAF9
+FAFA
+FAFB
+FAFC
+FB40
+FB41
+FB42
+FB43
+FB44
+FB45
+FB46
+FB47
+FB48
+FB49
+FB4A
+FB4B
+FB4C
+FB4D
+FB4E
+FB4F
+FB50
+FB51
+FB52
+FB53
+FB54
+FB55
+FB56
+FB57
+FB58
+FB59
+FB5A
+FB5B
+FB5C
+FB5D
+FB5E
+FB5F
+FB60
+FB61
+FB62
+FB63
+FB64
+FB65
+FB66
+FB67
+FB68
+FB69
+FB6A
+FB6B
+FB6C
+FB6D
+FB6E
+FB6F
+FB70
+FB71
+FB72
+FB73
+FB74
+FB75
+FB76
+FB77
+FB78
+FB79
+FB7A
+FB7B
+FB7C
+FB7D
+FB7E
+FB80
+FB81
+FB82
+FB83
+FB84
+FB85
+FB86
+FB87
+FB88
+FB89
+FB8A
+FB8B
+FB8C
+FB8D
+FB8E
+FB8F
+FB90
+FB91
+FB92
+FB93
+FB94
+FB95
+FB96
+FB97
+FB98
+FB99
+FB9A
+FB9B
+FB9C
+FB9D
+FB9E
+FB9F
+FBA0
+FBA1
+FBA2
+FBA3
+FBA4
+FBA5
+FBA6
+FBA7
+FBA8
+FBA9
+FBAA
+FBAB
+FBAC
+FBAD
+FBAE
+FBAF
+FBB0
+FBB1
+FBB2
+FBB3
+FBB4
+FBB5
+FBB6
+FBB7
+FBB8
+FBB9
+FBBA
+FBBB
+FBBC
+FBBD
+FBBE
+FBBF
+FBC0
+FBC1
+FBC2
+FBC3
+FBC4
+FBC5
+FBC6
+FBC7
+FBC8
+FBC9
+FBCA
+FBCB
+FBCC
+FBCD
+FBCE
+FBCF
+FBD0
+FBD1
+FBD2
+FBD3
+FBD4
+FBD5
+FBD6
+FBD7
+FBD8
+FBD9
+FBDA
+FBDB
+FBDC
+FBDD
+FBDE
+FBDF
+FBE0
+FBE1
+FBE2
+FBE3
+FBE4
+FBE5
+FBE6
+FBE7
+FBE8
+FBE9
+FBEA
+FBEB
+FBEC
+FBED
+FBEE
+FBEF
+FBF0
+FBF1
+FBF2
+FBF3
+FBF4
+FBF5
+FBF6
+FBF7
+FBF8
+FBF9
+FBFA
+FBFB
+FBFC
+FC40
+FC41
+FC42
+FC43
+FC44
+FC45
+FC46
+FC47
+FC48
+FC49
+FC4A
+FC4B
+F040
+F041
+F042
+F043
+F044
+F045
+F046
+F047
+F048
+F049
+F04A
+F04B
+F04C
+F04D
+F04E
+F04F
+F050
+F051
+F052
+F053
+F054
+F055
+F056
+F057
+F058
+F059
+F05A
+F05B
+F05C
+F05D
+F05E
+F05F
+F060
+F061
+F062
+F063
+F064
+F065
+F066
+F067
+F068
+F069
+F06A
+F06B
+F06C
+F06D
+F06E
+F06F
+F070
+F071
+F072
+F073
+F074
+F075
+F076
+F077
+F078
+F079
+F07A
+F07B
+F07C
+F07D
+F07E
+F080
+F081
+F082
+F083
+F084
+F085
+F086
+F087
+F088
+F089
+F08A
+F08B
+F08C
+F08D
+F08E
+F08F
+F090
+F091
+F092
+F093
+F094
+F095
+F096
+F097
+F098
+F099
+F09A
+F09B
+F09C
+F09D
+F09E
+F09F
+F0A0
+F0A1
+F0A2
+F0A3
+F0A4
+F0A5
+F0A6
+F0A7
+F0A8
+F0A9
+F0AA
+F0AB
+F0AC
+F0AD
+F0AE
+F0AF
+F0B0
+F0B1
+F0B2
+F0B3
+F0B4
+F0B5
+F0B6
+F0B7
+F0B8
+F0B9
+F0BA
+F0BB
+F0BC
+F0BD
+F0BE
+F0BF
+F0C0
+F0C1
+F0C2
+F0C3
+F0C4
+F0C5
+F0C6
+F0C7
+F0C8
+F0C9
+F0CA
+F0CB
+F0CC
+F0CD
+F0CE
+F0CF
+F0D0
+F0D1
+F0D2
+F0D3
+F0D4
+F0D5
+F0D6
+F0D7
+F0D8
+F0D9
+F0DA
+F0DB
+F0DC
+F0DD
+F0DE
+F0DF
+F0E0
+F0E1
+F0E2
+F0E3
+F0E4
+F0E5
+F0E6
+F0E7
+F0E8
+F0E9
+F0EA
+F0EB
+F0EC
+F0ED
+F0EE
+F0EF
+F0F0
+F0F1
+F0F2
+F0F3
+F0F4
+F0F5
+F0F6
+F0F7
+F0F8
+F0F9
+F0FA
+F0FB
+F0FC
+F140
+F141
+F142
+F143
+F144
+F145
+F146
+F147
+F148
+F149
+F14A
+F14B
+F14C
+F14D
+F14E
+F14F
+F150
+F151
+F152
+F153
+F154
+F155
+F156
+F157
+F158
+F159
+F15A
+F15B
+F15C
+F15D
+F15E
+F15F
+F160
+F161
+F162
+F163
+F164
+F165
+F166
+F167
+F168
+F169
+F16A
+F16B
+F16C
+F16D
+F16E
+F16F
+F170
+F171
+F172
+F173
+F174
+F175
+F176
+F177
+F178
+F179
+F17A
+F17B
+F17C
+F17D
+F17E
+F180
+F181
+F182
+F183
+F184
+F185
+F186
+F187
+F188
+F189
+F18A
+F18B
+F18C
+F18D
+F18E
+F18F
+F190
+F191
+F192
+F193
+F194
+F195
+F196
+F197
+F198
+F199
+F19A
+F19B
+F19C
+F19D
+F19E
+F19F
+F1A0
+F1A1
+F1A2
+F1A3
+F1A4
+F1A5
+F1A6
+F1A7
+F1A8
+F1A9
+F1AA
+F1AB
+F1AC
+F1AD
+F1AE
+F1AF
+F1B0
+F1B1
+F1B2
+F1B3
+F1B4
+F1B5
+F1B6
+F1B7
+F1B8
+F1B9
+F1BA
+F1BB
+F1BC
+F1BD
+F1BE
+F1BF
+F1C0
+F1C1
+F1C2
+F1C3
+F1C4
+F1C5
+F1C6
+F1C7
+F1C8
+F1C9
+F1CA
+F1CB
+F1CC
+F1CD
+F1CE
+F1CF
+F1D0
+F1D1
+F1D2
+F1D3
+F1D4
+F1D5
+F1D6
+F1D7
+F1D8
+F1D9
+F1DA
+F1DB
+F1DC
+F1DD
+F1DE
+F1DF
+F1E0
+F1E1
+F1E2
+F1E3
+F1E4
+F1E5
+F1E6
+F1E7
+F1E8
+F1E9
+F1EA
+F1EB
+F1EC
+F1ED
+F1EE
+F1EF
+F1F0
+F1F1
+F1F2
+F1F3
+F1F4
+F1F5
+F1F6
+F1F7
+F1F8
+F1F9
+F1FA
+F1FB
+F1FC
+F240
+F241
+F242
+F243
+F244
+F245
+F246
+F247
+F248
+F249
+F24A
+F24B
+F24C
+F24D
+F24E
+F24F
+F250
+F251
+F252
+F253
+F254
+F255
+F256
+F257
+F258
+F259
+F25A
+F25B
+F25C
+F25D
+F25E
+F25F
+F260
+F261
+F262
+F263
+F264
+F265
+F266
+F267
+F268
+F269
+F26A
+F26B
+F26C
+F26D
+F26E
+F26F
+F270
+F271
+F272
+F273
+F274
+F275
+F276
+F277
+F278
+F279
+F27A
+F27B
+F27C
+F27D
+F27E
+F280
+F281
+F282
+F283
+F284
+F285
+F286
+F287
+F288
+F289
+F28A
+F28B
+F28C
+F28D
+F28E
+F28F
+F290
+F291
+F292
+F293
+F294
+F295
+F296
+F297
+F298
+F299
+F29A
+F29B
+F29C
+F29D
+F29E
+F29F
+F2A0
+F2A1
+F2A2
+F2A3
+F2A4
+F2A5
+F2A6
+F2A7
+F2A8
+F2A9
+F2AA
+F2AB
+F2AC
+F2AD
+F2AE
+F2AF
+F2B0
+F2B1
+F2B2
+F2B3
+F2B4
+F2B5
+F2B6
+F2B7
+F2B8
+F2B9
+F2BA
+F2BB
+F2BC
+F2BD
+F2BE
+F2BF
+F2C0
+F2C1
+F2C2
+F2C3
+F2C4
+F2C5
+F2C6
+F2C7
+F2C8
+F2C9
+F2CA
+F2CB
+F2CC
+F2CD
+F2CE
+F2CF
+F2D0
+F2D1
+F2D2
+F2D3
+F2D4
+F2D5
+F2D6
+F2D7
+F2D8
+F2D9
+F2DA
+F2DB
+F2DC
+F2DD
+F2DE
+F2DF
+F2E0
+F2E1
+F2E2
+F2E3
+F2E4
+F2E5
+F2E6
+F2E7
+F2E8
+F2E9
+F2EA
+F2EB
+F2EC
+F2ED
+F2EE
+F2EF
+F2F0
+F2F1
+F2F2
+F2F3
+F2F4
+F2F5
+F2F6
+F2F7
+F2F8
+F2F9
+F2FA
+F2FB
+F2FC
+F340
+F341
+F342
+F343
+F344
+F345
+F346
+F347
+F348
+F349
+F34A
+F34B
+F34C
+F34D
+F34E
+F34F
+F350
+F351
+F352
+F353
+F354
+F355
+F356
+F357
+F358
+F359
+F35A
+F35B
+F35C
+F35D
+F35E
+F35F
+F360
+F361
+F362
+F363
+F364
+F365
+F366
+F367
+F368
+F369
+F36A
+F36B
+F36C
+F36D
+F36E
+F36F
+F370
+F371
+F372
+F373
+F374
+F375
+F376
+F377
+F378
+F379
+F37A
+F37B
+F37C
+F37D
+F37E
+F380
+F381
+F382
+F383
+F384
+F385
+F386
+F387
+F388
+F389
+F38A
+F38B
+F38C
+F38D
+F38E
+F38F
+F390
+F391
+F392
+F393
+F394
+F395
+F396
+F397
+F398
+F399
+F39A
+F39B
+F39C
+F39D
+F39E
+F39F
+F3A0
+F3A1
+F3A2
+F3A3
+F3A4
+F3A5
+F3A6
+F3A7
+F3A8
+F3A9
+F3AA
+F3AB
+F3AC
+F3AD
+F3AE
+F3AF
+F3B0
+F3B1
+F3B2
+F3B3
+F3B4
+F3B5
+F3B6
+F3B7
+F3B8
+F3B9
+F3BA
+F3BB
+F3BC
+F3BD
+F3BE
+F3BF
+F3C0
+F3C1
+F3C2
+F3C3
+F3C4
+F3C5
+F3C6
+F3C7
+F3C8
+F3C9
+F3CA
+F3CB
+F3CC
+F3CD
+F3CE
+F3CF
+F3D0
+F3D1
+F3D2
+F3D3
+F3D4
+F3D5
+F3D6
+F3D7
+F3D8
+F3D9
+F3DA
+F3DB
+F3DC
+F3DD
+F3DE
+F3DF
+F3E0
+F3E1
+F3E2
+F3E3
+F3E4
+F3E5
+F3E6
+F3E7
+F3E8
+F3E9
+F3EA
+F3EB
+F3EC
+F3ED
+F3EE
+F3EF
+F3F0
+F3F1
+F3F2
+F3F3
+F3F4
+F3F5
+F3F6
+F3F7
+F3F8
+F3F9
+F3FA
+F3FB
+F3FC
+F440
+F441
+F442
+F443
+F444
+F445
+F446
+F447
+F448
+F449
+F44A
+F44B
+F44C
+F44D
+F44E
+F44F
+F450
+F451
+F452
+F453
+F454
+F455
+F456
+F457
+F458
+F459
+F45A
+F45B
+F45C
+F45D
+F45E
+F45F
+F460
+F461
+F462
+F463
+F464
+F465
+F466
+F467
+F468
+F469
+F46A
+F46B
+F46C
+F46D
+F46E
+F46F
+F470
+F471
+F472
+F473
+F474
+F475
+F476
+F477
+F478
+F479
+F47A
+F47B
+F47C
+F47D
+F47E
+F480
+F481
+F482
+F483
+F484
+F485
+F486
+F487
+F488
+F489
+F48A
+F48B
+F48C
+F48D
+F48E
+F48F
+F490
+F491
+F492
+F493
+F494
+F495
+F496
+F497
+F498
+F499
+F49A
+F49B
+F49C
+F49D
+F49E
+F49F
+F4A0
+F4A1
+F4A2
+F4A3
+F4A4
+F4A5
+F4A6
+F4A7
+F4A8
+F4A9
+F4AA
+F4AB
+F4AC
+F4AD
+F4AE
+F4AF
+F4B0
+F4B1
+F4B2
+F4B3
+F4B4
+F4B5
+F4B6
+F4B7
+F4B8
+F4B9
+F4BA
+F4BB
+F4BC
+F4BD
+F4BE
+F4BF
+F4C0
+F4C1
+F4C2
+F4C3
+F4C4
+F4C5
+F4C6
+F4C7
+F4C8
+F4C9
+F4CA
+F4CB
+F4CC
+F4CD
+F4CE
+F4CF
+F4D0
+F4D1
+F4D2
+F4D3
+F4D4
+F4D5
+F4D6
+F4D7
+F4D8
+F4D9
+F4DA
+F4DB
+F4DC
+F4DD
+F4DE
+F4DF
+F4E0
+F4E1
+F4E2
+F4E3
+F4E4
+F4E5
+F4E6
+F4E7
+F4E8
+F4E9
+F4EA
+F4EB
+F4EC
+F4ED
+F4EE
+F4EF
+F4F0
+F4F1
+F4F2
+F4F3
+F4F4
+F4F5
+F4F6
+F4F7
+F4F8
+F4F9
+F4FA
+F4FB
+F4FC
+F540
+F541
+F542
+F543
+F544
+F545
+F546
+F547
+F548
+F549
+F54A
+F54B
+F54C
+F54D
+F54E
+F54F
+F550
+F551
+F552
+F553
+F554
+F555
+F556
+F557
+F558
+F559
+F55A
+F55B
+F55C
+F55D
+F55E
+F55F
+F560
+F561
+F562
+F563
+F564
+F565
+F566
+F567
+F568
+F569
+F56A
+F56B
+F56C
+F56D
+F56E
+F56F
+F570
+F571
+F572
+F573
+F574
+F575
+F576
+F577
+F578
+F579
+F57A
+F57B
+F57C
+F57D
+F57E
+F580
+F581
+F582
+F583
+F584
+F585
+F586
+F587
+F588
+F589
+F58A
+F58B
+F58C
+F58D
+F58E
+F58F
+F590
+F591
+F592
+F593
+F594
+F595
+F596
+F597
+F598
+F599
+F59A
+F59B
+F59C
+F59D
+F59E
+F59F
+F5A0
+F5A1
+F5A2
+F5A3
+F5A4
+F5A5
+F5A6
+F5A7
+F5A8
+F5A9
+F5AA
+F5AB
+F5AC
+F5AD
+F5AE
+F5AF
+F5B0
+F5B1
+F5B2
+F5B3
+F5B4
+F5B5
+F5B6
+F5B7
+F5B8
+F5B9
+F5BA
+F5BB
+F5BC
+F5BD
+F5BE
+F5BF
+F5C0
+F5C1
+F5C2
+F5C3
+F5C4
+F5C5
+F5C6
+F5C7
+F5C8
+F5C9
+F5CA
+F5CB
+F5CC
+F5CD
+F5CE
+F5CF
+F5D0
+F5D1
+F5D2
+F5D3
+F5D4
+F5D5
+F5D6
+F5D7
+F5D8
+F5D9
+F5DA
+F5DB
+F5DC
+F5DD
+F5DE
+F5DF
+F5E0
+F5E1
+F5E2
+F5E3
+F5E4
+F5E5
+F5E6
+F5E7
+F5E8
+F5E9
+F5EA
+F5EB
+F5EC
+F5ED
+F5EE
+F5EF
+F5F0
+F5F1
+F5F2
+F5F3
+F5F4
+F5F5
+F5F6
+F5F7
+F5F8
+F5F9
+F5FA
+F5FB
+F5FC
+F640
+F641
+F642
+F643
+F644
+F645
+F646
+F647
+F648
+F649
+F64A
+F64B
+F64C
+F64D
+F64E
+F64F
+F650
+F651
+F652
+F653
+F654
+F655
+F656
+F657
+F658
+F659
+F65A
+F65B
+F65C
+F65D
+F65E
+F65F
+F660
+F661
+F662
+F663
+F664
+F665
+F666
+F667
+F668
+F669
+F66A
+F66B
+F66C
+F66D
+F66E
+F66F
+F670
+F671
+F672
+F673
+F674
+F675
+F676
+F677
+F678
+F679
+F67A
+F67B
+F67C
+F67D
+F67E
+F680
+F681
+F682
+F683
+F684
+F685
+F686
+F687
+F688
+F689
+F68A
+F68B
+F68C
+F68D
+F68E
+F68F
+F690
+F691
+F692
+F693
+F694
+F695
+F696
+F697
+F698
+F699
+F69A
+F69B
+F69C
+F69D
+F69E
+F69F
+F6A0
+F6A1
+F6A2
+F6A3
+F6A4
+F6A5
+F6A6
+F6A7
+F6A8
+F6A9
+F6AA
+F6AB
+F6AC
+F6AD
+F6AE
+F6AF
+F6B0
+F6B1
+F6B2
+F6B3
+F6B4
+F6B5
+F6B6
+F6B7
+F6B8
+F6B9
+F6BA
+F6BB
+F6BC
+F6BD
+F6BE
+F6BF
+F6C0
+F6C1
+F6C2
+F6C3
+F6C4
+F6C5
+F6C6
+F6C7
+F6C8
+F6C9
+F6CA
+F6CB
+F6CC
+F6CD
+F6CE
+F6CF
+F6D0
+F6D1
+F6D2
+F6D3
+F6D4
+F6D5
+F6D6
+F6D7
+F6D8
+F6D9
+F6DA
+F6DB
+F6DC
+F6DD
+F6DE
+F6DF
+F6E0
+F6E1
+F6E2
+F6E3
+F6E4
+F6E5
+F6E6
+F6E7
+F6E8
+F6E9
+F6EA
+F6EB
+F6EC
+F6ED
+F6EE
+F6EF
+F6F0
+F6F1
+F6F2
+F6F3
+F6F4
+F6F5
+F6F6
+F6F7
+F6F8
+F6F9
+F6FA
+F6FB
+F6FC
+F740
+F741
+F742
+F743
+F744
+F745
+F746
+F747
+F748
+F749
+F74A
+F74B
+F74C
+F74D
+F74E
+F74F
+F750
+F751
+F752
+F753
+F754
+F755
+F756
+F757
+F758
+F759
+F75A
+F75B
+F75C
+F75D
+F75E
+F75F
+F760
+F761
+F762
+F763
+F764
+F765
+F766
+F767
+F768
+F769
+F76A
+F76B
+F76C
+F76D
+F76E
+F76F
+F770
+F771
+F772
+F773
+F774
+F775
+F776
+F777
+F778
+F779
+F77A
+F77B
+F77C
+F77D
+F77E
+F780
+F781
+F782
+F783
+F784
+F785
+F786
+F787
+F788
+F789
+F78A
+F78B
+F78C
+F78D
+F78E
+F78F
+F790
+F791
+F792
+F793
+F794
+F795
+F796
+F797
+F798
+F799
+F79A
+F79B
+F79C
+F79D
+F79E
+F79F
+F7A0
+F7A1
+F7A2
+F7A3
+F7A4
+F7A5
+F7A6
+F7A7
+F7A8
+F7A9
+F7AA
+F7AB
+F7AC
+F7AD
+F7AE
+F7AF
+F7B0
+F7B1
+F7B2
+F7B3
+F7B4
+F7B5
+F7B6
+F7B7
+F7B8
+F7B9
+F7BA
+F7BB
+F7BC
+F7BD
+F7BE
+F7BF
+F7C0
+F7C1
+F7C2
+F7C3
+F7C4
+F7C5
+F7C6
+F7C7
+F7C8
+F7C9
+F7CA
+F7CB
+F7CC
+F7CD
+F7CE
+F7CF
+F7D0
+F7D1
+F7D2
+F7D3
+F7D4
+F7D5
+F7D6
+F7D7
+F7D8
+F7D9
+F7DA
+F7DB
+F7DC
+F7DD
+F7DE
+F7DF
+F7E0
+F7E1
+F7E2
+F7E3
+F7E4
+F7E5
+F7E6
+F7E7
+F7E8
+F7E9
+F7EA
+F7EB
+F7EC
+F7ED
+F7EE
+F7EF
+F7F0
+F7F1
+F7F2
+F7F3
+F7F4
+F7F5
+F7F6
+F7F7
+F7F8
+F7F9
+F7FA
+F7FB
+F7FC
+F840
+F841
+F842
+F843
+F844
+F845
+F846
+F847
+F848
+F849
+F84A
+F84B
+F84C
+F84D
+F84E
+F84F
+F850
+F851
+F852
+F853
+F854
+F855
+F856
+F857
+F858
+F859
+F85A
+F85B
+F85C
+F85D
+F85E
+F85F
+F860
+F861
+F862
+F863
+F864
+F865
+F866
+F867
+F868
+F869
+F86A
+F86B
+F86C
+F86D
+F86E
+F86F
+F870
+F871
+F872
+F873
+F874
+F875
+F876
+F877
+F878
+F879
+F87A
+F87B
+F87C
+F87D
+F87E
+F880
+F881
+F882
+F883
+F884
+F885
+F886
+F887
+F888
+F889
+F88A
+F88B
+F88C
+F88D
+F88E
+F88F
+F890
+F891
+F892
+F893
+F894
+F895
+F896
+F897
+F898
+F899
+F89A
+F89B
+F89C
+F89D
+F89E
+F89F
+F8A0
+F8A1
+F8A2
+F8A3
+F8A4
+F8A5
+F8A6
+F8A7
+F8A8
+F8A9
+F8AA
+F8AB
+F8AC
+F8AD
+F8AE
+F8AF
+F8B0
+F8B1
+F8B2
+F8B3
+F8B4
+F8B5
+F8B6
+F8B7
+F8B8
+F8B9
+F8BA
+F8BB
+F8BC
+F8BD
+F8BE
+F8BF
+F8C0
+F8C1
+F8C2
+F8C3
+F8C4
+F8C5
+F8C6
+F8C7
+F8C8
+F8C9
+F8CA
+F8CB
+F8CC
+F8CD
+F8CE
+F8CF
+F8D0
+F8D1
+F8D2
+F8D3
+F8D4
+F8D5
+F8D6
+F8D7
+F8D8
+F8D9
+F8DA
+F8DB
+F8DC
+F8DD
+F8DE
+F8DF
+F8E0
+F8E1
+F8E2
+F8E3
+F8E4
+F8E5
+F8E6
+F8E7
+F8E8
+F8E9
+F8EA
+F8EB
+F8EC
+F8ED
+F8EE
+F8EF
+F8F0
+F8F1
+F8F2
+F8F3
+F8F4
+F8F5
+F8F6
+F8F7
+F8F8
+F8F9
+F8FA
+F8FB
+F8FC
+F940
+F941
+F942
+F943
+F944
+F945
+F946
+F947
+F948
+F949
+F94A
+F94B
+F94C
+F94D
+F94E
+F94F
+F950
+F951
+F952
+F953
+F954
+F955
+F956
+F957
+F958
+F959
+F95A
+F95B
+F95C
+F95D
+F95E
+F95F
+F960
+F961
+F962
+F963
+F964
+F965
+F966
+F967
+F968
+F969
+F96A
+F96B
+F96C
+F96D
+F96E
+F96F
+F970
+F971
+F972
+F973
+F974
+F975
+F976
+F977
+F978
+F979
+F97A
+F97B
+F97C
+F97D
+F97E
+F980
+F981
+F982
+F983
+F984
+F985
+F986
+F987
+F988
+F989
+F98A
+F98B
+F98C
+F98D
+F98E
+F98F
+F990
+F991
+F992
+F993
+F994
+F995
+F996
+F997
+F998
+F999
+F99A
+F99B
+F99C
+F99D
+F99E
+F99F
+F9A0
+F9A1
+F9A2
+F9A3
+F9A4
+F9A5
+F9A6
+F9A7
+F9A8
+F9A9
+F9AA
+F9AB
+F9AC
+F9AD
+F9AE
+F9AF
+F9B0
+F9B1
+F9B2
+F9B3
+F9B4
+F9B5
+F9B6
+F9B7
+F9B8
+F9B9
+F9BA
+F9BB
+F9BC
+F9BD
+F9BE
+F9BF
+F9C0
+F9C1
+F9C2
+F9C3
+F9C4
+F9C5
+F9C6
+F9C7
+F9C8
+F9C9
+F9CA
+F9CB
+F9CC
+F9CD
+F9CE
+F9CF
+F9D0
+F9D1
+F9D2
+F9D3
+F9D4
+F9D5
+F9D6
+F9D7
+F9D8
+F9D9
+F9DA
+F9DB
+F9DC
+F9DD
+F9DE
+F9DF
+F9E0
+F9E1
+F9E2
+F9E3
+F9E4
+F9E5
+F9E6
+F9E7
+F9E8
+F9E9
+F9EA
+F9EB
+F9EC
+F9ED
+F9EE
+F9EF
+F9F0
+F9F1
+F9F2
+F9F3
+F9F4
+F9F5
+F9F6
+F9F7
+F9F8
+F9F9
+F9FA
+F9FB
+F9FC
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
+SET collation_connection='eucjpms_japanese_ci';
+create table t1 select repeat('a',4000) a;
+delete from t1;
+insert into t1 values ('a'), ('a '), ('a\t');
+select collation(a),hex(a) from t1 order by a;
+collation(a) hex(a)
+eucjpms_japanese_ci 6109
+eucjpms_japanese_ci 61
+eucjpms_japanese_ci 6120
+drop table t1;
+SET collation_connection='eucjpms_bin';
+create table t1 select repeat('a',4000) a;
+delete from t1;
+insert into t1 values ('a'), ('a '), ('a\t');
+select collation(a),hex(a) from t1 order by a;
+collation(a) hex(a)
+eucjpms_bin 6109
+eucjpms_bin 61
+eucjpms_bin 6120
+drop table t1;
diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result
index f57d8c191bf..43947edbd48 100644
--- a/mysql-test/r/ctype_latin1_de.result
+++ b/mysql-test/r/ctype_latin1_de.result
@@ -220,11 +220,11 @@ select * from t1 where match a against ("te*" in boolean mode)+0;
a
test
drop table t1;
-create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word));
+create table t1 (word varchar(255) not null, word2 varchar(255) not null default '', index(word));
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `word` varchar(255) collate latin1_german2_ci NOT NULL default '',
+ `word` varchar(255) collate latin1_german2_ci NOT NULL,
`word2` varchar(255) collate latin1_german2_ci NOT NULL default '',
KEY `word` (`word`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci
diff --git a/mysql-test/r/ctype_many.result b/mysql-test/r/ctype_many.result
index 8bfc6e98226..87b83acfe0f 100644
--- a/mysql-test/r/ctype_many.result
+++ b/mysql-test/r/ctype_many.result
@@ -2,44 +2,44 @@ DROP TABLE IF EXISTS t1;
SET CHARACTER SET latin1;
CREATE TABLE t1 (
comment CHAR(32) ASCII NOT NULL,
-koi8_ru_f CHAR(32) CHARACTER SET koi8r NOT NULL
+koi8_ru_f CHAR(32) CHARACTER SET koi8r NOT NULL default ''
) CHARSET=latin5;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `comment` char(32) character set latin1 NOT NULL default '',
+ `comment` char(32) character set latin1 NOT NULL,
`koi8_ru_f` char(32) character set koi8r NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin5
ALTER TABLE t1 CHANGE comment comment CHAR(32) CHARACTER SET latin2 NOT NULL;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `comment` char(32) character set latin2 NOT NULL default '',
+ `comment` char(32) character set latin2 NOT NULL,
`koi8_ru_f` char(32) character set koi8r NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin5
ALTER TABLE t1 ADD latin5_f CHAR(32) NOT NULL;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `comment` char(32) character set latin2 NOT NULL default '',
+ `comment` char(32) character set latin2 NOT NULL,
`koi8_ru_f` char(32) character set koi8r NOT NULL default '',
- `latin5_f` char(32) NOT NULL default ''
+ `latin5_f` char(32) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin5
ALTER TABLE t1 DEFAULT CHARSET=latin2;
ALTER TABLE t1 ADD latin2_f CHAR(32) NOT NULL;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `comment` char(32) NOT NULL default '',
+ `comment` char(32) NOT NULL,
`koi8_ru_f` char(32) character set koi8r NOT NULL default '',
- `latin5_f` char(32) character set latin5 NOT NULL default '',
- `latin2_f` char(32) NOT NULL default ''
+ `latin5_f` char(32) character set latin5 NOT NULL,
+ `latin2_f` char(32) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin2
ALTER TABLE t1 DROP latin2_f, DROP latin5_f;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `comment` char(32) NOT NULL default '',
+ `comment` char(32) NOT NULL,
`koi8_ru_f` char(32) character set koi8r NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin2
INSERT INTO t1 (koi8_ru_f,comment) VALUES ('a','LAT SMALL A');
@@ -219,7 +219,7 @@ z LAT CAPIT Z 2
Ñ CYR CAPIT E 2
ÑŽ CYR CAPIT YU 2
Ñ CYR CAPIT YA 2
-ALTER TABLE t1 ADD utf8_f CHAR(32) CHARACTER SET utf8 NOT NULL;
+ALTER TABLE t1 ADD utf8_f CHAR(32) CHARACTER SET utf8 NOT NULL default '';
UPDATE t1 SET utf8_f=CONVERT(koi8_ru_f USING utf8);
SET CHARACTER SET koi8r;
SELECT * FROM t1;
@@ -340,7 +340,7 @@ CYR CAPIT SOFT SIGN ø ø
CYR CAPIT E ü ü
CYR CAPIT YU à à
CYR CAPIT YA ñ ñ
-ALTER TABLE t1 ADD bin_f CHAR(32) BYTE NOT NULL;
+ALTER TABLE t1 ADD bin_f CHAR(32) BYTE NOT NULL default '';
UPDATE t1 SET bin_f=koi8_ru_f;
SELECT COUNT(DISTINCT bin_f),COUNT(DISTINCT koi8_ru_f),COUNT(DISTINCT utf8_f) FROM t1;
COUNT(DISTINCT bin_f) COUNT(DISTINCT koi8_ru_f) COUNT(DISTINCT utf8_f)
diff --git a/mysql-test/r/ctype_mb.result b/mysql-test/r/ctype_mb.result
index dbdb9c1343c..f6e14e1a78f 100644
--- a/mysql-test/r/ctype_mb.result
+++ b/mysql-test/r/ctype_mb.result
@@ -3,16 +3,16 @@ CREATE TABLE t1 SELECT _utf8'test' as c1, _utf8'теÑÑ‚' as c2;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `c1` char(4) character set utf8 NOT NULL default '',
- `c2` char(4) character set utf8 NOT NULL default ''
+ `c1` varchar(4) character set utf8 NOT NULL default '',
+ `c2` varchar(4) character set utf8 NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DELETE FROM t1;
ALTER TABLE t1 ADD c3 CHAR(4) CHARACTER SET utf8;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `c1` char(4) character set utf8 NOT NULL default '',
- `c2` char(4) character set utf8 NOT NULL default '',
+ `c1` varchar(4) character set utf8 NOT NULL default '',
+ `c2` varchar(4) character set utf8 NOT NULL default '',
`c3` char(4) character set utf8 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES ('aaaabbbbccccdddd','aaaabbbbccccdddd','aaaabbbbccccdddd');
diff --git a/mysql-test/r/ctype_recoding.result b/mysql-test/r/ctype_recoding.result
index 1c75988fd21..da0007fdfbe 100644
--- a/mysql-test/r/ctype_recoding.result
+++ b/mysql-test/r/ctype_recoding.result
@@ -50,11 +50,11 @@ Tables_in_test
SHOW CREATE TABLE ÔÁÂÌÉÃÁ;
Table Create Table
ÔÁÂÌÉÃÁ CREATE TABLE `ÔÁÂÌÉÃÁ` (
- `ÐÏÌÅ` char(32) character set koi8r NOT NULL default '' COMMENT 'ËÏÍÍÅÎÔÁÒÉÊ ÐÏÌÑ'
+ `ÐÏÌÅ` char(32) character set koi8r NOT NULL COMMENT 'ËÏÍÍÅÎÔÁÒÉÊ ÐÏÌÑ'
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='ËÏÍÍÅÎÔÁÒÉÊ ÔÁÂÌÉÃÙ'
SHOW FIELDS FROM ÔÁÂÌÉÃÁ;
Field Type Null Key Default Extra
-ÐÏÌÅ char(32)
+ÐÏÌÅ char(32) NO
SET CHARACTER SET cp1251;
SHOW TABLES;
Tables_in_test
@@ -62,11 +62,11 @@ Tables_in_test
SHOW CREATE TABLE òàáëèöà;
Table Create Table
òàáëèöà CREATE TABLE `òàáëèöà` (
- `ïîëå` char(32) character set koi8r NOT NULL default '' COMMENT 'êîììåíòàðèé ïîëÿ'
+ `ïîëå` char(32) character set koi8r NOT NULL COMMENT 'êîììåíòàðèé ïîëÿ'
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='êîììåíòàðèé òàáëèöû'
SHOW FIELDS FROM òàáëèöà;
Field Type Null Key Default Extra
-ïîëå char(32)
+ïîëå char(32) NO
SET CHARACTER SET utf8;
SHOW TABLES;
Tables_in_test
@@ -74,11 +74,11 @@ Tables_in_test
SHOW CREATE TABLE таблица;
Table Create Table
таблица CREATE TABLE `таблица` (
- `поле` char(32) character set koi8r NOT NULL default '' COMMENT 'комментарий полÑ'
+ `поле` char(32) character set koi8r NOT NULL COMMENT 'комментарий полÑ'
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='комментарий таблицы'
SHOW FIELDS FROM таблица;
Field Type Null Key Default Extra
-поле char(32)
+поле char(32) NO
SET CHARACTER SET koi8r;
DROP TABLE ÔÁÂÌÉÃÁ;
SET CHARACTER SET default;
diff --git a/mysql-test/r/ctype_tis620.result b/mysql-test/r/ctype_tis620.result
index 6d8bfe74c4b..5734f7cac86 100644
--- a/mysql-test/r/ctype_tis620.result
+++ b/mysql-test/r/ctype_tis620.result
@@ -259,8 +259,8 @@ WU
¡Ñ³°ªÒ
¡Ñ³°Ô¡Ò
¡Ñ³·ÔÁÒ
-¡Ñ¹µì
¡Ñ¹µÔ¡Ã
+¡Ñ¹µì
¡Ñ¹¸ÔªÒ
¡Ñ¹¸ÔÁÒ
¡Ñ¹ÂÒÃѵ¹ì
@@ -272,8 +272,8 @@ WU
¡Ò­¨¹ÇÃó
¡Ò­¨¹Ò
¡Ò¹´Ò
-¡Ò¹µì
¡Ò¹µìÃÇÕ
+¡Ò¹µì
¡ÒÂÊÔ·¸Ôì
¡ÒÃÇÔÍÃ
¡ÒÃسÕ
@@ -350,8 +350,8 @@ WU
à¡ÕÂõÔÈÑ¡´Ôì
à¡ÕÂõÔÊÇÑÊ´Ôì
à¡×éÍ¡ÙÅ
-á¡éÇ
á¡éÇã¨
+á¡éÇ
â¡Ážѹ¸ì
â¡àÁÈ
â¡ÅºÍÅ ¤Í¹à¹ç¤ªÑè¹Êì
@@ -368,8 +368,8 @@ WU
¢¨Ãà¡ÕÂõÔ
¢¨ÃÈÃÕ
¢¨ÃÈÑ¡´Ôì
-¢¹ÔÉ°ì
¢¹ÔÉ°Ò
+¢¹ÔÉ°ì
¢ÇÑ­ã¨
¢ÇÑ­ªÑÂ
¢ÇÑ­à´×͹
@@ -412,8 +412,8 @@ WU
ठÊËÒÂÍÔÁà»ê¡«ì
à¤.«Õ.¾Õ. áÁªªÕ¹à¹ÍÃÕè
षշÕÅÔÊ«Ôè§
-ह áÁ¡«ì (»ÃÐà·Èä·Â)
ह áÁç¡«ì (»ÃÐà·Èä·Â)
+ह áÁ¡«ì (»ÃÐà·Èä·Â)
à¤Ã×ÍÇÑÅÂì
᤹¹Ù ÍÔ¹àµÍÃìà·Ã´
á¤Ð¨éÍÂ
@@ -494,12 +494,12 @@ WU
¨ÓàÃÔ­
¨ÓÅͧ
¨Ô³³ì
-¨Ôµµì
¨Ôµµì¹ÔÉÒ
¨ÔµµÁÒÊ
¨ÔµµÒ
¨ÔµµÔ
¨ÔµµÔ¹¹Ñ¹·ì
+¨Ôµµì
¨ÔµÃÅ´Ò
¨ÔµÃÒ
¨ÔµÃÒÀóì
@@ -627,10 +627,10 @@ WU
ªÇ¹¾ÔÈ
ªÇÅÔµ
ªÇÔÈÒ
-ªèÍ
ªèͩѵÃ
ªèÍ·Ô¾Âì
ªèÍÍÑ­ªÑ­
+ªèÍ
ªÐ¹ÔÅ
ªÐÍé͹
ªÑªªÑÂ
@@ -758,12 +758,12 @@ WU
³¸ÔµÒ
³ÀÑ·Ã
³Àѷáóì
-³Ã§¤ì
³Ã§¤ìªÑÂ
³Ã§¤ì¾ÑªÃì
³Ã§¤ìÄ·¸Ôì
³Ã§¤ìÇÔ·Âì
³Ã§¤ìÈÑ¡´Ôì
+³Ã§¤ì
³Ã§ÃÑ¡Éì
³Ã§Ä·¸Ôì
³Ã§ÈÑ¡´Ôì
@@ -862,11 +862,11 @@ WU
µÐÇѹ
µÑ觨Ñè§ËÅÍ´ä¿
µÒà¿ç´
-µØê
µØ꡵Ò
µØéÁ
µØëÂ
µØÅÒÅѡɳì
+µØê
àµçÁà´ª
àµ×͹ã¨
àµ×͹µÒ
@@ -917,8 +917,8 @@ WU
·Ñº·ÔÁ
·ÑȹÇÃó
·ÑȹվÃ
-·ÑȹÕÂì
·ÑȹÕÂÒ
+·ÑȹÕÂì
·ÑÈÇÃó
·èÒ·ÃÒÂá¨é§ÇѲ¹Ò
·Ô¦ÑÁ¾Ã
@@ -1088,8 +1088,8 @@ WU
¹Ã¾Å
¹ÃÀÑ·Ãì
¹ÃÒ
-¹ÃÔ¹·Ãì
¹ÃÔ¹·Ãìà´ª
+¹ÃÔ¹·Ãì
¹ÃÔÈ
¹ÃÔÉ°
¹ÃÕ
@@ -1115,8 +1115,8 @@ WU
¹Ñ·¸Á¹
¹Ñ¹ªÑÂ
¹Ñ¹·ªÑÂ
-¹Ñ¹·¹ì
¹Ñ¹·¹Ò
+¹Ñ¹·¹ì
¹Ñ¹·¾Ã
¹Ñ¹·¾Å
¹Ñ¹·ÁÒÊ
@@ -1148,14 +1148,14 @@ WU
¹Ôà«Ð
¹Ô´
¹Ô´Ò
-¹ÔµÂì
¹ÔµÂÒ
+¹ÔµÂì
¹ÔµÔ
¹ÔµÔ¾§Éì
¹ÔµÔÁÒ
¹Ô·ÃÒ
-¹Ô·Ñȹì
¹Ô·ÑȹÕÂì
+¹Ô·Ñȹì
¹Ô¸ÔÇ´Õ
¹Ô»»Í¹à¾¹µì(»ÃÐà·Èä·Â)
¹Ô¾¹¸ì
@@ -1349,8 +1349,8 @@ WU
»ÃÒ³ÕÂì
»ÃÒâÁ·Âì
»ÃÒö¹Ò
-»ÃÔ­­ì
»ÃÔ­­Ò
+»ÃÔ­­ì
»ÃÔ­´Ò
»ÃÔ³´Ò
»ÃÔ·ÑÈ
@@ -1454,10 +1454,10 @@ WU
¾§ÉìÈÑ¡´Ôì
¾§ÉìÊѹµì
¾§Éì͹ѹµì
-¾¨¹ì
¾¨¹Ò
¾¨¹Òö
¾¨¹ÕÂì
+¾¨¹ì
¾¨ÁÒ¹
¾¨ÁÒÅÂì
¾¹Á
@@ -1504,8 +1504,8 @@ WU
¾ÃÊÇÃäì
¾ÃËÁ¾Ñ²¹ì
¾ÃéÍÁªÑÂ
-¾ÃлÃÐá´§ Î͹´éÒ¤ÒÃìÊì
¾ÃлÃÐá´§ Î͹´éÒ¤ÒÃìÊì ¨Ó¡Ñ´
+¾ÃлÃÐá´§ Î͹´éÒ¤ÒÃìÊì
¾ÃÐÃÒÁ 3 ¤ÒÃìà«ç¹àµÍÃì
¾ÃÐÃÒÁ 3 Î͹´éÒ¤ÒÃìÊì
¾ÃÔéÁà¾ÃÒ
@@ -1604,10 +1604,10 @@ WU
¾Ùŷͧ¾Ãç;à¾ÍÃìµÕé_
¾ÙżÅ
à¾ç§ ¿Ù ËÅÔ¹
-à¾çªÃì
ྪÃÃѵ¹ì
ྪÃÅ´Ò
ྪÃÔ¹·Ãì
+à¾çªÃì
à¾ç­¨Ñ¹·Ãì
à¾ç­·Ô¾Âì
à¾ç­¹ÀÒ
@@ -1831,7 +1831,6 @@ WU
ÃÒàÁÈÃì
ÃÒÂÕ¹
Ã×è¹ÇÃÒËì
-ÃØé§
ÃØ觷ԾÂì
ÃØ觷ÔÇÒ
ÃØ觹ÀÒ
@@ -1840,11 +1839,12 @@ WU
ÃØè§Ãѵ¹ì
ÃØè§ÃÑÈÁÕ
ÃØè§àÃ×ͧ
-ÃØè§âè¹ì
ÃØè§âè¹ì¢¹Êè§
+ÃØè§âè¹ì
ÃØé§ÅÒÇÃó
ÃØè§ÇÔ·Âì
ÃØè§ÍÃس
+ÃØé§
ÃبÒ
ÃبÒÀÒ
ÃØËйÒ
@@ -1861,8 +1861,8 @@ WU
áþᾤ ¤Í¹ÊµÃѤªÑè¹
âç§Ò¹àËÅç¡¡Ãا෾Ï
âè¹ì»ÃÐàÊÃÔ°
-Ä·¸Ôì
Ä·¸ÔªÑÂ
+Ä·¸Ôì
ÅÅÔ´Ò
ÅÅÔµÒ
ÅÐÁèÍÁ
@@ -2050,8 +2050,8 @@ WU
ÇÔäÅÇÃó
ÇÔÇ
ÇÔÇÃø¹ì
-ÇÔÇѲ¹ì
ÇÔÇѲ¹ìªÑÂ
+ÇÔÇѲ¹ì
ÇÔȹÕ
ÇÔÈÃص
ÇÔÈÒÅ
@@ -2146,11 +2146,11 @@ WU
ÈÈÔÇÔÁÅ
ÈÈÔÉÒ
ÈÑ¡´Ò
-ÈÑ¡´Ôì
ÈÑ¡´ÔìªÑÂ
ÈÑ¡´ÔìàªÇ§
ÈÑ¡´Ôì´Ò
ÈÑ¡´ÔìÇÔºÙÅÂì
+ÈÑ¡´Ôì
ÈÑ¡ÃÔ¹·Ãì
ÈѹʹÕÂì
ÈÒ¹µÔᏴì
@@ -2348,18 +2348,18 @@ WU
ÊÓÃÒ­
ÊÓÄ·¸Ôì
ÊÓÅÕ
-ÊÔ§Ëì
ÊÔ§Ëì¾Å
ÊÔ§ËÒ
+ÊÔ§Ëì
ÊԵҹѹ
ÊÔµÒ¾Ã
ÊÔ·¸Ò
-ÊÔ·¸Ôì
ÊÔ·¸ÔªÑÂ
ÊÔ·¸Ôà´ª
ÊÔ·¸Ô¾Ã
ÊÔ·¸Ô¾Ãó
ÊÔ·¸Ô¾Å
+ÊÔ·¸Ôì
ÊÔ¹·ÇÕ
ÊÔÃÔªÑÂ
ÊÔÃÔà´ª
@@ -2393,15 +2393,15 @@ WU
ÊØ¢ÊÇÑÊ´Ôì¡Å¡ÒÃ
ÊØ¢Êѹµì
ÊØ¢ØÁ
-Êؤ¹¸ì
Êؤ¹¸Ò
+Êؤ¹¸ì
ÊبÒÃÕ
ÊبԵ
ÊبԵµÒ
ÊبԵÃÒ
ÊبԹ´Ò
-ÊبԹµì
ÊبԹµ¹ì
+ÊبԹµì
ÊتÅ
ÊتÑÂ
ÊتҴÒ
@@ -2443,13 +2443,13 @@ WU
ÊظԴÒ
ÊظÔÈÑ¡´Ôì
ÊظÕ
-ÊظÕÃì
ÊظÕÃÒ
+ÊظÕÃì
Êع·Ã
Êع·ÃÕ
Êعѷ·Õ
-Êعѹ·ì
Êعѹ·Ò
+Êعѹ·ì
ÊعԵÒ
ÊعÔÈÒ
ÊعÔÉÒ
@@ -2511,10 +2511,10 @@ WU
ÊØÃÈÑ¡´Ôì
ÊØÃÊÔ·¸Ôì
ÊØÃѪ¹Õ¡Ã
-ÊØÃѵ¹ì
ÊØÃѵ¹Ç´Õ
ÊØÃѵ¹ìÇ´Õ
ÊØÃѵ¹Ò
+ÊØÃѵ¹ì
ÊØÃѵÂÒ
ÊØÃÒ§¤¹Ò
ÊØÃÔªÑÂ
@@ -2529,8 +2529,8 @@ WU
ÊØÃÕ¸Ò¾Ã
ÊØÃÕ¾Ã
ÊØÃÕÁÒÈ
-ÊØÃÕÂì
ÊØÃÕÂì¾Ã
+ÊØÃÕÂì
ÊØÃÕÃѵ¹ì
ÊØÅÑ´´Ò
ÊØÇÀÑ·Ãì
@@ -2540,9 +2540,9 @@ WU
ÊØÇÃóÕ
ÊØÇÃóÕÂì
ÊØÇÃѵ¹ì
-ÊØÇѲ¹ì
ÊØÇѲ¹ìªÑÂ
ÊØÇѲ¹Ò
+ÊØÇѲ¹ì
ÊØÇѵªÑÂ
ÊØÇÒÃÕ
ÊØÇÔªÑÂ
@@ -2623,8 +2623,8 @@ WU
͹¹·ì
͹ÇѪ
͹ѭ­Ò
-͹ѹµì
͹ѹµÈÑ¡´Ôì
+͹ѹµì
͹ءԵÔ
͹ءÙÅ
͹تÒ
@@ -2770,8 +2770,8 @@ WU
ÍÒÃÒ¾Ã
ÍÒÃÔÂÒ
ÍÒÃÕ
-ÍÒÃÕÂì
ÍÒÃÕÂì àÊÁÒ©ÔÁ (ä·Âູ¡Ñ¹
+ÍÒÃÕÂì
ÍÒÃÕÃѵ¹ì
ÍÒÃÕÇÃó
ÍÓ¹ÇÂ
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 3face9b1ba6..b251044d48b 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -23,16 +23,24 @@ select binary 'a a' > 'a', binary 'a \0' > 'a', binary 'a\0' > 'a';
binary 'a a' > 'a' binary 'a \0' > 'a' binary 'a\0' > 'a'
1 1 1
SET CHARACTER SET koi8r;
-CREATE TABLE t1 (word VARCHAR(64) CHARACTER SET ucs2);
-INSERT INTO t1 VALUES (_koi8r'ò'), (X'2004');
+CREATE TABLE t1 (word VARCHAR(64) CHARACTER SET ucs2, word2 CHAR(64) CHARACTER SET ucs2);
+INSERT INTO t1 VALUES (_koi8r'ò',_koi8r'ò'), (X'2004',X'2004');
SELECT hex(word) FROM t1 ORDER BY word;
hex(word)
0420
2004
+SELECT hex(word2) FROM t1 ORDER BY word2;
+hex(word2)
+0420
+2004
DELETE FROM t1;
-INSERT INTO t1 VALUES (X'042000200020'), (X'200400200020');
+INSERT INTO t1 VALUES (X'042000200020',X'042000200020'), (X'200400200020', X'200400200020');
SELECT hex(word) FROM t1 ORDER BY word;
hex(word)
+042000200020
+200400200020
+SELECT hex(word2) FROM t1 ORDER BY word2;
+hex(word2)
0420
2004
DROP TABLE t1;
@@ -66,8 +74,8 @@ RPAD(_ucs2 X'0420',10,_ucs2 X'0421') r;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `l` char(10) character set ucs2 NOT NULL default '',
- `r` char(10) character set ucs2 NOT NULL default ''
+ `l` varchar(10) character set ucs2 NOT NULL default '',
+ `r` varchar(10) character set ucs2 NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
create table t2(f1 Char(30));
@@ -85,10 +93,10 @@ create table t1 (a varchar(10) character set ucs2, key(a));
insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test");
explain select * from t1 where a like 'abc%';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range a a 21 NULL 1 Using where; Using index
+1 SIMPLE t1 range a a 23 NULL 1 Using where; Using index
explain select * from t1 where a like concat('abc','%');
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range a a 21 NULL 1 Using where; Using index
+1 SIMPLE t1 range a a 23 NULL 1 Using where; Using index
select * from t1 where a like "abc%";
a
abc
@@ -313,7 +321,7 @@ aardvark 0
aardvarz 0
EXPLAIN SELECT word FROM t1 ORDER BY word;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL PRIMARY 128 NULL 6 Using index
+1 SIMPLE t1 index NULL PRIMARY 130 NULL 6 Using index
SELECT word FROM t1 ORDER by word;
word
a
@@ -337,7 +345,7 @@ INSERT INTO t1 (word) VALUES ("aardvara");
INSERT INTO t1 (word) VALUES ("aardvarz");
EXPLAIN SELECT * FROM t1 ORDER BY WORD;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL PRIMARY 128 NULL 6 Using index
+1 SIMPLE t1 index NULL PRIMARY 130 NULL 6 Using index
SELECT * FROM t1 ORDER BY word;
word
a
@@ -609,6 +617,14 @@ DROP TABLE t1;
CREATE TABLE t1 (Field1 int(10) unsigned default '0');
INSERT INTO t1 VALUES ('-1');
Warnings:
-Warning 1265 Data truncated for column 'Field1' at row 1
+Warning 1264 Out of range value adjusted for column 'Field1' at row 1
DROP TABLE t1;
SET NAMES latin1;
+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;
+SELECT * FROM t1;
+a b
+1.1 1.100
+2.1 2.100
+DROP TABLE t1;
diff --git a/mysql-test/r/ctype_ucs_binlog.result b/mysql-test/r/ctype_ucs_binlog.result
index 29718fa32a1..4267e495959 100644
--- a/mysql-test/r/ctype_ucs_binlog.result
+++ b/mysql-test/r/ctype_ucs_binlog.result
@@ -3,13 +3,20 @@ create table t2 (c char(30)) charset=ucs2;
set @v=convert('abc' using ucs2);
reset master;
insert into t2 values (@v);
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 User var 1 79 @`v`=_ucs2 0x006100620063 COLLATE ucs2_general_ci
-master-bin.000001 119 Query 1 119 use `test`; insert into t2 values (@v)
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 User var 1 138 @`v`=_ucs2 0x006100620063 COLLATE ucs2_general_ci
+master-bin.000001 138 Query 1 227 use `test`; insert into t2 values (@v)
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET @`v`:=_ucs2 0x006100620063 COLLATE `ucs2_general_ci`;
use test;
SET TIMESTAMP=10000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t2 values (@v);
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
drop table t2;
diff --git a/mysql-test/r/ctype_ujis.result b/mysql-test/r/ctype_ujis.result
index fd6c501499b..a00e68b596e 100644
--- a/mysql-test/r/ctype_ujis.result
+++ b/mysql-test/r/ctype_ujis.result
@@ -123,7 +123,7 @@ t1 CREATE TABLE `t1` (
) ENGINE=MyISAM DEFAULT CHARSET=ujis
SHOW COLUMNS FROM t1;
Field Type Null Key Default Extra
-a char(1)
+a char(1) NO
b enum('¤¢','¤¤') YES NULL
DROP TABLE t1;
CREATE TABLE t1
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 78c56bffbd3..490cde82ca3 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -124,7 +124,7 @@ create table t1 select date_format("2004-01-19 10:10:10", "%Y-%m-%d");
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `date_format("2004-01-19 10:10:10", "%Y-%m-%d")` binary(10) default NULL
+ `date_format("2004-01-19 10:10:10", "%Y-%m-%d")` varbinary(10) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t1;
date_format("2004-01-19 10:10:10", "%Y-%m-%d")
@@ -285,7 +285,7 @@ create table t2 select ifnull(a,a) from t1;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `ifnull(a,a)` char(5) character set utf8 default NULL
+ `ifnull(a,a)` varchar(5) character set utf8 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t2;
ifnull(a,a)
@@ -412,8 +412,8 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c` char(10) character set utf8 default NULL,
- UNIQUE KEY `a` TYPE HASH (`c`(1))
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ UNIQUE KEY `a` USING HASH (`c`(1))
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f');
insert into t1 values ('aa');
ERROR 23000: Duplicate entry 'aa' for key 1
@@ -448,8 +448,8 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c` char(10) character set utf8 default NULL,
- UNIQUE KEY `a` TYPE BTREE (`c`(1))
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ UNIQUE KEY `a` USING BTREE (`c`(1))
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f');
insert into t1 values ('aa');
ERROR 23000: Duplicate entry 'aa' for key 1
@@ -570,8 +570,8 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c` char(10) character set utf8 collate utf8_bin default NULL,
- UNIQUE KEY `a` TYPE HASH (`c`(1))
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ UNIQUE KEY `a` USING HASH (`c`(1))
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f');
insert into t1 values ('aa');
ERROR 23000: Duplicate entry 'aa' for key 1
@@ -606,8 +606,8 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c` char(10) character set utf8 collate utf8_bin default NULL,
- UNIQUE KEY `a` TYPE BTREE (`c`(1))
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ UNIQUE KEY `a` USING BTREE (`c`(1))
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
insert into t1 values ('a'),('b'),('c'),('d'),('e'),('f');
insert into t1 values ('aa');
ERROR 23000: Duplicate entry 'aa' for key 1
@@ -809,8 +809,8 @@ create table t2 select concat(a,_utf8'') as a, concat(b,_utf8'')as b from t1;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `a` char(5) character set utf8 NOT NULL default '',
- `b` char(15) character set utf8 NOT NULL default ''
+ `a` varchar(5) character set utf8 NOT NULL default '',
+ `b` varchar(15) character set utf8 NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t2;
drop table t1;
diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result
index 2db014c4a52..8217a0e7ba6 100644
--- a/mysql-test/r/date_formats.result
+++ b/mysql-test/r/date_formats.result
@@ -79,6 +79,11 @@ concat('%d-%m-%Y',' ','%H:%i:%s.%f'));
str_to_date(concat('15-01-2001',' 2:59:58.999'),
concat('%d-%m-%Y',' ','%H:%i:%s.%f'))
2001-01-15 02:59:58.999000
+select STR_TO_DATE('2004.12.12 22.30.61','%Y.%m.%d %T');
+STR_TO_DATE('2004.12.12 22.30.61','%Y.%m.%d %T')
+NULL
+Warnings:
+Error 1411 Incorrect time value: '22.30.61' for function str_to_time
create table t1 (date char(30), format char(30) not null);
insert into t1 values
('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'),
@@ -335,6 +340,22 @@ Tuesday 52 2001 %W %V %Y NULL
Tuesday 52 2001 %W %u %x NULL
7 53 1998 %w %u %Y NULL
NULL %m.%d.%Y NULL
+Warnings:
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_time
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12.123456' for function str_to_time
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AM' for function str_to_time
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AN' for function str_to_time
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_time
+Error 1411 Incorrect datetime value: '10:20:10AM' for function str_to_time
+Error 1411 Incorrect datetime value: '15 Septembei 2001' for function str_to_time
+Error 1411 Incorrect datetime value: '15 Ju 2001' for function str_to_time
+Error 1411 Incorrect datetime value: 'Sund 15 MA' for function str_to_time
+Error 1411 Incorrect datetime value: 'Thursdai 12 1998' for function str_to_time
+Error 1411 Incorrect datetime value: 'Sunday 01 2001' for function str_to_time
+Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_time
+Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_time
+Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_time
+Error 1411 Incorrect datetime value: '7 53 1998' for function str_to_time
select date,format,concat(str_to_date(date, format),'') as con from t1;
date format con
2003-01-02 10:11:12 PM %Y-%m-%d %H:%i:%S %p NULL
@@ -353,6 +374,22 @@ Tuesday 52 2001 %W %V %Y NULL
Tuesday 52 2001 %W %u %x NULL
7 53 1998 %w %u %Y NULL
NULL %m.%d.%Y NULL
+Warnings:
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_time
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12.123456' for function str_to_time
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AM' for function str_to_time
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12AN' for function str_to_time
+Error 1411 Incorrect datetime value: '2003-01-02 10:11:12 PM' for function str_to_time
+Error 1411 Incorrect datetime value: '10:20:10AM' for function str_to_time
+Error 1411 Incorrect datetime value: '15 Septembei 2001' for function str_to_time
+Error 1411 Incorrect datetime value: '15 Ju 2001' for function str_to_time
+Error 1411 Incorrect datetime value: 'Sund 15 MA' for function str_to_time
+Error 1411 Incorrect datetime value: 'Thursdai 12 1998' for function str_to_time
+Error 1411 Incorrect datetime value: 'Sunday 01 2001' for function str_to_time
+Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_time
+Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_time
+Error 1411 Incorrect datetime value: 'Tuesday 52 2001' for function str_to_time
+Error 1411 Incorrect datetime value: '7 53 1998' for function str_to_time
truncate table t1;
insert into t1 values
('10:20:10AM', '%h:%i:%s'),
@@ -391,6 +428,8 @@ NULL
select str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA'));
str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA'))
NULL
+Warnings:
+Error 1411 Incorrect datetime value: '15-01-2001 12:59:59' for function str_to_time
explain extended select makedate(1997,1), addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM"),cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME), maketime(23,11,12),microsecond("1997-12-31 23:59:59.000001");
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/delayed.result b/mysql-test/r/delayed.result
index ceb511a7891..e9766622cf6 100644
--- a/mysql-test/r/delayed.result
+++ b/mysql-test/r/delayed.result
@@ -22,6 +22,9 @@ insert delayed into t1 values (null,"c");
insert delayed into t1 values (3,"d"),(null,"e");
insert delayed into t1 values (3,"this will give an","error");
ERROR 21S01: Column count doesn't match value count at row 1
+show status like 'not_flushed_delayed_rows';
+Variable_name Value
+Not_flushed_delayed_rows 0
select * from t1;
a b
1 b
diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result
index b4d9a921178..fd6a834c694 100644
--- a/mysql-test/r/derived.result
+++ b/mysql-test/r/derived.result
@@ -318,11 +318,11 @@ create table t2 (a int, b int, primary key (a));
insert into t2 values (1,7),(2,7);
explain select a from t2 where a>1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 2 Using where; Using index
+1 SIMPLE t2 index PRIMARY PRIMARY 4 NULL 2 Using where; Using index
explain select a from (select a from t2 where a>1) tt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 1
-2 DERIVED t2 range PRIMARY PRIMARY 4 NULL 2 Using where; Using index
+2 DERIVED t2 index PRIMARY PRIMARY 4 NULL 2 Using where; Using index
drop table t2;
CREATE TABLE `t1` ( `itemid` int(11) NOT NULL default '0', `grpid` varchar(15) NOT NULL default '', `vendor` int(11) NOT NULL default '0', `date_` date NOT NULL default '0000-00-00', `price` decimal(12,2) NOT NULL default '0.00', PRIMARY KEY (`itemid`,`grpid`,`vendor`,`date_`), KEY `itemid` (`itemid`,`vendor`), KEY `itemid_2` (`itemid`,`date_`));
insert into t1 values (128, 'rozn', 2, now(), 10),(128, 'rozn', 1, now(), 10);
@@ -339,6 +339,11 @@ select distinct sum(b) from (select a,b from t1) y group by a;
sum(b)
4
drop table t1;
+CREATE TABLE t1 (a char(10), b char(10));
+INSERT INTO t1 VALUES ('root','localhost'), ('root','%');
+SELECT * FROM (SELECT (SELECT a.a FROM t1 AS a WHERE a.a = b.a) FROM t1 AS b) AS c;
+ERROR 21000: Subquery returns more than 1 row
+DROP TABLE t1;
create table t1(a int);
create table t2(a int);
create table t3(a int);
diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result
index f4bc4263c4d..177994b488d 100644
--- a/mysql-test/r/distinct.result
+++ b/mysql-test/r/distinct.result
@@ -212,7 +212,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index
explain SELECT distinct a from t3 order by a desc limit 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t3 index NULL a 5 NULL 204 Using index
+1 SIMPLE t3 index NULL a 5 NULL 10 Using index
explain SELECT distinct a,b from t3 order by a+1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort
@@ -388,8 +388,8 @@ SELECT DISTINCTROW email, shipcode FROM t1, t2 WHERE t1.infoID=t2.infoID;
email shipcode
test1@testdomain.com Z001
test2@testdomain.com Z001
-test3@testdomain.com Z001
test2@testdomain.com R002
+test3@testdomain.com Z001
SELECT DISTINCTROW email FROM t1 ORDER BY dateentered DESC;
email
test1@testdomain.com
@@ -457,10 +457,10 @@ drop table t1,t2;
CREATE TABLE t1 (
html varchar(5) default NULL,
rin int(11) default '0',
-out int(11) default '0'
+rout int(11) default '0'
) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('1',1,0);
-SELECT DISTINCT html,SUM(out)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin;
+SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin;
html prod
-1 0.00
+1 0.00000
drop table t1;
diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result
index b07cf16aa64..979e5d48871 100644
--- a/mysql-test/r/drop.result
+++ b/mysql-test/r/drop.result
@@ -46,6 +46,7 @@ unlock tables;
create database mysqltest;
show databases;
Database
+information_schema
mysql
mysqltest
test
@@ -56,6 +57,7 @@ unlock tables;
drop database mysqltest;
show databases;
Database
+information_schema
mysql
test
drop database mysqltest;
diff --git a/mysql-test/r/drop_temp_table.result b/mysql-test/r/drop_temp_table.result
index 5f1f142cde5..26b8511661a 100644
--- a/mysql-test/r/drop_temp_table.result
+++ b/mysql-test/r/drop_temp_table.result
@@ -11,12 +11,11 @@ select get_lock("a",10);
get_lock("a",10)
1
show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 # Start 1 # Server ver: VERSION, Binlog ver: 3
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4
master-bin.000001 # Query 1 # create database `drop-temp+table-test`
master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn1 (a int)
master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table `table:name` (a int)
master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn2 (a int)
master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn2`,`drop-temp+table-test`.`table:name`,`drop-temp+table-test`.`shortn1`
-master-bin.000001 # Query 1 # use `drop-temp+table-test`; DO RELEASE_LOCK("a")
drop database `drop-temp+table-test`;
diff --git a/mysql-test/r/endspace.result b/mysql-test/r/endspace.result
index 96210a0e16d..0e68418a80f 100644
--- a/mysql-test/r/endspace.result
+++ b/mysql-test/r/endspace.result
@@ -43,7 +43,7 @@ teststring
teststring
explain select * from t1 order by text1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL key1 32 NULL 3 Using index
+1 SIMPLE t1 index NULL key1 34 NULL 3 Using index
alter table t1 modify text1 char(32) binary not null;
check table t1;
Table Op Msg_type Msg_text
@@ -99,15 +99,15 @@ concat('|', text1, '|')
explain select concat('|', text1, '|') from t1 where text1='teststring ';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range key1 key1 22 NULL 2 Using where
-select * from t1 where text1 like 'teststring_%';
-text1
-teststring
-teststring
-select * from t1 where text1='teststring' or text1 like 'teststring_%';
-text1
-teststring
-teststring
-teststring
+select concat('|', text1, '|') from t1 where text1 like 'teststring_%';
+concat('|', text1, '|')
+|teststring |
+|teststring |
+select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%';
+concat('|', text1, '|')
+|teststring |
+|teststring|
+|teststring |
select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t';
concat('|', text1, '|')
|teststring|
@@ -121,14 +121,14 @@ concat('|', text1, '|')
drop table t1;
create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)) pack_keys=0;
insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
-select * from t1 where text1='teststring' or text1 like 'teststring_%';
-text1
-teststring
-teststring
-select * from t1 where text1='teststring' or text1 >= 'teststring\t';
-text1
-teststring
-teststring
+select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%';
+concat('|', text1, '|')
+|teststring |
+|teststring|
+select concat('|', text1, '|') from t1 where text1='teststring' or text1 >= 'teststring\t';
+concat('|', text1, '|')
+|teststring |
+|teststring|
drop table t1;
create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap;
insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
@@ -151,7 +151,7 @@ teststring
teststring
explain select * from t1 order by text1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL key1 32 NULL 3
+1 SIMPLE t1 index NULL key1 34 NULL 3
alter table t1 modify text1 char(32) binary not null;
select * from t1 order by text1;
text1
@@ -178,7 +178,7 @@ teststring
teststring
explain select * from t1 order by text1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL key1 32 NULL 3 Using index
+1 SIMPLE t1 index NULL key1 34 NULL 3 Using index
alter table t1 modify text1 char(32) binary not null;
select * from t1 order by text1;
text1
@@ -200,13 +200,13 @@ teststring
teststring
select text1, length(text1) from t1 where text1='teststring' or text1 like 'teststring_%';
text1 length(text1)
-teststring 10
teststring 11
+teststring 10
teststring 11
select text1, length(text1) from t1 where text1='teststring' or text1 >= 'teststring\t';
text1 length(text1)
-teststring 10
teststring 11
+teststring 10
teststring 11
select concat('|', text1, '|') from t1 order by text1;
concat('|', text1, '|')
diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result
new file mode 100644
index 00000000000..6c815e94b7c
--- /dev/null
+++ b/mysql-test/r/federated.result
@@ -0,0 +1,922 @@
+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;
+DROP DATABASE IF EXISTS federated;
+CREATE DATABASE federated;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+DEFAULT CHARSET=latin1;
+DROP DATABASE IF EXISTS federated;
+CREATE DATABASE federated;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:@/too/many/items/federated/t1';
+ERROR HY000: Can't create table 'connection string is not in the correct format' (errno: 0)
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1';
+ERROR HY000: Can't create table 'connection string is not in the correct format' (errno: 0)
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t3';
+ERROR HY000: Error running query on master: foreign table 't3' does not exist!
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://user:pass@127.0.0.1:SLAVE_PORT/federated/t1';
+ERROR 08S01: Error connecting to master: unable to connect to database 'federated' on host '127.0.0.1 as user 'user' !
+DROP TABLE IF EXISTS federated.t1;
+Warnings:
+Note 1051 Unknown table 't1'
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (id, name) VALUES (1, 'foo');
+INSERT INTO federated.t1 (id, name) VALUES (2, 'fee');
+SELECT * FROM federated.t1;
+id name
+1 foo
+2 fee
+DELETE FROM federated.t1;
+DROP TABLE federated.t1;
+DROP TABLE IF EXISTS federated.t2;
+Warnings:
+Note 1051 Unknown table 't2'
+CREATE TABLE federated.t2 (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t2 (id, name) VALUES (1, 'foo');
+INSERT INTO federated.t2 (id, name) VALUES (2, 'fee');
+SELECT * FROM federated.t2;
+id name
+1 foo
+2 fee
+DROP TABLE federated.t2;
+DROP TABLE IF EXISTS federated.t1;
+DROP TABLE IF EXISTS federated.`t1%`;
+Warnings:
+Note 1051 Unknown table 't1%'
+CREATE TABLE federated.`t1%` (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+Warnings:
+Note 1051 Unknown table 't1'
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1%';
+INSERT INTO federated.t1 (id, name) VALUES (1, 'foo');
+INSERT INTO federated.t1 (id, name) VALUES (2, 'fee');
+SELECT * FROM federated.t1;
+id name
+1 foo
+2 fee
+DELETE FROM federated.t1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.`t1%` (
+`id` int(20) NOT NULL,
+`name` varchar(32) NOT NULL default ''
+ )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1%';
+INSERT INTO federated.`t1%` (id, name) VALUES (1, 'foo');
+INSERT INTO federated.`t1%` (id, name) VALUES (2, 'fee');
+SELECT * FROM federated.`t1%`;
+id name
+1 foo
+2 fee
+DELETE FROM federated.`t1%`;
+DROP TABLE IF EXISTS federated.`t1%`;
+DROP TABLE IF EXISTS federated.`t1%`;
+DROP TABLE IF EXISTS federated.t1;
+Warnings:
+Note 1051 Unknown table 't1'
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32) NOT NULL default '',
+`other` int(20) NOT NULL default '0',
+`created` datetime default '2004-04-04 04:04:04',
+PRIMARY KEY (`id`),
+KEY `name` (`name`),
+KEY `other_key` (`other`))
+DEFAULT CHARSET=latin1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32) NOT NULL default '',
+`other` int(20) NOT NULL default '0',
+`created` datetime default '2004-04-04 04:04:04',
+PRIMARY KEY (`id`),
+KEY `name` (`name`),
+KEY `other_key` (`other`))
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111);
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', 22222);
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333);
+INSERT INTO federated.t1 (name, other) VALUES ('Fourth Name', 44444);
+INSERT INTO federated.t1 (name, other) VALUES ('Fifth Name', 55555);
+INSERT INTO federated.t1 (name, other) VALUES ('Sixth Name', 66666);
+INSERT INTO federated.t1 (name, other) VALUES ('Seventh Name', 77777);
+INSERT INTO federated.t1 (name, other) VALUES ('Eigth Name', 88888);
+INSERT INTO federated.t1 (name, other) VALUES ('Ninth Name', 99999);
+INSERT INTO federated.t1 (name, other) VALUES ('Tenth Name', 101010);
+SELECT * FROM federated.t1;
+id name other created
+1 First Name 11111 2004-04-04 04:04:04
+2 Second Name 22222 2004-04-04 04:04:04
+3 Third Name 33333 2004-04-04 04:04:04
+4 Fourth Name 44444 2004-04-04 04:04:04
+5 Fifth Name 55555 2004-04-04 04:04:04
+6 Sixth Name 66666 2004-04-04 04:04:04
+7 Seventh Name 77777 2004-04-04 04:04:04
+8 Eigth Name 88888 2004-04-04 04:04:04
+9 Ninth Name 99999 2004-04-04 04:04:04
+10 Tenth Name 101010 2004-04-04 04:04:04
+SELECT * FROM federated.t1 WHERE id = 5;
+id name other created
+5 Fifth Name 55555 2004-04-04 04:04:04
+SELECT * FROM federated.t1 WHERE name = 'Sixth Name';
+id name other created
+6 Sixth Name 66666 2004-04-04 04:04:04
+SELECT * FROM federated.t1 WHERE id = 6 and name = 'Sixth Name';
+id name other created
+6 Sixth Name 66666 2004-04-04 04:04:04
+SELECT * FROM federated.t1 WHERE other = 44444;
+id name other created
+4 Fourth Name 44444 2004-04-04 04:04:04
+SELECT * FROM federated.t1 WHERE name like '%th%';
+id name other created
+3 Third Name 33333 2004-04-04 04:04:04
+4 Fourth Name 44444 2004-04-04 04:04:04
+5 Fifth Name 55555 2004-04-04 04:04:04
+6 Sixth Name 66666 2004-04-04 04:04:04
+7 Seventh Name 77777 2004-04-04 04:04:04
+8 Eigth Name 88888 2004-04-04 04:04:04
+9 Ninth Name 99999 2004-04-04 04:04:04
+10 Tenth Name 101010 2004-04-04 04:04:04
+UPDATE federated.t1 SET name = '3rd name' WHERE id = 3;
+SELECT * FROM federated.t1 WHERE name = '3rd name';
+id name other created
+3 3rd name 33333 2004-04-04 04:04:04
+UPDATE federated.t1 SET name = 'Third name' WHERE name = '3rd name';
+SELECT * FROM federated.t1 WHERE name = 'Third name';
+id name other created
+3 Third name 33333 2004-04-04 04:04:04
+SELECT * FROM federated.t1 ORDER BY id DESC;
+id name other created
+10 Tenth Name 101010 2004-04-04 04:04:04
+9 Ninth Name 99999 2004-04-04 04:04:04
+8 Eigth Name 88888 2004-04-04 04:04:04
+7 Seventh Name 77777 2004-04-04 04:04:04
+6 Sixth Name 66666 2004-04-04 04:04:04
+5 Fifth Name 55555 2004-04-04 04:04:04
+4 Fourth Name 44444 2004-04-04 04:04:04
+3 Third name 33333 2004-04-04 04:04:04
+2 Second Name 22222 2004-04-04 04:04:04
+1 First Name 11111 2004-04-04 04:04:04
+SELECT * FROM federated.t1 ORDER BY name;
+id name other created
+8 Eigth Name 88888 2004-04-04 04:04:04
+5 Fifth Name 55555 2004-04-04 04:04:04
+1 First Name 11111 2004-04-04 04:04:04
+4 Fourth Name 44444 2004-04-04 04:04:04
+9 Ninth Name 99999 2004-04-04 04:04:04
+2 Second Name 22222 2004-04-04 04:04:04
+7 Seventh Name 77777 2004-04-04 04:04:04
+6 Sixth Name 66666 2004-04-04 04:04:04
+10 Tenth Name 101010 2004-04-04 04:04:04
+3 Third name 33333 2004-04-04 04:04:04
+SELECT * FROM federated.t1 ORDER BY name DESC;
+id name other created
+3 Third name 33333 2004-04-04 04:04:04
+10 Tenth Name 101010 2004-04-04 04:04:04
+6 Sixth Name 66666 2004-04-04 04:04:04
+7 Seventh Name 77777 2004-04-04 04:04:04
+2 Second Name 22222 2004-04-04 04:04:04
+9 Ninth Name 99999 2004-04-04 04:04:04
+4 Fourth Name 44444 2004-04-04 04:04:04
+1 First Name 11111 2004-04-04 04:04:04
+5 Fifth Name 55555 2004-04-04 04:04:04
+8 Eigth Name 88888 2004-04-04 04:04:04
+SELECT * FROM federated.t1 ORDER BY name ASC;
+id name other created
+8 Eigth Name 88888 2004-04-04 04:04:04
+5 Fifth Name 55555 2004-04-04 04:04:04
+1 First Name 11111 2004-04-04 04:04:04
+4 Fourth Name 44444 2004-04-04 04:04:04
+9 Ninth Name 99999 2004-04-04 04:04:04
+2 Second Name 22222 2004-04-04 04:04:04
+7 Seventh Name 77777 2004-04-04 04:04:04
+6 Sixth Name 66666 2004-04-04 04:04:04
+10 Tenth Name 101010 2004-04-04 04:04:04
+3 Third name 33333 2004-04-04 04:04:04
+SELECT * FROM federated.t1 GROUP BY other;
+id name other created
+1 First Name 11111 2004-04-04 04:04:04
+2 Second Name 22222 2004-04-04 04:04:04
+3 Third name 33333 2004-04-04 04:04:04
+4 Fourth Name 44444 2004-04-04 04:04:04
+5 Fifth Name 55555 2004-04-04 04:04:04
+6 Sixth Name 66666 2004-04-04 04:04:04
+7 Seventh Name 77777 2004-04-04 04:04:04
+8 Eigth Name 88888 2004-04-04 04:04:04
+9 Ninth Name 99999 2004-04-04 04:04:04
+10 Tenth Name 101010 2004-04-04 04:04:04
+DELETE FROM federated.t1 WHERE id = 5;
+SELECT * FROM federated.t1 WHERE id = 5;
+id name other created
+DELETE FROM federated.t1;
+SELECT * FROM federated.t1 WHERE id = 5;
+id name other created
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32),
+`other` varchar(20),
+PRIMARY KEY (`id`) );
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32),
+`other` varchar(20),
+PRIMARY KEY (`id`) )
+ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111);
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', NULL);
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333);
+INSERT INTO federated.t1 (name, other) VALUES (NULL, NULL);
+INSERT INTO federated.t1 (name, other) VALUES ('Fifth Name', 55555);
+INSERT INTO federated.t1 (name, other) VALUES ('Sixth Name', 66666);
+INSERT INTO federated.t1 (name) VALUES ('Seventh Name');
+INSERT INTO federated.t1 (name, other) VALUES ('Eigth Name', 88888);
+INSERT INTO federated.t1 (name, other) VALUES ('Ninth Name', 99999);
+INSERT INTO federated.t1 (other) VALUES ('fee fie foe fum');
+SELECT * FROM federated.t1 WHERE other IS NULL;
+id name other
+2 Second Name NULL
+4 NULL NULL
+7 Seventh Name NULL
+SELECT * FROM federated.t1 WHERE name IS NULL;
+id name other
+4 NULL NULL
+10 NULL fee fie foe fum
+SELECT * FROM federated.t1 WHERE name IS NULL and other IS NULL;
+id name other
+4 NULL NULL
+SELECT * FROM federated.t1 WHERE name IS NULL or other IS NULL;
+id name other
+2 Second Name NULL
+4 NULL NULL
+7 Seventh Name NULL
+10 NULL fee fie foe fum
+UPDATE federated.t1
+SET name = 'Fourth Name', other = 'four four four'
+WHERE name IS NULL AND other IS NULL;
+UPDATE federated.t1 SET other = 'two two two two' WHERE name = 'Second Name';
+UPDATE federated.t1 SET other = 'seven seven' WHERE name like 'Sec%';
+UPDATE federated.t1 SET other = 'seven seven' WHERE name = 'Seventh Name';
+UPDATE federated.t1 SET name = 'Tenth Name' WHERE other like 'fee fie%';
+SELECT * FROM federated.t1 WHERE name IS NULL OR other IS NULL ;
+id name other
+SELECT * FROM federated.t1;
+id name other
+1 First Name 11111
+2 Second Name seven seven
+3 Third Name 33333
+4 Fourth Name four four four
+5 Fifth Name 55555
+6 Sixth Name 66666
+7 Seventh Name seven seven
+8 Eigth Name 88888
+9 Ninth Name 99999
+10 Tenth Name fee fie foe fum
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32) NOT NULL DEFAULT '',
+`other` varchar(20) NOT NULL DEFAULT '',
+PRIMARY KEY (`id`),
+KEY nameoth (name, other) );
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32) NOT NULL DEFAULT '',
+`other` varchar(20) NOT NULL DEFAULT '',
+PRIMARY KEY (`id`),
+KEY nameoth (name, other))
+ENGINE="FEDERATED" DEFAULT
+CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (name, other) VALUES ('First Name', '1111');
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', '2222');
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', '3333');
+SELECT * FROM federated.t1 WHERE name = 'Second Name';
+id name other
+2 Second Name 2222
+SELECT * FROM federated.t1 WHERE other = '2222';
+id name other
+2 Second Name 2222
+SELECT * FROM federated.t1 WHERE name = 'Third Name';
+id name other
+3 Third Name 3333
+SELECT * FROM federated.t1 WHERE name = 'Third Name' AND other = '3333';
+id name other
+3 Third Name 3333
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int NOT NULL auto_increment,
+`name` char(32) NOT NULL DEFAULT '',
+`bincol` binary(4) NOT NULL,
+`floatval` decimal(5,2) NOT NULL DEFAULT 0.0,
+`other` int NOT NULL DEFAULT 0,
+PRIMARY KEY (id),
+KEY nameoth(name, other),
+KEY bincol(bincol),
+KEY floatval(floatval));
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int NOT NULL auto_increment,
+`name` char(32) NOT NULL DEFAULT '',
+`bincol` binary(4) NOT NULL,
+`floatval` decimal(5,2) NOT NULL DEFAULT 0.0,
+`other` int NOT NULL DEFAULT 0,
+PRIMARY KEY (id),
+KEY nameoth(name,other),
+KEY bincol(bincol),
+KEY floatval(floatval))
+ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+VALUES ('first', 0x65, 11.11, 1111);
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+VALUES ('second', 0x66, 22.22, 2222);
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+VALUES ('third', 'g', 22.22, 2222);
+SELECT * FROM federated.t1;
+id name bincol floatval other
+1 first e 11.11 1111
+2 second f 22.22 2222
+3 third g 22.22 2222
+SELECT * FROM federated.t1 WHERE name = 'second';
+id name bincol floatval other
+2 second f 22.22 2222
+SELECT * FROM federated.t1 WHERE bincol= 'f';
+id name bincol floatval other
+2 second f 22.22 2222
+SELECT * FROM federated.t1 WHERE bincol= 0x66;
+id name bincol floatval other
+2 second f 22.22 2222
+SELECT * FROM federated.t1 WHERE bincol= 0x67;
+id name bincol floatval other
+3 third g 22.22 2222
+SELECT * FROM federated.t1 WHERE bincol= 'g';
+id name bincol floatval other
+3 third g 22.22 2222
+SELECT * FROM federated.t1 WHERE floatval=11.11;
+id name bincol floatval other
+1 first e 11.11 1111
+SELECT * FROM federated.t1 WHERE name='third';
+id name bincol floatval other
+3 third g 22.22 2222
+SELECT * FROM federated.t1 WHERE other=2222;
+id name bincol floatval other
+2 second f 22.22 2222
+3 third g 22.22 2222
+SELECT * FROM federated.t1 WHERE name='third' and other=2222;
+id name bincol floatval other
+3 third g 22.22 2222
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int,
+`name` varchar(32),
+`floatval` float,
+`other` int)
+DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int,
+`name` varchar(32),
+`floatval` float,
+`other` int)
+ENGINE="FEDERATED"
+DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 values (NULL, NULL, NULL, NULL);
+INSERT INTO federated.t1 values ();
+INSERT INTO federated.t1 (id) VALUES (1);
+INSERT INTO federated.t1 (name, floatval, other)
+VALUES ('foo', 33.33333332, NULL);
+INSERT INTO federated.t1 (name, floatval, other)
+VALUES (0, 00.3333, NULL);
+SELECT * FROM federated.t1;
+id name floatval other
+NULL NULL NULL NULL
+NULL NULL NULL NULL
+1 NULL NULL NULL
+NULL foo 33.3333 NULL
+NULL 0 0.3333 NULL
+SELECT count(*) FROM federated.t1
+WHERE id IS NULL
+AND name IS NULL
+AND floatval IS NULL
+AND other IS NULL;
+count(*)
+2
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`blurb_id` int NOT NULL DEFAULT 0,
+`blurb` text default '',
+PRIMARY KEY (blurb_id))
+DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`blurb_id` int NOT NULL DEFAULT 0,
+`blurb` text default '',
+PRIMARY KEY (blurb_id))
+ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 VALUES (1, " MySQL supports a number of column types in several categories: numeric types, date and time types, and string (character) types. This chapter first gives an overview of these column types, and then provides a more detailed description of the properties of the types in each category, and a summary of the column type storage requirements. The overview is intentionally brief. The more detailed descriptions should be consulted for additional information about particular column types, such as the allowable formats in which you can specify values.");
+INSERT INTO federated.t1 VALUES (2, "All arithmetic is done using signed BIGINT or DOUBLE values, so you should not use unsigned big integers larger than 9223372036854775807 (63 bits) except with bit functions! If you do that, some of the last digits in the result may be wrong because of rounding errors when converting a BIGINT value to a DOUBLE.");
+INSERT INTO federated.t1 VALUES (3, " A floating-point number. p represents the precision. It can be from 0 to 24 for a single-precision floating-point number and from 25 to 53 for a double-precision floating-point number. These types are like the FLOAT and DOUBLE types described immediately following. FLOAT(p) has the same range as the corresponding FLOAT and DOUBLE types, but the display size and number of decimals are undefined. ");
+INSERT INTO federated.t1 VALUES(4, "Die Übersetzung einer so umfangreichen technischen Dokumentation wie des MySQL-Referenzhandbuchs ist schon eine besondere Herausforderung. Zumindest für jemanden, der seine Zielsprache ernst nimmt:");
+SELECT * FROM federated.t1;
+blurb_id blurb
+1 MySQL supports a number of column types in several categories: numeric types, date and time types, and string (character) types. This chapter first gives an overview of these column types, and then provides a more detailed description of the properties of the types in each category, and a summary of the column type storage requirements. The overview is intentionally brief. The more detailed descriptions should be consulted for additional information about particular column types, such as the allowable formats in which you can specify values.
+2 All arithmetic is done using signed BIGINT or DOUBLE values, so you should not use unsigned big integers larger than 9223372036854775807 (63 bits) except with bit functions! If you do that, some of the last digits in the result may be wrong because of rounding errors when converting a BIGINT value to a DOUBLE.
+3 A floating-point number. p represents the precision. It can be from 0 to 24 for a single-precision floating-point number and from 25 to 53 for a double-precision floating-point number. These types are like the FLOAT and DOUBLE types described immediately following. FLOAT(p) has the same range as the corresponding FLOAT and DOUBLE types, but the display size and number of decimals are undefined.
+4 Die Übersetzung einer so umfangreichen technischen Dokumentation wie des MySQL-Referenzhandbuchs ist schon eine besondere Herausforderung. Zumindest für jemanden, der seine Zielsprache ernst nimmt:
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`a` int NOT NULL,
+`b` int NOT NULL,
+`c` int NOT NULL,
+PRIMARY KEY (a),key(b));
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`a` int NOT NULL,
+`b` int NOT NULL,
+`c` int NOT NULL,
+PRIMARY KEY (a),
+KEY (b))
+ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 VALUES (3,3,3),(1,1,1),(2,2,2),(4,4,4);
+EXPLAIN SELECT * FROM federated.t1 ORDER BY a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort
+EXPLAIN SELECT * FROM federated.t1 ORDER BY b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort
+EXPLAIN SELECT * FROM federated.t1 ORDER BY c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort
+EXPLAIN SELECT a FROM federated.t1 ORDER BY a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort
+EXPLAIN SELECT b FROM federated.t1 ORDER BY b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort
+EXPLAIN SELECT a,b FROM federated.t1 ORDER BY b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort
+EXPLAIN SELECT a,b FROM federated.t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10000
+EXPLAIN SELECT a,b,c FROM federated.t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10000
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
+int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int, i17
+int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
+i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
+int, i35 int, i36 int, i37 int, i38 int, i39 int, i40 int, i41 int, i42 int,
+i43 int, i44 int, i45 int, i46 int, i47 int, i48 int, i49 int, i50 int, i51
+int, i52 int, i53 int, i54 int, i55 int, i56 int, i57 int, i58 int, i59 int,
+i60 int, i61 int, i62 int, i63 int, i64 int, i65 int, i66 int, i67 int, i68
+int, i69 int, i70 int, i71 int, i72 int, i73 int, i74 int, i75 int, i76 int,
+i77 int, i78 int, i79 int, i80 int, i81 int, i82 int, i83 int, i84 int, i85
+int, i86 int, i87 int, i88 int, i89 int, i90 int, i91 int, i92 int, i93 int,
+i94 int, i95 int, i96 int, i97 int, i98 int, i99 int, i100 int, i101 int, i102
+int, i103 int, i104 int, i105 int, i106 int, i107 int, i108 int, i109 int, i110
+int, i111 int, i112 int, i113 int, i114 int, i115 int, i116 int, i117 int, i118
+int, i119 int, i120 int, i121 int, i122 int, i123 int, i124 int, i125 int, i126
+int, i127 int, i128 int, i129 int, i130 int, i131 int, i132 int, i133 int, i134
+int, i135 int, i136 int, i137 int, i138 int, i139 int, i140 int, i141 int, i142
+int, i143 int, i144 int, i145 int, i146 int, i147 int, i148 int, i149 int, i150
+int, i151 int, i152 int, i153 int, i154 int, i155 int, i156 int, i157 int, i158
+int, i159 int, i160 int, i161 int, i162 int, i163 int, i164 int, i165 int, i166
+int, i167 int, i168 int, i169 int, i170 int, i171 int, i172 int, i173 int, i174
+int, i175 int, i176 int, i177 int, i178 int, i179 int, i180 int, i181 int, i182
+int, i183 int, i184 int, i185 int, i186 int, i187 int, i188 int, i189 int, i190
+int, i191 int, i192 int, i193 int, i194 int, i195 int, i196 int, i197 int, i198
+int, i199 int, i200 int, i201 int, i202 int, i203 int, i204 int, i205 int, i206
+int, i207 int, i208 int, i209 int, i210 int, i211 int, i212 int, i213 int, i214
+int, i215 int, i216 int, i217 int, i218 int, i219 int, i220 int, i221 int, i222
+int, i223 int, i224 int, i225 int, i226 int, i227 int, i228 int, i229 int, i230
+int, i231 int, i232 int, i233 int, i234 int, i235 int, i236 int, i237 int, i238
+int, i239 int, i240 int, i241 int, i242 int, i243 int, i244 int, i245 int, i246
+int, i247 int, i248 int, i249 int, i250 int, i251 int, i252 int, i253 int, i254
+int, i255 int, i256 int, i257 int, i258 int, i259 int, i260 int, i261 int, i262
+int, i263 int, i264 int, i265 int, i266 int, i267 int, i268 int, i269 int, i270
+int, i271 int, i272 int, i273 int, i274 int, i275 int, i276 int, i277 int, i278
+int, i279 int, i280 int, i281 int, i282 int, i283 int, i284 int, i285 int, i286
+int, i287 int, i288 int, i289 int, i290 int, i291 int, i292 int, i293 int, i294
+int, i295 int, i296 int, i297 int, i298 int, i299 int, i300 int, i301 int, i302
+int, i303 int, i304 int, i305 int, i306 int, i307 int, i308 int, i309 int, i310
+int, i311 int, i312 int, i313 int, i314 int, i315 int, i316 int, i317 int, i318
+int, i319 int, i320 int, i321 int, i322 int, i323 int, i324 int, i325 int, i326
+int, i327 int, i328 int, i329 int, i330 int, i331 int, i332 int, i333 int, i334
+int, i335 int, i336 int, i337 int, i338 int, i339 int, i340 int, i341 int, i342
+int, i343 int, i344 int, i345 int, i346 int, i347 int, i348 int, i349 int, i350
+int, i351 int, i352 int, i353 int, i354 int, i355 int, i356 int, i357 int, i358
+int, i359 int, i360 int, i361 int, i362 int, i363 int, i364 int, i365 int, i366
+int, i367 int, i368 int, i369 int, i370 int, i371 int, i372 int, i373 int, i374
+int, i375 int, i376 int, i377 int, i378 int, i379 int, i380 int, i381 int, i382
+int, i383 int, i384 int, i385 int, i386 int, i387 int, i388 int, i389 int, i390
+int, i391 int, i392 int, i393 int, i394 int, i395 int, i396 int, i397 int, i398
+int, i399 int, i400 int, i401 int, i402 int, i403 int, i404 int, i405 int, i406
+int, i407 int, i408 int, i409 int, i410 int, i411 int, i412 int, i413 int, i414
+int, i415 int, i416 int, i417 int, i418 int, i419 int, i420 int, i421 int, i422
+int, i423 int, i424 int, i425 int, i426 int, i427 int, i428 int, i429 int, i430
+int, i431 int, i432 int, i433 int, i434 int, i435 int, i436 int, i437 int, i438
+int, i439 int, i440 int, i441 int, i442 int, i443 int, i444 int, i445 int, i446
+int, i447 int, i448 int, i449 int, i450 int, i451 int, i452 int, i453 int, i454
+int, i455 int, i456 int, i457 int, i458 int, i459 int, i460 int, i461 int, i462
+int, i463 int, i464 int, i465 int, i466 int, i467 int, i468 int, i469 int, i470
+int, i471 int, i472 int, i473 int, i474 int, i475 int, i476 int, i477 int, i478
+int, i479 int, i480 int, i481 int, i482 int, i483 int, i484 int, i485 int, i486
+int, i487 int, i488 int, i489 int, i490 int, i491 int, i492 int, i493 int, i494
+int, i495 int, i496 int, i497 int, i498 int, i499 int, i500 int, i501 int, i502
+int, i503 int, i504 int, i505 int, i506 int, i507 int, i508 int, i509 int, i510
+int, i511 int, i512 int, i513 int, i514 int, i515 int, i516 int, i517 int, i518
+int, i519 int, i520 int, i521 int, i522 int, i523 int, i524 int, i525 int, i526
+int, i527 int, i528 int, i529 int, i530 int, i531 int, i532 int, i533 int, i534
+int, i535 int, i536 int, i537 int, i538 int, i539 int, i540 int, i541 int, i542
+int, i543 int, i544 int, i545 int, i546 int, i547 int, i548 int, i549 int, i550
+int, i551 int, i552 int, i553 int, i554 int, i555 int, i556 int, i557 int, i558
+int, i559 int, i560 int, i561 int, i562 int, i563 int, i564 int, i565 int, i566
+int, i567 int, i568 int, i569 int, i570 int, i571 int, i572 int, i573 int, i574
+int, i575 int, i576 int, i577 int, i578 int, i579 int, i580 int, i581 int, i582
+int, i583 int, i584 int, i585 int, i586 int, i587 int, i588 int, i589 int, i590
+int, i591 int, i592 int, i593 int, i594 int, i595 int, i596 int, i597 int, i598
+int, i599 int, i600 int, i601 int, i602 int, i603 int, i604 int, i605 int, i606
+int, i607 int, i608 int, i609 int, i610 int, i611 int, i612 int, i613 int, i614
+int, i615 int, i616 int, i617 int, i618 int, i619 int, i620 int, i621 int, i622
+int, i623 int, i624 int, i625 int, i626 int, i627 int, i628 int, i629 int, i630
+int, i631 int, i632 int, i633 int, i634 int, i635 int, i636 int, i637 int, i638
+int, i639 int, i640 int, i641 int, i642 int, i643 int, i644 int, i645 int, i646
+int, i647 int, i648 int, i649 int, i650 int, i651 int, i652 int, i653 int, i654
+int, i655 int, i656 int, i657 int, i658 int, i659 int, i660 int, i661 int, i662
+int, i663 int, i664 int, i665 int, i666 int, i667 int, i668 int, i669 int, i670
+int, i671 int, i672 int, i673 int, i674 int, i675 int, i676 int, i677 int, i678
+int, i679 int, i680 int, i681 int, i682 int, i683 int, i684 int, i685 int, i686
+int, i687 int, i688 int, i689 int, i690 int, i691 int, i692 int, i693 int, i694
+int, i695 int, i696 int, i697 int, i698 int, i699 int, i700 int, i701 int, i702
+int, i703 int, i704 int, i705 int, i706 int, i707 int, i708 int, i709 int, i710
+int, i711 int, i712 int, i713 int, i714 int, i715 int, i716 int, i717 int, i718
+int, i719 int, i720 int, i721 int, i722 int, i723 int, i724 int, i725 int, i726
+int, i727 int, i728 int, i729 int, i730 int, i731 int, i732 int, i733 int, i734
+int, i735 int, i736 int, i737 int, i738 int, i739 int, i740 int, i741 int, i742
+int, i743 int, i744 int, i745 int, i746 int, i747 int, i748 int, i749 int, i750
+int, i751 int, i752 int, i753 int, i754 int, i755 int, i756 int, i757 int, i758
+int, i759 int, i760 int, i761 int, i762 int, i763 int, i764 int, i765 int, i766
+int, i767 int, i768 int, i769 int, i770 int, i771 int, i772 int, i773 int, i774
+int, i775 int, i776 int, i777 int, i778 int, i779 int, i780 int, i781 int, i782
+int, i783 int, i784 int, i785 int, i786 int, i787 int, i788 int, i789 int, i790
+int, i791 int, i792 int, i793 int, i794 int, i795 int, i796 int, i797 int, i798
+int, i799 int, i800 int, i801 int, i802 int, i803 int, i804 int, i805 int, i806
+int, i807 int, i808 int, i809 int, i810 int, i811 int, i812 int, i813 int, i814
+int, i815 int, i816 int, i817 int, i818 int, i819 int, i820 int, i821 int, i822
+int, i823 int, i824 int, i825 int, i826 int, i827 int, i828 int, i829 int, i830
+int, i831 int, i832 int, i833 int, i834 int, i835 int, i836 int, i837 int, i838
+int, i839 int, i840 int, i841 int, i842 int, i843 int, i844 int, i845 int, i846
+int, i847 int, i848 int, i849 int, i850 int, i851 int, i852 int, i853 int, i854
+int, i855 int, i856 int, i857 int, i858 int, i859 int, i860 int, i861 int, i862
+int, i863 int, i864 int, i865 int, i866 int, i867 int, i868 int, i869 int, i870
+int, i871 int, i872 int, i873 int, i874 int, i875 int, i876 int, i877 int, i878
+int, i879 int, i880 int, i881 int, i882 int, i883 int, i884 int, i885 int, i886
+int, i887 int, i888 int, i889 int, i890 int, i891 int, i892 int, i893 int, i894
+int, i895 int, i896 int, i897 int, i898 int, i899 int, i900 int, i901 int, i902
+int, i903 int, i904 int, i905 int, i906 int, i907 int, i908 int, i909 int, i910
+int, i911 int, i912 int, i913 int, i914 int, i915 int, i916 int, i917 int, i918
+int, i919 int, i920 int, i921 int, i922 int, i923 int, i924 int, i925 int, i926
+int, i927 int, i928 int, i929 int, i930 int, i931 int, i932 int, i933 int, i934
+int, i935 int, i936 int, i937 int, i938 int, i939 int, i940 int, i941 int, i942
+int, i943 int, i944 int, i945 int, i946 int, i947 int, i948 int, i949 int, i950
+int, i951 int, i952 int, i953 int, i954 int, i955 int, i956 int, i957 int, i958
+int, i959 int, i960 int, i961 int, i962 int, i963 int, i964 int, i965 int, i966
+int, i967 int, i968 int, i969 int, i970 int, i971 int, i972 int, i973 int, i974
+int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
+int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
+int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
+int, i999 int, i1000 int, b varchar(256)) row_format=dynamic;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1
+(i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
+int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int,
+i17 int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
+i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
+int, i35 int, i36 int, i37 int, i38 int, i39 int, i40 int, i41 int, i42 int,
+i43 int, i44 int, i45 int, i46 int, i47 int, i48 int, i49 int, i50 int, i51
+int, i52 int, i53 int, i54 int, i55 int, i56 int, i57 int, i58 int, i59 int,
+i60 int, i61 int, i62 int, i63 int, i64 int, i65 int, i66 int, i67 int, i68
+int, i69 int, i70 int, i71 int, i72 int, i73 int, i74 int, i75 int, i76 int,
+i77 int, i78 int, i79 int, i80 int, i81 int, i82 int, i83 int, i84 int, i85
+int, i86 int, i87 int, i88 int, i89 int, i90 int, i91 int, i92 int, i93 int,
+i94 int, i95 int, i96 int, i97 int, i98 int, i99 int, i100 int, i101 int, i102
+int, i103 int, i104 int, i105 int, i106 int, i107 int, i108 int, i109 int, i110
+int, i111 int, i112 int, i113 int, i114 int, i115 int, i116 int, i117 int, i118
+int, i119 int, i120 int, i121 int, i122 int, i123 int, i124 int, i125 int, i126
+int, i127 int, i128 int, i129 int, i130 int, i131 int, i132 int, i133 int, i134
+int, i135 int, i136 int, i137 int, i138 int, i139 int, i140 int, i141 int, i142
+int, i143 int, i144 int, i145 int, i146 int, i147 int, i148 int, i149 int, i150
+int, i151 int, i152 int, i153 int, i154 int, i155 int, i156 int, i157 int, i158
+int, i159 int, i160 int, i161 int, i162 int, i163 int, i164 int, i165 int, i166
+int, i167 int, i168 int, i169 int, i170 int, i171 int, i172 int, i173 int, i174
+int, i175 int, i176 int, i177 int, i178 int, i179 int, i180 int, i181 int, i182
+int, i183 int, i184 int, i185 int, i186 int, i187 int, i188 int, i189 int, i190
+int, i191 int, i192 int, i193 int, i194 int, i195 int, i196 int, i197 int, i198
+int, i199 int, i200 int, i201 int, i202 int, i203 int, i204 int, i205 int, i206
+int, i207 int, i208 int, i209 int, i210 int, i211 int, i212 int, i213 int, i214
+int, i215 int, i216 int, i217 int, i218 int, i219 int, i220 int, i221 int, i222
+int, i223 int, i224 int, i225 int, i226 int, i227 int, i228 int, i229 int, i230
+int, i231 int, i232 int, i233 int, i234 int, i235 int, i236 int, i237 int, i238
+int, i239 int, i240 int, i241 int, i242 int, i243 int, i244 int, i245 int, i246
+int, i247 int, i248 int, i249 int, i250 int, i251 int, i252 int, i253 int, i254
+int, i255 int, i256 int, i257 int, i258 int, i259 int, i260 int, i261 int, i262
+int, i263 int, i264 int, i265 int, i266 int, i267 int, i268 int, i269 int, i270
+int, i271 int, i272 int, i273 int, i274 int, i275 int, i276 int, i277 int, i278
+int, i279 int, i280 int, i281 int, i282 int, i283 int, i284 int, i285 int, i286
+int, i287 int, i288 int, i289 int, i290 int, i291 int, i292 int, i293 int, i294
+int, i295 int, i296 int, i297 int, i298 int, i299 int, i300 int, i301 int, i302
+int, i303 int, i304 int, i305 int, i306 int, i307 int, i308 int, i309 int, i310
+int, i311 int, i312 int, i313 int, i314 int, i315 int, i316 int, i317 int, i318
+int, i319 int, i320 int, i321 int, i322 int, i323 int, i324 int, i325 int, i326
+int, i327 int, i328 int, i329 int, i330 int, i331 int, i332 int, i333 int, i334
+int, i335 int, i336 int, i337 int, i338 int, i339 int, i340 int, i341 int, i342
+int, i343 int, i344 int, i345 int, i346 int, i347 int, i348 int, i349 int, i350
+int, i351 int, i352 int, i353 int, i354 int, i355 int, i356 int, i357 int, i358
+int, i359 int, i360 int, i361 int, i362 int, i363 int, i364 int, i365 int, i366
+int, i367 int, i368 int, i369 int, i370 int, i371 int, i372 int, i373 int, i374
+int, i375 int, i376 int, i377 int, i378 int, i379 int, i380 int, i381 int, i382
+int, i383 int, i384 int, i385 int, i386 int, i387 int, i388 int, i389 int, i390
+int, i391 int, i392 int, i393 int, i394 int, i395 int, i396 int, i397 int, i398
+int, i399 int, i400 int, i401 int, i402 int, i403 int, i404 int, i405 int, i406
+int, i407 int, i408 int, i409 int, i410 int, i411 int, i412 int, i413 int, i414
+int, i415 int, i416 int, i417 int, i418 int, i419 int, i420 int, i421 int, i422
+int, i423 int, i424 int, i425 int, i426 int, i427 int, i428 int, i429 int, i430
+int, i431 int, i432 int, i433 int, i434 int, i435 int, i436 int, i437 int, i438
+int, i439 int, i440 int, i441 int, i442 int, i443 int, i444 int, i445 int, i446
+int, i447 int, i448 int, i449 int, i450 int, i451 int, i452 int, i453 int, i454
+int, i455 int, i456 int, i457 int, i458 int, i459 int, i460 int, i461 int, i462
+int, i463 int, i464 int, i465 int, i466 int, i467 int, i468 int, i469 int, i470
+int, i471 int, i472 int, i473 int, i474 int, i475 int, i476 int, i477 int, i478
+int, i479 int, i480 int, i481 int, i482 int, i483 int, i484 int, i485 int, i486
+int, i487 int, i488 int, i489 int, i490 int, i491 int, i492 int, i493 int, i494
+int, i495 int, i496 int, i497 int, i498 int, i499 int, i500 int, i501 int, i502
+int, i503 int, i504 int, i505 int, i506 int, i507 int, i508 int, i509 int, i510
+int, i511 int, i512 int, i513 int, i514 int, i515 int, i516 int, i517 int, i518
+int, i519 int, i520 int, i521 int, i522 int, i523 int, i524 int, i525 int, i526
+int, i527 int, i528 int, i529 int, i530 int, i531 int, i532 int, i533 int, i534
+int, i535 int, i536 int, i537 int, i538 int, i539 int, i540 int, i541 int, i542
+int, i543 int, i544 int, i545 int, i546 int, i547 int, i548 int, i549 int, i550
+int, i551 int, i552 int, i553 int, i554 int, i555 int, i556 int, i557 int, i558
+int, i559 int, i560 int, i561 int, i562 int, i563 int, i564 int, i565 int, i566
+int, i567 int, i568 int, i569 int, i570 int, i571 int, i572 int, i573 int, i574
+int, i575 int, i576 int, i577 int, i578 int, i579 int, i580 int, i581 int, i582
+int, i583 int, i584 int, i585 int, i586 int, i587 int, i588 int, i589 int, i590
+int, i591 int, i592 int, i593 int, i594 int, i595 int, i596 int, i597 int, i598
+int, i599 int, i600 int, i601 int, i602 int, i603 int, i604 int, i605 int, i606
+int, i607 int, i608 int, i609 int, i610 int, i611 int, i612 int, i613 int, i614
+int, i615 int, i616 int, i617 int, i618 int, i619 int, i620 int, i621 int, i622
+int, i623 int, i624 int, i625 int, i626 int, i627 int, i628 int, i629 int, i630
+int, i631 int, i632 int, i633 int, i634 int, i635 int, i636 int, i637 int, i638
+int, i639 int, i640 int, i641 int, i642 int, i643 int, i644 int, i645 int, i646
+int, i647 int, i648 int, i649 int, i650 int, i651 int, i652 int, i653 int, i654
+int, i655 int, i656 int, i657 int, i658 int, i659 int, i660 int, i661 int, i662
+int, i663 int, i664 int, i665 int, i666 int, i667 int, i668 int, i669 int, i670
+int, i671 int, i672 int, i673 int, i674 int, i675 int, i676 int, i677 int, i678
+int, i679 int, i680 int, i681 int, i682 int, i683 int, i684 int, i685 int, i686
+int, i687 int, i688 int, i689 int, i690 int, i691 int, i692 int, i693 int, i694
+int, i695 int, i696 int, i697 int, i698 int, i699 int, i700 int, i701 int, i702
+int, i703 int, i704 int, i705 int, i706 int, i707 int, i708 int, i709 int, i710
+int, i711 int, i712 int, i713 int, i714 int, i715 int, i716 int, i717 int, i718
+int, i719 int, i720 int, i721 int, i722 int, i723 int, i724 int, i725 int, i726
+int, i727 int, i728 int, i729 int, i730 int, i731 int, i732 int, i733 int, i734
+int, i735 int, i736 int, i737 int, i738 int, i739 int, i740 int, i741 int, i742
+int, i743 int, i744 int, i745 int, i746 int, i747 int, i748 int, i749 int, i750
+int, i751 int, i752 int, i753 int, i754 int, i755 int, i756 int, i757 int, i758
+int, i759 int, i760 int, i761 int, i762 int, i763 int, i764 int, i765 int, i766
+int, i767 int, i768 int, i769 int, i770 int, i771 int, i772 int, i773 int, i774
+int, i775 int, i776 int, i777 int, i778 int, i779 int, i780 int, i781 int, i782
+int, i783 int, i784 int, i785 int, i786 int, i787 int, i788 int, i789 int, i790
+int, i791 int, i792 int, i793 int, i794 int, i795 int, i796 int, i797 int, i798
+int, i799 int, i800 int, i801 int, i802 int, i803 int, i804 int, i805 int, i806
+int, i807 int, i808 int, i809 int, i810 int, i811 int, i812 int, i813 int, i814
+int, i815 int, i816 int, i817 int, i818 int, i819 int, i820 int, i821 int, i822
+int, i823 int, i824 int, i825 int, i826 int, i827 int, i828 int, i829 int, i830
+int, i831 int, i832 int, i833 int, i834 int, i835 int, i836 int, i837 int, i838
+int, i839 int, i840 int, i841 int, i842 int, i843 int, i844 int, i845 int, i846
+int, i847 int, i848 int, i849 int, i850 int, i851 int, i852 int, i853 int, i854
+int, i855 int, i856 int, i857 int, i858 int, i859 int, i860 int, i861 int, i862
+int, i863 int, i864 int, i865 int, i866 int, i867 int, i868 int, i869 int, i870
+int, i871 int, i872 int, i873 int, i874 int, i875 int, i876 int, i877 int, i878
+int, i879 int, i880 int, i881 int, i882 int, i883 int, i884 int, i885 int, i886
+int, i887 int, i888 int, i889 int, i890 int, i891 int, i892 int, i893 int, i894
+int, i895 int, i896 int, i897 int, i898 int, i899 int, i900 int, i901 int, i902
+int, i903 int, i904 int, i905 int, i906 int, i907 int, i908 int, i909 int, i910
+int, i911 int, i912 int, i913 int, i914 int, i915 int, i916 int, i917 int, i918
+int, i919 int, i920 int, i921 int, i922 int, i923 int, i924 int, i925 int, i926
+int, i927 int, i928 int, i929 int, i930 int, i931 int, i932 int, i933 int, i934
+int, i935 int, i936 int, i937 int, i938 int, i939 int, i940 int, i941 int, i942
+int, i943 int, i944 int, i945 int, i946 int, i947 int, i948 int, i949 int, i950
+int, i951 int, i952 int, i953 int, i954 int, i955 int, i956 int, i957 int, i958
+int, i959 int, i960 int, i961 int, i962 int, i963 int, i964 int, i965 int, i966
+int, i967 int, i968 int, i969 int, i970 int, i971 int, i972 int, i973 int, i974
+int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
+int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
+int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
+int, i999 int, i1000 int, b varchar(256))
+row_format=dynamic
+ENGINE="FEDERATED"
+DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1
+values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "PatrickG");
+UPDATE federated.t1 SET b=repeat('a',256);
+UPDATE federated.t1 SET i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0, i10=0;
+SELECT * FROM federated.t1 WHERE i9=0 and i10=0;
+i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20 i21 i22 i23 i24 i25 i26 i27 i28 i29 i30 i31 i32 i33 i34 i35 i36 i37 i38 i39 i40 i41 i42 i43 i44 i45 i46 i47 i48 i49 i50 i51 i52 i53 i54 i55 i56 i57 i58 i59 i60 i61 i62 i63 i64 i65 i66 i67 i68 i69 i70 i71 i72 i73 i74 i75 i76 i77 i78 i79 i80 i81 i82 i83 i84 i85 i86 i87 i88 i89 i90 i91 i92 i93 i94 i95 i96 i97 i98 i99 i100 i101 i102 i103 i104 i105 i106 i107 i108 i109 i110 i111 i112 i113 i114 i115 i116 i117 i118 i119 i120 i121 i122 i123 i124 i125 i126 i127 i128 i129 i130 i131 i132 i133 i134 i135 i136 i137 i138 i139 i140 i141 i142 i143 i144 i145 i146 i147 i148 i149 i150 i151 i152 i153 i154 i155 i156 i157 i158 i159 i160 i161 i162 i163 i164 i165 i166 i167 i168 i169 i170 i171 i172 i173 i174 i175 i176 i177 i178 i179 i180 i181 i182 i183 i184 i185 i186 i187 i188 i189 i190 i191 i192 i193 i194 i195 i196 i197 i198 i199 i200 i201 i202 i203 i204 i205 i206 i207 i208 i209 i210 i211 i212 i213 i214 i215 i216 i217 i218 i219 i220 i221 i222 i223 i224 i225 i226 i227 i228 i229 i230 i231 i232 i233 i234 i235 i236 i237 i238 i239 i240 i241 i242 i243 i244 i245 i246 i247 i248 i249 i250 i251 i252 i253 i254 i255 i256 i257 i258 i259 i260 i261 i262 i263 i264 i265 i266 i267 i268 i269 i270 i271 i272 i273 i274 i275 i276 i277 i278 i279 i280 i281 i282 i283 i284 i285 i286 i287 i288 i289 i290 i291 i292 i293 i294 i295 i296 i297 i298 i299 i300 i301 i302 i303 i304 i305 i306 i307 i308 i309 i310 i311 i312 i313 i314 i315 i316 i317 i318 i319 i320 i321 i322 i323 i324 i325 i326 i327 i328 i329 i330 i331 i332 i333 i334 i335 i336 i337 i338 i339 i340 i341 i342 i343 i344 i345 i346 i347 i348 i349 i350 i351 i352 i353 i354 i355 i356 i357 i358 i359 i360 i361 i362 i363 i364 i365 i366 i367 i368 i369 i370 i371 i372 i373 i374 i375 i376 i377 i378 i379 i380 i381 i382 i383 i384 i385 i386 i387 i388 i389 i390 i391 i392 i393 i394 i395 i396 i397 i398 i399 i400 i401 i402 i403 i404 i405 i406 i407 i408 i409 i410 i411 i412 i413 i414 i415 i416 i417 i418 i419 i420 i421 i422 i423 i424 i425 i426 i427 i428 i429 i430 i431 i432 i433 i434 i435 i436 i437 i438 i439 i440 i441 i442 i443 i444 i445 i446 i447 i448 i449 i450 i451 i452 i453 i454 i455 i456 i457 i458 i459 i460 i461 i462 i463 i464 i465 i466 i467 i468 i469 i470 i471 i472 i473 i474 i475 i476 i477 i478 i479 i480 i481 i482 i483 i484 i485 i486 i487 i488 i489 i490 i491 i492 i493 i494 i495 i496 i497 i498 i499 i500 i501 i502 i503 i504 i505 i506 i507 i508 i509 i510 i511 i512 i513 i514 i515 i516 i517 i518 i519 i520 i521 i522 i523 i524 i525 i526 i527 i528 i529 i530 i531 i532 i533 i534 i535 i536 i537 i538 i539 i540 i541 i542 i543 i544 i545 i546 i547 i548 i549 i550 i551 i552 i553 i554 i555 i556 i557 i558 i559 i560 i561 i562 i563 i564 i565 i566 i567 i568 i569 i570 i571 i572 i573 i574 i575 i576 i577 i578 i579 i580 i581 i582 i583 i584 i585 i586 i587 i588 i589 i590 i591 i592 i593 i594 i595 i596 i597 i598 i599 i600 i601 i602 i603 i604 i605 i606 i607 i608 i609 i610 i611 i612 i613 i614 i615 i616 i617 i618 i619 i620 i621 i622 i623 i624 i625 i626 i627 i628 i629 i630 i631 i632 i633 i634 i635 i636 i637 i638 i639 i640 i641 i642 i643 i644 i645 i646 i647 i648 i649 i650 i651 i652 i653 i654 i655 i656 i657 i658 i659 i660 i661 i662 i663 i664 i665 i666 i667 i668 i669 i670 i671 i672 i673 i674 i675 i676 i677 i678 i679 i680 i681 i682 i683 i684 i685 i686 i687 i688 i689 i690 i691 i692 i693 i694 i695 i696 i697 i698 i699 i700 i701 i702 i703 i704 i705 i706 i707 i708 i709 i710 i711 i712 i713 i714 i715 i716 i717 i718 i719 i720 i721 i722 i723 i724 i725 i726 i727 i728 i729 i730 i731 i732 i733 i734 i735 i736 i737 i738 i739 i740 i741 i742 i743 i744 i745 i746 i747 i748 i749 i750 i751 i752 i753 i754 i755 i756 i757 i758 i759 i760 i761 i762 i763 i764 i765 i766 i767 i768 i769 i770 i771 i772 i773 i774 i775 i776 i777 i778 i779 i780 i781 i782 i783 i784 i785 i786 i787 i788 i789 i790 i791 i792 i793 i794 i795 i796 i797 i798 i799 i800 i801 i802 i803 i804 i805 i806 i807 i808 i809 i810 i811 i812 i813 i814 i815 i816 i817 i818 i819 i820 i821 i822 i823 i824 i825 i826 i827 i828 i829 i830 i831 i832 i833 i834 i835 i836 i837 i838 i839 i840 i841 i842 i843 i844 i845 i846 i847 i848 i849 i850 i851 i852 i853 i854 i855 i856 i857 i858 i859 i860 i861 i862 i863 i864 i865 i866 i867 i868 i869 i870 i871 i872 i873 i874 i875 i876 i877 i878 i879 i880 i881 i882 i883 i884 i885 i886 i887 i888 i889 i890 i891 i892 i893 i894 i895 i896 i897 i898 i899 i900 i901 i902 i903 i904 i905 i906 i907 i908 i909 i910 i911 i912 i913 i914 i915 i916 i917 i918 i919 i920 i921 i922 i923 i924 i925 i926 i927 i928 i929 i930 i931 i932 i933 i934 i935 i936 i937 i938 i939 i940 i941 i942 i943 i944 i945 i946 i947 i948 i949 i950 i951 i952 i953 i954 i955 i956 i957 i958 i959 i960 i961 i962 i963 i964 i965 i966 i967 i968 i969 i970 i971 i972 i973 i974 i975 i976 i977 i978 i979 i980 i981 i982 i983 i984 i985 i986 i987 i988 i989 i990 i991 i992 i993 i994 i995 i996 i997 i998 i999 i1000 b
+0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+UPDATE federated.t1 SET i50=20;
+SELECT * FROM federated.t1;
+i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20 i21 i22 i23 i24 i25 i26 i27 i28 i29 i30 i31 i32 i33 i34 i35 i36 i37 i38 i39 i40 i41 i42 i43 i44 i45 i46 i47 i48 i49 i50 i51 i52 i53 i54 i55 i56 i57 i58 i59 i60 i61 i62 i63 i64 i65 i66 i67 i68 i69 i70 i71 i72 i73 i74 i75 i76 i77 i78 i79 i80 i81 i82 i83 i84 i85 i86 i87 i88 i89 i90 i91 i92 i93 i94 i95 i96 i97 i98 i99 i100 i101 i102 i103 i104 i105 i106 i107 i108 i109 i110 i111 i112 i113 i114 i115 i116 i117 i118 i119 i120 i121 i122 i123 i124 i125 i126 i127 i128 i129 i130 i131 i132 i133 i134 i135 i136 i137 i138 i139 i140 i141 i142 i143 i144 i145 i146 i147 i148 i149 i150 i151 i152 i153 i154 i155 i156 i157 i158 i159 i160 i161 i162 i163 i164 i165 i166 i167 i168 i169 i170 i171 i172 i173 i174 i175 i176 i177 i178 i179 i180 i181 i182 i183 i184 i185 i186 i187 i188 i189 i190 i191 i192 i193 i194 i195 i196 i197 i198 i199 i200 i201 i202 i203 i204 i205 i206 i207 i208 i209 i210 i211 i212 i213 i214 i215 i216 i217 i218 i219 i220 i221 i222 i223 i224 i225 i226 i227 i228 i229 i230 i231 i232 i233 i234 i235 i236 i237 i238 i239 i240 i241 i242 i243 i244 i245 i246 i247 i248 i249 i250 i251 i252 i253 i254 i255 i256 i257 i258 i259 i260 i261 i262 i263 i264 i265 i266 i267 i268 i269 i270 i271 i272 i273 i274 i275 i276 i277 i278 i279 i280 i281 i282 i283 i284 i285 i286 i287 i288 i289 i290 i291 i292 i293 i294 i295 i296 i297 i298 i299 i300 i301 i302 i303 i304 i305 i306 i307 i308 i309 i310 i311 i312 i313 i314 i315 i316 i317 i318 i319 i320 i321 i322 i323 i324 i325 i326 i327 i328 i329 i330 i331 i332 i333 i334 i335 i336 i337 i338 i339 i340 i341 i342 i343 i344 i345 i346 i347 i348 i349 i350 i351 i352 i353 i354 i355 i356 i357 i358 i359 i360 i361 i362 i363 i364 i365 i366 i367 i368 i369 i370 i371 i372 i373 i374 i375 i376 i377 i378 i379 i380 i381 i382 i383 i384 i385 i386 i387 i388 i389 i390 i391 i392 i393 i394 i395 i396 i397 i398 i399 i400 i401 i402 i403 i404 i405 i406 i407 i408 i409 i410 i411 i412 i413 i414 i415 i416 i417 i418 i419 i420 i421 i422 i423 i424 i425 i426 i427 i428 i429 i430 i431 i432 i433 i434 i435 i436 i437 i438 i439 i440 i441 i442 i443 i444 i445 i446 i447 i448 i449 i450 i451 i452 i453 i454 i455 i456 i457 i458 i459 i460 i461 i462 i463 i464 i465 i466 i467 i468 i469 i470 i471 i472 i473 i474 i475 i476 i477 i478 i479 i480 i481 i482 i483 i484 i485 i486 i487 i488 i489 i490 i491 i492 i493 i494 i495 i496 i497 i498 i499 i500 i501 i502 i503 i504 i505 i506 i507 i508 i509 i510 i511 i512 i513 i514 i515 i516 i517 i518 i519 i520 i521 i522 i523 i524 i525 i526 i527 i528 i529 i530 i531 i532 i533 i534 i535 i536 i537 i538 i539 i540 i541 i542 i543 i544 i545 i546 i547 i548 i549 i550 i551 i552 i553 i554 i555 i556 i557 i558 i559 i560 i561 i562 i563 i564 i565 i566 i567 i568 i569 i570 i571 i572 i573 i574 i575 i576 i577 i578 i579 i580 i581 i582 i583 i584 i585 i586 i587 i588 i589 i590 i591 i592 i593 i594 i595 i596 i597 i598 i599 i600 i601 i602 i603 i604 i605 i606 i607 i608 i609 i610 i611 i612 i613 i614 i615 i616 i617 i618 i619 i620 i621 i622 i623 i624 i625 i626 i627 i628 i629 i630 i631 i632 i633 i634 i635 i636 i637 i638 i639 i640 i641 i642 i643 i644 i645 i646 i647 i648 i649 i650 i651 i652 i653 i654 i655 i656 i657 i658 i659 i660 i661 i662 i663 i664 i665 i666 i667 i668 i669 i670 i671 i672 i673 i674 i675 i676 i677 i678 i679 i680 i681 i682 i683 i684 i685 i686 i687 i688 i689 i690 i691 i692 i693 i694 i695 i696 i697 i698 i699 i700 i701 i702 i703 i704 i705 i706 i707 i708 i709 i710 i711 i712 i713 i714 i715 i716 i717 i718 i719 i720 i721 i722 i723 i724 i725 i726 i727 i728 i729 i730 i731 i732 i733 i734 i735 i736 i737 i738 i739 i740 i741 i742 i743 i744 i745 i746 i747 i748 i749 i750 i751 i752 i753 i754 i755 i756 i757 i758 i759 i760 i761 i762 i763 i764 i765 i766 i767 i768 i769 i770 i771 i772 i773 i774 i775 i776 i777 i778 i779 i780 i781 i782 i783 i784 i785 i786 i787 i788 i789 i790 i791 i792 i793 i794 i795 i796 i797 i798 i799 i800 i801 i802 i803 i804 i805 i806 i807 i808 i809 i810 i811 i812 i813 i814 i815 i816 i817 i818 i819 i820 i821 i822 i823 i824 i825 i826 i827 i828 i829 i830 i831 i832 i833 i834 i835 i836 i837 i838 i839 i840 i841 i842 i843 i844 i845 i846 i847 i848 i849 i850 i851 i852 i853 i854 i855 i856 i857 i858 i859 i860 i861 i862 i863 i864 i865 i866 i867 i868 i869 i870 i871 i872 i873 i874 i875 i876 i877 i878 i879 i880 i881 i882 i883 i884 i885 i886 i887 i888 i889 i890 i891 i892 i893 i894 i895 i896 i897 i898 i899 i900 i901 i902 i903 i904 i905 i906 i907 i908 i909 i910 i911 i912 i913 i914 i915 i916 i917 i918 i919 i920 i921 i922 i923 i924 i925 i926 i927 i928 i929 i930 i931 i932 i933 i934 i935 i936 i937 i938 i939 i940 i941 i942 i943 i944 i945 i946 i947 i948 i949 i950 i951 i952 i953 i954 i955 i956 i957 i958 i959 i960 i961 i962 i963 i964 i965 i966 i967 i968 i969 i970 i971 i972 i973 i974 i975 i976 i977 i978 i979 i980 i981 i982 i983 i984 i985 i986 i987 i988 i989 i990 i991 i992 i993 i994 i995 i996 i997 i998 i999 i1000 b
+0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 20 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+DELETE FROM federated.t1 WHERE i51=20;
+SELECT * FROM federated.t1;
+i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20 i21 i22 i23 i24 i25 i26 i27 i28 i29 i30 i31 i32 i33 i34 i35 i36 i37 i38 i39 i40 i41 i42 i43 i44 i45 i46 i47 i48 i49 i50 i51 i52 i53 i54 i55 i56 i57 i58 i59 i60 i61 i62 i63 i64 i65 i66 i67 i68 i69 i70 i71 i72 i73 i74 i75 i76 i77 i78 i79 i80 i81 i82 i83 i84 i85 i86 i87 i88 i89 i90 i91 i92 i93 i94 i95 i96 i97 i98 i99 i100 i101 i102 i103 i104 i105 i106 i107 i108 i109 i110 i111 i112 i113 i114 i115 i116 i117 i118 i119 i120 i121 i122 i123 i124 i125 i126 i127 i128 i129 i130 i131 i132 i133 i134 i135 i136 i137 i138 i139 i140 i141 i142 i143 i144 i145 i146 i147 i148 i149 i150 i151 i152 i153 i154 i155 i156 i157 i158 i159 i160 i161 i162 i163 i164 i165 i166 i167 i168 i169 i170 i171 i172 i173 i174 i175 i176 i177 i178 i179 i180 i181 i182 i183 i184 i185 i186 i187 i188 i189 i190 i191 i192 i193 i194 i195 i196 i197 i198 i199 i200 i201 i202 i203 i204 i205 i206 i207 i208 i209 i210 i211 i212 i213 i214 i215 i216 i217 i218 i219 i220 i221 i222 i223 i224 i225 i226 i227 i228 i229 i230 i231 i232 i233 i234 i235 i236 i237 i238 i239 i240 i241 i242 i243 i244 i245 i246 i247 i248 i249 i250 i251 i252 i253 i254 i255 i256 i257 i258 i259 i260 i261 i262 i263 i264 i265 i266 i267 i268 i269 i270 i271 i272 i273 i274 i275 i276 i277 i278 i279 i280 i281 i282 i283 i284 i285 i286 i287 i288 i289 i290 i291 i292 i293 i294 i295 i296 i297 i298 i299 i300 i301 i302 i303 i304 i305 i306 i307 i308 i309 i310 i311 i312 i313 i314 i315 i316 i317 i318 i319 i320 i321 i322 i323 i324 i325 i326 i327 i328 i329 i330 i331 i332 i333 i334 i335 i336 i337 i338 i339 i340 i341 i342 i343 i344 i345 i346 i347 i348 i349 i350 i351 i352 i353 i354 i355 i356 i357 i358 i359 i360 i361 i362 i363 i364 i365 i366 i367 i368 i369 i370 i371 i372 i373 i374 i375 i376 i377 i378 i379 i380 i381 i382 i383 i384 i385 i386 i387 i388 i389 i390 i391 i392 i393 i394 i395 i396 i397 i398 i399 i400 i401 i402 i403 i404 i405 i406 i407 i408 i409 i410 i411 i412 i413 i414 i415 i416 i417 i418 i419 i420 i421 i422 i423 i424 i425 i426 i427 i428 i429 i430 i431 i432 i433 i434 i435 i436 i437 i438 i439 i440 i441 i442 i443 i444 i445 i446 i447 i448 i449 i450 i451 i452 i453 i454 i455 i456 i457 i458 i459 i460 i461 i462 i463 i464 i465 i466 i467 i468 i469 i470 i471 i472 i473 i474 i475 i476 i477 i478 i479 i480 i481 i482 i483 i484 i485 i486 i487 i488 i489 i490 i491 i492 i493 i494 i495 i496 i497 i498 i499 i500 i501 i502 i503 i504 i505 i506 i507 i508 i509 i510 i511 i512 i513 i514 i515 i516 i517 i518 i519 i520 i521 i522 i523 i524 i525 i526 i527 i528 i529 i530 i531 i532 i533 i534 i535 i536 i537 i538 i539 i540 i541 i542 i543 i544 i545 i546 i547 i548 i549 i550 i551 i552 i553 i554 i555 i556 i557 i558 i559 i560 i561 i562 i563 i564 i565 i566 i567 i568 i569 i570 i571 i572 i573 i574 i575 i576 i577 i578 i579 i580 i581 i582 i583 i584 i585 i586 i587 i588 i589 i590 i591 i592 i593 i594 i595 i596 i597 i598 i599 i600 i601 i602 i603 i604 i605 i606 i607 i608 i609 i610 i611 i612 i613 i614 i615 i616 i617 i618 i619 i620 i621 i622 i623 i624 i625 i626 i627 i628 i629 i630 i631 i632 i633 i634 i635 i636 i637 i638 i639 i640 i641 i642 i643 i644 i645 i646 i647 i648 i649 i650 i651 i652 i653 i654 i655 i656 i657 i658 i659 i660 i661 i662 i663 i664 i665 i666 i667 i668 i669 i670 i671 i672 i673 i674 i675 i676 i677 i678 i679 i680 i681 i682 i683 i684 i685 i686 i687 i688 i689 i690 i691 i692 i693 i694 i695 i696 i697 i698 i699 i700 i701 i702 i703 i704 i705 i706 i707 i708 i709 i710 i711 i712 i713 i714 i715 i716 i717 i718 i719 i720 i721 i722 i723 i724 i725 i726 i727 i728 i729 i730 i731 i732 i733 i734 i735 i736 i737 i738 i739 i740 i741 i742 i743 i744 i745 i746 i747 i748 i749 i750 i751 i752 i753 i754 i755 i756 i757 i758 i759 i760 i761 i762 i763 i764 i765 i766 i767 i768 i769 i770 i771 i772 i773 i774 i775 i776 i777 i778 i779 i780 i781 i782 i783 i784 i785 i786 i787 i788 i789 i790 i791 i792 i793 i794 i795 i796 i797 i798 i799 i800 i801 i802 i803 i804 i805 i806 i807 i808 i809 i810 i811 i812 i813 i814 i815 i816 i817 i818 i819 i820 i821 i822 i823 i824 i825 i826 i827 i828 i829 i830 i831 i832 i833 i834 i835 i836 i837 i838 i839 i840 i841 i842 i843 i844 i845 i846 i847 i848 i849 i850 i851 i852 i853 i854 i855 i856 i857 i858 i859 i860 i861 i862 i863 i864 i865 i866 i867 i868 i869 i870 i871 i872 i873 i874 i875 i876 i877 i878 i879 i880 i881 i882 i883 i884 i885 i886 i887 i888 i889 i890 i891 i892 i893 i894 i895 i896 i897 i898 i899 i900 i901 i902 i903 i904 i905 i906 i907 i908 i909 i910 i911 i912 i913 i914 i915 i916 i917 i918 i919 i920 i921 i922 i923 i924 i925 i926 i927 i928 i929 i930 i931 i932 i933 i934 i935 i936 i937 i938 i939 i940 i941 i942 i943 i944 i945 i946 i947 i948 i949 i950 i951 i952 i953 i954 i955 i956 i957 i958 i959 i960 i961 i962 i963 i964 i965 i966 i967 i968 i969 i970 i971 i972 i973 i974 i975 i976 i977 i978 i979 i980 i981 i982 i983 i984 i985 i986 i987 i988 i989 i990 i991 i992 i993 i994 i995 i996 i997 i998 i999 i1000 b
+0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 20 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+DELETE FROM federated.t1 WHERE i50=20;
+SELECT * FROM federated.t1;
+i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20 i21 i22 i23 i24 i25 i26 i27 i28 i29 i30 i31 i32 i33 i34 i35 i36 i37 i38 i39 i40 i41 i42 i43 i44 i45 i46 i47 i48 i49 i50 i51 i52 i53 i54 i55 i56 i57 i58 i59 i60 i61 i62 i63 i64 i65 i66 i67 i68 i69 i70 i71 i72 i73 i74 i75 i76 i77 i78 i79 i80 i81 i82 i83 i84 i85 i86 i87 i88 i89 i90 i91 i92 i93 i94 i95 i96 i97 i98 i99 i100 i101 i102 i103 i104 i105 i106 i107 i108 i109 i110 i111 i112 i113 i114 i115 i116 i117 i118 i119 i120 i121 i122 i123 i124 i125 i126 i127 i128 i129 i130 i131 i132 i133 i134 i135 i136 i137 i138 i139 i140 i141 i142 i143 i144 i145 i146 i147 i148 i149 i150 i151 i152 i153 i154 i155 i156 i157 i158 i159 i160 i161 i162 i163 i164 i165 i166 i167 i168 i169 i170 i171 i172 i173 i174 i175 i176 i177 i178 i179 i180 i181 i182 i183 i184 i185 i186 i187 i188 i189 i190 i191 i192 i193 i194 i195 i196 i197 i198 i199 i200 i201 i202 i203 i204 i205 i206 i207 i208 i209 i210 i211 i212 i213 i214 i215 i216 i217 i218 i219 i220 i221 i222 i223 i224 i225 i226 i227 i228 i229 i230 i231 i232 i233 i234 i235 i236 i237 i238 i239 i240 i241 i242 i243 i244 i245 i246 i247 i248 i249 i250 i251 i252 i253 i254 i255 i256 i257 i258 i259 i260 i261 i262 i263 i264 i265 i266 i267 i268 i269 i270 i271 i272 i273 i274 i275 i276 i277 i278 i279 i280 i281 i282 i283 i284 i285 i286 i287 i288 i289 i290 i291 i292 i293 i294 i295 i296 i297 i298 i299 i300 i301 i302 i303 i304 i305 i306 i307 i308 i309 i310 i311 i312 i313 i314 i315 i316 i317 i318 i319 i320 i321 i322 i323 i324 i325 i326 i327 i328 i329 i330 i331 i332 i333 i334 i335 i336 i337 i338 i339 i340 i341 i342 i343 i344 i345 i346 i347 i348 i349 i350 i351 i352 i353 i354 i355 i356 i357 i358 i359 i360 i361 i362 i363 i364 i365 i366 i367 i368 i369 i370 i371 i372 i373 i374 i375 i376 i377 i378 i379 i380 i381 i382 i383 i384 i385 i386 i387 i388 i389 i390 i391 i392 i393 i394 i395 i396 i397 i398 i399 i400 i401 i402 i403 i404 i405 i406 i407 i408 i409 i410 i411 i412 i413 i414 i415 i416 i417 i418 i419 i420 i421 i422 i423 i424 i425 i426 i427 i428 i429 i430 i431 i432 i433 i434 i435 i436 i437 i438 i439 i440 i441 i442 i443 i444 i445 i446 i447 i448 i449 i450 i451 i452 i453 i454 i455 i456 i457 i458 i459 i460 i461 i462 i463 i464 i465 i466 i467 i468 i469 i470 i471 i472 i473 i474 i475 i476 i477 i478 i479 i480 i481 i482 i483 i484 i485 i486 i487 i488 i489 i490 i491 i492 i493 i494 i495 i496 i497 i498 i499 i500 i501 i502 i503 i504 i505 i506 i507 i508 i509 i510 i511 i512 i513 i514 i515 i516 i517 i518 i519 i520 i521 i522 i523 i524 i525 i526 i527 i528 i529 i530 i531 i532 i533 i534 i535 i536 i537 i538 i539 i540 i541 i542 i543 i544 i545 i546 i547 i548 i549 i550 i551 i552 i553 i554 i555 i556 i557 i558 i559 i560 i561 i562 i563 i564 i565 i566 i567 i568 i569 i570 i571 i572 i573 i574 i575 i576 i577 i578 i579 i580 i581 i582 i583 i584 i585 i586 i587 i588 i589 i590 i591 i592 i593 i594 i595 i596 i597 i598 i599 i600 i601 i602 i603 i604 i605 i606 i607 i608 i609 i610 i611 i612 i613 i614 i615 i616 i617 i618 i619 i620 i621 i622 i623 i624 i625 i626 i627 i628 i629 i630 i631 i632 i633 i634 i635 i636 i637 i638 i639 i640 i641 i642 i643 i644 i645 i646 i647 i648 i649 i650 i651 i652 i653 i654 i655 i656 i657 i658 i659 i660 i661 i662 i663 i664 i665 i666 i667 i668 i669 i670 i671 i672 i673 i674 i675 i676 i677 i678 i679 i680 i681 i682 i683 i684 i685 i686 i687 i688 i689 i690 i691 i692 i693 i694 i695 i696 i697 i698 i699 i700 i701 i702 i703 i704 i705 i706 i707 i708 i709 i710 i711 i712 i713 i714 i715 i716 i717 i718 i719 i720 i721 i722 i723 i724 i725 i726 i727 i728 i729 i730 i731 i732 i733 i734 i735 i736 i737 i738 i739 i740 i741 i742 i743 i744 i745 i746 i747 i748 i749 i750 i751 i752 i753 i754 i755 i756 i757 i758 i759 i760 i761 i762 i763 i764 i765 i766 i767 i768 i769 i770 i771 i772 i773 i774 i775 i776 i777 i778 i779 i780 i781 i782 i783 i784 i785 i786 i787 i788 i789 i790 i791 i792 i793 i794 i795 i796 i797 i798 i799 i800 i801 i802 i803 i804 i805 i806 i807 i808 i809 i810 i811 i812 i813 i814 i815 i816 i817 i818 i819 i820 i821 i822 i823 i824 i825 i826 i827 i828 i829 i830 i831 i832 i833 i834 i835 i836 i837 i838 i839 i840 i841 i842 i843 i844 i845 i846 i847 i848 i849 i850 i851 i852 i853 i854 i855 i856 i857 i858 i859 i860 i861 i862 i863 i864 i865 i866 i867 i868 i869 i870 i871 i872 i873 i874 i875 i876 i877 i878 i879 i880 i881 i882 i883 i884 i885 i886 i887 i888 i889 i890 i891 i892 i893 i894 i895 i896 i897 i898 i899 i900 i901 i902 i903 i904 i905 i906 i907 i908 i909 i910 i911 i912 i913 i914 i915 i916 i917 i918 i919 i920 i921 i922 i923 i924 i925 i926 i927 i928 i929 i930 i931 i932 i933 i934 i935 i936 i937 i938 i939 i940 i941 i942 i943 i944 i945 i946 i947 i948 i949 i950 i951 i952 i953 i954 i955 i956 i957 i958 i959 i960 i961 i962 i963 i964 i965 i966 i967 i968 i969 i970 i971 i972 i973 i974 i975 i976 i977 i978 i979 i980 i981 i982 i983 i984 i985 i986 i987 i988 i989 i990 i991 i992 i993 i994 i995 i996 i997 i998 i999 i1000 b
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (id int NOT NULL auto_increment, code char(20) NOT NULL, fileguts blob NOT NULL, creation_date datetime, entered_time datetime default '2004-04-04 04:04:04', PRIMARY KEY(id), index(code), index(fileguts(10))) DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+id int NOT NULL auto_increment,
+code char(20) NOT NULL,
+fileguts blob NOT NULL,
+creation_date datetime,
+entered_time datetime default '2004-04-04 04:04:04',
+PRIMARY KEY(id),
+index(code),
+index(fileguts(10)))
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('ASDFWERQWETWETAWETA', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2003-03-03 03:03:03');
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04');
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04');
+SELECT * FROM federated.t1;
+id code fileguts creation_date entered_time
+1 ASDFWERQWETWETAWETA *()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[ 2003-03-03 03:03:03 2004-04-04 04:04:04
+2 DEUEUEUEUEUEUEUEUEU *()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[ 2004-04-04 04:04:04 2004-04-04 04:04:04
+3 DEUEUEUEUEUEUEUEUEU jimbob 2004-04-04 04:04:04 2004-04-04 04:04:04
+SELECT * FROM federated.t1 WHERE fileguts = 'jimbob';
+id code fileguts creation_date entered_time
+3 DEUEUEUEUEUEUEUEUEU jimbob 2004-04-04 04:04:04 2004-04-04 04:04:04
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (`a` BLOB);
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`a` BLOB)
+ENGINE="FEDERATED"
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 VALUES (0x00);
+INSERT INTO federated.t1 VALUES (0x0001);
+INSERT INTO federated.t1 VALUES (0x0100);
+SELECT HEX(a) FROM federated.t1;
+HEX(a)
+00
+0001
+0100
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`country_id` int(20) NOT NULL DEFAULT 0,
+`name` varchar(32),
+`other` varchar(20),
+PRIMARY KEY (`id`),
+key (country_id));
+DROP TABLE IF EXISTS federated.countries;
+Warnings:
+Note 1051 Unknown table 'countries'
+CREATE TABLE federated.countries (
+`id` int(20) NOT NULL auto_increment,
+`country` varchar(32),
+PRIMARY KEY (id));
+INSERT INTO federated.countries (country) VALUES ('India');
+INSERT INTO federated.countries (country) VALUES ('Germany');
+INSERT INTO federated.countries (country) VALUES ('Italy');
+INSERT INTO federated.countries (country) VALUES ('Finland');
+INSERT INTO federated.countries (country) VALUES ('Ukraine');
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`country_id` int(20) NOT NULL DEFAULT 0,
+`name` varchar(32),
+`other` varchar(20),
+PRIMARY KEY (`id`),
+KEY (country_id) )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Kumar', 1, 11111);
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Lenz', 2, 22222);
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Marizio', 3, 33333);
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Monty', 4, 33333);
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Sanja', 5, 33333);
+SELECT federated.t1.*, federated.countries.country
+FROM federated.t1 left join federated.countries
+ON federated.t1.country_id = federated.countries.id;
+id country_id name other country
+1 1 Kumar 11111 India
+2 2 Lenz 22222 Germany
+3 3 Marizio 33333 Italy
+4 4 Monty 33333 Finland
+5 5 Sanja 33333 Ukraine
+DROP TABLE federated.countries;
+DROP TABLE IF EXISTS federated.t1;
+DROP DATABASE IF EXISTS federated;
+DROP TABLE IF EXISTS federated.t1;
+DROP DATABASE IF EXISTS federated;
diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result
index bab9b543307..306376b13c3 100644
--- a/mysql-test/r/flush.result
+++ b/mysql-test/r/flush.result
@@ -8,7 +8,7 @@ n
3
flush tables with read lock;
drop table t2;
-ERROR HY000: Table 't2' was locked with a READ lock and can't be updated
+ERROR HY000: Can't execute the query because you have a conflicting read lock
drop table t2;
unlock tables;
create database mysqltest;
diff --git a/mysql-test/r/flush_block_commit.result b/mysql-test/r/flush_block_commit.result
index 2e9f1920937..2f6aca7e24a 100644
--- a/mysql-test/r/flush_block_commit.result
+++ b/mysql-test/r/flush_block_commit.result
@@ -37,3 +37,18 @@ show create database test;
Database Create Database
test CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */
drop table t1;
+create table t1 (a int) engine=innodb;
+reset master;
+set autocommit=0;
+insert t1 values (1);
+flush tables with read lock;
+show master status;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000001 98
+ commit;
+show master status;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000001 98
+unlock tables;
+drop table t1;
+set autocommit=1;
diff --git a/mysql-test/r/flush_read_lock_kill.result b/mysql-test/r/flush_read_lock_kill.result
new file mode 100644
index 00000000000..dfdcf51457a
--- /dev/null
+++ b/mysql-test/r/flush_read_lock_kill.result
@@ -0,0 +1,9 @@
+drop table if exists t1;
+create table t1 (kill_id int);
+insert into t1 values(connection_id());
+ flush tables with read lock;
+select ((@id := kill_id) - kill_id) from t1;
+((@id := kill_id) - kill_id)
+0
+kill connection @id;
+drop table t1;
diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result
index dd5b0407eb3..34d1213d1b2 100644
--- a/mysql-test/r/fulltext.result
+++ b/mysql-test/r/fulltext.result
@@ -17,7 +17,7 @@ explain extended select * from t1 where MATCH(a,b) AGAINST ("collections");
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 fulltext a a 0 1 Using where
Warnings:
-Note 1003 select test.t1.a AS `a`,test.t1.b AS `b` from test.t1 where (match test.t1.a,test.t1.b against (_latin1'collections'))
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (match `test`.`t1`.`a`,`test`.`t1`.`b` against (_latin1'collections'))
select * from t1 where MATCH(a,b) AGAINST ("indexes");
a b
Full-text indexes are called collections
@@ -78,7 +78,7 @@ explain extended select * from t1 where MATCH(a,b) AGAINST("support -collections
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 fulltext a a 0 1 Using where
Warnings:
-Note 1003 select test.t1.a AS `a`,test.t1.b AS `b` from test.t1 where (match test.t1.a,test.t1.b against (_latin1'support -collections' in boolean mode))
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (match `test`.`t1`.`a`,`test`.`t1`.`b` against (_latin1'support -collections' in boolean mode))
select * from t1 where MATCH(a,b) AGAINST("support collections" IN BOOLEAN MODE);
a b
MySQL has now support for full-text search
@@ -130,6 +130,9 @@ a b
select * from t1 where MATCH a,b AGAINST ('"Now sUPPort"' IN BOOLEAN MODE);
a b
MySQL has now support for full-text search
+select * from t1 where MATCH a,b AGAINST ('"now support"' IN BOOLEAN MODE);
+a b
+MySQL has now support for full-text search
select * from t1 where MATCH a,b AGAINST ('"text search" "now support"' IN BOOLEAN MODE);
a b
MySQL has now support for full-text search
@@ -151,8 +154,6 @@ a b
select * from t1 where MATCH a,b AGAINST ('+collections -supp* -foobar*' IN BOOLEAN MODE);
a b
Full-text indexes are called collections
-select * from t1 where MATCH a,b AGAINST ('"xt indexes"' IN BOOLEAN MODE);
-a b
select * from t1 where MATCH a,b AGAINST('"space model' IN BOOLEAN MODE);
a b
Full-text search in MySQL implements vector space model
diff --git a/mysql-test/r/func_concat.result b/mysql-test/r/func_concat.result
index cf6fbf2da4f..0bd53b32dd7 100644
--- a/mysql-test/r/func_concat.result
+++ b/mysql-test/r/func_concat.result
@@ -63,4 +63,8 @@ a0
select 'a' union select concat('a', -0.0);
a
a
-good
+a0.0
+select 'a' union select concat('a', -0.0000);
+a
+a
+a0.0000
diff --git a/mysql-test/r/func_default.result b/mysql-test/r/func_default.result
index 2993d79a870..c7483027322 100644
--- a/mysql-test/r/func_default.result
+++ b/mysql-test/r/func_default.result
@@ -8,7 +8,7 @@ explain extended select default(str), default(strnull), default(intg), default(r
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
Warnings:
-Note 1003 select default(test.t1.str) AS `default(str)`,default(test.t1.strnull) AS `default(strnull)`,default(test.t1.intg) AS `default(intg)`,default(test.t1.rel) AS `default(rel)` from test.t1
+Note 1003 select default(`test`.`t1`.`str`) AS `default(str)`,default(`test`.`t1`.`strnull`) AS `default(strnull)`,default(`test`.`t1`.`intg`) AS `default(intg)`,default(`test`.`t1`.`rel`) AS `default(rel)` from `test`.`t1`
select * from t1 where str <> default(str);
str strnull intg rel
0 0
diff --git a/mysql-test/r/func_equal.result b/mysql-test/r/func_equal.result
index 352b76f2744..fe5e5b1b371 100644
--- a/mysql-test/r/func_equal.result
+++ b/mysql-test/r/func_equal.result
@@ -1,7 +1,7 @@
drop table if exists t1,t2;
-select 0<=>0,0.0<=>0.0,"A"<=>"A",NULL<=>NULL;
-0<=>0 0.0<=>0.0 "A"<=>"A" NULL<=>NULL
-1 1 1 1
+select 0<=>0,0.0<=>0.0,0E0=0E0,"A"<=>"A",NULL<=>NULL;
+0<=>0 0.0<=>0.0 0E0=0E0 "A"<=>"A" NULL<=>NULL
+1 1 1 1 1
select 1<=>0,0<=>NULL,NULL<=>0;
1<=>0 0<=>NULL NULL<=>0
0 0 0
@@ -11,6 +11,12 @@ select 1.0<=>0.0,0.0<=>NULL,NULL<=>0.0;
select "A"<=>"B","A"<=>NULL,NULL<=>"A";
"A"<=>"B" "A"<=>NULL NULL<=>"A"
0 0 0
+select 0<=>0.0, 0.0<=>0E0, 0E0<=>"0", 10.0<=>1E1, 10<=>10.0, 10<=>1E1;
+0<=>0.0 0.0<=>0E0 0E0<=>"0" 10.0<=>1E1 10<=>10.0 10<=>1E1
+1 1 1 1 1 1
+select 1.0<=>0E1,10<=>NULL,NULL<=>0.0, NULL<=>0E0;
+1.0<=>0E1 10<=>NULL NULL<=>0.0 NULL<=>0E0
+0 0 0 0
create table t1 (id int, value int);
create table t2 (id int, value int);
insert into t1 values (1,null);
diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result
index c1ac1c084df..09ff3fc5a6e 100644
--- a/mysql-test/r/func_gconcat.result
+++ b/mysql-test/r/func_gconcat.result
@@ -18,7 +18,7 @@ explain extended select grp,group_concat(c) from t1 group by grp;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 9 Using filesort
Warnings:
-Note 1003 select test.t1.grp AS `grp`,group_concat(test.t1.c separator ',') AS `group_concat(c)` from test.t1 group by test.t1.grp
+Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(`test`.`t1`.`c` separator ',') AS `group_concat(c)` from `test`.`t1` group by `test`.`t1`.`grp`
select grp,group_concat(a,c) from t1 group by grp;
grp group_concat(a,c)
1 1a
@@ -93,7 +93,7 @@ explain extended select grp,group_concat(distinct c order by c desc) from t1 gro
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 9 Using filesort
Warnings:
-Note 1003 select test.t1.grp AS `grp`,group_concat(distinct test.t1.c order by test.t1.c separator ',') AS `group_concat(distinct c order by c desc)` from test.t1 group by test.t1.grp
+Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(distinct `test`.`t1`.`c` order by `test`.`t1`.`c` separator ',') AS `group_concat(distinct c order by c desc)` from `test`.`t1` group by `test`.`t1`.`grp`
select grp,group_concat(c order by c separator ",") from t1 group by grp;
grp group_concat(c order by c separator ",")
1 a
@@ -113,7 +113,7 @@ explain extended select grp,group_concat(distinct c order by c separator ",") fr
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 9 Using filesort
Warnings:
-Note 1003 select test.t1.grp AS `grp`,group_concat(distinct test.t1.c order by test.t1.c separator ',') AS `group_concat(distinct c order by c separator ",")` from test.t1 group by test.t1.grp
+Note 1003 select `test`.`t1`.`grp` AS `grp`,group_concat(distinct `test`.`t1`.`c` order by `test`.`t1`.`c` separator ',') AS `group_concat(distinct c order by c separator ",")` from `test`.`t1` group by `test`.`t1`.`grp`
select grp,group_concat(distinct c order by c desc separator ",") from t1 group by grp;
grp group_concat(distinct c order by c desc separator ",")
1 a
@@ -166,7 +166,7 @@ set group_concat_max_len = 1024;
select group_concat(sum(a)) from t1 group by grp;
ERROR HY000: Invalid use of group function
select grp,group_concat(c order by 2) from t1 group by grp;
-ERROR 42S22: Unknown column '2' in 'group statement'
+ERROR 42S22: Unknown column '2' in 'order clause'
drop table t1;
create table t1 ( URL_ID int(11), URL varchar(80));
create table t2 ( REQ_ID int(11), URL_ID int(11));
@@ -462,6 +462,13 @@ SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL;
gc
NULL
DROP TABLE t1;
+create table t1 (a char(3), b char(20), primary key (a, b));
+insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English');
+select group_concat(a) from t1 group by b;
+group_concat(a)
+ABW
+ABW
+drop table t1;
create table r2 (a int, b int);
insert into r2 values (1,1), (2,2);
select b x, (select group_concat(x) from r2) from r2;
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result
index 2fb18ca92c7..1cf1a19056b 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -90,6 +90,26 @@ id avg(rating)
1 3.0000
2 NULL
3 2.0000
+select sql_small_result t2.id, avg(rating) from t2 group by t2.id;
+id avg(rating)
+1 3.0000
+2 NULL
+3 2.0000
+select sql_big_result t2.id, avg(rating) from t2 group by t2.id;
+id avg(rating)
+1 3.0000
+2 NULL
+3 2.0000
+select sql_small_result t2.id, avg(rating+0.0e0) from t2 group by t2.id;
+id avg(rating+0.0e0)
+1 3
+2 NULL
+3 2
+select sql_big_result t2.id, avg(rating+0.0e0) from t2 group by t2.id;
+id avg(rating+0.0e0)
+1 3
+2 NULL
+3 2
drop table t1,t2;
create table t1 (a smallint(6) primary key, c char(10), b text);
INSERT INTO t1 VALUES (1,'1','1');
@@ -183,12 +203,12 @@ insert into t2 values('BBB', 20, 1.0);
select t1.a1, t1.a2, t2.a1, t2.a2 from t1,t2;
a1 a2 a1 a2
10 aaa AAA 10
-10 NULL AAA 10
-10 bbb AAA 10
-20 zzz AAA 10
10 aaa BBB 20
+10 NULL AAA 10
10 NULL BBB 20
+10 bbb AAA 10
10 bbb BBB 20
+20 zzz AAA 10
20 zzz BBB 20
select max(t1.a1), max(t2.a1) from t1, t2 where t2.a2=9;
max(t1.a1) max(t2.a1)
@@ -265,7 +285,7 @@ explain extended select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
Warnings:
-Note 1003 select sql_big_result test.t1.a AS `a`,count(test.t1.b) AS `count(b)`,sum(test.t1.b) AS `sum(b)`,avg(test.t1.b) AS `avg(b)`,std(test.t1.b) AS `std(b)`,min(test.t1.b) AS `min(b)`,max(test.t1.b) AS `max(b)`,bit_and(test.t1.b) AS `bit_and(b)`,bit_or(test.t1.b) AS `bit_or(b)`,bit_xor(test.t1.b) AS `bit_xor(b)` from test.t1 group by test.t1.a
+Note 1003 select sql_big_result `test`.`t1`.`a` AS `a`,count(`test`.`t1`.`b`) AS `count(b)`,sum(`test`.`t1`.`b`) AS `sum(b)`,avg(`test`.`t1`.`b`) AS `avg(b)`,std(`test`.`t1`.`b`) AS `std(b)`,min(`test`.`t1`.`b`) AS `min(b)`,max(`test`.`t1`.`b`) AS `max(b)`,bit_and(`test`.`t1`.`b`) AS `bit_and(b)`,bit_or(`test`.`t1`.`b`) AS `bit_or(b)`,bit_xor(`test`.`t1`.`b`) AS `bit_xor(b)` from `test`.`t1` group by `test`.`t1`.`a`
drop table t1;
create table t1 (col int);
insert into t1 values (-1), (-2), (-3);
@@ -315,12 +335,14 @@ insert into t1 values('GTM',3,'DAL',0.070,date'1977-09-23');
insert into t1 values('SSJ',null,'CHI',null,date'1974-03-19');
insert into t1 values('KKK',3,'ATL',null,null);
insert into t1 values('XXX',null,'MIN',null,null);
+insert into t1 values('WWW',1,'LED',null,null);
insert into t2 values('TKF','Seattle','WA','AME');
insert into t2 values('LCC','Los Angeles','CA','TWU');
insert into t2 values('DEN','Denver','CO','BDL');
insert into t2 values('SDC','San Diego','CA','TWU');
insert into t2 values('NOL','New Orleans','LA','GTM');
insert into t2 values('LAK','Los Angeles','CA','TWU');
+insert into t2 values('AAA','AAA','AA','AME');
select * from t1;
a1 a2 a3 a4 a5
AME 0 SEA 0.1 1942-02-19
@@ -337,6 +359,7 @@ GTM 3 DAL 0.07 1977-09-23
SSJ NULL CHI NULL 1974-03-19
KKK 3 ATL NULL NULL
XXX NULL MIN NULL NULL
+WWW 1 LED NULL NULL
select * from t2;
a1 a2 a3 a4
TKF Seattle WA AME
@@ -345,6 +368,7 @@ DEN Denver CO BDL
SDC San Diego CA TWU
NOL New Orleans LA GTM
LAK Los Angeles CA TWU
+AAA AAA AA AME
explain
select min(a1) from t1;
id select_type table type possible_keys key key_len ref rows Extra
@@ -474,7 +498,7 @@ CHI Los Angeles
explain
select max(a3) from t1 where a2 is null and a2 = 2;
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
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
select max(a3) from t1 where a2 is null and a2 = 2;
max(a3)
NULL
@@ -572,15 +596,15 @@ AME AME
explain
select min(a1) from t1 where a1 > 'KKK' or a1 < 'XXX';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range PRIMARY PRIMARY 0 NULL 15 Using where; Using index
+1 SIMPLE t1 index PRIMARY PRIMARY 3 NULL 15 Using where; Using index
explain
select min(a1) from t1 where a1 != 'KKK';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range PRIMARY PRIMARY 3 NULL 14 Using where; Using index
+1 SIMPLE t1 index PRIMARY PRIMARY 3 NULL 15 Using where; Using index
explain
select max(a3) from t1 where a2 < 2 and a3 < 'SEA';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range k1 k1 3 NULL 5 Using where; Using index
+1 SIMPLE t1 range k1 k1 3 NULL 6 Using where; Using index
explain
select max(t1.a3), min(t2.a2) from t1, t2 where t1.a2 = 2 and t1.a3 < 'MIN' and t2.a3 > 'CA';
id select_type table type possible_keys key key_len ref rows Extra
@@ -589,40 +613,40 @@ id select_type table type possible_keys key key_len ref rows Extra
explain
select min(a4 - 0.01) from t1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL k2 12 NULL 14 Using index
+1 SIMPLE t1 index NULL k2 12 NULL 15 Using index
explain
select max(a4 + 0.01) from t1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL k2 12 NULL 14 Using index
+1 SIMPLE t1 index NULL k2 12 NULL 15 Using index
explain
select min(a3) from t1 where (a2 +1 ) is null;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL k1 7 NULL 14 Using where; Using index
+1 SIMPLE t1 index NULL k1 7 NULL 15 Using where; Using index
explain
select min(a3) from t1 where (a2 + 1) = 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL k1 7 NULL 14 Using where; Using index
+1 SIMPLE t1 index NULL k1 7 NULL 15 Using where; Using index
explain
select min(a3) from t1 where 2 = (a2 + 1);
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL k1 7 NULL 14 Using where; Using index
+1 SIMPLE t1 index NULL k1 7 NULL 15 Using where; Using index
explain
select min(a2) from t1 where a2 < 2 * a2 - 8;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL k1 7 NULL 14 Using where; Using index
+1 SIMPLE t1 index NULL k1 7 NULL 15 Using where; Using index
explain
select min(a1) from t1 where a1 between a3 and 'KKK';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 14 Using where
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 15 Using where
explain
select min(a4) from t1 where (a4 + 0.01) between 0.07 and 0.08;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL k2 12 NULL 14 Using where; Using index
+1 SIMPLE t1 index NULL k2 12 NULL 15 Using where; Using index
explain
select concat(min(t1.a1),min(t2.a4)) from t1, t2 where t2.a4 <> 'AME';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range k2 k2 4 NULL 6 Using where; Using index
-1 SIMPLE t1 index NULL PRIMARY 3 NULL 14 Using index
+1 SIMPLE t1 index NULL PRIMARY 3 NULL 15 Using index
drop table t1, t2;
create table t1 (USR_ID integer not null, MAX_REQ integer not null, constraint PK_SEA_USER primary key (USR_ID)) engine=InnoDB;
insert into t1 values (1, 3);
@@ -645,6 +669,11 @@ select charset(max(a)), coercibility(max(a)),
charset(min(a)), coercibility(min(a)) from t1;
charset(max(a)) coercibility(max(a)) charset(min(a)) coercibility(min(a))
latin2 2 latin2 2
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(1) character set latin2 default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
create table t2 select max(a),min(a) from t1;
show create table t2;
Table Create Table
@@ -652,6 +681,13 @@ t2 CREATE TABLE `t2` (
`max(a)` char(1) character set latin2 default NULL,
`min(a)` char(1) character set latin2 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t2;
+create table t2 select concat(a) from t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `concat(a)` varchar(1) character set latin2 default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t2,t1;
create table t1 (a int);
insert into t1 values (1);
@@ -752,8 +788,73 @@ drop table t2;
create table t2 select f2 from (select now() f2 from t1) a;
show columns from t2;
Field Type Null Key Default Extra
-f2 datetime 0000-00-00 00:00:00
+f2 datetime NO 0000-00-00 00:00:00
drop table t2, t1;
+create table t2 (ff double);
+insert into t2 values (2.2);
+select cast(sum(distinct ff) as decimal(5,2)) from t2;
+cast(sum(distinct ff) as decimal(5,2))
+2.20
+select cast(sum(distinct ff) as signed) from t2;
+cast(sum(distinct ff) as signed)
+2
+select cast(variance(ff) as decimal(10,3)) from t2;
+cast(variance(ff) as decimal(10,3))
+0.000
+select cast(min(ff) as decimal(5,2)) from t2;
+cast(min(ff) as decimal(5,2))
+2.20
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select cast(sum(distinct df) as signed) from t1;
+cast(sum(distinct df) as signed)
+3
+select cast(min(df) as signed) from t1;
+cast(min(df) as signed)
+0
+select 1e8 * sum(distinct df) from t1;
+1e8 * sum(distinct df)
+330000000
+select 1e8 * min(df) from t1;
+1e8 * min(df)
+110000000
+create table t3 (ifl int);
+insert into t3 values(1), (2);
+select cast(min(ifl) as decimal(5,2)) from t3;
+cast(min(ifl) as decimal(5,2))
+1.00
+drop table t1, t2, t3;
+CREATE TABLE t1 (id int(11),value1 float(10,2));
+INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00), (2,13.00);
+select id, stddev_pop(value1), var_pop(value1), stddev_samp(value1), var_samp(value1) from t1 group by id;
+id stddev_pop(value1) var_pop(value1) stddev_samp(value1) var_samp(value1)
+1 0.816497 0.666667 1.000000 1.000000
+2 1.118034 1.250000 1.290994 1.666667
+DROP TABLE t1;
+CREATE TABLE t1 (col1 decimal(16,12));
+INSERT INTO t1 VALUES (-5.00000000001),(-5.00000000002),(-5.00000000003),(-5.00000000000),(-5.00000000001),(-5.00000000002);
+insert into t1 select * from t1;
+select col1,count(col1),sum(col1),avg(col1) from t1 group by col1;
+col1 count(col1) sum(col1) avg(col1)
+-5.000000000030 2 -10.000000000060 -5.0000000000300000
+-5.000000000020 4 -20.000000000080 -5.0000000000200000
+-5.000000000010 4 -20.000000000040 -5.0000000000100000
+-5.000000000000 2 -10.000000000000 -5.0000000000000000
+DROP TABLE t1;
+create table t1 (col1 decimal(16,12));
+insert into t1 values (-5.00000000001);
+insert into t1 values (-5.00000000001);
+select col1,sum(col1),max(col1),min(col1) from t1 group by col1;
+col1 sum(col1) max(col1) min(col1)
+-5.000000000010 -10.000000000020 -5.000000000010 -5.000000000010
+delete from t1;
+insert into t1 values (5.00000000001);
+insert into t1 values (5.00000000001);
+select col1,sum(col1),max(col1),min(col1) from t1 group by col1;
+col1 sum(col1) max(col1) min(col1)
+5.000000000010 10.000000000020 5.000000000010 5.000000000010
+DROP TABLE t1;
CREATE TABLE t1(
id int PRIMARY KEY,
a int,
@@ -780,3 +881,69 @@ SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
MAX(id)
NULL
DROP TABLE t1;
+CREATE TABLE t1 (a VARCHAR(400));
+INSERT INTO t1 (a) VALUES ("A"), ("a"), ("a "), ("a "),
+("B"), ("b"), ("b "), ("b ");
+SELECT COUNT(DISTINCT a) FROM t1;
+COUNT(DISTINCT a)
+2
+DROP TABLE t1;
+CREATE TABLE t1 (a int, b int, c int);
+INSERT INTO t1 (a, b, c) VALUES
+(1,1,1), (1,1,2), (1,1,3),
+(1,2,1), (1,2,2), (1,2,3),
+(1,3,1), (1,3,2), (1,3,3),
+(2,1,1), (2,1,2), (2,1,3),
+(2,2,1), (2,2,2), (2,2,3),
+(2,3,1), (2,3,2), (2,3,3),
+(3,1,1), (3,1,2), (3,1,3),
+(3,2,1), (3,2,2), (3,2,3),
+(3,3,1), (3,3,2), (3,3,3);
+SELECT b/c as v, a FROM t1 ORDER BY v;
+v a
+0.33333 3
+0.33333 1
+0.33333 2
+0.50000 1
+0.50000 2
+0.50000 3
+0.66667 2
+0.66667 1
+0.66667 3
+1.00000 3
+1.00000 2
+1.00000 3
+1.00000 1
+1.00000 2
+1.00000 3
+1.00000 2
+1.00000 1
+1.00000 1
+1.50000 3
+1.50000 2
+1.50000 1
+2.00000 1
+2.00000 3
+2.00000 2
+3.00000 3
+3.00000 2
+3.00000 1
+SELECT b/c as v, SUM(a) FROM t1 GROUP BY v;
+v SUM(a)
+0.33333 6
+0.50000 6
+0.66667 6
+1.00000 18
+1.50000 6
+2.00000 6
+3.00000 6
+SELECT SUM(a) FROM t1 GROUP BY b/c;
+SUM(a)
+6
+6
+6
+18
+6
+6
+6
+DROP TABLE t1;
diff --git a/mysql-test/r/func_if.result b/mysql-test/r/func_if.result
index 508a50caf02..4db31121756 100644
--- a/mysql-test/r/func_if.result
+++ b/mysql-test/r/func_if.result
@@ -43,22 +43,27 @@ explain extended select if(u=1,st,binary st) s from t1 where st like "%a%" order
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where; Using filesort
Warnings:
-Note 1003 select if((test.t1.u = 1),test.t1.st,cast(test.t1.st as char charset binary)) AS `s` from test.t1 where (test.t1.st like _latin1'%a%') order by if((test.t1.u = 1),test.t1.st,cast(test.t1.st as char charset binary))
-select nullif(u=0, 'test') from t1;
-nullif(u=0, 'test')
+Note 1003 select if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,cast(`test`.`t1`.`st` as char charset binary)) AS `s` from `test`.`t1` where (`test`.`t1`.`st` like _latin1'%a%') order by if((`test`.`t1`.`u` = 1),`test`.`t1`.`st`,cast(`test`.`t1`.`st` as char charset binary))
+select nullif(u, 1) from t1;
+nullif(u, 1)
NULL
NULL
NULL
NULL
NULL
-1
-1
-explain extended select nullif(u=0, 'test') from t1;
+0
+0
+explain extended select nullif(u, 1) from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 7
Warnings:
-Note 1003 select nullif((test.t1.u = 0),_latin1'test') AS `nullif(u=0, 'test')` from test.t1
+Note 1003 select nullif(`test`.`t1`.`u`,1) AS `nullif(u, 1)` from `test`.`t1`
drop table t1;
+select nullif(1,'test');
+nullif(1,'test')
+1
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'test'
select NULLIF(NULL,NULL), NULLIF(NULL,1), NULLIF(NULL,1.0), NULLIF(NULL,"test");
NULLIF(NULL,NULL) NULLIF(NULL,1) NULLIF(NULL,1.0) NULLIF(NULL,"test")
NULL NULL NULL NULL
diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result
index 516d0a28a21..f75fe0d1627 100644
--- a/mysql-test/r/func_in.result
+++ b/mysql-test/r/func_in.result
@@ -146,7 +146,7 @@ explain extended select * from t1 where 'a' in (a,b,c collate latin1_bin);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
Warnings:
-Note 1003 select test.t1.a AS `a`,test.t1.b AS `b`,test.t1.c AS `c` from test.t1 where (_latin1'a' in (test.t1.a,test.t1.b,(test.t1.c collate _latin1'latin1_bin')))
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (_latin1'a' in (`test`.`t1`.`a`,`test`.`t1`.`b`,(`test`.`t1`.`c` collate latin1_bin)))
drop table t1;
set names utf8;
create table t1 (a char(10) character set utf8 not null);
diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result
index a58432cb06e..ac8e5eda8e8 100644
--- a/mysql-test/r/func_like.result
+++ b/mysql-test/r/func_like.result
@@ -3,10 +3,10 @@ create table t1 (a varchar(10), key(a));
insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test");
explain select * from t1 where a like 'abc%';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range a a 11 NULL 1 Using where; Using index
+1 SIMPLE t1 index a a 13 NULL 5 Using where; Using index
explain select * from t1 where a like concat('abc','%');
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range a a 11 NULL 1 Using where; Using index
+1 SIMPLE t1 index a a 13 NULL 5 Using where; Using index
select * from t1 where a like "abc%";
a
abc
diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result
index 9cb1e4a56d6..005f41f7063 100644
--- a/mysql-test/r/func_math.result
+++ b/mysql-test/r/func_math.result
@@ -127,13 +127,3 @@ Warnings:
Note 1003 select degrees(pi()) AS `degrees(pi())`,radians(360) AS `radians(360)`
select rand(rand);
ERROR 42S22: Unknown column 'rand' in 'field list'
-create table t1 select round(1, 6);
-show create table t1;
-Table Create Table
-t1 CREATE TABLE `t1` (
- `round(1, 6)` double(7,6) NOT NULL default '0.000000'
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-select * from t1;
-round(1, 6)
-1.000000
-drop table t1;
diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result
index 2d464c891bf..1d9b813e68a 100644
--- a/mysql-test/r/func_misc.result
+++ b/mysql-test/r/func_misc.result
@@ -25,6 +25,8 @@ length(uuid()) charset(uuid()) length(unhex(replace(uuid(),_utf8'-',_utf8'')))
select length(format('nan', 2)) > 0;
length(format('nan', 2)) > 0
1
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'nan'
select concat("$",format(2500,2));
concat("$",format(2500,2))
$2,500.00
diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result
index 6cd975b0911..5f89fe7b727 100644
--- a/mysql-test/r/func_op.result
+++ b/mysql-test/r/func_op.result
@@ -1,6 +1,6 @@
select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2;
1+1 1-1 1+1*2 8/5 8%5 mod(8,5) mod(8,5)|0 -(1+1)*-2
-2 0 3 1.60 3 3 3 4
+2 0 3 1.60000 3 3 3 4
explain extended select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2;
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_regexp.result b/mysql-test/r/func_regexp.result
index 8228d6982d3..787463c6aa3 100644
--- a/mysql-test/r/func_regexp.result
+++ b/mysql-test/r/func_regexp.result
@@ -40,7 +40,7 @@ explain extended select * from t1 where xxx regexp('is a test of some long text
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
Warnings:
-Note 1003 select test.t1.xxx AS `xxx` from test.t1 where (test.t1.xxx regexp _latin1'is a test of some long text to')
+Note 1003 select `test`.`t1`.`xxx` AS `xxx` from `test`.`t1` where (`test`.`t1`.`xxx` regexp _latin1'is a test of some long text to')
select * from t1 where xxx regexp('is a test of some long text to ');
xxx
this is a test of some long text to see what happens
diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result
index 68c3baa7bde..f209866d953 100644
--- a/mysql-test/r/func_sapdb.result
+++ b/mysql-test/r/func_sapdb.result
@@ -56,15 +56,25 @@ subdate("1997-12-31 23:59:59.000001", 10)
select datediff("1997-12-31 23:59:59.000001","1997-12-30");
datediff("1997-12-31 23:59:59.000001","1997-12-30")
1
+select datediff("1997-11-30 23:59:59.000001","1997-12-31");
+datediff("1997-11-30 23:59:59.000001","1997-12-31")
+-31
+SET @@SQL_MODE="ALLOW_INVALID_DATES";
select datediff("1997-11-31 23:59:59.000001","1997-12-31");
datediff("1997-11-31 23:59:59.000001","1997-12-31")
-30
-select datediff("1997-11-31 23:59:59.000001",null);
-datediff("1997-11-31 23:59:59.000001",null)
+SET @@SQL_MODE="";
+select datediff("1997-11-31 23:59:59.000001","1997-12-31");
+datediff("1997-11-31 23:59:59.000001","1997-12-31")
+NULL
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '1997-11-31 23:59:59.000001'
+select datediff("1997-11-30 23:59:59.000001",null);
+datediff("1997-11-30 23:59:59.000001",null)
NULL
-select weekofyear("1997-11-31 23:59:59.000001");
-weekofyear("1997-11-31 23:59:59.000001")
-49
+select weekofyear("1997-11-30 23:59:59.000001");
+weekofyear("1997-11-30 23:59:59.000001")
+48
select makedate(1997,1);
makedate(1997,1)
1997-01-01
@@ -167,12 +177,12 @@ date("1997-12-31 23:59:59.000001") as f8,
time("1997-12-31 23:59:59.000001") as f9;
describe t1;
Field Type Null Key Default Extra
-f1 date 0000-00-00
+f1 date NO 0000-00-00
f2 datetime YES NULL
f3 time YES NULL
-f4 time 00:00:00
-f5 time 00:00:00
-f6 time 00:00:00
+f4 time NO 00:00:00
+f5 time NO 00:00:00
+f6 time NO 00:00:00
f7 datetime YES NULL
f8 date YES NULL
f9 time YES NULL
@@ -199,16 +209,17 @@ ttt qqq
NULL NULL
NULL NULL
2001-01-01 02:02:02 26:02:02
-SELECT TIMEDIFF(t1,t4) As ttt, TIMEDIFF(t2, t3) As qqq from test;
-ttt qqq
--744:00:00 NULL
-26305:01:02 22:58:58
--26305:01:02 -22:58:58
-NULL 26:02:02
-00:00:00 -26:02:02
-NULL NULL
-NULL NULL
-00:00:00 -24:00:00
+SELECT TIMEDIFF(t1, t4) As ttt, TIMEDIFF(t2, t3) As qqq,
+TIMEDIFF(t3, t2) As eee, TIMEDIFF(t2, t4) As rrr from test;
+ttt qqq eee rrr
+-744:00:00 NULL NULL NULL
+26305:01:02 22:58:58 -22:58:58 NULL
+-26305:01:02 -22:58:58 22:58:58 NULL
+NULL 26:02:02 -26:02:02 NULL
+00:00:00 -26:02:02 26:02:02 NULL
+NULL NULL NULL NULL
+NULL NULL NULL NULL
+00:00:00 -24:00:00 24:00:00 NULL
drop table t1, test;
select addtime("-01:01:01.01", "-23:59:59.1") as a;
a
diff --git a/mysql-test/r/func_set.result b/mysql-test/r/func_set.result
index ca6e0a8c319..aa71cee0752 100644
--- a/mysql-test/r/func_set.result
+++ b/mysql-test/r/func_set.result
@@ -30,6 +30,12 @@ Y-N-N-Y-N Y,N,N,Y,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,
select elt(2,1),field(NULL,"a","b","c");
elt(2,1) field(NULL,"a","b","c")
NULL 0
+select field("b","a",NULL),field(1,0,NULL)+0,field(1.0,0.0,NULL)+0.0,field(1.0e1,0.0e1,NULL)+0.0e1;
+field("b","a",NULL) field(1,0,NULL)+0 field(1.0,0.0,NULL)+0.0 field(1.0e1,0.0e1,NULL)+0.0e1
+0 0 0.0 0
+select field(NULL,"a",NULL),field(NULL,0,NULL)+0,field(NULL,0.0,NULL)+0.0,field(NULL,0.0e1,NULL)+0.0e1;
+field(NULL,"a",NULL) field(NULL,0,NULL)+0 field(NULL,0.0,NULL)+0.0 field(NULL,0.0e1,NULL)+0.0e1
+0 0 0.0 0
select find_in_set("","a,b,c"),find_in_set("","a,b,c,"),find_in_set("",",a,b,c");
find_in_set("","a,b,c") find_in_set("","a,b,c,") find_in_set("",",a,b,c")
0 4 1
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 5405dbf53d9..bbb5a94606e 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -1,4 +1,4 @@
-drop table if exists t1;
+drop table if exists t1,t2;
set names latin1;
select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo';
hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo
@@ -48,6 +48,9 @@ tcx.se .se
select concat(':',ltrim(' left '),':',rtrim(' right '),':');
concat(':',ltrim(' left '),':',rtrim(' right '),':')
:left : right:
+select concat(':',trim(leading from ' left '),':',trim(trailing from ' right '),':');
+concat(':',trim(leading from ' left '),':',trim(trailing from ' right '),':')
+:left : right:
select concat(':',trim(LEADING FROM ' left'),':',trim(TRAILING FROM ' right '),':');
concat(':',trim(LEADING FROM ' left'),':',trim(TRAILING FROM ' right '),':')
:left: right:
@@ -233,6 +236,8 @@ Warning 1301 Result of repeat() was larger than max_allowed_packet (1048576) - t
select position("0" in "baaa" in (1)),position("0" in "1" in (1,2,3)),position("sql" in ("mysql"));
position("0" in "baaa" in (1)) position("0" in "1" in (1,2,3)) position("sql" in ("mysql"))
1 0 3
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'baaa'
select position(("1" in (1,2,3)) in "01");
position(("1" in (1,2,3)) in "01")
2
@@ -390,9 +395,9 @@ select FIELD(_latin2'b','A','B');
ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field'
select FIELD('b',_latin2'A','B');
ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field'
-select FIELD('b',_latin2'A','B',1);
-FIELD('b',_latin2'A','B',1)
-1
+select FIELD('1',_latin2'3','2',1);
+FIELD('1',_latin2'3','2',1)
+3
select POSITION(_latin1'B' IN _latin1'abcd');
POSITION(_latin1'B' IN _latin1'abcd')
2
@@ -417,9 +422,9 @@ select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin1'd',2);
SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin1'd',2)
abcdabc
select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin2'd',2);
-ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'substr_index'
+ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'substring_index'
select SUBSTRING_INDEX(_latin1'abcdabcdabcd' COLLATE latin1_general_ci,_latin1'd' COLLATE latin1_bin,2);
-ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'substr_index'
+ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'substring_index'
select _latin1'B' between _latin1'a' and _latin1'c';
_latin1'B' between _latin1'a' and _latin1'c'
1
@@ -594,37 +599,37 @@ Warning 1265 Data truncated for column 'format(130,10)' at row 1
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `bin(130)` char(64) NOT NULL default '',
- `oct(130)` char(64) NOT NULL default '',
- `conv(130,16,10)` char(64) NOT NULL default '',
- `hex(130)` char(6) NOT NULL default '',
- `char(130)` char(1) NOT NULL default '',
- `format(130,10)` char(4) NOT NULL default '',
- `left(_latin2'a',1)` char(1) character set latin2 NOT NULL default '',
- `right(_latin2'a',1)` char(1) character set latin2 NOT NULL default '',
- `lcase(_latin2'a')` char(1) character set latin2 NOT NULL default '',
- `ucase(_latin2'a')` char(1) character set latin2 NOT NULL default '',
- `substring(_latin2'a',1,1)` char(1) character set latin2 NOT NULL default '',
- `concat(_latin2'a',_latin2'b')` char(2) character set latin2 NOT NULL default '',
- `lpad(_latin2'a',4,_latin2'b')` char(4) character set latin2 NOT NULL default '',
- `rpad(_latin2'a',4,_latin2'b')` char(4) character set latin2 NOT NULL default '',
- `concat_ws(_latin2'a',_latin2'b')` char(1) character set latin2 NOT NULL default '',
- `make_set(255,_latin2'a',_latin2'b',_latin2'c')` char(5) character set latin2 NOT NULL default '',
- `export_set(255,_latin2'y',_latin2'n',_latin2' ')` char(127) character set latin2 NOT NULL default '',
- `trim(_latin2' a ')` char(3) character set latin2 NOT NULL default '',
- `ltrim(_latin2' a ')` char(3) character set latin2 NOT NULL default '',
- `rtrim(_latin2' a ')` char(3) character set latin2 NOT NULL default '',
- `trim(LEADING _latin2' ' FROM _latin2' a ')` char(3) character set latin2 NOT NULL default '',
- `trim(TRAILING _latin2' ' FROM _latin2' a ')` char(3) character set latin2 NOT NULL default '',
- `trim(BOTH _latin2' ' FROM _latin2' a ')` char(3) character set latin2 NOT NULL default '',
- `repeat(_latin2'a',10)` char(10) character set latin2 NOT NULL default '',
- `reverse(_latin2'ab')` char(2) character set latin2 NOT NULL default '',
- `quote(_latin2'ab')` char(6) character set latin2 NOT NULL default '',
- `soundex(_latin2'ab')` char(4) character set latin2 NOT NULL default '',
- `substring(_latin2'ab',1)` char(2) character set latin2 NOT NULL default '',
- `insert(_latin2'abcd',2,3,_latin2'ef')` char(6) character set latin2 NOT NULL default '',
- `replace(_latin2'abcd',_latin2'b',_latin2'B')` char(4) character set latin2 NOT NULL default '',
- `encode('abcd','ab')` binary(4) NOT NULL default ''
+ `bin(130)` varchar(64) NOT NULL default '',
+ `oct(130)` varchar(64) NOT NULL default '',
+ `conv(130,16,10)` varchar(64) NOT NULL default '',
+ `hex(130)` varchar(6) NOT NULL default '',
+ `char(130)` varchar(1) NOT NULL default '',
+ `format(130,10)` varchar(4) NOT NULL default '',
+ `left(_latin2'a',1)` varchar(1) character set latin2 NOT NULL default '',
+ `right(_latin2'a',1)` varchar(1) character set latin2 NOT NULL default '',
+ `lcase(_latin2'a')` varchar(1) character set latin2 NOT NULL default '',
+ `ucase(_latin2'a')` varchar(1) character set latin2 NOT NULL default '',
+ `substring(_latin2'a',1,1)` varchar(1) character set latin2 NOT NULL default '',
+ `concat(_latin2'a',_latin2'b')` varchar(2) character set latin2 NOT NULL default '',
+ `lpad(_latin2'a',4,_latin2'b')` varchar(4) character set latin2 NOT NULL default '',
+ `rpad(_latin2'a',4,_latin2'b')` varchar(4) character set latin2 NOT NULL default '',
+ `concat_ws(_latin2'a',_latin2'b')` varchar(1) character set latin2 NOT NULL default '',
+ `make_set(255,_latin2'a',_latin2'b',_latin2'c')` varchar(5) character set latin2 NOT NULL default '',
+ `export_set(255,_latin2'y',_latin2'n',_latin2' ')` varchar(127) character set latin2 NOT NULL default '',
+ `trim(_latin2' a ')` varchar(3) character set latin2 NOT NULL default '',
+ `ltrim(_latin2' a ')` varchar(3) character set latin2 NOT NULL default '',
+ `rtrim(_latin2' a ')` varchar(3) character set latin2 NOT NULL default '',
+ `trim(LEADING _latin2' ' FROM _latin2' a ')` varchar(3) character set latin2 NOT NULL default '',
+ `trim(TRAILING _latin2' ' FROM _latin2' a ')` varchar(3) character set latin2 NOT NULL default '',
+ `trim(BOTH _latin2' ' FROM _latin2' a ')` varchar(3) character set latin2 NOT NULL default '',
+ `repeat(_latin2'a',10)` varchar(10) character set latin2 NOT NULL default '',
+ `reverse(_latin2'ab')` varchar(2) character set latin2 NOT NULL default '',
+ `quote(_latin2'ab')` varchar(6) character set latin2 NOT NULL default '',
+ `soundex(_latin2'ab')` varchar(4) character set latin2 NOT NULL default '',
+ `substring(_latin2'ab',1)` varchar(2) character set latin2 NOT NULL default '',
+ `insert(_latin2'abcd',2,3,_latin2'ef')` varchar(6) character set latin2 NOT NULL default '',
+ `replace(_latin2'abcd',_latin2'b',_latin2'B')` varchar(4) character set latin2 NOT NULL default '',
+ `encode('abcd','ab')` varbinary(4) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (a char character set latin2);
@@ -689,7 +694,7 @@ explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'moo
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select md5(_latin1'hello') AS `md5('hello')`,sha(_latin1'abc') AS `sha('abc')`,sha(_latin1'abc') AS `sha1('abc')`,soundex(_latin1'') AS `soundex('')`,(soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`,aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`,concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`,reverse(_latin1'abc') AS `reverse('abc')`,rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`,lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`,concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`,make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a',_latin2'b',_latin2'c')`,elt(2,1) AS `elt(2,1)`,locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`,format(130,10) AS `format(130,10)`,char(0) AS `char(0)`,conv(130,16,10) AS `conv(130,16,10)`,hex(130) AS `hex(130)`,cast(_latin1'HE' as char charset binary) AS `binary 'HE'`,export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y',_latin2'n',_latin2' ')`,field((_latin1'b' collate _latin1'latin1_bin'),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`,find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B',_latin1'a,b,c,d')`,collation(conv(130,16,10)) AS `collation(conv(130,16,10))`,coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`,length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`,length(_latin1'hello') AS `length('hello')`,char(ascii(_latin1'h')) AS `char(ascii('h'))`,ord(_latin1'h') AS `ord('h')`,quote((1 / 0)) AS `quote(1/0)`,crc32(_latin1'123') AS `crc32("123")`,replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`,insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`,left(_latin2'a',1) AS `left(_latin2'a',1)`,right(_latin2'a',1) AS `right(_latin2'a',1)`,lcase(_latin2'a') AS `lcase(_latin2'a')`,ucase(_latin2'a') AS `ucase(_latin2'a')`,substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`,substr_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`,trim(_latin2' a ') AS `trim(_latin2' a ')`,ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`,rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`,decode(encode(repeat(_latin1'a',100000))) AS `decode(encode(repeat("a",100000),"monty"),"monty")`
+Note 1003 select md5(_latin1'hello') AS `md5('hello')`,sha(_latin1'abc') AS `sha('abc')`,sha(_latin1'abc') AS `sha1('abc')`,soundex(_latin1'') AS `soundex('')`,(soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`,aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`,concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`,reverse(_latin1'abc') AS `reverse('abc')`,rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`,lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`,concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`,make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a',_latin2'b',_latin2'c')`,elt(2,1) AS `elt(2,1)`,locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`,format(130,10) AS `format(130,10)`,char(0) AS `char(0)`,conv(130,16,10) AS `conv(130,16,10)`,hex(130) AS `hex(130)`,cast(_latin1'HE' as char charset binary) AS `binary 'HE'`,export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y',_latin2'n',_latin2' ')`,field((_latin1'b' collate latin1_bin),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`,find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B',_latin1'a,b,c,d')`,collation(conv(130,16,10)) AS `collation(conv(130,16,10))`,coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`,length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`,length(_latin1'hello') AS `length('hello')`,char(ascii(_latin1'h')) AS `char(ascii('h'))`,ord(_latin1'h') AS `ord('h')`,quote((1 / 0)) AS `quote(1/0)`,crc32(_latin1'123') AS `crc32("123")`,replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`,insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`,left(_latin2'a',1) AS `left(_latin2'a',1)`,right(_latin2'a',1) AS `right(_latin2'a',1)`,lcase(_latin2'a') AS `lcase(_latin2'a')`,ucase(_latin2'a') AS `ucase(_latin2'a')`,substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`,substring_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`,trim(_latin2' a ') AS `trim(_latin2' a ')`,ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`,rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`,decode(encode(repeat(_latin1'a',100000))) AS `decode(encode(repeat("a",100000),"monty"),"monty")`
SELECT lpad(12345, 5, "#");
lpad(12345, 5, "#")
12345
@@ -709,16 +714,16 @@ drop table t1, t2;
create table t1 (c1 INT, c2 INT UNSIGNED);
insert into t1 values ('21474836461','21474836461');
Warnings:
-Warning 1265 Data truncated for column 'c1' at row 1
-Warning 1265 Data truncated for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
insert into t1 values ('-21474836461','-21474836461');
Warnings:
-Warning 1265 Data truncated for column 'c1' at row 1
-Warning 1265 Data truncated for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
show warnings;
Level Code Message
-Warning 1265 Data truncated for column 'c1' at row 1
-Warning 1265 Data truncated for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
select * from t1;
c1 c2
2147483647 4294967295
@@ -739,6 +744,12 @@ NULL
select trim('xyz' from null) as "must_be_null";
must_be_null
NULL
+select trim(leading NULL from 'kate') as "must_be_null";
+must_be_null
+NULL
+select trim(trailing NULL from 'xyz') as "must_be_null";
+must_be_null
+NULL
CREATE TABLE t1 (
id int(11) NOT NULL auto_increment,
a bigint(20) unsigned default NULL,
diff --git a/mysql-test/r/func_system.result b/mysql-test/r/func_system.result
index 137c25a2db5..5ec5d7d724e 100644
--- a/mysql-test/r/func_system.result
+++ b/mysql-test/r/func_system.result
@@ -46,8 +46,8 @@ create table t1 (version char(40)) select database(), user(), version() as 'vers
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `database()` char(34) character set utf8 default NULL,
- `user()` char(77) character set utf8 NOT NULL default '',
+ `database()` varchar(34) character set utf8 default NULL,
+ `user()` varchar(77) character set utf8 NOT NULL default '',
`version` char(40) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
@@ -61,8 +61,8 @@ create table t1 select charset(_utf8'a'), collation(_utf8'a');
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `charset(_utf8'a')` char(64) character set utf8 NOT NULL default '',
- `collation(_utf8'a')` char(64) character set utf8 NOT NULL default ''
+ `charset(_utf8'a')` varchar(64) character set utf8 NOT NULL default '',
+ `collation(_utf8'a')` varchar(64) character set utf8 NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select TRUE,FALSE,NULL;
diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result
index 8a28312b348..32883921e70 100644
--- a/mysql-test/r/func_test.result
+++ b/mysql-test/r/func_test.result
@@ -77,9 +77,9 @@ select * from t1 where 1 xor 1;
a
explain extended select * from t1 where 1 xor 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
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
Warnings:
-Note 1003 select test.t1.a AS `a` from test.t1 where (1 xor 1)
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1`
select - a from t1;
- a
-1
@@ -87,7 +87,7 @@ explain extended select - a from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
Warnings:
-Note 1003 select -(test.t1.a) AS `- a` from test.t1
+Note 1003 select -(`test`.`t1`.`a`) AS `- a` from `test`.`t1`
drop table t1;
select 5 between 0 and 10 between 0 and 1,(5 between 0 and 10) between 0 and 1;
5 between 0 and 10 between 0 and 1 (5 between 0 and 10) between 0 and 1
@@ -108,7 +108,7 @@ explain extended select _koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select (_koi8r'a' = (_koi8r'A' collate _latin1'koi8r_general_ci')) AS `_koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci`
+Note 1003 select (_koi8r'a' = (_koi8r'A' collate koi8r_general_ci)) AS `_koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci`
select _koi8r'a' = _koi8r'A' COLLATE koi8r_bin;
_koi8r'a' = _koi8r'A' COLLATE koi8r_bin
0
@@ -183,3 +183,13 @@ select 5.1 mod 3, 5.1 mod -3, -5.1 mod 3, -5.1 mod -3;
select 5 mod 3, 5 mod -3, -5 mod 3, -5 mod -3;
5 mod 3 5 mod -3 -5 mod 3 -5 mod -3
2 2 -2 -2
+create table t1 (a int, b int);
+insert into t1 values (1,2), (2,3), (3,4), (4,5);
+select * from t1 where a not between 1 and 2;
+a b
+3 4
+4 5
+select * from t1 where a not between 1 and 2 and b not between 3 and 4;
+a b
+4 5
+drop table t1;
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 4dd00ab74a1..4293ef5bd85 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -304,6 +304,8 @@ NULL
select date_sub("0000-00-00 00:00:00",INTERVAL 1 SECOND);
date_sub("0000-00-00 00:00:00",INTERVAL 1 SECOND)
NULL
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '0000-00-00 00:00:00'
select date_add('1998-01-30',Interval 1 month);
date_add('1998-01-30',Interval 1 month)
1998-02-28
@@ -424,6 +426,9 @@ insert into t1 values ("0000-00-00", "0000-00-00", "0000-00-00", "0000-00-00");
select dayofyear("0000-00-00"),dayofyear(d),dayofyear(dt),dayofyear(t),dayofyear(c) from t1;
dayofyear("0000-00-00") dayofyear(d) dayofyear(dt) dayofyear(t) dayofyear(c)
NULL NULL NULL NULL NULL
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '0000-00-00'
+Warning 1292 Truncated incorrect datetime value: '0000-00-00'
select dayofmonth("0000-00-00"),dayofmonth(d),dayofmonth(dt),dayofmonth(t),dayofmonth(c) from t1;
dayofmonth("0000-00-00") dayofmonth(d) dayofmonth(dt) dayofmonth(t) dayofmonth(c)
0 0 0 0 0
@@ -436,15 +441,24 @@ quarter("0000-00-00") quarter(d) quarter(dt) quarter(t) quarter(c)
select week("0000-00-00"),week(d),week(dt),week(t),week(c) from t1;
week("0000-00-00") week(d) week(dt) week(t) week(c)
NULL NULL NULL NULL NULL
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '0000-00-00'
+Warning 1292 Truncated incorrect datetime value: '0000-00-00'
select year("0000-00-00"),year(d),year(dt),year(t),year(c) from t1;
year("0000-00-00") year(d) year(dt) year(t) year(c)
0 0 0 0 0
select yearweek("0000-00-00"),yearweek(d),yearweek(dt),yearweek(t),yearweek(c) from t1;
yearweek("0000-00-00") yearweek(d) yearweek(dt) yearweek(t) yearweek(c)
NULL NULL NULL NULL NULL
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '0000-00-00'
+Warning 1292 Truncated incorrect datetime value: '0000-00-00'
select to_days("0000-00-00"),to_days(d),to_days(dt),to_days(t),to_days(c) from t1;
to_days("0000-00-00") to_days(d) to_days(dt) to_days(t) to_days(c)
NULL NULL NULL NULL NULL
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '0000-00-00'
+Warning 1292 Truncated incorrect datetime value: '0000-00-00'
select extract(MONTH FROM "0000-00-00"),extract(MONTH FROM d),extract(MONTH FROM dt),extract(MONTH FROM t),extract(MONTH FROM c) from t1;
extract(MONTH FROM "0000-00-00") extract(MONTH FROM d) extract(MONTH FROM dt) extract(MONTH FROM t) extract(MONTH FROM c)
0 0 0 0 0
@@ -539,11 +553,68 @@ date_add(date,INTERVAL "1 1:1" DAY_MINUTE)
select date_add(date,INTERVAL "1 1:1:1" DAY_SECOND) from t1;
date_add(date,INTERVAL "1 1:1:1" DAY_SECOND)
2003-01-03 01:01:01
+select date_add(date,INTERVAL "1" WEEK) from t1;
+date_add(date,INTERVAL "1" WEEK)
+2003-01-09 00:00:00
+select date_add(date,INTERVAL "1" QUARTER) from t1;
+date_add(date,INTERVAL "1" QUARTER)
+2003-04-02
+select timestampadd(MINUTE, 1, date) from t1;
+timestampadd(MINUTE, 1, date)
+2003-01-02 00:01:00
+select timestampadd(WEEK, 1, date) from t1;
+timestampadd(WEEK, 1, date)
+2003-01-09 00:00:00
+select timestampadd(SQL_TSI_SECOND, 1, date) from t1;
+timestampadd(SQL_TSI_SECOND, 1, date)
+2003-01-02 00:00:01
+select timestampadd(SQL_TSI_FRAC_SECOND, 1, date) from t1;
+timestampadd(SQL_TSI_FRAC_SECOND, 1, date)
+2003-01-02 00:00:00.000001
+select timestampdiff(MONTH, '2001-02-01', '2001-05-01') as a;
+a
+3
+select timestampdiff(YEAR, '2002-05-01', '2001-01-01') as a;
+a
+-1
+select timestampdiff(QUARTER, '2002-05-01', '2001-01-01') as a;
+a
+-5
+select timestampdiff(MONTH, '2000-03-28', '2000-02-29') as a;
+a
+0
+select timestampdiff(MONTH, '1991-03-28', '2000-02-29') as a;
+a
+107
+select timestampdiff(SQL_TSI_WEEK, '2001-02-01', '2001-05-01') as a;
+a
+12
+select timestampdiff(SQL_TSI_HOUR, '2001-02-01', '2001-05-01') as a;
+a
+2136
+select timestampdiff(SQL_TSI_DAY, '2001-02-01', '2001-05-01') as a;
+a
+89
+select timestampdiff(SQL_TSI_MINUTE, '2001-02-01 12:59:59', '2001-05-01 12:58:59') as a;
+a
+128159
+select timestampdiff(SQL_TSI_SECOND, '2001-02-01 12:59:59', '2001-05-01 12:58:58') as a;
+a
+7689539
+select timestampdiff(SQL_TSI_FRAC_SECOND, '2001-02-01 12:59:59.120000', '2001-05-01 12:58:58.119999') as a;
+a
+7689538999999
+select timestampdiff(SQL_TSI_DAY, '1986-02-01', '1986-03-01') as a1,
+timestampdiff(SQL_TSI_DAY, '1900-02-01', '1900-03-01') as a2,
+timestampdiff(SQL_TSI_DAY, '1996-02-01', '1996-03-01') as a3,
+timestampdiff(SQL_TSI_DAY, '2000-02-01', '2000-03-01') as a4;
+a1 a2 a3 a4
+28 28 29 29
select date_add(time,INTERVAL 1 SECOND) from t1;
date_add(time,INTERVAL 1 SECOND)
NULL
Warnings:
-Warning 1264 Data truncated; out of range for column 'time' at row 1
+Warning 1264 Out of range value adjusted for column 'time' at row 1
drop table t1;
select last_day('2000-02-05') as f1, last_day('2002-12-31') as f2,
last_day('2003-03-32') as f3, last_day('2003-04-01') as f4,
@@ -557,7 +628,7 @@ create table t1 select last_day('2000-02-05') as a,
from_days(to_days("960101")) as b;
describe t1;
Field Type Null Key Default Extra
-a date 0000-00-00
+a date NO 0000-00-00
b date YES NULL
select * from t1;
a b
@@ -611,3 +682,9 @@ SELECT count(*) FROM t1 WHERE d>FROM_DAYS(TO_DAYS(@TMP)) AND d<=FROM_DAYS(TO_DAY
count(*)
3
DROP TABLE t1;
+explain extended select timestampdiff(SQL_TSI_WEEK, '2001-02-01', '2001-05-01') as a1,
+timestampdiff(SQL_TSI_FRAC_SECOND, '2001-02-01 12:59:59.120000', '2001-05-01 12:58:58.119999') as a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select timestamp_diff(WEEK,_latin1'2001-02-01',_latin1'2001-05-01') AS `a1`,timestamp_diff(SECOND_FRAC,_latin1'2001-02-01 12:59:59.120000',_latin1'2001-05-01 12:58:58.119999') AS `a2`
diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result
index 7b63654ffaf..73cde35993e 100644
--- a/mysql-test/r/gis-rtree.result
+++ b/mysql-test/r/gis-rtree.result
@@ -8,7 +8,7 @@ SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`fid` int(11) NOT NULL auto_increment,
- `g` geometry NOT NULL default '',
+ `g` geometry NOT NULL,
PRIMARY KEY (`fid`),
SPATIAL KEY `g` (`g`(32))
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -291,7 +291,7 @@ SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`fid` int(11) NOT NULL auto_increment,
- `g` geometry NOT NULL default '',
+ `g` geometry NOT NULL,
PRIMARY KEY (`fid`),
SPATIAL KEY `g` (`g`(32))
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -758,7 +758,6 @@ SPATIAL KEY(g)
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
drop table t1;
CREATE TABLE t1 (
-geoobjid INT NOT NULL,
line LINESTRING NOT NULL,
kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
name VARCHAR(32),
@@ -802,5 +801,5 @@ CREATE TABLE t1 (st varchar(100));
INSERT INTO t1 VALUES ("Fake string");
CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom));
INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
-ERROR HY000: Unknown error
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
drop table t1, t2;
diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result
index c51b07f09d6..93216fe2003 100644
--- a/mysql-test/r/gis.result
+++ b/mysql-test/r/gis.result
@@ -9,35 +9,35 @@ CREATE TABLE gis_geometrycollection (fid INTEGER NOT NULL PRIMARY KEY, g GEOMET
CREATE TABLE gis_geometry (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY);
SHOW FIELDS FROM gis_point;
Field Type Null Key Default Extra
-fid int(11) PRI 0
+fid int(11) NO PRI
g point YES NULL
SHOW FIELDS FROM gis_line;
Field Type Null Key Default Extra
-fid int(11) PRI 0
+fid int(11) NO PRI
g linestring YES NULL
SHOW FIELDS FROM gis_polygon;
Field Type Null Key Default Extra
-fid int(11) PRI 0
+fid int(11) NO PRI
g polygon YES NULL
SHOW FIELDS FROM gis_multi_point;
Field Type Null Key Default Extra
-fid int(11) PRI 0
+fid int(11) NO PRI
g multipoint YES NULL
SHOW FIELDS FROM gis_multi_line;
Field Type Null Key Default Extra
-fid int(11) PRI 0
+fid int(11) NO PRI
g multilinestring YES NULL
SHOW FIELDS FROM gis_multi_polygon;
Field Type Null Key Default Extra
-fid int(11) PRI 0
+fid int(11) NO PRI
g multipolygon YES NULL
SHOW FIELDS FROM gis_geometrycollection;
Field Type Null Key Default Extra
-fid int(11) PRI 0
+fid int(11) NO PRI
g geometrycollection YES NULL
SHOW FIELDS FROM gis_geometry;
Field Type Null Key Default Extra
-fid int(11) PRI 0
+fid int(11) NO PRI
g geometry YES NULL
INSERT INTO gis_point VALUES
(101, PointFromText('POINT(10 10)')),
@@ -228,7 +228,7 @@ explain extended select Dimension(g), GeometryType(g), IsEmpty(g), AsText(Envelo
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE gis_geometry ALL NULL NULL NULL NULL 21
Warnings:
-Note 1003 select dimension(test.gis_geometry.g) AS `Dimension(g)`,geometrytype(test.gis_geometry.g) AS `GeometryType(g)`,isempty(test.gis_geometry.g) AS `IsEmpty(g)`,astext(envelope(test.gis_geometry.g)) AS `AsText(Envelope(g))` from test.gis_geometry
+Note 1003 select dimension(`test`.`gis_geometry`.`g`) AS `Dimension(g)`,geometrytype(`test`.`gis_geometry`.`g`) AS `GeometryType(g)`,isempty(`test`.`gis_geometry`.`g`) AS `IsEmpty(g)`,astext(envelope(`test`.`gis_geometry`.`g`)) AS `AsText(Envelope(g))` from `test`.`gis_geometry`
SELECT fid, X(g) FROM gis_point;
fid X(g)
101 10
@@ -245,7 +245,7 @@ explain extended select X(g),Y(g) FROM gis_point;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE gis_point ALL NULL NULL NULL NULL 4
Warnings:
-Note 1003 select x(test.gis_point.g) AS `X(g)`,y(test.gis_point.g) AS `Y(g)` from test.gis_point
+Note 1003 select x(`test`.`gis_point`.`g`) AS `X(g)`,y(`test`.`gis_point`.`g`) AS `Y(g)` from `test`.`gis_point`
SELECT fid, AsText(StartPoint(g)) FROM gis_line;
fid AsText(StartPoint(g))
105 POINT(0 0)
@@ -280,7 +280,7 @@ explain extended select AsText(StartPoint(g)),AsText(EndPoint(g)),GLength(g),Num
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE gis_line ALL NULL NULL NULL NULL 3
Warnings:
-Note 1003 select astext(startpoint(test.gis_line.g)) AS `AsText(StartPoint(g))`,astext(endpoint(test.gis_line.g)) AS `AsText(EndPoint(g))`,glength(test.gis_line.g) AS `GLength(g)`,numpoints(test.gis_line.g) AS `NumPoints(g)`,astext(pointn(test.gis_line.g,2)) AS `AsText(PointN(g, 2))`,isclosed(test.gis_line.g) AS `IsClosed(g)` from test.gis_line
+Note 1003 select astext(startpoint(`test`.`gis_line`.`g`)) AS `AsText(StartPoint(g))`,astext(endpoint(`test`.`gis_line`.`g`)) AS `AsText(EndPoint(g))`,glength(`test`.`gis_line`.`g`) AS `GLength(g)`,numpoints(`test`.`gis_line`.`g`) AS `NumPoints(g)`,astext(pointn(`test`.`gis_line`.`g`,2)) AS `AsText(PointN(g, 2))`,isclosed(`test`.`gis_line`.`g`) AS `IsClosed(g)` from `test`.`gis_line`
SELECT fid, AsText(Centroid(g)) FROM gis_polygon;
fid AsText(Centroid(g))
108 POINT(15 15)
@@ -310,7 +310,7 @@ explain extended select AsText(Centroid(g)),Area(g),AsText(ExteriorRing(g)),NumI
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE gis_polygon ALL NULL NULL NULL NULL 3
Warnings:
-Note 1003 select astext(centroid(test.gis_polygon.g)) AS `AsText(Centroid(g))`,area(test.gis_polygon.g) AS `Area(g)`,astext(exteriorring(test.gis_polygon.g)) AS `AsText(ExteriorRing(g))`,numinteriorrings(test.gis_polygon.g) AS `NumInteriorRings(g)`,astext(interiorringn(test.gis_polygon.g,1)) AS `AsText(InteriorRingN(g, 1))` from test.gis_polygon
+Note 1003 select astext(centroid(`test`.`gis_polygon`.`g`)) AS `AsText(Centroid(g))`,area(`test`.`gis_polygon`.`g`) AS `Area(g)`,astext(exteriorring(`test`.`gis_polygon`.`g`)) AS `AsText(ExteriorRing(g))`,numinteriorrings(`test`.`gis_polygon`.`g`) AS `NumInteriorRings(g)`,astext(interiorringn(`test`.`gis_polygon`.`g`,1)) AS `AsText(InteriorRingN(g, 1))` from `test`.`gis_polygon`
SELECT fid, IsClosed(g) FROM gis_multi_line;
fid IsClosed(g)
114 0
@@ -349,7 +349,7 @@ explain extended SELECT fid, NumGeometries(g) from gis_multi_point;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3
Warnings:
-Note 1003 select test.gis_multi_point.fid AS `fid`,numgeometries(test.gis_multi_point.g) AS `NumGeometries(g)` from test.gis_multi_point
+Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,numgeometries(`test`.`gis_multi_point`.`g`) AS `NumGeometries(g)` from `test`.`gis_multi_point`
SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point;
fid AsText(GeometryN(g, 2))
111 POINT(10 10)
@@ -377,7 +377,7 @@ explain extended SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3
Warnings:
-Note 1003 select test.gis_multi_point.fid AS `fid`,astext(geometryn(test.gis_multi_point.g,2)) AS `AsText(GeometryN(g, 2))` from test.gis_multi_point
+Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,astext(geometryn(`test`.`gis_multi_point`.`g`,2)) AS `AsText(GeometryN(g, 2))` from `test`.`gis_multi_point`
SELECT g1.fid as first, g2.fid as second,
Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o,
Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t,
@@ -397,7 +397,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE g1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
1 SIMPLE g2 ALL NULL NULL NULL NULL 2
Warnings:
-Note 1003 select test.g1.fid AS `first`,test.g2.fid AS `second`,within(test.g1.g,test.g2.g) AS `w`,contains(test.g1.g,test.g2.g) AS `c`,overlaps(test.g1.g,test.g2.g) AS `o`,equals(test.g1.g,test.g2.g) AS `e`,disjoint(test.g1.g,test.g2.g) AS `d`,touches(test.g1.g,test.g2.g) AS `t`,intersects(test.g1.g,test.g2.g) AS `i`,crosses(test.g1.g,test.g2.g) AS `r` from test.gis_geometrycollection g1 join test.gis_geometrycollection g2 order by test.g1.fid,test.g2.fid
+Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,within(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,contains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,overlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,equals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,disjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,intersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid`
DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry;
CREATE TABLE t1 (
gp point,
@@ -430,7 +430,7 @@ mln multilinestring YES NULL
mpg multipolygon YES NULL
gc geometrycollection YES NULL
gm geometry YES NULL
-fid int(11) 0
+fid int(11) NO
DROP TABLE t1;
SELECT AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)'))));
AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)'))))
@@ -461,9 +461,9 @@ Note 1003 select issimple(multipoint(point(3,6),point(4,10))) AS `issimple(Multi
create table t1 (a geometry not null);
insert into t1 values (GeomFromText('Point(1 2)'));
insert into t1 values ('Garbage');
-ERROR HY000: Unknown error
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
insert IGNORE into t1 values ('Garbage');
-ERROR HY000: Unknown error
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
alter table t1 add spatial index(a);
drop table t1;
create table t1(a geometry not null, spatial index(a));
@@ -655,3 +655,13 @@ t1 where object_id=85984;
object_id geometrytype(geo) ISSIMPLE(GEO) ASTEXT(centroid(geo))
85984 MULTIPOLYGON 0 POINT(-114.87787186923 36.33101763469)
drop table t1;
+create table t1 (fl geometry);
+insert into t1 values (1);
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+insert into t1 values (1.11);
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+insert into t1 values ("qwerty");
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+insert into t1 values (pointfromtext('point(1,1)'));
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+drop table t1;
diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result
index bb37480aaf8..c8ae8303d99 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -10,8 +10,8 @@ GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3
GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost'
grant delete on mysqltest.* to mysqltest_1@localhost;
select * from mysql.user where user="mysqltest_1";
-Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections
-localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0
+Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
+localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA'
@@ -41,15 +41,15 @@ delete from mysql.user where user='mysqltest_1';
flush privileges;
grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10;
select * from mysql.user where user="mysqltest_1";
-Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections
-localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N 10 0 0
+Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
+localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N 10 0 0 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10
grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30;
select * from mysql.user where user="mysqltest_1";
-Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections
-localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N 10 20 30
+Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections
+localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30
@@ -84,7 +84,7 @@ revoke LOCK TABLES, ALTER on mysqltest.* from mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
-GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION
+GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
delete from mysql.user where user='mysqltest_1';
flush privileges;
@@ -157,6 +157,10 @@ select 1;
1
1
insert into mysql.user (host, user) values ('localhost', 'test11');
+Warnings:
+Warning 1364 Field 'ssl_cipher' doesn't have a default value
+Warning 1364 Field 'x509_issuer' doesn't have a default value
+Warning 1364 Field 'x509_subject' doesn't have a default value
insert into mysql.db (host, db, user, select_priv) values
('localhost', 'a%', 'test11', 'Y'), ('localhost', 'ab%', 'test11', 'Y');
alter table mysql.db order by db asc;
@@ -240,17 +244,19 @@ grant select on test.* to drop_user3@localhost;
grant select on *.* to drop_user4@localhost;
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
-ERROR HY000: Can't drop one or more of the requested users
revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost,
drop_user3@localhost, drop_user4@localhost;
+ERROR HY000: Can't revoke all privileges, grant for one or more of the requested users
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
+ERROR HY000: Operation DROP USER failed for 'drop_user1'@'localhost','drop_user2'@'localhost','drop_user3'@'localhost','drop_user4'@'localhost'
drop table t1;
grant usage on *.* to mysqltest_1@localhost identified by "password";
-grant select, update, insert on test.* to mysqltest@localhost;
+grant select, update, insert on test.* to mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' IDENTIFIED BY PASSWORD '*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19'
+GRANT SELECT, INSERT, UPDATE ON `test`.* TO 'mysqltest_1'@'localhost'
drop user mysqltest_1@localhost;
SET NAMES koi8r;
CREATE DATABASE ÂÄ;
@@ -274,6 +280,7 @@ Grants for ÀÚÅÒ@localhost
GRANT USAGE ON *.* TO 'ÀÚÅÒ'@'localhost'
GRANT SELECT (ËÏÌ) ON `ÂÄ`.`ÔÁÂ` TO 'ÀÚÅÒ'@'localhost'
REVOKE SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ FROM ÀÚÅÒ@localhost;
+DROP USER ÀÚÅÒ@localhost;
DROP DATABASE ÂÄ;
SET NAMES latin1;
USE test;
@@ -351,10 +358,10 @@ GRANT USAGE ON *.* TO 'grant_user'@'localhost'
GRANT INSERT (a, d, c, b) ON `test`.`t1` TO 'grant_user'@'localhost'
select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv;
Host Db User Table_name Column_name Column_priv
-localhost test grant_user t1 c Insert
localhost test grant_user t1 b Insert
-localhost test grant_user t1 a Insert
localhost test grant_user t1 d Insert
+localhost test grant_user t1 a Insert
+localhost test grant_user t1 c Insert
revoke ALL PRIVILEGES on t1 from grant_user@localhost;
show grants for grant_user@localhost;
Grants for grant_user@localhost
@@ -377,15 +384,17 @@ show grants for mysqltest_3@localhost;
Grants for mysqltest_3@localhost
GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost'
GRANT SELECT (b) ON `mysqltest_1`.`t2` TO 'mysqltest_3'@'localhost'
-GRANT SELECT (c) ON `mysqltest_2`.`t1` TO 'mysqltest_3'@'localhost'
GRANT UPDATE (a) ON `mysqltest_1`.`t1` TO 'mysqltest_3'@'localhost'
GRANT UPDATE (d) ON `mysqltest_2`.`t2` TO 'mysqltest_3'@'localhost'
+GRANT SELECT (c) ON `mysqltest_2`.`t1` TO 'mysqltest_3'@'localhost'
update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1;
ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for column 'q' in table 't1'
-update mysqltest_1.t1, mysqltest_2.t2 set d=20 where d=1;
+update mysqltest_1.t2, mysqltest_2.t2 set d=20 where d=1;
ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 'd' in table 't2'
+update mysqltest_1.t1, mysqltest_2.t2 set d=20 where d=1;
+ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 't1'
update mysqltest_2.t1, mysqltest_1.t2 set c=20 where b=1;
-ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for column 'c' in table 't1'
+ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't1'
update mysqltest_2.t1, mysqltest_2.t2 set d=10 where s=2;
ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 's' in table 't1'
update mysqltest_1.t1, mysqltest_2.t2 set a=10,d=10;
@@ -406,14 +415,14 @@ flush privileges;
use mysqltest_1;
update mysqltest_2.t1, mysqltest_2.t2 set c=500,d=600;
update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200;
-ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for column 'a' in table 't1'
+ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't1'
use mysqltest_2;
update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200;
-ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysqltest_1'
+ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't1'
update mysqltest_2.t1, mysqltest_1.t2 set c=100,b=200;
-ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysqltest_1'
+ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't2'
update mysqltest_1.t1, mysqltest_2.t2 set a=100,d=200;
-ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysqltest_1'
+ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for table 't1'
select t1.*,t2.* from mysqltest_1.t1,mysqltest_1.t2;
a q b r
10 2 1 2
@@ -427,6 +436,35 @@ delete from mysql.columns_priv where user="mysqltest_3";
flush privileges;
drop database mysqltest_1;
drop database mysqltest_2;
+SHOW PRIVILEGES;
+Privilege Context Comment
+Alter Tables To alter the table
+Alter routine Functions,Procedures To alter or drop stored functions/procedures
+Create Databases,Tables,Indexes To create new databases and tables
+Create routine Functions,Procedures To use CREATE FUNCTION/PROCEDURE
+Create temporary tables Databases To use CREATE TEMPORARY TABLE
+Create view Tables To create new views
+Create user Server Admin To create new users
+Delete Tables To delete existing rows
+Drop Databases,Tables To drop databases, tables, and views
+Execute Functions,Procedures To execute stored routines
+File File access on server To read and write files on the server
+Grant option Databases,Tables,Functions,Procedures To give to other users those privileges you possess
+Index Tables To create or drop indexes
+Insert Tables To insert data into tables
+Lock tables Databases To use LOCK TABLES (together with SELECT privilege)
+Process Server Admin To view the plain text of currently executing queries
+References Databases,Tables To have references on tables
+Reload Server Admin To reload or refresh tables, logs and privileges
+Replication client Server Admin To ask where the slave or master servers are
+Replication slave Server Admin To read binary log events from the master
+Select Tables To retrieve rows from table
+Show databases Server Admin To see all databases with SHOW DATABASES
+Show view Tables To see views with SHOW CREATE VIEW
+Shutdown Server Admin To shut down the server
+Super Server Admin To use KILL thread, SET GLOBAL, CHANGE MASTER, etc.
+Update Tables To update existing rows
+Usage Server Admin No privileges - allow connect only
create database mysqltest;
create table mysqltest.t1 (a int,b int,c int);
grant all on mysqltest.t1 to mysqltest_1@localhost;
diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result
index ada205f6f23..dd35d1c3dac 100644
--- a/mysql-test/r/grant2.result
+++ b/mysql-test/r/grant2.result
@@ -6,16 +6,42 @@ delete from mysql.db where user like 'mysqltest\_%';
delete from mysql.tables_priv where user like 'mysqltest\_%';
delete from mysql.columns_priv where user like 'mysqltest\_%';
flush privileges;
+grant all privileges on `my\_1`.* to mysqltest_1@localhost with grant option;
+grant create user on *.* to mysqltest_1@localhost;
+create user mysqltest_2@localhost;
+grant select on `my\_1`.* to mysqltest_2@localhost;
+grant select on `my\_1`.* to mysqltest_2@localhost identified by 'pass';
+ERROR 42000: You must have privileges to update tables in the mysql database to be able to change passwords for others
+grant update on mysql.* to mysqltest_1@localhost;
+grant select on `my\_1`.* to mysqltest_2@localhost identified by 'pass';
+grant select on `my\_1`.* to mysqltest_3@localhost;
+grant insert on mysql.* to mysqltest_1@localhost;
+grant select on `my\_1`.* to mysqltest_3@localhost;
+grant select on `my\_1`.* to mysqltest_4@localhost identified by 'pass';
+delete from mysql.user where user like 'mysqltest\_%';
+delete from mysql.db where user like 'mysqltest\_%';
+delete from mysql.tables_priv where user like 'mysqltest\_%';
+delete from mysql.columns_priv where user like 'mysqltest\_%';
+flush privileges;
grant all privileges on `my\_%`.* to mysqltest_1@localhost with grant option;
+grant create user on *.* to mysqltest_1@localhost;
select current_user();
current_user()
mysqltest_1@localhost
grant all privileges on `my\_1`.* to mysqltest_2@localhost with grant option;
grant all privileges on `my_%`.* to mysqltest_3@localhost with grant option;
ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'my_%'
+set @@sql_mode='NO_AUTO_CREATE_USER';
+select @@sql_mode;
+@@sql_mode
+NO_AUTO_CREATE_USER
+grant select on `my\_1`.* to mysqltest_4@localhost with grant option;
+ERROR 42000: Can't find any matching row in the user table
+grant select on `my\_1`.* to mysqltest_4@localhost identified by 'mypass'
+with grant option;
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
-GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
+GRANT CREATE USER ON *.* TO 'mysqltest_1'@'localhost'
GRANT ALL PRIVILEGES ON `my\_%`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION
show grants for mysqltest_2@localhost;
Grants for mysqltest_2@localhost
@@ -33,6 +59,7 @@ current_user()
mysqltest_1@localhost
show databases;
Database
+information_schema
mysqltest_1
test
grant all privileges on `mysqltest_1`.* to mysqltest_1@localhost with grant option;
@@ -56,9 +83,9 @@ GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
GRANT SELECT, INSERT ON `mysqltest`.* TO 'mysqltest_1'@'localhost'
insert into t1 values (1, 'I can''t change it!');
update t1 set data='I can change it!' where id = 1;
-ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest'
+ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for table 't1'
insert into t1 values (1, 'XXX') on duplicate key update data= 'I can change it!';
-ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest'
+ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for table 't1'
select * from t1;
id data
1 I can't change it!
@@ -80,6 +107,169 @@ delete from mysql.columns_priv where user like 'mysqltest\_%';
flush privileges;
drop database mysqltest;
use test;
+set sql_mode='maxdb';
+drop table if exists t1, t2;
+create table t1(c1 int);
+create table t2(c1 int, c2 int);
+create user 'mysqltest_1';
+create user 'mysqltest_1';
+ERROR HY000: Operation CREATE USER failed for 'mysqltest_1'@'%'
+create user 'mysqltest_2' identified by 'Mysqltest-2';
+create user 'mysqltest_3' identified by password 'fffffffffffffffffffffffffffffffffffffffff';
+grant select on *.* to 'mysqltest_2';
+grant insert on test.* to 'mysqltest_2';
+grant update on test.t1 to 'mysqltest_2';
+grant update (c2) on test.t2 to 'mysqltest_2';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+host user password
+% mysqltest_1
+% mysqltest_2 *BD447CBA355AF58578D3AE33BA2E2CD388BA08D1
+% mysqltest_3 fffffffffffffffffffffffffffffffffffffffff
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+host db user
+% test mysqltest_2
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+host db user table_name
+% test mysqltest_2 t1
+% test mysqltest_2 t2
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+host db user table_name column_name
+% test mysqltest_2 t2 c2
+show grants for 'mysqltest_1';
+Grants for mysqltest_1@%
+GRANT USAGE ON *.* TO 'mysqltest_1'@'%'
+show grants for 'mysqltest_2';
+Grants for mysqltest_2@%
+GRANT SELECT ON *.* TO 'mysqltest_2'@'%' IDENTIFIED BY PASSWORD '*BD447CBA355AF58578D3AE33BA2E2CD388BA08D1'
+GRANT INSERT ON "test".* TO 'mysqltest_2'@'%'
+GRANT UPDATE (c2) ON "test"."t2" TO 'mysqltest_2'@'%'
+GRANT UPDATE ON "test"."t1" TO 'mysqltest_2'@'%'
+drop user 'mysqltest_1';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+host user password
+% mysqltest_2 *BD447CBA355AF58578D3AE33BA2E2CD388BA08D1
+% mysqltest_3 fffffffffffffffffffffffffffffffffffffffff
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+host db user
+% test mysqltest_2
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+host db user table_name
+% test mysqltest_2 t1
+% test mysqltest_2 t2
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+host db user table_name column_name
+% test mysqltest_2 t2 c2
+show grants for 'mysqltest_1';
+ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host '%'
+rename user 'mysqltest_2' to 'mysqltest_1';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+host user password
+% mysqltest_1 *BD447CBA355AF58578D3AE33BA2E2CD388BA08D1
+% mysqltest_3 fffffffffffffffffffffffffffffffffffffffff
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+host db user
+% test mysqltest_1
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+host db user table_name
+% test mysqltest_1 t1
+% test mysqltest_1 t2
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+host db user table_name column_name
+% test mysqltest_1 t2 c2
+show grants for 'mysqltest_1';
+Grants for mysqltest_1@%
+GRANT SELECT ON *.* TO 'mysqltest_1'@'%' IDENTIFIED BY PASSWORD '*BD447CBA355AF58578D3AE33BA2E2CD388BA08D1'
+GRANT INSERT ON "test".* TO 'mysqltest_1'@'%'
+GRANT UPDATE (c2) ON "test"."t2" TO 'mysqltest_1'@'%'
+GRANT UPDATE ON "test"."t1" TO 'mysqltest_1'@'%'
+drop user 'mysqltest_1', 'mysqltest_3';
+drop user 'mysqltest_1';
+ERROR HY000: Operation DROP USER failed for 'mysqltest_1'@'%'
+drop table t1, t2;
+insert into mysql.db set user='mysqltest_1', db='%', host='%';
+flush privileges;
+show grants for 'mysqltest_1';
+ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host '%'
+revoke all privileges, grant option from 'mysqltest_1';
+ERROR HY000: Can't revoke all privileges, grant for one or more of the requested users
+drop user 'mysqltest_1';
+select host,db,user from mysql.db where user = 'mysqltest_1' order by host,db,user;
+host db user
+insert into mysql.tables_priv set host='%', db='test', user='mysqltest_1', table_name='t1';
+flush privileges;
+show grants for 'mysqltest_1';
+ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host '%'
+drop user 'mysqltest_1';
+select host,db,user,table_name from mysql.tables_priv where user = 'mysqltest_1' order by host,db,user,table_name;
+host db user table_name
+insert into mysql.columns_priv set host='%', db='test', user='mysqltest_1', table_name='t1', column_name='c1';
+flush privileges;
+show grants for 'mysqltest_1';
+ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host '%'
+drop user 'mysqltest_1';
+select host,db,user,table_name,column_name from mysql.columns_priv where user = 'mysqltest_1' order by host,db,user,table_name,column_name;
+host db user table_name column_name
+create user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+create user 'mysqltest_1', 'mysqltest_2' identified by 'Mysqltest-2', 'mysqltest_3' identified by password 'fffffffffffffffffffffffffffffffffffffffff';
+rename user 'mysqltest_1' to 'mysqltest_1a', 'mysqltest_2' TO 'mysqltest_2a', 'mysqltest_3' TO 'mysqltest_3a';
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+ERROR HY000: Operation DROP USER failed for 'mysqltest_1'@'%','mysqltest_2'@'%','mysqltest_3'@'%'
+drop user 'mysqltest_1a', 'mysqltest_2a', 'mysqltest_3a';
+create user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+create user 'mysqltest_1a', 'mysqltest_2', 'mysqltest_3a';
+ERROR HY000: Operation CREATE USER failed for 'mysqltest_2'@'%'
+rename user 'mysqltest_1a' to 'mysqltest_1b', 'mysqltest_2a' TO 'mysqltest_2b', 'mysqltest_3a' TO 'mysqltest_3b';
+ERROR HY000: Operation RENAME USER failed for 'mysqltest_2a'@'%'
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+drop user 'mysqltest_1b', 'mysqltest_2b', 'mysqltest_3b';
+ERROR HY000: Operation DROP USER failed for 'mysqltest_2b'@'%'
+create user 'mysqltest_2' identified by 'Mysqltest-2';
+drop user 'mysqltest_2' identified by 'Mysqltest-2';
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'identified by 'Mysqltest-2'' at line 1
+create user '%@b'@'b';
+show grants for '%@b'@'b';
+Grants for %@b@b
+GRANT USAGE ON *.* TO '%@b'@'b'
+grant select on mysql.* to '%@b'@'b';
+show grants for '%@b'@'b';
+Grants for %@b@b
+GRANT USAGE ON *.* TO '%@b'@'b'
+GRANT SELECT ON "mysql".* TO '%@b'@'b'
+rename user '%@b'@'b' to '%@a'@'a';
+show grants for '%@b'@'b';
+ERROR 42000: There is no such grant defined for user '%@b' on host 'b'
+show grants for '%@a'@'a';
+Grants for %@a@a
+GRANT USAGE ON *.* TO '%@a'@'a'
+GRANT SELECT ON "mysql".* TO '%@a'@'a'
+drop user '%@a'@'a';
+create user mysqltest_2@localhost;
+grant create user on *.* to mysqltest_2@localhost;
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 'user'
+create user mysqltest_A@'%';
+rename user mysqltest_A@'%' to mysqltest_B@'%';
+drop user mysqltest_B@'%';
+drop user mysqltest_2@localhost;
+create user mysqltest_3@localhost;
+grant INSERT,DELETE,UPDATE on mysql.* to mysqltest_3@localhost;
+show grants;
+Grants for mysqltest_3@localhost
+GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost'
+GRANT INSERT, UPDATE, DELETE ON `mysql`.* TO 'mysqltest_3'@'localhost'
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 'user'
+insert into mysql.user set host='%', user='mysqltest_B';
+Warnings:
+Warning 1364 Field 'ssl_cipher' doesn't have a default value
+Warning 1364 Field 'x509_issuer' doesn't have a default value
+Warning 1364 Field 'x509_subject' doesn't have a default value
+create user mysqltest_A@'%';
+rename user mysqltest_B@'%' to mysqltest_C@'%';
+drop user mysqltest_C@'%';
+drop user mysqltest_3@localhost;
+set @@sql_mode='';
create database mysqltest_1;
create table mysqltest_1.t1 (i int);
insert into mysqltest_1.t1 values (1),(2),(3);
diff --git a/mysql-test/r/grant3.result b/mysql-test/r/grant3.result
new file mode 100644
index 00000000000..6193c4fd49d
--- /dev/null
+++ b/mysql-test/r/grant3.result
@@ -0,0 +1,18 @@
+SET NAMES binary;
+drop table if exists t1;
+delete from mysql.user where user like 'mysqltest\_%';
+delete from mysql.db where user like 'mysqltest\_%';
+delete from mysql.tables_priv where user like 'mysqltest\_%';
+delete from mysql.columns_priv where user like 'mysqltest\_%';
+flush privileges;
+create user mysqltest_1@localhost;
+grant create user on *.* to mysqltest_1@localhost;
+grant select on `my\_1`.* to mysqltest_1@localhost with grant option;
+grant select on `my\_1`.* to mysqltest_2@localhost;
+ERROR 42000: You are not allowed to create a user with GRANT
+create user mysqltest_2@localhost;
+delete from mysql.user where user like 'mysqltest\_%';
+delete from mysql.db where user like 'mysqltest\_%';
+delete from mysql.tables_priv where user like 'mysqltest\_%';
+delete from mysql.columns_priv where user like 'mysqltest\_%';
+flush privileges;
diff --git a/mysql-test/r/grant_cache.result b/mysql-test/r/grant_cache.result
index d905e9319fd..2a1170ee751 100644
--- a/mysql-test/r/grant_cache.result
+++ b/mysql-test/r/grant_cache.result
@@ -59,7 +59,7 @@ Variable_name Value
Qcache_hits 0
show status like "Qcache_not_cached";
Variable_name Value
-Qcache_not_cached 0
+Qcache_not_cached 5
select "user1";
user1
user1
@@ -71,7 +71,7 @@ Variable_name Value
Qcache_hits 0
show status like "Qcache_not_cached";
Variable_name Value
-Qcache_not_cached 1
+Qcache_not_cached 9
select * from t1;
a b c
1 1 1
@@ -84,7 +84,7 @@ Variable_name Value
Qcache_hits 1
show status like "Qcache_not_cached";
Variable_name Value
-Qcache_not_cached 1
+Qcache_not_cached 12
select a from t1 ;
a
1
@@ -97,7 +97,7 @@ Variable_name Value
Qcache_hits 2
show status like "Qcache_not_cached";
Variable_name Value
-Qcache_not_cached 1
+Qcache_not_cached 15
select c from t1;
c
1
@@ -110,7 +110,7 @@ Variable_name Value
Qcache_hits 3
show status like "Qcache_not_cached";
Variable_name Value
-Qcache_not_cached 1
+Qcache_not_cached 18
show grants for current_user();
Grants for @localhost
GRANT USAGE ON *.* TO ''@'localhost'
@@ -143,7 +143,7 @@ Variable_name Value
Qcache_hits 7
show status like "Qcache_not_cached";
Variable_name Value
-Qcache_not_cached 2
+Qcache_not_cached 22
select "user3";
user3
user3
@@ -167,7 +167,7 @@ Variable_name Value
Qcache_hits 7
show status like "Qcache_not_cached";
Variable_name Value
-Qcache_not_cached 7
+Qcache_not_cached 30
select "user4";
user4
user4
@@ -197,7 +197,7 @@ Variable_name Value
Qcache_hits 8
show status like "Qcache_not_cached";
Variable_name Value
-Qcache_not_cached 8
+Qcache_not_cached 34
set names binary;
delete from mysql.user where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
delete from mysql.db where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
diff --git a/mysql-test/r/greedy_optimizer.result b/mysql-test/r/greedy_optimizer.result
new file mode 100644
index 00000000000..1da49fbedb0
--- /dev/null
+++ b/mysql-test/r/greedy_optimizer.result
@@ -0,0 +1,657 @@
+drop table if exists t1,t2,t3,t4,t5,t6,t7;
+create table t1 (
+c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer,
+primary key (c11)
+);
+create table t2 (
+c21 integer,c22 integer,c23 integer,c24 integer,c25 integer,c26 integer
+);
+create table t3 (
+c31 integer,c32 integer,c33 integer,c34 integer,c35 integer,c36 integer,
+primary key (c31)
+);
+create table t4 (
+c41 integer,c42 integer,c43 integer,c44 integer,c45 integer,c46 integer
+);
+create table t5 (
+c51 integer,c52 integer,c53 integer,c54 integer,c55 integer,c56 integer,
+primary key (c51)
+);
+create table t6 (
+c61 integer,c62 integer,c63 integer,c64 integer,c65 integer,c66 integer
+);
+create table t7 (
+c71 integer,c72 integer,c73 integer,c74 integer,c75 integer,c76 integer,
+primary key (c71)
+);
+insert into t1 values (1,2,3,4,5,6);
+insert into t1 values (2,2,3,4,5,6);
+insert into t1 values (3,2,3,4,5,6);
+insert into t2 values (1,2,3,4,5,6);
+insert into t2 values (2,2,3,4,5,6);
+insert into t2 values (3,2,3,4,5,6);
+insert into t2 values (4,2,3,4,5,6);
+insert into t2 values (5,2,3,4,5,6);
+insert into t2 values (6,2,3,4,5,6);
+insert into t3 values (1,2,3,4,5,6);
+insert into t3 values (2,2,3,4,5,6);
+insert into t3 values (3,2,3,4,5,6);
+insert into t3 values (4,2,3,4,5,6);
+insert into t3 values (5,2,3,4,5,6);
+insert into t3 values (6,2,3,4,5,6);
+insert into t3 values (7,2,3,4,5,6);
+insert into t3 values (8,2,3,4,5,6);
+insert into t3 values (9,2,3,4,5,6);
+insert into t4 values (1,2,3,4,5,6);
+insert into t4 values (2,2,3,4,5,6);
+insert into t4 values (3,2,3,4,5,6);
+insert into t4 values (4,2,3,4,5,6);
+insert into t4 values (5,2,3,4,5,6);
+insert into t4 values (6,2,3,4,5,6);
+insert into t4 values (7,2,3,4,5,6);
+insert into t4 values (8,2,3,4,5,6);
+insert into t4 values (9,2,3,4,5,6);
+insert into t4 values (10,2,3,4,5,6);
+insert into t4 values (11,2,3,4,5,6);
+insert into t4 values (12,2,3,4,5,6);
+insert into t5 values (1,2,3,4,5,6);
+insert into t5 values (2,2,3,4,5,6);
+insert into t5 values (3,2,3,4,5,6);
+insert into t5 values (4,2,3,4,5,6);
+insert into t5 values (5,2,3,4,5,6);
+insert into t5 values (6,2,3,4,5,6);
+insert into t5 values (7,2,3,4,5,6);
+insert into t5 values (8,2,3,4,5,6);
+insert into t5 values (9,2,3,4,5,6);
+insert into t5 values (10,2,3,4,5,6);
+insert into t5 values (11,2,3,4,5,6);
+insert into t5 values (12,2,3,4,5,6);
+insert into t5 values (13,2,3,4,5,6);
+insert into t5 values (14,2,3,4,5,6);
+insert into t5 values (15,2,3,4,5,6);
+insert into t6 values (1,2,3,4,5,6);
+insert into t6 values (2,2,3,4,5,6);
+insert into t6 values (3,2,3,4,5,6);
+insert into t6 values (4,2,3,4,5,6);
+insert into t6 values (5,2,3,4,5,6);
+insert into t6 values (6,2,3,4,5,6);
+insert into t6 values (7,2,3,4,5,6);
+insert into t6 values (8,2,3,4,5,6);
+insert into t6 values (9,2,3,4,5,6);
+insert into t6 values (10,2,3,4,5,6);
+insert into t6 values (11,2,3,4,5,6);
+insert into t6 values (12,2,3,4,5,6);
+insert into t6 values (13,2,3,4,5,6);
+insert into t6 values (14,2,3,4,5,6);
+insert into t6 values (15,2,3,4,5,6);
+insert into t6 values (16,2,3,4,5,6);
+insert into t6 values (17,2,3,4,5,6);
+insert into t6 values (18,2,3,4,5,6);
+insert into t7 values (1,2,3,4,5,6);
+insert into t7 values (2,2,3,4,5,6);
+insert into t7 values (3,2,3,4,5,6);
+insert into t7 values (4,2,3,4,5,6);
+insert into t7 values (5,2,3,4,5,6);
+insert into t7 values (6,2,3,4,5,6);
+insert into t7 values (7,2,3,4,5,6);
+insert into t7 values (8,2,3,4,5,6);
+insert into t7 values (9,2,3,4,5,6);
+insert into t7 values (10,2,3,4,5,6);
+insert into t7 values (11,2,3,4,5,6);
+insert into t7 values (12,2,3,4,5,6);
+insert into t7 values (13,2,3,4,5,6);
+insert into t7 values (14,2,3,4,5,6);
+insert into t7 values (15,2,3,4,5,6);
+insert into t7 values (16,2,3,4,5,6);
+insert into t7 values (17,2,3,4,5,6);
+insert into t7 values (18,2,3,4,5,6);
+insert into t7 values (19,2,3,4,5,6);
+insert into t7 values (20,2,3,4,5,6);
+insert into t7 values (21,2,3,4,5,6);
+select @@optimizer_search_depth;
+@@optimizer_search_depth
+62
+select @@optimizer_prune_level;
+@@optimizer_prune_level
+1
+set optimizer_search_depth=63;
+select @@optimizer_search_depth;
+@@optimizer_search_depth
+63
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+set optimizer_prune_level=0;
+select @@optimizer_prune_level;
+@@optimizer_prune_level
+0
+set optimizer_search_depth=0;
+select @@optimizer_search_depth;
+@@optimizer_search_depth
+0
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 274.418727
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 274.418727
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 274.418727
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 274.418727
+set optimizer_search_depth=1;
+select @@optimizer_search_depth;
+@@optimizer_search_depth
+1
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+set optimizer_search_depth=62;
+select @@optimizer_search_depth;
+@@optimizer_search_depth
+62
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 274.418727
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 274.418727
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 274.418727
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.c21 1 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 274.418727
+set optimizer_prune_level=1;
+select @@optimizer_prune_level;
+@@optimizer_prune_level
+1
+set optimizer_search_depth=0;
+select @@optimizer_search_depth;
+@@optimizer_search_depth
+0
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+set optimizer_search_depth=1;
+select @@optimizer_search_depth;
+@@optimizer_search_depth
+1
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+set optimizer_search_depth=62;
+select @@optimizer_search_depth;
+@@optimizer_search_depth
+62
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.c22 1
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t4.c42 1
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t6.c62 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 821.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using index
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using index
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using index
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where
+1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t1.c12 1 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 12 Using where
+1 SIMPLE t5 eq_ref PRIMARY PRIMARY 4 test.t1.c14 1 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 18 Using where
+1 SIMPLE t7 eq_ref PRIMARY PRIMARY 4 test.t1.c16 1 Using where
+show status like 'Last_query_cost';
+Variable_name Value
+Last_query_cost 794.837037
+drop table t1,t2,t3,t4,t5,t6,t7;
diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result
index b0c00a51722..5cee9b15dcd 100644
--- a/mysql-test/r/group_by.result
+++ b/mysql-test/r/group_by.result
@@ -288,7 +288,7 @@ explain extended select sql_big_result spid,sum(userid) from t1 group by spid de
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using filesort
Warnings:
-Note 1003 select sql_big_result test.t1.spID AS `spid`,sum(test.t1.userID) AS `sum(userid)` from test.t1 group by test.t1.spID desc
+Note 1003 select sql_big_result `test`.`t1`.`spID` AS `spid`,sum(`test`.`t1`.`userID`) AS `sum(userid)` from `test`.`t1` group by `test`.`t1`.`spID` desc
explain select sql_big_result spid,sum(userid) from t1 group by spid desc order by null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using filesort
@@ -440,12 +440,12 @@ create table t2 (user_id integer not null, date date);
insert into t2 values (1, '2002-06-09'),(2, '2002-06-09'),(1, '2002-06-09'),(3, '2002-06-09'),(4, '2002-06-09'),(4, '2002-06-09');
select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender;
gender dist_count percentage
-F 3 60.00
-M 1 20.00
+F 3 60.00000
+M 1 20.00000
select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender order by percentage;
gender dist_count percentage
-M 1 20.00
-F 3 60.00
+M 1 20.00000
+F 3 60.00000
drop table t1,t2;
CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID
));
@@ -696,7 +696,7 @@ from t1 x3, t1 x4, t1 C, t1 D where x3.a < 3 and x4.a < 4 and D.a < 4;
delete from t2 where a = 2 and b = 'val-2' order by a,b,c,d limit 30;
explain select c from t2 where a = 2 and b = 'val-2' group by c;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ref PRIMARY,a PRIMARY 400 const,const 6 Using where
+1 SIMPLE t2 ref PRIMARY,a PRIMARY 402 const,const 6 Using where
select c from t2 where a = 2 and b = 'val-2' group by c;
c
val-74
diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result
new file mode 100644
index 00000000000..766e43b2299
--- /dev/null
+++ b/mysql-test/r/group_min_max.result
@@ -0,0 +1,1963 @@
+drop table if exists t1;
+create table t1 (
+a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' '
+);
+insert into t1 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
+('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
+('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
+('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
+('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'),
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
+('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
+('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
+('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
+('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4');
+create index idx_t1_0 on t1 (a1);
+create index idx_t1_1 on t1 (a1,a2,b,c);
+create index idx_t1_2 on t1 (a1,a2,b);
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Table is already up to date
+drop table if exists t2;
+create table t2 (
+a1 char(64), a2 char(64) not null, b char(16), c char(16), d char(16), dummy char(64) default ' '
+);
+insert into t2 select * from t1;
+insert into t2 (a1, a2, b, c, d) values
+('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'),
+('a','a','a',NULL,'xyz'),
+('a','a','b',NULL,'xyz'),
+('a','b','a',NULL,'xyz'),
+('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'),
+('d','b','b',NULL,'xyz'),
+('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),
+('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),
+('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'),
+('a','a','a',NULL,'xyz'),
+('a','a','b',NULL,'xyz'),
+('a','b','a',NULL,'xyz'),
+('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'),
+('d','b','b',NULL,'xyz'),
+('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),
+('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz');
+create index idx_t2_0 on t2 (a1);
+create index idx_t2_1 on t2 (a1,a2,b,c);
+create index idx_t2_2 on t2 (a1,a2,b);
+analyze table t2;
+Table Op Msg_type Msg_text
+test.t2 analyze status Table is already up to date
+drop table if exists t3;
+create table t3 (
+a1 char(1), a2 char(1), b char(1), c char(4) not null, d char(3), dummy char(1) default ' '
+);
+insert into t3 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
+insert into t3 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
+insert into t3 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
+insert into t3 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
+create index idx_t3_0 on t3 (a1);
+create index idx_t3_1 on t3 (a1,a2,b,c);
+create index idx_t3_2 on t3 (a1,a2,b);
+analyze table t3;
+Table Op Msg_type Msg_text
+test.t3 analyze status Table is already up to date
+explain select a1, min(a2) from t1 group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 65 NULL 5 Using index for group-by
+explain select a1, max(a2) from t1 group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 65 NULL 5 Using index for group-by
+explain select a1, min(a2), max(a2) from t1 group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 65 NULL 5 Using index for group-by
+explain select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by
+explain select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by
+explain select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 # NULL 21 Using index for group-by
+explain select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 65 NULL 5 Using index for group-by
+explain select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by
+explain select min(a2) from t1 group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 65 NULL 5 Using index for group-by
+explain select a2, min(c), max(c) from t1 group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by
+select a1, min(a2) from t1 group by a1;
+a1 min(a2)
+a a
+b a
+c a
+d a
+select a1, max(a2) from t1 group by a1;
+a1 max(a2)
+a b
+b b
+c b
+d b
+select a1, min(a2), max(a2) from t1 group by a1;
+a1 min(a2) max(a2)
+a a b
+b a b
+c a b
+d a b
+select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a a111 d111
+a a b e112 h112
+a b a i121 l121
+a b b m122 p122
+b a a a211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a a a311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a a411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b;
+a1 a2 b max(c) min(c)
+a a a d111 a111
+a a b h112 e112
+a b a l121 i121
+a b b p122 m122
+b a a d211 a211
+b a b h212 e212
+b b a l221 i221
+b b b p222 m222
+c a a d311 a311
+c a b h312 e312
+c b a l321 i321
+c b b p322 m322
+d a a d411 a411
+d a b h412 e412
+d b a l421 i421
+d b b p422 m422
+select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b;
+a1 a2 b max(c) min(c)
+a a NULL a999 a777
+a a a d111 a111
+a a b h112 e112
+a b a l121 i121
+a b b p122 m122
+b a a d211 a211
+b a b h212 e212
+b b a l221 i221
+b b b p222 m222
+c a NULL c999 c777
+c a a d311 a311
+c a b h312 e312
+c b a l321 i321
+c b b p322 m322
+d a a d411 a411
+d a b h412 e412
+d b a l421 i421
+d b b p422 m422
+e a a NULL NULL
+e a b NULL NULL
+select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1;
+min(a2) a1 max(a2) min(a2) a1
+a a b a a
+a b b a b
+a c b a c
+a d b a d
+select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b;
+a1 b min(c) a1 max(c) b a2 max(c) max(c)
+a a a111 a d111 a a d111 d111
+a b e112 a h112 b a h112 h112
+a a i121 a l121 a b l121 l121
+a b m122 a p122 b b p122 p122
+b a a211 b d211 a a d211 d211
+b b e212 b h212 b a h212 h212
+b a i221 b l221 a b l221 l221
+b b m222 b p222 b b p222 p222
+c a a311 c d311 a a d311 d311
+c b e312 c h312 b a h312 h312
+c a i321 c l321 a b l321 l321
+c b m322 c p322 b b p322 p322
+d a a411 d d411 a a d411 d411
+d b e412 d h412 b a h412 h412
+d a i421 d l421 a b l421 l421
+d b m422 d p422 b b p422 p422
+select min(a2) from t1 group by a1;
+min(a2)
+a
+a
+a
+a
+select a2, min(c), max(c) from t1 group by a1,a2,b;
+a2 min(c) max(c)
+a a111 d111
+a e112 h112
+b i121 l121
+b m122 p122
+a a211 d211
+a e212 h212
+b i221 l221
+b m222 p222
+a a311 d311
+a e312 h312
+b i321 l321
+b m322 p322
+a a411 d411
+a e412 h412
+b i421 l421
+b m422 p422
+explain select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by
+explain select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by
+explain select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by
+explain select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 13 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 12 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 12 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 16 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 18 Using where; Using index for group-by
+explain select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 18 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 9 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 9 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 9 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 9 Using where; Using index for group-by
+explain select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 16 Using where; Using index for group-by
+explain select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 13 Using where; Using index for group-by
+select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a a111 d111
+a a b e112 h112
+a b a i121 l121
+a b b m122 p122
+b a a a211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a a a311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
+a1 a2 b min(c) max(c)
+b a a a211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a a a311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a a411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+a1 a2 b max(c)
+a a a d111
+a a b h112
+a b a l121
+a b b p122
+c a a d311
+c a b h312
+c b a l321
+c b b p322
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+a1 max(c)
+a d111
+a h112
+a l121
+a p122
+c d311
+c h312
+c l321
+c p322
+d d411
+d h412
+d l421
+d p422
+select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a a111 d111
+a a b e112 h112
+b a a a211 d211
+b a b e212 h212
+c a a a311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a a411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+a1 a2 b max(c)
+b a a d211
+b a b h212
+b b a l221
+b b b p222
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+a1 a2 b min(c) max(c)
+b a a a211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+d a a a411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+a1 a2 b max(c)
+a b a l121
+a b b p122
+b b a l221
+b b b p222
+c b a l321
+c b b p322
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a b a i121 l121
+a b b m122 p122
+b b a i221 l221
+b b b m222 p222
+c b a i321 l321
+c b b m322 p322
+d b a i421 l421
+d b b m422 p422
+select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
+a1 min(c) max(c)
+b a211 d211
+b e212 h212
+b i221 l221
+b m222 p222
+c a311 d311
+c e312 h312
+c i321 l321
+c m322 p322
+d a411 d411
+d e412 h412
+d i421 l421
+d m422 p422
+select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b;
+a1 max(c)
+a d111
+a h112
+a l121
+a p122
+b d211
+b h212
+b l221
+b p222
+d d411
+d h412
+d l421
+d p422
+select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b;
+a1 a2 b max(c)
+a a NULL a999
+a a a d111
+a a b h112
+a b a l121
+a b b p122
+b a a d211
+b a b h212
+b b a l221
+b b b p222
+c a NULL c999
+c a a d311
+c a b h312
+c b a l321
+c b b p322
+select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a NULL a777 a999
+a a a a111 d111
+a a b e112 h112
+a b a i121 l121
+a b b m122 p122
+b a a a211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a NULL c777 c999
+c a a a311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
+a1 a2 b min(c) max(c)
+b a a a211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a NULL c777 c999
+c a a a311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a a411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+e a a NULL NULL
+e a b NULL NULL
+select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+a1 a2 b max(c)
+a a NULL a999
+a a a d111
+a a b h112
+a b a l121
+a b b p122
+c a NULL c999
+c a a d311
+c a b h312
+c b a l321
+c b b p322
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+e a a NULL
+e a b NULL
+select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+a1 max(c)
+a a999
+a d111
+a h112
+a l121
+a p122
+c c999
+c d311
+c h312
+c l321
+c p322
+d d411
+d h412
+d l421
+d p422
+e NULL
+e NULL
+select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a NULL a777 a999
+a a a a111 d111
+a a b e112 h112
+b a a a211 d211
+b a b e212 h212
+c a NULL c777 c999
+c a a a311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a a411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+e a a NULL NULL
+e a b NULL NULL
+select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+a1 a2 b max(c)
+b a a d211
+b a b h212
+b b a l221
+b b b p222
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+a1 a2 b min(c) max(c)
+b a a a211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+d a a a411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+a1 a2 b max(c)
+a b a l121
+a b b p122
+b b a l221
+b b b p222
+c b a l321
+c b b p322
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a b a i121 l121
+a b b m122 p122
+b b a i221 l221
+b b b m222 p222
+c b a i321 l321
+c b b m322 p322
+d b a i421 l421
+d b b m422 p422
+select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
+a1 min(c) max(c)
+b a211 d211
+b e212 h212
+b i221 l221
+b m222 p222
+c c777 c999
+c a311 d311
+c e312 h312
+c i321 l321
+c m322 p322
+d a411 d411
+d e412 h412
+d i421 l421
+d m422 p422
+e NULL NULL
+e NULL NULL
+select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b;
+a1 max(c)
+a a999
+a d111
+a h112
+a l121
+a p122
+b d211
+b h212
+b l221
+b p222
+d d411
+d h412
+d l421
+d p422
+explain select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 5 Using where; Using index for group-by
+explain select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 5 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 9 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 9 Using where; Using index for group-by
+explain select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 9 Using where; Using index for group-by
+explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 5 Using where; Using index for group-by
+explain select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 5 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 10 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by
+explain select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 10 Using where; Using index for group-by
+explain select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t3 range NULL idx_t3_1 6 NULL 4 Using where; Using index for group-by
+explain select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t3 range NULL idx_t3_1 6 NULL 4 Using where; Using index for group-by
+select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
+a1 a2 b max(c) min(c)
+a a b h112 e112
+b a b h212 e212
+c a b h312 e312
+d a b h412 e412
+select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
+a1 max(c) min(c)
+a h112 e112
+b h212 e212
+c h312 e312
+d h412 e412
+select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2;
+a1 a2 b max(c)
+a a b h112
+a b b p122
+b a b h212
+b b b p222
+c a b h312
+c b b p322
+d a b h412
+d b b p422
+select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2;
+a1 a2 b min(c) max(c)
+a a b e112 h112
+a b b m122 p122
+b a b e212 h212
+b b b m222 p222
+c a b e312 h312
+c b b m322 p322
+d a b e412 h412
+d b b m422 p422
+select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2;
+a1 a2 max(c)
+a a h112
+a b p122
+b a h212
+b b p222
+c a h312
+c b p322
+d a h412
+d b p422
+select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
+a1 a2 b max(c) min(c)
+a a b h112 e112
+b a b h212 e212
+c a b h312 e312
+d a b h412 e412
+e a b NULL NULL
+select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
+a1 max(c) min(c)
+a h112 e112
+b h212 e212
+c h312 e312
+d h412 e412
+e NULL NULL
+select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2;
+a1 a2 b max(c)
+a a b h112
+a b b p122
+b a b h212
+b b b p222
+c a b h312
+c b b p322
+d a b h412
+d b b p422
+e a b NULL
+select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2;
+a1 a2 b min(c) max(c)
+a a b e112 h112
+a b b m122 p122
+b a b e212 h212
+b b b m222 p222
+c a b e312 h312
+c b b m322 p322
+d a b e412 h412
+d b b m422 p422
+e a b NULL NULL
+select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2;
+a1 a2 max(c)
+a a h112
+a b p122
+b a h212
+b b p222
+c a h312
+c b p322
+d a h412
+d b p422
+e a NULL
+select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
+a1 a2 b max(c) min(c)
+a a b h112 e112
+b a b h212 e212
+c a b h312 e312
+select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
+a1 max(c) min(c)
+a h112 e112
+b h212 e212
+c h312 e312
+explain select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 5 Using where; Using index for group-by
+explain select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 5 Using where; Using index for group-by
+explain select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by
+explain select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 10 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 10 Using where; Using index for group-by
+select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1;
+a1 a2 b min(c)
+a a NULL a777
+c a NULL c777
+select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1;
+a1 a2 b max(c)
+a a NULL a999
+c a NULL c999
+select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2;
+a1 a2 b min(c)
+a a NULL a777
+c a NULL c777
+select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2;
+a1 a2 b max(c)
+a a NULL a999
+c a NULL c999
+select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
+a1 a2 b min(c) max(c)
+a a NULL a777 a999
+c a NULL c777 c999
+select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
+a1 a2 b min(c) max(c)
+a a NULL a777 a999
+c a NULL c777 c999
+explain select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b;
+a1 a2 b max(c)
+a a a d111
+a a b h112
+a b a l121
+a b b p122
+b a a d211
+b a b h212
+b b a l221
+b b b p222
+c a a d311
+c a b h312
+c b a l321
+c b b p322
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a b111 d111
+a a b e112 h112
+a b a i121 l121
+a b b m122 p122
+b a a b211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a a b311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a b411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b;
+a1 a2 b max(c)
+a a b h112
+a b a l121
+a b b p122
+b a b h212
+b b a l221
+b b b p222
+c a b h312
+c b a l321
+c b b p322
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a b g112 h112
+a b a i121 l121
+a b b m122 p122
+b a b f212 h212
+b b a i221 l221
+b b b m222 p222
+c a b f312 h312
+c b a i321 l321
+c b b m322 p322
+d a b f412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b;
+a1 a2 b max(c)
+select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b;
+a1 a2 b max(c)
+a a a d111
+a a b h112
+a b a k121
+b a a d211
+b a b h212
+b b a k221
+c a a d311
+c a b h312
+c b a j321
+d a a d411
+d a b h412
+d b a j421
+select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a a111 d111
+a a b e112 h112
+a b a i121 k121
+b a a a211 d211
+b a b e212 h212
+b b a i221 k221
+c a a a311 d311
+c a b e312 h312
+c b a i321 j321
+d a a a411 d411
+d a b e412 h412
+d b a i421 j421
+select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+a1 a2 b max(c)
+a a a d111
+a a b h112
+a b a l121
+a b b p122
+b a a d211
+b a b h212
+b b a l221
+b b b p222
+c a a d311
+c a b h312
+c b a l321
+c b b p322
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a b111 d111
+a a b e112 h112
+a b a i121 l121
+a b b m122 p122
+b a a b211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a a b311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a b411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+a1 a2 b max(c)
+a a a d111
+a a b h112
+a b a l121
+a b b p122
+b a a d211
+b a b h212
+b b a l221
+b b b p222
+c a a d311
+c a b h312
+c b a l321
+c b b p322
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a a111 d111
+a a b e112 h112
+a b a i121 l121
+a b b m122 p122
+b a a a211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a a a311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a a411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a c111 d111
+a a b e112 g112
+b a a b211 d211
+b a b e212 f212
+c a a b311 d311
+c a b e312 f312
+d a a b411 d411
+d a b e412 f412
+select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a a111 c111
+b a a a211 c211
+c a a a311 c311
+d a a a411 c411
+d a b g412 g412
+d b a k421 k421
+select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a c111 d111
+a a b e112 h112
+b a a b211 d211
+b a b e212 h212
+c a a b311 d311
+c a b e312 h312
+d a a b411 d411
+d a b e412 h412
+select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a b111 d111
+a a b e112 h112
+b a a b211 d211
+b a b e212 h212
+c a a b311 d311
+c a b e312 h312
+d a a b411 d411
+d a b e412 h412
+select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b;
+a1 a2 b max(c)
+a a a d111
+a a b h112
+a b a l121
+a b b p122
+b a a d211
+b a b h212
+b b a l221
+b b b p222
+c a NULL c999
+c a a d311
+c a b h312
+c b a l321
+c b b p322
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a b111 d111
+a a b e112 h112
+a b a i121 l121
+a b b m122 p122
+b a a b211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a NULL c777 c999
+c a a b311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a b411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b;
+a1 a2 b max(c)
+a a b h112
+a b a l121
+a b b p122
+b a b h212
+b b a l221
+b b b p222
+c a b h312
+c b a l321
+c b b p322
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a b g112 h112
+a b a i121 l121
+a b b m122 p122
+b a b f212 h212
+b b a i221 l221
+b b b m222 p222
+c a b f312 h312
+c b a i321 l321
+c b b m322 p322
+d a b f412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b;
+a1 a2 b max(c)
+select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b;
+a1 a2 b max(c)
+a a NULL a999
+a a a d111
+a a b h112
+a b a k121
+b a a d211
+b a b h212
+b b a k221
+c a NULL c999
+c a a d311
+c a b h312
+c b a j321
+d a a d411
+d a b h412
+d b a j421
+select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a NULL a777 a999
+a a a a111 d111
+a a b e112 h112
+a b a i121 k121
+b a a a211 d211
+b a b e212 h212
+b b a i221 k221
+c a NULL c777 c999
+c a a a311 d311
+c a b e312 h312
+c b a i321 j321
+d a a a411 d411
+d a b e412 h412
+d b a i421 j421
+select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+a1 a2 b max(c)
+a a a d111
+a a b h112
+a b a l121
+a b b p122
+b a a d211
+b a b h212
+b b a l221
+b b b p222
+c a NULL c999
+c a a d311
+c a b h312
+c b a l321
+c b b p322
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a b111 d111
+a a b e112 h112
+a b a i121 l121
+a b b m122 p122
+b a a b211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a NULL c777 c999
+c a a b311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a b411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+a1 a2 b max(c)
+a a NULL a999
+a a a d111
+a a b h112
+a b a l121
+a b b p122
+b a a d211
+b a b h212
+b b a l221
+b b b p222
+c a NULL c999
+c a a d311
+c a b h312
+c b a l321
+c b b p322
+d a a d411
+d a b h412
+d b a l421
+d b b p422
+select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a NULL a777 a999
+a a a a111 d111
+a a b e112 h112
+a b a i121 l121
+a b b m122 p122
+b a a a211 d211
+b a b e212 h212
+b b a i221 l221
+b b b m222 p222
+c a NULL c777 c999
+c a a a311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a a411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a c111 d111
+a a b e112 g112
+b a a b211 d211
+b a b e212 f212
+c a NULL c777 c999
+c a a b311 d311
+c a b e312 f312
+d a a b411 d411
+d a b e412 f412
+select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a NULL a777 a999
+a a a a111 c111
+b a a a211 c211
+c a a a311 c311
+d a a a411 c411
+d a b g412 g412
+d b a k421 k421
+select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a c111 d111
+a a b e112 h112
+b a a b211 d211
+b a b e212 h212
+c a NULL c777 c999
+c a a b311 d311
+c a b e312 h312
+d a a b411 d411
+d a b e412 h412
+explain select a1,a2,b,min(c),max(c) from t1
+where exists ( select * from t2 where t2.c = t1.c )
+group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index
+2 DEPENDENT SUBQUERY t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index
+explain select a1,a2,b,min(c),max(c) from t1
+where exists ( select * from t2 where t2.c > 'b1' )
+group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by
+2 SUBQUERY t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index
+explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 163 NULL 14 Using where; Using index for group-by
+explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 163 NULL 14 Using where; Using index for group-by
+explain select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by
+explain select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 16 Using where; Using index for group-by
+select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a b e112 h112
+b a b e212 h212
+c a b e312 h312
+c b b m322 p322
+d a b e412 h412
+d b b m422 p422
+select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a c111 d111
+a a b e112 h112
+b a a b211 d211
+b a b e212 h212
+c a a b311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a b411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a b a i121 l121
+b b a i221 l221
+c b a i321 l321
+d b a i421 l421
+select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
+a1 a2 b min(c)
+b b a k221
+c b a k321
+d b a k421
+select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
+a1 a2 b min(c)
+b b a k221
+c b a k321
+d b a k421
+select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+a1 a2 b min(c)
+select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b;
+a1 a2 b min(c)
+select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a b e112 h112
+b a b e212 h212
+c a b e312 h312
+c b b m322 p322
+d a b e412 h412
+d b b m422 p422
+e a b NULL NULL
+select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a a a c111 d111
+a a b e112 h112
+b a a b211 d211
+b a b e212 h212
+c a NULL c777 c999
+c a a b311 d311
+c a b e312 h312
+c b a i321 l321
+c b b m322 p322
+d a a b411 d411
+d a b e412 h412
+d b a i421 l421
+d b b m422 p422
+select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
+a1 a2 b min(c) max(c)
+a b a i121 l121
+b b a i221 l221
+c b a i321 l321
+d b a i421 l421
+select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
+a1 a2 b min(c)
+b b a k221
+c b a k321
+d b a k421
+select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
+a1 a2 b min(c)
+b b a k221
+c b a k321
+d b a k421
+select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+a1 a2 b min(c)
+explain select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by
+explain select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 16 Using where; Using index for group-by
+select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+a1 a2 b
+a a b
+b a b
+c a b
+c b b
+d a b
+d b b
+select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+a1 a2 b
+a b a
+b b a
+c b a
+d b a
+select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+a1 a2 b c
+a b a i121
+select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+a1 a2 b
+select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+a1 a2 b
+a a b
+b a b
+c a b
+c b b
+d a b
+d b b
+e a b
+select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+a1 a2 b
+a b a
+b b a
+c b a
+d b a
+select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+a1 a2 b c
+select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+a1 a2 b
+explain select distinct a1,a2,b from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by
+explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index
+explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by
+explain select distinct b from t1 where (a2 >= 'b') and (b = 'a');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index
+explain select distinct a1,a2,b from t2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 21 Using index for group-by
+explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 21 Using where; Using index for group-by
+explain select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index
+explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 16 Using where; Using index for group-by
+explain select distinct b from t2 where (a2 >= 'b') and (b = 'a');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL idx_t2_2 146 NULL 164 Using where; Using index
+select distinct a1,a2,b from t1;
+a1 a2 b
+a a a
+a a b
+a b a
+a b b
+b a a
+b a b
+b b a
+b b b
+c a a
+c a b
+c b a
+c b b
+d a a
+d a b
+d b a
+d b b
+select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a');
+a1 a2 b
+a b a
+b b a
+c b a
+d b a
+select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+a1 a2 b c
+a b a i121
+select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+a1 a2 b
+select distinct b from t1 where (a2 >= 'b') and (b = 'a');
+b
+a
+select distinct a1,a2,b from t2;
+a1 a2 b
+a a NULL
+a a a
+a a b
+a b a
+a b b
+b a a
+b a b
+b b a
+b b b
+c a NULL
+c a a
+c a b
+c b a
+c b b
+d a a
+d a b
+d b a
+d b b
+e a a
+e a b
+select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a');
+a1 a2 b
+a b a
+b b a
+c b a
+d b a
+select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+a1 a2 b c
+a b a i121
+select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+a1 a2 b
+select distinct b from t2 where (a2 >= 'b') and (b = 'a');
+b
+a
+select distinct t_00.a1
+from t1 t_00
+where exists ( select * from t2 where a1 = t_00.a1 );
+a1
+a
+b
+c
+d
+select distinct a1,a1 from t1;
+a1 a1
+a a
+b b
+c c
+d d
+select distinct a2,a1,a2,a1 from t1;
+a2 a1 a2 a1
+a a a a
+b a b a
+a b a b
+b b b b
+a c a c
+b c b c
+a d a d
+b d b d
+select distinct t1.a1,t2.a1 from t1,t2;
+a1 a1
+a a
+b a
+c a
+d a
+a b
+b b
+c b
+d b
+a c
+b c
+c c
+d c
+a d
+b d
+c d
+d d
+a e
+b e
+c e
+d e
+explain select distinct a1,a2,b from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by
+explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
+explain select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by
+explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by
+explain select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by; Using temporary; Using filesort
+explain select distinct a1,a2,b from t2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 21 Using index for group-by
+explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 21 Using where; Using index for group-by
+explain select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by
+explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 16 Using where; Using index for group-by
+explain select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NULL idx_t2_1 146 NULL 21 Using where; Using index for group-by; Using temporary; Using filesort
+select distinct a1,a2,b from t1;
+a1 a2 b
+a a a
+a a b
+a b a
+a b b
+b a a
+b a b
+b b a
+b b b
+c a a
+c a b
+c b a
+c b b
+d a a
+d a b
+d b a
+d b b
+select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+a1 a2 b
+a b a
+b b a
+c b a
+d b a
+select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+a1 a2 b c
+a b a i121
+select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+a1 a2 b
+select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+b
+a
+select distinct a1,a2,b from t2;
+a1 a2 b
+a a NULL
+a a a
+a a b
+a b a
+a b b
+b a a
+b a b
+b b a
+b b b
+c a NULL
+c a a
+c a b
+c b a
+c b b
+d a a
+d a b
+d b a
+d b b
+e a a
+e a b
+select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+a1 a2 b
+a b a
+b b a
+c b a
+d b a
+select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+a1 a2 b c
+select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+a1 a2 b
+select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+b
+a
+explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index
+explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index
+explain select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 128 Using where; Using index
+explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index
+explain select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 128 Using where; Using index
+select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
+count(distinct a1,a2,b)
+4
+select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+count(distinct a1,a2,b,c)
+1
+select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+count(distinct a1,a2,b)
+0
+select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
+count(distinct b)
+1
+select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
+ord(a1) + count(distinct a1,a2,b)
+104
+explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by
+explain select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by
+explain select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by
+explain select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by
+explain select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range NULL idx_t1_1 130 NULL 9 Using index for group-by
+select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b;
+a1 a2 b concat(min(c), max(c))
+a a a a111d111
+a a b e112h112
+a b a i121l121
+a b b m122p122
+b a a a211d211
+b a b e212h212
+b b a i221l221
+b b b m222p222
+c a a a311d311
+c a b e312h312
+c b a i321l321
+c b b m322p322
+select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b;
+concat(a1,min(c)) b
+aa111 a
+ae112 b
+ai121 a
+am122 b
+ba211 a
+be212 b
+bi221 a
+bm222 b
+ca311 a
+ce312 b
+ci321 a
+cm322 b
+select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b;
+concat(a1,min(c)) b max(c)
+aa111 a d111
+ae112 b h112
+ai121 a l121
+am122 b p122
+ba211 a d211
+be212 b h212
+bi221 a l221
+bm222 b p222
+ca311 a d311
+ce312 b h312
+ci321 a l321
+cm322 b p322
+select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
+concat(a1,a2) b min(c) max(c)
+aa a a111 d111
+aa b e112 h112
+ab a i121 l121
+ab b m122 p122
+ba a a211 d211
+ba b e212 h212
+bb a i221 l221
+bb b m222 p222
+ca a a311 d311
+ca b e312 h312
+cb a i321 l321
+cb b m322 p322
+select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2;
+concat(ord(min(b)),ord(max(b))) min(b) max(b)
+9798 a b
+9798 a b
+9798 a b
+9798 a b
+9798 a b
+9798 a b
+9798 a b
+9798 a b
+explain select a1,a2,b,d,min(c),max(c) from t1 group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 128 Using temporary; Using filesort
+explain select a1,a2,b,d from t1 group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 128 Using temporary; Using filesort
+explain select a1,a2,min(b),max(b) from t1
+where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 130 NULL 76 Using where; Using index
+explain select a1,a2,b,min(c),max(c) from t1
+where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL idx_t1_0,idx_t1_1,idx_t1_2 NULL NULL NULL 128 Using where; Using temporary; Using filesort
+explain select a1,a2,b,c from t1
+where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b,c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL idx_t1_0,idx_t1_1,idx_t1_2 NULL NULL NULL 128 Using where; Using temporary; Using filesort
+explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b < 'b') group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index
+explain select a1,a2,b from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 130 NULL 76 Using where; Using index
+explain select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index
+select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1;
+a1 a2 min(b) c
+a a a a111
+explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b = 'a') group by a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index
+explain select a1,a2,b,min(c),max(c) from t2
+where (c > 'a000') and (c <= 'd999') and (c like '_8__') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 Using where; Using index
+explain select a1, a2, b, c, min(d), max(d) from t1 group by a1,a2,b,c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 128 Using temporary; Using filesort
+explain select a1,a2,count(a2) from t1 group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using index
+explain select a1,a2,count(a2) from t1 where (a1 > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 163 NULL 128 Using where; Using index
+explain select sum(ord(a1)) from t1 where (a1 > 'a') group by a1,a2,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 163 NULL 128 Using where; Using index
+drop table t1;
+drop table t2;
+drop table t3;
+create table t1 (
+a varchar(30), b varchar(30), primary key(a), key(b)
+) engine=innodb;
+select distinct a from t1;
+a
+drop table t1;
diff --git a/mysql-test/r/have_cp932.require b/mysql-test/r/have_cp932.require
new file mode 100644
index 00000000000..988d720ed2c
--- /dev/null
+++ b/mysql-test/r/have_cp932.require
@@ -0,0 +1,2 @@
+Collation Charset Id Default Compiled Sortlen
+cp932_japanese_ci cp932 95 Yes Yes 1
diff --git a/mysql-test/r/have_eucjpms.require b/mysql-test/r/have_eucjpms.require
new file mode 100644
index 00000000000..f35621b2c1a
--- /dev/null
+++ b/mysql-test/r/have_eucjpms.require
@@ -0,0 +1,2 @@
+Collation Charset Id Default Compiled Sortlen
+eucjpms_japanese_ci eucjpms 97 Yes Yes 1
diff --git a/mysql-test/r/have_federated_db.require b/mysql-test/r/have_federated_db.require
new file mode 100644
index 00000000000..f4c521a8f35
--- /dev/null
+++ b/mysql-test/r/have_federated_db.require
@@ -0,0 +1,2 @@
+Variable_name Value
+have_federated_engine YES
diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result
index 218276406b1..86c9adf8cf6 100644
--- a/mysql-test/r/having.result
+++ b/mysql-test/r/having.result
@@ -1,4 +1,4 @@
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
create table t1 (a int);
select count(a) as b from t1 where a=0 having b > 0;
b
@@ -12,7 +12,7 @@ explain extended select count(a) as b from t1 where a=0 having b >=0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
-Note 1003 select count(test.t1.a) AS `b` from test.t1 where (test.t1.a = 0) having (count(test.t1.a) >= 0)
+Note 1003 select count(`test`.`t1`.`a`) AS `b` from `test`.`t1` where (`test`.`t1`.`a` = 0) having (count(`test`.`t1`.`a`) >= 0)
drop table t1;
CREATE TABLE t1 (
raw_id int(10) NOT NULL default '0',
@@ -128,3 +128,203 @@ id description c
1 test 0
2 test2 0
drop table t1,t2,t3;
+create table t1 (col1 int, col2 varchar(5), col_t1 int);
+create table t2 (col1 int, col2 varchar(5), col_t2 int);
+create table t3 (col1 int, col2 varchar(5), col_t3 int);
+insert into t1 values(10,'hello',10);
+insert into t1 values(20,'hello',20);
+insert into t1 values(30,'hello',30);
+insert into t1 values(10,'bye',10);
+insert into t1 values(10,'sam',10);
+insert into t1 values(10,'bob',10);
+insert into t2 select * from t1;
+insert into t3 select * from t1;
+select count(*) from t1 group by col1 having col1 = 10;
+count(*)
+4
+select count(*) as count_col1 from t1 group by col1 having col1 = 10;
+count_col1
+4
+select count(*) as count_col1 from t1 as tmp1 group by col1 having col1 = 10;
+count_col1
+4
+select count(*) from t1 group by col2 having col2 = 'hello';
+count(*)
+3
+select count(*) from t1 group by col2 having col1 = 10;
+ERROR 42S22: Unknown column 'col1' in 'having clause'
+select col1 as count_col1 from t1 as tmp1 group by col1 having col1 = 10;
+count_col1
+10
+select col1 as count_col1 from t1 as tmp1 group by col1 having count_col1 = 10;
+count_col1
+10
+select col1 as count_col1 from t1 as tmp1 group by count_col1 having col1 = 10;
+count_col1
+10
+select col1 as count_col1 from t1 as tmp1 group by count_col1 having count_col1 = 10;
+count_col1
+10
+select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having col1 = 10;
+count_col1 col2
+10 bob
+10 bye
+10 hello
+10 sam
+select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having count_col1 = 10;
+count_col1 col2
+10 bob
+10 bye
+10 hello
+10 sam
+select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having col2 = 'hello';
+count_col1 col2
+10 hello
+20 hello
+30 hello
+select col1 as count_col1,col2 as group_col2 from t1 as tmp1 group by col1,col2 having group_col2 = 'hello';
+count_col1 group_col2
+10 hello
+20 hello
+30 hello
+select sum(col1) as co12 from t1 group by col2 having col2 10;
+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 '10' at line 1
+select sum(col1) as co2, count(col2) as cc from t1 group by col1 having col1 =10;
+co2 cc
+40 4
+select t2.col2 from t2 group by t2.col1, t2.col2 having t1.col1 <= 10;
+ERROR 42S22: Unknown column 't1.col1' in 'having clause'
+select t1.col1 from t1
+where t1.col2 in
+(select t2.col2 from t2
+group by t2.col1, t2.col2 having t2.col1 <= 10);
+col1
+10
+20
+30
+10
+10
+10
+select t1.col1 from t1
+where t1.col2 in
+(select t2.col2 from t2
+group by t2.col1, t2.col2
+having t2.col1 <=
+(select min(t3.col1) from t3));
+col1
+10
+20
+30
+10
+10
+10
+select t1.col1 from t1
+where t1.col2 in
+(select t2.col2 from t2
+group by t2.col1, t2.col2 having t1.col1 <= 10);
+col1
+10
+10
+10
+10
+select t1.col1 as tmp_col from t1
+where t1.col2 in
+(select t2.col2 from t2
+group by t2.col1, t2.col2 having tmp_col <= 10);
+tmp_col
+10
+10
+10
+10
+select t1.col1 from t1
+where t1.col2 in
+(select t2.col2 from t2
+group by t2.col1, t2.col2 having col_t1 <= 10);
+col1
+10
+10
+10
+10
+select sum(col1) from t1
+group by col_t1
+having (select col_t1 from t2 where col_t1 = col_t2 order by col_t2 limit 1);
+sum(col1)
+40
+20
+30
+select t1.col1 from t1
+where t1.col2 in
+(select t2.col2 from t2
+group by t2.col1, t2.col2 having col_t1 <= 10)
+having col_t1 <= 20;
+ERROR 42S22: Unknown column 'col_t1' in 'having clause'
+select t1.col1 from t1
+where t1.col2 in
+(select t2.col2 from t2
+group by t2.col1, t2.col2 having col_t1 <= 10)
+group by col_t1
+having col_t1 <= 20;
+col1
+10
+select col_t1, sum(col1) from t1
+group by col_t1
+having col_t1 > 10 and
+exists (select sum(t2.col1) from t2
+group by t2.col2 having t2.col2 > 'b');
+col_t1 sum(col1)
+20 20
+30 30
+select sum(col1) from t1
+group by col_t1
+having col_t1 in (select sum(t2.col1) from t2
+group by t2.col2, t2.col1 having t2.col1 = t1.col1);
+ERROR 42S22: Unknown column 't1.col1' in 'having clause'
+select sum(col1) from t1
+group by col_t1
+having col_t1 in (select sum(t2.col1) from t2
+group by t2.col2, t2.col1 having t2.col1 = col_t1);
+sum(col1)
+40
+20
+30
+select t1.col1, t2.col1 from t1, t2 where t1.col1 = t2.col1
+group by t1.col1, t2.col1 having col1 = 2;
+ERROR 23000: Column 'col1' in having clause is ambiguous
+select t1.col1*10+t2.col1 from t1,t2 where t1.col1=t2.col1
+group by t1.col1, t2.col1 having col1 = 2;
+ERROR 23000: Column 'col1' in having clause is ambiguous
+drop table t1, t2, t3;
+create table t1 (s1 int);
+insert into t1 values (1),(2),(3);
+select count(*) from t1 group by s1 having s1 is null;
+count(*)
+select s1*0 as s1 from t1 group by s1 having s1 <> 0;
+s1
+0
+0
+0
+Warnings:
+Warning 1052 Column 's1' in having clause is ambiguous
+select s1*0 from t1 group by s1 having s1 = 0;
+s1*0
+select s1 from t1 group by 1 having 1 = 0;
+s1
+select count(s1) from t1 group by s1 having count(1+1)=2;
+count(s1)
+select count(s1) from t1 group by s1 having s1*0=0;
+count(s1)
+1
+1
+1
+select * from t1 a, t1 b group by a.s1 having s1 is null;
+ERROR 23000: Column 's1' in having clause is ambiguous
+drop table t1;
+create table t1 (s1 char character set latin1 collate latin1_german1_ci);
+insert into t1 values ('ü'),('y');
+Warnings:
+Warning 1265 Data truncated for column 's1' at row 1
+select s1,count(s1) from t1
+group by s1 collate latin1_swedish_ci having s1 = 'y';
+s1 count(s1)
+y 1
+drop table t1;
diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result
index 29207a4ae98..d2750fd5a43 100644
--- a/mysql-test/r/heap.result
+++ b/mysql-test/r/heap.result
@@ -1,4 +1,4 @@
-drop table if exists t1;
+drop table if exists t1,t2,t3;
create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100;
insert into t1 values(1,1),(2,2),(3,3),(4,4);
delete from t1 where a=1 or a=0;
@@ -40,7 +40,7 @@ a b
4 4
drop table t1;
create table t1 (a int not null) engine=heap;
-insert into t1 values (869751),(736494),(226312),(802616);
+insert into t1 values (869751),(736494),(226312),(802616),(728912);
select * from t1 where a > 736494;
a
869751
@@ -169,7 +169,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL btn NULL NULL NULL 11 Using where
explain select * from t1 where btn="a" and new_col="a";
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref btn btn 11 const,const 2 Using where
+1 SIMPLE t1 ref btn btn 11 const,const 1 Using where
drop table t1;
CREATE TABLE t1 (
a int default NULL,
@@ -249,16 +249,425 @@ a
3
2
drop table t1;
+set storage_engine=HEAP;
+create table t1 (v varchar(10), c char(10), t varchar(50));
+insert into t1 values('+ ', '+ ', '+ ');
+set @a=repeat(' ',20);
+insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
+Warnings:
+Note 1265 Data truncated for column 'v' at row 1
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+ *+*+ *
+*+ *+*+ *
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` varchar(50) default NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+create table t2 like t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` varchar(50) default NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+create table t3 select * from t1;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` varchar(50) default NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+alter table t1 modify c varchar(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` varchar(50) default NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+alter table t1 modify v char(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` varchar(50) default NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+alter table t1 modify t varchar(10);
+Warnings:
+Warning 1265 Data truncated for column 't' at row 2
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` varchar(10) default NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+*+*+ *
+*+*+*+ *
+drop table t1,t2,t3;
+create table t1 (v varchar(10), c char(10), t varchar(50), key(v), key(c), key(t(10)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` varchar(50) default NULL,
+ KEY `v` (`v`),
+ KEY `c` (`c`),
+ KEY `t` (`t`(10))
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+select count(*) from t1;
+count(*)
+270
+insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1)));
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where c='a';
+count(*)
+10
+select count(*) from t1 where t='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where c='a ';
+count(*)
+10
+select count(*) from t1 where t='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where c like 'a%';
+count(*)
+11
+select count(*) from t1 where t like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const 9 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
+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
+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
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL v NULL NULL NULL 271 Using where
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL v NULL NULL NULL 271 Using where
+alter table t1 add unique(v);
+ERROR 23000: Duplicate entry '{ ' for key 1
+select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*'));
+qq
+*a*a*a*
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const 9 Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(c) from t1 group by v limit 10;
+v count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result trim(v),count(t) from t1 group by v limit 10;
+trim(v) count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result trim(v),count(c) from t1 group by v limit 10;
+trim(v) count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(*) from t1 group by c limit 10;
+c count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(*) from t1 group by t limit 10;
+t count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(t) from t1 group by t limit 10;
+t count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result trim(t),count(t) from t1 group by t limit 10;
+trim(t) count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+drop table t1;
+create table t1 (a char(10), unique (a));
+insert into t1 values ('a');
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a' for key 1
+alter table t1 modify a varchar(10);
+insert into t1 values ('a '),('a '),('a '),('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+update t1 set a='a ' where a like 'a ';
+update t1 set a='a ' where a like 'a ';
+drop table t1;
+create table t1 (v varchar(10), c char(10), t varchar(50), key using btree (v), key using btree (c), key using btree (t(10)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` varchar(50) default NULL,
+ KEY `v` USING BTREE (`v`),
+ KEY `c` USING BTREE (`c`),
+ KEY `t` USING BTREE (`t`(10))
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+select count(*) from t1;
+count(*)
+270
+insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1)));
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where c='a';
+count(*)
+10
+select count(*) from t1 where t='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where c='a ';
+count(*)
+10
+select count(*) from t1 where t='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const # Using where
+explain select count(*) from t1 where c='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref c c 11 const # Using where
+explain select count(*) from t1 where t='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref t t 13 const # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where
+alter table t1 add unique(v);
+ERROR 23000: Duplicate entry '{ ' for key 1
+select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*'));
+qq
+*a*a*a*
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const # Using where
+drop table t1;
+create table t1 (a char(10), unique using btree (a)) engine=heap;
+insert into t1 values ('a');
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a' for key 1
+alter table t1 modify a varchar(10);
+insert into t1 values ('a '),('a '),('a '),('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+update t1 set a='a ' where a like 'a ';
+update t1 set a='a ' where a like 'a ';
+drop table t1;
+create table t1 (v varchar(10), c char(10), t varchar(50), key(v(5)), key(c(5)), key(t(5)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` varchar(50) default NULL,
+ KEY `v` (`v`(5)),
+ KEY `c` (`c`(5)),
+ KEY `t` (`t`(5))
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v varchar(65530), key(v(10)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(65530) default NULL,
+ KEY `v` (`v`(10))
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+insert into t1 values(repeat('a',65530));
+select length(v) from t1 where v=repeat('a',65530);
+length(v)
+65530
+drop table t1;
+set storage_engine=MyISAM;
create table t1 (a bigint unsigned auto_increment primary key, b int,
key (b, a)) engine=heap;
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
+insert t1 (b) values (1),(1),(1),(1),(1),(1),(1),(1);
select * from t1;
a b
1 1
@@ -272,14 +681,7 @@ a b
drop table t1;
create table t1 (a int not null, b int not null auto_increment,
primary key(a, b), key(b)) engine=heap;
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
+insert t1 (a) values (1),(1),(1),(1),(1),(1),(1),(1);
select * from t1;
a b
1 1
@@ -291,3 +693,6 @@ a b
1 7
1 8
drop table t1;
+create table t1 (a int not null, b int not null auto_increment,
+primary key(a, b)) engine=heap;
+ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key
diff --git a/mysql-test/r/heap_btree.result b/mysql-test/r/heap_btree.result
index 5c60c97d674..374d2c63632 100644
--- a/mysql-test/r/heap_btree.result
+++ b/mysql-test/r/heap_btree.result
@@ -40,7 +40,7 @@ a b
4 4
drop table t1;
create table t1 (a int not null) engine=heap;
-insert into t1 values (869751),(736494),(226312),(802616);
+insert into t1 values (869751),(736494),(226312),(802616),(728912);
select * from t1 where a > 736494;
a
869751
@@ -73,7 +73,7 @@ engine=heap;
insert into t1 values (1,1),(2,2),(1,3),(2,4),(2,5),(2,6);
explain select * from t1 where x=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref x x 4 const 1 Using where
+1 SIMPLE t1 ref x x 4 const 1
select * from t1 where x=1;
x y
1 1
@@ -134,7 +134,7 @@ a b
1 1
explain select * from tx where b=x;
id select_type table type possible_keys key key_len ref rows Extra
-x SIMPLE tx ref b b x const x Using where
+x SIMPLE tx ref b b x const x
drop table t1;
create table t1 (id int unsigned not null, primary key using BTREE (id)) engine=HEAP;
insert into t1 values(1);
diff --git a/mysql-test/r/heap_hash.result b/mysql-test/r/heap_hash.result
index d3673cd2a63..9720fe4843a 100644
--- a/mysql-test/r/heap_hash.result
+++ b/mysql-test/r/heap_hash.result
@@ -40,7 +40,7 @@ a b
4 4
drop table t1;
create table t1 (a int not null) engine=heap;
-insert into t1 values (869751),(736494),(226312),(802616);
+insert into t1 values (869751),(736494),(226312),(802616),(728912);
select * from t1 where a > 736494;
a
869751
@@ -169,7 +169,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL btn NULL NULL NULL 11 Using where
explain select * from t1 where btn="a" and new_col="a";
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref btn btn 11 const,const 2 Using where
+1 SIMPLE t1 ref btn btn 11 const,const 1 Using where
drop table t1;
CREATE TABLE t1 (
a int default NULL,
@@ -290,28 +290,28 @@ insert into t1 (name) values ('Matt'), ('Lilu'), ('Corbin'), ('Carly'),
insert into t2 select * from t1;
explain select * from t1 where name='matt';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 20 const 1 Using where
+1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 22 const 1 Using where
explain select * from t2 where name='matt';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 20 const 1 Using where
+1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 22 const 1 Using where
explain select * from t1 where name='Lilu';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 20 const 1 Using where
+1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 22 const 1 Using where
explain select * from t2 where name='Lilu';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 20 const 1 Using where
+1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 22 const 1 Using where
explain select * from t1 where name='Phil';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 20 const 1 Using where
+1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 22 const 1 Using where
explain select * from t2 where name='Phil';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 20 const 1 Using where
+1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 22 const 1 Using where
explain select * from t1 where name='Lilu';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 20 const 1 Using where
+1 SIMPLE t1 ref heap_idx,btree_idx heap_idx 22 const 1 Using where
explain select * from t2 where name='Lilu';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 20 const 1 Using where
+1 SIMPLE t2 ref btree_idx,heap_idx btree_idx 22 const 1 Using where
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
insert into t1 (name) select name from t2;
@@ -324,7 +324,7 @@ count(*)
7
explain select * from t1 ignore index (btree_idx) where name='matt';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref heap_idx heap_idx 20 const 7 Using where
+1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where
show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 id NULL 91 NULL NULL HASH
@@ -352,8 +352,8 @@ t3 1 a 1 a NULL NULL NULL NULL HASH
t3 1 a 2 b NULL 15 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 t1 ref heap_idx heap_idx 20 const 7 Using where
-1 SIMPLE t3 ref a a 40 func,const 6 Using where
+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
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/help.result b/mysql-test/r/help.result
index edf7d0e91cb..85ca832828d 100644
--- a/mysql-test/r/help.result
+++ b/mysql-test/r/help.result
@@ -1,32 +1,48 @@
insert into mysql.help_category(help_category_id,name)values(1,'impossible_category_1');
+Warnings:
+Warning 1364 Field 'url' doesn't have a default value
select @category1_id:= 1;
@category1_id:= 1
1
insert into mysql.help_category(help_category_id,name)values(2,'impossible_category_2');
+Warnings:
+Warning 1364 Field 'url' doesn't have a default value
select @category2_id:= 2;
@category2_id:= 2
2
insert into mysql.help_category(help_category_id,name,parent_category_id)values(3,'impossible_category_3',@category2_id);
+Warnings:
+Warning 1364 Field 'url' doesn't have a default value
select @category3_id:= 3;
@category3_id:= 3
3
insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(1,'impossible_function_1',@category1_id,'description of \n impossible_function1\n','example of \n impossible_function1');
+Warnings:
+Warning 1364 Field 'url' doesn't have a default value
select @topic1_id:= 1;
@topic1_id:= 1
1
insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(2,'impossible_function_2',@category1_id,'description of \n impossible_function2\n','example of \n impossible_function2');
+Warnings:
+Warning 1364 Field 'url' doesn't have a default value
select @topic2_id:= 2;
@topic2_id:= 2
2
insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(3,'impossible_function_3',@category2_id,'description of \n impossible_function3\n','example of \n impossible_function3');
+Warnings:
+Warning 1364 Field 'url' doesn't have a default value
select @topic3_id:= 3;
@topic3_id:= 3
3
insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(4,'impossible_function_4',@category2_id,'description of \n impossible_function4\n','example of \n impossible_function4');
+Warnings:
+Warning 1364 Field 'url' doesn't have a default value
select @topic4_id:= 4;
@topic4_id:= 4
4
insert into mysql.help_topic(help_topic_id,name,help_category_id,description,example)values(5,'impossible_function_7',@category3_id,'description of \n impossible_function5\n','example of \n impossible_function7');
+Warnings:
+Warning 1364 Field 'url' doesn't have a default value
select @topic5_id:= 5;
@topic5_id:= 5
5
diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result
new file mode 100644
index 00000000000..693cc63ba9e
--- /dev/null
+++ b/mysql-test/r/index_merge.result
@@ -0,0 +1,386 @@
+drop table if exists t0, t1, t2, t3, t4;
+create table t0
+(
+key1 int not null,
+INDEX i1(key1)
+);
+alter table t0 add key2 int not null, add index i2(key2);
+alter table t0 add key3 int not null, add index i3(key3);
+alter table t0 add key4 int not null, add index i4(key4);
+alter table t0 add key5 int not null, add index i5(key5);
+alter table t0 add key6 int not null, add index i6(key6);
+alter table t0 add key7 int not null, add index i7(key7);
+alter table t0 add key8 int not null, add index i8(key8);
+update t0 set key2=key1,key3=key1,key4=key1,key5=key1,key6=key1,key7=key1,key8=1024-key1;
+analyze table t0;
+Table Op Msg_type Msg_text
+test.t0 analyze status OK
+explain select * from t0 where key1 < 3 or key1 > 1020;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 range i1 i1 4 NULL 55 Using where
+explain
+select * from t0 where key1 < 3 or key2 > 1020;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 31 Using sort_union(i1,i2); Using where
+select * from t0 where key1 < 3 or key2 > 1020;
+key1 key2 key3 key4 key5 key6 key7 key8
+1 1 1 1 1 1 1 1023
+2 2 2 2 2 2 2 1022
+1021 1021 1021 1021 1021 1021 1021 3
+1022 1022 1022 1022 1022 1022 1022 2
+1023 1023 1023 1023 1023 1023 1023 1
+1024 1024 1024 1024 1024 1024 1024 0
+explain select * from t0 where key1 < 3 or key2 <4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 7 Using sort_union(i1,i2); Using where
+explain
+select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 9 Using sort_union(i1,i2); Using where
+select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40);
+key1 key2 key3 key4 key5 key6 key7 key8
+31 31 31 31 31 31 31 993
+32 32 32 32 32 32 32 992
+33 33 33 33 33 33 33 991
+34 34 34 34 34 34 34 990
+35 35 35 35 35 35 35 989
+36 36 36 36 36 36 36 988
+37 37 37 37 37 37 37 987
+38 38 38 38 38 38 38 986
+39 39 39 39 39 39 39 985
+explain select * from t0 ignore index (i2) where key1 < 3 or key2 <4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL i1 NULL NULL NULL 1024 Using where
+explain select * from t0 where (key1 < 3 or key2 <4) and key3 = 50;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ref i1,i2,i3 i3 4 const 1 Using where
+explain select * from t0 use index (i1,i2) where (key1 < 3 or key2 <4) and key3 = 50;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 7 Using sort_union(i1,i2); Using where
+explain select * from t0 where (key1 > 1 or key2 > 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL i1,i2 NULL NULL NULL 1024 Using where
+explain select * from t0 force index (i1,i2) where (key1 > 1 or key2 > 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 1024 Using sort_union(i1,i2); Using where
+explain
+select * from t0 where key1<3 or key2<3 or (key1>5 and key1<8) or
+(key1>10 and key1<12) or (key2>100 and key2<110);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 17 Using sort_union(i1,i2); Using where
+explain select * from t0 where key2 = 45 or key1 <=> null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 range i1,i2 i2 4 NULL 1 Using where
+explain select * from t0 where key2 = 45 or key1 is not null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL i1,i2 NULL NULL NULL 1024 Using where
+explain select * from t0 where key2 = 45 or key1 is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ref i2 i2 4 const 1
+explain select * from t0 where key2=10 or key3=3 or key4 <=> null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i2,i3,i4 i2,i3 4,4 NULL 2 Using union(i2,i3); Using where
+explain select * from t0 where key2=10 or key3=3 or key4 is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i2,i3 i2,i3 4,4 NULL 2 Using union(i2,i3); Using where
+explain select key1 from t0 where (key1 <=> null) or (key2 < 5) or
+(key3=10) or (key4 <=> null);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3,i4 i2,i3 4,4 NULL 6 Using sort_union(i2,i3); Using where
+explain select key1 from t0 where (key1 <=> null) or (key1 < 5) or
+(key3=10) or (key4 <=> null);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i3,i4 i1,i3 4,4 NULL 5 Using sort_union(i1,i3); Using where
+explain select * from t0 where
+(key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 5 or key6 < 5);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3,i4,i5,i6 i1,i2 4,4 NULL 6 Using sort_union(i1,i2); Using where
+explain
+select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3 i1,i2 4,4 NULL 9 Using sort_union(i1,i2); Using where
+select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4);
+key1 key2 key3 key4 key5 key6 key7 key8
+1 1 1 1 1 1 1 1023
+2 2 2 2 2 2 2 1022
+3 3 3 3 3 3 3 1021
+4 4 4 4 4 4 4 1020
+5 5 5 5 5 5 5 1019
+explain select * from t0 where
+(key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 2 or key6 < 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3,i4,i5,i6 i1,i2 4,4 NULL 6 Using sort_union(i1,i2); Using where
+explain select * from t0 where
+(key1 < 3 or key2 < 3) and (key3 < 100);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 range i1,i2,i3 i3 4 NULL 96 Using where
+explain select * from t0 where
+(key1 < 3 or key2 < 3) and (key3 < 1000);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL 1024 Using where
+explain select * from t0 where
+((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4))
+or
+key2 > 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL i1,i2,i3 NULL NULL NULL 1024 Using where
+explain select * from t0 where
+((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4))
+or
+key1 < 7;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3 i1,i2 4,4 NULL 10 Using sort_union(i1,i2); Using where
+select * from t0 where
+((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4))
+or
+key1 < 7;
+key1 key2 key3 key4 key5 key6 key7 key8
+1 1 1 1 1 1 1 1023
+2 2 2 2 2 2 2 1022
+3 3 3 3 3 3 3 1021
+4 4 4 4 4 4 4 1020
+5 5 5 5 5 5 5 1019
+6 6 6 6 6 6 6 1018
+explain select * from t0 where
+((key1 < 4 or key2 < 4) and (key3 <5 or key5 < 4))
+or
+((key5 < 5 or key6 < 6) and (key7 <7 or key8 < 4));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3,i5,i6,i7,i8 i1,i2,i5,i6 4,4,4,4 NULL 19 Using sort_union(i1,i2,i5,i6); Using where
+explain select * from t0 where
+((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+or
+((key7 <7 or key8 < 4) and (key5 < 5 or key6 < 6));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3,i5,i6,i7,i8 i3,i5,i7,i8 4,4,4,4 NULL 21 Using sort_union(i3,i5,i7,i8); Using where
+explain select * from t0 where
+((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+or
+((key3 <7 or key5 < 2) and (key5 < 5 or key6 < 6));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3,i5,i6 i3,i5 4,4 NULL 11 Using sort_union(i3,i5); Using where
+explain select * from t0 where
+((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+or
+(((key3 <7 and key7 < 6) or key5 < 2) and (key5 < 5 or key6 < 6));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3,i5,i6,i7 i3,i5 4,4 NULL 11 Using sort_union(i3,i5); Using where
+explain select * from t0 where
+((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+or
+((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL i1,i2,i3,i5,i6 NULL NULL NULL 1024 Using where
+explain select * from t0 force index(i1, i2, i3, i4, i5, i6 ) where
+((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+or
+((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2,i3,i5,i6 i3,i5 0,4 NULL 1024 Using sort_union(i3,i5); Using where
+select * from t0 where key1 < 5 or key8 < 4 order by key1;
+key1 key2 key3 key4 key5 key6 key7 key8
+1 1 1 1 1 1 1 1023
+2 2 2 2 2 2 2 1022
+3 3 3 3 3 3 3 1021
+4 4 4 4 4 4 4 1020
+1021 1021 1021 1021 1021 1021 1021 3
+1022 1022 1022 1022 1022 1022 1022 2
+1023 1023 1023 1023 1023 1023 1023 1
+1024 1024 1024 1024 1024 1024 1024 0
+explain
+select * from t0 where key1 < 5 or key8 < 4 order by key1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i8 i1,i8 4,4 NULL 9 Using sort_union(i1,i8); Using where; Using filesort
+create table t2 like t0;
+insert into t2 select * from t0;
+alter table t2 add index i1_3(key1, key3);
+alter table t2 add index i2_3(key2, key3);
+alter table t2 drop index i1;
+alter table t2 drop index i2;
+alter table t2 add index i321(key3, key2, key1);
+explain select key3 from t2 where key1 = 100 or key2 = 100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index_merge i1_3,i2_3 i1_3,i2_3 4,4 NULL 2 Using sort_union(i1_3,i2_3); Using where
+explain select key3 from t2 where key1 <100 or key2 < 100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index i1_3,i2_3 i321 12 NULL 1024 Using where; Using index
+explain select key7 from t2 where key1 <100 or key2 < 100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL i1_3,i2_3 NULL NULL NULL 1024 Using where
+create table t4 (
+key1a int not null,
+key1b int not null,
+key2 int not null,
+key2_1 int not null,
+key2_2 int not null,
+key3 int not null,
+index i1a (key1a, key1b),
+index i1b (key1b, key1a),
+index i2_1(key2, key2_1),
+index i2_2(key2, key2_1)
+);
+insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0;
+select * from t4 where key1a = 3 or key1b = 4;
+key1a key1b key2 key2_1 key2_2 key3
+3 3 0 3 3 3
+4 4 0 4 4 4
+explain select * from t4 where key1a = 3 or key1b = 4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 index_merge i1a,i1b i1a,i1b 4,4 NULL 2 Using sort_union(i1a,i1b); Using where
+explain select * from t4 where key2 = 1 and (key2_1 = 1 or key3 = 5);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 ref i2_1,i2_2 i2_1 4 const 10 Using where
+explain select * from t4 where key2 = 1 and (key2_1 = 1 or key2_2 = 5);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 ref i2_1,i2_2 i2_1 4 const 10 Using where
+explain select * from t4 where key2_1 = 1 or key2_2 = 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 ALL NULL NULL NULL NULL 1024 Using where
+create table t1 like t0;
+insert into t1 select * from t0;
+explain select * from t0 left join t1 on (t0.key1=t1.key1)
+where t0.key1=3 or t0.key2=4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where
+1 SIMPLE t1 ref i1 i1 4 test.t0.key1 1
+select * from t0 left join t1 on (t0.key1=t1.key1)
+where t0.key1=3 or t0.key2=4;
+key1 key2 key3 key4 key5 key6 key7 key8 key1 key2 key3 key4 key5 key6 key7 key8
+3 3 3 3 3 3 3 1021 3 3 3 3 3 3 3 1021
+4 4 4 4 4 4 4 1020 4 4 4 4 4 4 4 1020
+explain
+select * from t0,t1 where (t0.key1=t1.key1) and ( t0.key1=3 or t0.key2=4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where
+1 SIMPLE t1 ref i1 i1 4 test.t0.key1 1
+explain
+select * from t0,t1 where (t0.key1=t1.key1) and
+(t0.key1=3 or t0.key2=4) and t1.key1<200;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 range i1,i2 i1 4 NULL 179 Using where
+1 SIMPLE t1 ref i1 i1 4 test.t0.key1 1
+explain
+select * from t0,t1 where (t0.key1=t1.key1) and
+(t0.key1=3 or t0.key2<4) and t1.key1=2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ref i1,i2 i1 4 const 1 Using where
+1 SIMPLE t1 ref i1 i1 4 const 1
+explain select * from t0,t1 where t0.key1 = 5 and
+(t1.key1 = t0.key1 or t1.key8 = t0.key1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ref i1 i1 4 const 1
+1 SIMPLE t1 index_merge i1,i8 i1,i8 4,4 NULL 2 Using union(i1,i8); Using where
+explain select * from t0,t1 where t0.key1 < 3 and
+(t1.key1 = t0.key1 or t1.key8 = t0.key1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 range i1 i1 4 NULL 3 Using where
+1 SIMPLE t1 ALL i1,i8 NULL NULL NULL 1024 Range checked for each record (index map: 0x81)
+explain select * from t1 where key1=3 or key2=4
+union select * from t1 where key1<4 or key3=5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where
+2 UNION t1 index_merge i1,i3 i1,i3 4,4 NULL 5 Using sort_union(i1,i3); Using where
+NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL
+explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> system NULL NULL NULL NULL 1
+2 DERIVED t1 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where
+create table t3 like t0;
+insert into t3 select * from t0;
+alter table t3 add key9 int not null, add index i9(key9);
+alter table t3 add keyA int not null, add index iA(keyA);
+alter table t3 add keyB int not null, add index iB(keyB);
+alter table t3 add keyC int not null, add index iC(keyC);
+update t3 set key9=key1,keyA=key1,keyB=key1,keyC=key1;
+explain select * from t3 where
+key1=1 or key2=2 or key3=3 or key4=4 or
+key5=5 or key6=6 or key7=7 or key8=8 or
+key9=9 or keyA=10 or keyB=11 or keyC=12;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t3 index_merge i1,i2,i3,i4,i5,i6,i7,i8,i9,iA,iB,iC i1,i2,i3,i4,i5,i6,i7,i8,i9,iA,iB,iC 4,4,4,4,4,4,4,4,4,4,4,4 NULL 12 Using union(i1,i2,i3,i4,i5,i6,i7,i8,i9,iA,iB,iC); Using where
+select * from t3 where
+key1=1 or key2=2 or key3=3 or key4=4 or
+key5=5 or key6=6 or key7=7 or key8=8 or
+key9=9 or keyA=10 or keyB=11 or keyC=12;
+key1 key2 key3 key4 key5 key6 key7 key8 key9 keyA keyB keyC
+1 1 1 1 1 1 1 1023 1 1 1 1
+2 2 2 2 2 2 2 1022 2 2 2 2
+3 3 3 3 3 3 3 1021 3 3 3 3
+4 4 4 4 4 4 4 1020 4 4 4 4
+5 5 5 5 5 5 5 1019 5 5 5 5
+6 6 6 6 6 6 6 1018 6 6 6 6
+7 7 7 7 7 7 7 1017 7 7 7 7
+9 9 9 9 9 9 9 1015 9 9 9 9
+10 10 10 10 10 10 10 1014 10 10 10 10
+11 11 11 11 11 11 11 1013 11 11 11 11
+12 12 12 12 12 12 12 1012 12 12 12 12
+1016 1016 1016 1016 1016 1016 1016 8 1016 1016 1016 1016
+explain select * from t0 where key1 < 3 or key2 < 4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 7 Using sort_union(i1,i2); Using where
+select * from t0 where key1 < 3 or key2 < 4;
+key1 key2 key3 key4 key5 key6 key7 key8
+1 1 1 1 1 1 1 1023
+2 2 2 2 2 2 2 1022
+3 3 3 3 3 3 3 1021
+update t0 set key8=123 where key1 < 3 or key2 < 4;
+select * from t0 where key1 < 3 or key2 < 4;
+key1 key2 key3 key4 key5 key6 key7 key8
+1 1 1 1 1 1 1 123
+2 2 2 2 2 2 2 123
+3 3 3 3 3 3 3 123
+delete from t0 where key1 < 3 or key2 < 4;
+select * from t0 where key1 < 3 or key2 < 4;
+key1 key2 key3 key4 key5 key6 key7 key8
+select count(*) from t0;
+count(*)
+1021
+drop table t4;
+create table t4 (a int);
+insert into t4 values (1),(4),(3);
+set @save_join_buffer_size=@@join_buffer_size;
+set join_buffer_size= 4000;
+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 force index(i1,i2), t0 as B force index (i1,i2)
+where (A.key1 < 500000 or A.key2 < 3)
+and (B.key1 < 500000 or B.key2 < 3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL 1016 Using sort_union(i1,i2); Using where
+1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL 1016 Using sort_union(i1,i2); Using where
+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 force index(i1,i2), t0 as B force index (i1,i2)
+where (A.key1 < 500000 or A.key2 < 3)
+and (B.key1 < 500000 or B.key2 < 3);
+max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
+10240
+update t0 set key1=1;
+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 force index(i1,i2), t0 as B force index (i1,i2)
+where (A.key1 = 1 or A.key2 = 1)
+and (B.key1 = 1 or B.key2 = 1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL 1020 Using union(i1,i2); Using where
+1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL 1020 Using union(i1,i2); Using where
+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 force index(i1,i2), t0 as B force index (i1,i2)
+where (A.key1 = 1 or A.key2 = 1)
+and (B.key1 = 1 or B.key2 = 1);
+max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
+8194
+alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200);
+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.key7or16 = 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.key7or16 = 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 7or16 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 7or16 Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where
+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)
+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);
+max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
+8186
+set join_buffer_size= @save_join_buffer_size;
+drop table t0, t1, t2, t3, t4;
diff --git a/mysql-test/r/index_merge_bdb.result b/mysql-test/r/index_merge_bdb.result
new file mode 100644
index 00000000000..3113bf95d3a
--- /dev/null
+++ b/mysql-test/r/index_merge_bdb.result
@@ -0,0 +1,136 @@
+drop table if exists t1;
+create table t1 (
+pk int primary key,
+key1 int,
+key2 int,
+filler char(200),
+filler2 char(200),
+index(key1),
+index(key2)
+) engine=bdb;
+select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
+pk key1 key2 filler filler2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+9 9 9 filler-data filler-data-2
+10 10 10 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+5 5 5 filler-data filler-data-2
+6 6 6 filler-data filler-data-2
+7 7 7 filler-data filler-data-2
+8 8 8 filler-data filler-data-2
+set @maxv=1000;
+select * from t1 where
+(pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+or key1=18 or key1=60;
+pk key1 key2 filler filler2
+18 18 18 filler-data filler-data-2
+60 60 60 filler-data filler-data-2
+1 1 1 filler-data filler-data-2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+11 11 11 filler-data filler-data-2
+12 12 12 filler-data filler-data-2
+13 13 13 filler-data filler-data-2
+14 14 14 filler-data filler-data-2
+50 50 50 filler-data filler-data-2
+51 51 51 filler-data filler-data-2
+52 52 52 filler-data filler-data-2
+53 53 53 filler-data filler-data-2
+54 54 54 filler-data filler-data-2
+991 991 991 filler-data filler-data-2
+992 992 992 filler-data filler-data-2
+993 993 993 filler-data filler-data-2
+994 994 994 filler-data filler-data-2
+995 995 995 filler-data filler-data-2
+996 996 996 filler-data filler-data-2
+997 997 997 filler-data filler-data-2
+998 998 998 filler-data filler-data-2
+999 999 999 filler-data filler-data-2
+1000 1000 1000 filler-data filler-data-2
+select * from t1 where
+(pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+or key1 < 3 or key1 > @maxv-11;
+pk key1 key2 filler filler2
+990 990 990 filler-data filler-data-2
+1 1 1 filler-data filler-data-2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+11 11 11 filler-data filler-data-2
+12 12 12 filler-data filler-data-2
+13 13 13 filler-data filler-data-2
+14 14 14 filler-data filler-data-2
+50 50 50 filler-data filler-data-2
+51 51 51 filler-data filler-data-2
+52 52 52 filler-data filler-data-2
+53 53 53 filler-data filler-data-2
+54 54 54 filler-data filler-data-2
+991 991 991 filler-data filler-data-2
+992 992 992 filler-data filler-data-2
+993 993 993 filler-data filler-data-2
+994 994 994 filler-data filler-data-2
+995 995 995 filler-data filler-data-2
+996 996 996 filler-data filler-data-2
+997 997 997 filler-data filler-data-2
+998 998 998 filler-data filler-data-2
+999 999 999 filler-data filler-data-2
+1000 1000 1000 filler-data filler-data-2
+select * from t1 where
+(pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+or
+(key1 < 5) or (key1 > 10 and key1 < 15) or (key1 >= 50 and key1 < 55 ) or (key1 > @maxv-10);
+pk key1 key2 filler filler2
+1 1 1 filler-data filler-data-2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+11 11 11 filler-data filler-data-2
+12 12 12 filler-data filler-data-2
+13 13 13 filler-data filler-data-2
+14 14 14 filler-data filler-data-2
+50 50 50 filler-data filler-data-2
+51 51 51 filler-data filler-data-2
+52 52 52 filler-data filler-data-2
+53 53 53 filler-data filler-data-2
+54 54 54 filler-data filler-data-2
+991 991 991 filler-data filler-data-2
+992 992 992 filler-data filler-data-2
+993 993 993 filler-data filler-data-2
+994 994 994 filler-data filler-data-2
+995 995 995 filler-data filler-data-2
+996 996 996 filler-data filler-data-2
+997 997 997 filler-data filler-data-2
+998 998 998 filler-data filler-data-2
+999 999 999 filler-data filler-data-2
+1000 1000 1000 filler-data filler-data-2
+select * from t1 where
+(pk > 10 and pk < 15) or (pk >= 50 and pk < 55 )
+or
+(key1 < 5) or (key1 > @maxv-10);
+pk key1 key2 filler filler2
+1 1 1 filler-data filler-data-2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+991 991 991 filler-data filler-data-2
+992 992 992 filler-data filler-data-2
+993 993 993 filler-data filler-data-2
+994 994 994 filler-data filler-data-2
+995 995 995 filler-data filler-data-2
+996 996 996 filler-data filler-data-2
+997 997 997 filler-data filler-data-2
+998 998 998 filler-data filler-data-2
+999 999 999 filler-data filler-data-2
+1000 1000 1000 filler-data filler-data-2
+11 11 11 filler-data filler-data-2
+12 12 12 filler-data filler-data-2
+13 13 13 filler-data filler-data-2
+14 14 14 filler-data filler-data-2
+50 50 50 filler-data filler-data-2
+51 51 51 filler-data filler-data-2
+52 52 52 filler-data filler-data-2
+53 53 53 filler-data filler-data-2
+54 54 54 filler-data filler-data-2
+drop table t1;
diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result
new file mode 100644
index 00000000000..52e2a4046cf
--- /dev/null
+++ b/mysql-test/r/index_merge_innodb.result
@@ -0,0 +1,125 @@
+drop table if exists t1,t2;
+create table t1
+(
+key1 int not null,
+key2 int not null,
+INDEX i1(key1),
+INDEX i2(key2)
+) engine=innodb;
+explain select * from t1 where key1 < 5 or key2 > 197;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where
+select * from t1 where key1 < 5 or key2 > 197;
+key1 key2
+0 200
+1 199
+2 198
+3 197
+4 196
+explain select * from t1 where key1 < 3 or key2 > 195;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where
+select * from t1 where key1 < 3 or key2 > 195;
+key1 key2
+0 200
+1 199
+2 198
+3 197
+4 196
+alter table t1 add str1 char (255) not null,
+add zeroval int not null default 0,
+add str2 char (255) not null,
+add str3 char (255) not null;
+update t1 set str1='aaa', str2='bbb', str3=concat(key2, '-', key1 div 2, '_' ,if(key1 mod 2 = 0, 'a', 'A'));
+alter table t1 add primary key (str1, zeroval, str2, str3);
+explain select * from t1 where key1 < 5 or key2 > 197;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where
+select * from t1 where key1 < 5 or key2 > 197;
+key1 key2 str1 zeroval str2 str3
+4 196 aaa 0 bbb 196-2_a
+3 197 aaa 0 bbb 197-1_A
+2 198 aaa 0 bbb 198-1_a
+1 199 aaa 0 bbb 199-0_A
+0 200 aaa 0 bbb 200-0_a
+explain select * from t1 where key1 < 3 or key2 > 195;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 8 Using sort_union(i1,i2); Using where
+select * from t1 where key1 < 3 or key2 > 195;
+key1 key2 str1 zeroval str2 str3
+4 196 aaa 0 bbb 196-2_a
+3 197 aaa 0 bbb 197-1_A
+2 198 aaa 0 bbb 198-1_a
+1 199 aaa 0 bbb 199-0_A
+0 200 aaa 0 bbb 200-0_a
+drop table t1;
+create table t1 (
+pk integer not null auto_increment primary key,
+key1 integer,
+key2 integer not null,
+filler char (200),
+index (key1),
+index (key2)
+) engine=innodb;
+show warnings;
+Level Code Message
+explain select pk from t1 where key1 = 1 and key2 = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2 key1,key2 5,4 NULL 1 Using intersect(key1,key2); Using where; Using index
+select pk from t1 where key2 = 1 and key1 = 1;
+pk
+26
+27
+select pk from t1 ignore index(key1,key2) where key2 = 1 and key1 = 1;
+pk
+26
+27
+drop table t1;
+create table t1 (
+pk int primary key auto_increment,
+key1a int,
+key2a int,
+key1b int,
+key2b int,
+dummy1 int,
+dummy2 int,
+dummy3 int,
+dummy4 int,
+key3a int,
+key3b int,
+filler1 char (200),
+index i1(key1a, key1b),
+index i2(key2a, key2b),
+index i3(key3a, key3b)
+) engine=innodb;
+create table t2 (a int);
+insert into t2 values (0),(1),(2),(3),(4),(NULL);
+insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b)
+select A.a, B.a, C.a, D.a, C.a, D.a from t2 A,t2 B,t2 C, t2 D;
+insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b)
+select key1a, key1b, key2a, key2b, key3a, key3b from t1;
+insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b)
+select key1a, key1b, key2a, key2b, key3a, key3b from t1;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select count(*) from t1;
+count(*)
+5184
+explain select count(*) from t1 where
+key1a = 2 and key1b is null and key2a = 2 and key2b is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge i1,i2 i1,i2 10,10 NULL 3 Using intersect(i1,i2); Using where; Using index
+select count(*) from t1 where
+key1a = 2 and key1b is null and key2a = 2 and key2b is null;
+count(*)
+4
+explain select count(*) from t1 where
+key1a = 2 and key1b is null and key3a = 2 and key3b is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge i1,i3 i1,i3 10,10 NULL 3 Using intersect(i1,i3); Using where; Using index
+select count(*) from t1 where
+key1a = 2 and key1b is null and key3a = 2 and key3b is null;
+count(*)
+4
+drop table t1,t2;
diff --git a/mysql-test/r/index_merge_innodb2.result b/mysql-test/r/index_merge_innodb2.result
new file mode 100644
index 00000000000..91dd989fe90
--- /dev/null
+++ b/mysql-test/r/index_merge_innodb2.result
@@ -0,0 +1,136 @@
+drop table if exists t1;
+create table t1 (
+pk int primary key,
+key1 int,
+key2 int,
+filler char(200),
+filler2 char(200),
+index(key1),
+index(key2)
+) engine=innodb;
+select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
+pk key1 key2 filler filler2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+9 9 9 filler-data filler-data-2
+10 10 10 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+5 5 5 filler-data filler-data-2
+6 6 6 filler-data filler-data-2
+7 7 7 filler-data filler-data-2
+8 8 8 filler-data filler-data-2
+set @maxv=1000;
+select * from t1 where
+(pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+or key1=18 or key1=60;
+pk key1 key2 filler filler2
+18 18 18 filler-data filler-data-2
+60 60 60 filler-data filler-data-2
+1 1 1 filler-data filler-data-2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+11 11 11 filler-data filler-data-2
+12 12 12 filler-data filler-data-2
+13 13 13 filler-data filler-data-2
+14 14 14 filler-data filler-data-2
+50 50 50 filler-data filler-data-2
+51 51 51 filler-data filler-data-2
+52 52 52 filler-data filler-data-2
+53 53 53 filler-data filler-data-2
+54 54 54 filler-data filler-data-2
+991 991 991 filler-data filler-data-2
+992 992 992 filler-data filler-data-2
+993 993 993 filler-data filler-data-2
+994 994 994 filler-data filler-data-2
+995 995 995 filler-data filler-data-2
+996 996 996 filler-data filler-data-2
+997 997 997 filler-data filler-data-2
+998 998 998 filler-data filler-data-2
+999 999 999 filler-data filler-data-2
+1000 1000 1000 filler-data filler-data-2
+select * from t1 where
+(pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+or key1 < 3 or key1 > @maxv-11;
+pk key1 key2 filler filler2
+990 990 990 filler-data filler-data-2
+1 1 1 filler-data filler-data-2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+11 11 11 filler-data filler-data-2
+12 12 12 filler-data filler-data-2
+13 13 13 filler-data filler-data-2
+14 14 14 filler-data filler-data-2
+50 50 50 filler-data filler-data-2
+51 51 51 filler-data filler-data-2
+52 52 52 filler-data filler-data-2
+53 53 53 filler-data filler-data-2
+54 54 54 filler-data filler-data-2
+991 991 991 filler-data filler-data-2
+992 992 992 filler-data filler-data-2
+993 993 993 filler-data filler-data-2
+994 994 994 filler-data filler-data-2
+995 995 995 filler-data filler-data-2
+996 996 996 filler-data filler-data-2
+997 997 997 filler-data filler-data-2
+998 998 998 filler-data filler-data-2
+999 999 999 filler-data filler-data-2
+1000 1000 1000 filler-data filler-data-2
+select * from t1 where
+(pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+or
+(key1 < 5) or (key1 > 10 and key1 < 15) or (key1 >= 50 and key1 < 55 ) or (key1 > @maxv-10);
+pk key1 key2 filler filler2
+1 1 1 filler-data filler-data-2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+11 11 11 filler-data filler-data-2
+12 12 12 filler-data filler-data-2
+13 13 13 filler-data filler-data-2
+14 14 14 filler-data filler-data-2
+50 50 50 filler-data filler-data-2
+51 51 51 filler-data filler-data-2
+52 52 52 filler-data filler-data-2
+53 53 53 filler-data filler-data-2
+54 54 54 filler-data filler-data-2
+991 991 991 filler-data filler-data-2
+992 992 992 filler-data filler-data-2
+993 993 993 filler-data filler-data-2
+994 994 994 filler-data filler-data-2
+995 995 995 filler-data filler-data-2
+996 996 996 filler-data filler-data-2
+997 997 997 filler-data filler-data-2
+998 998 998 filler-data filler-data-2
+999 999 999 filler-data filler-data-2
+1000 1000 1000 filler-data filler-data-2
+select * from t1 where
+(pk > 10 and pk < 15) or (pk >= 50 and pk < 55 )
+or
+(key1 < 5) or (key1 > @maxv-10);
+pk key1 key2 filler filler2
+1 1 1 filler-data filler-data-2
+2 2 2 filler-data filler-data-2
+3 3 3 filler-data filler-data-2
+4 4 4 filler-data filler-data-2
+991 991 991 filler-data filler-data-2
+992 992 992 filler-data filler-data-2
+993 993 993 filler-data filler-data-2
+994 994 994 filler-data filler-data-2
+995 995 995 filler-data filler-data-2
+996 996 996 filler-data filler-data-2
+997 997 997 filler-data filler-data-2
+998 998 998 filler-data filler-data-2
+999 999 999 filler-data filler-data-2
+1000 1000 1000 filler-data filler-data-2
+11 11 11 filler-data filler-data-2
+12 12 12 filler-data filler-data-2
+13 13 13 filler-data filler-data-2
+14 14 14 filler-data filler-data-2
+50 50 50 filler-data filler-data-2
+51 51 51 filler-data filler-data-2
+52 52 52 filler-data filler-data-2
+53 53 53 filler-data filler-data-2
+54 54 54 filler-data filler-data-2
+drop table t1;
diff --git a/mysql-test/r/index_merge_ror.result b/mysql-test/r/index_merge_ror.result
new file mode 100644
index 00000000000..a1d306c3ea4
--- /dev/null
+++ b/mysql-test/r/index_merge_ror.result
@@ -0,0 +1,196 @@
+drop table if exists t0,t1,t2;
+select count(*) from t1;
+count(*)
+64801
+explain select key1,key2 from t1 where key1=100 and key2=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using intersect(key1,key2); Using where; Using index
+select key1,key2 from t1 where key1=100 and key2=100;
+key1 key2
+100 100
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+key1 key2 key3 key4 filler1
+100 100 100 100 key1-key2-key3-key4
+insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1-key2');
+insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3');
+explain select key1,key2,filler1 from t1 where key1=100 and key2=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using intersect(key1,key2); Using where
+select key1,key2,filler1 from t1 where key1=100 and key2=100;
+key1 key2 filler1
+100 100 key1-key2-key3-key4
+100 100 key1-key2
+explain select key1,key2 from t1 where key1=100 and key2=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using intersect(key1,key2); Using where; Using index
+select key1,key2 from t1 where key1=100 and key2=100;
+key1 key2
+100 100
+100 100
+explain select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where
+select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+key1 key2 key3 key4
+100 100 100 100
+100 100 -1 -1
+-1 -1 100 100
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+key1 key2 key3 key4 filler1
+100 100 100 100 key1-key2-key3-key4
+100 100 -1 -1 key1-key2
+-1 -1 100 100 key4-key3
+explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL 1 Using intersect(key1,key2,key3); Using where; Using index
+select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100;
+key1 key2 key3
+100 100 100
+insert into t1 (key1,key2,key3,key4,filler1) values (101,101,101,101, 'key1234-101');
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL 5 Using union(intersect(key1,key2),key3); Using where
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101;
+key1 key2 key3 key4 filler1
+100 100 100 100 key1-key2-key3-key4
+100 100 -1 -1 key1-key2
+101 101 101 101 key1234-101
+select key1,key2, filler1 from t1 where key1=100 and key2=100;
+key1 key2 filler1
+100 100 key1-key2-key3-key4
+100 100 key1-key2
+update t1 set filler1='to be deleted' where key1=100 and key2=100;
+update t1 set key1=200,key2=200 where key1=100 and key2=100;
+delete from t1 where key1=200 and key2=200;
+select key1,key2,filler1 from t1 where key2=100 and key2=200;
+key1 key2 filler1
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+key1 key2 key3 key4 filler1
+-1 -1 100 100 key4-key3
+delete from t1 where key3=100 and key4=100;
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+key1 key2 key3 key4 filler1
+explain select key1,key2 from t1 where key1=100 and key2=100;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using intersect(key1,key2); Using where; Using index
+select key1,key2 from t1 where key1=100 and key2=100;
+key1 key2
+insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-1');
+insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-2');
+insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3');
+explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 16 Using union(key3,intersect(key1,key2),key4); Using where
+select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+key1 key2 key3 key4 filler1
+100 100 200 200 key1-key2-key3-key4-3
+100 100 200 200 key1-key2-key3-key4-2
+100 100 200 200 key1-key2-key3-key4-1
+insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4');
+explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 18 Using union(key3,intersect(key1,key2),key4); Using where
+select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+key1 key2 key3 key4 filler1
+100 100 200 200 key1-key2-key3-key4-3
+100 100 200 200 key1-key2-key3-key4-2
+100 100 200 200 key1-key2-key3-key4-1
+-1 -1 -1 200 key4
+insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3');
+explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 20 Using union(key3,intersect(key1,key2),key4); Using where
+select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+key1 key2 key3 key4 filler1
+100 100 200 200 key1-key2-key3-key4-3
+100 100 200 200 key1-key2-key3-key4-2
+100 100 200 200 key1-key2-key3-key4-1
+-1 -1 -1 200 key4
+-1 -1 200 -1 key3
+explain select * from t1 where st_a=1 and st_b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL 2508 Using intersect(st_a,st_b); Using where
+explain select st_a,st_b from t1 where st_a=1 and st_b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL 2508 Using intersect(st_a,st_b); Using where; Using index
+explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,stb_swt1a_2b,stb_swt1b,st_b st_b 4 const 14720 Using where
+explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a sta_swt12a 12 const,const,const 958
+explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref stb_swt1a_2b,stb_swt1b,st_b stb_swt1b 8 const,const 3757 Using where
+explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL 42 Using intersect(sta_swt12a,stb_swt1a_2b); Using where
+explain select * from t1 ignore index (sta_swt21a, stb_swt1a_2b)
+where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt12a,stb_swt1b 12,8 NULL 42 Using intersect(sta_swt12a,stb_swt1b); Using where
+explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b)
+where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt1a,sta_swt2a,stb_swt1b 8,8,8 NULL 41 Using intersect(sta_swt1a,sta_swt2a,stb_swt1b); Using where
+explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b, stb_swt1b)
+where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,st_b sta_swt1a,sta_swt2a,st_b 8,8,4 NULL 159 Using intersect(sta_swt1a,sta_swt2a,st_b); Using where
+explain select * from t1
+where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL 42 Using intersect(sta_swt12a,stb_swt1a_2b); Using where
+explain select * from t1
+where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using intersect(sta_swt1a,stb_swt1b); Using where
+explain select st_a from t1
+where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using intersect(sta_swt1a,stb_swt1b); Using where; Using index
+explain select st_a from t1
+where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using intersect(sta_swt1a,stb_swt1b); Using where; Using index
+drop table t0,t1;
+create table t2 (
+a char(10),
+b char(10),
+filler1 char(255),
+filler2 char(255),
+key(a(5)),
+key(b(5))
+);
+select count(a) from t2 where a='BBBBBBBB';
+count(a)
+4
+select count(a) from t2 where b='BBBBBBBB';
+count(a)
+4
+expla_or_bin select count(a_or_b) from t2 where a_or_b='AAAAAAAA' a_or_bnd a_or_b='AAAAAAAA';
+id select_type ta_or_ba_or_ble type possia_or_ble_keys key key_len ref rows Extra_or_b
+1 SIMPLE t2 ref a_or_b,a_or_b a_or_b 6 const 4 Using where
+select count(a) from t2 where a='AAAAAAAA' and b='AAAAAAAA';
+count(a)
+4
+select count(a) from t2 ignore index(a,b) where a='AAAAAAAA' and b='AAAAAAAA';
+count(a)
+4
+insert into t2 values ('ab', 'ab', 'uh', 'oh');
+explain select a from t2 where a='ab';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ref a a 6 const 1 Using where
+drop table t2;
diff --git a/mysql-test/r/index_merge_ror_cpk.result b/mysql-test/r/index_merge_ror_cpk.result
new file mode 100644
index 00000000000..79bb1297abf
--- /dev/null
+++ b/mysql-test/r/index_merge_ror_cpk.result
@@ -0,0 +1,120 @@
+drop table if exists t1;
+create table t1
+(
+pk1 int not null,
+pk2 int not null,
+key1 int not null,
+key2 int not null,
+pktail1ok int not null,
+pktail2ok int not null,
+pktail3bad int not null,
+pktail4bad int not null,
+pktail5bad int not null,
+pk2copy int not null,
+badkey int not null,
+filler1 char (200),
+filler2 char (200),
+key (key1),
+key (key2),
+/* keys with tails from CPK members */
+key (pktail1ok, pk1),
+key (pktail2ok, pk1, pk2),
+key (pktail3bad, pk2, pk1),
+key (pktail4bad, pk1, pk2copy),
+key (pktail5bad, pk1, pk2, pk2copy),
+primary key (pk1, pk2)
+) engine=innodb;
+explain select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range PRIMARY,key1 PRIMARY 8 NULL 9 Using where
+select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
+pk1 pk2 key1 key2 pktail1ok pktail2ok pktail3bad pktail4bad pktail5bad pk2copy badkey filler1 filler2
+1 10 0 0 0 0 0 0 0 10 0 filler-data-10 filler2
+1 11 0 0 0 0 0 0 0 11 0 filler-data-11 filler2
+1 12 0 0 0 0 0 0 0 12 0 filler-data-12 filler2
+1 13 0 0 0 0 0 0 0 13 0 filler-data-13 filler2
+1 14 0 0 0 0 0 0 0 14 0 filler-data-14 filler2
+1 15 0 0 0 0 0 0 0 15 0 filler-data-15 filler2
+1 16 0 0 0 0 0 0 0 16 0 filler-data-16 filler2
+1 17 0 0 0 0 0 0 0 17 0 filler-data-17 filler2
+1 18 0 0 0 0 0 0 0 18 0 filler-data-18 filler2
+1 19 0 0 0 0 0 0 0 19 0 filler-data-19 filler2
+explain select pk1,pk2 from t1 where key1 = 10 and key2=10 and 2*pk1+1 < 2*96+1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2 key1,key2 4,4 NULL 1 Using intersect(key1,key2); Using where; Using index
+select pk1,pk2 from t1 where key1 = 10 and key2=10 and 2*pk1+1 < 2*96+1;
+pk1 pk2
+95 50
+95 51
+95 52
+95 53
+95 54
+95 55
+95 56
+95 57
+95 58
+95 59
+explain select * from t1 where badkey=1 and key1=10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref key1 key1 4 const 100 Using where
+explain select * from t1 where pk1 < 7500 and key1 = 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge PRIMARY,key1 key1,PRIMARY 4,4 NULL ROWS Using intersect(key1,PRIMARY); Using where
+explain select * from t1 where pktail1ok=1 and key1=10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,pktail1ok key1,pktail1ok 4,4 NULL 1 Using intersect(key1,pktail1ok); Using where
+explain select * from t1 where pktail2ok=1 and key1=10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,pktail2ok key1,pktail2ok 4,4 NULL 1 Using intersect(key1,pktail2ok); Using where
+select ' The following is actually a deficiency, it uses sort_union currently:' as 'note:';
+note:
+ The following is actually a deficiency, it uses sort_union currently:
+explain select * from t1 where (pktail2ok=1 and pk1< 50000) or key1=10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge PRIMARY,key1,pktail2ok pktail2ok,key1 8,4 NULL 199 Using sort_union(pktail2ok,key1); Using where
+explain select * from t1 where pktail3bad=1 and key1=10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref key1,pktail3bad key1 4 const 100 Using where
+explain select * from t1 where pktail4bad=1 and key1=10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref key1,pktail4bad key1 4 const 100 Using where
+explain select * from t1 where pktail5bad=1 and key1=10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref key1,pktail5bad key1 4 const 100 Using where
+explain select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2 key1,key2 4,4 NULL 1 Using intersect(key1,key2); Using where; Using index
+select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10;
+pk1 pk2 key1 key2
+95 50 10 10
+95 51 10 10
+95 52 10 10
+95 53 10 10
+95 54 10 10
+95 55 10 10
+95 56 10 10
+95 57 10 10
+95 58 10 10
+95 59 10 10
+drop table t1;
+create table t1
+(
+RUNID varchar(22),
+SUBMITNR varchar(5),
+ORDERNR char(1) ,
+PROGRAMM varchar(8),
+TESTID varchar(4),
+UCCHECK char(1),
+ETEXT varchar(80),
+ETEXT_TYPE char(1),
+INFO char(1),
+SEVERITY tinyint(3),
+TADIRFLAG char(1),
+PRIMARY KEY (RUNID,SUBMITNR,ORDERNR,PROGRAMM,TESTID,UCCHECK),
+KEY `TVERM~KEY` (PROGRAMM,TESTID,UCCHECK)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+update t1 set `ETEXT` = '', `ETEXT_TYPE`='', `INFO`='', `SEVERITY`='', `TADIRFLAG`=''
+WHERE
+`RUNID`= '' AND `SUBMITNR`= '' AND `ORDERNR`='' AND `PROGRAMM`='' AND
+`TESTID`='' AND `UCCHECK`='';
+drop table t1;
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
new file mode 100644
index 00000000000..c53779582f1
--- /dev/null
+++ b/mysql-test/r/information_schema.result
@@ -0,0 +1,728 @@
+show variables where variable_name like "skip_show_database";
+Variable_name Value
+skip_show_database OFF
+grant select, update, execute on test.* to mysqltest_2@localhost;
+grant select, update on test.* to mysqltest_1@localhost;
+select * from information_schema.SCHEMATA where schema_name > 'm';
+CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME SQL_PATH
+NULL mysql latin1 NULL
+NULL test latin1 NULL
+select schema_name from information_schema.schemata;
+schema_name
+information_schema
+mysql
+test
+show databases like 't%';
+Database (t%)
+test
+show databases;
+Database
+information_schema
+mysql
+test
+show databases where `database` = 't%';
+Database
+create database mysqltest;
+create table mysqltest.t1(a int, b VARCHAR(30), KEY string_data (b));
+create table test.t2(a int);
+create table t3(a int, KEY a_data (a));
+create table mysqltest.t4(a int);
+create view v1 (c) as select table_name from information_schema.TABLES;
+select * from v1;
+c
+SCHEMATA
+TABLES
+COLUMNS
+CHARACTER_SETS
+COLLATIONS
+COLLATION_CHARACTER_SET_APPLICABILITY
+ROUTINES
+STATISTICS
+VIEWS
+USER_PRIVILEGES
+SCHEMA_PRIVILEGES
+TABLE_PRIVILEGES
+COLUMN_PRIVILEGES
+TABLE_CONSTRAINTS
+KEY_COLUMN_USAGE
+columns_priv
+db
+func
+help_category
+help_keyword
+help_relation
+help_topic
+host
+proc
+procs_priv
+tables_priv
+time_zone
+time_zone_leap_second
+time_zone_name
+time_zone_transition
+time_zone_transition_type
+user
+t1
+t4
+t2
+t3
+v1
+select c,table_name from v1
+inner join information_schema.TABLES v2 on (v1.c=v2.table_name)
+where v1.c like "t%";
+c table_name
+TABLES TABLES
+TABLE_PRIVILEGES TABLE_PRIVILEGES
+TABLE_CONSTRAINTS TABLE_CONSTRAINTS
+tables_priv tables_priv
+time_zone time_zone
+time_zone_leap_second time_zone_leap_second
+time_zone_name time_zone_name
+time_zone_transition time_zone_transition
+time_zone_transition_type time_zone_transition_type
+t1 t1
+t4 t4
+t2 t2
+t3 t3
+select c,table_name from v1
+left join information_schema.TABLES v2 on (v1.c=v2.table_name)
+where v1.c like "t%";
+c table_name
+TABLES TABLES
+TABLE_PRIVILEGES TABLE_PRIVILEGES
+TABLE_CONSTRAINTS TABLE_CONSTRAINTS
+tables_priv tables_priv
+time_zone time_zone
+time_zone_leap_second time_zone_leap_second
+time_zone_name time_zone_name
+time_zone_transition time_zone_transition
+time_zone_transition_type time_zone_transition_type
+t1 t1
+t4 t4
+t2 t2
+t3 t3
+select c, v2.table_name from v1
+right join information_schema.TABLES v2 on (v1.c=v2.table_name)
+where v1.c like "t%";
+c table_name
+TABLES TABLES
+TABLE_PRIVILEGES TABLE_PRIVILEGES
+TABLE_CONSTRAINTS TABLE_CONSTRAINTS
+tables_priv tables_priv
+time_zone time_zone
+time_zone_leap_second time_zone_leap_second
+time_zone_name time_zone_name
+time_zone_transition time_zone_transition
+time_zone_transition_type time_zone_transition_type
+t1 t1
+t4 t4
+t2 t2
+t3 t3
+select table_name from information_schema.TABLES
+where table_schema = "mysqltest" and table_name like "t%";
+table_name
+t1
+t4
+select * from information_schema.STATISTICS where TABLE_SCHEMA = "mysqltest";
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT
+NULL mysqltest t1 1 mysqltest string_data 1 b A NULL NULL NULL YES BTREE
+show keys from t3 where Key_name = "a_data";
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t3 1 a_data 1 a A NULL NULL NULL YES BTREE
+show tables like 't%';
+Tables_in_test (t%)
+t2
+t3
+show table status;
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL
+t3 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL
+v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL view
+show full columns from t3 like "a%";
+Field Type Collation Null Key Default Extra Privileges Comment
+a int(11) NULL YES MUL NULL select,insert,update,references
+show full columns from mysql.db like "Insert%";
+Field Type Collation Null Key Default Extra Privileges Comment
+Insert_priv enum('N','Y') utf8_general_ci NO N select,insert,update,references
+show full columns from v1;
+Field Type Collation Null Key Default Extra Privileges Comment
+c varchar(64) utf8_general_ci NO select,insert,update,references
+select * from information_schema.COLUMNS where table_name="t1"
+and column_name= "a";
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT
+NULL mysqltest t1 a 1 NULL YES int NULL NULL 11 0 NULL NULL int(11) select,insert,update,references
+show columns from mysqltest.t1 where field like "%a%";
+Field Type Null Key Default Extra
+a int(11) YES NULL
+grant select (a) on mysqltest.t1 to mysqltest_2@localhost;
+select table_name, column_name, privileges from information_schema.columns
+where table_schema = 'mysqltest' and table_name = 't1';
+table_name column_name privileges
+t1 a select
+show columns from mysqltest.t1;
+Field Type Null Key Default Extra
+a int(11) YES NULL
+b varchar(30) YES MUL NULL
+drop view v1;
+drop tables mysqltest.t4, mysqltest.t1, t2, t3;
+drop database mysqltest;
+select * from information_schema.CHARACTER_SETS
+where CHARACTER_SET_NAME like 'latin1%';
+CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN
+latin1 latin1_swedish_ci ISO 8859-1 West European 1
+SHOW CHARACTER SET LIKE 'latin1%';
+Charset Description Default collation Maxlen
+latin1 ISO 8859-1 West European latin1_swedish_ci 1
+SHOW CHARACTER SET WHERE charset like 'latin1%';
+Charset Description Default collation Maxlen
+latin1 ISO 8859-1 West European latin1_swedish_ci 1
+select * from information_schema.COLLATIONS
+where COLLATION_NAME like 'latin1%';
+COLLATION_NAME CHARACTER_SET_NAME ID IS_DEFAULT IS_COMPILED SORTLEN
+latin1_german1_ci latin1 5 0
+latin1_swedish_ci latin1 8 Yes Yes 1
+latin1_danish_ci latin1 15 0
+latin1_german2_ci latin1 31 Yes 2
+latin1_bin latin1 47 Yes 1
+latin1_general_ci latin1 48 0
+latin1_general_cs latin1 49 0
+latin1_spanish_ci latin1 94 0
+SHOW COLLATION LIKE 'latin1%';
+Collation Charset Id Default Compiled Sortlen
+latin1_german1_ci latin1 5 0
+latin1_swedish_ci latin1 8 Yes Yes 1
+latin1_danish_ci latin1 15 0
+latin1_german2_ci latin1 31 Yes 2
+latin1_bin latin1 47 Yes 1
+latin1_general_ci latin1 48 0
+latin1_general_cs latin1 49 0
+latin1_spanish_ci latin1 94 0
+SHOW COLLATION WHERE collation like 'latin1%';
+Collation Charset Id Default Compiled Sortlen
+latin1_german1_ci latin1 5 0
+latin1_swedish_ci latin1 8 Yes Yes 1
+latin1_danish_ci latin1 15 0
+latin1_german2_ci latin1 31 Yes 2
+latin1_bin latin1 47 Yes 1
+latin1_general_ci latin1 48 0
+latin1_general_cs latin1 49 0
+latin1_spanish_ci latin1 94 0
+select * from information_schema.COLLATION_CHARACTER_SET_APPLICABILITY
+where COLLATION_NAME like 'latin1%';
+COLLATION_NAME CHARACTER_SET_NAME
+latin1_german1_ci latin1
+latin1_swedish_ci latin1
+latin1_danish_ci latin1
+latin1_german2_ci latin1
+latin1_bin latin1
+latin1_general_ci latin1
+latin1_general_cs latin1
+latin1_spanish_ci latin1
+create function sub1(i int) returns int
+return i+1;
+create procedure sel2()
+begin
+select * from t1;
+select * from t2;
+end|
+select parameter_style, sql_data_access, dtd_identifier
+from information_schema.routines;
+parameter_style sql_data_access dtd_identifier
+SQL CONTAINS SQL NULL
+SQL CONTAINS SQL int(11)
+show procedure status;
+Db Name Type Definer Modified Created Security_type Comment
+test sel2 PROCEDURE root@localhost # # DEFINER
+show function status;
+Db Name Type Definer Modified Created Security_type Comment
+test sub1 FUNCTION root@localhost # # DEFINER
+select a.ROUTINE_NAME from information_schema.ROUTINES a,
+information_schema.SCHEMATA b where
+a.ROUTINE_SCHEMA = b.SCHEMA_NAME;
+ROUTINE_NAME
+sel2
+sub1
+explain select a.ROUTINE_NAME from information_schema.ROUTINES a,
+information_schema.SCHEMATA b where
+a.ROUTINE_SCHEMA = b.SCHEMA_NAME;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE # ALL NULL NULL NULL NULL 2
+1 SIMPLE # ALL NULL NULL NULL NULL 2 Using where
+select a.ROUTINE_NAME, b.name from information_schema.ROUTINES a,
+mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8);
+ROUTINE_NAME name
+sub1 sub1
+sel2 sel2
+select count(*) from information_schema.ROUTINES;
+count(*)
+2
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+show create function sub1;
+ERROR 42000: FUNCTION sub1 does not exist
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+sel2
+sub1
+grant all privileges on test.* to mysqltest_1@localhost;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+sel2
+sub1
+create function sub2(i int) returns int
+return i+1;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+sel2
+sub1
+sub2 return i+1
+show create procedure sel2;
+Procedure sql_mode Create Procedure
+sel2
+show create function sub1;
+Function sql_mode Create Function
+sub1
+show create function sub2;
+Function sql_mode Create Function
+sub2 CREATE FUNCTION `test`.`sub2`(i int) RETURNS int(11)
+return i+1
+drop function sub2;
+show create procedure sel2;
+Procedure sql_mode Create Procedure
+sel2 CREATE PROCEDURE `test`.`sel2`()
+begin
+select * from t1;
+select * from t2;
+end
+create view v0 (c) as select schema_name from information_schema.schemata;
+select * from v0;
+c
+information_schema
+mysql
+test
+explain select * from v0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY # ALL NULL NULL NULL NULL 2
+create view v1 (c) as select table_name from information_schema.tables
+where table_name="v1";
+select * from v1;
+c
+v1
+create view v2 (c) as select column_name from information_schema.columns
+where table_name="v2";
+select * from v2;
+c
+c
+create view v3 (c) as select CHARACTER_SET_NAME from information_schema.character_sets
+where CHARACTER_SET_NAME like "latin1%";
+select * from v3;
+c
+latin1
+create view v4 (c) as select COLLATION_NAME from information_schema.collations
+where COLLATION_NAME like "latin1%";
+select * from v4;
+c
+latin1_german1_ci
+latin1_swedish_ci
+latin1_danish_ci
+latin1_german2_ci
+latin1_bin
+latin1_general_ci
+latin1_general_cs
+latin1_spanish_ci
+show keys from v4;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+select * from information_schema.views where TABLE_NAME like "v%";
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE
+NULL test v0 select sql_no_cache `schemata`.`SCHEMA_NAME` AS `c` from `information_schema`.`schemata` NONE NO
+NULL test v1 select sql_no_cache `tables`.`TABLE_NAME` AS `c` from `information_schema`.`tables` where (`tables`.`TABLE_NAME` = _utf8'v1') NONE NO
+NULL test v2 select sql_no_cache `columns`.`COLUMN_NAME` AS `c` from `information_schema`.`columns` where (`columns`.`TABLE_NAME` = _utf8'v2') NONE NO
+NULL test v3 select sql_no_cache `character_sets`.`CHARACTER_SET_NAME` AS `c` from `information_schema`.`character_sets` where (`character_sets`.`CHARACTER_SET_NAME` like _utf8'latin1%') NONE NO
+NULL test v4 select sql_no_cache `collations`.`COLLATION_NAME` AS `c` from `information_schema`.`collations` where (`collations`.`COLLATION_NAME` like _utf8'latin1%') NONE NO
+drop view v0, v1, v2, v3, v4;
+create table t1 (a int);
+grant select,update,insert on t1 to mysqltest_1@localhost;
+grant select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost;
+grant all on test.* to mysqltest_1@localhost with grant option;
+select * from information_schema.USER_PRIVILEGES where grantee like '%mysqltest_1%';
+GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_1'@'localhost' NULL USAGE NO
+select * from information_schema.SCHEMA_PRIVILEGES where grantee like '%mysqltest_1%';
+GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_1'@'localhost' NULL test SELECT YES
+'mysqltest_1'@'localhost' NULL test INSERT YES
+'mysqltest_1'@'localhost' NULL test UPDATE YES
+'mysqltest_1'@'localhost' NULL test DELETE YES
+'mysqltest_1'@'localhost' NULL test CREATE YES
+'mysqltest_1'@'localhost' NULL test DROP YES
+'mysqltest_1'@'localhost' NULL test REFERENCES YES
+'mysqltest_1'@'localhost' NULL test INDEX YES
+'mysqltest_1'@'localhost' NULL test ALTER YES
+'mysqltest_1'@'localhost' NULL test CREATE TEMPORARY TABLES YES
+'mysqltest_1'@'localhost' NULL test LOCK TABLES YES
+'mysqltest_1'@'localhost' NULL test EXECUTE YES
+'mysqltest_1'@'localhost' NULL test CREATE VIEW YES
+'mysqltest_1'@'localhost' NULL test SHOW VIEW YES
+'mysqltest_1'@'localhost' NULL test CREATE ROUTINE YES
+'mysqltest_1'@'localhost' NULL test ALTER ROUTINE YES
+select * from information_schema.TABLE_PRIVILEGES where grantee like '%mysqltest_1%';
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_1'@'localhost' NULL test t1 SELECT NO
+'mysqltest_1'@'localhost' NULL test t1 INSERT NO
+'mysqltest_1'@'localhost' NULL test t1 UPDATE NO
+select * from information_schema.COLUMN_PRIVILEGES where grantee like '%mysqltest_1%';
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE
+'mysqltest_1'@'localhost' NULL test t1 a SELECT NO
+'mysqltest_1'@'localhost' NULL test t1 a INSERT NO
+'mysqltest_1'@'localhost' NULL test t1 a UPDATE NO
+'mysqltest_1'@'localhost' NULL test t1 a REFERENCES NO
+delete from mysql.user where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.db where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.tables_priv where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.columns_priv where user='mysqltest_1' or user='mysqltest_2';
+flush privileges;
+drop table t1;
+create table t1 (a int null, primary key(a));
+alter table t1 add constraint constraint_1 unique (a);
+alter table t1 add constraint unique key_1(a);
+alter table t1 add constraint constraint_2 unique key_2(a);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL default '0',
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `constraint_1` (`a`),
+ UNIQUE KEY `key_1` (`a`),
+ UNIQUE KEY `key_2` (`a`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select * from information_schema.TABLE_CONSTRAINTS where
+TABLE_SCHEMA= "test";
+CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE
+NULL test PRIMARY test t1 PRIMARY KEY
+NULL test constraint_1 test t1 UNIQUE
+NULL test key_1 test t1 UNIQUE
+NULL test key_2 test t1 UNIQUE
+select * from information_schema.KEY_COLUMN_USAGE where
+TABLE_SCHEMA= "test";
+CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION POSITION_IN_UNIQUE_CONSTRAINT
+NULL test PRIMARY NULL test t1 a 1 NULL
+NULL test constraint_1 NULL test t1 a 1 NULL
+NULL test key_1 NULL test t1 a 1 NULL
+NULL test key_2 NULL test t1 a 1 NULL
+select table_name from information_schema.TABLES where table_schema like "test%";
+table_name
+t1
+select table_name,column_name from information_schema.COLUMNS where table_schema like "test%";
+table_name column_name
+t1 a
+select ROUTINE_NAME from information_schema.ROUTINES;
+ROUTINE_NAME
+sel2
+sub1
+delete from mysql.user where user='mysqltest_1';
+drop table t1;
+drop procedure sel2;
+drop function sub1;
+create table t1(a int);
+create view v1 (c) as select a from t1 with check option;
+create view v2 (c) as select a from t1 WITH LOCAL CHECK OPTION;
+create view v3 (c) as select a from t1 WITH CASCADED CHECK OPTION;
+select * from information_schema.views;
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME VIEW_DEFINITION CHECK_OPTION IS_UPDATABLE
+NULL test v1 select `test`.`t1`.`a` AS `c` from `test`.`t1` CASCADED YES
+NULL test v2 select `test`.`t1`.`a` AS `c` from `test`.`t1` LOCAL YES
+NULL test v3 select `test`.`t1`.`a` AS `c` from `test`.`t1` CASCADED YES
+grant select (a) on test.t1 to joe@localhost with grant option;
+select * from INFORMATION_SCHEMA.COLUMN_PRIVILEGES;
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE
+'joe'@'localhost' NULL test t1 a SELECT YES
+select * from INFORMATION_SCHEMA.TABLE_PRIVILEGES;
+GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
+drop view v1, v2, v3;
+drop table t1;
+delete from mysql.user where user='joe';
+delete from mysql.db where user='joe';
+delete from mysql.tables_priv where user='joe';
+delete from mysql.columns_priv where user='joe';
+flush privileges;
+create table t1 (a int not null auto_increment,b int, primary key (a));
+insert into t1 values (1,1),(NULL,3),(NULL,4);
+select AUTO_INCREMENT from information_schema.tables where table_name = 't1';
+AUTO_INCREMENT
+4
+drop table t1;
+create table t1 (s1 int);
+insert into t1 values (0),(9),(0);
+select s1 from t1 where s1 in (select version from
+information_schema.tables) union select version from
+information_schema.tables;
+s1
+0
+10
+drop table t1;
+SHOW CREATE TABLE INFORMATION_SCHEMA.character_sets;
+Table Create Table
+character_sets CREATE TEMPORARY TABLE `character_sets` (
+ `CHARACTER_SET_NAME` varchar(64) NOT NULL default '',
+ `DEFAULT_COLLATE_NAME` varchar(64) NOT NULL default '',
+ `DESCRIPTION` varchar(60) NOT NULL default '',
+ `MAXLEN` bigint(3) NOT NULL default '0'
+) ENGINE=MEMORY DEFAULT CHARSET=utf8
+set names latin2;
+SHOW CREATE TABLE INFORMATION_SCHEMA.character_sets;
+Table Create Table
+character_sets CREATE TEMPORARY TABLE `character_sets` (
+ `CHARACTER_SET_NAME` varchar(64) NOT NULL default '',
+ `DEFAULT_COLLATE_NAME` varchar(64) NOT NULL default '',
+ `DESCRIPTION` varchar(60) NOT NULL default '',
+ `MAXLEN` bigint(3) NOT NULL default '0'
+) ENGINE=MEMORY DEFAULT CHARSET=utf8
+set names latin1;
+create table t1 select * from information_schema.CHARACTER_SETS
+where CHARACTER_SET_NAME like "latin1";
+select * from t1;
+CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN
+latin1 latin1_swedish_ci ISO 8859-1 West European 1
+alter table t1 default character set utf8;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `CHARACTER_SET_NAME` varchar(64) NOT NULL default '',
+ `DEFAULT_COLLATE_NAME` varchar(64) NOT NULL default '',
+ `DESCRIPTION` varchar(60) NOT NULL default '',
+ `MAXLEN` bigint(3) NOT NULL default '0'
+) ENGINE=MyISAM DEFAULT CHARSET=utf8
+drop table t1;
+create view v1 as select * from information_schema.TABLES;
+drop view v1;
+create table t1(a NUMERIC(5,3), b NUMERIC(5,1), c float(5,2),
+d NUMERIC(6,4), e float, f DECIMAL(6,3), g int(11), h DOUBLE(10,3),
+i DOUBLE);
+select COLUMN_NAME,COLUMN_TYPE, CHARACTER_MAXIMUM_LENGTH,
+CHARACTER_OCTET_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE
+from information_schema.columns where table_name= 't1';
+COLUMN_NAME COLUMN_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE
+a decimal(5,3) NULL NULL 5 3
+b decimal(5,1) NULL NULL 5 1
+c float(5,2) NULL NULL 5 2
+d decimal(6,4) NULL NULL 6 4
+e float NULL NULL 12 NULL
+f decimal(6,3) NULL NULL 6 3
+g int(11) NULL NULL 11 0
+h double(10,3) NULL NULL 10 3
+i double NULL NULL 22 NULL
+drop table t1;
+create table t115 as select table_name, column_name, column_type
+from information_schema.columns where table_name = 'proc';
+select * from t115;
+table_name column_name column_type
+proc db char(64)
+proc name char(64)
+proc type enum('FUNCTION','PROCEDURE')
+proc specific_name char(64)
+proc language enum('SQL')
+proc sql_data_access enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA')
+proc is_deterministic enum('YES','NO')
+proc security_type enum('INVOKER','DEFINER')
+proc param_list blob
+proc returns char(64)
+proc body blob
+proc definer char(77)
+proc created timestamp
+proc modified timestamp
+proc 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')
+proc comment char(64)
+drop table t115;
+create procedure p108 () begin declare c cursor for select data_type
+from information_schema.columns; open c; open c; end;//
+call p108()//
+ERROR 24000: Cursor is already open
+drop procedure p108;
+create view v1 as select A1.table_name from information_schema.TABLES A1
+where table_name= "user";
+select * from v1;
+table_name
+user
+drop view v1;
+create view vo as select 'a' union select 'a';
+show index from vo;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+select * from information_schema.TABLE_CONSTRAINTS where
+TABLE_NAME= "vo";
+CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE
+select * from information_schema.KEY_COLUMN_USAGE where
+TABLE_NAME= "vo";
+CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION POSITION_IN_UNIQUE_CONSTRAINT
+drop view vo;
+select TABLE_NAME,TABLE_TYPE,ENGINE
+from information_schema.tables
+where table_schema='information_schema' limit 2;
+TABLE_NAME TABLE_TYPE ENGINE
+SCHEMATA TEMPORARY MEMORY
+TABLES TEMPORARY MEMORY
+show tables from information_schema like "T%";
+Tables_in_information_schema (T%)
+TABLES
+TABLE_PRIVILEGES
+TABLE_CONSTRAINTS
+create database information_schema;
+ERROR HY000: Can't create database 'information_schema'; database exists
+use information_schema;
+show full tables like "T%";
+Tables_in_information_schema (T%) Table_type
+TABLES TEMPORARY
+TABLE_PRIVILEGES TEMPORARY
+TABLE_CONSTRAINTS TEMPORARY
+create table t1(a int);
+ERROR 42S02: Unknown table 't1' in information_schema
+use test;
+show tables;
+Tables_in_test
+use information_schema;
+show tables like "T%";
+Tables_in_information_schema (T%)
+TABLES
+TABLE_PRIVILEGES
+TABLE_CONSTRAINTS
+select table_name from tables where table_name='user';
+table_name
+user
+select column_name, privileges from columns
+where table_name='user' and column_name like '%o%';
+column_name privileges
+Host select,insert,update,references
+Password select,insert,update,references
+Drop_priv select,insert,update,references
+Reload_priv select,insert,update,references
+Shutdown_priv select,insert,update,references
+Process_priv select,insert,update,references
+Show_db_priv select,insert,update,references
+Lock_tables_priv select,insert,update,references
+Show_view_priv select,insert,update,references
+Create_routine_priv select,insert,update,references
+Alter_routine_priv select,insert,update,references
+max_questions select,insert,update,references
+max_connections select,insert,update,references
+max_user_connections select,insert,update,references
+use test;
+create function sub1(i int) returns int
+return i+1;
+create table t1(f1 int);
+create view t2 (c) as select f1 from t1;
+create view t3 (c) as select sub1(1);
+create table t4(f1 int, KEY f1_key (f1));
+drop table t1;
+drop function sub1;
+select table_name from information_schema.views
+where table_schema='test';
+table_name
+Warnings:
+Warning 1356 View 'test.t2' references invalid table(s) or column(s) or function(s)
+Warning 1356 View 'test.t3' references invalid table(s) or column(s) or function(s)
+select table_name from information_schema.views
+where table_schema='test';
+table_name
+Warnings:
+Warning 1356 View 'test.t2' references invalid table(s) or column(s) or function(s)
+Warning 1356 View 'test.t3' references invalid table(s) or column(s) or function(s)
+select column_name from information_schema.columns
+where table_schema='test';
+column_name
+f1
+Warnings:
+Warning 1356 View 'test.t2' references invalid table(s) or column(s) or function(s)
+Warning 1356 View 'test.t3' references invalid table(s) or column(s) or function(s)
+select index_name from information_schema.statistics where table_schema='test';
+index_name
+f1_key
+select constraint_name from information_schema.table_constraints
+where table_schema='test';
+constraint_name
+drop view t2;
+drop view t3;
+drop table t4;
+select * from information_schema.table_names;
+ERROR 42S02: Unknown table 'table_names' in information_schema
+select column_type from information_schema.columns
+where table_schema="information_schema" and table_name="COLUMNS" and
+(column_name="character_set_name" or column_name="collation_name");
+column_type
+varchar(64)
+varchar(64)
+select TABLE_ROWS from information_schema.tables where
+table_schema="information_schema" and table_name="COLUMNS";
+TABLE_ROWS
+NULL
+select table_type from information_schema.tables
+where table_schema="mysql" and table_name="user";
+table_type
+BASE TABLE
+show open tables where `table` like "user";
+Database Table In_use Name_locked
+mysql user 0 0
+show status where variable_name like "%database%";
+Variable_name Value
+Com_show_databases 0
+show variables where variable_name like "skip_show_databas";
+Variable_name Value
+show global status like "Threads_running";
+Variable_name Value
+Threads_running 1
+create table t1(f1 int);
+create table t2(f2 int);
+create view v1 as select * from t1, t2;
+set @got_val= (select count(*) from information_schema.columns);
+drop view v1;
+drop table t1, t2;
+CREATE TABLE t_crashme ( f1 BIGINT);
+CREATE VIEW a1 (t_CRASHME) AS SELECT f1 FROM t_crashme GROUP BY f1;
+CREATE VIEW a2 AS SELECT t_CRASHME FROM a1;
+count(*)
+100
+drop view a2, a1;
+drop table t_crashme;
+select table_schema,table_name, column_name from
+information_schema.columns
+where data_type = 'longtext';
+table_schema table_name column_name
+information_schema COLUMNS COLUMN_TYPE
+information_schema ROUTINES ROUTINE_DEFINITION
+information_schema ROUTINES SQL_MODE
+information_schema VIEWS VIEW_DEFINITION
+select table_name, column_name, data_type from information_schema.columns
+where data_type = 'datetime';
+table_name column_name data_type
+TABLES CREATE_TIME datetime
+TABLES UPDATE_TIME datetime
+TABLES CHECK_TIME datetime
+ROUTINES CREATED datetime
+ROUTINES LAST_ALTERED datetime
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES A
+WHERE NOT EXISTS
+(SELECT * FROM INFORMATION_SCHEMA.COLUMNS B
+WHERE A.TABLE_SCHEMA = B.TABLE_SCHEMA
+AND A.TABLE_NAME = B.TABLE_NAME);
+COUNT(*)
+0
+create table t1
+( x_bigint BIGINT,
+x_integer INTEGER,
+x_smallint SMALLINT,
+x_decimal DECIMAL(5,3),
+x_numeric NUMERIC(5,3),
+x_real REAL,
+x_float FLOAT,
+x_double_precision DOUBLE PRECISION );
+SELECT COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH
+FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME= 't1';
+COLUMN_NAME CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH
+x_bigint NULL NULL
+x_integer NULL NULL
+x_smallint NULL NULL
+x_decimal NULL NULL
+x_numeric NULL NULL
+x_real NULL NULL
+x_float NULL NULL
+x_double_precision NULL NULL
+drop table t1;
diff --git a/mysql-test/r/information_schema_inno.result b/mysql-test/r/information_schema_inno.result
new file mode 100644
index 00000000000..a38139ba753
--- /dev/null
+++ b/mysql-test/r/information_schema_inno.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS t1,t2;
+CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
+CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id),
+FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE,
+FOREIGN KEY (t1_id) REFERENCES t1(id) ON UPDATE CASCADE) ENGINE=INNODB;
+select * from information_schema.TABLE_CONSTRAINTS where
+TABLE_SCHEMA= "test";
+CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE
+NULL test PRIMARY test t1 PRIMARY KEY
+NULL test PRIMARY test t2 PRIMARY KEY
+NULL test t2_ibfk_1 test t2 FOREIGN KEY
+NULL test t2_ibfk_2 test t2 FOREIGN KEY
+select * from information_schema.KEY_COLUMN_USAGE where
+TABLE_SCHEMA= "test";
+CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION POSITION_IN_UNIQUE_CONSTRAINT
+NULL test PRIMARY NULL test t1 id 1 NULL
+NULL test PRIMARY NULL test t2 id 1 NULL
+NULL test t2_ibfk_1 NULL test t2 t1_id 1 1
+NULL test t2_ibfk_2 NULL test t2 t1_id 1 1
+drop table t2, t1;
diff --git a/mysql-test/r/init_connect.result b/mysql-test/r/init_connect.result
index db1e72dfca9..eeae422edc4 100644
--- a/mysql-test/r/init_connect.result
+++ b/mysql-test/r/init_connect.result
@@ -12,7 +12,7 @@ set GLOBAL init_connect=DEFAULT;
select @a;
@a
NULL
-set global init_connect="create table t1(a char(10));\
+set global init_connect="drop table if exists t1; create table t1(a char(10));\
insert into t1 values ('\0');insert into t1 values('abc')";
select hex(a) from t1;
hex(a)
diff --git a/mysql-test/r/innodb-big.result b/mysql-test/r/innodb-big.result
new file mode 100644
index 00000000000..19204b7cc65
--- /dev/null
+++ b/mysql-test/r/innodb-big.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS t1, t2, t3, t4;
+CREATE TABLE t1 (id INTEGER) ENGINE=MYISAM;
+CREATE TABLE t2 (id INTEGER primary key) ENGINE=INNODB;
+CREATE TABLE t3 (a char(32) primary key,id INTEGER) ENGINE=INNODB;
+CREATE TABLE t4 (a char(32) primary key,id INTEGER) ENGINE=MYISAM;
+INSERT INTO t1 (id) VALUES (1);
+INSERT INTO t1 SELECT id+1 FROM t1;
+INSERT INTO t1 SELECT id+2 FROM t1;
+INSERT INTO t1 SELECT id+4 FROM t1;
+INSERT INTO t1 SELECT id+8 FROM t1;
+INSERT INTO t1 SELECT id+16 FROM t1;
+INSERT INTO t1 SELECT id+32 FROM t1;
+INSERT INTO t1 SELECT id+64 FROM t1;
+INSERT INTO t1 SELECT id+128 FROM t1;
+INSERT INTO t1 SELECT id+256 FROM t1;
+INSERT INTO t1 SELECT id+512 FROM t1;
+INSERT INTO t1 SELECT id+1024 FROM t1;
+INSERT INTO t1 SELECT id+2048 FROM t1;
+INSERT INTO t1 SELECT id+4096 FROM t1;
+INSERT INTO t1 SELECT id+8192 FROM t1;
+INSERT INTO t1 SELECT id+16384 FROM t1;
+INSERT INTO t1 SELECT id+32768 FROM t1;
+INSERT INTO t1 SELECT id+65536 FROM t1;
+INSERT INTO t1 SELECT id+131072 FROM t1;
+INSERT INTO t1 SELECT id+262144 FROM t1;
+INSERT INTO t1 SELECT id+524288 FROM t1;
+INSERT INTO t1 SELECT id+1048576 FROM t1;
+INSERT INTO t2 SELECT * FROM t1;
+INSERT INTO t3 SELECT concat(id),id from t2 ORDER BY -id;
+INSERT INTO t4 SELECT * from t3 ORDER BY concat(a);
+select sum(id) from t3;
+sum(id)
+2199024304128
+drop table t1,t2,t3,t4;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 6117b0a9a00..d6cfefff9e6 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -141,13 +141,13 @@ id parent_id level
1015 102 2
explain select level from t1 where level=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref level level 1 const # Using where; Using index
+1 SIMPLE t1 ref level level 1 const # Using index
explain select level,id from t1 where level=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref level level 1 const # Using where; Using index
+1 SIMPLE t1 ref level level 1 const # Using index
explain select level,id,parent_id from t1 where level=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref level level 1 const # Using where
+1 SIMPLE t1 ref level level 1 const #
select level,id from t1 where level=1;
level id
1 1002
@@ -249,6 +249,40 @@ n
4
5
6
+set autocommit=0;
+begin;
+savepoint `my_savepoint`;
+insert into t1 values (7);
+savepoint `savept2`;
+insert into t1 values (3);
+select n from t1;
+n
+3
+4
+5
+6
+7
+savepoint savept3;
+rollback to savepoint savept2;
+rollback to savepoint savept3;
+ERROR 42000: SAVEPOINT savept3 does not exist
+rollback to savepoint savept2;
+release savepoint `my_savepoint`;
+select n from t1;
+n
+4
+5
+6
+7
+rollback to savepoint `my_savepoint`;
+ERROR 42000: SAVEPOINT my_savepoint does not exist
+rollback to savepoint savept2;
+ERROR 42000: SAVEPOINT savept2 does not exist
+insert into t1 values (8);
+savepoint sv;
+commit;
+savepoint sv;
+set autocommit=1;
rollback;
drop table t1;
create table t1 (n int not null primary key) engine=innodb;
@@ -609,7 +643,7 @@ id parent_id level
1016 102 2
explain select level from t1 where level=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref level level 1 const # Using where; Using index
+1 SIMPLE t1 ref level level 1 const # Using index
select level,id from t1 where level=1;
level id
1 1004
@@ -897,6 +931,7 @@ a
1
2
truncate table t1;
+truncate table t1;
insert into t1 values(1),(2);
delete from t1;
select * from t1;
@@ -932,7 +967,7 @@ drop table t1;
create table t1 (t int not null default 1, key (t)) engine=innodb;
desc t1;
Field Type Null Key Default Extra
-t int(11) MUL 1
+t int(11) NO MUL 1
drop table t1;
CREATE TABLE t1 (
number bigint(20) NOT NULL default '0',
@@ -1327,8 +1362,8 @@ truncate table t1;
insert into t1 (a) values (NULL),(NULL);
SELECT * from t1;
a
-3
-4
+1
+2
drop table t1;
CREATE TABLE t1 (`id 1` INT NOT NULL, PRIMARY KEY (`id 1`)) ENGINE=INNODB;
CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY (`t1_id`) REFERENCES `t1`(`id 1`) ON DELETE CASCADE ) ENGINE=INNODB;
@@ -1377,7 +1412,7 @@ CREATE TABLE t1 (
`id` int(10) unsigned NOT NULL auto_increment,
`id_object` int(10) unsigned default '0',
`id_version` int(10) unsigned NOT NULL default '1',
-label varchar(100) NOT NULL default '',
+`label` varchar(100) NOT NULL default '',
`description` text,
PRIMARY KEY (`id`),
KEY `id_object` (`id_object`),
@@ -1391,8 +1426,8 @@ PRIMARY KEY (`id`),
KEY `id_version` (`id_version`)
) ENGINE=InnoDB;
INSERT INTO t2 VALUES("3524", "1"),("3525", "1"),("1794", "4"),("102", "5"),("1822", "6"),("3382", "9");
-SELECT t2.id, t1.label FROM t2 INNER JOIN
-(SELECT t1.id_object as id_object FROM t1 WHERE t1.label LIKE '%test%') AS lbl
+SELECT t2.id, t1.`label` FROM t2 INNER JOIN
+(SELECT t1.id_object as id_object FROM t1 WHERE t1.`label` LIKE '%test%') AS lbl
ON (t2.id = lbl.id_object) INNER JOIN t1 ON (t2.id = t1.id_object);
id label
3382 Test
@@ -1410,22 +1445,22 @@ insert t2 select * from t1;
insert t3 select * from t1;
checksum table t1, t2, t3, t4 quick;
Table Checksum
-test.t1 968604391
+test.t1 2948697075
test.t2 NULL
test.t3 NULL
test.t4 NULL
-checksum table t1, t2, t3, t4;
+Warnings:
+Error 1146 Table 'test.t4' doesn't exist
+checksum table t1, t2, t3;
Table Checksum
-test.t1 968604391
-test.t2 968604391
-test.t3 968604391
-test.t4 NULL
-checksum table t1, t2, t3, t4 extended;
+test.t1 2948697075
+test.t2 1157260244
+test.t3 1157260244
+checksum table t1, t2, t3 extended;
Table Checksum
-test.t1 968604391
-test.t2 968604391
-test.t3 968604391
-test.t4 NULL
+test.t1 3092701434
+test.t2 1157260244
+test.t3 1157260244
drop table t1,t2,t3;
create table t1 (id int, name char(10) not null, name2 char(10) not null) engine=innodb;
insert into t1 values(1,'first','fff'),(2,'second','sss'),(3,'third','ttt');
@@ -1449,14 +1484,14 @@ create table t2 (id int(11) not null, constraint t1_id_fk foreign key ( id ) ref
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `id` int(11) NOT NULL default '0',
- `id2` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
+ `id2` int(11) NOT NULL,
UNIQUE KEY `id` (`id`,`id2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
KEY `t1_id_fk` (`id`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
@@ -1464,7 +1499,7 @@ create index id on t2 (id);
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
KEY `id` (`id`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
@@ -1472,7 +1507,7 @@ create index id2 on t2 (id);
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
KEY `id` (`id`),
KEY `id2` (`id`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)
@@ -1483,7 +1518,7 @@ Got one of the listed errors
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
KEY `id` (`id`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
@@ -1492,8 +1527,8 @@ create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
- `id2` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
+ `id2` int(11) NOT NULL,
KEY `t1_id_fk` (`id`,`id2`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`, `id2`) REFERENCES `t1` (`id`, `id2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
@@ -1501,8 +1536,8 @@ create unique index id on t2 (id,id2);
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
- `id2` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
+ `id2` int(11) NOT NULL,
UNIQUE KEY `id` (`id`,`id2`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`, `id2`) REFERENCES `t1` (`id`, `id2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
@@ -1511,8 +1546,8 @@ create table t2 (id int(11) not null, id2 int(11) not null, unique (id,id2),cons
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
- `id2` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
+ `id2` int(11) NOT NULL,
UNIQUE KEY `id` (`id`,`id2`),
KEY `t1_id_fk` (`id2`,`id`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id2`, `id`) REFERENCES `t1` (`id`, `id2`)
@@ -1522,8 +1557,8 @@ create table t2 (id int(11) not null, id2 int(11) not null, unique (id,id2), con
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
- `id2` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
+ `id2` int(11) NOT NULL,
UNIQUE KEY `id` (`id`,`id2`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
@@ -1532,8 +1567,8 @@ create table t2 (id int(11) not null, id2 int(11) not null, unique (id,id2),cons
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `id` int(11) NOT NULL default '0',
- `id2` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
+ `id2` int(11) NOT NULL,
UNIQUE KEY `id` (`id`,`id2`),
KEY `t1_id_fk` (`id2`,`id`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id2`, `id`) REFERENCES `t1` (`id`, `id2`)
@@ -1544,7 +1579,7 @@ show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL auto_increment,
- `id2` int(11) NOT NULL default '0',
+ `id2` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `id` (`id`,`id2`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)
@@ -1555,7 +1590,7 @@ show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL auto_increment,
- `id2` int(11) NOT NULL default '0',
+ `id2` int(11) NOT NULL,
KEY `t1_id_fk` (`id`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
@@ -1564,14 +1599,14 @@ show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL auto_increment,
- `id2` int(11) NOT NULL default '0',
+ `id2` int(11) NOT NULL,
KEY `id_test` (`id`),
KEY `id_test2` (`id`,`id2`),
CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t2;
create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id2,id) references t1 (id)) engine = innodb;
-ERROR HY000: Can't create table './test/t2.frm' (errno: 150)
+ERROR HY000: Can't create table './test/t2' (errno: 150)
create table t2 (a int auto_increment primary key, b int, index(b), foreign key (b) references t1(id), unique(b)) engine=innodb;
show create table t2;
Table Create Table
@@ -1598,14 +1633,14 @@ t2 CREATE TABLE `t2` (
drop table t2, t1;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 24
+Binlog_cache_use 154
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
create table t1 (a int) engine=innodb;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 25
+Binlog_cache_use 155
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
@@ -1614,11 +1649,45 @@ delete from t1;
commit;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 26
+Binlog_cache_use 156
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
drop table t1;
+create table t1 (x bigint unsigned not null primary key) engine=innodb;
+insert into t1(x) values (0xfffffffffffffff0),(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
+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
+select count(*) from t1 where x > -16;
+count(*)
+1
+select * from t1 where x > -16;
+x
+18446744073709551601
+select count(*) from t1 where x = 18446744073709551601;
+count(*)
+1
+drop table t1;
create table t1 (c char(10), index (c,c)) engine=innodb;
ERROR 42S21: Duplicate column name 'c'
create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)) engine=innodb;
@@ -1637,3 +1706,688 @@ ERROR 42S21: Duplicate column name 'c1'
alter table t1 add key (c1,c1,c2);
ERROR 42S21: Duplicate column name 'c1'
drop table t1;
+show status like "Innodb_buffer_pool_pages_total";
+Variable_name Value
+Innodb_buffer_pool_pages_total 512
+show status like "Innodb_page_size";
+Variable_name Value
+Innodb_page_size 16384
+show status like "Innodb_rows_deleted";
+Variable_name Value
+Innodb_rows_deleted 2070
+show status like "Innodb_rows_inserted";
+Variable_name Value
+Innodb_rows_inserted 31709
+show status like "Innodb_rows_updated";
+Variable_name Value
+Innodb_rows_updated 29530
+show status like "Innodb_row_lock_waits";
+Variable_name Value
+Innodb_row_lock_waits 0
+show status like "Innodb_row_lock_current_waits";
+Variable_name Value
+Innodb_row_lock_current_waits 0
+show status like "Innodb_row_lock_time";
+Variable_name Value
+Innodb_row_lock_time 0
+show status like "Innodb_row_lock_time_max";
+Variable_name Value
+Innodb_row_lock_time_max 0
+show status like "Innodb_row_lock_time_avg";
+Variable_name Value
+Innodb_row_lock_time_avg 0
+show variables like "innodb_sync_spin_loops";
+Variable_name Value
+innodb_sync_spin_loops 20
+set global innodb_sync_spin_loops=1000;
+show variables like "innodb_sync_spin_loops";
+Variable_name Value
+innodb_sync_spin_loops 1000
+set global innodb_sync_spin_loops=0;
+show variables like "innodb_sync_spin_loops";
+Variable_name Value
+innodb_sync_spin_loops 0
+set global innodb_sync_spin_loops=20;
+show variables like "innodb_sync_spin_loops";
+Variable_name Value
+innodb_sync_spin_loops 20
+show variables like "innodb_thread_concurrency";
+Variable_name Value
+innodb_thread_concurrency 8
+set global innodb_thread_concurrency=1000;
+show variables like "innodb_thread_concurrency";
+Variable_name Value
+innodb_thread_concurrency 1000
+set global innodb_thread_concurrency=0;
+show variables like "innodb_thread_concurrency";
+Variable_name Value
+innodb_thread_concurrency 1
+set global innodb_thread_concurrency=16;
+show variables like "innodb_thread_concurrency";
+Variable_name Value
+innodb_thread_concurrency 16
+show variables like "innodb_concurrency_tickets";
+Variable_name Value
+innodb_concurrency_tickets 500
+set global innodb_concurrency_tickets=1000;
+show variables like "innodb_concurrency_tickets";
+Variable_name Value
+innodb_concurrency_tickets 1000
+set global innodb_concurrency_tickets=0;
+show variables like "innodb_concurrency_tickets";
+Variable_name Value
+innodb_concurrency_tickets 1
+set global innodb_concurrency_tickets=500;
+show variables like "innodb_concurrency_tickets";
+Variable_name Value
+innodb_concurrency_tickets 500
+show variables like "innodb_thread_sleep_delay";
+Variable_name Value
+innodb_thread_sleep_delay 10000
+set global innodb_thread_sleep_delay=100000;
+show variables like "innodb_thread_sleep_delay";
+Variable_name Value
+innodb_thread_sleep_delay 100000
+set global innodb_thread_sleep_delay=0;
+show variables like "innodb_thread_sleep_delay";
+Variable_name Value
+innodb_thread_sleep_delay 0
+set global innodb_thread_sleep_delay=10000;
+show variables like "innodb_thread_sleep_delay";
+Variable_name Value
+innodb_thread_sleep_delay 10000
+set storage_engine=INNODB;
+drop table if exists t1,t2,t3;
+--- Testing varchar ---
+--- Testing varchar ---
+create table t1 (v varchar(10), c char(10), t text);
+insert into t1 values('+ ', '+ ', '+ ');
+set @a=repeat(' ',20);
+insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
+Warnings:
+Note 1265 Data truncated for column 'v' at row 1
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+ *+*+ *
+*+ *+*+ *
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+create table t2 like t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+create table t3 select * from t1;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 modify c varchar(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` text
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 modify v char(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` text
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 modify t varchar(10);
+Warnings:
+Note 1265 Data truncated for column 't' at row 2
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` varchar(10) default NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+*+*+ *
+*+*+*+ *
+drop table t1,t2,t3;
+create table t1 (v varchar(10), c char(10), t text, key(v), key(c), key(t(10)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `v` (`v`),
+ KEY `c` (`c`),
+ KEY `t` (`t`(10))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+select count(*) from t1;
+count(*)
+270
+insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1)));
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where c='a';
+count(*)
+10
+select count(*) from t1 where t='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where c='a ';
+count(*)
+10
+select count(*) from t1 where t='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where c like 'a%';
+count(*)
+11
+select count(*) from t1 where t like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const # Using where; Using index
+explain select count(*) from t1 where c='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref c c 11 const # Using where; Using index
+explain select count(*) from t1 where t='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range t t 13 NULL # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where; Using index
+alter table t1 add unique(v);
+ERROR 23000: Duplicate entry '{ ' for key 1
+alter table t1 add key(v);
+select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a';
+qq
+*a*a*a*
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v,v_2 # 13 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(c) from t1 group by v limit 10;
+v count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(c) from t1 group by v limit 10;
+v count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(*) from t1 group by c limit 10;
+c count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(*) from t1 group by t limit 10;
+t count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(t) from t1 group by t limit 10;
+t count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result t,count(t) from t1 group by t limit 10;
+t count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 modify v varchar(300), drop key v, drop key v_2, add key v (v);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(300) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 303 const # Using where; Using index
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 303 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 303 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 303 NULL # Using where; Using index
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 303 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 drop key v, add key v (v(30));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(300) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`(30))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 modify v varchar(600), drop key v, add key v (v);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(600) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+drop table t1;
+create table t1 (a char(10), unique (a));
+insert into t1 values ('a ');
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a' for key 1
+alter table t1 modify a varchar(10);
+insert into t1 values ('a '),('a '),('a '),('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+update t1 set a='a ' where a like 'a%';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='abc ' where a like 'a ';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='a ' where a like 'a %';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='a ' where a like 'a ';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+drop table t1;
+create table t1 (v varchar(10), c char(10), t text, key(v(5)), key(c(5)), key(t(5)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `v` (`v`(5)),
+ KEY `c` (`c`(5)),
+ KEY `t` (`t`(5))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v char(10) character set utf8);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) character set utf8 default NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v varchar(10), c char(10)) row_format=fixed;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED
+insert into t1 values('a','a'),('a ','a ');
+select concat('*',v,'*',c,'*') from t1;
+concat('*',v,'*',c,'*')
+*a*a*
+*a *a*
+drop table t1;
+create table t1 (v varchar(65530), key(v(10)));
+insert into t1 values(repeat('a',65530));
+select length(v) from t1 where v=repeat('a',65530);
+length(v)
+65530
+drop table t1;
+create table t1(a int, b varchar(12), key ba(b, a));
+insert into t1 values (1, 'A'), (20, NULL);
+explain select * from t1 where a=20 and b is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref ba ba 20 const,const 1 Using where; Using index
+select * from t1 where a=20 and b is null;
+a b
+20 NULL
+drop table t1;
+create table t1 (v varchar(65530), key(v));
+ERROR HY000: Can't create table './test/t1' (errno: 139)
+create table t1 (v varchar(65536));
+Warnings:
+Note 1246 Converting column 'v' from VARCHAR to TEXT
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` mediumtext
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v varchar(65530) character set utf8);
+Warnings:
+Note 1246 Converting column 'v' from VARCHAR to TEXT
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` mediumtext character set utf8
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+set storage_engine=MyISAM;
+create table t1 (v varchar(16384)) engine=innodb;
+drop table t1;
diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result
index 71b10699fa9..f788576f824 100644
--- a/mysql-test/r/insert.result
+++ b/mysql-test/r/insert.result
@@ -1,4 +1,4 @@
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
create table t1 (a int not null);
insert into t1 values (1);
insert into t1 values (a+2);
@@ -63,7 +63,7 @@ insert into t1 values(NULL);
ERROR 23000: Column 'id' cannot be null
insert into t1 values (1), (NULL), (2);
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'id' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'id' at row 2
select * from t1;
id
1
@@ -157,20 +157,20 @@ f_float_3_1_u 0.0
set @value= "1e+1111111111a";
insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
Warnings:
-Warning 1265 Data truncated for column 'f_double' at row 1
-Warning 1265 Data truncated for column 'f_float' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float' at row 1
-Warning 1265 Data truncated for column 'f_double_7_2' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_7_2' at row 1
-Warning 1265 Data truncated for column 'f_float_4_3' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_4_3' at row 1
-Warning 1265 Data truncated for column 'f_double_u' at row 1
-Warning 1265 Data truncated for column 'f_float_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_u' at row 1
-Warning 1265 Data truncated for column 'f_double_15_1_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_15_1_u' at row 1
-Warning 1265 Data truncated for column 'f_float_3_1_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_3_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_7_2' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_7_2' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_4_3' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_4_3' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_15_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_15_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_3_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_3_1_u' at row 1
select * from t1 where number =last_insert_id();
number 4
original_value 1e+1111111111a
@@ -185,21 +185,21 @@ f_float_3_1_u 99.9
set @value= "-1e+1111111111a";
insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
Warnings:
-Warning 1265 Data truncated for column 'f_double' at row 1
-Warning 1265 Data truncated for column 'f_float' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float' at row 1
-Warning 1265 Data truncated for column 'f_double_7_2' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_7_2' at row 1
-Warning 1265 Data truncated for column 'f_float_4_3' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_4_3' at row 1
-Warning 1265 Data truncated for column 'f_double_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_u' at row 1
-Warning 1265 Data truncated for column 'f_float_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_u' at row 1
-Warning 1265 Data truncated for column 'f_double_15_1_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_15_1_u' at row 1
-Warning 1265 Data truncated for column 'f_float_3_1_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_3_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_7_2' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_7_2' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_4_3' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_4_3' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_15_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_15_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_3_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_3_1_u' at row 1
select * from t1 where number =last_insert_id();
number 5
original_value -1e+1111111111a
@@ -212,57 +212,20 @@ f_float_u 0
f_double_15_1_u 0.0
f_float_3_1_u 0.0
set @value= 1e+1111111111;
-insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
-Warnings:
-Warning 1264 Data truncated; out of range for column 'f_float' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_7_2' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_4_3' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_15_1_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_3_1_u' at row 1
-select * from t1 where number =last_insert_id();
-number 6
-original_value 1.7976931348623e+308
-f_double 1.79769313486232e+308
-f_float 3.40282e+38
-f_double_7_2 99999.99
-f_float_4_3 9.999
-f_double_u 1.79769313486232e+308
-f_float_u 3.40282e+38
-f_double_15_1_u 99999999999999.9
-f_float_3_1_u 99.9
+ERROR 22007: Illegal double '1e+1111111111' value found during parsing
set @value= -1e+1111111111;
-insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
-Warnings:
-Warning 1264 Data truncated; out of range for column 'f_float' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_7_2' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_4_3' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_15_1_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_3_1_u' at row 1
-select * from t1 where number =last_insert_id();
-number 7
-original_value -1.7976931348623e+308
-f_double -1.79769313486232e+308
-f_float -3.40282e+38
-f_double_7_2 -99999.99
-f_float_4_3 -9.999
-f_double_u 0
-f_float_u 0
-f_double_15_1_u 0.0
-f_float_3_1_u 0.0
+ERROR 22007: Illegal double '1e+1111111111' value found during parsing
set @value= 1e+111;
insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
Warnings:
-Warning 1264 Data truncated; out of range for column 'f_float' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_7_2' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_4_3' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_15_1_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_3_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_7_2' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_4_3' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_15_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_3_1_u' at row 1
select * from t1 where number =last_insert_id();
-number 8
+number 6
original_value 1e+111
f_double 1e+111
f_float 3.40282e+38
@@ -275,15 +238,15 @@ f_float_3_1_u 99.9
set @value= -1e+111;
insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
Warnings:
-Warning 1264 Data truncated; out of range for column 'f_float' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_7_2' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_4_3' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_15_1_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_3_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_7_2' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_4_3' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_15_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_3_1_u' at row 1
select * from t1 where number =last_insert_id();
-number 9
+number 7
original_value -1e+111
f_double -1e+111
f_float -3.40282e+38
@@ -296,7 +259,7 @@ f_float_3_1_u 0.0
set @value= 1;
insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
select * from t1 where number =last_insert_id();
-number 10
+number 8
original_value 1
f_double 1
f_float 1
@@ -309,12 +272,12 @@ f_float_3_1_u 1.0
set @value= -1;
insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
Warnings:
-Warning 1264 Data truncated; out of range for column 'f_double_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_double_15_1_u' at row 1
-Warning 1264 Data truncated; out of range for column 'f_float_3_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_double_15_1_u' at row 1
+Warning 1264 Out of range value adjusted for column 'f_float_3_1_u' at row 1
select * from t1 where number =last_insert_id();
-number 11
+number 9
original_value -1
f_double -1
f_float -1
@@ -325,3 +288,14 @@ f_float_u 0
f_double_15_1_u 0.0
f_float_3_1_u 0.0
drop table t1;
+create table t1(id1 int not null auto_increment primary key, t char(12));
+create table t2(id2 int not null, t char(12));
+create table t3(id3 int not null, t char(12), index(id3));
+select count(*) from t2;
+count(*)
+500
+insert into t2 select t1.* from t1, t2 t, t3 where t1.id1 = t.id2 and t.id2 = t3.id3;
+select count(*) from t2;
+count(*)
+25500
+drop table t1,t2,t3;
diff --git a/mysql-test/r/insert_select-binlog.result b/mysql-test/r/insert_select-binlog.result
index bca28059787..76f460b1de2 100644
--- a/mysql-test/r/insert_select-binlog.result
+++ b/mysql-test/r/insert_select-binlog.result
@@ -6,9 +6,9 @@ reset master;
insert into t1 select * from t2;
ERROR 23000: Duplicate entry '2' for key 1
show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 use `test`; insert into t1 select * from t2
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4
+master-bin.000001 98 Query 1 192 use `test`; insert into t1 select * from t2
select * from t1;
a
1
@@ -20,6 +20,6 @@ reset master;
create table t2(unique(a)) select a from t1;
ERROR 23000: Duplicate entry '1' for key 1
show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4
drop table t1;
diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result
index f843c6d0d18..d2c0a665845 100644
--- a/mysql-test/r/insert_select.result
+++ b/mysql-test/r/insert_select.result
@@ -606,8 +606,8 @@ NULL 2 100
create table t2(No int not null, Field int not null, Count int not null);
insert into t2 Select null, Field, Count From t1 Where Month=20030901 and Type=2;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'No' at row 1
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'No' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'No' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'No' at row 2
select * from t2;
No Field Count
0 1 100
diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result
index ff7ec1ba73f..1817500973e 100644
--- a/mysql-test/r/insert_update.result
+++ b/mysql-test/r/insert_update.result
@@ -60,12 +60,12 @@ explain extended SELECT *, VALUES(a) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5
Warnings:
-Note 1003 select test.t1.a AS `a`,test.t1.b AS `b`,test.t1.c AS `c`,values(test.t1.a) AS `VALUES(a)` from test.t1
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c`,values(`test`.`t1`.`a`) AS `VALUES(a)` from `test`.`t1`
explain extended select * from t1 where values(a);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
Warnings:
-Note 1003 select test.t1.a AS `a`,test.t1.b AS `b`,test.t1.c AS `c` from test.t1
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1`
DROP TABLE t1;
create table t1(a int primary key, b int);
insert into t1 values(1,1),(2,2),(3,3),(4,4),(5,5);
diff --git a/mysql-test/r/isam.result b/mysql-test/r/isam.result
index 52eb2d73ed5..cb308a1c71d 100644
--- a/mysql-test/r/isam.result
+++ b/mysql-test/r/isam.result
@@ -65,14 +65,14 @@ test.t2 check error Table 't2' was not locked with LOCK TABLES
test.t1 check status OK
show columns from t1;
Field Type Null Key Default Extra
-a int(11) PRI 0
-b int(11) MUL 0
-c int(11) 0
+a int(11) PRI
+b int(11) MUL
+c int(11)
show full columns from t1;
Field Type Collation Null Key Default Extra Privileges Comment
-a int(11) NULL PRI 0 select,insert,update,references
-b int(11) NULL MUL 0 select,insert,update,references
-c int(11) NULL 0 select,insert,update,references
+a int(11) NULL PRI select,insert,update,references
+b int(11) NULL MUL select,insert,update,references
+c int(11) NULL select,insert,update,references
show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 a A 4 NULL NULL BTREE
diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result
new file mode 100644
index 00000000000..bce086b00d2
--- /dev/null
+++ b/mysql-test/r/join_nested.result
@@ -0,0 +1,1323 @@
+DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
+CREATE TABLE t0 (a int, b int, c int);
+CREATE TABLE t1 (a int, b int, c int);
+CREATE TABLE t2 (a int, b int, c int);
+CREATE TABLE t3 (a int, b int, c int);
+CREATE TABLE t4 (a int, b int, c int);
+CREATE TABLE t5 (a int, b int, c int);
+CREATE TABLE t6 (a int, b int, c int);
+CREATE TABLE t7 (a int, b int, c int);
+CREATE TABLE t8 (a int, b int, c int);
+CREATE TABLE t9 (a int, b int, c int);
+INSERT INTO t0 VALUES (1,1,0), (1,2,0), (2,2,0);
+INSERT INTO t1 VALUES (1,3,0), (2,2,0), (3,2,0);
+INSERT INTO t2 VALUES (3,3,0), (4,2,0), (5,3,0);
+INSERT INTO t3 VALUES (1,2,0), (2,2,0);
+INSERT INTO t4 VALUES (3,2,0), (4,2,0);
+INSERT INTO t5 VALUES (3,1,0), (2,2,0), (3,3,0);
+INSERT INTO t6 VALUES (3,2,0), (6,2,0), (6,1,0);
+INSERT INTO t7 VALUES (1,1,0), (2,2,0);
+INSERT INTO t8 VALUES (0,2,0), (1,2,0);
+INSERT INTO t9 VALUES (1,1,0), (1,2,0), (3,3,0);
+SELECT t2.a,t2.b
+FROM t2;
+a b
+3 3
+4 2
+5 3
+SELECT t3.a,t3.b
+FROM t3;
+a b
+1 2
+2 2
+SELECT t4.a,t4.b
+FROM t4;
+a b
+3 2
+4 2
+SELECT t3.a,t3.b,t4.a,t4.b
+FROM t3,t4;
+a b a b
+1 2 3 2
+2 2 3 2
+1 2 4 2
+2 2 4 2
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t2
+LEFT JOIN
+(t3, t4)
+ON t2.b=t4.b;
+a b a b a b
+3 3 NULL NULL NULL NULL
+4 2 1 2 3 2
+4 2 1 2 4 2
+4 2 2 2 3 2
+4 2 2 2 4 2
+5 3 NULL NULL NULL NULL
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b;
+a b a b a b
+3 3 NULL NULL NULL NULL
+4 2 1 2 3 2
+4 2 1 2 4 2
+5 3 NULL NULL NULL NULL
+EXPLAIN EXTENDED
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t2
+LEFT JOIN
+(t3, t4)
+ON t2.b=t4.b
+WHERE t3.a=1 OR t3.c IS NULL;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 2
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t2` left join (`test`.`t3` join `test`.`t4`) on((`test`.`t4`.`b` = `test`.`t2`.`b`)) where ((`test`.`t3`.`a` = 1) or isnull(`test`.`t3`.`c`))
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t2
+LEFT JOIN
+(t3, t4)
+ON t2.b=t4.b
+WHERE t3.a=1 OR t3.c IS NULL;
+a b a b a b
+3 3 NULL NULL NULL NULL
+4 2 1 2 3 2
+4 2 1 2 4 2
+5 3 NULL NULL NULL NULL
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t2
+LEFT JOIN
+(t3, t4)
+ON t2.b=t4.b
+WHERE t3.a>1 OR t3.c IS NULL;
+a b a b a b
+3 3 NULL NULL NULL NULL
+4 2 2 2 3 2
+4 2 2 2 4 2
+5 3 NULL NULL NULL NULL
+SELECT t5.a,t5.b
+FROM t5;
+a b
+3 1
+2 2
+3 3
+SELECT t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+FROM t3,t4,t5;
+a b a b a b
+1 2 3 2 3 1
+2 2 3 2 3 1
+1 2 4 2 3 1
+2 2 4 2 3 1
+1 2 3 2 2 2
+2 2 3 2 2 2
+1 2 4 2 2 2
+2 2 4 2 2 2
+1 2 3 2 3 3
+2 2 3 2 3 3
+1 2 4 2 3 3
+2 2 4 2 3 3
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+FROM t2
+LEFT JOIN
+(t3, t4, t5)
+ON t2.b=t4.b;
+a b a b a b a b
+3 3 NULL NULL NULL NULL NULL NULL
+4 2 1 2 3 2 3 1
+4 2 1 2 3 2 2 2
+4 2 1 2 3 2 3 3
+4 2 1 2 4 2 3 1
+4 2 1 2 4 2 2 2
+4 2 1 2 4 2 3 3
+4 2 2 2 3 2 3 1
+4 2 2 2 3 2 2 2
+4 2 2 2 3 2 3 3
+4 2 2 2 4 2 3 1
+4 2 2 2 4 2 2 2
+4 2 2 2 4 2 3 3
+5 3 NULL NULL NULL NULL NULL NULL
+EXPLAIN EXTENDED
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+FROM t2
+LEFT JOIN
+(t3, t4, t5)
+ON t2.b=t4.b
+WHERE t3.a>1 OR t3.c IS NULL;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 2
+1 SIMPLE t5 ALL NULL NULL NULL NULL 3
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b` from `test`.`t2` left join (`test`.`t3` join `test`.`t4` join `test`.`t5`) on((`test`.`t4`.`b` = `test`.`t2`.`b`)) where ((`test`.`t3`.`a` > 1) or isnull(`test`.`t3`.`c`))
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+FROM t2
+LEFT JOIN
+(t3, t4, t5)
+ON t2.b=t4.b
+WHERE t3.a>1 OR t3.c IS NULL;
+a b a b a b a b
+3 3 NULL NULL NULL NULL NULL NULL
+4 2 2 2 3 2 3 1
+4 2 2 2 3 2 2 2
+4 2 2 2 3 2 3 3
+4 2 2 2 4 2 3 1
+4 2 2 2 4 2 2 2
+4 2 2 2 4 2 3 3
+5 3 NULL NULL NULL NULL NULL NULL
+EXPLAIN EXTENDED
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+FROM t2
+LEFT JOIN
+(t3, t4, t5)
+ON t2.b=t4.b
+WHERE (t3.a>1 OR t3.c IS NULL) AND
+(t5.a<3 OR t5.c IS NULL);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 2
+1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b` from `test`.`t2` left join (`test`.`t3` join `test`.`t4` join `test`.`t5`) on((`test`.`t4`.`b` = `test`.`t2`.`b`)) where (((`test`.`t3`.`a` > 1) or isnull(`test`.`t3`.`c`)) and ((`test`.`t5`.`a` < 3) or isnull(`test`.`t5`.`c`)))
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+FROM t2
+LEFT JOIN
+(t3, t4, t5)
+ON t2.b=t4.b
+WHERE (t3.a>1 OR t3.c IS NULL) AND
+(t5.a<3 OR t5.c IS NULL);
+a b a b a b a b
+3 3 NULL NULL NULL NULL NULL NULL
+4 2 2 2 3 2 2 2
+4 2 2 2 4 2 2 2
+5 3 NULL NULL NULL NULL NULL NULL
+SELECT t6.a,t6.b
+FROM t6;
+a b
+3 2
+6 2
+6 1
+SELECT t7.a,t7.b
+FROM t7;
+a b
+1 1
+2 2
+SELECT t6.a,t6.b,t7.a,t7.b
+FROM t6,t7;
+a b a b
+3 2 1 1
+3 2 2 2
+6 2 1 1
+6 2 2 2
+6 1 1 1
+6 1 2 2
+SELECT t8.a,t8.b
+FROM t8;
+a b
+0 2
+1 2
+EXPLAIN EXTENDED
+SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t7 ALL NULL NULL NULL NULL 2
+1 SIMPLE t6 ALL NULL NULL NULL NULL 3
+1 SIMPLE t8 ALL NULL NULL NULL NULL 2
+Warnings:
+Note 1003 select `test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b` from `test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t7`.`b` = `test`.`t8`.`b`) and (`test`.`t6`.`b` < 10))) where 1
+SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10;
+a b a b a b
+3 2 1 1 NULL NULL
+3 2 2 2 0 2
+3 2 2 2 1 2
+6 2 1 1 NULL NULL
+6 2 2 2 0 2
+6 2 2 2 1 2
+6 1 1 1 NULL NULL
+6 1 2 2 0 2
+6 1 2 2 1 2
+SELECT t5.a,t5.b
+FROM t5;
+a b
+3 1
+2 2
+3 3
+SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b;
+a b a b a b a b
+3 1 3 2 1 1 NULL NULL
+3 1 6 2 1 1 NULL NULL
+2 2 3 2 2 2 0 2
+2 2 3 2 2 2 1 2
+2 2 6 2 2 2 0 2
+2 2 6 2 2 2 1 2
+3 3 NULL NULL NULL NULL NULL NULL
+SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b AND
+(t8.a < 1 OR t8.c IS NULL);
+a b a b a b a b
+3 1 3 2 1 1 NULL NULL
+3 1 6 2 1 1 NULL NULL
+2 2 3 2 2 2 0 2
+2 2 6 2 2 2 0 2
+3 3 NULL NULL NULL NULL NULL NULL
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b;
+a b a b a b
+3 3 NULL NULL NULL NULL
+4 2 1 2 3 2
+4 2 1 2 4 2
+5 3 NULL NULL NULL NULL
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b;
+a b a b a b a b a b a b a b
+3 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+3 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
+4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
+4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
+4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
+4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
+5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
+3 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+3 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+3 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
+3 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
+4 2 1 2 3 2 2 2 3 2 2 2 0 2
+4 2 1 2 3 2 2 2 3 2 2 2 1 2
+4 2 1 2 3 2 2 2 6 2 2 2 0 2
+4 2 1 2 3 2 2 2 6 2 2 2 1 2
+4 2 1 2 4 2 2 2 3 2 2 2 0 2
+4 2 1 2 4 2 2 2 3 2 2 2 1 2
+4 2 1 2 4 2 2 2 6 2 2 2 0 2
+4 2 1 2 4 2 2 2 6 2 2 2 1 2
+5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
+5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
+3 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
+4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
+5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+WHERE t2.a > 3 AND
+(t6.a < 6 OR t6.c IS NULL);
+a b a b a b a b a b a b a b
+4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
+4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
+5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+4 2 1 2 3 2 2 2 3 2 2 2 0 2
+4 2 1 2 3 2 2 2 3 2 2 2 1 2
+4 2 1 2 4 2 2 2 3 2 2 2 0 2
+4 2 1 2 4 2 2 2 3 2 2 2 1 2
+5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
+4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
+5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+SELECT t1.a,t1.b
+FROM t1;
+a b
+1 3
+2 2
+3 2
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2);
+a b a b a b a b a b a b a b a b
+1 3 3 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+1 3 3 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
+1 3 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+1 3 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+1 3 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
+1 3 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
+1 3 3 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+1 3 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
+1 3 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
+1 3 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
+1 3 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
+1 3 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
+1 3 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
+1 3 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+1 3 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
+1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
+1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
+1 3 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+3 2 3 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+3 2 3 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
+3 2 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+3 2 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+3 2 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
+3 2 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
+3 2 3 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+3 2 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
+3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
+3 2 4 2 1 2 3 2 2 2 3 2 2 2 0 2
+3 2 4 2 1 2 3 2 2 2 3 2 2 2 1 2
+3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2
+3 2 4 2 1 2 3 2 2 2 6 2 2 2 1 2
+3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
+3 2 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
+3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
+3 2 4 2 1 2 4 2 2 2 3 2 2 2 0 2
+3 2 4 2 1 2 4 2 2 2 3 2 2 2 1 2
+3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2
+3 2 4 2 1 2 4 2 2 2 6 2 2 2 1 2
+3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
+3 2 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
+3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
+3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
+3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2)
+WHERE (t2.a >= 4 OR t2.c IS NULL);
+a b a b a b a b a b a b a b a b
+1 3 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
+1 3 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
+1 3 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
+1 3 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
+1 3 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
+1 3 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
+1 3 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+1 3 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
+1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
+1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
+1 3 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+3 2 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
+3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
+3 2 4 2 1 2 3 2 2 2 3 2 2 2 0 2
+3 2 4 2 1 2 3 2 2 2 3 2 2 2 1 2
+3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2
+3 2 4 2 1 2 3 2 2 2 6 2 2 2 1 2
+3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
+3 2 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
+3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
+3 2 4 2 1 2 4 2 2 2 3 2 2 2 0 2
+3 2 4 2 1 2 4 2 2 2 3 2 2 2 1 2
+3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2
+3 2 4 2 1 2 4 2 2 2 6 2 2 2 1 2
+3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
+3 2 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
+3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
+3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
+3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+SELECT t0.a,t0.b
+FROM t0;
+a b
+1 1
+1 2
+2 2
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t0,t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2)
+WHERE t0.a=1 AND
+t0.b=t1.b AND
+(t2.a >= 4 OR t2.c IS NULL);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2
+1 SIMPLE t4 ALL NULL NULL NULL NULL 2
+1 SIMPLE t5 ALL NULL NULL NULL NULL 3
+1 SIMPLE t7 ALL NULL NULL NULL NULL 2
+1 SIMPLE t6 ALL NULL NULL NULL NULL 3
+1 SIMPLE t8 ALL NULL NULL NULL NULL 2
+Warnings:
+Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) where ((`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)))
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+FROM t0,t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2)
+WHERE t0.a=1 AND
+t0.b=t1.b AND
+(t2.a >= 4 OR t2.c IS NULL);
+a b a b a b a b a b a b a b a b a b
+1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+1 2 3 2 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
+1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
+1 2 3 2 4 2 1 2 3 2 2 2 3 2 2 2 0 2
+1 2 3 2 4 2 1 2 3 2 2 2 3 2 2 2 1 2
+1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2
+1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 1 2
+1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
+1 2 3 2 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
+1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
+1 2 3 2 4 2 1 2 4 2 2 2 3 2 2 2 0 2
+1 2 3 2 4 2 1 2 4 2 2 2 3 2 2 2 1 2
+1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2
+1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 1 2
+1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
+1 2 3 2 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
+1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
+1 2 3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
+1 2 3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
+1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
+1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
+1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+FROM t0,t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2),
+t9
+WHERE t0.a=1 AND
+t0.b=t1.b AND
+(t2.a >= 4 OR t2.c IS NULL) AND
+(t3.a < 5 OR t3.c IS NULL) AND
+(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+(t5.a >=2 OR t5.c IS NULL) AND
+(t6.a >=4 OR t6.c IS NULL) AND
+(t7.a <= 2 OR t7.c IS NULL) AND
+(t8.a < 1 OR t8.c IS NULL) AND
+(t8.b=t9.b OR t8.c IS NULL) AND
+(t9.a=1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t8 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
+Warnings:
+Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`)))
+SELECT t9.a,t9.b
+FROM t9;
+a b
+1 1
+1 2
+3 3
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+FROM t0,t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2),
+t9
+WHERE t0.a=1 AND
+t0.b=t1.b AND
+(t2.a >= 4 OR t2.c IS NULL) AND
+(t3.a < 5 OR t3.c IS NULL) AND
+(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+(t5.a >=2 OR t5.c IS NULL) AND
+(t6.a >=4 OR t6.c IS NULL) AND
+(t7.a <= 2 OR t7.c IS NULL) AND
+(t8.a < 1 OR t8.c IS NULL) AND
+(t8.b=t9.b OR t8.c IS NULL) AND
+(t9.a=1);
+a b a b a b a b a b a b a b a b a b a b
+1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 1
+1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 1
+1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 1
+1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 1
+1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 1
+1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 1
+1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 1
+1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 2
+1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 2
+1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 1 2
+1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 2
+1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 2
+1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 1 2
+1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 2
+1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 2
+1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 1 2
+1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 2
+SELECT t1.a,t1.b
+FROM t1;
+a b
+1 3
+2 2
+3 2
+SELECT t2.a,t2.b
+FROM t2;
+a b
+3 3
+4 2
+5 3
+SELECT t3.a,t3.b
+FROM t3;
+a b
+1 2
+2 2
+SELECT t2.a,t2.b,t3.a,t3.b
+FROM t2
+LEFT JOIN
+t3
+ON t2.b=t3.b;
+a b a b
+3 3 NULL NULL
+4 2 1 2
+4 2 2 2
+5 3 NULL NULL
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b
+FROM t1, t2
+LEFT JOIN
+t3
+ON t2.b=t3.b
+WHERE t1.a <= 2;
+a b a b a b
+1 3 3 3 NULL NULL
+2 2 3 3 NULL NULL
+1 3 4 2 1 2
+1 3 4 2 2 2
+2 2 4 2 1 2
+2 2 4 2 2 2
+1 3 5 3 NULL NULL
+2 2 5 3 NULL NULL
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b
+FROM t1, t3
+RIGHT JOIN
+t2
+ON t2.b=t3.b
+WHERE t1.a <= 2;
+a b a b a b
+1 3 3 3 NULL NULL
+2 2 3 3 NULL NULL
+1 3 4 2 1 2
+1 3 4 2 2 2
+2 2 4 2 1 2
+2 2 4 2 2 2
+1 3 5 3 NULL NULL
+2 2 5 3 NULL NULL
+SELECT t3.a,t3.b,t4.a,t4.b
+FROM t3,t4;
+a b a b
+1 2 3 2
+2 2 3 2
+1 2 4 2
+2 2 4 2
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b;
+a b a b a b
+3 3 NULL NULL NULL NULL
+4 2 1 2 3 2
+4 2 1 2 4 2
+5 3 NULL NULL NULL NULL
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t1, t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b
+WHERE t1.a <= 2;
+a b a b a b a b
+1 3 3 3 NULL NULL NULL NULL
+2 2 3 3 NULL NULL NULL NULL
+1 3 4 2 1 2 3 2
+1 3 4 2 1 2 4 2
+2 2 4 2 1 2 3 2
+2 2 4 2 1 2 4 2
+1 3 5 3 NULL NULL NULL NULL
+2 2 5 3 NULL NULL NULL NULL
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t1, (t3, t4)
+RIGHT JOIN
+t2
+ON t3.a=1 AND t2.b=t4.b
+WHERE t1.a <= 2;
+a b a b a b a b
+1 3 3 3 NULL NULL NULL NULL
+2 2 3 3 NULL NULL NULL NULL
+1 3 4 2 1 2 3 2
+1 3 4 2 1 2 4 2
+2 2 4 2 1 2 3 2
+2 2 4 2 1 2 4 2
+1 3 5 3 NULL NULL NULL NULL
+2 2 5 3 NULL NULL NULL NULL
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t1, t3, t4
+RIGHT JOIN
+t2
+ON t3.a=1 AND t2.b=t4.b
+WHERE t1.a <= 2;
+a b a b a b a b
+1 3 3 3 1 2 NULL NULL
+1 3 3 3 2 2 NULL NULL
+2 2 3 3 1 2 NULL NULL
+2 2 3 3 2 2 NULL NULL
+1 3 4 2 1 2 3 2
+1 3 4 2 1 2 4 2
+1 3 4 2 2 2 NULL NULL
+2 2 4 2 1 2 3 2
+2 2 4 2 1 2 4 2
+2 2 4 2 2 2 NULL NULL
+1 3 5 3 1 2 NULL NULL
+1 3 5 3 2 2 NULL NULL
+2 2 5 3 1 2 NULL NULL
+2 2 5 3 2 2 NULL NULL
+EXPLAIN EXTENDED
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t1, t3, t4
+RIGHT JOIN
+t2
+ON t3.a=1 AND t2.b=t4.b
+WHERE t1.a <= 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3
+1 SIMPLE t4 ALL NULL NULL NULL NULL 2
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t1` join `test`.`t3` join `test`.`t2` left join `test`.`t4` on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) where (`test`.`t1`.`a` <= 2)
+CREATE INDEX idx_b ON t2(b);
+EXPLAIN EXTENDED
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t3,t4
+LEFT JOIN
+(t1,t2)
+ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2
+1 SIMPLE t4 ALL NULL NULL NULL NULL 2
+1 SIMPLE t2 ref idx_b idx_b 5 test.t3.b 2
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+Warnings:
+Note 1003 select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t3` join `test`.`t4` left join (`test`.`t1` join `test`.`t2`) on(((`test`.`t3`.`a` = 1) and (`test`.`t3`.`b` = `test`.`t2`.`b`) and (`test`.`t2`.`b` = `test`.`t4`.`b`))) where 1
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+FROM t3,t4
+LEFT JOIN
+(t1,t2)
+ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
+a b a b a b
+4 2 1 2 3 2
+4 2 1 2 3 2
+4 2 1 2 3 2
+NULL NULL 2 2 3 2
+4 2 1 2 4 2
+4 2 1 2 4 2
+4 2 1 2 4 2
+NULL NULL 2 2 4 2
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+FROM t0,t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2),
+t9
+WHERE t0.a=1 AND
+t0.b=t1.b AND
+(t2.a >= 4 OR t2.c IS NULL) AND
+(t3.a < 5 OR t3.c IS NULL) AND
+(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+(t5.a >=2 OR t5.c IS NULL) AND
+(t6.a >=4 OR t6.c IS NULL) AND
+(t7.a <= 2 OR t7.c IS NULL) AND
+(t8.a < 1 OR t8.c IS NULL) AND
+(t8.b=t9.b OR t8.c IS NULL) AND
+(t9.a=1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t4 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t8 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
+Warnings:
+Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`)))
+CREATE INDEX idx_b ON t4(b);
+CREATE INDEX idx_b ON t5(b);
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+FROM t0,t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2),
+t9
+WHERE t0.a=1 AND
+t0.b=t1.b AND
+(t2.a >= 4 OR t2.c IS NULL) AND
+(t3.a < 5 OR t3.c IS NULL) AND
+(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+(t5.a >=2 OR t5.c IS NULL) AND
+(t6.a >=4 OR t6.c IS NULL) AND
+(t7.a <= 2 OR t7.c IS NULL) AND
+(t8.a < 1 OR t8.c IS NULL) AND
+(t8.b=t9.b OR t8.c IS NULL) AND
+(t9.a=1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where
+1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t8 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
+Warnings:
+Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`)))
+CREATE INDEX idx_b ON t8(b);
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+FROM t0,t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2),
+t9
+WHERE t0.a=1 AND
+t0.b=t1.b AND
+(t2.a >= 4 OR t2.c IS NULL) AND
+(t3.a < 5 OR t3.c IS NULL) AND
+(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+(t5.a >=2 OR t5.c IS NULL) AND
+(t6.a >=4 OR t6.c IS NULL) AND
+(t7.a <= 2 OR t7.c IS NULL) AND
+(t8.a < 1 OR t8.c IS NULL) AND
+(t8.b=t9.b OR t8.c IS NULL) AND
+(t9.a=1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where
+1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 2 Using where
+1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
+Warnings:
+Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`)))
+CREATE INDEX idx_b ON t1(b);
+CREATE INDEX idx_a ON t0(a);
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+FROM t0,t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2),
+t9
+WHERE t0.a=1 AND
+t0.b=t1.b AND
+(t2.a >= 4 OR t2.c IS NULL) AND
+(t3.a < 5 OR t3.c IS NULL) AND
+(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+(t5.a >=2 OR t5.c IS NULL) AND
+(t6.a >=4 OR t6.c IS NULL) AND
+(t7.a <= 2 OR t7.c IS NULL) AND
+(t8.a < 1 OR t8.c IS NULL) AND
+(t8.b=t9.b OR t8.c IS NULL) AND
+(t9.a=1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 ref idx_a idx_a 5 const 1 Using where
+1 SIMPLE t1 ref idx_b idx_b 5 test.t0.b 2 Using where
+1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where
+1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
+1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 2 Using where
+1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
+Warnings:
+Note 1003 select `test`.`t0`.`a` AS `a`,`test`.`t0`.`b` AS `b`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b`,`test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b`,`test`.`t5`.`a` AS `a`,`test`.`t5`.`b` AS `b`,`test`.`t6`.`a` AS `a`,`test`.`t6`.`b` AS `b`,`test`.`t7`.`a` AS `a`,`test`.`t7`.`b` AS `b`,`test`.`t8`.`a` AS `a`,`test`.`t8`.`b` AS `b`,`test`.`t9`.`a` AS `a`,`test`.`t9`.`b` AS `b` from `test`.`t0` join `test`.`t1` left join (`test`.`t2` left join (`test`.`t3` join `test`.`t4`) on(((`test`.`t4`.`b` = `test`.`t2`.`b`) and (`test`.`t3`.`a` = 1))) join `test`.`t5` left join (`test`.`t6` join `test`.`t7` left join `test`.`t8` on(((`test`.`t8`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` < 10)))) on(((`test`.`t7`.`b` = `test`.`t5`.`b`) and (`test`.`t6`.`b` >= 2)))) on((((`test`.`t3`.`b` = 2) or isnull(`test`.`t3`.`c`)) and ((`test`.`t6`.`b` = 2) or isnull(`test`.`t6`.`c`)) and ((`test`.`t5`.`b` = `test`.`t0`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t6`.`c`) or isnull(`test`.`t8`.`c`)) and (`test`.`t1`.`a` <> 2))) join `test`.`t9` where ((`test`.`t9`.`a` = 1) and (`test`.`t1`.`b` = `test`.`t0`.`b`) and (`test`.`t0`.`a` = 1) and ((`test`.`t2`.`a` >= 4) or isnull(`test`.`t2`.`c`)) and ((`test`.`t3`.`a` < 5) or isnull(`test`.`t3`.`c`)) and ((`test`.`t4`.`b` = `test`.`t3`.`b`) or isnull(`test`.`t3`.`c`) or isnull(`test`.`t4`.`c`)) and ((`test`.`t5`.`a` >= 2) or isnull(`test`.`t5`.`c`)) and ((`test`.`t6`.`a` >= 4) or isnull(`test`.`t6`.`c`)) and ((`test`.`t7`.`a` <= 2) or isnull(`test`.`t7`.`c`)) and ((`test`.`t8`.`a` < 1) or isnull(`test`.`t8`.`c`)) and ((`test`.`t9`.`b` = `test`.`t8`.`b`) or isnull(`test`.`t8`.`c`)))
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+FROM t0,t1
+LEFT JOIN
+(
+t2
+LEFT JOIN
+(t3, t4)
+ON t3.a=1 AND t2.b=t4.b,
+t5
+LEFT JOIN
+(
+t6,
+t7
+LEFT JOIN
+t8
+ON t7.b=t8.b AND t6.b < 10
+)
+ON t6.b >= 2 AND t5.b=t7.b
+)
+ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+(t1.a != 2),
+t9
+WHERE t0.a=1 AND
+t0.b=t1.b AND
+(t2.a >= 4 OR t2.c IS NULL) AND
+(t3.a < 5 OR t3.c IS NULL) AND
+(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+(t5.a >=2 OR t5.c IS NULL) AND
+(t6.a >=4 OR t6.c IS NULL) AND
+(t7.a <= 2 OR t7.c IS NULL) AND
+(t8.a < 1 OR t8.c IS NULL) AND
+(t8.b=t9.b OR t8.c IS NULL) AND
+(t9.a=1);
+a b a b a b a b a b a b a b a b a b a b
+1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 1
+1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 1
+1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 1
+1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 1
+1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 1
+1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 1
+1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 1
+1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 2
+1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 2
+1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 1 2
+1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 2
+1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 2
+1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 1 2
+1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 2
+1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 2
+1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 1 2
+1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 2
+SELECT t2.a,t2.b
+FROM t2;
+a b
+3 3
+4 2
+5 3
+SELECT t3.a,t3.b
+FROM t3;
+a b
+1 2
+2 2
+SELECT t2.a,t2.b,t3.a,t3.b
+FROM t2 LEFT JOIN t3 ON t2.b=t3.b
+WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL);
+a b a b
+4 2 1 2
+4 2 2 2
+5 3 NULL NULL
+SELECT t2.a,t2.b,t3.a,t3.b
+FROM t2 LEFT JOIN (t3) ON t2.b=t3.b
+WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL);
+a b a b
+4 2 1 2
+4 2 2 2
+5 3 NULL NULL
+ALTER TABLE t3
+CHANGE COLUMN a a1 int,
+CHANGE COLUMN c c1 int;
+SELECT t2.a,t2.b,t3.a1,t3.b
+FROM t2 LEFT JOIN t3 ON t2.b=t3.b
+WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL);
+a b a1 b
+4 2 1 2
+4 2 2 2
+5 3 NULL NULL
+SELECT t2.a,t2.b,t3.a1,t3.b
+FROM t2 NATURAL LEFT JOIN t3
+WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL);
+a b a1 b
+4 2 1 2
+4 2 2 2
+5 3 NULL NULL
+DROP TABLE t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (a int);
+CREATE TABLE t3 (a int);
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t3 VALUES (2);
+INSERT INTO t1 VALUES (2);
+SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.a=t3.a;
+a a a
+1 NULL NULL
+2 2 2
+SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a;
+a a a
+1 NULL NULL
+2 2 2
+DELETE FROM t1 WHERE a=2;
+SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a;
+a a a
+1 NULL NULL
+DELETE FROM t2;
+SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a;
+a a a
+1 NULL NULL
+DROP TABLE t1,t2,t3;
+CREATE TABLE t1(a int, key (a));
+CREATE TABLE t2(b int, key (b));
+CREATE TABLE t3(c int, key (c));
+INSERT INTO t1 VALUES (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9),
+(10), (11), (12), (13), (14), (15), (16), (17), (18), (19);
+INSERT INTO t2 VALUES (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9),
+(10), (11), (12), (13), (14), (15), (16), (17), (18), (19);
+INSERT INTO t3 VALUES (0), (1), (2), (3), (4), (5);
+EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON c < 3 and b = c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 21 Using index
+1 SIMPLE t3 index c c 5 NULL 6 Using index
+1 SIMPLE t2 ref b b 5 test.t3.c 2 Using index
+EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 21 Using index
+1 SIMPLE t3 index c c 5 NULL 6 Using index
+1 SIMPLE t2 ref b b 5 test.t3.c 2 Using index
+SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c;
+a b c
+NULL 0 0
+NULL 1 1
+NULL 2 2
+0 0 0
+0 1 1
+0 2 2
+1 0 0
+1 1 1
+1 2 2
+2 0 0
+2 1 1
+2 2 2
+3 0 0
+3 1 1
+3 2 2
+4 0 0
+4 1 1
+4 2 2
+5 0 0
+5 1 1
+5 2 2
+6 0 0
+6 1 1
+6 2 2
+7 0 0
+7 1 1
+7 2 2
+8 0 0
+8 1 1
+8 2 2
+9 0 0
+9 1 1
+9 2 2
+10 0 0
+10 1 1
+10 2 2
+11 0 0
+11 1 1
+11 2 2
+12 0 0
+12 1 1
+12 2 2
+13 0 0
+13 1 1
+13 2 2
+14 0 0
+14 1 1
+14 2 2
+15 0 0
+15 1 1
+15 2 2
+16 0 0
+16 1 1
+16 2 2
+17 0 0
+17 1 1
+17 2 2
+18 0 0
+18 1 1
+18 2 2
+19 0 0
+19 1 1
+19 2 2
+DELETE FROM t3;
+EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 21 Using index
+1 SIMPLE t3 index c c 5 NULL 0 Using index
+1 SIMPLE t2 ref b b 5 test.t3.c 2 Using index
+SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c;
+a b c
+NULL NULL NULL
+0 NULL NULL
+1 NULL NULL
+2 NULL NULL
+3 NULL NULL
+4 NULL NULL
+5 NULL NULL
+6 NULL NULL
+7 NULL NULL
+8 NULL NULL
+9 NULL NULL
+10 NULL NULL
+11 NULL NULL
+12 NULL NULL
+13 NULL NULL
+14 NULL NULL
+15 NULL NULL
+16 NULL NULL
+17 NULL NULL
+18 NULL NULL
+19 NULL NULL
+DROP TABLE t1,t2,t3;
diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result
index b6265aac4a3..6db48cff57e 100644
--- a/mysql-test/r/join_outer.result
+++ b/mysql-test/r/join_outer.result
@@ -1,4 +1,4 @@
-drop table if exists t1,t2,t3,t4,t5;
+drop table if exists t0,t1,t2,t3,t4,t5;
CREATE TABLE t1 (
grp int(11) default NULL,
a bigint(20) unsigned default NULL,
@@ -356,13 +356,7 @@ select t1.name, t2.name, t2.id, t2.owner, t3.id from t1 left join t2 on (t1.id =
name name id owner id
Antonio Paz El Gato 1 1 1
Antonio Paz Perrito 2 1 1
-Lilliana Angelovska NULL NULL NULL 1
-Thimble Smith NULL NULL NULL 1
-Antonio Paz NULL NULL NULL 2
-Lilliana Angelovska NULL NULL NULL 2
-Thimble Smith NULL NULL NULL 2
-Antonio Paz NULL NULL NULL 3
-Lilliana Angelovska NULL NULL NULL 3
+NULL NULL NULL NULL 2
Thimble Smith Happy 3 3 3
drop table t1,t2;
create table t1 (id int not null, str char(10), index(str));
@@ -634,7 +628,7 @@ insert into t2 values (10,1),(20,2),(30,3);
explain select * from t2 left join t1 on t1.fooID = t2.fooID and t1.fooID = 30;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL PRIMARY 4 NULL 3 Using index
-1 SIMPLE t1 const PRIMARY PRIMARY 2 const 1 Using where; Using index
+1 SIMPLE t1 const PRIMARY PRIMARY 2 const 1 Using index
select * from t2 left join t1 on t1.fooID = t2.fooID and t1.fooID = 30;
fooID barID fooID
10 1 NULL
@@ -656,6 +650,13 @@ select * from t1 natural left join t2 natural left join t3;
i i i
1 NULL NULL
2 2 2
+select * from t1 natural left join t2 where (t2.i is not null)=0;
+i i
+1 NULL
+select * from t1 natural left join t2 where (t2.i is not null) is not null;
+i i
+1 NULL
+2 2
drop table t1,t2,t3;
create table t1 (f1 integer,f2 integer,f3 integer);
create table t2 (f2 integer,f4 integer);
@@ -729,13 +730,13 @@ explain select s.*, '*', m.*, (s.match_1_h - m.home) UUX from
order by m.match_id desc;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE s ALL NULL NULL NULL NULL 10
-1 SIMPLE m const match_id,match_id_2 match_id 1 const 1 Using where
+1 SIMPLE m const match_id,match_id_2 match_id 1 const 1
explain select s.*, '*', m.*, (s.match_1_h - m.home) UUX from
(t2 s left join t1 m on m.match_id = 1)
order by UUX desc;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE s ALL NULL NULL NULL NULL 10 Using temporary; Using filesort
-1 SIMPLE m const match_id,match_id_2 match_id 1 const 1 Using where
+1 SIMPLE m const match_id,match_id_2 match_id 1 const 1
select s.*, '*', m.*, (s.match_1_h - m.home) UUX from
(t2 s left join t1 m on m.match_id = 1)
order by UUX desc;
@@ -755,7 +756,7 @@ t2 s straight_join t1 m where m.match_id = 1
order by UUX desc;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE s ALL NULL NULL NULL NULL 10 Using temporary; Using filesort
-1 SIMPLE m const match_id,match_id_2 match_id 1 const 1 Using where
+1 SIMPLE m const match_id,match_id_2 match_id 1 const 1
select s.*, '*', m.*, (s.match_1_h - m.home) UUX from
t2 s straight_join t1 m where m.match_id = 1
order by UUX desc;
@@ -810,32 +811,91 @@ t2.flag_value IS NULL;
flag_name flag_value
flag2 NULL
DROP TABLE t1,t2;
-CREATE TABLE invoice (
+CREATE TABLE t1 (
id int(11) unsigned NOT NULL auto_increment,
text_id int(10) unsigned default NULL,
PRIMARY KEY (id)
);
-INSERT INTO invoice VALUES("1", "0");
-INSERT INTO invoice VALUES("2", "10");
-CREATE TABLE text_table (
+INSERT INTO t1 VALUES("1", "0");
+INSERT INTO t1 VALUES("2", "10");
+CREATE TABLE t2 (
text_id char(3) NOT NULL default '',
language_id char(3) NOT NULL default '',
text_data text,
PRIMARY KEY (text_id,language_id)
);
-INSERT INTO text_table VALUES("0", "EN", "0-EN");
-INSERT INTO text_table VALUES("0", "SV", "0-SV");
-INSERT INTO text_table VALUES("10", "EN", "10-EN");
-INSERT INTO text_table VALUES("10", "SV", "10-SV");
-SELECT invoice.id, invoice.text_id, text_table.text_data
-FROM invoice LEFT JOIN text_table
-ON invoice.text_id = text_table.text_id
-AND text_table.language_id = 'SV'
- WHERE (invoice.id LIKE '%' OR text_table.text_data LIKE '%');
+INSERT INTO t2 VALUES("0", "EN", "0-EN");
+INSERT INTO t2 VALUES("0", "SV", "0-SV");
+INSERT INTO t2 VALUES("10", "EN", "10-EN");
+INSERT INTO t2 VALUES("10", "SV", "10-SV");
+SELECT t1.id, t1.text_id, t2.text_data
+FROM t1 LEFT JOIN t2
+ON t1.text_id = t2.text_id
+AND t2.language_id = 'SV'
+ WHERE (t1.id LIKE '%' OR t2.text_data LIKE '%');
id text_id text_data
1 0 0-SV
2 10 10-SV
-DROP TABLE invoice, text_table;
+DROP TABLE t1, t2;
+CREATE TABLE t0 (a0 int PRIMARY KEY);
+CREATE TABLE t1 (a1 int PRIMARY KEY);
+CREATE TABLE t2 (a2 int);
+CREATE TABLE t3 (a3 int);
+INSERT INTO t0 VALUES (1);
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (1), (2);
+INSERT INTO t3 VALUES (1), (2);
+SELECT * FROM t1 LEFT JOIN t2 ON a1=0;
+a1 a2
+1 NULL
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON a1=0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 1
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2
+SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0;
+a1 a2 a3
+1 NULL NULL
+EXPLAIN SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 1
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2
+SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1;
+a0 a1 a2 a3
+1 1 NULL NULL
+EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 system PRIMARY NULL NULL NULL 1
+1 SIMPLE t1 system PRIMARY NULL NULL NULL 1
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2
+INSERT INTO t0 VALUES (0);
+INSERT INTO t1 VALUES (0);
+SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
+a0 a1 a2 a3
+1 1 NULL NULL
+EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t0 const PRIMARY PRIMARY 4 const 1 Using index
+1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2
+1 SIMPLE t3 ALL NULL NULL NULL NULL 2
+drop table t1,t2;
+create table t1 (a int, b int);
+insert into t1 values (1,1),(2,2),(3,3);
+create table t2 (a int, b int);
+insert into t2 values (1,1), (2,2);
+select * from t2 right join t1 on t2.a=t1.a;
+a b a b
+1 1 1 1
+2 2 2 2
+NULL NULL 3 3
+select straight_join * from t2 right join t1 on t2.a=t1.a;
+a b a b
+1 1 1 1
+2 2 2 2
+NULL NULL 3 3
+DROP TABLE t0,t1,t2,t3;
CREATE TABLE t1 (a int PRIMARY KEY, b int);
CREATE TABLE t2 (a int PRIMARY KEY, b int);
INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (4,2);
diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result
index cceaf393a60..98e8851bb7e 100644
--- a/mysql-test/r/key.result
+++ b/mysql-test/r/key.result
@@ -110,7 +110,11 @@ name_id name
SELECT * FROM t2 WHERE name='[T,U]_axpby';
name_id name
2 [T,U]_axpby
-drop table t1,t2;
+CREATE TABLE t3 SELECT * FROM t2 WHERE name='[T,U]_axpby';
+SELECT * FROM t2 WHERE name='[T,U]_axpby';
+name_id name
+2 [T,U]_axpby
+drop table t1,t2,t3;
create table t1
(
SEQNO numeric(12 ) not null,
@@ -155,8 +159,8 @@ CREATE TABLE t1 (c CHAR(10) NOT NULL,i INT NOT NULL AUTO_INCREMENT,
UNIQUE (c,i));
INSERT INTO t1 (c) VALUES (NULL),(NULL);
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'c' at row 1
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'c' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'c' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'c' at row 2
SELECT * FROM t1;
c i
1
@@ -212,14 +216,14 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index
explain select 1 from t1 where id =2 or id=3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 2 Using where; Using index
+1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 7 Using where; Using index
explain select name from t1 where id =2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1
ALTER TABLE t1 DROP PRIMARY KEY, ADD INDEX (id);
explain select 1 from t1 where id =2;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref id id 4 const 1 Using where; Using index
+1 SIMPLE t1 ref id id 4 const 1 Using index
drop table t1;
CREATE TABLE t1 (numeropost mediumint(8) unsigned NOT NULL default '0', numreponse int(10) unsigned NOT NULL auto_increment, PRIMARY KEY (numeropost,numreponse), UNIQUE KEY numreponse (numreponse));
INSERT INTO t1 (numeropost,numreponse) VALUES ('1','1'),('1','2'),('2','3'),('2','4');
diff --git a/mysql-test/r/key_cache.result b/mysql-test/r/key_cache.result
index 79b5a6e84b2..7c286ced58a 100644
--- a/mysql-test/r/key_cache.result
+++ b/mysql-test/r/key_cache.result
@@ -193,6 +193,8 @@ cache index t1 key (unknown_key) in keycache1;
Table Op Msg_type Msg_text
test.t1 assign_to_keycache error Key column 'unknown_key' doesn't exist in table
test.t1 assign_to_keycache status Operation failed
+Warnings:
+Error 1072 Key column 'unknown_key' doesn't exist in table
select @@keycache2.key_buffer_size;
@@keycache2.key_buffer_size
4194304
diff --git a/mysql-test/r/keywords.result b/mysql-test/r/keywords.result
index c218379110f..88a0ab8abd5 100644
--- a/mysql-test/r/keywords.result
+++ b/mysql-test/r/keywords.result
@@ -1,12 +1,14 @@
drop table if exists t1;
-create table t1 (time time, date date, timestamp timestamp);
-insert into t1 values ("12:22:22","97:02:03","1997-01-02");
+create table t1 (time time, date date, timestamp timestamp,
+quarter int, week int, year int, timestampadd int, timestampdiff int);
+insert into t1 values ("12:22:22","97:02:03","1997-01-02",1,2,3,4,5);
select * from t1;
-time date timestamp
-12:22:22 1997-02-03 1997-01-02 00:00:00
-select t1.time+0,t1.date+0,t1.timestamp+0,concat(date," ",time) from t1;
-t1.time+0 t1.date+0 t1.timestamp+0 concat(date," ",time)
-122222 19970203 19970102000000 1997-02-03 12:22:22
+time date timestamp quarter week year timestampadd timestampdiff
+12:22:22 1997-02-03 1997-01-02 00:00:00 1 2 3 4 5
+select t1.time+0,t1.date+0,t1.timestamp+0,concat(date," ",time),
+t1.quarter+t1.week, t1.year+timestampadd, timestampdiff from t1;
+t1.time+0 t1.date+0 t1.timestamp+0 concat(date," ",time) t1.quarter+t1.week t1.year+timestampadd timestampdiff
+122222 19970203 19970102000000 1997-02-03 12:22:22 3 7 5
drop table t1;
create table events(binlog int);
insert into events values(1);
diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result
index ba9ba2833f6..754568093ff 100644
--- a/mysql-test/r/kill.result
+++ b/mysql-test/r/kill.result
@@ -17,3 +17,15 @@ select 4;
4
4
drop table t1;
+select get_lock("a", 10);
+get_lock("a", 10)
+1
+ select get_lock("a", 10);
+get_lock("a", 10)
+NULL
+select 1;
+1
+1
+select RELEASE_LOCK("a");
+RELEASE_LOCK("a")
+1
diff --git a/mysql-test/r/limit.result b/mysql-test/r/limit.result
index 6a3d2bffab0..1e38f762dd1 100644
--- a/mysql-test/r/limit.result
+++ b/mysql-test/r/limit.result
@@ -1,5 +1,5 @@
drop table if exists t1;
-create table t1 (a int primary key, b int not null);
+create table t1 (a int not null default 0 primary key, b int not null default 0);
insert into t1 () values ();
insert into t1 values (1,1),(2,1),(3,1);
update t1 set a=4 where b=1 limit 1;
diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result
index c0baabcc507..d76fff372f5 100644
--- a/mysql-test/r/loaddata.result
+++ b/mysql-test/r/loaddata.result
@@ -1,4 +1,4 @@
-drop table if exists t1;
+drop table if exists t1, t2;
create table t1 (a date, b date, c date not null, d date);
load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',';
Warnings:
@@ -43,9 +43,9 @@ drop table t1;
create table t1 (a int, b char(10));
load data infile '../../std_data/loaddata3.dat' into table t1 fields terminated by '' enclosed by '' ignore 1 lines;
Warnings:
-Warning 1265 Data truncated for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 3
Warning 1262 Row 3 was truncated; it contained more data than there were input columns
-Warning 1265 Data truncated for column 'a' at row 5
+Warning 1264 Out of range value adjusted for column 'a' at row 5
Warning 1262 Row 5 was truncated; it contained more data than there were input columns
select * from t1;
a b
@@ -57,7 +57,7 @@ a b
truncate table t1;
load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated by '' enclosed by '' lines terminated by '' ignore 1 lines;
Warnings:
-Warning 1265 Data truncated for column 'a' at row 4
+Warning 1264 Out of range value adjusted for column 'a' at row 4
Warning 1261 Row 4 doesn't contain data for all columns
select * from t1;
a b
@@ -66,3 +66,57 @@ a b
3 row 3
0
drop table t1;
+create table t1 (a int default 100, b int, c varchar(60));
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (a, @b) set b=@b+10, c=concat("b=",@b);
+select * from t1;
+a b c
+NULL 20 b=10
+NULL 25 b=15
+truncate table t1;
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (a, @b) set c= if(a is null,"oops",a);
+select * from t1;
+a b c
+NULL NULL oops
+NULL NULL oops
+truncate table t1;
+set @c:=123;
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (@a, b) set c= if(@a is null,@c,b);
+select * from t1;
+a b c
+100 10 123
+100 15 123
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (@a, @b);
+select * from t1;
+a b c
+100 10 123
+100 15 123
+100 NULL NULL
+100 NULL NULL
+select @a, @b;
+@a @b
+NULL 15
+truncate table t1;
+load data infile '../../std_data/loaddata5.dat' into table t1 fields terminated by '' enclosed by '' (a, b) set c="Wow";
+select * from t1;
+a b c
+1 2 Wow
+3 4 Wow
+5 6 Wow
+truncate table t1;
+load data infile '../../std_data/loaddata5.dat' into table t1 fields terminated by '' enclosed by '' (a, b) set c=concat(a,"+",b,"+",@c,"+",b,"+",if(c is null,"NIL",c));
+select * from t1;
+a b c
+1 2 1+2+123+2+NIL
+3 4 3+4+123+4+NIL
+5 6 5+6+123+6+NIL
+load data infile '../../std_data/loaddata5.dat' into table t1 fields terminated by '' enclosed by '' (a, @b);
+ERROR HY000: Can't load value from file with fixed size rows to variable
+create table t2 (num int primary key, str varchar(10));
+insert into t2 values (10,'Ten'), (15,'Fifteen');
+truncate table t1;
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (@dummy,@n) set a= @n, c= (select str from t2 where num=@n);
+select * from t1;
+a b c
+10 NULL Ten
+15 NULL Fifteen
+drop table t1, t2;
diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result
index 429bc5ed352..16c92fa201f 100644
--- a/mysql-test/r/lock.result
+++ b/mysql-test/r/lock.result
@@ -41,7 +41,7 @@ lock tables t1 write;
check table t2;
Table Op Msg_type Msg_text
test.t2 check error Table 't2' was not locked with LOCK TABLES
-insert into t1 select nr from t1;
+insert into t1 select index1,nr from t1;
ERROR HY000: Table 't1' was not locked with LOCK TABLES
unlock tables;
lock tables t1 write, t1 as t1_alias read;
diff --git a/mysql-test/r/lowercase_table.result b/mysql-test/r/lowercase_table.result
index a30ec0f160c..c0df8d968cb 100644
--- a/mysql-test/r/lowercase_table.result
+++ b/mysql-test/r/lowercase_table.result
@@ -1,6 +1,7 @@
drop table if exists t1,t2,t3,t4;
drop table if exists t0,t5,t6,t7,t8,t9;
drop database if exists mysqltest;
+drop view if exists v0, v1, v2, v3, v4;
create table T1 (id int primary key, Word varchar(40) not null, Index(Word));
create table t4 (id int primary key, Word varchar(40) not null);
INSERT INTO T1 VALUES (1, 'a'), (2, 'b'), (3, 'c');
diff --git a/mysql-test/r/lowercase_table3.result b/mysql-test/r/lowercase_table3.result
index 8182d07c26b..995a2c0d08a 100644
--- a/mysql-test/r/lowercase_table3.result
+++ b/mysql-test/r/lowercase_table3.result
@@ -6,5 +6,5 @@ drop table t1;
flush tables;
CREATE TABLE t1 (a int) ENGINE=INNODB;
SELECT * from T1;
-ERROR HY000: Can't open file: 'T1.ibd' (errno: 1)
+ERROR 42S02: Table 'test.T1' doesn't exist
drop table t1;
diff --git a/mysql-test/r/lowercase_table_grant.result b/mysql-test/r/lowercase_table_grant.result
index 3889bd418db..c3813d57074 100644
--- a/mysql-test/r/lowercase_table_grant.result
+++ b/mysql-test/r/lowercase_table_grant.result
@@ -6,8 +6,8 @@ Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_1'@'localhost'
select * from db where user = 'mysqltest_1';
-Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv
-localhost mysqltest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y
+Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv
+localhost mysqltest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y
update db set db = 'MYSQLtest' where db = 'mysqltest' and user = 'mysqltest_1' and host = 'localhost';
flush privileges;
show grants for mysqltest_1@localhost;
@@ -15,8 +15,8 @@ Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_1'@'localhost'
select * from db where user = 'mysqltest_1';
-Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv
-localhost MYSQLtest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y
+Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv
+localhost MYSQLtest mysqltest_1 Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y
delete from db where db = 'MYSQLtest' and user = 'mysqltest_1' and host = 'localhost';
flush privileges;
drop user mysqltest_1@localhost;
diff --git a/mysql-test/r/lowercase_view.result b/mysql-test/r/lowercase_view.result
new file mode 100644
index 00000000000..37252c6dde7
--- /dev/null
+++ b/mysql-test/r/lowercase_view.result
@@ -0,0 +1,133 @@
+drop table if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop view if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop database if exists MySQLTest;
+create database MySQLTest;
+use MySQLTest;
+create table TaB (Field int);
+create view ViE as select * from TAb;
+show create table VIe;
+View Create View
+vie CREATE ALGORITHM=UNDEFINED VIEW `mysqltest`.`vie` AS select `mysqltest`.`tab`.`Field` AS `Field` from `mysqltest`.`tab`
+drop database MySQLTest;
+use test;
+create table t1Aa (col1 int);
+create table t2aA (col1 int);
+create view v1Aa as select * from t1aA;
+create view v2aA as select * from v1aA;
+create view v3Aa as select v2Aa.col1 from v2aA,t2Aa where v2Aa.col1 = t2aA.col1;
+update v2aA set col1 = (select max(col1) from v1Aa);
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+update v2Aa set col1 = (select max(col1) from t1Aa);
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+update v2aA set col1 = (select max(col1) from v2Aa);
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v1aA) where v2aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v1Aa) where t1aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't1aa' for update in FROM clause
+update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause
+update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from v1aA) where v2Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't2aa' for update in FROM clause
+update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v1Aa) where t1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't2aa' for update in FROM clause
+update t2Aa,v1aA set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't2aa' for update in FROM clause
+update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from t1aA) where v2aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+update t1Aa,t2Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't1aa' for update in FROM clause
+update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from t1Aa) where v1aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause
+update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from t1aA) where v2Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't2aa' for update in FROM clause
+update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't2aa' for update in FROM clause
+update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from t1Aa) where v1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't2aa' for update in FROM clause
+update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v2aA) where t1aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't1aa' for update in FROM clause
+update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v2Aa) where v1aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause
+update t2Aa,v2aA set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't2aa' for update in FROM clause
+update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v2aA) where t1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't2aa' for update in FROM clause
+update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from v2Aa) where v1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't2aa' for update in FROM clause
+update v3aA set v3Aa.col1 = (select max(col1) from v1aA);
+ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause
+update v3aA set v3Aa.col1 = (select max(col1) from t1aA);
+ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause
+update v3aA set v3Aa.col1 = (select max(col1) from v2aA);
+ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause
+update v3aA set v3Aa.col1 = (select max(col1) from v3aA);
+ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause
+delete from v2Aa where col1 = (select max(col1) from v1Aa);
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+delete from v2aA where col1 = (select max(col1) from t1Aa);
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+delete from v2Aa where col1 = (select max(col1) from v2aA);
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+delete v2Aa from v2aA,t2Aa where (select max(col1) from v1aA) > 0 and v2Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+delete t1aA from t1Aa,t2Aa where (select max(col1) from v1Aa) > 0 and t1aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't1aa' for update in FROM clause
+delete v1aA from v1Aa,t2Aa where (select max(col1) from v1aA) > 0 and v1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause
+delete v2aA from v2Aa,t2Aa where (select max(col1) from t1Aa) > 0 and v2aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+delete t1aA from t1Aa,t2Aa where (select max(col1) from t1aA) > 0 and t1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't1aa' for update in FROM clause
+delete v1aA from v1Aa,t2Aa where (select max(col1) from t1aA) > 0 and v1aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause
+delete v2Aa from v2aA,t2Aa where (select max(col1) from v2Aa) > 0 and v2aA.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+delete t1Aa from t1aA,t2Aa where (select max(col1) from v2Aa) > 0 and t1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 't1aa' for update in FROM clause
+delete v1Aa from v1aA,t2Aa where (select max(col1) from v2aA) > 0 and v1Aa.col1 = t2aA.col1;
+ERROR HY000: You can't specify target table 'v1aa' for update in FROM clause
+insert into v2Aa values ((select max(col1) from v1aA));
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+insert into t1aA values ((select max(col1) from v1Aa));
+ERROR HY000: You can't specify target table 't1aa' for update in FROM clause
+insert into v2aA values ((select max(col1) from v1aA));
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+insert into v2Aa values ((select max(col1) from t1Aa));
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+insert into t1aA values ((select max(col1) from t1Aa));
+ERROR HY000: You can't specify target table 't1aa' for update in FROM clause
+insert into v2aA values ((select max(col1) from t1aA));
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+insert into v2Aa values ((select max(col1) from v2aA));
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+insert into t1Aa values ((select max(col1) from v2Aa));
+ERROR HY000: You can't specify target table 't1aa' for update in FROM clause
+insert into v2aA values ((select max(col1) from v2Aa));
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+insert into v3Aa (col1) values ((select max(col1) from v1Aa));
+ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause
+insert into v3aA (col1) values ((select max(col1) from t1aA));
+ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause
+insert into v3Aa (col1) values ((select max(col1) from v2aA));
+ERROR HY000: You can't specify target table 'v3aa' for update in FROM clause
+drop view v3aA,v2Aa,v1aA;
+drop table t1Aa,t2Aa;
+create table t1Aa (col1 int);
+create view v1Aa as select col1 from t1Aa as AaA;
+show create view v1AA;
+View Create View
+v1aa CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1aa` AS select `aaa`.`col1` AS `col1` from `test`.`t1aa` `AaA`
+drop view v1AA;
+select Aaa.col1 from t1Aa as AaA;
+col1
+create view v1Aa as select Aaa.col1 from t1Aa as AaA;
+drop view v1AA;
+create view v1Aa as select AaA.col1 from t1Aa as AaA;
+show create view v1AA;
+View Create View
+v1aa CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1aa` AS select `aaa`.`col1` AS `col1` from `test`.`t1aa` `AaA`
+drop view v1AA;
+drop table t1Aa;
diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result
index 79d8f019ce3..54feabc6608 100644
--- a/mysql-test/r/merge.result
+++ b/mysql-test/r/merge.result
@@ -172,22 +172,22 @@ a b
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` char(20) default NULL,
KEY `a` (`a`)
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`,`t2`)
create table t4 (a int not null, b char(10), key(a)) engine=MERGE UNION=(t1,t2);
select * from t4;
-ERROR HY000: Can't open file: 't4.MRG' (errno: 143)
+ERROR HY000: All tables in the MERGE table are not identically defined
alter table t4 add column c int;
-ERROR HY000: Can't open file: 't4.MRG' (errno: 143)
+ERROR HY000: All tables in the MERGE table are not identically defined
create database mysqltest;
create table mysqltest.t6 (a int not null primary key auto_increment, message char(20));
create table t5 (a int not null, b char(20), key(a)) engine=MERGE UNION=(test.t1,mysqltest.t6);
show create table t5;
Table Create Table
t5 CREATE TABLE `t5` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` char(20) default NULL,
KEY `a` (`a`)
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`,`mysqltest`.`t6`)
@@ -260,16 +260,16 @@ ENGINE=MERGE UNION=(t1,t2);
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
- `incr` int(11) NOT NULL default '0',
- `othr` int(11) NOT NULL default '0',
+ `incr` int(11) NOT NULL,
+ `othr` int(11) NOT NULL,
PRIMARY KEY (`incr`)
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`,`t2`)
alter table t3 drop primary key;
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
- `incr` int(11) NOT NULL default '0',
- `othr` int(11) NOT NULL default '0'
+ `incr` int(11) NOT NULL,
+ `othr` int(11) NOT NULL
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`,`t2`)
drop table t3,t2,t1;
create table t1 (a int not null, key(a)) engine=merge;
@@ -296,28 +296,28 @@ create table t6 (a int not null, b int not null auto_increment, primary key(a,b)
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
- `a` int(11) NOT NULL default '0',
- `b` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
+ `b` int(11) NOT NULL,
KEY `a` (`a`,`b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table t4;
Table Create Table
t4 CREATE TABLE `t4` (
- `a` int(11) NOT NULL default '0',
- `b` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
+ `b` int(11) NOT NULL,
KEY `a` (`a`,`b`)
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`,`t2`)
show create table t5;
Table Create Table
t5 CREATE TABLE `t5` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` int(11) NOT NULL auto_increment,
PRIMARY KEY (`a`,`b`)
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=FIRST UNION=(`t1`,`t2`)
show create table t6;
Table Create Table
t6 CREATE TABLE `t6` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` int(11) NOT NULL auto_increment,
PRIMARY KEY (`a`,`b`)
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`)
@@ -382,8 +382,8 @@ alter table t4 UNION=(t1,t2,t3);
show create table t4;
Table Create Table
t4 CREATE TABLE `t4` (
- `a` int(11) NOT NULL default '0',
- `b` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
+ `b` int(11) NOT NULL,
KEY `a` (`a`,`b`)
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`,`t2`,`t3`)
select * from t4 order by a,b;
@@ -408,8 +408,8 @@ alter table t4 INSERT_METHOD=FIRST;
show create table t4;
Table Create Table
t4 CREATE TABLE `t4` (
- `a` int(11) NOT NULL default '0',
- `b` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
+ `b` int(11) NOT NULL,
KEY `a` (`a`,`b`)
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=FIRST UNION=(`t1`,`t2`,`t3`)
insert into t4 values (4,1),(4,2);
@@ -614,19 +614,19 @@ KEY files (fileset_id,fileset_root_id)
EXPLAIN SELECT * FROM t2 IGNORE INDEX (files) WHERE fileset_id = 2
AND file_code BETWEEN '0000000115' AND '0000000120' LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 range PRIMARY PRIMARY 33 NULL 5 Using where
+1 SIMPLE t2 range PRIMARY PRIMARY 35 NULL 5 Using where
EXPLAIN SELECT * FROM t2 WHERE fileset_id = 2
AND file_code BETWEEN '0000000115' AND '0000000120' LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 range PRIMARY,files PRIMARY 33 NULL 5 Using where
+1 SIMPLE t2 range PRIMARY,files PRIMARY 35 NULL 5 Using where
EXPLAIN SELECT * FROM t1 WHERE fileset_id = 2
AND file_code BETWEEN '0000000115' AND '0000000120' LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range PRIMARY,files PRIMARY 33 NULL 5 Using where
+1 SIMPLE t1 range PRIMARY,files PRIMARY 35 NULL 5 Using where
EXPLAIN SELECT * FROM t2 WHERE fileset_id = 2
AND file_code = '0000000115' LIMIT 1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 const PRIMARY,files PRIMARY 33 const,const 1
+1 SIMPLE t2 ref PRIMARY,files PRIMARY 35 const,const 1 Using where
DROP TABLE t2, t1;
create table t1 (x int, y int, index xy(x, y));
create table t2 (x int, y int, index xy(x, y));
@@ -650,6 +650,8 @@ create table t3 engine=merge union=(t1, t2) select * from t1;
ERROR HY000: You can't specify target table 't1' for update in FROM clause
create table t3 engine=merge union=(t1, t2) select * from t2;
ERROR HY000: You can't specify target table 't2' for update in FROM clause
+create table t3 engine=merge union=(t1, t2) select (select max(a) from t2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
drop table t1, t2;
create table t1 (a int,b int,c int, index (a,b,c));
create table t2 (a int,b int,c int, index (a,b,c));
diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result
index 8f25e6b7f4a..b5d5785f0f1 100644
--- a/mysql-test/r/metadata.result
+++ b/mysql-test/r/metadata.result
@@ -2,9 +2,9 @@ drop table if exists t1,t2;
select 1, 1.0, -1, "hello", NULL;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def 1 8 1 1 N 32897 0 63
-def 1.0 5 3 3 N 32897 1 63
+def 1.0 246 4 3 N 161 1 63
def -1 8 2 2 N 32897 0 63
-def hello 254 5 5 N 1 31 8
+def hello 253 5 5 N 1 31 8
def NULL 6 0 0 Y 32896 0 63
1 1.0 -1 hello NULL
1 1.0 -1 hello NULL
@@ -18,7 +18,7 @@ def test t1 t1 d d 3 11 0 Y 32768 0 63
def test t1 t1 e e 8 20 0 Y 32768 0 63
def test t1 t1 f f 4 3 0 Y 32768 2 63
def test t1 t1 g g 5 4 0 Y 32768 3 63
-def test t1 t1 h h 0 7 0 Y 32768 4 63
+def test t1 t1 h h 246 5 0 Y 0 4 63
def test t1 t1 i i 13 4 0 Y 32864 0 63
def test t1 t1 j j 10 10 0 Y 128 0 63
def test t1 t1 k k 7 19 0 N 1249 0 63
diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result
index 72288d1027b..e4528450b31 100644
--- a/mysql-test/r/mix_innodb_myisam_binlog.result
+++ b/mysql-test/r/mix_innodb_myisam_binlog.result
@@ -6,12 +6,12 @@ begin;
insert into t1 values(1);
insert into t2 select * from t1;
commit;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; BEGIN
-master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(1)
-master-bin.000001 178 Query 1 79 use `test`; insert into t2 select * from t1
-master-bin.000001 244 Query 1 244 use `test`; COMMIT
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; BEGIN
+master-bin.000001 166 Query 1 # use `test`; insert into t1 values(1)
+master-bin.000001 253 Query 1 # use `test`; insert into t2 select * from t1
+master-bin.000001 347 Xid 1 # COMMIT /* xid=8 */
delete from t1;
delete from t2;
reset master;
@@ -21,12 +21,12 @@ insert into t2 select * from t1;
rollback;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; BEGIN
-master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(2)
-master-bin.000001 178 Query 1 79 use `test`; insert into t2 select * from t1
-master-bin.000001 244 Query 1 244 use `test`; ROLLBACK
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; BEGIN
+master-bin.000001 166 Query 1 # use `test`; insert into t1 values(2)
+master-bin.000001 253 Query 1 # use `test`; insert into t2 select * from t1
+master-bin.000001 347 Query 1 # use `test`; ROLLBACK
delete from t1;
delete from t2;
reset master;
@@ -39,15 +39,15 @@ rollback to savepoint my_savepoint;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
commit;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; BEGIN
-master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(3)
-master-bin.000001 178 Query 1 79 use `test`; savepoint my_savepoint
-master-bin.000001 235 Query 1 79 use `test`; insert into t1 values(4)
-master-bin.000001 294 Query 1 79 use `test`; insert into t2 select * from t1
-master-bin.000001 360 Query 1 79 use `test`; rollback to savepoint my_savepoint
-master-bin.000001 429 Query 1 429 use `test`; COMMIT
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; BEGIN
+master-bin.000001 166 Query 1 # use `test`; insert into t1 values(3)
+master-bin.000001 253 Query 1 # use `test`; savepoint my_savepoint
+master-bin.000001 338 Query 1 # use `test`; insert into t1 values(4)
+master-bin.000001 425 Query 1 # use `test`; insert into t2 select * from t1
+master-bin.000001 519 Query 1 # use `test`; rollback to savepoint my_savepoint
+master-bin.000001 616 Xid 1 # COMMIT /* xid=25 */
delete from t1;
delete from t2;
reset master;
@@ -65,16 +65,16 @@ select a from t1 order by a;
a
5
7
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; BEGIN
-master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(5)
-master-bin.000001 178 Query 1 79 use `test`; savepoint my_savepoint
-master-bin.000001 235 Query 1 79 use `test`; insert into t1 values(6)
-master-bin.000001 294 Query 1 79 use `test`; insert into t2 select * from t1
-master-bin.000001 360 Query 1 79 use `test`; rollback to savepoint my_savepoint
-master-bin.000001 429 Query 1 79 use `test`; insert into t1 values(7)
-master-bin.000001 488 Query 1 488 use `test`; COMMIT
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; BEGIN
+master-bin.000001 166 Query 1 # use `test`; insert into t1 values(5)
+master-bin.000001 253 Query 1 # use `test`; savepoint my_savepoint
+master-bin.000001 338 Query 1 # use `test`; insert into t1 values(6)
+master-bin.000001 425 Query 1 # use `test`; insert into t2 select * from t1
+master-bin.000001 519 Query 1 # use `test`; rollback to savepoint my_savepoint
+master-bin.000001 616 Query 1 # use `test`; insert into t1 values(7)
+master-bin.000001 703 Xid 1 # COMMIT /* xid=37 */
delete from t1;
delete from t2;
reset master;
@@ -87,40 +87,43 @@ insert into t2 select * from t1;
select get_lock("a",10);
get_lock("a",10)
1
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; BEGIN
-master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(8)
-master-bin.000001 178 Query 1 79 use `test`; insert into t2 select * from t1
-master-bin.000001 244 Query 1 244 use `test`; ROLLBACK
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; BEGIN
+master-bin.000001 166 Query 1 # use `test`; insert into t1 values(8)
+master-bin.000001 253 Query 1 # use `test`; insert into t2 select * from t1
+master-bin.000001 347 Query 1 # use `test`; ROLLBACK
delete from t1;
delete from t2;
reset master;
insert into t1 values(9);
insert into t2 select * from t1;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; insert into t1 values(9)
-master-bin.000001 138 Query 1 138 use `test`; insert into t2 select * from t1
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; insert into t1 values(9)
+master-bin.000001 185 Xid 1 # COMMIT /* xid=60 */
+master-bin.000001 212 Query 1 # use `test`; insert into t2 select * from t1
delete from t1;
delete from t2;
reset master;
insert into t1 values(10);
begin;
insert into t2 select * from t1;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; insert into t1 values(10)
-master-bin.000001 139 Query 1 139 use `test`; insert into t2 select * from t1
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; insert into t1 values(10)
+master-bin.000001 186 Xid 1 # COMMIT /* xid=66 */
+master-bin.000001 213 Query 1 # use `test`; insert into t2 select * from t1
insert into t1 values(11);
commit;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; insert into t1 values(10)
-master-bin.000001 139 Query 1 139 use `test`; insert into t2 select * from t1
-master-bin.000001 205 Query 1 205 use `test`; BEGIN
-master-bin.000001 245 Query 1 205 use `test`; insert into t1 values(11)
-master-bin.000001 305 Query 1 305 use `test`; COMMIT
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; insert into t1 values(10)
+master-bin.000001 186 Xid 1 # COMMIT /* xid=66 */
+master-bin.000001 213 Query 1 # use `test`; insert into t2 select * from t1
+master-bin.000001 307 Query 1 # use `test`; BEGIN
+master-bin.000001 375 Query 1 # use `test`; insert into t1 values(11)
+master-bin.000001 463 Xid 1 # COMMIT /* xid=68 */
alter table t2 engine=INNODB;
delete from t1;
delete from t2;
@@ -129,12 +132,12 @@ begin;
insert into t1 values(12);
insert into t2 select * from t1;
commit;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; BEGIN
-master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(12)
-master-bin.000001 179 Query 1 79 use `test`; insert into t2 select * from t1
-master-bin.000001 245 Query 1 245 use `test`; COMMIT
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; BEGIN
+master-bin.000001 166 Query 1 # use `test`; insert into t1 values(12)
+master-bin.000001 254 Query 1 # use `test`; insert into t2 select * from t1
+master-bin.000001 348 Xid 1 # COMMIT /* xid=78 */
delete from t1;
delete from t2;
reset master;
@@ -142,8 +145,8 @@ begin;
insert into t1 values(13);
insert into t2 select * from t1;
rollback;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
delete from t1;
delete from t2;
reset master;
@@ -154,11 +157,11 @@ insert into t1 values(15);
insert into t2 select * from t1;
rollback to savepoint my_savepoint;
commit;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; BEGIN
-master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(14)
-master-bin.000001 179 Query 1 179 use `test`; COMMIT
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; BEGIN
+master-bin.000001 166 Query 1 # use `test`; insert into t1 values(14)
+master-bin.000001 254 Xid 1 # COMMIT /* xid=94 */
delete from t1;
delete from t2;
reset master;
@@ -174,12 +177,12 @@ select a from t1 order by a;
a
16
18
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; BEGIN
-master-bin.000001 119 Query 1 79 use `test`; insert into t1 values(16)
-master-bin.000001 179 Query 1 79 use `test`; insert into t1 values(18)
-master-bin.000001 239 Query 1 239 use `test`; COMMIT
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 # use `test`; BEGIN
+master-bin.000001 166 Query 1 # use `test`; insert into t1 values(16)
+master-bin.000001 254 Query 1 # use `test`; insert into t1 values(18)
+master-bin.000001 342 Xid 1 # COMMIT /* xid=105 */
delete from t1;
delete from t2;
alter table t2 type=MyISAM;
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
index dba10296063..f5c4e19af64 100644
--- a/mysql-test/r/multi_update.result
+++ b/mysql-test/r/multi_update.result
@@ -1,5 +1,6 @@
drop table if exists t1,t2,t3;
drop database if exists mysqltest;
+drop view if exists v1;
revoke all privileges on mysqltest.t1 from mysqltest_1@localhost;
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
delete from mysql.user where user=_binary'mysqltest_1';
@@ -475,3 +476,46 @@ aclid bigint, index idx_acl(aclid)
insert into t2 values(1,null);
delete t2, t1 from t2 left join t1 on (t2.aclid=t1.aclid) where t2.refid='1';
drop table t1, t2;
+create table t1 ( c char(8) not null ) engine=innodb;
+insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9');
+insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F');
+alter table t1 add b char(8) not null;
+alter table t1 add a char(8) not null;
+alter table t1 add primary key (a,b,c);
+update t1 set a=c, b=c;
+create table t2 like t1;
+insert into t2 select * from t1;
+delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b;
+drop table t1,t2;
+create table t1 ( c char(8) not null ) engine=bdb;
+insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9');
+insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F');
+alter table t1 add b char(8) not null;
+alter table t1 add a char(8) not null;
+alter table t1 add primary key (a,b,c);
+update t1 set a=c, b=c;
+create table t2 like t1;
+insert into t2 select * from t1;
+delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b;
+drop table t1,t2;
+create table t1 (a int, b int);
+insert into t1 values (1, 2), (2, 3), (3, 4);
+create table t2 (a int);
+insert into t2 values (10), (20), (30);
+create view v1 as select a as b, a/10 as a from t2;
+lock table t1 write;
+ alter table t1 add column c int default 100 after a;
+ update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a;
+unlock tables;
+select * from t1;
+a c b
+1 100 13
+2 100 25
+3 100 37
+select * from t2;
+a
+10
+20
+30
+drop view v1;
+drop table t1, t2;
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index 5b69ce68a79..1a8ace98d05 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -408,8 +408,8 @@ Table Op Msg_type Msg_text
test.t1 repair status OK
select concat(a,'.') from t1 where a='aaa';
concat(a,'.')
-aaa.
aaa .
+aaa.
select concat(a,'.') from t1 where binary a='aaa';
concat(a,'.')
aaa.
@@ -461,20 +461,27 @@ concat(a,'.')
a .
drop table t1;
create table t1 (a int not null auto_increment primary key, b text not null, unique b (b(20)));
-insert into t1 (b) values ('a'),('a '),('a ');
+insert into t1 (b) values ('a'),('b'),('c');
select concat(b,'.') from t1;
concat(b,'.')
a.
-a .
-a .
+b.
+c.
update t1 set b='b ' where a=2;
update t1 set b='b ' where a > 1;
ERROR 23000: Duplicate entry 'b ' for key 2
+insert into t1 (b) values ('b');
+ERROR 23000: Duplicate entry 'b' for key 2
+select * from t1;
+a b
+1 a
+2 b
+3 c
delete from t1 where b='b';
select a,concat(b,'.') from t1;
a concat(b,'.')
1 a.
-3 a .
+3 c.
drop table t1;
create table t1 (a int not null);
create table t2 (a int not null, primary key (a));
@@ -506,19 +513,25 @@ insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
insert t2 select * from t1;
checksum table t1, t2, t3 quick;
Table Checksum
-test.t1 968604391
+test.t1 2948697075
test.t2 NULL
test.t3 NULL
+Warnings:
+Error 1146 Table 'test.t3' doesn't exist
checksum table t1, t2, t3;
Table Checksum
-test.t1 968604391
-test.t2 968604391
+test.t1 2948697075
+test.t2 3092701434
test.t3 NULL
+Warnings:
+Error 1146 Table 'test.t3' doesn't exist
checksum table t1, t2, t3 extended;
Table Checksum
-test.t1 968604391
-test.t2 968604391
+test.t1 3092701434
+test.t2 3092701434
test.t3 NULL
+Warnings:
+Error 1146 Table 'test.t3' doesn't exist
drop table t1,t2;
create table t1 (a int, key (a));
show keys from t1;
@@ -581,3 +594,612 @@ check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
+set storage_engine=MyISAM;
+drop table if exists t1,t2,t3;
+--- Testing varchar ---
+--- Testing varchar ---
+create table t1 (v varchar(10), c char(10), t text);
+insert into t1 values('+ ', '+ ', '+ ');
+set @a=repeat(' ',20);
+insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
+Warnings:
+Note 1265 Data truncated for column 'v' at row 1
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+ *+*+ *
+*+ *+*+ *
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+create table t2 like t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+create table t3 select * from t1;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+alter table t1 modify c varchar(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` text
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+alter table t1 modify v char(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` text
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+alter table t1 modify t varchar(10);
+Warnings:
+Note 1265 Data truncated for column 't' at row 2
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) default NULL,
+ `c` varchar(10) default NULL,
+ `t` varchar(10) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+*+*+ *
+*+*+*+ *
+drop table t1,t2,t3;
+create table t1 (v varchar(10), c char(10), t text, key(v), key(c), key(t(10)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `v` (`v`),
+ KEY `c` (`c`),
+ KEY `t` (`t`(10))
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select count(*) from t1;
+count(*)
+270
+insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1)));
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where c='a';
+count(*)
+10
+select count(*) from t1 where t='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where c='a ';
+count(*)
+10
+select count(*) from t1 where t='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where c like 'a%';
+count(*)
+11
+select count(*) from t1 where t like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const # Using where; Using index
+explain select count(*) from t1 where c='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref c c 11 const # Using where; Using index
+explain select count(*) from t1 where t='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range t t 13 NULL # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where; Using index
+alter table t1 add unique(v);
+ERROR 23000: Duplicate entry '{ ' for key 1
+alter table t1 add key(v);
+select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a';
+qq
+*a*a*a*
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v,v_2 # 13 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(c) from t1 group by v limit 10;
+v count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(c) from t1 group by v limit 10;
+v count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(*) from t1 group by c limit 10;
+c count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(*) from t1 group by t limit 10;
+t count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(t) from t1 group by t limit 10;
+t count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result t,count(t) from t1 group by t limit 10;
+t count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 modify v varchar(300), drop key v, drop key v_2, add key v (v);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(300) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 303 const # Using where; Using index
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 303 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 303 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 303 NULL # Using where; Using index
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 303 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 drop key v, add key v (v(30));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(300) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`(30))
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 modify v varchar(600), drop key v, add key v (v);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(600) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+drop table t1;
+create table t1 (a char(10), unique (a));
+insert into t1 values ('a ');
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a' for key 1
+alter table t1 modify a varchar(10);
+insert into t1 values ('a '),('a '),('a '),('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+update t1 set a='a ' where a like 'a%';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='abc ' where a like 'a ';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='a ' where a like 'a %';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='a ' where a like 'a ';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+drop table t1;
+create table t1 (v varchar(10), c char(10), t text, key(v(5)), key(c(5)), key(t(5)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL,
+ `t` text,
+ KEY `v` (`v`(5)),
+ KEY `c` (`c`(5)),
+ KEY `t` (`t`(5))
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v char(10) character set utf8);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) character set utf8 default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v varchar(10), c char(10)) row_format=fixed;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) default NULL,
+ `c` char(10) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED
+insert into t1 values('a','a'),('a ','a ');
+select concat('*',v,'*',c,'*') from t1;
+concat('*',v,'*',c,'*')
+*a*a*
+*a *a*
+drop table t1;
+create table t1 (v varchar(65530), key(v(10)));
+insert into t1 values(repeat('a',65530));
+select length(v) from t1 where v=repeat('a',65530);
+length(v)
+65530
+drop table t1;
+create table t1(a int, b varchar(12), key ba(b, a));
+insert into t1 values (1, 'A'), (20, NULL);
+explain select * from t1 where a=20 and b is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref ba ba 20 const,const 1 Using where; Using index
+select * from t1 where a=20 and b is null;
+a b
+20 NULL
+drop table t1;
+create table t1 (v varchar(65530), key(v));
+Warnings:
+Warning 1071 Specified key was too long; max key length is 1000 bytes
+drop table if exists t1;
+create table t1 (v varchar(65536));
+Warnings:
+Note 1246 Converting column 'v' from VARCHAR to TEXT
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` mediumtext
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v varchar(65530) character set utf8);
+Warnings:
+Note 1246 Converting column 'v' from VARCHAR to TEXT
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` mediumtext character set utf8
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (v varchar(65535));
+ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs
+set storage_engine=MyISAM;
+create table t1 (a int) engine=myisam;
+drop table if exists t1;
+Warnings:
+Error 2 Can't find file: 't1' (errno: 2)
+create table t1 (a int) engine=myisam;
+drop table t1;
+Got one of the listed errors
+create table t1 (a int) engine=myisam;
+drop table t1;
+Got one of the listed errors
+drop table t1;
+ERROR 42S02: Unknown table 't1'
diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result
index e88ece6b361..8765e65f11b 100644
--- a/mysql-test/r/mysqlbinlog.result
+++ b/mysql-test/r/mysqlbinlog.result
@@ -9,14 +9,18 @@ load data infile '../../std_data/words.dat' into table t1;
load data infile '../../std_data/words.dat' into table t1;
load data infile '../../std_data/words.dat' into table t1;
load data infile '../../std_data/words.dat' into table t1;
-load data infile '../../std_data/words.dat' into table t1;
insert into t1 values ("Alas");
flush logs;
--- Local --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1000000000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
drop table if exists t1,t2;
SET TIMESTAMP=1000000000;
create table t1 (word varchar(20));
@@ -27,32 +31,58 @@ insert into t1 values ("abirvalg");
SET INSERT_ID=1;
SET TIMESTAMP=1000000000;
insert into t2 values ();
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-1-0' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-2-0' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-3-0' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-4-0' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-5-0' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
+SET TIMESTAMP=1000000000;
+load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-1-0' INTO table t1;
+SET TIMESTAMP=1000000000;
+load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-2-0' INTO table t1;
+SET TIMESTAMP=1000000000;
+load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-3-0' INTO table t1;
+SET TIMESTAMP=1000000000;
+load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-4-0' INTO table t1;
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- Broken LOAD DATA --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
use test;
SET TIMESTAMP=1000000000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values ("Alas");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- --database --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=1;
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- --position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
use test;
SET TIMESTAMP=1000000000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values ("Alas");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- Remote --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1000000000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
drop table if exists t1,t2;
SET TIMESTAMP=1000000000;
create table t1 (word varchar(20));
@@ -63,25 +93,67 @@ insert into t1 values ("abirvalg");
SET INSERT_ID=1;
SET TIMESTAMP=1000000000;
insert into t2 values ();
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-1-1' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-2-1' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-3-1' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-4-1' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
-LOAD DATA LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/words.dat-5-1' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' (word);
+SET TIMESTAMP=1000000000;
+load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-1-2' INTO table t1;
+SET TIMESTAMP=1000000000;
+load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-2-2' INTO table t1;
+SET TIMESTAMP=1000000000;
+load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-3-2' INTO table t1;
+SET TIMESTAMP=1000000000;
+load data LOCAL INFILE 'MYSQL_TEST_DIR/var/tmp/SQL_LOAD_MB-4-2' INTO table t1;
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- Broken LOAD DATA --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
use test;
SET TIMESTAMP=1000000000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values ("Alas");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- --database --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=1;
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- --position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
use test;
SET TIMESTAMP=1000000000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values ("Alas");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+
+--- reading stdin --
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
+use test;
+SET TIMESTAMP=1108844556;
+BEGIN;
+SET TIMESTAMP=1108844555;
+insert t1 values (1);
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+use test;
+SET TIMESTAMP=1108844556;
+BEGIN;
+SET TIMESTAMP=1108844555;
+insert t1 values (1);
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
drop table t1, t2;
diff --git a/mysql-test/r/mysqlbinlog2.result b/mysql-test/r/mysqlbinlog2.result
index 3c1b85e05a1..9899fa54301 100644
--- a/mysql-test/r/mysqlbinlog2.result
+++ b/mysql-test/r/mysqlbinlog2.result
@@ -16,8 +16,13 @@ insert into t1 values(null, "f");
--- Local --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -34,12 +39,19 @@ insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- offset --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=1;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "a");
SET INSERT_ID=2;
SET TIMESTAMP=1579609942;
@@ -53,20 +65,34 @@ insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- start-position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+SET INSERT_ID=4;
use test;
SET TIMESTAMP=1579609946;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- stop-position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -77,13 +103,19 @@ insert into t1 values(null, "b");
SET INSERT_ID=3;
SET TIMESTAMP=1579609944;
insert into t1 values(null, "c");
-SET INSERT_ID=4;
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- start-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=3;
use test;
SET TIMESTAMP=1579609944;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "c");
SET INSERT_ID=4;
SET TIMESTAMP=1579609946;
@@ -91,11 +123,18 @@ insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- stop-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -103,11 +142,18 @@ insert into t1 values(null, "a");
SET INSERT_ID=2;
SET TIMESTAMP=1579609942;
insert into t1 values(null, "b");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- Local with 2 binlogs on command line --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -127,13 +173,23 @@ insert into t1 values(null, "e");
SET INSERT_ID=6;
use test;
SET TIMESTAMP=1579609943;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "f");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- offset --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=1;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "a");
SET INSERT_ID=2;
SET TIMESTAMP=1579609942;
@@ -150,12 +206,22 @@ insert into t1 values(null, "e");
SET INSERT_ID=6;
use test;
SET TIMESTAMP=1579609943;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "f");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- start-position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+SET INSERT_ID=4;
use test;
SET TIMESTAMP=1579609946;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
@@ -163,12 +229,22 @@ insert into t1 values(null, "e");
SET INSERT_ID=6;
use test;
SET TIMESTAMP=1579609943;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "f");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- stop-position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -186,12 +262,19 @@ SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
SET INSERT_ID=6;
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- start-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=3;
use test;
SET TIMESTAMP=1579609944;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "c");
SET INSERT_ID=4;
SET TIMESTAMP=1579609946;
@@ -202,12 +285,22 @@ insert into t1 values(null, "e");
SET INSERT_ID=6;
use test;
SET TIMESTAMP=1579609943;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "f");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- stop-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -215,11 +308,18 @@ insert into t1 values(null, "a");
SET INSERT_ID=2;
SET TIMESTAMP=1579609942;
insert into t1 values(null, "b");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- Remote --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -236,12 +336,19 @@ insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- offset --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=1;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "a");
SET INSERT_ID=2;
SET TIMESTAMP=1579609942;
@@ -255,20 +362,34 @@ insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- start-position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+SET INSERT_ID=4;
use test;
SET TIMESTAMP=1579609946;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- stop-position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -279,13 +400,19 @@ insert into t1 values(null, "b");
SET INSERT_ID=3;
SET TIMESTAMP=1579609944;
insert into t1 values(null, "c");
-SET INSERT_ID=4;
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- start-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=3;
use test;
SET TIMESTAMP=1579609944;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "c");
SET INSERT_ID=4;
SET TIMESTAMP=1579609946;
@@ -293,11 +420,18 @@ insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- stop-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -305,11 +439,18 @@ insert into t1 values(null, "a");
SET INSERT_ID=2;
SET TIMESTAMP=1579609942;
insert into t1 values(null, "b");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- Remote with 2 binlogs on command line --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -329,13 +470,23 @@ insert into t1 values(null, "e");
SET INSERT_ID=6;
use test;
SET TIMESTAMP=1579609943;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "f");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- offset --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=1;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "a");
SET INSERT_ID=2;
SET TIMESTAMP=1579609942;
@@ -352,12 +503,22 @@ insert into t1 values(null, "e");
SET INSERT_ID=6;
use test;
SET TIMESTAMP=1579609943;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "f");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- start-position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+SET INSERT_ID=4;
use test;
SET TIMESTAMP=1579609946;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "d");
SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
@@ -365,12 +526,22 @@ insert into t1 values(null, "e");
SET INSERT_ID=6;
use test;
SET TIMESTAMP=1579609943;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "f");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- stop-position --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -388,12 +559,19 @@ SET INSERT_ID=5;
SET TIMESTAMP=1579609946;
insert into t1 values(null, "e");
SET INSERT_ID=6;
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- start-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET INSERT_ID=3;
use test;
SET TIMESTAMP=1579609944;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "c");
SET INSERT_ID=4;
SET TIMESTAMP=1579609946;
@@ -404,12 +582,22 @@ insert into t1 values(null, "e");
SET INSERT_ID=6;
use test;
SET TIMESTAMP=1579609943;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
insert into t1 values(null, "f");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- stop-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -417,11 +605,18 @@ insert into t1 values(null, "a");
SET INSERT_ID=2;
SET TIMESTAMP=1579609942;
insert into t1 values(null, "b");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- to-last-log --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
use test;
SET TIMESTAMP=1579609942;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
create table t1 (a int auto_increment not null primary key, b char(3));
SET INSERT_ID=1;
SET TIMESTAMP=1579609942;
@@ -441,6 +636,8 @@ insert into t1 values(null, "e");
SET INSERT_ID=6;
SET TIMESTAMP=1579609943;
insert into t1 values(null, "f");
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
--- end of test --
drop table t1;
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index 69ca9486d2f..fdbdd26b00c 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -1,4 +1,6 @@
-DROP TABLE IF EXISTS t1, `"t"1`;
+DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa;
+drop database if exists mysqldump_test_db;
+drop view if exists v1;
CREATE TABLE t1(a int);
INSERT INTO t1 VALUES (1), (2);
<?xml version="1.0"?>
@@ -18,16 +20,18 @@ INSERT INTO t1 VALUES (1), (2);
</database>
</mysqldump>
DROP TABLE t1;
-CREATE TABLE t1 (a decimal(240, 20));
+CREATE TABLE t1 (a decimal(64, 20));
INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"),
("0987654321098765432109876543210987654321");
CREATE TABLE `t1` (
- `a` decimal(240,20) default NULL
+ `a` decimal(64,20) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-INSERT INTO `t1` VALUES ('1234567890123456789012345678901234567890.00000000000000000000'),('0987654321098765432109876543210987654321.00000000000000000000');
+INSERT INTO `t1` VALUES ('1234567890123456789012345678901234567890.00000000000000000000'),('987654321098765432109876543210987654321.00000000000000000000');
DROP TABLE t1;
CREATE TABLE t1 (a double);
-INSERT INTO t1 VALUES (-9e999999);
+INSERT INTO t1 VALUES ('-9e999999');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
CREATE TABLE `t1` (
`a` double default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
@@ -108,7 +112,7 @@ INSERT INTO t1 VALUES (1, "test", "tes"), (2, "TEST", "TES");
<table_structure name="t1">
<field Field="a" Type="int(11)" Null="YES" Key="" Extra="" />
<field Field="b" Type="text" Null="YES" Key="" Extra="" />
- <field Field="c" Type="char(3)" Null="YES" Key="" Extra="" />
+ <field Field="c" Type="varchar(3)" Null="YES" Key="" Extra="" />
</table_structure>
<table_data name="t1">
<row>
@@ -352,6 +356,41 @@ CREATE TABLE `t1` (
2
3
drop table t1;
+create table t1(a int);
+create view v1 as select * from t1;
+
+/*!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;
+
+
+/*!40000 ALTER TABLE `t1` DISABLE KEYS */;
+LOCK TABLES `t1` WRITE;
+UNLOCK TABLES;
+/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
+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 */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+drop view v1;
+drop table t1;
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
@@ -560,3 +599,35 @@ UNLOCK TABLES;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
DROP TABLE t1;
+CREATE TABLE t1 (a char(10));
+INSERT INTO t1 VALUES ('\'');
+
+/*!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` char(10) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+
+/*!40000 ALTER TABLE `t1` DISABLE KEYS */;
+LOCK TABLES `t1` WRITE;
+INSERT INTO `t1` VALUES ('\'');
+UNLOCK TABLES;
+/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+DROP TABLE t1;
diff --git a/mysql-test/r/mysqlshow.result b/mysql-test/r/mysqlshow.result
new file mode 100644
index 00000000000..a04a7081b34
--- /dev/null
+++ b/mysql-test/r/mysqlshow.result
@@ -0,0 +1,76 @@
+CREATE TABLE t1 (a int);
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE TABLE t2 (a int, b int);
+show tables;
+Tables_in_test
+t1
+t2
+select "--------------------" as "";
+
+--------------------
+Database: test
++--------+
+| Tables |
++--------+
+| t1 |
+| t2 |
++--------+
+select "---- -v ------------" as "";
+
+---- -v ------------
+Database: test
++--------+----------+
+| Tables | Columns |
++--------+----------+
+| t1 | 1 |
+| t2 | 2 |
++--------+----------+
+2 rows in set.
+
+select "---- -v -v ---------" as "";
+
+---- -v -v ---------
+Database: test
++--------+----------+------------+
+| Tables | Columns | Total Rows |
++--------+----------+------------+
+| t1 | 1 | 3 |
+| t2 | 2 | 0 |
++--------+----------+------------+
+2 rows in set.
+
+select "----- -t -----------" as "";
+
+----- -t -----------
+Database: test
++--------+------------+
+| Tables | table_type |
++--------+------------+
+| t1 | BASE TABLE |
+| t2 | BASE TABLE |
++--------+------------+
+select "---- -v -t ---------" as "";
+
+---- -v -t ---------
+Database: test
++--------+------------+----------+
+| Tables | table_type | Columns |
++--------+------------+----------+
+| t1 | BASE TABLE | 1 |
+| t2 | BASE TABLE | 2 |
++--------+------------+----------+
+2 rows in set.
+
+select "---- -v -v -t ------" as "";
+
+---- -v -v -t ------
+Database: test
++--------+------------+----------+------------+
+| Tables | table_type | Columns | Total Rows |
++--------+------------+----------+------------+
+| t1 | BASE TABLE | 1 | 3 |
+| t2 | BASE TABLE | 2 | 0 |
++--------+------------+----------+------------+
+2 rows in set.
+
+DROP TABLE t1, t2;
diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result
index 52ae0b58d56..6f4d84edef5 100644
--- a/mysql-test/r/ndb_alter_table.result
+++ b/mysql-test/r/ndb_alter_table.result
@@ -34,13 +34,13 @@ col5 enum('PENDING', 'ACTIVE', 'DISABLED') not null,
col6 int not null, to_be_deleted int) ENGINE=ndbcluster;
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 ndbcluster 9 Dynamic 0 0 0 NULL 0 0 1 NULL NULL NULL latin1_swedish_ci NULL
+t1 ndbcluster 10 Dynamic 0 0 # # 0 # 1 # # # latin1_swedish_ci NULL #
SET SQL_MODE=NO_AUTO_VALUE_ON_ZERO;
insert into t1 values
(0,4,3,5,"PENDING",1,7),(NULL,4,3,5,"PENDING",1,7),(31,4,3,5,"PENDING",1,7), (7,4,3,5,"PENDING",1,7), (NULL,4,3,5,"PENDING",1,7), (100,4,3,5,"PENDING",1,7), (99,4,3,5,"PENDING",1,7), (8,4,3,5,"PENDING",1,7), (NULL,4,3,5,"PENDING",1,7);
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 ndbcluster 9 Dynamic 9 0 0 NULL 0 0 102 NULL NULL NULL latin1_swedish_ci NULL
+t1 ndbcluster 10 Dynamic 9 96 # # 0 # 102 # # # latin1_swedish_ci NULL #
select * from t1 order by col1;
col1 col2 col3 col4 col5 col6 to_be_deleted
0 4 3 5 PENDING 1 7
@@ -60,7 +60,7 @@ change column col2 fourth varchar(30) not null after col3,
modify column col6 int not null first;
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 ndbcluster 9 Dynamic 9 0 0 NULL 0 0 102 NULL NULL NULL latin1_swedish_ci NULL
+t1 ndbcluster 10 Dynamic 9 152 # # 0 # 102 # # # latin1_swedish_ci NULL #
select * from t1 order by col1;
col6 col1 col3 fourth col4 col4_5 col5 col7 col8
1 0 3 4 5 PENDING 0000-00-00 00:00:00
@@ -75,7 +75,7 @@ col6 col1 col3 fourth col4 col4_5 col5 col7 col8
insert into t1 values (2, NULL,4,3,5,99,"PENDING","EXTRA",'2004-01-01 00:00:00');
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 ndbcluster 9 Dynamic 10 0 0 NULL 0 0 103 NULL NULL NULL latin1_swedish_ci NULL
+t1 ndbcluster 10 Dynamic 10 152 # # 0 # 103 # # # latin1_swedish_ci NULL #
select * from t1 order by col1;
col6 col1 col3 fourth col4 col4_5 col5 col7 col8
1 0 3 4 5 PENDING 0000-00-00 00:00:00
diff --git a/mysql-test/r/ndb_autodiscover.result b/mysql-test/r/ndb_autodiscover.result
index b7afb5918a4..27ebda36669 100644
--- a/mysql-test/r/ndb_autodiscover.result
+++ b/mysql-test/r/ndb_autodiscover.result
@@ -105,7 +105,7 @@ Handler_discover 2
SHOW CREATE TABLE t3;
Table Create Table
t3 CREATE TABLE `t3` (
- `id` int(11) NOT NULL default '0',
+ `id` int(11) NOT NULL,
`name` char(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
@@ -144,8 +144,8 @@ Handler_discover 1
flush tables;
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
-t6 MyISAM 9 Fixed 1 260 # # # 0 NULL # # NULL # NULL
-t7 ndbcluster 9 Fixed 1 0 # # # 0 NULL # # NULL # NULL
+t6 MyISAM 10 Fixed 1 260 # # # 0 NULL # # NULL # NULL #
+t7 ndbcluster 10 Fixed 1 276 # # # 0 NULL # # NULL # NULL #
show status like 'handler_discover%';
Variable_name Value
Handler_discover 2
@@ -167,6 +167,25 @@ show status like 'handler_discover%';
Variable_name Value
Handler_discover 0
drop table t4;
+ERROR 42S02: Unknown table 't4'
+create table t4(
+id int not null primary key,
+name char(27)
+) engine=ndb;
+insert into t4 values (1, "Automatic");
+select * from t4;
+id name
+1 Automatic
+select * from t4;
+ERROR 42S02: Table 'test.t4' doesn't exist
+drop table if exists t4;
+Warnings:
+Error 155 Table 'test.t4' doesn't exist
+drop table t5;
+ERROR 42S02: Unknown table 't5'
+drop table if exists t5;
+Warnings:
+Note 1051 Unknown table 't5'
flush status;
create table t4(
id int not null primary key,
@@ -353,11 +372,17 @@ drop table t1;
use test2;
drop table t2;
drop database test2;
-show databases;
-Database
-mysql
-test
use test;
+drop database if exists test_only_ndb_tables;
+create database test_only_ndb_tables;
+use test_only_ndb_tables;
+create table t1 (a int primary key) engine=ndb;
+select * from t1;
+a
+select * from t1;
+ERROR HY000: Can't lock file (errno: 4009)
+use test;
+drop database test_only_ndb_tables;
CREATE TABLE t9 (
a int NOT NULL PRIMARY KEY,
b int
diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result
index 3712fa2b5ca..6383a636cad 100644
--- a/mysql-test/r/ndb_basic.result
+++ b/mysql-test/r/ndb_basic.result
@@ -577,7 +577,7 @@ create table t1
(a bigint, b bigint, c bigint, d bigint,
primary key (a,b,c,d))
engine=ndb
-max_rows=200000000;
+max_rows=800000000;
Warnings:
Warning 1105 Ndb might have problems storing the max amount of rows specified
insert into t1 values
diff --git a/mysql-test/r/ndb_bitfield.result b/mysql-test/r/ndb_bitfield.result
new file mode 100644
index 00000000000..66ec593e195
--- /dev/null
+++ b/mysql-test/r/ndb_bitfield.result
@@ -0,0 +1,152 @@
+drop table if exists t1;
+create table t1 (
+pk1 int not null primary key,
+b bit(64)
+) engine=ndbcluster;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `pk1` int(11) NOT NULL,
+ `b` bit(64) default NULL,
+ PRIMARY KEY (`pk1`)
+) ENGINE=ndbcluster DEFAULT CHARSET=latin1
+insert into t1 values
+(0,b'1111111111111111111111111111111111111111111111111111111111111111'),
+(1,b'1000000000000000000000000000000000000000000000000000000000000000'),
+(2,b'0000000000000000000000000000000000000000000000000000000000000001'),
+(3,b'1010101010101010101010101010101010101010101010101010101010101010'),
+(4,b'0101010101010101010101010101010101010101010101010101010101010101');
+select hex(b) from t1 order by pk1;
+hex(b)
+FFFFFFFFFFFFFFFF
+8000000000000000
+1
+AAAAAAAAAAAAAAAA
+5555555555555555
+drop table t1;
+create table t1 (
+pk1 int not null primary key,
+b bit(9)
+) engine=ndbcluster;
+insert into t1 values
+(0,b'000000000'),
+(1,b'000000001'),
+(2,b'000000010'),
+(3,b'000000011'),
+(4,b'000000100');
+select hex(b) from t1 order by pk1;
+hex(b)
+0
+1
+2
+3
+4
+update t1 set b = b + b'101010101';
+select hex(b) from t1 order by pk1;
+hex(b)
+155
+156
+157
+158
+159
+drop table t1;
+create table t1 (a bit(7), b bit(9)) engine = ndbcluster;
+insert into t1 values
+(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177),
+(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380),
+(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36),
+(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499),
+(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403),
+(44, 307), (68, 454), (57, 135);
+select a+0 from t1 order by a;
+a+0
+0
+4
+5
+9
+23
+24
+28
+29
+30
+31
+34
+44
+49
+56
+57
+59
+60
+61
+68
+68
+75
+77
+78
+79
+87
+88
+94
+94
+104
+106
+108
+111
+116
+118
+119
+122
+123
+127
+select b+0 from t1 order by b;
+b+0
+36
+42
+46
+67
+83
+118
+123
+133
+135
+152
+177
+178
+188
+202
+206
+245
+280
+307
+343
+345
+349
+351
+363
+368
+368
+379
+380
+390
+398
+399
+403
+411
+411
+438
+446
+454
+468
+499
+drop table t1;
+create table t1 (
+pk1 bit(9) not null primary key,
+b int
+) engine=ndbcluster;
+ERROR HY000: Can't create table './test/t1.frm' (errno: 739)
+create table t1 (
+pk1 int not null primary key,
+b bit(9),
+key(b)
+) engine=ndbcluster;
+ERROR HY000: Can't create table './test/t1.frm' (errno: 743)
diff --git a/mysql-test/r/ndb_blob.result b/mysql-test/r/ndb_blob.result
index 6f25ec95c80..f806cf08ea9 100644
--- a/mysql-test/r/ndb_blob.result
+++ b/mysql-test/r/ndb_blob.result
@@ -134,7 +134,7 @@ insert into t1 values(2,@b2,222,@d2);
commit;
explain select * from t1 where c = 111;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref c c 4 const 10 Using where
+1 SIMPLE t1 ref c c 4 const 10
select a,length(b),substr(b,1+2*900,2),length(d),substr(d,1+3*900,3)
from t1 where c=111;
a length(b) substr(b,1+2*900,2) length(d) substr(d,1+3*900,3)
diff --git a/mysql-test/r/ndb_cache.result b/mysql-test/r/ndb_cache.result
index 714e1831267..478663b1aa1 100644
--- a/mysql-test/r/ndb_cache.result
+++ b/mysql-test/r/ndb_cache.result
@@ -1,43 +1,191 @@
+drop table if exists t1;
+set GLOBAL query_cache_type=on;
set GLOBAL query_cache_size=1355776;
reset query cache;
flush status;
-drop table if exists t1,t2;
-CREATE TABLE t1 (a int) ENGINE=ndbcluster;
-CREATE TABLE t2 (a int);
+CREATE TABLE t1 ( pk int not null primary key,
+a int, b int not null, c varchar(20)) ENGINE=ndbcluster;
+insert into t1 value (1, 2, 3, 'First row');
select * from t1;
-a
+pk a b c
+1 2 3 First row
show status like "Qcache_queries_in_cache";
Variable_name Value
-Qcache_queries_in_cache 0
+Qcache_queries_in_cache 1
show status like "Qcache_inserts";
Variable_name Value
-Qcache_inserts 0
+Qcache_inserts 1
show status like "Qcache_hits";
Variable_name Value
Qcache_hits 0
-select * from t2;
-a
+select * from t1;
+pk a b c
+1 2 3 First row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+update t1 set a=3 where pk=1;
+select * from t1;
+pk a b c
+1 3 3 First row
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+insert into t1 value (2, 7, 8, 'Second row');
+insert into t1 value (4, 5, 6, 'Fourth row');
+select * from t1 order by pk;
+pk a b c
+1 3 3 First row
+2 7 8 Second row
+4 5 6 Fourth row
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+select * from t1 order by pk;
+pk a b c
+1 3 3 First row
+2 7 8 Second row
+4 5 6 Fourth row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+select * from t1 where b=3;
+pk a b c
+1 3 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+select * from t1 where b=3;
+pk a b c
+1 3 3 First row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+delete from t1 where c='Fourth row';
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t1 where b=3;
+pk a b c
+1 3 3 First row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+use test;
+select * from t1 order by pk;
+pk a b c
+1 3 3 First row
+2 7 8 Second row
+select * from t1 where b=3;
+pk a b c
+1 3 3 First row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+update t1 set a=4 where b=3;
+use test;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t1 order by pk desc;
+pk a b c
+2 7 8 Second row
+1 4 3 First row
+select * from t1 order by pk desc;
+pk a b c
+2 7 8 Second row
+1 4 3 First row
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 7
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 5
+select * from t1 order by pk desc;
+pk a b c
+2 7 8 Second row
+1 4 3 First row
+select * from t1 order by pk desc;
+pk a b c
+2 7 8 Second row
+1 4 3 First row
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
+Qcache_inserts 7
show status like "Qcache_hits";
Variable_name Value
-Qcache_hits 0
-select * from t1;
-a
-select * from t2;
-a
+Qcache_hits 7
+begin;
+update t1 set a=5 where pk=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 7
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+select * from t1 order by pk desc;
+pk a b c
+2 7 8 Second row
+1 4 3 First row
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
+Qcache_inserts 8
show status like "Qcache_hits";
Variable_name Value
-Qcache_hits 1
-drop table t1, t2;
+Qcache_hits 7
+commit;
+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 8
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+select * from t1 order by pk desc;
+pk a b c
+2 7 8 Second row
+1 5 3 First row
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 9
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+select * from t1 order by pk desc;
+pk a b c
+2 7 8 Second row
+1 5 3 First row
+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 9
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 8
+drop table t1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
SET GLOBAL query_cache_size=0;
diff --git a/mysql-test/r/ndb_cache2.result b/mysql-test/r/ndb_cache2.result
new file mode 100644
index 00000000000..2876002f864
--- /dev/null
+++ b/mysql-test/r/ndb_cache2.result
@@ -0,0 +1,623 @@
+drop table if exists t1, t2, t3, t4, t5;
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+set GLOBAL ndb_cache_check_time=100;
+reset query cache;
+flush status;
+CREATE TABLE t1 (
+pk int not null primary key,
+a1 int,
+b1 int not null,
+c1 varchar(20)
+) ENGINE=ndb;
+CREATE TABLE t2 (
+pk int not null primary key,
+a2 int,
+b2 int not null
+) ENGINE=ndb;
+CREATE TABLE t3 (
+pk int not null primary key,
+a3 int,
+b3 int not null,
+c3 int not null,
+d3 varchar(20)
+) ENGINE=ndb;
+CREATE TABLE t4 (
+a4 int,
+b4 int not null,
+c4 char(20)
+) ENGINE=ndbcluster;
+CREATE TABLE t5 (
+pk int not null primary key,
+a5 int,
+b5 int not null,
+c5 varchar(255)
+) ENGINE=ndbcluster;
+insert into t1 value (1, 2, 3, 'First row');
+insert into t2 value (1, 2, 3);
+insert into t3 value (1, 2, 3, 4, '3 - First row');
+insert into t4 value (2, 3, '4 - First row');
+insert into t5 value (1, 2, 3, '5 - First row');
+select * from t1;
+pk a1 b1 c1
+1 2 3 First row
+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 t1;
+pk a1 b1 c1
+1 2 3 First row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+update t1 set a1=3 where pk=1;
+select * from t1;
+pk a1 b1 c1
+1 3 3 First row
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+insert into t1 value (2, 7, 8, 'Second row');
+insert into t1 value (4, 5, 6, 'Fourth row');
+select * from t1 order by pk desc;
+pk a1 b1 c1
+4 5 6 Fourth row
+2 7 8 Second row
+1 3 3 First row
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+select * from t1 order by pk desc;
+pk a1 b1 c1
+4 5 6 Fourth row
+2 7 8 Second row
+1 3 3 First row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+select * from t1 where b1=3;
+pk a1 b1 c1
+1 3 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+select * from t1 where b1=3;
+pk a1 b1 c1
+1 3 3 First row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+delete from t1 where c1='Fourth row';
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t1 where b1=3;
+pk a1 b1 c1
+1 3 3 First row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+use test;
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 3 3 First row
+select * from t1 where b1=3;
+pk a1 b1 c1
+1 3 3 First row
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+update t1 set a1=4 where b1=3;
+use test;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 4 3 First row
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 4 3 First row
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 7
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 5
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 4 3 First row
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 4 3 First row
+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 7
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+select * from t2;
+pk a2 b2
+1 2 3
+select * from t3;
+pk a3 b3 c3 d3
+1 2 3 4 3 - First row
+select * from t4;
+a4 b4 c4
+2 3 4 - First row
+select * from t5;
+pk a5 b5 c5
+1 2 3 5 - First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+flush status;
+begin;
+update t1 set a1=5 where pk=1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 4 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+commit;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 5 3 First row
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 5 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+flush status;
+begin;
+update t1 set a1=6 where pk=1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 5 3 First row
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 5 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 6 3 First row
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 6 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+commit;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 6 3 First row
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 6 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+flush status;
+begin;
+insert into t1 set pk=5, a1=6, b1=3, c1="New row";
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 where pk=5;
+pk a1 b1 c1
+select * from t1 order by pk desc;
+pk a1 b1 c1
+2 7 8 Second row
+1 6 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 where pk=5;
+pk a1 b1 c1
+5 6 3 New row
+select * from t1 where pk=5;
+pk a1 b1 c1
+5 6 3 New row
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+2 7 8 Second row
+1 6 3 First row
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+2 7 8 Second row
+1 6 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+commit;
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+2 7 8 Second row
+1 6 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+flush status;
+begin;
+delete from t1 where pk=2;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 where pk=2;
+pk a1 b1 c1
+2 7 8 Second row
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+2 7 8 Second row
+1 6 3 First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 where pk=2;
+pk a1 b1 c1
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 6 3 First row
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 6 3 First row
+select * from t1 where pk=2;
+pk a1 b1 c1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+commit;
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 6 3 First row
+select * from t1 where pk=2;
+pk a1 b1 c1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+flush status;
+begin;
+update t1 set a1=9 where pk=1;
+update t2 set a2=9 where pk=1;
+update t3 set a3=9 where pk=1;
+update t4 set a4=9 where a4=2;
+update t5 set a5=9 where pk=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
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 6 3 First row
+select * from t2;
+pk a2 b2
+1 2 3
+select * from t3;
+pk a3 b3 c3 d3
+1 2 3 4 3 - First row
+select * from t4;
+a4 b4 c4
+2 3 4 - First row
+select * from t5;
+pk a5 b5 c5
+1 2 3 5 - First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 5
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 9 3 First row
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 9 3 First row
+select * from t2;
+pk a2 b2
+1 9 3
+select * from t3;
+pk a3 b3 c3 d3
+1 9 3 4 3 - First row
+select * from t4;
+a4 b4 c4
+9 3 4 - First row
+select * from t5;
+pk a5 b5 c5
+1 9 3 5 - First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 5
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+commit;
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 9 3 First row
+select * from t2;
+pk a2 b2
+1 9 3
+select * from t3;
+pk a3 b3 c3 d3
+1 9 3 4 3 - First row
+select * from t4;
+a4 b4 c4
+9 3 4 - First row
+select * from t5;
+pk a5 b5 c5
+1 9 3 5 - First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 10
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 9 3 First row
+select * from t2;
+pk a2 b2
+1 9 3
+select * from t3;
+pk a3 b3 c3 d3
+1 9 3 4 3 - First row
+select * from t4;
+a4 b4 c4
+9 3 4 - First row
+select * from t5;
+pk a5 b5 c5
+1 9 3 5 - First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 10
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 5
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 9 3 First row
+select * from t2;
+pk a2 b2
+1 9 3
+select * from t3;
+pk a3 b3 c3 d3
+1 9 3 4 3 - First row
+select * from t4;
+a4 b4 c4
+9 3 4 - First row
+select * from t5;
+pk a5 b5 c5
+1 9 3 5 - First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 10
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 10
+select * from t1 order by pk desc;
+pk a1 b1 c1
+5 6 3 New row
+1 9 3 First row
+select * from t2;
+pk a2 b2
+1 9 3
+select * from t3;
+pk a3 b3 c3 d3
+1 9 3 4 3 - First row
+select * from t4;
+a4 b4 c4
+9 3 4 - First row
+select * from t5;
+pk a5 b5 c5
+1 9 3 5 - First row
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 5
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 10
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 15
+drop table t1, t2, t3, t4, t5;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+SET GLOBAL query_cache_size=0;
+SET GLOBAL ndb_cache_check_time=0;
diff --git a/mysql-test/r/ndb_cache_multi.result b/mysql-test/r/ndb_cache_multi.result
new file mode 100644
index 00000000000..c7135ed9e8a
--- /dev/null
+++ b/mysql-test/r/ndb_cache_multi.result
@@ -0,0 +1,72 @@
+drop table if exists t1, t2;
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+reset query cache;
+flush status;
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+reset query cache;
+flush status;
+create table t1 (a int) engine=ndbcluster;
+create table t2 (a int) engine=ndbcluster;
+insert into t1 value (2);
+insert into t2 value (3);
+select * from t1;
+a
+2
+select * from t2;
+a
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+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
+select * from t1;
+a
+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 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+update t1 set a=3 where a=2;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1;
+a
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+drop table t1, t2;
diff --git a/mysql-test/r/ndb_cache_multi2.result b/mysql-test/r/ndb_cache_multi2.result
new file mode 100644
index 00000000000..2863908a436
--- /dev/null
+++ b/mysql-test/r/ndb_cache_multi2.result
@@ -0,0 +1,82 @@
+drop table if exists t1, t2;
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+set GLOBAL ndb_cache_check_time=1;
+reset query cache;
+flush status;
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+set GLOBAL ndb_cache_check_time=1;
+reset query cache;
+flush status;
+create table t1 (a int) engine=ndbcluster;
+create table t2 (a int) engine=ndbcluster;
+insert into t1 value (2);
+insert into t2 value (3);
+select * from t1;
+a
+2
+select * from t2;
+a
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+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
+select * from t1;
+a
+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 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+update t1 set a=3 where a=2;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+select * from t1;
+a
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+drop table t1, t2;
+set GLOBAL query_cache_size=0;
+set GLOBAL ndb_cache_check_time=0;
+reset query cache;
+flush status;
+set GLOBAL query_cache_size=0;
+set GLOBAL ndb_cache_check_time=0;
+reset query cache;
+flush status;
diff --git a/mysql-test/r/ndb_charset.result b/mysql-test/r/ndb_charset.result
index 00bc36a7c0d..500b0497890 100644
--- a/mysql-test/r/ndb_charset.result
+++ b/mysql-test/r/ndb_charset.result
@@ -47,6 +47,40 @@ a
aAa
drop table t1;
create table t1 (
+a varchar(20) character set latin1 collate latin1_swedish_ci primary key
+) engine=ndb;
+insert into t1 values ('A'),('b '),('C '),('d '),('E'),('f');
+insert into t1 values('b');
+ERROR 23000: Duplicate entry 'b' for key 1
+insert into t1 values('a ');
+ERROR 23000: Duplicate entry 'a ' for key 1
+select a,length(a) from t1 order by a;
+a length(a)
+A 1
+b 2
+C 3
+d 7
+E 1
+f 1
+select a,length(a) from t1 order by a desc;
+a length(a)
+f 1
+E 1
+d 7
+C 3
+b 2
+A 1
+select * from t1 where a = 'a';
+a
+A
+select * from t1 where a = 'a ';
+a
+A
+select * from t1 where a = 'd';
+a
+d
+drop table t1;
+create table t1 (
p int primary key,
a char(3) character set latin1 collate latin1_bin not null,
unique key(a)
@@ -99,6 +133,42 @@ p a
drop table t1;
create table t1 (
p int primary key,
+a varchar(20) character set latin1 collate latin1_swedish_ci not null,
+unique key(a)
+) engine=ndb;
+insert into t1 values (1,'A'),(2,'b '),(3,'C '),(4,'d '),(5,'E'),(6,'f');
+insert into t1 values(99,'b');
+ERROR 23000: Duplicate entry '99' for key 1
+insert into t1 values(99,'a ');
+ERROR 23000: Duplicate entry '99' for key 1
+select a,length(a) from t1 order by a;
+a length(a)
+A 1
+b 2
+C 3
+d 7
+E 1
+f 1
+select a,length(a) from t1 order by a desc;
+a length(a)
+f 1
+E 1
+d 7
+C 3
+b 2
+A 1
+select * from t1 where a = 'a';
+p a
+1 A
+select * from t1 where a = 'a ';
+p a
+1 A
+select * from t1 where a = 'd';
+p a
+4 d
+drop table t1;
+create table t1 (
+p int primary key,
a char(3) character set latin1 collate latin1_bin not null,
index(a)
) engine=ndb;
@@ -190,7 +260,52 @@ p a
6 AAA
drop table t1;
create table t1 (
-a varchar(10) primary key
+p int primary key,
+a varchar(20) character set latin1 collate latin1_swedish_ci not null,
+index(a, p)
+) engine=ndb;
+insert into t1 values (1,'A'),(2,'b '),(3,'C '),(4,'d '),(5,'E'),(6,'f');
+insert into t1 values (7,'a'),(8,'B '),(9,'c '),(10,'D'),(11,'e'),(12,'F ');
+select p,a,length(a) from t1 order by a, p;
+p a length(a)
+1 A 1
+7 a 1
+2 b 2
+8 B 2
+3 C 3
+9 c 3
+4 d 7
+10 D 1
+5 E 1
+11 e 1
+6 f 1
+12 F 3
+select * from t1 where a = 'a ' order by a desc, p desc;
+p a
+7 a
+1 A
+select * from t1 where a >= 'D' order by a, p;
+p a
+4 d
+10 D
+5 E
+11 e
+6 f
+12 F
+select * from t1 where a < 'D' order by a, p;
+p a
+1 A
+7 a
+2 b
+8 B
+3 C
+9 c
+select count(*) from t1 x, t1 y, t1 z where x.a = y.a and y.a = z.a;
+count(*)
+48
+drop table t1;
+create table t1 (
+a char(10) primary key
) engine=ndb;
insert into t1 values ('jonas % ');
replace into t1 values ('jonas % ');
diff --git a/mysql-test/r/ndb_condition_pushdown.result b/mysql-test/r/ndb_condition_pushdown.result
new file mode 100644
index 00000000000..7f769154212
--- /dev/null
+++ b/mysql-test/r/ndb_condition_pushdown.result
@@ -0,0 +1,1143 @@
+DROP TABLE IF EXISTS t1,t2;
+CREATE TABLE t1 (
+auto int(5) unsigned NOT NULL auto_increment,
+string char(10),
+vstring varchar(10),
+bin binary(7),
+vbin varbinary(7),
+tiny tinyint(4) DEFAULT '0' NOT NULL ,
+short smallint(6) DEFAULT '1' NOT NULL ,
+medium mediumint(8) DEFAULT '0' NOT NULL,
+long_int int(11) DEFAULT '0' NOT NULL,
+longlong bigint(13) DEFAULT '0' NOT NULL,
+real_float float(13,1) DEFAULT 0.0 NOT NULL,
+real_double double(16,4),
+real_decimal decimal(16,4),
+utiny tinyint(3) unsigned DEFAULT '0' NOT NULL,
+ushort smallint(5) unsigned zerofill DEFAULT '00000' NOT NULL,
+umedium mediumint(8) unsigned DEFAULT '0' NOT NULL,
+ulong int(11) unsigned DEFAULT '0' NOT NULL,
+ulonglong bigint(13) unsigned DEFAULT '0' NOT NULL,
+bits bit(3),
+options enum('zero','one','two','three','four') not null,
+flags set('zero','one','two','three','four') not null,
+date_field date,
+year_field year,
+time_field time,
+date_time datetime,
+time_stamp timestamp,
+PRIMARY KEY (auto)
+) engine=ndb;
+insert into t1 values
+(NULL,"aaaa","aaaa",0xAAAA,0xAAAA,-1,-1,-1,-1,-1,1.1,1.1,1.1,1,1,1,1,1,
+b'001','one','one',
+'1901-01-01','1901',
+'01:01:01','1901-01-01 01:01:01',NULL),
+(NULL,"bbbb","bbbb",0xBBBB,0xBBBB,-2,-2,-2,-2,-2,2.2,2.2,2.2,2,2,2,2,2,
+b'010','two','one,two',
+'1902-02-02','1902',
+'02:02:02','1902-02-02 02:02:02',NULL),
+(NULL,"cccc","cccc",0xCCCC,0xCCCC,-3,-3,-3,-3,-3,3.3,3.3,3.3,3,3,3,3,3,
+b'011','three','one,two,three',
+'1903-03-03','1903',
+'03:03:03','1903-03-03 03:03:03',NULL),
+(NULL,"dddd","dddd",0xDDDD,0xDDDD,-4,-4,-4,-4,-4,4.4,4.4,4.4,4,4,4,4,4,
+b'100','four','one,two,three,four',
+'1904-04-04','1904',
+'04:04:04','1904-04-04 04:04:04',NULL);
+CREATE TABLE t2 (pk1 int unsigned NOT NULL PRIMARY KEY, attr1 int unsigned NOT NULL, attr2 int unsigned, attr3 VARCHAR(10) ) ENGINE=ndbcluster;
+insert into t2 values (0,0,0, "a"),(1,1,1,"b"),(2,2,NULL,NULL),(3,3,3,"d"),(4,4,4,"e"),(5,5,5,"f");
+CREATE TABLE t3 (pk1 int unsigned NOT NULL PRIMARY KEY, attr1 int unsigned NOT NULL, attr2 bigint unsigned, attr3 tinyint unsigned, attr4 VARCHAR(10) ) ENGINE=ndbcluster;
+insert into t3 values (0,0,0,0,"a"),(1,1,9223372036854775803,1,"b"),(2,2,9223372036854775804,2,"c"),(3,3,9223372036854775805,3,"d"),(4,4,9223372036854775806,4,"e"),(5,5,9223372036854775807,5,"f");
+CREATE TABLE t4 (pk1 int unsigned NOT NULL PRIMARY KEY, attr1 int unsigned NOT NULL, attr2 bigint unsigned, attr3 tinyint unsigned, attr4 VARCHAR(10) , KEY (attr1)) ENGINE=ndbcluster;
+insert into t4 values (0,0,0,0,"a"),(1,1,9223372036854775803,1,"b"),(2,2,9223372036854775804,2,"c"),(3,3,9223372036854775805,3,"d"),(4,4,9223372036854775806,4,"e"),(5,5,9223372036854775807,5,"f");
+set @old_ecpd = @@session.engine_condition_pushdown;
+set engine_condition_pushdown = off;
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+bits = b'001' and
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+auto
+1
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+bits != b'001' and
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+auto
+2
+3
+4
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+bits > b'001' and
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+auto
+2
+3
+4
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+bits >= b'001' and
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+auto
+1
+2
+3
+4
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+bits < b'100' and
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+auto
+1
+2
+3
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 and
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+bits <= b'100' and
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+auto
+1
+2
+3
+4
+select auto from t1 where
+string like "b%" and
+vstring like "b%" and
+bin like concat(0xBB, '%') and
+vbin like concat(0xBB, '%')
+order by auto;
+auto
+2
+select auto from t1 where
+string not like "b%" and
+vstring not like "b%" and
+bin not like concat(0xBB, '%') and
+vbin not like concat(0xBB, '%')
+order by auto;
+auto
+1
+3
+4
+select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
+pk1 attr1 attr2 attr3
+2 2 NULL NULL
+3 3 3 d
+select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
+pk1 attr1 attr2 attr3
+3 3 3 d
+4 4 4 e
+5 5 5 f
+select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
+pk1 attr1 attr2 attr3 attr4
+2 2 9223372036854775804 2 c
+4 4 9223372036854775806 4 e
+5 5 9223372036854775807 5 f
+select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
+pk1 attr1 attr2 attr3 pk1 attr1 attr2 attr3 attr4
+0 0 0 a 0 0 0 0 a
+select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
+pk1 attr1 attr2 attr3 attr4
+2 2 9223372036854775804 2 c
+4 4 9223372036854775806 4 e
+select * from t3,t4 where t4.attr1 > 1 and t4.attr2 = t3.attr2 and t4.attr3 < 5 order by t4.pk1;
+pk1 attr1 attr2 attr3 attr4 pk1 attr1 attr2 attr3 attr4
+2 2 9223372036854775804 2 c 2 2 9223372036854775804 2 c
+3 3 9223372036854775805 3 d 3 3 9223372036854775805 3 d
+4 4 9223372036854775806 4 e 4 4 9223372036854775806 4 e
+set engine_condition_pushdown = on;
+explain
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where with pushed condition; Using filesort
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+auto
+1
+explain
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+/* bits != b'001' and */
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where with pushed condition; Using filesort
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+/* bits != b'001' and */
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+auto
+2
+3
+4
+explain
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+/* bits > b'001' and */
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where with pushed condition; Using filesort
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+/* bits > b'001' and */
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+auto
+2
+3
+4
+explain
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+/* bits >= b'001' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where with pushed condition; Using filesort
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+/* bits >= b'001' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+auto
+1
+2
+3
+4
+explain
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+/* bits < b'100' and */
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where with pushed condition; Using filesort
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+/* bits < b'100' and */
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+auto
+1
+2
+3
+explain
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 - 1 + 1 and /* Checking function composition */
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+/* bits <= b'100' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where with pushed condition; Using filesort
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 - 1 + 1 and /* Checking function composition */
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+/* bits <= b'100' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+auto
+1
+2
+3
+4
+create index medium_index on t1(medium);
+explain
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref medium_index medium_index 3 const 10 Using where with pushed condition; Using filesort
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+auto
+1
+explain
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+/* bits != b'001' and */
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range medium_index medium_index 3 NULL 20 Using where with pushed condition; Using filesort
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+/* bits != b'001' and */
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+auto
+2
+3
+4
+explain
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+/* bits > b'001' and */
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range medium_index medium_index 3 NULL 10 Using where with pushed condition; Using filesort
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+/* bits > b'001' and */
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+auto
+2
+3
+4
+explain
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+/* bits >= b'001' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range medium_index medium_index 3 NULL 10 Using where with pushed condition; Using filesort
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+/* bits >= b'001' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+auto
+1
+2
+3
+4
+explain
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+/* bits < b'100' and */
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range medium_index medium_index 3 NULL 10 Using where with pushed condition; Using filesort
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+/* bits < b'100' and */
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+auto
+1
+2
+3
+explain
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 - 1 + 1 and /* Checking function composition */
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+/* bits <= b'100' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range medium_index medium_index 3 NULL 10 Using where with pushed condition; Using filesort
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 - 1 + 1 and /* Checking function composition */
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+/* bits <= b'100' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+auto
+1
+2
+3
+4
+explain
+select auto from t1 where
+string like "b%" and
+vstring like "b%" and
+bin like concat(0xBB, '%') and
+vbin like concat(0xBB, '%')
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where with pushed condition; Using filesort
+select auto from t1 where
+string like "b%" and
+vstring like "b%" and
+bin like concat(0xBB, '%') and
+vbin like concat(0xBB, '%')
+order by auto;
+auto
+2
+explain
+select auto from t1 where
+string not like "b%" and
+vstring not like "b%" and
+bin not like concat(0xBB, '%') and
+vbin not like concat(0xBB, '%')
+order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where with pushed condition; Using filesort
+select auto from t1 where
+string not like "b%" and
+vstring not like "b%" and
+bin not like concat(0xBB, '%') and
+vbin not like concat(0xBB, '%')
+order by auto;
+auto
+1
+3
+4
+update t1
+set medium = 17
+where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01';
+delete from t1
+where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = 17 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01';
+select count(*) from t1;
+count(*)
+3
+explain
+select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 6 Using where with pushed condition; Using filesort
+select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
+pk1 attr1 attr2 attr3
+2 2 NULL NULL
+3 3 3 d
+explain
+select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where with pushed condition; Using filesort
+select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
+pk1 attr1 attr2 attr3
+3 3 3 d
+4 4 4 e
+5 5 5 f
+explain
+select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t3 ALL NULL NULL NULL NULL 6 Using where with pushed condition; Using filesort
+select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
+pk1 attr1 attr2 attr3 attr4
+2 2 9223372036854775804 2 c
+4 4 9223372036854775806 4 e
+5 5 9223372036854775807 5 f
+explain
+select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where with pushed condition; Using temporary; Using filesort
+1 SIMPLE t3 ALL NULL NULL NULL NULL 6 Using where with pushed condition
+select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
+pk1 attr1 attr2 attr3 pk1 attr1 attr2 attr3 attr4
+0 0 0 a 0 0 0 0 a
+explain
+select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 range attr1 attr1 4 NULL 10 Using where with pushed condition; Using filesort
+select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
+pk1 attr1 attr2 attr3 attr4
+2 2 9223372036854775804 2 c
+4 4 9223372036854775806 4 e
+explain
+select * from t3,t4 where t4.attr1 > 1 and t4.attr2 = t3.attr2 and t4.attr3 < 5 order by t4.pk1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t4 range attr1 attr1 4 NULL 10 Using where with pushed condition; Using temporary; Using filesort
+1 SIMPLE t3 ALL NULL NULL NULL NULL 6 Using where
+select * from t3,t4 where t4.attr1 > 1 and t4.attr2 = t3.attr2 and t4.attr3 < 5 order by t4.pk1;
+pk1 attr1 attr2 attr3 attr4 pk1 attr1 attr2 attr3 attr4
+2 2 9223372036854775804 2 c 2 2 9223372036854775804 2 c
+3 3 9223372036854775805 3 d 3 3 9223372036854775805 3 d
+4 4 9223372036854775806 4 e 4 4 9223372036854775806 4 e
+explain
+select auto from t1 where string = "aaaa" collate latin1_general_ci order by auto;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where; Using filesort
+explain
+select * from t2 where (attr1 < 2) = (attr2 < 2) order by pk1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Using filesort
+set engine_condition_pushdown = @old_ecpd;
+DROP TABLE t1,t2,t3,t4;
diff --git a/mysql-test/r/ndb_default_cluster.require b/mysql-test/r/ndb_default_cluster.require
new file mode 100644
index 00000000000..aa4988cdca3
--- /dev/null
+++ b/mysql-test/r/ndb_default_cluster.require
@@ -0,0 +1,2 @@
+Variable_name Value
+Ndb_connected_host localhost
diff --git a/mysql-test/r/ndb_grant.result b/mysql-test/r/ndb_grant.result
index 6583065a0c4..6192a7cace5 100644
--- a/mysql-test/r/ndb_grant.result
+++ b/mysql-test/r/ndb_grant.result
@@ -31,8 +31,8 @@ begin;
grant delete on mysqltest.* to mysqltest_1@localhost;
commit;
select * from mysql.user where user="mysqltest_1";
-Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections
-localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0
+Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections
+localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N 0 0 0
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA'
@@ -99,7 +99,7 @@ commit;
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
-GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION
+GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES, CREATE VIEW, SHOW VIEW ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION
begin;
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
commit;
@@ -271,23 +271,26 @@ grant select on test.t1 to drop_user2@localhost;
grant select on test.* to drop_user3@localhost;
grant select on *.* to drop_user4@localhost;
commit;
+flush privileges;
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
-ERROR HY000: Can't drop one or more of the requested users
begin;
revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost,
drop_user3@localhost, drop_user4@localhost;
+ERROR HY000: Can't revoke all privileges, grant for one or more of the requested users
commit;
+flush privileges;
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
drop table t1;
begin;
grant usage on *.* to mysqltest_1@localhost identified by "password";
-grant select, update, insert on test.* to mysqltest@localhost;
+grant select, update, insert on test.* to mysqltest_1@localhost;
commit;
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' IDENTIFIED BY PASSWORD '*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19'
+GRANT SELECT, INSERT, UPDATE ON `test`.* TO 'mysqltest_1'@'localhost'
drop user mysqltest_1@localhost;
SET NAMES koi8r;
CREATE DATABASE ÂÄ;
@@ -396,6 +399,31 @@ DROP DATABASE testdb7;
DROP DATABASE testdb8;
DROP DATABASE testdb9;
DROP DATABASE testdb10;
+SHOW PRIVILEGES;
+Privilege Context Comment
+Alter Tables To alter the table
+Create Databases,Tables,Indexes To create new databases and tables
+Create temporary tables Databases To use CREATE TEMPORARY TABLE
+Create view Tables To create new views
+Delete Tables To delete existing rows
+Drop Databases,Tables To drop databases, tables, and views
+File File access on server To read and write files on the server
+Grant option Databases,Tables To give to other users those privileges you possess
+Index Tables To create or drop indexes
+Insert Tables To insert data into tables
+Lock tables Databases To use LOCK TABLES (together with SELECT privilege)
+Process Server Admin To view the plain text of currently executing queries
+References Databases,Tables To have references on tables
+Reload Server Admin To reload or refresh tables, logs and privileges
+Replication client Server Admin To ask where the slave or master servers are
+Replication slave Server Admin To read binary log events from the master
+Select Tables To retrieve rows from table
+Show databases Server Admin To see all databases with SHOW DATABASES
+Show view Tables To see views with SHOW CREATE VIEW
+Shutdown Server Admin To shut down the server
+Super Server Admin To use KILL thread, SET GLOBAL, CHANGE MASTER, etc.
+Update Tables To update existing rows
+Usage Server Admin No privileges - allow connect only
use mysql;
alter table columns_priv engine=myisam;
alter table db engine=myisam;
diff --git a/mysql-test/r/ndb_index_ordered.result b/mysql-test/r/ndb_index_ordered.result
index f5794d477f3..212c843cc44 100644
--- a/mysql-test/r/ndb_index_ordered.result
+++ b/mysql-test/r/ndb_index_ordered.result
@@ -275,6 +275,115 @@ a b c
1 1 1
4 4 NULL
drop table t1;
+create table t1 (
+a int unsigned primary key,
+b int unsigned,
+c char(10),
+key bc (b, c)
+) engine=ndb;
+insert into t1 values(1,1,'a'),(2,2,'b'),(3,3,'c'),(4,4,'d'),(5,5,'e');
+insert into t1 select a*7,10*b,'f' from t1;
+insert into t1 select a*13,10*b,'g' from t1;
+insert into t1 select a*17,10*b,'h' from t1;
+insert into t1 select a*19,10*b,'i' from t1;
+insert into t1 select a*23,10*b,'j' from t1;
+insert into t1 select a*29,10*b,'k' from t1;
+select b, c from t1 where b <= 10 and c <'f' order by b, c;
+b c
+1 a
+2 b
+3 c
+4 d
+5 e
+select b, c from t1 where b <= 10 and c <'f' order by b desc, c desc;
+b c
+5 e
+4 d
+3 c
+2 b
+1 a
+select b, c from t1 where b=4000 and c<'k' order by b, c;
+b c
+4000 h
+4000 i
+4000 i
+4000 i
+4000 j
+4000 j
+4000 j
+4000 j
+4000 j
+4000 j
+select b, c from t1 where b=4000 and c<'k' order by b desc, c desc;
+b c
+4000 j
+4000 j
+4000 j
+4000 j
+4000 j
+4000 j
+4000 i
+4000 i
+4000 i
+4000 h
+select b, c from t1 where 1000<=b and b<=100000 and c<'j' order by b, c;
+b c
+1000 h
+1000 i
+1000 i
+1000 i
+2000 h
+2000 i
+2000 i
+2000 i
+3000 h
+3000 i
+3000 i
+3000 i
+4000 h
+4000 i
+4000 i
+4000 i
+5000 h
+5000 i
+5000 i
+5000 i
+10000 i
+20000 i
+30000 i
+40000 i
+50000 i
+select b, c from t1 where 1000<=b and b<=100000 and c<'j' order by b desc, c desc;
+b c
+50000 i
+40000 i
+30000 i
+20000 i
+10000 i
+5000 i
+5000 i
+5000 i
+5000 h
+4000 i
+4000 i
+4000 i
+4000 h
+3000 i
+3000 i
+3000 i
+3000 h
+2000 i
+2000 i
+2000 i
+2000 h
+1000 i
+1000 i
+1000 i
+1000 h
+select min(b), max(b) from t1;
+min(b) max(b)
+1 5000000
+drop table t1;
CREATE TABLE test1 (
SubscrID int(11) NOT NULL auto_increment,
UsrID int(11) NOT NULL default '0',
diff --git a/mysql-test/r/ndb_index_unique.result b/mysql-test/r/ndb_index_unique.result
index 598b9dcccf7..1401ae26ddb 100644
--- a/mysql-test/r/ndb_index_unique.result
+++ b/mysql-test/r/ndb_index_unique.result
@@ -1,4 +1,4 @@
-drop table if exists t1, t2, t3, t4, t5, t6, t7;
+drop table if exists t1, t2, t3, t4, t5, t6, t7, t8;
CREATE TABLE t1 (
a int unsigned NOT NULL PRIMARY KEY,
b int unsigned not null,
@@ -248,8 +248,8 @@ INSERT INTO t3 VALUES (1,'V1',NULL);
CREATE TABLE t4 (
uid bigint(20) unsigned NOT NULL default '0',
gid bigint(20) unsigned NOT NULL,
-rid bigint(20) unsigned NOT NULL default '-1',
-cid bigint(20) unsigned NOT NULL default '-1',
+rid bigint(20) unsigned NOT NULL,
+cid bigint(20) unsigned NOT NULL,
UNIQUE KEY m (uid,gid,rid,cid)
) engine=ndbcluster;
INSERT INTO t4 VALUES (1,1,2,4);
@@ -275,8 +275,8 @@ CREATE TABLE t7 (
mid bigint(20) unsigned NOT NULL PRIMARY KEY,
uid bigint(20) unsigned NOT NULL default '0',
gid bigint(20) unsigned NOT NULL,
-rid bigint(20) unsigned NOT NULL default '-1',
-cid bigint(20) unsigned NOT NULL default '-1',
+rid bigint(20) unsigned NOT NULL,
+cid bigint(20) unsigned NOT NULL,
UNIQUE KEY m (uid,gid,rid,cid)
) engine=ndbcluster;
INSERT INTO t7 VALUES(1, 1, 1, 1, 1);
diff --git a/mysql-test/r/ndb_read_multi_range.result b/mysql-test/r/ndb_read_multi_range.result
new file mode 100644
index 00000000000..f42ac394b6c
--- /dev/null
+++ b/mysql-test/r/ndb_read_multi_range.result
@@ -0,0 +1,265 @@
+DROP TABLE IF EXISTS t1, r1;
+create table t1 (
+a int primary key,
+b int not null,
+c int not null,
+index(b), unique index using hash(c)
+) engine = ndb;
+insert into t1 values
+(1,2,1),(2,3,2),(3,4,3),(4,5,4),
+(5,2,12),(6,3,11),(7,4,10),(8,5,9),
+(9,2,8),(10,3,7),(11,4,6),(12,5,5);
+create table r1 as select * from t1 where a in (2,8,12);
+select * from r1 order by a;
+a b c
+2 3 2
+8 5 9
+12 5 5
+drop table r1;
+create table r1 as select * from t1 where b in (1,2,5);
+select * from r1 order by a;
+a b c
+1 2 1
+4 5 4
+5 2 12
+8 5 9
+9 2 8
+12 5 5
+drop table r1;
+create table r1 as select * from t1 where c in (2,8,12);
+select * from r1 order by a;
+a b c
+2 3 2
+5 2 12
+9 2 8
+drop table r1;
+create table r1 as select * from t1 where a in (2,8) or (a > 11) or (a <= 1);
+select * from r1 order by a;
+a b c
+1 2 1
+2 3 2
+8 5 9
+12 5 5
+drop table r1;
+create table r1 as select * from t1 where a in (33,8,12);
+select * from r1 order by a;
+a b c
+8 5 9
+12 5 5
+drop table r1;
+create table r1 as select * from t1 where a in (2,33,8,12,34);
+select * from r1 order by a;
+a b c
+2 3 2
+8 5 9
+12 5 5
+drop table r1;
+create table r1 as select * from t1 where b in (1,33,5);
+select * from r1 order by a;
+a b c
+4 5 4
+8 5 9
+12 5 5
+drop table r1;
+select * from t1 where b in (1,33,5) order by a;
+a b c
+4 5 4
+8 5 9
+12 5 5
+create table r1 as select * from t1 where b in (45,1,33,5,44);
+select * from r1 order by a;
+a b c
+4 5 4
+8 5 9
+12 5 5
+drop table r1;
+select * from t1 where b in (45,22) order by a;
+a b c
+create table r1 as select * from t1 where c in (2,8,33);
+select * from r1 order by a;
+a b c
+2 3 2
+9 2 8
+drop table r1;
+create table r1 as select * from t1 where c in (13,2,8,33,12);
+select * from r1 order by a;
+a b c
+2 3 2
+5 2 12
+9 2 8
+drop table r1;
+select * from t1 where a in (33,8,12) order by a;
+a b c
+8 5 9
+12 5 5
+select * from t1 where a in (33,34,35) order by a;
+a b c
+select * from t1 where a in (2,8) or (a > 11) or (a <= 1) order by a;
+a b c
+1 2 1
+2 3 2
+8 5 9
+12 5 5
+select * from t1 where b in (6,7) or (b <= 5) or (b >= 10) order by b,a;
+a b c
+1 2 1
+5 2 12
+9 2 8
+2 3 2
+6 3 11
+10 3 7
+3 4 3
+7 4 10
+11 4 6
+4 5 4
+8 5 9
+12 5 5
+select * from t1 where c in (13,2,8,33,12) order by c,a;
+a b c
+2 3 2
+9 2 8
+5 2 12
+drop table t1;
+create table t1 (
+a int not null,
+b int not null,
+c int not null,
+d int not null,
+e int not null,
+primary key (a,b,c,d), index (d)
+) engine = ndb;
+insert into t1 values
+(1,2,1,1,1),(2,3,2,3,1),(3,4,3,1,1),(4,5,4,7,1),
+(5,2,12,12,1),(6,3,11,1,1),(7,4,10,3,1),(8,5,9,5,1),
+(9,2,8,6,1),(10,3,7,5,1),(11,4,6,3,1),(12,5,5,2,1),
+(1,2,1,2,1),
+(1,2,1,3,1),
+(1,2,1,4,1),
+(1,2,1,5,1);
+create table r1 as select * from t1
+where a=1 and b=2 and c=1 and d in (1,4,3,2);
+select * from r1 order by a,b,c,d;
+a b c d e
+1 2 1 1 1
+1 2 1 2 1
+1 2 1 3 1
+1 2 1 4 1
+drop table r1;
+update t1 set e = 100
+where d in (12,6,7);
+select * from t1 where d in (12,6,7) order by a,b,c,d;
+a b c d e
+4 5 4 7 100
+5 2 12 12 100
+9 2 8 6 100
+select * from t1 where d not in (12,6,7) and e = 100;
+a b c d e
+update t1
+set e = 101
+where a=1 and
+b=2 and
+c=1 and
+d in (1,4,3,2);
+select *
+from t1
+where a=1 and b=2 and c=1 and d in (1,4,3,2)
+order by a,b,c,d;
+a b c d e
+1 2 1 1 101
+1 2 1 2 101
+1 2 1 3 101
+1 2 1 4 101
+select *
+from t1
+where not (a=1 and b=2 and c=1 and d in (1,4,3,2))
+and e=101;
+a b c d e
+update t1
+set e =
+(case d
+when 12 then 112
+when 6 then 106
+when 7 then 107
+end)
+where d in (12,6,7);
+select * from t1 where d in (12,6,7) order by a,b,c,d;
+a b c d e
+4 5 4 7 107
+5 2 12 12 112
+9 2 8 6 106
+update t1
+set e =
+(case d
+when 1 then 111
+when 4 then 444
+when 3 then 333
+when 2 then 222
+end)
+where a=1 and
+b=2 and
+c=1 and
+d in (1,4,3,2);
+select *
+from t1
+where a=1 and b=2 and c=1 and d in (1,4,3,2)
+order by a,b,c,d;
+a b c d e
+1 2 1 1 111
+1 2 1 2 222
+1 2 1 3 333
+1 2 1 4 444
+delete from t1 where d in (12,6,7);
+select * from t1 where d in (12,6,7);
+a b c d e
+drop table t1;
+create table t1 (
+a int not null primary key,
+b int,
+c int,
+d int,
+unique index (b),
+index(c)
+) engine = ndb;
+insert into t1 values
+(1,null,1,1),
+(2,2,2,2),
+(3,null,null,3),
+(4,4,null,4),
+(5,null,5,null),
+(6,6,6,null),
+(7,null,null,null),
+(8,8,null,null),
+(9,null,9,9),
+(10,10,10,10),
+(11,null,null,11),
+(12,12,null,12),
+(13,null,13,null),
+(14,14,14,null),
+(15,null,null,null),
+(16,16,null,null);
+create table t2 as select * from t1 where a in (5,6,7,8,9,10);
+select * from t2 order by a;
+a b c d
+5 NULL 5 NULL
+6 6 6 NULL
+7 NULL NULL NULL
+8 8 NULL NULL
+9 NULL 9 9
+10 10 10 10
+drop table t2;
+create table t2 as select * from t1 where b in (5,6,7,8,9,10);
+select * from t2 order by a;
+a b c d
+6 6 6 NULL
+8 8 NULL NULL
+10 10 10 10
+drop table t2;
+create table t2 as select * from t1 where c in (5,6,7,8,9,10);
+select * from t2 order by a;
+a b c d
+5 NULL 5 NULL
+6 6 6 NULL
+9 NULL 9 9
+10 10 10 10
+drop table t2;
+drop table t1;
diff --git a/mysql-test/r/ndb_types.result b/mysql-test/r/ndb_types.result
index 5afa9c57e38..37ce7732f65 100644
--- a/mysql-test/r/ndb_types.result
+++ b/mysql-test/r/ndb_types.result
@@ -12,11 +12,13 @@ long_int int(11) DEFAULT '0' NOT NULL,
longlong bigint(13) DEFAULT '0' NOT NULL,
real_float float(13,1) DEFAULT 0.0 NOT NULL,
real_double double(16,4),
+real_decimal decimal(16,4),
utiny tinyint(3) unsigned DEFAULT '0' NOT NULL,
ushort smallint(5) unsigned zerofill DEFAULT '00000' NOT NULL,
umedium mediumint(8) unsigned DEFAULT '0' NOT NULL,
ulong int(11) unsigned DEFAULT '0' NOT NULL,
ulonglong bigint(13) unsigned DEFAULT '0' NOT NULL,
+bits bit(3),
options enum('one','two','tree') not null,
flags set('one','two','tree') not null,
date_field date,
@@ -40,32 +42,33 @@ KEY (options,flags)
set @now = now();
insert into t1
(string,vstring,bin,vbin,tiny,short,medium,long_int,longlong,
-real_float,real_double, utiny, ushort, umedium,ulong,ulonglong,
-options,flags,date_field,year_field,time_field,date_time)
+real_float,real_double, real_decimal,utiny, ushort, umedium,ulong,ulonglong,
+bits,options,flags,date_field,year_field,time_field,date_time)
values
-("aaaa","aaaa",0xAAAA,0xAAAA,-1,-1,-1,-1,-1,1.1,1.1,1,1,1,1,1,
-'one','one', '1901-01-01','1901','01:01:01','1901-01-01 01:01:01');
+("aaaa","aaaa",0xAAAA,0xAAAA,-1,-1,-1,-1,-1,1.1,1.1,1.1,1,1,1,1,1,
+b'001','one','one', '1901-01-01','1901','01:01:01','1901-01-01 01:01:01');
select auto,string,vstring,bin,vbin,tiny,short,medium,long_int,longlong,
-real_float,real_double, utiny, ushort, umedium,ulong,ulonglong,
-options,flags,date_field,year_field,time_field,date_time
+real_float,real_double,real_decimal,utiny,ushort,umedium,ulong,ulonglong,
+bits,options,flags,date_field,year_field,time_field,date_time
from t1;
-auto string vstring bin vbin tiny short medium long_int longlong real_float real_double utiny ushort umedium ulong ulonglong options flags date_field year_field time_field date_time
-1 aaaa aaaa ªª ªª -1 -1 -1 -1 -1 1.1 1.1000 1 00001 1 1 1 one one 1901-01-01 1901 01:01:01 1901-01-01 01:01:01
+auto string vstring bin vbin tiny short medium long_int longlong real_float real_double real_decimal utiny ushort umedium ulong ulonglong bits options flags date_field year_field time_field date_time
+1 aaaa aaaa ªª ªª -1 -1 -1 -1 -1 1.1 1.1000 1.1000 1 00001 1 1 1  one one 1901-01-01 1901 01:01:01 1901-01-01 01:01:01
select time_stamp>@now from t1;
time_stamp>@now
1
set @now = now();
update t1 set string="bbbb",vstring="bbbb",bin=0xBBBB,vbin=0xBBBB,
tiny=-2,short=-2,medium=-2,long_int=-2,longlong=-2,real_float=2.2,
-real_double=2.2,utiny=2,ushort=2,umedium=2,ulong=2,ulonglong=2,
+real_double=2.2,real_decimal=2.2,utiny=2,ushort=2,umedium=2,ulong=2,
+ulonglong=2, bits=b'010',
options='one',flags='one', date_field='1902-02-02',year_field='1902',
time_field='02:02:02',date_time='1902-02-02 02:02:02' where auto=1;
select auto,string,vstring,bin,vbin,tiny,short,medium,long_int,longlong,
-real_float,real_double, utiny, ushort, umedium,ulong,ulonglong,
-options,flags,date_field,year_field,time_field,date_time
+real_float,real_double,real_decimal,utiny,ushort,umedium,ulong,ulonglong,
+bits,options,flags,date_field,year_field,time_field,date_time
from t1;
-auto string vstring bin vbin tiny short medium long_int longlong real_float real_double utiny ushort umedium ulong ulonglong options flags date_field year_field time_field date_time
-1 bbbb bbbb »» »» -2 -2 -2 -2 -2 2.2 2.2000 2 00002 2 2 2 one one 1902-02-02 1902 02:02:02 1902-02-02 02:02:02
+auto string vstring bin vbin tiny short medium long_int longlong real_float real_double real_decimal utiny ushort umedium ulong ulonglong bits options flags date_field year_field time_field date_time
+1 bbbb bbbb »» »» -2 -2 -2 -2 -2 2.2 2.2000 2.2000 2 00002 2 2 2  one one 1902-02-02 1902 02:02:02 1902-02-02 02:02:02
select time_stamp>@now from t1;
time_stamp>@now
1
diff --git a/mysql-test/r/negation_elimination.result b/mysql-test/r/negation_elimination.result
index 9193a125cd1..a7dbe0d9052 100644
--- a/mysql-test/r/negation_elimination.result
+++ b/mysql-test/r/negation_elimination.result
@@ -387,5 +387,5 @@ explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like "
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL a 5 NULL 5 Using where; Using index
Warnings:
-Note 1003 select test.t1.a AS `a`,(test.t1.a <> 0) AS `not(not(a))`,((test.t1.a > 2) or test.t1.a) AS `not(a <= 2 and not(a))`,(test.t1.a like _latin1'1') AS `not(a not like "1")`,(test.t1.a in (1,2)) AS `not (a not in (1,2))`,(test.t1.a = 2) AS `not(a != 2)` from test.t1 where test.t1.a having test.t1.a
+Note 1003 select `test`.`t1`.`a` AS `a`,(`test`.`t1`.`a` <> 0) AS `not(not(a))`,((`test`.`t1`.`a` > 2) or `test`.`t1`.`a`) AS `not(a <= 2 and not(a))`,(`test`.`t1`.`a` like _latin1'1') AS `not(a not like "1")`,(`test`.`t1`.`a` in (1,2)) AS `not (a not in (1,2))`,(`test`.`t1`.`a` = 2) AS `not(a != 2)` from `test`.`t1` where `test`.`t1`.`a` having `test`.`t1`.`a`
drop table t1;
diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result
index 3e233eb512a..c2b925072dd 100644
--- a/mysql-test/r/null.result
+++ b/mysql-test/r/null.result
@@ -88,7 +88,7 @@ b ifnull(t2.b,"this is null")
NULL this is null
NULL this is null
drop table t1;
-CREATE TABLE t1 (a varchar(16) NOT NULL, b smallint(6) NOT NULL, c datetime NOT NULL, d smallint(6) NOT NULL);
+CREATE TABLE t1 (a varchar(16) NOT NULL default '', b smallint(6) NOT NULL default 0, c datetime NOT NULL default '0000-00-00 00:00:00', d smallint(6) NOT NULL default 0);
INSERT INTO t1 SET a = "", d= "2003-01-14 03:54:55";
Warnings:
Warning 1265 Data truncated for column 'd' at row 1
@@ -97,39 +97,39 @@ Warnings:
Warning 1265 Data truncated for column 'd' at row 1
UPDATE t1 SET d=NULL;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'd' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'd' at row 1
INSERT INTO t1 (a) values (null);
ERROR 23000: Column 'a' cannot be null
INSERT INTO t1 (a) values (1/null);
ERROR 23000: Column 'a' cannot be null
INSERT INTO t1 (a) values (null),(null);
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 2
INSERT INTO t1 (b) values (null);
ERROR 23000: Column 'b' cannot be null
INSERT INTO t1 (b) values (1/null);
ERROR 23000: Column 'b' cannot be null
INSERT INTO t1 (b) values (null),(null);
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'b' at row 1
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'b' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'b' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'b' at row 2
INSERT INTO t1 (c) values (null);
ERROR 23000: Column 'c' cannot be null
INSERT INTO t1 (c) values (1/null);
ERROR 23000: Column 'c' cannot be null
INSERT INTO t1 (c) values (null),(null);
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'c' at row 1
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'c' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'c' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'c' at row 2
INSERT INTO t1 (d) values (null);
ERROR 23000: Column 'd' cannot be null
INSERT INTO t1 (d) values (1/null);
ERROR 23000: Column 'd' cannot be null
INSERT INTO t1 (d) values (null),(null);
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'd' at row 1
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'd' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'd' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'd' at row 2
select * from t1;
a b c d
0 0000-00-00 00:00:00 0
@@ -167,13 +167,22 @@ insert into t1 select i*2 from t1;
insert into t1 select i*2 from t1;
insert into t1 select i*2 from t1;
insert into t1 select i*2 from t1;
+insert into t1 values(null);
explain select * from t1 where i=2 or i is null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref_or_null i i 5 const 10 Using where; Using index
+select count(*) from t1 where i=2 or i is null;
+count(*)
+10
alter table t1 change i i int not null;
+Warnings:
+Warning 1265 Data truncated for column 'i' at row 513
explain select * from t1 where i=2 or i is null;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref i i 4 const 7 Using where; Using index
+1 SIMPLE t1 ref i i 4 const 8 Using index
+select count(*) from t1 where i=2 or i is null;
+count(*)
+9
drop table t1;
set names latin2;
create table t1 select
@@ -246,14 +255,14 @@ t1 CREATE TABLE `t1` (
`c25` varchar(12) character set latin2 default NULL,
`c26` varchar(7) character set latin2 default NULL,
`c27` varchar(7) character set latin2 default NULL,
- `c29` longtext character set latin2,
- `c30` longtext character set latin2,
+ `c29` varchar(381) character set latin2 default NULL,
+ `c30` varchar(317) character set latin2 default NULL,
`c31` varchar(192) character set latin2 default NULL,
`c32` char(0) character set latin2 default NULL,
- `c33` char(3) character set latin2 default NULL,
- `c34` char(3) character set latin2 default NULL,
- `c35` char(3) character set latin2 default NULL,
- `c36` char(3) character set latin2 default NULL,
+ `c33` varchar(3) character set latin2 default NULL,
+ `c34` varchar(3) character set latin2 default NULL,
+ `c35` varchar(3) character set latin2 default NULL,
+ `c36` varchar(3) character set latin2 default NULL,
`c37` varchar(10) character set latin2 default NULL,
`c38` varchar(10) character set latin2 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result
index 4b7400e5e60..b9824cc4b81 100644
--- a/mysql-test/r/null_key.result
+++ b/mysql-test/r/null_key.result
@@ -30,7 +30,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a,b a 5 const 3 Using where; Using index
explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range a,b a 9 NULL 2 Using where; Using index
+1 SIMPLE t1 ref a,b a 5 const 2 Using where; Using index
explain select * from t1 where a > 1 and a < 3 limit 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 5 NULL 1 Using where; Using index
@@ -66,6 +66,11 @@ a b
NULL 7
NULL 9
NULL 9
+select * from t1 where a > 1 and a < 3 limit 1;
+a b
+2 2
+select * from t1 where a > 8 and a < 9;
+a b
create table t2 like t1;
insert into t2 select * from t1;
alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10));
@@ -153,12 +158,12 @@ a b
7 NULL
explain select * from t1 where (a = 7 or a is null) and (b=7 or b is null);
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range a,b a 10 NULL 3 Using where; Using index
+1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using where; Using index
select * from t1 where (a = 7 or a is null) and (b=7 or b is null);
a b
-NULL 7
7 NULL
7 7
+NULL 7
explain select * from t1 where (a = 7 or a is null) and (a = 7 or a is null);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref_or_null a a 5 const 5 Using where; Using index
@@ -337,7 +342,7 @@ index (id2)
);
insert into t1 values(null,null),(1,1);
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'id2' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'id2' at row 1
select * from t1;
id id2
NULL 0
diff --git a/mysql-test/r/odbc.result b/mysql-test/r/odbc.result
index c0b2ada0053..2d9d39393b1 100644
--- a/mysql-test/r/odbc.result
+++ b/mysql-test/r/odbc.result
@@ -12,5 +12,5 @@ select * from t1 where a is null;
a b
explain select * from t1 where b is null;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
drop table t1;
diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result
index 341d51033f2..06f474923eb 100644
--- a/mysql-test/r/olap.result
+++ b/mysql-test/r/olap.result
@@ -85,7 +85,7 @@ explain extended select product, country_id , year, sum(profit) from t1 group by
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 15 Using temporary; Using filesort
Warnings:
-Note 1003 select test.t1.product AS `product`,test.t1.country_id AS `country_id`,test.t1.year AS `year`,sum(test.t1.profit) AS `sum(profit)` from test.t1 group by test.t1.product,test.t1.country_id,test.t1.year with rollup
+Note 1003 select `test`.`t1`.`product` AS `product`,`test`.`t1`.`country_id` AS `country_id`,`test`.`t1`.`year` AS `year`,sum(`test`.`t1`.`profit`) AS `sum(profit)` from `test`.`t1` group by `test`.`t1`.`product`,`test`.`t1`.`country_id`,`test`.`t1`.`year` with rollup
select product, country_id , sum(profit) from t1 group by product desc, country_id with rollup;
product country_id sum(profit)
TV 1 400
@@ -164,48 +164,48 @@ product country_id year sum(profit)
NULL NULL NULL 7785
select concat(product,':',country_id) as 'prod', concat(":",year,":") as 'year',1+1, sum(profit)/count(*) from t1 group by 1,2 with rollup;
prod year 1+1 sum(profit)/count(*)
-Calculator:1 :1999: 2 50.00
-Calculator:1 :2000: 2 75.00
-Calculator:1 NULL 2 62.50
-Calculator:2 :2000: 2 75.00
-Calculator:2 NULL 2 75.00
-Computer:1 :1999: 2 1350.00
-Computer:1 :2000: 2 1500.00
-Computer:1 NULL 2 1400.00
-Computer:2 :2000: 2 1350.00
-Computer:2 NULL 2 1350.00
-Phone:3 :2003: 2 10.00
-Phone:3 NULL 2 10.00
-TV:1 :1999: 2 125.00
-TV:1 :2000: 2 150.00
-TV:1 NULL 2 133.33
-TV:2 :2000: 2 100.00
-TV:2 NULL 2 100.00
-NULL NULL 2 519.00
+Calculator:1 :1999: 2 50.00000
+Calculator:1 :2000: 2 75.00000
+Calculator:1 NULL 2 62.50000
+Calculator:2 :2000: 2 75.00000
+Calculator:2 NULL 2 75.00000
+Computer:1 :1999: 2 1350.00000
+Computer:1 :2000: 2 1500.00000
+Computer:1 NULL 2 1400.00000
+Computer:2 :2000: 2 1350.00000
+Computer:2 NULL 2 1350.00000
+Phone:3 :2003: 2 10.00000
+Phone:3 NULL 2 10.00000
+TV:1 :1999: 2 125.00000
+TV:1 :2000: 2 150.00000
+TV:1 NULL 2 133.33333
+TV:2 :2000: 2 100.00000
+TV:2 NULL 2 100.00000
+NULL NULL 2 519.00000
select product, sum(profit)/count(*) from t1 group by product with rollup;
product sum(profit)/count(*)
-Calculator 68.75
-Computer 1380.00
-Phone 10.00
-TV 120.00
-NULL 519.00
+Calculator 68.75000
+Computer 1380.00000
+Phone 10.00000
+TV 120.00000
+NULL 519.00000
select left(product,4) as prod, sum(profit)/count(*) from t1 group by prod with rollup;
prod sum(profit)/count(*)
-Calc 68.75
-Comp 1380.00
-Phon 10.00
-TV 120.00
-NULL 519.00
+Calc 68.75000
+Comp 1380.00000
+Phon 10.00000
+TV 120.00000
+NULL 519.00000
select concat(product,':',country_id), 1+1, sum(profit)/count(*) from t1 group by concat(product,':',country_id) with rollup;
concat(product,':',country_id) 1+1 sum(profit)/count(*)
-Calculator:1 2 62.50
-Calculator:2 2 75.00
-Computer:1 2 1400.00
-Computer:2 2 1350.00
-Phone:3 2 10.00
-TV:1 2 133.33
-TV:2 2 100.00
-NULL 2 519.00
+Calculator:1 2 62.50000
+Calculator:2 2 75.00000
+Computer:1 2 1400.00000
+Computer:2 2 1350.00000
+Phone:3 2 10.00000
+TV:1 2 133.33333
+TV:2 2 100.00000
+NULL 2 519.00000
select product, country , year, sum(profit) from t1,t2 where t1.country_id=t2.country_id group by product, country, year with rollup;
product country year sum(profit)
Calculator India 2000 150
@@ -378,6 +378,51 @@ a sum(b)
2 6
4 4
NULL 14
+SELECT b, a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP;
+b a sum(b)
+4 1 4
+NULL 1 4
+1 2 2
+2 2 4
+NULL 2 6
+1 4 4
+NULL 4 4
+NULL NULL 14
+SELECT DISTINCT b,a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP;
+b a sum(b)
+4 1 4
+NULL 1 4
+1 2 2
+2 2 4
+NULL 2 6
+1 4 4
+NULL 4 4
+NULL NULL 14
+ALTER TABLE t1 ADD COLUMN c INT;
+SELECT a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP;
+a b sum(c)
+1 4 NULL
+1 4 NULL
+1 NULL NULL
+2 1 NULL
+2 1 NULL
+2 2 NULL
+2 2 NULL
+2 NULL NULL
+4 1 NULL
+4 1 NULL
+4 NULL NULL
+NULL NULL NULL
+SELECT distinct a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP;
+a b sum(c)
+1 4 NULL
+1 NULL NULL
+2 1 NULL
+2 2 NULL
+2 NULL NULL
+4 1 NULL
+4 NULL NULL
+NULL NULL NULL
DROP TABLE t1;
CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES
diff --git a/mysql-test/r/openssl_1.result b/mysql-test/r/openssl_1.result
index f7cb17a1a74..035c84431f8 100644
--- a/mysql-test/r/openssl_1.result
+++ b/mysql-test/r/openssl_1.result
@@ -10,22 +10,22 @@ select * from t1;
f1
5
delete from t1;
-ERROR 42000: Access denied for user 'ssl_user1'@'localhost' to database 'test'
+ERROR 42000: DELETE command denied to user 'ssl_user1'@'localhost' for table 't1'
select * from t1;
f1
5
delete from t1;
-ERROR 42000: Access denied for user 'ssl_user2'@'localhost' to database 'test'
+ERROR 42000: DELETE command denied to user 'ssl_user2'@'localhost' for table 't1'
select * from t1;
f1
5
delete from t1;
-ERROR 42000: Access denied for user 'ssl_user3'@'localhost' to database 'test'
+ERROR 42000: DELETE command denied to user 'ssl_user3'@'localhost' for table 't1'
select * from t1;
f1
5
delete from t1;
-ERROR 42000: Access denied for user 'ssl_user4'@'localhost' to database 'test'
+ERROR 42000: DELETE command denied to user 'ssl_user4'@'localhost' for table 't1'
delete from mysql.user where user='ssl_user%';
delete from mysql.db where user='ssl_user%';
flush privileges;
diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result
index ee8ca5f0328..628ca5fd958 100644
--- a/mysql-test/r/order_by.result
+++ b/mysql-test/r/order_by.result
@@ -257,7 +257,7 @@ favo_tijdschrift varchar(50) NOT NULL default '',
favo_tv varchar(50) NOT NULL default '',
favo_eten varchar(50) NOT NULL default '',
favo_muziek varchar(30) NOT NULL default '',
-info text NOT NULL,
+info text NOT NULL default '',
ipnr varchar(30) NOT NULL default '',
PRIMARY KEY (member_id)
) ENGINE=MyISAM PACK_KEYS=1;
@@ -272,7 +272,7 @@ create table t1 (a int not null, b int, c varchar(10), key (a, b, c));
insert into t1 values (1, NULL, NULL), (1, NULL, 'b'), (1, 1, NULL), (1, 1, 'b'), (1, 1, 'b'), (2, 1, 'a'), (2, 1, 'b'), (2, 2, 'a'), (2, 2, 'b'), (2, 3, 'c'),(1,3,'b');
explain select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range a a 20 NULL 2 Using where; Using index
+1 SIMPLE t1 index a a 22 NULL 11 Using where; Using index
select * from t1 where (a = 1 and b is null and c = 'b') or (a > 2) order by a desc;
a b c
1 NULL b
@@ -348,7 +348,7 @@ Warning 1265 Data truncated for column 'b' at row 2
Warning 1265 Data truncated for column 'c' at row 3
explain select * from t1 order by a, b, c;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL a 18 NULL 11 Using index
+1 SIMPLE t1 index NULL a 20 NULL 11 Using index
select * from t1 order by a, b, c;
a b c
1 0
@@ -364,7 +364,7 @@ a b c
2 3 c
explain select * from t1 order by a desc, b desc, c desc;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL a 18 NULL 11 Using index
+1 SIMPLE t1 index NULL a 20 NULL 11 Using index
select * from t1 order by a desc, b desc, c desc;
a b c
2 3 c
@@ -380,7 +380,7 @@ a b c
1 0
explain select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range a a 18 NULL 3 Using where; Using index
+1 SIMPLE t1 range a a 20 NULL 3 Using where; Using index
select * from t1 where (a = 1 and b = 1 and c = 'b') or (a > 2) order by a desc;
a b c
1 1 b
@@ -574,7 +574,7 @@ KEY StringField (FieldKey,StringVal(32))
INSERT INTO t1 VALUES ('0',3,'0'),('0',2,'1'),('0',1,'2'),('1',2,'1'),('1',1,'3'), ('1',0,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('3',2,'1'),('3',1,'2'),('3','3','3');
EXPLAIN SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref FieldKey,LongField,StringField LongField 36 const 3 Using where
+1 SIMPLE t1 ref FieldKey,LongField,StringField LongField 38 const 3 Using where
SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal;
FieldKey LongVal StringVal
1 0 2
@@ -582,7 +582,7 @@ FieldKey LongVal StringVal
1 2 1
EXPLAIN SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY LongVal;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range FieldKey,LongField,StringField FieldKey 36 NULL 4 Using where; Using filesort
+1 SIMPLE t1 range FieldKey,LongField,StringField FieldKey 38 NULL 4 Using where; Using filesort
SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY LongVal;
FieldKey LongVal StringVal
3 1 2
@@ -590,7 +590,7 @@ FieldKey LongVal StringVal
3 3 3
EXPLAIN SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY FieldKey, LongVal;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range FieldKey,LongField,StringField LongField 36 NULL 4 Using where
+1 SIMPLE t1 range FieldKey,LongField,StringField LongField 38 NULL 4 Using where
SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY FieldKey, LongVal;
FieldKey LongVal StringVal
3 1 2
@@ -733,6 +733,13 @@ xxxxxxxxxxxxxxxxxxxaa
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxz
drop table t1;
+create table t1 (a int not null, b int not null, c int not null);
+insert t1 values (1,1,1),(1,1,2),(1,2,1);
+select a, b from t1 group by a, b order by sum(c);
+a b
+1 2
+1 1
+drop table t1;
create table t1 (
`sid` decimal(8,0) default null,
`wnid` varchar(11) not null default '',
@@ -757,7 +764,7 @@ insert into t1 (`sid`, `wnid`) values
('25295','02071491000'),('25296','02071491000'),('25297','02071499000');
explain select * from t1 where wnid like '0101%' order by wnid;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range wnid14,wnid wnid 11 NULL 10 Using where
+1 SIMPLE t1 range wnid14,wnid wnid 13 NULL 10 Using where
select * from t1 where wnid like '0101%' order by wnid;
sid wnid
10100 01019000000
diff --git a/mysql-test/r/preload.result b/mysql-test/r/preload.result
index 7237a0da7e0..b5e6dcfcdbb 100644
--- a/mysql-test/r/preload.result
+++ b/mysql-test/r/preload.result
@@ -145,6 +145,8 @@ load index into cache t3, t2 key (primary,b) ;
Table Op Msg_type Msg_text
test.t3 preload_keys error Table 'test.t3' doesn't exist
test.t2 preload_keys status OK
+Warnings:
+Error 1146 Table 'test.t3' doesn't exist
show status like "key_read%";
Variable_name Value
Key_read_requests 355
@@ -160,6 +162,9 @@ Table Op Msg_type Msg_text
test.t3 preload_keys error Table 'test.t3' doesn't exist
test.t2 preload_keys error Key column 'c' doesn't exist in table
test.t2 preload_keys status Operation failed
+Warnings:
+Error 1146 Table 'test.t3' doesn't exist
+Error 1072 Key column 'c' doesn't exist in table
show status like "key_read%";
Variable_name Value
Key_read_requests 0
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 89c369a51e8..bbd95da2f82 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -153,24 +153,24 @@ id select_type table type possible_keys key key_len ref rows Extra
6 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
5 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
4 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
-3 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
-2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
+3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
execute stmt1 ;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
6 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
5 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
4 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
-3 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
-2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
+3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
explain SELECT (SELECT SUM(c1 + c12 + 0.0) FROM t2 where (t1.c2 - 0e-3) = t2.c2 GROUP BY t1.c15 LIMIT 1) as scalar_s, exists (select 1.0e+0 from t2 where t2.c3 * 9.0000000000 = t1.c4) as exists_s, c5 * 4 in (select c6 + 0.3e+1 from t2) as in_s, (c7 - 4, c8 - 4) in (select c9 + 4.0, c10 + 40e-1 from t2) as in_row_s FROM t1, (select c25 x, c32 y from t2) tt WHERE x * 1 = c25;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
6 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
5 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
4 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
-3 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
-2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
+3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
deallocate prepare stmt1;
drop tables t1,t2;
set @arg00=1;
@@ -207,10 +207,10 @@ create table t1 ( a int primary key, b varchar(30)) engine = MYISAM ;
prepare stmt1 from ' show table status from test like ''t1%'' ';
execute stmt1;
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 9 Dynamic 0 0 0 4294967295 1024 0 NULL # # # latin1_swedish_ci NULL
+t1 MyISAM 10 Dynamic 0 0 0 4294967295 1024 0 NULL # # # latin1_swedish_ci NULL
show table status from test like 't1%' ;
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
-t1 MyISAM 9 Dynamic 0 0 0 4294967295 1024 0 NULL # # # latin1_swedish_ci NULL
+t1 MyISAM 10 Dynamic 0 0 0 4294967295 1024 0 NULL # # # latin1_swedish_ci NULL
deallocate prepare stmt1 ;
drop table t1;
create table t1(a varchar(2), b varchar(3));
@@ -482,6 +482,11 @@ execute stmt;
pnum
deallocate prepare stmt;
drop table t1, t2;
+create table t1 (a varchar(20));
+insert into t1 values ('foo');
+prepare stmt FROM 'SELECT char_length (a) FROM t1';
+ERROR 42000: FUNCTION test.char_length does not exist
+drop table t1;
prepare stmt from "SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0";
execute stmt;
foo
@@ -494,3 +499,74 @@ SELECT FOUND_ROWS();
FOUND_ROWS()
2
deallocate prepare stmt;
+create table t1 (a char(3) not null, b char(3) not null,
+c char(3) not null, primary key (a, b, c));
+create table t2 like t1;
+prepare stmt from
+"select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b)
+ where t1.a=1";
+execute stmt;
+a
+execute stmt;
+a
+execute stmt;
+a
+prepare stmt from
+"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from
+(t1 left outer join t2 on t2.a=? and t1.b=t2.b)
+left outer join t2 t3 on t3.a=? where t1.a=?";
+set @a:=1, @b:=1, @c:=1;
+execute stmt using @a, @b, @c;
+a b c a b c
+execute stmt using @a, @b, @c;
+a b c a b c
+execute stmt using @a, @b, @c;
+a b c a b c
+deallocate prepare stmt;
+drop table t1,t2;
+SET @aux= "SELECT COUNT(*)
+ FROM INFORMATION_SCHEMA.COLUMNS A,
+ INFORMATION_SCHEMA.COLUMNS B
+ WHERE A.TABLE_SCHEMA = B.TABLE_SCHEMA
+ AND A.TABLE_NAME = B.TABLE_NAME
+ AND A.COLUMN_NAME = B.COLUMN_NAME AND
+ A.TABLE_NAME = 'user'";
+prepare my_stmt from @aux;
+execute my_stmt;
+COUNT(*)
+37
+execute my_stmt;
+COUNT(*)
+37
+execute my_stmt;
+COUNT(*)
+37
+deallocate prepare my_stmt;
+drop procedure if exists p1|
+drop table if exists t1|
+create table t1 (id int)|
+insert into t1 values(1)|
+create procedure p1(a int, b int)
+begin
+declare c int;
+select max(id)+1 into c from t1;
+insert into t1 select a+b;
+insert into t1 select a-b;
+insert into t1 select a-c;
+end|
+set @a= 3, @b= 4|
+prepare stmt from "call p1(?, ?)"|
+execute stmt using @a, @b|
+execute stmt using @a, @b|
+select * from t1|
+id
+1
+7
+-1
+1
+7
+-1
+-5
+deallocate prepare stmt|
+drop procedure p1|
+drop table t1|
diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result
index 68d88a454ff..6c616a99fb0 100644
--- a/mysql-test/r/ps_1general.result
+++ b/mysql-test/r/ps_1general.result
@@ -1,6 +1,9 @@
drop table if exists t5, t6, t7, t8;
drop database if exists mysqltest ;
drop database if exists client_test_db;
+drop database if exists testtets;
+drop table if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop view if exists t1Aa,t2Aa,v1Aa,v2Aa;
test_sequence
------ basic tests ------
drop table if exists t1, t9 ;
@@ -15,7 +18,7 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
+c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -255,16 +258,29 @@ a int primary key, b char(10)
prepare stmt4 from ' show databases ';
execute stmt4;
Database
+information_schema
mysql
test
prepare stmt4 from ' show tables from test like ''t2%'' ';
execute stmt4;
Tables_in_test (t2%)
t2
+prepare stmt4 from ' show columns from t2 where field in (select ?) ';
+SET @arg00="a";
+execute stmt4 using @arg00;
+Field Type Null Key Default Extra
+a int(11) NO PRI
+SET @arg00="b";
+execute stmt4 using @arg00;
+Field Type Null Key Default Extra
+b char(10) YES NULL
+SET @arg00=1;
+execute stmt4 using @arg00;
+Field Type Null Key Default Extra
prepare stmt4 from ' show columns from t2 from test like ''a%'' ';
execute stmt4;
Field Type Null Key Default Extra
-a int(11) PRI 0
+a int(11) NO PRI
create index t2_idx on t2(b);
prepare stmt4 from ' show index from t2 from test ';
execute stmt4;
@@ -274,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 9 Fixed 0 0 0 64424509439 1024 0 NULL # # # latin1_swedish_ci NULL
+t2 MyISAM 10 Fixed 0 0 0 64424509439 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 9 Dynamic 2 220 440 4294967295 2048 0 NULL # # # latin1_swedish_ci NULL
+t9 MyISAM 10 Dynamic 2 216 432 4294967295 2048 0 NULL # # # latin1_swedish_ci NULL
prepare stmt4 from ' show status like ''Threads_running'' ';
execute stmt4;
Variable_name Value
@@ -306,8 +322,8 @@ prepare stmt4 from ' show storage engines ';
execute stmt4;
Engine Support Comment
MyISAM YES/NO Default engine as of MySQL 3.23 with great performance
-HEAP YES/NO Alias for MEMORY
MEMORY YES/NO Hash based, stored in memory, useful for temporary tables
+HEAP YES/NO Alias for MEMORY
MERGE YES/NO Collection of identical MyISAM tables
MRG_MYISAM YES/NO Alias for MERGE
ISAM YES/NO Obsolete storage engine, now replaced by MyISAM
@@ -321,7 +337,8 @@ NDB YES/NO Alias for NDBCLUSTER
EXAMPLE YES/NO Example storage engine
ARCHIVE YES/NO Archive storage engine
CSV YES/NO CSV storage engine
-BLACKHOLE YES/NO Storage engine designed to act as null storage
+FEDERATED YES/NO Federated MySQL storage engine
+BLACKHOLE YES/NO /dev/null storage engine (anything you write to it disappears)
drop table if exists t5;
prepare stmt1 from ' drop table if exists t5 ' ;
execute stmt1 ;
@@ -393,22 +410,10 @@ create database mysqltest ;
prepare stmt3 from ' drop database mysqltest ';
ERROR HY000: This command is not supported in the prepared statement protocol yet
drop database mysqltest ;
-prepare stmt3 from ' grant all on test.t1 to drop_user@localhost
-identified by ''looser'' ';
-ERROR HY000: This command is not supported in the prepared statement protocol yet
-grant all on test.t1 to drop_user@localhost
-identified by 'looser' ;
-prepare stmt3 from ' revoke all privileges on test.t1 from
-drop_user@localhost ';
-ERROR HY000: This command is not supported in the prepared statement protocol yet
-revoke all privileges on test.t1 from drop_user@localhost ;
-prepare stmt3 from ' drop user drop_user@localhost ';
-ERROR HY000: This command is not supported in the prepared statement protocol yet
-drop user drop_user@localhost;
prepare stmt3 from ' describe t2 ';
execute stmt3;
Field Type Null Key Default Extra
-a int(11) PRI 0
+a int(11) NO PRI
b char(10) YES MUL NULL
drop table t2 ;
execute stmt3;
@@ -435,9 +440,7 @@ ERROR HY000: This command is not supported in the prepared statement protocol ye
prepare stmt1 from ' handler t1 open ';
ERROR HY000: This command is not supported in the prepared statement protocol yet
prepare stmt3 from ' commit ' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
prepare stmt3 from ' rollback ' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
prepare stmt4 from ' SET sql_mode=ansi ';
execute stmt4;
select 'a' || 'b' ;
@@ -445,17 +448,17 @@ select 'a' || 'b' ;
ab
prepare stmt4 from ' SET sql_mode="" ';
execute stmt4;
-select 'a' || 'b' ;
-'a' || 'b'
-0
-prepare stmt5 from ' select ''a'' || ''b'' ' ;
+select '2' || '3' ;
+'2' || '3'
+1
+prepare stmt5 from ' select ''2'' || ''3'' ' ;
execute stmt5;
-'a' || 'b'
-0
+'2' || '3'
+1
SET sql_mode=ansi;
execute stmt5;
-'a' || 'b'
-0
+'2' || '3'
+1
SET sql_mode="";
prepare stmt1 from ' flush local privileges ' ;
ERROR HY000: This command is not supported in the prepared statement protocol yet
@@ -472,7 +475,7 @@ def table 253 64 2 N 1 31 8
def type 253 10 3 N 1 31 8
def possible_keys 253 4096 0 Y 0 31 8
def key 253 64 0 Y 0 31 8
-def key_len 8 3 0 Y 32928 0 63
+def key_len 253 4096 0 Y 128 31 63
def ref 253 1024 0 Y 0 31 8
def rows 8 10 1 N 32929 0 63
def Extra 253 255 14 N 1 31 8
@@ -488,7 +491,7 @@ def table 253 64 2 N 1 31 8
def type 253 10 5 N 1 31 8
def possible_keys 253 4096 7 Y 0 31 8
def key 253 64 7 Y 0 31 8
-def key_len 8 3 1 Y 32928 0 63
+def key_len 253 4096 1 Y 128 31 63
def ref 253 1024 0 Y 0 31 8
def rows 8 10 1 N 32929 0 63
def Extra 253 255 27 N 1 31 8
@@ -545,11 +548,8 @@ m
1
drop table t3;
prepare stmt3 from ' create index t2_idx on t2(b) ';
-ERROR HY000: This command is not supported in the prepared statement protocol yet
prepare stmt3 from ' drop index t2_idx on t2 ' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
prepare stmt3 from ' alter table t2 drop primary key ';
-ERROR HY000: This command is not supported in the prepared statement protocol yet
drop table if exists new_t2;
prepare stmt3 from ' rename table t2 to new_t2 ';
execute stmt3;
@@ -560,7 +560,7 @@ drop table t2;
prepare stmt1 from ' rename table t5 to t6, t7 to t8 ' ;
create table t5 (a int) ;
execute stmt1 ;
-ERROR HY000: Can't find file: './test/t7.frm' (errno: 2)
+ERROR HY000: Can't find file: './test/t7' (errno: 2)
create table t7 (a int) ;
execute stmt1 ;
execute stmt1 ;
diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result
index fd17dc5b1b5..37c3682cacd 100644
--- a/mysql-test/r/ps_2myisam.result
+++ b/mysql-test/r/ps_2myisam.result
@@ -11,7 +11,7 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
+c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -59,17 +59,17 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63
def test t9 t9 c8 c8 5 22 1 Y 32768 31 63
def test t9 t9 c9 c9 5 22 1 Y 32768 31 63
def test t9 t9 c10 c10 5 22 1 Y 32768 31 63
-def test t9 t9 c11 c11 0 9 6 Y 32768 4 63
-def test t9 t9 c12 c12 0 10 6 Y 32768 4 63
+def test t9 t9 c11 c11 246 7 6 Y 0 4 63
+def test t9 t9 c12 c12 246 8 6 Y 0 4 63
def test t9 t9 c13 c13 10 10 10 Y 128 0 63
def test t9 t9 c14 c14 12 19 19 Y 128 0 63
def test t9 t9 c15 c15 7 19 19 N 1249 0 63
def test t9 t9 c16 c16 11 8 8 Y 128 0 63
def test t9 t9 c17 c17 13 4 4 Y 32864 0 63
-def test t9 t9 c18 c18 1 1 1 Y 32768 0 63
+def test t9 t9 c18 c18 1 4 1 Y 32768 0 63
def test t9 t9 c19 c19 1 1 1 Y 32768 0 63
def test t9 t9 c20 c20 254 1 1 Y 0 0 8
-def test t9 t9 c21 c21 253 10 10 Y 0 0 8
+def test t9 t9 c21 c21 254 10 10 Y 0 0 8
def test t9 t9 c22 c22 253 30 30 Y 0 0 8
def test t9 t9 c23 c23 252 255 8 Y 144 0 63
def test t9 t9 c24 c24 252 255 8 Y 16 0 8
@@ -1155,7 +1155,7 @@ def table 253 64 2 N 1 31 8
def type 253 10 3 N 1 31 8
def possible_keys 253 4096 0 Y 0 31 8
def key 253 64 0 Y 0 31 8
-def key_len 8 3 0 Y 32928 0 63
+def key_len 253 4096 0 Y 128 31 63
def ref 253 1024 0 Y 0 31 8
def rows 8 10 1 N 32929 0 63
def Extra 253 255 0 N 1 31 8
@@ -1223,7 +1223,6 @@ execute stmt1 using @arg00;
select a,b from t1 where b=@arg00;
a b
prepare stmt1 from 'truncate table t1' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
test_sequence
------ update tests ------
delete from t1 ;
@@ -1302,7 +1301,7 @@ set @arg00=NULL;
set @arg01=2;
execute stmt1 using @arg00, @arg01;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1
select a,b from t1 order by a;
a b
0 two
@@ -1713,8 +1712,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
delete from t2 ;
prepare stmt1 from ' insert into t2 (b,a)
@@ -1732,8 +1731,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
drop table t2;
drop table if exists t5 ;
@@ -1777,13 +1776,13 @@ Table Create Table
t5 CREATE TABLE `t5` (
`const01` bigint(1) NOT NULL default '0',
`param01` bigint(20) default NULL,
- `const02` double(3,1) NOT NULL default '0.0',
- `param02` double default NULL,
+ `const02` decimal(3,1) NOT NULL default '0.0',
+ `param02` decimal(64,30) default NULL,
`const03` double NOT NULL default '0',
`param03` double default NULL,
- `const04` char(3) NOT NULL default '',
+ `const04` varchar(3) NOT NULL default '',
`param04` longtext,
- `const05` binary(3) NOT NULL default '',
+ `const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
@@ -1799,7 +1798,7 @@ t5 CREATE TABLE `t5` (
`param11` bigint(20) default NULL,
`const12` binary(0) default NULL,
`param12` bigint(20) default NULL,
- `param13` double default NULL,
+ `param13` decimal(64,30) default NULL,
`param14` longtext,
`param15` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -1807,13 +1806,13 @@ select * from t5 ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t5 t5 const01 const01 8 1 1 N 32769 0 63
def test t5 t5 param01 param01 8 20 1 Y 32768 0 63
-def test t5 t5 const02 const02 5 3 3 N 32769 1 63
-def test t5 t5 param02 param02 5 20 1 Y 32768 31 63
-def test t5 t5 const03 const03 5 23 1 N 32769 31 63
+def test t5 t5 const02 const02 246 3 3 N 1 1 63
+def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63
-def test t5 t5 const04 const04 254 3 3 N 1 0 8
+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 const05 const05 254 3 3 N 129 0 63
+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 const06 const06 253 10 10 N 1 0 8
def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
@@ -1829,13 +1828,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
-def test t5 t5 param13 param13 5 20 0 Y 32768 31 63
+def test t5 t5 param13 param13 246 64 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
const01 8
param01 8
const02 8.0
-param02 8
+param02 8.000000000000000000000000000000
const03 8
param03 8
const04 abc
@@ -1917,40 +1916,40 @@ from t9 where c1= 1 ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
@arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
@arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
@@ -1964,38 +1963,38 @@ from t9 where c1= 0 ;
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select
@@ -2014,78 +2013,78 @@ execute stmt1 using @my_key ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select ? := c1 from t9 where c1= 1" ;
@@ -2102,40 +2101,40 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 1 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
c25, c26, c27, c28, c29, c30, c31, c32
@@ -2146,38 +2145,38 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 0 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
@@ -2192,76 +2191,76 @@ set @my_key= 1 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1 into ? from t9 where c1= 1" ;
@@ -2572,12 +2571,12 @@ set @arg00= 9223372036854775807 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2589,18 +2588,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '9223372036854775807' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2612,18 +2611,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -9223372036854775808 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2641,12 +2640,12 @@ set @arg00= '-9223372036854775808' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2664,14 +2663,14 @@ set @arg00= 1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2683,7 +2682,7 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '1.11111111111111111111e+50' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@@ -2695,8 +2694,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 1
c2 1
@@ -2708,20 +2707,20 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2745,8 +2744,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -1
c2 -1
@@ -2818,10 +2817,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30
41 4 41 41 41 41 41 41 41 41 41 41
42 4 42 42 42 42 42 42 42 42 42 42
43 4 43 43 43 43 43 43 43 43 43 43
-50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00
-51 5 51 51 51 51 51 51 51 51 51 51
-52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00
-53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00
+50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0
+51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0
+52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0
+53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0
54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00
55 5 55 55 55 55 55 55 55 55 55 55
56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00
@@ -2977,45 +2976,45 @@ Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
select c1, c13, c14, c15, c16, c17 from t9 order by c1 ;
c1 c13 c14 c15 c16 c17
20 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result
index 50dc580a930..d56fcb96726 100644
--- a/mysql-test/r/ps_3innodb.result
+++ b/mysql-test/r/ps_3innodb.result
@@ -11,7 +11,7 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
+c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -59,17 +59,17 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63
def test t9 t9 c8 c8 5 22 1 Y 32768 31 63
def test t9 t9 c9 c9 5 22 1 Y 32768 31 63
def test t9 t9 c10 c10 5 22 1 Y 32768 31 63
-def test t9 t9 c11 c11 0 9 6 Y 32768 4 63
-def test t9 t9 c12 c12 0 10 6 Y 32768 4 63
+def test t9 t9 c11 c11 246 7 6 Y 0 4 63
+def test t9 t9 c12 c12 246 8 6 Y 0 4 63
def test t9 t9 c13 c13 10 10 10 Y 128 0 63
def test t9 t9 c14 c14 12 19 19 Y 128 0 63
def test t9 t9 c15 c15 7 19 19 N 1249 0 63
def test t9 t9 c16 c16 11 8 8 Y 128 0 63
def test t9 t9 c17 c17 13 4 4 Y 32864 0 63
-def test t9 t9 c18 c18 1 1 1 Y 32768 0 63
+def test t9 t9 c18 c18 1 4 1 Y 32768 0 63
def test t9 t9 c19 c19 1 1 1 Y 32768 0 63
def test t9 t9 c20 c20 254 1 1 Y 0 0 8
-def test t9 t9 c21 c21 253 10 10 Y 0 0 8
+def test t9 t9 c21 c21 254 10 10 Y 0 0 8
def test t9 t9 c22 c22 253 30 30 Y 0 0 8
def test t9 t9 c23 c23 252 255 8 Y 144 0 63
def test t9 t9 c24 c24 252 255 8 Y 16 0 8
@@ -1155,7 +1155,7 @@ def table 253 64 2 N 1 31 8
def type 253 10 3 N 1 31 8
def possible_keys 253 4096 0 Y 0 31 8
def key 253 64 0 Y 0 31 8
-def key_len 8 3 0 Y 32928 0 63
+def key_len 253 4096 0 Y 128 31 63
def ref 253 1024 0 Y 0 31 8
def rows 8 10 1 N 32929 0 63
def Extra 253 255 0 N 1 31 8
@@ -1206,7 +1206,6 @@ execute stmt1 using @arg00;
select a,b from t1 where b=@arg00;
a b
prepare stmt1 from 'truncate table t1' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
test_sequence
------ update tests ------
delete from t1 ;
@@ -1285,7 +1284,7 @@ set @arg00=NULL;
set @arg01=2;
execute stmt1 using @arg00, @arg01;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1
select a,b from t1 order by a;
a b
0 two
@@ -1696,8 +1695,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
delete from t2 ;
prepare stmt1 from ' insert into t2 (b,a)
@@ -1715,8 +1714,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
drop table t2;
drop table if exists t5 ;
@@ -1760,13 +1759,13 @@ Table Create Table
t5 CREATE TABLE `t5` (
`const01` bigint(1) NOT NULL default '0',
`param01` bigint(20) default NULL,
- `const02` double(3,1) NOT NULL default '0.0',
- `param02` double default NULL,
+ `const02` decimal(3,1) NOT NULL default '0.0',
+ `param02` decimal(64,30) default NULL,
`const03` double NOT NULL default '0',
`param03` double default NULL,
- `const04` char(3) NOT NULL default '',
+ `const04` varchar(3) NOT NULL default '',
`param04` longtext,
- `const05` binary(3) NOT NULL default '',
+ `const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
@@ -1782,7 +1781,7 @@ t5 CREATE TABLE `t5` (
`param11` bigint(20) default NULL,
`const12` binary(0) default NULL,
`param12` bigint(20) default NULL,
- `param13` double default NULL,
+ `param13` decimal(64,30) default NULL,
`param14` longtext,
`param15` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -1790,13 +1789,13 @@ select * from t5 ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t5 t5 const01 const01 8 1 1 N 32769 0 63
def test t5 t5 param01 param01 8 20 1 Y 32768 0 63
-def test t5 t5 const02 const02 5 3 3 N 32769 1 63
-def test t5 t5 param02 param02 5 20 1 Y 32768 31 63
-def test t5 t5 const03 const03 5 23 1 N 32769 31 63
+def test t5 t5 const02 const02 246 3 3 N 1 1 63
+def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63
-def test t5 t5 const04 const04 254 3 3 N 1 0 8
+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 const05 const05 254 3 3 N 129 0 63
+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 const06 const06 253 10 10 N 1 0 8
def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
@@ -1812,13 +1811,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
-def test t5 t5 param13 param13 5 20 0 Y 32768 31 63
+def test t5 t5 param13 param13 246 64 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
const01 8
param01 8
const02 8.0
-param02 8
+param02 8.000000000000000000000000000000
const03 8
param03 8
const04 abc
@@ -1900,40 +1899,40 @@ from t9 where c1= 1 ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
@arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
@arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
@@ -1947,38 +1946,38 @@ from t9 where c1= 0 ;
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select
@@ -1997,78 +1996,78 @@ execute stmt1 using @my_key ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select ? := c1 from t9 where c1= 1" ;
@@ -2085,40 +2084,40 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 1 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
c25, c26, c27, c28, c29, c30, c31, c32
@@ -2129,38 +2128,38 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 0 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
@@ -2175,76 +2174,76 @@ set @my_key= 1 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1 into ? from t9 where c1= 1" ;
@@ -2555,12 +2554,12 @@ set @arg00= 9223372036854775807 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2572,18 +2571,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '9223372036854775807' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2595,18 +2594,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -9223372036854775808 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2624,12 +2623,12 @@ set @arg00= '-9223372036854775808' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2647,14 +2646,14 @@ set @arg00= 1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2666,7 +2665,7 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '1.11111111111111111111e+50' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@@ -2678,8 +2677,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 1
c2 1
@@ -2691,20 +2690,20 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2728,8 +2727,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -1
c2 -1
@@ -2801,10 +2800,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30
41 4 41 41 41 41 41 41 41 41 41 41
42 4 42 42 42 42 42 42 42 42 42 42
43 4 43 43 43 43 43 43 43 43 43 43
-50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00
-51 5 51 51 51 51 51 51 51 51 51 51
-52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00
-53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00
+50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0
+51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0
+52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0
+53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0
54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00
55 5 55 55 55 55 55 55 55 55 55 55
56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00
@@ -2960,45 +2959,45 @@ Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
select c1, c13, c14, c15, c16, c17 from t9 order by c1 ;
c1 c13 c14 c15 c16 c17
20 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result
index 050a63f254c..899299fa36c 100644
--- a/mysql-test/r/ps_4heap.result
+++ b/mysql-test/r/ps_4heap.result
@@ -12,10 +12,10 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
-c21 char(10), c22 varchar(30), c23 char(100), c24 char(100),
-c25 char(100), c26 char(100), c27 char(100), c28 char(100),
-c29 char(100), c30 char(100), c31 enum('one', 'two', 'three'),
+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),
+c29 varchar(100), c30 varchar(100), c31 enum('one', 'two', 'three'),
c32 set('monday', 'tuesday', 'wednesday'),
primary key(c1)
) engine = 'HEAP' ;
@@ -60,17 +60,17 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63
def test t9 t9 c8 c8 5 22 1 Y 32768 31 63
def test t9 t9 c9 c9 5 22 1 Y 32768 31 63
def test t9 t9 c10 c10 5 22 1 Y 32768 31 63
-def test t9 t9 c11 c11 0 9 6 Y 32768 4 63
-def test t9 t9 c12 c12 0 10 6 Y 32768 4 63
+def test t9 t9 c11 c11 246 7 6 Y 0 4 63
+def test t9 t9 c12 c12 246 8 6 Y 0 4 63
def test t9 t9 c13 c13 10 10 10 Y 128 0 63
def test t9 t9 c14 c14 12 19 19 Y 128 0 63
def test t9 t9 c15 c15 7 19 19 N 1249 0 63
def test t9 t9 c16 c16 11 8 8 Y 128 0 63
def test t9 t9 c17 c17 13 4 4 Y 32864 0 63
-def test t9 t9 c18 c18 1 1 1 Y 32768 0 63
+def test t9 t9 c18 c18 1 4 1 Y 32768 0 63
def test t9 t9 c19 c19 1 1 1 Y 32768 0 63
def test t9 t9 c20 c20 254 1 1 Y 0 0 8
-def test t9 t9 c21 c21 253 10 10 Y 0 0 8
+def test t9 t9 c21 c21 254 10 10 Y 0 0 8
def test t9 t9 c22 c22 253 30 30 Y 0 0 8
def test t9 t9 c23 c23 253 100 8 Y 0 0 8
def test t9 t9 c24 c24 253 100 8 Y 0 0 8
@@ -1156,7 +1156,7 @@ def table 253 64 2 N 1 31 8
def type 253 10 3 N 1 31 8
def possible_keys 253 4096 0 Y 0 31 8
def key 253 64 0 Y 0 31 8
-def key_len 8 3 0 Y 32928 0 63
+def key_len 253 4096 0 Y 128 31 63
def ref 253 1024 0 Y 0 31 8
def rows 8 10 1 N 32929 0 63
def Extra 253 255 0 N 1 31 8
@@ -1207,7 +1207,6 @@ execute stmt1 using @arg00;
select a,b from t1 where b=@arg00;
a b
prepare stmt1 from 'truncate table t1' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
test_sequence
------ update tests ------
delete from t1 ;
@@ -1286,7 +1285,7 @@ set @arg00=NULL;
set @arg01=2;
execute stmt1 using @arg00, @arg01;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1
select a,b from t1 order by a;
a b
0 two
@@ -1697,8 +1696,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
delete from t2 ;
prepare stmt1 from ' insert into t2 (b,a)
@@ -1716,8 +1715,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
drop table t2;
drop table if exists t5 ;
@@ -1761,13 +1760,13 @@ Table Create Table
t5 CREATE TABLE `t5` (
`const01` bigint(1) NOT NULL default '0',
`param01` bigint(20) default NULL,
- `const02` double(3,1) NOT NULL default '0.0',
- `param02` double default NULL,
+ `const02` decimal(3,1) NOT NULL default '0.0',
+ `param02` decimal(64,30) default NULL,
`const03` double NOT NULL default '0',
`param03` double default NULL,
- `const04` char(3) NOT NULL default '',
+ `const04` varchar(3) NOT NULL default '',
`param04` longtext,
- `const05` binary(3) NOT NULL default '',
+ `const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
@@ -1783,7 +1782,7 @@ t5 CREATE TABLE `t5` (
`param11` bigint(20) default NULL,
`const12` binary(0) default NULL,
`param12` bigint(20) default NULL,
- `param13` double default NULL,
+ `param13` decimal(64,30) default NULL,
`param14` longtext,
`param15` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -1791,13 +1790,13 @@ select * from t5 ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t5 t5 const01 const01 8 1 1 N 32769 0 63
def test t5 t5 param01 param01 8 20 1 Y 32768 0 63
-def test t5 t5 const02 const02 5 3 3 N 32769 1 63
-def test t5 t5 param02 param02 5 20 1 Y 32768 31 63
-def test t5 t5 const03 const03 5 23 1 N 32769 31 63
+def test t5 t5 const02 const02 246 3 3 N 1 1 63
+def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63
-def test t5 t5 const04 const04 254 3 3 N 1 0 8
+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 const05 const05 254 3 3 N 129 0 63
+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 const06 const06 253 10 10 N 1 0 8
def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
@@ -1813,13 +1812,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
-def test t5 t5 param13 param13 5 20 0 Y 32768 31 63
+def test t5 t5 param13 param13 246 64 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
const01 8
param01 8
const02 8.0
-param02 8
+param02 8.000000000000000000000000000000
const03 8
param03 8
const04 abc
@@ -1901,40 +1900,40 @@ from t9 where c1= 1 ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 0 31 8
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 0 31 8
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 0 31 8
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 0 31 8
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 0 31 8
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 0 31 8
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 0 31 8
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 0 31 8
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
@arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
@arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
@@ -1948,38 +1947,38 @@ from t9 where c1= 0 ;
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 0 31 8
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 0 31 8
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 0 31 8
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 0 31 8
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 0 31 8
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 0 31 8
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 0 31 8
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 0 31 8
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select
@@ -1998,78 +1997,78 @@ execute stmt1 using @my_key ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 0 31 8
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 0 31 8
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 0 31 8
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 0 31 8
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 0 31 8
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 0 31 8
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 0 31 8
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 0 31 8
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 0 31 8
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 0 31 8
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 0 31 8
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 0 31 8
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 0 31 8
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 0 31 8
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 0 31 8
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 0 31 8
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select ? := c1 from t9 where c1= 1" ;
@@ -2086,40 +2085,40 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 1 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 0 31 8
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 0 31 8
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 0 31 8
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 0 31 8
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 0 31 8
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 0 31 8
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 0 31 8
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 0 31 8
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
c25, c26, c27, c28, c29, c30, c31, c32
@@ -2130,38 +2129,38 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 0 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 0 31 8
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 0 31 8
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 0 31 8
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 0 31 8
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 0 31 8
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 0 31 8
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 0 31 8
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 0 31 8
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
@@ -2176,76 +2175,76 @@ set @my_key= 1 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 0 31 8
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 0 31 8
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 0 31 8
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 0 31 8
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 0 31 8
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 0 31 8
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 0 31 8
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 0 31 8
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 0 31 8
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 0 31 8
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 0 31 8
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 0 31 8
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 0 31 8
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 0 31 8
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 0 31 8
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 0 31 8
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1 into ? from t9 where c1= 1" ;
@@ -2556,12 +2555,12 @@ set @arg00= 9223372036854775807 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2573,18 +2572,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '9223372036854775807' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2596,18 +2595,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -9223372036854775808 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2625,12 +2624,12 @@ set @arg00= '-9223372036854775808' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2648,14 +2647,14 @@ set @arg00= 1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2667,7 +2666,7 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '1.11111111111111111111e+50' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@@ -2679,8 +2678,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 1
c2 1
@@ -2692,20 +2691,20 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2729,8 +2728,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -1
c2 -1
@@ -2802,10 +2801,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30
41 4 41 41 41 41 41 41 41 41 41 41
42 4 42 42 42 42 42 42 42 42 42 42
43 4 43 43 43 43 43 43 43 43 43 43
-50 5 50 50 50 50 50 50 50 50 50 50
-51 5 51 51 51 51 51 51 51 51 51 51
-52 5 52 52 52 52 52 52 52 52 52 52
-53 5 53 53 53 53 53 53 53 53 53 53
+50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0
+51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0
+52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0
+53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0
54 5 54 54 54 54 54 54 54 54 54 54
55 5 55 55 55 55 55 55 55 55 55 55
56 6 56 56 56 56 56 56 56 56 56 56
@@ -2961,45 +2960,45 @@ Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
select c1, c13, c14, c15, c16, c17 from t9 order by c1 ;
c1 c13 c14 c15 c16 c17
20 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result
index c228ec4672f..4a53fe47f3f 100644
--- a/mysql-test/r/ps_5merge.result
+++ b/mysql-test/r/ps_5merge.result
@@ -13,7 +13,7 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
+c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -33,7 +33,7 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
+c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -53,7 +53,7 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
+c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -102,17 +102,17 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63
def test t9 t9 c8 c8 5 22 1 Y 32768 31 63
def test t9 t9 c9 c9 5 22 1 Y 32768 31 63
def test t9 t9 c10 c10 5 22 1 Y 32768 31 63
-def test t9 t9 c11 c11 0 9 6 Y 32768 4 63
-def test t9 t9 c12 c12 0 10 6 Y 32768 4 63
+def test t9 t9 c11 c11 246 7 6 Y 0 4 63
+def test t9 t9 c12 c12 246 8 6 Y 0 4 63
def test t9 t9 c13 c13 10 10 10 Y 128 0 63
def test t9 t9 c14 c14 12 19 19 Y 128 0 63
def test t9 t9 c15 c15 7 19 19 N 1249 0 63
def test t9 t9 c16 c16 11 8 8 Y 128 0 63
def test t9 t9 c17 c17 13 4 4 Y 32864 0 63
-def test t9 t9 c18 c18 1 1 1 Y 32768 0 63
+def test t9 t9 c18 c18 1 4 1 Y 32768 0 63
def test t9 t9 c19 c19 1 1 1 Y 32768 0 63
def test t9 t9 c20 c20 254 1 1 Y 0 0 8
-def test t9 t9 c21 c21 253 10 10 Y 0 0 8
+def test t9 t9 c21 c21 254 10 10 Y 0 0 8
def test t9 t9 c22 c22 253 30 30 Y 0 0 8
def test t9 t9 c23 c23 252 255 8 Y 144 0 63
def test t9 t9 c24 c24 252 255 8 Y 16 0 8
@@ -1198,7 +1198,7 @@ def table 253 64 2 N 1 31 8
def type 253 10 3 N 1 31 8
def possible_keys 253 4096 0 Y 0 31 8
def key 253 64 0 Y 0 31 8
-def key_len 8 3 0 Y 32928 0 63
+def key_len 253 4096 0 Y 128 31 63
def ref 253 1024 0 Y 0 31 8
def rows 8 10 1 N 32929 0 63
def Extra 253 255 0 N 1 31 8
@@ -1249,7 +1249,6 @@ execute stmt1 using @arg00;
select a,b from t1 where b=@arg00;
a b
prepare stmt1 from 'truncate table t1' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
test_sequence
------ update tests ------
delete from t1 ;
@@ -1328,7 +1327,7 @@ set @arg00=NULL;
set @arg01=2;
execute stmt1 using @arg00, @arg01;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1
select a,b from t1 order by a;
a b
0 two
@@ -1697,13 +1696,13 @@ Table Create Table
t5 CREATE TABLE `t5` (
`const01` bigint(1) NOT NULL default '0',
`param01` bigint(20) default NULL,
- `const02` double(3,1) NOT NULL default '0.0',
- `param02` double default NULL,
+ `const02` decimal(3,1) NOT NULL default '0.0',
+ `param02` decimal(64,30) default NULL,
`const03` double NOT NULL default '0',
`param03` double default NULL,
- `const04` char(3) NOT NULL default '',
+ `const04` varchar(3) NOT NULL default '',
`param04` longtext,
- `const05` binary(3) NOT NULL default '',
+ `const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
@@ -1719,7 +1718,7 @@ t5 CREATE TABLE `t5` (
`param11` bigint(20) default NULL,
`const12` binary(0) default NULL,
`param12` bigint(20) default NULL,
- `param13` double default NULL,
+ `param13` decimal(64,30) default NULL,
`param14` longtext,
`param15` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -1727,13 +1726,13 @@ select * from t5 ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t5 t5 const01 const01 8 1 1 N 32769 0 63
def test t5 t5 param01 param01 8 20 1 Y 32768 0 63
-def test t5 t5 const02 const02 5 3 3 N 32769 1 63
-def test t5 t5 param02 param02 5 20 1 Y 32768 31 63
-def test t5 t5 const03 const03 5 23 1 N 32769 31 63
+def test t5 t5 const02 const02 246 3 3 N 1 1 63
+def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63
-def test t5 t5 const04 const04 254 3 3 N 1 0 8
+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 const05 const05 254 3 3 N 129 0 63
+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 const06 const06 253 10 10 N 1 0 8
def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
@@ -1749,13 +1748,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
-def test t5 t5 param13 param13 5 20 0 Y 32768 31 63
+def test t5 t5 param13 param13 246 64 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
const01 8
param01 8
const02 8.0
-param02 8
+param02 8.000000000000000000000000000000
const03 8
param03 8
const04 abc
@@ -1837,40 +1836,40 @@ from t9 where c1= 1 ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
@arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
@arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
@@ -1884,38 +1883,38 @@ from t9 where c1= 0 ;
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select
@@ -1934,78 +1933,78 @@ execute stmt1 using @my_key ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select ? := c1 from t9 where c1= 1" ;
@@ -2022,40 +2021,40 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 1 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
c25, c26, c27, c28, c29, c30, c31, c32
@@ -2066,38 +2065,38 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 0 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
@@ -2112,76 +2111,76 @@ set @my_key= 1 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1 into ? from t9 where c1= 1" ;
@@ -2492,12 +2491,12 @@ set @arg00= 9223372036854775807 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2509,18 +2508,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '9223372036854775807' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2532,18 +2531,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -9223372036854775808 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2561,12 +2560,12 @@ set @arg00= '-9223372036854775808' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2584,14 +2583,14 @@ set @arg00= 1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2603,7 +2602,7 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '1.11111111111111111111e+50' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@@ -2615,8 +2614,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 1
c2 1
@@ -2628,20 +2627,20 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2665,8 +2664,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -1
c2 -1
@@ -2738,10 +2737,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30
41 4 41 41 41 41 41 41 41 41 41 41
42 4 42 42 42 42 42 42 42 42 42 42
43 4 43 43 43 43 43 43 43 43 43 43
-50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00
-51 5 51 51 51 51 51 51 51 51 51 51
-52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00
-53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00
+50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0
+51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0
+52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0
+53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0
54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00
55 5 55 55 55 55 55 55 55 55 55 55
56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00
@@ -2897,45 +2896,45 @@ Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
select c1, c13, c14, c15, c16, c17 from t9 order by c1 ;
c1 c13 c14 c15 c16 c17
20 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
@@ -3067,7 +3066,7 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
+c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -3116,17 +3115,17 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63
def test t9 t9 c8 c8 5 22 1 Y 32768 31 63
def test t9 t9 c9 c9 5 22 1 Y 32768 31 63
def test t9 t9 c10 c10 5 22 1 Y 32768 31 63
-def test t9 t9 c11 c11 0 9 6 Y 32768 4 63
-def test t9 t9 c12 c12 0 10 6 Y 32768 4 63
+def test t9 t9 c11 c11 246 7 6 Y 0 4 63
+def test t9 t9 c12 c12 246 8 6 Y 0 4 63
def test t9 t9 c13 c13 10 10 10 Y 128 0 63
def test t9 t9 c14 c14 12 19 19 Y 128 0 63
def test t9 t9 c15 c15 7 19 19 N 1249 0 63
def test t9 t9 c16 c16 11 8 8 Y 128 0 63
def test t9 t9 c17 c17 13 4 4 Y 32864 0 63
-def test t9 t9 c18 c18 1 1 1 Y 32768 0 63
+def test t9 t9 c18 c18 1 4 1 Y 32768 0 63
def test t9 t9 c19 c19 1 1 1 Y 32768 0 63
def test t9 t9 c20 c20 254 1 1 Y 0 0 8
-def test t9 t9 c21 c21 253 10 10 Y 0 0 8
+def test t9 t9 c21 c21 254 10 10 Y 0 0 8
def test t9 t9 c22 c22 253 30 30 Y 0 0 8
def test t9 t9 c23 c23 252 255 8 Y 144 0 63
def test t9 t9 c24 c24 252 255 8 Y 16 0 8
@@ -4212,7 +4211,7 @@ def table 253 64 2 N 1 31 8
def type 253 10 3 N 1 31 8
def possible_keys 253 4096 0 Y 0 31 8
def key 253 64 0 Y 0 31 8
-def key_len 8 3 0 Y 32928 0 63
+def key_len 253 4096 0 Y 128 31 63
def ref 253 1024 0 Y 0 31 8
def rows 8 10 1 N 32929 0 63
def Extra 253 255 0 N 1 31 8
@@ -4263,7 +4262,6 @@ execute stmt1 using @arg00;
select a,b from t1 where b=@arg00;
a b
prepare stmt1 from 'truncate table t1' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
test_sequence
------ update tests ------
delete from t1 ;
@@ -4342,7 +4340,7 @@ set @arg00=NULL;
set @arg01=2;
execute stmt1 using @arg00, @arg01;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1
select a,b from t1 order by a;
a b
0 two
@@ -4711,13 +4709,13 @@ Table Create Table
t5 CREATE TABLE `t5` (
`const01` bigint(1) NOT NULL default '0',
`param01` bigint(20) default NULL,
- `const02` double(3,1) NOT NULL default '0.0',
- `param02` double default NULL,
+ `const02` decimal(3,1) NOT NULL default '0.0',
+ `param02` decimal(64,30) default NULL,
`const03` double NOT NULL default '0',
`param03` double default NULL,
- `const04` char(3) NOT NULL default '',
+ `const04` varchar(3) NOT NULL default '',
`param04` longtext,
- `const05` binary(3) NOT NULL default '',
+ `const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
@@ -4733,7 +4731,7 @@ t5 CREATE TABLE `t5` (
`param11` bigint(20) default NULL,
`const12` binary(0) default NULL,
`param12` bigint(20) default NULL,
- `param13` double default NULL,
+ `param13` decimal(64,30) default NULL,
`param14` longtext,
`param15` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -4741,13 +4739,13 @@ select * from t5 ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t5 t5 const01 const01 8 1 1 N 32769 0 63
def test t5 t5 param01 param01 8 20 1 Y 32768 0 63
-def test t5 t5 const02 const02 5 3 3 N 32769 1 63
-def test t5 t5 param02 param02 5 20 1 Y 32768 31 63
-def test t5 t5 const03 const03 5 23 1 N 32769 31 63
+def test t5 t5 const02 const02 246 3 3 N 1 1 63
+def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63
-def test t5 t5 const04 const04 254 3 3 N 1 0 8
+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 const05 const05 254 3 3 N 129 0 63
+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 const06 const06 253 10 10 N 1 0 8
def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
@@ -4763,13 +4761,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
-def test t5 t5 param13 param13 5 20 0 Y 32768 31 63
+def test t5 t5 param13 param13 246 64 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
const01 8
param01 8
const02 8.0
-param02 8
+param02 8.000000000000000000000000000000
const03 8
param03 8
const04 abc
@@ -4851,40 +4849,40 @@ from t9 where c1= 1 ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
@arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
@arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
@@ -4898,38 +4896,38 @@ from t9 where c1= 0 ;
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select
@@ -4948,78 +4946,78 @@ execute stmt1 using @my_key ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select ? := c1 from t9 where c1= 1" ;
@@ -5036,40 +5034,40 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 1 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
c25, c26, c27, c28, c29, c30, c31, c32
@@ -5080,38 +5078,38 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 0 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
@@ -5126,76 +5124,76 @@ set @my_key= 1 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1 into ? from t9 where c1= 1" ;
@@ -5506,12 +5504,12 @@ set @arg00= 9223372036854775807 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -5523,18 +5521,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '9223372036854775807' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -5546,18 +5544,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -9223372036854775808 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -5575,12 +5573,12 @@ set @arg00= '-9223372036854775808' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -5598,14 +5596,14 @@ set @arg00= 1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -5617,7 +5615,7 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '1.11111111111111111111e+50' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@@ -5629,8 +5627,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 1
c2 1
@@ -5642,20 +5640,20 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -5679,8 +5677,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -1
c2 -1
@@ -5752,10 +5750,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30
41 4 41 41 41 41 41 41 41 41 41 41
42 4 42 42 42 42 42 42 42 42 42 42
43 4 43 43 43 43 43 43 43 43 43 43
-50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00
-51 5 51 51 51 51 51 51 51 51 51 51
-52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00
-53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00
+50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0
+51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0
+52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0
+53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0
54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00
55 5 55 55 55 55 55 55 55 55 55 55
56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00
@@ -5911,45 +5909,45 @@ Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
select c1, c13, c14, c15, c16, c17 from t9 order by c1 ;
c1 c13 c14 c15 c16 c17
20 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result
index f69db9c1e42..8ea5b092b5e 100644
--- a/mysql-test/r/ps_6bdb.result
+++ b/mysql-test/r/ps_6bdb.result
@@ -11,7 +11,7 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
+c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -59,17 +59,17 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63
def test t9 t9 c8 c8 5 22 1 Y 32768 31 63
def test t9 t9 c9 c9 5 22 1 Y 32768 31 63
def test t9 t9 c10 c10 5 22 1 Y 32768 31 63
-def test t9 t9 c11 c11 0 9 6 Y 32768 4 63
-def test t9 t9 c12 c12 0 10 6 Y 32768 4 63
+def test t9 t9 c11 c11 246 7 6 Y 0 4 63
+def test t9 t9 c12 c12 246 8 6 Y 0 4 63
def test t9 t9 c13 c13 10 10 10 Y 128 0 63
def test t9 t9 c14 c14 12 19 19 Y 128 0 63
def test t9 t9 c15 c15 7 19 19 N 1249 0 63
def test t9 t9 c16 c16 11 8 8 Y 128 0 63
def test t9 t9 c17 c17 13 4 4 Y 32864 0 63
-def test t9 t9 c18 c18 1 1 1 Y 32768 0 63
+def test t9 t9 c18 c18 1 4 1 Y 32768 0 63
def test t9 t9 c19 c19 1 1 1 Y 32768 0 63
def test t9 t9 c20 c20 254 1 1 Y 0 0 8
-def test t9 t9 c21 c21 253 10 10 Y 0 0 8
+def test t9 t9 c21 c21 254 10 10 Y 0 0 8
def test t9 t9 c22 c22 253 30 30 Y 0 0 8
def test t9 t9 c23 c23 252 255 8 Y 144 0 63
def test t9 t9 c24 c24 252 255 8 Y 16 0 8
@@ -1155,7 +1155,7 @@ def table 253 64 2 N 1 31 8
def type 253 10 3 N 1 31 8
def possible_keys 253 4096 0 Y 0 31 8
def key 253 64 0 Y 0 31 8
-def key_len 8 3 0 Y 32928 0 63
+def key_len 253 4096 0 Y 128 31 63
def ref 253 1024 0 Y 0 31 8
def rows 8 10 1 N 32929 0 63
def Extra 253 255 0 N 1 31 8
@@ -1206,7 +1206,6 @@ execute stmt1 using @arg00;
select a,b from t1 where b=@arg00;
a b
prepare stmt1 from 'truncate table t1' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
test_sequence
------ update tests ------
delete from t1 ;
@@ -1285,7 +1284,7 @@ set @arg00=NULL;
set @arg01=2;
execute stmt1 using @arg00, @arg01;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1
select a,b from t1 order by a;
a b
0 two
@@ -1696,8 +1695,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
delete from t2 ;
prepare stmt1 from ' insert into t2 (b,a)
@@ -1715,8 +1714,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
drop table t2;
drop table if exists t5 ;
@@ -1760,13 +1759,13 @@ Table Create Table
t5 CREATE TABLE `t5` (
`const01` bigint(1) NOT NULL default '0',
`param01` bigint(20) default NULL,
- `const02` double(3,1) NOT NULL default '0.0',
- `param02` double default NULL,
+ `const02` decimal(3,1) NOT NULL default '0.0',
+ `param02` decimal(64,30) default NULL,
`const03` double NOT NULL default '0',
`param03` double default NULL,
- `const04` char(3) NOT NULL default '',
+ `const04` varchar(3) NOT NULL default '',
`param04` longtext,
- `const05` binary(3) NOT NULL default '',
+ `const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
@@ -1782,7 +1781,7 @@ t5 CREATE TABLE `t5` (
`param11` bigint(20) default NULL,
`const12` binary(0) default NULL,
`param12` bigint(20) default NULL,
- `param13` double default NULL,
+ `param13` decimal(64,30) default NULL,
`param14` longtext,
`param15` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -1790,13 +1789,13 @@ select * from t5 ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t5 t5 const01 const01 8 1 1 N 32769 0 63
def test t5 t5 param01 param01 8 20 1 Y 32768 0 63
-def test t5 t5 const02 const02 5 3 3 N 32769 1 63
-def test t5 t5 param02 param02 5 20 1 Y 32768 31 63
-def test t5 t5 const03 const03 5 23 1 N 32769 31 63
+def test t5 t5 const02 const02 246 3 3 N 1 1 63
+def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63
-def test t5 t5 const04 const04 254 3 3 N 1 0 8
+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 const05 const05 254 3 3 N 129 0 63
+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 const06 const06 253 10 10 N 1 0 8
def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
@@ -1812,13 +1811,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
-def test t5 t5 param13 param13 5 20 0 Y 32768 31 63
+def test t5 t5 param13 param13 246 64 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
const01 8
param01 8
const02 8.0
-param02 8
+param02 8.000000000000000000000000000000
const03 8
param03 8
const04 abc
@@ -1900,40 +1899,40 @@ from t9 where c1= 1 ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
@arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
@arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
@@ -1947,38 +1946,38 @@ from t9 where c1= 0 ;
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select
@@ -1997,78 +1996,78 @@ execute stmt1 using @my_key ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select ? := c1 from t9 where c1= 1" ;
@@ -2085,40 +2084,40 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 1 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
c25, c26, c27, c28, c29, c30, c31, c32
@@ -2129,38 +2128,38 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 0 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
@@ -2175,76 +2174,76 @@ set @my_key= 1 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1 into ? from t9 where c1= 1" ;
@@ -2555,12 +2554,12 @@ set @arg00= 9223372036854775807 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2572,18 +2571,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '9223372036854775807' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2595,18 +2594,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -9223372036854775808 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2624,12 +2623,12 @@ set @arg00= '-9223372036854775808' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2647,14 +2646,14 @@ set @arg00= 1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2666,7 +2665,7 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '1.11111111111111111111e+50' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@@ -2678,8 +2677,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 1
c2 1
@@ -2691,20 +2690,20 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2728,8 +2727,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -1
c2 -1
@@ -2801,10 +2800,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30
41 4 41 41 41 41 41 41 41 41 41 41
42 4 42 42 42 42 42 42 42 42 42 42
43 4 43 43 43 43 43 43 43 43 43 43
-50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00
-51 5 51 51 51 51 51 51 51 51 51 51
-52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00
-53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00
+50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0
+51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0
+52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0
+53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0
54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00
55 5 55 55 55 55 55 55 55 55 55 55
56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00
@@ -2960,45 +2959,45 @@ Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
select c1, c13, c14, c15, c16, c17 from t9 order by c1 ;
c1 c13 c14 c15 c16 c17
20 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result
index e7a4ff40e2b..ec8c47031c1 100644
--- a/mysql-test/r/ps_7ndb.result
+++ b/mysql-test/r/ps_7ndb.result
@@ -11,7 +11,7 @@ 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,
-c17 year, c18 bit, c19 bool, c20 char,
+c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -59,17 +59,17 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63
def test t9 t9 c8 c8 5 22 1 Y 32768 31 63
def test t9 t9 c9 c9 5 22 1 Y 32768 31 63
def test t9 t9 c10 c10 5 22 1 Y 32768 31 63
-def test t9 t9 c11 c11 0 9 6 Y 32768 4 63
-def test t9 t9 c12 c12 0 10 6 Y 32768 4 63
+def test t9 t9 c11 c11 246 7 6 Y 0 4 63
+def test t9 t9 c12 c12 246 8 6 Y 0 4 63
def test t9 t9 c13 c13 10 10 10 Y 128 0 63
def test t9 t9 c14 c14 12 19 19 Y 128 0 63
def test t9 t9 c15 c15 7 19 19 N 1249 0 63
def test t9 t9 c16 c16 11 8 8 Y 128 0 63
def test t9 t9 c17 c17 13 4 4 Y 32864 0 63
-def test t9 t9 c18 c18 1 1 1 Y 32768 0 63
+def test t9 t9 c18 c18 1 4 1 Y 32768 0 63
def test t9 t9 c19 c19 1 1 1 Y 32768 0 63
def test t9 t9 c20 c20 254 1 1 Y 0 0 8
-def test t9 t9 c21 c21 253 10 10 Y 0 0 8
+def test t9 t9 c21 c21 254 10 10 Y 0 0 8
def test t9 t9 c22 c22 253 30 30 Y 0 0 8
def test t9 t9 c23 c23 252 255 8 Y 144 0 63
def test t9 t9 c24 c24 252 255 8 Y 16 0 8
@@ -1155,7 +1155,7 @@ def table 253 64 2 N 1 31 8
def type 253 10 3 N 1 31 8
def possible_keys 253 4096 0 Y 0 31 8
def key 253 64 0 Y 0 31 8
-def key_len 8 3 0 Y 32928 0 63
+def key_len 253 4096 0 Y 128 31 63
def ref 253 1024 0 Y 0 31 8
def rows 8 10 1 N 32929 0 63
def Extra 253 255 0 N 1 31 8
@@ -1206,7 +1206,6 @@ execute stmt1 using @arg00;
select a,b from t1 where b=@arg00;
a b
prepare stmt1 from 'truncate table t1' ;
-ERROR HY000: This command is not supported in the prepared statement protocol yet
test_sequence
------ update tests ------
delete from t1 ;
@@ -1285,7 +1284,7 @@ set @arg00=NULL;
set @arg01=2;
execute stmt1 using @arg00, @arg01;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1
select a,b from t1 order by a;
a b
0 two
@@ -1696,8 +1695,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
delete from t2 ;
prepare stmt1 from ' insert into t2 (b,a)
@@ -1715,8 +1714,8 @@ affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
select a,b from t2 order by a ;
a b
-3 duplicate
-4 duplicate
+3 duplicate
+4 duplicate
103 three
drop table t2;
drop table if exists t5 ;
@@ -1760,13 +1759,13 @@ Table Create Table
t5 CREATE TABLE `t5` (
`const01` bigint(1) NOT NULL default '0',
`param01` bigint(20) default NULL,
- `const02` double(3,1) NOT NULL default '0.0',
- `param02` double default NULL,
+ `const02` decimal(3,1) NOT NULL default '0.0',
+ `param02` decimal(64,30) default NULL,
`const03` double NOT NULL default '0',
`param03` double default NULL,
- `const04` char(3) NOT NULL default '',
+ `const04` varchar(3) NOT NULL default '',
`param04` longtext,
- `const05` binary(3) NOT NULL default '',
+ `const05` varbinary(3) NOT NULL default '',
`param05` longblob,
`const06` varchar(10) NOT NULL default '',
`param06` longtext,
@@ -1782,7 +1781,7 @@ t5 CREATE TABLE `t5` (
`param11` bigint(20) default NULL,
`const12` binary(0) default NULL,
`param12` bigint(20) default NULL,
- `param13` double default NULL,
+ `param13` decimal(64,30) default NULL,
`param14` longtext,
`param15` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -1790,13 +1789,13 @@ select * from t5 ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t5 t5 const01 const01 8 1 1 N 32769 0 63
def test t5 t5 param01 param01 8 20 1 Y 32768 0 63
-def test t5 t5 const02 const02 5 3 3 N 32769 1 63
-def test t5 t5 param02 param02 5 20 1 Y 32768 31 63
-def test t5 t5 const03 const03 5 23 1 N 32769 31 63
+def test t5 t5 const02 const02 246 3 3 N 1 1 63
+def test t5 t5 param02 param02 246 64 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 20 1 Y 32768 31 63
-def test t5 t5 const04 const04 254 3 3 N 1 0 8
+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 const05 const05 254 3 3 N 129 0 63
+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 const06 const06 253 10 10 N 1 0 8
def test t5 t5 param06 param06 252 16777215 10 Y 16 0 8
@@ -1812,13 +1811,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
-def test t5 t5 param13 param13 5 20 0 Y 32768 31 63
+def test t5 t5 param13 param13 246 64 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
const01 8
param01 8
const02 8.0
-param02 8
+param02 8.000000000000000000000000000000
const03 8
param03 8
const04 abc
@@ -1900,40 +1899,40 @@ from t9 where c1= 1 ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
@arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
@arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
@@ -1947,38 +1946,38 @@ from t9 where c1= 0 ;
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select
@@ -1997,78 +1996,78 @@ execute stmt1 using @my_key ;
1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select ? := c1 from t9 where c1= 1" ;
@@ -2085,40 +2084,40 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 1 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
c25, c26, c27, c28, c29, c30, c31, c32
@@ -2129,38 +2128,38 @@ into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
from t9 where c1= 0 ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
@@ -2175,76 +2174,76 @@ set @my_key= 1 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 1 Y 128 31 63
-def @arg03 254 20 1 Y 128 31 63
-def @arg04 254 20 1 Y 128 31 63
-def @arg05 254 20 1 Y 128 31 63
-def @arg06 254 20 1 Y 128 31 63
-def @arg07 254 20 1 Y 128 31 63
-def @arg08 254 20 1 Y 128 31 63
-def @arg09 254 20 1 Y 128 31 63
-def @arg10 254 20 1 Y 128 31 63
-def @arg11 254 20 1 Y 128 31 63
-def @arg12 254 20 1 Y 128 31 63
-def @arg13 254 8192 10 Y 128 31 63
-def @arg14 254 8192 19 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 8 Y 128 31 63
-def @arg17 254 20 4 Y 128 31 63
-def @arg18 254 20 1 Y 128 31 63
-def @arg19 254 20 1 Y 128 31 63
-def @arg20 254 8192 1 Y 0 31 8
-def @arg21 254 8192 10 Y 0 31 8
-def @arg22 254 8192 30 Y 0 31 8
-def @arg23 254 8192 8 Y 128 31 63
-def @arg24 254 8192 8 Y 0 31 8
-def @arg25 254 8192 4 Y 128 31 63
-def @arg26 254 8192 4 Y 0 31 8
-def @arg27 254 8192 10 Y 128 31 63
-def @arg28 254 8192 10 Y 0 31 8
-def @arg29 254 8192 8 Y 128 31 63
-def @arg30 254 8192 8 Y 0 31 8
-def @arg31 254 8192 3 Y 0 31 8
-def @arg32 254 8192 6 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 1 Y 128 31 63
+def @arg03 253 20 1 Y 128 31 63
+def @arg04 253 20 1 Y 128 31 63
+def @arg05 253 20 1 Y 128 31 63
+def @arg06 253 20 1 Y 128 31 63
+def @arg07 253 20 1 Y 128 31 63
+def @arg08 253 20 1 Y 128 31 63
+def @arg09 253 20 1 Y 128 31 63
+def @arg10 253 20 1 Y 128 31 63
+def @arg11 253 64 6 Y 128 30 63
+def @arg12 253 64 6 Y 128 30 63
+def @arg13 253 8192 10 Y 128 31 63
+def @arg14 253 8192 19 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 8 Y 128 31 63
+def @arg17 253 20 4 Y 128 31 63
+def @arg18 253 20 1 Y 128 31 63
+def @arg19 253 20 1 Y 128 31 63
+def @arg20 253 8192 1 Y 0 31 8
+def @arg21 253 8192 10 Y 0 31 8
+def @arg22 253 8192 30 Y 0 31 8
+def @arg23 253 8192 8 Y 128 31 63
+def @arg24 253 8192 8 Y 0 31 8
+def @arg25 253 8192 4 Y 128 31 63
+def @arg26 253 8192 4 Y 0 31 8
+def @arg27 253 8192 10 Y 128 31 63
+def @arg28 253 8192 10 Y 0 31 8
+def @arg29 253 8192 8 Y 128 31 63
+def @arg30 253 8192 8 Y 0 31 8
+def @arg31 253 8192 3 Y 0 31 8
+def @arg32 253 8192 6 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
-1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
set @my_key= 0 ;
execute stmt1 using @my_key ;
execute full_info ;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @arg01 254 20 1 Y 128 31 63
-def @arg02 254 20 0 Y 128 31 63
-def @arg03 254 20 0 Y 128 31 63
-def @arg04 254 20 0 Y 128 31 63
-def @arg05 254 20 0 Y 128 31 63
-def @arg06 254 20 0 Y 128 31 63
-def @arg07 254 20 0 Y 128 31 63
-def @arg08 254 20 0 Y 128 31 63
-def @arg09 254 20 0 Y 128 31 63
-def @arg10 254 20 0 Y 128 31 63
-def @arg11 254 20 0 Y 128 31 63
-def @arg12 254 20 0 Y 128 31 63
-def @arg13 254 8192 0 Y 128 31 63
-def @arg14 254 8192 0 Y 128 31 63
-def @arg15 254 8192 19 Y 128 31 63
-def @arg16 254 8192 0 Y 128 31 63
-def @arg17 254 20 0 Y 128 31 63
-def @arg18 254 20 0 Y 128 31 63
-def @arg19 254 20 0 Y 128 31 63
-def @arg20 254 8192 0 Y 0 31 8
-def @arg21 254 8192 0 Y 0 31 8
-def @arg22 254 8192 0 Y 0 31 8
-def @arg23 254 8192 0 Y 128 31 63
-def @arg24 254 8192 0 Y 0 31 8
-def @arg25 254 8192 0 Y 128 31 63
-def @arg26 254 8192 0 Y 0 31 8
-def @arg27 254 8192 0 Y 128 31 63
-def @arg28 254 8192 0 Y 0 31 8
-def @arg29 254 8192 0 Y 128 31 63
-def @arg30 254 8192 0 Y 0 31 8
-def @arg31 254 8192 0 Y 0 31 8
-def @arg32 254 8192 0 Y 0 31 8
+def @arg01 253 20 1 Y 128 31 63
+def @arg02 253 20 0 Y 128 31 63
+def @arg03 253 20 0 Y 128 31 63
+def @arg04 253 20 0 Y 128 31 63
+def @arg05 253 20 0 Y 128 31 63
+def @arg06 253 20 0 Y 128 31 63
+def @arg07 253 20 0 Y 128 31 63
+def @arg08 253 20 0 Y 128 31 63
+def @arg09 253 20 0 Y 128 31 63
+def @arg10 253 20 0 Y 128 31 63
+def @arg11 253 64 0 Y 128 30 63
+def @arg12 253 64 0 Y 128 30 63
+def @arg13 253 8192 0 Y 128 31 63
+def @arg14 253 8192 0 Y 128 31 63
+def @arg15 253 8192 19 Y 128 31 63
+def @arg16 253 8192 0 Y 128 31 63
+def @arg17 253 20 0 Y 128 31 63
+def @arg18 253 20 0 Y 128 31 63
+def @arg19 253 20 0 Y 128 31 63
+def @arg20 253 8192 0 Y 0 31 8
+def @arg21 253 8192 0 Y 0 31 8
+def @arg22 253 8192 0 Y 0 31 8
+def @arg23 253 8192 0 Y 128 31 63
+def @arg24 253 8192 0 Y 0 31 8
+def @arg25 253 8192 0 Y 128 31 63
+def @arg26 253 8192 0 Y 0 31 8
+def @arg27 253 8192 0 Y 128 31 63
+def @arg28 253 8192 0 Y 0 31 8
+def @arg29 253 8192 0 Y 128 31 63
+def @arg30 253 8192 0 Y 0 31 8
+def @arg31 253 8192 0 Y 0 31 8
+def @arg32 253 8192 0 Y 0 31 8
@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
prepare stmt1 from "select c1 into ? from t9 where c1= 1" ;
@@ -2555,12 +2554,12 @@ set @arg00= 9223372036854775807 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2572,18 +2571,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '9223372036854775807' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2595,18 +2594,18 @@ c7 9.22337e+18
c8 9.22337203685478e+18
c9 9.22337203685478e+18
c10 9.22337203685478e+18
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -9223372036854775808 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2624,12 +2623,12 @@ set @arg00= '-9223372036854775808' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1265 Data truncated for column 'c4' at row 1
-Warning 1265 Data truncated for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2647,14 +2646,14 @@ set @arg00= 1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 127
c2 32767
@@ -2666,7 +2665,7 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= '1.11111111111111111111e+50' ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@@ -2678,8 +2677,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 1
c2 1
@@ -2691,20 +2690,20 @@ c7 3.40282e+38
c8 1.11111111111111e+50
c9 1.11111111111111e+50
c10 1.11111111111111e+50
-c12 99999.9999
+c12 9999.9999
execute my_delete ;
set @arg00= -1.11111111111111111111e+50 ;
execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
@arg00, @arg00, @arg00, @arg00, @arg00 ;
Warnings:
-Warning 1264 Data truncated; out of range for column 'c1' at row 1
-Warning 1264 Data truncated; out of range for column 'c2' at row 1
-Warning 1264 Data truncated; out of range for column 'c3' at row 1
-Warning 1264 Data truncated; out of range for column 'c4' at row 1
-Warning 1264 Data truncated; out of range for column 'c5' at row 1
-Warning 1264 Data truncated; out of range for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c1' at row 1
+Warning 1264 Out of range value adjusted for column 'c2' at row 1
+Warning 1264 Out of range value adjusted for column 'c3' at row 1
+Warning 1264 Out of range value adjusted for column 'c4' at row 1
+Warning 1264 Out of range value adjusted for column 'c5' at row 1
+Warning 1264 Out of range value adjusted for column 'c6' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -128
c2 -32768
@@ -2728,8 +2727,8 @@ Warning 1265 Data truncated for column 'c3' at row 1
Warning 1265 Data truncated for column 'c4' at row 1
Warning 1265 Data truncated for column 'c5' at row 1
Warning 1265 Data truncated for column 'c6' at row 1
-Warning 1264 Data truncated; out of range for column 'c7' at row 1
-Warning 1264 Data truncated; out of range for column 'c12' at row 1
+Warning 1264 Out of range value adjusted for column 'c7' at row 1
+Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ;
c1 -1
c2 -1
@@ -2801,10 +2800,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30
41 4 41 41 41 41 41 41 41 41 41 41
42 4 42 42 42 42 42 42 42 42 42 42
43 4 43 43 43 43 43 43 43 43 43 43
-50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00
-51 5 51 51 51 51 51 51 51 51 51 51
-52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00
-53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00
+50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0
+51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0
+52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0
+53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0
54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00
55 5 55 55 55 55 55 55 55 55 55 55
56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00
@@ -2960,45 +2959,45 @@ Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
-Warning 1264 Data truncated; out of range for column 'c13' at row 1
+Warning 1264 Out of range value adjusted for column 'c13' at row 1
Warning 1265 Data truncated for column 'c14' at row 1
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
Warnings:
Warning 1265 Data truncated for column 'c15' at row 1
-Warning 1264 Data truncated; out of range for column 'c16' at row 1
-Warning 1264 Data truncated; out of range for column 'c17' at row 1
+Warning 1264 Out of range value adjusted for column 'c16' at row 1
+Warning 1264 Out of range value adjusted for column 'c17' at row 1
select c1, c13, c14, c15, c16, c17 from t9 order by c1 ;
c1 c13 c14 c15 c16 c17
20 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
diff --git a/mysql-test/r/ps_grant.result b/mysql-test/r/ps_grant.result
index 4c60bb03165..3a302ba3ba8 100644
--- a/mysql-test/r/ps_grant.result
+++ b/mysql-test/r/ps_grant.result
@@ -36,19 +36,19 @@ identified by 'looser' ;
show grants for second_user@localhost ;
Grants for second_user@localhost
GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3'
-GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost'
+GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
drop table mysqltest.t9 ;
show grants for second_user@localhost ;
Grants for second_user@localhost
GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3'
-GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost'
+GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
show grants for second_user@localhost ;
Grants for second_user@localhost
GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3'
-GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost'
+GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost'
prepare s_t1 from 'select a as my_col from t1' ;
execute s_t1 ;
my_col
@@ -79,3 +79,15 @@ commit ;
show grants for second_user@localhost ;
ERROR 42000: There is no such grant defined for user 'second_user' on host 'localhost'
drop database mysqltest;
+prepare stmt3 from ' grant all on test.t1 to drop_user@localhost
+identified by ''looser'' ';
+ERROR HY000: This command is not supported in the prepared statement protocol yet
+grant all on test.t1 to drop_user@localhost
+identified by 'looser' ;
+prepare stmt3 from ' revoke all privileges on test.t1 from
+drop_user@localhost ';
+ERROR HY000: This command is not supported in the prepared statement protocol yet
+revoke all privileges on test.t1 from drop_user@localhost ;
+prepare stmt3 from ' drop user drop_user@localhost ';
+ERROR HY000: This command is not supported in the prepared statement protocol yet
+drop user drop_user@localhost;
diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
index 5385eec6da3..8db57104477 100644
--- a/mysql-test/r/query_cache.result
+++ b/mysql-test/r/query_cache.result
@@ -307,7 +307,7 @@ explain extended select benchmark(1,1) from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select sql_no_cache benchmark(1,1) AS `benchmark(1,1)` from test.t1
+Note 1003 select sql_no_cache benchmark(1,1) AS `benchmark(1,1)` from `test`.`t1`
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
@@ -924,6 +924,42 @@ group_concat(a)
12345678901234567890
set group_concat_max_len=default;
drop table t1;
+create table t1 (a int);
+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 19
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 6
+/**/ select * from t1;
+a
+/**/ select * from t1;
+a
+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 20
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+DROP TABLE t1;
+SET GLOBAL query_cache_size=0;
+SET SESSION query_cache_type = 2;
+create table t1(a int);
+select table_name from information_schema.tables
+where table_schema="test";
+table_name
+t1
+drop table t1;
+select table_name from information_schema.tables
+where table_schema="test";
+table_name
+SET SESSION query_cache_type = 1;
set global query_cache_size=1024*1024;
flush query cache;
create table t1 ( a int );
diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result
index afd91ce5fe9..fea5754d704 100644
--- a/mysql-test/r/range.result
+++ b/mysql-test/r/range.result
@@ -218,26 +218,26 @@ drop table t1;
create table t1 (x int, y int, index(x), index(y));
insert into t1 (x) values (1),(2),(3),(4),(5),(6),(7),(8),(9);
update t1 set y=x;
-explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 7 and t1.y+0;
+explain select * from t1, t1 t2 where t1.y = 8 and t2.x between 7 and t1.y+0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref y y 5 const 1 Using where
-1 SIMPLE t2 range x x 5 NULL 4 Range checked for each record (index map: 0x1)
-explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= 7 and t2.x <= t1.y+0;
+1 SIMPLE t2 range x x 5 NULL 2 Using where
+explain select * from t1, t1 t2 where t1.y = 8 and t2.x >= 7 and t2.x <= t1.y+0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref y y 5 const 1 Using where
-1 SIMPLE t2 range x x 5 NULL 4 Using where
+1 SIMPLE t2 range x x 5 NULL 2 Using where
explain select * from t1, t1 t2 where t1.y = 2 and t2.x between t1.y-1 and t1.y+1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref y y 5 const 1 Using where
-1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1)
+1 SIMPLE t2 range x x 5 NULL 3 Using where
explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= t1.y-1 and t2.x <= t1.y+1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref y y 5 const 1 Using where
-1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1)
+1 SIMPLE t2 range x x 5 NULL 3 Using where
explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 0 and t1.y;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref y y 5 const 1 Using where
-1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1)
+1 SIMPLE t2 range x x 5 NULL 2 Using where
explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= 0 and t2.x <= t1.y;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref y y 5 const 1 Using where
@@ -247,16 +247,21 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref x x 5 const 1 Using where; Using index
explain select count(*) from t1 where x in (1,2);
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 range x x 5 NULL 2 Using where; Using index
+1 SIMPLE t1 index x x 5 NULL 9 Using where; Using index
drop table t1;
CREATE TABLE t1 (key1 int(11) NOT NULL default '0', KEY i1 (key1));
-INSERT INTO t1 VALUES (0),(0),(1),(1);
+INSERT INTO t1 VALUES (0),(0),(0),(0),(0),(1),(1);
CREATE TABLE t2 (keya int(11) NOT NULL default '0', KEY j1 (keya));
INSERT INTO t2 VALUES (0),(0),(1),(1),(2),(2);
explain select * from t1, t2 where (t1.key1 <t2.keya + 1) and t2.keya=3;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ref j1 j1 4 const 1 Using where; Using index
-1 SIMPLE t1 ALL i1 NULL NULL NULL 4 Range checked for each record (index map: 0x1)
+1 SIMPLE t2 ref j1 j1 4 const 1 Using index
+1 SIMPLE t1 index i1 i1 4 NULL 7 Using where; Using index
+explain select * from t1 force index(i1), t2 force index(j1) where
+(t1.key1 <t2.keya + 1) and t2.keya=3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ref j1 j1 4 const 1 Using index
+1 SIMPLE t1 index i1 i1 4 NULL 7 Using where; Using index
DROP TABLE t1,t2;
CREATE TABLE t1 (
a int(11) default NULL,
@@ -410,14 +415,26 @@ count(*)
select count(*) from t2;
count(*)
1026
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status Table is already up to date
explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range uid_index uid_index 4 NULL 128 Using where
1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38
+explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid > 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range uid_index uid_index 4 NULL 128 Using where
+1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38
explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range uid_index uid_index 4 NULL 129 Using where
1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38
+explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid != 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range uid_index uid_index 4 NULL 129 Using where
+1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38
select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0;
id name uid id name uid
1001 A 1 1001 A 1
@@ -531,36 +548,7 @@ count(*)
select count(*) from t2 where x = 18446744073709551601;
count(*)
0
-drop table t1;
-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(*)
-1
-select count(*) from t1 where x = 18446744073709551601;
-count(*)
-1
-drop table t1;
+drop table t1,t2;
set names latin1;
create table t1 (a char(10), b text, key (a)) character set latin1;
INSERT INTO t1 (a) VALUES
diff --git a/mysql-test/r/repair.result b/mysql-test/r/repair.result
index dbca5c39a6c..d8fa4dbbb72 100644
--- a/mysql-test/r/repair.result
+++ b/mysql-test/r/repair.result
@@ -27,11 +27,15 @@ drop table t1;
repair table t1 use_frm;
Table Op Msg_type Msg_text
test.t1 repair error Table 'test.t1' doesn't exist
+Warnings:
+Error 1146 Table 'test.t1' doesn't exist
create table t1 engine=myisam SELECT 1,"table 1";
flush tables;
repair table t1;
Table Op Msg_type Msg_text
-test.t1 repair error Can't open file: 't1.MYI' (errno: 130)
+test.t1 repair error Incorrect file format 't1'
+Warnings:
+Error 130 Incorrect file format 't1'
repair table t1 use_frm;
Table Op Msg_type Msg_text
test.t1 repair warning Number of rows changed from 0 to 1
diff --git a/mysql-test/r/replace.result b/mysql-test/r/replace.result
index 83cde76215a..a7d59fcfa62 100644
--- a/mysql-test/r/replace.result
+++ b/mysql-test/r/replace.result
@@ -3,12 +3,10 @@ CREATE TABLE t1 (
gesuchnr int(11) DEFAULT '0' NOT NULL,
benutzer_id int(11) DEFAULT '0' NOT NULL,
PRIMARY KEY (gesuchnr,benutzer_id)
-) engine=ISAM;
+);
replace into t1 (gesuchnr,benutzer_id) values (2,1);
replace into t1 (gesuchnr,benutzer_id) values (1,1);
replace into t1 (gesuchnr,benutzer_id) values (1,1);
-alter table t1 engine=myisam;
-replace into t1 (gesuchnr,benutzer_id) values (1,1);
alter table t1 engine=heap;
replace into t1 (gesuchnr,benutzer_id) values (1,1);
drop table t1;
diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result
index 76d6fa13766..f7f7e3e8429 100644
--- a/mysql-test/r/row.result
+++ b/mysql-test/r/row.result
@@ -14,12 +14,17 @@ row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3))
select row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a'));
row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a'))
1
-select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3));
-row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3))
-1
+Warnings:
+Warning 1292 Truncated incorrect DECIMAL value: 'a'
+Warning 1292 Truncated incorrect INTEGER value: 'a'
select row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3));
row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3))
1
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: 'a'
+select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3));
+row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3))
+1
select row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3));
row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3))
1
diff --git a/mysql-test/r/rowid_order_bdb.result b/mysql-test/r/rowid_order_bdb.result
new file mode 100644
index 00000000000..bbdc6f6ff77
--- /dev/null
+++ b/mysql-test/r/rowid_order_bdb.result
@@ -0,0 +1,186 @@
+drop table if exists t1, t2, t3,t4;
+create table t1 (
+pk1 int not NULL,
+key1 int(11),
+key2 int(11),
+PRIMARY KEY (pk1),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=bdb;
+insert into t1 values (-5, 1, 1),
+(-100, 1, 1),
+(3, 1, 1),
+(0, 1, 1),
+(10, 1, 1);
+explain select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 5 Using sort_union(key1,key2); Using where
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 key1 key2
+-100 1 1
+-5 1 1
+0 1 1
+3 1 1
+10 1 1
+drop table t1;
+create table t1 (
+pk1 int unsigned not NULL,
+key1 int(11),
+key2 int(11),
+PRIMARY KEY (pk1),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=bdb;
+insert into t1 values (0, 1, 1),
+(0xFFFFFFFF, 1, 1),
+(0xFFFFFFFE, 1, 1),
+(1, 1, 1),
+(2, 1, 1);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 key1 key2
+0 1 1
+1 1 1
+2 1 1
+4294967294 1 1
+4294967295 1 1
+drop table t1;
+create table t1 (
+pk1 char(4) not NULL,
+key1 int(11),
+key2 int(11),
+PRIMARY KEY (pk1),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=bdb collate latin2_general_ci;
+insert into t1 values ('a1', 1, 1),
+('b2', 1, 1),
+('A3', 1, 1),
+('B4', 1, 1);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 key1 key2
+a1 1 1
+A3 1 1
+b2 1 1
+B4 1 1
+drop table t1;
+create table t1 (
+pk1 int not NULL,
+pk2 char(4) not NULL collate latin1_german1_ci,
+pk3 char(4) not NULL collate latin1_bin,
+key1 int(11),
+key2 int(11),
+PRIMARY KEY (pk1,pk2,pk3),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=bdb;
+insert into t1 values
+(1, 'u', 'u', 1, 1),
+(1, 'u', char(0xEC), 1, 1),
+(1, 'u', 'x', 1, 1);
+insert ignore into t1 select pk1, char(0xEC), pk3, key1, key2 from t1;
+insert ignore into t1 select pk1, 'x', pk3, key1, key2 from t1 where pk2='u';
+insert ignore into t1 select 2, pk2, pk3, key1, key2 from t1;
+select * from t1;
+pk1 pk2 pk3 key1 key2
+1 ì u 1 1
+1 ì x 1 1
+1 ì ì 1 1
+1 u u 1 1
+1 u x 1 1
+1 u ì 1 1
+1 x u 1 1
+1 x x 1 1
+1 x ì 1 1
+2 ì u 1 1
+2 ì x 1 1
+2 ì ì 1 1
+2 u u 1 1
+2 u x 1 1
+2 u ì 1 1
+2 x u 1 1
+2 x x 1 1
+2 x ì 1 1
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 pk2 pk3 key1 key2
+1 ì u 1 1
+1 ì x 1 1
+1 ì ì 1 1
+1 u u 1 1
+1 u x 1 1
+1 u ì 1 1
+1 x u 1 1
+1 x x 1 1
+1 x ì 1 1
+2 ì u 1 1
+2 ì x 1 1
+2 ì ì 1 1
+2 u u 1 1
+2 u x 1 1
+2 u ì 1 1
+2 x u 1 1
+2 x x 1 1
+2 x ì 1 1
+alter table t1 drop primary key;
+select * from t1;
+pk1 pk2 pk3 key1 key2
+1 ì u 1 1
+1 ì x 1 1
+1 ì ì 1 1
+1 u u 1 1
+1 u x 1 1
+1 u ì 1 1
+1 x u 1 1
+1 x x 1 1
+1 x ì 1 1
+2 ì u 1 1
+2 ì x 1 1
+2 ì ì 1 1
+2 u u 1 1
+2 u x 1 1
+2 u ì 1 1
+2 x u 1 1
+2 x x 1 1
+2 x ì 1 1
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 pk2 pk3 key1 key2
+1 ì u 1 1
+1 ì x 1 1
+1 ì ì 1 1
+1 u u 1 1
+1 u x 1 1
+1 u ì 1 1
+1 x u 1 1
+1 x x 1 1
+1 x ì 1 1
+2 ì u 1 1
+2 ì x 1 1
+2 ì ì 1 1
+2 u u 1 1
+2 u x 1 1
+2 u ì 1 1
+2 x u 1 1
+2 x x 1 1
+2 x ì 1 1
+drop table t1;
+create table t1 (
+pk1 varchar(8) NOT NULL default '',
+pk2 varchar(4) NOT NULL default '',
+key1 int(11),
+key2 int(11),
+primary key(pk1, pk2),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=bdb;
+insert into t1 values ('','empt',2,2),
+('a','a--a',2,2),
+('bb','b--b',2,2),
+('ccc','c--c',2,2),
+('dddd','d--d',2,2);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 pk2 key1 key2
+ empt 2 2
+a a--a 2 2
+bb b--b 2 2
+ccc c--c 2 2
+dddd d--d 2 2
+drop table t1;
diff --git a/mysql-test/r/rowid_order_innodb.result b/mysql-test/r/rowid_order_innodb.result
new file mode 100644
index 00000000000..d55029f9064
--- /dev/null
+++ b/mysql-test/r/rowid_order_innodb.result
@@ -0,0 +1,186 @@
+drop table if exists t1, t2, t3,t4;
+create table t1 (
+pk1 int not NULL,
+key1 int(11),
+key2 int(11),
+PRIMARY KEY (pk1),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=innodb;
+insert into t1 values (-5, 1, 1),
+(-100, 1, 1),
+(3, 1, 1),
+(0, 1, 1),
+(10, 1, 1);
+explain select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 4 Using sort_union(key1,key2); Using where
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 key1 key2
+-100 1 1
+-5 1 1
+0 1 1
+3 1 1
+10 1 1
+drop table t1;
+create table t1 (
+pk1 int unsigned not NULL,
+key1 int(11),
+key2 int(11),
+PRIMARY KEY (pk1),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=innodb;
+insert into t1 values (0, 1, 1),
+(0xFFFFFFFF, 1, 1),
+(0xFFFFFFFE, 1, 1),
+(1, 1, 1),
+(2, 1, 1);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 key1 key2
+0 1 1
+1 1 1
+2 1 1
+4294967294 1 1
+4294967295 1 1
+drop table t1;
+create table t1 (
+pk1 char(4) not NULL,
+key1 int(11),
+key2 int(11),
+PRIMARY KEY (pk1),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=innodb collate latin2_general_ci;
+insert into t1 values ('a1', 1, 1),
+('b2', 1, 1),
+('A3', 1, 1),
+('B4', 1, 1);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 key1 key2
+a1 1 1
+A3 1 1
+b2 1 1
+B4 1 1
+drop table t1;
+create table t1 (
+pk1 int not NULL,
+pk2 char(4) not NULL collate latin1_german1_ci,
+pk3 char(4) not NULL collate latin1_bin,
+key1 int(11),
+key2 int(11),
+PRIMARY KEY (pk1,pk2,pk3),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=innodb;
+insert into t1 values
+(1, 'u', 'u', 1, 1),
+(1, 'u', char(0xEC), 1, 1),
+(1, 'u', 'x', 1, 1);
+insert ignore into t1 select pk1, char(0xEC), pk3, key1, key2 from t1;
+insert ignore into t1 select pk1, 'x', pk3, key1, key2 from t1 where pk2='u';
+insert ignore into t1 select 2, pk2, pk3, key1, key2 from t1;
+select * from t1;
+pk1 pk2 pk3 key1 key2
+1 ì u 1 1
+1 ì x 1 1
+1 ì ì 1 1
+1 u u 1 1
+1 u x 1 1
+1 u ì 1 1
+1 x u 1 1
+1 x x 1 1
+1 x ì 1 1
+2 ì u 1 1
+2 ì x 1 1
+2 ì ì 1 1
+2 u u 1 1
+2 u x 1 1
+2 u ì 1 1
+2 x u 1 1
+2 x x 1 1
+2 x ì 1 1
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 pk2 pk3 key1 key2
+1 ì u 1 1
+1 ì x 1 1
+1 ì ì 1 1
+1 u u 1 1
+1 u x 1 1
+1 u ì 1 1
+1 x u 1 1
+1 x x 1 1
+1 x ì 1 1
+2 ì u 1 1
+2 ì x 1 1
+2 ì ì 1 1
+2 u u 1 1
+2 u x 1 1
+2 u ì 1 1
+2 x u 1 1
+2 x x 1 1
+2 x ì 1 1
+alter table t1 drop primary key;
+select * from t1;
+pk1 pk2 pk3 key1 key2
+1 ì u 1 1
+1 ì x 1 1
+1 ì ì 1 1
+1 u u 1 1
+1 u x 1 1
+1 u ì 1 1
+1 x u 1 1
+1 x x 1 1
+1 x ì 1 1
+2 ì u 1 1
+2 ì x 1 1
+2 ì ì 1 1
+2 u u 1 1
+2 u x 1 1
+2 u ì 1 1
+2 x u 1 1
+2 x x 1 1
+2 x ì 1 1
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 pk2 pk3 key1 key2
+1 ì u 1 1
+1 ì x 1 1
+1 ì ì 1 1
+1 u u 1 1
+1 u x 1 1
+1 u ì 1 1
+1 x u 1 1
+1 x x 1 1
+1 x ì 1 1
+2 ì u 1 1
+2 ì x 1 1
+2 ì ì 1 1
+2 u u 1 1
+2 u x 1 1
+2 u ì 1 1
+2 x u 1 1
+2 x x 1 1
+2 x ì 1 1
+drop table t1;
+create table t1 (
+pk1 varchar(8) NOT NULL default '',
+pk2 varchar(4) NOT NULL default '',
+key1 int(11),
+key2 int(11),
+primary key(pk1, pk2),
+KEY key1 (key1),
+KEY key2 (key2)
+) engine=innodb;
+insert into t1 values ('','empt',2,2),
+('a','a--a',2,2),
+('bb','b--b',2,2),
+('ccc','c--c',2,2),
+('dddd','d--d',2,2);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+pk1 pk2 key1 key2
+a a--a 2 2
+bb b--b 2 2
+ccc c--c 2 2
+dddd d--d 2 2
+ empt 2 2
+drop table t1;
diff --git a/mysql-test/r/rpl000001.result b/mysql-test/r/rpl000001.result
index eef986d8f8c..450e728090e 100644
--- a/mysql-test/r/rpl000001.result
+++ b/mysql-test/r/rpl000001.result
@@ -33,27 +33,12 @@ select sum(length(word)) from t1;
sum(length(word))
1022
drop table t1,t3;
+create table t1 (n int) engine=myisam;
reset master;
stop slave;
reset slave;
-create table t1(n int);
-select get_lock("hold_slave",10);
-get_lock("hold_slave",10)
-1
-explain extended select get_lock("hold_slave",10);
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
-Warnings:
-Note 1003 select sql_no_cache get_lock(_latin1'hold_slave',10) AS `get_lock("hold_slave",10)`
+lock tables t1 read;
start slave;
-select release_lock("hold_slave");
-release_lock("hold_slave")
-1
-explain extended select release_lock("hold_slave");
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
-Warnings:
-Note 1003 select sql_no_cache release_lock(_latin1'hold_slave') AS `release_lock("hold_slave")`
unlock tables;
create table t2(id int);
insert into t2 values(connection_id());
@@ -76,6 +61,10 @@ create table t1 (n int);
insert into t1 values(3456);
insert into mysql.user (Host, User, Password)
VALUES ("10.10.10.%", "blafasel2", password("blafasel2"));
+Warnings:
+Warning 1364 Field 'ssl_cipher' doesn't have a default value
+Warning 1364 Field 'x509_issuer' doesn't have a default value
+Warning 1364 Field 'x509_subject' doesn't have a default value
select select_priv,user from mysql.user where user = _binary'blafasel2';
select_priv user
N blafasel2
diff --git a/mysql-test/r/rpl000009.result b/mysql-test/r/rpl000009.result
index bb82dcb1e6a..a4dbf54f39b 100644
--- a/mysql-test/r/rpl000009.result
+++ b/mysql-test/r/rpl000009.result
@@ -32,6 +32,7 @@ create database mysqltest2;
create database mysqltest;
show databases;
Database
+information_schema
mysql
mysqltest
mysqltest2
@@ -48,6 +49,7 @@ insert into mysqltest.t2 values (11, 'eleven test'), (12, 'twelve test'),
set sql_log_bin = 1;
show databases;
Database
+information_schema
mysql
test
create database mysqltest2;
@@ -66,6 +68,7 @@ insert into mysqltest.t3 values (1, 'original bar.t3');
load data from master;
show databases;
Database
+information_schema
mysql
mysqltest
mysqltest2
diff --git a/mysql-test/r/rpl000015.result b/mysql-test/r/rpl000015.result
index 8cbbe3ab0e8..e33201ced93 100644
--- a/mysql-test/r/rpl000015.result
+++ b/mysql-test/r/rpl000015.result
@@ -1,23 +1,23 @@
reset master;
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 79
+master-bin.000001 98
reset 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
change master to master_host='127.0.0.1';
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 test MASTER_PORT 7 4 slave-relay-bin.000001 4 No No 0 0 0 4 None 0 No #
+# 127.0.0.1 test MASTER_PORT 7 4 # # No No 0 0 0 # None 0 No #
change master to master_host='127.0.0.1',master_user='root',
master_password='',master_port=MASTER_PORT;
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 7 4 slave-relay-bin.000001 4 No No 0 0 0 4 None 0 No #
+# 127.0.0.1 root MASTER_PORT 7 4 # # No No 0 0 0 # None 0 No #
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 7 master-bin.000001 79 slave-relay-bin.000001 123 master-bin.000001 Yes Yes 0 0 79 123 None 0 No #
+# 127.0.0.1 root MASTER_PORT 7 master-bin.000001 98 # # master-bin.000001 Yes Yes 0 0 98 # None 0 No #
drop table if exists t1;
create table t1 (n int);
insert into t1 values (10),(45),(90);
diff --git a/mysql-test/r/rpl_EE_error.result b/mysql-test/r/rpl_EE_error.result
index 49ad4832c81..f4765b4b13c 100644
--- a/mysql-test/r/rpl_EE_error.result
+++ b/mysql-test/r/rpl_EE_error.result
@@ -6,7 +6,9 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
create table t1 (a int) engine=myisam;
flush tables;
-drop table t1;
+drop table if exists t1;
+Warnings:
+Error 2 Can't find file: 't1' (errno: 2)
create table t1 (a int, unique(a)) engine=myisam;
set sql_log_bin=0;
insert into t1 values(2);
diff --git a/mysql-test/r/rpl_auto_increment.result b/mysql-test/r/rpl_auto_increment.result
new file mode 100644
index 00000000000..9eca51ad2d9
--- /dev/null
+++ b/mysql-test/r/rpl_auto_increment.result
@@ -0,0 +1,185 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+create table t1 (a int not null auto_increment,b int, primary key (a)) engine=myisam auto_increment=3;
+insert into t1 values (NULL,1),(NULL,2),(NULL,3);
+select * from t1;
+a b
+12 1
+22 2
+32 3
+select * from t1;
+a b
+12 1
+22 2
+32 3
+drop table t1;
+create table t1 (a int not null auto_increment,b int, primary key (a)) engine=myisam;
+insert into t1 values (1,1),(NULL,2),(3,3),(NULL,4);
+delete from t1 where b=4;
+insert into t1 values (NULL,5),(NULL,6);
+select * from t1;
+a b
+1 1
+2 2
+3 3
+22 5
+32 6
+select * from t1;
+a b
+1 1
+2 2
+3 3
+22 5
+32 6
+drop table t1;
+set @@session.auto_increment_increment=100, @@session.auto_increment_offset=10;
+show variables like "%auto_inc%";
+Variable_name Value
+auto_increment_increment 100
+auto_increment_offset 10
+create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
+insert into t1 values (NULL),(5),(NULL);
+insert into t1 values (250),(NULL);
+select * from t1;
+a
+5
+10
+110
+250
+310
+insert into t1 values (1000);
+set @@insert_id=400;
+insert into t1 values(NULL),(NULL);
+select * from t1;
+a
+5
+10
+110
+250
+310
+400
+410
+1000
+select * from t1;
+a
+5
+10
+110
+250
+310
+400
+410
+1000
+drop table t1;
+create table t1 (a int not null auto_increment, primary key (a)) engine=innodb;
+insert into t1 values (NULL),(5),(NULL);
+insert into t1 values (250),(NULL);
+select * from t1;
+a
+5
+10
+110
+250
+310
+insert into t1 values (1000);
+set @@insert_id=400;
+insert into t1 values(NULL),(NULL);
+select * from t1;
+a
+5
+10
+110
+250
+310
+400
+410
+1000
+select * from t1;
+a
+5
+10
+110
+250
+310
+400
+410
+1000
+drop table t1;
+set @@session.auto_increment_increment=1, @@session.auto_increment_offset=1;
+create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
+insert into t1 values (NULL),(5),(NULL),(NULL);
+insert into t1 values (500),(NULL),(502),(NULL),(NULL);
+select * from t1;
+a
+1
+5
+6
+7
+500
+501
+502
+503
+504
+set @@insert_id=600;
+insert into t1 values(600),(NULL),(NULL);
+ERROR 23000: Duplicate entry '600' for key 1
+set @@insert_id=600;
+insert ignore into t1 values(600),(NULL),(NULL),(610),(NULL);
+select * from t1;
+a
+1
+5
+6
+7
+500
+501
+502
+503
+504
+600
+610
+611
+select * from t1;
+a
+1
+5
+6
+7
+500
+501
+502
+503
+504
+600
+610
+611
+drop table t1;
+set @@session.auto_increment_increment=10, @@session.auto_increment_offset=1;
+create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
+insert into t1 values(2),(12),(22),(32),(42);
+insert into t1 values (NULL),(NULL);
+insert into t1 values (3),(NULL),(NULL);
+select * from t1;
+a
+1
+3
+11
+21
+31
+select * from t1;
+a
+1
+2
+3
+11
+12
+21
+22
+31
+32
+42
+drop table t1;
diff --git a/mysql-test/r/rpl_change_master.result b/mysql-test/r/rpl_change_master.result
index a6342d47b49..7f2ba568fb3 100644
--- a/mysql-test/r/rpl_change_master.result
+++ b/mysql-test/r/rpl_change_master.result
@@ -4,26 +4,20 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
-select get_lock("a",5);
-get_lock("a",5)
-1
create table t1(n int);
-insert into t1 values(1+get_lock("a",15)*0);
-insert into t1 values(2);
-stop slave;
select * from t1;
n
-1
+stop slave sql_thread;
+insert into t1 values(1);
+insert into t1 values(2);
+stop 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_MYPORT 1 master-bin.000001 273 slave-relay-bin.000002 258 master-bin.000001 No No 0 0 214 317 None 0 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 357 # # master-bin.000001 No No 0 0 183 # None 0 No #
change master to master_user='root';
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 214 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 214 4 None 0 No #
-select release_lock("a");
-release_lock("a")
-1
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 183 # # master-bin.000001 No No 0 0 183 # None 0 No #
start slave;
select * from t1;
n
diff --git a/mysql-test/r/rpl_charset.result b/mysql-test/r/rpl_charset.result
index 292cfb19175..b27acc0972e 100644
--- a/mysql-test/r/rpl_charset.result
+++ b/mysql-test/r/rpl_charset.result
@@ -4,6 +4,7 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
+set timestamp=1000000000;
drop database if exists mysqltest2;
drop database if exists mysqltest3;
create database mysqltest2 character set latin2;
@@ -87,7 +88,6 @@ a b
2 Muffler
3 latin1_german2_ci
4 Müller
-load data infile '../../std_data/words.dat' into table t1 (b);
set @a= _cp850 'Müller' collate cp850_general_ci;
truncate table t1;
insert into t1 (b) values(collation(@a));
@@ -103,68 +103,44 @@ a b
1 cp850_general_ci
drop database mysqltest2;
drop database mysqltest3;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 drop database if exists mysqltest2
-master-bin.000001 154 Query 1 154 drop database if exists mysqltest3
-master-bin.000001 229 Query 1 229 create database mysqltest2 character set latin2
-master-bin.000001 317 Query 1 317 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=30
-master-bin.000001 451 Query 1 451 create database mysqltest3
-master-bin.000001 518 Query 1 518 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=64
-master-bin.000001 652 Query 1 652 drop database mysqltest3
-master-bin.000001 717 Query 1 717 use `test`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=8,COLLATION_SERVER=64
-master-bin.000001 851 Query 1 851 create database mysqltest3
-master-bin.000001 918 Query 1 918 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=8,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 1058 Query 1 1058 use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))
-master-bin.000001 1165 Query 1 1165 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 1306 Intvar 1 1306 INSERT_ID=1
-master-bin.000001 1334 Query 1 1334 use `mysqltest2`; insert into t1 (b) values(@@character_set_server)
-master-bin.000001 1424 Query 1 1424 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 1565 Intvar 1 1565 INSERT_ID=2
-master-bin.000001 1593 Query 1 1593 use `mysqltest2`; insert into t1 (b) values(@@collation_server)
-master-bin.000001 1679 Query 1 1679 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 1820 Intvar 1 1820 INSERT_ID=3
-master-bin.000001 1848 Query 1 1848 use `mysqltest2`; insert into t1 (b) values(@@character_set_client)
-master-bin.000001 1938 Query 1 1938 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 2079 Intvar 1 2079 INSERT_ID=4
-master-bin.000001 2107 Query 1 2107 use `mysqltest2`; insert into t1 (b) values(@@character_set_connection)
-master-bin.000001 2201 Query 1 2201 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=4,COLLATION_CONNECTION=27,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 2342 Intvar 1 2342 INSERT_ID=5
-master-bin.000001 2370 Query 1 2370 use `mysqltest2`; insert into t1 (b) values(@@collation_connection)
-master-bin.000001 2460 Query 1 2460 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=5,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 2600 Query 1 2600 use `mysqltest2`; truncate table t1
-master-bin.000001 2658 Query 1 2658 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=5,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 2798 Intvar 1 2798 INSERT_ID=1
-master-bin.000001 2826 Query 1 2826 use `mysqltest2`; insert into t1 (b) values(@@collation_connection)
-master-bin.000001 2916 Query 1 2916 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=5,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 3056 Intvar 1 3056 INSERT_ID=2
-master-bin.000001 3084 Query 1 3084 use `mysqltest2`; insert into t1 (b) values(LEAST("Müller","Muffler"))
-master-bin.000001 3177 Query 1 3177 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 3318 Intvar 1 3318 INSERT_ID=3
-master-bin.000001 3346 Query 1 3346 use `mysqltest2`; insert into t1 (b) values(@@collation_connection)
-master-bin.000001 3436 Query 1 3436 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 3577 Intvar 1 3577 INSERT_ID=4
-master-bin.000001 3605 Query 1 3605 use `mysqltest2`; insert into t1 (b) values(LEAST("Müller","Muffler"))
-master-bin.000001 3698 Query 1 3698 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 3839 Intvar 1 3839 INSERT_ID=74
-master-bin.000001 3867 Create_file 1 3867 db=mysqltest2;table=t1;file_id=1;block_len=581
-master-bin.000001 4540 Query 1 4540 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 4681 Intvar 1 4681 INSERT_ID=5
-master-bin.000001 4709 Exec_load 1 4709 ;file_id=1
-master-bin.000001 4732 Query 1 4732 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 4873 Query 1 4873 use `mysqltest2`; truncate table t1
-master-bin.000001 4931 Query 1 4931 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 5072 Intvar 1 5072 INSERT_ID=1
-master-bin.000001 5100 User var 1 5100 @`a`=_cp850 0x4DFC6C6C6572 COLLATE cp850_general_ci
-master-bin.000001 5140 Query 1 5140 use `mysqltest2`; insert into t1 (b) values(collation(@a))
-master-bin.000001 5221 Query 1 5221 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 5362 Query 1 5362 drop database mysqltest2
-master-bin.000001 5427 Query 1 5427 SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64
-master-bin.000001 5558 Query 1 5558 drop database mysqltest3
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query 1 # drop database if exists mysqltest2
+master-bin.000001 # Query 1 # drop database if exists mysqltest3
+master-bin.000001 # Query 1 # create database mysqltest2 character set latin2
+master-bin.000001 # Query 1 # create database mysqltest3
+master-bin.000001 # Query 1 # drop database mysqltest3
+master-bin.000001 # Query 1 # create database mysqltest3
+master-bin.000001 # Query 1 # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))
+master-bin.000001 # Intvar 1 # INSERT_ID=1
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@character_set_server)
+master-bin.000001 # Intvar 1 # INSERT_ID=2
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@collation_server)
+master-bin.000001 # Intvar 1 # INSERT_ID=3
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@character_set_client)
+master-bin.000001 # Intvar 1 # INSERT_ID=4
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@character_set_connection)
+master-bin.000001 # Intvar 1 # INSERT_ID=5
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@collation_connection)
+master-bin.000001 # Query 1 # use `mysqltest2`; truncate table t1
+master-bin.000001 # Intvar 1 # INSERT_ID=1
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@collation_connection)
+master-bin.000001 # Intvar 1 # INSERT_ID=2
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(LEAST("Müller","Muffler"))
+master-bin.000001 # Intvar 1 # INSERT_ID=3
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(@@collation_connection)
+master-bin.000001 # Intvar 1 # INSERT_ID=4
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(LEAST("Müller","Muffler"))
+master-bin.000001 # Query 1 # use `mysqltest2`; truncate table t1
+master-bin.000001 # Intvar 1 # INSERT_ID=1
+master-bin.000001 # User var 1 # @`a`=_cp850 0x4DFC6C6C6572 COLLATE cp850_general_ci
+master-bin.000001 # Query 1 # use `mysqltest2`; insert into t1 (b) values(collation(@a))
+master-bin.000001 # Query 1 # drop database mysqltest2
+master-bin.000001 # Query 1 # drop database mysqltest3
set global character_set_server=latin2;
-ERROR HY000: Binary logging and replication forbid changing the global server character set or collation
+set global character_set_server=latin1;
set global character_set_server=latin2;
-ERROR HY000: Binary logging and replication forbid changing the global server character set or collation
+set global character_set_server=latin1;
set one_shot @@character_set_server=latin5;
set @@max_join_size=1000;
select @@character_set_server;
@@ -181,7 +157,7 @@ select @@character_set_server;
@@character_set_server
latin5
set one_shot max_join_size=10;
-ERROR HY000: The SET ONE_SHOT syntax is reserved for purposes internal to the MySQL server
+ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server
set character_set_client=9999999;
ERROR 42000: Unknown character set: '9999999'
set collation_server=9999998;
@@ -198,14 +174,80 @@ CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3
select hex(c1), hex(c2) from t1;
hex(c1) hex(c2)
CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3
-stop slave;
-delete from t1;
-change master to master_log_pos=5847;
-start slave until master_log_file='master-bin.000001', master_log_pos=5983;
-start slave;
-select hex(c1), hex(c2) from t1;
-hex(c1) hex(c2)
-CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
+SET TIMESTAMP=1000000000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
+drop database if exists mysqltest2;
+SET TIMESTAMP=1000000000;
+drop database if exists mysqltest3;
+SET TIMESTAMP=1000000000;
+create database mysqltest2 character set latin2;
+SET TIMESTAMP=1000000000;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=30;
+create database mysqltest3;
+SET TIMESTAMP=1000000000;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=64;
+drop database mysqltest3;
+SET TIMESTAMP=1000000000;
+create database mysqltest3;
+use mysqltest2;
+SET TIMESTAMP=1000000000;
+create table t1 (a int auto_increment primary key, b varchar(100));
+SET INSERT_ID=1;
+SET TIMESTAMP=1000000000;
+SET @@session.character_set_client=4,@@session.collation_connection=27,@@session.collation_server=64;
+insert into t1 (b) values(@@character_set_server);
+SET INSERT_ID=2;
+SET TIMESTAMP=1000000000;
+insert into t1 (b) values(@@collation_server);
+SET INSERT_ID=3;
+SET TIMESTAMP=1000000000;
+insert into t1 (b) values(@@character_set_client);
+SET INSERT_ID=4;
+SET TIMESTAMP=1000000000;
+insert into t1 (b) values(@@character_set_connection);
+SET INSERT_ID=5;
+SET TIMESTAMP=1000000000;
+insert into t1 (b) values(@@collation_connection);
+SET TIMESTAMP=1000000000;
+SET @@session.character_set_client=8,@@session.collation_connection=5,@@session.collation_server=64;
+truncate table t1;
+SET INSERT_ID=1;
+SET TIMESTAMP=1000000000;
+insert into t1 (b) values(@@collation_connection);
+SET INSERT_ID=2;
+SET TIMESTAMP=1000000000;
+insert into t1 (b) values(LEAST("Müller","Muffler"));
+SET INSERT_ID=3;
+SET TIMESTAMP=1000000000;
+SET @@session.character_set_client=8,@@session.collation_connection=31,@@session.collation_server=64;
+insert into t1 (b) values(@@collation_connection);
+SET INSERT_ID=4;
+SET TIMESTAMP=1000000000;
+insert into t1 (b) values(LEAST("Müller","Muffler"));
+SET TIMESTAMP=1000000000;
+truncate table t1;
+SET INSERT_ID=1;
+SET @`a`:=_cp850 0x4DFC6C6C6572 COLLATE `cp850_general_ci`;
+SET TIMESTAMP=1000000000;
+insert into t1 (b) values(collation(@a));
+SET TIMESTAMP=1000000000;
+drop database mysqltest2;
+SET TIMESTAMP=1000000000;
+drop database mysqltest3;
+use test;
+SET TIMESTAMP=1000000000;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=30;
+CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255));
+SET TIMESTAMP=1000000000;
+SET @@session.character_set_client=7,@@session.collation_connection=51,@@session.collation_server=30;
+INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ');
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
drop table t1;
create table `t1` (
`pk` varchar(10) not null default '',
diff --git a/mysql-test/r/rpl_create_database.result b/mysql-test/r/rpl_create_database.result
index 2375e13bb5c..ca4585d0d8d 100644
--- a/mysql-test/r/rpl_create_database.result
+++ b/mysql-test/r/rpl_create_database.result
@@ -22,6 +22,7 @@ USE mysqltest_sisyfos;
ALTER DATABASE mysqltest_bob CHARACTER SET latin1;
SHOW DATABASES;
Database
+information_schema
mysql
mysqltest_bob
mysqltest_prometheus
@@ -29,6 +30,7 @@ mysqltest_sisyfos
test
SHOW DATABASES;
Database
+information_schema
mysql
mysqltest_prometheus
mysqltest_sisyfos
@@ -41,22 +43,23 @@ CREATE DATABASE mysqltest_sisyfos;
USE mysqltest_sisyfos;
CREATE TABLE t2 (a INT);
SHOW BINLOG EVENTS;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 DROP DATABASE IF EXISTS mysqltest_prometheus
-master-bin.000001 174 Query 1 174 DROP DATABASE IF EXISTS mysqltest_sisyfos
-master-bin.000001 263 Query 1 263 CREATE DATABASE mysqltest_prometheus
-master-bin.000001 350 Query 1 350 CREATE DATABASE mysqltest_sisyfos
-master-bin.000001 431 Query 1 431 use `mysqltest_sisyfos`; CREATE TABLE t1 (b int)
-master-bin.000001 502 Query 1 502 use `mysqltest_sisyfos`; INSERT INTO t1 VALUES(1)
-master-bin.000001 574 Query 1 574 ALTER DATABASE mysqltest_sisyfos CHARACTER SET latin1
-master-bin.000001 675 Query 1 675 DROP DATABASE IF EXISTS mysqltest_sisyfos
-master-bin.000001 764 Query 1 764 use `mysqltest_prometheus`; CREATE TABLE t1 (a INT)
-master-bin.000001 838 Query 1 838 use `mysqltest_prometheus`; INSERT INTO t1 VALUES (1)
-master-bin.000001 914 Query 1 914 CREATE DATABASE mysqltest_sisyfos
-master-bin.000001 995 Query 1 995 use `mysqltest_sisyfos`; CREATE TABLE t2 (a INT)
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4
+master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS mysqltest_prometheus
+master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS mysqltest_sisyfos
+master-bin.000001 # Query 1 # CREATE DATABASE mysqltest_prometheus
+master-bin.000001 # Query 1 # CREATE DATABASE mysqltest_sisyfos
+master-bin.000001 # Query 1 # use `mysqltest_sisyfos`; CREATE TABLE t1 (b int)
+master-bin.000001 # Query 1 # use `mysqltest_sisyfos`; INSERT INTO t1 VALUES(1)
+master-bin.000001 # Query 1 # ALTER DATABASE mysqltest_sisyfos CHARACTER SET latin1
+master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS mysqltest_sisyfos
+master-bin.000001 # Query 1 # use `mysqltest_prometheus`; CREATE TABLE t1 (a INT)
+master-bin.000001 # Query 1 # use `mysqltest_prometheus`; INSERT INTO t1 VALUES (1)
+master-bin.000001 # Query 1 # CREATE DATABASE mysqltest_sisyfos
+master-bin.000001 # Query 1 # use `mysqltest_sisyfos`; CREATE TABLE t2 (a INT)
SHOW DATABASES;
Database
+information_schema
mysql
mysqltest_bob
mysqltest_prometheus
@@ -64,6 +67,7 @@ mysqltest_sisyfos
test
SHOW DATABASES;
Database
+information_schema
mysql
mysqltest_prometheus
mysqltest_sisyfos
diff --git a/mysql-test/r/rpl_deadlock.result b/mysql-test/r/rpl_deadlock.result
index 8808a973855..866edb45cbb 100644
--- a/mysql-test/r/rpl_deadlock.result
+++ b/mysql-test/r/rpl_deadlock.result
@@ -10,17 +10,17 @@ create table t3 (a int) engine=innodb;
create table t4 (a int) engine=innodb;
show variables like 'slave_transaction_retries';
Variable_name Value
-slave_transaction_retries 0
+slave_transaction_retries 10
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
show variables like 'slave_transaction_retries';
@@ -45,9 +45,9 @@ a
22
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 13110 # # master-bin.000001 Yes Yes 0 0 13110 # None 0 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 18911 # # master-bin.000001 Yes Yes 0 0 18911 # None 0 No #
stop slave;
-change master to master_log_pos=401;
+change master to master_log_pos=532;
begin;
select * from t2 for update;
a
@@ -63,10 +63,10 @@ a
22
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 13110 # # master-bin.000001 Yes Yes 0 0 13110 # None 0 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 18911 # # master-bin.000001 Yes Yes 0 0 18911 # None 0 No #
set global max_relay_log_size=0;
stop slave;
-change master to master_log_pos=401;
+change master to master_log_pos=532;
begin;
select * from t2 for update;
a
@@ -83,5 +83,5 @@ a
22
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 13110 # # master-bin.000001 Yes Yes 0 0 13110 # None 0 No #
+# 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;
diff --git a/mysql-test/r/rpl_drop_temp.result b/mysql-test/r/rpl_drop_temp.result
index e00309cac8f..04fe094ea26 100644
--- a/mysql-test/r/rpl_drop_temp.result
+++ b/mysql-test/r/rpl_drop_temp.result
@@ -10,3 +10,4 @@ create temporary table mysqltest.t2 (n int);
show status like 'Slave_open_temp_tables';
Variable_name Value
Slave_open_temp_tables 0
+drop database mysqltest;
diff --git a/mysql-test/r/rpl_error_ignored_table.result b/mysql-test/r/rpl_error_ignored_table.result
index 4a562dbfc70..a0a808ce9a8 100644
--- a/mysql-test/r/rpl_error_ignored_table.result
+++ b/mysql-test/r/rpl_error_ignored_table.result
@@ -9,7 +9,7 @@ insert into t1 values (1),(1);
ERROR 23000: Duplicate entry '1' for key 1
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 213 slave-relay-bin.000002 257 master-bin.000001 Yes Yes test.t3,test.t1,test.t2 0 0 213 257 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 288 # # master-bin.000001 Yes Yes test.t3,test.t1,test.t2 0 0 288 # None 0 No #
show tables like 't1';
Tables_in_test (t1)
drop table t1;
@@ -26,14 +26,14 @@ select (@id := id) - id from t3;
0
kill @id;
drop table t2,t3;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; create table t1 (a int primary key)
-master-bin.000001 149 Query 1 149 use `test`; insert into t1 values (1),(1)
-master-bin.000001 213 Query 1 213 use `test`; drop table t1
-master-bin.000001 261 Query 1 261 use `test`; create table t2 (a int primary key)
-master-bin.000001 331 Query 1 331 use `test`; insert into t2 values(1)
-master-bin.000001 390 Query 1 390 use `test`; create table t3 (id int)
-master-bin.000001 449 Query 1 449 use `test`; insert into t3 values(connection_id())
-master-bin.000001 522 Query 1 522 use `test`; update t2 set a = a + 1 + get_lock('crash_lock%20C', 10)
-master-bin.000001 613 Query 1 613 use `test`; drop table t2,t3
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query 1 # use `test`; create table t1 (a int primary key)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values (1),(1)
+master-bin.000001 # Query 1 # use `test`; drop table t1
+master-bin.000001 # Query 1 # use `test`; create table t2 (a int primary key)
+master-bin.000001 # Query 1 # use `test`; insert into t2 values(1)
+master-bin.000001 # Query 1 # use `test`; create table t3 (id int)
+master-bin.000001 # Query 1 # use `test`; insert into t3 values(connection_id())
+master-bin.000001 # Query 1 # use `test`; update t2 set a = a + 1 + get_lock('crash_lock%20C', 10)
+master-bin.000001 # Query 1 # use `test`; drop table t2,t3
diff --git a/mysql-test/r/rpl_failed_optimize.result b/mysql-test/r/rpl_failed_optimize.result
index 1576ec60500..c7199e56ec8 100644
--- a/mysql-test/r/rpl_failed_optimize.result
+++ b/mysql-test/r/rpl_failed_optimize.result
@@ -10,6 +10,10 @@ INSERT INTO t1 VALUES (1);
OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize status Operation failed
+Warnings:
+Error 1205 Lock wait timeout exceeded; try restarting transaction
OPTIMIZE TABLE non_existing;
Table Op Msg_type Msg_text
test.non_existing optimize error Table 'test.non_existing' doesn't exist
+Warnings:
+Error 1146 Table 'test.non_existing' doesn't exist
diff --git a/mysql-test/r/rpl_flush_log_loop.result b/mysql-test/r/rpl_flush_log_loop.result
index 25177a6bca3..b4e840ba271 100644
--- a/mysql-test/r/rpl_flush_log_loop.result
+++ b/mysql-test/r/rpl_flush_log_loop.result
@@ -14,4 +14,4 @@ start slave;
flush logs;
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 SLAVE_PORT 60 slave-bin.000001 161 relay-log.000002 4 slave-bin.000001 Yes Yes 0 0 161 4 None 0 No #
+# 127.0.0.1 root SLAVE_PORT 60 slave-bin.000001 208 # # slave-bin.000001 Yes Yes 0 0 208 # None 0 No #
diff --git a/mysql-test/r/rpl_flush_tables.result b/mysql-test/r/rpl_flush_tables.result
index 70e4774a920..ca2e77cac66 100644
--- a/mysql-test/r/rpl_flush_tables.result
+++ b/mysql-test/r/rpl_flush_tables.result
@@ -13,28 +13,28 @@ insert into t4 select * from t3;
rename table t1 to t5, t2 to t1;
flush no_write_to_binlog tables;
show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: SERVER_VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 use `test`; create table t1 (a int)
-master-bin.000001 137 Query 1 137 use `test`; insert into t1 values (10)
-master-bin.000001 198 Query 1 198 use `test`; create table t2 (a int)
-master-bin.000001 256 Query 1 256 use `test`; create table t3 (a int) engine=merge union(t1)
-master-bin.000001 337 Query 1 337 use `test`; create table t4 (a int)
-master-bin.000001 395 Query 1 395 use `test`; insert into t4 select * from t3
-master-bin.000001 461 Query 1 461 use `test`; rename table t1 to t5, t2 to t1
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Format_desc 1 # Server ver: SERVER_VERSION, Binlog ver: 4
+master-bin.000001 # Query 1 # use `test`; create table t1 (a int)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values (10)
+master-bin.000001 # Query 1 # use `test`; create table t2 (a int)
+master-bin.000001 # Query 1 # use `test`; create table t3 (a int) engine=merge union(t1)
+master-bin.000001 # Query 1 # use `test`; create table t4 (a int)
+master-bin.000001 # Query 1 # use `test`; insert into t4 select * from t3
+master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
select * from t3;
a
flush tables;
show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: SERVER_VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 use `test`; create table t1 (a int)
-master-bin.000001 137 Query 1 137 use `test`; insert into t1 values (10)
-master-bin.000001 198 Query 1 198 use `test`; create table t2 (a int)
-master-bin.000001 256 Query 1 256 use `test`; create table t3 (a int) engine=merge union(t1)
-master-bin.000001 337 Query 1 337 use `test`; create table t4 (a int)
-master-bin.000001 395 Query 1 395 use `test`; insert into t4 select * from t3
-master-bin.000001 461 Query 1 461 use `test`; rename table t1 to t5, t2 to t1
-master-bin.000001 527 Query 1 527 use `test`; flush tables
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Format_desc 1 # Server ver: SERVER_VERSION, Binlog ver: 4
+master-bin.000001 # Query 1 # use `test`; create table t1 (a int)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values (10)
+master-bin.000001 # Query 1 # use `test`; create table t2 (a int)
+master-bin.000001 # Query 1 # use `test`; create table t3 (a int) engine=merge union(t1)
+master-bin.000001 # Query 1 # use `test`; create table t4 (a int)
+master-bin.000001 # Query 1 # use `test`; insert into t4 select * from t3
+master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
+master-bin.000001 # Query 1 # use `test`; flush tables
select * from t3;
a
diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result
index 65fc9d1b415..dc11d10fab8 100644
--- a/mysql-test/r/rpl_loaddata.result
+++ b/mysql-test/r/rpl_loaddata.result
@@ -22,7 +22,7 @@ day id category name
2003-03-22 2416 a bbbbb
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
-slave-bin.000001 964
+slave-bin.000001 1286
drop table t1;
drop table t2;
drop table t3;
@@ -33,7 +33,7 @@ set global sql_slave_skip_counter=1;
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.000001 1311 slave-relay-bin.000002 1355 master-bin.000001 Yes Yes 0 0 1311 1355 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1789 # # master-bin.000001 Yes Yes 0 0 1789 # None 0 No #
set sql_log_bin=0;
delete from t1;
set sql_log_bin=1;
@@ -43,7 +43,7 @@ change master to master_user='test';
change master to master_user='root';
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.000001 1419 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 1419 4 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1824 # # master-bin.000001 No No 0 0 1824 # None 0 No #
set global sql_slave_skip_counter=1;
start slave;
set sql_log_bin=0;
@@ -54,15 +54,28 @@ stop slave;
reset 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 4 slave-relay-bin.000001 4 No No 0 0 0 4 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 4 # # No No 0 0 0 # None 0 No #
reset master;
create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60),
-unique(day));
+unique(day)) engine=MyISAM;
load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
'\n##\n' starting by '>' ignore 1 lines;
ERROR 23000: Duplicate entry '2003-03-22' for key 1
-show master status;
-File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 491
+select * from t2;
+day id category name
+2003-02-22 2461 b a a a @ %  ' " a
+2003-03-22 2161 c asdf
+start slave;
+select * from t2;
+day id category name
+2003-02-22 2461 b a a a @ %  ' " a
+2003-03-22 2161 c asdf
+alter table t2 drop key day;
+delete from t2;
+load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
+terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
+'\n##\n' starting by '>' ignore 1 lines;
+ERROR 23000: Duplicate entry '2003-03-22' for key 1
+drop table t2;
drop table t2;
diff --git a/mysql-test/r/rpl_loaddata_rule_m.result b/mysql-test/r/rpl_loaddata_rule_m.result
index 08f2c2ec071..3571c9973ea 100644
--- a/mysql-test/r/rpl_loaddata_rule_m.result
+++ b/mysql-test/r/rpl_loaddata_rule_m.result
@@ -10,8 +10,10 @@ create database mysqltest;
create table t1(a int, b int, unique(b));
use mysqltest;
load data infile '../../std_data/rpl_loaddata.dat' into table test.t1;
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 drop database if exists mysqltest
-master-bin.000001 152 Query 1 152 create database mysqltest
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query 1 # drop database if exists mysqltest
+master-bin.000001 # Query 1 # create database mysqltest
+master-bin.000001 # Begin_load_query 1 # ;file_id=1;block_len=12
+master-bin.000001 # Execute_load_query 1 # use `mysqltest`; load data infile '../../std_data/rpl_loaddata.dat' into table test.t1 ;file_id=1
drop database mysqltest;
diff --git a/mysql-test/r/rpl_loaddata_rule_s.result b/mysql-test/r/rpl_loaddata_rule_s.result
index 26893cb1e9e..16720c81374 100644
--- a/mysql-test/r/rpl_loaddata_rule_s.result
+++ b/mysql-test/r/rpl_loaddata_rule_s.result
@@ -10,5 +10,5 @@ load data infile '../../std_data/rpl_loaddata.dat' into table test.t1;
select count(*) from t1;
count(*)
2
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
diff --git a/mysql-test/r/rpl_loaddatalocal.result b/mysql-test/r/rpl_loaddatalocal.result
index b49ea842485..c29825c3c98 100644
--- a/mysql-test/r/rpl_loaddatalocal.result
+++ b/mysql-test/r/rpl_loaddatalocal.result
@@ -12,3 +12,20 @@ select a,count(*) from t1 group by a;
a count(*)
1 10000
drop table t1;
+create table t1(a int);
+insert into t1 values (1), (2), (2), (3);
+select * into outfile '../../var/master-data/rpl_loaddatalocal.select_outfile' from t1;
+drop table t1;
+create table t1(a int primary key);
+load data local infile './var/master-data/rpl_loaddatalocal.select_outfile' into table t1;
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+drop table t1;
diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result
index 2f8a54369c9..5d61746b984 100644
--- a/mysql-test/r/rpl_log.result
+++ b/mysql-test/r/rpl_log.result
@@ -18,26 +18,26 @@ count(*)
69
drop table t1;
show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key)
-master-bin.000001 172 Intvar 1 172 INSERT_ID=1
-master-bin.000001 200 Query 1 200 use `test`; insert into t1 values (NULL)
-master-bin.000001 263 Query 1 263 use `test`; drop table t1
-master-bin.000001 311 Query 1 311 use `test`; create table t1 (word char(20) not null)
-master-bin.000001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581
-master-bin.000001 1056 Exec_load 1 1056 ;file_id=1
-master-bin.000001 1079 Query 1 1079 use `test`; drop table t1
-show binlog events from 79 limit 1;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key)
-show binlog events from 79 limit 2;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key)
-master-bin.000001 172 Intvar 1 172 INSERT_ID=1
-show binlog events from 79 limit 2,1;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 200 Query 1 200 use `test`; insert into t1 values (NULL)
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4
+master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key)
+master-bin.000001 219 Intvar 1 247 INSERT_ID=1
+master-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL)
+master-bin.000001 338 Query 1 414 use `test`; drop table t1
+master-bin.000001 414 Query 1 517 use `test`; create table t1 (word char(20) not null)
+master-bin.000001 517 Begin_load_query 1 1121 ;file_id=1;block_len=581
+master-bin.000001 1121 Execute_load_query 1 1269 use `test`; load data infile '../../std_data/words.dat' into table t1 ignore 1 lines ;file_id=1
+master-bin.000001 1269 Query 1 1345 use `test`; drop table t1
+show binlog events from 98 limit 1;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key)
+show binlog events from 98 limit 2;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key)
+master-bin.000001 219 Intvar 1 247 INSERT_ID=1
+show binlog events from 98 limit 2,1;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL)
flush logs;
create table t5 (a int);
drop table t5;
@@ -48,24 +48,25 @@ create table t1 (n int);
insert into t1 values (1);
drop table t1;
show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key)
-master-bin.000001 172 Intvar 1 172 INSERT_ID=1
-master-bin.000001 200 Query 1 200 use `test`; insert into t1 values (NULL)
-master-bin.000001 263 Query 1 263 use `test`; drop table t1
-master-bin.000001 311 Query 1 311 use `test`; create table t1 (word char(20) not null)
-master-bin.000001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581
-master-bin.000001 1056 Exec_load 1 1056 ;file_id=1
-master-bin.000001 1079 Query 1 1079 use `test`; drop table t1
-master-bin.000001 1127 Rotate 1 1127 master-bin.000002;pos=4
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4
+master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key)
+master-bin.000001 219 Intvar 1 247 INSERT_ID=1
+master-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL)
+master-bin.000001 338 Query 1 414 use `test`; drop table t1
+master-bin.000001 414 Query 1 517 use `test`; create table t1 (word char(20) not null)
+master-bin.000001 517 Begin_load_query 1 1121 ;file_id=1;block_len=581
+master-bin.000001 1121 Execute_load_query 1 1269 use `test`; load data infile '../../std_data/words.dat' into table t1 ignore 1 lines ;file_id=1
+master-bin.000001 1269 Query 1 1345 use `test`; drop table t1
+master-bin.000001 1345 Rotate 1 1389 master-bin.000002;pos=4
show binlog events in 'master-bin.000002';
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000002 4 Query 1 4 use `test`; create table t5 (a int)
-master-bin.000002 62 Query 1 62 use `test`; drop table t5
-master-bin.000002 110 Query 1 110 use `test`; create table t1 (n int)
-master-bin.000002 168 Query 1 168 use `test`; insert into t1 values (1)
-master-bin.000002 228 Query 1 228 use `test`; drop table t1
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4
+master-bin.000002 98 Query 1 184 use `test`; create table t5 (a int)
+master-bin.000002 184 Query 1 260 use `test`; drop table t5
+master-bin.000002 260 Query 1 346 use `test`; create table t1 (n int)
+master-bin.000002 346 Query 1 434 use `test`; insert into t1 values (1)
+master-bin.000002 434 Query 1 510 use `test`; drop table t1
show binary logs;
Log_name
master-bin.000001
@@ -76,26 +77,27 @@ Log_name
slave-bin.000001
slave-bin.000002
show binlog events in 'slave-bin.000001' from 4;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-slave-bin.000001 4 Start 2 4 Server ver: VERSION, Binlog ver: 3
-slave-bin.000001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key)
-slave-bin.000001 172 Intvar 1 172 INSERT_ID=1
-slave-bin.000001 200 Query 1 200 use `test`; insert into t1 values (NULL)
-slave-bin.000001 263 Query 1 263 use `test`; drop table t1
-slave-bin.000001 311 Query 1 311 use `test`; create table t1 (word char(20) not null)
-slave-bin.000001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581
-slave-bin.000001 1065 Exec_load 1 1065 ;file_id=1
-slave-bin.000001 1088 Query 1 1088 use `test`; drop table t1
-slave-bin.000001 1136 Query 1 1136 use `test`; create table t5 (a int)
-slave-bin.000001 1194 Query 1 1194 use `test`; drop table t5
-slave-bin.000001 1242 Rotate 2 1242 slave-bin.000002;pos=4
+Log_name Pos Event_type Server_id End_log_pos Info
+slave-bin.000001 4 Format_desc 2 98 Server ver: VERSION, Binlog ver: 4
+slave-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key)
+slave-bin.000001 219 Intvar 1 247 INSERT_ID=1
+slave-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL)
+slave-bin.000001 338 Query 1 414 use `test`; drop table t1
+slave-bin.000001 414 Query 1 517 use `test`; create table t1 (word char(20) not null)
+slave-bin.000001 517 Begin_load_query 1 1121 ;file_id=1;block_len=581
+slave-bin.000001 1121 Execute_load_query 1 1278 use `test`; load data INFILE '../../var/tmp/SQL_LOAD-2-1-1.data' INTO table t1 ignore 1 lines ;file_id=1
+slave-bin.000001 1278 Query 1 1354 use `test`; drop table t1
+slave-bin.000001 1354 Query 1 1440 use `test`; create table t5 (a int)
+slave-bin.000001 1440 Query 1 1516 use `test`; drop table t5
+slave-bin.000001 1516 Rotate 2 1559 slave-bin.000002;pos=4
show binlog events in 'slave-bin.000002' from 4;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-slave-bin.000002 4 Query 1 4 use `test`; create table t1 (n int)
-slave-bin.000002 62 Query 1 62 use `test`; insert into t1 values (1)
-slave-bin.000002 122 Query 1 122 use `test`; drop table t1
+Log_name Pos Event_type Server_id End_log_pos Info
+slave-bin.000002 4 Format_desc 2 98 Server ver: VERSION, Binlog ver: 4
+slave-bin.000002 98 Query 1 184 use `test`; create table t1 (n int)
+slave-bin.000002 184 Query 1 272 use `test`; insert into t1 values (1)
+slave-bin.000002 272 Query 1 348 use `test`; drop table t1
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_PORT 1 master-bin.000002 276 slave-relay-bin.000003 214 master-bin.000002 Yes Yes 0 0 276 214 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000002 510 # # master-bin.000002 Yes Yes 0 0 510 # None 0 No #
show binlog events in 'slave-bin.000005' from 4;
ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log
diff --git a/mysql-test/r/rpl_log_pos.result b/mysql-test/r/rpl_log_pos.result
index 10c78272de6..cf13756966e 100644
--- a/mysql-test/r/rpl_log_pos.result
+++ b/mysql-test/r/rpl_log_pos.result
@@ -6,10 +6,10 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 79
+master-bin.000001 98
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.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 123 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 98 # # master-bin.000001 Yes Yes 0 0 98 # None 0 No #
stop slave;
change master to master_log_pos=73;
start slave;
@@ -17,26 +17,26 @@ stop slave;
change master to master_log_pos=73;
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.000001 73 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 73 4 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 73 # # master-bin.000001 No No 0 0 73 # None 0 No #
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.000001 73 slave-relay-bin.000001 48 master-bin.000001 No Yes 0 0 73 48 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 73 # # master-bin.000001 No Yes 0 0 73 # None 0 No #
stop slave;
change master to master_log_pos=173;
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.000001 173 slave-relay-bin.000001 4 master-bin.000001 No Yes 0 0 173 4 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 173 # # master-bin.000001 No Yes 0 0 173 # None 0 No #
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 79
+master-bin.000001 98
create table if not exists t1 (n int);
drop table if exists t1;
create table t1 (n int);
insert into t1 values (1),(2),(3);
stop slave;
-change master to master_log_pos=79;
+change master to master_log_pos=98;
start slave;
select * from t1;
n
diff --git a/mysql-test/r/rpl_max_relay_size.result b/mysql-test/r/rpl_max_relay_size.result
index 5c3360b0f66..fbe3b89828a 100644
--- a/mysql-test/r/rpl_max_relay_size.result
+++ b/mysql-test/r/rpl_max_relay_size.result
@@ -16,7 +16,7 @@ select @@global.max_relay_log_size;
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.000001 50477 slave-relay-bin.000014 1221 master-bin.000001 Yes Yes 0 0 50477 1221 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 72952 # # master-bin.000001 Yes Yes 0 0 72952 # None 0 No #
stop slave;
reset slave;
set global max_relay_log_size=(5*4096);
@@ -26,7 +26,7 @@ select @@global.max_relay_log_size;
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.000001 50477 slave-relay-bin.000004 9457 master-bin.000001 Yes Yes 0 0 50477 9457 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 72952 # # master-bin.000001 Yes Yes 0 0 72952 # None 0 No #
stop slave;
reset slave;
set global max_relay_log_size=0;
@@ -36,26 +36,26 @@ select @@global.max_relay_log_size;
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.000001 50477 slave-relay-bin.000008 1283 master-bin.000001 Yes Yes 0 0 50477 1283 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 72952 # # master-bin.000001 Yes Yes 0 0 72952 # None 0 No #
stop slave;
reset slave;
flush logs;
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 4 slave-relay-bin.000001 4 No No 0 0 0 4 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 4 # # No No 0 0 0 # None 0 No #
reset slave;
start slave;
flush logs;
create table t1 (a int);
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.000001 50535 slave-relay-bin.000009 62 master-bin.000001 Yes Yes 0 0 50535 62 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 73038 # # master-bin.000001 Yes Yes 0 0 73038 # None 0 No #
flush logs;
drop table t1;
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 50583 slave-relay-bin.000010 52 master-bin.000001 Yes Yes 0 0 50583 52 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 73114 # # master-bin.000001 Yes Yes 0 0 73114 # None 0 No #
flush logs;
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000002 4
+master-bin.000002 98
diff --git a/mysql-test/r/rpl_multi_query.result b/mysql-test/r/rpl_multi_query.result
index 2521dbe1ed9..f2d8ea77536 100644
--- a/mysql-test/r/rpl_multi_query.result
+++ b/mysql-test/r/rpl_multi_query.result
@@ -19,8 +19,8 @@ n
3
4
5
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # drop database if exists mysqltest
master-bin.000001 # Query 1 # create database mysqltest
master-bin.000001 # Query 1 # use `test`; create table mysqltest.t1 ( n int)
diff --git a/mysql-test/r/rpl_openssl.result b/mysql-test/r/rpl_openssl.result
index ad7251fd631..a4ed922d9d4 100644
--- a/mysql-test/r/rpl_openssl.result
+++ b/mysql-test/r/rpl_openssl.result
@@ -20,11 +20,11 @@ t
1
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 replssl MASTER_MYPORT 1 master-bin.000001 289 slave-relay-bin.000001 108 master-bin.000001 Yes Yes 0 0 289 108 None 0 Yes MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem #
+# 127.0.0.1 replssl MASTER_MYPORT 1 master-bin.000001 392 # # master-bin.000001 Yes Yes 0 0 392 # None 0 Yes MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem #
stop slave;
change master to master_user='root',master_password='', master_ssl=0;
start slave;
drop table t1;
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 337 slave-relay-bin.000001 96 master-bin.000001 Yes Yes 0 0 337 96 None 0 No MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 468 # # master-bin.000001 Yes Yes 0 0 468 # None 0 No MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem #
diff --git a/mysql-test/r/rpl_relayrotate.result b/mysql-test/r/rpl_relayrotate.result
index bf9bbbb9b93..c79187e12d0 100644
--- a/mysql-test/r/rpl_relayrotate.result
+++ b/mysql-test/r/rpl_relayrotate.result
@@ -13,7 +13,10 @@ start slave;
select master_pos_wait('master-bin.001',3000)>=0;
master_pos_wait('master-bin.001',3000)>=0
1
-select * from t1 where a=8000;
-a
+select max(a) from t1;
+max(a)
8000
+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 735186 # # master-bin.000001 Yes Yes 0 0 735186 # None 0 No #
drop table t1;
diff --git a/mysql-test/r/rpl_replicate_do.result b/mysql-test/r/rpl_replicate_do.result
index ca290d46fda..8bcae3d25ad 100644
--- a/mysql-test/r/rpl_replicate_do.result
+++ b/mysql-test/r/rpl_replicate_do.result
@@ -28,4 +28,4 @@ ERROR 42S02: Table 'test.t11' doesn't exist
drop table if exists t1,t2,t11;
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.000001 1340 slave-relay-bin.000002 1384 master-bin.000001 Yes Yes test.t1 0 0 1340 1384 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1658 # # master-bin.000001 Yes Yes test.t1 0 0 1658 # None 0 No #
diff --git a/mysql-test/r/rpl_reset_slave.result b/mysql-test/r/rpl_reset_slave.result
index 42d41533cb0..ab55423b773 100644
--- a/mysql-test/r/rpl_reset_slave.result
+++ b/mysql-test/r/rpl_reset_slave.result
@@ -6,20 +6,20 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
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.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 123 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 98 # # master-bin.000001 Yes Yes 0 0 98 # None 0 No #
stop slave;
change master to master_user='test';
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 test MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 79 4 None 0 No #
+# 127.0.0.1 test MASTER_PORT 1 master-bin.000001 98 # # master-bin.000001 No No 0 0 98 # None 0 No #
reset 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 4 slave-relay-bin.000001 4 No No 0 0 0 4 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 4 # # No No 0 0 0 # None 0 No #
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.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 123 None 0 No #
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 98 # # master-bin.000001 Yes Yes 0 0 98 # None 0 No #
stop slave;
reset slave;
start slave;
diff --git a/mysql-test/r/rpl_rewrite_db.result b/mysql-test/r/rpl_rewrite_db.result
index da3ec0243fe..d4a24626cc3 100644
--- a/mysql-test/r/rpl_rewrite_db.result
+++ b/mysql-test/r/rpl_rewrite_db.result
@@ -67,9 +67,9 @@ drop table t1;
create table t1 (a int, b char(10));
load data infile '../../std_data/loaddata3.dat' into table t1 fields terminated by '' enclosed by '' ignore 1 lines;
Warnings:
-Warning 1265 Data truncated for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 3
Warning 1262 Row 3 was truncated; it contained more data than there were input columns
-Warning 1265 Data truncated for column 'a' at row 5
+Warning 1264 Out of range value adjusted for column 'a' at row 5
Warning 1262 Row 5 was truncated; it contained more data than there were input columns
select * from rewrite.t1;
a b
@@ -81,7 +81,7 @@ a b
truncate table t1;
load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated by '' enclosed by '' lines terminated by '' ignore 1 lines;
Warnings:
-Warning 1265 Data truncated for column 'a' at row 4
+Warning 1264 Out of range value adjusted for column 'a' at row 4
Warning 1261 Row 4 doesn't contain data for all columns
select * from rewrite.t1;
a b
diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result
index 62e5522fad9..de177d12196 100644
--- a/mysql-test/r/rpl_rotate_logs.result
+++ b/mysql-test/r/rpl_rotate_logs.result
@@ -1,7 +1,7 @@
drop table if exists t1, t2, t3, t4;
drop table if exists t1, t2, t3, t4;
start slave;
-ERROR HY000: Could not initialize master info structure; more error messages can be found in the MySQL error log
+Got one of the listed errors
start slave;
ERROR HY000: Could not initialize master info structure; more error messages can be found in the MySQL error log
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root';
@@ -16,7 +16,7 @@ create table t1 (s text);
insert into t1 values('Could not break slave'),('Tried hard');
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 60 master-bin.000001 417 slave-relay-bin.000001 461 master-bin.000001 Yes Yes 0 0 417 461 None 0 No #
+# 127.0.0.1 root MASTER_PORT 60 master-bin.000001 548 # # master-bin.000001 Yes Yes 0 0 548 # None 0 No #
select * from t1;
s
Could not break slave
@@ -57,7 +57,7 @@ master-bin.000003
insert into t2 values (65);
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 60 master-bin.000003 290 slave-relay-bin.000001 1088 master-bin.000003 Yes Yes 0 0 290 1088 None 0 No #
+# 127.0.0.1 root MASTER_PORT 60 master-bin.000003 496 # # master-bin.000003 Yes Yes 0 0 496 # None 0 No #
select * from t2;
m
34
@@ -76,15 +76,16 @@ show binary logs;
Log_name
master-bin.000003
master-bin.000004
+master-bin.000005
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000004 2886
+master-bin.000005 2032
select * from t4;
a
testing temporary tables part 2
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_PORT 60 master-bin.000004 2886 slave-relay-bin.000001 7891 master-bin.000004 Yes Yes 0 0 2886 7891 None 0 No #
+# 127.0.0.1 root MASTER_PORT 60 master-bin.000005 2032 # # master-bin.000005 Yes Yes 0 0 2032 # None 0 No #
lock tables t3 read;
select count(*) from t3 where n >= 4;
count(*)
diff --git a/mysql-test/r/rpl_server_id1.result b/mysql-test/r/rpl_server_id1.result
index 32e14b053d7..a3ab6672f69 100644
--- a/mysql-test/r/rpl_server_id1.result
+++ b/mysql-test/r/rpl_server_id1.result
@@ -10,7 +10,7 @@ stop slave;
change master to master_port=SLAVE_PORT;
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 SLAVE_PORT 1 4 slave-relay-bin.000001 4 No No # 0 0 0 4 None 0 No NULL
+ 127.0.0.1 root SLAVE_PORT 1 4 slave-relay-bin.000001 4 No No # 0 0 0 98 None 0 No NULL
start slave;
insert into t1 values (1);
show status like "slave_running";
diff --git a/mysql-test/r/rpl_server_id2.result b/mysql-test/r/rpl_server_id2.result
index 82ab1ff85a7..b196646aecc 100644
--- a/mysql-test/r/rpl_server_id2.result
+++ b/mysql-test/r/rpl_server_id2.result
@@ -10,7 +10,7 @@ stop slave;
change master to master_port=SLAVE_PORT;
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 SLAVE_PORT 1 4 slave-relay-bin.000001 4 No No # 0 0 0 4 None 0 No NULL
+ 127.0.0.1 root SLAVE_PORT 1 4 slave-relay-bin.000001 4 No No # 0 0 0 98 None 0 No NULL
start slave;
insert into t1 values (1);
select * from t1;
diff --git a/mysql-test/r/rpl_session_var.result b/mysql-test/r/rpl_session_var.result
new file mode 100644
index 00000000000..b5b4b815ade
--- /dev/null
+++ b/mysql-test/r/rpl_session_var.result
@@ -0,0 +1,43 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+create table t1(a varchar(100),b int);
+set @@session.sql_mode=pipes_as_concat;
+insert into t1 values('My'||'SQL', 1);
+set @@session.sql_mode=default;
+insert into t1 values('1'||'2', 2);
+select * from t1 where b<3 order by a;
+a b
+1 2
+MySQL 1
+select * from t1 where b<3 order by a;
+a b
+1 2
+MySQL 1
+set @@session.sql_mode=ignore_space;
+insert into t1 values(password ('MySQL'), 3);
+set @@session.sql_mode=ansi_quotes;
+create table "t2" ("a" int);
+drop table t1, t2;
+set @@session.sql_mode=default;
+create table t1(a int auto_increment primary key);
+create table t2(b int, a int);
+set @@session.sql_auto_is_null=1;
+insert into t1 values(null);
+insert into t2 select 1,a from t1 where a is null;
+set @@session.sql_auto_is_null=0;
+insert into t1 values(null);
+insert into t2 select 2,a from t1 where a is null;
+select * from t2 order by b;
+b a
+1 1
+select * from t2 order by b;
+b a
+1 1
+drop table t1,t2;
diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result
index b9865d282fa..a76fb87a52b 100644
--- a/mysql-test/r/rpl_temporary.result
+++ b/mysql-test/r/rpl_temporary.result
@@ -7,12 +7,12 @@ start slave;
reset master;
SET @save_select_limit=@@session.sql_select_limit;
SET @@session.sql_select_limit=10, @@session.pseudo_thread_id=100;
-ERROR HY000: Access denied; you need the SUPER privilege for this operation
+ERROR 42000: Access denied; you need the SUPER privilege for this operation
SELECT @@session.sql_select_limit = @save_select_limit;
@@session.sql_select_limit = @save_select_limit
1
SET @@session.sql_select_limit=10, @@session.sql_log_bin=0;
-ERROR HY000: Access denied; you need the SUPER privilege for this operation
+ERROR 42000: Access denied; you need the SUPER privilege for this operation
SELECT @@session.sql_select_limit = @save_select_limit;
@@session.sql_select_limit = @save_select_limit
1
@@ -37,20 +37,20 @@ f
5
7
show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 use `test`; drop table if exists t1,t2
-master-bin.000001 140 Query 1 140 use `test`; create table t1(f int)
-master-bin.000001 197 Query 1 197 use `test`; create table t2(f int)
-master-bin.000001 254 Query 1 254 use `test`; insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
-master-bin.000001 351 Query 1 351 use `test`; create temporary table t3(f int)
-master-bin.000001 418 Query 1 418 use `test`; insert into t3 select * from t1 where f<6
-master-bin.000001 494 Query 1 494 use `test`; create temporary table t3(f int)
-master-bin.000001 561 Query 1 561 use `test`; insert into t2 select count(*) from t3
-master-bin.000001 634 Query 1 634 use `test`; insert into t3 select * from t1 where f>=4
-master-bin.000001 711 Query 1 711 use `test`; drop temporary table t3
-master-bin.000001 769 Query 1 769 use `test`; insert into t2 select count(*) from t3
-master-bin.000001 842 Query 1 842 use `test`; drop temporary table t3
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4
+master-bin.000001 # Query 1 # use `test`; drop table if exists t1,t2
+master-bin.000001 # Query 1 # use `test`; create table t1(f int)
+master-bin.000001 # Query 1 # use `test`; create table t2(f int)
+master-bin.000001 # Query 1 # use `test`; insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
+master-bin.000001 # Query 1 # use `test`; create temporary table t3(f int)
+master-bin.000001 # Query 1 # use `test`; insert into t3 select * from t1 where f<6
+master-bin.000001 # Query 1 # use `test`; create temporary table t3(f int)
+master-bin.000001 # Query 1 # use `test`; insert into t2 select count(*) from t3
+master-bin.000001 # Query 1 # use `test`; insert into t3 select * from t1 where f>=4
+master-bin.000001 # Query 1 # use `test`; drop temporary table t3
+master-bin.000001 # Query 1 # use `test`; insert into t2 select count(*) from t3
+master-bin.000001 # Query 1 # use `test`; drop temporary table t3
drop table t1, t2;
use test;
SET TIMESTAMP=1040323920;
diff --git a/mysql-test/r/rpl_timezone.result b/mysql-test/r/rpl_timezone.result
index c7be3324533..85637638f99 100644
--- a/mysql-test/r/rpl_timezone.result
+++ b/mysql-test/r/rpl_timezone.result
@@ -4,21 +4,31 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
+set timestamp=100000000;
create table t1 (t timestamp);
create table t2 (t char(32));
select @@time_zone;
@@time_zone
+Japan
+select @@time_zone;
+@@time_zone
Europe/Moscow
+insert into t1 values ('20050101000000'), ('20050611093902');
set time_zone='UTC';
insert into t1 values ('20040101000000'), ('20040611093902');
select * from t1;
t
+2004-12-31 21:00:00
+2005-06-11 05:39:02
2004-01-01 00:00:00
2004-06-11 09:39:02
+set time_zone='UTC';
select * from t1;
t
-2004-01-01 03:00:00
-2004-06-11 13:39:02
+2004-12-31 21:00:00
+2005-06-11 05:39:02
+2004-01-01 00:00:00
+2004-06-11 09:39:02
delete from t1;
set time_zone='Europe/Moscow';
insert into t1 values ('20040101000000'), ('20040611093902');
@@ -26,19 +36,51 @@ select * from t1;
t
2004-01-01 00:00:00
2004-06-11 09:39:02
+set time_zone='Europe/Moscow';
+select * from t1;
+t
+2004-01-01 00:00:00
+2004-06-11 09:39:02
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
+use test;
+SET TIMESTAMP=100000000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
+create table t1 (t timestamp);
+SET TIMESTAMP=100000000;
+create table t2 (t char(32));
+SET TIMESTAMP=100000000;
+SET @@session.time_zone='Europe/Moscow';
+insert into t1 values ('20050101000000'), ('20050611093902');
+SET TIMESTAMP=100000000;
+SET @@session.time_zone='UTC';
+insert into t1 values ('20040101000000'), ('20040611093902');
+SET TIMESTAMP=100000000;
+delete from t1;
+SET TIMESTAMP=100000000;
+SET @@session.time_zone='Europe/Moscow';
+insert into t1 values ('20040101000000'), ('20040611093902');
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+delete from t1;
+set time_zone='UTC';
+load data infile '../../std_data/rpl_timezone.dat' into table t1;
select * from t1;
t
2004-01-01 00:00:00
2004-06-11 09:39:02
-show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 use `test`; create table t1 (t timestamp)
-master-bin.000001 143 Query 1 143 use `test`; create table t2 (t char(32))
-master-bin.000001 206 Query 1 206 use `test`; SET ONE_SHOT TIME_ZONE='UTC'
-master-bin.000001 269 Query 1 269 use `test`; insert into t1 values ('20040101000000'), ('20040611093902')
-master-bin.000001 364 Query 1 364 use `test`; delete from t1
-master-bin.000001 413 Query 1 413 use `test`; insert into t1 values ('20040101000000'), ('20040611093902')
+set time_zone='UTC';
+select * from t1;
+t
+2004-01-01 00:00:00
+2004-06-11 09:39:02
+set time_zone='Europe/Moscow';
+set time_zone='Europe/Moscow';
+delete from t1;
+insert into t1 values ('20040101000000'), ('20040611093902');
set time_zone='MET';
insert into t2 (select t from t1);
select * from t1;
@@ -52,10 +94,6 @@ t
delete from t2;
set timestamp=1000072000;
insert into t2 values (current_timestamp), (current_date), (current_time);
-set timestamp=1000072000;
-select current_timestamp, current_date, current_time;
-current_timestamp current_date current_time
-2001-09-10 01:46:40 2001-09-10 01:46:40
select * from t2;
t
2001-09-09 23:46:40
@@ -73,5 +111,16 @@ t
2001-09-09 03:46:40
1000000000
set global time_zone='MET';
-ERROR HY000: Binary logging and replication forbid changing of the global server time zone
+delete from t2;
+set time_zone='UTC';
+insert into t2 values(convert_tz('2004-01-01 00:00:00','MET',@@time_zone));
+insert into t2 values(convert_tz('2005-01-01 00:00:00','MET','Japan'));
+select * from t2;
+t
+2003-12-31 23:00:00
+2005-01-01 08:00:00
+select * from t2;
+t
+2003-12-31 23:00:00
+2005-01-01 08:00:00
drop table t1, t2;
diff --git a/mysql-test/r/rpl_trunc_binlog.result b/mysql-test/r/rpl_trunc_binlog.result
index 085a2937584..2663fffe4d4 100644
--- a/mysql-test/r/rpl_trunc_binlog.result
+++ b/mysql-test/r/rpl_trunc_binlog.result
@@ -6,8 +6,12 @@ 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 slave-relay-bin.000002 123 master-bin.000001 Yes No 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 79 # None 0 No #
+# 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/rpl_until.result b/mysql-test/r/rpl_until.result
index 5772f176919..64efeab0145 100644
--- a/mysql-test/r/rpl_until.result
+++ b/mysql-test/r/rpl_until.result
@@ -13,16 +13,16 @@ insert into t2 values (1),(2);
insert into t2 values (3),(4);
drop table t2;
show binlog events;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
-master-bin.000001 79 Query 1 79 use `test`; create table t1(n int not null auto_increment primary key)
-master-bin.000001 172 Query 1 172 use `test`; insert into t1 values (1),(2),(3),(4)
-master-bin.000001 244 Query 1 244 use `test`; drop table t1
-master-bin.000001 292 Query 1 292 use `test`; create table t2(n int not null auto_increment primary key)
-master-bin.000001 385 Query 1 385 use `test`; insert into t2 values (1),(2)
-master-bin.000001 449 Query 1 449 use `test`; insert into t2 values (3),(4)
-master-bin.000001 513 Query 1 513 use `test`; drop table t2
-start slave until master_log_file='master-bin.000001', master_log_pos=244;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4
+master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key)
+master-bin.000001 219 Query 1 319 use `test`; insert into t1 values (1),(2),(3),(4)
+master-bin.000001 319 Query 1 395 use `test`; drop table t1
+master-bin.000001 395 Query 1 516 use `test`; create table t2(n int not null auto_increment primary key)
+master-bin.000001 516 Query 1 608 use `test`; insert into t2 values (1),(2)
+master-bin.000001 608 Query 1 700 use `test`; insert into t2 values (3),(4)
+master-bin.000001 700 Query 1 776 use `test`; drop table t2
+start slave until master_log_file='master-bin.000001', master_log_pos=319;
select * from t1;
n
1
@@ -31,7 +31,7 @@ n
4
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 561 slave-relay-bin.000002 # master-bin.000001 Yes No 0 0 244 # Master master-bin.000001 244 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 319 # Master master-bin.000001 319 No #
start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291;
select * from t1;
n
@@ -41,21 +41,21 @@ n
4
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 561 slave-relay-bin.000002 # master-bin.000001 Yes No 0 0 244 # Master master-no-such-bin.000001 291 No #
-start slave until relay_log_file='slave-relay-bin.000002', relay_log_pos=537;
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 319 # Master master-no-such-bin.000001 291 No #
+start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746;
select * from t2;
n
1
2
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 561 slave-relay-bin.000002 # master-bin.000001 Yes No 0 0 449 # Relay slave-relay-bin.000002 537 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 608 # Relay slave-relay-bin.000004 746 No #
start slave;
stop slave;
-start slave until master_log_file='master-bin.000001', master_log_pos=561;
+start slave until master_log_file='master-bin.000001', master_log_pos=776;
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 561 slave-relay-bin.000002 # master-bin.000001 Yes No 0 0 561 # Master master-bin.000001 561 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 776 # Master master-bin.000001 776 No #
start slave until master_log_file='master-bin', master_log_pos=561;
ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UNTIL
start slave until master_log_file='master-bin.000001', master_log_pos=561, relay_log_pos=12;
@@ -67,6 +67,6 @@ ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UN
start slave until relay_log_file='slave-relay-bin.000002', master_log_pos=561;
ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UNTIL
start slave sql_thread;
-start slave until master_log_file='master-bin.000001', master_log_pos=561;
+start slave until master_log_file='master-bin.000001', master_log_pos=776;
Warnings:
Note 1254 Slave is already running
diff --git a/mysql-test/r/rpl_user_variables.result b/mysql-test/r/rpl_user_variables.result
index 85768270ba3..4198bbcc154 100644
--- a/mysql-test/r/rpl_user_variables.result
+++ b/mysql-test/r/rpl_user_variables.result
@@ -76,34 +76,35 @@ abcn1n2
NULL
NULL
NULL
-show binlog events from 141;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-slave-bin.000001 141 User var 2 141 @`i1`=12345678901234
-slave-bin.000001 184 User var 2 184 @`i2`=-12345678901234
-slave-bin.000001 227 User var 2 227 @`i3`=0
-slave-bin.000001 270 User var 2 270 @`i4`=-1
-slave-bin.000001 313 Query 1 313 use `test`; insert into t1 values (@i1), (@i2), (@i3), (@i4)
-slave-bin.000001 396 User var 2 396 @`r1`=12.5
-slave-bin.000001 439 User var 2 439 @`r2`=-12.5
-slave-bin.000001 482 Query 1 482 use `test`; insert into t1 values (@r1), (@r2)
-slave-bin.000001 551 User var 2 551 @`s1`=_latin1 0x5468697320697320612074657374 COLLATE latin1_swedish_ci
-slave-bin.000001 600 User var 2 600 @`s2`=_latin1 "" COLLATE latin1_swedish_ci
-slave-bin.000001 635 User var 2 635 @`s3`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci
-slave-bin.000001 677 User var 2 677 @`s4`=_latin1 0x6162635C646566 COLLATE latin1_swedish_ci
-slave-bin.000001 719 User var 2 719 @`s5`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci
-slave-bin.000001 761 Query 1 761 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5)
-slave-bin.000001 851 User var 2 851 @`n1`=NULL
-slave-bin.000001 877 Query 1 877 use `test`; insert into t1 values (@n1)
-slave-bin.000001 939 User var 2 939 @`n2`=NULL
-slave-bin.000001 965 Query 1 965 use `test`; insert into t1 values (@n2)
-slave-bin.000001 1027 Query 1 1027 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1)
-slave-bin.000001 1115 User var 2 1115 @`a`=2
-slave-bin.000001 1157 Query 1 1157 use `test`; insert into t1 values (@a+(@b:=@a+1))
-slave-bin.000001 1229 User var 2 1229 @`q`=_latin1 0x616263 COLLATE latin1_swedish_ci
-slave-bin.000001 1266 Query 1 1266 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2'))
-slave-bin.000001 1370 User var 2 1370 @`a`=5
-slave-bin.000001 1412 Query 1 1412 use `test`; insert into t1 values (@a),(@a)
-slave-bin.000001 1478 User var 2 1478 @`a`=NULL
-slave-bin.000001 1503 Query 1 1503 use `test`; insert into t1 values (@a),(@a),(@a*5)
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+slave-bin.000001 # Query 1 # use `test`; create table t1(n char(30))
+slave-bin.000001 # User var 2 # @`i1`=12345678901234
+slave-bin.000001 # User var 2 # @`i2`=-12345678901234
+slave-bin.000001 # User var 2 # @`i3`=0
+slave-bin.000001 # User var 2 # @`i4`=-1
+slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@i1), (@i2), (@i3), (@i4)
+slave-bin.000001 # User var 2 # @`r1`=12.5
+slave-bin.000001 # User var 2 # @`r2`=-12.5
+slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@r1), (@r2)
+slave-bin.000001 # User var 2 # @`s1`=_latin1 0x5468697320697320612074657374 COLLATE latin1_swedish_ci
+slave-bin.000001 # User var 2 # @`s2`=_latin1 "" COLLATE latin1_swedish_ci
+slave-bin.000001 # User var 2 # @`s3`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci
+slave-bin.000001 # User var 2 # @`s4`=_latin1 0x6162635C646566 COLLATE latin1_swedish_ci
+slave-bin.000001 # User var 2 # @`s5`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci
+slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5)
+slave-bin.000001 # User var 2 # @`n1`=NULL
+slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@n1)
+slave-bin.000001 # User var 2 # @`n2`=NULL
+slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@n2)
+slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1)
+slave-bin.000001 # User var 2 # @`a`=2
+slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a+(@b:=@a+1))
+slave-bin.000001 # User var 2 # @`q`=_latin1 0x616263 COLLATE latin1_swedish_ci
+slave-bin.000001 # Query 1 # use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2'))
+slave-bin.000001 # User var 2 # @`a`=5
+slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a),(@a)
+slave-bin.000001 # User var 2 # @`a`=NULL
+slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a),(@a),(@a*5)
drop table t1;
stop slave;
diff --git a/mysql-test/r/rpl_view.result b/mysql-test/r/rpl_view.result
new file mode 100644
index 00000000000..ce807a361ba
--- /dev/null
+++ b/mysql-test/r/rpl_view.result
@@ -0,0 +1,44 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+drop table if exists t1,v1;
+drop view if exists t1,v1;
+create table t1 (a int);
+insert into t1 values (1);
+create view v1 as select a from t1;
+insert into v1 values (2);
+select * from v1 order by a;
+a
+1
+2
+select * from v1 order by a;
+a
+1
+2
+update v1 set a=3 where a=1;
+select * from v1 order by a;
+a
+2
+3
+select * from v1 order by a;
+a
+2
+3
+delete from v1 where a=2;
+select * from v1 order by a;
+a
+3
+select * from v1 order by a;
+a
+3
+alter view v1 as select a as b from t1;
+select * from v1 order by 1;
+b
+3
+drop view v1;
+select * from v1 order by a;
+ERROR 42S02: Table 'test.v1' doesn't exist
+drop table t1;
diff --git a/mysql-test/r/schema.result b/mysql-test/r/schema.result
new file mode 100644
index 00000000000..48e6ebcfad2
--- /dev/null
+++ b/mysql-test/r/schema.result
@@ -0,0 +1,11 @@
+create schema foo;
+show create schema foo;
+Database Create Database
+foo CREATE DATABASE `foo` /*!40100 DEFAULT CHARACTER SET latin1 */
+show schemas;
+Database
+information_schema
+foo
+mysql
+test
+drop schema foo;
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index 9df5efc66d6..7f131c63421 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -1,5 +1,6 @@
drop table if exists t1,t2,t3,t4;
-drop table if exists t1_1,t1_2,t9_1,t9_2;
+drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa;
+drop view if exists v1;
CREATE TABLE t1 (
Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL,
Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL
@@ -1375,7 +1376,7 @@ id select_type table type possible_keys key key_len ref rows Extra
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
-1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where
+1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t4 ALL NULL NULL NULL NULL 12
@@ -1394,8 +1395,8 @@ companynr companynr
41 40
explain select distinct t2.companynr,t4.companynr from t2,t4 where t2.companynr=t4.companynr+1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using temporary
-1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using where; Using index
+1 SIMPLE t4 index NULL PRIMARY 1 NULL 12 Using index; Using temporary
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
select t2.fld1,t2.companynr,fld3,period from t3,t2 where t2.fld1 = 38208 and t2.fld1=t3.t2nr and period = 1008 or t2.fld1 = 38008 and t2.fld1 =t3.t2nr and period = 1008;
fld1 companynr fld3 period
038008 37 reporters 1008
@@ -1471,7 +1472,7 @@ explain extended select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
Warnings:
-Note 1003 select count(0) AS `count(*)`,min(test.t2.fld4) AS `min(fld4)`,max(test.t2.fld4) AS `max(fld4)`,sum(test.t2.fld1) AS `sum(fld1)`,avg(test.t2.fld1) AS `avg(fld1)`,std(test.t2.fld1) AS `std(fld1)`,variance(test.t2.fld1) AS `variance(fld1)` from test.t2 where ((test.t2.companynr = 34) and (test.t2.fld4 <> _latin1''))
+Note 1003 select count(0) AS `count(*)`,min(`test`.`t2`.`fld4`) AS `min(fld4)`,max(`test`.`t2`.`fld4`) AS `max(fld4)`,sum(`test`.`t2`.`fld1`) AS `sum(fld1)`,avg(`test`.`t2`.`fld1`) AS `avg(fld1)`,std(`test`.`t2`.`fld1`) AS `std(fld1)`,variance(`test`.`t2`.`fld1`) AS `variance(fld1)` from `test`.`t2` where ((`test`.`t2`.`companynr` = 34) and (`test`.`t2`.`fld4` <> _latin1''))
select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 group by companynr limit 3;
companynr count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) variance(fld1)
00 82 Anthony windmills 10355753 126289.6707 115550.9757 13352027981.7087
@@ -1671,7 +1672,7 @@ fld1 count(*)
158402 4181
select sum(Period)/count(*) from t1;
sum(Period)/count(*)
-9410.00
+9410.00000
select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr;
companynr count sum diff func
37 12543 309394878010 0.0000 464091
@@ -2033,20 +2034,20 @@ show tables from test like "t?";
Tables_in_test (t?)
show full columns from t2;
Field Type Collation Null Key Default Extra Privileges Comment
-auto int(11) NULL PRI NULL auto_increment #
-fld1 int(6) unsigned zerofill NULL UNI 000000 #
-companynr tinyint(2) unsigned zerofill NULL 00 #
-fld3 char(30) latin1_swedish_ci MUL #
-fld4 char(35) latin1_swedish_ci #
-fld5 char(35) latin1_swedish_ci #
-fld6 char(4) latin1_swedish_ci #
+auto int(11) NULL NO PRI NULL auto_increment #
+fld1 int(6) unsigned zerofill NULL NO UNI 000000 #
+companynr tinyint(2) unsigned zerofill NULL NO 00 #
+fld3 char(30) latin1_swedish_ci NO MUL #
+fld4 char(35) latin1_swedish_ci NO #
+fld5 char(35) latin1_swedish_ci NO #
+fld6 char(4) latin1_swedish_ci NO #
show full columns from t2 from test like 'f%';
Field Type Collation Null Key Default Extra Privileges Comment
-fld1 int(6) unsigned zerofill NULL UNI 000000 #
-fld3 char(30) latin1_swedish_ci MUL #
-fld4 char(35) latin1_swedish_ci #
-fld5 char(35) latin1_swedish_ci #
-fld6 char(4) latin1_swedish_ci #
+fld1 int(6) unsigned zerofill NULL NO UNI 000000 #
+fld3 char(30) latin1_swedish_ci NO MUL #
+fld4 char(35) latin1_swedish_ci NO #
+fld5 char(35) latin1_swedish_ci NO #
+fld6 char(4) latin1_swedish_ci NO #
show full columns from t2 from test like 's%';
Field Type Collation Null Key Default Extra Privileges Comment
show keys from t2;
@@ -2079,10 +2080,8 @@ INSERT INTO t2 VALUES (1,3,10,'2002-06-01 08:00:00',35),(1,3,1010,'2002-06-01 12
SELECT a.gvid, (SUM(CASE b.sampletid WHEN 140 THEN b.samplevalue ELSE 0 END)) as the_success,(SUM(CASE b.sampletid WHEN 141 THEN b.samplevalue ELSE 0 END)) as the_fail,(SUM(CASE b.sampletid WHEN 142 THEN b.samplevalue ELSE 0 END)) as the_size,(SUM(CASE b.sampletid WHEN 143 THEN b.samplevalue ELSE 0 END)) as the_time FROM t1 a, t2 b WHERE a.hmid = b.hmid AND a.volid = b.volid AND b.sampletime >= 'wrong-date-value' AND b.sampletime < 'wrong-date-value' AND b.sampletid IN (140, 141, 142, 143) GROUP BY a.gvid;
gvid the_success the_fail the_size the_time
Warnings:
-Warning 1292 Truncated incorrect datetime value: 'wrong-date-value'
-Warning 1292 Truncated incorrect datetime value: 'wrong-date-value'
-Warning 1292 Truncated incorrect datetime value: 'wrong-date-value'
-Warning 1292 Truncated incorrect datetime value: 'wrong-date-value'
+Warning 1292 Incorrect datetime value: 'wrong-date-value' for column 'sampletime' at row 1
+Warning 1292 Incorrect datetime value: 'wrong-date-value' for column 'sampletime' at row 1
SELECT a.gvid, (SUM(CASE b.sampletid WHEN 140 THEN b.samplevalue ELSE 0 END)) as the_success,(SUM(CASE b.sampletid WHEN 141 THEN b.samplevalue ELSE 0 END)) as the_fail,(SUM(CASE b.sampletid WHEN 142 THEN b.samplevalue ELSE 0 END)) as the_size,(SUM(CASE b.sampletid WHEN 143 THEN b.samplevalue ELSE 0 END)) as the_time FROM t1 a, t2 b WHERE a.hmid = b.hmid AND a.volid = b.volid AND b.sampletime >= NULL AND b.sampletime < NULL AND b.sampletid IN (140, 141, 142, 143) GROUP BY a.gvid;
gvid the_success the_fail the_size the_time
DROP TABLE t1,t2;
@@ -2110,7 +2109,7 @@ select @b;
aaaa
select @c;
@c
-6.26
+6.260
create table t1 (a int not null auto_increment primary key);
insert into t1 values ();
insert into t1 values ();
@@ -2162,20 +2161,17 @@ a a a
select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1;
a a a
1 1 2
-1 1 3
2 2 2
-2 2 3
3 3 2
+1 1 3
+2 2 3
3 3 3
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
a a a
-1 1 NULL
2 1 1
3 1 1
-1 2 NULL
2 2 2
3 2 2
-1 3 NULL
2 3 3
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 using ( a );
@@ -2186,13 +2182,7 @@ a a a
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) using ( a );
a a a
1 1 1
-2 1 NULL
-3 1 NULL
-1 2 NULL
2 2 2
-3 2 NULL
-1 3 NULL
-2 3 NULL
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) left outer join t1 on t1.a>1;
a a a
@@ -2204,14 +2194,12 @@ a a a
3 3 3
select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
a a a
-1 1 NULL
+1 NULL NULL
2 1 1
-3 1 1
-1 2 NULL
2 2 2
-3 2 2
-1 3 NULL
2 3 3
+3 1 1
+3 2 2
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) left join t1 using ( a );
a a a
@@ -2221,13 +2209,7 @@ a a a
select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a );
a a a
1 1 1
-2 1 NULL
-3 1 NULL
-1 2 NULL
2 2 2
-3 2 NULL
-1 3 NULL
-2 3 NULL
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1;
a a a
@@ -2241,9 +2223,7 @@ a a a
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1;
a a a
-1 NULL 1
-2 NULL 1
-3 NULL 1
+NULL NULL 1
1 1 2
2 2 2
3 3 2
@@ -2261,13 +2241,7 @@ a a a
select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a );
a a a
1 1 1
-2 NULL 1
-3 NULL 1
-1 NULL 2
2 2 2
-3 NULL 2
-1 NULL 3
-2 NULL 3
3 3 3
select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a );
a a a
@@ -2277,13 +2251,7 @@ a a a
select * from (t1 as t2 left join t1 as t3 using (a)) natural right join t1;
a a a
1 1 1
-2 NULL 1
-3 NULL 1
-1 NULL 2
2 2 2
-3 NULL 2
-1 NULL 3
-2 NULL 3
3 3 3
select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a));
a a a
@@ -2296,10 +2264,10 @@ a a
2 2
3 3
select * from (t1 as t2 left join t1 as t3 using (a)) natural join t1;
-a a a
-1 1 1
-2 2 2
-3 3 3
+a a
+1 1
+2 2
+3 3
drop table t1;
CREATE TABLE t1 ( aa char(2), id int(11) NOT NULL auto_increment, t2_id int(11) NOT NULL default '0', PRIMARY KEY (id), KEY replace_id (t2_id)) ENGINE=MyISAM;
INSERT INTO t1 VALUES ("1",8264,2506),("2",8299,2517),("3",8301,2518),("4",8302,2519),("5",8303,2520),("6",8304,2521),("7",8305,2522);
@@ -2345,7 +2313,7 @@ select * from t2 where s = 'one';
s
select * from t3 where s = 'one';
s
-one
+one
select * from t1,t2 where t1.s = t2.s;
s s
two two
@@ -2387,6 +2355,39 @@ EXPLAIN SELECT i FROM t1 WHERE i=1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index
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',
+F2I4 int(11) NOT NULL default '0'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES
+('W%RT', '0100', 1),
+('W-RT', '0100', 1),
+('WART', '0100', 1),
+('WART', '0200', 1),
+('WERT', '0100', 2),
+('WORT','0200', 2),
+('WT', '0100', 2),
+('W_RT', '0100', 2),
+('WaRT', '0100', 3),
+('WART', '0300', 3),
+('WRT' , '0400', 3),
+('WURM', '0500', 3),
+('W%T', '0600', 4),
+('WA%T', '0700', 4),
+('WA_T', '0800', 4);
+SELECT K2C4, K4N4, F2I4 FROM t1
+WHERE K2C4 = 'WART' AND
+(F2I4 = 2 AND K2C4 = 'WART' OR (F2I4 = 2 OR K4N4 = '0200'));
+K2C4 K4N4 F2I4
+WART 0200 1
+SELECT K2C4, K4N4, F2I4 FROM t1
+WHERE K2C4 = 'WART' AND (K2C4 = 'WART' OR K4N4 = '0200');
+K2C4 K4N4 F2I4
+WART 0100 1
+WART 0200 1
+WART 0300 3
+DROP TABLE t1;
CREATE TABLE t1 ( a BLOB, INDEX (a(20)) );
CREATE TABLE t2 ( a BLOB, INDEX (a(20)) );
INSERT INTO t1 VALUES ('one'),('two'),('three'),('four'),('five');
@@ -2445,3 +2446,12 @@ cast((a - b) as unsigned)
1
18446744073709551615
drop table t1;
+create table t1 (a int, b int);
+create table t2 like t1;
+select t1.a from (t1 inner join t2 on t1.a=t2.a) where t2.a=1;
+a
+select t1.a from ((t1 inner join t2 on t1.a=t2.a)) where t2.a=1;
+a
+select x.a, y.a, z.a from ( (t1 x inner join t2 y on x.a=y.a) inner join t2 z on y.a=z.a) WHERE x.a=1;
+a a a
+drop table t1,t2;
diff --git a/mysql-test/r/select_found.result b/mysql-test/r/select_found.result
index b8178bbeb52..7abd65beb46 100644
--- a/mysql-test/r/select_found.result
+++ b/mysql-test/r/select_found.result
@@ -84,7 +84,7 @@ UNIQUE KEY e_n (email,name)
EXPLAIN SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system PRIMARY,kid NULL NULL NULL 0 const row not found
-1 SIMPLE t2 index NULL e_n 100 NULL 200
+1 SIMPLE t2 index NULL e_n 104 NULL 200
SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
email
email1
diff --git a/mysql-test/r/have_isam.require b/mysql-test/r/server_id.require
index 9b4142361ed..adffcc483b1 100644
--- a/mysql-test/r/have_isam.require
+++ b/mysql-test/r/server_id.require
@@ -1,2 +1,2 @@
Variable_name Value
-have_isam YES
+server_id 1
diff --git a/mysql-test/r/server_id1.require b/mysql-test/r/server_id1.require
new file mode 100644
index 00000000000..666c94ef633
--- /dev/null
+++ b/mysql-test/r/server_id1.require
@@ -0,0 +1,2 @@
+Variable_name Value
+server_id 102
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index 4a9e28e9ea4..dd07e0ba755 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -1,4 +1,5 @@
drop table if exists t1,t2;
+drop table if exists t1aa,t2aa;
drop database if exists mysqltest;
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
@@ -50,6 +51,7 @@ show table status from test like "this_doesn't_exists%";
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
show databases;
Database
+information_schema
mysql
test
show databases like "test%";
@@ -80,13 +82,13 @@ create temporary table t1 (a int not null);
show create table t1;
Table Create Table
t1 CREATE TEMPORARY TABLE `t1` (
- `a` int(11) NOT NULL default '0'
+ `a` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
alter table t1 rename t2;
show create table t2;
Table Create Table
t2 CREATE TEMPORARY TABLE `t2` (
- `a` int(11) NOT NULL default '0'
+ `a` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t2;
create table t1 (
@@ -101,7 +103,7 @@ Table Create Table
t1 CREATE TABLE `t1` (
`test_set` set('val1','val2','val3') NOT NULL default '',
`name` char(20) default 'O''Brien' COMMENT 'O''Brien as default',
- `c` int(11) NOT NULL default '0' COMMENT 'int column',
+ `c` int(11) NOT NULL COMMENT 'int column',
`c-b` int(11) default NULL COMMENT 'name with a minus',
`space 2` int(11) default NULL COMMENT 'name with a space'
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='it''s a table'
@@ -110,17 +112,17 @@ show create table t1;
Table Create Table
t1 CREATE TABLE t1 (
test_set set('val1','val2','val3') NOT NULL default '',
- name char(20) default 'O''Brien' COMMENT 'O''Brien as default',
- c int(11) NOT NULL default '0' COMMENT 'int column',
+ `name` char(20) default 'O''Brien' COMMENT 'O''Brien as default',
+ c int(11) NOT NULL COMMENT 'int column',
`c-b` int(11) default NULL COMMENT 'name with a minus',
`space 2` int(11) default NULL COMMENT 'name with a space'
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='it''s a table'
set sql_quote_show_create=1;
show full columns from t1;
Field Type Collation Null Key Default Extra Privileges Comment
-test_set set('val1','val2','val3') latin1_swedish_ci select,insert,update,references
+test_set set('val1','val2','val3') latin1_swedish_ci NO select,insert,update,references
name char(20) latin1_swedish_ci YES O'Brien select,insert,update,references O'Brien as default
-c int(11) NULL 0 select,insert,update,references int column
+c int(11) NULL NO select,insert,update,references int column
c-b int(11) NULL YES NULL select,insert,update,references name with a minus
space 2 int(11) NULL YES NULL select,insert,update,references name with a space
drop table t1;
@@ -128,7 +130,7 @@ create table t1 (a int not null, unique aa (a));
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
UNIQUE KEY `aa` (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
@@ -136,7 +138,7 @@ create table t1 (a int not null, primary key (a));
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
@@ -153,15 +155,15 @@ create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CH
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
- `b` char(10) default NULL,
+ `a` int(11) NOT NULL,
+ `b` varchar(10) default NULL,
KEY `b` (`b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 MIN_ROWS=10 MAX_ROWS=100 AVG_ROW_LENGTH=10 PACK_KEYS=1 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=FIXED COMMENT='test'
alter table t1 MAX_ROWS=200 ROW_FORMAT=dynamic PACK_KEYS=0;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` varchar(10) default NULL,
KEY `b` (`b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 MIN_ROWS=10 MAX_ROWS=200 AVG_ROW_LENGTH=10 PACK_KEYS=0 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='test'
@@ -169,7 +171,7 @@ ALTER TABLE t1 AVG_ROW_LENGTH=0 CHECKSUM=0 COMMENT="" MIN_ROWS=0 MAX_ROWS=0 PACK
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` varchar(10) default NULL,
KEY `b` (`b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
@@ -193,7 +195,7 @@ h float(3,2) NULL YES NULL select,insert,update,references
i float(3,0) NULL YES NULL select,insert,update,references
drop table t1;
create table t1 (
-type_bool bool not null,
+type_bool bool not null default 0,
type_tiny tinyint not null auto_increment primary key,
type_short smallint(3),
type_mediumint mediumint,
@@ -204,9 +206,9 @@ empty_char char(0),
type_char char(2),
type_varchar varchar(10),
type_timestamp timestamp not null,
-type_date date not null,
-type_time time not null,
-type_datetime datetime not null,
+type_date date not null default '0000-00-00',
+type_time time not null default '00:00:00',
+type_datetime datetime not null default '0000-00-00 00:00:00',
type_year year,
type_enum enum ('red', 'green', 'blue'),
type_set enum ('red', 'green', 'blue'),
@@ -250,11 +252,9 @@ type_bool type_tiny type_short type_mediumint type_bigint type_decimal type_nume
drop table t1;
create table t1 (a int not null);
create table t2 select max(a) from t1;
-Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'max(a)' at row 1
show columns from t2;
Field Type Null Key Default Extra
-max(a) int(11) 0
+max(a) int(11) YES NULL
drop table t1,t2;
create table t1 (c decimal, d double, f float, r real);
show columns from t1;
@@ -275,7 +275,6 @@ SET @old_sql_mode= @@sql_mode, sql_mode= '';
SET @old_sql_quote_show_create= @@sql_quote_show_create, sql_quote_show_create= OFF;
CREATE TABLE `a/b` (i INT);
ERROR 42000: Incorrect table name 'a/b'
-SET sql_mode= 'ANSI_QUOTES';
SET sql_mode= '';
SET sql_quote_show_create= OFF;
CREATE TABLE t1 (i INT);
@@ -299,7 +298,7 @@ select @@max_heap_table_size;
1047552
CREATE TABLE t1 (
a int(11) default NULL,
-KEY a TYPE BTREE (a)
+KEY a USING BTREE (a)
) ENGINE=HEAP;
CREATE TABLE t2 (
b int(11) default NULL,
@@ -308,7 +307,7 @@ index(b)
CREATE TABLE t3 (
a int(11) default NULL,
b int(11) default NULL,
-KEY a TYPE BTREE (a),
+KEY a USING BTREE (a),
index(b)
) ENGINE=HEAP;
insert into t1 values (1),(2);
@@ -316,57 +315,57 @@ insert into t2 values (1),(2);
insert into t3 values (1,1),(2,2);
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 HEAP 9 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t2 HEAP 9 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t3 HEAP 9 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t1 MEMORY 10 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t2 MEMORY 10 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t3 MEMORY 10 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
insert into t1 values (3),(4);
insert into t2 values (3),(4);
insert into t3 values (3,3),(4,4);
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 HEAP 9 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t2 HEAP 9 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t3 HEAP 9 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t1 MEMORY 10 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t2 MEMORY 10 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t3 MEMORY 10 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
insert into t1 values (5);
insert into t2 values (5);
insert into t3 values (5,5);
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 HEAP 9 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t2 HEAP 9 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t3 HEAP 9 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t1 MEMORY 10 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t2 MEMORY 10 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t3 MEMORY 10 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
delete from t1 where a=3;
delete from t2 where b=3;
delete from t3 where a=3;
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 HEAP 9 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
-t2 HEAP 9 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
-t3 HEAP 9 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
+t1 MEMORY 10 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
+t2 MEMORY 10 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
+t3 MEMORY 10 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
delete from t1;
delete from t2;
delete from t3;
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 HEAP 9 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t2 HEAP 9 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t3 HEAP 9 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t1 MEMORY 10 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t2 MEMORY 10 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t3 MEMORY 10 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
insert into t1 values (5);
insert into t2 values (5);
insert into t3 values (5,5);
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 HEAP 9 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t2 HEAP 9 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
-t3 HEAP 9 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t1 MEMORY 10 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t2 MEMORY 10 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
+t3 MEMORY 10 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL
delete from t1 where a=5;
delete from t2 where b=5;
delete from t3 where a=5;
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 HEAP 9 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
-t2 HEAP 9 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
-t3 HEAP 9 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
+t1 MEMORY 10 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
+t2 MEMORY 10 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
+t3 MEMORY 10 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL
drop table t1, t2, t3;
create database mysqltest;
show create database mysqltest;
@@ -384,19 +383,19 @@ show create database mysqltest;
Database Create Database
mysqltest CREATE DATABASE `mysqltest` /*!40100 DEFAULT CHARACTER SET latin1 */
drop table t1;
-ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest'
+ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 't1'
drop database mysqltest;
ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest'
select * from mysqltest.t1;
-ERROR 42000: Access denied for user 'mysqltest_2'@'localhost' to database 'mysqltest'
+ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 't1'
show create database mysqltest;
ERROR 42000: Access denied for user 'mysqltest_2'@'localhost' to database 'mysqltest'
drop table mysqltest.t1;
-ERROR 42000: Access denied for user 'mysqltest_2'@'localhost' to database 'mysqltest'
+ERROR 42000: DROP command denied to user 'mysqltest_2'@'localhost' for table 't1'
drop database mysqltest;
ERROR 42000: Access denied for user 'mysqltest_2'@'localhost' to database 'mysqltest'
select * from mysqltest.t1;
-ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysqltest'
+ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 't1'
show create database mysqltest;
ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysqltest'
drop table mysqltest.t1;
@@ -413,23 +412,23 @@ Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) default NULL,
KEY `i` (`i`)
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (i int, KEY USING HASH (i)) ENGINE=MEMORY;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) default NULL,
- KEY `i` TYPE HASH (`i`)
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ KEY `i` USING HASH (`i`)
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (i int, KEY USING BTREE (i)) ENGINE=MEMORY;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) default NULL,
- KEY `i` TYPE BTREE (`i`)
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ KEY `i` USING BTREE (`i`)
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (i int, KEY (i)) ENGINE=MyISAM;
SHOW CREATE TABLE t1;
@@ -444,7 +443,7 @@ SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) default NULL,
- KEY `i` TYPE BTREE (`i`)
+ KEY `i` USING BTREE (`i`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (i int, KEY (i)) ENGINE=MyISAM;
@@ -460,22 +459,22 @@ Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) default NULL,
KEY `i` (`i`)
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (i int, KEY USING BTREE (i)) ENGINE=MyISAM;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) default NULL,
- KEY `i` TYPE BTREE (`i`)
+ KEY `i` USING BTREE (`i`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 ENGINE=MEMORY;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` int(11) default NULL,
- KEY `i` TYPE BTREE (`i`)
-) ENGINE=HEAP DEFAULT CHARSET=latin1
+ KEY `i` USING BTREE (`i`)
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1(
field1 text NOT NULL,
@@ -483,18 +482,18 @@ PRIMARY KEY(field1(1000))
);
show index from t1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def Table 253 64 2 N 129 31 63
-def Non_unique 1 1 1 N 32929 0 63
-def Key_name 253 64 7 N 129 31 63
-def Seq_in_index 1 2 1 N 32929 0 63
-def Column_name 253 64 6 N 129 31 63
-def Collation 253 1 1 Y 128 31 63
-def Cardinality 8 21 1 Y 32896 0 63
-def Sub_part 2 3 4 Y 32928 0 63
-def Packed 253 10 0 Y 128 31 63
-def Null 253 3 0 N 129 31 63
-def Index_type 253 16 5 N 129 31 63
-def Comment 253 255 0 N 129 31 63
+def STATISTICS TABLE_NAME Table 253 64 2 N 1 0 63
+def STATISTICS NON_UNIQUE Non_unique 8 1 1 N 32769 0 63
+def STATISTICS INDEX_NAME Key_name 253 64 7 N 1 0 63
+def STATISTICS SEQ_IN_INDEX Seq_in_index 8 2 1 N 32769 0 63
+def STATISTICS COLUMN_NAME Column_name 253 64 6 N 1 0 63
+def STATISTICS COLLATION Collation 253 1 1 Y 0 0 63
+def STATISTICS CARDINALITY Cardinality 8 21 1 Y 32768 0 63
+def STATISTICS SUB_PART Sub_part 8 3 4 Y 32768 0 63
+def STATISTICS PACKED Packed 253 10 0 Y 0 0 63
+def STATISTICS NULLABLE Null 253 3 0 N 1 0 63
+def STATISTICS INDEX_TYPE Index_type 253 16 5 N 1 0 63
+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;
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
new file mode 100644
index 00000000000..683f3e12091
--- /dev/null
+++ b/mysql-test/r/sp-error.result
@@ -0,0 +1,645 @@
+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
+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
+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
+drop table if exists t3|
+create table t3 ( x int )|
+insert into t3 values (2), (3)|
+create procedure bad_into(out param int)
+select x from t3 into param|
+call bad_into(@x)|
+ERROR 42000: Result consisted of more than one row
+drop procedure bad_into|
+drop table t3|
+create procedure proc1()
+set @x = 42|
+create function func1() returns int
+return 42|
+create procedure foo()
+create procedure bar() set @x=3|
+ERROR 2F003: Can't create a PROCEDURE from within another stored routine
+create procedure foo()
+create function bar() returns double return 2.3|
+ERROR 2F003: Can't create a FUNCTION from within another stored routine
+create procedure proc1()
+set @x = 42|
+ERROR 42000: PROCEDURE proc1 already exists
+create function func1() returns int
+return 42|
+ERROR 42000: FUNCTION func1 already exists
+drop procedure proc1|
+drop function func1|
+alter procedure foo|
+ERROR 42000: PROCEDURE test.foo does not exist
+alter function foo|
+ERROR 42000: FUNCTION test.foo does not exist
+drop procedure foo|
+ERROR 42000: PROCEDURE test.foo does not exist
+drop function foo|
+ERROR 42000: FUNCTION test.foo does not exist
+call foo()|
+ERROR 42000: PROCEDURE test.foo does not exist
+drop procedure if exists foo|
+Warnings:
+Note 1305 PROCEDURE foo does not exist
+show create procedure foo|
+ERROR 42000: PROCEDURE foo does not exist
+show create function foo|
+ERROR 42000: FUNCTION foo does not exist
+create procedure foo()
+foo: loop
+leave bar;
+end loop|
+ERROR 42000: LEAVE with no matching label: bar
+create procedure foo()
+foo: loop
+iterate bar;
+end loop|
+ERROR 42000: ITERATE with no matching label: bar
+create procedure foo()
+foo: begin
+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;
+end loop foo;
+end loop foo|
+ERROR 42000: Redefining label foo
+create procedure foo()
+foo: loop
+set @x=2;
+end loop bar|
+ERROR 42000: End-label bar without match
+create procedure foo()
+return 42|
+ERROR 42000: RETURN is only allowed in a FUNCTION
+create procedure p(x int)
+set @x = x|
+create function f(x int) returns int
+return x+42|
+call p()|
+ERROR 42000: Incorrect number of arguments for PROCEDURE test.p; expected 1, got 0
+call p(1, 2)|
+ERROR 42000: Incorrect number of arguments for PROCEDURE test.p; expected 1, got 2
+select f()|
+ERROR 42000: Incorrect number of arguments for FUNCTION test.f; expected 1, got 0
+select f(1, 2)|
+ERROR 42000: Incorrect number of arguments for FUNCTION test.f; expected 1, got 2
+drop procedure p|
+drop function f|
+create procedure p(val int, out res int)
+begin
+declare x int default 0;
+declare continue handler for foo set x = 1;
+insert into test.t1 values (val);
+if (x) then
+set res = 0;
+else
+set res = 1;
+end if;
+end|
+ERROR 42000: Undefined CONDITION: foo
+create procedure p(val int, out res int)
+begin
+declare x int default 0;
+declare foo condition for 1146;
+declare continue handler for bar set x = 1;
+insert into test.t1 values (val);
+if (x) then
+set res = 0;
+else
+set res = 1;
+end if;
+end|
+ERROR 42000: Undefined CONDITION: bar
+create function f(val int) returns int
+begin
+declare x int;
+set x = val+3;
+end|
+ERROR 42000: No RETURN found in FUNCTION f
+create function f(val int) returns int
+begin
+declare x int;
+set x = val+3;
+if x < 4 then
+return x;
+end if;
+end|
+select f(10)|
+ERROR 2F005: FUNCTION f ended without RETURN
+drop function f|
+create procedure p()
+begin
+declare c cursor for insert into test.t1 values ("foo", 42);
+open c;
+close c;
+end|
+ERROR 42000: Cursor statement must be a SELECT
+create procedure p()
+begin
+declare x int;
+declare c cursor for select * into x from test.t limit 1;
+open c;
+close c;
+end|
+ERROR 42000: Cursor SELECT must not have INTO
+create procedure p()
+begin
+declare c cursor for select * from test.t;
+open cc;
+close c;
+end|
+ERROR 42000: Undefined CURSOR: cc
+drop table if exists t1|
+create table t1 (val int)|
+create procedure p()
+begin
+declare c cursor for select * from test.t1;
+open c;
+open c;
+close c;
+end|
+call p()|
+ERROR 24000: Cursor is already open
+drop procedure p|
+create procedure p()
+begin
+declare c cursor for select * from test.t1;
+open c;
+close c;
+close c;
+end|
+call p()|
+ERROR 24000: Cursor is not open
+drop procedure p|
+alter procedure bar3 sql security invoker|
+ERROR 42000: PROCEDURE test.bar3 does not exist
+drop table t1|
+drop table if exists t1|
+create table t1 (val int, x float)|
+insert into t1 values (42, 3.1), (19, 1.2)|
+create procedure p()
+begin
+declare x int;
+declare c cursor for select * from t1;
+open c;
+fetch c into x, y;
+close c;
+end|
+ERROR 42000: Undeclared variable: y
+create procedure p()
+begin
+declare x int;
+declare c cursor for select * from t1;
+open c;
+fetch c into x;
+close c;
+end|
+call p()|
+ERROR HY000: Incorrect number of FETCH variables
+drop procedure p|
+create procedure p()
+begin
+declare x int;
+declare y float;
+declare z int;
+declare c cursor for select * from t1;
+open c;
+fetch c into x, y, z;
+close c;
+end|
+call p()|
+ERROR HY000: Incorrect number of FETCH variables
+drop procedure p|
+create procedure p(in x int, x char(10))
+begin
+end|
+ERROR 42000: Duplicate parameter: x
+create function p(x int, x char(10))
+begin
+end|
+ERROR 42000: Duplicate parameter: x
+create procedure p()
+begin
+declare x float;
+declare x int;
+end|
+ERROR 42000: Duplicate variable: x
+create procedure p()
+begin
+declare c condition for 1064;
+declare c condition for 1065;
+end|
+ERROR 42000: Duplicate condition: c
+create procedure p()
+begin
+declare c cursor for select * from t1;
+declare c cursor for select field from t1;
+end|
+ERROR 42000: Duplicate cursor: c
+create procedure u()
+use sptmp|
+ERROR 42000: USE is not allowed in a stored procedure
+create procedure p()
+begin
+declare c cursor for select * from t1;
+declare x int;
+end|
+ERROR 42000: Variable or condition declaration after cursor or handler declaration
+create procedure p()
+begin
+declare x int;
+declare continue handler for sqlstate '42S99' set x = 1;
+declare foo condition for sqlstate '42S99';
+end|
+ERROR 42000: Variable or condition declaration after cursor or handler declaration
+create procedure p()
+begin
+declare x int;
+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
+set y = x+y;
+set z = x+y;
+end|
+set @tmp_x = 42|
+set @tmp_y = 3|
+set @tmp_z = 0|
+call p(@tmp_x, @tmp_y, @tmp_z)|
+select @tmp_x, @tmp_y, @tmp_z|
+@tmp_x @tmp_y @tmp_z
+42 45 87
+call p(42, 43, @tmp_z)|
+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 bug1965()
+begin
+declare c cursor for select val from t1 order by valname;
+open c;
+close c;
+end|
+call bug1965()|
+ERROR 42S22: Unknown column 'valname' in 'order clause'
+drop procedure bug1965|
+select 1 into a|
+ERROR 42000: Undeclared variable: a
+drop table if exists t3|
+create table t3 (column_1_0 int)|
+create procedure bug1653()
+update t3 set column_1 = 0|
+call bug1653()|
+ERROR 42S22: Unknown column 'column_1' in 'field list'
+drop table t3|
+create table t3 (column_1 int)|
+call bug1653()|
+drop procedure bug1653|
+drop table t3|
+create procedure bug2259()
+begin
+declare v1 int;
+declare c1 cursor for select s1 from t1;
+fetch c1 into v1;
+end|
+call bug2259()|
+ERROR 24000: Cursor is not open
+drop procedure bug2259|
+create procedure bug2272()
+begin
+declare v int;
+update t1 set v = 42;
+end|
+insert into t1 values (666, 51.3)|
+call bug2272()|
+ERROR 42S22: Unknown column 'v' in 'field list'
+delete from t1|
+drop procedure bug2272|
+create procedure bug2329_1()
+begin
+declare v int;
+insert into t1 (v) values (5);
+end|
+create procedure bug2329_2()
+begin
+declare v int;
+replace t1 set v = 5;
+end|
+call bug2329_1()|
+ERROR 42S22: Unknown column 'v' in 'field list'
+call bug2329_2()|
+ERROR 42S22: Unknown column 'v' in 'field list'
+drop procedure bug2329_1|
+drop procedure bug2329_2|
+create function bug3287() returns int
+begin
+declare v int default null;
+case
+when v is not null then return 1;
+end case;
+return 2;
+end|
+select bug3287()|
+ERROR 20000: Case not found for CASE statement
+drop function bug3287|
+create procedure bug3287(x int)
+case x
+when 0 then
+insert into test.t1 values (x, 0.1);
+when 1 then
+insert into test.t1 values (x, 1.1);
+end case|
+call bug3287(2)|
+ERROR 20000: Case not found for CASE statement
+drop procedure bug3287|
+drop table if exists t3|
+create table t3 (s1 int, primary key (s1))|
+insert into t3 values (5),(6)|
+create procedure bug3279(out y int)
+begin
+declare x int default 0;
+begin
+declare exit handler for sqlexception set x = x+1;
+insert into t3 values (5);
+end;
+if x < 2 then
+set x = x+1;
+insert into t3 values (6);
+end if;
+set y = x;
+end|
+set @x = 0|
+call bug3279(@x)|
+ERROR 23000: Duplicate entry '6' for key 1
+select @x|
+@x
+0
+drop procedure bug3279|
+drop table t3|
+create procedure nodb.bug3339() begin end|
+ERROR 42000: Unknown database 'nodb'
+create procedure bug2653_1(a int, out b int)
+set b = aa|
+create procedure bug2653_2(a int, out b int)
+begin
+if aa < 0 then
+set b = - a;
+else
+set b = a;
+end if;
+end|
+call bug2653_1(1, @b)|
+ERROR 42S22: Unknown column 'aa' in 'order clause'
+call bug2653_2(2, @b)|
+ERROR 42S22: Unknown column 'aa' in 'order clause'
+drop procedure bug2653_1|
+drop procedure bug2653_2|
+create procedure bug4344() drop procedure bug4344|
+ERROR HY000: Can't drop or alter a PROCEDURE from within another stored routine
+create procedure bug4344() drop function bug4344|
+ERROR HY000: Can't drop or alter a FUNCTION from within another stored routine
+drop procedure if exists bug3294|
+create procedure bug3294()
+begin
+declare continue handler for sqlexception drop table t5;
+drop table t5;
+drop table t5;
+end|
+create table t5 (x int)|
+call bug3294()|
+ERROR 42S02: Unknown table 't5'
+drop procedure bug3294|
+drop procedure if exists bug6807|
+create procedure bug6807()
+begin
+declare id int;
+set id = connection_id();
+kill query id;
+select 'Not reached';
+end|
+call bug6807()|
+ERROR 70100: Query execution was interrupted
+call bug6807()|
+ERROR 70100: Query execution was interrupted
+drop procedure bug6807|
+drop procedure if exists bug8776_1|
+drop procedure if exists bug8776_2|
+drop procedure if exists bug8776_3|
+drop procedure if exists bug8776_4|
+create procedure bug8776_1()
+begin
+declare continue handler for sqlstate '42S0200test' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '42S0200test'
+create procedure bug8776_2()
+begin
+declare continue handler for sqlstate '4200' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '4200'
+create procedure bug8776_3()
+begin
+declare continue handler for sqlstate '420000' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '420000'
+create procedure bug8776_4()
+begin
+declare continue handler for sqlstate '42x00' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '42x00'
+create procedure bug6600()
+check table t1|
+ERROR 0A000: CHECK is not allowed in stored procedures
+create procedure bug6600()
+lock table t1 read|
+ERROR 0A000: LOCK is not allowed in stored procedures
+create procedure bug6600()
+unlock table t1|
+ERROR 0A000: UNLOCK is not allowed in stored procedures
+drop procedure if exists bug9566|
+create procedure bug9566()
+begin
+select * from t1;
+end|
+lock table t1 read|
+call bug9566()|
+ERROR HY000: Table 'proc' was not locked with LOCK TABLES
+unlock tables|
+drop procedure bug9566|
+drop procedure if exists bug7299|
+create procedure bug7299()
+begin
+declare v int;
+declare c cursor for select val from t1;
+declare exit handler for sqlexception select 'Error!';
+open c;
+fetch c into v;
+end|
+delete from t1|
+call bug7299()|
+ERROR 02000: No data to FETCH
+drop procedure bug7299|
+create procedure bug9073()
+begin
+declare continue handler for sqlexception select 1;
+declare continue handler for sqlexception select 2;
+end|
+ERROR 42000: Duplicate handler declared in the same block
+create procedure bug9073()
+begin
+declare condname1 condition for 1234;
+declare continue handler for condname1 select 1;
+declare exit handler for condname1 select 2;
+end|
+ERROR 42000: Duplicate handler declared in the same block
+create procedure bug9073()
+begin
+declare condname1 condition for sqlstate '42000';
+declare condname2 condition for sqlstate '42000';
+declare exit handler for condname1 select 1;
+declare continue handler for condname2 select 2;
+end|
+ERROR 42000: Duplicate handler declared in the same block
+create procedure bug9073()
+begin
+declare condname1 condition for sqlstate '42000';
+declare exit handler for condname1 select 1;
+declare exit handler for sqlstate '42000' select 2;
+end|
+ERROR 42000: Duplicate handler declared in the same block
+drop procedure if exists bug9073|
+create procedure bug9073()
+begin
+declare condname1 condition for sqlstate '42000';
+declare continue handler for condname1 select 1;
+begin
+declare exit handler for sqlstate '42000' select 2;
+begin
+declare continue handler for sqlstate '42000' select 3;
+end;
+end;
+end|
+drop procedure bug9073|
+create procedure bug7047()
+alter procedure bug7047|
+ERROR HY000: Can't drop or alter a PROCEDURE from within another stored routine
+create function bug7047() returns int
+begin
+alter function bug7047;
+return 0;
+end|
+ERROR HY000: Can't drop or alter a FUNCTION from within another stored routine
+create function bug8408() returns int
+begin
+select * from t1;
+return 0;
+end|
+ERROR 0A000: Not allowed to return a result set from a function
+create function bug8408() returns int
+begin
+show warnings;
+return 0;
+end|
+ERROR 0A000: Not allowed to return a result set from a function
+create function bug8408(a int) returns int
+begin
+declare b int;
+select b;
+return b;
+end|
+ERROR 0A000: Not allowed to return a result set from a function
+drop function if exists bug8408_f|
+drop procedure if exists bug8408_p|
+create function bug8408_f() returns int
+begin
+call bug8408_p();
+return 0;
+end|
+create procedure bug8408_p()
+select * from t1|
+call bug8408_p()|
+val x
+select bug8408_f()|
+ERROR 0A000: PROCEDURE test.bug8408_p can't return a result set in the given context
+drop procedure bug8408_p|
+drop function bug8408_f|
+create function bug8408() returns int
+begin
+declare n int default 0;
+select count(*) into n from t1;
+return n;
+end|
+insert into t1 value (2, 2.7), (3, 3.14), (7, 7.0)|
+select *,bug8408() from t1|
+val x bug8408()
+2 2.7 3
+3 3.14 3
+7 7 3
+drop function bug8408|
+delete from t1|
+drop table t1|
diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result
new file mode 100644
index 00000000000..d7078d5087d
--- /dev/null
+++ b/mysql-test/r/sp-security.result
@@ -0,0 +1,196 @@
+use test;
+grant usage on *.* to user1@localhost;
+flush privileges;
+drop database if exists db1_secret;
+create database db1_secret;
+create procedure db1_secret.dummy() begin end;
+drop procedure db1_secret.dummy;
+use db1_secret;
+create table t1 ( u varchar(64), i int );
+create procedure stamp(i int)
+insert into db1_secret.t1 values (user(), i);
+show procedure status like 'stamp';
+Db Name Type Definer Modified Created Security_type Comment
+db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+create function db() returns varchar(64) return database();
+show function status like 'db';
+Db Name Type Definer Modified Created Security_type Comment
+db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+call stamp(1);
+select * from t1;
+u i
+root@localhost 1
+select db();
+db()
+db1_secret
+grant execute on db1_secret.stamp to user1@'%';
+grant execute on db1_secret.db to user1@'%';
+grant execute on db1_secret.stamp to ''@'%';
+grant execute on db1_secret.db to ''@'%';
+call db1_secret.stamp(2);
+select db1_secret.db();
+db1_secret.db()
+db1_secret
+select * from db1_secret.t1;
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
+create procedure db1_secret.dummy() begin end;
+ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret'
+drop procedure db1_secret.dummy;
+ERROR 42000: PROCEDURE db1_secret.dummy does not exist
+call db1_secret.stamp(3);
+select db1_secret.db();
+db1_secret.db()
+db1_secret
+select * from db1_secret.t1;
+ERROR 42000: SELECT command denied to user ''@'localhost' for table 't1'
+create procedure db1_secret.dummy() begin end;
+ERROR 42000: Access denied for user ''@'localhost' to database 'db1_secret'
+drop procedure db1_secret.dummy;
+ERROR 42000: PROCEDURE db1_secret.dummy does not exist
+select * from t1;
+u i
+root@localhost 1
+user1@localhost 2
+anon@localhost 3
+alter procedure stamp sql security invoker;
+show procedure status like 'stamp';
+Db Name Type Definer Modified Created Security_type Comment
+db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
+alter function db sql security invoker;
+show function status like 'db';
+Db Name Type Definer Modified Created Security_type Comment
+db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
+call stamp(4);
+select * from t1;
+u i
+root@localhost 1
+user1@localhost 2
+anon@localhost 3
+root@localhost 4
+select db();
+db()
+db1_secret
+call db1_secret.stamp(5);
+ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret'
+select db1_secret.db();
+ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret'
+call db1_secret.stamp(6);
+ERROR 42000: Access denied for user ''@'localhost' to database 'db1_secret'
+select db1_secret.db();
+ERROR 42000: Access denied for user ''@'localhost' to database 'db1_secret'
+drop database if exists db2;
+create database db2;
+use db2;
+create table t2 (s1 int);
+insert into t2 values (0);
+grant usage on db2.* to user1@localhost;
+grant select on db2.* to user1@localhost;
+grant usage on db2.* to user2@localhost;
+grant select,insert,update,delete,create routine on db2.* to user2@localhost;
+grant create routine on db2.* to user1@localhost;
+flush privileges;
+use db2;
+create procedure p () insert into t2 values (1);
+call p();
+ERROR 42000: INSERT command denied to user 'user1'@'localhost' for table 't2'
+use db2;
+call p();
+ERROR 42000: execute command denied to user 'user2'@'localhost' for routine 'db2.p'
+select * from t2;
+s1
+0
+create procedure q () insert into t2 values (2);
+call q();
+select * from t2;
+s1
+0
+2
+grant usage on db2.q to user2@localhost with grant option;
+grant execute on db2.q to user1@localhost;
+use db2;
+call q();
+select * from t2;
+s1
+0
+2
+2
+alter procedure p modifies sql data;
+drop procedure p;
+alter procedure q modifies sql data;
+ERROR 42000: alter procedure command denied to user 'user1'@'localhost' for routine 'db2.q'
+drop procedure q;
+ERROR 42000: alter procedure command denied to user 'user1'@'localhost' for routine 'db2.q'
+use db2;
+alter procedure q modifies sql data;
+drop procedure q;
+use test;
+select type,db,name from mysql.proc;
+type db name
+FUNCTION db1_secret db
+PROCEDURE db1_secret stamp
+drop database db1_secret;
+drop database db2;
+select type,db,name from mysql.proc;
+type db name
+delete from mysql.user where user='user1' or user='user2';
+delete from mysql.procs_priv where user='user1' or user='user2';
+grant usage on *.* to usera@localhost;
+grant usage on *.* to userb@localhost;
+grant usage on *.* to userc@localhost;
+create database sptest;
+create table t1 ( u varchar(64), i int );
+create procedure sptest.p1(i int) insert into test.t1 values (user(), i);
+grant insert on t1 to usera@localhost;
+grant execute on sptest.p1 to usera@localhost;
+show grants for usera@localhost;
+Grants for usera@localhost
+GRANT USAGE ON *.* TO 'usera'@'localhost'
+GRANT INSERT ON `test`.`t1` TO 'usera'@'localhost'
+GRANT EXECUTE ON `sptest`.`p1` TO 'usera'@'localhost'
+grant execute on sptest.p1 to userc@localhost with grant option;
+show grants for userc@localhost;
+Grants for userc@localhost
+GRANT USAGE ON *.* TO 'userc'@'localhost'
+GRANT EXECUTE ON `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION
+call sptest.p1(1);
+grant execute on sptest.p1 to userb@localhost;
+ERROR 42000: grant command denied to user 'usera'@'localhost' for routine 'sptest.p1'
+drop procedure sptest.p1;
+ERROR 42000: alter procedure command denied to user 'usera'@'localhost' for routine 'sptest.p1'
+call sptest.p1(2);
+ERROR 42000: execute command denied to user 'userb'@'localhost' for routine 'sptest.p1'
+grant execute on sptest.p1 to userb@localhost;
+ERROR 42000: execute command denied to user 'userb'@'localhost' for routine 'sptest.p1'
+drop procedure sptest.p1;
+ERROR 42000: alter procedure command denied to user 'userb'@'localhost' for routine 'sptest.p1'
+call sptest.p1(3);
+grant execute on sptest.p1 to userb@localhost;
+drop procedure sptest.p1;
+ERROR 42000: alter procedure command denied to user 'userc'@'localhost' for routine 'sptest.p1'
+call sptest.p1(4);
+grant execute on sptest.p1 to userb@localhost;
+ERROR 42000: grant command denied to user 'userb'@'localhost' for routine 'sptest.p1'
+drop procedure sptest.p1;
+ERROR 42000: alter procedure command denied to user 'userb'@'localhost' for routine 'sptest.p1'
+select * from t1;
+u i
+usera@localhost 1
+userc@localhost 3
+userb@localhost 4
+grant all privileges on sptest.p1 to userc@localhost;
+show grants for userc@localhost;
+Grants for userc@localhost
+GRANT USAGE ON *.* TO 'userc'@'localhost'
+GRANT EXECUTE, ALTER ROUTINE ON `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION
+show grants for userb@localhost;
+Grants for userb@localhost
+GRANT USAGE ON *.* TO 'userb'@'localhost'
+GRANT EXECUTE ON `sptest`.`p1` TO 'userb'@'localhost'
+revoke all privileges on sptest.p1 from userb@localhost;
+show grants for userb@localhost;
+Grants for userb@localhost
+GRANT USAGE ON *.* TO 'userb'@'localhost'
+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';
diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result
new file mode 100644
index 00000000000..a081e520496
--- /dev/null
+++ b/mysql-test/r/sp-threads.result
@@ -0,0 +1,42 @@
+use test;
+drop table if exists t1;
+create table t1 (s1 int, s2 int, s3 int);
+create procedure bug4934()
+begin
+insert into t1 values (1,0,1);
+end//
+use test;
+call bug4934();
+select * from t1;
+s1 s2 s3
+1 0 1
+drop table t1;
+create table t1 (s1 int, s2 int, s3 int);
+drop procedure bug4934;
+create procedure bug4934()
+begin
+end//
+select * from t1;
+s1 s2 s3
+call bug4934();
+select * from t1;
+s1 s2 s3
+drop table t1;
+drop procedure bug4934;
+drop procedure if exists bug9486;
+drop table if exists t1, t2;
+create table t1 (id1 int, val int);
+create table t2 (id2 int);
+create procedure bug9486()
+update t1, t2 set val= 1 where id1=id2;
+call bug9486();
+lock tables t2 write;
+ call bug9486();
+show processlist;
+Id User Host db Command Time State Info
+# root localhost test Sleep # NULL
+# root localhost test Query # Locked call bug9486()
+# root localhost test Query # NULL show processlist
+unlock tables;
+drop procedure bug9486;
+drop table t1, t2;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
new file mode 100644
index 00000000000..9f28acbcb7d
--- /dev/null
+++ b/mysql-test/r/sp.result
@@ -0,0 +1,3044 @@
+use test;
+drop table if exists t1;
+create table t1 (
+id char(16) not null default '',
+data int not null
+);
+drop table if exists t2;
+create table t2 (
+s char(16),
+i int,
+d double
+);
+drop procedure if exists foo42;
+create procedure foo42()
+insert into test.t1 values ("foo", 42);
+call foo42();
+select * from t1;
+id data
+foo 42
+delete from t1;
+drop procedure foo42;
+drop procedure if exists bar;
+create procedure bar(x char(16), y int)
+insert into test.t1 values (x, y);
+call bar("bar", 666);
+select * from t1;
+id data
+bar 666
+delete from t1;
+drop procedure if exists empty|
+create procedure empty()
+begin
+end|
+call empty()|
+drop procedure empty|
+drop procedure if exists scope|
+create procedure scope(a int, b float)
+begin
+declare b int;
+declare c float;
+begin
+declare c int;
+end;
+end|
+drop procedure scope|
+drop procedure if exists two|
+create procedure two(x1 char(16), x2 char(16), y int)
+begin
+insert into test.t1 values (x1, y);
+insert into test.t1 values (x2, y);
+end|
+call two("one", "two", 3)|
+select * from t1|
+id data
+one 3
+two 3
+delete from t1|
+drop procedure two|
+drop procedure if exists locset|
+create procedure locset(x char(16), y int)
+begin
+declare z1, z2 int;
+set z1 = y;
+set z2 = z1+2;
+insert into test.t1 values (x, z2);
+end|
+call locset("locset", 19)|
+select * from t1|
+id data
+locset 21
+delete from t1|
+drop procedure locset|
+drop procedure if exists setcontext|
+create procedure setcontext()
+begin
+declare data int default 2;
+insert into t1 (id, data) values ("foo", 1);
+replace t1 set data = data, id = "bar";
+update t1 set id = "kaka", data = 3 where t1.data = data;
+end|
+call setcontext()|
+select * from t1|
+id data
+foo 1
+kaka 3
+delete from t1|
+drop procedure setcontext|
+drop table if exists t3|
+create table t3 ( d date, i int, f double, s varchar(32) )|
+drop procedure if exists nullset|
+create procedure nullset()
+begin
+declare ld date;
+declare li int;
+declare lf double;
+declare ls varchar(32);
+set ld = null, li = null, lf = null, ls = null;
+insert into t3 values (ld, li, lf, ls);
+insert into t3 (i, f, s) values ((ld is null), 1, "ld is null"),
+((li is null), 1, "li is null"),
+((li = 0), null, "li = 0"),
+((lf is null), 1, "lf is null"),
+((lf = 0), null, "lf = 0"),
+((ls is null), 1, "ls is null");
+end|
+call nullset()|
+select * from t3|
+d i f s
+NULL NULL NULL NULL
+NULL 1 1 ld is null
+NULL 1 1 li is null
+NULL NULL NULL li = 0
+NULL 1 1 lf is null
+NULL NULL NULL lf = 0
+NULL 1 1 ls is null
+drop table t3|
+drop procedure nullset|
+drop procedure if exists mixset|
+create procedure mixset(x char(16), y int)
+begin
+declare z int;
+set @z = y, z = 666, max_join_size = 100;
+insert into test.t1 values (x, z);
+end|
+call mixset("mixset", 19)|
+show variables like 'max_join_size'|
+Variable_name Value
+max_join_size 100
+select id,data,@z from t1|
+id data @z
+mixset 666 19
+delete from t1|
+drop procedure mixset|
+drop procedure if exists zip|
+create procedure zip(x char(16), y int)
+begin
+declare z int;
+call zap(y, z);
+call bar(x, z);
+end|
+drop procedure if exists zap|
+create procedure zap(x int, out y int)
+begin
+declare z int;
+set z = x+1, y = z;
+end|
+call zip("zip", 99)|
+select * from t1|
+id data
+zip 100
+delete from t1|
+drop procedure zip|
+drop procedure bar|
+call zap(7, @zap)|
+select @zap|
+@zap
+8
+drop procedure zap|
+drop procedure if exists c1|
+create procedure c1(x int)
+call c2("c", x)|
+drop procedure if exists c2|
+create procedure c2(s char(16), x int)
+call c3(x, s)|
+drop procedure if exists c3|
+create procedure c3(x int, s char(16))
+call c4("level", x, s)|
+drop procedure if exists c4|
+create procedure c4(l char(8), x int, s char(16))
+insert into t1 values (concat(l,s), x)|
+call c1(42)|
+select * from t1|
+id data
+levelc 42
+delete from t1|
+drop procedure c1|
+drop procedure c2|
+drop procedure c3|
+drop procedure c4|
+drop procedure if exists iotest|
+create procedure iotest(x1 char(16), x2 char(16), y int)
+begin
+call inc2(x2, y);
+insert into test.t1 values (x1, y);
+end|
+drop procedure if exists inc2|
+create procedure inc2(x char(16), y int)
+begin
+call inc(y);
+insert into test.t1 values (x, y);
+end|
+drop procedure if exists inc|
+create procedure inc(inout io int)
+set io = io + 1|
+call iotest("io1", "io2", 1)|
+select * from t1|
+id data
+io2 2
+io1 1
+delete from t1|
+drop procedure iotest|
+drop procedure inc2|
+drop procedure if exists incr|
+create procedure incr(inout x int)
+call inc(x)|
+select @zap|
+@zap
+8
+call incr(@zap)|
+select @zap|
+@zap
+9
+drop procedure inc|
+drop procedure incr|
+drop procedure if exists cbv1|
+create procedure cbv1()
+begin
+declare y int default 3;
+call cbv2(y+1, y);
+insert into test.t1 values ("cbv1", y);
+end|
+drop procedure if exists cbv2|
+create procedure cbv2(y1 int, inout y2 int)
+begin
+set y2 = 4711;
+insert into test.t1 values ("cbv2", y1);
+end|
+call cbv1()|
+select * from t1|
+id data
+cbv2 4
+cbv1 4711
+delete from t1|
+drop procedure cbv1|
+drop procedure cbv2|
+insert into t2 values ("a", 1, 1.1), ("b", 2, 1.2), ("c", 3, 1.3)|
+drop procedure if exists sub1|
+create procedure sub1(id char(16), x int)
+insert into test.t1 values (id, x)|
+drop procedure if exists sub2|
+create procedure sub2(id char(16))
+begin
+declare x int;
+set x = (select sum(t.i) from test.t2 t);
+insert into test.t1 values (id, x);
+end|
+drop procedure if exists sub3|
+create function sub3(i int) returns int
+return i+1|
+call sub1("sub1a", (select 7))|
+call sub1("sub1b", (select max(i) from t2))|
+call sub1("sub1c", (select i,d from t2 limit 1))|
+call sub1("sub1d", (select 1 from (select 1) a))|
+call sub2("sub2");
+select * from t1|
+id data
+sub1a 7
+sub1b 3
+sub1c 1
+sub1d 1
+sub2 6
+select sub3((select max(i) from t2))|
+sub3((select max(i) from t2))
+4
+drop procedure sub1|
+drop procedure sub2|
+drop function sub3|
+delete from t2|
+drop procedure if exists a0|
+create procedure a0(x int)
+while x do
+set x = x-1;
+insert into test.t1 values ("a0", x);
+end while|
+call a0(3)|
+select * from t1|
+id data
+sub1a 7
+sub1b 3
+sub1c 1
+sub1d 1
+sub2 6
+a0 2
+a0 1
+a0 0
+delete from t1|
+drop procedure a0|
+drop procedure if exists a|
+create procedure a(x int)
+while x > 0 do
+set x = x-1;
+insert into test.t1 values ("a", x);
+end while|
+call a(3)|
+select * from t1|
+id data
+a 2
+a 1
+a 0
+delete from t1|
+drop procedure a|
+drop procedure if exists b|
+create procedure b(x int)
+repeat
+insert into test.t1 values (repeat("b",3), x);
+set x = x-1;
+until x = 0 end repeat|
+call b(3)|
+select * from t1|
+id data
+bbb 3
+bbb 2
+bbb 1
+delete from t1|
+drop procedure b|
+drop procedure if exists b2|
+create procedure b2(x int)
+repeat(select 1 into outfile 'b2');
+insert into test.t1 values (repeat("b2",3), x);
+set x = x-1;
+until x = 0 end repeat|
+drop procedure b2|
+drop procedure if exists c|
+create procedure c(x int)
+hmm: while x > 0 do
+insert into test.t1 values ("c", x);
+set x = x-1;
+iterate hmm;
+insert into test.t1 values ("x", x);
+end while hmm|
+call c(3)|
+select * from t1|
+id data
+c 3
+c 2
+c 1
+delete from t1|
+drop procedure c|
+drop procedure if exists d|
+create procedure d(x int)
+hmm: while x > 0 do
+insert into test.t1 values ("d", x);
+set x = x-1;
+leave hmm;
+insert into test.t1 values ("x", x);
+end while|
+call d(3)|
+select * from t1|
+id data
+d 3
+delete from t1|
+drop procedure d|
+drop procedure if exists e|
+create procedure e(x int)
+foo: loop
+if x = 0 then
+leave foo;
+end if;
+insert into test.t1 values ("e", x);
+set x = x-1;
+end loop foo|
+call e(3)|
+select * from t1|
+id data
+e 3
+e 2
+e 1
+delete from t1|
+drop procedure e|
+drop procedure if exists f|
+create procedure f(x int)
+if x < 0 then
+insert into test.t1 values ("f", 0);
+elseif x = 0 then
+insert into test.t1 values ("f", 1);
+else
+insert into test.t1 values ("f", 2);
+end if|
+call f(-2)|
+call f(0)|
+call f(4)|
+select * from t1|
+id data
+f 0
+f 1
+f 2
+delete from t1|
+drop procedure f|
+drop procedure if exists g|
+create procedure g(x int)
+case
+when x < 0 then
+insert into test.t1 values ("g", 0);
+when x = 0 then
+insert into test.t1 values ("g", 1);
+else
+insert into test.t1 values ("g", 2);
+end case|
+call g(-42)|
+call g(0)|
+call g(1)|
+select * from t1|
+id data
+g 0
+g 1
+g 2
+delete from t1|
+drop procedure g|
+drop procedure if exists h|
+create procedure h(x int)
+case x
+when 0 then
+insert into test.t1 values ("h0", x);
+when 1 then
+insert into test.t1 values ("h1", x);
+else
+insert into test.t1 values ("h?", x);
+end case|
+call h(0)|
+call h(1)|
+call h(17)|
+select * from t1|
+id data
+h0 0
+h1 1
+h? 17
+delete from t1|
+drop procedure h|
+drop procedure if exists i|
+create procedure i(x int)
+foo:
+begin
+if x = 0 then
+leave foo;
+end if;
+insert into test.t1 values ("i", x);
+end foo|
+call i(0)|
+call i(3)|
+select * from t1|
+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|
+create procedure sel1()
+begin
+select * from t1;
+end|
+call sel1()|
+id data
+foo 3
+bar 19
+drop procedure sel1|
+drop procedure if exists sel2|
+create procedure sel2()
+begin
+select * from t1;
+select * from t2;
+end|
+call sel2()|
+id data
+foo 3
+bar 19
+s i d
+x 9 4.1
+y -1 19.2
+z 3 2.2
+drop procedure sel2|
+delete from t1|
+delete from t2|
+drop procedure if exists into_test|
+create procedure into_test(x char(16), y int)
+begin
+insert into test.t1 values (x, y);
+select id,data into x,y from test.t1 limit 1;
+insert into test.t1 values (concat(x, "2"), y+2);
+end|
+call into_test("into", 100)|
+select * from t1|
+id data
+into 100
+into2 102
+delete from t1|
+drop procedure into_test|
+drop procedure if exists into_tes2|
+create procedure into_test2(x char(16), y int)
+begin
+insert into test.t1 values (x, y);
+select id,data into x,@z from test.t1 limit 1;
+insert into test.t1 values (concat(x, "2"), y+2);
+end|
+call into_test2("into", 100)|
+select id,data,@z from t1|
+id data @z
+into 100 100
+into2 102 100
+delete from t1|
+drop procedure into_test2|
+drop procedure if exists into_test3|
+create procedure into_test3()
+begin
+declare x char(16);
+declare y int;
+select * into x,y from test.t1 limit 1;
+insert into test.t2 values (x, y, 0.0);
+end|
+insert into t1 values ("into3", 19)|
+call into_test3()|
+call into_test3()|
+select * from t2|
+s i d
+into3 19 0
+into3 19 0
+delete from t1|
+delete from t2|
+drop procedure into_test3|
+drop procedure if exists into_test4|
+create procedure into_test4()
+begin
+declare x int;
+select data into x from test.t1 limit 1;
+insert into test.t3 values ("into4", x);
+end|
+delete from t1|
+drop table if exists t3|
+create table t3 ( s char(16), d int)|
+call into_test4()|
+Warnings:
+Warning 1329 No data to FETCH
+select * from t3|
+s d
+into4 NULL
+insert into t1 values ("i4", 77)|
+call into_test4()|
+select * from t3|
+s d
+into4 NULL
+into4 77
+delete from t1|
+drop table t3|
+drop procedure into_test4|
+drop procedure if exists into_outfile|
+create procedure into_outfile(x char(16), y int)
+begin
+insert into test.t1 values (x, y);
+select * into outfile "/tmp/spout" from test.t1;
+insert into test.t1 values (concat(x, "2"), y+2);
+end|
+call into_outfile("ofile", 1)|
+delete from t1|
+drop procedure into_outfile|
+drop procedure if exists into_dumpfile|
+create procedure into_dumpfile(x char(16), y int)
+begin
+insert into test.t1 values (x, y);
+select * into dumpfile "/tmp/spdump" from test.t1 limit 1;
+insert into test.t1 values (concat(x, "2"), y+2);
+end|
+call into_dumpfile("dfile", 1)|
+delete from t1|
+drop procedure into_dumpfile|
+drop procedure if exists create_select|
+create procedure create_select(x char(16), y int)
+begin
+insert into test.t1 values (x, y);
+create temporary table test.t3 select * from test.t1;
+insert into test.t3 values (concat(x, "2"), y+2);
+end|
+drop table if exists t3|
+call create_select("cs", 90)|
+select * from t1, t3|
+id data id data
+cs 90 cs 90
+cs 90 cs2 92
+drop table if exists t3|
+delete from t1|
+drop procedure create_select|
+drop function if exists e|
+create function e() returns double
+return 2.7182818284590452354|
+set @e = e()|
+select e(), @e|
+e() @e
+2.718281828459 2.718281828459
+drop function if exists inc|
+create function inc(i int) returns int
+return i+1|
+select inc(1), inc(99), inc(-71)|
+inc(1) inc(99) inc(-71)
+2 100 -70
+drop function if exists mul|
+create function mul(x int, y int) returns int
+return x*y|
+select mul(1,1), mul(3,5), mul(4711, 666)|
+mul(1,1) mul(3,5) mul(4711, 666)
+1 15 3137526
+drop function if exists append|
+create function append(s1 char(8), s2 char(8)) returns char(16)
+return concat(s1, s2)|
+select append("foo", "bar")|
+append("foo", "bar")
+foobar
+drop function if exists fac|
+create function fac(n int unsigned) returns bigint unsigned
+begin
+declare f bigint unsigned default 1;
+while n > 1 do
+set f = f * n;
+set n = n - 1;
+end while;
+return f;
+end|
+select fac(1), fac(2), fac(5), fac(10)|
+fac(1) fac(2) fac(5) fac(10)
+1 2 120 3628800
+drop function if exists fun|
+create function fun(d double, i int, u int unsigned) returns double
+return mul(inc(i), fac(u)) / e()|
+select fun(2.3, 3, 5)|
+fun(2.3, 3, 5)
+176.58213176229
+insert into t2 values (append("xxx", "yyy"), mul(4,3), e())|
+insert into t2 values (append("a", "b"), mul(2,mul(3,4)), fun(1.7, 4, 6))|
+select * from t2 where s = append("a", "b")|
+s i d
+ab 24 1324.36598821719
+select * from t2 where i = mul(4,3) or i = mul(mul(3,4),2)|
+s i d
+xxxyyy 12 2.71828182845905
+ab 24 1324.36598821719
+select * from t2 where d = e()|
+s i d
+xxxyyy 12 2.71828182845905
+select * from t2|
+s i d
+xxxyyy 12 2.71828182845905
+ab 24 1324.36598821719
+delete from t2|
+drop function e|
+drop function inc|
+drop function mul|
+drop function append|
+drop function fun|
+drop procedure if exists hndlr1|
+create procedure hndlr1(val int)
+begin
+declare x int default 0;
+declare foo condition for 1136;
+declare bar condition for sqlstate '42S98'; # Just for testing syntax
+declare zip condition for sqlstate value '42S99'; # Just for testing syntax
+declare continue handler for foo set x = 1;
+insert into test.t1 values ("hndlr1", val, 2); # Too many values
+if (x) then
+insert into test.t1 values ("hndlr1", val); # This instead then
+end if;
+end|
+call hndlr1(42)|
+select * from t1|
+id data
+hndlr1 42
+delete from t1|
+drop procedure hndlr1|
+drop procedure if exists hndlr2|
+create procedure hndlr2(val int)
+begin
+declare x int default 0;
+begin
+declare exit handler for sqlstate '21S01' set x = 1;
+insert into test.t1 values ("hndlr2", val, 2); # Too many values
+end;
+insert into test.t1 values ("hndlr2", x);
+end|
+call hndlr2(42)|
+select * from t1|
+id data
+hndlr2 1
+delete from t1|
+drop procedure hndlr2|
+drop procedure if exists hndlr3|
+create procedure hndlr3(val int)
+begin
+declare x int default 0;
+declare continue handler for sqlexception # Any error
+begin
+declare z int;
+set z = 2 * val;
+set x = 1;
+end;
+if val < 10 then
+begin
+declare y int;
+set y = val + 10;
+insert into test.t1 values ("hndlr3", y, 2); # Too many values
+if x then
+insert into test.t1 values ("hndlr3", y);
+end if;
+end;
+end if;
+end|
+call hndlr3(3)|
+select * from t1|
+id data
+hndlr3 13
+delete from t1|
+drop procedure hndlr3|
+drop table if exists t3|
+create table t3 ( id char(16), data int )|
+drop procedure if exists hndlr4|
+create procedure hndlr4()
+begin
+declare x int default 0;
+declare val int; # No default
+declare continue handler for sqlstate '02000' set x=1;
+select data into val from test.t3 where id='z' limit 1; # No hits
+insert into test.t3 values ('z', val);
+end|
+call hndlr4()|
+select * from t3|
+id data
+z NULL
+drop table t3|
+drop procedure hndlr4|
+drop procedure if exists cur1|
+create procedure cur1()
+begin
+declare a char(16);
+declare b int;
+declare c double;
+declare done int default 0;
+declare c cursor for select * from test.t2;
+declare continue handler for sqlstate '02000' set done = 1;
+open c;
+repeat
+fetch c into a, b, c;
+if not done then
+insert into test.t1 values (a, b+c);
+end if;
+until done end repeat;
+close c;
+end|
+insert into t2 values ("foo", 42, -1.9), ("bar", 3, 12.1), ("zap", 666, -3.14)|
+call cur1()|
+select * from t1|
+id data
+foo 40
+bar 15
+zap 663
+drop procedure cur1|
+drop table if exists t3|
+create table t3 ( s char(16), i int )|
+drop procedure if exists cur2|
+create procedure cur2()
+begin
+declare done int default 0;
+declare c1 cursor for select id,data from test.t1;
+declare c2 cursor for select i from test.t2;
+declare continue handler for sqlstate '02000' set done = 1;
+open c1;
+open c2;
+repeat
+begin
+declare a char(16);
+declare b,c int;
+fetch from c1 into a, b;
+fetch next from c2 into c;
+if not done then
+if b < c then
+insert into test.t3 values (a, b);
+else
+insert into test.t3 values (a, c);
+end if;
+end if;
+end;
+until done end repeat;
+close c1;
+close c2;
+end|
+call cur2()|
+select * from t3|
+s i
+foo 40
+bar 3
+zap 663
+delete from t1|
+delete from t2|
+drop table t3|
+drop procedure cur2|
+drop procedure if exists chistics|
+create procedure chistics()
+language sql
+modifies sql data
+not deterministic
+sql security definer
+comment 'Characteristics procedure test'
+ insert into t1 values ("chistics", 1)|
+show create procedure chistics|
+Procedure sql_mode Create Procedure
+chistics CREATE PROCEDURE `test`.`chistics`()
+ MODIFIES SQL DATA
+ COMMENT 'Characteristics procedure test'
+insert into t1 values ("chistics", 1)
+call chistics()|
+select * from t1|
+id data
+chistics 1
+delete from t1|
+alter procedure chistics sql security invoker|
+show create procedure chistics|
+Procedure sql_mode Create Procedure
+chistics CREATE PROCEDURE `test`.`chistics`()
+ MODIFIES SQL DATA
+ SQL SECURITY INVOKER
+ COMMENT 'Characteristics procedure test'
+insert into t1 values ("chistics", 1)
+drop procedure chistics|
+drop function if exists chistics|
+create function chistics() returns int
+language sql
+deterministic
+sql security invoker
+comment 'Characteristics procedure test'
+ return 42|
+show create function chistics|
+Function sql_mode Create Function
+chistics CREATE FUNCTION `test`.`chistics`() RETURNS int(11)
+ DETERMINISTIC
+ SQL SECURITY INVOKER
+ COMMENT 'Characteristics procedure test'
+return 42
+select chistics()|
+chistics()
+42
+alter function chistics
+no sql
+comment 'Characteristics function test'|
+show create function chistics|
+Function sql_mode Create Function
+chistics CREATE FUNCTION `test`.`chistics`() RETURNS int(11)
+ NO SQL
+ DETERMINISTIC
+ SQL SECURITY INVOKER
+ COMMENT 'Characteristics function test'
+return 42
+drop function chistics|
+insert into t1 values ("foo", 1), ("bar", 2), ("zip", 3)|
+set @@sql_mode = 'ANSI'|
+drop procedure if exists modes$
+create procedure modes(out c1 int, out c2 int)
+begin
+declare done int default 0;
+declare x int;
+declare c cursor for select data from t1;
+declare continue handler for sqlstate '02000' set done = 1;
+select 1 || 2 into c1;
+set c2 = 0;
+open c;
+repeat
+fetch c into x;
+if not done then
+set c2 = c2 + 1;
+end if;
+until done end repeat;
+close c;
+end$
+set @@sql_mode = ''|
+set sql_select_limit = 1|
+call modes(@c1, @c2)|
+set sql_select_limit = default|
+select @c1, @c2|
+@c1 @c2
+12 3
+delete from t1|
+drop procedure modes|
+create database sp_db1|
+drop database sp_db1|
+create database sp_db2|
+use sp_db2|
+create table t3 ( s char(4), t int )|
+insert into t3 values ("abcd", 42), ("dcba", 666)|
+use test|
+drop database sp_db2|
+create database sp_db3|
+use sp_db3|
+drop procedure if exists dummy|
+create procedure dummy(out x int)
+set x = 42|
+use test|
+drop database sp_db3|
+select type,db,name from mysql.proc where db = 'sp_db3'|
+type db name
+drop procedure if exists rc|
+create procedure rc()
+begin
+delete from t1;
+insert into t1 values ("a", 1), ("b", 2), ("c", 3);
+end|
+call rc()|
+select row_count()|
+row_count()
+3
+update t1 set data=42 where id = "b";
+select row_count()|
+row_count()
+1
+delete from t1|
+select row_count()|
+row_count()
+3
+delete from t1|
+select row_count()|
+row_count()
+0
+select * from t1|
+id data
+select row_count()|
+row_count()
+-1
+drop procedure rc|
+drop function if exists f0|
+drop function if exists f1|
+drop function if exists f2|
+drop function if exists f3|
+drop function if exists f4|
+drop function if exists f5|
+drop function if exists f6|
+drop function if exists f7|
+drop function if exists f8|
+drop view if exists v0|
+drop view if exists v1|
+drop view if exists v2|
+delete from t1|
+delete from t2|
+insert into t1 values ("a", 1), ("b", 2) |
+insert into t2 values ("a", 1, 1.0), ("b", 2, 2.0), ("c", 3, 3.0) |
+create function f1() returns int
+return (select sum(data) from t1)|
+select f1()|
+f1()
+3
+select id, f1() from t1|
+id f1()
+a 3
+b 3
+create function f2() returns int
+return (select data from t1 where data <= (select sum(data) from t1) limit 1)|
+select f2()|
+f2()
+1
+select id, f2() from t1|
+id f2()
+a 1
+b 1
+create function f3() returns int
+begin
+declare n int;
+declare m int;
+set n:= (select min(data) from t1);
+set m:= (select max(data) from t1);
+return n < m;
+end|
+select f3()|
+f3()
+1
+select id, f3() from t1|
+id f3()
+a 1
+b 1
+select f1(), f3()|
+f1() f3()
+3 1
+select id, f1(), f3() from t1|
+id f1() f3()
+a 3 1
+b 3 1
+create function f4() returns double
+return (select d from t1, t2 where t1.data = t2.i and t1.id= "b")|
+select f4()|
+f4()
+2
+select s, f4() from t2|
+s f4()
+a 2
+b 2
+c 2
+create function f5(i int) returns int
+begin
+if i <= 0 then
+return 0;
+elseif i = 1 then
+return (select count(*) from t1 where data = i);
+else
+return (select count(*) + f5( i - 1) from t1 where data = i);
+end if;
+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;
+set n:= f1();
+return (select count(*) from t1 where data <= f7() and data <= n);
+end|
+create function f7() returns int
+return (select sum(data) from t1 where data <= f1())|
+select f6()|
+f6()
+2
+select id, f6() from t1|
+id f6()
+a 2
+b 2
+create view v1 (a) as select f1()|
+select * from v1|
+a
+3
+select id, a from t1, v1|
+id a
+a 3
+b 3
+select * from v1, v1 as v|
+a a
+3 3
+create view v2 (a) as select a*10 from v1|
+select * from v2|
+a
+30
+select id, a from t1, v2|
+id a
+a 30
+b 30
+select * from v1, v2|
+a a
+3 30
+create function f8 () returns int
+return (select count(*) from v2)|
+select *, f8() from v1|
+a f8()
+3 1
+drop function f1|
+select * from v1|
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
+create function f1() returns int
+return (select sum(data) from t1) + (select sum(data) from v1)|
+drop function f1|
+create function f1() returns int
+return (select sum(data) from t1)|
+create function f0() returns int
+return (select * from (select 100) as r)|
+select f0()|
+f0()
+100
+select *, f0() from (select 1) as t|
+1 f0()
+1 100
+create view v0 as select f0()|
+select * from v0|
+f0()
+100
+select *, f0() from v0|
+f0() f0()
+100 100
+lock tables t1 read, t1 as t11 read, mysql.proc read|
+select f3()|
+f3()
+1
+select id, f3() from t1 as t11|
+id f3()
+a 1
+b 1
+select f0()|
+f0()
+100
+select * from v0|
+f0()
+100
+select *, f0() from v0, (select 123) as d1|
+f0() 123 f0()
+100 123 100
+select id, f3() from t1|
+ERROR HY000: Table 't1' was not locked with LOCK TABLES
+select f4()|
+ERROR HY000: Table 't2' was not locked with LOCK TABLES
+unlock tables|
+lock tables v2 read, mysql.proc read|
+select * from v2|
+a
+30
+select * from v1|
+a
+3
+select * from v1, v2|
+ERROR HY000: Table 't1' was not locked with LOCK TABLES
+select f4()|
+ERROR HY000: Table 't2' was not locked with LOCK TABLES
+unlock tables|
+drop function f0|
+drop function f1|
+drop function f2|
+drop function f3|
+drop function f4|
+drop function f5|
+drop function f6|
+drop function f7|
+drop function f8|
+drop view v0|
+drop view v1|
+drop view v2|
+delete from t1 |
+delete from t2 |
+drop table if exists fac|
+create table fac (n int unsigned not null primary key, f bigint unsigned)|
+drop procedure if exists ifac|
+create procedure ifac(n int unsigned)
+begin
+declare i int unsigned default 1;
+if n > 20 then
+set n = 20; # bigint overflow otherwise
+end if;
+while i <= n do
+begin
+insert into test.fac values (i, fac(i));
+set i = i + 1;
+end;
+end while;
+end|
+call ifac(20)|
+select * from fac|
+n f
+1 1
+2 2
+3 6
+4 24
+5 120
+6 720
+7 5040
+8 40320
+9 362880
+10 3628800
+11 39916800
+12 479001600
+13 6227020800
+14 87178291200
+15 1307674368000
+16 20922789888000
+17 355687428096000
+18 6402373705728000
+19 121645100408832000
+20 2432902008176640000
+drop table fac|
+show function status like '%f%'|
+Db Name Type Definer Modified Created Security_type Comment
+test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+drop procedure ifac|
+drop function fac|
+show function status like '%f%'|
+Db Name Type Definer Modified Created Security_type Comment
+drop table if exists primes|
+create table primes (
+i int unsigned not null primary key,
+p bigint unsigned not null
+)|
+insert into primes values
+( 0, 3), ( 1, 5), ( 2, 7), ( 3, 11), ( 4, 13),
+( 5, 17), ( 6, 19), ( 7, 23), ( 8, 29), ( 9, 31),
+(10, 37), (11, 41), (12, 43), (13, 47), (14, 53),
+(15, 59), (16, 61), (17, 67), (18, 71), (19, 73),
+(20, 79), (21, 83), (22, 89), (23, 97), (24, 101),
+(25, 103), (26, 107), (27, 109), (28, 113), (29, 127),
+(30, 131), (31, 137), (32, 139), (33, 149), (34, 151),
+(35, 157), (36, 163), (37, 167), (38, 173), (39, 179),
+(40, 181), (41, 191), (42, 193), (43, 197), (44, 199)|
+drop procedure if exists opp|
+create procedure opp(n bigint unsigned, out pp bool)
+begin
+declare r double;
+declare b, s bigint unsigned default 0;
+set r = sqrt(n);
+again:
+loop
+if s = 45 then
+set b = b+200, s = 0;
+else
+begin
+declare p bigint unsigned;
+select t.p into p from test.primes t where t.i = s;
+if b+p > r then
+set pp = 1;
+leave again;
+end if;
+if mod(n, b+p) = 0 then
+set pp = 0;
+leave again;
+end if;
+set s = s+1;
+end;
+end if;
+end loop;
+end|
+drop procedure if exists ip|
+create procedure ip(m int unsigned)
+begin
+declare p bigint unsigned;
+declare i int unsigned;
+set i=45, p=201;
+while i < m do
+begin
+declare pp bool default 0;
+call opp(p, pp);
+if pp then
+insert into test.primes values (i, p);
+set i = i+1;
+end if;
+set p = p+2;
+end;
+end while;
+end|
+show create procedure opp|
+Procedure sql_mode Create Procedure
+opp CREATE PROCEDURE `test`.`opp`(n bigint unsigned, out pp bool)
+begin
+declare r double;
+declare b, s bigint unsigned default 0;
+set r = sqrt(n);
+again:
+loop
+if s = 45 then
+set b = b+200, s = 0;
+else
+begin
+declare p bigint unsigned;
+select t.p into p from test.primes t where t.i = s;
+if b+p > r then
+set pp = 1;
+leave again;
+end if;
+if mod(n, b+p) = 0 then
+set pp = 0;
+leave again;
+end if;
+set s = s+1;
+end;
+end if;
+end loop;
+end
+show procedure status like '%p%'|
+Db Name Type Definer Modified Created Security_type Comment
+test ip PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+test opp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+call ip(200)|
+select * from primes where i=45 or i=100 or i=199|
+i p
+45 211
+100 557
+199 1229
+drop table primes|
+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 )|
+insert into fib values (1), (1)|
+drop procedure if exists fib|
+create procedure fib(n int unsigned)
+begin
+if n > 0 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|
+call fib(20)|
+select * from fib order by f asc|
+f
+1
+1
+2
+3
+5
+8
+13
+21
+34
+55
+89
+144
+233
+377
+610
+987
+1597
+2584
+4181
+6765
+10946
+17711
+drop table fib|
+drop procedure fib|
+drop procedure if exists bar|
+create procedure bar(x char(16), y int)
+comment "111111111111" sql security invoker
+insert into test.t1 values (x, y)|
+show procedure status like 'bar'|
+Db Name Type Definer Modified Created Security_type Comment
+test bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER 111111111111
+alter procedure bar comment "2222222222" sql security definer|
+alter procedure bar comment "3333333333"|
+alter procedure bar|
+show create procedure bar|
+Procedure sql_mode Create Procedure
+bar CREATE PROCEDURE `test`.`bar`(x char(16), y int)
+ COMMENT '3333333333'
+insert into test.t1 values (x, y)
+show procedure status like 'bar'|
+Db Name Type Definer Modified Created Security_type Comment
+test bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER 3333333333
+drop procedure bar|
+drop procedure if exists p1|
+create procedure p1 ()
+select (select s1 from t3) from t3|
+create table t3 (s1 int)|
+call p1()|
+(select s1 from t3)
+insert into t3 values (1)|
+call p1()|
+(select s1 from t3)
+1
+drop procedure p1|
+drop table t3|
+drop function if exists foo|
+create function `foo` () returns int
+return 5|
+select `foo` ()|
+`foo` ()
+5
+drop function `foo`|
+drop function if exists t1max|
+Warnings:
+Note 1305 FUNCTION t1max does not exist
+create function t1max() returns int
+begin
+declare x int;
+select max(data) into x from t1;
+return x;
+end|
+insert into t1 values ("foo", 3), ("bar", 2), ("zip", 5), ("zap", 1)|
+select t1max()|
+t1max()
+5
+drop function t1max|
+drop table if exists t3|
+create table t3 (
+v char(16) not null primary key,
+c int unsigned not null
+)|
+create function getcount(s char(16)) returns int
+begin
+declare x int;
+select count(*) into x from t3 where v = s;
+if x = 0 then
+insert into t3 values (s, 1);
+else
+update t3 set c = c+1 where v = s;
+end if;
+return x;
+end|
+select * from t1 where data = getcount("bar")|
+id data
+zap 1
+select * from t3|
+v c
+bar 4
+select getcount("zip")|
+getcount("zip")
+0
+select getcount("zip")|
+getcount("zip")
+1
+select * from t3|
+v c
+bar 4
+zip 2
+select getcount(id) from t1 where data = 3|
+getcount(id)
+0
+select getcount(id) from t1 where data = 5|
+getcount(id)
+1
+select * from t3|
+v c
+bar 4
+zip 3
+foo 1
+drop table t3|
+drop function getcount|
+drop procedure if exists bug822|
+create procedure bug822(a_id char(16), a_data int)
+begin
+declare n int;
+select count(*) into n from t1 where id = a_id and data = a_data;
+if n = 0 then
+insert into t1 (id, data) values (a_id, a_data);
+end if;
+end|
+delete from t1|
+call bug822('foo', 42)|
+call bug822('foo', 42)|
+call bug822('bar', 666)|
+select * from t1|
+id data
+foo 42
+bar 666
+delete from t1|
+drop procedure bug822|
+drop procedure if exists bug1495|
+create procedure bug1495()
+begin
+declare x int;
+select data into x from t1 order by id limit 1;
+if x > 10 then
+insert into t1 values ("less", x-10);
+else
+insert into t1 values ("more", x+10);
+end if;
+end|
+insert into t1 values ('foo', 12)|
+call bug1495()|
+delete from t1 where id='foo'|
+insert into t1 values ('bar', 7)|
+call bug1495()|
+delete from t1 where id='bar'|
+select * from t1|
+id data
+less 2
+more 17
+delete from t1|
+drop procedure bug1495|
+drop procedure if exists bug1547|
+create procedure bug1547(s char(16))
+begin
+declare x int;
+select data into x from t1 where s = id limit 1;
+if x > 10 then
+insert into t1 values ("less", x-10);
+else
+insert into t1 values ("more", x+10);
+end if;
+end|
+insert into t1 values ("foo", 12), ("bar", 7)|
+call bug1547("foo")|
+call bug1547("bar")|
+select * from t1|
+id data
+foo 12
+bar 7
+less 2
+more 17
+delete from t1|
+drop procedure bug1547|
+drop table if exists t70|
+create table t70 (s1 int,s2 int)|
+insert into t70 values (1,2)|
+drop procedure if exists bug1656|
+create procedure bug1656(out p1 int, out p2 int)
+select * into p1, p1 from t70|
+call bug1656(@1, @2)|
+select @1, @2|
+@1 @2
+2 NULL
+drop table t70|
+drop procedure bug1656|
+drop table if exists t3|
+create table t3(a int)|
+drop procedure if exists bug1862|
+create procedure bug1862()
+begin
+insert into t3 values(2);
+flush tables;
+end|
+call bug1862()|
+call bug1862()|
+select * from t3|
+a
+2
+2
+drop table t3|
+drop procedure bug1862|
+drop procedure if exists bug1874|
+create procedure bug1874()
+begin
+declare x int;
+declare y double;
+select max(data) into x from t1;
+insert into t2 values ("max", x, 0);
+select min(data) into x from t1;
+insert into t2 values ("min", x, 0);
+select sum(data) into x from t1;
+insert into t2 values ("sum", x, 0);
+select avg(data) into y from t1;
+insert into t2 values ("avg", 0, y);
+end|
+insert into t1 (data) values (3), (1), (5), (9), (4)|
+call bug1874()|
+select * from t2|
+s i d
+max 9 0
+min 1 0
+sum 22 0
+avg 0 4.4
+delete from t1|
+delete from t2|
+drop procedure bug1874|
+drop procedure if exists bug2260|
+create procedure bug2260()
+begin
+declare v1 int;
+declare c1 cursor for select data from t1;
+declare continue handler for not found set @x2 = 1;
+open c1;
+fetch c1 into v1;
+set @x2 = 2;
+close c1;
+end|
+call bug2260()|
+select @x2|
+@x2
+2
+drop procedure bug2260|
+drop procedure if exists bug2227|
+create procedure bug2227(x int)
+begin
+declare y float default 2.6;
+declare z char(16) default "zzz";
+select 1.3, x, y, 42, z;
+end|
+call bug2227(9)|
+1.3 x y 42 z
+1.3 9 2.6 42 zzz
+drop procedure bug2227|
+drop function if exists bug2674|
+create function bug2674() returns int
+return @@sort_buffer_size|
+set @osbs = @@sort_buffer_size|
+set @@sort_buffer_size = 262000|
+select bug2674()|
+bug2674()
+262000
+drop function bug2674|
+set @@sort_buffer_size = @osbs|
+drop procedure if exists bug3259_1 |
+create procedure bug3259_1 () begin end|
+drop procedure if exists BUG3259_2 |
+create procedure BUG3259_2 () begin end|
+drop procedure if exists Bug3259_3 |
+create procedure Bug3259_3 () begin end|
+call BUG3259_1()|
+call BUG3259_1()|
+call bug3259_2()|
+call Bug3259_2()|
+call bug3259_3()|
+call bUG3259_3()|
+drop procedure bUg3259_1|
+drop procedure BuG3259_2|
+drop procedure BUG3259_3|
+drop function if exists bug2772|
+create function bug2772() returns char(10) character set latin2
+return 'a'|
+select bug2772()|
+bug2772()
+a
+drop function bug2772|
+drop procedure if exists bug2776_1|
+create procedure bug2776_1(out x int)
+begin
+declare v int;
+set v = default;
+set x = v;
+end|
+drop procedure if exists bug2776_2|
+create procedure bug2776_2(out x int)
+begin
+declare v int default 42;
+set v = default;
+set x = v;
+end|
+set @x = 1|
+call bug2776_1(@x)|
+select @x|
+@x
+NULL
+call bug2776_2(@x)|
+select @x|
+@x
+42
+drop procedure bug2776_1|
+drop procedure bug2776_2|
+drop table if exists t3|
+create table t3 (s1 smallint)|
+insert into t3 values (123456789012)|
+Warnings:
+Warning 1264 Out of range value adjusted for column 's1' at row 1
+drop procedure if exists bug2780|
+create procedure bug2780()
+begin
+declare exit handler for sqlwarning set @x = 1;
+set @x = 0;
+insert into t3 values (123456789012);
+insert into t3 values (0);
+end|
+call bug2780()|
+select @x|
+@x
+1
+select * from t3|
+s1
+32767
+32767
+drop procedure bug2780|
+drop table t3|
+create table t3 (content varchar(10) )|
+insert into t3 values ("test1")|
+insert into t3 values ("test2")|
+create table t4 (f1 int, rc int, t3 int)|
+drop procedure if exists bug1863|
+create procedure bug1863(in1 int)
+begin
+declare ind int default 0;
+declare t1 int;
+declare t2 int;
+declare t3 int;
+declare rc int default 0;
+declare continue handler for 1065 set rc = 1;
+drop temporary table if exists temp_t1;
+create temporary table temp_t1 (
+f1 int auto_increment, f2 varchar(20), primary key (f1)
+);
+insert into temp_t1 (f2) select content from t3;
+select f2 into t3 from temp_t1 where f1 = 10;
+if (rc) then
+insert into t4 values (1, rc, t3);
+end if;
+insert into t4 values (2, rc, t3);
+end|
+call bug1863(10)|
+Warnings:
+Note 1051 Unknown table 'temp_t1'
+Warning 1329 No data to FETCH
+call bug1863(10)|
+Warnings:
+Warning 1329 No data to FETCH
+select * from t4|
+f1 rc t3
+2 0 NULL
+2 0 NULL
+drop procedure bug1863|
+drop temporary table temp_t1;
+drop table t3, t4|
+drop table if exists t3, t4|
+create table t3 (
+OrderID int not null,
+MarketID int,
+primary key (OrderID)
+)|
+create table t4 (
+MarketID int not null,
+Market varchar(60),
+Status char(1),
+primary key (MarketID)
+)|
+insert t3 (OrderID,MarketID) values (1,1)|
+insert t3 (OrderID,MarketID) values (2,2)|
+insert t4 (MarketID,Market,Status) values (1,"MarketID One","A")|
+insert t4 (MarketID,Market,Status) values (2,"MarketID Two","A")|
+drop procedure if exists bug2656_1|
+create procedure bug2656_1()
+begin
+select
+m.Market
+from t4 m JOIN t3 o
+ON o.MarketID != 1 and o.MarketID = m.MarketID;
+end |
+drop procedure if exists bug2656_2|
+create procedure bug2656_2()
+begin
+select
+m.Market
+from
+t4 m, t3 o
+where
+m.MarketID != 1 and m.MarketID = o.MarketID;
+end |
+call bug2656_1()|
+Market
+MarketID Two
+call bug2656_1()|
+Market
+MarketID Two
+call bug2656_2()|
+Market
+MarketID Two
+call bug2656_2()|
+Market
+MarketID Two
+drop procedure bug2656_1|
+drop procedure bug2656_2|
+drop table t3, t4|
+drop procedure if exists bug3426|
+create procedure bug3426(in_time int unsigned, out x int)
+begin
+if in_time is null then
+set @stamped_time=10;
+set x=1;
+else
+set @stamped_time=in_time;
+set x=2;
+end if;
+end|
+call bug3426(1000, @i)|
+select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
+@i time
+2 01-01-1970 03:16:40
+call bug3426(NULL, @i)|
+select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
+@i time
+1 01-01-1970 03:00:10
+alter procedure bug3426 sql security invoker|
+call bug3426(NULL, @i)|
+select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
+@i time
+1 01-01-1970 03:00:10
+call bug3426(1000, @i)|
+select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
+@i time
+2 01-01-1970 03:16:40
+drop procedure bug3426|
+drop table if exists t3, t4|
+create table t3 (
+a int primary key,
+ach char(1)
+) engine = innodb|
+create table t4 (
+b int primary key ,
+bch char(1)
+) engine = innodb|
+insert into t3 values (1 , 'aCh1' ) , ('2' , 'aCh2')|
+Warnings:
+Warning 1265 Data truncated for column 'ach' at row 1
+Warning 1265 Data truncated for column 'ach' at row 2
+insert into t4 values (1 , 'bCh1' )|
+Warnings:
+Warning 1265 Data truncated for column 'bch' at row 1
+drop procedure if exists bug3448|
+create procedure bug3448()
+select * from t3 inner join t4 on t3.a = t4.b|
+select * from t3 inner join t4 on t3.a = t4.b|
+a ach b bch
+1 a 1 b
+call bug3448()|
+a ach b bch
+1 a 1 b
+call bug3448()|
+a ach b bch
+1 a 1 b
+drop procedure bug3448|
+drop table t3, t4|
+drop table if exists t3|
+create table t3 (
+id int unsigned auto_increment not null primary key,
+title VARCHAR(200),
+body text,
+fulltext (title,body)
+)|
+insert into t3 (title,body) values
+('MySQL Tutorial','DBMS stands for DataBase ...'),
+('How To Use MySQL Well','After you went through a ...'),
+('Optimizing MySQL','In this tutorial we will show ...'),
+('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
+('MySQL vs. YourSQL','In the following database comparison ...'),
+('MySQL Security','When configured properly, MySQL ...')|
+drop procedure if exists bug3734 |
+create procedure bug3734 (param1 varchar(100))
+select * from t3 where match (title,body) against (param1)|
+call bug3734('database')|
+id title body
+5 MySQL vs. YourSQL In the following database comparison ...
+1 MySQL Tutorial DBMS stands for DataBase ...
+call bug3734('Security')|
+id title body
+6 MySQL Security When configured properly, MySQL ...
+drop procedure bug3734|
+drop table t3|
+drop procedure if exists bug3863|
+create procedure bug3863()
+begin
+set @a = 0;
+while @a < 5 do
+set @a = @a + 1;
+end while;
+end|
+call bug3863()|
+select @a|
+@a
+5
+call bug3863()|
+select @a|
+@a
+5
+drop procedure bug3863|
+create table t3 (
+id int(10) unsigned not null default 0,
+rid int(10) unsigned not null default 0,
+msg text not null,
+primary key (id),
+unique key rid (rid, id)
+)|
+drop procedure if exists bug2460_1|
+create procedure bug2460_1(in v int)
+begin
+( select n0.id from t3 as n0 where n0.id = v )
+union
+( select n0.id from t3 as n0, t3 as n1
+where n0.id = n1.rid and n1.id = v )
+union
+( select n0.id from t3 as n0, t3 as n1, t3 as n2
+where n0.id = n1.rid and n1.id = n2.rid and n2.id = v );
+end|
+call bug2460_1(2)|
+id
+call bug2460_1(2)|
+id
+insert into t3 values (1, 1, 'foo'), (2, 1, 'bar'), (3, 1, 'zip zap')|
+call bug2460_1(2)|
+id
+2
+1
+call bug2460_1(2)|
+id
+2
+1
+drop procedure if exists bug2460_2|
+create procedure bug2460_2()
+begin
+drop table if exists t3;
+create temporary table t3 (s1 int);
+insert into t3 select 1 union select 1;
+end|
+call bug2460_2()|
+call bug2460_2()|
+select * from t3|
+s1
+1
+drop procedure bug2460_1|
+drop procedure bug2460_2|
+drop table t3|
+set @@sql_mode = ''|
+drop procedure if exists bug2564_1|
+create procedure bug2564_1()
+comment 'Joe''s procedure'
+ insert into `t1` values ("foo", 1)|
+set @@sql_mode = 'ANSI_QUOTES'|
+drop procedure if exists bug2564_2|
+create procedure bug2564_2()
+insert into "t1" values ('foo', 1)|
+set @@sql_mode = ''$
+drop function if exists bug2564_3$
+create function bug2564_3(x int, y int) returns int
+return x || y$
+set @@sql_mode = 'ANSI'$
+drop function if exists bug2564_4$
+create function bug2564_4(x int, y int) returns int
+return x || y$
+set @@sql_mode = ''|
+show create procedure bug2564_1|
+Procedure sql_mode Create Procedure
+bug2564_1 CREATE PROCEDURE `test`.`bug2564_1`()
+ COMMENT 'Joe''s procedure'
+insert into `t1` values ("foo", 1)
+show create procedure bug2564_2|
+Procedure sql_mode Create Procedure
+bug2564_2 ANSI_QUOTES CREATE PROCEDURE "test"."bug2564_2"()
+insert into "t1" values ('foo', 1)
+show create function bug2564_3|
+Function sql_mode Create Function
+bug2564_3 CREATE FUNCTION `test`.`bug2564_3`(x int, y int) RETURNS int(11)
+return x || y
+show create function bug2564_4|
+Function sql_mode Create Function
+bug2564_4 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI CREATE FUNCTION "test"."bug2564_4"(x int, y int) RETURNS int(11)
+return x || y
+drop procedure bug2564_1|
+drop procedure bug2564_2|
+drop function bug2564_3|
+drop function bug2564_4|
+drop function if exists bug3132|
+create function bug3132(s char(20)) returns char(50)
+return concat('Hello, ', s, '!')|
+select bug3132('Bob') union all select bug3132('Judy')|
+bug3132('Bob')
+Hello, Bob!
+Hello, Judy!
+drop function bug3132|
+drop procedure if exists bug3843|
+create procedure bug3843()
+analyze table t1|
+call bug3843()|
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+call bug3843()|
+Table Op Msg_type Msg_text
+test.t1 analyze status Table is already up to date
+select 1+2|
+1+2
+3
+drop procedure bug3843|
+drop table if exists t3|
+create table t3 ( s1 char(10) )|
+insert into t3 values ('a'), ('b')|
+drop procedure if exists bug3368|
+create procedure bug3368(v char(10))
+begin
+select group_concat(v) from t3;
+end|
+call bug3368('x')|
+group_concat(v)
+x,x
+call bug3368('yz')|
+group_concat(v)
+yz,yz
+drop procedure bug3368|
+drop table t3|
+drop table if exists t3|
+create table t3 (f1 int, f2 int)|
+insert into t3 values (1,1)|
+drop procedure if exists bug4579_1|
+create procedure bug4579_1 ()
+begin
+declare sf1 int;
+select f1 into sf1 from t3 where f1=1 and f2=1;
+update t3 set f2 = f2 + 1 where f1=1 and f2=1;
+call bug4579_2();
+end|
+drop procedure if exists bug4579_2|
+create procedure bug4579_2 ()
+begin
+end|
+call bug4579_1()|
+call bug4579_1()|
+Warnings:
+Warning 1329 No data to FETCH
+call bug4579_1()|
+Warnings:
+Warning 1329 No data to FETCH
+drop procedure bug4579_1|
+drop procedure bug4579_2|
+drop table t3|
+drop table if exists t3|
+drop procedure if exists bug2773|
+create function bug2773() returns int return null|
+create table t3 as select bug2773()|
+show create table t3|
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `bug2773()` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t3|
+drop function bug2773|
+drop procedure if exists bug3788|
+create function bug3788() returns date return cast("2005-03-04" as date)|
+select bug3788()|
+bug3788()
+2005-03-04
+drop function bug3788|
+create function bug3788() returns binary(5) return 5|
+select bug3788()|
+bug3788()
+5
+drop function bug3788|
+drop table if exists t3|
+create table t3 (f1 int, f2 int, f3 int)|
+insert into t3 values (1,1,1)|
+drop procedure if exists bug4726|
+create procedure bug4726()
+begin
+declare tmp_o_id INT;
+declare tmp_d_id INT default 1;
+while tmp_d_id <= 2 do
+begin
+select f1 into tmp_o_id from t3 where f2=1 and f3=1;
+set tmp_d_id = tmp_d_id + 1;
+end;
+end while;
+end|
+call bug4726()|
+call bug4726()|
+call bug4726()|
+drop procedure bug4726|
+drop table t3|
+drop procedure if exists bug4902|
+create procedure bug4902()
+begin
+show charset like 'foo';
+show collation like 'foo';
+show column types;
+show create table t1;
+show create database test;
+show databases like 'foo';
+show errors;
+show columns from t1;
+show grants for 'root'@'localhost';
+show keys from t1;
+show open tables like 'foo';
+show privileges;
+show status like 'foo';
+show tables like 'foo';
+show variables like 'foo';
+show warnings;
+end|
+call bug4902()|
+Charset Description Default collation Maxlen
+Collation Charset Id Default Compiled Sortlen
+Type Size Min_Value Max_Value Prec Scale Nullable Auto_Increment Unsigned Zerofill Searchable Case_Sensitive Default Comment
+tinyint 1 -128 127 0 0 YES YES NO YES YES NO NULL,0 A very small integer
+tinyint unsigned 1 0 255 0 0 YES YES YES YES YES NO NULL,0 A very small integer
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` char(16) NOT NULL default '',
+ `data` int(11) NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Database Create Database
+test CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */
+Database (foo)
+Level Code Message
+Field Type Null Key Default Extra
+id char(16) NO
+data int(11) NO
+Grants for root@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+Database Table In_use Name_locked
+Privilege Context Comment
+Alter Tables To alter the table
+Alter routine Functions,Procedures To alter or drop stored functions/procedures
+Create Databases,Tables,Indexes To create new databases and tables
+Create routine Functions,Procedures To use CREATE FUNCTION/PROCEDURE
+Create temporary tables Databases To use CREATE TEMPORARY TABLE
+Create view Tables To create new views
+Create user Server Admin To create new users
+Delete Tables To delete existing rows
+Drop Databases,Tables To drop databases, tables, and views
+Execute Functions,Procedures To execute stored routines
+File File access on server To read and write files on the server
+Grant option Databases,Tables,Functions,Procedures To give to other users those privileges you possess
+Index Tables To create or drop indexes
+Insert Tables To insert data into tables
+Lock tables Databases To use LOCK TABLES (together with SELECT privilege)
+Process Server Admin To view the plain text of currently executing queries
+References Databases,Tables To have references on tables
+Reload Server Admin To reload or refresh tables, logs and privileges
+Replication client Server Admin To ask where the slave or master servers are
+Replication slave Server Admin To read binary log events from the master
+Select Tables To retrieve rows from table
+Show databases Server Admin To see all databases with SHOW DATABASES
+Show view Tables To see views with SHOW CREATE VIEW
+Shutdown Server Admin To shut down the server
+Super Server Admin To use KILL thread, SET GLOBAL, CHANGE MASTER, etc.
+Update Tables To update existing rows
+Usage Server Admin No privileges - allow connect only
+Variable_name Value
+Tables_in_test (foo)
+Variable_name Value
+Level Code Message
+call bug4902()|
+Charset Description Default collation Maxlen
+Collation Charset Id Default Compiled Sortlen
+Type Size Min_Value Max_Value Prec Scale Nullable Auto_Increment Unsigned Zerofill Searchable Case_Sensitive Default Comment
+tinyint 1 -128 127 0 0 YES YES NO YES YES NO NULL,0 A very small integer
+tinyint unsigned 1 0 255 0 0 YES YES YES YES YES NO NULL,0 A very small integer
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` char(16) NOT NULL default '',
+ `data` int(11) NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Database Create Database
+test CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */
+Database (foo)
+Level Code Message
+Field Type Null Key Default Extra
+id char(16) NO
+data int(11) NO
+Grants for root@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+Database Table In_use Name_locked
+Privilege Context Comment
+Alter Tables To alter the table
+Alter routine Functions,Procedures To alter or drop stored functions/procedures
+Create Databases,Tables,Indexes To create new databases and tables
+Create routine Functions,Procedures To use CREATE FUNCTION/PROCEDURE
+Create temporary tables Databases To use CREATE TEMPORARY TABLE
+Create view Tables To create new views
+Create user Server Admin To create new users
+Delete Tables To delete existing rows
+Drop Databases,Tables To drop databases, tables, and views
+Execute Functions,Procedures To execute stored routines
+File File access on server To read and write files on the server
+Grant option Databases,Tables,Functions,Procedures To give to other users those privileges you possess
+Index Tables To create or drop indexes
+Insert Tables To insert data into tables
+Lock tables Databases To use LOCK TABLES (together with SELECT privilege)
+Process Server Admin To view the plain text of currently executing queries
+References Databases,Tables To have references on tables
+Reload Server Admin To reload or refresh tables, logs and privileges
+Replication client Server Admin To ask where the slave or master servers are
+Replication slave Server Admin To read binary log events from the master
+Select Tables To retrieve rows from table
+Show databases Server Admin To see all databases with SHOW DATABASES
+Show view Tables To see views with SHOW CREATE VIEW
+Shutdown Server Admin To shut down the server
+Super Server Admin To use KILL thread, SET GLOBAL, CHANGE MASTER, etc.
+Update Tables To update existing rows
+Usage Server Admin No privileges - allow connect only
+Variable_name Value
+Tables_in_test (foo)
+Variable_name Value
+Level Code Message
+drop procedure bug4902|
+drop procedure if exists bug4902_2|
+create procedure bug4902_2()
+begin
+show processlist;
+end|
+call bug4902_2()|
+Id User Host db Command Time State Info
+# root localhost test Query # NULL show processlist
+call bug4902_2()|
+Id User Host db Command Time State Info
+# root localhost test Query # NULL show processlist
+drop procedure bug4902_2|
+drop table if exists t3|
+drop procedure if exists bug4904|
+create procedure bug4904()
+begin
+declare continue handler for sqlstate 'HY000' begin end;
+create table t2 as select * from t3;
+end|
+call bug4904()|
+ERROR 42S02: Table 'test.t3' doesn't exist
+drop procedure bug4904|
+create table t3 (s1 char character set latin1, s2 char character set latin2)|
+drop procedure if exists bug4904|
+create procedure bug4904 ()
+begin
+declare continue handler for sqlstate 'HY000' begin end;
+select s1 from t3 union select s2 from t3;
+end|
+call bug4904()|
+drop procedure bug4904|
+drop table t3|
+drop procedure if exists bug336|
+create procedure bug336(out y int)
+begin
+declare x int;
+set x = (select sum(t.data) from test.t1 t);
+set y = x;
+end|
+insert into t1 values ("a", 2), ("b", 3)|
+call bug336(@y)|
+select @y|
+@y
+5
+delete from t1|
+drop procedure bug336|
+drop procedure if exists bug3157|
+create procedure bug3157()
+begin
+if exists(select * from t1) then
+set @n= @n + 1;
+end if;
+if (select count(*) from t1) then
+set @n= @n + 1;
+end if;
+end|
+set @n = 0|
+insert into t1 values ("a", 1)|
+call bug3157()|
+select @n|
+@n
+2
+delete from t1|
+drop procedure bug3157|
+drop procedure if exists bug5251|
+create procedure bug5251()
+begin
+end|
+select created into @c1 from mysql.proc
+where db='test' and name='bug5251'|
+alter procedure bug5251 comment 'foobar'|
+select count(*) from mysql.proc
+where db='test' and name='bug5251' and created = @c1|
+count(*)
+1
+drop procedure bug5251|
+drop procedure if exists bug5251|
+create procedure bug5251()
+checksum table t1|
+call bug5251()|
+Table Checksum
+test.t1 0
+call bug5251()|
+Table Checksum
+test.t1 0
+drop procedure bug5251|
+drop procedure if exists bug5287|
+create procedure bug5287(param1 int)
+label1:
+begin
+declare c cursor for select 5;
+loop
+if param1 >= 0 then
+leave label1;
+end if;
+end loop;
+end|
+call bug5287(1)|
+drop procedure bug5287|
+drop procedure if exists bug5307|
+create procedure bug5307()
+begin
+end; set @x = 3|
+call bug5307()|
+select @x|
+@x
+3
+drop procedure bug5307|
+drop procedure if exists bug5258|
+create procedure bug5258()
+begin
+end|
+drop procedure if exists bug5258_aux|
+create procedure bug5258_aux()
+begin
+declare c, m char(19);
+select created,modified into c,m from mysql.proc where name = 'bug5258';
+if c = m then
+select 'Ok';
+else
+select c, m;
+end if;
+end|
+call bug5258_aux()|
+Ok
+Ok
+drop procedure bug5258|
+drop procedure bug5258_aux|
+drop function if exists bug4487|
+create function bug4487() returns char
+begin
+declare v char;
+return v;
+end|
+select bug4487()|
+bug4487()
+NULL
+drop function bug4487|
+drop procedure if exists bug4941|
+drop procedure if exists bug4941|
+create procedure bug4941(out x int)
+begin
+declare c cursor for select i from t2 limit 1;
+open c;
+fetch c into x;
+close c;
+end|
+insert into t2 values (null, null, null)|
+set @x = 42|
+call bug4941(@x)|
+select @x|
+@x
+NULL
+delete from t1|
+drop procedure bug4941|
+drop procedure if exists bug3583|
+drop procedure if exists bug3583|
+create procedure bug3583()
+begin
+declare c int;
+select * from t1;
+select count(*) into c from t1;
+select c;
+end|
+insert into t1 values ("x", 3), ("y", 5)|
+set @x = @@query_cache_size|
+set global query_cache_size = 10*1024*1024|
+flush status|
+flush query cache|
+show status like 'Qcache_hits'|
+Variable_name Value
+Qcache_hits 0
+call bug3583()|
+id data
+x 3
+y 5
+c
+2
+show status like 'Qcache_hits'|
+Variable_name Value
+Qcache_hits 0
+call bug3583()|
+id data
+x 3
+y 5
+c
+2
+call bug3583()|
+id data
+x 3
+y 5
+c
+2
+show status like 'Qcache_hits'|
+Variable_name Value
+Qcache_hits 2
+set global query_cache_size = @x|
+flush status|
+flush query cache|
+delete from t1|
+drop procedure bug3583|
+drop table if exists t3|
+drop procedure if exists bug4905|
+create table t3 (s1 int,primary key (s1))|
+drop procedure if exists bug4905|
+create procedure bug4905()
+begin
+declare v int;
+declare continue handler for sqlstate '23000' set v = 5;
+insert into t3 values (1);
+end|
+call bug4905()|
+select row_count()|
+row_count()
+1
+call bug4905()|
+select row_count()|
+row_count()
+0
+call bug4905()|
+select row_count()|
+row_count()
+0
+select * from t3|
+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()
+begin
+declare exit handler for 1136 select '1136';
+declare exit handler for sqlstate '23000' select 'sqlstate 23000';
+declare continue handler for sqlexception select 'sqlexception';
+insert into t3 values (1);
+insert into t3 values (1,2);
+end|
+create table t3 (s1 int, primary key (s1))|
+insert into t3 values (1)|
+call bug6029()|
+sqlstate 23000
+sqlstate 23000
+delete from t3|
+call bug6029()|
+1136
+1136
+drop procedure bug6029|
+drop table t3|
+drop procedure if exists bug8540|
+create procedure bug8540()
+begin
+declare x int default 1;
+select x as y, x+0 as z;
+end|
+call bug8540()|
+y z
+1 1
+drop procedure bug8540|
+drop table if exists t3|
+create table t3 (s1 int)|
+drop procedure if exists bug6642|
+create procedure bug6642()
+select abs(count(s1)) from t3|
+call bug6642()|
+abs(count(s1))
+0
+call bug6642()|
+abs(count(s1))
+0
+drop procedure bug6642|
+insert into t3 values (0),(1)|
+drop procedure if exists bug7013|
+create procedure bug7013()
+select s1,count(s1) from t3 group by s1 with rollup|
+call bug7013()|
+s1 count(s1)
+0 1
+1 1
+NULL 2
+call bug7013()|
+s1 count(s1)
+0 1
+1 1
+NULL 2
+drop procedure bug7013|
+drop table if exists t4|
+create table t4 (
+a mediumint(8) unsigned not null auto_increment,
+b smallint(5) unsigned not null,
+c char(32) not null,
+primary key (a)
+) engine=myisam default charset=latin1|
+insert into t4 values (1, 2, 'oneword')|
+insert into t4 values (2, 2, 'anotherword')|
+drop procedure if exists bug7743|
+create procedure bug7743 ( searchstring char(28) )
+begin
+declare var mediumint(8) unsigned;
+select a into var from t4 where b = 2 and c = binary searchstring limit 1;
+select var;
+end|
+call bug7743("oneword")|
+var
+1
+call bug7743("OneWord")|
+var
+NULL
+Warnings:
+Warning 1329 No data to FETCH
+call bug7743("anotherword")|
+var
+2
+call bug7743("AnotherWord")|
+var
+NULL
+Warnings:
+Warning 1329 No data to FETCH
+drop procedure bug7743|
+drop table t4|
+delete from t3|
+insert into t3 values(1)|
+drop procedure if exists bug7992_1|
+Warnings:
+Note 1305 PROCEDURE bug7992_1 does not exist
+drop procedure if exists bug7992_2|
+Warnings:
+Note 1305 PROCEDURE bug7992_2 does not exist
+create procedure bug7992_1()
+begin
+declare i int;
+select max(s1)+1 into i from t3;
+end|
+create procedure bug7992_2()
+insert into t3 (s1) select max(t4.s1)+1 from t3 as t4|
+call bug7992_1()|
+call bug7992_1()|
+call bug7992_2()|
+call bug7992_2()|
+drop procedure bug7992_1|
+drop procedure bug7992_2|
+drop table t3|
+drop table if exists t3|
+create table t3 ( userid bigint(20) not null default 0 )|
+drop procedure if exists bug8116|
+create procedure bug8116(in _userid int)
+select * from t3 where userid = _userid|
+call bug8116(42)|
+userid
+call bug8116(42)|
+userid
+drop procedure bug8116|
+drop table t3|
+drop procedure if exists bug6857|
+create procedure bug6857(counter int)
+begin
+declare t0, t1 int;
+declare plus bool default 0;
+set t0 = current_time();
+while counter > 0 do
+set counter = counter - 1;
+end while;
+set t1 = current_time();
+if t1 > t0 then
+set plus = 1;
+end if;
+select plus;
+end|
+drop procedure bug6857|
+drop procedure if exists bug8757|
+create procedure bug8757()
+begin
+declare x int;
+declare c1 cursor for select data from t1 limit 1;
+begin
+declare y int;
+declare c2 cursor for select i from t2 limit 1;
+open c2;
+fetch c2 into y;
+close c2;
+select 2,y;
+end;
+open c1;
+fetch c1 into x;
+close c1;
+select 1,x;
+end|
+delete from t1|
+delete from t2|
+insert into t1 values ("x", 1)|
+insert into t2 values ("y", 2, 0.0)|
+call bug8757()|
+2 y
+2 2
+1 x
+1 1
+delete from t1|
+delete from t2|
+drop procedure bug8757|
+drop procedure if exists bug8762|
+drop procedure if exists bug8762; create procedure bug8762() begin end|
+drop procedure if exists bug8762; create procedure bug8762() begin end|
+drop procedure bug8762|
+drop function if exists bug5240|
+create function bug5240 () returns int
+begin
+declare x int;
+declare c cursor for select data from t1 limit 1;
+open c;
+fetch c into x;
+close c;
+return x;
+end|
+delete from t1|
+insert into t1 values ("answer", 42)|
+select id, bug5240() from t1|
+id bug5240()
+answer 42
+drop function bug5240|
+drop function if exists bug5278|
+create function bug5278 () returns char
+begin
+SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass');
+return 'okay';
+end|
+select bug5278()|
+ERROR 42000: Can't find any matching row in the user table
+select bug5278()|
+ERROR 42000: Can't find any matching row in the user table
+drop function bug5278|
+drop procedure if exists p1|
+create table t3(id int)|
+insert into t3 values(1)|
+create procedure bug7992()
+begin
+declare i int;
+select max(id)+1 into i from t3;
+end|
+call bug7992()|
+call bug7992()|
+drop procedure bug7992|
+drop table t3|
+create table t3 (
+lpitnumber int(11) default null,
+lrecordtype int(11) default null
+)|
+create table t4 (
+lbsiid int(11) not null default '0',
+ltradingmodeid int(11) not null default '0',
+ltradingareaid int(11) not null default '0',
+csellingprice decimal(19,4) default null,
+primary key (lbsiid,ltradingmodeid,ltradingareaid)
+)|
+create table t5 (
+lbsiid int(11) not null default '0',
+ltradingareaid int(11) not null default '0',
+primary key (lbsiid,ltradingareaid)
+)|
+drop procedure if exists bug8849|
+create procedure bug8849()
+begin
+insert into t5
+(
+t5.lbsiid,
+t5.ltradingareaid
+)
+select distinct t3.lpitnumber, t4.ltradingareaid
+from
+t4 join t3 on
+t3.lpitnumber = t4.lbsiid
+and t3.lrecordtype = 1
+left join t4 as price01 on
+price01.lbsiid = t4.lbsiid and
+price01.ltradingmodeid = 1 and
+t4.ltradingareaid = price01.ltradingareaid;
+end|
+call bug8849()|
+call bug8849()|
+call bug8849()|
+drop procedure bug8849|
+drop tables t3,t4,t5|
+drop procedure if exists bug8937|
+create procedure bug8937()
+begin
+declare s,x,y,z int;
+declare a float;
+select sum(data),avg(data),min(data),max(data) into s,x,y,z from t1;
+select s,x,y,z;
+select avg(data) into a from t1;
+select a;
+end|
+delete from t1|
+insert into t1 (data) values (1), (2), (3), (4), (6)|
+call bug8937()|
+s x y z
+16 3 1 6
+a
+3.2000
+drop procedure bug8937|
+delete from t1|
+drop procedure if exists bug6900|
+drop procedure if exists bug9074|
+drop procedure if exists bug6900_9074|
+drop table if exists t3|
+create table t3 (w char unique, x char)|
+insert into t3 values ('a', 'b')|
+create procedure bug6900()
+begin
+declare exit handler for sqlexception select '1';
+begin
+declare exit handler for sqlexception select '2';
+insert into t3 values ('x', 'y', 'z');
+end;
+end|
+create procedure bug9074()
+begin
+declare x1, x2, x3, x4, x5, x6 int default 0;
+begin
+declare continue handler for sqlstate '23000' set x5 = 1;
+insert into t3 values ('a', 'b');
+set x6 = 1;
+end;
+begin1_label:
+begin
+declare continue handler for sqlstate '23000' set x1 = 1;
+insert into t3 values ('a', 'b');
+set x2 = 1;
+begin2_label:
+begin
+declare exit handler for sqlstate '23000' set x3 = 1;
+set x4= 1;
+insert into t3 values ('a','b');
+set x4= 0;
+end begin2_label;
+end begin1_label;
+select x1, x2, x3, x4, x5, x6;
+end|
+create procedure bug6900_9074(z int)
+begin
+declare exit handler for sqlstate '23000' select '23000';
+begin
+declare exit handler for sqlexception select 'sqlexception';
+if z = 1 then
+insert into t3 values ('a', 'b');
+else
+insert into t3 values ('x', 'y', 'z');
+end if;
+end;
+end|
+call bug6900()|
+2
+2
+call bug9074()|
+x1 x2 x3 x4 x5 x6
+1 1 1 1 1 1
+call bug6900_9074(0)|
+sqlexception
+sqlexception
+call bug6900_9074(1)|
+23000
+23000
+drop procedure bug6900|
+drop procedure bug9074|
+drop procedure bug6900_9074|
+drop table t3|
+drop procedure if exists avg|
+create procedure avg ()
+begin
+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
+drop procedure bug6129|
+drop procedure if exists bug9856|
+create procedure bug9856()
+begin
+declare v int;
+declare c cursor for select data from t1;
+declare exit handler for sqlexception, not found select '16';
+open c;
+fetch c into v;
+select v;
+end|
+delete from t1|
+call bug9856()|
+16
+16
+call bug9856()|
+16
+16
+drop procedure bug9856|
+drop procedure if exists bug9674_1|
+drop procedure if exists bug9674_2|
+create procedure bug9674_1(out arg int)
+begin
+declare temp_in1 int default 0;
+declare temp_fl1 int default 0;
+set temp_in1 = 100;
+set temp_fl1 = temp_in1/10;
+set arg = temp_fl1;
+end|
+create procedure bug9674_2()
+begin
+declare v int default 100;
+select v/10;
+end|
+call bug9674_1(@sptmp)|
+call bug9674_1(@sptmp)|
+select @sptmp|
+@sptmp
+10
+call bug9674_2()|
+v/10
+10.00000
+call bug9674_2()|
+v/10
+10.00000
+drop procedure bug9674_1|
+drop procedure bug9674_2|
+drop procedure if exists bug9598_1|
+drop procedure if exists bug9598_2|
+create procedure bug9598_1(in var_1 char(16),
+out var_2 integer, out var_3 integer)
+begin
+set var_2 = 50;
+set var_3 = 60;
+end|
+create procedure bug9598_2(in v1 char(16),
+in v2 integer,
+in v3 integer,
+in v4 integer,
+in v5 integer)
+begin
+select v1,v2,v3,v4,v5;
+call bug9598_1(v1,@tmp1,@tmp2);
+select v1,v2,v3,v4,v5;
+end|
+call bug9598_2('Test',2,3,4,5)|
+v1 v2 v3 v4 v5
+Test 2 3 4 5
+v1 v2 v3 v4 v5
+Test 2 3 4 5
+select @tmp1, @tmp2|
+@tmp1 @tmp2
+50 60
+drop procedure bug9598_1|
+drop procedure bug9598_2|
+drop procedure if exists bug9902|
+create function bug9902() returns int(11)
+begin
+set @x = @x + 1;
+return @x;
+end|
+set @qcs1 = @@query_cache_size|
+set global query_cache_size = 100000|
+set @x = 1|
+insert into t1 values ("qc", 42)|
+select bug9902() from t1|
+bug9902()
+2
+select bug9902() from t1|
+bug9902()
+3
+select @x|
+@x
+3
+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()|
+bug9102()
+a
+drop function bug9102|
+drop function if exists bug7648|
+create function bug7648() returns bit(8) return 'a'|
+select bug7648()|
+bug7648()
+a
+drop function bug7648|
+drop function if exists bug9775|
+create function bug9775(v1 char(1)) returns enum('a','b') return v1|
+select bug9775('a'),bug9775('b'),bug9775('c')|
+bug9775('a') bug9775('b') bug9775('c')
+a b
+drop function bug9775|
+create function bug9775(v1 int) returns enum('a','b') return v1|
+select bug9775(1),bug9775(2),bug9775(3)|
+bug9775(1) bug9775(2) bug9775(3)
+a b
+drop function bug9775|
+create function bug9775(v1 char(1)) returns set('a','b') return v1|
+select bug9775('a'),bug9775('b'),bug9775('a,b'),bug9775('c')|
+bug9775('a') bug9775('b') bug9775('a,b') bug9775('c')
+a b a,b
+drop function bug9775|
+create function bug9775(v1 int) returns set('a','b') return v1|
+select bug9775(1),bug9775(2),bug9775(3),bug9775(4)|
+bug9775(1) bug9775(2) bug9775(3) bug9775(4)
+a b a,b
+drop function bug9775|
+drop function if exists bug8861|
+create function bug8861(v1 int) returns year return v1|
+select bug8861(05)|
+bug8861(05)
+2005
+set @x = bug8861(05)|
+select @x|
+@x
+2005
+drop function bug8861|
+drop procedure if exists bug9004_1|
+drop procedure if exists bug9004_2|
+create procedure bug9004_1(x char(16))
+begin
+insert into t1 values (x, 42);
+insert into t1 values (x, 17);
+end|
+create procedure bug9004_2(x char(16))
+call bug9004_1(x)|
+call bug9004_1('12345678901234567')|
+Warnings:
+Warning 1265 Data truncated for column 'id' at row 1
+Warning 1265 Data truncated for column 'id' at row 2
+call bug9004_2('12345678901234567890')|
+Warnings:
+Warning 1265 Data truncated for column 'id' at row 1
+Warning 1265 Data truncated for column 'id' at row 2
+delete from t1|
+drop procedure bug9004_1|
+drop procedure bug9004_2|
+drop table t1,t2;
diff --git a/mysql-test/r/sp_trans.result b/mysql-test/r/sp_trans.result
new file mode 100644
index 00000000000..dee87979ff4
--- /dev/null
+++ b/mysql-test/r/sp_trans.result
@@ -0,0 +1,22 @@
+drop procedure if exists bug8850|
+create table t1 (a int) engine=innodb|
+create procedure bug8850()
+begin
+truncate table t1; insert t1 values (1); rollback;
+end|
+set autocommit=0|
+insert t1 values (2)|
+call bug8850()|
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+commit|
+select * from t1|
+a
+2
+call bug8850()|
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+set autocommit=1|
+select * from t1|
+a
+2
+drop table t1|
+drop procedure bug8850|
diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result
index c18be2df403..09adc48259c 100644
--- a/mysql-test/r/sql_mode.result
+++ b/mysql-test/r/sql_mode.result
@@ -17,8 +17,8 @@ t1 CREATE TABLE `t1` (
`pseudo` varchar(35) character set latin2 NOT NULL default '',
`email` varchar(60) character set latin2 NOT NULL default '',
PRIMARY KEY (`a`),
- UNIQUE KEY `email` TYPE BTREE (`email`)
-) ENGINE=HEAP DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+ UNIQUE KEY `email` USING BTREE (`email`)
+) ENGINE=MEMORY DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
set @@sql_mode="ansi_quotes";
show variables like 'sql_mode';
Variable_name Value
@@ -30,8 +30,8 @@ t1 CREATE TABLE "t1" (
"pseudo" varchar(35) character set latin2 NOT NULL default '',
"email" varchar(60) character set latin2 NOT NULL default '',
PRIMARY KEY ("a"),
- UNIQUE KEY "email" TYPE BTREE ("email")
-) ENGINE=HEAP DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+ UNIQUE KEY "email" USING BTREE ("email")
+) ENGINE=MEMORY DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
set @@sql_mode="no_table_options";
show variables like 'sql_mode';
Variable_name Value
@@ -43,7 +43,7 @@ t1 CREATE TABLE `t1` (
`pseudo` varchar(35) character set latin2 NOT NULL default '',
`email` varchar(60) character set latin2 NOT NULL default '',
PRIMARY KEY (`a`),
- UNIQUE KEY `email` TYPE BTREE (`email`)
+ UNIQUE KEY `email` USING BTREE (`email`)
)
set @@sql_mode="no_key_options";
show variables like 'sql_mode';
@@ -57,11 +57,11 @@ t1 CREATE TABLE `t1` (
`email` varchar(60) character set latin2 NOT NULL default '',
PRIMARY KEY (`a`),
UNIQUE KEY `email` (`email`)
-) ENGINE=HEAP DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+) ENGINE=MEMORY DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
set @@sql_mode="no_field_options,mysql323,mysql40";
show variables like 'sql_mode';
Variable_name Value
-sql_mode NO_FIELD_OPTIONS,MYSQL323,MYSQL40
+sql_mode NO_FIELD_OPTIONS,MYSQL323,MYSQL40,HIGH_NOT_PRECEDENCE
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
@@ -74,7 +74,7 @@ t1 CREATE TABLE `t1` (
set sql_mode="postgresql,oracle,mssql,db2,maxdb";
select @@sql_mode;
@@sql_mode
-PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,POSTGRESQL,ORACLE,MSSQL,DB2,MAXDB,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS
+PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,POSTGRESQL,ORACLE,MSSQL,DB2,MAXDB,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER
show create table t1;
Table Create Table
t1 CREATE TABLE "t1" (
@@ -138,3 +138,266 @@ t1 CREATE TABLE `t1` (
`min_num` decimal(7,6) default '0.000001'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1 ;
+SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE='';
+show local variables like 'SQL_MODE';
+Variable_name Value
+sql_mode
+CREATE TABLE t1 (p int not null auto_increment, a varchar(20), primary key(p));
+INSERT t1 (a) VALUES
+('\\'),
+('\n'),
+('\b'),
+('\r'),
+('\t'),
+('\x'),
+('\a'),
+('\aa'),
+('\\a'),
+('\\aa'),
+('_'),
+('\_'),
+('\\_'),
+('\\\_'),
+('\\\\_'),
+('%'),
+('\%'),
+('\\%'),
+('\\\%'),
+('\\\\%')
+;
+SELECT p, hex(a) FROM t1;
+p hex(a)
+1 5C
+2 0A
+3 08
+4 0D
+5 09
+6 78
+7 61
+8 6161
+9 5C61
+10 5C6161
+11 5F
+12 5C5F
+13 5C5F
+14 5C5C5F
+15 5C5C5F
+16 25
+17 5C25
+18 5C25
+19 5C5C25
+20 5C5C25
+delete from t1 where a in ('\n','\r','\t', '\b');
+select
+masks.p,
+masks.a as mask,
+examples.a as example
+from
+t1 as masks
+left join t1 as examples on examples.a LIKE masks.a
+order by masks.p, example;
+p mask example
+1 \ \
+6 x x
+7 a a
+8 aa aa
+9 \a a
+10 \aa aa
+11 _ %
+11 _ a
+11 _ x
+11 _ \
+11 _ _
+12 \_ _
+13 \_ _
+14 \\_ \%
+14 \\_ \%
+14 \\_ \a
+14 \\_ \_
+14 \\_ \_
+15 \\_ \%
+15 \\_ \%
+15 \\_ \a
+15 \\_ \_
+15 \\_ \_
+16 % %
+16 % a
+16 % aa
+16 % x
+16 % \
+16 % \%
+16 % \%
+16 % \a
+16 % \aa
+16 % \\%
+16 % \\%
+16 % \\_
+16 % \\_
+16 % \_
+16 % \_
+16 % _
+17 \% %
+18 \% %
+19 \\% \
+19 \\% \%
+19 \\% \%
+19 \\% \a
+19 \\% \aa
+19 \\% \\%
+19 \\% \\%
+19 \\% \\_
+19 \\% \\_
+19 \\% \_
+19 \\% \_
+20 \\% \
+20 \\% \%
+20 \\% \%
+20 \\% \a
+20 \\% \aa
+20 \\% \\%
+20 \\% \\%
+20 \\% \\_
+20 \\% \\_
+20 \\% \_
+20 \\% \_
+DROP TABLE t1;
+SET @@SQL_MODE='NO_BACKSLASH_ESCAPES';
+show local variables like 'SQL_MODE';
+Variable_name Value
+sql_mode NO_BACKSLASH_ESCAPES
+CREATE TABLE t1 (p int not null auto_increment, a varchar(20), primary key(p));
+INSERT t1 (a) VALUES
+('\\'),
+('\n'),
+('\b'),
+('\r'),
+('\t'),
+('\x'),
+('\a'),
+('\aa'),
+('\\a'),
+('\\aa'),
+('_'),
+('\_'),
+('\\_'),
+('\\\_'),
+('\\\\_'),
+('%'),
+('\%'),
+('\\%'),
+('\\\%'),
+('\\\\%')
+;
+SELECT p, hex(a) FROM t1;
+p hex(a)
+1 5C5C
+2 5C6E
+3 5C62
+4 5C72
+5 5C74
+6 5C78
+7 5C61
+8 5C6161
+9 5C5C61
+10 5C5C6161
+11 5F
+12 5C5F
+13 5C5C5F
+14 5C5C5C5F
+15 5C5C5C5C5F
+16 25
+17 5C25
+18 5C5C25
+19 5C5C5C25
+20 5C5C5C5C25
+delete from t1 where a in ('\n','\r','\t', '\b');
+select
+masks.p,
+masks.a as mask,
+examples.a as example
+from
+t1 as masks
+left join t1 as examples on examples.a LIKE masks.a
+order by masks.p, example;
+p mask example
+1 \\ \\
+6 \x \x
+7 \a \a
+8 \aa \aa
+9 \\a \\a
+10 \\aa \\aa
+11 _ %
+11 _ _
+12 \_ \%
+12 \_ \a
+12 \_ \x
+12 \_ \\
+12 \_ \_
+13 \\_ \\%
+13 \\_ \\a
+13 \\_ \\_
+14 \\\_ \\\%
+14 \\\_ \\\_
+15 \\\\_ \\\\%
+15 \\\\_ \\\\_
+16 % %
+16 % \%
+16 % \a
+16 % \aa
+16 % \x
+16 % \\
+16 % \\%
+16 % \\a
+16 % \\aa
+16 % \\\%
+16 % \\\\%
+16 % \\\\_
+16 % \\\_
+16 % \\_
+16 % \_
+16 % _
+17 \% \%
+17 \% \a
+17 \% \aa
+17 \% \x
+17 \% \\
+17 \% \\%
+17 \% \\a
+17 \% \\aa
+17 \% \\\%
+17 \% \\\\%
+17 \% \\\\_
+17 \% \\\_
+17 \% \\_
+17 \% \_
+18 \\% \\
+18 \\% \\%
+18 \\% \\a
+18 \\% \\aa
+18 \\% \\\%
+18 \\% \\\\%
+18 \\% \\\\_
+18 \\% \\\_
+18 \\% \\_
+19 \\\% \\\%
+19 \\\% \\\\%
+19 \\\% \\\\_
+19 \\\% \\\_
+20 \\\\% \\\\%
+20 \\\\% \\\\_
+DROP TABLE t1;
+SET @@SQL_MODE='NO_BACKSLASH_ESCAPES';
+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
+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 @@SQL_MODE='';
+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
+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 @@SQL_MODE=@OLD_SQL_MODE;
diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result
new file mode 100644
index 00000000000..7d1b6b67fd2
--- /dev/null
+++ b/mysql-test/r/strict.result
@@ -0,0 +1,1234 @@
+set @org_mode=@@sql_mode;
+set @@sql_mode='ansi,traditional';
+select @@sql_mode;
+@@sql_mode
+REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (col1 date);
+INSERT INTO t1 VALUES('2004-01-01'),('0000-10-31'),('2004-02-29');
+INSERT INTO t1 VALUES('2004-0-31');
+ERROR 22007: Incorrect date value: '2004-0-31' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-01-02'),('2004-0-31');
+ERROR 22007: Incorrect date value: '2004-0-31' for column 'col1' at row 2
+INSERT INTO t1 VALUES('2004-10-0');
+ERROR 22007: Incorrect date value: '2004-10-0' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-09-31');
+ERROR 22007: Incorrect date value: '2004-09-31' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-10-32');
+ERROR 22007: Incorrect date value: '2004-10-32' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2003-02-29');
+ERROR 22007: Incorrect date value: '2003-02-29' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-13-15');
+ERROR 22007: Incorrect date value: '2004-13-15' for column 'col1' at row 1
+INSERT INTO t1 VALUES('0000-00-00');
+ERROR 22007: Incorrect date value: '0000-00-00' for column 'col1' at row 1
+INSERT INTO t1 VALUES ('59');
+ERROR 22007: Incorrect date value: '59' for column 'col1' at row 1
+set @@sql_mode='STRICT_ALL_TABLES';
+INSERT INTO t1 VALUES('2004-01-03'),('2004-0-31');
+set @@sql_mode='STRICT_ALL_TABLES,NO_ZERO_IN_DATE';
+INSERT INTO t1 VALUES('2004-0-30');
+ERROR 22007: Incorrect date value: '2004-0-30' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-01-04'),('2004-0-31'),('2004-01-05');
+ERROR 22007: Incorrect date value: '2004-0-31' for column 'col1' at row 2
+INSERT INTO t1 VALUES('0000-00-00');
+INSERT IGNORE INTO t1 VALUES('2004-0-29');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+set @@sql_mode='STRICT_ALL_TABLES,NO_ZERO_DATE';
+INSERT INTO t1 VALUES('0000-00-00');
+ERROR 22007: Incorrect date value: '0000-00-00' for column 'col1' at row 1
+INSERT IGNORE INTO t1 VALUES('0000-00-00');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT INTO t1 VALUES ('2004-0-30');
+INSERT INTO t1 VALUES ('2004-2-30');
+ERROR 22007: Incorrect date value: '2004-2-30' for column 'col1' at row 1
+set @@sql_mode='STRICT_ALL_TABLES,ALLOW_INVALID_DATES';
+INSERT INTO t1 VALUES ('2004-2-30');
+set @@sql_mode='ansi,traditional';
+INSERT IGNORE INTO t1 VALUES('2004-02-29'),('2004-13-15'),('0000-00-00');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 2
+Warning 1265 Data truncated for column 'col1' at row 3
+select * from t1;
+col1
+2004-01-01
+0000-10-31
+2004-02-29
+2004-01-02
+2004-01-03
+2004-00-31
+2004-01-04
+0000-00-00
+0000-00-00
+0000-00-00
+2004-00-30
+2004-02-30
+2004-02-29
+0000-00-00
+0000-00-00
+drop table t1;
+set @@sql_mode='strict_trans_tables';
+CREATE TABLE t1 (col1 date) engine=myisam;
+INSERT INTO t1 VALUES('2004-13-31'),('2004-1-1');
+ERROR 22007: Incorrect date value: '2004-13-31' for column 'col1' at row 1
+INSERT INTO t1 VALUES ('2004-1-2'), ('2004-13-31'),('2004-1-3');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 2
+INSERT IGNORE INTO t1 VALUES('2004-13-31'),('2004-1-4');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT INTO t1 VALUES ('2003-02-29');
+ERROR 22007: Incorrect date value: '2003-02-29' for column 'col1' at row 1
+INSERT ignore INTO t1 VALUES('2003-02-30');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+set @@sql_mode='STRICT_ALL_TABLES,ALLOW_INVALID_DATES';
+INSERT ignore INTO t1 VALUES('2003-02-31');
+select * from t1;
+col1
+2004-01-02
+0000-00-00
+2004-01-03
+0000-00-00
+2004-01-04
+0000-00-00
+2003-02-31
+drop table t1;
+set @@sql_mode='strict_trans_tables';
+CREATE TABLE t1 (col1 date) engine=innodb;
+INSERT INTO t1 VALUES('2004-13-31'),('2004-1-1');
+ERROR 22007: Incorrect date value: '2004-13-31' for column 'col1' at row 1
+INSERT INTO t1 VALUES ('2004-1-2'), ('2004-13-31'),('2004-1-3');
+ERROR 22007: Incorrect date value: '2004-13-31' for column 'col1' at row 2
+INSERT IGNORE INTO t1 VALUES('2004-13-31'),('2004-1-4');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT INTO t1 VALUES ('2003-02-29');
+ERROR 22007: Incorrect date value: '2003-02-29' for column 'col1' at row 1
+INSERT ignore INTO t1 VALUES('2003-02-30');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+set @@sql_mode='STRICT_ALL_TABLES,ALLOW_INVALID_DATES';
+INSERT ignore INTO t1 VALUES('2003-02-31');
+select * from t1;
+col1
+0000-00-00
+2004-01-04
+0000-00-00
+2003-02-31
+drop table t1;
+set @@sql_mode='ansi,traditional';
+CREATE TABLE t1 (col1 datetime);
+INSERT INTO t1 VALUES('2004-10-31 15:30:00'),('0000-10-31 15:30:00'),('2004-02-29 15:30:00');
+INSERT INTO t1 VALUES('2004-0-31 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-0-31 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-10-0 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-10-0 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-09-31 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-09-31 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-10-32 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-10-32 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2003-02-29 15:30:00');
+ERROR 22007: Incorrect datetime value: '2003-02-29 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-13-15 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-13-15 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('0000-00-00 15:30:00');
+ERROR 22007: Incorrect datetime value: '0000-00-00 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES ('59');
+ERROR 22007: Incorrect datetime value: '59' for column 'col1' at row 1
+select * from t1;
+col1
+2004-10-31 15:30:00
+0000-10-31 15:30:00
+2004-02-29 15:30:00
+drop table t1;
+CREATE TABLE t1 (col1 timestamp);
+INSERT INTO t1 VALUES('2004-10-31 15:30:00'),('2004-02-29 15:30:00');
+INSERT INTO t1 VALUES('0000-10-31 15:30:00');
+ERROR 22007: Incorrect datetime value: '0000-10-31 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-0-31 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-0-31 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-10-0 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-10-0 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-09-31 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-09-31 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-10-32 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-10-32 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2003-02-29 15:30:00');
+ERROR 22007: Incorrect datetime value: '2003-02-29 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-13-15 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-13-15 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-02-29 25:30:00');
+ERROR 22007: Incorrect datetime value: '2004-02-29 25:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-02-29 15:65:00');
+ERROR 22007: Incorrect datetime value: '2004-02-29 15:65:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-02-29 15:31:61');
+ERROR 22007: Incorrect datetime value: '2004-02-29 15:31:61' for column 'col1' at row 1
+INSERT INTO t1 VALUES('0000-00-00 15:30:00');
+ERROR 22007: Incorrect datetime value: '0000-00-00 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('0000-00-00 00:00:00');
+ERROR 22007: Incorrect datetime value: '0000-00-00 00:00:00' for column 'col1' at row 1
+INSERT IGNORE INTO t1 VALUES('0000-00-00 00:00:00');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT INTO t1 VALUES ('59');
+ERROR 22007: Incorrect datetime value: '59' for column 'col1' at row 1
+set @@sql_mode='STRICT_ALL_TABLES,ALLOW_INVALID_DATES';
+INSERT INTO t1 VALUES('2004-0-31 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-0-31 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-10-0 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-10-0 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-10-32 15:30:00');
+ERROR 22007: Incorrect datetime value: '2004-10-32 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 VALUES('2004-02-30 15:30:04');
+ERROR 22007: Incorrect datetime value: '2004-02-30 15:30:04' for column 'col1' at row 1
+INSERT INTO t1 VALUES('0000-00-00 00:00:00');
+set @@sql_mode='STRICT_ALL_TABLES,NO_ZERO_IN_DATE';
+INSERT INTO t1 VALUES('0000-00-00 00:00:00');
+set @@sql_mode='STRICT_ALL_TABLES,NO_ZERO_DATE';
+INSERT INTO t1 VALUES('0000-00-00 00:00:00');
+ERROR 22007: Incorrect datetime value: '0000-00-00 00:00:00' for column 'col1' at row 1
+set @@sql_mode='ansi,traditional';
+SELECT * FROM t1;
+col1
+2004-10-31 15:30:00
+2004-02-29 15:30:00
+0000-00-00 00:00:00
+0000-00-00 00:00:00
+0000-00-00 00:00:00
+DROP TABLE t1;
+CREATE TABLE t1 (col1 date, col2 datetime, col3 timestamp);
+INSERT INTO t1 (col1) VALUES (STR_TO_DATE('15.10.2004','%d.%m.%Y'));
+INSERT INTO t1 (col2) VALUES (STR_TO_DATE('15.10.2004 10.15','%d.%m.%Y %H.%i'));
+INSERT INTO t1 (col3) VALUES (STR_TO_DATE('15.10.2004 10.15','%d.%m.%Y %H.%i'));
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('31.10.0000 15.30','%d.%m.%Y %H.%i'));
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('31.0.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect date value: '2004-00-31 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('0.10.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect date value: '2004-10-00 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('31.9.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect date value: '2004-09-31 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR HY000: Incorrect datetime value: '32.10.2004 15.30' for function str_to_time
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('29.02.2003 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect date value: '2003-02-29 15:30:00' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('15.13.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR HY000: Incorrect datetime value: '15.13.2004 15.30' for function str_to_time
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('00.00.0000','%d.%m.%Y'));
+ERROR 22007: Incorrect date value: '0000-00-00' for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('31.10.0000 15.30','%d.%m.%Y %H.%i'));
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('31.0.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect datetime value: '2004-00-31 15:30:00' for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('0.10.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('31.9.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect datetime value: '2004-09-31 15:30:00' for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR HY000: Incorrect datetime value: '32.10.2004 15.30' for function str_to_time
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('29.02.2003 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect datetime value: '2003-02-29 15:30:00' for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('15.13.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR HY000: Incorrect datetime value: '15.13.2004 15.30' for function str_to_time
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('00.00.0000','%d.%m.%Y'));
+ERROR 22007: Incorrect datetime value: '0000-00-00' for column 'col2' at row 1
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('31.10.0000 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect datetime value: '0000-10-31 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('31.0.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect datetime value: '2004-00-31 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('0.10.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('31.9.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect datetime value: '2004-09-31 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR HY000: Incorrect datetime value: '32.10.2004 15.30' for function str_to_time
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('29.02.2003 15.30','%d.%m.%Y %H.%i'));
+ERROR 22007: Incorrect datetime value: '2003-02-29 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('15.13.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR HY000: Incorrect datetime value: '15.13.2004 15.30' for function str_to_time
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('00.00.0000','%d.%m.%Y'));
+ERROR 22007: Incorrect datetime value: '0000-00-00' for column 'col3' at row 1
+drop table t1;
+CREATE TABLE t1 (col1 date, col2 datetime, col3 timestamp);
+INSERT INTO t1 (col1) VALUES (CAST('2004-10-15' AS DATE));
+INSERT INTO t1 (col2) VALUES (CAST('2004-10-15 10:15' AS DATETIME));
+INSERT INTO t1 (col3) VALUES (CAST('2004-10-15 10:15' AS DATETIME));
+INSERT INTO t1 (col1) VALUES(CAST('0000-10-31' AS DATE));
+INSERT INTO t1 (col1) VALUES(CAST('2004-10-0' AS DATE));
+ERROR 22007: Incorrect date value: '2004-10-00' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(CAST('2004-0-10' AS DATE));
+ERROR 22007: Incorrect date value: '2004-00-10' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(CAST('0000-00-00' AS DATE));
+ERROR 22007: Truncated incorrect datetime value: '0000-00-00'
+INSERT INTO t1 (col2) VALUES(CAST('0000-10-31 15:30' AS DATETIME));
+INSERT INTO t1 (col2) VALUES(CAST('2004-10-0 15:30' AS DATETIME));
+ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(CAST('2004-0-10 15:30' AS DATETIME));
+ERROR 22007: Incorrect datetime value: '2004-00-10 15:30:00' for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(CAST('0000-00-00' AS DATETIME));
+ERROR 22007: Truncated incorrect datetime value: '0000-00-00'
+INSERT INTO t1 (col3) VALUES(CAST('0000-10-31 15:30' AS DATETIME));
+ERROR 22007: Incorrect datetime value: '0000-10-31 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(CAST('2004-10-0 15:30' AS DATETIME));
+ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(CAST('2004-0-10 15:30' AS DATETIME));
+ERROR 22007: Incorrect datetime value: '2004-00-10 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(CAST('0000-00-00' AS DATETIME));
+ERROR 22007: Truncated incorrect datetime value: '0000-00-00'
+drop table t1;
+CREATE TABLE t1 (col1 date, col2 datetime, col3 timestamp);
+INSERT INTO t1 (col1) VALUES (CONVERT('2004-10-15',DATE));
+INSERT INTO t1 (col2) VALUES (CONVERT('2004-10-15 10:15',DATETIME));
+INSERT INTO t1 (col3) VALUES (CONVERT('2004-10-15 10:15',DATETIME));
+INSERT INTO t1 (col1) VALUES(CONVERT('0000-10-31' , DATE));
+INSERT INTO t1 (col1) VALUES(CONVERT('2004-10-0' , DATE));
+ERROR 22007: Incorrect date value: '2004-10-00' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(CONVERT('2004-0-10' , DATE));
+ERROR 22007: Incorrect date value: '2004-00-10' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(CONVERT('0000-00-00',DATE));
+ERROR 22007: Truncated incorrect datetime value: '0000-00-00'
+INSERT INTO t1 (col2) VALUES(CONVERT('0000-10-31 15:30',DATETIME));
+INSERT INTO t1 (col2) VALUES(CONVERT('2004-10-0 15:30',DATETIME));
+ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(CONVERT('2004-0-10 15:30',DATETIME));
+ERROR 22007: Incorrect datetime value: '2004-00-10 15:30:00' for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(CONVERT('0000-00-00',DATETIME));
+ERROR 22007: Truncated incorrect datetime value: '0000-00-00'
+INSERT INTO t1 (col3) VALUES(CONVERT('0000-10-31 15:30',DATETIME));
+ERROR 22007: Incorrect datetime value: '0000-10-31 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(CONVERT('2004-10-0 15:30',DATETIME));
+ERROR 22007: Incorrect datetime value: '2004-10-00 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(CONVERT('2004-0-10 15:30',DATETIME));
+ERROR 22007: Incorrect datetime value: '2004-00-10 15:30:00' for column 'col3' at row 1
+INSERT INTO t1 (col3) VALUES(CONVERT('0000-00-00',DATETIME));
+ERROR 22007: Truncated incorrect datetime value: '0000-00-00'
+drop table t1;
+CREATE TABLE t1(col1 TINYINT, col2 TINYINT UNSIGNED);
+INSERT INTO t1 VALUES(-128,0),(0,0),(127,255),('-128','0'),('0','0'),('127','255'),(-128.0,0.0),(0.0,0.0),(127.0,255.0);
+SELECT MOD(col1,0) FROM t1 WHERE col1 > 0 LIMIT 2;
+MOD(col1,0)
+NULL
+NULL
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+INSERT INTO t1 (col1) VALUES(-129);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(128);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(-1);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(256);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES('-129');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES('128');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES('-1');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES('256');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES(128.0);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(-1.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(256.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+SELECT MOD(col1,0) FROM t1 WHERE col1 > 0 LIMIT 1;
+MOD(col1,0)
+NULL
+Warnings:
+Error 1365 Division by 0
+UPDATE t1 SET col1 = col1 - 50 WHERE col1 < 0;
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+UPDATE t1 SET col2=col2 + 50 WHERE col2 > 0;
+ERROR 22003: Out of range value adjusted for column 'col2' at row 3
+UPDATE t1 SET col1=col1 / 0 WHERE col1 > 0;
+ERROR 22012: Division by 0
+set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO';
+INSERT INTO t1 values (1/0,1/0);
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+set @@sql_mode='ansi,traditional';
+SELECT MOD(col1,0) FROM t1 WHERE col1 > 0 LIMIT 2;
+MOD(col1,0)
+NULL
+NULL
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+INSERT INTO t1 (col1) VALUES ('');
+ERROR HY000: Incorrect integer value: '' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('a59b');
+ERROR HY000: Incorrect integer value: 'a59b' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('1a');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 values (1/0,1/0);
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+set @@sql_mode='ansi';
+INSERT INTO t1 values (1/0,1/0);
+set @@sql_mode='ansi,traditional';
+INSERT IGNORE INTO t1 VALUES('-129','-1'),('128','256');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+INSERT IGNORE INTO t1 VALUES(-129.0,-1.0),(128.0,256.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+SELECT * FROM t1;
+col1 col2
+-128 0
+0 NULL
+127 255
+-128 0
+0 NULL
+127 255
+-128 0
+0 NULL
+127 255
+NULL NULL
+2 NULL
+NULL NULL
+NULL NULL
+-128 0
+127 255
+-128 0
+127 255
+DROP TABLE t1;
+CREATE TABLE t1(col1 SMALLINT, col2 SMALLINT UNSIGNED);
+INSERT INTO t1 VALUES(-32768,0),(0,0),(32767,65535),('-32768','0'),('32767','65535'),(-32768.0,0.0),(32767.0,65535.0);
+INSERT INTO t1 (col1) VALUES(-32769);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(32768);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(-1);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(65536);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES('-32769');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES('32768');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES('-1');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES('65536');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES(-32769.0);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(32768.0);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(-1.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(65536.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+UPDATE t1 SET col1 = col1 - 50 WHERE col1 < 0;
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+UPDATE t1 SET col2 = col2 + 50 WHERE col2 > 0;
+ERROR 22003: Out of range value adjusted for column 'col2' at row 3
+UPDATE t1 SET col1 = col1 / 0 WHERE col1 > 0;
+ERROR 22012: Division by 0
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+ERROR 22012: Division by 0
+INSERT INTO t1 (col1) VALUES ('');
+ERROR HY000: Incorrect integer value: '' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('a59b');
+ERROR HY000: Incorrect integer value: 'a59b' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('1a');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 values (1/0,1/0);
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+INSERT IGNORE INTO t1 VALUES(-32769,-1),(32768,65536);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+INSERT IGNORE INTO t1 VALUES('-32769','-1'),('32768','65536');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+INSERT IGNORE INTO t1 VALUES(-32769,-1.0),(32768.0,65536.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+SELECT * FROM t1;
+col1 col2
+-32768 0
+0 NULL
+32767 65535
+-32768 0
+32767 65535
+-32768 0
+32767 65535
+2 NULL
+NULL NULL
+-32768 0
+32767 65535
+-32768 0
+32767 65535
+-32768 0
+32767 65535
+DROP TABLE t1;
+CREATE TABLE t1 (col1 MEDIUMINT, col2 MEDIUMINT UNSIGNED);
+INSERT INTO t1 VALUES(-8388608,0),(0,0),(8388607,16777215),('-8388608','0'),('8388607','16777215'),(-8388608.0,0.0),(8388607.0,16777215.0);
+INSERT INTO t1 (col1) VALUES(-8388609);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(8388608);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(-1);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(16777216);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES('-8388609');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES('8388608');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES('-1');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES('16777216');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES(-8388609.0);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(8388608.0);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(-1.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(16777216.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+UPDATE t1 SET col1 = col1 - 50 WHERE col1 < 0;
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+UPDATE t1 SET col2 = col2 + 50 WHERE col2 > 0;
+ERROR 22003: Out of range value adjusted for column 'col2' at row 3
+UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0;
+ERROR 22012: Division by 0
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+ERROR 22012: Division by 0
+INSERT INTO t1 (col1) VALUES ('');
+ERROR HY000: Incorrect integer value: '' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('a59b');
+ERROR HY000: Incorrect integer value: 'a59b' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('1a');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 values (1/0,1/0);
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+INSERT IGNORE INTO t1 VALUES(-8388609,-1),(8388608,16777216);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+INSERT IGNORE INTO t1 VALUES('-8388609','-1'),('8388608','16777216');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+INSERT IGNORE INTO t1 VALUES(-8388609.0,-1.0),(8388608.0,16777216.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+SELECT * FROM t1;
+col1 col2
+-8388608 0
+0 NULL
+8388607 16777215
+-8388608 0
+8388607 16777215
+-8388608 0
+8388607 16777215
+2 NULL
+NULL NULL
+-8388608 0
+8388607 16777215
+-8388608 0
+8388607 16777215
+-8388608 0
+8388607 16777215
+DROP TABLE t1;
+CREATE TABLE t1 (col1 INT, col2 INT UNSIGNED);
+INSERT INTO t1 VALUES(-2147483648,0),(0,0),(2147483647,4294967295),('-2147483648','0'),('2147483647','4294967295'),(-2147483648.0,0.0),(2147483647.0,4294967295.0);
+INSERT INTO t1 (col1) VALUES(-2147483649);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(2147643648);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(-1);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(4294967296);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES('-2147483649');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES('2147643648');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES('-1');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES('4294967296');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES(-2147483649.0);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(2147643648.0);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(-1.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(4294967296.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+UPDATE t1 SET col1 = col1 - 50 WHERE col1 < 0;
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+UPDATE t1 SET col2 =col2 + 50 WHERE col2 > 0;
+ERROR 22003: Out of range value adjusted for column 'col2' at row 3
+UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0;
+ERROR 22012: Division by 0
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+ERROR 22012: Division by 0
+INSERT INTO t1 (col1) VALUES ('');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('a59b');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('1a');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 values (1/0,1/0);
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+INSERT IGNORE INTO t1 values (-2147483649, -1),(2147643648,4294967296);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+INSERT IGNORE INTO t1 values ('-2147483649', '-1'),('2147643648','4294967296');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+INSERT IGNORE INTO t1 values (-2147483649.0, -1.0),(2147643648.0,4294967296.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+SELECT * FROM t1;
+col1 col2
+-2147483648 0
+0 NULL
+2147483647 4294967295
+-2147483648 0
+2147483647 4294967295
+-2147483648 0
+2147483647 4294967295
+2 NULL
+NULL NULL
+-2147483648 0
+2147483647 4294967295
+-2147483648 0
+2147483647 4294967295
+-2147483648 0
+2147483647 4294967295
+DROP TABLE t1;
+CREATE TABLE t1 (col1 BIGINT, col2 BIGINT UNSIGNED);
+INSERT INTO t1 VALUES(-9223372036854775808,0),(0,0),(9223372036854775807,18446744073709551615);
+INSERT INTO t1 VALUES('-9223372036854775808','0'),('9223372036854775807','18446744073709551615');
+INSERT INTO t1 VALUES(-9223372036854774000.0,0.0),(9223372036854775700.0,1844674407370954000.0);
+INSERT INTO t1 (col1) VALUES(-9223372036854775809);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(9223372036854775808);
+INSERT INTO t1 (col2) VALUES(-1);
+INSERT INTO t1 (col2) VALUES(18446744073709551616);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES('-9223372036854775809');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES('9223372036854775808');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES('-1');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES('18446744073709551616');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES(-9223372036854785809.0);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES(9223372036854785808.0);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES(-1.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES(18446744073709551616.0);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0;
+ERROR 22012: Division by 0
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+ERROR 22012: Division by 0
+INSERT INTO t1 (col1) VALUES ('');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('a59b');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('1a');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 values (1/0,1/0);
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+INSERT IGNORE INTO t1 VALUES(-9223372036854775809,-1),(9223372036854775808,18446744073709551616);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+INSERT IGNORE INTO t1 VALUES('-9223372036854775809','-1'),('9223372036854775808','18446744073709551616');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+INSERT IGNORE INTO t1 VALUES(-9223372036854785809.0,-1.0),(9223372036854785808.0,18446744073709551616.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+Warning 1264 Out of range value adjusted for column 'col2' at row 2
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+SELECT * FROM t1;
+col1 col2
+-9223372036854775808 0
+0 NULL
+9223372036854775807 18446744073709551615
+-9223372036854775808 0
+9223372036854775807 18446744073709551615
+-9223372036854774000 0
+9223372036854775700 1844674407370954000
+-9223372036854775808 NULL
+NULL 18446744073709551615
+2 NULL
+NULL NULL
+-9223372036854775808 18446744073709551615
+-9223372036854775808 18446744073709551615
+-9223372036854775808 0
+9223372036854775807 18446744073709551615
+-9223372036854775808 0
+9223372036854775807 18446744073709551615
+DROP TABLE t1;
+CREATE TABLE t1 (col1 NUMERIC(4,2));
+INSERT INTO t1 VALUES (10.55),(10.5555),(0),(-10.55),(-10.5555),(11),(1e+01);
+Warnings:
+Note 1265 Data truncated for column 'col1' at row 2
+Note 1265 Data truncated for column 'col1' at row 5
+INSERT INTO t1 VALUES ('10.55'),('10.5555'),('-10.55'),('-10.5555'),('11'),('1e+01');
+Warnings:
+Note 1265 Data truncated for column 'col1' at row 2
+Note 1265 Data truncated for column 'col1' at row 4
+INSERT INTO t1 VALUES (101.55);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES (101);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES (-101.55);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES (1010.55);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES (1010);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES ('101.55');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES ('101');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES ('-101.55');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES ('-1010.55');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES ('-100E+1');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 VALUES ('-100E');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+UPDATE t1 SET col1 =col1 * 50000 WHERE col1 =11;
+ERROR 22003: Out of range value adjusted for column 'col1' at row 6
+UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0;
+ERROR 22012: Division by 0
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+ERROR 22012: Division by 0
+INSERT INTO t1 (col1) VALUES ('');
+ERROR HY000: Incorrect decimal value: '' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('a59b');
+ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('1a');
+Warnings:
+Note 1265 Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+Warnings:
+Note 1265 Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 values (1/0);
+Warnings:
+Error 1365 Division by 0
+INSERT IGNORE INTO t1 VALUES(1000),(-1000);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+INSERT IGNORE INTO t1 VALUES('1000'),('-1000');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+INSERT IGNORE INTO t1 VALUES(1000.0),(-1000.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+UPDATE IGNORE t1 SET col1=1/NULL where col1=0;
+SELECT * FROM t1;
+col1
+10.55
+10.56
+NULL
+-10.55
+-10.56
+11.00
+10.00
+10.55
+10.56
+-10.55
+-10.56
+11.00
+10.00
+1.00
+2.00
+NULL
+99.99
+-99.99
+99.99
+-99.99
+99.99
+-99.99
+DROP TABLE t1;
+CREATE TABLE t1 (col1 FLOAT, col2 FLOAT UNSIGNED);
+INSERT INTO t1 VALUES (-1.1E-37,0),(+3.4E+38,+3.4E+38);
+INSERT INTO t1 VALUES ('-1.1E-37',0),('+3.4E+38','+3.4E+38');
+INSERT INTO t1 (col1) VALUES (3E-46);
+INSERT INTO t1 (col1) VALUES (+3.4E+39);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES (-1.1E-3);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES ('+3.4E+39');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES ('-1.1E-3');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
+ERROR 22003: Out of range value adjusted for column 'col1' at row 2
+UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
+ERROR 22012: Division by 0
+UPDATE t1 SET col2= MOD(col2,0) WHERE col2 > 0;
+ERROR 22012: Division by 0
+INSERT INTO t1 (col1) VALUES ('');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('a59b');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('1a');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) VALUES (1/0);
+Warnings:
+Error 1365 Division by 0
+INSERT IGNORE INTO t1 VALUES (+3.4E+39,-3.4E+39);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+INSERT IGNORE INTO t1 VALUES ('+3.4E+39','-3.4E+39');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+SELECT * FROM t1;
+col1 col2
+-1.1e-37 0
+3.4e+38 3.4e+38
+-1.1e-37 0
+3.4e+38 3.4e+38
+0 NULL
+2 NULL
+NULL NULL
+3.40282e+38 0
+3.40282e+38 0
+DROP TABLE t1;
+CREATE TABLE t1 (col1 DOUBLE PRECISION, col2 DOUBLE PRECISION UNSIGNED);
+INSERT INTO t1 VALUES (-2.2E-307,0),(2E-307,0),(+1.7E+308,+1.7E+308);
+INSERT INTO t1 VALUES ('-2.2E-307',0),('-2E-307',0),('+1.7E+308','+1.7E+308');
+INSERT INTO t1 (col1) VALUES (-2.2E-330);
+INSERT INTO t1 (col1) VALUES (+1.7E+309);
+Got one of the listed errors
+INSERT INTO t1 (col2) VALUES (-1.1E-3);
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+INSERT INTO t1 (col1) VALUES ('+1.8E+309');
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES ('-1.2E-3');
+ERROR 22003: Out of range value adjusted for column 'col2' at row 1
+UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
+ERROR 22003: Out of range value adjusted for column 'col1' at row 3
+UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
+ERROR 22012: Division by 0
+UPDATE t1 SET col2= MOD(col2,0) WHERE col2 > 0;
+ERROR 22012: Division by 0
+INSERT INTO t1 (col1) VALUES ('');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('a59b');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('1a');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+INSERT IGNORE INTO t1 (col1) values (1/0);
+Warnings:
+Error 1365 Division by 0
+INSERT IGNORE INTO t1 VALUES (+1.9E+309,-1.9E+309);
+ERROR 22007: Illegal double '1.9E+309' value found during parsing
+INSERT IGNORE INTO t1 VALUES ('+2.0E+309','-2.0E+309');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+SELECT * FROM t1;
+col1 col2
+0 0
+1e-303 0
+1.7e+308 1.7e+308
+0 0
+-2e-307 0
+1.7e+308 1.7e+308
+0 NULL
+2 NULL
+NULL NULL
+1.79769313486232e+308 0
+DROP TABLE t1;
+CREATE TABLE t1 (col1 CHAR(5), col2 VARCHAR(6));
+INSERT INTO t1 VALUES ('hello', 'hello'),('he', 'he'),('hello ', 'hello ');
+INSERT INTO t1 (col1) VALUES ('hellobob');
+ERROR 22001: Data too long for column 'col1' at row 1
+INSERT INTO t1 (col2) VALUES ('hellobob');
+ERROR 22001: Data too long for column 'col2' at row 1
+INSERT INTO t1 (col2) VALUES ('hello ');
+Warnings:
+Note 1265 Data truncated for column 'col2' at row 1
+UPDATE t1 SET col1 ='hellobob' WHERE col1 ='he';
+ERROR 22001: Data too long for column 'col1' at row 2
+UPDATE t1 SET col2 ='hellobob' WHERE col2 ='he';
+ERROR 22001: Data too long for column 'col2' at row 2
+INSERT IGNORE INTO t1 VALUES ('hellobob', 'hellobob');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+Warning 1265 Data truncated for column 'col2' at row 1
+UPDATE IGNORE t1 SET col2 ='hellotrudy' WHERE col2 ='he';
+Warnings:
+Warning 1265 Data truncated for column 'col2' at row 2
+SELECT * FROM t1;
+col1 col2
+hello hello
+he hellot
+hello hello
+NULL hello
+hello hellob
+DROP TABLE t1;
+CREATE TABLE t1 (col1 enum('red','blue','green'));
+INSERT INTO t1 VALUES ('red'),('blue'),('green');
+INSERT INTO t1 (col1) VALUES ('yellow');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT INTO t1 (col1) VALUES ('redd');
+ERROR 01000: Data truncated for column 'col1' at row 1
+INSERT INTO t1 VALUES ('');
+ERROR 01000: Data truncated for column 'col1' at row 1
+UPDATE t1 SET col1 ='yellow' WHERE col1 ='green';
+ERROR 01000: Data truncated for column 'col1' at row 3
+INSERT IGNORE INTO t1 VALUES ('yellow');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+UPDATE IGNORE t1 SET col1 ='yellow' WHERE col1 ='blue';
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 2
+SELECT * FROM t1;
+col1
+red
+
+green
+
+DROP TABLE t1;
+CREATE TABLE t1 (col1 INT NOT NULL, col2 CHAR(5) NOT NULL, col3 DATE NOT NULL);
+INSERT INTO t1 VALUES (100, 'hello', '2004-08-20');
+INSERT INTO t1 (col1,col2,col3) VALUES (101, 'hell2', '2004-08-21');
+INSERT INTO t1 (col1,col2,col3) VALUES (NULL, '', '2004-01-01');
+ERROR 23000: Column 'col1' cannot be null
+INSERT INTO t1 (col1,col2,col3) VALUES (102, NULL, '2004-01-01');
+ERROR 23000: Column 'col2' cannot be null
+INSERT INTO t1 VALUES (103,'',NULL);
+ERROR 23000: Column 'col3' cannot be null
+UPDATE t1 SET col1=NULL WHERE col1 =100;
+ERROR 22004: Column set to default value; NULL supplied to NOT NULL column 'col1' at row 1
+UPDATE t1 SET col2 =NULL WHERE col2 ='hello';
+ERROR 22004: Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1
+UPDATE t1 SET col2 =NULL where col3 IS NOT NULL;
+ERROR 22004: Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1
+INSERT IGNORE INTO t1 values (NULL,NULL,NULL);
+Warnings:
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col1' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col3' at row 1
+SELECT * FROM t1;
+col1 col2 col3
+100 hello 2004-08-20
+101 hell2 2004-08-21
+0 0000-00-00
+DROP TABLE t1;
+CREATE TABLE t1 (col1 INT NOT NULL default 99, col2 CHAR(6) NOT NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE "t1" (
+ "col1" int(11) NOT NULL default '99',
+ "col2" char(6) NOT NULL
+)
+INSERT INTO t1 VALUES (1, 'hello');
+INSERT INTO t1 (col2) VALUES ('hello2');
+INSERT INTO t1 (col2) VALUES (NULL);
+ERROR 23000: Column 'col2' cannot be null
+INSERT INTO t1 (col1) VALUES (2);
+ERROR HY000: Field 'col2' doesn't have a default value
+INSERT INTO t1 VALUES(default(col1),default(col2));
+ERROR HY000: Field 'col2' doesn't have a default value
+INSERT INTO t1 (col1) SELECT 1;
+ERROR HY000: Field 'col2' doesn't have a default value
+INSERT INTO t1 SELECT 1,NULL;
+ERROR 22004: Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1
+INSERT IGNORE INTO t1 values (NULL,NULL);
+Warnings:
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col1' at row 1
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1
+INSERT IGNORE INTO t1 (col1) values (3);
+Warnings:
+Warning 1364 Field 'col2' doesn't have a default value
+INSERT IGNORE INTO t1 () values ();
+Warnings:
+Warning 1364 Field 'col2' doesn't have a default value
+SELECT * FROM t1;
+col1 col2
+1 hello
+99 hello2
+0
+3
+99
+DROP TABLE t1;
+set sql_mode='traditional';
+create table t1 (charcol char(255), varcharcol varchar(255),
+binarycol binary(255), varbinarycol varbinary(255), tinytextcol tinytext,
+tinyblobcol tinyblob);
+insert into t1 (charcol) values (repeat('x',256));
+ERROR 22001: Data too long for column 'charcol' at row 1
+insert into t1 (varcharcol) values (repeat('x',256));
+ERROR 22001: Data too long for column 'varcharcol' at row 1
+insert into t1 (binarycol) values (repeat('x',256));
+ERROR 22001: Data too long for column 'binarycol' at row 1
+insert into t1 (varbinarycol) values (repeat('x',256));
+ERROR 22001: Data too long for column 'varbinarycol' at row 1
+insert into t1 (tinytextcol) values (repeat('x',256));
+ERROR 22001: Data too long for column 'tinytextcol' at row 1
+insert into t1 (tinyblobcol) values (repeat('x',256));
+ERROR 22001: Data too long for column 'tinyblobcol' at row 1
+select * from t1;
+charcol varcharcol binarycol varbinarycol tinytextcol tinyblobcol
+drop table t1;
+set sql_mode='traditional';
+create table t1 (col1 datetime);
+insert into t1 values(STR_TO_DATE('31.10.2004 15.30 abc','%d.%m.%Y %H.%i'));
+ERROR 22007: Truncated incorrect datetime value: '31.10.2004 15.30 abc'
+insert into t1 values(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+ERROR HY000: Incorrect datetime value: '32.10.2004 15.30' for function str_to_time
+insert into t1 values(STR_TO_DATE('2004.12.12 22:22:33 AM','%Y.%m.%d %r'));
+ERROR HY000: Incorrect time value: '22:22:33 AM' for function str_to_time
+insert into t1 values(STR_TO_DATE('2004.12.12 abc','%Y.%m.%d %T'));
+ERROR HY000: Incorrect time value: 'abc' for function str_to_time
+set sql_mode='';
+insert into t1 values(STR_TO_DATE('31.10.2004 15.30 abc','%d.%m.%Y %H.%i'));
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '31.10.2004 15.30 abc'
+insert into t1 values(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+Warnings:
+Error 1411 Incorrect datetime value: '32.10.2004 15.30' for function str_to_time
+insert into t1 values(STR_TO_DATE('2004.12.12 22:22:33 AM','%Y.%m.%d %r'));
+Warnings:
+Error 1411 Incorrect time value: '22:22:33 AM' for function str_to_time
+insert into t1 values(STR_TO_DATE('2004.12.12 abc','%Y.%m.%d %T'));
+Warnings:
+Error 1411 Incorrect time value: 'abc' for function str_to_time
+insert into t1 values(STR_TO_DATE('31.10.2004 15.30','%d.%m.%Y %H.%i'));
+insert into t1 values(STR_TO_DATE('2004.12.12 11:22:33 AM','%Y.%m.%d %r'));
+insert into t1 values(STR_TO_DATE('2004.12.12 10:22:59','%Y.%m.%d %T'));
+select * from t1;
+col1
+2004-10-31 15:30:00
+NULL
+NULL
+NULL
+2004-10-31 15:30:00
+2004-12-12 11:22:33
+2004-12-12 10:22:59
+set sql_mode='traditional';
+select count(*) from t1 where STR_TO_DATE('2004.12.12 10:22:61','%Y.%m.%d %T') IS NULL;
+count(*)
+7
+Warnings:
+Error 1411 Incorrect datetime value: '2004.12.12 10:22:61' for function str_to_time
+Error 1411 Incorrect datetime value: '2004.12.12 10:22:61' for function str_to_time
+Error 1411 Incorrect datetime value: '2004.12.12 10:22:61' for function str_to_time
+drop table t1;
+create table t1 (col1 char(3), col2 integer);
+insert into t1 (col1) values (cast(1000 as char(3)));
+ERROR 22007: Truncated incorrect CHAR(3) value: '1000'
+insert into t1 (col1) values (cast(1000E+0 as char(3)));
+ERROR 22007: Truncated incorrect CHAR(3) value: '1000'
+insert into t1 (col1) values (cast(1000.0 as char(3)));
+ERROR 22007: Truncated incorrect CHAR(3) value: '1000.0'
+insert into t1 (col2) values (cast('abc' as signed integer));
+ERROR 22007: Truncated incorrect INTEGER value: 'abc'
+insert into t1 (col2) values (10E+0 + 'a');
+ERROR 22007: Truncated incorrect DOUBLE value: 'a'
+insert into t1 (col2) values (cast('10a' as unsigned integer));
+ERROR 22007: Truncated incorrect INTEGER value: '10a'
+insert into t1 (col2) values (cast('10' as unsigned integer));
+insert into t1 (col2) values (cast('10' as signed integer));
+insert into t1 (col2) values (10E+0 + '0 ');
+select * from t1;
+col1 col2
+NULL 10
+NULL 10
+NULL 10
+drop table t1;
+create table t1 (col1 date, col2 datetime, col3 timestamp);
+insert into t1 values (0,0,0);
+ERROR 22007: Incorrect date value: '0' for column 'col1' at row 1
+insert into t1 values (0.0,0.0,0.0);
+ERROR 22007: Incorrect date value: '0' for column 'col1' at row 1
+insert into t1 (col1) values (convert('0000-00-00',date));
+ERROR 22007: Truncated incorrect datetime value: '0000-00-00'
+insert into t1 (col1) values (cast('0000-00-00' as date));
+ERROR 22007: Truncated incorrect datetime value: '0000-00-00'
+set sql_mode='no_zero_date';
+insert into t1 values (0,0,0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1265 Data truncated for column 'col3' at row 1
+insert into t1 values (0.0,0.0,0.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col2' at row 1
+Warning 1265 Data truncated for column 'col3' at row 1
+drop table t1;
+set sql_mode='traditional';
+create table t1 (col1 date);
+insert ignore into t1 values ('0000-00-00');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+insert into t1 select * from t1;
+ERROR 22007: Incorrect date value: '0000-00-00' for column 'col1' at row 1
+insert ignore into t1 values ('0000-00-00');
+Warnings:
+Warning 1265 Data truncated for column 'col1' at row 1
+insert ignore into t1 (col1) values (cast('0000-00-00' as date));
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '0000-00-00'
+insert into t1 select * from t1;
+ERROR 22007: Incorrect date value: '0000-00-00' for column 'col1' at row 1
+alter table t1 modify col1 datetime;
+ERROR 22007: Incorrect datetime value: '0000-00-00' for column 'col1' at row 1
+alter ignore table t1 modify col1 datetime;
+Warnings:
+Warning 1264 Out of range value adjusted for column 'col1' at row 1
+Warning 1264 Out of range value adjusted for column 'col1' at row 2
+insert into t1 select * from t1;
+ERROR 22007: Incorrect datetime value: '0000-00-00 00:00:00' for column 'col1' at row 1
+select * from t1;
+col1
+0000-00-00 00:00:00
+0000-00-00 00:00:00
+NULL
+drop table t1;
+create table t1 (col1 tinyint);
+drop procedure if exists t1;
+Warnings:
+Note 1305 PROCEDURE t1 does not exist
+create procedure t1 () begin declare exit handler for sqlexception
+select'a'; insert into t1 values (200); end;|
+call t1();
+a
+a
+select * from t1;
+col1
+drop procedure t1;
+drop table t1;
+set sql_mode=@org_mode;
+SET @@sql_mode = 'traditional';
+CREATE TABLE t1 (i int not null);
+INSERT INTO t1 VALUES ();
+ERROR HY000: Field 'i' doesn't have a default value
+INSERT INTO t1 VALUES (DEFAULT);
+ERROR HY000: Field 'i' doesn't have a default value
+INSERT INTO t1 VALUES (DEFAULT(i));
+ERROR HY000: Field 'i' doesn't have a default value
+ALTER TABLE t1 ADD j int;
+INSERT INTO t1 SET j = 1;
+ERROR HY000: Field 'i' doesn't have a default value
+INSERT INTO t1 SET j = 1, i = DEFAULT;
+ERROR HY000: Field 'i' doesn't have a default value
+INSERT INTO t1 SET j = 1, i = DEFAULT(i);
+ERROR HY000: Field 'i' doesn't have a default value
+INSERT INTO t1 VALUES (DEFAULT,1);
+ERROR HY000: Field 'i' doesn't have a default value
+DROP TABLE t1;
+SET @@sql_mode = '';
+CREATE TABLE t1 (i int not null);
+INSERT INTO t1 VALUES ();
+Warnings:
+Warning 1364 Field 'i' doesn't have a default value
+INSERT INTO t1 VALUES (DEFAULT);
+Warnings:
+Warning 1364 Field 'i' doesn't have a default value
+INSERT INTO t1 VALUES (DEFAULT(i));
+ERROR HY000: Field 'i' doesn't have a default value
+ALTER TABLE t1 ADD j int;
+INSERT INTO t1 SET j = 1;
+Warnings:
+Warning 1364 Field 'i' doesn't have a default value
+INSERT INTO t1 SET j = 1, i = DEFAULT;
+Warnings:
+Warning 1364 Field 'i' doesn't have a default value
+INSERT INTO t1 SET j = 1, i = DEFAULT(i);
+ERROR HY000: Field 'i' doesn't have a default value
+INSERT INTO t1 VALUES (DEFAULT,1);
+Warnings:
+Warning 1364 Field 'i' doesn't have a default value
+DROP TABLE t1;
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 8f17f545d1a..fa5f27b7eed 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -50,7 +50,7 @@ id select_type table type possible_keys key key_len ref rows Extra
Warnings:
Note 1276 Field or reference 'a' of SELECT #3 was resolved in SELECT #1
Note 1276 Field or reference 'b.a' of SELECT #3 was resolved in SELECT #1
-Note 1003 select 1 AS `1` from (select 1 AS `a`) b having ((select b.a AS `a`) = 1)
+Note 1003 select 1 AS `1` from (select 1 AS `a`) `b` having ((select `b`.`a` AS `a`) = 1)
SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1;
1
1
@@ -117,15 +117,17 @@ SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'a');
SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'b');
(SELECT 1.5,2,'a') = ROW(1.5,2,'b')
0
-SELECT (SELECT 1.5,2,'a') = ROW('b',2,'b');
-(SELECT 1.5,2,'a') = ROW('b',2,'b')
+SELECT (SELECT 1.5,2,'a') = ROW('1.5b',2,'b');
+(SELECT 1.5,2,'a') = ROW('1.5b',2,'b')
0
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: '1.5b'
SELECT (SELECT 'b',2,'a') = ROW(1.5,2,'a');
(SELECT 'b',2,'a') = ROW(1.5,2,'a')
0
-SELECT (SELECT 1.5,2,'a') = ROW(1.5,'c','a');
-(SELECT 1.5,2,'a') = ROW(1.5,'c','a')
-0
+SELECT (SELECT 1.5,2,'a') = ROW(1.5,'2','a');
+(SELECT 1.5,2,'a') = ROW(1.5,'2','a')
+1
SELECT (SELECT 1.5,'c','a') = ROW(1.5,2,'a');
(SELECT 1.5,'c','a') = ROW(1.5,2,'a')
0
@@ -186,7 +188,7 @@ id select_type table type possible_keys key key_len ref rows Extra
4 SUBQUERY t2 ALL NULL NULL NULL NULL 2
NULL UNION RESULT <union1,3> ALL NULL NULL NULL NULL NULL
Warnings:
-Note 1003 (select test.t2.a AS `a`,test.t2.b AS `b` from test.t2 where (test.t2.b = (select test.t3.a AS `a` from test.t3 order by test.t3.a desc limit 1))) union (select test.t4.a AS `a`,test.t4.b AS `b` from test.t4 where (test.t4.b = (select (max(test.t2.a) * 4) AS `max(t2.a)*4` from test.t2)) order by a)
+Note 1003 (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`b` = (select `test`.`t3`.`a` AS `a` from `test`.`t3` order by 1 desc limit 1))) union (select `test`.`t4`.`a` AS `a`,`test`.`t4`.`b` AS `b` from `test`.`t4` where (`test`.`t4`.`b` = (select (max(`test`.`t2`.`a`) * 4) AS `max(t2.a)*4` from `test`.`t2`)) order by `a`)
select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2;
(select a from t3 where a<t2.a*4 order by 1 desc limit 1) a
3 1
@@ -202,7 +204,7 @@ id select_type table type possible_keys key key_len ref rows Extra
3 DERIVED t2 ALL NULL NULL NULL NULL 2 Using where
2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using where; Using filesort
Warnings:
-Note 1003 select (select test.t3.a AS `a` from test.t3 where (test.t3.a < 8) order by test.t3.a desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,tt.a AS `a` from (select test.t2.a AS `a`,test.t2.b AS `b` from test.t2 where (test.t2.a > 1)) tt
+Note 1003 select (select `test`.`t3`.`a` AS `a` from `test`.`t3` where (`test`.`t3`.`a` < 8) order by 1 desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,`tt`.`a` AS `a` from (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` > 1)) `tt`
select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1);
a
2
@@ -223,7 +225,7 @@ id select_type table type possible_keys key key_len ref rows Extra
3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using where
Warnings:
Note 1276 Field or reference 't4.a' of SELECT #3 was resolved in SELECT #1
-Note 1003 select test.t4.b AS `b`,(select avg((test.t2.a + (select min(test.t3.a) AS `min(t3.a)` from test.t3 where (test.t3.a >= test.t4.a)))) AS `avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a))` from test.t2) AS `(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2)` from test.t4
+Note 1003 select `test`.`t4`.`b` AS `b`,(select avg((`test`.`t2`.`a` + (select min(`test`.`t3`.`a`) AS `min(t3.a)` from `test`.`t3` where (`test`.`t3`.`a` >= `test`.`t4`.`a`)))) AS `avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a))` from `test`.`t2`) AS `(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2)` from `test`.`t4`
select * from t3 where exists (select * from t2 where t2.b=t3.a);
a
7
@@ -269,7 +271,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 ALL NULL NULL NULL NULL 3
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3 where <nop>((test.t3.a >= (select min(test.t2.b) from test.t2)))
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <nop>((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))
select * from t3 where a >= all (select b from t2);
a
7
@@ -313,7 +315,7 @@ NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
Warnings:
Note 1276 Field or reference 't2.a' of SELECT #2 was resolved in SELECT #1
Note 1276 Field or reference 't2.a' of SELECT #3 was resolved in SELECT #1
-Note 1003 select (select test.t1.a AS `a` from test.t1 where (test.t1.a = test.t2.a) union select test.t5.a AS `a` from test.t5 where (test.t5.a = test.t2.a)) AS `(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a)`,test.t2.a AS `a` from test.t2
+Note 1003 select (select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = `test`.`t2`.`a`) union select `test`.`t5`.`a` AS `a` from `test`.`t5` where (`test`.`t5`.`a` = `test`.`t2`.`a`)) AS `(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a)`,`test`.`t2`.`a` AS `a` from `test`.`t2`
select (select a from t1 where t1.a=t2.a union all select a from t5 where t5.a=t2.a), a from t2;
ERROR 21000: Subquery returns more than 1 row
create table t6 (patient_uq int, clinic_uq int, index i1 (clinic_uq));
@@ -331,7 +333,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DEPENDENT SUBQUERY t7 eq_ref PRIMARY PRIMARY 4 test.t6.clinic_uq 1 Using index
Warnings:
Note 1276 Field or reference 'clinic_uq' of SELECT #2 was resolved in SELECT #1
-Note 1003 select test.t6.patient_uq AS `patient_uq`,test.t6.clinic_uq AS `clinic_uq` from test.t6 where exists(select 1 AS `Not_used` from test.t7 where (test.t7.uq = test.t6.clinic_uq))
+Note 1003 select `test`.`t6`.`patient_uq` AS `patient_uq`,`test`.`t6`.`clinic_uq` AS `clinic_uq` from `test`.`t6` where exists(select 1 AS `Not_used` from `test`.`t7` where (`test`.`t6`.`clinic_uq` = `test`.`t7`.`uq`))
select * from t1 where a= (select a from t2,t4 where t2.b=t4.b);
ERROR 23000: Column 'a' in field list is ambiguous
drop table t1,t2,t3;
@@ -361,12 +363,12 @@ INSERT INTO t8 (pseudo,email) VALUES ('joce1','test1');
INSERT INTO t8 (pseudo,email) VALUES ('2joce1','2test1');
EXPLAIN EXTENDED SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce');
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t8 const PRIMARY PRIMARY 35 const 1 Using index
-4 SUBQUERY t8 const PRIMARY PRIMARY 35 1 Using index
-2 SUBQUERY t8 const PRIMARY PRIMARY 35 const 1
-3 SUBQUERY t8 const PRIMARY PRIMARY 35 1 Using index
+1 PRIMARY t8 ref PRIMARY PRIMARY 37 const 1 Using where; Using index
+4 SUBQUERY t8 ref PRIMARY PRIMARY 37 1 Using where; Using index
+2 SUBQUERY t8 ref PRIMARY PRIMARY 37 const 1 Using where
+3 SUBQUERY t8 ref PRIMARY PRIMARY 37 1 Using where; Using index
Warnings:
-Note 1003 select test.t8.pseudo AS `pseudo`,(select test.t8.email AS `email` from test.t8 where (test.t8.pseudo = (select test.t8.pseudo AS `pseudo` from test.t8 where (test.t8.pseudo = _latin1'joce')))) AS `(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'))` from test.t8 where (test.t8.pseudo = (select test.t8.pseudo AS `pseudo` from test.t8 where (test.t8.pseudo = _latin1'joce')))
+Note 1003 select `test`.`t8`.`pseudo` AS `pseudo`,(select `test`.`t8`.`email` AS `email` from `test`.`t8` where (`test`.`t8`.`pseudo` = (select `test`.`t8`.`pseudo` AS `pseudo` from `test`.`t8` where (`test`.`t8`.`pseudo` = _latin1'joce')))) AS `(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'))` from `test`.`t8` where (`test`.`t8`.`pseudo` = (select `test`.`t8`.`pseudo` AS `pseudo` from `test`.`t8` where (`test`.`t8`.`pseudo` = _latin1'joce')))
SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM
t8 WHERE pseudo='joce');
ERROR 21000: Operand should contain 1 column(s)
@@ -390,15 +392,15 @@ INSERT INTO t1 (topic,date,pseudo) VALUES
('43506','2002-10-02','joce'),('40143','2002-08-03','joce');
EXPLAIN EXTENDED SELECT DISTINCT date FROM t1 WHERE date='2002-08-03';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index NULL PRIMARY 41 NULL 2 Using where; Using index
+1 SIMPLE t1 index NULL PRIMARY 43 NULL 2 Using where; Using index
Warnings:
-Note 1003 select distinct test.t1.date AS `date` from test.t1 where (test.t1.date = 20020803)
+Note 1003 select distinct `test`.`t1`.`date` AS `date` from `test`.`t1` where (`test`.`t1`.`date` = 20020803)
EXPLAIN EXTENDED SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03');
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
-2 SUBQUERY t1 index NULL PRIMARY 41 NULL 2 Using where; Using index
+2 SUBQUERY t1 index NULL PRIMARY 43 NULL 2 Using where; Using index
Warnings:
-Note 1003 select (select distinct test.t1.date AS `date` from test.t1 where (test.t1.date = 20020803)) AS `(SELECT DISTINCT date FROM t1 WHERE date='2002-08-03')`
+Note 1003 select (select distinct `test`.`t1`.`date` AS `date` from `test`.`t1` where (`test`.`t1`.`date` = 20020803)) AS `(SELECT DISTINCT date FROM t1 WHERE date='2002-08-03')`
SELECT DISTINCT date FROM t1 WHERE date='2002-08-03';
date
2002-08-03
@@ -419,7 +421,7 @@ id select_type table type possible_keys key key_len ref rows Extra
3 UNION NULL NULL NULL NULL NULL NULL NULL No tables used
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
Warnings:
-Note 1003 select 1 AS `1` from test.t1
+Note 1003 select 1 AS `1` from `test`.`t1`
drop table t1;
CREATE TABLE `t1` (
`numeropost` mediumint(8) unsigned NOT NULL auto_increment,
@@ -539,13 +541,13 @@ EXPLAIN EXTENDED SELECT MAX(numreponse) FROM t1 WHERE numeropost='1';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
Warnings:
-Note 1003 select max(test.t1.numreponse) AS `MAX(numreponse)` from test.t1 where (test.t1.numeropost = _latin1'1')
+Note 1003 select max(`test`.`t1`.`numreponse`) AS `MAX(numreponse)` from `test`.`t1` where (`test`.`t1`.`numeropost` = _latin1'1')
EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1');
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 const PRIMARY,numreponse PRIMARY 7 const,const 1 Using index
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
Warnings:
-Note 1003 select test.t1.numreponse AS `numreponse` from test.t1 where ((test.t1.numeropost = _latin1'1') and (test.t1.numreponse = 3))
+Note 1003 select `test`.`t1`.`numreponse` AS `numreponse` from `test`.`t1` where ((`test`.`t1`.`numreponse` = (select max(`test`.`t1`.`numreponse`) AS `MAX(numreponse)` from `test`.`t1` where (`test`.`t1`.`numeropost` = _latin1'1'))) and (`test`.`t1`.`numeropost` = _latin1'1'))
drop table t1;
CREATE TABLE t1 (a int(1));
INSERT INTO t1 VALUES (1);
@@ -652,6 +654,14 @@ x
3
3
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
+select * from t1;
+x
+1
+2
+3
+3
+11
+11
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2));
ERROR 42S22: Unknown column 'x' in 'field list'
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
@@ -713,7 +723,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ref id id 5 const 1 Using where; Using index
Warnings:
Note 1249 Select 2 was reduced during optimization
-Note 1003 select test.t2.id AS `id` from test.t2 where (test.t2.id = 1)
+Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = 1)
SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3);
id
1
@@ -726,7 +736,7 @@ id select_type table type possible_keys key key_len ref rows Extra
Warnings:
Note 1249 Select 3 was reduced during optimization
Note 1249 Select 2 was reduced during optimization
-Note 1003 select test.t2.id AS `id` from test.t2 where (test.t2.id = (1 + 1))
+Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where (`test`.`t2`.`id` = (1 + 1))
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL id 5 NULL 2 Using where; Using index
@@ -734,7 +744,7 @@ id select_type table type possible_keys key key_len ref rows Extra
3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL No tables used
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
Warnings:
-Note 1003 select test.t2.id AS `id` from test.t2 where <in_optimizer>(test.t2.id,<exists>(select 1 AS `Not_used` having (<cache>(test.t2.id) = <null_helper>(1)) union select 1 AS `Not_used` having (<cache>(test.t2.id) = <null_helper>(3))))
+Note 1003 select `test`.`t2`.`id` AS `id` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`id`,<exists>(select 1 AS `Not_used` having (<cache>(`test`.`t2`.`id`) = <null_helper>(1)) union select 1 AS `Not_used` having (<cache>(`test`.`t2`.`id`) = <null_helper>(3))))
SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 3);
id
SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2);
@@ -860,7 +870,7 @@ id select_type table type possible_keys key key_len ref rows Extra
Warnings:
Note 1276 Field or reference 'a' of SELECT #2 was resolved in SELECT #1
Note 1249 Select 2 was reduced during optimization
-Note 1003 select (test.t1.a + 1) AS `(select a+1)` from test.t1
+Note 1003 select (`test`.`t1`.`a` + 1) AS `(select a+1)` from `test`.`t1`
select (select a+1) from t1;
(select a+1)
2.5
@@ -882,7 +892,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index
2 DEPENDENT SUBQUERY t2 index_subquery a a 5 func 2 Using index
Warnings:
-Note 1003 select test.t1.a AS `a`,<in_optimizer>(test.t1.a,<exists>(<index_lookup>(<cache>(test.t1.a) in t2 on a chicking NULL))) AS `t1.a in (select t2.a from t2)` from test.t1
+Note 1003 select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in t2 on a checking NULL))) AS `t1.a in (select t2.a from t2)` from `test`.`t1`
CREATE TABLE t3 (a int(11) default '0');
INSERT INTO t3 VALUES (1),(2),(3);
SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
@@ -897,7 +907,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 func 2 Using where; Using index
2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using where
Warnings:
-Note 1003 select test.t1.a AS `a`,<in_optimizer>(test.t1.a,<exists>(select 1 AS `Not_used` from test.t2 join test.t3 where ((test.t3.a = test.t2.a) and ((<cache>(test.t1.a) = test.t2.a) or isnull(test.t2.a))) having <is_not_null_test>(test.t2.a))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from test.t1
+Note 1003 select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(select 1 AS `Not_used` from `test`.`t2` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t2`.`a`) and ((<cache>(`test`.`t1`.`a`) = `test`.`t2`.`a`) or isnull(`test`.`t2`.`a`))) having <is_not_null_test>(`test`.`t2`.`a`))) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from `test`.`t1`
drop table t1,t2,t3;
create table t1 (a float);
select 10.5 IN (SELECT * from t1 LIMIT 1);
@@ -1009,19 +1019,19 @@ 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 rand() AS `RAND()` from test.t1) AS `(SELECT RAND() FROM t1)` from test.t1
+Note 1003 select sql_no_cache (select sql_no_cache rand() AS `RAND()` from `test`.`t1`) AS `(SELECT RAND() FROM t1)` from `test`.`t1`
EXPLAIN EXTENDED SELECT (SELECT ENCRYPT('test') 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
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 ecrypt(_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
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 benchmark(1,1) AS `BENCHMARK(1,1)` from test.t1) AS `(SELECT BENCHMARK(1,1) FROM t1)` from test.t1
+Note 1003 select sql_no_cache (select sql_no_cache benchmark(1,1) AS `BENCHMARK(1,1)` from `test`.`t1`) AS `(SELECT BENCHMARK(1,1) FROM t1)` from `test`.`t1`
drop table t1;
CREATE TABLE `t1` (
`mot` varchar(30) character set latin1 NOT NULL default '',
@@ -1116,7 +1126,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 3
3 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 3
Warnings:
-Note 1003 select sql_no_cache test.t1.a AS `a`,(select sql_no_cache (select sql_no_cache rand() AS `rand()` from test.t1 limit 1) AS `(select rand() from t1 limit 1)` from test.t1 limit 1) AS `(select (select rand() from t1 limit 1) from t1 limit 1)` from test.t1
+Note 1003 select sql_no_cache `test`.`t1`.`a` AS `a`,(select sql_no_cache (select sql_no_cache rand() AS `rand()` from `test`.`t1` limit 1) AS `(select rand() from t1 limit 1)` from `test`.`t1` limit 1) AS `(select (select rand() from t1 limit 1) from t1 limit 1)` from `test`.`t1`
drop table t1;
select t1.Continent, t2.Name, t2.Population from t1 LEFT JOIN t2 ON t1.Code = t2.Country where t2.Population IN (select max(t2.Population) AS Population from t2, t1 where t2.Country = t1.Code group by Continent);
ERROR 42S02: Table 'test.t1' doesn't exist
@@ -1170,7 +1180,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
Warnings:
-Note 1003 select <in_optimizer>(0,<exists>(select 1 AS `Not_used` from test.t1 a)) AS `0 IN (SELECT 1 FROM t1 a)`
+Note 1003 select <in_optimizer>(0,<exists>(select 1 AS `Not_used` from `test`.`t1` `a`)) AS `0 IN (SELECT 1 FROM t1 a)`
INSERT INTO t1 (pseudo) VALUES ('test1');
SELECT 0 IN (SELECT 1 FROM t1 a);
0 IN (SELECT 1 FROM t1 a)
@@ -1180,7 +1190,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
Warnings:
-Note 1003 select <in_optimizer>(0,<exists>(select 1 AS `Not_used` from test.t1 a)) AS `0 IN (SELECT 1 FROM t1 a)`
+Note 1003 select <in_optimizer>(0,<exists>(select 1 AS `Not_used` from `test`.`t1` `a`)) AS `0 IN (SELECT 1 FROM t1 a)`
drop table t1;
CREATE TABLE `t1` (
`i` int(11) NOT NULL default '0',
@@ -1225,7 +1235,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ref salary salary 5 const 1 Using where
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
Warnings:
-Note 1003 select test.t1.id AS `id` from test.t1 where (test.t1.salary = (select max(test.t1.salary) AS `MAX(salary)` from test.t1))
+Note 1003 select `test`.`t1`.`id` AS `id` from `test`.`t1` where (`test`.`t1`.`salary` = (select max(`test`.`t1`.`salary`) AS `MAX(salary)` from `test`.`t1`))
drop table t1;
CREATE TABLE t1 (
ID int(10) unsigned NOT NULL auto_increment,
@@ -1287,7 +1297,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using index
Warnings:
-Note 1003 select test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<primary_index_lookup>(<cache>(test.t2.a) in t1 on PRIMARY)))
+Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY)))
select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
a
2
@@ -1297,7 +1307,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using index; Using where
Warnings:
-Note 1003 select test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<primary_index_lookup>(<cache>(test.t2.a) in t1 on PRIMARY where (test.t1.b <> 30))))
+Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<primary_index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on PRIMARY where (`test`.`t1`.`b` <> 30))))
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
a
2
@@ -1308,7 +1318,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where
2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 Using where; Using index
Warnings:
-Note 1003 select test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(select 1 AS `Not_used` from test.t1 join test.t3 where ((test.t1.b = test.t3.a) and (<cache>(test.t2.a) = test.t1.a))))
+Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(select 1 AS `Not_used` from `test`.`t1` join `test`.`t3` where ((`test`.`t3`.`a` = `test`.`t1`.`b`) and (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`))))
drop table t1, t2, t3;
create table t1 (a int, b int, index a (a,b));
create table t2 (a int, index a (a));
@@ -1326,7 +1336,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 1001 Using index
Warnings:
-Note 1003 select test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<index_lookup>(<cache>(test.t2.a) in t1 on a)))
+Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on a)))
select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
a
2
@@ -1336,7 +1346,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 1001 Using index; Using where
Warnings:
-Note 1003 select test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<index_lookup>(<cache>(test.t2.a) in t1 on a where (test.t1.b <> 30))))
+Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on a where (`test`.`t1`.`b` <> 30))))
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
a
2
@@ -1344,10 +1354,10 @@ a
explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
-2 DEPENDENT SUBQUERY t1 ref a a 5 func 1001 Using where; Using index
-2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using where; Using index
+2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using index
+2 DEPENDENT SUBQUERY t1 ref a a 10 func,test.t3.a 1167 Using where; Using index
Warnings:
-Note 1003 select test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(select 1 AS `Not_used` from test.t1 join test.t3 where ((test.t1.b = test.t3.a) and (<cache>(test.t2.a) = test.t1.a))))
+Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(select 1 AS `Not_used` from `test`.`t1` join `test`.`t3` where ((`test`.`t1`.`b` = `test`.`t3`.`a`) and (<cache>(`test`.`t2`.`a`) = `test`.`t1`.`a`))))
insert into t1 values (3,31);
select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
a
@@ -1363,7 +1373,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 1001 Using index; Using where
Warnings:
-Note 1003 select test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<index_lookup>(<cache>(test.t2.a) in t1 on a where (test.t1.b <> 30))))
+Note 1003 select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t2`.`a`) in t1 on a where (`test`.`t1`.`b` <> 30))))
drop table t1, t2, t3;
create table t1 (a int, b int);
create table t2 (a int, b int);
@@ -1420,7 +1430,7 @@ explain extended (select * from t1);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
Warnings:
-Note 1003 (select test.t1.s1 AS `s1` from test.t1)
+Note 1003 (select `test`.`t1`.`s1` AS `s1` from `test`.`t1`)
(select * from t1);
s1
tttt
@@ -1454,25 +1464,25 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 Using index
2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index
Warnings:
-Note 1003 select test.t1.s1 AS `s1`,not(<in_optimizer>(test.t1.s1,<exists>(<index_lookup>(<cache>(test.t1.s1) in t2 on s1 chicking NULL)))) AS `s1 NOT IN (SELECT s1 FROM t2)` from test.t1
+Note 1003 select `test`.`t1`.`s1` AS `s1`,not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL)))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 Using index
2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index
Warnings:
-Note 1003 select test.t1.s1 AS `s1`,<in_optimizer>(test.t1.s1,<exists>(<index_lookup>(<cache>(test.t1.s1) in t2 on s1 chicking NULL))) AS `s1 = ANY (SELECT s1 FROM t2)` from test.t1
+Note 1003 select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 Using index
2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index
Warnings:
-Note 1003 select test.t1.s1 AS `s1`,not(<in_optimizer>(test.t1.s1,<exists>(<index_lookup>(<cache>(test.t1.s1) in t2 on s1 chicking NULL)))) AS `s1 <> ALL (SELECT s1 FROM t2)` from test.t1
+Note 1003 select `test`.`t1`.`s1` AS `s1`,not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL)))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1`
explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 Using index
2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 1 Using index; Using where
Warnings:
-Note 1003 select test.t1.s1 AS `s1`,not(<in_optimizer>(test.t1.s1,<exists>(<index_lookup>(<cache>(test.t1.s1) in t2 on s1 chicking NULL where (test.t2.s1 < _latin1'a2'))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from test.t1
+Note 1003 select `test`.`t1`.`s1` AS `s1`,not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL where (`test`.`t2`.`s1` < _latin1'a2'))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1`
drop table t1,t2;
create table t2 (a int, b int);
create table t3 (a int);
@@ -1487,7 +1497,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3 where <not>((test.t3.a < (select max(test.t2.b) from test.t2)))
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <not>((`test`.`t3`.`a` < (select max(`test`.`t2`.`b`) from `test`.`t2`)))
select * from t3 where a >= some (select b from t2);
a
explain extended select * from t3 where a >= some (select b from t2);
@@ -1495,7 +1505,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3 where <nop>((test.t3.a >= (select min(test.t2.b) from test.t2)))
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <nop>((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))
select * from t3 where a >= all (select b from t2 group by 1);
a
6
@@ -1506,7 +1516,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3 where <not>((test.t3.a < <max>(select test.t2.b AS `b` from test.t2 group by test.t2.b)))
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <not>((`test`.`t3`.`a` < <max>(select `test`.`t2`.`b` AS `b` from `test`.`t2` group by 1)))
select * from t3 where a >= some (select b from t2 group by 1);
a
explain extended select * from t3 where a >= some (select b from t2 group by 1);
@@ -1514,7 +1524,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3 where <nop>((test.t3.a >= <min>(select test.t2.b AS `b` from test.t2 group by test.t2.b)))
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <nop>((`test`.`t3`.`a` >= <min>(select `test`.`t2`.`b` AS `b` from `test`.`t2` group by 1)))
select * from t3 where NULL >= any (select b from t2);
a
explain extended select * from t3 where NULL >= any (select b from t2);
@@ -1522,7 +1532,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3`
select * from t3 where NULL >= any (select b from t2 group by 1);
a
explain extended select * from t3 where NULL >= any (select b from t2 group by 1);
@@ -1530,7 +1540,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3`
select * from t3 where NULL >= some (select b from t2);
a
explain extended select * from t3 where NULL >= some (select b from t2);
@@ -1538,7 +1548,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3`
select * from t3 where NULL >= some (select b from t2 group by 1);
a
explain extended select * from t3 where NULL >= some (select b from t2 group by 1);
@@ -1546,7 +1556,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3`
insert into t2 values (2,2), (2,1), (3,3), (3,1);
select * from t3 where a > all (select max(b) from t2 group by a);
a
@@ -1557,7 +1567,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
Warnings:
-Note 1003 select test.t3.a AS `a` from test.t3 where <not>((test.t3.a <= <max>(select max(test.t2.b) AS `max(b)` from test.t2 group by test.t2.a)))
+Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where <not>((`test`.`t3`.`a` <= <max>(select max(`test`.`t2`.`b`) AS `max(b)` from `test`.`t2` group by `test`.`t2`.`a`)))
drop table t2, t3;
CREATE TABLE `t1` ( `id` mediumint(9) NOT NULL auto_increment, `taskid` bigint(20) NOT NULL default '0', `dbid` int(11) NOT NULL default '0', `create_date` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `t1` (`id`, `taskid`, `dbid`, `create_date`,`last_update`) VALUES (1, 1, 15, '2003-09-29 10:31:36', '2003-09-29 10:31:36'), (2, 1, 21, now(), now());
@@ -1590,6 +1600,8 @@ insert into t1 values (2);
set sort_buffer_size = (select s1 from t1);
ERROR 21000: Subquery returns more than 1 row
do (select * from t1);
+Warnings:
+Error 1242 Subquery returns more than 1 row
drop table t1;
create table t1 (s1 char);
insert into t1 values ('e');
@@ -1606,7 +1618,7 @@ id select_type table type possible_keys key key_len ref rows Extra
3 UNION t1 system NULL NULL NULL NULL 1
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
Warnings:
-Note 1003 select test.t1.s1 AS `s1` from test.t1
+Note 1003 select `test`.`t1`.`s1` AS `s1` from `test`.`t1`
drop table t1;
CREATE TABLE t1 (number char(11) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1;
INSERT INTO t1 VALUES ('69294728265'),('18621828126'),('89356874041'),('95895001874');
@@ -1725,14 +1737,14 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 12 Using where
2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using index; Using where
Warnings:
-Note 1003 select test.t1.id AS `id`,test.t1.text AS `text` from test.t1 where not(<in_optimizer>(test.t1.id,<exists>(<primary_index_lookup>(<cache>(test.t1.id) in t1 on PRIMARY where (test.t1.id < 8)))))
+Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `test`.`t1` where not(<in_optimizer>(`test`.`t1`.`id`,<exists>(<primary_index_lookup>(<cache>(`test`.`t1`.`id`) in t1 on PRIMARY where (`test`.`t1`.`id` < 8)))))
explain extended select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY tt ALL NULL NULL NULL NULL 12 Using where
-2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 test.tt.id 7 Using where; Using index
+2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 test.tt.id 1 Using where; Using index
Warnings:
Note 1276 Field or reference 'tt.id' of SELECT #2 was resolved in SELECT #1
-Note 1003 select test.tt.id AS `id`,test.tt.text AS `text` from test.t1 tt where not(exists(select test.t1.id AS `id` from test.t1 where ((test.t1.id < 8) and ((test.t1.id = test.tt.id) or isnull(test.t1.id))) having (test.t1.id is not null)))
+Note 1003 select `test`.`tt`.`id` AS `id`,`test`.`tt`.`text` AS `text` from `test`.`t1` `tt` where not(exists(select `test`.`t1`.`id` AS `id` from `test`.`t1` where ((`test`.`t1`.`id` < 8) and (`test`.`tt`.`id` = `test`.`t1`.`id`)) having (`test`.`t1`.`id` is not null)))
insert into t1 (id, text) values (1000, 'text1000'), (1001, 'text1001');
create table t2 (id int not null, text varchar(20) not null default '', primary key (id));
insert into t2 (id, text) values (1, 'text1'), (2, 'text2'), (3, 'text3'), (4, 'text4'), (5, 'text5'), (6, 'text6'), (7, 'text7'), (8, 'text8'), (9, 'text9'), (10, 'text10'), (11, 'text1'), (12, 'text2'), (13, 'text3'), (14, 'text4'), (15, 'text5'), (16, 'text6'), (17, 'text7'), (18, 'text8'), (19, 'text9'), (20, 'text10'),(21, 'text1'), (22, 'text2'), (23, 'text3'), (24, 'text4'), (25, 'text5'), (26, 'text6'), (27, 'text7'), (28, 'text8'), (29, 'text9'), (30, 'text10'), (31, 'text1'), (32, 'text2'), (33, 'text3'), (34, 'text4'), (35, 'text5'), (36, 'text6'), (37, 'text7'), (38, 'text8'), (39, 'text9'), (40, 'text10'), (41, 'text1'), (42, 'text2'), (43, 'text3'), (44, 'text4'), (45, 'text5'), (46, 'text6'), (47, 'text7'), (48, 'text8'), (49, 'text9'), (50, 'text10');
@@ -1758,7 +1770,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE b eq_ref PRIMARY PRIMARY 4 test.a.id 2
1 SIMPLE c eq_ref PRIMARY PRIMARY 4 func 1 Using where
Warnings:
-Note 1003 select test.a.id AS `id`,test.a.text AS `text`,test.b.id AS `id`,test.b.text AS `text`,test.c.id AS `id`,test.c.text AS `text` from test.t1 a left join test.t2 b on(((test.a.id = test.b.id) or isnull(test.b.id))) join test.t1 c where (if(isnull(test.b.id),1000,test.b.id) = test.c.id)
+Note 1003 select `test`.`a`.`id` AS `id`,`test`.`a`.`text` AS `text`,`test`.`b`.`id` AS `id`,`test`.`b`.`text` AS `text`,`test`.`c`.`id` AS `id`,`test`.`c`.`text` AS `text` from `test`.`t1` `a` left join `test`.`t2` `b` on(((`test`.`b`.`id` = `test`.`a`.`id`) or isnull(`test`.`b`.`id`))) join `test`.`t1` `c` where (if(isnull(`test`.`b`.`id`),1000,`test`.`b`.`id`) = `test`.`c`.`id`)
drop table t1,t2;
create table t1 (a int);
insert into t1 values (1);
@@ -2260,7 +2272,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using where
Warnings:
Note 1276 Field or reference 'up.a' of SELECT #2 was resolved in SELECT #1
-Note 1003 select test.up.a AS `a`,test.up.b AS `b` from test.t1 up where exists(select 1 AS `Not_used` from test.t1 where (test.t1.a = test.up.a))
+Note 1003 select `test`.`up`.`a` AS `a`,`test`.`up`.`b` AS `b` from `test`.`t1` `up` where exists(select 1 AS `Not_used` from `test`.`t1` where (`test`.`up`.`a` = `test`.`t1`.`a`))
drop table t1;
CREATE TABLE t1 (t1_a int);
INSERT INTO t1 VALUES (1);
@@ -2697,3 +2709,75 @@ select (1,2,3) = (select * from t1);
ERROR 21000: Operand should contain 3 column(s)
select (select * from t1) = (1,2,3);
ERROR 21000: Operand should contain 2 column(s)
+drop table t1;
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select * from t1 where df <= all (select avg(df) from t1 group by df);
+df
+1.1
+select * from t1 where df >= all (select avg(df) from t1 group by df);
+df
+2.2
+drop table t1;
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+select 1.1 * exists(select * from t1);
+1.1 * exists(select * from t1)
+1.1
+drop table t1;
+CREATE TABLE t1 (
+grp int(11) default NULL,
+a decimal(10,2) default NULL);
+insert into t1 values (1, 1), (2, 2), (2, 3), (3, 4), (3, 5), (3, 6), (NULL, NULL);
+select * from t1;
+grp a
+1 1.00
+2 2.00
+2 3.00
+3 4.00
+3 5.00
+3 6.00
+NULL NULL
+select min(a) from t1 group by grp;
+min(a)
+NULL
+1.00
+2.00
+4.00
+drop table t1;
+CREATE table t1 ( c1 integer );
+INSERT INTO t1 VALUES ( 1 );
+INSERT INTO t1 VALUES ( 2 );
+INSERT INTO t1 VALUES ( 3 );
+CREATE TABLE t2 ( c2 integer );
+INSERT INTO t2 VALUES ( 1 );
+INSERT INTO t2 VALUES ( 4 );
+INSERT INTO t2 VALUES ( 5 );
+SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2 WHERE c2 IN (1);
+c1 c2
+1 1
+SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2
+WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2 IN ( 1 ) );
+c1 c2
+1 1
+DROP TABLE t1,t2;
+CREATE TABLE t1 ( c1 integer );
+INSERT INTO t1 VALUES ( 1 );
+INSERT INTO t1 VALUES ( 2 );
+INSERT INTO t1 VALUES ( 3 );
+INSERT INTO t1 VALUES ( 6 );
+CREATE TABLE t2 ( c2 integer );
+INSERT INTO t2 VALUES ( 1 );
+INSERT INTO t2 VALUES ( 4 );
+INSERT INTO t2 VALUES ( 5 );
+INSERT INTO t2 VALUES ( 6 );
+CREATE TABLE t3 ( c3 integer );
+INSERT INTO t3 VALUES ( 7 );
+INSERT INTO t3 VALUES ( 8 );
+SELECT c1,c2 FROM t1 LEFT JOIN t2 ON c1 = c2
+WHERE EXISTS (SELECT c3 FROM t3 WHERE c2 IS NULL );
+c1 c2
+2 NULL
+3 NULL
+DROP TABLE t1,t2,t3;
diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result
index b04fec26c6f..210ac0a8cc3 100644
--- a/mysql-test/r/subselect2.result
+++ b/mysql-test/r/subselect2.result
@@ -122,10 +122,10 @@ EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JO
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system PRIMARY NULL NULL NULL 0 const row not found
1 PRIMARY t2 ALL DDOCTYPEID_IDX NULL NULL NULL 9 Using where
-1 PRIMARY t4 eq_ref PRIMARY PRIMARY 32 test.t2.DOCTYPEID 1
-2 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 32 func 1 Using index; Using where
-3 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 32 func 1 Using index; Using where
-4 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 32 func 1 Using index; Using where
-5 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 32 func 1 Using index; Using where
-6 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 32 func 1 Using index; Using where
+1 PRIMARY t4 eq_ref PRIMARY PRIMARY 34 test.t2.DOCTYPEID 1
+2 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where
+3 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where
+4 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where
+5 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 34 func 1 Using index; Using where
+6 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 34 func 1 Using index; Using where
drop table t1, t2, t3, t4;
diff --git a/mysql-test/r/sum_distinct-big.result b/mysql-test/r/sum_distinct-big.result
new file mode 100644
index 00000000000..06bfc6b1f78
--- /dev/null
+++ b/mysql-test/r/sum_distinct-big.result
@@ -0,0 +1,108 @@
+using_big_test
+0
+CREATE TABLE t1 (id INTEGER);
+CREATE TABLE t2 (id INTEGER);
+INSERT INTO t1 (id) VALUES (1), (1), (1),(1);
+INSERT INTO t1 (id) SELECT id FROM t1;
+/* 8 */
+INSERT INTO t1 (id) SELECT id FROM t1;
+/* 12 */
+INSERT INTO t1 (id) SELECT id FROM t1;
+/* 16 */
+INSERT INTO t1 (id) SELECT id FROM t1;
+/* 20 */
+INSERT INTO t1 (id) SELECT id FROM t1;
+/* 24 */
+INSERT INTO t1 SELECT id+1 FROM t1;
+INSERT INTO t1 SELECT id+2 FROM t1;
+INSERT INTO t1 SELECT id+4 FROM t1;
+INSERT INTO t1 SELECT id+8 FROM t1;
+INSERT INTO t1 SELECT id+16 FROM t1;
+INSERT INTO t1 SELECT id+32 FROM t1;
+INSERT INTO t1 SELECT id+64 FROM t1;
+INSERT INTO t1 SELECT id+128 FROM t1;
+INSERT INTO t1 SELECT id+256 FROM t1;
+INSERT INTO t1 SELECT id+512 FROM t1;
+SELECT AVG(DISTINCT id) FROM t1 GROUP BY id % 13;
+AVG(DISTINCT id)
+513.5000
+508.0000
+509.0000
+510.0000
+511.0000
+512.0000
+513.0000
+514.0000
+515.0000
+516.0000
+517.0000
+511.5000
+512.5000
+SELECT SUM(DISTINCT id)/COUNT(DISTINCT id) FROM t1 GROUP BY id % 13;
+SUM(DISTINCT id)/COUNT(DISTINCT id)
+513.50000
+508.00000
+509.00000
+510.00000
+511.00000
+512.00000
+513.00000
+514.00000
+515.00000
+516.00000
+517.00000
+511.50000
+512.50000
+INSERT INTO t1 SELECT id+1024 FROM t1;
+INSERT INTO t1 SELECT id+2048 FROM t1;
+INSERT INTO t1 SELECT id+4096 FROM t1;
+INSERT INTO t1 SELECT id+8192 FROM t1;
+INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand();
+SELECT SUM(DISTINCT id) sm FROM t1;
+sm
+134225920
+SELECT SUM(DISTINCT id) sm FROM t2;
+sm
+134225920
+SELECT SUM(DISTINCT id) sm FROM t1 group by id % 13;
+sm
+10327590
+10328851
+10330112
+10331373
+10332634
+10317510
+10318770
+10320030
+10321290
+10322550
+10323810
+10325070
+10326330
+SET max_heap_table_size=16384;
+SHOW variables LIKE 'max_heap_table_size';
+Variable_name Value
+max_heap_table_size 16384
+SELECT SUM(DISTINCT id) sm FROM t1;
+sm
+134225920
+SELECT SUM(DISTINCT id) sm FROM t2;
+sm
+134225920
+SELECT SUM(DISTINCT id) sm FROM t1 GROUP BY id % 13;
+sm
+10327590
+10328851
+10330112
+10331373
+10332634
+10317510
+10318770
+10320030
+10321290
+10322550
+10323810
+10325070
+10326330
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/r/sum_distinct.result b/mysql-test/r/sum_distinct.result
new file mode 100644
index 00000000000..c615817f52d
--- /dev/null
+++ b/mysql-test/r/sum_distinct.result
@@ -0,0 +1,97 @@
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 (
+id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
+gender CHAR(1),
+name VARCHAR(20)
+);
+SELECT SUM(DISTINCT LENGTH(name)) s1 FROM t1;
+s1
+NULL
+INSERT INTO t1 (gender, name) VALUES (NULL, NULL);
+INSERT INTO t1 (gender, name) VALUES (NULL, NULL);
+INSERT INTO t1 (gender, name) VALUES (NULL, NULL);
+SELECT SUM(DISTINCT LENGTH(name)) s1 FROM t1;
+s1
+NULL
+INSERT INTO t1 (gender, name) VALUES ('F', 'Helen'), ('F', 'Anastasia'),
+('F', 'Katherine'), ('F', 'Margo'), ('F', 'Magdalene'), ('F', 'Mary');
+CREATE TABLE t2 SELECT name FROM t1;
+SELECT (SELECT SUM(DISTINCT LENGTH(name)) FROM t1) FROM t2;
+(SELECT SUM(DISTINCT LENGTH(name)) FROM t1)
+18
+18
+18
+18
+18
+18
+18
+18
+18
+DROP TABLE t2;
+INSERT INTO t1 (gender, name) VALUES ('F', 'Eva'), ('F', 'Sofia'),
+('F', 'Sara'), ('F', 'Golda'), ('F', 'Toba'), ('F', 'Victory'),
+('F', 'Faina'), ('F', 'Miriam'), ('F', 'Beki'), ('F', 'America'),
+('F', 'Susan'), ('F', 'Glory'), ('F', 'Priscilla'), ('F', 'Rosmary'),
+('F', 'Rose'), ('F', 'Margareth'), ('F', 'Elizabeth'), ('F', 'Meredith'),
+('F', 'Julie'), ('F', 'Xenia'), ('F', 'Zena'), ('F', 'Olga'),
+('F', 'Brunhilda'), ('F', 'Nataly'), ('F', 'Lara'), ('F', 'Svetlana'),
+('F', 'Grethem'), ('F', 'Irene');
+SELECT
+SUM(DISTINCT LENGTH(name)) s1,
+SUM(DISTINCT SUBSTRING(NAME, 1, 3)) s2,
+SUM(DISTINCT LENGTH(SUBSTRING(name, 1, 4))) s3
+FROM t1;
+s1 s2 s3
+42 0 7
+SELECT
+SUM(DISTINCT LENGTH(g1.name)) s1,
+SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2,
+SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3
+FROM t1 g1, t1 g2, t1 g3;
+s1 s2 s3
+42 0 7
+SELECT
+SUM(DISTINCT LENGTH(g1.name)) s1,
+SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2,
+SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3
+FROM t1 g1, t1 g2, t1 g3 GROUP BY LENGTH(SUBSTRING(g3.name, 5, 10));
+s1 s2 s3
+42 0 NULL
+42 0 7
+42 0 4
+42 0 4
+42 0 4
+42 0 4
+42 0 4
+SELECT SQL_BUFFER_RESULT
+SUM(DISTINCT LENGTH(name)) s1,
+SUM(DISTINCT SUBSTRING(NAME, 1, 3)) s2,
+SUM(DISTINCT LENGTH(SUBSTRING(name, 1, 4))) s3
+FROM t1;
+s1 s2 s3
+42 0 7
+SELECT SQL_BUFFER_RESULT
+SUM(DISTINCT LENGTH(g1.name)) s1,
+SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2,
+SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3
+FROM t1 g1, t1 g2, t1 g3 GROUP BY LENGTH(SUBSTRING(g3.name, 5, 10));
+s1 s2 s3
+42 0 NULL
+42 0 7
+42 0 4
+42 0 4
+42 0 4
+42 0 4
+42 0 4
+SET @l=1;
+UPDATE t1 SET name=CONCAT(name, @l:=@l+1);
+SELECT SUM(DISTINCT RIGHT(name, 1)) FROM t1;
+SUM(DISTINCT RIGHT(name, 1))
+45
+SELECT SUM(DISTINCT id) FROM t1;
+SUM(DISTINCT id)
+703
+SELECT SUM(DISTINCT id % 11) FROM t1;
+SUM(DISTINCT id % 11)
+55
+DROP TABLE t1;
diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result
index 26612ec81fd..b36020bc2a3 100644
--- a/mysql-test/r/symlink.result
+++ b/mysql-test/r/symlink.result
@@ -37,14 +37,23 @@ show create table t9;
Table Create Table
t9 CREATE TABLE `t9` (
`a` int(11) NOT NULL auto_increment,
- `b` char(16) NOT NULL default '',
- `c` int(11) NOT NULL default '0',
+ `b` char(16) NOT NULL,
+ `c` int(11) NOT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='TEST_DIR/var/tmp/' INDEX DIRECTORY='TEST_DIR/var/run/'
alter table t9 rename t8, add column d int not null;
alter table t8 rename t7;
rename table t7 to t9;
drop table t1;
+SHOW CREATE TABLE t9;
+Table Create Table
+t9 CREATE TABLE `t9` (
+ `a` int(11) NOT NULL auto_increment,
+ `b` char(16) NOT NULL,
+ `c` int(11) NOT NULL,
+ `d` int(11) NOT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='TEST_DIR/var/tmp/' INDEX DIRECTORY='TEST_DIR/var/run/'
Got one of the listed errors
Got one of the listed errors
Got one of the listed errors
@@ -58,9 +67,9 @@ show create table mysqltest.t9;
Table Create Table
t9 CREATE TABLE `t9` (
`a` int(11) NOT NULL auto_increment,
- `b` char(16) NOT NULL default '',
- `c` int(11) NOT NULL default '0',
- `d` int(11) NOT NULL default '0',
+ `b` char(16) NOT NULL,
+ `c` int(11) NOT NULL,
+ `d` int(11) NOT NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='TEST_DIR/var/tmp/' INDEX DIRECTORY='TEST_DIR/var/run/'
drop database mysqltest;
@@ -68,19 +77,19 @@ create table t1 (a int not null) engine=myisam;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0'
+ `a` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
alter table t1 add b int;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` int(11) NOT NULL default '0',
+ `a` int(11) NOT NULL,
`b` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
diff --git a/mysql-test/r/synchronization.result b/mysql-test/r/synchronization.result
index ad9443c86da..0b84697066c 100644
--- a/mysql-test/r/synchronization.result
+++ b/mysql-test/r/synchronization.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
CREATE TABLE t1 (x1 int);
ALTER TABLE t1 CHANGE x1 x2 int;
CREATE TABLE t2 LIKE t1;
diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result
index 141878a7bf6..40a9c3b9af5 100644
--- a/mysql-test/r/system_mysql_db.result
+++ b/mysql-test/r/system_mysql_db.result
@@ -1,3 +1,4 @@
+drop table if exists t1,t1aa,t2aa;
show tables;
Tables_in_db
columns_priv
@@ -8,6 +9,8 @@ help_keyword
help_relation
help_topic
host
+proc
+procs_priv
tables_priv
time_zone
time_zone_leap_second
@@ -33,6 +36,11 @@ db CREATE TABLE `db` (
`Alter_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
`Create_tmp_table_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
`Lock_tables_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Create_view_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Show_view_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Create_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Alter_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Execute_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
PRIMARY KEY (`Host`,`Db`,`User`),
KEY `User` (`User`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Database privileges'
@@ -53,14 +61,16 @@ host CREATE TABLE `host` (
`Alter_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
`Create_tmp_table_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
`Lock_tables_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Create_view_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Show_view_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
PRIMARY KEY (`Host`,`Db`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Host privileges; Merged with database privileges'
show create table user;
Table Create Table
user CREATE TABLE `user` (
- `Host` varchar(60) collate utf8_bin NOT NULL default '',
- `User` varchar(16) collate utf8_bin NOT NULL default '',
- `Password` varchar(41) collate utf8_bin NOT NULL default '',
+ `Host` char(60) collate utf8_bin NOT NULL default '',
+ `User` char(16) collate utf8_bin NOT NULL default '',
+ `Password` char(41) collate utf8_bin NOT NULL default '',
`Select_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
`Insert_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
`Update_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
@@ -82,6 +92,11 @@ user CREATE TABLE `user` (
`Execute_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
`Repl_slave_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
`Repl_client_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Create_view_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Show_view_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Create_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Alter_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
+ `Create_user_priv` enum('N','Y') character set utf8 NOT NULL default 'N',
`ssl_type` enum('','ANY','X509','SPECIFIED') character set utf8 NOT NULL default '',
`ssl_cipher` blob NOT NULL,
`x509_issuer` blob NOT NULL,
@@ -89,6 +104,7 @@ user CREATE TABLE `user` (
`max_questions` int(11) unsigned NOT NULL default '0',
`max_updates` int(11) unsigned NOT NULL default '0',
`max_connections` int(11) unsigned NOT NULL default '0',
+ `max_user_connections` int(11) unsigned NOT NULL default '0',
PRIMARY KEY (`Host`,`User`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges'
show create table func;
@@ -126,5 +142,39 @@ columns_priv CREATE TABLE `columns_priv` (
`Column_priv` set('Select','Insert','Update','References') character set utf8 NOT NULL default '',
PRIMARY KEY (`Host`,`Db`,`User`,`Table_name`,`Column_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Column privileges'
+show create table procs_priv;
+Table Create Table
+procs_priv CREATE TABLE `procs_priv` (
+ `Host` char(60) collate utf8_bin NOT NULL default '',
+ `Db` char(64) collate utf8_bin NOT NULL default '',
+ `User` char(16) collate utf8_bin NOT NULL default '',
+ `Routine_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,
+ `Proc_priv` set('Execute','Alter Routine','Grant') character set utf8 NOT NULL default '',
+ PRIMARY KEY (`Host`,`Db`,`User`,`Routine_name`),
+ KEY `Grantor` (`Grantor`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Procedure privileges'
+show create table proc;
+Table Create Table
+proc CREATE TABLE `proc` (
+ `db` char(64) character set latin1 collate latin1_bin NOT NULL default '',
+ `name` char(64) NOT NULL default '',
+ `type` enum('FUNCTION','PROCEDURE') NOT NULL default 'FUNCTION',
+ `specific_name` char(64) NOT NULL default '',
+ `language` enum('SQL') NOT NULL default 'SQL',
+ `sql_data_access` enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA') NOT NULL default 'CONTAINS_SQL',
+ `is_deterministic` enum('YES','NO') NOT NULL default 'NO',
+ `security_type` enum('INVOKER','DEFINER') NOT NULL default 'DEFINER',
+ `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 '',
+ `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 '',
+ PRIMARY KEY (`db`,`name`,`type`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Stored Procedures'
show tables;
Tables_in_test
diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result
index 10c0a2e3652..f43fd09982a 100644
--- a/mysql-test/r/temp_table.result
+++ b/mysql-test/r/temp_table.result
@@ -95,5 +95,31 @@ d
show status like "created_tmp%tables";
Variable_name Value
Created_tmp_disk_tables 0
-Created_tmp_tables 1
+Created_tmp_tables 2
drop table t1;
+create temporary table t1 as select 'This is temp. table' A;
+create view t1 as select 'This is view' A;
+select * from t1;
+A
+This is temp. table
+show create table t1;
+Table Create Table
+t1 CREATE TEMPORARY TABLE `t1` (
+ `A` varchar(19) NOT NULL default ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+show create view t1;
+View Create View
+t1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`t1` AS select _latin1'This is view' AS `A`
+drop view t1;
+select * from t1;
+A
+This is temp. table
+create view t1 as select 'This is view again' A;
+select * from t1;
+A
+This is temp. table
+drop table t1;
+select * from t1;
+A
+This is view again
+drop view t1;
diff --git a/mysql-test/r/testdb_only.require b/mysql-test/r/testdb_only.require
new file mode 100644
index 00000000000..e717418fdb6
--- /dev/null
+++ b/mysql-test/r/testdb_only.require
@@ -0,0 +1,2 @@
+Variable_name Value
+use extern server NO
diff --git a/mysql-test/r/timezone2.result b/mysql-test/r/timezone2.result
index 199b48ef1aa..a90bdf9ad5b 100644
--- a/mysql-test/r/timezone2.result
+++ b/mysql-test/r/timezone2.result
@@ -108,9 +108,9 @@ insert into t1 values ('0000-00-00 00:00:00'),('1969-12-31 23:59:59'),
('1970-01-01 00:00:00'),('1970-01-01 00:00:01'),
('2037-12-31 23:59:59'),('2038-01-01 00:00:00');
Warnings:
-Warning 1264 Data truncated; out of range for column 'ts' at row 2
-Warning 1264 Data truncated; out of range for column 'ts' at row 3
-Warning 1264 Data truncated; out of range for column 'ts' at row 6
+Warning 1264 Out of range value adjusted for column 'ts' at row 2
+Warning 1264 Out of range value adjusted for column 'ts' at row 3
+Warning 1264 Out of range value adjusted for column 'ts' at row 6
select * from t1;
ts
0000-00-00 00:00:00
@@ -125,9 +125,9 @@ insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 00:30:00'),
('1970-01-01 01:00:00'),('1970-01-01 01:00:01'),
('2038-01-01 00:59:59'),('2038-01-01 01:00:00');
Warnings:
-Warning 1264 Data truncated; out of range for column 'ts' at row 2
-Warning 1264 Data truncated; out of range for column 'ts' at row 3
-Warning 1264 Data truncated; out of range for column 'ts' at row 6
+Warning 1264 Out of range value adjusted for column 'ts' at row 2
+Warning 1264 Out of range value adjusted for column 'ts' at row 3
+Warning 1264 Out of range value adjusted for column 'ts' at row 6
select * from t1;
ts
0000-00-00 00:00:00
@@ -142,9 +142,9 @@ insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 01:00:00'),
('1970-01-01 01:30:00'),('1970-01-01 01:30:01'),
('2038-01-01 01:29:59'),('2038-01-01 01:30:00');
Warnings:
-Warning 1264 Data truncated; out of range for column 'ts' at row 2
-Warning 1264 Data truncated; out of range for column 'ts' at row 3
-Warning 1264 Data truncated; out of range for column 'ts' at row 6
+Warning 1264 Out of range value adjusted for column 'ts' at row 2
+Warning 1264 Out of range value adjusted for column 'ts' at row 3
+Warning 1264 Out of range value adjusted for column 'ts' at row 6
select * from t1;
ts
0000-00-00 00:00:00
diff --git a/mysql-test/r/timezone_grant.result b/mysql-test/r/timezone_grant.result
index 685f8007ac7..dfe0b75ee43 100644
--- a/mysql-test/r/timezone_grant.result
+++ b/mysql-test/r/timezone_grant.result
@@ -20,9 +20,9 @@ convert_tz(b, 'Europe/Moscow', 'UTC')
update t1, t2 set t1.b = convert_tz('2004-10-21 19:00:00', 'Europe/Moscow', 'UTC')
where t1.a = t2.c and t2.d = (select max(d) from t2);
select * from mysql.time_zone_name;
-ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysql'
+ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'time_zone_name'
select Name, convert_tz('2004-10-21 19:00:00', Name, 'UTC') from mysql.time_zone_name;
-ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysql'
+ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'time_zone_name'
delete from mysql.db where user like 'mysqltest\_%';
flush privileges;
grant all privileges on test.t1 to mysqltest_1@localhost;
@@ -36,7 +36,9 @@ set time_zone= '+00:00';
set time_zone= 'Europe/Moscow';
select convert_tz('2004-11-31 12:00:00', 'Europe/Moscow', 'UTC');
convert_tz('2004-11-31 12:00:00', 'Europe/Moscow', 'UTC')
-2004-12-01 09:00:00
+NULL
+Warnings:
+Warning 1292 Truncated incorrect datetime value: '2004-11-31 12:00:00'
select convert_tz(b, 'Europe/Moscow', 'UTC') from t1;
convert_tz(b, 'Europe/Moscow', 'UTC')
update t1, t2 set t1.b = convert_tz('2004-11-30 12:00:00', 'Europe/Moscow', 'UTC')
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
new file mode 100644
index 00000000000..cf0e0e8f564
--- /dev/null
+++ b/mysql-test/r/trigger.result
@@ -0,0 +1,208 @@
+drop table if exists t1, t2;
+drop view if exists v1;
+drop database if exists mysqltest;
+create table t1 (i int);
+create trigger trg before insert on t1 for each row set @a:=1;
+set @a:=0;
+select @a;
+@a
+0
+insert into t1 values (1);
+select @a;
+@a
+1
+drop trigger t1.trg;
+create trigger trg before insert on t1 for each row set @a:=new.i;
+insert into t1 values (123);
+select @a;
+@a
+123
+drop trigger t1.trg;
+drop table t1;
+create table t1 (i int not null, j int);
+create trigger trg before insert on t1 for each row
+begin
+if isnull(new.j) then
+set new.j:= new.i * 10;
+end if;
+end|
+insert into t1 (i) values (1)|
+insert into t1 (i,j) values (2, 3)|
+select * from t1|
+i j
+1 10
+2 3
+drop trigger t1.trg|
+drop table t1|
+create table t1 (i int not null primary key);
+create trigger trg after insert on t1 for each row
+set @a:= if(@a,concat(@a, ":", new.i), new.i);
+set @a:="";
+insert into t1 values (2),(3),(4),(5);
+select @a;
+@a
+2:3:4:5
+drop trigger t1.trg;
+drop table t1;
+create table t1 (aid int not null primary key, balance int not null default 0);
+insert into t1 values (1, 1000), (2,3000);
+create trigger trg before update on t1 for each row
+begin
+declare loc_err varchar(255);
+if abs(new.balance - old.balance) > 1000 then
+set new.balance:= old.balance;
+set loc_err := concat("Too big change for aid = ", new.aid);
+set @update_failed:= if(@update_failed, concat(@a, ":", loc_err), loc_err);
+end if;
+end|
+set @update_failed:=""|
+update t1 set balance=1500|
+select @update_failed;
+select * from t1|
+@update_failed
+Too big change for aid = 2
+aid balance
+1 1500
+2 3000
+drop trigger t1.trg|
+drop table t1|
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg after update on t1 for each row
+set @total_change:=@total_change + new.i - old.i;
+set @total_change:=0;
+update t1 set i=3;
+select @total_change;
+@total_change
+2
+drop trigger t1.trg;
+drop table t1;
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg before delete on t1 for each row
+set @del_sum:= @del_sum + old.i;
+set @del_sum:= 0;
+delete from t1 where i <= 3;
+select @del_sum;
+@del_sum
+6
+drop trigger t1.trg;
+drop table t1;
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg after delete on t1 for each row set @del:= 1;
+set @del:= 0;
+delete from t1 where i <> 0;
+select @del;
+@del
+1
+drop trigger t1.trg;
+drop table t1;
+create table t1 (i int, j int);
+create trigger trg1 before insert on t1 for each row
+begin
+if new.j > 10 then
+set new.j := 10;
+end if;
+end|
+create trigger trg2 before update on t1 for each row
+begin
+if old.i % 2 = 0 then
+set new.j := -1;
+end if;
+end|
+create trigger trg3 after update on t1 for each row
+begin
+if new.j = -1 then
+set @fired:= "Yes";
+end if;
+end|
+set @fired:="";
+insert into t1 values (1,2),(2,3),(3,14);
+select @fired;
+@fired
+
+select * from t1;
+i j
+1 2
+2 3
+3 10
+update t1 set j= 20;
+select @fired;
+@fired
+Yes
+select * from t1;
+i j
+1 20
+2 -1
+3 20
+drop trigger t1.trg1;
+drop trigger t1.trg2;
+drop trigger t1.trg3;
+drop table t1;
+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
+create trigger trg before delete on t1 for each row set @a:= new.i;
+ERROR HY000: There is no NEW row in on DELETE trigger
+create trigger trg before update on t1 for each row set old.i:=1;
+ERROR HY000: Updating of OLD row is not allowed in trigger
+create trigger trg before delete on t1 for each row set new.i:=1;
+ERROR HY000: There is no NEW row in on DELETE trigger
+create trigger trg after update on t1 for each row set new.i:=1;
+ERROR HY000: Updating of NEW row is not allowed in after trigger
+create trigger trg before update on t1 for each row set new.j:=1;
+ERROR 42S22: Unknown column 'j' in 'NEW'
+create trigger trg before update on t1 for each row set @a:=old.j;
+ERROR 42S22: Unknown column 'j' in 'OLD'
+create trigger trg before insert on t2 for each row set @a:=1;
+ERROR 42S02: Table 'test.t2' doesn't exist
+create trigger trg before insert on t1 for each row set @a:=1;
+create trigger trg after insert on t1 for each row set @a:=1;
+ERROR HY000: Trigger already exists
+create trigger trg2 before insert on t1 for each row set @a:=1;
+ERROR HY000: Trigger already exists
+drop trigger t1.trg;
+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
+drop view v1;
+drop table t1;
+create temporary table t1 (i int);
+create trigger trg before insert on t1 for each row set @a:=1;
+ERROR HY000: Trigger's 't1' is view or temporary table
+drop table t1;
+create table t1 (x1col char);
+create trigger tx1 before insert on t1 for each row set new.x1col = 'x';
+insert into t1 values ('y');
+drop trigger t1.tx1;
+drop table t1;
+create table t1 (i int) engine=myisam;
+insert into t1 values (1), (2);
+create trigger trg1 before delete on t1 for each row set @del_before:= @del_before + old.i;
+create trigger trg2 after delete on t1 for each row set @del_after:= @del_after + old.i;
+set @del_before:=0, @del_after:= 0;
+delete from t1;
+select @del_before, @del_after;
+@del_before @del_after
+3 3
+drop trigger t1.trg1;
+drop trigger t1.trg2;
+drop table t1;
+create table t1 (a int);
+create trigger trg1 before insert on t1 for each row set new.a= 10;
+drop table t1;
+create table t1 (a int);
+insert into t1 values ();
+select * from t1;
+a
+NULL
+drop table t1;
+create database mysqltest;
+use mysqltest;
+create table t1 (i int);
+create trigger trg1 before insert on t1 for each row set @a:= 1;
+drop database mysqltest;
+use test;
diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result
new file mode 100644
index 00000000000..b0cd4150c9d
--- /dev/null
+++ b/mysql-test/r/type_bit.result
@@ -0,0 +1,439 @@
+select 0 + b'1';
+0 + b'1'
+1
+select 0 + b'0';
+0 + b'0'
+0
+select 0 + b'000001';
+0 + b'000001'
+1
+select 0 + b'000011';
+0 + b'000011'
+3
+select 0 + b'000101';
+0 + b'000101'
+5
+select 0 + b'000000';
+0 + b'000000'
+0
+select 0 + b'10000000';
+0 + b'10000000'
+128
+select 0 + b'11111111';
+0 + b'11111111'
+255
+select 0 + b'10000001';
+0 + b'10000001'
+129
+select 0 + b'1000000000000000';
+0 + b'1000000000000000'
+32768
+select 0 + b'1111111111111111';
+0 + b'1111111111111111'
+65535
+select 0 + b'1000000000000001';
+0 + b'1000000000000001'
+32769
+drop table if exists t1;
+create table t1 (a bit(65));
+ERROR 42000: Column length too big for column 'a' (max = 64); use BLOB or TEXT instead
+create table t1 (a bit(0));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bit(1) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (a bit(64));
+insert into t1 values
+(b'1111111111111111111111111111111111111111111111111111111111111111'),
+(b'1000000000000000000000000000000000000000000000000000000000000000'),
+(b'0000000000000000000000000000000000000000000000000000000000000001'),
+(b'1010101010101010101010101010101010101010101010101010101010101010'),
+(b'0101010101010101010101010101010101010101010101010101010101010101');
+select hex(a) from t1;
+hex(a)
+FFFFFFFFFFFFFFFF
+8000000000000000
+1
+AAAAAAAAAAAAAAAA
+5555555555555555
+drop table t1;
+create table t1 (a bit);
+insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+select hex(a) from t1;
+hex(a)
+0
+1
+0
+1
+1
+alter table t1 add unique (a);
+ERROR 23000: Duplicate entry '' for key 1
+drop table t1;
+create table t1 (a bit(2));
+insert into t1 values (b'00'), (b'01'), (b'10'), (b'100');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+select a+0 from t1;
+a+0
+0
+1
+2
+3
+alter table t1 add key (a);
+explain select a+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 2 NULL 4 Using index
+select a+0 from t1;
+a+0
+0
+1
+2
+3
+drop table t1;
+create table t1 (a bit(7), b bit(9), key(a, b));
+insert into t1 values
+(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177),
+(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380),
+(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36),
+(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499),
+(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403),
+(44, 307), (68, 454), (57, 135);
+explain select a+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 38 Using index
+select a+0 from t1;
+a+0
+0
+4
+5
+9
+23
+24
+28
+29
+30
+31
+34
+44
+49
+56
+57
+59
+60
+61
+68
+68
+75
+77
+78
+79
+87
+88
+94
+94
+104
+106
+108
+111
+116
+118
+119
+122
+123
+127
+explain select b+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 38 Using index
+select b+0 from t1;
+b+0
+177
+245
+178
+363
+36
+398
+499
+399
+83
+438
+202
+307
+345
+379
+135
+188
+343
+152
+206
+454
+42
+133
+123
+349
+351
+411
+46
+468
+280
+446
+67
+368
+390
+380
+368
+118
+411
+403
+explain select a+0, b+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 38 Using index
+select a+0, b+0 from t1;
+a+0 b+0
+0 177
+4 245
+5 178
+9 363
+23 36
+24 398
+28 499
+29 399
+30 83
+31 438
+34 202
+44 307
+49 345
+56 379
+57 135
+59 188
+60 343
+61 152
+68 206
+68 454
+75 42
+77 133
+78 123
+79 349
+87 351
+88 411
+94 46
+94 468
+104 280
+106 446
+108 67
+111 368
+116 390
+118 380
+119 368
+122 118
+123 411
+127 403
+explain select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 2 NULL 27 Using where; Using index; Using filesort
+select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+a+0 b+0
+44 307
+49 345
+56 379
+60 343
+68 206
+68 454
+79 349
+87 351
+88 411
+94 468
+104 280
+106 446
+111 368
+116 390
+118 380
+119 368
+123 411
+127 403
+explain select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 2 NULL 8 Using where; Using index; Using filesort
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+a+0 b+0
+57 135
+61 152
+59 188
+68 206
+44 307
+60 343
+49 345
+56 379
+68 454
+set @@max_length_for_sort_data=0;
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+a+0 b+0
+57 135
+61 152
+59 188
+68 206
+44 307
+60 343
+49 345
+56 379
+68 454
+select hex(min(a)) from t1;
+hex(min(a))
+0
+select hex(min(b)) from t1;
+hex(min(b))
+24
+select hex(min(a)), hex(max(a)), hex(min(b)), hex(max(b)) from t1;
+hex(min(a)) hex(max(a)) hex(min(b)) hex(max(b))
+0 7F 24 1F3
+drop table t1;
+create table t1 (a int not null, b bit, c bit(9), key(a, b, c));
+insert into t1 values
+(4, NULL, 1), (4, 0, 3), (2, 1, 4), (1, 1, 100), (4, 0, 23), (4, 0, 54),
+(56, 0, 22), (4, 1, 100), (23, 0, 1), (4, 0, 34);
+select a+0, b+0, c+0 from t1;
+a+0 b+0 c+0
+1 1 100
+2 1 4
+4 NULL 1
+4 0 3
+4 0 23
+4 0 34
+4 0 54
+4 1 100
+23 0 1
+56 0 22
+select hex(min(b)) from t1 where a = 4;
+hex(min(b))
+0
+select hex(min(c)) from t1 where a = 4 and b = 0;
+hex(min(c))
+3
+select hex(max(b)) from t1;
+hex(max(b))
+1
+select a+0, b+0, c+0 from t1 where a = 4 and b = 0 limit 2;
+a+0 b+0 c+0
+4 0 3
+4 0 23
+select a+0, b+0, c+0 from t1 where a = 4 and b = 1;
+a+0 b+0 c+0
+4 1 100
+select a+0, b+0, c+0 from t1 where a = 4 and b = 1 and c=100;
+a+0 b+0 c+0
+4 1 100
+select a+0, b+0, c+0 from t1 order by b desc;
+a+0 b+0 c+0
+2 1 4
+1 1 100
+4 1 100
+4 0 3
+4 0 23
+4 0 54
+56 0 22
+23 0 1
+4 0 34
+4 NULL 1
+select a+0, b+0, c+0 from t1 order by c;
+a+0 b+0 c+0
+4 NULL 1
+23 0 1
+4 0 3
+2 1 4
+56 0 22
+4 0 23
+4 0 34
+4 0 54
+1 1 100
+4 1 100
+drop table t1;
+create table t1(a bit(2), b bit(2));
+insert into t1 (a) values (0x01), (0x03), (0x02);
+update t1 set b= concat(a);
+select a+0, b+0 from t1;
+a+0 b+0
+1 1
+3 3
+2 2
+drop table t1;
+create table t1 (a bit(7), key(a));
+insert into t1 values (44), (57);
+select a+0 from t1;
+a+0
+44
+57
+drop table t1;
+create table t1 (a bit(3), b bit(12));
+insert into t1 values (7,(1<<12)-2), (0x01,0x01ff);
+select hex(a),hex(b) from t1;
+hex(a) hex(b)
+7 FFE
+1 1FF
+select hex(concat(a)),hex(concat(b)) from t1;
+hex(concat(a)) hex(concat(b))
+07 0FFE
+01 01FF
+drop table t1;
+create table t1(a int, b bit not null);
+alter table t1 add primary key (a);
+drop table t1;
+create table t1 (a bit(19), b bit(5));
+insert into t1 values (1000, 10), (3, 8), (200, 6), (2303, 2), (12345, 4), (1, 0);
+select a+0, b+0 from t1;
+a+0 b+0
+1000 10
+3 8
+200 6
+2303 2
+12345 4
+1 0
+alter table t1 engine=heap;
+select a+0, b+0 from t1;
+a+0 b+0
+1000 10
+3 8
+200 6
+2303 2
+12345 4
+1 0
+alter table t1 add key(a, b);
+select a+0, b+0 from t1;
+a+0 b+0
+1000 10
+3 8
+200 6
+2303 2
+12345 4
+1 0
+alter table t1 engine=myisam;
+select a+0, b+0 from t1;
+a+0 b+0
+1 0
+3 8
+200 6
+1000 10
+2303 2
+12345 4
+create table t2 engine=heap select * from t1;
+select a+0, b+0 from t2;
+a+0 b+0
+1 0
+3 8
+200 6
+1000 10
+2303 2
+12345 4
+drop table t1;
+create table t1 select * from t2;
+select a+0, b+0 from t1;
+a+0 b+0
+1 0
+3 8
+200 6
+1000 10
+2303 2
+12345 4
+drop table t1, t2;
diff --git a/mysql-test/r/type_bit_innodb.result b/mysql-test/r/type_bit_innodb.result
new file mode 100644
index 00000000000..f3e9dad3baa
--- /dev/null
+++ b/mysql-test/r/type_bit_innodb.result
@@ -0,0 +1,404 @@
+select 0 + b'1';
+0 + b'1'
+1
+select 0 + b'0';
+0 + b'0'
+0
+select 0 + b'000001';
+0 + b'000001'
+1
+select 0 + b'000011';
+0 + b'000011'
+3
+select 0 + b'000101';
+0 + b'000101'
+5
+select 0 + b'000000';
+0 + b'000000'
+0
+select 0 + b'10000000';
+0 + b'10000000'
+128
+select 0 + b'11111111';
+0 + b'11111111'
+255
+select 0 + b'10000001';
+0 + b'10000001'
+129
+select 0 + b'1000000000000000';
+0 + b'1000000000000000'
+32768
+select 0 + b'1111111111111111';
+0 + b'1111111111111111'
+65535
+select 0 + b'1000000000000001';
+0 + b'1000000000000001'
+32769
+drop table if exists t1;
+create table t1 (a bit(65)) engine=innodb;
+ERROR 42000: Column length too big for column 'a' (max = 64); use BLOB or TEXT instead
+create table t1 (a bit(0)) engine=innodb;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bit(1) default NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (a bit(64)) engine=innodb;
+insert into t1 values
+(b'1111111111111111111111111111111111111111111111111111111111111111'),
+(b'1000000000000000000000000000000000000000000000000000000000000000'),
+(b'0000000000000000000000000000000000000000000000000000000000000001'),
+(b'1010101010101010101010101010101010101010101010101010101010101010'),
+(b'0101010101010101010101010101010101010101010101010101010101010101');
+select hex(a) from t1;
+hex(a)
+FFFFFFFFFFFFFFFF
+8000000000000000
+1
+AAAAAAAAAAAAAAAA
+5555555555555555
+drop table t1;
+create table t1 (a bit) engine=innodb;
+insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+select hex(a) from t1;
+hex(a)
+0
+1
+0
+1
+1
+alter table t1 add unique (a);
+ERROR 23000: Duplicate entry '' for key 1
+drop table t1;
+create table t1 (a bit(2)) engine=innodb;
+insert into t1 values (b'00'), (b'01'), (b'10'), (b'100');
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+select a+0 from t1;
+a+0
+0
+1
+2
+3
+alter table t1 add key (a);
+explain select a+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 2 NULL 4 Using index
+select a+0 from t1;
+a+0
+0
+1
+2
+3
+drop table t1;
+create table t1 (a bit(7), b bit(9), key(a, b)) engine=innodb;
+insert into t1 values
+(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177),
+(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380),
+(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36),
+(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499),
+(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403),
+(44, 307), (68, 454), (57, 135);
+explain select a+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 38 Using index
+select a+0 from t1;
+a+0
+0
+4
+5
+9
+23
+24
+28
+29
+30
+31
+34
+44
+49
+56
+57
+59
+60
+61
+68
+68
+75
+77
+78
+79
+87
+88
+94
+94
+104
+106
+108
+111
+116
+118
+119
+122
+123
+127
+explain select b+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 38 Using index
+select b+0 from t1;
+b+0
+177
+245
+178
+363
+36
+398
+499
+399
+83
+438
+202
+307
+345
+379
+135
+188
+343
+152
+206
+454
+42
+133
+123
+349
+351
+411
+46
+468
+280
+446
+67
+368
+390
+380
+368
+118
+411
+403
+explain select a+0, b+0 from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 38 Using index
+select a+0, b+0 from t1;
+a+0 b+0
+0 177
+4 245
+5 178
+9 363
+23 36
+24 398
+28 499
+29 399
+30 83
+31 438
+34 202
+44 307
+49 345
+56 379
+57 135
+59 188
+60 343
+61 152
+68 206
+68 454
+75 42
+77 133
+78 123
+79 349
+87 351
+88 411
+94 46
+94 468
+104 280
+106 446
+108 67
+111 368
+116 390
+118 380
+119 368
+122 118
+123 411
+127 403
+explain select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 2 NULL 19 Using where; Using index; Using filesort
+select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+a+0 b+0
+44 307
+49 345
+56 379
+60 343
+68 206
+68 454
+79 349
+87 351
+88 411
+94 468
+104 280
+106 446
+111 368
+116 390
+118 380
+119 368
+123 411
+127 403
+explain select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 2 NULL 8 Using where; Using index; Using filesort
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+a+0 b+0
+57 135
+61 152
+59 188
+68 206
+44 307
+60 343
+49 345
+56 379
+68 454
+set @@max_length_for_sort_data=0;
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+a+0 b+0
+57 135
+61 152
+59 188
+68 206
+44 307
+60 343
+49 345
+56 379
+68 454
+select hex(min(a)) from t1;
+hex(min(a))
+0
+select hex(min(b)) from t1;
+hex(min(b))
+24
+select hex(min(a)), hex(max(a)), hex(min(b)), hex(max(b)) from t1;
+hex(min(a)) hex(max(a)) hex(min(b)) hex(max(b))
+0 7F 24 1F3
+drop table t1;
+create table t1 (a int not null, b bit, c bit(9), key(a, b, c)) engine=innodb;
+insert into t1 values
+(4, NULL, 1), (4, 0, 3), (2, 1, 4), (1, 1, 100), (4, 0, 23), (4, 0, 54),
+(56, 0, 22), (4, 1, 100), (23, 0, 1), (4, 0, 34);
+select a+0, b+0, c+0 from t1;
+a+0 b+0 c+0
+1 1 100
+2 1 4
+4 NULL 1
+4 0 3
+4 0 23
+4 0 34
+4 0 54
+4 1 100
+23 0 1
+56 0 22
+select hex(min(b)) from t1 where a = 4;
+hex(min(b))
+0
+select hex(min(c)) from t1 where a = 4 and b = 0;
+hex(min(c))
+3
+select hex(max(b)) from t1;
+hex(max(b))
+1
+select a+0, b+0, c+0 from t1 where a = 4 and b = 0 limit 2;
+a+0 b+0 c+0
+4 0 3
+4 0 23
+select a+0, b+0, c+0 from t1 where a = 4 and b = 1;
+a+0 b+0 c+0
+4 1 100
+select a+0, b+0, c+0 from t1 where a = 4 and b = 1 and c=100;
+a+0 b+0 c+0
+4 1 100
+select a+0, b+0, c+0 from t1 order by b desc;
+a+0 b+0 c+0
+2 1 4
+1 1 100
+4 1 100
+4 0 3
+4 0 23
+4 0 54
+56 0 22
+23 0 1
+4 0 34
+4 NULL 1
+select a+0, b+0, c+0 from t1 order by c;
+a+0 b+0 c+0
+4 NULL 1
+23 0 1
+4 0 3
+2 1 4
+56 0 22
+4 0 23
+4 0 34
+4 0 54
+1 1 100
+4 1 100
+drop table t1;
+create table t1(a bit(2), b bit(2)) engine=innodb;
+insert into t1 (a) values (0x01), (0x03), (0x02);
+update t1 set b= concat(a);
+select a+0, b+0 from t1;
+a+0 b+0
+1 1
+3 3
+2 2
+drop table t1;
+create table t1 (a bit(7), key(a)) engine=innodb;
+insert into t1 values (44), (57);
+select a+0 from t1;
+a+0
+44
+57
+drop table t1;
+create table t1 (a bit(3), b bit(12)) engine=innodb;
+insert into t1 values (7,(1<<12)-2), (0x01,0x01ff);
+select hex(a),hex(b) from t1;
+hex(a) hex(b)
+7 FFE
+1 1FF
+select hex(concat(a)),hex(concat(b)) from t1;
+hex(concat(a)) hex(concat(b))
+07 0FFE
+01 01FF
+drop table t1;
+create table t1(a int, b bit not null) engine=innodb;
+alter table t1 add primary key (a);
+drop table t1;
+create table t1 (a bit, b bit(10)) engine=innodb;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bit(1) default NULL,
+ `b` bit(10) default NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 engine=heap;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bit(1) default NULL,
+ `b` bit(10) default NULL
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+alter table t1 engine=innodb;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bit(1) default NULL,
+ `b` bit(10) default NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result
index 6b4b54fbb66..6f437ddbe0d 100644
--- a/mysql-test/r/type_blob.result
+++ b/mysql-test/r/type_blob.result
@@ -7,14 +7,16 @@ b text YES NULL
c tinyblob YES NULL
d mediumtext YES NULL
e longtext YES NULL
-CREATE TABLE t2 (a char(257), b varbinary(70000), c varchar(70000000));
+CREATE TABLE t2 (a char(255), b varbinary(70000), c varchar(70000000));
Warnings:
-Warning 1246 Converting column 'a' from CHAR to TEXT
-Warning 1246 Converting column 'b' from CHAR to BLOB
-Warning 1246 Converting column 'c' from CHAR to TEXT
+Note 1246 Converting column 'b' from VARCHAR to BLOB
+Note 1246 Converting column 'c' from VARCHAR to TEXT
+CREATE TABLE t4 (c varchar(65530) character set utf8 not null);
+Warnings:
+Note 1246 Converting column 'c' from VARCHAR to TEXT
show columns from t2;
Field Type Null Key Default Extra
-a text YES NULL
+a char(255) YES NULL
b mediumblob YES NULL
c longtext YES NULL
create table t3 (a long, b long byte);
@@ -24,10 +26,18 @@ t3 CREATE TABLE `t3` (
`a` mediumtext,
`b` mediumblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
-drop table t1,t2,t3
-#;
+show create TABLE t4;
+Table Create Table
+t4 CREATE TABLE `t4` (
+ `c` mediumtext character set utf8 NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1,t2,t3,t4;
CREATE TABLE t1 (a char(257) default "hello");
ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT instead
+CREATE TABLE t2 (a char(256));
+ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT instead
+CREATE TABLE t1 (a varchar(70000) default "hello");
+ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead
CREATE TABLE t2 (a blob default "hello");
ERROR 42000: BLOB/TEXT column 'a' can't have a default value
drop table if exists t1,t2;
@@ -71,16 +81,16 @@ lock tables t1 READ;
show full fields from t1;
Field Type Collation Null Key Default Extra Privileges Comment
t text latin1_swedish_ci YES NULL #
-c varchar(10) latin1_swedish_ci YES NULL #
+c char(10) latin1_swedish_ci YES NULL #
b blob NULL YES NULL #
-d varbinary(10) NULL YES NULL #
+d binary(10) NULL YES NULL #
lock tables t1 WRITE;
show full fields from t1;
Field Type Collation Null Key Default Extra Privileges Comment
t text latin1_swedish_ci YES NULL #
-c varchar(10) latin1_swedish_ci YES NULL #
+c char(10) latin1_swedish_ci YES NULL #
b blob NULL YES NULL #
-d varbinary(10) NULL YES NULL #
+d binary(10) NULL YES NULL #
unlock tables;
select t from t1 where t like "hello";
t
@@ -492,7 +502,7 @@ select foobar, boggle from t1 where foobar = 'fish' and boggle = 10;
foobar boggle
fish 10
drop table t1;
-create table t1 (id integer auto_increment unique,imagem LONGBLOB not null);
+create table t1 (id integer auto_increment unique,imagem LONGBLOB not null default '');
insert into t1 (id) values (1);
select
charset(load_file('../../std_data/words.dat')),
@@ -520,6 +530,11 @@ l longblob NULL YES NULL #
drop table t1;
create table t1 (id integer primary key auto_increment, txt text not null, unique index txt_index (txt (20)));
insert into t1 (txt) values ('Chevy'), ('Chevy ');
+ERROR 23000: Duplicate entry 'Chevy ' for key 2
+insert into t1 (txt) values ('Chevy'), ('CHEVY');
+ERROR 23000: Duplicate entry 'Chevy' for key 2
+alter table t1 drop index txt_index, add index txt_index (txt(20));
+insert into t1 (txt) values ('Chevy ');
select * from t1 where txt='Chevy';
id txt
1 Chevy
@@ -589,7 +604,7 @@ id txt
2 Chevy
3 Ford
drop table t1;
-create table t1 (id integer primary key auto_increment, txt text, unique index txt_index (txt (20)));
+create table t1 (id integer primary key auto_increment, txt text, index txt_index (txt (20)));
insert into t1 (txt) values ('Chevy'), ('Chevy '), (NULL);
select * from t1 where txt='Chevy' or txt is NULL;
id txt
diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result
index 3428b5969d9..e88eebffb55 100644
--- a/mysql-test/r/type_date.result
+++ b/mysql-test/r/type_date.result
@@ -99,7 +99,7 @@ DROP TABLE t1, t2, t3;
CREATE TABLE t1 (y YEAR);
INSERT INTO t1 VALUES ('abc');
Warnings:
-Warning 1265 Data truncated for column 'y' at row 1
+Warning 1264 Out of range value adjusted for column 'y' at row 1
SELECT * FROM t1;
y
0000
diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result
index 7b101d31fc5..920c82c3e67 100644
--- a/mysql-test/r/type_datetime.result
+++ b/mysql-test/r/type_datetime.result
@@ -119,12 +119,12 @@ insert into t1 values
("2003-01-02 03:04:60"),("2003-01-02 03:63:01"),("2003-01-02 24:04:01"),
("2003-01-32 03:04:01"),("2003-13-02 03:04:01"), ("10000-12-02 03:04:00");
Warnings:
-Warning 1264 Data truncated; out of range for column 't' at row 1
-Warning 1264 Data truncated; out of range for column 't' at row 2
-Warning 1264 Data truncated; out of range for column 't' at row 3
-Warning 1264 Data truncated; out of range for column 't' at row 4
-Warning 1264 Data truncated; out of range for column 't' at row 5
-Warning 1264 Data truncated; out of range for column 't' at row 6
+Warning 1264 Out of range value adjusted for column 't' at row 1
+Warning 1264 Out of range value adjusted for column 't' at row 2
+Warning 1264 Out of range value adjusted for column 't' at row 3
+Warning 1264 Out of range value adjusted for column 't' at row 4
+Warning 1264 Out of range value adjusted for column 't' at row 5
+Warning 1264 Out of range value adjusted for column 't' at row 6
select * from t1;
t
0000-00-00 00:00:00
@@ -136,8 +136,8 @@ t
delete from t1;
insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer");
Warnings:
-Warning 1264 Data truncated; out of range for column 't' at row 1
-Warning 1264 Data truncated; out of range for column 't' at row 2
+Warning 1264 Out of range value adjusted for column 't' at row 1
+Warning 1264 Out of range value adjusted for column 't' at row 2
select * from t1;
t
0000-00-00 00:00:00
diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result
index a9dcabd121e..a7b6fa1b376 100644
--- a/mysql-test/r/type_decimal.result
+++ b/mysql-test/r/type_decimal.result
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
SET SQL_WARNINGS=1;
CREATE TABLE t1 (
id int(11) NOT NULL auto_increment,
@@ -156,42 +156,62 @@ insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0");
insert into t1 values ("-.1"),("+.1"),(".1");
insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001");
insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11");
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1265 Data truncated for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Note 1265 Data truncated for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
+insert into t1 values ("1e+4294967296"),("1e-4294967296");
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Note 1265 Data truncated for column 'a' at row 2
+insert into t1 values ("1e+18446744073709551615"),("1e+18446744073709551616"),("1e-9223372036854775807"),("1e-9223372036854775809");
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1366 Incorrect decimal value: '1e+18446744073709551616' for column 'a' at row 2
+Note 1265 Data truncated for column 'a' at row 3
+Warning 1366 Incorrect decimal value: '1e-9223372036854775809' for column 'a' at row 4
insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0");
Warnings:
-Warning 1265 Data truncated for column 'a' at row 3
+Note 1265 Data truncated for column 'a' at row 1
+Note 1265 Data truncated for column 'a' at row 3
select * from t1;
a
0.00
--0.00
-+0.00
-01.00
-+01.00
--01.00
+0.00
+0.00
+1.00
+1.00
+-1.00
-0.10
-+0.10
0.10
-000000001.00
-+00000001.00
--00000001.00
-111111111.11
-111111111.11
+0.10
+1.00
+1.00
+-1.00
+99999999.99
+99999999.99
-11111111.11
-99999999.99
-999999999.99
-999999999.99
-999999999.99
+99999999.99
+99999999.99
+99999999.99
0.00
-99999999.99
+99999999.99
+0.00
+99999999.99
+0.00
+0.00
+0.00
123.40
12340.00
1.23
@@ -201,45 +221,46 @@ drop table t1;
create table t1 (a decimal(10,2) unsigned);
insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 6
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 6
insert into t1 values ("-.1"),("+.1"),(".1");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 1
insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1265 Data truncated for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Note 1265 Data truncated for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0");
Warnings:
-Warning 1265 Data truncated for column 'a' at row 3
+Note 1265 Data truncated for column 'a' at row 1
+Note 1265 Data truncated for column 'a' at row 3
select * from t1;
a
0.00
0.00
-+0.00
-01.00
-+01.00
+0.00
+1.00
+1.00
0.00
0.00
-+0.10
0.10
-00000001.00
-+0000001.00
+0.10
+1.00
+1.00
0.00
99999999.99
99999999.99
@@ -259,32 +280,33 @@ drop table t1;
create table t1 (a decimal(10,2) zerofill);
insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 6
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 6
insert into t1 values ("-.1"),("+.1"),(".1");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 1
insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000");
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1265 Data truncated for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Note 1265 Data truncated for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0");
Warnings:
-Warning 1265 Data truncated for column 'a' at row 3
+Note 1265 Data truncated for column 'a' at row 1
+Note 1265 Data truncated for column 'a' at row 3
select * from t1;
a
00000000.00
@@ -319,20 +341,27 @@ insert into t1 values (0.0),("-0.0"),(+0.0),(01.0),(+01.0),(-01.0);
insert into t1 values (-.1),(+.1),(.1);
insert into t1 values (00000000000001),(+0000000000001),(-0000000000001);
insert into t1 values (+111111111.11),(111111111.11),(-11111111.11);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
insert into t1 values (-111111111.11),(+1111111111.11),(1111111111.11);
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values (1e+100),(1e-100),(-1e+100);
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Note 1265 Data truncated for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0);
+Warnings:
+Note 1265 Data truncated for column 'a' at row 3
+insert into t1 values (MID("987",1,2)),("987 "),("987.6e+2 ");
select * from t1;
a
0.00
--0.00
+0.00
0.00
1.00
1.00
@@ -343,13 +372,13 @@ a
1.00
1.00
-1.00
-111111111.11
-111111111.11
+99999999.99
+99999999.99
-11111111.11
-99999999.99
-999999999.99
-999999999.99
-999999999.99
+99999999.99
+99999999.99
+99999999.99
0.00
-99999999.99
123.40
@@ -357,48 +386,52 @@ a
1.23
1230.00
123.00
+98.00
+987.00
+98760.00
drop table t1;
create table t1 (a decimal);
insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+12345678901'),(99999999999999);
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 7
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 6
+Warning 1264 Out of range value adjusted for column 'a' at row 7
select * from t1;
a
-9999999999
-1
-+1
-01
-+0000000001
-12345678901
-99999999999
+1
+1
+1
+9999999999
+9999999999
drop table t1;
create table t1 (a decimal unsigned);
insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999);
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 7
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 7
select * from t1;
a
-0
-0
-+1
-01
-+000000001
+9999999999
+9999999999
+1
+1
+1
1234567890
9999999999
drop table t1;
create table t1 (a decimal zerofill);
insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999);
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 7
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 7
select * from t1;
a
-0000000000
-0000000000
+9999999999
+9999999999
0000000001
0000000001
0000000001
@@ -408,13 +441,13 @@ drop table t1;
create table t1 (a decimal unsigned zerofill);
insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999);
Warnings:
-Warning 1264 Data truncated; out of range for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 7
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 7
select * from t1;
a
-0000000000
-0000000000
+9999999999
+9999999999
0000000001
0000000001
0000000001
@@ -424,19 +457,17 @@ drop table t1;
create table t1(a decimal(10,0));
insert into t1 values ("1e4294967295");
Warnings:
-Warning 1265 Data truncated for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 1
select * from t1;
a
-99999999999
+9999999999
delete from t1;
insert into t1 values("1e4294967297");
Warnings:
-Warning 1265 Data truncated for column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 1
select * from t1;
a
-99999999999
+9999999999
drop table t1;
CREATE TABLE t1 (a_dec DECIMAL(-1,0));
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,0))' at line 1
@@ -448,7 +479,7 @@ CREATE TABLE t1 (a_dec DECIMAL(0,11));
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a_dec` decimal(12,11) default NULL
+ `a_dec` decimal(11,11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
create table t1(a decimal(7,3));
@@ -456,64 +487,64 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000
select * from t1;
a
1.000
-+1.000
+1.000
+-1.000
+1.000
+1.000
-1.000
-00001.000
-+0001.000
--0001.000
10.000
-+10.000
+10.000
-10.000
-00010.000
-+0010.000
--0010.000
+10.000
+10.000
+-10.000
+100.000
100.000
-+100.000
-100.000
-00100.000
-+0100.000
--0100.000
+100.000
+100.000
+-100.000
+1000.000
1000.000
-+1000.000
-1000.000
-01000.000
-+1000.000
+1000.000
+1000.000
-1000.000
-10000.000
-10000.000
+9999.999
+9999.999
-9999.999
-10000.000
-10000.000
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
-99999.999
-99999.999
+9999.999
+9999.999
-9999.999
drop table t1;
create table t1(a decimal(7,3) unsigned);
@@ -521,22 +552,22 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000
select * from t1;
a
1.000
-+1.000
+1.000
0.000
-0001.000
-+001.000
+1.000
+1.000
0.000
10.000
-+10.000
+10.000
0.000
-0010.000
-+010.000
+10.000
+10.000
0.000
100.000
-+100.000
+100.000
0.000
-0100.000
-+100.000
+100.000
+100.000
0.000
1000.000
1000.000
@@ -646,3 +677,110 @@ a
9999.999
0000.000
drop table t1;
+CREATE TABLE t1
+(EMPNUM CHAR(3) NOT NULL,
+HOURS DECIMAL(5));
+CREATE TABLE t2
+(EMPNUM CHAR(3) NOT NULL,
+HOURS BIGINT);
+INSERT INTO t1 VALUES ('E1',40);
+INSERT INTO t1 VALUES ('E8',NULL);
+INSERT INTO t2 VALUES ('E1',40);
+SELECT EMPNUM FROM t1 WHERE HOURS IN (SELECT HOURS FROM t2);
+EMPNUM
+E1
+SELECT EMPNUM FROM t1 WHERE HOURS IN (SELECT HOURS FROM t1);
+EMPNUM
+E1
+DROP TABLE t1,t2;
+create table t1 (d decimal(64,0));
+insert into t1 values (1);
+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
+t1 CREATE TABLE `t1` (
+ `d` decimal(5,0) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (d decimal);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `d` decimal(10,0) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (d decimal(65,0));
+ERROR 42000: Incorrect column specifier for column 'd'
+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),
+(2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
+(4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
+(5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
+(6, 0.00, 0.00), (6, -51.40, 0.00);
+SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1 GROUP BY i HAVING a <> b;
+i a b
+6 -51.40 0.00
+SELECT i, ROUND(SUM(d1), 2) AS a, ROUND(SUM(d2), 2) AS b FROM t1 GROUP BY i
+HAVING a <> b;
+i a b
+6 -51.40 0.00
+drop table t1;
+create table t1 (c1 varchar(100), c2 longtext);
+insert into t1 set c1= 'non PS, 1.0 as constant', c2=1.0;
+prepare stmt from "insert into t1 set c1='PS, 1.0 as constant ', c2=1.0";
+execute stmt;
+set @a=1.0;
+insert into t1 set c1='non PS, 1.0 in parameter', c2=@a;
+prepare stmt from "insert into t1 set c1='PS, 1.0 in parameter ', c2=?";
+execute stmt using @a;
+select * from t1;
+c1 c2
+non PS, 1.0 as constant 1.0
+PS, 1.0 as constant 1.0
+non PS, 1.0 in parameter 1.0
+PS, 1.0 in parameter 1.0
+deallocate prepare stmt;
+drop table t1;
+create table t1 (
+strippedproductid char(15) not null default '',
+zlevelprice decimal(10,2) default null,
+primary key (strippedproductid)
+);
+create table t2 (
+productid char(15) not null default '',
+zlevelprice char(21) default null,
+primary key (productid)
+);
+insert into t1 values ('002trans','49.99');
+insert into t1 values ('003trans','39.98');
+insert into t1 values ('004trans','31.18');
+insert INTO t2 SELECT * FROM t1;
+select * from t2;
+productid zlevelprice
+002trans 49.99
+003trans 39.98
+004trans 31.18
+drop table t1, t2;
diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result
index ab3c441a7e2..f6cfa7f2733 100644
--- a/mysql-test/r/type_enum.result
+++ b/mysql-test/r/type_enum.result
@@ -1654,7 +1654,7 @@ set names latin1;
create table t1 (a enum(0xE4, '1', '2') not null default 0xE4);
show columns from t1;
Field Type Null Key Default Extra
-a enum('ä','1','2') ä
+a enum('ä','1','2') NO ä
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
@@ -1675,7 +1675,7 @@ t1 CREATE TABLE `t1` (
show columns from t1;
Field Type Null Key Default Extra
a int(11) YES 1
-b enum('value','öäü_value','ÊÃÕ') value
+b enum('value','öäü_value','ÊÃÕ') NO value
drop table t1;
CREATE TABLE t1 (c enum('a', 'A') BINARY);
INSERT INTO t1 VALUES ('a'),('A');
diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result
index 0906df8f621..3cdf35f5032 100644
--- a/mysql-test/r/type_float.result
+++ b/mysql-test/r/type_float.result
@@ -24,8 +24,8 @@ f1 float NULL YES NULL #
f2 double NULL YES NULL #
insert into t1 values(10,10),(1e+5,1e+5),(1234567890,1234567890),(1e+10,1e+10),(1e+15,1e+15),(1e+20,1e+20),(1e+50,1e+50),(1e+150,1e+150);
Warnings:
-Warning 1264 Data truncated; out of range for column 'f1' at row 7
-Warning 1264 Data truncated; out of range for column 'f1' at row 8
+Warning 1264 Out of range value adjusted for column 'f1' at row 7
+Warning 1264 Out of range value adjusted for column 'f1' at row 8
insert into t1 values(-10,-10),(1e-5,1e-5),(1e-10,1e-10),(1e-15,1e-15),(1e-20,1e-20),(1e-50,1e-50),(1e-150,1e-150);
select * from t1;
f1 f2
@@ -72,7 +72,7 @@ select a from t1 order by a;
a
-0.010
-0.002
--0.000
+0.000
0.000
1.000
select min(a) from t1;
@@ -125,7 +125,7 @@ select a from t1 order by a;
a
-0.010
-0.002
--0.000
+0.000
0.000
1.000
select min(a) from t1;
@@ -159,7 +159,7 @@ create table t1 (d1 double, d2 double unsigned);
insert into t1 set d1 = -1.0;
update t1 set d2 = d1;
Warnings:
-Warning 1264 Data truncated; out of range for column 'd2' at row 1
+Warning 1264 Out of range value adjusted for column 'd2' at row 1
select * from t1;
d1 d2
-1 0
@@ -167,12 +167,12 @@ drop table t1;
create table t1 (f float(4,3));
insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11");
Warnings:
-Warning 1264 Data truncated; out of range for column 'f' at row 1
-Warning 1264 Data truncated; out of range for column 'f' at row 2
-Warning 1264 Data truncated; out of range for column 'f' at row 3
-Warning 1264 Data truncated; out of range for column 'f' at row 4
-Warning 1264 Data truncated; out of range for column 'f' at row 5
-Warning 1264 Data truncated; out of range for column 'f' at row 6
+Warning 1264 Out of range value adjusted for column 'f' at row 1
+Warning 1264 Out of range value adjusted for column 'f' at row 2
+Warning 1264 Out of range value adjusted for column 'f' at row 3
+Warning 1264 Out of range value adjusted for column 'f' at row 4
+Warning 1264 Out of range value adjusted for column 'f' at row 5
+Warning 1264 Out of range value adjusted for column 'f' at row 6
select * from t1;
f
-9.999
@@ -185,12 +185,12 @@ drop table if exists t1;
create table t1 (f double(4,3));
insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11");
Warnings:
-Warning 1264 Data truncated; out of range for column 'f' at row 1
-Warning 1264 Data truncated; out of range for column 'f' at row 2
-Warning 1264 Data truncated; out of range for column 'f' at row 3
-Warning 1264 Data truncated; out of range for column 'f' at row 4
-Warning 1264 Data truncated; out of range for column 'f' at row 5
-Warning 1264 Data truncated; out of range for column 'f' at row 6
+Warning 1264 Out of range value adjusted for column 'f' at row 1
+Warning 1264 Out of range value adjusted for column 'f' at row 2
+Warning 1264 Out of range value adjusted for column 'f' at row 3
+Warning 1264 Out of range value adjusted for column 'f' at row 4
+Warning 1264 Out of range value adjusted for column 'f' at row 5
+Warning 1264 Out of range value adjusted for column 'f' at row 6
select * from t1;
f
-9.999
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
new file mode 100644
index 00000000000..330caf68293
--- /dev/null
+++ b/mysql-test/r/type_newdecimal.result
@@ -0,0 +1,844 @@
+drop table if exists t1;
+select 1.1 IN (1.0, 1.2);
+1.1 IN (1.0, 1.2)
+0
+select 1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5);
+1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5)
+1
+select 1.1 IN (1.0, 1.2, NULL, 1.4, 0.5);
+1.1 IN (1.0, 1.2, NULL, 1.4, 0.5)
+NULL
+select 0.5 IN (1.0, 1.2, NULL, 1.4, 0.5);
+0.5 IN (1.0, 1.2, NULL, 1.4, 0.5)
+1
+select 1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5);
+1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5)
+1
+select 1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5);
+1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5)
+NULL
+select case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END;
+case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END
+b
+select case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END;
+case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END
+a
+select case 1 when 0.1 then "a" when 1.0 then "b" else "c" END;
+case 1 when 0.1 then "a" when 1.0 then "b" else "c" END
+b
+select case 1.0 when 0.1 then "a" when 1 then "b" else "c" END;
+case 1.0 when 0.1 then "a" when 1 then "b" else "c" END
+b
+select case 1.001 when 0.1 then "a" when 1 then "b" else "c" END;
+case 1.001 when 0.1 then "a" when 1 then "b" else "c" END
+c
+create table t1 (a decimal(6,3));
+insert into t1 values (1.0), (NULL), (0.1);
+select * from t1;
+a
+1.000
+NULL
+0.100
+select 0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) from t1;
+0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5)
+0
+NULL
+1
+drop table t1;
+create table t1 select if(1, 1.1, 1.2), if(0, 1.1, 1.2), if(0.1, 1.1, 1.2), if(0, 1, 1.1), if(0, NULL, 1.2), if(1, 0.22e1, 1.1), if(1E0, 1.1, 1.2);
+select * from t1;
+if(1, 1.1, 1.2) if(0, 1.1, 1.2) if(0.1, 1.1, 1.2) if(0, 1, 1.1) if(0, NULL, 1.2) if(1, 0.22e1, 1.1) if(1E0, 1.1, 1.2)
+1.1 1.2 1.1 1.1 1.2 2.2 1.1
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `if(1, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0',
+ `if(0, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0',
+ `if(0.1, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0',
+ `if(0, 1, 1.1)` decimal(5,1) NOT NULL default '0.0',
+ `if(0, NULL, 1.2)` decimal(5,1) default NULL,
+ `if(1, 0.22e1, 1.1)` double NOT NULL default '0',
+ `if(1E0, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 select nullif(1.1, 1.1), nullif(1.1, 1.2), nullif(1.1, 0.11e1), nullif(1.0, 1), nullif(1, 1.0), nullif(1, 1.1);
+select * from t1;
+nullif(1.1, 1.1) nullif(1.1, 1.2) nullif(1.1, 0.11e1) nullif(1.0, 1) nullif(1, 1.0) nullif(1, 1.1)
+NULL 1.1 NULL NULL NULL 1
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `nullif(1.1, 1.1)` decimal(5,1) default NULL,
+ `nullif(1.1, 1.2)` decimal(5,1) default NULL,
+ `nullif(1.1, 0.11e1)` double(4,1) default NULL,
+ `nullif(1.0, 1)` decimal(5,1) default NULL,
+ `nullif(1, 1.0)` decimal(1,0) default NULL,
+ `nullif(1, 1.1)` decimal(1,0) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (a decimal(4,2));
+insert into t1 value (10000), (1.1e10), ("11111"), (100000.1);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+select a from t1;
+a
+99.99
+99.99
+99.99
+99.99
+-99.99
+-99.99
+-99.99
+-99.99
+drop table t1;
+create table t1 (a decimal(4,2) unsigned);
+insert into t1 value (10000), (1.1e10), ("11111"), (100000.1);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+select a from t1;
+a
+99.99
+99.99
+99.99
+99.99
+99.99
+0.00
+0.00
+0.00
+drop table t1;
+create table t1 (a bigint);
+insert into t1 values (18446744073709551615.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+insert into t1 values (9223372036854775808.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+insert into t1 values (-18446744073709551615.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+select * from t1;
+a
+9223372036854775807
+9223372036854775807
+-9223372036854775808
+drop table t1;
+create table t1 (a bigint unsigned);
+insert into t1 values (18446744073709551615.0);
+insert into t1 values (9223372036854775808.0);
+insert into t1 values (9999999999999999999999999.000);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+insert into t1 values (-1.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+select * from t1;
+a
+18446744073709551615
+9223372036854775808
+18446744073709551615
+0
+drop table t1;
+create table t1 (a tinyint);
+insert into t1 values (18446744073709551615.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+insert into t1 values (9223372036854775808.0);
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+select * from t1;
+a
+127
+127
+drop table t1;
+create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(-1.1);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `round(15.4,-1)` decimal(5,0) NOT NULL default '0',
+ `truncate(-5678.123451,-3)` decimal(13,0) NOT NULL default '0',
+ `abs(-1.1)` decimal(6,1) NOT NULL default '0.0',
+ `-(-1.1)` decimal(7,1) NOT NULL default '0.0'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+set session sql_mode='traditional';
+select 1e10/0e0;
+1e10/0e0
+NULL
+Warnings:
+Error 1365 Division by 0
+create table wl1612 (col1 int, col2 decimal(38,10), col3 numeric(38,10));
+insert into wl1612 values(1,12345678901234567890.1234567890,12345678901234567890.1234567890);
+select * from wl1612;
+col1 col2 col3
+1 12345678901234567890.1234567890 12345678901234567890.1234567890
+insert into wl1612 values(2,01234567890123456789.0123456789,01234567890123456789.0123456789);
+select * from wl1612 where col1=2;
+col1 col2 col3
+2 1234567890123456789.0123456789 1234567890123456789.0123456789
+insert into wl1612 values(3,1234567890123456789012345678.0123456789,1234567890123456789012345678.0123456789);
+select * from wl1612 where col1=3;
+col1 col2 col3
+3 1234567890123456789012345678.0123456789 1234567890123456789012345678.0123456789
+select col1/0 from wl1612;
+col1/0
+NULL
+NULL
+NULL
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+Error 1365 Division by 0
+select col2/0 from wl1612;
+col2/0
+NULL
+NULL
+NULL
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+Error 1365 Division by 0
+select col3/0 from wl1612;
+col3/0
+NULL
+NULL
+NULL
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+Error 1365 Division by 0
+insert into wl1612 values(5,5000.0005,5000.0005);
+insert into wl1612 values(6,5000.0005,5000.0005);
+select sum(col2),sum(col3) from wl1612;
+sum(col2) sum(col3)
+1234567903703703580370380357.1491481468 1234567903703703580370380357.1491481468
+insert into wl1612 values(7,500000.000005,500000.000005);
+insert into wl1612 values(8,500000.000005,500000.000005);
+select sum(col2),sum(col3) from wl1612 where col1>4;
+sum(col2) sum(col3)
+1010000.0010100000 1010000.0010100000
+insert into wl1612 (col1, col2) values(9,1.01234567891);
+Warnings:
+Note 1265 Data truncated for column 'col2' at row 1
+insert into wl1612 (col1, col2) values(10,1.01234567894);
+Warnings:
+Note 1265 Data truncated for column 'col2' at row 1
+insert into wl1612 (col1, col2) values(11,1.01234567895);
+Warnings:
+Note 1265 Data truncated for column 'col2' at row 1
+insert into wl1612 (col1, col2) values(12,1.01234567896);
+Warnings:
+Note 1265 Data truncated for column 'col2' at row 1
+select col1,col2 from wl1612 where col1>8;
+col1 col2
+9 1.0123456789
+10 1.0123456789
+11 1.0123456790
+12 1.0123456790
+insert into wl1612 (col1, col3) values(13,1.01234567891);
+Warnings:
+Note 1265 Data truncated for column 'col3' at row 1
+insert into wl1612 (col1, col3) values(14,1.01234567894);
+Warnings:
+Note 1265 Data truncated for column 'col3' at row 1
+insert into wl1612 (col1, col3) values(15,1.01234567895);
+Warnings:
+Note 1265 Data truncated for column 'col3' at row 1
+insert into wl1612 (col1, col3) values(16,1.01234567896);
+Warnings:
+Note 1265 Data truncated for column 'col3' at row 1
+select col1,col3 from wl1612 where col1>12;
+col1 col3
+13 1.0123456789
+14 1.0123456789
+15 1.0123456790
+16 1.0123456790
+select col1 from wl1612 where col1>4 and col2=1.01234567891;
+col1
+select col1 from wl1612 where col1>4 and col2=1.0123456789;
+col1
+9
+10
+select col1 from wl1612 where col1>4 and col2<>1.0123456789;
+col1
+5
+6
+7
+8
+11
+12
+select col1 from wl1612 where col1>4 and col2<1.0123456789;
+col1
+select col1 from wl1612 where col1>4 and col2<=1.0123456789;
+col1
+9
+10
+select col1 from wl1612 where col1>4 and col2>1.0123456789;
+col1
+5
+6
+7
+8
+11
+12
+select col1 from wl1612 where col1>4 and col2>=1.0123456789;
+col1
+5
+6
+7
+8
+9
+10
+11
+12
+select col1 from wl1612 where col1>4 and col2=1.012345679;
+col1
+11
+12
+select col1 from wl1612 where col1>4 and col2<>1.012345679;
+col1
+5
+6
+7
+8
+9
+10
+select col1 from wl1612 where col1>4 and col3=1.01234567891;
+col1
+select col1 from wl1612 where col1>4 and col3=1.0123456789;
+col1
+13
+14
+select col1 from wl1612 where col1>4 and col3<>1.0123456789;
+col1
+5
+6
+7
+8
+15
+16
+select col1 from wl1612 where col1>4 and col3<1.0123456789;
+col1
+select col1 from wl1612 where col1>4 and col3<=1.0123456789;
+col1
+13
+14
+select col1 from wl1612 where col1>4 and col3>1.0123456789;
+col1
+5
+6
+7
+8
+15
+16
+select col1 from wl1612 where col1>4 and col3>=1.0123456789;
+col1
+5
+6
+7
+8
+13
+14
+15
+16
+select col1 from wl1612 where col1>4 and col3=1.012345679;
+col1
+15
+16
+select col1 from wl1612 where col1>4 and col3<>1.012345679;
+col1
+5
+6
+7
+8
+13
+14
+drop table wl1612;
+select 1/3;
+1/3
+0.33333
+select 0.8=0.7+0.1;
+0.8=0.7+0.1
+1
+select 0.7+0.1;
+0.7+0.1
+0.8
+create table wl1612_1 (col1 int);
+insert into wl1612_1 values(10);
+select * from wl1612_1 where 0.8=0.7+0.1;
+col1
+10
+select 0.07+0.07 from wl1612_1;
+0.07+0.07
+0.14
+select 0.07-0.07 from wl1612_1;
+0.07-0.07
+0.00
+select 0.07*0.07 from wl1612_1;
+0.07*0.07
+0.0049
+select 0.07/0.07 from wl1612_1;
+0.07/0.07
+1.000000000
+drop table wl1612_1;
+create table wl1612_2 (col1 decimal(10,2), col2 numeric(10,2));
+insert into wl1612_2 values(1,1);
+insert into wl1612_2 values(+1,+1);
+insert into wl1612_2 values(+01,+01);
+insert into wl1612_2 values(+001,+001);
+select col1,count(*) from wl1612_2 group by col1;
+col1 count(*)
+1.00 4
+select col2,count(*) from wl1612_2 group by col2;
+col2 count(*)
+1.00 4
+drop table wl1612_2;
+create table wl1612_3 (col1 decimal(10,2), col2 numeric(10,2));
+insert into wl1612_3 values('1','1');
+insert into wl1612_3 values('+1','+1');
+insert into wl1612_3 values('+01','+01');
+insert into wl1612_3 values('+001','+001');
+select col1,count(*) from wl1612_3 group by col1;
+col1 count(*)
+1.00 4
+select col2,count(*) from wl1612_3 group by col2;
+col2 count(*)
+1.00 4
+drop table wl1612_3;
+select mod(234,10) ;
+mod(234,10)
+4
+select mod(234.567,10.555);
+mod(234.567,10.555)
+2.357
+select mod(-234.567,10.555);
+mod(-234.567,10.555)
+-2.357
+select mod(234.567,-10.555);
+mod(234.567,-10.555)
+2.357
+select round(15.1);
+round(15.1)
+15
+select round(15.4);
+round(15.4)
+15
+select round(15.5);
+round(15.5)
+16
+select round(15.6);
+round(15.6)
+16
+select round(15.9);
+round(15.9)
+16
+select round(-15.1);
+round(-15.1)
+-15
+select round(-15.4);
+round(-15.4)
+-15
+select round(-15.5);
+round(-15.5)
+-16
+select round(-15.6);
+round(-15.6)
+-16
+select round(-15.9);
+round(-15.9)
+-16
+select round(15.1,1);
+round(15.1,1)
+15.1
+select round(15.4,1);
+round(15.4,1)
+15.4
+select round(15.5,1);
+round(15.5,1)
+15.5
+select round(15.6,1);
+round(15.6,1)
+15.6
+select round(15.9,1);
+round(15.9,1)
+15.9
+select round(-15.1,1);
+round(-15.1,1)
+-15.1
+select round(-15.4,1);
+round(-15.4,1)
+-15.4
+select round(-15.5,1);
+round(-15.5,1)
+-15.5
+select round(-15.6,1);
+round(-15.6,1)
+-15.6
+select round(-15.9,1);
+round(-15.9,1)
+-15.9
+select round(15.1,0);
+round(15.1,0)
+15
+select round(15.4,0);
+round(15.4,0)
+15
+select round(15.5,0);
+round(15.5,0)
+16
+select round(15.6,0);
+round(15.6,0)
+16
+select round(15.9,0);
+round(15.9,0)
+16
+select round(-15.1,0);
+round(-15.1,0)
+-15
+select round(-15.4,0);
+round(-15.4,0)
+-15
+select round(-15.5,0);
+round(-15.5,0)
+-16
+select round(-15.6,0);
+round(-15.6,0)
+-16
+select round(-15.9,0);
+round(-15.9,0)
+-16
+select round(15.1,-1);
+round(15.1,-1)
+20
+select round(15.4,-1);
+round(15.4,-1)
+20
+select round(15.5,-1);
+round(15.5,-1)
+20
+select round(15.6,-1);
+round(15.6,-1)
+20
+select round(15.9,-1);
+round(15.9,-1)
+20
+select round(-15.1,-1);
+round(-15.1,-1)
+-20
+select round(-15.4,-1);
+round(-15.4,-1)
+-20
+select round(-15.5,-1);
+round(-15.5,-1)
+-20
+select round(-15.6,-1);
+round(-15.6,-1)
+-20
+select round(-15.91,-1);
+round(-15.91,-1)
+-20
+select truncate(5678.123451,0);
+truncate(5678.123451,0)
+5678
+select truncate(5678.123451,1);
+truncate(5678.123451,1)
+5678.1
+select truncate(5678.123451,2);
+truncate(5678.123451,2)
+5678.12
+select truncate(5678.123451,3);
+truncate(5678.123451,3)
+5678.123
+select truncate(5678.123451,4);
+truncate(5678.123451,4)
+5678.1234
+select truncate(5678.123451,5);
+truncate(5678.123451,5)
+5678.12345
+select truncate(5678.123451,6);
+truncate(5678.123451,6)
+5678.123451
+select truncate(5678.123451,-1);
+truncate(5678.123451,-1)
+5670
+select truncate(5678.123451,-2);
+truncate(5678.123451,-2)
+5600
+select truncate(5678.123451,-3);
+truncate(5678.123451,-3)
+5000
+select truncate(5678.123451,-4);
+truncate(5678.123451,-4)
+0
+select truncate(-5678.123451,0);
+truncate(-5678.123451,0)
+-5678
+select truncate(-5678.123451,1);
+truncate(-5678.123451,1)
+-5678.1
+select truncate(-5678.123451,2);
+truncate(-5678.123451,2)
+-5678.12
+select truncate(-5678.123451,3);
+truncate(-5678.123451,3)
+-5678.123
+select truncate(-5678.123451,4);
+truncate(-5678.123451,4)
+-5678.1234
+select truncate(-5678.123451,5);
+truncate(-5678.123451,5)
+-5678.12345
+select truncate(-5678.123451,6);
+truncate(-5678.123451,6)
+-5678.123451
+select truncate(-5678.123451,-1);
+truncate(-5678.123451,-1)
+-5670
+select truncate(-5678.123451,-2);
+truncate(-5678.123451,-2)
+-5600
+select truncate(-5678.123451,-3);
+truncate(-5678.123451,-3)
+-5000
+select truncate(-5678.123451,-4);
+truncate(-5678.123451,-4)
+0
+create table wl1612_4 (col1 int, col2 decimal(30,25), col3 numeric(30,25));
+insert into wl1612_4 values(1,0.0123456789012345678912345,0.0123456789012345678912345);
+select col2/9999999999 from wl1612_4 where col1=1;
+col2/9999999999
+0.0000000000012345678902469135781481410000000000000000000
+select col3/9999999999 from wl1612_4 where col1=1;
+col3/9999999999
+0.0000000000012345678902469135781481410000000000000000000
+select 9999999999/col2 from wl1612_4 where col1=1;
+9999999999/col2
+810000007209.00007
+select 9999999999/col3 from wl1612_4 where col1=1;
+9999999999/col3
+810000007209.00007
+select col2*9999999999 from wl1612_4 where col1=1;
+col2*9999999999
+123456789.0000000000111104321087655
+select col3*9999999999 from wl1612_4 where col1=1;
+col3*9999999999
+123456789.0000000000111104321087655
+insert into wl1612_4 values(2,55555.0123456789012345678912345,55555.0123456789012345678912345);
+select col2/9999999999 from wl1612_4 where col1=2;
+col2/9999999999
+0.0000055555012351234402469691331481460000000000000000000
+select col3/9999999999 from wl1612_4 where col1=2;
+col3/9999999999
+0.0000055555012351234402469691331481460000000000000000000
+select 9999999999/col2 from wl1612_4 where col1=2;
+9999999999/col2
+180001.76000
+select 9999999999/col3 from wl1612_4 where col1=2;
+9999999999/col3
+180001.76000
+select col2*9999999999 from wl1612_4 where col1=2;
+col2*9999999999
+555550123401234.0000000000111104321087655
+select col3*9999999999 from wl1612_4 where col1=2;
+col3*9999999999
+555550123401234.0000000000111104321087655
+drop table wl1612_4;
+set sql_mode='';
+select 23.4 + (-41.7), 23.4 - (41.7) = -18.3;
+23.4 + (-41.7) 23.4 - (41.7) = -18.3
+-18.3 1
+select -18.3=-18.3;
+-18.3=-18.3
+1
+select 18.3=18.3;
+18.3=18.3
+1
+select -18.3=18.3;
+-18.3=18.3
+0
+select 0.8 = 0.7 + 0.1;
+0.8 = 0.7 + 0.1
+1
+create procedure p1 () begin
+declare v1, v2, v3, v4 decimal(16,12); declare v5 int;
+set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0;
+while v5 < 100000 do
+set v1 = v1 + 0.000000000001; set v2 = v2 - 0.000000000001; set v3 = v3 + 1; set v4 = v4 - 1; set v5 = v5 + 1;
+end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;//
+#
+call p1()//
+#
+v1 v2 v3 * 0.000000000001 v4 * 0.000000000001
+1.000000100000 1.999999900000 1.000000100000 1.999999900000
+drop procedure p1;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+create table t1 (col1 decimal(38));
+insert into t1 values (12345678901234567890123456789012345678);
+select * from t1;
+col1
+12345678901234567890123456789012345678
+drop table t1;
+create table t1 (col1 decimal(31,30));
+insert into t1 values (0.00000000001);
+select * from t1;
+col1
+0.000000000010000000000000000000
+drop table t1;
+select 7777777777777777777777777777777777777 * 10;
+7777777777777777777777777777777777777 * 10
+77777777777777777777777777777777777770
+select .7777777777777777777777777777777777777 *
+1000000000000000000;
+.7777777777777777777777777777777777777 *
+1000000000000000000
+777777777777777777.7777777777777777777000000000000000000
+select .7777777777777777777777777777777777777 - 0.1;
+.7777777777777777777777777777777777777 - 0.1
+0.6777777777777777777777777777777777777
+select .343434343434343434 + .343434343434343434;
+.343434343434343434 + .343434343434343434
+0.686868686868686868
+select abs(9999999999999999999999);
+abs(9999999999999999999999)
+9999999999999999999999
+select abs(-9999999999999999999999);
+abs(-9999999999999999999999)
+9999999999999999999999
+select ceiling(999999999999999999);
+ceiling(999999999999999999)
+999999999999999999
+select ceiling(99999999999999999999);
+ceiling(99999999999999999999)
+99999999999999999999
+select ceiling(9.9999999999999999999);
+ceiling(9.9999999999999999999)
+10
+select ceiling(-9.9999999999999999999);
+ceiling(-9.9999999999999999999)
+-9
+select floor(999999999999999999);
+floor(999999999999999999)
+999999999999999999
+select floor(9999999999999999999999);
+floor(9999999999999999999999)
+9999999999999999999999
+select floor(9.999999999999999999999);
+floor(9.999999999999999999999)
+9
+select floor(-9.999999999999999999999);
+floor(-9.999999999999999999999)
+-10
+select floor(-999999999999999999999.999);
+floor(-999999999999999999999.999)
+-1000000000000000000000
+select ceiling(999999999999999999999.999);
+ceiling(999999999999999999999.999)
+1000000000000000000000
+select 99999999999999999999999999999999999999 mod 3;
+99999999999999999999999999999999999999 mod 3
+0
+select round(99999999999999999.999);
+round(99999999999999999.999)
+100000000000000000
+select round(-99999999999999999.999);
+round(-99999999999999999.999)
+-100000000000000000
+select round(99999999999999999.999,3);
+round(99999999999999999.999,3)
+99999999999999999.999
+select round(-99999999999999999.999,3);
+round(-99999999999999999.999,3)
+-99999999999999999.999
+select truncate(99999999999999999999999999999999999999,31);
+truncate(99999999999999999999999999999999999999,31)
+99999999999999999999999999999999999999.000000000000000000000000000
+select truncate(99.999999999999999999999999999999999999,31);
+truncate(99.999999999999999999999999999999999999,31)
+99.9999999999999999999999999999999
+select truncate(99999999999999999999999999999999999999,-31);
+truncate(99999999999999999999999999999999999999,-31)
+99999990000000000000000000000000000000
+create table t1 as select 0.5;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `0.5` decimal(3,1) NOT NULL default '0.0'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+select round(1.5),round(2.5);
+round(1.5) round(2.5)
+2 3
+select 0.07 * 0.07;
+0.07 * 0.07
+0.0049
+set sql_mode='traditional';
+select 1E-500 = 0;
+1E-500 = 0
+1
+select 1 / 1E-500;
+1 / 1E-500
+NULL
+Warnings:
+Error 1365 Division by 0
+select 1 / 0;
+1 / 0
+NULL
+Warnings:
+Error 1365 Division by 0
+set sql_mode='ansi,traditional';
+CREATE TABLE Sow6_2f (col1 NUMERIC(4,2));
+INSERT INTO Sow6_2f VALUES (10.55);
+INSERT INTO Sow6_2f VALUES (10.5555);
+Warnings:
+Note 1265 Data truncated for column 'col1' at row 1
+INSERT INTO Sow6_2f VALUES (-10.55);
+INSERT INTO Sow6_2f VALUES (-10.5555);
+Warnings:
+Note 1265 Data truncated for column 'col1' at row 1
+INSERT INTO Sow6_2f VALUES (11);
+INSERT INTO Sow6_2f VALUES (101.55);
+ERROR 22003: Out of range value adjusted for column 'col1' at row 1
+UPDATE Sow6_2f SET col1 = col1 * 50 WHERE col1 = 11;
+ERROR 22003: Out of range value adjusted for column 'col1' at row 5
+UPDATE Sow6_2f SET col1 = col1 / 0 WHERE col1 > 0;
+ERROR 22012: Division by 0
+SELECT MOD(col1,0) FROM Sow6_2f;
+MOD(col1,0)
+NULL
+NULL
+NULL
+NULL
+NULL
+Warnings:
+Error 1365 Division by 0
+Error 1365 Division by 0
+Error 1365 Division by 0
+Error 1365 Division by 0
+Error 1365 Division by 0
+INSERT INTO Sow6_2f VALUES ('a59b');
+ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1
+drop table Sow6_2f;
+select 10.3330000000000/12.34500000;
+10.3330000000000/12.34500000
+0.8370190360469825840421223160000
diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result
index 90207f39417..3b07464c8f4 100644
--- a/mysql-test/r/type_ranges.result
+++ b/mysql-test/r/type_ranges.result
@@ -21,10 +21,10 @@ time_field time,
date_time datetime,
blob_col blob,
tinyblob_col tinyblob,
-mediumblob_col mediumblob not null,
-longblob_col longblob not null,
-options enum('one','two','tree') not null,
-flags set('one','two','tree') not null,
+mediumblob_col mediumblob not null default '',
+longblob_col longblob not null default '',
+options enum('one','two','tree') not null ,
+flags set('one','two','tree') not null default '',
PRIMARY KEY (auto),
KEY (utiny),
KEY (tiny),
@@ -40,30 +40,30 @@ KEY (options,flags)
);
show full fields from t1;
Field Type Collation Null Key Default Extra Privileges Comment
-auto int(5) unsigned NULL PRI NULL auto_increment #
-string varchar(10) latin1_swedish_ci YES hello #
-tiny tinyint(4) NULL MUL 0 #
-short smallint(6) NULL MUL 1 #
-medium mediumint(8) NULL MUL 0 #
-long_int int(11) NULL 0 #
-longlong bigint(13) NULL MUL 0 #
-real_float float(13,1) NULL MUL 0.0 #
+auto int(5) unsigned NULL NO PRI NULL auto_increment #
+string char(10) latin1_swedish_ci YES hello #
+tiny tinyint(4) NULL NO MUL 0 #
+short smallint(6) NULL NO MUL 1 #
+medium mediumint(8) NULL NO MUL 0 #
+long_int int(11) NULL NO 0 #
+longlong bigint(13) NULL NO MUL 0 #
+real_float float(13,1) NULL NO MUL 0.0 #
real_double double(16,4) NULL YES NULL #
-utiny tinyint(3) unsigned NULL MUL 0 #
-ushort smallint(5) unsigned zerofill NULL MUL 00000 #
-umedium mediumint(8) unsigned NULL MUL 0 #
-ulong int(11) unsigned NULL MUL 0 #
-ulonglong bigint(13) unsigned NULL MUL 0 #
+utiny tinyint(3) unsigned NULL NO MUL 0 #
+ushort smallint(5) unsigned zerofill NULL NO MUL 00000 #
+umedium mediumint(8) unsigned NULL NO MUL 0 #
+ulong int(11) unsigned NULL NO MUL 0 #
+ulonglong bigint(13) unsigned NULL NO MUL 0 #
time_stamp timestamp NULL YES CURRENT_TIMESTAMP #
date_field date NULL YES NULL #
time_field time NULL YES NULL #
date_time datetime NULL YES NULL #
blob_col blob NULL YES NULL #
tinyblob_col tinyblob NULL YES NULL #
-mediumblob_col mediumblob NULL #
-longblob_col longblob NULL #
-options enum('one','two','tree') latin1_swedish_ci MUL one #
-flags set('one','two','tree') latin1_swedish_ci #
+mediumblob_col mediumblob NULL NO #
+longblob_col longblob NULL NO #
+options enum('one','two','tree') latin1_swedish_ci NO MUL one #
+flags set('one','two','tree') latin1_swedish_ci NO #
show keys from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
t1 0 PRIMARY 1 auto A 0 NULL NULL BTREE
@@ -87,42 +87,44 @@ DROP INDEX test ON t1;
insert into t1 values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one');
insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,NULL,2,2,'two','two,one');
insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3);
+Warnings:
+Warning 1265 Data truncated for column 'string' at row 1
insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1);
Warnings:
-Warning 1264 Data truncated; out of range for column 'utiny' at row 1
-Warning 1264 Data truncated; out of range for column 'ushort' at row 1
-Warning 1264 Data truncated; out of range for column 'umedium' at row 1
-Warning 1264 Data truncated; out of range for column 'ulong' at row 1
+Warning 1264 Out of range value adjusted for column 'utiny' at row 1
+Warning 1264 Out of range value adjusted for column 'ushort' at row 1
+Warning 1264 Out of range value adjusted for column 'umedium' at row 1
+Warning 1264 Out of range value adjusted for column 'ulong' at row 1
Warning 1265 Data truncated for column 'options' at row 1
Warning 1265 Data truncated for column 'flags' at row 1
insert into t1 values (0,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,NULL,0,0,0,-4294967295,-4294967295,-4294967295,'-4294967295',0,"one,two,tree");
Warnings:
Warning 1265 Data truncated for column 'string' at row 1
-Warning 1264 Data truncated; out of range for column 'tiny' at row 1
-Warning 1264 Data truncated; out of range for column 'short' at row 1
-Warning 1264 Data truncated; out of range for column 'medium' at row 1
-Warning 1264 Data truncated; out of range for column 'long_int' at row 1
-Warning 1264 Data truncated; out of range for column 'utiny' at row 1
-Warning 1264 Data truncated; out of range for column 'ushort' at row 1
-Warning 1264 Data truncated; out of range for column 'umedium' at row 1
-Warning 1264 Data truncated; out of range for column 'ulong' at row 1
+Warning 1264 Out of range value adjusted for column 'tiny' at row 1
+Warning 1264 Out of range value adjusted for column 'short' at row 1
+Warning 1264 Out of range value adjusted for column 'medium' at row 1
+Warning 1264 Out of range value adjusted for column 'long_int' at row 1
+Warning 1264 Out of range value adjusted for column 'utiny' at row 1
+Warning 1264 Out of range value adjusted for column 'ushort' at row 1
+Warning 1264 Out of range value adjusted for column 'umedium' at row 1
+Warning 1264 Out of range value adjusted for column 'ulong' at row 1
Warning 1265 Data truncated for column 'options' at row 1
insert into t1 values (0,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,NULL,0,0,0,4294967295,4294967295,4294967295,'4294967295',0,0);
Warnings:
-Warning 1264 Data truncated; out of range for column 'tiny' at row 1
-Warning 1264 Data truncated; out of range for column 'short' at row 1
-Warning 1264 Data truncated; out of range for column 'medium' at row 1
-Warning 1264 Data truncated; out of range for column 'long_int' at row 1
-Warning 1264 Data truncated; out of range for column 'utiny' at row 1
-Warning 1264 Data truncated; out of range for column 'ushort' at row 1
-Warning 1264 Data truncated; out of range for column 'umedium' at row 1
+Warning 1264 Out of range value adjusted for column 'tiny' at row 1
+Warning 1264 Out of range value adjusted for column 'short' at row 1
+Warning 1264 Out of range value adjusted for column 'medium' at row 1
+Warning 1264 Out of range value adjusted for column 'long_int' at row 1
+Warning 1264 Out of range value adjusted for column 'utiny' at row 1
+Warning 1264 Out of range value adjusted for column 'ushort' at row 1
+Warning 1264 Out of range value adjusted for column 'umedium' at row 1
Warning 1265 Data truncated for column 'options' at row 1
insert into t1 (tiny) values (1);
select auto,string,tiny,short,medium,long_int,longlong,real_float,real_double,utiny,ushort,umedium,ulong,ulonglong,mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000),date_field,time_field,date_time,blob_col,tinyblob_col,mediumblob_col,longblob_col from t1;
auto string tiny short medium long_int longlong real_float real_double utiny ushort umedium ulong ulonglong mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000) date_field time_field date_time blob_col tinyblob_col mediumblob_col longblob_col
10 1 1 1 1 1 1 1.0 1.0000 1 00001 1 1 1 0 0000-00-00 00:00:00 0000-00-00 00:00:00 1 1 1 1
11 2 2 2 2 2 2 2.0 2.0000 2 00002 2 2 2 0 NULL NULL NULL NULL NULL 2 2
-12 0.33 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3
+12 0.33333333 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3
13 -1 -1 -1 -1 -1 -1 -1.0 -1.0000 0 00000 0 0 18446744073709551615 0 1997-08-07 08:07:06 1997-04-03 09:08:07 -1 -1 -1 -1
14 -429496729 -128 -32768 -8388608 -2147483648 -4294967295 -4294967296.0 -4294967295.0000 0 00000 0 0 18446744069414584321 0 0000-00-00 00:00:00 0000-00-00 00:00:00 -4294967295 -4294967295 -4294967295 -4294967295
15 4294967295 127 32767 8388607 2147483647 4294967295 4294967296.0 4294967295.0000 255 65535 16777215 4294967295 4294967295 0 0000-00-00 00:00:00 0000-00-00 00:00:00 4294967295 4294967295 4294967295 4294967295
@@ -131,7 +133,7 @@ ALTER TABLE t1
add new_field char(10) default "new" not null,
change blob_col new_blob_col varchar(20),
change date_field date_field char(10),
-alter column string set default "new default",
+alter column string set default "newdefault",
alter short drop default,
DROP INDEX utiny,
DROP INDEX ushort,
@@ -174,7 +176,7 @@ Warning 1265 Data truncated for column 'new_field' at row 7
select * from t2;
auto string mediumblob_col new_field
1 2 2 ne
-2 0.33 ne
+2 0.33333333 ne
3 -1 -1 ne
4 -429496729 -4294967295 ne
5 4294967295 4294967295 ne
@@ -208,56 +210,56 @@ Warning 1265 Data truncated for column 'options' at row 6
update t2 set string="changed" where auto=16;
show full columns from t1;
Field Type Collation Null Key Default Extra Privileges Comment
-auto int(5) unsigned NULL MUL NULL auto_increment #
-string varchar(10) latin1_swedish_ci YES new defaul #
-tiny tinyint(4) NULL MUL 0 #
-short smallint(6) NULL MUL 0 #
-medium mediumint(8) NULL MUL 0 #
-long_int int(11) NULL 0 #
-longlong bigint(13) NULL MUL 0 #
-real_float float(13,1) NULL MUL 0.0 #
+auto int(5) unsigned NULL NO MUL NULL auto_increment #
+string char(10) latin1_swedish_ci YES newdefault #
+tiny tinyint(4) NULL NO MUL 0 #
+short smallint(6) NULL NO MUL 0 #
+medium mediumint(8) NULL NO MUL 0 #
+long_int int(11) NULL NO 0 #
+longlong bigint(13) NULL NO MUL 0 #
+real_float float(13,1) NULL NO MUL 0.0 #
real_double double(16,4) NULL YES NULL #
-utiny tinyint(3) unsigned NULL 0 #
-ushort smallint(5) unsigned zerofill NULL 00000 #
-umedium mediumint(8) unsigned NULL MUL 0 #
-ulong int(11) unsigned NULL MUL 0 #
-ulonglong bigint(13) unsigned NULL MUL 0 #
+utiny tinyint(3) unsigned NULL NO 0 #
+ushort smallint(5) unsigned zerofill NULL NO 00000 #
+umedium mediumint(8) unsigned NULL NO MUL 0 #
+ulong int(11) unsigned NULL NO MUL 0 #
+ulonglong bigint(13) unsigned NULL NO MUL 0 #
time_stamp timestamp NULL YES CURRENT_TIMESTAMP #
-date_field varchar(10) latin1_swedish_ci YES NULL #
+date_field char(10) latin1_swedish_ci YES NULL #
time_field time NULL YES NULL #
date_time datetime NULL YES NULL #
new_blob_col varchar(20) latin1_swedish_ci YES NULL #
tinyblob_col tinyblob NULL YES NULL #
-mediumblob_col mediumblob NULL #
-options enum('one','two','tree') latin1_swedish_ci MUL one #
-flags set('one','two','tree') latin1_swedish_ci #
-new_field varchar(10) latin1_swedish_ci new #
+mediumblob_col mediumblob NULL NO #
+options enum('one','two','tree') latin1_swedish_ci NO MUL one #
+flags set('one','two','tree') latin1_swedish_ci NO #
+new_field char(10) latin1_swedish_ci NO new #
show full columns from t2;
Field Type Collation Null Key Default Extra Privileges Comment
-auto int(5) unsigned NULL 0 #
-string varchar(10) latin1_swedish_ci YES new defaul #
-tiny tinyint(4) NULL 0 #
-short smallint(6) NULL 0 #
-medium mediumint(8) NULL 0 #
-long_int int(11) NULL 0 #
-longlong bigint(13) NULL 0 #
-real_float float(13,1) NULL 0.0 #
+auto int(5) unsigned NULL NO 0 #
+string char(10) latin1_swedish_ci YES newdefault #
+tiny tinyint(4) NULL NO 0 #
+short smallint(6) NULL NO 0 #
+medium mediumint(8) NULL NO 0 #
+long_int int(11) NULL NO 0 #
+longlong bigint(13) NULL NO 0 #
+real_float float(13,1) NULL NO 0.0 #
real_double double(16,4) NULL YES NULL #
-utiny tinyint(3) unsigned NULL 0 #
-ushort smallint(5) unsigned zerofill NULL 00000 #
-umedium mediumint(8) unsigned NULL 0 #
-ulong int(11) unsigned NULL 0 #
-ulonglong bigint(13) unsigned NULL 0 #
+utiny tinyint(3) unsigned NULL NO 0 #
+ushort smallint(5) unsigned zerofill NULL NO 00000 #
+umedium mediumint(8) unsigned NULL NO 0 #
+ulong int(11) unsigned NULL NO 0 #
+ulonglong bigint(13) unsigned NULL NO 0 #
time_stamp timestamp NULL YES 0000-00-00 00:00:00 #
-date_field varchar(10) latin1_swedish_ci YES NULL #
+date_field char(10) latin1_swedish_ci YES NULL #
time_field time NULL YES NULL #
date_time datetime NULL YES NULL #
new_blob_col varchar(20) latin1_swedish_ci YES NULL #
tinyblob_col tinyblob NULL YES NULL #
-mediumblob_col mediumblob NULL #
-options enum('one','two','tree') latin1_swedish_ci one #
-flags set('one','two','tree') latin1_swedish_ci #
-new_field varchar(10) latin1_swedish_ci new #
+mediumblob_col mediumblob NULL NO #
+options enum('one','two','tree') latin1_swedish_ci NO one #
+flags set('one','two','tree') latin1_swedish_ci NO #
+new_field char(10) latin1_swedish_ci NO new #
select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and ((t1.string<>t2.string and (t1.string is not null or t2.string is not null)) or (t1.tiny<>t2.tiny and (t1.tiny is not null or t2.tiny is not null)) or (t1.short<>t2.short and (t1.short is not null or t2.short is not null)) or (t1.medium<>t2.medium and (t1.medium is not null or t2.medium is not null)) or (t1.long_int<>t2.long_int and (t1.long_int is not null or t2.long_int is not null)) or (t1.longlong<>t2.longlong and (t1.longlong is not null or t2.longlong is not null)) or (t1.real_float<>t2.real_float and (t1.real_float is not null or t2.real_float is not null)) or (t1.real_double<>t2.real_double and (t1.real_double is not null or t2.real_double is not null)) or (t1.utiny<>t2.utiny and (t1.utiny is not null or t2.utiny is not null)) or (t1.ushort<>t2.ushort and (t1.ushort is not null or t2.ushort is not null)) or (t1.umedium<>t2.umedium and (t1.umedium is not null or t2.umedium is not null)) or (t1.ulong<>t2.ulong and (t1.ulong is not null or t2.ulong is not null)) or (t1.ulonglong<>t2.ulonglong and (t1.ulonglong is not null or t2.ulonglong is not null)) or (t1.time_stamp<>t2.time_stamp and (t1.time_stamp is not null or t2.time_stamp is not null)) or (t1.date_field<>t2.date_field and (t1.date_field is not null or t2.date_field is not null)) or (t1.time_field<>t2.time_field and (t1.time_field is not null or t2.time_field is not null)) or (t1.date_time<>t2.date_time and (t1.date_time is not null or t2.date_time is not null)) or (t1.new_blob_col<>t2.new_blob_col and (t1.new_blob_col is not null or t2.new_blob_col is not null)) or (t1.tinyblob_col<>t2.tinyblob_col and (t1.tinyblob_col is not null or t2.tinyblob_col is not null)) or (t1.mediumblob_col<>t2.mediumblob_col and (t1.mediumblob_col is not null or t2.mediumblob_col is not null)) or (t1.options<>t2.options and (t1.options is not null or t2.options is not null)) or (t1.flags<>t2.flags and (t1.flags is not null or t2.flags is not null)) or (t1.new_field<>t2.new_field and (t1.new_field is not null or t2.new_field is not null)));
auto auto
16 16
@@ -265,23 +267,27 @@ select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and not (t1.string<=>t2.
auto auto
16 16
drop table t2;
-create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, "a" as t2, repeat("a",256) as t3, binary repeat("b",256) as t4 from t1;
+create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1;
show full columns from t2;
Field Type Collation Null Key Default Extra Privileges Comment
-auto bigint(17) unsigned NULL PRI 0 #
-t1 bigint(1) NULL 0 #
-t2 char(1) latin1_swedish_ci #
-t3 longtext latin1_swedish_ci #
-t4 longblob NULL #
-select * from t2;
-auto t1 t2 t3 t4
-11 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-12 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-13 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-14 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-15 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-16 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-17 1 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+auto int(6) unsigned NULL NO PRI 0 #
+t1 bigint(1) NULL NO 0 #
+t2 varchar(1) latin1_swedish_ci NO #
+t3 varchar(256) latin1_swedish_ci NO #
+t4 varbinary(256) NULL NO #
+t5 longtext latin1_swedish_ci NO #
+t6 longblob NULL NO #
+t7 char(0) latin1_swedish_ci NO #
+t8 binary(0) NULL NO #
+select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2;
+t1 t2 length(t3) length(t4) length(t5) length(t6) t7 t8
+1 a 256 256 4096 4096
+1 a 256 256 4096 4096
+1 a 256 256 4096 4096
+1 a 256 256 4096 4096
+1 a 256 256 4096 4096
+1 a 256 256 4096 4096
+1 a 256 256 4096 4096
drop table t1,t2;
create table t1 (c int);
insert into t1 values(1),(2);
@@ -293,7 +299,7 @@ show full columns from t3;
Field Type Collation Null Key Default Extra Privileges Comment
c1 int(11) NULL YES NULL #
c2 int(11) NULL YES NULL #
-const bigint(1) NULL 0 #
+const bigint(1) NULL NO 0 #
drop table t1,t2,t3;
create table t1 ( myfield INT NOT NULL, UNIQUE INDEX (myfield), unique (myfield), index(myfield));
drop table t1;
diff --git a/mysql-test/r/type_set.result b/mysql-test/r/type_set.result
index 5aedefda283..fdda4aca25c 100644
--- a/mysql-test/r/type_set.result
+++ b/mysql-test/r/type_set.result
@@ -3,7 +3,7 @@ create table t1 (a set (' ','a','b') not null);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` set('','a','b') NOT NULL default ''
+ `a` set('','a','b') NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (a set (' ','a','b ') not null default 'b ');
diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result
index 025cf2a57f1..442435b0459 100644
--- a/mysql-test/r/type_time.result
+++ b/mysql-test/r/type_time.result
@@ -26,9 +26,9 @@ t
insert into t1 values("10.22.22"),(1234567),(123456789),(123456789.10),("10 22:22"),("12.45a");
Warnings:
Warning 1265 Data truncated for column 't' at row 1
-Warning 1264 Data truncated; out of range for column 't' at row 2
-Warning 1264 Data truncated; out of range for column 't' at row 3
-Warning 1264 Data truncated; out of range for column 't' at row 4
+Warning 1264 Out of range value adjusted for column 't' at row 2
+Warning 1264 Out of range value adjusted for column 't' at row 3
+Warning 1264 Out of range value adjusted for column 't' at row 4
Warning 1265 Data truncated for column 't' at row 6
select * from t1;
t
diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result
index c0396e4640d..9b851d74a12 100644
--- a/mysql-test/r/type_timestamp.result
+++ b/mysql-test/r/type_timestamp.result
@@ -35,6 +35,10 @@ UPDATE t1 SET value="my value" WHERE id="myKey";
SELECT stamp FROM t1 WHERE id="myKey";
stamp
1999-04-02 00:00:00
+UPDATE t1 SET id="myKey" WHERE value="my value";
+SELECT stamp FROM t1 WHERE id="myKey";
+stamp
+1999-04-02 00:00:00
drop table t1;
create table t1 (a timestamp);
insert into t1 values (now());
diff --git a/mysql-test/r/type_uint.result b/mysql-test/r/type_uint.result
index d8edf9085b7..0474f3a24f4 100644
--- a/mysql-test/r/type_uint.result
+++ b/mysql-test/r/type_uint.result
@@ -4,10 +4,10 @@ create table t1 (this int unsigned);
insert into t1 values (1);
insert into t1 values (-1);
Warnings:
-Warning 1264 Data truncated; out of range for column 'this' at row 1
+Warning 1264 Out of range value adjusted for column 'this' at row 1
insert into t1 values ('5000000000');
Warnings:
-Warning 1265 Data truncated for column 'this' at row 1
+Warning 1264 Out of range value adjusted for column 'this' at row 1
select * from t1;
this
1
diff --git a/mysql-test/r/type_varchar.result b/mysql-test/r/type_varchar.result
new file mode 100644
index 00000000000..3bd7fe6b175
--- /dev/null
+++ b/mysql-test/r/type_varchar.result
@@ -0,0 +1,394 @@
+drop table if exists t1, t2;
+create table t1 (v varchar(30), c char(3), e enum('abc','def','ghi'), t text);
+truncate table vchar;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(30) default NULL,
+ `c` char(3) default NULL,
+ `e` enum('abc','def','ghi') default NULL,
+ `t` text
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+show create table vchar;
+Table Create Table
+vchar CREATE TABLE `vchar` (
+ `v` varchar(30) default NULL,
+ `c` char(3) default NULL,
+ `e` enum('abc','def','ghi') default NULL,
+ `t` text
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+insert into t1 values ('abc', 'de', 'ghi', 'jkl');
+insert into t1 values ('abc ', 'de ', 'ghi', 'jkl ');
+insert into t1 values ('abc ', 'd ', 'ghi', 'jkl ');
+insert into vchar values ('abc', 'de', 'ghi', 'jkl');
+insert into vchar values ('abc ', 'de ', 'ghi', 'jkl ');
+insert into vchar values ('abc ', 'd ', 'ghi', 'jkl ');
+select length(v),length(c),length(e),length(t) from t1;
+length(v) length(c) length(e) length(t)
+3 2 3 3
+4 2 3 4
+7 1 3 7
+select length(v),length(c),length(e),length(t) from vchar;
+length(v) length(c) length(e) length(t)
+3 2 3 3
+3 2 3 4
+3 1 3 7
+alter table vchar add i int;
+show create table vchar;
+Table Create Table
+vchar CREATE TABLE `vchar` (
+ `v` varchar(30) default NULL,
+ `c` char(3) default NULL,
+ `e` enum('abc','def','ghi') default NULL,
+ `t` text,
+ `i` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select length(v),length(c),length(e),length(t) from vchar;
+length(v) length(c) length(e) length(t)
+3 2 3 3
+3 2 3 4
+3 1 3 7
+drop table t1, vchar;
+create table t1 (v varchar(20));
+insert into t1 values('a ');
+select v='a' from t1;
+v='a'
+1
+select binary v='a' from t1;
+binary v='a'
+0
+select binary v='a ' from t1;
+binary v='a '
+1
+insert into t1 values('a');
+alter table t1 add primary key (v);
+ERROR 23000: Duplicate entry 'a' for key 1
+drop table t1;
+create table t1 (v varbinary(20));
+insert into t1 values('a');
+insert into t1 values('a ');
+alter table t1 add primary key (v);
+drop table t1;
+create table t1 (v varchar(254), index (v));
+insert into t1 values ("This is a test ");
+insert into t1 values ("Some sample data");
+insert into t1 values (" garbage ");
+insert into t1 values (" This is a test ");
+insert into t1 values ("This is a test");
+insert into t1 values ("Hello world");
+insert into t1 values ("Foo bar");
+insert into t1 values ("This is a test");
+insert into t1 values ("MySQL varchar test");
+insert into t1 values ("test MySQL varchar");
+insert into t1 values ("This is a long string to have some random length data included");
+insert into t1 values ("Short string");
+insert into t1 values ("VSS");
+insert into t1 values ("Some samples");
+insert into t1 values ("Bar foo");
+insert into t1 values ("Bye");
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using index
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where; Using index
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using index
+alter table t1 change v v varchar(255);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort
+alter table t1 change v v varchar(256);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort
+alter table t1 change v v varchar(257);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort
+alter table t1 change v v varchar(258);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort
+alter table t1 change v v varchar(259);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort
+alter table t1 change v v varchar(258);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort
+alter table t1 change v v varchar(257);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort
+alter table t1 change v v varchar(256);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort
+alter table t1 change v v varchar(255);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using filesort
+alter table t1 change v v varchar(254);
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 3 Using where; Using index
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 257 const 3 Using where; Using index
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 257 NULL 2 Using where; Using index
+alter table t1 change v v varchar(253);
+alter table t1 change v v varchar(254), drop key v;
+alter table t1 change v v varchar(300), add key (v(10));
+select * from t1 where v like 'This is a test' order by v;
+v
+This is a test
+This is a test
+select * from t1 where v='This is a test' order by v;
+v
+This is a test
+This is a test
+This is a test
+select * from t1 where v like 'S%' order by v;
+v
+Short string
+Some sample data
+Some samples
+explain select * from t1 where v like 'This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL 4 Using where; Using filesort
+explain select * from t1 where v='This is a test' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const 4 Using where
+explain select * from t1 where v like 'S%' order by v;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL 2 Using where; Using filesort
+drop table t1;
+create table t1 (pkcol varchar(16), othercol varchar(16), primary key (pkcol));
+insert into t1 values ('test', 'something');
+update t1 set othercol='somethingelse' where pkcol='test';
+select * from t1;
+pkcol othercol
+test somethingelse
+drop table t1;
+create table t1 (a int, b varchar(12));
+insert into t1 values (1, 'A'), (22, NULL);
+create table t2 (a int);
+insert into t2 values (22), (22);
+select t1.a, t1.b, min(t1.b) from t1 inner join t2 ON t2.a = t1.a
+group by t1.b, t1.a;
+a b min(t1.b)
+22 NULL NULL
+drop table t1, t2;
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index c140ecd26e1..dcd364f1422 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -88,7 +88,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 UNION t2 ALL NULL NULL NULL NULL 4 Using filesort
NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL Using filesort
Warnings:
-Note 1003 (select test.t1.a AS `a`,test.t1.b AS `b` from test.t1 limit 2) union all (select test.t2.a AS `a`,test.t2.b AS `b` from test.t2 order by test.t2.a limit 1) order by b desc
+Note 1003 (select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` limit 2) union all (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` order by `test`.`t2`.`a` limit 1) order by `b` desc
(select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2;
a b
1 a
@@ -480,7 +480,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 UNION t2 const PRIMARY PRIMARY 4 const 1
NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL
Warnings:
-Note 1003 (select test.t1.a AS `a`,test.t1.b AS `b` from test.t1 where (test.t1.a = 1)) union (select test.t2.a AS `a`,test.t2.b AS `b` from test.t2 where (test.t2.a = 1))
+Note 1003 (select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (`test`.`t1`.`a` = 1)) union (select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b` from `test`.`t2` where (`test`.`t2`.`a` = 1))
(select * from t1 where a=5) union (select * from t2 where a=1);
a b
1 10
@@ -543,7 +543,7 @@ aa
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` char(2) NOT NULL default ''
+ `a` varchar(2) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT 12 as a UNION select "aa" as a;
@@ -554,7 +554,7 @@ aa
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` binary(20) NOT NULL default ''
+ `a` varbinary(20) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT 12 as a UNION select 12.2 as a;
@@ -565,7 +565,7 @@ a
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` double(53,1) NOT NULL default '0.0'
+ `a` decimal(19,1) NOT NULL default '0.0'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da date, dt datetime, sc char(10), sv varchar(10), b blob, tx text);
@@ -788,11 +788,11 @@ create table t3 select * from t2 union select * from t1;
select * from t3;
d
1.234567800
-100000000.0
+100000000.000000000
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
- `d` decimal(10,9) default NULL
+ `d` decimal(19,9) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1,t2,t3;
create table t1 select 1 union select -1;
@@ -812,7 +812,7 @@ create table t1 select _latin2"test" union select _latin2"testt" ;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `test` char(5) character set latin2 NOT NULL default ''
+ `test` varchar(5) character set latin2 NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (s char(200));
@@ -851,27 +851,27 @@ count(*)
26
show status like 'Slow_queries';
Variable_name Value
-Slow_queries 0
+Slow_queries 1
select count(*) from t1 where b=13;
count(*)
10
show status like 'Slow_queries';
Variable_name Value
-Slow_queries 1
+Slow_queries 3
select count(*) from t1 where b=13 union select count(*) from t1 where a=7;
count(*)
10
26
show status like 'Slow_queries';
Variable_name Value
-Slow_queries 2
+Slow_queries 5
select count(*) from t1 where a=7 union select count(*) from t1 where b=13;
count(*)
26
10
show status like 'Slow_queries';
Variable_name Value
-Slow_queries 3
+Slow_queries 7
flush status;
select a from t1 where b not in (1,2,3) union select a from t1 where b not in (4,5,6);
a
@@ -1056,7 +1056,7 @@ create table t1 as
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `test` char(4) NOT NULL default ''
+ `test` varchar(4) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select count(*) from t1;
count(*)
@@ -1114,7 +1114,7 @@ create table t1 as
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a collate latin1_german1_ci` char(1) character set latin1 collate latin1_german1_ci default NULL
+ `a collate latin1_german1_ci` varchar(1) character set latin1 collate latin1_german1_ci default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 as
@@ -1123,7 +1123,7 @@ create table t1 as
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` char(1) character set latin1 collate latin1_german1_ci default NULL
+ `a` varchar(1) character set latin1 collate latin1_german1_ci default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 as
@@ -1133,7 +1133,7 @@ create table t1 as
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` char(1) character set latin1 collate latin1_german1_ci default NULL
+ `a` varchar(1) character set latin1 collate latin1_german1_ci default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
drop table t2;
@@ -1226,7 +1226,7 @@ drop table t2;
create table t2 select a from t1 union select a from t1;
show columns from t2;
Field Type Null Key Default Extra
-a char(1)
+a varchar(1) NO
drop table t2;
create table t2 select a from t1 union select c from t1;
ERROR HY000: Illegal mix of collations (utf8_general_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation 'UNION'
@@ -1235,3 +1235,20 @@ show columns from t2;
Field Type Null Key Default Extra
a varchar(3) YES NULL
drop table t2, t1;
+create table t1 (a varchar(5));
+create table t2 select * from t1 union select 'abcdefghijkl';
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` varchar(12) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select row_format from information_schema.TABLES where table_schema="test" and table_name="t2";
+row_format
+Dynamic
+alter table t2 ROW_FORMAT=fixed;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` varchar(12) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED
+drop table t1,t2;
diff --git a/mysql-test/r/user_limits.result b/mysql-test/r/user_limits.result
new file mode 100644
index 00000000000..75062e97200
--- /dev/null
+++ b/mysql-test/r/user_limits.result
@@ -0,0 +1,96 @@
+drop table if exists t1;
+create table t1 (i int);
+delete from mysql.user where user like 'mysqltest\_%';
+delete from mysql.db where user like 'mysqltest\_%';
+delete from mysql.tables_priv where user like 'mysqltest\_%';
+delete from mysql.columns_priv where user like 'mysqltest\_%';
+flush privileges;
+grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 2;
+flush user_resources;
+select * from t1;
+i
+select * from t1;
+i
+select * from t1;
+ERROR 42000: User 'mysqltest_1' has exceeded the 'max_questions' resource (current value: 2)
+select * from t1;
+ERROR 42000: User 'mysqltest_1' has exceeded the 'max_questions' resource (current value: 2)
+drop user mysqltest_1@localhost;
+grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 2;
+flush user_resources;
+select * from t1;
+i
+select * from t1;
+i
+select * from t1;
+i
+delete from t1;
+delete from t1;
+delete from t1;
+ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates' resource (current value: 2)
+select * from t1;
+i
+delete from t1;
+ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates' resource (current value: 2)
+select * from t1;
+i
+drop user mysqltest_1@localhost;
+grant usage on *.* to mysqltest_1@localhost with max_connections_per_hour 2;
+flush user_resources;
+select * from t1;
+i
+select * from t1;
+i
+connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
+ERROR 42000: User 'mysqltest_1' has exceeded the 'max_connections' resource (current value: 2)
+select * from t1;
+i
+connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
+ERROR 42000: User 'mysqltest_1' has exceeded the 'max_connections' resource (current value: 2)
+drop user mysqltest_1@localhost;
+flush privileges;
+grant usage on *.* to mysqltest_1@localhost with max_user_connections 2;
+flush user_resources;
+select * from t1;
+i
+select * from t1;
+i
+connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
+ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 2)
+select * from t1;
+i
+grant usage on *.* to mysqltest_1@localhost with max_user_connections 3;
+flush user_resources;
+select * from t1;
+i
+connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
+ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 3)
+drop user mysqltest_1@localhost;
+select @@session.max_user_connections, @@global.max_user_connections;
+@@session.max_user_connections @@global.max_user_connections
+0 0
+set session max_user_connections= 2;
+ERROR HY000: Variable 'max_user_connections' is a GLOBAL variable and should be set with SET GLOBAL
+set global max_user_connections= 2;
+select @@session.max_user_connections, @@global.max_user_connections;
+@@session.max_user_connections @@global.max_user_connections
+2 2
+grant usage on *.* to mysqltest_1@localhost;
+flush user_resources;
+select @@session.max_user_connections, @@global.max_user_connections;
+@@session.max_user_connections @@global.max_user_connections
+2 2
+select * from t1;
+i
+connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
+ERROR 42000: User mysqltest_1 already has more than 'max_user_connections' active connections
+grant usage on *.* to mysqltest_1@localhost with max_user_connections 3;
+flush user_resources;
+select @@session.max_user_connections, @@global.max_user_connections;
+@@session.max_user_connections @@global.max_user_connections
+3 2
+connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
+ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 3)
+set global max_user_connections= 0;
+drop user mysqltest_1@localhost;
+drop table t1;
diff --git a/mysql-test/r/user_var-binlog.result b/mysql-test/r/user_var-binlog.result
index 06a2a846a0e..0e9692523ef 100644
--- a/mysql-test/r/user_var-binlog.result
+++ b/mysql-test/r/user_var-binlog.result
@@ -6,20 +6,27 @@ INSERT INTO t1 VALUES(@`a b`);
set @var1= "';aaa";
SET @var2=char(ascii('a'));
insert into t1 values (@var1),(@var2);
-show binlog events from 79;
-Log_name Pos Event_type Server_id Orig_log_pos Info
-master-bin.000001 79 User var 1 79 @`a b`=_latin1 0x68656C6C6F COLLATE latin1_swedish_ci
-master-bin.000001 120 Query 1 120 use `test`; INSERT INTO t1 VALUES(@`a b`)
-master-bin.000001 184 User var 1 184 @`var1`=_latin1 0x273B616161 COLLATE latin1_swedish_ci
-master-bin.000001 226 User var 1 226 @`var2`=_latin1 0x61 COLLATE latin1_swedish_ci
-master-bin.000001 264 Query 1 264 use `test`; insert into t1 values (@var1),(@var2)
+show binlog events from 98;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 98 User var 1 139 @`a b`=_latin1 0x68656C6C6F COLLATE latin1_swedish_ci
+master-bin.000001 139 Query 1 231 use `test`; INSERT INTO t1 VALUES(@`a b`)
+master-bin.000001 231 User var 1 273 @`var1`=_latin1 0x273B616161 COLLATE latin1_swedish_ci
+master-bin.000001 273 User var 1 311 @`var2`=_latin1 0x61 COLLATE latin1_swedish_ci
+master-bin.000001 311 Query 1 411 use `test`; insert into t1 values (@var1),(@var2)
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
SET @`a b`:=_latin1 0x68656C6C6F COLLATE `latin1_swedish_ci`;
use test;
SET TIMESTAMP=10000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
INSERT INTO t1 VALUES(@`a b`);
SET @`var1`:=_latin1 0x273B616161 COLLATE `latin1_swedish_ci`;
SET @`var2`:=_latin1 0x61 COLLATE `latin1_swedish_ci`;
SET TIMESTAMP=10000;
insert into t1 values (@var1),(@var2);
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
drop table t1;
diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result
index e42849abdf1..d9a647ce2c3 100644
--- a/mysql-test/r/user_var.result
+++ b/mysql-test/r/user_var.result
@@ -23,7 +23,11 @@ i @vv1:=if(sv1.i,1,0) @vv2:=if(sv2.i,1,0) @vv3:=if(sv3.i,1,0) @vv1+@vv2+@vv3
2 1 0 0 1
explain select * from t1 where i=@vv1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref i i 4 const 1 Using where
+1 SIMPLE t1 ref i i 4 const 1
+select @vv1,i,v from t1 where i=@vv1;
+@vv1 i v
+1 1 1
+1 1 3
explain select * from t1 where @vv1:=@vv1+1 and i=@vv1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
@@ -32,7 +36,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL i 4 NULL 3 Using where; Using index
explain select * from t1 where i=@vv1;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 ref i i 4 const 1 Using where
+1 SIMPLE t1 ref i i 4 const 1
drop table t1,t2;
set @a=0,@b=0;
select @a:=10, @b:=1, @a > @b, @a < @b;
@@ -176,6 +180,46 @@ select coercibility(@v1),coercibility(@v2),coercibility(@v3),coercibility(@v4);
coercibility(@v1) coercibility(@v2) coercibility(@v3) coercibility(@v4)
2 2 2 2
set session @honk=99;
-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 '@honk=99' at line 1
set one_shot @honk=99;
-ERROR HY000: The SET ONE_SHOT syntax is reserved for purposes internal to the MySQL server
+ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server
+set @first_var= NULL;
+create table t1 select @first_var;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `@first_var` longblob
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+set @first_var= cast(NULL as signed integer);
+create table t1 select @first_var;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `@first_var` bigint(20) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+set @first_var= NULL;
+create table t1 select @first_var;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `@first_var` bigint(20) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+set @first_var= concat(NULL);
+create table t1 select @first_var;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `@first_var` longblob
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+set @first_var=1;
+set @first_var= cast(NULL as CHAR);
+create table t1 select @first_var;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `@first_var` longtext
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
diff --git a/mysql-test/r/varbinary.result b/mysql-test/r/varbinary.result
index ab5779859ae..e55e6b35915 100644
--- a/mysql-test/r/varbinary.result
+++ b/mysql-test/r/varbinary.result
@@ -15,7 +15,7 @@ explain extended select * from t1 where UNIQ=0x38afba1d73e6a18a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const UNIQ UNIQ 8 const 1
Warnings:
-Note 1003 select test.t1.ID AS `ID`,test.t1.UNIQ AS `UNIQ` from test.t1 where (test.t1.UNIQ = 4084688022709641610)
+Note 1003 select `test`.`t1`.`ID` AS `ID`,`test`.`t1`.`UNIQ` AS `UNIQ` from `test`.`t1` where (`test`.`t1`.`UNIQ` = 4084688022709641610)
drop table t1;
select x'hello';
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 'x'hello'' at line 1
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index 6d4f9055e4e..b3850bcc72c 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -1,8 +1,30 @@
drop table if exists t1,t2;
-set @`test`=1,@TEST=3,@select=2,@t5=1.23456;
-select @test,@`select`,@TEST,@not_used;
-@test @`select` @TEST @not_used
-1 2 3 NULL
+set @`test`=1;
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+@test @`test` @TEST @`TEST` @"teSt"
+1 1 1 1 1
+set @TEST=2;
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+@test @`test` @TEST @`TEST` @"teSt"
+2 2 2 2 2
+set @"tEST"=3;
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+@test @`test` @TEST @`TEST` @"teSt"
+3 3 3 3 3
+set @`TeST`=4;
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+@test @`test` @TEST @`TEST` @"teSt"
+4 4 4 4 4
+select @`teST`:=5;
+@`teST`:=5
+5
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+@test @`test` @TEST @`TEST` @"teSt"
+5 5 5 5 5
+set @select=2,@t5=1.23456;
+select @`select`,@not_used;
+@`select` @not_used
+2 NULL
set @test_int=10,@test_double=1e-10,@test_string="abcdeghi",@test_string2="abcdefghij",@select=NULL;
select @test_int,@test_double,@test_string,@test_string2,@select;
@test_int @test_double @test_string @test_string2 @select
@@ -115,10 +137,18 @@ set global concurrent_insert=DEFAULT;
show variables like 'concurrent_insert';
Variable_name Value
concurrent_insert ON
+set global timed_mutexes=1;
+show variables like 'timed_mutexes';
+Variable_name Value
+timed_mutexes ON
+set global timed_mutexes=0;
+show variables like 'timed_mutexes';
+Variable_name Value
+timed_mutexes OFF
set storage_engine=MYISAM, storage_engine="HEAP", global storage_engine="MERGE";
show local variables like 'storage_engine';
Variable_name Value
-storage_engine HEAP
+storage_engine MEMORY
show global variables like 'storage_engine';
Variable_name Value
storage_engine MERGE
@@ -224,7 +254,7 @@ set storage_engine=MERGE, big_tables=2;
ERROR 42000: Variable 'big_tables' can't be set to the value of '2'
show local variables like 'storage_engine';
Variable_name Value
-storage_engine HEAP
+storage_engine MEMORY
set SESSION query_cache_size=10000;
ERROR HY000: Variable 'query_cache_size' is a GLOBAL variable and should be set with SET GLOBAL
set GLOBAL storage_engine=DEFAULT;
@@ -340,6 +370,8 @@ set sql_buffer_result=1;
set sql_log_bin=1;
set sql_log_off=1;
set sql_log_update=1;
+Warnings:
+Note 1315 The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored
set sql_low_priority_updates=1;
set sql_max_join_size=200;
select @@sql_max_join_size,@@max_join_size;
@@ -466,14 +498,15 @@ t1 CREATE TABLE `t1` (
`c5` bigint(20) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
-set @arg00= 8, @arg01= 8.8, @arg02= 'a string';
-create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3;
+set @arg00= 8, @arg01= 8.8, @arg02= 'a string', @arg03= 0.2e0;
+create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3, @arg03 as c4;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` bigint(20) default NULL,
- `c2` double default NULL,
- `c3` longtext
+ `c2` decimal(64,30) default NULL,
+ `c3` longtext,
+ `c4` double default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
SET GLOBAL MYISAM_DATA_POINTER_SIZE= 8;
@@ -485,3 +518,11 @@ SHOW VARIABLES LIKE 'table_cache';
Variable_name Value
table_cache 1
SET GLOBAL table_cache=DEFAULT;
+create table t1 (a int);
+select a into @x from t1;
+Warnings:
+Warning 1329 No data to FETCH
+show warnings;
+Level Code Message
+Warning 1329 No data to FETCH
+drop table t1;
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
new file mode 100644
index 00000000000..f8629e578f0
--- /dev/null
+++ b/mysql-test/r/view.result
@@ -0,0 +1,1714 @@
+drop table if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6;
+drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6;
+drop database if exists mysqltest;
+use test;
+create view v1 (c,d) as select a,b from t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+create temporary table t1 (a int, b int);
+create view v1 (c) as select b+1 from t1;
+ERROR HY000: View's SELECT contains a temporary table 't1'
+drop table t1;
+create table t1 (a int, b int);
+insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
+create view v1 (c,d) as select a,b+@@global.max_user_connections from t1;
+ERROR HY000: View's SELECT contains a variable or parameter
+create view v1 (c) as select b+1 from t1;
+select c from v1;
+c
+3
+4
+5
+6
+11
+create temporary table t1 (a int, b int);
+select * from t1;
+a b
+select c from v1;
+c
+3
+4
+5
+6
+11
+show create table v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1`
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1`
+show create view t1;
+ERROR HY000: 'test.t1' is not VIEW
+drop table t1;
+select a from v1;
+ERROR 42S22: Unknown column 'a' in 'field list'
+select v1.a from v1;
+ERROR 42S22: Unknown column 'v1.a' in 'field list'
+select b from v1;
+ERROR 42S22: Unknown column 'b' in 'field list'
+select v1.b from v1;
+ERROR 42S22: Unknown column 'v1.b' in 'field list'
+explain extended select c from v1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5
+Warnings:
+Note 1003 select (`test`.`t1`.`b` + 1) AS `c` from `test`.`v1`
+create algorithm=temptable view v2 (c) as select b+1 from t1;
+show create view v2;
+View Create View
+v2 CREATE ALGORITHM=TEMPTABLE VIEW `test`.`v2` AS select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1`
+select c from v2;
+c
+3
+4
+5
+6
+11
+explain extended select c from v2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 5
+2 DERIVED t1 ALL NULL NULL NULL NULL 5
+Warnings:
+Note 1003 select `v2`.`c` AS `c` from `test`.`v2`
+create view v3 (c) as select a+1 from v1;
+ERROR 42S22: Unknown column 'a' in 'field list'
+create view v3 (c) as select b+1 from v1;
+ERROR 42S22: Unknown column 'b' in 'field list'
+create view v3 (c) as select c+1 from v1;
+select c from v3;
+c
+4
+5
+6
+7
+12
+explain extended select c from v3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5
+Warnings:
+Note 1003 select ((`test`.`t1`.`b` + 1) + 1) AS `c` from `test`.`v3`
+create algorithm=temptable view v4 (c) as select c+1 from v2;
+select c from v4;
+c
+4
+5
+6
+7
+12
+explain extended select c from v4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 5
+2 DERIVED <derived3> ALL NULL NULL NULL NULL 5
+3 DERIVED t1 ALL NULL NULL NULL NULL 5
+Warnings:
+Note 1003 select `v4`.`c` AS `c` from `test`.`v4`
+create view v5 (c) as select c+1 from v2;
+select c from v5;
+c
+4
+5
+6
+7
+12
+explain extended select c from v5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived3> ALL NULL NULL NULL NULL 5
+3 DERIVED t1 ALL NULL NULL NULL NULL 5
+Warnings:
+Note 1003 select (`v2`.`c` + 1) AS `c` from `test`.`v5`
+create algorithm=temptable view v6 (c) as select c+1 from v1;
+select c from v6;
+c
+4
+5
+6
+7
+12
+explain extended select c from v6;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 5
+2 DERIVED t1 ALL NULL NULL NULL NULL 5
+Warnings:
+Note 1003 select `v6`.`c` AS `c` from `test`.`v6`
+show tables;
+Tables_in_test
+t1
+v1
+v2
+v3
+v4
+v5
+v6
+show full tables;
+Tables_in_test Table_type
+t1 BASE TABLE
+v1 VIEW
+v2 VIEW
+v3 VIEW
+v4 VIEW
+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 38654705663 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
+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;
+create view v2 as select c, d from v1;
+select * from v1;
+c d e f
+1 2 0 0
+1 3 0 0
+2 4 0 0
+2 5 0 0
+3 10 1 0
+select * from v2;
+c d
+1 2
+1 3
+2 4
+2 5
+3 10
+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;
+ERROR 42S01: Table 'v1' already exists
+create or replace 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;
+drop view v2;
+alter view v2 as select c, d from v1;
+ERROR 42S02: Table 'test.v2' doesn't exist
+create or replace view v2 as select c, d from v1;
+alter view v1 (c,d) as select a,max(b) from t1 group by a;
+select * from v1;
+c d
+1 3
+2 5
+3 10
+select * from v2;
+c d
+1 3
+2 5
+3 10
+drop view v100;
+ERROR 42S02: Unknown table 'test.v100'
+drop view t1;
+ERROR HY000: 'test.t1' is not VIEW
+drop table v1;
+ERROR 42S02: Unknown table 'v1'
+drop view v1,v2;
+drop table t1;
+create table t1 (a int);
+insert into t1 values (1), (2), (3);
+create view v1 (a) as select a+1 from t1;
+create view v2 (a) as select a-1 from t1;
+select * from t1 natural left join v1;
+a a
+1 NULL
+2 2
+3 3
+select * from v2 natural left join t1;
+a a
+0 NULL
+1 1
+2 2
+select * from v2 natural left join v1;
+a a
+0 NULL
+1 NULL
+2 2
+drop view v1, v2;
+drop table t1;
+create table t1 (a int);
+insert into t1 values (1), (2), (3), (1), (2), (3);
+create view v1 as select distinct a from t1;
+select * from v1;
+a
+1
+2
+3
+explain select * from v1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
+2 DERIVED t1 ALL NULL NULL NULL NULL 6 Using temporary
+select * from t1;
+a
+1
+2
+3
+1
+2
+3
+drop view v1;
+drop table t1;
+create table t1 (a int);
+create view v1 as select distinct a from t1 WITH CHECK OPTION;
+ERROR HY000: CHECK OPTION on non-updatable view 'test.v1'
+create view v1 as select a from t1 WITH CHECK OPTION;
+create view v2 as select a from t1 WITH CASCADED CHECK OPTION;
+create view v3 as select a from t1 WITH LOCAL CHECK OPTION;
+drop view v3 RESTRICT;
+drop view v2 CASCADE;
+drop view v1;
+drop table t1;
+create table t1 (a int, b int);
+insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
+create view v1 (c) as select b+1 from t1;
+select test.c from v1 test;
+c
+3
+4
+5
+6
+11
+create algorithm=temptable view v2 (c) as select b+1 from t1;
+select test.c from v2 test;
+c
+3
+4
+5
+6
+11
+select test1.* from v1 test1, v2 test2 where test1.c=test2.c;
+c
+3
+4
+5
+6
+11
+select test2.* from v1 test1, v2 test2 where test1.c=test2.c;
+c
+3
+4
+5
+6
+11
+drop table t1;
+drop view v1,v2;
+create table t1 (a int);
+insert into t1 values (1), (2), (3), (4);
+create view v1 as select a+1 from t1 order by 1 desc limit 2;
+select * from v1;
+a+1
+5
+4
+explain select * from v1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2
+2 DERIVED t1 ALL NULL NULL NULL NULL 4 Using filesort
+drop view v1;
+drop table t1;
+create table t1 (a int);
+insert into t1 values (1), (2), (3), (4);
+create view v1 as select a+1 from t1;
+create table t2 select * from v1;
+show columns from t2;
+Field Type Null Key Default Extra
+a+1 bigint(12) YES NULL
+select * from t2;
+a+1
+2
+3
+4
+5
+drop view v1;
+drop table t1,t2;
+create table t1 (a int, b int, primary key(a));
+insert into t1 values (10,2), (20,3), (30,4), (40,5), (50,10);
+create view v1 (a,c) as select a, b+1 from t1;
+create algorithm=temptable view v2 (a,c) as select a, b+1 from t1;
+update v1 set c=a+c;
+ERROR HY000: Column 'c' is not updatable
+update v2 set a=a+c;
+ERROR HY000: The target table v2 of the UPDATE is not updatable
+update v1 set a=a+c;
+select * from v1;
+a c
+13 3
+24 4
+35 5
+46 6
+61 11
+select * from t1;
+a b
+13 2
+24 3
+35 4
+46 5
+61 10
+drop table t1;
+drop view v1,v2;
+create table t1 (a int, b int, primary key(a));
+insert into t1 values (10,2), (20,3), (30,4), (40,5), (50,10);
+create table t2 (x int);
+insert into t2 values (10), (20);
+create view v1 (a,c) as select a, b+1 from t1;
+create algorithm=temptable view v2 (a,c) as select a, b+1 from t1;
+update t2,v1 set v1.c=v1.a+v1.c where t2.x=v1.a;
+ERROR HY000: Column 'c' is not updatable
+update t2,v2 set v2.a=v2.v2.a+c where t2.x=v2.a;
+ERROR HY000: The target table v2 of the UPDATE is not updatable
+update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.a;
+select * from v1;
+a c
+13 3
+24 4
+30 5
+40 6
+50 11
+select * from t1;
+a b
+13 2
+24 3
+30 4
+40 5
+50 10
+drop table t1,t2;
+drop view v1,v2;
+create table t1 (a int, b int, primary key(b));
+insert into t1 values (1,20), (2,30), (3,40), (4,50), (5,100);
+create view v1 (c) as select b from t1 where a<3;
+select * from v1;
+c
+20
+30
+explain extended select * from v1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`b` AS `c` from `test`.`v1` where (`test`.`t1`.`a` < 3)
+update v1 set c=c+1;
+select * from t1;
+a b
+1 21
+2 31
+3 40
+4 50
+5 100
+create view v2 (c) as select b from t1 where a>=3;
+select * from v1, v2;
+c c
+21 40
+31 40
+21 50
+31 50
+21 100
+31 100
+drop view v1, v2;
+drop table t1;
+create table t1 (a int, b int, primary key(a));
+insert into t1 values (1,2), (2,3), (3,4), (4,5), (5,10);
+create view v1 (a,c) as select a, b+1 from t1;
+create algorithm=temptable view v2 (a,c) as select a, b+1 from t1;
+delete from v2 where c < 4;
+ERROR HY000: The target table v2 of the DELETE is not updatable
+delete from v1 where c < 4;
+select * from v1;
+a c
+2 4
+3 5
+4 6
+5 11
+select * from t1;
+a b
+2 3
+3 4
+4 5
+5 10
+drop table t1;
+drop view v1,v2;
+create table t1 (a int, b int, primary key(a));
+insert into t1 values (1,2), (2,3), (3,4), (4,5), (5,10);
+create table t2 (x int);
+insert into t2 values (1), (2), (3), (4);
+create view v1 (a,c) as select a, b+1 from t1;
+create algorithm=temptable view v2 (a,c) as select a, b+1 from t1;
+delete v2 from t2,v2 where t2.x=v2.a;
+ERROR HY000: The target table v2 of the DELETE is not updatable
+delete v1 from t2,v1 where t2.x=v1.a;
+select * from v1;
+a c
+5 11
+select * from t1;
+a b
+5 10
+drop table t1,t2;
+drop view v1,v2;
+create table t1 (a int, b int, c int, primary key(a,b));
+insert into t1 values (10,2,-1), (20,3,-2), (30,4,-3), (40,5,-4), (50,10,-5);
+create view v1 (x,y) as select a, b from t1;
+create view v2 (x,y) as select a, c from t1;
+set updatable_views_with_limit=NO;
+update v1 set x=x+1;
+update v2 set x=x+1;
+update v1 set x=x+1 limit 1;
+update v2 set x=x+1 limit 1;
+ERROR HY000: The target table v2 of the UPDATE is not updatable
+set updatable_views_with_limit=YES;
+update v1 set x=x+1 limit 1;
+update v2 set x=x+1 limit 1;
+Warnings:
+Note 1355 View being updated does not have complete key of underlying table in it
+set updatable_views_with_limit=DEFAULT;
+show variables like "updatable_views_with_limit";
+Variable_name Value
+updatable_views_with_limit YES
+select * from t1;
+a b c
+15 2 -1
+22 3 -2
+32 4 -3
+42 5 -4
+52 10 -5
+drop table t1;
+drop view v1,v2;
+create table t1 (a int, b int, c int, primary key(a,b));
+insert into t1 values (10,2,-1), (20,3,-2);
+create view v1 (x,y,z) as select c, b, a from t1;
+create view v2 (x,y) as select b, a from t1;
+create view v3 (x,y,z) as select b, a, b from t1;
+create view v4 (x,y,z) as select c+1, b, a from t1;
+create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
+insert into v3 values (-60,4,30);
+ERROR HY000: The target table v3 of the INSERT is not updatable
+insert into v4 values (-60,4,30);
+ERROR HY000: The target table v4 of the INSERT is not updatable
+insert into v5 values (-60,4,30);
+ERROR HY000: The target table v5 of the INSERT is not updatable
+insert into v1 values (-60,4,30);
+insert into v1 (z,y,x) values (50,6,-100);
+insert into v2 values (5,40);
+select * from t1;
+a b c
+10 2 -1
+20 3 -2
+30 4 -60
+50 6 -100
+40 5 NULL
+drop table t1;
+drop view v1,v2,v3,v4,v5;
+create table t1 (a int, b int, c int, primary key(a,b));
+insert into t1 values (10,2,-1), (20,3,-2);
+create table t2 (a int, b int, c int, primary key(a,b));
+insert into t2 values (30,4,-60);
+create view v1 (x,y,z) as select c, b, a from t1;
+create view v2 (x,y) as select b, a from t1;
+create view v3 (x,y,z) as select b, a, b from t1;
+create view v4 (x,y,z) as select c+1, b, a from t1;
+create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
+insert into v3 select c, b, a from t2;
+ERROR HY000: The target table v3 of the INSERT is not updatable
+insert into v4 select c, b, a from t2;
+ERROR HY000: The target table v4 of the INSERT is not updatable
+insert into v5 select c, b, a from t2;
+ERROR HY000: The target table v5 of the INSERT is not updatable
+insert into v1 select c, b, a from t2;
+insert into v1 (z,y,x) select a+20,b+2,-100 from t2;
+insert into v2 select b+1, a+10 from t2;
+select * from t1;
+a b c
+10 2 -1
+20 3 -2
+30 4 -60
+50 6 -100
+40 5 NULL
+drop table t1, t2;
+drop view v1,v2,v3,v4,v5;
+create table t1 (a int, primary key(a));
+insert into t1 values (1), (2), (3);
+create view v1 (x) as select a from t1 where a > 1;
+select t1.a, v1.x from t1 left join v1 on (t1.a= v1.x);
+a x
+1 NULL
+2 2
+3 3
+drop table t1;
+drop view v1;
+create table t1 (a int, primary key(a));
+insert into t1 values (1), (2), (3), (200);
+create view v1 (x) as select a from t1 where a > 1;
+create view v2 (y) as select x from v1 where x < 100;
+select * from v2;
+y
+2
+3
+drop table t1;
+drop view v1,v2;
+create table t1 (a int, primary key(a));
+insert into t1 values (1), (2), (3), (200);
+create ALGORITHM=TEMPTABLE view v1 (x) as select a from t1;
+create view v2 (y) as select x from v1;
+update v2 set y=10 where y=2;
+ERROR HY000: The target table v2 of the UPDATE is not updatable
+drop table t1;
+drop view v1,v2;
+create table t1 (a int not null auto_increment, b int not null, primary key(a), unique(b));
+create view v1 (x) as select b from t1;
+insert into v1 values (1);
+select last_insert_id();
+last_insert_id()
+0
+insert into t1 (b) values (2);
+select last_insert_id();
+last_insert_id()
+2
+select * from t1;
+a b
+1 1
+2 2
+drop view v1;
+drop table t1;
+set sql_mode='ansi';
+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`
+drop view v1;
+drop table t1;
+set sql_mode=default;
+create table t1 (t_column int);
+create view v1 as select 'a';
+select * from v1, t1;
+a t_column
+drop view v1;
+drop table t1;
+create table `t1a``b` (col1 char(2));
+create view v1 as select * from `t1a``b`;
+select * from v1;
+col1
+describe v1;
+Field Type Null Key Default Extra
+col1 varchar(2) YES NULL
+drop view v1;
+drop table `t1a``b`;
+create table t1 (col1 char(5),col2 char(5));
+create view v1 as select * from t1;
+drop table t1;
+create table t1 (col1 char(5),newcol2 char(5));
+insert into v1 values('a','aa');
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
+drop table t1;
+select * from v1;
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
+drop view v1;
+create view v1 (a,a) as select 'a','a';
+ERROR 42S21: Duplicate column name 'a'
+create table t1 (col1 int,col2 char(22));
+insert into t1 values(5,'Hello, world of views');
+create view v1 as select * from t1;
+create view v2 as select * from v1;
+update v2 set col2='Hello, view world';
+select * from t1;
+col1 col2
+5 Hello, view world
+drop view v2, v1;
+drop table t1;
+create table t1 (a int, b int);
+create view v1 as select a, sum(b) from t1 group by a;
+select b from v1 use index (some_index) where b=1;
+ERROR 42000: Key column 'some_index' doesn't exist in table
+drop view v1;
+drop table t1;
+create table t1 (col1 char(5),col2 char(5));
+create view v1 (col1,col2) as select col1,col2 from t1;
+insert into v1 values('s1','p1'),('s1','p2'),('s1','p3'),('s1','p4'),('s2','p1'),('s3','p2'),('s4','p4');
+select distinct first.col2 from t1 first where first.col2 in (select second.col2 from t1 second where second.col1<>first.col1);
+col2
+p1
+p2
+p4
+select distinct first.col2 from v1 first where first.col2 in (select second.col2 from t1 second where second.col1<>first.col1);
+col2
+p1
+p2
+p4
+drop view v1;
+drop table t1;
+create table t1 (a int);
+create view v1 as select a from t1;
+insert into t1 values (1);
+SET @v0 = '2';
+PREPARE stmt FROM 'UPDATE v1 SET a = ?';
+EXECUTE stmt USING @v0;
+DEALLOCATE PREPARE stmt;
+SET @v0 = '3';
+PREPARE stmt FROM 'insert into v1 values (?)';
+EXECUTE stmt USING @v0;
+DEALLOCATE PREPARE stmt;
+SET @v0 = '4';
+PREPARE stmt FROM 'insert into v1 (a) values (?)';
+EXECUTE stmt USING @v0;
+DEALLOCATE PREPARE stmt;
+select * from t1;
+a
+2
+3
+4
+drop view v1;
+drop table t1;
+CREATE VIEW v02 AS SELECT * FROM DUAL;
+ERROR HY000: No tables used
+SHOW TABLES;
+Tables_in_test
+CREATE VIEW v1 AS SELECT EXISTS (SELECT 1 UNION SELECT 2);
+select * from v1;
+EXISTS (SELECT 1 UNION SELECT 2)
+1
+drop view v1;
+create table t1 (col1 int,col2 char(22));
+create view v1 as select * from t1;
+create index i1 on v1 (col1);
+ERROR HY000: 'test.v1' is not BASE TABLE
+drop view v1;
+drop table t1;
+CREATE VIEW v1 (f1,f2,f3,f4) AS SELECT connection_id(), pi(), current_user(), version();
+SHOW CREATE VIEW v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache connection_id() AS `f1`,pi() AS `f2`,current_user() AS `f3`,version() AS `f4`
+drop view v1;
+create table t1 (s1 int);
+create table t2 (s2 int);
+insert into t1 values (1), (2);
+insert into t2 values (2), (3);
+create view v1 as select * from t1,t2 union all select * from t1,t2;
+select * from v1;
+s1 s2
+1 2
+2 2
+1 3
+2 3
+1 2
+2 2
+1 3
+2 3
+drop view v1;
+drop tables t1, t2;
+create table t1 (col1 int);
+insert into t1 values (1);
+create view v1 as select count(*) from t1;
+insert into t1 values (null);
+select * from v1;
+count(*)
+2
+drop view v1;
+drop table t1;
+create table t1 (a int);
+create table t2 (a int);
+create view v1 as select a from t1;
+create view v2 as select a from t2 where a in (select a from v1);
+show create view v2;
+View Create View
+v2 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v2` AS select `test`.`t2`.`a` AS `a` from `test`.`t2` where `a` in (select `v1`.`a` AS `a` from `test`.`v1`)
+drop view v2, v1;
+drop table t1, t2;
+CREATE VIEW `v 1` AS select 5 AS `5`;
+show create view `v 1`;
+View Create View
+v 1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v 1` AS select 5 AS `5`
+drop view `v 1`;
+create database mysqltest;
+create table mysqltest.t1 (a int, b int);
+create view mysqltest.v1 as select a from mysqltest.t1;
+alter view mysqltest.v1 as select b from mysqltest.t1;
+alter view mysqltest.v1 as select a from mysqltest.t1;
+drop database mysqltest;
+CREATE TABLE t1 (c1 int not null auto_increment primary key, c2 varchar(20), fulltext(c2));
+insert into t1 (c2) VALUES ('real Beer'),('Water'),('Kossu'),('Coca-Cola'),('Vodka'),('Wine'),('almost real Beer');
+select * from t1 WHERE match (c2) against ('Beer');
+c1 c2
+1 real Beer
+7 almost real Beer
+CREATE VIEW v1 AS SELECT * from t1 WHERE match (c2) against ('Beer');
+select * from v1;
+c1 c2
+1 real Beer
+7 almost real Beer
+drop view v1;
+drop table t1;
+create table t1 (a int);
+insert into t1 values (1),(1),(2),(2),(3),(3);
+create view v1 as select a from t1;
+select distinct a from v1;
+a
+1
+2
+3
+select distinct a from v1 limit 2;
+a
+1
+2
+select distinct a from t1 limit 2;
+a
+1
+2
+prepare stmt1 from "select distinct a from v1 limit 2";
+execute stmt1;
+a
+1
+2
+execute stmt1;
+a
+1
+2
+deallocate prepare stmt1;
+drop view v1;
+drop table t1;
+create table t1 (tg_column bigint);
+create view v1 as select count(tg_column) as vg_column from t1;
+select avg(vg_column) from v1;
+avg(vg_column)
+0.0000
+drop view v1;
+drop table t1;
+create table t1 (col1 bigint not null, primary key (col1));
+create table t2 (col1 bigint not null, key (col1));
+create view v1 as select * from t1;
+create view v2 as select * from t2;
+insert into v1 values (1);
+insert into v2 values (1);
+create view v3 (a,b) as select v1.col1 as a, v2.col1 as b from v1, v2 where v1.col1 = v2.col1;
+select * from v3;
+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`)
+drop view v3, v2, v1;
+drop table t2, t1;
+create function `f``1` () returns int return 5;
+create view v1 as select test.`f``1` ();
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`f``1`() AS `test.``f````1`` ()`
+select * from v1;
+test.`f``1` ()
+5
+drop view v1;
+drop function `f``1`;
+create function x () returns int return 5;
+create view v1 as select x ();
+select * from v1;
+x ()
+5
+drop view v1;
+drop function x;
+create table t2 (col1 char collate latin1_german2_ci);
+create view v2 as select col1 collate latin1_german1_ci from t2;
+show create view v2;
+View Create View
+v2 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v2` AS select (`test`.`t2`.`col1` collate latin1_german1_ci) AS `col1 collate latin1_german1_ci` from `test`.`t2`
+show create view v2;
+View Create View
+v2 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v2` AS select (`test`.`t2`.`col1` collate latin1_german1_ci) AS `col1 collate latin1_german1_ci` from `test`.`t2`
+drop view v2;
+drop table t2;
+create table t1 (a int);
+insert into t1 values (1), (2);
+create view v1 as select 5 from t1 order by 1;
+select * from v1;
+5
+5
+5
+drop view v1;
+drop table t1;
+create function x1 () returns int return 5;
+create table t1 (s1 int);
+create view v1 as select x1() from t1;
+drop function x1;
+select * from v1;
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
+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 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL
+v1 NULL NULL NULL NULL NULL NULL # NULL NULL NULL # # NULL NULL NULL NULL View 'test.v1' references invalid table(s) or column(s) or function(s)
+drop view v1;
+drop table t1;
+create view v1 as select 99999999999999999999999999999999999999999999999999999 as col1;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select 99999999999999999999999999999999999999999999999999999 AS `col1`
+drop view v1;
+create table tü (cü char);
+create view vü as select cü from tü;
+insert into vü values ('ü');
+select * from vü;
+cü
+drop view vü;
+drop table tü;
+create table t1 (a int, b int);
+insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
+create view v1(c) as select a+1 from t1 where b >= 4;
+select c from v1 where exists (select * from t1 where a=2 and b=c);
+c
+4
+drop view v1;
+drop table t1;
+create view v1 as select cast(1 as char(3));
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select cast(1 as char(3) charset latin1) AS `cast(1 as char(3))`
+select * from v1;
+cast(1 as char(3))
+1
+drop view v1;
+create view v1 as select 'a',1;
+create view v2 as select * from v1 union all select * from v1;
+create view v3 as select * from v2 where 1 = (select `1` from v2);
+create view v4 as select * from v3;
+select * from v4;
+ERROR 21000: Subquery returns more than 1 row
+drop view v4, v3, v2, v1;
+create view v1 as select 5 into @w;
+ERROR HY000: View's SELECT contains a 'INTO' clause
+create view v1 as select 5 into outfile 'ttt';
+ERROR HY000: View's SELECT contains a 'INTO' clause
+create table t1 (a int);
+create view v1 as select a from t1 procedure analyse();
+ERROR HY000: View's SELECT contains a 'PROCEDURE' clause
+drop table t1;
+create table t1 (s1 int, primary key (s1));
+create view v1 as select * from t1;
+insert into v1 values (1) on duplicate key update s1 = 7;
+insert into v1 values (1) on duplicate key update s1 = 7;
+select * from t1;
+s1
+7
+drop view v1;
+drop table t1;
+create table t1 (col1 int);
+create table t2 (col1 int);
+create view v1 as select * from t1;
+create view v2 as select * from v1;
+create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1;
+update v2 set col1 = (select max(col1) from v1);
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+update v2 set col1 = (select max(col1) from t1);
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+update v2 set col1 = (select max(col1) from v2);
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+update v2,t2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+update t1,t2 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
+update v1,t2 set v1.col1 = (select max(col1) from v1) where v1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v1' for update in FROM clause
+update t2,v2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+update t2,t1 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+update t2,v1 set v1.col1 = (select max(col1) from v1) where v1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+update v2,t2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
+update v1,t2 set v1.col1 = (select max(col1) from t1) where v1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v1' for update in FROM clause
+update t2,v2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+update t2,t1 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+update t2,v1 set v1.col1 = (select max(col1) from t1) where v1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+update v2,t2 set v2.col1 = (select max(col1) from v2) where v2.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+update t1,t2 set t1.col1 = (select max(col1) from v2) where t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
+update v1,t2 set v1.col1 = (select max(col1) from v2) where v1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v1' for update in FROM clause
+update t2,v2 set v2.col1 = (select max(col1) from v2) where v2.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+update t2,t1 set t1.col1 = (select max(col1) from v2) where t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+update t2,v1 set v1.col1 = (select max(col1) from v2) where v1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
+update v3 set v3.col1 = (select max(col1) from v1);
+ERROR HY000: You can't specify target table 'v3' for update in FROM clause
+update v3 set v3.col1 = (select max(col1) from t1);
+ERROR HY000: You can't specify target table 'v3' for update in FROM clause
+update v3 set v3.col1 = (select max(col1) from v2);
+ERROR HY000: You can't specify target table 'v3' for update in FROM clause
+update v3 set v3.col1 = (select max(col1) from v3);
+ERROR HY000: You can't specify target table 'v3' for update in FROM clause
+delete from v2 where col1 = (select max(col1) from v1);
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+delete from v2 where col1 = (select max(col1) from t1);
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+delete from v2 where col1 = (select max(col1) from v2);
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+delete v2 from v2,t2 where (select max(col1) from v1) > 0 and v2.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+delete t1 from t1,t2 where (select max(col1) from v1) > 0 and t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
+delete v1 from v1,t2 where (select max(col1) from v1) > 0 and v1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v1' for update in FROM clause
+delete v2 from v2,t2 where (select max(col1) from t1) > 0 and v2.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+delete t1 from t1,t2 where (select max(col1) from t1) > 0 and t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
+delete v1 from v1,t2 where (select max(col1) from t1) > 0 and v1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v1' for update in FROM clause
+delete v2 from v2,t2 where (select max(col1) from v2) > 0 and v2.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+delete t1 from t1,t2 where (select max(col1) from v2) > 0 and t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
+delete v1 from v1,t2 where (select max(col1) from v2) > 0 and v1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 'v1' for update in FROM clause
+insert into v2 values ((select max(col1) from v1));
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+insert into t1 values ((select max(col1) from v1));
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
+insert into v2 values ((select max(col1) from v1));
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+insert into v2 values ((select max(col1) from t1));
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+insert into t1 values ((select max(col1) from t1));
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
+insert into v2 values ((select max(col1) from t1));
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+insert into v2 values ((select max(col1) from v2));
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+insert into t1 values ((select max(col1) from v2));
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
+insert into v2 values ((select max(col1) from v2));
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+insert into v3 (col1) values ((select max(col1) from v1));
+ERROR HY000: You can't specify target table 'v3' for update in FROM clause
+insert into v3 (col1) values ((select max(col1) from t1));
+ERROR HY000: You can't specify target table 'v3' for update in FROM clause
+insert into v3 (col1) values ((select max(col1) from v2));
+ERROR HY000: You can't specify target table 'v3' for update in FROM clause
+insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2));
+ERROR HY000: You can't specify target table 'v3' for update in FROM clause
+insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
+insert into mysql.time_zone values ('', (select CONVERT_TZ('20050101000000','UTC','MET') from t2));
+ERROR 23000: Column 'Use_leap_seconds' cannot be null
+create algorithm=temptable view v4 as select * from t1;
+insert into t1 values (1),(2),(3);
+insert into t1 (col1) values ((select max(col1) from v4));
+select * from t1;
+col1
+NULL
+1
+2
+3
+3
+drop view v4,v3,v2,v1;
+drop table t1,t2;
+create table t1 (s1 int);
+create view v1 as select * from t1;
+handler v1 open as xx;
+ERROR HY000: 'test.v1' is not BASE TABLE
+drop view v1;
+drop table t1;
+create table t1(a int);
+insert into t1 values (0), (1), (2), (3);
+create table t2 (a int);
+insert into t2 select a from t1 where a > 1;
+create view v1 as select a from t1 where a > 1;
+select * from t1 left join (t2 as t, v1) on v1.a=t1.a;
+a a a
+0 NULL NULL
+1 NULL NULL
+2 2 2
+2 3 2
+3 2 3
+3 3 3
+select * from t1 left join (t2 as t, t2) on t2.a=t1.a;
+a a a
+0 NULL NULL
+1 NULL NULL
+2 2 2
+2 3 2
+3 2 3
+3 3 3
+drop view v1;
+drop table t1, t2;
+create table t1 (s1 char);
+create view v1 as select s1 collate latin1_german1_ci as s1 from t1;
+insert into v1 values ('a');
+select * from v1;
+s1
+a
+update v1 set s1='b';
+select * from v1;
+s1
+b
+update v1,t1 set v1.s1='c' where t1.s1=v1.s1;
+select * from v1;
+s1
+c
+prepare stmt1 from "update v1,t1 set v1.s1=? where t1.s1=v1.s1";
+set @arg='d';
+execute stmt1 using @arg;
+select * from v1;
+s1
+d
+set @arg='e';
+execute stmt1 using @arg;
+select * from v1;
+s1
+e
+deallocate prepare stmt1;
+drop view v1;
+drop table t1;
+create table t1 (a int);
+create table t2 (a int);
+create view v1 as select * from t1;
+lock tables t1 read, v1 read;
+select * from v1;
+a
+select * from t2;
+ERROR HY000: Table 't2' was not locked with LOCK TABLES
+drop view v1;
+drop table t1, t2;
+create table t1 (a int);
+create view v1 as select * from t1 where a < 2 with check option;
+insert into v1 values(1);
+insert into v1 values(3);
+ERROR HY000: CHECK OPTION failed 'test.v1'
+insert ignore into v1 values (2),(3),(0);
+Warnings:
+Error 1369 CHECK OPTION failed 'test.v1'
+Error 1369 CHECK OPTION failed 'test.v1'
+select * from t1;
+a
+1
+0
+delete from t1;
+insert into v1 SELECT 1;
+insert into v1 SELECT 3;
+ERROR HY000: CHECK OPTION failed 'test.v1'
+create table t2 (a int);
+insert into t2 values (2),(3),(0);
+insert ignore into v1 SELECT a from t2;
+Warnings:
+Error 1369 CHECK OPTION failed 'test.v1'
+Error 1369 CHECK OPTION failed 'test.v1'
+select * from t1;
+a
+1
+0
+update v1 set a=-1 where a=0;
+update v1 set a=2 where a=1;
+ERROR HY000: CHECK OPTION failed 'test.v1'
+select * from t1;
+a
+1
+-1
+update v1 set a=0 where a=0;
+insert into t2 values (1);
+update v1,t2 set v1.a=v1.a-1 where v1.a=t2.a;
+select * from t1;
+a
+0
+-1
+update v1 set a=a+1;
+update ignore v1,t2 set v1.a=v1.a+1 where v1.a=t2.a;
+Warnings:
+Error 1369 CHECK OPTION failed 'test.v1'
+select * from t1;
+a
+1
+1
+drop view v1;
+drop table t1, t2;
+create table t1 (a int);
+create view v1 as select * from t1 where a < 2 with check option;
+create view v2 as select * from v1 where a > 0 with local check option;
+create view v3 as select * from v1 where a > 0 with cascaded check option;
+insert into v2 values (1);
+insert into v3 values (1);
+insert into v2 values (0);
+ERROR HY000: CHECK OPTION failed 'test.v2'
+insert into v3 values (0);
+ERROR HY000: CHECK OPTION failed 'test.v3'
+insert into v2 values (2);
+insert into v3 values (2);
+ERROR HY000: CHECK OPTION failed 'test.v3'
+select * from t1;
+a
+1
+1
+2
+drop view v3,v2,v1;
+drop table t1;
+create table t1 (a int, primary key (a));
+create view v1 as select * from t1 where a < 2 with check option;
+insert into v1 values (1) on duplicate key update a=2;
+insert into v1 values (1) on duplicate key update a=2;
+ERROR HY000: CHECK OPTION failed 'test.v1'
+insert ignore into v1 values (1) on duplicate key update a=2;
+Warnings:
+Error 1369 CHECK OPTION failed 'test.v1'
+select * from t1;
+a
+1
+drop view v1;
+drop table t1;
+create table t1 (s1 int);
+create view v1 as select * from t1;
+create view v2 as select * from v1;
+alter view v1 as select * from v2;
+ERROR 42S02: Table 'test.v1' doesn't exist
+alter view v1 as select * from v1;
+ERROR 42000: Not unique table/alias: 'v1'
+create or replace view v1 as select * from v2;
+ERROR 42S02: Table 'test.v1' doesn't exist
+create or replace view v1 as select * from v1;
+ERROR 42000: Not unique table/alias: 'v1'
+drop view v2,v1;
+drop table t1;
+create table t1 (a int);
+create view v1 as select * 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`
+alter algorithm=undefined view v1 as select * from t1 with check option;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` WITH CASCADED CHECK OPTION
+alter algorithm=merge view v1 as select * from t1 with cascaded check option;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=MERGE VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` WITH CASCADED CHECK OPTION
+alter algorithm=temptable view v1 as select * from t1;
+show create view v1;
+View Create View
+v1 CREATE ALGORITHM=TEMPTABLE VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1`
+drop view v1;
+drop table t1;
+create table t1 (s1 int);
+create table t2 (s1 int);
+create view v2 as select * from t2 where s1 in (select s1 from t1);
+insert into v2 values (5);
+insert into t1 values (5);
+select * from v2;
+s1
+5
+update v2 set s1 = 0;
+select * from v2;
+s1
+select * from t2;
+s1
+0
+alter view v2 as select * from t2 where s1 in (select s1 from t1) with check option;
+insert into v2 values (5);
+update v2 set s1 = 1;
+ERROR HY000: CHECK OPTION failed 'test.v2'
+insert into t1 values (1);
+update v2 set s1 = 1;
+select * from v2;
+s1
+1
+select * from t2;
+s1
+0
+1
+prepare stmt1 from "select * from v2;";
+execute stmt1;
+s1
+1
+insert into t1 values (0);
+execute stmt1;
+s1
+0
+1
+deallocate prepare stmt1;
+drop view v2;
+drop table t1, t2;
+create table t1 (t time);
+create view v1 as select substring_index(t,':',2) as t from t1;
+insert into t1 (t) values ('12:24:10');
+select substring_index(t,':',2) from t1;
+substring_index(t,':',2)
+12:24
+select substring_index(t,':',2) from v1;
+substring_index(t,':',2)
+12:24
+drop view v1;
+drop table t1;
+create table t1 (s1 tinyint);
+create view v1 as select * from t1 where s1 <> 0 with local check option;
+create view v2 as select * from v1 with cascaded check option;
+insert into v2 values (0);
+ERROR HY000: CHECK OPTION failed 'test.v2'
+drop view v2, v1;
+drop table t1;
+create table t1 (s1 int);
+create view v1 as select * from t1 where s1 < 5 with check option;
+insert ignore into v1 values (6);
+ERROR HY000: CHECK OPTION failed 'test.v1'
+insert ignore into v1 values (6),(3);
+Warnings:
+Error 1369 CHECK OPTION failed 'test.v1'
+select * from t1;
+s1
+3
+drop view v1;
+drop table t1;
+create table t1 (s1 tinyint);
+create trigger t1_bi before insert on t1 for each row set new.s1 = 500;
+create view v1 as select * from t1 where s1 <> 127 with check option;
+insert into v1 values (0);
+ERROR HY000: CHECK OPTION failed 'test.v1'
+select * from v1;
+s1
+select * from t1;
+s1
+drop trigger t1.t1_bi;
+drop view v1;
+drop table t1;
+create table t1 (s1 tinyint);
+create view v1 as select * from t1 where s1 <> 0;
+create view v2 as select * from v1 where s1 <> 1 with cascaded check option;
+insert into v2 values (0);
+ERROR HY000: CHECK OPTION failed 'test.v2'
+select * from v2;
+s1
+select * from t1;
+s1
+drop view v2, v1;
+drop table t1;
+create table t1 (a int, b char(10));
+create view v1 as select * from t1 where a != 0 with check option;
+load data infile '../../std_data/loaddata3.dat' into table v1 fields terminated by '' enclosed by '' ignore 1 lines;
+ERROR HY000: CHECK OPTION failed 'test.v1'
+select * from t1;
+a b
+1 row 1
+2 row 2
+select * from v1;
+a b
+1 row 1
+2 row 2
+delete from t1;
+load data infile '../../std_data/loaddata3.dat' ignore into table v1 fields terminated by '' enclosed by '' ignore 1 lines;
+Warnings:
+Warning 1264 Out of range value adjusted for column 'a' at row 3
+Error 1369 CHECK OPTION failed 'test.v1'
+Warning 1264 Out of range value adjusted for column 'a' at row 4
+Error 1369 CHECK OPTION failed 'test.v1'
+select * from t1;
+a b
+1 row 1
+2 row 2
+3 row 3
+select * from v1;
+a b
+1 row 1
+2 row 2
+3 row 3
+drop view v1;
+drop table t1;
+create table t1 (a text, b text);
+create view v1 as select * from t1 where a <> 'Field A' with check option;
+load data infile '../../std_data/loaddata2.dat' into table v1 fields terminated by ',' enclosed by '''';
+ERROR HY000: CHECK OPTION failed 'test.v1'
+select concat('|',a,'|'), concat('|',b,'|') from t1;
+concat('|',a,'|') concat('|',b,'|')
+select concat('|',a,'|'), concat('|',b,'|') from v1;
+concat('|',a,'|') concat('|',b,'|')
+delete from t1;
+load data infile '../../std_data/loaddata2.dat' ignore into table v1 fields terminated by ',' enclosed by '''';
+Warnings:
+Error 1369 CHECK OPTION failed 'test.v1'
+Warning 1261 Row 2 doesn't contain data for all columns
+select concat('|',a,'|'), concat('|',b,'|') from t1;
+concat('|',a,'|') concat('|',b,'|')
+|Field 1| |Field 2'
+Field 3,'Field 4|
+|Field 5' ,'Field 6| NULL
+|Field 6| | 'Field 7'|
+select concat('|',a,'|'), concat('|',b,'|') from v1;
+concat('|',a,'|') concat('|',b,'|')
+|Field 1| |Field 2'
+Field 3,'Field 4|
+|Field 5' ,'Field 6| NULL
+|Field 6| | 'Field 7'|
+drop view v1;
+drop table t1;
+create table t1 (s1 smallint);
+create view v1 as select * from t1 where 20 < (select (s1) from t1);
+insert into v1 values (30);
+ERROR HY000: The target table v1 of the INSERT is not updatable
+create view v2 as select * from t1;
+create view v3 as select * from t1 where 20 < (select (s1) from v2);
+insert into v3 values (30);
+ERROR HY000: The target table v3 of the INSERT is not updatable
+create view v4 as select * from v2 where 20 < (select (s1) from t1);
+insert into v4 values (30);
+ERROR HY000: You can't specify target table 'v4' for update in FROM clause
+drop view v4, v3, v2, v1;
+drop table t1;
+create table t1 (a int);
+create view v1 as select * from t1;
+check table t1,v1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+test.v1 check status OK
+check table v1,t1;
+Table Op Msg_type Msg_text
+test.v1 check status OK
+test.t1 check status OK
+drop table t1;
+check table v1;
+Table Op Msg_type Msg_text
+test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s)
+drop view v1;
+create table t1 (a int);
+create table t2 (a int);
+create table t3 (a int);
+insert into t1 values (1), (2), (3);
+insert into t2 values (1), (3);
+insert into t3 values (1), (2), (4);
+create view v3 (a,b) as select t1.a as a, t2.a as b from t1 left join t2 on (t1.a=t2.a);
+select * from t3 left join v3 on (t3.a = v3.a);
+a a b
+1 1 1
+2 2 NULL
+4 NULL NULL
+explain extended select * from t3 left join v3 on (t3.a = v3.a);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 3
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2
+Warnings:
+Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`t1` left join `test`.`t2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1
+create view v1 (a) as select a from t1;
+create view v2 (a) as select a from t2;
+create view v4 (a,b) as select v1.a as a, v2.a as b from v1 left join v2 on (v1.a=v2.a);
+select * from t3 left join v4 on (t3.a = v4.a);
+a a b
+1 1 1
+2 2 NULL
+4 NULL NULL
+explain extended select * from t3 left join v4 on (t3.a = v4.a);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 3
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY t2 ALL NULL NULL NULL NULL 2
+Warnings:
+Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`v1` left join `test`.`v2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1
+prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);";
+execute stmt1;
+a a b
+1 1 1
+2 2 NULL
+4 NULL NULL
+execute stmt1;
+a a b
+1 1 1
+2 2 NULL
+4 NULL NULL
+deallocate prepare stmt1;
+drop view v4,v3,v2,v1;
+drop tables t1,t2,t3;
+create table t1 (a int, primary key (a), b int);
+create table t2 (a int, primary key (a));
+insert into t1 values (1,100), (2,200);
+insert into t2 values (1), (3);
+create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
+update v3 set a= 10 where a=1;
+select * from t1;
+a b
+10 100
+2 200
+select * from t2;
+a
+1
+3
+create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
+set updatable_views_with_limit=NO;
+update v2 set a= 10 where a=200 limit 1;
+ERROR HY000: The target table t1 of the UPDATE is not updatable
+set updatable_views_with_limit=DEFAULT;
+select * from v3;
+a b
+2 1
+10 1
+2 3
+10 3
+select * from v2;
+a b
+100 1
+200 1
+100 3
+200 3
+set @a= 10;
+set @b= 100;
+prepare stmt1 from "update v3 set a= ? where a=?";
+execute stmt1 using @a,@b;
+select * from v3;
+a b
+2 1
+10 1
+2 3
+10 3
+set @a= 300;
+set @b= 10;
+execute stmt1 using @a,@b;
+select * from v3;
+a b
+2 1
+300 1
+2 3
+300 3
+deallocate prepare stmt1;
+drop view v3,v2;
+drop tables t1,t2;
+create table t1 (a int, primary key (a), b int);
+create table t2 (a int, primary key (a), b int);
+insert into t2 values (1000, 2000);
+create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
+insert into v3 values (1,2);
+ERROR HY000: Can not insert into join view 'test.v3' without fields list
+insert into v3 select * from t2;
+ERROR HY000: Can not insert into join view 'test.v3' without fields list
+insert into v3(a,b) values (1,2);
+ERROR HY000: Can not modify more than one base table through a join view 'test.v3'
+insert into v3(a,b) select * from t2;
+ERROR HY000: Can not modify more than one base table through a join view 'test.v3'
+insert into v3(a) values (1);
+insert into v3(b) values (10);
+insert into v3(a) select a from t2;
+insert into v3(b) select b from t2;
+Warnings:
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 2
+insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a);
+select * from t1;
+a b
+10002 NULL
+10 NULL
+1000 NULL
+select * from t2;
+a b
+1000 2000
+10 NULL
+2000 NULL
+0 NULL
+delete from v3;
+ERROR HY000: Can not delete from join view 'test.v3'
+delete v3,t1 from v3,t1;
+ERROR HY000: Can not delete from join view 'test.v3'
+delete t1,v3 from t1,v3;
+ERROR HY000: Can not delete from join view 'test.v3'
+delete from t1;
+prepare stmt1 from "insert into v3(a) values (?);";
+set @a= 100;
+execute stmt1 using @a;
+set @a= 300;
+execute stmt1 using @a;
+deallocate prepare stmt1;
+prepare stmt1 from "insert into v3(a) select ?;";
+set @a= 101;
+execute stmt1 using @a;
+set @a= 301;
+execute stmt1 using @a;
+deallocate prepare stmt1;
+select * from v3;
+a b
+100 1000
+101 1000
+300 1000
+301 1000
+100 10
+101 10
+300 10
+301 10
+100 2000
+101 2000
+300 2000
+301 2000
+100 0
+101 0
+300 0
+301 0
+drop view v3;
+drop tables t1,t2;
+create table t1(f1 int);
+create view v1 as select f1 from t1;
+select * from v1 where F1 = 1;
+f1
+drop view v1;
+drop table t1;
+create table t1(c1 int);
+create table t2(c2 int);
+insert into t1 values (1),(2),(3);
+insert into t2 values (1);
+SELECT c1 FROM t1 WHERE c1 IN (SELECT c2 FROM t2);
+c1
+1
+SELECT c1 FROM t1 WHERE EXISTS (SELECT c2 FROM t2 WHERE c2 = c1);
+c1
+1
+create view v1 as SELECT c1 FROM t1 WHERE c1 IN (SELECT c2 FROM t2);
+create view v2 as SELECT c1 FROM t1 WHERE EXISTS (SELECT c2 FROM t2 WHERE c2 = c1);
+select * from v1;
+c1
+1
+select * from v2;
+c1
+1
+select * from (select c1 from v2) X;
+c1
+1
+drop view v2, v1;
+drop table t1, t2;
+CREATE TABLE t1 (C1 INT, C2 INT);
+CREATE TABLE t2 (C2 INT);
+CREATE VIEW v1 AS SELECT C2 FROM t2;
+CREATE VIEW v2 AS SELECT C1 FROM t1 LEFT OUTER JOIN v1 USING (C2);
+SELECT * FROM v2;
+C1
+drop view v2, v1;
+drop table t1, t2;
+create table t1 (col1 char(5),col2 int,col3 int);
+insert into t1 values ('one',10,25), ('two',10,50), ('two',10,50), ('one',20,25), ('one',30,25);
+create view v1 as select * from t1;
+select col1,group_concat(col2,col3) from t1 group by col1;
+col1 group_concat(col2,col3)
+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
+two 1050,1050
+drop view v1;
+drop table t1;
+create table t1 (s1 int, s2 char);
+create view v1 as select s1, s2 from t1;
+select s2 from v1 vq1 where 2 = (select count(*) from v1 vq2 having vq1.s2 = vq2.s2);
+ERROR 42S22: Unknown column 'vq2.s2' in 'having clause'
+select s2 from v1 vq1 where 2 = (select count(*) aa from v1 vq2 having vq1.s2 = aa);
+s2
+drop view v1;
+drop table t1;
+CREATE TABLE t1 (a1 int);
+CREATE TABLE t2 (a2 int);
+INSERT INTO t1 VALUES (1), (2), (3), (4);
+INSERT INTO t2 VALUES (1), (2), (3);
+CREATE VIEW v1(a,b) AS SELECT a1,a2 FROM t1 JOIN t2 ON a1=a2 WHERE a1>1;
+SELECT * FROM v1;
+a b
+2 2
+3 3
+CREATE TABLE t3 SELECT * FROM v1;
+SELECT * FROM t3;
+a b
+2 2
+3 3
+DROP VIEW v1;
+DROP TABLE t1,t2,t3;
+create table t1 (a int);
+create table t2 like t1;
+create table t3 like t1;
+create view v1 as select t1.a x, t2.a y from t1 join t2 where t1.a=t2.a;
+insert into t3 select x from v1;
+insert into t2 select x from v1;
+drop view v1;
+drop table t1,t2,t3;
+CREATE TABLE t1 (col1 int PRIMARY KEY, col2 varchar(10));
+INSERT INTO t1 VALUES(1,'trudy');
+INSERT INTO t1 VALUES(2,'peter');
+INSERT INTO t1 VALUES(3,'sanja');
+INSERT INTO t1 VALUES(4,'monty');
+INSERT INTO t1 VALUES(5,'david');
+INSERT INTO t1 VALUES(6,'kent');
+INSERT INTO t1 VALUES(7,'carsten');
+INSERT INTO t1 VALUES(8,'ranger');
+INSERT INTO t1 VALUES(10,'matt');
+CREATE TABLE t2 (col1 int, col2 int, col3 char(1));
+INSERT INTO t2 VALUES (1,1,'y');
+INSERT INTO t2 VALUES (1,2,'y');
+INSERT INTO t2 VALUES (2,1,'n');
+INSERT INTO t2 VALUES (3,1,'n');
+INSERT INTO t2 VALUES (4,1,'y');
+INSERT INTO t2 VALUES (4,2,'n');
+INSERT INTO t2 VALUES (4,3,'n');
+INSERT INTO t2 VALUES (6,1,'n');
+INSERT INTO t2 VALUES (8,1,'y');
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT a.col1,a.col2,b.col2,b.col3
+FROM t1 a LEFT JOIN t2 b ON a.col1=b.col1
+WHERE b.col2 IS NULL OR
+b.col2=(SELECT MAX(col2) FROM t2 b WHERE b.col1=a.col1);
+col1 col2 col2 col3
+1 trudy 2 y
+2 peter 1 n
+3 sanja 1 n
+4 monty 3 n
+5 david NULL NULL
+6 kent 1 n
+7 carsten NULL NULL
+8 ranger 1 y
+10 matt NULL NULL
+SELECT a.col1,a.col2,b.col2,b.col3
+FROM v1 a LEFT JOIN t2 b ON a.col1=b.col1
+WHERE b.col2 IS NULL OR
+b.col2=(SELECT MAX(col2) FROM t2 b WHERE b.col1=a.col1);
+col1 col2 col2 col3
+1 trudy 2 y
+2 peter 1 n
+3 sanja 1 n
+4 monty 3 n
+5 david NULL NULL
+6 kent 1 n
+7 carsten NULL NULL
+8 ranger 1 y
+10 matt NULL NULL
+CREATE VIEW v2 AS SELECT * FROM t2;
+SELECT a.col1,a.col2,b.col2,b.col3
+FROM v2 b RIGHT JOIN v1 a ON a.col1=b.col1
+WHERE b.col2 IS NULL OR
+b.col2=(SELECT MAX(col2) FROM v2 b WHERE b.col1=a.col1);
+col1 col2 col2 col3
+1 trudy 2 y
+2 peter 1 n
+3 sanja 1 n
+4 monty 3 n
+5 david NULL NULL
+6 kent 1 n
+7 carsten NULL NULL
+8 ranger 1 y
+10 matt NULL NULL
+SELECT a.col1,a.col2,b.col2,b.col3
+FROM v2 b RIGHT JOIN v1 a ON a.col1=b.col1
+WHERE a.col1 IN (1,5,9) AND
+(b.col2 IS NULL OR
+b.col2=(SELECT MAX(col2) FROM v2 b WHERE b.col1=a.col1));
+col1 col2 col2 col3
+1 trudy 2 y
+5 david NULL NULL
+CREATE VIEW v3 AS SELECT * FROM t1 WHERE col1 IN (1,5,9);
+SELECT a.col1,a.col2,b.col2,b.col3
+FROM v2 b RIGHT JOIN v3 a ON a.col1=b.col1
+WHERE b.col2 IS NULL OR
+b.col2=(SELECT MAX(col2) FROM v2 b WHERE b.col1=a.col1);
+col1 col2 col2 col3
+1 trudy 2 y
+5 david NULL NULL
+DROP VIEW v1,v2,v3;
+DROP TABLE t1,t2;
+create table t1 as select 1 A union select 2 union select 3;
+create table t2 as select * from t1;
+create view v1 as select * from t1 where a in (select * from t2);
+select * from v1 A, v1 B where A.a = B.a;
+A A
+1 1
+2 2
+3 3
+create table t3 as select a a,a b from t2;
+create view v2 as select * from t3 where
+a in (select * from t1) or b in (select * from t2);
+select * from v2 A, v2 B where A.a = B.b;
+a b a b
+1 1 1 1
+2 2 2 2
+3 3 3 3
+drop view v1, v2;
+drop table t1, t2, t3;
diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
new file mode 100644
index 00000000000..df8e2b04f47
--- /dev/null
+++ b/mysql-test/r/view_grant.result
@@ -0,0 +1,304 @@
+grant create view on test.* to test@localhost;
+show grants for test@localhost;
+Grants for test@localhost
+GRANT USAGE ON *.* TO 'test'@'localhost'
+GRANT CREATE VIEW ON `test`.* TO 'test'@'localhost'
+revoke create view on test.* from test@localhost;
+show grants for test@localhost;
+Grants for test@localhost
+GRANT USAGE ON *.* TO 'test'@'localhost'
+create database mysqltest;
+create table mysqltest.t1 (a int, b int);
+create table mysqltest.t2 (a int, b int);
+grant select on mysqltest.t1 to mysqltest_1@localhost;
+grant create view,select on test.* to mysqltest_1@localhost;
+create view v1 as select * from mysqltest.t1;
+alter view v1 as select * from mysqltest.t1;
+ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 'v1'
+create or replace view v1 as select * from mysqltest.t1;
+ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 'v1'
+create view mysqltest.v2 as select * from mysqltest.t1;
+ERROR 42000: CREATE VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2'
+create view v2 as select * from mysqltest.t2;
+ERROR 42000: ANY command denied to user 'mysqltest_1'@'localhost' for table 't2'
+grant create view,drop,select on test.* to mysqltest_1@localhost;
+use test;
+alter view v1 as select * from mysqltest.t1;
+create or replace view v1 as select * from mysqltest.t1;
+revoke all privileges on mysqltest.t1 from mysqltest_1@localhost;
+revoke all privileges on test.* from mysqltest_1@localhost;
+drop database mysqltest;
+drop view test.v1;
+create database mysqltest;
+create table mysqltest.t1 (a int, b int);
+create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1;
+grant select (c) on mysqltest.v1 to mysqltest_1@localhost;
+select c from mysqltest.v1;
+c
+select d from mysqltest.v1;
+ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'd' in table 'v1'
+revoke all privileges on mysqltest.v1 from mysqltest_1@localhost;
+delete from mysql.user where user='mysqltest_1';
+drop database mysqltest;
+create database mysqltest;
+create table mysqltest.t1 (a int, b int);
+create algorithm=temptable view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1;
+grant select (c) on mysqltest.v1 to mysqltest_1@localhost;
+select c from mysqltest.v1;
+c
+select d from mysqltest.v1;
+ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'd' in table 'v1'
+revoke all privileges on mysqltest.v1 from mysqltest_1@localhost;
+delete from mysql.user where user='mysqltest_1';
+drop database mysqltest;
+create database mysqltest;
+create table mysqltest.t1 (a int, b int);
+create table mysqltest.t2 (a int, b int);
+create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1;
+create algorithm=temptable view mysqltest.v2 (c,d) as select a+1,b+1 from mysqltest.t1;
+create view mysqltest.v3 (c,d) as select a+1,b+1 from mysqltest.t2;
+create algorithm=temptable view mysqltest.v4 (c,d) as select a+1,b+1 from mysqltest.t2;
+grant select on mysqltest.v1 to mysqltest_1@localhost;
+grant select on mysqltest.v2 to mysqltest_1@localhost;
+grant select on mysqltest.v3 to mysqltest_1@localhost;
+grant select on mysqltest.v4 to mysqltest_1@localhost;
+select c from mysqltest.v1;
+c
+select c from mysqltest.v2;
+c
+select c from mysqltest.v3;
+c
+select c from mysqltest.v4;
+c
+show columns from mysqltest.v1;
+Field Type Null Key Default Extra
+c bigint(20) YES NULL
+d bigint(20) YES NULL
+show columns from mysqltest.v2;
+Field Type Null Key Default Extra
+c bigint(20) YES NULL
+d bigint(20) YES NULL
+explain select c from mysqltest.v1;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+show create view mysqltest.v1;
+ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1'
+explain select c from mysqltest.v2;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+show create view mysqltest.v2;
+ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2'
+explain select c from mysqltest.v3;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+show create view mysqltest.v3;
+ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v3'
+explain select c from mysqltest.v4;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+show create view mysqltest.v4;
+ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v4'
+grant select on mysqltest.t1 to mysqltest_1@localhost;
+explain select c from mysqltest.v1;
+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
+show create view mysqltest.v1;
+ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1'
+explain select c from mysqltest.v2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+show create view mysqltest.v2;
+ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v2'
+explain select c from mysqltest.v3;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+show create view mysqltest.v3;
+ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v3'
+explain select c from mysqltest.v4;
+ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+show create view mysqltest.v4;
+ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v4'
+grant show view on mysqltest.* to mysqltest_1@localhost;
+explain select c from mysqltest.v1;
+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
+show create view mysqltest.v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `mysqltest`.`v1` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1`
+explain select c from mysqltest.v2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+show create view mysqltest.v2;
+View Create View
+v2 CREATE ALGORITHM=TEMPTABLE VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1`
+explain select c from mysqltest.v3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 system NULL NULL NULL NULL 0 const row not found
+show create view mysqltest.v3;
+View Create View
+v3 CREATE ALGORITHM=UNDEFINED VIEW `mysqltest`.`v3` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2`
+explain select c from mysqltest.v4;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> system NULL NULL NULL NULL 0 const row not found
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+show create view mysqltest.v4;
+View Create View
+v4 CREATE ALGORITHM=TEMPTABLE VIEW `mysqltest`.`v4` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2`
+revoke all privileges on mysqltest.* from mysqltest_1@localhost;
+delete from mysql.user where user='mysqltest_1';
+drop database mysqltest;
+create database mysqltest;
+create table mysqltest.t1 (a int, b int, primary key(a));
+insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10);
+create table mysqltest.t2 (x int);
+insert into mysqltest.t2 values (3), (4), (5), (6);
+create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1;
+create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1;
+create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1;
+grant update (a) on mysqltest.v2 to mysqltest_1@localhost;
+grant update on mysqltest.v1 to mysqltest_1@localhost;
+grant select on mysqltest.* to mysqltest_1@localhost;
+use mysqltest;
+update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.c;
+select * from t1;
+a b
+13 2
+24 3
+35 4
+46 5
+50 10
+update v1 set a=a+c;
+select * from t1;
+a b
+16 2
+28 3
+40 4
+52 5
+61 10
+update t2,v2 set v2.a=v2.a+v2.c where t2.x=v2.c;
+select * from t1;
+a b
+16 2
+31 3
+44 4
+57 5
+61 10
+update v2 set a=a+c;
+select * from t1;
+a b
+18 2
+34 3
+48 4
+62 5
+71 10
+update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c;
+ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for column 'c' in table 'v2'
+update v2 set c=a+c;
+ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for column 'c' in table 'v2'
+update t2,v3 set v3.a=v3.a+v3.c where t2.x=v3.c;
+ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for table 'v3'
+update v3 set a=a+c;
+ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for table 'v3'
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
+drop database mysqltest;
+create database mysqltest;
+create table mysqltest.t1 (a int, b int, primary key(a));
+insert into mysqltest.t1 values (1,2), (2,3), (3,4), (4,5), (5,10);
+create table mysqltest.t2 (x int);
+insert into mysqltest.t2 values (3), (4), (5), (6);
+create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1;
+create view mysqltest.v2 (a,c) as select a, b+1 from mysqltest.t1;
+grant delete on mysqltest.v1 to mysqltest_1@localhost;
+grant select on mysqltest.* to mysqltest_1@localhost;
+use mysqltest;
+delete from v1 where c < 4;
+select * from t1;
+a b
+2 3
+3 4
+4 5
+5 10
+delete v1 from t2,v1 where t2.x=v1.c;
+select * from t1;
+a b
+5 10
+delete v2 from t2,v2 where t2.x=v2.c;
+ERROR 42000: DELETE command denied to user 'mysqltest_1'@'localhost' for table 'v2'
+delete from v2 where c < 4;
+ERROR 42000: DELETE command denied to user 'mysqltest_1'@'localhost' for table 'v2'
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
+drop database mysqltest;
+create database mysqltest;
+create table mysqltest.t1 (a int, b int, primary key(a));
+insert into mysqltest.t1 values (1,2), (2,3);
+create table mysqltest.t2 (x int, y int);
+insert into mysqltest.t2 values (3,4);
+create view mysqltest.v1 (a,c) as select a, b from mysqltest.t1;
+create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1;
+grant insert on mysqltest.v1 to mysqltest_1@localhost;
+grant select on mysqltest.* to mysqltest_1@localhost;
+use mysqltest;
+insert into v1 values (5,6);
+select * from t1;
+a b
+1 2
+2 3
+5 6
+insert into v1 select x,y from t2;
+select * from t1;
+a b
+1 2
+2 3
+5 6
+3 4
+insert into v2 values (5,6);
+ERROR 42000: INSERT command denied to user 'mysqltest_1'@'localhost' for table 'v2'
+insert into v2 select x,y from t2;
+ERROR 42000: INSERT command denied to user 'mysqltest_1'@'localhost' for table 'v2'
+use test;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
+drop database mysqltest;
+create database mysqltest;
+create table mysqltest.t1 (a int, b int);
+create table mysqltest.t2 (a int, b int);
+grant update on mysqltest.t1 to mysqltest_1@localhost;
+grant update(b) on mysqltest.t2 to mysqltest_1@localhost;
+grant create view,update on test.* to mysqltest_1@localhost;
+create view v1 as select * from mysqltest.t1;
+create view v2 as select b from mysqltest.t2;
+create view mysqltest.v1 as select * from mysqltest.t1;
+ERROR 42000: CREATE VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1'
+create view v3 as select a from mysqltest.t2;
+ERROR 42000: ANY command denied to user 'mysqltest_1'@'localhost' for column 'a' in table 't2'
+create table mysqltest.v3 (b int);
+grant create view on mysqltest.v3 to mysqltest_1@localhost;
+drop table mysqltest.v3;
+create view mysqltest.v3 as select b from mysqltest.t2;
+grant create view, update on mysqltest.v3 to mysqltest_1@localhost;
+drop view mysqltest.v3;
+create view mysqltest.v3 as select b from mysqltest.t2;
+grant create view, update, insert on mysqltest.v3 to mysqltest_1@localhost;
+drop view mysqltest.v3;
+create view mysqltest.v3 as select b from mysqltest.t2;
+ERROR 42000: create view command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 'v3'
+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'
+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;
+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 update,select(b) on mysqltest.t2 to mysqltest_1@localhost;
+create view v4 as select b+1 from mysqltest.t2;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
+drop database mysqltest;
+drop view v1,v2,v4;
+create database mysqltest;
+create table mysqltest.t1 (a int);
+grant all privileges on mysqltest.* to mysqltest_1@localhost;
+use mysqltest;
+create view v1 as select * from t1;
+revoke all privileges on mysqltest.* from mysqltest_1@localhost;
+drop database mysqltest;
diff --git a/mysql-test/r/view_query_cache.result b/mysql-test/r/view_query_cache.result
new file mode 100644
index 00000000000..e6c2c0152f3
--- /dev/null
+++ b/mysql-test/r/view_query_cache.result
@@ -0,0 +1,126 @@
+drop table if exists t1,t2,v1,v2,v3;
+drop view if exists t1,t2,v1,v2,v3;
+set GLOBAL query_cache_size=1355776;
+flush status;
+create table t1 (a int, b int);
+create view v1 (c,d) as select sql_no_cache a,b from t1;
+create view v2 (c,d) as select a+rand(),b from t1;
+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
+select * from v1;
+c d
+select * from v2;
+c d
+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
+select * from v1;
+c d
+select * from v2;
+c d
+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 view v1,v2;
+set query_cache_type=demand;
+flush status;
+create view v1 (c,d) as select sql_cache a,b from t1;
+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
+select * from v1;
+c d
+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 t1;
+a b
+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 v1;
+c d
+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
+select * from t1;
+a b
+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
+drop view v1;
+set query_cache_type=default;
+drop table t1;
+create table t1 (a int);
+insert into t1 values (1), (2), (3);
+create view v1 as select a from t1 where a > 1;
+select * from v1;
+a
+2
+3
+alter view v1 as select a from t1 where a > 2;
+select * from v1;
+a
+3
+drop view v1;
+select * from v1;
+ERROR 42S02: Table 'test.v1' doesn't exist
+drop table t1;
+create table t1 (a int, primary key (a), b int);
+create table t2 (a int, primary key (a), b int);
+insert into t2 values (1000, 2000);
+create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
+select * from v3;
+a b
+drop view v3;
+drop table t1, t2;
+set GLOBAL query_cache_size=default;
diff --git a/mysql-test/r/view_skip_grants.result b/mysql-test/r/view_skip_grants.result
new file mode 100644
index 00000000000..48cb9f2aa25
--- /dev/null
+++ b/mysql-test/r/view_skip_grants.result
@@ -0,0 +1,6 @@
+drop table if exists t1,v1;
+drop view if exists t1,v1;
+use test;
+create table t1 (field1 INT);
+CREATE VIEW v1 AS SELECT field1 FROM t1;
+drop view v1;
diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result
index d1d96afa153..442d0784953 100644
--- a/mysql-test/r/warnings.result
+++ b/mysql-test/r/warnings.result
@@ -31,19 +31,19 @@ Error 1064 You have an error in your SQL syntax; check the manual that correspon
insert into t1 values (1);
insert into t1 values ("hej");
Warnings:
-Warning 1265 Data truncated for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 1
insert into t1 values ("hej"),("då");
Warnings:
-Warning 1265 Data truncated for column 'a' at row 1
-Warning 1265 Data truncated for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
set SQL_WARNINGS=1;
insert into t1 values ("hej");
Warnings:
-Warning 1265 Data truncated for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 1
insert into t1 values ("hej"),("då");
Warnings:
-Warning 1265 Data truncated for column 'a' at row 1
-Warning 1265 Data truncated for column 'a' at row 2
+Warning 1264 Out of range value adjusted for column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'a' at row 2
drop table t1;
set SQL_WARNINGS=0;
drop temporary table if exists not_exists;
@@ -70,13 +70,13 @@ drop table t1;
create table t1(a tinyint, b int not null, c date, d char(5));
load data infile '../../std_data/warnings_loaddata.dat' into table t1 fields terminated by ',';
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'b' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'b' at row 2
Warning 1265 Data truncated for column 'd' at row 3
Warning 1265 Data truncated for column 'c' at row 4
Warning 1261 Row 5 doesn't contain data for all columns
Warning 1265 Data truncated for column 'b' at row 6
Warning 1262 Row 7 was truncated; it contained more data than there were input columns
-Warning 1264 Data truncated; out of range for column 'a' at row 8
+Warning 1264 Out of range value adjusted for column 'a' at row 8
select @@warning_count;
@@warning_count
7
@@ -84,11 +84,11 @@ drop table t1;
create table t1(a tinyint NOT NULL, b tinyint unsigned, c char(5));
insert into t1 values(NULL,100,'mysql'),(10,-1,'mysql ab'),(500,256,'open source'),(20,NULL,'test');
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1
-Warning 1264 Data truncated; out of range for column 'b' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1
+Warning 1264 Out of range value adjusted for column 'b' at row 2
Warning 1265 Data truncated for column 'c' at row 2
-Warning 1264 Data truncated; out of range for column 'a' at row 3
-Warning 1264 Data truncated; out of range for column 'b' at row 3
+Warning 1264 Out of range value adjusted for column 'a' at row 3
+Warning 1264 Out of range value adjusted for column 'b' at row 3
Warning 1265 Data truncated for column 'c' at row 3
alter table t1 modify c char(4);
Warnings:
@@ -97,7 +97,7 @@ Warning 1265 Data truncated for column 'c' at row 2
alter table t1 add d char(2);
update t1 set a=NULL where a=10;
Warnings:
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 2
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 2
update t1 set c='mysql ab' where c='test';
Warnings:
Warning 1265 Data truncated for column 'c' at row 4
@@ -113,14 +113,16 @@ Warnings:
Warning 1265 Data truncated for column 'b' at row 1
Warning 1265 Data truncated for column 'b' at row 2
Warning 1265 Data truncated for column 'b' at row 3
-Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 4
+Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 4
Warning 1265 Data truncated for column 'b' at row 4
insert into t2(b) values('mysqlab');
Warnings:
+Warning 1364 Field 'a' doesn't have a default value
Warning 1265 Data truncated for column 'b' at row 1
set sql_warnings=1;
insert into t2(b) values('mysqlab');
Warnings:
+Warning 1364 Field 'a' doesn't have a default value
Warning 1265 Data truncated for column 'b' at row 1
set sql_warnings=0;
drop table t1, t2;
diff --git a/mysql-test/r/xa.result b/mysql-test/r/xa.result
new file mode 100644
index 00000000000..1dde495d6ae
--- /dev/null
+++ b/mysql-test/r/xa.result
@@ -0,0 +1,45 @@
+drop table if exists t1, t2;
+create table t1 (a int) engine=innodb;
+xa start 'test1';
+insert t1 values (10);
+xa end 'test1';
+xa prepare 'test1';
+xa rollback 'test1';
+select * from t1;
+a
+xa start 'test2';
+xa start 'test-bad';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed in the ACTIVE state
+insert t1 values (20);
+xa prepare 'test2';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed in the ACTIVE state
+xa end 'test2';
+xa prepare 'test2';
+xa commit 'test2';
+select * from t1;
+a
+20
+xa start 'testa','testb';
+insert t1 values (30);
+xa end 'testa','testb';
+xa start 0x7465737462, 0x2030405060, 0xb;
+insert t1 values (40);
+xa end 'testb',' 0@P`',11;
+xa prepare 'testb',0x2030405060,11;
+xa recover;
+formatID gtrid_length bqual_length data
+11 5 5 testb 0@P`
+xa prepare 'testa','testb';
+xa recover;
+formatID gtrid_length bqual_length data
+11 5 5 testb 0@P`
+1 5 5 testatestb
+xa commit 'testb',0x2030405060,11;
+xa rollback 'testa','testb';
+xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
+select * from t1;
+a
+20
+40
+drop table t1;
diff --git a/mysql-test/std_data/loaddata5.dat b/mysql-test/std_data/loaddata5.dat
new file mode 100644
index 00000000000..6e1881bd8e2
--- /dev/null
+++ b/mysql-test/std_data/loaddata5.dat
@@ -0,0 +1,3 @@
+1 2
+3 4
+5 6
diff --git a/mysql-test/std_data/rpl_timezone.dat b/mysql-test/std_data/rpl_timezone.dat
new file mode 100644
index 00000000000..2df8a39f1e3
--- /dev/null
+++ b/mysql-test/std_data/rpl_timezone.dat
@@ -0,0 +1,2 @@
+20040101000000
+20040611093902
diff --git a/mysql-test/std_data/trunc_binlog.000001 b/mysql-test/std_data/trunc_binlog.000001
index 2c2b4ec6ce4..3da2490eab2 100644
--- a/mysql-test/std_data/trunc_binlog.000001
+++ b/mysql-test/std_data/trunc_binlog.000001
Binary files differ
diff --git a/mysql-test/std_data/vchar.frm b/mysql-test/std_data/vchar.frm
new file mode 100644
index 00000000000..5f037261d5f
--- /dev/null
+++ b/mysql-test/std_data/vchar.frm
Binary files differ
diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test
index 52e367769a2..f5523f83226 100644
--- a/mysql-test/t/analyse.test
+++ b/mysql-test/t/analyse.test
@@ -47,3 +47,11 @@ create table t1 (v varchar(128));
insert into t1 values ('abc'),('abc\'def\\hij\"klm\0opq'),('\''),('\"'),('\\'),('a\0'),('b\''),('c\"'),('d\\'),('\'b'),('\"c'),('\\d'),('a\0\0\0b'),('a\'\'\'\'b'),('a\"\"\"\"b'),('a\\\\\\\\b'),('\'\0\\\"'),('\'\''),('\"\"'),('\\\\'),('The\ZEnd');
select * from t1 procedure analyse();
drop table t1;
+
+#decimal-related test
+
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select * from t1 procedure analyse();
+drop table t1;
diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test
index b9e392870dc..9d25524da5f 100644
--- a/mysql-test/t/archive.test
+++ b/mysql-test/t/archive.test
@@ -1289,6 +1289,18 @@ select fld3 from t2 where (fld3 like "C%" and fld3 = "Chantilly");
select fld1,fld3 from t2 where fld1 like "25050%";
select fld1,fld3 from t2 where fld1 like "25050_";
+
+#
+# Test rename of table
+#
+create table t3 engine=archive select * from t2;
+select * from t3 where fld3='bonfire';
+select count(*) from t3;
+rename table t3 to t4;
+select * from t4 where fld3='bonfire';
+select count(*) from t4;
+
+
#
# Test for insert after select
#
@@ -1299,15 +1311,18 @@ INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','');
SELECT * FROM t2;
OPTIMIZE TABLE t2;
SELECT * FROM t2;
+REPAIR TABLE t2;
+SELECT * FROM t2;
#
-# Test rename of table
-#
-create table t3 engine=archive select * from t2;
-select * from t3 where fld3='bonfire';
-select count(*) from t3;
-rename table t3 to t4;
-select * from t4 where fld3='bonfire';
-select count(*) from t4;
+# Test bulk inserts
+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;
+# Just test syntax, we will never know if the out put is right or wrong
+# Must be the last test
+INSERT DELAYED INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','');
+#
+# Cleanup, test is over
+#
drop table t1, t2, t4;
diff --git a/mysql-test/t/backup.test b/mysql-test/t/backup.test
index ed24161bef5..8b3a46724ab 100644
--- a/mysql-test/t/backup.test
+++ b/mysql-test/t/backup.test
@@ -10,10 +10,10 @@ set SQL_LOG_BIN=0;
drop table if exists t1, t2, t3;
--enable_warnings
create table t4(n int);
---replace_result "errno: 1" "errno: X" "errno: 2" "errno: X" "errno: 22" "errno: X" "errno: 23" "errno: X"
+--replace_result ": 1" ": X" ": 2" ": X" ": 22" ": X" ": 23" ": X" $MYSQL_TEST_DIR MYSQL_TEST_DIR
backup table t4 to '../bogus';
backup table t4 to '../tmp';
---replace_result "errno: 7" "errno: X" "errno: 17" "errno: X"
+--replace_result ": 7" ": X" ": 17" ": X" $MYSQL_TEST_DIR MYSQL_TEST_DIR
backup table t4 to '../tmp';
drop table t4;
restore table t4 from '../tmp';
@@ -23,6 +23,7 @@ create table t1(n int);
insert into t1 values (23),(45),(67);
backup table t1 to '../tmp';
drop table t1;
+--replace_result ": 1" ": X" ": 2" ": X" ": 22" ": X" ": 23" ": X" $MYSQL_TEST_DIR MYSQL_TEST_DIR
restore table t1 from '../bogus';
restore table t1 from '../tmp';
select n from t1;
diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test
index 069ec758ba2..f4895318818 100644
--- a/mysql-test/t/bdb.test
+++ b/mysql-test/t/bdb.test
@@ -42,8 +42,13 @@ update ignore t1 set id=id+1; # This will change all rows
select * from t1;
update ignore t1 set id=1023 where id=1010;
select * from t1 where parent_id=102 order by parent_id,id;
+# Here and below the differences in result are caused by difference in
+# floating point calculations performed in BDB handler.
+--replace_result 5 X 6 X
explain select level from t1 where level=1;
+--replace_result 5 X 6 X
explain select level,id from t1 where level=1;
+--replace_result 5 X 6 X
explain select level,id,parent_id from t1 where level=1;
select level,id from t1 where level=1;
select level,id,parent_id from t1 where level=1;
@@ -349,6 +354,7 @@ update ignore t1 set id=id+1; # This will change all rows
select * from t1;
update ignore t1 set id=1023 where id=1010;
select * from t1 where parent_id=102;
+--replace_result 5 X 6 X
explain select level from t1 where level=1;
select level,id from t1 where level=1;
select level,id,parent_id from t1 where level=1;
@@ -824,7 +830,7 @@ select a from t1;
drop table t1;
#
-# bug#2686 - index_merge select on BerkeleyDB table with varchar PK causes mysqld to crash
+# bug#2686 - index_merge select on BerkeleyDB table with varchar PK crashes
#
create table t1(
@@ -842,7 +848,8 @@ select substring(pk1, 1, 4), substring(pk1, 4001),
drop table t1;
#
-# bug#2688 - Wrong index_merge query results for BDB table with variable length primary key
+# bug#2688 - Wrong index_merge query results for BDB table with
+# variable length primary key
#
create table t1 (
@@ -929,3 +936,37 @@ SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterb");
SELECT id FROM t1 WHERE (list_id = 1) AND (term = "lettera");
SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterd");
DROP TABLE t1;
+
+#
+# alter temp table
+#
+create temporary table t1 (a int, primary key(a)) engine=bdb;
+select * from t1;
+alter table t1 add b int;
+select * from t1;
+drop table t1;
+
+
+#
+# Test varchar
+#
+
+let $default=`select @@storage_engine`;
+set storage_engine=bdb;
+source include/varchar.inc;
+
+#
+# Some errors/warnings on create
+#
+
+create table t1 (v varchar(65530), key(v));
+drop table if exists t1;
+create table t1 (v varchar(65536));
+show create table t1;
+drop table t1;
+create table t1 (v varchar(65530) character set utf8);
+show create table t1;
+drop table t1;
+
+# End varchar test
+eval set storage_engine=$default;
diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test
index a26b78254e7..99c8a13d0b5 100644
--- a/mysql-test/t/bigint.test
+++ b/mysql-test/t/bigint.test
@@ -104,3 +104,13 @@ t2.value64=t1.value64;
drop table t1, t2;
+#
+# Test of CREATE ... SELECT and unsigned integers
+#
+create table t1 select 1 as 'a';
+show create table t1;
+drop table t1;
+create table t1 select 9223372036854775809 as 'a';
+show create table t1;
+select * from t1;
+drop table t1;
diff --git a/mysql-test/t/binlog-master.opt b/mysql-test/t/binlog-master.opt
new file mode 100644
index 00000000000..ad2c6a647b5
--- /dev/null
+++ b/mysql-test/t/binlog-master.opt
@@ -0,0 +1 @@
+-O max_binlog_size=4096
diff --git a/mysql-test/t/binlog.test b/mysql-test/t/binlog.test
new file mode 100644
index 00000000000..2310e800df7
--- /dev/null
+++ b/mysql-test/t/binlog.test
@@ -0,0 +1,48 @@
+#
+# misc binlogging tests that do not require a slave running
+#
+-- source include/have_bdb.inc
+-- source include/have_innodb.inc
+
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+reset master;
+
+create table t1 (a int) engine=bdb;
+create table t2 (a int) engine=innodb;
+begin;
+insert t1 values (5);
+commit;
+begin;
+insert t2 values (5);
+commit;
+# first COMMIT must be Query_log_event, second - Xid_log_event
+--replace_result "xid=18" "xid=11"
+--replace_column 2 # 5 #
+show binlog events from 98;
+drop table t1,t2;
+
+#
+# binlog rotation after one big transaction
+#
+reset master;
+let $1=100;
+
+create table t1 (n int) engine=innodb;
+begin;
+--disable_query_log
+while ($1)
+{
+ eval insert into t1 values($1 + 4);
+ dec $1;
+}
+--enable_query_log
+commit;
+drop table t1;
+--replace_result "xid=29" "xid=18"
+--replace_column 2 # 5 #
+show binlog events in 'master-bin.000001' from 98;
+--replace_column 2 # 5 #
+show binlog events in 'master-bin.000002' from 98;
+
diff --git a/mysql-test/t/bool.test b/mysql-test/t/bool.test
index b263ecfded2..53230dd5fa3 100644
--- a/mysql-test/t/bool.test
+++ b/mysql-test/t/bool.test
@@ -20,6 +20,16 @@ SELECT * FROM t1 where (1 AND a)=0;
SELECT * FROM t1 where (1 AND a)=1;
SELECT * FROM t1 where (1 AND a) IS NULL;
+# WL#638 - Behaviour of NOT does not follow SQL specification
+set sql_mode='high_not_precedence';
+select * from t1 where not a between 2 and 3;
+set sql_mode=default;
+select * from t1 where not a between 2 and 3;
+
+# SQL boolean tests
+select a, a is false, a is true, a is unknown from t1;
+select a, a is not false, a is not true, a is not unknown from t1;
+
# Verify that NULL optimisation works in AND clause:
SET @a=0, @b=0;
SELECT * FROM t1 WHERE NULL AND (@a:=@a+1);
diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test
index 87e456baba7..fed3ff07a13 100644
--- a/mysql-test/t/case.test
+++ b/mysql-test/t/case.test
@@ -58,7 +58,10 @@ CREATE TABLE t1 SELECT
CASE WHEN 1 THEN 1.0 ELSE 'a' END AS c6,
CASE WHEN 1 THEN 1 ELSE 1.0 END AS c7,
CASE WHEN 1 THEN 1.0 ELSE 1 END AS c8,
- CASE WHEN 1 THEN 1.0 END AS c9
+ CASE WHEN 1 THEN 1.0 END AS c9,
+ CASE WHEN 1 THEN 0.1e1 else 0.1 END AS c10,
+ CASE WHEN 1 THEN 0.1e1 else 1 END AS c11,
+ CASE WHEN 1 THEN 0.1e1 else '1' END AS c12
;
SHOW CREATE TABLE t1;
DROP TABLE t1;
diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test
index aeab81585f0..cafecd6000d 100644
--- a/mysql-test/t/cast.test
+++ b/mysql-test/t/cast.test
@@ -4,6 +4,7 @@
select CAST(1-2 AS UNSIGNED);
select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER);
+select CAST('10 ' as unsigned integer);
select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1;
select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1;
select ~5, cast(~5 as signed);
@@ -15,11 +16,22 @@ select cast("A" as binary) = "a", cast(BINARY "a" as CHAR) = "A";
select cast("2001-1-1" as DATE), cast("2001-1-1" as DATETIME);
select cast("1:2:3" as TIME);
select CONVERT("2004-01-22 21:45:33",DATE);
+select 10+'10';
+select 10.0+'10';
+select 10E+0+'10';
+
+# The following cast creates warnings
+
select CONVERT(DATE "2004-01-22 21:45:33" USING latin1);
select CONVERT(DATE "2004-01-22 21:45:33",CHAR);
select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4));
select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4));
select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4));
+select cast('-10a' as signed integer);
+select cast('a10' as unsigned integer);
+select 10+'a';
+select 10.0+cast('a' as decimal);
+select 10E+0+'a';
# out-of-range cases
select cast('18446744073709551616' as unsigned);
@@ -49,6 +61,7 @@ select
cast(_latin1'abc' AS char(2)) as c3,
cast(_latin1'a ' AS char(2)) as c4,
cast(_latin1'a' AS char(2)) as c5;
+select cast(1000 as CHAR(3));
create table t1 select
cast(_latin1'ab' AS char) as c1,
@@ -142,3 +155,16 @@ select cast(concat('184467440','73709551615') as signed);
select cast(repeat('1',20) as unsigned);
select cast(repeat('1',20) as signed);
+
+#decimal-related additions
+select cast('1.2' as decimal(3,2));
+select 1e18 * cast('1.2' as decimal(3,2));
+select cast(cast('1.2' as decimal(3,2)) as signed);
+set @v1=1e18;
+select cast(@v1 as decimal(22, 2));
+select cast(-1e18 as decimal(22,2));
+
+create table t1(s1 time);
+insert into t1 values ('11:11:11');
+select cast(s1 as decimal(7,2)) from t1;
+drop table t1;
diff --git a/mysql-test/t/client_xml.test b/mysql-test/t/client_xml.test
new file mode 100644
index 00000000000..58e9178ef3a
--- /dev/null
+++ b/mysql-test/t/client_xml.test
@@ -0,0 +1,21 @@
+# Can't run with embedded server
+-- source include/not_embedded.inc
+
+# Test of the xml output of the 'mysql' and 'mysqldump' clients -- makes
+# sure that basic encoding issues are handled properly
+create table t1 (
+ `a&b` int,
+ `a<b` int,
+ `a>b` text
+);
+insert into t1 values (1, 2, 'a&b a<b a>b');
+--exec $MYSQL --xml test -e 'select * from t1'
+--exec $MYSQL_DUMP --xml --skip-create test
+
+--exec $MYSQL --xml test -e 'select count(*) from t1'
+--exec $MYSQL --xml test -e 'select 1 < 2 from dual'
+--exec $MYSQL --xml test -e 'select 1 > 2 from dual'
+--exec $MYSQL --xml test -e 'select 1 & 3 from dual'
+--exec $MYSQL --xml test -e 'select null from dual'
+
+drop table t1;
diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test
index 034cd11d0c1..5d2d53a2a90 100644
--- a/mysql-test/t/connect.test
+++ b/mysql-test/t/connect.test
@@ -52,7 +52,7 @@ flush privileges;
#show tables;
connect (con1,localhost,test,gambling2,mysql);
set password="";
---error 1105
+--error 1372
set password='gambling3';
set password=old_password('gambling3');
show tables;
diff --git a/mysql-test/t/count_distinct.test b/mysql-test/t/count_distinct.test
index 1f0404876cb..73c6951e78f 100644
--- a/mysql-test/t/count_distinct.test
+++ b/mysql-test/t/count_distinct.test
@@ -55,3 +55,11 @@ create table t1 (f int);
select count(distinct f) from t1;
drop table t1;
+#
+# Bug #6515
+#
+
+create table t1 (a char(3), b char(20), primary key (a, b));
+insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English');
+select count(distinct a) from t1 group by b;
+drop table t1;
diff --git a/mysql-test/t/count_distinct2.test b/mysql-test/t/count_distinct2.test
index 9100f622dec..2b982e3e620 100644
--- a/mysql-test/t/count_distinct2.test
+++ b/mysql-test/t/count_distinct2.test
@@ -64,7 +64,7 @@ select count(distinct n) from t1;
show status like 'Created_tmp_disk_tables';
drop table t1;
-#test conversion from heap to MyISAM
+# Test use of MyISAM tmp tables
create table t1 (s text);
let $1=5000;
disable_query_log;
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 6f222eedec1..1e2cf391221 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -49,14 +49,25 @@ create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int);
#
-# Some wrong defaults, so these creates should fail too
+# Some wrong defaults, so these creates should fail too (Bug #5902)
#
--error 1067
-create table test (a datetime default now());
+create table t1 (a datetime default now());
--error 1294
-create table test (a datetime on update now());
+create table t1 (a datetime on update now());
--error 1067
-create table test (a int default 100 auto_increment);
+create table t1 (a int default 100 auto_increment);
+--error 1067
+create table t1 (a tinyint default 1000);
+--error 1067
+create table t1 (a varchar(5) default 'abcdef');
+
+create table t1 (a varchar(5) default 'abcde');
+insert into t1 values();
+select * from t1;
+--error 1067
+alter table t1 alter column a set default 'abcdef';
+drop table t1;
#
# test of dummy table names
@@ -273,8 +284,8 @@ create table t3 like t1;
show create table t3;
select * from t3;
# Disable PS becasue of @@warning_count
---disable_ps_protocol
create table if not exists t3 like t1;
+--disable_ps_protocol
select @@warning_count;
--enable_ps_protocol
create temporary table t3 like t2;
@@ -294,7 +305,7 @@ select * from t2;
create table t3 like t1;
--error 1050
create table t3 like mysqltest.t3;
---error 1044,1
+--error ER_DBACCESS_DENIED_ERROR,1
create table non_existing_database.t1 like t1;
--error 1051
create table t3 like non_existing_table;
diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test
new file mode 100644
index 00000000000..fed87af3adc
--- /dev/null
+++ b/mysql-test/t/ctype_cp932.test
@@ -0,0 +1,405 @@
+-- source include/have_cp932.inc
+
+--character_set cp932
+--disable_warnings
+drop table if exists t1;
+drop table if exists t2;
+drop table if exists t3;
+drop table if exists t4;
+--enable_warnings
+
+set names cp932;
+set character_set_database = cp932;
+
+CREATE TABLE t1(c1 CHAR(1)) DEFAULT CHARACTER SET = cp932;
+
+#Characters which are converted to Unicode ambiguously
+INSERT INTO t1 VALUES
+(0x05),(0x7E),(0x815C),(0x815F),(0x8160),(0x8161),(0x817C),(0x8191),(0x8192),(0x81CA);
+
+#NEC ROW 13 characters (0x8740 - 0x879C)
+INSERT INTO t1 VALUES
+(0x8740),(0x8741),(0x8742),(0x8743),(0x8744),(0x8745),(0x8746),(0x8747),
+(0x8748),(0x8749),(0x874A),(0x874B),(0x874C),(0x874D),(0x874E),(0x874F),
+(0x8750),(0x8751),(0x8752),(0x8753),(0x8754),(0x8755),(0x8756),(0x8757),
+(0x8758),(0x8759),(0x875A),(0x875B),(0x875C),(0x875D),(0x875F),
+(0x8760),(0x8761),(0x8762),(0x8763),(0x8764),(0x8765),(0x8766),(0x8767),
+(0x8768),(0x8769),(0x876A),(0x876B),(0x876C),(0x876D),(0x876E),(0x876F),
+(0x8770),(0x8771),(0x8772),(0x8773),(0x8774),(0x8775),(0x877E),
+(0x8780),(0x8781),(0x8782),(0x8783),(0x8784),(0x8785),(0x8786),(0x8787),
+(0x8788),(0x8789),(0x878A),(0x878B),(0x878C),(0x878D),(0x878E),(0x878F),
+(0x8790),(0x8791),(0x8792),(0x8793),(0x8794),(0x8795),(0x8796),(0x8797),
+(0x8798),(0x8799),(0x879A),(0x879B),(0x879C);
+
+#IBM selected characters kanji & non-kanji, NEC implementation (0xED40 - 0xEEFC)
+INSERT INTO t1 VALUES
+(0xED40),(0xED41),(0xED42),(0xED43),(0xED44),(0xED45),(0xED46),(0xED47),
+(0xED48),(0xED49),(0xED4A),(0xED4B),(0xED4C),(0xED4D),(0xED4E),(0xED4F),
+(0xED50),(0xED51),(0xED52),(0xED53),(0xED54),(0xED55),(0xED56),(0xED57),
+(0xED58),(0xED59),(0xED5A),(0xED5B),(0xED5C),(0xED5D),(0xED5E),(0xED5F),
+(0xED60),(0xED61),(0xED62),(0xED63),(0xED64),(0xED65),(0xED66),(0xED67),
+(0xED68),(0xED69),(0xED6A),(0xED6B),(0xED6C),(0xED6D),(0xED6E),(0xED6F),
+(0xED70),(0xED71),(0xED72),(0xED73),(0xED74),(0xED75),(0xED76),(0xED77),
+(0xED78),(0xED79),(0xED7A),(0xED7B),(0xED7C),(0xED7D),(0xED7E),
+(0xED80),(0xED81),(0xED82),(0xED83),(0xED84),(0xED85),(0xED86),(0xED87),
+(0xED88),(0xED89),(0xED8A),(0xED8B),(0xED8C),(0xED8D),(0xED8E),(0xED8F),
+(0xED90),(0xED91),(0xED92),(0xED93),(0xED94),(0xED95),(0xED96),(0xED97),
+(0xED98),(0xED99),(0xED9A),(0xED9B),(0xED9C),(0xED9D),(0xED9E),(0xED9F),
+(0xEDA0),(0xEDA1),(0xEDA2),(0xEDA3),(0xEDA4),(0xEDA5),(0xEDA6),(0xEDA7),
+(0xEDA8),(0xEDA9),(0xEDAA),(0xEDAB),(0xEDAC),(0xEDAD),(0xEDAE),(0xEDAF),
+(0xEDB0),(0xEDB1),(0xEDB2),(0xEDB3),(0xEDB4),(0xEDB5),(0xEDB6),(0xEDB7),
+(0xEDB8),(0xEDB9),(0xEDBA),(0xEDBB),(0xEDBC),(0xEDBD),(0xEDBE),(0xEDBF),
+(0xEDC0),(0xEDC1),(0xEDC2),(0xEDC3),(0xEDC4),(0xEDC5),(0xEDC6),(0xEDC7),
+(0xEDC8),(0xEDC9),(0xEDCA),(0xEDCB),(0xEDCC),(0xEDCD),(0xEDCE),(0xEDCF),
+(0xEDD0),(0xEDD1),(0xEDD2),(0xEDD3),(0xEDD4),(0xEDD5),(0xEDD6),(0xEDD7),
+(0xEDD8),(0xEDD9),(0xEDDA),(0xEDDB),(0xEDDC),(0xEDDD),(0xEDDE),(0xEDDF),
+(0xEDE0),(0xEDE1),(0xEDE2),(0xEDE3),(0xEDE4),(0xEDE5),(0xEDE6),(0xEDE7),
+(0xEDE8),(0xEDE9),(0xEDEA),(0xEDEB),(0xEDEC),(0xEDED),(0xEDEE),(0xEDEF),
+(0xEDF0),(0xEDF1),(0xEDF2),(0xEDF3),(0xEDF4),(0xEDF5),(0xEDF6),(0xEDF7),
+(0xEDF8),(0xEDF9),(0xEDFA),(0xEDFB),(0xEDFC),
+(0xEE40),(0xEE41),(0xEE42),(0xEE43),(0xEE44),(0xEE45),(0xEE46),(0xEE47),
+(0xEE48),(0xEE49),(0xEE4A),(0xEE4B),(0xEE4C),(0xEE4D),(0xEE4E),(0xEE4F),
+(0xEE50),(0xEE51),(0xEE52),(0xEE53),(0xEE54),(0xEE55),(0xEE56),(0xEE57),
+(0xEE58),(0xEE59),(0xEE5A),(0xEE5B),(0xEE5C),(0xEE5D),(0xEE5E),(0xEE5F),
+(0xEE60),(0xEE61),(0xEE62),(0xEE63),(0xEE64),(0xEE65),(0xEE66),(0xEE67),
+(0xEE68),(0xEE69),(0xEE6A),(0xEE6B),(0xEE6C),(0xEE6D),(0xEE6E),(0xEE6F),
+(0xEE70),(0xEE71),(0xEE72),(0xEE73),(0xEE74),(0xEE75),(0xEE76),(0xEE77),
+(0xEE78),(0xEE79),(0xEE7A),(0xEE7B),(0xEE7C),(0xEE7D),(0xEE7E),
+(0xEE80),(0xEE81),(0xEE82),(0xEE83),(0xEE84),(0xEE85),(0xEE86),(0xEE87),
+(0xEE88),(0xEE89),(0xEE8A),(0xEE8B),(0xEE8C),(0xEE8D),(0xEE8E),(0xEE8F),
+(0xEE90),(0xEE91),(0xEE92),(0xEE93),(0xEE94),(0xEE95),(0xEE96),(0xEE97),
+(0xEE98),(0xEE99),(0xEE9A),(0xEE9B),(0xEE9C),(0xEE9D),(0xEE9E),(0xEE9F),
+(0xEEA0),(0xEEA1),(0xEEA2),(0xEEA3),(0xEEA4),(0xEEA5),(0xEEA6),(0xEEA7),
+(0xEEA8),(0xEEA9),(0xEEAA),(0xEEAB),(0xEEAC),(0xEEAD),(0xEEAE),(0xEEAF),
+(0xEEB0),(0xEEB1),(0xEEB2),(0xEEB3),(0xEEB4),(0xEEB5),(0xEEB6),(0xEEB7),
+(0xEEB8),(0xEEB9),(0xEEBA),(0xEEBB),(0xEEBC),(0xEEBD),(0xEEBE),(0xEEBF),
+(0xEEC0),(0xEEC1),(0xEEC2),(0xEEC3),(0xEEC4),(0xEEC5),(0xEEC6),(0xEEC7),
+(0xEEC8),(0xEEC9),(0xEECA),(0xEECB),(0xEECC),(0xEECD),(0xEECE),(0xEECF),
+(0xEED0),(0xEED1),(0xEED2),(0xEED3),(0xEED4),(0xEED5),(0xEED6),(0xEED7),
+(0xEED8),(0xEED9),(0xEEDA),(0xEEDB),(0xEEDC),(0xEEDD),(0xEEDE),(0xEEDF),
+(0xEEE0),(0xEEE1),(0xEEE2),(0xEEE3),(0xEEE4),(0xEEE5),(0xEEE6),(0xEEE7),
+(0xEEE8),(0xEEE9),(0xEEEA),(0xEEEB),(0xEEEC),(0xEEEF),
+(0xEEF0),(0xEEF1),(0xEEF2),(0xEEF3),(0xEEF4),(0xEEF5),(0xEEF6),(0xEEF7),
+(0xEEF8),(0xEEF9),(0xEEFA),(0xEEFB),(0xEEFC);
+
+#IBM selected kanji & non-kanji (0xFA40 - 0xFC4B)
+INSERT INTO t1 VALUES
+(0xFA40),(0xFA41),(0xFA42),(0xFA43),(0xFA44),(0xFA45),(0xFA46),(0xFA47),
+(0xFA48),(0xFA49),(0xFA4A),(0xFA4B),(0xFA4C),(0xFA4D),(0xFA4E),(0xFA4F),
+(0xFA50),(0xFA51),(0xFA52),(0xFA53),(0xFA54),(0xFA55),(0xFA56),(0xFA57),
+(0xFA58),(0xFA59),(0xFA5A),(0xFA5B),(0xFA5C),(0xFA5D),(0xFA5E),(0xFA5F),
+(0xFA60),(0xFA61),(0xFA62),(0xFA63),(0xFA64),(0xFA65),(0xFA66),(0xFA67),
+(0xFA68),(0xFA69),(0xFA6A),(0xFA6B),(0xFA6C),(0xFA6D),(0xFA6E),(0xFA6F),
+(0xFA70),(0xFA71),(0xFA72),(0xFA73),(0xFA74),(0xFA75),(0xFA76),(0xFA77),
+(0xFA78),(0xFA79),(0xFA7A),(0xFA7B),(0xFA7C),(0xFA7D),(0xFA7E),
+(0xFA80),(0xFA81),(0xFA82),(0xFA83),(0xFA84),(0xFA85),(0xFA86),(0xFA87),
+(0xFA88),(0xFA89),(0xFA8A),(0xFA8B),(0xFA8C),(0xFA8D),(0xFA8E),(0xFA8F),
+(0xFA90),(0xFA91),(0xFA92),(0xFA93),(0xFA94),(0xFA95),(0xFA96),(0xFA97),
+(0xFA98),(0xFA99),(0xFA9A),(0xFA9B),(0xFA9C),(0xFA9D),(0xFA9E),(0xFA9F),
+(0xFAA0),(0xFAA1),(0xFAA2),(0xFAA3),(0xFAA4),(0xFAA5),(0xFAA6),(0xFAA7),
+(0xFAA8),(0xFAA9),(0xFAAA),(0xFAAB),(0xFAAC),(0xFAAD),(0xFAAE),(0xFAAF),
+(0xFAB0),(0xFAB1),(0xFAB2),(0xFAB3),(0xFAB4),(0xFAB5),(0xFAB6),(0xFAB7),
+(0xFAB8),(0xFAB9),(0xFABA),(0xFABB),(0xFABC),(0xFABD),(0xFABE),(0xFABF),
+(0xFAC0),(0xFAC1),(0xFAC2),(0xFAC3),(0xFAC4),(0xFAC5),(0xFAC6),(0xFAC7),
+(0xFAC8),(0xFAC9),(0xFACA),(0xFACB),(0xFACC),(0xFACD),(0xFACE),(0xFACF),
+(0xFAD0),(0xFAD1),(0xFAD2),(0xFAD3),(0xFAD4),(0xFAD5),(0xFAD6),(0xFAD7),
+(0xFAD8),(0xFAD9),(0xFADA),(0xFADB),(0xFADC),(0xFADD),(0xFADE),(0xFADF),
+(0xFAE0),(0xFAE1),(0xFAE2),(0xFAE3),(0xFAE4),(0xFAE5),(0xFAE6),(0xFAE7),
+(0xFAE8),(0xFAE9),(0xFAEA),(0xFAEB),(0xFAEC),(0xFAED),(0xFAEE),(0xFAEF),
+(0xFAF0),(0xFAF1),(0xFAF2),(0xFAF3),(0xFAF4),(0xFAF5),(0xFAF6),(0xFAF7),
+(0xFAF8),(0xFAF9),(0xFAFA),(0xFAFB),(0xFAFC),
+(0xFB40),(0xFB41),(0xFB42),(0xFB43),(0xFB44),(0xFB45),(0xFB46),(0xFB47),
+(0xFB48),(0xFB49),(0xFB4A),(0xFB4B),(0xFB4C),(0xFB4D),(0xFB4E),(0xFB4F),
+(0xFB50),(0xFB51),(0xFB52),(0xFB53),(0xFB54),(0xFB55),(0xFB56),(0xFB57),
+(0xFB58),(0xFB59),(0xFB5A),(0xFB5B),(0xFB5C),(0xFB5D),(0xFB5E),(0xFB5F),
+(0xFB60),(0xFB61),(0xFB62),(0xFB63),(0xFB64),(0xFB65),(0xFB66),(0xFB67),
+(0xFB68),(0xFB69),(0xFB6A),(0xFB6B),(0xFB6C),(0xFB6D),(0xFB6E),(0xFB6F),
+(0xFB70),(0xFB71),(0xFB72),(0xFB73),(0xFB74),(0xFB75),(0xFB76),(0xFB77),
+(0xFB78),(0xFB79),(0xFB7A),(0xFB7B),(0xFB7C),(0xFB7D),(0xFB7E),
+(0xFB80),(0xFB81),(0xFB82),(0xFB83),(0xFB84),(0xFB85),(0xFB86),(0xFB87),
+(0xFB88),(0xFB89),(0xFB8A),(0xFB8B),(0xFB8C),(0xFB8D),(0xFB8E),(0xFB8F),
+(0xFB90),(0xFB91),(0xFB92),(0xFB93),(0xFB94),(0xFB95),(0xFB96),(0xFB97),
+(0xFB98),(0xFB99),(0xFB9A),(0xFB9B),(0xFB9C),(0xFB9D),(0xFB9E),(0xFB9F),
+(0xFBA0),(0xFBA1),(0xFBA2),(0xFBA3),(0xFBA4),(0xFBA5),(0xFBA6),(0xFBA7),
+(0xFBA8),(0xFBA9),(0xFBAA),(0xFBAB),(0xFBAC),(0xFBAD),(0xFBAE),(0xFBAF),
+(0xFBB0),(0xFBB1),(0xFBB2),(0xFBB3),(0xFBB4),(0xFBB5),(0xFBB6),(0xFBB7),
+(0xFBB8),(0xFBB9),(0xFBBA),(0xFBBB),(0xFBBC),(0xFBBD),(0xFBBE),(0xFBBF),
+(0xFBC0),(0xFBC1),(0xFBC2),(0xFBC3),(0xFBC4),(0xFBC5),(0xFBC6),(0xFBC7),
+(0xFBC8),(0xFBC9),(0xFBCA),(0xFBCB),(0xFBCC),(0xFBCD),(0xFBCE),(0xFBCF),
+(0xFBD0),(0xFBD1),(0xFBD2),(0xFBD3),(0xFBD4),(0xFBD5),(0xFBD6),(0xFBD7),
+(0xFBD8),(0xFBD9),(0xFBDA),(0xFBDB),(0xFBDC),(0xFBDD),(0xFBDE),(0xFBDF),
+(0xFBE0),(0xFBE1),(0xFBE2),(0xFBE3),(0xFBE4),(0xFBE5),(0xFBE6),(0xFBE7),
+(0xFBE8),(0xFBE9),(0xFBEA),(0xFBEB),(0xFBEC),(0xFBED),(0xFBEE),(0xFBEF),
+(0xFBF0),(0xFBF1),(0xFBF2),(0xFBF3),(0xFBF4),(0xFBF5),(0xFBF6),(0xFBF7),
+(0xFBF8),(0xFBF9),(0xFBFA),(0xFBFB),(0xFBFC),
+(0xFC40),(0xFC41),(0xFC42),(0xFC43),(0xFC44),(0xFC45),(0xFC46),(0xFC47),
+(0xFC48),(0xFC49),(0xFC4A),(0xFC4B);
+
+#User defined characters (0xF040-0xF9FC)
+INSERT INTO t1 VALUES
+(0xF040),(0xF041),(0xF042),(0xF043),(0xF044),(0xF045),(0xF046),(0xF047),
+(0xF048),(0xF049),(0xF04A),(0xF04B),(0xF04C),(0xF04D),(0xF04E),(0xF04F),
+(0xF050),(0xF051),(0xF052),(0xF053),(0xF054),(0xF055),(0xF056),(0xF057),
+(0xF058),(0xF059),(0xF05A),(0xF05B),(0xF05C),(0xF05D),(0xF05E),(0xF05F),
+(0xF060),(0xF061),(0xF062),(0xF063),(0xF064),(0xF065),(0xF066),(0xF067),
+(0xF068),(0xF069),(0xF06A),(0xF06B),(0xF06C),(0xF06D),(0xF06E),(0xF06F),
+(0xF070),(0xF071),(0xF072),(0xF073),(0xF074),(0xF075),(0xF076),(0xF077),
+(0xF078),(0xF079),(0xF07A),(0xF07B),(0xF07C),(0xF07D),(0xF07E),
+(0xF080),(0xF081),(0xF082),(0xF083),(0xF084),(0xF085),(0xF086),(0xF087),
+(0xF088),(0xF089),(0xF08A),(0xF08B),(0xF08C),(0xF08D),(0xF08E),(0xF08F),
+(0xF090),(0xF091),(0xF092),(0xF093),(0xF094),(0xF095),(0xF096),(0xF097),
+(0xF098),(0xF099),(0xF09A),(0xF09B),(0xF09C),(0xF09D),(0xF09E),(0xF09F),
+(0xF0A0),(0xF0A1),(0xF0A2),(0xF0A3),(0xF0A4),(0xF0A5),(0xF0A6),(0xF0A7),
+(0xF0A8),(0xF0A9),(0xF0AA),(0xF0AB),(0xF0AC),(0xF0AD),(0xF0AE),(0xF0AF),
+(0xF0B0),(0xF0B1),(0xF0B2),(0xF0B3),(0xF0B4),(0xF0B5),(0xF0B6),(0xF0B7),
+(0xF0B8),(0xF0B9),(0xF0BA),(0xF0BB),(0xF0BC),(0xF0BD),(0xF0BE),(0xF0BF),
+(0xF0C0),(0xF0C1),(0xF0C2),(0xF0C3),(0xF0C4),(0xF0C5),(0xF0C6),(0xF0C7),
+(0xF0C8),(0xF0C9),(0xF0CA),(0xF0CB),(0xF0CC),(0xF0CD),(0xF0CE),(0xF0CF),
+(0xF0D0),(0xF0D1),(0xF0D2),(0xF0D3),(0xF0D4),(0xF0D5),(0xF0D6),(0xF0D7),
+(0xF0D8),(0xF0D9),(0xF0DA),(0xF0DB),(0xF0DC),(0xF0DD),(0xF0DE),(0xF0DF),
+(0xF0E0),(0xF0E1),(0xF0E2),(0xF0E3),(0xF0E4),(0xF0E5),(0xF0E6),(0xF0E7),
+(0xF0E8),(0xF0E9),(0xF0EA),(0xF0EB),(0xF0EC),(0xF0ED),(0xF0EE),(0xF0EF),
+(0xF0F0),(0xF0F1),(0xF0F2),(0xF0F3),(0xF0F4),(0xF0F5),(0xF0F6),(0xF0F7),
+(0xF0F8),(0xF0F9),(0xF0FA),(0xF0FB),(0xF0FC),
+(0xF140),(0xF141),(0xF142),(0xF143),(0xF144),(0xF145),(0xF146),(0xF147),
+(0xF148),(0xF149),(0xF14A),(0xF14B),(0xF14C),(0xF14D),(0xF14E),(0xF14F),
+(0xF150),(0xF151),(0xF152),(0xF153),(0xF154),(0xF155),(0xF156),(0xF157),
+(0xF158),(0xF159),(0xF15A),(0xF15B),(0xF15C),(0xF15D),(0xF15E),(0xF15F),
+(0xF160),(0xF161),(0xF162),(0xF163),(0xF164),(0xF165),(0xF166),(0xF167),
+(0xF168),(0xF169),(0xF16A),(0xF16B),(0xF16C),(0xF16D),(0xF16E),(0xF16F),
+(0xF170),(0xF171),(0xF172),(0xF173),(0xF174),(0xF175),(0xF176),(0xF177),
+(0xF178),(0xF179),(0xF17A),(0xF17B),(0xF17C),(0xF17D),(0xF17E),
+(0xF180),(0xF181),(0xF182),(0xF183),(0xF184),(0xF185),(0xF186),(0xF187),
+(0xF188),(0xF189),(0xF18A),(0xF18B),(0xF18C),(0xF18D),(0xF18E),(0xF18F),
+(0xF190),(0xF191),(0xF192),(0xF193),(0xF194),(0xF195),(0xF196),(0xF197),
+(0xF198),(0xF199),(0xF19A),(0xF19B),(0xF19C),(0xF19D),(0xF19E),(0xF19F),
+(0xF1A0),(0xF1A1),(0xF1A2),(0xF1A3),(0xF1A4),(0xF1A5),(0xF1A6),(0xF1A7),
+(0xF1A8),(0xF1A9),(0xF1AA),(0xF1AB),(0xF1AC),(0xF1AD),(0xF1AE),(0xF1AF),
+(0xF1B0),(0xF1B1),(0xF1B2),(0xF1B3),(0xF1B4),(0xF1B5),(0xF1B6),(0xF1B7),
+(0xF1B8),(0xF1B9),(0xF1BA),(0xF1BB),(0xF1BC),(0xF1BD),(0xF1BE),(0xF1BF),
+(0xF1C0),(0xF1C1),(0xF1C2),(0xF1C3),(0xF1C4),(0xF1C5),(0xF1C6),(0xF1C7),
+(0xF1C8),(0xF1C9),(0xF1CA),(0xF1CB),(0xF1CC),(0xF1CD),(0xF1CE),(0xF1CF),
+(0xF1D0),(0xF1D1),(0xF1D2),(0xF1D3),(0xF1D4),(0xF1D5),(0xF1D6),(0xF1D7),
+(0xF1D8),(0xF1D9),(0xF1DA),(0xF1DB),(0xF1DC),(0xF1DD),(0xF1DE),(0xF1DF),
+(0xF1E0),(0xF1E1),(0xF1E2),(0xF1E3),(0xF1E4),(0xF1E5),(0xF1E6),(0xF1E7),
+(0xF1E8),(0xF1E9),(0xF1EA),(0xF1EB),(0xF1EC),(0xF1ED),(0xF1EE),(0xF1EF),
+(0xF1F0),(0xF1F1),(0xF1F2),(0xF1F3),(0xF1F4),(0xF1F5),(0xF1F6),(0xF1F7),
+(0xF1F8),(0xF1F9),(0xF1FA),(0xF1FB),(0xF1FC),
+(0xF240),(0xF241),(0xF242),(0xF243),(0xF244),(0xF245),(0xF246),(0xF247),
+(0xF248),(0xF249),(0xF24A),(0xF24B),(0xF24C),(0xF24D),(0xF24E),(0xF24F),
+(0xF250),(0xF251),(0xF252),(0xF253),(0xF254),(0xF255),(0xF256),(0xF257),
+(0xF258),(0xF259),(0xF25A),(0xF25B),(0xF25C),(0xF25D),(0xF25E),(0xF25F),
+(0xF260),(0xF261),(0xF262),(0xF263),(0xF264),(0xF265),(0xF266),(0xF267),
+(0xF268),(0xF269),(0xF26A),(0xF26B),(0xF26C),(0xF26D),(0xF26E),(0xF26F),
+(0xF270),(0xF271),(0xF272),(0xF273),(0xF274),(0xF275),(0xF276),(0xF277),
+(0xF278),(0xF279),(0xF27A),(0xF27B),(0xF27C),(0xF27D),(0xF27E),
+(0xF280),(0xF281),(0xF282),(0xF283),(0xF284),(0xF285),(0xF286),(0xF287),
+(0xF288),(0xF289),(0xF28A),(0xF28B),(0xF28C),(0xF28D),(0xF28E),(0xF28F),
+(0xF290),(0xF291),(0xF292),(0xF293),(0xF294),(0xF295),(0xF296),(0xF297),
+(0xF298),(0xF299),(0xF29A),(0xF29B),(0xF29C),(0xF29D),(0xF29E),(0xF29F),
+(0xF2A0),(0xF2A1),(0xF2A2),(0xF2A3),(0xF2A4),(0xF2A5),(0xF2A6),(0xF2A7),
+(0xF2A8),(0xF2A9),(0xF2AA),(0xF2AB),(0xF2AC),(0xF2AD),(0xF2AE),(0xF2AF),
+(0xF2B0),(0xF2B1),(0xF2B2),(0xF2B3),(0xF2B4),(0xF2B5),(0xF2B6),(0xF2B7),
+(0xF2B8),(0xF2B9),(0xF2BA),(0xF2BB),(0xF2BC),(0xF2BD),(0xF2BE),(0xF2BF),
+(0xF2C0),(0xF2C1),(0xF2C2),(0xF2C3),(0xF2C4),(0xF2C5),(0xF2C6),(0xF2C7),
+(0xF2C8),(0xF2C9),(0xF2CA),(0xF2CB),(0xF2CC),(0xF2CD),(0xF2CE),(0xF2CF),
+(0xF2D0),(0xF2D1),(0xF2D2),(0xF2D3),(0xF2D4),(0xF2D5),(0xF2D6),(0xF2D7),
+(0xF2D8),(0xF2D9),(0xF2DA),(0xF2DB),(0xF2DC),(0xF2DD),(0xF2DE),(0xF2DF),
+(0xF2E0),(0xF2E1),(0xF2E2),(0xF2E3),(0xF2E4),(0xF2E5),(0xF2E6),(0xF2E7),
+(0xF2E8),(0xF2E9),(0xF2EA),(0xF2EB),(0xF2EC),(0xF2ED),(0xF2EE),(0xF2EF),
+(0xF2F0),(0xF2F1),(0xF2F2),(0xF2F3),(0xF2F4),(0xF2F5),(0xF2F6),(0xF2F7),
+(0xF2F8),(0xF2F9),(0xF2FA),(0xF2FB),(0xF2FC),
+(0xF340),(0xF341),(0xF342),(0xF343),(0xF344),(0xF345),(0xF346),(0xF347),
+(0xF348),(0xF349),(0xF34A),(0xF34B),(0xF34C),(0xF34D),(0xF34E),(0xF34F),
+(0xF350),(0xF351),(0xF352),(0xF353),(0xF354),(0xF355),(0xF356),(0xF357),
+(0xF358),(0xF359),(0xF35A),(0xF35B),(0xF35C),(0xF35D),(0xF35E),(0xF35F),
+(0xF360),(0xF361),(0xF362),(0xF363),(0xF364),(0xF365),(0xF366),(0xF367),
+(0xF368),(0xF369),(0xF36A),(0xF36B),(0xF36C),(0xF36D),(0xF36E),(0xF36F),
+(0xF370),(0xF371),(0xF372),(0xF373),(0xF374),(0xF375),(0xF376),(0xF377),
+(0xF378),(0xF379),(0xF37A),(0xF37B),(0xF37C),(0xF37D),(0xF37E),
+(0xF380),(0xF381),(0xF382),(0xF383),(0xF384),(0xF385),(0xF386),(0xF387),
+(0xF388),(0xF389),(0xF38A),(0xF38B),(0xF38C),(0xF38D),(0xF38E),(0xF38F),
+(0xF390),(0xF391),(0xF392),(0xF393),(0xF394),(0xF395),(0xF396),(0xF397),
+(0xF398),(0xF399),(0xF39A),(0xF39B),(0xF39C),(0xF39D),(0xF39E),(0xF39F),
+(0xF3A0),(0xF3A1),(0xF3A2),(0xF3A3),(0xF3A4),(0xF3A5),(0xF3A6),(0xF3A7),
+(0xF3A8),(0xF3A9),(0xF3AA),(0xF3AB),(0xF3AC),(0xF3AD),(0xF3AE),(0xF3AF),
+(0xF3B0),(0xF3B1),(0xF3B2),(0xF3B3),(0xF3B4),(0xF3B5),(0xF3B6),(0xF3B7),
+(0xF3B8),(0xF3B9),(0xF3BA),(0xF3BB),(0xF3BC),(0xF3BD),(0xF3BE),(0xF3BF),
+(0xF3C0),(0xF3C1),(0xF3C2),(0xF3C3),(0xF3C4),(0xF3C5),(0xF3C6),(0xF3C7),
+(0xF3C8),(0xF3C9),(0xF3CA),(0xF3CB),(0xF3CC),(0xF3CD),(0xF3CE),(0xF3CF),
+(0xF3D0),(0xF3D1),(0xF3D2),(0xF3D3),(0xF3D4),(0xF3D5),(0xF3D6),(0xF3D7),
+(0xF3D8),(0xF3D9),(0xF3DA),(0xF3DB),(0xF3DC),(0xF3DD),(0xF3DE),(0xF3DF),
+(0xF3E0),(0xF3E1),(0xF3E2),(0xF3E3),(0xF3E4),(0xF3E5),(0xF3E6),(0xF3E7),
+(0xF3E8),(0xF3E9),(0xF3EA),(0xF3EB),(0xF3EC),(0xF3ED),(0xF3EE),(0xF3EF),
+(0xF3F0),(0xF3F1),(0xF3F2),(0xF3F3),(0xF3F4),(0xF3F5),(0xF3F6),(0xF3F7),
+(0xF3F8),(0xF3F9),(0xF3FA),(0xF3FB),(0xF3FC),
+(0xF440),(0xF441),(0xF442),(0xF443),(0xF444),(0xF445),(0xF446),(0xF447),
+(0xF448),(0xF449),(0xF44A),(0xF44B),(0xF44C),(0xF44D),(0xF44E),(0xF44F),
+(0xF450),(0xF451),(0xF452),(0xF453),(0xF454),(0xF455),(0xF456),(0xF457),
+(0xF458),(0xF459),(0xF45A),(0xF45B),(0xF45C),(0xF45D),(0xF45E),(0xF45F),
+(0xF460),(0xF461),(0xF462),(0xF463),(0xF464),(0xF465),(0xF466),(0xF467),
+(0xF468),(0xF469),(0xF46A),(0xF46B),(0xF46C),(0xF46D),(0xF46E),(0xF46F),
+(0xF470),(0xF471),(0xF472),(0xF473),(0xF474),(0xF475),(0xF476),(0xF477),
+(0xF478),(0xF479),(0xF47A),(0xF47B),(0xF47C),(0xF47D),(0xF47E),
+(0xF480),(0xF481),(0xF482),(0xF483),(0xF484),(0xF485),(0xF486),(0xF487),
+(0xF488),(0xF489),(0xF48A),(0xF48B),(0xF48C),(0xF48D),(0xF48E),(0xF48F),
+(0xF490),(0xF491),(0xF492),(0xF493),(0xF494),(0xF495),(0xF496),(0xF497),
+(0xF498),(0xF499),(0xF49A),(0xF49B),(0xF49C),(0xF49D),(0xF49E),(0xF49F),
+(0xF4A0),(0xF4A1),(0xF4A2),(0xF4A3),(0xF4A4),(0xF4A5),(0xF4A6),(0xF4A7),
+(0xF4A8),(0xF4A9),(0xF4AA),(0xF4AB),(0xF4AC),(0xF4AD),(0xF4AE),(0xF4AF),
+(0xF4B0),(0xF4B1),(0xF4B2),(0xF4B3),(0xF4B4),(0xF4B5),(0xF4B6),(0xF4B7),
+(0xF4B8),(0xF4B9),(0xF4BA),(0xF4BB),(0xF4BC),(0xF4BD),(0xF4BE),(0xF4BF),
+(0xF4C0),(0xF4C1),(0xF4C2),(0xF4C3),(0xF4C4),(0xF4C5),(0xF4C6),(0xF4C7),
+(0xF4C8),(0xF4C9),(0xF4CA),(0xF4CB),(0xF4CC),(0xF4CD),(0xF4CE),(0xF4CF),
+(0xF4D0),(0xF4D1),(0xF4D2),(0xF4D3),(0xF4D4),(0xF4D5),(0xF4D6),(0xF4D7),
+(0xF4D8),(0xF4D9),(0xF4DA),(0xF4DB),(0xF4DC),(0xF4DD),(0xF4DE),(0xF4DF),
+(0xF4E0),(0xF4E1),(0xF4E2),(0xF4E3),(0xF4E4),(0xF4E5),(0xF4E6),(0xF4E7),
+(0xF4E8),(0xF4E9),(0xF4EA),(0xF4EB),(0xF4EC),(0xF4ED),(0xF4EE),(0xF4EF),
+(0xF4F0),(0xF4F1),(0xF4F2),(0xF4F3),(0xF4F4),(0xF4F5),(0xF4F6),(0xF4F7),
+(0xF4F8),(0xF4F9),(0xF4FA),(0xF4FB),(0xF4FC),
+(0xF540),(0xF541),(0xF542),(0xF543),(0xF544),(0xF545),(0xF546),(0xF547),
+(0xF548),(0xF549),(0xF54A),(0xF54B),(0xF54C),(0xF54D),(0xF54E),(0xF54F),
+(0xF550),(0xF551),(0xF552),(0xF553),(0xF554),(0xF555),(0xF556),(0xF557),
+(0xF558),(0xF559),(0xF55A),(0xF55B),(0xF55C),(0xF55D),(0xF55E),(0xF55F),
+(0xF560),(0xF561),(0xF562),(0xF563),(0xF564),(0xF565),(0xF566),(0xF567),
+(0xF568),(0xF569),(0xF56A),(0xF56B),(0xF56C),(0xF56D),(0xF56E),(0xF56F),
+(0xF570),(0xF571),(0xF572),(0xF573),(0xF574),(0xF575),(0xF576),(0xF577),
+(0xF578),(0xF579),(0xF57A),(0xF57B),(0xF57C),(0xF57D),(0xF57E),
+(0xF580),(0xF581),(0xF582),(0xF583),(0xF584),(0xF585),(0xF586),(0xF587),
+(0xF588),(0xF589),(0xF58A),(0xF58B),(0xF58C),(0xF58D),(0xF58E),(0xF58F),
+(0xF590),(0xF591),(0xF592),(0xF593),(0xF594),(0xF595),(0xF596),(0xF597),
+(0xF598),(0xF599),(0xF59A),(0xF59B),(0xF59C),(0xF59D),(0xF59E),(0xF59F),
+(0xF5A0),(0xF5A1),(0xF5A2),(0xF5A3),(0xF5A4),(0xF5A5),(0xF5A6),(0xF5A7),
+(0xF5A8),(0xF5A9),(0xF5AA),(0xF5AB),(0xF5AC),(0xF5AD),(0xF5AE),(0xF5AF),
+(0xF5B0),(0xF5B1),(0xF5B2),(0xF5B3),(0xF5B4),(0xF5B5),(0xF5B6),(0xF5B7),
+(0xF5B8),(0xF5B9),(0xF5BA),(0xF5BB),(0xF5BC),(0xF5BD),(0xF5BE),(0xF5BF),
+(0xF5C0),(0xF5C1),(0xF5C2),(0xF5C3),(0xF5C4),(0xF5C5),(0xF5C6),(0xF5C7),
+(0xF5C8),(0xF5C9),(0xF5CA),(0xF5CB),(0xF5CC),(0xF5CD),(0xF5CE),(0xF5CF),
+(0xF5D0),(0xF5D1),(0xF5D2),(0xF5D3),(0xF5D4),(0xF5D5),(0xF5D6),(0xF5D7),
+(0xF5D8),(0xF5D9),(0xF5DA),(0xF5DB),(0xF5DC),(0xF5DD),(0xF5DE),(0xF5DF),
+(0xF5E0),(0xF5E1),(0xF5E2),(0xF5E3),(0xF5E4),(0xF5E5),(0xF5E6),(0xF5E7),
+(0xF5E8),(0xF5E9),(0xF5EA),(0xF5EB),(0xF5EC),(0xF5ED),(0xF5EE),(0xF5EF),
+(0xF5F0),(0xF5F1),(0xF5F2),(0xF5F3),(0xF5F4),(0xF5F5),(0xF5F6),(0xF5F7),
+(0xF5F8),(0xF5F9),(0xF5FA),(0xF5FB),(0xF5FC),
+(0xF640),(0xF641),(0xF642),(0xF643),(0xF644),(0xF645),(0xF646),(0xF647),
+(0xF648),(0xF649),(0xF64A),(0xF64B),(0xF64C),(0xF64D),(0xF64E),(0xF64F),
+(0xF650),(0xF651),(0xF652),(0xF653),(0xF654),(0xF655),(0xF656),(0xF657),
+(0xF658),(0xF659),(0xF65A),(0xF65B),(0xF65C),(0xF65D),(0xF65E),(0xF65F),
+(0xF660),(0xF661),(0xF662),(0xF663),(0xF664),(0xF665),(0xF666),(0xF667),
+(0xF668),(0xF669),(0xF66A),(0xF66B),(0xF66C),(0xF66D),(0xF66E),(0xF66F),
+(0xF670),(0xF671),(0xF672),(0xF673),(0xF674),(0xF675),(0xF676),(0xF677),
+(0xF678),(0xF679),(0xF67A),(0xF67B),(0xF67C),(0xF67D),(0xF67E),
+(0xF680),(0xF681),(0xF682),(0xF683),(0xF684),(0xF685),(0xF686),(0xF687),
+(0xF688),(0xF689),(0xF68A),(0xF68B),(0xF68C),(0xF68D),(0xF68E),(0xF68F),
+(0xF690),(0xF691),(0xF692),(0xF693),(0xF694),(0xF695),(0xF696),(0xF697),
+(0xF698),(0xF699),(0xF69A),(0xF69B),(0xF69C),(0xF69D),(0xF69E),(0xF69F),
+(0xF6A0),(0xF6A1),(0xF6A2),(0xF6A3),(0xF6A4),(0xF6A5),(0xF6A6),(0xF6A7),
+(0xF6A8),(0xF6A9),(0xF6AA),(0xF6AB),(0xF6AC),(0xF6AD),(0xF6AE),(0xF6AF),
+(0xF6B0),(0xF6B1),(0xF6B2),(0xF6B3),(0xF6B4),(0xF6B5),(0xF6B6),(0xF6B7),
+(0xF6B8),(0xF6B9),(0xF6BA),(0xF6BB),(0xF6BC),(0xF6BD),(0xF6BE),(0xF6BF),
+(0xF6C0),(0xF6C1),(0xF6C2),(0xF6C3),(0xF6C4),(0xF6C5),(0xF6C6),(0xF6C7),
+(0xF6C8),(0xF6C9),(0xF6CA),(0xF6CB),(0xF6CC),(0xF6CD),(0xF6CE),(0xF6CF),
+(0xF6D0),(0xF6D1),(0xF6D2),(0xF6D3),(0xF6D4),(0xF6D5),(0xF6D6),(0xF6D7),
+(0xF6D8),(0xF6D9),(0xF6DA),(0xF6DB),(0xF6DC),(0xF6DD),(0xF6DE),(0xF6DF),
+(0xF6E0),(0xF6E1),(0xF6E2),(0xF6E3),(0xF6E4),(0xF6E5),(0xF6E6),(0xF6E7),
+(0xF6E8),(0xF6E9),(0xF6EA),(0xF6EB),(0xF6EC),(0xF6ED),(0xF6EE),(0xF6EF),
+(0xF6F0),(0xF6F1),(0xF6F2),(0xF6F3),(0xF6F4),(0xF6F5),(0xF6F6),(0xF6F7),
+(0xF6F8),(0xF6F9),(0xF6FA),(0xF6FB),(0xF6FC),
+(0xF740),(0xF741),(0xF742),(0xF743),(0xF744),(0xF745),(0xF746),(0xF747),
+(0xF748),(0xF749),(0xF74A),(0xF74B),(0xF74C),(0xF74D),(0xF74E),(0xF74F),
+(0xF750),(0xF751),(0xF752),(0xF753),(0xF754),(0xF755),(0xF756),(0xF757),
+(0xF758),(0xF759),(0xF75A),(0xF75B),(0xF75C),(0xF75D),(0xF75E),(0xF75F),
+(0xF760),(0xF761),(0xF762),(0xF763),(0xF764),(0xF765),(0xF766),(0xF767),
+(0xF768),(0xF769),(0xF76A),(0xF76B),(0xF76C),(0xF76D),(0xF76E),(0xF76F),
+(0xF770),(0xF771),(0xF772),(0xF773),(0xF774),(0xF775),(0xF776),(0xF777),
+(0xF778),(0xF779),(0xF77A),(0xF77B),(0xF77C),(0xF77D),(0xF77E),
+(0xF780),(0xF781),(0xF782),(0xF783),(0xF784),(0xF785),(0xF786),(0xF787),
+(0xF788),(0xF789),(0xF78A),(0xF78B),(0xF78C),(0xF78D),(0xF78E),(0xF78F),
+(0xF790),(0xF791),(0xF792),(0xF793),(0xF794),(0xF795),(0xF796),(0xF797),
+(0xF798),(0xF799),(0xF79A),(0xF79B),(0xF79C),(0xF79D),(0xF79E),(0xF79F),
+(0xF7A0),(0xF7A1),(0xF7A2),(0xF7A3),(0xF7A4),(0xF7A5),(0xF7A6),(0xF7A7),
+(0xF7A8),(0xF7A9),(0xF7AA),(0xF7AB),(0xF7AC),(0xF7AD),(0xF7AE),(0xF7AF),
+(0xF7B0),(0xF7B1),(0xF7B2),(0xF7B3),(0xF7B4),(0xF7B5),(0xF7B6),(0xF7B7),
+(0xF7B8),(0xF7B9),(0xF7BA),(0xF7BB),(0xF7BC),(0xF7BD),(0xF7BE),(0xF7BF),
+(0xF7C0),(0xF7C1),(0xF7C2),(0xF7C3),(0xF7C4),(0xF7C5),(0xF7C6),(0xF7C7),
+(0xF7C8),(0xF7C9),(0xF7CA),(0xF7CB),(0xF7CC),(0xF7CD),(0xF7CE),(0xF7CF),
+(0xF7D0),(0xF7D1),(0xF7D2),(0xF7D3),(0xF7D4),(0xF7D5),(0xF7D6),(0xF7D7),
+(0xF7D8),(0xF7D9),(0xF7DA),(0xF7DB),(0xF7DC),(0xF7DD),(0xF7DE),(0xF7DF),
+(0xF7E0),(0xF7E1),(0xF7E2),(0xF7E3),(0xF7E4),(0xF7E5),(0xF7E6),(0xF7E7),
+(0xF7E8),(0xF7E9),(0xF7EA),(0xF7EB),(0xF7EC),(0xF7ED),(0xF7EE),(0xF7EF),
+(0xF7F0),(0xF7F1),(0xF7F2),(0xF7F3),(0xF7F4),(0xF7F5),(0xF7F6),(0xF7F7),
+(0xF7F8),(0xF7F9),(0xF7FA),(0xF7FB),(0xF7FC),
+(0xF840),(0xF841),(0xF842),(0xF843),(0xF844),(0xF845),(0xF846),(0xF847),
+(0xF848),(0xF849),(0xF84A),(0xF84B),(0xF84C),(0xF84D),(0xF84E),(0xF84F),
+(0xF850),(0xF851),(0xF852),(0xF853),(0xF854),(0xF855),(0xF856),(0xF857),
+(0xF858),(0xF859),(0xF85A),(0xF85B),(0xF85C),(0xF85D),(0xF85E),(0xF85F),
+(0xF860),(0xF861),(0xF862),(0xF863),(0xF864),(0xF865),(0xF866),(0xF867),
+(0xF868),(0xF869),(0xF86A),(0xF86B),(0xF86C),(0xF86D),(0xF86E),(0xF86F),
+(0xF870),(0xF871),(0xF872),(0xF873),(0xF874),(0xF875),(0xF876),(0xF877),
+(0xF878),(0xF879),(0xF87A),(0xF87B),(0xF87C),(0xF87D),(0xF87E),
+(0xF880),(0xF881),(0xF882),(0xF883),(0xF884),(0xF885),(0xF886),(0xF887),
+(0xF888),(0xF889),(0xF88A),(0xF88B),(0xF88C),(0xF88D),(0xF88E),(0xF88F),
+(0xF890),(0xF891),(0xF892),(0xF893),(0xF894),(0xF895),(0xF896),(0xF897),
+(0xF898),(0xF899),(0xF89A),(0xF89B),(0xF89C),(0xF89D),(0xF89E),(0xF89F),
+(0xF8A0),(0xF8A1),(0xF8A2),(0xF8A3),(0xF8A4),(0xF8A5),(0xF8A6),(0xF8A7),
+(0xF8A8),(0xF8A9),(0xF8AA),(0xF8AB),(0xF8AC),(0xF8AD),(0xF8AE),(0xF8AF),
+(0xF8B0),(0xF8B1),(0xF8B2),(0xF8B3),(0xF8B4),(0xF8B5),(0xF8B6),(0xF8B7),
+(0xF8B8),(0xF8B9),(0xF8BA),(0xF8BB),(0xF8BC),(0xF8BD),(0xF8BE),(0xF8BF),
+(0xF8C0),(0xF8C1),(0xF8C2),(0xF8C3),(0xF8C4),(0xF8C5),(0xF8C6),(0xF8C7),
+(0xF8C8),(0xF8C9),(0xF8CA),(0xF8CB),(0xF8CC),(0xF8CD),(0xF8CE),(0xF8CF),
+(0xF8D0),(0xF8D1),(0xF8D2),(0xF8D3),(0xF8D4),(0xF8D5),(0xF8D6),(0xF8D7),
+(0xF8D8),(0xF8D9),(0xF8DA),(0xF8DB),(0xF8DC),(0xF8DD),(0xF8DE),(0xF8DF),
+(0xF8E0),(0xF8E1),(0xF8E2),(0xF8E3),(0xF8E4),(0xF8E5),(0xF8E6),(0xF8E7),
+(0xF8E8),(0xF8E9),(0xF8EA),(0xF8EB),(0xF8EC),(0xF8ED),(0xF8EE),(0xF8EF),
+(0xF8F0),(0xF8F1),(0xF8F2),(0xF8F3),(0xF8F4),(0xF8F5),(0xF8F6),(0xF8F7),
+(0xF8F8),(0xF8F9),(0xF8FA),(0xF8FB),(0xF8FC),
+(0xF940),(0xF941),(0xF942),(0xF943),(0xF944),(0xF945),(0xF946),(0xF947),
+(0xF948),(0xF949),(0xF94A),(0xF94B),(0xF94C),(0xF94D),(0xF94E),(0xF94F),
+(0xF950),(0xF951),(0xF952),(0xF953),(0xF954),(0xF955),(0xF956),(0xF957),
+(0xF958),(0xF959),(0xF95A),(0xF95B),(0xF95C),(0xF95D),(0xF95E),(0xF95F),
+(0xF960),(0xF961),(0xF962),(0xF963),(0xF964),(0xF965),(0xF966),(0xF967),
+(0xF968),(0xF969),(0xF96A),(0xF96B),(0xF96C),(0xF96D),(0xF96E),(0xF96F),
+(0xF970),(0xF971),(0xF972),(0xF973),(0xF974),(0xF975),(0xF976),(0xF977),
+(0xF978),(0xF979),(0xF97A),(0xF97B),(0xF97C),(0xF97D),(0xF97E),
+(0xF980),(0xF981),(0xF982),(0xF983),(0xF984),(0xF985),(0xF986),(0xF987),
+(0xF988),(0xF989),(0xF98A),(0xF98B),(0xF98C),(0xF98D),(0xF98E),(0xF98F),
+(0xF990),(0xF991),(0xF992),(0xF993),(0xF994),(0xF995),(0xF996),(0xF997),
+(0xF998),(0xF999),(0xF99A),(0xF99B),(0xF99C),(0xF99D),(0xF99E),(0xF99F),
+(0xF9A0),(0xF9A1),(0xF9A2),(0xF9A3),(0xF9A4),(0xF9A5),(0xF9A6),(0xF9A7),
+(0xF9A8),(0xF9A9),(0xF9AA),(0xF9AB),(0xF9AC),(0xF9AD),(0xF9AE),(0xF9AF),
+(0xF9B0),(0xF9B1),(0xF9B2),(0xF9B3),(0xF9B4),(0xF9B5),(0xF9B6),(0xF9B7),
+(0xF9B8),(0xF9B9),(0xF9BA),(0xF9BB),(0xF9BC),(0xF9BD),(0xF9BE),(0xF9BF),
+(0xF9C0),(0xF9C1),(0xF9C2),(0xF9C3),(0xF9C4),(0xF9C5),(0xF9C6),(0xF9C7),
+(0xF9C8),(0xF9C9),(0xF9CA),(0xF9CB),(0xF9CC),(0xF9CD),(0xF9CE),(0xF9CF),
+(0xF9D0),(0xF9D1),(0xF9D2),(0xF9D3),(0xF9D4),(0xF9D5),(0xF9D6),(0xF9D7),
+(0xF9D8),(0xF9D9),(0xF9DA),(0xF9DB),(0xF9DC),(0xF9DD),(0xF9DE),(0xF9DF),
+(0xF9E0),(0xF9E1),(0xF9E2),(0xF9E3),(0xF9E4),(0xF9E5),(0xF9E6),(0xF9E7),
+(0xF9E8),(0xF9E9),(0xF9EA),(0xF9EB),(0xF9EC),(0xF9ED),(0xF9EE),(0xF9EF),
+(0xF9F0),(0xF9F1),(0xF9F2),(0xF9F3),(0xF9F4),(0xF9F5),(0xF9F6),(0xF9F7),
+(0xF9F8),(0xF9F9),(0xF9FA),(0xF9FB),(0xF9FC);
+
+#Test that all the characters are stored correctly
+SELECT HEX(c1) FROM t1;
+
+#Test conversion to ucs2
+CREATE TABLE t2 SELECT CONVERT(c1 USING ucs2) AS c1 FROM t1;
+SELECT HEX(c1) FROM t2;
+
+#Test round trip conversion
+CREATE TABLE t3 SELECT CONVERT(c1 USING cp932) AS c1 FROM t2;
+SELECT HEX(c1) FROM t3;
+
+#Test conversion to eucjpms
+CREATE TABLE t4 SELECT CONVERT(c1 USING eucjpms) AS c1 FROM t1;
+SELECT HEX(c1) FROM t4;
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
+
+
+SET collation_connection='cp932_japanese_ci';
+-- source include/ctype_filesort.inc
+SET collation_connection='cp932_bin';
+-- source include/ctype_filesort.inc
diff --git a/mysql-test/t/ctype_eucjpms.test b/mysql-test/t/ctype_eucjpms.test
new file mode 100644
index 00000000000..cec1e2a9861
--- /dev/null
+++ b/mysql-test/t/ctype_eucjpms.test
@@ -0,0 +1,353 @@
+-- source include/have_eucjpms.inc
+
+
+--disable_warnings
+drop table if exists t1;
+drop table if exists t2;
+drop table if exists t3;
+drop table if exists t4;
+--enable_warnings
+
+set names eucjpms;
+set character_set_database = eucjpms;
+
+CREATE TABLE t1(c1 CHAR(1)) DEFAULT CHARACTER SET = eucjpms;
+
+#Characters which are converted to Unicode ambiguously
+INSERT INTO t1 VALUES
+(0x5C),(0x7E),(0xA1B1),(0xA1BD),(0xA1C0),(0xA1C1),(0xA1C2),(0xA1DD),(0xA1F1),(0xA1F2),(0xA1EF),(0xA2CC),(0x8FA2B7),(0x8FA2C3);
+
+#NEC ROW 13 characters (0x8740 - 0x879C of cp932)
+INSERT INTO t1 VALUES
+(0xADA1),(0xADA2),(0xADA3),(0xADA4),(0xADA5),(0xADA6),(0xADA7),(0xADA8),
+(0xADA9),(0xADAA),(0xADAB),(0xADAC),(0xADAD),(0xADAE),(0xADAF),(0xADB0),
+(0xADB1),(0xADB2),(0xADB3),(0xADB4),(0xADB5),(0xADB6),(0xADB7),(0xADB8),
+(0xADB9),(0xADBA),(0xADBB),(0xADBC),(0xADBD),(0xADBE),(0xADC0),(0xADC1),
+(0xADC2),(0xADC3),(0xADC4),(0xADC5),(0xADC6),(0xADC7),(0xADC8),(0xADC9),
+(0xADCA),(0xADCB),(0xADCC),(0xADCD),(0xADCE),(0xADCF),(0xADD0),(0xADD1),
+(0xADD2),(0xADD3),(0xADD4),(0xADD5),(0xADD6),(0xADDF),(0xADE0),(0xADE1),
+(0xADE2),(0xADE3),(0xADE4),(0xADE5),(0xADE6),(0xADE7),(0xADE8),(0xADE9),
+(0xADEA),(0xADEB),(0xADEC),(0xADED),(0xADEE),(0xADEF),(0xADF0),(0xADF1),
+(0xADF2),(0xADF3),(0xADF4),(0xADF5),(0xADF6),(0xADF7),(0xADF8),(0xADF9),
+(0xADFA),(0xADFB),(0xADFC);
+
+#IBM Selected Kanji and Non-Kanji (0xFA40 - 0xFC4B of cp932)
+INSERT INTO t1 VALUES
+(0x8FF3F3),(0x8FF3F4),(0x8FF3F5),(0x8FF3F6),(0x8FF3F7),(0x8FF3F8),(0x8FF3F9),(0x8FF3FA),
+(0x8FF3FB),(0x8FF3FC),(0x8FF3FD),(0x8FF3FE),(0x8FF4A1),(0x8FF4A2),(0x8FF4A3),(0x8FF4A4),
+(0x8FF4A5),(0x8FF4A6),(0x8FF4A7),(0x8FF4A8),(0xA2CC),(0x8FA2C3),(0x8FF4A9),(0x8FF4AA),
+(0x8FF4AB),(0x8FF4AC),(0x8FF4AD),(0xA2E8),(0x8FD4E3),(0x8FDCDF),(0x8FE4E9),(0x8FE3F8),
+(0x8FD9A1),(0x8FB1BB),(0x8FF4AE),(0x8FC2AD),(0x8FC3FC),(0x8FE4D0),(0x8FC2BF),(0x8FBCF4),
+(0x8FB0A9),(0x8FB0C8),(0x8FF4AF),(0x8FB0D2),(0x8FB0D4),(0x8FB0E3),(0x8FB0EE),(0x8FB1A7),
+(0x8FB1A3),(0x8FB1AC),(0x8FB1A9),(0x8FB1BE),(0x8FB1DF),(0x8FB1D8),(0x8FB1C8),(0x8FB1D7),
+(0x8FB1E3),(0x8FB1F4),(0x8FB1E1),(0x8FB2A3),(0x8FF4B0),(0x8FB2BB),(0x8FB2E6),(0x8FB2ED),
+(0x8FB2F5),(0x8FB2FC),(0x8FF4B1),(0x8FB3B5),(0x8FB3D8),(0x8FB3DB),(0x8FB3E5),(0x8FB3EE),
+(0x8FB3FB),(0x8FF4B2),(0x8FF4B3),(0x8FB4C0),(0x8FB4C7),(0x8FB4D0),(0x8FB4DE),(0x8FF4B4),
+(0x8FB5AA),(0x8FF4B5),(0x8FB5AF),(0x8FB5C4),(0x8FB5E8),(0x8FF4B6),(0x8FB7C2),(0x8FB7E4),
+(0x8FB7E8),(0x8FB7E7),(0x8FF4B7),(0x8FF4B8),(0x8FF4B9),(0x8FB8CE),(0x8FB8E1),(0x8FB8F5),
+(0x8FB8F7),(0x8FB8F8),(0x8FB8FC),(0x8FB9AF),(0x8FB9B7),(0x8FBABE),(0x8FBADB),(0x8FCDAA),
+(0x8FBAE1),(0x8FF4BA),(0x8FBAEB),(0x8FBBB3),(0x8FBBB8),(0x8FF4BB),(0x8FBBCA),(0x8FF4BC),
+(0x8FF4BD),(0x8FBBD0),(0x8FBBDE),(0x8FBBF4),(0x8FBBF5),(0x8FBBF9),(0x8FBCE4),(0x8FBCED),
+(0x8FBCFE),(0x8FF4BE),(0x8FBDC2),(0x8FBDE7),(0x8FF4BF),(0x8FBDF0),(0x8FBEB0),(0x8FBEAC),
+(0x8FF4C0),(0x8FBEB3),(0x8FBEBD),(0x8FBECD),(0x8FBEC9),(0x8FBEE4),(0x8FBFA8),(0x8FBFC9),
+(0x8FC0C4),(0x8FC0E4),(0x8FC0F4),(0x8FC1A6),(0x8FF4C1),(0x8FC1F5),(0x8FC1FC),(0x8FF4C2),
+(0x8FC1F8),(0x8FC2AB),(0x8FC2A1),(0x8FC2A5),(0x8FF4C3),(0x8FC2B8),(0x8FC2BA),(0x8FF4C4),
+(0x8FC2C4),(0x8FC2D2),(0x8FC2D7),(0x8FC2DB),(0x8FC2DE),(0x8FC2ED),(0x8FC2F0),(0x8FF4C5),
+(0x8FC3A1),(0x8FC3B5),(0x8FC3C9),(0x8FC3B9),(0x8FF4C6),(0x8FC3D8),(0x8FC3FE),(0x8FF4C7),
+(0x8FC4CC),(0x8FF4C8),(0x8FC4D9),(0x8FC4EA),(0x8FC4FD),(0x8FF4C9),(0x8FC5A7),(0x8FC5B5),
+(0x8FC5B6),(0x8FF4CA),(0x8FC5D5),(0x8FC6B8),(0x8FC6D7),(0x8FC6E0),(0x8FC6EA),(0x8FC6E3),
+(0x8FC7A1),(0x8FC7AB),(0x8FC7C7),(0x8FC7C3),(0x8FC7CB),(0x8FC7CF),(0x8FC7D9),(0x8FF4CB),
+(0x8FF4CC),(0x8FC7E6),(0x8FC7EE),(0x8FC7FC),(0x8FC7EB),(0x8FC7F0),(0x8FC8B1),(0x8FC8E5),
+(0x8FC8F8),(0x8FC9A6),(0x8FC9AB),(0x8FC9AD),(0x8FF4CD),(0x8FC9CA),(0x8FC9D3),(0x8FC9E9),
+(0x8FC9E3),(0x8FC9FC),(0x8FC9F4),(0x8FC9F5),(0x8FF4CE),(0x8FCAB3),(0x8FCABD),(0x8FCAEF),
+(0x8FCAF1),(0x8FCBAE),(0x8FF4CF),(0x8FCBCA),(0x8FCBE6),(0x8FCBEA),(0x8FCBF0),(0x8FCBF4),
+(0x8FCBEE),(0x8FCCA5),(0x8FCBF9),(0x8FCCAB),(0x8FCCAE),(0x8FCCAD),(0x8FCCB2),(0x8FCCC2),
+(0x8FCCD0),(0x8FCCD9),(0x8FF4D0),(0x8FCDBB),(0x8FF4D1),(0x8FCEBB),(0x8FF4D2),(0x8FCEBA),
+(0x8FCEC3),(0x8FF4D3),(0x8FCEF2),(0x8FB3DD),(0x8FCFD5),(0x8FCFE2),(0x8FCFE9),(0x8FCFED),
+(0x8FF4D4),(0x8FF4D5),(0x8FF4D6),(0x8FF4D7),(0x8FD0E5),(0x8FF4D8),(0x8FD0E9),(0x8FD1E8),
+(0x8FF4D9),(0x8FF4DA),(0x8FD1EC),(0x8FD2BB),(0x8FF4DB),(0x8FD3E1),(0x8FD3E8),(0x8FD4A7),
+(0x8FF4DC),(0x8FF4DD),(0x8FD4D4),(0x8FD4F2),(0x8FD5AE),(0x8FF4DE),(0x8FD7DE),(0x8FF4DF),
+(0x8FD8A2),(0x8FD8B7),(0x8FD8C1),(0x8FD8D1),(0x8FD8F4),(0x8FD9C6),(0x8FD9C8),(0x8FD9D1),
+(0x8FF4E0),(0x8FF4E1),(0x8FF4E2),(0x8FF4E3),(0x8FF4E4),(0x8FDCD3),(0x8FDDC8),(0x8FDDD4),
+(0x8FDDEA),(0x8FDDFA),(0x8FDEA4),(0x8FDEB0),(0x8FF4E5),(0x8FDEB5),(0x8FDECB),(0x8FF4E6),
+(0x8FDFB9),(0x8FF4E7),(0x8FDFC3),(0x8FF4E8),(0x8FF4E9),(0x8FE0D9),(0x8FF4EA),(0x8FF4EB),
+(0x8FE1E2),(0x8FF4EC),(0x8FF4ED),(0x8FF4EE),(0x8FE2C7),(0x8FE3A8),(0x8FE3A6),(0x8FE3A9),
+(0x8FE3AF),(0x8FE3B0),(0x8FE3AA),(0x8FE3AB),(0x8FE3BC),(0x8FE3C1),(0x8FE3BF),(0x8FE3D5),
+(0x8FE3D8),(0x8FE3D6),(0x8FE3DF),(0x8FE3E3),(0x8FE3E1),(0x8FE3D4),(0x8FE3E9),(0x8FE4A6),
+(0x8FE3F1),(0x8FE3F2),(0x8FE4CB),(0x8FE4C1),(0x8FE4C3),(0x8FE4BE),(0x8FF4EF),(0x8FE4C0),
+(0x8FE4C7),(0x8FE4BF),(0x8FE4E0),(0x8FE4DE),(0x8FE4D1),(0x8FF4F0),(0x8FE4DC),(0x8FE4D2),
+(0x8FE4DB),(0x8FE4D4),(0x8FE4FA),(0x8FE4EF),(0x8FE5B3),(0x8FE5BF),(0x8FE5C9),(0x8FE5D0),
+(0x8FE5E2),(0x8FE5EA),(0x8FE5EB),(0x8FF4F1),(0x8FF4F2),(0x8FF4F3),(0x8FE6E8),(0x8FE6EF),
+(0x8FE7AC),(0x8FF4F4),(0x8FE7AE),(0x8FF4F5),(0x8FE7B1),(0x8FF4F6),(0x8FE7B2),(0x8FE8B1),
+(0x8FE8B6),(0x8FF4F7),(0x8FF4F8),(0x8FE8DD),(0x8FF4F9),(0x8FF4FA),(0x8FE9D1),(0x8FF4FB),
+(0x8FE9ED),(0x8FEACD),(0x8FF4FC),(0x8FEADB),(0x8FEAE6),(0x8FEAEA),(0x8FEBA5),(0x8FEBFB),
+(0x8FEBFA),(0x8FF4FD),(0x8FECD6),(0x8FF4FE);
+
+#User defined characters (0xF040-F9FC of cp932)
+INSERT INTO t1 VALUES
+(0xF5A1),(0xF5A2),(0xF5A3),(0xF5A4),(0xF5A5),(0xF5A6),(0xF5A7),(0xF5A8),
+(0xF5A9),(0xF5AA),(0xF5AB),(0xF5AC),(0xF5AD),(0xF5AE),(0xF5AF),(0xF5B0),
+(0xF5B1),(0xF5B2),(0xF5B3),(0xF5B4),(0xF5B5),(0xF5B6),(0xF5B7),(0xF5B8),
+(0xF5B9),(0xF5BA),(0xF5BB),(0xF5BC),(0xF5BD),(0xF5BE),(0xF5BF),(0xF5C0),
+(0xF5C1),(0xF5C2),(0xF5C3),(0xF5C4),(0xF5C5),(0xF5C6),(0xF5C7),(0xF5C8),
+(0xF5C9),(0xF5CA),(0xF5CB),(0xF5CC),(0xF5CD),(0xF5CE),(0xF5CF),(0xF5D0),
+(0xF5D1),(0xF5D2),(0xF5D3),(0xF5D4),(0xF5D5),(0xF5D6),(0xF5D7),(0xF5D8),
+(0xF5D9),(0xF5DA),(0xF5DB),(0xF5DC),(0xF5DD),(0xF5DE),(0xF5DF),(0xF5E0),
+(0xF5E1),(0xF5E2),(0xF5E3),(0xF5E4),(0xF5E5),(0xF5E6),(0xF5E7),(0xF5E8),
+(0xF5E9),(0xF5EA),(0xF5EB),(0xF5EC),(0xF5ED),(0xF5EE),(0xF5EF),(0xF5F0),
+(0xF5F1),(0xF5F2),(0xF5F3),(0xF5F4),(0xF5F5),(0xF5F6),(0xF5F7),(0xF5F8),
+(0xF5F9),(0xF5FA),(0xF5FB),(0xF5FC),(0xF5FD),(0xF5FE),
+(0xF6A1),(0xF6A2),(0xF6A3),(0xF6A4),(0xF6A5),(0xF6A6),(0xF6A7),(0xF6A8),
+(0xF6A9),(0xF6AA),(0xF6AB),(0xF6AC),(0xF6AD),(0xF6AE),(0xF6AF),(0xF6B0),
+(0xF6B1),(0xF6B2),(0xF6B3),(0xF6B4),(0xF6B5),(0xF6B6),(0xF6B7),(0xF6B8),
+(0xF6B9),(0xF6BA),(0xF6BB),(0xF6BC),(0xF6BD),(0xF6BE),(0xF6BF),(0xF6C0),
+(0xF6C1),(0xF6C2),(0xF6C3),(0xF6C4),(0xF6C5),(0xF6C6),(0xF6C7),(0xF6C8),
+(0xF6C9),(0xF6CA),(0xF6CB),(0xF6CC),(0xF6CD),(0xF6CE),(0xF6CF),(0xF6D0),
+(0xF6D1),(0xF6D2),(0xF6D3),(0xF6D4),(0xF6D5),(0xF6D6),(0xF6D7),(0xF6D8),
+(0xF6D9),(0xF6DA),(0xF6DB),(0xF6DC),(0xF6DD),(0xF6DE),(0xF6DF),(0xF6E0),
+(0xF6E1),(0xF6E2),(0xF6E3),(0xF6E4),(0xF6E5),(0xF6E6),(0xF6E7),(0xF6E8),
+(0xF6E9),(0xF6EA),(0xF6EB),(0xF6EC),(0xF6ED),(0xF6EE),(0xF6EF),(0xF6F0),
+(0xF6F1),(0xF6F2),(0xF6F3),(0xF6F4),(0xF6F5),(0xF6F6),(0xF6F7),(0xF6F8),
+(0xF6F9),(0xF6FA),(0xF6FB),(0xF6FC),(0xF6FD),(0xF6FE),
+(0xF7A1),(0xF7A2),(0xF7A3),(0xF7A4),(0xF7A5),(0xF7A6),(0xF7A7),(0xF7A8),
+(0xF7A9),(0xF7AA),(0xF7AB),(0xF7AC),(0xF7AD),(0xF7AE),(0xF7AF),(0xF7B0),
+(0xF7B1),(0xF7B2),(0xF7B3),(0xF7B4),(0xF7B5),(0xF7B6),(0xF7B7),(0xF7B8),
+(0xF7B9),(0xF7BA),(0xF7BB),(0xF7BC),(0xF7BD),(0xF7BE),(0xF7BF),(0xF7C0),
+(0xF7C1),(0xF7C2),(0xF7C3),(0xF7C4),(0xF7C5),(0xF7C6),(0xF7C7),(0xF7C8),
+(0xF7C9),(0xF7CA),(0xF7CB),(0xF7CC),(0xF7CD),(0xF7CE),(0xF7CF),(0xF7D0),
+(0xF7D1),(0xF7D2),(0xF7D3),(0xF7D4),(0xF7D5),(0xF7D6),(0xF7D7),(0xF7D8),
+(0xF7D9),(0xF7DA),(0xF7DB),(0xF7DC),(0xF7DD),(0xF7DE),(0xF7DF),(0xF7E0),
+(0xF7E1),(0xF7E2),(0xF7E3),(0xF7E4),(0xF7E5),(0xF7E6),(0xF7E7),(0xF7E8),
+(0xF7E9),(0xF7EA),(0xF7EB),(0xF7EC),(0xF7ED),(0xF7EE),(0xF7EF),(0xF7F0),
+(0xF7F1),(0xF7F2),(0xF7F3),(0xF7F4),(0xF7F5),(0xF7F6),(0xF7F7),(0xF7F8),
+(0xF7F9),(0xF7FA),(0xF7FB),(0xF7FC),(0xF7FD),(0xF7FE),
+(0xF8A1),(0xF8A2),(0xF8A3),(0xF8A4),(0xF8A5),(0xF8A6),(0xF8A7),(0xF8A8),
+(0xF8A9),(0xF8AA),(0xF8AB),(0xF8AC),(0xF8AD),(0xF8AE),(0xF8AF),(0xF8B0),
+(0xF8B1),(0xF8B2),(0xF8B3),(0xF8B4),(0xF8B5),(0xF8B6),(0xF8B7),(0xF8B8),
+(0xF8B9),(0xF8BA),(0xF8BB),(0xF8BC),(0xF8BD),(0xF8BE),(0xF8BF),(0xF8C0),
+(0xF8C1),(0xF8C2),(0xF8C3),(0xF8C4),(0xF8C5),(0xF8C6),(0xF8C7),(0xF8C8),
+(0xF8C9),(0xF8CA),(0xF8CB),(0xF8CC),(0xF8CD),(0xF8CE),(0xF8CF),(0xF8D0),
+(0xF8D1),(0xF8D2),(0xF8D3),(0xF8D4),(0xF8D5),(0xF8D6),(0xF8D7),(0xF8D8),
+(0xF8D9),(0xF8DA),(0xF8DB),(0xF8DC),(0xF8DD),(0xF8DE),(0xF8DF),(0xF8E0),
+(0xF8E1),(0xF8E2),(0xF8E3),(0xF8E4),(0xF8E5),(0xF8E6),(0xF8E7),(0xF8E8),
+(0xF8E9),(0xF8EA),(0xF8EB),(0xF8EC),(0xF8ED),(0xF8EE),(0xF8EF),(0xF8F0),
+(0xF8F1),(0xF8F2),(0xF8F3),(0xF8F4),(0xF8F5),(0xF8F6),(0xF8F7),(0xF8F8),
+(0xF8F9),(0xF8FA),(0xF8FB),(0xF8FC),(0xF8FD),(0xF8FE),
+(0xF9A1),(0xF9A2),(0xF9A3),(0xF9A4),(0xF9A5),(0xF9A6),(0xF9A7),(0xF9A8),
+(0xF9A9),(0xF9AA),(0xF9AB),(0xF9AC),(0xF9AD),(0xF9AE),(0xF9AF),(0xF9B0),
+(0xF9B1),(0xF9B2),(0xF9B3),(0xF9B4),(0xF9B5),(0xF9B6),(0xF9B7),(0xF9B8),
+(0xF9B9),(0xF9BA),(0xF9BB),(0xF9BC),(0xF9BD),(0xF9BE),(0xF9BF),(0xF9C0),
+(0xF9C1),(0xF9C2),(0xF9C3),(0xF9C4),(0xF9C5),(0xF9C6),(0xF9C7),(0xF9C8),
+(0xF9C9),(0xF9CA),(0xF9CB),(0xF9CC),(0xF9CD),(0xF9CE),(0xF9CF),(0xF9D0),
+(0xF9D1),(0xF9D2),(0xF9D3),(0xF9D4),(0xF9D5),(0xF9D6),(0xF9D7),(0xF9D8),
+(0xF9D9),(0xF9DA),(0xF9DB),(0xF9DC),(0xF9DD),(0xF9DE),(0xF9DF),(0xF9E0),
+(0xF9E1),(0xF9E2),(0xF9E3),(0xF9E4),(0xF9E5),(0xF9E6),(0xF9E7),(0xF9E8),
+(0xF9E9),(0xF9EA),(0xF9EB),(0xF9EC),(0xF9ED),(0xF9EE),(0xF9EF),(0xF9F0),
+(0xF9F1),(0xF9F2),(0xF9F3),(0xF9F4),(0xF9F5),(0xF9F6),(0xF9F7),(0xF9F8),
+(0xF9F9),(0xF9FA),(0xF9FB),(0xF9FC),(0xF9FD),(0xF9FE),
+(0xFAA1),(0xFAA2),(0xFAA3),(0xFAA4),(0xFAA5),(0xFAA6),(0xFAA7),(0xFAA8),
+(0xFAA9),(0xFAAA),(0xFAAB),(0xFAAC),(0xFAAD),(0xFAAE),(0xFAAF),(0xFAB0),
+(0xFAB1),(0xFAB2),(0xFAB3),(0xFAB4),(0xFAB5),(0xFAB6),(0xFAB7),(0xFAB8),
+(0xFAB9),(0xFABA),(0xFABB),(0xFABC),(0xFABD),(0xFABE),(0xFABF),(0xFAC0),
+(0xFAC1),(0xFAC2),(0xFAC3),(0xFAC4),(0xFAC5),(0xFAC6),(0xFAC7),(0xFAC8),
+(0xFAC9),(0xFACA),(0xFACB),(0xFACC),(0xFACD),(0xFACE),(0xFACF),(0xFAD0),
+(0xFAD1),(0xFAD2),(0xFAD3),(0xFAD4),(0xFAD5),(0xFAD6),(0xFAD7),(0xFAD8),
+(0xFAD9),(0xFADA),(0xFADB),(0xFADC),(0xFADD),(0xFADE),(0xFADF),(0xFAE0),
+(0xFAE1),(0xFAE2),(0xFAE3),(0xFAE4),(0xFAE5),(0xFAE6),(0xFAE7),(0xFAE8),
+(0xFAE9),(0xFAEA),(0xFAEB),(0xFAEC),(0xFAED),(0xFAEE),(0xFAEF),(0xFAF0),
+(0xFAF1),(0xFAF2),(0xFAF3),(0xFAF4),(0xFAF5),(0xFAF6),(0xFAF7),(0xFAF8),
+(0xFAF9),(0xFAFA),(0xFAFB),(0xFAFC),(0xFAFD),(0xFAFE),
+(0xFBA1),(0xFBA2),(0xFBA3),(0xFBA4),(0xFBA5),(0xFBA6),(0xFBA7),(0xFBA8),
+(0xFBA9),(0xFBAA),(0xFBAB),(0xFBAC),(0xFBAD),(0xFBAE),(0xFBAF),(0xFBB0),
+(0xFBB1),(0xFBB2),(0xFBB3),(0xFBB4),(0xFBB5),(0xFBB6),(0xFBB7),(0xFBB8),
+(0xFBB9),(0xFBBA),(0xFBBB),(0xFBBC),(0xFBBD),(0xFBBE),(0xFBBF),(0xFBC0),
+(0xFBC1),(0xFBC2),(0xFBC3),(0xFBC4),(0xFBC5),(0xFBC6),(0xFBC7),(0xFBC8),
+(0xFBC9),(0xFBCA),(0xFBCB),(0xFBCC),(0xFBCD),(0xFBCE),(0xFBCF),(0xFBD0),
+(0xFBD1),(0xFBD2),(0xFBD3),(0xFBD4),(0xFBD5),(0xFBD6),(0xFBD7),(0xFBD8),
+(0xFBD9),(0xFBDA),(0xFBDB),(0xFBDC),(0xFBDD),(0xFBDE),(0xFBDF),(0xFBE0),
+(0xFBE1),(0xFBE2),(0xFBE3),(0xFBE4),(0xFBE5),(0xFBE6),(0xFBE7),(0xFBE8),
+(0xFBE9),(0xFBEA),(0xFBEB),(0xFBEC),(0xFBED),(0xFBEE),(0xFBEF),(0xFBF0),
+(0xFBF1),(0xFBF2),(0xFBF3),(0xFBF4),(0xFBF5),(0xFBF6),(0xFBF7),(0xFBF8),
+(0xFBF9),(0xFBFA),(0xFBFB),(0xFBFC),(0xFBFD),(0xFBFE),
+(0xFCA1),(0xFCA2),(0xFCA3),(0xFCA4),(0xFCA5),(0xFCA6),(0xFCA7),(0xFCA8),
+(0xFCA9),(0xFCAA),(0xFCAB),(0xFCAC),(0xFCAD),(0xFCAE),(0xFCAF),(0xFCB0),
+(0xFCB1),(0xFCB2),(0xFCB3),(0xFCB4),(0xFCB5),(0xFCB6),(0xFCB7),(0xFCB8),
+(0xFCB9),(0xFCBA),(0xFCBB),(0xFCBC),(0xFCBD),(0xFCBE),(0xFCBF),(0xFCC0),
+(0xFCC1),(0xFCC2),(0xFCC3),(0xFCC4),(0xFCC5),(0xFCC6),(0xFCC7),(0xFCC8),
+(0xFCC9),(0xFCCA),(0xFCCB),(0xFCCC),(0xFCCD),(0xFCCE),(0xFCCF),(0xFCD0),
+(0xFCD1),(0xFCD2),(0xFCD3),(0xFCD4),(0xFCD5),(0xFCD6),(0xFCD7),(0xFCD8),
+(0xFCD9),(0xFCDA),(0xFCDB),(0xFCDC),(0xFCDD),(0xFCDE),(0xFCDF),(0xFCE0),
+(0xFCE1),(0xFCE2),(0xFCE3),(0xFCE4),(0xFCE5),(0xFCE6),(0xFCE7),(0xFCE8),
+(0xFCE9),(0xFCEA),(0xFCEB),(0xFCEC),(0xFCED),(0xFCEE),(0xFCEF),(0xFCF0),
+(0xFCF1),(0xFCF2),(0xFCF3),(0xFCF4),(0xFCF5),(0xFCF6),(0xFCF7),(0xFCF8),
+(0xFCF9),(0xFCFA),(0xFCFB),(0xFCFC),(0xFCFD),(0xFCFE),
+(0xFDA1),(0xFDA2),(0xFDA3),(0xFDA4),(0xFDA5),(0xFDA6),(0xFDA7),(0xFDA8),
+(0xFDA9),(0xFDAA),(0xFDAB),(0xFDAC),(0xFDAD),(0xFDAE),(0xFDAF),(0xFDB0),
+(0xFDB1),(0xFDB2),(0xFDB3),(0xFDB4),(0xFDB5),(0xFDB6),(0xFDB7),(0xFDB8),
+(0xFDB9),(0xFDBA),(0xFDBB),(0xFDBC),(0xFDBD),(0xFDBE),(0xFDBF),(0xFDC0),
+(0xFDC1),(0xFDC2),(0xFDC3),(0xFDC4),(0xFDC5),(0xFDC6),(0xFDC7),(0xFDC8),
+(0xFDC9),(0xFDCA),(0xFDCB),(0xFDCC),(0xFDCD),(0xFDCE),(0xFDCF),(0xFDD0),
+(0xFDD1),(0xFDD2),(0xFDD3),(0xFDD4),(0xFDD5),(0xFDD6),(0xFDD7),(0xFDD8),
+(0xFDD9),(0xFDDA),(0xFDDB),(0xFDDC),(0xFDDD),(0xFDDE),(0xFDDF),(0xFDE0),
+(0xFDE1),(0xFDE2),(0xFDE3),(0xFDE4),(0xFDE5),(0xFDE6),(0xFDE7),(0xFDE8),
+(0xFDE9),(0xFDEA),(0xFDEB),(0xFDEC),(0xFDED),(0xFDEE),(0xFDEF),(0xFDF0),
+(0xFDF1),(0xFDF2),(0xFDF3),(0xFDF4),(0xFDF5),(0xFDF6),(0xFDF7),(0xFDF8),
+(0xFDF9),(0xFDFA),(0xFDFB),(0xFDFC),(0xFDFD),(0xFDFE),
+(0xFEA1),(0xFEA2),(0xFEA3),(0xFEA4),(0xFEA5),(0xFEA6),(0xFEA7),(0xFEA8),
+(0xFEA9),(0xFEAA),(0xFEAB),(0xFEAC),(0xFEAD),(0xFEAE),(0xFEAF),(0xFEB0),
+(0xFEB1),(0xFEB2),(0xFEB3),(0xFEB4),(0xFEB5),(0xFEB6),(0xFEB7),(0xFEB8),
+(0xFEB9),(0xFEBA),(0xFEBB),(0xFEBC),(0xFEBD),(0xFEBE),(0xFEBF),(0xFEC0),
+(0xFEC1),(0xFEC2),(0xFEC3),(0xFEC4),(0xFEC5),(0xFEC6),(0xFEC7),(0xFEC8),
+(0xFEC9),(0xFECA),(0xFECB),(0xFECC),(0xFECD),(0xFECE),(0xFECF),(0xFED0),
+(0xFED1),(0xFED2),(0xFED3),(0xFED4),(0xFED5),(0xFED6),(0xFED7),(0xFED8),
+(0xFED9),(0xFEDA),(0xFEDB),(0xFEDC),(0xFEDD),(0xFEDE),(0xFEDF),(0xFEE0),
+(0xFEE1),(0xFEE2),(0xFEE3),(0xFEE4),(0xFEE5),(0xFEE6),(0xFEE7),(0xFEE8),
+(0xFEE9),(0xFEEA),(0xFEEB),(0xFEEC),(0xFEED),(0xFEEE),(0xFEEF),(0xFEF0),
+(0xFEF1),(0xFEF2),(0xFEF3),(0xFEF4),(0xFEF5),(0xFEF6),(0xFEF7),(0xFEF8),
+(0xFEF9),(0xFEFA),(0xFEFB),(0xFEFC),(0xFEFD),(0xFEFE),
+(0x8FF5A1),(0x8FF5A2),(0x8FF5A3),(0x8FF5A4),(0x8FF5A5),(0x8FF5A6),(0x8FF5A7),(0x8FF5A8),
+(0x8FF5A9),(0x8FF5AA),(0x8FF5AB),(0x8FF5AC),(0x8FF5AD),(0x8FF5AE),(0x8FF5AF),(0x8FF5B0),
+(0x8FF5B1),(0x8FF5B2),(0x8FF5B3),(0x8FF5B4),(0x8FF5B5),(0x8FF5B6),(0x8FF5B7),(0x8FF5B8),
+(0x8FF5B9),(0x8FF5BA),(0x8FF5BB),(0x8FF5BC),(0x8FF5BD),(0x8FF5BE),(0x8FF5BF),(0x8FF5C0),
+(0x8FF5C1),(0x8FF5C2),(0x8FF5C3),(0x8FF5C4),(0x8FF5C5),(0x8FF5C6),(0x8FF5C7),(0x8FF5C8),
+(0x8FF5C9),(0x8FF5CA),(0x8FF5CB),(0x8FF5CC),(0x8FF5CD),(0x8FF5CE),(0x8FF5CF),(0x8FF5D0),
+(0x8FF5D1),(0x8FF5D2),(0x8FF5D3),(0x8FF5D4),(0x8FF5D5),(0x8FF5D6),(0x8FF5D7),(0x8FF5D8),
+(0x8FF5D9),(0x8FF5DA),(0x8FF5DB),(0x8FF5DC),(0x8FF5DD),(0x8FF5DE),(0x8FF5DF),(0x8FF5E0),
+(0x8FF5E1),(0x8FF5E2),(0x8FF5E3),(0x8FF5E4),(0x8FF5E5),(0x8FF5E6),(0x8FF5E7),(0x8FF5E8),
+(0x8FF5E9),(0x8FF5EA),(0x8FF5EB),(0x8FF5EC),(0x8FF5ED),(0x8FF5EE),(0x8FF5EF),(0x8FF5F0),
+(0x8FF5F1),(0x8FF5F2),(0x8FF5F3),(0x8FF5F4),(0x8FF5F5),(0x8FF5F6),(0x8FF5F7),(0x8FF5F8),
+(0x8FF5F9),(0x8FF5FA),(0x8FF5FB),(0x8FF5FC),(0x8FF5FD),(0x8FF5FE),
+(0x8FF6A1),(0x8FF6A2),(0x8FF6A3),(0x8FF6A4),(0x8FF6A5),(0x8FF6A6),(0x8FF6A7),(0x8FF6A8),
+(0x8FF6A9),(0x8FF6AA),(0x8FF6AB),(0x8FF6AC),(0x8FF6AD),(0x8FF6AE),(0x8FF6AF),(0x8FF6B0),
+(0x8FF6B1),(0x8FF6B2),(0x8FF6B3),(0x8FF6B4),(0x8FF6B5),(0x8FF6B6),(0x8FF6B7),(0x8FF6B8),
+(0x8FF6B9),(0x8FF6BA),(0x8FF6BB),(0x8FF6BC),(0x8FF6BD),(0x8FF6BE),(0x8FF6BF),(0x8FF6C0),
+(0x8FF6C1),(0x8FF6C2),(0x8FF6C3),(0x8FF6C4),(0x8FF6C5),(0x8FF6C6),(0x8FF6C7),(0x8FF6C8),
+(0x8FF6C9),(0x8FF6CA),(0x8FF6CB),(0x8FF6CC),(0x8FF6CD),(0x8FF6CE),(0x8FF6CF),(0x8FF6D0),
+(0x8FF6D1),(0x8FF6D2),(0x8FF6D3),(0x8FF6D4),(0x8FF6D5),(0x8FF6D6),(0x8FF6D7),(0x8FF6D8),
+(0x8FF6D9),(0x8FF6DA),(0x8FF6DB),(0x8FF6DC),(0x8FF6DD),(0x8FF6DE),(0x8FF6DF),(0x8FF6E0),
+(0x8FF6E1),(0x8FF6E2),(0x8FF6E3),(0x8FF6E4),(0x8FF6E5),(0x8FF6E6),(0x8FF6E7),(0x8FF6E8),
+(0x8FF6E9),(0x8FF6EA),(0x8FF6EB),(0x8FF6EC),(0x8FF6ED),(0x8FF6EE),(0x8FF6EF),(0x8FF6F0),
+(0x8FF6F1),(0x8FF6F2),(0x8FF6F3),(0x8FF6F4),(0x8FF6F5),(0x8FF6F6),(0x8FF6F7),(0x8FF6F8),
+(0x8FF6F9),(0x8FF6FA),(0x8FF6FB),(0x8FF6FC),(0x8FF6FD),(0x8FF6FE),
+(0x8FF7A1),(0x8FF7A2),(0x8FF7A3),(0x8FF7A4),(0x8FF7A5),(0x8FF7A6),(0x8FF7A7),(0x8FF7A8),
+(0x8FF7A9),(0x8FF7AA),(0x8FF7AB),(0x8FF7AC),(0x8FF7AD),(0x8FF7AE),(0x8FF7AF),(0x8FF7B0),
+(0x8FF7B1),(0x8FF7B2),(0x8FF7B3),(0x8FF7B4),(0x8FF7B5),(0x8FF7B6),(0x8FF7B7),(0x8FF7B8),
+(0x8FF7B9),(0x8FF7BA),(0x8FF7BB),(0x8FF7BC),(0x8FF7BD),(0x8FF7BE),(0x8FF7BF),(0x8FF7C0),
+(0x8FF7C1),(0x8FF7C2),(0x8FF7C3),(0x8FF7C4),(0x8FF7C5),(0x8FF7C6),(0x8FF7C7),(0x8FF7C8),
+(0x8FF7C9),(0x8FF7CA),(0x8FF7CB),(0x8FF7CC),(0x8FF7CD),(0x8FF7CE),(0x8FF7CF),(0x8FF7D0),
+(0x8FF7D1),(0x8FF7D2),(0x8FF7D3),(0x8FF7D4),(0x8FF7D5),(0x8FF7D6),(0x8FF7D7),(0x8FF7D8),
+(0x8FF7D9),(0x8FF7DA),(0x8FF7DB),(0x8FF7DC),(0x8FF7DD),(0x8FF7DE),(0x8FF7DF),(0x8FF7E0),
+(0x8FF7E1),(0x8FF7E2),(0x8FF7E3),(0x8FF7E4),(0x8FF7E5),(0x8FF7E6),(0x8FF7E7),(0x8FF7E8),
+(0x8FF7E9),(0x8FF7EA),(0x8FF7EB),(0x8FF7EC),(0x8FF7ED),(0x8FF7EE),(0x8FF7EF),(0x8FF7F0),
+(0x8FF7F1),(0x8FF7F2),(0x8FF7F3),(0x8FF7F4),(0x8FF7F5),(0x8FF7F6),(0x8FF7F7),(0x8FF7F8),
+(0x8FF7F9),(0x8FF7FA),(0x8FF7FB),(0x8FF7FC),(0x8FF7FD),(0x8FF7FE),
+(0x8FF8A1),(0x8FF8A2),(0x8FF8A3),(0x8FF8A4),(0x8FF8A5),(0x8FF8A6),(0x8FF8A7),(0x8FF8A8),
+(0x8FF8A9),(0x8FF8AA),(0x8FF8AB),(0x8FF8AC),(0x8FF8AD),(0x8FF8AE),(0x8FF8AF),(0x8FF8B0),
+(0x8FF8B1),(0x8FF8B2),(0x8FF8B3),(0x8FF8B4),(0x8FF8B5),(0x8FF8B6),(0x8FF8B7),(0x8FF8B8),
+(0x8FF8B9),(0x8FF8BA),(0x8FF8BB),(0x8FF8BC),(0x8FF8BD),(0x8FF8BE),(0x8FF8BF),(0x8FF8C0),
+(0x8FF8C1),(0x8FF8C2),(0x8FF8C3),(0x8FF8C4),(0x8FF8C5),(0x8FF8C6),(0x8FF8C7),(0x8FF8C8),
+(0x8FF8C9),(0x8FF8CA),(0x8FF8CB),(0x8FF8CC),(0x8FF8CD),(0x8FF8CE),(0x8FF8CF),(0x8FF8D0),
+(0x8FF8D1),(0x8FF8D2),(0x8FF8D3),(0x8FF8D4),(0x8FF8D5),(0x8FF8D6),(0x8FF8D7),(0x8FF8D8),
+(0x8FF8D9),(0x8FF8DA),(0x8FF8DB),(0x8FF8DC),(0x8FF8DD),(0x8FF8DE),(0x8FF8DF),(0x8FF8E0),
+(0x8FF8E1),(0x8FF8E2),(0x8FF8E3),(0x8FF8E4),(0x8FF8E5),(0x8FF8E6),(0x8FF8E7),(0x8FF8E8),
+(0x8FF8E9),(0x8FF8EA),(0x8FF8EB),(0x8FF8EC),(0x8FF8ED),(0x8FF8EE),(0x8FF8EF),(0x8FF8F0),
+(0x8FF8F1),(0x8FF8F2),(0x8FF8F3),(0x8FF8F4),(0x8FF8F5),(0x8FF8F6),(0x8FF8F7),(0x8FF8F8),
+(0x8FF8F9),(0x8FF8FA),(0x8FF8FB),(0x8FF8FC),(0x8FF8FD),(0x8FF8FE),
+(0x8FF9A1),(0x8FF9A2),(0x8FF9A3),(0x8FF9A4),(0x8FF9A5),(0x8FF9A6),(0x8FF9A7),(0x8FF9A8),
+(0x8FF9A9),(0x8FF9AA),(0x8FF9AB),(0x8FF9AC),(0x8FF9AD),(0x8FF9AE),(0x8FF9AF),(0x8FF9B0),
+(0x8FF9B1),(0x8FF9B2),(0x8FF9B3),(0x8FF9B4),(0x8FF9B5),(0x8FF9B6),(0x8FF9B7),(0x8FF9B8),
+(0x8FF9B9),(0x8FF9BA),(0x8FF9BB),(0x8FF9BC),(0x8FF9BD),(0x8FF9BE),(0x8FF9BF),(0x8FF9C0),
+(0x8FF9C1),(0x8FF9C2),(0x8FF9C3),(0x8FF9C4),(0x8FF9C5),(0x8FF9C6),(0x8FF9C7),(0x8FF9C8),
+(0x8FF9C9),(0x8FF9CA),(0x8FF9CB),(0x8FF9CC),(0x8FF9CD),(0x8FF9CE),(0x8FF9CF),(0x8FF9D0),
+(0x8FF9D1),(0x8FF9D2),(0x8FF9D3),(0x8FF9D4),(0x8FF9D5),(0x8FF9D6),(0x8FF9D7),(0x8FF9D8),
+(0x8FF9D9),(0x8FF9DA),(0x8FF9DB),(0x8FF9DC),(0x8FF9DD),(0x8FF9DE),(0x8FF9DF),(0x8FF9E0),
+(0x8FF9E1),(0x8FF9E2),(0x8FF9E3),(0x8FF9E4),(0x8FF9E5),(0x8FF9E6),(0x8FF9E7),(0x8FF9E8),
+(0x8FF9E9),(0x8FF9EA),(0x8FF9EB),(0x8FF9EC),(0x8FF9ED),(0x8FF9EE),(0x8FF9EF),(0x8FF9F0),
+(0x8FF9F1),(0x8FF9F2),(0x8FF9F3),(0x8FF9F4),(0x8FF9F5),(0x8FF9F6),(0x8FF9F7),(0x8FF9F8),
+(0x8FF9F9),(0x8FF9FA),(0x8FF9FB),(0x8FF9FC),(0x8FF9FD),(0x8FF9FE),
+(0x8FFAA1),(0x8FFAA2),(0x8FFAA3),(0x8FFAA4),(0x8FFAA5),(0x8FFAA6),(0x8FFAA7),(0x8FFAA8),
+(0x8FFAA9),(0x8FFAAA),(0x8FFAAB),(0x8FFAAC),(0x8FFAAD),(0x8FFAAE),(0x8FFAAF),(0x8FFAB0),
+(0x8FFAB1),(0x8FFAB2),(0x8FFAB3),(0x8FFAB4),(0x8FFAB5),(0x8FFAB6),(0x8FFAB7),(0x8FFAB8),
+(0x8FFAB9),(0x8FFABA),(0x8FFABB),(0x8FFABC),(0x8FFABD),(0x8FFABE),(0x8FFABF),(0x8FFAC0),
+(0x8FFAC1),(0x8FFAC2),(0x8FFAC3),(0x8FFAC4),(0x8FFAC5),(0x8FFAC6),(0x8FFAC7),(0x8FFAC8),
+(0x8FFAC9),(0x8FFACA),(0x8FFACB),(0x8FFACC),(0x8FFACD),(0x8FFACE),(0x8FFACF),(0x8FFAD0),
+(0x8FFAD1),(0x8FFAD2),(0x8FFAD3),(0x8FFAD4),(0x8FFAD5),(0x8FFAD6),(0x8FFAD7),(0x8FFAD8),
+(0x8FFAD9),(0x8FFADA),(0x8FFADB),(0x8FFADC),(0x8FFADD),(0x8FFADE),(0x8FFADF),(0x8FFAE0),
+(0x8FFAE1),(0x8FFAE2),(0x8FFAE3),(0x8FFAE4),(0x8FFAE5),(0x8FFAE6),(0x8FFAE7),(0x8FFAE8),
+(0x8FFAE9),(0x8FFAEA),(0x8FFAEB),(0x8FFAEC),(0x8FFAED),(0x8FFAEE),(0x8FFAEF),(0x8FFAF0),
+(0x8FFAF1),(0x8FFAF2),(0x8FFAF3),(0x8FFAF4),(0x8FFAF5),(0x8FFAF6),(0x8FFAF7),(0x8FFAF8),
+(0x8FFAF9),(0x8FFAFA),(0x8FFAFB),(0x8FFAFC),(0x8FFAFD),(0x8FFAFE),
+(0x8FFBA1),(0x8FFBA2),(0x8FFBA3),(0x8FFBA4),(0x8FFBA5),(0x8FFBA6),(0x8FFBA7),(0x8FFBA8),
+(0x8FFBA9),(0x8FFBAA),(0x8FFBAB),(0x8FFBAC),(0x8FFBAD),(0x8FFBAE),(0x8FFBAF),(0x8FFBB0),
+(0x8FFBB1),(0x8FFBB2),(0x8FFBB3),(0x8FFBB4),(0x8FFBB5),(0x8FFBB6),(0x8FFBB7),(0x8FFBB8),
+(0x8FFBB9),(0x8FFBBA),(0x8FFBBB),(0x8FFBBC),(0x8FFBBD),(0x8FFBBE),(0x8FFBBF),(0x8FFBC0),
+(0x8FFBC1),(0x8FFBC2),(0x8FFBC3),(0x8FFBC4),(0x8FFBC5),(0x8FFBC6),(0x8FFBC7),(0x8FFBC8),
+(0x8FFBC9),(0x8FFBCA),(0x8FFBCB),(0x8FFBCC),(0x8FFBCD),(0x8FFBCE),(0x8FFBCF),(0x8FFBD0),
+(0x8FFBD1),(0x8FFBD2),(0x8FFBD3),(0x8FFBD4),(0x8FFBD5),(0x8FFBD6),(0x8FFBD7),(0x8FFBD8),
+(0x8FFBD9),(0x8FFBDA),(0x8FFBDB),(0x8FFBDC),(0x8FFBDD),(0x8FFBDE),(0x8FFBDF),(0x8FFBE0),
+(0x8FFBE1),(0x8FFBE2),(0x8FFBE3),(0x8FFBE4),(0x8FFBE5),(0x8FFBE6),(0x8FFBE7),(0x8FFBE8),
+(0x8FFBE9),(0x8FFBEA),(0x8FFBEB),(0x8FFBEC),(0x8FFBED),(0x8FFBEE),(0x8FFBEF),(0x8FFBF0),
+(0x8FFBF1),(0x8FFBF2),(0x8FFBF3),(0x8FFBF4),(0x8FFBF5),(0x8FFBF6),(0x8FFBF7),(0x8FFBF8),
+(0x8FFBF9),(0x8FFBFA),(0x8FFBFB),(0x8FFBFC),(0x8FFBFD),(0x8FFBFE),
+(0x8FFCA1),(0x8FFCA2),(0x8FFCA3),(0x8FFCA4),(0x8FFCA5),(0x8FFCA6),(0x8FFCA7),(0x8FFCA8),
+(0x8FFCA9),(0x8FFCAA),(0x8FFCAB),(0x8FFCAC),(0x8FFCAD),(0x8FFCAE),(0x8FFCAF),(0x8FFCB0),
+(0x8FFCB1),(0x8FFCB2),(0x8FFCB3),(0x8FFCB4),(0x8FFCB5),(0x8FFCB6),(0x8FFCB7),(0x8FFCB8),
+(0x8FFCB9),(0x8FFCBA),(0x8FFCBB),(0x8FFCBC),(0x8FFCBD),(0x8FFCBE),(0x8FFCBF),(0x8FFCC0),
+(0x8FFCC1),(0x8FFCC2),(0x8FFCC3),(0x8FFCC4),(0x8FFCC5),(0x8FFCC6),(0x8FFCC7),(0x8FFCC8),
+(0x8FFCC9),(0x8FFCCA),(0x8FFCCB),(0x8FFCCC),(0x8FFCCD),(0x8FFCCE),(0x8FFCCF),(0x8FFCD0),
+(0x8FFCD1),(0x8FFCD2),(0x8FFCD3),(0x8FFCD4),(0x8FFCD5),(0x8FFCD6),(0x8FFCD7),(0x8FFCD8),
+(0x8FFCD9),(0x8FFCDA),(0x8FFCDB),(0x8FFCDC),(0x8FFCDD),(0x8FFCDE),(0x8FFCDF),(0x8FFCE0),
+(0x8FFCE1),(0x8FFCE2),(0x8FFCE3),(0x8FFCE4),(0x8FFCE5),(0x8FFCE6),(0x8FFCE7),(0x8FFCE8),
+(0x8FFCE9),(0x8FFCEA),(0x8FFCEB),(0x8FFCEC),(0x8FFCED),(0x8FFCEE),(0x8FFCEF),(0x8FFCF0),
+(0x8FFCF1),(0x8FFCF2),(0x8FFCF3),(0x8FFCF4),(0x8FFCF5),(0x8FFCF6),(0x8FFCF7),(0x8FFCF8),
+(0x8FFCF9),(0x8FFCFA),(0x8FFCFB),(0x8FFCFC),(0x8FFCFD),(0x8FFCFE),
+(0x8FFDA1),(0x8FFDA2),(0x8FFDA3),(0x8FFDA4),(0x8FFDA5),(0x8FFDA6),(0x8FFDA7),(0x8FFDA8),
+(0x8FFDA9),(0x8FFDAA),(0x8FFDAB),(0x8FFDAC),(0x8FFDAD),(0x8FFDAE),(0x8FFDAF),(0x8FFDB0),
+(0x8FFDB1),(0x8FFDB2),(0x8FFDB3),(0x8FFDB4),(0x8FFDB5),(0x8FFDB6),(0x8FFDB7),(0x8FFDB8),
+(0x8FFDB9),(0x8FFDBA),(0x8FFDBB),(0x8FFDBC),(0x8FFDBD),(0x8FFDBE),(0x8FFDBF),(0x8FFDC0),
+(0x8FFDC1),(0x8FFDC2),(0x8FFDC3),(0x8FFDC4),(0x8FFDC5),(0x8FFDC6),(0x8FFDC7),(0x8FFDC8),
+(0x8FFDC9),(0x8FFDCA),(0x8FFDCB),(0x8FFDCC),(0x8FFDCD),(0x8FFDCE),(0x8FFDCF),(0x8FFDD0),
+(0x8FFDD1),(0x8FFDD2),(0x8FFDD3),(0x8FFDD4),(0x8FFDD5),(0x8FFDD6),(0x8FFDD7),(0x8FFDD8),
+(0x8FFDD9),(0x8FFDDA),(0x8FFDDB),(0x8FFDDC),(0x8FFDDD),(0x8FFDDE),(0x8FFDDF),(0x8FFDE0),
+(0x8FFDE1),(0x8FFDE2),(0x8FFDE3),(0x8FFDE4),(0x8FFDE5),(0x8FFDE6),(0x8FFDE7),(0x8FFDE8),
+(0x8FFDE9),(0x8FFDEA),(0x8FFDEB),(0x8FFDEC),(0x8FFDED),(0x8FFDEE),(0x8FFDEF),(0x8FFDF0),
+(0x8FFDF1),(0x8FFDF2),(0x8FFDF3),(0x8FFDF4),(0x8FFDF5),(0x8FFDF6),(0x8FFDF7),(0x8FFDF8),
+(0x8FFDF9),(0x8FFDFA),(0x8FFDFB),(0x8FFDFC),(0x8FFDFD),(0x8FFDFE),
+(0x8FFEA1),(0x8FFEA2),(0x8FFEA3),(0x8FFEA4),(0x8FFEA5),(0x8FFEA6),(0x8FFEA7),(0x8FFEA8),
+(0x8FFEA9),(0x8FFEAA),(0x8FFEAB),(0x8FFEAC),(0x8FFEAD),(0x8FFEAE),(0x8FFEAF),(0x8FFEB0),
+(0x8FFEB1),(0x8FFEB2),(0x8FFEB3),(0x8FFEB4),(0x8FFEB5),(0x8FFEB6),(0x8FFEB7),(0x8FFEB8),
+(0x8FFEB9),(0x8FFEBA),(0x8FFEBB),(0x8FFEBC),(0x8FFEBD),(0x8FFEBE),(0x8FFEBF),(0x8FFEC0),
+(0x8FFEC1),(0x8FFEC2),(0x8FFEC3),(0x8FFEC4),(0x8FFEC5),(0x8FFEC6),(0x8FFEC7),(0x8FFEC8),
+(0x8FFEC9),(0x8FFECA),(0x8FFECB),(0x8FFECC),(0x8FFECD),(0x8FFECE),(0x8FFECF),(0x8FFED0),
+(0x8FFED1),(0x8FFED2),(0x8FFED3),(0x8FFED4),(0x8FFED5),(0x8FFED6),(0x8FFED7),(0x8FFED8),
+(0x8FFED9),(0x8FFEDA),(0x8FFEDB),(0x8FFEDC),(0x8FFEDD),(0x8FFEDE),(0x8FFEDF),(0x8FFEE0),
+(0x8FFEE1),(0x8FFEE2),(0x8FFEE3),(0x8FFEE4),(0x8FFEE5),(0x8FFEE6),(0x8FFEE7),(0x8FFEE8),
+(0x8FFEE9),(0x8FFEEA),(0x8FFEEB),(0x8FFEEC),(0x8FFEED),(0x8FFEEE),(0x8FFEEF),(0x8FFEF0),
+(0x8FFEF1),(0x8FFEF2),(0x8FFEF3),(0x8FFEF4),(0x8FFEF5),(0x8FFEF6),(0x8FFEF7),(0x8FFEF8),
+(0x8FFEF9),(0x8FFEFA),(0x8FFEFB),(0x8FFEFC),(0x8FFEFD),(0x8FFEFE);
+
+#Test that all the characters are stored correctly
+SELECT HEX(c1) FROM t1;
+
+#Test conversion to ucs2
+CREATE TABLE t2 SELECT CONVERT(c1 USING ucs2) AS c1 FROM t1;
+SELECT HEX(c1) FROM t2;
+
+#Test round trip conversion
+CREATE TABLE t3 SELECT CONVERT(c1 USING eucjpms) AS c1 FROM t2;
+SELECT HEX(c1) FROM t3;
+
+#Test conversion to cp932
+CREATE TABLE t4 SELECT CONVERT(c1 USING cp932) AS c1 FROM t1;
+SELECT HEX(c1) FROM t4;
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
+
+
+SET collation_connection='eucjpms_japanese_ci';
+-- source include/ctype_filesort.inc
+SET collation_connection='eucjpms_bin';
+-- source include/ctype_filesort.inc
diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test
index 512ae88a445..e17806a54aa 100644
--- a/mysql-test/t/ctype_latin1_de.test
+++ b/mysql-test/t/ctype_latin1_de.test
@@ -66,7 +66,7 @@ drop table t1;
#
# The below checks both binary and character comparisons.
#
-create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word));
+create table t1 (word varchar(255) not null, word2 varchar(255) not null default '', index(word));
show create table t1;
insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae');
update t1 set word2=word;
diff --git a/mysql-test/t/ctype_many.test b/mysql-test/t/ctype_many.test
index 26057e7c997..454e2c63cbb 100644
--- a/mysql-test/t/ctype_many.test
+++ b/mysql-test/t/ctype_many.test
@@ -8,7 +8,7 @@ SET CHARACTER SET latin1;
CREATE TABLE t1 (
comment CHAR(32) ASCII NOT NULL,
- koi8_ru_f CHAR(32) CHARACTER SET koi8r NOT NULL
+ koi8_ru_f CHAR(32) CHARACTER SET koi8r NOT NULL default ''
) CHARSET=latin5;
SHOW CREATE TABLE t1;
@@ -142,13 +142,13 @@ INSERT INTO t1 (koi8_ru_f,comment) VALUES (_koi8r'ñ','CYR CAPIT YA');
SET CHARACTER SET utf8;
SELECT koi8_ru_f,MIN(comment),COUNT(*) FROM t1 GROUP BY 1;
-ALTER TABLE t1 ADD utf8_f CHAR(32) CHARACTER SET utf8 NOT NULL;
+ALTER TABLE t1 ADD utf8_f CHAR(32) CHARACTER SET utf8 NOT NULL default '';
UPDATE t1 SET utf8_f=CONVERT(koi8_ru_f USING utf8);
SET CHARACTER SET koi8r;
SELECT * FROM t1;
-ALTER TABLE t1 ADD bin_f CHAR(32) BYTE NOT NULL;
+ALTER TABLE t1 ADD bin_f CHAR(32) BYTE NOT NULL default '';
UPDATE t1 SET bin_f=koi8_ru_f;
SELECT COUNT(DISTINCT bin_f),COUNT(DISTINCT koi8_ru_f),COUNT(DISTINCT utf8_f) FROM t1;
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index db5b13cf1b4..9d5bd0459b0 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -20,17 +20,19 @@ SET CHARACTER SET koi8r;
# which contains 0x20 in the high byte.
#
-CREATE TABLE t1 (word VARCHAR(64) CHARACTER SET ucs2);
-INSERT INTO t1 VALUES (_koi8r'ò'), (X'2004');
+CREATE TABLE t1 (word VARCHAR(64) CHARACTER SET ucs2, word2 CHAR(64) CHARACTER SET ucs2);
+INSERT INTO t1 VALUES (_koi8r'ò',_koi8r'ò'), (X'2004',X'2004');
SELECT hex(word) FROM t1 ORDER BY word;
+SELECT hex(word2) FROM t1 ORDER BY word2;
DELETE FROM t1;
#
# Check that real spaces are correctly trimmed.
#
-INSERT INTO t1 VALUES (X'042000200020'), (X'200400200020');
+INSERT INTO t1 VALUES (X'042000200020',X'042000200020'), (X'200400200020', X'200400200020');
SELECT hex(word) FROM t1 ORDER BY word;
+SELECT hex(word2) FROM t1 ORDER BY word2;
DROP TABLE t1;
#
@@ -52,7 +54,6 @@ RPAD(_ucs2 X'0420',10,_ucs2 X'0421') r;
SHOW CREATE TABLE t1;
DROP TABLE t1;
-
#
# BUG3946
#
@@ -61,6 +62,7 @@ create table t2(f1 Char(30));
insert into t2 values ("103000"), ("22720000"), ("3401200"), ("78000");
select lpad(f1, 12, "-o-/") from t2;
drop table t2;
+
######################################################
#
# Test of like
@@ -394,3 +396,12 @@ CREATE TABLE t1 (Field1 int(10) unsigned default '0');
INSERT INTO t1 VALUES ('-1');
DROP TABLE t1;
SET NAMES latin1;
+
+#
+# Conversion from an UCS2 string to a decimal column
+#
+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;
+SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/mysql-test/t/ctype_ucs_binlog.test b/mysql-test/t/ctype_ucs_binlog.test
index b50fe3b4180..226f128c1c2 100644
--- a/mysql-test/t/ctype_ucs_binlog.test
+++ b/mysql-test/t/ctype_ucs_binlog.test
@@ -9,7 +9,7 @@ create table t2 (c char(30)) charset=ucs2;
set @v=convert('abc' using ucs2);
reset master;
insert into t2 values (@v);
-show binlog events from 79;
+show binlog events from 98;
# more important than SHOW BINLOG EVENTS, mysqlbinlog (where we
# absolutely need variables names to be quoted and strings to be
# escaped).
diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test
index 800e5880b09..e8bd8965b96 100644
--- a/mysql-test/t/date_formats.test
+++ b/mysql-test/t/date_formats.test
@@ -122,6 +122,7 @@ SET datetime_format=default;
--disable_ps_protocol
select str_to_date(concat('15-01-2001',' 2:59:58.999'),
concat('%d-%m-%Y',' ','%H:%i:%s.%f'));
+select STR_TO_DATE('2004.12.12 22.30.61','%Y.%m.%d %T');
--enable_ps_protocol
create table t1 (date char(30), format char(30) not null);
diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test
index 40bd7a912f3..513de990165 100644
--- a/mysql-test/t/delayed.test
+++ b/mysql-test/t/delayed.test
@@ -31,6 +31,8 @@ insert delayed into t1 values (null,"c");
insert delayed into t1 values (3,"d"),(null,"e");
--error 1136
insert delayed into t1 values (3,"this will give an","error");
---sleep 2
+# 2 was not enough for --ps-protocol
+--sleep 4
+show status like 'not_flushed_delayed_rows';
select * from t1;
drop table t1;
diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test
index bd27e0654e0..1e3ffd5160b 100644
--- a/mysql-test/t/derived.test
+++ b/mysql-test/t/derived.test
@@ -140,7 +140,6 @@ select * from ( select * from t1 union select * from t1) a,(select * from t1 uni
explain select * from ( select * from t1 union select * from t1) a,(select * from t1 union select * from t1) b;
drop table t1;
-
#
# multi-update & multi-delete with derived tables
#
@@ -224,6 +223,19 @@ select distinct sum(b) from t1 group by a;
select distinct sum(b) from (select a,b from t1) y group by a;
drop table t1;
+
+#
+# Test for bug #7413 "Subquery with non-scalar results participating in
+# select list of derived table crashes server" aka "VIEW with sub query can
+# cause the MySQL server to crash". If we have encountered problem during
+# filling of derived table we should report error and perform cleanup
+# properly.
+#
+CREATE TABLE t1 (a char(10), b char(10));
+INSERT INTO t1 VALUES ('root','localhost'), ('root','%');
+--error 1242
+SELECT * FROM (SELECT (SELECT a.a FROM t1 AS a WHERE a.a = b.a) FROM t1 AS b) AS c;
+DROP TABLE t1;
#
# test of union subquery in the FROM clause with complex distinct/all (BUG#6565)
#
diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
new file mode 100644
index 00000000000..9bfe9567d83
--- /dev/null
+++ b/mysql-test/t/disabled.def
@@ -0,0 +1,12 @@
+##############################################################################
+#
+# List the test cases that are to be disabled temporarely.
+#
+# Separate the test case name and the comment with ':'.
+#
+# <testcasename> : Comment test
+#
+# Don't use any TAB characters for whitespace.
+#
+##############################################################################
+
diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test
index 3c1f18b7524..a3862786cc3 100644
--- a/mysql-test/t/distinct.test
+++ b/mysql-test/t/distinct.test
@@ -326,9 +326,9 @@ drop table t1,t2;
CREATE TABLE t1 (
html varchar(5) default NULL,
rin int(11) default '0',
- out int(11) default '0'
+ rout int(11) default '0'
) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('1',1,0);
-SELECT DISTINCT html,SUM(out)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin;
+SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin;
drop table t1;
diff --git a/mysql-test/t/endspace.test b/mysql-test/t/endspace.test
index 462bc3083e1..3d27c44c3b9 100644
--- a/mysql-test/t/endspace.test
+++ b/mysql-test/t/endspace.test
@@ -41,16 +41,16 @@ alter table t1 modify text1 text not null, pack_keys=1;
select concat('|', text1, '|') from t1 where text1='teststring';
select concat('|', text1, '|') from t1 where text1='teststring ';
explain select concat('|', text1, '|') from t1 where text1='teststring ';
-select * from t1 where text1 like 'teststring_%';
-select * from t1 where text1='teststring' or text1 like 'teststring_%';
+select concat('|', text1, '|') from t1 where text1 like 'teststring_%';
+select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%';
select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t';
select concat('|', text1, '|') from t1 order by text1;
drop table t1;
create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)) pack_keys=0;
insert into t1 values ('teststring'), ('nothing'), ('teststring\t');
-select * from t1 where text1='teststring' or text1 like 'teststring_%';
-select * from t1 where text1='teststring' or text1 >= 'teststring\t';
+select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%';
+select concat('|', text1, '|') from t1 where text1='teststring' or text1 >= 'teststring\t';
drop table t1;
# Test HEAP tables (with BTREE keys)
diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test
new file mode 100644
index 00000000000..6a0e0bdac79
--- /dev/null
+++ b/mysql-test/t/federated.test
@@ -0,0 +1,880 @@
+--source include/have_federated_db.inc
+
+source include/master-slave.inc;
+
+# remote table creation
+
+connection slave;
+--replicate-ignore-db=federated
+stop slave;
+
+--disable_warnings
+# at this point, we are connected to master
+DROP DATABASE IF EXISTS federated;
+--enable_warnings
+CREATE DATABASE federated;
+
+CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ DEFAULT CHARSET=latin1;
+
+connection master;
+--disable_warnings
+DROP DATABASE IF EXISTS federated;
+--enable_warnings
+CREATE DATABASE federated;
+
+# test too many items (malformed) in the comment string url
+--error 1005
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:@/too/many/items/federated/t1';
+
+# test not enough items (malformed) in the comment string url
+--error 1005
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1';
+
+# test non-existant table
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+--error 1219
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t3';
+
+# test bad user/password
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+--error 1218
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://user:pass@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+DROP TABLE IF EXISTS federated.t1;
+# # correct connection, same named tables
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (id, name) VALUES (1, 'foo');
+INSERT INTO federated.t1 (id, name) VALUES (2, 'fee');
+
+SELECT * FROM federated.t1;
+DELETE FROM federated.t1;
+DROP TABLE federated.t1;
+
+# correct connection, differently named tables
+DROP TABLE IF EXISTS federated.t2;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t2 (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t2 (id, name) VALUES (1, 'foo');
+INSERT INTO federated.t2 (id, name) VALUES (2, 'fee');
+
+SELECT * FROM federated.t2;
+DROP TABLE federated.t2;
+
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+
+DROP TABLE IF EXISTS federated.`t1%`;
+CREATE TABLE federated.`t1%` (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ DEFAULT CHARSET=latin1;
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1%';
+
+INSERT INTO federated.t1 (id, name) VALUES (1, 'foo');
+INSERT INTO federated.t1 (id, name) VALUES (2, 'fee');
+
+SELECT * FROM federated.t1;
+DELETE FROM federated.t1;
+DROP TABLE IF EXISTS federated.t1;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.`t1%` (
+ `id` int(20) NOT NULL,
+ `name` varchar(32) NOT NULL default ''
+ )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1%';
+
+INSERT INTO federated.`t1%` (id, name) VALUES (1, 'foo');
+INSERT INTO federated.`t1%` (id, name) VALUES (2, 'fee');
+
+SELECT * FROM federated.`t1%`;
+DELETE FROM federated.`t1%`;
+DROP TABLE IF EXISTS federated.`t1%`;
+
+connection slave;
+DROP TABLE IF EXISTS federated.`t1%`;
+
+# I wanted to use timestamp, but results will fail if so!!!
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `name` varchar(32) NOT NULL default '',
+ `other` int(20) NOT NULL default '0',
+ `created` datetime default '2004-04-04 04:04:04',
+ PRIMARY KEY (`id`),
+ KEY `name` (`name`),
+ KEY `other_key` (`other`))
+ DEFAULT CHARSET=latin1;
+
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `name` varchar(32) NOT NULL default '',
+ `other` int(20) NOT NULL default '0',
+ `created` datetime default '2004-04-04 04:04:04',
+ PRIMARY KEY (`id`),
+ KEY `name` (`name`),
+ KEY `other_key` (`other`))
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111);
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', 22222);
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333);
+INSERT INTO federated.t1 (name, other) VALUES ('Fourth Name', 44444);
+INSERT INTO federated.t1 (name, other) VALUES ('Fifth Name', 55555);
+INSERT INTO federated.t1 (name, other) VALUES ('Sixth Name', 66666);
+INSERT INTO federated.t1 (name, other) VALUES ('Seventh Name', 77777);
+INSERT INTO federated.t1 (name, other) VALUES ('Eigth Name', 88888);
+INSERT INTO federated.t1 (name, other) VALUES ('Ninth Name', 99999);
+INSERT INTO federated.t1 (name, other) VALUES ('Tenth Name', 101010);
+
+# basic select
+SELECT * FROM federated.t1;
+# with PRIMARY KEY index_read_idx
+SELECT * FROM federated.t1 WHERE id = 5;
+# with regular key index_read -> index_read_idx
+SELECT * FROM federated.t1 WHERE name = 'Sixth Name';
+# regular and PRIMARY KEY index_read_idx
+SELECT * FROM federated.t1 WHERE id = 6 and name = 'Sixth Name';
+# with regular key index_read -> index_read_idx
+SELECT * FROM federated.t1 WHERE other = 44444;
+SELECT * FROM federated.t1 WHERE name like '%th%';
+# update - update_row, index_read_idx
+UPDATE federated.t1 SET name = '3rd name' WHERE id = 3;
+SELECT * FROM federated.t1 WHERE name = '3rd name';
+# update - update_row, index_read -> index_read_idx
+UPDATE federated.t1 SET name = 'Third name' WHERE name = '3rd name';
+SELECT * FROM federated.t1 WHERE name = 'Third name';
+# rnd_post, ::position
+SELECT * FROM federated.t1 ORDER BY id DESC;
+SELECT * FROM federated.t1 ORDER BY name;
+SELECT * FROM federated.t1 ORDER BY name DESC;
+SELECT * FROM federated.t1 ORDER BY name ASC;
+SELECT * FROM federated.t1 GROUP BY other;
+
+# ::delete_row
+DELETE FROM federated.t1 WHERE id = 5;
+SELECT * FROM federated.t1 WHERE id = 5;
+
+# ::delete_all_rows
+DELETE FROM federated.t1;
+SELECT * FROM federated.t1 WHERE id = 5;
+
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `name` varchar(32),
+ `other` varchar(20),
+ PRIMARY KEY (`id`) );
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `name` varchar(32),
+ `other` varchar(20),
+ PRIMARY KEY (`id`) )
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111);
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', NULL);
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333);
+INSERT INTO federated.t1 (name, other) VALUES (NULL, NULL);
+INSERT INTO federated.t1 (name, other) VALUES ('Fifth Name', 55555);
+INSERT INTO federated.t1 (name, other) VALUES ('Sixth Name', 66666);
+INSERT INTO federated.t1 (name) VALUES ('Seventh Name');
+INSERT INTO federated.t1 (name, other) VALUES ('Eigth Name', 88888);
+INSERT INTO federated.t1 (name, other) VALUES ('Ninth Name', 99999);
+INSERT INTO federated.t1 (other) VALUES ('fee fie foe fum');
+
+SELECT * FROM federated.t1 WHERE other IS NULL;
+SELECT * FROM federated.t1 WHERE name IS NULL;
+SELECT * FROM federated.t1 WHERE name IS NULL and other IS NULL;
+SELECT * FROM federated.t1 WHERE name IS NULL or other IS NULL;
+
+UPDATE federated.t1
+SET name = 'Fourth Name', other = 'four four four'
+WHERE name IS NULL AND other IS NULL;
+
+UPDATE federated.t1 SET other = 'two two two two' WHERE name = 'Second Name';
+UPDATE federated.t1 SET other = 'seven seven' WHERE name like 'Sec%';
+UPDATE federated.t1 SET other = 'seven seven' WHERE name = 'Seventh Name';
+UPDATE federated.t1 SET name = 'Tenth Name' WHERE other like 'fee fie%';
+SELECT * FROM federated.t1 WHERE name IS NULL OR other IS NULL ;
+SELECT * FROM federated.t1;
+
+# test multi-keys
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `name` varchar(32) NOT NULL DEFAULT '',
+ `other` varchar(20) NOT NULL DEFAULT '',
+ PRIMARY KEY (`id`),
+ KEY nameoth (name, other) );
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `name` varchar(32) NOT NULL DEFAULT '',
+ `other` varchar(20) NOT NULL DEFAULT '',
+ PRIMARY KEY (`id`),
+ KEY nameoth (name, other))
+ ENGINE="FEDERATED" DEFAULT
+ CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, other) VALUES ('First Name', '1111');
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', '2222');
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', '3333');
+SELECT * FROM federated.t1 WHERE name = 'Second Name';
+SELECT * FROM federated.t1 WHERE other = '2222';
+SELECT * FROM federated.t1 WHERE name = 'Third Name';
+SELECT * FROM federated.t1 WHERE name = 'Third Name' AND other = '3333';
+
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int NOT NULL auto_increment,
+ `name` char(32) NOT NULL DEFAULT '',
+ `bincol` binary(4) NOT NULL,
+ `floatval` decimal(5,2) NOT NULL DEFAULT 0.0,
+ `other` int NOT NULL DEFAULT 0,
+ PRIMARY KEY (id),
+ KEY nameoth(name, other),
+ KEY bincol(bincol),
+ KEY floatval(floatval));
+
+# test other types of indexes
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int NOT NULL auto_increment,
+ `name` char(32) NOT NULL DEFAULT '',
+ `bincol` binary(4) NOT NULL,
+ `floatval` decimal(5,2) NOT NULL DEFAULT 0.0,
+ `other` int NOT NULL DEFAULT 0,
+ PRIMARY KEY (id),
+ KEY nameoth(name,other),
+ KEY bincol(bincol),
+ KEY floatval(floatval))
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+ VALUES ('first', 0x65, 11.11, 1111);
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+ VALUES ('second', 0x66, 22.22, 2222);
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+ VALUES ('third', 'g', 22.22, 2222);
+SELECT * FROM federated.t1;
+SELECT * FROM federated.t1 WHERE name = 'second';
+SELECT * FROM federated.t1 WHERE bincol= 'f';
+SELECT * FROM federated.t1 WHERE bincol= 0x66;
+SELECT * FROM federated.t1 WHERE bincol= 0x67;
+SELECT * FROM federated.t1 WHERE bincol= 'g';
+SELECT * FROM federated.t1 WHERE floatval=11.11;
+SELECT * FROM federated.t1 WHERE name='third';
+SELECT * FROM federated.t1 WHERE other=2222;
+SELECT * FROM federated.t1 WHERE name='third' and other=2222;
+
+# test NULLs
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int,
+ `name` varchar(32),
+ `floatval` float,
+ `other` int)
+DEFAULT CHARSET=latin1;
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int,
+ `name` varchar(32),
+ `floatval` float,
+ `other` int)
+ENGINE="FEDERATED"
+DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+# these both should be the same
+INSERT INTO federated.t1 values (NULL, NULL, NULL, NULL);
+INSERT INTO federated.t1 values ();
+INSERT INTO federated.t1 (id) VALUES (1);
+INSERT INTO federated.t1 (name, floatval, other)
+ VALUES ('foo', 33.33333332, NULL);
+INSERT INTO federated.t1 (name, floatval, other)
+ VALUES (0, 00.3333, NULL);
+SELECT * FROM federated.t1;
+SELECT count(*) FROM federated.t1
+WHERE id IS NULL
+AND name IS NULL
+AND floatval IS NULL
+AND other IS NULL;
+
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `blurb_id` int NOT NULL DEFAULT 0,
+ `blurb` text default '',
+ PRIMARY KEY (blurb_id))
+ DEFAULT CHARSET=latin1;
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `blurb_id` int NOT NULL DEFAULT 0,
+ `blurb` text default '',
+ PRIMARY KEY (blurb_id))
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 VALUES (1, " MySQL supports a number of column types in several categories: numeric types, date and time types, and string (character) types. This chapter first gives an overview of these column types, and then provides a more detailed description of the properties of the types in each category, and a summary of the column type storage requirements. The overview is intentionally brief. The more detailed descriptions should be consulted for additional information about particular column types, such as the allowable formats in which you can specify values.");
+INSERT INTO federated.t1 VALUES (2, "All arithmetic is done using signed BIGINT or DOUBLE values, so you should not use unsigned big integers larger than 9223372036854775807 (63 bits) except with bit functions! If you do that, some of the last digits in the result may be wrong because of rounding errors when converting a BIGINT value to a DOUBLE.");
+INSERT INTO federated.t1 VALUES (3, " A floating-point number. p represents the precision. It can be from 0 to 24 for a single-precision floating-point number and from 25 to 53 for a double-precision floating-point number. These types are like the FLOAT and DOUBLE types described immediately following. FLOAT(p) has the same range as the corresponding FLOAT and DOUBLE types, but the display size and number of decimals are undefined. ");
+INSERT INTO federated.t1 VALUES(4, "Die Übersetzung einer so umfangreichen technischen Dokumentation wie des MySQL-Referenzhandbuchs ist schon eine besondere Herausforderung. Zumindest für jemanden, der seine Zielsprache ernst nimmt:");
+SELECT * FROM federated.t1;
+
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `a` int NOT NULL,
+ `b` int NOT NULL,
+ `c` int NOT NULL,
+ PRIMARY KEY (a),key(b));
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `a` int NOT NULL,
+ `b` int NOT NULL,
+ `c` int NOT NULL,
+ PRIMARY KEY (a),
+ KEY (b))
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 VALUES (3,3,3),(1,1,1),(2,2,2),(4,4,4);
+EXPLAIN SELECT * FROM federated.t1 ORDER BY a;
+EXPLAIN SELECT * FROM federated.t1 ORDER BY b;
+EXPLAIN SELECT * FROM federated.t1 ORDER BY c;
+EXPLAIN SELECT a FROM federated.t1 ORDER BY a;
+EXPLAIN SELECT b FROM federated.t1 ORDER BY b;
+EXPLAIN SELECT a,b FROM federated.t1 ORDER BY b;
+EXPLAIN SELECT a,b FROM federated.t1;
+EXPLAIN SELECT a,b,c FROM federated.t1;
+
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
+int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int, i17
+int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
+i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
+int, i35 int, i36 int, i37 int, i38 int, i39 int, i40 int, i41 int, i42 int,
+i43 int, i44 int, i45 int, i46 int, i47 int, i48 int, i49 int, i50 int, i51
+int, i52 int, i53 int, i54 int, i55 int, i56 int, i57 int, i58 int, i59 int,
+i60 int, i61 int, i62 int, i63 int, i64 int, i65 int, i66 int, i67 int, i68
+int, i69 int, i70 int, i71 int, i72 int, i73 int, i74 int, i75 int, i76 int,
+i77 int, i78 int, i79 int, i80 int, i81 int, i82 int, i83 int, i84 int, i85
+int, i86 int, i87 int, i88 int, i89 int, i90 int, i91 int, i92 int, i93 int,
+i94 int, i95 int, i96 int, i97 int, i98 int, i99 int, i100 int, i101 int, i102
+int, i103 int, i104 int, i105 int, i106 int, i107 int, i108 int, i109 int, i110
+int, i111 int, i112 int, i113 int, i114 int, i115 int, i116 int, i117 int, i118
+int, i119 int, i120 int, i121 int, i122 int, i123 int, i124 int, i125 int, i126
+int, i127 int, i128 int, i129 int, i130 int, i131 int, i132 int, i133 int, i134
+int, i135 int, i136 int, i137 int, i138 int, i139 int, i140 int, i141 int, i142
+int, i143 int, i144 int, i145 int, i146 int, i147 int, i148 int, i149 int, i150
+int, i151 int, i152 int, i153 int, i154 int, i155 int, i156 int, i157 int, i158
+int, i159 int, i160 int, i161 int, i162 int, i163 int, i164 int, i165 int, i166
+int, i167 int, i168 int, i169 int, i170 int, i171 int, i172 int, i173 int, i174
+int, i175 int, i176 int, i177 int, i178 int, i179 int, i180 int, i181 int, i182
+int, i183 int, i184 int, i185 int, i186 int, i187 int, i188 int, i189 int, i190
+int, i191 int, i192 int, i193 int, i194 int, i195 int, i196 int, i197 int, i198
+int, i199 int, i200 int, i201 int, i202 int, i203 int, i204 int, i205 int, i206
+int, i207 int, i208 int, i209 int, i210 int, i211 int, i212 int, i213 int, i214
+int, i215 int, i216 int, i217 int, i218 int, i219 int, i220 int, i221 int, i222
+int, i223 int, i224 int, i225 int, i226 int, i227 int, i228 int, i229 int, i230
+int, i231 int, i232 int, i233 int, i234 int, i235 int, i236 int, i237 int, i238
+int, i239 int, i240 int, i241 int, i242 int, i243 int, i244 int, i245 int, i246
+int, i247 int, i248 int, i249 int, i250 int, i251 int, i252 int, i253 int, i254
+int, i255 int, i256 int, i257 int, i258 int, i259 int, i260 int, i261 int, i262
+int, i263 int, i264 int, i265 int, i266 int, i267 int, i268 int, i269 int, i270
+int, i271 int, i272 int, i273 int, i274 int, i275 int, i276 int, i277 int, i278
+int, i279 int, i280 int, i281 int, i282 int, i283 int, i284 int, i285 int, i286
+int, i287 int, i288 int, i289 int, i290 int, i291 int, i292 int, i293 int, i294
+int, i295 int, i296 int, i297 int, i298 int, i299 int, i300 int, i301 int, i302
+int, i303 int, i304 int, i305 int, i306 int, i307 int, i308 int, i309 int, i310
+int, i311 int, i312 int, i313 int, i314 int, i315 int, i316 int, i317 int, i318
+int, i319 int, i320 int, i321 int, i322 int, i323 int, i324 int, i325 int, i326
+int, i327 int, i328 int, i329 int, i330 int, i331 int, i332 int, i333 int, i334
+int, i335 int, i336 int, i337 int, i338 int, i339 int, i340 int, i341 int, i342
+int, i343 int, i344 int, i345 int, i346 int, i347 int, i348 int, i349 int, i350
+int, i351 int, i352 int, i353 int, i354 int, i355 int, i356 int, i357 int, i358
+int, i359 int, i360 int, i361 int, i362 int, i363 int, i364 int, i365 int, i366
+int, i367 int, i368 int, i369 int, i370 int, i371 int, i372 int, i373 int, i374
+int, i375 int, i376 int, i377 int, i378 int, i379 int, i380 int, i381 int, i382
+int, i383 int, i384 int, i385 int, i386 int, i387 int, i388 int, i389 int, i390
+int, i391 int, i392 int, i393 int, i394 int, i395 int, i396 int, i397 int, i398
+int, i399 int, i400 int, i401 int, i402 int, i403 int, i404 int, i405 int, i406
+int, i407 int, i408 int, i409 int, i410 int, i411 int, i412 int, i413 int, i414
+int, i415 int, i416 int, i417 int, i418 int, i419 int, i420 int, i421 int, i422
+int, i423 int, i424 int, i425 int, i426 int, i427 int, i428 int, i429 int, i430
+int, i431 int, i432 int, i433 int, i434 int, i435 int, i436 int, i437 int, i438
+int, i439 int, i440 int, i441 int, i442 int, i443 int, i444 int, i445 int, i446
+int, i447 int, i448 int, i449 int, i450 int, i451 int, i452 int, i453 int, i454
+int, i455 int, i456 int, i457 int, i458 int, i459 int, i460 int, i461 int, i462
+int, i463 int, i464 int, i465 int, i466 int, i467 int, i468 int, i469 int, i470
+int, i471 int, i472 int, i473 int, i474 int, i475 int, i476 int, i477 int, i478
+int, i479 int, i480 int, i481 int, i482 int, i483 int, i484 int, i485 int, i486
+int, i487 int, i488 int, i489 int, i490 int, i491 int, i492 int, i493 int, i494
+int, i495 int, i496 int, i497 int, i498 int, i499 int, i500 int, i501 int, i502
+int, i503 int, i504 int, i505 int, i506 int, i507 int, i508 int, i509 int, i510
+int, i511 int, i512 int, i513 int, i514 int, i515 int, i516 int, i517 int, i518
+int, i519 int, i520 int, i521 int, i522 int, i523 int, i524 int, i525 int, i526
+int, i527 int, i528 int, i529 int, i530 int, i531 int, i532 int, i533 int, i534
+int, i535 int, i536 int, i537 int, i538 int, i539 int, i540 int, i541 int, i542
+int, i543 int, i544 int, i545 int, i546 int, i547 int, i548 int, i549 int, i550
+int, i551 int, i552 int, i553 int, i554 int, i555 int, i556 int, i557 int, i558
+int, i559 int, i560 int, i561 int, i562 int, i563 int, i564 int, i565 int, i566
+int, i567 int, i568 int, i569 int, i570 int, i571 int, i572 int, i573 int, i574
+int, i575 int, i576 int, i577 int, i578 int, i579 int, i580 int, i581 int, i582
+int, i583 int, i584 int, i585 int, i586 int, i587 int, i588 int, i589 int, i590
+int, i591 int, i592 int, i593 int, i594 int, i595 int, i596 int, i597 int, i598
+int, i599 int, i600 int, i601 int, i602 int, i603 int, i604 int, i605 int, i606
+int, i607 int, i608 int, i609 int, i610 int, i611 int, i612 int, i613 int, i614
+int, i615 int, i616 int, i617 int, i618 int, i619 int, i620 int, i621 int, i622
+int, i623 int, i624 int, i625 int, i626 int, i627 int, i628 int, i629 int, i630
+int, i631 int, i632 int, i633 int, i634 int, i635 int, i636 int, i637 int, i638
+int, i639 int, i640 int, i641 int, i642 int, i643 int, i644 int, i645 int, i646
+int, i647 int, i648 int, i649 int, i650 int, i651 int, i652 int, i653 int, i654
+int, i655 int, i656 int, i657 int, i658 int, i659 int, i660 int, i661 int, i662
+int, i663 int, i664 int, i665 int, i666 int, i667 int, i668 int, i669 int, i670
+int, i671 int, i672 int, i673 int, i674 int, i675 int, i676 int, i677 int, i678
+int, i679 int, i680 int, i681 int, i682 int, i683 int, i684 int, i685 int, i686
+int, i687 int, i688 int, i689 int, i690 int, i691 int, i692 int, i693 int, i694
+int, i695 int, i696 int, i697 int, i698 int, i699 int, i700 int, i701 int, i702
+int, i703 int, i704 int, i705 int, i706 int, i707 int, i708 int, i709 int, i710
+int, i711 int, i712 int, i713 int, i714 int, i715 int, i716 int, i717 int, i718
+int, i719 int, i720 int, i721 int, i722 int, i723 int, i724 int, i725 int, i726
+int, i727 int, i728 int, i729 int, i730 int, i731 int, i732 int, i733 int, i734
+int, i735 int, i736 int, i737 int, i738 int, i739 int, i740 int, i741 int, i742
+int, i743 int, i744 int, i745 int, i746 int, i747 int, i748 int, i749 int, i750
+int, i751 int, i752 int, i753 int, i754 int, i755 int, i756 int, i757 int, i758
+int, i759 int, i760 int, i761 int, i762 int, i763 int, i764 int, i765 int, i766
+int, i767 int, i768 int, i769 int, i770 int, i771 int, i772 int, i773 int, i774
+int, i775 int, i776 int, i777 int, i778 int, i779 int, i780 int, i781 int, i782
+int, i783 int, i784 int, i785 int, i786 int, i787 int, i788 int, i789 int, i790
+int, i791 int, i792 int, i793 int, i794 int, i795 int, i796 int, i797 int, i798
+int, i799 int, i800 int, i801 int, i802 int, i803 int, i804 int, i805 int, i806
+int, i807 int, i808 int, i809 int, i810 int, i811 int, i812 int, i813 int, i814
+int, i815 int, i816 int, i817 int, i818 int, i819 int, i820 int, i821 int, i822
+int, i823 int, i824 int, i825 int, i826 int, i827 int, i828 int, i829 int, i830
+int, i831 int, i832 int, i833 int, i834 int, i835 int, i836 int, i837 int, i838
+int, i839 int, i840 int, i841 int, i842 int, i843 int, i844 int, i845 int, i846
+int, i847 int, i848 int, i849 int, i850 int, i851 int, i852 int, i853 int, i854
+int, i855 int, i856 int, i857 int, i858 int, i859 int, i860 int, i861 int, i862
+int, i863 int, i864 int, i865 int, i866 int, i867 int, i868 int, i869 int, i870
+int, i871 int, i872 int, i873 int, i874 int, i875 int, i876 int, i877 int, i878
+int, i879 int, i880 int, i881 int, i882 int, i883 int, i884 int, i885 int, i886
+int, i887 int, i888 int, i889 int, i890 int, i891 int, i892 int, i893 int, i894
+int, i895 int, i896 int, i897 int, i898 int, i899 int, i900 int, i901 int, i902
+int, i903 int, i904 int, i905 int, i906 int, i907 int, i908 int, i909 int, i910
+int, i911 int, i912 int, i913 int, i914 int, i915 int, i916 int, i917 int, i918
+int, i919 int, i920 int, i921 int, i922 int, i923 int, i924 int, i925 int, i926
+int, i927 int, i928 int, i929 int, i930 int, i931 int, i932 int, i933 int, i934
+int, i935 int, i936 int, i937 int, i938 int, i939 int, i940 int, i941 int, i942
+int, i943 int, i944 int, i945 int, i946 int, i947 int, i948 int, i949 int, i950
+int, i951 int, i952 int, i953 int, i954 int, i955 int, i956 int, i957 int, i958
+int, i959 int, i960 int, i961 int, i962 int, i963 int, i964 int, i965 int, i966
+int, i967 int, i968 int, i969 int, i970 int, i971 int, i972 int, i973 int, i974
+int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
+int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
+int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
+int, i999 int, i1000 int, b varchar(256)) row_format=dynamic;
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1
+(i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
+int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int,
+i17 int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
+i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
+int, i35 int, i36 int, i37 int, i38 int, i39 int, i40 int, i41 int, i42 int,
+i43 int, i44 int, i45 int, i46 int, i47 int, i48 int, i49 int, i50 int, i51
+int, i52 int, i53 int, i54 int, i55 int, i56 int, i57 int, i58 int, i59 int,
+i60 int, i61 int, i62 int, i63 int, i64 int, i65 int, i66 int, i67 int, i68
+int, i69 int, i70 int, i71 int, i72 int, i73 int, i74 int, i75 int, i76 int,
+i77 int, i78 int, i79 int, i80 int, i81 int, i82 int, i83 int, i84 int, i85
+int, i86 int, i87 int, i88 int, i89 int, i90 int, i91 int, i92 int, i93 int,
+i94 int, i95 int, i96 int, i97 int, i98 int, i99 int, i100 int, i101 int, i102
+int, i103 int, i104 int, i105 int, i106 int, i107 int, i108 int, i109 int, i110
+int, i111 int, i112 int, i113 int, i114 int, i115 int, i116 int, i117 int, i118
+int, i119 int, i120 int, i121 int, i122 int, i123 int, i124 int, i125 int, i126
+int, i127 int, i128 int, i129 int, i130 int, i131 int, i132 int, i133 int, i134
+int, i135 int, i136 int, i137 int, i138 int, i139 int, i140 int, i141 int, i142
+int, i143 int, i144 int, i145 int, i146 int, i147 int, i148 int, i149 int, i150
+int, i151 int, i152 int, i153 int, i154 int, i155 int, i156 int, i157 int, i158
+int, i159 int, i160 int, i161 int, i162 int, i163 int, i164 int, i165 int, i166
+int, i167 int, i168 int, i169 int, i170 int, i171 int, i172 int, i173 int, i174
+int, i175 int, i176 int, i177 int, i178 int, i179 int, i180 int, i181 int, i182
+int, i183 int, i184 int, i185 int, i186 int, i187 int, i188 int, i189 int, i190
+int, i191 int, i192 int, i193 int, i194 int, i195 int, i196 int, i197 int, i198
+int, i199 int, i200 int, i201 int, i202 int, i203 int, i204 int, i205 int, i206
+int, i207 int, i208 int, i209 int, i210 int, i211 int, i212 int, i213 int, i214
+int, i215 int, i216 int, i217 int, i218 int, i219 int, i220 int, i221 int, i222
+int, i223 int, i224 int, i225 int, i226 int, i227 int, i228 int, i229 int, i230
+int, i231 int, i232 int, i233 int, i234 int, i235 int, i236 int, i237 int, i238
+int, i239 int, i240 int, i241 int, i242 int, i243 int, i244 int, i245 int, i246
+int, i247 int, i248 int, i249 int, i250 int, i251 int, i252 int, i253 int, i254
+int, i255 int, i256 int, i257 int, i258 int, i259 int, i260 int, i261 int, i262
+int, i263 int, i264 int, i265 int, i266 int, i267 int, i268 int, i269 int, i270
+int, i271 int, i272 int, i273 int, i274 int, i275 int, i276 int, i277 int, i278
+int, i279 int, i280 int, i281 int, i282 int, i283 int, i284 int, i285 int, i286
+int, i287 int, i288 int, i289 int, i290 int, i291 int, i292 int, i293 int, i294
+int, i295 int, i296 int, i297 int, i298 int, i299 int, i300 int, i301 int, i302
+int, i303 int, i304 int, i305 int, i306 int, i307 int, i308 int, i309 int, i310
+int, i311 int, i312 int, i313 int, i314 int, i315 int, i316 int, i317 int, i318
+int, i319 int, i320 int, i321 int, i322 int, i323 int, i324 int, i325 int, i326
+int, i327 int, i328 int, i329 int, i330 int, i331 int, i332 int, i333 int, i334
+int, i335 int, i336 int, i337 int, i338 int, i339 int, i340 int, i341 int, i342
+int, i343 int, i344 int, i345 int, i346 int, i347 int, i348 int, i349 int, i350
+int, i351 int, i352 int, i353 int, i354 int, i355 int, i356 int, i357 int, i358
+int, i359 int, i360 int, i361 int, i362 int, i363 int, i364 int, i365 int, i366
+int, i367 int, i368 int, i369 int, i370 int, i371 int, i372 int, i373 int, i374
+int, i375 int, i376 int, i377 int, i378 int, i379 int, i380 int, i381 int, i382
+int, i383 int, i384 int, i385 int, i386 int, i387 int, i388 int, i389 int, i390
+int, i391 int, i392 int, i393 int, i394 int, i395 int, i396 int, i397 int, i398
+int, i399 int, i400 int, i401 int, i402 int, i403 int, i404 int, i405 int, i406
+int, i407 int, i408 int, i409 int, i410 int, i411 int, i412 int, i413 int, i414
+int, i415 int, i416 int, i417 int, i418 int, i419 int, i420 int, i421 int, i422
+int, i423 int, i424 int, i425 int, i426 int, i427 int, i428 int, i429 int, i430
+int, i431 int, i432 int, i433 int, i434 int, i435 int, i436 int, i437 int, i438
+int, i439 int, i440 int, i441 int, i442 int, i443 int, i444 int, i445 int, i446
+int, i447 int, i448 int, i449 int, i450 int, i451 int, i452 int, i453 int, i454
+int, i455 int, i456 int, i457 int, i458 int, i459 int, i460 int, i461 int, i462
+int, i463 int, i464 int, i465 int, i466 int, i467 int, i468 int, i469 int, i470
+int, i471 int, i472 int, i473 int, i474 int, i475 int, i476 int, i477 int, i478
+int, i479 int, i480 int, i481 int, i482 int, i483 int, i484 int, i485 int, i486
+int, i487 int, i488 int, i489 int, i490 int, i491 int, i492 int, i493 int, i494
+int, i495 int, i496 int, i497 int, i498 int, i499 int, i500 int, i501 int, i502
+int, i503 int, i504 int, i505 int, i506 int, i507 int, i508 int, i509 int, i510
+int, i511 int, i512 int, i513 int, i514 int, i515 int, i516 int, i517 int, i518
+int, i519 int, i520 int, i521 int, i522 int, i523 int, i524 int, i525 int, i526
+int, i527 int, i528 int, i529 int, i530 int, i531 int, i532 int, i533 int, i534
+int, i535 int, i536 int, i537 int, i538 int, i539 int, i540 int, i541 int, i542
+int, i543 int, i544 int, i545 int, i546 int, i547 int, i548 int, i549 int, i550
+int, i551 int, i552 int, i553 int, i554 int, i555 int, i556 int, i557 int, i558
+int, i559 int, i560 int, i561 int, i562 int, i563 int, i564 int, i565 int, i566
+int, i567 int, i568 int, i569 int, i570 int, i571 int, i572 int, i573 int, i574
+int, i575 int, i576 int, i577 int, i578 int, i579 int, i580 int, i581 int, i582
+int, i583 int, i584 int, i585 int, i586 int, i587 int, i588 int, i589 int, i590
+int, i591 int, i592 int, i593 int, i594 int, i595 int, i596 int, i597 int, i598
+int, i599 int, i600 int, i601 int, i602 int, i603 int, i604 int, i605 int, i606
+int, i607 int, i608 int, i609 int, i610 int, i611 int, i612 int, i613 int, i614
+int, i615 int, i616 int, i617 int, i618 int, i619 int, i620 int, i621 int, i622
+int, i623 int, i624 int, i625 int, i626 int, i627 int, i628 int, i629 int, i630
+int, i631 int, i632 int, i633 int, i634 int, i635 int, i636 int, i637 int, i638
+int, i639 int, i640 int, i641 int, i642 int, i643 int, i644 int, i645 int, i646
+int, i647 int, i648 int, i649 int, i650 int, i651 int, i652 int, i653 int, i654
+int, i655 int, i656 int, i657 int, i658 int, i659 int, i660 int, i661 int, i662
+int, i663 int, i664 int, i665 int, i666 int, i667 int, i668 int, i669 int, i670
+int, i671 int, i672 int, i673 int, i674 int, i675 int, i676 int, i677 int, i678
+int, i679 int, i680 int, i681 int, i682 int, i683 int, i684 int, i685 int, i686
+int, i687 int, i688 int, i689 int, i690 int, i691 int, i692 int, i693 int, i694
+int, i695 int, i696 int, i697 int, i698 int, i699 int, i700 int, i701 int, i702
+int, i703 int, i704 int, i705 int, i706 int, i707 int, i708 int, i709 int, i710
+int, i711 int, i712 int, i713 int, i714 int, i715 int, i716 int, i717 int, i718
+int, i719 int, i720 int, i721 int, i722 int, i723 int, i724 int, i725 int, i726
+int, i727 int, i728 int, i729 int, i730 int, i731 int, i732 int, i733 int, i734
+int, i735 int, i736 int, i737 int, i738 int, i739 int, i740 int, i741 int, i742
+int, i743 int, i744 int, i745 int, i746 int, i747 int, i748 int, i749 int, i750
+int, i751 int, i752 int, i753 int, i754 int, i755 int, i756 int, i757 int, i758
+int, i759 int, i760 int, i761 int, i762 int, i763 int, i764 int, i765 int, i766
+int, i767 int, i768 int, i769 int, i770 int, i771 int, i772 int, i773 int, i774
+int, i775 int, i776 int, i777 int, i778 int, i779 int, i780 int, i781 int, i782
+int, i783 int, i784 int, i785 int, i786 int, i787 int, i788 int, i789 int, i790
+int, i791 int, i792 int, i793 int, i794 int, i795 int, i796 int, i797 int, i798
+int, i799 int, i800 int, i801 int, i802 int, i803 int, i804 int, i805 int, i806
+int, i807 int, i808 int, i809 int, i810 int, i811 int, i812 int, i813 int, i814
+int, i815 int, i816 int, i817 int, i818 int, i819 int, i820 int, i821 int, i822
+int, i823 int, i824 int, i825 int, i826 int, i827 int, i828 int, i829 int, i830
+int, i831 int, i832 int, i833 int, i834 int, i835 int, i836 int, i837 int, i838
+int, i839 int, i840 int, i841 int, i842 int, i843 int, i844 int, i845 int, i846
+int, i847 int, i848 int, i849 int, i850 int, i851 int, i852 int, i853 int, i854
+int, i855 int, i856 int, i857 int, i858 int, i859 int, i860 int, i861 int, i862
+int, i863 int, i864 int, i865 int, i866 int, i867 int, i868 int, i869 int, i870
+int, i871 int, i872 int, i873 int, i874 int, i875 int, i876 int, i877 int, i878
+int, i879 int, i880 int, i881 int, i882 int, i883 int, i884 int, i885 int, i886
+int, i887 int, i888 int, i889 int, i890 int, i891 int, i892 int, i893 int, i894
+int, i895 int, i896 int, i897 int, i898 int, i899 int, i900 int, i901 int, i902
+int, i903 int, i904 int, i905 int, i906 int, i907 int, i908 int, i909 int, i910
+int, i911 int, i912 int, i913 int, i914 int, i915 int, i916 int, i917 int, i918
+int, i919 int, i920 int, i921 int, i922 int, i923 int, i924 int, i925 int, i926
+int, i927 int, i928 int, i929 int, i930 int, i931 int, i932 int, i933 int, i934
+int, i935 int, i936 int, i937 int, i938 int, i939 int, i940 int, i941 int, i942
+int, i943 int, i944 int, i945 int, i946 int, i947 int, i948 int, i949 int, i950
+int, i951 int, i952 int, i953 int, i954 int, i955 int, i956 int, i957 int, i958
+int, i959 int, i960 int, i961 int, i962 int, i963 int, i964 int, i965 int, i966
+int, i967 int, i968 int, i969 int, i970 int, i971 int, i972 int, i973 int, i974
+int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
+int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
+int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
+int, i999 int, i1000 int, b varchar(256))
+row_format=dynamic
+ENGINE="FEDERATED"
+DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1
+values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "PatrickG");
+UPDATE federated.t1 SET b=repeat('a',256);
+UPDATE federated.t1 SET i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0, i10=0;
+SELECT * FROM federated.t1 WHERE i9=0 and i10=0;
+UPDATE federated.t1 SET i50=20;
+SELECT * FROM federated.t1;
+DELETE FROM federated.t1 WHERE i51=20;
+SELECT * FROM federated.t1;
+DELETE FROM federated.t1 WHERE i50=20;
+SELECT * FROM federated.t1;
+
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (id int NOT NULL auto_increment, code char(20) NOT NULL, fileguts blob NOT NULL, creation_date datetime, entered_time datetime default '2004-04-04 04:04:04', PRIMARY KEY(id), index(code), index(fileguts(10))) DEFAULT CHARSET=latin1;
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ id int NOT NULL auto_increment,
+ code char(20) NOT NULL,
+ fileguts blob NOT NULL,
+ creation_date datetime,
+ entered_time datetime default '2004-04-04 04:04:04',
+ PRIMARY KEY(id),
+ index(code),
+ index(fileguts(10)))
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('ASDFWERQWETWETAWETA', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2003-03-03 03:03:03');
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04');
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04');
+SELECT * FROM federated.t1;
+# test blob indexes
+SELECT * FROM federated.t1 WHERE fileguts = 'jimbob';
+
+# test blob with binary
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (`a` BLOB);
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `a` BLOB)
+ENGINE="FEDERATED"
+COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 VALUES (0x00);
+INSERT INTO federated.t1 VALUES (0x0001);
+INSERT INTO federated.t1 VALUES (0x0100);
+SELECT HEX(a) FROM federated.t1;
+
+# # simple tests for cyrillic, given to me by
+# DROP TABLE IF EXISTS federated.t1;
+# --replace_result $SLAVE_MYPORT SLAVE_PORT
+# eval CREATE TABLE federated.t1
+# (a char(20)) charset=cp1251
+# ENGINE="FEDERATED" COMMENT="mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1";
+# #
+# connection slave;
+# DROP TABLE IF EXISTS federated.t1;
+# CREATE TABLE federated.t1 (a char(20)) charset=cp1251;
+# #
+# connection master;
+# INSERT INTO federated.t1 values (_cp1251'À-ÁÂÃ-1');
+# INSERT INTO federated.t1 values (_cp1251'Á-ÂÃÄ-2');
+# SELECT * FROM federated.t1;
+# SET names cp1251;
+# INSERT INTO federated.t1 values ('Â-ÃÄÅ-3');
+# INSERT INTO federated.t1 values ('Ã-ŨÆ-4');
+# SELECT * FROM federated.t1;
+# SELECT hex(a) from federated.t1;
+# SELECT hex(a) from federated.t1 ORDER BY a desc;
+# UPDATE federated.t1 SET a='À-ÁÂÃ-1íîâûé' WHERE a='À-ÁÂÃ-1';
+# SELECT * FROM federated.t1;
+# DELETE FROM federated.t1 WHERE a='Ã-ŨÆ-4';
+# SELECT * FROM federated.t1;
+# DELETE FROM federated.t1 WHERE a>'Â-';
+# SELECT * FROM federated.t1;
+# SET names default;
+# DROP TABLE IF EXISTS federated.t1;
+
+#
+# DROP TABLE IF EXISTS federated.t1;
+#
+
+# test joins with non-federated table
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `country_id` int(20) NOT NULL DEFAULT 0,
+ `name` varchar(32),
+ `other` varchar(20),
+ PRIMARY KEY (`id`),
+ key (country_id));
+
+connection master;
+DROP TABLE IF EXISTS federated.countries;
+CREATE TABLE federated.countries (
+ `id` int(20) NOT NULL auto_increment,
+ `country` varchar(32),
+ PRIMARY KEY (id));
+INSERT INTO federated.countries (country) VALUES ('India');
+INSERT INTO federated.countries (country) VALUES ('Germany');
+INSERT INTO federated.countries (country) VALUES ('Italy');
+INSERT INTO federated.countries (country) VALUES ('Finland');
+INSERT INTO federated.countries (country) VALUES ('Ukraine');
+
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `country_id` int(20) NOT NULL DEFAULT 0,
+ `name` varchar(32),
+ `other` varchar(20),
+ PRIMARY KEY (`id`),
+ KEY (country_id) )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Kumar', 1, 11111);
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Lenz', 2, 22222);
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Marizio', 3, 33333);
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Monty', 4, 33333);
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Sanja', 5, 33333);
+
+SELECT federated.t1.*, federated.countries.country
+FROM federated.t1 left join federated.countries
+ON federated.t1.country_id = federated.countries.id;
+
+DROP TABLE federated.countries;
+
+connection master;
+--disable_warnings
+DROP TABLE IF EXISTS federated.t1;
+DROP DATABASE IF EXISTS federated;
+--enable_warnings
+
+connection slave;
+--disable_warnings
+DROP TABLE IF EXISTS federated.t1;
+DROP DATABASE IF EXISTS federated;
+--enable_warnings
diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test
index 9ee6b5d76b8..62af9d4932b 100644
--- a/mysql-test/t/flush.test
+++ b/mysql-test/t/flush.test
@@ -37,7 +37,7 @@ connection con1;
select * from t1;
connection con2;
flush tables with read lock;
---error 1099;
+--error 1223
drop table t2;
connection con1;
send drop table t2;
diff --git a/mysql-test/t/flush_block_commit.test b/mysql-test/t/flush_block_commit.test
index 49d68d05fb6..29ef7b8a0b9 100644
--- a/mysql-test/t/flush_block_commit.test
+++ b/mysql-test/t/flush_block_commit.test
@@ -76,3 +76,24 @@ select * from t1;
show create database test;
drop table t1;
+
+# FLUSH TABLES WITH READ LOCK should block writes to binlog too
+connection con1;
+create table t1 (a int) engine=innodb;
+reset master;
+set autocommit=0;
+insert t1 values (1);
+connection con2;
+flush tables with read lock;
+show master status;
+connection con1;
+send commit;
+connection con2;
+sleep 1;
+show master status;
+unlock tables;
+connection con1;
+reap;
+drop table t1;
+set autocommit=1;
+
diff --git a/mysql-test/t/flush_read_lock_kill-master.opt b/mysql-test/t/flush_read_lock_kill-master.opt
new file mode 100644
index 00000000000..2b2b5eb5ebf
--- /dev/null
+++ b/mysql-test/t/flush_read_lock_kill-master.opt
@@ -0,0 +1 @@
+--loose-debug=d,make_global_read_lock_block_commit_loop
diff --git a/mysql-test/t/flush_read_lock_kill.test b/mysql-test/t/flush_read_lock_kill.test
new file mode 100644
index 00000000000..02384357711
--- /dev/null
+++ b/mysql-test/t/flush_read_lock_kill.test
@@ -0,0 +1,49 @@
+# Let's see if FLUSH TABLES WITH READ LOCK can be killed when waiting
+# for running commits to finish (in the past it could not)
+# This will not be a meaningful test on non-debug servers so will be
+# skipped.
+# If running mysql-test-run --debug, the --debug added by
+# mysql-test-run to the mysqld command line will override the one of
+# -master.opt. But this test is designed to still pass then (though it
+# won't test anything interesting).
+
+# This also won't work with the embedded server test
+-- source include/not_embedded.inc
+
+-- source include/have_debug.inc
+
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+connection con1;
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (kill_id int);
+insert into t1 values(connection_id());
+
+# Thanks to the parameter we passed to --debug, this FLUSH will
+# block on a debug build running with our --debug=make_global... It
+# will block until killed. In other cases (non-debug build or other
+# --debug) it will succeed immediately
+
+connection con1;
+send flush tables with read lock;
+
+# kill con1
+connection con2;
+select ((@id := kill_id) - kill_id) from t1;
+
+--sleep 2; # leave time for FLUSH to block
+kill connection @id;
+
+connection con1;
+# On debug builds it will be error 1053 (killed); on non-debug, or
+# debug build running without our --debug=make_global..., will be
+# error 0 (no error). The only important thing to test is that on
+# debug builds with our --debug=make_global... we don't hang forever.
+--error 0,1053
+reap;
+
+connection con2;
+drop table t1;
diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test
index 4809f6f0357..2acf69dad76 100644
--- a/mysql-test/t/fulltext.test
+++ b/mysql-test/t/fulltext.test
@@ -59,6 +59,7 @@ select * from t1 where MATCH a,b AGAINST ("+call* +coll*" IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"support now"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"Now sUPPort"' IN BOOLEAN MODE);
+select * from t1 where MATCH a,b AGAINST ('"now support"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"text search" "now support"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"text search" -"now support"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"text search" +"now support"' IN BOOLEAN MODE);
@@ -68,7 +69,6 @@ select * from t1 where MATCH a,b AGAINST ('"xt indexes"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('+(support collections) +foobar*' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('+(+(support collections)) +foobar*' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('+collections -supp* -foobar*' IN BOOLEAN MODE);
-select * from t1 where MATCH a,b AGAINST ('"xt indexes"' IN BOOLEAN MODE);
# bug#2708, bug#3870 crash
diff --git a/mysql-test/t/func_compress.test b/mysql-test/t/func_compress.test
index f46589e9e0e..9c32313e967 100644
--- a/mysql-test/t/func_compress.test
+++ b/mysql-test/t/func_compress.test
@@ -2,6 +2,8 @@
#
# Test for compress and uncompress functions:
#
+# Note that this test gives error in the gzip library when running under
+# valgrind, but these warnings can be ignored
select @test_compress_string:='string for test compress function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ';
select length(@test_compress_string);
diff --git a/mysql-test/t/func_concat.test b/mysql-test/t/func_concat.test
index b94901e9966..4f13ce7513c 100644
--- a/mysql-test/t/func_concat.test
+++ b/mysql-test/t/func_concat.test
@@ -46,7 +46,9 @@ select 'a' union select concat('a', -'3');
select 'a' union select concat('a', -concat('3',4));
select 'a' union select concat('a', -0);
-
---replace_result 'a-0.0' good 'a0.0' good
+--replace_result a-0.0 a0.0
select 'a' union select concat('a', -0.0);
+--replace_result a-0.0000 a0.0000
+select 'a' union select concat('a', -0.0000);
+
diff --git a/mysql-test/t/func_equal.test b/mysql-test/t/func_equal.test
index cbf589ffcc2..f446e277c92 100644
--- a/mysql-test/t/func_equal.test
+++ b/mysql-test/t/func_equal.test
@@ -11,10 +11,12 @@ drop table if exists t1,t2;
# First some simple tests
#
-select 0<=>0,0.0<=>0.0,"A"<=>"A",NULL<=>NULL;
+select 0<=>0,0.0<=>0.0,0E0=0E0,"A"<=>"A",NULL<=>NULL;
select 1<=>0,0<=>NULL,NULL<=>0;
select 1.0<=>0.0,0.0<=>NULL,NULL<=>0.0;
select "A"<=>"B","A"<=>NULL,NULL<=>"A";
+select 0<=>0.0, 0.0<=>0E0, 0E0<=>"0", 10.0<=>1E1, 10<=>10.0, 10<=>1E1;
+select 1.0<=>0E1,10<=>NULL,NULL<=>0.0, NULL<=>0E0;
#
# Test with tables
diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test
index d32c8796075..694e0223753 100644
--- a/mysql-test/t/func_gconcat.test
+++ b/mysql-test/t/func_gconcat.test
@@ -286,9 +286,18 @@ SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL;
DROP TABLE t1;
#
+# Bug #6475
+#
+create table t1 (a char(3), b char(20), primary key (a, b));
+insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English');
+select group_concat(a) from t1 group by b;
+drop table t1;
+
+#
# Bug #8656: Crash with group_concat on alias in outer table
#
create table r2 (a int, b int);
insert into r2 values (1,1), (2,2);
select b x, (select group_concat(x) from r2) from r2;
drop table r2;
+
diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index 78e7d3c5ed6..9b6f91067d4 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -32,9 +32,7 @@ create table t2 (grp int, a bigint unsigned, c char(10));
insert into t2 select grp,max(a)+max(grp),max(c) from t1 group by grp;
# REPLACE ... SELECT doesn't yet work with PS
---disable_ps_protocol
replace into t2 select grp, a, c from t1 limit 2,1;
---enable_ps_protocol
select * from t2;
drop table t1,t2;
@@ -60,6 +58,11 @@ create table t2 (id int not null,rating int null);
insert into t1 values(1),(2),(3);
insert into t2 values(1, 3),(2, NULL),(2, NULL),(3, 2),(3, NULL);
select t1.id, avg(rating) from t1 left join t2 on ( t1.id = t2.id ) group by t1.id;
+# Test different types with avg()
+select sql_small_result t2.id, avg(rating) from t2 group by t2.id;
+select sql_big_result t2.id, avg(rating) from t2 group by t2.id;
+select sql_small_result t2.id, avg(rating+0.0e0) from t2 group by t2.id;
+select sql_big_result t2.id, avg(rating+0.0e0) from t2 group by t2.id;
drop table t1,t2;
#
@@ -216,6 +219,7 @@ insert into t1 values('GTM',3,'DAL',0.070,date'1977-09-23');
insert into t1 values('SSJ',null,'CHI',null,date'1974-03-19');
insert into t1 values('KKK',3,'ATL',null,null);
insert into t1 values('XXX',null,'MIN',null,null);
+insert into t1 values('WWW',1,'LED',null,null);
# Populate table t2
insert into t2 values('TKF','Seattle','WA','AME');
@@ -224,6 +228,7 @@ insert into t2 values('DEN','Denver','CO','BDL');
insert into t2 values('SDC','San Diego','CA','TWU');
insert into t2 values('NOL','New Orleans','LA','GTM');
insert into t2 values('LAK','Los Angeles','CA','TWU');
+insert into t2 values('AAA','AAA','AA','AME');
# Show the table contents
select * from t1;
@@ -390,8 +395,12 @@ create table t1 (a char character set latin2);
insert into t1 values ('a'),('b');
select charset(max(a)), coercibility(max(a)),
charset(min(a)), coercibility(min(a)) from t1;
+show create table t1;
create table t2 select max(a),min(a) from t1;
show create table t2;
+drop table t2;
+create table t2 select concat(a) from t1;
+show create table t2;
drop table t2,t1;
#
@@ -497,6 +506,62 @@ create table t2 select f2 from (select now() f2 from t1) a;
show columns from t2;
drop table t2, t1;
+# decimal-related tests
+create table t2 (ff double);
+insert into t2 values (2.2);
+select cast(sum(distinct ff) as decimal(5,2)) from t2;
+select cast(sum(distinct ff) as signed) from t2;
+select cast(variance(ff) as decimal(10,3)) from t2;
+select cast(min(ff) as decimal(5,2)) from t2;
+
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+select cast(sum(distinct df) as signed) from t1;
+select cast(min(df) as signed) from t1;
+select 1e8 * sum(distinct df) from t1;
+select 1e8 * min(df) from t1;
+
+create table t3 (ifl int);
+insert into t3 values(1), (2);
+select cast(min(ifl) as decimal(5,2)) from t3;
+
+drop table t1, t2, t3;
+
+
+#
+# BUG#3190, WL#1639: Standard Deviation STDDEV - 2 different calculations
+#
+
+CREATE TABLE t1 (id int(11),value1 float(10,2));
+INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00), (2,13.00);
+select id, stddev_pop(value1), var_pop(value1), stddev_samp(value1), var_samp(value1) from t1 group by id;
+DROP TABLE t1;
+
+#
+# BUG#8464 decimal AVG returns incorrect result
+#
+
+CREATE TABLE t1 (col1 decimal(16,12));
+INSERT INTO t1 VALUES (-5.00000000001),(-5.00000000002),(-5.00000000003),(-5.00000000000),(-5.00000000001),(-5.00000000002);
+insert into t1 select * from t1;
+select col1,count(col1),sum(col1),avg(col1) from t1 group by col1;
+DROP TABLE t1;
+
+#
+# BUG#8465 decimal MIN and MAX return incorrect result
+#
+
+create table t1 (col1 decimal(16,12));
+insert into t1 values (-5.00000000001);
+insert into t1 values (-5.00000000001);
+select col1,sum(col1),max(col1),min(col1) from t1 group by col1;
+delete from t1;
+insert into t1 values (5.00000000001);
+insert into t1 values (5.00000000001);
+select col1,sum(col1),max(col1),min(col1) from t1 group by col1;
+DROP TABLE t1;
+
#
# Bug 8893: wrong result for min/max optimization with 2 indexes
#
@@ -526,3 +591,36 @@ INSERT INTO t1 VALUES
(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1);
SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
DROP TABLE t1;
+
+#
+# Test that new VARCHAR correctly works with COUNT(DISTINCT)
+#
+
+CREATE TABLE t1 (a VARCHAR(400));
+INSERT INTO t1 (a) VALUES ("A"), ("a"), ("a "), ("a "),
+ ("B"), ("b"), ("b "), ("b ");
+SELECT COUNT(DISTINCT a) FROM t1;
+DROP TABLE t1;
+
+#
+# Test for buf #9210: GROUP BY with expression if a decimal type
+#
+
+CREATE TABLE t1 (a int, b int, c int);
+INSERT INTO t1 (a, b, c) VALUES
+ (1,1,1), (1,1,2), (1,1,3),
+ (1,2,1), (1,2,2), (1,2,3),
+ (1,3,1), (1,3,2), (1,3,3),
+ (2,1,1), (2,1,2), (2,1,3),
+ (2,2,1), (2,2,2), (2,2,3),
+ (2,3,1), (2,3,2), (2,3,3),
+ (3,1,1), (3,1,2), (3,1,3),
+ (3,2,1), (3,2,2), (3,2,3),
+ (3,3,1), (3,3,2), (3,3,3);
+
+SELECT b/c as v, a FROM t1 ORDER BY v;
+SELECT b/c as v, SUM(a) FROM t1 GROUP BY v;
+SELECT SUM(a) FROM t1 GROUP BY b/c;
+
+DROP TABLE t1;
+
diff --git a/mysql-test/t/func_if.test b/mysql-test/t/func_if.test
index 693773b18c8..a2ea26390ca 100644
--- a/mysql-test/t/func_if.test
+++ b/mysql-test/t/func_if.test
@@ -25,9 +25,10 @@ explain extended select if(u=1,st,binary st) s from t1 where st like "%a%" order
#
# NULLIF test
#
-select nullif(u=0, 'test') from t1;
-explain extended select nullif(u=0, 'test') from t1;
+select nullif(u, 1) from t1;
+explain extended select nullif(u, 1) from t1;
drop table t1;
+select nullif(1,'test');
#
# Bug 2629
diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test
index 4c24dae8c5d..33b672e42b5 100644
--- a/mysql-test/t/func_math.test
+++ b/mysql-test/t/func_math.test
@@ -62,12 +62,3 @@ explain extended select degrees(pi()),radians(360);
--error 1054
select rand(rand);
-
-#
-# Bug #9837: problem with round()
-#
-
-create table t1 select round(1, 6);
-show create table t1;
-select * from t1;
-drop table t1;
diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test
index da3affaa36d..bb9159eefbe 100644
--- a/mysql-test/t/func_sapdb.test
+++ b/mysql-test/t/func_sapdb.test
@@ -30,10 +30,16 @@ select adddate("1997-12-31 23:59:59.000001", 10);
select subdate("1997-12-31 23:59:59.000001", 10);
select datediff("1997-12-31 23:59:59.000001","1997-12-30");
+select datediff("1997-11-30 23:59:59.000001","1997-12-31");
+SET @@SQL_MODE="ALLOW_INVALID_DATES";
select datediff("1997-11-31 23:59:59.000001","1997-12-31");
-select datediff("1997-11-31 23:59:59.000001",null);
+SET @@SQL_MODE="";
-select weekofyear("1997-11-31 23:59:59.000001");
+-- This will give a warning
+select datediff("1997-11-31 23:59:59.000001","1997-12-31");
+select datediff("1997-11-30 23:59:59.000001",null);
+
+select weekofyear("1997-11-30 23:59:59.000001");
select makedate(1997,1);
select makedate(1997,0);
@@ -108,7 +114,8 @@ insert into test values
SELECT ADDTIME(t1,t2) As ttt, ADDTIME(t2, t3) As qqq from test;
# PS doesn't support fractional seconds
--disable_ps_protocol
-SELECT TIMEDIFF(t1,t4) As ttt, TIMEDIFF(t2, t3) As qqq from test;
+SELECT TIMEDIFF(t1, t4) As ttt, TIMEDIFF(t2, t3) As qqq,
+ TIMEDIFF(t3, t2) As eee, TIMEDIFF(t2, t4) As rrr from test;
--enable_ps_protocol
drop table t1, test;
diff --git a/mysql-test/t/func_set.test b/mysql-test/t/func_set.test
index 98ef1e07bfe..0c79dec7cc2 100644
--- a/mysql-test/t/func_set.test
+++ b/mysql-test/t/func_set.test
@@ -18,6 +18,8 @@ select export_set(9,"Y","N","-",5),export_set(9,"Y","N"),export_set(9,"Y","N",""
# Wrong usage of functions
#
select elt(2,1),field(NULL,"a","b","c");
+select field("b","a",NULL),field(1,0,NULL)+0,field(1.0,0.0,NULL)+0.0,field(1.0e1,0.0e1,NULL)+0.0e1;
+select field(NULL,"a",NULL),field(NULL,0,NULL)+0,field(NULL,0.0,NULL)+0.0,field(NULL,0.0e1,NULL)+0.0e1;
select find_in_set("","a,b,c"),find_in_set("","a,b,c,"),find_in_set("",",a,b,c");
select find_in_set("abc","abc"),find_in_set("ab","abc"),find_in_set("abcd","abc");
select interval(null, 1, 10, 100);
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index 22028437111..b3c875f7bf5 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -3,7 +3,7 @@
# Testing string functions
--disable_warnings
-drop table if exists t1;
+drop table if exists t1,t2;
--enable_warnings
set names latin1;
@@ -25,6 +25,7 @@ select substring_index('www.tcx.se','tcx',1),substring_index('www.tcx.se','tcx',
select substring_index('.tcx.se','.',-2),substring_index('.tcx.se','.tcx',-1);
select concat(':',ltrim(' left '),':',rtrim(' right '),':');
+select concat(':',trim(leading from ' left '),':',trim(trailing from ' right '),':');
select concat(':',trim(LEADING FROM ' left'),':',trim(TRAILING FROM ' right '),':');
select concat(':',trim(' m '),':',trim(BOTH FROM ' y '),':',trim('*' FROM '*s*'),':');
select concat(':',trim(BOTH 'ab' FROM 'ababmyabab'),':',trim(BOTH '*' FROM '***sql'),':');
@@ -243,7 +244,7 @@ select FIELD('b','A' COLLATE latin1_bin,'B');
select FIELD(_latin2'b','A','B');
--error 1270
select FIELD('b',_latin2'A','B');
-select FIELD('b',_latin2'A','B',1);
+select FIELD('1',_latin2'3','2',1);
select POSITION(_latin1'B' IN _latin1'abcd');
select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin);
@@ -472,6 +473,8 @@ drop table t1;
#
select trim(null from 'kate') as "must_be_null";
select trim('xyz' from null) as "must_be_null";
+select trim(leading NULL from 'kate') as "must_be_null";
+select trim(trailing NULL from 'xyz') as "must_be_null";
#
# Bug #7751 - conversion for a bigint unsigned constant
@@ -520,4 +523,3 @@ SELECT t1.id, aes_decrypt(str, 'bar') FROM t1, t2 WHERE t1.id = t2.id
ORDER BY t1.id;
DROP TABLE t1, t2;
-
diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test
index eb506a58870..732cdc12cae 100644
--- a/mysql-test/t/func_test.test
+++ b/mysql-test/t/func_test.test
@@ -107,3 +107,12 @@ select 5.1 mod 3, 5.1 mod -3, -5.1 mod 3, -5.1 mod -3;
#
select 5 mod 3, 5 mod -3, -5 mod 3, -5 mod -3;
+
+#
+# Bug#6726: NOT BETWEEN parse failure
+#
+create table t1 (a int, b int);
+insert into t1 values (1,2), (2,3), (3,4), (4,5);
+select * from t1 where a not between 1 and 2;
+select * from t1 where a not between 1 and 2 and b not between 3 and 4;
+drop table t1;
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 0f495ef891d..80ddb205110 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -266,6 +266,33 @@ select date_add(date,INTERVAL "1 1" YEAR_MONTH) from t1;
select date_add(date,INTERVAL "1:1:1" HOUR_SECOND) from t1;
select date_add(date,INTERVAL "1 1:1" DAY_MINUTE) from t1;
select date_add(date,INTERVAL "1 1:1:1" DAY_SECOND) from t1;
+select date_add(date,INTERVAL "1" WEEK) from t1;
+select date_add(date,INTERVAL "1" QUARTER) from t1;
+select timestampadd(MINUTE, 1, date) from t1;
+select timestampadd(WEEK, 1, date) from t1;
+select timestampadd(SQL_TSI_SECOND, 1, date) from t1;
+# Prepared statements doesn't support FRAC_SECOND yet
+--disable_ps_protocol
+select timestampadd(SQL_TSI_FRAC_SECOND, 1, date) from t1;
+--enable_ps_protocol
+
+select timestampdiff(MONTH, '2001-02-01', '2001-05-01') as a;
+select timestampdiff(YEAR, '2002-05-01', '2001-01-01') as a;
+select timestampdiff(QUARTER, '2002-05-01', '2001-01-01') as a;
+select timestampdiff(MONTH, '2000-03-28', '2000-02-29') as a;
+select timestampdiff(MONTH, '1991-03-28', '2000-02-29') as a;
+select timestampdiff(SQL_TSI_WEEK, '2001-02-01', '2001-05-01') as a;
+select timestampdiff(SQL_TSI_HOUR, '2001-02-01', '2001-05-01') as a;
+select timestampdiff(SQL_TSI_DAY, '2001-02-01', '2001-05-01') as a;
+select timestampdiff(SQL_TSI_MINUTE, '2001-02-01 12:59:59', '2001-05-01 12:58:59') as a;
+select timestampdiff(SQL_TSI_SECOND, '2001-02-01 12:59:59', '2001-05-01 12:58:58') as a;
+select timestampdiff(SQL_TSI_FRAC_SECOND, '2001-02-01 12:59:59.120000', '2001-05-01 12:58:58.119999') as a;
+
+select timestampdiff(SQL_TSI_DAY, '1986-02-01', '1986-03-01') as a1,
+ timestampdiff(SQL_TSI_DAY, '1900-02-01', '1900-03-01') as a2,
+ timestampdiff(SQL_TSI_DAY, '1996-02-01', '1996-03-01') as a3,
+ timestampdiff(SQL_TSI_DAY, '2000-02-01', '2000-03-01') as a4;
+
select date_add(time,INTERVAL 1 SECOND) from t1;
drop table t1;
@@ -307,3 +334,5 @@ INSERT INTO t1 VALUES (NOW());
SELECT count(*) FROM t1 WHERE d>FROM_DAYS(TO_DAYS(@TMP)) AND d<=FROM_DAYS(TO_DAYS(@TMP)+1);
DROP TABLE t1;
+explain extended select timestampdiff(SQL_TSI_WEEK, '2001-02-01', '2001-05-01') as a1,
+ timestampdiff(SQL_TSI_FRAC_SECOND, '2001-02-01 12:59:59.120000', '2001-05-01 12:58:58.119999') as a2;
diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test
index 716dd38a119..522f7a6f637 100644
--- a/mysql-test/t/gis-rtree.test
+++ b/mysql-test/t/gis-rtree.test
@@ -120,7 +120,6 @@ INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('
drop table t1;
CREATE TABLE t1 (
- geoobjid INT NOT NULL,
line LINESTRING NOT NULL,
kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
name VARCHAR(32),
@@ -169,6 +168,6 @@ drop table t1;
CREATE TABLE t1 (st varchar(100));
INSERT INTO t1 VALUES ("Fake string");
CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom));
---error 1105
+--error 1416
INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
drop table t1, t2;
diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test
index 86c34eacbc5..b7071019e9d 100644
--- a/mysql-test/t/gis.test
+++ b/mysql-test/t/gis.test
@@ -165,9 +165,9 @@ explain extended select issimple(MultiPoint(Point(3, 6), Point(4, 10))), issimpl
create table t1 (a geometry not null);
insert into t1 values (GeomFromText('Point(1 2)'));
--- error 1105
+-- error 1416
insert into t1 values ('Garbage');
--- error 1105
+-- error 1416
insert IGNORE into t1 values ('Garbage');
alter table t1 add spatial index(a);
@@ -359,3 +359,15 @@ select object_id, geometrytype(geo), ISSIMPLE(GEO), ASTEXT(centroid(geo)) from
t1 where object_id=85984;
drop table t1;
+
+create table t1 (fl geometry);
+--error 1416
+insert into t1 values (1);
+--error 1416
+insert into t1 values (1.11);
+--error 1416
+insert into t1 values ("qwerty");
+--error 1416
+insert into t1 values (pointfromtext('point(1,1)'));
+
+drop table t1;
diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test
index 1c8fbe0ff0d..34d9a09cba7 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -184,16 +184,18 @@ grant select(a) on test.t1 to drop_user1@localhost;
grant select on test.t1 to drop_user2@localhost;
grant select on test.* to drop_user3@localhost;
grant select on *.* to drop_user4@localhost;
---error 1268
+# Drop user now implicitly revokes all privileges.
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
+--error 1269
revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost,
drop_user3@localhost, drop_user4@localhost;
+--error 1396
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
drop table t1;
grant usage on *.* to mysqltest_1@localhost identified by "password";
-grant select, update, insert on test.* to mysqltest@localhost;
+grant select, update, insert on test.* to mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
drop user mysqltest_1@localhost;
@@ -217,6 +219,9 @@ GRANT SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ TO ÀÚÅÒ@localhost;
SHOW GRANTS FOR ÀÚÅÒ@localhost;
REVOKE SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ FROM ÀÚÅÒ@localhost;
+# Revoke does not drop user. Leave a clean user table for the next tests.
+DROP USER ÀÚÅÒ@localhost;
+
DROP DATABASE ÂÄ;
SET NAMES latin1;
@@ -324,8 +329,10 @@ show grants for mysqltest_3@localhost;
--error 1143
update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1;
--error 1143
+update mysqltest_1.t2, mysqltest_2.t2 set d=20 where d=1;
+--error 1142
update mysqltest_1.t1, mysqltest_2.t2 set d=20 where d=1;
---error 1143
+--error 1142
update mysqltest_2.t1, mysqltest_1.t2 set c=20 where b=1;
--error 1143
update mysqltest_2.t1, mysqltest_2.t2 set d=10 where s=2;
@@ -350,15 +357,15 @@ connection conn2;
use mysqltest_1;
update mysqltest_2.t1, mysqltest_2.t2 set c=500,d=600;
# the following failed before, should fail now.
---error 1143
+--error 1142
update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200;
use mysqltest_2;
#the following used to succeed, it must fail now.
---error 1044
+--error 1142
update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200;
---error 1044
+--error 1142
update mysqltest_2.t1, mysqltest_1.t2 set c=100,b=200;
---error 1044
+--error 1142
update mysqltest_1.t1, mysqltest_2.t2 set a=100,d=200;
#lets see the result
connection master;
@@ -374,6 +381,11 @@ drop database mysqltest_1;
drop database mysqltest_2;
#
+# just SHOW PRIVILEGES test
+#
+SHOW PRIVILEGES;
+
+#
# Rights for renaming test (Bug #3270)
#
connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
@@ -391,4 +403,3 @@ connection root;
revoke all privileges on mysqltest.t1 from mysqltest_1@localhost;
delete from mysql.user where user=_binary'mysqltest_1';
drop database mysqltest;
-
diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test
index 362efc1230d..07bd6d53c4e 100644
--- a/mysql-test/t/grant2.test
+++ b/mysql-test/t/grant2.test
@@ -21,17 +21,61 @@ delete from mysql.columns_priv where user like 'mysqltest\_%';
flush privileges;
+grant all privileges on `my\_1`.* to mysqltest_1@localhost with grant option;
+grant create user on *.* to mysqltest_1@localhost;
+create user mysqltest_2@localhost;
+connect (user_a,localhost,mysqltest_1,,);
+connection user_a;
+grant select on `my\_1`.* to mysqltest_2@localhost;
+--error 1132
+grant select on `my\_1`.* to mysqltest_2@localhost identified by 'pass';
+disconnect user_a;
+connection default;
+grant update on mysql.* to mysqltest_1@localhost;
+connect (user_b,localhost,mysqltest_1,,);
+connection user_b;
+grant select on `my\_1`.* to mysqltest_2@localhost identified by 'pass';
+grant select on `my\_1`.* to mysqltest_3@localhost;
+disconnect user_b;
+connection default;
+grant insert on mysql.* to mysqltest_1@localhost;
+connect (user_c,localhost,mysqltest_1,,);
+connection user_c;
+grant select on `my\_1`.* to mysqltest_3@localhost;
+grant select on `my\_1`.* to mysqltest_4@localhost identified by 'pass';
+disconnect user_c;
+connection default;
+delete from mysql.user where user like 'mysqltest\_%';
+delete from mysql.db where user like 'mysqltest\_%';
+delete from mysql.tables_priv where user like 'mysqltest\_%';
+delete from mysql.columns_priv where user like 'mysqltest\_%';
+flush privileges;
+
#
# wild_compare fun
#
grant all privileges on `my\_%`.* to mysqltest_1@localhost with grant option;
+grant create user on *.* to mysqltest_1@localhost;
connect (user1,localhost,mysqltest_1,,);
connection user1;
select current_user();
grant all privileges on `my\_1`.* to mysqltest_2@localhost with grant option;
--error 1044
grant all privileges on `my_%`.* to mysqltest_3@localhost with grant option;
+
+#
+# NO_AUTO_CREATE_USER mode
+#
+set @@sql_mode='NO_AUTO_CREATE_USER';
+select @@sql_mode;
+#
+# GRANT without IDENTIFIED BY does not create new users
+#
+--error 1133
+grant select on `my\_1`.* to mysqltest_4@localhost with grant option;
+grant select on `my\_1`.* to mysqltest_4@localhost identified by 'mypass'
+with grant option;
disconnect user1;
connection default;
show grants for mysqltest_1@localhost;
@@ -75,10 +119,10 @@ connect (mrbad, localhost, mysqltest_1,,mysqltest);
connection mrbad;
show grants for current_user();
insert into t1 values (1, 'I can''t change it!');
---error 1044
+--error 1142
update t1 set data='I can change it!' where id = 1;
# This should not be allowed since it too require UPDATE privilege.
---error 1044
+--error 1142
insert into t1 values (1, 'XXX') on duplicate key update data= 'I can change it!';
select * from t1;
disconnect mrbad;
@@ -88,7 +132,8 @@ drop table t1;
delete from mysql.user where user like 'mysqltest\_%';
delete from mysql.db where user like 'mysqltest\_%';
flush privileges;
-
+#
+#
create table t1 (a int, b int);
grant select (a) on t1 to mysqltest_1@localhost with grant option;
connect (mrugly, localhost, mysqltest_1,,mysqltest);
@@ -110,7 +155,150 @@ flush privileges;
drop database mysqltest;
use test;
+#
+# Create and drop user
+#
+set sql_mode='maxdb';
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+create table t1(c1 int);
+create table t2(c1 int, c2 int);
+#
+# Three forms of CREATE USER
+create user 'mysqltest_1';
+--error 1396
+create user 'mysqltest_1';
+create user 'mysqltest_2' identified by 'Mysqltest-2';
+create user 'mysqltest_3' identified by password 'fffffffffffffffffffffffffffffffffffffffff';
+grant select on *.* to 'mysqltest_2';
+grant insert on test.* to 'mysqltest_2';
+grant update on test.t1 to 'mysqltest_2';
+grant update (c2) on test.t2 to 'mysqltest_2';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+show grants for 'mysqltest_1';
+show grants for 'mysqltest_2';
+#
+# Drop
+drop user 'mysqltest_1';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+--error 1141
+show grants for 'mysqltest_1';
+#
+# Rename
+rename user 'mysqltest_2' to 'mysqltest_1';
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+select host,db,user from mysql.db where user like 'mysqltest_%' order by host,db,user;
+select host,db,user,table_name from mysql.tables_priv where user like 'mysqltest_%' order by host,db,user,table_name;
+select host,db,user,table_name,column_name from mysql.columns_priv where user like 'mysqltest_%' order by host,db,user,table_name,column_name;
+show grants for 'mysqltest_1';
+drop user 'mysqltest_1', 'mysqltest_3';
+--error 1396
+drop user 'mysqltest_1';
+#
+# Cleanup
+drop table t1, t2;
+#
+# Add a stray record
+insert into mysql.db set user='mysqltest_1', db='%', host='%';
+flush privileges;
+--error 1141
+show grants for 'mysqltest_1';
+--error 1269
+revoke all privileges, grant option from 'mysqltest_1';
+drop user 'mysqltest_1';
+select host,db,user from mysql.db where user = 'mysqltest_1' order by host,db,user;
+#
+# Add a stray record
+insert into mysql.tables_priv set host='%', db='test', user='mysqltest_1', table_name='t1';
+flush privileges;
+--error 1141
+show grants for 'mysqltest_1';
+drop user 'mysqltest_1';
+select host,db,user,table_name from mysql.tables_priv where user = 'mysqltest_1' order by host,db,user,table_name;
+#
+# Add a stray record
+insert into mysql.columns_priv set host='%', db='test', user='mysqltest_1', table_name='t1', column_name='c1';
+flush privileges;
+--error 1141
+show grants for 'mysqltest_1';
+drop user 'mysqltest_1';
+select host,db,user,table_name,column_name from mysql.columns_priv where user = 'mysqltest_1' order by host,db,user,table_name,column_name;
+#
+# Handle multi user lists
+create user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+create user 'mysqltest_1', 'mysqltest_2' identified by 'Mysqltest-2', 'mysqltest_3' identified by password 'fffffffffffffffffffffffffffffffffffffffff';
+rename user 'mysqltest_1' to 'mysqltest_1a', 'mysqltest_2' TO 'mysqltest_2a', 'mysqltest_3' TO 'mysqltest_3a';
+--error 1396
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+drop user 'mysqltest_1a', 'mysqltest_2a', 'mysqltest_3a';
+#
+# Let one of multiple users fail
+create user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+--error 1396
+create user 'mysqltest_1a', 'mysqltest_2', 'mysqltest_3a';
+--error 1396
+rename user 'mysqltest_1a' to 'mysqltest_1b', 'mysqltest_2a' TO 'mysqltest_2b', 'mysqltest_3a' TO 'mysqltest_3b';
+drop user 'mysqltest_1', 'mysqltest_2', 'mysqltest_3';
+--error 1396
+drop user 'mysqltest_1b', 'mysqltest_2b', 'mysqltest_3b';
+#
+# Obsolete syntax has been dropped
+create user 'mysqltest_2' identified by 'Mysqltest-2';
+--error 1064
+drop user 'mysqltest_2' identified by 'Mysqltest-2';
+#
+# Strange user names
+create user '%@b'@'b';
+show grants for '%@b'@'b';
+grant select on mysql.* to '%@b'@'b';
+show grants for '%@b'@'b';
+rename user '%@b'@'b' to '%@a'@'a';
+--error 1141
+show grants for '%@b'@'b';
+show grants for '%@a'@'a';
+drop user '%@a'@'a';
+#
+# CREATE USER privilege is enough
+#
+create user mysqltest_2@localhost;
+grant create user on *.* to mysqltest_2@localhost;
+connect (user3,localhost,mysqltest_2,,);
+connection user3;
+--error 1142
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+create user mysqltest_A@'%';
+rename user mysqltest_A@'%' to mysqltest_B@'%';
+drop user mysqltest_B@'%';
+disconnect user3;
+connection default;
+drop user mysqltest_2@localhost;
+#
+# INSERT/UPDATE/DELETE is ok too
+create user mysqltest_3@localhost;
+grant INSERT,DELETE,UPDATE on mysql.* to mysqltest_3@localhost;
+connect (user4,localhost,mysqltest_3,,);
+connection user4;
+show grants;
+--error 1142
+select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password;
+insert into mysql.user set host='%', user='mysqltest_B';
+create user mysqltest_A@'%';
+rename user mysqltest_B@'%' to mysqltest_C@'%';
+drop user mysqltest_C@'%';
+disconnect user4;
+connection default;
+drop user mysqltest_3@localhost;
+#
# Bug #3309: Test IP addresses with netmask
+set @@sql_mode='';
create database mysqltest_1;
create table mysqltest_1.t1 (i int);
insert into mysqltest_1.t1 values (1),(2),(3);
diff --git a/mysql-test/t/grant3-master.opt b/mysql-test/t/grant3-master.opt
new file mode 100644
index 00000000000..4b11f5902c1
--- /dev/null
+++ b/mysql-test/t/grant3-master.opt
@@ -0,0 +1 @@
+--safe-user-create
diff --git a/mysql-test/t/grant3.test b/mysql-test/t/grant3.test
new file mode 100644
index 00000000000..115586e807d
--- /dev/null
+++ b/mysql-test/t/grant3.test
@@ -0,0 +1,36 @@
+# Can't run with embedded server
+-- source include/not_embedded.inc
+
+# Test of GRANT commands
+
+SET NAMES binary;
+connect (master,localhost,root,,);
+connection master;
+
+# Cleanup
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+delete from mysql.user where user like 'mysqltest\_%';
+delete from mysql.db where user like 'mysqltest\_%';
+delete from mysql.tables_priv where user like 'mysqltest\_%';
+delete from mysql.columns_priv where user like 'mysqltest\_%';
+flush privileges;
+
+create user mysqltest_1@localhost;
+grant create user on *.* to mysqltest_1@localhost;
+grant select on `my\_1`.* to mysqltest_1@localhost with grant option;
+connect (user_a,localhost,mysqltest_1,,);
+connection user_a;
+--error 1410
+grant select on `my\_1`.* to mysqltest_2@localhost;
+create user mysqltest_2@localhost;
+disconnect user_a;
+connection default;
+
+delete from mysql.user where user like 'mysqltest\_%';
+delete from mysql.db where user like 'mysqltest\_%';
+delete from mysql.tables_priv where user like 'mysqltest\_%';
+delete from mysql.columns_priv where user like 'mysqltest\_%';
+flush privileges;
diff --git a/mysql-test/t/grant_cache.test b/mysql-test/t/grant_cache.test
index 7d6f7262f0a..1e24d5c9c03 100644
--- a/mysql-test/t/grant_cache.test
+++ b/mysql-test/t/grant_cache.test
@@ -12,7 +12,7 @@ drop database if exists mysqltest;
reset query cache;
flush status;
-connect (root,localhost,root,,test,$MASTER_MYPORT,master.sock);
+connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
connection root;
show grants for current_user;
show grants;
@@ -27,7 +27,7 @@ insert into mysqltest.t2 values (3,3,3);
create table test.t1 (a char (10));
insert into test.t1 values ("test.t1");
select * from t1;
-connect (root2,localhost,root,,mysqltest,$MASTER_MYPORT,master.sock);
+connect (root2,localhost,root,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK);
connection root2;
# put queries in cache
select * from t1;
@@ -45,7 +45,7 @@ grant SELECT on test.t1 to mysqltest_2@localhost;
grant SELECT(a) on mysqltest.t1 to mysqltest_3@localhost;
# The following queries should be fetched from cache
-connect (user1,localhost,mysqltest_1,,mysqltest,$MASTER_MYPORT,master.sock);
+connect (user1,localhost,mysqltest_1,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK);
connection user1;
show grants for current_user();
show status like "Qcache_queries_in_cache";
@@ -70,12 +70,12 @@ show status like "Qcache_hits";
show status like "Qcache_not_cached";
# Don't use '' as user because it will pick Unix login
-connect (unkuser,localhost,unkuser,,,$MASTER_MYPORT,master.sock);
+connect (unkuser,localhost,unkuser,,,$MASTER_MYPORT,$MASTER_MYSOCK);
connection unkuser;
show grants for current_user();
# The following queries should be fetched from cache
-connect (user2,localhost,mysqltest_2,,mysqltest,$MASTER_MYPORT,master.sock);
+connect (user2,localhost,mysqltest_2,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK);
connection user2;
select "user2";
select * from t1;
@@ -90,7 +90,7 @@ show status like "Qcache_hits";
show status like "Qcache_not_cached";
# The following queries should not be fetched from cache
-connect (user3,localhost,mysqltest_3,,mysqltest,$MASTER_MYPORT,master.sock);
+connect (user3,localhost,mysqltest_3,,mysqltest,$MASTER_MYPORT,$MASTER_MYSOCK);
connection user3;
select "user3";
--replace_result 127.0.0.1 localhost
@@ -111,7 +111,7 @@ show status like "Qcache_hits";
show status like "Qcache_not_cached";
# Connect without a database
-connect (user4,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,master.sock);
+connect (user4,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,$MASTER_MYSOCK);
connection user4;
select "user4";
show grants;
diff --git a/mysql-test/t/greedy_optimizer.test b/mysql-test/t/greedy_optimizer.test
new file mode 100644
index 00000000000..e547d85b7f3
--- /dev/null
+++ b/mysql-test/t/greedy_optimizer.test
@@ -0,0 +1,313 @@
+#
+# A simple test of the greedy query optimization algorithm and the switches that
+# control the optimizationprocess.
+#
+
+#
+# Schema
+#
+--disable_warnings
+drop table if exists t1,t2,t3,t4,t5,t6,t7;
+--enable_warnings
+
+create table t1 (
+ c11 integer,c12 integer,c13 integer,c14 integer,c15 integer,c16 integer,
+ primary key (c11)
+);
+create table t2 (
+ c21 integer,c22 integer,c23 integer,c24 integer,c25 integer,c26 integer
+);
+create table t3 (
+ c31 integer,c32 integer,c33 integer,c34 integer,c35 integer,c36 integer,
+ primary key (c31)
+);
+create table t4 (
+ c41 integer,c42 integer,c43 integer,c44 integer,c45 integer,c46 integer
+);
+create table t5 (
+ c51 integer,c52 integer,c53 integer,c54 integer,c55 integer,c56 integer,
+ primary key (c51)
+);
+create table t6 (
+ c61 integer,c62 integer,c63 integer,c64 integer,c65 integer,c66 integer
+);
+create table t7 (
+ c71 integer,c72 integer,c73 integer,c74 integer,c75 integer,c76 integer,
+ primary key (c71)
+);
+
+#
+# Data
+# cardinality(Ti) = cardinality(T(i-1)) + 3
+#
+insert into t1 values (1,2,3,4,5,6);
+insert into t1 values (2,2,3,4,5,6);
+insert into t1 values (3,2,3,4,5,6);
+
+insert into t2 values (1,2,3,4,5,6);
+insert into t2 values (2,2,3,4,5,6);
+insert into t2 values (3,2,3,4,5,6);
+insert into t2 values (4,2,3,4,5,6);
+insert into t2 values (5,2,3,4,5,6);
+insert into t2 values (6,2,3,4,5,6);
+
+insert into t3 values (1,2,3,4,5,6);
+insert into t3 values (2,2,3,4,5,6);
+insert into t3 values (3,2,3,4,5,6);
+insert into t3 values (4,2,3,4,5,6);
+insert into t3 values (5,2,3,4,5,6);
+insert into t3 values (6,2,3,4,5,6);
+insert into t3 values (7,2,3,4,5,6);
+insert into t3 values (8,2,3,4,5,6);
+insert into t3 values (9,2,3,4,5,6);
+
+insert into t4 values (1,2,3,4,5,6);
+insert into t4 values (2,2,3,4,5,6);
+insert into t4 values (3,2,3,4,5,6);
+insert into t4 values (4,2,3,4,5,6);
+insert into t4 values (5,2,3,4,5,6);
+insert into t4 values (6,2,3,4,5,6);
+insert into t4 values (7,2,3,4,5,6);
+insert into t4 values (8,2,3,4,5,6);
+insert into t4 values (9,2,3,4,5,6);
+insert into t4 values (10,2,3,4,5,6);
+insert into t4 values (11,2,3,4,5,6);
+insert into t4 values (12,2,3,4,5,6);
+
+insert into t5 values (1,2,3,4,5,6);
+insert into t5 values (2,2,3,4,5,6);
+insert into t5 values (3,2,3,4,5,6);
+insert into t5 values (4,2,3,4,5,6);
+insert into t5 values (5,2,3,4,5,6);
+insert into t5 values (6,2,3,4,5,6);
+insert into t5 values (7,2,3,4,5,6);
+insert into t5 values (8,2,3,4,5,6);
+insert into t5 values (9,2,3,4,5,6);
+insert into t5 values (10,2,3,4,5,6);
+insert into t5 values (11,2,3,4,5,6);
+insert into t5 values (12,2,3,4,5,6);
+insert into t5 values (13,2,3,4,5,6);
+insert into t5 values (14,2,3,4,5,6);
+insert into t5 values (15,2,3,4,5,6);
+
+insert into t6 values (1,2,3,4,5,6);
+insert into t6 values (2,2,3,4,5,6);
+insert into t6 values (3,2,3,4,5,6);
+insert into t6 values (4,2,3,4,5,6);
+insert into t6 values (5,2,3,4,5,6);
+insert into t6 values (6,2,3,4,5,6);
+insert into t6 values (7,2,3,4,5,6);
+insert into t6 values (8,2,3,4,5,6);
+insert into t6 values (9,2,3,4,5,6);
+insert into t6 values (10,2,3,4,5,6);
+insert into t6 values (11,2,3,4,5,6);
+insert into t6 values (12,2,3,4,5,6);
+insert into t6 values (13,2,3,4,5,6);
+insert into t6 values (14,2,3,4,5,6);
+insert into t6 values (15,2,3,4,5,6);
+insert into t6 values (16,2,3,4,5,6);
+insert into t6 values (17,2,3,4,5,6);
+insert into t6 values (18,2,3,4,5,6);
+
+insert into t7 values (1,2,3,4,5,6);
+insert into t7 values (2,2,3,4,5,6);
+insert into t7 values (3,2,3,4,5,6);
+insert into t7 values (4,2,3,4,5,6);
+insert into t7 values (5,2,3,4,5,6);
+insert into t7 values (6,2,3,4,5,6);
+insert into t7 values (7,2,3,4,5,6);
+insert into t7 values (8,2,3,4,5,6);
+insert into t7 values (9,2,3,4,5,6);
+insert into t7 values (10,2,3,4,5,6);
+insert into t7 values (11,2,3,4,5,6);
+insert into t7 values (12,2,3,4,5,6);
+insert into t7 values (13,2,3,4,5,6);
+insert into t7 values (14,2,3,4,5,6);
+insert into t7 values (15,2,3,4,5,6);
+insert into t7 values (16,2,3,4,5,6);
+insert into t7 values (17,2,3,4,5,6);
+insert into t7 values (18,2,3,4,5,6);
+insert into t7 values (19,2,3,4,5,6);
+insert into t7 values (20,2,3,4,5,6);
+insert into t7 values (21,2,3,4,5,6);
+
+#
+# The actual test begins here
+#
+
+# Check the default values for the optimizer paramters
+
+select @@optimizer_search_depth;
+select @@optimizer_prune_level;
+
+-- This value swithes back to the old implementation of 'find_best()'
+-- set optimizer_search_depth=63; - old (independent of the optimizer_prune_level)
+--
+-- These are the values for the parameters that control the greedy optimizer
+-- (total 6 combinations - 3 for optimizer_search_depth, 2 for optimizer_prune_level):
+--
+-- set optimizer_search_depth=0; - automatic
+-- set optimizer_search_depth=1; - min
+-- set optimizer_search_depth=62; - max (default)
+--
+-- set optimizer_prune_level=0 - exhaustive;
+-- set optimizer_prune_level=1 - heuristic; -- default
+
+
+#
+# Compile several queries with all combinations of the query
+# optimizer parameters. Each test query has two variants, where
+# in the second variant the tables in the FROM clause are in
+# inverse order to the tables in the first variant.
+# Due to pre-sorting of tables before compilation, there should
+# be no difference in the plans for each two such query variants.
+#
+
+# First, for reference compile the test queries with the 'old' optimization
+# procedure 'find_best'. Notice that 'find_best' does not depend on the
+# choice of heuristic.
+
+set optimizer_search_depth=63;
+select @@optimizer_search_depth;
+
+-- 6-table join, chain
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, star
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, clique
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+
+
+# Test the new optimization procedures
+
+set optimizer_prune_level=0;
+select @@optimizer_prune_level;
+
+set optimizer_search_depth=0;
+select @@optimizer_search_depth;
+
+-- 6-table join, chain
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, star
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, clique
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+
+set optimizer_search_depth=1;
+select @@optimizer_search_depth;
+
+-- 6-table join, chain
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, star
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, clique
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+
+set optimizer_search_depth=62;
+select @@optimizer_search_depth;
+
+-- 6-table join, chain
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, star
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, clique
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+
+
+set optimizer_prune_level=1;
+select @@optimizer_prune_level;
+
+set optimizer_search_depth=0;
+select @@optimizer_search_depth;
+
+-- 6-table join, chain
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, star
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, clique
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+
+set optimizer_search_depth=1;
+select @@optimizer_search_depth;
+
+-- 6-table join, chain
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, star
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, clique
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+
+set optimizer_search_depth=62;
+select @@optimizer_search_depth;
+
+-- 6-table join, chain
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c12 = t2.c21 and t2.c22 = t3.c31 and t3.c32 = t4.c41 and t4.c42 = t5.c51 and t5.c52 = t6.c61 and t6.c62 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, star
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71;
+show status like 'Last_query_cost';
+-- 6-table join, clique
+explain select t1.c11 from t1, t2, t3, t4, t5, t6, t7 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+explain select t1.c11 from t7, t6, t5, t4, t3, t2, t1 where t1.c11 = t2.c21 and t1.c12 = t3.c31 and t1.c13 = t4.c41 and t1.c14 = t5.c51 and t1.c15 = t6.c61 and t1.c16 = t7.c71 and t2.c22 = t3.c32 and t2.c23 = t4.c42 and t2.c24 = t5.c52 and t2.c25 = t6.c62 and t2.c26 = t7.c72 and t3.c33 = t4.c43 and t3.c34 = t5.c53 and t3.c35 = t6.c63 and t3.c36 = t7.c73 and t4.c42 = t5.c54 and t4.c43 = t6.c64 and t4.c44 = t7.c74 and t5.c52 = t6.c65 and t5.c53 = t7.c75 and t6.c62 = t7.c76;
+show status like 'Last_query_cost';
+
+drop table t1,t2,t3,t4,t5,t6,t7;
diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test
new file mode 100644
index 00000000000..d85b3395853
--- /dev/null
+++ b/mysql-test/t/group_min_max.test
@@ -0,0 +1,612 @@
+#
+# Test file for WL#1724 (Min/Max Optimization for Queries with Group By Clause).
+# The queries in this file test query execution via QUICK_GROUP_MIN_MAX_SELECT.
+#
+
+#
+# TODO:
+# Add queries with:
+# - C != const
+# - C IS NOT NULL
+# - HAVING clause
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (
+ a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' '
+);
+
+insert into t1 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
+('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
+('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
+('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
+('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'),
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
+('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
+('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
+('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
+('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4');
+
+create index idx_t1_0 on t1 (a1);
+create index idx_t1_1 on t1 (a1,a2,b,c);
+create index idx_t1_2 on t1 (a1,a2,b);
+analyze table t1;
+
+-- t2 is the same as t1, but with some NULLs in the MIN/MAX column, and one more
+-- nullable attribute
+
+--disable_warnings
+drop table if exists t2;
+--enable_warnings
+
+create table t2 (
+ a1 char(64), a2 char(64) not null, b char(16), c char(16), d char(16), dummy char(64) default ' '
+);
+insert into t2 select * from t1;
+-- add few rows with NULL's in the MIN/MAX column
+insert into t2 (a1, a2, b, c, d) values
+('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'),
+('a','a','a',NULL,'xyz'),
+('a','a','b',NULL,'xyz'),
+('a','b','a',NULL,'xyz'),
+('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'),
+('d','b','b',NULL,'xyz'),
+('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),
+('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),
+('a','a',NULL,'a777','xyz'),('a','a',NULL,'a888','xyz'),('a','a',NULL,'a999','xyz'),
+('a','a','a',NULL,'xyz'),
+('a','a','b',NULL,'xyz'),
+('a','b','a',NULL,'xyz'),
+('c','a',NULL,'c777','xyz'),('c','a',NULL,'c888','xyz'),('c','a',NULL,'c999','xyz'),
+('d','b','b',NULL,'xyz'),
+('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),('e','a','a',NULL,'xyz'),
+('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz'),('e','a','b',NULL,'xyz');
+
+create index idx_t2_0 on t2 (a1);
+create index idx_t2_1 on t2 (a1,a2,b,c);
+create index idx_t2_2 on t2 (a1,a2,b);
+analyze table t2;
+
+-- Table t3 is the same as t1, but with smaller column lenghts.
+-- This allows to test different branches of the cost computation procedure
+-- when the number of keys per block are less than the number of keys in the
+-- sub-groups formed by predicates over non-group attributes.
+
+--disable_warnings
+drop table if exists t3;
+--enable_warnings
+
+create table t3 (
+ a1 char(1), a2 char(1), b char(1), c char(4) not null, d char(3), dummy char(1) default ' '
+);
+
+insert into t3 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
+insert into t3 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
+insert into t3 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
+insert into t3 (a1, a2, b, c, d) values
+('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
+('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
+('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
+('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
+('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
+('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
+('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
+('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
+('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
+('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
+('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
+('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4');
+
+create index idx_t3_0 on t3 (a1);
+create index idx_t3_1 on t3 (a1,a2,b,c);
+create index idx_t3_2 on t3 (a1,a2,b);
+analyze table t3;
+
+
+--
+-- Queries without a WHERE clause. These queries do not use ranges.
+--
+
+-- plans
+explain select a1, min(a2) from t1 group by a1;
+explain select a1, max(a2) from t1 group by a1;
+explain select a1, min(a2), max(a2) from t1 group by a1;
+explain select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b;
+explain select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b;
+--replace_column 7 #
+explain select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b;
+-- Select fields in different order
+explain select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1;
+explain select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b;
+explain select min(a2) from t1 group by a1;
+explain select a2, min(c), max(c) from t1 group by a1,a2,b;
+
+-- queries
+select a1, min(a2) from t1 group by a1;
+select a1, max(a2) from t1 group by a1;
+select a1, min(a2), max(a2) from t1 group by a1;
+select a1, a2, b, min(c), max(c) from t1 group by a1,a2,b;
+select a1,a2,b,max(c),min(c) from t1 group by a1,a2,b;
+select a1,a2,b,max(c),min(c) from t2 group by a1,a2,b;
+-- Select fields in different order
+select min(a2), a1, max(a2), min(a2), a1 from t1 group by a1;
+select a1, b, min(c), a1, max(c), b, a2, max(c), max(c) from t1 group by a1, a2, b;
+select min(a2) from t1 group by a1;
+select a2, min(c), max(c) from t1 group by a1,a2,b;
+
+--
+-- Queries with a where clause
+--
+
+-- A) Preds only over the group 'A' attributes
+-- plans
+explain select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
+explain select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+explain select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
+explain select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+explain select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+explain select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
+explain select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b;
+
+explain select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
+explain select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+explain select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
+explain select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+explain select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+explain select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
+explain select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b;
+
+-- queries
+select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
+select a1,a2,b, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+select a1, max(c) from t1 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
+select a1,a2,b, max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+select a1,a2,b, max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+select a1,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b;
+select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b;
+
+select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
+select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b;
+select a1,a2,b, max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where a1 = 'z' or a1 = 'b' or a1 = 'd' group by a1,a2,b;
+select a1,a2,b, max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') group by a1,a2,b;
+select a1,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b;
+select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b;
+
+-- B) Equalities only over the non-group 'B' attributes
+-- plans
+explain select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
+explain select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
+explain select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2;
+explain select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2;
+explain select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2;
+
+explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
+explain select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
+explain select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2;
+explain select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2;
+explain select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2;
+
+-- these queries test case 2) in TRP_GROUP_MIN_MAX::update_cost()
+explain select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
+explain select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
+
+-- queries
+select a1,a2,b,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
+select a1,max(c),min(c) from t1 where (a2 = 'a') and (b = 'b') group by a1;
+select a1,a2,b, max(c) from t1 where (b = 'b') group by a1,a2;
+select a1,a2,b,min(c),max(c) from t1 where (b = 'b') group by a1,a2;
+select a1,a2, max(c) from t1 where (b = 'b') group by a1,a2;
+
+select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
+select a1,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') group by a1;
+select a1,a2,b, max(c) from t2 where (b = 'b') group by a1,a2;
+select a1,a2,b,min(c),max(c) from t2 where (b = 'b') group by a1,a2;
+select a1,a2, max(c) from t2 where (b = 'b') group by a1,a2;
+
+-- these queries test case 2) in TRP_GROUP_MIN_MAX::update_cost()
+select a1,a2,b,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
+select a1,max(c),min(c) from t3 where (a2 = 'a') and (b = 'b') group by a1;
+
+
+-- IS NULL (makes sense for t2 only)
+-- plans
+explain select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1;
+explain select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1;
+explain select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2;
+explain select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2;
+explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
+explain select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
+-- queries
+select a1,a2,b,min(c) from t2 where (a2 = 'a') and b is NULL group by a1;
+select a1,a2,b,max(c) from t2 where (a2 = 'a') and b is NULL group by a1;
+select a1,a2,b,min(c) from t2 where b is NULL group by a1,a2;
+select a1,a2,b,max(c) from t2 where b is NULL group by a1,a2;
+select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
+select a1,a2,b,min(c),max(c) from t2 where b is NULL group by a1,a2;
+
+-- C) Range predicates for the MIN/MAX attribute
+-- plans
+explain select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b;
+
+explain select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+explain select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
+
+-- queries
+select a1,a2,b, max(c) from t1 where (c > 'b1') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') group by a1,a2,b;
+select a1,a2,b, max(c) from t1 where (c > 'f123') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (c > 'f123') group by a1,a2,b;
+select a1,a2,b, max(c) from t1 where (c < 'a0') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') group by a1,a2,b;
+select a1,a2,b, max(c) from t1 where (c < 'k321') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (c < 'k321') group by a1,a2,b;
+select a1,a2,b, max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (c between 'b111' and 'g112') or (c between 'd000' and 'i110') group by a1,a2,b;
+
+select a1,a2,b, max(c) from t2 where (c > 'b1') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') group by a1,a2,b;
+select a1,a2,b, max(c) from t2 where (c > 'f123') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (c > 'f123') group by a1,a2,b;
+select a1,a2,b, max(c) from t2 where (c < 'a0') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') group by a1,a2,b;
+select a1,a2,b, max(c) from t2 where (c < 'k321') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (c < 'k321') group by a1,a2,b;
+select a1,a2,b, max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (c < 'a0') or (c > 'b1') group by a1,a2,b;
+select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (c > 'b111') and (c <= 'g112') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (c < 'c5') or (c = 'g412') or (c = 'k421') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where ((c > 'b111') and (c <= 'g112')) or ((c > 'd000') and (c <= 'i110')) group by a1,a2,b;
+
+-- analyze the sub-select
+explain select a1,a2,b,min(c),max(c) from t1
+where exists ( select * from t2 where t2.c = t1.c )
+group by a1,a2,b;
+
+-- the sub-select is unrelated to MIN/MAX
+explain select a1,a2,b,min(c),max(c) from t1
+where exists ( select * from t2 where t2.c > 'b1' )
+group by a1,a2,b;
+
+
+-- A,B,C) Predicates referencing mixed classes of attributes
+-- plans
+explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
+explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
+explain select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
+explain select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+explain select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b;
+
+explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
+explain select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
+explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
+explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
+explain select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+
+-- queries
+select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t1 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
+select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
+select a1,a2,b,min(c) from t1 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
+select a1,a2,b,min(c) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+select a1,a2,b,min(c) from t1 where (ord(a1) > 97) and (ord(a2) + ord(a1) > 194) and (b = 'c') group by a1,a2,b;
+
+select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (a1 >= 'c' or a2 < 'b') and (c > 'b111') group by a1,a2,b;
+select a1,a2,b,min(c),max(c) from t2 where (a2 >= 'b') and (b = 'a') and (c > 'b111') group by a1,a2,b;
+select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b;
+select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b;
+select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+
+
+--
+-- GROUP BY queries without MIN/MAX
+--
+
+-- plans
+explain select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+explain select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+explain select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+explain select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+
+explain select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+explain select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+explain select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+explain select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+
+-- queries
+select a1,a2,b from t1 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+select a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+select a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+select a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+
+select a1,a2,b from t2 where (a1 >= 'c' or a2 < 'b') and (b > 'a') group by a1,a2,b;
+select a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+select a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+
+
+--
+-- DISTINCT queries
+--
+
+-- plans
+explain select distinct a1,a2,b from t1;
+explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a');
+explain select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+explain select distinct b from t1 where (a2 >= 'b') and (b = 'a');
+
+explain select distinct a1,a2,b from t2;
+explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a');
+explain select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+explain select distinct b from t2 where (a2 >= 'b') and (b = 'a');
+
+-- queries
+select distinct a1,a2,b from t1;
+select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a');
+select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+select distinct b from t1 where (a2 >= 'b') and (b = 'a');
+
+select distinct a1,a2,b from t2;
+select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a');
+select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+select distinct b from t2 where (a2 >= 'b') and (b = 'a');
+
+-- BUG #6303
+select distinct t_00.a1
+from t1 t_00
+where exists ( select * from t2 where a1 = t_00.a1 );
+
+-- BUG #8532 - SELECT DISTINCT a, a causes server to crash
+select distinct a1,a1 from t1;
+select distinct a2,a1,a2,a1 from t1;
+select distinct t1.a1,t2.a1 from t1,t2;
+
+--
+-- DISTINCT queries with GROUP-BY
+--
+
+-- plans
+explain select distinct a1,a2,b from t1;
+explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+explain select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+explain select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+
+explain select distinct a1,a2,b from t2;
+explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+explain select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+explain select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+
+-- queries
+select distinct a1,a2,b from t1;
+select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+select distinct b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+
+select distinct a1,a2,b from t2;
+select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121') group by a1,a2,b;
+select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b;
+select distinct b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b;
+
+
+--
+-- COUNT (DISTINCT cols) queries
+--
+
+explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
+explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+explain select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
+explain select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
+
+select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
+select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
+select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
+select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
+select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
+
+--
+-- Queries with expressions in the select clause
+--
+
+explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b;
+explain select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b;
+explain select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b;
+explain select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
+explain select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2;
+
+select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b;
+select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b;
+select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b;
+select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b;
+select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2;
+
+
+--
+-- Negative examples: queries that should NOT be treated as optimizable by
+-- QUICK_GROUP_MIN_MAX_SELECT
+--
+
+-- select a non-indexed attribute
+explain select a1,a2,b,d,min(c),max(c) from t1 group by a1,a2,b;
+
+explain select a1,a2,b,d from t1 group by a1,a2,b;
+
+-- predicate that references an attribute that is after the MIN/MAX argument
+-- in the index
+explain select a1,a2,min(b),max(b) from t1
+where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2;
+
+-- predicate that references a non-indexed attribute
+explain select a1,a2,b,min(c),max(c) from t1
+where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b;
+
+explain select a1,a2,b,c from t1
+where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (d > 'xy2') group by a1,a2,b,c;
+
+-- non-equality predicate for a non-group select attribute
+explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b < 'b') group by a1;
+explain select a1,a2,b from t1 where (a1 = 'b' or a1 = 'd' or a1 = 'a' or a1 = 'c') and (a2 > 'a') and (c > 'a111') group by a1,a2,b;
+
+-- non-group field with an equality predicate that references a keypart after the
+-- MIN/MAX argument
+explain select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1;
+select a1,a2,min(b),c from t2 where (a2 = 'a') and (c = 'a111') group by a1;
+
+-- disjunction for a non-group select attribute
+explain select a1,a2,b,max(c),min(c) from t2 where (a2 = 'a') and (b = 'b') or (b = 'a') group by a1;
+
+-- non-range predicate for the MIN/MAX attribute
+explain select a1,a2,b,min(c),max(c) from t2
+where (c > 'a000') and (c <= 'd999') and (c like '_8__') group by a1,a2,b;
+
+-- not all attributes are indexed by one index
+explain select a1, a2, b, c, min(d), max(d) from t1 group by a1,a2,b,c;
+
+-- other aggregate functions than MIN/MAX
+explain select a1,a2,count(a2) from t1 group by a1,a2,b;
+explain select a1,a2,count(a2) from t1 where (a1 > 'a') group by a1,a2,b;
+explain select sum(ord(a1)) from t1 where (a1 > 'a') group by a1,a2,b;
+
+drop table t1;
+drop table t2;
+drop table t3;
+
+#
+# Bug #6142: a problem with the empty innodb table
+#
+
+--disable_warnings
+create table t1 (
+ a varchar(30), b varchar(30), primary key(a), key(b)
+) engine=innodb;
+--enable_warnings
+select distinct a from t1;
+drop table t1;
diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test
index 12a44fd75dc..3221b0d4624 100644
--- a/mysql-test/t/having.test
+++ b/mysql-test/t/having.test
@@ -2,7 +2,7 @@
#
--disable_warnings
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
--enable_warnings
create table t1 (a int);
@@ -122,3 +122,200 @@ from t1 a left join t3 b on a.id=b.order_id
group by a.id, a.description
having (a.description is not null) and (c=0);
drop table t1,t2,t3;
+
+
+#
+# Tests for WL#1972 CORRECT EVALUATION OF COLUMN REFERENCES IN THE HAVING CLAUSE
+# Per the SAP VERI tests and WL#1972, MySQL must ensure that HAVING can
+# correctly evaluate column references from the GROUP BY clause, even if the
+# same references are not also found in the select list.
+#
+
+# set global sql_mode='ansi';
+# set session sql_mode='ansi';
+
+create table t1 (col1 int, col2 varchar(5), col_t1 int);
+create table t2 (col1 int, col2 varchar(5), col_t2 int);
+create table t3 (col1 int, col2 varchar(5), col_t3 int);
+
+insert into t1 values(10,'hello',10);
+insert into t1 values(20,'hello',20);
+insert into t1 values(30,'hello',30);
+insert into t1 values(10,'bye',10);
+insert into t1 values(10,'sam',10);
+insert into t1 values(10,'bob',10);
+
+insert into t2 select * from t1;
+insert into t3 select * from t1;
+
+select count(*) from t1 group by col1 having col1 = 10;
+select count(*) as count_col1 from t1 group by col1 having col1 = 10;
+select count(*) as count_col1 from t1 as tmp1 group by col1 having col1 = 10;
+select count(*) from t1 group by col2 having col2 = 'hello';
+--error 1054
+select count(*) from t1 group by col2 having col1 = 10;
+select col1 as count_col1 from t1 as tmp1 group by col1 having col1 = 10;
+select col1 as count_col1 from t1 as tmp1 group by col1 having count_col1 = 10;
+select col1 as count_col1 from t1 as tmp1 group by count_col1 having col1 = 10;
+# ANSI: should return SQLSTATE 42000 Syntax error or access violation
+# MySQL: returns 10 - because of GROUP BY name resolution
+select col1 as count_col1 from t1 as tmp1 group by count_col1 having count_col1 = 10;
+# ANSI: should return SQLSTATE 42000 Syntax error or access violation
+# MySQL: returns 10 - because of GROUP BY name resolution
+select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having col1 = 10;
+select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having count_col1 = 10;
+select col1 as count_col1,col2 from t1 as tmp1 group by col1,col2 having col2 = 'hello';
+select col1 as count_col1,col2 as group_col2 from t1 as tmp1 group by col1,col2 having group_col2 = 'hello';
+--error 1064
+select sum(col1) as co12 from t1 group by col2 having col2 10;
+select sum(col1) as co2, count(col2) as cc from t1 group by col1 having col1 =10;
+--error 1054
+select t2.col2 from t2 group by t2.col1, t2.col2 having t1.col1 <= 10;
+
+
+#
+# queries with nested sub-queries
+#
+
+# the having column is resolved in the same query
+select t1.col1 from t1
+where t1.col2 in
+ (select t2.col2 from t2
+ group by t2.col1, t2.col2 having t2.col1 <= 10);
+
+select t1.col1 from t1
+where t1.col2 in
+ (select t2.col2 from t2
+ group by t2.col1, t2.col2
+ having t2.col1 <=
+ (select min(t3.col1) from t3));
+
+# the having column is resolved in the SELECT clause of the outer query -
+# works in ANSI
+select t1.col1 from t1
+where t1.col2 in
+ (select t2.col2 from t2
+ group by t2.col1, t2.col2 having t1.col1 <= 10);
+
+# the having column is resolved in the SELECT clause of the outer query -
+# error in ANSI, works with MySQL extension
+select t1.col1 as tmp_col from t1
+where t1.col2 in
+ (select t2.col2 from t2
+ group by t2.col1, t2.col2 having tmp_col <= 10);
+
+# the having column is resolved in the FROM clause of the outer query -
+# works in ANSI
+select t1.col1 from t1
+where t1.col2 in
+ (select t2.col2 from t2
+ group by t2.col1, t2.col2 having col_t1 <= 10);
+
+# Item_field must be resolved in the same way as Item_ref
+select sum(col1) from t1
+group by col_t1
+having (select col_t1 from t2 where col_t1 = col_t2 order by col_t2 limit 1);
+
+# nested queries with HAVING, inner having column resolved in outer FROM clause
+# the outer having column is not referenced in GROUP BY which results in an error
+--error 1054
+select t1.col1 from t1
+where t1.col2 in
+ (select t2.col2 from t2
+ group by t2.col1, t2.col2 having col_t1 <= 10)
+having col_t1 <= 20;
+
+# both having columns are resolved in the GROUP clause of the outer query
+select t1.col1 from t1
+where t1.col2 in
+ (select t2.col2 from t2
+ group by t2.col1, t2.col2 having col_t1 <= 10)
+group by col_t1
+having col_t1 <= 20;
+
+
+#
+# nested HAVING clauses
+#
+
+# non-correlated subqueries
+select col_t1, sum(col1) from t1
+group by col_t1
+having col_t1 > 10 and
+ exists (select sum(t2.col1) from t2
+ group by t2.col2 having t2.col2 > 'b');
+
+# correlated subqueries - inner having column 't1.col2' resolves to
+# the outer FROM clause, which cannot be used because the outer query
+# is grouped
+--error 1054
+select sum(col1) from t1
+group by col_t1
+having col_t1 in (select sum(t2.col1) from t2
+ group by t2.col2, t2.col1 having t2.col1 = t1.col1);
+
+# correlated subqueries - inner having column 'col_t1' resolves to
+# the outer GROUP clause
+select sum(col1) from t1
+group by col_t1
+having col_t1 in (select sum(t2.col1) from t2
+ group by t2.col2, t2.col1 having t2.col1 = col_t1);
+
+#
+# queries with joins and ambiguous column names
+#
+--error 1052
+select t1.col1, t2.col1 from t1, t2 where t1.col1 = t2.col1
+group by t1.col1, t2.col1 having col1 = 2;
+
+--error 1052
+select t1.col1*10+t2.col1 from t1,t2 where t1.col1=t2.col1
+group by t1.col1, t2.col1 having col1 = 2;
+
+drop table t1, t2, t3;
+
+# More queries to test ANSI compatibility
+create table t1 (s1 int);
+insert into t1 values (1),(2),(3);
+
+select count(*) from t1 group by s1 having s1 is null;
+
+# prepared statements prints warnings too early
+--disable_ps_protocol
+select s1*0 as s1 from t1 group by s1 having s1 <> 0;
+--enable_ps_protocol
+
+# ANSI requires: 3 rows
+# MySQL returns: 0 rows - because of GROUP BY name resolution
+
+select s1*0 from t1 group by s1 having s1 = 0;
+
+select s1 from t1 group by 1 having 1 = 0;
+
+select count(s1) from t1 group by s1 having count(1+1)=2;
+# ANSI requires: 3 rows
+# MySQL returns: 0 rows - because of GROUP BY name resolution
+
+select count(s1) from t1 group by s1 having s1*0=0;
+
+-- error 1052
+select * from t1 a, t1 b group by a.s1 having s1 is null;
+# ANSI requires: 0 rows
+# MySQL returns:
+# "ERROR 1052 (23000): Column 's1' in having clause is ambiguous"
+# I think the column is ambiguous in ANSI too.
+# It is the same as:
+# select a.s1, b.s1 from t1 a, t1 b group by a.s1 having s1 is null;
+# currently we first check SELECT, thus s1 is ambiguous.
+
+drop table t1;
+
+create table t1 (s1 char character set latin1 collate latin1_german1_ci);
+insert into t1 values ('ü'),('y');
+
+select s1,count(s1) from t1
+group by s1 collate latin1_swedish_ci having s1 = 'y';
+# ANSI requires: 1 row, with count(s1) = 2
+# MySQL returns: 1 row, with count(s1) = 1
+
+drop table t1;
diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test
index e082993a58e..68a84e1c193 100644
--- a/mysql-test/t/heap.test
+++ b/mysql-test/t/heap.test
@@ -3,7 +3,7 @@
#
--disable_warnings
-drop table if exists t1;
+drop table if exists t1,t2,t3;
--enable_warnings
create table t1 (a int not null,b int not null, primary key (a)) engine=heap comment="testing heaps" avg_row_length=100 min_rows=1 max_rows=100;
@@ -34,7 +34,7 @@ select * from t1;
drop table t1;
create table t1 (a int not null) engine=heap;
-insert into t1 values (869751),(736494),(226312),(802616);
+insert into t1 values (869751),(736494),(226312),(802616),(728912);
select * from t1 where a > 736494;
alter table t1 add unique uniq_id(a);
select * from t1 where a > 736494;
@@ -197,30 +197,232 @@ select * from t1;
drop table t1;
#
+# Test varchar
+# We can't use varchar.inc becasue heap doesn't support blob's
+#
+
+let $default=`select @@storage_engine`;
+set storage_engine=HEAP;
+
+#
+# Simple basic test that endspace is saved
+#
+
+create table t1 (v varchar(10), c char(10), t varchar(50));
+insert into t1 values('+ ', '+ ', '+ ');
+set @a=repeat(' ',20);
+insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
+select concat('*',v,'*',c,'*',t,'*') from t1;
+
+# Check how columns are copied
+show create table t1;
+create table t2 like t1;
+show create table t2;
+create table t3 select * from t1;
+show create table t3;
+alter table t1 modify c varchar(10);
+show create table t1;
+alter table t1 modify v char(10);
+show create table t1;
+alter table t1 modify t varchar(10);
+show create table t1;
+select concat('*',v,'*',c,'*',t,'*') from t1;
+drop table t1,t2,t3;
+
+#
+# Testing of keys
+#
+create table t1 (v varchar(10), c char(10), t varchar(50), key(v), key(c), key(t(10)));
+show create table t1;
+disable_query_log;
+let $1=10;
+while ($1)
+{
+ let $2=27;
+ eval set @space=repeat(' ',10-$1);
+ while ($2)
+ {
+ eval set @char=char(ascii('a')+$2-1);
+ insert into t1 values(concat(@char,@space),concat(@char,@space),concat(@char,@space));
+ dec $2;
+ }
+ dec $1;
+}
+enable_query_log;
+select count(*) from t1;
+insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1)));
+select count(*) from t1 where v='a';
+select count(*) from t1 where c='a';
+select count(*) from t1 where t='a';
+select count(*) from t1 where v='a ';
+select count(*) from t1 where c='a ';
+select count(*) from t1 where t='a ';
+select count(*) from t1 where v between 'a' and 'a ';
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+select count(*) from t1 where v like 'a%';
+select count(*) from t1 where c like 'a%';
+select count(*) from t1 where t like 'a%';
+select count(*) from t1 where v like 'a %';
+explain select count(*) from t1 where v='a ';
+explain select count(*) from t1 where c='a ';
+explain select count(*) from t1 where t='a ';
+explain select count(*) from t1 where v like 'a%';
+explain select count(*) from t1 where v between 'a' and 'a ';
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+
+--error 1062
+alter table t1 add unique(v);
+select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*'));
+explain select * from t1 where v='a';
+
+# GROUP BY
+
+select v,count(*) from t1 group by v limit 10;
+select v,count(t) from t1 group by v limit 10;
+select v,count(c) from t1 group by v limit 10;
+select sql_big_result trim(v),count(t) from t1 group by v limit 10;
+select sql_big_result trim(v),count(c) from t1 group by v limit 10;
+select c,count(*) from t1 group by c limit 10;
+select c,count(t) from t1 group by c limit 10;
+select sql_big_result c,count(t) from t1 group by c limit 10;
+select t,count(*) from t1 group by t limit 10;
+select t,count(t) from t1 group by t limit 10;
+select sql_big_result trim(t),count(t) from t1 group by t limit 10;
+drop table t1;
+
+#
+# Test unique keys
+#
+
+create table t1 (a char(10), unique (a));
+insert into t1 values ('a');
+--error 1062
+insert into t1 values ('a ');
+
+alter table t1 modify a varchar(10);
+--error 1062
+insert into t1 values ('a '),('a '),('a '),('a ');
+--error 1062
+insert into t1 values ('a ');
+--error 1062
+insert into t1 values ('a ');
+--error 1062
+insert into t1 values ('a ');
+update t1 set a='a ' where a like 'a ';
+update t1 set a='a ' where a like 'a ';
+drop table t1;
+
+#
+# Testing of btree keys
+#
+
+create table t1 (v varchar(10), c char(10), t varchar(50), key using btree (v), key using btree (c), key using btree (t(10)));
+show create table t1;
+disable_query_log;
+let $1=10;
+while ($1)
+{
+ let $2=27;
+ eval set @space=repeat(' ',10-$1);
+ while ($2)
+ {
+ eval set @char=char(ascii('a')+$2-1);
+ insert into t1 values(concat(@char,@space),concat(@char,@space),concat(@char,@space));
+ dec $2;
+ }
+ dec $1;
+}
+enable_query_log;
+select count(*) from t1;
+insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1)));
+select count(*) from t1 where v='a';
+select count(*) from t1 where c='a';
+select count(*) from t1 where t='a';
+select count(*) from t1 where v='a ';
+select count(*) from t1 where c='a ';
+select count(*) from t1 where t='a ';
+select count(*) from t1 where v between 'a' and 'a ';
+--replace_column 9 #
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+--replace_column 9 #
+explain select count(*) from t1 where v='a ';
+--replace_column 9 #
+explain select count(*) from t1 where c='a ';
+--replace_column 9 #
+explain select count(*) from t1 where t='a ';
+--replace_column 9 #
+explain select count(*) from t1 where v like 'a%';
+--replace_column 9 #
+explain select count(*) from t1 where v between 'a' and 'a ';
+--replace_column 9 #
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+
+--error 1062
+alter table t1 add unique(v);
+select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a' order by length(concat('*',v,'*',c,'*',t,'*'));
+# Number of rows is not constant for b-trees keys
+--replace_column 9 #
+explain select * from t1 where v='a';
+
+drop table t1;
+
+#
+# Test unique btree keys
+#
+
+create table t1 (a char(10), unique using btree (a)) engine=heap;
+insert into t1 values ('a');
+--error 1062
+insert into t1 values ('a ');
+
+alter table t1 modify a varchar(10);
+--error 1062
+insert into t1 values ('a '),('a '),('a '),('a ');
+--error 1062
+insert into t1 values ('a ');
+--error 1062
+insert into t1 values ('a ');
+--error 1062
+insert into t1 values ('a ');
+update t1 set a='a ' where a like 'a ';
+update t1 set a='a ' where a like 'a ';
+drop table t1;
+
+#
+# test show create table
+#
+
+create table t1 (v varchar(10), c char(10), t varchar(50), key(v(5)), key(c(5)), key(t(5)));
+show create table t1;
+drop table t1;
+
+create table t1 (v varchar(65530), key(v(10)));
+show create table t1;
+insert into t1 values(repeat('a',65530));
+select length(v) from t1 where v=repeat('a',65530);
+drop table t1;
+
+#
+# Reset varchar test
+#
+eval set storage_engine=$default;
+
+#
# Bug #8489: Strange auto_increment behaviour
#
create table t1 (a bigint unsigned auto_increment primary key, b int,
key (b, a)) engine=heap;
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-insert t1 (b) values (1);
-select * from t1;
+insert t1 (b) values (1),(1),(1),(1),(1),(1),(1),(1);
+select * from t1;
drop table t1;
+
create table t1 (a int not null, b int not null auto_increment,
primary key(a, b), key(b)) engine=heap;
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-insert t1 (a) values (1);
-select * from t1;
+insert t1 (a) values (1),(1),(1),(1),(1),(1),(1),(1);
+select * from t1;
drop table t1;
+
+--error 1075
+create table t1 (a int not null, b int not null auto_increment,
+ primary key(a, b)) engine=heap;
diff --git a/mysql-test/t/heap_btree.test b/mysql-test/t/heap_btree.test
index d156d059634..6fec2ac1703 100644
--- a/mysql-test/t/heap_btree.test
+++ b/mysql-test/t/heap_btree.test
@@ -34,7 +34,7 @@ select * from t1;
drop table t1;
create table t1 (a int not null) engine=heap;
-insert into t1 values (869751),(736494),(226312),(802616);
+insert into t1 values (869751),(736494),(226312),(802616),(728912);
select * from t1 where a > 736494;
alter table t1 add unique uniq_id using BTREE (a);
select * from t1 where a > 736494;
diff --git a/mysql-test/t/heap_hash.test b/mysql-test/t/heap_hash.test
index 6d27f19dfad..46669dd2b8f 100644
--- a/mysql-test/t/heap_hash.test
+++ b/mysql-test/t/heap_hash.test
@@ -34,7 +34,7 @@ select * from t1;
drop table t1;
create table t1 (a int not null) engine=heap;
-insert into t1 values (869751),(736494),(226312),(802616);
+insert into t1 values (869751),(736494),(226312),(802616),(728912);
select * from t1 where a > 736494;
alter table t1 add unique uniq_id using HASH (a);
select * from t1 where a > 736494;
diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test
new file mode 100644
index 00000000000..5acbcd8eaeb
--- /dev/null
+++ b/mysql-test/t/index_merge.test
@@ -0,0 +1,328 @@
+#
+# Index merge tests
+#
+--disable_warnings
+drop table if exists t0, t1, t2, t3, t4;
+--enable_warnings
+
+# Create and fill a table with simple keys
+create table t0
+(
+ key1 int not null,
+ INDEX i1(key1)
+);
+
+--disable_query_log
+insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
+
+let $1=7;
+set @d=8;
+while ($1)
+{
+ eval insert into t0 select key1+@d from t0;
+ eval set @d=@d*2;
+ dec $1;
+}
+--enable_query_log
+
+alter table t0 add key2 int not null, add index i2(key2);
+alter table t0 add key3 int not null, add index i3(key3);
+alter table t0 add key4 int not null, add index i4(key4);
+alter table t0 add key5 int not null, add index i5(key5);
+alter table t0 add key6 int not null, add index i6(key6);
+alter table t0 add key7 int not null, add index i7(key7);
+alter table t0 add key8 int not null, add index i8(key8);
+
+update t0 set key2=key1,key3=key1,key4=key1,key5=key1,key6=key1,key7=key1,key8=1024-key1;
+analyze table t0;
+
+# 1. One index
+explain select * from t0 where key1 < 3 or key1 > 1020;
+
+# 2. Simple cases
+explain
+select * from t0 where key1 < 3 or key2 > 1020;
+select * from t0 where key1 < 3 or key2 > 1020;
+
+explain select * from t0 where key1 < 3 or key2 <4;
+
+explain
+select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40);
+select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40);
+
+# 3. Check that index_merge doesn't break "ignore/force/use index"
+explain select * from t0 ignore index (i2) where key1 < 3 or key2 <4;
+explain select * from t0 where (key1 < 3 or key2 <4) and key3 = 50;
+explain select * from t0 use index (i1,i2) where (key1 < 3 or key2 <4) and key3 = 50;
+
+explain select * from t0 where (key1 > 1 or key2 > 2);
+explain select * from t0 force index (i1,i2) where (key1 > 1 or key2 > 2);
+
+
+# 4. Check if conjuncts are grouped by keyuse
+explain
+ select * from t0 where key1<3 or key2<3 or (key1>5 and key1<8) or
+ (key1>10 and key1<12) or (key2>100 and key2<110);
+
+# 5. Check index_merge with conjuncts that are always true/false
+# verify fallback to "range" if there is only one non-confluent condition
+explain select * from t0 where key2 = 45 or key1 <=> null;
+
+explain select * from t0 where key2 = 45 or key1 is not null;
+explain select * from t0 where key2 = 45 or key1 is null;
+
+# the last conj. is always false and will be discarded
+explain select * from t0 where key2=10 or key3=3 or key4 <=> null;
+
+# the last conj. is always true and will cause 'all' scan
+explain select * from t0 where key2=10 or key3=3 or key4 is null;
+
+# some more complicated cases
+explain select key1 from t0 where (key1 <=> null) or (key2 < 5) or
+ (key3=10) or (key4 <=> null);
+explain select key1 from t0 where (key1 <=> null) or (key1 < 5) or
+ (key3=10) or (key4 <=> null);
+
+# 6.Several ways to do index_merge, (ignored) index_merge vs. range
+explain select * from t0 where
+ (key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 5 or key6 < 5);
+
+explain
+select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4);
+
+select * from t0 where (key1 < 3 or key2 < 6) and (key1 < 7 or key3 < 4);
+
+
+explain select * from t0 where
+ (key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 2 or key6 < 2);
+
+# now index_merge is not used at all when "range" is possible
+explain select * from t0 where
+ (key1 < 3 or key2 < 3) and (key3 < 100);
+
+# this even can cause "all" scan:
+explain select * from t0 where
+ (key1 < 3 or key2 < 3) and (key3 < 1000);
+
+
+# 7. Complex cases
+# tree_or(List<SEL_IMERGE>, range SEL_TREE).
+explain select * from t0 where
+ ((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4))
+ or
+ key2 > 5;
+
+explain select * from t0 where
+ ((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4))
+ or
+ key1 < 7;
+
+select * from t0 where
+ ((key1 < 4 or key2 < 4) and (key2 <5 or key3 < 4))
+ or
+ key1 < 7;
+
+# tree_or(List<SEL_IMERGE>, List<SEL_IMERGE>).
+explain select * from t0 where
+ ((key1 < 4 or key2 < 4) and (key3 <5 or key5 < 4))
+ or
+ ((key5 < 5 or key6 < 6) and (key7 <7 or key8 < 4));
+
+explain select * from t0 where
+ ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+ or
+ ((key7 <7 or key8 < 4) and (key5 < 5 or key6 < 6));
+
+explain select * from t0 where
+ ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+ or
+ ((key3 <7 or key5 < 2) and (key5 < 5 or key6 < 6));
+
+explain select * from t0 where
+ ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+ or
+ (((key3 <7 and key7 < 6) or key5 < 2) and (key5 < 5 or key6 < 6));
+
+explain select * from t0 where
+ ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+ or
+ ((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6));
+
+explain select * from t0 force index(i1, i2, i3, i4, i5, i6 ) where
+ ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4))
+ or
+ ((key3 >=5 or key5 < 2) and (key5 < 5 or key6 < 6));
+
+# 8. Verify that "order by" after index merge uses filesort
+select * from t0 where key1 < 5 or key8 < 4 order by key1;
+
+explain
+select * from t0 where key1 < 5 or key8 < 4 order by key1;
+
+# 9. Check that index_merge cost is compared to 'index' where possible
+create table t2 like t0;
+insert into t2 select * from t0;
+
+alter table t2 add index i1_3(key1, key3);
+alter table t2 add index i2_3(key2, key3);
+alter table t2 drop index i1;
+alter table t2 drop index i2;
+alter table t2 add index i321(key3, key2, key1);
+
+# index_merge vs 'index', index_merge is better.
+explain select key3 from t2 where key1 = 100 or key2 = 100;
+
+# index_merge vs 'index', 'index' is better.
+explain select key3 from t2 where key1 <100 or key2 < 100;
+
+# index_merge vs 'all', index_merge is better.
+explain select key7 from t2 where key1 <100 or key2 < 100;
+
+# 10. Multipart keys.
+create table t4 (
+ key1a int not null,
+ key1b int not null,
+ key2 int not null,
+ key2_1 int not null,
+ key2_2 int not null,
+ key3 int not null,
+
+ index i1a (key1a, key1b),
+ index i1b (key1b, key1a),
+
+ index i2_1(key2, key2_1),
+ index i2_2(key2, key2_1)
+);
+
+insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0;
+
+# the following will be handled by index_merge:
+select * from t4 where key1a = 3 or key1b = 4;
+explain select * from t4 where key1a = 3 or key1b = 4;
+
+# and the following will not
+explain select * from t4 where key2 = 1 and (key2_1 = 1 or key3 = 5);
+
+explain select * from t4 where key2 = 1 and (key2_1 = 1 or key2_2 = 5);
+
+explain select * from t4 where key2_1 = 1 or key2_2 = 5;
+
+
+# 11. Multitable selects
+create table t1 like t0;
+insert into t1 select * from t0;
+
+# index_merge on first table in join
+explain select * from t0 left join t1 on (t0.key1=t1.key1)
+ where t0.key1=3 or t0.key2=4;
+
+select * from t0 left join t1 on (t0.key1=t1.key1)
+ where t0.key1=3 or t0.key2=4;
+
+explain
+select * from t0,t1 where (t0.key1=t1.key1) and ( t0.key1=3 or t0.key2=4);
+
+# index_merge vs. ref
+explain
+select * from t0,t1 where (t0.key1=t1.key1) and
+ (t0.key1=3 or t0.key2=4) and t1.key1<200;
+
+# index_merge vs. ref
+explain
+select * from t0,t1 where (t0.key1=t1.key1) and
+ (t0.key1=3 or t0.key2<4) and t1.key1=2;
+
+# index_merge on second table in join
+explain select * from t0,t1 where t0.key1 = 5 and
+ (t1.key1 = t0.key1 or t1.key8 = t0.key1);
+
+# Fix for bug#1974
+explain select * from t0,t1 where t0.key1 < 3 and
+ (t1.key1 = t0.key1 or t1.key8 = t0.key1);
+
+# index_merge inside union
+explain select * from t1 where key1=3 or key2=4
+ union select * from t1 where key1<4 or key3=5;
+
+# index merge in subselect
+explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5;
+
+# 12. check for long index_merges.
+create table t3 like t0;
+insert into t3 select * from t0;
+alter table t3 add key9 int not null, add index i9(key9);
+alter table t3 add keyA int not null, add index iA(keyA);
+alter table t3 add keyB int not null, add index iB(keyB);
+alter table t3 add keyC int not null, add index iC(keyC);
+update t3 set key9=key1,keyA=key1,keyB=key1,keyC=key1;
+
+explain select * from t3 where
+ key1=1 or key2=2 or key3=3 or key4=4 or
+ key5=5 or key6=6 or key7=7 or key8=8 or
+ key9=9 or keyA=10 or keyB=11 or keyC=12;
+
+select * from t3 where
+ key1=1 or key2=2 or key3=3 or key4=4 or
+ key5=5 or key6=6 or key7=7 or key8=8 or
+ key9=9 or keyA=10 or keyB=11 or keyC=12;
+
+# Test for Bug#3183
+explain select * from t0 where key1 < 3 or key2 < 4;
+select * from t0 where key1 < 3 or key2 < 4;
+
+update t0 set key8=123 where key1 < 3 or key2 < 4;
+select * from t0 where key1 < 3 or key2 < 4;
+
+delete from t0 where key1 < 3 or key2 < 4;
+select * from t0 where key1 < 3 or key2 < 4;
+select count(*) from t0;
+
+# Test for BUG#4177
+drop table t4;
+create table t4 (a int);
+insert into t4 values (1),(4),(3);
+set @save_join_buffer_size=@@join_buffer_size;
+set join_buffer_size= 4000;
+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 force index(i1,i2), t0 as B force index (i1,i2)
+ where (A.key1 < 500000 or A.key2 < 3)
+ and (B.key1 < 500000 or B.key2 < 3);
+
+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 force index(i1,i2), t0 as B force index (i1,i2)
+ where (A.key1 < 500000 or A.key2 < 3)
+ and (B.key1 < 500000 or B.key2 < 3);
+
+update t0 set key1=1;
+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 force index(i1,i2), t0 as B force index (i1,i2)
+ where (A.key1 = 1 or A.key2 = 1)
+ and (B.key1 = 1 or B.key2 = 1);
+
+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 force index(i1,i2), t0 as B force index (i1,i2)
+ where (A.key1 = 1 or A.key2 = 1)
+ and (B.key1 = 1 or B.key2 = 1);
+
+alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200);
+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 7or16 16 7or16
+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)
+ 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);
+
+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)
+ 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);
+
+set join_buffer_size= @save_join_buffer_size;
+# Test for BUG#4177 ends
+
+drop table t0, t1, t2, t3, t4;
+
diff --git a/mysql-test/t/index_merge_bdb.test b/mysql-test/t/index_merge_bdb.test
new file mode 100644
index 00000000000..c49e6ab3175
--- /dev/null
+++ b/mysql-test/t/index_merge_bdb.test
@@ -0,0 +1,52 @@
+#
+# 2-sweeps read Index_merge test
+#
+-- source include/have_bdb.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (
+ pk int primary key,
+ key1 int,
+ key2 int,
+ filler char(200),
+ filler2 char(200),
+ index(key1),
+ index(key2)
+) engine=bdb;
+
+
+--disable_query_log
+let $1=1000;
+while ($1)
+{
+ eval insert into t1 values($1, $1, $1, 'filler-data','filler-data-2');
+ dec $1;
+}
+--enable_query_log
+
+select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
+
+set @maxv=1000;
+
+select * from t1 where
+ (pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+ or key1=18 or key1=60;
+
+select * from t1 where
+ (pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+ or key1 < 3 or key1 > @maxv-11;
+
+select * from t1 where
+ (pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+ or
+ (key1 < 5) or (key1 > 10 and key1 < 15) or (key1 >= 50 and key1 < 55 ) or (key1 > @maxv-10);
+
+select * from t1 where
+ (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 )
+ or
+ (key1 < 5) or (key1 > @maxv-10);
+
+drop table t1;
diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test
new file mode 100644
index 00000000000..5e270c161a2
--- /dev/null
+++ b/mysql-test/t/index_merge_innodb.test
@@ -0,0 +1,122 @@
+#
+# Index merge tests
+#
+-- source include/have_innodb.inc
+
+--disable_warnings
+drop table if exists t1,t2;
+--enable_warnings
+
+create table t1
+(
+ key1 int not null,
+ key2 int not null,
+
+ INDEX i1(key1),
+ INDEX i2(key2)
+) engine=innodb;
+
+--disable_query_log
+let $1=200;
+while ($1)
+{
+ eval insert into t1 values (200-$1, $1);
+ dec $1;
+}
+--enable_query_log
+
+# No primary key
+explain select * from t1 where key1 < 5 or key2 > 197;
+
+select * from t1 where key1 < 5 or key2 > 197;
+
+explain select * from t1 where key1 < 3 or key2 > 195;
+select * from t1 where key1 < 3 or key2 > 195;
+
+# Primary key as case-sensitive string with \0s.
+# also make primary key be longer then max. index length of MyISAM.
+alter table t1 add str1 char (255) not null,
+ add zeroval int not null default 0,
+ add str2 char (255) not null,
+ add str3 char (255) not null;
+
+update t1 set str1='aaa', str2='bbb', str3=concat(key2, '-', key1 div 2, '_' ,if(key1 mod 2 = 0, 'a', 'A'));
+
+alter table t1 add primary key (str1, zeroval, str2, str3);
+
+explain select * from t1 where key1 < 5 or key2 > 197;
+
+select * from t1 where key1 < 5 or key2 > 197;
+
+explain select * from t1 where key1 < 3 or key2 > 195;
+select * from t1 where key1 < 3 or key2 > 195;
+
+# Test for BUG#5401
+drop table t1;
+create table t1 (
+ pk integer not null auto_increment primary key,
+ key1 integer,
+ key2 integer not null,
+ filler char (200),
+ index (key1),
+ index (key2)
+) engine=innodb;
+show warnings;
+--disable_query_log
+let $1=30;
+while ($1)
+{
+ eval insert into t1 (key1, key2, filler) values ($1/4, $1/8, 'filler-data');
+ dec $1;
+}
+--enable_query_log
+explain select pk from t1 where key1 = 1 and key2 = 1;
+select pk from t1 where key2 = 1 and key1 = 1;
+select pk from t1 ignore index(key1,key2) where key2 = 1 and key1 = 1;
+
+# More tests for BUG#5401.
+drop table t1;
+create table t1 (
+ pk int primary key auto_increment,
+ key1a int,
+ key2a int,
+ key1b int,
+ key2b int,
+ dummy1 int,
+ dummy2 int,
+ dummy3 int,
+ dummy4 int,
+ key3a int,
+ key3b int,
+ filler1 char (200),
+ index i1(key1a, key1b),
+ index i2(key2a, key2b),
+ index i3(key3a, key3b)
+) engine=innodb;
+
+create table t2 (a int);
+insert into t2 values (0),(1),(2),(3),(4),(NULL);
+
+insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b)
+ select A.a, B.a, C.a, D.a, C.a, D.a from t2 A,t2 B,t2 C, t2 D;
+insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b)
+ select key1a, key1b, key2a, key2b, key3a, key3b from t1;
+insert into t1 (key1a, key1b, key2a, key2b, key3a, key3b)
+ select key1a, key1b, key2a, key2b, key3a, key3b from t1;
+analyze table t1;
+select count(*) from t1;
+
+explain select count(*) from t1 where
+ key1a = 2 and key1b is null and key2a = 2 and key2b is null;
+
+select count(*) from t1 where
+ key1a = 2 and key1b is null and key2a = 2 and key2b is null;
+
+explain select count(*) from t1 where
+ key1a = 2 and key1b is null and key3a = 2 and key3b is null;
+
+select count(*) from t1 where
+ key1a = 2 and key1b is null and key3a = 2 and key3b is null;
+
+drop table t1,t2;
+
diff --git a/mysql-test/t/index_merge_innodb2.test b/mysql-test/t/index_merge_innodb2.test
new file mode 100644
index 00000000000..ec4ea672bc1
--- /dev/null
+++ b/mysql-test/t/index_merge_innodb2.test
@@ -0,0 +1,52 @@
+#
+# 2-sweeps read Index_merge test
+#
+-- source include/have_innodb.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (
+ pk int primary key,
+ key1 int,
+ key2 int,
+ filler char(200),
+ filler2 char(200),
+ index(key1),
+ index(key2)
+) engine=innodb;
+
+
+--disable_query_log
+let $1=1000;
+while ($1)
+{
+ eval insert into t1 values($1, $1, $1, 'filler-data','filler-data-2');
+ dec $1;
+}
+--enable_query_log
+
+select * from t1 where (key1 >= 2 and key1 <= 10) or (pk >= 4 and pk <=8 );
+
+set @maxv=1000;
+
+select * from t1 where
+ (pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+ or key1=18 or key1=60;
+
+select * from t1 where
+ (pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+ or key1 < 3 or key1 > @maxv-11;
+
+select * from t1 where
+ (pk < 5) or (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 ) or (pk > @maxv-10)
+ or
+ (key1 < 5) or (key1 > 10 and key1 < 15) or (key1 >= 50 and key1 < 55 ) or (key1 > @maxv-10);
+
+select * from t1 where
+ (pk > 10 and pk < 15) or (pk >= 50 and pk < 55 )
+ or
+ (key1 < 5) or (key1 > @maxv-10);
+
+drop table t1;
diff --git a/mysql-test/t/index_merge_ror.test b/mysql-test/t/index_merge_ror.test
new file mode 100644
index 00000000000..3a484157267
--- /dev/null
+++ b/mysql-test/t/index_merge_ror.test
@@ -0,0 +1,250 @@
+#
+# ROR-index_merge tests.
+#
+--disable_warnings
+drop table if exists t0,t1,t2;
+--enable_warnings
+--disable_query_log
+create table t1
+(
+ /* Field names reflect value(rowid) distribution, st=STairs, swt= SaWTooth */
+ st_a int not null default 0,
+ swt1a int not null default 0,
+ swt2a int not null default 0,
+
+ st_b int not null default 0,
+ swt1b int not null default 0,
+ swt2b int not null default 0,
+
+ /* fields/keys for row retrieval tests */
+ key1 int,
+ key2 int,
+ key3 int,
+ key4 int,
+
+ /* make rows much bigger then keys */
+ filler1 char (200),
+ filler2 char (200),
+ filler3 char (200),
+ filler4 char (200),
+ filler5 char (200),
+ filler6 char (200),
+
+ /* order of keys is important */
+ key sta_swt12a(st_a,swt1a,swt2a),
+ key sta_swt1a(st_a,swt1a),
+ key sta_swt2a(st_a,swt2a),
+ key sta_swt21a(st_a,swt2a,swt1a),
+
+ key st_a(st_a),
+ key stb_swt1a_2b(st_b,swt1b,swt2a),
+ key stb_swt1b(st_b,swt1b),
+ key st_b(st_b),
+
+ key(key1),
+ key(key2),
+ key(key3),
+ key(key4)
+) ;
+
+# Fill table
+create table t0 as select * from t1;
+let $cnt=1000;
+while ($cnt)
+{
+ eval insert into t0 values (1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 'data1', 'data2', 'data3', 'data4', 'data5', 'data6');
+ dec $cnt;
+}
+
+alter table t1 disable keys;
+let $1=4;
+while ($1)
+{
+ let $2=4;
+ while ($2)
+ {
+ let $3=4;
+ while ($3)
+ {
+ eval insert into t1 select $1, $2, $3, $1 ,$2, $3, key1, key2, key3, key4, filler1, filler2, filler3, filler4, filler5, filler6 from t0;
+ dec $3;
+ }
+ dec $2;
+ }
+ dec $1;
+}
+
+# Row retrieval tests
+# -1 is used for values 'out of any range we are using'
+# insert enough rows for index intersection to be used for (key1,key2)
+insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 100, 100,'key1-key2-key3-key4');
+let $cnt=400;
+while ($cnt)
+{
+ eval insert into t1 (key1, key2, key3, key4, filler1) values (100, -1, 100, -1,'key1-key3');
+ dec $cnt;
+}
+let $cnt=400;
+while ($cnt)
+{
+ eval insert into t1 (key1, key2, key3, key4, filler1) values (-1, 100, -1, 100,'key2-key4');
+ dec $cnt;
+}
+alter table t1 enable keys;
+--enable_query_log
+select count(*) from t1;
+
+# One row results tests for cases where a single row matches all conditions
+explain select key1,key2 from t1 where key1=100 and key2=100;
+select key1,key2 from t1 where key1=100 and key2=100;
+
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+
+# Several-rows results
+insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1-key2');
+insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3');
+
+# ROR-intersection, not covering
+explain select key1,key2,filler1 from t1 where key1=100 and key2=100;
+select key1,key2,filler1 from t1 where key1=100 and key2=100;
+
+# ROR-intersection, covering
+explain select key1,key2 from t1 where key1=100 and key2=100;
+select key1,key2 from t1 where key1=100 and key2=100;
+
+# ROR-union of ROR-intersections
+explain select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+
+# 3-way ROR-intersection
+explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100;
+select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100;
+
+# ROR-union(ROR-intersection, ROR-range)
+insert into t1 (key1,key2,key3,key4,filler1) values (101,101,101,101, 'key1234-101');
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101;
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101;
+
+# Run some ROR updates/deletes
+select key1,key2, filler1 from t1 where key1=100 and key2=100;
+update t1 set filler1='to be deleted' where key1=100 and key2=100;
+update t1 set key1=200,key2=200 where key1=100 and key2=100;
+delete from t1 where key1=200 and key2=200;
+select key1,key2,filler1 from t1 where key2=100 and key2=200;
+
+# ROR-union(ROR-intersection) with one of ROR-intersection giving empty
+# results
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+
+delete from t1 where key3=100 and key4=100;
+
+# ROR-union with all ROR-intersections giving empty results
+explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
+
+# ROR-intersection with empty result
+explain select key1,key2 from t1 where key1=100 and key2=100;
+select key1,key2 from t1 where key1=100 and key2=100;
+
+# ROR-union tests with various cases.
+# All scans returning duplicate rows:
+insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-1');
+insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-2');
+insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3');
+
+explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+
+insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4');
+
+explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+
+insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3');
+
+explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
+
+##
+## Optimizer tests
+##
+
+# Check that the shortest key is used for ROR-intersection, covering and non-covering.
+explain select * from t1 where st_a=1 and st_b=1;
+explain select st_a,st_b from t1 where st_a=1 and st_b=1;
+
+# Check if "ingore index" syntax works
+explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1;
+
+# Do many tests
+# Check that keys that don't improve selectivity are skipped.
+#
+
+explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1;
+
+explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1;
+
+explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
+
+explain select * from t1 ignore index (sta_swt21a, stb_swt1a_2b)
+ where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
+
+explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b)
+ where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
+
+explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b, stb_swt1b)
+ where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1;
+
+explain select * from t1
+ where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1;
+
+explain select * from t1
+ where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
+
+explain select st_a from t1
+ where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
+
+explain select st_a from t1
+ where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1;
+
+drop table t0,t1;
+
+# 'Partially' covered fields test
+
+create table t2 (
+ a char(10),
+ b char(10),
+ filler1 char(255),
+ filler2 char(255),
+ key(a(5)),
+ key(b(5))
+);
+
+--disable_query_log
+let $1=8;
+while ($1)
+{
+ eval insert into t2 values (repeat(char($1+64), 8),repeat(char($1+64), 8),'filler1', 'filler2');
+ dec $1;
+}
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+--enable_query_log
+
+# The table row buffer is reused. Fill it with rows that don't match.
+select count(a) from t2 where a='BBBBBBBB';
+select count(a) from t2 where b='BBBBBBBB';
+
+# BUG#1:
+--replace_result a a_or_b b a_or_b
+explain select count(a) from t2 where a='AAAAAAAA' and b='AAAAAAAA';
+select count(a) from t2 where a='AAAAAAAA' and b='AAAAAAAA';
+select count(a) from t2 ignore index(a,b) where a='AAAAAAAA' and b='AAAAAAAA';
+
+insert into t2 values ('ab', 'ab', 'uh', 'oh');
+explain select a from t2 where a='ab';
+drop table t2;
diff --git a/mysql-test/t/index_merge_ror_cpk.test b/mysql-test/t/index_merge_ror_cpk.test
new file mode 100644
index 00000000000..94abf395d0a
--- /dev/null
+++ b/mysql-test/t/index_merge_ror_cpk.test
@@ -0,0 +1,111 @@
+#
+# Clustered PK ROR-index_merge tests
+#
+-- source include/have_innodb.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1
+(
+ pk1 int not null,
+ pk2 int not null,
+
+ key1 int not null,
+ key2 int not null,
+
+ pktail1ok int not null,
+ pktail2ok int not null,
+ pktail3bad int not null,
+ pktail4bad int not null,
+ pktail5bad int not null,
+
+ pk2copy int not null,
+ badkey int not null,
+
+ filler1 char (200),
+ filler2 char (200),
+ key (key1),
+ key (key2),
+
+ /* keys with tails from CPK members */
+ key (pktail1ok, pk1),
+ key (pktail2ok, pk1, pk2),
+ key (pktail3bad, pk2, pk1),
+ key (pktail4bad, pk1, pk2copy),
+ key (pktail5bad, pk1, pk2, pk2copy),
+
+ primary key (pk1, pk2)
+) engine=innodb;
+
+--disable_query_log
+set autocommit=0;
+let $1=10000;
+while ($1)
+{
+ eval insert into t1 values ($1 div 10,$1 mod 100, $1/100,$1/100, $1/100,$1/100,$1/100,$1/100,$1/100, $1 mod 100, $1/1000,'filler-data-$1','filler2');
+ dec $1;
+}
+set autocommit=1;
+--enable_query_log
+
+# Verify that range scan on CPK is ROR
+# (use index_intersection because it is impossible to check that for index union)
+explain select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
+# CPK scan + 1 ROR range scan is a special case
+select * from t1 where pk1 = 1 and pk2 < 80 and key1=0;
+
+# Verify that CPK fields are considered to be covered by index scans
+explain select pk1,pk2 from t1 where key1 = 10 and key2=10 and 2*pk1+1 < 2*96+1;
+select pk1,pk2 from t1 where key1 = 10 and key2=10 and 2*pk1+1 < 2*96+1;
+
+# Verify that CPK is always used for index intersection scans
+# (this is because it is used as a filter, not for retrieval)
+explain select * from t1 where badkey=1 and key1=10;
+--replace_result 38 ROWS 37 ROWS
+explain select * from t1 where pk1 < 7500 and key1 = 10;
+
+# Verify that keys with 'tails' of PK members are ok.
+explain select * from t1 where pktail1ok=1 and key1=10;
+explain select * from t1 where pktail2ok=1 and key1=10;
+
+select ' The following is actually a deficiency, it uses sort_union currently:' as 'note:';
+explain select * from t1 where (pktail2ok=1 and pk1< 50000) or key1=10;
+
+# The expected rows differs a bit from platform to platform
+--replace_result 98 ROWS 99 ROWS
+explain select * from t1 where pktail3bad=1 and key1=10;
+explain select * from t1 where pktail4bad=1 and key1=10;
+explain select * from t1 where pktail5bad=1 and key1=10;
+
+# Test for problem with innodb key values prefetch buffer:
+explain select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10;
+select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10;
+
+drop table t1;
+# Testcase for BUG#4984
+create table t1
+(
+ RUNID varchar(22),
+ SUBMITNR varchar(5),
+ ORDERNR char(1) ,
+ PROGRAMM varchar(8),
+ TESTID varchar(4),
+ UCCHECK char(1),
+ ETEXT varchar(80),
+ ETEXT_TYPE char(1),
+ INFO char(1),
+ SEVERITY tinyint(3),
+ TADIRFLAG char(1),
+ PRIMARY KEY (RUNID,SUBMITNR,ORDERNR,PROGRAMM,TESTID,UCCHECK),
+ KEY `TVERM~KEY` (PROGRAMM,TESTID,UCCHECK)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+update t1 set `ETEXT` = '', `ETEXT_TYPE`='', `INFO`='', `SEVERITY`='', `TADIRFLAG`=''
+WHERE
+ `RUNID`= '' AND `SUBMITNR`= '' AND `ORDERNR`='' AND `PROGRAMM`='' AND
+ `TESTID`='' AND `UCCHECK`='';
+
+drop table t1;
+
diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test
new file mode 100644
index 00000000000..b4cc118c62f
--- /dev/null
+++ b/mysql-test/t/information_schema.test
@@ -0,0 +1,466 @@
+# This test uses grants, which can't get tested for embedded server
+-- source include/not_embedded.inc
+
+# Test for information_schema.schemata &
+# show databases
+
+show variables where variable_name like "skip_show_database";
+grant select, update, execute on test.* to mysqltest_2@localhost;
+grant select, update on test.* to mysqltest_1@localhost;
+
+select * from information_schema.SCHEMATA where schema_name > 'm';
+select schema_name from information_schema.schemata;
+show databases like 't%';
+show databases;
+show databases where `database` = 't%';
+
+# Test for information_schema.tables &
+# show tables
+
+create database mysqltest;
+create table mysqltest.t1(a int, b VARCHAR(30), KEY string_data (b));
+create table test.t2(a int);
+create table t3(a int, KEY a_data (a));
+create table mysqltest.t4(a int);
+create view v1 (c) as select table_name from information_schema.TABLES;
+select * from v1;
+
+select c,table_name from v1
+inner join information_schema.TABLES v2 on (v1.c=v2.table_name)
+where v1.c like "t%";
+
+select c,table_name from v1
+left join information_schema.TABLES v2 on (v1.c=v2.table_name)
+where v1.c like "t%";
+
+select c, v2.table_name from v1
+right join information_schema.TABLES v2 on (v1.c=v2.table_name)
+where v1.c like "t%";
+
+select table_name from information_schema.TABLES
+where table_schema = "mysqltest" and table_name like "t%";
+
+select * from information_schema.STATISTICS where TABLE_SCHEMA = "mysqltest";
+show keys from t3 where Key_name = "a_data";
+
+show tables like 't%';
+--replace_column 8 # 12 # 13 #
+show table status;
+show full columns from t3 like "a%";
+show full columns from mysql.db like "Insert%";
+show full columns from v1;
+select * from information_schema.COLUMNS where table_name="t1"
+and column_name= "a";
+show columns from mysqltest.t1 where field like "%a%";
+
+grant select (a) on mysqltest.t1 to mysqltest_2@localhost;
+connect (user3,localhost,mysqltest_2,,);
+connection user3;
+select table_name, column_name, privileges from information_schema.columns
+where table_schema = 'mysqltest' and table_name = 't1';
+show columns from mysqltest.t1;
+connection default;
+
+drop view v1;
+drop tables mysqltest.t4, mysqltest.t1, t2, t3;
+drop database mysqltest;
+
+# Test for information_schema.CHARACTER_SETS &
+# SHOW CHARACTER SET
+
+select * from information_schema.CHARACTER_SETS
+where CHARACTER_SET_NAME like 'latin1%';
+SHOW CHARACTER SET LIKE 'latin1%';
+SHOW CHARACTER SET WHERE charset like 'latin1%';
+
+# Test for information_schema.COLLATIONS &
+# SHOW COLLATION
+
+select * from information_schema.COLLATIONS
+where COLLATION_NAME like 'latin1%';
+SHOW COLLATION LIKE 'latin1%';
+SHOW COLLATION WHERE collation like 'latin1%';
+
+select * from information_schema.COLLATION_CHARACTER_SET_APPLICABILITY
+where COLLATION_NAME like 'latin1%';
+
+# Test for information_schema.ROUTINES &
+#
+
+create function sub1(i int) returns int
+ return i+1;
+delimiter |;
+create procedure sel2()
+begin
+ select * from t1;
+ select * from t2;
+end|
+delimiter ;|
+
+#
+# Bug#7222 information_schema: errors in "routines"
+#
+select parameter_style, sql_data_access, dtd_identifier
+from information_schema.routines;
+
+--replace_column 5 # 6 #
+show procedure status;
+--replace_column 5 # 6 #
+show function status;
+select a.ROUTINE_NAME from information_schema.ROUTINES a,
+information_schema.SCHEMATA b where
+a.ROUTINE_SCHEMA = b.SCHEMA_NAME;
+--replace_column 3 #
+explain select a.ROUTINE_NAME from information_schema.ROUTINES a,
+information_schema.SCHEMATA b where
+a.ROUTINE_SCHEMA = b.SCHEMA_NAME;
+
+select a.ROUTINE_NAME, b.name from information_schema.ROUTINES a,
+mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8);
+select count(*) from information_schema.ROUTINES;
+
+connect (user1,localhost,mysqltest_1,,);
+connection user1;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+--error 1305
+show create function sub1;
+connection user3;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+connection default;
+grant all privileges on test.* to mysqltest_1@localhost;
+connect (user2,localhost,mysqltest_1,,);
+connection user2;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+create function sub2(i int) returns int
+ return i+1;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+show create procedure sel2;
+show create function sub1;
+show create function sub2;
+connection default;
+disconnect user1;
+drop function sub2;
+show create procedure sel2;
+
+#
+# Test for views
+#
+create view v0 (c) as select schema_name from information_schema.schemata;
+select * from v0;
+--replace_column 3 #
+explain select * from v0;
+create view v1 (c) as select table_name from information_schema.tables
+where table_name="v1";
+select * from v1;
+create view v2 (c) as select column_name from information_schema.columns
+where table_name="v2";
+select * from v2;
+create view v3 (c) as select CHARACTER_SET_NAME from information_schema.character_sets
+where CHARACTER_SET_NAME like "latin1%";
+select * from v3;
+create view v4 (c) as select COLLATION_NAME from information_schema.collations
+where COLLATION_NAME like "latin1%";
+select * from v4;
+show keys from v4;
+select * from information_schema.views where TABLE_NAME like "v%";
+drop view v0, v1, v2, v3, v4;
+
+#
+# Test for privileges tables
+#
+create table t1 (a int);
+grant select,update,insert on t1 to mysqltest_1@localhost;
+grant select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost;
+grant all on test.* to mysqltest_1@localhost with grant option;
+select * from information_schema.USER_PRIVILEGES where grantee like '%mysqltest_1%';
+select * from information_schema.SCHEMA_PRIVILEGES where grantee like '%mysqltest_1%';
+select * from information_schema.TABLE_PRIVILEGES where grantee like '%mysqltest_1%';
+select * from information_schema.COLUMN_PRIVILEGES where grantee like '%mysqltest_1%';
+delete from mysql.user where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.db where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.tables_priv where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.columns_priv where user='mysqltest_1' or user='mysqltest_2';
+flush privileges;
+drop table t1;
+
+
+#
+# Test for KEY_COLUMN_USAGE & TABLE_CONSTRAINTS tables
+#
+
+create table t1 (a int null, primary key(a));
+alter table t1 add constraint constraint_1 unique (a);
+alter table t1 add constraint unique key_1(a);
+alter table t1 add constraint constraint_2 unique key_2(a);
+show create table t1;
+select * from information_schema.TABLE_CONSTRAINTS where
+TABLE_SCHEMA= "test";
+select * from information_schema.KEY_COLUMN_USAGE where
+TABLE_SCHEMA= "test";
+
+connection user2;
+select table_name from information_schema.TABLES where table_schema like "test%";
+select table_name,column_name from information_schema.COLUMNS where table_schema like "test%";
+select ROUTINE_NAME from information_schema.ROUTINES;
+disconnect user2;
+connection default;
+delete from mysql.user where user='mysqltest_1';
+drop table t1;
+drop procedure sel2;
+drop function sub1;
+
+create table t1(a int);
+create view v1 (c) as select a from t1 with check option;
+create view v2 (c) as select a from t1 WITH LOCAL CHECK OPTION;
+create view v3 (c) as select a from t1 WITH CASCADED CHECK OPTION;
+select * from information_schema.views;
+grant select (a) on test.t1 to joe@localhost with grant option;
+select * from INFORMATION_SCHEMA.COLUMN_PRIVILEGES;
+select * from INFORMATION_SCHEMA.TABLE_PRIVILEGES;
+drop view v1, v2, v3;
+drop table t1;
+delete from mysql.user where user='joe';
+delete from mysql.db where user='joe';
+delete from mysql.tables_priv where user='joe';
+delete from mysql.columns_priv where user='joe';
+flush privileges;
+
+# QQ This results in NULLs instead of the version numbers when
+# QQ a LOCK TABLES is in effect when selecting from
+# QQ information_schema.tables. Until this bug has been fixed,
+# QQ this test is disabled /pem
+#delimiter //;
+#create procedure px5 ()
+#begin
+#declare v int;
+#declare c cursor for select version from
+#information_schema.tables where table_schema <> 'information_schema';
+#open c;
+#fetch c into v;
+#select v;
+#close c;
+#end;//
+#
+#call px5()//
+#call px5()//
+#delimiter ;//
+#select sql_mode from information_schema.ROUTINES;
+#drop procedure px5;
+
+create table t1 (a int not null auto_increment,b int, primary key (a));
+insert into t1 values (1,1),(NULL,3),(NULL,4);
+select AUTO_INCREMENT from information_schema.tables where table_name = 't1';
+drop table t1;
+
+create table t1 (s1 int);
+insert into t1 values (0),(9),(0);
+select s1 from t1 where s1 in (select version from
+information_schema.tables) union select version from
+information_schema.tables;
+drop table t1;
+
+SHOW CREATE TABLE INFORMATION_SCHEMA.character_sets;
+set names latin2;
+SHOW CREATE TABLE INFORMATION_SCHEMA.character_sets;
+set names latin1;
+
+create table t1 select * from information_schema.CHARACTER_SETS
+where CHARACTER_SET_NAME like "latin1";
+select * from t1;
+alter table t1 default character set utf8;
+show create table t1;
+drop table t1;
+
+create view v1 as select * from information_schema.TABLES;
+drop view v1;
+create table t1(a NUMERIC(5,3), b NUMERIC(5,1), c float(5,2),
+ d NUMERIC(6,4), e float, f DECIMAL(6,3), g int(11), h DOUBLE(10,3),
+ i DOUBLE);
+select COLUMN_NAME,COLUMN_TYPE, CHARACTER_MAXIMUM_LENGTH,
+ CHARACTER_OCTET_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE
+from information_schema.columns where table_name= 't1';
+drop table t1;
+
+create table t115 as select table_name, column_name, column_type
+from information_schema.columns where table_name = 'proc';
+select * from t115;
+drop table t115;
+
+delimiter //;
+create procedure p108 () begin declare c cursor for select data_type
+from information_schema.columns; open c; open c; end;//
+--error 1325
+call p108()//
+delimiter ;//
+drop procedure p108;
+
+create view v1 as select A1.table_name from information_schema.TABLES A1
+where table_name= "user";
+select * from v1;
+drop view v1;
+
+create view vo as select 'a' union select 'a';
+show index from vo;
+select * from information_schema.TABLE_CONSTRAINTS where
+TABLE_NAME= "vo";
+select * from information_schema.KEY_COLUMN_USAGE where
+TABLE_NAME= "vo";
+drop view vo;
+
+select TABLE_NAME,TABLE_TYPE,ENGINE
+from information_schema.tables
+where table_schema='information_schema' limit 2;
+show tables from information_schema like "T%";
+
+--error 1007
+create database information_schema;
+use information_schema;
+show full tables like "T%";
+--error 1109
+create table t1(a int);
+use test;
+show tables;
+use information_schema;
+show tables like "T%";
+
+#
+# Bug#7210: information_schema: can't access when table-name = reserved word
+#
+select table_name from tables where table_name='user';
+select column_name, privileges from columns
+where table_name='user' and column_name like '%o%';
+
+#
+# Bug#7212: information_schema: "Can't find file" errors if storage engine gone
+# Bug#7211: information_schema: crash if bad view
+#
+use test;
+create function sub1(i int) returns int
+ return i+1;
+create table t1(f1 int);
+create view t2 (c) as select f1 from t1;
+create view t3 (c) as select sub1(1);
+create table t4(f1 int, KEY f1_key (f1));
+drop table t1;
+drop function sub1;
+select table_name from information_schema.views
+where table_schema='test';
+select table_name from information_schema.views
+where table_schema='test';
+select column_name from information_schema.columns
+where table_schema='test';
+select index_name from information_schema.statistics where table_schema='test';
+select constraint_name from information_schema.table_constraints
+where table_schema='test';
+drop view t2;
+drop view t3;
+drop table t4;
+
+#
+# Bug#7213: information_schema: redundant non-standard TABLE_NAMES table
+#
+--error 1109
+select * from information_schema.table_names;
+
+#
+# Bug#2719 information_schema: errors in "columns"
+#
+select column_type from information_schema.columns
+where table_schema="information_schema" and table_name="COLUMNS" and
+(column_name="character_set_name" or column_name="collation_name");
+
+#
+# Bug#2718 information_schema: errors in "tables"
+#
+select TABLE_ROWS from information_schema.tables where
+table_schema="information_schema" and table_name="COLUMNS";
+select table_type from information_schema.tables
+where table_schema="mysql" and table_name="user";
+
+# test for 'show open tables ... where'
+show open tables where `table` like "user";
+# test for 'show status ... where'
+show status where variable_name like "%database%";
+# test for 'show variables ... where'
+show variables where variable_name like "skip_show_databas";
+
+#
+# Bug #7981:SHOW GLOBAL STATUS crashes server
+#
+show global status like "Threads_running";
+
+#
+# Bug #7915 crash,JOIN VIEW, subquery,
+# SELECT .. FROM INFORMATION_SCHEMA.COLUMNS
+#
+create table t1(f1 int);
+create table t2(f2 int);
+create view v1 as select * from t1, t2;
+set @got_val= (select count(*) from information_schema.columns);
+drop view v1;
+drop table t1, t2;
+
+#
+# Bug #7476: crash on SELECT * FROM INFORMATION_SCHEMA.TABLES
+#
+
+CREATE TABLE t_crashme ( f1 BIGINT);
+CREATE VIEW a1 (t_CRASHME) AS SELECT f1 FROM t_crashme GROUP BY f1;
+CREATE VIEW a2 AS SELECT t_CRASHME FROM a1;
+let $tab_count= 65;
+--disable_query_log
+while ($tab_count)
+{
+ EVAL CREATE TABLE t_$tab_count (f1 BIGINT);
+ dec $tab_count ;
+}
+--disable_result_log
+SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES;
+--enable_result_log
+SELECT count(*) FROM INFORMATION_SCHEMA.TABLES;
+let $tab_count= 65;
+while ($tab_count)
+{
+ EVAL DROP TABLE t_$tab_count;
+ dec $tab_count ;
+}
+--enable_query_log
+drop view a2, a1;
+drop table t_crashme;
+
+#
+# Bug #7215 information_schema: columns are longtext instead of varchar
+# Bug #7217 information_schema: columns are varbinary() instead of timestamp
+#
+select table_schema,table_name, column_name from
+information_schema.columns
+where data_type = 'longtext';
+select table_name, column_name, data_type from information_schema.columns
+where data_type = 'datetime';
+
+#
+# Bug #8164 subquery with INFORMATION_SCHEMA.COLUMNS, 100 % CPU
+#
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES A
+WHERE NOT EXISTS
+(SELECT * FROM INFORMATION_SCHEMA.COLUMNS B
+ WHERE A.TABLE_SCHEMA = B.TABLE_SCHEMA
+ AND A.TABLE_NAME = B.TABLE_NAME);
+
+#
+# Bug #9344 INFORMATION_SCHEMA, wrong content, numeric columns
+#
+
+create table t1
+( x_bigint BIGINT,
+ x_integer INTEGER,
+ x_smallint SMALLINT,
+ x_decimal DECIMAL(5,3),
+ x_numeric NUMERIC(5,3),
+ x_real REAL,
+ x_float FLOAT,
+ x_double_precision DOUBLE PRECISION );
+SELECT COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH
+FROM INFORMATION_SCHEMA.COLUMNS
+WHERE TABLE_NAME= 't1';
+drop table t1;
diff --git a/mysql-test/t/information_schema_inno.test b/mysql-test/t/information_schema_inno.test
new file mode 100644
index 00000000000..af8bd9f98b8
--- /dev/null
+++ b/mysql-test/t/information_schema_inno.test
@@ -0,0 +1,19 @@
+-- source include/have_innodb.inc
+--disable_warnings
+DROP TABLE IF EXISTS t1,t2;
+--enable_warnings
+
+#
+# Test for KEY_COLUMN_USAGE & TABLE_CONSTRAINTS tables
+#
+
+CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
+CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id),
+FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE,
+FOREIGN KEY (t1_id) REFERENCES t1(id) ON UPDATE CASCADE) ENGINE=INNODB;
+select * from information_schema.TABLE_CONSTRAINTS where
+TABLE_SCHEMA= "test";
+select * from information_schema.KEY_COLUMN_USAGE where
+TABLE_SCHEMA= "test";
+
+drop table t2, t1;
diff --git a/mysql-test/t/init_connect.test b/mysql-test/t/init_connect.test
index 29962abc04d..d9682eb8122 100644
--- a/mysql-test/t/init_connect.test
+++ b/mysql-test/t/init_connect.test
@@ -19,7 +19,7 @@ connect (con3,localhost,user_1,,);
connection con3;
select @a;
connection con0;
-set global init_connect="create table t1(a char(10));\
+set global init_connect="drop table if exists t1; create table t1(a char(10));\
insert into t1 values ('\0');insert into t1 values('abc')";
connect (con4,localhost,user_1,,);
connection con4;
diff --git a/mysql-test/t/innodb-big.test b/mysql-test/t/innodb-big.test
new file mode 100644
index 00000000000..ade69ffdb45
--- /dev/null
+++ b/mysql-test/t/innodb-big.test
@@ -0,0 +1,46 @@
+#
+# Test some things that takes a long time
+
+-- source include/big_test.inc
+-- source include/have_innodb.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2, t3, t4;
+--enable_warnings
+
+#
+# Test test how filesort and buffered-record-reads works with innodb
+#
+
+CREATE TABLE t1 (id INTEGER) ENGINE=MYISAM;
+CREATE TABLE t2 (id INTEGER primary key) ENGINE=INNODB;
+CREATE TABLE t3 (a char(32) primary key,id INTEGER) ENGINE=INNODB;
+CREATE TABLE t4 (a char(32) primary key,id INTEGER) ENGINE=MYISAM;
+
+INSERT INTO t1 (id) VALUES (1);
+INSERT INTO t1 SELECT id+1 FROM t1;
+INSERT INTO t1 SELECT id+2 FROM t1;
+INSERT INTO t1 SELECT id+4 FROM t1;
+INSERT INTO t1 SELECT id+8 FROM t1;
+INSERT INTO t1 SELECT id+16 FROM t1;
+INSERT INTO t1 SELECT id+32 FROM t1;
+INSERT INTO t1 SELECT id+64 FROM t1;
+INSERT INTO t1 SELECT id+128 FROM t1;
+INSERT INTO t1 SELECT id+256 FROM t1;
+INSERT INTO t1 SELECT id+512 FROM t1;
+INSERT INTO t1 SELECT id+1024 FROM t1;
+INSERT INTO t1 SELECT id+2048 FROM t1;
+INSERT INTO t1 SELECT id+4096 FROM t1;
+INSERT INTO t1 SELECT id+8192 FROM t1;
+INSERT INTO t1 SELECT id+16384 FROM t1;
+INSERT INTO t1 SELECT id+32768 FROM t1;
+INSERT INTO t1 SELECT id+65536 FROM t1;
+INSERT INTO t1 SELECT id+131072 FROM t1;
+INSERT INTO t1 SELECT id+262144 FROM t1;
+INSERT INTO t1 SELECT id+524288 FROM t1;
+INSERT INTO t1 SELECT id+1048576 FROM t1;
+INSERT INTO t2 SELECT * FROM t1;
+INSERT INTO t3 SELECT concat(id),id from t2 ORDER BY -id;
+INSERT INTO t4 SELECT * from t3 ORDER BY concat(a);
+select sum(id) from t3;
+drop table t1,t2,t3,t4;
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 7501889127a..bd07d2220d2 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -129,6 +129,32 @@ insert into t1 values (6);
-- error 1062
insert into t1 values (4);
select n from t1;
+set autocommit=0;
+#
+# savepoints
+#
+begin;
+savepoint `my_savepoint`;
+insert into t1 values (7);
+savepoint `savept2`;
+insert into t1 values (3);
+select n from t1;
+savepoint savept3;
+rollback to savepoint savept2;
+--error 1305
+rollback to savepoint savept3;
+rollback to savepoint savept2;
+release savepoint `my_savepoint`;
+select n from t1;
+-- error 1305
+rollback to savepoint `my_savepoint`;
+--error 1305
+rollback to savepoint savept2;
+insert into t1 values (8);
+savepoint sv;
+commit;
+savepoint sv;
+set autocommit=1;
# nop
rollback;
drop table t1;
@@ -589,6 +615,7 @@ truncate table t1;
insert into t1 values(1),(2);
select * from t1;
truncate table t1;
+truncate table t1;
insert into t1 values(1),(2);
delete from t1;
select * from t1;
@@ -999,7 +1026,7 @@ CREATE TABLE t1 (
`id` int(10) unsigned NOT NULL auto_increment,
`id_object` int(10) unsigned default '0',
`id_version` int(10) unsigned NOT NULL default '1',
- label varchar(100) NOT NULL default '',
+ `label` varchar(100) NOT NULL default '',
`description` text,
PRIMARY KEY (`id`),
KEY `id_object` (`id_object`),
@@ -1017,8 +1044,8 @@ CREATE TABLE t2 (
INSERT INTO t2 VALUES("3524", "1"),("3525", "1"),("1794", "4"),("102", "5"),("1822", "6"),("3382", "9");
-SELECT t2.id, t1.label FROM t2 INNER JOIN
-(SELECT t1.id_object as id_object FROM t1 WHERE t1.label LIKE '%test%') AS lbl
+SELECT t2.id, t1.`label` FROM t2 INNER JOIN
+(SELECT t1.id_object as id_object FROM t1 WHERE t1.`label` LIKE '%test%') AS lbl
ON (t2.id = lbl.id_object) INNER JOIN t1 ON (t2.id = t1.id_object);
drop table t1,t2;
@@ -1029,8 +1056,8 @@ insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
insert t2 select * from t1;
insert t3 select * from t1;
checksum table t1, t2, t3, t4 quick;
-checksum table t1, t2, t3, t4;
-checksum table t1, t2, t3, t4 extended;
+checksum table t1, t2, t3;
+checksum table t1, t2, t3 extended;
#show table status;
drop table t1,t2,t3;
@@ -1098,7 +1125,10 @@ show create table t2;
drop table t2;
# Test error handling
---replace_result \\ / $MYSQL_TEST_DIR . /var/master-data/ /
+
+# Clean up filename -- embedded server reports whole path without .frm,
+# regular server reports relative path with .frm (argh!)
+--replace_result \\ / $MYSQL_TEST_DIR . /var/master-data/ / t2.frm t2
--error 1005
create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id2,id) references t1 (id)) engine = innodb;
@@ -1144,6 +1174,27 @@ delete from t1;
commit;
show status like "binlog_cache_use";
show status like "binlog_cache_disk_use";
+drop table t1;
+
+#
+# range optimizer problem
+#
+
+create table t1 (x bigint unsigned not null primary key) engine=innodb;
+insert into t1(x) values (0xfffffffffffffff0),(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;
+explain select count(*) from t1 where x > -16;
+
+# The following result should be (2). To be fixed when we add 'unsigned flag' to
+# Field::store(longlong)
+select count(*) from t1 where x > -16;
+select * from t1 where x > -16;
+select count(*) from t1 where x = 18446744073709551601;
drop table t1;
@@ -1168,3 +1219,84 @@ alter table t1 add key (c1,c2,c1);
--error 1060
alter table t1 add key (c1,c1,c2);
drop table t1;
+
+# Test for testable InnoDB status variables. This test
+# uses previous ones(pages_created, rows_deleted, ...).
+show status like "Innodb_buffer_pool_pages_total";
+show status like "Innodb_page_size";
+show status like "Innodb_rows_deleted";
+show status like "Innodb_rows_inserted";
+show status like "Innodb_rows_updated";
+
+# Test for row locks InnoDB status variables.
+show status like "Innodb_row_lock_waits";
+show status like "Innodb_row_lock_current_waits";
+show status like "Innodb_row_lock_time";
+show status like "Innodb_row_lock_time_max";
+show status like "Innodb_row_lock_time_avg";
+
+# Test for innodb_sync_spin_loops variable
+show variables like "innodb_sync_spin_loops";
+set global innodb_sync_spin_loops=1000;
+show variables like "innodb_sync_spin_loops";
+set global innodb_sync_spin_loops=0;
+show variables like "innodb_sync_spin_loops";
+set global innodb_sync_spin_loops=20;
+show variables like "innodb_sync_spin_loops";
+
+# Test for innodb_thread_concurrency variable
+show variables like "innodb_thread_concurrency";
+set global innodb_thread_concurrency=1000;
+show variables like "innodb_thread_concurrency";
+set global innodb_thread_concurrency=0;
+show variables like "innodb_thread_concurrency";
+set global innodb_thread_concurrency=16;
+show variables like "innodb_thread_concurrency";
+
+# Test for innodb_concurrency_tickets variable
+show variables like "innodb_concurrency_tickets";
+set global innodb_concurrency_tickets=1000;
+show variables like "innodb_concurrency_tickets";
+set global innodb_concurrency_tickets=0;
+show variables like "innodb_concurrency_tickets";
+set global innodb_concurrency_tickets=500;
+show variables like "innodb_concurrency_tickets";
+
+# Test for innodb_thread_sleep_delay variable
+show variables like "innodb_thread_sleep_delay";
+set global innodb_thread_sleep_delay=100000;
+show variables like "innodb_thread_sleep_delay";
+set global innodb_thread_sleep_delay=0;
+show variables like "innodb_thread_sleep_delay";
+set global innodb_thread_sleep_delay=10000;
+show variables like "innodb_thread_sleep_delay";
+
+#
+# Test varchar
+#
+
+let $default=`select @@storage_engine`;
+set storage_engine=INNODB;
+source include/varchar.inc;
+
+#
+# Some errors/warnings on create
+#
+
+# Clean up filename -- embedded server reports whole path without .frm,
+# regular server reports relative path with .frm (argh!)
+--replace_result \\ / $MYSQL_TEST_DIR . /var/master-data/ / t1.frm t1
+--error 1005
+create table t1 (v varchar(65530), key(v));
+create table t1 (v varchar(65536));
+show create table t1;
+drop table t1;
+create table t1 (v varchar(65530) character set utf8);
+show create table t1;
+drop table t1;
+
+eval set storage_engine=$default;
+
+# InnoDB specific varchar tests
+create table t1 (v varchar(16384)) engine=innodb;
+drop table t1;
diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test
index f5acab05108..e977de94871 100644
--- a/mysql-test/t/insert.test
+++ b/mysql-test/t/insert.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 (a int not null);
@@ -87,6 +87,7 @@ use mysqltest;
create table t1 (c int);
insert into mysqltest.t1 set mysqltest.t1.c = '1';
drop database mysqltest;
+use test;
#
# Test of wrong values for float data (bug #2082)
@@ -94,7 +95,6 @@ drop database mysqltest;
# PS gives sligthly different numbers for max-float/max-double
--disable_ps_protocol
-use test;
create table t1(number int auto_increment primary key, original_value varchar(50), f_double double, f_float float, f_double_7_2 double(7,2), f_float_4_3 float (4,3), f_double_u double unsigned, f_float_u float unsigned, f_double_15_1_u double(15,1) unsigned, f_float_3_1_u float (3,1) unsigned);
set @value= "aa";
@@ -122,15 +122,11 @@ insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@val
--replace_result e-0 e- e+0 e+
--query_vertical select * from t1 where number =last_insert_id()
+--error 1367
set @value= 1e+1111111111;
-insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
---replace_result e-0 e- e+0 e+
---query_vertical select * from t1 where number =last_insert_id()
-
+--error 1367
set @value= -1e+1111111111;
-insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
---replace_result e-0 e- e+0 e+
---query_vertical select * from t1 where number =last_insert_id()
+
set @value= 1e+111;
insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@value,@value);
@@ -154,3 +150,31 @@ insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@val
drop table t1;
--enable_ps_protocol
+
+create table t1(id1 int not null auto_increment primary key, t char(12));
+create table t2(id2 int not null, t char(12));
+create table t3(id3 int not null, t char(12), index(id3));
+disable_query_log;
+let $1 = 100;
+while ($1)
+ {
+ let $2 = 5;
+ eval insert into t1(t) values ('$1');
+ while ($2)
+ {
+ eval insert into t2(id2,t) values ($1,'$2');
+ let $3 = 10;
+ while ($3)
+ {
+ eval insert into t3(id3,t) values ($1,'$2');
+ dec $3;
+ }
+ dec $2;
+ }
+ dec $1;
+ }
+enable_query_log;
+select count(*) from t2;
+insert into t2 select t1.* from t1, t2 t, t3 where t1.id1 = t.id2 and t.id2 = t3.id3;
+select count(*) from t2;
+drop table t1,t2,t3;
diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test
index ecc83e3883b..40dc4e20093 100644
--- a/mysql-test/t/insert_select.test
+++ b/mysql-test/t/insert_select.test
@@ -105,9 +105,7 @@ insert into t2 values (2,"t2:2"), (3,"t2:3");
insert into t1 select * from t2;
select * from t1;
# REPLACE .. SELECT is not yet supported by PS
---disable_ps_protocol
replace into t1 select * from t2;
---enable_ps_protocol
select * from t1;
drop table t1,t2;
diff --git a/mysql-test/t/isam.test b/mysql-test/t/isam.test
deleted file mode 100644
index f77d29fd20f..00000000000
--- a/mysql-test/t/isam.test
+++ /dev/null
@@ -1,247 +0,0 @@
--- source include/have_isam.inc
-
---disable_warnings
-drop table if exists t1,t2;
---enable_warnings
-
-#
-# Test possible problem with rows that are about 65535 bytes long
-#
-
-create table t1 (a tinyint not null auto_increment, b blob not null, primary key (a)) engine=isam;
-
-let $1=100;
-disable_query_log;
---disable_warnings
-while ($1)
-{
- eval insert into t1 (b) values(repeat(char(65+$1),65540-$1));
- dec $1;
-}
-enable_query_log;
---enable_warnings
-delete from t1 where (a & 1);
-select sum(length(b)) from t1;
-drop table t1;
-
-#
-# Test of auto_increment; The test for BDB tables is in bdb.test
-#
-
-create table t1 (a int not null auto_increment,b int, primary key (a)) engine=isam;
-insert into t1 values (1,1),(NULL,2),(3,3),(NULL,4);
-delete from t1 where a=4 or a=2;
-insert into t1 values (NULL,4),(NULL,5),(6,6);
-select * from t1;
-delete from t1 where a=6;
-#show table status like "t1";
-replace t1 values (3,1);
-replace t1 values (3,3);
-ALTER TABLE t1 add c int;
-insert into t1 values (NULL,6,6);
-select * from t1;
-drop table t1;
-
-#
-# Test of some CREATE TABLE's that should fail
-#
---error 1121
-create table t1 (a int,b text, index(a)) engine=isam;
---error 1073
-create table t1 (a int,b text, index(b)) engine=isam;
---error 1075
-create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) engine=isam;
---error 1121
-create table t1 (ordid int(8), unique (ordid)) engine=isam;
-drop table if exists t1;
-
-#
-# Test of some show commands
-#
-
-create table t1 (a int not null primary key, b int not null,c int not null, key(b,c));
-insert into t1 values (1,2,2),(2,2,3),(3,2,4),(4,2,4);
-create table t2 engine=isam select * from t1;
-optimize table t1;
-check table t1,t2;
-repair table t1,t2;
-check table t2,t1;
-lock tables t1 write;
-check table t2,t1;
-show columns from t1;
-show full columns from t1;
-show index from t1;
-drop table t1,t2;
-
-#
-# test of table with huge number of packed fields
-#
-
-create table t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
-int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int, i17
-int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
-i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
-int, i35 int, i36 int, i37 int, i38 int, i39 int, i40 int, i41 int, i42 int,
-i43 int, i44 int, i45 int, i46 int, i47 int, i48 int, i49 int, i50 int, i51
-int, i52 int, i53 int, i54 int, i55 int, i56 int, i57 int, i58 int, i59 int,
-i60 int, i61 int, i62 int, i63 int, i64 int, i65 int, i66 int, i67 int, i68
-int, i69 int, i70 int, i71 int, i72 int, i73 int, i74 int, i75 int, i76 int,
-i77 int, i78 int, i79 int, i80 int, i81 int, i82 int, i83 int, i84 int, i85
-int, i86 int, i87 int, i88 int, i89 int, i90 int, i91 int, i92 int, i93 int,
-i94 int, i95 int, i96 int, i97 int, i98 int, i99 int, i100 int, i101 int, i102
-int, i103 int, i104 int, i105 int, i106 int, i107 int, i108 int, i109 int, i110
-int, i111 int, i112 int, i113 int, i114 int, i115 int, i116 int, i117 int, i118
-int, i119 int, i120 int, i121 int, i122 int, i123 int, i124 int, i125 int, i126
-int, i127 int, i128 int, i129 int, i130 int, i131 int, i132 int, i133 int, i134
-int, i135 int, i136 int, i137 int, i138 int, i139 int, i140 int, i141 int, i142
-int, i143 int, i144 int, i145 int, i146 int, i147 int, i148 int, i149 int, i150
-int, i151 int, i152 int, i153 int, i154 int, i155 int, i156 int, i157 int, i158
-int, i159 int, i160 int, i161 int, i162 int, i163 int, i164 int, i165 int, i166
-int, i167 int, i168 int, i169 int, i170 int, i171 int, i172 int, i173 int, i174
-int, i175 int, i176 int, i177 int, i178 int, i179 int, i180 int, i181 int, i182
-int, i183 int, i184 int, i185 int, i186 int, i187 int, i188 int, i189 int, i190
-int, i191 int, i192 int, i193 int, i194 int, i195 int, i196 int, i197 int, i198
-int, i199 int, i200 int, i201 int, i202 int, i203 int, i204 int, i205 int, i206
-int, i207 int, i208 int, i209 int, i210 int, i211 int, i212 int, i213 int, i214
-int, i215 int, i216 int, i217 int, i218 int, i219 int, i220 int, i221 int, i222
-int, i223 int, i224 int, i225 int, i226 int, i227 int, i228 int, i229 int, i230
-int, i231 int, i232 int, i233 int, i234 int, i235 int, i236 int, i237 int, i238
-int, i239 int, i240 int, i241 int, i242 int, i243 int, i244 int, i245 int, i246
-int, i247 int, i248 int, i249 int, i250 int, i251 int, i252 int, i253 int, i254
-int, i255 int, i256 int, i257 int, i258 int, i259 int, i260 int, i261 int, i262
-int, i263 int, i264 int, i265 int, i266 int, i267 int, i268 int, i269 int, i270
-int, i271 int, i272 int, i273 int, i274 int, i275 int, i276 int, i277 int, i278
-int, i279 int, i280 int, i281 int, i282 int, i283 int, i284 int, i285 int, i286
-int, i287 int, i288 int, i289 int, i290 int, i291 int, i292 int, i293 int, i294
-int, i295 int, i296 int, i297 int, i298 int, i299 int, i300 int, i301 int, i302
-int, i303 int, i304 int, i305 int, i306 int, i307 int, i308 int, i309 int, i310
-int, i311 int, i312 int, i313 int, i314 int, i315 int, i316 int, i317 int, i318
-int, i319 int, i320 int, i321 int, i322 int, i323 int, i324 int, i325 int, i326
-int, i327 int, i328 int, i329 int, i330 int, i331 int, i332 int, i333 int, i334
-int, i335 int, i336 int, i337 int, i338 int, i339 int, i340 int, i341 int, i342
-int, i343 int, i344 int, i345 int, i346 int, i347 int, i348 int, i349 int, i350
-int, i351 int, i352 int, i353 int, i354 int, i355 int, i356 int, i357 int, i358
-int, i359 int, i360 int, i361 int, i362 int, i363 int, i364 int, i365 int, i366
-int, i367 int, i368 int, i369 int, i370 int, i371 int, i372 int, i373 int, i374
-int, i375 int, i376 int, i377 int, i378 int, i379 int, i380 int, i381 int, i382
-int, i383 int, i384 int, i385 int, i386 int, i387 int, i388 int, i389 int, i390
-int, i391 int, i392 int, i393 int, i394 int, i395 int, i396 int, i397 int, i398
-int, i399 int, i400 int, i401 int, i402 int, i403 int, i404 int, i405 int, i406
-int, i407 int, i408 int, i409 int, i410 int, i411 int, i412 int, i413 int, i414
-int, i415 int, i416 int, i417 int, i418 int, i419 int, i420 int, i421 int, i422
-int, i423 int, i424 int, i425 int, i426 int, i427 int, i428 int, i429 int, i430
-int, i431 int, i432 int, i433 int, i434 int, i435 int, i436 int, i437 int, i438
-int, i439 int, i440 int, i441 int, i442 int, i443 int, i444 int, i445 int, i446
-int, i447 int, i448 int, i449 int, i450 int, i451 int, i452 int, i453 int, i454
-int, i455 int, i456 int, i457 int, i458 int, i459 int, i460 int, i461 int, i462
-int, i463 int, i464 int, i465 int, i466 int, i467 int, i468 int, i469 int, i470
-int, i471 int, i472 int, i473 int, i474 int, i475 int, i476 int, i477 int, i478
-int, i479 int, i480 int, i481 int, i482 int, i483 int, i484 int, i485 int, i486
-int, i487 int, i488 int, i489 int, i490 int, i491 int, i492 int, i493 int, i494
-int, i495 int, i496 int, i497 int, i498 int, i499 int, i500 int, i501 int, i502
-int, i503 int, i504 int, i505 int, i506 int, i507 int, i508 int, i509 int, i510
-int, i511 int, i512 int, i513 int, i514 int, i515 int, i516 int, i517 int, i518
-int, i519 int, i520 int, i521 int, i522 int, i523 int, i524 int, i525 int, i526
-int, i527 int, i528 int, i529 int, i530 int, i531 int, i532 int, i533 int, i534
-int, i535 int, i536 int, i537 int, i538 int, i539 int, i540 int, i541 int, i542
-int, i543 int, i544 int, i545 int, i546 int, i547 int, i548 int, i549 int, i550
-int, i551 int, i552 int, i553 int, i554 int, i555 int, i556 int, i557 int, i558
-int, i559 int, i560 int, i561 int, i562 int, i563 int, i564 int, i565 int, i566
-int, i567 int, i568 int, i569 int, i570 int, i571 int, i572 int, i573 int, i574
-int, i575 int, i576 int, i577 int, i578 int, i579 int, i580 int, i581 int, i582
-int, i583 int, i584 int, i585 int, i586 int, i587 int, i588 int, i589 int, i590
-int, i591 int, i592 int, i593 int, i594 int, i595 int, i596 int, i597 int, i598
-int, i599 int, i600 int, i601 int, i602 int, i603 int, i604 int, i605 int, i606
-int, i607 int, i608 int, i609 int, i610 int, i611 int, i612 int, i613 int, i614
-int, i615 int, i616 int, i617 int, i618 int, i619 int, i620 int, i621 int, i622
-int, i623 int, i624 int, i625 int, i626 int, i627 int, i628 int, i629 int, i630
-int, i631 int, i632 int, i633 int, i634 int, i635 int, i636 int, i637 int, i638
-int, i639 int, i640 int, i641 int, i642 int, i643 int, i644 int, i645 int, i646
-int, i647 int, i648 int, i649 int, i650 int, i651 int, i652 int, i653 int, i654
-int, i655 int, i656 int, i657 int, i658 int, i659 int, i660 int, i661 int, i662
-int, i663 int, i664 int, i665 int, i666 int, i667 int, i668 int, i669 int, i670
-int, i671 int, i672 int, i673 int, i674 int, i675 int, i676 int, i677 int, i678
-int, i679 int, i680 int, i681 int, i682 int, i683 int, i684 int, i685 int, i686
-int, i687 int, i688 int, i689 int, i690 int, i691 int, i692 int, i693 int, i694
-int, i695 int, i696 int, i697 int, i698 int, i699 int, i700 int, i701 int, i702
-int, i703 int, i704 int, i705 int, i706 int, i707 int, i708 int, i709 int, i710
-int, i711 int, i712 int, i713 int, i714 int, i715 int, i716 int, i717 int, i718
-int, i719 int, i720 int, i721 int, i722 int, i723 int, i724 int, i725 int, i726
-int, i727 int, i728 int, i729 int, i730 int, i731 int, i732 int, i733 int, i734
-int, i735 int, i736 int, i737 int, i738 int, i739 int, i740 int, i741 int, i742
-int, i743 int, i744 int, i745 int, i746 int, i747 int, i748 int, i749 int, i750
-int, i751 int, i752 int, i753 int, i754 int, i755 int, i756 int, i757 int, i758
-int, i759 int, i760 int, i761 int, i762 int, i763 int, i764 int, i765 int, i766
-int, i767 int, i768 int, i769 int, i770 int, i771 int, i772 int, i773 int, i774
-int, i775 int, i776 int, i777 int, i778 int, i779 int, i780 int, i781 int, i782
-int, i783 int, i784 int, i785 int, i786 int, i787 int, i788 int, i789 int, i790
-int, i791 int, i792 int, i793 int, i794 int, i795 int, i796 int, i797 int, i798
-int, i799 int, i800 int, i801 int, i802 int, i803 int, i804 int, i805 int, i806
-int, i807 int, i808 int, i809 int, i810 int, i811 int, i812 int, i813 int, i814
-int, i815 int, i816 int, i817 int, i818 int, i819 int, i820 int, i821 int, i822
-int, i823 int, i824 int, i825 int, i826 int, i827 int, i828 int, i829 int, i830
-int, i831 int, i832 int, i833 int, i834 int, i835 int, i836 int, i837 int, i838
-int, i839 int, i840 int, i841 int, i842 int, i843 int, i844 int, i845 int, i846
-int, i847 int, i848 int, i849 int, i850 int, i851 int, i852 int, i853 int, i854
-int, i855 int, i856 int, i857 int, i858 int, i859 int, i860 int, i861 int, i862
-int, i863 int, i864 int, i865 int, i866 int, i867 int, i868 int, i869 int, i870
-int, i871 int, i872 int, i873 int, i874 int, i875 int, i876 int, i877 int, i878
-int, i879 int, i880 int, i881 int, i882 int, i883 int, i884 int, i885 int, i886
-int, i887 int, i888 int, i889 int, i890 int, i891 int, i892 int, i893 int, i894
-int, i895 int, i896 int, i897 int, i898 int, i899 int, i900 int, i901 int, i902
-int, i903 int, i904 int, i905 int, i906 int, i907 int, i908 int, i909 int, i910
-int, i911 int, i912 int, i913 int, i914 int, i915 int, i916 int, i917 int, i918
-int, i919 int, i920 int, i921 int, i922 int, i923 int, i924 int, i925 int, i926
-int, i927 int, i928 int, i929 int, i930 int, i931 int, i932 int, i933 int, i934
-int, i935 int, i936 int, i937 int, i938 int, i939 int, i940 int, i941 int, i942
-int, i943 int, i944 int, i945 int, i946 int, i947 int, i948 int, i949 int, i950
-int, i951 int, i952 int, i953 int, i954 int, i955 int, i956 int, i957 int, i958
-int, i959 int, i960 int, i961 int, i962 int, i963 int, i964 int, i965 int, i966
-int, i967 int, i968 int, i969 int, i970 int, i971 int, i972 int, i973 int, i974
-int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
-int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
-int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
-int, i999 int, i1000 int, b blob) row_format=dynamic;
-insert into t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "Sergei");
-update t1 set b=repeat('a',256);
-update t1 set i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0;
-check table t1;
-drop table t1;
diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test
new file mode 100644
index 00000000000..9591f1fa7ed
--- /dev/null
+++ b/mysql-test/t/join_nested.test
@@ -0,0 +1,754 @@
+
+--disable_warnings
+DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
+--enable_warnings
+
+CREATE TABLE t0 (a int, b int, c int);
+CREATE TABLE t1 (a int, b int, c int);
+CREATE TABLE t2 (a int, b int, c int);
+CREATE TABLE t3 (a int, b int, c int);
+CREATE TABLE t4 (a int, b int, c int);
+CREATE TABLE t5 (a int, b int, c int);
+CREATE TABLE t6 (a int, b int, c int);
+CREATE TABLE t7 (a int, b int, c int);
+CREATE TABLE t8 (a int, b int, c int);
+CREATE TABLE t9 (a int, b int, c int);
+
+INSERT INTO t0 VALUES (1,1,0), (1,2,0), (2,2,0);
+INSERT INTO t1 VALUES (1,3,0), (2,2,0), (3,2,0);
+INSERT INTO t2 VALUES (3,3,0), (4,2,0), (5,3,0);
+INSERT INTO t3 VALUES (1,2,0), (2,2,0);
+INSERT INTO t4 VALUES (3,2,0), (4,2,0);
+INSERT INTO t5 VALUES (3,1,0), (2,2,0), (3,3,0);
+INSERT INTO t6 VALUES (3,2,0), (6,2,0), (6,1,0);
+INSERT INTO t7 VALUES (1,1,0), (2,2,0);
+INSERT INTO t8 VALUES (0,2,0), (1,2,0);
+INSERT INTO t9 VALUES (1,1,0), (1,2,0), (3,3,0);
+
+
+SELECT t2.a,t2.b
+ FROM t2;
+
+SELECT t3.a,t3.b
+ FROM t3;
+
+SELECT t4.a,t4.b
+ FROM t4;
+
+SELECT t3.a,t3.b,t4.a,t4.b
+ FROM t3,t4;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4)
+ ON t2.b=t4.b;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b;
+
+EXPLAIN EXTENDED
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4)
+ ON t2.b=t4.b
+ WHERE t3.a=1 OR t3.c IS NULL;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4)
+ ON t2.b=t4.b
+ WHERE t3.a=1 OR t3.c IS NULL;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4)
+ ON t2.b=t4.b
+ WHERE t3.a>1 OR t3.c IS NULL;
+
+SELECT t5.a,t5.b
+ FROM t5;
+
+SELECT t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+ FROM t3,t4,t5;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4, t5)
+ ON t2.b=t4.b;
+
+EXPLAIN EXTENDED
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4, t5)
+ ON t2.b=t4.b
+ WHERE t3.a>1 OR t3.c IS NULL;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4, t5)
+ ON t2.b=t4.b
+ WHERE t3.a>1 OR t3.c IS NULL;
+
+EXPLAIN EXTENDED
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4, t5)
+ ON t2.b=t4.b
+ WHERE (t3.a>1 OR t3.c IS NULL) AND
+ (t5.a<3 OR t5.c IS NULL);
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4, t5)
+ ON t2.b=t4.b
+ WHERE (t3.a>1 OR t3.c IS NULL) AND
+ (t5.a<3 OR t5.c IS NULL);
+
+SELECT t6.a,t6.b
+ FROM t6;
+
+SELECT t7.a,t7.b
+ FROM t7;
+
+SELECT t6.a,t6.b,t7.a,t7.b
+ FROM t6,t7;
+
+SELECT t8.a,t8.b
+ FROM t8;
+
+EXPLAIN EXTENDED
+SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10;
+
+SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10;
+
+SELECT t5.a,t5.b
+ FROM t5;
+
+SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b;
+
+SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b AND
+ (t8.a < 1 OR t8.c IS NULL);
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ WHERE t2.a > 3 AND
+ (t6.a < 6 OR t6.c IS NULL);
+
+SELECT t1.a,t1.b
+ FROM t1;
+
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2);
+
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2)
+ WHERE (t2.a >= 4 OR t2.c IS NULL);
+
+SELECT t0.a,t0.b
+ FROM t0;
+
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t0,t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2)
+ WHERE t0.a=1 AND
+ t0.b=t1.b AND
+ (t2.a >= 4 OR t2.c IS NULL);
+
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
+ FROM t0,t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2)
+ WHERE t0.a=1 AND
+ t0.b=t1.b AND
+ (t2.a >= 4 OR t2.c IS NULL);
+
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+ FROM t0,t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2),
+ t9
+ WHERE t0.a=1 AND
+ t0.b=t1.b AND
+ (t2.a >= 4 OR t2.c IS NULL) AND
+ (t3.a < 5 OR t3.c IS NULL) AND
+ (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+ (t5.a >=2 OR t5.c IS NULL) AND
+ (t6.a >=4 OR t6.c IS NULL) AND
+ (t7.a <= 2 OR t7.c IS NULL) AND
+ (t8.a < 1 OR t8.c IS NULL) AND
+ (t8.b=t9.b OR t8.c IS NULL) AND
+ (t9.a=1);
+
+SELECT t9.a,t9.b
+ FROM t9;
+
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+ FROM t0,t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2),
+ t9
+ WHERE t0.a=1 AND
+ t0.b=t1.b AND
+ (t2.a >= 4 OR t2.c IS NULL) AND
+ (t3.a < 5 OR t3.c IS NULL) AND
+ (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+ (t5.a >=2 OR t5.c IS NULL) AND
+ (t6.a >=4 OR t6.c IS NULL) AND
+ (t7.a <= 2 OR t7.c IS NULL) AND
+ (t8.a < 1 OR t8.c IS NULL) AND
+ (t8.b=t9.b OR t8.c IS NULL) AND
+ (t9.a=1);
+
+SELECT t1.a,t1.b
+ FROM t1;
+
+SELECT t2.a,t2.b
+ FROM t2;
+
+SELECT t3.a,t3.b
+ FROM t3;
+
+SELECT t2.a,t2.b,t3.a,t3.b
+ FROM t2
+ LEFT JOIN
+ t3
+ ON t2.b=t3.b;
+
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b
+ FROM t1, t2
+ LEFT JOIN
+ t3
+ ON t2.b=t3.b
+ WHERE t1.a <= 2;
+
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b
+ FROM t1, t3
+ RIGHT JOIN
+ t2
+ ON t2.b=t3.b
+ WHERE t1.a <= 2;
+
+SELECT t3.a,t3.b,t4.a,t4.b
+ FROM t3,t4;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b;
+
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t1, t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b
+ WHERE t1.a <= 2;
+
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t1, (t3, t4)
+ RIGHT JOIN
+ t2
+ ON t3.a=1 AND t2.b=t4.b
+ WHERE t1.a <= 2;
+
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t1, t3, t4
+ RIGHT JOIN
+ t2
+ ON t3.a=1 AND t2.b=t4.b
+ WHERE t1.a <= 2;
+
+EXPLAIN EXTENDED
+SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t1, t3, t4
+ RIGHT JOIN
+ t2
+ ON t3.a=1 AND t2.b=t4.b
+ WHERE t1.a <= 2;
+
+CREATE INDEX idx_b ON t2(b);
+
+EXPLAIN EXTENDED
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t3,t4
+ LEFT JOIN
+ (t1,t2)
+ ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
+
+SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
+ FROM t3,t4
+ LEFT JOIN
+ (t1,t2)
+ ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
+
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+ FROM t0,t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2),
+ t9
+ WHERE t0.a=1 AND
+ t0.b=t1.b AND
+ (t2.a >= 4 OR t2.c IS NULL) AND
+ (t3.a < 5 OR t3.c IS NULL) AND
+ (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+ (t5.a >=2 OR t5.c IS NULL) AND
+ (t6.a >=4 OR t6.c IS NULL) AND
+ (t7.a <= 2 OR t7.c IS NULL) AND
+ (t8.a < 1 OR t8.c IS NULL) AND
+ (t8.b=t9.b OR t8.c IS NULL) AND
+ (t9.a=1);
+
+CREATE INDEX idx_b ON t4(b);
+CREATE INDEX idx_b ON t5(b);
+
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+ FROM t0,t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2),
+ t9
+ WHERE t0.a=1 AND
+ t0.b=t1.b AND
+ (t2.a >= 4 OR t2.c IS NULL) AND
+ (t3.a < 5 OR t3.c IS NULL) AND
+ (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+ (t5.a >=2 OR t5.c IS NULL) AND
+ (t6.a >=4 OR t6.c IS NULL) AND
+ (t7.a <= 2 OR t7.c IS NULL) AND
+ (t8.a < 1 OR t8.c IS NULL) AND
+ (t8.b=t9.b OR t8.c IS NULL) AND
+ (t9.a=1);
+
+CREATE INDEX idx_b ON t8(b);
+
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+ FROM t0,t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2),
+ t9
+ WHERE t0.a=1 AND
+ t0.b=t1.b AND
+ (t2.a >= 4 OR t2.c IS NULL) AND
+ (t3.a < 5 OR t3.c IS NULL) AND
+ (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+ (t5.a >=2 OR t5.c IS NULL) AND
+ (t6.a >=4 OR t6.c IS NULL) AND
+ (t7.a <= 2 OR t7.c IS NULL) AND
+ (t8.a < 1 OR t8.c IS NULL) AND
+ (t8.b=t9.b OR t8.c IS NULL) AND
+ (t9.a=1);
+
+CREATE INDEX idx_b ON t1(b);
+CREATE INDEX idx_a ON t0(a);
+
+EXPLAIN EXTENDED
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+ FROM t0,t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2),
+ t9
+ WHERE t0.a=1 AND
+ t0.b=t1.b AND
+ (t2.a >= 4 OR t2.c IS NULL) AND
+ (t3.a < 5 OR t3.c IS NULL) AND
+ (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+ (t5.a >=2 OR t5.c IS NULL) AND
+ (t6.a >=4 OR t6.c IS NULL) AND
+ (t7.a <= 2 OR t7.c IS NULL) AND
+ (t8.a < 1 OR t8.c IS NULL) AND
+ (t8.b=t9.b OR t8.c IS NULL) AND
+ (t9.a=1);
+
+SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
+ t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
+ FROM t0,t1
+ LEFT JOIN
+ (
+ t2
+ LEFT JOIN
+ (t3, t4)
+ ON t3.a=1 AND t2.b=t4.b,
+ t5
+ LEFT JOIN
+ (
+ t6,
+ t7
+ LEFT JOIN
+ t8
+ ON t7.b=t8.b AND t6.b < 10
+ )
+ ON t6.b >= 2 AND t5.b=t7.b
+ )
+ ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
+ (t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
+ (t1.a != 2),
+ t9
+ WHERE t0.a=1 AND
+ t0.b=t1.b AND
+ (t2.a >= 4 OR t2.c IS NULL) AND
+ (t3.a < 5 OR t3.c IS NULL) AND
+ (t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
+ (t5.a >=2 OR t5.c IS NULL) AND
+ (t6.a >=4 OR t6.c IS NULL) AND
+ (t7.a <= 2 OR t7.c IS NULL) AND
+ (t8.a < 1 OR t8.c IS NULL) AND
+ (t8.b=t9.b OR t8.c IS NULL) AND
+ (t9.a=1);
+
+SELECT t2.a,t2.b
+ FROM t2;
+
+SELECT t3.a,t3.b
+ FROM t3;
+
+SELECT t2.a,t2.b,t3.a,t3.b
+ FROM t2 LEFT JOIN t3 ON t2.b=t3.b
+ WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL);
+
+SELECT t2.a,t2.b,t3.a,t3.b
+ FROM t2 LEFT JOIN (t3) ON t2.b=t3.b
+ WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL);
+
+ALTER TABLE t3
+ CHANGE COLUMN a a1 int,
+ CHANGE COLUMN c c1 int;
+
+SELECT t2.a,t2.b,t3.a1,t3.b
+ FROM t2 LEFT JOIN t3 ON t2.b=t3.b
+ WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL);
+
+SELECT t2.a,t2.b,t3.a1,t3.b
+ FROM t2 NATURAL LEFT JOIN t3
+ WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL);
+
+DROP TABLE t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
+
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 (a int);
+CREATE TABLE t3 (a int);
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t3 VALUES (2);
+INSERT INTO t1 VALUES (2);
+
+#check proper syntax for nested outer joins
+
+SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.a=t3.a;
+
+#must be equivalent to:
+
+SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a;
+
+#check that everything is al right when all tables contain not more than 1 row
+#(bug #4922)
+
+DELETE FROM t1 WHERE a=2;
+SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a;
+DELETE FROM t2;
+SELECT * FROM t1 LEFT JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.a=t3.a;
+
+DROP TABLE t1,t2,t3;
+
+#on expression for a nested outer join does not depend on the outer table
+#bug #4976
+
+CREATE TABLE t1(a int, key (a));
+CREATE TABLE t2(b int, key (b));
+CREATE TABLE t3(c int, key (c));
+
+INSERT INTO t1 VALUES (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9),
+(10), (11), (12), (13), (14), (15), (16), (17), (18), (19);
+
+INSERT INTO t2 VALUES (NULL), (0), (1), (2), (3), (4), (5), (6), (7), (8), (9),
+(10), (11), (12), (13), (14), (15), (16), (17), (18), (19);
+
+INSERT INTO t3 VALUES (0), (1), (2), (3), (4), (5);
+
+EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON c < 3 and b = c;
+EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c;
+SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c;
+
+DELETE FROM t3;
+EXPLAIN SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c;
+SELECT a, b, c FROM t1 LEFT JOIN (t2, t3) ON b < 3 and b = c;
+
+DROP TABLE t1,t2,t3;
diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test
index d5fa1592965..25344af55b4 100644
--- a/mysql-test/t/join_outer.test
+++ b/mysql-test/t/join_outer.test
@@ -3,7 +3,7 @@
#
--disable_warnings
-drop table if exists t1,t2,t3,t4,t5;
+drop table if exists t0,t1,t2,t3,t4,t5;
--enable_warnings
CREATE TABLE t1 (
@@ -430,6 +430,8 @@ insert into t1 values(1),(2);
insert into t2 values(2),(3);
insert into t3 values(2),(4);
select * from t1 natural left join t2 natural left join t3;
+select * from t1 natural left join t2 where (t2.i is not null)=0;
+select * from t1 natural left join t2 where (t2.i is not null) is not null;
drop table t1,t2,t3;
#
@@ -567,34 +569,69 @@ SELECT t1.flag_name,t2.flag_value
DROP TABLE t1,t2;
-CREATE TABLE invoice (
+CREATE TABLE t1 (
id int(11) unsigned NOT NULL auto_increment,
text_id int(10) unsigned default NULL,
PRIMARY KEY (id)
);
-INSERT INTO invoice VALUES("1", "0");
-INSERT INTO invoice VALUES("2", "10");
+INSERT INTO t1 VALUES("1", "0");
+INSERT INTO t1 VALUES("2", "10");
-CREATE TABLE text_table (
+CREATE TABLE t2 (
text_id char(3) NOT NULL default '',
language_id char(3) NOT NULL default '',
text_data text,
PRIMARY KEY (text_id,language_id)
);
-INSERT INTO text_table VALUES("0", "EN", "0-EN");
-INSERT INTO text_table VALUES("0", "SV", "0-SV");
-INSERT INTO text_table VALUES("10", "EN", "10-EN");
-INSERT INTO text_table VALUES("10", "SV", "10-SV");
+INSERT INTO t2 VALUES("0", "EN", "0-EN");
+INSERT INTO t2 VALUES("0", "SV", "0-SV");
+INSERT INTO t2 VALUES("10", "EN", "10-EN");
+INSERT INTO t2 VALUES("10", "SV", "10-SV");
+
+SELECT t1.id, t1.text_id, t2.text_data
+ FROM t1 LEFT JOIN t2
+ ON t1.text_id = t2.text_id
+ AND t2.language_id = 'SV'
+ WHERE (t1.id LIKE '%' OR t2.text_data LIKE '%');
+
+DROP TABLE t1, t2;
+
+# Test for bug #5896
+
+CREATE TABLE t0 (a0 int PRIMARY KEY);
+CREATE TABLE t1 (a1 int PRIMARY KEY);
+CREATE TABLE t2 (a2 int);
+CREATE TABLE t3 (a3 int);
+INSERT INTO t0 VALUES (1);
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (1), (2);
+INSERT INTO t3 VALUES (1), (2);
+
+SELECT * FROM t1 LEFT JOIN t2 ON a1=0;
+EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON a1=0;
+SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0;
+EXPLAIN SELECT * FROM t1 LEFT JOIN (t2,t3) ON a1=0;
+SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1;
+EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=0 WHERE a0=a1;
+
+INSERT INTO t0 VALUES (0);
+INSERT INTO t1 VALUES (0);
+SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
+EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
+
+# Test for BUG#4480
+drop table t1,t2;
+create table t1 (a int, b int);
+insert into t1 values (1,1),(2,2),(3,3);
+create table t2 (a int, b int);
+insert into t2 values (1,1), (2,2);
-SELECT invoice.id, invoice.text_id, text_table.text_data
- FROM invoice LEFT JOIN text_table
- ON invoice.text_id = text_table.text_id
- AND text_table.language_id = 'SV'
- WHERE (invoice.id LIKE '%' OR text_table.text_data LIKE '%');
+select * from t2 right join t1 on t2.a=t1.a;
+select straight_join * from t2 right join t1 on t2.a=t1.a;
-DROP TABLE invoice, text_table;
+DROP TABLE t0,t1,t2,t3;
#
# Test for bug #9017: left join mistakingly converted to inner join
diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test
index a0a291fdf3c..af3509c8454 100644
--- a/mysql-test/t/key.test
+++ b/mysql-test/t/key.test
@@ -129,7 +129,11 @@ create table t2
INSERT t2 select * from t1;
SELECT * FROM t2 WHERE name='[T,U]_axpy';
SELECT * FROM t2 WHERE name='[T,U]_axpby';
-drop table t1,t2;
+# Test possible problems with warnings in CREATE ... SELECT
+CREATE TABLE t3 SELECT * FROM t2 WHERE name='[T,U]_axpby';
+SELECT * FROM t2 WHERE name='[T,U]_axpby';
+
+drop table t1,t2,t3;
#
# Test bug with long primary key
@@ -295,7 +299,7 @@ drop table t1;
# create dedicated error code for this and
# and change my_printf_error() to my_error
---error 1105
+--error 1391
create table t1 (c char(10), index (c(0)));
#
diff --git a/mysql-test/t/keywords.test b/mysql-test/t/keywords.test
index e7ec63afe54..3392bfa1b3b 100644
--- a/mysql-test/t/keywords.test
+++ b/mysql-test/t/keywords.test
@@ -6,10 +6,12 @@
drop table if exists t1;
--enable_warnings
-create table t1 (time time, date date, timestamp timestamp);
-insert into t1 values ("12:22:22","97:02:03","1997-01-02");
+create table t1 (time time, date date, timestamp timestamp,
+quarter int, week int, year int, timestampadd int, timestampdiff int);
+insert into t1 values ("12:22:22","97:02:03","1997-01-02",1,2,3,4,5);
select * from t1;
-select t1.time+0,t1.date+0,t1.timestamp+0,concat(date," ",time) from t1;
+select t1.time+0,t1.date+0,t1.timestamp+0,concat(date," ",time),
+ t1.quarter+t1.week, t1.year+timestampadd, timestampdiff from t1;
drop table t1;
create table events(binlog int);
insert into events values(1);
diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test
index 1fec41d8ee4..37e11e14df5 100644
--- a/mysql-test/t/kill.test
+++ b/mysql-test/t/kill.test
@@ -38,3 +38,22 @@ select @id != connection_id();
connection con2;
select 4;
drop table t1;
+
+#
+# test of blocking of sending ERROR after OK or EOF
+#
+connection con1;
+select get_lock("a", 10);
+connection con2;
+let $ID= `select connection_id()`;
+send select get_lock("a", 10);
+--real_sleep 2;
+connection con1;
+disable_query_log;
+eval kill query $ID;
+enable_query_log;
+connection con2;
+reap;
+select 1;
+connection con1;
+select RELEASE_LOCK("a");
diff --git a/mysql-test/t/limit.test b/mysql-test/t/limit.test
index 28b287a5d4a..3dc56295375 100644
--- a/mysql-test/t/limit.test
+++ b/mysql-test/t/limit.test
@@ -6,7 +6,7 @@
drop table if exists t1;
--enable_warnings
-create table t1 (a int primary key, b int not null);
+create table t1 (a int not null default 0 primary key, b int not null default 0);
insert into t1 () values (); -- Testing default values
insert into t1 values (1,1),(2,1),(3,1);
update t1 set a=4 where b=1 limit 1;
diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test
index aa0ea0a2f55..14ef749c802 100644
--- a/mysql-test/t/loaddata.test
+++ b/mysql-test/t/loaddata.test
@@ -3,7 +3,7 @@
#
--disable_warnings
-drop table if exists t1;
+drop table if exists t1, t2;
--enable_warnings
create table t1 (a date, b date, c date not null, d date);
@@ -31,3 +31,46 @@ load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated
select * from t1;
drop table t1;
+#
+# Let us test extended LOAD DATA features
+#
+create table t1 (a int default 100, b int, c varchar(60));
+# we can do something like this
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (a, @b) set b=@b+10, c=concat("b=",@b);
+select * from t1;
+truncate table t1;
+# we can use filled fields in expressions
+# we also assigning NULL value to field with non-NULL default here
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (a, @b) set c= if(a is null,"oops",a);
+select * from t1;
+truncate table t1;
+# we even can use variables in set clause, and missed columns will be set
+# with default values
+set @c:=123;
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (@a, b) set c= if(@a is null,@c,b);
+select * from t1;
+# let us test side-effect of such load
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (@a, @b);
+select * from t1;
+select @a, @b;
+truncate table t1;
+# now going to test fixed field-row file format
+load data infile '../../std_data/loaddata5.dat' into table t1 fields terminated by '' enclosed by '' (a, b) set c="Wow";
+select * from t1;
+truncate table t1;
+# this also should work
+load data infile '../../std_data/loaddata5.dat' into table t1 fields terminated by '' enclosed by '' (a, b) set c=concat(a,"+",b,"+",@c,"+",b,"+",if(c is null,"NIL",c));
+select * from t1;
+# and this should bark
+--error 1409
+load data infile '../../std_data/loaddata5.dat' into table t1 fields terminated by '' enclosed by '' (a, @b);
+
+# Now let us test LOAD DATA with subselect
+create table t2 (num int primary key, str varchar(10));
+insert into t2 values (10,'Ten'), (15,'Fifteen');
+truncate table t1;
+load data infile '../../std_data/rpl_loaddata.dat' into table t1 (@dummy,@n) set a= @n, c= (select str from t2 where num=@n);
+select * from t1;
+
+# cleanup
+drop table t1, t2;
diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test
index 26fc4e32bda..faa1fa3ac25 100644
--- a/mysql-test/t/lock.test
+++ b/mysql-test/t/lock.test
@@ -54,7 +54,7 @@ check table t1;
lock tables t1 write;
check table t2;
--error 1100
-insert into t1 select nr from t1;
+insert into t1 select index1,nr from t1;
unlock tables;
lock tables t1 write, t1 as t1_alias read;
insert into t1 select index1,nr from t1 as t1_alias;
diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test
index a9c0c976afc..f6142b3ddfd 100644
--- a/mysql-test/t/lowercase_table.test
+++ b/mysql-test/t/lowercase_table.test
@@ -7,6 +7,7 @@ drop table if exists t1,t2,t3,t4;
# Clear up from other tests (to ensure that SHOW TABLES below is right)
drop table if exists t0,t5,t6,t7,t8,t9;
drop database if exists mysqltest;
+drop view if exists v0, v1, v2, v3, v4;
--enable_warnings
create table T1 (id int primary key, Word varchar(40) not null, Index(Word));
diff --git a/mysql-test/t/lowercase_table3.test b/mysql-test/t/lowercase_table3.test
index a394cde7237..9841059a26b 100644
--- a/mysql-test/t/lowercase_table3.test
+++ b/mysql-test/t/lowercase_table3.test
@@ -32,6 +32,6 @@ flush tables;
#
CREATE TABLE t1 (a int) ENGINE=INNODB;
---error 1016
+--error 1146
SELECT * from T1;
drop table t1;
diff --git a/mysql-test/t/lowercase_view-master.opt b/mysql-test/t/lowercase_view-master.opt
new file mode 100644
index 00000000000..62ab6dad1e0
--- /dev/null
+++ b/mysql-test/t/lowercase_view-master.opt
@@ -0,0 +1 @@
+--lower_case_table_names=1
diff --git a/mysql-test/t/lowercase_view.test b/mysql-test/t/lowercase_view.test
new file mode 100644
index 00000000000..b39223f71d5
--- /dev/null
+++ b/mysql-test/t/lowercase_view.test
@@ -0,0 +1,140 @@
+--disable_warnings
+drop table if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop view if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop database if exists MySQLTest;
+--enable_warnings
+
+#
+# different cases in VIEW
+#
+create database MySQLTest;
+use MySQLTest;
+create table TaB (Field int);
+create view ViE as select * from TAb;
+show create table VIe;
+drop database MySQLTest;
+use test;
+
+#
+# test of updating and fetching from the same table check
+#
+create table t1Aa (col1 int);
+create table t2aA (col1 int);
+create view v1Aa as select * from t1aA;
+create view v2aA as select * from v1aA;
+create view v3Aa as select v2Aa.col1 from v2aA,t2Aa where v2Aa.col1 = t2aA.col1;
+-- error 1093
+update v2aA set col1 = (select max(col1) from v1Aa);
+-- error 1093
+update v2Aa set col1 = (select max(col1) from t1Aa);
+-- error 1093
+update v2aA set col1 = (select max(col1) from v2Aa);
+-- error 1093
+update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v1aA) where v2aA.col1 = t2aA.col1;
+-- error 1093
+update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v1Aa) where t1aA.col1 = t2aA.col1;
+-- error 1093
+update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1;
+-- error 1093
+update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from v1aA) where v2Aa.col1 = t2aA.col1;
+-- error 1093
+update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v1Aa) where t1Aa.col1 = t2aA.col1;
+-- error 1093
+update t2Aa,v1aA set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1;
+-- error 1093
+update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from t1aA) where v2aA.col1 = t2aA.col1;
+-- error 1093
+update t1Aa,t2Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1;
+-- error 1093
+update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from t1Aa) where v1aA.col1 = t2aA.col1;
+-- error 1093
+update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from t1aA) where v2Aa.col1 = t2aA.col1;
+-- error 1093
+update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1;
+-- error 1093
+update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from t1Aa) where v1Aa.col1 = t2aA.col1;
+-- error 1093
+update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1;
+-- error 1093
+update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v2aA) where t1aA.col1 = t2aA.col1;
+-- error 1093
+update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v2Aa) where v1aA.col1 = t2aA.col1;
+-- error 1093
+update t2Aa,v2aA set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1;
+-- error 1093
+update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v2aA) where t1Aa.col1 = t2aA.col1;
+-- error 1093
+update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from v2Aa) where v1Aa.col1 = t2aA.col1;
+-- error 1093
+update v3aA set v3Aa.col1 = (select max(col1) from v1aA);
+-- error 1093
+update v3aA set v3Aa.col1 = (select max(col1) from t1aA);
+-- error 1093
+update v3aA set v3Aa.col1 = (select max(col1) from v2aA);
+-- error 1093
+update v3aA set v3Aa.col1 = (select max(col1) from v3aA);
+-- error 1093
+delete from v2Aa where col1 = (select max(col1) from v1Aa);
+-- error 1093
+delete from v2aA where col1 = (select max(col1) from t1Aa);
+-- error 1093
+delete from v2Aa where col1 = (select max(col1) from v2aA);
+-- error 1093
+delete v2Aa from v2aA,t2Aa where (select max(col1) from v1aA) > 0 and v2Aa.col1 = t2aA.col1;
+-- error 1093
+delete t1aA from t1Aa,t2Aa where (select max(col1) from v1Aa) > 0 and t1aA.col1 = t2aA.col1;
+-- error 1093
+delete v1aA from v1Aa,t2Aa where (select max(col1) from v1aA) > 0 and v1Aa.col1 = t2aA.col1;
+-- error 1093
+delete v2aA from v2Aa,t2Aa where (select max(col1) from t1Aa) > 0 and v2aA.col1 = t2aA.col1;
+-- error 1093
+delete t1aA from t1Aa,t2Aa where (select max(col1) from t1aA) > 0 and t1Aa.col1 = t2aA.col1;
+-- error 1093
+delete v1aA from v1Aa,t2Aa where (select max(col1) from t1aA) > 0 and v1aA.col1 = t2aA.col1;
+-- error 1093
+delete v2Aa from v2aA,t2Aa where (select max(col1) from v2Aa) > 0 and v2aA.col1 = t2aA.col1;
+-- error 1093
+delete t1Aa from t1aA,t2Aa where (select max(col1) from v2Aa) > 0 and t1Aa.col1 = t2aA.col1;
+-- error 1093
+delete v1Aa from v1aA,t2Aa where (select max(col1) from v2aA) > 0 and v1Aa.col1 = t2aA.col1;
+-- error 1093
+insert into v2Aa values ((select max(col1) from v1aA));
+-- error 1093
+insert into t1aA values ((select max(col1) from v1Aa));
+-- error 1093
+insert into v2aA values ((select max(col1) from v1aA));
+-- error 1093
+insert into v2Aa values ((select max(col1) from t1Aa));
+-- error 1093
+insert into t1aA values ((select max(col1) from t1Aa));
+-- error 1093
+insert into v2aA values ((select max(col1) from t1aA));
+-- error 1093
+insert into v2Aa values ((select max(col1) from v2aA));
+-- error 1093
+insert into t1Aa values ((select max(col1) from v2Aa));
+-- error 1093
+insert into v2aA values ((select max(col1) from v2Aa));
+-- error 1093
+insert into v3Aa (col1) values ((select max(col1) from v1Aa));
+-- error 1093
+insert into v3aA (col1) values ((select max(col1) from t1aA));
+-- error 1093
+insert into v3Aa (col1) values ((select max(col1) from v2aA));
+drop view v3aA,v2Aa,v1aA;
+drop table t1Aa,t2Aa;
+
+#
+# aliases in VIEWs
+#
+create table t1Aa (col1 int);
+create view v1Aa as select col1 from t1Aa as AaA;
+show create view v1AA;
+drop view v1AA;
+select Aaa.col1 from t1Aa as AaA;
+create view v1Aa as select Aaa.col1 from t1Aa as AaA;
+drop view v1AA;
+create view v1Aa as select AaA.col1 from t1Aa as AaA;
+show create view v1AA;
+drop view v1AA;
+drop table t1Aa;
diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test
index 508f9da225e..4c8d7cc1b74 100644
--- a/mysql-test/t/merge.test
+++ b/mysql-test/t/merge.test
@@ -47,9 +47,9 @@ show create table t3;
# The following should give errors
create table t4 (a int not null, b char(10), key(a)) engine=MERGE UNION=(t1,t2);
---error 1016
+--error 1168
select * from t4;
---error 1016
+--error 1168
alter table t4 add column c int;
#
@@ -284,6 +284,8 @@ insert into t2 values (1);
create table t3 engine=merge union=(t1, t2) select * from t1;
--error 1093
create table t3 engine=merge union=(t1, t2) select * from t2;
+--error 1093
+create table t3 engine=merge union=(t1, t2) select (select max(a) from t2);
drop table t1, t2;
# BUG#6699 : no sorting on 'ref' retrieval
diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test
index 544fa5559fa..0641acb552f 100644
--- a/mysql-test/t/mix_innodb_myisam_binlog.test
+++ b/mysql-test/t/mix_innodb_myisam_binlog.test
@@ -28,7 +28,9 @@ insert into t1 values(1);
insert into t2 select * from t1;
commit;
-show binlog events from 79;
+--replace_column 5 #
+--replace_result "xid=15" "xid=8"
+show binlog events from 98;
delete from t1;
delete from t2;
@@ -40,7 +42,8 @@ insert into t2 select * from t1;
# should say some changes to non-transact1onal tables couldn't be rolled back
rollback;
-show binlog events from 79;
+--replace_column 5 #
+show binlog events from 98;
delete from t1;
delete from t2;
@@ -54,7 +57,9 @@ insert into t2 select * from t1;
rollback to savepoint my_savepoint;
commit;
-show binlog events from 79;
+--replace_column 5 #
+--replace_result "xid=48" "xid=25"
+show binlog events from 98;
delete from t1;
delete from t2;
@@ -70,7 +75,9 @@ insert into t1 values(7);
commit;
select a from t1 order by a; # check that savepoints work :)
-show binlog events from 79;
+--replace_column 5 #
+--replace_result "xid=70" "xid=37"
+show binlog events from 98;
# and when ROLLBACK is not explicit?
delete from t1;
@@ -90,7 +97,8 @@ connection con2;
# so SHOW BINLOG EVENTS may come before con1 does the loggin. To be sure that
# logging has been done, we use a user lock.
select get_lock("a",10);
-show binlog events from 79;
+--replace_column 5 #
+show binlog events from 98;
# and when not in a transact1on?
delete from t1;
@@ -100,10 +108,12 @@ reset master;
insert into t1 values(9);
insert into t2 select * from t1;
-show binlog events from 79;
+--replace_column 5 #
+--replace_result "xid=119" "xid=60"
+show binlog events from 98;
# Check that when the query updat1ng the MyISAM table is the first in the
-# transact1on, we log it immediately.
+# transaction, we log it immediately.
delete from t1;
delete from t2;
reset master;
@@ -111,11 +121,15 @@ reset master;
insert into t1 values(10); # first make t1 non-empty
begin;
insert into t2 select * from t1;
-show binlog events from 79;
+--replace_column 5 #
+--replace_result "xid=133" "xid=66"
+show binlog events from 98;
insert into t1 values(11);
commit;
-show binlog events from 79;
+--replace_column 5 #
+--replace_result "xid=133" "xid=66" "xid=136" "xid=68"
+show binlog events from 98;
# Check that things work like before this BEGIN/ROLLBACK code was added,
@@ -132,7 +146,9 @@ insert into t1 values(12);
insert into t2 select * from t1;
commit;
-show binlog events from 79;
+--replace_column 5 #
+--replace_result "xid=155" "xid=78"
+show binlog events from 98;
delete from t1;
delete from t2;
@@ -143,7 +159,8 @@ insert into t1 values(13);
insert into t2 select * from t1;
rollback;
-show binlog events from 79;
+--replace_column 5 #
+show binlog events from 98;
delete from t1;
delete from t2;
@@ -157,7 +174,9 @@ insert into t2 select * from t1;
rollback to savepoint my_savepoint;
commit;
-show binlog events from 79;
+--replace_column 5 #
+--replace_result "xid=187" "xid=94"
+show binlog events from 98;
delete from t1;
delete from t2;
@@ -173,7 +192,9 @@ insert into t1 values(18);
commit;
select a from t1 order by a; # check that savepoints work :)
-show binlog events from 79;
+--replace_column 5 #
+--replace_result "xid=208" "xid=105"
+show binlog events from 98;
# Test for BUG#5714, where a MyISAM update in the transaction used to
# release row-level locks in InnoDB
diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
index 4a7367a333c..0ca42e86204 100644
--- a/mysql-test/t/multi_update.test
+++ b/mysql-test/t/multi_update.test
@@ -2,9 +2,13 @@
# Test of update statement that uses many tables.
#
+# Requires grants, so won't work with embedded server test
+-- source include/not_embedded.inc
+
--disable_warnings
drop table if exists t1,t2,t3;
drop database if exists mysqltest;
+drop view if exists v1;
--error 0,1141,1147
revoke all privileges on mysqltest.t1 from mysqltest_1@localhost;
--error 0,1141,1147
@@ -448,3 +452,75 @@ insert into t2 values(1,null);
delete t2, t1 from t2 left join t1 on (t2.aclid=t1.aclid) where t2.refid='1';
drop table t1, t2;
+#
+# Test for bug #1980.
+#
+--disable_warnings
+create table t1 ( c char(8) not null ) engine=innodb;
+--enable_warnings
+
+insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9');
+insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F');
+
+alter table t1 add b char(8) not null;
+alter table t1 add a char(8) not null;
+alter table t1 add primary key (a,b,c);
+update t1 set a=c, b=c;
+
+create table t2 like t1;
+insert into t2 select * from t1;
+
+delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b;
+
+drop table t1,t2;
+
+--disable_warnings
+create table t1 ( c char(8) not null ) engine=bdb;
+--enable_warnings
+
+insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9');
+insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F');
+
+alter table t1 add b char(8) not null;
+alter table t1 add a char(8) not null;
+alter table t1 add primary key (a,b,c);
+update t1 set a=c, b=c;
+
+create table t2 like t1;
+insert into t2 select * from t1;
+
+delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b;
+
+drop table t1,t2;
+
+create table t1 (a int, b int);
+insert into t1 values (1, 2), (2, 3), (3, 4);
+create table t2 (a int);
+insert into t2 values (10), (20), (30);
+create view v1 as select a as b, a/10 as a from t2;
+
+connect (locker,localhost,root,,test);
+connection locker;
+lock table t1 write;
+
+connect (changer,localhost,root,,test);
+connection changer;
+send alter table t1 add column c int default 100 after a;
+
+connect (updater,localhost,root,,test);
+connection updater;
+send update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a;
+
+connection locker;
+sleep 2;
+unlock tables;
+
+connection changer;
+reap;
+
+connection updater;
+reap;
+select * from t1;
+select * from t2;
+drop view v1;
+drop table t1, t2;
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index 46a6499adad..2b60e85fcc6 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -450,11 +450,14 @@ drop table t1;
# Test text and unique
#
create table t1 (a int not null auto_increment primary key, b text not null, unique b (b(20)));
-insert into t1 (b) values ('a'),('a '),('a ');
+insert into t1 (b) values ('a'),('b'),('c');
select concat(b,'.') from t1;
update t1 set b='b ' where a=2;
--error 1062
update t1 set b='b ' where a > 1;
+--error 1062
+insert into t1 (b) values ('b');
+select * from t1;
delete from t1 where b='b';
select a,concat(b,'.') from t1;
drop table t1;
@@ -560,3 +563,46 @@ update t1 set c2='A B' where c1=2;
check table t1;
drop table t1;
+#
+# Test varchar
+#
+
+let $default=`select @@storage_engine`;
+set storage_engine=MyISAM;
+source include/varchar.inc;
+
+#
+# Some errors/warnings on create
+#
+
+create table t1 (v varchar(65530), key(v));
+drop table if exists t1;
+create table t1 (v varchar(65536));
+show create table t1;
+drop table t1;
+create table t1 (v varchar(65530) character set utf8);
+show create table t1;
+drop table t1;
+
+# MyISAM specific varchar tests
+--error 1118
+create table t1 (v varchar(65535));
+
+eval set storage_engine=$default;
+
+#
+# Test how DROP TABLE works if the index or data file doesn't exists
+
+create table t1 (a int) engine=myisam;
+system rm ./var/master-data/test/t1.MYI ;
+drop table if exists t1;
+create table t1 (a int) engine=myisam;
+system rm ./var/master-data/test/t1.MYI ;
+--error 1051,6
+drop table t1;
+create table t1 (a int) engine=myisam;
+system rm ./var/master-data/test/t1.MYD ;
+--error 1105,6,29
+drop table t1;
+--error 1051
+drop table t1;
diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test
index 435fa8289da..49b8237d99f 100644
--- a/mysql-test/t/mysqlbinlog.test
+++ b/mysql-test/t/mysqlbinlog.test
@@ -27,7 +27,6 @@ load data infile '../../std_data/words.dat' into table t1;
load data infile '../../std_data/words.dat' into table t1;
load data infile '../../std_data/words.dat' into table t1;
load data infile '../../std_data/words.dat' into table t1;
-load data infile '../../std_data/words.dat' into table t1;
# simple query to show more in second binlog
insert into t1 values ("Alas");
flush logs;
@@ -64,7 +63,7 @@ select "--- --database --" as "";
select "--- --position --" as "";
--enable_query_log
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
---exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --position=27 $MYSQL_TEST_DIR/var/log/master-bin.000002
+--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --position=231 $MYSQL_TEST_DIR/var/log/master-bin.000002
# These are tests for remote binlog.
# They should return the same as previous test.
@@ -96,7 +95,18 @@ select "--- --database --" as "";
select "--- --position --" as "";
--enable_query_log
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
---exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --read-from-remote-server --position=27 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002
+--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --read-from-remote-server --position=231 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002
+
+# Bug#7853 (mysqlbinlog does not accept input from stdin)
+--disable_query_log
+select "--- reading stdin --" as "";
+--enable_query_log
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+--exec cat $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 | $MYSQL_BINLOG --short-form -
+
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+--exec cat $MYSQL_TEST_DIR/std_data/trunc_binlog.000001 | $MYSQL_BINLOG --short-form --position=79 -
# clean up
drop table t1, t2;
+
diff --git a/mysql-test/t/mysqlbinlog2.test b/mysql-test/t/mysqlbinlog2.test
index 0eddc4ec2e4..6e2eda07695 100644
--- a/mysql-test/t/mysqlbinlog2.test
+++ b/mysql-test/t/mysqlbinlog2.test
@@ -49,11 +49,11 @@ select "--- offset --" as "";
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --start-position=497 $MYSQL_TEST_DIR/var/log/master-bin.000001
+--exec $MYSQL_BINLOG --short-form --start-position=600 $MYSQL_TEST_DIR/var/log/master-bin.000001
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --stop-position=497 $MYSQL_TEST_DIR/var/log/master-bin.000001
+--exec $MYSQL_BINLOG --short-form --stop-position=600 $MYSQL_TEST_DIR/var/log/master-bin.000001
--disable_query_log
select "--- start-datetime --" as "";
--enable_query_log
@@ -78,11 +78,11 @@ select "--- offset --" as "";
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --start-position=497 $MYSQL_TEST_DIR/var/log/master-bin.000001 $MYSQL_TEST_DIR/var/log/master-bin.000002
+--exec $MYSQL_BINLOG --short-form --start-position=600 $MYSQL_TEST_DIR/var/log/master-bin.000001 $MYSQL_TEST_DIR/var/log/master-bin.000002
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --stop-position=32 $MYSQL_TEST_DIR/var/log/master-bin.000001 $MYSQL_TEST_DIR/var/log/master-bin.000002
+--exec $MYSQL_BINLOG --short-form --stop-position=126 $MYSQL_TEST_DIR/var/log/master-bin.000001 $MYSQL_TEST_DIR/var/log/master-bin.000002
--disable_query_log
select "--- start-datetime --" as "";
--enable_query_log
@@ -105,11 +105,11 @@ select "--- offset --" as "";
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --start-position=497 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
+--exec $MYSQL_BINLOG --short-form --start-position=600 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --stop-position=497 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
+--exec $MYSQL_BINLOG --short-form --stop-position=600 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
--disable_query_log
select "--- start-datetime --" as "";
--enable_query_log
@@ -132,11 +132,11 @@ select "--- offset --" as "";
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --start-position=497 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002
+--exec $MYSQL_BINLOG --short-form --start-position=600 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --stop-position=32 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002
+--exec $MYSQL_BINLOG --short-form --stop-position=126 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002
--disable_query_log
select "--- start-datetime --" as "";
--enable_query_log
diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index c321fb9c6b7..949c62ef288 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -2,7 +2,9 @@
--source include/not_embedded.inc
--disable_warnings
-DROP TABLE IF EXISTS t1, `"t"1`;
+DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa;
+drop database if exists mysqldump_test_db;
+drop view if exists v1;
--enable_warnings
# XML output
@@ -16,7 +18,7 @@ DROP TABLE t1;
# Bug #2005
#
-CREATE TABLE t1 (a decimal(240, 20));
+CREATE TABLE t1 (a decimal(64, 20));
INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"),
("0987654321098765432109876543210987654321");
--exec $MYSQL_DUMP --compact test t1
@@ -27,7 +29,7 @@ DROP TABLE t1;
#
CREATE TABLE t1 (a double);
-INSERT INTO t1 VALUES (-9e999999);
+INSERT INTO t1 VALUES ('-9e999999');
# The following replaces is here because some systems replaces the above
# double with '-inf' and others with MAX_DOUBLE
--replace_result (-1.79769313486232e+308) (RES) (NULL) (RES)
@@ -132,6 +134,15 @@ insert into t1 values (1),(2),(3);
drop table t1;
#
+# dump of view
+#
+create table t1(a int);
+create view v1 as select * from t1;
+--exec $MYSQL_DUMP --skip-comments test
+drop view v1;
+drop table t1;
+
+#
# Bug #6101: create database problem
#
@@ -185,3 +196,11 @@ INSERT INTO `t1` VALUES (0x602010000280100005E71A);
--exec $MYSQL_DUMP --skip-extended-insert --hex-blob test --skip-comments t1
DROP TABLE t1;
+#
+# Bug #9756
+#
+
+CREATE TABLE t1 (a char(10));
+INSERT INTO t1 VALUES ('\'');
+--exec $MYSQL_DUMP --skip-comments test t1
+DROP TABLE t1;
diff --git a/mysql-test/t/mysqlshow.test b/mysql-test/t/mysqlshow.test
new file mode 100644
index 00000000000..33ae8aef9a0
--- /dev/null
+++ b/mysql-test/t/mysqlshow.test
@@ -0,0 +1,23 @@
+# Can't run test of external client with embedded server
+-- source include/not_embedded.inc
+
+#
+## Bug #5036 mysqlshow is missing a column
+#
+CREATE TABLE t1 (a int);
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE TABLE t2 (a int, b int);
+show tables;
+select "--------------------" as "";
+--exec $MYSQL_SHOW test
+select "---- -v ------------" as "";
+--exec $MYSQL_SHOW test -v
+select "---- -v -v ---------" as "";
+--exec $MYSQL_SHOW test -v -v
+select "----- -t -----------" as "";
+--exec $MYSQL_SHOW test -t
+select "---- -v -t ---------" as "";
+--exec $MYSQL_SHOW test -v -t
+select "---- -v -v -t ------" as "";
+--exec $MYSQL_SHOW test -v -v -t
+DROP TABLE t1, t2;
diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test
index 9cc1426554f..1e5c31da98e 100644
--- a/mysql-test/t/ndb_alter_table.test
+++ b/mysql-test/t/ndb_alter_table.test
@@ -49,10 +49,12 @@ col3 varchar (20) not null,
col4 varchar(4) not null,
col5 enum('PENDING', 'ACTIVE', 'DISABLED') not null,
col6 int not null, to_be_deleted int) ENGINE=ndbcluster;
+--replace_column 7 # 8 # 10 # 12 # 13 # 14 # 18 #
show table status;
SET SQL_MODE=NO_AUTO_VALUE_ON_ZERO;
insert into t1 values
(0,4,3,5,"PENDING",1,7),(NULL,4,3,5,"PENDING",1,7),(31,4,3,5,"PENDING",1,7), (7,4,3,5,"PENDING",1,7), (NULL,4,3,5,"PENDING",1,7), (100,4,3,5,"PENDING",1,7), (99,4,3,5,"PENDING",1,7), (8,4,3,5,"PENDING",1,7), (NULL,4,3,5,"PENDING",1,7);
+--replace_column 7 # 8 # 10 # 12 # 13 # 14 # 18 #
show table status;
select * from t1 order by col1;
alter table t1
@@ -61,9 +63,11 @@ add column col7 varchar(30) not null after col5,
add column col8 datetime not null, drop column to_be_deleted,
change column col2 fourth varchar(30) not null after col3,
modify column col6 int not null first;
+--replace_column 7 # 8 # 10 # 12 # 13 # 14 # 18 #
show table status;
select * from t1 order by col1;
insert into t1 values (2, NULL,4,3,5,99,"PENDING","EXTRA",'2004-01-01 00:00:00');
+--replace_column 7 # 8 # 10 # 12 # 13 # 14 # 18 #
show table status;
select * from t1 order by col1;
delete from t1;
@@ -144,7 +148,7 @@ select * from t1 where b = 'two';
connection server1;
alter table t1 drop index c;
connection server2;
---error 1105
+--error 1412
select * from t1 where b = 'two';
select * from t1 where b = 'two';
connection server1;
diff --git a/mysql-test/t/ndb_autodiscover.test b/mysql-test/t/ndb_autodiscover.test
index bd73a36fcab..80f6f3f35d3 100644
--- a/mysql-test/t/ndb_autodiscover.test
+++ b/mysql-test/t/ndb_autodiscover.test
@@ -177,7 +177,7 @@ show status like 'handler_discover%';
flush tables;
system rm var/master-data/test/t7.frm ;
---replace_column 7 # 8 # 9 # 12 # 13 # 15 #
+--replace_column 7 # 8 # 9 # 12 # 13 # 15 # 18 #
show table status;
show status like 'handler_discover%';
@@ -210,8 +210,30 @@ select * from t4;
select * from t4;
show status like 'handler_discover%';
+--error 1051
drop table t4;
+create table t4(
+ id int not null primary key,
+ name char(27)
+) engine=ndb;
+insert into t4 values (1, "Automatic");
+select * from t4;
+
+# Remove the table from NDB
+system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t4 >> $NDB_TOOLS_OUTPUT ;
+
+--error 1146
+select * from t4;
+
+drop table if exists t4;
+
+# Test that dropping a table that does not exists
+# on disk or in NDB gives same result as above
+--error 1051
+drop table t5;
+drop table if exists t5;
+
#######################################################
# Test that a table that has been dropped from NDB
@@ -450,9 +472,28 @@ drop table t1;
use test2;
drop table t2;
drop database test2;
-show databases;
use test;
+#########################################################
+# Bug#8035
+# mysqld would segfault on second select * before bug was fixed
+#
+--disable_warnings
+drop database if exists test_only_ndb_tables;
+--enable_warnings
+create database test_only_ndb_tables;
+use test_only_ndb_tables;
+create table t1 (a int primary key) engine=ndb;
+select * from t1;
+--exec $NDB_MGM --no-defaults -e "all restart -n" > /dev/null
+--exec $NDB_TOOLS_DIR/ndb_waiter --no-defaults --not-started > /dev/null
+--error 1015
+select * from t1;
+--exec $NDB_MGM --no-defaults -e "all start" > /dev/null
+--exec $NDB_TOOLS_DIR/ndb_waiter --no-defaults > /dev/null
+use test;
+drop database test_only_ndb_tables;
+
######################################################
# 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_basic.test b/mysql-test/t/ndb_basic.test
index 24baf8d9fb4..051a95ca42a 100644
--- a/mysql-test/t/ndb_basic.test
+++ b/mysql-test/t/ndb_basic.test
@@ -551,7 +551,7 @@ create table t1
(a bigint, b bigint, c bigint, d bigint,
primary key (a,b,c,d))
engine=ndb
- max_rows=200000000;
+ max_rows=800000000;
insert into t1 values
(1,2,3,4),(2,3,4,5),(3,4,5,6),
(3,2,3,4),(1,3,4,5),(2,4,5,6),
diff --git a/mysql-test/t/ndb_bitfield.test b/mysql-test/t/ndb_bitfield.test
new file mode 100644
index 00000000000..efacd8f7c06
--- /dev/null
+++ b/mysql-test/t/ndb_bitfield.test
@@ -0,0 +1,62 @@
+-- source include/have_ndb.inc
+-- source include/not_embedded.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (
+ pk1 int not null primary key,
+ b bit(64)
+) engine=ndbcluster;
+
+show create table t1;
+insert into t1 values
+(0,b'1111111111111111111111111111111111111111111111111111111111111111'),
+(1,b'1000000000000000000000000000000000000000000000000000000000000000'),
+(2,b'0000000000000000000000000000000000000000000000000000000000000001'),
+(3,b'1010101010101010101010101010101010101010101010101010101010101010'),
+(4,b'0101010101010101010101010101010101010101010101010101010101010101');
+select hex(b) from t1 order by pk1;
+drop table t1;
+
+create table t1 (
+ pk1 int not null primary key,
+ b bit(9)
+) engine=ndbcluster;
+insert into t1 values
+(0,b'000000000'),
+(1,b'000000001'),
+(2,b'000000010'),
+(3,b'000000011'),
+(4,b'000000100');
+select hex(b) from t1 order by pk1;
+update t1 set b = b + b'101010101';
+select hex(b) from t1 order by pk1;
+drop table t1;
+
+create table t1 (a bit(7), b bit(9)) engine = ndbcluster;
+insert into t1 values
+(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177),
+(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380),
+(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36),
+(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499),
+(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403),
+(44, 307), (68, 454), (57, 135);
+select a+0 from t1 order by a;
+select b+0 from t1 order by b;
+drop table t1;
+
+--error 1005
+create table t1 (
+ pk1 bit(9) not null primary key,
+ b int
+) engine=ndbcluster;
+
+--error 1005
+create table t1 (
+ pk1 int not null primary key,
+ b bit(9),
+ key(b)
+) engine=ndbcluster;
+
diff --git a/mysql-test/t/ndb_cache.test b/mysql-test/t/ndb_cache.test
index 5ba42f9b23c..b61422a58fb 100644
--- a/mysql-test/t/ndb_cache.test
+++ b/mysql-test/t/ndb_cache.test
@@ -2,31 +2,121 @@
-- source include/have_ndb.inc
-- source include/not_embedded.inc
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+# Turn on and reset query cache
+set GLOBAL query_cache_type=on;
set GLOBAL query_cache_size=1355776;
reset query cache;
flush status;
---disable_warnings
-drop table if exists t1,t2;
---enable_warnings
+# Create test table in NDB
+CREATE TABLE t1 ( pk int not null primary key,
+ a int, b int not null, c varchar(20)) ENGINE=ndbcluster;
+insert into t1 value (1, 2, 3, 'First row');
+
+# Perform one query which should be inerted in query cache
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
-CREATE TABLE t1 (a int) ENGINE=ndbcluster;
-CREATE TABLE t2 (a int);
+# Perform the same query and make sure the query cache is hit
+select * from t1;
+show status like "Qcache_hits";
+# Update the table and make sure the correct data is returned
+update t1 set a=3 where pk=1;
select * from t1;
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+# Insert a new record and make sure the correct data is returned
+insert into t1 value (2, 7, 8, 'Second row');
+insert into t1 value (4, 5, 6, 'Fourth row');
+select * from t1 order by pk;
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from t1 order by pk;
+show status like "Qcache_hits";
+
+# Perform a "new" query and make sure the query cache is not hit
+select * from t1 where b=3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+# Same query again...
+select * from t1 where b=3;
+show status like "Qcache_hits";
+
+# Delete from the table
+delete from t1 where c='Fourth row';
+show status like "Qcache_queries_in_cache";
+select * from t1 where b=3;
+show status like "Qcache_hits";
+
+# Start another connection and check that the query cache is hit
+connect (con1,localhost,root,,);
+connection con1;
+use test;
+select * from t1 order by pk;
+select * from t1 where b=3;
+show status like "Qcache_hits";
+
+# Update the table and switch to other connection
+update t1 set a=4 where b=3;
+connect (con2,localhost,root,,);
+connection con2;
+use test;
show status like "Qcache_queries_in_cache";
+select * from t1 order by pk desc;
+select * from t1 order by pk desc;
show status like "Qcache_inserts";
show status like "Qcache_hits";
-select * from t2;
+connection con1;
+select * from t1 order by pk desc;
+select * from t1 order by pk desc;
show status like "Qcache_queries_in_cache";
show status like "Qcache_inserts";
show status like "Qcache_hits";
-select * from t1;
-select * from t2;
+
+# Use transactions and make sure the query cache is not updated until
+# transaction is commited
+begin;
+update t1 set a=5 where pk=1;
+# Note!! the below test shows that table is invalidated
+# before transaction is committed
+# TODO Fix so that cache is not invalidated HERE!
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con2;
+select * from t1 order by pk desc;
show status like "Qcache_queries_in_cache";
show status like "Qcache_inserts";
show status like "Qcache_hits";
+connection con1;
+commit;
+# TODO Here query is invalidated once again, commit count in NDB has changed
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con2;
+select * from t1 order by pk desc;
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con1;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+drop table t1;
-drop table t1, t2;
+show status like "Qcache_queries_in_cache";
SET GLOBAL query_cache_size=0;
+
+
diff --git a/mysql-test/t/ndb_cache2.test b/mysql-test/t/ndb_cache2.test
new file mode 100644
index 00000000000..352b01ef73f
--- /dev/null
+++ b/mysql-test/t/ndb_cache2.test
@@ -0,0 +1,361 @@
+-- source include/have_query_cache.inc
+-- source include/have_ndb.inc
+-- source include/not_embedded.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3, t4, t5;
+--enable_warnings
+
+
+# Turn on and reset query cache
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+# Turn on thread that will fetch commit count for open tables
+set GLOBAL ndb_cache_check_time=100;
+reset query cache;
+flush status;
+
+# Create test tables in NDB
+CREATE TABLE t1 (
+ pk int not null primary key,
+ a1 int,
+ b1 int not null,
+ c1 varchar(20)
+) ENGINE=ndb;
+CREATE TABLE t2 (
+ pk int not null primary key,
+ a2 int,
+ b2 int not null
+) ENGINE=ndb;
+CREATE TABLE t3 (
+ pk int not null primary key,
+ a3 int,
+ b3 int not null,
+ c3 int not null,
+ d3 varchar(20)
+) ENGINE=ndb;
+CREATE TABLE t4 (
+ a4 int,
+ b4 int not null,
+ c4 char(20)
+) ENGINE=ndbcluster;
+CREATE TABLE t5 (
+ pk int not null primary key,
+ a5 int,
+ b5 int not null,
+ c5 varchar(255)
+) ENGINE=ndbcluster;
+insert into t1 value (1, 2, 3, 'First row');
+insert into t2 value (1, 2, 3);
+insert into t3 value (1, 2, 3, 4, '3 - First row');
+insert into t4 value (2, 3, '4 - First row');
+insert into t5 value (1, 2, 3, '5 - First row');
+
+# Perform one query which should be inserted in query cache
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+# Perform the same query and make sure the query cache is hit
+select * from t1;
+show status like "Qcache_hits";
+
+# Update the table and make sure the correct data is returned
+update t1 set a1=3 where pk=1;
+select * from t1;
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+# Insert a new record and make sure the correct data is returned
+insert into t1 value (2, 7, 8, 'Second row');
+insert into t1 value (4, 5, 6, 'Fourth row');
+select * from t1 order by pk desc;
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from t1 order by pk desc;
+show status like "Qcache_hits";
+
+# Perform a "new" query and make sure the query cache is not hit
+select * from t1 where b1=3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+# Same query again...
+select * from t1 where b1=3;
+show status like "Qcache_hits";
+
+# Delete from the table
+delete from t1 where c1='Fourth row';
+show status like "Qcache_queries_in_cache";
+select * from t1 where b1=3;
+show status like "Qcache_hits";
+
+# Start another connection and check that the query cache is hit
+connect (con1,localhost,root,,);
+connection con1;
+use test;
+select * from t1 order by pk desc;
+select * from t1 where b1=3;
+show status like "Qcache_hits";
+
+# Update the table and switch to other connection
+update t1 set a1=4 where b1=3;
+connect (con2,localhost,root,,);
+connection con2;
+use test;
+show status like "Qcache_queries_in_cache";
+select * from t1 order by pk desc;
+select * from t1 order by pk desc;
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con1;
+select * from t1 order by pk desc;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+# Load all tables into cache
+select * from t2;
+select * from t3;
+select * from t4;
+select * from t5;
+show status like "Qcache_queries_in_cache";
+
+#####################################################################
+# Start transaction and perform update
+# Switch to other transaction and check that update does not show up
+# Switch back and commit transaction
+# Switch to other transaction and check that update shows up
+#####################################################################
+connection con1;
+flush status;
+begin;
+update t1 set a1=5 where pk=1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con2;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con1;
+commit;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con2;
+select * from t1 order by pk desc;
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con1;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+#####################################################################
+# Start transaction and perform update
+# Switch to other transaction and check that update does not show up
+# Switch back, perform selects and commit transaction
+# Switch to other transaction and check that update shows up
+#####################################################################
+connection con1;
+flush status;
+begin;
+update t1 set a1=6 where pk=1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con2;
+select * from t1 order by pk desc;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con1;
+# The two queries below will not hit cache since transaction is ongoing
+select * from t1 order by pk desc;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+commit;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con2;
+select * from t1 order by pk desc;
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con1;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+#####################################################################
+# Start transaction and perform insert
+# Switch to other transaction and check that insert does not show up
+# Switch back, perform selects and commit transaction
+# Switch to other transaction and check that update shows up
+#####################################################################
+connection con1;
+flush status;
+begin;
+insert into t1 set pk=5, a1=6, b1=3, c1="New row";
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con2;
+select * from t1 where pk=5;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con1;
+# The below four queries will not be cached, trans is ongoing
+select * from t1 where pk=5;
+select * from t1 where pk=5;
+select * from t1 order by pk desc;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+commit;
+
+connection con2;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+connection con1;
+
+#####################################################################
+# Start transaction and perform delete
+# Switch to other transaction and check that delete does not show up
+# Switch back, perform selects and commit transaction
+# Switch to other transaction and check that update shows up
+#####################################################################
+connection con1;
+flush status;
+begin;
+delete from t1 where pk=2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con2;
+select * from t1 where pk=2;
+select * from t1 order by pk desc;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con1;
+# The below four queries will not be cached, trans is ongoing
+select * from t1 where pk=2;
+select * from t1 order by pk desc;
+select * from t1 order by pk desc;
+select * from t1 where pk=2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+commit;
+
+connection con2;
+select * from t1 order by pk desc;
+select * from t1 where pk=2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+connection con1;
+
+#####################################################################
+# Start a transaction which updates all tables
+# Switch to other transaction and check updates does not show up
+# Switch back, perform selects and commit transaction
+# Switch to other transaction and check that update shows up
+#####################################################################
+flush status;
+begin;
+update t1 set a1=9 where pk=1;
+update t2 set a2=9 where pk=1;
+update t3 set a3=9 where pk=1;
+update t4 set a4=9 where a4=2;
+update t5 set a5=9 where pk=1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con2;
+select * from t1 order by pk desc;
+select * from t2;
+select * from t3;
+select * from t4;
+select * from t5;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+connection con1;
+# The below five queries will not be cached, trans is ongoing
+select * from t1 order by pk desc;
+select * from t1 order by pk desc;
+select * from t2;
+select * from t3;
+select * from t4;
+select * from t5;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+commit;
+
+connection con2;
+select * from t1 order by pk desc;
+select * from t2;
+select * from t3;
+select * from t4;
+select * from t5;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+connection con1;
+select * from t1 order by pk desc;
+select * from t2;
+select * from t3;
+select * from t4;
+select * from t5;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from t1 order by pk desc;
+select * from t2;
+select * from t3;
+select * from t4;
+select * from t5;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+connection con2;
+select * from t1 order by pk desc;
+select * from t2;
+select * from t3;
+select * from t4;
+select * from t5;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+drop table t1, t2, t3, t4, t5;
+
+# There should be no queries in cache, when tables have been dropped
+show status like "Qcache_queries_in_cache";
+
+SET GLOBAL query_cache_size=0;
+SET GLOBAL ndb_cache_check_time=0;
+
+
diff --git a/mysql-test/t/ndb_cache_multi.test b/mysql-test/t/ndb_cache_multi.test
new file mode 100644
index 00000000000..beb8e4bc2ac
--- /dev/null
+++ b/mysql-test/t/ndb_cache_multi.test
@@ -0,0 +1,65 @@
+-- source include/have_query_cache.inc
+-- source include/have_ndb.inc
+-- source include/have_multi_ndb.inc
+-- source include/not_embedded.inc
+
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+
+
+# Turn on and reset query cache on server1
+connection server1;
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+reset query cache;
+flush status;
+
+# Turn on and reset query cache on server2
+connection server2;
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+reset query cache;
+flush status;
+
+
+
+# Create test tables in NDB and load them into cache
+# on server1
+connection server1;
+create table t1 (a int) engine=ndbcluster;
+create table t2 (a int) engine=ndbcluster;
+insert into t1 value (2);
+insert into t2 value (3);
+select * from t1;
+select * from t2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+
+# Connect server2, load table in to cache, then update the table
+connection server2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+update t1 set a=3 where a=2;
+
+# Connect to server1 and check that cache is invalidated
+# and correct data is returned
+connection server1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+drop table t1, t2;
+
+
diff --git a/mysql-test/t/ndb_cache_multi2.test b/mysql-test/t/ndb_cache_multi2.test
new file mode 100644
index 00000000000..9352505649c
--- /dev/null
+++ b/mysql-test/t/ndb_cache_multi2.test
@@ -0,0 +1,82 @@
+-- source include/have_query_cache.inc
+-- source include/have_ndb.inc
+-- source include/have_multi_ndb.inc
+-- source include/not_embedded.inc
+
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+
+
+# Turn on and reset query cache on server1
+connection server1;
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+set GLOBAL ndb_cache_check_time=1;
+reset query cache;
+flush status;
+
+# Turn on and reset query cache on server2
+connection server2;
+set GLOBAL query_cache_type=on;
+set GLOBAL query_cache_size=1355776;
+set GLOBAL ndb_cache_check_time=1;
+reset query cache;
+flush status;
+
+# Sleep so that the query cache check thread has time to start
+sleep 15;
+
+
+# Create test tables in NDB and load them into cache
+# on server1
+connection server1;
+create table t1 (a int) engine=ndbcluster;
+create table t2 (a int) engine=ndbcluster;
+insert into t1 value (2);
+insert into t2 value (3);
+select * from t1;
+select * from t2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+
+# Connect server2, load table in to cache, then update the table
+connection server2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+update t1 set a=3 where a=2;
+
+# Sleep so that the query cache check thread has time to run
+sleep 5;
+
+# Connect to server1 and check that cache is invalidated
+# and correct data is returned
+connection server1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+drop table t1, t2;
+
+# Turn off and reset query cache on server1 and server2
+connection server1;
+set GLOBAL query_cache_size=0;
+set GLOBAL ndb_cache_check_time=0;
+reset query cache;
+flush status;
+connection server2;
+set GLOBAL query_cache_size=0;
+set GLOBAL ndb_cache_check_time=0;
+reset query cache;
+flush status;
diff --git a/mysql-test/t/ndb_charset.test b/mysql-test/t/ndb_charset.test
index 242f9192948..becbe9a4d06 100644
--- a/mysql-test/t/ndb_charset.test
+++ b/mysql-test/t/ndb_charset.test
@@ -54,6 +54,25 @@ select * from t1 where a = 'AaA';
select * from t1 where a = 'AAA';
drop table t1;
+# pk - varchar
+
+create table t1 (
+ a varchar(20) character set latin1 collate latin1_swedish_ci primary key
+) engine=ndb;
+#
+insert into t1 values ('A'),('b '),('C '),('d '),('E'),('f');
+-- error 1062
+insert into t1 values('b');
+-- error 1062
+insert into t1 values('a ');
+#
+select a,length(a) from t1 order by a;
+select a,length(a) from t1 order by a desc;
+select * from t1 where a = 'a';
+select * from t1 where a = 'a ';
+select * from t1 where a = 'd';
+drop table t1;
+
# unique hash index - binary
create table t1 (
@@ -103,6 +122,27 @@ select * from t1 where a = 'AaA';
select * from t1 where a = 'AAA';
drop table t1;
+# unique hash index - varchar
+
+create table t1 (
+ p int primary key,
+ a varchar(20) character set latin1 collate latin1_swedish_ci not null,
+ unique key(a)
+) engine=ndb;
+#
+insert into t1 values (1,'A'),(2,'b '),(3,'C '),(4,'d '),(5,'E'),(6,'f');
+-- error 1062
+insert into t1 values(99,'b');
+-- error 1062
+insert into t1 values(99,'a ');
+#
+select a,length(a) from t1 order by a;
+select a,length(a) from t1 order by a desc;
+select * from t1 where a = 'a';
+select * from t1 where a = 'a ';
+select * from t1 where a = 'd';
+drop table t1;
+
# ordered index - binary
create table t1 (
@@ -159,9 +199,47 @@ select * from t1 where a = 'AaA' order by p;
select * from t1 where a = 'AAA' order by p;
drop table t1;
+# ordered index - varchar
+
+create table t1 (
+ p int primary key,
+ a varchar(20) character set latin1 collate latin1_swedish_ci not null,
+ index(a, p)
+) engine=ndb;
+#
+insert into t1 values (1,'A'),(2,'b '),(3,'C '),(4,'d '),(5,'E'),(6,'f');
+insert into t1 values (7,'a'),(8,'B '),(9,'c '),(10,'D'),(11,'e'),(12,'F ');
+select p,a,length(a) from t1 order by a, p;
+select * from t1 where a = 'a ' order by a desc, p desc;
+select * from t1 where a >= 'D' order by a, p;
+select * from t1 where a < 'D' order by a, p;
+#
+select count(*) from t1 x, t1 y, t1 z where x.a = y.a and y.a = z.a;
+drop table t1;
+
+# minimal multi-byte test
+# removed by jonas as this requires a configure --with-extra-charsets
+#create table t1 (
+# a char(5) character set ucs2,
+# b varchar(7) character set utf8,
+# primary key(a, b)
+#) engine=ndb;
+#
+#insert into t1 values
+# ('a','A '),('B ','b'),('c','C '),('D','d'),('e ','E'),('F','f '),
+# ('A','b '),('b ','C'),('C','d '),('d','E'),('E ','f'),
+# ('a','C '),('B ','d'),('c','E '),('D','f');
+#-- error 1062
+#insert into t1 values('d','f');
+#
+#select a,b,length(a),length(b) from t1 order by a,b limit 3;
+#select a,b,length(a),length(b) from t1 order by a desc, b desc limit 3;
+#select a,b,length(a),length(b) from t1 where a='c' and b='c';
+#drop table t1;
+
# bug
create table t1 (
- a varchar(10) primary key
+ a char(10) primary key
) engine=ndb;
insert into t1 values ('jonas % ');
replace into t1 values ('jonas % ');
diff --git a/mysql-test/t/ndb_condition_pushdown.test b/mysql-test/t/ndb_condition_pushdown.test
new file mode 100644
index 00000000000..1d201a94c95
--- /dev/null
+++ b/mysql-test/t/ndb_condition_pushdown.test
@@ -0,0 +1,1049 @@
+-- source include/have_ndb.inc
+-- source include/not_embedded.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1,t2;
+--enable_warnings
+
+#
+# Test of condition pushdown to storage engine
+#
+CREATE TABLE t1 (
+ auto int(5) unsigned NOT NULL auto_increment,
+ string char(10),
+ vstring varchar(10),
+ bin binary(7),
+ vbin varbinary(7),
+ tiny tinyint(4) DEFAULT '0' NOT NULL ,
+ short smallint(6) DEFAULT '1' NOT NULL ,
+ medium mediumint(8) DEFAULT '0' NOT NULL,
+ long_int int(11) DEFAULT '0' NOT NULL,
+ longlong bigint(13) DEFAULT '0' NOT NULL,
+ real_float float(13,1) DEFAULT 0.0 NOT NULL,
+ real_double double(16,4),
+ real_decimal decimal(16,4),
+ utiny tinyint(3) unsigned DEFAULT '0' NOT NULL,
+ ushort smallint(5) unsigned zerofill DEFAULT '00000' NOT NULL,
+ umedium mediumint(8) unsigned DEFAULT '0' NOT NULL,
+ ulong int(11) unsigned DEFAULT '0' NOT NULL,
+ ulonglong bigint(13) unsigned DEFAULT '0' NOT NULL,
+ bits bit(3),
+ options enum('zero','one','two','three','four') not null,
+ flags set('zero','one','two','three','four') not null,
+ date_field date,
+ year_field year,
+ time_field time,
+ date_time datetime,
+ time_stamp timestamp,
+ PRIMARY KEY (auto)
+) engine=ndb;
+
+insert into t1 values
+(NULL,"aaaa","aaaa",0xAAAA,0xAAAA,-1,-1,-1,-1,-1,1.1,1.1,1.1,1,1,1,1,1,
+ b'001','one','one',
+ '1901-01-01','1901',
+'01:01:01','1901-01-01 01:01:01',NULL),
+(NULL,"bbbb","bbbb",0xBBBB,0xBBBB,-2,-2,-2,-2,-2,2.2,2.2,2.2,2,2,2,2,2,
+ b'010','two','one,two',
+ '1902-02-02','1902',
+'02:02:02','1902-02-02 02:02:02',NULL),
+(NULL,"cccc","cccc",0xCCCC,0xCCCC,-3,-3,-3,-3,-3,3.3,3.3,3.3,3,3,3,3,3,
+ b'011','three','one,two,three',
+ '1903-03-03','1903',
+'03:03:03','1903-03-03 03:03:03',NULL),
+(NULL,"dddd","dddd",0xDDDD,0xDDDD,-4,-4,-4,-4,-4,4.4,4.4,4.4,4,4,4,4,4,
+ b'100','four','one,two,three,four',
+ '1904-04-04','1904',
+'04:04:04','1904-04-04 04:04:04',NULL);
+
+CREATE TABLE t2 (pk1 int unsigned NOT NULL PRIMARY KEY, attr1 int unsigned NOT NULL, attr2 int unsigned, attr3 VARCHAR(10) ) ENGINE=ndbcluster;
+
+insert into t2 values (0,0,0, "a"),(1,1,1,"b"),(2,2,NULL,NULL),(3,3,3,"d"),(4,4,4,"e"),(5,5,5,"f");
+
+CREATE TABLE t3 (pk1 int unsigned NOT NULL PRIMARY KEY, attr1 int unsigned NOT NULL, attr2 bigint unsigned, attr3 tinyint unsigned, attr4 VARCHAR(10) ) ENGINE=ndbcluster;
+
+insert into t3 values (0,0,0,0,"a"),(1,1,9223372036854775803,1,"b"),(2,2,9223372036854775804,2,"c"),(3,3,9223372036854775805,3,"d"),(4,4,9223372036854775806,4,"e"),(5,5,9223372036854775807,5,"f");
+
+CREATE TABLE t4 (pk1 int unsigned NOT NULL PRIMARY KEY, attr1 int unsigned NOT NULL, attr2 bigint unsigned, attr3 tinyint unsigned, attr4 VARCHAR(10) , KEY (attr1)) ENGINE=ndbcluster;
+
+insert into t4 values (0,0,0,0,"a"),(1,1,9223372036854775803,1,"b"),(2,2,9223372036854775804,2,"c"),(3,3,9223372036854775805,3,"d"),(4,4,9223372036854775806,4,"e"),(5,5,9223372036854775807,5,"f");
+
+set @old_ecpd = @@session.engine_condition_pushdown;
+set engine_condition_pushdown = off;
+
+# Test all types and compare operators
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+bits = b'001' and
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+bits != b'001' and
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+bits > b'001' and
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+bits >= b'001' and
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+bits < b'100' and
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 and
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+bits <= b'100' and
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+
+# Test LIKE/NOT LIKE
+select auto from t1 where
+string like "b%" and
+vstring like "b%" and
+bin like concat(0xBB, '%') and
+vbin like concat(0xBB, '%')
+order by auto;
+
+select auto from t1 where
+string not like "b%" and
+vstring not like "b%" and
+bin not like concat(0xBB, '%') and
+vbin not like concat(0xBB, '%')
+order by auto;
+
+# Various tests
+select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
+select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
+select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
+select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
+select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
+select * from t3,t4 where t4.attr1 > 1 and t4.attr2 = t3.attr2 and t4.attr3 < 5 order by t4.pk1;
+
+set engine_condition_pushdown = on;
+
+# Test all types and compare operators
+explain
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+
+explain
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+/* bits != b'001' and */
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+/* bits != b'001' and */
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+
+explain
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+/* bits > b'001' and */
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+/* bits > b'001' and */
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+
+explain
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+/* bits >= b'001' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+/* bits >= b'001' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+
+explain
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+/* bits < b'100' and */
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+/* bits < b'100' and */
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+
+explain
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 - 1 + 1 and /* Checking function composition */
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+/* bits <= b'100' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 - 1 + 1 and /* Checking function composition */
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+/* bits <= b'100' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+
+# Test index scan with filter
+create index medium_index on t1(medium);
+
+# Test all types and compare operators
+explain
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01'
+order by auto;
+
+explain
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+/* bits != b'001' and */
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string != "aaaa" and
+vstring != "aaaa" and
+bin != 0xAAAA and
+vbin != 0xAAAA and
+tiny != -1 and
+short != -1 and
+medium != -1 and
+long_int != -1 and
+longlong != -1 and
+(real_float < 1.0 or real_float > 2.0) and
+(real_double < 1.0 or real_double > 2.0) and
+(real_decimal < 1.0 or real_decimal > 2.0) and
+utiny != 1 and
+ushort != 1 and
+umedium != 1 and
+ulong != 1 and
+ulonglong != 1 and
+/* bits != b'001' and */
+options != 'one' and
+flags != 'one' and
+date_field != '1901-01-01' and
+year_field != '1901' and
+time_field != '01:01:01' and
+date_time != '1901-01-01 01:01:01'
+order by auto;
+
+explain
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+/* bits > b'001' and */
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string > "aaaa" and
+vstring > "aaaa" and
+bin > 0xAAAA and
+vbin > 0xAAAA and
+tiny < -1 and
+short < -1 and
+medium < -1 and
+long_int < -1 and
+longlong < -1 and
+real_float > 1.1 and
+real_double > 1.1 and
+real_decimal > 1.1 and
+utiny > 1 and
+ushort > 1 and
+umedium > 1 and
+ulong > 1 and
+ulonglong > 1 and
+/* bits > b'001' and */
+(options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field > '1901-01-01' and
+year_field > '1901' and
+time_field > '01:01:01' and
+date_time > '1901-01-01 01:01:01'
+order by auto;
+
+explain
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+/* bits >= b'001' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+
+select auto from t1 where
+string >= "aaaa" and
+vstring >= "aaaa" and
+bin >= 0xAAAA and
+vbin >= 0xAAAA and
+tiny <= -1 and
+short <= -1 and
+medium <= -1 and
+long_int <= -1 and
+longlong <= -1 and
+real_float >= 1.0 and
+real_double >= 1.0 and
+real_decimal >= 1.0 and
+utiny >= 1 and
+ushort >= 1 and
+umedium >= 1 and
+ulong >= 1 and
+ulonglong >= 1 and
+/* bits >= b'001' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field >= '1901-01-01' and
+year_field >= '1901' and
+time_field >= '01:01:01' and
+date_time >= '1901-01-01 01:01:01'
+order by auto;
+
+explain
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+/* bits < b'100' and */
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+
+select auto from t1 where
+string < "dddd" and
+vstring < "dddd" and
+bin < 0xDDDD and
+vbin < 0xDDDD and
+tiny > -4 and
+short > -4 and
+medium > -4 and
+long_int > -4 and
+longlong > -4 and
+real_float < 4.4 and
+real_double < 4.4 and
+real_decimal < 4.4 and
+utiny < 4 and
+ushort < 4 and
+umedium < 4 and
+ulong < 4 and
+ulonglong < 4 and
+/* bits < b'100' and */
+(options = 'one' or options = 'two' or options = 'three') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three') and
+date_field < '1904-01-01' and
+year_field < '1904' and
+time_field < '04:04:04' and
+date_time < '1904-04-04 04:04:04'
+order by auto;
+
+explain
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 - 1 + 1 and /* Checking function composition */
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+/* bits <= b'100' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+
+select auto from t1 where
+string <= "dddd" and
+vstring <= "dddd" and
+bin <= 0xDDDD and
+vbin <= 0xDDDD and
+tiny >= -4 and
+short >= -4 and
+medium >= -4 and
+long_int >= -4 and
+longlong >= -4 and
+real_float <= 4.5 and
+real_double <= 4.5 and
+real_decimal <= 4.5 and
+utiny <= 4 - 1 + 1 and /* Checking function composition */
+ushort <= 4 and
+umedium <= 4 and
+ulong <= 4 and
+ulonglong <= 4 and
+/* bits <= b'100' and */
+(options = 'one' or options = 'two' or options = 'three' or options = 'four') and
+(flags = 'one' or flags = 'one,two' or flags = 'one,two,three' or flags = 'one,two,three,four') and
+date_field <= '1904-04-04' and
+year_field <= '1904' and
+time_field <= '04:04:04' and
+date_time <= '1904-04-04 04:04:04'
+order by auto;
+
+# Test LIKE/NOT LIKE
+explain
+select auto from t1 where
+string like "b%" and
+vstring like "b%" and
+bin like concat(0xBB, '%') and
+vbin like concat(0xBB, '%')
+order by auto;
+
+select auto from t1 where
+string like "b%" and
+vstring like "b%" and
+bin like concat(0xBB, '%') and
+vbin like concat(0xBB, '%')
+order by auto;
+
+explain
+select auto from t1 where
+string not like "b%" and
+vstring not like "b%" and
+bin not like concat(0xBB, '%') and
+vbin not like concat(0xBB, '%')
+order by auto;
+
+select auto from t1 where
+string not like "b%" and
+vstring not like "b%" and
+bin not like concat(0xBB, '%') and
+vbin not like concat(0xBB, '%')
+order by auto;
+
+# Update test
+update t1
+set medium = 17
+where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = -1 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01';
+
+# Delete test
+delete from t1
+where
+string = "aaaa" and
+vstring = "aaaa" and
+bin = 0xAAAA and
+vbin = 0xAAAA and
+tiny = -1 and
+short = -1 and
+medium = 17 and
+long_int = -1 and
+longlong = -1 and
+real_float > 1.0 and real_float < 2.0 and
+real_double > 1.0 and real_double < 2.0 and
+real_decimal > 1.0 and real_decimal < 2.0 and
+utiny = 1 and
+ushort = 1 and
+umedium = 1 and
+ulong = 1 and
+ulonglong = 1 and
+/* bits = b'001' and */
+options = 'one' and
+flags = 'one' and
+date_field = '1901-01-01' and
+year_field = '1901' and
+time_field = '01:01:01' and
+date_time = '1901-01-01 01:01:01';
+
+select count(*) from t1;
+
+# Various tests
+explain
+select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
+select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
+
+explain
+select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
+select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
+
+explain
+select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
+select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
+
+explain
+select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
+select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
+
+explain
+select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
+select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
+
+explain
+select * from t3,t4 where t4.attr1 > 1 and t4.attr2 = t3.attr2 and t4.attr3 < 5 order by t4.pk1;
+select * from t3,t4 where t4.attr1 > 1 and t4.attr2 = t3.attr2 and t4.attr3 < 5 order by t4.pk1;
+
+# Some tests that are currently not supported and should not push condition
+explain
+select auto from t1 where string = "aaaa" collate latin1_general_ci order by auto;
+explain
+select * from t2 where (attr1 < 2) = (attr2 < 2) order by pk1;
+
+set engine_condition_pushdown = @old_ecpd;
+DROP TABLE t1,t2,t3,t4;
diff --git a/mysql-test/t/ndb_grant.later b/mysql-test/t/ndb_grant.later
index d3899d9972f..b4885d2c5fc 100644
--- a/mysql-test/t/ndb_grant.later
+++ b/mysql-test/t/ndb_grant.later
@@ -226,19 +226,23 @@ grant select on test.t1 to drop_user2@localhost;
grant select on test.* to drop_user3@localhost;
grant select on *.* to drop_user4@localhost;
commit;
---error 1268
+flush privileges;
+# Drop user now implicitly revokes all privileges.
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
begin;
+--error 1269
revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost,
drop_user3@localhost, drop_user4@localhost;
commit;
+flush privileges;
+#--error 1268
drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost,
drop_user4@localhost;
drop table t1;
begin;
grant usage on *.* to mysqltest_1@localhost identified by "password";
-grant select, update, insert on test.* to mysqltest@localhost;
+grant select, update, insert on test.* to mysqltest_1@localhost;
commit;
show grants for mysqltest_1@localhost;
drop user mysqltest_1@localhost;
@@ -352,6 +356,11 @@ DROP DATABASE testdb9;
DROP DATABASE testdb10;
#
+# just SHOW PRIVILEGES test
+#
+SHOW PRIVILEGES;
+
+#
# Alter mysql system tables back to myisam
#
use mysql;
diff --git a/mysql-test/t/ndb_index_ordered.test b/mysql-test/t/ndb_index_ordered.test
index 4bc2021d45e..9c9d5d5a84f 100644
--- a/mysql-test/t/ndb_index_ordered.test
+++ b/mysql-test/t/ndb_index_ordered.test
@@ -149,6 +149,37 @@ select * from t1 use index (bc) where b IS NOT NULL order by a;
drop table t1;
#
+# Order by again, including descending.
+#
+
+create table t1 (
+ a int unsigned primary key,
+ b int unsigned,
+ c char(10),
+ key bc (b, c)
+) engine=ndb;
+
+insert into t1 values(1,1,'a'),(2,2,'b'),(3,3,'c'),(4,4,'d'),(5,5,'e');
+insert into t1 select a*7,10*b,'f' from t1;
+insert into t1 select a*13,10*b,'g' from t1;
+insert into t1 select a*17,10*b,'h' from t1;
+insert into t1 select a*19,10*b,'i' from t1;
+insert into t1 select a*23,10*b,'j' from t1;
+insert into t1 select a*29,10*b,'k' from t1;
+#
+select b, c from t1 where b <= 10 and c <'f' order by b, c;
+select b, c from t1 where b <= 10 and c <'f' order by b desc, c desc;
+#
+select b, c from t1 where b=4000 and c<'k' order by b, c;
+select b, c from t1 where b=4000 and c<'k' order by b desc, c desc;
+select b, c from t1 where 1000<=b and b<=100000 and c<'j' order by b, c;
+select b, c from t1 where 1000<=b and b<=100000 and c<'j' order by b desc, c desc;
+#
+select min(b), max(b) from t1;
+#
+drop table t1;
+
+#
# Bug #6435
CREATE TABLE test1 (
SubscrID int(11) NOT NULL auto_increment,
diff --git a/mysql-test/t/ndb_index_unique.test b/mysql-test/t/ndb_index_unique.test
index 67cf6cb4537..d6de013c1e2 100644
--- a/mysql-test/t/ndb_index_unique.test
+++ b/mysql-test/t/ndb_index_unique.test
@@ -2,7 +2,7 @@
-- source include/not_embedded.inc
--disable_warnings
-drop table if exists t1, t2, t3, t4, t5, t6, t7;
+drop table if exists t1, t2, t3, t4, t5, t6, t7, t8;
--enable_warnings
#
@@ -183,8 +183,8 @@ INSERT INTO t3 VALUES (1,'V1',NULL);
CREATE TABLE t4 (
uid bigint(20) unsigned NOT NULL default '0',
gid bigint(20) unsigned NOT NULL,
- rid bigint(20) unsigned NOT NULL default '-1',
- cid bigint(20) unsigned NOT NULL default '-1',
+ rid bigint(20) unsigned NOT NULL,
+ cid bigint(20) unsigned NOT NULL,
UNIQUE KEY m (uid,gid,rid,cid)
) engine=ndbcluster;
INSERT INTO t4 VALUES (1,1,2,4);
@@ -210,8 +210,8 @@ CREATE TABLE t7 (
mid bigint(20) unsigned NOT NULL PRIMARY KEY,
uid bigint(20) unsigned NOT NULL default '0',
gid bigint(20) unsigned NOT NULL,
- rid bigint(20) unsigned NOT NULL default '-1',
- cid bigint(20) unsigned NOT NULL default '-1',
+ rid bigint(20) unsigned NOT NULL,
+ cid bigint(20) unsigned NOT NULL,
UNIQUE KEY m (uid,gid,rid,cid)
) engine=ndbcluster;
INSERT INTO t7 VALUES(1, 1, 1, 1, 1);
diff --git a/mysql-test/t/ndb_read_multi_range.test b/mysql-test/t/ndb_read_multi_range.test
new file mode 100644
index 00000000000..9d1f918fef0
--- /dev/null
+++ b/mysql-test/t/ndb_read_multi_range.test
@@ -0,0 +1,202 @@
+-- source include/have_ndb.inc
+-- source include/not_embedded.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1, r1;
+--enable_warnings
+
+#
+# Basic test to see that batching is working
+#
+
+create table t1 (
+ a int primary key,
+ b int not null,
+ c int not null,
+ index(b), unique index using hash(c)
+) engine = ndb;
+insert into t1 values
+ (1,2,1),(2,3,2),(3,4,3),(4,5,4),
+ (5,2,12),(6,3,11),(7,4,10),(8,5,9),
+ (9,2,8),(10,3,7),(11,4,6),(12,5,5);
+
+# batch on primary key
+create table r1 as select * from t1 where a in (2,8,12);
+select * from r1 order by a;
+drop table r1;
+
+# batch on ordered index
+create table r1 as select * from t1 where b in (1,2,5);
+select * from r1 order by a;
+drop table r1;
+
+# batch on unique hash index
+create table r1 as select * from t1 where c in (2,8,12);
+select * from r1 order by a;
+drop table r1;
+
+# batch mixed
+create table r1 as select * from t1 where a in (2,8) or (a > 11) or (a <= 1);
+select * from r1 order by a;
+drop table r1;
+
+# batch on primary key, missing values
+create table r1 as select * from t1 where a in (33,8,12);
+select * from r1 order by a;
+drop table r1;
+create table r1 as select * from t1 where a in (2,33,8,12,34);
+select * from r1 order by a;
+drop table r1;
+
+# batch on ordered index, missing values
+create table r1 as select * from t1 where b in (1,33,5);
+select * from r1 order by a;
+drop table r1;
+select * from t1 where b in (1,33,5) order by a;
+create table r1 as select * from t1 where b in (45,1,33,5,44);
+select * from r1 order by a;
+drop table r1;
+select * from t1 where b in (45,22) order by a;
+
+# batch on unique hash index, missing values
+create table r1 as select * from t1 where c in (2,8,33);
+select * from r1 order by a;
+drop table r1;
+create table r1 as select * from t1 where c in (13,2,8,33,12);
+select * from r1 order by a;
+drop table r1;
+
+select * from t1 where a in (33,8,12) order by a;
+select * from t1 where a in (33,34,35) order by a;
+select * from t1 where a in (2,8) or (a > 11) or (a <= 1) order by a;
+select * from t1 where b in (6,7) or (b <= 5) or (b >= 10) order by b,a;
+select * from t1 where c in (13,2,8,33,12) order by c,a;
+drop table t1;
+
+#
+# Somewhat more complicated
+#
+
+create table t1 (
+ a int not null,
+ b int not null,
+ c int not null,
+ d int not null,
+ e int not null,
+ primary key (a,b,c,d), index (d)
+) engine = ndb;
+
+insert into t1 values
+ (1,2,1,1,1),(2,3,2,3,1),(3,4,3,1,1),(4,5,4,7,1),
+ (5,2,12,12,1),(6,3,11,1,1),(7,4,10,3,1),(8,5,9,5,1),
+ (9,2,8,6,1),(10,3,7,5,1),(11,4,6,3,1),(12,5,5,2,1),
+ (1,2,1,2,1),
+ (1,2,1,3,1),
+ (1,2,1,4,1),
+ (1,2,1,5,1);
+
+# batch on primary key
+create table r1 as select * from t1
+ where a=1 and b=2 and c=1 and d in (1,4,3,2);
+select * from r1 order by a,b,c,d;
+drop table r1;
+
+# batched update ordered index, one value for all
+update t1 set e = 100
+ where d in (12,6,7);
+select * from t1 where d in (12,6,7) order by a,b,c,d;
+select * from t1 where d not in (12,6,7) and e = 100;
+
+# batched update primary key, one value for all
+update t1
+ set e = 101
+ where a=1 and
+ b=2 and
+ c=1 and
+ d in (1,4,3,2);
+select *
+ from t1
+ where a=1 and b=2 and c=1 and d in (1,4,3,2)
+ order by a,b,c,d;
+select *
+ from t1
+ where not (a=1 and b=2 and c=1 and d in (1,4,3,2))
+ and e=101;
+
+
+# batched update ordered index, different values
+update t1
+ set e =
+ (case d
+ when 12 then 112
+ when 6 then 106
+ when 7 then 107
+ end)
+ where d in (12,6,7);
+select * from t1 where d in (12,6,7) order by a,b,c,d;
+
+# batched update primary key, different values
+update t1
+ set e =
+ (case d
+ when 1 then 111
+ when 4 then 444
+ when 3 then 333
+ when 2 then 222
+ end)
+ where a=1 and
+ b=2 and
+ c=1 and
+ d in (1,4,3,2);
+select *
+ from t1
+ where a=1 and b=2 and c=1 and d in (1,4,3,2)
+ order by a,b,c,d;
+
+# batched delete
+delete from t1 where d in (12,6,7);
+select * from t1 where d in (12,6,7);
+
+drop table t1;
+
+# null handling
+create table t1 (
+ a int not null primary key,
+ b int,
+ c int,
+ d int,
+ unique index (b),
+ index(c)
+) engine = ndb;
+
+insert into t1 values
+ (1,null,1,1),
+ (2,2,2,2),
+ (3,null,null,3),
+ (4,4,null,4),
+ (5,null,5,null),
+ (6,6,6,null),
+ (7,null,null,null),
+ (8,8,null,null),
+ (9,null,9,9),
+ (10,10,10,10),
+ (11,null,null,11),
+ (12,12,null,12),
+ (13,null,13,null),
+ (14,14,14,null),
+ (15,null,null,null),
+ (16,16,null,null);
+
+create table t2 as select * from t1 where a in (5,6,7,8,9,10);
+select * from t2 order by a;
+drop table t2;
+
+create table t2 as select * from t1 where b in (5,6,7,8,9,10);
+select * from t2 order by a;
+drop table t2;
+
+create table t2 as select * from t1 where c in (5,6,7,8,9,10);
+select * from t2 order by a;
+drop table t2;
+
+drop table t1;
diff --git a/mysql-test/t/ndb_restore.test b/mysql-test/t/ndb_restore.test
index ee47f7da6bc..e3191538a22 100644
--- a/mysql-test/t/ndb_restore.test
+++ b/mysql-test/t/ndb_restore.test
@@ -1,4 +1,5 @@
-- source include/have_ndb.inc
+-- source include/ndb_default_cluster.inc
-- source include/not_embedded.inc
--disable_warnings
diff --git a/mysql-test/t/ndb_types.test b/mysql-test/t/ndb_types.test
index 4276fa147eb..d4bf4133807 100644
--- a/mysql-test/t/ndb_types.test
+++ b/mysql-test/t/ndb_types.test
@@ -21,11 +21,13 @@ CREATE TABLE t1 (
longlong bigint(13) DEFAULT '0' NOT NULL,
real_float float(13,1) DEFAULT 0.0 NOT NULL,
real_double double(16,4),
+ real_decimal decimal(16,4),
utiny tinyint(3) unsigned DEFAULT '0' NOT NULL,
ushort smallint(5) unsigned zerofill DEFAULT '00000' NOT NULL,
umedium mediumint(8) unsigned DEFAULT '0' NOT NULL,
ulong int(11) unsigned DEFAULT '0' NOT NULL,
ulonglong bigint(13) unsigned DEFAULT '0' NOT NULL,
+ bits bit(3),
options enum('one','two','tree') not null,
flags set('one','two','tree') not null,
date_field date,
@@ -51,15 +53,15 @@ set @now = now();
sleep 1;
insert into t1
(string,vstring,bin,vbin,tiny,short,medium,long_int,longlong,
- real_float,real_double, utiny, ushort, umedium,ulong,ulonglong,
- options,flags,date_field,year_field,time_field,date_time)
+ real_float,real_double, real_decimal,utiny, ushort, umedium,ulong,ulonglong,
+ bits,options,flags,date_field,year_field,time_field,date_time)
values
-("aaaa","aaaa",0xAAAA,0xAAAA,-1,-1,-1,-1,-1,1.1,1.1,1,1,1,1,1,
- 'one','one', '1901-01-01','1901','01:01:01','1901-01-01 01:01:01');
+("aaaa","aaaa",0xAAAA,0xAAAA,-1,-1,-1,-1,-1,1.1,1.1,1.1,1,1,1,1,1,
+ b'001','one','one', '1901-01-01','1901','01:01:01','1901-01-01 01:01:01');
select auto,string,vstring,bin,vbin,tiny,short,medium,long_int,longlong,
- real_float,real_double, utiny, ushort, umedium,ulong,ulonglong,
- options,flags,date_field,year_field,time_field,date_time
+ real_float,real_double,real_decimal,utiny,ushort,umedium,ulong,ulonglong,
+ bits,options,flags,date_field,year_field,time_field,date_time
from t1;
select time_stamp>@now from t1;
@@ -67,13 +69,14 @@ set @now = now();
sleep 1;
update t1 set string="bbbb",vstring="bbbb",bin=0xBBBB,vbin=0xBBBB,
tiny=-2,short=-2,medium=-2,long_int=-2,longlong=-2,real_float=2.2,
-real_double=2.2,utiny=2,ushort=2,umedium=2,ulong=2,ulonglong=2,
+real_double=2.2,real_decimal=2.2,utiny=2,ushort=2,umedium=2,ulong=2,
+ulonglong=2, bits=b'010',
options='one',flags='one', date_field='1902-02-02',year_field='1902',
time_field='02:02:02',date_time='1902-02-02 02:02:02' where auto=1;
select auto,string,vstring,bin,vbin,tiny,short,medium,long_int,longlong,
- real_float,real_double, utiny, ushort, umedium,ulong,ulonglong,
- options,flags,date_field,year_field,time_field,date_time
+ real_float,real_double,real_decimal,utiny,ushort,umedium,ulong,ulonglong,
+ bits,options,flags,date_field,year_field,time_field,date_time
from t1;
select time_stamp>@now from t1;
diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test
index 9ddef252d67..4cd20979319 100644
--- a/mysql-test/t/null.test
+++ b/mysql-test/t/null.test
@@ -59,7 +59,7 @@ drop table t1;
#
# Test inserting and updating with NULL
#
-CREATE TABLE t1 (a varchar(16) NOT NULL, b smallint(6) NOT NULL, c datetime NOT NULL, d smallint(6) NOT NULL);
+CREATE TABLE t1 (a varchar(16) NOT NULL default '', b smallint(6) NOT NULL default 0, c datetime NOT NULL default '0000-00-00 00:00:00', d smallint(6) NOT NULL default 0);
INSERT INTO t1 SET a = "", d= "2003-01-14 03:54:55";
UPDATE t1 SET d=1/NULL;
UPDATE t1 SET d=NULL;
@@ -100,9 +100,9 @@ drop table t1;
select cast(NULL as signed);
#
-# Test case for bug #4256
+# IS NULL is unable to use index in range if column is declared not null
+# (Bug #4256)
#
-
create table t1(i int, key(i));
insert into t1 values(1);
insert into t1 select i*2 from t1;
@@ -114,9 +114,12 @@ insert into t1 select i*2 from t1;
insert into t1 select i*2 from t1;
insert into t1 select i*2 from t1;
insert into t1 select i*2 from t1;
+insert into t1 values(null);
explain select * from t1 where i=2 or i is null;
+select count(*) from t1 where i=2 or i is null;
alter table t1 change i i int not null;
explain select * from t1 where i=2 or i is null;
+select count(*) from t1 where i=2 or i is null;
drop table t1;
#
diff --git a/mysql-test/t/null_key.test b/mysql-test/t/null_key.test
index 9b346a181bf..d7f6a634d1e 100644
--- a/mysql-test/t/null_key.test
+++ b/mysql-test/t/null_key.test
@@ -26,6 +26,8 @@ select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3;
select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3;
select * from t1 where (a is null or a = 7) and b=7;
select * from t1 where a is null and b=9 or a is null and b=7 limit 3;
+select * from t1 where a > 1 and a < 3 limit 1;
+select * from t1 where a > 8 and a < 9;
create table t2 like t1;
insert into t2 select * from t1;
alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10));
diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test
index 4f3b0f51286..03b26e0b6c6 100644
--- a/mysql-test/t/olap.test
+++ b/mysql-test/t/olap.test
@@ -153,6 +153,13 @@ SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1
SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP;
SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP;
+SELECT b, a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP;
+SELECT DISTINCT b,a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP;
+
+ALTER TABLE t1 ADD COLUMN c INT;
+SELECT a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP;
+SELECT distinct a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP;
+
DROP TABLE t1;
#
diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test
index 912c9fb9bec..2262395d586 100644
--- a/mysql-test/t/openssl_1.test
+++ b/mysql-test/t/openssl_1.test
@@ -20,22 +20,22 @@ connect (con4,localhost,ssl_user4,,);
connection con1;
select * from t1;
---error 1044;
+--error 1142;
delete from t1;
connection con2;
select * from t1;
---error 1044;
+--error 1142;
delete from t1;
connection con3;
select * from t1;
---error 1044;
+--error 1142;
delete from t1;
connection con4;
select * from t1;
---error 1044;
+--error 1142;
delete from t1;
connection default;
diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test
index c6a77c71b2f..36eee6e43b7 100644
--- a/mysql-test/t/order_by.test
+++ b/mysql-test/t/order_by.test
@@ -206,7 +206,7 @@ CREATE TABLE t1 (
favo_tv varchar(50) NOT NULL default '',
favo_eten varchar(50) NOT NULL default '',
favo_muziek varchar(30) NOT NULL default '',
- info text NOT NULL,
+ info text NOT NULL default '',
ipnr varchar(30) NOT NULL default '',
PRIMARY KEY (member_id)
) ENGINE=MyISAM PACK_KEYS=1;
@@ -501,6 +501,11 @@ set max_sort_length=20;
select a from t1 order by a;
drop table t1;
+create table t1 (a int not null, b int not null, c int not null);
+insert t1 values (1,1,1),(1,1,2),(1,2,1);
+select a, b from t1 group by a, b order by sum(c);
+drop table t1;
+
#
# Bug #7331
#
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index b204e59267e..820fae12db0 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -485,6 +485,17 @@ execute stmt;
deallocate prepare stmt;
drop table t1, t2;
+#
+# Bug#6102 "Server crash with prepared statement and blank after
+# function name"
+# ensure that stored functions are cached when preparing a statement
+# before we open tables
+#
+create table t1 (a varchar(20));
+insert into t1 values ('foo');
+--error 1305
+prepare stmt FROM 'SELECT char_length (a) FROM t1';
+drop table t1;
#
# Bug #6089: FOUND_ROWS returns wrong values when no table/view is used
@@ -496,3 +507,83 @@ SELECT FOUND_ROWS();
execute stmt;
SELECT FOUND_ROWS();
deallocate prepare stmt;
+
+#
+# Bug#8115: equality propagation and prepared statements
+#
+
+create table t1 (a char(3) not null, b char(3) not null,
+ c char(3) not null, primary key (a, b, c));
+create table t2 like t1;
+
+# reduced query
+prepare stmt from
+ "select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b)
+ where t1.a=1";
+execute stmt;
+execute stmt;
+execute stmt;
+
+# original query
+prepare stmt from
+"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from
+(t1 left outer join t2 on t2.a=? and t1.b=t2.b)
+left outer join t2 t3 on t3.a=? where t1.a=?";
+
+set @a:=1, @b:=1, @c:=1;
+
+execute stmt using @a, @b, @c;
+execute stmt using @a, @b, @c;
+execute stmt using @a, @b, @c;
+
+deallocate prepare stmt;
+
+drop table t1,t2;
+
+
+#
+# Bug#9383: INFORMATION_SCHEMA.COLUMNS, JOIN, Crash, prepared statement
+#
+
+eval SET @aux= "SELECT COUNT(*)
+ FROM INFORMATION_SCHEMA.COLUMNS A,
+ INFORMATION_SCHEMA.COLUMNS B
+ WHERE A.TABLE_SCHEMA = B.TABLE_SCHEMA
+ AND A.TABLE_NAME = B.TABLE_NAME
+ AND A.COLUMN_NAME = B.COLUMN_NAME AND
+ A.TABLE_NAME = 'user'";
+
+let $exec_loop_count= 3;
+eval prepare my_stmt from @aux;
+while ($exec_loop_count)
+{
+ eval execute my_stmt;
+ dec $exec_loop_count;
+}
+deallocate prepare my_stmt;
+
+# Test CALL in prepared mode
+delimiter |;
+--disable_warnings
+drop procedure if exists p1|
+drop table if exists t1|
+--enable_warnings
+create table t1 (id int)|
+insert into t1 values(1)|
+create procedure p1(a int, b int)
+begin
+ declare c int;
+ select max(id)+1 into c from t1;
+ insert into t1 select a+b;
+ insert into t1 select a-b;
+ insert into t1 select a-c;
+end|
+set @a= 3, @b= 4|
+prepare stmt from "call p1(?, ?)"|
+execute stmt using @a, @b|
+execute stmt using @a, @b|
+select * from t1|
+deallocate prepare stmt|
+drop procedure p1|
+drop table t1|
+delimiter ;|
diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test
index bf177a108dd..1fa9d30eaba 100644
--- a/mysql-test/t/ps_1general.test
+++ b/mysql-test/t/ps_1general.test
@@ -11,7 +11,12 @@
--disable_warnings
drop table if exists t5, t6, t7, t8;
drop database if exists mysqltest ;
+
+# Cleanup from other tests
drop database if exists client_test_db;
+drop database if exists testtets;
+drop table if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop view if exists t1Aa,t2Aa,v1Aa,v2Aa;
--enable_warnings
--disable_query_log
@@ -287,6 +292,14 @@ prepare stmt4 from ' show databases ';
execute stmt4;
prepare stmt4 from ' show tables from test like ''t2%'' ';
execute stmt4;
+prepare stmt4 from ' show columns from t2 where field in (select ?) ';
+SET @arg00="a";
+execute stmt4 using @arg00;
+SET @arg00="b";
+execute stmt4 using @arg00;
+SET @arg00=1;
+execute stmt4 using @arg00;
+
prepare stmt4 from ' show columns from t2 from test like ''a%'' ';
execute stmt4;
create index t2_idx on t2(b);
@@ -423,20 +436,6 @@ create database mysqltest ;
prepare stmt3 from ' drop database mysqltest ';
drop database mysqltest ;
-## grant/revoke + drop user
---error 1295
-prepare stmt3 from ' grant all on test.t1 to drop_user@localhost
-identified by ''looser'' ';
-grant all on test.t1 to drop_user@localhost
-identified by 'looser' ;
---error 1295
-prepare stmt3 from ' revoke all privileges on test.t1 from
-drop_user@localhost ';
-revoke all privileges on test.t1 from drop_user@localhost ;
---error 1295
-prepare stmt3 from ' drop user drop_user@localhost ';
-drop user drop_user@localhost;
-
#### table related commands
## describe
prepare stmt3 from ' describe t2 ';
@@ -472,9 +471,7 @@ prepare stmt1 from ' handler t1 open ';
## commit/rollback
---error 1295
prepare stmt3 from ' commit ' ;
---error 1295
prepare stmt3 from ' rollback ' ;
@@ -486,10 +483,10 @@ select 'a' || 'b' ;
prepare stmt4 from ' SET sql_mode="" ';
execute stmt4;
# check if the sql_mode is not ansi
-select 'a' || 'b' ;
+select '2' || '3' ;
# Will a switch of the sqlmode affect the execution of already prepared
# statements ?
-prepare stmt5 from ' select ''a'' || ''b'' ' ;
+prepare stmt5 from ' select ''2'' || ''3'' ' ;
execute stmt5;
SET sql_mode=ansi;
execute stmt5;
@@ -575,11 +572,8 @@ execute stmt3 using @arg00;
select m from t3;
drop table t3;
---error 1295
prepare stmt3 from ' create index t2_idx on t2(b) ';
---error 1295
prepare stmt3 from ' drop index t2_idx on t2 ' ;
---error 1295
prepare stmt3 from ' alter table t2 drop primary key ';
## RENAME TABLE
@@ -598,7 +592,7 @@ prepare stmt1 from ' rename table t5 to t6, t7 to t8 ' ;
create table t5 (a int) ;
# rename must fail, t7 does not exist
# Clean up the filename here because embedded server reports whole path
---replace_result \\ / $MYSQL_TEST_DIR . /var/master-data/ /
+--replace_result \\ / $MYSQL_TEST_DIR . /var/master-data/ / t7.frm t7
--error 1017
execute stmt1 ;
create table t7 (a int) ;
diff --git a/mysql-test/t/ps_4heap.test b/mysql-test/t/ps_4heap.test
index a7b2e332af4..1c9346721ab 100644
--- a/mysql-test/t/ps_4heap.test
+++ b/mysql-test/t/ps_4heap.test
@@ -32,10 +32,10 @@ eval create table t9
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,
- c17 year, c18 bit, c19 bool, c20 char,
- c21 char(10), c22 varchar(30), c23 char(100), c24 char(100),
- c25 char(100), c26 char(100), c27 char(100), c28 char(100),
- c29 char(100), c30 char(100), c31 enum('one', 'two', 'three'),
+ 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),
+ c29 varchar(100), c30 varchar(100), c31 enum('one', 'two', 'three'),
c32 set('monday', 'tuesday', 'wednesday'),
primary key(c1)
) engine = $type ;
diff --git a/mysql-test/t/ps_5merge.test b/mysql-test/t/ps_5merge.test
index 9a79842709c..891d1be2c57 100644
--- a/mysql-test/t/ps_5merge.test
+++ b/mysql-test/t/ps_5merge.test
@@ -32,7 +32,7 @@ create table t9
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,
- c17 year, c18 bit, c19 bool, c20 char,
+ c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
@@ -63,7 +63,7 @@ create table t9
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,
- c17 year, c18 bit, c19 bool, c20 char,
+ c17 year, c18 tinyint, c19 bool, c20 char,
c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
diff --git a/mysql-test/t/ps_grant.test b/mysql-test/t/ps_grant.test
index 06613072824..07bd70f6cff 100644
--- a/mysql-test/t/ps_grant.test
+++ b/mysql-test/t/ps_grant.test
@@ -116,4 +116,17 @@ show grants for second_user@localhost ;
drop database mysqltest;
+## grant/revoke + drop user
+--error 1295
+prepare stmt3 from ' grant all on test.t1 to drop_user@localhost
+identified by ''looser'' ';
+grant all on test.t1 to drop_user@localhost
+identified by 'looser' ;
+--error 1295
+prepare stmt3 from ' revoke all privileges on test.t1 from
+drop_user@localhost ';
+revoke all privileges on test.t1 from drop_user@localhost ;
+--error 1295
+prepare stmt3 from ' drop user drop_user@localhost ';
+drop user drop_user@localhost;
diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test
index ad36d8b425a..475ba466ea9 100644
--- a/mysql-test/t/query_cache.test
+++ b/mysql-test/t/query_cache.test
@@ -616,9 +616,7 @@ set character_set_results=cp1251;
SELECT a,'Â','â'='Â' FROM t1;
show status like "Qcache_hits";
show status like "Qcache_queries_in_cache";
-#
-# Keep things tidy
-#
+
DROP TABLE t1;
#
@@ -638,7 +636,6 @@ DROP TABLE t1;
set character_set_results=null;
select @@character_set_results;
set character_set_results=default;
-
#
# query cache and environment variables
#
@@ -673,7 +670,36 @@ select group_concat(a) FROM t1 group by b;
set group_concat_max_len=default;
drop table t1;
+# comments before command
+#
+create table t1 (a int);
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+/**/ select * from t1;
+/**/ select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+#
+# Keep things tidy
+#
+DROP TABLE t1;
+SET GLOBAL query_cache_size=0;
+
+#
+# Information schema & query cache test
+#
+SET SESSION query_cache_type = 2;
+create table t1(a int);
+select table_name from information_schema.tables
+where table_schema="test";
+drop table t1;
+select table_name from information_schema.tables
+where table_schema="test";
# Bug #8480: REPAIR TABLE needs to flush the table from the query cache
+SET SESSION query_cache_type = 1;
set global query_cache_size=1024*1024;
flush query cache;
create table t1 ( a int );
diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test
index 3d3d4748fe3..84ae9674de9 100644
--- a/mysql-test/t/range.test
+++ b/mysql-test/t/range.test
@@ -181,8 +181,8 @@ create table t1 (x int, y int, index(x), index(y));
insert into t1 (x) values (1),(2),(3),(4),(5),(6),(7),(8),(9);
update t1 set y=x;
# between with only one end fixed
-explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 7 and t1.y+0;
-explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= 7 and t2.x <= t1.y+0;
+explain select * from t1, t1 t2 where t1.y = 8 and t2.x between 7 and t1.y+0;
+explain select * from t1, t1 t2 where t1.y = 8 and t2.x >= 7 and t2.x <= t1.y+0;
# between with both expressions on both ends
explain select * from t1, t1 t2 where t1.y = 2 and t2.x between t1.y-1 and t1.y+1;
explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= t1.y-1 and t2.x <= t1.y+1;
@@ -195,13 +195,15 @@ explain select count(*) from t1 where x in (1,2);
drop table t1;
#
-# bug #1172
+# bug #1172: "Force index" option caused server crash
#
CREATE TABLE t1 (key1 int(11) NOT NULL default '0', KEY i1 (key1));
-INSERT INTO t1 VALUES (0),(0),(1),(1);
+INSERT INTO t1 VALUES (0),(0),(0),(0),(0),(1),(1);
CREATE TABLE t2 (keya int(11) NOT NULL default '0', KEY j1 (keya));
INSERT INTO t2 VALUES (0),(0),(1),(1),(2),(2);
explain select * from t1, t2 where (t1.key1 <t2.keya + 1) and t2.keya=3;
+explain select * from t1 force index(i1), t2 force index(j1) where
+ (t1.key1 <t2.keya + 1) and t2.keya=3;
DROP TABLE t1,t2;
#
@@ -376,8 +378,12 @@ insert into t2(id, uid, name) select id, uid, name from t1;
select count(*) from t1;
select count(*) from t2;
+analyze table t1,t2;
+
explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0;
+explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid > 0;
explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0;
+explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid != 0;
select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0;
select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0;
@@ -410,26 +416,7 @@ select count(*) from t2 where x < -16;
select count(*) from t2 where x = -16;
select count(*) from t2 where x > -16;
select count(*) from t2 where x = 18446744073709551601;
-
-drop table t1;
---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;
-# The following query returns wrong value because the range optimizer can't
-# handle search on a signed value for an unsigned parameter. This will be fixed in
-# 5.0
-select count(*) from t1 where x > -16;
-select count(*) from t1 where x = 18446744073709551601;
-
-drop table t1;
+drop table t1,t2;
#
# Bug #6045: Binary Comparison regression in MySQL 4.1
diff --git a/mysql-test/t/replace.test b/mysql-test/t/replace.test
index 8429d80a4ef..2b3775f4f67 100644
--- a/mysql-test/t/replace.test
+++ b/mysql-test/t/replace.test
@@ -1,7 +1,5 @@
--- source include/have_isam.inc
-
#
-# Test of REPLACE with ISAM and MyISAM and HEAP
+# Test of REPLACE with MyISAM and HEAP
#
--disable_warnings
@@ -12,13 +10,11 @@ CREATE TABLE t1 (
gesuchnr int(11) DEFAULT '0' NOT NULL,
benutzer_id int(11) DEFAULT '0' NOT NULL,
PRIMARY KEY (gesuchnr,benutzer_id)
-) engine=ISAM;
+);
replace into t1 (gesuchnr,benutzer_id) values (2,1);
replace into t1 (gesuchnr,benutzer_id) values (1,1);
replace into t1 (gesuchnr,benutzer_id) values (1,1);
-alter table t1 engine=myisam;
-replace into t1 (gesuchnr,benutzer_id) values (1,1);
alter table t1 engine=heap;
replace into t1 (gesuchnr,benutzer_id) values (1,1);
drop table t1;
diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test
index 62e8eb7991c..afcaaef6811 100644
--- a/mysql-test/t/row.test
+++ b/mysql-test/t/row.test
@@ -7,9 +7,11 @@ select (1,2,3) IN ((3,2,3), (1,2,3), (1,3,3));
select row(10,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3));
select row(1,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3));
select row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3));
+--disable_ps_warnings
select row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a'));
-select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3));
select row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3));
+--enable_ps_warnings
+select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3));
select row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3));
select row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3));
select row('b',1.5,3) IN (row('b',NULL,3), row('a',1.5,3), row(1,3,3));
diff --git a/mysql-test/t/rowid_order_bdb.test b/mysql-test/t/rowid_order_bdb.test
new file mode 100644
index 00000000000..ef133054c35
--- /dev/null
+++ b/mysql-test/t/rowid_order_bdb.test
@@ -0,0 +1,108 @@
+#
+# Test for rowid ordering (and comparison) functions.
+# do index_merge select for tables with PK of various types.
+#
+--disable_warnings
+drop table if exists t1, t2, t3,t4;
+--enable_warnings
+
+-- source include/have_bdb.inc
+
+# Signed number as rowid
+create table t1 (
+ pk1 int not NULL,
+ key1 int(11),
+ key2 int(11),
+ PRIMARY KEY (pk1),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=bdb;
+insert into t1 values (-5, 1, 1),
+ (-100, 1, 1),
+ (3, 1, 1),
+ (0, 1, 1),
+ (10, 1, 1);
+explain select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+drop table t1;
+
+# Unsigned numbers as rowids
+create table t1 (
+ pk1 int unsigned not NULL,
+ key1 int(11),
+ key2 int(11),
+ PRIMARY KEY (pk1),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=bdb;
+insert into t1 values (0, 1, 1),
+ (0xFFFFFFFF, 1, 1),
+ (0xFFFFFFFE, 1, 1),
+ (1, 1, 1),
+ (2, 1, 1);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+drop table t1;
+
+# Case-insensitive char(N)
+create table t1 (
+ pk1 char(4) not NULL,
+ key1 int(11),
+ key2 int(11),
+ PRIMARY KEY (pk1),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=bdb collate latin2_general_ci;
+insert into t1 values ('a1', 1, 1),
+ ('b2', 1, 1),
+ ('A3', 1, 1),
+ ('B4', 1, 1);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+drop table t1;
+
+# Multi-part PK
+create table t1 (
+ pk1 int not NULL,
+ pk2 char(4) not NULL collate latin1_german1_ci,
+ pk3 char(4) not NULL collate latin1_bin,
+ key1 int(11),
+ key2 int(11),
+ PRIMARY KEY (pk1,pk2,pk3),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=bdb;
+insert into t1 values
+ (1, 'u', 'u', 1, 1),
+ (1, 'u', char(0xEC), 1, 1),
+ (1, 'u', 'x', 1, 1);
+insert ignore into t1 select pk1, char(0xEC), pk3, key1, key2 from t1;
+insert ignore into t1 select pk1, 'x', pk3, key1, key2 from t1 where pk2='u';
+insert ignore into t1 select 2, pk2, pk3, key1, key2 from t1;
+select * from t1;
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+
+# Hidden PK
+alter table t1 drop primary key;
+select * from t1;
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+drop table t1;
+
+# Variable-length PK
+# this is also test for Bug#2688
+create table t1 (
+ pk1 varchar(8) NOT NULL default '',
+ pk2 varchar(4) NOT NULL default '',
+ key1 int(11),
+ key2 int(11),
+ primary key(pk1, pk2),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=bdb;
+insert into t1 values ('','empt',2,2),
+ ('a','a--a',2,2),
+ ('bb','b--b',2,2),
+ ('ccc','c--c',2,2),
+ ('dddd','d--d',2,2);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+
+drop table t1;
+
diff --git a/mysql-test/t/rowid_order_innodb.test b/mysql-test/t/rowid_order_innodb.test
new file mode 100644
index 00000000000..fb4959d78e6
--- /dev/null
+++ b/mysql-test/t/rowid_order_innodb.test
@@ -0,0 +1,108 @@
+#
+# Test for rowid ordering (and comparison) functions.
+# do index_merge select for tables with PK of various types.
+#
+--disable_warnings
+drop table if exists t1, t2, t3,t4;
+--enable_warnings
+
+-- source include/have_innodb.inc
+
+# Signed number as rowid
+create table t1 (
+ pk1 int not NULL,
+ key1 int(11),
+ key2 int(11),
+ PRIMARY KEY (pk1),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=innodb;
+insert into t1 values (-5, 1, 1),
+ (-100, 1, 1),
+ (3, 1, 1),
+ (0, 1, 1),
+ (10, 1, 1);
+explain select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+drop table t1;
+
+# Unsigned numbers as rowids
+create table t1 (
+ pk1 int unsigned not NULL,
+ key1 int(11),
+ key2 int(11),
+ PRIMARY KEY (pk1),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=innodb;
+insert into t1 values (0, 1, 1),
+ (0xFFFFFFFF, 1, 1),
+ (0xFFFFFFFE, 1, 1),
+ (1, 1, 1),
+ (2, 1, 1);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+drop table t1;
+
+# Case-insensitive char(N)
+create table t1 (
+ pk1 char(4) not NULL,
+ key1 int(11),
+ key2 int(11),
+ PRIMARY KEY (pk1),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=innodb collate latin2_general_ci;
+insert into t1 values ('a1', 1, 1),
+ ('b2', 1, 1),
+ ('A3', 1, 1),
+ ('B4', 1, 1);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+drop table t1;
+
+# Multi-part PK
+create table t1 (
+ pk1 int not NULL,
+ pk2 char(4) not NULL collate latin1_german1_ci,
+ pk3 char(4) not NULL collate latin1_bin,
+ key1 int(11),
+ key2 int(11),
+ PRIMARY KEY (pk1,pk2,pk3),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=innodb;
+insert into t1 values
+ (1, 'u', 'u', 1, 1),
+ (1, 'u', char(0xEC), 1, 1),
+ (1, 'u', 'x', 1, 1);
+insert ignore into t1 select pk1, char(0xEC), pk3, key1, key2 from t1;
+insert ignore into t1 select pk1, 'x', pk3, key1, key2 from t1 where pk2='u';
+insert ignore into t1 select 2, pk2, pk3, key1, key2 from t1;
+select * from t1;
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+
+# Hidden PK
+alter table t1 drop primary key;
+select * from t1;
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+drop table t1;
+
+# Variable-length PK
+# this is also test for Bug#2688
+create table t1 (
+ pk1 varchar(8) NOT NULL default '',
+ pk2 varchar(4) NOT NULL default '',
+ key1 int(11),
+ key2 int(11),
+ primary key(pk1, pk2),
+ KEY key1 (key1),
+ KEY key2 (key2)
+) engine=innodb;
+insert into t1 values ('','empt',2,2),
+ ('a','a--a',2,2),
+ ('bb','b--b',2,2),
+ ('ccc','c--c',2,2),
+ ('dddd','d--d',2,2);
+select * from t1 force index(key1, key2) where key1 < 3 or key2 < 3;
+
+drop table t1;
+
diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test
index 835af92186f..e9a87529706 100644
--- a/mysql-test/t/rpl000001.test
+++ b/mysql-test/t/rpl000001.test
@@ -39,7 +39,13 @@ save_master_pos;
connection slave;
sync_with_master;
-#test handling of aborted connection in the middle of update
+# Test if the slave SQL thread can be more than 16K behind the slave
+# I/O thread (> IO_SIZE)
+
+connection master;
+# we'll use table-level locking to delay slave SQL thread
+create table t1 (n int) engine=myisam;
+sync_slave_with_master;
connection master;
reset master;
connection slave;
@@ -47,29 +53,26 @@ stop slave;
reset slave;
connection master;
-create table t1(n int);
-#we want the log to exceed 16K to test deal with the log that is bigger than
-#IO_SIZE
let $1=5000;
+# Generate 16K of relay log
disable_query_log;
while ($1)
{
- eval insert into t1 values($1+get_lock("hold_slave",10)*0);
+ eval insert into t1 values($1);
dec $1;
}
enable_query_log;
-# Try to cause a large relay log lag on the slave
+# Try to cause a large relay log lag on the slave by locking t1
connection slave;
-select get_lock("hold_slave",10);
-explain extended select get_lock("hold_slave",10);
+lock tables t1 read;
start slave;
#hope this is long enough for I/O thread to fetch over 16K relay log data
sleep 3;
-select release_lock("hold_slave");
-explain extended select release_lock("hold_slave");
unlock tables;
+#test handling of aborted connection in the middle of update
+
connection master;
create table t2(id int);
insert into t2 values(connection_id());
diff --git a/mysql-test/t/rpl000010-slave.opt b/mysql-test/t/rpl000010-slave.opt
index 429a7f63f7b..0dbfb311e33 100644
--- a/mysql-test/t/rpl000010-slave.opt
+++ b/mysql-test/t/rpl000010-slave.opt
@@ -1 +1 @@
---disconnect-slave-event-count=1
+--disconnect-slave-event-count=2
diff --git a/mysql-test/t/rpl000015.test b/mysql-test/t/rpl000015.test
index b7fff94f7f3..da73c5f4db2 100644
--- a/mysql-test/t/rpl000015.test
+++ b/mysql-test/t/rpl000015.test
@@ -1,4 +1,4 @@
-connect (master,localhost,root,,test,$MASTER_MYPORT,master.sock);
+connect (master,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
connect (slave,localhost,root,,test,$SLAVE_MYPORT,slave.sock);
connection master;
reset master;
@@ -7,24 +7,24 @@ save_master_pos;
connection slave;
reset slave;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
change master to master_host='127.0.0.1';
# The following needs to be cleaned up when change master is fixed
--replace_result $MASTER_MYPORT MASTER_PORT $MYSQL_TCP_PORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
--replace_result $MASTER_MYPORT MASTER_PORT
eval change master to master_host='127.0.0.1',master_user='root',
master_password='',master_port=$MASTER_MYPORT;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
start slave;
sync_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
connection master;
--disable_warnings
diff --git a/mysql-test/t/rpl000017.test b/mysql-test/t/rpl000017.test
index cf808a2cbc0..3b39a6b49a6 100644
--- a/mysql-test/t/rpl000017.test
+++ b/mysql-test/t/rpl000017.test
@@ -1,4 +1,4 @@
-connect (master,localhost,root,,test,$MASTER_MYPORT,master.sock);
+connect (master,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
connect (slave,localhost,root,,test,$SLAVE_MYPORT,slave.sock);
connection master;
reset master;
diff --git a/mysql-test/t/rpl000018.test b/mysql-test/t/rpl000018.test
index 884ec9727d2..fd2be2399a5 100644
--- a/mysql-test/t/rpl000018.test
+++ b/mysql-test/t/rpl000018.test
@@ -4,7 +4,7 @@
#
require_manager;
-connect (master,localhost,root,,test,0,master.sock);
+connect (master,localhost,root,,test,0,$MASTER_MYPORT);
connect (slave,localhost,root,,test,0,slave.sock);
connection master;
reset master;
diff --git a/mysql-test/t/rpl_EE_error.test b/mysql-test/t/rpl_EE_error.test
index 1a1572b48b0..90d8c36685f 100644
--- a/mysql-test/t/rpl_EE_error.test
+++ b/mysql-test/t/rpl_EE_error.test
@@ -9,7 +9,7 @@ source include/master-slave.inc;
create table t1 (a int) engine=myisam;
flush tables;
system rm ./var/master-data/test/t1.MYI ;
-drop table t1;
+drop table if exists t1;
save_master_pos;
connection slave;
sync_with_master;
diff --git a/mysql-test/t/rpl_auto_increment-master.opt b/mysql-test/t/rpl_auto_increment-master.opt
new file mode 100644
index 00000000000..a8a6af19da9
--- /dev/null
+++ b/mysql-test/t/rpl_auto_increment-master.opt
@@ -0,0 +1 @@
+--auto-increment-increment=10 --auto-increment-offset=2
diff --git a/mysql-test/t/rpl_auto_increment.test b/mysql-test/t/rpl_auto_increment.test
new file mode 100644
index 00000000000..71032404307
--- /dev/null
+++ b/mysql-test/t/rpl_auto_increment.test
@@ -0,0 +1,104 @@
+#
+# Test of auto_increment with offset
+#
+source include/have_innodb.inc;
+source include/master-slave.inc;
+
+create table t1 (a int not null auto_increment,b int, primary key (a)) engine=myisam auto_increment=3;
+insert into t1 values (NULL,1),(NULL,2),(NULL,3);
+select * from t1;
+
+sync_slave_with_master;
+select * from t1;
+connection master;
+drop table t1;
+
+create table t1 (a int not null auto_increment,b int, primary key (a)) engine=myisam;
+insert into t1 values (1,1),(NULL,2),(3,3),(NULL,4);
+delete from t1 where b=4;
+insert into t1 values (NULL,5),(NULL,6);
+select * from t1;
+
+sync_slave_with_master;
+select * from t1;
+connection master;
+
+drop table t1;
+
+set @@session.auto_increment_increment=100, @@session.auto_increment_offset=10;
+show variables like "%auto_inc%";
+
+create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
+# Insert with 2 insert statements to get better testing of logging
+insert into t1 values (NULL),(5),(NULL);
+insert into t1 values (250),(NULL);
+select * from t1;
+insert into t1 values (1000);
+set @@insert_id=400;
+insert into t1 values(NULL),(NULL);
+select * from t1;
+
+sync_slave_with_master;
+select * from t1;
+connection master;
+drop table t1;
+
+#
+# Same test with innodb (as the innodb code is a bit different)
+#
+create table t1 (a int not null auto_increment, primary key (a)) engine=innodb;
+# Insert with 2 insert statements to get better testing of logging
+insert into t1 values (NULL),(5),(NULL);
+insert into t1 values (250),(NULL);
+select * from t1;
+insert into t1 values (1000);
+set @@insert_id=400;
+insert into t1 values(NULL),(NULL);
+select * from t1;
+
+sync_slave_with_master;
+select * from t1;
+connection master;
+drop table t1;
+
+set @@session.auto_increment_increment=1, @@session.auto_increment_offset=1;
+create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
+# Insert with 2 insert statements to get better testing of logging
+insert into t1 values (NULL),(5),(NULL),(NULL);
+insert into t1 values (500),(NULL),(502),(NULL),(NULL);
+select * from t1;
+set @@insert_id=600;
+--error 1062
+insert into t1 values(600),(NULL),(NULL);
+set @@insert_id=600;
+insert ignore into t1 values(600),(NULL),(NULL),(610),(NULL);
+select * from t1;
+
+sync_slave_with_master;
+select * from t1;
+connection master;
+drop table t1;
+
+#
+# Test that auto-increment works when slave has rows in the table
+#
+set @@session.auto_increment_increment=10, @@session.auto_increment_offset=1;
+
+create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
+
+sync_slave_with_master;
+insert into t1 values(2),(12),(22),(32),(42);
+connection master;
+
+insert into t1 values (NULL),(NULL);
+insert into t1 values (3),(NULL),(NULL);
+select * from t1;
+
+sync_slave_with_master;
+select * from t1;
+connection master;
+
+drop table t1;
+
+# End cleanup
+sync_slave_with_master;
diff --git a/mysql-test/t/rpl_change_master.test b/mysql-test/t/rpl_change_master.test
index e6452b5b619..23866447c98 100644
--- a/mysql-test/t/rpl_change_master.test
+++ b/mysql-test/t/rpl_change_master.test
@@ -1,25 +1,30 @@
+# Verify that after CHANGE MASTER, replication (I/O thread and SQL
+# thread) restart from where SQL thread left, not from where
+# I/O thread left (some old bug fixed in 4.0.17)
+
source include/master-slave.inc;
-connection slave;
-select get_lock("a",5);
connection master;
+# Make SQL slave thread advance a bit
create table t1(n int);
-insert into t1 values(1+get_lock("a",15)*0);
+sync_slave_with_master;
+select * from t1;
+# Now stop it and make I/O slave thread be ahead
+stop slave sql_thread;
+connection master;
+insert into t1 values(1);
insert into t1 values(2);
save_master_pos;
connection slave;
---real_sleep 3; # can't sync_with_master as we should be blocked
+--real_sleep 3; # wait for I/O thread to have read updates
stop slave;
-select * from t1;
--replace_result $MASTER_MYPORT MASTER_MYPORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
change master to master_user='root';
--replace_result $MASTER_MYPORT MASTER_MYPORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
-# Will restart from after the values(2), which is bug
-select release_lock("a");
start slave;
sync_with_master;
select * from t1;
diff --git a/mysql-test/t/rpl_charset.test b/mysql-test/t/rpl_charset.test
index 3f7eabfa434..ee54bc72a65 100644
--- a/mysql-test/t/rpl_charset.test
+++ b/mysql-test/t/rpl_charset.test
@@ -1,11 +1,9 @@
# Replication of character sets.
# This test will fail if the server/client does not support enough charsets.
-# Remember that there currently exists
-# Bug #2326: Charset of table is determined by charset of db only if "USE db;"
-
source include/master-slave.inc;
--disable_warnings
+set timestamp=1000000000;
drop database if exists mysqltest2;
drop database if exists mysqltest3;
--enable_warnings
@@ -46,7 +44,7 @@ set character_set_client=cp850, collation_connection=latin2_croatian_ci;
insert into t1 (b) values(@@character_set_server);
insert into t1 (b) values(@@collation_server);
# character_set_database and collation_database are not tested as they
-# are not replicated (Bar said that this variable may be removed shortly).
+# needn't be replicated (Bar said in Jan 2005).
insert into t1 (b) values(@@character_set_client);
# collation_client does not exist
insert into t1 (b) values(@@character_set_connection);
@@ -79,9 +77,10 @@ select "--- --slave--" as "";
--enable_query_log
select * from mysqltest2.t1 order by a;
-# See if SET ONE_SHOT gets into binlog when LOAD DATA
-connection master;
-load data infile '../../std_data/words.dat' into table t1 (b);
+# Presently charset info is not logged with LOAD DATA but it will
+# change in Jan 2005 when Dmitri pushes his new LOAD DATA,
+# before 5.0.3 goes out. When done, LOAD DATA INFILE should be tested
+# here.
# See if user var is prefixed with collation in binlog and replicated well.
# Note: replication of user variables is broken as far as derivation is
@@ -90,6 +89,7 @@ load data infile '../../std_data/words.dat' into table t1 (b);
# know if the collation was explicit or not, so we use DERIVATION_NONE,
# which provokes error messages (like 'Illegal mix of collation') when
# we replay the master's INSERT/etc statements.
+connection master;
set @a= _cp850 'Müller' collate cp850_general_ci;
truncate table t1;
insert into t1 (b) values(collation(@a));
@@ -106,16 +106,17 @@ select * from mysqltest2.t1 order by a;
connection master;
drop database mysqltest2;
drop database mysqltest3;
-show binlog events from 79;
+--replace_column 2 # 5 #
+show binlog events from 98;
sync_slave_with_master;
-# Check that we can't change global.collation_server
+# Check that we can change global.collation_server (since 5.0.3)
-error 1105;
set global character_set_server=latin2;
+set global character_set_server=latin1; # back
connection master;
-error 1105;
set global character_set_server=latin2;
+set global character_set_server=latin1; # back
# Check that SET ONE_SHOT is really one shot
@@ -128,7 +129,7 @@ select @@character_set_server;
select @@character_set_server;
# ONE_SHOT on not charset/collation stuff is not allowed
-error 1105;
+-- error 1382
set one_shot max_join_size=10;
# Test of wrong character set numbers;
@@ -149,24 +150,10 @@ select hex(c1), hex(c2) from t1;
sync_slave_with_master;
select hex(c1), hex(c2) from t1;
-# Now test for BUG##5705: SET CHARATER_SET_SERVERetc will be lost if
-# STOP SLAVE before following query
-
-stop slave;
-delete from t1;
-change master to master_log_pos=5847;
-start slave until master_log_file='master-bin.000001', master_log_pos=5983;
-# Slave is supposed to stop _after_ the INSERT, even though 5983 is
-# the position of the beginning of the INSERT; after SET slave is not
-# supposed to increment position.
-wait_for_slave_to_stop;
-# When you merge this into 5.0 you will have to adjust positions
-# above; the first master_log_pos above should be the one of the SET,
-# the second should be the one of the INSERT.
-start slave;
-sync_with_master;
-select hex(c1), hex(c2) from t1;
connection master;
+# Let's have a look at generated SETs.
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001
drop table t1;
sync_slave_with_master;
diff --git a/mysql-test/t/rpl_create_database.test b/mysql-test/t/rpl_create_database.test
index 7ed0d5dbdbb..c63b0bc85ef 100644
--- a/mysql-test/t/rpl_create_database.test
+++ b/mysql-test/t/rpl_create_database.test
@@ -56,6 +56,7 @@ USE mysqltest_sisyfos;
CREATE TABLE t2 (a INT);
let $VERSION=`select version()`;
--replace_result $VERSION VERSION
+--replace_column 2 # 5 #
SHOW BINLOG EVENTS;
SHOW DATABASES;
sync_slave_with_master;
diff --git a/mysql-test/t/rpl_deadlock.test b/mysql-test/t/rpl_deadlock.test
index 9ad6362f7e7..3bcbb1d4567 100644
--- a/mysql-test/t/rpl_deadlock.test
+++ b/mysql-test/t/rpl_deadlock.test
@@ -72,7 +72,7 @@ show slave status;
# 2) Test lock wait timeout
stop slave;
-change master to master_log_pos=401; # the BEGIN log event
+change master to master_log_pos=532; # the BEGIN log event
begin;
select * from t2 for update; # hold lock
start slave;
@@ -93,7 +93,7 @@ set global max_relay_log_size=0;
# This is really copy-paste of 2) of above
stop slave;
-change master to master_log_pos=401;
+change master to master_log_pos=532;
begin;
select * from t2 for update;
start slave;
diff --git a/mysql-test/t/rpl_drop_temp.test b/mysql-test/t/rpl_drop_temp.test
index 73d691d9d90..cf663367b78 100644
--- a/mysql-test/t/rpl_drop_temp.test
+++ b/mysql-test/t/rpl_drop_temp.test
@@ -11,3 +11,6 @@ disconnect master;
connection slave;
--real_sleep 3; # time for DROP to be written
show status like 'Slave_open_temp_tables';
+connection default;
+drop database mysqltest;
+
diff --git a/mysql-test/t/rpl_empty_master_crash.test b/mysql-test/t/rpl_empty_master_crash.test
index bee9ef72dc4..98a630c69ca 100644
--- a/mysql-test/t/rpl_empty_master_crash.test
+++ b/mysql-test/t/rpl_empty_master_crash.test
@@ -1,6 +1,6 @@
source include/master-slave.inc;
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
#
diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test
index 0062a67ff1a..5388b6af8d4 100644
--- a/mysql-test/t/rpl_error_ignored_table.test
+++ b/mysql-test/t/rpl_error_ignored_table.test
@@ -15,7 +15,7 @@ sync_with_master;
# The port number is different when doing the release build with
# Do-compile, hence we have to replace the port number here accordingly
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# check that the table has been ignored, because otherwise the test is nonsense
show tables like 't1';
@@ -48,7 +48,8 @@ connection master;
--error 0,1053;
reap;
connection master1;
-show binlog events from 79;
+--replace_column 2 # 5 #
+show binlog events from 98;
save_master_pos;
connection slave;
# SQL slave thread should not have stopped (because table of the killed
diff --git a/mysql-test/t/rpl_flush_log_loop.test b/mysql-test/t/rpl_flush_log_loop.test
index 74920722868..ccaae8ad765 100644
--- a/mysql-test/t/rpl_flush_log_loop.test
+++ b/mysql-test/t/rpl_flush_log_loop.test
@@ -18,5 +18,5 @@ sleep 5;
flush logs;
sleep 5;
--replace_result $SLAVE_MYPORT SLAVE_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
diff --git a/mysql-test/t/rpl_flush_tables.test b/mysql-test/t/rpl_flush_tables.test
index b98235fbed8..eb16ddcd8de 100644
--- a/mysql-test/t/rpl_flush_tables.test
+++ b/mysql-test/t/rpl_flush_tables.test
@@ -18,6 +18,7 @@ rename table t1 to t5, t2 to t1;
flush no_write_to_binlog tables;
# Check that it's not in the binlog.
--replace_result $SERVER_VERSION SERVER_VERSION
+--replace_column 2 # 5 #
show binlog events;
# Check that the master is not confused.
select * from t3;
@@ -25,6 +26,7 @@ select * from t3;
flush tables;
# Check that it's in the binlog.
--replace_result $SERVER_VERSION SERVER_VERSION
+--replace_column 2 # 5 #
show binlog events;
save_master_pos;
connection slave;
diff --git a/mysql-test/t/rpl_get_lock.test b/mysql-test/t/rpl_get_lock.test
index 5e58753e59a..847e7145be6 100644
--- a/mysql-test/t/rpl_get_lock.test
+++ b/mysql-test/t/rpl_get_lock.test
@@ -22,6 +22,13 @@ connection slave;
sync_with_master;
select get_lock("lock",3);
select * from t1;
+# There is no point in testing REPLICATIION of the IS_*_LOCK
+# functions; slave does not run with the same concurrency context as
+# master (generally in slave we can't know that on master this lock
+# was already held by another connection and so that the the
+# get_lock() we're replicating timed out on master hence returned 0,
+# or that the is_free_lock() we're playing returned 0 etc.
+# But here all we do is test these functions outside of replication.
select is_free_lock("lock"), is_used_lock("lock") = connection_id();
explain extended select is_free_lock("lock"), is_used_lock("lock");
# Check lock functions
diff --git a/mysql-test/t/rpl_heap.test b/mysql-test/t/rpl_heap.test
index 0bc71eaf30c..3452f3990bf 100644
--- a/mysql-test/t/rpl_heap.test
+++ b/mysql-test/t/rpl_heap.test
@@ -7,7 +7,7 @@ require_manager;
# issue a query after the server restart.
# Maybe this is something awkward in mysqltest or in the manager?
# So we use sockets.
-connect (master,localhost,root,,test,0,master.sock);
+connect (master,localhost,root,,test,0,$MASTER_MYPORT);
connect (slave,localhost,root,,test,0,slave.sock);
connection master;
diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test
index 10213644836..3d54897adda 100644
--- a/mysql-test/t/rpl_loaddata.test
+++ b/mysql-test/t/rpl_loaddata.test
@@ -36,8 +36,7 @@ select * from t3;
# But we can't simply read this binlog, because as the slave has not been
# restarted for this test, the file_id is uncertain (would cause test
# failures). So instead, we test if the binlog looks long enough to
-# contain LOAD DATA. That is, I (Guilhem) have done SHOW BINLOG EVENTS on my
-# machine, saw that the binlog is of size 964 when things go fine.
+# contain LOAD DATA. Since 5.0.3 we assume that binlog of 1292 is ok.
# If LOAD DATA was not logged, the binlog would be shorter.
show master status;
@@ -72,7 +71,7 @@ set global sql_slave_skip_counter=1;
start slave;
sync_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# Trigger error again to test CHANGE MASTER
@@ -84,7 +83,9 @@ set sql_log_bin=1;
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
save_master_pos;
connection slave;
-# The SQL slave thread should be stopped now.
+# The SQL slave thread should be stopped now.
+# Exec_Master_Log_Pos should point to the start of Execute event
+# for last load data.
wait_for_slave_to_stop;
# CHANGE MASTER and see if error is cleared in SHOW SLAVE STATUS.
@@ -92,7 +93,7 @@ stop slave;
change master to master_user='test';
change master to master_user='root';
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# Trigger error again to test RESET SLAVE
@@ -114,7 +115,7 @@ wait_for_slave_to_stop;
stop slave;
reset slave;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# Finally, see if logging is done ok on master for a failing LOAD DATA INFILE
@@ -122,12 +123,29 @@ show slave status;
connection master;
reset master;
create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60),
-unique(day));
+unique(day)) engine=MyISAM; # no transactions
--error 1062;
load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
'\n##\n' starting by '>' ignore 1 lines;
-# To test that there is Create_file & Delete_file, we test if the binlog is as
-# long as expected (can't do SHOW BINLOG EVENTS because of varying file_id).
-show master status;
+select * from t2;
+save_master_pos;
+connection slave;
+start slave;
+sync_with_master;
+select * from t2;
+
+# verify that if no error on slave, this is an error
+
+alter table t2 drop key day;
+connection master;
+delete from t2;
+--error 1062;
+load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields
+terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by
+'\n##\n' starting by '>' ignore 1 lines;
+connection slave;
+wait_for_slave_to_stop;
+drop table t2;
+connection master;
drop table t2;
diff --git a/mysql-test/t/rpl_loaddata_rule_m.test b/mysql-test/t/rpl_loaddata_rule_m.test
index 678dae13889..97c984c4369 100644
--- a/mysql-test/t/rpl_loaddata_rule_m.test
+++ b/mysql-test/t/rpl_loaddata_rule_m.test
@@ -19,5 +19,9 @@ create database mysqltest;
create table t1(a int, b int, unique(b));
use mysqltest;
load data infile '../../std_data/rpl_loaddata.dat' into table test.t1;
-show binlog events from 79; # should be nothing
+# Starting from 5.0.3 LOAD DATA is replicated much in the same way as ordinary
+# query so "show binlog ..." should show two events (before 5.0.3 no events
+# were returned).
+--replace_column 2 # 5 #
+show binlog events from 98;
drop database mysqltest;
diff --git a/mysql-test/t/rpl_loaddata_rule_s.test b/mysql-test/t/rpl_loaddata_rule_s.test
index 1ea4f6825f5..9802c00d35f 100644
--- a/mysql-test/t/rpl_loaddata_rule_s.test
+++ b/mysql-test/t/rpl_loaddata_rule_s.test
@@ -17,4 +17,4 @@ save_master_pos;
connection slave;
sync_with_master;
select count(*) from t1; # check that LOAD was replicated
-show binlog events from 79; # should be nothing
+show binlog events from 98; # should be nothing
diff --git a/mysql-test/t/rpl_loaddatalocal.test b/mysql-test/t/rpl_loaddatalocal.test
index 70f4ab96b6a..f9325b39af6 100644
--- a/mysql-test/t/rpl_loaddatalocal.test
+++ b/mysql-test/t/rpl_loaddatalocal.test
@@ -34,3 +34,27 @@ drop table t1;
save_master_pos;
connection slave;
sync_with_master;
+
+#
+# Now let us test how well we replicate LOAD DATA LOCAL in situation when
+# we met duplicates in tables to which we are adding rows.
+# (It supposed that LOAD DATA LOCAL ignores such errors)
+#
+connection master;
+create table t1(a int);
+insert into t1 values (1), (2), (2), (3);
+select * into outfile '../../var/master-data/rpl_loaddatalocal.select_outfile' from t1;
+drop table t1;
+create table t1(a int primary key);
+load data local infile './var/master-data/rpl_loaddatalocal.select_outfile' into table t1;
+system rm ./var/master-data/rpl_loaddatalocal.select_outfile ;
+select * from t1;
+save_master_pos;
+connection slave;
+sync_with_master;
+select * from t1;
+connection master;
+drop table t1;
+save_master_pos;
+connection slave;
+sync_with_master;
diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test
index 8fdccdd068d..8cb99d5432e 100644
--- a/mysql-test/t/rpl_log.test
+++ b/mysql-test/t/rpl_log.test
@@ -38,9 +38,9 @@ select count(*) from t1;
drop table t1;
--replace_result $VERSION VERSION
show binlog events;
-show binlog events from 79 limit 1;
-show binlog events from 79 limit 2;
-show binlog events from 79 limit 2,1;
+show binlog events from 98 limit 1;
+show binlog events from 98 limit 2;
+show binlog events from 98 limit 2,1;
flush logs;
# We need an extra update before doing save_master_pos.
@@ -82,6 +82,7 @@ insert into t1 values (1);
drop table t1;
--replace_result $VERSION VERSION
show binlog events;
+--replace_result $VERSION VERSION
show binlog events in 'master-bin.000002';
show binary logs;
save_master_pos;
@@ -94,7 +95,7 @@ show binlog events in 'slave-bin.000001' from 4;
--replace_result $MASTER_MYPORT MASTER_PORT $VERSION VERSION
show binlog events in 'slave-bin.000002' from 4;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# Need to recode the following
diff --git a/mysql-test/t/rpl_log_pos.test b/mysql-test/t/rpl_log_pos.test
index a40736577c8..2a03497846b 100644
--- a/mysql-test/t/rpl_log_pos.test
+++ b/mysql-test/t/rpl_log_pos.test
@@ -5,7 +5,7 @@ source include/master-slave.inc;
show master status;
sync_slave_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
stop slave;
change master to master_log_pos=73;
@@ -15,19 +15,19 @@ stop slave;
change master to master_log_pos=73;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
start slave;
sleep 5;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
stop slave;
change master to master_log_pos=173;
start slave;
sleep 2;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
connection master;
show master status;
@@ -38,7 +38,7 @@ insert into t1 values (1),(2),(3);
save_master_pos;
connection slave;
stop slave;
-change master to master_log_pos=79;
+change master to master_log_pos=98;
start slave;
sync_with_master;
select * from t1;
diff --git a/mysql-test/t/rpl_max_relay_size.test b/mysql-test/t/rpl_max_relay_size.test
index cbcc115a942..963a76fb959 100644
--- a/mysql-test/t/rpl_max_relay_size.test
+++ b/mysql-test/t/rpl_max_relay_size.test
@@ -29,7 +29,7 @@ select @@global.max_relay_log_size;
start slave;
sync_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
stop slave;
reset slave;
@@ -38,7 +38,7 @@ select @@global.max_relay_log_size;
start slave;
sync_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
stop slave;
reset slave;
@@ -47,7 +47,7 @@ select @@global.max_relay_log_size;
start slave;
sync_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# Tests below are mainly to ensure that we have not coded with wrong assumptions
@@ -58,7 +58,7 @@ reset slave;
# (to make sure it does not crash).
flush logs;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
reset slave;
@@ -74,7 +74,7 @@ save_master_pos;
connection slave;
sync_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# one more rotation, to be sure Relay_Log_Space is correctly updated
flush logs;
@@ -84,7 +84,7 @@ save_master_pos;
connection slave;
sync_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
connection master;
diff --git a/mysql-test/t/rpl_multi_query.test b/mysql-test/t/rpl_multi_query.test
index 482a2679e7a..2ddd61ce7ba 100644
--- a/mysql-test/t/rpl_multi_query.test
+++ b/mysql-test/t/rpl_multi_query.test
@@ -24,6 +24,6 @@ sync_slave_with_master;
select * from mysqltest.t1;
connection master;
--replace_column 2 # 5 #
-show binlog events from 79;
+show binlog events from 98;
drop database mysqltest;
sync_slave_with_master;
diff --git a/mysql-test/t/rpl_openssl.test b/mysql-test/t/rpl_openssl.test
index 8a36904f4d4..779ec4e84bf 100644
--- a/mysql-test/t/rpl_openssl.test
+++ b/mysql-test/t/rpl_openssl.test
@@ -45,7 +45,7 @@ select * from t1;
#checking show slave status
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_MYPORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
#checking if replication works without ssl also performing clean up
@@ -58,5 +58,5 @@ save_master_pos;
connection slave;
sync_with_master;
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_MYPORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
diff --git a/mysql-test/t/rpl_redirect.test b/mysql-test/t/rpl_redirect.test
index c533c0052f0..d505351cc69 100644
--- a/mysql-test/t/rpl_redirect.test
+++ b/mysql-test/t/rpl_redirect.test
@@ -14,7 +14,7 @@ sync_with_master;
#discover slaves
connection master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
SHOW SLAVE STATUS;
--replace_result $SLAVE_MYPORT SLAVE_PORT
SHOW SLAVE HOSTS;
diff --git a/mysql-test/t/rpl_relayrotate-slave.opt b/mysql-test/t/rpl_relayrotate-slave.opt
index 8b671423363..3a4abbf091e 100644
--- a/mysql-test/t/rpl_relayrotate-slave.opt
+++ b/mysql-test/t/rpl_relayrotate-slave.opt
@@ -1,4 +1,3 @@
--O max_binlog_size=16384
+-O max_relay_log_size=16384
--innodb
--log-warnings
-
diff --git a/mysql-test/t/rpl_relayrotate.test b/mysql-test/t/rpl_relayrotate.test
index 1bc6b574663..2fde590356a 100644
--- a/mysql-test/t/rpl_relayrotate.test
+++ b/mysql-test/t/rpl_relayrotate.test
@@ -55,8 +55,10 @@ start slave;
# reading, MASTER_POS_WAIT() will do it for sure
# (the only statement with position>=3000 is COMMIT).
select master_pos_wait('master-bin.001',3000)>=0;
-select * from t1 where a=8000;
-
+select max(a) from t1;
+--replace_column 1 # 8 # 9 # 23 # 33 #
+--replace_result $MASTER_MYPORT MASTER_MYPORT
+show slave status;
connection master;
# The following DROP is a very important cleaning task:
diff --git a/mysql-test/t/rpl_replicate_do.test b/mysql-test/t/rpl_replicate_do.test
index 7066f6e53d8..108dd54ce0a 100644
--- a/mysql-test/t/rpl_replicate_do.test
+++ b/mysql-test/t/rpl_replicate_do.test
@@ -33,6 +33,6 @@ connection slave;
sync_with_master;
# show slave status, just to see of it prints replicate-do-table
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
diff --git a/mysql-test/t/rpl_reset_slave.test b/mysql-test/t/rpl_reset_slave.test
index d58e9c711d1..1b27e059f92 100644
--- a/mysql-test/t/rpl_reset_slave.test
+++ b/mysql-test/t/rpl_reset_slave.test
@@ -11,24 +11,24 @@ save_master_pos;
connection slave;
sync_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
stop slave;
change master to master_user='test';
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
reset slave;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
start slave;
sync_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# test of crash with temp tables & RESET SLAVE
diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test
index da4d5f0bce1..2355e92e58b 100644
--- a/mysql-test/t/rpl_rotate_logs.test
+++ b/mysql-test/t/rpl_rotate_logs.test
@@ -9,7 +9,7 @@
# changes
# - Test creating a duplicate key error and recover from it
-connect (master,localhost,root,,test,$MASTER_MYPORT,master.sock);
+connect (master,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
--disable_warnings
drop table if exists t1, t2, t3, t4;
--enable_warnings
@@ -23,7 +23,8 @@ drop table if exists t1, t2, t3, t4;
# START SLAVE will fail because it can't read the file (mode 000)
# (system error 13)
---error 1201
+--replace_result $MYSQL_TEST_DIR TESTDIR
+--error 1105,1105,29
start slave;
system chmod 600 var/slave-data/master.info;
# It will fail again because the file is empty so the slave cannot get valuable
@@ -55,7 +56,7 @@ create table t1 (s text);
insert into t1 values('Could not break slave'),('Tried hard');
sync_slave_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
select * from t1;
connection master;
@@ -108,7 +109,7 @@ show binary logs;
insert into t2 values (65);
sync_slave_with_master;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
select * from t2;
@@ -140,7 +141,7 @@ sync_with_master;
select * from t4;
--replace_result $MASTER_MYPORT MASTER_PORT
---replace_column 1 # 33 #
+--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# because of concurrent insert, the table may not be up to date
# if we do not lock
@@ -151,3 +152,4 @@ unlock tables;
connection master;
drop table if exists t1,t2,t3,t4;
sync_slave_with_master;
+
diff --git a/mysql-test/t/rpl_session_var.test b/mysql-test/t/rpl_session_var.test
new file mode 100644
index 00000000000..a6f4b496a23
--- /dev/null
+++ b/mysql-test/t/rpl_session_var.test
@@ -0,0 +1,42 @@
+# Replication of session variables.
+# FOREIGN_KEY_CHECKS is tested in rpl_insert_id.test
+
+source include/master-slave.inc;
+drop table if exists t1;
+create table t1(a varchar(100),b int);
+set @@session.sql_mode=pipes_as_concat;
+insert into t1 values('My'||'SQL', 1);
+set @@session.sql_mode=default;
+insert into t1 values('1'||'2', 2);
+select * from t1 where b<3 order by a;
+save_master_pos;
+connection slave;
+sync_with_master;
+select * from t1 where b<3 order by a;
+connection master;
+# if the slave does the next sync_with_master fine, then it means it accepts the
+# two lines of ANSI syntax below, which is what we want to check.
+set @@session.sql_mode=ignore_space;
+insert into t1 values(password ('MySQL'), 3);
+set @@session.sql_mode=ansi_quotes;
+create table "t2" ("a" int);
+drop table t1, t2;
+set @@session.sql_mode=default;
+create table t1(a int auto_increment primary key);
+create table t2(b int, a int);
+set @@session.sql_auto_is_null=1;
+insert into t1 values(null);
+insert into t2 select 1,a from t1 where a is null;
+set @@session.sql_auto_is_null=0;
+insert into t1 values(null);
+insert into t2 select 2,a from t1 where a is null;
+select * from t2 order by b;
+save_master_pos;
+connection slave;
+sync_with_master;
+select * from t2 order by b;
+connection master;
+drop table t1,t2;
+save_master_pos;
+connection slave;
+sync_with_master;
diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test
index f84c9b09aef..e65469de7e0 100644
--- a/mysql-test/t/rpl_temporary.test
+++ b/mysql-test/t/rpl_temporary.test
@@ -82,6 +82,7 @@ drop temporary table t3;
select * from t2;
--replace_result $VERSION VERSION
+--replace_column 2 # 5 #
show binlog events;
drop table t1, t2;
diff --git a/mysql-test/t/rpl_timezone-slave.opt b/mysql-test/t/rpl_timezone-slave.opt
index 8e43bfbbb7e..191182c329c 100644
--- a/mysql-test/t/rpl_timezone-slave.opt
+++ b/mysql-test/t/rpl_timezone-slave.opt
@@ -1 +1 @@
---default-time-zone=Europe/Moscow
+--default-time-zone=Japan
diff --git a/mysql-test/t/rpl_timezone.test b/mysql-test/t/rpl_timezone.test
index 8dff90a84cf..a7547f7afc6 100644
--- a/mysql-test/t/rpl_timezone.test
+++ b/mysql-test/t/rpl_timezone.test
@@ -1,23 +1,38 @@
# Test of replication of time zones.
+
+# There is currently some bug possibly in prepared statements (this
+# test fails with --ps-protocol): sys_var_thd_time_zone::value_ptr()
+# is called only at prepare time, not at execution time. So,
+# thd->time_zone_used is not equal to 1 (it is back to 0, because of
+# reset_thd_for_next_command called at execution time), so the
+# timezone used in CONVERT_TZ is not binlogged. To debug (by Guilhem
+# and possibly Konstantin).
+
+--disable_ps_protocol
+
source include/master-slave.inc;
# Some preparations
let $VERSION=`select version()`;
+set timestamp=100000000; # for fixed output of mysqlbinlog
create table t1 (t timestamp);
create table t2 (t char(32));
+connection slave;
+select @@time_zone;
+
#
# Let us check how well replication works when we are saving datetime
# value in TIMESTAMP field.
#
connection master;
select @@time_zone;
+insert into t1 values ('20050101000000'), ('20050611093902');
set time_zone='UTC';
insert into t1 values ('20040101000000'), ('20040611093902');
select * from t1;
-# On slave we still in 'Europe/Moscow' so we should see equivalent but
-# textually different values.
sync_slave_with_master;
+set time_zone='UTC';
select * from t1;
# Let us check also that setting of time_zone back to default also works
@@ -28,11 +43,29 @@ set time_zone='Europe/Moscow';
insert into t1 values ('20040101000000'), ('20040611093902');
select * from t1;
sync_slave_with_master;
+set time_zone='Europe/Moscow';
select * from t1;
connection master;
-# We should not see SET ONE_SHOT time_zone before second insert
---replace_result $VERSION VERSION
-show binlog events;
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001
+
+# Let us check with LOAD DATA INFILE
+# (we do it after mysqlbinlog because the temp files names are not constant)
+connection master;
+delete from t1;
+set time_zone='UTC';
+load data infile '../../std_data/rpl_timezone.dat' into table t1;
+select * from t1;
+sync_slave_with_master;
+set time_zone='UTC';
+select * from t1;
+set time_zone='Europe/Moscow';
+
+# Put back values of before the LOAD
+connection master;
+set time_zone='Europe/Moscow';
+delete from t1;
+insert into t1 values ('20040101000000'), ('20040611093902');
#
# Now let us check how well we replicate statments reading TIMESTAMP fields
@@ -53,10 +86,6 @@ delete from t2;
set timestamp=1000072000;
insert into t2 values (current_timestamp), (current_date), (current_time);
sync_slave_with_master;
-# Values in ouput of these to queries should differ because we are in
-# in 'MET' on master and in 'Europe/Moscow on slave...
-set timestamp=1000072000;
-select current_timestamp, current_date, current_time;
select * from t2;
#
@@ -72,13 +101,24 @@ sync_slave_with_master;
select * from t2;
#
-# Let us check that we are not allowing to set global time_zone with
+# Let us check that we are allowing to set global time_zone with
# replication
#
connection master;
---error 1105
set global time_zone='MET';
+#
+# Let us see if CONVERT_TZ(@@time_zone) replicates
+#
+delete from t2;
+set time_zone='UTC';
+insert into t2 values(convert_tz('2004-01-01 00:00:00','MET',@@time_zone));
+insert into t2 values(convert_tz('2005-01-01 00:00:00','MET','Japan'));
+select * from t2;
+sync_slave_with_master;
+select * from t2;
+
# Clean up
+connection master;
drop table t1, t2;
sync_slave_with_master;
diff --git a/mysql-test/t/rpl_trunc_binlog.test b/mysql-test/t/rpl_trunc_binlog.test
index 2ade41ee96d..eec36532275 100644
--- a/mysql-test/t/rpl_trunc_binlog.test
+++ b/mysql-test/t/rpl_trunc_binlog.test
@@ -1,25 +1,35 @@
# We are testing if a binlog which contains BEGIN but not COMMIT (the
-# master did while writing the transaction to the binlog) triggers an
-# error on slave. So we use such a truncated binlog and simulate that
+# 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.
+# 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 # 23 # 33 #
+--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 45b343ace14..714719f5441 100644
--- a/mysql-test/t/rpl_until.test
+++ b/mysql-test/t/rpl_until.test
@@ -24,7 +24,7 @@ show binlog events;
# try to replicate all queries until drop of t1
connection slave;
-start slave until master_log_file='master-bin.000001', master_log_pos=244;
+start slave until master_log_file='master-bin.000001', master_log_pos=319;
sleep 2;
# here table should be still not deleted
select * from t1;
@@ -42,7 +42,7 @@ sleep 2;
show slave status;
# try replicate all until second insert to t2;
-start slave until relay_log_file='slave-relay-bin.000002', relay_log_pos=537;
+start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746;
sleep 4;
select * from t2;
--replace_result $MASTER_MYPORT MASTER_MYPORT
@@ -57,8 +57,8 @@ connection slave;
sync_with_master;
stop slave;
-# this should stop immideately
-start slave until master_log_file='master-bin.000001', master_log_pos=561;
+# 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
# here the sql slave thread should be stopped
@@ -77,6 +77,6 @@ start slave until master_log_file='master-bin.000001';
start slave until relay_log_file='slave-relay-bin.000002';
--error 1277
start slave until relay_log_file='slave-relay-bin.000002', master_log_pos=561;
-
+# Warning should be given for second command
start slave sql_thread;
-start slave until master_log_file='master-bin.000001', master_log_pos=561;
+start slave until master_log_file='master-bin.000001', master_log_pos=776;
diff --git a/mysql-test/t/rpl_user_variables.test b/mysql-test/t/rpl_user_variables.test
index 73b3ace473e..711d83219a6 100644
--- a/mysql-test/t/rpl_user_variables.test
+++ b/mysql-test/t/rpl_user_variables.test
@@ -46,7 +46,8 @@ save_master_pos;
connection slave;
sync_with_master;
select * from t1;
-show binlog events from 141;
+--replace_column 2 # 5 #
+show binlog events from 98;
connection master;
drop table t1;
save_master_pos;
diff --git a/mysql-test/t/rpl_view.test b/mysql-test/t/rpl_view.test
new file mode 100644
index 00000000000..c50e9fc6dc9
--- /dev/null
+++ b/mysql-test/t/rpl_view.test
@@ -0,0 +1,44 @@
+source include/master-slave.inc;
+--disable_warnings
+drop table if exists t1,v1;
+drop view if exists t1,v1;
+sync_slave_with_master;
+--enable_warnings
+
+#
+# Check that createion drop of view is replicated, also check replication of
+# updating of view
+#
+connection master;
+create table t1 (a int);
+insert into t1 values (1);
+create view v1 as select a from t1;
+insert into v1 values (2);
+select * from v1 order by a;
+sync_slave_with_master;
+# view already have to be on slave
+select * from v1 order by a;
+connection master;
+update v1 set a=3 where a=1;
+select * from v1 order by a;
+sync_slave_with_master;
+select * from v1 order by a;
+connection master;
+delete from v1 where a=2;
+select * from v1 order by a;
+sync_slave_with_master;
+select * from v1 order by a;
+connection master;
+# 'alter view' internally maped to creation, but still check that it works
+alter view v1 as select a as b from t1;
+sync_slave_with_master;
+select * from v1 order by 1;
+connection master;
+drop view v1;
+sync_slave_with_master;
+#error, because view have to be removed from slave
+-- error 1146
+select * from v1 order by a;
+connection master;
+drop table t1;
+sync_slave_with_master;
diff --git a/mysql-test/t/schema.test b/mysql-test/t/schema.test
new file mode 100644
index 00000000000..d9bd607b2db
--- /dev/null
+++ b/mysql-test/t/schema.test
@@ -0,0 +1,8 @@
+#
+# Just a couple of tests to make sure that schema works.
+#
+
+create schema foo;
+show create schema foo;
+show schemas;
+drop schema foo;
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index f58a78205ec..a92c8ffdc66 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -9,7 +9,8 @@
--disable_warnings
drop table if exists t1,t2,t3,t4;
# The following may be left from older tests
-drop table if exists t1_1,t1_2,t9_1,t9_2;
+drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa;
+drop view if exists v1;
--enable_warnings
CREATE TABLE t1 (
@@ -1764,9 +1765,9 @@ DO benchmark(100,1+1),1,1;
# Bug #6449: do default;
#
---error 1064
+--error ER_PARSE_ERROR
do default;
---error 1054
+--error ER_BAD_FIELD_ERROR
do foobar;
#
@@ -1792,7 +1793,10 @@ CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned defa
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);
+# Disable PS becasue we get more warnings from PS than from normal execution
+--disable_ps_protocol
SELECT a.gvid, (SUM(CASE b.sampletid WHEN 140 THEN b.samplevalue ELSE 0 END)) as the_success,(SUM(CASE b.sampletid WHEN 141 THEN b.samplevalue ELSE 0 END)) as the_fail,(SUM(CASE b.sampletid WHEN 142 THEN b.samplevalue ELSE 0 END)) as the_size,(SUM(CASE b.sampletid WHEN 143 THEN b.samplevalue ELSE 0 END)) as the_time FROM t1 a, t2 b WHERE a.hmid = b.hmid AND a.volid = b.volid AND b.sampletime >= 'wrong-date-value' AND b.sampletime < 'wrong-date-value' AND b.sampletid IN (140, 141, 142, 143) GROUP BY a.gvid;
+--enable_ps_protocol
# Testing the same select with NULL's instead of invalid datetime values
SELECT a.gvid, (SUM(CASE b.sampletid WHEN 140 THEN b.samplevalue ELSE 0 END)) as the_success,(SUM(CASE b.sampletid WHEN 141 THEN b.samplevalue ELSE 0 END)) as the_fail,(SUM(CASE b.sampletid WHEN 142 THEN b.samplevalue ELSE 0 END)) as the_size,(SUM(CASE b.sampletid WHEN 143 THEN b.samplevalue ELSE 0 END)) as the_time FROM t1 a, t2 b WHERE a.hmid = b.hmid AND a.volid = b.volid AND b.sampletime >= NULL AND b.sampletime < NULL AND b.sampletid IN (140, 141, 142, 143) GROUP BY a.gvid;
DROP TABLE t1,t2;
@@ -1936,6 +1940,42 @@ EXPLAIN SELECT i FROM t1 WHERE i=1;
DROP TABLE t1;
#
+# Test for bug #6474
+#
+
+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',
+F2I4 int(11) NOT NULL default '0'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+INSERT INTO t1 VALUES
+('W%RT', '0100', 1),
+('W-RT', '0100', 1),
+('WART', '0100', 1),
+('WART', '0200', 1),
+('WERT', '0100', 2),
+('WORT','0200', 2),
+('WT', '0100', 2),
+('W_RT', '0100', 2),
+('WaRT', '0100', 3),
+('WART', '0300', 3),
+('WRT' , '0400', 3),
+('WURM', '0500', 3),
+('W%T', '0600', 4),
+('WA%T', '0700', 4),
+('WA_T', '0800', 4);
+
+SELECT K2C4, K4N4, F2I4 FROM t1
+ WHERE K2C4 = 'WART' AND
+ (F2I4 = 2 AND K2C4 = 'WART' OR (F2I4 = 2 OR K4N4 = '0200'));
+
+SELECT K2C4, K4N4, F2I4 FROM t1
+ WHERE K2C4 = 'WART' AND (K2C4 = 'WART' OR K4N4 = '0200');
+
+DROP TABLE t1;
+
+#
# Test case for bug 7520: a wrong cost of the index for a BLOB field
#
@@ -1979,3 +2019,13 @@ 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#8670
+#
+create table t1 (a int, b int);
+create table t2 like t1;
+select t1.a from (t1 inner join t2 on t1.a=t2.a) where t2.a=1;
+select t1.a from ((t1 inner join t2 on t1.a=t2.a)) where t2.a=1;
+select x.a, y.a, z.a from ( (t1 x inner join t2 y on x.a=y.a) inner join t2 z on y.a=z.a) WHERE x.a=1;
+drop table t1,t2;
diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test
index f80e720275a..f74ffc4f4f5 100644
--- a/mysql-test/t/show_check.test
+++ b/mysql-test/t/show_check.test
@@ -8,6 +8,7 @@
--disable_warnings
drop table if exists t1,t2;
+drop table if exists t1aa,t2aa;
drop database if exists mysqltest;
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
@@ -105,7 +106,7 @@ drop table t1;
# Do a create table that tries to cover all types and options
#
create table t1 (
-type_bool bool not null,
+type_bool bool not null default 0,
type_tiny tinyint not null auto_increment primary key,
type_short smallint(3),
type_mediumint mediumint,
@@ -116,9 +117,9 @@ empty_char char(0),
type_char char(2),
type_varchar varchar(10),
type_timestamp timestamp not null,
-type_date date not null,
-type_time time not null,
-type_datetime datetime not null,
+type_date date not null default '0000-00-00',
+type_time time not null default '00:00:00',
+type_datetime datetime not null default '0000-00-00 00:00:00',
type_year year,
type_enum enum ('red', 'green', 'blue'),
type_set enum ('red', 'green', 'blue'),
@@ -176,16 +177,24 @@ CREATE TABLE `a/b` (i INT);
#CREATE TABLE ```ab````cd``` (i INT);
#SHOW CREATE TABLE ```ab````cd```;
#DROP TABLE ```ab````cd```;
-
+#
#CREATE TABLE ```a` (i INT);
#SHOW CREATE TABLE ```a`;
#DROP TABLE ```a`;
-
-SET sql_mode= 'ANSI_QUOTES';
-
+#
+#SET sql_mode= 'ANSI_QUOTES';
+#
#CREATE TABLE """a" (i INT);
#SHOW CREATE TABLE """a";
#DROP TABLE """a";
+#
+#Bug #4374 SHOW TABLE STATUS FROM ignores collation_connection
+#set names latin1;
+#create database `ä`;
+#create table `ä`.`ä` (a int) engine=heap;
+#--replace_column 7 # 8 # 9 #
+#show table status from `ä` LIKE 'ä';
+#drop database `ä`;
#########################################################
# end of part that must be uncommented when WL#1324 is done
#########################################################
@@ -214,7 +223,7 @@ select @@max_heap_table_size;
CREATE TABLE t1 (
a int(11) default NULL,
- KEY a TYPE BTREE (a)
+ KEY a USING BTREE (a)
) ENGINE=HEAP;
CREATE TABLE t2 (
@@ -225,7 +234,7 @@ CREATE TABLE t2 (
CREATE TABLE t3 (
a int(11) default NULL,
b int(11) default NULL,
- KEY a TYPE BTREE (a),
+ KEY a USING BTREE (a),
index(b)
) ENGINE=HEAP;
@@ -283,25 +292,25 @@ connect (con1,localhost,mysqltest_1,,mysqltest);
connection con1;
select * from t1;
show create database mysqltest;
---error 1044
+--error 1142
drop table t1;
--error 1044
drop database mysqltest;
connect (con2,localhost,mysqltest_2,,test);
connection con2;
---error 1044
+--error 1142
select * from mysqltest.t1;
--error 1044
show create database mysqltest;
---error 1044
+--error 1142
drop table mysqltest.t1;
--error 1044
drop database mysqltest;
connect (con3,localhost,mysqltest_3,,test);
connection con3;
---error 1044
+--error 1142
select * from mysqltest.t1;
--error 1044
show create database mysqltest;
@@ -316,7 +325,6 @@ delete from mysql.db
where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
flush privileges;
-#Bug #4374 SHOW TABLE STATUS FROM ignores collation_connection
# This test fails on MAC OSX, so it is temporary disabled.
# This needs WL#1324 to be done.
#set names latin1;
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
new file mode 100644
index 00000000000..ff317b4ac28
--- /dev/null
+++ b/mysql-test/t/sp-error.test
@@ -0,0 +1,907 @@
+#
+# Stored PROCEDURE error tests
+#
+
+# Make sure we don't have any procedures left.
+delete from mysql.proc;
+
+delimiter |;
+
+# This should give three syntax errors (sometimes crashed; bug #643)
+# (Unfortunately, this is not a 100% test, on some platforms this
+# passed despite the bug.)
+--error 1064
+create procedure syntaxerror(t int)|
+--error 1064
+create procedure syntaxerror(t int)|
+--error 1064
+create procedure syntaxerror(t int)|
+
+# Check that we get the right error, i.e. UDF declaration parses correctly,
+# but foo.so doesn't exist.
+# This generates an error message containing a misleading errno which
+# might vary between systems (it usually doesn't have anything to do with
+# the actual failing dlopen()).
+#--error 1126
+#create function foo returns real soname "foo.so"|
+
+
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 ( x int )|
+insert into t3 values (2), (3)|
+
+create procedure bad_into(out param int)
+ select x from t3 into param|
+
+--error 1172
+call bad_into(@x)|
+
+drop procedure bad_into|
+drop table t3|
+
+
+create procedure proc1()
+ set @x = 42|
+
+create function func1() returns int
+ return 42|
+
+# Can't create recursively
+--error 1303
+create procedure foo()
+ create procedure bar() set @x=3|
+--error 1303
+create procedure foo()
+ create function bar() returns double return 2.3|
+
+# Already exists
+--error 1304
+create procedure proc1()
+ set @x = 42|
+--error 1304
+create function func1() returns int
+ return 42|
+
+drop procedure proc1|
+drop function func1|
+
+# Does not exist
+--error 1305
+alter procedure foo|
+--error 1305
+alter function foo|
+--error 1305
+drop procedure foo|
+--error 1305
+drop function foo|
+--error 1305
+call foo()|
+drop procedure if exists foo|
+--error 1305
+show create procedure foo|
+--error 1305
+show create function foo|
+
+# LEAVE/ITERATE/GOTO with no match
+--error 1308
+create procedure foo()
+foo: loop
+ leave bar;
+end loop|
+--error 1308
+create procedure foo()
+foo: loop
+ iterate bar;
+end loop|
+--error 1308
+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
+create procedure foo()
+foo: loop
+ foo: loop
+ set @x=2;
+ end loop foo;
+end loop foo|
+
+# End label mismatch
+--error 1310
+create procedure foo()
+foo: loop
+ set @x=2;
+end loop bar|
+
+# RETURN in FUNCTION only
+--error 1313
+create procedure foo()
+ return 42|
+
+# Wrong number of arguments
+create procedure p(x int)
+ set @x = x|
+create function f(x int) returns int
+ return x+42|
+
+--error 1318
+call p()|
+--error 1318
+call p(1, 2)|
+--error 1318
+select f()|
+--error 1318
+select f(1, 2)|
+
+drop procedure p|
+drop function f|
+
+--error 1319
+create procedure p(val int, out res int)
+begin
+ declare x int default 0;
+ declare continue handler for foo set x = 1;
+
+ insert into test.t1 values (val);
+ if (x) then
+ set res = 0;
+ else
+ set res = 1;
+ end if;
+end|
+
+--error 1319
+create procedure p(val int, out res int)
+begin
+ declare x int default 0;
+ declare foo condition for 1146;
+ declare continue handler for bar set x = 1;
+
+ insert into test.t1 values (val);
+ if (x) then
+ set res = 0;
+ else
+ set res = 1;
+ end if;
+end|
+
+--error 1320
+create function f(val int) returns int
+begin
+ declare x int;
+
+ set x = val+3;
+end|
+
+create function f(val int) returns int
+begin
+ declare x int;
+
+ set x = val+3;
+ if x < 4 then
+ return x;
+ end if;
+end|
+
+--error 1321
+select f(10)|
+
+drop function f|
+
+--error 1322
+create procedure p()
+begin
+ declare c cursor for insert into test.t1 values ("foo", 42);
+
+ open c;
+ close c;
+end|
+
+--error 1323
+create procedure p()
+begin
+ declare x int;
+ declare c cursor for select * into x from test.t limit 1;
+
+ open c;
+ close c;
+end|
+
+--error 1324
+create procedure p()
+begin
+ declare c cursor for select * from test.t;
+
+ open cc;
+ close c;
+end|
+
+--disable_warnings
+drop table if exists t1|
+--enable_warnings
+create table t1 (val int)|
+
+create procedure p()
+begin
+ declare c cursor for select * from test.t1;
+
+ open c;
+ open c;
+ close c;
+end|
+--error 1325
+call p()|
+drop procedure p|
+
+create procedure p()
+begin
+ declare c cursor for select * from test.t1;
+
+ open c;
+ close c;
+ close c;
+end|
+--error 1326
+call p()|
+drop procedure p|
+
+--error 1305
+alter procedure bar3 sql security invoker|
+
+drop table t1|
+
+--disable_warnings
+drop table if exists t1|
+--enable_warnings
+create table t1 (val int, x float)|
+insert into t1 values (42, 3.1), (19, 1.2)|
+
+--error 1327
+create procedure p()
+begin
+ declare x int;
+ declare c cursor for select * from t1;
+
+ open c;
+ fetch c into x, y;
+ close c;
+end|
+
+create procedure p()
+begin
+ declare x int;
+ declare c cursor for select * from t1;
+
+ open c;
+ fetch c into x;
+ close c;
+end|
+--error 1328
+call p()|
+drop procedure p|
+
+create procedure p()
+begin
+ declare x int;
+ declare y float;
+ declare z int;
+ declare c cursor for select * from t1;
+
+ open c;
+ fetch c into x, y, z;
+ close c;
+end|
+--error 1328
+call p()|
+drop procedure p|
+
+--error 1330
+create procedure p(in x int, x char(10))
+begin
+end|
+--error 1330
+create function p(x int, x char(10))
+begin
+end|
+
+--error 1331
+create procedure p()
+begin
+ declare x float;
+ declare x int;
+end|
+
+--error 1332
+create procedure p()
+begin
+ declare c condition for 1064;
+ declare c condition for 1065;
+end|
+
+--error 1333
+create procedure p()
+begin
+ declare c cursor for select * from t1;
+ declare c cursor for select field from t1;
+end|
+
+# USE is not allowed
+--error 1336
+create procedure u()
+ use sptmp|
+
+# Enforced standard order of declarations
+--error 1337
+create procedure p()
+begin
+ declare c cursor for select * from t1;
+ declare x int;
+end|
+--error 1337
+create procedure p()
+begin
+ declare x int;
+ declare continue handler for sqlstate '42S99' set x = 1;
+ declare foo condition for sqlstate '42S99';
+end|
+
+--error 1338
+create procedure p()
+begin
+ declare x int;
+ declare continue handler for sqlstate '42S99' set x = 1;
+ 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|
+--enable_warnings
+create procedure p(in x int, inout y int, out z int)
+begin
+ set y = x+y;
+ set z = x+y;
+end|
+
+set @tmp_x = 42|
+set @tmp_y = 3|
+set @tmp_z = 0|
+# For reference: this is ok
+call p(@tmp_x, @tmp_y, @tmp_z)|
+select @tmp_x, @tmp_y, @tmp_z|
+
+--error ER_SP_NOT_VAR_ARG
+call p(42, 43, @tmp_z)|
+--error ER_SP_NOT_VAR_ARG
+call p(42, @tmp_y, 43)|
+
+drop procedure p|
+
+
+#
+# BUG#1965
+#
+create procedure bug1965()
+begin
+ declare c cursor for select val from t1 order by valname;
+ open c;
+ close c;
+end|
+
+--error 1054
+call bug1965()|
+drop procedure bug1965|
+
+#
+# BUG#1966
+#
+--error 1327
+select 1 into a|
+
+#
+# BUG#1653
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 (column_1_0 int)|
+
+create procedure bug1653()
+ update t3 set column_1 = 0|
+
+--error 1054
+call bug1653()|
+drop table t3|
+create table t3 (column_1 int)|
+call bug1653()|
+
+drop procedure bug1653|
+drop table t3|
+
+#
+# BUG#2259
+#
+# Note: When this bug existed, it did not necessarily cause a crash
+# in all builds, but valgrind did give warnings.
+create procedure bug2259()
+begin
+ declare v1 int;
+ declare c1 cursor for select s1 from t1;
+
+ fetch c1 into v1;
+end|
+
+--error 1326
+call bug2259()|
+drop procedure bug2259|
+
+#
+# BUG#2272
+#
+create procedure bug2272()
+begin
+ declare v int;
+
+ update t1 set v = 42;
+end|
+
+insert into t1 values (666, 51.3)|
+--error 1054
+call bug2272()|
+delete from t1|
+drop procedure bug2272|
+
+#
+# BUG#2329
+#
+create procedure bug2329_1()
+begin
+ declare v int;
+
+ insert into t1 (v) values (5);
+end|
+
+create procedure bug2329_2()
+begin
+ declare v int;
+
+ replace t1 set v = 5;
+end|
+
+--error 1054
+call bug2329_1()|
+--error 1054
+call bug2329_2()|
+drop procedure bug2329_1|
+drop procedure bug2329_2|
+
+#
+# BUG#3287
+#
+create function bug3287() returns int
+begin
+ declare v int default null;
+
+ case
+ when v is not null then return 1;
+ end case;
+ return 2;
+end|
+--error 1339
+select bug3287()|
+drop function bug3287|
+
+create procedure bug3287(x int)
+case x
+when 0 then
+ insert into test.t1 values (x, 0.1);
+when 1 then
+ insert into test.t1 values (x, 1.1);
+end case|
+--error 1339
+call bug3287(2)|
+drop procedure bug3287|
+
+#
+# BUG#3297
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 (s1 int, primary key (s1))|
+insert into t3 values (5),(6)|
+
+create procedure bug3279(out y int)
+begin
+ declare x int default 0;
+ begin
+ declare exit handler for sqlexception set x = x+1;
+ insert into t3 values (5);
+ end;
+ if x < 2 then
+ set x = x+1;
+ insert into t3 values (6);
+ end if;
+ set y = x;
+end|
+
+set @x = 0|
+--error 1062
+call bug3279(@x)|
+select @x|
+drop procedure bug3279|
+drop table t3|
+
+#
+# BUG#3339
+#
+--error 1049
+create procedure nodb.bug3339() begin end|
+
+#
+# BUG#2653
+#
+create procedure bug2653_1(a int, out b int)
+ set b = aa|
+
+create procedure bug2653_2(a int, out b int)
+begin
+ if aa < 0 then
+ set b = - a;
+ else
+ set b = a;
+ end if;
+end|
+
+--error 1054
+call bug2653_1(1, @b)|
+--error 1054
+call bug2653_2(2, @b)|
+
+drop procedure bug2653_1|
+drop procedure bug2653_2|
+
+#
+# BUG#4344
+#
+--error 1357
+create procedure bug4344() drop procedure bug4344|
+--error 1357
+create procedure bug4344() drop function bug4344|
+
+#
+# BUG#3294: Stored procedure crash if table dropped before use
+# (Actually, when an error occurs within an error handler.)
+--disable_warnings
+drop procedure if exists bug3294|
+--enable_warnings
+create procedure bug3294()
+begin
+ declare continue handler for sqlexception drop table t5;
+ drop table t5;
+ drop table t5;
+end|
+
+create table t5 (x int)|
+--error 1051
+call bug3294()|
+drop procedure bug3294|
+
+#
+# BUG#6807: Stored procedure crash if CREATE PROCEDURE ... KILL QUERY
+#
+--disable_warnings
+drop procedure if exists bug6807|
+--enable_warnings
+create procedure bug6807()
+begin
+ declare id int;
+
+ set id = connection_id();
+ kill query id;
+ select 'Not reached';
+end|
+
+--error 1317
+call bug6807()|
+--error 1317
+call bug6807()|
+
+drop procedure bug6807|
+
+#
+# BUG#876: Stored Procedures: Invalid SQLSTATE is allowed in
+# a DECLARE ? HANDLER FOR stmt.
+#
+--disable_warnings
+drop procedure if exists bug8776_1|
+drop procedure if exists bug8776_2|
+drop procedure if exists bug8776_3|
+drop procedure if exists bug8776_4|
+--enable_warnings
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_1()
+begin
+ declare continue handler for sqlstate '42S0200test' begin end;
+ begin end;
+end|
+
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_2()
+begin
+ declare continue handler for sqlstate '4200' begin end;
+ begin end;
+end|
+
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_3()
+begin
+ declare continue handler for sqlstate '420000' begin end;
+ begin end;
+end|
+
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_4()
+begin
+ declare continue handler for sqlstate '42x00' begin end;
+ begin end;
+end|
+
+
+#
+# BUG#6600: Stored procedure crash after repeated calls with check table
+#
+--error ER_SP_BADSTATEMENT
+create procedure bug6600()
+ check table t1|
+
+# Check these two as well, while we're at it. (Although it isn't really
+# related to the bug report, but to the fix.)
+--error ER_SP_BADSTATEMENT
+create procedure bug6600()
+ lock table t1 read|
+--error ER_SP_BADSTATEMENT
+create procedure bug6600()
+ unlock table t1|
+
+#
+# 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.
+#
+--disable_warnings
+drop procedure if exists bug9566|
+--enable_warnings
+create procedure bug9566()
+begin
+ select * from t1;
+end|
+lock table t1 read|
+# This should fail because we forgot to lock mysql.proc table explicitly
+--error 1100
+call bug9566()|
+unlock tables|
+# This should succeed
+drop procedure bug9566|
+
+
+#
+# BUG#7299: Stored procedures: exception handler catches not-found conditions
+#
+--disable_warnings
+drop procedure if exists bug7299|
+--enable_warnings
+create procedure bug7299()
+begin
+ declare v int;
+ declare c cursor for select val from t1;
+ declare exit handler for sqlexception select 'Error!';
+
+ open c;
+ fetch c into v;
+end|
+
+delete from t1|
+--error ER_SP_FETCH_NO_DATA
+call bug7299()|
+drop procedure bug7299|
+
+
+#
+# BUG#9073: Able to declare two handlers for same condition in same scope
+#
+--error ER_SP_DUP_HANDLER
+create procedure bug9073()
+begin
+ declare continue handler for sqlexception select 1;
+ declare continue handler for sqlexception select 2;
+end|
+--error ER_SP_DUP_HANDLER
+create procedure bug9073()
+begin
+ declare condname1 condition for 1234;
+ declare continue handler for condname1 select 1;
+ declare exit handler for condname1 select 2;
+end|
+--error ER_SP_DUP_HANDLER
+create procedure bug9073()
+begin
+ declare condname1 condition for sqlstate '42000';
+ declare condname2 condition for sqlstate '42000';
+ declare exit handler for condname1 select 1;
+ declare continue handler for condname2 select 2;
+end|
+--error ER_SP_DUP_HANDLER
+create procedure bug9073()
+begin
+ declare condname1 condition for sqlstate '42000';
+ declare exit handler for condname1 select 1;
+ declare exit handler for sqlstate '42000' select 2;
+end|
+
+# This should still work.
+--disable_warnings
+drop procedure if exists bug9073|
+--enable_warnings
+create procedure bug9073()
+begin
+ declare condname1 condition for sqlstate '42000';
+ declare continue handler for condname1 select 1;
+ begin
+ declare exit handler for sqlstate '42000' select 2;
+ begin
+ declare continue handler for sqlstate '42000' select 3;
+ end;
+ end;
+end|
+drop procedure bug9073|
+
+
+#
+# BUG#7047: Stored procedure crash if alter procedure
+#
+--error ER_SP_NO_DROP_SP
+create procedure bug7047()
+ alter procedure bug7047|
+--error ER_SP_NO_DROP_SP
+create function bug7047() returns int
+begin
+ alter function bug7047;
+ return 0;
+end|
+
+
+#
+# BUG#8408: Stored procedure crash if function contains SHOW
+# BUG#9058: Stored Procedures: Crash if function included SELECT
+#
+
+# Some things are caught when parsing
+--error ER_SP_NO_RETSET_IN_FUNC
+create function bug8408() returns int
+begin
+ select * from t1;
+ return 0;
+end|
+--error ER_SP_NO_RETSET_IN_FUNC
+create function bug8408() returns int
+begin
+ show warnings;
+ return 0;
+end|
+--error ER_SP_NO_RETSET_IN_FUNC
+create function bug8408(a int) returns int
+begin
+ declare b int;
+ select b;
+ return b;
+end|
+
+--disable_warnings
+drop function if exists bug8408_f|
+drop procedure if exists bug8408_p|
+--enable_warnings
+
+# Some things must be caught at invokation time
+create function bug8408_f() returns int
+begin
+ call bug8408_p();
+ return 0;
+end|
+create procedure bug8408_p()
+ select * from t1|
+
+call bug8408_p()|
+--error ER_SP_BADSELECT
+select bug8408_f()|
+
+drop procedure bug8408_p|
+drop function bug8408_f|
+
+# But this is ok
+create function bug8408() returns int
+begin
+ declare n int default 0;
+ select count(*) into n from t1;
+ return n;
+end|
+
+insert into t1 value (2, 2.7), (3, 3.14), (7, 7.0)|
+select *,bug8408() from t1|
+
+drop function bug8408|
+delete from t1|
+
+
+#
+# BUG#NNNN: New bug synopsis
+#
+#--disable_warnings
+#drop procedure if exists bugNNNN|
+#--enable_warnings
+#create procedure bugNNNN...
+
+
+drop table t1|
+
+delimiter ;|
diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test
new file mode 100644
index 00000000000..5a8dfc54920
--- /dev/null
+++ b/mysql-test/t/sp-security.test
@@ -0,0 +1,306 @@
+#
+# Testing SQL SECURITY of stored procedures
+#
+
+# Can't test with embedded server that doesn't support grants
+-- source include/not_embedded.inc
+
+connect (con1root,localhost,root,,);
+
+connection con1root;
+use test;
+
+# Create user user1 with no particular access rights
+grant usage on *.* to user1@localhost;
+flush privileges;
+
+--disable_warnings
+drop database if exists db1_secret;
+--enable_warnings
+# Create our secret database
+create database db1_secret;
+
+# Can create a procedure in other db
+create procedure db1_secret.dummy() begin end;
+drop procedure db1_secret.dummy;
+
+use db1_secret;
+
+create table t1 ( u varchar(64), i int );
+
+# A test procedure and function
+create procedure stamp(i int)
+ insert into db1_secret.t1 values (user(), i);
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show procedure status like 'stamp';
+
+create function db() returns varchar(64) return database();
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show function status like 'db';
+
+# root can, of course
+call stamp(1);
+select * from t1;
+select db();
+
+grant execute on db1_secret.stamp to user1@'%';
+grant execute on db1_secret.db to user1@'%';
+grant execute on db1_secret.stamp to ''@'%';
+grant execute on db1_secret.db to ''@'%';
+
+connect (con2user1,localhost,user1,,);
+connect (con3anon,localhost,anon,,);
+
+
+#
+# User1 can
+#
+connection con2user1;
+
+# This should work...
+call db1_secret.stamp(2);
+select db1_secret.db();
+
+# ...but not this
+--error 1142
+select * from db1_secret.t1;
+
+# ...and not this
+--error 1044
+create procedure db1_secret.dummy() begin end;
+--error 1305
+drop procedure db1_secret.dummy;
+
+
+#
+# Anonymous can
+#
+connection con3anon;
+
+# This should work...
+call db1_secret.stamp(3);
+select db1_secret.db();
+
+# ...but not this
+--error 1142
+select * from db1_secret.t1;
+
+# ...and not this
+--error 1044
+create procedure db1_secret.dummy() begin end;
+--error 1305
+drop procedure db1_secret.dummy;
+
+
+#
+# Check it out
+#
+connection con1root;
+select * from t1;
+
+#
+# Change to invoker's rights
+#
+alter procedure stamp sql security invoker;
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show procedure status like 'stamp';
+
+alter function db sql security invoker;
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show function status like 'db';
+
+# root still can
+call stamp(4);
+select * from t1;
+select db();
+
+#
+# User1 cannot
+#
+connection con2user1;
+
+# This should not work
+--error 1044
+call db1_secret.stamp(5);
+--error 1044
+select db1_secret.db();
+
+#
+# Anonymous cannot
+#
+connection con3anon;
+
+# This should not work
+--error 1044
+call db1_secret.stamp(6);
+--error 1044
+select db1_secret.db();
+
+#
+# BUG#2777
+#
+
+connection con1root;
+--disable_warnings
+drop database if exists db2;
+--enable_warnings
+create database db2;
+
+use db2;
+
+create table t2 (s1 int);
+insert into t2 values (0);
+
+grant usage on db2.* to user1@localhost;
+grant select on db2.* to user1@localhost;
+grant usage on db2.* to user2@localhost;
+grant select,insert,update,delete,create routine on db2.* to user2@localhost;
+grant create routine on db2.* to user1@localhost;
+flush privileges;
+
+connection con2user1;
+use db2;
+
+create procedure p () insert into t2 values (1);
+
+# Check that this doesn't work.
+--error 1142
+call p();
+
+connect (con4user2,localhost,user2,,);
+
+connection con4user2;
+use db2;
+
+# This should not work, since p is executed with definer's (user1's) rights.
+--error 1370
+call p();
+select * from t2;
+
+create procedure q () insert into t2 values (2);
+
+call q();
+select * from t2;
+
+connection con1root;
+grant usage on db2.q to user2@localhost with grant option;
+
+connection con4user2;
+grant execute on db2.q to user1@localhost;
+
+connection con2user1;
+use db2;
+
+# This should work
+call q();
+select * from t2;
+
+
+#
+# BUG#6030: Stored procedure has no appropriate DROP privilege
+# (or ALTER for that matter)
+
+# still connection con2user1 in db2
+
+# This should work:
+alter procedure p modifies sql data;
+drop procedure p;
+
+# This should NOT work
+--error 1370
+alter procedure q modifies sql data;
+--error 1370
+drop procedure q;
+
+connection con1root;
+use db2;
+# But root always can
+alter procedure q modifies sql data;
+drop procedure q;
+
+
+# Clean up
+#Still connection con1root;
+disconnect con2user1;
+disconnect con3anon;
+disconnect con4user2;
+use test;
+select type,db,name from mysql.proc;
+drop database db1_secret;
+drop database db2;
+# Make sure the routines are gone
+select type,db,name from mysql.proc;
+# Get rid of the users
+delete from mysql.user where user='user1' or user='user2';
+# And any routine privileges
+delete from mysql.procs_priv where user='user1' or user='user2';
+
+#
+# Test the new security acls
+#
+grant usage on *.* to usera@localhost;
+grant usage on *.* to userb@localhost;
+grant usage on *.* to userc@localhost;
+create database sptest;
+create table t1 ( u varchar(64), i int );
+create procedure sptest.p1(i int) insert into test.t1 values (user(), i);
+grant insert on t1 to usera@localhost;
+grant execute on sptest.p1 to usera@localhost;
+show grants for usera@localhost;
+grant execute on sptest.p1 to userc@localhost with grant option;
+show grants for userc@localhost;
+
+connect (con2usera,localhost,usera,,);
+connect (con3userb,localhost,userb,,);
+connect (con4userc,localhost,userc,,);
+
+connection con2usera;
+call sptest.p1(1);
+--error 1370
+grant execute on sptest.p1 to userb@localhost;
+--error 1370
+drop procedure sptest.p1;
+
+connection con3userb;
+--error 1370
+call sptest.p1(2);
+--error 1370
+grant execute on sptest.p1 to userb@localhost;
+--error 1370
+drop procedure sptest.p1;
+
+connection con4userc;
+call sptest.p1(3);
+grant execute on sptest.p1 to userb@localhost;
+--error 1370
+drop procedure sptest.p1;
+
+connection con3userb;
+call sptest.p1(4);
+--error 1370
+grant execute on sptest.p1 to userb@localhost;
+--error 1370
+drop procedure sptest.p1;
+
+connection con1root;
+select * from t1;
+
+grant all privileges on sptest.p1 to userc@localhost;
+show grants for userc@localhost;
+show grants for userb@localhost;
+
+connection con4userc;
+revoke all privileges on sptest.p1 from userb@localhost;
+
+connection con1root;
+show grants for userb@localhost;
+
+#cleanup
+disconnect con4userc;
+disconnect con3userb;
+disconnect con2usera;
+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';
+
diff --git a/mysql-test/t/sp-threads.test b/mysql-test/t/sp-threads.test
new file mode 100644
index 00000000000..608ac3e2ee7
--- /dev/null
+++ b/mysql-test/t/sp-threads.test
@@ -0,0 +1,95 @@
+#
+# Testing stored procedures with multiple connections,
+# except security/privilege tests, they go to sp-security.test
+#
+
+connect (con1root,localhost,root,,);
+connect (con2root,localhost,root,,);
+
+connection con1root;
+use test;
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (s1 int, s2 int, s3 int);
+
+delimiter //;
+create procedure bug4934()
+begin
+ insert into t1 values (1,0,1);
+end//
+delimiter ;//
+
+
+connection con2root;
+use test;
+
+call bug4934();
+select * from t1;
+
+
+connection con1root;
+
+drop table t1;
+create table t1 (s1 int, s2 int, s3 int);
+
+drop procedure bug4934;
+delimiter //;
+create procedure bug4934()
+begin
+end//
+delimiter ;//
+
+
+connection con2root;
+
+select * from t1;
+call bug4934();
+select * from t1;
+
+connection con1root;
+
+drop table t1;
+drop procedure bug4934;
+
+
+#
+# BUG #9486 "Can't perform multi-update in stored procedure"
+#
+--disable_warnings
+drop procedure if exists bug9486;
+drop table if exists t1, t2;
+--enable_warnings
+create table t1 (id1 int, val int);
+create table t2 (id2 int);
+
+create procedure bug9486()
+ update t1, t2 set val= 1 where id1=id2;
+call bug9486();
+# Let us check that SP invocation requires write lock for t2.
+connection con2root;
+lock tables t2 write;
+connection con1root;
+send call bug9486();
+connection con2root;
+--sleep 2
+# There should be call statement in locked state.
+--replace_column 1 # 6 #
+show processlist;
+unlock tables;
+connection con1root;
+reap;
+
+drop procedure bug9486;
+drop table t1, t2;
+
+
+#
+# BUG#NNNN: New bug synopsis
+#
+#--disable_warnings
+#drop procedure if exists bugNNNN;
+#--enable_warnings
+#create procedure bugNNNN...
+
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
new file mode 100644
index 00000000000..7b3bff4eb55
--- /dev/null
+++ b/mysql-test/t/sp.test
@@ -0,0 +1,3740 @@
+#
+# Basic stored PROCEDURE tests
+#
+# Please keep this file free of --error cases and other
+# things that will not run in a single debugged mysqld
+# process (e.g. master-slave things).
+#
+# Test cases for bugs are added at the end. See template there.
+#
+# Tests that require --error go into sp-error.test
+# Tests that require inndb go into sp_trans.test
+# 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.
+
+use test;
+
+# Test tables
+#
+# t1 and t2 are reused throughout the file, and dropped at the end.
+# t3 and up are created and dropped when needed.
+#
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (
+ id char(16) not null default '',
+ data int not null
+);
+--disable_warnings
+drop table if exists t2;
+--enable_warnings
+create table t2 (
+ s char(16),
+ i int,
+ d double
+);
+
+
+# Single statement, no params.
+--disable_warnings
+drop procedure if exists foo42;
+--enable_warnings
+create procedure foo42()
+ insert into test.t1 values ("foo", 42);
+
+call foo42();
+select * from t1;
+delete from t1;
+drop procedure foo42;
+
+
+# Single statement, two IN params.
+--disable_warnings
+drop procedure if exists bar;
+--enable_warnings
+create procedure bar(x char(16), y int)
+ insert into test.t1 values (x, y);
+
+call bar("bar", 666);
+select * from t1;
+delete from t1;
+# Don't drop procedure yet...
+
+
+# Now for multiple statements...
+delimiter |;
+
+# Empty statement
+--disable_warnings
+drop procedure if exists empty|
+--enable_warnings
+create procedure empty()
+begin
+end|
+
+call empty()|
+drop procedure empty|
+
+# Scope test. This is legal (warnings might be possible in the future,
+# but for the time being, we just accept it).
+--disable_warnings
+drop procedure if exists scope|
+--enable_warnings
+create procedure scope(a int, b float)
+begin
+ declare b int;
+ declare c float;
+
+ begin
+ declare c int;
+ end;
+end|
+
+drop procedure scope|
+
+# Two statements.
+--disable_warnings
+drop procedure if exists two|
+--enable_warnings
+create procedure two(x1 char(16), x2 char(16), y int)
+begin
+ insert into test.t1 values (x1, y);
+ insert into test.t1 values (x2, y);
+end|
+
+call two("one", "two", 3)|
+select * from t1|
+delete from t1|
+drop procedure two|
+
+
+# Simple test of local variables and SET.
+--disable_warnings
+drop procedure if exists locset|
+--enable_warnings
+create procedure locset(x char(16), y int)
+begin
+ declare z1, z2 int;
+ set z1 = y;
+ set z2 = z1+2;
+ insert into test.t1 values (x, z2);
+end|
+
+call locset("locset", 19)|
+select * from t1|
+delete from t1|
+drop procedure locset|
+
+
+# In some contexts local variables are not recognized
+# (and in some, you have to qualify the identifier).
+--disable_warnings
+drop procedure if exists setcontext|
+--enable_warnings
+create procedure setcontext()
+begin
+ declare data int default 2;
+
+ insert into t1 (id, data) values ("foo", 1);
+ replace t1 set data = data, id = "bar";
+ update t1 set id = "kaka", data = 3 where t1.data = data;
+end|
+
+call setcontext()|
+select * from t1|
+delete from t1|
+drop procedure setcontext|
+
+
+# Set things to null
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 ( d date, i int, f double, s varchar(32) )|
+
+--disable_warnings
+drop procedure if exists nullset|
+--enable_warnings
+create procedure nullset()
+begin
+ declare ld date;
+ declare li int;
+ declare lf double;
+ declare ls varchar(32);
+
+ set ld = null, li = null, lf = null, ls = null;
+ insert into t3 values (ld, li, lf, ls);
+
+ insert into t3 (i, f, s) values ((ld is null), 1, "ld is null"),
+ ((li is null), 1, "li is null"),
+ ((li = 0), null, "li = 0"),
+ ((lf is null), 1, "lf is null"),
+ ((lf = 0), null, "lf = 0"),
+ ((ls is null), 1, "ls is null");
+end|
+
+call nullset()|
+select * from t3|
+drop table t3|
+drop procedure nullset|
+
+
+# The peculiar (non-standard) mixture of variables types in SET.
+--disable_warnings
+drop procedure if exists mixset|
+--enable_warnings
+create procedure mixset(x char(16), y int)
+begin
+ declare z int;
+
+ set @z = y, z = 666, max_join_size = 100;
+ insert into test.t1 values (x, z);
+end|
+
+call mixset("mixset", 19)|
+show variables like 'max_join_size'|
+select id,data,@z from t1|
+delete from t1|
+drop procedure mixset|
+
+
+# Multiple CALL statements, one with OUT parameter.
+--disable_warnings
+drop procedure if exists zip|
+--enable_warnings
+create procedure zip(x char(16), y int)
+begin
+ declare z int;
+ call zap(y, z);
+ call bar(x, z);
+end|
+
+# SET local variables and OUT parameter.
+--disable_warnings
+drop procedure if exists zap|
+--enable_warnings
+create procedure zap(x int, out y int)
+begin
+ declare z int;
+ set z = x+1, y = z;
+end|
+
+call zip("zip", 99)|
+select * from t1|
+delete from t1|
+drop procedure zip|
+drop procedure bar|
+
+# Top-level OUT parameter
+call zap(7, @zap)|
+select @zap|
+
+drop procedure zap|
+
+
+# "Deep" calls...
+--disable_warnings
+drop procedure if exists c1|
+--enable_warnings
+create procedure c1(x int)
+ call c2("c", x)|
+--disable_warnings
+drop procedure if exists c2|
+--enable_warnings
+create procedure c2(s char(16), x int)
+ call c3(x, s)|
+--disable_warnings
+drop procedure if exists c3|
+--enable_warnings
+create procedure c3(x int, s char(16))
+ call c4("level", x, s)|
+--disable_warnings
+drop procedure if exists c4|
+--enable_warnings
+create procedure c4(l char(8), x int, s char(16))
+ insert into t1 values (concat(l,s), x)|
+
+call c1(42)|
+select * from t1|
+delete from t1|
+drop procedure c1|
+drop procedure c2|
+drop procedure c3|
+drop procedure c4|
+
+# INOUT test
+--disable_warnings
+drop procedure if exists iotest|
+--enable_warnings
+create procedure iotest(x1 char(16), x2 char(16), y int)
+begin
+ call inc2(x2, y);
+ insert into test.t1 values (x1, y);
+end|
+
+--disable_warnings
+drop procedure if exists inc2|
+--enable_warnings
+create procedure inc2(x char(16), y int)
+begin
+ call inc(y);
+ insert into test.t1 values (x, y);
+end|
+
+--disable_warnings
+drop procedure if exists inc|
+--enable_warnings
+create procedure inc(inout io int)
+ set io = io + 1|
+
+call iotest("io1", "io2", 1)|
+select * from t1|
+delete from t1|
+drop procedure iotest|
+drop procedure inc2|
+
+# Propagating top-level @-vars
+--disable_warnings
+drop procedure if exists incr|
+--enable_warnings
+create procedure incr(inout x int)
+ call inc(x)|
+
+# Before
+select @zap|
+call incr(@zap)|
+# After
+select @zap|
+
+drop procedure inc|
+drop procedure incr|
+
+# Call-by-value test
+# The expected result is:
+# ("cbv2", 4)
+# ("cbv1", 4711)
+--disable_warnings
+drop procedure if exists cbv1|
+--enable_warnings
+create procedure cbv1()
+begin
+ declare y int default 3;
+
+ call cbv2(y+1, y);
+ insert into test.t1 values ("cbv1", y);
+end|
+
+--disable_warnings
+drop procedure if exists cbv2|
+--enable_warnings
+create procedure cbv2(y1 int, inout y2 int)
+begin
+ set y2 = 4711;
+ insert into test.t1 values ("cbv2", y1);
+end|
+
+call cbv1()|
+select * from t1|
+delete from t1|
+drop procedure cbv1|
+drop procedure cbv2|
+
+
+# Subselect arguments
+
+insert into t2 values ("a", 1, 1.1), ("b", 2, 1.2), ("c", 3, 1.3)|
+
+--disable_warnings
+drop procedure if exists sub1|
+--enable_warnings
+create procedure sub1(id char(16), x int)
+ insert into test.t1 values (id, x)|
+
+--disable_warnings
+drop procedure if exists sub2|
+--enable_warnings
+create procedure sub2(id char(16))
+begin
+ declare x int;
+ set x = (select sum(t.i) from test.t2 t);
+ insert into test.t1 values (id, x);
+end|
+
+--disable_warnings
+drop procedure if exists sub3|
+--enable_warnings
+create function sub3(i int) returns int
+ return i+1|
+
+call sub1("sub1a", (select 7))|
+call sub1("sub1b", (select max(i) from t2))|
+call sub1("sub1c", (select i,d from t2 limit 1))|
+call sub1("sub1d", (select 1 from (select 1) a))|
+call sub2("sub2");
+select * from t1|
+select sub3((select max(i) from t2))|
+drop procedure sub1|
+drop procedure sub2|
+drop function sub3|
+delete from t2|
+
+# Basic tests of the flow control constructs
+
+# Just test on 'x'...
+--disable_warnings
+drop procedure if exists a0|
+--enable_warnings
+create procedure a0(x int)
+while x do
+ set x = x-1;
+ insert into test.t1 values ("a0", x);
+end while|
+
+call a0(3)|
+select * from t1|
+delete from t1|
+drop procedure a0|
+
+
+# The same, but with a more traditional test.
+--disable_warnings
+drop procedure if exists a|
+--enable_warnings
+create procedure a(x int)
+while x > 0 do
+ set x = x-1;
+ insert into test.t1 values ("a", x);
+end while|
+
+call a(3)|
+select * from t1|
+delete from t1|
+drop procedure a|
+
+
+# REPEAT
+--disable_warnings
+drop procedure if exists b|
+--enable_warnings
+create procedure b(x int)
+repeat
+ insert into test.t1 values (repeat("b",3), x);
+ set x = x-1;
+until x = 0 end repeat|
+
+call b(3)|
+select * from t1|
+delete from t1|
+drop procedure b|
+
+
+# Check that repeat isn't parsed the wrong way
+--disable_warnings
+drop procedure if exists b2|
+--enable_warnings
+create procedure b2(x int)
+repeat(select 1 into outfile 'b2');
+ insert into test.t1 values (repeat("b2",3), x);
+ set x = x-1;
+until x = 0 end repeat|
+
+# We don't actually want to call it.
+drop procedure b2|
+
+
+# Labelled WHILE with ITERATE (pointless really)
+--disable_warnings
+drop procedure if exists c|
+--enable_warnings
+create procedure c(x int)
+hmm: while x > 0 do
+ insert into test.t1 values ("c", x);
+ set x = x-1;
+ iterate hmm;
+ insert into test.t1 values ("x", x);
+end while hmm|
+
+call c(3)|
+select * from t1|
+delete from t1|
+drop procedure c|
+
+
+# Labelled WHILE with LEAVE
+--disable_warnings
+drop procedure if exists d|
+--enable_warnings
+create procedure d(x int)
+hmm: while x > 0 do
+ insert into test.t1 values ("d", x);
+ set x = x-1;
+ leave hmm;
+ insert into test.t1 values ("x", x);
+end while|
+
+call d(3)|
+select * from t1|
+delete from t1|
+drop procedure d|
+
+
+# LOOP, with simple IF statement
+--disable_warnings
+drop procedure if exists e|
+--enable_warnings
+create procedure e(x int)
+foo: loop
+ if x = 0 then
+ leave foo;
+ end if;
+ insert into test.t1 values ("e", x);
+ set x = x-1;
+end loop foo|
+
+call e(3)|
+select * from t1|
+delete from t1|
+drop procedure e|
+
+
+# A full IF statement
+--disable_warnings
+drop procedure if exists f|
+--enable_warnings
+create procedure f(x int)
+if x < 0 then
+ insert into test.t1 values ("f", 0);
+elseif x = 0 then
+ insert into test.t1 values ("f", 1);
+else
+ insert into test.t1 values ("f", 2);
+end if|
+
+call f(-2)|
+call f(0)|
+call f(4)|
+select * from t1|
+delete from t1|
+drop procedure f|
+
+
+# This form of CASE is really just syntactic sugar for IF-ELSEIF-...
+--disable_warnings
+drop procedure if exists g|
+--enable_warnings
+create procedure g(x int)
+case
+when x < 0 then
+ insert into test.t1 values ("g", 0);
+when x = 0 then
+ insert into test.t1 values ("g", 1);
+else
+ insert into test.t1 values ("g", 2);
+end case|
+
+call g(-42)|
+call g(0)|
+call g(1)|
+select * from t1|
+delete from t1|
+drop procedure g|
+
+
+# The "simple CASE"
+--disable_warnings
+drop procedure if exists h|
+--enable_warnings
+create procedure h(x int)
+case x
+when 0 then
+ insert into test.t1 values ("h0", x);
+when 1 then
+ insert into test.t1 values ("h1", x);
+else
+ insert into test.t1 values ("h?", x);
+end case|
+
+call h(0)|
+call h(1)|
+call h(17)|
+select * from t1|
+delete from t1|
+drop procedure h|
+
+
+# It's actually possible to LEAVE a BEGIN-END block
+--disable_warnings
+drop procedure if exists i|
+--enable_warnings
+create procedure i(x int)
+foo:
+begin
+ if x = 0 then
+ leave foo;
+ end if;
+ insert into test.t1 values ("i", x);
+end foo|
+
+call i(0)|
+call i(3)|
+select * from t1|
+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)|
+
+--disable_warnings
+drop procedure if exists sel1|
+--enable_warnings
+create procedure sel1()
+begin
+ select * from t1;
+end|
+
+call sel1()|
+drop procedure sel1|
+
+--disable_warnings
+drop procedure if exists sel2|
+--enable_warnings
+create procedure sel2()
+begin
+ select * from t1;
+ select * from t2;
+end|
+
+call sel2()|
+drop procedure sel2|
+delete from t1|
+delete from t2|
+
+# SELECT INTO local variables
+--disable_warnings
+drop procedure if exists into_test|
+--enable_warnings
+create procedure into_test(x char(16), y int)
+begin
+ insert into test.t1 values (x, y);
+ select id,data into x,y from test.t1 limit 1;
+ insert into test.t1 values (concat(x, "2"), y+2);
+end|
+
+call into_test("into", 100)|
+select * from t1|
+delete from t1|
+drop procedure into_test|
+
+
+# SELECT INTO with a mix of local and global variables
+--disable_warnings
+drop procedure if exists into_tes2|
+--enable_warnings
+create procedure into_test2(x char(16), y int)
+begin
+ insert into test.t1 values (x, y);
+ select id,data into x,@z from test.t1 limit 1;
+ insert into test.t1 values (concat(x, "2"), y+2);
+end|
+
+call into_test2("into", 100)|
+select id,data,@z from t1|
+delete from t1|
+drop procedure into_test2|
+
+
+# SELECT * INTO ... (bug test)
+--disable_warnings
+drop procedure if exists into_test3|
+--enable_warnings
+create procedure into_test3()
+begin
+ declare x char(16);
+ declare y int;
+
+ select * into x,y from test.t1 limit 1;
+ insert into test.t2 values (x, y, 0.0);
+end|
+
+insert into t1 values ("into3", 19)|
+# Two call needed for bug test
+call into_test3()|
+call into_test3()|
+select * from t2|
+delete from t1|
+delete from t2|
+drop procedure into_test3|
+
+
+# SELECT INTO with no data is a warning ("no data", which we will
+# not see normally). When not caught, execution proceeds.
+--disable_warnings
+drop procedure if exists into_test4|
+--enable_warnings
+create procedure into_test4()
+begin
+ declare x int;
+
+ select data into x from test.t1 limit 1;
+ insert into test.t3 values ("into4", x);
+end|
+
+delete from t1|
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 ( s char(16), d int)|
+call into_test4()|
+select * from t3|
+insert into t1 values ("i4", 77)|
+call into_test4()|
+select * from t3|
+delete from t1|
+drop table t3|
+drop procedure into_test4|
+
+
+# These two (and the two procedures above) caused an assert() to fail in
+# sql_base.cc:lock_tables() at some point.
+--disable_warnings
+drop procedure if exists into_outfile|
+--enable_warnings
+create procedure into_outfile(x char(16), y int)
+begin
+ insert into test.t1 values (x, y);
+ select * into outfile "/tmp/spout" from test.t1;
+ insert into test.t1 values (concat(x, "2"), y+2);
+end|
+
+system rm -f /tmp/spout|
+call into_outfile("ofile", 1)|
+system rm -f /tmp/spout|
+delete from t1|
+drop procedure into_outfile|
+
+--disable_warnings
+drop procedure if exists into_dumpfile|
+--enable_warnings
+create procedure into_dumpfile(x char(16), y int)
+begin
+ insert into test.t1 values (x, y);
+ select * into dumpfile "/tmp/spdump" from test.t1 limit 1;
+ insert into test.t1 values (concat(x, "2"), y+2);
+end|
+
+system rm -f /tmp/spdump|
+call into_dumpfile("dfile", 1)|
+system rm -f /tmp/spdump|
+delete from t1|
+drop procedure into_dumpfile|
+
+--disable_warnings
+drop procedure if exists create_select|
+--enable_warnings
+create procedure create_select(x char(16), y int)
+begin
+ insert into test.t1 values (x, y);
+ create temporary table test.t3 select * from test.t1;
+ insert into test.t3 values (concat(x, "2"), y+2);
+end|
+
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+call create_select("cs", 90)|
+select * from t1, t3|
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+delete from t1|
+drop procedure create_select|
+
+
+# A minimal, constant FUNCTION.
+--disable_warnings
+drop function if exists e|
+--enable_warnings
+create function e() returns double
+ return 2.7182818284590452354|
+
+set @e = e()|
+select e(), @e|
+
+# A minimal function with one argument
+--disable_warnings
+drop function if exists inc|
+--enable_warnings
+create function inc(i int) returns int
+ return i+1|
+
+select inc(1), inc(99), inc(-71)|
+
+# A minimal function with two arguments
+--disable_warnings
+drop function if exists mul|
+--enable_warnings
+create function mul(x int, y int) returns int
+ return x*y|
+
+select mul(1,1), mul(3,5), mul(4711, 666)|
+
+# A minimal string function
+--disable_warnings
+drop function if exists append|
+--enable_warnings
+create function append(s1 char(8), s2 char(8)) returns char(16)
+ return concat(s1, s2)|
+
+select append("foo", "bar")|
+
+# A function with flow control
+--disable_warnings
+drop function if exists fac|
+--enable_warnings
+create function fac(n int unsigned) returns bigint unsigned
+begin
+ declare f bigint unsigned default 1;
+
+ while n > 1 do
+ set f = f * n;
+ set n = n - 1;
+ end while;
+ return f;
+end|
+
+select fac(1), fac(2), fac(5), fac(10)|
+
+# Nested calls
+--disable_warnings
+drop function if exists fun|
+--enable_warnings
+create function fun(d double, i int, u int unsigned) returns double
+ return mul(inc(i), fac(u)) / e()|
+
+select fun(2.3, 3, 5)|
+
+
+# Various function calls in differen statements
+
+insert into t2 values (append("xxx", "yyy"), mul(4,3), e())|
+insert into t2 values (append("a", "b"), mul(2,mul(3,4)), fun(1.7, 4, 6))|
+
+# Disable PS because double's give a bit different values
+--disable_ps_protocol
+select * from t2 where s = append("a", "b")|
+select * from t2 where i = mul(4,3) or i = mul(mul(3,4),2)|
+select * from t2 where d = e()|
+select * from t2|
+--enable_ps_protocol
+delete from t2|
+
+drop function e|
+drop function inc|
+drop function mul|
+drop function append|
+drop function fun|
+
+
+#
+# CONDITIONs and HANDLERs
+#
+
+--disable_warnings
+drop procedure if exists hndlr1|
+--enable_warnings
+create procedure hndlr1(val int)
+begin
+ declare x int default 0;
+ declare foo condition for 1136;
+ declare bar condition for sqlstate '42S98'; # Just for testing syntax
+ declare zip condition for sqlstate value '42S99'; # Just for testing syntax
+ declare continue handler for foo set x = 1;
+
+ insert into test.t1 values ("hndlr1", val, 2); # Too many values
+ if (x) then
+ insert into test.t1 values ("hndlr1", val); # This instead then
+ end if;
+end|
+
+call hndlr1(42)|
+select * from t1|
+delete from t1|
+drop procedure hndlr1|
+
+--disable_warnings
+drop procedure if exists hndlr2|
+--enable_warnings
+create procedure hndlr2(val int)
+begin
+ declare x int default 0;
+
+ begin
+ declare exit handler for sqlstate '21S01' set x = 1;
+
+ insert into test.t1 values ("hndlr2", val, 2); # Too many values
+ end;
+
+ insert into test.t1 values ("hndlr2", x);
+end|
+
+call hndlr2(42)|
+select * from t1|
+delete from t1|
+drop procedure hndlr2|
+
+
+--disable_warnings
+drop procedure if exists hndlr3|
+--enable_warnings
+create procedure hndlr3(val int)
+begin
+ declare x int default 0;
+ declare continue handler for sqlexception # Any error
+ begin
+ declare z int;
+
+ set z = 2 * val;
+ set x = 1;
+ end;
+
+ if val < 10 then
+ begin
+ declare y int;
+
+ set y = val + 10;
+ insert into test.t1 values ("hndlr3", y, 2); # Too many values
+ if x then
+ insert into test.t1 values ("hndlr3", y);
+ end if;
+ end;
+ end if;
+end|
+
+call hndlr3(3)|
+select * from t1|
+delete from t1|
+drop procedure hndlr3|
+
+
+# Variables might be uninitialized when using handlers
+# (Otherwise the compiler can detect if a variable is not set, but
+# not in this case.)
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 ( id char(16), data int )|
+
+--disable_warnings
+drop procedure if exists hndlr4|
+--enable_warnings
+create procedure hndlr4()
+begin
+ declare x int default 0;
+ declare val int; # No default
+ declare continue handler for sqlstate '02000' set x=1;
+
+ select data into val from test.t3 where id='z' limit 1; # No hits
+
+ insert into test.t3 values ('z', val);
+end|
+
+call hndlr4()|
+select * from t3|
+drop table t3|
+drop procedure hndlr4|
+
+
+#
+# Cursors
+#
+--disable_warnings
+drop procedure if exists cur1|
+--enable_warnings
+create procedure cur1()
+begin
+ declare a char(16);
+ declare b int;
+ declare c double;
+ declare done int default 0;
+ declare c cursor for select * from test.t2;
+ declare continue handler for sqlstate '02000' set done = 1;
+
+ open c;
+ repeat
+ fetch c into a, b, c;
+ if not done then
+ insert into test.t1 values (a, b+c);
+ end if;
+ until done end repeat;
+ close c;
+end|
+
+insert into t2 values ("foo", 42, -1.9), ("bar", 3, 12.1), ("zap", 666, -3.14)|
+call cur1()|
+select * from t1|
+drop procedure cur1|
+
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 ( s char(16), i int )|
+
+--disable_warnings
+drop procedure if exists cur2|
+--enable_warnings
+create procedure cur2()
+begin
+ declare done int default 0;
+ declare c1 cursor for select id,data from test.t1;
+ declare c2 cursor for select i from test.t2;
+ declare continue handler for sqlstate '02000' set done = 1;
+
+ open c1;
+ open c2;
+ repeat
+ begin
+ declare a char(16);
+ declare b,c int;
+
+ fetch from c1 into a, b;
+ fetch next from c2 into c;
+ if not done then
+ if b < c then
+ insert into test.t3 values (a, b);
+ else
+ insert into test.t3 values (a, c);
+ end if;
+ end if;
+ end;
+ until done end repeat;
+ close c1;
+ close c2;
+end|
+
+call cur2()|
+select * from t3|
+delete from t1|
+delete from t2|
+drop table t3|
+drop procedure cur2|
+
+
+# The few characteristics we parse
+--disable_warnings
+drop procedure if exists chistics|
+--enable_warnings
+create procedure chistics()
+ language sql
+ modifies sql data
+ not deterministic
+ sql security definer
+ comment 'Characteristics procedure test'
+ insert into t1 values ("chistics", 1)|
+
+show create procedure chistics|
+# Call it, just to make sure.
+call chistics()|
+select * from t1|
+delete from t1|
+alter procedure chistics sql security invoker|
+show create procedure chistics|
+drop procedure chistics|
+
+--disable_warnings
+drop function if exists chistics|
+--enable_warnings
+create function chistics() returns int
+ language sql
+ deterministic
+ sql security invoker
+ comment 'Characteristics procedure test'
+ return 42|
+
+show create function chistics|
+# Call it, just to make sure.
+select chistics()|
+alter function chistics
+ no sql
+ comment 'Characteristics function test'|
+show create function chistics|
+drop function chistics|
+
+
+# Check mode settings
+insert into t1 values ("foo", 1), ("bar", 2), ("zip", 3)|
+
+set @@sql_mode = 'ANSI'|
+delimiter $|
+--disable_warnings
+drop procedure if exists modes$
+--enable_warnings
+create procedure modes(out c1 int, out c2 int)
+begin
+ declare done int default 0;
+ declare x int;
+ declare c cursor for select data from t1;
+ declare continue handler for sqlstate '02000' set done = 1;
+
+ select 1 || 2 into c1;
+ set c2 = 0;
+ open c;
+ repeat
+ fetch c into x;
+ if not done then
+ set c2 = c2 + 1;
+ end if;
+ until done end repeat;
+ close c;
+end$
+delimiter |$
+set @@sql_mode = ''|
+
+set sql_select_limit = 1|
+call modes(@c1, @c2)|
+set sql_select_limit = default|
+
+select @c1, @c2|
+delete from t1|
+drop procedure modes|
+
+
+# Check that dropping a database without routines works.
+# (Dropping with routines is tested in sp-security.test)
+# First an empty db.
+create database sp_db1|
+drop database sp_db1|
+
+# Again, with a table.
+create database sp_db2|
+use sp_db2|
+# Just put something in here...
+create table t3 ( s char(4), t int )|
+insert into t3 values ("abcd", 42), ("dcba", 666)|
+use test|
+drop database sp_db2|
+
+# And yet again, with just a procedure.
+create database sp_db3|
+use sp_db3|
+--disable_warnings
+drop procedure if exists dummy|
+--enable_warnings
+create procedure dummy(out x int)
+ set x = 42|
+use test|
+drop database sp_db3|
+# Check that it's gone
+select type,db,name from mysql.proc where db = 'sp_db3'|
+
+
+# ROW_COUNT() function after a CALL
+# We test the other cases here too, although it's not strictly SP specific
+--disable_warnings
+drop procedure if exists rc|
+--enable_warnings
+create procedure rc()
+begin
+ delete from t1;
+ insert into t1 values ("a", 1), ("b", 2), ("c", 3);
+end|
+
+call rc()|
+select row_count()|
+--disable_ps_protocol
+update t1 set data=42 where id = "b";
+select row_count()|
+--enable_ps_protocol
+delete from t1|
+select row_count()|
+delete from t1|
+select row_count()|
+select * from t1|
+select row_count()|
+drop procedure rc|
+
+
+#
+# Let us test how well new locking scheme works.
+#
+
+# Let us prepare playground
+--disable_warnings
+drop function if exists f0|
+drop function if exists f1|
+drop function if exists f2|
+drop function if exists f3|
+drop function if exists f4|
+drop function if exists f5|
+drop function if exists f6|
+drop function if exists f7|
+drop function if exists f8|
+drop view if exists v0|
+drop view if exists v1|
+drop view if exists v2|
+--enable_warnings
+delete from t1|
+delete from t2|
+insert into t1 values ("a", 1), ("b", 2) |
+insert into t2 values ("a", 1, 1.0), ("b", 2, 2.0), ("c", 3, 3.0) |
+
+# Test the simplest function using tables
+create function f1() returns int
+ return (select sum(data) from t1)|
+select f1()|
+# This should work too (and give 2 rows as result)
+select id, f1() from t1|
+
+# Function which uses two instances of table simultaneously
+create function f2() returns int
+ return (select data from t1 where data <= (select sum(data) from t1) limit 1)|
+select f2()|
+select id, f2() from t1|
+
+# Function which uses the same table twice in different queries
+create function f3() returns int
+begin
+ declare n int;
+ declare m int;
+ set n:= (select min(data) from t1);
+ set m:= (select max(data) from t1);
+ return n < m;
+end|
+select f3()|
+select id, f3() from t1|
+
+# Calling two functions using same table
+select f1(), f3()|
+select id, f1(), f3() from t1|
+
+# Function which uses two different tables
+create function f4() returns double
+ return (select d from t1, t2 where t1.data = t2.i and t1.id= "b")|
+select f4()|
+select s, f4() from t2|
+
+# Recursive functions which due to this recursion require simultaneous
+# access to several instance of the same table won't work
+create function f5(i int) returns int
+begin
+ if i <= 0 then
+ return 0;
+ elseif i = 1 then
+ return (select count(*) from t1 where data = i);
+ else
+ return (select count(*) + f5( i - 1) from t1 where data = i);
+ end if;
+end|
+select f5(1)|
+# This should generate an error about insuficient number of tables locked
+--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)|
+
+# OTOH this should work
+create function f6() returns int
+begin
+ declare n int;
+ set n:= f1();
+ return (select count(*) from t1 where data <= f7() and data <= n);
+end|
+create function f7() returns int
+ return (select sum(data) from t1 where data <= f1())|
+select f6()|
+select id, f6() from t1|
+
+# TODO Test temporary table handling
+
+#
+# Let us test how new locking work with views
+#
+# The most trivial view
+create view v1 (a) as select f1()|
+select * from v1|
+select id, a from t1, v1|
+select * from v1, v1 as v|
+# A bit more complex construction
+create view v2 (a) as select a*10 from v1|
+select * from v2|
+select id, a from t1, v2|
+select * from v1, v2|
+
+# Nice example where the same view is used on
+# on different expression levels
+create function f8 () returns int
+ return (select count(*) from v2)|
+
+select *, f8() from v1|
+
+# Let us test what will happen if function is missing
+drop function f1|
+--error 1356
+select * from v1|
+
+# And what will happen if we have recursion which involves
+# 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 :)
+#select f1()|
+#select * from v1|
+#select * from v2|
+# Back to the normal cases
+drop function f1|
+create function f1() returns int
+ return (select sum(data) from t1)|
+
+# Let us also test some weird cases where no real tables is used
+create function f0() returns int
+ return (select * from (select 100) as r)|
+select f0()|
+select *, f0() from (select 1) as t|
+create view v0 as select f0()|
+select * from v0|
+select *, f0() from v0|
+
+#
+# Let us test how well prelocking works with explicit LOCK TABLES.
+#
+# Nowdays we have to lock mysql.proc to be able to read SP definitions.
+# But Monty was going to fix this.
+lock tables t1 read, t1 as t11 read, mysql.proc read|
+# These should work well
+select f3()|
+select id, f3() from t1 as t11|
+# Degenerate cases work too :)
+select f0()|
+select * from v0|
+select *, f0() from v0, (select 123) as d1|
+# But these should not !
+--error 1100
+select id, f3() from t1|
+--error 1100
+select f4()|
+unlock tables|
+
+# Let us test how LOCK TABLES which implicitly depends on functions
+# works
+lock tables v2 read, mysql.proc read|
+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|
+--error 1100
+select f4()|
+unlock tables|
+
+
+# TODO We also should test integration with triggers
+
+
+# Cleanup
+drop function f0|
+drop function f1|
+drop function f2|
+drop function f3|
+drop function f4|
+drop function f5|
+drop function f6|
+drop function f7|
+drop function f8|
+drop view v0|
+drop view v1|
+drop view v2|
+delete from t1 |
+delete from t2 |
+
+# End of non-bug tests
+
+
+#
+# Some "real" examples
+#
+
+# fac
+
+--disable_warnings
+drop table if exists fac|
+--enable_warnings
+create table fac (n int unsigned not null primary key, f bigint unsigned)|
+
+--disable_warnings
+drop procedure if exists ifac|
+--enable_warnings
+create procedure ifac(n int unsigned)
+begin
+ declare i int unsigned default 1;
+
+ if n > 20 then
+ set n = 20; # bigint overflow otherwise
+ end if;
+ while i <= n do
+ begin
+ insert into test.fac values (i, fac(i));
+ set i = i + 1;
+ end;
+ end while;
+end|
+
+call ifac(20)|
+select * from fac|
+drop table fac|
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show function status like '%f%'|
+drop procedure ifac|
+drop function fac|
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show function status like '%f%'|
+
+
+# primes
+
+--disable_warnings
+drop table if exists primes|
+--enable_warnings
+
+create table primes (
+ i int unsigned not null primary key,
+ p bigint unsigned not null
+)|
+
+insert into primes values
+ ( 0, 3), ( 1, 5), ( 2, 7), ( 3, 11), ( 4, 13),
+ ( 5, 17), ( 6, 19), ( 7, 23), ( 8, 29), ( 9, 31),
+ (10, 37), (11, 41), (12, 43), (13, 47), (14, 53),
+ (15, 59), (16, 61), (17, 67), (18, 71), (19, 73),
+ (20, 79), (21, 83), (22, 89), (23, 97), (24, 101),
+ (25, 103), (26, 107), (27, 109), (28, 113), (29, 127),
+ (30, 131), (31, 137), (32, 139), (33, 149), (34, 151),
+ (35, 157), (36, 163), (37, 167), (38, 173), (39, 179),
+ (40, 181), (41, 191), (42, 193), (43, 197), (44, 199)|
+
+--disable_warnings
+drop procedure if exists opp|
+--enable_warnings
+create procedure opp(n bigint unsigned, out pp bool)
+begin
+ declare r double;
+ declare b, s bigint unsigned default 0;
+
+ set r = sqrt(n);
+
+ again:
+ loop
+ if s = 45 then
+ set b = b+200, s = 0;
+ else
+ begin
+ declare p bigint unsigned;
+
+ select t.p into p from test.primes t where t.i = s;
+ if b+p > r then
+ set pp = 1;
+ leave again;
+ end if;
+ if mod(n, b+p) = 0 then
+ set pp = 0;
+ leave again;
+ end if;
+ set s = s+1;
+ end;
+ end if;
+ end loop;
+end|
+
+--disable_warnings
+drop procedure if exists ip|
+--enable_warnings
+create procedure ip(m int unsigned)
+begin
+ declare p bigint unsigned;
+ declare i int unsigned;
+
+ set i=45, p=201;
+
+ while i < m do
+ begin
+ declare pp bool default 0;
+
+ call opp(p, pp);
+ if pp then
+ insert into test.primes values (i, p);
+ set i = i+1;
+ end if;
+ set p = p+2;
+ end;
+ end while;
+end|
+show create procedure opp|
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show procedure status like '%p%'|
+
+# This isn't the fastest way in the world to compute prime numbers, so
+# don't be too ambitious. ;-)
+call ip(200)|
+# We don't want to select the entire table here, just pick a few
+# examples.
+# The expected result is:
+# i p
+# --- ----
+# 45 211
+# 100 557
+# 199 1229
+select * from primes where i=45 or i=100 or i=199|
+drop table primes|
+drop procedure opp|
+drop procedure ip|
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+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 )|
+
+insert into fib values (1), (1)|
+
+# 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 > 0 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|
+
+call fib(20)|
+
+select * from fib order by f asc|
+drop table fib|
+drop procedure fib|
+
+
+#
+# Comment & suid
+#
+
+--disable_warnings
+drop procedure if exists bar|
+--enable_warnings
+create procedure bar(x char(16), y int)
+ comment "111111111111" sql security invoker
+ insert into test.t1 values (x, y)|
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show procedure status like 'bar'|
+alter procedure bar comment "2222222222" sql security definer|
+alter procedure bar comment "3333333333"|
+alter procedure bar|
+show create procedure bar|
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show procedure status like 'bar'|
+drop procedure bar|
+
+#
+# rexecution
+#
+--disable_warnings
+drop procedure if exists p1|
+--enable_warnings
+create procedure p1 ()
+ select (select s1 from t3) from t3|
+
+create table t3 (s1 int)|
+
+call p1()|
+insert into t3 values (1)|
+call p1()|
+drop procedure p1|
+drop table t3|
+
+#
+# backticks
+#
+--disable_warnings
+drop function if exists foo|
+--enable_warnings
+create function `foo` () returns int
+ return 5|
+select `foo` ()|
+drop function `foo`|
+
+#
+# Implicit LOCK/UNLOCK TABLES for table access in functions
+#
+
+--disable_warning
+drop function if exists t1max|
+--enable_warnings
+create function t1max() returns int
+begin
+ declare x int;
+ select max(data) into x from t1;
+ return x;
+end|
+
+insert into t1 values ("foo", 3), ("bar", 2), ("zip", 5), ("zap", 1)|
+select t1max()|
+drop function t1max|
+
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 (
+ v char(16) not null primary key,
+ c int unsigned not null
+)|
+
+create function getcount(s char(16)) returns int
+begin
+ declare x int;
+
+ select count(*) into x from t3 where v = s;
+ if x = 0 then
+ insert into t3 values (s, 1);
+ else
+ update t3 set c = c+1 where v = s;
+ end if;
+ return x;
+end|
+
+select * from t1 where data = getcount("bar")|
+select * from t3|
+select getcount("zip")|
+select getcount("zip")|
+select * from t3|
+select getcount(id) from t1 where data = 3|
+select getcount(id) from t1 where data = 5|
+select * from t3|
+drop table t3|
+drop function getcount|
+
+
+#
+# Test cases for old bugs
+#
+
+#
+# BUG#822
+#
+--disable_warnings
+drop procedure if exists bug822|
+--enable_warnings
+create procedure bug822(a_id char(16), a_data int)
+begin
+ declare n int;
+ select count(*) into n from t1 where id = a_id and data = a_data;
+ if n = 0 then
+ insert into t1 (id, data) values (a_id, a_data);
+ end if;
+end|
+
+delete from t1|
+call bug822('foo', 42)|
+call bug822('foo', 42)|
+call bug822('bar', 666)|
+select * from t1|
+delete from t1|
+drop procedure bug822|
+
+#
+# BUG#1495
+#
+--disable_warnings
+drop procedure if exists bug1495|
+--enable_warnings
+create procedure bug1495()
+begin
+ declare x int;
+
+ select data into x from t1 order by id limit 1;
+ if x > 10 then
+ insert into t1 values ("less", x-10);
+ else
+ insert into t1 values ("more", x+10);
+ end if;
+end|
+
+insert into t1 values ('foo', 12)|
+call bug1495()|
+delete from t1 where id='foo'|
+insert into t1 values ('bar', 7)|
+call bug1495()|
+delete from t1 where id='bar'|
+select * from t1|
+delete from t1|
+drop procedure bug1495|
+
+#
+# BUG#1547
+#
+--disable_warnings
+drop procedure if exists bug1547|
+--enable_warnings
+create procedure bug1547(s char(16))
+begin
+ declare x int;
+
+ select data into x from t1 where s = id limit 1;
+ if x > 10 then
+ insert into t1 values ("less", x-10);
+ else
+ insert into t1 values ("more", x+10);
+ end if;
+end|
+
+insert into t1 values ("foo", 12), ("bar", 7)|
+call bug1547("foo")|
+call bug1547("bar")|
+select * from t1|
+delete from t1|
+drop procedure bug1547|
+
+#
+# BUG#1656
+#
+--disable_warnings
+drop table if exists t70|
+--enable_warnings
+create table t70 (s1 int,s2 int)|
+insert into t70 values (1,2)|
+
+--disable_warnings
+drop procedure if exists bug1656|
+--enable_warnings
+create procedure bug1656(out p1 int, out p2 int)
+ select * into p1, p1 from t70|
+
+call bug1656(@1, @2)|
+select @1, @2|
+drop table t70|
+drop procedure bug1656|
+
+#
+# BUG#1862
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3(a int)|
+
+--disable_warnings
+drop procedure if exists bug1862|
+--enable_warnings
+create procedure bug1862()
+begin
+ insert into t3 values(2);
+ flush tables;
+end|
+
+call bug1862()|
+# the second call caused a segmentation
+call bug1862()|
+select * from t3|
+drop table t3|
+drop procedure bug1862|
+
+#
+# BUG#1874
+#
+--disable_warnings
+drop procedure if exists bug1874|
+--enable_warnings
+create procedure bug1874()
+begin
+ declare x int;
+ declare y double;
+ select max(data) into x from t1;
+ insert into t2 values ("max", x, 0);
+ select min(data) into x from t1;
+ insert into t2 values ("min", x, 0);
+ select sum(data) into x from t1;
+ insert into t2 values ("sum", x, 0);
+ select avg(data) into y from t1;
+ insert into t2 values ("avg", 0, y);
+end|
+
+insert into t1 (data) values (3), (1), (5), (9), (4)|
+call bug1874()|
+select * from t2|
+delete from t1|
+delete from t2|
+drop procedure bug1874|
+
+#
+# BUG#2260
+#
+--disable_warnings
+drop procedure if exists bug2260|
+--enable_warnings
+create procedure bug2260()
+begin
+ declare v1 int;
+ declare c1 cursor for select data from t1;
+ declare continue handler for not found set @x2 = 1;
+
+ open c1;
+ fetch c1 into v1;
+ set @x2 = 2;
+ close c1;
+end|
+
+call bug2260()|
+select @x2|
+drop procedure bug2260|
+
+#
+# BUG#2267
+#
+# NOTE: This test case will be fixed as soon as Monty
+# will allow to open mysql.proc table under LOCK TABLES
+# without mentioning in lock list.
+#
+# FIXME: Other solution would be to use preopened proc table
+# instead of opening it anew.
+#
+#--disable_warnings
+#drop procedure if exists bug2267_1|
+#--enable_warnings
+#create procedure bug2267_1()
+#begin
+# show procedure status;
+#end|
+#
+#--disable_warnings
+#drop procedure if exists bug2267_2|
+#--enable_warnings
+#create procedure bug2267_2()
+#begin
+# show function status;
+#end|
+#
+#--disable_warnings
+#drop procedure if exists bug2267_3|
+#--enable_warnings
+#create procedure bug2267_3()
+#begin
+# show create procedure bug2267_1;
+#end|
+#
+#--disable_warnings
+#drop procedure if exists bug2267_4|
+#--enable_warnings
+#create procedure bug2267_4()
+#begin
+# show create function fac;
+#end|
+#
+#--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+#call bug2267_1()|
+#--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+#call bug2267_2()|
+#call bug2267_3()|
+#call bug2267_4()|
+#
+#drop procedure bug2267_1|
+#drop procedure bug2267_2|
+#drop procedure bug2267_3|
+#drop procedure bug2267_4|
+
+#
+# BUG#2227
+#
+--disable_warnings
+drop procedure if exists bug2227|
+--enable_warnings
+create procedure bug2227(x int)
+begin
+ declare y float default 2.6;
+ declare z char(16) default "zzz";
+
+ select 1.3, x, y, 42, z;
+end|
+
+call bug2227(9)|
+drop procedure bug2227|
+
+#
+# BUG#2614
+#
+# QQ The second insert doesn't work with temporary tables (it was an
+# QQ ordinary table before we changed the locking scheme). It results
+# QQ in an error: 1137: Can't reopen table: 't3'
+# QQ which is a known limit with temporary tables.
+# QQ For this reason we can't run this test any more (i.e., if we modify
+# QQ it, it's no longer a test case for the bug), but we keep it here
+# QQ anyway, for tracability.
+#--disable_warnings
+#drop procedure if exists bug2614|
+#--enable_warnings
+#create procedure bug2614()
+#begin
+# drop temporary table if exists t3;
+# create temporary table t3 (id int default '0' not null);
+# insert into t3 select 12;
+# insert into t3 select * from t3;
+#end|
+#
+#--disable_warnings
+#call bug2614()|
+#--enable_warnings
+#call bug2614()|
+#drop temporary table t3|
+#drop procedure bug2614|
+
+#
+# BUG#2674
+#
+--disable_warnings
+drop function if exists bug2674|
+--enable_warnings
+create function bug2674() returns int
+ return @@sort_buffer_size|
+
+set @osbs = @@sort_buffer_size|
+set @@sort_buffer_size = 262000|
+select bug2674()|
+drop function bug2674|
+set @@sort_buffer_size = @osbs|
+
+#
+# BUG#3259
+#
+--disable_warnings
+drop procedure if exists bug3259_1 |
+--enable_warnings
+create procedure bug3259_1 () begin end|
+--disable_warnings
+drop procedure if exists BUG3259_2 |
+--enable_warnings
+create procedure BUG3259_2 () begin end|
+--disable_warnings
+drop procedure if exists Bug3259_3 |
+--enable_warnings
+create procedure Bug3259_3 () begin end|
+
+call BUG3259_1()|
+call BUG3259_1()|
+call bug3259_2()|
+call Bug3259_2()|
+call bug3259_3()|
+call bUG3259_3()|
+
+drop procedure bUg3259_1|
+drop procedure BuG3259_2|
+drop procedure BUG3259_3|
+
+#
+# BUG#2772
+#
+--disable_warnings
+drop function if exists bug2772|
+--enable_warnings
+create function bug2772() returns char(10) character set latin2
+ return 'a'|
+
+select bug2772()|
+drop function bug2772|
+
+#
+# BUG#2776
+#
+--disable_warnings
+drop procedure if exists bug2776_1|
+--enable_warnings
+create procedure bug2776_1(out x int)
+begin
+ declare v int;
+
+ set v = default;
+ set x = v;
+end|
+
+--disable_warnings
+drop procedure if exists bug2776_2|
+--enable_warnings
+create procedure bug2776_2(out x int)
+begin
+ declare v int default 42;
+
+ set v = default;
+ set x = v;
+end|
+
+set @x = 1|
+call bug2776_1(@x)|
+select @x|
+call bug2776_2(@x)|
+select @x|
+drop procedure bug2776_1|
+drop procedure bug2776_2|
+
+#
+# BUG#2780
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 (s1 smallint)|
+
+insert into t3 values (123456789012)|
+
+--disable_warnings
+drop procedure if exists bug2780|
+--enable_warnings
+create procedure bug2780()
+begin
+ declare exit handler for sqlwarning set @x = 1;
+
+ set @x = 0;
+ insert into t3 values (123456789012);
+ insert into t3 values (0);
+end|
+
+call bug2780()|
+select @x|
+select * from t3|
+
+drop procedure bug2780|
+drop table t3|
+
+#
+# BUG#1863
+#
+create table t3 (content varchar(10) )|
+insert into t3 values ("test1")|
+insert into t3 values ("test2")|
+create table t4 (f1 int, rc int, t3 int)|
+
+--disable_warnings
+drop procedure if exists bug1863|
+--enable_warnings
+create procedure bug1863(in1 int)
+begin
+
+ declare ind int default 0;
+ declare t1 int;
+ declare t2 int;
+ declare t3 int;
+
+ declare rc int default 0;
+ declare continue handler for 1065 set rc = 1;
+
+ drop temporary table if exists temp_t1;
+ create temporary table temp_t1 (
+ f1 int auto_increment, f2 varchar(20), primary key (f1)
+ );
+
+ insert into temp_t1 (f2) select content from t3;
+
+ select f2 into t3 from temp_t1 where f1 = 10;
+
+ if (rc) then
+ insert into t4 values (1, rc, t3);
+ end if;
+
+ insert into t4 values (2, rc, t3);
+
+end|
+
+call bug1863(10)|
+call bug1863(10)|
+select * from t4|
+
+drop procedure bug1863|
+drop temporary table temp_t1;
+drop table t3, t4|
+
+#
+# BUG#2656
+#
+--disable_warnings
+drop table if exists t3, t4|
+--enable_warnings
+
+create table t3 (
+ OrderID int not null,
+ MarketID int,
+ primary key (OrderID)
+)|
+
+create table t4 (
+ MarketID int not null,
+ Market varchar(60),
+ Status char(1),
+ primary key (MarketID)
+)|
+
+insert t3 (OrderID,MarketID) values (1,1)|
+insert t3 (OrderID,MarketID) values (2,2)|
+insert t4 (MarketID,Market,Status) values (1,"MarketID One","A")|
+insert t4 (MarketID,Market,Status) values (2,"MarketID Two","A")|
+
+--disable_warnings
+drop procedure if exists bug2656_1|
+--enable_warnings
+create procedure bug2656_1()
+begin
+ select
+ m.Market
+ from t4 m JOIN t3 o
+ ON o.MarketID != 1 and o.MarketID = m.MarketID;
+end |
+
+--disable_warnings
+drop procedure if exists bug2656_2|
+--enable_warnings
+create procedure bug2656_2()
+begin
+ select
+ m.Market
+ from
+ t4 m, t3 o
+ where
+ m.MarketID != 1 and m.MarketID = o.MarketID;
+
+end |
+
+call bug2656_1()|
+call bug2656_1()|
+call bug2656_2()|
+call bug2656_2()|
+drop procedure bug2656_1|
+drop procedure bug2656_2|
+drop table t3, t4|
+
+
+#
+# BUG#3426
+#
+--disable_warnings
+drop procedure if exists bug3426|
+--enable_warnings
+create procedure bug3426(in_time int unsigned, out x int)
+begin
+ if in_time is null then
+ set @stamped_time=10;
+ set x=1;
+ else
+ set @stamped_time=in_time;
+ set x=2;
+ end if;
+end|
+
+call bug3426(1000, @i)|
+select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
+call bug3426(NULL, @i)|
+select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
+# Clear SP cache
+alter procedure bug3426 sql security invoker|
+call bug3426(NULL, @i)|
+select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
+call bug3426(1000, @i)|
+select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
+
+drop procedure bug3426|
+
+#
+# BUG#3448
+#
+--disable_warnings
+drop table if exists t3, t4|
+
+create table t3 (
+ a int primary key,
+ ach char(1)
+) engine = innodb|
+
+create table t4 (
+ b int primary key ,
+ bch char(1)
+) engine = innodb|
+--enable_warnings
+
+insert into t3 values (1 , 'aCh1' ) , ('2' , 'aCh2')|
+insert into t4 values (1 , 'bCh1' )|
+
+--disable_warnings
+drop procedure if exists bug3448|
+--enable_warnings
+create procedure bug3448()
+ select * from t3 inner join t4 on t3.a = t4.b|
+
+select * from t3 inner join t4 on t3.a = t4.b|
+call bug3448()|
+call bug3448()|
+
+drop procedure bug3448|
+drop table t3, t4|
+
+
+#
+# BUG#3734
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 (
+ id int unsigned auto_increment not null primary key,
+ title VARCHAR(200),
+ body text,
+ fulltext (title,body)
+)|
+
+insert into t3 (title,body) values
+ ('MySQL Tutorial','DBMS stands for DataBase ...'),
+ ('How To Use MySQL Well','After you went through a ...'),
+ ('Optimizing MySQL','In this tutorial we will show ...'),
+ ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
+ ('MySQL vs. YourSQL','In the following database comparison ...'),
+ ('MySQL Security','When configured properly, MySQL ...')|
+
+--disable_warnings
+drop procedure if exists bug3734 |
+--enable_warnings
+create procedure bug3734 (param1 varchar(100))
+ select * from t3 where match (title,body) against (param1)|
+
+call bug3734('database')|
+call bug3734('Security')|
+
+drop procedure bug3734|
+drop table t3|
+
+#
+# BUG#3863
+#
+--disable_warnings
+drop procedure if exists bug3863|
+--enable_warnings
+create procedure bug3863()
+begin
+ set @a = 0;
+ while @a < 5 do
+ set @a = @a + 1;
+ end while;
+end|
+
+call bug3863()|
+select @a|
+call bug3863()|
+select @a|
+
+drop procedure bug3863|
+
+#
+# BUG#2460
+#
+
+create table t3 (
+ id int(10) unsigned not null default 0,
+ rid int(10) unsigned not null default 0,
+ msg text not null,
+ primary key (id),
+ unique key rid (rid, id)
+)|
+
+--disable_warnings
+drop procedure if exists bug2460_1|
+--enable_warnings
+create procedure bug2460_1(in v int)
+begin
+ ( select n0.id from t3 as n0 where n0.id = v )
+ union
+ ( select n0.id from t3 as n0, t3 as n1
+ where n0.id = n1.rid and n1.id = v )
+ union
+ ( select n0.id from t3 as n0, t3 as n1, t3 as n2
+ where n0.id = n1.rid and n1.id = n2.rid and n2.id = v );
+end|
+
+call bug2460_1(2)|
+call bug2460_1(2)|
+insert into t3 values (1, 1, 'foo'), (2, 1, 'bar'), (3, 1, 'zip zap')|
+call bug2460_1(2)|
+call bug2460_1(2)|
+
+--disable_warnings
+drop procedure if exists bug2460_2|
+--enable_warnings
+create procedure bug2460_2()
+begin
+ drop table if exists t3;
+ create temporary table t3 (s1 int);
+ insert into t3 select 1 union select 1;
+end|
+
+call bug2460_2()|
+call bug2460_2()|
+select * from t3|
+
+drop procedure bug2460_1|
+drop procedure bug2460_2|
+drop table t3|
+
+
+#
+# BUG#2564
+#
+set @@sql_mode = ''|
+--disable_warnings
+drop procedure if exists bug2564_1|
+--enable_warnings
+create procedure bug2564_1()
+ comment 'Joe''s procedure'
+ insert into `t1` values ("foo", 1)|
+
+set @@sql_mode = 'ANSI_QUOTES'|
+--disable_warnings
+drop procedure if exists bug2564_2|
+--enable_warnings
+create procedure bug2564_2()
+ insert into "t1" values ('foo', 1)|
+
+delimiter $|
+set @@sql_mode = ''$
+--disable_warnings
+drop function if exists bug2564_3$
+--enable_warnings
+create function bug2564_3(x int, y int) returns int
+ return x || y$
+
+set @@sql_mode = 'ANSI'$
+--disable_warnings
+drop function if exists bug2564_4$
+--enable_warnings
+create function bug2564_4(x int, y int) returns int
+ return x || y$
+delimiter |$
+
+set @@sql_mode = ''|
+show create procedure bug2564_1|
+show create procedure bug2564_2|
+show create function bug2564_3|
+show create function bug2564_4|
+
+drop procedure bug2564_1|
+drop procedure bug2564_2|
+drop function bug2564_3|
+drop function bug2564_4|
+
+#
+# BUG#3132
+#
+--disable_warnings
+drop function if exists bug3132|
+--enable_warnings
+create function bug3132(s char(20)) returns char(50)
+ return concat('Hello, ', s, '!')|
+
+select bug3132('Bob') union all select bug3132('Judy')|
+drop function bug3132|
+
+#
+# BUG#3843
+#
+--disable_warnings
+drop procedure if exists bug3843|
+--enable_warnings
+create procedure bug3843()
+ analyze table t1|
+
+# Testing for packets out of order
+call bug3843()|
+call bug3843()|
+select 1+2|
+
+drop procedure bug3843|
+
+#
+# BUG#3368
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 ( s1 char(10) )|
+insert into t3 values ('a'), ('b')|
+
+--disable_warnings
+drop procedure if exists bug3368|
+--enable_warnings
+create procedure bug3368(v char(10))
+begin
+ select group_concat(v) from t3;
+end|
+
+call bug3368('x')|
+call bug3368('yz')|
+drop procedure bug3368|
+drop table t3|
+
+#
+# BUG#4579
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 (f1 int, f2 int)|
+insert into t3 values (1,1)|
+
+--disable_warnings
+drop procedure if exists bug4579_1|
+--enable_warnings
+create procedure bug4579_1 ()
+begin
+ declare sf1 int;
+
+ select f1 into sf1 from t3 where f1=1 and f2=1;
+ update t3 set f2 = f2 + 1 where f1=1 and f2=1;
+ call bug4579_2();
+end|
+
+--disable_warnings
+drop procedure if exists bug4579_2|
+--enable_warnings
+create procedure bug4579_2 ()
+begin
+end|
+
+call bug4579_1()|
+call bug4579_1()|
+call bug4579_1()|
+
+drop procedure bug4579_1|
+drop procedure bug4579_2|
+drop table t3|
+
+#
+# BUG#2773: Function's data type ignored in stored procedures
+#
+--disable_warnings
+drop table if exists t3|
+drop procedure if exists bug2773|
+--enable_warnings
+
+create function bug2773() returns int return null|
+create table t3 as select bug2773()|
+show create table t3|
+drop table t3|
+drop function bug2773|
+
+#
+# BUG#3788: Stored procedure packet error
+#
+--disable_warnings
+drop procedure if exists bug3788|
+--enable_warnings
+
+create function bug3788() returns date return cast("2005-03-04" as date)|
+select bug3788()|
+drop function bug3788|
+
+create function bug3788() returns binary(5) return 5|
+select bug3788()|
+drop function bug3788|
+
+
+#
+# BUG#4726
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+
+create table t3 (f1 int, f2 int, f3 int)|
+insert into t3 values (1,1,1)|
+
+--disable_warnings
+drop procedure if exists bug4726|
+--enable_warnings
+create procedure bug4726()
+begin
+ declare tmp_o_id INT;
+ declare tmp_d_id INT default 1;
+
+ while tmp_d_id <= 2 do
+ begin
+ select f1 into tmp_o_id from t3 where f2=1 and f3=1;
+ set tmp_d_id = tmp_d_id + 1;
+ end;
+ end while;
+end|
+
+call bug4726()|
+call bug4726()|
+call bug4726()|
+
+drop procedure bug4726|
+drop table t3|
+
+#
+# BUG#4318
+#
+#QQ Don't know if HANDLER commands can work with SPs, or at all...
+#--disable_warnings
+#drop table if exists t3|
+#--enable_warnings
+#
+#create table t3 (s1 int)|
+#insert into t3 values (3), (4)|
+#
+#--disable_warnings
+#drop procedure if exists bug4318|
+#--enable_warnings
+#create procedure bug4318()
+# handler t3 read next|
+#
+#handler t3 open|
+## Expect no results, as tables are closed, but there shouldn't be any errors
+#call bug4318()|
+#call bug4318()|
+#handler t3 close|
+#
+#drop procedure bug4318|
+#drop table t3|
+
+#
+# BUG#4902: Stored procedure with SHOW WARNINGS leads to packet error
+#
+# Added tests for most other show commands we could find too.
+# (Skipping those already tested, and the ones depending on optional handlers.)
+#
+# Note: This will return a large number of results of different formats,
+# which makes it impossible to filter with --replace_column.
+# It's possible that some of these are not deterministic across
+# platforms. If so, just remove the offending command.
+#
+--disable_warnings
+drop procedure if exists bug4902|
+--enable_warnings
+create procedure bug4902()
+begin
+ show charset like 'foo';
+ show collation like 'foo';
+ show column types;
+ show create table t1;
+ show create database test;
+ show databases like 'foo';
+ show errors;
+ show columns from t1;
+ show grants for 'root'@'localhost';
+ show keys from t1;
+ show open tables like 'foo';
+ show privileges;
+ show status like 'foo';
+ show tables like 'foo';
+ show variables like 'foo';
+ show warnings;
+end|
+#show binlog events;
+#show storage engines;
+#show master status;
+#show slave hosts;
+#show slave status;
+
+call bug4902()|
+call bug4902()|
+
+drop procedure bug4902|
+
+# We need separate SP for SHOW PROCESSLIST since we want use replace_column
+--disable_warnings
+drop procedure if exists bug4902_2|
+--enable_warnings
+create procedure bug4902_2()
+begin
+ show processlist;
+end|
+--replace_column 1 # 6 #
+call bug4902_2()|
+--replace_column 1 # 6 #
+call bug4902_2()|
+drop procedure bug4902_2|
+
+#
+# BUG#4904
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+
+--disable_warnings
+drop procedure if exists bug4904|
+--enable_warnings
+create procedure bug4904()
+begin
+ declare continue handler for sqlstate 'HY000' begin end;
+
+ create table t2 as select * from t3;
+end|
+
+-- error 1146
+call bug4904()|
+
+drop procedure bug4904|
+
+create table t3 (s1 char character set latin1, s2 char character set latin2)|
+
+--disable_warnings
+drop procedure if exists bug4904|
+--enable_warnings
+create procedure bug4904 ()
+begin
+ declare continue handler for sqlstate 'HY000' begin end;
+
+ select s1 from t3 union select s2 from t3;
+end|
+
+call bug4904()|
+
+drop procedure bug4904|
+drop table t3|
+
+#
+# BUG#336
+#
+--disable_warnings
+drop procedure if exists bug336|
+--enable_warnings
+create procedure bug336(out y int)
+begin
+ declare x int;
+ set x = (select sum(t.data) from test.t1 t);
+ set y = x;
+end|
+
+insert into t1 values ("a", 2), ("b", 3)|
+call bug336(@y)|
+select @y|
+delete from t1|
+drop procedure bug336|
+
+#
+# BUG#3157
+#
+--disable_warnings
+drop procedure if exists bug3157|
+--enable_warnings
+create procedure bug3157()
+begin
+ if exists(select * from t1) then
+ set @n= @n + 1;
+ end if;
+ if (select count(*) from t1) then
+ set @n= @n + 1;
+ end if;
+end|
+
+set @n = 0|
+insert into t1 values ("a", 1)|
+call bug3157()|
+select @n|
+delete from t1|
+drop procedure bug3157|
+
+#
+# BUG#5251: mysql changes creation time of a procedure/function when altering
+#
+--disable_warnings
+drop procedure if exists bug5251|
+--enable_warnings
+create procedure bug5251()
+begin
+end|
+
+select created into @c1 from mysql.proc
+ where db='test' and name='bug5251'|
+--sleep 2
+alter procedure bug5251 comment 'foobar'|
+select count(*) from mysql.proc
+ where db='test' and name='bug5251' and created = @c1|
+
+drop procedure bug5251|
+
+#
+# BUG#5279: Stored procedure packets out of order if CHECKSUM TABLE
+#
+--disable_warnings
+drop procedure if exists bug5251|
+--enable_warnings
+create procedure bug5251()
+ checksum table t1|
+
+call bug5251()|
+call bug5251()|
+drop procedure bug5251|
+
+#
+# BUG#5287: Stored procedure crash if leave outside loop
+#
+--disable_warnings
+drop procedure if exists bug5287|
+--enable_warnings
+create procedure bug5287(param1 int)
+label1:
+ begin
+ declare c cursor for select 5;
+
+ loop
+ if param1 >= 0 then
+ leave label1;
+ end if;
+ end loop;
+end|
+call bug5287(1)|
+drop procedure bug5287|
+
+
+#
+# BUG#5307: Stored procedure allows statement after BEGIN ... END
+#
+--disable_warnings
+drop procedure if exists bug5307|
+--enable_warnings
+create procedure bug5307()
+begin
+end; set @x = 3|
+
+call bug5307()|
+select @x|
+drop procedure bug5307|
+
+#
+# BUG#5258: Stored procedure modified date is 0000-00-00
+# (This was a design flaw)
+--disable_warnings
+drop procedure if exists bug5258|
+--enable_warnings
+create procedure bug5258()
+begin
+end|
+
+--disable_warnings
+drop procedure if exists bug5258_aux|
+--enable_warnings
+create procedure bug5258_aux()
+begin
+ declare c, m char(19);
+
+ select created,modified into c,m from mysql.proc where name = 'bug5258';
+ if c = m then
+ select 'Ok';
+ else
+ select c, m;
+ end if;
+end|
+
+call bug5258_aux()|
+
+drop procedure bug5258|
+drop procedure bug5258_aux|
+
+#
+# BUG#4487: Stored procedure connection aborted if uninitialized char
+#
+--disable_warnings
+drop function if exists bug4487|
+--enable_warnings
+create function bug4487() returns char
+begin
+ declare v char;
+ return v;
+end|
+
+select bug4487()|
+drop function bug4487|
+
+
+#
+# BUG#4941: Stored procedure crash fetching null value into variable.
+#
+--disable_warnings
+drop procedure if exists bug4941|
+--enable_warnings
+--disable_warnings
+drop procedure if exists bug4941|
+--enable_warnings
+create procedure bug4941(out x int)
+begin
+ declare c cursor for select i from t2 limit 1;
+ open c;
+ fetch c into x;
+ close c;
+end|
+
+insert into t2 values (null, null, null)|
+set @x = 42|
+call bug4941(@x)|
+select @x|
+delete from t1|
+drop procedure bug4941|
+
+
+#
+# BUG#3583: query cache doesn't work for stored procedures
+#
+--disable_warnings
+drop procedure if exists bug3583|
+--enable_warnings
+--disable_warnings
+drop procedure if exists bug3583|
+--enable_warnings
+create procedure bug3583()
+begin
+ declare c int;
+
+ select * from t1;
+ select count(*) into c from t1;
+ select c;
+end|
+
+insert into t1 values ("x", 3), ("y", 5)|
+set @x = @@query_cache_size|
+set global query_cache_size = 10*1024*1024|
+
+flush status|
+flush query cache|
+show status like 'Qcache_hits'|
+call bug3583()|
+show status like 'Qcache_hits'|
+call bug3583()|
+call bug3583()|
+show status like 'Qcache_hits'|
+
+set global query_cache_size = @x|
+flush status|
+flush query cache|
+delete from t1|
+drop procedure bug3583|
+
+#
+# BUG#4905: Stored procedure doesn't clear for "Rows affected"
+#
+--disable_warnings
+drop table if exists t3|
+drop procedure if exists bug4905|
+--enable_warnings
+
+create table t3 (s1 int,primary key (s1))|
+
+--disable_warnings
+drop procedure if exists bug4905|
+--enable_warnings
+create procedure bug4905()
+begin
+ declare v int;
+ declare continue handler for sqlstate '23000' set v = 5;
+
+ insert into t3 values (1);
+end|
+
+call bug4905()|
+select row_count()|
+call bug4905()|
+select row_count()|
+call bug4905()|
+select row_count()|
+select * from t3|
+
+drop procedure bug4905|
+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|
+
+#
+# BUG#6029: Stored procedure specific handlers should have priority
+#
+--disable_warnings
+drop procedure if exists bug6029|
+--enable_warnings
+
+--disable_warnings
+drop procedure if exists bug6029|
+--enable_warnings
+create procedure bug6029()
+begin
+ declare exit handler for 1136 select '1136';
+ declare exit handler for sqlstate '23000' select 'sqlstate 23000';
+ declare continue handler for sqlexception select 'sqlexception';
+
+ insert into t3 values (1);
+ insert into t3 values (1,2);
+end|
+
+create table t3 (s1 int, primary key (s1))|
+insert into t3 values (1)|
+call bug6029()|
+delete from t3|
+call bug6029()|
+
+drop procedure bug6029|
+drop table t3|
+
+#
+# BUG#8540: Local variable overrides an alias
+#
+--disable_warnings
+drop procedure if exists bug8540|
+--enable_warnings
+
+create procedure bug8540()
+begin
+ declare x int default 1;
+ select x as y, x+0 as z;
+end|
+
+call bug8540()|
+drop procedure bug8540|
+
+#
+# BUG#6642: Stored procedure crash if expression with set function
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 (s1 int)|
+
+--disable_warnings
+drop procedure if exists bug6642|
+--enable_warnings
+
+create procedure bug6642()
+ select abs(count(s1)) from t3|
+
+call bug6642()|
+call bug6642()|
+drop procedure bug6642|
+
+#
+# BUG#7013: Stored procedure crash if group by ... with rollup
+#
+insert into t3 values (0),(1)|
+--disable_warnings
+drop procedure if exists bug7013|
+--enable_warnings
+create procedure bug7013()
+ select s1,count(s1) from t3 group by s1 with rollup|
+call bug7013()|
+call bug7013()|
+drop procedure bug7013|
+
+#
+# BUG#7743: 'Lost connection to MySQL server during query' on Stored Procedure
+#
+--disable_warnings
+drop table if exists t4|
+--enable_warnings
+create table t4 (
+ a mediumint(8) unsigned not null auto_increment,
+ b smallint(5) unsigned not null,
+ c char(32) not null,
+ primary key (a)
+) engine=myisam default charset=latin1|
+insert into t4 values (1, 2, 'oneword')|
+insert into t4 values (2, 2, 'anotherword')|
+
+--disable_warnings
+drop procedure if exists bug7743|
+--enable_warnings
+create procedure bug7743 ( searchstring char(28) )
+begin
+ declare var mediumint(8) unsigned;
+ select a into var from t4 where b = 2 and c = binary searchstring limit 1;
+ select var;
+end|
+
+call bug7743("oneword")|
+call bug7743("OneWord")|
+call bug7743("anotherword")|
+call bug7743("AnotherWord")|
+drop procedure bug7743|
+drop table t4|
+
+#
+# BUG#7992: SELECT .. INTO variable .. within Stored Procedure crashes
+# the server
+#
+delete from t3|
+insert into t3 values(1)|
+drop procedure if exists bug7992_1|
+drop procedure if exists bug7992_2|
+create procedure bug7992_1()
+begin
+ declare i int;
+ select max(s1)+1 into i from t3;
+end|
+create procedure bug7992_2()
+ insert into t3 (s1) select max(t4.s1)+1 from t3 as t4|
+
+call bug7992_1()|
+call bug7992_1()|
+call bug7992_2()|
+call bug7992_2()|
+
+drop procedure bug7992_1|
+drop procedure bug7992_2|
+drop table t3|
+
+#
+# BUG#8116: calling simple stored procedure twice in a row results
+# in server crash
+#
+--disable_warnings
+drop table if exists t3|
+--enable_warnings
+create table t3 ( userid bigint(20) not null default 0 )|
+
+--disable_warnings
+drop procedure if exists bug8116|
+--enable_warnings
+create procedure bug8116(in _userid int)
+ select * from t3 where userid = _userid|
+
+call bug8116(42)|
+call bug8116(42)|
+drop procedure bug8116|
+drop table t3|
+
+#
+# BUG#6857: current_time() in STORED PROCEDURES
+#
+--disable_warnings
+drop procedure if exists bug6857|
+--enable_warnings
+create procedure bug6857(counter int)
+begin
+ declare t0, t1 int;
+ declare plus bool default 0;
+
+ set t0 = current_time();
+ while counter > 0 do
+ set counter = counter - 1;
+ end while;
+ set t1 = current_time();
+ if t1 > t0 then
+ set plus = 1;
+ end if;
+ select plus;
+end|
+
+# QQ: This is currently disabled. Not only does it slow down a normal test
+# run, it makes running with valgrind (or similar tools) extremely
+# painful.
+# Make sure this takes at least one second on all machines in all builds.
+# 30000 makes it about 3 seconds on an old 1.1GHz linux.
+#call bug6857(300000)|
+
+drop procedure bug6857|
+
+#
+# BUG#8757: Stored Procedures: Scope of Begin and End Statements do not
+# work properly.
+--disable_warnings
+drop procedure if exists bug8757|
+--enable_warnings
+create procedure bug8757()
+begin
+ declare x int;
+ declare c1 cursor for select data from t1 limit 1;
+
+ begin
+ declare y int;
+ declare c2 cursor for select i from t2 limit 1;
+
+ open c2;
+ fetch c2 into y;
+ close c2;
+ select 2,y;
+ end;
+ open c1;
+ fetch c1 into x;
+ close c1;
+ select 1,x;
+end|
+
+delete from t1|
+delete from t2|
+insert into t1 values ("x", 1)|
+insert into t2 values ("y", 2, 0.0)|
+
+call bug8757()|
+
+delete from t1|
+delete from t2|
+drop procedure bug8757|
+
+
+#
+# BUG#8762: Stored Procedures: Inconsistent behavior
+# of DROP PROCEDURE IF EXISTS statement.
+--disable_warnings
+drop procedure if exists bug8762|
+--enable_warnings
+# Doesn't exist
+drop procedure if exists bug8762; create procedure bug8762() begin end|
+# Does exist
+drop procedure if exists bug8762; create procedure bug8762() begin end|
+drop procedure bug8762|
+
+
+#
+# BUG#5240: Stored procedure crash if function has cursor declaration
+#
+# The following test case fails in --ps-protocol mode due to some bugs
+# in algorithm which calculates list of tables to be locked for queries
+# using Stored Functions. It is disabled until Dmitri fixes this.
+#
+--disable_ps_protocol
+
+--disable_warnings
+drop function if exists bug5240|
+--enable_warnings
+create function bug5240 () returns int
+begin
+ declare x int;
+ declare c cursor for select data from t1 limit 1;
+
+ open c;
+ fetch c into x;
+ close c;
+ return x;
+end|
+
+delete from t1|
+insert into t1 values ("answer", 42)|
+select id, bug5240() from t1|
+drop function bug5240|
+
+--enable_ps_protocol
+
+#
+# BUG#5278: Stored procedure packets out of order if SET PASSWORD.
+#
+--disable_warnings
+drop function if exists bug5278|
+--enable_warnings
+create function bug5278 () returns char
+begin
+ SET PASSWORD FOR 'bob'@'%.loc.gov' = PASSWORD('newpass');
+ return 'okay';
+end|
+
+--error 1133
+select bug5278()|
+--error 1133
+select bug5278()|
+drop function bug5278|
+
+#
+# BUG#7992: rolling back temporary Item tree changes in SP
+#
+--disable_warnings
+drop procedure if exists p1|
+--enable_warnings
+create table t3(id int)|
+insert into t3 values(1)|
+create procedure bug7992()
+begin
+ declare i int;
+ select max(id)+1 into i from t3;
+end|
+
+call bug7992()|
+call bug7992()|
+drop procedure bug7992|
+drop table t3|
+delimiter ;|
+
+#
+# BUG#8849: problem with insert statement with table alias's
+#
+# Rolling back changes to AND/OR structure of ON and WHERE clauses in SP
+#
+
+delimiter |;
+create table t3 (
+ lpitnumber int(11) default null,
+ lrecordtype int(11) default null
+)|
+
+create table t4 (
+ lbsiid int(11) not null default '0',
+ ltradingmodeid int(11) not null default '0',
+ ltradingareaid int(11) not null default '0',
+ csellingprice decimal(19,4) default null,
+ primary key (lbsiid,ltradingmodeid,ltradingareaid)
+)|
+
+create table t5 (
+ lbsiid int(11) not null default '0',
+ ltradingareaid int(11) not null default '0',
+ primary key (lbsiid,ltradingareaid)
+)|
+
+--disable_warnings
+drop procedure if exists bug8849|
+--enable_warnings
+create procedure bug8849()
+begin
+ insert into t5
+ (
+ t5.lbsiid,
+ t5.ltradingareaid
+ )
+ select distinct t3.lpitnumber, t4.ltradingareaid
+ from
+ t4 join t3 on
+ t3.lpitnumber = t4.lbsiid
+ and t3.lrecordtype = 1
+ left join t4 as price01 on
+ price01.lbsiid = t4.lbsiid and
+ price01.ltradingmodeid = 1 and
+ t4.ltradingareaid = price01.ltradingareaid;
+end|
+
+call bug8849()|
+call bug8849()|
+call bug8849()|
+drop procedure bug8849|
+drop tables t3,t4,t5|
+
+#
+# BUG#8937: Stored Procedure: AVG() works as SUM() in SELECT ... INTO statement
+#
+--disable_warnings
+drop procedure if exists bug8937|
+--enable_warnings
+create procedure bug8937()
+begin
+ declare s,x,y,z int;
+ declare a float;
+
+ select sum(data),avg(data),min(data),max(data) into s,x,y,z from t1;
+ select s,x,y,z;
+ select avg(data) into a from t1;
+ select a;
+end|
+
+delete from t1|
+insert into t1 (data) values (1), (2), (3), (4), (6)|
+call bug8937()|
+
+drop procedure bug8937|
+delete from t1|
+
+
+#
+# BUG#6900: Stored procedure inner handler ignored
+# BUG#9074: STORED PROC: The scope of every handler declared is not
+# properly applied
+#
+--disable_warnings
+drop procedure if exists bug6900|
+drop procedure if exists bug9074|
+drop procedure if exists bug6900_9074|
+drop table if exists t3|
+--enable_warnings
+
+create table t3 (w char unique, x char)|
+insert into t3 values ('a', 'b')|
+
+create procedure bug6900()
+begin
+ declare exit handler for sqlexception select '1';
+
+ begin
+ declare exit handler for sqlexception select '2';
+
+ insert into t3 values ('x', 'y', 'z');
+ end;
+end|
+
+create procedure bug9074()
+begin
+ declare x1, x2, x3, x4, x5, x6 int default 0;
+
+ begin
+ declare continue handler for sqlstate '23000' set x5 = 1;
+
+ insert into t3 values ('a', 'b');
+ set x6 = 1;
+ end;
+
+ begin1_label:
+ begin
+ declare continue handler for sqlstate '23000' set x1 = 1;
+
+ insert into t3 values ('a', 'b');
+ set x2 = 1;
+
+ begin2_label:
+ begin
+ declare exit handler for sqlstate '23000' set x3 = 1;
+
+ set x4= 1;
+ insert into t3 values ('a','b');
+ set x4= 0;
+ end begin2_label;
+ end begin1_label;
+
+ select x1, x2, x3, x4, x5, x6;
+end|
+
+create procedure bug6900_9074(z int)
+begin
+ declare exit handler for sqlstate '23000' select '23000';
+
+ begin
+ declare exit handler for sqlexception select 'sqlexception';
+
+ if z = 1 then
+ insert into t3 values ('a', 'b');
+ else
+ insert into t3 values ('x', 'y', 'z');
+ end if;
+ end;
+end|
+
+call bug6900()|
+call bug9074()|
+call bug6900_9074(0)|
+call bug6900_9074(1)|
+
+drop procedure bug6900|
+drop procedure bug9074|
+drop procedure bug6900_9074|
+drop table t3|
+
+
+#
+# BUG#7185: Stored procedure crash if identifier is AVG
+#
+--disable_warnings
+drop procedure if exists avg|
+--enable_warnings
+create procedure avg ()
+begin
+end|
+
+call avg ()|
+drop procedure avg|
+
+
+#
+# BUG#6129: Stored procedure won't display @@sql_mode value
+#
+--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)|
+
+drop procedure bug6129|
+
+
+#
+# BUG#9856: Stored procedures: crash if handler for sqlexception, not found
+#
+--disable_warnings
+drop procedure if exists bug9856|
+--enable_warnings
+create procedure bug9856()
+begin
+ declare v int;
+ declare c cursor for select data from t1;
+ declare exit handler for sqlexception, not found select '16';
+
+ open c;
+ fetch c into v;
+ select v;
+end|
+
+delete from t1|
+call bug9856()|
+call bug9856()|
+drop procedure bug9856|
+
+
+#
+# BUG##9674: Stored Procs: Using declared vars in algebric operation causes
+# system crash.
+#
+--disable_warnings
+drop procedure if exists bug9674_1|
+drop procedure if exists bug9674_2|
+--enable_warnings
+create procedure bug9674_1(out arg int)
+begin
+ declare temp_in1 int default 0;
+ declare temp_fl1 int default 0;
+
+ set temp_in1 = 100;
+ set temp_fl1 = temp_in1/10;
+ set arg = temp_fl1;
+end|
+
+create procedure bug9674_2()
+begin
+ declare v int default 100;
+
+ select v/10;
+end|
+
+call bug9674_1(@sptmp)|
+call bug9674_1(@sptmp)|
+select @sptmp|
+call bug9674_2()|
+call bug9674_2()|
+drop procedure bug9674_1|
+drop procedure bug9674_2|
+
+
+#
+# BUG#9598: stored procedure call within stored procedure overwrites IN variable
+#
+--disable_warnings
+drop procedure if exists bug9598_1|
+drop procedure if exists bug9598_2|
+--enable_warnings
+create procedure bug9598_1(in var_1 char(16),
+ out var_2 integer, out var_3 integer)
+begin
+ set var_2 = 50;
+ set var_3 = 60;
+end|
+
+create procedure bug9598_2(in v1 char(16),
+ in v2 integer,
+ in v3 integer,
+ in v4 integer,
+ in v5 integer)
+begin
+ select v1,v2,v3,v4,v5;
+ call bug9598_1(v1,@tmp1,@tmp2);
+ select v1,v2,v3,v4,v5;
+end|
+
+call bug9598_2('Test',2,3,4,5)|
+select @tmp1, @tmp2|
+
+drop procedure bug9598_1|
+drop procedure bug9598_2|
+
+
+#
+# BUG#9902: Crash with simple stored function using user defined variables
+#
+--disable_warnings
+drop procedure if exists bug9902|
+--enable_warnings
+create function bug9902() returns int(11)
+begin
+ set @x = @x + 1;
+ return @x;
+end|
+
+set @qcs1 = @@query_cache_size|
+set global query_cache_size = 100000|
+set @x = 1|
+insert into t1 values ("qc", 42)|
+select bug9902() from t1|
+select bug9902() from t1|
+select @x|
+
+set global query_cache_size = @qcs1|
+delete from t1|
+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
+drop function if exists bug9102|
+--enable_warnings
+create function bug9102() returns blob return 'a'|
+select bug9102()|
+drop function bug9102|
+
+
+#
+# BUG#7648: Stored procedure crash when invoking a function that returns a bit
+#
+--disable_warnings
+drop function if exists bug7648|
+--enable_warnings
+create function bug7648() returns bit(8) return 'a'|
+select bug7648()|
+drop function bug7648|
+
+
+#
+# BUG#9775: crash if create function that returns enum or set
+#
+--disable_warnings
+drop function if exists bug9775|
+--enable_warnings
+create function bug9775(v1 char(1)) returns enum('a','b') return v1|
+select bug9775('a'),bug9775('b'),bug9775('c')|
+drop function bug9775|
+create function bug9775(v1 int) returns enum('a','b') return v1|
+select bug9775(1),bug9775(2),bug9775(3)|
+drop function bug9775|
+
+create function bug9775(v1 char(1)) returns set('a','b') return v1|
+select bug9775('a'),bug9775('b'),bug9775('a,b'),bug9775('c')|
+drop function bug9775|
+create function bug9775(v1 int) returns set('a','b') return v1|
+select bug9775(1),bug9775(2),bug9775(3),bug9775(4)|
+drop function bug9775|
+
+
+#
+# BUG#8861: If Return is a YEAR data type, value is not shown in year format
+#
+--disable_warnings
+drop function if exists bug8861|
+--enable_warnings
+create function bug8861(v1 int) returns year return v1|
+select bug8861(05)|
+set @x = bug8861(05)|
+select @x|
+drop function bug8861|
+
+
+#
+# BUG#9004: Inconsistent behaviour of SP re. warnings
+#
+--disable_warnings
+drop procedure if exists bug9004_1|
+drop procedure if exists bug9004_2|
+--enable_warnings
+create procedure bug9004_1(x char(16))
+begin
+ insert into t1 values (x, 42);
+ insert into t1 values (x, 17);
+end|
+create procedure bug9004_2(x char(16))
+ call bug9004_1(x)|
+
+# Truncation warnings expected...
+call bug9004_1('12345678901234567')|
+call bug9004_2('12345678901234567890')|
+
+delete from t1|
+drop procedure bug9004_1|
+drop procedure bug9004_2|
+
+
+#
+# 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, t3 etc temporarily (and drop them).
+delimiter ;|
+drop table t1,t2;
+
diff --git a/mysql-test/t/sp_trans.test b/mysql-test/t/sp_trans.test
new file mode 100644
index 00000000000..f5b38ada674
--- /dev/null
+++ b/mysql-test/t/sp_trans.test
@@ -0,0 +1,46 @@
+#
+# tests that require InnoDB...
+#
+
+-- source include/have_innodb.inc
+
+delimiter |;
+
+#
+# BUG#8850: Truncate table in a stored procedure locks the tables
+#
+--disable_warnings
+drop procedure if exists bug8850|
+--enable_warnings
+create table t1 (a int) engine=innodb|
+create procedure bug8850()
+begin
+ truncate table t1; insert t1 values (1); rollback;
+end|
+
+set autocommit=0|
+insert t1 values (2)|
+--error 1192
+call bug8850()|
+commit|
+select * from t1|
+#
+# when CALL will be fixed to not start a transaction, the error should
+# go away
+--error 1192
+call bug8850()|
+set autocommit=1|
+select * from t1|
+drop table t1|
+drop procedure bug8850|
+
+
+#
+# BUG#NNNN: New bug synopsis
+#
+#--disable_warnings
+#drop procedure if exists bugNNNN|
+#--enable_warnings
+#create procedure bugNNNN...
+
+delimiter ;|
diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test
index f841d36e837..e80752eb71b 100644
--- a/mysql-test/t/sql_mode.test
+++ b/mysql-test/t/sql_mode.test
@@ -80,3 +80,108 @@ create table t1 ( min_num dec(6,6) default .000001);
show create table t1;
drop table t1 ;
+
+#
+# test for
+# WL 1941 "NO_C_ESCAPES sql_mode"
+#
+# an sql_mode to disable \n, \r, \b, etc escapes in string literals. actually, to
+# disable special meaning of backslash completely. It's not in the SQL standard
+# and it causes some R/3 tests to fail.
+#
+
+SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE='';
+show local variables like 'SQL_MODE';
+
+CREATE TABLE t1 (p int not null auto_increment, a varchar(20), primary key(p));
+INSERT t1 (a) VALUES
+('\\'),
+('\n'),
+('\b'),
+('\r'),
+('\t'),
+('\x'),
+('\a'),
+('\aa'),
+('\\a'),
+('\\aa'),
+('_'),
+('\_'),
+('\\_'),
+('\\\_'),
+('\\\\_'),
+('%'),
+('\%'),
+('\\%'),
+('\\\%'),
+('\\\\%')
+;
+
+SELECT p, hex(a) FROM t1;
+
+delete from t1 where a in ('\n','\r','\t', '\b');
+
+select
+ masks.p,
+ masks.a as mask,
+ examples.a as example
+from
+ t1 as masks
+ left join t1 as examples on examples.a LIKE masks.a
+order by masks.p, example;
+
+DROP TABLE t1;
+
+SET @@SQL_MODE='NO_BACKSLASH_ESCAPES';
+show local variables like 'SQL_MODE';
+
+CREATE TABLE t1 (p int not null auto_increment, a varchar(20), primary key(p));
+INSERT t1 (a) VALUES
+('\\'),
+('\n'),
+('\b'),
+('\r'),
+('\t'),
+('\x'),
+('\a'),
+('\aa'),
+('\\a'),
+('\\aa'),
+('_'),
+('\_'),
+('\\_'),
+('\\\_'),
+('\\\\_'),
+('%'),
+('\%'),
+('\\%'),
+('\\\%'),
+('\\\\%')
+;
+
+SELECT p, hex(a) FROM t1;
+
+delete from t1 where a in ('\n','\r','\t', '\b');
+
+select
+ masks.p,
+ masks.a as mask,
+ examples.a as example
+from
+ t1 as masks
+ left join t1 as examples on examples.a LIKE masks.a
+order by masks.p, example;
+
+DROP TABLE t1;
+
+# Bug #6368: Make sure backslashes mixed with doubled quotes are handled
+# correctly in NO_BACKSLASH_ESCAPES mode
+SET @@SQL_MODE='NO_BACKSLASH_ESCAPES';
+SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b';
+SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b";
+
+SET @@SQL_MODE='';
+SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b';
+SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b";
+
+SET @@SQL_MODE=@OLD_SQL_MODE;
diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test
new file mode 100644
index 00000000000..333ec40b1b9
--- /dev/null
+++ b/mysql-test/t/strict.test
@@ -0,0 +1,1085 @@
+# Testing of "strict" mode
+
+-- source include/have_innodb.inc
+
+set @org_mode=@@sql_mode;
+set @@sql_mode='ansi,traditional';
+select @@sql_mode;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# Test INSERT with DATE
+
+CREATE TABLE t1 (col1 date);
+INSERT INTO t1 VALUES('2004-01-01'),('0000-10-31'),('2004-02-29');
+
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid date value>
+--error 1292
+INSERT INTO t1 VALUES('2004-0-31');
+--error 1292
+INSERT INTO t1 VALUES('2004-01-02'),('2004-0-31');
+--error 1292
+INSERT INTO t1 VALUES('2004-10-0');
+--error 1292
+INSERT INTO t1 VALUES('2004-09-31');
+--error 1292
+INSERT INTO t1 VALUES('2004-10-32');
+--error 1292
+INSERT INTO t1 VALUES('2003-02-29');
+--error 1292
+INSERT INTO t1 VALUES('2004-13-15');
+--error 1292
+INSERT INTO t1 VALUES('0000-00-00');
+# Standard says we should return SQLSTATE 22018
+--error 1292
+INSERT INTO t1 VALUES ('59');
+
+# Test the different related modes
+set @@sql_mode='STRICT_ALL_TABLES';
+INSERT INTO t1 VALUES('2004-01-03'),('2004-0-31');
+set @@sql_mode='STRICT_ALL_TABLES,NO_ZERO_IN_DATE';
+--error 1292
+INSERT INTO t1 VALUES('2004-0-30');
+--error 1292
+INSERT INTO t1 VALUES('2004-01-04'),('2004-0-31'),('2004-01-05');
+INSERT INTO t1 VALUES('0000-00-00');
+INSERT IGNORE INTO t1 VALUES('2004-0-29');
+set @@sql_mode='STRICT_ALL_TABLES,NO_ZERO_DATE';
+--error 1292
+INSERT INTO t1 VALUES('0000-00-00');
+INSERT IGNORE INTO t1 VALUES('0000-00-00');
+INSERT INTO t1 VALUES ('2004-0-30');
+--error 1292
+INSERT INTO t1 VALUES ('2004-2-30');
+set @@sql_mode='STRICT_ALL_TABLES,ALLOW_INVALID_DATES';
+INSERT INTO t1 VALUES ('2004-2-30');
+set @@sql_mode='ansi,traditional';
+INSERT IGNORE INTO t1 VALUES('2004-02-29'),('2004-13-15'),('0000-00-00');
+
+select * from t1;
+drop table t1;
+
+# Test difference in behaviour with InnoDB and MyISAM tables
+
+set @@sql_mode='strict_trans_tables';
+CREATE TABLE t1 (col1 date) engine=myisam;
+--error 1292
+INSERT INTO t1 VALUES('2004-13-31'),('2004-1-1');
+INSERT INTO t1 VALUES ('2004-1-2'), ('2004-13-31'),('2004-1-3');
+INSERT IGNORE INTO t1 VALUES('2004-13-31'),('2004-1-4');
+--error 1292
+INSERT INTO t1 VALUES ('2003-02-29');
+INSERT ignore INTO t1 VALUES('2003-02-30');
+set @@sql_mode='STRICT_ALL_TABLES,ALLOW_INVALID_DATES';
+INSERT ignore INTO t1 VALUES('2003-02-31');
+select * from t1;
+drop table t1;
+
+set @@sql_mode='strict_trans_tables';
+CREATE TABLE t1 (col1 date) engine=innodb;
+--error 1292
+INSERT INTO t1 VALUES('2004-13-31'),('2004-1-1');
+--error 1292
+INSERT INTO t1 VALUES ('2004-1-2'), ('2004-13-31'),('2004-1-3');
+INSERT IGNORE INTO t1 VALUES('2004-13-31'),('2004-1-4');
+--error 1292
+INSERT INTO t1 VALUES ('2003-02-29');
+INSERT ignore INTO t1 VALUES('2003-02-30');
+set @@sql_mode='STRICT_ALL_TABLES,ALLOW_INVALID_DATES';
+INSERT ignore INTO t1 VALUES('2003-02-31');
+select * from t1;
+drop table t1;
+set @@sql_mode='ansi,traditional';
+
+# Test INSERT with DATETIME
+
+CREATE TABLE t1 (col1 datetime);
+INSERT INTO t1 VALUES('2004-10-31 15:30:00'),('0000-10-31 15:30:00'),('2004-02-29 15:30:00');
+
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid datetime value>
+--error 1292
+INSERT INTO t1 VALUES('2004-0-31 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-10-0 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-09-31 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-10-32 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2003-02-29 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-13-15 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('0000-00-00 15:30:00');
+# Standard says we should return SQLSTATE 22018
+--error 1292
+INSERT INTO t1 VALUES ('59');
+select * from t1;
+drop table t1;
+
+# Test INSERT with TIMESTAMP
+
+CREATE TABLE t1 (col1 timestamp);
+INSERT INTO t1 VALUES('2004-10-31 15:30:00'),('2004-02-29 15:30:00');
+
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid datetime value>
+# Standard says we should return ok, but we can't as this is out of range
+--error 1292
+INSERT INTO t1 VALUES('0000-10-31 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-0-31 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-10-0 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-09-31 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-10-32 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2003-02-29 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-13-15 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-02-29 25:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-02-29 15:65:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-02-29 15:31:61');
+--error 1292
+INSERT INTO t1 VALUES('0000-00-00 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('0000-00-00 00:00:00');
+INSERT IGNORE INTO t1 VALUES('0000-00-00 00:00:00');
+# Standard says we should return SQLSTATE 22018
+--error 1292
+INSERT INTO t1 VALUES ('59');
+
+set @@sql_mode='STRICT_ALL_TABLES,ALLOW_INVALID_DATES';
+--error 1292
+INSERT INTO t1 VALUES('2004-0-31 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-10-0 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-10-32 15:30:00');
+--error 1292
+INSERT INTO t1 VALUES('2004-02-30 15:30:04');
+INSERT INTO t1 VALUES('0000-00-00 00:00:00');
+set @@sql_mode='STRICT_ALL_TABLES,NO_ZERO_IN_DATE';
+INSERT INTO t1 VALUES('0000-00-00 00:00:00');
+set @@sql_mode='STRICT_ALL_TABLES,NO_ZERO_DATE';
+--error 1292
+INSERT INTO t1 VALUES('0000-00-00 00:00:00');
+set @@sql_mode='ansi,traditional';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+#### Test INSERT with STR_TO_DATE into DATE/DATETIME/TIMESTAMP
+
+CREATE TABLE t1 (col1 date, col2 datetime, col3 timestamp);
+
+INSERT INTO t1 (col1) VALUES (STR_TO_DATE('15.10.2004','%d.%m.%Y'));
+INSERT INTO t1 (col2) VALUES (STR_TO_DATE('15.10.2004 10.15','%d.%m.%Y %H.%i'));
+INSERT INTO t1 (col3) VALUES (STR_TO_DATE('15.10.2004 10.15','%d.%m.%Y %H.%i'));
+
+## Test INSERT with STR_TO_DATE into DATE
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid date value>
+
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('31.10.0000 15.30','%d.%m.%Y %H.%i'));
+
+--error 1292
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('31.0.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('0.10.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('31.9.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1411
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('29.02.2003 15.30','%d.%m.%Y %H.%i'));
+--error 1411
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('15.13.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col1) VALUES(STR_TO_DATE('00.00.0000','%d.%m.%Y'));
+
+## Test INSERT with STR_TO_DATE into DATETIME
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid datetime value>
+
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('31.10.0000 15.30','%d.%m.%Y %H.%i'));
+
+--error 1292
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('31.0.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('0.10.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('31.9.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1411
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('29.02.2003 15.30','%d.%m.%Y %H.%i'));
+--error 1411
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('15.13.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col2) VALUES(STR_TO_DATE('00.00.0000','%d.%m.%Y'));
+
+## Test INSERT with STR_TO_DATE into TIMESTAMP
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid datetime value>
+
+--error 1292
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('31.10.0000 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('31.0.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('0.10.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('31.9.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1411
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('29.02.2003 15.30','%d.%m.%Y %H.%i'));
+--error 1411
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('15.13.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1292
+INSERT INTO t1 (col3) VALUES(STR_TO_DATE('00.00.0000','%d.%m.%Y'));
+
+drop table t1;
+
+
+#### Test INSERT with CAST AS DATE/DATETIME into DATE/DATETIME/TIMESTAMP
+
+CREATE TABLE t1 (col1 date, col2 datetime, col3 timestamp);
+
+INSERT INTO t1 (col1) VALUES (CAST('2004-10-15' AS DATE));
+INSERT INTO t1 (col2) VALUES (CAST('2004-10-15 10:15' AS DATETIME));
+INSERT INTO t1 (col3) VALUES (CAST('2004-10-15 10:15' AS DATETIME));
+
+
+## Test INSERT with CAST AS DATE into DATE
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid date value>
+INSERT INTO t1 (col1) VALUES(CAST('0000-10-31' AS DATE));
+
+--error 1292
+INSERT INTO t1 (col1) VALUES(CAST('2004-10-0' AS DATE));
+--error 1292
+INSERT INTO t1 (col1) VALUES(CAST('2004-0-10' AS DATE));
+
+# deactivated because of Bug#8294
+# Bug#8294 Traditional: Misleading error message for invalid CAST to DATE
+# --error 1292
+# INSERT INTO t1 (col1) VALUES(CAST('2004-9-31' AS DATE));
+# --error 1292
+# INSERT INTO t1 (col1) VALUES(CAST('2004-10-32' AS DATE));
+# --error 1292
+# INSERT INTO t1 (col1) VALUES(CAST('2003-02-29' AS DATE));
+# --error 1292
+# INSERT INTO t1 (col1) VALUES(CAST('2004-13-15' AS DATE));
+
+# deactivated because of Bug#6145
+# Bug#6145: Traditional: CONVERT and CAST should reject zero DATE values
+--error 1292
+INSERT INTO t1 (col1) VALUES(CAST('0000-00-00' AS DATE));
+
+## Test INSERT with CAST AS DATETIME into DATETIME
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid datetime value>
+INSERT INTO t1 (col2) VALUES(CAST('0000-10-31 15:30' AS DATETIME));
+
+--error 1292
+INSERT INTO t1 (col2) VALUES(CAST('2004-10-0 15:30' AS DATETIME));
+--error 1292
+INSERT INTO t1 (col2) VALUES(CAST('2004-0-10 15:30' AS DATETIME));
+
+# deactivated because of Bug#8294
+# Bug#8294 Traditional: Misleading error message for invalid CAST to DATE
+#--error 1292
+#INSERT INTO t1 (col2) VALUES(CAST('2004-9-31 15:30' AS DATETIME));
+#--error 1292
+#INSERT INTO t1 (col2) VALUES(CAST('2004-10-32 15:30' AS DATETIME));
+#--error 1292
+#INSERT INTO t1 (col2) VALUES(CAST('2003-02-29 15:30' AS DATETIME));
+#--error 1292
+#INSERT INTO t1 (col2) VALUES(CAST('2004-13-15 15:30' AS DATETIME));
+
+# Bug#6145: Traditional: CONVERT and CAST should reject zero DATE values
+--error 1292
+INSERT INTO t1 (col2) VALUES(CAST('0000-00-00' AS DATETIME));
+
+## Test INSERT with CAST AS DATETIME into TIMESTAMP
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid datetime value>
+!$1292
+INSERT INTO t1 (col3) VALUES(CAST('0000-10-31 15:30' AS DATETIME));
+-- should return OK
+-- We accept this to be a failure
+
+--error 1292
+INSERT INTO t1 (col3) VALUES(CAST('2004-10-0 15:30' AS DATETIME));
+--error 1292
+INSERT INTO t1 (col3) VALUES(CAST('2004-0-10 15:30' AS DATETIME));
+-- should return SQLSTATE 22007 <invalid datetime value>
+
+# deactivated because of Bug#8294
+# Bug#8294 Traditional: Misleading error message for invalid CAST to DATE
+#--error 1292
+#INSERT INTO t1 (col3) VALUES(CAST('2004-9-31 15:30' AS DATETIME));
+#--error 1292
+#INSERT INTO t1 (col3) VALUES(CAST('2004-10-32 15:30' AS DATETIME));
+#--error 1292
+#INSERT INTO t1 (col3) VALUES(CAST('2003-02-29 15:30' AS DATETIME));
+#--error 1292
+#INSERT INTO t1 (col3) VALUES(CAST('2004-13-15 15:30' AS DATETIME));
+
+# Bug#6145: Traditional: CONVERT and CAST should reject zero DATE values
+--error 1292
+INSERT INTO t1 (col3) VALUES(CAST('0000-00-00' AS DATETIME));
+
+drop table t1;
+
+
+#### Test INSERT with CONVERT to DATE/DATETIME into DATE/DATETIME/TIMESTAMP
+
+CREATE TABLE t1 (col1 date, col2 datetime, col3 timestamp);
+
+INSERT INTO t1 (col1) VALUES (CONVERT('2004-10-15',DATE));
+INSERT INTO t1 (col2) VALUES (CONVERT('2004-10-15 10:15',DATETIME));
+INSERT INTO t1 (col3) VALUES (CONVERT('2004-10-15 10:15',DATETIME));
+
+
+## Test INSERT with CONVERT to DATE into DATE
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid date value>
+INSERT INTO t1 (col1) VALUES(CONVERT('0000-10-31' , DATE));
+
+--error 1292
+INSERT INTO t1 (col1) VALUES(CONVERT('2004-10-0' , DATE));
+--error 1292
+INSERT INTO t1 (col1) VALUES(CONVERT('2004-0-10' , DATE));
+
+# deactivated because of Bug#8294
+# Bug#8294 Traditional: Misleading error message for invalid CAST to DATE
+#--error 1292
+#INSERT INTO t1 (col1) VALUES(CONVERT('2004-9-31' , DATE));
+#--error 1292
+#INSERT INTO t1 (col1) VALUES(CONVERT('2004-10-32' , DATE));
+#--error 1292
+#INSERT INTO t1 (col1) VALUES(CONVERT('2003-02-29' , DATE));
+#--error 1292
+#INSERT INTO t1 (col1) VALUES(CONVERT('2004-13-15',DATE));
+
+# Bug#6145: Traditional: CONVERT and CAST should reject zero DATE values
+--error 1292
+INSERT INTO t1 (col1) VALUES(CONVERT('0000-00-00',DATE));
+
+## Test INSERT with CONVERT to DATETIME into DATETIME
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid datetime value>
+INSERT INTO t1 (col2) VALUES(CONVERT('0000-10-31 15:30',DATETIME));
+
+--error 1292
+INSERT INTO t1 (col2) VALUES(CONVERT('2004-10-0 15:30',DATETIME));
+--error 1292
+INSERT INTO t1 (col2) VALUES(CONVERT('2004-0-10 15:30',DATETIME));
+
+# deactivated because of Bug#8294
+# Bug#8294 Traditional: Misleading error message for invalid CAST to DATE
+#--error 1292
+#INSERT INTO t1 (col2) VALUES(CONVERT('2004-9-31 15:30',DATETIME));
+#--error 1292
+#INSERT INTO t1 (col2) VALUES(CONVERT('2004-10-32 15:30',DATETIME));
+#--error 1292
+#INSERT INTO t1 (col2) VALUES(CONVERT('2003-02-29 15:30',DATETIME));
+#--error 1292
+#INSERT INTO t1 (col2) VALUES(CONVERT('2004-13-15 15:30',DATETIME));
+
+# Bug#6145: Traditional: CONVERT and CAST should reject zero DATE values
+--error 1292
+INSERT INTO t1 (col2) VALUES(CONVERT('0000-00-00',DATETIME));
+
+## Test INSERT with CONVERT to DATETIME into DATETIME
+# All test cases expected to fail should return
+# SQLSTATE 22007 <invalid datetime value>
+!$1292
+INSERT INTO t1 (col3) VALUES(CONVERT('0000-10-31 15:30',DATETIME));
+-- should return OK
+-- We accept this to be a failure
+
+--error 1292
+INSERT INTO t1 (col3) VALUES(CONVERT('2004-10-0 15:30',DATETIME));
+--error 1292
+INSERT INTO t1 (col3) VALUES(CONVERT('2004-0-10 15:30',DATETIME));
+
+# deactivated because of Bug#8294
+# Bug#8294 Traditional: Misleading error message for invalid CAST to DATE
+#--error 1292
+#INSERT INTO t1 (col3) VALUES(CONVERT('2004-9-31 15:30',DATETIME));
+#--error 1292
+#INSERT INTO t1 (col3) VALUES(CONVERT('2004-10-32 15:30',DATETIME));
+#--error 1292
+#INSERT INTO t1 (col3) VALUES(CONVERT('2003-02-29 15:30',DATETIME));
+#--error 1292
+#INSERT INTO t1 (col3) VALUES(CONVERT('2004-13-15 15:30',DATETIME));
+
+# Bug#6145: Traditional: CONVERT and CAST should reject zero DATE values
+--error 1292
+INSERT INTO t1 (col3) VALUES(CONVERT('0000-00-00',DATETIME));
+
+drop table t1;
+
+
+# Test INSERT with TINYINT
+
+CREATE TABLE t1(col1 TINYINT, col2 TINYINT UNSIGNED);
+INSERT INTO t1 VALUES(-128,0),(0,0),(127,255),('-128','0'),('0','0'),('127','255'),(-128.0,0.0),(0.0,0.0),(127.0,255.0);
+# Test that we restored the mode checking properly after an ok query
+SELECT MOD(col1,0) FROM t1 WHERE col1 > 0 LIMIT 2;
+-- error 1264
+INSERT INTO t1 (col1) VALUES(-129);
+-- error 1264
+INSERT INTO t1 (col1) VALUES(128);
+-- error 1264
+INSERT INTO t1 (col2) VALUES(-1);
+-- error 1264
+INSERT INTO t1 (col2) VALUES(256);
+-- error 1264
+INSERT INTO t1 (col1) VALUES('-129');
+-- error 1264
+INSERT INTO t1 (col1) VALUES('128');
+-- error 1264
+INSERT INTO t1 (col2) VALUES('-1');
+-- error 1264
+INSERT INTO t1 (col2) VALUES('256');
+-- error 1264
+INSERT INTO t1 (col1) VALUES(128.0);
+-- error 1264
+INSERT INTO t1 (col2) VALUES(-1.0);
+-- error 1264
+INSERT INTO t1 (col2) VALUES(256.0);
+SELECT MOD(col1,0) FROM t1 WHERE col1 > 0 LIMIT 1;
+--error 1264
+UPDATE t1 SET col1 = col1 - 50 WHERE col1 < 0;
+--error 1264
+UPDATE t1 SET col2=col2 + 50 WHERE col2 > 0;
+--error 1365
+UPDATE t1 SET col1=col1 / 0 WHERE col1 > 0;
+set @@sql_mode='ERROR_FOR_DIVISION_BY_ZERO';
+INSERT INTO t1 values (1/0,1/0);
+set @@sql_mode='ansi,traditional';
+SELECT MOD(col1,0) FROM t1 WHERE col1 > 0 LIMIT 2;
+# Should return SQLSTATE 22018 invalid character value for cast
+--error 1366
+INSERT INTO t1 (col1) VALUES ('');
+--error 1366
+INSERT INTO t1 (col1) VALUES ('a59b');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('1a');
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+INSERT IGNORE INTO t1 values (1/0,1/0);
+set @@sql_mode='ansi';
+INSERT INTO t1 values (1/0,1/0);
+set @@sql_mode='ansi,traditional';
+INSERT IGNORE INTO t1 VALUES('-129','-1'),('128','256');
+INSERT IGNORE INTO t1 VALUES(-129.0,-1.0),(128.0,256.0);
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Test INSERT with SMALLINT
+
+CREATE TABLE t1(col1 SMALLINT, col2 SMALLINT UNSIGNED);
+INSERT INTO t1 VALUES(-32768,0),(0,0),(32767,65535),('-32768','0'),('32767','65535'),(-32768.0,0.0),(32767.0,65535.0);
+
+--error 1264
+INSERT INTO t1 (col1) VALUES(-32769);
+--error 1264
+INSERT INTO t1 (col1) VALUES(32768);
+--error 1264
+INSERT INTO t1 (col2) VALUES(-1);
+--error 1264
+INSERT INTO t1 (col2) VALUES(65536);
+--error 1264
+INSERT INTO t1 (col1) VALUES('-32769');
+--error 1264
+INSERT INTO t1 (col1) VALUES('32768');
+--error 1264
+INSERT INTO t1 (col2) VALUES('-1');
+--error 1264
+INSERT INTO t1 (col2) VALUES('65536');
+--error 1264
+INSERT INTO t1 (col1) VALUES(-32769.0);
+--error 1264
+INSERT INTO t1 (col1) VALUES(32768.0);
+--error 1264
+INSERT INTO t1 (col2) VALUES(-1.0);
+--error 1264
+INSERT INTO t1 (col2) VALUES(65536.0);
+--error 1264
+UPDATE t1 SET col1 = col1 - 50 WHERE col1 < 0;
+--error 1264
+UPDATE t1 SET col2 = col2 + 50 WHERE col2 > 0;
+--error 1365
+UPDATE t1 SET col1 = col1 / 0 WHERE col1 > 0;
+--error 1365
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+--error 1366
+INSERT INTO t1 (col1) VALUES ('');
+--error 1366
+INSERT INTO t1 (col1) VALUES ('a59b');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('1a');
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+INSERT IGNORE INTO t1 values (1/0,1/0);
+INSERT IGNORE INTO t1 VALUES(-32769,-1),(32768,65536);
+INSERT IGNORE INTO t1 VALUES('-32769','-1'),('32768','65536');
+INSERT IGNORE INTO t1 VALUES(-32769,-1.0),(32768.0,65536.0);
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Test INSERT with MEDIUMINT
+
+CREATE TABLE t1 (col1 MEDIUMINT, col2 MEDIUMINT UNSIGNED);
+INSERT INTO t1 VALUES(-8388608,0),(0,0),(8388607,16777215),('-8388608','0'),('8388607','16777215'),(-8388608.0,0.0),(8388607.0,16777215.0);
+--error 1264
+INSERT INTO t1 (col1) VALUES(-8388609);
+--error 1264
+INSERT INTO t1 (col1) VALUES(8388608);
+--error 1264
+INSERT INTO t1 (col2) VALUES(-1);
+--error 1264
+INSERT INTO t1 (col2) VALUES(16777216);
+--error 1264
+INSERT INTO t1 (col1) VALUES('-8388609');
+--error 1264
+INSERT INTO t1 (col1) VALUES('8388608');
+--error 1264
+INSERT INTO t1 (col2) VALUES('-1');
+--error 1264
+INSERT INTO t1 (col2) VALUES('16777216');
+--error 1264
+INSERT INTO t1 (col1) VALUES(-8388609.0);
+--error 1264
+INSERT INTO t1 (col1) VALUES(8388608.0);
+--error 1264
+INSERT INTO t1 (col2) VALUES(-1.0);
+--error 1264
+INSERT INTO t1 (col2) VALUES(16777216.0);
+
+--error 1264
+UPDATE t1 SET col1 = col1 - 50 WHERE col1 < 0;
+--error 1264
+UPDATE t1 SET col2 = col2 + 50 WHERE col2 > 0;
+--error 1365
+UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0;
+--error 1365
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+--error 1366
+INSERT INTO t1 (col1) VALUES ('');
+--error 1366
+INSERT INTO t1 (col1) VALUES ('a59b');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('1a');
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+INSERT IGNORE INTO t1 values (1/0,1/0);
+INSERT IGNORE INTO t1 VALUES(-8388609,-1),(8388608,16777216);
+INSERT IGNORE INTO t1 VALUES('-8388609','-1'),('8388608','16777216');
+INSERT IGNORE INTO t1 VALUES(-8388609.0,-1.0),(8388608.0,16777216.0);
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Test INSERT with INT
+
+CREATE TABLE t1 (col1 INT, col2 INT UNSIGNED);
+INSERT INTO t1 VALUES(-2147483648,0),(0,0),(2147483647,4294967295),('-2147483648','0'),('2147483647','4294967295'),(-2147483648.0,0.0),(2147483647.0,4294967295.0);
+--error 1264
+INSERT INTO t1 (col1) VALUES(-2147483649);
+--error 1264
+INSERT INTO t1 (col1) VALUES(2147643648);
+--error 1264
+INSERT INTO t1 (col2) VALUES(-1);
+--error 1264
+INSERT INTO t1 (col2) VALUES(4294967296);
+--error 1264
+INSERT INTO t1 (col1) VALUES('-2147483649');
+--error 1264
+INSERT INTO t1 (col1) VALUES('2147643648');
+--error 1264
+INSERT INTO t1 (col2) VALUES('-1');
+--error 1264
+INSERT INTO t1 (col2) VALUES('4294967296');
+--error 1264
+INSERT INTO t1 (col1) VALUES(-2147483649.0);
+--error 1264
+INSERT INTO t1 (col1) VALUES(2147643648.0);
+--error 1264
+INSERT INTO t1 (col2) VALUES(-1.0);
+--error 1264
+INSERT INTO t1 (col2) VALUES(4294967296.0);
+
+--error 1264
+UPDATE t1 SET col1 = col1 - 50 WHERE col1 < 0;
+--error 1264
+UPDATE t1 SET col2 =col2 + 50 WHERE col2 > 0;
+--error 1365
+UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0;
+--error 1365
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+--error 1264
+INSERT INTO t1 (col1) VALUES ('');
+--error 1264
+INSERT INTO t1 (col1) VALUES ('a59b');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('1a');
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+INSERT IGNORE INTO t1 values (1/0,1/0);
+INSERT IGNORE INTO t1 values (-2147483649, -1),(2147643648,4294967296);
+INSERT IGNORE INTO t1 values ('-2147483649', '-1'),('2147643648','4294967296');
+INSERT IGNORE INTO t1 values (-2147483649.0, -1.0),(2147643648.0,4294967296.0);
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Test INSERT with BIGINT
+# Note that this doesn't behave 100 % to standard as we rotate
+# integers when it's too big/small (just like C)
+
+CREATE TABLE t1 (col1 BIGINT, col2 BIGINT UNSIGNED);
+INSERT INTO t1 VALUES(-9223372036854775808,0),(0,0),(9223372036854775807,18446744073709551615);
+INSERT INTO t1 VALUES('-9223372036854775808','0'),('9223372036854775807','18446744073709551615');
+INSERT INTO t1 VALUES(-9223372036854774000.0,0.0),(9223372036854775700.0,1844674407370954000.0);
+
+-- error 1264
+INSERT INTO t1 (col1) VALUES(-9223372036854775809);
+INSERT INTO t1 (col1) VALUES(9223372036854775808);
+INSERT INTO t1 (col2) VALUES(-1);
+
+--error 1264
+INSERT INTO t1 (col2) VALUES(18446744073709551616);
+--error 1264
+INSERT INTO t1 (col1) VALUES('-9223372036854775809');
+--error 1264
+INSERT INTO t1 (col1) VALUES('9223372036854775808');
+--error 1264
+INSERT INTO t1 (col2) VALUES('-1');
+--error 1264
+INSERT INTO t1 (col2) VALUES('18446744073709551616');
+
+# Note that the following two double numbers are slighty bigger than max/min
+# bigint becasue of rounding errors when converting it to bigint
+--error 1264
+INSERT INTO t1 (col1) VALUES(-9223372036854785809.0);
+--error 1264
+INSERT INTO t1 (col1) VALUES(9223372036854785808.0);
+--error 1264
+INSERT INTO t1 (col2) VALUES(-1.0);
+--error 1264
+INSERT INTO t1 (col2) VALUES(18446744073709551616.0);
+
+# The following doesn't give an error as it's done in integer context
+# UPDATE t1 SET col1=col1 - 5000 WHERE col1 < 0;
+# UPDATE t1 SET col2 =col2 + 5000 WHERE col2 > 0;
+
+--error 1365
+UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0;
+--error 1365
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+--error 1264
+INSERT INTO t1 (col1) VALUES ('');
+--error 1264
+INSERT INTO t1 (col1) VALUES ('a59b');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('1a');
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+INSERT IGNORE INTO t1 values (1/0,1/0);
+INSERT IGNORE INTO t1 VALUES(-9223372036854775809,-1),(9223372036854775808,18446744073709551616);
+INSERT IGNORE INTO t1 VALUES('-9223372036854775809','-1'),('9223372036854775808','18446744073709551616');
+INSERT IGNORE INTO t1 VALUES(-9223372036854785809.0,-1.0),(9223372036854785808.0,18446744073709551616.0);
+UPDATE IGNORE t1 SET col2=1/NULL where col1=0;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Test INSERT with NUMERIC
+
+CREATE TABLE t1 (col1 NUMERIC(4,2));
+INSERT INTO t1 VALUES (10.55),(10.5555),(0),(-10.55),(-10.5555),(11),(1e+01);
+-- Note that the +/-10.5555 is inserted as +/-10.55, not +/-10.56 !
+INSERT INTO t1 VALUES ('10.55'),('10.5555'),('-10.55'),('-10.5555'),('11'),('1e+01');
+
+-- The 2 following inserts should generate a warning, but doesn't yet
+-- because NUMERIC works like DECIMAL
+--error 1264
+INSERT INTO t1 VALUES (101.55);
+--error 1264
+INSERT INTO t1 VALUES (101);
+--error 1264
+INSERT INTO t1 VALUES (-101.55);
+--error 1264
+INSERT INTO t1 VALUES (1010.55);
+--error 1264
+INSERT INTO t1 VALUES (1010);
+-- The 2 following inserts should generate a warning, but doesn't yet
+-- because NUMERIC works like DECIMAL
+--error 1264
+INSERT INTO t1 VALUES ('101.55');
+--error 1264
+INSERT INTO t1 VALUES ('101');
+--error 1264
+INSERT INTO t1 VALUES ('-101.55');
+--error 1264
+INSERT INTO t1 VALUES ('-1010.55');
+--error 1264
+INSERT INTO t1 VALUES ('-100E+1');
+--error 1264
+INSERT INTO t1 VALUES ('-100E');
+--error 1264
+UPDATE t1 SET col1 =col1 * 50000 WHERE col1 =11;
+--error 1365
+UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0;
+--error 1365
+UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0;
+#--error 1265
+--error 1366
+INSERT INTO t1 (col1) VALUES ('');
+#--error 1265
+--error 1366
+INSERT INTO t1 (col1) VALUES ('a59b');
+#--error 1265
+INSERT INTO t1 (col1) VALUES ('1a');
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+INSERT IGNORE INTO t1 values (1/0);
+INSERT IGNORE INTO t1 VALUES(1000),(-1000);
+INSERT IGNORE INTO t1 VALUES('1000'),('-1000');
+INSERT IGNORE INTO t1 VALUES(1000.0),(-1000.0);
+UPDATE IGNORE t1 SET col1=1/NULL where col1=0;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Test INSERT with FLOAT
+
+CREATE TABLE t1 (col1 FLOAT, col2 FLOAT UNSIGNED);
+INSERT INTO t1 VALUES (-1.1E-37,0),(+3.4E+38,+3.4E+38);
+INSERT INTO t1 VALUES ('-1.1E-37',0),('+3.4E+38','+3.4E+38');
+# We don't give warnings for underflow
+INSERT INTO t1 (col1) VALUES (3E-46);
+--error 1264
+INSERT INTO t1 (col1) VALUES (+3.4E+39);
+--error 1264
+INSERT INTO t1 (col2) VALUES (-1.1E-3);
+--error 1264
+INSERT INTO t1 (col1) VALUES ('+3.4E+39');
+--error 1264
+INSERT INTO t1 (col2) VALUES ('-1.1E-3');
+--error 1264
+UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
+--error 1365
+UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
+--error 1365
+UPDATE t1 SET col2= MOD(col2,0) WHERE col2 > 0;
+--error 1265
+INSERT INTO t1 (col1) VALUES ('');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('a59b');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('1a');
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+INSERT IGNORE INTO t1 (col1) VALUES (1/0);
+INSERT IGNORE INTO t1 VALUES (+3.4E+39,-3.4E+39);
+INSERT IGNORE INTO t1 VALUES ('+3.4E+39','-3.4E+39');
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Test INSERT with DOUBLE
+
+CREATE TABLE t1 (col1 DOUBLE PRECISION, col2 DOUBLE PRECISION UNSIGNED);
+INSERT INTO t1 VALUES (-2.2E-307,0),(2E-307,0),(+1.7E+308,+1.7E+308);
+INSERT INTO t1 VALUES ('-2.2E-307',0),('-2E-307',0),('+1.7E+308','+1.7E+308');
+# We don't give warnings for underflow
+INSERT INTO t1 (col1) VALUES (-2.2E-330);
+--error 1367,1264
+INSERT INTO t1 (col1) VALUES (+1.7E+309);
+--error 1264
+INSERT INTO t1 (col2) VALUES (-1.1E-3);
+--error 1264
+INSERT INTO t1 (col1) VALUES ('+1.8E+309');
+--error 1264
+INSERT INTO t1 (col2) VALUES ('-1.2E-3');
+--error 1264
+UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
+--error 1365
+UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
+--error 1365
+UPDATE t1 SET col2= MOD(col2,0) WHERE col2 > 0;
+--error 1265
+INSERT INTO t1 (col1) VALUES ('');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('a59b');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('1a');
+INSERT IGNORE INTO t1 (col1) VALUES ('2a');
+INSERT IGNORE INTO t1 (col1) values (1/0);
+--error 1367
+INSERT IGNORE INTO t1 VALUES (+1.9E+309,-1.9E+309);
+INSERT IGNORE INTO t1 VALUES ('+2.0E+309','-2.0E+309');
+# stupid...
+--replace_result -0 0 1.7976931348623e+308 1.79769313486232e+308
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Testing INSERT with CHAR/VARCHAR
+
+CREATE TABLE t1 (col1 CHAR(5), col2 VARCHAR(6));
+INSERT INTO t1 VALUES ('hello', 'hello'),('he', 'he'),('hello ', 'hello ');
+--error 1406
+INSERT INTO t1 (col1) VALUES ('hellobob');
+--error 1406
+INSERT INTO t1 (col2) VALUES ('hellobob');
+INSERT INTO t1 (col2) VALUES ('hello ');
+--error 1406
+UPDATE t1 SET col1 ='hellobob' WHERE col1 ='he';
+--error 1406
+UPDATE t1 SET col2 ='hellobob' WHERE col2 ='he';
+INSERT IGNORE INTO t1 VALUES ('hellobob', 'hellobob');
+UPDATE IGNORE t1 SET col2 ='hellotrudy' WHERE col2 ='he';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Testing INSERT with ENUM
+
+CREATE TABLE t1 (col1 enum('red','blue','green'));
+INSERT INTO t1 VALUES ('red'),('blue'),('green');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('yellow');
+--error 1265
+INSERT INTO t1 (col1) VALUES ('redd');
+--error 1265
+INSERT INTO t1 VALUES ('');
+--error 1265
+UPDATE t1 SET col1 ='yellow' WHERE col1 ='green';
+INSERT IGNORE INTO t1 VALUES ('yellow');
+UPDATE IGNORE t1 SET col1 ='yellow' WHERE col1 ='blue';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Testing of insert of NULL in not NULL column
+
+CREATE TABLE t1 (col1 INT NOT NULL, col2 CHAR(5) NOT NULL, col3 DATE NOT NULL);
+INSERT INTO t1 VALUES (100, 'hello', '2004-08-20');
+INSERT INTO t1 (col1,col2,col3) VALUES (101, 'hell2', '2004-08-21');
+--error 1048
+INSERT INTO t1 (col1,col2,col3) VALUES (NULL, '', '2004-01-01');
+--error 1048
+INSERT INTO t1 (col1,col2,col3) VALUES (102, NULL, '2004-01-01');
+--error 1048
+INSERT INTO t1 VALUES (103,'',NULL);
+--error 1263
+UPDATE t1 SET col1=NULL WHERE col1 =100;
+--error 1263
+UPDATE t1 SET col2 =NULL WHERE col2 ='hello';
+--error 1263
+UPDATE t1 SET col2 =NULL where col3 IS NOT NULL;
+INSERT IGNORE INTO t1 values (NULL,NULL,NULL);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Testing of default values
+
+CREATE TABLE t1 (col1 INT NOT NULL default 99, col2 CHAR(6) NOT NULL);
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (1, 'hello');
+INSERT INTO t1 (col2) VALUES ('hello2');
+--error 1048
+INSERT INTO t1 (col2) VALUES (NULL);
+--error 1364
+INSERT INTO t1 (col1) VALUES (2);
+--error 1364
+INSERT INTO t1 VALUES(default(col1),default(col2));
+--error 1364
+INSERT INTO t1 (col1) SELECT 1;
+--error 1263
+INSERT INTO t1 SELECT 1,NULL;
+INSERT IGNORE INTO t1 values (NULL,NULL);
+INSERT IGNORE INTO t1 (col1) values (3);
+INSERT IGNORE INTO t1 () values ();
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Bug #9029 Traditional: Wrong SQLSTATE returned for string truncation
+#
+
+set sql_mode='traditional';
+create table t1 (charcol char(255), varcharcol varchar(255),
+binarycol binary(255), varbinarycol varbinary(255), tinytextcol tinytext,
+tinyblobcol tinyblob);
+--error 1406
+insert into t1 (charcol) values (repeat('x',256));
+--error 1406
+insert into t1 (varcharcol) values (repeat('x',256));
+--error 1406
+insert into t1 (binarycol) values (repeat('x',256));
+--error 1406
+insert into t1 (varbinarycol) values (repeat('x',256));
+--error 1406
+insert into t1 (tinytextcol) values (repeat('x',256));
+--error 1406
+insert into t1 (tinyblobcol) values (repeat('x',256));
+select * from t1;
+drop table t1;
+
+#
+# Bug #5902: STR_TO_DATE() didn't give errors in traditional mode
+#
+
+set sql_mode='traditional';
+create table t1 (col1 datetime);
+--error 1292
+insert into t1 values(STR_TO_DATE('31.10.2004 15.30 abc','%d.%m.%Y %H.%i'));
+--error 1411
+insert into t1 values(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+--error 1411
+insert into t1 values(STR_TO_DATE('2004.12.12 22:22:33 AM','%Y.%m.%d %r'));
+--error 1411
+insert into t1 values(STR_TO_DATE('2004.12.12 abc','%Y.%m.%d %T'));
+set sql_mode='';
+insert into t1 values(STR_TO_DATE('31.10.2004 15.30 abc','%d.%m.%Y %H.%i'));
+insert into t1 values(STR_TO_DATE('32.10.2004 15.30','%d.%m.%Y %H.%i'));
+insert into t1 values(STR_TO_DATE('2004.12.12 22:22:33 AM','%Y.%m.%d %r'));
+insert into t1 values(STR_TO_DATE('2004.12.12 abc','%Y.%m.%d %T'));
+
+# Some correct values, just to test the functions
+insert into t1 values(STR_TO_DATE('31.10.2004 15.30','%d.%m.%Y %H.%i'));
+insert into t1 values(STR_TO_DATE('2004.12.12 11:22:33 AM','%Y.%m.%d %r'));
+insert into t1 values(STR_TO_DATE('2004.12.12 10:22:59','%Y.%m.%d %T'));
+
+select * from t1;
+
+# Check that select don't abort even in strict mode (for now)
+set sql_mode='traditional';
+
+--disable_ps_warnings
+select count(*) from t1 where STR_TO_DATE('2004.12.12 10:22:61','%Y.%m.%d %T') IS NULL;
+--enable_ps_warnings
+
+drop table t1;
+
+#
+# Check insert with wrong CAST() (Bug #5912)
+#
+
+create table t1 (col1 char(3), col2 integer);
+--error 1292
+insert into t1 (col1) values (cast(1000 as char(3)));
+--error 1292
+insert into t1 (col1) values (cast(1000E+0 as char(3)));
+--error 1292
+insert into t1 (col1) values (cast(1000.0 as char(3)));
+--error 1292
+insert into t1 (col2) values (cast('abc' as signed integer));
+--error 1292
+insert into t1 (col2) values (10E+0 + 'a');
+--error 1292
+insert into t1 (col2) values (cast('10a' as unsigned integer));
+insert into t1 (col2) values (cast('10' as unsigned integer));
+insert into t1 (col2) values (cast('10' as signed integer));
+insert into t1 (col2) values (10E+0 + '0 ');
+select * from t1;
+drop table t1;
+
+#
+# Zero dates using numbers was not checked properly (Bug #5933 & #6145)
+#
+
+create table t1 (col1 date, col2 datetime, col3 timestamp);
+--error 1292
+insert into t1 values (0,0,0);
+--error 1292
+insert into t1 values (0.0,0.0,0.0);
+--error 1292
+insert into t1 (col1) values (convert('0000-00-00',date));
+--error 1292
+insert into t1 (col1) values (cast('0000-00-00' as date));
+
+set sql_mode='no_zero_date';
+insert into t1 values (0,0,0);
+insert into t1 values (0.0,0.0,0.0);
+drop table t1;
+set sql_mode='traditional';
+create table t1 (col1 date);
+insert ignore into t1 values ('0000-00-00');
+--error 1292
+insert into t1 select * from t1;
+insert ignore into t1 values ('0000-00-00');
+insert ignore into t1 (col1) values (cast('0000-00-00' as date));
+--error 1292
+insert into t1 select * from t1;
+--error 1292
+alter table t1 modify col1 datetime;
+alter ignore table t1 modify col1 datetime;
+--error 1292
+insert into t1 select * from t1;
+select * from t1;
+drop table t1;
+
+#
+# Test of inserting an invalid value via a stored procedure (Bug #5907)
+#
+create table t1 (col1 tinyint);
+drop procedure if exists t1;
+delimiter |;
+create procedure t1 () begin declare exit handler for sqlexception
+select'a'; insert into t1 values (200); end;|
+delimiter ;|
+call t1();
+select * from t1;
+drop procedure t1;
+drop table t1;
+
+#
+# Restore mode
+#
+set sql_mode=@org_mode;
+
+# Test fields with no default value that are NOT NULL (Bug #5986)
+SET @@sql_mode = 'traditional';
+CREATE TABLE t1 (i int not null);
+--error 1364
+INSERT INTO t1 VALUES ();
+--error 1364
+INSERT INTO t1 VALUES (DEFAULT);
+--error 1364
+INSERT INTO t1 VALUES (DEFAULT(i));
+ALTER TABLE t1 ADD j int;
+--error 1364
+INSERT INTO t1 SET j = 1;
+--error 1364
+INSERT INTO t1 SET j = 1, i = DEFAULT;
+--error 1364
+INSERT INTO t1 SET j = 1, i = DEFAULT(i);
+--error 1364
+INSERT INTO t1 VALUES (DEFAULT,1);
+DROP TABLE t1;
+SET @@sql_mode = '';
+CREATE TABLE t1 (i int not null);
+INSERT INTO t1 VALUES ();
+INSERT INTO t1 VALUES (DEFAULT);
+# DEFAULT(i) is an error even with the default sql_mode
+--error 1364
+INSERT INTO t1 VALUES (DEFAULT(i));
+ALTER TABLE t1 ADD j int;
+INSERT INTO t1 SET j = 1;
+INSERT INTO t1 SET j = 1, i = DEFAULT;
+--error 1364
+INSERT INTO t1 SET j = 1, i = DEFAULT(i);
+INSERT INTO t1 VALUES (DEFAULT,1);
+DROP TABLE t1;
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 1882a04936c..fe7cd42995d 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -46,9 +46,9 @@ SELECT ROW(1,2,3) > (SELECT 1,2,1);
SELECT ROW(1,2,3) = (SELECT 1,2,NULL);
SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'a');
SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'b');
-SELECT (SELECT 1.5,2,'a') = ROW('b',2,'b');
+SELECT (SELECT 1.5,2,'a') = ROW('1.5b',2,'b');
SELECT (SELECT 'b',2,'a') = ROW(1.5,2,'a');
-SELECT (SELECT 1.5,2,'a') = ROW(1.5,'c','a');
+SELECT (SELECT 1.5,2,'a') = ROW(1.5,'2','a');
SELECT (SELECT 1.5,'c','a') = ROW(1.5,2,'a');
-- error 1241
@@ -352,7 +352,9 @@ INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
select * from t1;
INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2;
select * from t1;
+# After this, only data based on old t1 records should have been added.
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
+select * from t1;
-- error 1054
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2));
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
@@ -507,6 +509,9 @@ select ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a');
select ROW(1, 1, 'a') IN (select b,a,c from t1 limit 2);
drop table t1;
+#
+# DO & SET
+#
create table t1 (a int);
insert into t1 values (1);
do @a:=(SELECT a from t1);
@@ -1721,4 +1726,76 @@ select (select a from t1) = (1,2);
select (1,2,3) = (select * from t1);
-- error 1241
select (select * from t1) = (1,2,3);
-drop table t1
+drop table t1;
+
+#
+#decimal-related tests
+#
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+insert into t1 values(2.2);
+
+select * from t1 where df <= all (select avg(df) from t1 group by df);
+select * from t1 where df >= all (select avg(df) from t1 group by df);
+drop table t1;
+
+create table t1 (df decimal(5,1));
+insert into t1 values(1.1);
+select 1.1 * exists(select * from t1);
+drop table t1;
+
+CREATE TABLE t1 (
+ grp int(11) default NULL,
+ a decimal(10,2) default NULL);
+
+insert into t1 values (1, 1), (2, 2), (2, 3), (3, 4), (3, 5), (3, 6), (NULL, NULL);
+select * from t1;
+select min(a) from t1 group by grp;
+drop table t1;
+
+#
+# Test for bug #9338: lame substitution of c1 instead of c2
+#
+
+CREATE table t1 ( c1 integer );
+INSERT INTO t1 VALUES ( 1 );
+INSERT INTO t1 VALUES ( 2 );
+INSERT INTO t1 VALUES ( 3 );
+
+CREATE TABLE t2 ( c2 integer );
+INSERT INTO t2 VALUES ( 1 );
+INSERT INTO t2 VALUES ( 4 );
+INSERT INTO t2 VALUES ( 5 );
+
+SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2 WHERE c2 IN (1);
+
+SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2
+ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2 IN ( 1 ) );
+
+DROP TABLE t1,t2;
+
+#
+# Test for bug #9516: wrong evaluation of not_null_tables attribute in SQ
+#
+
+CREATE TABLE t1 ( c1 integer );
+INSERT INTO t1 VALUES ( 1 );
+INSERT INTO t1 VALUES ( 2 );
+INSERT INTO t1 VALUES ( 3 );
+INSERT INTO t1 VALUES ( 6 );
+
+CREATE TABLE t2 ( c2 integer );
+INSERT INTO t2 VALUES ( 1 );
+INSERT INTO t2 VALUES ( 4 );
+INSERT INTO t2 VALUES ( 5 );
+INSERT INTO t2 VALUES ( 6 );
+
+CREATE TABLE t3 ( c3 integer );
+INSERT INTO t3 VALUES ( 7 );
+INSERT INTO t3 VALUES ( 8 );
+
+SELECT c1,c2 FROM t1 LEFT JOIN t2 ON c1 = c2
+ WHERE EXISTS (SELECT c3 FROM t3 WHERE c2 IS NULL );
+
+DROP TABLE t1,t2,t3;
+
diff --git a/mysql-test/t/sum_distinct-big.test b/mysql-test/t/sum_distinct-big.test
new file mode 100644
index 00000000000..0859f4b3d89
--- /dev/null
+++ b/mysql-test/t/sum_distinct-big.test
@@ -0,0 +1,67 @@
+#
+# Various tests for SUM(DISTINCT ...)
+#
+
+--source include/big_test.inc
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+#
+# Test the case when distinct values doesn't fit in memory and
+# filesort is used (see uniques.cc:merge_walk)
+#
+
+CREATE TABLE t1 (id INTEGER);
+CREATE TABLE t2 (id INTEGER);
+
+INSERT INTO t1 (id) VALUES (1), (1), (1),(1);
+INSERT INTO t1 (id) SELECT id FROM t1; /* 8 */
+INSERT INTO t1 (id) SELECT id FROM t1; /* 12 */
+INSERT INTO t1 (id) SELECT id FROM t1; /* 16 */
+INSERT INTO t1 (id) SELECT id FROM t1; /* 20 */
+INSERT INTO t1 (id) SELECT id FROM t1; /* 24 */
+INSERT INTO t1 SELECT id+1 FROM t1;
+INSERT INTO t1 SELECT id+2 FROM t1;
+INSERT INTO t1 SELECT id+4 FROM t1;
+INSERT INTO t1 SELECT id+8 FROM t1;
+INSERT INTO t1 SELECT id+16 FROM t1;
+INSERT INTO t1 SELECT id+32 FROM t1;
+INSERT INTO t1 SELECT id+64 FROM t1;
+INSERT INTO t1 SELECT id+128 FROM t1;
+INSERT INTO t1 SELECT id+256 FROM t1;
+INSERT INTO t1 SELECT id+512 FROM t1;
+
+# Just test that AVG(DISTINCT) is there
+SELECT AVG(DISTINCT id) FROM t1 GROUP BY id % 13;
+SELECT SUM(DISTINCT id)/COUNT(DISTINCT id) FROM t1 GROUP BY id % 13;
+
+INSERT INTO t1 SELECT id+1024 FROM t1;
+INSERT INTO t1 SELECT id+2048 FROM t1;
+INSERT INTO t1 SELECT id+4096 FROM t1;
+INSERT INTO t1 SELECT id+8192 FROM t1;
+INSERT INTO t2 SELECT id FROM t1 ORDER BY id*rand();
+
+# SELECT '++++++++++++++++++++++++++++++++++++++++++++++++++';
+
+SELECT SUM(DISTINCT id) sm FROM t1;
+SELECT SUM(DISTINCT id) sm FROM t2;
+SELECT SUM(DISTINCT id) sm FROM t1 group by id % 13;
+
+# this limit for max_heap_table_size is set to force testing the case, when
+# all distinct sum values can not fit in memory and must be stored in a
+# temporary table
+
+SET max_heap_table_size=16384;
+
+# to check that max_heap_table_size was actually set (hard limit for minimum
+# max_heap_table_size is set in mysqld.cc):
+
+SHOW variables LIKE 'max_heap_table_size';
+
+SELECT SUM(DISTINCT id) sm FROM t1;
+SELECT SUM(DISTINCT id) sm FROM t2;
+SELECT SUM(DISTINCT id) sm FROM t1 GROUP BY id % 13;
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/t/sum_distinct.test b/mysql-test/t/sum_distinct.test
new file mode 100644
index 00000000000..c58155a8e25
--- /dev/null
+++ b/mysql-test/t/sum_distinct.test
@@ -0,0 +1,95 @@
+#
+# Various tests for SUM(DISTINCT ...)
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+CREATE TABLE t1 (
+ id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ gender CHAR(1),
+ name VARCHAR(20)
+);
+
+# According to ANSI SQL, SUM(DISTINCT ...) should return NULL for empty
+# record set
+
+SELECT SUM(DISTINCT LENGTH(name)) s1 FROM t1;
+
+# According to ANSI SQL, SUM(DISTINCT ...) should return NULL for records sets
+# entirely consisting of NULLs
+
+INSERT INTO t1 (gender, name) VALUES (NULL, NULL);
+INSERT INTO t1 (gender, name) VALUES (NULL, NULL);
+INSERT INTO t1 (gender, name) VALUES (NULL, NULL);
+
+SELECT SUM(DISTINCT LENGTH(name)) s1 FROM t1;
+
+
+# Filling table with t1
+
+INSERT INTO t1 (gender, name) VALUES ('F', 'Helen'), ('F', 'Anastasia'),
+('F', 'Katherine'), ('F', 'Margo'), ('F', 'Magdalene'), ('F', 'Mary');
+
+CREATE TABLE t2 SELECT name FROM t1;
+
+SELECT (SELECT SUM(DISTINCT LENGTH(name)) FROM t1) FROM t2;
+
+DROP TABLE t2;
+
+INSERT INTO t1 (gender, name) VALUES ('F', 'Eva'), ('F', 'Sofia'),
+('F', 'Sara'), ('F', 'Golda'), ('F', 'Toba'), ('F', 'Victory'),
+('F', 'Faina'), ('F', 'Miriam'), ('F', 'Beki'), ('F', 'America'),
+('F', 'Susan'), ('F', 'Glory'), ('F', 'Priscilla'), ('F', 'Rosmary'),
+('F', 'Rose'), ('F', 'Margareth'), ('F', 'Elizabeth'), ('F', 'Meredith'),
+('F', 'Julie'), ('F', 'Xenia'), ('F', 'Zena'), ('F', 'Olga'),
+('F', 'Brunhilda'), ('F', 'Nataly'), ('F', 'Lara'), ('F', 'Svetlana'),
+('F', 'Grethem'), ('F', 'Irene');
+
+SELECT
+ SUM(DISTINCT LENGTH(name)) s1,
+ SUM(DISTINCT SUBSTRING(NAME, 1, 3)) s2,
+ SUM(DISTINCT LENGTH(SUBSTRING(name, 1, 4))) s3
+FROM t1;
+
+SELECT
+ SUM(DISTINCT LENGTH(g1.name)) s1,
+ SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2,
+ SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3
+FROM t1 g1, t1 g2, t1 g3;
+
+SELECT
+ SUM(DISTINCT LENGTH(g1.name)) s1,
+ SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2,
+ SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3
+FROM t1 g1, t1 g2, t1 g3 GROUP BY LENGTH(SUBSTRING(g3.name, 5, 10));
+
+# here we explicitly request summing through temporary table (so
+# Item_sum_sum_distinct::copy_or_same() is called)
+
+SELECT SQL_BUFFER_RESULT
+ SUM(DISTINCT LENGTH(name)) s1,
+ SUM(DISTINCT SUBSTRING(NAME, 1, 3)) s2,
+ SUM(DISTINCT LENGTH(SUBSTRING(name, 1, 4))) s3
+FROM t1;
+
+SELECT SQL_BUFFER_RESULT
+ SUM(DISTINCT LENGTH(g1.name)) s1,
+ SUM(DISTINCT SUBSTRING(g2.name, 1, 3)) s2,
+ SUM(DISTINCT LENGTH(SUBSTRING(g3.name, 1, 4))) s3
+FROM t1 g1, t1 g2, t1 g3 GROUP BY LENGTH(SUBSTRING(g3.name, 5, 10));
+
+# this test demonstrates that strings are automatically converted to numbers
+# before summing
+
+SET @l=1;
+UPDATE t1 SET name=CONCAT(name, @l:=@l+1);
+
+SELECT SUM(DISTINCT RIGHT(name, 1)) FROM t1;
+
+# this is a test case for ordinary t1
+
+SELECT SUM(DISTINCT id) FROM t1;
+SELECT SUM(DISTINCT id % 11) FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test
index ddde5171200..f477fc378c6 100644
--- a/mysql-test/t/symlink.test
+++ b/mysql-test/t/symlink.test
@@ -49,6 +49,7 @@ check table t9;
optimize table t9;
repair table t9;
alter table t9 add column c int not null;
+
--replace_result $MYSQL_TEST_DIR TEST_DIR
show create table t9;
@@ -64,6 +65,9 @@ drop table t1;
# Note that we are using the above table t9 here!
#
+--replace_result $MYSQL_TEST_DIR TEST_DIR
+SHOW CREATE TABLE t9;
+
disable_query_log;
--error 1103,1103
create table t1 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam data directory="tmp";
@@ -78,9 +82,11 @@ create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, p
--error 1103,1103
create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="not-hard-path";
---error 1,1
+# Should fail becasue the file t9.MYI already exist in 'run'
+--error 1,1,1105
eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="$MYSQL_TEST_DIR/var/run";
+# Should fail becasue the file t9.MYD already exist in 'tmp'
--error 1,1
eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam data directory="$MYSQL_TEST_DIR/var/tmp";
enable_query_log;
diff --git a/mysql-test/t/synchronization.test b/mysql-test/t/synchronization.test
index 7bdeaa8a740..09324b32b97 100644
--- a/mysql-test/t/synchronization.test
+++ b/mysql-test/t/synchronization.test
@@ -1,7 +1,12 @@
#
-# Test for Bug #2385 CREATE TABLE LIKE lacks locking on source and destination table
+# Test for Bug #2385 CREATE TABLE LIKE lacks locking on source and destination
+# table
#
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
diff --git a/mysql-test/t/system_mysql_db.test b/mysql-test/t/system_mysql_db.test
index a6d683489c3..acd19f47728 100644
--- a/mysql-test/t/system_mysql_db.test
+++ b/mysql-test/t/system_mysql_db.test
@@ -2,6 +2,11 @@
# This test must examine integrity of system database "mysql"
#
+# First delete some tables maybe left over from previous tests
+--disable_warnings
+drop table if exists t1,t1aa,t2aa;
+--enable_warnings
+
-- disable_query_log
use mysql;
-- enable_query_log
diff --git a/mysql-test/t/system_mysql_db_fix.test b/mysql-test/t/system_mysql_db_fix.test
index d0aae7b411c..f47b4cba6e6 100644
--- a/mysql-test/t/system_mysql_db_fix.test
+++ b/mysql-test/t/system_mysql_db_fix.test
@@ -4,6 +4,14 @@
#
# This is the test for mysql_fix_privilege_tables
#
+# Note: If this test fails, don't be confused about the errors reported
+# by mysql-test-run; This shows warnings from generated by
+# mysql_fix_system_tables which should be ignored.
+# Instead, concentrate on the errors in r/system_mysql_db.reject
+
+--disable_warnings
+drop table if exists t1,t1aa,t2aa;
+--enable_warnings
-- disable_result_log
-- disable_query_log
@@ -77,7 +85,7 @@ INSERT INTO user VALUES ('localhost','', '','N','N','N','N','N','N','N','N','
-- disable_query_log
-DROP TABLE db, host, user, func, tables_priv, columns_priv, help_category, help_keyword, help_relation, help_topic, time_zone, time_zone_leap_second, time_zone_name, time_zone_transition, time_zone_transition_type;
+DROP TABLE db, host, user, func, tables_priv, columns_priv, procs_priv, help_category, help_keyword, help_relation, help_topic, proc, time_zone, time_zone_leap_second, time_zone_name, time_zone_transition, time_zone_transition_type;
-- enable_query_log
diff --git a/mysql-test/t/temp_table.test b/mysql-test/t/temp_table.test
index 74276c7668c..eeb33515570 100644
--- a/mysql-test/t/temp_table.test
+++ b/mysql-test/t/temp_table.test
@@ -89,3 +89,18 @@ flush status;
select * from t1 group by d;
show status like "created_tmp%tables";
drop table t1;
+
+# Fix for BUG#8921: Check that temporary table is ingored by view commands.
+create temporary table t1 as select 'This is temp. table' A;
+create view t1 as select 'This is view' A;
+select * from t1;
+show create table t1;
+show create view t1;
+drop view t1;
+select * from t1;
+create view t1 as select 'This is view again' A;
+select * from t1;
+drop table t1;
+select * from t1;
+drop view t1;
+
diff --git a/mysql-test/t/timezone2.test b/mysql-test/t/timezone2.test
index f952c0f65b2..0b5aaed5d30 100644
--- a/mysql-test/t/timezone2.test
+++ b/mysql-test/t/timezone2.test
@@ -200,7 +200,7 @@ select convert_tz(ts, @@time_zone, 'Japan') from t1;
drop table t1;
#
-# Test for bug #7705 "CONVERT_TZ() crashes with subquery/WHERE on index
+# Test for bug #7705 "CONVERT_TZ() crashes with subquery/WHERE on index
# column". Queries in which one of time zone arguments of CONVERT_TZ() is
# determined as constant only at val() stage (not at fix_fields() stage),
# should not crash server.
diff --git a/mysql-test/t/timezone_grant.test b/mysql-test/t/timezone_grant.test
index 501315668f5..f586ba0c5fe 100644
--- a/mysql-test/t/timezone_grant.test
+++ b/mysql-test/t/timezone_grant.test
@@ -28,9 +28,9 @@ select convert_tz(b, 'Europe/Moscow', 'UTC') from t1;
update t1, t2 set t1.b = convert_tz('2004-10-21 19:00:00', 'Europe/Moscow', 'UTC')
where t1.a = t2.c and t2.d = (select max(d) from t2);
# But still these two statements should not work:
---error 1044
+--error 1142
select * from mysql.time_zone_name;
---error 1044
+--error 1142
select Name, convert_tz('2004-10-21 19:00:00', Name, 'UTC') from mysql.time_zone_name;
#
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
new file mode 100644
index 00000000000..53144cf3591
--- /dev/null
+++ b/mysql-test/t/trigger.test
@@ -0,0 +1,251 @@
+#
+# Basic triggers test
+#
+
+--disable_warnings
+drop table if exists t1, t2;
+drop view if exists v1;
+drop database if exists mysqltest;
+--enable_warnings
+
+create table t1 (i int);
+
+# let us test some very simple trigger
+create trigger trg before insert on t1 for each row set @a:=1;
+set @a:=0;
+select @a;
+insert into t1 values (1);
+select @a;
+drop trigger t1.trg;
+
+# let us test simple trigger reading some values
+create trigger trg before insert on t1 for each row set @a:=new.i;
+insert into t1 values (123);
+select @a;
+drop trigger t1.trg;
+
+drop table t1;
+
+# Let us test before insert trigger
+# Such triggers can be used for setting complex default values
+create table t1 (i int not null, j int);
+delimiter |;
+create trigger trg before insert on t1 for each row
+begin
+ if isnull(new.j) then
+ set new.j:= new.i * 10;
+ end if;
+end|
+insert into t1 (i) values (1)|
+insert into t1 (i,j) values (2, 3)|
+select * from t1|
+drop trigger t1.trg|
+drop table t1|
+delimiter ;|
+
+# After insert trigger
+# Useful for aggregating data
+create table t1 (i int not null primary key);
+create trigger trg after insert on t1 for each row
+ set @a:= if(@a,concat(@a, ":", new.i), new.i);
+set @a:="";
+insert into t1 values (2),(3),(4),(5);
+select @a;
+drop trigger t1.trg;
+drop table t1;
+
+# PS doesn't work with multi-row statements
+--disable_ps_protocol
+# Before update trigger
+# (In future we will achieve this via proper error handling in triggers)
+create table t1 (aid int not null primary key, balance int not null default 0);
+insert into t1 values (1, 1000), (2,3000);
+delimiter |;
+create trigger trg before update on t1 for each row
+begin
+ declare loc_err varchar(255);
+ if abs(new.balance - old.balance) > 1000 then
+ set new.balance:= old.balance;
+ set loc_err := concat("Too big change for aid = ", new.aid);
+ set @update_failed:= if(@update_failed, concat(@a, ":", loc_err), loc_err);
+ end if;
+end|
+set @update_failed:=""|
+update t1 set balance=1500|
+select @update_failed;
+select * from t1|
+drop trigger t1.trg|
+drop table t1|
+delimiter ;|
+--enable_ps_protocol
+
+# After update trigger
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg after update on t1 for each row
+ set @total_change:=@total_change + new.i - old.i;
+set @total_change:=0;
+update t1 set i=3;
+select @total_change;
+drop trigger t1.trg;
+drop table t1;
+
+# Before delete trigger
+# This can be used for aggregation too :)
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg before delete on t1 for each row
+ set @del_sum:= @del_sum + old.i;
+set @del_sum:= 0;
+delete from t1 where i <= 3;
+select @del_sum;
+drop trigger t1.trg;
+drop table t1;
+
+# After delete trigger.
+# Just run out of imagination.
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg after delete on t1 for each row set @del:= 1;
+set @del:= 0;
+delete from t1 where i <> 0;
+select @del;
+drop trigger t1.trg;
+drop table t1;
+
+# Several triggers on one table
+create table t1 (i int, j int);
+
+delimiter |;
+create trigger trg1 before insert on t1 for each row
+begin
+ if new.j > 10 then
+ set new.j := 10;
+ end if;
+end|
+create trigger trg2 before update on t1 for each row
+begin
+ if old.i % 2 = 0 then
+ set new.j := -1;
+ end if;
+end|
+create trigger trg3 after update on t1 for each row
+begin
+ if new.j = -1 then
+ set @fired:= "Yes";
+ end if;
+end|
+delimiter ;|
+set @fired:="";
+insert into t1 values (1,2),(2,3),(3,14);
+select @fired;
+select * from t1;
+update t1 set j= 20;
+select @fired;
+select * from t1;
+
+drop trigger t1.trg1;
+drop trigger t1.trg2;
+drop trigger t1.trg3;
+drop table t1;
+
+
+#
+# Test of wrong column specifiers in triggers
+#
+create table t1 (i int);
+
+--error 1363
+create trigger trg before insert on t1 for each row set @a:= old.i;
+--error 1363
+create trigger trg before delete on t1 for each row set @a:= new.i;
+--error 1362
+create trigger trg before update on t1 for each row set old.i:=1;
+--error 1363
+create trigger trg before delete on t1 for each row set new.i:=1;
+--error 1362
+create trigger trg after update on t1 for each row set new.i:=1;
+--error 1054
+create trigger trg before update on t1 for each row set new.j:=1;
+--error 1054
+create trigger trg before update on t1 for each row set @a:=old.j;
+
+
+#
+# Let us test various trigger creation errors
+#
+#
+--error 1146
+create trigger trg before insert on t2 for each row set @a:=1;
+
+create trigger trg before insert on t1 for each row set @a:=1;
+--error 1359
+create trigger trg after insert on t1 for each row set @a:=1;
+--error 1359
+create trigger trg2 before insert on t1 for each row set @a:=1;
+drop trigger t1.trg;
+
+--error 1360
+drop trigger t1.trg;
+
+create view v1 as select * from t1;
+--error 1361
+create trigger trg before insert on v1 for each row set @a:=1;
+drop view v1;
+
+drop table t1;
+
+create temporary table t1 (i int);
+--error 1361
+create trigger trg before insert on t1 for each row set @a:=1;
+drop table t1;
+
+
+
+#
+# Tests for various trigger-related bugs
+#
+
+# Test for bug #5887 "Triggers with string literals cause errors".
+# New .FRM parser was not handling escaped strings properly.
+create table t1 (x1col char);
+create trigger tx1 before insert on t1 for each row set new.x1col = 'x';
+insert into t1 values ('y');
+drop trigger t1.tx1;
+drop table t1;
+
+#
+# Test for bug #5890 "Triggers fail for DELETE without WHERE".
+# If we are going to delete all rows in table but DELETE triggers exist
+# we should perform row-by-row deletion instead of using optimized
+# delete_all_rows() method.
+#
+create table t1 (i int) engine=myisam;
+insert into t1 values (1), (2);
+create trigger trg1 before delete on t1 for each row set @del_before:= @del_before + old.i;
+create trigger trg2 after delete on t1 for each row set @del_after:= @del_after + old.i;
+set @del_before:=0, @del_after:= 0;
+delete from t1;
+select @del_before, @del_after;
+drop trigger t1.trg1;
+drop trigger t1.trg2;
+drop table t1;
+
+# Test for bug #5859 "DROP TABLE does not drop triggers". Trigger should not
+# magically reappear when we recreate dropped table.
+create table t1 (a int);
+create trigger trg1 before insert on t1 for each row set new.a= 10;
+drop table t1;
+create table t1 (a int);
+insert into t1 values ();
+select * from t1;
+drop table t1;
+
+# Test for bug #6559 "DROP DATABASE forgets to drop triggers".
+create database mysqltest;
+use mysqltest;
+create table t1 (i int);
+create trigger trg1 before insert on t1 for each row set @a:= 1;
+# This should succeed
+drop database mysqltest;
+use test;
diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test
new file mode 100644
index 00000000000..1fbcf01d5a6
--- /dev/null
+++ b/mysql-test/t/type_bit.test
@@ -0,0 +1,142 @@
+#
+# testing of the BIT column type
+#
+
+select 0 + b'1';
+select 0 + b'0';
+select 0 + b'000001';
+select 0 + b'000011';
+select 0 + b'000101';
+select 0 + b'000000';
+select 0 + b'10000000';
+select 0 + b'11111111';
+select 0 + b'10000001';
+select 0 + b'1000000000000000';
+select 0 + b'1111111111111111';
+select 0 + b'1000000000000001';
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+--error 1074
+create table t1 (a bit(65));
+
+create table t1 (a bit(0));
+show create table t1;
+drop table t1;
+
+create table t1 (a bit(64));
+insert into t1 values
+(b'1111111111111111111111111111111111111111111111111111111111111111'),
+(b'1000000000000000000000000000000000000000000000000000000000000000'),
+(b'0000000000000000000000000000000000000000000000000000000000000001'),
+(b'1010101010101010101010101010101010101010101010101010101010101010'),
+(b'0101010101010101010101010101010101010101010101010101010101010101');
+select hex(a) from t1;
+drop table t1;
+
+create table t1 (a bit);
+insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001');
+select hex(a) from t1;
+--error 1062
+alter table t1 add unique (a);
+drop table t1;
+
+create table t1 (a bit(2));
+insert into t1 values (b'00'), (b'01'), (b'10'), (b'100');
+select a+0 from t1;
+alter table t1 add key (a);
+explain select a+0 from t1;
+select a+0 from t1;
+drop table t1;
+
+create table t1 (a bit(7), b bit(9), key(a, b));
+insert into t1 values
+(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177),
+(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380),
+(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36),
+(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499),
+(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403),
+(44, 307), (68, 454), (57, 135);
+explain select a+0 from t1;
+select a+0 from t1;
+explain select b+0 from t1;
+select b+0 from t1;
+explain select a+0, b+0 from t1;
+select a+0, b+0 from t1;
+explain select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+explain select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+set @@max_length_for_sort_data=0;
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+select hex(min(a)) from t1;
+select hex(min(b)) from t1;
+select hex(min(a)), hex(max(a)), hex(min(b)), hex(max(b)) from t1;
+drop table t1;
+
+create table t1 (a int not null, b bit, c bit(9), key(a, b, c));
+insert into t1 values
+(4, NULL, 1), (4, 0, 3), (2, 1, 4), (1, 1, 100), (4, 0, 23), (4, 0, 54),
+(56, 0, 22), (4, 1, 100), (23, 0, 1), (4, 0, 34);
+select a+0, b+0, c+0 from t1;
+select hex(min(b)) from t1 where a = 4;
+select hex(min(c)) from t1 where a = 4 and b = 0;
+select hex(max(b)) from t1;
+select a+0, b+0, c+0 from t1 where a = 4 and b = 0 limit 2;
+select a+0, b+0, c+0 from t1 where a = 4 and b = 1;
+select a+0, b+0, c+0 from t1 where a = 4 and b = 1 and c=100;
+select a+0, b+0, c+0 from t1 order by b desc;
+select a+0, b+0, c+0 from t1 order by c;
+drop table t1;
+
+create table t1(a bit(2), b bit(2));
+insert into t1 (a) values (0x01), (0x03), (0x02);
+update t1 set b= concat(a);
+select a+0, b+0 from t1;
+drop table t1;
+
+# Some magic numbers
+
+create table t1 (a bit(7), key(a));
+insert into t1 values (44), (57);
+select a+0 from t1;
+drop table t1;
+
+#
+# Test conversion to and from strings
+#
+create table t1 (a bit(3), b bit(12));
+insert into t1 values (7,(1<<12)-2), (0x01,0x01ff);
+select hex(a),hex(b) from t1;
+select hex(concat(a)),hex(concat(b)) from t1;
+drop table t1;
+
+#
+# Bug #9571: problem with primary key creation
+#
+
+create table t1(a int, b bit not null);
+alter table t1 add primary key (a);
+drop table t1;
+
+#
+# myisam <-> heap
+#
+
+create table t1 (a bit(19), b bit(5));
+insert into t1 values (1000, 10), (3, 8), (200, 6), (2303, 2), (12345, 4), (1, 0);
+select a+0, b+0 from t1;
+alter table t1 engine=heap;
+select a+0, b+0 from t1;
+alter table t1 add key(a, b);
+select a+0, b+0 from t1;
+alter table t1 engine=myisam;
+select a+0, b+0 from t1;
+create table t2 engine=heap select * from t1;
+select a+0, b+0 from t2;
+drop table t1;
+create table t1 select * from t2;
+select a+0, b+0 from t1;
+drop table t1, t2;
diff --git a/mysql-test/t/type_bit_innodb.test b/mysql-test/t/type_bit_innodb.test
new file mode 100644
index 00000000000..693fc169717
--- /dev/null
+++ b/mysql-test/t/type_bit_innodb.test
@@ -0,0 +1,135 @@
+--source include/have_innodb.inc
+#
+# testing of the BIT column type
+#
+
+select 0 + b'1';
+select 0 + b'0';
+select 0 + b'000001';
+select 0 + b'000011';
+select 0 + b'000101';
+select 0 + b'000000';
+select 0 + b'10000000';
+select 0 + b'11111111';
+select 0 + b'10000001';
+select 0 + b'1000000000000000';
+select 0 + b'1111111111111111';
+select 0 + b'1000000000000001';
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+--error 1074
+create table t1 (a bit(65)) engine=innodb;
+
+create table t1 (a bit(0)) engine=innodb;
+show create table t1;
+drop table t1;
+
+create table t1 (a bit(64)) engine=innodb;
+insert into t1 values
+(b'1111111111111111111111111111111111111111111111111111111111111111'),
+(b'1000000000000000000000000000000000000000000000000000000000000000'),
+(b'0000000000000000000000000000000000000000000000000000000000000001'),
+(b'1010101010101010101010101010101010101010101010101010101010101010'),
+(b'0101010101010101010101010101010101010101010101010101010101010101');
+select hex(a) from t1;
+drop table t1;
+
+create table t1 (a bit) engine=innodb;
+insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001');
+select hex(a) from t1;
+--error 1062
+alter table t1 add unique (a);
+drop table t1;
+
+create table t1 (a bit(2)) engine=innodb;
+insert into t1 values (b'00'), (b'01'), (b'10'), (b'100');
+select a+0 from t1;
+alter table t1 add key (a);
+explain select a+0 from t1;
+select a+0 from t1;
+drop table t1;
+
+create table t1 (a bit(7), b bit(9), key(a, b)) engine=innodb;
+insert into t1 values
+(94, 46), (31, 438), (61, 152), (78, 123), (88, 411), (122, 118), (0, 177),
+(75, 42), (108, 67), (79, 349), (59, 188), (68, 206), (49, 345), (118, 380),
+(111, 368), (94, 468), (56, 379), (77, 133), (29, 399), (9, 363), (23, 36),
+(116, 390), (119, 368), (87, 351), (123, 411), (24, 398), (34, 202), (28, 499),
+(30, 83), (5, 178), (60, 343), (4, 245), (104, 280), (106, 446), (127, 403),
+(44, 307), (68, 454), (57, 135);
+explain select a+0 from t1;
+select a+0 from t1;
+explain select b+0 from t1;
+select b+0 from t1;
+explain select a+0, b+0 from t1;
+select a+0, b+0 from t1;
+explain select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+select a+0, b+0 from t1 where a > 40 and b > 200 order by 1;
+explain select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+set @@max_length_for_sort_data=0;
+select a+0, b+0 from t1 where a > 40 and a < 70 order by 2;
+select hex(min(a)) from t1;
+select hex(min(b)) from t1;
+select hex(min(a)), hex(max(a)), hex(min(b)), hex(max(b)) from t1;
+drop table t1;
+
+create table t1 (a int not null, b bit, c bit(9), key(a, b, c)) engine=innodb;
+insert into t1 values
+(4, NULL, 1), (4, 0, 3), (2, 1, 4), (1, 1, 100), (4, 0, 23), (4, 0, 54),
+(56, 0, 22), (4, 1, 100), (23, 0, 1), (4, 0, 34);
+select a+0, b+0, c+0 from t1;
+select hex(min(b)) from t1 where a = 4;
+select hex(min(c)) from t1 where a = 4 and b = 0;
+select hex(max(b)) from t1;
+select a+0, b+0, c+0 from t1 where a = 4 and b = 0 limit 2;
+select a+0, b+0, c+0 from t1 where a = 4 and b = 1;
+select a+0, b+0, c+0 from t1 where a = 4 and b = 1 and c=100;
+select a+0, b+0, c+0 from t1 order by b desc;
+select a+0, b+0, c+0 from t1 order by c;
+drop table t1;
+
+create table t1(a bit(2), b bit(2)) engine=innodb;
+insert into t1 (a) values (0x01), (0x03), (0x02);
+update t1 set b= concat(a);
+select a+0, b+0 from t1;
+drop table t1;
+
+# Some magic numbers
+
+create table t1 (a bit(7), key(a)) engine=innodb;
+insert into t1 values (44), (57);
+select a+0 from t1;
+drop table t1;
+
+#
+# Test conversion to and from strings
+#
+create table t1 (a bit(3), b bit(12)) engine=innodb;
+insert into t1 values (7,(1<<12)-2), (0x01,0x01ff);
+select hex(a),hex(b) from t1;
+select hex(concat(a)),hex(concat(b)) from t1;
+drop table t1;
+
+#
+# Bug #9571: problem with primary key creation
+#
+
+create table t1(a int, b bit not null) engine=innodb;
+alter table t1 add primary key (a);
+drop table t1;
+
+#
+# altering tables
+#
+
+create table t1 (a bit, b bit(10)) engine=innodb;
+show create table t1;
+alter table t1 engine=heap;
+show create table t1;
+alter table t1 engine=innodb;
+show create table t1;
+drop table t1;
diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test
index b081c27cb30..c33ea3f435d 100644
--- a/mysql-test/t/type_blob.test
+++ b/mysql-test/t/type_blob.test
@@ -17,13 +17,13 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7;
CREATE TABLE t1 (a blob, b text, c blob(250), d text(70000), e text(70000000));
show columns from t1;
# PS doesn't give errors on prepare yet
---disable_ps_protocol
-CREATE TABLE t2 (a char(257), b varbinary(70000), c varchar(70000000));
---enable_ps_protocol
+CREATE TABLE t2 (a char(255), b varbinary(70000), c varchar(70000000));
+CREATE TABLE t4 (c varchar(65530) character set utf8 not null);
show columns from t2;
create table t3 (a long, b long byte);
show create TABLE t3;
-drop table t1,t2,t3
+show create TABLE t4;
+drop table t1,t2,t3,t4;
#
# Check errors with blob
@@ -31,6 +31,10 @@ drop table t1,t2,t3
--error 1074
CREATE TABLE t1 (a char(257) default "hello");
+--error 1074
+CREATE TABLE t2 (a char(256));
+--error 1074
+CREATE TABLE t1 (a varchar(70000) default "hello");
--error 1101
CREATE TABLE t2 (a blob default "hello");
@@ -300,7 +304,7 @@ drop table t1;
# Bug when blob is updated
#
-create table t1 (id integer auto_increment unique,imagem LONGBLOB not null);
+create table t1 (id integer auto_increment unique,imagem LONGBLOB not null default '');
insert into t1 (id) values (1);
# We have to clean up the path in the results for safe comparison
--replace_result $MYSQL_TEST_DIR ../..
@@ -326,10 +330,16 @@ drop table t1;
#
# Test blob's with end space (Bug #1651)
+# This is a bit changed since we now have true varchar
#
create table t1 (id integer primary key auto_increment, txt text not null, unique index txt_index (txt (20)));
+--error 1062
insert into t1 (txt) values ('Chevy'), ('Chevy ');
+--error 1062
+insert into t1 (txt) values ('Chevy'), ('CHEVY');
+alter table t1 drop index txt_index, add index txt_index (txt(20));
+insert into t1 (txt) values ('Chevy ');
select * from t1 where txt='Chevy';
select * from t1 where txt='Chevy ';
select * from t1 where txt='Chevy ' or txt='Chevy';
@@ -350,7 +360,7 @@ select * from t1 where txt > 'Chevy';
select * from t1 where txt >= 'Chevy';
drop table t1;
-create table t1 (id integer primary key auto_increment, txt text, unique index txt_index (txt (20)));
+create table t1 (id integer primary key auto_increment, txt text, index txt_index (txt (20)));
insert into t1 (txt) values ('Chevy'), ('Chevy '), (NULL);
select * from t1 where txt='Chevy' or txt is NULL;
explain select * from t1 where txt='Chevy' or txt is NULL;
diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test
index 414a06deaa9..f86113ac66b 100644
--- a/mysql-test/t/type_decimal.test
+++ b/mysql-test/t/type_decimal.test
@@ -1,7 +1,7 @@
# bug in decimal() with negative numbers by kaido@tradenet.ee
--disable_warnings
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
--enable_warnings
SET SQL_WARNINGS=1;
@@ -165,6 +165,8 @@ insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001");
insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11");
insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11");
insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000");
+insert into t1 values ("1e+4294967296"),("1e-4294967296");
+insert into t1 values ("1e+18446744073709551615"),("1e+18446744073709551616"),("1e-9223372036854775807"),("1e-9223372036854775809");
insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0");
select * from t1;
drop table t1;
@@ -201,6 +203,7 @@ insert into t1 values (+111111111.11),(111111111.11),(-11111111.11);
insert into t1 values (-111111111.11),(+1111111111.11),(1111111111.11);
insert into t1 values (1e+100),(1e-100),(-1e+100);
insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0);
+insert into t1 values (MID("987",1,2)),("987 "),("987.6e+2 ");
select * from t1;
drop table t1;
@@ -265,3 +268,106 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000
--enable_warnings
select * from t1;
drop table t1;
+
+# Test for BUG#8397: decimal type in subselects (Item_cache_decimal)
+CREATE TABLE t1
+(EMPNUM CHAR(3) NOT NULL,
+HOURS DECIMAL(5));
+CREATE TABLE t2
+(EMPNUM CHAR(3) NOT NULL,
+HOURS BIGINT);
+
+INSERT INTO t1 VALUES ('E1',40);
+INSERT INTO t1 VALUES ('E8',NULL);
+INSERT INTO t2 VALUES ('E1',40);
+
+SELECT EMPNUM FROM t1 WHERE HOURS IN (SELECT HOURS FROM t2);
+SELECT EMPNUM FROM t1 WHERE HOURS IN (SELECT HOURS FROM t1);
+
+DROP TABLE t1,t2;
+
+#
+# Test limits of decimal
+#
+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
+create table t1 (d decimal(65,0));
+
+#
+# Test example from manual
+#
+
+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),
+(2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
+(4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
+(5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
+(6, 0.00, 0.00), (6, -51.40, 0.00);
+
+SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1 GROUP BY i HAVING a <> b;
+SELECT i, ROUND(SUM(d1), 2) AS a, ROUND(SUM(d2), 2) AS b FROM t1 GROUP BY i
+HAVING a <> b;
+drop table t1;
+
+#
+# A test case for Bug#4956 "strange result, insert into longtext, parameter
+# with numeric value": ensure that conversion is done identically no matter
+# where the input data comes from.
+#
+create table t1 (c1 varchar(100), c2 longtext);
+insert into t1 set c1= 'non PS, 1.0 as constant', c2=1.0;
+prepare stmt from "insert into t1 set c1='PS, 1.0 as constant ', c2=1.0";
+execute stmt;
+set @a=1.0;
+insert into t1 set c1='non PS, 1.0 in parameter', c2=@a;
+prepare stmt from "insert into t1 set c1='PS, 1.0 in parameter ', c2=?";
+execute stmt using @a;
+select * from t1;
+deallocate prepare stmt;
+drop table t1;
+
+#
+# A test case for Bug#5673 "Rounding problem in 4.0.21 inserting decimal
+# value into a char field": this is a regression bug in 4.0 tree caused by
+# a fix for some other decimal conversion issue. The patch never was
+# approved to get into 4.0 (maybe because it was considered too intrusive)
+#
+
+create table t1 (
+ strippedproductid char(15) not null default '',
+ zlevelprice decimal(10,2) default null,
+ primary key (strippedproductid)
+);
+
+create table t2 (
+ productid char(15) not null default '',
+ zlevelprice char(21) default null,
+ primary key (productid)
+);
+
+insert into t1 values ('002trans','49.99');
+insert into t1 values ('003trans','39.98');
+insert into t1 values ('004trans','31.18');
+
+insert INTO t2 SELECT * FROM t1;
+
+select * from t2;
+drop table t1, t2;
diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
new file mode 100644
index 00000000000..e85cc3d55c6
--- /dev/null
+++ b/mysql-test/t/type_newdecimal.test
@@ -0,0 +1,871 @@
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+#
+# constant IN function test
+#
+select 1.1 IN (1.0, 1.2);
+select 1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5);
+select 1.1 IN (1.0, 1.2, NULL, 1.4, 0.5);
+select 0.5 IN (1.0, 1.2, NULL, 1.4, 0.5);
+select 1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5);
+select 1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5);
+
+#
+# case function test
+#
+select case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END;
+select case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END;
+select case 1 when 0.1 then "a" when 1.0 then "b" else "c" END;
+select case 1.0 when 0.1 then "a" when 1 then "b" else "c" END;
+select case 1.001 when 0.1 then "a" when 1 then "b" else "c" END;
+
+#
+# non constant IN test
+#
+create table t1 (a decimal(6,3));
+insert into t1 values (1.0), (NULL), (0.1);
+select * from t1;
+select 0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) from t1;
+drop table t1;
+
+#
+# if function test
+#
+create table t1 select if(1, 1.1, 1.2), if(0, 1.1, 1.2), if(0.1, 1.1, 1.2), if(0, 1, 1.1), if(0, NULL, 1.2), if(1, 0.22e1, 1.1), if(1E0, 1.1, 1.2);
+select * from t1;
+show create table t1;
+drop table t1;
+
+#
+# NULLIF
+#
+create table t1 select nullif(1.1, 1.1), nullif(1.1, 1.2), nullif(1.1, 0.11e1), nullif(1.0, 1), nullif(1, 1.0), nullif(1, 1.1);
+select * from t1;
+show create table t1;
+drop table t1;
+
+#
+# saving in decimal field with overflow
+#
+
+create table t1 (a decimal(4,2));
+insert into t1 value (10000), (1.1e10), ("11111"), (100000.1);
+insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1);
+select a from t1;
+drop table t1;
+create table t1 (a decimal(4,2) unsigned);
+insert into t1 value (10000), (1.1e10), ("11111"), (100000.1);
+insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1);
+select a from t1;
+drop table t1;
+
+
+#
+# saving in field with overflow from decimal
+#
+create table t1 (a bigint);
+insert into t1 values (18446744073709551615.0);
+insert into t1 values (9223372036854775808.0);
+insert into t1 values (-18446744073709551615.0);
+select * from t1;
+drop table t1;
+create table t1 (a bigint unsigned);
+insert into t1 values (18446744073709551615.0);
+insert into t1 values (9223372036854775808.0);
+insert into t1 values (9999999999999999999999999.000);
+insert into t1 values (-1.0);
+select * from t1;
+drop table t1;
+create table t1 (a tinyint);
+insert into t1 values (18446744073709551615.0);
+insert into t1 values (9223372036854775808.0);
+select * from t1;
+drop table t1;
+
+#
+# test that functions create decimal fields
+#
+create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(-1.1);
+show create table t1;
+drop table t1;
+
+#
+# Trydy's tests
+#
+set session sql_mode='traditional';
+select 1e10/0e0;
+create table wl1612 (col1 int, col2 decimal(38,10), col3 numeric(38,10));
+insert into wl1612 values(1,12345678901234567890.1234567890,12345678901234567890.1234567890);
+select * from wl1612;
+insert into wl1612 values(2,01234567890123456789.0123456789,01234567890123456789.0123456789);
+select * from wl1612 where col1=2;
+insert into wl1612 values(3,1234567890123456789012345678.0123456789,1234567890123456789012345678.0123456789);
+select * from wl1612 where col1=3;
+
+select col1/0 from wl1612;
+select col2/0 from wl1612;
+select col3/0 from wl1612;
+
+insert into wl1612 values(5,5000.0005,5000.0005);
+insert into wl1612 values(6,5000.0005,5000.0005);
+select sum(col2),sum(col3) from wl1612;
+#select avg(col2),avg(col3) from wl1612;
+
+insert into wl1612 values(7,500000.000005,500000.000005);
+insert into wl1612 values(8,500000.000005,500000.000005);
+select sum(col2),sum(col3) from wl1612 where col1>4;
+#select avg(col2),avg(col3) from wl1612 where col1>4;
+
+#insert into wl1612 (col1,col2) values(9,123456789012345678901234567890);
+#insert into wl1612 (col1,col3) values(9,123456789012345678901234567890);
+
+insert into wl1612 (col1, col2) values(9,1.01234567891);
+insert into wl1612 (col1, col2) values(10,1.01234567894);
+insert into wl1612 (col1, col2) values(11,1.01234567895);
+insert into wl1612 (col1, col2) values(12,1.01234567896);
+select col1,col2 from wl1612 where col1>8;
+
+insert into wl1612 (col1, col3) values(13,1.01234567891);
+insert into wl1612 (col1, col3) values(14,1.01234567894);
+insert into wl1612 (col1, col3) values(15,1.01234567895);
+insert into wl1612 (col1, col3) values(16,1.01234567896);
+select col1,col3 from wl1612 where col1>12;
+
+select col1 from wl1612 where col1>4 and col2=1.01234567891;
+#-- should return 0 rows
+#
+select col1 from wl1612 where col1>4 and col2=1.0123456789;
+#-- should return col1 values 9 & 10
+#
+select col1 from wl1612 where col1>4 and col2<>1.0123456789;
+#-- should return col1 values 5,6,7,8,11,12
+#
+select col1 from wl1612 where col1>4 and col2<1.0123456789;
+#-- should return 0 rows
+#
+select col1 from wl1612 where col1>4 and col2<=1.0123456789;
+#-- should return col1 values 9 & 10
+#
+select col1 from wl1612 where col1>4 and col2>1.0123456789;
+#-- should return col1 values 5,6,7,8,11,12
+#
+select col1 from wl1612 where col1>4 and col2>=1.0123456789;
+#-- should return col1 values 5,6,7,8,910,11,12
+#
+#select col1, col2 from wl1612 where col1=11 or col1=12;
+select col1 from wl1612 where col1>4 and col2=1.012345679;
+#-- should return col1 values 11,12
+#
+select col1 from wl1612 where col1>4 and col2<>1.012345679;
+#-- should return col1 values 5,6,7,8,9,10
+#
+select col1 from wl1612 where col1>4 and col3=1.01234567891;
+#-- should return 0 rows
+#
+select col1 from wl1612 where col1>4 and col3=1.0123456789;
+#-- should return col1 values 13,14
+#
+select col1 from wl1612 where col1>4 and col3<>1.0123456789;
+#-- should return col1 values 5,6,7,8,15,16
+#
+select col1 from wl1612 where col1>4 and col3<1.0123456789;
+#-- should return 0 rows
+#
+select col1 from wl1612 where col1>4 and col3<=1.0123456789;
+#-- should return col1 values 13,14
+#
+select col1 from wl1612 where col1>4 and col3>1.0123456789;
+#-- should return col1 values 5,6,7,8,15,16
+#
+select col1 from wl1612 where col1>4 and col3>=1.0123456789;
+#-- should return col1 values 5,6,7,8,13,14,15,16
+#
+select col1 from wl1612 where col1>4 and col3=1.012345679;
+#-- should return col1 values 15,16
+#
+select col1 from wl1612 where col1>4 and col3<>1.012345679;
+#-- should return col1 values 5,6,7,8,13,14
+#
+drop table wl1612;
+#
+select 1/3;
+#
+select 0.8=0.7+0.1;
+#-- should return 1 (true)
+#
+select 0.7+0.1;
+#
+create table wl1612_1 (col1 int);
+insert into wl1612_1 values(10);
+#
+select * from wl1612_1 where 0.8=0.7+0.1;
+#--should return 1 row (col1=10)
+#
+select 0.07+0.07 from wl1612_1;
+#
+select 0.07-0.07 from wl1612_1;
+#
+select 0.07*0.07 from wl1612_1;
+#
+select 0.07/0.07 from wl1612_1;
+#
+drop table wl1612_1;
+#
+create table wl1612_2 (col1 decimal(10,2), col2 numeric(10,2));
+insert into wl1612_2 values(1,1);
+insert into wl1612_2 values(+1,+1);
+insert into wl1612_2 values(+01,+01);
+insert into wl1612_2 values(+001,+001);
+#
+select col1,count(*) from wl1612_2 group by col1;
+#
+select col2,count(*) from wl1612_2 group by col2;
+#
+drop table wl1612_2;
+#
+create table wl1612_3 (col1 decimal(10,2), col2 numeric(10,2));
+insert into wl1612_3 values('1','1');
+insert into wl1612_3 values('+1','+1');
+#
+insert into wl1612_3 values('+01','+01');
+insert into wl1612_3 values('+001','+001');
+#
+select col1,count(*) from wl1612_3 group by col1;
+#
+select col2,count(*) from wl1612_3 group by col2;
+#
+drop table wl1612_3;
+#
+select mod(234,10) ;
+#-- should return 4
+#
+select mod(234.567,10.555);
+#-- should return 2.357
+#
+select mod(-234.567,10.555);
+#-- should return -2.357
+#
+select mod(234.567,-10.555);
+#-- should return 2.357
+#
+select round(15.1);
+#-- should return 15
+#
+select round(15.4);
+#-- should return 15
+#
+select round(15.5);
+#-- should return 16
+#
+select round(15.6);
+#-- should return 16
+#
+select round(15.9);
+#-- should return 16
+#
+select round(-15.1);
+#-- should return -15
+#
+select round(-15.4);
+#-- should return -15
+#
+select round(-15.5);
+#-- should return -16
+#
+select round(-15.6);
+#-- should return -16
+#
+select round(-15.9);
+#-- should return -16
+#
+select round(15.1,1);
+#-- should return 15.1
+#
+select round(15.4,1);
+#-- should return 15.4
+#
+select round(15.5,1);
+#-- should return 15.5
+#
+select round(15.6,1);
+#-- should return 15.6
+#
+select round(15.9,1);
+#-- should return 15.9
+#
+select round(-15.1,1);
+#-- should return -15.1
+#
+select round(-15.4,1);
+#-- should return -15.4
+#
+select round(-15.5,1);
+#-- should return -15.5
+#
+select round(-15.6,1);
+#-- should return -15.6
+#
+select round(-15.9,1);
+#-- should return -15.9
+#
+select round(15.1,0);
+#-- should return 15
+#
+select round(15.4,0);
+#-- should return 15
+#
+select round(15.5,0);
+#-- should return 16
+#
+select round(15.6,0);
+#-- should return 16
+#
+select round(15.9,0);
+#-- should return 16
+#
+select round(-15.1,0);
+#-- should return -15
+#
+select round(-15.4,0);
+#-- should return -15
+#
+select round(-15.5,0);
+#-- should return -16
+#
+select round(-15.6,0);
+#-- should return -16
+#
+select round(-15.9,0);
+#-- should return -16
+#
+select round(15.1,-1);
+#-- should return 20
+#
+select round(15.4,-1);
+#-- should return 20
+#
+select round(15.5,-1);
+#-- should return 20
+#
+select round(15.6,-1);
+#-- should return 20
+#
+select round(15.9,-1);
+#-- should return 20
+#
+select round(-15.1,-1);
+#-- should return -20
+#
+select round(-15.4,-1);
+#-- should return -20
+#
+select round(-15.5,-1);
+#-- should return -20
+#
+select round(-15.6,-1);
+#-- should return -20
+#
+select round(-15.91,-1);
+#-- should return -20
+#
+select truncate(5678.123451,0);
+#-- should return 5678
+#
+select truncate(5678.123451,1);
+#-- should return 5678.1
+#
+select truncate(5678.123451,2);
+#-- should return 5678.12
+#
+select truncate(5678.123451,3);
+#-- should return 5678.123
+#
+select truncate(5678.123451,4);
+#-- should return 5678.1234
+#
+select truncate(5678.123451,5);
+#-- should return 5678.12345
+#
+select truncate(5678.123451,6);
+#-- should return 5678.123451
+#
+select truncate(5678.123451,-1);
+#-- should return 5670
+#
+select truncate(5678.123451,-2);
+#-- should return 5600
+#
+select truncate(5678.123451,-3);
+#-- should return 5000
+#
+select truncate(5678.123451,-4);
+#-- should return 0
+#
+select truncate(-5678.123451,0);
+#-- should return -5678
+#
+select truncate(-5678.123451,1);
+#-- should return -5678.1
+#
+select truncate(-5678.123451,2);
+#-- should return -5678.12
+#
+select truncate(-5678.123451,3);
+#-- should return -5678.123
+#
+select truncate(-5678.123451,4);
+#-- should return -5678.1234
+#
+select truncate(-5678.123451,5);
+#-- should return -5678.12345
+#
+select truncate(-5678.123451,6);
+#-- should return -5678.123451
+#
+select truncate(-5678.123451,-1);
+#-- should return -5670
+#
+select truncate(-5678.123451,-2);
+#-- should return -5600
+#
+select truncate(-5678.123451,-3);
+#-- should return -5000
+#
+select truncate(-5678.123451,-4);
+#-- should return 0
+#
+#drop table if exists wl1612_4;
+create table wl1612_4 (col1 int, col2 decimal(30,25), col3 numeric(30,25));
+#
+insert into wl1612_4 values(1,0.0123456789012345678912345,0.0123456789012345678912345);
+#
+select col2/9999999999 from wl1612_4 where col1=1;
+#
+select col3/9999999999 from wl1612_4 where col1=1;
+#
+select 9999999999/col2 from wl1612_4 where col1=1;
+#
+select 9999999999/col3 from wl1612_4 where col1=1;
+#
+select col2*9999999999 from wl1612_4 where col1=1;
+#
+select col3*9999999999 from wl1612_4 where col1=1;
+#
+insert into wl1612_4 values(2,55555.0123456789012345678912345,55555.0123456789012345678912345);
+#
+select col2/9999999999 from wl1612_4 where col1=2;
+#
+select col3/9999999999 from wl1612_4 where col1=2;
+#
+select 9999999999/col2 from wl1612_4 where col1=2;
+#
+select 9999999999/col3 from wl1612_4 where col1=2;
+#
+select col2*9999999999 from wl1612_4 where col1=2;
+#
+select col3*9999999999 from wl1612_4 where col1=2;
+#
+drop table wl1612_4;
+#
+#
+#
+#
+#-- Additional tests for WL#1612 Precision math
+#
+#-- 1. Comparisons should show that a number is
+#-- exactly equal to its value as displayed.
+#
+set sql_mode='';
+#
+select 23.4 + (-41.7), 23.4 - (41.7) = -18.3;
+#
+select -18.3=-18.3;
+#
+select 18.3=18.3;
+#
+select -18.3=18.3;
+#
+select 0.8 = 0.7 + 0.1;
+#
+#-- 2. Adding (one millionth) one million times should be the same as
+#-- adding 1. So a stored procedure with many iterations will show if
+#-- small errors accumulate.
+#
+#drop procedure p1;
+#
+delimiter //
+#
+create procedure p1 () begin
+ declare v1, v2, v3, v4 decimal(16,12); declare v5 int;
+ set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0;
+ while v5 < 100000 do
+ set v1 = v1 + 0.000000000001; set v2 = v2 - 0.000000000001; set v3 = v3 + 1; set v4 = v4 - 1; set v5 = v5 + 1;
+ end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;//
+#
+call p1()//
+#-- should return
+# -- v1=1.0000001
+# -- v2=1.999999900000
+# -- v3=1.0000001
+# -- v4=1.999999900000
+#
+delimiter ;//
+#
+drop procedure p1;
+#
+#-- 3. It should be possible to define a column
+#-- with up to 38 digits precision either before
+#-- or after the decimal point. Any number which
+#-- is inserted, if it's within the range, should
+#-- be exactly the same as the number that gets
+#-- selected.
+#
+drop table if exists t1;
+#
+create table t1 (col1 decimal(38));
+#
+insert into t1 values (12345678901234567890123456789012345678);
+#
+select * from t1;
+#-- should return:
+#+----------------------------------------+
+#| col1 |
+#+----------------------------------------+
+#| 12345678901234567890123456789012345678 |
+#+----------------------------------------+
+#
+#drop table t1;
+#
+#create table t1 (col1 decimal(38,38));
+#
+#insert into t1 values (.12345678901234567890123456789012345678);
+#
+#select * from t1;
+#-- should return:
+#+------------------------------------------+
+#| col1 |
+#+------------------------------------------+
+#| 0.12345678901234567890123456789012345678 |
+#+------------------------------------------+
+#
+drop table t1;
+#
+create table t1 (col1 decimal(31,30));
+#
+insert into t1 values (0.00000000001);
+#
+select * from t1;
+#-- should return:
+#+---------------+
+#|col1 |
+#+---------------+
+#| 0.00000000001 |
+#+---------------+
+#
+drop table t1;
+#
+#-- 4. The usual arithmetic operators / * + - should work.
+#
+#select 77777777777777777777777777777777777777 / 7777777777777777777777777777777777777 = 10;
+#-- should return 0 (false).
+#
+select 7777777777777777777777777777777777777 * 10;
+#-- should return 77777777777777777777777777777777777770
+#
+select .7777777777777777777777777777777777777 *
+ 1000000000000000000;
+#-- should return 777777777777777777.7777777777777777777
+#
+select .7777777777777777777777777777777777777 - 0.1;
+#-- should return .6777777777777777777777777777777777777
+#
+select .343434343434343434 + .343434343434343434;
+#-- should return .686868686868686868
+#
+#-- 5. All arithmetic functions mentioned in the
+#MySQL Reference Manual should work.
+#
+select abs(9999999999999999999999);
+#-- should return 9999999999999999999999
+#
+select abs(-9999999999999999999999);
+#-- should return 9999999999999999999999
+#
+select ceiling(999999999999999999);
+select ceiling(99999999999999999999);
+#-- should return 99999999999999999999
+#
+select ceiling(9.9999999999999999999);
+#-- should return 10
+#
+select ceiling(-9.9999999999999999999);
+#-- should return 9
+#
+select floor(999999999999999999);
+select floor(9999999999999999999999);
+#-- should return 9999999999999999999999
+#
+select floor(9.999999999999999999999);
+#-- should return 9
+#
+select floor(-9.999999999999999999999);
+#-- should return -10
+#
+select floor(-999999999999999999999.999);
+select ceiling(999999999999999999999.999);
+#
+#
+select 99999999999999999999999999999999999999 mod 3;
+#-- should return 0
+#
+select round(99999999999999999.999);
+#-- should return 100000000000000000
+#
+select round(-99999999999999999.999);
+#-- should return -100000000000000000
+#
+select round(99999999999999999.999,3);
+#-- should return 100000000000000000.000
+#
+select round(-99999999999999999.999,3);
+#-- should return -100000000000000000.000
+#
+select truncate(99999999999999999999999999999999999999,31);
+#-- should return 99999999999999999999999999999999999999.000
+#
+select truncate(99.999999999999999999999999999999999999,31);
+#-- should return 99.9999999999999999999999999999999
+#
+select truncate(99999999999999999999999999999999999999,-31);
+-- should return 90000000000000000000000000000000
+#
+#-- 6. Set functions (AVG, SUM, COUNT) should work.
+#
+#drop table if exists t1;
+#
+#delimiter //
+#
+#create procedure p1 () begin
+# declare v1 int default 1; declare v2 decimal(0,38) default 0;
+# create table t1 (col1 decimal(0,38));
+# while v1 <= 10000 do
+# insert into t1 values (-v2);
+# set v2 = v2 + 0.00000000000000000000000000000000000001;
+# set v1 = v1 + 1;
+# end while;
+# select avg(col1),sum(col1),count(col1) from t1; end;//
+#
+#call p1()//
+#-- should return
+# -- avg(col1)=0.00000000000000000000000000000000000001 added 10,000 times, then divided by 10,000
+# -- sum(col1)=0.00000000000000000000000000000000000001 added 10,000 times
+#
+# -- count(col1)=10000
+#
+#delimiter ;//
+#
+#drop procedure p1;
+#drop table t1;
+#
+#-- 7. When I say DECIMAL(x) I should be able to store x digits.
+#-- If I can't, there should be an error at CREATE time.
+#
+#drop table if exists t1;
+#
+#create table t1 (col1 decimal(254));
+#-- should return SQLSTATE 22003 numeric value out of range
+#
+#-- 8. When I say DECIMAL(x,y) there should be no silent change of precision or scale.
+#
+#drop table if exists t1;
+#
+#create table t1 (col1 decimal(0,38));
+#
+#show create table t1;
+#-- should return:
+#+-------+--------------------------------+
+#| Table | Create Table |
+#+-------+--------------------------------+
+#| t9 | CREATE TABLE `t1` ( |
+#|`s1` decimal(0,38) default NULL |
+#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
+#+-------+--------------------------------+
+#
+#drop table t1;
+#
+#-- 9. From WL#1612 "The future" point 2.:
+#-- The standard requires that we treat numbers like "0.5" as
+#-- DECIMAL or NUMERIC, not as floating-point.
+#
+#drop table if exists t1;
+#
+#
+create table t1 as select 0.5;
+#
+show create table t1;
+#-- should return:
+#+-------+-----------------------------------+
+#| Table | Create Table |
+#+-------+-----------------------------------+
+#| t7 | CREATE TABLE `t1` ( |
+#| `0.5` decimal(3,1) NOT NULL default '0.0' |
+#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
+#+-------+-----------------------------------+
+#
+drop table t1;
+#
+#-- 10. From WL#1612, "The future", point 3.: We have to start rounding correctly.
+#
+select round(1.5),round(2.5);
+#-- should return:
+#+------------+------------+
+#| round(1.5) | round(2.5) |
+#+------------+------------+
+#| 2 | 3 |
+#+------------+------------+
+#
+#-- 11. From WL#1612, "The future", point 4.: "select 0.07 * 0.07;" should return 0.0049, not 0.00.
+#-- If operand#1 has scale X and operand#2 has scale Y, then result should have scale (X+Y).
+#
+select 0.07 * 0.07;
+#-- should return 0.0049
+#
+#-- 12. From WL#1612, "The future", point 5.: Division by zero is an error.
+#
+set sql_mode='traditional';
+#
+select 1E-500 = 0;
+#-- should return 1 (true).
+#
+select 1 / 1E-500;
+#
+#-- should return SQLSTATE 22012 division by zero.
+#
+select 1 / 0;
+#-- should return SQLSTATE 22012 division by zero.
+#
+#+-------+
+#| 1 / 0 |
+#+-------+
+#| NULL |
+#+-------+
+#1 row in set, 1 warning (0.00 sec)
+#
+#-- 13. From WL#1612 "The future" point 6.: Overflow is an error.
+#
+#set sql_mode='';
+#
+#select 1E300 * 1E300;
+#-- should return SQLSTATE 22003 numeric value out of range
+#
+#select 18446744073709551615 + 1;
+#-- should return SQLSTATE 22003 numeric value out of range
+#
+#-- 14. From WL#1612 "The future" point 7.:
+#-- If s1 is INTEGER and s2 is DECIMAL, then
+#-- "create table tk7 as select avg(s1),avg(s2) from tk;"
+#-- should not create a table with "double(17,4)" data types.
+#-- The result of AVG must still be exact numeric, with a
+#-- scale the same or greater than the operand's scale.
+#-- The result of SUM must still be exact numeric, with
+#-- a scale the same as the operand's scale.
+#
+#drop table if exists t1;
+#drop table if exists t2;
+#
+#create table t1 (col1 int, col2 decimal(5));
+#
+#create table t2 as select avg(col1),avg(col2) from t1;
+#
+#
+#show create table t2;
+#-- should return:
+#+-------+---------------------------------+
+#| Table | Create Table |
+#+-------+---------------------------------+
+#| t2 | CREATE TABLE `t2` ( |
+#| `avg(col1)` decimal(17,4) default NULL, |
+#| `avg(col2)` decimal(17,5) default NULL |
+#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
+#+-------+---------------------------------+
+#
+#drop table t2;
+#drop table t1;
+#
+#-- 15. From WL#1612 "The future" point 8.: Stop storing leading "+" signs and leading "0"s.
+#
+#drop table if exists t1;
+#
+#create table t1 (col1 decimal(5,2),col2 decimal(5) zerofill, col3 decimal(3,1));
+#
+#insert into t1 values (1,1,1);
+#
+#select col1 from t1 union select col2 from t1 union select col3 from t1;
+#
+#drop table t1;
+#
+#-- 16. From WL#1612, The future" point 9.:
+#-- Accept the data type and precision and scale as the user
+#-- asks, or return an error, but don't change to something else.
+#
+#drop table if exists t1;
+#
+#create table t1 (col1 numeric(4,2));
+#
+#show create table t1;
+#
+#drop table t1;
+#
+#-- 17. The scripts in the following bugs should work:
+#
+
+#BUG#559 Maximum precision for DECIMAL column ...
+#BUG#1499 INSERT/UPDATE into decimal field rounding problem
+#BUG#1845 Not correctly recognising value for decimal field
+#BUG#2493 Round function doesn't work correctly
+#BUG#2649 round(0.5) gives 0 (should be 1)
+#BUG#3612 impicite rounding of VARCHARS during aritchmetic operations...
+#BUG#3722 SELECT fails for certain values in Double(255,10) column.
+#BUG#4485 Floating point conversions are inconsistent
+#BUG#4891 MATH
+#BUG#5931 Out-of-range values are accepted
+#BUG#6048 Stored procedure causes operating system reboot
+#BUG#6053 DOUBLE PRECISION literal
+
+-- 18. Tests from 'traditional' mode tests
+#
+set sql_mode='ansi,traditional';
+#
+CREATE TABLE Sow6_2f (col1 NUMERIC(4,2));
+#-- should return OK
+INSERT INTO Sow6_2f VALUES (10.55);
+#-- should return OK
+INSERT INTO Sow6_2f VALUES (10.5555);
+#-- should return OK
+INSERT INTO Sow6_2f VALUES (-10.55);
+#-- should return OK
+INSERT INTO Sow6_2f VALUES (-10.5555);
+#-- should return OK
+INSERT INTO Sow6_2f VALUES (11);
+#-- should return OK
+-- error 1264
+INSERT INTO Sow6_2f VALUES (101.55);
+#-- should return SQLSTATE 22003 numeric value out of range
+-- error 1264
+UPDATE Sow6_2f SET col1 = col1 * 50 WHERE col1 = 11;
+#-- should return SQLSTATE 22003 numeric value out of range
+-- error 1365
+UPDATE Sow6_2f SET col1 = col1 / 0 WHERE col1 > 0;
+#-- should return SQLSTATE 22012 division by zero
+SELECT MOD(col1,0) FROM Sow6_2f;
+#-- should return SQLSTATE 22012 division by zero
+-- error 1366
+INSERT INTO Sow6_2f VALUES ('a59b');
+#-- should return SQLSTATE 22018 invalid character value for cast
+drop table Sow6_2f;
+
+#
+# bug#9501
+#
+select 10.3330000000000/12.34500000;
diff --git a/mysql-test/t/type_ranges.test b/mysql-test/t/type_ranges.test
index fb089cfd3df..a2deb367e14 100644
--- a/mysql-test/t/type_ranges.test
+++ b/mysql-test/t/type_ranges.test
@@ -28,10 +28,10 @@ CREATE TABLE t1 (
date_time datetime,
blob_col blob,
tinyblob_col tinyblob,
- mediumblob_col mediumblob not null,
- longblob_col longblob not null,
- options enum('one','two','tree') not null,
- flags set('one','two','tree') not null,
+ mediumblob_col mediumblob not null default '',
+ longblob_col longblob not null default '',
+ options enum('one','two','tree') not null ,
+ flags set('one','two','tree') not null default '',
PRIMARY KEY (auto),
KEY (utiny),
KEY (tiny),
@@ -71,7 +71,7 @@ ALTER TABLE t1
add new_field char(10) default "new" not null,
change blob_col new_blob_col varchar(20),
change date_field date_field char(10),
-alter column string set default "new default",
+alter column string set default "newdefault",
alter short drop default,
DROP INDEX utiny,
DROP INDEX ushort,
@@ -132,11 +132,11 @@ select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and not (t1.string<=>t2.
drop table t2;
-create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, "a" as t2, repeat("a",256) as t3, binary repeat("b",256) as t4 from t1;
+create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1;
# We mask out the Privileges column because it differs with embedded server
--replace_column 8 #
show full columns from t2;
-select * from t2;
+select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2;
drop table t1,t2;
create table t1 (c int);
diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test
index 3c7f07dfbce..01d18afc5af 100644
--- a/mysql-test/t/type_timestamp.test
+++ b/mysql-test/t/type_timestamp.test
@@ -29,6 +29,8 @@ INSERT INTO t1 VALUES ("my value", "myKey","1999-04-02 00:00:00");
SELECT stamp FROM t1 WHERE id="myKey";
UPDATE t1 SET value="my value" WHERE id="myKey";
SELECT stamp FROM t1 WHERE id="myKey";
+UPDATE t1 SET id="myKey" WHERE value="my value";
+SELECT stamp FROM t1 WHERE id="myKey";
drop table t1;
create table t1 (a timestamp);
diff --git a/mysql-test/t/type_varchar.test b/mysql-test/t/type_varchar.test
new file mode 100644
index 00000000000..2bffca6b889
--- /dev/null
+++ b/mysql-test/t/type_varchar.test
@@ -0,0 +1,120 @@
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+
+create table t1 (v varchar(30), c char(3), e enum('abc','def','ghi'), t text);
+system cp std_data/vchar.frm var/master-data/test/;
+truncate table vchar;
+show create table t1;
+show create table vchar;
+insert into t1 values ('abc', 'de', 'ghi', 'jkl');
+insert into t1 values ('abc ', 'de ', 'ghi', 'jkl ');
+insert into t1 values ('abc ', 'd ', 'ghi', 'jkl ');
+insert into vchar values ('abc', 'de', 'ghi', 'jkl');
+insert into vchar values ('abc ', 'de ', 'ghi', 'jkl ');
+insert into vchar values ('abc ', 'd ', 'ghi', 'jkl ');
+select length(v),length(c),length(e),length(t) from t1;
+select length(v),length(c),length(e),length(t) from vchar;
+alter table vchar add i int;
+show create table vchar;
+select length(v),length(c),length(e),length(t) from vchar;
+drop table t1, vchar;
+create table t1 (v varchar(20));
+insert into t1 values('a ');
+select v='a' from t1;
+select binary v='a' from t1;
+select binary v='a ' from t1;
+insert into t1 values('a');
+--error 1062
+alter table t1 add primary key (v);
+drop table t1;
+create table t1 (v varbinary(20));
+insert into t1 values('a');
+insert into t1 values('a ');
+alter table t1 add primary key (v);
+drop table t1;
+
+#
+# Test with varchar of lengths 254,255,256,258 & 258 to ensure we don't
+# have any problems with varchar with one or two byte length_bytes
+#
+
+create table t1 (v varchar(254), index (v));
+insert into t1 values ("This is a test ");
+insert into t1 values ("Some sample data");
+insert into t1 values (" garbage ");
+insert into t1 values (" This is a test ");
+insert into t1 values ("This is a test");
+insert into t1 values ("Hello world");
+insert into t1 values ("Foo bar");
+insert into t1 values ("This is a test");
+insert into t1 values ("MySQL varchar test");
+insert into t1 values ("test MySQL varchar");
+insert into t1 values ("This is a long string to have some random length data included");
+insert into t1 values ("Short string");
+insert into t1 values ("VSS");
+insert into t1 values ("Some samples");
+insert into t1 values ("Bar foo");
+insert into t1 values ("Bye");
+let $i= 255;
+let $j= 5;
+while ($j)
+{
+ select * from t1 where v like 'This is a test' order by v;
+ select * from t1 where v='This is a test' order by v;
+ select * from t1 where v like 'S%' order by v;
+ explain select * from t1 where v like 'This is a test' order by v;
+ explain select * from t1 where v='This is a test' order by v;
+ explain select * from t1 where v like 'S%' order by v;
+ eval alter table t1 change v v varchar($i);
+ inc $i;
+ dec $j;
+}
+let $i= 258;
+let $j= 6;
+while ($j)
+{
+ select * from t1 where v like 'This is a test' order by v;
+ select * from t1 where v='This is a test' order by v;
+ select * from t1 where v like 'S%' order by v;
+ explain select * from t1 where v like 'This is a test' order by v;
+ explain select * from t1 where v='This is a test' order by v;
+ explain select * from t1 where v like 'S%' order by v;
+ eval alter table t1 change v v varchar($i);
+ dec $i;
+ dec $j;
+}
+alter table t1 change v v varchar(254), drop key v;
+
+# Test with length(varchar) > 256 and key < 256 (to ensure things works with
+# different kind of packing
+
+alter table t1 change v v varchar(300), add key (v(10));
+select * from t1 where v like 'This is a test' order by v;
+select * from t1 where v='This is a test' order by v;
+select * from t1 where v like 'S%' order by v;
+explain select * from t1 where v like 'This is a test' order by v;
+explain select * from t1 where v='This is a test' order by v;
+explain select * from t1 where v like 'S%' order by v;
+drop table t1;
+
+#
+# bug#9339 - meaningless Field_varstring::get_key_image
+#
+create table t1 (pkcol varchar(16), othercol varchar(16), primary key (pkcol));
+insert into t1 values ('test', 'something');
+update t1 set othercol='somethingelse' where pkcol='test';
+select * from t1;
+drop table t1;
+
+#
+# Bug #9489: problems with key handling
+#
+
+create table t1 (a int, b varchar(12));
+insert into t1 values (1, 'A'), (22, NULL);
+create table t2 (a int);
+insert into t2 values (22), (22);
+select t1.a, t1.b, min(t1.b) from t1 inner join t2 ON t2.a = t1.a
+ group by t1.b, t1.a;
+drop table t1, t2;
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index b0446e1ea4a..239a7aaad4b 100644
--- a/mysql-test/t/union.test
+++ b/mysql-test/t/union.test
@@ -5,9 +5,6 @@
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6;
--enable_warnings
-# PS doesn't work correctly with found_rows: to be fixed
---disable_ps_protocol
-
CREATE TABLE t1 (a int not null, b char (10) not null);
insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c');
@@ -30,9 +27,12 @@ select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 g
(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b;
explain extended (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc;
(select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2;
+# PS doesn't work correctly with found_rows: to be fixed
+--disable_ps_protocol
select found_rows();
select sql_calc_found_rows a,b from t1 union all select a,b from t2 limit 2;
select found_rows();
+--enable_ps_protocol
#
# Test some error conditions with UNION
@@ -210,15 +210,27 @@ insert into t2 values (3),(4),(5);
# Test global limits
(SELECT SQL_CALC_FOUND_ROWS * FROM t1) UNION all (SELECT * FROM t2) LIMIT 1;
+# PS doesn't work correctly with found_rows: to be fixed
+--disable_ps_protocol
select found_rows();
+--enable_ps_protocol
(SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION all (SELECT * FROM t2) LIMIT 2;
+# PS doesn't work correctly with found_rows: to be fixed
+--disable_ps_protocol
select found_rows();
+--enable_ps_protocol
# Test cases where found_rows() should return number of returned rows
(SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION all (SELECT * FROM t2);
+# PS doesn't work correctly with found_rows: to be fixed
+--disable_ps_protocol
select found_rows();
+--enable_ps_protocol
(SELECT SQL_CALC_FOUND_ROWS * FROM t1) UNION all (SELECT * FROM t2 LIMIT 1);
+# PS doesn't work correctly with found_rows: to be fixed
+--disable_ps_protocol
select found_rows();
+--enable_ps_protocol
# This used to work in 4.0 but not anymore in 4.1
--error 1064
(SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION SELECT * FROM t2 LIMIT 1;
@@ -226,9 +238,15 @@ select found_rows();
# In these case found_rows() should work
SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION all SELECT * FROM t2 LIMIT 2;
+# PS doesn't work correctly with found_rows: to be fixed
+--disable_ps_protocol
select found_rows();
+--disable_ps_protocol
SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION all SELECT * FROM t2 LIMIT 2;
+# PS doesn't work correctly with found_rows: to be fixed
+--disable_ps_protocol
select found_rows();
+--disable_ps_protocol
# The following examples will not be exact
SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2;
@@ -742,3 +760,15 @@ create table t2 select a from t1 union select c from t1;
create table t2 select a from t1 union select b from t1;
show columns from t2;
drop table t2, t1;
+
+#
+# Test that union with VARCHAR produces dynamic row tables
+#
+
+create table t1 (a varchar(5));
+create table t2 select * from t1 union select 'abcdefghijkl';
+show create table t2;
+select row_format from information_schema.TABLES where table_schema="test" and table_name="t2";
+alter table t2 ROW_FORMAT=fixed;
+show create table t2;
+drop table t1,t2;
diff --git a/mysql-test/t/user_limits.test b/mysql-test/t/user_limits.test
new file mode 100644
index 00000000000..af0f6545ac4
--- /dev/null
+++ b/mysql-test/t/user_limits.test
@@ -0,0 +1,169 @@
+#
+# Test behavior of various per-account limits (aka quotas)
+#
+
+# Requires privileges to be enabled
+-- source include/not_embedded.inc
+
+# Prepare play-ground
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (i int);
+# Just be sure that nothing will bother us
+delete from mysql.user where user like 'mysqltest\_%';
+delete from mysql.db where user like 'mysqltest\_%';
+delete from mysql.tables_priv where user like 'mysqltest\_%';
+delete from mysql.columns_priv where user like 'mysqltest\_%';
+flush privileges;
+
+# Limits doesn't work with prepared statements (yet)
+--disable_ps_protocol
+
+# Test of MAX_QUERIES_PER_HOUR limit
+grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 2;
+# This ensures that counters are reset and makes test scheduling independent
+flush user_resources;
+connect (mqph, localhost, mysqltest_1,,);
+connection mqph;
+select * from t1;
+select * from t1;
+--error 1226
+select * from t1;
+connect (mqph2, localhost, mysqltest_1,,);
+connection mqph2;
+--error 1226
+select * from t1;
+# cleanup
+connection default;
+drop user mysqltest_1@localhost;
+disconnect mqph;
+disconnect mqph2;
+
+# Test of MAX_UPDATES_PER_HOUR limit
+grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 2;
+flush user_resources;
+connect (muph, localhost, mysqltest_1,,);
+connection muph;
+select * from t1;
+select * from t1;
+select * from t1;
+delete from t1;
+delete from t1;
+--error 1226
+delete from t1;
+select * from t1;
+connect (muph2, localhost, mysqltest_1,,);
+connection muph2;
+--error 1226
+delete from t1;
+select * from t1;
+# Cleanup
+connection default;
+drop user mysqltest_1@localhost;
+disconnect muph;
+disconnect muph2;
+
+# Test of MAX_CONNECTIONS_PER_HOUR limit
+grant usage on *.* to mysqltest_1@localhost with max_connections_per_hour 2;
+flush user_resources;
+connect (mcph1, localhost, mysqltest_1,,);
+connection mcph1;
+select * from t1;
+connect (mcph2, localhost, mysqltest_1,,);
+connection mcph2;
+select * from t1;
+--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
+--error 1226
+connect (mcph3, localhost, mysqltest_1,,);
+# Old connection is still ok
+select * from t1;
+# Let us try to close old connections and try again. This will also test that
+# counters are not thrown away if there are no connections for this user.
+disconnect mcph1;
+disconnect mcph2;
+--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
+--error 1226
+connect (mcph3, localhost, mysqltest_1,,);
+# Cleanup
+connection default;
+drop user mysqltest_1@localhost;
+
+# Test of MAX_USER_CONNECTIONS limit
+# We need this to reset internal mqh_used variable
+flush privileges;
+grant usage on *.* to mysqltest_1@localhost with max_user_connections 2;
+flush user_resources;
+connect (muc1, localhost, mysqltest_1,,);
+connection muc1;
+select * from t1;
+connect (muc2, localhost, mysqltest_1,,);
+connection muc2;
+select * from t1;
+--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
+--error 1226
+connect (muc3, localhost, mysqltest_1,,);
+# Closing of one of connections should help
+disconnect muc1;
+connect (muc3, localhost, mysqltest_1,,);
+select * from t1;
+# Changing of limit should also help (and immediately)
+connection default;
+grant usage on *.* to mysqltest_1@localhost with max_user_connections 3;
+flush user_resources;
+connect (muc4, localhost, mysqltest_1,,);
+connection muc4;
+select * from t1;
+--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
+--error 1226
+connect (muc5, localhost, mysqltest_1,,);
+# Clean up
+connection default;
+disconnect muc2;
+disconnect muc3;
+disconnect muc4;
+drop user mysqltest_1@localhost;
+
+# Now let us test interaction between global and per-account
+# max_user_connections limits
+select @@session.max_user_connections, @@global.max_user_connections;
+# Local max_user_connections variable can't be set directly
+# since this limit is per-account
+--error 1229
+set session max_user_connections= 2;
+# But it is ok to set global max_user_connections
+set global max_user_connections= 2;
+select @@session.max_user_connections, @@global.max_user_connections;
+# Let us check that global limit works
+grant usage on *.* to mysqltest_1@localhost;
+flush user_resources;
+connect (muca1, localhost, mysqltest_1,,);
+connection muca1;
+select @@session.max_user_connections, @@global.max_user_connections;
+connect (muca2, localhost, mysqltest_1,,);
+connection muca2;
+select * from t1;
+--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
+--error 1203
+connect (muca3, localhost, mysqltest_1,,);
+# Now we are testing that per-account limit prevails over gloabl limit
+connection default;
+grant usage on *.* to mysqltest_1@localhost with max_user_connections 3;
+flush user_resources;
+connect (muca3, localhost, mysqltest_1,,);
+connection muca3;
+select @@session.max_user_connections, @@global.max_user_connections;
+--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
+--error 1226
+connect (muca4, localhost, mysqltest_1,,);
+# Cleanup
+connection default;
+disconnect muca1;
+disconnect muca2;
+disconnect muca3;
+set global max_user_connections= 0;
+drop user mysqltest_1@localhost;
+--enable_ps_protocol
+
+# Final cleanup
+drop table t1;
diff --git a/mysql-test/t/user_var-binlog.test b/mysql-test/t/user_var-binlog.test
index 8b11ea735ad..916a7dfa47b 100644
--- a/mysql-test/t/user_var-binlog.test
+++ b/mysql-test/t/user_var-binlog.test
@@ -10,7 +10,7 @@ INSERT INTO t1 VALUES(@`a b`);
set @var1= "';aaa";
SET @var2=char(ascii('a'));
insert into t1 values (@var1),(@var2);
-show binlog events from 79;
+show binlog events from 98;
# more important than SHOW BINLOG EVENTS, mysqlbinlog (where we
# absolutely need variables names to be quoted and strings to be
# escaped).
diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test
index a288b7ef708..b9d06558f34 100644
--- a/mysql-test/t/user_var.test
+++ b/mysql-test/t/user_var.test
@@ -20,6 +20,7 @@ insert into t2 select distinct i from t1;
select * from t2;
select distinct t2.i,@vv1:=if(sv1.i,1,0),@vv2:=if(sv2.i,1,0),@vv3:=if(sv3.i,1,0), @vv1+@vv2+@vv3 from t2 left join t1 as sv1 on sv1.i=t2.i and sv1.v=1 left join t1 as sv2 on sv2.i=t2.i and sv2.v=2 left join t1 as sv3 on sv3.i=t2.i and sv3.v=3;
explain select * from t1 where i=@vv1;
+select @vv1,i,v from t1 where i=@vv1;
explain select * from t1 where @vv1:=@vv1+1 and i=@vv1;
explain select @vv1:=i from t1 where i=@vv1;
explain select * from t1 where i=@vv1;
@@ -115,7 +116,32 @@ select coercibility(@v1),coercibility(@v2),coercibility(@v3),coercibility(@v4);
#
# Bug #9286 SESSION/GLOBAL should be disallowed for user variables
#
---error 1064
set session @honk=99;
---error 1105
+--error 1382
set one_shot @honk=99;
+
+#
+# Bug #6598: problem with cast(NULL as signed integer);
+#
+
+set @first_var= NULL;
+create table t1 select @first_var;
+show create table t1;
+drop table t1;
+set @first_var= cast(NULL as signed integer);
+create table t1 select @first_var;
+show create table t1;
+drop table t1;
+set @first_var= NULL;
+create table t1 select @first_var;
+show create table t1;
+drop table t1;
+set @first_var= concat(NULL);
+create table t1 select @first_var;
+show create table t1;
+drop table t1;
+set @first_var=1;
+set @first_var= cast(NULL as CHAR);
+create table t1 select @first_var;
+show create table t1;
+drop table t1;
diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test
index 50bcc1c038c..9931b72599f 100644
--- a/mysql-test/t/variables.test
+++ b/mysql-test/t/variables.test
@@ -5,8 +5,20 @@
drop table if exists t1,t2;
--enable_warnings
-set @`test`=1,@TEST=3,@select=2,@t5=1.23456;
-select @test,@`select`,@TEST,@not_used;
+# case insensitivity tests (new in 5.0)
+set @`test`=1;
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+set @TEST=2;
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+set @"tEST"=3;
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+set @`TeST`=4;
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+select @`teST`:=5;
+select @test, @`test`, @TEST, @`TEST`, @"teSt";
+
+set @select=2,@t5=1.23456;
+select @`select`,@not_used;
set @test_int=10,@test_double=1e-10,@test_string="abcdeghi",@test_string2="abcdefghij",@select=NULL;
--replace_result e-0 e- e+0 e+
select @test_int,@test_double,@test_string,@test_string2,@select;
@@ -71,6 +83,12 @@ show variables like 'concurrent_insert';
set global concurrent_insert=DEFAULT;
show variables like 'concurrent_insert';
+set global timed_mutexes=1;
+show variables like 'timed_mutexes';
+set global timed_mutexes=0;
+show variables like 'timed_mutexes';
+
+
set storage_engine=MYISAM, storage_engine="HEAP", global storage_engine="MERGE";
show local variables like 'storage_engine';
show global variables like 'storage_engine';
@@ -348,8 +366,8 @@ show create table t1;
drop table t1;
#
# What types and widths have variables?
-set @arg00= 8, @arg01= 8.8, @arg02= 'a string';
-create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3;
+set @arg00= 8, @arg01= 8.8, @arg02= 'a string', @arg03= 0.2e0;
+create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3, @arg03 as c4;
show create table t1;
drop table t1;
@@ -368,3 +386,12 @@ SHOW VARIABLES LIKE 'MYISAM_DATA_POINTER_SIZE';
SET GLOBAL table_cache=-1;
SHOW VARIABLES LIKE 'table_cache';
SET GLOBAL table_cache=DEFAULT;
+
+#
+# Bug#6282 Packet error with SELECT INTO
+#
+create table t1 (a int);
+select a into @x from t1;
+show warnings;
+drop table t1;
+
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
new file mode 100644
index 00000000000..0303605a9ef
--- /dev/null
+++ b/mysql-test/t/view.test
@@ -0,0 +1,1535 @@
+--disable_warnings
+drop table if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6;
+drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6;
+drop database if exists mysqltest;
+--enable_warnings
+use test;
+
+#
+# some basic test of views and its functionality
+#
+
+# create view on nonexistent table
+-- error 1146
+create view v1 (c,d) as select a,b from t1;
+
+create temporary table t1 (a int, b int);
+# view on temporary table
+-- error 1352
+create view v1 (c) as select b+1 from t1;
+drop table t1;
+
+create table t1 (a int, b int);
+insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
+
+# view with variable
+-- error 1351
+create view v1 (c,d) as select a,b+@@global.max_user_connections from t1;
+
+# simple view
+create view v1 (c) as select b+1 from t1;
+select c from v1;
+
+# temporary table should not hide table of view
+create temporary table t1 (a int, b int);
+# this is empty
+select * from t1;
+# but this based on normal t1
+select c from v1;
+show create table v1;
+show create view v1;
+-- error 1347
+show create view t1;
+drop table t1;
+
+# try to use fields from underlying table
+-- error 1054
+select a from v1;
+-- error 1054
+select v1.a from v1;
+-- error 1054
+select b from v1;
+-- error 1054
+select v1.b from v1;
+
+# view with different algorithms (explain output differs)
+explain extended select c from v1;
+create algorithm=temptable view v2 (c) as select b+1 from t1;
+show create view v2;
+select c from v2;
+explain extended select c from v2;
+
+# try to use underlying table fields in VIEW creation process
+-- error 1054
+create view v3 (c) as select a+1 from v1;
+-- error 1054
+create view v3 (c) as select b+1 from v1;
+
+
+# VIEW on VIEW test with mixing different algorithms on different order
+create view v3 (c) as select c+1 from v1;
+select c from v3;
+explain extended select c from v3;
+create algorithm=temptable view v4 (c) as select c+1 from v2;
+select c from v4;
+explain extended select c from v4;
+create view v5 (c) as select c+1 from v2;
+select c from v5;
+explain extended select c from v5;
+create algorithm=temptable view v6 (c) as select c+1 from v1;
+select c from v6;
+explain extended select c from v6;
+
+# show table/table status test
+show tables;
+show full tables;
+--replace_column 12 # 13 #
+--replace_result 2147483647 38654705663
+show table status;
+
+drop view v1,v2,v3,v4,v5,v6;
+
+#
+# alter/create view test
+#
+
+# view with subqueries of different types
+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;
+create view v2 as select c, d from v1;
+select * from v1;
+select * from v2;
+
+# try to create VIEW with name of existing VIEW
+-- error 1050
+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;
+
+# 'or replace' should work in this case
+create or replace 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;
+
+# try to ALTER unexisting VIEW
+drop view v2;
+-- error 1146
+alter view v2 as select c, d from v1;
+
+# 'or replace' on unexisting view
+create or replace view v2 as select c, d from v1;
+
+# alter view on existing view
+alter view v1 (c,d) as select a,max(b) from t1 group by a;
+
+# check that created view works
+select * from v1;
+select * from v2;
+
+# try to drop nonexistent VIEW
+-- error 1051
+drop view v100;
+
+# try to drop table with DROP VIEW
+-- error 1347
+drop view t1;
+
+# try to drop VIEW with DROP TABLE
+-- error 1051
+drop table v1;
+
+# try to drop table with DROP VIEW
+
+drop view v1,v2;
+drop table t1;
+
+#
+# outer left join with merged views
+#
+create table t1 (a int);
+insert into t1 values (1), (2), (3);
+
+create view v1 (a) as select a+1 from t1;
+create view v2 (a) as select a-1 from t1;
+
+select * from t1 natural left join v1;
+select * from v2 natural left join t1;
+select * from v2 natural left join v1;
+
+drop view v1, v2;
+drop table t1;
+
+
+#
+# DISTINCT option for VIEW
+#
+create table t1 (a int);
+insert into t1 values (1), (2), (3), (1), (2), (3);
+create view v1 as select distinct a from t1;
+select * from v1;
+explain select * from v1;
+select * from t1;
+drop view v1;
+drop table t1;
+
+#
+# syntax compatibility
+#
+create table t1 (a int);
+-- error 1368
+create view v1 as select distinct a from t1 WITH CHECK OPTION;
+create view v1 as select a from t1 WITH CHECK OPTION;
+create view v2 as select a from t1 WITH CASCADED CHECK OPTION;
+create view v3 as select a from t1 WITH LOCAL CHECK OPTION;
+drop view v3 RESTRICT;
+drop view v2 CASCADE;
+drop view v1;
+drop table t1;
+
+#
+# aliases
+#
+create table t1 (a int, b int);
+insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
+create view v1 (c) as select b+1 from t1;
+select test.c from v1 test;
+create algorithm=temptable view v2 (c) as select b+1 from t1;
+select test.c from v2 test;
+select test1.* from v1 test1, v2 test2 where test1.c=test2.c;
+select test2.* from v1 test1, v2 test2 where test1.c=test2.c;
+drop table t1;
+drop view v1,v2;
+
+#
+# LIMIT clause test
+#
+create table t1 (a int);
+insert into t1 values (1), (2), (3), (4);
+create view v1 as select a+1 from t1 order by 1 desc limit 2;
+select * from v1;
+explain select * from v1;
+drop view v1;
+drop table t1;
+
+#
+# CREATE ... SELECT view test
+#
+create table t1 (a int);
+insert into t1 values (1), (2), (3), (4);
+create view v1 as select a+1 from t1;
+create table t2 select * from v1;
+show columns from t2;
+select * from t2;
+drop view v1;
+drop table t1,t2;
+
+#
+# simple view + simple update
+#
+create table t1 (a int, b int, primary key(a));
+insert into t1 values (10,2), (20,3), (30,4), (40,5), (50,10);
+create view v1 (a,c) as select a, b+1 from t1;
+create algorithm=temptable view v2 (a,c) as select a, b+1 from t1;
+# try to update expression
+-- error 1348
+update v1 set c=a+c;
+# try to update VIEW with forced TEMPORARY TABLE algorithm
+-- error 1288
+update v2 set a=a+c;
+# updatable field of updateable view
+update v1 set a=a+c;
+select * from v1;
+select * from t1;
+drop table t1;
+drop view v1,v2;
+
+#
+# simple view + simple multi-update
+#
+create table t1 (a int, b int, primary key(a));
+insert into t1 values (10,2), (20,3), (30,4), (40,5), (50,10);
+create table t2 (x int);
+insert into t2 values (10), (20);
+create view v1 (a,c) as select a, b+1 from t1;
+create algorithm=temptable view v2 (a,c) as select a, b+1 from t1;
+# try to update expression
+-- error 1348
+update t2,v1 set v1.c=v1.a+v1.c where t2.x=v1.a;
+# try to update VIEW with forced TEMPORARY TABLE algorithm
+-- error 1288
+update t2,v2 set v2.a=v2.v2.a+c where t2.x=v2.a;
+# updatable field of updateable view
+update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.a;
+select * from v1;
+select * from t1;
+drop table t1,t2;
+drop view v1,v2;
+
+#
+# MERGE VIEW with WHERE clause
+#
+create table t1 (a int, b int, primary key(b));
+insert into t1 values (1,20), (2,30), (3,40), (4,50), (5,100);
+create view v1 (c) as select b from t1 where a<3;
+# simple select and explaint to be sure that it is MERGE
+select * from v1;
+explain extended select * from v1;
+# update test
+update v1 set c=c+1;
+select * from t1;
+# join of such VIEWs test
+create view v2 (c) as select b from t1 where a>=3;
+select * from v1, v2;
+drop view v1, v2;
+drop table t1;
+
+#
+# simple view + simple delete
+#
+create table t1 (a int, b int, primary key(a));
+insert into t1 values (1,2), (2,3), (3,4), (4,5), (5,10);
+create view v1 (a,c) as select a, b+1 from t1;
+create algorithm=temptable view v2 (a,c) as select a, b+1 from t1;
+# try to update VIEW with forced TEMPORARY TABLE algorithm
+-- error 1288
+delete from v2 where c < 4;
+# updatable field of updateable view
+delete from v1 where c < 4;
+select * from v1;
+select * from t1;
+drop table t1;
+drop view v1,v2;
+
+#
+# simple view + simple multi-delete
+#
+create table t1 (a int, b int, primary key(a));
+insert into t1 values (1,2), (2,3), (3,4), (4,5), (5,10);
+create table t2 (x int);
+insert into t2 values (1), (2), (3), (4);
+create view v1 (a,c) as select a, b+1 from t1;
+create algorithm=temptable view v2 (a,c) as select a, b+1 from t1;
+# try to update VIEW with forced TEMPORARY TABLE algorithm
+-- error 1288
+delete v2 from t2,v2 where t2.x=v2.a;
+# updatable field of updateable view
+delete v1 from t2,v1 where t2.x=v1.a;
+select * from v1;
+select * from t1;
+drop table t1,t2;
+drop view v1,v2;
+
+#
+# key presence check
+#
+create table t1 (a int, b int, c int, primary key(a,b));
+insert into t1 values (10,2,-1), (20,3,-2), (30,4,-3), (40,5,-4), (50,10,-5);
+create view v1 (x,y) as select a, b from t1;
+create view v2 (x,y) as select a, c from t1;
+set updatable_views_with_limit=NO;
+update v1 set x=x+1;
+update v2 set x=x+1;
+update v1 set x=x+1 limit 1;
+-- error 1288
+update v2 set x=x+1 limit 1;
+set updatable_views_with_limit=YES;
+update v1 set x=x+1 limit 1;
+update v2 set x=x+1 limit 1;
+set updatable_views_with_limit=DEFAULT;
+show variables like "updatable_views_with_limit";
+select * from t1;
+drop table t1;
+drop view v1,v2;
+
+#
+# simple insert
+#
+create table t1 (a int, b int, c int, primary key(a,b));
+insert into t1 values (10,2,-1), (20,3,-2);
+create view v1 (x,y,z) as select c, b, a from t1;
+create view v2 (x,y) as select b, a from t1;
+create view v3 (x,y,z) as select b, a, b from t1;
+create view v4 (x,y,z) as select c+1, b, a from t1;
+create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
+# try insert to VIEW with fields duplicate
+-- error 1288
+insert into v3 values (-60,4,30);
+# try insert to VIEW with expression in SELECT list
+-- error 1288
+insert into v4 values (-60,4,30);
+# try insert to VIEW using temporary table algorithm
+-- error 1288
+insert into v5 values (-60,4,30);
+insert into v1 values (-60,4,30);
+insert into v1 (z,y,x) values (50,6,-100);
+insert into v2 values (5,40);
+select * from t1;
+drop table t1;
+drop view v1,v2,v3,v4,v5;
+
+#
+# insert ... select
+#
+create table t1 (a int, b int, c int, primary key(a,b));
+insert into t1 values (10,2,-1), (20,3,-2);
+create table t2 (a int, b int, c int, primary key(a,b));
+insert into t2 values (30,4,-60);
+create view v1 (x,y,z) as select c, b, a from t1;
+create view v2 (x,y) as select b, a from t1;
+create view v3 (x,y,z) as select b, a, b from t1;
+create view v4 (x,y,z) as select c+1, b, a from t1;
+create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
+# try insert to VIEW with fields duplicate
+-- error 1288
+insert into v3 select c, b, a from t2;
+# try insert to VIEW with expression in SELECT list
+-- error 1288
+insert into v4 select c, b, a from t2;
+# try insert to VIEW using temporary table algorithm
+-- error 1288
+insert into v5 select c, b, a from t2;
+insert into v1 select c, b, a from t2;
+insert into v1 (z,y,x) select a+20,b+2,-100 from t2;
+insert into v2 select b+1, a+10 from t2;
+select * from t1;
+drop table t1, t2;
+drop view v1,v2,v3,v4,v5;
+
+#
+# outer join based on VIEW with WHERE clause
+#
+create table t1 (a int, primary key(a));
+insert into t1 values (1), (2), (3);
+create view v1 (x) as select a from t1 where a > 1;
+select t1.a, v1.x from t1 left join v1 on (t1.a= v1.x);
+drop table t1;
+drop view v1;
+
+#
+# merging WHERE condition on VIEW on VIEW
+#
+create table t1 (a int, primary key(a));
+insert into t1 values (1), (2), (3), (200);
+create view v1 (x) as select a from t1 where a > 1;
+create view v2 (y) as select x from v1 where x < 100;
+select * from v2;
+drop table t1;
+drop view v1,v2;
+
+#
+# VIEW on non-updatable view
+#
+create table t1 (a int, primary key(a));
+insert into t1 values (1), (2), (3), (200);
+create ALGORITHM=TEMPTABLE view v1 (x) as select a from t1;
+create view v2 (y) as select x from v1;
+-- error 1288
+update v2 set y=10 where y=2;
+drop table t1;
+drop view v1,v2;
+
+#
+# auto_increment field out of VIEW
+#
+create table t1 (a int not null auto_increment, b int not null, primary key(a), unique(b));
+create view v1 (x) as select b from t1;
+insert into v1 values (1);
+select last_insert_id();
+insert into t1 (b) values (2);
+select last_insert_id();
+select * from t1;
+drop view v1;
+drop table t1;
+
+#
+# VIEW fields quoting
+#
+set sql_mode='ansi';
+create table t1 ("a*b" int);
+create view v1 as select "a*b" from t1;
+show create view v1;
+drop view v1;
+drop table t1;
+set sql_mode=default;
+
+#
+# VIEW without tables
+#
+create table t1 (t_column int);
+create view v1 as select 'a';
+select * from v1, t1;
+drop view v1;
+drop table t1;
+
+#
+# quote mark inside table name
+#
+create table `t1a``b` (col1 char(2));
+create view v1 as select * from `t1a``b`;
+select * from v1;
+describe v1;
+drop view v1;
+drop table `t1a``b`;
+
+#
+# Changing of underlying table
+#
+create table t1 (col1 char(5),col2 char(5));
+create view v1 as select * from t1;
+drop table t1;
+create table t1 (col1 char(5),newcol2 char(5));
+-- error 1356
+insert into v1 values('a','aa');
+drop table t1;
+-- error 1356
+select * from v1;
+drop view v1;
+
+#
+# check of duplication of column names
+#
+-- error 1060
+create view v1 (a,a) as select 'a','a';
+
+#
+# SP variables inside view test
+#
+# QQ This can't be tested with the new table locking for functions,
+# QQ since views created in an SP can't be used within the same SP
+# QQ (just as for tables). Instead it fails with error 1146.
+#delimiter //;
+#create procedure p1 () begin declare v int; create view v1 as select v; end;//
+#delimiter ;//
+#-- error 1351
+#call p1();
+#drop procedure p1;
+
+#
+# updatablity should be transitive
+#
+create table t1 (col1 int,col2 char(22));
+insert into t1 values(5,'Hello, world of views');
+create view v1 as select * from t1;
+create view v2 as select * from v1;
+update v2 set col2='Hello, view world';
+select * from t1;
+drop view v2, v1;
+drop table t1;
+
+#
+# check 'use index' on view with temporary table
+#
+create table t1 (a int, b int);
+create view v1 as select a, sum(b) from t1 group by a;
+-- error 1072
+select b from v1 use index (some_index) where b=1;
+drop view v1;
+drop table t1;
+
+#
+# using VIEW fields several times in query resolved via temporary tables
+#
+create table t1 (col1 char(5),col2 char(5));
+create view v1 (col1,col2) as select col1,col2 from t1;
+insert into v1 values('s1','p1'),('s1','p2'),('s1','p3'),('s1','p4'),('s2','p1'),('s3','p2'),('s4','p4');
+select distinct first.col2 from t1 first where first.col2 in (select second.col2 from t1 second where second.col1<>first.col1);
+select distinct first.col2 from v1 first where first.col2 in (select second.col2 from t1 second where second.col1<>first.col1);
+drop view v1;
+drop table t1;
+
+#
+# Test of view updatability in prepared statement
+#
+create table t1 (a int);
+create view v1 as select a from t1;
+insert into t1 values (1);
+
+#update
+SET @v0 = '2';
+PREPARE stmt FROM 'UPDATE v1 SET a = ?';
+EXECUTE stmt USING @v0;
+DEALLOCATE PREPARE stmt;
+
+#insert without field list
+SET @v0 = '3';
+PREPARE stmt FROM 'insert into v1 values (?)';
+EXECUTE stmt USING @v0;
+DEALLOCATE PREPARE stmt;
+
+#insert with field list
+SET @v0 = '4';
+PREPARE stmt FROM 'insert into v1 (a) values (?)';
+EXECUTE stmt USING @v0;
+DEALLOCATE PREPARE stmt;
+
+select * from t1;
+
+drop view v1;
+drop table t1;
+
+#
+# error on preparation
+#
+-- error 1096
+CREATE VIEW v02 AS SELECT * FROM DUAL;
+SHOW TABLES;
+
+#
+# EXISTS with UNION VIEW
+#
+CREATE VIEW v1 AS SELECT EXISTS (SELECT 1 UNION SELECT 2);
+select * from v1;
+drop view v1;
+
+#
+# using VIEW where table is required
+#
+create table t1 (col1 int,col2 char(22));
+create view v1 as select * from t1;
+-- error 1347
+create index i1 on v1 (col1);
+drop view v1;
+drop table t1;
+
+#
+# connection_id(), pi(), current_user(), version() representation test
+#
+CREATE VIEW v1 (f1,f2,f3,f4) AS SELECT connection_id(), pi(), current_user(), version();
+SHOW CREATE VIEW v1;
+drop view v1;
+
+#
+# VIEW built over UNION
+#
+create table t1 (s1 int);
+create table t2 (s2 int);
+insert into t1 values (1), (2);
+insert into t2 values (2), (3);
+create view v1 as select * from t1,t2 union all select * from t1,t2;
+select * from v1;
+drop view v1;
+drop tables t1, t2;
+
+#
+# Aggregate functions in view list
+#
+create table t1 (col1 int);
+insert into t1 values (1);
+create view v1 as select count(*) from t1;
+insert into t1 values (null);
+select * from v1;
+drop view v1;
+drop table t1;
+
+#
+# Showing VIEW with VIEWs in subquery
+#
+create table t1 (a int);
+create table t2 (a int);
+create view v1 as select a from t1;
+create view v2 as select a from t2 where a in (select a from v1);
+show create view v2;
+drop view v2, v1;
+drop table t1, t2;
+
+#
+# SHOW VIEW view with name with spaces
+#
+CREATE VIEW `v 1` AS select 5 AS `5`;
+show create view `v 1`;
+drop view `v 1`;
+
+#
+# Removing database with .frm archives
+#
+create database mysqltest;
+create table mysqltest.t1 (a int, b int);
+create view mysqltest.v1 as select a from mysqltest.t1;
+alter view mysqltest.v1 as select b from mysqltest.t1;
+alter view mysqltest.v1 as select a from mysqltest.t1;
+drop database mysqltest;
+
+#
+# VIEW with full text
+#
+CREATE TABLE t1 (c1 int not null auto_increment primary key, c2 varchar(20), fulltext(c2));
+insert into t1 (c2) VALUES ('real Beer'),('Water'),('Kossu'),('Coca-Cola'),('Vodka'),('Wine'),('almost real Beer');
+select * from t1 WHERE match (c2) against ('Beer');
+CREATE VIEW v1 AS SELECT * from t1 WHERE match (c2) against ('Beer');
+select * from v1;
+drop view v1;
+drop table t1;
+
+#
+# distinct in temporary table with a VIEW
+#
+create table t1 (a int);
+insert into t1 values (1),(1),(2),(2),(3),(3);
+create view v1 as select a from t1;
+select distinct a from v1;
+select distinct a from v1 limit 2;
+select distinct a from t1 limit 2;
+prepare stmt1 from "select distinct a from v1 limit 2";
+execute stmt1;
+execute stmt1;
+deallocate prepare stmt1;
+drop view v1;
+drop table t1;
+
+#
+# aggregate function of aggregate function
+#
+create table t1 (tg_column bigint);
+create view v1 as select count(tg_column) as vg_column from t1;
+select avg(vg_column) from v1;
+drop view v1;
+drop table t1;
+
+#
+# VIEW of VIEW with column renaming
+#
+create table t1 (col1 bigint not null, primary key (col1));
+create table t2 (col1 bigint not null, key (col1));
+create view v1 as select * from t1;
+create view v2 as select * from t2;
+insert into v1 values (1);
+insert into v2 values (1);
+create view v3 (a,b) as select v1.col1 as a, v2.col1 as b from v1, v2 where v1.col1 = v2.col1;
+select * from v3;
+show create view v3;
+drop view v3, v2, v1;
+drop table t2, t1;
+
+#
+# VIEW based on functions with complex names
+#
+create function `f``1` () returns int return 5;
+create view v1 as select test.`f``1` ();
+show create view v1;
+select * from v1;
+drop view v1;
+drop function `f``1`;
+
+#
+# tested problem when function name length close to ALIGN_SIZE
+#
+create function x () returns int return 5;
+create view v1 as select x ();
+select * from v1;
+drop view v1;
+drop function x;
+
+#
+# VIEW with collation
+#
+create table t2 (col1 char collate latin1_german2_ci);
+create view v2 as select col1 collate latin1_german1_ci from t2;
+show create view v2;
+show create view v2;
+drop view v2;
+drop table t2;
+
+#
+# order by refers on integer field
+#
+create table t1 (a int);
+insert into t1 values (1), (2);
+create view v1 as select 5 from t1 order by 1;
+select * from v1;
+drop view v1;
+drop table t1;
+
+#
+# VIEW over dropped function
+#
+create function x1 () returns int return 5;
+create table t1 (s1 int);
+create view v1 as select x1() from t1;
+drop function x1;
+-- error 1356
+select * from v1;
+--replace_column 8 # 12 # 13 #
+show table status;
+drop view v1;
+drop table t1;
+
+#
+# VIEW with floating point (long number) as column
+#
+create view v1 as select 99999999999999999999999999999999999999999999999999999 as col1;
+show create view v1;
+drop view v1;
+
+#
+# VIEWs with national characters
+#
+create table tü (cü char);
+create view vü as select cü from tü;
+insert into vü values ('ü');
+select * from vü;
+drop view vü;
+drop table tü;
+
+#
+# problem with used_tables() of outer reference resolved in VIEW
+#
+create table t1 (a int, b int);
+insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
+create view v1(c) as select a+1 from t1 where b >= 4;
+select c from v1 where exists (select * from t1 where a=2 and b=c);
+drop view v1;
+drop table t1;
+
+#
+# view with cast operation
+#
+create view v1 as select cast(1 as char(3));
+show create view v1;
+select * from v1;
+drop view v1;
+
+#
+# bug handling from VIEWs
+#
+create view v1 as select 'a',1;
+create view v2 as select * from v1 union all select * from v1;
+create view v3 as select * from v2 where 1 = (select `1` from v2);
+create view v4 as select * from v3;
+-- error 1242
+select * from v4;
+drop view v4, v3, v2, v1;
+
+#
+# VIEW over SELECT with prohibited clauses
+#
+-- error 1350
+create view v1 as select 5 into @w;
+-- error 1350
+create view v1 as select 5 into outfile 'ttt';
+create table t1 (a int);
+-- error 1350
+create view v1 as select a from t1 procedure analyse();
+drop table t1;
+
+#
+# INSERT into VIEW with ON DUPLICATE
+#
+create table t1 (s1 int, primary key (s1));
+create view v1 as select * from t1;
+insert into v1 values (1) on duplicate key update s1 = 7;
+insert into v1 values (1) on duplicate key update s1 = 7;
+select * from t1;
+drop view v1;
+drop table t1;
+
+#
+# test of updating and fetching from the same table check
+#
+create table t1 (col1 int);
+create table t2 (col1 int);
+create view v1 as select * from t1;
+create view v2 as select * from v1;
+create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1;
+-- error 1093
+update v2 set col1 = (select max(col1) from v1);
+-- error 1093
+update v2 set col1 = (select max(col1) from t1);
+-- error 1093
+update v2 set col1 = (select max(col1) from v2);
+-- error 1093
+update v2,t2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1;
+-- error 1093
+update t1,t2 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1;
+-- error 1093
+update v1,t2 set v1.col1 = (select max(col1) from v1) where v1.col1 = t2.col1;
+-- error 1093
+update t2,v2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1;
+-- error 1093
+update t2,t1 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1;
+-- error 1093
+update t2,v1 set v1.col1 = (select max(col1) from v1) where v1.col1 = t2.col1;
+-- error 1093
+update v2,t2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1;
+-- error 1093
+update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1;
+-- error 1093
+update v1,t2 set v1.col1 = (select max(col1) from t1) where v1.col1 = t2.col1;
+-- error 1093
+update t2,v2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1;
+-- error 1093
+update t2,t1 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1;
+-- error 1093
+update t2,v1 set v1.col1 = (select max(col1) from t1) where v1.col1 = t2.col1;
+-- error 1093
+update v2,t2 set v2.col1 = (select max(col1) from v2) where v2.col1 = t2.col1;
+-- error 1093
+update t1,t2 set t1.col1 = (select max(col1) from v2) where t1.col1 = t2.col1;
+-- error 1093
+update v1,t2 set v1.col1 = (select max(col1) from v2) where v1.col1 = t2.col1;
+-- error 1093
+update t2,v2 set v2.col1 = (select max(col1) from v2) where v2.col1 = t2.col1;
+-- error 1093
+update t2,t1 set t1.col1 = (select max(col1) from v2) where t1.col1 = t2.col1;
+-- error 1093
+update t2,v1 set v1.col1 = (select max(col1) from v2) where v1.col1 = t2.col1;
+-- error 1093
+update v3 set v3.col1 = (select max(col1) from v1);
+-- error 1093
+update v3 set v3.col1 = (select max(col1) from t1);
+-- error 1093
+update v3 set v3.col1 = (select max(col1) from v2);
+-- error 1093
+update v3 set v3.col1 = (select max(col1) from v3);
+-- error 1093
+delete from v2 where col1 = (select max(col1) from v1);
+-- error 1093
+delete from v2 where col1 = (select max(col1) from t1);
+-- error 1093
+delete from v2 where col1 = (select max(col1) from v2);
+-- error 1093
+delete v2 from v2,t2 where (select max(col1) from v1) > 0 and v2.col1 = t2.col1;
+-- error 1093
+delete t1 from t1,t2 where (select max(col1) from v1) > 0 and t1.col1 = t2.col1;
+-- error 1093
+delete v1 from v1,t2 where (select max(col1) from v1) > 0 and v1.col1 = t2.col1;
+-- error 1093
+delete v2 from v2,t2 where (select max(col1) from t1) > 0 and v2.col1 = t2.col1;
+-- error 1093
+delete t1 from t1,t2 where (select max(col1) from t1) > 0 and t1.col1 = t2.col1;
+-- error 1093
+delete v1 from v1,t2 where (select max(col1) from t1) > 0 and v1.col1 = t2.col1;
+-- error 1093
+delete v2 from v2,t2 where (select max(col1) from v2) > 0 and v2.col1 = t2.col1;
+-- error 1093
+delete t1 from t1,t2 where (select max(col1) from v2) > 0 and t1.col1 = t2.col1;
+-- error 1093
+delete v1 from v1,t2 where (select max(col1) from v2) > 0 and v1.col1 = t2.col1;
+-- error 1093
+insert into v2 values ((select max(col1) from v1));
+-- error 1093
+insert into t1 values ((select max(col1) from v1));
+-- error 1093
+insert into v2 values ((select max(col1) from v1));
+-- error 1093
+insert into v2 values ((select max(col1) from t1));
+-- error 1093
+insert into t1 values ((select max(col1) from t1));
+-- error 1093
+insert into v2 values ((select max(col1) from t1));
+-- error 1093
+insert into v2 values ((select max(col1) from v2));
+-- error 1093
+insert into t1 values ((select max(col1) from v2));
+-- error 1093
+insert into v2 values ((select max(col1) from v2));
+-- error 1093
+insert into v3 (col1) values ((select max(col1) from v1));
+-- error 1093
+insert into v3 (col1) values ((select max(col1) from t1));
+-- error 1093
+insert into v3 (col1) values ((select max(col1) from v2));
+#check with TZ tables in list
+-- error 1093
+insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2));
+insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
+-- error 1048
+insert into mysql.time_zone values ('', (select CONVERT_TZ('20050101000000','UTC','MET') from t2));
+# temporary table algorithm view should be equal to subquery in the from clause
+create algorithm=temptable view v4 as select * from t1;
+insert into t1 values (1),(2),(3);
+insert into t1 (col1) values ((select max(col1) from v4));
+select * from t1;
+
+drop view v4,v3,v2,v1;
+drop table t1,t2;
+
+#
+# HANDLER with VIEW
+#
+create table t1 (s1 int);
+create view v1 as select * from t1;
+-- error 1347
+handler v1 open as xx;
+drop view v1;
+drop table t1;
+
+#
+# view with WHERE in nested join
+#
+create table t1(a int);
+insert into t1 values (0), (1), (2), (3);
+create table t2 (a int);
+insert into t2 select a from t1 where a > 1;
+create view v1 as select a from t1 where a > 1;
+select * from t1 left join (t2 as t, v1) on v1.a=t1.a;
+select * from t1 left join (t2 as t, t2) on t2.a=t1.a;
+drop view v1;
+drop table t1, t2;
+
+#
+# Collation with view update
+#
+create table t1 (s1 char);
+create view v1 as select s1 collate latin1_german1_ci as s1 from t1;
+insert into v1 values ('a');
+select * from v1;
+update v1 set s1='b';
+select * from v1;
+update v1,t1 set v1.s1='c' where t1.s1=v1.s1;
+select * from v1;
+prepare stmt1 from "update v1,t1 set v1.s1=? where t1.s1=v1.s1";
+set @arg='d';
+execute stmt1 using @arg;
+select * from v1;
+set @arg='e';
+execute stmt1 using @arg;
+select * from v1;
+deallocate prepare stmt1;
+drop view v1;
+drop table t1;
+
+#
+# test view with LOCK TABLES (work around)
+#
+create table t1 (a int);
+create table t2 (a int);
+create view v1 as select * from t1;
+lock tables t1 read, v1 read;
+select * from v1;
+-- error 1100
+select * from t2;
+drop view v1;
+drop table t1, t2;
+
+#
+# WITH CHECK OPTION insert/update test
+#
+create table t1 (a int);
+create view v1 as select * from t1 where a < 2 with check option;
+# simple insert
+insert into v1 values(1);
+-- error 1369
+insert into v1 values(3);
+# simple insert with ignore
+insert ignore into v1 values (2),(3),(0);
+select * from t1;
+# prepare data for next check
+delete from t1;
+# INSERT SELECT test
+insert into v1 SELECT 1;
+-- error 1369
+insert into v1 SELECT 3;
+# prepare data for next check
+create table t2 (a int);
+insert into t2 values (2),(3),(0);
+# INSERT SELECT with ignore test
+insert ignore into v1 SELECT a from t2;
+select * from t1;
+#simple UPDATE test
+update v1 set a=-1 where a=0;
+-- error 1369
+update v1 set a=2 where a=1;
+select * from t1;
+# prepare data for next check
+update v1 set a=0 where a=0;
+insert into t2 values (1);
+# multiupdate test
+update v1,t2 set v1.a=v1.a-1 where v1.a=t2.a;
+select * from t1;
+# prepare data for next check
+update v1 set a=a+1;
+# multiupdate with ignore test
+update ignore v1,t2 set v1.a=v1.a+1 where v1.a=t2.a;
+select * from t1;
+
+drop view v1;
+drop table t1, t2;
+
+#
+# CASCADED/LOCAL CHECK OPTION test
+#
+create table t1 (a int);
+create view v1 as select * from t1 where a < 2 with check option;
+create view v2 as select * from v1 where a > 0 with local check option;
+create view v3 as select * from v1 where a > 0 with cascaded check option;
+insert into v2 values (1);
+insert into v3 values (1);
+-- error 1369
+insert into v2 values (0);
+-- error 1369
+insert into v3 values (0);
+insert into v2 values (2);
+-- error 1369
+insert into v3 values (2);
+select * from t1;
+drop view v3,v2,v1;
+drop table t1;
+
+#
+# CHECK OPTION with INSERT ... ON DUPLICATE KEY UPDATE
+#
+create table t1 (a int, primary key (a));
+create view v1 as select * from t1 where a < 2 with check option;
+insert into v1 values (1) on duplicate key update a=2;
+-- error 1369
+insert into v1 values (1) on duplicate key update a=2;
+insert ignore into v1 values (1) on duplicate key update a=2;
+select * from t1;
+drop view v1;
+drop table t1;
+
+#
+# check cyclic referencing protection on altering view
+#
+create table t1 (s1 int);
+create view v1 as select * from t1;
+create view v2 as select * from v1;
+-- error 1146
+alter view v1 as select * from v2;
+-- error 1066
+alter view v1 as select * from v1;
+-- error 1146
+create or replace view v1 as select * from v2;
+-- error 1066
+create or replace view v1 as select * from v1;
+drop view v2,v1;
+drop table t1;
+
+#
+# check altering differ options
+#
+create table t1 (a int);
+create view v1 as select * from t1;
+show create view v1;
+alter algorithm=undefined view v1 as select * from t1 with check option;
+show create view v1;
+alter algorithm=merge view v1 as select * from t1 with cascaded check option;
+show create view v1;
+alter algorithm=temptable view v1 as select * from t1;
+show create view v1;
+drop view v1;
+drop table t1;
+
+#
+# updating view with subquery in the WHERE clause
+#
+create table t1 (s1 int);
+create table t2 (s1 int);
+create view v2 as select * from t2 where s1 in (select s1 from t1);
+insert into v2 values (5);
+insert into t1 values (5);
+select * from v2;
+update v2 set s1 = 0;
+select * from v2;
+select * from t2;
+# check it with check option
+alter view v2 as select * from t2 where s1 in (select s1 from t1) with check option;
+insert into v2 values (5);
+-- error 1369
+update v2 set s1 = 1;
+insert into t1 values (1);
+update v2 set s1 = 1;
+select * from v2;
+select * from t2;
+# scheck how VIEWs with subqueries work with prepared statements
+prepare stmt1 from "select * from v2;";
+execute stmt1;
+insert into t1 values (0);
+execute stmt1;
+deallocate prepare stmt1;
+drop view v2;
+drop table t1, t2;
+
+#
+# test of substring_index with view
+#
+create table t1 (t time);
+create view v1 as select substring_index(t,':',2) as t from t1;
+insert into t1 (t) values ('12:24:10');
+select substring_index(t,':',2) from t1;
+select substring_index(t,':',2) from v1;
+drop view v1;
+drop table t1;
+
+#
+# test of cascaded check option for whiew without WHERE clause
+#
+create table t1 (s1 tinyint);
+create view v1 as select * from t1 where s1 <> 0 with local check option;
+create view v2 as select * from v1 with cascaded check option;
+-- error 1369
+insert into v2 values (0);
+drop view v2, v1;
+drop table t1;
+
+#
+# inserting single value with check option failed always get error
+#
+create table t1 (s1 int);
+create view v1 as select * from t1 where s1 < 5 with check option;
+#single value
+-- error 1369
+insert ignore into v1 values (6);
+#several values
+insert ignore into v1 values (6),(3);
+select * from t1;
+drop view v1;
+drop table t1;
+
+#
+# changing value by trigger and CHECK OPTION
+#
+create table t1 (s1 tinyint);
+create trigger t1_bi before insert on t1 for each row set new.s1 = 500;
+create view v1 as select * from t1 where s1 <> 127 with check option;
+-- error 1369
+insert into v1 values (0);
+select * from v1;
+select * from t1;
+drop trigger t1.t1_bi;
+drop view v1;
+drop table t1;
+
+#
+# CASCADED should be used for all underlaying VIEWs
+#
+create table t1 (s1 tinyint);
+create view v1 as select * from t1 where s1 <> 0;
+create view v2 as select * from v1 where s1 <> 1 with cascaded check option;
+-- error 1369
+insert into v2 values (0);
+select * from v2;
+select * from t1;
+drop view v2, v1;
+drop table t1;
+
+#
+# LOAD DATA with view and CHECK OPTION
+#
+# fixed length fields
+create table t1 (a int, b char(10));
+create view v1 as select * from t1 where a != 0 with check option;
+-- error 1369
+load data infile '../../std_data/loaddata3.dat' into table v1 fields terminated by '' enclosed by '' ignore 1 lines;
+select * from t1;
+select * from v1;
+delete from t1;
+load data infile '../../std_data/loaddata3.dat' ignore into table v1 fields terminated by '' enclosed by '' ignore 1 lines;
+select * from t1;
+select * from v1;
+drop view v1;
+drop table t1;
+# variable length fields
+create table t1 (a text, b text);
+create view v1 as select * from t1 where a <> 'Field A' with check option;
+-- error 1369
+load data infile '../../std_data/loaddata2.dat' into table v1 fields terminated by ',' enclosed by '''';
+select concat('|',a,'|'), concat('|',b,'|') from t1;
+select concat('|',a,'|'), concat('|',b,'|') from v1;
+delete from t1;
+load data infile '../../std_data/loaddata2.dat' ignore into table v1 fields terminated by ',' enclosed by '''';
+select concat('|',a,'|'), concat('|',b,'|') from t1;
+select concat('|',a,'|'), concat('|',b,'|') from v1;
+drop view v1;
+drop table t1;
+
+#
+# Trys update table from which we select using views and subqueries
+#
+create table t1 (s1 smallint);
+create view v1 as select * from t1 where 20 < (select (s1) from t1);
+-- error 1288
+insert into v1 values (30);
+create view v2 as select * from t1;
+create view v3 as select * from t1 where 20 < (select (s1) from v2);
+-- error 1288
+insert into v3 values (30);
+create view v4 as select * from v2 where 20 < (select (s1) from t1);
+-- error 1093
+insert into v4 values (30);
+drop view v4, v3, v2, v1;
+drop table t1;
+
+#
+# CHECK TABLE with VIEW
+#
+create table t1 (a int);
+create view v1 as select * from t1;
+check table t1,v1;
+check table v1,t1;
+drop table t1;
+check table v1;
+drop view v1;
+
+#
+# merge of VIEW with several tables
+#
+create table t1 (a int);
+create table t2 (a int);
+create table t3 (a int);
+insert into t1 values (1), (2), (3);
+insert into t2 values (1), (3);
+insert into t3 values (1), (2), (4);
+# view over tables
+create view v3 (a,b) as select t1.a as a, t2.a as b from t1 left join t2 on (t1.a=t2.a);
+select * from t3 left join v3 on (t3.a = v3.a);
+explain extended select * from t3 left join v3 on (t3.a = v3.a);
+# view over views
+create view v1 (a) as select a from t1;
+create view v2 (a) as select a from t2;
+create view v4 (a,b) as select v1.a as a, v2.a as b from v1 left join v2 on (v1.a=v2.a);
+select * from t3 left join v4 on (t3.a = v4.a);
+explain extended select * from t3 left join v4 on (t3.a = v4.a);
+# PS with view over views
+prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);";
+execute stmt1;
+execute stmt1;
+deallocate prepare stmt1;
+drop view v4,v3,v2,v1;
+drop tables t1,t2,t3;
+
+#
+# updating of join view
+#
+create table t1 (a int, primary key (a), b int);
+create table t2 (a int, primary key (a));
+insert into t1 values (1,100), (2,200);
+insert into t2 values (1), (3);
+# legal view for update
+create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
+update v3 set a= 10 where a=1;
+select * from t1;
+select * from t2;
+# view without primary key
+create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
+set updatable_views_with_limit=NO;
+-- error 1288
+update v2 set a= 10 where a=200 limit 1;
+set updatable_views_with_limit=DEFAULT;
+# just view selects
+select * from v3;
+select * from v2;
+# prepare statement with updating join view
+set @a= 10;
+set @b= 100;
+prepare stmt1 from "update v3 set a= ? where a=?";
+execute stmt1 using @a,@b;
+select * from v3;
+set @a= 300;
+set @b= 10;
+execute stmt1 using @a,@b;
+select * from v3;
+deallocate prepare stmt1;
+drop view v3,v2;
+drop tables t1,t2;
+
+#
+# inserting/deleting join view
+#
+create table t1 (a int, primary key (a), b int);
+create table t2 (a int, primary key (a), b int);
+insert into t2 values (1000, 2000);
+create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
+# inserting into join view without field list
+-- error 1394
+insert into v3 values (1,2);
+-- error 1394
+insert into v3 select * from t2;
+# inserting in several tables of join view
+-- error 1393
+insert into v3(a,b) values (1,2);
+-- error 1393
+insert into v3(a,b) select * from t2;
+# correct inserts into join view
+insert into v3(a) values (1);
+insert into v3(b) values (10);
+insert into v3(a) select a from t2;
+insert into v3(b) select b from t2;
+insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a);
+select * from t1;
+select * from t2;
+# try delete from join view
+-- error 1395
+delete from v3;
+-- error 1395
+delete v3,t1 from v3,t1;
+-- error 1395
+delete t1,v3 from t1,v3;
+# delete from t1 just to reduce result set size
+delete from t1;
+# prepare statement with insert join view
+prepare stmt1 from "insert into v3(a) values (?);";
+set @a= 100;
+execute stmt1 using @a;
+set @a= 300;
+execute stmt1 using @a;
+deallocate prepare stmt1;
+prepare stmt1 from "insert into v3(a) select ?;";
+set @a= 101;
+execute stmt1 using @a;
+set @a= 301;
+execute stmt1 using @a;
+deallocate prepare stmt1;
+select * from v3;
+
+drop view v3;
+drop tables t1,t2;
+
+#
+# View field names should be case insensitive
+#
+create table t1(f1 int);
+create view v1 as select f1 from t1;
+select * from v1 where F1 = 1;
+drop view v1;
+drop table t1;
+
+#
+# Resolving view fields in subqueries in VIEW (Bug #6394)
+#
+create table t1(c1 int);
+create table t2(c2 int);
+insert into t1 values (1),(2),(3);
+insert into t2 values (1);
+SELECT c1 FROM t1 WHERE c1 IN (SELECT c2 FROM t2);
+SELECT c1 FROM t1 WHERE EXISTS (SELECT c2 FROM t2 WHERE c2 = c1);
+create view v1 as SELECT c1 FROM t1 WHERE c1 IN (SELECT c2 FROM t2);
+create view v2 as SELECT c1 FROM t1 WHERE EXISTS (SELECT c2 FROM t2 WHERE c2 = c1);
+select * from v1;
+select * from v2;
+select * from (select c1 from v2) X;
+drop view v2, v1;
+drop table t1, t2;
+
+#
+# view over other view setup (BUG#7433)
+#
+CREATE TABLE t1 (C1 INT, C2 INT);
+CREATE TABLE t2 (C2 INT);
+CREATE VIEW v1 AS SELECT C2 FROM t2;
+CREATE VIEW v2 AS SELECT C1 FROM t1 LEFT OUTER JOIN v1 USING (C2);
+SELECT * FROM v2;
+drop view v2, v1;
+drop table t1, t2;
+
+#
+# view and group_concat() (BUG#7116)
+#
+create table t1 (col1 char(5),col2 int,col3 int);
+insert into t1 values ('one',10,25), ('two',10,50), ('two',10,50), ('one',20,25), ('one',30,25);
+create view v1 as select * from t1;
+select col1,group_concat(col2,col3) from t1 group by col1;
+select col1,group_concat(col2,col3) from v1 group by col1;
+drop view v1;
+drop table t1;
+
+#
+# Item_ref resolved as view field (BUG#6894)
+#
+create table t1 (s1 int, s2 char);
+create view v1 as select s1, s2 from t1;
+-- error 1054
+select s2 from v1 vq1 where 2 = (select count(*) from v1 vq2 having vq1.s2 = vq2.s2);
+select s2 from v1 vq1 where 2 = (select count(*) aa from v1 vq2 having vq1.s2 = aa);
+drop view v1;
+drop table t1;
+
+#
+# Test case for bug #9398 CREATE TABLE with SELECT from a multi-table view
+#
+CREATE TABLE t1 (a1 int);
+CREATE TABLE t2 (a2 int);
+INSERT INTO t1 VALUES (1), (2), (3), (4);
+INSERT INTO t2 VALUES (1), (2), (3);
+CREATE VIEW v1(a,b) AS SELECT a1,a2 FROM t1 JOIN t2 ON a1=a2 WHERE a1>1;
+
+SELECT * FROM v1;
+CREATE TABLE t3 SELECT * FROM v1;
+SELECT * FROM t3;
+
+DROP VIEW v1;
+DROP TABLE t1,t2,t3;
+
+#
+# Test for BUG#8703 "insert into table select from view crashes"
+#
+create table t1 (a int);
+create table t2 like t1;
+create table t3 like t1;
+create view v1 as select t1.a x, t2.a y from t1 join t2 where t1.a=t2.a;
+insert into t3 select x from v1;
+insert into t2 select x from v1;
+drop view v1;
+drop table t1,t2,t3;
+
+#
+# Test for BUG #6106: query over a view using subquery for the underlying table
+#
+
+CREATE TABLE t1 (col1 int PRIMARY KEY, col2 varchar(10));
+INSERT INTO t1 VALUES(1,'trudy');
+INSERT INTO t1 VALUES(2,'peter');
+INSERT INTO t1 VALUES(3,'sanja');
+INSERT INTO t1 VALUES(4,'monty');
+INSERT INTO t1 VALUES(5,'david');
+INSERT INTO t1 VALUES(6,'kent');
+INSERT INTO t1 VALUES(7,'carsten');
+INSERT INTO t1 VALUES(8,'ranger');
+INSERT INTO t1 VALUES(10,'matt');
+CREATE TABLE t2 (col1 int, col2 int, col3 char(1));
+INSERT INTO t2 VALUES (1,1,'y');
+INSERT INTO t2 VALUES (1,2,'y');
+INSERT INTO t2 VALUES (2,1,'n');
+INSERT INTO t2 VALUES (3,1,'n');
+INSERT INTO t2 VALUES (4,1,'y');
+INSERT INTO t2 VALUES (4,2,'n');
+INSERT INTO t2 VALUES (4,3,'n');
+INSERT INTO t2 VALUES (6,1,'n');
+INSERT INTO t2 VALUES (8,1,'y');
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+SELECT a.col1,a.col2,b.col2,b.col3
+ FROM t1 a LEFT JOIN t2 b ON a.col1=b.col1
+ WHERE b.col2 IS NULL OR
+ b.col2=(SELECT MAX(col2) FROM t2 b WHERE b.col1=a.col1);
+
+SELECT a.col1,a.col2,b.col2,b.col3
+ FROM v1 a LEFT JOIN t2 b ON a.col1=b.col1
+ WHERE b.col2 IS NULL OR
+ b.col2=(SELECT MAX(col2) FROM t2 b WHERE b.col1=a.col1);
+
+CREATE VIEW v2 AS SELECT * FROM t2;
+
+SELECT a.col1,a.col2,b.col2,b.col3
+ FROM v2 b RIGHT JOIN v1 a ON a.col1=b.col1
+ WHERE b.col2 IS NULL OR
+ b.col2=(SELECT MAX(col2) FROM v2 b WHERE b.col1=a.col1);
+
+# Tests from the report for bug #6107
+
+SELECT a.col1,a.col2,b.col2,b.col3
+ FROM v2 b RIGHT JOIN v1 a ON a.col1=b.col1
+ WHERE a.col1 IN (1,5,9) AND
+ (b.col2 IS NULL OR
+ b.col2=(SELECT MAX(col2) FROM v2 b WHERE b.col1=a.col1));
+
+CREATE VIEW v3 AS SELECT * FROM t1 WHERE col1 IN (1,5,9);
+
+SELECT a.col1,a.col2,b.col2,b.col3
+ FROM v2 b RIGHT JOIN v3 a ON a.col1=b.col1
+ WHERE b.col2 IS NULL OR
+ b.col2=(SELECT MAX(col2) FROM v2 b WHERE b.col1=a.col1);
+
+DROP VIEW v1,v2,v3;
+DROP TABLE t1,t2;
+
+# BUG#8490 Select from views containing subqueries causes server to hang
+# forever.
+create table t1 as select 1 A union select 2 union select 3;
+create table t2 as select * from t1;
+create view v1 as select * from t1 where a in (select * from t2);
+select * from v1 A, v1 B where A.a = B.a;
+create table t3 as select a a,a b from t2;
+create view v2 as select * from t3 where
+ a in (select * from t1) or b in (select * from t2);
+select * from v2 A, v2 B where A.a = B.b;
+drop view v1, v2;
+drop table t1, t2, t3;
+
diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test
new file mode 100644
index 00000000000..bb603b75daa
--- /dev/null
+++ b/mysql-test/t/view_grant.test
@@ -0,0 +1,403 @@
+# Can't test with embedded server
+-- source include/not_embedded.inc
+
+# simple test of grants
+grant create view on test.* to test@localhost;
+show grants for test@localhost;
+revoke create view on test.* from test@localhost;
+show grants for test@localhost;
+
+# grant create view test
+#
+connect (root,localhost,root,,test);
+connection root;
+--disable_warnings
+create database mysqltest;
+--enable_warnings
+
+create table mysqltest.t1 (a int, b int);
+create table mysqltest.t2 (a int, b int);
+
+grant select on mysqltest.t1 to mysqltest_1@localhost;
+grant create view,select on test.* to mysqltest_1@localhost;
+
+connect (user1,localhost,mysqltest_1,,test);
+connection user1;
+
+create view v1 as select * from mysqltest.t1;
+# try to modify view without DROP privilege on it
+-- error 1142
+alter view v1 as select * from mysqltest.t1;
+-- error 1142
+create or replace view v1 as select * from mysqltest.t1;
+# no CRETE VIEW privilege
+-- error 1142
+create view mysqltest.v2 as select * from mysqltest.t1;
+# no SELECT privilege
+-- error 1142
+create view v2 as select * from mysqltest.t2;
+
+connection root;
+grant create view,drop,select on test.* to mysqltest_1@localhost;
+
+connection user1;
+# following 'use' command is workaround of bug #9582 and should be removed
+# when that bug will be fixed
+use test;
+alter view v1 as select * from mysqltest.t1;
+create or replace view v1 as select * from mysqltest.t1;
+
+connection root;
+revoke all privileges on mysqltest.t1 from mysqltest_1@localhost;
+revoke all privileges on test.* from mysqltest_1@localhost;
+
+drop database mysqltest;
+drop view test.v1;
+
+#
+# grants per columns
+#
+# MERGE algorithm
+--disable_warnings
+create database mysqltest;
+--enable_warnings
+
+create table mysqltest.t1 (a int, b int);
+create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1;
+grant select (c) on mysqltest.v1 to mysqltest_1@localhost;
+
+connection user1;
+select c from mysqltest.v1;
+# there are no privileges on column 'd'
+-- error 1143
+select d from mysqltest.v1;
+
+connection root;
+revoke all privileges on mysqltest.v1 from mysqltest_1@localhost;
+delete from mysql.user where user='mysqltest_1';
+drop database mysqltest;
+
+# TEMPORARY TABLE algorithm
+--disable_warnings
+create database mysqltest;
+--enable_warnings
+
+create table mysqltest.t1 (a int, b int);
+create algorithm=temptable view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1;
+grant select (c) on mysqltest.v1 to mysqltest_1@localhost;
+
+connection user1;
+select c from mysqltest.v1;
+# there are no privileges on column 'd'
+-- error 1143
+select d from mysqltest.v1;
+
+connection root;
+revoke all privileges on mysqltest.v1 from mysqltest_1@localhost;
+delete from mysql.user where user='mysqltest_1';
+drop database mysqltest;
+
+#
+# EXPLAIN rights
+#
+connection root;
+--disable_warnings
+create database mysqltest;
+--enable_warnings
+#prepare views and tables
+create table mysqltest.t1 (a int, b int);
+create table mysqltest.t2 (a int, b int);
+create view mysqltest.v1 (c,d) as select a+1,b+1 from mysqltest.t1;
+create algorithm=temptable view mysqltest.v2 (c,d) as select a+1,b+1 from mysqltest.t1;
+create view mysqltest.v3 (c,d) as select a+1,b+1 from mysqltest.t2;
+create algorithm=temptable view mysqltest.v4 (c,d) as select a+1,b+1 from mysqltest.t2;
+grant select on mysqltest.v1 to mysqltest_1@localhost;
+grant select on mysqltest.v2 to mysqltest_1@localhost;
+grant select on mysqltest.v3 to mysqltest_1@localhost;
+grant select on mysqltest.v4 to mysqltest_1@localhost;
+
+connection user1;
+# all selects works
+select c from mysqltest.v1;
+select c from mysqltest.v2;
+select c from mysqltest.v3;
+select c from mysqltest.v4;
+# test of show coluns
+show columns from mysqltest.v1;
+show columns from mysqltest.v2;
+# but explain/show do not
+-- error 1345
+explain select c from mysqltest.v1;
+-- error 1142
+show create view mysqltest.v1;
+-- error 1345
+explain select c from mysqltest.v2;
+-- error 1142
+show create view mysqltest.v2;
+-- error 1345
+explain select c from mysqltest.v3;
+-- error 1142
+show create view mysqltest.v3;
+-- error 1345
+explain select c from mysqltest.v4;
+-- error 1142
+show create view mysqltest.v4;
+
+# allow to see one of underlying table
+connection root;
+grant select on mysqltest.t1 to mysqltest_1@localhost;
+connection user1;
+# EXPLAIN of view on above table works
+explain select c from mysqltest.v1;
+-- error 1142
+show create view mysqltest.v1;
+explain select c from mysqltest.v2;
+-- error 1142
+show create view mysqltest.v2;
+# but other EXPLAINs do not
+-- error 1345
+explain select c from mysqltest.v3;
+-- error 1142
+show create view mysqltest.v3;
+-- error 1345
+explain select c from mysqltest.v4;
+-- error 1142
+show create view mysqltest.v4;
+
+# allow to see any view in mysqltest database
+connection root;
+grant show view on mysqltest.* to mysqltest_1@localhost;
+connection user1;
+explain select c from mysqltest.v1;
+show create view mysqltest.v1;
+explain select c from mysqltest.v2;
+show create view mysqltest.v2;
+explain select c from mysqltest.v3;
+show create view mysqltest.v3;
+explain select c from mysqltest.v4;
+show create view mysqltest.v4;
+
+connection root;
+revoke all privileges on mysqltest.* from mysqltest_1@localhost;
+delete from mysql.user where user='mysqltest_1';
+drop database mysqltest;
+
+#
+# UPDATE privileges on VIEW columns and whole VIEW
+#
+connection root;
+--disable_warnings
+create database mysqltest;
+--enable_warnings
+
+create table mysqltest.t1 (a int, b int, primary key(a));
+insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10);
+create table mysqltest.t2 (x int);
+insert into mysqltest.t2 values (3), (4), (5), (6);
+create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1;
+create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1;
+create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1;
+
+grant update (a) on mysqltest.v2 to mysqltest_1@localhost;
+grant update on mysqltest.v1 to mysqltest_1@localhost;
+grant select on mysqltest.* to mysqltest_1@localhost;
+
+connection user1;
+use mysqltest;
+# update with rights on VIEW column
+update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.c;
+select * from t1;
+update v1 set a=a+c;
+select * from t1;
+# update with rights on whole VIEW
+update t2,v2 set v2.a=v2.a+v2.c where t2.x=v2.c;
+select * from t1;
+update v2 set a=a+c;
+select * from t1;
+# no rights on column
+-- error 1143
+update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c;
+-- error 1143
+update v2 set c=a+c;
+# no rights for view
+-- error 1142
+update t2,v3 set v3.a=v3.a+v3.c where t2.x=v3.c;
+-- error 1142
+update v3 set a=a+c;
+
+use test;
+connection root;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
+drop database mysqltest;
+
+#
+# DELETE privileges on VIEW
+#
+connection root;
+--disable_warnings
+create database mysqltest;
+--enable_warnings
+
+create table mysqltest.t1 (a int, b int, primary key(a));
+insert into mysqltest.t1 values (1,2), (2,3), (3,4), (4,5), (5,10);
+create table mysqltest.t2 (x int);
+insert into mysqltest.t2 values (3), (4), (5), (6);
+create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1;
+create view mysqltest.v2 (a,c) as select a, b+1 from mysqltest.t1;
+
+grant delete on mysqltest.v1 to mysqltest_1@localhost;
+grant select on mysqltest.* to mysqltest_1@localhost;
+
+connection user1;
+use mysqltest;
+# update with rights on VIEW column
+delete from v1 where c < 4;
+select * from t1;
+delete v1 from t2,v1 where t2.x=v1.c;
+select * from t1;
+# no rights for view
+-- error 1142
+delete v2 from t2,v2 where t2.x=v2.c;
+-- error 1142
+delete from v2 where c < 4;
+
+use test;
+connection root;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
+drop database mysqltest;
+
+#
+# insert privileges on VIEW
+#
+connection root;
+--disable_warnings
+create database mysqltest;
+--enable_warnings
+
+create table mysqltest.t1 (a int, b int, primary key(a));
+insert into mysqltest.t1 values (1,2), (2,3);
+create table mysqltest.t2 (x int, y int);
+insert into mysqltest.t2 values (3,4);
+create view mysqltest.v1 (a,c) as select a, b from mysqltest.t1;
+create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1;
+
+grant insert on mysqltest.v1 to mysqltest_1@localhost;
+grant select on mysqltest.* to mysqltest_1@localhost;
+
+connection user1;
+use mysqltest;
+# update with rights on VIEW column
+insert into v1 values (5,6);
+select * from t1;
+insert into v1 select x,y from t2;
+select * from t1;
+# no rights for view
+-- error 1142
+insert into v2 values (5,6);
+-- error 1142
+insert into v2 select x,y from t2;
+
+use test;
+connection root;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
+drop database mysqltest;
+
+#
+# test of CREATE VIEW privileges if we have limited privileges
+#
+connection root;
+--disable_warnings
+create database mysqltest;
+--enable_warnings
+
+create table mysqltest.t1 (a int, b int);
+create table mysqltest.t2 (a int, b int);
+
+grant update on mysqltest.t1 to mysqltest_1@localhost;
+grant update(b) on mysqltest.t2 to mysqltest_1@localhost;
+grant create view,update on test.* to mysqltest_1@localhost;
+
+connection user1;
+
+create view v1 as select * from mysqltest.t1;
+create view v2 as select b from mysqltest.t2;
+# There are not rights on mysqltest.v1
+-- error 1142
+create view mysqltest.v1 as select * from mysqltest.t1;
+# There are not any rights on mysqltest.t2.a
+-- error 1143
+create view v3 as select a from mysqltest.t2;
+
+# give CREATE VIEW privileges (without any privileges for result column)
+connection root;
+create table mysqltest.v3 (b int);
+grant create view on mysqltest.v3 to mysqltest_1@localhost;
+drop table mysqltest.v3;
+connection user1;
+create view mysqltest.v3 as select b from mysqltest.t2;
+
+# give UPDATE privileges
+connection root;
+grant create view, update on mysqltest.v3 to mysqltest_1@localhost;
+drop view mysqltest.v3;
+connection user1;
+create view mysqltest.v3 as select b from mysqltest.t2;
+
+# give UPDATE and INSERT privilege (to get more privileges then underlying
+# table)
+connection root;
+grant create view, update, insert on mysqltest.v3 to mysqltest_1@localhost;
+drop view mysqltest.v3;
+connection user1;
+-- error 1143
+create view mysqltest.v3 as select b from mysqltest.t2;
+
+
+# If we would get more privileges on VIEW then we have on
+# underlying tables => creation prohibited
+connection root;
+create table mysqltest.v3 (b int);
+grant select(b) on mysqltest.v3 to mysqltest_1@localhost;
+drop table mysqltest.v3;
+connection user1;
+-- error 1142
+create view mysqltest.v3 as select b from mysqltest.t2;
+
+# Expression need select privileges
+-- error 1143
+create view v4 as select b+1 from mysqltest.t2;
+
+connection root;
+grant create view,update,select on test.* to mysqltest_1@localhost;
+connection user1;
+-- error 1143
+create view v4 as select b+1 from mysqltest.t2;
+
+connection root;
+grant update,select(b) on mysqltest.t2 to mysqltest_1@localhost;
+connection user1;
+create view v4 as select b+1 from mysqltest.t2;
+
+connection root;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_1@localhost;
+drop database mysqltest;
+drop view v1,v2,v4;
+
+#
+# user with global DB privileges
+#
+connection root;
+--disable_warnings
+create database mysqltest;
+--enable_warnings
+create table mysqltest.t1 (a int);
+grant all privileges on mysqltest.* to mysqltest_1@localhost;
+
+connection user1;
+use mysqltest;
+create view v1 as select * from t1;
+
+connection root;
+revoke all privileges on mysqltest.* from mysqltest_1@localhost;
+drop database mysqltest;
+
diff --git a/mysql-test/t/view_query_cache.test b/mysql-test/t/view_query_cache.test
new file mode 100644
index 00000000000..bca111a5ed1
--- /dev/null
+++ b/mysql-test/t/view_query_cache.test
@@ -0,0 +1,87 @@
+-- source include/have_query_cache.inc
+#
+# QUERY CACHE options for VIEWs
+#
+--disable_warnings
+drop table if exists t1,t2,v1,v2,v3;
+drop view if exists t1,t2,v1,v2,v3;
+--enable_warnings
+
+set GLOBAL query_cache_size=1355776;
+flush status;
+create table t1 (a int, b int);
+
+# queries with following views should not be in query cache
+create view v1 (c,d) as select sql_no_cache a,b from t1;
+create view v2 (c,d) as select a+rand(),b from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from v1;
+select * from v2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from v1;
+select * from v2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+drop view v1,v2;
+
+# SQL_CACHE option
+set query_cache_type=demand;
+flush status;
+# query with view will be cached, but direct acess to table will not
+create view v1 (c,d) as select sql_cache a,b from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from v1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from v1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+drop view v1;
+set query_cache_type=default;
+
+drop table t1;
+
+#
+# invalidation of view
+#
+create table t1 (a int);
+insert into t1 values (1), (2), (3);
+create view v1 as select a from t1 where a > 1;
+select * from v1;
+alter view v1 as select a from t1 where a > 2;
+select * from v1;
+drop view v1;
+-- error 1146
+select * from v1;
+drop table t1;
+
+#
+# join view with QC
+#
+create table t1 (a int, primary key (a), b int);
+create table t2 (a int, primary key (a), b int);
+insert into t2 values (1000, 2000);
+create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
+select * from v3;
+drop view v3;
+drop table t1, t2;
+
+set GLOBAL query_cache_size=default;
diff --git a/mysql-test/t/view_skip_grants-master.opt b/mysql-test/t/view_skip_grants-master.opt
new file mode 100644
index 00000000000..5699a3387b8
--- /dev/null
+++ b/mysql-test/t/view_skip_grants-master.opt
@@ -0,0 +1 @@
+--skip-grant-tables
diff --git a/mysql-test/t/view_skip_grants.test b/mysql-test/t/view_skip_grants.test
new file mode 100644
index 00000000000..bfbaec44eb1
--- /dev/null
+++ b/mysql-test/t/view_skip_grants.test
@@ -0,0 +1,14 @@
+--disable_warnings
+drop table if exists t1,v1;
+drop view if exists t1,v1;
+--enable_warnings
+use test;
+
+#
+# test that we can create VIEW if privileges check switched off
+#
+create table t1 (field1 INT);
+CREATE VIEW v1 AS SELECT field1 FROM t1;
+
+drop view v1;
+drop table t1
diff --git a/mysql-test/t/warnings.test b/mysql-test/t/warnings.test
index 2a90f5f637d..69284b4c6e4 100644
--- a/mysql-test/t/warnings.test
+++ b/mysql-test/t/warnings.test
@@ -39,9 +39,8 @@ show warnings limit 1;
drop database if exists not_exists_db;
show count(*) warnings;
create table t1(id int);
-# PS doesn't give warnings on prepare
---disable_ps_protocol
create table if not exists t1(id int);
+--disable_ps_protocol
select @@warning_count;
--enable_ps_protocol
drop table t1;
@@ -122,12 +121,9 @@ drop table t1;
# Test for deprecated TYPE= syntax
#
-# PS doesn't give warnings on prepare
---disable_ps_protocol
create table t1 (id int) type=heap;
alter table t1 type=myisam;
drop table t1;
---enable_ps_protocol
#
# Test for deprecated table_type variable
diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test
new file mode 100644
index 00000000000..321e5008035
--- /dev/null
+++ b/mysql-test/t/xa.test
@@ -0,0 +1,58 @@
+#
+# WL#1756
+#
+-- source include/have_innodb.inc
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+create table t1 (a int) engine=innodb;
+xa start 'test1';
+insert t1 values (10);
+xa end 'test1';
+xa prepare 'test1';
+xa rollback 'test1';
+select * from t1;
+
+xa start 'test2';
+--error 1399
+xa start 'test-bad';
+insert t1 values (20);
+--error 1399
+xa prepare 'test2';
+xa end 'test2';
+xa prepare 'test2';
+xa commit 'test2';
+select * from t1;
+
+xa start 'testa','testb';
+insert t1 values (30);
+xa end 'testa','testb';
+
+connect (con1,localhost,,,);
+connection con1;
+
+# gtrid [ , bqual [ , formatID ] ]
+xa start 0x7465737462, 0x2030405060, 0xb;
+insert t1 values (40);
+xa end 'testb',' 0@P`',11;
+xa prepare 'testb',0x2030405060,11;
+
+xa recover;
+
+# uncomment the line below when binlog will be able to prepare
+#disconnect con1;
+connection default;
+
+xa prepare 'testa','testb';
+
+xa recover;
+
+xa commit 'testb',0x2030405060,11;
+xa rollback 'testa','testb';
+
+--error 1064
+xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
+
+select * from t1;
+drop table t1;
+
diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp
new file mode 100644
index 00000000000..d8a13ca9dfd
--- /dev/null
+++ b/mysql-test/valgrind.supp
@@ -0,0 +1,94 @@
+#
+# Suppress some common (not fatal) errors in system libraries found by valgrind
+#
+
+#
+# Pthread doesn't free all thread specific memory before program exists
+#
+{
+ pthread allocate_tls memory loss
+ Memcheck:Leak
+ fun:calloc
+ fun:_dl_allocate_tls
+ fun:allocate_stack
+ fun:pthread_create@@GLIBC_2.1
+}
+
+{
+ pthread allocate_dtv memory loss
+ Memcheck:Leak
+ fun:calloc
+ fun:allocate_dtv
+ fun:_dl_allocate_tls_storage
+ fun:__GI__dl_allocate_tls
+ fun:pthread_create
+}
+
+{
+ pthread memalign memory loss
+ Memcheck:Leak
+ fun:memalign
+ fun:_dl_allocate_tls_storage
+ fun:__GI__dl_allocate_tls
+ fun:pthread_create
+}
+
+{
+ pthread errno
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlsym
+ fun:__errno_location
+}
+
+
+#
+# Warnings in libz becasue it works with aligned memory(?)
+#
+
+{
+ libz tr_flush_block
+ Memcheck:Cond
+ fun:_tr_flush_block
+ fun:deflate_slow
+ fun:deflate
+ fun:do_flush
+ fun:gzclose
+}
+
+{
+ libz tr_flush_block2
+ Memcheck:Cond
+ fun:_tr_flush_block
+ fun:deflate_slow
+ fun:deflate
+ fun:compress2
+}
+
+{
+ libz longest_match
+ Memcheck:Cond
+ fun:longest_match
+ fun:deflate_slow
+ fun:deflate
+ fun:do_flush
+}
+
+{
+ libz longest_match2
+ Memcheck:Cond
+ fun:longest_match
+ fun:deflate_slow
+ fun:deflate
+ fun:compress2
+}
+
+{
+ libz deflate
+ Memcheck:Cond
+ obj:/usr/lib/libz.so.*
+ obj:/usr/lib/libz.so.*
+ fun:deflate
+ fun:compress2
+}
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index 3ae9c05bff5..db8aa10bf1a 100644
--- a/mysys/Makefile.am
+++ b/mysys/Makefile.am
@@ -17,8 +17,7 @@
MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
-INCLUDES = @MT_INCLUDES@ \
- @ZLIB_INCLUDES@ -I$(top_srcdir)/include -I$(srcdir)
+INCLUDES = @ZLIB_INCLUDES@ -I$(top_srcdir)/include -I$(srcdir)
pkglib_LIBRARIES = libmysys.a
LDADD = libmysys.a ../dbug/libdbug.a \
../strings/libmystrings.a
@@ -26,7 +25,7 @@ noinst_HEADERS = mysys_priv.h my_static.h \
my_os2cond.c my_os2dirsrch.c my_os2dirsrch.h \
my_os2dlfcn.c my_os2file64.c my_os2mutex.c \
my_os2thread.c my_os2tls.c
-libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c \
+libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_path.c mf_loadpath.c my_file.c \
my_open.c my_create.c my_dup.c my_seek.c my_read.c \
my_pread.c my_write.c \
@@ -53,11 +52,11 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c \
my_net.c my_semaphore.c my_port.c my_sleep.c \
charset.c charset-def.c my_bitmap.c my_bit.c md5.c \
my_gethostbyname.c rijndael.c my_aes.c sha1.c \
- my_handler.c my_netware.c my_windac.c
+ my_handler.c my_netware.c my_largepage.c \
+ my_windac.c
EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
thr_mutex.c thr_rwlock.c
libmysys_a_LIBADD = @THREAD_LOBJECTS@
-noinst_PROGRAMS = charset2html @THREAD_LPROGRAMS@
# test_dir_DEPENDENCIES= $(LIBRARIES)
# testhash_DEPENDENCIES= $(LIBRARIES)
# test_charset_DEPENDENCIES= $(LIBRARIES)
@@ -67,6 +66,7 @@ DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
+ -DDEFAULT_HOME_ENV=MYSQL_HOME \
@DEFS@
libmysys_a_DEPENDENCIES= @THREAD_LOBJECTS@
@@ -105,9 +105,6 @@ test_dir$(EXEEXT): test_dir.c $(LIBRARIES)
test_charset$(EXEEXT): test_charset.c $(LIBRARIES)
$(LINK) $(FLAGS) -DMAIN $(srcdir)/test_charset.c $(LDADD) $(LIBS)
-charset2html$(EXEEXT): charset2html.c $(LIBRARIES)
- $(LINK) $(FLAGS) -DMAIN $(srcdir)/charset2html.c $(LDADD) $(LIBS)
-
testhash$(EXEEXT): testhash.c $(LIBRARIES)
$(LINK) $(FLAGS) -DMAIN $(srcdir)/testhash.c $(LDADD) $(LIBS)
diff --git a/mysys/charset-def.c b/mysys/charset-def.c
index d4f69a49a2c..0464ba893fb 100644
--- a/mysys/charset-def.c
+++ b/mysys/charset-def.c
@@ -88,10 +88,20 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_cp1250_czech_ci);
#endif
+#ifdef HAVE_CHARSET_cp932
+ add_compiled_collation(&my_charset_cp932_japanese_ci);
+ add_compiled_collation(&my_charset_cp932_bin);
+#endif
+
#ifdef HAVE_CHARSET_latin2
add_compiled_collation(&my_charset_latin2_czech_ci);
#endif
+#ifdef HAVE_CHARSET_eucjpms
+ add_compiled_collation(&my_charset_eucjpms_japanese_ci);
+ add_compiled_collation(&my_charset_eucjpms_bin);
+#endif
+
#ifdef HAVE_CHARSET_euckr
add_compiled_collation(&my_charset_euckr_korean_ci);
add_compiled_collation(&my_charset_euckr_bin);
diff --git a/mysys/charset.c b/mysys/charset.c
index 4b7ad3e59f4..534a6aa998e 100644
--- a/mysys/charset.c
+++ b/mysys/charset.c
@@ -547,10 +547,10 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name,
DBUG_PRINT("enter",("name: '%s'", cs_name));
(void) init_available_charsets(MYF(0)); /* If it isn't initialized */
-
+
cs_number= get_charset_number(cs_name, cs_flags);
cs= cs_number ? get_internal_charset(cs_number, flags) : NULL;
-
+
if (!cs && (flags & MY_WME))
{
char index_file[FN_REFLEN];
@@ -561,22 +561,35 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name,
DBUG_RETURN(cs);
}
-
-ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to,
+/*
+ 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.
+*/
+ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
+ char *to, ulong to_length,
const char *from, ulong length)
{
const char *to_start= to;
- const char *end;
+ const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
+ my_bool overflow=0;
#ifdef USE_MB
my_bool use_mb_flag= use_mb(charset_info);
#endif
- for (end= from + length; from != end; from++)
+ for (end= from + length; from < end; from++)
{
+ char escape=0;
#ifdef USE_MB
- int l;
- if (use_mb_flag && (l= my_ismbchar(charset_info, from, end)))
+ int tmp_length;
+ if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
{
- while (l--)
+ if (to + tmp_length > to_end)
+ {
+ overflow=1;
+ break;
+ }
+ while (tmp_length--)
*to++= *from++;
from--;
continue;
@@ -592,46 +605,54 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to,
multi-byte character into a valid one. For example, 0xbf27 is not
a valid GBK character, but 0xbf5c is. (0x27 = ', 0x5c = \)
*/
- if (use_mb_flag && (l= my_mbcharlen(charset_info, *from)) > 1)
- {
- *to++= '\\';
- *to++= *from;
- continue;
- }
+ if (use_mb_flag && (tmp_length= my_mbcharlen(charset_info, *from)) > 1)
+ escape= *from;
+ else
#endif
switch (*from) {
case 0: /* Must be escaped for 'mysql' */
- *to++= '\\';
- *to++= '0';
+ escape= '0';
break;
case '\n': /* Must be escaped for logs */
- *to++= '\\';
- *to++= 'n';
+ escape= 'n';
break;
case '\r':
- *to++= '\\';
- *to++= 'r';
+ escape= 'r';
break;
case '\\':
- *to++= '\\';
- *to++= '\\';
+ escape= '\\';
break;
case '\'':
- *to++= '\\';
- *to++= '\'';
+ escape= '\'';
break;
case '"': /* Better safe than sorry */
- *to++= '\\';
- *to++= '"';
+ escape= '"';
break;
case '\032': /* This gives problems on Win32 */
- *to++= '\\';
- *to++= 'Z';
+ escape= 'Z';
break;
- default:
+ }
+ if (escape)
+ {
+ if (to + 2 > to_end)
+ {
+ overflow=1;
+ break;
+ }
+ *to++= '\\';
+ *to++= escape;
+ }
+ else
+ {
+ if (to + 1 > to_end)
+ {
+ overflow=1;
+ break;
+ }
*to++= *from;
}
}
*to= 0;
- return (ulong) (to - to_start);
+ return overflow ? (ulong)~0 : (ulong) (to - to_start);
}
+
diff --git a/mysys/default.c b/mysys/default.c
index bf23502389d..aa2293ac0af 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -37,28 +37,16 @@
#include "m_string.h"
#include "m_ctype.h"
#include <my_dir.h>
+#ifdef __WIN__
+#include <winbase.h>
+#endif
char *defaults_extra_file=0;
/* Which directories are searched for options (and in which order) */
-const char *default_directories[]= {
-#ifdef __WIN__
-"C:/",
-#elif defined(__NETWARE__)
-"sys:/etc/",
-#else
-"/etc/",
-#endif
-#ifdef DATADIR
-DATADIR,
-#endif
-"", /* Place for defaults_extra_dir */
-#if !defined(__WIN__) && !defined(__NETWARE__)
-"~/",
-#endif
-NullS,
-};
+#define MAX_DEFAULT_DIRS 4
+const char *default_directories[MAX_DEFAULT_DIRS + 1];
#ifdef __WIN__
static const char *f_extensions[]= { ".ini", ".cnf", 0 };
@@ -66,19 +54,174 @@ static const char *f_extensions[]= { ".ini", ".cnf", 0 };
static const char *f_extensions[]= { ".cnf", 0 };
#endif
-static int search_default_file(DYNAMIC_ARRAY *args,MEM_ROOT *alloc,
- const char *dir, const char *config_file,
- TYPELIB *group);
+/*
+ This structure defines the context that we pass to callback
+ function 'handle_default_option' used in search_default_file
+ to process each option. This context is used if search_default_file
+ was called from load_defaults.
+*/
+
+struct handle_option_ctx
+{
+ MEM_ROOT *alloc;
+ DYNAMIC_ARRAY *args;
+ TYPELIB *group;
+};
-static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
+static int search_default_file(Process_option_func func, void *func_ctx,
+ const char *dir, const char *config_file);
+static int search_default_file_with_ext(Process_option_func func,
+ void *func_ctx,
const char *dir, const char *ext,
- const char *config_file,
- TYPELIB *group, int recursion_level);
+ const char *config_file, int recursion_level);
+static void init_default_directories();
static char *remove_end_comment(char *ptr);
/*
+ Process config files in default directories.
+
+ SYNOPSIS
+ my_search_option_files()
+ conf_file Basename for configuration file to search for.
+ If this is a path, then only this file is read.
+ argc Pointer to argc of original program
+ argv Pointer to argv of original program
+ args_used Pointer to variable for storing the number of
+ arguments used.
+ func Pointer to the function to process options
+ func_ctx It's context. Usually it is the structure to
+ store additional options.
+ DESCRIPTION
+
+ This function looks for config files in default directories. Then it
+ travesrses each of the files and calls func to process each option.
+
+ RETURN
+ 0 ok
+ 1 given cinf_file doesn't exist
+*/
+
+int my_search_option_files(const char *conf_file, int *argc, char ***argv,
+ uint *args_used, Process_option_func func,
+ void *func_ctx)
+{
+ const char **dirs, *forced_default_file;
+ int error= 0;
+ DBUG_ENTER("my_search_option_files");
+
+ /* Check if we want to force the use a specific default file */
+ get_defaults_files(*argc, *argv,
+ (char **)&forced_default_file, &defaults_extra_file);
+ if (forced_default_file)
+ forced_default_file= strchr(forced_default_file,'=')+1;
+ if (defaults_extra_file)
+ defaults_extra_file= strchr(defaults_extra_file,'=')+1;
+
+ (*args_used)+= (forced_default_file ? 1 : 0) + (defaults_extra_file ? 1 : 0);
+
+ if (forced_default_file)
+ {
+ if ((error= search_default_file_with_ext(func, func_ctx, "", "",
+ forced_default_file, 0)) < 0)
+ goto err;
+ if (error > 0)
+ {
+ fprintf(stderr, "Could not open required defaults file: %s\n",
+ forced_default_file);
+ goto err;
+ }
+ }
+ else if (dirname_length(conf_file))
+ {
+ if ((error= search_default_file(func, func_ctx, NullS, conf_file)) < 0)
+ goto err;
+ }
+ else
+ {
+#ifdef __WIN__
+ char system_dir[FN_REFLEN];
+ GetWindowsDirectory(system_dir,sizeof(system_dir));
+ if ((search_default_file(func, func_ctx, system_dir, conf_file)))
+ goto err;
+#endif
+#if defined(__EMX__) || defined(OS2)
+ {
+ const char *etc;
+ if ((etc= getenv("ETC")) &&
+ (search_default_file(func, func_ctx, etc, conf_file)) < 0)
+ goto err;
+ }
+#endif
+ for (dirs= default_directories ; *dirs; dirs++)
+ {
+ if (**dirs)
+ {
+ if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
+ goto err;
+ }
+ else if (defaults_extra_file)
+ {
+ if (search_default_file(func, func_ctx, NullS,
+ defaults_extra_file) < 0)
+ goto err; /* Fatal error */
+
+ }
+ }
+ }
+
+ DBUG_RETURN(error);
+
+err:
+ fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
+ exit(1);
+ return 0; /* Keep compiler happy */
+}
+
+
+/*
+ The option handler for load_defaults.
+
+ SYNOPSIS
+ handle_deault_option()
+ in_ctx Handler context. In this case it is a
+ handle_option_ctx structure.
+ group_name The name of the group the option belongs to.
+ option The very option to be processed. It is already
+ prepared to be used in argv (has -- prefix)
+
+ DESCRIPTION
+ This handler checks whether a group is one of the listed and adds an option
+ to the array if yes. Some other handler can record, for instance, all
+ groups and their options, not knowing in advance the names and amount of
+ groups.
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+static int handle_default_option(void *in_ctx, const char *group_name,
+ const char *option)
+{
+ char *tmp;
+ struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
+
+ if (find_type((char *)group_name, ctx->group, 3))
+ {
+ if (!(tmp= alloc_root(ctx->alloc, (uint) strlen(option) + 1)))
+ return 1;
+ if (insert_dynamic(ctx->args, (gptr) &tmp))
+ return 1;
+ strmov(tmp, option);
+ }
+
+ return 0;
+}
+
+
+/*
Gets --defaults-file and --defaults-extra-file options from command line.
SYNOPSIS
@@ -136,7 +279,6 @@ void get_defaults_files(int argc, char **argv,
RETURN
0 ok
1 The given conf_file didn't exists
- 2 The given conf_file was not a normal readable file
*/
@@ -144,16 +286,16 @@ int load_defaults(const char *conf_file, const char **groups,
int *argc, char ***argv)
{
DYNAMIC_ARRAY args;
- const char **dirs, *forced_default_file;
TYPELIB group;
my_bool found_print_defaults=0;
uint args_used=0;
int error= 0;
MEM_ROOT alloc;
- char *ptr, **res;
-
+ char *ptr,**res;
+ struct handle_option_ctx ctx;
DBUG_ENTER("load_defaults");
+ init_default_directories();
init_alloc_root(&alloc,512,0);
if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
{
@@ -173,75 +315,22 @@ int load_defaults(const char *conf_file, const char **groups,
DBUG_RETURN(0);
}
- get_defaults_files(*argc, *argv,
- (char **)&forced_default_file, &defaults_extra_file);
- if (forced_default_file)
- forced_default_file= strchr(forced_default_file,'=')+1;
- if (defaults_extra_file)
- defaults_extra_file= strchr(defaults_extra_file,'=')+1;
-
- args_used+= (forced_default_file ? 1 : 0) + (defaults_extra_file ? 1 : 0);
-
group.count=0;
group.name= "defaults";
group.type_names= groups;
+
for (; *groups ; groups++)
group.count++;
if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
goto err;
- if (forced_default_file)
- {
- if ((error= search_default_file_with_ext(&args, &alloc, "", "",
- forced_default_file,
- &group, 0)) < 0)
- goto err;
- if (error > 0)
- {
- fprintf(stderr, "Could not open required defaults file: %s\n",
- forced_default_file);
- goto err;
- }
- }
- else if (dirname_length(conf_file))
- {
- if ((error= search_default_file(&args, &alloc, NullS, conf_file,
- &group)) < 0)
- goto err;
- }
- else
- {
-#ifdef __WIN__
- char system_dir[FN_REFLEN];
- GetWindowsDirectory(system_dir,sizeof(system_dir));
- if ((search_default_file(&args, &alloc, system_dir, conf_file, &group)))
- goto err;
-#endif
-#if defined(__EMX__) || defined(OS2)
- {
- const char *etc;
- if ((etc= getenv("ETC")) &&
- (search_default_file(&args, &alloc, etc, conf_file,
- &group)) < 0)
- goto err;
- }
-#endif
- for (dirs=default_directories ; *dirs; dirs++)
- {
- if (**dirs)
- {
- if (search_default_file(&args, &alloc, *dirs, conf_file,
- &group) < 0)
- goto err;
- }
- else if (defaults_extra_file)
- {
- if (search_default_file(&args, &alloc, NullS, defaults_extra_file,
- &group) < 0)
- goto err; /* Fatal error */
- }
- }
- }
+
+ ctx.alloc= &alloc;
+ ctx.args= &args;
+ ctx.group= &group;
+
+ error= my_search_option_files(conf_file, argc, argv, &args_used,
+ handle_default_option, (void *) &ctx);
/*
Here error contains <> 0 only if we have a fully specified conf_file
or a forced default file
@@ -301,17 +390,19 @@ void free_defaults(char **argv)
}
-static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
+static int search_default_file(Process_option_func opt_handler,
+ void *handler_ctx,
const char *dir,
- const char *config_file, TYPELIB *group)
+ const char *config_file)
{
char **ext;
for (ext= (char**) f_extensions; *ext; *ext++)
{
int error;
- if ((error= search_default_file_with_ext(args, alloc, dir, *ext,
- config_file, group, 0)) < 0)
+ if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
+ dir, *ext,
+ config_file, 0)) < 0)
return error;
}
return 0;
@@ -373,8 +464,10 @@ static char *get_argument(const char *keyword, uint kwlen,
SYNOPSIS
search_default_file_with_ext()
- args Store pointer to found options here
- alloc Allocate strings in this object
+ opt_handler Option handler function. It is used to process
+ every separate option.
+ handler_ctx Pointer to the structure to store actual
+ parameters of the function.
dir directory to read
ext Extension for configuration file
config_file Name of configuration file
@@ -386,21 +479,23 @@ static char *get_argument(const char *keyword, uint kwlen,
0 Success
-1 Fatal error, abort
1 File not found (Warning)
- 2 File is not a regular file (Warning)
*/
-static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
- const char *dir, const char *ext,
- const char *config_file,
- TYPELIB *group, int recursion_level)
+static int search_default_file_with_ext(Process_option_func opt_handler,
+ void *handler_ctx,
+ const char *dir,
+ const char *ext,
+ const char *config_file,
+ int recursion_level)
{
- char name[FN_REFLEN + 10], buff[4096], *ptr, *end, *value, *tmp, **tmp_ext;
+ char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
+ char *value, option[4096], tmp[FN_REFLEN];
static const char includedir_keyword[]= "includedir";
static const char include_keyword[]= "include";
const int max_recursion_level= 10;
FILE *fp;
- uint line= 0;
- my_bool read_values= 0, found_group= 0;
+ uint line=0;
+ my_bool found_group=0;
uint i;
MY_DIR *search_dir;
FILEINFO *search_file;
@@ -432,13 +527,13 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
if ((stat_info.st_mode & S_IWOTH) &&
(stat_info.st_mode & S_IFMT) == S_IFREG)
{
- fprintf(stderr, "warning: World-writable config file %s is ignored\n",
+ fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
name);
return 0;
}
}
#endif
- if (!(fp= my_fopen(fn_format(name, name, "", "", 4), O_RDONLY, MYF(0))))
+ if (!(fp= my_fopen(name, O_RDONLY, MYF(0))))
return 0; /* Ignore wrong files */
while (fgets(buff, sizeof(buff) - 1, fp))
@@ -498,14 +593,10 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
if (*tmp_ext)
{
- if (!(tmp= alloc_root(alloc, 2 + strlen(search_file->name)
- + strlen(ptr))))
- goto err;
-
fn_format(tmp, search_file->name, ptr, "",
MY_UNPACK_FILENAME | MY_SAFE_PATH);
- search_default_file_with_ext(args, alloc, "", "", tmp, group,
+ search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp,
recursion_level + 1);
}
}
@@ -520,7 +611,7 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
name, line)))
goto err;
- search_default_file_with_ext(args, alloc, "", "", ptr, group,
+ search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
recursion_level + 1);
}
@@ -539,7 +630,8 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
}
for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;/* Remove end space */
end[0]=0;
- read_values=find_type(ptr,group,3) > 0;
+
+ strnmov(curr_gr, ptr, min((uint) (end-ptr)+1, 4096));
continue;
}
if (!found_group)
@@ -549,19 +641,17 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
name,line);
goto err;
}
- if (!read_values)
- continue;
+
+
end= remove_end_comment(ptr);
if ((value= strchr(ptr, '=')))
end= value; /* Option without argument */
for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
if (!value)
{
- if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3)))
- goto err;
- strmake(strmov(tmp,"--"),ptr,(uint) (end-ptr));
- if (insert_dynamic(args,(gptr) &tmp))
- goto err;
+ strmake(strmov(option,"--"),ptr,(uint) (end-ptr));
+ if (opt_handler(handler_ctx, curr_gr, option))
+ goto err;
}
else
{
@@ -583,12 +673,7 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
value++;
value_end--;
}
- if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3 +
- (uint) (value_end-value)+1)))
- goto err;
- if (insert_dynamic(args,(gptr) &tmp))
- goto err;
- ptr=strnmov(strmov(tmp,"--"),ptr,(uint) (end-ptr));
+ ptr=strnmov(strmov(option,"--"),ptr,(uint) (end-ptr));
*ptr++= '=';
for ( ; value != value_end; value++)
@@ -630,6 +715,8 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
*ptr++= *value;
}
*ptr=0;
+ if (opt_handler(handler_ctx, curr_gr, option))
+ goto err;
}
}
my_fclose(fp,MYF(0));
@@ -676,6 +763,7 @@ void print_defaults(const char *conf_file, const char **groups)
char name[FN_REFLEN], **ext;
const char **dirs;
+ init_default_directories();
puts("\nDefault options are read from the following files in the given order:");
if (dirname_length(conf_file))
@@ -738,3 +826,23 @@ void print_defaults(const char *conf_file, const char **groups)
}
#include <help_end.h>
+
+static void init_default_directories()
+{
+ const char *env, **ptr= default_directories;
+
+#ifdef __WIN__
+ *ptr++= "C:/";
+#elif defined(__NETWARE__)
+ *ptr++= "sys:/etc/";
+#else
+ *ptr++= "/etc/";
+#endif
+ if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV))))
+ *ptr++= env;
+ *ptr++= ""; /* Place for defaults_extra_file */
+#if !defined(__WIN__) && !defined(__NETWARE__)
+ *ptr++= "~/";;
+#endif
+ *ptr= 0; /* end marker */
+}
diff --git a/mysys/errors.c b/mysys/errors.c
index 05436c9a212..4472b7173fa 100644
--- a/mysys/errors.c
+++ b/mysys/errors.c
@@ -21,7 +21,6 @@
const char * NEAR globerrs[GLOBERRS]=
{
- "File '%s' not found (Errcode: %d)",
"Can't create/write to file '%s' (Errcode: %d)",
"Error reading file '%s' (Errcode: %d)",
"Error writing file '%s' (Errcode: %d)",
@@ -50,20 +49,18 @@ const char * NEAR globerrs[GLOBERRS]=
"Error on realpath() on '%s' (Error %d)",
"Can't sync file '%s' to disk (Errcode: %d)",
"Collation '%s' is not a compiled collation and is not specified in the '%s' file",
+ "File '%s' not found (Errcode: %d)",
};
void init_glob_errs(void)
{
- my_errmsg[GLOB] = & globerrs[0];
-} /* init_glob_errs */
+ /* This is now done statically. */
+}
#else
void init_glob_errs()
{
- my_errmsg[GLOB] = & globerrs[0];
-
- EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)";
EE(EE_CANTCREATEFILE) = "Can't create/write to file '%s' (Errcode: %d)";
EE(EE_READ) = "Error reading file '%s' (Errcode: %d)";
EE(EE_WRITE) = "Error writing file '%s' (Errcode: %d)";
@@ -91,5 +88,6 @@ void init_glob_errs()
EE(EE_REALPATH)= "Error on realpath() on '%s' (Error %d)";
EE(EE_SYNC)= "Can't sync file '%s' to disk (Errcode: %d)";
EE(EE_UNKNOWN_COLLATION)= "Collation '%s' is not a compiled collation and is not specified in the %s file";
+ EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)";
}
#endif
diff --git a/mysys/hash.c b/mysys/hash.c
index b829f19dfc8..fe27b5fcb6d 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -103,7 +103,7 @@ static inline void hash_free_elements(HASH *hash)
hash_free()
hash the hash to delete elements of
- NOTES: Hash can't be reused wuthing calling hash_init again.
+ NOTES: Hash can't be reused without calling hash_init again.
*/
void hash_free(HASH *hash)
diff --git a/mysys/list.c b/mysys/list.c
index 64fca10dc0b..c3cd6c94b9f 100644
--- a/mysys/list.c
+++ b/mysys/list.c
@@ -28,7 +28,7 @@
LIST *list_add(LIST *root, LIST *element)
{
DBUG_ENTER("list_add");
- DBUG_PRINT("enter",("root: 0x%lx element: %lx", root, element));
+ DBUG_PRINT("enter",("root: 0x%lx element: 0x%lx", root, element));
if (root)
{
if (root->prev) /* If add in mid of list */
diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c
index 189d43e782a..b12e68cc1f9 100644
--- a/mysys/mf_getdate.c
+++ b/mysys/mf_getdate.c
@@ -19,11 +19,20 @@
#include "mysys_priv.h"
#include <m_string.h>
- /*
- If flag & 1 Return date and time
- If flag & 2 Return short date format YYMMDD
- if flag & 4 Return time in HHMMDD format.
- */
+/*
+ get date as string
+
+ SYNOPSIS
+ get_date()
+ to - string where date will be written
+ flag - format of date:
+ If flag & GETDATE_TIME Return date and time
+ If flag & GETDATE_SHORT_DATE Return short date format YYMMDD
+ If flag & GETDATE_HHMMSSTIME Return time in HHMMDD format.
+ If flag & GETDATE_GMT Date/time in GMT
+ If flag & GETDATE_FIXEDLENGTH Return fixed length date/time
+ date - for conversion
+*/
void get_date(register my_string to, int flag, time_t date)
@@ -36,27 +45,36 @@ void get_date(register my_string to, int flag, time_t date)
skr=date ? (time_t) date : time((time_t*) 0);
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
- localtime_r(&skr,&tm_tmp);
+ if (flag & GETDATE_GMT)
+ localtime_r(&skr,&tm_tmp);
+ else
+ gmtime_r(&skr,&tm_tmp);
start_time= &tm_tmp;
#else
- start_time=localtime(&skr);
+ if (flag & GETDATE_GMT)
+ start_time= localtime(&skr);
+ else
+ gmtime(&skr,&tm_tmp);
#endif
- if (flag & 2)
+ if (flag & GETDATE_SHORT_DATE)
sprintf(to,"%02d%02d%02d",
start_time->tm_year % 100,
start_time->tm_mon+1,
start_time->tm_mday);
else
- sprintf(to,"%d-%02d-%02d",
+ sprintf(to, ((flag & GETDATE_FIXEDLENGTH) ?
+ "%4d-%02d-%02d" : "%d-%02d-%02d"),
start_time->tm_year+1900,
start_time->tm_mon+1,
start_time->tm_mday);
- if (flag & 1)
- sprintf(strend(to)," %2d:%02d:%02d",
+ if (flag & GETDATE_DATE_TIME)
+ sprintf(strend(to),
+ ((flag & GETDATE_FIXEDLENGTH) ?
+ " %02d:%02d:%02d" : " %2d:%02d:%02d"),
start_time->tm_hour,
start_time->tm_min,
start_time->tm_sec);
- else if (flag & 4)
+ else if (flag & GETDATE_HHMMSSTIME)
sprintf(strend(to),"%02d%02d%02d",
start_time->tm_hour,
start_time->tm_min,
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
index d80de3101be..b86e9daf92d 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -27,7 +27,7 @@
also info->read_pos is set to info->read_end.
If called through open_cached_file(), then the temporary file will
only be created if a write exeeds the file buffer or if one calls
- flush_io_cache().
+ my_b_flush_io_cache().
If one uses SEQ_READ_APPEND, then two buffers are allocated, one for
reading and another for writing. Reads are first done from disk and
@@ -43,7 +43,7 @@ TODO:
each time the write buffer gets full and it's written to disk, we will
always do a disk read to read a part of the buffer from disk to the
read buffer.
- This should be fixed so that when we do a flush_io_cache() and
+ This should be fixed so that when we do a my_b_flush_io_cache() and
we have been reading the write buffer, we should transfer the rest of the
write buffer to the read buffer before we start to reuse it.
*/
@@ -360,7 +360,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
if (info->type == WRITE_CACHE && type == READ_CACHE)
info->end_of_file=my_b_tell(info);
/* flush cache if we want to reuse it */
- if (!clear_cache && flush_io_cache(info))
+ if (!clear_cache && my_b_flush_io_cache(info,1))
DBUG_RETURN(1);
info->pos_in_file=seek_offset;
/* Better to do always do a seek */
@@ -969,7 +969,7 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
Buffer+=rest_length;
Count-=rest_length;
info->write_pos+=rest_length;
- if (flush_io_cache(info))
+ if (my_b_flush_io_cache(info,1))
return 1;
if (Count >= IO_SIZE)
{ /* Fill first intern buffer */
@@ -1212,6 +1212,7 @@ int end_io_cache(IO_CACHE *info)
int error=0;
IO_CACHE_CALLBACK pre_close;
DBUG_ENTER("end_io_cache");
+ DBUG_PRINT("enter",("cache: 0x%lx", (ulong) info));
#ifdef THREAD
/*
@@ -1221,7 +1222,7 @@ int end_io_cache(IO_CACHE *info)
*/
if (info->share)
{
- pthread_cond_destroy (&info->share->cond);
+ pthread_cond_destroy(&info->share->cond);
pthread_mutex_destroy(&info->share->mutex);
info->share=0;
}
@@ -1236,7 +1237,7 @@ int end_io_cache(IO_CACHE *info)
{
info->alloced_buffer=0;
if (info->file != -1) /* File doesn't exist */
- error=flush_io_cache(info);
+ error= my_b_flush_io_cache(info,1);
my_free((gptr) info->buffer,MYF(MY_WME));
info->buffer=info->read_pos=(byte*) 0;
}
diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c
index 3755bcdb53d..1f3db84304e 100644
--- a/mysys/mf_iocache2.c
+++ b/mysys/mf_iocache2.c
@@ -65,6 +65,13 @@ my_off_t my_b_append_tell(IO_CACHE* info)
return res;
}
+my_off_t my_b_safe_tell(IO_CACHE *info)
+{
+ if (unlikely(info->type == SEQ_READ_APPEND))
+ return my_b_append_tell(info);
+ return my_b_tell(info);
+}
+
/*
Make next read happen at the given position
For write cache, make next write happen at the given position
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
index cee1b7eb4e9..2308536cd37 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -341,8 +341,8 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
blocks--;
/* Allocate memory for cache page buffers */
if ((keycache->block_mem=
- my_malloc_lock((ulong) blocks * keycache->key_cache_block_size,
- MYF(0))))
+ my_large_malloc((ulong) blocks * keycache->key_cache_block_size,
+ MYF(MY_WME))))
{
/*
Allocate memory for blocks, hash_links and hash entries;
@@ -351,7 +351,7 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
if ((keycache->block_root= (BLOCK_LINK*) my_malloc((uint) length,
MYF(0))))
break;
- my_free_lock(keycache->block_mem, MYF(0));
+ my_large_free(keycache->block_mem, MYF(0));
keycache->block_mem= 0;
}
if (blocks < 8)
@@ -422,7 +422,7 @@ err:
keycache->blocks= 0;
if (keycache->block_mem)
{
- my_free_lock((gptr) keycache->block_mem, MYF(0));
+ my_large_free((gptr) keycache->block_mem, MYF(0));
keycache->block_mem= NULL;
}
if (keycache->block_root)
@@ -606,7 +606,7 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup)
{
if (keycache->block_mem)
{
- my_free_lock((gptr) keycache->block_mem, MYF(0));
+ my_large_free((gptr) keycache->block_mem, MYF(0));
keycache->block_mem= NULL;
my_free((gptr) keycache->block_root, MYF(0));
keycache->block_root= NULL;
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index d8c19d86e5c..e0d6288f76b 100644
--- a/mysys/my_alloc.c
+++ b/mysys/my_alloc.c
@@ -166,7 +166,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
gptr point;
reg1 USED_MEM *next= 0;
reg2 USED_MEM **prev;
-
+ DBUG_ENTER("alloc_root");
+ DBUG_PRINT("enter",("root: 0x%lx", mem_root));
DBUG_ASSERT(alloc_root_inited(mem_root));
Size= ALIGN_SIZE(Size);
@@ -213,7 +214,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
mem_root->used= next;
mem_root->first_block_usage= 0;
}
- return(point);
+ DBUG_PRINT("exit",("ptr: 0x%lx", (ulong) point));
+ DBUG_RETURN(point);
#endif
}
@@ -245,6 +247,19 @@ static inline void mark_blocks_free(MEM_ROOT* root)
/*
Deallocate everything used by alloc_root or just move
used blocks to free list if called with MY_USED_TO_FREE
+
+ SYNOPSIS
+ free_root()
+ root Memory root
+ MyFlags Flags for what should be freed:
+
+ MY_MARK_BLOCKS_FREED Don't free blocks, just mark them free
+ MY_KEEP_PREALLOC If this is not set, then free also the
+ preallocated block
+
+ NOTES
+ One can call this function either with root block initialised with
+ init_alloc_root() or with a bzero()-ed block.
*/
void free_root(MEM_ROOT *root, myf MyFlags)
diff --git a/mysys/my_bit.c b/mysys/my_bit.c
index 55dd72f5f76..01c9b5ea68d 100644
--- a/mysys/my_bit.c
+++ b/mysys/my_bit.c
@@ -71,3 +71,8 @@ uint my_count_bits(ulonglong v)
#endif
}
+uint my_count_bits_ushort(ushort v)
+{
+ return nbits[v];
+}
+
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index f0d3339535d..c0eb6f15548 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -29,6 +29,9 @@
* bitmap_intersect() is an exception :)
(for for Bitmap::intersect(ulonglong map2buff))
+ If THREAD is defined all bitmap operations except bitmap_init/bitmap_free
+ are thread-safe.
+
TODO:
Make assembler THREAD safe versions of these using test-and-set instructions
*/
@@ -37,7 +40,7 @@
#include <my_bitmap.h>
#include <m_string.h>
-static inline void bitmap_lock(MY_BITMAP* map)
+static inline void bitmap_lock(MY_BITMAP *map)
{
#ifdef THREAD
if (map->mutex)
@@ -45,7 +48,7 @@ static inline void bitmap_lock(MY_BITMAP* map)
#endif
}
-static inline void bitmap_unlock(MY_BITMAP* map)
+static inline void bitmap_unlock(MY_BITMAP *map)
{
#ifdef THREAD
if (map->mutex)
@@ -327,3 +330,66 @@ void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
bitmap_unlock(map);
}
+
+/*
+ SYNOPSIS
+ bitmap_bits_set()
+ map
+ RETURN
+ Number of set bits in the bitmap.
+*/
+
+uint bitmap_bits_set(const MY_BITMAP *map)
+{
+ uchar *m= map->bitmap;
+ uchar *end= m + map->bitmap_size;
+ uint res= 0;
+
+ DBUG_ASSERT(map->bitmap);
+ bitmap_lock((MY_BITMAP *)map);
+ while (m < end)
+ {
+ res+= my_count_bits_ushort(*m++);
+ }
+ bitmap_unlock((MY_BITMAP *)map);
+ return res;
+}
+
+
+/*
+ SYNOPSIS
+ bitmap_get_first()
+ map
+ RETURN
+ Number of first unset bit in the bitmap or MY_BIT_NONE if all bits are set.
+*/
+
+uint bitmap_get_first(const MY_BITMAP *map)
+{
+ uchar *bitmap=map->bitmap;
+ uint bit_found = MY_BIT_NONE;
+ uint bitmap_size=map->bitmap_size*8;
+ uint i;
+
+ DBUG_ASSERT(map->bitmap);
+ bitmap_lock((MY_BITMAP *)map);
+ for (i=0; i < bitmap_size ; i++, bitmap++)
+ {
+ if (*bitmap != 0xff)
+ { /* Found slot with free bit */
+ uint b;
+ for (b=0; ; b++)
+ {
+ if (!(*bitmap & (1 << b)))
+ {
+ bit_found = (i*8)+b;
+ break;
+ }
+ }
+ break; /* Found bit */
+ }
+ }
+ bitmap_unlock((MY_BITMAP *)map);
+ return bit_found;
+}
+
diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c
index cf26428d65f..c258121226d 100644
--- a/mysys/my_chsize.c
+++ b/mysys/my_chsize.c
@@ -48,9 +48,9 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
DBUG_PRINT("info",("old_size: %ld", (ulong) oldsize));
if (oldsize > newlength)
+ {
#if defined(HAVE_SETFILEPOINTER)
/* This is for the moment only true on windows */
- {
long is_success;
HANDLE win_file= (HANDLE) _get_osfhandle(fd);
long length_low, length_high;
@@ -63,35 +63,29 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
DBUG_RETURN(0);
my_errno= GetLastError();
goto err;
- }
#elif defined(HAVE_FTRUNCATE)
- {
if (ftruncate(fd, (off_t) newlength))
{
my_errno= errno;
goto err;
}
DBUG_RETURN(0);
- }
#elif defined(HAVE_CHSIZE)
- {
if (chsize(fd, (off_t) newlength))
{
my_errno=errno;
goto err;
}
DBUG_RETURN(0);
- }
#else
- {
/*
Fill space between requested length and true length with 'filler'
We should never come here on any modern machine
*/
VOID(my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE)));
swap_variables(my_off_t, newlength, oldsize);
- }
#endif
+ }
/* Full file with 'filler' until it's as big as requested */
bfill(buff, IO_SIZE, filler);
diff --git a/mysys/my_error.c b/mysys/my_error.c
index 8a377f63c7e..0c18bbf6e8b 100644
--- a/mysys/my_error.c
+++ b/mysys/my_error.c
@@ -22,10 +22,40 @@
/* Define some external variables for error handling */
-const char ** NEAR my_errmsg[MAXMAPS]={0,0,0,0};
+/*
+ WARNING!
+ my_error family functions have to be used according following rules:
+ - if message have not parameters use my_message(ER_CODE, ER(ER_CODE), MYF(N))
+ - if message registered use my_error(ER_CODE, MYF(N), ...).
+ - With some special text of errror message use:
+ my_printf_error(ER_CODE, format, MYF(N), ...)
+*/
+
char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
/*
+ Message texts are registered into a linked list of 'my_err_head' structs.
+ Each struct contains (1.) an array of pointers to C character strings with
+ '\0' termination, (2.) the error number for the first message in the array
+ (array index 0) and (3.) the error number for the last message in the array
+ (array index (last - first)).
+ The array may contain gaps with NULL pointers and pointers to empty strings.
+ Both kinds of gaps will be translated to "Unknown error %d.", if my_error()
+ is called with a respective error number.
+ The list of header structs is sorted in increasing order of error numbers.
+ Negative error numbers are allowed. Overlap of error numbers is not allowed.
+ Not registered error numbers will be translated to "Unknown error %d.".
+*/
+static struct my_err_head
+{
+ struct my_err_head *meh_next; /* chain link */
+ const char **meh_errmsgs; /* error messages array */
+ int meh_first; /* error number matching array slot 0 */
+ int meh_last; /* error number matching last slot */
+} my_errmsgs_globerrs = {NULL, globerrs, EE_ERROR_FIRST, EE_ERROR_LAST};
+static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs;
+
+/*
Error message to user
SYNOPSIS
@@ -33,115 +63,42 @@ char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
nr Errno
MyFlags Flags
... variable list
- NOTE
- The following subset of printf format is supported:
- "%[0-9.-]*l?[sdu]", where all length flags are parsed but ignored.
- Additionally "%.*s" is supported and "%.*[ud]" is correctly parsed but
- the length value is ignored.
+ RETURN
+ What (*error_handler_hook)() returns:
+ 0 OK
*/
-int my_error(int nr,myf MyFlags, ...)
+int my_error(int nr, myf MyFlags, ...)
{
- va_list ap;
- uint olen, plen;
- reg1 const char *tpos;
- reg2 char *endpos;
- char * par;
- char ebuff[ERRMSGSIZE+20];
- int prec_chars; /* output precision */
- my_bool prec_supplied;
+ const char *format;
+ struct my_err_head *meh_p;
+ va_list args;
+ char ebuff[ERRMSGSIZE + 20];
DBUG_ENTER("my_error");
- LINT_INIT(prec_chars); /* protected by prec_supplied */
- va_start(ap,MyFlags);
DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno));
- if (nr / ERRMOD == GLOB && my_errmsg[GLOB] == 0)
- init_glob_errs();
+ /* Search for the error messages array, which could contain the message. */
+ for (meh_p= my_errmsgs_list; meh_p; meh_p= meh_p->meh_next)
+ if (nr <= meh_p->meh_last)
+ break;
- olen=(uint) strlen(tpos=my_errmsg[nr / ERRMOD][nr % ERRMOD]);
- endpos=ebuff;
+#ifdef SHARED_LIBRARY
+ if ((meh_p == &my_errmsgs_globerrs) && ! globerrs[0])
+ init_glob_errs();
+#endif
- while (*tpos)
+ /* get the error message string. Default, if NULL or empty string (""). */
+ if (! (format= (meh_p && (nr >= meh_p->meh_first)) ?
+ meh_p->meh_errmsgs[nr - meh_p->meh_first] : NULL) || ! *format)
+ (void) my_snprintf (ebuff, sizeof(ebuff), "Unknown error %d", nr);
+ else
{
- if (tpos[0] != '%')
- {
- *endpos++= *tpos++; /* Copy ordinary char */
- continue;
- }
- if (*++tpos == '%') /* test if %% */
- {
- olen--;
- }
- else
- {
- /*
- Skip size/precision flags to be compatible with printf.
- The only size/precision flag supported is "%.*s".
- If "%.*u" or "%.*d" are encountered, the precision number is read
- from the variable argument list but its value is ignored.
- */
- prec_supplied= 0;
- if (*tpos== '.')
- {
- tpos++;
- olen--;
- if (*tpos == '*')
- {
- tpos++;
- olen--;
- prec_chars= va_arg(ap, int); /* get length parameter */
- prec_supplied= 1;
- }
- }
-
- if (!prec_supplied)
- {
- while (my_isdigit(&my_charset_latin1, *tpos) || *tpos == '.' ||
- *tpos == '-')
- tpos++;
-
- if (*tpos == 'l') /* Skip 'l' argument */
- tpos++;
- }
-
- if (*tpos == 's') /* String parameter */
- {
- par= va_arg(ap, char *);
- plen= (uint) strlen(par);
- if (prec_supplied && prec_chars > 0)
- plen= min((uint)prec_chars, plen);
- if (olen + plen < ERRMSGSIZE+2) /* Replace if possible */
- {
- strmake(endpos, par, plen);
- endpos+= plen;
- tpos++;
- olen+= plen-2;
- continue;
- }
- }
- else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */
- {
- register int iarg;
- iarg= va_arg(ap, int);
- if (*tpos == 'd')
- plen= (uint) (int10_to_str((long) iarg, endpos, -10) - endpos);
- else
- plen= (uint) (int10_to_str((long) (uint) iarg, endpos, 10) - endpos);
- if (olen + plen < ERRMSGSIZE+2) /* Replace parameter if possible */
- {
- endpos+= plen;
- tpos++;
- olen+= plen-2;
- continue;
- }
- }
- }
- *endpos++= '%'; /* % used as % or unknown code */
+ va_start(args,MyFlags);
+ (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args);
+ va_end(args);
}
- *endpos= '\0'; /* End of errmessage */
- va_end(ap);
DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
}
@@ -160,11 +117,14 @@ int my_printf_error(uint error, const char *format, myf MyFlags, ...)
{
va_list args;
char ebuff[ERRMSGSIZE+20];
+ DBUG_ENTER("my_printf_error");
+ DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d Format: %s",
+ error, MyFlags, errno, format));
va_start(args,MyFlags);
- (void) vsprintf (ebuff,format,args);
+ (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args);
va_end(args);
- return (*error_handler_hook)(error, ebuff, MyFlags);
+ DBUG_RETURN((*error_handler_hook)(error, ebuff, MyFlags));
}
/*
@@ -181,3 +141,109 @@ int my_message(uint error, const char *str, register myf MyFlags)
{
return (*error_handler_hook)(error, str, MyFlags);
}
+
+
+/*
+ Register error messages for use with my_error().
+
+ SYNOPSIS
+ my_error_register()
+ errmsgs array of pointers to error messages
+ first error number of first message in the array
+ last error number of last message in the array
+
+ DESCRIPTION
+ The pointer array is expected to contain addresses to NUL-terminated
+ C character strings. The array contains (last - first + 1) pointers.
+ NULL pointers and empty strings ("") are allowed. These will be mapped to
+ "Unknown error" when my_error() is called with a matching error number.
+ This function registers the error numbers 'first' to 'last'.
+ No overlapping with previously registered error numbers is allowed.
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
+
+int my_error_register(const char **errmsgs, int first, int last)
+{
+ struct my_err_head *meh_p;
+ struct my_err_head **search_meh_pp;
+
+ /* Allocate a new header structure. */
+ if (! (meh_p= (struct my_err_head*) my_malloc(sizeof(struct my_err_head),
+ MYF(MY_WME))))
+ return 1;
+ meh_p->meh_errmsgs= errmsgs;
+ meh_p->meh_first= first;
+ meh_p->meh_last= last;
+
+ /* Search for the right position in the list. */
+ for (search_meh_pp= &my_errmsgs_list;
+ *search_meh_pp;
+ search_meh_pp= &(*search_meh_pp)->meh_next)
+ {
+ if ((*search_meh_pp)->meh_last > first)
+ break;
+ }
+
+ /* Error numbers must be unique. No overlapping is allowed. */
+ if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last))
+ return 1;
+
+ /* Insert header into the chain. */
+ meh_p->meh_next= *search_meh_pp;
+ *search_meh_pp= meh_p;
+ return 0;
+}
+
+
+/*
+ Unregister formerly registered error messages.
+
+ SYNOPSIS
+ my_error_unregister()
+ first error number of first message
+ last error number of last message
+
+ DESCRIPTION
+ This function unregisters the error numbers 'first' to 'last'.
+ These must have been previously registered by my_error_register().
+ 'first' and 'last' must exactly match the registration.
+ If a matching registration is present, the header is removed from the
+ list and the pointer to the error messages pointers array is returned.
+ Otherwise, NULL is returned.
+
+ RETURN
+ non-NULL OK, returns address of error messages pointers array.
+ NULL Error, no such number range registered.
+*/
+
+const char **my_error_unregister(int first, int last)
+{
+ struct my_err_head *meh_p;
+ struct my_err_head **search_meh_pp;
+ const char **errmsgs;
+
+ /* Search for the registration in the list. */
+ for (search_meh_pp= &my_errmsgs_list;
+ *search_meh_pp;
+ search_meh_pp= &(*search_meh_pp)->meh_next)
+ {
+ if (((*search_meh_pp)->meh_first == first) &&
+ ((*search_meh_pp)->meh_last == last))
+ break;
+ }
+ if (! *search_meh_pp)
+ return NULL;
+
+ /* Remove header from the chain. */
+ meh_p= *search_meh_pp;
+ *search_meh_pp= meh_p->meh_next;
+
+ /* Save the return value and free the header. */
+ errmsgs= meh_p->meh_errmsgs;
+ my_free((gptr) meh_p, MYF(0));
+
+ return errmsgs;
+}
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c
index 53e46932167..5e93ad56cb5 100644
--- a/mysys/my_getopt.c
+++ b/mysys/my_getopt.c
@@ -205,7 +205,8 @@ int handle_options(int *argc, char ***argv,
{
if (!getopt_compare_strings(special_opt_prefix[i], opt_str,
special_opt_prefix_lengths[i]) &&
- opt_str[special_opt_prefix_lengths[i]] == '-')
+ (opt_str[special_opt_prefix_lengths[i]] == '-' ||
+ opt_str[special_opt_prefix_lengths[i]] == '_'))
{
/*
We were called with a special prefix, we can reuse opt_found
diff --git a/mysys/my_handler.c b/mysys/my_handler.c
index 5ee181ca78e..87e526d0ea3 100644
--- a/mysys/my_handler.c
+++ b/mysys/my_handler.c
@@ -21,11 +21,11 @@ int mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
uchar *b, uint b_length, my_bool part_key,
my_bool skip_end_space)
{
- if (skip_end_space)
+ if (!part_key)
return charset_info->coll->strnncollsp(charset_info, a, a_length,
- b, b_length);
+ b, b_length, !skip_end_space);
return charset_info->coll->strnncoll(charset_info, a, a_length,
- b, b_length, part_key);
+ b, b_length, part_key);
}
@@ -178,6 +178,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
}
break;
case HA_KEYTYPE_BINARY:
+ case HA_KEYTYPE_BIT:
if (keyseg->flag & HA_SPACE_PACK)
{
int a_length,b_length,pack_length;
@@ -206,13 +207,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
b+=length;
}
break;
- case HA_KEYTYPE_VARTEXT:
+ case HA_KEYTYPE_VARTEXT1:
+ case HA_KEYTYPE_VARTEXT2:
{
- int a_length,full_a_length,b_length,full_b_length,pack_length;
+ int a_length,b_length,pack_length;
get_key_length(a_length,a);
get_key_pack_length(b_length,pack_length,b);
- full_a_length= a_length;
- full_b_length= b_length;
next_key_length=key_length-b_length-pack_length;
if (piks &&
@@ -221,14 +221,17 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
next_key_length <= 0),
(my_bool) ((nextflag & (SEARCH_FIND |
SEARCH_UPDATE)) ==
- SEARCH_FIND))))
+ SEARCH_FIND &&
+ ! (keyseg->flag &
+ HA_END_SPACE_ARE_EQUAL)))))
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
- a+= full_a_length;
- b+= full_b_length;
+ a+= a_length;
+ b+= b_length;
break;
}
break;
- case HA_KEYTYPE_VARBINARY:
+ case HA_KEYTYPE_VARBINARY1:
+ case HA_KEYTYPE_VARBINARY2:
{
int a_length,b_length,pack_length;
get_key_length(a_length,a);
diff --git a/mysys/my_largepage.c b/mysys/my_largepage.c
new file mode 100644
index 00000000000..0639c360b46
--- /dev/null
+++ b/mysys/my_largepage.c
@@ -0,0 +1,167 @@
+/* Copyright (C) 2004 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 "mysys_priv.h"
+
+#ifdef HAVE_LARGE_PAGES
+
+#ifdef HAVE_SYS_IPC_H
+#include <sys/ipc.h>
+#endif
+
+#ifdef HAVE_SYS_SHM_H
+#include <sys/shm.h>
+#endif
+
+static uint my_get_large_page_size_int(void);
+static gptr my_large_malloc_int(uint size, myf my_flags);
+static my_bool my_large_free_int(gptr ptr, myf my_flags);
+
+/* Gets the size of large pages from the OS */
+
+uint my_get_large_page_size(void)
+{
+ uint size;
+ DBUG_ENTER("my_get_large_page_size");
+
+ if (!(size = my_get_large_page_size_int()))
+ fprintf(stderr, "Warning: Failed to determine large page size\n");
+
+ DBUG_RETURN(size);
+}
+
+/*
+ General large pages allocator.
+ Tries to allocate memory from large pages pool and falls back to
+ my_malloc_lock() in case of failure
+*/
+
+gptr my_large_malloc(uint size, myf my_flags)
+{
+ gptr ptr;
+ DBUG_ENTER("my_large_malloc");
+
+ if (my_use_large_pages && my_large_page_size)
+ {
+ if ((ptr = my_large_malloc_int(size, my_flags)) != NULL)
+ DBUG_RETURN(ptr);
+ if (my_flags & MY_WME)
+ fprintf(stderr, "Warning: Using conventional memory pool\n");
+ }
+
+ DBUG_RETURN(my_malloc_lock(size, my_flags));
+}
+
+/*
+ General large pages deallocator.
+ Tries to deallocate memory as if it was from large pages pool and falls back
+ to my_free_lock() in case of failure
+ */
+
+void my_large_free(gptr ptr, myf my_flags __attribute__((unused)))
+{
+ DBUG_ENTER("my_large_free");
+
+ /*
+ my_large_free_int() can only fail if ptr was not allocated with
+ my_large_malloc_int(), i.e. my_malloc_lock() was used so we should free it
+ with my_free_lock()
+ */
+ if (!my_use_large_pages || !my_large_page_size ||
+ !my_large_free_int(ptr, my_flags))
+ my_free_lock(ptr, my_flags);
+
+ DBUG_VOID_RETURN;
+}
+
+#ifdef HUGETLB_USE_PROC_MEMINFO
+/* Linux-specific function to determine the size of large pages */
+
+uint my_get_large_page_size_int(void)
+{
+ FILE *f;
+ uint size = 0;
+ char buf[256];
+ DBUG_ENTER("my_get_large_page_size_int");
+
+ if (!(f = my_fopen("/proc/meminfo", O_RDONLY, MYF(MY_WME))))
+ goto finish;
+
+ while (fgets(buf, sizeof(buf), f))
+ if (sscanf(buf, "Hugepagesize: %u kB", &size))
+ break;
+
+ my_fclose(f, MYF(MY_WME));
+
+finish:
+ DBUG_RETURN(size * 1024);
+}
+#endif /* HUGETLB_USE_PROC_MEMINFO */
+
+#if HAVE_DECL_SHM_HUGETLB
+/* Linux-specific large pages allocator */
+
+gptr my_large_malloc_int(uint size, myf my_flags)
+{
+ int shmid;
+ gptr ptr;
+ struct shmid_ds buf;
+ DBUG_ENTER("my_large_malloc_int");
+
+ /* Align block size to my_large_page_size */
+ size = ((size - 1) & ~(my_large_page_size - 1)) + my_large_page_size;
+
+ shmid = shmget(IPC_PRIVATE, (size_t)size, SHM_HUGETLB | SHM_R | SHM_W);
+ if (shmid < 0)
+ {
+ if (my_flags & MY_WME)
+ fprintf(stderr,
+ "Warning: Failed to allocate %d bytes from HugeTLB memory."
+ " errno %d\n", size, errno);
+
+ DBUG_RETURN(NULL);
+ }
+
+ ptr = shmat(shmid, NULL, 0);
+ if (ptr == (void *)-1)
+ {
+ if (my_flags& MY_WME)
+ fprintf(stderr, "Warning: Failed to attach shared memory segment,"
+ " errno %d\n", errno);
+ shmctl(shmid, IPC_RMID, &buf);
+
+ DBUG_RETURN(NULL);
+ }
+
+ /*
+ Remove the shared memory segment so that it will be automatically freed
+ after memory is detached or process exits
+ */
+ shmctl(shmid, IPC_RMID, &buf);
+
+ DBUG_RETURN(ptr);
+}
+
+/* Linux-specific large pages deallocator */
+
+my_bool my_large_free_int(byte *ptr, myf my_flags __attribute__((unused)))
+{
+ DBUG_ENTER("my_large_free_int");
+ DBUG_RETURN(shmdt(ptr) == 0);
+}
+#endif /* HAVE_DECL_SHM_HUGETLB */
+
+#endif /* HAVE_LARGE_PAGES */
diff --git a/mysys/my_mmap.c b/mysys/my_mmap.c
new file mode 100644
index 00000000000..cd84630a761
--- /dev/null
+++ b/mysys/my_mmap.c
@@ -0,0 +1,91 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "mysys_priv.h"
+
+#ifdef HAVE_SYS_MMAN_H
+
+/*
+ system msync() only syncs mmap'ed area to fs cache.
+ fsync() is required to really sync to disc
+*/
+int my_msync(int fd, void *addr, size_t len, int flags)
+{
+ msync(addr, len, flags);
+ return my_sync(fd, MYF(0));
+}
+
+#elif defined(__WIN__)
+
+static SECURITY_ATTRIBUTES mmap_security_attributes=
+ {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
+
+int my_getpagesize(void)
+{
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return si.dwPageSize;
+}
+
+void *my_mmap(void *addr, size_t len, int prot,
+ int flags, int fd, my_off_t offset)
+{
+ DWORD flProtect=0;
+ HANDLE hFileMap;
+ LPVOID ptr;
+ HANDLE hFile= (HANDLE)_get_osfhandle(fd);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return MAP_FAILED;
+
+ flProtect|=SEC_COMMIT;
+
+ hFileMap=CreateFileMapping(hFile, &mmap_security_attributes,
+ PAGE_READWRITE, 0, len, NULL);
+ if (hFileMap == 0)
+ return MAP_FAILED;
+
+ ptr=MapViewOfFile(hFileMap,
+ flags & PROT_WRITE ? FILE_MAP_WRITE : FILE_MAP_READ,
+ (DWORD)(offset >> 32), (DWORD)offset, len);
+
+ /*
+ MSDN explicitly states that it's possible to close File Mapping Object
+ even when a view is not unmapped - then the object will be held open
+ implicitly until unmap, as every view stores internally a handler of
+ a corresponding File Mapping Object
+ */
+ CloseHandle(hFileMap);
+
+ if (ptr)
+ return ptr;
+
+ return MAP_FAILED;
+}
+
+int my_munmap(void *addr, size_t len)
+{
+ return UnmapViewOfFile(addr) ? 0 : -1;
+}
+
+int my_msync(int fd, void *addr, size_t len, int flags)
+{
+ return FlushViewOfFile(addr, len) ? 0 : -1;
+}
+
+#else
+#warning "no mmap!"
+#endif
+
diff --git a/mysys/my_open.c b/mysys/my_open.c
index ca5c0d8683f..a5cd3811bbf 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -69,7 +69,7 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
my_close()
fd File sescriptor
myf Special Flags
-
+
*/
int my_close(File fd, myf MyFlags)
@@ -79,7 +79,12 @@ int my_close(File fd, myf MyFlags)
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
pthread_mutex_lock(&THR_LOCK_open);
- if ((err = close(fd)))
+ do
+ {
+ err= close(fd);
+ } while (err == -1 && errno == EINTR);
+
+ if (err)
{
DBUG_PRINT("error",("Got error %d on close",err));
my_errno=errno;
diff --git a/mysys/my_static.c b/mysys/my_static.c
index 5f034555156..8207463ea50 100644
--- a/mysys/my_static.c
+++ b/mysys/my_static.c
@@ -25,6 +25,8 @@
#include "my_alarm.h"
#endif
+my_bool timed_mutexes= 0;
+
/* from my_init */
my_string home_dir=0,my_progname=0;
char NEAR curr_dir[FN_REFLEN]= {0},
@@ -61,6 +63,12 @@ const char *soundex_map= "01230120022455012623010202";
USED_MEM* my_once_root_block=0; /* pointer to first block */
uint my_once_extra=ONCE_ALLOC_INIT; /* Memory to alloc / block */
+ /* from my_largepage.c */
+#ifdef HAVE_LARGE_PAGES
+my_bool my_use_large_pages= 0;
+uint my_large_page_size= 0;
+#endif
+
/* from my_tempnam */
#if !defined(HAVE_TEMPNAM) || defined(HPUX11)
int _my_tempnam_used=0;
diff --git a/mysys/my_sync.c b/mysys/my_sync.c
index 317ca039346..c557324b52c 100644
--- a/mysys/my_sync.c
+++ b/mysys/my_sync.c
@@ -27,7 +27,14 @@
my_flags Flags (now only MY_WME is supported)
NOTE
- If file system supports its, only file data is synced, not inode date
+ If file system supports its, only file data is synced, not inode data.
+
+ MY_IGNORE_BADFD is useful when fd is "volatile" - not protected by a
+ mutex. In this case by the time of fsync(), fd may be already closed by
+ another thread, or even reassigned to a different file. With this flag -
+ MY_IGNORE_BADFD - such a situation will not be considered an error.
+ (which is correct behaviour, if we know that the other thread synced the
+ file before closing)
RETURN
0 ok
@@ -40,21 +47,30 @@ int my_sync(File fd, myf my_flags)
DBUG_ENTER("my_sync");
DBUG_PRINT("my",("Fd: %d my_flags: %d", fd, my_flags));
+ do
+ {
#if defined(HAVE_FDATASYNC)
- res= fdatasync(fd);
+ res= fdatasync(fd);
#elif defined(HAVE_FSYNC)
- res=fsync(fd);
+ res= fsync(fd);
#elif defined(__WIN__)
res= _commit(fd);
#else
- res= 0; /* No sync (strange OS) */
+ res= 0; /* No sync (strange OS) */
#endif
+ } while (res == -1 && errno == EINTR);
+
if (res)
{
- if (!(my_errno= errno))
- my_errno= -1; /* Unknown error */
- if (my_flags & MY_WME)
+ int er= errno;
+ if (!(my_errno= er))
+ my_errno= -1; /* Unknown error */
+ if ((my_flags & MY_IGNORE_BADFD) &&
+ (er == EBADF || er == EINVAL || er == EROFS))
+ res= 0;
+ else if (my_flags & MY_WME)
my_error(EE_SYNC, MYF(ME_BELL+ME_WAITTANG), my_filename(fd), my_errno);
}
DBUG_RETURN(res);
-} /* my_read */
+} /* my_sync */
+
diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c
index 5fc7ccab4fa..57778574bb6 100644
--- a/mysys/ptr_cmp.c
+++ b/mysys/ptr_cmp.c
@@ -21,6 +21,7 @@
*/
#include "mysys_priv.h"
+#include <myisampack.h>
static int ptr_compare(uint *compare_length, uchar **a, uchar **b);
static int ptr_compare_0(uint *compare_length, uchar **a, uchar **b);
@@ -152,3 +153,41 @@ static int ptr_compare_3(uint *compare_length,uchar **a, uchar **b)
}
return (0);
}
+
+void my_store_ptr(byte *buff, uint pack_length, my_off_t pos)
+{
+ switch (pack_length) {
+#if SIZEOF_OFF_T > 4
+ case 8: mi_int8store(buff,pos); break;
+ case 7: mi_int7store(buff,pos); break;
+ case 6: mi_int6store(buff,pos); break;
+ case 5: mi_int5store(buff,pos); break;
+#endif
+ case 4: mi_int4store(buff,pos); break;
+ case 3: mi_int3store(buff,pos); break;
+ case 2: mi_int2store(buff,pos); break;
+ case 1: buff[0]= (uchar) pos; break;
+ default: DBUG_ASSERT(0);
+ }
+ return;
+}
+
+my_off_t my_get_ptr(byte *ptr, uint pack_length)
+{
+ my_off_t pos;
+ switch (pack_length) {
+#if SIZEOF_OFF_T > 4
+ case 8: pos= (my_off_t) mi_uint8korr(ptr); break;
+ case 7: pos= (my_off_t) mi_uint7korr(ptr); break;
+ case 6: pos= (my_off_t) mi_uint6korr(ptr); break;
+ case 5: pos= (my_off_t) mi_uint5korr(ptr); break;
+#endif
+ case 4: pos= (my_off_t) mi_uint4korr(ptr); break;
+ case 3: pos= (my_off_t) mi_uint3korr(ptr); break;
+ case 2: pos= (my_off_t) mi_uint2korr(ptr); break;
+ case 1: pos= (my_off_t) mi_uint2korr(ptr); break;
+ default: DBUG_ASSERT(0);
+ }
+ return pos;
+}
+
diff --git a/mysys/raid.cc b/mysys/raid.cc
index 0b688464fb3..1d2e0cb01f0 100644
--- a/mysys/raid.cc
+++ b/mysys/raid.cc
@@ -185,7 +185,7 @@ extern "C" {
uint my_raid_write(File fd,const byte *Buffer, uint Count, myf MyFlags)
{
DBUG_ENTER("my_raid_write");
- DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
+ DBUG_PRINT("enter",("Fd: %d Buffer: 0x%lx Count: %u MyFlags: %d",
fd, Buffer, Count, MyFlags));
if (is_raid(fd))
{
@@ -198,7 +198,7 @@ extern "C" {
uint my_raid_read(File fd, byte *Buffer, uint Count, myf MyFlags)
{
DBUG_ENTER("my_raid_read");
- DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
+ DBUG_PRINT("enter",("Fd: %d Buffer: 0x%lx Count: %u MyFlags: %d",
fd, Buffer, Count, MyFlags));
if (is_raid(fd))
{
@@ -212,8 +212,9 @@ extern "C" {
myf MyFlags)
{
DBUG_ENTER("my_raid_pread");
- DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u offset: %u MyFlags: %d",
- Filedes, Buffer, Count, offset, MyFlags));
+ DBUG_PRINT("enter",
+ ("Fd: %d Buffer: 0x%lx Count: %u offset: %u MyFlags: %d",
+ Filedes, Buffer, Count, offset, MyFlags));
if (is_raid(Filedes))
{
assert(offset != MY_FILEPOS_ERROR);
@@ -231,8 +232,9 @@ extern "C" {
my_off_t offset, myf MyFlags)
{
DBUG_ENTER("my_raid_pwrite");
- DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u offset: %u MyFlags: %d",
- Filedes, Buffer, Count, offset, MyFlags));
+ DBUG_PRINT("enter",
+ ("Fd: %d Buffer: 0x %lx Count: %u offset: %u MyFlags: %d",
+ Filedes, Buffer, Count, offset, MyFlags));
if (is_raid(Filedes))
{
assert(offset != MY_FILEPOS_ERROR);
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index d47ca8de183..9ce058f90fc 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -523,8 +523,10 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type)
data->prev=lock->write_wait.last;
lock->write_wait.last= &data->next;
data->cond=get_cond();
- if (lock->get_status)
- (*lock->get_status)(data->status_param);
+ /*
+ We don't have to do get_status here as we will do it when we change
+ the delayed lock to a real write lock
+ */
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
diff --git a/ndb/Makefile.am b/ndb/Makefile.am
index 32c821383e6..3aac54b38ee 100644
--- a/ndb/Makefile.am
+++ b/ndb/Makefile.am
@@ -1,12 +1,13 @@
SUBDIRS = src tools . include @ndb_opt_subdirs@
DIST_SUBDIRS = src tools include test docs
-EXTRA_DIST = config
+EXTRA_DIST = config ndbapi-examples
include $(top_srcdir)/ndb/config/common.mk.am
dist-hook:
-rm -rf `find $(distdir) -type d -name SCCS`
-rm -rf `find $(distdir) -type d -name old_files`
+ -rm -rf `find $(distdir)/ndbapi-examples -name '*.o'`
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" != "." -a "$$subdir" != "include"; then \
files="`find $$subdir -name '*\.h'` `find $$subdir -name '*\.hpp'`"; \
diff --git a/ndb/docs/Makefile.am b/ndb/docs/Makefile.am
index 1399ce3b6a5..afa91857771 100644
--- a/ndb/docs/Makefile.am
+++ b/ndb/docs/Makefile.am
@@ -1,18 +1,19 @@
DOXYDIR = doxygen
noinst_HEADERS = $(DOXYDIR)/predoxy.pl $(DOXYDIR)/postdoxy.pl $(DOXYDIR)/Doxyfile.ndbapi $(DOXYDIR)/Doxyfile.mgmapi $(DOXYDIR)/header.ndbapi.tex $(DOXYDIR)/header.mgmapi.tex
-all: do-check ndbapidoc mgmapidoc
+all: do-check-html ndbapidoc-html mgmapidoc-html
+all-pdf: do-check-pdf ndbapidoc-pdf mgmapidoc-pdf
DOXYTMP = .doxytmp
DOXYOUT = .doxyout
NDB_RELEASE = @NDB_VERSION_MAJOR@.@NDB_VERSION_MINOR@.@NDB_VERSION_BUILD@-@NDB_VERSION_STATUS@
-clean:
+clean-local:
rm -rf ndbapi.pdf ndbapi.html mgmapi.pdf mgmapi.html
rm -rf $(DOXYTMP) $(DOXYOUT)
-do-check:
+do-check-html:
@set -x; \
if test @PERL@ = no ; then \
echo "Perl needed to make docs"; \
@@ -21,7 +22,9 @@ do-check:
if test @DOXYGEN@ = no ; then \
echo "Doxygen needed to make docs"; \
exit 1; \
- fi; \
+ fi;
+
+do-check-pdf: do-check-html
if test @PDFLATEX@ = no ; then \
echo "Pdflatex needed to make docs"; \
exit 1; \
@@ -30,26 +33,30 @@ do-check:
echo "Makeindex needed to make docs"; \
exit 1; \
fi;
+
###
#
# NDB API Programmer's Guide
#
-ndbapidoc: ndbapi.pdf
+ndbapidoc-html: ndbapi.html
+ndbapidoc-pdf: ndbapi.pdf
-ndbapi.pdf: $(noinst_HEADERS)
+ndbapi.html: $(noinst_HEADERS)
@set -x; \
export NDB_RELEASE=$(NDB_RELEASE); \
@RM@ -f ndbapi.pdf ndbapi.html; \
@RM@ -rf $(DOXYTMP) $(DOXYOUT); \
mkdir -p $(DOXYTMP) $(DOXYOUT); \
@CP@ $(top_srcdir)/ndb/include/ndbapi/* $(DOXYTMP); \
- @CP@ $(top_srcdir)/ndb/examples/*/*.[ch]pp $(DOXYTMP); \
+ @CP@ $(top_srcdir)/ndb/ndbapi-examples/*/*.[ch]pp $(DOXYTMP); \
@PERL@ $(DOXYDIR)/predoxy.pl; \
mv footer.html $(DOXYTMP); \
(cd $(DOXYTMP) ; @DOXYGEN@ ../$(DOXYDIR)/Doxyfile.ndbapi); \
- @PERL@ $(DOXYDIR)/postdoxy.pl $(DOXYOUT)/ndbapi.latex "NDB API Programmer Guide"; \
+ @PERL@ $(DOXYDIR)/postdoxy.pl $(DOXYOUT)/ndbapi.latex "MySQL Cluster NDB API Programmer Guide"; \
(cd $(DOXYOUT) && \
- find ndbapi.html -print | cpio -pdm ..); \
+ find ndbapi.html -print | cpio -pdm ..);
+
+ndbapi.pdf: ndbapi.html
(cd $(DOXYOUT)/ndbapi.latex && \
@PDFLATEX@ refman.tex && @MAKEINDEX@ refman && @PDFLATEX@ refman.tex && \
cp -p refman.pdf ../../ndbapi.pdf);
@@ -58,9 +65,10 @@ ndbapi.pdf: $(noinst_HEADERS)
#
# MGM API Guide
#
-mgmapidoc: mgmapi.pdf
+mgmapidoc-html: mgmapi.html
+mgmapidoc-pdf: mgmapi.pdf
-mgmapi.pdf: $(noinst_HEADERS)
+mgmapi.html: $(noinst_HEADERS)
@set -x; \
export NDB_RELEASE=$(NDB_RELEASE); \
@RM@ -f mgmapi.pdf mgmapi.html; \
@@ -70,9 +78,11 @@ mgmapi.pdf: $(noinst_HEADERS)
@PERL@ $(DOXYDIR)/predoxy.pl; \
mv footer.html $(DOXYTMP); \
(cd $(DOXYTMP) ; @DOXYGEN@ ../$(DOXYDIR)/Doxyfile.mgmapi); \
- @PERL@ $(DOXYDIR)/postdoxy.pl $(DOXYOUT)/mgmapi.latex "NDB Cluster MGM API Guide"; \
+ @PERL@ $(DOXYDIR)/postdoxy.pl $(DOXYOUT)/mgmapi.latex "MySQL Cluster MGM API Guide"; \
(cd $(DOXYOUT) && \
- find mgmapi.html -print | cpio -pdm ..); \
+ find mgmapi.html -print | cpio -pdm ..);
+
+mgmapi.pdf: mgmapi.html
(cd $(DOXYOUT)/mgmapi.latex && \
@PDFLATEX@ refman.tex && @MAKEINDEX@ refman && @PDFLATEX@ refman.tex && \
cp -p refman.pdf ../../mgmapi.pdf);
diff --git a/ndb/docs/doxygen/Doxyfile.mgmapi b/ndb/docs/doxygen/Doxyfile.mgmapi
index 4287b37fd97..1e743dcb60e 100644
--- a/ndb/docs/doxygen/Doxyfile.mgmapi
+++ b/ndb/docs/doxygen/Doxyfile.mgmapi
@@ -59,7 +59,7 @@ EXTRACT_PRIVATE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
-EXTRACT_STATIC = NO
+EXTRACT_STATIC = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
@@ -146,7 +146,7 @@ HIDE_SCOPE_NAMES = NO
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
-VERBATIM_HEADERS = YES
+VERBATIM_HEADERS = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
@@ -190,7 +190,7 @@ DISTRIBUTE_GROUP_DOC = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
-TAB_SIZE = 8
+TAB_SIZE = 2
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
@@ -245,7 +245,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
-SHOW_USED_FILES = YES
+SHOW_USED_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@@ -447,7 +447,7 @@ HTML_STYLESHEET =
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
-HTML_ALIGN_MEMBERS = YES
+HTML_ALIGN_MEMBERS = NO
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
@@ -477,7 +477,7 @@ TOC_EXPAND = NO
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
-DISABLE_INDEX = NO
+DISABLE_INDEX = YES
# This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation.
@@ -688,7 +688,8 @@ INCLUDE_FILE_PATTERNS =
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed.
-PREDEFINED = DOXYGEN_SHOULD_SKIP_DEPRECATED \
+PREDEFINED = DOXYGEN_FIX \
+ DOXYGEN_SHOULD_SKIP_DEPRECATED \
DOXYGEN_SHOULD_SKIP_INTERNAL \
protected=private
diff --git a/ndb/docs/doxygen/Doxyfile.ndb b/ndb/docs/doxygen/Doxyfile.ndb
index d43a66323f8..3986a7cd17f 100644
--- a/ndb/docs/doxygen/Doxyfile.ndb
+++ b/ndb/docs/doxygen/Doxyfile.ndb
@@ -14,6 +14,8 @@
# General configuration options
#---------------------------------------------------------------------------
+DETAILS_AT_TOP = YES
+
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
@@ -52,7 +54,7 @@ EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
-EXTRACT_PRIVATE = YES
+EXTRACT_PRIVATE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
@@ -105,7 +107,7 @@ ALWAYS_DETAILED_SEC = NO
# ordinary class members. Constructors, destructors and assignment operators of
# the base classes will not be shown.
-INLINE_INHERITED_MEMB = NO
+INLINE_INHERITED_MEMB = YES
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
@@ -157,13 +159,13 @@ HIDE_SCOPE_NAMES = NO
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
-VERBATIM_HEADERS = YES
+VERBATIM_HEADERS = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
# of that file.
-SHOW_INCLUDE_FILES = YES
+SHOW_INCLUDE_FILES = NO
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style
@@ -201,7 +203,7 @@ DISTRIBUTE_GROUP_DOC = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
-TAB_SIZE = 8
+TAB_SIZE = 2
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
@@ -256,7 +258,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
-SHOW_USED_FILES = YES
+SHOW_USED_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@@ -485,7 +487,7 @@ HTML_STYLESHEET =
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
-HTML_ALIGN_MEMBERS = YES
+HTML_ALIGN_MEMBERS = NO
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
@@ -515,7 +517,7 @@ TOC_EXPAND = NO
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
-DISABLE_INDEX = NO
+DISABLE_INDEX = YES
# This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation.
@@ -794,21 +796,21 @@ PERL_PATH = /usr/bin/perl
# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
# recommended to install and use dot, since it yield more powerful graphs.
-CLASS_DIAGRAMS = YES
+CLASS_DIAGRAMS = NO
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
-HAVE_DOT = YES
+HAVE_DOT = NO
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the
# the CLASS_DIAGRAMS tag to NO.
-CLASS_GRAPH = YES
+CLASS_GRAPH = NO
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
@@ -820,7 +822,7 @@ COLLABORATION_GRAPH = YES
# If set to YES, the inheritance and collaboration graphs will show the
# relations between templates and their instances.
-TEMPLATE_RELATIONS = YES
+TEMPLATE_RELATIONS = NO
# If set to YES, the inheritance and collaboration graphs will hide
# inheritance and usage relations if the target is undocumented
diff --git a/ndb/docs/doxygen/Doxyfile.ndbapi b/ndb/docs/doxygen/Doxyfile.ndbapi
index 61d58d4fea3..da610148468 100644
--- a/ndb/docs/doxygen/Doxyfile.ndbapi
+++ b/ndb/docs/doxygen/Doxyfile.ndbapi
@@ -13,8 +13,8 @@
#---------------------------------------------------------------------------
# General configuration options
#---------------------------------------------------------------------------
-DETAILS_AT_TOP = yes
-HIDE_FRIEND_COMPOUNDS = yes
+DETAILS_AT_TOP = YES
+HIDE_FRIEND_COMPOUNDS = YES
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
@@ -59,7 +59,7 @@ EXTRACT_PRIVATE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
-EXTRACT_STATIC = NO
+EXTRACT_STATIC = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
@@ -146,7 +146,7 @@ HIDE_SCOPE_NAMES = NO
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
-VERBATIM_HEADERS = YES
+VERBATIM_HEADERS = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
@@ -190,7 +190,7 @@ DISTRIBUTE_GROUP_DOC = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
-TAB_SIZE = 8
+TAB_SIZE = 2
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
@@ -245,7 +245,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
-SHOW_USED_FILES = YES
+SHOW_USED_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@@ -447,7 +447,7 @@ HTML_STYLESHEET =
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
-HTML_ALIGN_MEMBERS = YES
+HTML_ALIGN_MEMBERS = NO
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
@@ -477,7 +477,7 @@ TOC_EXPAND = NO
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
-DISABLE_INDEX = NO
+DISABLE_INDEX = YES
# This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation.
diff --git a/ndb/docs/doxygen/Doxyfile.odbc b/ndb/docs/doxygen/Doxyfile.odbc
index 93e052d5b9d..262513852b7 100644
--- a/ndb/docs/doxygen/Doxyfile.odbc
+++ b/ndb/docs/doxygen/Doxyfile.odbc
@@ -14,6 +14,8 @@
# General configuration options
#---------------------------------------------------------------------------
+DETAILS_AT_TOP = YES
+
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
@@ -52,7 +54,7 @@ EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
-EXTRACT_PRIVATE = YES
+EXTRACT_PRIVATE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
@@ -157,7 +159,7 @@ HIDE_SCOPE_NAMES = NO
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
-VERBATIM_HEADERS = YES
+VERBATIM_HEADERS = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
@@ -201,7 +203,7 @@ DISTRIBUTE_GROUP_DOC = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
-TAB_SIZE = 8
+TAB_SIZE = 2
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
@@ -256,7 +258,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
-SHOW_USED_FILES = YES
+SHOW_USED_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@@ -469,7 +471,7 @@ HTML_STYLESHEET =
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
-HTML_ALIGN_MEMBERS = YES
+HTML_ALIGN_MEMBERS = NO
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
@@ -499,7 +501,7 @@ TOC_EXPAND = NO
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
-DISABLE_INDEX = NO
+DISABLE_INDEX = YES
# This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation.
diff --git a/ndb/docs/doxygen/Doxyfile.test b/ndb/docs/doxygen/Doxyfile.test
index 34ee21873ff..801c82cf380 100644
--- a/ndb/docs/doxygen/Doxyfile.test
+++ b/ndb/docs/doxygen/Doxyfile.test
@@ -14,6 +14,8 @@
# General configuration options
#---------------------------------------------------------------------------
+DETAILS_AT_TOP = YES
+
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
@@ -52,7 +54,7 @@ EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
-EXTRACT_PRIVATE = YES
+EXTRACT_PRIVATE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
@@ -157,7 +159,7 @@ HIDE_SCOPE_NAMES = NO
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
-VERBATIM_HEADERS = YES
+VERBATIM_HEADERS = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
@@ -201,7 +203,7 @@ DISTRIBUTE_GROUP_DOC = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
-TAB_SIZE = 8
+TAB_SIZE = 2
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
@@ -256,7 +258,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
-SHOW_USED_FILES = YES
+SHOW_USED_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@@ -469,7 +471,7 @@ HTML_STYLESHEET =
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
-HTML_ALIGN_MEMBERS = YES
+HTML_ALIGN_MEMBERS = NO
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
@@ -499,7 +501,7 @@ TOC_EXPAND = NO
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
-DISABLE_INDEX = NO
+DISABLE_INDEX = YES
# This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation.
diff --git a/ndb/docs/doxygen/predoxy.pl b/ndb/docs/doxygen/predoxy.pl
index 8dad1d964d0..3994054dcf6 100755
--- a/ndb/docs/doxygen/predoxy.pl
+++ b/ndb/docs/doxygen/predoxy.pl
@@ -18,7 +18,7 @@ print OUTFILE<<EOT;
<center>
EOT
print OUTFILE "Documentation generated " . localtime() .
- " from NDB Cluster source files.";
+ " from mysql source files.";
print OUTFILE<<EOT;
<br>
&copy; 2003-2004
diff --git a/ndb/examples/configurations/demos.tar b/ndb/examples/configurations/demos.tar
deleted file mode 100644
index d8cae90ec5b..00000000000
--- a/ndb/examples/configurations/demos.tar
+++ /dev/null
Binary files differ
diff --git a/ndb/examples/ndbapi_async_example/Makefile b/ndb/examples/ndbapi_async_example/Makefile
deleted file mode 100644
index f30398f9587..00000000000
--- a/ndb/examples/ndbapi_async_example/Makefile
+++ /dev/null
@@ -1,34 +0,0 @@
--include .defs.mk
-#NDB_OS = OS_YOU_ARE_RUNNING_ON
-#NDB_OS = LINUX
-#You need to set the NDB_OS variable here (LINUX, SOLARIS, MACOSX)
-TARGET = ndbapi_async
-SRCS = ndbapi_async.cpp
-OBJS = ndbapi_async.o
-CC = g++
-CFLAGS = -c -Wall -fno-rtti -D$(NDB_OS)
-DEBUG =
-LFLAGS = -Wall
-INCLUDE_DIR = ../../include
-LIB_DIR = ../../lib
-ifeq ($(NDB_OS), SOLARIS)
-# Here is the definition of system libraries necessary for Solaris 7
-SYS_LIB = -lpthread -lsocket -lnsl -lrt
-endif
-ifeq ($(NDB_OS), LINUX)
-# Here is the definition of system libraries necessary for Linux 2.4
-SYS_LIB = -lpthread
-endif
-ifeq ($(NDB_OS), MACOSX)
-# Here is the definition of system libraries necessary for Mac OS X
-SYS_LIB =
-endif
-
-$(TARGET): $(OBJS)
- $(CC) $(LFLAGS) -L$(LIB_DIR) -lNDB_API $(OBJS) $(SYS_LIB) -o $(TARGET)
-
-$(TARGET).o: $(SRCS)
- $(CC) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
-
-clean:
- rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_example1/Makefile b/ndb/examples/ndbapi_example1/Makefile
deleted file mode 100644
index eb0142ce673..00000000000
--- a/ndb/examples/ndbapi_example1/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
--include .defs.mk
-#NDB_OS = OS_YOU_ARE_RUNNING_ON
-#You need to set the NDB_OS variable here
-TARGET = ndbapi_example1
-SRCS = ndbapi_example1.cpp
-OBJS = ndbapi_example1.o
-CXX = g++
-CFLAGS = -c -Wall -fno-rtti -fno-exceptions
-DEBUG =
-LFLAGS = -Wall
-INCLUDE_DIR = ../../include
-LIB_DIR = ../../lib
-ifeq ($(NDB_OS), SOLARIS)
-# Here is the definition of system libraries necessary for Solaris 7
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), LINUX)
-# Here is the definition of system libraries necessary for Linux 2.4
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), MACOSX)
-# Here is the definition of system libraries necessary for Mac OS X
-SYS_LIB =
-endif
-
-$(TARGET): $(OBJS)
- $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(SYS_LIB) -o $(TARGET)
-
-$(TARGET).o: $(SRCS)
- $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
-
-clean:
- rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_example1/ndbapi_example1.cpp b/ndb/examples/ndbapi_example1/ndbapi_example1.cpp
deleted file mode 100644
index 03a84aa249b..00000000000
--- a/ndb/examples/ndbapi_example1/ndbapi_example1.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-//
-// ndbapi_example1.cpp: Using synchronous transactions in NDB API
-//
-// Correct output from this program is:
-//
-// ATTR1 ATTR2
-// 0 10
-// 1 1
-// 2 12
-// Detected that deleted tuple doesn't exist!
-// 4 14
-// 5 5
-// 6 16
-// 7 7
-// 8 18
-// 9 9
-
-#include <NdbApi.hpp>
-
-// Used for cout
-#include <stdio.h>
-#include <iostream>
-
-#define APIERROR(error) \
- { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
- << error.code << ", msg: " << error.message << "." << std::endl; \
- exit(-1); }
-
-int main()
-{
- ndb_init();
- Ndb* myNdb = new Ndb( "TEST_DB_1" ); // Object representing the database
- NdbDictionary::Table myTable;
- NdbDictionary::Column myColumn;
-
- NdbConnection *myConnection; // For other transactions
- NdbOperation *myOperation; // For other operations
- NdbRecAttr *myRecAttr; // Result of reading attribute value
-
- /********************************************
- * Initialize NDB and wait until it's ready *
- ********************************************/
- if (myNdb->init() == -1) {
- APIERROR(myNdb->getNdbError());
- exit(-1);
- }
-
- if (myNdb->waitUntilReady(30) != 0) {
- std::cout << "NDB was not ready within 30 secs." << std::endl;
- exit(-1);
- }
-
- NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
-
- /*********************************************************
- * Create a table named MYTABLENAME if it does not exist *
- *********************************************************/
- if (myDict->getTable("MYTABLENAME") != NULL) {
- std::cout << "NDB already has example table: MYTABLENAME." << std::endl;
- exit(-1);
- }
-
- myTable.setName("MYTABLENAME");
-
- myColumn.setName("ATTR1");
- myColumn.setType(NdbDictionary::Column::Unsigned);
- myColumn.setLength(1);
- myColumn.setPrimaryKey(true);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
- myColumn.setName("ATTR2");
- myColumn.setType(NdbDictionary::Column::Unsigned);
- myColumn.setLength(1);
- myColumn.setPrimaryKey(false);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
- if (myDict->createTable(myTable) == -1)
- APIERROR(myDict->getNdbError());
-
- /**************************************************************************
- * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
- **************************************************************************/
- for (int i = 0; i < 5; i++) {
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myOperation = myConnection->getNdbOperation("MYTABLENAME");
- if (myOperation == NULL) APIERROR(myConnection->getNdbError());
-
- myOperation->insertTuple();
- myOperation->equal("ATTR1", i);
- myOperation->setValue("ATTR2", i);
-
- myOperation = myConnection->getNdbOperation("MYTABLENAME");
- if (myOperation == NULL) APIERROR(myConnection->getNdbError());
-
- myOperation->insertTuple();
- myOperation->equal("ATTR1", i+5);
- myOperation->setValue("ATTR2", i+5);
-
- if (myConnection->execute( Commit ) == -1)
- APIERROR(myConnection->getNdbError());
-
- myNdb->closeTransaction(myConnection);
- }
-
- /*****************************************************************
- * Update the second attribute in half of the tuples (adding 10) *
- *****************************************************************/
- for (int i = 0; i < 10; i+=2) {
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myOperation = myConnection->getNdbOperation("MYTABLENAME");
- if (myOperation == NULL) APIERROR(myConnection->getNdbError());
-
- myOperation->updateTuple();
- myOperation->equal( "ATTR1", i );
- myOperation->setValue( "ATTR2", i+10);
-
- if( myConnection->execute( Commit ) == -1 )
- APIERROR(myConnection->getNdbError());
-
- myNdb->closeTransaction(myConnection);
- }
-
- /*************************************************
- * Delete one tuple (the one with primary key 3) *
- *************************************************/
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myOperation = myConnection->getNdbOperation("MYTABLENAME");
- if (myOperation == NULL)
- APIERROR(myConnection->getNdbError());
-
- myOperation->deleteTuple();
- myOperation->equal( "ATTR1", 3 );
-
- if (myConnection->execute(Commit) == -1)
- APIERROR(myConnection->getNdbError());
-
- myNdb->closeTransaction(myConnection);
-
- /*****************************
- * Read and print all tuples *
- *****************************/
- std::cout << "ATTR1 ATTR2" << std::endl;
-
- for (int i = 0; i < 10; i++) {
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myOperation = myConnection->getNdbOperation("MYTABLENAME");
- if (myOperation == NULL) APIERROR(myConnection->getNdbError());
-
- myOperation->readTuple();
- myOperation->equal("ATTR1", i);
-
- myRecAttr = myOperation->getValue("ATTR2", NULL);
- if (myRecAttr == NULL) APIERROR(myConnection->getNdbError());
-
- if(myConnection->execute( Commit ) == -1)
- if (i == 3) {
- std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
- } else {
- APIERROR(myConnection->getNdbError());
- }
-
- if (i != 3) {
- printf(" %2d %2d\n", i, myRecAttr->u_32_value());
- }
- myNdb->closeTransaction(myConnection);
- }
- delete myNdb;
-}
diff --git a/ndb/examples/ndbapi_example2/Makefile b/ndb/examples/ndbapi_example2/Makefile
deleted file mode 100644
index 17b2b1528fc..00000000000
--- a/ndb/examples/ndbapi_example2/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
--include .defs.mk
-#NDB_OS = OS_YOU_ARE_RUNNING_ON
-#You need to set the NDB_OS variable here
-TARGET = ndbapi_example2
-SRCS = ndbapi_example2.cpp
-OBJS = ndbapi_example2.o
-CXX = g++
-CFLAGS = -c -Wall -fno-rtti -fno-exceptions
-DEBUG =
-LFLAGS = -Wall
-INCLUDE_DIR = ../../include
-LIB_DIR = ../../lib
-ifeq ($(NDB_OS), SOLARIS)
-# Here is the definition of system libraries necessary for Solaris 7
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), LINUX)
-# Here is the definition of system libraries necessary for Linux 2.4
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), MACOSX)
-# Here is the definition of system libraries necessary for Mac OS X
-SYS_LIB =
-endif
-
-$(TARGET): $(OBJS)
- $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(SYS_LIB) -o $(TARGET)
-
-$(TARGET).o: $(SRCS)
- $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
-
-clean:
- rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_example3/Makefile b/ndb/examples/ndbapi_example3/Makefile
deleted file mode 100644
index bd6f0182aa4..00000000000
--- a/ndb/examples/ndbapi_example3/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
--include .defs.mk
-#NDB_OS = OS_YOU_ARE_RUNNING_ON
-#You need to set the NDB_OS variable here
-TARGET = ndbapi_example3
-SRCS = ndbapi_example3.cpp
-OBJS = ndbapi_example3.o
-CXX = g++
-CFLAGS = -c -Wall -fno-rtti -fno-exceptions
-DEBUG =
-LFLAGS = -Wall
-INCLUDE_DIR = ../../include
-LIB_DIR = ../../lib
-ifeq ($(NDB_OS), SOLARIS)
-# Here is the definition of system libraries necessary for Solaris 7
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), LINUX)
-# Here is the definition of system libraries necessary for Linux 2.4
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), MACOSX)
-# Here is the definition of system libraries necessary for Mac OS X
-SYS_LIB =
-endif
-
-$(TARGET): $(OBJS)
- $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(SYS_LIB) -o $(TARGET)
-
-$(TARGET).o: $(SRCS)
- $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
-
-clean:
- rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_example4/Makefile b/ndb/examples/ndbapi_example4/Makefile
deleted file mode 100644
index b0ce852d347..00000000000
--- a/ndb/examples/ndbapi_example4/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
--include .defs.mk
-#NDB_OS = OS_YOU_ARE_RUNNING_ON
-#You need to set the NDB_OS variable here
-TARGET = ndbapi_example4
-SRCS = ndbapi_example4.cpp
-OBJS = ndbapi_example4.o
-CXX = g++
-CFLAGS = -c -Wall -fno-rtti -fno-exceptions
-DEBUG =
-LFLAGS = -Wall
-INCLUDE_DIR = ../../include
-LIB_DIR = ../../lib
-ifeq ($(NDB_OS), SOLARIS)
-# Here is the definition of system libraries necessary for Solaris 7
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), LINUX)
-# Here is the definition of system libraries necessary for Linux 2.4
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), MACOSX)
-# Here is the definition of system libraries necessary for Mac OS X
-SYS_LIB =
-endif
-
-$(TARGET): $(OBJS)
- $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(SYS_LIB) -o $(TARGET)
-
-$(TARGET).o: $(SRCS)
- $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
-
-clean:
- rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_example4/ndbapi_example4.cpp b/ndb/examples/ndbapi_example4/ndbapi_example4.cpp
deleted file mode 100644
index fcb770d49e9..00000000000
--- a/ndb/examples/ndbapi_example4/ndbapi_example4.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-//
-// ndbapi_example4.cpp: Using secondary indexes in NDB API
-//
-// Correct output from this program is:
-//
-// ATTR1 ATTR2
-// 0 10
-// 1 1
-// 2 12
-// Detected that deleted tuple doesn't exist!
-// 4 14
-// 5 5
-// 6 16
-// 7 7
-// 8 18
-// 9 9
-
-#include <NdbApi.hpp>
-
-// Used for cout
-#include <stdio.h>
-#include <iostream>
-
-#define APIERROR(error) \
- { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
- << error.code << ", msg: " << error.message << "." << std::endl; \
- exit(-1); }
-
-int main()
-{
- ndb_init();
- Ndb* myNdb = new Ndb( "TEST_DB_1" ); // Object representing the database
- NdbDictionary::Table myTable;
- NdbDictionary::Column myColumn;
- NdbDictionary::Index myIndex;
-
- NdbConnection *myConnection; // For transactions
- NdbOperation *myOperation; // For primary key operations
- NdbIndexOperation *myIndexOperation; // For index operations
- NdbRecAttr *myRecAttr; // Result of reading attribute value
-
- /********************************************
- * Initialize NDB and wait until it's ready *
- ********************************************/
- if (myNdb->init() == -1) {
- APIERROR(myNdb->getNdbError());
- exit(-1);
- }
-
- if (myNdb->waitUntilReady(30) != 0) {
- std::cout << "NDB was not ready within 30 secs." << std::endl;
- exit(-1);
- }
-
- /*********************************************************
- * Create a table named MYTABLENAME if it does not exist *
- *********************************************************/
- NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
- if (myDict->getTable("MYTABLENAME") != NULL) {
- std::cout << "NDB already has example table: MYTABLENAME." << std::endl;
- exit(-1);
- }
-
- myTable.setName("MYTABLENAME");
-
- myColumn.setName("ATTR1");
- myColumn.setType(NdbDictionary::Column::Unsigned);
- myColumn.setLength(1);
- myColumn.setPrimaryKey(true);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
- myColumn.setName("ATTR2");
- myColumn.setType(NdbDictionary::Column::Unsigned);
- myColumn.setLength(1);
- myColumn.setPrimaryKey(false);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
- if (myDict->createTable(myTable) == -1)
- APIERROR(myDict->getNdbError());
-
-
- /**********************************************************
- * Create an index named MYINDEXNAME if it does not exist *
- **********************************************************/
- if (myDict->getIndex("MYINDEXNAME", "MYTABLENAME") != NULL) {
- std::cout << "NDB already has example index: MYINDEXNAME." << std::endl;
- exit(-1);
- }
-
- myIndex.setName("MYINDEXNAME");
- myIndex.setTable("MYTABLENAME");
- myIndex.setType(NdbDictionary::Index::UniqueHashIndex);
- const char* attr_arr[] = {"ATTR2"};
- myIndex.addIndexColumns(1, attr_arr);
-
- if (myDict->createIndex(myIndex) == -1)
- APIERROR(myDict->getNdbError());
-
-
- /**************************************************************************
- * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
- **************************************************************************/
- for (int i = 0; i < 5; i++) {
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myOperation = myConnection->getNdbOperation("MYTABLENAME");
- if (myOperation == NULL) APIERROR(myConnection->getNdbError());
-
- myOperation->insertTuple();
- myOperation->equal("ATTR1", i);
- myOperation->setValue("ATTR2", i);
-
- myOperation = myConnection->getNdbOperation("MYTABLENAME");
- if (myOperation == NULL) APIERROR(myConnection->getNdbError());
-
- myOperation->insertTuple();
- myOperation->equal("ATTR1", i+5);
- myOperation->setValue("ATTR2", i+5);
-
- if (myConnection->execute( Commit ) == -1)
- APIERROR(myConnection->getNdbError());
-
- myNdb->closeTransaction(myConnection);
- }
-
- /*****************************************
- * Read and print all tuples using index *
- *****************************************/
- std::cout << "ATTR1 ATTR2" << std::endl;
-
- for (int i = 0; i < 10; i++) {
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myIndexOperation = myConnection->getNdbIndexOperation("MYINDEXNAME",
- "MYTABLENAME");
- if (myIndexOperation == NULL) APIERROR(myConnection->getNdbError());
-
- myIndexOperation->readTuple();
- myIndexOperation->equal("ATTR2", i);
-
- myRecAttr = myIndexOperation->getValue("ATTR1", NULL);
- if (myRecAttr == NULL) APIERROR(myConnection->getNdbError());
-
- if(myConnection->execute( Commit ) != -1)
- printf(" %2d %2d\n", myRecAttr->u_32_value(), i);
- }
- myNdb->closeTransaction(myConnection);
-
- /*****************************************************************
- * Update the second attribute in half of the tuples (adding 10) *
- *****************************************************************/
- for (int i = 0; i < 10; i+=2) {
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myIndexOperation = myConnection->getNdbIndexOperation("MYINDEXNAME",
- "MYTABLENAME");
- if (myIndexOperation == NULL) APIERROR(myConnection->getNdbError());
-
- myIndexOperation->updateTuple();
- myIndexOperation->equal( "ATTR2", i );
- myIndexOperation->setValue( "ATTR2", i+10);
-
- if( myConnection->execute( Commit ) == -1 )
- APIERROR(myConnection->getNdbError());
-
- myNdb->closeTransaction(myConnection);
- }
-
- /*************************************************
- * Delete one tuple (the one with primary key 3) *
- *************************************************/
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myIndexOperation = myConnection->getNdbIndexOperation("MYINDEXNAME",
- "MYTABLENAME");
- if (myIndexOperation == NULL)
- APIERROR(myConnection->getNdbError());
-
- myIndexOperation->deleteTuple();
- myIndexOperation->equal( "ATTR2", 3 );
-
- if (myConnection->execute(Commit) == -1)
- APIERROR(myConnection->getNdbError());
-
- myNdb->closeTransaction(myConnection);
-
- /*****************************
- * Read and print all tuples *
- *****************************/
- std::cout << "ATTR1 ATTR2" << std::endl;
-
- for (int i = 0; i < 10; i++) {
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myOperation = myConnection->getNdbOperation("MYTABLENAME");
- if (myOperation == NULL) APIERROR(myConnection->getNdbError());
-
- myOperation->readTuple();
- myOperation->equal("ATTR1", i);
-
- myRecAttr = myOperation->getValue("ATTR2", NULL);
- if (myRecAttr == NULL) APIERROR(myConnection->getNdbError());
-
- if(myConnection->execute( Commit ) == -1)
- if (i == 3) {
- std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
- } else {
- APIERROR(myConnection->getNdbError());
- }
-
- if (i != 3) {
- printf(" %2d %2d\n", i, myRecAttr->u_32_value());
- }
- myNdb->closeTransaction(myConnection);
- }
-
- /**************
- * Drop index *
- **************/
- if (myDict->dropIndex("MYINDEXNAME", "MYTABLENAME") == -1)
- APIERROR(myDict->getNdbError());
-
- /**************
- * Drop table *
- **************/
- if (myDict->dropTable("MYTABLENAME") == -1)
- APIERROR(myDict->getNdbError());
-
- delete myNdb;
-}
diff --git a/ndb/examples/ndbapi_example5/Makefile b/ndb/examples/ndbapi_example5/Makefile
deleted file mode 100644
index e2e3f06374a..00000000000
--- a/ndb/examples/ndbapi_example5/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
--include .defs.mk
-#NDB_OS = OS_YOU_ARE_RUNNING_ON
-#You need to set the NDB_OS variable here
-TARGET = ndbapi_example5
-SRCS = ndbapi_example5.cpp
-OBJS = ndbapi_example5.o
-CXX = g++
-CFLAGS = -c -Wall -fno-rtti -fno-exceptions
-DEBUG =
-LFLAGS = -Wall
-INCLUDE_DIR = ../../include
-LIB_DIR = ../../lib
-ifeq ($(NDB_OS), SOLARIS)
-# Here is the definition of system libraries necessary for Solaris 7
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), LINUX)
-# Here is the definition of system libraries necessary for Linux 2.4
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), MACOSX)
-# Here is the definition of system libraries necessary for Mac OS X
-SYS_LIB =
-endif
-
-$(TARGET): $(OBJS)
- $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(SYS_LIB) -o $(TARGET)
-
-$(TARGET).o: $(SRCS)
- $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
-
-clean:
- rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_scan_example/Makefile b/ndb/examples/ndbapi_scan_example/Makefile
deleted file mode 100644
index d7f08af4647..00000000000
--- a/ndb/examples/ndbapi_scan_example/Makefile
+++ /dev/null
@@ -1,35 +0,0 @@
--include .defs.mk
-#NDB_OS = OS_YOU_ARE_RUNNING_ON
-#You need to set the NDB_OS variable here (LINUX, SOLARIS, MACOSX)
-#NDB_OS = LINUX
-
-TARGET = ndbapi_scan
-SRCS = ndbapi_scan.cpp
-OBJS = ndbapi_scan.o
-CC = g++
-CFLAGS = -c -Wall -fno-rtti
-DEBUG =
-LFLAGS = -Wall
-INCLUDE_DIR = ../../include
-LIB_DIR = ../../lib
-ifeq ($(NDB_OS), SOLARIS)
-# Here is the definition of system libraries necessary for Solaris 7
-SYS_LIB = -lpthread -lsocket -lnsl -lrt
-endif
-ifeq ($(NDB_OS), LINUX)
-# Here is the definition of system libraries necessary for Linux 2.4
-SYS_LIB = -lpthread
-endif
-ifeq ($(NDB_OS), MACOSX)
-# Here is the definition of system libraries necessary for Mac OS X
-SYS_LIB =
-endif
-
-$(TARGET): $(OBJS)
- $(CC) $(LFLAGS) -L$(LIB_DIR) -lNDB_API $(OBJS) $(SYS_LIB) -o $(TARGET)
-
-$(TARGET).o: $(SRCS)
- $(CC) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
-
-clean:
- rm -f *.o $(TARGET)
diff --git a/ndb/examples/select_all/Makefile b/ndb/examples/select_all/Makefile
deleted file mode 100644
index 2bec205fa99..00000000000
--- a/ndb/examples/select_all/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
--include .defs.mk
-#NDB_OS = OS_YOU_ARE_RUNNING_ON
-#You need to set the NDB_OS variable here
-TARGET = select_all
-SRCS = select_all.cpp
-OBJS = select_all.o
-CXX = g++
-CFLAGS = -c -Wall -fno-rtti -fno-exceptions
-DEBUG =
-LFLAGS = -Wall
-INCLUDE_DIR = ../../include
-LIB_DIR = ../../lib
-ifeq ($(NDB_OS), SOLARIS)
-# Here is the definition of system libraries necessary for Solaris 7
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), LINUX)
-# Here is the definition of system libraries necessary for Linux 2.4
-SYS_LIB =
-endif
-ifeq ($(NDB_OS), MACOSX)
-# Here is the definition of system libraries necessary for Mac OS X
-SYS_LIB =
-endif
-
-$(TARGET): $(OBJS)
- $(CXX) $(LFLAGS) -L$(LIB_DIR) $(OBJS) -lNDB_API $(SYS_LIB) -o $(TARGET)
-
-$(TARGET).o: $(SRCS)
- $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
-
-clean:
- rm -f *.o $(TARGET)
diff --git a/ndb/examples/select_all/select_all.cpp b/ndb/examples/select_all/select_all.cpp
deleted file mode 100644
index 24bb1214bd2..00000000000
--- a/ndb/examples/select_all/select_all.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-//
-// select_all.cpp: Prints all rows of a table
-//
-// Usage: select_all <table_name>+
-
-#include <NdbApi.hpp>
-
-// Used for cout
-#include <iostream>
-using namespace std;
-#include <stdio.h>
-#include <string.h>
-
-#define APIERROR(error) \
- { cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
- << error.code << ", msg: " << error.message << "." << endl; \
- exit(-1); }
-
-void usage(const char* prg) {
- cout << "Usage: " << prg << " <table name>" << endl;
- cout << "Prints all rows of table named <table name>" << endl;
- exit(0);
-}
-
-/*****************************************************************************
- *************************** Result Set Container ****************************
- *****************************************************************************/
-
-/*
- * Container of NdbRecAttr objects.
- * (NdbRecAttr objects are database rows read by a scan operation.)
- */
-class ResultSetContainer {
-public:
- /**
- * Initialize ResultSetContainer object for table named <tableName>
- * - Allocates memory
- * - Fetches attribute names from NDB Cluster
- */
- void init(NdbDictionary::Dictionary* dict, const char* tableName);
-
- /**
- * Get no of attributes for stored NdbRecAttr objects
- */
- int getNoOfAttributes() const;
-
- /**
- * Get NdbRecAttr object no i
- */
- NdbRecAttr* & getAttrStore(int i);
-
- /**
- * Get attribute name of attribute no i
- */
- const char* getAttrName(int i) const;
-
- /**
- * Print header of rows
- */
- void header() const;
-
-private:
- int m_cols; // No of attributes for stored NdbRecAttr objects
- char **m_names; // Names of attributes
- NdbRecAttr **m_data; // The actual stored NdbRecAttr objects
-};
-
-void ResultSetContainer::init(NdbDictionary::Dictionary * dict,
- const char* tableName)
-{
- // Get Table object from NDB (this contains metadata about all tables)
- const NdbDictionary::Table * tab = dict->getTable(tableName);
-
- // Get table id of the table we are interested in
- if (tab == 0) APIERROR(dict->getNdbError()); // E.g. table didn't exist
-
- // Get no of attributes and allocate memory
- m_cols = tab->getNoOfColumns();
- m_names = new char* [m_cols];
- m_data = new NdbRecAttr* [m_cols];
-
- // Store all attribute names for the table
- for (int i = 0; i < m_cols; i++) {
- m_names[i] = new char[255];
- BaseString::snprintf(m_names[i], 255, "%s", tab->getColumn(i)->getName());
- }
-}
-
-int ResultSetContainer::getNoOfAttributes() const {return m_cols;}
-NdbRecAttr*& ResultSetContainer::getAttrStore(int i) {return m_data[i];}
-const char* ResultSetContainer::getAttrName(int i) const {return m_names[i];}
-
-/*****************************************************************************
- ********************************** MAIN ***********************************
- *****************************************************************************/
-
-int main(int argc, const char** argv)
-{
- ndb_init();
- Ndb* myNdb = new Ndb("ndbapi_example4"); // Object representing the database
- NdbConnection* myNdbConnection; // For transactions
- NdbOperation* myNdbOperation; // For operations
- int check;
-
- if (argc != 2) {
- usage(argv[0]);
- exit(0);
- }
- const char* tableName = argv[1];
-
- /*******************************************
- * Initialize NDB and wait until its ready *
- *******************************************/
- if (myNdb->init() == -1) {
- APIERROR(myNdb->getNdbError());
- exit(-1);
- }
-
- if (myNdb->waitUntilReady(30) != 0) {
- cout << "NDB was not ready within 30 secs." << endl;
- exit(-1);
- }
-
- /***************************
- * Define and execute scan *
- ***************************/
- cout << "Select * from " << tableName << endl;
-
- ResultSetContainer * container = new ResultSetContainer;
- container->init(myNdb->getDictionary(), tableName);
-
- myNdbConnection = myNdb->startTransaction();
- if (myNdbConnection == NULL) APIERROR(myNdb->getNdbError());
-
- myNdbOperation = myNdbConnection->getNdbOperation(tableName);
- if (myNdbOperation == NULL) APIERROR(myNdbConnection->getNdbError());
-
- // Define the operation to be an 'openScanRead' operation.
- check = myNdbOperation->openScanRead(1);
- if (check == -1) APIERROR(myNdbConnection->getNdbError());
-
- // Set interpreted program to just be the single instruction
- // 'interpret_exit_ok'. (This approves all rows of the table.)
- if (myNdbOperation->interpret_exit_ok() == -1)
- APIERROR(myNdbConnection->getNdbError());
-
- // Get all attribute values of the row
- for(int i = 0; i < container->getNoOfAttributes(); i++){
- if((container->getAttrStore(i) =
- myNdbOperation->getValue(container->getAttrName(i))) == 0)
- APIERROR(myNdbConnection->getNdbError());
- }
-
- // Execute scan operation
- check = myNdbConnection->executeScan();
- if (check == -1) APIERROR(myNdbConnection->getNdbError());
-
- /****************
- * Print header *
- ****************/
- for (int i = 0; i < container->getNoOfAttributes(); i++)
- cout << container->getAttrName(i) << "\t";
-
- cout << endl;
- for (int i = 0; i < container->getNoOfAttributes(); i++) {
- for (int j = strlen(container->getAttrName(i)); j > 0; j--)
- cout << "-";
- cout << "\t";
- }
- cout << "\n";
-
- /**************
- * Scan table *
- **************/
- int eof;
- int rows = 0;
-
- // Print all rows of table
- while ((eof = myNdbConnection->nextScanResult()) == 0) {
- rows++;
-
- for (int i = 0; i < container->getNoOfAttributes(); i++) {
- if (container->getAttrStore(i)->isNULL()) {
- cout << "NULL";
- } else {
-
- // Element size of value (No of bits per element in attribute value)
- const int size = container->getAttrStore(i)->attrSize();
-
- // No of elements in an array attribute (Is 1 if non-array attribute)
- const int aSize = container->getAttrStore(i)->arraySize();
-
- switch(container->getAttrStore(i)->attrType()){
- case UnSigned:
- switch(size) {
- case 8: cout << container->getAttrStore(i)->u_64_value(); break;
- case 4: cout << container->getAttrStore(i)->u_32_value(); break;
- case 2: cout << container->getAttrStore(i)->u_short_value(); break;
- case 1: cout << (unsigned) container->getAttrStore(i)->u_char_value();
- break;
- default: cout << "Unknown size" << endl;
- }
- break;
-
- case Signed:
- switch(size) {
- case 8: cout << container->getAttrStore(i)->int64_value(); break;
- case 4: cout << container->getAttrStore(i)->int32_value(); break;
- case 2: cout << container->getAttrStore(i)->short_value(); break;
- case 1: cout << (int) container->getAttrStore(i)->char_value(); break;
- default: cout << "Unknown size" << endl;
- }
- break;
-
- case String:
- {
- char* buf = new char[aSize+1];
- memcpy(buf, container->getAttrStore(i)->aRef(), aSize);
- buf[aSize] = 0;
- cout << buf;
- delete [] buf;
- }
- break;
-
- case Float:
- cout << container->getAttrStore(i)->float_value();
- break;
-
- default:
- cout << "Unknown";
- break;
- }
- }
- cout << "\t";
- }
- cout << endl;
- }
- if (eof == -1) APIERROR(myNdbConnection->getNdbError());
-
- myNdb->closeTransaction(myNdbConnection);
-
- cout << "Selected " << rows << " rows." << endl;
-}
diff --git a/ndb/include/Makefile.am b/ndb/include/Makefile.am
index ef4e9552566..10f297492e9 100644
--- a/ndb/include/Makefile.am
+++ b/ndb/include/Makefile.am
@@ -2,6 +2,7 @@
include $(top_srcdir)/ndb/config/common.mk.am
ndbinclude_HEADERS = \
+ndb_constants.h \
ndb_init.h \
ndb_types.h \
ndb_version.h
@@ -11,8 +12,7 @@ ndbapi/ndbapi_limits.h \
ndbapi/ndb_opt_defaults.h \
ndbapi/Ndb.hpp \
ndbapi/NdbApi.hpp \
-ndbapi/NdbConnection.hpp \
-ndbapi/NdbCursorOperation.hpp \
+ndbapi/NdbTransaction.hpp \
ndbapi/NdbDictionary.hpp \
ndbapi/NdbError.hpp \
ndbapi/NdbEventOperation.hpp \
@@ -23,7 +23,6 @@ ndbapi/NdbBlob.hpp \
ndbapi/NdbPool.hpp \
ndbapi/NdbRecAttr.hpp \
ndbapi/NdbReceiver.hpp \
-ndbapi/NdbResultSet.hpp \
ndbapi/NdbScanFilter.hpp \
ndbapi/NdbScanOperation.hpp \
ndbapi/NdbIndexScanOperation.hpp \
@@ -33,7 +32,8 @@ mgmapiinclude_HEADERS = \
mgmapi/mgmapi.h \
mgmapi/mgmapi_debug.h \
mgmapi/mgmapi_config_parameters.h \
-mgmapi/mgmapi_config_parameters_debug.h
+mgmapi/mgmapi_config_parameters_debug.h \
+mgmapi/ndb_logevent.h
noinst_HEADERS = \
ndb_global.h \
@@ -46,3 +46,6 @@ dist-hook:
-rm -rf `find $(distdir) -type d -name SCCS`
windoze-dsp:
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/ndb/include/debugger/EventLogger.hpp b/ndb/include/debugger/EventLogger.hpp
index ddf21b79f5f..6308cf25465 100644
--- a/ndb/include/debugger/EventLogger.hpp
+++ b/ndb/include/debugger/EventLogger.hpp
@@ -17,12 +17,12 @@
#ifndef EVENTLOGGER_H
#define EVENTLOGGER_H
-#include <Logger.hpp>
-#include <FileLogHandler.hpp>
-#include <GrepError.hpp>
-#include <kernel_types.h>
+#include <logger/Logger.hpp>
+#include <logger/FileLogHandler.hpp>
+#include "GrepError.hpp"
+#include <kernel/kernel_types.h>
#include <kernel/LogLevel.hpp>
-#include <signaldata/EventReport.hpp>
+#include <kernel/signaldata/EventReport.hpp>
class EventLoggerBase {
public:
@@ -39,11 +39,14 @@ public:
* threshold - is in range [0-15]
* severity - DEBUG to ALERT (Type of log message)
*/
+ typedef void (* EventTextFunction)(char *,size_t,const Uint32*);
+
struct EventRepLogLevelMatrix {
- EventReport::EventType eventType;
- LogLevel::EventCategory eventCategory;
- Uint32 threshold;
- Logger::LoggerLevel severity;
+ Ndb_logevent_type eventType;
+ LogLevel::EventCategory eventCategory;
+ Uint32 threshold;
+ Logger::LoggerLevel severity;
+ EventTextFunction textF;
};
static const EventRepLogLevelMatrix matrix[];
@@ -51,7 +54,8 @@ public:
static int event_lookup(int eventType,
LogLevel::EventCategory &cat,
Uint32 &threshold,
- Logger::LoggerLevel &severity);
+ Logger::LoggerLevel &severity,
+ EventTextFunction &textF);
};
/**
@@ -130,17 +134,18 @@ public:
* @param nodeId the node id of event origin.
*/
virtual void log(int, const Uint32*, NodeId = 0,const class LogLevel * = 0);
+
/**
* Returns the event text for the specified event report type.
*
- * @param type the event type.
+ * @param textF print function for the event
* @param theData the event data.
* @param nodeId a node id.
* @return the event report text.
*/
static const char* getText(char * dst, size_t dst_len,
- int type,
+ EventTextFunction textF,
const Uint32* theData, NodeId nodeId = 0);
/**
diff --git a/ndb/include/kernel/AttributeDescriptor.hpp b/ndb/include/kernel/AttributeDescriptor.hpp
index 071d45e2607..af28e777213 100644
--- a/ndb/include/kernel/AttributeDescriptor.hpp
+++ b/ndb/include/kernel/AttributeDescriptor.hpp
@@ -19,6 +19,8 @@
class AttributeDescriptor {
friend class Dbdict;
+ friend class Dbtc;
+ friend class Dbacc;
friend class Dbtup;
friend class Dbtux;
@@ -26,47 +28,39 @@ private:
static void setType(Uint32 &, Uint32 type);
static void setSize(Uint32 &, Uint32 size);
static void setArray(Uint32 &, Uint32 arraySize);
- static void setOriginal(Uint32 &, Uint32 original);
static void setNullable(Uint32 &, Uint32 nullable);
- static void setDGroup(Uint32 &, Uint32 dgroup);
static void setDKey(Uint32 &, Uint32 dkey);
static void setPrimaryKey(Uint32 &, Uint32 dkey);
- static void setStoredInTup(Uint32 &, Uint32 storedInTup);
static void setDynamic(Uint32 &, Uint32 dynamicInd);
static Uint32 getType(const Uint32 &);
static Uint32 getSize(const Uint32 &);
+ static Uint32 getSizeInBytes(const Uint32 &);
static Uint32 getSizeInWords(const Uint32 &);
static Uint32 getArrayType(const Uint32 &);
static Uint32 getArraySize(const Uint32 &);
- static Uint32 getOriginal(const Uint32 &);
static Uint32 getNullable(const Uint32 &);
- static Uint32 getDGroup(const Uint32 &);
static Uint32 getDKey(const Uint32 &);
static Uint32 getPrimaryKey(const Uint32 &);
- static Uint32 getStoredInTup(const Uint32 &);
static Uint32 getDynamic(const Uint32 &);
};
/**
*
* a = Array type - 2 Bits -> Max 3 (Bit 0-1)
- * t = Attribute type - 2 Bits -> Max 3 (Bit 2-3)
- * s = Attribute size - 3 Bits -> Max 7 (Bit 4-6)
- * o = Original attribute - 1 Bit 7
- * n = Nullable - 1 Bit 8
- * ? = Stored in tup - 1 Bit 9
- * d = Disk based - 1 Bit 10
- * g = Distribution Group Ind- 1 Bit 11
- * k = Distribution Key Ind - 1 Bit 12
- * r = Distribution group sz - 1 Bit 13
+ * t = Attribute type - 5 Bits -> Max 31 (Bit 2-6)
+ * s = Attribute size - 3 Bits -> Max 7 (Bit 8-10)
+ * d = Disk based - 1 Bit 11
+ * n = Nullable - 1 Bit 12
+ * k = Distribution Key Ind - 1 Bit 13
* p = Primary key attribute - 1 Bit 14
* y = Dynamic attribute - 1 Bit 15
* z = Array size - 16 Bits -> Max 65535 (Bit 16-31)
*
* 1111111111222222222233
* 01234567890123456789012345678901
- * aattsss n dgkrpyzzzzzzzzzzzzzzzz
+ * aattttt sssdnkpyzzzzzzzzzzzzzzzz
+ * aattsss n d k pyzzzzzzzzzzzzzzzz [ old format ]
*
*/
@@ -74,21 +68,17 @@ private:
#define AD_ARRAY_TYPE_MASK (3)
#define AD_TYPE_SHIFT (2)
-#define AD_TYPE_MASK (3)
+#define AD_TYPE_MASK (31)
-#define AD_SIZE_SHIFT (4)
+#define AD_SIZE_SHIFT (8)
#define AD_SIZE_MASK (7)
+#define AD_SIZE_IN_BYTES_SHIFT (3)
#define AD_SIZE_IN_WORDS_OFFSET (31)
#define AD_SIZE_IN_WORDS_SHIFT (5)
-#define AD_ORIGINAL_SHIFT (8)
-#define AD_NULLABLE_SHIFT (8)
-#define AD_TUP_STORED_SHIFT (9)
-
-#define AD_DISTR_GROUP_SHIFT (11)
-#define AD_DISTR_KEY_SHIFT (12)
-#define AD_DISTR_GROUP_SZ (13)
+#define AD_NULLABLE_SHIFT (12)
+#define AD_DISTR_KEY_SHIFT (13)
#define AD_PRIMARY_KEY (14)
#define AD_DYNAMIC (15)
@@ -130,20 +120,6 @@ AttributeDescriptor::setNullable(Uint32 & desc, Uint32 nullable){
inline
void
-AttributeDescriptor::setOriginal(Uint32 & desc, Uint32 original){
- ASSERT_BOOL(original, "AttributeDescriptor::setOriginal");
- desc |= (original << AD_ORIGINAL_SHIFT);
-}
-
-inline
-void
-AttributeDescriptor::setDGroup(Uint32 & desc, Uint32 dgroup){
- ASSERT_BOOL(dgroup, "AttributeDescriptor::setDGroup");
- desc |= (dgroup << AD_DISTR_GROUP_SHIFT);
-}
-
-inline
-void
AttributeDescriptor::setDKey(Uint32 & desc, Uint32 dkey){
ASSERT_BOOL(dkey, "AttributeDescriptor::setDKey");
desc |= (dkey << AD_DISTR_KEY_SHIFT);
@@ -158,13 +134,6 @@ AttributeDescriptor::setPrimaryKey(Uint32 & desc, Uint32 dkey){
inline
void
-AttributeDescriptor::setStoredInTup(Uint32 & desc, Uint32 storedInTup){
- ASSERT_BOOL(storedInTup, "AttributeDescriptor::setStoredInTup");
- desc |= (storedInTup << AD_TUP_STORED_SHIFT);
-}
-
-inline
-void
AttributeDescriptor::setDynamic(Uint32 & desc, Uint32 dynamic){
ASSERT_BOOL(dynamic, "AttributeDescriptor::setDynamic");
desc |= (dynamic << AD_DYNAMIC);
@@ -187,6 +156,13 @@ AttributeDescriptor::getSize(const Uint32 & desc){
inline
Uint32
+AttributeDescriptor::getSizeInBytes(const Uint32 & desc){
+ return (getArraySize(desc) << getSize(desc))
+ >> AD_SIZE_IN_BYTES_SHIFT;
+}
+
+inline
+Uint32
AttributeDescriptor::getSizeInWords(const Uint32 & desc){
return ((getArraySize(desc) << getSize(desc))
+ AD_SIZE_IN_WORDS_OFFSET)
@@ -213,18 +189,6 @@ AttributeDescriptor::getNullable(const Uint32 & desc){
inline
Uint32
-AttributeDescriptor::getOriginal(const Uint32 & desc){
- return (desc >> AD_ORIGINAL_SHIFT) & 1;
-}
-
-inline
-Uint32
-AttributeDescriptor::getDGroup(const Uint32 & desc){
- return (desc >> AD_DISTR_GROUP_SHIFT) & 1;
-}
-
-inline
-Uint32
AttributeDescriptor::getDKey(const Uint32 & desc){
return (desc >> AD_DISTR_KEY_SHIFT) & 1;
}
@@ -241,10 +205,4 @@ AttributeDescriptor::getDynamic(const Uint32 & desc){
return (desc >> AD_DYNAMIC) & 1;
}
-inline
-Uint32
-AttributeDescriptor::getStoredInTup(const Uint32 & desc){
- return (desc >> AD_TUP_STORED_SHIFT) & 1;
-}
-
#endif
diff --git a/ndb/include/kernel/AttributeHeader.hpp b/ndb/include/kernel/AttributeHeader.hpp
index ed9085301be..3cb432067eb 100644
--- a/ndb/include/kernel/AttributeHeader.hpp
+++ b/ndb/include/kernel/AttributeHeader.hpp
@@ -33,10 +33,14 @@ public:
* Psuedo columns
*/
STATIC_CONST( PSUEDO = 0x8000 );
- STATIC_CONST( FRAGMENT = 0xFFFE );
- STATIC_CONST( ROW_COUNT = 0xFFFD );
- STATIC_CONST( COMMIT_COUNT = 0xFFFC );
+ STATIC_CONST( FRAGMENT = 0xFFFE ); // Read fragment no
+ STATIC_CONST( ROW_COUNT = 0xFFFD ); // Read row count (committed)
+ STATIC_CONST( COMMIT_COUNT = 0xFFFC ); // Read commit count
+ STATIC_CONST( RANGE_NO = 0xFFFB ); // Read range no (when batched ranges)
+ STATIC_CONST( ROW_SIZE = 0xFFFA );
+ STATIC_CONST( FRAGMENT_MEMORY= 0xFFF9 );
+
/** Initialize AttributeHeader at location aHeaderPtr */
static AttributeHeader& init(void* aHeaderPtr, Uint32 anAttributeId,
Uint32 aDataSize);
diff --git a/ndb/include/kernel/LogLevel.hpp b/ndb/include/kernel/LogLevel.hpp
index 3c2f349e0e1..60dcd36ab56 100644
--- a/ndb/include/kernel/LogLevel.hpp
+++ b/ndb/include/kernel/LogLevel.hpp
@@ -57,7 +57,7 @@ public:
llInfo = CFG_LOGLEVEL_INFO - CFG_MIN_LOGLEVEL,
llWarning = CFG_LOGLEVEL_WARNING - CFG_MIN_LOGLEVEL,
llError = CFG_LOGLEVEL_ERROR - CFG_MIN_LOGLEVEL,
- llGrep = CFG_LOGLEVEL_GREP - CFG_MIN_LOGLEVEL,
+ llCongestion = CFG_LOGLEVEL_CONGESTION - CFG_MIN_LOGLEVEL,
llDebug = CFG_LOGLEVEL_DEBUG - CFG_MIN_LOGLEVEL
,llBackup = CFG_LOGLEVEL_BACKUP - CFG_MIN_LOGLEVEL
};
@@ -147,7 +147,7 @@ LogLevel::set_max(const LogLevel & org){
return * this;
}
-#include <signaldata/EventSubscribeReq.hpp>
+#include "signaldata/EventSubscribeReq.hpp"
inline
LogLevel&
diff --git a/ndb/include/kernel/ndb_limits.h b/ndb/include/kernel/ndb_limits.h
index 48a56c019bb..2646b54fa02 100644
--- a/ndb/include/kernel/ndb_limits.h
+++ b/ndb/include/kernel/ndb_limits.h
@@ -50,7 +50,6 @@
**/
#define MAX_TUPLES_PER_PAGE 8191
#define MAX_TUPLES_BITS 13 /* 13 bits = 8191 tuples per page */
-/*#define MAX_NO_OF_TUPLEKEY 16 Not currently used */
#define MAX_TABLES 1600
#define MAX_TAB_NAME_SIZE 128
#define MAX_ATTR_NAME_SIZE 32
@@ -58,9 +57,10 @@
#define MAX_ATTRIBUTES_IN_TABLE 128
#define MAX_ATTRIBUTES_IN_INDEX 32
#define MAX_TUPLE_SIZE_IN_WORDS 2013
-#define MAX_FIXED_KEY_LENGTH_IN_WORDS 8
#define MAX_KEY_SIZE_IN_WORDS 1023
#define MAX_FRM_DATA_SIZE 6000
+#define MAX_NULL_BITS 4096
+#define MAX_FRAGMENT_DATA_BYTES (4+(2 * 8 * MAX_REPLICAS * MAX_NDB_NODES))
#define MIN_ATTRBUF ((MAX_ATTRIBUTES_IN_TABLE/24) + 1)
/*
@@ -118,6 +118,11 @@
#define NDB_BLOB_HEAD_SIZE 2 /* sizeof(NdbBlob::Head) >> 2 */
/*
+ * Character sets.
+ */
+#define MAX_XFRM_MULTIPLY 8 /* max expansion when normalizing */
+
+/*
* Long signals
*/
#define NDB_SECTION_SEGMENT_SZ 60
diff --git a/ndb/include/kernel/signaldata/AccScan.hpp b/ndb/include/kernel/signaldata/AccScan.hpp
index eab1c3262fc..d1ca4424d1a 100644
--- a/ndb/include/kernel/signaldata/AccScan.hpp
+++ b/ndb/include/kernel/signaldata/AccScan.hpp
@@ -51,30 +51,29 @@ private:
* Previously there where also a scan type
*/
static Uint32 getLockMode(const Uint32 & requestInfo);
- static Uint32 getKeyinfoFlag(const Uint32 & requestInfo);
static Uint32 getReadCommittedFlag(const Uint32 & requestInfo);
+ static Uint32 getDescendingFlag(const Uint32 & requestInfo);
static void setLockMode(Uint32 & requestInfo, Uint32 lockMode);
- static void setKeyinfoFlag(Uint32 & requestInfo, Uint32 keyinfo);
static void setReadCommittedFlag(Uint32 & requestInfo, Uint32 readCommitted);
+ static void setDescendingFlag(Uint32 & requestInfo, Uint32 descending);
};
/**
* Request Info
*
* l = Lock Mode - 1 Bit 2
- * k = Keyinfo - 1 Bit 4
* h = Read Committed - 1 Bit 5
+ * z = Descending (TUX) - 1 Bit 6
*
* 1111111111222222222233
* 01234567890123456789012345678901
- * l kh
+ * l hz
*/
#define AS_LOCK_MODE_SHIFT (2)
#define AS_LOCK_MODE_MASK (1)
-
-#define AS_KEYINFO_SHIFT (4)
#define AS_READ_COMMITTED_SHIFT (5)
+#define AS_DESCENDING_SHIFT (6)
inline
Uint32
@@ -84,14 +83,14 @@ AccScanReq::getLockMode(const Uint32 & requestInfo){
inline
Uint32
-AccScanReq::getKeyinfoFlag(const Uint32 & requestInfo){
- return (requestInfo >> AS_KEYINFO_SHIFT) & 1;
+AccScanReq::getReadCommittedFlag(const Uint32 & requestInfo){
+ return (requestInfo >> AS_READ_COMMITTED_SHIFT) & 1;
}
inline
Uint32
-AccScanReq::getReadCommittedFlag(const Uint32 & requestInfo){
- return (requestInfo >> AS_READ_COMMITTED_SHIFT) & 1;
+AccScanReq::getDescendingFlag(const Uint32 & requestInfo){
+ return (requestInfo >> AS_DESCENDING_SHIFT) & 1;
}
inline
@@ -103,16 +102,16 @@ AccScanReq::setLockMode(UintR & requestInfo, UintR val){
inline
void
-AccScanReq::setKeyinfoFlag(UintR & requestInfo, UintR val){
- ASSERT_BOOL(val, "AccScanReq::setKeyinfoFlag");
- requestInfo |= (val << AS_KEYINFO_SHIFT);
+AccScanReq::setReadCommittedFlag(UintR & requestInfo, UintR val){
+ ASSERT_BOOL(val, "AccScanReq::setReadCommittedFlag");
+ requestInfo |= (val << AS_READ_COMMITTED_SHIFT);
}
inline
void
-AccScanReq::setReadCommittedFlag(UintR & requestInfo, UintR val){
- ASSERT_BOOL(val, "AccScanReq::setReadCommittedFlag");
- requestInfo |= (val << AS_READ_COMMITTED_SHIFT);
+AccScanReq::setDescendingFlag(UintR & requestInfo, UintR val){
+ ASSERT_BOOL(val, "AccScanReq::setDescendingFlag");
+ requestInfo |= (val << AS_DESCENDING_SHIFT);
}
class AccScanConf {
diff --git a/ndb/include/kernel/signaldata/CreateEvnt.hpp b/ndb/include/kernel/signaldata/CreateEvnt.hpp
index e911fa36ce6..8712ce8890c 100644
--- a/ndb/include/kernel/signaldata/CreateEvnt.hpp
+++ b/ndb/include/kernel/signaldata/CreateEvnt.hpp
@@ -17,6 +17,7 @@
#ifndef CREATE_EVNT_HPP
#define CREATE_EVNT_HPP
+#include <ndberror.h>
#include "SignalData.hpp"
#include <NodeBitmask.hpp>
#include <signaldata/DictTabInfo.hpp>
@@ -101,7 +102,7 @@ public:
Busy = 701,
NotMaster = 702,
SeizeError = 703,
- EventNotFound = 4238,
+ EventNotFound = 4710,
EventNameTooLong = 4241,
TooManyEvents = 4242,
BadRequestType = 4247,
@@ -363,12 +364,10 @@ struct CreateEvntRef {
Busy = 701,
NotMaster = 702,
SeizeError = 703,
- EventNotFound = 4238,
- EventExists = 4239,
- EventNameTooLong = 4241,
- TooManyEvents = 4242,
- // EventExists = 4244,
- AttributeNotStored = 4245,
+ TooManyEvents = 4707,
+ EventNameTooLong = 4708,
+ EventNameExists = 746,
+ EventNotFound = 4731,
AttributeNullable = 4246,
BadRequestType = 4247,
InvalidName = 4248,
@@ -376,7 +375,7 @@ struct CreateEvntRef {
InvalidEventType = 4250,
NotUnique = 4251,
AllocationError = 4252,
- CreateEventTableFailed = 4253,
+ CreateEventTableFailed = 4711,
InvalidAttributeOrder = 4255,
Temporary = 0x1 << 16
};
diff --git a/ndb/include/kernel/signaldata/CreateIndx.hpp b/ndb/include/kernel/signaldata/CreateIndx.hpp
index 5563f80a555..a9dc653f349 100644
--- a/ndb/include/kernel/signaldata/CreateIndx.hpp
+++ b/ndb/include/kernel/signaldata/CreateIndx.hpp
@@ -198,7 +198,6 @@ public:
IndexNameTooLong = 4241,
TooManyIndexes = 4242,
IndexExists = 4244,
- AttributeNotStored = 4245,
AttributeNullable = 4246,
BadRequestType = 4247,
InvalidName = 4248,
@@ -207,7 +206,7 @@ public:
NotUnique = 4251,
AllocationError = 4252,
CreateIndexTableFailed = 4253,
- InvalidAttributeOrder = 4255
+ DuplicateAttributes = 4258
};
CreateIndxConf m_conf;
diff --git a/ndb/include/kernel/signaldata/CreateTable.hpp b/ndb/include/kernel/signaldata/CreateTable.hpp
index 67e510d2ed0..481b323fdb0 100644
--- a/ndb/include/kernel/signaldata/CreateTable.hpp
+++ b/ndb/include/kernel/signaldata/CreateTable.hpp
@@ -86,6 +86,7 @@ public:
NoMoreAttributeRecords = 708,
AttributeNameTwice = 720,
TableAlreadyExist = 721,
+ InvalidArraySize = 736,
ArraySizeTooBig = 737,
RecordTooBig = 738,
InvalidPrimaryKeySize = 739,
diff --git a/ndb/include/kernel/signaldata/DictTabInfo.hpp b/ndb/include/kernel/signaldata/DictTabInfo.hpp
index a2f9fcc9799..09b00cf8993 100644
--- a/ndb/include/kernel/signaldata/DictTabInfo.hpp
+++ b/ndb/include/kernel/signaldata/DictTabInfo.hpp
@@ -24,6 +24,28 @@
#include <trigger_definitions.h>
#include <NdbSqlUtil.hpp>
+#ifndef my_decimal_h
+
+// sql/my_decimal.h requires many more sql/*.h new to ndb
+// for now, copy the bit we need TODO proper fix
+
+#define DECIMAL_MAX_LENGTH ((8 * 9) - 8)
+
+#ifndef NOT_FIXED_DEC
+#define NOT_FIXED_DEC 31
+#endif
+
+C_MODE_START
+extern int decimal_bin_size(int, int);
+C_MODE_END
+
+inline int my_decimal_get_binary_size(uint precision, uint scale)
+{
+ return decimal_bin_size((int)precision, (int)scale);
+}
+
+#endif
+
#define DTIMAP(x, y, z) \
{ DictTabInfo::y, offsetof(x, z), SimpleProperties::Uint32Value, 0, (~0), 0 }
@@ -85,10 +107,6 @@ public:
MaxLoadFactor = 11, //Default 80
KeyLength = 12, //Default 1 (No of words in primary key)
FragmentTypeVal = 13, //Default AllNodesSmallTable
- TableStorageVal = 14, //Default StorageType::MainMemory
- ScanOptimised = 15, //Default updateOptimised
- FragmentKeyTypeVal = 16, //Default PrimaryKey
- SecondTableId = 17, //Mandatory between DICT's otherwise not allowed
TableTypeVal = 18, //Default TableType::UserTable
PrimaryTable = 19, //Mandatory for index otherwise RNIL
PrimaryTableId = 20, //ditto
@@ -100,21 +118,20 @@ public:
FrmLen = 26,
FrmData = 27,
FragmentCount = 128, // No of fragments in table (!fragment replicas)
+ FragmentDataLen = 129,
+ FragmentData = 130, // CREATE_FRAGMENTATION reply
TableEnd = 999,
AttributeName = 1000, // String, Mandatory
AttributeId = 1001, //Mandatory between DICT's otherwise not allowed
- AttributeType = 1002, //Default UnSignedType
+ AttributeType = 1002, //for osu 4.1->5.0.x
AttributeSize = 1003, //Default DictTabInfo::a32Bit
AttributeArraySize = 1005, //Default 1
AttributeKeyFlag = 1006, //Default noKey
AttributeStorage = 1007, //Default MainMemory
AttributeNullableFlag = 1008, //Default NotNullable
- AttributeDGroup = 1009, //Default NotDGroup
AttributeDKey = 1010, //Default NotDKey
- AttributeStoredInd = 1011, //Default NotStored
- AttributeGroup = 1012, //Default 0
- AttributeExtType = 1013, //Default 0 (undefined)
+ AttributeExtType = 1013, //Default ExtUnsigned
AttributeExtPrecision = 1014, //Default 0
AttributeExtScale = 1015, //Default 0
AttributeExtLength = 1016, //Default 0
@@ -127,12 +144,7 @@ public:
// have a default value. Thus the default values are part of the protocol.
// ----------------------------------------------------------------------
- // FragmentKeyType constants
- enum FragmentKeyType {
- PrimaryKey = 0,
- DistributionKey = 1,
- DistributionGroup = 2
- };
+
// FragmentType constants
enum FragmentType {
@@ -142,12 +154,6 @@ public:
SingleFragment = 3
};
- // TableStorage AND AttributeStorage constants
- enum StorageType {
- MainMemory = 0,
- DiskMemory = 1
- };
-
// TableType constants + objects
enum TableType {
UndefTableType = 0,
@@ -219,40 +225,18 @@ public:
StorePermanent = 2
};
- // ScanOptimised constants
- STATIC_CONST( updateOptimised = 0 );
- STATIC_CONST( scanOptimised = 1 );
-
- // AttributeType constants
- STATIC_CONST( SignedType = 0 );
- STATIC_CONST( UnSignedType = 1 );
- STATIC_CONST( FloatingPointType = 2 );
- STATIC_CONST( StringType = 3 );
-
// AttributeSize constants
+ STATIC_CONST( aBit = 0 );
STATIC_CONST( an8Bit = 3 );
STATIC_CONST( a16Bit = 4 );
STATIC_CONST( a32Bit = 5 );
STATIC_CONST( a64Bit = 6 );
STATIC_CONST( a128Bit = 7 );
-
- // AttributeDGroup constants
- STATIC_CONST( NotDGroup = 0 );
- STATIC_CONST( DGroup = 1 );
-
- // AttributeDKey constants
- STATIC_CONST( NotDKey = 0 );
- STATIC_CONST( DKey = 1 );
-
- // AttributeStoredInd constants
- STATIC_CONST( NotStored = 0 );
- STATIC_CONST( Stored = 1 );
-
+
// Table data interpretation
struct Table {
char TableName[MAX_TAB_NAME_SIZE];
Uint32 TableId;
- Uint32 SecondTableId;
char PrimaryTable[MAX_TAB_NAME_SIZE]; // Only used when "index"
Uint32 PrimaryTableId;
Uint32 TableLoggedFlag;
@@ -266,8 +250,6 @@ public:
Uint32 KeyLength;
Uint32 FragmentType;
Uint32 TableStorage;
- Uint32 ScanOptimised;
- Uint32 FragmentKeyType;
Uint32 TableType;
Uint32 TableVersion;
Uint32 IndexState;
@@ -278,7 +260,9 @@ public:
Uint32 FrmLen;
char FrmData[MAX_FRM_DATA_SIZE];
Uint32 FragmentCount;
-
+ Uint32 FragmentDataLen;
+ Uint16 FragmentData[(MAX_FRAGMENT_DATA_BYTES+1)/2];
+
void init();
};
@@ -304,6 +288,8 @@ public:
ExtDouble = NdbSqlUtil::Type::Double,
ExtOlddecimal = NdbSqlUtil::Type::Olddecimal,
ExtOlddecimalunsigned = NdbSqlUtil::Type::Olddecimalunsigned,
+ ExtDecimal = NdbSqlUtil::Type::Decimal,
+ ExtDecimalunsigned = NdbSqlUtil::Type::Decimalunsigned,
ExtChar = NdbSqlUtil::Type::Char,
ExtVarchar = NdbSqlUtil::Type::Varchar,
ExtBinary = NdbSqlUtil::Type::Binary,
@@ -312,6 +298,9 @@ public:
ExtDate = NdbSqlUtil::Type::Date,
ExtBlob = NdbSqlUtil::Type::Blob,
ExtText = NdbSqlUtil::Type::Text,
+ ExtBit = NdbSqlUtil::Type::Bit,
+ ExtLongvarchar = NdbSqlUtil::Type::Longvarchar,
+ ExtLongvarbinary = NdbSqlUtil::Type::Longvarbinary,
ExtTime = NdbSqlUtil::Type::Time,
ExtYear = NdbSqlUtil::Type::Year,
ExtTimestamp = NdbSqlUtil::Type::Timestamp
@@ -321,16 +310,12 @@ public:
struct Attribute {
char AttributeName[MAX_TAB_NAME_SIZE];
Uint32 AttributeId;
- Uint32 AttributeType;
+ Uint32 AttributeType; // for osu 4.1->5.0.x
Uint32 AttributeSize;
Uint32 AttributeArraySize;
Uint32 AttributeKeyFlag;
- Uint32 AttributeStorage;
Uint32 AttributeNullableFlag;
- Uint32 AttributeDGroup;
Uint32 AttributeDKey;
- Uint32 AttributeStoredInd;
- Uint32 AttributeGroup;
Uint32 AttributeExtType;
Uint32 AttributeExtPrecision;
Uint32 AttributeExtScale;
@@ -346,132 +331,125 @@ public:
return ((1 << AttributeSize) * AttributeArraySize + 31) >> 5;
}
- // translate to old kernel types and sizes
+ // compute old-sty|e attribute size and array size
inline bool
translateExtType() {
switch (AttributeExtType) {
case DictTabInfo::ExtUndefined:
- break;
+ return false;
case DictTabInfo::ExtTinyint:
- AttributeType = DictTabInfo::SignedType;
- AttributeSize = DictTabInfo::an8Bit;
- AttributeArraySize = AttributeExtLength;
- return true;
case DictTabInfo::ExtTinyunsigned:
- AttributeType = DictTabInfo::UnSignedType;
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize = AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtSmallint:
- AttributeType = DictTabInfo::SignedType;
- AttributeSize = DictTabInfo::a16Bit;
- AttributeArraySize = AttributeExtLength;
- return true;
case DictTabInfo::ExtSmallunsigned:
- AttributeType = DictTabInfo::UnSignedType;
AttributeSize = DictTabInfo::a16Bit;
AttributeArraySize = AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtMediumint:
- AttributeType = DictTabInfo::SignedType;
- AttributeSize = DictTabInfo::an8Bit;
- AttributeArraySize = 3 * AttributeExtLength;
- return true;
case DictTabInfo::ExtMediumunsigned:
- AttributeType = DictTabInfo::UnSignedType;
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize = 3 * AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtInt:
- AttributeType = DictTabInfo::SignedType;
- AttributeSize = DictTabInfo::a32Bit;
- AttributeArraySize = AttributeExtLength;
- return true;
case DictTabInfo::ExtUnsigned:
- AttributeType = DictTabInfo::UnSignedType;
AttributeSize = DictTabInfo::a32Bit;
AttributeArraySize = AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtBigint:
- AttributeType = DictTabInfo::SignedType;
- AttributeSize = DictTabInfo::a64Bit;
- AttributeArraySize = AttributeExtLength;
- return true;
case DictTabInfo::ExtBigunsigned:
- AttributeType = DictTabInfo::UnSignedType;
AttributeSize = DictTabInfo::a64Bit;
AttributeArraySize = AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtFloat:
- AttributeType = DictTabInfo::FloatingPointType;
AttributeSize = DictTabInfo::a32Bit;
AttributeArraySize = AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtDouble:
- AttributeType = DictTabInfo::FloatingPointType;
AttributeSize = DictTabInfo::a64Bit;
AttributeArraySize = AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtOlddecimal:
- AttributeType = DictTabInfo::StringType;
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize =
(1 + AttributeExtPrecision + (int(AttributeExtScale) > 0)) *
AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtOlddecimalunsigned:
- AttributeType = DictTabInfo::StringType;
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize =
(0 + AttributeExtPrecision + (int(AttributeExtScale) > 0)) *
AttributeExtLength;
- return true;
+ break;
+ case DictTabInfo::ExtDecimal:
+ case DictTabInfo::ExtDecimalunsigned:
+ {
+ // copy from Field_new_decimal ctor
+ uint precision = AttributeExtPrecision;
+ uint scale = AttributeExtScale;
+ if (precision > DECIMAL_MAX_LENGTH || scale >= NOT_FIXED_DEC)
+ precision = DECIMAL_MAX_LENGTH;
+ uint bin_size = my_decimal_get_binary_size(precision, scale);
+ AttributeSize = DictTabInfo::an8Bit;
+ AttributeArraySize = bin_size * AttributeExtLength;
+ }
+ break;
case DictTabInfo::ExtChar:
case DictTabInfo::ExtBinary:
- AttributeType = DictTabInfo::StringType;
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize = AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtVarchar:
case DictTabInfo::ExtVarbinary:
- AttributeType = DictTabInfo::StringType;
+ if (AttributeExtLength > 0xff)
+ return false;
AttributeSize = DictTabInfo::an8Bit;
- AttributeArraySize = AttributeExtLength + 2;
- return true;
+ AttributeArraySize = AttributeExtLength + 1;
+ break;
case DictTabInfo::ExtDatetime:
- AttributeType = DictTabInfo::StringType;
+ // to fix
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize = 8 * AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtDate:
- AttributeType = DictTabInfo::StringType;
+ // to fix
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize = 3 * AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtBlob:
case DictTabInfo::ExtText:
- AttributeType = DictTabInfo::StringType;
AttributeSize = DictTabInfo::an8Bit;
- // head + inline part [ attr precision lower half ]
+ // head + inline part (length in precision lower half)
AttributeArraySize = (NDB_BLOB_HEAD_SIZE << 2) + (AttributeExtPrecision & 0xFFFF);
- return true;
+ break;
+ case DictTabInfo::ExtBit:
+ AttributeSize = DictTabInfo::aBit;
+ AttributeArraySize = AttributeExtLength;
+ break;
+ case DictTabInfo::ExtLongvarchar:
+ case DictTabInfo::ExtLongvarbinary:
+ if (AttributeExtLength > 0xffff)
+ return false;
+ AttributeSize = DictTabInfo::an8Bit;
+ AttributeArraySize = AttributeExtLength + 2;
+ break;
case DictTabInfo::ExtTime:
- AttributeType = DictTabInfo::StringType;
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize = 3 * AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtYear:
- AttributeType = DictTabInfo::StringType;
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize = 1 * AttributeExtLength;
- return true;
+ break;
case DictTabInfo::ExtTimestamp:
- AttributeType = DictTabInfo::StringType;
AttributeSize = DictTabInfo::an8Bit;
AttributeArraySize = 4 * AttributeExtLength;
- return true;
+ break;
+ default:
+ return false;
};
- return false;
+ return true;
}
inline void print(FILE *out) {
@@ -482,9 +460,7 @@ public:
fprintf(out, "AttributeKeyFlag = %d\n", AttributeKeyFlag);
fprintf(out, "AttributeStorage = %d\n", AttributeStorage);
fprintf(out, "AttributeNullableFlag = %d\n", AttributeNullableFlag);
- fprintf(out, "AttributeDGroup = %d\n", AttributeDGroup);
fprintf(out, "AttributeDKey = %d\n", AttributeDKey);
- fprintf(out, "AttributeStoredInd = %d\n", AttributeStoredInd);
fprintf(out, "AttributeGroup = %d\n", AttributeGroup);
fprintf(out, "AttributeAutoIncrement = %d\n", AttributeAutoIncrement);
fprintf(out, "AttributeExtType = %d\n", AttributeExtType);
@@ -518,6 +494,22 @@ private:
*/
Uint32 tabInfoData[DataLength];
+
+public:
+ enum Depricated
+ {
+ AttributeDGroup = 1009, //Default NotDGroup
+ AttributeStoredInd = 1011, //Default NotStored
+ SecondTableId = 17, //Mandatory between DICT's otherwise not allowed
+ FragmentKeyTypeVal = 16 //Default PrimaryKey
+ };
+
+ enum Unimplemented
+ {
+ TableStorageVal = 14, //Default StorageType::MainMemory
+ ScanOptimised = 15, //Default updateOptimised
+ AttributeGroup = 1012 //Default 0
+ };
};
#endif
diff --git a/ndb/include/kernel/signaldata/EventReport.hpp b/ndb/include/kernel/signaldata/EventReport.hpp
index 1ad6e1bf7ac..9822a0539cf 100644
--- a/ndb/include/kernel/signaldata/EventReport.hpp
+++ b/ndb/include/kernel/signaldata/EventReport.hpp
@@ -17,6 +17,7 @@
#ifndef SD_EVENT_REPORT_H
#define SD_EVENT_REPORT_H
+#include <ndb_logevent.h>
#include "SignalData.hpp"
/**
@@ -67,98 +68,21 @@ public:
4) Add SentHeartbeat in EventLogger::getText()
*/
- enum EventType {
- // CONNECTION
- Connected = 0,
- Disconnected = 1,
- CommunicationClosed = 2,
- CommunicationOpened = 3,
- ConnectedApiVersion = 51,
- // CHECKPOINT
- GlobalCheckpointStarted = 4,
- GlobalCheckpointCompleted = 5,
- LocalCheckpointStarted = 6,
- LocalCheckpointCompleted = 7,
- LCPStoppedInCalcKeepGci = 8,
- LCPFragmentCompleted = 9,
- // STARTUP
- NDBStartStarted = 10,
- NDBStartCompleted = 11,
- STTORRYRecieved = 12,
- StartPhaseCompleted = 13,
- CM_REGCONF = 14,
- CM_REGREF = 15,
- FIND_NEIGHBOURS = 16,
- NDBStopStarted = 17,
- NDBStopAborted = 18,
- StartREDOLog = 19,
- StartLog = 20,
- UNDORecordsExecuted = 21,
-
- // NODERESTART
- NR_CopyDict = 22,
- NR_CopyDistr = 23,
- NR_CopyFragsStarted = 24,
- NR_CopyFragDone = 25,
- NR_CopyFragsCompleted = 26,
-
- // NODEFAIL
- NodeFailCompleted = 27,
- NODE_FAILREP = 28,
- ArbitState = 29,
- ArbitResult = 30,
- GCP_TakeoverStarted = 31,
- GCP_TakeoverCompleted = 32,
- LCP_TakeoverStarted = 33,
- LCP_TakeoverCompleted = 34,
-
- // STATISTIC
- TransReportCounters = 35,
- OperationReportCounters = 36,
- TableCreated = 37,
- UndoLogBlocked = 38,
- JobStatistic = 39,
- SendBytesStatistic = 40,
- ReceiveBytesStatistic = 41,
- MemoryUsage = 50,
-
- // ERROR
- TransporterError = 42,
- TransporterWarning = 43,
- MissedHeartbeat = 44,
- DeadDueToHeartbeat = 45,
- WarningEvent = 46,
- // INFO
- SentHeartbeat = 47,
- CreateLogBytes = 48,
- InfoEvent = 49,
-
- //GREP
- GrepSubscriptionInfo = 52,
- GrepSubscriptionAlert = 53,
-
- //BACKUP
- BackupStarted = 54,
- BackupFailedToStart = 55,
- BackupCompleted = 56,
- BackupAborted = 57
- };
-
- void setEventType(EventType type);
- EventType getEventType() const;
+ void setEventType(Ndb_logevent_type type);
+ Ndb_logevent_type getEventType() const;
UintR eventType; // DATA 0
};
inline
void
-EventReport::setEventType(EventType type){
+EventReport::setEventType(Ndb_logevent_type type){
eventType = (UintR) type;
}
inline
-EventReport::EventType
+Ndb_logevent_type
EventReport::getEventType() const {
- return (EventType)eventType;
+ return (Ndb_logevent_type)eventType;
}
#endif
diff --git a/ndb/include/kernel/signaldata/ScanFrag.hpp b/ndb/include/kernel/signaldata/ScanFrag.hpp
index 41ea569c45d..e4b774f1416 100644
--- a/ndb/include/kernel/signaldata/ScanFrag.hpp
+++ b/ndb/include/kernel/signaldata/ScanFrag.hpp
@@ -56,6 +56,7 @@ public:
static Uint32 getKeyinfoFlag(const Uint32 & requestInfo);
static Uint32 getReadCommittedFlag(const Uint32 & requestInfo);
static Uint32 getRangeScanFlag(const Uint32 & requestInfo);
+ static Uint32 getDescendingFlag(const Uint32 & requestInfo);
static Uint32 getAttrLen(const Uint32 & requestInfo);
static Uint32 getScanPrio(const Uint32 & requestInfo);
@@ -64,6 +65,7 @@ public:
static void setKeyinfoFlag(Uint32 & requestInfo, Uint32 keyinfo);
static void setReadCommittedFlag(Uint32 & requestInfo, Uint32 readCommitted);
static void setRangeScanFlag(Uint32 & requestInfo, Uint32 rangeScan);
+ static void setDescendingFlag(Uint32 & requestInfo, Uint32 descending);
static void setAttrLen(Uint32 & requestInfo, Uint32 attrLen);
static void setScanPrio(Uint32& requestInfo, Uint32 prio);
};
@@ -197,11 +199,12 @@ public:
* k = Keyinfo - 1 Bit 8
* r = read committed - 1 Bit 9
* x = range scan - 1 Bit 6
+ * z = descending - 1 Bit 10
* p = Scan prio - 4 Bits (12-15) -> max 15
*
* 1111111111222222222233
* 01234567890123456789012345678901
- * lxhkr ppppaaaaaaaaaaaaaaaa
+ * lxhkrz ppppaaaaaaaaaaaaaaaa
*/
#define SF_LOCK_MODE_SHIFT (5)
#define SF_LOCK_MODE_MASK (1)
@@ -210,6 +213,7 @@ public:
#define SF_KEYINFO_SHIFT (8)
#define SF_READ_COMMITTED_SHIFT (9)
#define SF_RANGE_SCAN_SHIFT (6)
+#define SF_DESCENDING_SHIFT (10)
#define SF_ATTR_LEN_SHIFT (16)
#define SF_ATTR_LEN_MASK (65535)
@@ -243,6 +247,12 @@ ScanFragReq::getRangeScanFlag(const Uint32 & requestInfo){
inline
Uint32
+ScanFragReq::getDescendingFlag(const Uint32 & requestInfo){
+ return (requestInfo >> SF_DESCENDING_SHIFT) & 1;
+}
+
+inline
+Uint32
ScanFragReq::getReadCommittedFlag(const Uint32 & requestInfo){
return (requestInfo >> SF_READ_COMMITTED_SHIFT) & 1;
}
@@ -303,6 +313,13 @@ ScanFragReq::setRangeScanFlag(UintR & requestInfo, UintR val){
inline
void
+ScanFragReq::setDescendingFlag(UintR & requestInfo, UintR val){
+ ASSERT_BOOL(val, "ScanFragReq::setDescendingFlag");
+ requestInfo |= (val << SF_DESCENDING_SHIFT);
+}
+
+inline
+void
ScanFragReq::setAttrLen(UintR & requestInfo, UintR val){
ASSERT_MAX(val, SF_ATTR_LEN_MASK, "ScanFragReq::setAttrLen");
requestInfo |= (val << SF_ATTR_LEN_SHIFT);
diff --git a/ndb/include/kernel/signaldata/ScanTab.hpp b/ndb/include/kernel/signaldata/ScanTab.hpp
index 2029b16197e..894f973145c 100644
--- a/ndb/include/kernel/signaldata/ScanTab.hpp
+++ b/ndb/include/kernel/signaldata/ScanTab.hpp
@@ -33,8 +33,9 @@ class ScanTabReq {
/**
* Sender(s)
*/
- friend class NdbConnection;
- friend class NdbScanOperation;
+ friend class NdbTransaction;
+ friend class NdbScanOperation;
+ friend class NdbIndexScanOperation;
/**
* For printing
@@ -65,7 +66,12 @@ private:
UintR buddyConPtr; // DATA 8
UintR batch_byte_size; // DATA 9
UintR first_batch_size; // DATA 10
-
+
+ /**
+ * Optional
+ */
+ Uint32 distributionKey;
+
/**
* Get:ers for requestInfo
*/
@@ -74,8 +80,10 @@ private:
static Uint8 getHoldLockFlag(const UintR & requestInfo);
static Uint8 getReadCommittedFlag(const UintR & requestInfo);
static Uint8 getRangeScanFlag(const UintR & requestInfo);
+ static Uint8 getDescendingFlag(const UintR & requestInfo);
static Uint8 getKeyinfoFlag(const UintR & requestInfo);
static Uint16 getScanBatch(const UintR & requestInfo);
+ static Uint8 getDistributionKeyFlag(const UintR & requestInfo);
/**
* Set:ers for requestInfo
@@ -86,8 +94,10 @@ private:
static void setHoldLockFlag(UintR & requestInfo, Uint32 flag);
static void setReadCommittedFlag(UintR & requestInfo, Uint32 flag);
static void setRangeScanFlag(UintR & requestInfo, Uint32 flag);
+ static void setDescendingFlag(UintR & requestInfo, Uint32 flag);
static void setKeyinfoFlag(UintR & requestInfo, Uint32 flag);
static void setScanBatch(Uint32& requestInfo, Uint32 sz);
+ static void setDistributionKeyFlag(Uint32& requestInfo, Uint32 flag);
};
/**
@@ -98,12 +108,14 @@ private:
h = Hold lock mode - 1 Bit 10
c = Read Committed - 1 Bit 11
k = Keyinfo - 1 Bit 12
+ z = Descending (TUX) - 1 Bit 14
x = Range Scan (TUX) - 1 Bit 15
b = Scan batch - 10 Bit 16-25 (max 1023)
+ d = Distribution key flag
1111111111222222222233
01234567890123456789012345678901
- ppppppppl hck xbbbbbbbbbb
+ ppppppppl hck zxbbbbbbbbbb
*/
#define PARALLELL_SHIFT (0)
@@ -124,9 +136,14 @@ private:
#define RANGE_SCAN_SHIFT (15)
#define RANGE_SCAN_MASK (1)
+#define DESCENDING_SHIFT (14)
+#define DESCENDING_MASK (1)
+
#define SCAN_BATCH_SHIFT (16)
#define SCAN_BATCH_MASK (1023)
+#define SCAN_DISTR_KEY_SHIFT (26)
+
inline
Uint8
ScanTabReq::getParallelism(const UintR & requestInfo){
@@ -158,6 +175,12 @@ ScanTabReq::getRangeScanFlag(const UintR & requestInfo){
}
inline
+Uint8
+ScanTabReq::getDescendingFlag(const UintR & requestInfo){
+ return (Uint8)((requestInfo >> DESCENDING_SHIFT) & DESCENDING_MASK);
+}
+
+inline
Uint16
ScanTabReq::getScanBatch(const Uint32 & requestInfo){
return (Uint16)((requestInfo >> SCAN_BATCH_SHIFT) & SCAN_BATCH_MASK);
@@ -205,6 +228,13 @@ ScanTabReq::setRangeScanFlag(UintR & requestInfo, Uint32 flag){
}
inline
+void
+ScanTabReq::setDescendingFlag(UintR & requestInfo, Uint32 flag){
+ ASSERT_BOOL(flag, "ScanTabReq::setDescendingFlag");
+ requestInfo |= (flag << DESCENDING_SHIFT);
+}
+
+inline
void
ScanTabReq::setScanBatch(Uint32 & requestInfo, Uint32 flag){
ASSERT_MAX(flag, SCAN_BATCH_MASK, "ScanTabReq::setScanBatch");
@@ -225,6 +255,18 @@ ScanTabReq::setKeyinfoFlag(UintR & requestInfo, Uint32 flag){
requestInfo |= (flag << KEYINFO_SHIFT);
}
+inline
+Uint8
+ScanTabReq::getDistributionKeyFlag(const UintR & requestInfo){
+ return (Uint8)((requestInfo >> SCAN_DISTR_KEY_SHIFT) & 1);
+}
+
+inline
+void
+ScanTabReq::setDistributionKeyFlag(UintR & requestInfo, Uint32 flag){
+ ASSERT_BOOL(flag, "ScanTabReq::setKeyinfoFlag");
+ requestInfo |= (flag << SCAN_DISTR_KEY_SHIFT);
+}
/**
*
@@ -235,7 +277,7 @@ class ScanTabConf {
/**
* Reciver(s)
*/
- friend class NdbConnection; // Reciver
+ friend class NdbTransaction; // Reciver
/**
* Sender(s)
@@ -303,7 +345,7 @@ class ScanTabRef {
/**
* Reciver(s)
*/
- friend class NdbConnection; // Reciver
+ friend class NdbTransaction; // Reciver
/**
* Sender(s)
diff --git a/ndb/include/kernel/signaldata/SignalData.hpp b/ndb/include/kernel/signaldata/SignalData.hpp
index f9d3a6faa64..f825b0feb7b 100644
--- a/ndb/include/kernel/signaldata/SignalData.hpp
+++ b/ndb/include/kernel/signaldata/SignalData.hpp
@@ -18,8 +18,8 @@
#define SIGNAL_DATA_H
#include <ndb_global.h>
-#include <ndb_limits.h>
-#include <kernel_types.h>
+#include <kernel/ndb_limits.h>
+#include <kernel/kernel_types.h>
#include <BaseString.hpp>
#define ASSERT_BOOL(flag, message) assert(flag<=1)
@@ -177,9 +177,16 @@ GSN_PRINT_SIGNATURE(printFAIL_REP);
GSN_PRINT_SIGNATURE(printDISCONNECT_REP);
GSN_PRINT_SIGNATURE(printSUB_CREATE_REQ);
GSN_PRINT_SIGNATURE(printSUB_CREATE_CONF);
+GSN_PRINT_SIGNATURE(printSUB_CREATE_REF);
+GSN_PRINT_SIGNATURE(printSUB_REMOVE_REQ);
+GSN_PRINT_SIGNATURE(printSUB_REMOVE_CONF);
+GSN_PRINT_SIGNATURE(printSUB_REMOVE_REF);
GSN_PRINT_SIGNATURE(printSUB_START_REQ);
GSN_PRINT_SIGNATURE(printSUB_START_REF);
GSN_PRINT_SIGNATURE(printSUB_START_CONF);
+GSN_PRINT_SIGNATURE(printSUB_STOP_REQ);
+GSN_PRINT_SIGNATURE(printSUB_STOP_REF);
+GSN_PRINT_SIGNATURE(printSUB_STOP_CONF);
GSN_PRINT_SIGNATURE(printSUB_SYNC_REQ);
GSN_PRINT_SIGNATURE(printSUB_SYNC_REF);
GSN_PRINT_SIGNATURE(printSUB_SYNC_CONF);
diff --git a/ndb/include/kernel/signaldata/SumaImpl.hpp b/ndb/include/kernel/signaldata/SumaImpl.hpp
index 89ade067dcd..75fb65e1ad2 100644
--- a/ndb/include/kernel/signaldata/SumaImpl.hpp
+++ b/ndb/include/kernel/signaldata/SumaImpl.hpp
@@ -592,11 +592,11 @@ public:
Uint32 subscriptionId;
Uint32 subscriptionKey;
- Uint32 err;
union { // Haven't decide what to call it
Uint32 senderData;
Uint32 subscriberData;
};
+ Uint32 err;
};
class SumaStartMe {
diff --git a/ndb/include/kernel/signaldata/TcCommit.hpp b/ndb/include/kernel/signaldata/TcCommit.hpp
index b7f3fbbb361..9499b20ada3 100644
--- a/ndb/include/kernel/signaldata/TcCommit.hpp
+++ b/ndb/include/kernel/signaldata/TcCommit.hpp
@@ -33,7 +33,7 @@ class TcCommitConf {
* Reciver(s)
*/
friend class Ndb;
- friend class NdbConnection;
+ friend class NdbTransaction;
public:
STATIC_CONST( SignalLength = 3 );
@@ -60,7 +60,7 @@ class TcCommitRef {
/**
* Reciver(s)
*/
- friend class NdbConnection;
+ friend class NdbTransaction;
public:
STATIC_CONST( SignalLength = 4 );
diff --git a/ndb/include/kernel/signaldata/TcHbRep.hpp b/ndb/include/kernel/signaldata/TcHbRep.hpp
index 58ab015917a..7e701b510f9 100644
--- a/ndb/include/kernel/signaldata/TcHbRep.hpp
+++ b/ndb/include/kernel/signaldata/TcHbRep.hpp
@@ -36,7 +36,7 @@ class TcHbRep {
/**
* Sender(s)
*/
- friend class NdbConnection;
+ friend class NdbTransaction;
/**
* For printing
diff --git a/ndb/include/kernel/signaldata/TcIndx.hpp b/ndb/include/kernel/signaldata/TcIndx.hpp
index 764d4e9fcd7..c5e7d2489ba 100644
--- a/ndb/include/kernel/signaldata/TcIndx.hpp
+++ b/ndb/include/kernel/signaldata/TcIndx.hpp
@@ -18,379 +18,7 @@
#define TC_INDX_H
#include "SignalData.hpp"
-
-class TcIndxReq {
- /**
- * Reciver(s)
- */
- friend class Dbtc; // Reciver
-
- /**
- * Sender(s)
- */
- friend class NdbIndexOperation;
-
- /**
- * For printing
- */
- friend bool printTCINDXREQ(FILE *, const Uint32 *, Uint32, Uint16);
-
-public:
- /**
- * Length of signal
- */
- STATIC_CONST( StaticLength = 8 );
- STATIC_CONST( SignalLength = 25 );
- STATIC_CONST( MaxKeyInfo = 8 );
- STATIC_CONST( MaxAttrInfo = 5 );
-
-private:
-
- enum CommitType {
- CommitIfFailFree = 0,
- TryCommit = 1,
- CommitAsMuchAsPossible = 2
- };
-
- /**
- * DATA VARIABLES
- */
-//-------------------------------------------------------------
-// Unconditional part. First 8 words
-//-------------------------------------------------------------
- UintR apiConnectPtr; // DATA 0
- UintR senderData; // DATA 1
- UintR attrLen; // DATA 2 (including API Version)
- UintR indexId; // DATA 3
- UintR requestInfo; // DATA 4
- UintR indexSchemaVersion; // DATA 5
- UintR transId1; // DATA 6
- UintR transId2; // DATA 7
-//-------------------------------------------------------------
-// Conditional part. Those four words will be sent only if their
-// indicator is set.
-//-------------------------------------------------------------
- UintR scanInfo; // DATA 8
- UintR distrGroupHashValue; // DATA 9
- UintR distributionKeySize; // DATA 10
- UintR storedProcId; // DATA 11
-
-//-------------------------------------------------------------
-// Variable sized key and attrinfo part. Those will be placed to
-// pack the signal in an appropriate manner.
-//-------------------------------------------------------------
- UintR keyInfo[MaxKeyInfo]; // DATA 12 - 19
- UintR attrInfo[MaxAttrInfo]; // DATA 20 - 24
-
- static Uint8 getAPIVersion(const UintR & attrLen);
-
- /**
- * Get:ers for requestInfo
- */
- static Uint8 getCommitFlag(const UintR & requestInfo);
- static Uint8 getCommitType(const UintR & requestInfo);
- static Uint8 getStartFlag(const UintR & requestInfo);
- static Uint8 getSimpleFlag(const UintR & requestInfo);
- static Uint8 getDirtyFlag(const UintR & requestInfo);
- static Uint8 getInterpretedFlag(const UintR & requestInfo);
- static Uint8 getDistributionGroupFlag(const UintR & requestInfo);
- static Uint8 getDistributionGroupTypeFlag(const UintR & requestInfo);
- static Uint8 getDistributionKeyFlag(const UintR & requestInfo);
- static Uint8 getScanIndFlag(const UintR & requestInfo);
-
- static Uint8 getOperationType(const UintR & requestInfo);
-
- static Uint16 getIndexLength(const UintR & requestInfo);
- static Uint8 getAIInTcIndxReq(const UintR & requestInfo);
-
- /**
- * Get:ers for scanInfo
- */
-
- static void setAPIVersion(UintR & attrLen, Uint16 apiVersion);
-
- /**
- * Set:ers for requestInfo
- */
- static void clearRequestInfo(UintR & requestInfo);
- static void setCommitType(UintR & requestInfo, Uint32 type);
- static void setCommitFlag(UintR & requestInfo, Uint32 flag);
- static void setStartFlag(UintR & requestInfo, Uint32 flag);
- static void setSimpleFlag(UintR & requestInfo, Uint32 flag);
- static void setDirtyFlag(UintR & requestInfo, Uint32 flag);
- static void setInterpretedFlag(UintR & requestInfo, Uint32 flag);
- static void setDistributionGroupFlag(UintR & requestInfo, Uint32 flag);
- static void setDistributionGroupTypeFlag(UintR & requestInfo, Uint32 flag);
- static void setDistributionKeyFlag(UintR & requestInfo, Uint32 flag);
- static void setScanIndFlag(UintR & requestInfo, Uint32 flag);
-
- static void setOperationType(UintR & requestInfo, Uint32 type);
-
- static void setIndexLength(UintR & requestInfo, Uint32 len);
- static void setAIInTcIndxReq(UintR & requestInfo, Uint32 len);
-
- /**
- * Set:ers for scanInfo
- */
-
-};
-
-#define API_VER_NO_SHIFT (16)
-#define API_VER_NO_MASK (65535)
-
-/**
- * Request Info
- *
- a = Attr Info in TCINDXREQ - 3 Bits -> Max 7 (Bit 16-18)
- b = Distribution Key Ind - 1 Bit 2
- c = Commit Indicator - 1 Bit 4
- d = Dirty Indicator - 1 Bit 0
- e = Scan Indicator - 1 Bit 14
- g = Distribution Group Ind - 1 Bit 1
- i = Interpreted Indicator - 1 Bit 15
- k = Index lengt - 12 Bits -> Max 4095 (Bit 20 - 31)
- o = Operation Type - 3 Bits -> Max 7 (Bit 5-7)
- p = Simple Indicator - 1 Bit 8
- s = Start Indicator - 1 Bit 11
- t = Distribution GroupType - 1 Bit 3
- y = Commit Type - 2 Bit 12-13
- x = Last Op in execute - 1 Bit 19
-
- 1111111111222222222233
- 01234567890123456789012345678901
- dgbtcooop syyeiaaa-kkkkkkkkkkkk
-*/
-
-#define COMMIT_SHIFT (4)
-#define START_SHIFT (11)
-#define SIMPLE_SHIFT (8)
-#define DIRTY_SHIFT (0)
-#define INTERPRETED_SHIFT (15)
-#define DISTR_GROUP_SHIFT (1)
-#define DISTR_GROUP_TYPE_SHIFT (3)
-#define DISTR_KEY_SHIFT (2)
-#define SCAN_SHIFT (14)
-
-#define OPERATION_SHIFT (5)
-#define OPERATION_MASK (7)
-
-#define AINFO_SHIFT (16)
-#define AINFO_MASK (7)
-
-#define INDEX_LEN_SHIFT (20)
-#define INDEX_LEN_MASK (4095)
-
-#define COMMIT_TYPE_SHIFT (12)
-#define COMMIT_TYPE_MASK (3)
-
-#define LAST_OP_IN_EXEC_SHIFT (19)
-
-/**
- * Scan Info
- *
-
-
- 1111111111222222222233
- 01234567890123456789012345678901
-
-*/
-
-inline
-Uint8
-TcIndxReq::getCommitFlag(const UintR & requestInfo){
- return (Uint8)((requestInfo >> COMMIT_SHIFT) & 1);
-}
-
-inline
-Uint8
-TcIndxReq::getCommitType(const UintR & requestInfo){
- return (Uint8)((requestInfo >> COMMIT_TYPE_SHIFT) & COMMIT_TYPE_MASK);
-}
-
-inline
-Uint8
-TcIndxReq::getStartFlag(const UintR & requestInfo){
- return (Uint8)((requestInfo >> START_SHIFT) & 1);
-}
-
-inline
-Uint8
-TcIndxReq::getSimpleFlag(const UintR & requestInfo){
- return (Uint8)((requestInfo >> SIMPLE_SHIFT) & 1);
-}
-
-inline
-Uint8
-TcIndxReq::getDirtyFlag(const UintR & requestInfo){
- return (Uint8)((requestInfo >> DIRTY_SHIFT) & 1);
-}
-
-inline
-Uint8
-TcIndxReq::getInterpretedFlag(const UintR & requestInfo){
- return (Uint8)((requestInfo >> INTERPRETED_SHIFT) & 1);
-}
-
-inline
-Uint8
-TcIndxReq::getDistributionGroupFlag(const UintR & requestInfo){
- return (Uint8)((requestInfo >> DISTR_GROUP_SHIFT) & 1);
-}
-
-inline
-Uint8
-TcIndxReq::getDistributionGroupTypeFlag(const UintR & requestInfo){
- return (Uint8)((requestInfo >> DISTR_GROUP_TYPE_SHIFT) & 1);
-}
-
-inline
-Uint8
-TcIndxReq::getDistributionKeyFlag(const UintR & requestInfo){
- return (Uint8)((requestInfo >> DISTR_KEY_SHIFT) & 1);
-}
-
-inline
-Uint8
-TcIndxReq::getScanIndFlag(const UintR & requestInfo){
- return (Uint8)((requestInfo >> SCAN_SHIFT) & 1);
-}
-
-inline
-Uint8
-TcIndxReq::getOperationType(const UintR & requestInfo){
- return (Uint8)((requestInfo >> OPERATION_SHIFT) & OPERATION_MASK);
-}
-
-inline
-Uint16
-TcIndxReq::getIndexLength(const UintR & requestInfo){
- return (Uint16)((requestInfo >> INDEX_LEN_SHIFT) & INDEX_LEN_MASK);
-}
-
-inline
-Uint8
-TcIndxReq::getAIInTcIndxReq(const UintR & requestInfo){
- return (Uint8)((requestInfo >> AINFO_SHIFT) & AINFO_MASK);
-}
-
-inline
-void
-TcIndxReq::clearRequestInfo(UintR & requestInfo){
- requestInfo = 0;
-}
-
-inline
-void
-TcIndxReq::setCommitType(UintR & requestInfo, Uint32 type){
- ASSERT_MAX(type, COMMIT_TYPE_MASK, "TcIndxReq::setCommitType");
- requestInfo |= (type << COMMIT_TYPE_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setCommitFlag(UintR & requestInfo, Uint32 flag){
- ASSERT_BOOL(flag, "TcIndxReq::setCommitFlag");
- requestInfo &= ~(1 << COMMIT_SHIFT);
- requestInfo |= (flag << COMMIT_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setStartFlag(UintR & requestInfo, Uint32 flag){
- ASSERT_BOOL(flag, "TcIndxReq::setStartFlag");
- requestInfo &= ~(1 << START_SHIFT);
- requestInfo |= (flag << START_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setSimpleFlag(UintR & requestInfo, Uint32 flag){
- ASSERT_BOOL(flag, "TcIndxReq::setSimpleFlag");
- requestInfo &= ~(1 << SIMPLE_SHIFT);
- requestInfo |= (flag << SIMPLE_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setDirtyFlag(UintR & requestInfo, Uint32 flag){
- ASSERT_BOOL(flag, "TcIndxReq::setDirtyFlag");
- requestInfo &= ~(1 << DIRTY_SHIFT);
- requestInfo |= (flag << DIRTY_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setInterpretedFlag(UintR & requestInfo, Uint32 flag){
- ASSERT_BOOL(flag, "TcIndxReq::setInterpretedFlag");
- requestInfo &= ~(1 << INTERPRETED_SHIFT);
- requestInfo |= (flag << INTERPRETED_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setDistributionGroupTypeFlag(UintR & requestInfo, Uint32 flag){
- ASSERT_BOOL(flag, "TcIndxReq::setDistributionGroupTypeFlag");
- requestInfo &= ~(1 << DISTR_GROUP_TYPE_SHIFT);
- requestInfo |= (flag << DISTR_GROUP_TYPE_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setDistributionGroupFlag(UintR & requestInfo, Uint32 flag){
- ASSERT_BOOL(flag, "TcIndxReq::setDistributionGroupFlag");
- requestInfo &= ~(1 << DISTR_GROUP_SHIFT);
- requestInfo |= (flag << DISTR_GROUP_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setDistributionKeyFlag(UintR & requestInfo, Uint32 flag){
- ASSERT_BOOL(flag, "TcIndxReq::setDistributionKeyFlag");
- requestInfo &= ~(1 << DISTR_KEY_SHIFT);
- requestInfo |= (flag << DISTR_KEY_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setScanIndFlag(UintR & requestInfo, Uint32 flag){
- ASSERT_BOOL(flag, "TcIndxReq::setScanIndFlag");
- requestInfo &= ~(1 << SCAN_SHIFT);
- requestInfo |= (flag << SCAN_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setOperationType(UintR & requestInfo, Uint32 type){
- ASSERT_MAX(type, OPERATION_MASK, "TcIndxReq::setOperationType");
- requestInfo |= (type << OPERATION_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setIndexLength(UintR & requestInfo, Uint32 len){
- ASSERT_MAX(len, INDEX_LEN_MASK, "TcIndxReq::setKeyLength");
- requestInfo |= (len << INDEX_LEN_SHIFT);
-}
-
-inline
-void
-TcIndxReq::setAIInTcIndxReq(UintR & requestInfo, Uint32 len){
- ASSERT_MAX(len, AINFO_MASK, "TcIndxReq::setAIInTcIndxReq");
- requestInfo |= (len << AINFO_SHIFT);
-}
-
-inline
-Uint8
-TcIndxReq::getAPIVersion(const UintR & anAttrLen){
- return (Uint16)((anAttrLen >> API_VER_NO_SHIFT) & API_VER_NO_MASK);
-}
-
-inline
-void
-TcIndxReq::setAPIVersion(UintR & anAttrLen, Uint16 apiVersion){
-// ASSERT_MAX(apiVersion, API_VER_NO_MASK, "TcIndxReq::setAPIVersion");
- anAttrLen |= (apiVersion << API_VER_NO_SHIFT);
-}
+#include "TcKeyReq.hpp"
class TcIndxConf {
@@ -398,7 +26,7 @@ class TcIndxConf {
* Reciver(s)
*/
friend class Ndb;
- friend class NdbConnection;
+ friend class NdbTransaction;
/**
* Sender(s)
@@ -495,34 +123,4 @@ TcIndxConf::setMarkerFlag(Uint32 & confInfo, Uint32 flag){
confInfo |= (flag << 17);
}
-class TcIndxRef {
-
- /**
- * Reciver(s)
- */
- friend class NdbIndexOperation;
-
- /**
- * Sender(s)
- */
- friend class Dbtc;
-
- /**
- * For printing
- */
- friend bool printTCINDXREF(FILE *, const Uint32 *, Uint32, Uint16);
-
-public:
- /**
- * Length of signal
- */
-public:
- STATIC_CONST( SignalLength = 4 );
-
-private:
- Uint32 connectPtr;
- Uint32 transId[2];
- Uint32 errorCode;
-};
-
#endif
diff --git a/ndb/include/kernel/signaldata/TcKeyConf.hpp b/ndb/include/kernel/signaldata/TcKeyConf.hpp
index 277872b990b..c23e94951dc 100644
--- a/ndb/include/kernel/signaldata/TcKeyConf.hpp
+++ b/ndb/include/kernel/signaldata/TcKeyConf.hpp
@@ -27,7 +27,7 @@ class TcKeyConf {
* Reciver(s)
*/
friend class Ndb;
- friend class NdbConnection;
+ friend class NdbTransaction;
friend class Ndbcntr;
friend class DbUtil;
diff --git a/ndb/include/kernel/signaldata/TcKeyFailConf.hpp b/ndb/include/kernel/signaldata/TcKeyFailConf.hpp
index d8207b63262..7c0a766df40 100644
--- a/ndb/include/kernel/signaldata/TcKeyFailConf.hpp
+++ b/ndb/include/kernel/signaldata/TcKeyFailConf.hpp
@@ -33,7 +33,7 @@ class TcKeyFailConf {
* Reciver(s)
*/
friend class Ndb;
- friend class NdbConnection;
+ friend class NdbTransaction;
public:
STATIC_CONST( SignalLength = 3 );
diff --git a/ndb/include/kernel/signaldata/TcKeyReq.hpp b/ndb/include/kernel/signaldata/TcKeyReq.hpp
index 9e42f2a70d5..d7c11ca773c 100644
--- a/ndb/include/kernel/signaldata/TcKeyReq.hpp
+++ b/ndb/include/kernel/signaldata/TcKeyReq.hpp
@@ -142,7 +142,7 @@ private:
* Get:ers for scanInfo
*/
static Uint8 getTakeOverScanFlag(const UintR & scanInfo);
- static Uint16 getTakeOverScanNode(const UintR & scanInfo);
+ static Uint16 getTakeOverScanFragment(const UintR & scanInfo);
static Uint32 getTakeOverScanInfo(const UintR & scanInfo);
@@ -171,7 +171,7 @@ private:
* Set:ers for scanInfo
*/
static void setTakeOverScanFlag(UintR & scanInfo, Uint8 flag);
- static void setTakeOverScanNode(UintR & scanInfo, Uint16 node);
+ static void setTakeOverScanFragment(UintR & scanInfo, Uint16 fragment);
static void setTakeOverScanInfo(UintR & scanInfo, Uint32 aScanInfo);
};
@@ -238,8 +238,8 @@ private:
#define TAKE_OVER_SHIFT (0)
-#define TAKE_OVER_NODE_SHIFT (20)
-#define TAKE_OVER_NODE_MASK (4095)
+#define TAKE_OVER_FRAG_SHIFT (20)
+#define TAKE_OVER_FRAG_MASK (4095)
#define SCAN_INFO_SHIFT (1)
#define SCAN_INFO_MASK (262143)
@@ -485,8 +485,8 @@ TcKeyReq::getTakeOverScanFlag(const UintR & scanInfo){
inline
Uint16
-TcKeyReq::getTakeOverScanNode(const UintR & scanInfo){
- return (Uint16)((scanInfo >> TAKE_OVER_NODE_SHIFT) & TAKE_OVER_NODE_MASK);
+TcKeyReq::getTakeOverScanFragment(const UintR & scanInfo){
+ return (Uint16)((scanInfo >> TAKE_OVER_FRAG_SHIFT) & TAKE_OVER_FRAG_MASK);
}
inline
@@ -505,9 +505,9 @@ TcKeyReq::setTakeOverScanFlag(UintR & scanInfo, Uint8 flag){
inline
void
-TcKeyReq::setTakeOverScanNode(UintR & scanInfo, Uint16 node){
+TcKeyReq::setTakeOverScanFragment(UintR & scanInfo, Uint16 node){
// ASSERT_MAX(node, TAKE_OVER_NODE_MASK, "TcKeyReq::setTakeOverScanNode");
- scanInfo |= (node << TAKE_OVER_NODE_SHIFT);
+ scanInfo |= (node << TAKE_OVER_FRAG_SHIFT);
}
inline
diff --git a/ndb/include/kernel/signaldata/TcRollbackRep.hpp b/ndb/include/kernel/signaldata/TcRollbackRep.hpp
index b00731a04a6..febbd4f86b1 100644
--- a/ndb/include/kernel/signaldata/TcRollbackRep.hpp
+++ b/ndb/include/kernel/signaldata/TcRollbackRep.hpp
@@ -23,7 +23,7 @@ class TcRollbackRep {
/**
* Sender(s)
*/
- friend class NdbConnection;
+ friend class NdbTransaction;
friend class DbUtil;
/**
diff --git a/ndb/include/kernel/signaldata/TransIdAI.hpp b/ndb/include/kernel/signaldata/TransIdAI.hpp
index 4df7bf2a126..5beaf6eba4b 100755
--- a/ndb/include/kernel/signaldata/TransIdAI.hpp
+++ b/ndb/include/kernel/signaldata/TransIdAI.hpp
@@ -28,7 +28,7 @@ class TransIdAI {
/**
* Receiver(s)
*/
- friend class NdbConnection;
+ friend class NdbTransaction;
friend class Dbtc;
friend class Dbutil;
friend class Dblqh;
diff --git a/ndb/include/kernel/signaldata/TupFrag.hpp b/ndb/include/kernel/signaldata/TupFrag.hpp
index c132b19c50a..8acb3d28bd6 100644
--- a/ndb/include/kernel/signaldata/TupFrag.hpp
+++ b/ndb/include/kernel/signaldata/TupFrag.hpp
@@ -104,9 +104,9 @@ public:
STATIC_CONST( SignalLength = 2 );
enum ErrorCode {
NoError = 0,
- InvalidRequest = 800,
- NoFreeFragment = 604,
- NoFreeAttributes = 827
+ InvalidRequest = 903,
+ NoFreeFragment = 904,
+ NoFreeAttributes = 905
};
private:
Uint32 userPtr;
@@ -145,7 +145,8 @@ public:
STATIC_CONST( SignalLength = 2 );
enum ErrorCode {
NoError = 0,
- InvalidCharset = 743
+ InvalidCharset = 743,
+ TooManyBitsUsed = 831
};
private:
Uint32 userPtr;
@@ -185,9 +186,9 @@ public:
STATIC_CONST( SignalLength = 2 );
enum ErrorCode {
NoError = 0,
- InvalidAttributeType = 742,
- InvalidCharset = 743,
- InvalidNodeSize = 832
+ InvalidAttributeType = 906,
+ InvalidCharset = 907,
+ InvalidNodeSize = 908
};
private:
Uint32 userPtr;
diff --git a/ndb/include/kernel/signaldata/TuxBound.hpp b/ndb/include/kernel/signaldata/TuxBound.hpp
index 87ce3c3c098..7e12897407b 100644
--- a/ndb/include/kernel/signaldata/TuxBound.hpp
+++ b/ndb/include/kernel/signaldata/TuxBound.hpp
@@ -34,7 +34,9 @@ public:
enum ErrorCode {
InvalidAttrInfo = 4110,
InvalidBounds = 4259,
- OutOfBuffers = 873
+ OutOfBuffers = 873,
+ InvalidCharFormat = 744,
+ TooMuchAttrInfo = 823
};
STATIC_CONST( SignalLength = 3 );
private:
@@ -50,6 +52,8 @@ private:
* Number of words of bound info included after fixed signal data.
*/
Uint32 boundAiLength;
+
+ Uint32 data[1];
};
#endif
diff --git a/ndb/include/kernel/trigger_definitions.h b/ndb/include/kernel/trigger_definitions.h
index 7ce74877de4..11410654a15 100644
--- a/ndb/include/kernel/trigger_definitions.h
+++ b/ndb/include/kernel/trigger_definitions.h
@@ -56,6 +56,7 @@ struct TriggerActionTime {
};
struct TriggerEvent {
+ /** TableEvent must match 1 << TriggerEvent */
enum Value {
TE_INSERT = 0,
TE_DELETE = 1,
diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h
index fa0774afa06..dca88e4950e 100644
--- a/ndb/include/mgmapi/mgmapi.h
+++ b/ndb/include/mgmapi/mgmapi.h
@@ -18,31 +18,121 @@
#define MGMAPI_H
/**
- * @mainpage NDB Cluster Management API
+ * @mainpage MySQL Cluster Management API
*
- * The NDB Cluster Management API (MGM API) is a C API
- * that is used to:
- * - Start/stop database nodes (DB nodes)
- * - Start/stop NDB Cluster backups
- * - Control the NDB Cluster log
- * - Other administrative tasks
+ * The MySQL Cluster Management API (MGM API) is a C language API
+ * that is used for:
+ * - Starting and stopping database nodes (ndbd processes)
+ * - Starting and stopping Cluster backups
+ * - Controlling the NDB Cluster log
+ * - Performing other administrative tasks
*
- * @section General Concepts
+ * @section secMgmApiGeneral General Concepts
*
- * Each MGM API function needs a management server handle
- * (of type Mgm_C_Api::NdbMgmHandle).
- * This handle is initally is created by calling the
- * function ndb_mgm_create_handle().
+ * Each MGM API function needs a management server handle
+ * of type @ref NdbMgmHandle.
+ * This handle is created by calling the function
+ * function ndb_mgm_create_handle() and freed by calling
+ * ndb_mgm_destroy_handle().
*
- * A function can return:
- * -# An integer value.
- * If it returns -1 then this indicates an error, and then
- * -# A pointer value. If it returns NULL then check the latest error.
- * If it didn't return NULL, then a "something" is returned.
- * This "something" has to be free:ed by the user of the MGM API.
+ * A function can return any of the following:
+ * -# An integer value, with
+ * a value of <b>-1</b> indicating an error.
+ * -# A non-constant pointer value. A <var>NULL</var> value indicates an error;
+ * otherwise, the return value must be freed
+ * by the programmer
+ * -# A constant pointer value, with a <var>NULL</var> value indicating an error.
+ * The returned value should <em>not</em> be freed.
*
- * If there are an error, then the get latest error functions
- * can be used to check what the error was.
+ * Error conditions can be identified by using the appropriate
+ * error-reporting functions ndb_mgm_get_latest_error() and
+ * @ref ndb_mgm_error.
+ *
+ * Here is an example using the MGM API (without error handling for brevity's sake).
+ * @code
+ * NdbMgmHandle handle= ndb_mgm_create_handle();
+ * ndb_mgm_connect(handle,0,0,0);
+ * struct ndb_mgm_cluster_state *state= ndb_mgm_get_status(handle);
+ * for(int i=0; i < state->no_of_nodes; i++)
+ * {
+ * struct ndb_mgm_node_state *node_state= &state->node_states[i];
+ * printf("node with ID=%d ", node_state->node_id);
+ * if(node_state->version != 0)
+ * printf("connected\n");
+ * else
+ * printf("not connected\n");
+ * }
+ * free((void*)state);
+ * ndb_mgm_destroy_handle(&handle);
+ * @endcode
+ *
+ * @section secLogEvents Log Events
+ *
+ * The database nodes and management server(s) regularly and on specific
+ * occations report on various log events that occurs in the cluster. These
+ * log events are written to the cluster log. Optionally a mgmapi client
+ * may listen to these events by using the method ndb_mgm_listen_event().
+ * Each log event belongs to a category, @ref ndb_mgm_event_category, and
+ * has a severity, @ref ndb_mgm_event_severity, associated with it. Each
+ * log event also has a level (0-15) associated with it.
+ *
+ * Which log events that come out is controlled with ndb_mgm_listen_event(),
+ * ndb_mgm_set_clusterlog_loglevel(), and
+ * ndb_mgm_set_clusterlog_severity_filter().
+ *
+ * Below is an example of how to listen to events related to backup.
+ *
+ * @code
+ * int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0 };
+ * int fd = ndb_mgm_listen_event(handle, filter);
+ * @endcode
+ *
+ *
+ * @section secSLogEvents Structured Log Events
+ *
+ * The following steps are involved:
+ * - Create a NdbEventLogHandle using ndb_mgm_create_logevent_handle()
+ * - Wait and store log events using ndb_logevent_get_next()
+ * - The log event data is available in the struct ndb_logevent. The
+ * data which is specific to a particular event is stored in a union
+ * between structs so use ndb_logevent::type to decide which struct
+ * is valid.
+ *
+ * Sample code for listening to Backup related events. The availaable log
+ * events are listed in @ref ndb_logevent.h
+ *
+ * @code
+ * int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0 };
+ * NdbEventLogHandle le_handle= ndb_mgm_create_logevent_handle(handle, filter);
+ * struct ndb_logevent le;
+ * int r= ndb_logevent_get_next(le_handle,&le,0);
+ * if (r < 0) error
+ * else if (r == 0) no event
+ *
+ * switch (le.type)
+ * {
+ * case NDB_LE_BackupStarted:
+ * ... le.BackupStarted.starting_node;
+ * ... le.BackupStarted.backup_id;
+ * break;
+ * case NDB_LE_BackupFailedToStart:
+ * ... le.BackupFailedToStart.error;
+ * break;
+ * case NDB_LE_BackupCompleted:
+ * ... le.BackupCompleted.stop_gci;
+ * break;
+ * case NDB_LE_BackupAborted:
+ * ... le.BackupStarted.backup_id;
+ * break;
+ * default:
+ * break;
+ * }
+ * @endcode
+ */
+
+/*
+ * @page ndb_logevent.h ndb_logevent.h
+ * @include ndb_logevent.h
*/
/** @addtogroup MGM_C_API
@@ -50,6 +140,7 @@
*/
#include <ndb_types.h>
+#include "ndb_logevent.h"
#include "mgmapi_config_parameters.h"
#ifdef __cplusplus
@@ -65,82 +156,116 @@ extern "C" {
* NDB Cluster node types
*/
enum ndb_mgm_node_type {
- NDB_MGM_NODE_TYPE_UNKNOWN = -1, /*< Node type not known*/
- NDB_MGM_NODE_TYPE_API = NODE_TYPE_API,/*< An application node (API)*/
- NDB_MGM_NODE_TYPE_NDB = NODE_TYPE_DB, /*< A database node (DB)*/
- NDB_MGM_NODE_TYPE_MGM = NODE_TYPE_MGM,/*< A mgmt server node (MGM)*/
- NDB_MGM_NODE_TYPE_REP = NODE_TYPE_REP,/*< A replication node */
-
- NDB_MGM_NODE_TYPE_MIN = 0, /*< Min valid value*/
- NDB_MGM_NODE_TYPE_MAX = 3 /*< Max valid value*/
+ NDB_MGM_NODE_TYPE_UNKNOWN = -1 /** Node type not known*/
+ ,NDB_MGM_NODE_TYPE_API /** An application (NdbApi) node */
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ = NODE_TYPE_API
+#endif
+ ,NDB_MGM_NODE_TYPE_NDB /** A database node */
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ = NODE_TYPE_DB
+#endif
+ ,NDB_MGM_NODE_TYPE_MGM /** A management server node */
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ = NODE_TYPE_MGM
+#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ ,NDB_MGM_NODE_TYPE_REP = NODE_TYPE_REP /** A replication node */
+ ,NDB_MGM_NODE_TYPE_MIN = 0 /** Min valid value*/
+ ,NDB_MGM_NODE_TYPE_MAX = 3 /** Max valid value*/
+#endif
};
/**
* Database node status
*/
enum ndb_mgm_node_status {
- NDB_MGM_NODE_STATUS_UNKNOWN = 0, /*< Node status not known*/
- NDB_MGM_NODE_STATUS_NO_CONTACT = 1, /*< No contact with node*/
- NDB_MGM_NODE_STATUS_NOT_STARTED = 2, /*< Has not run starting protocol*/
- NDB_MGM_NODE_STATUS_STARTING = 3, /*< Is running starting protocol*/
- NDB_MGM_NODE_STATUS_STARTED = 4, /*< Running*/
- NDB_MGM_NODE_STATUS_SHUTTING_DOWN = 5, /*< Is shutting down*/
- NDB_MGM_NODE_STATUS_RESTARTING = 6, /*< Is restarting*/
- NDB_MGM_NODE_STATUS_SINGLEUSER = 7, /*< Maintenance mode*/
- NDB_MGM_NODE_STATUS_RESUME = 8, /*< Resume mode*/
-
- NDB_MGM_NODE_STATUS_MIN = 0, /*< Min valid value*/
- NDB_MGM_NODE_STATUS_MAX = 6 /*< Max valid value*/
+ /** Node status not known*/
+ NDB_MGM_NODE_STATUS_UNKNOWN = 0,
+ /** No contact with node*/
+ NDB_MGM_NODE_STATUS_NO_CONTACT = 1,
+ /** Has not run starting protocol*/
+ NDB_MGM_NODE_STATUS_NOT_STARTED = 2,
+ /** Is running starting protocol*/
+ NDB_MGM_NODE_STATUS_STARTING = 3,
+ /** Running*/
+ NDB_MGM_NODE_STATUS_STARTED = 4,
+ /** Is shutting down*/
+ NDB_MGM_NODE_STATUS_SHUTTING_DOWN = 5,
+ /** Is restarting*/
+ NDB_MGM_NODE_STATUS_RESTARTING = 6,
+ /** Maintenance mode*/
+ NDB_MGM_NODE_STATUS_SINGLEUSER = 7,
+ /** Resume mode*/
+ NDB_MGM_NODE_STATUS_RESUME = 8,
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ /** Min valid value*/
+ NDB_MGM_NODE_STATUS_MIN = 0,
+ /** Max valid value*/
+ NDB_MGM_NODE_STATUS_MAX = 8
+#endif
};
/**
* Error codes
*/
enum ndb_mgm_error {
+ /** Not an error */
NDB_MGM_NO_ERROR = 0,
/* Request for service errors */
+ /** Supplied connectstring is illegal */
NDB_MGM_ILLEGAL_CONNECT_STRING = 1001,
- NDB_MGM_ILLEGAL_PORT_NUMBER = 1002,
- NDB_MGM_ILLEGAL_SOCKET = 1003,
- NDB_MGM_ILLEGAL_IP_ADDRESS = 1004,
+ /** Supplied NdbMgmHandle is illegal */
NDB_MGM_ILLEGAL_SERVER_HANDLE = 1005,
+ /** Illegal reply from server */
NDB_MGM_ILLEGAL_SERVER_REPLY = 1006,
+ /** Illegal number of nodes */
NDB_MGM_ILLEGAL_NUMBER_OF_NODES = 1007,
+ /** Illegal node status */
NDB_MGM_ILLEGAL_NODE_STATUS = 1008,
+ /** Memory allocation error */
NDB_MGM_OUT_OF_MEMORY = 1009,
+ /** Management server not connected */
NDB_MGM_SERVER_NOT_CONNECTED = 1010,
+ /** Could not connect to socker */
NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET = 1011,
/* Service errors - Start/Stop Node or System */
+ /** Start failed */
NDB_MGM_START_FAILED = 2001,
+ /** Stop failed */
NDB_MGM_STOP_FAILED = 2002,
+ /** Restart failed */
NDB_MGM_RESTART_FAILED = 2003,
/* Service errors - Backup */
+ /** Unable to start backup */
NDB_MGM_COULD_NOT_START_BACKUP = 3001,
+ /** Unable to abort backup */
NDB_MGM_COULD_NOT_ABORT_BACKUP = 3002,
/* Service errors - Single User Mode */
+ /** Unable to enter single user mode */
NDB_MGM_COULD_NOT_ENTER_SINGLE_USER_MODE = 4001,
+ /** Unable to exit single user mode */
NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE = 4002,
/* Usage errors */
+ /** Usage error */
NDB_MGM_USAGE_ERROR = 5001
};
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
struct Ndb_Mgm_Error_Msg {
enum ndb_mgm_error code;
- const char * msg;
+ const char * msg;
};
-
const struct Ndb_Mgm_Error_Msg ndb_mgm_error_msgs[] = {
{ NDB_MGM_NO_ERROR, "No error" },
+ /* Request for service errors */
{ NDB_MGM_ILLEGAL_CONNECT_STRING, "Illegal connect string" },
- { NDB_MGM_ILLEGAL_PORT_NUMBER, "Illegal port number" },
- { NDB_MGM_ILLEGAL_SOCKET, "Illegal socket" },
- { NDB_MGM_ILLEGAL_IP_ADDRESS, "Illegal IP address" },
{ NDB_MGM_ILLEGAL_SERVER_HANDLE, "Illegal server handle" },
{ NDB_MGM_ILLEGAL_SERVER_REPLY, "Illegal reply from server" },
{ NDB_MGM_ILLEGAL_NUMBER_OF_NODES, "Illegal number of nodes" },
@@ -157,77 +282,102 @@ extern "C" {
/* Service errors - Backup */
{ NDB_MGM_COULD_NOT_START_BACKUP, "Could not start backup" },
{ NDB_MGM_COULD_NOT_ABORT_BACKUP, "Could not abort backup" },
-
+
/* Service errors - Single User Mode */
- { NDB_MGM_COULD_NOT_ENTER_SINGLE_USER_MODE,
+ { NDB_MGM_COULD_NOT_ENTER_SINGLE_USER_MODE,
"Could not enter single user mode" },
- { NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE,
+ { NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE,
"Could not exit single user mode" },
/* Usage errors */
{ NDB_MGM_USAGE_ERROR,
"Usage error" }
};
-
- const int ndb_mgm_noOfErrorMsgs =
+ const int ndb_mgm_noOfErrorMsgs =
sizeof(ndb_mgm_error_msgs)/sizeof(struct Ndb_Mgm_Error_Msg);
+#endif
/**
- * Structure returned by ndb_mgm_get_status
+ * Status of a node in the cluster.
+ *
+ * Sub-structure in enum ndb_mgm_cluster_state
+ * returned by ndb_mgm_get_status().
+ *
+ * @note <var>node_status</var>, <var>start_phase</var>,
+ * <var>dynamic_id</var>
+ * and <var>node_group</var> are relevant only for database nodes,
+ * i.e. <var>node_type</var> == @ref NDB_MGM_NODE_TYPE_NDB.
*/
struct ndb_mgm_node_state {
- int node_id; /*< NDB Cluster node id*/
- enum ndb_mgm_node_type node_type; /*< Type of NDB Cluster node*/
- enum ndb_mgm_node_status node_status; /*< State of node*/
- int start_phase; /*< Start phase.
- *< @note Start phase is only
- *< valid if
- *< node_type is
- *< NDB_MGM_NODE_TYPE_NDB and
- *< node_status is
- *< NDB_MGM_NODE_STATUS_STARTING
- */
- int dynamic_id; /*< Id for heartbeats and
- *< master take-over
- *< (only valid for DB nodes)
- */
- int node_group; /*< Node group of node
- *< (only valid for DB nodes)*/
- int version; /*< Internal version number*/
- int connect_count; /*< No of times node has connected
- *< or disconnected to the mgm srv
- */
- char connect_address[sizeof("000.000.000.000")+1];
+ /** NDB Cluster node ID*/
+ int node_id;
+ /** Type of NDB Cluster node*/
+ enum ndb_mgm_node_type node_type;
+ /** State of node*/
+ enum ndb_mgm_node_status node_status;
+ /** Start phase.
+ *
+ * @note Start phase is only valid if the <var>node_type</var> is
+ * NDB_MGM_NODE_TYPE_NDB and the <var>node_status</var> is
+ * NDB_MGM_NODE_STATUS_STARTING
+ */
+ int start_phase;
+ /** ID for heartbeats and master take-over (only valid for DB nodes)
+ */
+ int dynamic_id;
+ /** Node group of node (only valid for DB nodes)*/
+ int node_group;
+ /** Internal version number*/
+ int version;
+ /** Number of times node has connected or disconnected to the
+ * management server
+ */
+ int connect_count;
+ /** IP address of node when it connected to the management server.
+ * @note This value will be empty if the management server has restarted
+ * since the node last connected.
+ */
+ char connect_address[
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ sizeof("000.000.000.000")+1
+#endif
+ ];
};
/**
- * Cluster status
+ * State of all nodes in the cluster; returned from
+ * ndb_mgm_get_status()
*/
struct ndb_mgm_cluster_state {
- int no_of_nodes; /*< No of entries in the
- *< node_states array
- */
- struct ndb_mgm_node_state /*< An array with node_states*/
- node_states[1];
- const char *hostname;
+ /** Number of entries in the node_states array */
+ int no_of_nodes;
+ /** An array with node_states*/
+ struct ndb_mgm_node_state node_states[
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ 1
+#endif
+ ];
};
/**
- * Default reply from the server
+ * Default reply from the server (reserved for future use)
*/
struct ndb_mgm_reply {
- int return_code; /*< 0 if successful,
- *< otherwise error code.
- */
- char message[256]; /*< Error or reply message.*/
+ /** 0 if successful, otherwise error code. */
+ int return_code;
+ /** Error or reply message.*/
+ char message[256];
};
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Default information types
*/
enum ndb_mgm_info {
- NDB_MGM_INFO_CLUSTER, /*< ?*/
- NDB_MGM_INFO_CLUSTERLOG /*< Cluster log*/
+ /** ?*/
+ NDB_MGM_INFO_CLUSTER,
+ /** Cluster log*/
+ NDB_MGM_INFO_CLUSTERLOG
};
/**
@@ -235,86 +385,26 @@ extern "C" {
* (Used only in the development of NDB Cluster.)
*/
enum ndb_mgm_signal_log_mode {
- NDB_MGM_SIGNAL_LOG_MODE_IN, /*< Log receiving signals */
- NDB_MGM_SIGNAL_LOG_MODE_OUT, /*< Log sending signals*/
- NDB_MGM_SIGNAL_LOG_MODE_INOUT, /*< Log both sending/receiving*/
- NDB_MGM_SIGNAL_LOG_MODE_OFF /*< Log off*/
+ /** Log receiving signals */
+ NDB_MGM_SIGNAL_LOG_MODE_IN,
+ /** Log sending signals*/
+ NDB_MGM_SIGNAL_LOG_MODE_OUT,
+ /** Log both sending/receiving*/
+ NDB_MGM_SIGNAL_LOG_MODE_INOUT,
+ /** Log off*/
+ NDB_MGM_SIGNAL_LOG_MODE_OFF
};
+#endif
- /**
- * Log severities (used to filter the cluster log)
- */
- enum ndb_mgm_clusterlog_level {
- NDB_MGM_ILLEGAL_CLUSTERLOG_LEVEL = -1,
- /* must range from 0 and up, indexes into an array */
- NDB_MGM_CLUSTERLOG_ON = 0, /*< Cluster log on*/
- NDB_MGM_CLUSTERLOG_DEBUG = 1, /*< Used in NDB Cluster
- *< developement
- */
- NDB_MGM_CLUSTERLOG_INFO = 2, /*< Informational messages*/
- NDB_MGM_CLUSTERLOG_WARNING = 3, /*< Conditions that are not
- *< error condition, but
- *< might require handling
- */
- NDB_MGM_CLUSTERLOG_ERROR = 4, /*< Conditions that should be
- *< corrected
- */
- NDB_MGM_CLUSTERLOG_CRITICAL = 5, /*< Critical conditions, like
- *< device errors or out of
- *< resources
- */
- NDB_MGM_CLUSTERLOG_ALERT = 6, /*< A condition that should be
- *< corrected immediately,
- *< such as a corrupted system
- */
- /* must be next number, works as bound in loop */
- NDB_MGM_CLUSTERLOG_ALL = 7 /*< All severities */
- };
-
- /**
- * Log categories
- */
- enum ndb_mgm_event_category {
- /**
- * Invalid
- */
- NDB_MGM_ILLEGAL_EVENT_CATEGORY = -1,
- /**
- * Events during all kinds of startups
- */
- NDB_MGM_EVENT_CATEGORY_STARTUP = CFG_LOGLEVEL_STARTUP,
-
- /**
- * Events during shutdown
- */
- NDB_MGM_EVENT_CATEGORY_SHUTDOWN = CFG_LOGLEVEL_SHUTDOWN,
-
- /**
- * Transaction statistics (Job level, TCP/IP speed)
- */
- NDB_MGM_EVENT_CATEGORY_STATISTIC = CFG_LOGLEVEL_STATISTICS,
- NDB_MGM_EVENT_CATEGORY_CHECKPOINT = CFG_LOGLEVEL_CHECKPOINT,
- NDB_MGM_EVENT_CATEGORY_NODE_RESTART = CFG_LOGLEVEL_NODERESTART,
- NDB_MGM_EVENT_CATEGORY_CONNECTION = CFG_LOGLEVEL_CONNECTION,
- NDB_MGM_EVENT_CATEGORY_DEBUG = CFG_LOGLEVEL_DEBUG,
- NDB_MGM_EVENT_CATEGORY_INFO = CFG_LOGLEVEL_INFO,
- NDB_MGM_EVENT_CATEGORY_WARNING = CFG_LOGLEVEL_WARNING,
- NDB_MGM_EVENT_CATEGORY_ERROR = CFG_LOGLEVEL_ERROR,
- NDB_MGM_EVENT_CATEGORY_GREP = CFG_LOGLEVEL_GREP,
- NDB_MGM_EVENT_CATEGORY_BACKUP = CFG_LOGLEVEL_BACKUP,
-
- NDB_MGM_MIN_EVENT_CATEGORY = CFG_MIN_LOGLEVEL,
- NDB_MGM_MAX_EVENT_CATEGORY = CFG_MAX_LOGLEVEL
- };
-
/***************************************************************************/
- /**
+ /**
* @name Functions: Error Handling
* @{
*/
/**
- * Get latest error associated with a management server handle
+ * Get the most recent error associated with the management server whose handle
+ * is used as the value of <var>handle</var>.
*
* @param handle Management handle
* @return Latest error code
@@ -322,7 +412,7 @@ extern "C" {
int ndb_mgm_get_latest_error(const NdbMgmHandle handle);
/**
- * Get latest main error message associated with a handle
+ * Get the most recent general error message associated with a handle
*
* @param handle Management handle.
* @return Latest error message
@@ -330,9 +420,9 @@ extern "C" {
const char * ndb_mgm_get_latest_error_msg(const NdbMgmHandle handle);
/**
- * Get latest error description associated with a handle
+ * Get the most recent error description associated with a handle
*
- * The error description gives some additional information to
+ * The error description gives some additional information regarding
* the error message.
*
* @param handle Management handle.
@@ -342,36 +432,58 @@ extern "C" {
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
- * Get latest internal source code error line associated with a handle
+ * Get the most recent internal source code error line associated with a handle
*
* @param handle Management handle.
* @return Latest internal source code line of latest error
- * @deprecated
+ * @deprecated
*/
int ndb_mgm_get_latest_error_line(const NdbMgmHandle handle);
#endif
/** @} *********************************************************************/
- /**
+ /**
* @name Functions: Create/Destroy Management Server Handles
* @{
*/
- /**
- * Create a handle to a management server
+ /**
+ * Create a handle to a management server.
*
* @return A management handle<br>
- * or NULL if no management handle could be created.
+ * or <var>NULL</var> if no management handle could be created.
*/
NdbMgmHandle ndb_mgm_create_handle();
-
- /**
- * Set connecst string to management server
+
+ /**
+ * Destroy a management server handle.
+ *
+ * @param handle Management handle
+ */
+ void ndb_mgm_destroy_handle(NdbMgmHandle * handle);
+
+ /** @} *********************************************************************/
+ /**
+ * @name Functions: Connect/Disconnect Management Server
+ * @{
+ */
+
+ /**
+ * Sets the connectstring for a management server
*
* @param handle Management handle
- * @param connect_string Connect string to the management server,
+ * @param connect_string Connect string to the management server,
*
* @return -1 on error.
+ *
+ * @code
+ * <connectstring> := [<nodeid-specification>,]<host-specification>[,<host-specification>]
+ * <nodeid-specification> := nodeid=<id>
+ * <host-specification> := <host>[:<port>]
+ * <id> is an integer greater than 0 identifying a node in config.ini
+ * <port> is an integer referring to a regular unix port
+ * <host> is a string containing a valid network host address
+ * @endcode
*/
int ndb_mgm_set_connectstring(NdbMgmHandle handle,
const char *connect_string);
@@ -383,43 +495,88 @@ extern "C" {
const char *ndb_mgm_get_connectstring(NdbMgmHandle handle, char *buf, int buf_sz);
/**
- * Destroy a management server handle
+ * Gets the connectstring used for a connection
*
- * @param handle Management handle
- */
- void ndb_mgm_destroy_handle(NdbMgmHandle * handle);
-
- /** @} *********************************************************************/
- /**
- * @name Functions: Connect/Disconnect Management Server
- * @{
+ * @note This function returns the default connectstring if no call to
+ * ndb_mgm_set_connectstring() has been performed. Also, the
+ * returned connectstring may be formatted differently.
+ *
+ * @param handle Management handle
+ * @param buf Buffer to hold result
+ * @param buf_sz Size of buffer.
+ *
+ * @return connectstring (same as <var>buf</var>)
*/
+ const char *ndb_mgm_get_connectstring(NdbMgmHandle handle, char *buf, int buf_sz);
/**
- * Connect to a management server
+ * Connects to a management server. Connectstring is set by
+ * ndb_mgm_set_connectstring().
*
* @param handle Management handle.
+ * @param no_retries Number of retries to connect
+ * (0 means connect once).
+ * @param retry_delay_in_seconds
+ * How long to wait until retry is performed.
+ * @param verbose Make printout regarding connect retries.
+ *
* @return -1 on error.
*/
int ndb_mgm_connect(NdbMgmHandle handle, int no_retries,
int retry_delay_in_seconds, int verbose);
-
/**
- * Disconnect from a management server
+ * Return true if connected.
+ *
+ * @param handle Management handle
+ * @return 0 if not connected, non-zero if connected.
+ */
+ int ndb_mgm_is_connected(NdbMgmHandle handle);
+
+ /**
+ * Disconnects from a management server
*
* @param handle Management handle.
* @return -1 on error.
*/
int ndb_mgm_disconnect(NdbMgmHandle handle);
-
+
+ /**
+ * Gets connection node ID
+ *
+ * @param handle Management handle
+ *
+ * @return Node ID; 0 indicates that no node ID has been
+ * specified
+ */
+ int ndb_mgm_get_configuration_nodeid(NdbMgmHandle handle);
+
+ /**
+ * Gets connection port
+ *
+ * @param handle Management handle
+ *
+ * @return port
+ */
+ int ndb_mgm_get_connected_port(NdbMgmHandle handle);
+
+ /**
+ * Gets connection host
+ *
+ * @param handle Management handle
+ *
+ * @return hostname
+ */
+ const char *ndb_mgm_get_connected_host(NdbMgmHandle handle);
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/** @} *********************************************************************/
- /**
- * @name Functions: Convert between different data formats
+ /**
+ * @name Functions: Used to convert between different data formats
* @{
*/
/**
- * Convert a string to a ndb_mgm_node_type
+ * Converts a string to an <var>ndb_mgm_node_type</var> value
*
* @param type Node type as string.
* @return NDB_MGM_NODE_TYPE_UNKNOWN if invalid string.
@@ -427,23 +584,24 @@ extern "C" {
enum ndb_mgm_node_type ndb_mgm_match_node_type(const char * type);
/**
- * Convert an ndb_mgm_node_type to a string
+ * Converts an ndb_mgm_node_type to a string
*
* @param type Node type.
- * @return NULL if invalid id.
+ * @return <var>NULL</var> if invalid ID.
*/
const char * ndb_mgm_get_node_type_string(enum ndb_mgm_node_type type);
/**
- * Convert an ndb_mgm_node_type to a alias string
+ * Converts an ndb_mgm_node_type to a alias string
*
* @param type Node type.
- * @return NULL if invalid id.
+ * @return <var>NULL</var> if the ID is invalid.
*/
- const char * ndb_mgm_get_node_type_alias_string(enum ndb_mgm_node_type type, const char **str);
+ const char * ndb_mgm_get_node_type_alias_string(enum ndb_mgm_node_type type,
+ const char **str);
/**
- * Convert a string to a ndb_mgm_node_status
+ * Converts a string to a <var>ndb_mgm_node_status</var> value
*
* @param status NDB node status string.
* @return NDB_MGM_NODE_STATUS_UNKNOWN if invalid string.
@@ -451,67 +609,72 @@ extern "C" {
enum ndb_mgm_node_status ndb_mgm_match_node_status(const char * status);
/**
- * Convert an id to a string
+ * Converts an ID to a string
*
* @param status NDB node status.
- * @return NULL if invalid id.
+ * @return <var>NULL</var> if invalid ID.
*/
const char * ndb_mgm_get_node_status_string(enum ndb_mgm_node_status status);
+ const char * ndb_mgm_get_event_severity_string(enum ndb_mgm_event_severity);
ndb_mgm_event_category ndb_mgm_match_event_category(const char *);
const char * ndb_mgm_get_event_category_string(enum ndb_mgm_event_category);
+#endif
/** @} *********************************************************************/
- /**
- * @name Functions: State of cluster
+ /**
+ * @name Functions: Cluster status
* @{
*/
/**
- * Get status of the nodes in an NDB Cluster
+ * Gets status of the nodes in an NDB Cluster
*
- * Note the caller must free the pointer returned.
+ * @note The caller must free the pointer returned by this function.
*
* @param handle Management handle.
- * @return Cluster state (or NULL on error).
+ *
+ * @return Cluster state (or <var>NULL</var> on error).
*/
struct ndb_mgm_cluster_state * ndb_mgm_get_status(NdbMgmHandle handle);
/** @} *********************************************************************/
- /**
- * @name Functions: Start/stop nodes
+ /**
+ * @name Functions: Start/stop nodes
* @{
*/
/**
- * Stop database nodes
+ * Stops database nodes
*
* @param handle Management handle.
- * @param no_of_nodes no of database nodes<br>
- * 0 - means all database nodes in cluster<br>
- * n - Means stop n node(s) specified in the
+ * @param no_of_nodes Number of database nodes to be stopped<br>
+ * 0: All database nodes in cluster<br>
+ * n: Stop the <var>n</var> node(s) specified in the
* array node_list
- * @param node_list List of node ids of database nodes to be stopped
- * @return No of nodes stopped (or -1 on error)
+ * @param node_list List of node IDs for database nodes to be stopped
+ *
+ * @return Number of nodes stopped (-1 on error)
*
- * @note The function is equivalent
- * to ndb_mgm_stop2(handle, no_of_nodes, node_list, 0)
+ * @note This function is equivalent
+ * to calling ndb_mgm_stop2(handle, no_of_nodes, node_list, 0)
*/
- int ndb_mgm_stop(NdbMgmHandle handle, int no_of_nodes,
+ int ndb_mgm_stop(NdbMgmHandle handle, int no_of_nodes,
const int * node_list);
/**
- * Stop database nodes
+ * Stops database nodes
*
* @param handle Management handle.
- * @param no_of_nodes No of database nodes<br>
- * 0 - means all database nodes in cluster<br>
- * n - Means stop n node(s) specified in
+ * @param no_of_nodes Number of database nodes to stop<br>
+ * 0: All database nodes in cluster<br>
+ * n: Stop the <var>n</var> node(s) specified in
* the array node_list
- * @param node_list List of node ids of database nodes to be stopped
- * @param abort Don't perform gracefull stop,
- * but rather stop immediatly
- * @return No of nodes stopped (or -1 on error).
+ * @param node_list List of node IDs of database nodes to be stopped
+ * @param abort Don't perform graceful stop,
+ * but rather stop immediately
+ *
+ * @return Number of nodes stopped (-1 on error).
*/
int ndb_mgm_stop2(NdbMgmHandle handle, int no_of_nodes,
const int * node_list, int abort);
@@ -520,123 +683,142 @@ extern "C" {
* Restart database nodes
*
* @param handle Management handle.
- * @param no_of_nodes No of database nodes<br>
- * 0 - means all database nodes in cluster<br>
- * n - Means stop n node(s) specified in the
+ * @param no_of_nodes Number of database nodes to restart<br>
+ * 0: All database nodes in cluster<br>
+ * n: Restart the <var>n</var> node(s) specified in the
* array node_list
- * @param node_list List of node ids of database nodes to be stopped
- * @return No of nodes stopped (or -1 on error).
+ * @param node_list List of node IDs of database nodes to be restarted
+ *
+ * @return Number of nodes restarted (-1 on error).
*
- * @note The function is equivalent to
+ * @note This function is equivalent to calling
* ndb_mgm_restart2(handle, no_of_nodes, node_list, 0, 0, 0);
*/
- int ndb_mgm_restart(NdbMgmHandle handle, int no_of_nodes,
+ int ndb_mgm_restart(NdbMgmHandle handle, int no_of_nodes,
const int * node_list);
/**
* Restart database nodes
*
* @param handle Management handle.
- * @param no_of_nodes No of database nodes<br>
- * 0 - means all database nodes in cluster<br>
- * n - Means stop n node(s) specified in the
+ * @param no_of_nodes Number of database nodes to be restarted:<br>
+ * 0: Restart all database nodes in the cluster<br>
+ * n: Restart the <var>n</var> node(s) specified in the
* array node_list
- * @param node_list List of node ids of database nodes to be stopped
- * @param initial Remove filesystem from node(s) restarting
- * @param nostart Don't actually start node(s) but leave them
+ * @param node_list List of node IDs of database nodes to be restarted
+ * @param initial Remove filesystem from restarting node(s)
+ * @param nostart Don't actually start node(s) but leave them
* waiting for start command
- * @param abort Don't perform gracefull restart,
- * but rather restart immediatly
- * @return No of nodes stopped (or -1 on error).
+ * @param abort Don't perform graceful restart,
+ * but rather restart immediately
+ *
+ * @return Number of nodes stopped (-1 on error).
*/
int ndb_mgm_restart2(NdbMgmHandle handle, int no_of_nodes,
const int * node_list, int initial,
int nostart, int abort);
-
+
/**
* Start database nodes
*
* @param handle Management handle.
- * @param no_of_nodes No of database nodes<br>
- * 0 - means all database nodes in cluster<br>
- * n - Means start n node(s) specified in
+ * @param no_of_nodes Number of database nodes to be started<br>
+ * 0: Start all database nodes in the cluster<br>
+ * n: Start the <var>n</var> node(s) specified in
* the array node_list
- * @param node_list List of node ids of database nodes to be started
- * @return No of nodes started (or -1 on error).
+ * @param node_list List of node IDs of database nodes to be started
+ *
+ * @return Number of nodes actually started (-1 on error).
*
- * @note The nodes to start must have been started with nostart(-n)
+ * @note The nodes to be started must have been started with nostart(-n)
* argument.
- * This means that the database node binary is started and
- * waiting for a START management command which will
- * actually start the database node functionality
+ * This means that the database node binary is started and
+ * waiting for a START management command which will
+ * actually enable the database node
*/
int ndb_mgm_start(NdbMgmHandle handle,
int no_of_nodes,
const int * node_list);
/** @} *********************************************************************/
- /**
- * @name Functions: Logging and Statistics
+ /**
+ * @name Functions: Controlling Clusterlog output
* @{
*/
/**
- * Filter cluster log
+ * Filter cluster log severities
*
* @param handle NDB management handle.
- * @param level A cluster log level to filter.
- * @param enable set 1=enable 0=disable
+ * @param severity A cluster log severity to filter.
+ * @param enable set 1=enable o 0=disable
* @param reply Reply message.
+ *
* @return -1 on error.
*/
- int ndb_mgm_filter_clusterlog(NdbMgmHandle handle,
- enum ndb_mgm_clusterlog_level level,
- int enable,
- struct ndb_mgm_reply* reply);
-
+ int ndb_mgm_set_clusterlog_severity_filter(NdbMgmHandle handle,
+ enum ndb_mgm_event_severity severity,
+ int enable,
+ struct ndb_mgm_reply* reply);
/**
- * Get log filter
- *
+ * Get clusterlog severity filter
+ *
* @param handle NDB management handle
- * @return A vector of seven elements,
+ *
+ * @return A vector of seven elements,
* where each element contains
- * 1 if a severity is enabled and 0 if not.
- * A severity is stored at position
- * ndb_mgm_clusterlog_level,
+ * 1 if a severity indicator is enabled and 0 if not.
+ * A severity level is stored at position
+ * ndb_mgm_clusterlog_level;
* for example the "error" level is stored in position
- * [NDB_MGM_CLUSTERLOG_ERROR-1].
- * The first element in the vector signals
- * whether the clusterlog
+ * [NDB_MGM_EVENT_SEVERITY_ERROR].
+ * The first element [NDB_MGM_EVENT_SEVERITY_ON] in
+ * the vector signals
+ * whether the cluster log
* is disabled or enabled.
*/
- unsigned int *ndb_mgm_get_logfilter(NdbMgmHandle handle);
+ const unsigned int *ndb_mgm_get_clusterlog_severity_filter(NdbMgmHandle handle);
/**
* Set log category and levels for the cluster log
*
* @param handle NDB management handle.
- * @param nodeId Node id.
+ * @param nodeId Node ID.
* @param category Event category.
* @param level Log level (0-15).
* @param reply Reply message.
* @return -1 on error.
*/
- int ndb_mgm_set_loglevel_clusterlog(NdbMgmHandle handle,
+ int ndb_mgm_set_clusterlog_loglevel(NdbMgmHandle handle,
int nodeId,
enum ndb_mgm_event_category category,
int level,
struct ndb_mgm_reply* reply);
- ndb_mgm_clusterlog_level
- ndb_mgm_match_clusterlog_level(const char * name);
- const char *
- ndb_mgm_get_clusterlog_level_string(enum ndb_mgm_clusterlog_level level);
+ /** @} *********************************************************************/
+ /**
+ * @name Functions: Listening to log events
+ * @{
+ */
+
+ /**
+ * Listen to log events. They are read from the return file descriptor
+ * and the format is textual, and the same as in the cluster log.
+ *
+ * @param handle NDB management handle.
+ * @param filter pairs of { level, ndb_mgm_event_category } that will be
+ * pushed to fd, level=0 ends list.
+ *
+ * @return fd filedescriptor to read events from
+ */
+ int ndb_mgm_listen_event(NdbMgmHandle handle, const int filter[]);
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Set log category and levels for the Node
*
* @param handle NDB management handle.
- * @param nodeId Node id.
+ * @param nodeId Node ID.
* @param category Event category.
* @param level Log level (0-15).
* @param reply Reply message.
@@ -657,9 +839,68 @@ extern "C" {
*/
int ndb_mgm_get_stat_port(NdbMgmHandle handle,
struct ndb_mgm_reply* reply);
+#endif
+
+ /**
+ * The NdbLogEventHandle
+ */
+ typedef struct ndb_logevent_handle * NdbLogEventHandle;
+
+ /**
+ * Listen to log events.
+ *
+ * @param handle NDB management handle.
+ * @param filter pairs of { level, ndb_mgm_event_category } that will be
+ * pushed to fd, level=0 ends list.
+ *
+ * @return NdbLogEventHandle
+ */
+ NdbLogEventHandle ndb_mgm_create_logevent_handle(NdbMgmHandle,
+ const int filter[]);
+ void ndb_mgm_destroy_logevent_handle(NdbLogEventHandle*);
+
+ /**
+ * Retrieve filedescriptor from NdbLogEventHandle. May be used in
+ * e.g. an application select() statement.
+ *
+ * @note Do not attemt to read from it, it will corrupt the parsing.
+ *
+ * @return filedescriptor, -1 on failure.
+ */
+ int ndb_logevent_get_fd(const NdbLogEventHandle);
+
+ /**
+ * Attempt to retrieve next log event and will fill in the supplied
+ * struct dst
+ *
+ * @param dst Pointer to struct to fill in event information
+ * @param timeout_in_milliseconds Timeout for waiting for event
+ *
+ * @return >0 if event exists, 0 no event (timed out), or -1 on error.
+ *
+ * @note Return value <=0 will leave dst untouched
+ */
+ int ndb_logevent_get_next(const NdbLogEventHandle,
+ struct ndb_logevent *dst,
+ unsigned timeout_in_milliseconds);
+
+ /**
+ * Retrieve laterst error code
+ *
+ * @return error code
+ */
+ int ndb_logevent_get_latest_error(const NdbLogEventHandle);
+
+ /**
+ * Retrieve laterst error message
+ *
+ * @return error message
+ */
+ const char *ndb_logevent_get_latest_error_msg(const NdbLogEventHandle);
+
/** @} *********************************************************************/
- /**
+ /**
* @name Functions: Backup
* @{
*/
@@ -667,13 +908,13 @@ extern "C" {
/**
* Start backup
*
- * @param handle NDB management handle.
- * @param wait_completed 0=don't wait for confirmation
- 1=wait for backup started
- 2=wait for backup completed
- * @param backup_id Backup id is returned from function.
- * @param reply Reply message.
- * @return -1 on error.
+ * @param handle NDB management handle.
+ * @param wait_completed 0: Don't wait for confirmation<br>
+ * 1: Wait for backup to be started<br>
+ * 2: Wait for backup to be completed
+ * @param backup_id Backup ID is returned from function.
+ * @param reply Reply message.
+ * @return -1 on error.
*/
int ndb_mgm_start_backup(NdbMgmHandle handle, int wait_completed,
unsigned int* backup_id,
@@ -683,7 +924,7 @@ extern "C" {
* Abort backup
*
* @param handle NDB management handle.
- * @param backup_id Backup Id.
+ * @param backup_id Backup ID.
* @param reply Reply message.
* @return -1 on error.
*/
@@ -692,48 +933,49 @@ extern "C" {
/** @} *********************************************************************/
- /**
+ /**
* @name Functions: Single User Mode
* @{
*/
/**
- * Enter Single user mode
+ * Enter Single user mode
*
* @param handle NDB management handle.
- * @param nodeId Node Id of the single user node
+ * @param nodeId Node ID of the single user node
* @param reply Reply message.
* @return -1 on error.
*/
int ndb_mgm_enter_single_user(NdbMgmHandle handle, unsigned int nodeId,
struct ndb_mgm_reply* reply);
-
+
/**
- * Exit Single user mode
+ * Exit Single user mode
*
* @param handle NDB management handle.
- * @param nodeId Node Id of the single user node
* @param reply Reply message.
+ *
* @return -1 on error.
*/
- int ndb_mgm_exit_single_user(NdbMgmHandle handle,
+ int ndb_mgm_exit_single_user(NdbMgmHandle handle,
struct ndb_mgm_reply* reply);
-
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ /** @} *********************************************************************/
/**
- * Listen event
- *
- * @param filter pairs of { level, category } that will be
- * pushed to fd, level=0 ends lists
- * @return fd which events will be pushed to
+ * @name Configuration handling
+ * @{
*/
- int ndb_mgm_listen_event(NdbMgmHandle handle, int filter[]);
-
+
/**
* Get configuration
* @param handle NDB management handle.
* @param version Version of configuration, 0 means latest
- * @see MAKE_VERSION
- * @Note the caller must call ndb_mgm_detroy_configuration
+ * (Currently this is the only supported value for this parameter)
+ *
+ * @return configuration
+ *
+ * @note The caller is responsible for calling ndb_mgm_destroy_configuration()
*/
struct ndb_mgm_configuration * ndb_mgm_get_configuration(NdbMgmHandle handle,
unsigned version);
@@ -741,6 +983,13 @@ extern "C" {
int ndb_mgm_alloc_nodeid(NdbMgmHandle handle,
unsigned version, int nodetype);
+
+
+ /**
+ * Get the node id of the mgm server we're connected to
+ */
+ Uint32 ndb_mgm_get_mgmd_nodeid(NdbMgmHandle handle);
+
/**
* Config iterator
*/
@@ -749,14 +998,14 @@ extern "C" {
ndb_mgm_configuration_iterator* ndb_mgm_create_configuration_iterator
(struct ndb_mgm_configuration *, unsigned type_of_section);
void ndb_mgm_destroy_iterator(ndb_mgm_configuration_iterator*);
-
+
int ndb_mgm_first(ndb_mgm_configuration_iterator*);
int ndb_mgm_next(ndb_mgm_configuration_iterator*);
int ndb_mgm_valid(const ndb_mgm_configuration_iterator*);
- int ndb_mgm_find(ndb_mgm_configuration_iterator*,
+ int ndb_mgm_find(ndb_mgm_configuration_iterator*,
int param, unsigned value);
-
- int ndb_mgm_get_int_parameter(const ndb_mgm_configuration_iterator*,
+
+ int ndb_mgm_get_int_parameter(const ndb_mgm_configuration_iterator*,
int param, unsigned * value);
int ndb_mgm_get_int64_parameter(const ndb_mgm_configuration_iterator*,
int param, Uint64 * value);
@@ -764,6 +1013,38 @@ extern "C" {
int param, const char ** value);
int ndb_mgm_purge_stale_sessions(NdbMgmHandle handle, char **);
int ndb_mgm_check_connection(NdbMgmHandle handle);
+#endif
+
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ enum ndb_mgm_clusterlog_level {
+ NDB_MGM_ILLEGAL_CLUSTERLOG_LEVEL = -1,
+ NDB_MGM_CLUSTERLOG_ON = 0,
+ NDB_MGM_CLUSTERLOG_DEBUG = 1,
+ NDB_MGM_CLUSTERLOG_INFO = 2,
+ NDB_MGM_CLUSTERLOG_WARNING = 3,
+ NDB_MGM_CLUSTERLOG_ERROR = 4,
+ NDB_MGM_CLUSTERLOG_CRITICAL = 5,
+ NDB_MGM_CLUSTERLOG_ALERT = 6,
+ NDB_MGM_CLUSTERLOG_ALL = 7
+ };
+ inline
+ int ndb_mgm_filter_clusterlog(NdbMgmHandle h,
+ enum ndb_mgm_clusterlog_level s,
+ int e, struct ndb_mgm_reply* r)
+ { return ndb_mgm_set_clusterlog_severity_filter(h,(ndb_mgm_event_severity)s,
+ e,r); }
+
+ inline
+ const unsigned int *ndb_mgm_get_logfilter(NdbMgmHandle h)
+ { return ndb_mgm_get_clusterlog_severity_filter(h); }
+
+ inline
+ int ndb_mgm_set_loglevel_clusterlog(NdbMgmHandle h, int n,
+ enum ndb_mgm_event_category c,
+ int l, struct ndb_mgm_reply* r)
+ { return ndb_mgm_set_clusterlog_loglevel(h,n,c,l,r); }
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/ndb/include/mgmapi/mgmapi_config_parameters.h b/ndb/include/mgmapi/mgmapi_config_parameters.h
index 432854d1d36..33134899d1e 100644
--- a/ndb/include/mgmapi/mgmapi_config_parameters.h
+++ b/ndb/include/mgmapi/mgmapi_config_parameters.h
@@ -96,7 +96,7 @@
#define CFG_LOGLEVEL_INFO 256
#define CFG_LOGLEVEL_WARNING 257
#define CFG_LOGLEVEL_ERROR 258
-#define CFG_LOGLEVEL_GREP 259
+#define CFG_LOGLEVEL_CONGESTION 259
#define CFG_LOGLEVEL_DEBUG 260
#define CFG_LOGLEVEL_BACKUP 261
#define CFG_MAX_LOGLEVEL 261
diff --git a/ndb/include/mgmapi/mgmapi_debug.h b/ndb/include/mgmapi/mgmapi_debug.h
index 1c562cd164f..e86d9d4b768 100644
--- a/ndb/include/mgmapi/mgmapi_debug.h
+++ b/ndb/include/mgmapi/mgmapi_debug.h
@@ -131,6 +131,7 @@ extern "C" {
int param,
const char * value,
struct ndb_mgm_reply* reply);
+
#ifdef __cplusplus
}
#endif
diff --git a/ndb/include/mgmapi/ndb_logevent.h b/ndb/include/mgmapi/ndb_logevent.h
new file mode 100644
index 00000000000..d5744b0fffe
--- /dev/null
+++ b/ndb/include/mgmapi/ndb_logevent.h
@@ -0,0 +1,618 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef NDB_LOGEVENT_H
+#define NDB_LOGEVENT_H
+
+/** @addtogroup MGM_C_API
+ * @{
+ */
+
+#include "mgmapi_config_parameters.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /**
+ * Available log events grouped by @ref ndb_mgm_event_category
+ */
+
+ enum Ndb_logevent_type {
+
+ NDB_LE_ILLEGAL_TYPE = -1,
+
+ /** NDB_MGM_EVENT_CATEGORY_CONNECTION */
+ NDB_LE_Connected = 0,
+ /** NDB_MGM_EVENT_CATEGORY_CONNECTION */
+ NDB_LE_Disconnected = 1,
+ /** NDB_MGM_EVENT_CATEGORY_CONNECTION */
+ NDB_LE_CommunicationClosed = 2,
+ /** NDB_MGM_EVENT_CATEGORY_CONNECTION */
+ NDB_LE_CommunicationOpened = 3,
+ /** NDB_MGM_EVENT_CATEGORY_CONNECTION */
+ NDB_LE_ConnectedApiVersion = 51,
+
+ /** NDB_MGM_EVENT_CATEGORY_CHECKPOINT */
+ NDB_LE_GlobalCheckpointStarted = 4,
+ /** NDB_MGM_EVENT_CATEGORY_CHECKPOINT */
+ NDB_LE_GlobalCheckpointCompleted = 5,
+ /** NDB_MGM_EVENT_CATEGORY_CHECKPOINT */
+ NDB_LE_LocalCheckpointStarted = 6,
+ /** NDB_MGM_EVENT_CATEGORY_CHECKPOINT */
+ NDB_LE_LocalCheckpointCompleted = 7,
+ /** NDB_MGM_EVENT_CATEGORY_CHECKPOINT */
+ NDB_LE_LCPStoppedInCalcKeepGci = 8,
+ /** NDB_MGM_EVENT_CATEGORY_CHECKPOINT */
+ NDB_LE_LCPFragmentCompleted = 9,
+
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_NDBStartStarted = 10,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_NDBStartCompleted = 11,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_STTORRYRecieved = 12,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_StartPhaseCompleted = 13,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_CM_REGCONF = 14,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_CM_REGREF = 15,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_FIND_NEIGHBOURS = 16,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_NDBStopStarted = 17,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_NDBStopAborted = 18,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_StartREDOLog = 19,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_StartLog = 20,
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_UNDORecordsExecuted = 21,
+
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_NR_CopyDict = 22,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_NR_CopyDistr = 23,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_NR_CopyFragsStarted = 24,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_NR_CopyFragDone = 25,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_NR_CopyFragsCompleted = 26,
+
+ /* NODEFAIL */
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_NodeFailCompleted = 27,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_NODE_FAILREP = 28,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_ArbitState = 29,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_ArbitResult = 30,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_GCP_TakeoverStarted = 31,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_GCP_TakeoverCompleted = 32,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_LCP_TakeoverStarted = 33,
+ /** NDB_MGM_EVENT_CATEGORY_NODE_RESTART */
+ NDB_LE_LCP_TakeoverCompleted = 34,
+
+ /** NDB_MGM_EVENT_CATEGORY_STATISTIC */
+ NDB_LE_TransReportCounters = 35,
+ /** NDB_MGM_EVENT_CATEGORY_STATISTIC */
+ NDB_LE_OperationReportCounters = 36,
+ /** NDB_MGM_EVENT_CATEGORY_STATISTIC */
+ NDB_LE_TableCreated = 37,
+ /** NDB_MGM_EVENT_CATEGORY_STATISTIC */
+ NDB_LE_UndoLogBlocked = 38,
+ /** NDB_MGM_EVENT_CATEGORY_STATISTIC */
+ NDB_LE_JobStatistic = 39,
+ /** NDB_MGM_EVENT_CATEGORY_STATISTIC */
+ NDB_LE_SendBytesStatistic = 40,
+ /** NDB_MGM_EVENT_CATEGORY_STATISTIC */
+ NDB_LE_ReceiveBytesStatistic = 41,
+ /** NDB_MGM_EVENT_CATEGORY_STATISTIC */
+ NDB_LE_MemoryUsage = 50,
+
+ /** NDB_MGM_EVENT_CATEGORY_ERROR */
+ NDB_LE_TransporterError = 42,
+ /** NDB_MGM_EVENT_CATEGORY_ERROR */
+ NDB_LE_TransporterWarning = 43,
+ /** NDB_MGM_EVENT_CATEGORY_ERROR */
+ NDB_LE_MissedHeartbeat = 44,
+ /** NDB_MGM_EVENT_CATEGORY_ERROR */
+ NDB_LE_DeadDueToHeartbeat = 45,
+ /** NDB_MGM_EVENT_CATEGORY_ERROR */
+ NDB_LE_WarningEvent = 46,
+
+ /** NDB_MGM_EVENT_CATEGORY_INFO */
+ NDB_LE_SentHeartbeat = 47,
+ /** NDB_MGM_EVENT_CATEGORY_INFO */
+ NDB_LE_CreateLogBytes = 48,
+ /** NDB_MGM_EVENT_CATEGORY_INFO */
+ NDB_LE_InfoEvent = 49,
+
+ /* GREP */
+ NDB_LE_GrepSubscriptionInfo = 52,
+ NDB_LE_GrepSubscriptionAlert = 53,
+
+ /** NDB_MGM_EVENT_CATEGORY_BACKUP */
+ NDB_LE_BackupStarted = 54,
+ /** NDB_MGM_EVENT_CATEGORY_BACKUP */
+ NDB_LE_BackupFailedToStart = 55,
+ /** NDB_MGM_EVENT_CATEGORY_BACKUP */
+ NDB_LE_BackupCompleted = 56,
+ /** NDB_MGM_EVENT_CATEGORY_BACKUP */
+ NDB_LE_BackupAborted = 57
+ };
+
+ /**
+ * Log event severities (used to filter the cluster log,
+ * ndb_mgm_set_clusterlog_severity_filter(), and filter listening to events
+ * ndb_mgm_listen_event())
+ */
+ enum ndb_mgm_event_severity {
+ NDB_MGM_ILLEGAL_EVENT_SEVERITY = -1,
+ /* Must be a nonnegative integer (used for array indexing) */
+ /** Cluster log on */
+ NDB_MGM_EVENT_SEVERITY_ON = 0,
+ /** Used in NDB Cluster developement */
+ NDB_MGM_EVENT_SEVERITY_DEBUG = 1,
+ /** Informational messages*/
+ NDB_MGM_EVENT_SEVERITY_INFO = 2,
+ /** Conditions that are not error condition, but might require handling.
+ */
+ NDB_MGM_EVENT_SEVERITY_WARNING = 3,
+ /** Conditions that, while not fatal, should be corrected. */
+ NDB_MGM_EVENT_SEVERITY_ERROR = 4,
+ /** Critical conditions, like device errors or out of resources */
+ NDB_MGM_EVENT_SEVERITY_CRITICAL = 5,
+ /** A condition that should be corrected immediately,
+ * such as a corrupted system
+ */
+ NDB_MGM_EVENT_SEVERITY_ALERT = 6,
+ /* must be next number, works as bound in loop */
+ /** All severities */
+ NDB_MGM_EVENT_SEVERITY_ALL = 7
+ };
+
+ /**
+ * Log event categories, used to set filter level on the log events using
+ * ndb_mgm_set_clusterlog_loglevel() and ndb_mgm_listen_event()
+ */
+ enum ndb_mgm_event_category {
+ /**
+ * Invalid log event category
+ */
+ NDB_MGM_ILLEGAL_EVENT_CATEGORY = -1,
+ /**
+ * Log events during all kinds of startups
+ */
+ NDB_MGM_EVENT_CATEGORY_STARTUP = CFG_LOGLEVEL_STARTUP,
+ /**
+ * Log events during shutdown
+ */
+ NDB_MGM_EVENT_CATEGORY_SHUTDOWN = CFG_LOGLEVEL_SHUTDOWN,
+ /**
+ * Statistics log events
+ */
+ NDB_MGM_EVENT_CATEGORY_STATISTIC = CFG_LOGLEVEL_STATISTICS,
+ /**
+ * Log events related to checkpoints
+ */
+ NDB_MGM_EVENT_CATEGORY_CHECKPOINT = CFG_LOGLEVEL_CHECKPOINT,
+ /**
+ * Log events during node restart
+ */
+ NDB_MGM_EVENT_CATEGORY_NODE_RESTART = CFG_LOGLEVEL_NODERESTART,
+ /**
+ * Log events related to connections between cluster nodes
+ */
+ NDB_MGM_EVENT_CATEGORY_CONNECTION = CFG_LOGLEVEL_CONNECTION,
+ /**
+ * Backup related log events
+ */
+ NDB_MGM_EVENT_CATEGORY_BACKUP = CFG_LOGLEVEL_BACKUP,
+ /**
+ * Congestion related log events
+ */
+ NDB_MGM_EVENT_CATEGORY_CONGESTION = CFG_LOGLEVEL_CONGESTION,
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ /**
+ * Loglevel debug
+ */
+ NDB_MGM_EVENT_CATEGORY_DEBUG = CFG_LOGLEVEL_DEBUG,
+#endif
+ /**
+ * Uncategorized log events (severity info)
+ */
+ NDB_MGM_EVENT_CATEGORY_INFO = CFG_LOGLEVEL_INFO,
+ /**
+ * Uncategorized log events (severity warning or higher)
+ */
+ NDB_MGM_EVENT_CATEGORY_ERROR = CFG_LOGLEVEL_ERROR,
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ NDB_MGM_MIN_EVENT_CATEGORY = CFG_MIN_LOGLEVEL,
+ NDB_MGM_MAX_EVENT_CATEGORY = CFG_MAX_LOGLEVEL
+#endif
+ };
+
+ /**
+ * Structure to store and retrieve log event information.
+ * @see @ref secSLogEvents
+ */
+ struct ndb_logevent {
+ /** NdbLogEventHandle (to be used for comparing only)
+ * set in ndb_logevent_get_next()
+ */
+ void *handle;
+
+ /** Which event */
+ enum Ndb_logevent_type type;
+
+ /** Time when log event was registred at the management server */
+ unsigned time;
+
+ /** Category of log event */
+ enum ndb_mgm_event_category category;
+
+ /** Severity of log event */
+ enum ndb_mgm_event_severity severity;
+
+ /** Level (0-15) of log event */
+ unsigned level;
+
+ /** Node ID of the node that reported the log event */
+ unsigned source_nodeid;
+
+ /** Union of log event specific data. Use @ref type to decide
+ * which struct to use
+ */
+ union {
+ /* CONNECT */
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ } Connected;
+
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ } Disconnected;
+
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ } CommunicationClosed;
+
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ } CommunicationOpened;
+
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ unsigned version;
+ } ConnectedApiVersion;
+
+ /* CHECKPOINT */
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned gci;
+ } GlobalCheckpointStarted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned gci;
+ } GlobalCheckpointCompleted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned lci;
+ unsigned keep_gci;
+ unsigned restore_gci;
+ } LocalCheckpointStarted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned lci;
+ } LocalCheckpointCompleted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned data;
+ } LCPStoppedInCalcKeepGci;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ unsigned table_id;
+ unsigned fragment_id;
+ } LCPFragmentCompleted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned acc_count;
+ unsigned tup_count;
+ } UndoLogBlocked;
+
+ /* STARTUP */
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned version;
+ } NDBStartStarted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned version;
+ } NDBStartCompleted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ } STTORRYRecieved;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned phase;
+ unsigned starttype;
+ } StartPhaseCompleted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned own_id;
+ unsigned president_id;
+ unsigned dynamic_id;
+ } CM_REGCONF;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned own_id;
+ unsigned other_id;
+ unsigned cause;
+ } CM_REGREF;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned own_id;
+ unsigned left_id;
+ unsigned right_id;
+ unsigned dynamic_id;
+ } FIND_NEIGHBOURS;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned stoptype;
+ } NDBStopStarted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ } NDBStopAborted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ unsigned keep_gci;
+ unsigned completed_gci;
+ unsigned restorable_gci;
+ } StartREDOLog;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned log_part;
+ unsigned start_mb;
+ unsigned stop_mb;
+ unsigned gci;
+ } StartLog;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned block;
+ unsigned data1;
+ unsigned data2;
+ unsigned data3;
+ unsigned data4;
+ unsigned data5;
+ unsigned data6;
+ unsigned data7;
+ unsigned data8;
+ unsigned data9;
+ unsigned data10;
+ } UNDORecordsExecuted;
+
+ /* NODERESTART */
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ } NR_CopyDict;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ } NR_CopyDistr;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned dest_node;
+ } NR_CopyFragsStarted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned dest_node;
+ unsigned table_id;
+ unsigned fragment_id;
+ } NR_CopyFragDone;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned dest_node;
+ } NR_CopyFragsCompleted;
+
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned block; /* 0 = all */
+ unsigned failed_node;
+ unsigned completing_node; /* 0 = all */
+ } NodeFailCompleted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned failed_node;
+ unsigned failure_state;
+ } NODE_FAILREP;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned code; /* code & state << 16 */
+ unsigned arbit_node;
+ unsigned ticket_0;
+ unsigned ticket_1;
+ /* TODO */
+ } ArbitState;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned code; /* code & state << 16 */
+ unsigned arbit_node;
+ unsigned ticket_0;
+ unsigned ticket_1;
+ /* TODO */
+ } ArbitResult;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ } GCP_TakeoverStarted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ } GCP_TakeoverCompleted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ } LCP_TakeoverStarted;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned state;
+ } LCP_TakeoverCompleted;
+
+ /* STATISTIC */
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned trans_count;
+ unsigned commit_count;
+ unsigned read_count;
+ unsigned simple_read_count;
+ unsigned write_count;
+ unsigned attrinfo_count;
+ unsigned conc_op_count;
+ unsigned abort_count;
+ unsigned scan_count;
+ unsigned range_scan_count;
+ } TransReportCounters;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned ops;
+ } OperationReportCounters;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned table_id;
+ } TableCreated;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned mean_loop_count;
+ } JobStatistic;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned to_node;
+ unsigned mean_sent_bytes;
+ } SendBytesStatistic;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned from_node;
+ unsigned mean_received_bytes;
+ } ReceiveBytesStatistic;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ int gth;
+ unsigned page_size_kb;
+ unsigned pages_used;
+ unsigned pages_total;
+ unsigned block;
+ } MemoryUsage;
+
+ /* ERROR */
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned to_node;
+ unsigned code;
+ } TransporterError;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned to_node;
+ unsigned code;
+ } TransporterWarning;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ unsigned count;
+ } MissedHeartbeat;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ } DeadDueToHeartbeat;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ /* TODO */
+ } WarningEvent;
+
+ /* INFO */
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ } SentHeartbeat;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ unsigned node;
+ } CreateLogBytes;
+ /** Log event specific data for for corresponding NDB_LE_ log event */
+ struct {
+ /* TODO */
+ } InfoEvent;
+
+ /** Log event data for @ref NDB_LE_BackupStarted */
+ struct {
+ unsigned starting_node;
+ unsigned backup_id;
+ } BackupStarted;
+ /** Log event data @ref NDB_LE_BackupFailedToStart */
+ struct {
+ unsigned starting_node;
+ unsigned error;
+ } BackupFailedToStart;
+ /** Log event data @ref NDB_LE_BackupCompleted */
+ struct {
+ unsigned starting_node;
+ unsigned backup_id;
+ unsigned start_gci;
+ unsigned stop_gci;
+ unsigned n_records;
+ unsigned n_log_records;
+ unsigned n_bytes;
+ unsigned n_log_bytes;
+ } BackupCompleted;
+ /** Log event data @ref NDB_LE_BackupAborted */
+ struct {
+ unsigned starting_node;
+ unsigned backup_id;
+ unsigned error;
+ } BackupAborted;
+#ifndef DOXYGEN_FIX
+ };
+#else
+ } <union>;
+#endif
+ };
+
+enum ndb_logevent_handle_error {
+ NDB_LEH_NO_ERROR,
+ NDB_LEH_READ_ERROR,
+ NDB_LEH_MISSING_EVENT_SPECIFIER,
+ NDB_LEH_UNKNOWN_EVENT_TYPE,
+ NDB_LEH_UNKNOWN_EVENT_VARIABLE,
+ NDB_LEH_INTERNAL_ERROR
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
diff --git a/ndb/include/mgmcommon/ConfigRetriever.hpp b/ndb/include/mgmcommon/ConfigRetriever.hpp
index be6d656e1a5..95d257dea23 100644
--- a/ndb/include/mgmcommon/ConfigRetriever.hpp
+++ b/ndb/include/mgmcommon/ConfigRetriever.hpp
@@ -75,6 +75,8 @@ public:
Uint32 get_mgmd_port() const;
const char *get_mgmd_host() const;
const char *get_connectstring(char *buf, int buf_sz) const;
+ NdbMgmHandle get_mgmHandle() { return m_handle; };
+ NdbMgmHandle* get_mgmHandlePtr() { return &m_handle; };
Uint32 get_configuration_nodeid() const;
private:
diff --git a/ndb/include/ndb_constants.h b/ndb/include/ndb_constants.h
new file mode 100644
index 00000000000..c292880749b
--- /dev/null
+++ b/ndb/include/ndb_constants.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/**
+ * @file ndb_constants.h
+ *
+ * Constants common to NDB API and NDB kernel.
+ * Changing the values makes database upgrade impossible.
+ *
+ * New or removed definitions must be replicated to
+ * NdbDictionary.hpp and NdbSqlUtil.hpp.
+ *
+ * Not for use by application programs.
+ * Use the enums provided by NdbDictionary instead.
+ */
+
+#ifndef NDB_CONSTANTS_H
+#define NDB_CONSTANTS_H
+
+/*
+ * Data type constants.
+ */
+
+#define NDB_TYPE_UNDEFINED 0
+
+#define NDB_TYPE_TINYINT 1
+#define NDB_TYPE_TINYUNSIGNED 2
+#define NDB_TYPE_SMALLINT 3
+#define NDB_TYPE_SMALLUNSIGNED 4
+#define NDB_TYPE_MEDIUMINT 5
+#define NDB_TYPE_MEDIUMUNSIGNED 6
+#define NDB_TYPE_INT 7
+#define NDB_TYPE_UNSIGNED 8
+#define NDB_TYPE_BIGINT 9
+#define NDB_TYPE_BIGUNSIGNED 10
+#define NDB_TYPE_FLOAT 11
+#define NDB_TYPE_DOUBLE 12
+#define NDB_TYPE_OLDDECIMAL 13
+#define NDB_TYPE_CHAR 14
+#define NDB_TYPE_VARCHAR 15
+#define NDB_TYPE_BINARY 16
+#define NDB_TYPE_VARBINARY 17
+#define NDB_TYPE_DATETIME 18
+#define NDB_TYPE_DATE 19
+#define NDB_TYPE_BLOB 20
+#define NDB_TYPE_TEXT 21
+#define NDB_TYPE_BIT 22
+#define NDB_TYPE_LONGVARCHAR 23
+#define NDB_TYPE_LONGVARBINARY 24
+#define NDB_TYPE_TIME 25
+#define NDB_TYPE_YEAR 26
+#define NDB_TYPE_TIMESTAMP 27
+#define NDB_TYPE_OLDDECIMALUNSIGNED 28
+#define NDB_TYPE_DECIMAL 29
+#define NDB_TYPE_DECIMALUNSIGNED 30
+
+#define NDB_TYPE_MAX 31
+
+#endif
diff --git a/ndb/include/ndb_global.h.in b/ndb/include/ndb_global.h.in
index eadd5e37b9b..43f90e1f8b5 100644
--- a/ndb/include/ndb_global.h.in
+++ b/ndb/include/ndb_global.h.in
@@ -14,8 +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 */
-#ifndef NDBGLOBAL_H
-#define NDBGLOBAL_H
+#ifndef NDB_GLOBAL_H
+#define NDB_GLOBAL_H
#include <ndb_types.h>
@@ -31,45 +31,22 @@
#define HAVE_STRCASECMP
#define strcasecmp _strcmpi
#pragma warning(disable: 4503 4786)
-typedef unsigned __int64 Uint64;
-typedef signed __int64 Int64;
#else
#undef NDB_WIN32
#define DIR_SEPARATOR "/"
-typedef unsigned long long Uint64;
-typedef signed long long Int64;
#endif
#include <my_global.h>
-typedef signed char Int8;
-typedef unsigned char Uint8;
-typedef signed short Int16;
-typedef unsigned short Uint16;
-typedef signed int Int32;
-typedef unsigned int Uint32;
-
-typedef unsigned int UintR;
-
-#ifdef __SIZE_TYPE__
-typedef __SIZE_TYPE__ UintPtr;
-#elif SIZEOF_CHARP == 4
-typedef Uint32 UintPtr;
-#elif SIZEOF_CHARP == 8
-typedef Uint64 UintPtr;
-#else
-#error "Unknown size of (char *)"
-#endif
-
-#if ! (SIZEOF_CHAR == 1)
+#if ! (NDB_SIZEOF_CHAR == SIZEOF_CHAR)
#error "Invalid define for Uint8"
#endif
-#if ! (SIZEOF_INT == 4)
+#if ! (NDB_SIZEOF_INT == SIZEOF_INT)
#error "Invalid define for Uint32"
#endif
-#if ! (SIZEOF_LONG_LONG == 8)
+#if ! (NDB_SIZEOF_LONG_LONG == SIZEOF_LONG_LONG)
#error "Invalid define for Uint64"
#endif
diff --git a/ndb/include/ndb_types.h.in b/ndb/include/ndb_types.h.in
new file mode 100644
index 00000000000..2a5d576ffea
--- /dev/null
+++ b/ndb/include/ndb_types.h.in
@@ -0,0 +1,81 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/**
+ * @file ndb_types.h
+ */
+
+#ifndef NDB_TYPES_H
+#define NDB_TYPES_H
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(_WIN64)
+#define NDB_SIZEOF_CHARP SIZEOF_CHARP
+#define NDB_SIZEOF_CHAR SIZEOF_CHAR
+#define NDB_SIZEOF_SHORT 2
+#define NDB_SIZEOF_INT SIZEOF_INT
+#define NDB_SIZEOF_LONG SIZEOF_LONG
+#define NDB_SIZEOF_LONG_LONG SIZEOF_LONG_LONG
+typedef unsigned __int64 Uint64;
+typedef signed __int64 Int64;
+#else
+#define NDB_SIZEOF_CHARP @NDB_SIZEOF_CHARP@
+#define NDB_SIZEOF_CHAR @NDB_SIZEOF_CHAR@
+#define NDB_SIZEOF_INT @NDB_SIZEOF_INT@
+#define NDB_SIZEOF_SHORT @NDB_SIZEOF_SHORT@
+#define NDB_SIZEOF_LONG @NDB_SIZEOF_LONG@
+#define NDB_SIZEOF_LONG_LONG @NDB_SIZEOF_LONG_LONG@
+typedef unsigned long long Uint64;
+typedef signed long long Int64;
+#endif
+
+typedef signed char Int8;
+typedef unsigned char Uint8;
+typedef signed short Int16;
+typedef unsigned short Uint16;
+typedef signed int Int32;
+typedef unsigned int Uint32;
+
+typedef unsigned int UintR;
+
+#ifdef __SIZE_TYPE__
+ typedef __SIZE_TYPE__ UintPtr;
+#elif NDB_SIZEOF_CHARP == 4
+ typedef Uint32 UintPtr;
+#elif NDB_SIZEOF_CHARP == 8
+ typedef Uint64 UintPtr;
+#else
+ #error "Unknown size of (char *)"
+#endif
+
+#if ! (NDB_SIZEOF_CHAR == 1)
+#error "Invalid define for Uint8"
+#endif
+
+#if ! (NDB_SIZEOF_SHORT == 2)
+#error "Invalid define for Uint16"
+#endif
+
+#if ! (NDB_SIZEOF_INT == 4)
+#error "Invalid define for Uint32"
+#endif
+
+#if ! (NDB_SIZEOF_LONG_LONG == 8)
+#error "Invalid define for Uint64"
+#endif
+
+#include "ndb_constants.h"
+
+#endif
diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp
index 766409d64e2..41085e6e06a 100644
--- a/ndb/include/ndbapi/Ndb.hpp
+++ b/ndb/include/ndbapi/Ndb.hpp
@@ -17,245 +17,700 @@
/**
@mainpage NDB API Programmers' Guide
- This guide assumes a basic familiarity with NDB Cluster concepts.
- Some of the fundamental ones are described in section @ref secConcepts.
-
- The <em>NDB API</em> is an NDB Cluster application interface
- that implements both synchronous and asynchronous transactions.
+ This guide assumes a basic familiarity with MySQL Cluster concepts found
+ on http://dev.mysql.com/doc/mysql/en/NDBCluster.html .
+ Some of the fundamental ones are also described in section @ref secConcepts.
+
+ The NDB API is a MySQL Cluster application interface
+ that implements transactions.
The NDB API consists of the following fundamental classes:
- - Ndb is the main class representing the database,
- - NdbConnection represents a transaction,
- - NdbOperation represents a transaction operation using primary key,
- - NdbIndexOperation represents a transaction operation using a secondary
- index,
- - NdbRecAttr represents the value of an attribute, and
+ - Ndb_cluster_connection, representing a connection to a cluster,
+ - Ndb is the main class, representing a connection to a database,
+ - NdbTransaction represents a transaction,
+ - NdbOperation represents an operation using a primary key,
+ - NdbScanOperation represents an operation performing a full table scan.
+ - NdbIndexOperation represents an operation using a unique hash index,
+ - NdbIndexScanOperation represents an operation performing a scan using
+ an ordered index,
+ - NdbRecAttr represents an attribute value
- NdbDictionary represents meta information about tables and attributes.
- - NdbError represents an error condition
- There are also some auxiliary classes.
+
+ In addition, the NDB API defines a structure NdbError, which contains the
+ specification for an error.
+
+ It is also possible to receive "events" triggered when data in the database in changed.
+ This is done through the NdbEventOperation class.
+
+ There are also some auxiliary classes, which are listed in the class hierarchy.
The main structure of an application program is as follows:
- -# Construct and initialize Ndb object(s).
- -# Define and execute (synchronous or asynchronous) transactions.
- -# Delete Ndb objects
-
- The main structure of a transaction is as follows:
- -# Start transaction
- -# Add and define operations (associated with the transaction)
- -# Execute transaction
-
- The execute can be of two different types,
- <em>Commit</em> or <em>NoCommit</em>.
- (The execute can also be divided into three
- steps: prepare, send, and poll to get asynchronous
- transactions. More about this later.)
-
- If the execute is of type NoCommit,
- then the application program executes part of a transaction,
- but without committing the transaction.
- After a NoCommit type of execute, the program can continue
+ -# Connect to a cluster using the Ndb_cluster_connection
+ object.
+ -# Initiate a database connection by constructing and initialising one or more Ndb objects.
+ -# Define and execute transactions using the NdbTransaction class.
+ -# Delete Ndb objects.
+ -# Terminate the connection to the cluster (terminate instance of Ndb_cluster_connection).
+
+ The procedure for using transactions is as follows:
+ -# Start transaction (instantiate an NdbTransaction object)
+ -# Add and define operations associated with the transaction using instances of one or more of the
+ NdbOperation, NdbScanOperation, NdbIndexOperation, and NdbIndexScanOperation classes
+ -# Execute transaction (call NdbTransaction::execute())
+
+ The operation can be of two different types,
+ <var>Commit</var> or <var>NoCommit</var>.
+ If the operation is of type <var>NoCommit</var>,
+ then the application program executes the operation part of a transaction,
+ but without actually committing the transaction.
+ After executing a <var>NoCommit</var> operation, the program can continue
to add and define more operations to the transaction
for later execution.
- If the execute is of type Commit, then the transaction is
- committed and no further adding and defining of operations
- is allowed.
-
+ If the operation is of type <var>Commit</var>, then the transaction is
+ immediately committed. The transaction <em>must</em> be closed after it has been
+ commited (event if commit fails), and no further addition or definition of
+ operations for this transaction is allowed.
@section secSync Synchronous Transactions
- Synchronous transactions are defined and executed in the following way.
+ Synchronous transactions are defined and executed as follows:
- -# Start (create) transaction (the transaction will be
- referred to by an NdbConnection object,
- typically created by Ndb::startTransaction).
- At this step the transaction is being defined.
- It is not yet sent to the NDB kernel.
- -# Add and define operations to the transaction
- (using NdbConnection::getNdbOperation and
- methods from class NdbOperation).
- The transaction is still not sent to the NDB kernel.
- -# Execute the transaction (using NdbConnection::execute).
- -# Close the transaction (using Ndb::closeTransaction).
+ -# Start (create) the transaction, which is
+ referenced by an NdbTransaction object
+ (typically created using Ndb::startTransaction()).
+ At this point, the transaction is only being defined,
+ and is not yet sent to the NDB kernel.
+ -# Define operations and add them to the transaction, using one or more of
+ - NdbTransaction::getNdbOperation()
+ - NdbTransaction::getNdbScanOperation()
+ - NdbTransaction::getNdbIndexOperation()
+ - NdbTransaction::getNdbIndexScanOperation()
+ along with the appropriate methods of the respective NdbOperation class
+ (or one possiblt one or more of its subclasses).
+ Note that the transaction has still not yet been sent to the NDB kernel.
+ -# Execute the transaction, using the NdbTransaction::execute() method.
+ -# Close the transaction (call Ndb::closeTransaction()).
- See example program in section @ref ndbapi_example1.cpp.
+ For an example of this process, see the program listing in
+ @ref ndbapi_simple.cpp.
To execute several parallel synchronous transactions, one can either
- use multiple Ndb objects in several threads or start multiple
- applications programs.
- Another way to execute several parallel transactions is to use
- asynchronous transactions.
-
-
+ use multiple Ndb objects in several threads, or start multiple
+ application programs.
+
@section secNdbOperations Operations
- Each transaction (NdbConnection object) consist of a list of
- operations (NdbOperation or NdbIndexOperation objects.
- NdbIndexOperation is used for accessing tables through secondary indexes).
- Operations are of two different kinds:
- -# standard operations, and
- -# interpreted program operations.
+ A NdbTransaction consists of a list of operations, each of which is represented
+ by an instance of NdbOperation, NdbScanOperation, NdbIndexOperation, or
+ NdbIndexScanOperation.
- <h3>Standard Operations</h3>
- After the operation is created using NdbConnection::getNdbOperation
- (or NdbConnection::getNdbIndexOperation),
- it is defined in the following three steps:
- -# Defining standard operation type
- (e.g. using NdbOperation::readTuple)
- -# Specifying search conditions
- (e.g. using NdbOperation::equal)
- -# Specify attribute actions
- (e.g. using NdbOperation::getValue)
-
- Example code (using an NdbOperation):
+ <h3>Single row operations</h3>
+ After the operation is created using NdbTransaction::getNdbOperation()
+ (or NdbTransaction::getNdbIndexOperation()), it is defined in the following
+ three steps:
+ -# Define the standard operation type, using NdbOperation::readTuple()
+ -# Specify search conditions, using NdbOperation::equal()
+ -# Specify attribute actions, using NdbOperation::getValue()
+
+ Here are two brief examples illustrating this process. For the sake of
+ brevity, we omit error handling.
+
+ This first example uses an NdbOperation:
@code
- MyOperation = MyConnection->getNdbOperation("MYTABLENAME"); // 1. Create
- if (MyOperation == NULL) APIERROR(MyConnection->getNdbError());
+ // 1. Retrieve table object
+ myTable= myDict->getTable("MYTABLENAME");
+
+ // 2. Create
+ myOperation= myTransaction->getNdbOperation(myTable);
- MyOperation->readTuple(); // 2. Define type of operation
- MyOperation->equal("ATTR1", i); // 3. Specify Search Conditions
+ // 3. Define type of operation and lock mode
+ myOperation->readTuple(NdbOperation::LM_Read);
+
+ // 4. Specify Search Conditions
+ myOperation->equal("ATTR1", i);
- MyRecAttr = MyOperation->getValue("ATTR2", NULL); // 4. Attribute Actions
- if (MyRecAttr == NULL) APIERROR(MyConnection->getNdbError());
+ // 5. Attribute Actions
+ myRecAttr= myOperation->getValue("ATTR2", NULL);
@endcode
- For more examples, see @ref ndbapi_example1.cpp and @ref ndbapi_example2.cpp.
+ For additional examples of this sort, see @ref ndbapi_simple.cpp.
- Example code using an NdbIndexOperation:
+ The second example uses an NdbIndexOperation:
@code
- MyOperation = // 1. Create
- MyConnection->getNdbIndexOperation("MYINDEX", "MYTABLENAME");
- if (MyOperation == NULL) APIERROR(MyConnection->getNdbError());
+ // 1. Retrieve index object
+ myIndex= myDict->getIndex("MYINDEX", "MYTABLENAME");
+
+ // 2. Create
+ myOperation= myTransaction->getNdbIndexOperation(myIndex);
+
+ // 3. Define type of operation and lock mode
+ myOperation->readTuple(NdbOperation::LM_Read);
- MyOperation->readTuple(); // 2. Define type of operation
- MyOperation->equal("ATTR1", i); // 3. Specify Search Conditions
+ // 4. Specify Search Conditions
+ myOperation->equal("ATTR1", i);
- MyRecAttr = MyOperation->getValue("ATTR2", NULL); // 4. Attribute Actions
- if (MyRecAttr == NULL) APIERROR(MyConnection->getNdbError());
+ // 5. Attribute Actions
+ myRecAttr = myOperation->getValue("ATTR2", NULL);
@endcode
- For more examples, see @ref ndbapi_example4.cpp.
+ Another example of this second type can be found in
+ @ref ndbapi_simple_index.cpp.
+ We will now discuss in somewhat greater detail each step involved in the
+ creation and use of synchronous transactions.
- <h4>Step 1: Define Standard Operation Type</h4>
- The following types of standard operations exist:
- -# NdbOperation::insertTuple :
+ <h4>Step 1: Define single row operation type</h4>
+ The following operation types are supported:
+ -# NdbOperation::insertTuple() :
inserts a non-existing tuple
- -# NdbOperation::writeTuple :
+ -# NdbOperation::writeTuple() :
updates an existing tuple if is exists,
otherwise inserts a new tuple
- -# NdbOperation::updateTuple :
+ -# NdbOperation::updateTuple() :
updates an existing tuple
- -# NdbOperation::deleteTuple :
+ -# NdbOperation::deleteTuple() :
deletes an existing tuple
- -# NdbOperation::readTuple :
- reads an existing tuple
- -# NdbOperation::readTupleExclusive :
- reads an existing tuple using an exclusive lock
- -# NdbOperation::simpleRead :
- reads an existing tuple (using shared read lock),
- but releases lock immediately after read
- -# NdbOperation::committedRead :
- reads committed tuple
- -# NdbOperation::dirtyUpdate :
- updates an existing tuple, but releases lock immediately
- after read (uses dirty lock)
- -# NdbOperation::dirtyWrite :
- updates or writes a tuple, but releases lock immediately
- after read (uses dirty lock)
+ -# NdbOperation::readTuple() :
+ reads an existing tuple with specified lock mode
All of these operations operate on the unique tuple key.
(When NdbIndexOperation is used then all of these operations
- operate on a defined secondary index.)
-
-
- Some comments:
- - NdbOperation::simpleRead and
- NdbOperation::committedRead can execute on the same transaction
- as the above operations but will release its locks immediately
- after reading the tuple.
- NdbOperation::simpleRead will always read the latest version
- of the tuple.
- Thus it will wait until it can acquire a shared read lock on
- the tuple.
- NdbOperation::committedRead will read the latest committed
- version of the tuple.
- <br>
- Both NdbOperation::simpleRead and NdbOperation::committedRead
- are examples of consistent reads which are not repeatable.
- All reads read the latest version if updates were made by the same
- transaction.
- Errors on simple read are only reported by the NdbOperation object.
- These error codes are not transferred to the NdbConnection object.
- - NdbOperation::dirtyUpdate and NdbOperation::dirtyWrite
- will execute in the same transaction
- but will release the lock immediately after updating the
- tuple.
- It will wait on the lock until it can acquire an exclusive
- write lock.
- In a replicated version of NDB Cluster NdbOperation::dirtyUpdate
- can lead to inconsistency between the replicas.
- Examples of when it could be used is
- to update statistical counters on tuples which are "hot-spots".
+ operate on a defined unique hash index.)
@note If you want to define multiple operations within the same transaction,
- then you need to call NdbConnection::getNdbOperation
- (or NdbConnection::getNdbIndexOperation) for each
- operation.
-
+ then you need to call NdbTransaction::getNdbOperation() or
+ NdbTransaction::getNdbIndexOperation() for each operation.
<h4>Step 2: Specify Search Conditions</h4>
- The search condition is used to select tuples.
- (In the current NdbIndexOperation implementation
- this means setting the value of
- the secondary index attributes of the wanted tuple.)
-
- If a tuple identity is used, then NdbOperation::setTupleId
- is used to define the search key when inserting new tuples.
- Otherwise, NdbOperation::equal is used.
-
- For NdbOperation::insertTuple it is also allowed to define the
- search key by using NdbOperation::setValue.
- The NDB API will automatically detect that it is
- supposed to use NdbOperation::equal instead.
- For NdbOperation::insertTuple it is not necessary to use
- NdbOperation::setValue on key attributes before other attributes.
-
+ The search condition is used to select tuples. Search conditions are set using NdbOperation::equal().
<h4>Step 3: Specify Attribute Actions</h4>
- Now it is time to define which attributes should be read or updated.
- Deletes can neither read nor set values, read can only read values and
- updates can only set values.
- Normally the attribute is defined by its name but it is
- also possible to use the attribute identity to define the
+ Next, it is necessary to determine which attributes should be read or updated.
+ It is important to remember that:
+ - Deletes can neither read nor set values, but only delete them
+ - Reads can only read values
+ - Updates can only set values
+ Normally the attribute is identified by name, but it is
+ also possible to use the attribute's identity to determine the
attribute.
- The mapping from name to identity is performed by the Table object.
- NdbIndexOperation::getValue returns an NdbRecAttr object
+ NdbOperation::getValue() returns an NdbRecAttr object
containing the read value.
- To get the value, there is actually two methods.
- The application can either
+ To obtain the actual value, one of two methods can be used;
+ the application can either
- use its own memory (passed through a pointer aValue) to
- NdbIndexOperation::getValue, or
+ NdbOperation::getValue(), or
- receive the attribute value in an NdbRecAttr object allocated
by the NDB API.
- The NdbRecAttr object is released when Ndb::closeTransaction
+ The NdbRecAttr object is released when Ndb::closeTransaction()
is called.
- Thus, the application can not reference this object after
- Ndb::closeTransaction have been called.
- The result of reading data from an NdbRecAttr object before
- calling NdbConnection::execute is undefined.
+ Thus, the application cannot reference this object following
+ any subsequent call to Ndb::closeTransaction().
+ Attempting to read data from an NdbRecAttr object before
+ calling NdbTransaction::execute() yields an undefined result.
+
+
+ @subsection secScan Scan Operations
+
+ Scans are roughly the equivalent of SQL cursors, providing a means to
+ preform high-speed row processing. A scan can be performed
+ on either a table (using @ref NdbScanOperation) or
+ an ordered index (by means of an @ref NdbIndexScanOperation).
+
+ Scan operations are characterised by the following:
+ - They can perform only reads (shared, exclusive or dirty)
+ - They can potentially work with multiple rows
+ - They can be used to update or delete multiple rows
+ - They can operate on several nodes in parallel
+
+ After the operation is created using NdbTransaction::getNdbScanOperation()
+ (or NdbTransaction::getNdbIndexScanOperation()),
+ it is carried out in the following three steps:
+ -# Define the standard operation type, using NdbScanOperation::readTuples()
+ -# Specify search conditions, using @ref NdbScanFilter and/or
+ @ref NdbIndexScanOperation::setBound()
+ -# Specify attribute actions, using NdbOperation::getValue()
+ -# Executing the transaction, using NdbTransaction::execute()
+ -# Traversing the result set by means of succssive calls to
+ NdbScanOperation::nextResult()
+
+ Here are two brief examples illustrating this process. Once again, in order
+ to keep things relatively short and simple, we will forego any error handling.
+
+ This first example performs a table scan, using an NdbScanOperation:
+ @code
+ // 1. Retrieve table object
+ myTable= myDict->getTable("MYTABLENAME");
+
+ // 2. Create
+ myOperation= myTransaction->getNdbScanOperation(myTable);
+
+ // 3. Define type of operation and lock mode
+ myOperation->readTuples(NdbOperation::LM_Read);
+
+ // 4. Specify Search Conditions
+ NdbScanFilter sf(myOperation);
+ sf.begin(NdbScanFilter::OR);
+ sf.eq(0, i); // Return rows with column 0 equal to i or
+ sf.eq(1, i+1); // column 1 equal to (i+1)
+ sf.end();
+
+ // 5. Attribute Actions
+ myRecAttr= myOperation->getValue("ATTR2", NULL);
+ @endcode
+
+ Our second example uses an NdbIndexScanOperation to perform an index scan:
+ @code
+ // 1. Retrieve index object
+ myIndex= myDict->getIndex("MYORDEREDINDEX", "MYTABLENAME");
+
+ // 2. Create
+ myOperation= myTransaction->getNdbIndexScanOperation(myIndex);
+
+ // 3. Define type of operation and lock mode
+ myOperation->readTuples(NdbOperation::LM_Read);
+
+ // 4. Specify Search Conditions
+ // All rows with ATTR1 between i and (i+1)
+ myOperation->setBound("ATTR1", NdbIndexScanOperation::BoundGE, i);
+ myOperation->setBound("ATTR1", NdbIndexScanOperation::BoundLE, i+1);
+
+ // 5. Attribute Actions
+ myRecAttr = MyOperation->getValue("ATTR2", NULL);
+ @endcode
+
+ Some additional discussion of each step required to perform a scan follows:
+
+ <h4>Step 1: Define Scan Operation Type</h4>
+ It is important to remember that only a single operation is supported for each scan operation
+ (@ref NdbScanOperation::readTuples() or @ref NdbIndexScanOperation::readTuples()).
+
+ @note If you want to define multiple scan operations within the same
+ transaction, then you need to call
+ NdbTransaction::getNdbScanOperation() or
+ NdbTransaction::getNdbIndexScanOperation() separately for <b>each</b> operation.
+
+ <h4>Step 2: Specify Search Conditions</h4>
+ The search condition is used to select tuples.
+ If no search condition is specified, the scan will return all rows
+ in the table.
+
+ The search condition can be an @ref NdbScanFilter (which can be used on both
+ @ref NdbScanOperation and @ref NdbIndexScanOperation) or bounds which
+ can only be used on index scans (@ref NdbIndexScanOperation::setBound()).
+ An index scan can use both NdbScanFilter and bounds.
+
+ @note When NdbScanFilter is used, each row is examined, whether or not it is
+ actually returned. However, when using bounds, only rows within the bounds will be examined.
+
+ <h4>Step 3: Specify Attribute Actions</h4>
+
+ Next, it is necessary to define which attributes should be read.
+ As with transaction attributes, scan attributes are defined by name but it is
+ also possible to use the attributes' identities to define attributes.
+
+ As previously discussed (see @ref secSync), the value read is returned as
+ an NdbRecAttr object by the NdbOperation::getValue() method.
+
+ <h3>Using Scan to Update/Delete</h3>
+ Scanning can also be used to update or delete rows.
+ This is performed by
+ -# Scanning using exclusive locks (using NdbOperation::LM_Exclusive)
+ -# When iterating through the result set, for each row optionally calling
+ either NdbScanOperation::updateCurrentTuple() or
+ NdbScanOperation::deleteCurrentTuple()
+ -# (If performing NdbScanOperation::updateCurrentTuple():)
+ Setting new values for records simply by using @ref NdbOperation::setValue().
+ NdbOperation::equal() should <em>not</em> be called in such cases, as the primary
+ key is retrieved from the scan.
+
+ @note The actual update or delete will not be performed until the next
+ call to NdbTransaction::execute(), just as with single row operations.
+ NdbTransaction::execute() also must be called before any locks are released;
+ see @ref secScanLocks for more information.
+
+ <h4>Features Specific to Index Scans</h4>
+
+ When performing an index scan, it is possible to
+ scan only a subset of a table using @ref NdbIndexScanOperation::setBound().
+ In addition, result sets can be sorted in either ascending or descending order, using
+ @ref NdbIndexScanOperation::readTuples(). Note that rows are returned unordered
+ by default, that is, unless <var>sorted</var> is set to <b>true</b>.
+ It is also important to note that, when using NdbIndexScanOperation::BoundEQ
+ on a partition key, only fragments containing rows will actually be scanned.
+
+ @note When performing a sorted scan, any value passed as the
+ NdbIndexScanOperation::readTuples() method's <code>parallel</code> argument
+ will be ignored and maximum parallelism will be used instead. In other words, all
+ fragments which it is possible to scan will be scanned simultaneously and in parallel
+ in such cases.
+
+ @subsection secScanLocks Lock handling with scans
+
+ Performing scans on either a tables or an index has the potential
+ return a great many records; however, Ndb will lock only a predetermined
+ number of rows per fragment at a time.
+ How many rows will be locked per fragment is controlled by the
+ <var>batch</var> parameter passed to NdbScanOperation::readTuples().
+
+ In order to allow the application to handle how locks are released,
+ NdbScanOperation::nextResult() has a Boolean parameter <var>fetch_allow</var>.
+ If NdbScanOperation::nextResult() is called with <var>fetch_allow</var> equal to
+ <b>false</b>, then no locks may be released as result of the function call.
+ Otherwise the locks for the current batch may be released.
+
+ This next example shows a scan delete that handle locks in an efficient manner.
+ For the sake of brevity, we omit error-handling.
+ @code
+ int check;
+
+ // Outer loop for each batch of rows
+ while((check = MyScanOperation->nextResult(true)) == 0)
+ {
+ do
+ {
+ // Inner loop for each row within batch
+ MyScanOperation->deleteCurrentTuple();
+ } while((check = MyScanOperation->nextResult(false)) == 0);
+
+ // When no more rows in batch, exeute all defined deletes
+ MyTransaction->execute(NoCommit);
+ }
+ @endcode
+
+ See @ref ndbapi_scan.cpp for a more complete example of a scan.
+
+ @section secError Error Handling
+
+ Errors can occur either when operations making up a transaction are being
+ defined, or when the transaction is actually being executed. Catching and
+ handling either sort of error requires testing the value returned by
+ NdbTransaction::execute(), and then, if an error is indicated (that is,
+ if this value is equal to -1), using the following two methods in order to
+ identify the error's type and location:
+
+ - NdbTransaction::getNdbErrorOperation() returns a reference to the
+ operation causing the most recent error.
+ - NdbTransaction::getNdbErrorLine() yields the method number of the
+ erroneous method in the operation.
+
+ This short example illustrates how to detect an error and to use these
+ two methods to identify it:
+
+ @code
+ theTransaction = theNdb->startTransaction();
+ theOperation = theTransaction->getNdbOperation("TEST_TABLE");
+ if (theOperation == NULL) goto error;
+ theOperation->readTuple(NdbOperation::LM_Read);
+ theOperation->setValue("ATTR_1", at1);
+ theOperation->setValue("ATTR_2", at1); // Error occurs here
+ theOperation->setValue("ATTR_3", at1);
+ theOperation->setValue("ATTR_4", at1);
+
+ if (theTransaction->execute(Commit) == -1) {
+ errorLine = theTransaction->getNdbErrorLine();
+ errorOperation = theTransaction->getNdbErrorOperation();
+ }
+ @endcode
+
+ Here <code>errorLine</code> will be 3, as the error occurred in the
+ third method called on the NdbOperation object (in this case,
+ <code>theOperation</code>); if the result of
+ NdbTransaction::getNdbErrorLine() is 0, this means that the error
+ occurred when the operations were executed. In this example,
+ <code>errorOperation</code> will be a pointer to the <code>theOperation</code>
+ object. The NdbTransaction::getNdbError() method returns an NdbError
+ object providing information about the error.
+
+ @note Transactions are <b>not</b> automatically closed when an error occurs. Call
+ Ndb::closeTransaction() to close the transaction.
+
+ One recommended way to handle a transaction failure
+ (i.e. an error is reported) is to:
+ -# Rollback transaction (call NdbTransaction::execute() with a special parameter)
+ -# Close transaction (call NdbTransaction::closeTransaction())
+ -# If the error was temporary, attempt to restart the transaction
+
+ Several errors can occur when a transaction contains multiple
+ operations which are simultaneously executed.
+ In this case the application has to go through all operations
+ and query their NdbError objects to find out what really happened.
+
+ It is also important to note that errors can occur even when a commit is
+ reported as successful. In order to handle such situations, the NDB API
+ provides an additional NdbTransaction::commitStatus() method to check the
+ transactions's commit status.
+
+******************************************************************************/
+
+/**
+ * @page ndbapi_simple.cpp ndbapi_simple.cpp
+ * @include ndbapi_simple.cpp
+ */
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
+ * @page ndbapi_async.cpp ndbapi_async.cpp
+ * @include ndbapi_async.cpp
+ */
+/**
+ * @page ndbapi_async1.cpp ndbapi_async1.cpp
+ * @include ndbapi_async1.cpp
+ */
+#endif
+
+/**
+ * @page ndbapi_retries.cpp ndbapi_retries.cpp
+ * @include ndbapi_retries.cpp
+ */
+
+/**
+ * @page ndbapi_simple_index.cpp ndbapi_simple_index.cpp
+ * @include ndbapi_simple_index.cpp
+ */
+
+/**
+ * @page ndbapi_scan.cpp ndbapi_scan.cpp
+ * @include ndbapi_scan.cpp
+ */
+
+/**
+ * @page ndbapi_event.cpp ndbapi_event.cpp
+ * @include ndbapi_event.cpp
+ */
+
+
+/**
+ @page secAdapt Adaptive Send Algorithm
+
+ At the time of "sending" a transaction
+ (using NdbTransaction::execute()), the transactions
+ are in reality <em>not</em> immediately transfered to the NDB Kernel.
+ Instead, the "sent" transactions are only kept in a
+ special send list (buffer) in the Ndb object to which they belong.
+ The adaptive send algorithm decides when transactions should
+ actually be transferred to the NDB kernel.
+
+ The NDB API is designed as a multi-threaded interface and so
+ it is often desirable to transfer database operations from more than
+ one thread at a time.
+ The NDB API keeps track of which Ndb objects are active in transferring
+ information to the NDB kernel and the expected amount of threads to
+ interact with the NDB kernel.
+ Note that a given instance of Ndb should be used in at most one thread;
+ different threads should <em>not</em> use the same Ndb object.
+
+ There are four conditions leading to the transfer of database
+ operations from Ndb object buffers to the NDB kernel:
+ -# The NDB Transporter (TCP/IP, OSE, SCI or shared memory)
+ decides that a buffer is full and sends it off.
+ The buffer size is implementation-dependent and
+ may change between MySQL Cluster releases.
+ On TCP/IP the buffer size is usually around 64 KB;
+ on OSE/Delta it is usually less than 2000 bytes.
+ Since each Ndb object provides a single buffer per storage node,
+ the notion of a "full" buffer is local to this storage node.
+ -# The accumulation of statistical data on transferred information
+ may force sending of buffers to all storage nodes.
+ -# Every 10 ms, a special transmission thread checks whether or not
+ any send activity has occurred. If not, then the thread will
+ force transmission to all nodes.
+ This means that 20 ms is the maximum time database operations
+ are kept waiting before being sent off. The 10-millisecond limit
+ is likely to become a configuration parameter in
+ future releases of MySQL Cluster; however, for checks that
+ are more frequent than each 10 ms,
+ additional support from the operating system is required.
+ -# For methods that are affected by the adaptive send alorithm
+ (such as NdbTransaction::execute()), there is a <var>force</var>
+ parameter
+ that overrides its default behaviour in this regard and forces
+ immediate transmission to all nodes. See the inidvidual NDB API class
+ listings for more information.
+
+ @note The conditions listed above are subject to change in future releases
+ of MySQL Cluster.
+*/
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
+
+ For each of these "sent" transactions, there are three
+ possible states:
+ -# Waiting to be transferred to NDB Kernel.
+ -# Has been transferred to the NDB Kernel and is currently
+ being processed.
+ -# Has been transferred to the NDB Kernel and has
+ finished processing.
+ Now it is waiting for a call to a poll method.
+ (When the poll method is invoked,
+ then the transaction callback method will be executed.)
+
+ The poll method invoked (either Ndb::pollNdb() or Ndb::sendPollNdb())
+ will return when:
+ -# at least 'minNoOfEventsToWakeup' of the transactions
+ in the send list have transitioned to state 3 as described above, and
+ -# all of these transactions have executed their callback methods.
+*/
+#endif
+
+/**
+ @page secConcepts MySQL Cluster Concepts
+
+ The <em>NDB Kernel</em> is the collection of storage nodes
+ belonging to a MySQL Cluster.
+ The application programmer can for most purposes view the
+ set of all storage nodes as a single entity.
+ Each storage node is made up of three main components:
+ - TC : The transaction co-ordinator
+ - ACC : Index storage component
+ - TUP : Data storage component
+
+ When an application program executes a transaction,
+ it connects to one transaction co-ordinator on one storage node.
+ Usually, the programmer does not need to specify which TC should be used,
+ but in some cases when performance is important, the programmer can
+ provide "hints" to use a certain TC.
+ (If the node with the desired transaction co-ordinator is down, then another TC will
+ automatically take over the work.)
+ Every storage node has an ACC and a TUP which store
+ the indexes and data portions of the database table fragment.
+ Even though one TC is responsible for the transaction,
+ several ACCs and TUPs on other storage nodes might be involved in the
+ execution of the transaction.
+ @section secNdbKernelConnection Selecting a Transaction Co-ordinator
+
+ The default method is to select the transaction co-ordinator (TC) determined to be
+ the "closest" storage node, using a heuristic for proximity based on
+ the type of transporter connection. In order of closest to most distant, these are
+ - SCI
+ - SHM
+ - TCP/IP (localhost)
+ - TCP/IP (remote host)
+ If there are several connections available with the same proximity, they will each be
+ selected in a round robin fashion for every transaction. Optionally
+ one may set the method for TC selection to round-robin mode, where each new set of
+ transactions is placed on the next DB node. The pool of connections from which this
+ selection is made consists of all available connections.
+
+ As noted previously, the application programmer can provide hints to the NDB API as to
+ which transaction co-ordinator it should use. This is done by
+ providing a <em>table</em> and <em>partition key</em>
+ (usually the primary key).
+ By using the primary key as the partition key,
+ the transaction will be placed on the node where the primary replica
+ of that record resides.
+ Note that this is only a hint; the system can be
+ reconfigured at any time, in which case the NDB API will choose a transaction
+ co-ordinator without using the hint.
+ For more information, see NdbDictionary::Column::getPartitionKey() and
+ Ndb::startTransaction(). The application programmer can specify
+ the partition key from SQL by using the construct,
+ <code>CREATE TABLE ... ENGINE=NDB PARTITION BY KEY (<var>attribute-list</var>);</code>.
+
+
+ @section secRecordStruct NDB Record Structure
+ The NDB Cluster engine used by MySQL Cluster is a relational database engine
+ storing records in tables just as with any other RDBMS.
+ Table rows represent records as tuples of relational data.
+ When a new table is created, its attribute schema is specified for the table as a whole,
+ and thus each record of the table has the same structure. Again, this is typical
+ of relational databases, and NDB is no different in this regard.
+
+
+ @subsection secKeys Primary Keys
+ Each record has from 1 up to 32 attributes which belong
+ to the primary key of the table.
+
+ @section secTrans Transactions
+
+ Transactions are committed first to main memory,
+ and then to disk after a global checkpoint (GCP) is issued.
+ Since all data is (in most NDB Cluster configurations)
+ synchronously replicated and stored on multiple NDB nodes,
+ the system can still handle processor failures without loss
+ of data.
+ However, in the case of a system failure (e.g. the whole system goes down),
+ then all (committed or not) transactions occurring since the latest GCP are lost.
+
+
+ @subsection secConcur Concurrency Control
+ NDB Cluster uses pessimistic concurrency control based on locking.
+ If a requested lock (implicit and depending on database operation)
+ cannot be attained within a specified time,
+ then a timeout error occurs.
+
+ Concurrent transactions as requested by parallel application programs and
+ thread-based applications can sometimes deadlock when they try to access
+ the same information simultaneously.
+ Thus, applications need to be written in a manner so that timeout errors
+ occurring due to such deadlocks are handled gracefully. This generally
+ means that the transaction encountering a timeout should be rolled back
+ and restarted.
+
+
+ @section secHint Hints and Performance
+
+ Placing the transaction co-ordinator in close proximity
+ to the actual data used in the transaction can in many cases
+ improve performance significantly. This is particularly true for
+ systems using TCP/IP. For example, a Solaris system using a single 500 MHz processor
+ has a cost model for TCP/IP communication which can be represented by the formula
+
+ <code>[30 microseconds] + ([100 nanoseconds] * [<var>number of bytes</var>])</code>
+
+ This means that if we can ensure that we use "popular" links we increase
+ buffering and thus drastically reduce the communication cost.
+ The same system using SCI has a different cost model:
+
+ <code>[5 microseconds] + ([10 nanoseconds] * [<var>number of bytes</var>])</code>
+
+ Thus, the efficiency of an SCI system is much less dependent on selection of
+ transaction co-ordinators.
+ Typically, TCP/IP systems spend 30-60% of their working time on communication,
+ whereas for SCI systems this figure is closer to 5-10%.
+ Thus, employing SCI for data transport means that less care from the NDB API
+ programmer is required and greater scalability can be achieved, even for
+ applications using data from many different parts of the database.
+
+ A simple example is an application that uses many simple updates where
+ a transaction needs to update one record.
+ This record has a 32 bit primary key,
+ which is also the partition key.
+ Then the keyData will be the address of the integer
+ of the primary key and keyLen will be 4.
+*/
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
+ (A transaction's execution can also be divided into three
+ steps: prepare, send, and poll. This allows us to perform asynchronous
+ transactions. More about this later.)
+*/
+#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
+ Another way to execute several parallel transactions is to use
+ asynchronous transactions.
+*/
+#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
+ Operations are of two different kinds:
+ -# standard operations, and
+ -# interpreted program operations.
+*/
+#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
<h3>Interpreted Program Operations</h3>
The following types of interpreted program operations exist:
-# NdbOperation::interpretedUpdateTuple :
updates a tuple using an interpreted program
-# NdbOperation::interpretedDeleteTuple :
delete a tuple using an interpreted program
- -# NdbOperation::openScanRead :
- scans a table with read lock on each tuple
- -# NdbOperation::openScanExclusive :
- scans a table with exclusive update lock on each tuple
The operations interpretedUpdateTuple and interpretedDeleteTuple both
work using the unique tuple key.
@@ -306,124 +761,10 @@
There might be zero NdbOperation::getValue calls.
-# The fifth step is possible subroutine definitions using
NdbOperation::def_subroutine and NdbOperation::ret_sub.
-
-
- @subsection secScan Scanning
- The most common use of interpreted programs is for scanning
- tables. Scanning is a search of all tuples in a table.
- Tuples which satisfy conditions (a search filter)
- stated in the interpreted program
- are sent to the application.
-
- Reasons for using scan transactions include
- need to use a search key different from the primary key
- and any secondary index.
- Or that the query needs to access so many tuples so that
- it is more efficient to scan the entire table.
-
- Scanning can also be used to update information.
- The scanning transaction itself is however
- not allowed to update any tuples.
- To do updates via scanning transactions, the tuples
- need to be handed over to another transaction which is
- executing the actual update.
-
- Even though a scan operation is part of a transaction,
- the scan transaction is not a normal transaction.
- The locks are <em>not</em> kept throughout the entire
- scan transaction, since this would imply non-optimal performance.
- <em>
- A transaction containing a scan operation can only
- contain that operation.
- No other operations are allowed in the same transaction.
- </em>
-
- The NdbOperation::openScanRead operation
- only sets a temporary read lock while
- reading the tuple.
- The tuple lock is released already when the
- result of the read reaches the application.
- The NdbOperation::openScanExclusive operation sets an
- exclusive lock on the tuple
- and sends the result to the application.
- Thus when the application reads the data it is still
- locked with the exclusive lock.
-
- If the application desires to update the tuple it may transfer
- the tuple to another transaction which updates the tuple.
- The updating transaction can consist of a combination of tuples
- received from the scan and normal operations.
-
- For transferred operations it is not necessary to provide the
- primary key. It is part of the transfer.
- You only need to give the operation type and the
- actions to perform on the tuple.
-
- The scan transaction starts like a usual transaction,
- but is of the following form:
- -# Start transaction
- -# Get NdbOperation for the table to be scanned
- -# Set the operation type using NdbOperation::openScanRead or
- NdbOperation::openScanExclusive
- -# Search conditions are defined by an interpreted program
- (setValue and write_attr are not allowed, since scan transactions
- are only allowed to read information).
- The instruction interpret_exit_nok does in this case
- not abort the transaction, it only skips the tuple and
- proceeds with the next.
- The skipped tuple will not be reported to the application.
- -# Call NdbConnection::executeScan to define (and start) the scan.
- -# Call NdbConnection::nextScanResult to proceed with next tuple.
- When calling NdbConnection::nextScanResult, the lock on any
- previous tuples are released.
- <br>
- If the tuple should be updated then it must be transferred over
- to another updating transaction.
- This is performed by calling
- NdbOperation::takeOverForUpdate or takeOverForDelete on
- the scanning transactions NdbOperation object with the updating
- transactions NdbConnection object as parameter.
- <p>
- If NdbOperation::takeOverFor* returns NULL then the
- operation was not successful, otherwise it returns a reference
- to the NdbOperation which the updating transaction has received
- -# Use Ndb::closeTransaction as usual to close the transaction.
- This can be performed even if there are more tuples to scan.
-
- See also example program in section @ref select_all.cpp.
-
- However, a new scan api is under development, using NdbScanOperation
- and NdbScanFilter. NdbScanFilter makes it easier to define a search
- criteria and is recommended instead of using Interpreted Programs.
-
- The scan transaction starts like a usual transaction,
- but is of the following form:
- -# Start transaction
- -# Get NdbScanOperation for the table to be scanned
- -# NdbScanOperation::readTuplesExclusive returns a handle to a
- NdbResultSet.
- -# Search conditions are defined by NdbScanFilter
- -# Call NdbConnection::execute(NoCommit) to start the scan.
- -# Call NdbResultSet::nextResult to proceed with next tuple.
- When calling NdbResultSet::nextResult(false), the lock on any
- previous tuples are released and the next tuple cached in the API
- is fetched.
- <br>
- If the tuple should be updated then define a new update operation
- (NdbOperation) using NdbResultSet::updateTuple().
- The new update operation can the be used to modify the tuple.
- When nextResult(false) returns != 0, then no more tuples
- are cached in the API. Updated tuples is now commit using
- NdbConnection::execute(Commit).
- After the commit, more tuples are fetched from NDB using
- nextResult(true).
- -# Use Ndb::closeTransaction as usual to close the transaction.
- This can be performed even if there are more tuples to scan.
-
- See the scan example program in @ref ndbapi_scan.cppn for example
- usage of the new scan api.
-
-
+*/
+#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
<h3>Interpreted Programs</h3>
Interpretation programs are executed in a
register-based virtual machine.
@@ -494,8 +835,11 @@
The parameter used by NdbOperation::def_subroutine
should match the automatic numbering to make it easier to
debug the interpreted program.
+*/
+#endif
-
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
@section secAsync Asynchronous Transactions
The asynchronous interface is used to increase the speed of
transaction executing by better utilizing the connection
@@ -508,7 +852,7 @@
chunks of data are sent when actually sending and thus decreasing
the operating system overhead.
- The synchronous call to NdbConnection::execute
+ The synchronous call to NdbTransaction::execute
normally performs three main steps:<br>
-# <b>Prepare</b>
Check transaction status
@@ -520,7 +864,7 @@
-# <b>Poll</b>
Wait for response from NDB kernel.
- The asynchronous method NdbConnection::executeAsynchPrepare
+ The asynchronous method NdbTransaction::executeAsynchPrepare
only perform step 1.
(The abort part in step 1 is only prepared for. The actual
aborting of the transaction is performed in a later step.)
@@ -531,11 +875,11 @@
synchronous transactions)
-# Add and define operations (also as in the synchronous case)
-# <b>Prepare</b> transactions
- (using NdbConnection::executeAsynchPrepare or
- NdbConnection::executeAsynch)
+ (using NdbTransaction::executeAsynchPrepare or
+ NdbTransaction::executeAsynch)
-# <b>Send</b> transactions to NDB Kernel
(using Ndb::sendPreparedTransactions,
- NdbConnection::executeAsynch, or Ndb::sendPollNdb)
+ NdbTransaction::executeAsynch, or Ndb::sendPollNdb)
-# <b>Poll</b> NDB kernel to find completed transactions
(using Ndb::pollNdb or Ndb::sendPollNdb)
-# Close transactions (same way as for the synchronous transactions)
@@ -546,24 +890,24 @@
- (Prepare-Send-Poll). This is the one-step variant provided
by synchronous transactions.
- (Prepare-Send)-Poll. This is the two-step variant using
- NdbConnection::executeAsynch and Ndb::pollNdb.
+ NdbTransaction::executeAsynch and Ndb::pollNdb.
- Prepare-(Send-Poll). This is the two-step variant using
- NdbConnection::executeAsynchPrepare and Ndb::sendPollNdb.
+ NdbTransaction::executeAsynchPrepare and Ndb::sendPollNdb.
- Prepare-Send-Poll. This is the three-step variant using
- NdbConnection::executeAsynchPrepare, Ndb::sendPreparedTransactions, and
+ NdbTransaction::executeAsynchPrepare, Ndb::sendPreparedTransactions, and
Ndb::pollNdb.
Transactions first has to be prepared by using method
- NdbConnection::executeAsynchPrepare or NdbConnection::executeAsynch.
+ NdbTransaction::executeAsynchPrepare or NdbTransaction::executeAsynch.
The difference between these is that
- NdbConnection::executeAsynch also sends the transaction to
+ NdbTransaction::executeAsynch also sends the transaction to
the NDB kernel.
One of the arguments to these methods is a callback method.
The callback method is executed during polling (item 5 above).
- Note that NdbConnection::executeAsynchPrepare does not
+ Note that NdbTransaction::executeAsynchPrepare does not
send the transaction to the NDB kernel. When using
- NdbConnection::executeAsynchPrepare, you either have to call
+ NdbTransaction::executeAsynchPrepare, you either have to call
Ndb::sendPreparedTransactions or Ndb::sendPollNdb to send the
database operations.
(Ndb::sendPollNdb also polls Ndb for completed transactions.)
@@ -583,276 +927,34 @@
The poll method returns the number of transactions that
have finished processing and executed their callback methods.
-
+
@note When an asynchronous transaction has been started and sent to
the NDB kernel, it is not allowed to execute any methods on
objects belonging to this transaction until the transaction
callback method have been executed.
(The transaction is stated and sent by either
- NdbConnection::executeAsynch or through the combination of
- NdbConnection::executeAsynchPrepare and either
+ NdbTransaction::executeAsynch or through the combination of
+ NdbTransaction::executeAsynchPrepare and either
Ndb::sendPreparedTransactions or Ndb::sendPollNdb).
- More about how transactions are send the NDB Kernel is
+ More about how transactions are sent the NDB Kernel is
available in section @ref secAdapt.
-
-
- @section secError Error Handling
-
- Errors can occur when
- -# operations are being defined, or when the
- -# transaction is being executed.
-
- One recommended way to handle a transaction failure
- (i.e. an error is reported) is to:
- -# Rollback transaction (NdbConnection::execute with a special parameter)
- -# Close transaction
- -# Restart transaction (if the error was temporary)
-
- @note Transaction are not automatically closed when an error occur.
-
- Several errors can occur when a transaction holds multiple
- operations which are simultaneously executed.
- In this case the application has to go through the operation
- objects and query for their NdbError objects to find out what really
- happened.
-
- NdbConnection::getNdbErrorOperation returns a reference to the
- operation causing the latest error.
- NdbConnection::getNdbErrorLine delivers the method number of the
- erroneous method in the operation.
-
- @code
- theConnection = theNdb->startTransaction();
- theOperation = theConnection->getNdbOperation("TEST_TABLE");
- if (theOperation == NULL) goto error;
- theOperation->readTuple();
- theOperation->setValue("ATTR_1", at1);
- theOperation->setValue("ATTR_2", at1); //Here an error occurs
- theOperation->setValue("ATTR_3", at1);
- theOperation->setValue("ATTR_4", at1);
-
- if (theConnection->execute(Commit) == -1) {
- errorLine = theConnection->getNdbErrorLine();
- errorOperation = theConnection->getNdbErrorOperation();
- @endcode
-
- Here errorLine will be 3 as the error occurred in the third method
- on the operation object.
- Getting errorLine == 0 means that the error occurred when executing the
- operations.
- Here errorOperation will be a pointer to the theOperation object.
- NdbConnection::getNdbError will return the NdbError object
- including holding information about the error.
-
- Since errors could have occurred even when a commit was reported,
- there is also a special method, NdbConnection::commitStatus,
- to check the commit status of the transaction.
-
-*******************************************************************************/
-
-/**
- * @page ndbapi_example1.cpp ndbapi_example1.cpp
- * @include ndbapi_example1.cpp
- */
-
-/**
- * @page ndbapi_example2.cpp ndbapi_example2.cpp
- * @include ndbapi_example2.cpp
- */
-
-/**
- * @page ndbapi_example3.cpp ndbapi_example3.cpp
- * @include ndbapi_example3.cpp
- */
-
-/**
- * @page ndbapi_example4.cpp ndbapi_example4.cpp
- * @include ndbapi_example4.cpp
- */
-
-/**
- * @page select_all.cpp select_all.cpp
- * @include select_all.cpp
- */
-
-/**
- * @page ndbapi_async.cpp ndbapi_async.cpp
- * @include ndbapi_async.cpp
- */
-
-/**
- * @page ndbapi_scan.cpp ndbapi_scan.cpp
- * @include ndbapi_scan.cpp
- */
-
-
-/**
- @page secAdapt Adaptive Send Algorithm
-
- At the time of "sending" the transaction
- (using NdbConnection::execute, NdbConnection::executeAsynch,
- Ndb::sendPreparedTransactions, or Ndb::sendPollNdb), the transactions
- are in reality <em>not</em> immediately transfered to the NDB Kernel.
- Instead, the "sent" transactions are only kept in a
- special send list (buffer) in the Ndb object to which they belong.
- The adaptive send algorithm decides when transactions should
- be transfered to the NDB kernel.
-
- For each of these "sent" transactions, there are three
- possible states:
- -# Waiting to be transfered to NDB Kernel.
- -# Has been transfered to the NDB Kernel and is currently
- being processed.
- -# Has been transfered to the NDB Kernel and has
- finished processing.
- Now it is waiting for a call to a poll method.
- (When the poll method is invoked,
- then the transaction callback method will be executed.)
-
- The poll method invoked (either Ndb::pollNdb or Ndb::sendPollNdb)
- will return when:
- -# at least 'minNoOfEventsToWakeup' of the transactions
- in the send list have transitioned to state 3 as described above, and
- -# all of these transactions have executed their callback methods.
-
-
- Since the NDB API is designed as a multi-threaded interface,
- it is desirable to transfer database operations from more than
- one thread at a time.
- The NDB API keeps track of which Ndb objects are active in transfering
- information to the NDB kernel and the expected amount of threads to
- interact with the NDB kernel.
- Note that an Ndb object should be used in at most one thread.
- Two different threads should <em>not</em> use the same Ndb object.
-
- There are four reasons leading to transfering of database
- operations:
- -# The NDB Transporter (TCP/IP, OSE, SCI or shared memory)
- decides that a buffer is full and sends it off.
- The buffer size is implementation dependent and
- might change between NDB Cluster releases.
- On TCP/IP the buffer size is usually around 64 kByte and
- on OSE/Delta it is usually less than 2000 bytes.
- In each Ndb object there is one buffer per DB node,
- so this criteria of a full buffer is only
- local to the connection to one DB node.
- -# Statistical information on the transfered information
- may force sending of buffers to all DB nodes.
- -# Every 10 ms a special send-thread checks whether
- any send activity has occurred. If not, then the thread will
- force sending to all nodes.
- This means that 20 ms is the maximum time database operations
- are waiting before being sent off. The 10 millisecond limit
- is likely to become a configuration parameter in
- later releases of NDB Cluster.
- However, to support faster than 10 ms checks,
- there has to be support from the operating system.
- -# When calling NdbConnection::execute synchronously or calling any
- of the poll-methods, there is a force parameter that overrides the
- adaptive algorithm and forces the send to all nodes.
-
- @note The times mentioned above are examples. These might
- change in later releases of NDB Cluster.
*/
-
-/**
- @page secConcepts NDB Cluster Concepts
-
- The <em>NDB Kernel</em> is the collection of database (DB) nodes
- belonging to an NDB Cluster.
- The application programmer can for most purposes view the
- set of all DB nodes as one entity.
- Each DB node has three main components:
- - TC : The transaction coordinator
- - ACC : The index storage
- - TUP : The data storage
-
- When the application program executes a transaction,
- it connects to one TC on one DB node.
- Usually, the programmer does not need to specify which TC to use,
- but some cases when performance is important,
- transactions can be hinted to use a certain TC.
- (If the node with the TC is down, then another TC will
- automatically take over the work.)
-
- Every DB node has an ACC and a TUP which stores
- the index and the data part of the database.
- Even though one TC is responsible for the transaction,
- several ACCs and TUPs on other DB nodes might be involved in the
- execution of the transaction.
-
-
- @section secNdbKernelConnection Selecting Transaction Coordinator
- The default method is round robin,
- where each new set of transactions
- is placed on the next DB node.
- The application chooses a TC for a number of transactions
- and then lets the next TC (on the next DB node) carry out
- the next set of transactions.
-
- The application programmer can however hint the NDB API which
- transaction coordinator to use
- by providing a <em>distribution key</em> (usually the primary key).
- By using the primary key as distribution key,
- the transaction will be placed on the node where the primary replica
- of that record resides.
- Note that this is only a hint, the system can be
- reconfigured and then the NDB API will choose a transaction
- coordinator without using the hint.
- For more information, see NdbDictionary::Column::setDistributionKey.
+#endif
- @section secRecordStruct Record Structure
- NDB Cluster is a relational database with tables of records.
- Table rows represent tuples of relational data stored as records.
- When created, the attribute schema of the table is specified,
- and thus each record of the table has the same schema.
+/**
-
- @subsection secKeys Tuple Keys
- Each record has from zero up to four attributes which belong
- to the primary key of the table.
- If no attribute belongs to the primary key, then
- the NDB Cluster creates an attribute named <em>NDB$TID</em>
- which stores a tuple identity.
- The <em>tuple key</em> of a table is thus either
- the primary key attributes or the special NDB$TID attribute.
-
+ Put this back when real array ops are supported
+ i.e. get/setValue("kalle[3]");
@subsection secArrays Array Attributes
- A table attribute in NDB Cluster can be of <em>array type</em>.
- This means that the attribute consists of an array of
- <em>elements</em>. The <em>attribute size</em> is the size
- of one element of the array (expressed in bits) and the
- <em>array size</em> is the number of elements of the array.
-
+ A table attribute in NDB Cluster can be of type <var>Array</var>,
+ meaning that the attribute consists of an ordered sequence of
+ elements. In such cases, <var>attribute size</var> is the size
+ (expressed in bits) of any one element making up the array; the
+ <var>array size</var> is the number of elements in the array.
- @section secTrans Transactions
-
- Transactions are committed to main memory,
- and are committed to disk after a global checkpoint, GCP.
- Since all data is (in most NDB Cluster configurations)
- synchronously replicated and stored on multiple NDB nodes,
- the system can still handle processor failures without loss
- of data.
- However, in the case of a system failure (e.g. the whole system goes down),
- then all (committed or not) transactions after the latest GCP are lost.
-
-
- @subsection secConcur Concurrency Control
- NDB Cluster uses pessimistic concurrency control based on locking.
- If a requested lock (implicit and depending on database operation)
- cannot be attained within a specified time,
- then a timeout error occurs.
-
- Concurrent transactions (parallel application programs, thread-based
- applications, or applications with asynchronous transactions)
- sometimes deadlock when they try to access the same information.
- Applications need to be programmed so that timeout errors
- occurring due to deadlocks are handled. This generally
- means that the transaction encountering timeout
- should be rolled back and restarted.
*/
#ifndef Ndb_H
@@ -870,7 +972,7 @@ class NdbEventOperationImpl;
class NdbScanOperation;
class NdbIndexScanOperation;
class NdbIndexOperation;
-class NdbConnection;
+class NdbTransaction;
class NdbApiSignal;
class NdbRecAttr;
class NdbLabel;
@@ -928,6 +1030,11 @@ typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*);
* Semaphores, mutexes and so forth are easy ways of issuing memory
* barriers without having to bother about the memory barrier concept.
*
+ */
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+// to be documented later
+/*
* If one Ndb object is used to handle parallel transactions through the
* asynchronous programming interface, please read the notes regarding
* asynchronous transactions (Section @ref secAsync).
@@ -938,12 +1045,15 @@ typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*);
* asynchronous transaction or the methods for
* synchronous transactions but not both.
*/
+#endif
+
class Ndb
{
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class NdbReceiver;
friend class NdbOperation;
friend class NdbEventOperationImpl;
- friend class NdbConnection;
+ friend class NdbTransaction;
friend class Table;
friend class NdbApiSignal;
friend class NdbIndexOperation;
@@ -952,6 +1062,7 @@ class Ndb
friend class NdbDictionaryImpl;
friend class NdbDictInterface;
friend class NdbBlob;
+#endif
public:
/**
@@ -959,29 +1070,26 @@ public:
* @{
*/
/**
- * The starting point of your application code is to create an
- * Ndb object.
- * This object represents the NDB kernel and is the main
- * object used in interaction with the NDB kernel.
+ * The Ndb object represents a connection to a database.
*
- * @param aCatalogName is the name of the catalog you want to use.
- * @note The catalog name provides a name space for the tables and
+ * @note The init() method must be called before the Ndb object may actually be used.
+ *
+ * @param ndb_cluster_connection is a connection to the cluster containing
+ * the database to be used
+ * @param aCatalogName is the name of the catalog to be used.
+ * @note The catalog name provides a namespace for the tables and
* indexes created in any connection from the Ndb object.
* @param aSchemaName is the name of the schema you
- * want to use. It is optional and defaults to the "def" schema.
- * @note The schema name provides an additional name space
+ * want to use.
+ * @note The schema name provides an additional namespace
* for the tables and indexes created in a given catalog.
- * @note The methods get/setDatabaseName and get/setDatabaseSchemaName
- * are equivalent to get/setCatalogName and get/setSchemaName.
- * The get/setDatabaseName and get/setDatabaseSchemaName are
- * deprecated.
*/
- Ndb(const char* aCatalogName = "", const char* aSchemaName = "def");
Ndb(Ndb_cluster_connection *ndb_cluster_connection,
const char* aCatalogName = "", const char* aSchemaName = "def");
~Ndb();
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* The current catalog name can be fetched by getCatalogName.
*
@@ -1009,7 +1117,7 @@ public:
* @param aSchemaName is the new name of the current schema
*/
void setSchemaName(const char * aSchemaName);
-
+#endif
/**
* The current database name can be fetched by getDatabaseName.
@@ -1040,22 +1148,21 @@ public:
void setDatabaseSchemaName(const char * aDatabaseSchemaName);
/**
- * Before anything else it is necessary to initialize (start)
- * the Ndb object.
+ * Initializes the Ndb object
*
* @param maxNoOfTransactions
* Maximum number of parallel
- * NdbConnection objects that should be handled by the Ndb object.
- * A value larger than 1024 will be downgraded to 1024.
- * This means that one Ndb object can handle at most 1024 parallel
- * transactions.
- * @return 0 if successful, -1 otherwise.
+ * NdbTransaction objects that can be handled by the Ndb object.
+ * Maximum value is 1024.
+ *
+ * @note each scan or index scan operation uses one extra
+ * NdbTransaction object
*
- * @note The internal implementation multiplies this value
- * with 3.
+ * @return 0 if successful, -1 otherwise.
*/
int init(int maxNoOfTransactions = 4);
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Wait for Ndb object to successfully set-up connections to
* the NDB kernel.
@@ -1068,8 +1175,8 @@ public:
* @return 0: Ndb is ready and timeout has not occurred.<br>
* -1: Timeout has expired
*/
-
int waitUntilReady(int timeout = 60);
+#endif
/** @} *********************************************************************/
@@ -1079,30 +1186,55 @@ public:
*/
/**
- * Query the database for schema information
- * (without performing any transaction).
+ * Get an object for retrieving or manipulating database schema information
+ *
+ * @note this object operates outside any transaction
*
* @return Object containing meta information about all tables
* in NDB Cluster.
*/
class NdbDictionary::Dictionary* getDictionary() const;
+
+ /** @} *********************************************************************/
+
+ /**
+ * @name Event subscriptions
+ * @{
+ */
+
+ /**
+ * Create a subcription to an event defined in the database
+ *
+ * @param eventName
+ * unique identifier of the event
+ * @param bufferLength
+ * circular buffer size for storing event data
+ *
+ * @return Object representing an event, NULL on failure
+ */
NdbEventOperation* createEventOperation(const char* eventName,
const int bufferLength);
- int dropEventOperation(NdbEventOperation*);
- void monitorEvent(NdbEventOperation *, NdbEventCallback, void*);
- int pollEvents(int aMillisecondNumber);
+ /**
+ * Drop a subscription to an event
+ *
+ * @param eventOp
+ * Event operation
+ *
+ * @return 0 on success
+ */
+ int dropEventOperation(NdbEventOperation* eventOp);
/**
- * Get the application node identity.
+ * Wait for an event to occur. Will return as soon as an event
+ * is detected on any of the created events.
*
- * Each node (DB nodes, Applications, and Management Servers)
- * has its own node identity in the NDB Cluster.
- * See documentation for the management server configuration file.
+ * @param aMillisecondNumber
+ * maximum time to wait
*
- * @return Node id of this application.
+ * @return the number of events that has occured, -1 on failure
*/
- int getNodeId();
+ int pollEvents(int aMillisecondNumber);
/** @} *********************************************************************/
@@ -1112,79 +1244,33 @@ public:
*/
/**
- * This method returns an NdbConnection which caters for the transaction.
- * When the transaction is completed it must be closed.
- * The Ndb::closeTransaction also return the NdbConnection object
- * and all other memory related to the transaction.
- * Failure to close the transaction will lead to memory leakage.
- * The transaction must be closed independent of its outcome, i.e.
- * even if there is an error.
- *
- * NDB API can be hinted to select a particular transaction coordinator.
- * The default method is round robin where each set of new transactions
- * is placed on the next NDB kernel node.
- * By providing a distribution key (usually the primary key
- * of the mostly used table of the transaction) for a record
- * the transaction will be placed on the node where the primary replica
- * of that record resides.
- * Note that this is only a hint, the system can
- * be under reconfiguration and then the NDB API
- * will use select the transaction coordinator without using
- * this hint.
- *
- * Placing the transaction coordinator close
- * to the actual data used in the transaction can in many cases
- * improve performance significantly. This is particularly true for
- * systems using TCP/IP. A system using Solaris and a 500 MHz processor
- * has a cost model for TCP/IP communication which is:
- *
- * 30 microseconds + (100 nanoseconds * no of Bytes)
+ * Start a transaction
*
- * This means that if we can ensure that we use "popular" links we increase
- * buffering and thus drastically reduce the communication cost.
- * Systems using SCI has a different cost model which is:
+ * @note When the transaction is completed it must be closed using
+ * Ndb::closeTransaction or NdbTransaction::close.
+ * The transaction must be closed independent of its outcome, i.e.
+ * even if there is an error.
*
- * 5 microseconds + (10 nanoseconds * no of Bytes)
- *
- * Thus SCI systems are much less dependent on selection of
- * transaction coordinators.
- * Typically TCP/IP systems spend 30-60% of the time during communication,
- * whereas SCI systems typically spend 5-10% of the time during
- * communication.
- * Thus SCI means that less care from the NDB API programmer is
- * needed and great scalability can be achieved even for applications using
- * data from many parts of the database.
- *
- * A simple example is an application that uses many simple updates where
- * a transaction needs to update one record.
- * This record has a 32 bit primary key,
- * which is also the distribution key.
- * Then the keyData will be the address of the integer
- * of the primary key and keyLen will be 4.
- *
- * @note Transaction priorities are not yet supported.
- *
- * @param prio The priority of the transaction.<br>
- * Priority 0 is the highest priority and is used
- * for short transactions with requirements on low delay.<br>
- * Priority 1 is a medium priority for short transactions.
- * <br>
- * Priority 2 is a medium priority for long transactions.<br>
- * Priority 3 is a low priority for long transactions.<br>
- * <em>This parameter is not currently used,
- * and can be set to any value</em>
- * @param keyData Pointer to distribution key
- * @param keyLen Length of distribution key expressed in bytes
+ * @param table Pointer to table object used for deciding
+ * which node to run the Transaction Coordinator on
+ * @param keyData Pointer to partition key corresponding to
+ * <var>table</var>
+ * @param keyLen Length of partition key expressed in bytes
*
- * @return NdbConnection object, or NULL if method failed.
+ * @return NdbTransaction object, or NULL on failure.
*/
- NdbConnection* startTransaction(Uint32 prio = 0,
- const char * keyData = 0,
- Uint32 keyLen = 0);
+ NdbTransaction* startTransaction(const NdbDictionary::Table *table= 0,
+ const char *keyData = 0,
+ Uint32 keyLen = 0);
/**
- * When a transactions is completed, the transaction has to be closed.
+ * Close a transaction.
*
+ * @note should be called after the transaction has completed, irrespective
+ * of success or failure
+ */
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ /**
* @note It is not allowed to call Ndb::closeTransaction after sending the
* transaction asynchronously with either
* Ndb::sendPreparedTransactions or
@@ -1194,11 +1280,13 @@ public:
* has completed before calling Ndb::closeTransaction).
* If the transaction is not committed it will be aborted.
*/
- void closeTransaction(NdbConnection* aConnection);
-
+#endif
+ void closeTransaction(NdbTransaction*);
/** @} *********************************************************************/
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ // to be documented later
/**
* @name Asynchronous Transactions
* @{
@@ -1209,11 +1297,10 @@ public:
* Will return as soon as at least 'minNoOfEventsToWakeUp'
* of them have completed, or the maximum time given as timeout has passed.
*
- * @param aMillisecondNumber Maximum time to wait for transactions
- * to complete.
- * Polling without wait is achieved by setting the
- * timer to zero.
- * Time is expressed in milliseconds.
+ * @param aMillisecondNumber
+ * Maximum time to wait for transactions to complete. Polling
+ * without wait is achieved by setting the timer to zero.
+ * Time is expressed in milliseconds.
* @param minNoOfEventsToWakeup Minimum number of transactions
* which has to wake up before the poll-call will return.
* If minNoOfEventsToWakeup is
@@ -1275,9 +1362,9 @@ public:
int sendPollNdb(int aMillisecondNumber = WAITFOR_RESPONSE_TIMEOUT,
int minNoOfEventsToWakeup = 1,
int forceSend = 0);
-
/** @} *********************************************************************/
-
+#endif
+
/**
* @name Error Handling
* @{
@@ -1286,7 +1373,7 @@ public:
/**
* Get the NdbError object
*
- * The NdbError object is valid until you call a new NDB API method.
+ * @note The NdbError object is valid until a new NDB API method is called.
*/
const NdbError & getNdbError() const;
@@ -1298,37 +1385,29 @@ public:
const NdbError & getNdbError(int errorCode);
+ /** @} *********************************************************************/
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
- * setConnectString
- * @param connectString - the connectString has the following format:
- * @code
- * "nodeid=<ID>;host=host://<HOSTNAME>:<PORT>;
- * host=host://<HOSTNAME2>:<PORT>;..."
- * @endcode
- * or
- * @code
- * "nodeid=<ID>;host=<HOSTNAME>:<PORT>;host=<HOSTNAME2>:<PORT>;..."
- * @endcode
+ * Get the application node identity.
+ *
+ * @return Node id of this application.
*/
- static void setConnectString(const char * connectString);
+ int getNodeId();
bool usingFullyQualifiedNames();
- /** @} *********************************************************************/
-
-#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
-
/**
* Different types of tampering with the NDB Cluster.
* <b>Only for debugging purposes only.</b>
*/
enum TamperType {
- LockGlbChp = 1, ///< Lock GCP
- UnlockGlbChp, ///< Unlock GCP
- CrashNode, ///< Crash an NDB node
- ReadRestartGCI, ///< Request the restart GCI id from NDB Cluster
- InsertError ///< Execute an error in NDB Cluster
- ///< (may crash system)
+ LockGlbChp = 1, ///< Lock GCP
+ UnlockGlbChp, ///< Unlock GCP
+ CrashNode, ///< Crash an NDB node
+ ReadRestartGCI, ///< Request the restart GCI id from NDB Cluster
+ InsertError ///< Execute an error in NDB Cluster
+ ///< (may crash system)
};
/**
@@ -1347,9 +1426,7 @@ public:
* on type of tampering.
*/
int NdbTamper(TamperType aAction, int aNode);
-#endif
-#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Return a unique tuple id for a table. The id sequence is
* ascending but may contain gaps.
@@ -1379,12 +1456,10 @@ public:
bool increase);
bool setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase);
Uint64 opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op);
-#endif
-#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
*/
- NdbConnection* hupp( NdbConnection* );
+ NdbTransaction* hupp( NdbTransaction* );
Uint32 getReference() const { return theMyRef;}
#endif
@@ -1399,11 +1474,11 @@ private:
void connected(Uint32 block_reference);
- NdbConnection* startTransactionLocal(Uint32 aPrio, Uint32 aFragmentId);
+ NdbTransaction* startTransactionLocal(Uint32 aPrio, Uint32 aFragmentId);
// Connect the connection object to the Database.
int NDB_connect(Uint32 tNode);
- NdbConnection* doConnect(Uint32 nodeId);
+ NdbTransaction* doConnect(Uint32 nodeId);
void doDisconnect();
NdbReceiver* getNdbScanRec();// Get a NdbScanReceiver from idle list
@@ -1435,8 +1510,8 @@ private:
void check_send_timeout();
void remove_sent_list(Uint32);
- Uint32 insert_completed_list(NdbConnection*);
- Uint32 insert_sent_list(NdbConnection*);
+ Uint32 insert_completed_list(NdbTransaction*);
+ Uint32 insert_sent_list(NdbTransaction*);
// Handle a received signal. Used by both
// synchronous and asynchronous interface
@@ -1476,20 +1551,20 @@ private:
void freeNdbScanRec(); // Free the first idle NdbScanRec obj
void freeNdbBlob(); // Free the first etc
- NdbConnection* getNdbCon(); // Get a connection from idle list
+ NdbTransaction* getNdbCon(); // Get a connection from idle list
/**
- * Get a connected NdbConnection to nodeId
+ * Get a connected NdbTransaction to nodeId
* Returns NULL if none found
*/
- NdbConnection* getConnectedNdbConnection(Uint32 nodeId);
+ NdbTransaction* getConnectedNdbTransaction(Uint32 nodeId);
// Release and disconnect from DBTC a connection
// and seize it to theConIdleList
- void releaseConnectToNdb (NdbConnection* aConnectConnection);
+ void releaseConnectToNdb (NdbTransaction*);
// Release a connection to idle list
- void releaseNdbCon (NdbConnection* aConnection);
+ void releaseNdbCon (NdbTransaction*);
int checkInitState(); // Check that we are initialized
void report_node_failure(Uint32 node_id); // Report Failed node
@@ -1499,15 +1574,15 @@ private:
int NDB_connect(); // Perform connect towards NDB Kernel
- // Release arrays of NdbConnection pointers
+ // Release arrays of NdbTransaction pointers
void releaseTransactionArrays();
- Uint32 pollCompleted(NdbConnection** aCopyArray);
+ Uint32 pollCompleted(NdbTransaction** aCopyArray);
void sendPrepTrans(int forceSend);
- void reportCallback(NdbConnection** aCopyArray, Uint32 aNoOfComplTrans);
+ void reportCallback(NdbTransaction** aCopyArray, Uint32 aNoOfComplTrans);
void waitCompletedTransactions(int milliSecs, int noOfEventsToWaitFor);
- void completedTransaction(NdbConnection* aTransaction);
- void completedScanTransaction(NdbConnection* aTransaction);
+ void completedTransaction(NdbTransaction* aTransaction);
+ void completedScanTransaction(NdbTransaction* aTransaction);
void abortTransactionsAfterNodeFailure(Uint16 aNodeId);
@@ -1529,16 +1604,16 @@ private:
void* int2void (Uint32 val);
NdbReceiver* void2rec (void* val);
- NdbConnection* void2con (void* val);
+ NdbTransaction* void2con (void* val);
NdbOperation* void2rec_op (void* val);
NdbIndexOperation* void2rec_iop (void* val);
/******************************************************************************
* These are the private variables in this class.
*****************************************************************************/
- NdbConnection** thePreparedTransactionsArray;
- NdbConnection** theSentTransactionsArray;
- NdbConnection** theCompletedTransactionsArray;
+ NdbTransaction** thePreparedTransactionsArray;
+ NdbTransaction** theSentTransactionsArray;
+ NdbTransaction** theCompletedTransactionsArray;
Uint32 theNoOfPreparedTransactions;
Uint32 theNoOfSentTransactions;
@@ -1562,21 +1637,21 @@ private:
class NdbDictionaryImpl* theDictionary;
class NdbGlobalEventBufferHandle* theGlobalEventBufferHandle;
- NdbConnection* theConIdleList; // First connection in idle list.
+ NdbTransaction* theConIdleList; // First connection in idle list.
NdbOperation* theOpIdleList; // First operation in the idle list.
NdbIndexScanOperation* theScanOpIdleList; // First scan operation in the idle list.
NdbIndexOperation* theIndexOpIdleList; // First index operation in the idle list.
- NdbConnection* theTransactionList;
- NdbConnection** theConnectionArray;
+ NdbTransaction* theTransactionList;
+ NdbTransaction** theConnectionArray;
NdbRecAttr* theRecAttrIdleList;
NdbApiSignal* theSignalIdleList; // First signal in idlelist.
NdbLabel* theLabelList; // First label descriptor in list
NdbBranch* theBranchList; // First branch descriptor in list
NdbSubroutine* theSubroutineList; // First subroutine descriptor in
NdbCall* theCallList; // First call descriptor in list
- NdbReceiver* theScanList;
+ NdbReceiver* theScanList;
NdbBlob* theNdbBlobIdleList;
Uint32 theMyRef; // My block reference
diff --git a/ndb/include/ndbapi/NdbApi.hpp b/ndb/include/ndbapi/NdbApi.hpp
index ae7025f560a..aed4d5efbd7 100644
--- a/ndb/include/ndbapi/NdbApi.hpp
+++ b/ndb/include/ndbapi/NdbApi.hpp
@@ -21,14 +21,13 @@
#include "ndb_cluster_connection.hpp"
#include "ndbapi_limits.h"
#include "Ndb.hpp"
-#include "NdbConnection.hpp"
+#include "NdbTransaction.hpp"
#include "NdbOperation.hpp"
#include "NdbScanOperation.hpp"
#include "NdbIndexOperation.hpp"
#include "NdbIndexScanOperation.hpp"
#include "NdbScanFilter.hpp"
#include "NdbRecAttr.hpp"
-#include "NdbResultSet.hpp"
#include "NdbDictionary.hpp"
#include "NdbEventOperation.hpp"
#include "NdbPool.hpp"
diff --git a/ndb/include/ndbapi/NdbBlob.hpp b/ndb/include/ndbapi/NdbBlob.hpp
index b145c69b04b..271287b765c 100644
--- a/ndb/include/ndbapi/NdbBlob.hpp
+++ b/ndb/include/ndbapi/NdbBlob.hpp
@@ -19,11 +19,11 @@
#include <ndb_types.h>
#include <NdbDictionary.hpp>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <NdbError.hpp>
class Ndb;
-class NdbConnection;
+class NdbTransaction;
class NdbOperation;
class NdbRecAttr;
class NdbTableImpl;
@@ -67,7 +67,7 @@ class NdbColumnImpl;
* cases NdbBlob is forced to do implicit executes. To avoid this,
* operate on complete blob parts.
*
- * Use NdbConnection::executePendingBlobOps to flush your reads and
+ * Use NdbTransaction::executePendingBlobOps to flush your reads and
* writes. It avoids execute penalty if nothing is pending. It is not
* needed after execute (obviously) or after next scan result.
*
@@ -88,8 +88,13 @@ class NdbColumnImpl;
* - lock mode vs allowed operation is not checked
* - too many pending blob ops can blow up i/o buffers
* - table and its blob part tables are not created atomically
+ */
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+/**
* - there is no support for an asynchronous interface
*/
+#endif
+
class NdbBlob {
public:
/**
@@ -102,6 +107,9 @@ public:
Closed = 3,
Invalid = 9
};
+ /**
+ * Get the state of a NdbBlob object.
+ */
State getState();
/**
* Inline blob header.
@@ -111,7 +119,7 @@ public:
};
/**
* Prepare to read blob value. The value is available after execute.
- * Use getNull to check for NULL and getLength to get the real length
+ * Use getNull() to check for NULL and getLength() to get the real length
* and to check for truncation. Sets current read/write position to
* after the data read.
*/
@@ -124,10 +132,10 @@ public:
*/
int setValue(const void* data, Uint32 bytes);
/**
- * Callback for setActiveHook. Invoked immediately when the prepared
- * operation has been executed (but not committed). Any getValue or
- * setValue is done first. The blob handle is active so readData or
- * writeData etc can be used to manipulate blob value. A user-defined
+ * Callback for setActiveHook(). Invoked immediately when the prepared
+ * operation has been executed (but not committed). Any getValue() or
+ * setValue() is done first. The blob handle is active so readData or
+ * writeData() etc can be used to manipulate blob value. A user-defined
* argument is passed along. Returns non-zero on error.
*/
typedef int ActiveHook(NdbBlob* me, void* arg);
@@ -190,19 +198,26 @@ public:
const NdbError& getNdbError() const;
/**
* Return info about all blobs in this operation.
+ *
+ * Get first blob in list.
*/
- // Get first blob in list
NdbBlob* blobsFirstBlob();
- // Get next blob in list after this one
+ /**
+ * Return info about all blobs in this operation.
+ *
+ * Get next blob in list. Initialize with blobsFirstBlob().
+ */
NdbBlob* blobsNextBlob();
private:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class Ndb;
- friend class NdbConnection;
+ friend class NdbTransaction;
friend class NdbOperation;
friend class NdbScanOperation;
friend class NdbDictionaryImpl;
friend class NdbResultSet; // atNextResult
+#endif
// state
State theState;
void setState(State newState);
@@ -211,7 +226,7 @@ private:
static void getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c);
// ndb api stuff
Ndb* theNdb;
- NdbConnection* theNdbCon;
+ NdbTransaction* theNdbCon;
NdbOperation* theNdbOp;
const NdbTableImpl* theTable;
const NdbTableImpl* theAccessTable;
@@ -301,15 +316,15 @@ private:
// callbacks
int invokeActiveHook();
// blob handle maintenance
- int atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn);
- int preExecute(ExecType anExecType, bool& batch);
- int postExecute(ExecType anExecType);
+ int atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn);
+ int preExecute(NdbTransaction::ExecType anExecType, bool& batch);
+ int postExecute(NdbTransaction::ExecType anExecType);
int preCommit();
int atNextResult();
// errors
void setErrorCode(int anErrorCode, bool invalidFlag = true);
void setErrorCode(NdbOperation* anOp, bool invalidFlag = true);
- void setErrorCode(NdbConnection* aCon, bool invalidFlag = true);
+ void setErrorCode(NdbTransaction* aCon, bool invalidFlag = true);
#ifdef VM_TRACE
int getOperationType() const;
friend class NdbOut& operator<<(NdbOut&, const NdbBlob&);
diff --git a/ndb/include/ndbapi/NdbDictionary.hpp b/ndb/include/ndbapi/NdbDictionary.hpp
index 0e4f506c604..86130be4c4b 100644
--- a/ndb/include/ndbapi/NdbDictionary.hpp
+++ b/ndb/include/ndbapi/NdbDictionary.hpp
@@ -14,18 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*****************************************************************************
- * Name: NdbDictionary.hpp
- * Include:
- * Link:
- * Author: Jonas Oreland
- * Date: 2003-05-14
- * Version: 0.1
- * Description: Data dictionary support
- * Documentation:
- * Adjust: 2003-05-14 Jonas Oreland First version.
- ****************************************************************************/
-
#ifndef NdbDictionary_H
#define NdbDictionary_H
@@ -39,11 +27,17 @@ typedef struct charset_info_st CHARSET_INFO;
* @class NdbDictionary
* @brief Data dictionary class
*
- * This class supports all schema data definition and enquiry such as:
- * -# Creating tables (Dictionary::createTable) and table columns
- * -# Dropping tables (Dictionary::dropTable)
- * -# Creating secondary indexes (Dictionary::createIndex)
- * -# Dropping secondary indexes (Dictionary::dropIndex)
+ * The preferred and supported way to create and drop tables and indexes
+ * in ndb is through the
+ * MySQL Server (see MySQL reference Manual, section MySQL Cluster).
+ *
+ * Tables and indexes that are created directly through the
+ * NdbDictionary class
+ * can not be viewed from the MySQL Server.
+ * Dropping indexes directly via the NdbApi will cause inconsistencies
+ * if they were originally created from a MySQL Cluster.
+ *
+ * This class supports schema data enquiries such as:
* -# Enquiries about tables
* (Dictionary::getTable, Table::getNoOfColumns,
* Table::getPrimaryKey, and Table::getNoOfPrimaryKeys)
@@ -51,12 +45,19 @@ typedef struct charset_info_st CHARSET_INFO;
* (Dictionary::getIndex, Index::getNoOfColumns,
* and Index::getColumn)
*
- * NdbDictionary has several help (inner) classes:
+ * This class supports schema data definition such as:
+ * -# Creating tables (Dictionary::createTable) and table columns
+ * -# Dropping tables (Dictionary::dropTable)
+ * -# Creating secondary indexes (Dictionary::createIndex)
+ * -# Dropping secondary indexes (Dictionary::dropIndex)
+ *
+ * NdbDictionary has several help (inner) classes to support this:
+ * -# NdbDictionary::Dictionary the dictionary handling dictionary objects
* -# NdbDictionary::Table for creating tables
* -# NdbDictionary::Column for creating table columns
* -# NdbDictionary::Index for creating secondary indexes
- *
- * See @ref ndbapi_example4.cpp for details of usage.
+ *
+ * See @ref ndbapi_simple_index.cpp for details of usage.
*/
class NdbDictionary {
public:
@@ -100,8 +101,6 @@ public:
SystemTable = 1, ///< System table
UserTable = 2, ///< User table (may be temporary)
UniqueHashIndex = 3, ///< Unique un-ordered hash index
- HashIndex = 4, ///< Non-unique un-ordered hash index
- UniqueOrderedIndex = 5, ///< Unique ordered index
OrderedIndex = 6, ///< Non-unique ordered index
HashIndexTrigger = 7, ///< Index maintenance, internal
IndexTrigger = 8, ///< Index maintenance, internal
@@ -154,14 +153,20 @@ public:
/**
* @class Column
- * @brief Represents an column in an NDB Cluster table
+ * @brief Represents a column in an NDB Cluster table
*
- * Each column has a type. The type of a column is determind by a number
+ * Each column has a type. The type of a column is determined by a number
* of type specifiers.
* The type specifiers are:
* - Builtin type
* - Array length or max length
- * - Precision and scale
+ * - Precision and scale (not used yet)
+ * - Character set for string types
+ * - Inline and part sizes for blobs
+ *
+ * Types in general correspond to MySQL types and their variants.
+ * Data formats are same as in MySQL. NDB API provides no support for
+ * constructing such formats. NDB kernel checks them however.
*/
class Column {
public:
@@ -169,78 +174,56 @@ public:
* The builtin column types
*/
enum Type {
- Undefined=0,///< Undefined
- Tinyint, ///< 8 bit. 1 byte signed integer, can be used in array
- Tinyunsigned, ///< 8 bit. 1 byte unsigned integer, can be used in array
- Smallint, ///< 16 bit. 2 byte signed integer, can be used in array
- Smallunsigned, ///< 16 bit. 2 byte unsigned integer, can be used in array
- Mediumint, ///< 24 bit. 3 byte signed integer, can be used in array
- Mediumunsigned,///< 24 bit. 3 byte unsigned integer, can be used in array
- Int, ///< 32 bit. 4 byte signed integer, can be used in array
- Unsigned, ///< 32 bit. 4 byte unsigned integer, can be used in array
- Bigint, ///< 64 bit. 8 byte signed integer, can be used in array
- Bigunsigned, ///< 64 Bit. 8 byte signed integer, can be used in array
- Float, ///< 32-bit float. 4 bytes float, can be used in array
- Double, ///< 64-bit float. 8 byte float, can be used in array
- Olddecimal, ///< MySQL < 5.0 signed decimal, Precision, Scale
- Char, ///< Len. A fixed array of 1-byte chars
- Varchar, ///< Max len
- Binary, ///< Len
- Varbinary, ///< Max len
- Datetime, ///< Precision down to 1 sec (sizeof(Datetime) == 8 bytes )
- Date, ///< Precision down to 1 day(sizeof(Date) == 4 bytes )
- Blob, ///< Binary large object (see NdbBlob)
- Text, ///< Text blob
- Time = 25, ///< Time without date
- Year = 26, ///< Year 1901-2155 (1 byte)
- Timestamp = 27, ///< Unix time
- Olddecimalunsigned = 28
+ Undefined = NDB_TYPE_UNDEFINED, ///< Undefined
+ Tinyint = NDB_TYPE_TINYINT, ///< 8 bit. 1 byte signed integer, can be used in array
+ Tinyunsigned = NDB_TYPE_TINYUNSIGNED, ///< 8 bit. 1 byte unsigned integer, can be used in array
+ Smallint = NDB_TYPE_SMALLINT, ///< 16 bit. 2 byte signed integer, can be used in array
+ Smallunsigned = NDB_TYPE_SMALLUNSIGNED, ///< 16 bit. 2 byte unsigned integer, can be used in array
+ Mediumint = NDB_TYPE_MEDIUMINT, ///< 24 bit. 3 byte signed integer, can be used in array
+ Mediumunsigned = NDB_TYPE_MEDIUMUNSIGNED,///< 24 bit. 3 byte unsigned integer, can be used in array
+ Int = NDB_TYPE_INT, ///< 32 bit. 4 byte signed integer, can be used in array
+ Unsigned = NDB_TYPE_UNSIGNED, ///< 32 bit. 4 byte unsigned integer, can be used in array
+ Bigint = NDB_TYPE_BIGINT, ///< 64 bit. 8 byte signed integer, can be used in array
+ Bigunsigned = NDB_TYPE_BIGUNSIGNED, ///< 64 Bit. 8 byte signed integer, can be used in array
+ Float = NDB_TYPE_FLOAT, ///< 32-bit float. 4 bytes float, can be used in array
+ Double = NDB_TYPE_DOUBLE, ///< 64-bit float. 8 byte float, can be used in array
+ Olddecimal = NDB_TYPE_OLDDECIMAL, ///< MySQL < 5.0 signed decimal, Precision, Scale
+ Olddecimalunsigned = NDB_TYPE_OLDDECIMALUNSIGNED,
+ Decimal = NDB_TYPE_DECIMAL, ///< MySQL >= 5.0 signed decimal, Precision, Scale
+ Decimalunsigned = NDB_TYPE_DECIMALUNSIGNED,
+ Char = NDB_TYPE_CHAR, ///< Len. A fixed array of 1-byte chars
+ Varchar = NDB_TYPE_VARCHAR, ///< Length bytes: 1, Max: 255
+ Binary = NDB_TYPE_BINARY, ///< Len
+ Varbinary = NDB_TYPE_VARBINARY, ///< Length bytes: 1, Max: 255
+ Datetime = NDB_TYPE_DATETIME, ///< Precision down to 1 sec (sizeof(Datetime) == 8 bytes )
+ Date = NDB_TYPE_DATE, ///< Precision down to 1 day(sizeof(Date) == 4 bytes )
+ Blob = NDB_TYPE_BLOB, ///< Binary large object (see NdbBlob)
+ Text = NDB_TYPE_TEXT, ///< Text blob
+ Bit = NDB_TYPE_BIT, ///< Bit, length specifies no of bits
+ Longvarchar = NDB_TYPE_LONGVARCHAR, ///< Length bytes: 2, little-endian
+ Longvarbinary = NDB_TYPE_LONGVARBINARY, ///< Length bytes: 2, little-endian
+ Time = NDB_TYPE_TIME, ///< Time without date
+ Year = NDB_TYPE_YEAR, ///< Year 1901-2155 (1 byte)
+ Timestamp = NDB_TYPE_TIMESTAMP ///< Unix time
};
/**
* @name General
* @{
*/
- /**
- * Constructor
- * @param name Name of column
- */
- Column(const char * name = "");
- /**
- * Copy constructor
- * @param column Column to be copied
- */
- Column(const Column& column);
- ~Column();
/**
- * Set name of column
- * @param name Name of the column
- */
- void setName(const char * name);
-
- /**
* Get name of column
* @return Name of the column
*/
const char* getName() const;
/**
- * Set whether column is nullable or not
- */
- void setNullable(bool);
-
- /**
* Get if the column is nullable or not
*/
bool getNullable() const;
/**
- * Set that column is part of primary key
- */
- void setPrimaryKey(bool);
-
- /**
* Check if column is part of primary key
*/
bool getPrimaryKey() const;
@@ -257,92 +240,62 @@ public:
*/
bool equal(const Column& column) const;
+
/** @} *******************************************************************/
/**
- * @name Type Specifiers
+ * @name Get Type Specifiers
* @{
*/
/**
- * Set type of column
- * @param type Type of column
- *
- * @note setType resets <em>all</em> column attributes
- * to (type dependent) defaults and should be the first
- * method to call. Default type is Unsigned.
- */
- void setType(Type type);
-
- /**
* Get type of column
*/
Type getType() const;
/**
- * Set precision of column.
- * @note Only applicable for decimal types
- */
- void setPrecision(int);
-
- /**
* Get precision of column.
* @note Only applicable for decimal types
*/
int getPrecision() const;
/**
- * Set scale of column.
- * @note Only applicable for decimal types
- */
- void setScale(int);
-
- /**
* Get scale of column.
* @note Only applicable for decimal types
*/
int getScale() const;
/**
- * Set length for column
- * Array length for column or max length for variable length arrays.
- */
- void setLength(int length);
-
- /**
* Get length for column
* Array length for column or max length for variable length arrays.
*/
int getLength() const;
/**
- * For Char or Varchar or Text, set or get MySQL CHARSET_INFO. This
+ * For Char or Varchar or Text, get MySQL CHARSET_INFO. This
* specifies both character set and collation. See get_charset()
* etc in MySQL. (The cs is not "const" in MySQL).
*/
- void setCharset(CHARSET_INFO* cs);
CHARSET_INFO* getCharset() const;
+
/**
- * For blob, set or get "inline size" i.e. number of initial bytes
+ * For blob, get "inline size" i.e. number of initial bytes
* to store in table's blob attribute. This part is normally in
* main memory and can be indexed and interpreted.
*/
- void setInlineSize(int size);
int getInlineSize() const;
/**
- * For blob, set or get "part size" i.e. number of bytes to store in
+ * For blob, get "part size" i.e. number of bytes to store in
* each tuple of the "blob table". Can be set to zero to omit parts
* and to allow only inline bytes ("tinyblob").
*/
- void setPartSize(int size);
int getPartSize() const;
/**
* For blob, set or get "stripe size" i.e. number of consecutive
* <em>parts</em> to store in each node group.
*/
- void setStripeSize(int size);
int getStripeSize() const;
/**
@@ -351,64 +304,162 @@ public:
int getSize() const;
/**
- * Set distribution key
+ * Check if column is part of partition key
*
- * A <em>distribution key</em> is a set of attributes which are used
+ * A <em>partition key</em> is a set of attributes which are used
* to distribute the tuples onto the NDB nodes.
- * The distribution key uses the NDB Cluster hashing function.
+ * The partition key uses the NDB Cluster hashing function.
*
* An example where this is useful is TPC-C where it might be
- * good to use the warehouse id and district id as the distribution key.
+ * good to use the warehouse id and district id as the partition key.
* This would place all data for a specific district and warehouse
* in the same database node.
*
* Locally in the fragments the full primary key
* will still be used with the hashing algorithm.
*
- * @param enable If set to true, then the column will be part of
- * the distribution key.
+ * @return true then the column is part of
+ * the partition key.
+ */
+ bool getPartitionKey() const;
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ inline bool getDistributionKey() const { return getPartitionKey(); };
+#endif
+
+ /** @} *******************************************************************/
+
+
+ /**
+ * @name Column creation
+ * @{
+ *
+ * These operations should normally not be performed in an NbdApi program
+ * as results will not be visable in the MySQL Server
+ *
*/
- void setDistributionKey(bool enable);
/**
- * Check if column is part of distribution key
- * @see setDistributionKey
+ * Constructor
+ * @param name Name of column
*/
- bool getDistributionKey() const;
- /** @} *******************************************************************/
+ Column(const char * name = "");
+ /**
+ * Copy constructor
+ * @param column Column to be copied
+ */
+ Column(const Column& column);
+ ~Column();
-#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
- void setTupleKey(bool);
- bool getTupleKey() const;
-
- void setDistributionGroup(bool, int bits = 16);
- bool getDistributionGroup() const;
- int getDistributionGroupBits() const;
-
- void setIndexOnlyStorage(bool);
- bool getIndexOnlyStorage() const;
+ /**
+ * Set name of column
+ * @param name Name of the column
+ */
+ void setName(const char * name);
- const Table * getBlobTable() const;
+ /**
+ * Set whether column is nullable or not
+ */
+ void setNullable(bool);
+
+ /**
+ * Set that column is part of primary key
+ */
+ void setPrimaryKey(bool);
+
+ /**
+ * Set type of column
+ * @param type Type of column
+ *
+ * @note setType resets <em>all</em> column attributes
+ * to (type dependent) defaults and should be the first
+ * method to call. Default type is Unsigned.
+ */
+ void setType(Type type);
+
+ /**
+ * Set precision of column.
+ * @note Only applicable for decimal types
+ */
+ void setPrecision(int);
+
+ /**
+ * Set scale of column.
+ * @note Only applicable for decimal types
+ */
+ void setScale(int);
+
+ /**
+ * Set length for column
+ * Array length for column or max length for variable length arrays.
+ */
+ void setLength(int length);
+
+ /**
+ * For Char or Varchar or Text, get MySQL CHARSET_INFO. This
+ * specifies both character set and collation. See get_charset()
+ * etc in MySQL. (The cs is not "const" in MySQL).
+ */
+ void setCharset(CHARSET_INFO* cs);
+
+ /**
+ * For blob, get "inline size" i.e. number of initial bytes
+ * to store in table's blob attribute. This part is normally in
+ * main memory and can be indexed and interpreted.
+ */
+ void setInlineSize(int size);
+
+ /**
+ * For blob, get "part size" i.e. number of bytes to store in
+ * each tuple of the "blob table". Can be set to zero to omit parts
+ * and to allow only inline bytes ("tinyblob").
+ */
+ void setPartSize(int size);
+
+ /**
+ * For blob, get "stripe size" i.e. number of consecutive
+ * <em>parts</em> to store in each node group.
+ */
+ void setStripeSize(int size);
/**
- * @name ODBC Specific methods
- * @{
+ * Set partition key
+ * @see getPartitionKey
+ *
+ * @param enable If set to true, then the column will be part of
+ * the partition key.
*/
- void setAutoIncrement(bool);
+ void setPartitionKey(bool enable);
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ inline void setDistributionKey(bool enable)
+ { setPartitionKey(enable); };
+#endif
+
+ /** @} *******************************************************************/
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ const Table * getBlobTable() const;
+
+ void setAutoIncrement(bool);
bool getAutoIncrement() const;
void setAutoIncrementInitialValue(Uint64 val);
void setDefaultValue(const char*);
const char* getDefaultValue() const;
- /** @} *******************************************************************/
static const Column * FRAGMENT;
+ static const Column * FRAGMENT_MEMORY;
static const Column * ROW_COUNT;
static const Column * COMMIT_COUNT;
+ static const Column * ROW_SIZE;
+ static const Column * RANGE_NO;
+
+ int getSizeInBytes() const;
#endif
private:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class NdbRecAttr;
friend class NdbColumnImpl;
+#endif
class NdbColumnImpl & m_impl;
Column(NdbColumnImpl&);
Column& operator=(const Column&);
@@ -446,30 +497,6 @@ public:
* @name General
* @{
*/
- /**
- * Constructor
- * @param name Name of table
- */
- Table(const char * name = "");
-
- /**
- * Copy constructor
- * @param table Table to be copied
- */
- Table(const Table& table);
- virtual ~Table();
-
- /**
- * Assignment operator, deep copy
- * @param table Table to be copied
- */
- Table& operator=(const Table&);
-
- /**
- * Name of table
- * @param name Name of table
- */
- void setName(const char * name);
/**
* Get table name
@@ -482,12 +509,6 @@ public:
int getTableId() const;
/**
- * Add a column definition to a table
- * @note creates a copy
- */
- void addColumn(const Column &);
-
- /**
* Get column definition via name.
* @return null if none existing name
*/
@@ -528,17 +549,7 @@ public:
* The default value is true and indicates a normal table
* with full checkpointing and logging activated.
*/
- void setLogging(bool);
-
- /**
- * @see NdbDictionary::Table::setLogging.
- */
bool getLogging() const;
-
- /**
- * Set fragmentation type
- */
- void setFragmentType(FragmentType);
/**
* Get fragmentation type
@@ -546,13 +557,6 @@ public:
FragmentType getFragmentType() const;
/**
- * Set KValue (Hash parameter.)
- * Only allowed value is 6.
- * Later implementations might add flexibility in this parameter.
- */
- void setKValue(int kValue);
-
- /**
* Get KValue (Hash parameter.)
* Only allowed value is 6.
* Later implementations might add flexibility in this parameter.
@@ -560,15 +564,6 @@ public:
int getKValue() const;
/**
- * Set MinLoadFactor (Hash parameter.)
- * This value specifies the load factor when starting to shrink
- * the hash table.
- * It must be smaller than MaxLoadFactor.
- * Both these factors are given in percentage.
- */
- void setMinLoadFactor(int);
-
- /**
* Get MinLoadFactor (Hash parameter.)
* This value specifies the load factor when starting to shrink
* the hash table.
@@ -578,16 +573,6 @@ public:
int getMinLoadFactor() const;
/**
- * Set MaxLoadFactor (Hash parameter.)
- * This value specifies the load factor when starting to split
- * the containers in the local hash tables.
- * 100 is the maximum which will optimize memory usage.
- * A lower figure will store less information in each container and thus
- * find the key faster but consume more memory.
- */
- void setMaxLoadFactor(int);
-
- /**
* Get MaxLoadFactor (Hash parameter.)
* This value specifies the load factor when starting to split
* the containers in the local hash tables.
@@ -629,15 +614,83 @@ public:
const void* getFrmData() const;
Uint32 getFrmLength() const;
+ /** @} *******************************************************************/
+
+ /**
+ * @name Table creation
+ * @{
+ *
+ * These methods should normally not be used in an application as
+ * the result is not accessible from the MySQL Server
+ *
+ */
+
/**
- * Set frm file to store with this table
- */
- void setFrm(const void* data, Uint32 len);
+ * Constructor
+ * @param name Name of table
+ */
+ Table(const char * name = "");
+ /**
+ * Copy constructor
+ * @param table Table to be copied
+ */
+ Table(const Table& table);
+ virtual ~Table();
+
/**
- * Set table object type
+ * Assignment operator, deep copy
+ * @param table Table to be copied
*/
- void setObjectType(Object::Type type);
+ Table& operator=(const Table& table);
+
+ /**
+ * Name of table
+ * @param name Name of table
+ */
+ void setName(const char * name);
+
+ /**
+ * Add a column definition to a table
+ * @note creates a copy
+ */
+ void addColumn(const Column &);
+
+ /**
+ * @see NdbDictionary::Table::getLogging.
+ */
+ void setLogging(bool);
+
+ /**
+ * Set fragmentation type
+ */
+ void setFragmentType(FragmentType);
+
+ /**
+ * Set KValue (Hash parameter.)
+ * Only allowed value is 6.
+ * Later implementations might add flexibility in this parameter.
+ */
+ void setKValue(int kValue);
+
+ /**
+ * Set MinLoadFactor (Hash parameter.)
+ * This value specifies the load factor when starting to shrink
+ * the hash table.
+ * It must be smaller than MaxLoadFactor.
+ * Both these factors are given in percentage.
+ */
+ void setMinLoadFactor(int);
+
+ /**
+ * Set MaxLoadFactor (Hash parameter.)
+ * This value specifies the load factor when starting to split
+ * the containers in the local hash tables.
+ * 100 is the maximum which will optimize memory usage.
+ * A lower figure will store less information in each container and thus
+ * find the key faster but consume more memory.
+ */
+ void setMaxLoadFactor(int);
/**
* Get table object type
@@ -654,18 +707,32 @@ public:
*/
virtual int getObjectVersion() const;
+ /**
+ * Set frm file to store with this table
+ */
+ void setFrm(const void* data, Uint32 len);
+
+ /**
+ * Set table object type
+ */
+ void setObjectType(Object::Type type);
+
/** @} *******************************************************************/
-#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
void setStoredTable(bool x) { setLogging(x); }
bool getStoredTable() const { return getLogging(); }
int getRowSizeInBytes() const ;
int createTableInDb(Ndb*, bool existingEqualIsOk = true) const ;
+
+ int getReplicaCount() const ;
#endif
private:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class NdbTableImpl;
+#endif
class NdbTableImpl & m_impl;
Table(NdbTableImpl&);
};
@@ -676,29 +743,18 @@ public:
*/
class Index : public Object {
public:
- /**
- * Constructor
- * @param name Name of index
+
+ /**
+ * @name Getting Index properties
+ * @{
*/
- Index(const char * name = "");
- virtual ~Index();
/**
- * Set the name of an index
- */
- void setName(const char * name);
-
- /**
* Get the name of an index
*/
const char * getName() const;
/**
- * Define the name of the table to be indexed
- */
- void setTable(const char * name);
-
- /**
* Get the name of the table being indexed
*/
const char * getTable() const;
@@ -708,22 +764,89 @@ public:
*/
unsigned getNoOfColumns() const;
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Get the number of columns in the index
* Depricated, use getNoOfColumns instead.
*/
int getNoOfIndexColumns() const;
+#endif
/**
* Get a specific column in the index
*/
const Column * getColumn(unsigned no) const ;
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Get a specific column name in the index
* Depricated, use getColumn instead.
*/
const char * getIndexColumn(int no) const ;
+#endif
+
+ /**
+ * Represents type of index
+ */
+ enum Type {
+ Undefined = 0, ///< Undefined object type (initial value)
+ UniqueHashIndex = 3, ///< Unique un-ordered hash index
+ ///< (only one currently supported)
+ OrderedIndex = 6 ///< Non-unique ordered index
+ };
+
+ /**
+ * Get index type of the index
+ */
+ Type getType() const;
+
+ /**
+ * Check if index is set to be stored on disk
+ *
+ * @return if true then logging id enabled
+ *
+ * @note Non-logged indexes are rebuilt at system restart.
+ * @note Ordered index does not currently support logging.
+ */
+ bool getLogging() const;
+
+ /**
+ * Get object status
+ */
+ virtual Object::Status getObjectStatus() const;
+
+ /**
+ * Get object version
+ */
+ virtual int getObjectVersion() const;
+
+ /** @} *******************************************************************/
+
+ /**
+ * @name Index creation
+ * @{
+ *
+ * These methods should normally not be used in an application as
+ * the result will not be visible from the MySQL Server
+ *
+ */
+
+ /**
+ * Constructor
+ * @param name Name of index
+ */
+ Index(const char * name = "");
+ virtual ~Index();
+
+ /**
+ * Set the name of an index
+ */
+ void setName(const char * name);
+
+ /**
+ * Define the name of the table to be indexed
+ */
+ void setTable(const char * name);
/**
* Add a column to the index definition
@@ -739,6 +862,7 @@ public:
*/
void addColumnName(const char * name);
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Add a column name to the index definition
* Note that the order of indexes will be in
@@ -746,6 +870,7 @@ public:
* Depricated, use addColumnName instead.
*/
void addIndexColumn(const char * name);
+#endif
/**
* Add several column names to the index definition
@@ -754,6 +879,7 @@ public:
*/
void addColumnNames(unsigned noOfNames, const char ** names);
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Add several column names to the index definition
* Note that the order of indexes will be in
@@ -761,18 +887,7 @@ public:
* Depricated, use addColumnNames instead.
*/
void addIndexColumns(int noOfNames, const char ** names);
-
- /**
- * Represents type of index
- */
- enum Type {
- Undefined = 0, ///< Undefined object type (initial value)
- UniqueHashIndex = 3, ///< Unique un-ordered hash index
- ///< (only one currently supported)
- HashIndex = 4, ///< Non-unique un-ordered hash index
- UniqueOrderedIndex = 5, ///< Unique ordered index
- OrderedIndex = 6 ///< Non-unique ordered index
- };
+#endif
/**
* Set index type of the index
@@ -780,47 +895,25 @@ public:
void setType(Type type);
/**
- * Get index type of the index
- */
- Type getType() const;
-
- /**
* Enable/Disable index storage on disk
*
* @param enable If enable is set to true, then logging becomes enabled
*
- * @see NdbDictionary::Table::setLogging
- *
- * @note Non-logged indexes are rebuilt at system restart.
- * @note Ordered index does not currently support logging.
+ * @see NdbDictionary::Index::getLogging
*/
void setLogging(bool enable);
- /**
- * Check if index is set to be stored on disk
- *
- * @see NdbDictionary::Index::setLogging
- */
- bool getLogging() const;
-
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
void setStoredIndex(bool x) { setLogging(x); }
bool getStoredIndex() const { return getLogging(); }
#endif
- /**
- * Get object status
- */
- virtual Object::Status getObjectStatus() const;
-
- /**
- * Get object version
- */
- virtual int getObjectVersion() const;
+ /** @} *******************************************************************/
private:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class NdbIndexImpl;
-
+#endif
class NdbIndexImpl & m_impl;
Index(NdbIndexImpl&);
};
@@ -831,35 +924,137 @@ public:
*/
class Event : public Object {
public:
- enum TableEvent { TE_INSERT=1, TE_DELETE=2, TE_UPDATE=4, TE_ALL=7 };
+ /**
+ * Specifies the type of database operations an Event listens to
+ */
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ /** TableEvent must match 1 << TriggerEvent */
+#endif
+ enum TableEvent {
+ TE_INSERT=1, ///< Insert event on table
+ TE_DELETE=2, ///< Delete event on table
+ TE_UPDATE=4, ///< Update event on table
+ TE_ALL=7 ///< Any/all event on table (not relevant when
+ ///< events are received)
+ };
+ /**
+ * Specifies the durability of an event
+ * (future version may supply other types)
+ */
enum EventDurability {
- ED_UNDEFINED = 0,
+ ED_UNDEFINED
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ = 0
+#endif
#if 0 // not supported
- ED_SESSION = 1,
+ ,ED_SESSION = 1,
// Only this API can use it
// and it's deleted after api has disconnected or ndb has restarted
- ED_TEMPORARY = 2,
+ ED_TEMPORARY = 2
// All API's can use it,
// But's its removed when ndb is restarted
-#endif
- ED_PERMANENT = 3
- // All API's can use it,
- // It's still defined after a restart
+#endif
+ ,ED_PERMANENT ///< All API's can use it.
+ ///< It's still defined after a cluster system restart
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ = 3
+#endif
};
-
+
+ /**
+ * Constructor
+ * @param name Name of event
+ */
Event(const char *name);
+ /**
+ * Constructor
+ * @param name Name of event
+ * @param table Reference retrieved from NdbDictionary
+ */
+ Event(const char *name, const NdbDictionary::Table& table);
virtual ~Event();
- void setName(const char *);
- void setTable(const char *);
- void addTableEvent(const TableEvent);
- void setDurability(const EventDurability);
+ /**
+ * Set unique identifier for the event
+ */
+ void setName(const char *name);
+ /**
+ * Get unique identifier for the event
+ */
+ const char *getName() const;
+ /**
+ * Define table on which events should be detected
+ *
+ * @note calling this method will default to detection
+ * of events on all columns. Calling subsequent
+ * addEventColumn calls will override this.
+ *
+ * @param table reference retrieved from NdbDictionary
+ */
+ void setTable(const NdbDictionary::Table& table);
+ /**
+ * Set table for which events should be detected
+ *
+ * @note preferred way is using setTable(const NdbDictionary::Table&)
+ * or constructor with table object parameter
+ */
+ void setTable(const char *tableName);
+ /**
+ * Get table name for events
+ *
+ * @return table name
+ */
+ const char* getTableName() const;
+ /**
+ * Add type of event that should be detected
+ */
+ void addTableEvent(const TableEvent te);
+ /**
+ * Set durability of the event
+ */
+ void setDurability(EventDurability);
+ /**
+ * Get durability of the event
+ */
+ EventDurability getDurability() const;
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
void addColumn(const Column &c);
+#endif
+ /**
+ * Add a column on which events should be detected
+ *
+ * @param attrId Column id
+ *
+ * @note errors will mot be detected until createEvent() is called
+ */
void addEventColumn(unsigned attrId);
+ /**
+ * Add a column on which events should be detected
+ *
+ * @param columnName Column name
+ *
+ * @note errors will not be detected until createEvent() is called
+ */
void addEventColumn(const char * columnName);
+ /**
+ * Add several columns on which events should be detected
+ *
+ * @param n Number of columns
+ * @param columnNames Column names
+ *
+ * @note errors will mot be detected until
+ * NdbDictionary::Dictionary::createEvent() is called
+ */
void addEventColumns(int n, const char ** columnNames);
/**
+ * Get no of columns defined in an Event
+ *
+ * @return Number of columns, -1 on error
+ */
+ int getNoOfEventColumns() const;
+
+ /**
* Get object status
*/
virtual Object::Status getObjectStatus() const;
@@ -869,11 +1064,15 @@ public:
*/
virtual int getObjectVersion() const;
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
void print();
+#endif
private:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class NdbEventImpl;
friend class NdbEventOperationImpl;
+#endif
class NdbEventImpl & m_impl;
Event(NdbEventImpl&);
};
@@ -936,8 +1135,17 @@ public:
/**
* Fetch list of all objects, optionally restricted to given type.
+ *
+ * @param list List of objects returned in the dictionary
+ * @param type Restrict returned list to only contain objects of
+ * this type
+ *
+ * @return -1 if error.
+ *
*/
int listObjects(List & list, Object::Type type = Object::TypeUndefined);
+ int listObjects(List & list,
+ Object::Type type = Object::TypeUndefined) const;
/**
* Get the latest error
@@ -947,24 +1155,87 @@ public:
const struct NdbError & getNdbError() const;
/** @} *******************************************************************/
+
+ /**
+ * @name Retrieving references to Tables and Indexes
+ * @{
+ */
+
+ /**
+ * Get table with given name, NULL if undefined
+ * @param name Name of table to get
+ * @return table if successful otherwise NULL.
+ */
+ const Table * getTable(const char * name) const;
+
+ /**
+ * Get index with given name, NULL if undefined
+ * @param indexName Name of index to get.
+ * @param tableName Name of table that index belongs to.
+ * @return index if successful, otherwise 0.
+ */
+ const Index * getIndex(const char * indexName,
+ const char * tableName) const;
+
+ /**
+ * Fetch list of indexes of given table.
+ * @param list Reference to list where to store the listed indexes
+ * @param tableName Name of table that index belongs to.
+ * @return 0 if successful, otherwise -1
+ */
+ int listIndexes(List & list, const char * tableName);
+ int listIndexes(List & list, const char * tableName) const;
+
+ /** @} *******************************************************************/
+ /**
+ * @name Events
+ * @{
+ */
+
+ /**
+ * Create event given defined Event instance
+ * @param event Event to create
+ * @return 0 if successful otherwise -1.
+ */
+ int createEvent(const Event &event);
+
+ /**
+ * Drop event with given name
+ * @param eventName Name of event to drop.
+ * @return 0 if successful otherwise -1.
+ */
+ int dropEvent(const char * eventName);
+
+ /**
+ * Get event with given name.
+ * @param eventName Name of event to get.
+ * @return an Event if successful, otherwise NULL.
+ */
+ const Event * getEvent(const char * eventName);
+
+ /** @} *******************************************************************/
+
/**
- * @name Tables
+ * @name Table creation
* @{
+ *
+ * These methods should normally not be used in an application as
+ * the result will not be visible from the MySQL Server
*/
/**
* Create defined table given defined Table instance
- * @param Table Table to create
+ * @param table Table to create
* @return 0 if successful otherwise -1.
*/
- int createTable(const Table &);
+ int createTable(const Table &table);
/**
* Drop table given retrieved Table instance
- * @param Table Table to drop
+ * @param table Table to drop
* @return 0 if successful otherwise -1.
*/
- int dropTable(Table &);
+ int dropTable(Table & table);
/**
* Drop table given table name
@@ -973,23 +1244,16 @@ public:
*/
int dropTable(const char * name);
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Alter defined table given defined Table instance
- * @param Table Table to alter
+ * @param table Table to alter
* @return -2 (incompatible version) <br>
* -1 general error <br>
* 0 success
*/
- int alterTable(const Table &);
-
- /**
- * Get table with given name, NULL if undefined
- * @param name Name of table to get
- * @return table if successful otherwise NULL.
- */
- const Table * getTable(const char * name);
+ int alterTable(const Table &table);
-#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Invalidate cached table object
* @param name Name of table to invalidate
@@ -998,24 +1262,31 @@ public:
#endif
/**
- * Remove table/index from local cache
+ * Remove table from local cache
*/
void removeCachedTable(const char * table);
+ /**
+ * Remove index from local cache
+ */
void removeCachedIndex(const char * index, const char * table);
/** @} *******************************************************************/
/**
- * @name Indexes
+ * @name Index creation
* @{
+ *
+ * These methods should normally not be used in an application as
+ * the result will not be visible from the MySQL Server
+ *
*/
/**
* Create index given defined Index instance
- * @param Index to create
+ * @param index Index to create
* @return 0 if successful otherwise -1.
*/
- int createIndex(const Index &);
+ int createIndex(const Index &index);
/**
* Drop index with given name
@@ -1026,15 +1297,6 @@ public:
int dropIndex(const char * indexName,
const char * tableName);
- /**
- * Get index with given name, NULL if undefined
- * @param indexName Name of index to get.
- * @param tableName Name of table that index belongs to.
- * @return index if successful, otherwise 0.
- */
- const Index * getIndex(const char * indexName,
- const char * tableName);
-
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Invalidate cached index object
@@ -1043,58 +1305,27 @@ public:
const char * tableName);
#endif
- /**
- * Fetch list of indexes of given table.
- * @param list Reference to list where to store the listed indexes
- * @param tableName Name of table that index belongs to.
- * @return 0 if successful, otherwise -1
- */
- int listIndexes(List & list, const char * tableName);
-
/** @} *******************************************************************/
- /**
- * @name Events
- * @{
- */
-
- /**
- * Create event given defined Event instance
- * @param Event to create
- * @return 0 if successful otherwise -1.
- */
- int createEvent(const Event &);
- /**
- * Drop event with given name
- * @param eventName Name of event to drop.
- * @return 0 if successful otherwise -1.
- */
- int dropEvent(const char * eventName);
-
- /**
- * Get event with given name.
- * @param eventName Name of event to get.
- * @return an Event if successful, otherwise NULL.
- */
- const Event * getEvent(const char * eventName);
-
- /** @} *******************************************************************/
-
protected:
Dictionary(Ndb & ndb);
~Dictionary();
private:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class NdbDictionaryImpl;
friend class UtilTransactions;
friend class NdbBlob;
+#endif
class NdbDictionaryImpl & m_impl;
Dictionary(NdbDictionaryImpl&);
const Table * getIndexTable(const char * indexName,
- const char * tableName);
+ const char * tableName) const;
public:
- const Table * getTable(const char * name, void **data);
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ const Table * getTable(const char * name, void **data) const;
void set_local_table_data_size(unsigned sz);
+#endif
};
};
diff --git a/ndb/include/ndbapi/NdbError.hpp b/ndb/include/ndbapi/NdbError.hpp
index 8cde2a8cf38..f67b3c4ccaa 100644
--- a/ndb/include/ndbapi/NdbError.hpp
+++ b/ndb/include/ndbapi/NdbError.hpp
@@ -41,7 +41,7 @@
* The <em>error messages</em> and <em>error details</em> may
* change without notice.
*
- * For example of use, see @ref ndbapi_example3.cpp.
+ * For example of use, see @ref ndbapi_retries.cpp.
*/
struct NdbError {
/**
@@ -168,7 +168,12 @@ struct NdbError {
/**
* Node shutdown
*/
- NodeShutdown = ndberror_cl_node_shutdown
+ NodeShutdown = ndberror_cl_node_shutdown,
+
+ /**
+ * Schema object already exists
+ */
+ SchemaObjectExists = ndberror_cl_schema_object_already_exists
};
/**
@@ -199,6 +204,7 @@ struct NdbError {
*/
char * details;
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
NdbError(){
status = UnknownResult;
classification = NoError;
@@ -222,6 +228,7 @@ struct NdbError {
ndberror.details = details;
return ndberror;
}
+#endif
};
class NdbOut& operator <<(class NdbOut&, const NdbError &);
diff --git a/ndb/include/ndbapi/NdbEventOperation.hpp b/ndb/include/ndbapi/NdbEventOperation.hpp
index 056e9a58c74..55ee96b3144 100644
--- a/ndb/include/ndbapi/NdbEventOperation.hpp
+++ b/ndb/include/ndbapi/NdbEventOperation.hpp
@@ -14,19 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*****************************************************************************
- * Name: NdbEventOperation.hpp
- * Include:
- * Link:
- * Author: Tomas Ulin MySQL AB
- * Date: 2003-11-21
- * Version: 0.1
- * Description: Event support
- * Documentation:
- * Adjust: 2003-11-21 Tomas Ulin First version.
- * Adjust: 2003-12-11 Tomas Ulin Alpha Release.
- ****************************************************************************/
-
#ifndef NdbEventOperation_H
#define NdbEventOperation_H
@@ -37,80 +24,79 @@ class NdbEventOperationImpl;
* @class NdbEventOperation
* @brief Class of operations for getting change events from database.
*
- * An NdbEventOperation object is instantiated by
- * NdbEventOperation *Ndb::createEventOperation(const char *eventName,
- * int bufferLength)
- *
- * Prior to that an event must have been created in the Database through
- * int NdbDictionary::createEvent(NdbDictionary::Event)
- *
- * bufferLength indicates size of circular buffer to store event info as
- * they occur.
+ * Brief description on how to work with events:
*
- * The instance is removed by Ndb::dropEventOperation(NdbEventOperation*)
+ * - An event, represented by an NdbDictionary::Event, i created in the
+ * Database through
+ * NdbDictionary::Dictionary::createEvent() (note that this can be done
+ * by any application or thread and not necessarily by the "listener")
+ * - To listen to events, an NdbEventOperation object is instantiated by
+ * Ndb::createEventOperation()
+ * - execute() starts the event flow. Use Ndb::pollEvents() to wait
+ * for an event to occur. Use next() to iterate
+ * through the events that have occured.
+ * - The instance is removed by Ndb::dropEventOperation()
*
* For more info see:
- * ndbapi_example5.cpp
- * Ndb.hpp
- * NdbDictionary.hpp
+ * @ref ndbapi_event.cpp
*
* Known limitations:
*
- * Maximum number of active NdbEventOperations are now set at compile time.
+ * - Maximum number of active NdbEventOperations are now set at compile time.
* Today 100. This will become a configuration parameter later.
- *
- * Maximum number of NdbEventOperations tied to same event are maximum 16
+ * - Maximum number of NdbEventOperations tied to same event are maximum 16
* per process.
*
* Known issues:
*
- * When several NdbEventOperation s are tied to the same event in the same
+ * - When several NdbEventOperation's are tied to the same event in the same
* process they will share the circular buffer. The BufferLength will then
* be the same for all and decided by the first NdbEventOperation
* instantiation. Just make sure to instantiate the "largest" one first.
- *
- * Today all events INSERT/DELETE/UPDATE and all changed attributes are
+ * - Today all events INSERT/DELETE/UPDATE and all changed attributes are
* sent to the API, even if only specific attributes have been specified.
* These are however hidden from the user and only relevant data is shown
- * after next(). However false exits from pollEvents() may occur and thus
- * the subsequent next() will return zero, since there was no available
- * data. Just do pollEvents() again. Will be fixed in later versions.
- *
- * Event code does not check table schema version. Make sure to drop events
+ * after next().
+ * - "False" exits from Ndb::pollEvents() may occur and thus
+ * the subsequent next() will return zero,
+ * since there was no available data. Just do Ndb::pollEvents() again.
+ * - Event code does not check table schema version. Make sure to drop events
* after table is dropped. Will be fixed in later
* versions.
- *
- * On a replicated system one will receive each event 2 times, one for each
- * replica. If a node fails events will not be received twice anymore
- * for data in corresponding fragment. Will be optimized in later versions.
- *
- * If a nodefailiure has occured not all events will be recieved
+ * - If a node failure has occured not all events will be recieved
* anymore. Drop NdbEventOperation and Create again after nodes are up
* again. Will be fixed in later versions.
*
* Test status:
- * Tests have been run on 1-node and 2-node systems
*
- * Known bugs:
- *
- * None, except if we can call some of the "isses" above bugs
+ * - Tests have been run on 1-node and 2-node systems
*
* Useful API programs:
*
- * select_all -d sys 'NDB$EVENTS_0'
- * Will show contents in the system table containing created events.
+ * - ndb_select_all -d sys 'NDB$EVENTS_0'
+ * shows contents in the system table containing created events.
*
+ * @note this is an inteface to viewing events that is subject to change
*/
class NdbEventOperation {
public:
- enum State {CREATED,EXECUTING,ERROR};
-
+ /**
+ * State of the NdbEventOperation object
+ */
+ enum State {
+ EO_CREATED, ///< Created but execute() not called
+ EO_EXECUTING, ///< execute() called
+ EO_ERROR ///< An error has occurred. Object unusable.
+ };
+ /**
+ * Retrieve current state of the NdbEventOperation object
+ */
State getState();
/**
* Activates the NdbEventOperation to start receiving events. The
* changed attribute values may be retrieved after next() has returned
- * a value greater than zero. The getValue() methods below must be called
+ * a value greater than zero. The getValue() methods must be called
* prior to execute().
*
* @return 0 if successful otherwise -1.
@@ -132,21 +118,21 @@ public:
* aligned appropriately. The buffer is used directly
* (avoiding a copy penalty) only if it is aligned on a
* 4-byte boundary and the attribute size in bytes
- * (i.e. NdbRecAttr::attrSize times NdbRecAttr::arraySize is
+ * (i.e. NdbRecAttr::attrSize() times NdbRecAttr::arraySize() is
* a multiple of 4).
*
- * @note There are two versions, NdbOperation::getValue and
- * NdbOperation::getPreValue for retrieving the current and
+ * @note There are two versions, getValue() and
+ * getPreValue() for retrieving the current and
* previous value repectively.
*
* @note This method does not fetch the attribute value from
* the database! The NdbRecAttr object returned by this method
* is <em>not</em> readable/printable before the
- * NdbEventConnection::execute has been made and
- * NdbEventConnection::next has returned a value greater than
+ * execute() has been made and
+ * next() has returned a value greater than
* zero. If a specific attribute has not changed the corresponding
* NdbRecAttr will be in state UNDEFINED. This is checked by
- * NdbRecAttr::isNull which then returns -1.
+ * NdbRecAttr::isNULL() which then returns -1.
*
* @param anAttrName Attribute name
* @param aValue If this is non-NULL, then the attribute value
@@ -158,19 +144,24 @@ public:
* (indicating error).
*/
NdbRecAttr *getValue(const char *anAttrName, char *aValue = 0);
+ /**
+ * See getValue().
+ */
NdbRecAttr *getPreValue(const char *anAttrName, char *aValue = 0);
/**
* Retrieves event resultset if available, inserted into the NdbRecAttrs
* specified in getValue() and getPreValue(). To avoid polling for
- * a resultset, one can use Ndb::pollEvents(int millisecond_timeout)
+ * a resultset, one can use Ndb::pollEvents()
* which will wait on a mutex until an event occurs or the specified
* timeout occurs.
*
- * @return >=0 if successful otherwise -1. Return value inicates number
+ * @return >=0 if successful otherwise -1. Return value indicates number
* of available events. By sending pOverRun one may query for buffer
* overflow and *pOverRun will indicate the number of events that have
* overwritten.
+ *
+ * @return number of available events, -1 on failure
*/
int next(int *pOverRun=0);
@@ -182,18 +173,47 @@ public:
/**
* Query for occured event type.
- * NdbDictionary::Event::{TE_INSERT,TE_UPDATE,TE_DELETE}
- * Only valid after next() has returned value >= 0
+ *
+ * @note Only valid after next() has been called and returned value >= 0
+ *
+ * @return type of event
*/
NdbDictionary::Event::TableEvent getEventType();
+ /**
+ * Retrieve the GCI of the latest retrieved event
+ *
+ * @return GCI number
+ */
Uint32 getGCI();
+
+ /**
+ * Retrieve the complete GCI in the cluster (not necessarily
+ * associated with an event)
+ *
+ * @return GCI number
+ */
Uint32 getLatestGCI();
+
+ /**
+ * Get the latest error
+ *
+ * @return Error object.
+ */
+ const struct NdbError & getNdbError() const;
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ /*
+ *
+ */
void print();
+#endif
private:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class NdbEventOperationImpl;
friend class Ndb;
+#endif
NdbEventOperation(Ndb *theNdb, const char* eventName,int bufferLength);
~NdbEventOperation();
static int wait(void *p, int aMillisecondNumber);
diff --git a/ndb/include/ndbapi/NdbIndexOperation.hpp b/ndb/include/ndbapi/NdbIndexOperation.hpp
index 1472f1b249e..3de6835238e 100644
--- a/ndb/include/ndbapi/NdbIndexOperation.hpp
+++ b/ndb/include/ndbapi/NdbIndexOperation.hpp
@@ -14,18 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*****************************************************************************
- * Name: NdbIndexOperation.hpp
- * Include:
- * Link:
- * Author: Martin Sköld
- * Date: 2002-04-01
- * Version: 0.1
- * Description: Secondary index support
- * Documentation:
- * Adjust: 2002-04-01 Martin Sköld First version.
- ****************************************************************************/
-
#ifndef NdbIndexOperation_H
#define NdbIndexOperation_H
@@ -40,8 +28,10 @@ class NdbResultSet;
*/
class NdbIndexOperation : public NdbOperation
{
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class Ndb;
- friend class NdbConnection;
+ friend class NdbTransaction;
+#endif
public:
/**
@@ -54,16 +44,17 @@ public:
/**
* Define the NdbIndexOperation to be a standard operation of type readTuple.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* reads a tuple.
*
* @return 0 if successful otherwise -1.
*/
int readTuple(LockMode);
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Define the NdbIndexOperation to be a standard operation of type readTuple.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* reads a tuple.
*
* @return 0 if successful otherwise -1.
@@ -73,7 +64,7 @@ public:
/**
* Define the NdbIndexOperation to be a standard operation of type
* readTupleExclusive.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* read a tuple using an exclusive lock.
*
* @return 0 if successful otherwise -1.
@@ -82,7 +73,7 @@ public:
/**
* Define the NdbIndexOperation to be a standard operation of type simpleRead.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* reads an existing tuple (using shared read lock),
* but releases lock immediately after read.
*
@@ -101,7 +92,7 @@ public:
/**
* Define the NdbOperation to be a standard operation of type committedRead.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* read latest committed value of the record.
*
* This means that if another transaction is updating the
@@ -113,7 +104,6 @@ public:
*/
int dirtyRead();
-#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
int committedRead();
#endif
@@ -121,7 +111,7 @@ public:
* Define the NdbIndexOperation to be a standard operation of type
* updateTuple.
*
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* updates a tuple in the table.
*
* @return 0 if successful otherwise -1.
@@ -132,24 +122,27 @@ public:
* Define the NdbIndexOperation to be a standard operation of type
* deleteTuple.
*
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* deletes a tuple.
*
* @return 0 if successful otherwise -1.
*/
int deleteTuple();
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Define the NdbIndexOperation to be a standard operation of type
* dirtyUpdate.
*
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* updates without two-phase commit.
*
* @return 0 if successful otherwise -1.
*/
int dirtyUpdate();
+#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/** @} *********************************************************************/
/**
* @name Define Interpreted Program Operation
@@ -169,6 +162,7 @@ public:
* @return 0 if successful otherwise -1.
*/
int interpretedDeleteTuple();
+#endif
/** @} *********************************************************************/
@@ -176,30 +170,17 @@ private:
NdbIndexOperation(Ndb* aNdb);
~NdbIndexOperation();
- void closeScan();
-
int receiveTCINDXREF(NdbApiSignal* aSignal);
- // Overloaded method from NdbOperation
- void setLastFlag(NdbApiSignal* signal, Uint32 lastFlag);
-
- // Overloaded methods from NdbCursorOperation
- int executeCursor(int ProcessorId);
-
// Overloaded methods from NdbCursorOperation
int indxInit(const class NdbIndexImpl* anIndex,
const class NdbTableImpl* aTable,
- NdbConnection* myConnection);
+ NdbTransaction*);
- int equal_impl(const class NdbColumnImpl*, const char* aValue, Uint32 len);
int prepareSend(Uint32 TC_ConnectPtr, Uint64 TransactionId);
// Private attributes
const NdbIndexImpl* m_theIndex;
- const NdbTableImpl* m_thePrimaryTable;
- Uint32 m_theIndexDefined[NDB_MAX_ATTRIBUTES_IN_INDEX][3];
- Uint32 m_theIndexLen; // Length of the index in words
- Uint32 m_theNoOfIndexDefined; // The number of index attributes
};
#endif
diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp
index a3388f62f58..b91a2a90d11 100644
--- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp
+++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp
@@ -24,37 +24,34 @@
* @brief Class of scan operations for use to scan ordered index
*/
class NdbIndexScanOperation : public NdbScanOperation {
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class Ndb;
- friend class NdbConnection;
+ friend class NdbTransaction;
friend class NdbResultSet;
friend class NdbOperation;
friend class NdbScanOperation;
+#endif
+
public:
/**
- * readTuples returns a NdbResultSet where tuples are stored.
- * Tuples are not stored in NdbResultSet until execute(NoCommit)
- * has been executed and nextResult has been called.
+ * readTuples using ordered index
*
- * @param parallel Scan parallelism
+ * @param lock_mode Lock mode
* @param batch No of rows to fetch from each fragment at a time
- * @param LockMode Scan lock handling
+ * @param parallel No of fragments to scan in parallel
* @param order_by Order result set in index order
- * @returns NdbResultSet.
+ * @param order_desc Order descending, ignored unless order_by
+ * @param read_range_no Enable reading of range no using @ref get_range_no
+ * @returns 0 for success and -1 for failure
* @see NdbScanOperation::readTuples
*/
- NdbResultSet* readTuples(LockMode = LM_Read,
- Uint32 batch = 0,
- Uint32 parallel = 0,
- bool order_by = false);
+ int readTuples(LockMode lock_mode = LM_Read,
+ Uint32 batch = 0,
+ Uint32 parallel = 0,
+ bool order_by = false,
+ bool order_desc = false,
+ bool read_range_no = false);
- inline NdbResultSet* readTuples(int parallell){
- return readTuples(LM_Read, 0, parallell, false);
- }
-
- inline NdbResultSet* readTuplesExclusive(int parallell = 0){
- return readTuples(LM_Exclusive, 0, parallell, false);
- }
-
/**
* Type of ordered index key bound. The values (0-4) will not change
* and can be used explicitly (e.g. they could be computed).
@@ -76,7 +73,7 @@ public:
*
* For equality, it is better to use BoundEQ instead of the equivalent
* pair of BoundLE and BoundGE. This is especially true when table
- * distribution key is an initial part of the index key.
+ * partition key is an initial part of the index key.
*
* The sets of lower and upper bounds must be on initial sequences of
* index keys. All but possibly the last bound must be non-strict.
@@ -93,15 +90,14 @@ public:
* An index stores also all-NULL keys. Doing index scan with empty
* bound set returns all table tuples.
*
- * @param attrName Attribute name, alternatively:
- * @param anAttrId Index column id (starting from 0)
+ * @param attr Attribute name, alternatively:
* @param type Type of bound
* @param value Pointer to bound value, 0 for NULL
* @param len Value length in bytes.
* Fixed per datatype and can be omitted
* @return 0 if successful otherwise -1
*/
- int setBound(const char* attr, int type, const void* aValue, Uint32 len = 0);
+ int setBound(const char* attr, int type, const void* value, Uint32 len = 0);
/**
* Define bound on index key in range scan using index column id.
@@ -114,8 +110,27 @@ public:
* sent on next execute
*/
int reset_bounds(bool forceSend = false);
+
+ /**
+ * Marks end of a bound,
+ * used when batching index reads (multiple ranges)
+ */
+ int end_of_bound(Uint32 range_no);
+
+ /**
+ * Return range no for current row
+ */
+ int get_range_no();
+ /**
+ * Is current scan sorted
+ */
bool getSorted() const { return m_ordered; }
+
+ /**
+ * Is current scan sorted descending
+ */
+ bool getDescending() const { return m_descending; }
private:
NdbIndexScanOperation(Ndb* aNdb);
virtual ~NdbIndexScanOperation();
@@ -132,6 +147,9 @@ private:
int compare(Uint32 key, Uint32 cols, const NdbReceiver*, const NdbReceiver*);
Uint32 m_sort_columns;
+
+ Uint32 m_this_bound_start;
+ Uint32 * m_first_bound_word;
};
#endif
diff --git a/ndb/include/ndbapi/NdbOperation.hpp b/ndb/include/ndbapi/NdbOperation.hpp
index 46d4ddab0f5..fca610772cc 100644
--- a/ndb/include/ndbapi/NdbOperation.hpp
+++ b/ndb/include/ndbapi/NdbOperation.hpp
@@ -27,7 +27,7 @@ class Ndb;
class NdbApiSignal;
class NdbRecAttr;
class NdbOperation;
-class NdbConnection;
+class NdbTransaction;
class NdbColumnImpl;
class NdbBlob;
@@ -37,14 +37,17 @@ class NdbBlob;
*/
class NdbOperation
{
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class Ndb;
- friend class NdbConnection;
+ friend class NdbTransaction;
friend class NdbScanOperation;
friend class NdbScanReceiver;
friend class NdbScanFilter;
friend class NdbScanFilterImpl;
friend class NdbReceiver;
friend class NdbBlob;
+#endif
+
public:
/**
* @name Define Standard Operation Type
@@ -56,17 +59,24 @@ public:
*/
enum LockMode {
- LM_Read = 0,
- LM_Exclusive = 1,
- LM_CommittedRead = 2,
+ LM_Read ///< Read with shared lock
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ = 0
+#endif
+ ,LM_Exclusive ///< Read with exclusive lock
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ = 1
+#endif
+ ,LM_CommittedRead ///< Ignore locks, read last committed value
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ = 2,
LM_Dirty = 2
#endif
};
/**
* Define the NdbOperation to be a standard operation of type insertTuple.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* adds a new tuple to the table.
*
* @return 0 if successful otherwise -1.
@@ -75,7 +85,7 @@ public:
/**
* Define the NdbOperation to be a standard operation of type updateTuple.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* updates a tuple in the table.
*
* @return 0 if successful otherwise -1.
@@ -84,7 +94,7 @@ public:
/**
* Define the NdbOperation to be a standard operation of type writeTuple.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* writes a tuple to the table.
* If the tuple exists, it updates it, otherwise an insert takes place.
*
@@ -94,7 +104,7 @@ public:
/**
* Define the NdbOperation to be a standard operation of type deleteTuple.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* delete a tuple.
*
* @return 0 if successful otherwise -1.
@@ -103,16 +113,17 @@ public:
/**
* Define the NdbOperation to be a standard operation of type readTuple.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* reads a tuple.
*
* @return 0 if successful otherwise -1.
*/
virtual int readTuple(LockMode);
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Define the NdbOperation to be a standard operation of type readTuple.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* reads a tuple.
*
* @return 0 if successful otherwise -1.
@@ -122,7 +133,7 @@ public:
/**
* Define the NdbOperation to be a standard operation of type
* readTupleExclusive.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* read a tuple using an exclusive lock.
*
* @return 0 if successful otherwise -1.
@@ -132,7 +143,7 @@ public:
/**
* Define the NdbOperation to be a standard operation of type
* simpleRead.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* reads an existing tuple (using shared read lock),
* but releases lock immediately after read.
*
@@ -149,10 +160,9 @@ public:
*/
virtual int simpleRead();
-#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
/**
* Define the NdbOperation to be a standard operation of type committedRead.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* read latest committed value of the record.
*
* This means that if another transaction is updating the
@@ -165,11 +175,10 @@ public:
* @depricated
*/
virtual int dirtyRead();
-#endif
/**
* Define the NdbOperation to be a standard operation of type committedRead.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* read latest committed value of the record.
*
* This means that if another transaction is updating the
@@ -183,7 +192,7 @@ public:
/**
* Define the NdbOperation to be a standard operation of type dirtyUpdate.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* updates without two-phase commit.
*
* @return 0 if successful otherwise -1.
@@ -192,13 +201,15 @@ public:
/**
* Define the NdbOperation to be a standard operation of type dirtyWrite.
- * When calling NdbConnection::execute, this operation
+ * When calling NdbTransaction::execute, this operation
* writes without two-phase commit.
*
* @return 0 if successful otherwise -1.
*/
virtual int dirtyWrite();
+#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/** @} *********************************************************************/
/**
* @name Define Interpreted Program Operation Type
@@ -218,6 +229,7 @@ public:
* @return 0 if successful otherwise -1.
*/
virtual int interpretedDeleteTuple();
+#endif
/** @} *********************************************************************/
@@ -232,10 +244,13 @@ public:
* use several equals (then all of them must be satisfied for the
* tuple to be selected).
*
- * @note There are 10 versions of NdbOperation::equal with
+ * @note For insertTuple() it is also allowed to define the
+ * search key by using setValue().
+ *
+ * @note There are 10 versions of equal() with
* slightly different parameters.
*
- * @note When using NdbOperation::equal with a string (char *) as
+ * @note When using equal() with a string (char *) as
* second argument, the string needs to be padded with
* zeros in the following sense:
* @code
@@ -243,6 +258,8 @@ public:
* strncpy(buf, str, sizeof(buf));
* NdbOperation->equal("Attr1", buf);
* @endcode
+ *
+ *
*
* @param anAttrName Attribute name
* @param aValue Attribute value.
@@ -260,21 +277,6 @@ public:
int equal(Uint32 anAttrId, Int64 aValue);
int equal(Uint32 anAttrId, Uint64 aValue);
- /**
- * Generate a tuple id and set it as search argument.
- *
- * The Tuple id has NDB$TID as attribute name and 0 as attribute id.
- *
- * The generated tuple id is returned by the method.
- * If zero is returned there is an error.
- *
- * This is mostly used for tables without any primary key
- * attributes.
- *
- * @return Generated tuple id if successful, otherwise 0.
- */
- Uint64 setTupleId();
-
/** @} *********************************************************************/
/**
* @name Specify Attribute Actions for Operations
@@ -301,7 +303,7 @@ public:
* @note This method does not fetch the attribute value from
* the database! The NdbRecAttr object returned by this method
* is <em>not</em> readable/printable before the
- * transaction has been executed with NdbConnection::execute.
+ * transaction has been executed with NdbTransaction::execute.
*
* @param anAttrName Attribute name
* @param aValue If this is non-NULL, then the attribute value
@@ -338,6 +340,12 @@ public:
* then the API will assume that the pointer
* is correct and not bother with checking it.
*
+ * @note For insertTuple() the NDB API will automatically detect that
+ * it is supposed to use equal() instead.
+ *
+ * @note For insertTuple() it is not necessary to use
+ * setValue() on key attributes before other attributes.
+ *
* @note There are 14 versions of NdbOperation::setValue with
* slightly different parameters.
*
@@ -374,6 +382,7 @@ public:
virtual NdbBlob* getBlobHandle(const char* anAttrName);
virtual NdbBlob* getBlobHandle(Uint32 anAttrId);
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/** @} *********************************************************************/
/**
* @name Specify Interpreted Program Instructions
@@ -586,21 +595,21 @@ public:
* @param Label label to jump to
* @return -1 if unsuccessful
*/
- int branch_col_eq(Uint32 ColId, const char * val, Uint32 len,
+ int branch_col_eq(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label);
- int branch_col_ne(Uint32 ColId, const char * val, Uint32 len,
+ int branch_col_ne(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label);
- int branch_col_lt(Uint32 ColId, const char * val, Uint32 len,
+ int branch_col_lt(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label);
- int branch_col_le(Uint32 ColId, const char * val, Uint32 len,
+ int branch_col_le(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label);
- int branch_col_gt(Uint32 ColId, const char * val, Uint32 len,
+ int branch_col_gt(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label);
- int branch_col_ge(Uint32 ColId, const char * val, Uint32 len,
+ int branch_col_ge(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label);
- int branch_col_like(Uint32 ColId, const char *, Uint32 len,
+ int branch_col_like(Uint32 ColId, const void *, Uint32 len,
bool nopad, Uint32 Label);
- int branch_col_notlike(Uint32 ColId, const char *, Uint32 len,
+ int branch_col_notlike(Uint32 ColId, const void *, Uint32 len,
bool nopad, Uint32 Label);
/**
@@ -672,6 +681,7 @@ public:
* @return -1 if unsuccessful.
*/
int ret_sub();
+#endif
/** @} *********************************************************************/
@@ -699,8 +709,14 @@ public:
*/
const char* getTableName() const;
+ /**
+ * Get table object for this operation
+ */
+ const NdbDictionary::Table * getTable() const;
+
/** @} *********************************************************************/
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Type of operation
*/
@@ -716,9 +732,26 @@ public:
NotDefined2, ///< Internal for debugging
NotDefined ///< Internal for debugging
};
+#endif
+ /**
+ * Return lock mode for operation
+ */
LockMode getLockMode() const { return theLockMode; }
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ void setAbortOption(Int8 ao) { m_abortOption = ao; }
+
+ /**
+ * Set/get partition key
+ */
+ void setPartitionId(Uint32 id);
+ void setPartitionHash(Uint32 key);
+ void setPartitionHash(const Uint64 *, Uint32 len);
+ Uint32 getPartitionId() const;
+#endif
+protected:
+ int handle_distribution_key(const Uint64 *, Uint32 len);
protected:
/******************************************************************************
* These are the methods used to create and delete the NdbOperation objects.
@@ -733,14 +766,20 @@ protected:
//--------------------------------------------------------------
// Initialise after allocating operation to a transaction
//--------------------------------------------------------------
- int init(const class NdbTableImpl*, NdbConnection* aCon);
+ int init(const class NdbTableImpl*, NdbTransaction* aCon);
void initInterpreter();
void next(NdbOperation*); // Set next pointer
-
NdbOperation* next(); // Get next pointer
+public:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ const NdbOperation* next() const;
+ const NdbRecAttr* getFirstRecAttr() const;
+#endif
+protected:
- enum OperationStatus{
+ enum OperationStatus
+ {
Init,
OperationDefined,
TupleKeyDefined,
@@ -761,7 +800,7 @@ protected:
void Status(OperationStatus); // Set the status information
- void NdbCon(NdbConnection*); // Set reference to connection
+ void NdbCon(NdbTransaction*); // Set reference to connection
// object.
virtual void release(); // Release all operations
@@ -798,7 +837,7 @@ protected:
virtual int equal_impl(const NdbColumnImpl*,const char* aValue, Uint32 len);
virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char* aValue = 0);
int setValue(const NdbColumnImpl* anAttrObject, const char* aValue, Uint32 len);
- NdbBlob* getBlobHandle(NdbConnection* aCon, const NdbColumnImpl* anAttrObject);
+ NdbBlob* getBlobHandle(NdbTransaction* aCon, const NdbColumnImpl* anAttrObject);
int incValue(const NdbColumnImpl* anAttrObject, Uint32 aValue);
int incValue(const NdbColumnImpl* anAttrObject, Uint64 aValue);
int subValue(const NdbColumnImpl* anAttrObject, Uint32 aValue);
@@ -806,17 +845,16 @@ protected:
int read_attr(const NdbColumnImpl* anAttrObject, Uint32 RegDest);
int write_attr(const NdbColumnImpl* anAttrObject, Uint32 RegSource);
int branch_reg_reg(Uint32 type, Uint32, Uint32, Uint32);
- int branch_col(Uint32 type, Uint32, const char *, Uint32, bool, Uint32 Label);
+ int branch_col(Uint32 type, Uint32, const void *, Uint32, bool, Uint32 Label);
int branch_col_null(Uint32 type, Uint32 col, Uint32 Label);
// Handle ATTRINFO signals
- int insertATTRINFO(Uint32 aData);
- int insertATTRINFOloop(const Uint32* aDataPtr, Uint32 aLength);
-
- int insertKEYINFO(const char* aValue,
- Uint32 aStartPosition,
- Uint32 aKeyLenInByte,
- Uint32 anAttrBitsInLastWord);
+ int insertATTRINFO(Uint32 aData);
+ int insertATTRINFOloop(const Uint32* aDataPtr, Uint32 aLength);
+
+ int insertKEYINFO(const char* aValue,
+ Uint32 aStartPosition,
+ Uint32 aKeyLenInByte);
virtual void setErrorCode(int aErrorCode);
virtual void setErrorCodeAbort(int aErrorCode);
@@ -848,16 +886,20 @@ protected:
int theErrorLine; // Error line
Ndb* theNdb; // Point back to the Ndb object.
- NdbConnection* theNdbCon; // Point back to the connection object.
+ NdbTransaction* theNdbCon; // Point back to the connection object.
NdbOperation* theNext; // Next pointer to operation.
- NdbApiSignal* theTCREQ; // The TC[KEY/INDX]REQ signal object
+
+ union {
+ NdbApiSignal* theTCREQ; // The TC[KEY/INDX]REQ signal object
+ NdbApiSignal* theSCAN_TABREQ;
+ };
+
NdbApiSignal* theFirstATTRINFO; // The first ATTRINFO signal object
NdbApiSignal* theCurrentATTRINFO; // The current ATTRINFO signal object
Uint32 theTotalCurrAI_Len; // The total number of attribute info
// words currently defined
Uint32 theAI_LenInCurrAI; // The number of words defined in the
// current ATTRINFO signal
- NdbApiSignal* theFirstKEYINFO; // The first KEYINFO signal object
NdbApiSignal* theLastKEYINFO; // The first KEYINFO signal object
class NdbLabel* theFirstLabel;
@@ -874,8 +916,8 @@ protected:
Uint32* theKEYINFOptr; // Pointer to where to write KEYINFO
Uint32* theATTRINFOptr; // Pointer to where to write ATTRINFO
- const class NdbTableImpl* m_currentTable; // The current table
- const class NdbTableImpl* m_accessTable;
+ const class NdbTableImpl* m_currentTable; // The current table
+ const class NdbTableImpl* m_accessTable; // Index table (== current for pk)
// Set to TRUE when a tuple key attribute has been defined.
Uint32 theTupleKeyDefined[NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY][3];
@@ -883,18 +925,18 @@ protected:
Uint32 theTotalNrOfKeyWordInSignal; // The total number of
// keyword in signal.
- Uint32 theTupKeyLen; // Length of the tuple key in words
- Uint32 theNoOfTupKeyDefined; // The number of tuple key attributes
- // currently defined
- OperationType theOperationType; // Read Request, Update Req......
-
+ Uint32 theTupKeyLen; // Length of the tuple key in words
+ // left until done
+ Uint8 theNoOfTupKeyLeft; // The number of tuple key attributes
+ OperationType theOperationType; // Read Request, Update Req......
+
LockMode theLockMode; // Can be set to WRITE if read operation
OperationStatus theStatus; // The status of the operation.
+
Uint32 theMagicNumber; // Magic number to verify that object
// is correct
Uint32 theScanInfo; // Scan info bits (take over flag etc)
- Uint32 theDistrKeySize; // Distribution Key size if used
- Uint32 theDistributionGroup; // Distribution Group if used
+ Uint32 theDistributionKey; // Distribution Key size if used
Uint32 theSubroutineSize; // Size of subroutines for interpretation
Uint32 theInitialReadSize; // Size of initial reads for interpretation
@@ -902,14 +944,12 @@ protected:
Uint32 theFinalUpdateSize; // Size of final updates for interpretation
Uint32 theFinalReadSize; // Size of final reads for interpretation
- Uint8 theStartIndicator; // Indicator of whether start operation
- Uint8 theCommitIndicator; // Indicator of whether commit operation
- Uint8 theSimpleIndicator; // Indicator of whether simple operation
- Uint8 theDirtyIndicator; // Indicator of whether dirty operation
- Uint8 theInterpretIndicator; // Indicator of whether interpreted operation
- Uint8 theDistrGroupIndicator; // Indicates whether distribution grp is used
- Uint8 theDistrGroupType; // Type of distribution group used
- Uint8 theDistrKeyIndicator; // Indicates whether distr. key is used
+ Uint8 theStartIndicator; // Indicator of whether start operation
+ Uint8 theCommitIndicator; // Indicator of whether commit operation
+ Uint8 theSimpleIndicator; // Indicator of whether simple operation
+ Uint8 theDirtyIndicator; // Indicator of whether dirty operation
+ Uint8 theInterpretIndicator; // Indicator of whether interpreted operation
+ Int8 theDistrKeyIndicator_; // Indicates whether distr. key is used
Uint16 m_tcReqGSN;
Uint16 m_keyInfoGSN;
@@ -931,6 +971,7 @@ protected:
#include <stdlib.h>
#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
inline
int
@@ -985,6 +1026,20 @@ NdbOperation::next()
return theNext;
}
+inline
+const NdbOperation*
+NdbOperation::next() const
+{
+ return theNext;
+}
+
+inline
+const NdbRecAttr*
+NdbOperation::getFirstRecAttr() const
+{
+ return theReceiver.theFirstRecAttr;
+}
+
/******************************************************************************
OperationStatus Status();
@@ -1014,14 +1069,14 @@ NdbOperation::Status( OperationStatus aStatus )
}
/******************************************************************************
-void NdbCon(NdbConnection* aNdbCon);
+void NdbCon(NdbTransaction* aNdbCon);
-Parameters: aNdbCon: Pointers to NdbConnection object.
+Parameters: aNdbCon: Pointers to NdbTransaction object.
Remark: Set the reference to the connection in the operation object.
******************************************************************************/
inline
void
-NdbOperation::NdbCon(NdbConnection* aNdbCon)
+NdbOperation::NdbCon(NdbTransaction* aNdbCon)
{
theNdbCon = aNdbCon;
}
@@ -1166,4 +1221,6 @@ NdbOperation::setValue(Uint32 anAttrId, double aPar)
return setValue(anAttrId, (const char*)&aPar, (Uint32)8);
}
+#endif // doxygen
+
#endif
diff --git a/ndb/include/ndbapi/NdbRecAttr.hpp b/ndb/include/ndbapi/NdbRecAttr.hpp
index 05635a99385..50de4f3277e 100644
--- a/ndb/include/ndbapi/NdbRecAttr.hpp
+++ b/ndb/include/ndbapi/NdbRecAttr.hpp
@@ -34,23 +34,22 @@ class NdbOperation;
* MyRecAttr = MyOperation->getValue("ATTR2", NULL);
* if (MyRecAttr == NULL) goto error;
*
- * if (MyConnection->execute(Commit) == -1) goto error;
+ * if (MyTransaction->execute(Commit) == -1) goto error;
*
* ndbout << MyRecAttr->u_32_value();
* @endcode
* For more examples, see
- * @ref ndbapi_example1.cpp and
- * @ref ndbapi_example2.cpp.
+ * @ref ndbapi_simple.cpp.
*
* @note The NdbRecAttr object is instantiated with its value when
- * NdbConnection::execute is called. Before this, the value is
+ * NdbTransaction::execute is called. Before this, the value is
* undefined. (NdbRecAttr::isNULL can be used to check
* if the value is defined or not.)
* This means that an NdbRecAttr object only has valid information
- * between the time of calling NdbConnection::execute and
+ * between the time of calling NdbTransaction::execute and
* the time of Ndb::closeTransaction.
* The value of the null indicator is -1 until the
- * NdbConnection::execute method have been called.
+ * NdbTransaction::execute method have been called.
*
* For simple types, there are methods which directly getting the value
* from the NdbRecAttr object.
@@ -72,12 +71,14 @@ class NdbOperation;
*/
class NdbRecAttr
{
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class NdbOperation;
friend class NdbIndexScanOperation;
friend class NdbEventOperationImpl;
friend class NdbReceiver;
friend class Ndb;
friend class NdbOut& operator<<(class NdbOut&, const class AttributeS&);
+#endif
public:
/**
@@ -124,7 +125,7 @@ public:
* Check if attribute value is NULL.
*
* @return -1 = Not defined (Failure or
- * NdbConnection::execute not yet called).<br>
+ * NdbTransaction::execute not yet called).<br>
* 0 = Attribute value is defined, but not equal to NULL.<br>
* 1 = Attribute value is defined and equal to NULL.
*/
@@ -241,18 +242,24 @@ public:
* i.e. objects that has been cloned.
*/
~NdbRecAttr();
+
+public:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ const NdbRecAttr* next() const;
+#endif
private:
NdbRecAttr();
Uint32 attrId() const; /* Get attribute id */
bool setNULL(); /* Set NULL indicator */
+ void setUNDEFINED(); /* Set UNDEFINED indicator */
bool receive_data(const Uint32*, Uint32);
void release(); /* Release memory if allocated */
void init(); /* Initialise object when allocated */
void next(NdbRecAttr* aRecAttr);
- NdbRecAttr* next() const;
+ NdbRecAttr* next();
int setup(const class NdbDictionary::Column* col, char* aValue);
int setup(const class NdbColumnImpl* anAttrInfo, char* aValue);
@@ -275,6 +282,8 @@ private:
const NdbDictionary::Column* m_column;
};
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+
inline
NdbDictionary::Column::Type
NdbRecAttr::getType() const {
@@ -373,6 +382,13 @@ NdbRecAttr::next(NdbRecAttr* aRecAttr)
inline
NdbRecAttr*
+NdbRecAttr::next()
+{
+ return theNext;
+}
+
+inline
+const NdbRecAttr*
NdbRecAttr::next() const
{
return theNext;
@@ -408,6 +424,13 @@ NdbRecAttr::setNULL()
}
inline
+void
+NdbRecAttr::setUNDEFINED()
+{
+ theNULLind = -1;
+}
+
+inline
int
NdbRecAttr::isNULL() const
{
@@ -416,5 +439,7 @@ NdbRecAttr::isNULL() const
class NdbOut& operator <<(class NdbOut&, const NdbRecAttr &);
+#endif // ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+
#endif
diff --git a/ndb/include/ndbapi/NdbReceiver.hpp b/ndb/include/ndbapi/NdbReceiver.hpp
index af624f69bd3..ff6debc7fd3 100644
--- a/ndb/include/ndbapi/NdbReceiver.hpp
+++ b/ndb/include/ndbapi/NdbReceiver.hpp
@@ -21,7 +21,7 @@
#include <ndb_types.h>
class Ndb;
-class NdbConnection;
+class NdbTransaction;
class NdbReceiver
{
@@ -30,7 +30,7 @@ class NdbReceiver
friend class NdbScanOperation;
friend class NdbIndexOperation;
friend class NdbIndexScanOperation;
- friend class NdbConnection;
+ friend class NdbTransaction;
public:
enum ReceiverType { NDB_UNINITIALIZED,
NDB_OPERATION = 1,
@@ -51,7 +51,7 @@ public:
return m_type;
}
- inline NdbConnection * getTransaction();
+ inline NdbTransaction * getTransaction();
void* getOwner(){
return m_owner;
}
@@ -67,7 +67,7 @@ private:
Ndb* m_ndb;
Uint32 m_id;
Uint32 m_tcPtrI;
- Uint32 m_key_info;
+ Uint32 m_hidden_count;
ReceiverType m_type;
void* m_owner;
NdbReceiver* m_next;
@@ -76,7 +76,7 @@ private:
* At setup
*/
class NdbRecAttr * getValue(const class NdbColumnImpl*, char * user_dst_ptr);
- void do_get_value(NdbReceiver*, Uint32 rows, Uint32 key_size);
+ void do_get_value(NdbReceiver*, Uint32 rows, Uint32 key_size, Uint32 range);
void prepareSend();
void calculate_batch_size(Uint32, Uint32, Uint32&, Uint32&, Uint32&);
@@ -97,7 +97,7 @@ private:
Uint32 m_received_result_length;
bool nextResult() const { return m_current_row < m_result_rows; }
- void copyout(NdbReceiver&);
+ NdbRecAttr* copyout(NdbReceiver&);
};
#ifdef NDB_NO_DROPPED_SIGNAL
@@ -146,5 +146,5 @@ NdbReceiver::execSCANOPCONF(Uint32 tcPtrI, Uint32 len, Uint32 rows){
return (tmp == len ? 1 : 0);
}
-#endif
+#endif // DOXYGEN_SHOULD_SKIP_INTERNAL
#endif
diff --git a/ndb/include/ndbapi/NdbResultSet.hpp b/ndb/include/ndbapi/NdbResultSet.hpp
deleted file mode 100644
index dc0288a380c..00000000000
--- a/ndb/include/ndbapi/NdbResultSet.hpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*****************************************************************************
- * Name: NdbResultSet.hpp
- * Include:
- * Link:
- * Author: Martin Sköld
- * Date: 2002-04-01
- * Version: 0.1
- * Description: Cursor class
- * Documentation:
- * Adjust: 2002-04-01 Martin Sköld First version.
- ****************************************************************************/
-
-#ifndef NdbResultSet_H
-#define NdbResultSet_H
-
-
-#include <NdbScanOperation.hpp>
-
-/**
- * @class NdbResultSet
- * @brief NdbResultSet contains a NdbScanOperation.
- */
-class NdbResultSet
-{
- friend class NdbScanOperation;
-
-public:
-
- /**
- * Get the next tuple in a scan transaction.
- *
- * After each call to NdbResult::nextResult
- * the buffers and NdbRecAttr objects defined in
- * NdbOperation::getValue are updated with values
- * from the scanned tuple.
- *
- * @param fetchAllowed If set to false, then fetching is disabled
- *
- * The NDB API will contact the NDB Kernel for more tuples
- * when necessary to do so unless you set the fetchAllowed
- * to false.
- * This will force NDB to process any records it
- * already has in it's caches. When there are no more cached
- * records it will return 2. You must then call nextResult
- * with fetchAllowed = true in order to contact NDB for more
- * records.
- *
- * fetchAllowed = false is useful when you want to update or
- * delete all the records fetched in one transaction(This will save a
- * lot of round trip time and make updates or deletes of scanned
- * records a lot faster).
- * While nextResult(false)
- * returns 0 take over the record to another transaction. When
- * nextResult(false) returns 2 you must execute and commit the other
- * transaction. This will cause the locks to be transferred to the
- * other transaction, updates or deletes will be made and then the
- * locks will be released.
- * After that, call nextResult(true) which will fetch new records and
- * cache them in the NdbApi.
- *
- * @note If you don't take over the records to another transaction the
- * locks on those records will be released the next time NDB Kernel
- * is contacted for more records.
- *
- * @note Please contact for examples of efficient scan
- * updates and deletes.
- *
- * @note See ndb/examples/ndbapi_scan_example for usage.
- *
- * @return
- * - -1: if unsuccessful,<br>
- * - 0: if another tuple was received, and<br>
- * - 1: if there are no more tuples to scan.
- * - 2: if there are no more cached records in NdbApi
- */
- int nextResult(bool fetchAllowed = true, bool forceSend = false);
-
- /**
- * Close result set (scan)
- */
- void close(bool forceSend = false);
-
- /**
- * Restart
- */
- int restart(bool forceSend = false);
-
- /**
- * Transfer scan operation to an updating transaction. Use this function
- * when a scan has found a record that you want to update.
- * 1. Start a new transaction.
- * 2. Call the function takeOverForUpdate using your new transaction
- * as parameter, all the properties of the found record will be copied
- * to the new transaction.
- * 3. When you execute the new transaction, the lock held by the scan will
- * be transferred to the new transaction(it's taken over).
- *
- * @note You must have started the scan with openScanExclusive
- * to be able to update the found tuple.
- *
- * @param updateTrans the update transaction connection.
- * @return an NdbOperation or NULL.
- */
- NdbOperation* updateTuple();
- NdbOperation* updateTuple(NdbConnection* updateTrans);
-
- /**
- * Transfer scan operation to a deleting transaction. Use this function
- * when a scan has found a record that you want to delete.
- * 1. Start a new transaction.
- * 2. Call the function takeOverForDelete using your new transaction
- * as parameter, all the properties of the found record will be copied
- * to the new transaction.
- * 3. When you execute the new transaction, the lock held by the scan will
- * be transferred to the new transaction(its taken over).
- *
- * @note You must have started the scan with openScanExclusive
- * to be able to delete the found tuple.
- *
- * @param deleteTrans the delete transaction connection.
- * @return an NdbOperation or NULL.
- */
- int deleteTuple();
- int deleteTuple(NdbConnection* takeOverTransaction);
-
- /**
- * Get underlying operation
- */
- NdbOperation* getOperation();
-private:
- NdbResultSet(NdbScanOperation*);
-
- ~NdbResultSet();
-
- void init();
-
- NdbScanOperation* m_operation;
-};
-
-inline
-NdbOperation*
-NdbResultSet::getOperation(){
- return m_operation;
-}
-
-#endif
diff --git a/ndb/include/ndbapi/NdbScanFilter.hpp b/ndb/include/ndbapi/NdbScanFilter.hpp
index 9f8a01b1059..b5457bab99b 100644
--- a/ndb/include/ndbapi/NdbScanFilter.hpp
+++ b/ndb/include/ndbapi/NdbScanFilter.hpp
@@ -45,7 +45,19 @@ public:
NAND = 3, ///< NOT (x1 AND x2 AND x3)
NOR = 4 ///< NOT (x1 OR x2 OR x3)
};
-
+
+ enum BinaryCondition
+ {
+ COND_LE = 0, ///< lower bound
+ COND_LT = 1, ///< lower bound, strict
+ COND_GE = 2, ///< upper bound
+ COND_GT = 3, ///< upper bound, strict
+ COND_EQ = 4, ///< equality
+ COND_NE = 5, ///< not equal
+ COND_LIKE = 6, ///< like
+ COND_NOT_LIKE = 7 ///< not like
+ };
+
/**
* @name Grouping
* @{
@@ -74,7 +86,12 @@ public:
* <i>Explanation missing</i>
*/
int isfalse();
-
+
+ /**
+ * Compare column <b>ColId</b> with <b>val</b>
+ */
+ int cmp(BinaryCondition cond, int ColId, const void *val, Uint32 len = 0);
+
/**
* @name Integer Comparators
* @{
@@ -82,80 +99,61 @@ public:
/** Compare column value with integer for equal
* ®return 0 if successful, -1 otherwize
*/
- int eq(int ColId, Uint32 value);
+ int eq(int ColId, Uint32 value) { return cmp(COND_EQ, ColId, &value, 4);}
+
/** Compare column value with integer for not equal.
* ®return 0 if successful, -1 otherwize
*/
- int ne(int ColId, Uint32 value);
+ int ne(int ColId, Uint32 value) { return cmp(COND_NE, ColId, &value, 4);}
/** Compare column value with integer for less than.
* ®return 0 if successful, -1 otherwize
*/
- int lt(int ColId, Uint32 value);
+ int lt(int ColId, Uint32 value) { return cmp(COND_LT, ColId, &value, 4);}
/** Compare column value with integer for less than or equal.
* ®return 0 if successful, -1 otherwize
*/
- int le(int ColId, Uint32 value);
+ int le(int ColId, Uint32 value) { return cmp(COND_LE, ColId, &value, 4);}
/** Compare column value with integer for greater than.
* ®return 0 if successful, -1 otherwize
*/
- int gt(int ColId, Uint32 value);
+ int gt(int ColId, Uint32 value) { return cmp(COND_GT, ColId, &value, 4);}
/** Compare column value with integer for greater than or equal.
* ®return 0 if successful, -1 otherwize
*/
- int ge(int ColId, Uint32 value);
+ int ge(int ColId, Uint32 value) { return cmp(COND_GE, ColId, &value, 4);}
/** Compare column value with integer for equal. 64-bit.
* ®return 0 if successful, -1 otherwize
*/
- int eq(int ColId, Uint64 value);
+ int eq(int ColId, Uint64 value) { return cmp(COND_EQ, ColId, &value, 8);}
/** Compare column value with integer for not equal. 64-bit.
* ®return 0 if successful, -1 otherwize
*/
- int ne(int ColId, Uint64 value);
+ int ne(int ColId, Uint64 value) { return cmp(COND_NE, ColId, &value, 8);}
/** Compare column value with integer for less than. 64-bit.
* ®return 0 if successful, -1 otherwize
*/
- int lt(int ColId, Uint64 value);
+ int lt(int ColId, Uint64 value) { return cmp(COND_LT, ColId, &value, 8);}
/** Compare column value with integer for less than or equal. 64-bit.
* ®return 0 if successful, -1 otherwize
*/
- int le(int ColId, Uint64 value);
+ int le(int ColId, Uint64 value) { return cmp(COND_LE, ColId, &value, 8);}
/** Compare column value with integer for greater than. 64-bit.
* ®return 0 if successful, -1 otherwize
*/
- int gt(int ColId, Uint64 value);
+ int gt(int ColId, Uint64 value) { return cmp(COND_GT, ColId, &value, 8);}
/** Compare column value with integer for greater than or equal. 64-bit.
* ®return 0 if successful, -1 otherwize
*/
- int ge(int ColId, Uint64 value);
+ int ge(int ColId, Uint64 value) { return cmp(COND_GE, ColId, &value, 8);}
/** @} *********************************************************************/
/** Check if column value is NULL */
int isnull(int ColId);
/** Check if column value is non-NULL */
int isnotnull(int ColId);
-
- /**
- * @name String Comparators
- * @{
- */
- /**
- * Compare string against a Char or Varchar column.
- *
- * By default Char comparison blank-pads both sides to common length.
- * Varchar comparison does not blank-pad.
- *
- * The extra <i>nopad</i> argument can be used to
- * force non-padded comparison for a Char column.
- * ®return 0 if successful, -1 otherwize
- */
- int eq(int ColId, const char * val, Uint32 len, bool nopad=false);
- int ne(int ColId, const char * val, Uint32 len, bool nopad=false);
- int lt(int ColId, const char * val, Uint32 len, bool nopad=false);
- int le(int ColId, const char * val, Uint32 len, bool nopad=false);
- int gt(int ColId, const char * val, Uint32 len, bool nopad=false);
- int ge(int ColId, const char * val, Uint32 len, bool nopad=false);
-
+
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Like comparison operator.
* ®return 0 if successful, -1 otherwize
@@ -167,9 +165,12 @@ public:
*/
int notlike(int ColId, const char * val, Uint32 len, bool nopad=false);
/** @} *********************************************************************/
+#endif
private:
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class NdbScanFilterImpl;
+#endif
class NdbScanFilterImpl & m_impl;
NdbScanFilter& operator=(const NdbScanFilter&); ///< Defined not implemented
};
diff --git a/ndb/include/ndbapi/NdbScanOperation.hpp b/ndb/include/ndbapi/NdbScanOperation.hpp
index f6e68dd4abe..1c9649195d2 100644
--- a/ndb/include/ndbapi/NdbScanOperation.hpp
+++ b/ndb/include/ndbapi/NdbScanOperation.hpp
@@ -14,18 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*****************************************************************************
- * Name: NdbScanOperation.hpp
- * Include:
- * Link:
- * Author: Martin Sköld
- * Date: 2002-04-01
- * Version: 0.1
- * Description: Table scan support
- * Documentation:
- * Adjust: 2002-04-01 Martin Sköld First version.
- ****************************************************************************/
-
#ifndef NdbScanOperation_H
#define NdbScanOperation_H
@@ -39,68 +27,145 @@ class NdbResultSet;
* @brief Class of scan operations for use in transactions.
*/
class NdbScanOperation : public NdbOperation {
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class Ndb;
- friend class NdbConnection;
+ friend class NdbTransaction;
friend class NdbResultSet;
friend class NdbOperation;
friend class NdbBlob;
-public:
- /**
- * Type of cursor
- */
- enum CursorType {
- NoCursor = 0,
- ScanCursor = 1,
- IndexCursor = 2
- };
-
- /**
- * Type of cursor
- */
- CursorType get_cursor_type() const;
+#endif
+public:
/**
- * readTuples returns a NdbResultSet where tuples are stored.
- * Tuples are not stored in NdbResultSet until execute(NoCommit)
- * has been executed and nextResult has been called.
+ * readTuples
*
- * @param parallel Scan parallelism
+ * @param lock_mode Lock mode
* @param batch No of rows to fetch from each fragment at a time
- * @param LockMode Scan lock handling
- * @returns NdbResultSet.
+ * @param parallel No of fragments to scan in parallell
* @note specifying 0 for batch and parallall means max performance
*/
- NdbResultSet* readTuples(LockMode = LM_Read,
- Uint32 batch = 0, Uint32 parallel = 0);
+ int readTuples(LockMode lock_mode = LM_Read,
+ Uint32 batch = 0, Uint32 parallel = 0);
- inline NdbResultSet* readTuples(int parallell){
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ inline int readTuples(int parallell){
return readTuples(LM_Read, 0, parallell);
}
- inline NdbResultSet* readTuplesExclusive(int parallell = 0){
+ inline int readTuplesExclusive(int parallell = 0){
return readTuples(LM_Exclusive, 0, parallell);
}
+#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
NdbBlob* getBlobHandle(const char* anAttrName);
NdbBlob* getBlobHandle(Uint32 anAttrId);
+#endif
-protected:
- CursorType m_cursor_type;
+ /**
+ * Get the next tuple in a scan transaction.
+ *
+ * After each call to nextResult
+ * the buffers and NdbRecAttr objects defined in
+ * NdbOperation::getValue are updated with values
+ * from the scanned tuple.
+ *
+ * @param fetchAllowed If set to false, then fetching is disabled
+ * @param forceSend If true send will occur immediately (see @ref secAdapt)
+ *
+ * The NDB API will contact the NDB Kernel for more tuples
+ * when necessary to do so unless you set the fetchAllowed
+ * to false.
+ * This will force NDB to process any records it
+ * already has in it's caches. When there are no more cached
+ * records it will return 2. You must then call nextResult
+ * with fetchAllowed = true in order to contact NDB for more
+ * records.
+ *
+ * fetchAllowed = false is useful when you want to update or
+ * delete all the records fetched in one transaction(This will save a
+ * lot of round trip time and make updates or deletes of scanned
+ * records a lot faster).
+ * While nextResult(false)
+ * returns 0 take over the record to another transaction. When
+ * nextResult(false) returns 2 you must execute and commit the other
+ * transaction. This will cause the locks to be transferred to the
+ * other transaction, updates or deletes will be made and then the
+ * locks will be released.
+ * After that, call nextResult(true) which will fetch new records and
+ * cache them in the NdbApi.
+ *
+ * @note If you don't take over the records to another transaction the
+ * locks on those records will be released the next time NDB Kernel
+ * is contacted for more records.
+ *
+ * @note Please contact for examples of efficient scan
+ * updates and deletes.
+ *
+ * @note See ndb/examples/ndbapi_scan_example for usage.
+ *
+ * @return
+ * - -1: if unsuccessful,<br>
+ * - 0: if another tuple was received, and<br>
+ * - 1: if there are no more tuples to scan.
+ * - 2: if there are no more cached records in NdbApi
+ */
+ int nextResult(bool fetchAllowed = true, bool forceSend = false);
+
+ /**
+ * Close scan
+ */
+ void close(bool forceSend = false, bool releaseOp = false);
+
+ /**
+ * Update current tuple
+ *
+ * @return an NdbOperation or NULL.
+ */
+ NdbOperation* updateCurrentTuple();
+ /**
+ * Update current tuple
+ *
+ * @param updateTrans Transaction that should perform the update
+ *
+ * @return an NdbOperation or NULL.
+ */
+ NdbOperation* updateCurrentTuple(NdbTransaction* updateTrans);
+ /**
+ * Delete current tuple
+ * @return 0 on success or -1 on failure
+ */
+ int deleteCurrentTuple();
+ /**
+ * Delete current tuple
+ *
+ * @param takeOverTransaction Transaction that should perform the delete
+ *
+ * @return 0 on success or -1 on failure
+ */
+ int deleteCurrentTuple(NdbTransaction* takeOverTransaction);
+
+ /**
+ * Restart scan with exactly the same
+ * getValues and search conditions
+ */
+ int restart(bool forceSend = false);
+
+protected:
NdbScanOperation(Ndb* aNdb);
virtual ~NdbScanOperation();
- int nextResult(bool fetchAllowed = true, bool forceSend = false);
+ int nextResultImpl(bool fetchAllowed = true, bool forceSend = false);
virtual void release();
- void closeScan(bool forceSend = false, bool releaseOp = false);
int close_impl(class TransporterFacade*, bool forceSend = false);
// Overloaded methods from NdbCursorOperation
int executeCursor(int ProcessorId);
// Overloaded private methods from NdbOperation
- int init(const NdbTableImpl* tab, NdbConnection* myConnection);
+ int init(const NdbTableImpl* tab, NdbTransaction*);
int prepareSend(Uint32 TC_ConnectPtr, Uint64 TransactionId);
int doSend(int ProcessorId);
void checkForceSend(bool forceSend);
@@ -108,14 +173,11 @@ protected:
virtual void setErrorCode(int aErrorCode);
virtual void setErrorCodeAbort(int aErrorCode);
- NdbResultSet * m_resultSet;
- NdbResultSet* getResultSet();
- NdbConnection *m_transConnection;
+ NdbTransaction *m_transConnection;
// Scan related variables
Uint32 theParallelism;
Uint32 m_keyInfo;
- NdbApiSignal* theSCAN_TABREQ;
int getFirstATTRINFOScan();
int doSendScan(int ProcessorId);
@@ -154,17 +216,41 @@ protected:
void execCLOSE_SCAN_REP();
int getKeyFromKEYINFO20(Uint32* data, unsigned size);
- NdbOperation* takeOverScanOp(OperationType opType, NdbConnection*);
+ NdbOperation* takeOverScanOp(OperationType opType, NdbTransaction*);
- Uint32 m_ordered;
-
- int restart(bool forceSend = false);
+ bool m_ordered;
+ bool m_descending;
+ Uint32 m_read_range_no;
+ NdbRecAttr *m_curr_row; // Pointer to last returned row
};
inline
-NdbScanOperation::CursorType
-NdbScanOperation::get_cursor_type() const {
- return m_cursor_type;
+NdbOperation*
+NdbScanOperation::updateCurrentTuple(){
+ return updateCurrentTuple(m_transConnection);
+}
+
+inline
+NdbOperation*
+NdbScanOperation::updateCurrentTuple(NdbTransaction* takeOverTrans){
+ return takeOverScanOp(NdbOperation::UpdateRequest,
+ takeOverTrans);
+}
+
+inline
+int
+NdbScanOperation::deleteCurrentTuple(){
+ return deleteCurrentTuple(m_transConnection);
+}
+
+inline
+int
+NdbScanOperation::deleteCurrentTuple(NdbTransaction * takeOverTrans){
+ void * res = takeOverScanOp(NdbOperation::DeleteRequest,
+ takeOverTrans);
+ if(res == 0)
+ return -1;
+ return 0;
}
#endif
diff --git a/ndb/include/ndbapi/NdbConnection.hpp b/ndb/include/ndbapi/NdbTransaction.hpp
index 2ab6f7d6f64..2e102b104d8 100644
--- a/ndb/include/ndbapi/NdbConnection.hpp
+++ b/ndb/include/ndbapi/NdbTransaction.hpp
@@ -14,14 +14,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#ifndef NdbConnection_H
-#define NdbConnection_H
+#ifndef NdbTransaction_H
+#define NdbTransaction_H
#include <ndb_types.h>
#include <NdbError.hpp>
#include <NdbDictionary.hpp>
-class NdbConnection;
+class NdbTransaction;
class NdbOperation;
class NdbScanOperation;
class NdbIndexScanOperation;
@@ -30,106 +30,81 @@ class NdbApiSignal;
class Ndb;
class NdbBlob;
-
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+// to be documented later
/**
* NdbAsynchCallback functions are used when executing asynchronous
- * transactions (using NdbConnection::executeAsynchPrepare, or
- * NdbConnection::executeAsynch).
+ * transactions (using NdbTransaction::executeAsynchPrepare, or
+ * NdbTransaction::executeAsynch).
* The functions are called when the execute has finished.
* See @ref secAsync for more information.
*/
-typedef void (* NdbAsynchCallback)(int, NdbConnection*, void*);
+typedef void (* NdbAsynchCallback)(int, NdbTransaction*, void*);
+#endif
-/**
- * Commit type of transaction
- */
-enum AbortOption {
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
- CommitIfFailFree = 0,
- CommitAsMuchAsPossible = 2, ///< Commit transaction with as many
- TryCommit = 0, ///< <i>Missing explanation</i>
-#endif
- AbortOnError = 0, ///< Abort transaction on failed operation
- AO_IgnoreError = 2 ///< Transaction continues on failed operation
+enum AbortOption {
+ CommitIfFailFree= 0,
+ TryCommit= 0,
+ AbortOnError= 0,
+ CommitAsMuchAsPossible= 2,
+ AO_IgnoreError= 2
};
-
-typedef AbortOption CommitType;
-
-
-/**
- * Execution type of transaction
- */
enum ExecType {
- NoExecTypeDef = -1, ///< Erroneous type (Used for debugging only)
- Prepare, ///< <i>Missing explanation</i>
- NoCommit, ///< Execute the transaction as far as it has
- ///< been defined, but do not yet commit it
- Commit, ///< Execute and try to commit the transaction
- Rollback ///< Rollback transaction
+ NoExecTypeDef = -1,
+ Prepare,
+ NoCommit,
+ Commit,
+ Rollback
};
-
+#endif
/**
- * @class NdbConnection
+ * @class NdbTransaction
* @brief Represents a transaction.
*
- * A transaction (represented by an NdbConnection object)
- * belongs to an Ndb object and is typically created using
- * Ndb::startTransaction.
+ * A transaction (represented by an NdbTransaction object)
+ * belongs to an Ndb object and is created using
+ * Ndb::startTransaction().
* A transaction consists of a list of operations
- * (represented by NdbOperation objects).
+ * (represented by NdbOperation, NdbScanOperation, NdbIndexOperation,
+ * and NdbIndexScanOperation objects).
* Each operation access exactly one table.
*
- * After getting the NdbConnection object,
- * the first step is to get (allocate) an operation given the table name.
+ * After getting the NdbTransaction object,
+ * the first step is to get (allocate) an operation given the table name using
+ * one of the methods getNdbOperation(), getNdbScanOperation(),
+ * getNdbIndexOperation(), or getNdbIndexScanOperation().
* Then the operation is defined.
- * Several operations can be defined in parallel on the same
- * NdbConnection object.
- * When all operations are defined, the NdbConnection::execute
- * method sends them to the NDB kernel for execution.
+ * Several operations can be defined on the same
+ * NdbTransaction object, they will in that case be executed in parallell.
+ * When all operations are defined, the execute()
+ * method sends them to the NDB kernel for execution.
*
- * The NdbConnection::execute method returns when the NDB kernel has
+ * The execute() method returns when the NDB kernel has
* completed execution of all operations defined before the call to
- * NdbConnection::execute.
- * All allocated operations should be properly defined
- * before calling NdbConnection::execute.
+ * execute(). All allocated operations should be properly defined
+ * before calling execute().
*
- * A call to NdbConnection::execute uses one out of three types of execution:
- * -# ExecType::NoCommit Executes operations without committing them.
- * -# ExecType::Commit Executes remaining operation and commits the
+ * A call to execute() uses one out of three types of execution:
+ * -# NdbTransaction::NoCommit Executes operations without committing them.
+ * -# NdbTransaction::Commit Executes remaining operation and commits the
* complete transaction
- * -# ExecType::Rollback Rollbacks the entire transaction.
+ * -# NdbTransaction::Rollback Rollbacks the entire transaction.
*
- * NdbConnection::execute is equipped with an extra error handling parameter
+ * execute() is equipped with an extra error handling parameter.
* There are two alternatives:
- * -# AbortOption::AbortOnError (default).
+ * -# NdbTransaction::AbortOnError (default).
* The transaction is aborted if there are any error during the
* execution
- * -# AbortOption::IgnoreError
+ * -# NdbTransaction::AO_IgnoreError
* Continue execution of transaction even if operation fails
*
- * NdbConnection::execute can sometimes indicate an error
- * (return with -1) while the error code on the NdbConnection is 0.
- * This is an indication that one of the operations found a record
- * problem. The transaction is still ok and can continue as usual.
- * The NdbConnection::execute returns -1 together with error code
- * on NdbConnection object equal to 0 always means that an
- * operation was not successful but that the total transaction was OK.
- * By checking error codes on the individual operations it is possible
- * to find out which operation was not successful.
- *
- * NdbConnection::executeScan is used to setup a scan in the NDB kernel
- * after it has been defined.
- * NdbConnection::nextScanResult is used to iterate through the
- * scanned tuples.
- * After each call to NdbConnection::nextScanResult, the pointers
- * of NdbRecAttr objects defined in the NdbOperation::getValue
- * operations are updated with the values of the new the scanned tuple.
*/
/* FUTURE IMPLEMENTATION:
* Later a prepare mode will be added when Ndb supports Prepare-To-Commit
- * The NdbConnection can deliver the Transaction Id of the transaction.
+ * The NdbTransaction can deliver the Transaction Id of the transaction.
* After committing a transaction it is also possible to retrieve the
* global transaction checkpoint which the transaction was put in.
*
@@ -148,24 +123,66 @@ enum ExecType {
* not known the table of the tuple. As long as the table is
* derived from the known base class everything is ok.
* It is not possible to provide any primary key since it is
- * already supplied with the call to NdbConnection::getNdbOperation.
+ * already supplied with the call to NdbTransaction::getNdbOperation.
* -# The third method is used when a scanned tuple is to be transferred to
* another transaction. In this case it is not possible to define the
* primary key since it came along from the scanned tuple.
*
*/
-class NdbConnection
+
+class NdbTransaction
{
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
friend class Ndb;
friend class NdbOperation;
friend class NdbScanOperation;
friend class NdbIndexOperation;
friend class NdbIndexScanOperation;
friend class NdbBlob;
-
+#endif
+
public:
/**
+ * Commit type of transaction
+ */
+ enum AbortOption {
+ AbortOnError= ///< Abort transaction on failed operation
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ ::AbortOnError
+#endif
+ ,AO_IgnoreError= ///< Transaction continues on failed operation
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ ::AO_IgnoreError
+#endif
+ };
+
+ /**
+ * Execution type of transaction
+ */
+ enum ExecType {
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ NoExecTypeDef=
+ ::NoExecTypeDef, ///< Erroneous type (Used for debugging only)
+ Prepare= ::Prepare, ///< <i>Missing explanation</i>
+#endif
+ NoCommit= ///< Execute the transaction as far as it has
+ ///< been defined, but do not yet commit it
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ ::NoCommit
+#endif
+ ,Commit= ///< Execute and try to commit the transaction
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ ::Commit
+#endif
+ ,Rollback ///< Rollback transaction
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ = ::Rollback
+#endif
+ };
+
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ /**
* Get an NdbOperation for a table.
* Note that the operation has to be defined before it is executed.
*
@@ -176,41 +193,100 @@ public:
* @return Pointer to an NdbOperation object if successful, otherwise NULL.
*/
NdbOperation* getNdbOperation(const char* aTableName);
+#endif
/**
+ * Get an NdbOperation for a table.
+ * Note that the operation has to be defined before it is executed.
+ *
+ * @note All operations within the same transaction need to
+ * be initialized with this method.
+ *
+ * @param aTable
+ * A table object (fetched by NdbDictionary::Dictionary::getTable)
+ * @return Pointer to an NdbOperation object if successful, otherwise NULL.
+ */
+ NdbOperation* getNdbOperation(const NdbDictionary::Table * aTable);
+
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ /**
* Get an operation from NdbScanOperation idlelist and
- * get the NdbConnection object which
+ * get the NdbTransaction object which
* was fetched by startTransaction pointing to this operation.
*
- * @param aTableName a table name.
+ * @param aTableName The table name.
* @return pointer to an NdbOperation object if successful, otherwise NULL
*/
NdbScanOperation* getNdbScanOperation(const char* aTableName);
+#endif
/**
* Get an operation from NdbScanOperation idlelist and
- * get the NdbConnection object which
+ * get the NdbTransaction object which
+ * was fetched by startTransaction pointing to this operation.
+ *
+ * @param aTable
+ * A table object (fetched by NdbDictionary::Dictionary::getTable)
+ * @return pointer to an NdbOperation object if successful, otherwise NULL
+ */
+ NdbScanOperation* getNdbScanOperation(const NdbDictionary::Table * aTable);
+
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ /**
+ * Get an operation from NdbIndexScanOperation idlelist and
+ * get the NdbTransaction object which
* was fetched by startTransaction pointing to this operation.
*
* @param anIndexName The index name.
- * @param aTableName a table name.
+ * @param aTableName The table name.
* @return pointer to an NdbOperation object if successful, otherwise NULL
*/
NdbIndexScanOperation* getNdbIndexScanOperation(const char* anIndexName,
const char* aTableName);
+ NdbIndexScanOperation* getNdbIndexScanOperation
+ (const NdbDictionary::Index *anIndex, const NdbDictionary::Table *aTable);
+#endif
/**
+ * Get an operation from NdbIndexScanOperation idlelist and
+ * get the NdbTransaction object which
+ * was fetched by startTransaction pointing to this operation.
+ *
+ * @param anIndex
+ An index object (fetched by NdbDictionary::Dictionary::getIndex).
+ * @return pointer to an NdbOperation object if successful, otherwise NULL
+ */
+ NdbIndexScanOperation* getNdbIndexScanOperation
+ (const NdbDictionary::Index *anIndex);
+
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ /**
* Get an operation from NdbIndexOperation idlelist and
- * get the NdbConnection object that
+ * get the NdbTransaction object that
* was fetched by startTransaction pointing to this operation.
*
- * @param indexName An index name (as created by createIndex).
- * @param tableName A table name.
+ * @param anIndexName The index name (as created by createIndex).
+ * @param aTableName The table name.
* @return Pointer to an NdbIndexOperation object if
* successful, otherwise NULL
*/
- NdbIndexOperation* getNdbIndexOperation(const char* indexName,
- const char* tableName);
+ NdbIndexOperation* getNdbIndexOperation(const char* anIndexName,
+ const char* aTableName);
+ NdbIndexOperation* getNdbIndexOperation(const NdbDictionary::Index *anIndex,
+ const NdbDictionary::Table *aTable);
+#endif
+
+ /**
+ * Get an operation from NdbIndexOperation idlelist and
+ * get the NdbTransaction object that
+ * was fetched by startTransaction pointing to this operation.
+ *
+ * @param anIndex
+ * An index object (fetched by NdbDictionary::Dictionary::getIndex).
+ * @return Pointer to an NdbIndexOperation object if
+ * successful, otherwise NULL
+ */
+ NdbIndexOperation* getNdbIndexOperation(const NdbDictionary::Index *anIndex);
/**
* @name Execute Transaction
@@ -238,10 +314,18 @@ public:
* the send.
* @return 0 if successful otherwise -1.
*/
- int execute(ExecType execType,
+ int execute(ExecType execType,
AbortOption abortOption = AbortOnError,
int force = 0 );
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ int execute(::ExecType execType,
+ ::AbortOption abortOption = ::AbortOnError,
+ int force = 0 )
+ { return execute ((ExecType)execType,(AbortOption)abortOption,force); }
+#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ // to be documented later
/**
* Prepare an asynchronous transaction.
*
@@ -255,7 +339,7 @@ public:
* ExecType::Rollback rollbacks the entire transaction.
* @param callback A callback method. This method gets
* called when the transaction has been
- * executed. See @ref ndbapi_example2.cpp
+ * executed. See @ref ndbapi_async1.cpp
* for an example on how to specify and use
* a callback method.
* @param anyObject A void pointer. This pointer is forwarded to the
@@ -269,15 +353,23 @@ public:
NdbAsynchCallback callback,
void* anyObject,
AbortOption abortOption = AbortOnError);
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ void executeAsynchPrepare(::ExecType execType,
+ NdbAsynchCallback callback,
+ void* anyObject,
+ ::AbortOption abortOption = ::AbortOnError)
+ { executeAsynchPrepare((ExecType)execType, callback, anyObject,
+ (AbortOption)abortOption); }
+#endif
/**
* Prepare and send an asynchronous transaction.
*
* This method perform the same action as
- * NdbConnection::executeAsynchPrepare
+ * NdbTransaction::executeAsynchPrepare
* but also sends the operations to the NDB kernel.
*
- * See NdbConnection::executeAsynchPrepare for information
+ * See NdbTransaction::executeAsynchPrepare for information
* about the parameters of this method.
*
* See @ref secAsync for more information on
@@ -287,7 +379,15 @@ public:
NdbAsynchCallback aCallback,
void* anyObject,
AbortOption abortOption = AbortOnError);
-
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+ void executeAsynch(::ExecType aTypeOfExec,
+ NdbAsynchCallback aCallback,
+ void* anyObject,
+ ::AbortOption abortOption= ::AbortOnError)
+ { executeAsynch((ExecType)aTypeOfExec, aCallback, anyObject,
+ (AbortOption)abortOption); }
+#endif
+#endif
/**
* Refresh
* Update timeout counter of this transaction
@@ -302,25 +402,39 @@ public:
/**
* Close transaction
- * @note It is not allowed to call NdbConnection::close after sending the
+ *
+ * @note Equivalent to to calling Ndb::closeTransaction()
+ */
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ /**
+ * @note It is not allowed to call NdbTransaction::close after sending the
* transaction asynchronously before the callback method has
* been called.
* (The application should keep track of the number of
* outstanding transactions and wait until all of them
- * has completed before calling NdbConnection::close).
+ * has completed before calling NdbTransaction::close).
* If the transaction is not committed it will be aborted.
*/
+#endif
void close();
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
* Restart transaction
*
* Once a transaction has been completed successfully
* it can be started again wo/ calling closeTransaction/startTransaction
*
- * Note this method also releases completed operations
+ * @note This method also releases completed operations
+ *
+ * @note This method does not close open scans,
+ * c.f. NdbScanOperation::close()
+ *
+ * @note This method can only be called _directly_ after commit
+ * and only if commit is successful
*/
int restart();
+#endif
/** @} *********************************************************************/
@@ -347,23 +461,20 @@ public:
* (This is because no updates are performed in scan transactions.)
*
* @return GCI of transaction or -1 if GCI is not available.
- * (Note that there has to be an NdbConnection::execute call
+ * (Note that there has to be an NdbTransaction::execute call
* with Ndb::Commit for the GCI to be available.)
*/
- int getGCI();
+ int getGCI();
/**
* Get transaction identity.
*
* @return Transaction id.
*/
- Uint64 getTransactionId();
+ Uint64 getTransactionId();
/**
- * Returns the commit status of the transaction.
- *
- * @return The commit status of the transaction, i.e. one of
- * { NotStarted, Started, TimeOut, Committed, Aborted, NeedAbort }
+ * The commit status of the transaction.
*/
enum CommitStatusType {
NotStarted, ///< Transaction not yet started
@@ -373,6 +484,11 @@ public:
NeedAbort ///< <i>Missing explanation</i>
};
+ /**
+ * Get the commit status of the transaction.
+ *
+ * @return The commit status of the transaction
+ */
CommitStatusType commitStatus();
/** @} *********************************************************************/
@@ -391,10 +507,10 @@ public:
/**
* Get the latest NdbOperation which had an error.
- * This method is used on the NdbConnection object to find the
+ * This method is used on the NdbTransaction object to find the
* NdbOperation causing an error.
* To find more information about the
- * actual error, use method NdbOperation::getNdbError
+ * actual error, use method NdbOperation::getNdbError()
* on the returned NdbOperation object.
*
* @return The NdbOperation causing the latest error.
@@ -413,9 +529,9 @@ public:
*
* This method should only be used <em>after</em> a transaction
* has been executed.
- * - NdbConnection::getNextCompletedOperation(NULL) returns the
+ * - NdbTransaction::getNextCompletedOperation(NULL) returns the
* first NdbOperation object.
- * - NdbConnection::getNextCompletedOperation(op) returns the
+ * - NdbTransaction::getNextCompletedOperation(op) returns the
* NdbOperation object defined after the NdbOperation "op".
*
* This method is typically used to fetch all NdbOperation:s of
@@ -430,6 +546,10 @@ public:
*/
const NdbOperation * getNextCompletedOperation(const NdbOperation * op)const;
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+ const NdbOperation* getFirstDefinedOperation()const{return theFirstOpInList;}
+ const NdbOperation* getLastDefinedOperation()const{return theLastOpInList;}
+
/** @} *********************************************************************/
/**
@@ -441,16 +561,12 @@ public:
*/
int executePendingBlobOps(Uint8 flags = 0xFF);
- // Fast path calls for MySQL ha_ndbcluster
- NdbOperation* getNdbOperation(const NdbDictionary::Table * table);
- NdbIndexOperation* getNdbIndexOperation(const NdbDictionary::Index *,
- const NdbDictionary::Table * table);
- NdbScanOperation* getNdbScanOperation(const NdbDictionary::Table * table);
- NdbIndexScanOperation* getNdbIndexScanOperation(const NdbDictionary::Index * index,
- const NdbDictionary::Table * table);
+ /**
+ * Get nodeId of TC for this transaction
+ */
+ Uint32 getConnectedNodeId(); // Get Connected node id
+#endif
- Uint32 getConnectedNodeId(); // Get Connected node id
-
private:
/**
* Release completed operations
@@ -466,9 +582,9 @@ private:
* These are the create and delete methods of this class. *
**************************************************************************/
- NdbConnection(Ndb* aNdb);
+ NdbTransaction(Ndb* aNdb);
- ~NdbConnection();
+ ~NdbTransaction();
void init(); // Initialize connection object for new transaction
@@ -487,8 +603,8 @@ private:
int getTC_ConnectPtr(); // Gets TC Connect pointer
void setBuddyConPtr(Uint32); // Sets Buddy Con Ptr
Uint32 getBuddyConPtr(); // Gets Buddy Con Ptr
- NdbConnection* next(); // Returns the next pointer
- void next(NdbConnection*); // Sets the next pointer
+ NdbTransaction* next(); // Returns the next pointer
+ void next(NdbTransaction*); // Sets the next pointer
enum ConStatusType {
NotConnected,
@@ -600,7 +716,7 @@ private:
NdbOperation* theErrorOperation; // The NdbOperation where the error occurred
Ndb* theNdb; // Pointer to Ndb object
- NdbConnection* theNext; // Next pointer. Used in idle list.
+ NdbTransaction* theNext; // Next pointer. Used in idle list.
NdbOperation* theFirstOpInList; // First operation in defining list.
NdbOperation* theLastOpInList; // Last operation in defining list.
@@ -693,16 +809,18 @@ private:
friend class HugoOperations;
};
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+
inline
Uint32
-NdbConnection::get_send_size()
+NdbTransaction::get_send_size()
{
return 0;
}
inline
void
-NdbConnection::set_send_size(Uint32 send_size)
+NdbTransaction::set_send_size(Uint32 send_size)
{
return;
}
@@ -713,7 +831,7 @@ NdbConnection::set_send_size(Uint32 send_size)
inline
int
-NdbConnection::checkMagicNumber()
+NdbTransaction::checkMagicNumber()
{
if (theMagicNumber == 0x37412619)
return 0;
@@ -727,7 +845,7 @@ NdbConnection::checkMagicNumber()
inline
bool
-NdbConnection::checkState_TransId(const Uint32 * transId) const {
+NdbTransaction::checkState_TransId(const Uint32 * transId) const {
const Uint32 tTmp1 = transId[0];
const Uint32 tTmp2 = transId[1];
Uint64 tRecTransId = (Uint64)tTmp1 + ((Uint64)tTmp2 << 32);
@@ -742,14 +860,14 @@ Remark: Set the transaction identity.
************************************************************************************************/
inline
void
-NdbConnection::setTransactionId(Uint64 aTransactionId)
+NdbTransaction::setTransactionId(Uint64 aTransactionId)
{
theTransactionId = aTransactionId;
}
inline
void
-NdbConnection::setConnectedNodeId(Uint32 aNode, Uint32 aSequenceNo)
+NdbTransaction::setConnectedNodeId(Uint32 aNode, Uint32 aSequenceNo)
{
theDBnode = aNode;
theNodeSequence = aSequenceNo;
@@ -762,7 +880,7 @@ Remark: Get Connected node id.
******************************************************************************/
inline
Uint32
-NdbConnection::getConnectedNodeId()
+NdbTransaction::getConnectedNodeId()
{
return theDBnode;
}
@@ -774,7 +892,7 @@ Remark: Set my block refrerence.
******************************************************************************/
inline
void
-NdbConnection::setMyBlockReference(int aBlockRef)
+NdbTransaction::setMyBlockReference(int aBlockRef)
{
theMyRef = aBlockRef;
}
@@ -786,7 +904,7 @@ Remark: Sets TC Connect pointer.
******************************************************************************/
inline
void
-NdbConnection::setTC_ConnectPtr(Uint32 aTCConPtr)
+NdbTransaction::setTC_ConnectPtr(Uint32 aTCConPtr)
{
theTCConPtr = aTCConPtr;
}
@@ -799,61 +917,61 @@ Remark: Gets TC Connect pointer.
******************************************************************************/
inline
int
-NdbConnection::getTC_ConnectPtr()
+NdbTransaction::getTC_ConnectPtr()
{
return theTCConPtr;
}
inline
void
-NdbConnection::setBuddyConPtr(Uint32 aBuddyConPtr)
+NdbTransaction::setBuddyConPtr(Uint32 aBuddyConPtr)
{
theBuddyConPtr = aBuddyConPtr;
}
inline
-Uint32 NdbConnection::getBuddyConPtr()
+Uint32 NdbTransaction::getBuddyConPtr()
{
return theBuddyConPtr;
}
/******************************************************************************
-NdbConnection* next();
+NdbTransaction* next();
inline
void
-NdbConnection::setBuddyConPtr(Uint32 aBuddyConPtr)
+NdbTransaction::setBuddyConPtr(Uint32 aBuddyConPtr)
{
theBuddyConPtr = aBuddyConPtr;
}
inline
-Uint32 NdbConnection::getBuddyConPtr()
+Uint32 NdbTransaction::getBuddyConPtr()
{
return theBuddyConPtr;
}
-Return Value: Return next pointer to NdbConnection object.
+Return Value: Return next pointer to NdbTransaction object.
Remark: Get the next pointer.
******************************************************************************/
inline
-NdbConnection*
-NdbConnection::next()
+NdbTransaction*
+NdbTransaction::next()
{
return theNext;
}
/******************************************************************************
-void next(NdbConnection aConnection);
+void next(NdbTransaction aTransaction);
-Parameters: aConnection: The connection object.
+Parameters: aTransaction: The connection object.
Remark: Sets the next pointer.
******************************************************************************/
inline
void
-NdbConnection::next(NdbConnection* aConnection)
+NdbTransaction::next(NdbTransaction* aTransaction)
{
- theNext = aConnection;
+ theNext = aTransaction;
}
/******************************************************************************
@@ -864,8 +982,8 @@ Parameters: aStatus: The status.
Remark: Sets Connect status.
******************************************************************************/
inline
-NdbConnection::ConStatusType
-NdbConnection::Status()
+NdbTransaction::ConStatusType
+NdbTransaction::Status()
{
return theStatus;
}
@@ -878,7 +996,7 @@ Remark: Sets Connect status.
******************************************************************************/
inline
void
-NdbConnection::Status( ConStatusType aStatus )
+NdbTransaction::Status( ConStatusType aStatus )
{
theStatus = aStatus;
}
@@ -891,7 +1009,7 @@ Remark: Set global checkpoint identity of the transaction
******************************************************************************/
inline
void
-NdbConnection::setGCI(int aGlobalCheckpointId)
+NdbTransaction::setGCI(int aGlobalCheckpointId)
{
theGlobalCheckpointId = aGlobalCheckpointId;
}
@@ -903,7 +1021,7 @@ Remark: An operation was sent with success that expects a response.
******************************************************************************/
inline
void
-NdbConnection::OpSent()
+NdbTransaction::OpSent()
{
theNoOfOpSent++;
}
@@ -914,7 +1032,7 @@ void executePendingBlobOps();
#include <stdlib.h>
inline
int
-NdbConnection::executePendingBlobOps(Uint8 flags)
+NdbTransaction::executePendingBlobOps(Uint8 flags)
{
if (thePendingBlobOps & flags) {
// not executeNoBlobs because there can be new ops with blobs
@@ -925,8 +1043,12 @@ NdbConnection::executePendingBlobOps(Uint8 flags)
inline
Uint32
-NdbConnection::ptr2int(){
+NdbTransaction::ptr2int(){
return theId;
}
+typedef NdbTransaction NdbConnection;
+
+#endif // ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+
#endif
diff --git a/ndb/include/ndbapi/ndb_cluster_connection.hpp b/ndb/include/ndbapi/ndb_cluster_connection.hpp
index 0e559700716..97db76563aa 100644
--- a/ndb/include/ndbapi/ndb_cluster_connection.hpp
+++ b/ndb/include/ndbapi/ndb_cluster_connection.hpp
@@ -20,39 +20,42 @@
/**
* @class Ndb_cluster_connection
- * @brief Represents a connection to a cluster of storage nodes
+ * @brief Represents a connection to a cluster of storage nodes.
*
- * Always start your application program by creating a
- * Ndb_cluster_connection object. Your application should contain
- * only one Ndb_cluster_connection. Your application connects to
- * a cluster management server when method connect() is called.
- * With the method wait_until_ready() it is possible to wait
- * for the connection to one or several storage nodes.
+ * Any NDB application program should begin with the creation of a
+ * single Ndb_cluster_connection object, and should make use of one
+ * and only one Ndb_cluster_connection. The application connects to
+ * a cluster management server when this object's connect() method is called.
+ * By using the wait_until_ready() method it is possible to wait
+ * for the connection to reach one or more storage nodes.
*/
class Ndb_cluster_connection {
public:
/**
* Create a connection to a cluster of storage nodes
*
- * @param specify the connectstring for where to find the
- * management server
+ * @param connectstring The connectstring for where to find the
+ * management server
*/
- Ndb_cluster_connection(const char * connect_string = 0);
+ Ndb_cluster_connection(const char * connectstring = 0);
~Ndb_cluster_connection();
/**
* Connect to a cluster management server
*
- * @param no_retries specifies the number of retries to perform
- * if the connect fails, negative number results in infinite
- * number of retries
+ * @param no_retries specifies the number of retries to attempt
+ * in the event of connection failure; a negative value
+ * will result in the attempt to connect being repeated
+ * indefinitely
+ *
* @param retry_delay_in_seconds specifies how often retries should
* be performed
- * @param verbose specifies if the method should print progess
*
- * @return 0 if success,
- * 1 if retriable error,
- * -1 if non-retriable error
+ * @param verbose specifies if the method should print a report of its progess
+ *
+ * @return 0 = success,
+ * 1 = recoverable error,
+ * -1 = non-recoverable error
*/
int connect(int no_retries=0, int retry_delay_in_seconds=1, int verbose=0);
@@ -61,15 +64,15 @@ public:
#endif
/**
- * Wait until one or several storage nodes are connected
+ * Wait until the requested connection with one or more storage nodes is successful
*
- * @param time_out_for_first_alive number of seconds to wait until
- * first alive node is detected
- * @param timeout_after_first_alive number of seconds to wait after
- * first alive node is detected
+ * @param timeout_for_first_alive Number of seconds to wait until
+ * first live node is detected
+ * @param timeout_after_first_alive Number of seconds to wait after
+ * first live node is detected
*
- * @return 0 all nodes alive,
- * > 0 at least one node alive,
+ * @return = 0 all nodes live,
+ * > 0 at least one node live,
* < 0 error
*/
int wait_until_ready(int timeout_for_first_alive,
@@ -83,6 +86,7 @@ public:
void set_optimized_node_selection(int val);
unsigned no_db_nodes();
+ unsigned node_id();
#endif
private:
diff --git a/ndb/include/ndbapi/ndb_opt_defaults.h b/ndb/include/ndbapi/ndb_opt_defaults.h
index 63b673ed60d..d03a9dcc36f 100644
--- a/ndb/include/ndbapi/ndb_opt_defaults.h
+++ b/ndb/include/ndbapi/ndb_opt_defaults.h
@@ -17,11 +17,7 @@
#ifndef NDB_OPT_DEFAULTS_H
#define NDB_OPT_DEFAULTS_H
-#ifdef SIGRTMIN
-#define OPT_NDB_SHM_SIGNUM_DEFAULT SIGRTMIN+2
-#else
#define OPT_NDB_SHM_SIGNUM_DEFAULT 0
-#endif
#define OPT_NDB_SHM_DEFAULT 0
#endif
diff --git a/ndb/include/ndbapi/ndberror.h b/ndb/include/ndbapi/ndberror.h
index ceb1881a4cc..2225f68f08d 100644
--- a/ndb/include/ndbapi/ndberror.h
+++ b/ndb/include/ndbapi/ndberror.h
@@ -21,6 +21,8 @@
extern "C" {
#endif
+#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
+
typedef enum
{
ndberror_st_success = 0,
@@ -47,7 +49,8 @@ typedef enum
ndberror_cl_function_not_implemented = 13,
ndberror_cl_unknown_error_code = 14,
ndberror_cl_node_shutdown = 15,
- ndberror_cl_configuration = 16
+ ndberror_cl_configuration = 16,
+ ndberror_cl_schema_object_already_exists = 17
} ndberror_classification_enum;
@@ -92,6 +95,8 @@ const char *ndberror_classification_message(ndberror_classification);
void ndberror_update(ndberror_struct *);
int ndb_error_string(int err_no, char *str, unsigned int size);
+#endif /* doxygen skip internal*/
+
#ifdef __cplusplus
}
#endif
diff --git a/ndb/include/transporter/TransporterDefinitions.hpp b/ndb/include/transporter/TransporterDefinitions.hpp
index d4763ba4c37..18d1ec76a3c 100644
--- a/ndb/include/transporter/TransporterDefinitions.hpp
+++ b/ndb/include/transporter/TransporterDefinitions.hpp
@@ -49,74 +49,50 @@ enum SendStatus {
const Uint32 MAX_MESSAGE_SIZE = (12+4+4+(4*25)+(3*4)+4*4096);
/**
- * TCP Transporter Configuration
+ * TransporterConfiguration
+ *
+ * used for setting up a transporter. the union member specific is for
+ * information specific to a transporter type.
*/
-struct TCP_TransporterConfiguration {
- Uint32 port;
+struct TransporterConfiguration {
+ Uint32 port;
const char *remoteHostName;
const char *localHostName;
NodeId remoteNodeId;
NodeId localNodeId;
- Uint32 sendBufferSize; // Size of SendBuffer of priority B
- Uint32 maxReceiveSize; // Maximum no of bytes to receive
+ NodeId serverNodeId;
bool checksum;
bool signalId;
-};
-
-/**
- * SHM Transporter Configuration
- */
-struct SHM_TransporterConfiguration {
- Uint32 port;
- const char *remoteHostName;
- const char *localHostName;
- NodeId remoteNodeId;
- NodeId localNodeId;
- bool checksum;
- bool signalId;
-
- Uint32 shmKey;
- Uint32 shmSize;
- int signum;
-};
-
-/**
- * OSE Transporter Configuration
- */
-struct OSE_TransporterConfiguration {
- const char *remoteHostName;
- const char *localHostName;
- NodeId remoteNodeId;
- NodeId localNodeId;
- bool checksum;
- bool signalId;
-
- Uint32 prioASignalSize;
- Uint32 prioBSignalSize;
- Uint32 receiveBufferSize; // In number of signals
-};
-
-/**
- * SCI Transporter Configuration
- */
-struct SCI_TransporterConfiguration {
- const char *remoteHostName;
- const char *localHostName;
- Uint32 port;
- Uint32 sendLimit; // Packet size
- Uint32 bufferSize; // Buffer size
-
- Uint32 nLocalAdapters; // 1 or 2, the number of adapters on local host
-
- Uint32 remoteSciNodeId0; // SCInodeId for adapter 1
- Uint32 remoteSciNodeId1; // SCInodeId for adapter 2
-
- NodeId localNodeId; // Local node Id
- NodeId remoteNodeId; // Remote node Id
-
- bool checksum;
- bool signalId;
-
+ bool isMgmConnection; // is a mgm connection, requires transforming
+
+ union { // Transporter specific configuration information
+
+ struct {
+ Uint32 sendBufferSize; // Size of SendBuffer of priority B
+ Uint32 maxReceiveSize; // Maximum no of bytes to receive
+ } tcp;
+
+ struct {
+ Uint32 shmKey;
+ Uint32 shmSize;
+ int signum;
+ } shm;
+
+ struct {
+ Uint32 prioASignalSize;
+ Uint32 prioBSignalSize;
+ } ose;
+
+ struct {
+ Uint32 sendLimit; // Packet size
+ Uint32 bufferSize; // Buffer size
+
+ Uint32 nLocalAdapters; // 1 or 2, the number of adapters on local host
+
+ Uint32 remoteSciNodeId0; // SCInodeId for adapter 1
+ Uint32 remoteSciNodeId1; // SCInodeId for adapter 2
+ } sci;
+ };
};
struct SignalHeader {
diff --git a/ndb/include/transporter/TransporterRegistry.hpp b/ndb/include/transporter/TransporterRegistry.hpp
index 7487d6b1e80..363cdabe10a 100644
--- a/ndb/include/transporter/TransporterRegistry.hpp
+++ b/ndb/include/transporter/TransporterRegistry.hpp
@@ -30,9 +30,12 @@
#include "TransporterDefinitions.hpp"
#include <SocketServer.hpp>
+#include <SocketClient.hpp>
#include <NdbTCP.h>
+#include <mgmapi/mgmapi.h>
+
// A transporter is always in an IOState.
// NoHalt is used initially and as long as it is no restrictions on
// sending or receiving.
@@ -97,7 +100,15 @@ public:
TransporterRegistry(void * callback = 0 ,
unsigned maxTransporters = MAX_NTRANSPORTERS,
unsigned sizeOfLongSignalMemory = 100);
-
+
+ /**
+ * this handle will be used in the client connect thread
+ * to fetch information on dynamic ports. The old handle
+ * (if set) is destroyed, and this is destroyed by the destructor
+ */
+ void set_mgm_handle(NdbMgmHandle h);
+ NdbMgmHandle get_mgm_handle(void) { return m_mgm_handle; };
+
bool init(NodeId localNodeId);
/**
@@ -105,6 +116,20 @@ public:
*/
bool connect_server(NDB_SOCKET_TYPE sockfd);
+ bool connect_client(NdbMgmHandle *h);
+
+ /**
+ * Given a SocketClient, creates a NdbMgmHandle, turns it into a transporter
+ * and returns the socket.
+ */
+ NDB_SOCKET_TYPE connect_ndb_mgmd(SocketClient *sc);
+
+ /**
+ * Given a connected NdbMgmHandle, turns it into a transporter
+ * and returns the socket.
+ */
+ NDB_SOCKET_TYPE connect_ndb_mgmd(NdbMgmHandle *h);
+
/**
* Remove all transporters
*/
@@ -174,10 +199,10 @@ public:
* started, startServer is called. A transporter of the selected kind
* is created and it is put in the transporter arrays.
*/
- bool createTransporter(struct TCP_TransporterConfiguration * config);
- bool createTransporter(struct SCI_TransporterConfiguration * config);
- bool createTransporter(struct SHM_TransporterConfiguration * config);
- bool createTransporter(struct OSE_TransporterConfiguration * config);
+ bool createTCPTransporter(struct TransporterConfiguration * config);
+ bool createSCITransporter(struct TransporterConfiguration * config);
+ bool createSHMTransporter(struct TransporterConfiguration * config);
+ bool createOSETransporter(struct TransporterConfiguration * config);
/**
* prepareSend
@@ -226,16 +251,23 @@ public:
class Transporter_interface {
public:
- unsigned short m_service_port;
+ NodeId m_remote_nodeId;
+ int m_s_service_port; // signed port number
const char *m_interface;
};
Vector<Transporter_interface> m_transporter_interface;
- void add_transporter_interface(const char *interf, unsigned short port);
+ void add_transporter_interface(NodeId remoteNodeId, const char *interf,
+ int s_port); // signed port. <0 is dynamic
+ Transporter* get_transporter(NodeId nodeId);
+ NodeId get_localNodeId() { return localNodeId; };
+
protected:
private:
void * callbackObj;
+ NdbMgmHandle m_mgm_handle;
+
struct NdbThread *m_start_clients_thread;
bool m_run_start_clients_thread;
diff --git a/ndb/include/util/Base64.hpp b/ndb/include/util/Base64.hpp
index 1156636eec8..f4b11ad9214 100644
--- a/ndb/include/util/Base64.hpp
+++ b/ndb/include/util/Base64.hpp
@@ -21,6 +21,7 @@
#include <BaseString.hpp>
int base64_encode(const UtilBuffer &src, BaseString &dst);
+int base64_encode(const void * s, size_t src_len, BaseString &dst);
int base64_decode(const BaseString &src, UtilBuffer &dst);
int base64_decode(const char * s, size_t len, UtilBuffer &dst);
diff --git a/ndb/include/util/Bitmask.hpp b/ndb/include/util/Bitmask.hpp
index 19aa604e4a1..ade57a5ee57 100644
--- a/ndb/include/util/Bitmask.hpp
+++ b/ndb/include/util/Bitmask.hpp
@@ -131,10 +131,26 @@ public:
static void setField(unsigned size, Uint32 data[],
unsigned pos, unsigned len, Uint32 val);
+
+ /**
+ * getField - Get bitfield at given position and length
+ */
+ static void getField(unsigned size, const Uint32 data[],
+ unsigned pos, unsigned len, Uint32 dst[]);
+
+ /**
+ * setField - Set bitfield at given position and length
+ */
+ static void setField(unsigned size, Uint32 data[],
+ unsigned pos, unsigned len, const Uint32 src[]);
+
/**
* getText - Return as hex-digits (only for debug routines).
*/
static char* getText(unsigned size, const Uint32 data[], char* buf);
+private:
+ static void getFieldImpl(const Uint32 data[], unsigned, unsigned, Uint32 []);
+ static void setFieldImpl(Uint32 data[], unsigned, unsigned, const Uint32 []);
};
inline bool
@@ -794,4 +810,45 @@ public:
Bitmask() { this->clear();}
};
+inline void
+BitmaskImpl::getField(unsigned size, const Uint32 src[],
+ unsigned pos, unsigned len, Uint32 dst[])
+{
+ assert(pos + len < (size << 5));
+
+ src += (pos >> 5);
+ Uint32 offset = pos & 31;
+ * dst = (* src >> offset) & (len >= 32 ? ~0 : (1 << len) - 1);
+
+ if(offset + len <= 32)
+ {
+ return;
+ }
+ Uint32 used = (32 - offset);
+ assert(len > used);
+ getFieldImpl(src+1, used & 31, len-used, dst+(used >> 5));
+}
+
+inline void
+BitmaskImpl::setField(unsigned size, Uint32 dst[],
+ unsigned pos, unsigned len, const Uint32 src[])
+{
+ assert(pos + len < (size << 5));
+
+ dst += (pos >> 5);
+ Uint32 offset = pos & 31;
+ Uint32 mask = (len >= 32 ? ~0 : (1 << len) - 1) << offset;
+
+ * dst = (* dst & ~mask) | ((*src << offset) & mask);
+
+ if(offset + len <= 32)
+ {
+ return;
+ }
+ Uint32 used = (32 - offset);
+ assert(len > used);
+ setFieldImpl(dst+1, used & 31, len-used, src+(used >> 5));
+}
+
+
#endif
diff --git a/ndb/include/util/NdbSqlUtil.hpp b/ndb/include/util/NdbSqlUtil.hpp
index 5b27bd4e0c4..3e98dcd1805 100644
--- a/ndb/include/util/NdbSqlUtil.hpp
+++ b/ndb/include/util/NdbSqlUtil.hpp
@@ -20,34 +20,41 @@
#include <ndb_global.h>
#include <kernel/ndb_limits.h>
+struct charset_info_st;
+typedef struct charset_info_st CHARSET_INFO;
+
class NdbSqlUtil {
public:
/**
- * Compare strings, optionally with padded semantics. Returns
- * negative (less), zero (equal), or positive (greater).
- */
- static int char_compare(const char* s1, unsigned n1,
- const char* s2, unsigned n2, bool padded);
-
- /**
- * Like operator, optionally with padded semantics. Returns true or
- * false.
+ * Compare attribute values. Returns -1, 0, +1 for less, equal,
+ * greater, respectively. Parameters are pointers to values and their
+ * lengths in bytes. The lengths can differ.
+ *
+ * First value is a full value but second value can be partial. If
+ * the partial value is not enough to determine the result, CmpUnknown
+ * will be returned. A shorter second value is not necessarily
+ * partial. Partial values are allowed only for types where prefix
+ * comparison is possible (basically, binary strings).
+ *
+ * First parameter is a pointer to type specific extra info. Char
+ * types receive CHARSET_INFO in it.
+ *
+ * If a value cannot be parsed, it compares like NULL i.e. less than
+ * any valid value.
*/
- static bool char_like(const char* s1, unsigned n1,
- const char* s2, unsigned n2, bool padded);
+ typedef int Cmp(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full);
/**
- * Compare kernel attribute values. Returns -1, 0, +1 for less,
- * equal, greater, respectively. Parameters are pointers to values,
- * full attribute size in words, and size of available data in words.
- * There is also pointer to type specific extra info. Char types
- * receive CHARSET_INFO in it.
+ * Prototype for "like" comparison. Defined for string types. Second
+ * argument must have same type-specific format. Returns 0 on match,
+ * +1 on no match, and -1 on bad data.
+ *
+ * Uses default special chars ( \ % _ ).
*
- * If available size is less than full size, CmpUnknown may be
- * returned. If a value cannot be parsed, it compares like NULL i.e.
- * less than any valid value.
+ * TODO convert special chars to the cs so that ucs2 etc works
+ * TODO allow user-defined escape ( \ )
*/
- typedef int Cmp(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size);
+ typedef int Like(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2);
enum CmpResult {
CmpLess = -1,
@@ -56,41 +63,43 @@ public:
CmpUnknown = 2 // insufficient partial data
};
- /**
- * Kernel data types. Must match m_typeList in NdbSqlUtil.cpp.
- * Now also must match types in NdbDictionary.
- */
struct Type {
enum Enum {
- Undefined = 0, // Undefined
- Tinyint, // 8 bit
- Tinyunsigned, // 8 bit
- Smallint, // 16 bit
- Smallunsigned, // 16 bit
- Mediumint, // 24 bit
- Mediumunsigned, // 24 bit
- Int, // 32 bit
- Unsigned, // 32 bit
- Bigint, // 64 bit
- Bigunsigned, // 64 Bit
- Float, // 32-bit float
- Double, // 64-bit float
- Olddecimal, // Precision, Scale
- Char, // Len
- Varchar, // Max len
- Binary, // Len
- Varbinary, // Max len
- Datetime, // Precision down to 1 sec (size 8 bytes)
- Date, // Precision down to 1 day (size 4 bytes)
- Blob, // Blob
- Text, // Text blob
- Time = 25, // Time without date
- Year = 26, // Year (size 1 byte)
- Timestamp = 27, // Unix seconds (uint32)
- Olddecimalunsigned = 28
+ Undefined = NDB_TYPE_UNDEFINED,
+ Tinyint = NDB_TYPE_TINYINT,
+ Tinyunsigned = NDB_TYPE_TINYUNSIGNED,
+ Smallint = NDB_TYPE_SMALLINT,
+ Smallunsigned = NDB_TYPE_SMALLUNSIGNED,
+ Mediumint = NDB_TYPE_MEDIUMINT,
+ Mediumunsigned = NDB_TYPE_MEDIUMUNSIGNED,
+ Int = NDB_TYPE_INT,
+ Unsigned = NDB_TYPE_UNSIGNED,
+ Bigint = NDB_TYPE_BIGINT,
+ Bigunsigned = NDB_TYPE_BIGUNSIGNED,
+ Float = NDB_TYPE_FLOAT,
+ Double = NDB_TYPE_DOUBLE,
+ Olddecimal = NDB_TYPE_OLDDECIMAL,
+ Char = NDB_TYPE_CHAR,
+ Varchar = NDB_TYPE_VARCHAR,
+ Binary = NDB_TYPE_BINARY,
+ Varbinary = NDB_TYPE_VARBINARY,
+ Datetime = NDB_TYPE_DATETIME,
+ Date = NDB_TYPE_DATE,
+ Blob = NDB_TYPE_BLOB,
+ Text = NDB_TYPE_TEXT,
+ Bit = NDB_TYPE_BIT,
+ Longvarchar = NDB_TYPE_LONGVARCHAR,
+ Longvarbinary = NDB_TYPE_LONGVARBINARY,
+ Time = NDB_TYPE_TIME,
+ Year = NDB_TYPE_YEAR,
+ Timestamp = NDB_TYPE_TIMESTAMP,
+ Olddecimalunsigned = NDB_TYPE_OLDDECIMALUNSIGNED,
+ Decimal = NDB_TYPE_DECIMAL,
+ Decimalunsigned = NDB_TYPE_DECIMALUNSIGNED
};
- Enum m_typeId;
+ Enum m_typeId; // redundant
Cmp* m_cmp; // comparison method
+ Like* m_like; // "like" comparison method
};
/**
@@ -99,16 +108,30 @@ public:
static const Type& getType(Uint32 typeId);
/**
- * Get type by id but replace char type by corresponding binary type.
+ * Get the normalized type used in hashing and key comparisons.
+ * Maps all string types to Binary. This includes Var* strings
+ * because strxfrm result is padded to fixed (maximum) length.
*/
static const Type& getTypeBinary(Uint32 typeId);
/**
* Check character set.
*/
- static bool usable_in_pk(Uint32 typeId, const void* cs);
- static bool usable_in_hash_index(Uint32 typeId, const void* cs);
- static bool usable_in_ordered_index(Uint32 typeId, const void* cs);
+ static bool usable_in_pk(Uint32 typeId, const void* info);
+ static bool usable_in_hash_index(Uint32 typeId, const void* info);
+ static bool usable_in_ordered_index(Uint32 typeId, const void* info);
+
+ /**
+ * Get number of length bytes and length from variable length string.
+ * Returns false on error (invalid data). For other types returns
+ * zero length bytes and the fixed attribute length.
+ */
+ static bool get_var_length(Uint32 typeId, const void* p, unsigned attrlen, Uint32& lb, Uint32& len);
+
+ /**
+ * Temporary workaround for bug#7284.
+ */
+ static int strnxfrm_bug7284(CHARSET_INFO* cs, unsigned char* dst, unsigned dstLen, const unsigned char*src, unsigned srcLen);
/**
* Compare decimal numbers.
@@ -144,10 +167,22 @@ private:
static Cmp cmpDate;
static Cmp cmpBlob;
static Cmp cmpText;
+ static Cmp cmpBit;
+ static Cmp cmpLongvarchar;
+ static Cmp cmpLongvarbinary;
static Cmp cmpTime;
static Cmp cmpYear;
static Cmp cmpTimestamp;
static Cmp cmpOlddecimalunsigned;
+ static Cmp cmpDecimal;
+ static Cmp cmpDecimalunsigned;
+ //
+ static Like likeChar;
+ static Like likeBinary;
+ static Like likeVarchar;
+ static Like likeVarbinary;
+ static Like likeLongvarchar;
+ static Like likeLongvarbinary;
};
#endif
diff --git a/ndb/include/util/SocketClient.hpp b/ndb/include/util/SocketClient.hpp
index de9a081464a..bf1ad7d45d6 100644
--- a/ndb/include/util/SocketClient.hpp
+++ b/ndb/include/util/SocketClient.hpp
@@ -31,6 +31,12 @@ public:
SocketClient(const char *server_name, unsigned short port, SocketAuthenticator *sa = 0);
~SocketClient();
bool init();
+ void set_port(unsigned short port) {
+ m_port = port;
+ m_servaddr.sin_port = htons(m_port);
+ };
+ unsigned short get_port() { return m_port; };
+ char *get_server_name() { return m_server_name; };
NDB_SOCKET_TYPE connect();
bool close();
};
diff --git a/ndb/include/util/SocketServer.hpp b/ndb/include/util/SocketServer.hpp
index 9d8af204391..2e1afb74945 100644
--- a/ndb/include/util/SocketServer.hpp
+++ b/ndb/include/util/SocketServer.hpp
@@ -83,7 +83,7 @@ public:
* bind & listen
* Returns false if no success
*/
- bool setup(Service *, unsigned short port, const char * pinterface = 0);
+ bool setup(Service *, unsigned short *port, const char * pinterface = 0);
/**
* start/stop the server
diff --git a/ndb/include/util/Vector.hpp b/ndb/include/util/Vector.hpp
index f60817dab67..480dddf8243 100644
--- a/ndb/include/util/Vector.hpp
+++ b/ndb/include/util/Vector.hpp
@@ -61,6 +61,10 @@ Vector<T>::Vector(int i){
template<class T>
Vector<T>::~Vector(){
delete[] m_items;
+ // safety for placement new usage
+ m_items = 0;
+ m_size = 0;
+ m_arraySize = 0;
}
template<class T>
@@ -174,6 +178,10 @@ MutexVector<T>::MutexVector(int i){
template<class T>
MutexVector<T>::~MutexVector(){
delete[] m_items;
+ // safety for placement new usage
+ m_items = 0;
+ m_size = 0;
+ m_arraySize = 0;
}
template<class T>
diff --git a/ndb/include/util/md5_hash.hpp b/ndb/include/util/md5_hash.hpp
index 4c3cf239881..b79dce3b5a9 100644
--- a/ndb/include/util/md5_hash.hpp
+++ b/ndb/include/util/md5_hash.hpp
@@ -20,6 +20,15 @@
#include <ndb_types.h>
// External declaration of hash function
-Uint32 md5_hash(const Uint64* keybuf, Uint32 no_of_32_words);
+void md5_hash(Uint32 result[4], const Uint64* keybuf, Uint32 no_of_32_words);
+
+inline
+Uint32
+md5_hash(const Uint64* keybuf, Uint32 no_of_32_words)
+{
+ Uint32 result[4];
+ md5_hash(result, keybuf, no_of_32_words);
+ return result[0];
+}
#endif
diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h
index aa7a02f58ae..72abd6d5d7a 100644
--- a/ndb/include/util/ndb_opts.h
+++ b/ndb/include/util/ndb_opts.h
@@ -25,10 +25,19 @@
#include <ndb_opt_defaults.h>
#define NDB_STD_OPTS_VARS \
-const char *opt_connect_str= 0;\
my_bool opt_ndb_optimized_node_selection
+int opt_ndb_nodeid;
my_bool opt_ndb_shm;
+const char *opt_ndb_connectstring= 0;
+const char *opt_connect_str= 0;
+const char *opt_ndb_mgmd= 0;
+char opt_ndb_constrbuf[1024];
+unsigned opt_ndb_constrbuf_len= 0;
+
+#ifndef DBUG_OFF
+const char *opt_debug= 0;
+#endif
#define OPT_NDB_CONNECTSTRING 'c'
@@ -43,8 +52,17 @@ my_bool opt_ndb_shm;
"Set connect string for connecting to ndb_mgmd. " \
"Syntax: \"[nodeid=<id>;][host=]<hostname>[:<port>]\". " \
"Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", \
- (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, \
+ (gptr*) &opt_ndb_connectstring, (gptr*) &opt_ndb_connectstring, \
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\
+ { "ndb-mgmd-host", OPT_NDB_MGMD, \
+ "Set host and port for connecting to ndb_mgmd. " \
+ "Syntax: <hostname>[:<port>].", \
+ (gptr*) &opt_ndb_mgmd, (gptr*) &opt_ndb_mgmd, 0, \
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\
+ { "ndb-nodeid", OPT_NDB_NODEID, \
+ "Set node id for this node.", \
+ (gptr*) &opt_ndb_nodeid, (gptr*) &opt_ndb_nodeid, 0, \
+ GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\
{ "ndb-shm", OPT_NDB_SHM,\
"Allow optimizing using shared memory connections when available",\
(gptr*) &opt_ndb_shm, (gptr*) &opt_ndb_shm, 0,\
@@ -55,13 +73,14 @@ my_bool opt_ndb_shm;
(gptr*) &opt_ndb_optimized_node_selection, 0,\
GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},\
{ "connect-string", OPT_NDB_CONNECTSTRING, "same as --ndb-connectstring",\
- (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0,\
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }
+ (gptr*) &opt_ndb_connectstring, (gptr*) &opt_ndb_connectstring, \
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }
#ifndef DBUG_OFF
#define NDB_STD_OPTS(prog_name) \
{ "debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", \
- 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 }, \
+ (gptr*) &opt_debug, (gptr*) &opt_debug, \
+ 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 }, \
NDB_STD_OPTS_COMMON
#else
#define NDB_STD_OPTS(prog_name) NDB_STD_OPTS_COMMON
@@ -79,21 +98,29 @@ enum ndb_std_options {
OPT_NDB_SHM= 256,
OPT_NDB_SHM_SIGNUM,
OPT_NDB_OPTIMIZED_NODE_SELECTION,
+ OPT_NDB_MGMD,
+ OPT_NDB_NODEID,
NDB_STD_OPTIONS_LAST /* should always be last in this enum */
};
static my_bool
ndb_std_get_one_option(int optid,
const struct my_option *opt __attribute__((unused)),
- const char *argument)
+ char *argument)
{
switch (optid) {
+#ifndef DBUG_OFF
case '#':
- if (argument)
+ if (opt_debug)
{
- DBUG_PUSH(argument);
+ DBUG_PUSH(opt_debug);
+ }
+ else
+ {
+ DBUG_PUSH("d:t");
}
break;
+#endif
case 'V':
ndb_std_print_version();
exit(0);
@@ -110,6 +137,29 @@ ndb_std_get_one_option(int optid,
#endif
}
break;
+ case OPT_NDB_MGMD:
+ case OPT_NDB_NODEID:
+ {
+ int len= my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
+ sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
+ "%s%s%s",opt_ndb_constrbuf_len > 0 ? ",":"",
+ optid == OPT_NDB_NODEID ? "nodeid=" : "",
+ argument);
+ opt_ndb_constrbuf_len+= len;
+ }
+ /* fall through to add the connectstring to the end
+ * and set opt_ndbcluster_connectstring
+ */
+ case OPT_NDB_CONNECTSTRING:
+ if (opt_ndb_connectstring && opt_ndb_connectstring[0])
+ my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
+ sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
+ "%s%s", opt_ndb_constrbuf_len > 0 ? ",":"",
+ opt_ndb_connectstring);
+ else
+ opt_ndb_constrbuf[opt_ndb_constrbuf_len]= 0;
+ opt_connect_str= opt_ndb_constrbuf;
+ break;
}
return 0;
}
diff --git a/ndb/examples/Makefile b/ndb/ndbapi-examples/Makefile
index 0294632e23d..965dc3ec29f 100644
--- a/ndb/examples/Makefile
+++ b/ndb/ndbapi-examples/Makefile
@@ -1,12 +1,11 @@
--include .defs.mk
-
-#ifneq ($(C++),)
-#OPTS = CC=$(CC) CXX=$(C++)
-#endif
-
-# XXX ndbapi_example4 commented out until fixed
-BIN_DIRS := ndbapi_example1 ndbapi_example2 ndbapi_example3 $(ndbapi_example4) \
- ndbapi_example5 select_all
+BIN_DIRS := ndbapi_simple_example \
+ ndbapi_async_example \
+ ndbapi_async_example1 \
+ ndbapi_retries_example \
+ ndbapi_simple_index_example \
+ ndbapi_event_example \
+ ndbapi_scan_example \
+ mgmapi_logevent_example
bins: $(patsubst %, _bins_%, $(BIN_DIRS))
@@ -24,4 +23,3 @@ clean_dep: clean
cleanall: clean
tidy: clean
distclean: clean
-
diff --git a/ndb/ndbapi-examples/mgmapi_logevent_example/Makefile b/ndb/ndbapi-examples/mgmapi_logevent_example/Makefile
new file mode 100644
index 00000000000..c1ca32dfe17
--- /dev/null
+++ b/ndb/ndbapi-examples/mgmapi_logevent_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = mgmapi_logevent
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS =
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/mgmapi -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/ndbapi-examples/mgmapi_logevent_example/mgmapi_logevent.cpp b/ndb/ndbapi-examples/mgmapi_logevent_example/mgmapi_logevent.cpp
new file mode 100644
index 00000000000..5ec1fba6314
--- /dev/null
+++ b/ndb/ndbapi-examples/mgmapi_logevent_example/mgmapi_logevent.cpp
@@ -0,0 +1,140 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <mysql.h>
+#include <ndbapi/NdbApi.hpp>
+#include <mgmapi.h>
+#include <stdio.h>
+
+/*
+ * export LD_LIBRARY_PATH=../../../libmysql_r/.libs:../../../ndb/src/.libs
+ */
+
+#define MGMERROR(h) \
+{ \
+ fprintf(stderr, "code: %d msg: %s\n", \
+ ndb_mgm_get_latest_error(h), \
+ ndb_mgm_get_latest_error_msg(h)); \
+ exit(-1); \
+}
+
+#define LOGEVENTERROR(h) \
+{ \
+ fprintf(stderr, "code: %d msg: %s\n", \
+ ndb_logevent_get_latest_error(h), \
+ ndb_logevent_get_latest_error_msg(h)); \
+ exit(-1); \
+}
+
+int main()
+{
+ NdbMgmHandle h;
+ NdbLogEventHandle le;
+ int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP,
+ 15, NDB_MGM_EVENT_CATEGORY_CONNECTION,
+ 15, NDB_MGM_EVENT_CATEGORY_NODE_RESTART,
+ 15, NDB_MGM_EVENT_CATEGORY_STARTUP,
+ 15, NDB_MGM_EVENT_CATEGORY_ERROR,
+ 0 };
+ struct ndb_logevent event;
+
+ ndb_init();
+
+ h= ndb_mgm_create_handle();
+ if ( h == 0)
+ {
+ printf("Unable to create handle\n");
+ exit(-1);
+ }
+ if (ndb_mgm_connect(h,0,0,0)) MGMERROR(h);
+
+ le= ndb_mgm_create_logevent_handle(h, filter);
+ if ( le == 0 ) MGMERROR(h);
+
+ while (1)
+ {
+ int timeout= 5000;
+ int r= ndb_logevent_get_next(le,&event,timeout);
+ if (r == 0)
+ printf("No event within %d milliseconds\n", timeout);
+ else if (r < 0)
+ LOGEVENTERROR(le)
+ else
+ {
+ switch (event.type) {
+ case NDB_LE_BackupStarted:
+ printf("Node %d: BackupStarted\n", event.source_nodeid);
+ printf(" Starting node ID: %d\n", event.BackupStarted.starting_node);
+ printf(" Backup ID: %d\n", event.BackupStarted.backup_id);
+ break;
+ case NDB_LE_BackupCompleted:
+ printf("Node %d: BackupCompleted\n", event.source_nodeid);
+ printf(" Backup ID: %d\n", event.BackupStarted.backup_id);
+ break;
+ case NDB_LE_BackupAborted:
+ printf("Node %d: BackupAborted\n", event.source_nodeid);
+ break;
+ case NDB_LE_BackupFailedToStart:
+ printf("Node %d: BackupFailedToStart\n", event.source_nodeid);
+ break;
+
+ case NDB_LE_NodeFailCompleted:
+ printf("Node %d: NodeFailCompleted\n", event.source_nodeid);
+ break;
+ case NDB_LE_ArbitResult:
+ printf("Node %d: ArbitResult\n", event.source_nodeid);
+ printf(" code %d, arbit_node %d\n",
+ event.ArbitResult.code & 0xffff,
+ event.ArbitResult.arbit_node);
+ break;
+ case NDB_LE_DeadDueToHeartbeat:
+ printf("Node %d: DeadDueToHeartbeat\n", event.source_nodeid);
+ printf(" node %d\n", event.DeadDueToHeartbeat.node);
+ break;
+
+ case NDB_LE_Connected:
+ printf("Node %d: Connected\n", event.source_nodeid);
+ printf(" node %d\n", event.Connected.node);
+ break;
+ case NDB_LE_Disconnected:
+ printf("Node %d: Disconnected\n", event.source_nodeid);
+ printf(" node %d\n", event.Disconnected.node);
+ break;
+ case NDB_LE_NDBStartCompleted:
+ printf("Node %d: StartCompleted\n", event.source_nodeid);
+ printf(" version %d.%d.%d\n",
+ event.NDBStartCompleted.version >> 16 & 0xff,
+ event.NDBStartCompleted.version >> 8 & 0xff,
+ event.NDBStartCompleted.version >> 0 & 0xff);
+ break;
+ case NDB_LE_ArbitState:
+ printf("Node %d: ArbitState\n", event.source_nodeid);
+ printf(" code %d, arbit_node %d\n",
+ event.ArbitState.code & 0xffff,
+ event.ArbitResult.arbit_node);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ ndb_mgm_destroy_logevent_handle(&le);
+ ndb_mgm_destroy_handle(&h);
+ ndb_end(0);
+ return 0;
+}
diff --git a/ndb/ndbapi-examples/ndbapi_async_example/Makefile b/ndb/ndbapi-examples/ndbapi_async_example/Makefile
new file mode 100644
index 00000000000..55e4a13343f
--- /dev/null
+++ b/ndb/ndbapi-examples/ndbapi_async_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_async
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -g -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS = -g
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/extra -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_async_example/ndbapi_async.cpp b/ndb/ndbapi-examples/ndbapi_async_example/ndbapi_async.cpp
index 76ce1a8efe3..aa745f4d28d 100644
--- a/ndb/examples/ndbapi_async_example/ndbapi_async.cpp
+++ b/ndb/ndbapi-examples/ndbapi_async_example/ndbapi_async.cpp
@@ -24,10 +24,12 @@
*
* Classes and methods in NDBAPI used in this example:
*
+ * Ndb_cluster_connection
+ * connect()
+ * wait_until_ready()
+ *
* Ndb
* init()
- * waitUntilRead()
- * getDictionary()
* startTransaction()
* closeTransaction()
* sendPollNdb()
@@ -38,23 +40,6 @@
* executeAsynchPrepare()
* getNdbError()
*
- * NdbDictionary::Dictionary
- * getTable()
- * dropTable()
- * createTable()
- * getNdbError()
- *
- * NdbDictionary::Column
- * setName()
- * setType()
- * setLength()
- * setPrimaryKey()
- * setNullable()
- *
- * NdbDictionary::Table
- * setName()
- * addColumn()
- *
* NdbOperation
* insertTuple()
* equal()
@@ -63,33 +48,37 @@
*/
-#include <ndb_global.h>
-
+#include <mysql.h>
+#include <mysqld_error.h>
#include <NdbApi.hpp>
-#include <NdbScanFilter.hpp>
+
#include <iostream> // Used for cout
/**
* Helper sleep function
*/
-int
+static void
milliSleep(int milliseconds){
- int result = 0;
- struct timespec sleeptime;
+ struct timeval sleeptime;
sleeptime.tv_sec = milliseconds / 1000;
- sleeptime.tv_nsec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
- result = nanosleep(&sleeptime, NULL);
- return result;
+ sleeptime.tv_usec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
+ select(0, 0, 0, 0, &sleeptime);
}
+
/**
* error printout macro
*/
-#define APIERROR(error) \
- { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
- << error.code << ", msg: " << error.message << "." << std::endl; \
- exit(-1); }
-
+#define PRINT_ERROR(code,msg) \
+ std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
+ << ", code: " << code \
+ << ", msg: " << msg << "." << std::endl
+#define MYSQLERROR(mysql) { \
+ PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
+ exit(-1); }
+#define APIERROR(error) { \
+ PRINT_ERROR(error.code,error.message); \
+ exit(-1); }
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/**
@@ -106,10 +95,10 @@ typedef struct {
} async_callback_t;
/**
- * Structure used in "free list" to a NdbConnection
+ * Structure used in "free list" to a NdbTransaction
*/
typedef struct {
- NdbConnection* conn;
+ NdbTransaction* conn;
int used;
} transaction_t;
@@ -132,7 +121,7 @@ int populate(Ndb * myNdb, int data, async_callback_t * cbData);
/**
* Error handler.
*/
-bool asynchErrorHandler(NdbConnection * trans, Ndb* ndb);
+bool asynchErrorHandler(NdbTransaction * trans, Ndb* ndb);
/**
* Exit function
@@ -155,9 +144,6 @@ int create_table(Ndb * myNdb);
int tempErrors = 0;
int permErrors = 0;
-/**
- * Helper function for callback(...)
- */
void
closeTransaction(Ndb * ndb , async_callback_t * cb)
{
@@ -171,7 +157,7 @@ closeTransaction(Ndb * ndb , async_callback_t * cb)
* Callback executed when transaction has return from NDB
*/
static void
-callback(int result, NdbConnection* trans, void* aObject)
+callback(int result, NdbTransaction* trans, void* aObject)
{
async_callback_t * cbData = (async_callback_t *)aObject;
if (result<0)
@@ -207,61 +193,26 @@ callback(int result, NdbConnection* trans, void* aObject)
/**
* Create table "GARAGE"
*/
-int create_table(Ndb * myNdb)
+int create_table(MYSQL &mysql)
{
- NdbDictionary::Table myTable;
- NdbDictionary::Column myColumn;
-
- NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
-
- /*********************************************************
- * Create a table named GARAGE if it does not exist *
- *********************************************************/
- if (myDict->getTable("GARAGE") != NULL)
+ while (mysql_query(&mysql,
+ "CREATE TABLE"
+ " GARAGE"
+ " (REG_NO INT UNSIGNED NOT NULL,"
+ " BRAND CHAR(20) NOT NULL,"
+ " COLOR CHAR(20) NOT NULL,"
+ " PRIMARY KEY USING HASH (REG_NO))"
+ " ENGINE=NDB"))
{
- std::cout << "NDB already has example table: GARAGE. "
+ if (mysql_errno(&mysql) != ER_TABLE_EXISTS_ERROR)
+ MYSQLERROR(mysql);
+ std::cout << "MySQL Cluster already has example table: GARAGE. "
<< "Dropping it..." << std::endl;
- if(myDict->dropTable("GARAGE") == -1)
- {
- std::cout << "Failed to drop: GARAGE." << std::endl;
- exit(1);
- }
- }
-
- myTable.setName("GARAGE");
-
-/**
- * Column REG_NO
- */
- myColumn.setName("REG_NO");
- myColumn.setType(NdbDictionary::Column::Unsigned);
- myColumn.setLength(1);
- myColumn.setPrimaryKey(true);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
-/**
- * Column BRAND
- */
- myColumn.setName("BRAND");
- myColumn.setType(NdbDictionary::Column::Char);
- myColumn.setLength(20);
- myColumn.setPrimaryKey(false);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
-/**
- * Column COLOR
- */
- myColumn.setName("COLOR");
- myColumn.setType(NdbDictionary::Column::Char);
- myColumn.setLength(20);
- myColumn.setPrimaryKey(false);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
- if (myDict->createTable(myTable) == -1) {
- APIERROR(myDict->getNdbError());
+ /**************
+ * Drop table *
+ **************/
+ if (mysql_query(&mysql, "DROP TABLE GARAGE"))
+ MYSQLERROR(mysql);
}
return 1;
}
@@ -276,7 +227,7 @@ void asynchExitHandler(Ndb * m_ndb)
/* returns true if is recoverable (temporary),
* false if it is an error that is permanent.
*/
-bool asynchErrorHandler(NdbConnection * trans, Ndb* ndb)
+bool asynchErrorHandler(NdbTransaction * trans, Ndb* ndb)
{
NdbError error = trans->getNdbError();
switch(error.status)
@@ -339,6 +290,10 @@ int populate(Ndb * myNdb, int data, async_callback_t * cbData)
{
NdbOperation* myNdbOperation; // For operations
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
async_callback_t * cb;
int retries = 0;
@@ -395,8 +350,7 @@ int populate(Ndb * myNdb, int data, async_callback_t * cbData)
}
asynchExitHandler(myNdb);
}
- // Error check. If error, then maybe table GARAGE is not in database
- myNdbOperation = transaction[current].conn->getNdbOperation("GARAGE");
+ myNdbOperation = transaction[current].conn->getNdbOperation(myTable);
if (myNdbOperation == NULL)
{
if (asynchErrorHandler(transaction[current].conn, myNdb))
@@ -426,7 +380,7 @@ int populate(Ndb * myNdb, int data, async_callback_t * cbData)
}
/*Prepare transaction (the transaction is NOT yet sent to NDB)*/
- transaction[current].conn->executeAsynchPrepare(Commit,
+ transaction[current].conn->executeAsynchPrepare(NdbTransaction::Commit,
&callback,
cb);
/**
@@ -455,22 +409,48 @@ int populate(Ndb * myNdb, int data, async_callback_t * cbData)
int main()
{
ndb_init();
- Ndb* myNdb = new Ndb( "TEST_DB" ); // Object representing the database
-
- /*******************************************
- * Initialize NDB and wait until its ready *
- *******************************************/
- if (myNdb->init(1024) == -1) { // Set max 1024 parallel transactions
- APIERROR(myNdb->getNdbError());
+ MYSQL mysql;
+
+ /**************************************************************
+ * Connect to mysql server and create table *
+ **************************************************************/
+ {
+ if ( !mysql_init(&mysql) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
+ 3306, "/tmp/mysql.sock", 0) )
+ MYSQLERROR(mysql);
+
+ mysql_query(&mysql, "CREATE DATABASE TEST_DB");
+ if (mysql_query(&mysql, "USE TEST_DB") != 0) MYSQLERROR(mysql);
+
+ create_table(mysql);
}
- if (myNdb->waitUntilReady(30) != 0) {
- std::cout << "NDB was not ready within 30 secs." << std::endl;
+ /**************************************************************
+ * Connect to ndb cluster *
+ **************************************************************/
+ Ndb_cluster_connection cluster_connection;
+ if (cluster_connection.connect(4, 5, 1))
+ {
+ std::cout << "Unable to connect to cluster within 30 secs." << std::endl;
exit(-1);
}
- create_table(myNdb);
+ // Optionally connect and wait for the storage nodes (ndbd's)
+ if (cluster_connection.wait_until_ready(30,0) < 0)
+ {
+ std::cout << "Cluster was not ready within 30 secs.\n";
+ exit(-1);
+ }
+
+ Ndb* myNdb = new Ndb( &cluster_connection,
+ "TEST_DB" ); // Object representing the database
+ if (myNdb->init(1024) == -1) { // Set max 1024 parallel transactions
+ APIERROR(myNdb->getNdbError());
+ }
-
/**
* Initialise transaction array
*/
diff --git a/ndb/examples/ndbapi_async_example/readme.txt b/ndb/ndbapi-examples/ndbapi_async_example/readme.txt
index 47cb4bf9ffa..47cb4bf9ffa 100644
--- a/ndb/examples/ndbapi_async_example/readme.txt
+++ b/ndb/ndbapi-examples/ndbapi_async_example/readme.txt
diff --git a/ndb/ndbapi-examples/ndbapi_async_example1/Makefile b/ndb/ndbapi-examples/ndbapi_async_example1/Makefile
new file mode 100644
index 00000000000..7f6ea0b4d25
--- /dev/null
+++ b/ndb/ndbapi-examples/ndbapi_async_example1/Makefile
@@ -0,0 +1,21 @@
+TARGET = ndbapi_async1
+SRCS = ndbapi_async1.cpp
+OBJS = ndbapi_async1.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = -L../../src/.libs \
+ -L../../../libmysql_r/.libs \
+ -L../../../mysys -L../../../strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_example2/ndbapi_example2.cpp b/ndb/ndbapi-examples/ndbapi_async_example1/ndbapi_async1.cpp
index 95a7bae66b8..e8bc19e267b 100644
--- a/ndb/examples/ndbapi_example2/ndbapi_example2.cpp
+++ b/ndb/ndbapi-examples/ndbapi_async_example1/ndbapi_async1.cpp
@@ -15,7 +15,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
//
-// ndbapi_example2.cpp: Using asynchronous transactions in NDB API
+// ndbapi_async1.cpp: Using asynchronous transactions in NDB API
//
// Execute ndbapi_example1 to create the table "MYTABLENAME"
// before executing this program.
@@ -35,46 +35,75 @@
<< error.code << ", msg: " << error.message << "." << std::endl; \
exit(-1); }
-static void callback(int result, NdbConnection* NdbObject, void* aObject);
+static void callback(int result, NdbTransaction* NdbObject, void* aObject);
int main()
{
ndb_init();
- Ndb* myNdb = new Ndb( "TEST_DB_2" ); // Object representing the database
- NdbConnection* myNdbConnection[2]; // For transactions
+ Ndb_cluster_connection *cluster_connection=
+ new Ndb_cluster_connection(); // Object representing the cluster
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ int r= cluster_connection->connect(5 /* retries */,
+ 3 /* delay between retries */,
+ 1 /* verbose */);
+ if (r > 0)
+ {
+ std::cout
+ << "Cluster connect failed, possibly resolved with more retries.\n";
+ exit(-1);
+ }
+ else if (r < 0)
+ {
+ std::cout
+ << "Cluster connect failed.\n";
+ exit(-1);
+ }
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ Ndb* myNdb = new Ndb( cluster_connection,
+ "TEST_DB_2" ); // Object representing the database
+
+ NdbTransaction* myNdbTransaction[2]; // For transactions
NdbOperation* myNdbOperation; // For operations
- /*******************************************
- * Initialize NDB and wait until its ready *
- *******************************************/
if (myNdb->init(2) == -1) { // Want two parallel insert transactions
APIERROR(myNdb->getNdbError());
exit(-1);
}
- if (myNdb->waitUntilReady(30) != 0) {
- std::cout << "NDB was not ready within 30 secs." << std::endl;
- exit(-1);
- }
-
/******************************************************
* Insert (we do two insert transactions in parallel) *
******************************************************/
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
for (int i = 0; i < 2; i++) {
- myNdbConnection[i] = myNdb->startTransaction();
- if (myNdbConnection[i] == NULL) APIERROR(myNdb->getNdbError());
+ myNdbTransaction[i] = myNdb->startTransaction();
+ if (myNdbTransaction[i] == NULL) APIERROR(myNdb->getNdbError());
- myNdbOperation = myNdbConnection[i]->getNdbOperation("MYTABLENAME");
- // Error check. If error, then maybe table MYTABLENAME is not in database
- if (myNdbOperation == NULL) APIERROR(myNdbConnection[i]->getNdbError());
+ myNdbOperation = myNdbTransaction[i]->getNdbOperation(myTable);
+ if (myNdbOperation == NULL) APIERROR(myNdbTransaction[i]->getNdbError());
myNdbOperation->insertTuple();
myNdbOperation->equal("ATTR1", 20 + i);
myNdbOperation->setValue("ATTR2", 20 + i);
// Prepare transaction (the transaction is NOT yet sent to NDB)
- myNdbConnection[i]->executeAsynchPrepare(Commit, &callback, NULL);
+ myNdbTransaction[i]->executeAsynchPrepare(NdbTransaction::Commit,
+ &callback, NULL);
}
// Send all transactions to NDB
@@ -85,9 +114,13 @@ int main()
// Close all transactions
for (int i = 0; i < 2; i++)
- myNdb->closeTransaction(myNdbConnection[i]);
+ myNdb->closeTransaction(myNdbTransaction[i]);
delete myNdb;
+ delete cluster_connection;
+
+ ndb_end(0);
+ return 0;
}
/*
@@ -95,12 +128,12 @@ int main()
*
* (This function must have three arguments:
* - The result of the transaction,
- * - The NdbConnection object, and
+ * - The NdbTransaction object, and
* - A pointer to an arbitrary object.)
*/
static void
-callback(int result, NdbConnection* myTrans, void* aObject)
+callback(int result, NdbTransaction* myTrans, void* aObject)
{
if (result == -1) {
std::cout << "Poll error: " << std::endl;
diff --git a/ndb/ndbapi-examples/ndbapi_event_example/Makefile b/ndb/ndbapi-examples/ndbapi_event_example/Makefile
new file mode 100644
index 00000000000..12e109c654f
--- /dev/null
+++ b/ndb/ndbapi-examples/ndbapi_event_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_event
+SRCS = ndbapi_event.cpp
+OBJS = ndbapi_event.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS =
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)/ndb/include
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_example5/ndbapi_example5.cpp b/ndb/ndbapi-examples/ndbapi_event_example/ndbapi_event.cpp
index 77f74e7bb63..286f6fafbab 100644
--- a/ndb/examples/ndbapi_example5/ndbapi_example5.cpp
+++ b/ndb/ndbapi-examples/ndbapi_event_example/ndbapi_event.cpp
@@ -15,11 +15,41 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/**
- * ndbapi_example5.cpp: Using API level events in NDB API
+ * ndbapi_event.cpp: Using API level events in NDB API
+ *
+ * Classes and methods used in this example:
+ *
+ * Ndb_cluster_connection
+ * connect()
+ * wait_until_ready()
+ *
+ * Ndb
+ * init()
+ * getDictionary()
+ * createEventOperation()
+ * dropEventOperation()
+ * pollEvents()
+ *
+ * NdbDictionary
+ * createEvent()
+ * dropEvent()
+ *
+ * NdbDictionary::Event
+ * setTable()
+ * addTableEvent()
+ * addEventColumn()
+ *
+ * NdbEventOperation
+ * getValue()
+ * getPreValue()
+ * execute()
+ * next()
+ * isConsistent()
+ * getEventType()
+ *
*/
#include <NdbApi.hpp>
-#include <NdbEventOperation.hpp>
// Used for cout
#include <stdio.h>
@@ -33,19 +63,20 @@
* another process (e.g. flexBench -l 0 -stdtables).
* We want to monitor what happens with columns COL0, COL2, COL11
*
- * or together with the mysqlcluster client;
+ * or together with the mysql client;
*
- * shell> mysqlcluster -u root
+ * shell> mysql -u root
* mysql> create database TEST_DB;
* mysql> use TEST_DB;
- * mysql> create table TAB0 (COL0 int primary key, COL1 int, COL11 int);
+ * mysql> create table TAB0 (COL0 int primary key, COL1 int, COL11 int) engine=ndb;
*
- * In another window start ndbapi_example5, wait until properly started
+ * In another window start ndbapi_event, wait until properly started
*
- * mysql> insert into TAB0 values (1,2,3);
- * mysql> insert into TAB0 values (2,2,3);
- * mysql> insert into TAB0 values (3,2,9);
- * mysql>
+ insert into TAB0 values (1,2,3);
+ insert into TAB0 values (2,2,3);
+ insert into TAB0 values (3,2,9);
+ update TAB0 set COL1=10 where COL0=1;
+ delete from TAB0 where COL0=1;
*
* you should see the data popping up in the example window
*
@@ -56,45 +87,69 @@
<< error.code << ", msg: " << error.message << "." << std::endl; \
exit(-1); }
-Ndb* myCreateNdb();
int myCreateEvent(Ndb* myNdb,
const char *eventName,
const char *eventTableName,
- const char **eventComlumnName,
- const int noEventComlumnName);
+ const char **eventColumnName,
+ const int noEventColumnName);
int main()
{
ndb_init();
- Ndb* myNdb = myCreateNdb();
- NdbDictionary::Dictionary *myDict;
- const char *eventName = "CHNG_IN_TAB0";
- const char *eventTableName = "TAB0";
- const int noEventColumnName = 3;
- const char *eventColumnName[noEventColumnName] =
+ Ndb_cluster_connection *cluster_connection=
+ new Ndb_cluster_connection(); // Object representing the cluster
+
+ int r= cluster_connection->connect(5 /* retries */,
+ 3 /* delay between retries */,
+ 1 /* verbose */);
+ if (r > 0)
+ {
+ std::cout
+ << "Cluster connect failed, possibly resolved with more retries.\n";
+ exit(-1);
+ }
+ else if (r < 0)
+ {
+ std::cout
+ << "Cluster connect failed.\n";
+ exit(-1);
+ }
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ Ndb* myNdb= new Ndb(cluster_connection,
+ "TEST_DB"); // Object representing the database
+
+ if (myNdb->init() == -1) APIERROR(myNdb->getNdbError());
+
+ const char *eventName= "CHNG_IN_TAB0";
+ const char *eventTableName= "TAB0";
+ const int noEventColumnName= 3;
+ const char *eventColumnName[noEventColumnName]=
{"COL0",
"COL1",
"COL11"};
- myDict = myNdb->getDictionary();
-
// Create events
myCreateEvent(myNdb,
eventName,
eventTableName,
eventColumnName,
noEventColumnName);
- int j = 0;
+
+ int j= 0;
while (j < 5) {
// Start "transaction" for handling events
NdbEventOperation* op;
printf("create EventOperation\n");
- if ((op = myNdb->createEventOperation(eventName,100)) == NULL) {
- printf("Event operation creation failed\n");
- exit(-1);
- }
+ if ((op = myNdb->createEventOperation(eventName,100)) == NULL)
+ APIERROR(myNdb->getNdbError());
printf("get values\n");
NdbRecAttr* recAttr[noEventColumnName];
@@ -107,23 +162,21 @@ int main()
// set up the callbacks
printf("execute\n");
- if (op->execute()) { // This starts changes to "start flowing"
- printf("operationd execution failed\n");
- exit(-1);
- }
-
- int i = 0;
+ // This starts changes to "start flowing"
+ if (op->execute())
+ APIERROR(op->getNdbError());
+ int i= 0;
while(i < 40) {
- //printf("now waiting for event...\n");
- int r = myNdb->pollEvents(1000); // wait for event or 1000 ms
- if (r>0) {
- //printf("got data! %d\n", r);
+ // printf("now waiting for event...\n");
+ int r= myNdb->pollEvents(1000); // wait for event or 1000 ms
+ if (r > 0) {
+ // printf("got data! %d\n", r);
int overrun;
while (op->next(&overrun) > 0) {
i++;
if (!op->isConsistent())
- printf("A node failiure has occured and events might be missing\n");
+ printf("A node failure has occured and events might be missing\n");
switch (op->getEventType()) {
case NdbDictionary::Event::TE_INSERT:
printf("%u INSERT: ", i);
@@ -134,6 +187,8 @@ int main()
case NdbDictionary::Event::TE_UPDATE:
printf("%u UPDATE: ", i);
break;
+ default:
+ abort(); // should not happen
}
printf("overrun %u pk %u: ", overrun, recAttr[0]->u_32_value());
for (int i = 1; i < noEventColumnName; i++) {
@@ -145,7 +200,7 @@ int main()
printf("NULL");
}
if (recAttrPre[i]->isNULL() >= 0) { // we have a value
- printf(" post[%u]=", i);
+ printf(" pre[%u]=", i);
if (recAttrPre[i]->isNULL() == 0) // we have a non-null value
printf("%u", recAttrPre[i]->u_32_value());
else // we have a null value
@@ -157,75 +212,58 @@ int main()
} else
;//printf("timed out\n");
}
- // don't want to listen to eventsanymore
- myNdb->dropEventOperation(op);
+ // don't want to listen to events anymore
+ if (myNdb->dropEventOperation(op)) APIERROR(myNdb->getNdbError());
j++;
}
- myDict->dropEvent(eventName); // remove event from database
-
- delete myNdb;
-}
-
-Ndb* myCreateNdb()
-{
- Ndb* myNdb = new Ndb("TEST_DB");
-
- /********************************************
- * Initialize NDB and wait until it's ready *
- ********************************************/
- if (myNdb->init() == -1) {
- APIERROR(myNdb->getNdbError());
- exit(-1);
- }
-
- if (myNdb->waitUntilReady(30) != 0) {
- std::cout << "NDB was not ready within 30 secs." << std::endl;
- exit(-1);
+ {
+ NdbDictionary::Dictionary *myDict = myNdb->getDictionary();
+ if (!myDict) APIERROR(myNdb->getNdbError());
+ // remove event from database
+ if (myDict->dropEvent(eventName)) APIERROR(myDict->getNdbError());
}
- return myNdb;
+ delete myNdb;
+ delete cluster_connection;
+ ndb_end(0);
+ return 0;
}
int myCreateEvent(Ndb* myNdb,
const char *eventName,
const char *eventTableName,
- const char **eventColumnName,
- const int noEventColumnName)
+ const char **eventColumnNames,
+ const int noEventColumnNames)
{
- NdbDictionary::Dictionary *myDict = myNdb->getDictionary();
+ NdbDictionary::Dictionary *myDict= myNdb->getDictionary();
+ if (!myDict) APIERROR(myNdb->getNdbError());
- if (!myDict) {
- printf("Event Creation failedDictionary not found");
- exit(-1);
- }
+ const NdbDictionary::Table *table= myDict->getTable(eventTableName);
+ if (!table) APIERROR(myDict->getNdbError());
- NdbDictionary::Event myEvent(eventName);
- myEvent.setTable(eventTableName);
+ NdbDictionary::Event myEvent(eventName, *table);
myEvent.addTableEvent(NdbDictionary::Event::TE_ALL);
// myEvent.addTableEvent(NdbDictionary::Event::TE_INSERT);
// myEvent.addTableEvent(NdbDictionary::Event::TE_UPDATE);
// myEvent.addTableEvent(NdbDictionary::Event::TE_DELETE);
- for (int i = 0; i < noEventColumnName; i++)
- myEvent.addEventColumn(eventColumnName[i]);
+ myEvent.addEventColumns(noEventColumnNames, eventColumnNames);
- int res = myDict->createEvent(myEvent); // Add event to database
-
- if (res == 0)
+ // Add event to database
+ if (myDict->createEvent(myEvent) == 0)
myEvent.print();
- else {
- printf("Event creation failed\n");
- printf("trying drop Event, maybe event exists\n");
- res = myDict->dropEvent(eventName);
- if (res)
- exit(-1);
+ else if (myDict->getNdbError().classification ==
+ NdbError::SchemaObjectExists) {
+ printf("Event creation failed, event exists\n");
+ printf("dropping Event...\n");
+ if (myDict->dropEvent(eventName)) APIERROR(myDict->getNdbError());
// try again
- res = myDict->createEvent(myEvent); // Add event to database
- if (res)
- exit(-1);
- }
+ // Add event to database
+ if ( myDict->createEvent(myEvent)) APIERROR(myDict->getNdbError());
+ } else
+ APIERROR(myDict->getNdbError());
- return res;
+ return 0;
}
diff --git a/ndb/ndbapi-examples/ndbapi_retries_example/Makefile b/ndb/ndbapi-examples/ndbapi_retries_example/Makefile
new file mode 100644
index 00000000000..829a7009031
--- /dev/null
+++ b/ndb/ndbapi-examples/ndbapi_retries_example/Makefile
@@ -0,0 +1,21 @@
+TARGET = ndbapi_retries
+SRCS = ndbapi_retries.cpp
+OBJS = ndbapi_retries.o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+DEBUG =
+LFLAGS = -Wall
+INCLUDE_DIR = ../../include
+LIB_DIR = -L../../src/.libs \
+ -L../../../libmysql_r/.libs \
+ -L../../../mysys -L../../../strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_example3/ndbapi_example3.cpp b/ndb/ndbapi-examples/ndbapi_retries_example/ndbapi_retries.cpp
index 91d9ff122ba..8c29fe31446 100644
--- a/ndb/examples/ndbapi_example3/ndbapi_example3.cpp
+++ b/ndb/ndbapi-examples/ndbapi_retries_example/ndbapi_retries.cpp
@@ -15,14 +15,14 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
//
-// ndbapi_example3.cpp: Error handling and transaction retries
+// ndbapi_retries.cpp: Error handling and transaction retries
//
-// Execute ndbapi_example1 to create the table "MYTABLENAME"
+// Execute ndbapi_simple to create the table "MYTABLENAME"
// before executing this program.
//
// There are many ways to program using the NDB API. In this example
// we execute two inserts in the same transaction using
-// NdbConnection::Ndbexecute(NoCommit).
+// NdbConnection::execute(NoCommit).
//
// Transaction failing is handled by re-executing the transaction
// in case of non-permanent transaction errors.
@@ -52,28 +52,28 @@
}
//
-// CONERROR prints all error info regarding an NdbConnection
+// TRANSERROR prints all error info regarding an NdbTransaction
//
-#define CONERROR(ndbConnection) \
- { NdbError error = ndbConnection->getNdbError(); \
- std::cout << "CON ERROR: " << error.code << " " << error.message \
+#define TRANSERROR(ndbTransaction) \
+ { NdbError error = ndbTransaction->getNdbError(); \
+ std::cout << "TRANS ERROR: " << error.code << " " << error.message \
<< std::endl \
<< " " << "Status: " << error.status \
<< ", Classification: " << error.classification << std::endl \
<< " " << "File: " << __FILE__ \
<< " (Line: " << __LINE__ << ")" << std::endl \
; \
- printTransactionError(ndbConnection); \
+ printTransactionError(ndbTransaction); \
}
-void printTransactionError(NdbConnection *ndbConnection) {
+void printTransactionError(NdbTransaction *ndbTransaction) {
const NdbOperation *ndbOp = NULL;
int i=0;
/****************************************************************
* Print NdbError object of every operations in the transaction *
****************************************************************/
- while ((ndbOp = ndbConnection->getNextCompletedOperation(ndbOp)) != NULL) {
+ while ((ndbOp = ndbTransaction->getNextCompletedOperation(ndbOp)) != NULL) {
NdbError error = ndbOp->getNdbError();
std::cout << " OPERATION " << i+1 << ": "
<< error.code << " " << error.message << std::endl
@@ -86,15 +86,17 @@ void printTransactionError(NdbConnection *ndbConnection) {
//
// Example insert
-// @param myNdb Ndb object representing NDB Cluster
-// @param myConnection NdbConnection used for transaction
-// @param error NdbError object returned in case of errors
+// @param myNdb Ndb object representing NDB Cluster
+// @param myTransaction NdbTransaction used for transaction
+// @param myTable Table to insert into
+// @param error NdbError object returned in case of errors
// @return -1 in case of failures, 0 otherwise
//
-int insert(int transactionId, NdbConnection* myConnection) {
+int insert(int transactionId, NdbTransaction* myTransaction,
+ const NdbDictionary::Table *myTable) {
NdbOperation *myOperation; // For other operations
- myOperation = myConnection->getNdbOperation("MYTABLENAME");
+ myOperation = myTransaction->getNdbOperation(myTable);
if (myOperation == NULL) return -1;
if (myOperation->insertTuple() ||
@@ -104,7 +106,7 @@ int insert(int transactionId, NdbConnection* myConnection) {
exit(-1);
}
- return myConnection->execute(NoCommit);
+ return myTransaction->execute(NdbTransaction::NoCommit);
}
@@ -113,10 +115,11 @@ int insert(int transactionId, NdbConnection* myConnection) {
// if there are temporary errors (e.g. the NDB Cluster is overloaded).
// @return -1 failure, 1 success
//
-int executeInsertTransaction(int transactionId, Ndb* myNdb) {
+int executeInsertTransaction(int transactionId, Ndb* myNdb,
+ const NdbDictionary::Table *myTable) {
int result = 0; // No result yet
int noOfRetriesLeft = 10;
- NdbConnection *myConnection; // For other transactions
+ NdbTransaction *myTransaction; // For other transactions
NdbError ndberror;
while (noOfRetriesLeft > 0 && !result) {
@@ -124,16 +127,16 @@ int executeInsertTransaction(int transactionId, Ndb* myNdb) {
/*********************************
* Start and execute transaction *
*********************************/
- myConnection = myNdb->startTransaction();
- if (myConnection == NULL) {
+ myTransaction = myNdb->startTransaction();
+ if (myTransaction == NULL) {
APIERROR(myNdb->getNdbError());
ndberror = myNdb->getNdbError();
result = -1; // Failure
- } else if (insert(transactionId, myConnection) ||
- insert(10000+transactionId, myConnection) ||
- myConnection->execute(Commit)) {
- CONERROR(myConnection);
- ndberror = myConnection->getNdbError();
+ } else if (insert(transactionId, myTransaction, myTable) ||
+ insert(10000+transactionId, myTransaction, myTable) ||
+ myTransaction->execute(NdbTransaction::Commit)) {
+ TRANSERROR(myTransaction);
+ ndberror = myTransaction->getNdbError();
result = -1; // Failure
} else {
result = 1; // Success
@@ -164,8 +167,8 @@ int executeInsertTransaction(int transactionId, Ndb* myNdb) {
/*********************
* Close transaction *
*********************/
- if (myConnection != NULL) {
- myNdb->closeTransaction(myConnection);
+ if (myTransaction != NULL) {
+ myNdb->closeTransaction(myTransaction);
}
}
@@ -177,27 +180,57 @@ int executeInsertTransaction(int transactionId, Ndb* myNdb) {
int main()
{
ndb_init();
- Ndb* myNdb = new Ndb( "TEST_DB_1" ); // Object representing the database
+
+ Ndb_cluster_connection *cluster_connection=
+ new Ndb_cluster_connection(); // Object representing the cluster
+
+ int r= cluster_connection->connect(5 /* retries */,
+ 3 /* delay between retries */,
+ 1 /* verbose */);
+ if (r > 0)
+ {
+ std::cout
+ << "Cluster connect failed, possibly resolved with more retries.\n";
+ exit(-1);
+ }
+ else if (r < 0)
+ {
+ std::cout
+ << "Cluster connect failed.\n";
+ exit(-1);
+ }
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs." << std::endl;
+ exit(-1);
+ }
+
+ Ndb* myNdb= new Ndb( cluster_connection,
+ "TEST_DB_1" ); // Object representing the database
- /*******************************************
- * Initialize NDB and wait until its ready *
- *******************************************/
- if (myNdb->init() == -1) {
+ if (myNdb->init() == -1) {
APIERROR(myNdb->getNdbError());
exit(-1);
}
- if (myNdb->waitUntilReady(30) != 0) {
- std::cout << "NDB was not ready within 30 secs." << std::endl;
- exit(-1);
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+ if (myTable == NULL)
+ {
+ APIERROR(myDict->getNdbError());
+ return -1;
}
-
/************************************
* Execute some insert transactions *
************************************/
for (int i = 10000; i < 20000; i++) {
- executeInsertTransaction(i, myNdb);
+ executeInsertTransaction(i, myNdb, myTable);
}
delete myNdb;
+ delete cluster_connection;
+
+ ndb_end(0);
+ return 0;
}
diff --git a/ndb/ndbapi-examples/ndbapi_scan_example/Makefile b/ndb/ndbapi-examples/ndbapi_scan_example/Makefile
new file mode 100644
index 00000000000..31886b02bf1
--- /dev/null
+++ b/ndb/ndbapi-examples/ndbapi_scan_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_scan
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -g -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS = -g
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/extra -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/examples/ndbapi_scan_example/ndbapi_scan.cpp b/ndb/ndbapi-examples/ndbapi_scan_example/ndbapi_scan.cpp
index 22641bc5b57..69ffd99b8ca 100644
--- a/ndb/examples/ndbapi_scan_example/ndbapi_scan.cpp
+++ b/ndb/ndbapi-examples/ndbapi_scan_example/ndbapi_scan.cpp
@@ -24,171 +24,118 @@
*
* Classes and methods used in this example:
*
+ * Ndb_cluster_connection
+ * connect()
+ * wait_until_ready()
+ *
* Ndb
* init()
- * waitUntilRead()
* getDictionary()
* startTransaction()
* closeTransaction()
- * sendPreparedTransactions()
- * pollNdb()
*
- * NdbConnection
- * getNdbOperation()
- * executeAsynchPrepare()
- * getNdbError()
- * executeScan()
- * nextScanResult()
+ * NdbTransaction
+ * getNdbScanOperation()
+ * execute()
+ *
+ * NdbScanOperation
+ * getValue()
+ * readTuples()
+ * nextResult()
+ * deleteCurrentTuple()
+ * updateCurrentTuple()
*
- * NdbDictionary::Dictionary
+ * const NdbDictionary::Dictionary
* getTable()
- * dropTable()
- * createTable()
*
- * NdbDictionary::Column
- * setName()
- * setType()
- * setLength()
- * setPrimaryKey()
- * setNullable()
+ * const NdbDictionary::Table
+ * getColumn()
*
- * NdbDictionary::Table
- * setName()
- * addColumn()
+ * const NdbDictionary::Column
+ * getLength()
*
* NdbOperation
* insertTuple()
* equal()
* setValue()
- * openScanRead()
- * openScanExclusive()
- *
- * NdbRecAttr
- * aRef()
- * u_32_value()
- *
- * NdbResultSet
- * nextResult()
- * deleteTuple()
- * updateTuple()
- *
- * NdbScanOperation
- * getValue()
- * readTuplesExclusive()
*
* NdbScanFilter
* begin()
* eq()
* end()
*
- *
*/
-#include <ndb_global.h>
-
+#include <mysql.h>
+#include <mysqld_error.h>
#include <NdbApi.hpp>
-#include <NdbScanFilter.hpp>
// Used for cout
#include <iostream>
+#include <stdio.h>
/**
* Helper sleep function
*/
-int
+static void
milliSleep(int milliseconds){
- int result = 0;
- struct timespec sleeptime;
+ struct timeval sleeptime;
sleeptime.tv_sec = milliseconds / 1000;
- sleeptime.tv_nsec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
- result = nanosleep(&sleeptime, NULL);
- return result;
+ sleeptime.tv_usec = (milliseconds - (sleeptime.tv_sec * 1000)) * 1000000;
+ select(0, 0, 0, 0, &sleeptime);
}
/**
* Helper sleep function
*/
-#define APIERROR(error) \
- { std::cout << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
- << error.code << ", msg: " << error.message << "." << std::endl; \
- exit(-1); }
-
-/*
- * callback : This is called when the transaction is polled
- *
- * (This function must have three arguments:
- * - The result of the transaction,
- * - The NdbConnection object, and
- * - A pointer to an arbitrary object.)
- */
-static void
-callback(int result, NdbConnection* myTrans, void* aObject)
+#define PRINT_ERROR(code,msg) \
+ std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
+ << ", code: " << code \
+ << ", msg: " << msg << "." << std::endl
+#define MYSQLERROR(mysql) { \
+ PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
+ exit(-1); }
+#define APIERROR(error) { \
+ PRINT_ERROR(error.code,error.message); \
+ exit(-1); }
+
+struct Car
{
- if (result == -1) {
- std::cout << "In callback: " << std::endl;
- /**
- * Put error checking code here (see ndb_async_example)
- */
- APIERROR(myTrans->getNdbError());
- } else {
- /**
- * Ok!
- */
- return;
- }
-}
+ /**
+ * Note memset, so that entire char-fields are cleared
+ * as all 20 bytes are significant (as type is char)
+ */
+ Car() { memset(this, 0, sizeof(* this)); }
+
+ unsigned int reg_no;
+ char brand[20];
+ char color[20];
+};
/**
* Function to create table
*/
-int create_table(Ndb * myNdb)
+int create_table(MYSQL &mysql)
{
- NdbDictionary::Table myTable;
- NdbDictionary::Column myColumn;
-
- NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
-
- /*********************************************************
- * Create a table named GARAGE if it does not exist *
- *********************************************************/
- if (myDict->getTable("GARAGE") != NULL) {
- std::cout << "NDB already has example table: GARAGE. "
+ while (mysql_query(&mysql,
+ "CREATE TABLE"
+ " GARAGE"
+ " (REG_NO INT UNSIGNED NOT NULL,"
+ " BRAND CHAR(20) NOT NULL,"
+ " COLOR CHAR(20) NOT NULL,"
+ " PRIMARY KEY USING HASH (REG_NO))"
+ " ENGINE=NDB"))
+ {
+ if (mysql_errno(&mysql) != ER_TABLE_EXISTS_ERROR)
+ MYSQLERROR(mysql);
+ std::cout << "MySQL Cluster already has example table: GARAGE. "
<< "Dropping it..." << std::endl;
- if(myDict->dropTable("GARAGE") == -1)
- {
- std::cout << "Failed to drop: GARAGE." << std::endl;
- exit(1);
- }
- }
-
- myTable.setName("GARAGE");
-
- myColumn.setName("REG_NO");
- myColumn.setType(NdbDictionary::Column::Unsigned);
- myColumn.setLength(1);
- myColumn.setPrimaryKey(true);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
- myColumn.setName("BRAND");
- myColumn.setType(NdbDictionary::Column::Char);
- myColumn.setLength(20);
- myColumn.setPrimaryKey(false);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
-
- myColumn.setName("COLOR");
- myColumn.setType(NdbDictionary::Column::Char);
- myColumn.setLength(20);
- myColumn.setPrimaryKey(false);
- myColumn.setNullable(false);
- myTable.addColumn(myColumn);
-
- if (myDict->createTable(myTable) == -1) {
- APIERROR(myDict->getNdbError());
- return -1;
+ /**************
+ * Drop table *
+ **************/
+ if (mysql_query(&mysql, "DROP TABLE GARAGE"))
+ MYSQLERROR(mysql);
}
return 1;
}
@@ -196,93 +143,71 @@ int create_table(Ndb * myNdb)
int populate(Ndb * myNdb)
{
- NdbConnection* myNdbConnection[15]; // For transactions
- NdbOperation* myNdbOperation; // For operations
- /******************************************************
- * Insert (we do 15 insert transactions in parallel) *
- ******************************************************/
+ int i;
+ Car cars[15];
+
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
/**
* Five blue mercedes
*/
- for (int i = 0; i < 5; i++)
+ for (i = 0; i < 5; i++)
{
- myNdbConnection[i] = myNdb->startTransaction();
- if (myNdbConnection[i] == NULL)
- APIERROR(myNdb->getNdbError());
- myNdbOperation = myNdbConnection[i]->getNdbOperation("GARAGE");
- // Error check. If error, then maybe table GARAGE is not in database
- if (myNdbOperation == NULL)
- APIERROR(myNdbConnection[i]->getNdbError());
- myNdbOperation->insertTuple();
- myNdbOperation->equal("REG_NO", i);
- myNdbOperation->setValue("BRAND", "Mercedes");
- myNdbOperation->setValue("COLOR", "Blue");
- // Prepare transaction (the transaction is NOT yet sent to NDB)
- myNdbConnection[i]->executeAsynchPrepare(Commit, &callback, NULL);
+ cars[i].reg_no = i;
+ sprintf(cars[i].brand, "Mercedes");
+ sprintf(cars[i].color, "Blue");
}
-
/**
* Five black bmw
*/
- for (int i = 5; i < 10; i++)
+ for (i = 5; i < 10; i++)
{
- myNdbConnection[i] = myNdb->startTransaction();
- if (myNdbConnection[i] == NULL)
- APIERROR(myNdb->getNdbError());
- myNdbOperation = myNdbConnection[i]->getNdbOperation("GARAGE");
- // Error check. If error, then maybe table MYTABLENAME is not in database
- if (myNdbOperation == NULL)
- APIERROR(myNdbConnection[i]->getNdbError());
- myNdbOperation->insertTuple();
- myNdbOperation->equal("REG_NO", i);
- myNdbOperation->setValue("BRAND", "BMW");
- myNdbOperation->setValue("COLOR", "Black");
- // Prepare transaction (the transaction is NOT yet sent to NDB)
- myNdbConnection[i]->executeAsynchPrepare(Commit, &callback, NULL);
+ cars[i].reg_no = i;
+ sprintf(cars[i].brand, "BMW");
+ sprintf(cars[i].color, "Black");
}
/**
* Five pink toyotas
*/
- for (int i = 10; i < 15; i++) {
- myNdbConnection[i] = myNdb->startTransaction();
- if (myNdbConnection[i] == NULL) APIERROR(myNdb->getNdbError());
- myNdbOperation = myNdbConnection[i]->getNdbOperation("GARAGE");
- // Error check. If error, then maybe table MYTABLENAME is not in database
- if (myNdbOperation == NULL) APIERROR(myNdbConnection[i]->getNdbError());
+ for (i = 10; i < 15; i++)
+ {
+ cars[i].reg_no = i;
+ sprintf(cars[i].brand, "Toyota");
+ sprintf(cars[i].color, "Pink");
+ }
+
+ NdbTransaction* myTrans = myNdb->startTransaction();
+ if (myTrans == NULL)
+ APIERROR(myNdb->getNdbError());
+
+ for (i = 0; i < 15; i++)
+ {
+ NdbOperation* myNdbOperation = myTrans->getNdbOperation(myTable);
+ if (myNdbOperation == NULL)
+ APIERROR(myTrans->getNdbError());
myNdbOperation->insertTuple();
- myNdbOperation->equal("REG_NO", i);
- myNdbOperation->setValue("BRAND", "Toyota");
- myNdbOperation->setValue("COLOR", "Pink");
- // Prepare transaction (the transaction is NOT yet sent to NDB)
- myNdbConnection[i]->executeAsynchPrepare(Commit, &callback, NULL);
+ myNdbOperation->equal("REG_NO", cars[i].reg_no);
+ myNdbOperation->setValue("BRAND", cars[i].brand);
+ myNdbOperation->setValue("COLOR", cars[i].color);
}
- // Send all transactions to NDB
- myNdb->sendPreparedTransactions(0);
- // Poll all transactions
- myNdb->pollNdb(3000, 0);
-
- // it is also possible to use sendPollNdb instead of
- // myNdb->sendPreparedTransactions(0); and myNdb->pollNdb(3000, 15); above.
- // myNdb->sendPollNdb(3000,0);
- // Note! Neither sendPollNdb or pollNdb returs until all 15 callbacks have
- // executed.
-
- // Close all transactions. It is also possible to close transactions
- // in the callback.
- for (int i = 0; i < 15; i++)
- myNdb->closeTransaction(myNdbConnection[i]);
- return 1;
+ int check = myTrans->execute(NdbTransaction::Commit);
+
+ myTrans->close();
+
+ return check != -1;
}
int scan_delete(Ndb* myNdb,
- int parallelism,
int column,
- int column_len,
const char * color)
-
+
{
// Scan all records exclusive and delete
@@ -292,9 +217,15 @@ int scan_delete(Ndb* myNdb,
int deletedRows = 0;
int check;
NdbError err;
- NdbConnection *myTrans;
+ NdbTransaction *myTrans;
NdbScanOperation *myScanOp;
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
/**
* Loop as long as :
* retryMax not reached
@@ -331,7 +262,7 @@ int scan_delete(Ndb* myNdb,
/**
* Get a scan operation.
*/
- myScanOp = myTrans->getNdbScanOperation("GARAGE");
+ myScanOp = myTrans->getNdbScanOperation(myTable);
if (myScanOp == NULL)
{
std::cout << myTrans->getNdbError().message << std::endl;
@@ -342,20 +273,20 @@ int scan_delete(Ndb* myNdb,
/**
* Define a result set for the scan.
*/
- NdbResultSet * rs = myScanOp->readTuplesExclusive(parallelism);
- if( rs == 0 ) {
+ if(myScanOp->readTuples(NdbOperation::LM_Exclusive) != 0)
+ {
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
return -1;
}
-
+
/**
* Use NdbScanFilter to define a search critera
*/
NdbScanFilter filter(myScanOp) ;
if(filter.begin(NdbScanFilter::AND) < 0 ||
- filter.eq(column, color, column_len, false) <0||
- filter.end() <0)
+ filter.cmp(NdbScanFilter::COND_EQ, column, color) < 0 ||
+ filter.end() < 0)
{
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
@@ -365,7 +296,7 @@ int scan_delete(Ndb* myNdb,
/**
* Start scan (NoCommit since we are only reading at this stage);
*/
- if(myTrans->execute(NoCommit) != 0){
+ if(myTrans->execute(NdbTransaction::NoCommit) != 0){
err = myTrans->getNdbError();
if(err.status == NdbError::TemporaryError){
std::cout << myTrans->getNdbError().message << std::endl;
@@ -384,9 +315,11 @@ int scan_delete(Ndb* myNdb,
* start of loop: nextResult(true) means that "parallelism" number of
* rows are fetched from NDB and cached in NDBAPI
*/
- while((check = rs->nextResult(true)) == 0){
- do {
- if (rs->deleteTuple() != 0){
+ while((check = myScanOp->nextResult(true)) == 0){
+ do
+ {
+ if (myScanOp->deleteCurrentTuple() != 0)
+ {
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
return -1;
@@ -398,21 +331,32 @@ int scan_delete(Ndb* myNdb,
* cached in the NDBAPI are modified before
* fetching more rows from NDB.
*/
- } while((check = rs->nextResult(false)) == 0);
+ } while((check = myScanOp->nextResult(false)) == 0);
/**
* Commit when all cached tuple have been marked for deletion
*/
- if(check != -1){
- check = myTrans->execute(Commit);
- myTrans->releaseCompletedOperations();
+ if(check != -1)
+ {
+ check = myTrans->execute(NdbTransaction::Commit);
+ }
+
+ if(check == -1)
+ {
+ /**
+ * Create a new transaction, while keeping scan open
+ */
+ check = myTrans->restart();
}
+
/**
* Check for errors
*/
err = myTrans->getNdbError();
- if(check == -1){
- if(err.status == NdbError::TemporaryError){
+ if(check == -1)
+ {
+ if(err.status == NdbError::TemporaryError)
+ {
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
milliSleep(50);
@@ -426,10 +370,10 @@ int scan_delete(Ndb* myNdb,
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
return 0;
-
-
}
- if(myTrans!=0) {
+
+ if(myTrans!=0)
+ {
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
}
@@ -438,10 +382,7 @@ int scan_delete(Ndb* myNdb,
int scan_update(Ndb* myNdb,
- int parallelism,
- int column_len,
int update_column,
- const char * column_name,
const char * before_color,
const char * after_color)
@@ -454,9 +395,15 @@ int scan_update(Ndb* myNdb,
int updatedRows = 0;
int check;
NdbError err;
- NdbConnection *myTrans;
+ NdbTransaction *myTrans;
NdbScanOperation *myScanOp;
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
/**
* Loop as long as :
* retryMax not reached
@@ -494,7 +441,7 @@ int scan_update(Ndb* myNdb,
/**
* Get a scan operation.
*/
- myScanOp = myTrans->getNdbScanOperation("GARAGE");
+ myScanOp = myTrans->getNdbScanOperation(myTable);
if (myScanOp == NULL)
{
std::cout << myTrans->getNdbError().message << std::endl;
@@ -505,8 +452,8 @@ int scan_update(Ndb* myNdb,
/**
* Define a result set for the scan.
*/
- NdbResultSet * rs = myScanOp->readTuplesExclusive(parallelism);
- if( rs == 0 ) {
+ if( myScanOp->readTuples(NdbOperation::LM_Exclusive) )
+ {
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
return -1;
@@ -517,7 +464,7 @@ int scan_update(Ndb* myNdb,
*/
NdbScanFilter filter(myScanOp) ;
if(filter.begin(NdbScanFilter::AND) < 0 ||
- filter.eq(update_column, before_color, column_len, false) <0||
+ filter.cmp(NdbScanFilter::COND_EQ, update_column, before_color) <0||
filter.end() <0)
{
std::cout << myTrans->getNdbError().message << std::endl;
@@ -528,7 +475,8 @@ int scan_update(Ndb* myNdb,
/**
* Start scan (NoCommit since we are only reading at this stage);
*/
- if(myTrans->execute(NoCommit) != 0){
+ if(myTrans->execute(NdbTransaction::NoCommit) != 0)
+ {
err = myTrans->getNdbError();
if(err.status == NdbError::TemporaryError){
std::cout << myTrans->getNdbError().message << std::endl;
@@ -541,49 +489,49 @@ int scan_update(Ndb* myNdb,
return -1;
}
- /**
- * Define an update operation
- */
- NdbOperation * myUpdateOp;
- /**
- * start of loop: nextResult(true) means that "parallelism" number of
- * rows are fetched from NDB and cached in NDBAPI
- */
- while((check = rs->nextResult(true)) == 0){
+ /**
+ * start of loop: nextResult(true) means that "parallelism" number of
+ * rows are fetched from NDB and cached in NDBAPI
+ */
+ while((check = myScanOp->nextResult(true)) == 0){
do {
/**
* Get update operation
*/
- myUpdateOp = rs->updateTuple();
- if (myUpdateOp == 0){
+ NdbOperation * myUpdateOp = myScanOp->updateCurrentTuple();
+ if (myUpdateOp == 0)
+ {
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
return -1;
}
updatedRows++;
+
/**
* do the update
*/
- myUpdateOp->setValue(update_column,after_color);
+ myUpdateOp->setValue(update_column, after_color);
/**
* nextResult(false) means that the records
* cached in the NDBAPI are modified before
* fetching more rows from NDB.
*/
- } while((check = rs->nextResult(false)) == 0);
+ } while((check = myScanOp->nextResult(false)) == 0);
/**
- * Commit when all cached tuple have been updated
+ * NoCommit when all cached tuple have been updated
*/
- if(check != -1){
- check = myTrans->execute(Commit);
- myTrans->releaseCompletedOperations();
+ if(check != -1)
+ {
+ check = myTrans->execute(NdbTransaction::NoCommit);
}
+
/**
* Check for errors
*/
err = myTrans->getNdbError();
- if(check == -1){
+ if(check == -1)
+ {
if(err.status == NdbError::TemporaryError){
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
@@ -595,13 +543,28 @@ int scan_update(Ndb* myNdb,
* End of loop
*/
}
+
+ /**
+ * Commit all prepared operations
+ */
+ if(myTrans->execute(NdbTransaction::Commit) == -1)
+ {
+ if(err.status == NdbError::TemporaryError){
+ std::cout << myTrans->getNdbError().message << std::endl;
+ myNdb->closeTransaction(myTrans);
+ milliSleep(50);
+ continue;
+ }
+ }
+
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
- return 0;
-
-
+ return 0;
}
- if(myTrans!=0) {
+
+
+ if(myTrans!=0)
+ {
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
}
@@ -610,9 +573,7 @@ int scan_update(Ndb* myNdb,
-int scan_print(Ndb * myNdb, int parallelism,
- int column_len_brand,
- int column_len_color)
+int scan_print(Ndb * myNdb)
{
// Scan all records exclusive and update
// them one by one
@@ -621,13 +582,19 @@ int scan_print(Ndb * myNdb, int parallelism,
int fetchedRows = 0;
int check;
NdbError err;
- NdbConnection *myTrans;
+ NdbTransaction *myTrans;
NdbScanOperation *myScanOp;
/* Result of reading attribute value, three columns:
REG_NO, BRAND, and COLOR
*/
NdbRecAttr * myRecAttr[3];
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("GARAGE");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
/**
* Loop as long as :
* retryMax not reached
@@ -665,7 +632,7 @@ int scan_print(Ndb * myNdb, int parallelism,
* Define a scan operation.
* NDBAPI.
*/
- myScanOp = myTrans->getNdbScanOperation("GARAGE");
+ myScanOp = myTrans->getNdbScanOperation(myTable);
if (myScanOp == NULL)
{
std::cout << myTrans->getNdbError().message << std::endl;
@@ -674,10 +641,10 @@ int scan_print(Ndb * myNdb, int parallelism,
}
/**
- * Define a result set for the scan.
- */
- NdbResultSet * rs = myScanOp->readTuplesExclusive(parallelism);
- if( rs == 0 ) {
+ * Read without locks, without being placed in lock queue
+ */
+ if( myScanOp->readTuples(NdbOperation::LM_CommittedRead) == -1)
+ {
std::cout << myTrans->getNdbError().message << std::endl;
myNdb->closeTransaction(myTrans);
return -1;
@@ -701,7 +668,7 @@ int scan_print(Ndb * myNdb, int parallelism,
/**
* Start scan (NoCommit since we are only reading at this stage);
*/
- if(myTrans->execute(NoCommit) != 0){
+ if(myTrans->execute(NdbTransaction::NoCommit) != 0){
err = myTrans->getNdbError();
if(err.status == NdbError::TemporaryError){
std::cout << myTrans->getNdbError().message << std::endl;
@@ -719,7 +686,7 @@ int scan_print(Ndb * myNdb, int parallelism,
* start of loop: nextResult(true) means that "parallelism" number of
* rows are fetched from NDB and cached in NDBAPI
*/
- while((check = rs->nextResult(true)) == 0){
+ while((check = myScanOp->nextResult(true)) == 0){
do {
fetchedRows++;
@@ -727,28 +694,23 @@ int scan_print(Ndb * myNdb, int parallelism,
* print REG_NO unsigned int
*/
std::cout << myRecAttr[0]->u_32_value() << "\t";
- char * buf_brand = new char[column_len_brand+1];
- char * buf_color = new char[column_len_color+1];
+
/**
* print BRAND character string
*/
- memcpy(buf_brand, myRecAttr[1]->aRef(), column_len_brand);
- buf_brand[column_len_brand] = 0;
- std::cout << buf_brand << "\t";
- delete [] buf_brand;
+ std::cout << myRecAttr[1]->aRef() << "\t";
+
/**
* print COLOR character string
*/
- memcpy(buf_color, myRecAttr[2]->aRef(), column_len_color);
- buf_brand[column_len_color] = 0;
- std::cout << buf_color << std::endl;
- delete [] buf_color;
+ std::cout << myRecAttr[2]->aRef() << std::endl;
+
/**
* nextResult(false) means that the records
* cached in the NDBAPI are modified before
* fetching more rows from NDB.
*/
- } while((check = rs->nextResult(false)) == 0);
+ } while((check = myScanOp->nextResult(false)) == 0);
}
myNdb->closeTransaction(myTrans);
@@ -762,55 +724,102 @@ int scan_print(Ndb * myNdb, int parallelism,
int main()
{
ndb_init();
- Ndb* myNdb = new Ndb( "TEST_DB" ); // Object representing the database
+ MYSQL mysql;
-
-
- /*******************************************
- * Initialize NDB and wait until its ready *
- *******************************************/
- if (myNdb->init(1024) == -1) { // Set max 1024 parallel transactions
- APIERROR(myNdb->getNdbError());
+ /**************************************************************
+ * Connect to mysql server and create table *
+ **************************************************************/
+ {
+ if ( !mysql_init(&mysql) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
+ 3306, "/tmp/mysql.sock", 0) )
+ MYSQLERROR(mysql);
+
+ mysql_query(&mysql, "CREATE DATABASE TEST_DB");
+ if (mysql_query(&mysql, "USE TEST_DB") != 0) MYSQLERROR(mysql);
+
+ create_table(mysql);
+ }
+
+ /**************************************************************
+ * Connect to ndb cluster *
+ **************************************************************/
+
+ Ndb_cluster_connection cluster_connection;
+ if (cluster_connection.connect(4, 5, 1))
+ {
+ std::cout << "Unable to connect to cluster within 30 secs." << std::endl;
+ exit(-1);
+ }
+ // Optionally connect and wait for the storage nodes (ndbd's)
+ if (cluster_connection.wait_until_ready(30,0) < 0)
+ {
+ std::cout << "Cluster was not ready within 30 secs.\n";
exit(-1);
}
- if (myNdb->waitUntilReady(30) != 0) {
- std::cout << "NDB was not ready within 30 secs." << std::endl;
+ Ndb myNdb(&cluster_connection,"TEST_DB");
+ if (myNdb.init(1024) == -1) { // Set max 1024 parallel transactions
+ APIERROR(myNdb.getNdbError());
exit(-1);
}
- create_table(myNdb);
-
- NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
- int column_color = myDict->getTable("GARAGE")->getColumn("COLOR")->getColumnNo();
- int column_len_color =
- myDict->getTable("GARAGE")->getColumn("COLOR")->getLength();
- int column_len_brand =
- myDict->getTable("GARAGE")->getColumn("BRAND")->getLength();
- int parallelism = 16;
-
- if(populate(myNdb) > 0)
- std::cout << "populate: Success!" << std::endl;
+ /*******************************************
+ * Check table definition *
+ *******************************************/
+ int column_color;
+ {
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *t= myDict->getTable("GARAGE");
+
+ Car car;
+ if (t->getColumn("COLOR")->getLength() != sizeof(car.color) ||
+ t->getColumn("BRAND")->getLength() != sizeof(car.brand))
+ {
+ std::cout << "Wrong table definition" << std::endl;
+ exit(-1);
+ }
+ column_color= t->getColumn("COLOR")->getColumnNo();
+ }
- if(scan_print(myNdb, parallelism, column_len_brand, column_len_color) > 0)
+ if(populate(&myNdb) > 0)
+ std::cout << "populate: Success!" << std::endl;
+
+ if(scan_print(&myNdb) > 0)
std::cout << "scan_print: Success!" << std::endl << std::endl;
std::cout << "Going to delete all pink cars!" << std::endl;
- if(scan_delete(myNdb, parallelism, column_color,
- column_len_color, "Pink") > 0)
- std::cout << "scan_delete: Success!" << std::endl << std::endl;
+
+ {
+ /**
+ * Note! color needs to be of exact the same size as column defined
+ */
+ Car tmp;
+ sprintf(tmp.color, "Pink");
+ if(scan_delete(&myNdb, column_color, tmp.color) > 0)
+ std::cout << "scan_delete: Success!" << std::endl << std::endl;
+ }
- if(scan_print(myNdb, parallelism, column_len_brand, column_len_color) > 0)
+ if(scan_print(&myNdb) > 0)
std::cout << "scan_print: Success!" << std::endl << std::endl;
- std::cout << "Going to update all blue cars to black cars!" << std::endl;
- if(scan_update(myNdb, parallelism, column_len_color, column_color,
- "COLOR", "Blue", "Black") > 0)
{
- std::cout << "scan_update: Success!" << std::endl << std::endl;
+ /**
+ * Note! color1 & 2 need to be of exact the same size as column defined
+ */
+ Car tmp1, tmp2;
+ sprintf(tmp1.color, "Blue");
+ sprintf(tmp2.color, "Black");
+ std::cout << "Going to update all " << tmp1.color
+ << " cars to " << tmp2.color << " cars!" << std::endl;
+ if(scan_update(&myNdb, column_color, tmp1.color, tmp2.color) > 0)
+ std::cout << "scan_update: Success!" << std::endl << std::endl;
}
- if(scan_print(myNdb, parallelism, column_len_brand, column_len_color) > 0)
+ if(scan_print(&myNdb) > 0)
std::cout << "scan_print: Success!" << std::endl << std::endl;
- delete myNdb;
+ return 0;
}
diff --git a/ndb/examples/ndbapi_scan_example/readme.txt b/ndb/ndbapi-examples/ndbapi_scan_example/readme.txt
index 47cb4bf9ffa..47cb4bf9ffa 100644
--- a/ndb/examples/ndbapi_scan_example/readme.txt
+++ b/ndb/ndbapi-examples/ndbapi_scan_example/readme.txt
diff --git a/ndb/ndbapi-examples/ndbapi_simple_example/Makefile b/ndb/ndbapi-examples/ndbapi_simple_example/Makefile
new file mode 100644
index 00000000000..0a59584fb66
--- /dev/null
+++ b/ndb/ndbapi-examples/ndbapi_simple_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_simple
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS =
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/ndbapi-examples/ndbapi_simple_example/ndbapi_simple.cpp b/ndb/ndbapi-examples/ndbapi_simple_example/ndbapi_simple.cpp
new file mode 100644
index 00000000000..152d4fa44af
--- /dev/null
+++ b/ndb/ndbapi-examples/ndbapi_simple_example/ndbapi_simple.cpp
@@ -0,0 +1,278 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ * ndbapi_simple.cpp: Using synchronous transactions in NDB API
+ *
+ * Correct output from this program is:
+ *
+ * ATTR1 ATTR2
+ * 0 10
+ * 1 1
+ * 2 12
+ * Detected that deleted tuple doesn't exist!
+ * 4 14
+ * 5 5
+ * 6 16
+ * 7 7
+ * 8 18
+ * 9 9
+ *
+ */
+
+#include <mysql.h>
+#include <NdbApi.hpp>
+// Used for cout
+#include <stdio.h>
+#include <iostream>
+
+static void run_application(MYSQL &, Ndb_cluster_connection &);
+
+#define PRINT_ERROR(code,msg) \
+ std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
+ << ", code: " << code \
+ << ", msg: " << msg << "." << std::endl
+#define MYSQLERROR(mysql) { \
+ PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
+ exit(-1); }
+#define APIERROR(error) { \
+ PRINT_ERROR(error.code,error.message); \
+ exit(-1); }
+
+int main()
+{
+ // ndb_init must be called first
+ ndb_init();
+
+ // connect to mysql server and cluster and run application
+ {
+ // Object representing the cluster
+ Ndb_cluster_connection cluster_connection;
+
+ // Connect to cluster management server (ndb_mgmd)
+ if (cluster_connection.connect(4 /* retries */,
+ 5 /* delay between retries */,
+ 1 /* verbose */))
+ {
+ std::cout << "Cluster management server was not ready within 30 secs.\n";
+ exit(-1);
+ }
+
+ // Optionally connect and wait for the storage nodes (ndbd's)
+ if (cluster_connection.wait_until_ready(30,0) < 0)
+ {
+ std::cout << "Cluster was not ready within 30 secs.\n";
+ exit(-1);
+ }
+
+ // connect to mysql server
+ MYSQL mysql;
+ if ( !mysql_init(&mysql) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
+ 3306, "/tmp/mysql.sock", 0) )
+ MYSQLERROR(mysql);
+
+ // run the application code
+ run_application(mysql, cluster_connection);
+ }
+
+ ndb_end(0);
+
+ std::cout << "\nTo drop created table use:\n"
+ << "echo \"drop table MYTABLENAME\" | mysql TEST_DB_1 -u root\n";
+
+ return 0;
+}
+
+static void create_table(MYSQL &);
+static void do_insert(Ndb &);
+static void do_update(Ndb &);
+static void do_delete(Ndb &);
+static void do_read(Ndb &);
+
+static void run_application(MYSQL &mysql,
+ Ndb_cluster_connection &cluster_connection)
+{
+ /********************************************
+ * Connect to database via mysql-c *
+ ********************************************/
+ mysql_query(&mysql, "CREATE DATABASE TEST_DB_1");
+ if (mysql_query(&mysql, "USE TEST_DB_1") != 0) MYSQLERROR(mysql);
+ create_table(mysql);
+
+ /********************************************
+ * Connect to database via NdbApi *
+ ********************************************/
+ // Object representing the database
+ Ndb myNdb( &cluster_connection, "TEST_DB_1" );
+ if (myNdb.init()) APIERROR(myNdb.getNdbError());
+
+ /*
+ * Do different operations on database
+ */
+ do_insert(myNdb);
+ do_update(myNdb);
+ do_delete(myNdb);
+ do_read(myNdb);
+}
+
+/*********************************************************
+ * Create a table named MYTABLENAME if it does not exist *
+ *********************************************************/
+static void create_table(MYSQL &mysql)
+{
+ if (mysql_query(&mysql,
+ "CREATE TABLE"
+ " MYTABLENAME"
+ " (ATTR1 INT UNSIGNED NOT NULL PRIMARY KEY,"
+ " ATTR2 INT UNSIGNED NOT NULL)"
+ " ENGINE=NDB"))
+ MYSQLERROR(mysql);
+}
+
+/**************************************************************************
+ * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
+ **************************************************************************/
+static void do_insert(Ndb &myNdb)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ for (int i = 0; i < 5; i++) {
+ NdbTransaction *myTransaction= myNdb.startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i);
+ myOperation->setValue("ATTR2", i);
+
+ myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i+5);
+ myOperation->setValue("ATTR2", i+5);
+
+ if (myTransaction->execute( NdbTransaction::Commit ) == -1)
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb.closeTransaction(myTransaction);
+ }
+}
+
+/*****************************************************************
+ * Update the second attribute in half of the tuples (adding 10) *
+ *****************************************************************/
+static void do_update(Ndb &myNdb)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ for (int i = 0; i < 10; i+=2) {
+ NdbTransaction *myTransaction= myNdb.startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->updateTuple();
+ myOperation->equal( "ATTR1", i );
+ myOperation->setValue( "ATTR2", i+10);
+
+ if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb.closeTransaction(myTransaction);
+ }
+}
+
+/*************************************************
+ * Delete one tuple (the one with primary key 3) *
+ *************************************************/
+static void do_delete(Ndb &myNdb)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ NdbTransaction *myTransaction= myNdb.startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->deleteTuple();
+ myOperation->equal( "ATTR1", 3 );
+
+ if (myTransaction->execute(NdbTransaction::Commit) == -1)
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb.closeTransaction(myTransaction);
+}
+
+/*****************************
+ * Read and print all tuples *
+ *****************************/
+static void do_read(Ndb &myNdb)
+{
+ const NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+
+ std::cout << "ATTR1 ATTR2" << std::endl;
+
+ for (int i = 0; i < 10; i++) {
+ NdbTransaction *myTransaction= myNdb.startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->readTuple(NdbOperation::LM_Read);
+ myOperation->equal("ATTR1", i);
+
+ NdbRecAttr *myRecAttr= myOperation->getValue("ATTR2", NULL);
+ if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
+
+ if(myTransaction->execute( NdbTransaction::Commit ) == -1)
+ if (i == 3) {
+ std::cout << "Detected that deleted tuple doesn't exist!" << std::endl;
+ } else {
+ APIERROR(myTransaction->getNdbError());
+ }
+
+ if (i != 3) {
+ printf(" %2d %2d\n", i, myRecAttr->u_32_value());
+ }
+ myNdb.closeTransaction(myTransaction);
+ }
+}
diff --git a/ndb/ndbapi-examples/ndbapi_simple_index_example/Makefile b/ndb/ndbapi-examples/ndbapi_simple_index_example/Makefile
new file mode 100644
index 00000000000..d4356055935
--- /dev/null
+++ b/ndb/ndbapi-examples/ndbapi_simple_index_example/Makefile
@@ -0,0 +1,23 @@
+TARGET = ndbapi_simple_index
+SRCS = $(TARGET).cpp
+OBJS = $(TARGET).o
+CXX = g++
+CFLAGS = -c -Wall -fno-rtti -fno-exceptions
+CXXFLAGS =
+DEBUG =
+LFLAGS = -Wall
+TOP_SRCDIR = ../../..
+INCLUDE_DIR = $(TOP_SRCDIR)
+LIB_DIR = -L$(TOP_SRCDIR)/ndb/src/.libs \
+ -L$(TOP_SRCDIR)/libmysql_r/.libs \
+ -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+SYS_LIB =
+
+$(TARGET): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+
+$(TARGET).o: $(SRCS)
+ $(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/ndb/include -I$(INCLUDE_DIR)/ndb/include/ndbapi $(SRCS)
+
+clean:
+ rm -f *.o $(TARGET)
diff --git a/ndb/ndbapi-examples/ndbapi_simple_index_example/ndbapi_simple_index.cpp b/ndb/ndbapi-examples/ndbapi_simple_index_example/ndbapi_simple_index.cpp
new file mode 100644
index 00000000000..5afaf6078d1
--- /dev/null
+++ b/ndb/ndbapi-examples/ndbapi_simple_index_example/ndbapi_simple_index.cpp
@@ -0,0 +1,254 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+//
+// ndbapi_simple_index.cpp: Using secondary indexes in NDB API
+//
+// Correct output from this program is:
+//
+// ATTR1 ATTR2
+// 0 10
+// 1 1
+// 2 12
+// Detected that deleted tuple doesn't exist!
+// 4 14
+// 5 5
+// 6 16
+// 7 7
+// 8 18
+// 9 9
+
+#include <mysql.h>
+#include <NdbApi.hpp>
+
+// Used for cout
+#include <stdio.h>
+#include <iostream>
+
+#define PRINT_ERROR(code,msg) \
+ std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
+ << ", code: " << code \
+ << ", msg: " << msg << "." << std::endl
+#define MYSQLERROR(mysql) { \
+ PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
+ exit(-1); }
+#define APIERROR(error) { \
+ PRINT_ERROR(error.code,error.message); \
+ exit(-1); }
+
+int main()
+{
+ ndb_init();
+ MYSQL mysql;
+
+ /**************************************************************
+ * Connect to mysql server and create table *
+ **************************************************************/
+ {
+ if ( !mysql_init(&mysql) ) {
+ std::cout << "mysql_init failed\n";
+ exit(-1);
+ }
+ if ( !mysql_real_connect(&mysql, "localhost", "root", "", "",
+ 3306, "/tmp/mysql.sock", 0) )
+ MYSQLERROR(mysql);
+
+ mysql_query(&mysql, "CREATE DATABASE TEST_DB_1");
+ if (mysql_query(&mysql, "USE TEST_DB_1") != 0) MYSQLERROR(mysql);
+
+ if (mysql_query(&mysql,
+ "CREATE TABLE"
+ " MYTABLENAME"
+ " (ATTR1 INT UNSIGNED,"
+ " ATTR2 INT UNSIGNED NOT NULL,"
+ " PRIMARY KEY USING HASH (ATTR1),"
+ " UNIQUE MYINDEXNAME USING HASH (ATTR2))"
+ " ENGINE=NDB"))
+ MYSQLERROR(mysql);
+ }
+
+ /**************************************************************
+ * Connect to ndb cluster *
+ **************************************************************/
+
+ Ndb_cluster_connection *cluster_connection=
+ new Ndb_cluster_connection(); // Object representing the cluster
+
+ if (cluster_connection->connect(5,3,1))
+ {
+ std::cout << "Connect to cluster management server failed.\n";
+ exit(-1);
+ }
+
+ if (cluster_connection->wait_until_ready(30,30))
+ {
+ std::cout << "Cluster was not ready within 30 secs.\n";
+ exit(-1);
+ }
+
+ Ndb* myNdb = new Ndb( cluster_connection,
+ "TEST_DB_1" ); // Object representing the database
+ if (myNdb->init() == -1) {
+ APIERROR(myNdb->getNdbError());
+ exit(-1);
+ }
+
+ const NdbDictionary::Dictionary* myDict= myNdb->getDictionary();
+ const NdbDictionary::Table *myTable= myDict->getTable("MYTABLENAME");
+ if (myTable == NULL)
+ APIERROR(myDict->getNdbError());
+ const NdbDictionary::Index *myIndex= myDict->getIndex("MYINDEXNAME","MYTABLENAME");
+ if (myIndex == NULL)
+ APIERROR(myDict->getNdbError());
+
+ /**************************************************************************
+ * Using 5 transactions, insert 10 tuples in table: (0,0),(1,1),...,(9,9) *
+ **************************************************************************/
+ for (int i = 0; i < 5; i++) {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i);
+ myOperation->setValue("ATTR2", i);
+
+ myOperation = myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->insertTuple();
+ myOperation->equal("ATTR1", i+5);
+ myOperation->setValue("ATTR2", i+5);
+
+ if (myTransaction->execute( NdbTransaction::Commit ) == -1)
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb->closeTransaction(myTransaction);
+ }
+
+ /*****************************************
+ * Read and print all tuples using index *
+ *****************************************/
+ std::cout << "ATTR1 ATTR2" << std::endl;
+
+ for (int i = 0; i < 10; i++) {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbIndexOperation *myIndexOperation=
+ myTransaction->getNdbIndexOperation(myIndex);
+ if (myIndexOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myIndexOperation->readTuple(NdbOperation::LM_Read);
+ myIndexOperation->equal("ATTR2", i);
+
+ NdbRecAttr *myRecAttr= myIndexOperation->getValue("ATTR1", NULL);
+ if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
+
+ if(myTransaction->execute( NdbTransaction::Commit ) != -1)
+ printf(" %2d %2d\n", myRecAttr->u_32_value(), i);
+
+ myNdb->closeTransaction(myTransaction);
+ }
+
+ /*****************************************************************
+ * Update the second attribute in half of the tuples (adding 10) *
+ *****************************************************************/
+ for (int i = 0; i < 10; i+=2) {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbIndexOperation *myIndexOperation=
+ myTransaction->getNdbIndexOperation(myIndex);
+ if (myIndexOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myIndexOperation->updateTuple();
+ myIndexOperation->equal( "ATTR2", i );
+ myIndexOperation->setValue( "ATTR2", i+10);
+
+ if( myTransaction->execute( NdbTransaction::Commit ) == -1 )
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb->closeTransaction(myTransaction);
+ }
+
+ /*************************************************
+ * Delete one tuple (the one with primary key 3) *
+ *************************************************/
+ {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbIndexOperation *myIndexOperation=
+ myTransaction->getNdbIndexOperation(myIndex);
+ if (myIndexOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myIndexOperation->deleteTuple();
+ myIndexOperation->equal( "ATTR2", 3 );
+
+ if (myTransaction->execute(NdbTransaction::Commit) == -1)
+ APIERROR(myTransaction->getNdbError());
+
+ myNdb->closeTransaction(myTransaction);
+ }
+
+ /*****************************
+ * Read and print all tuples *
+ *****************************/
+ {
+ std::cout << "ATTR1 ATTR2" << std::endl;
+
+ for (int i = 0; i < 10; i++) {
+ NdbTransaction *myTransaction= myNdb->startTransaction();
+ if (myTransaction == NULL) APIERROR(myNdb->getNdbError());
+
+ NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
+ if (myOperation == NULL) APIERROR(myTransaction->getNdbError());
+
+ myOperation->readTuple(NdbOperation::LM_Read);
+ myOperation->equal("ATTR1", i);
+
+ NdbRecAttr *myRecAttr= myOperation->getValue("ATTR2", NULL);
+ if (myRecAttr == NULL) APIERROR(myTransaction->getNdbError());
+
+ if(myTransaction->execute( NdbTransaction::Commit ) == -1)
+ if (i == 3) {
+ std::cout << "Detected that deleted tuple doesn't exist!\n";
+ } else {
+ APIERROR(myTransaction->getNdbError());
+ }
+
+ if (i != 3) {
+ printf(" %2d %2d\n", i, myRecAttr->u_32_value());
+ }
+ myNdb->closeTransaction(myTransaction);
+ }
+ }
+
+ /**************
+ * Drop table *
+ **************/
+ if (mysql_query(&mysql, "DROP TABLE MYTABLENAME"))
+ MYSQLERROR(mysql);
+
+ delete myNdb;
+ delete cluster_connection;
+
+ ndb_end(0);
+ return 0;
+}
diff --git a/ndb/src/Makefile.am b/ndb/src/Makefile.am
index eb1cf1c6543..d35790a2e43 100644
--- a/ndb/src/Makefile.am
+++ b/ndb/src/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = common mgmapi ndbapi . kernel mgmsrv mgmclient cw
+SUBDIRS = common mgmapi ndbapi . kernel mgmclient mgmsrv cw
include $(top_srcdir)/ndb/config/common.mk.am
diff --git a/ndb/src/common/debugger/EventLogger.cpp b/ndb/src/common/debugger/EventLogger.cpp
index 97945394690..5a534b36b59 100644
--- a/ndb/src/common/debugger/EventLogger.cpp
+++ b/ndb/src/common/debugger/EventLogger.cpp
@@ -33,1281 +33,698 @@ EventLoggerBase::~EventLoggerBase()
}
-/**
- * This matrix defines which event should be printed when
- *
- * threshold - is in range [0-15]
- * severity - DEBUG to ALERT (Type of log message)
- */
-const EventLoggerBase::EventRepLogLevelMatrix EventLoggerBase::matrix[] = {
- // CONNECTION
- { EventReport::Connected, LogLevel::llConnection, 8, Logger::LL_INFO },
- { EventReport::Disconnected, LogLevel::llConnection, 8, Logger::LL_ALERT },
- { EventReport::CommunicationClosed, LogLevel::llConnection, 8, Logger::LL_INFO },
- { EventReport::CommunicationOpened, LogLevel::llConnection, 8, Logger::LL_INFO },
- { EventReport::ConnectedApiVersion, LogLevel::llConnection, 8, Logger::LL_INFO },
- // CHECKPOINT
- { EventReport::GlobalCheckpointStarted, LogLevel::llCheckpoint, 9, Logger::LL_INFO },
- { EventReport::GlobalCheckpointCompleted,LogLevel::llCheckpoint,10, Logger::LL_INFO },
- { EventReport::LocalCheckpointStarted, LogLevel::llCheckpoint, 7, Logger::LL_INFO },
- { EventReport::LocalCheckpointCompleted,LogLevel::llCheckpoint, 8, Logger::LL_INFO },
- { EventReport::LCPStoppedInCalcKeepGci, LogLevel::llCheckpoint, 0, Logger::LL_ALERT },
- { EventReport::LCPFragmentCompleted, LogLevel::llCheckpoint, 11, Logger::LL_INFO },
- { EventReport::UndoLogBlocked, LogLevel::llCheckpoint, 7, Logger::LL_INFO },
- // STARTUP
- { EventReport::NDBStartStarted, LogLevel::llStartUp, 1, Logger::LL_INFO },
- { EventReport::NDBStartCompleted, LogLevel::llStartUp, 1, Logger::LL_INFO },
- { EventReport::STTORRYRecieved, LogLevel::llStartUp,15, Logger::LL_INFO },
- { EventReport::StartPhaseCompleted, LogLevel::llStartUp, 4, Logger::LL_INFO },
- { EventReport::CM_REGCONF, LogLevel::llStartUp, 3, Logger::LL_INFO },
- { EventReport::CM_REGREF, LogLevel::llStartUp, 8, Logger::LL_INFO },
- { EventReport::FIND_NEIGHBOURS, LogLevel::llStartUp, 8, Logger::LL_INFO },
- { EventReport::NDBStopStarted, LogLevel::llStartUp, 1, Logger::LL_INFO },
- { EventReport::NDBStopAborted, LogLevel::llStartUp, 1, Logger::LL_INFO },
- { EventReport::StartREDOLog, LogLevel::llStartUp, 10, Logger::LL_INFO },
- { EventReport::StartLog, LogLevel::llStartUp, 10, Logger::LL_INFO },
- { EventReport::UNDORecordsExecuted, LogLevel::llStartUp, 15, Logger::LL_INFO },
-
- // NODERESTART
- { EventReport::NR_CopyDict, LogLevel::llNodeRestart, 8, Logger::LL_INFO },
- { EventReport::NR_CopyDistr, LogLevel::llNodeRestart, 8, Logger::LL_INFO },
- { EventReport::NR_CopyFragsStarted, LogLevel::llNodeRestart, 8, Logger::LL_INFO },
- { EventReport::NR_CopyFragDone, LogLevel::llNodeRestart, 10, Logger::LL_INFO },
- { EventReport::NR_CopyFragsCompleted, LogLevel::llNodeRestart, 8, Logger::LL_INFO },
-
- { EventReport::NodeFailCompleted, LogLevel::llNodeRestart, 8, Logger::LL_ALERT},
- { EventReport::NODE_FAILREP, LogLevel::llNodeRestart, 8, Logger::LL_ALERT},
- { EventReport::ArbitState, LogLevel::llNodeRestart, 6, Logger::LL_INFO },
- { EventReport::ArbitResult, LogLevel::llNodeRestart, 2, Logger::LL_ALERT},
- { EventReport::GCP_TakeoverStarted, LogLevel::llNodeRestart, 7, Logger::LL_INFO },
- { EventReport::GCP_TakeoverCompleted, LogLevel::llNodeRestart, 7, Logger::LL_INFO },
- { EventReport::LCP_TakeoverStarted, LogLevel::llNodeRestart, 7, Logger::LL_INFO },
- { EventReport::LCP_TakeoverCompleted, LogLevel::llNodeRestart, 7, Logger::LL_INFO },
-
- // STATISTIC
- { EventReport::TransReportCounters, LogLevel::llStatistic, 8, Logger::LL_INFO },
- { EventReport::OperationReportCounters, LogLevel::llStatistic, 8, Logger::LL_INFO },
- { EventReport::TableCreated, LogLevel::llStatistic, 7, Logger::LL_INFO },
- { EventReport::JobStatistic, LogLevel::llStatistic, 9, Logger::LL_INFO },
- { EventReport::SendBytesStatistic, LogLevel::llStatistic, 9, Logger::LL_INFO },
- { EventReport::ReceiveBytesStatistic, LogLevel::llStatistic, 9, Logger::LL_INFO },
- { EventReport::MemoryUsage, LogLevel::llStatistic, 5, Logger::LL_INFO },
-
- // ERROR
- { EventReport::TransporterError, LogLevel::llError, 2, Logger::LL_ERROR },
- { EventReport::TransporterWarning, LogLevel::llError, 8, Logger::LL_WARNING },
- { EventReport::MissedHeartbeat, LogLevel::llError, 8, Logger::LL_WARNING },
- { EventReport::DeadDueToHeartbeat, LogLevel::llError, 8, Logger::LL_ALERT },
- { EventReport::WarningEvent, LogLevel::llError, 2, Logger::LL_WARNING },
- // INFO
- { EventReport::SentHeartbeat, LogLevel::llInfo, 12, Logger::LL_INFO },
- { EventReport::CreateLogBytes, LogLevel::llInfo, 11, Logger::LL_INFO },
- { EventReport::InfoEvent, LogLevel::llInfo, 2, Logger::LL_INFO },
+#define QQQQ char *m_text, size_t m_text_len, const Uint32* theData
- //Global replication
- { EventReport::GrepSubscriptionInfo, LogLevel::llGrep, 7, Logger::LL_INFO},
- { EventReport::GrepSubscriptionAlert, LogLevel::llGrep, 7, Logger::LL_ALERT},
-
- // Backup
- { EventReport::BackupStarted, LogLevel::llBackup, 7, Logger::LL_INFO },
- { EventReport::BackupCompleted, LogLevel::llBackup, 7, Logger::LL_INFO },
- { EventReport::BackupFailedToStart, LogLevel::llBackup, 7, Logger::LL_ALERT},
- { EventReport::BackupAborted, LogLevel::llBackup, 7, Logger::LL_ALERT }
-};
-
-const Uint32 EventLoggerBase::matrixSize = sizeof(EventLoggerBase::matrix)/
- sizeof(EventRepLogLevelMatrix);
-
-const char*
-EventLogger::getText(char * m_text, size_t m_text_len,
- int type,
- const Uint32* theData, NodeId nodeId)
-{
- // TODO: Change the switch implementation...
- char theNodeId[32];
- if (nodeId != 0){
- BaseString::snprintf(theNodeId, 32, "Node %u: ", nodeId);
- } else {
- theNodeId[0] = 0;
- }
-
- EventReport::EventType eventType = (EventReport::EventType)type;
- switch (eventType){
- case EventReport::Connected:
- BaseString::snprintf(m_text, m_text_len,
- "%sNode %u Connected",
- theNodeId,
- theData[1]);
- break;
- case EventReport::ConnectedApiVersion:
- BaseString::snprintf(m_text, m_text_len,
- "%sNode %u: API version %d.%d.%d",
- theNodeId,
- theData[1],
- getMajor(theData[2]),
- getMinor(theData[2]),
- getBuild(theData[2]));
- break;
- case EventReport::Disconnected:
- BaseString::snprintf(m_text, m_text_len,
- "%sNode %u Disconnected",
- theNodeId,
- theData[1]);
- break;
- case EventReport::CommunicationClosed:
- //-----------------------------------------------------------------------
- // REPORT communication to node closed.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text, m_text_len,
- "%sCommunication to Node %u closed",
- theNodeId,
- theData[1]);
- break;
- case EventReport::CommunicationOpened:
- //-----------------------------------------------------------------------
- // REPORT communication to node opened.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text, m_text_len,
- "%sCommunication to Node %u opened",
- theNodeId,
- theData[1]);
- break;
- case EventReport::NDBStartStarted:
- //-----------------------------------------------------------------------
- // Start of NDB has been initiated.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text, m_text_len,
- "%sStart initiated (version %d.%d.%d)",
- theNodeId ,
- getMajor(theData[1]),
- getMinor(theData[1]),
- getBuild(theData[1]));
- break;
- case EventReport::NDBStopStarted:
- BaseString::snprintf(m_text, m_text_len,
- "%s%s shutdown initiated",
- theNodeId,
- (theData[1] == 1 ? "Cluster" : "Node"));
- break;
- case EventReport::NDBStopAborted:
- BaseString::snprintf(m_text, m_text_len,
- "%sNode shutdown aborted",
- theNodeId);
- break;
- case EventReport::NDBStartCompleted:
- //-----------------------------------------------------------------------
- // Start of NDB has been completed.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text, m_text_len,
- "%sStarted (version %d.%d.%d)",
- theNodeId ,
- getMajor(theData[1]),
- getMinor(theData[1]),
- getBuild(theData[1]));
-
- break;
- case EventReport::STTORRYRecieved:
- //-----------------------------------------------------------------------
- // STTORRY recevied after restart finished.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text, m_text_len,
- "%sSTTORRY received after restart finished",
- theNodeId);
- break;
- case EventReport::StartPhaseCompleted:{
- //-----------------------------------------------------------------------
- // REPORT Start phase completed.
- //-----------------------------------------------------------------------
- const char * type = "<Unknown>";
- switch((NodeState::StartType)theData[2]){
- case NodeState::ST_INITIAL_START:
- type = "(initial start)";
- break;
- case NodeState::ST_SYSTEM_RESTART:
- type = "(system restart)";
- break;
- case NodeState::ST_NODE_RESTART:
- type = "(node restart)";
- break;
- case NodeState::ST_INITIAL_NODE_RESTART:
- type = "(initial node restart)";
- break;
- case NodeState::ST_ILLEGAL_TYPE:
- type = "";
- break;
- default:{
- BaseString::snprintf(m_text, m_text_len,
- "%sStart phase %u completed (unknown = %d)",
- theNodeId,
- theData[1],
- theData[2]);
- return m_text;
- }
- }
- BaseString::snprintf(m_text, m_text_len,
- "%sStart phase %u completed %s",
- theNodeId,
- theData[1],
- type);
- return m_text;
- break;
- }
- case EventReport::CM_REGCONF:
- BaseString::snprintf(m_text, m_text_len,
- "%sCM_REGCONF president = %u, own Node = %u, our dynamic id = %u"
- ,
- theNodeId,
- theData[2],
- theData[1],
- theData[3]);
- break;
- case EventReport::CM_REGREF:
- {
- const char* line = "";
- switch (theData[3]) {
- case 0:
- line = "Busy";
- break;
- case 1:
- line = "Election with wait = false";
- break;
- case 2:
- line = "Election with wait = false";
- break;
- case 3:
- line = "Not president";
- break;
- case 4:
- line = "Election without selecting new candidate";
- break;
- default:
- line = "No such cause";
- break;
- }//switch
-
- BaseString::snprintf(m_text, m_text_len,
- "%sCM_REGREF from Node %u to our Node %u. Cause = %s",
- theNodeId,
- theData[2],
- theData[1],
- line);
- }
- break;
- case EventReport::FIND_NEIGHBOURS:
- //-----------------------------------------------------------------------
- // REPORT Node Restart copied a fragment.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sWe are Node %u with dynamic ID %u, our left neighbour "
- "is Node %u, our right is Node %u",
- theNodeId,
- theData[1],
- theData[4],
- theData[2],
- theData[3]);
- break;
- case EventReport::NodeFailCompleted:
- //-----------------------------------------------------------------------
- // REPORT Node failure phase completed.
- //-----------------------------------------------------------------------
- if (theData[1] == 0)
- {
- if (theData[3] != 0) {
- BaseString::snprintf(m_text, m_text_len,
- "%sNode %u completed failure of Node %u",
- theNodeId,
- theData[3],
- theData[2]);
- } else {
- BaseString::snprintf(m_text, m_text_len,
- "%sAll nodes completed failure of Node %u",
- theNodeId,
- theData[2]);
- }//if
- } else {
- const char* line = "";
- if (theData[1] == DBTC){
- line = "DBTC";
- }else if (theData[1] == DBDICT){
- line = "DBDICT";
- }else if (theData[1] == DBDIH){
- line = "DBDIH";
- }else if (theData[1] == DBLQH){
- line = "DBLQH";
- }
-
- BaseString::snprintf(m_text, m_text_len,
- "%sNode failure of %u %s completed",
- theNodeId,
- theData[2],
- line);
- }
- break;
- case EventReport::NODE_FAILREP:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sNode %u has failed. The Node state at failure "
- "was %u",
- theNodeId,
- theData[1],
- theData[2]);
-
- break;
- case EventReport::ArbitState:
- //-----------------------------------------------------------------------
- // REPORT arbitrator found or lost.
- //-----------------------------------------------------------------------
- { const ArbitSignalData* sd = (ArbitSignalData*)theData;
- char ticketText[ArbitTicket::TextLength + 1];
- char errText[ArbitCode::ErrTextLength + 1];
- const unsigned code = sd->code & 0xFFFF;
- const unsigned state = sd->code >> 16;
- switch (code) {
- case ArbitCode::ThreadStart:
- BaseString::snprintf(m_text, m_text_len,
- "%sPresident restarts arbitration thread [state=%u]",
- theNodeId, state);
- break;
- case ArbitCode::PrepPart2:
- sd->ticket.getText(ticketText, sizeof(ticketText));
- BaseString::snprintf(m_text, m_text_len,
- "%sPrepare arbitrator node %u [ticket=%s]",
- theNodeId, sd->node, ticketText);
- break;
- case ArbitCode::PrepAtrun:
- sd->ticket.getText(ticketText, sizeof(ticketText));
- BaseString::snprintf(m_text, m_text_len,
- "%sReceive arbitrator node %u [ticket=%s]",
- theNodeId, sd->node, ticketText);
- break;
- case ArbitCode::ApiStart:
- sd->ticket.getText(ticketText, sizeof(ticketText));
- BaseString::snprintf(m_text, m_text_len,
- "%sStarted arbitrator node %u [ticket=%s]",
- theNodeId, sd->node, ticketText);
- break;
- case ArbitCode::ApiFail:
- BaseString::snprintf(m_text, m_text_len,
- "%sLost arbitrator node %u - process failure [state=%u]",
- theNodeId, sd->node, state);
- break;
- case ArbitCode::ApiExit:
- BaseString::snprintf(m_text, m_text_len,
- "%sLost arbitrator node %u - process exit [state=%u]",
- theNodeId, sd->node, state);
- break;
- default:
- ArbitCode::getErrText(code, errText, sizeof(errText));
- BaseString::snprintf(m_text, m_text_len,
- "%sLost arbitrator node %u - %s [state=%u]",
- theNodeId, sd->node, errText, state);
- break;
- }
- }
- break;
- case EventReport::ArbitResult:
- //-----------------------------------------------------------------------
- // REPORT arbitration result (the failures may not reach us).
- //-----------------------------------------------------------------------
- { const ArbitSignalData* sd = (ArbitSignalData*)theData;
- char errText[ArbitCode::ErrTextLength + 1];
- const unsigned code = sd->code & 0xFFFF;
- const unsigned state = sd->code >> 16;
- switch (code) {
- case ArbitCode::LoseNodes:
- BaseString::snprintf(m_text, m_text_len,
- "%sArbitration check lost - less than 1/2 nodes left",
- theNodeId);
- break;
- case ArbitCode::WinNodes:
- BaseString::snprintf(m_text, m_text_len,
- "%sArbitration check won - all node groups and more than 1/2 nodes left",
- theNodeId);
- break;
- case ArbitCode::WinGroups:
- BaseString::snprintf(m_text, m_text_len,
- "%sArbitration check won - node group majority",
- theNodeId);
- break;
- case ArbitCode::LoseGroups:
- BaseString::snprintf(m_text, m_text_len,
- "%sArbitration check lost - missing node group",
- theNodeId);
- break;
- case ArbitCode::Partitioning:
- BaseString::snprintf(m_text, m_text_len,
- "%sNetwork partitioning - arbitration required",
- theNodeId);
- break;
- case ArbitCode::WinChoose:
- BaseString::snprintf(m_text, m_text_len,
- "%sArbitration won - positive reply from node %u",
- theNodeId, sd->node);
- break;
- case ArbitCode::LoseChoose:
- BaseString::snprintf(m_text, m_text_len,
- "%sArbitration lost - negative reply from node %u",
- theNodeId, sd->node);
- break;
- case ArbitCode::LoseNorun:
- BaseString::snprintf(m_text, m_text_len,
- "%sNetwork partitioning - no arbitrator available",
- theNodeId);
- break;
- case ArbitCode::LoseNocfg:
- BaseString::snprintf(m_text, m_text_len,
- "%sNetwork partitioning - no arbitrator configured",
- theNodeId);
- break;
- default:
- ArbitCode::getErrText(code, errText, sizeof(errText));
- BaseString::snprintf(m_text, m_text_len,
- "%sArbitration failure - %s [state=%u]",
- theNodeId, errText, state);
- break;
- }
- }
+void getTextConnected(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Node %u Connected",
+ theData[1]);
+}
+void getTextConnectedApiVersion(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Node %u: API version %d.%d.%d",
+ theData[1],
+ getMajor(theData[2]),
+ getMinor(theData[2]),
+ getBuild(theData[2]));
+}
+void getTextDisconnected(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Node %u Disconnected",
+ theData[1]);
+}
+void getTextCommunicationClosed(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT communication to node closed.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Communication to Node %u closed",
+ theData[1]);
+}
+void getTextCommunicationOpened(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT communication to node opened.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Communication to Node %u opened",
+ theData[1]);
+}
+void getTextNDBStartStarted(QQQQ) {
+ //-----------------------------------------------------------------------
+ // Start of NDB has been initiated.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Start initiated (version %d.%d.%d)",
+ getMajor(theData[1]),
+ getMinor(theData[1]),
+ getBuild(theData[1]));
+}
+void getTextNDBStopStarted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "%s shutdown initiated",
+ (theData[1] == 1 ? "Cluster" : "Node"));
+}
+void getTextNDBStopAborted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Node shutdown aborted");
+}
+void getTextNDBStartCompleted(QQQQ) {
+ //-----------------------------------------------------------------------
+ // Start of NDB has been completed.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Started (version %d.%d.%d)",
+ getMajor(theData[1]),
+ getMinor(theData[1]),
+ getBuild(theData[1]));
+}
+void getTextSTTORRYRecieved(QQQQ) {
+ //-----------------------------------------------------------------------
+ // STTORRY recevied after restart finished.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "STTORRY received after restart finished");
+}
+void getTextStartPhaseCompleted(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Start phase completed.
+ //-----------------------------------------------------------------------
+ const char *type = "<Unknown>";
+ switch((NodeState::StartType)theData[2]){
+ case NodeState::ST_INITIAL_START:
+ type = "(initial start)";
break;
- case EventReport::GlobalCheckpointStarted:
- //-----------------------------------------------------------------------
- // This event reports that a global checkpoint has been started and this
- // node is the master of this global checkpoint.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sGlobal checkpoint %u started",
- theNodeId,
- theData[1]);
+ case NodeState::ST_SYSTEM_RESTART:
+ type = "(system restart)";
break;
- case EventReport::GlobalCheckpointCompleted:
- //-----------------------------------------------------------------------
- // This event reports that a global checkpoint has been completed on this
- // node and the node is the master of this global checkpoint.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text, m_text_len,
- "%sGlobal checkpoint %u completed",
- theNodeId,
- theData[1]);
+ case NodeState::ST_NODE_RESTART:
+ type = "(node restart)";
break;
- case EventReport::LocalCheckpointStarted:
- //-----------------------------------------------------------------------
- // This event reports that a local checkpoint has been started and this
- // node is the master of this local checkpoint.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sLocal checkpoint %u started. "
- "Keep GCI = %u oldest restorable GCI = %u",
- theNodeId,
- theData[1],
- theData[2],
- theData[3]);
+ case NodeState::ST_INITIAL_NODE_RESTART:
+ type = "(initial node restart)";
break;
- case EventReport::LocalCheckpointCompleted:
- //-----------------------------------------------------------------------
- // This event reports that a local checkpoint has been completed on this
- // node and the node is the master of this local checkpoint.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sLocal checkpoint %u completed",
- theNodeId,
- theData[1]);
+ case NodeState::ST_ILLEGAL_TYPE:
+ type = "";
break;
- case EventReport::TableCreated:
- //-----------------------------------------------------------------------
- // This event reports that a table has been created.
- //-----------------------------------------------------------------------
+ default:
BaseString::snprintf(m_text, m_text_len,
- "%sTable with ID = %u created",
- theNodeId,
- theData[1]);
- break;
- case EventReport::LCPStoppedInCalcKeepGci:
- if (theData[1] == 0)
- BaseString::snprintf(m_text, m_text_len,
- "%sLocal Checkpoint stopped in CALCULATED_KEEP_GCI",
- theNodeId);
- break;
- case EventReport::NR_CopyDict:
- //-----------------------------------------------------------------------
- // REPORT Node Restart completed copy of dictionary information.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sNode restart completed copy of dictionary information",
- theNodeId);
- break;
- case EventReport::NR_CopyDistr:
- //-----------------------------------------------------------------------
- // REPORT Node Restart completed copy of distribution information.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sNode restart completed copy of distribution information",
- theNodeId);
- break;
- case EventReport::NR_CopyFragsStarted:
- //-----------------------------------------------------------------------
- // REPORT Node Restart is starting to copy the fragments.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sNode restart starting to copy the fragments "
- "to Node %u",
- theNodeId,
- theData[1]);
- break;
- case EventReport::NR_CopyFragDone:
- //-----------------------------------------------------------------------
- // REPORT Node Restart copied a fragment.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sTable ID = %u, fragment ID = %u have been copied "
- "to Node %u",
- theNodeId,
- theData[2],
- theData[3],
- theData[1]);
- break;
- case EventReport::NR_CopyFragsCompleted:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sNode restart completed copying the fragments "
- "to Node %u",
- theNodeId,
- theData[1]);
- break;
- case EventReport::LCPFragmentCompleted:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sTable ID = %u, fragment ID = %u has completed LCP "
- "on Node %u",
- theNodeId,
- theData[2],
- theData[3],
- theData[1]);
+ "Start phase %u completed (unknown = %d)",
+ theData[1],
+ theData[2]);
+ return;
+ }
+ BaseString::snprintf(m_text, m_text_len,
+ "Start phase %u completed %s",
+ theData[1],
+ type);
+}
+void getTextCM_REGCONF(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "CM_REGCONF president = %u, own Node = %u, our dynamic id = %u",
+ theData[2],
+ theData[1],
+ theData[3]);
+}
+void getTextCM_REGREF(QQQQ) {
+ const char* line = "";
+ switch (theData[3]) {
+ case 0:
+ line = "Busy";
break;
- case EventReport::TransReportCounters:
- // -------------------------------------------------------------------
- // Report information about transaction activity once per 10 seconds.
- // -------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sTrans. Count = %u, Commit Count = %u, "
- "Read Count = %u, Simple Read Count = %u,\n"
- "Write Count = %u, AttrInfo Count = %u, "
- "Concurrent Operations = %u, Abort Count = %u\n"
- " Scans: %u Range scans: %u",
- theNodeId,
- theData[1],
- theData[2],
- theData[3],
- theData[4],
- theData[5],
- theData[6],
- theData[7],
- theData[8],
- theData[9],
- theData[10]);
+ case 1:
+ line = "Election with wait = false";
break;
- case EventReport::OperationReportCounters:
- BaseString::snprintf(m_text, m_text_len,
- "%sOperations=%u",
- theNodeId,
- theData[1]);
+ case 2:
+ line = "Election with wait = false";
break;
- case EventReport::UndoLogBlocked:
- //-----------------------------------------------------------------------
- // REPORT Undo Logging blocked due to buffer near to overflow.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sACC Blocked %u and TUP Blocked %u times last second",
- theNodeId,
- theData[1],
- theData[2]);
- break;
- case EventReport::TransporterError:
- case EventReport::TransporterWarning:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sTransporter to node %d reported error 0x%x",
- theNodeId,
- theData[1],
- theData[2]);
- break;
- case EventReport::MissedHeartbeat:
- //-----------------------------------------------------------------------
- // REPORT Undo Logging blocked due to buffer near to overflow.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sNode %d missed heartbeat %d",
- theNodeId,
- theData[1],
- theData[2]);
- break;
- case EventReport::DeadDueToHeartbeat:
- //-----------------------------------------------------------------------
- // REPORT Undo Logging blocked due to buffer near to overflow.
- //-----------------------------------------------------------------------
- BaseString::snprintf(m_text,
- m_text_len,
- "%sNode %d declared dead due to missed heartbeat",
- theNodeId,
- theData[1]);
- break;
- case EventReport::JobStatistic:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sMean loop Counter in doJob last 8192 times = %u",
- theNodeId,
- theData[1]);
+ case 3:
+ line = "Not president";
break;
- case EventReport::SendBytesStatistic:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sMean send size to Node = %d last 4096 sends = %u bytes",
- theNodeId,
- theData[1],
- theData[2]);
+ case 4:
+ line = "Election without selecting new candidate";
break;
- case EventReport::ReceiveBytesStatistic:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sMean receive size to Node = %d last 4096 sends = %u bytes",
- theNodeId,
- theData[1],
- theData[2]);
- break;
- case EventReport::SentHeartbeat:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sNode Sent Heartbeat to node = %d",
- theNodeId,
- theData[1]);
- break;
- case EventReport::CreateLogBytes:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sLog part %u, log file %u, MB %u",
- theNodeId,
- theData[1],
- theData[2],
- theData[3]);
- break;
- case EventReport::StartLog:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sLog part %u, start MB %u, stop MB %u, last GCI, log exec %u",
- theNodeId,
- theData[1],
- theData[2],
- theData[3],
- theData[4]);
- break;
- case EventReport::StartREDOLog:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sNode: %d StartLog: [GCI Keep: %d LastCompleted: %d NewestRestorable: %d]",
- theNodeId,
- theData[1],
- theData[2],
- theData[3],
- theData[4]);
- break;
- case EventReport::UNDORecordsExecuted:{
- const char* line = "";
- if (theData[1] == DBTUP){
- line = "DBTUP";
- }else if (theData[1] == DBACC){
- line = "DBACC";
- }
-
- BaseString::snprintf(m_text,
- m_text_len,
- "%s UNDO %s %d [%d %d %d %d %d %d %d %d %d]",
- theNodeId,
- line,
- theData[2],
- theData[3],
- theData[4],
- theData[5],
- theData[6],
- theData[7],
- theData[8],
- theData[9],
- theData[10],
- theData[11]);
- }
- break;
- case EventReport::InfoEvent:
- BaseString::snprintf(m_text,
- m_text_len,
- "%s%s",
- theNodeId,
- (char *)&theData[1]);
- break;
- case EventReport::WarningEvent:
- BaseString::snprintf(m_text,
- m_text_len,
- "%s%s",
- theNodeId,
- (char *)&theData[1]);
- break;
- case EventReport::GCP_TakeoverStarted:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sGCP Take over started", theNodeId);
- break;
- case EventReport::GCP_TakeoverCompleted:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sGCP Take over completed", theNodeId);
- break;
- case EventReport::LCP_TakeoverStarted:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sLCP Take over started", theNodeId);
- break;
- case EventReport::LCP_TakeoverCompleted:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sLCP Take over completed (state = %d)",
- theNodeId, theData[1]);
- break;
- case EventReport::MemoryUsage:{
- const int gth = theData[1];
- const int size = theData[2];
- const int used = theData[3];
- const int total = theData[4];
- const int block = theData[5];
- const int percent = (used*100)/total;
-
- BaseString::snprintf(m_text, m_text_len,
- "%s%s usage %s %d%s(%d %dK pages of total %d)",
- theNodeId,
- (block==DBACC ? "Index" : (block == DBTUP ?"Data":"<unknown>")),
- (gth == 0 ? "is" : (gth > 0 ? "increased to" : "decreased to")),
- percent, "%",
- used, size/1024, total
- );
+ default:
+ line = "No such cause";
break;
- }
- case EventReport::GrepSubscriptionInfo :
- {
- GrepEvent::Subscription event = (GrepEvent::Subscription)theData[1];
- switch(event) {
- case GrepEvent::GrepSS_CreateSubIdConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Created subscription id"
- " (subId=%d,SubKey=%d)"
- " Return code: %d.",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepPS_CreateSubIdConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: Created subscription id"
- " (subId=%d,SubKey=%d)"
- " Return code: %d.",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepSS_SubCreateConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- const int nodegrp = theData[5];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Created subscription using"
- " (subId=%d,SubKey=%d)"
- " in primary system. Primary system has %d nodegroup(s)."
- " Return code: %d",
- subId,
- subKey,
- nodegrp,
- err);
- break;
- }
- case GrepEvent::GrepPS_SubCreateConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: All participants have created "
- "subscriptions"
- " using (subId=%d,SubKey=%d)."
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepSS_SubStartMetaConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Logging started on meta data changes."
- " using (subId=%d,SubKey=%d)"
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepPS_SubStartMetaConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: All participants have started "
- "logging meta data"
- " changes on the subscription subId=%d,SubKey=%d) "
- "(N.I yet)."
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepSS_SubStartDataConf: {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Logging started on table data changes "
- " using (subId=%d,SubKey=%d)"
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepPS_SubStartDataConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: All participants have started logging "
- "table data changes on the subscription "
- "subId=%d,SubKey=%d)."
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepPS_SubSyncMetaConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: All participants have started "
- " synchronization on meta data (META SCAN) using "
- "(subId=%d,SubKey=%d)."
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepSS_SubSyncMetaConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Synchronization started (META SCAN) on "
- " meta data using (subId=%d,SubKey=%d)"
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepPS_SubSyncDataConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: All participants have started "
- "synchronization "
- " on table data (DATA SCAN) using (subId=%d,SubKey=%d)."
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepSS_SubSyncDataConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- const int gci = theData[5];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Synchronization started (DATA SCAN) on "
- "table data using (subId=%d,SubKey=%d). GCI = %d"
- " Return code: %d",
- subId,
- subKey,
- gci,
- err);
- break;
- }
- case GrepEvent::GrepPS_SubRemoveConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
+ }//switch
+
+ BaseString::snprintf(m_text, m_text_len,
+ "CM_REGREF from Node %u to our Node %u. Cause = %s",
+ theData[2],
+ theData[1],
+ line);
+}
+void getTextFIND_NEIGHBOURS(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Node Restart copied a fragment.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "We are Node %u with dynamic ID %u, our left neighbour "
+ "is Node %u, our right is Node %u",
+ theData[1],
+ theData[4],
+ theData[2],
+ theData[3]);
+}
+void getTextNodeFailCompleted(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Node failure phase completed.
+ //-----------------------------------------------------------------------
+ if (theData[1] == 0)
+ {
+ if (theData[3] != 0) {
BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: All participants have removed "
- "subscription (subId=%d,SubKey=%d). I have cleaned "
- "up resources I've used."
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- case GrepEvent::GrepSS_SubRemoveConf:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
+ "Node %u completed failure of Node %u",
+ theData[3],
+ theData[2]);
+ } else {
BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Removed subscription "
- "(subId=%d,SubKey=%d)"
- " Return code: %d",
- subId,
- subKey,
- err);
- break;
- }
- default:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sUnknown GrepSubscriptonInfo event: %d",
- theNodeId,
- theData[1]);
+ "All nodes completed failure of Node %u",
+ theData[2]);
+ }//if
+ } else {
+ const char* line = "";
+ if (theData[1] == DBTC){
+ line = "DBTC";
+ }else if (theData[1] == DBDICT){
+ line = "DBDICT";
+ }else if (theData[1] == DBDIH){
+ line = "DBDIH";
+ }else if (theData[1] == DBLQH){
+ line = "DBLQH";
}
- break;
+ BaseString::snprintf(m_text, m_text_len,
+ "Node failure of %u %s completed",
+ theData[2],
+ line);
}
-
- case EventReport::GrepSubscriptionAlert :
+}
+void getTextNODE_FAILREP(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Node %u has failed. The Node state at failure "
+ "was %u",
+ theData[1],
+ theData[2]);
+}
+void getTextArbitState(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT arbitrator found or lost.
+ //-----------------------------------------------------------------------
{
- GrepEvent::Subscription event = (GrepEvent::Subscription)theData[1];
- switch(event)
- {
- case GrepEvent::GrepSS_CreateSubIdRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord:Error code: %d Error message: %s"
- " (subId=%d,SubKey=%d)",
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err),
- subId,
- subKey);
- break;
- }
- case GrepEvent::GrepSS_SubCreateRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: FAILED to Created subscription using"
- " (subId=%d,SubKey=%d)in primary system."
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
- break;
- }
- case GrepEvent::GrepSS_SubStartMetaRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Logging failed to start on meta "
- "data changes."
- " using (subId=%d,SubKey=%d)"
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
- break;
- }
- case GrepEvent::GrepSS_SubStartDataRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Logging FAILED to start on table data "
- " changes using (subId=%d,SubKey=%d)"
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
- break;
- }
- case GrepEvent::GrepSS_SubSyncMetaRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Synchronization FAILED (META SCAN) on "
- " meta data using (subId=%d,SubKey=%d)"
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
- break;
- }
- case GrepEvent::GrepSS_SubSyncDataRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- const int gci = theData[5];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Synchronization FAILED (DATA SCAN) on "
- "table data using (subId=%d,SubKey=%d). GCI = %d"
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- gci,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
- break;
- }
- case GrepEvent::GrepSS_SubRemoveRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::SSCoord: Failed to remove subscription "
- "(subId=%d,SubKey=%d). "
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err)
- );
- break;
- }
-
- case GrepEvent::GrepPS_CreateSubIdRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: Error code: %d Error Message: %s"
- " (subId=%d,SubKey=%d)",
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err),
- subId,
- subKey);
- break;
- }
- case GrepEvent::GrepPS_SubCreateRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: FAILED to Created subscription using"
- " (subId=%d,SubKey=%d)in primary system."
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
+ const ArbitSignalData* sd = (ArbitSignalData*)theData;
+ char ticketText[ArbitTicket::TextLength + 1];
+ char errText[ArbitCode::ErrTextLength + 1];
+ const unsigned code = sd->code & 0xFFFF;
+ const unsigned state = sd->code >> 16;
+ switch (code) {
+ case ArbitCode::ThreadStart:
+ BaseString::snprintf(m_text, m_text_len,
+ "President restarts arbitration thread [state=%u]",
+ state);
+ break;
+ case ArbitCode::PrepPart2:
+ sd->ticket.getText(ticketText, sizeof(ticketText));
+ BaseString::snprintf(m_text, m_text_len,
+ "Prepare arbitrator node %u [ticket=%s]",
+ sd->node, ticketText);
+ break;
+ case ArbitCode::PrepAtrun:
+ sd->ticket.getText(ticketText, sizeof(ticketText));
+ BaseString::snprintf(m_text, m_text_len,
+ "Receive arbitrator node %u [ticket=%s]",
+ sd->node, ticketText);
+ break;
+ case ArbitCode::ApiStart:
+ sd->ticket.getText(ticketText, sizeof(ticketText));
+ BaseString::snprintf(m_text, m_text_len,
+ "Started arbitrator node %u [ticket=%s]",
+ sd->node, ticketText);
+ break;
+ case ArbitCode::ApiFail:
+ BaseString::snprintf(m_text, m_text_len,
+ "Lost arbitrator node %u - process failure [state=%u]",
+ sd->node, state);
+ break;
+ case ArbitCode::ApiExit:
+ BaseString::snprintf(m_text, m_text_len,
+ "Lost arbitrator node %u - process exit [state=%u]",
+ sd->node, state);
break;
- }
- case GrepEvent::GrepPS_SubStartMetaRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: Logging failed to start on meta "
- "data changes."
- " using (subId=%d,SubKey=%d)"
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
- break;
- }
- case GrepEvent::GrepPS_SubStartDataRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: Logging FAILED to start on table data "
- " changes using (subId=%d,SubKey=%d)"
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
- break;
- }
- case GrepEvent::GrepPS_SubSyncMetaRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: Synchronization FAILED (META SCAN) on "
- " meta data using (subId=%d,SubKey=%d)"
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
- break;
- }
- case GrepEvent::GrepPS_SubSyncDataRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- const int gci = theData[5];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: Synchronization FAILED (DATA SCAN) on "
- "table data using (subId=%d,SubKey=%d). GCI = %d. "
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- gci,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
+ default:
+ ArbitCode::getErrText(code, errText, sizeof(errText));
+ BaseString::snprintf(m_text, m_text_len,
+ "Lost arbitrator node %u - %s [state=%u]",
+ sd->node, errText, state);
break;
}
- case GrepEvent::GrepPS_SubRemoveRef:
- {
- const int subId = theData[2];
- const int subKey = theData[3];
- const int err = theData[4];
- BaseString::snprintf(m_text, m_text_len,
- "Grep::PSCoord: Failed to remove subscription "
- "(subId=%d,SubKey=%d)."
- " Error code: %d Error Message: %s",
- subId,
- subKey,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
- break;
- }
- case GrepEvent::Rep_Disconnect:
- {
- const int err = theData[4];
- const int nodeId = theData[5];
- BaseString::snprintf(m_text, m_text_len,
- "Rep: Node %d."
- " Error code: %d Error Message: %s",
- nodeId,
- err,
- GrepError::getErrorDesc((GrepError::GE_Code)err));
+ }
+}
+
+void getTextArbitResult(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT arbitration result (the failures may not reach us).
+ //-----------------------------------------------------------------------
+ {
+ const ArbitSignalData* sd = (ArbitSignalData*)theData;
+ char errText[ArbitCode::ErrTextLength + 1];
+ const unsigned code = sd->code & 0xFFFF;
+ const unsigned state = sd->code >> 16;
+ switch (code) {
+ case ArbitCode::LoseNodes:
+ BaseString::snprintf(m_text, m_text_len,
+ "Arbitration check lost - less than 1/2 nodes left");
+ break;
+ case ArbitCode::WinNodes:
+ BaseString::snprintf(m_text, m_text_len,
+ "Arbitration check won - all node groups and more than 1/2 nodes left");
+ break;
+ case ArbitCode::WinGroups:
+ BaseString::snprintf(m_text, m_text_len,
+ "Arbitration check won - node group majority");
+ break;
+ case ArbitCode::LoseGroups:
+ BaseString::snprintf(m_text, m_text_len,
+ "Arbitration check lost - missing node group");
+ break;
+ case ArbitCode::Partitioning:
+ BaseString::snprintf(m_text, m_text_len,
+ "Network partitioning - arbitration required");
+ break;
+ case ArbitCode::WinChoose:
+ BaseString::snprintf(m_text, m_text_len,
+ "Arbitration won - positive reply from node %u",
+ sd->node);
+ break;
+ case ArbitCode::LoseChoose:
+ BaseString::snprintf(m_text, m_text_len,
+ "Arbitration lost - negative reply from node %u",
+ sd->node);
+ break;
+ case ArbitCode::LoseNorun:
+ BaseString::snprintf(m_text, m_text_len,
+ "Network partitioning - no arbitrator available");
+ break;
+ case ArbitCode::LoseNocfg:
+ BaseString::snprintf(m_text, m_text_len,
+ "Network partitioning - no arbitrator configured");
break;
- }
-
-
default:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sUnknown GrepSubscriptionAlert event: %d",
- theNodeId,
- theData[1]);
- break;
+ ArbitCode::getErrText(code, errText, sizeof(errText));
+ BaseString::snprintf(m_text, m_text_len,
+ "Arbitration failure - %s [state=%u]",
+ errText, state);
+ break;
}
- break;
}
-
- case EventReport::BackupStarted:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sBackup %d started from node %d",
- theNodeId, theData[2], refToNode(theData[1]));
- break;
- case EventReport::BackupFailedToStart:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sBackup request from %d failed to start. Error: %d",
- theNodeId, refToNode(theData[1]), theData[2]);
- break;
- case EventReport::BackupCompleted:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sBackup %u started from node %u completed\n"
- " StartGCP: %u StopGCP: %u\n"
- " #Records: %u #LogRecords: %u\n"
- " Data: %u bytes Log: %u bytes",
- theNodeId, theData[2], refToNode(theData[1]),
- theData[3], theData[4], theData[6], theData[8],
- theData[5], theData[7]);
- break;
- case EventReport::BackupAborted:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sBackup %d started from %d has been aborted. Error: %d",
- theNodeId,
- theData[2],
- refToNode(theData[1]),
- theData[3]);
- break;
- default:
- BaseString::snprintf(m_text,
- m_text_len,
- "%sUnknown event: %d",
- theNodeId,
- theData[0]);
-
+}
+void getTextGlobalCheckpointStarted(QQQQ) {
+ //-----------------------------------------------------------------------
+ // This event reports that a global checkpoint has been started and this
+ // node is the master of this global checkpoint.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Global checkpoint %u started",
+ theData[1]);
+}
+void getTextGlobalCheckpointCompleted(QQQQ) {
+ //-----------------------------------------------------------------------
+ // This event reports that a global checkpoint has been completed on this
+ // node and the node is the master of this global checkpoint.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Global checkpoint %u completed",
+ theData[1]);
+}
+void getTextLocalCheckpointStarted(QQQQ) {
+ //-----------------------------------------------------------------------
+ // This event reports that a local checkpoint has been started and this
+ // node is the master of this local checkpoint.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Local checkpoint %u started. "
+ "Keep GCI = %u oldest restorable GCI = %u",
+ theData[1],
+ theData[2],
+ theData[3]);
+}
+void getTextLocalCheckpointCompleted(QQQQ) {
+ //-----------------------------------------------------------------------
+ // This event reports that a local checkpoint has been completed on this
+ // node and the node is the master of this local checkpoint.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Local checkpoint %u completed",
+ theData[1]);
+}
+void getTextTableCreated(QQQQ) {
+ //-----------------------------------------------------------------------
+ // This event reports that a table has been created.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Table with ID = %u created",
+ theData[1]);
+}
+/* STRANGE */
+void getTextLCPStoppedInCalcKeepGci(QQQQ) {
+ if (theData[1] == 0)
+ BaseString::snprintf(m_text, m_text_len,
+ "Local Checkpoint stopped in CALCULATED_KEEP_GCI");
+}
+void getTextNR_CopyDict(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Node Restart completed copy of dictionary information.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Node restart completed copy of dictionary information");
+}
+void getTextNR_CopyDistr(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Node Restart completed copy of distribution information.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Node restart completed copy of distribution information");
+}
+void getTextNR_CopyFragsStarted(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Node Restart is starting to copy the fragments.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Node restart starting to copy the fragments "
+ "to Node %u",
+ theData[1]);
+}
+void getTextNR_CopyFragDone(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Node Restart copied a fragment.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Table ID = %u, fragment ID = %u have been copied "
+ "to Node %u",
+ theData[2],
+ theData[3],
+ theData[1]);
+}
+void getTextNR_CopyFragsCompleted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Node restart completed copying the fragments "
+ "to Node %u",
+ theData[1]);
+}
+void getTextLCPFragmentCompleted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Table ID = %u, fragment ID = %u has completed LCP "
+ "on Node %u",
+ theData[2],
+ theData[3],
+ theData[1]);
+}
+void getTextTransReportCounters(QQQQ) {
+ // -------------------------------------------------------------------
+ // Report information about transaction activity once per 10 seconds.
+ // -------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Trans. Count = %u, Commit Count = %u, "
+ "Read Count = %u, Simple Read Count = %u,\n"
+ "Write Count = %u, AttrInfo Count = %u, "
+ "Concurrent Operations = %u, Abort Count = %u\n"
+ " Scans: %u Range scans: %u",
+ theData[1],
+ theData[2],
+ theData[3],
+ theData[4],
+ theData[5],
+ theData[6],
+ theData[7],
+ theData[8],
+ theData[9],
+ theData[10]);
+}
+void getTextOperationReportCounters(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Operations=%u",
+ theData[1]);
+}
+void getTextUndoLogBlocked(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Undo Logging blocked due to buffer near to overflow.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "ACC Blocked %u and TUP Blocked %u times last second",
+ theData[1],
+ theData[2]);
+}
+void getTextTransporterError(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Transporter to node %d reported error 0x%x",
+ theData[1],
+ theData[2]);
+}
+void getTextTransporterWarning(QQQQ) {
+ getTextTransporterError(m_text, m_text_len, theData);
+}
+void getTextMissedHeartbeat(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Undo Logging blocked due to buffer near to overflow.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Node %d missed heartbeat %d",
+ theData[1],
+ theData[2]);
+}
+void getTextDeadDueToHeartbeat(QQQQ) {
+ //-----------------------------------------------------------------------
+ // REPORT Undo Logging blocked due to buffer near to overflow.
+ //-----------------------------------------------------------------------
+ BaseString::snprintf(m_text, m_text_len,
+ "Node %d declared dead due to missed heartbeat",
+ theData[1]);
+}
+void getTextJobStatistic(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Mean loop Counter in doJob last 8192 times = %u",
+ theData[1]);
+}
+void getTextSendBytesStatistic(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Mean send size to Node = %d last 4096 sends = %u bytes",
+ theData[1],
+ theData[2]);
+}
+void getTextReceiveBytesStatistic(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Mean receive size to Node = %d last 4096 sends = %u bytes",
+ theData[1],
+ theData[2]);
+}
+void getTextSentHeartbeat(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Node Sent Heartbeat to node = %d",
+ theData[1]);
+}
+void getTextCreateLogBytes(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Log part %u, log file %u, MB %u",
+ theData[1],
+ theData[2],
+ theData[3]);
+}
+void getTextStartLog(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Log part %u, start MB %u, stop MB %u, last GCI, log exec %u",
+ theData[1],
+ theData[2],
+ theData[3],
+ theData[4]);
+}
+void getTextStartREDOLog(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Node: %d StartLog: [GCI Keep: %d LastCompleted: %d NewestRestorable: %d]",
+ theData[1],
+ theData[2],
+ theData[3],
+ theData[4]);
+}
+void getTextUNDORecordsExecuted(QQQQ) {
+ const char* line = "";
+ if (theData[1] == DBTUP){
+ line = "DBTUP";
+ }else if (theData[1] == DBACC){
+ line = "DBACC";
}
- return m_text;
+
+ BaseString::snprintf(m_text, m_text_len,
+ " UNDO %s %d [%d %d %d %d %d %d %d %d %d]",
+ line,
+ theData[2],
+ theData[3],
+ theData[4],
+ theData[5],
+ theData[6],
+ theData[7],
+ theData[8],
+ theData[9],
+ theData[10],
+ theData[11]);
+}
+void getTextInfoEvent(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len, (char *)&theData[1]);
+}
+void getTextWarningEvent(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len, (char *)&theData[1]);
+}
+void getTextGCP_TakeoverStarted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len, "GCP Take over started");
+}
+void getTextGCP_TakeoverCompleted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len, "GCP Take over completed");
+}
+void getTextLCP_TakeoverStarted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len, "LCP Take over started");
+}
+void getTextLCP_TakeoverCompleted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "LCP Take over completed (state = %d)",
+ theData[1]);
+}
+void getTextMemoryUsage(QQQQ) {
+ const int gth = theData[1];
+ const int size = theData[2];
+ const int used = theData[3];
+ const int total = theData[4];
+ const int block = theData[5];
+ const int percent = (used*100)/total;
+
+ BaseString::snprintf(m_text, m_text_len,
+ "%s usage %s %d%s(%d %dK pages of total %d)",
+ (block==DBACC ? "Index" : (block == DBTUP ?"Data":"<unknown>")),
+ (gth == 0 ? "is" : (gth > 0 ? "increased to" : "decreased to")),
+ percent, "%",
+ used, size/1024, total
+ );
+}
+
+void getTextBackupStarted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Backup %d started from node %d",
+ theData[2], refToNode(theData[1]));
+}
+void getTextBackupFailedToStart(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Backup request from %d failed to start. Error: %d",
+ refToNode(theData[1]), theData[2]);
+}
+void getTextBackupCompleted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Backup %u started from node %u completed\n"
+ " StartGCP: %u StopGCP: %u\n"
+ " #Records: %u #LogRecords: %u\n"
+ " Data: %u bytes Log: %u bytes",
+ theData[2], refToNode(theData[1]),
+ theData[3], theData[4], theData[6], theData[8],
+ theData[5], theData[7]);
+}
+void getTextBackupAborted(QQQQ) {
+ BaseString::snprintf(m_text, m_text_len,
+ "Backup %d started from %d has been aborted. Error: %d",
+ theData[2],
+ refToNode(theData[1]),
+ theData[3]);
}
+#if 0
+BaseString::snprintf(m_text,
+ m_text_len,
+ "Unknown event: %d",
+ theData[0]);
+#endif
+
+/**
+ * This matrix defines which event should be printed when
+ *
+ * threshold - is in range [0-15]
+ * severity - DEBUG to ALERT (Type of log message)
+ */
+
+#define ROW(a,b,c,d) \
+{ NDB_LE_ ## a, b, c, d, getText ## a}
+
+const EventLoggerBase::EventRepLogLevelMatrix EventLoggerBase::matrix[] = {
+ // CONNECTION
+ ROW(Connected, LogLevel::llConnection, 8, Logger::LL_INFO ),
+ ROW(Disconnected, LogLevel::llConnection, 8, Logger::LL_ALERT ),
+ ROW(CommunicationClosed, LogLevel::llConnection, 8, Logger::LL_INFO ),
+ ROW(CommunicationOpened, LogLevel::llConnection, 8, Logger::LL_INFO ),
+ ROW(ConnectedApiVersion, LogLevel::llConnection, 8, Logger::LL_INFO ),
+ // CHECKPOINT
+ ROW(GlobalCheckpointStarted, LogLevel::llCheckpoint, 9, Logger::LL_INFO ),
+ ROW(GlobalCheckpointCompleted,LogLevel::llCheckpoint,10, Logger::LL_INFO ),
+ ROW(LocalCheckpointStarted, LogLevel::llCheckpoint, 7, Logger::LL_INFO ),
+ ROW(LocalCheckpointCompleted,LogLevel::llCheckpoint, 8, Logger::LL_INFO ),
+ ROW(LCPStoppedInCalcKeepGci, LogLevel::llCheckpoint, 0, Logger::LL_ALERT ),
+ ROW(LCPFragmentCompleted, LogLevel::llCheckpoint, 11, Logger::LL_INFO ),
+ ROW(UndoLogBlocked, LogLevel::llCheckpoint, 7, Logger::LL_INFO ),
+
+ // STARTUP
+ ROW(NDBStartStarted, LogLevel::llStartUp, 1, Logger::LL_INFO ),
+ ROW(NDBStartCompleted, LogLevel::llStartUp, 1, Logger::LL_INFO ),
+ ROW(STTORRYRecieved, LogLevel::llStartUp, 15, Logger::LL_INFO ),
+ ROW(StartPhaseCompleted, LogLevel::llStartUp, 4, Logger::LL_INFO ),
+ ROW(CM_REGCONF, LogLevel::llStartUp, 3, Logger::LL_INFO ),
+ ROW(CM_REGREF, LogLevel::llStartUp, 8, Logger::LL_INFO ),
+ ROW(FIND_NEIGHBOURS, LogLevel::llStartUp, 8, Logger::LL_INFO ),
+ ROW(NDBStopStarted, LogLevel::llStartUp, 1, Logger::LL_INFO ),
+ ROW(NDBStopAborted, LogLevel::llStartUp, 1, Logger::LL_INFO ),
+ ROW(StartREDOLog, LogLevel::llStartUp, 10, Logger::LL_INFO ),
+ ROW(StartLog, LogLevel::llStartUp, 10, Logger::LL_INFO ),
+ ROW(UNDORecordsExecuted, LogLevel::llStartUp, 15, Logger::LL_INFO ),
+
+ // NODERESTART
+ ROW(NR_CopyDict, LogLevel::llNodeRestart, 8, Logger::LL_INFO ),
+ ROW(NR_CopyDistr, LogLevel::llNodeRestart, 8, Logger::LL_INFO ),
+ ROW(NR_CopyFragsStarted, LogLevel::llNodeRestart, 8, Logger::LL_INFO ),
+ ROW(NR_CopyFragDone, LogLevel::llNodeRestart,10, Logger::LL_INFO ),
+ ROW(NR_CopyFragsCompleted, LogLevel::llNodeRestart, 8, Logger::LL_INFO ),
+
+ ROW(NodeFailCompleted, LogLevel::llNodeRestart, 8, Logger::LL_ALERT),
+ ROW(NODE_FAILREP, LogLevel::llNodeRestart, 8, Logger::LL_ALERT),
+ ROW(ArbitState, LogLevel::llNodeRestart, 6, Logger::LL_INFO ),
+ ROW(ArbitResult, LogLevel::llNodeRestart, 2, Logger::LL_ALERT),
+ ROW(GCP_TakeoverStarted, LogLevel::llNodeRestart, 7, Logger::LL_INFO ),
+ ROW(GCP_TakeoverCompleted, LogLevel::llNodeRestart, 7, Logger::LL_INFO ),
+ ROW(LCP_TakeoverStarted, LogLevel::llNodeRestart, 7, Logger::LL_INFO ),
+ ROW(LCP_TakeoverCompleted, LogLevel::llNodeRestart, 7, Logger::LL_INFO ),
+
+ // STATISTIC
+ ROW(TransReportCounters, LogLevel::llStatistic, 8, Logger::LL_INFO ),
+ ROW(OperationReportCounters, LogLevel::llStatistic, 8, Logger::LL_INFO ),
+ ROW(TableCreated, LogLevel::llStatistic, 7, Logger::LL_INFO ),
+ ROW(JobStatistic, LogLevel::llStatistic, 9, Logger::LL_INFO ),
+ ROW(SendBytesStatistic, LogLevel::llStatistic, 9, Logger::LL_INFO ),
+ ROW(ReceiveBytesStatistic, LogLevel::llStatistic, 9, Logger::LL_INFO ),
+ ROW(MemoryUsage, LogLevel::llStatistic, 5, Logger::LL_INFO ),
+
+ // ERROR
+ ROW(TransporterError, LogLevel::llError, 2, Logger::LL_ERROR ),
+ ROW(TransporterWarning, LogLevel::llError, 8, Logger::LL_WARNING ),
+ ROW(MissedHeartbeat, LogLevel::llError, 8, Logger::LL_WARNING ),
+ ROW(DeadDueToHeartbeat, LogLevel::llError, 8, Logger::LL_ALERT ),
+ ROW(WarningEvent, LogLevel::llError, 2, Logger::LL_WARNING ),
+ // INFO
+ ROW(SentHeartbeat, LogLevel::llInfo, 12, Logger::LL_INFO ),
+ ROW(CreateLogBytes, LogLevel::llInfo, 11, Logger::LL_INFO ),
+ ROW(InfoEvent, LogLevel::llInfo, 2, Logger::LL_INFO ),
+
+ // Backup
+ ROW(BackupStarted, LogLevel::llBackup, 7, Logger::LL_INFO ),
+ ROW(BackupCompleted, LogLevel::llBackup, 7, Logger::LL_INFO ),
+ ROW(BackupFailedToStart, LogLevel::llBackup, 7, Logger::LL_ALERT),
+ ROW(BackupAborted, LogLevel::llBackup, 7, Logger::LL_ALERT )
+};
+
+const Uint32 EventLoggerBase::matrixSize=
+sizeof(EventLoggerBase::matrix)/sizeof(EventRepLogLevelMatrix);
+
EventLogger::EventLogger() : m_filterLevel(15)
{
setCategory("EventLogger");
@@ -1346,19 +763,37 @@ int
EventLoggerBase::event_lookup(int eventType,
LogLevel::EventCategory &cat,
Uint32 &threshold,
- Logger::LoggerLevel &severity)
+ Logger::LoggerLevel &severity,
+ EventTextFunction &textF)
{
for(unsigned i = 0; i<EventLoggerBase::matrixSize; i++){
if(EventLoggerBase::matrix[i].eventType == eventType){
cat = EventLoggerBase::matrix[i].eventCategory;
threshold = EventLoggerBase::matrix[i].threshold;
severity = EventLoggerBase::matrix[i].severity;
+ textF= EventLoggerBase::matrix[i].textF;
return 0;
}
}
return 1;
}
+const char*
+EventLogger::getText(char * dst, size_t dst_len,
+ EventTextFunction textF,
+ const Uint32* theData, NodeId nodeId )
+{
+ int pos= 0;
+ if (nodeId != 0)
+ {
+ BaseString::snprintf(dst, dst_len, "Node %u: ", nodeId);
+ pos= strlen(dst);
+ }
+ if (dst_len-pos > 0)
+ textF(dst+pos,dst_len-pos,theData);
+ return dst;
+}
+
void
EventLogger::log(int eventType, const Uint32* theData, NodeId nodeId,
const LogLevel* ll)
@@ -1366,52 +801,43 @@ EventLogger::log(int eventType, const Uint32* theData, NodeId nodeId,
Uint32 threshold = 0;
Logger::LoggerLevel severity = Logger::LL_WARNING;
LogLevel::EventCategory cat= LogLevel::llInvalid;
+ EventTextFunction textF;
DBUG_ENTER("EventLogger::log");
DBUG_PRINT("enter",("eventType=%d, nodeid=%d", eventType, nodeId));
- if (EventLoggerBase::event_lookup(eventType,cat,threshold,severity))
+ if (EventLoggerBase::event_lookup(eventType,cat,threshold,severity,textF))
DBUG_VOID_RETURN;
Uint32 set = ll?ll->getLogLevel(cat) : m_logLevel.getLogLevel(cat);
DBUG_PRINT("info",("threshold=%d, set=%d", threshold, set));
if (ll)
DBUG_PRINT("info",("m_logLevel.getLogLevel=%d", m_logLevel.getLogLevel(cat)));
+
if (threshold <= set){
+ getText(m_text,sizeof(m_text),textF,theData,nodeId);
+
switch (severity){
case Logger::LL_ALERT:
- alert(EventLogger::getText(m_text, sizeof(m_text),
- eventType, theData, nodeId));
+ alert(m_text);
break;
-
case Logger::LL_CRITICAL:
- critical(EventLogger::getText(m_text, sizeof(m_text),
- eventType, theData, nodeId));
+ critical(m_text);
break;
-
case Logger::LL_WARNING:
- warning(EventLogger::getText(m_text, sizeof(m_text),
- eventType, theData, nodeId));
+ warning(m_text);
break;
-
case Logger::LL_ERROR:
- error(EventLogger::getText(m_text, sizeof(m_text),
- eventType, theData, nodeId));
+ error(m_text);
break;
-
case Logger::LL_INFO:
- info(EventLogger::getText(m_text, sizeof(m_text),
- eventType, theData, nodeId));
+ info(m_text);
break;
-
case Logger::LL_DEBUG:
- debug(EventLogger::getText(m_text, sizeof(m_text),
- eventType, theData, nodeId));
+ debug(m_text);
break;
-
default:
- info(EventLogger::getText(m_text, sizeof(m_text),
- eventType, theData, nodeId));
+ info(m_text);
break;
}
} // if (..
diff --git a/ndb/src/common/debugger/signaldata/DictTabInfo.cpp b/ndb/src/common/debugger/signaldata/DictTabInfo.cpp
index c6165532ddb..43c129347c0 100644
--- a/ndb/src/common/debugger/signaldata/DictTabInfo.cpp
+++ b/ndb/src/common/debugger/signaldata/DictTabInfo.cpp
@@ -23,7 +23,6 @@ SimpleProperties::SP2StructMapping
DictTabInfo::TableMapping[] = {
DTIMAPS(Table, TableName, TableName, 0, MAX_TAB_NAME_SIZE),
DTIMAP(Table, TableId, TableId),
- DTIMAP(Table, SecondTableId, SecondTableId),
DTIMAPS(Table, PrimaryTable, PrimaryTable, 0, MAX_TAB_NAME_SIZE),
DTIMAP(Table, PrimaryTableId, PrimaryTableId),
DTIMAP2(Table, TableLoggedFlag, TableLoggedFlag, 0, 1),
@@ -32,8 +31,6 @@ DictTabInfo::TableMapping[] = {
DTIMAP2(Table, MaxLoadFactor, MaxLoadFactor, 25, 110),
DTIMAP2(Table, FragmentTypeVal, FragmentType, 0, 3),
DTIMAP2(Table, TableStorageVal, TableStorage, 0, 0),
- DTIMAP2(Table, ScanOptimised, ScanOptimised, 0, 0),
- DTIMAP2(Table, FragmentKeyTypeVal, FragmentKeyType, 0, 2),
DTIMAP2(Table, TableTypeVal, TableType, 1, 3),
DTIMAP(Table, NoOfKeyAttr, NoOfKeyAttr),
DTIMAP2(Table, NoOfAttributes, NoOfAttributes, 1, MAX_ATTRIBUTES_IN_TABLE),
@@ -49,6 +46,8 @@ DictTabInfo::TableMapping[] = {
DTIMAP2(Table, FrmLen, FrmLen, 0, MAX_FRM_DATA_SIZE),
DTIMAPB(Table, FrmData, FrmData, 0, MAX_FRM_DATA_SIZE, FrmLen),
DTIMAP(Table, FragmentCount, FragmentCount),
+ DTIMAP2(Table, FragmentDataLen, FragmentDataLen, 0, MAX_FRAGMENT_DATA_BYTES),
+ DTIMAPB(Table, FragmentData, FragmentData, 0, MAX_FRAGMENT_DATA_BYTES, FragmentDataLen),
DTIBREAK(AttributeName)
};
@@ -62,16 +61,12 @@ SimpleProperties::SP2StructMapping
DictTabInfo::AttributeMapping[] = {
DTIMAPS(Attribute, AttributeName, AttributeName, 0, MAX_ATTR_NAME_SIZE),
DTIMAP(Attribute, AttributeId, AttributeId),
- DTIMAP2(Attribute, AttributeType, AttributeType, 0, 3),
+ DTIMAP(Attribute, AttributeType, AttributeType),
DTIMAP2(Attribute, AttributeSize, AttributeSize, 3, 7),
DTIMAP2(Attribute, AttributeArraySize, AttributeArraySize, 0, 65535),
DTIMAP2(Attribute, AttributeKeyFlag, AttributeKeyFlag, 0, 1),
- DTIMAP2(Attribute, AttributeStorage, AttributeStorage, 0, 0),
DTIMAP2(Attribute, AttributeNullableFlag, AttributeNullableFlag, 0, 1),
- DTIMAP2(Attribute, AttributeDGroup, AttributeDGroup, 0, 1),
DTIMAP2(Attribute, AttributeDKey, AttributeDKey, 0, 1),
- DTIMAP2(Attribute, AttributeStoredInd, AttributeStoredInd, 0, 1),
- DTIMAP2(Attribute, AttributeGroup, AttributeGroup, 0, 0),
DTIMAP(Attribute, AttributeExtType, AttributeExtType),
DTIMAP(Attribute, AttributeExtPrecision, AttributeExtPrecision),
DTIMAP(Attribute, AttributeExtScale, AttributeExtScale),
@@ -104,7 +99,6 @@ void
DictTabInfo::Table::init(){
memset(TableName, 0, sizeof(TableName));//TableName[0] = 0;
TableId = ~0;
- SecondTableId = ~0;
memset(PrimaryTable, 0, sizeof(PrimaryTable));//PrimaryTable[0] = 0; // Only used when "index"
PrimaryTableId = RNIL;
TableLoggedFlag = 1;
@@ -118,8 +112,6 @@ DictTabInfo::Table::init(){
KeyLength = 0;
FragmentType = DictTabInfo::AllNodesSmallTable;
TableStorage = 0;
- ScanOptimised = 0;
- FragmentKeyType = DictTabInfo::PrimaryKey;
TableType = DictTabInfo::UndefTableType;
TableVersion = 0;
IndexState = ~0;
@@ -130,23 +122,21 @@ DictTabInfo::Table::init(){
FrmLen = 0;
memset(FrmData, 0, sizeof(FrmData));
FragmentCount = 0;
+ FragmentDataLen = 0;
+ memset(FragmentData, 0, sizeof(FragmentData));
}
void
DictTabInfo::Attribute::init(){
memset(AttributeName, 0, sizeof(AttributeName));//AttributeName[0] = 0;
AttributeId = 0;
- AttributeType = DictTabInfo::UnSignedType;
+ AttributeType = ~0, // deprecated
AttributeSize = DictTabInfo::a32Bit;
AttributeArraySize = 1;
AttributeKeyFlag = 0;
- AttributeStorage = 1;
AttributeNullableFlag = 0;
- AttributeDGroup = 0;
AttributeDKey = 0;
- AttributeStoredInd = 1;
- AttributeGroup = 0;
- AttributeExtType = 0,
+ AttributeExtType = DictTabInfo::ExtUnsigned,
AttributeExtPrecision = 0,
AttributeExtScale = 0,
AttributeExtLength = 0,
diff --git a/ndb/src/common/debugger/signaldata/ScanTab.cpp b/ndb/src/common/debugger/signaldata/ScanTab.cpp
index 0755ee0a856..e9c5ba6cc52 100644
--- a/ndb/src/common/debugger/signaldata/ScanTab.cpp
+++ b/ndb/src/common/debugger/signaldata/ScanTab.cpp
@@ -30,20 +30,25 @@ printSCANTABREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiv
fprintf(output, " apiConnectPtr: H\'%.8x",
sig->apiConnectPtr);
fprintf(output, " requestInfo: H\'%.8x:\n", requestInfo);
- fprintf(output, " Parallellism: %u, Batch: %u LockMode: %u, Keyinfo: %u Holdlock: %u, RangeScan: %u ReadCommitted: %u\n",
+ fprintf(output, " Parallellism: %u, Batch: %u LockMode: %u Keyinfo: %u Holdlock: %u RangeScan: %u Descending: %u ReadCommitted: %u\n DistributionKeyFlag: %u",
sig->getParallelism(requestInfo),
sig->getScanBatch(requestInfo),
sig->getLockMode(requestInfo),
sig->getKeyinfoFlag(requestInfo),
sig->getHoldLockFlag(requestInfo),
sig->getRangeScanFlag(requestInfo),
- sig->getReadCommittedFlag(requestInfo));
+ sig->getDescendingFlag(requestInfo),
+ sig->getReadCommittedFlag(requestInfo),
+ sig->getDistributionKeyFlag(requestInfo));
+
+ if(sig->getDistributionKeyFlag(requestInfo))
+ fprintf(output, " DKey: %x", sig->distributionKey);
Uint32 keyLen = (sig->attrLenKeyLen >> 16);
Uint32 attrLen = (sig->attrLenKeyLen & 0xFFFF);
fprintf(output, " attrLen: %d, keyLen: %d tableId: %d, tableSchemaVer: %d\n",
attrLen, keyLen, sig->tableId, sig->tableSchemaVersion);
-
+
fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x) storedProcId: H\'%.8x\n",
sig->transId1, sig->transId2, sig->storedProcId);
fprintf(output, " batch_byte_size: %d, first_batch_size: %d\n",
diff --git a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
index a4cee38e06f..ab23c04bffa 100644
--- a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
+++ b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
@@ -27,6 +27,7 @@
const NameFunctionPair
SignalDataPrintFunctions[] = {
{ GSN_TCKEYREQ, printTCKEYREQ },
+ { GSN_TCINDXREQ, printTCKEYREQ },
{ GSN_TCKEYCONF, printTCKEYCONF },
{ GSN_TCKEYREF, printTCKEYREF },
{ GSN_LQHKEYREQ, printLQHKEYREQ },
@@ -82,14 +83,10 @@ SignalDataPrintFunctions[] = {
{ GSN_ALTER_INDX_REQ, printALTER_INDX_REQ },
{ GSN_ALTER_INDX_CONF, printALTER_INDX_CONF },
{ GSN_ALTER_INDX_REF, printALTER_INDX_REF },
- { GSN_TCINDXREQ, printTCINDXREQ },
{ GSN_TCINDXCONF, printTCINDXCONF },
{ GSN_TCINDXREF, printTCINDXREF },
{ GSN_INDXKEYINFO, printINDXKEYINFO },
{ GSN_INDXATTRINFO, printINDXATTRINFO },
- //{ GSN_TCINDXNEXTREQ, printTCINDXNEXTREQ },
- //{ GSN_TCINDEXNEXTCONF, printTCINDEXNEXTCONF },
- //{ GSN_TCINDEXNEXREF, printTCINDEXNEXREF },
{ GSN_FSAPPENDREQ, printFSAPPENDREQ },
{ GSN_BACKUP_REQ, printBACKUP_REQ },
{ GSN_BACKUP_DATA, printBACKUP_DATA },
@@ -154,11 +151,17 @@ SignalDataPrintFunctions[] = {
{ GSN_DISCONNECT_REP, printDISCONNECT_REP },
{ GSN_SUB_CREATE_REQ, printSUB_CREATE_REQ },
- //{ GSN_SUB_CREATE_REF, printSUB_CREATE_REF },
+ { GSN_SUB_CREATE_REF, printSUB_CREATE_REF },
{ GSN_SUB_CREATE_CONF, printSUB_CREATE_CONF },
+ { GSN_SUB_REMOVE_REQ, printSUB_REMOVE_REQ },
+ { GSN_SUB_REMOVE_REF, printSUB_REMOVE_REF },
+ { GSN_SUB_REMOVE_CONF, printSUB_REMOVE_CONF },
{ GSN_SUB_START_REQ, printSUB_START_REQ },
{ GSN_SUB_START_REF, printSUB_START_REF },
{ GSN_SUB_START_CONF, printSUB_START_CONF },
+ { GSN_SUB_STOP_REQ, printSUB_STOP_REQ },
+ { GSN_SUB_STOP_REF, printSUB_STOP_REF },
+ { GSN_SUB_STOP_CONF, printSUB_STOP_CONF },
{ GSN_SUB_SYNC_REQ, printSUB_SYNC_REQ },
{ GSN_SUB_SYNC_REF, printSUB_SYNC_REF },
{ GSN_SUB_SYNC_CONF, printSUB_SYNC_CONF },
diff --git a/ndb/src/common/debugger/signaldata/SignalNames.cpp b/ndb/src/common/debugger/signaldata/SignalNames.cpp
index 9228e305677..984d28819c0 100644
--- a/ndb/src/common/debugger/signaldata/SignalNames.cpp
+++ b/ndb/src/common/debugger/signaldata/SignalNames.cpp
@@ -578,6 +578,9 @@ const GsnName SignalNames [] = {
,{ GSN_SUB_CREATE_REQ, "SUB_CREATE_REQ" }
,{ GSN_SUB_CREATE_REF, "SUB_CREATE_REF" }
,{ GSN_SUB_CREATE_CONF, "SUB_CREATE_CONF" }
+ ,{ GSN_SUB_REMOVE_REQ, "SUB_REMOVE_REQ" }
+ ,{ GSN_SUB_REMOVE_REF, "SUB_REMOVE_REF" }
+ ,{ GSN_SUB_REMOVE_CONF, "SUB_REMOVE_CONF" }
,{ GSN_SUB_START_REQ, "SUB_START_REQ" }
,{ GSN_SUB_START_REF, "SUB_START_REF" }
,{ GSN_SUB_START_CONF, "SUB_START_CONF" }
diff --git a/ndb/src/common/debugger/signaldata/SumaImpl.cpp b/ndb/src/common/debugger/signaldata/SumaImpl.cpp
index 558842ed2ba..e50a3040fe3 100644
--- a/ndb/src/common/debugger/signaldata/SumaImpl.cpp
+++ b/ndb/src/common/debugger/signaldata/SumaImpl.cpp
@@ -40,12 +40,55 @@ printSUB_CREATE_CONF(FILE * output, const Uint32 * theData,
}
bool
+printSUB_CREATE_REF(FILE * output, const Uint32 * theData,
+ Uint32 len, Uint16 receiverBlockNo) {
+ const SubCreateRef * const sig = (SubCreateRef *)theData;
+ fprintf(output, " subscriptionId: %x\n", sig->subscriptionId);
+ fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey);
+ fprintf(output, " subscriberData: %x\n", sig->subscriberData);
+ return false;
+}
+
+bool
+printSUB_REMOVE_REQ(FILE * output, const Uint32 * theData,
+ Uint32 len, Uint16 receiverBlockNo)
+{
+ const SubRemoveReq * const sig = (SubRemoveReq *)theData;
+ fprintf(output, " subscriptionId: %x\n", sig->subscriptionId);
+ fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey);
+ return false;
+}
+
+bool
+printSUB_REMOVE_CONF(FILE * output, const Uint32 * theData,
+ Uint32 len, Uint16 receiverBlockNo)
+{
+ const SubRemoveConf * const sig = (SubRemoveConf *)theData;
+ fprintf(output, " subscriptionId: %x\n", sig->subscriptionId);
+ fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey);
+ fprintf(output, " subscriberData: %x\n", sig->subscriberData);
+ return false;
+}
+
+bool
+printSUB_REMOVE_REF(FILE * output, const Uint32 * theData,
+ Uint32 len, Uint16 receiverBlockNo)
+{
+ const SubRemoveRef * const sig = (SubRemoveRef *)theData;
+ fprintf(output, " subscriptionId: %x\n", sig->subscriptionId);
+ fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey);
+ fprintf(output, " subscriberData: %x\n", sig->subscriberData);
+ fprintf(output, " err: %x\n", sig->err);
+ return false;
+}
+
+bool
printSUB_START_REQ(FILE * output, const Uint32 * theData,
Uint32 len, Uint16 receiverBlockNo) {
const SubStartReq * const sig = (SubStartReq *)theData;
fprintf(output, " subscriptionId: %x\n", sig->subscriptionId);
fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey);
- fprintf(output, " startPart: %x\n", sig->part);
+ fprintf(output, " subscriberData: %x\n", sig->subscriberData);
return false;
}
@@ -73,6 +116,37 @@ printSUB_START_CONF(FILE * output, const Uint32 * theData,
}
bool
+printSUB_STOP_REQ(FILE * output, const Uint32 * theData,
+ Uint32 len, Uint16 receiverBlockNo) {
+ const SubStopReq * const sig = (SubStopReq *)theData;
+ fprintf(output, " subscriptionId: %x\n", sig->subscriptionId);
+ fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey);
+ fprintf(output, " subscriberData: %x\n", sig->subscriberData);
+ return false;
+}
+
+bool
+printSUB_STOP_REF(FILE * output, const Uint32 * theData,
+ Uint32 len, Uint16 receiverBlockNo) {
+ const SubStopRef * const sig = (SubStopRef *)theData;
+ fprintf(output, " subscriptionId: %x\n", sig->subscriptionId);
+ fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey);
+ fprintf(output, " subscriberData: %x\n", sig->subscriberData);
+ fprintf(output, " err: %x\n", sig->err);
+ return false;
+}
+
+bool
+printSUB_STOP_CONF(FILE * output, const Uint32 * theData,
+ Uint32 len, Uint16 receiverBlockNo) {
+ const SubStopConf * const sig = (SubStopConf *)theData;
+ fprintf(output, " subscriptionId: %x\n", sig->subscriptionId);
+ fprintf(output, " subscriptionKey: %x\n", sig->subscriptionKey);
+ fprintf(output, " subscriberData: %x\n", sig->subscriberData);
+ return false;
+}
+
+bool
printSUB_SYNC_REQ(FILE * output, const Uint32 * theData,
Uint32 len, Uint16 receiverBlockNo) {
const SubSyncReq * const sig = (SubSyncReq *)theData;
diff --git a/ndb/src/common/debugger/signaldata/TcIndx.cpp b/ndb/src/common/debugger/signaldata/TcIndx.cpp
index 6bfa29eff15..b0578f5b646 100644
--- a/ndb/src/common/debugger/signaldata/TcIndx.cpp
+++ b/ndb/src/common/debugger/signaldata/TcIndx.cpp
@@ -18,91 +18,6 @@
#include <signaldata/TcKeyReq.hpp>
#include <BlockNumbers.h>
-bool
-printTCINDXREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){
-
- const TcIndxReq * const sig = (TcIndxReq *) theData;
-
- UintR requestInfo = sig->requestInfo;
- UintR scanInfo = sig->scanInfo;
-
- fprintf(output, " apiConnectPtr: H\'%.8x, senderData: H\'%.8x\n",
- sig->apiConnectPtr, sig->senderData);
-
- fprintf(output, " Operation: %s, Flags: ",
- sig->getOperationType(requestInfo) == ZREAD ? "Read" :
- sig->getOperationType(requestInfo) == ZREAD_EX ? "Read-Ex" :
- sig->getOperationType(requestInfo) == ZUPDATE ? "Update" :
- sig->getOperationType(requestInfo) == ZINSERT ? "Insert" :
- sig->getOperationType(requestInfo) == ZDELETE ? "Delete" :
- sig->getOperationType(requestInfo) == ZWRITE ? "Write" :
- "Unknown");
-
- {
- if(sig->getDirtyFlag(requestInfo)){
- fprintf(output, "Dirty ");
- }
- if(sig->getStartFlag(requestInfo)){
- fprintf(output, "Start ");
- }
- if (TcKeyReq::getExecuteFlag(sig->requestInfo)) {
- fprintf(output, "Execute ");
- }
- if(sig->getCommitFlag(requestInfo)){
- fprintf(output, "Commit, Type = ");
- UintR TcommitType = sig->getCommitType(requestInfo);
- if (TcommitType == TcIndxReq::CommitIfFailFree) {
- fprintf(output, "FailFree ");
- } else if (TcommitType == TcIndxReq::TryCommit) {
- fprintf(output, "TryCommit ");
- } else if (TcommitType == TcIndxReq::CommitAsMuchAsPossible) {
- fprintf(output, "Always ");
- }//if
- }
- if(sig->getSimpleFlag(requestInfo)){
- fprintf(output, "Simple ");
- }
- if(sig->getInterpretedFlag(requestInfo)){
- fprintf(output, "Interpreted ");
- }
- if(sig->getDistributionGroupFlag(requestInfo)){
- fprintf(output, "DGroup = %d ", sig->distrGroupHashValue);
- }
- if(sig->getDistributionKeyFlag(sig->requestInfo)){
- fprintf(output, "DKey = %d ", sig->distributionKeySize);
- }
- fprintf(output, "\n");
- }
-
- const int indexLen = sig->getIndexLength(requestInfo);
- const int attrInThis = sig->getAIInTcIndxReq(requestInfo);
- fprintf(output,
- " indexLen: %d, attrLen: %d, AI in this: %d, indexId: %d, "
- "indexSchemaVer: %d, API Ver: %d\n",
- indexLen, sig->attrLen, attrInThis,
- sig->indexId, sig->indexSchemaVersion, sig->getAPIVersion(scanInfo));
-
- fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x)\n -- Variable Data --\n",
- sig->transId1, sig->transId2);
-
- Uint32 restLen = (len - 8);
- const Uint32 * rest = &sig->scanInfo;
- while(restLen >= 7){
- fprintf(output,
- " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n",
- rest[0], rest[1], rest[2], rest[3],
- rest[4], rest[5], rest[6]);
- restLen -= 7;
- rest += 7;
- }
- if(restLen > 0){
- for(Uint32 i = 0; i<restLen; i++)
- fprintf(output, " H\'%.8x", rest[i]);
- fprintf(output, "\n");
- }
-
- return true;
-}
bool
printTCINDXCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){
diff --git a/ndb/src/common/debugger/signaldata/TcKeyReq.cpp b/ndb/src/common/debugger/signaldata/TcKeyReq.cpp
index 7304872ff9c..3918bd5db26 100644
--- a/ndb/src/common/debugger/signaldata/TcKeyReq.cpp
+++ b/ndb/src/common/debugger/signaldata/TcKeyReq.cpp
@@ -68,11 +68,8 @@ printTCKEYREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiver
if(sig->getInterpretedFlag(requestInfo)){
fprintf(output, "Interpreted ");
}
- if(sig->getDistributionGroupFlag(requestInfo)){
- fprintf(output, "DGroup = %d ", sig->distrGroupHashValue);
- }
if(sig->getDistributionKeyFlag(sig->requestInfo)){
- fprintf(output, "DKey = %d ", sig->distributionKeySize);
+ fprintf(output, " d-key");
}
fprintf(output, "\n");
}
diff --git a/ndb/src/common/mgmcommon/IPCConfig.cpp b/ndb/src/common/mgmcommon/IPCConfig.cpp
index 86791490863..f188a433f1b 100644
--- a/ndb/src/common/mgmcommon/IPCConfig.cpp
+++ b/ndb/src/common/mgmcommon/IPCConfig.cpp
@@ -111,175 +111,6 @@ IPCConfig::addRemoteNodeId(NodeId nodeId){
}
/**
- * Returns no of transporters configured
- */
-int
-IPCConfig::configureTransporters(TransporterRegistry * theTransporterRegistry){
- int noOfTransportersCreated = 0;
-
- Uint32 noOfConnections;
- if(!props->get("NoOfConnections", &noOfConnections)) return -1;
-
- for (Uint32 i = 0; i < noOfConnections; i++){
- const Properties * tmp;
- Uint32 nodeId1, nodeId2;
- const char * host1;
- const char * host2;
-
- if(!props->get("Connection", i, &tmp)) continue;
- if(!tmp->get("NodeId1", &nodeId1)) continue;
- if(!tmp->get("NodeId2", &nodeId2)) continue;
- if(nodeId1 != the_ownId && nodeId2 != the_ownId) continue;
-
- Uint32 sendSignalId;
- Uint32 compression;
- Uint32 checksum;
- if(!tmp->get("SendSignalId", &sendSignalId)) continue;
- if(!tmp->get("Checksum", &checksum)) continue;
-
- const char * type;
- if(!tmp->get("Type", &type)) continue;
-
- if(strcmp("SHM", type) == 0){
- SHM_TransporterConfiguration conf;
- conf.localNodeId = the_ownId;
- conf.remoteNodeId = (nodeId1 != the_ownId ? nodeId1 : nodeId2);
- conf.checksum = checksum;
- conf.signalId = sendSignalId;
-
- if(!tmp->get("ShmKey", &conf.shmKey)) continue;
- if(!tmp->get("ShmSize", &conf.shmSize)) continue;
-
- if(!theTransporterRegistry->createTransporter(&conf)){
- ndbout << "Failed to create SHM Transporter from: "
- << conf.localNodeId << " to: " << conf.remoteNodeId << endl;
- continue;
- } else {
- noOfTransportersCreated++;
- continue;
- }
-
- } else if(strcmp("SCI", type) == 0){
- SCI_TransporterConfiguration conf;
- conf.localNodeId = the_ownId;
- conf.remoteNodeId = (nodeId1 != the_ownId ? nodeId1 : nodeId2);
- conf.checksum = checksum;
- conf.signalId = sendSignalId;
-
- if(!tmp->get("SendLimit", &conf.sendLimit)) continue;
- if(!tmp->get("SharedBufferSize", &conf.bufferSize)) continue;
-
- if(the_ownId == nodeId1){
- if(!tmp->get("Node1_NoOfAdapters", &conf.nLocalAdapters)) continue;
- if(!tmp->get("Node2_Adapter", 0, &conf.remoteSciNodeId0)) continue;
-
- if(conf.nLocalAdapters > 1){
- if(!tmp->get("Node2_Adapter", 1, &conf.remoteSciNodeId1)) continue;
- }
- } else {
- if(!tmp->get("Node2_NoOfAdapters", &conf.nLocalAdapters)) continue;
- if(!tmp->get("Node1_Adapter", 0, &conf.remoteSciNodeId0)) continue;
-
- if(conf.nLocalAdapters > 1){
- if(!tmp->get("Node1_Adapter", 1, &conf.remoteSciNodeId1)) continue;
- }
- }
-
- if(!theTransporterRegistry->createTransporter(&conf)){
- ndbout << "Failed to create SCI Transporter from: "
- << conf.localNodeId << " to: " << conf.remoteNodeId << endl;
- continue;
- } else {
- noOfTransportersCreated++;
- continue;
- }
- }
-
- if(!tmp->get("HostName1", &host1)) continue;
- if(!tmp->get("HostName2", &host2)) continue;
-
- Uint32 ownNodeId;
- Uint32 remoteNodeId;
- const char * ownHostName;
- const char * remoteHostName;
-
- if(nodeId1 == the_ownId){
- ownNodeId = nodeId1;
- ownHostName = host1;
- remoteNodeId = nodeId2;
- remoteHostName = host2;
- } else if(nodeId2 == the_ownId){
- ownNodeId = nodeId2;
- ownHostName = host2;
- remoteNodeId = nodeId1;
- remoteHostName = host1;
- } else {
- continue;
- }
-
- if(strcmp("TCP", type) == 0){
- TCP_TransporterConfiguration conf;
-
- if(!tmp->get("PortNumber", &conf.port)) continue;
- if(!tmp->get("SendBufferSize", &conf.sendBufferSize)) continue;
- if(!tmp->get("MaxReceiveSize", &conf.maxReceiveSize)) continue;
-
- const char * proxy;
- if (tmp->get("Proxy", &proxy)) {
- if (strlen(proxy) > 0 && nodeId2 == the_ownId) {
- // TODO handle host:port
- conf.port = atoi(proxy);
- }
- }
- conf.sendBufferSize *= MAX_MESSAGE_SIZE;
- conf.maxReceiveSize *= MAX_MESSAGE_SIZE;
-
- conf.remoteHostName = remoteHostName;
- conf.localHostName = ownHostName;
- conf.remoteNodeId = remoteNodeId;
- conf.localNodeId = ownNodeId;
- conf.checksum = checksum;
- conf.signalId = sendSignalId;
-
- if(!theTransporterRegistry->createTransporter(&conf)){
- ndbout << "Failed to create TCP Transporter from: "
- << ownNodeId << " to: " << remoteNodeId << endl;
- } else {
- noOfTransportersCreated++;
- }
-
- } else if(strcmp("OSE", type) == 0){
-
- OSE_TransporterConfiguration conf;
-
- if(!tmp->get("PrioASignalSize", &conf.prioASignalSize))
- continue;
- if(!tmp->get("PrioBSignalSize", &conf.prioBSignalSize))
- continue;
- if(!tmp->get("ReceiveArraySize", &conf.receiveBufferSize))
- continue;
-
- conf.remoteHostName = remoteHostName;
- conf.localHostName = ownHostName;
- conf.remoteNodeId = remoteNodeId;
- conf.localNodeId = ownNodeId;
- conf.checksum = checksum;
- conf.signalId = sendSignalId;
-
- if(!theTransporterRegistry->createTransporter(&conf)){
- ndbout << "Failed to create OSE Transporter from: "
- << ownNodeId << " to: " << remoteNodeId << endl;
- } else {
- noOfTransportersCreated++;
- }
- } else {
- continue;
- }
- }
- return noOfTransportersCreated;
-}
-
-/**
* Supply a nodeId,
* and get next higher node id
* Returns false if none found
@@ -335,8 +166,39 @@ Uint32
IPCConfig::configureTransporters(Uint32 nodeId,
const class ndb_mgm_configuration & config,
class TransporterRegistry & tr){
+ TransporterConfiguration conf;
+
DBUG_ENTER("IPCConfig::configureTransporters");
+ /**
+ * Iterate over all MGM's an construct a connectstring
+ * create mgm_handle and give it to the Transporter Registry
+ */
+ {
+ const char *separator= "";
+ BaseString connect_string;
+ ndb_mgm_configuration_iterator iter(config, CFG_SECTION_NODE);
+ for(iter.first(); iter.valid(); iter.next())
+ {
+ Uint32 type;
+ if(iter.get(CFG_TYPE_OF_SECTION, &type)) continue;
+ if(type != NODE_TYPE_MGM) continue;
+ const char* hostname;
+ Uint32 port;
+ if(iter.get(CFG_NODE_HOST, &hostname)) continue;
+ if( strlen(hostname) == 0 ) continue;
+ if(iter.get(CFG_MGM_PORT, &port)) continue;
+ connect_string.appfmt("%s%s:port",separator,hostname,port);
+ separator= ",";
+ }
+ NdbMgmHandle h= ndb_mgm_create_handle();
+ if ( h && connect_string.length() > 0 )
+ {
+ ndb_mgm_set_connectstring(h,connect_string.c_str());
+ tr.set_mgm_handle(h);
+ }
+ }
+
Uint32 noOfTransportersCreated= 0;
ndb_mgm_configuration_iterator iter(config, CFG_SECTION_CONNECTION);
@@ -368,32 +230,68 @@ IPCConfig::configureTransporters(Uint32 nodeId,
Uint32 server_port= 0;
if(iter.get(CFG_CONNECTION_SERVER_PORT, &server_port)) break;
- if (nodeId <= nodeId1 && nodeId <= nodeId2) {
- tr.add_transporter_interface(localHostName, server_port);
+
+ /*
+ We check the node type. MGM node becomes server.
+ */
+ Uint32 node1type, node2type;
+ ndb_mgm_configuration_iterator node1iter(config, CFG_SECTION_NODE);
+ ndb_mgm_configuration_iterator node2iter(config, CFG_SECTION_NODE);
+ node1iter.find(CFG_NODE_ID,nodeId1);
+ node2iter.find(CFG_NODE_ID,nodeId2);
+ node1iter.get(CFG_TYPE_OF_SECTION,&node1type);
+ node2iter.get(CFG_TYPE_OF_SECTION,&node2type);
+
+ conf.serverNodeId= (nodeId1 < nodeId2)? nodeId1:nodeId2;
+
+ conf.isMgmConnection= false;
+ if(node2type==NODE_TYPE_MGM)
+ {
+ conf.isMgmConnection= true;
+ conf.serverNodeId= nodeId2;
+ }
+ else if(node1type==NODE_TYPE_MGM)
+ {
+ conf.isMgmConnection= true;
+ conf.serverNodeId= nodeId1;
}
+ else if (nodeId == conf.serverNodeId) {
+ tr.add_transporter_interface(remoteNodeId, localHostName, server_port);
+ }
+
DBUG_PRINT("info", ("Transporter between this node %d and node %d using port %d, signalId %d, checksum %d",
nodeId, remoteNodeId, server_port, sendSignalId, checksum));
+ /*
+ This may be a dynamic port. It depends on when we're getting
+ our configuration. If we've been restarted, we'll be getting
+ a configuration with our old dynamic port in it, hence the number
+ here is negative (and we try the old port number first).
+
+ On a first-run, server_port will be zero (with dynamic ports)
+
+ If we're not using dynamic ports, we don't do anything.
+ */
+ if((int)server_port<0)
+ server_port= -server_port;
+
+ conf.localNodeId = nodeId;
+ conf.remoteNodeId = remoteNodeId;
+ conf.checksum = checksum;
+ conf.signalId = sendSignalId;
+ conf.port = server_port;
+ conf.localHostName = localHostName;
+ conf.remoteHostName = remoteHostName;
+
switch(type){
- case CONNECTION_TYPE_SHM:{
- SHM_TransporterConfiguration conf;
- conf.localNodeId = nodeId;
- conf.remoteNodeId = remoteNodeId;
- conf.checksum = checksum;
- conf.signalId = sendSignalId;
-
- if(iter.get(CFG_SHM_KEY, &conf.shmKey)) break;
- if(iter.get(CFG_SHM_BUFFER_MEM, &conf.shmSize)) break;
- {
- Uint32 tmp;
- if(iter.get(CFG_SHM_SIGNUM, &tmp)) break;
- conf.signum= tmp;
- }
+ case CONNECTION_TYPE_SHM:
+ if(iter.get(CFG_SHM_KEY, &conf.shm.shmKey)) break;
+ if(iter.get(CFG_SHM_BUFFER_MEM, &conf.shm.shmSize)) break;
- conf.port= server_port;
- conf.localHostName = localHostName;
- conf.remoteHostName = remoteHostName;
+ Uint32 tmp;
+ if(iter.get(CFG_SHM_SIGNUM, &tmp)) break;
+ conf.shm.signum= tmp;
- if(!tr.createTransporter(&conf)){
+ if(!tr.createSHMTransporter(&conf)){
DBUG_PRINT("error", ("Failed to create SHM Transporter from %d to %d",
conf.localNodeId, conf.remoteNodeId));
ndbout << "Failed to create SHM Transporter from: "
@@ -401,60 +299,53 @@ IPCConfig::configureTransporters(Uint32 nodeId,
} else {
noOfTransportersCreated++;
}
- DBUG_PRINT("info", ("Created SHM Transporter using shmkey %d, buf size = %d",
- conf.shmKey, conf.shmSize));
+ DBUG_PRINT("info", ("Created SHM Transporter using shmkey %d, "
+ "buf size = %d", conf.shm.shmKey, conf.shm.shmSize));
+
break;
- }
- case CONNECTION_TYPE_SCI:{
- SCI_TransporterConfiguration conf;
- conf.localNodeId = nodeId;
- conf.remoteNodeId = remoteNodeId;
- conf.checksum = checksum;
- conf.signalId = sendSignalId;
- conf.port= server_port;
-
- conf.localHostName = localHostName;
- conf.remoteHostName = remoteHostName;
- if(iter.get(CFG_SCI_SEND_LIMIT, &conf.sendLimit)) break;
- if(iter.get(CFG_SCI_BUFFER_MEM, &conf.bufferSize)) break;
+ case CONNECTION_TYPE_SCI:
+ if(iter.get(CFG_SCI_SEND_LIMIT, &conf.sci.sendLimit)) break;
+ if(iter.get(CFG_SCI_BUFFER_MEM, &conf.sci.bufferSize)) break;
if (nodeId == nodeId1) {
- if(iter.get(CFG_SCI_HOST2_ID_0, &conf.remoteSciNodeId0)) break;
- if(iter.get(CFG_SCI_HOST2_ID_1, &conf.remoteSciNodeId1)) break;
+ if(iter.get(CFG_SCI_HOST2_ID_0, &conf.sci.remoteSciNodeId0)) break;
+ if(iter.get(CFG_SCI_HOST2_ID_1, &conf.sci.remoteSciNodeId1)) break;
} else {
- if(iter.get(CFG_SCI_HOST1_ID_0, &conf.remoteSciNodeId0)) break;
- if(iter.get(CFG_SCI_HOST1_ID_1, &conf.remoteSciNodeId1)) break;
+ if(iter.get(CFG_SCI_HOST1_ID_0, &conf.sci.remoteSciNodeId0)) break;
+ if(iter.get(CFG_SCI_HOST1_ID_1, &conf.sci.remoteSciNodeId1)) break;
}
- if (conf.remoteSciNodeId1 == 0) {
- conf.nLocalAdapters = 1;
+ if (conf.sci.remoteSciNodeId1 == 0) {
+ conf.sci.nLocalAdapters = 1;
} else {
- conf.nLocalAdapters = 2;
+ conf.sci.nLocalAdapters = 2;
}
- if(!tr.createTransporter(&conf)){
+ if(!tr.createSCITransporter(&conf)){
DBUG_PRINT("error", ("Failed to create SCI Transporter from %d to %d",
conf.localNodeId, conf.remoteNodeId));
ndbout << "Failed to create SCI Transporter from: "
<< conf.localNodeId << " to: " << conf.remoteNodeId << endl;
} else {
- DBUG_PRINT("info", ("Created SCI Transporter: Adapters = %d, remote SCI node id %d",
- conf.nLocalAdapters, conf.remoteSciNodeId0));
- DBUG_PRINT("info", ("Host 1 = %s, Host 2 = %s, sendLimit = %d, buf size = %d",
- conf.localHostName, conf.remoteHostName, conf.sendLimit, conf.bufferSize));
- if (conf.nLocalAdapters > 1) {
- DBUG_PRINT("info", ("Fault-tolerant with 2 Remote Adapters, second remote SCI node id = %d",
- conf.remoteSciNodeId1));
+ DBUG_PRINT("info", ("Created SCI Transporter: Adapters = %d, "
+ "remote SCI node id %d",
+ conf.sci.nLocalAdapters, conf.sci.remoteSciNodeId0));
+ DBUG_PRINT("info", ("Host 1 = %s, Host 2 = %s, sendLimit = %d, "
+ "buf size = %d", conf.localHostName,
+ conf.remoteHostName, conf.sci.sendLimit,
+ conf.sci.bufferSize));
+ if (conf.sci.nLocalAdapters > 1) {
+ DBUG_PRINT("info", ("Fault-tolerant with 2 Remote Adapters, "
+ "second remote SCI node id = %d",
+ conf.sci.remoteSciNodeId1));
}
noOfTransportersCreated++;
continue;
}
- }
- case CONNECTION_TYPE_TCP:{
- TCP_TransporterConfiguration conf;
-
- if(iter.get(CFG_TCP_SEND_BUFFER_SIZE, &conf.sendBufferSize)) break;
- if(iter.get(CFG_TCP_RECEIVE_BUFFER_SIZE, &conf.maxReceiveSize)) break;
+ break;
+
+ case CONNECTION_TYPE_TCP:
+ if(iter.get(CFG_TCP_SEND_BUFFER_SIZE, &conf.tcp.sendBufferSize)) break;
+ if(iter.get(CFG_TCP_RECEIVE_BUFFER_SIZE, &conf.tcp.maxReceiveSize)) break;
- conf.port= server_port;
const char * proxy;
if (!iter.get(CFG_TCP_PROXY, &proxy)) {
if (strlen(proxy) > 0 && nodeId2 == nodeId) {
@@ -463,50 +354,35 @@ IPCConfig::configureTransporters(Uint32 nodeId,
}
}
- conf.localNodeId = nodeId;
- conf.remoteNodeId = remoteNodeId;
- conf.localHostName = localHostName;
- conf.remoteHostName = remoteHostName;
- conf.checksum = checksum;
- conf.signalId = sendSignalId;
-
- if(!tr.createTransporter(&conf)){
+ if(!tr.createTCPTransporter(&conf)){
ndbout << "Failed to create TCP Transporter from: "
<< nodeId << " to: " << remoteNodeId << endl;
} else {
noOfTransportersCreated++;
}
- DBUG_PRINT("info", ("Created TCP Transporter: sendBufferSize = %d, maxReceiveSize = %d",
- conf.sendBufferSize, conf.maxReceiveSize));
+ DBUG_PRINT("info", ("Created TCP Transporter: sendBufferSize = %d, "
+ "maxReceiveSize = %d", conf.tcp.sendBufferSize,
+ conf.tcp.maxReceiveSize));
break;
- case CONNECTION_TYPE_OSE:{
- OSE_TransporterConfiguration conf;
-
- if(iter.get(CFG_OSE_PRIO_A_SIZE, &conf.prioASignalSize)) break;
- if(iter.get(CFG_OSE_PRIO_B_SIZE, &conf.prioBSignalSize)) break;
- if(iter.get(CFG_OSE_RECEIVE_ARRAY_SIZE, &conf.receiveBufferSize)) break;
-
- conf.localNodeId = nodeId;
- conf.remoteNodeId = remoteNodeId;
- conf.localHostName = localHostName;
- conf.remoteHostName = remoteHostName;
- conf.checksum = checksum;
- conf.signalId = sendSignalId;
+ case CONNECTION_TYPE_OSE:
+ if(iter.get(CFG_OSE_PRIO_A_SIZE, &conf.ose.prioASignalSize)) break;
+ if(iter.get(CFG_OSE_PRIO_B_SIZE, &conf.ose.prioBSignalSize)) break;
- if(!tr.createTransporter(&conf)){
+ if(!tr.createOSETransporter(&conf)){
ndbout << "Failed to create OSE Transporter from: "
<< nodeId << " to: " << remoteNodeId << endl;
} else {
noOfTransportersCreated++;
}
- }
+ break;
+
default:
ndbout << "Unknown transporter type from: " << nodeId <<
" to: " << remoteNodeId << endl;
break;
- }
- }
- }
+ } // switch
+ } // for
+
DBUG_RETURN(noOfTransportersCreated);
}
diff --git a/ndb/src/common/transporter/Makefile.am b/ndb/src/common/transporter/Makefile.am
index b902012e56d..4c277097a91 100644
--- a/ndb/src/common/transporter/Makefile.am
+++ b/ndb/src/common/transporter/Makefile.am
@@ -13,7 +13,7 @@ EXTRA_libtransporter_la_SOURCES = SHM_Transporter.cpp SHM_Transporter.unix.cpp S
libtransporter_la_LIBADD = @ndb_transporter_opt_objs@
libtransporter_la_DEPENDENCIES = @ndb_transporter_opt_objs@
-INCLUDES_LOC = -I$(top_srcdir)/ndb/include/mgmapi -I$(top_srcdir)/ndb/include/debugger -I$(top_srcdir)/ndb/include/kernel -I$(top_srcdir)/ndb/include/transporter @NDB_SCI_INCLUDES@
+INCLUDES_LOC = -I$(top_srcdir)/ndb/include/mgmapi -I$(top_srcdir)/ndb/src/mgmapi -I$(top_srcdir)/ndb/include/debugger -I$(top_srcdir)/ndb/include/kernel -I$(top_srcdir)/ndb/include/transporter @NDB_SCI_INCLUDES@
include $(top_srcdir)/ndb/config/common.mk.am
include $(top_srcdir)/ndb/config/type_util.mk.am
diff --git a/ndb/src/common/transporter/OSE_Transporter.cpp b/ndb/src/common/transporter/OSE_Transporter.cpp
index a52862a80e5..ad67791fc0c 100644
--- a/ndb/src/common/transporter/OSE_Transporter.cpp
+++ b/ndb/src/common/transporter/OSE_Transporter.cpp
@@ -32,6 +32,7 @@ OSE_Transporter::OSE_Transporter(int _prioASignalSize,
NodeId localNodeId,
const char * lHostName,
NodeId remoteNodeId,
+ NodeId serverNodeId,
const char * rHostName,
int byteorder,
bool compression,
@@ -40,6 +41,7 @@ OSE_Transporter::OSE_Transporter(int _prioASignalSize,
Uint32 reportFreq) :
Transporter(localNodeId,
remoteNodeId,
+ serverNodeId,
byteorder,
compression,
checksum,
diff --git a/ndb/src/common/transporter/OSE_Transporter.hpp b/ndb/src/common/transporter/OSE_Transporter.hpp
index 4fd06130477..898352366ba 100644
--- a/ndb/src/common/transporter/OSE_Transporter.hpp
+++ b/ndb/src/common/transporter/OSE_Transporter.hpp
@@ -48,6 +48,7 @@ public:
NodeId localNodeId,
const char * lHostName,
NodeId remoteNodeId,
+ NodeId serverNodeId,
const char * rHostName,
int byteorder,
bool compression,
diff --git a/ndb/src/common/transporter/SCI_Transporter.cpp b/ndb/src/common/transporter/SCI_Transporter.cpp
index e7807c972b1..506140a887f 100644
--- a/ndb/src/common/transporter/SCI_Transporter.cpp
+++ b/ndb/src/common/transporter/SCI_Transporter.cpp
@@ -34,19 +34,21 @@ SCI_Transporter::SCI_Transporter(TransporterRegistry &t_reg,
const char *lHostName,
const char *rHostName,
int r_port,
+ bool isMgmConnection,
Uint32 packetSize,
Uint32 bufferSize,
Uint32 nAdapters,
Uint16 remoteSciNodeId0,
Uint16 remoteSciNodeId1,
NodeId _localNodeId,
- NodeId _remoteNodeId,
+ NodeId _remoteNodeId,
+ NodeId serverNodeId,
bool chksm,
bool signalId,
Uint32 reportFreq) :
Transporter(t_reg, tt_SCI_TRANSPORTER,
- lHostName, rHostName, r_port, _localNodeId,
- _remoteNodeId, 0, false, chksm, signalId)
+ lHostName, rHostName, r_port, isMgmConnection, _localNodeId,
+ _remoteNodeId, serverNodeID, 0, false, chksm, signalId)
{
DBUG_ENTER("SCI_Transporter::SCI_Transporter");
m_PacketSize = (packetSize + 3)/4 ;
diff --git a/ndb/src/common/transporter/SCI_Transporter.hpp b/ndb/src/common/transporter/SCI_Transporter.hpp
index e2f2dfcaf99..8d263f32a57 100644
--- a/ndb/src/common/transporter/SCI_Transporter.hpp
+++ b/ndb/src/common/transporter/SCI_Transporter.hpp
@@ -139,13 +139,15 @@ private:
const char *local_host,
const char *remote_host,
int port,
+ bool isMgmConnection,
Uint32 packetSize,
Uint32 bufferSize,
Uint32 nAdapters,
Uint16 remoteSciNodeId0,
Uint16 remoteSciNodeId1,
NodeId localNodeID,
- NodeId remoteNodeID,
+ NodeId remoteNodeID,
+ NodeId serverNodeId,
bool checksum,
bool signalId,
Uint32 reportFreq = 4096);
diff --git a/ndb/src/common/transporter/SHM_Transporter.cpp b/ndb/src/common/transporter/SHM_Transporter.cpp
index eed3ad77be6..e2d23cf94e2 100644
--- a/ndb/src/common/transporter/SHM_Transporter.cpp
+++ b/ndb/src/common/transporter/SHM_Transporter.cpp
@@ -32,14 +32,17 @@ SHM_Transporter::SHM_Transporter(TransporterRegistry &t_reg,
const char *lHostName,
const char *rHostName,
int r_port,
+ bool isMgmConnection,
NodeId lNodeId,
- NodeId rNodeId,
+ NodeId rNodeId,
+ NodeId serverNodeId,
bool checksum,
bool signalId,
key_t _shmKey,
Uint32 _shmSize) :
Transporter(t_reg, tt_SHM_TRANSPORTER,
- lHostName, rHostName, r_port, lNodeId, rNodeId,
+ lHostName, rHostName, r_port, isMgmConnection,
+ lNodeId, rNodeId, serverNodeId,
0, false, checksum, signalId),
shmKey(_shmKey),
shmSize(_shmSize)
diff --git a/ndb/src/common/transporter/SHM_Transporter.hpp b/ndb/src/common/transporter/SHM_Transporter.hpp
index b501f652168..677bd6efc37 100644
--- a/ndb/src/common/transporter/SHM_Transporter.hpp
+++ b/ndb/src/common/transporter/SHM_Transporter.hpp
@@ -36,8 +36,10 @@ public:
const char *lHostName,
const char *rHostName,
int r_port,
+ bool isMgmConnection,
NodeId lNodeId,
- NodeId rNodeId,
+ NodeId rNodeId,
+ NodeId serverNodeId,
bool checksum,
bool signalId,
key_t shmKey,
diff --git a/ndb/src/common/transporter/TCP_Transporter.cpp b/ndb/src/common/transporter/TCP_Transporter.cpp
index a629b620157..fd71cf71cd9 100644
--- a/ndb/src/common/transporter/TCP_Transporter.cpp
+++ b/ndb/src/common/transporter/TCP_Transporter.cpp
@@ -68,12 +68,15 @@ TCP_Transporter::TCP_Transporter(TransporterRegistry &t_reg,
const char *lHostName,
const char *rHostName,
int r_port,
+ bool isMgmConnection,
NodeId lNodeId,
NodeId rNodeId,
+ NodeId serverNodeId,
bool chksm, bool signalId,
Uint32 _reportFreq) :
Transporter(t_reg, tt_TCP_TRANSPORTER,
- lHostName, rHostName, r_port, lNodeId, rNodeId,
+ lHostName, rHostName, r_port, isMgmConnection,
+ lNodeId, rNodeId, serverNodeId,
0, false, chksm, signalId),
m_sendBuffer(sendBufSize)
{
diff --git a/ndb/src/common/transporter/TCP_Transporter.hpp b/ndb/src/common/transporter/TCP_Transporter.hpp
index 48046310bf8..9cd174150c1 100644
--- a/ndb/src/common/transporter/TCP_Transporter.hpp
+++ b/ndb/src/common/transporter/TCP_Transporter.hpp
@@ -49,9 +49,11 @@ private:
int sendBufferSize, int maxReceiveSize,
const char *lHostName,
const char *rHostName,
- int r_port,
+ int r_port,
+ bool isMgmConnection,
NodeId lHostId,
NodeId rHostId,
+ NodeId serverNodeId,
bool checksum, bool signalId,
Uint32 reportFreq = 4096);
diff --git a/ndb/src/common/transporter/Transporter.cpp b/ndb/src/common/transporter/Transporter.cpp
index b84f8f6fb5e..124ed5f7241 100644
--- a/ndb/src/common/transporter/Transporter.cpp
+++ b/ndb/src/common/transporter/Transporter.cpp
@@ -31,13 +31,15 @@ Transporter::Transporter(TransporterRegistry &t_reg,
TransporterType _type,
const char *lHostName,
const char *rHostName,
- int r_port,
+ int s_port,
+ bool _isMgmConnection,
NodeId lNodeId,
- NodeId rNodeId,
+ NodeId rNodeId,
+ NodeId serverNodeId,
int _byteorder,
bool _compression, bool _checksum, bool _signalId)
- : m_r_port(r_port), remoteNodeId(rNodeId), localNodeId(lNodeId),
- isServer(lNodeId < rNodeId),
+ : m_s_port(s_port), remoteNodeId(rNodeId), localNodeId(lNodeId),
+ isServer(lNodeId==serverNodeId), isMgmConnection(_isMgmConnection),
m_packer(_signalId, _checksum),
m_type(_type),
m_transporter_registry(t_reg)
@@ -61,10 +63,10 @@ Transporter::Transporter(TransporterRegistry &t_reg,
if (strlen(lHostName) > 0)
Ndb_getInAddr(&localHostAddress, lHostName);
- DBUG_PRINT("info",("rId=%d lId=%d isServer=%d rHost=%s lHost=%s r_port=%d",
+ DBUG_PRINT("info",("rId=%d lId=%d isServer=%d rHost=%s lHost=%s s_port=%d",
remoteNodeId, localNodeId, isServer,
remoteHostName, localHostName,
- r_port));
+ s_port));
byteOrder = _byteorder;
compressionUsed = _compression;
@@ -74,10 +76,13 @@ Transporter::Transporter(TransporterRegistry &t_reg,
m_connected = false;
m_timeOutMillis = 1000;
+ if(s_port<0)
+ s_port= -s_port; // was dynamic
+
if (isServer)
m_socket_client= 0;
else
- m_socket_client= new SocketClient(remoteHostName, r_port,
+ m_socket_client= new SocketClient(remoteHostName, s_port,
new SocketAuthSimple("ndbd",
"ndbd passwd"));
DBUG_VOID_RETURN;
@@ -109,22 +114,42 @@ Transporter::connect_server(NDB_SOCKET_TYPE sockfd) {
bool
Transporter::connect_client() {
+ NDB_SOCKET_TYPE sockfd;
+
if(m_connected)
return true;
- NDB_SOCKET_TYPE sockfd = m_socket_client->connect();
-
+
+ if(isMgmConnection)
+ sockfd= m_transporter_registry.connect_ndb_mgmd(m_socket_client);
+ else
+ sockfd= m_socket_client->connect();
+
+ return connect_client(sockfd);
+}
+
+bool
+Transporter::connect_client(NDB_SOCKET_TYPE sockfd) {
+
+ if(m_connected)
+ return true;
+
if (sockfd == NDB_INVALID_SOCKET)
return false;
DBUG_ENTER("Transporter::connect_client");
+ DBUG_PRINT("info",("port %d isMgmConnection=%d",m_s_port,isMgmConnection));
+
+ SocketOutputStream s_output(sockfd);
+ SocketInputStream s_input(sockfd);
+
// send info about own id
// send info about own transporter type
- SocketOutputStream s_output(sockfd);
+
s_output.println("%d %d", localNodeId, m_type);
// get remote id
int nodeId, remote_transporter_type= -1;
- SocketInputStream s_input(sockfd);
+
char buf[256];
if (s_input.gets(buf, 256) == 0) {
NDB_CLOSE_SOCKET(sockfd);
diff --git a/ndb/src/common/transporter/Transporter.hpp b/ndb/src/common/transporter/Transporter.hpp
index baff6d53dd8..53414f1179d 100644
--- a/ndb/src/common/transporter/Transporter.hpp
+++ b/ndb/src/common/transporter/Transporter.hpp
@@ -44,6 +44,7 @@ public:
* Use isConnected() to check status
*/
bool connect_client();
+ bool connect_client(NDB_SOCKET_TYPE sockfd);
bool connect_server(NDB_SOCKET_TYPE socket);
/**
@@ -69,14 +70,32 @@ public:
*/
NodeId getLocalNodeId() const;
+ /**
+ * Get port we're connecting to (signed)
+ */
+ int get_s_port() { return m_s_port; };
+
+ /**
+ * Set port to connect to (signed)
+ */
+ void set_s_port(int port) {
+ m_s_port = port;
+ if(port<0)
+ port= -port;
+ if(m_socket_client)
+ m_socket_client->set_port(port);
+ };
+
protected:
Transporter(TransporterRegistry &,
TransporterType,
const char *lHostName,
const char *rHostName,
- int r_port,
+ int s_port,
+ bool isMgmConnection,
NodeId lNodeId,
- NodeId rNodeId,
+ NodeId rNodeId,
+ NodeId serverNodeId,
int byteorder,
bool compression,
bool checksum,
@@ -102,7 +121,7 @@ protected:
struct in_addr remoteHostAddress;
struct in_addr localHostAddress;
- const unsigned int m_r_port;
+ int m_s_port;
const NodeId remoteNodeId;
const NodeId localNodeId;
@@ -119,6 +138,12 @@ protected:
private:
+ /**
+ * means that we transform an MGM connection into
+ * a transporter connection
+ */
+ bool isMgmConnection;
+
SocketClient *m_socket_client;
protected:
diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp
index 439730435ec..f331b1660c1 100644
--- a/ndb/src/common/transporter/TransporterRegistry.cpp
+++ b/ndb/src/common/transporter/TransporterRegistry.cpp
@@ -48,6 +48,10 @@ extern int g_ndb_shm_signum;
#include <InputStream.hpp>
#include <OutputStream.hpp>
+#include <mgmapi/mgmapi.h>
+#include <mgmapi_internal.h>
+#include <mgmapi/mgmapi_debug.h>
+
#include <EventLogger.hpp>
extern EventLogger g_eventLogger;
@@ -75,6 +79,7 @@ TransporterRegistry::TransporterRegistry(void * callback,
nodeIdSpecified = false;
maxTransporters = _maxTransporters;
sendCounter = 1;
+ m_mgm_handle= 0;
callbackObj=callback;
@@ -109,6 +114,27 @@ TransporterRegistry::TransporterRegistry(void * callback,
theOSEJunkSocketRecv = 0;
}
+void TransporterRegistry::set_mgm_handle(NdbMgmHandle h)
+{
+ DBUG_ENTER("TransporterRegistry::set_mgm_handle");
+ if (m_mgm_handle)
+ ndb_mgm_destroy_handle(&m_mgm_handle);
+ m_mgm_handle= h;
+#ifndef DBUG_OFF
+ if (h)
+ {
+ char buf[256];
+ DBUG_PRINT("info",("handle set with connectstring: %s",
+ ndb_mgm_get_connectstring(h,buf, sizeof(buf))));
+ }
+ else
+ {
+ DBUG_PRINT("info",("handle set to NULL"));
+ }
+#endif
+ DBUG_VOID_RETURN;
+}
+
TransporterRegistry::~TransporterRegistry() {
removeAll();
@@ -129,6 +155,8 @@ TransporterRegistry::~TransporterRegistry() {
theOSEReceiver = 0;
}
#endif
+ if (m_mgm_handle)
+ ndb_mgm_destroy_handle(&m_mgm_handle);
}
void
@@ -244,7 +272,7 @@ TransporterRegistry::connect_server(NDB_SOCKET_TYPE sockfd)
}
bool
-TransporterRegistry::createTransporter(TCP_TransporterConfiguration *config) {
+TransporterRegistry::createTCPTransporter(TransporterConfiguration *config) {
#ifdef NDB_TCP_TRANSPORTER
if(!nodeIdSpecified){
@@ -258,13 +286,15 @@ TransporterRegistry::createTransporter(TCP_TransporterConfiguration *config) {
return false;
TCP_Transporter * t = new TCP_Transporter(*this,
- config->sendBufferSize,
- config->maxReceiveSize,
+ config->tcp.sendBufferSize,
+ config->tcp.maxReceiveSize,
config->localHostName,
config->remoteHostName,
config->port,
+ config->isMgmConnection,
localNodeId,
config->remoteNodeId,
+ config->serverNodeId,
config->checksum,
config->signalId);
if (t == NULL)
@@ -293,7 +323,7 @@ TransporterRegistry::createTransporter(TCP_TransporterConfiguration *config) {
}
bool
-TransporterRegistry::createTransporter(OSE_TransporterConfiguration *conf) {
+TransporterRegistry::createOSETransporter(TransporterConfiguration *conf) {
#ifdef NDB_OSE_TRANSPORTER
if(!nodeIdSpecified){
@@ -312,11 +342,12 @@ TransporterRegistry::createTransporter(OSE_TransporterConfiguration *conf) {
localNodeId);
}
- OSE_Transporter * t = new OSE_Transporter(conf->prioASignalSize,
- conf->prioBSignalSize,
+ OSE_Transporter * t = new OSE_Transporter(conf->ose.prioASignalSize,
+ conf->ose.prioBSignalSize,
localNodeId,
conf->localHostName,
conf->remoteNodeId,
+ conf->serverNodeId,
conf->remoteHostName,
conf->checksum,
conf->signalId);
@@ -342,7 +373,7 @@ TransporterRegistry::createTransporter(OSE_TransporterConfiguration *conf) {
}
bool
-TransporterRegistry::createTransporter(SCI_TransporterConfiguration *config) {
+TransporterRegistry::createSCITransporter(TransporterConfiguration *config) {
#ifdef NDB_SCI_TRANSPORTER
if(!SCI_Transporter::initSCI())
@@ -362,13 +393,15 @@ TransporterRegistry::createTransporter(SCI_TransporterConfiguration *config) {
config->localHostName,
config->remoteHostName,
config->port,
- config->sendLimit,
- config->bufferSize,
- config->nLocalAdapters,
- config->remoteSciNodeId0,
- config->remoteSciNodeId1,
+ config->isMgmConnection,
+ config->sci.sendLimit,
+ config->sci.bufferSize,
+ config->sci.nLocalAdapters,
+ config->sci.remoteSciNodeId0,
+ config->sci.remoteSciNodeId1,
localNodeId,
config->remoteNodeId,
+ config->serverNodeId,
config->checksum,
config->signalId);
@@ -393,7 +426,7 @@ TransporterRegistry::createTransporter(SCI_TransporterConfiguration *config) {
}
bool
-TransporterRegistry::createTransporter(SHM_TransporterConfiguration *config) {
+TransporterRegistry::createSHMTransporter(TransporterConfiguration *config) {
DBUG_ENTER("TransporterRegistry::createTransporter SHM");
#ifdef NDB_SHM_TRANSPORTER
if(!nodeIdSpecified){
@@ -404,7 +437,7 @@ TransporterRegistry::createTransporter(SHM_TransporterConfiguration *config) {
return false;
if (!g_ndb_shm_signum) {
- g_ndb_shm_signum= config->signum;
+ g_ndb_shm_signum= config->shm.signum;
DBUG_PRINT("info",("Block signum %d",g_ndb_shm_signum));
/**
* Make sure to block g_ndb_shm_signum
@@ -416,7 +449,7 @@ TransporterRegistry::createTransporter(SHM_TransporterConfiguration *config) {
pthread_sigmask(SIG_BLOCK, &mask, 0);
}
- if(config->signum != g_ndb_shm_signum)
+ if(config->shm.signum != g_ndb_shm_signum)
return false;
if(theTransporters[config->remoteNodeId] != NULL)
@@ -426,12 +459,14 @@ TransporterRegistry::createTransporter(SHM_TransporterConfiguration *config) {
config->localHostName,
config->remoteHostName,
config->port,
+ config->isMgmConnection,
localNodeId,
config->remoteNodeId,
+ config->serverNodeId,
config->checksum,
config->signalId,
- config->shmKey,
- config->shmSize
+ config->shm.shmKey,
+ config->shm.shmSize
);
if (t == NULL)
return false;
@@ -1198,8 +1233,61 @@ TransporterRegistry::start_clients_thread()
const NodeId nodeId = t->getRemoteNodeId();
switch(performStates[nodeId]){
case CONNECTING:
- if(!t->isConnected() && !t->isServer)
- t->connect_client();
+ if(!t->isConnected() && !t->isServer) {
+ bool connected= false;
+ /**
+ * First, we try to connect (if we have a port number).
+ */
+ if (t->get_s_port())
+ connected= t->connect_client();
+
+ /**
+ * If dynamic, get the port for connecting from the management server
+ */
+ if( !connected && t->get_s_port() <= 0) { // Port is dynamic
+ int server_port= 0;
+ struct ndb_mgm_reply mgm_reply;
+
+ if(!ndb_mgm_is_connected(m_mgm_handle))
+ ndb_mgm_connect(m_mgm_handle, 0, 0, 0);
+
+ if(ndb_mgm_is_connected(m_mgm_handle))
+ {
+ int res=
+ ndb_mgm_get_connection_int_parameter(m_mgm_handle,
+ t->getRemoteNodeId(),
+ t->getLocalNodeId(),
+ CFG_CONNECTION_SERVER_PORT,
+ &server_port,
+ &mgm_reply);
+ DBUG_PRINT("info",("Got dynamic port %d for %d -> %d (ret: %d)",
+ server_port,t->getRemoteNodeId(),
+ t->getLocalNodeId(),res));
+ if( res >= 0 )
+ {
+ /**
+ * Server_port == 0 just means that that a mgmt server
+ * has not received a new port yet. Keep the old.
+ */
+ if (server_port)
+ t->set_s_port(server_port);
+ }
+ else
+ {
+ ndbout_c("Failed to get dynamic port to connect to: %d", res);
+ ndb_mgm_disconnect(m_mgm_handle);
+ }
+ }
+ /** else
+ * We will not be able to get a new port unless
+ * the m_mgm_handle is connected. Note that not
+ * being connected is an ok state, just continue
+ * until it is able to connect. Continue using the
+ * old port until we can connect again and get a
+ * new port.
+ */
+ }
+ }
break;
case DISCONNECTING:
if(t->isConnected())
@@ -1235,24 +1323,26 @@ TransporterRegistry::stop_clients()
if (m_start_clients_thread) {
m_run_start_clients_thread= false;
void* status;
- int r= NdbThread_WaitFor(m_start_clients_thread, &status);
+ NdbThread_WaitFor(m_start_clients_thread, &status);
NdbThread_Destroy(&m_start_clients_thread);
}
return true;
}
void
-TransporterRegistry::add_transporter_interface(const char *interf, unsigned short port)
+TransporterRegistry::add_transporter_interface(NodeId remoteNodeId,
+ const char *interf,
+ int s_port)
{
DBUG_ENTER("TransporterRegistry::add_transporter_interface");
- DBUG_PRINT("enter",("interface=%s, port= %d", interf, port));
+ DBUG_PRINT("enter",("interface=%s, s_port= %d", interf, s_port));
if (interf && strlen(interf) == 0)
interf= 0;
for (unsigned i= 0; i < m_transporter_interface.size(); i++)
{
Transporter_interface &tmp= m_transporter_interface[i];
- if (port != tmp.m_service_port)
+ if (s_port != tmp.m_s_service_port || tmp.m_s_service_port==0)
continue;
if (interf != 0 && tmp.m_interface != 0 &&
strcmp(interf, tmp.m_interface) == 0)
@@ -1265,7 +1355,8 @@ TransporterRegistry::add_transporter_interface(const char *interf, unsigned shor
}
}
Transporter_interface t;
- t.m_service_port= port;
+ t.m_remote_nodeId= remoteNodeId;
+ t.m_s_service_port= s_port;
t.m_interface= interf;
m_transporter_interface.push_back(t);
DBUG_PRINT("exit",("interface and port added"));
@@ -1275,34 +1366,50 @@ TransporterRegistry::add_transporter_interface(const char *interf, unsigned shor
bool
TransporterRegistry::start_service(SocketServer& socket_server)
{
+ struct ndb_mgm_reply mgm_reply;
+
+ DBUG_ENTER("TransporterRegistry::start_service");
if (m_transporter_interface.size() > 0 && !nodeIdSpecified)
{
ndbout_c("TransporterRegistry::startReceiving: localNodeId not specified");
- return false;
+ DBUG_RETURN(false);
}
for (unsigned i= 0; i < m_transporter_interface.size(); i++)
{
Transporter_interface &t= m_transporter_interface[i];
- if (t.m_service_port == 0)
- {
- continue;
- }
+
+ unsigned short port= (unsigned short)t.m_s_service_port;
+ if(t.m_s_service_port<0)
+ port= -t.m_s_service_port; // is a dynamic port
TransporterService *transporter_service =
new TransporterService(new SocketAuthSimple("ndbd", "ndbd passwd"));
if(!socket_server.setup(transporter_service,
- t.m_service_port, t.m_interface))
+ &port, t.m_interface))
{
- ndbout_c("Unable to setup transporter service port: %s:%d!\n"
- "Please check if the port is already used,\n"
- "(perhaps the node is already running)",
- t.m_interface ? t.m_interface : "*", t.m_service_port);
- delete transporter_service;
- return false;
+ DBUG_PRINT("info", ("Trying new port"));
+ port= 0;
+ if(t.m_s_service_port>0
+ || !socket_server.setup(transporter_service,
+ &port, t.m_interface))
+ {
+ /*
+ * If it wasn't a dynamically allocated port, or
+ * our attempts at getting a new dynamic port failed
+ */
+ ndbout_c("Unable to setup transporter service port: %s:%d!\n"
+ "Please check if the port is already used,\n"
+ "(perhaps the node is already running)",
+ t.m_interface ? t.m_interface : "*", t.m_s_service_port);
+ delete transporter_service;
+ DBUG_RETURN(false);
+ }
}
+ t.m_s_service_port= (t.m_s_service_port<=0)?-port:port; // -`ve if dynamic
+ DBUG_PRINT("info", ("t.m_s_service_port = %d",t.m_s_service_port));
transporter_service->setTransporterRegistry(this);
}
- return true;
+ DBUG_RETURN(true);
}
#ifdef NDB_SHM_TRANSPORTER
@@ -1354,12 +1461,7 @@ TransporterRegistry::startReceiving()
DBUG_PRINT("error",("Install failed"));
g_eventLogger.error("Failed to install signal handler for"
" SHM transporter errno: %d (%s)", errno,
-#ifdef HAVE_STRERROR
- strerror(errno)
-#else
- ""
-#endif
- );
+ strerror(errno));
}
}
#endif // NDB_SHM_TRANSPORTER
@@ -1417,4 +1519,107 @@ NdbOut & operator <<(NdbOut & out, SignalHeader & sh){
return out;
}
+Transporter*
+TransporterRegistry::get_transporter(NodeId nodeId) {
+ return theTransporters[nodeId];
+}
+
+bool TransporterRegistry::connect_client(NdbMgmHandle *h)
+{
+ DBUG_ENTER("TransporterRegistry::connect_client(NdbMgmHandle)");
+
+ Uint32 mgm_nodeid= ndb_mgm_get_mgmd_nodeid(*h);
+
+ if(!mgm_nodeid)
+ {
+ ndbout_c("%s: %d", __FILE__, __LINE__);
+ return false;
+ }
+ Transporter * t = theTransporters[mgm_nodeid];
+ if (!t)
+ {
+ ndbout_c("%s: %d", __FILE__, __LINE__);
+ return false;
+ }
+ DBUG_RETURN(t->connect_client(connect_ndb_mgmd(h)));
+}
+
+/**
+ * Given a connected NdbMgmHandle, turns it into a transporter
+ * and returns the socket.
+ */
+NDB_SOCKET_TYPE TransporterRegistry::connect_ndb_mgmd(NdbMgmHandle *h)
+{
+ struct ndb_mgm_reply mgm_reply;
+
+ if ( h==NULL || *h == NULL )
+ {
+ ndbout_c("%s: %d", __FILE__, __LINE__);
+ return NDB_INVALID_SOCKET;
+ }
+
+ for(unsigned int i=0;i < m_transporter_interface.size();i++)
+ if (m_transporter_interface[i].m_s_service_port < 0
+ && ndb_mgm_set_connection_int_parameter(*h,
+ get_localNodeId(),
+ m_transporter_interface[i].m_remote_nodeId,
+ CFG_CONNECTION_SERVER_PORT,
+ m_transporter_interface[i].m_s_service_port,
+ &mgm_reply) < 0)
+ {
+ ndbout_c("Error: %s: %d",
+ ndb_mgm_get_latest_error_desc(*h),
+ ndb_mgm_get_latest_error(*h));
+ ndbout_c("%s: %d", __FILE__, __LINE__);
+ ndb_mgm_destroy_handle(h);
+ return NDB_INVALID_SOCKET;
+ }
+
+ /**
+ * convert_to_transporter also disposes of the handle (i.e. we don't leak
+ * memory here.
+ */
+ NDB_SOCKET_TYPE sockfd= ndb_mgm_convert_to_transporter(h);
+ if ( sockfd == NDB_INVALID_SOCKET)
+ {
+ ndbout_c("Error: %s: %d",
+ ndb_mgm_get_latest_error_desc(*h),
+ ndb_mgm_get_latest_error(*h));
+ ndbout_c("%s: %d", __FILE__, __LINE__);
+ ndb_mgm_destroy_handle(h);
+ }
+ return sockfd;
+}
+
+/**
+ * Given a SocketClient, creates a NdbMgmHandle, turns it into a transporter
+ * and returns the socket.
+ */
+NDB_SOCKET_TYPE TransporterRegistry::connect_ndb_mgmd(SocketClient *sc)
+{
+ NdbMgmHandle h= ndb_mgm_create_handle();
+
+ if ( h == NULL )
+ {
+ return NDB_INVALID_SOCKET;
+ }
+
+ /**
+ * Set connectstring
+ */
+ {
+ BaseString cs;
+ cs.assfmt("%s:%u",sc->get_server_name(),sc->get_port());
+ ndb_mgm_set_connectstring(h, cs.c_str());
+ }
+
+ if(ndb_mgm_connect(h, 0, 0, 0)<0)
+ {
+ ndb_mgm_destroy_handle(&h);
+ return NDB_INVALID_SOCKET;
+ }
+
+ return connect_ndb_mgmd(&h);
+}
+
template class Vector<TransporterRegistry::Transporter_interface>;
diff --git a/ndb/src/common/util/Base64.cpp b/ndb/src/common/util/Base64.cpp
index f7a490d427d..3db911f481f 100644
--- a/ndb/src/common/util/Base64.cpp
+++ b/ndb/src/common/util/Base64.cpp
@@ -22,17 +22,22 @@ static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789+/";
int
-base64_encode(const UtilBuffer &src, BaseString &dst) {
- const unsigned char *s = (const unsigned char *)src.get_data();
+base64_encode(const UtilBuffer &src, BaseString &dst)
+{
+ return base64_encode(src.get_data(), src.length(), dst);
+}
+
+int
+base64_encode(const void * _s, size_t src_len, BaseString &dst) {
+ const unsigned char * s = (const unsigned char*)_s;
size_t i = 0;
size_t len = 0;
- size_t src_len = src.length();
while(i < src_len) {
if(len == 76){
len = 0;
dst.append('\n');
}
-
+
unsigned c;
c = s[i++];
c <<= 8;
diff --git a/ndb/src/common/util/Bitmask.cpp b/ndb/src/common/util/Bitmask.cpp
new file mode 100644
index 00000000000..0aa39a37204
--- /dev/null
+++ b/ndb/src/common/util/Bitmask.cpp
@@ -0,0 +1,351 @@
+#include <Bitmask.hpp>
+#include <NdbOut.hpp>
+
+static
+void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
+{
+ printf("b'");
+ for(unsigned i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
+ printf("1");
+ else
+ printf("0");
+ if((i & 31) == 31)
+ printf(" ");
+ }
+}
+
+#ifndef __TEST_BITMASK__
+
+void
+BitmaskImpl::getFieldImpl(const Uint32 src[],
+ unsigned shiftL, unsigned len, Uint32 dst[])
+{
+ assert(shiftL < 32);
+
+ unsigned shiftR = 32 - shiftL;
+ unsigned undefined = shiftL ? ~0 : 0;
+
+ * dst = shiftL ? * dst : 0;
+
+ while(len >= 32)
+ {
+ * dst++ |= (* src) << shiftL;
+ * dst = ((* src++) >> shiftR) & undefined;
+ len -= 32;
+ }
+
+ if(len < shiftR)
+ {
+ * dst |= ((* src) & ((1 << len) - 1)) << shiftL;
+ }
+ else
+ {
+ * dst++ |= ((* src) << shiftL);
+ * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined;
+ }
+}
+
+void
+BitmaskImpl::setFieldImpl(Uint32 dst[],
+ unsigned shiftL, unsigned len, const Uint32 src[])
+{
+ /**
+ *
+ * abcd ef00
+ * 00ab cdef
+ */
+ assert(shiftL < 32);
+ unsigned shiftR = 32 - shiftL;
+ unsigned undefined = shiftL ? ~0 : 0;
+ while(len >= 32)
+ {
+ * dst = (* src++) >> shiftL;
+ * dst++ |= ((* src) << shiftR) & undefined;
+ len -= 32;
+ }
+
+ Uint32 mask = ((1 << len) -1);
+ * dst = (* dst & ~mask);
+ if(len < shiftR)
+ {
+ * dst |= ((* src++) >> shiftL) & mask;
+ }
+ else
+ {
+ * dst |= ((* src++) >> shiftL);
+ * dst |= ((* src) & ((1 << (len - shiftR)) - 1)) << shiftR ;
+ }
+}
+#else
+
+#define DEBUG 0
+#include <Vector.hpp>
+static void do_test(int bitmask_size);
+
+int
+main(int argc, char** argv)
+{
+ int loops = argc > 1 ? atoi(argv[1]) : 1000;
+ int max_size = argc > 2 ? atoi(argv[2]) : 1000;
+
+
+ for(int i = 0; i<loops; i++)
+ do_test(1 + (rand() % max_size));
+}
+
+struct Alloc
+{
+ Uint32 pos;
+ Uint32 size;
+ Vector<Uint32> data;
+};
+
+static void require(bool b)
+{
+ if(!b) abort();
+}
+
+static
+bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
+{
+ Uint32 sz32 = (len + 31) >> 5;
+ for(int i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
+ return false;
+ }
+ return true;
+}
+
+
+static int val_pos = 0;
+static int val[] = { 384, 241, 32,
+ 1,1,1,1, 0,0,0,0, 1,1,1,1, 0,0,0,0,
+ 241 };
+
+static int lrand()
+{
+#if 0
+ return val[val_pos++];
+#else
+ return rand();
+#endif
+}
+
+static
+void rand(Uint32 dst[], Uint32 len)
+{
+ for(int i = 0; i<len; i++)
+ BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
+}
+
+static
+void simple(int pos, int size)
+{
+ ndbout_c("simple pos: %d size: %d", pos, size);
+ Vector<Uint32> _mask;
+ Vector<Uint32> _src;
+ Vector<Uint32> _dst;
+ Uint32 sz32 = (size + pos + 32) >> 5;
+ const Uint32 sz = 4 * sz32;
+
+ Uint32 zero = 0;
+ _mask.fill(sz32+1, zero);
+ _src.fill(sz32+1, zero);
+ _dst.fill(sz32+1, zero);
+
+ Uint32 * src = _src.getBase();
+ Uint32 * dst = _dst.getBase();
+ Uint32 * mask = _mask.getBase();
+
+ memset(src, 0x0, sz);
+ memset(dst, 0x0, sz);
+ memset(mask, 0xFF, sz);
+ rand(src, size);
+ BitmaskImpl::setField(sz32, mask, pos, size, src);
+ BitmaskImpl::getField(sz32, mask, pos, size, dst);
+ printf("src: "); print(src, size+31); printf("\n");
+ printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
+ printf("dst: "); print(dst, size+31); printf("\n");
+ require(cmp(src, dst, size+31));
+};
+
+static
+void simple2(int size, int loops)
+{
+ ndbout_c("simple2 %d - ", size);
+ Vector<Uint32> _mask;
+ Vector<Uint32> _src;
+ Vector<Uint32> _dst;
+
+ Uint32 sz32 = (size + 32) >> 5;
+ Uint32 sz = sz32 << 2;
+
+ Uint32 zero = 0;
+ _mask.fill(sz32+1, zero);
+ _src.fill(sz32+1, zero);
+ _dst.fill(sz32+1, zero);
+
+ Uint32 * src = _src.getBase();
+ Uint32 * dst = _dst.getBase();
+ Uint32 * mask = _mask.getBase();
+
+ Vector<Uint32> save;
+ for(int i = 0; i<loops; i++)
+ {
+ memset(mask, 0xFF, sz);
+ memset(dst, 0xFF, sz);
+ int len;
+ int pos = 0;
+ while(pos+1 < size)
+ {
+ memset(src, 0xFF, sz);
+ while(!(len = rand() % (size - pos)));
+ BitmaskImpl::setField(sz32, mask, pos, len, src);
+ if(memcmp(dst, mask, sz))
+ {
+ ndbout_c("pos: %d len: %d", pos, len);
+ print(mask, size);
+ abort();
+ }
+ printf("[ %d %d ]", pos, len);
+ save.push_back(pos);
+ save.push_back(len);
+ pos += len;
+ }
+
+ for(int j = 0; j<save.size(); )
+ {
+ pos = save[j++];
+ len = save[j++];
+ memset(src, 0xFF, sz);
+ BitmaskImpl::getField(sz32, mask, pos, len, src);
+ if(memcmp(dst, src, sz))
+ {
+ ndbout_c("pos: %d len: %d", pos, len);
+ printf("src: "); print(src, size); printf("\n");
+ printf("dst: "); print(dst, size); printf("\n");
+ printf("msk: "); print(mask, size); printf("\n");
+ abort();
+ }
+ }
+ ndbout_c("");
+ }
+}
+
+static void
+do_test(int bitmask_size)
+{
+#if 1
+ simple(rand() % 33, (rand() % 63)+1);
+//#else
+ Vector<Alloc> alloc_list;
+ bitmask_size = (bitmask_size + 31) & ~31;
+ Uint32 sz32 = (bitmask_size >> 5);
+ Vector<Uint32> alloc_mask;
+ Vector<Uint32> test_mask;
+
+ ndbout_c("Testing bitmask of size %d", bitmask_size);
+ Uint32 zero = 0;
+ alloc_mask.fill(sz32, zero);
+ test_mask.fill(sz32, zero);
+
+ for(int i = 0; i<5000; i++)
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ int pos = lrand() % (bitmask_size - 1);
+ int free = 0;
+ if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
+ {
+ // Bit was allocated
+ // 1) Look up allocation
+ // 2) Check data
+ // 3) free it
+ size_t j;
+ int min, max;
+ for(j = 0; j<alloc_list.size(); j++)
+ {
+ min = alloc_list[j].pos;
+ max = min + alloc_list[j].size;
+ if(pos >= min && pos < max)
+ {
+ break;
+ }
+ }
+ require(pos >= min && pos < max);
+ BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
+ tmp.getBase());
+ if(DEBUG)
+ {
+ printf("freeing [ %d %d ]", min, max);
+ printf("- mask: ");
+ print(tmp.getBase(), max - min);
+
+ printf(" save: ");
+ size_t k;
+ Alloc& a = alloc_list[j];
+ for(k = 0; k<a.data.size(); k++)
+ printf("%.8x ", a.data[k]);
+ printf("\n");
+ }
+ int bytes = (max - min + 7) >> 3;
+ if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
+ {
+ abort();
+ }
+ while(min < max)
+ BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
+ alloc_list.erase(j);
+ }
+ else
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ // Bit was free
+ // 1) Check how much space is avaiable
+ // 2) Create new allocation of lrandom size
+ // 3) Fill data with lrandom data
+ // 4) Update alloc mask
+ while(pos+free < bitmask_size &&
+ !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
+ free++;
+
+ Uint32 sz =
+ (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
+ sz = sz ? sz : 1;
+ sz = pos + sz == bitmask_size ? sz - 1 : sz;
+ Alloc a;
+ a.pos = pos;
+ a.size = sz;
+ a.data.fill(((sz+31)>> 5)-1, zero);
+ if(DEBUG)
+ printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
+ for(size_t j = 0; j<sz; j++)
+ {
+ BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
+ if((lrand() % 1000) > 500)
+ BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
+ }
+ if(DEBUG)
+ {
+ printf("- mask: ");
+ print(a.data.getBase(), sz);
+ printf("\n");
+ }
+ BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
+ a.data.getBase());
+ alloc_list.push_back(a);
+ }
+ }
+#endif
+}
+
+template class Vector<Alloc>;
+template class Vector<Uint32>;
+
+#endif
diff --git a/ndb/src/common/util/Makefile.am b/ndb/src/common/util/Makefile.am
index a62c8186174..2719d14ee92 100644
--- a/ndb/src/common/util/Makefile.am
+++ b/ndb/src/common/util/Makefile.am
@@ -9,7 +9,24 @@ libgeneral_la_SOURCES = \
NdbSqlUtil.cpp new.cpp \
uucode.c random.c version.c \
strdup.c \
- ConfigValues.cpp ndb_init.c basestring_vsnprintf.c
+ ConfigValues.cpp ndb_init.c basestring_vsnprintf.c \
+ Bitmask.cpp
+
+EXTRA_PROGRAMS = testBitmask
+testBitmask_SOURCES = testBitmask.cpp
+testBitmask_LDFLAGS = @ndb_bin_am_ldflags@ \
+ $(top_builddir)/ndb/src/libndbclient.la \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/strings/libmystrings.a
+
+testBitmask.cpp : Bitmask.cpp
+ rm -f testBitmask.cpp
+ @LN_CP_F@ Bitmask.cpp testBitmask.cpp
+
+testBitmask.o: $(testBitmask_SOURCES)
+ $(CXXCOMPILE) -c $(INCLUDES) -D__TEST_BITMASK__ $<
+
include $(top_srcdir)/ndb/config/common.mk.am
include $(top_srcdir)/ndb/config/type_util.mk.am
diff --git a/ndb/src/common/util/NdbSqlUtil.cpp b/ndb/src/common/util/NdbSqlUtil.cpp
index c4114ad5ffa..09e150dbacf 100644
--- a/ndb/src/common/util/NdbSqlUtil.cpp
+++ b/ndb/src/common/util/NdbSqlUtil.cpp
@@ -15,182 +15,169 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <NdbSqlUtil.hpp>
+#include <NdbOut.hpp>
+#include <my_sys.h>
-int
-NdbSqlUtil::char_compare(const char* s1, unsigned n1,
- const char* s2, unsigned n2, bool padded)
-{
- int c1 = 0;
- int c2 = 0;
- unsigned i = 0;
- while (i < n1 || i < n2) {
- c1 = i < n1 ? s1[i] : padded ? 0x20 : 0;
- c2 = i < n2 ? s2[i] : padded ? 0x20 : 0;
- if (c1 != c2)
- break;
- i++;
- }
- return c1 - c2;
-}
-
-bool
-NdbSqlUtil::char_like(const char* s1, unsigned n1,
- const char* s2, unsigned n2, bool padded)
-{
- int c1 = 0;
- int c2 = 0;
- unsigned i1 = 0;
- unsigned i2 = 0;
- while (i1 < n1 || i2 < n2) {
- c1 = i1 < n1 ? s1[i1] : padded ? 0x20 : 0;
- c2 = i2 < n2 ? s2[i2] : padded ? 0x20 : 0;
- if (c2 == '%') {
- while (i2 + 1 < n2 && s2[i2 + 1] == '%') {
- i2++;
- }
- unsigned m = 0;
- while (m <= n1 - i1) {
- if (char_like(s1 + i1 + m, n1 -i1 - m,
- s2 + i2 + 1, n2 - i2 - 1, padded))
- return true;
- m++;
- }
- return false;
- }
- if (c2 == '_') {
- if (c1 == 0)
- return false;
- } else {
- if (c1 != c2)
- return false;
- }
- i1++;
- i2++;
- }
- return i1 == n2 && i2 == n2;
-}
-
-/**
- * Data types.
+/*
+ * Data types. The entries must be in the numerical order.
*/
const NdbSqlUtil::Type
NdbSqlUtil::m_typeList[] = {
{ // 0
Type::Undefined,
+ NULL,
NULL
},
{ // 1
Type::Tinyint,
- cmpTinyint
+ cmpTinyint,
+ NULL
},
{ // 2
Type::Tinyunsigned,
- cmpTinyunsigned
+ cmpTinyunsigned,
+ NULL
},
{ // 3
Type::Smallint,
- cmpSmallint
+ cmpSmallint,
+ NULL
},
{ // 4
Type::Smallunsigned,
- cmpSmallunsigned
+ cmpSmallunsigned,
+ NULL
},
{ // 5
Type::Mediumint,
- cmpMediumint
+ cmpMediumint,
+ NULL
},
{ // 6
Type::Mediumunsigned,
- cmpMediumunsigned
+ cmpMediumunsigned,
+ NULL
},
{ // 7
Type::Int,
- cmpInt
+ cmpInt,
+ NULL
},
{ // 8
Type::Unsigned,
- cmpUnsigned
+ cmpUnsigned,
+ NULL
},
{ // 9
Type::Bigint,
- cmpBigint
+ cmpBigint,
+ NULL
},
{ // 10
Type::Bigunsigned,
- cmpBigunsigned
+ cmpBigunsigned,
+ NULL
},
{ // 11
Type::Float,
- cmpFloat
+ cmpFloat,
+ NULL
},
{ // 12
Type::Double,
- cmpDouble
+ cmpDouble,
+ NULL
},
{ // 13
Type::Olddecimal,
- cmpOlddecimal
+ cmpOlddecimal,
+ NULL
},
{ // 14
Type::Char,
- cmpChar
+ cmpChar,
+ likeChar
},
{ // 15
Type::Varchar,
- cmpVarchar
+ cmpVarchar,
+ likeVarchar
},
{ // 16
Type::Binary,
- cmpBinary
+ cmpBinary,
+ likeBinary
},
{ // 17
Type::Varbinary,
- cmpVarbinary
+ cmpVarbinary,
+ likeVarbinary
},
{ // 18
Type::Datetime,
- cmpDatetime
+ cmpDatetime,
+ NULL
},
{ // 19
Type::Date,
- cmpDate
+ cmpDate,
+ NULL
},
{ // 20
Type::Blob,
- cmpBlob
+ NULL,
+ NULL
},
{ // 21
Type::Text,
- cmpText
+ NULL,
+ NULL
},
{ // 22
- Type::Undefined, // 5.0 Bit
+ Type::Bit,
+ NULL,
NULL
},
{ // 23
- Type::Undefined, // 5.0 Longvarchar
- NULL
+ Type::Longvarchar,
+ cmpLongvarchar,
+ likeLongvarchar
},
{ // 24
- Type::Undefined, // 5.0 Longvarbinary
- NULL
+ Type::Longvarbinary,
+ cmpLongvarbinary,
+ likeLongvarbinary
},
{ // 25
Type::Time,
- cmpTime
+ cmpTime,
+ NULL
},
{ // 26
Type::Year,
- cmpYear
+ cmpYear,
+ NULL
},
{ // 27
Type::Timestamp,
- cmpTimestamp
+ cmpTimestamp,
+ NULL
},
{ // 28
Type::Olddecimalunsigned,
- cmpOlddecimalunsigned
+ cmpOlddecimalunsigned,
+ NULL
+ },
+ { // 29
+ Type::Decimal,
+ cmpDecimal,
+ NULL
+ },
+ { // 30
+ Type::Decimalunsigned,
+ cmpDecimalunsigned,
+ NULL
}
};
@@ -209,10 +196,12 @@ NdbSqlUtil::getTypeBinary(Uint32 typeId)
{
switch (typeId) {
case Type::Char:
- typeId = Type::Binary;
- break;
case Type::Varchar:
- typeId = Type::Varbinary;
+ case Type::Binary:
+ case Type::Varbinary:
+ case Type::Longvarchar:
+ case Type::Longvarbinary:
+ typeId = Type::Binary;
break;
case Type::Text:
typeId = Type::Blob;
@@ -223,194 +212,211 @@ NdbSqlUtil::getTypeBinary(Uint32 typeId)
return getType(typeId);
}
-// compare
+/*
+ * Comparison functions.
+ */
int
-NdbSqlUtil::cmpTinyint(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpTinyint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { Uint32 p[1]; Int8 v; } u1, u2;
- u1.p[0] = p1[0];
- u2.p[0] = p2[0];
- if (u1.v < u2.v)
- return -1;
- if (u1.v > u2.v)
- return +1;
- return 0;
+ if (n2 >= sizeof(Int8)) {
+ Int8 v1, v2;
+ memcpy(&v1, p1, sizeof(Int8));
+ memcpy(&v2, p2, sizeof(Int8));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpTinyunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpTinyunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { Uint32 p[1]; Uint8 v; } u1, u2;
- u1.p[0] = p1[0];
- u2.p[0] = p2[0];
- if (u1.v < u2.v)
- return -1;
- if (u1.v > u2.v)
- return +1;
- return 0;
+ if (n2 >= sizeof(Uint8)) {
+ Uint8 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint8));
+ memcpy(&v2, p2, sizeof(Uint8));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpSmallint(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpSmallint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { Uint32 p[1]; Int16 v; } u1, u2;
- u1.p[0] = p1[0];
- u2.p[0] = p2[0];
- if (u1.v < u2.v)
- return -1;
- if (u1.v > u2.v)
- return +1;
- return 0;
+ if (n2 >= sizeof(Int16)) {
+ Int16 v1, v2;
+ memcpy(&v1, p1, sizeof(Int16));
+ memcpy(&v2, p2, sizeof(Int16));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpSmallunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpSmallunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { Uint32 p[1]; Uint16 v; } u1, u2;
- u1.p[0] = p1[0];
- u2.p[0] = p2[0];
- if (u1.v < u2.v)
- return -1;
- if (u1.v > u2.v)
- return +1;
- return 0;
+ if (n2 >= sizeof(Uint16)) {
+ Uint16 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint16));
+ memcpy(&v2, p2, sizeof(Uint16));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpMediumint(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpMediumint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { const Uint32* p; const unsigned char* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
- Int32 v1 = sint3korr(u1.v);
- Int32 v2 = sint3korr(u2.v);
- if (v1 < v2)
- return -1;
- if (v1 > v2)
- return +1;
- return 0;
+ if (n2 >= 3) {
+ Int32 v1, v2;
+ v1 = sint3korr((const uchar*)p1);
+ v2 = sint3korr((const uchar*)p2);
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpMediumunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpMediumunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { const Uint32* p; const unsigned char* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
- Uint32 v1 = uint3korr(u1.v);
- Uint32 v2 = uint3korr(u2.v);
- if (v1 < v2)
- return -1;
- if (v1 > v2)
- return +1;
- return 0;
+ if (n2 >= 3) {
+ Uint32 v1, v2;
+ v1 = uint3korr((const uchar*)p1);
+ v2 = uint3korr((const uchar*)p2);
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpInt(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpInt(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { Uint32 p[1]; Int32 v; } u1, u2;
- u1.p[0] = p1[0];
- u2.p[0] = p2[0];
- if (u1.v < u2.v)
- return -1;
- if (u1.v > u2.v)
- return +1;
- return 0;
+ if (n2 >= sizeof(Int32)) {
+ Int32 v1, v2;
+ memcpy(&v1, p1, sizeof(Int32));
+ memcpy(&v2, p2, sizeof(Int32));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpUnsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpUnsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { Uint32 p[1]; Uint32 v; } u1, u2;
- u1.v = p1[0];
- u2.v = p2[0];
- if (u1.v < u2.v)
- return -1;
- if (u1.v > u2.v)
- return +1;
- return 0;
+ if (n2 >= sizeof(Uint32)) {
+ Uint32 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint32));
+ memcpy(&v2, p2, sizeof(Uint32));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpBigint(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpBigint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- if (size >= 2) {
- union { Uint32 p[2]; Int64 v; } u1, u2;
- u1.p[0] = p1[0];
- u1.p[1] = p1[1];
- u2.p[0] = p2[0];
- u2.p[1] = p2[1];
- if (u1.v < u2.v)
+ if (n2 >= sizeof(Int64)) {
+ Int64 v1, v2;
+ memcpy(&v1, p1, sizeof(Int64));
+ memcpy(&v2, p2, sizeof(Int64));
+ if (v1 < v2)
return -1;
- if (u1.v > u2.v)
+ if (v1 > v2)
return +1;
return 0;
}
+ assert(! full);
return CmpUnknown;
}
int
-NdbSqlUtil::cmpBigunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpBigunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- if (size >= 2) {
- union { Uint32 p[2]; Uint64 v; } u1, u2;
- u1.p[0] = p1[0];
- u1.p[1] = p1[1];
- u2.p[0] = p2[0];
- u2.p[1] = p2[1];
- if (u1.v < u2.v)
+ if (n2 >= sizeof(Uint64)) {
+ Uint64 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint64));
+ memcpy(&v2, p2, sizeof(Uint64));
+ if (v1 < v2)
return -1;
- if (u1.v > u2.v)
+ if (v1 > v2)
return +1;
return 0;
}
+ assert(! full);
return CmpUnknown;
}
int
-NdbSqlUtil::cmpFloat(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpFloat(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { Uint32 p[1]; float v; } u1, u2;
- u1.p[0] = p1[0];
- u2.p[0] = p2[0];
- // no format check
- if (u1.v < u2.v)
- return -1;
- if (u1.v > u2.v)
- return +1;
- return 0;
+ if (n2 >= sizeof(float)) {
+ float v1, v2;
+ memcpy(&v1, p1, sizeof(float));
+ memcpy(&v2, p2, sizeof(float));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpDouble(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpDouble(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- if (size >= 2) {
- union { Uint32 p[2]; double v; } u1, u2;
- u1.p[0] = p1[0];
- u1.p[1] = p1[1];
- u2.p[0] = p2[0];
- u2.p[1] = p2[1];
- // no format check
- if (u1.v < u2.v)
+ if (n2 >= sizeof(double)) {
+ double v1, v2;
+ memcpy(&v1, p1, sizeof(double));
+ memcpy(&v2, p2, sizeof(double));
+ if (v1 < v2)
return -1;
- if (u1.v > u2.v)
+ if (v1 > v2)
return +1;
return 0;
}
+ assert(! full);
return CmpUnknown;
}
@@ -440,266 +446,428 @@ NdbSqlUtil::cmp_olddecimal(const uchar* s1, const uchar* s2, unsigned n)
}
int
-NdbSqlUtil::cmpOlddecimal(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpOlddecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- if (full == size) {
- union { const Uint32* p; const uchar* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
- return cmp_olddecimal(u1.v, u2.v, full << 2);
+ if (full) {
+ assert(n1 == n2);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ return cmp_olddecimal(v1, v2, n1);
}
return CmpUnknown;
}
int
-NdbSqlUtil::cmpOlddecimalunsigned(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpOlddecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- if (full == size) {
- union { const Uint32* p; const uchar* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
- return cmp_olddecimal(u1.v, u2.v, full << 2);
+ if (full) {
+ assert(n1 == n2);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ return cmp_olddecimal(v1, v2, n1);
}
return CmpUnknown;
}
int
-NdbSqlUtil::cmpChar(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpDecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ // compare as binary strings
+ unsigned n = (n1 <= n2 ? n1 : n2);
+ int k = memcmp(v1, v2, n);
+ if (k == 0) {
+ k = (full ? n1 : n) - n2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpDecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ // compare as binary strings
+ unsigned n = (n1 <= n2 ? n1 : n2);
+ int k = memcmp(v1, v2, n);
+ if (k == 0) {
+ k = (full ? n1 : n) - n2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
// collation does not work on prefix for some charsets
- assert(full == size && size > 0);
- /*
- * Char is blank-padded to length and null-padded to word size.
- */
- union { const Uint32* p; const uchar* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
+ assert(full);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
// not const in MySQL
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
- // length in bytes including null padding to Uint32
- uint l1 = (full << 2);
- int k = (*cs->coll->strnncollsp)(cs, u1.v, l1, u2.v, l1);
+ // compare with space padding
+ int k = (*cs->coll->strnncollsp)(cs, v1, n1, v2, n2, false);
return k < 0 ? -1 : k > 0 ? +1 : 0;
}
int
-NdbSqlUtil::cmpVarchar(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- /*
- * Varchar is not allowed to contain a null byte and the value is
- * null-padded. Therefore comparison does not need to use the length.
- *
- * Not used before MySQL 5.0. Format is likely to change. Handle
- * only binary collation for now.
- */
- union { const Uint32* p; const char* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
- // skip length in first 2 bytes
- int k = strncmp(u1.v + 2, u2.v + 2, (size << 2) - 2);
- return k < 0 ? -1 : k > 0 ? +1 : full == size ? 0 : CmpUnknown;
+ const unsigned lb = 1;
+ // collation does not work on prefix for some charsets
+ assert(full && n1 >= lb && n2 >= lb);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = *v1;
+ unsigned m2 = *v2;
+ if (m1 <= n1 - lb && m2 <= n2 - lb) {
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ // compare with space padding
+ int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false);
+ return k < 0 ? -1 : k > 0 ? +1 : 0;
+ }
+ // treat bad data as NULL
+ if (m1 > n1 - lb && m2 <= n2 - lb)
+ return -1;
+ if (m1 <= n1 - lb && m2 > n2 - lb)
+ return +1;
+ return 0;
}
int
-NdbSqlUtil::cmpBinary(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
-{
- assert(full >= size && size > 0);
- /*
- * Binary data of full length. Compare bytewise.
- */
- union { const Uint32* p; const unsigned char* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
- int k = memcmp(u1.v, u2.v, size << 2);
- return k < 0 ? -1 : k > 0 ? +1 : full == size ? 0 : CmpUnknown;
+NdbSqlUtil::cmpBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ // compare as binary strings
+ unsigned n = (n1 <= n2 ? n1 : n2);
+ int k = memcmp(v1, v2, n);
+ if (k == 0) {
+ k = (full ? n1 : n) - n2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
}
int
-NdbSqlUtil::cmpVarbinary(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
-{
- assert(full >= size && size > 0);
- /*
- * Binary data of variable length padded with nulls. The comparison
- * does not need to use the length.
- *
- * Not used before MySQL 5.0. Format is likely to change.
- */
- union { const Uint32* p; const unsigned char* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
- // skip length in first 2 bytes
- int k = memcmp(u1.v + 2, u2.v + 2, (size << 2) - 2);
- return k < 0 ? -1 : k > 0 ? +1 : full == size ? 0 : CmpUnknown;
+NdbSqlUtil::cmpVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const unsigned lb = 1;
+ if (n2 >= lb) {
+ assert(n1 >= lb);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = *v1;
+ unsigned m2 = *v2;
+ if (m1 <= n1 - lb && m2 <= n2 - lb) {
+ // compare as binary strings
+ unsigned m = (m1 <= m2 ? m1 : m2);
+ int k = memcmp(v1 + lb, v2 + lb, m);
+ if (k == 0) {
+ k = (full ? m1 : m) - m2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
+ }
+ // treat bad data as NULL
+ if (m1 > n1 - lb && m2 <= n2 - lb)
+ return -1;
+ if (m1 <= n1 - lb && m2 > n2 - lb)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpDatetime(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpDatetime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- if (size >= 2) {
- union { Uint32 p[2]; Int64 v; } u1, u2;
- u1.p[0] = p1[0];
- u1.p[1] = p1[1];
- u2.p[0] = p2[0];
- u2.p[1] = p2[1];
- if (u1.v < u2.v)
+ if (n2 >= sizeof(Int64)) {
+ Int64 v1, v2;
+ memcpy(&v1, p1, sizeof(Int64));
+ memcpy(&v2, p2, sizeof(Int64));
+ if (v1 < v2)
return -1;
- if (u1.v > u2.v)
+ if (v1 > v2)
return +1;
return 0;
}
+ assert(! full);
return CmpUnknown;
}
int
-NdbSqlUtil::cmpDate(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
#ifdef ndb_date_is_4_byte_native_int
- assert(full >= size && size > 0);
- union { Uint32 p[2]; Int32 v; } u1, u2;
- u1.p[0] = p1[0];
- u2.p[0] = p2[0];
- if (u1.v < u2.v)
- return -1;
- if (u1.v > u2.v)
- return +1;
- return 0;
+ if (n2 >= sizeof(Int32)) {
+ Int32 v1, v2;
+ memcpy(&v1, p1, sizeof(Int32));
+ memcpy(&v2, p2, sizeof(Int32));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
#else
- assert(full >= size && size > 0);
- union { const Uint32* p; const unsigned char* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
#ifdef ndb_date_sol9x86_cc_xO3_madness
- // from Field_newdate::val_int
- Uint64 j1 = uint3korr(u1.v);
- Uint64 j2 = uint3korr(u2.v);
- j1 = (j1 % 32L)+(j1 / 32L % 16L)*100L + (j1/(16L*32L))*10000L;
- j2 = (j2 % 32L)+(j2 / 32L % 16L)*100L + (j2/(16L*32L))*10000L;
- if (j1 < j2)
- return -1;
- if (j1 > j2)
- return +1;
- return 0;
+ if (n2 >= 3) {
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ // from Field_newdate::val_int
+ Uint64 j1 = uint3korr(v1);
+ Uint64 j2 = uint3korr(v2);
+ j1 = (j1 % 32L)+(j1 / 32L % 16L)*100L + (j1/(16L*32L))*10000L;
+ j2 = (j2 % 32L)+(j2 / 32L % 16L)*100L + (j2/(16L*32L))*10000L;
+ if (j1 < j2)
+ return -1;
+ if (j1 > j2)
+ return +1;
+ return 0;
+ }
#else
- uint j1 = uint3korr(u1.v);
- uint j2 = uint3korr(u2.v);
- uint d1 = (j1 & 31);
- uint d2 = (j2 & 31);
- j1 = (j1 >> 5);
- j2 = (j2 >> 5);
- uint m1 = (j1 & 15);
- uint m2 = (j2 & 15);
- j1 = (j1 >> 4);
- j2 = (j2 >> 4);
- uint y1 = j1;
- uint y2 = j2;
- if (y1 < y2)
- return -1;
- if (y1 > y2)
- return +1;
- if (m1 < m2)
- return -1;
- if (m1 > m2)
- return +1;
- if (d1 < d2)
- return -1;
- if (d1 > d2)
- return +1;
- return 0;
+ if (n2 >= 3) {
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ uint j1 = uint3korr(v1);
+ uint j2 = uint3korr(v2);
+ uint d1 = (j1 & 31);
+ uint d2 = (j2 & 31);
+ j1 = (j1 >> 5);
+ j2 = (j2 >> 5);
+ uint m1 = (j1 & 15);
+ uint m2 = (j2 & 15);
+ j1 = (j1 >> 4);
+ j2 = (j2 >> 4);
+ uint y1 = j1;
+ uint y2 = j2;
+ if (y1 < y2)
+ return -1;
+ if (y1 > y2)
+ return +1;
+ if (m1 < m2)
+ return -1;
+ if (m1 > m2)
+ return +1;
+ if (d1 < d2)
+ return -1;
+ if (d1 > d2)
+ return +1;
+ return 0;
+ }
#endif
#endif
+ assert(! full);
+ return CmpUnknown;
}
+// not supported
int
-NdbSqlUtil::cmpBlob(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpBlob(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- /*
- * Blob comparison is on the inline bytes (null padded).
- */
- const unsigned head = NDB_BLOB_HEAD_SIZE;
- // skip blob head
- if (size >= head + 1) {
- union { const Uint32* p; const unsigned char* v; } u1, u2;
- u1.p = p1 + head;
- u2.p = p2 + head;
- int k = memcmp(u1.v, u2.v, (size - head) << 2);
- return k < 0 ? -1 : k > 0 ? +1 : full == size ? 0 : CmpUnknown;
+ assert(false);
+ return 0;
+}
+
+// not supported
+int
+NdbSqlUtil::cmpText(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ assert(false);
+ return 0;
+}
+
+int
+NdbSqlUtil::cmpTime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= 3) {
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ // from Field_time::val_int
+ Int32 j1 = sint3korr(v1);
+ Int32 j2 = sint3korr(v2);
+ if (j1 < j2)
+ return -1;
+ if (j1 > j2)
+ return +1;
+ return 0;
}
+ assert(! full);
return CmpUnknown;
}
+// not yet
+int
+NdbSqlUtil::cmpBit(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ assert(false);
+ return 0;
+}
+
int
-NdbSqlUtil::cmpText(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
+ const unsigned lb = 2;
// collation does not work on prefix for some charsets
- assert(full == size && size > 0);
- /*
- * Text comparison is on the inline bytes (blank padded). Currently
- * not supported for multi-byte charsets.
- */
- const unsigned head = NDB_BLOB_HEAD_SIZE;
- // skip blob head
- if (size >= head + 1) {
- union { const Uint32* p; const uchar* v; } u1, u2;
- u1.p = p1 + head;
- u2.p = p2 + head;
- // not const in MySQL
+ assert(full && n1 >= lb && n2 >= lb);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = uint2korr(v1);
+ unsigned m2 = uint2korr(v2);
+ if (m1 <= n1 - lb && m2 <= n2 - lb) {
CHARSET_INFO* cs = (CHARSET_INFO*)(info);
- // length in bytes including null padding to Uint32
- uint l1 = (full << 2);
- int k = (*cs->coll->strnncollsp)(cs, u1.v, l1, u2.v, l1);
+ // compare with space padding
+ int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false);
return k < 0 ? -1 : k > 0 ? +1 : 0;
}
+ // treat bad data as NULL
+ if (m1 > n1 - lb && m2 <= n2 - lb)
+ return -1;
+ if (m1 <= n1 - lb && m2 > n2 - lb)
+ return +1;
+ return 0;
+}
+
+int
+NdbSqlUtil::cmpLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const unsigned lb = 2;
+ if (n2 >= lb) {
+ assert(n1 >= lb);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = uint2korr(v1);
+ unsigned m2 = uint2korr(v2);
+ if (m1 <= n1 - lb && m2 <= n2 - lb) {
+ // compare as binary strings
+ unsigned m = (m1 <= m2 ? m1 : m2);
+ int k = memcmp(v1 + lb, v2 + lb, m);
+ if (k == 0) {
+ k = (full ? m1 : m) - m2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
+ }
+ // treat bad data as NULL
+ if (m1 > n1 - lb && m2 <= n2 - lb)
+ return -1;
+ if (m1 <= n1 - lb && m2 > n2 - lb)
+ return +1;
+ return 0;
+ }
+ assert(! full);
return CmpUnknown;
}
int
-NdbSqlUtil::cmpTime(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpYear(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { const Uint32* p; const unsigned char* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
- // from Field_time::val_int
- Int32 j1 = sint3korr(u1.v);
- Int32 j2 = sint3korr(u2.v);
- if (j1 < j2)
- return -1;
- if (j1 > j2)
- return +1;
- return 0;
+ if (n2 >= sizeof(Uint8)) {
+ Uint8 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint8));
+ memcpy(&v2, p2, sizeof(Uint8));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
int
-NdbSqlUtil::cmpYear(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::cmpTimestamp(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
{
- assert(full >= size && size > 0);
- union { const Uint32* p; const unsigned char* v; } u1, u2;
- u1.p = p1;
- u2.p = p2;
- if (u1.v[0] < u2.v[0])
- return -1;
- if (u1.v[0] > u2.v[0])
- return +1;
- return 0;
+ if (n2 >= sizeof(Uint32)) {
+ Uint32 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint32));
+ memcpy(&v2, p2, sizeof(Uint32));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
}
+// like
+
+static const int ndb_wild_prefix = '\\';
+static const int ndb_wild_one = '_';
+static const int ndb_wild_many = '%';
+
int
-NdbSqlUtil::cmpTimestamp(const void* info, const Uint32* p1, const Uint32* p2, Uint32 full, Uint32 size)
+NdbSqlUtil::likeChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
{
- assert(full >= size && size > 0);
- union { Uint32 p[1]; Uint32 v; } u1, u2;
- u1.v = p1[0];
- u2.v = p2[0];
- if (u1.v < u2.v)
- return -1;
- if (u1.v > u2.v)
- return +1;
- return 0;
+ const char* v1 = (const char*)p1;
+ const char* v2 = (const char*)p2;
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ int k = (cs->coll->wildcmp)(cs, v1, v1 + n1, v2, v2 + n2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
+ return k == 0 ? 0 : +1;
+}
+
+int
+NdbSqlUtil::likeBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ assert(info == 0);
+ return likeChar(&my_charset_bin, p1, n1, p2, n2);
+}
+
+int
+NdbSqlUtil::likeVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ const unsigned lb = 1;
+ if (n1 >= lb && n2 >= lb) {
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = *v1;
+ unsigned m2 = *v2;
+ if (lb + m1 <= n1 && lb + m2 <= n2) {
+ const char* w1 = (const char*)v1 + lb;
+ const char* w2 = (const char*)v2 + lb;
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ int k = (cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
+ return k == 0 ? 0 : +1;
+ }
+ }
+ return -1;
+}
+
+int
+NdbSqlUtil::likeVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ assert(info == 0);
+ return likeVarchar(&my_charset_bin, p1, n1, p2, n2);
+}
+
+int
+NdbSqlUtil::likeLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ const unsigned lb = 2;
+ if (n1 >= lb && n2 >= lb) {
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = uint2korr(v1);
+ unsigned m2 = uint2korr(v2);
+ if (lb + m1 <= n1 && lb + m2 <= n2) {
+ const char* w1 = (const char*)v1 + lb;
+ const char* w2 = (const char*)v2 + lb;
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ int k = (cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
+ return k == 0 ? 0 : +1;
+ }
+ }
+ return -1;
+}
+
+int
+NdbSqlUtil::likeLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ assert(info == 0);
+ return likeLongvarchar(&my_charset_bin, p1, n1, p2, n2);
}
// check charset
@@ -709,9 +877,9 @@ NdbSqlUtil::usable_in_pk(Uint32 typeId, const void* info)
{
const Type& type = getType(typeId);
switch (type.m_typeId) {
- case Type::Undefined:
- break;
case Type::Char:
+ case Type::Varchar:
+ case Type::Longvarchar:
{
const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
return
@@ -719,13 +887,13 @@ NdbSqlUtil::usable_in_pk(Uint32 typeId, const void* info)
cs->cset != 0 &&
cs->coll != 0 &&
cs->coll->strnxfrm != 0 &&
- cs->strxfrm_multiply <= 1; // current limitation
+ cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY;
}
break;
- case Type::Varchar:
- return true; // Varchar not used via MySQL
+ case Type::Undefined:
case Type::Blob:
case Type::Text:
+ case Type::Bit:
break;
default:
return true;
@@ -743,10 +911,12 @@ bool
NdbSqlUtil::usable_in_ordered_index(Uint32 typeId, const void* info)
{
const Type& type = getType(typeId);
+ if (type.m_cmp == NULL)
+ return false;
switch (type.m_typeId) {
- case Type::Undefined:
- break;
case Type::Char:
+ case Type::Varchar:
+ case Type::Longvarchar:
{
const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
return
@@ -755,23 +925,13 @@ NdbSqlUtil::usable_in_ordered_index(Uint32 typeId, const void* info)
cs->coll != 0 &&
cs->coll->strnxfrm != 0 &&
cs->coll->strnncollsp != 0 &&
- cs->strxfrm_multiply <= 1; // current limitation
+ cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY;
}
break;
- case Type::Varchar:
- return true; // Varchar not used via MySQL
+ case Type::Undefined:
+ case Type::Blob:
case Type::Text:
- {
- const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
- return
- cs != 0 &&
- cs->mbmaxlen == 1 && // extra limitation
- cs->cset != 0 &&
- cs->coll != 0 &&
- cs->coll->strnxfrm != 0 &&
- cs->coll->strnncollsp != 0 &&
- cs->strxfrm_multiply <= 1; // current limitation
- }
+ case Type::Bit: // can be fixed
break;
default:
return true;
@@ -779,68 +939,69 @@ NdbSqlUtil::usable_in_ordered_index(Uint32 typeId, const void* info)
return false;
}
-#ifdef NDB_SQL_UTIL_TEST
-
-#include <NdbTick.h>
-#include <NdbOut.hpp>
+// utilities
-struct Testcase {
- int op; // 1=compare 2=like
- int res;
- const char* s1;
- const char* s2;
- int pad;
-};
-const Testcase testcase[] = {
- { 2, 1, "abc", "abc", 0 },
- { 2, 1, "abc", "abc%", 0 },
- { 2, 1, "abcdef", "abc%", 0 },
- { 2, 1, "abcdefabcdefabcdef", "abc%", 0 },
- { 2, 1, "abcdefabcdefabcdef", "abc%f", 0 },
- { 2, 0, "abcdefabcdefabcdef", "abc%z", 0 },
- { 2, 1, "abcdefabcdefabcdef", "%f", 0 },
- { 2, 1, "abcdef", "a%b%c%d%e%f", 0 },
- { 0, 0, 0, 0 }
-};
-
-int
-main(int argc, char** argv)
-{
- ndb_init(); // for charsets
- unsigned count = argc > 1 ? atoi(argv[1]) : 1000000;
- ndbout_c("count = %u", count);
- assert(count != 0);
- for (const Testcase* t = testcase; t->s1 != 0; t++) {
- ndbout_c("%d = '%s' %s '%s' pad=%d",
- t->res, t->s1, t->op == 1 ? "comp" : "like", t->s2);
- NDB_TICKS x1 = NdbTick_CurrentMillisecond();
- unsigned n1 = strlen(t->s1);
- unsigned n2 = strlen(t->s2);
- for (unsigned i = 0; i < count; i++) {
- if (t->op == 1) {
- int res = NdbSqlUtil::char_compare(t->s1, n1, t->s2, n2, t->pad);
- assert(res == t->res);
- continue;
- }
- if (t->op == 2) {
- int res = NdbSqlUtil::char_like(t->s1, n1, t->s2, n2, t->pad);
- assert(res == t->res);
- continue;
- }
- assert(false);
+bool
+NdbSqlUtil::get_var_length(Uint32 typeId, const void* p, unsigned attrlen, Uint32& lb, Uint32& len)
+{
+ const unsigned char* const src = (const unsigned char*)p;
+ switch (typeId) {
+ case NdbSqlUtil::Type::Varchar:
+ case NdbSqlUtil::Type::Varbinary:
+ lb = 1;
+ if (attrlen >= lb) {
+ len = src[0];
+ if (attrlen >= lb + len)
+ return true;
}
- NDB_TICKS x2 = NdbTick_CurrentMillisecond();
- if (x2 < x1)
- x2 = x1;
- double usec = 1000000.0 * double(x2 - x1) / double(count);
- ndbout_c("time %.0f usec per call", usec);
- }
- // quick check
- for (unsigned i = 0; i < sizeof(m_typeList) / sizeof(m_typeList[0]); i++) {
- const NdbSqlUtil::Type& t = m_typeList[i];
- assert(t.m_typeId == i);
+ break;
+ case NdbSqlUtil::Type::Longvarchar:
+ case NdbSqlUtil::Type::Longvarbinary:
+ lb = 2;
+ if (attrlen >= lb) {
+ len = src[0] + (src[1] << 8);
+ if (attrlen >= lb + len)
+ return true;
+ }
+ break;
+ default:
+ lb = 0;
+ len = attrlen;
+ return true;
+ break;
}
- return 0;
+ return false;
}
+// workaround
+
+int
+NdbSqlUtil::strnxfrm_bug7284(CHARSET_INFO* cs, unsigned char* dst, unsigned dstLen, const unsigned char*src, unsigned srcLen)
+{
+ unsigned char nsp[20]; // native space char
+ unsigned char xsp[20]; // strxfrm-ed space char
+#ifdef VM_TRACE
+ memset(nsp, 0x1f, sizeof(nsp));
+ memset(xsp, 0x1f, sizeof(xsp));
#endif
+ // convert from unicode codepoint for space
+ int n1 = (*cs->cset->wc_mb)(cs, (my_wc_t)0x20, nsp, nsp + sizeof(nsp));
+ if (n1 <= 0)
+ return -1;
+ // strxfrm to binary
+ int n2 = (*cs->coll->strnxfrm)(cs, xsp, sizeof(xsp), nsp, n1);
+ if (n2 <= 0)
+ return -1;
+ // XXX bug workaround - strnxfrm may not write full string
+ memset(dst, 0x0, dstLen);
+ // strxfrm argument string - returns no error indication
+ int n3 = (*cs->coll->strnxfrm)(cs, dst, dstLen, src, srcLen);
+ // pad with strxfrm-ed space chars
+ int n4 = n3;
+ while (n4 < (int)dstLen) {
+ dst[n4] = xsp[(n4 - n3) % n2];
+ n4++;
+ }
+ // no check for partial last
+ return dstLen;
+}
diff --git a/ndb/src/common/util/SocketServer.cpp b/ndb/src/common/util/SocketServer.cpp
index da06389b5df..6019d24d736 100644
--- a/ndb/src/common/util/SocketServer.cpp
+++ b/ndb/src/common/util/SocketServer.cpp
@@ -82,15 +82,15 @@ SocketServer::tryBind(unsigned short port, const char * intface) {
bool
SocketServer::setup(SocketServer::Service * service,
- unsigned short port,
+ unsigned short * port,
const char * intface){
DBUG_ENTER("SocketServer::setup");
- DBUG_PRINT("enter",("interface=%s, port=%d", intface, port));
+ DBUG_PRINT("enter",("interface=%s, port=%u", intface, *port));
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_port = htons(port);
+ servaddr.sin_port = htons(*port);
if(intface != 0){
if(Ndb_getInAddr(&servaddr.sin_addr, intface))
@@ -119,7 +119,17 @@ SocketServer::setup(SocketServer::Service * service,
NDB_CLOSE_SOCKET(sock);
DBUG_RETURN(false);
}
-
+
+ /* Get the port we bound to */
+ SOCKET_SIZE_TYPE sock_len = sizeof(servaddr);
+ if(getsockname(sock,(struct sockaddr*)&servaddr,&sock_len)<0) {
+ ndbout_c("An error occurred while trying to find out what"
+ " port we bound to. Error: %s",strerror(errno));
+ NDB_CLOSE_SOCKET(sock);
+ DBUG_RETURN(false);
+ }
+
+ DBUG_PRINT("info",("bound to %u",ntohs(servaddr.sin_port)));
if (listen(sock, m_maxSessions) == -1){
DBUG_PRINT("error",("listen() - %d - %s",
errno, strerror(errno)));
@@ -131,6 +141,9 @@ SocketServer::setup(SocketServer::Service * service,
i.m_socket = sock;
i.m_service = service;
m_services.push_back(i);
+
+ *port = ntohs(servaddr.sin_port);
+
DBUG_RETURN(true);
}
@@ -310,11 +323,18 @@ sessionThread_C(void* _sc){
return 0;
}
- if(!si->m_stop){
- si->m_stopped = false;
- si->runSession();
- } else {
- NDB_CLOSE_SOCKET(si->m_socket);
+ /**
+ * may have m_stopped set if we're transforming a mgm
+ * connection into a transporter connection.
+ */
+ if(!si->m_stopped)
+ {
+ if(!si->m_stop){
+ si->m_stopped = false;
+ si->runSession();
+ } else {
+ NDB_CLOSE_SOCKET(si->m_socket);
+ }
}
si->m_stopped = true;
diff --git a/ndb/src/common/util/md5_hash.cpp b/ndb/src/common/util/md5_hash.cpp
index 068843183ac..d4eedbc40fb 100644
--- a/ndb/src/common/util/md5_hash.cpp
+++ b/ndb/src/common/util/md5_hash.cpp
@@ -75,7 +75,7 @@ void byteReverse(unsigned char *buf, unsigned longs)
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
-void MD5Transform(Uint32 buf[4], Uint32 const in[16])
+static void MD5Transform(Uint32 buf[4], Uint32 const in[16])
{
register Uint32 a, b, c, d;
@@ -162,13 +162,13 @@ void MD5Transform(Uint32 buf[4], Uint32 const in[16])
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
-Uint32 md5_hash(const Uint64* keybuf, Uint32 no_of_32_words)
+void md5_hash(Uint32 result[4], const Uint64* keybuf, Uint32 no_of_32_words)
{
-/*
- * This is the external interface of the module
- * It is assumed that keybuf is placed on 8 byte
- * alignment.
- */
+ /**
+ * This is the external interface of the module
+ * It is assumed that keybuf is placed on 8 byte
+ * alignment.
+ */
Uint32 i;
Uint32 buf[4];
Uint64 transform64_buf[8];
@@ -230,6 +230,10 @@ Uint32 md5_hash(const Uint64* keybuf, Uint32 no_of_32_words)
byteReverse((unsigned char *)transform32_buf, 16);
MD5Transform(buf, transform32_buf);
}
- return buf[0];
+
+ result[0] = buf[0];
+ result[1] = buf[1];
+ result[2] = buf[2];
+ result[3] = buf[3];
}
diff --git a/ndb/src/common/util/version.c b/ndb/src/common/util/version.c
index 8cc6de0fc24..dfbb1e4a2e6 100644
--- a/ndb/src/common/util/version.c
+++ b/ndb/src/common/util/version.c
@@ -90,13 +90,14 @@ void ndbSetOwnVersion() {}
#ifndef TEST_VERSION
struct NdbUpGradeCompatible ndbCompatibleTable_full[] = {
- { MAKE_VERSION(4,1,10), MAKE_VERSION(4,1,9), UG_Exact },
+ { MAKE_VERSION(5,0,3), MAKE_VERSION(5,0,2), UG_Exact },
{ MAKE_VERSION(4,1,9), MAKE_VERSION(4,1,8), UG_Exact },
{ MAKE_VERSION(3,5,2), MAKE_VERSION(3,5,1), UG_Exact },
{ 0, 0, UG_Null }
};
struct NdbUpGradeCompatible ndbCompatibleTable_upgrade[] = {
+ { MAKE_VERSION(5,0,2), MAKE_VERSION(4,1,8), UG_Exact },
{ MAKE_VERSION(3,5,4), MAKE_VERSION(3,5,3), UG_Exact },
{ 0, 0, UG_Null }
};
diff --git a/ndb/src/cw/cpcd/main.cpp b/ndb/src/cw/cpcd/main.cpp
index 25632f132e9..9bbd5e484d4 100644
--- a/ndb/src/cw/cpcd/main.cpp
+++ b/ndb/src/cw/cpcd/main.cpp
@@ -32,7 +32,7 @@
#include "common.hpp"
static const char *work_dir = CPCD_DEFAULT_WORK_DIR;
-static int port;
+static short unsigned int port;
static int use_syslog;
static const char *logfile = NULL;
static const char *config_file = CPCD_DEFAULT_CONFIG_FILE;
@@ -142,7 +142,7 @@ int main(int argc, char** argv){
SocketServer * ss = new SocketServer();
CPCDAPIService * serv = new CPCDAPIService(cpcd);
- if(!ss->setup(serv, port)){
+ if(!ss->setup(serv, &port)){
logger.critical("Cannot setup server: %s", strerror(errno));
sleep(1);
delete ss;
diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt
index 5193d3eae9d..fedddb58c0d 100644
--- a/ndb/src/kernel/blocks/ERROR_codes.txt
+++ b/ndb/src/kernel/blocks/ERROR_codes.txt
@@ -10,7 +10,7 @@ Next DBTC 8035
Next CMVMI 9000
Next BACKUP 10022
Next DBUTIL 11002
-Next DBTUX 12007
+Next DBTUX 12008
Next SUMA 13001
TESTING NODE FAILURE, ARBITRATION
@@ -196,6 +196,8 @@ Delay execution of ABORTREQ signal 2 seconds to generate time-out.
8048: Make TC not choose own node for simple/dirty read
5041: Crash is receiving simple read from other TC on different node
+8050: Send TCKEYREF is operation is non local
+
ERROR CODES FOR TESTING TIME-OUT HANDLING IN DBTC
-------------------------------------------------
8040:
@@ -409,6 +411,8 @@ Drop Table/Index:
8033: Fail next trigger create in TC
8034: Fail next index create in TC
+
+
System Restart:
---------------
@@ -439,6 +443,7 @@ Test routing of signals:
Ordered index:
--------------
+12007: Make next alloc node fail with no memory error
Dbdict:
-------
diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp
index 3ef73beb8d2..fdff2702bec 100644
--- a/ndb/src/kernel/blocks/backup/Backup.cpp
+++ b/ndb/src/kernel/blocks/backup/Backup.cpp
@@ -948,7 +948,7 @@ Backup::sendBackupRef(BlockReference senderRef, Signal *signal,
sendSignal(senderRef, GSN_BACKUP_REF, signal, BackupRef::SignalLength, JBB);
if(errorCode != BackupRef::IAmNotMaster){
- signal->theData[0] = EventReport::BackupFailedToStart;
+ signal->theData[0] = NDB_LE_BackupFailedToStart;
signal->theData[1] = senderRef;
signal->theData[2] = errorCode;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
@@ -1201,7 +1201,7 @@ Backup::defineBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId)
sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal,
BackupConf::SignalLength, JBB);
- signal->theData[0] = EventReport::BackupStarted;
+ signal->theData[0] = NDB_LE_BackupStarted;
signal->theData[1] = ptr.p->clientRef;
signal->theData[2] = ptr.p->backupId;
ptr.p->nodes.copyto(NdbNodeBitmask::Size, signal->theData+3);
@@ -2077,7 +2077,7 @@ Backup::stopBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId)
sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal,
BackupCompleteRep::SignalLength, JBB);
- signal->theData[0] = EventReport::BackupCompleted;
+ signal->theData[0] = NDB_LE_BackupCompleted;
signal->theData[1] = ptr.p->clientRef;
signal->theData[2] = ptr.p->backupId;
signal->theData[3] = ptr.p->startGCP;
@@ -2120,7 +2120,7 @@ Backup::masterAbort(Signal* signal, BackupRecordPtr ptr)
sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal,
BackupAbortRep::SignalLength, JBB);
- signal->theData[0] = EventReport::BackupAborted;
+ signal->theData[0] = NDB_LE_BackupAborted;
signal->theData[1] = ptr.p->clientRef;
signal->theData[2] = ptr.p->backupId;
signal->theData[3] = ptr.p->errorCode;
diff --git a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
index 0274ef4af3e..c313abc28eb 100644
--- a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
+++ b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
@@ -188,7 +188,7 @@ void Cmvmi::execEVENT_REP(Signal* signal)
// to the graphical management interface.
//-----------------------------------------------------------------------
EventReport * const eventReport = (EventReport *)&signal->theData[0];
- EventReport::EventType eventType = eventReport->getEventType();
+ Ndb_logevent_type eventType = eventReport->getEventType();
jamEntry();
@@ -198,7 +198,8 @@ void Cmvmi::execEVENT_REP(Signal* signal)
Uint32 threshold;
LogLevel::EventCategory eventCategory;
Logger::LoggerLevel severity;
- if (EventLoggerBase::event_lookup(eventType,eventCategory,threshold,severity))
+ EventLoggerBase::EventTextFunction textF;
+ if (EventLoggerBase::event_lookup(eventType,eventCategory,threshold,severity,textF))
return;
SubscriberPtr ptr;
@@ -362,7 +363,7 @@ void Cmvmi::execCLOSE_COMREQ(Signal* signal)
//-----------------------------------------------------
// Report that the connection to the node is closed
//-----------------------------------------------------
- signal->theData[0] = EventReport::CommunicationClosed;
+ signal->theData[0] = NDB_LE_CommunicationClosed;
signal->theData[1] = i;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -396,7 +397,7 @@ void Cmvmi::execOPEN_COMREQ(Signal* signal)
//-----------------------------------------------------
// Report that the connection to the node is opened
//-----------------------------------------------------
- signal->theData[0] = EventReport::CommunicationOpened;
+ signal->theData[0] = NDB_LE_CommunicationOpened;
signal->theData[1] = tStartingNode;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
//-----------------------------------------------------
@@ -408,7 +409,7 @@ void Cmvmi::execOPEN_COMREQ(Signal* signal)
globalTransporterRegistry.do_connect(i);
globalTransporterRegistry.setIOState(i, HaltIO);
- signal->theData[0] = EventReport::CommunicationOpened;
+ signal->theData[0] = NDB_LE_CommunicationOpened;
signal->theData[1] = i;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
}
@@ -433,7 +434,7 @@ void Cmvmi::execENABLE_COMORD(Signal* signal)
//-----------------------------------------------------
// Report that the version of the node
//-----------------------------------------------------
- signal->theData[0] = EventReport::ConnectedApiVersion;
+ signal->theData[0] = NDB_LE_ConnectedApiVersion;
signal->theData[1] = tStartingNode;
signal->theData[2] = getNodeInfo(tStartingNode).m_version;
@@ -475,7 +476,7 @@ void Cmvmi::execDISCONNECT_REP(Signal *signal)
cancelSubscription(hostId);
- signal->theData[0] = EventReport::Disconnected;
+ signal->theData[0] = NDB_LE_Disconnected;
signal->theData[1] = hostId;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
}
@@ -525,7 +526,7 @@ void Cmvmi::execCONNECT_REP(Signal *signal){
//------------------------------------------
// Also report this event to the Event handler
//------------------------------------------
- signal->theData[0] = EventReport::Connected;
+ signal->theData[0] = NDB_LE_Connected;
signal->theData[1] = hostId;
signal->header.theLength = 2;
diff --git a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
index 246afc5ceb8..a2d6fe4d64a 100644
--- a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
+++ b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
@@ -22,6 +22,9 @@
#include <pc.hpp>
#include <SimulatedBlock.hpp>
+// primary key is stored in TUP
+#include <Dbtup.hpp>
+
#ifdef DBACC_C
// Debug Macros
#define dbgWord32(ptr, ind, val)
@@ -98,7 +101,6 @@ ndbout << "Ptr: " << ptr.p->word32 << " \tIndex: " << tmp_string << " \tValue: "
#define ZPOS_PREV_PAGE 11
#define ZNORMAL_PAGE_TYPE 0
#define ZOVERFLOW_PAGE_TYPE 1
-#define ZLONG_PAGE_TYPE 2
#define ZDEFAULT_LIST 3
#define ZWORDS_IN_PAGE 2048
/* --------------------------------------------------------------------------------- */
@@ -132,16 +134,6 @@ ndbout << "Ptr: " << ptr.p->word32 << " \tIndex: " << tmp_string << " \tValue: "
#define ZPAGEZERO_NODETYPE 33
#define ZPAGEZERO_SLACK_CHECK 34
/* --------------------------------------------------------------------------------- */
-/* CONSTANTS FOR THE LONG KEY PAGES */
-/* --------------------------------------------------------------------------------- */
-/* --------------------------------------------------------------------------------- */
-// Maximum number of elements in long key page = (ZWORDS_IN_PAGE - ZHEAD_SIZE) /
-// (MinKeySize + IndexSize) = (2048 - 32) / (8 + 1) = 224. MinKeySize is actually 9
-// because 8 is the largest normal key size.
-#define ZMAX_NO_OF_LONGKEYS_IN_PAGE 225
-#define ZMAX_LONG_KEY_ARRAY_INDEX 3
-#define ZACTIVE_LONG_KEY_LEN 1
-/* --------------------------------------------------------------------------------- */
/* CONSTANTS IN ALPHABETICAL ORDER */
/* --------------------------------------------------------------------------------- */
#define ZADDFRAG 0
@@ -392,49 +384,6 @@ enum State {
// Records
-
-//----------------------------------------------------------------------------------
-// LONGKEY PAGE RECORD
-//
-// A long key page consist of a header part, a key data part and an index part. The
-// page starts with a header of size HEAD_SIZE. As you can see below, not every word
-// in the header is used. After the header comes the data part, where the actual
-// keys are stored. A key is always inserted after the existing keys in the data
-// part. If we have a fragmented data part and a new key doesn't fit after the
-// existing keys we reorganize the keys. The index part starts at the end of the
-// page and grows towards the end of the data part. This means that the limit
-// between the data part and the index part is floating. Each inserted key have a
-// word in the index part that describes size and position of the key in the data
-// part. The free indexes in the index part are single linked.
-//----------------------------------------------------------------------------------
- union LongKeyPage {
- struct {
- Uint32 pageId; // ZPOS_PAGE_ID 0
- Uint32 b;
- // The number of keys in page.
- Uint32 noOfElements; // ZPOS_NO_ELEM_IN_PAGE 2
- Uint32 d;
- Uint32 e;
- // The free area in the data part of page.
- Uint32 freeArea; // ZPOS_FREE_AREA_IN_PAGE 5
- // The index position, which defines the limit between the data and the index part.
- Uint32 highestIndex; // ZPOS_LAST_INDEX 6
- // The position where to insert the actual key in the data part.
- Uint32 insertPos; // ZPOS_INSERT_INDEX 7
- // Position in a page array where the pages are stored in a double linked list.
- // Based on the free area in the page. Values 0 to 3.
- Uint32 pageArrayPos; // ZPOS_ARRAY_POS 8
- // Next free position in the index part.
- Uint32 nextFreeIndex; // ZPOS_NEXT_FREE_INDEX 9
- // Next page in the double linked list.
- Uint32 nextPage; // ZPOS_NEXT_PAGE 10
- // Previous page in the double linked list.
- Uint32 prevPage; // ZPOS_PREV_PAGE 11
- } header;
- // This is kept to keep the logic and to make changes to a minimum.
- Uint32 word32[2048];
- };
-
/* --------------------------------------------------------------------------------- */
/* UNDO HEADER RECORD */
/* --------------------------------------------------------------------------------- */
@@ -444,9 +393,7 @@ enum State {
ZPAGE_INFO = 0,
ZOVER_PAGE_INFO = 1,
ZOP_INFO = 2,
- ZUNDO_INSERT_LONG_KEY = 3,
- ZUNDO_DELETE_LONG_KEY = 4,
- ZNO_UNDORECORD_TYPES = 5
+ ZNO_UNDORECORD_TYPES = 3
};
UintR tableId;
UintR rootFragId;
@@ -660,10 +607,10 @@ struct Fragmentrec {
//-----------------------------------------------------------------------------
// elementLength: Length of element in bucket and overflow pages
-// keyLength: Length of key (== 0 if long key or variable key length)
+// keyLength: Length of key
//-----------------------------------------------------------------------------
Uint8 elementLength;
- Uint8 keyLength;
+ Uint16 keyLength;
//-----------------------------------------------------------------------------
// This flag is used to avoid sending a big number of expand or shrink signals
@@ -689,6 +636,11 @@ struct Fragmentrec {
//-----------------------------------------------------------------------------
Uint8 nodetype;
Uint8 stopQueOp;
+
+//-----------------------------------------------------------------------------
+// flag to avoid accessing table record if no char attributes
+//-----------------------------------------------------------------------------
+ Uint8 hasCharAttr;
};
typedef Ptr<Fragmentrec> FragmentrecPtr;
@@ -771,6 +723,7 @@ struct Operationrec {
State transactionstate;
Uint16 elementContainer;
Uint16 tupkeylen;
+ Uint32 xfrmtupkeylen;
Uint32 userblockref;
Uint32 scanBits;
Uint8 elementIsDisappeared;
@@ -783,7 +736,7 @@ struct Operationrec {
Uint8 dirtyRead;
Uint8 commitDeleteCheckFlag;
Uint8 isAccLockReq;
- Uint32 nextOpList;
+ Uint8 isUndoLogReq;
}; /* p2c: size = 168 bytes */
typedef Ptr<Operationrec> OperationrecPtr;
@@ -898,6 +851,13 @@ struct Tabrec {
Uint32 fragptrholder[MAX_FRAG_PER_NODE];
Uint32 tabUserPtr;
BlockReference tabUserRef;
+
+ Uint8 noOfKeyAttr;
+ Uint8 hasCharAttr;
+ struct KeyAttr {
+ Uint32 attributeDescriptor;
+ CHARSET_INFO* charsetInfo;
+ } keyAttr[MAX_ATTRIBUTES_IN_INDEX];
};
typedef Ptr<Tabrec> TabrecPtr;
@@ -914,6 +874,9 @@ public:
Dbacc(const class Configuration &);
virtual ~Dbacc();
+ // pointer to TUP instance in this thread
+ Dbtup* c_tup;
+
private:
BLOCK_DEFINES(Dbacc);
@@ -940,6 +903,7 @@ private:
void execACCKEYREQ(Signal* signal);
void execACCSEIZEREQ(Signal* signal);
void execACCFRAGREQ(Signal* signal);
+ void execTC_SCHVERREQ(Signal* signal);
void execACC_SRREQ(Signal* signal);
void execNEXT_SCANREQ(Signal* signal);
void execACC_ABORTREQ(Signal* signal);
@@ -977,10 +941,8 @@ private:
void initFragGeneral(FragmentrecPtr);
void verifyFragCorrect(FragmentrecPtr regFragPtr);
void sendFSREMOVEREQ(Signal* signal, Uint32 tableId);
- void sendDROP_TABFILECONF(Signal* signal, TabrecPtr tabPtr);
void releaseFragResources(Signal* signal, Uint32 fragIndex);
void releaseRootFragRecord(Signal* signal, RootfragmentrecPtr rootPtr);
- void sendREL_TABMEMCONF(Signal* signal, TabrecPtr tabPtr);
void releaseRootFragResources(Signal* signal, Uint32 tableId);
void releaseDirResources(Signal* signal,
Uint32 fragIndex,
@@ -1056,7 +1018,6 @@ private:
void releaseScanRec(Signal* signal);
bool searchScanContainer(Signal* signal);
void sendNextScanConf(Signal* signal);
- void sendScaninfo(Signal* signal);
void setlock(Signal* signal);
void takeOutActiveScanOp(Signal* signal);
void takeOutScanLockQueue(Uint32 scanRecIndex);
@@ -1068,15 +1029,8 @@ private:
void increaselistcont(Signal* signal);
void seizeLeftlist(Signal* signal);
void seizeRightlist(Signal* signal);
- void allocLongOverflowPage(Signal* signal);
- void allocSpecificLongOverflowPage(Signal* signal);
- void getLongKeyPage(Signal* signal);
- void initLongOverpage(Signal* signal);
- void storeLongKeys(Signal* signal);
- void storeLongKeysAtPos(Signal* signal);
- void reorgLongPage(Signal* signal);
+ Uint32 readTablePk(Uint32 localkey1);
void getElement(Signal* signal);
- void searchLongKey(Signal* signal, bool verify);
void getdirindex(Signal* signal);
void commitdelete(Signal* signal, bool systemRestart);
void deleteElement(Signal* signal);
@@ -1084,15 +1038,6 @@ private:
void releaseLeftlist(Signal* signal);
void releaseRightlist(Signal* signal);
void checkoverfreelist(Signal* signal);
- void deleteLongKey(Signal* signal);
- void removeFromPageArrayList(Signal* signal);
- void insertPageArrayList(Signal* signal);
- void checkPageArrayList(Signal* signal, const char *);
- void checkPageB4Insert(Uint32, const char *);
- void checkPageB4Remove(Uint32, const char *);
- void checkIndexInLongKeyPage(Uint32, const char *);
- void printoutInfoAndShutdown(LongKeyPage *);
- void releaseLongPage(Signal* signal);
void abortOperation(Signal* signal);
void accAbortReqLab(Signal* signal, bool sendConf);
void commitOperation(Signal* signal);
@@ -1110,7 +1055,6 @@ private:
void initLcpConnRec(Signal* signal);
void initOverpage(Signal* signal);
void initPage(Signal* signal);
- void initPageZero(Signal* signal);
void initRootfragrec(Signal* signal);
void putOpInFragWaitQue(Signal* signal);
void putOverflowRecInFrag(Signal* signal);
@@ -1164,8 +1108,6 @@ private:
void refaccConnectLab(Signal* signal);
void srReadOverPagesLab(Signal* signal);
void releaseScanLab(Signal* signal);
- void exeoperationLab(Signal* signal);
- void saveKeyDataLab(Signal* signal);
void lcpOpenUndofileConfLab(Signal* signal);
void srFsOpenConfLab(Signal* signal);
void checkSyncUndoPagesLab(Signal* signal);
@@ -1177,13 +1119,12 @@ private:
void srReadPagesLab(Signal* signal);
void srDoUndoLab(Signal* signal);
void ndbrestart1Lab(Signal* signal);
- void initialiseRecordsLab(Signal* signal, Uint32 returnRef, Uint32 retData);
+ void initialiseRecordsLab(Signal* signal, Uint32 ref, Uint32 data);
void srReadPagesAllocLab(Signal* signal);
void checkNextBucketLab(Signal* signal);
void endsavepageLab(Signal* signal);
void saveZeroPageLab(Signal* signal);
void srAllocPage0011Lab(Signal* signal);
- void allocscanrecLab(Signal* signal);
void sendLcpFragidconfLab(Signal* signal);
void savepagesLab(Signal* signal);
void saveOverPagesLab(Signal* signal);
@@ -1197,6 +1138,8 @@ private:
void lcp_write_op_to_undolog(Signal* signal);
void reenable_expand_after_redo_log_exection_complete(Signal*);
+ // charsets
+ void xfrmKeyData(Signal* signal);
// Initialisation
void initData();
@@ -1286,8 +1229,6 @@ private:
/* --------------------------------------------------------------------------------- */
Page8 *page8;
/* 8 KB PAGE */
- Page8Ptr aslpPageptr;
- Page8Ptr alpPageptr;
Page8Ptr ancPageptr;
Page8Ptr colPageptr;
Page8Ptr ccoPageptr;
@@ -1298,29 +1239,17 @@ private:
Page8Ptr gdiPageptr;
Page8Ptr gePageptr;
Page8Ptr gflPageptr;
- Page8Ptr glkPageptr;
Page8Ptr idrPageptr;
Page8Ptr ilcPageptr;
- Page8Ptr iloPageptr;
Page8Ptr inpPageptr;
Page8Ptr iopPageptr;
- Page8Ptr ipzPageptr;
Page8Ptr lastPageptr;
Page8Ptr lastPrevpageptr;
Page8Ptr lcnPageptr;
Page8Ptr lcnCopyPageptr;
Page8Ptr lupPageptr;
- Page8Ptr dlkPageptr;
- Page8Ptr ipaPagePtr;
Page8Ptr priPageptr;
Page8Ptr pwiPageptr;
- Page8Ptr rfpPageptr;
- Page8Ptr relpPageptr;
- Page8Ptr rlopPageptr;
- Page8Ptr slkPageptr;
- Page8Ptr slkCopyPageptr;
- Page8Ptr slkapPageptr;
- Page8Ptr slkapCopyPageptr;
Page8Ptr ciPageidptr;
Page8Ptr gsePageidptr;
Page8Ptr isoPageptr;
@@ -1334,7 +1263,6 @@ private:
Page8Ptr ropPageptr;
Page8Ptr rpPageptr;
Page8Ptr slPageptr;
- Page8Ptr slpPageptr;
Page8Ptr spPageptr;
Uint32 cfirstfreepage;
Uint32 cfreepage;
@@ -1352,7 +1280,6 @@ private:
/* --------------------------------------------------------------------------------- */
Rootfragmentrec *rootfragmentrec;
RootfragmentrecPtr rootfragrecptr;
- RootfragmentrecPtr tmprootfrgptr;
Uint32 crootfragmentsize;
Uint32 cfirstfreerootfrag;
/* --------------------------------------------------------------------------------- */
@@ -1385,7 +1312,6 @@ private:
Uint32 tpriElementptr;
Uint32 tgseElementptr;
Uint32 tgseContainerptr;
- Uint32 tiloIndex;
Uint32 trlHead;
Uint32 trlRelCon;
Uint32 trlNextused;
@@ -1394,20 +1320,12 @@ private:
Uint32 tlupElemIndex;
Uint32 tlupIndex;
Uint32 tlupForward;
- Uint32 tslkPageIndex;
- Uint32 tslkKeyLen;
- Uint32 tslkapKeyLen;
- Uint32 tslkapPageIndex;
- Uint32 tipaArrayPos;
- Uint32 trfpArrayPos;
- Uint32 tdlkLogicalPageIndex;
Uint32 tancNext;
Uint32 tancBufType;
Uint32 tancContainerptr;
Uint32 tancPageindex;
Uint32 tancPageid;
Uint32 tidrResult;
- Uint32 tidrKeyLen;
Uint32 tidrElemhead;
Uint32 tidrForward;
Uint32 tidrPageindex;
@@ -1425,15 +1343,11 @@ private:
Uint32 tdelForward;
Uint32 tiopPageId;
Uint32 tipPageId;
- Uint32 ttupKeyLength;
Uint32 tgeLocked;
Uint32 tgeResult;
Uint32 tgeContainerptr;
Uint32 tgeElementptr;
Uint32 tgeForward;
- Uint32 tslcResult;
- Uint32 tslcPagedir;
- Uint32 tslcPageIndex;
Uint32 tundoElemIndex;
Uint32 texpReceivedBucket;
Uint32 texpDirInd;
@@ -1458,7 +1372,6 @@ private:
Uint32 tscanFlag;
Uint32 theadundoindex;
Uint32 tgflBufType;
- Uint32 thashvalue;
Uint32 tgseIsforward;
Uint32 tsscIsforward;
Uint32 trscIsforward;
@@ -1467,21 +1380,10 @@ private:
Uint32 tisoIsforward;
Uint32 tgseIsLocked;
Uint32 tsscIsLocked;
- Uint32 tkey1;
- Uint32 tkey2;
- Uint32 tkey3;
- Uint32 tkey4;
Uint32 tkeylen;
- Uint32 tkSize;
- Uint32 tlhfragbits;
- Uint32 tlhdirbits;
- Uint32 tlocalkeylen;
- Uint32 tmaxloadfactor;
- Uint32 tminloadfactor;
Uint32 tmp;
Uint32 tmpP;
Uint32 tmpP2;
- Uint32 taslpDirIndex;
Uint32 tmp1;
Uint32 tmp2;
Uint32 tgflPageindex;
@@ -1495,9 +1397,6 @@ private:
Uint32 trsbPageindex;
Uint32 tnciPageindex;
Uint32 tlastPrevconptr;
- Uint32 treqinfo;
- Uint32 transactionid1;
- Uint32 transactionid2;
Uint32 tresult;
Uint32 tslUpdateHeader;
Uint32 tuserptr;
@@ -1510,15 +1409,12 @@ private:
Uint32 tgdiPageindex;
Uint32 tiopIndex;
Uint32 tnciTmp;
- Uint32 tlenKeyinfo;
Uint32 tullIndex;
Uint32 turlIndex;
Uint32 tlfrTmp1;
Uint32 tlfrTmp2;
- Uint32 tudqeIndex;
Uint32 tscanTrid1;
Uint32 tscanTrid2;
- Uint32 taccscanTmp;
Uint16 clastUndoPageIdWritten;
Uint32 cactiveCheckpId;
@@ -1562,10 +1458,13 @@ private:
Uint32 cexcPrevpageindex;
Uint32 cexcPrevforward;
Uint32 clocalkey[32];
+ union {
Uint32 ckeys[2048];
+ Uint64 ckeys_align;
+ };
Uint32 c_errorInsert3000_TableId;
- Uint32 cSrUndoRecords[5];
+ Uint32 cSrUndoRecords[UndoHeader::ZNO_UNDORECORD_TYPES];
};
#endif
diff --git a/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp b/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp
index 95b336a0a65..94782e13e00 100644
--- a/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp
+++ b/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp
@@ -133,7 +133,8 @@ void Dbacc::initRecords()
}//Dbacc::initRecords()
Dbacc::Dbacc(const class Configuration & conf):
- SimulatedBlock(DBACC, conf)
+ SimulatedBlock(DBACC, conf),
+ c_tup(0)
{
Uint32 log_page_size= 0;
BLOCK_CONSTRUCTOR(Dbacc);
@@ -178,6 +179,7 @@ Dbacc::Dbacc(const class Configuration & conf):
addRecSignal(GSN_ACCKEYREQ, &Dbacc::execACCKEYREQ);
addRecSignal(GSN_ACCSEIZEREQ, &Dbacc::execACCSEIZEREQ);
addRecSignal(GSN_ACCFRAGREQ, &Dbacc::execACCFRAGREQ);
+ addRecSignal(GSN_TC_SCHVERREQ, &Dbacc::execTC_SCHVERREQ);
addRecSignal(GSN_ACC_SRREQ, &Dbacc::execACC_SRREQ);
addRecSignal(GSN_NEXT_SCANREQ, &Dbacc::execNEXT_SCANREQ);
addRecSignal(GSN_ACC_ABORTREQ, &Dbacc::execACC_ABORTREQ);
diff --git a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
index 44c891fc220..0054b935cdb 100644
--- a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
+++ b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
@@ -16,6 +16,7 @@
#define DBACC_C
#include "Dbacc.hpp"
+#include <my_sys.h>
#include <AttributeHeader.hpp>
#include <signaldata/AccFrag.hpp>
@@ -27,6 +28,7 @@
#include <signaldata/FsRemoveReq.hpp>
#include <signaldata/DropTab.hpp>
#include <signaldata/DumpStateOrd.hpp>
+#include <SectionReader.hpp>
// TO_DO_RONM is a label for comments on what needs to be improved in future versions
// when more time is given.
@@ -570,7 +572,14 @@ void Dbacc::execNDB_STTOR(Signal* signal)
void Dbacc::execSTTOR(Signal* signal)
{
jamEntry();
- // tstartphase = signal->theData[1];
+ Uint32 tstartphase = signal->theData[1];
+ switch (tstartphase) {
+ case 1:
+ jam();
+ c_tup = (Dbtup*)globalData.getBlock(DBTUP);
+ ndbrequire(c_tup != 0);
+ break;
+ }
tuserblockref = signal->theData[3];
csignalkey = signal->theData[6];
sttorrysignalLab(signal);
@@ -1026,6 +1035,12 @@ void Dbacc::initialiseTableRec(Signal* signal)
tabptr.p->fragholder[i] = RNIL;
tabptr.p->fragptrholder[i] = RNIL;
}//for
+ tabptr.p->noOfKeyAttr = 0;
+ tabptr.p->hasCharAttr = 0;
+ for (Uint32 k = 0; k < MAX_ATTRIBUTES_IN_INDEX; k++) {
+ tabptr.p->keyAttr[k].attributeDescriptor = 0;
+ tabptr.p->keyAttr[k].charsetInfo = 0;
+ }
}//for
}//Dbacc::initialiseTableRec()
@@ -1073,7 +1088,7 @@ void Dbacc::execACCFRAGREQ(Signal* signal)
// config mismatch - do not crash if release compiled
if (tabptr.i >= ctablesize) {
jam();
- addFragRefuse(signal, 800);
+ addFragRefuse(signal, 640);
return;
}
#endif
@@ -1181,6 +1196,66 @@ void Dbacc::addFragRefuse(Signal* signal, Uint32 errorCode)
}//Dbacc::addFragRefuseEarly()
void
+Dbacc::execTC_SCHVERREQ(Signal* signal)
+{
+ jamEntry();
+ if (! assembleFragments(signal)) {
+ jam();
+ return;
+ }
+ tabptr.i = signal->theData[0];
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+ Uint32 noOfKeyAttr = signal->theData[6];
+ ndbrequire(noOfKeyAttr <= MAX_ATTRIBUTES_IN_INDEX);
+ Uint32 hasCharAttr = 0;
+
+ SegmentedSectionPtr s0Ptr;
+ signal->getSection(s0Ptr, 0);
+ SectionReader r0(s0Ptr, getSectionSegmentPool());
+ Uint32 i = 0;
+ while (i < noOfKeyAttr) {
+ jam();
+ Uint32 attributeDescriptor = ~0;
+ Uint32 csNumber = ~0;
+ if (! r0.getWord(&attributeDescriptor) ||
+ ! r0.getWord(&csNumber)) {
+ jam();
+ break;
+ }
+ CHARSET_INFO* cs = 0;
+ if (csNumber != 0) {
+ cs = all_charsets[csNumber];
+ ndbrequire(cs != 0);
+ hasCharAttr = 1;
+ }
+ tabptr.p->keyAttr[i].attributeDescriptor = attributeDescriptor;
+ tabptr.p->keyAttr[i].charsetInfo = cs;
+ i++;
+ }
+ ndbrequire(i == noOfKeyAttr);
+ releaseSections(signal);
+
+ tabptr.p->noOfKeyAttr = noOfKeyAttr;
+ tabptr.p->hasCharAttr = hasCharAttr;
+
+ // copy char attr flag to each fragment
+ for (Uint32 i1 = 0; i1 < MAX_FRAG_PER_NODE; i1++) {
+ jam();
+ if (tabptr.p->fragptrholder[i1] != RNIL) {
+ rootfragrecptr.i = tabptr.p->fragptrholder[i1];
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
+ for (Uint32 i2 = 0; i2 < 2; i2++) {
+ fragrecptr.i = rootfragrecptr.p->fragmentptr[i2];
+ ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
+ fragrecptr.p->hasCharAttr = hasCharAttr;
+ }
+ }
+ }
+
+ // no reply to DICT
+}
+
+void
Dbacc::execDROP_TAB_REQ(Signal* signal){
jamEntry();
DropTabReq* req = (DropTabReq*)signal->getDataPtr();
@@ -1543,6 +1618,7 @@ void Dbacc::initOpRec(Signal* signal)
operationRecPtr.p->hashValue = signal->theData[3];
operationRecPtr.p->tupkeylen = signal->theData[4];
+ operationRecPtr.p->xfrmtupkeylen = signal->theData[4];
operationRecPtr.p->transId1 = signal->theData[5];
operationRecPtr.p->transId2 = signal->theData[6];
operationRecPtr.p->transactionstate = ACTIVE;
@@ -1581,6 +1657,9 @@ void Dbacc::initOpRec(Signal* signal)
// bit to mark lock operation
operationRecPtr.p->isAccLockReq = (Treqinfo >> 31) & 0x1;
+
+ // undo log is not run via ACCKEYREQ
+ operationRecPtr.p->isUndoLogReq = 0;
}//Dbacc::initOpRec()
/* --------------------------------------------------------------------------------- */
@@ -1654,6 +1733,10 @@ void Dbacc::execACCKEYREQ(Signal* signal)
ndbrequire(operationRecPtr.p->transactionstate == IDLE);
initOpRec(signal);
+ // normalize key if any char attr
+ if (! operationRecPtr.p->isAccLockReq && fragrecptr.p->hasCharAttr)
+ xfrmKeyData(signal);
+
/*---------------------------------------------------------------*/
/* */
/* WE WILL USE THE HASH VALUE TO LOOK UP THE PROPER MEMORY */
@@ -1748,6 +1831,60 @@ void Dbacc::execACCKEYREQ(Signal* signal)
return;
}//Dbacc::execACCKEYREQ()
+void
+Dbacc::xfrmKeyData(Signal* signal)
+{
+ tabptr.i = fragrecptr.p->myTableId;
+ ptrCheckGuard(tabptr, ctablesize, tabrec);
+
+ Uint32 dst[1024 * MAX_XFRM_MULTIPLY];
+ Uint32 dstSize = (sizeof(dst) >> 2);
+ Uint32* src = &signal->theData[7];
+ const Uint32 noOfKeyAttr = tabptr.p->noOfKeyAttr;
+ Uint32 dstPos = 0;
+ Uint32 srcPos = 0;
+ Uint32 i = 0;
+
+ while (i < noOfKeyAttr) {
+ const Tabrec::KeyAttr& keyAttr = tabptr.p->keyAttr[i];
+
+ Uint32 srcBytes = AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor);
+ Uint32 srcWords = (srcBytes + 3) / 4;
+ Uint32 dstWords = ~0;
+ uchar* dstPtr = (uchar*)&dst[dstPos];
+ const uchar* srcPtr = (const uchar*)&src[srcPos];
+ CHARSET_INFO* cs = keyAttr.charsetInfo;
+
+ if (cs == 0) {
+ jam();
+ memcpy(dstPtr, srcPtr, srcWords << 2);
+ dstWords = srcWords;
+ } else {
+ jam();
+ Uint32 typeId = AttributeDescriptor::getType(keyAttr.attributeDescriptor);
+ Uint32 lb, len;
+ bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len);
+ ndbrequire(ok);
+ Uint32 xmul = cs->strxfrm_multiply;
+ if (xmul == 0)
+ xmul = 1;
+ // see comment in DbtcMain.cpp
+ Uint32 dstLen = xmul * (srcBytes - lb);
+ ndbrequire(dstLen <= ((dstSize - dstPos) << 2));
+ int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len);
+ ndbrequire(n != -1);
+ while ((n & 3) != 0)
+ dstPtr[n++] = 0;
+ dstWords = (n >> 2);
+ }
+ dstPos += dstWords;
+ srcPos += srcWords;
+ i++;
+ }
+ memcpy(src, dst, dstPos << 2);
+ operationRecPtr.p->xfrmtupkeylen = dstPos;
+}
+
void Dbacc::accIsLockedLab(Signal* signal)
{
ndbrequire(csystemRestart == ZFALSE);
@@ -1821,8 +1958,6 @@ void Dbacc::insertExistElemLab(Signal* signal)
/* --------------------------------------------------------------------------------- */
void Dbacc::insertelementLab(Signal* signal)
{
- Uint32 tinsKeyLen;
-
if (fragrecptr.p->createLcp == ZTRUE) {
if (remainingUndoPages() < ZMIN_UNDO_PAGES_AT_OPERATION) {
jam();
@@ -1840,46 +1975,9 @@ void Dbacc::insertelementLab(Signal* signal)
}//if
}//if
if (fragrecptr.p->keyLength != operationRecPtr.p->tupkeylen) {
+ // historical
ndbrequire(fragrecptr.p->keyLength == 0);
}//if
- if (fragrecptr.p->keyLength != 0) {
- ndbrequire(operationRecPtr.p->tupkeylen <= 8);
- for (Uint32 i = 0; i < operationRecPtr.p->tupkeylen; i++) {
- jam();
- ckeys[i] = signal->theData[i + 7];
- }//for
- tinsKeyLen = operationRecPtr.p->tupkeylen;
- } else {
- jam();
- seizePage(signal);
- if (tresult > ZLIMIT_OF_ERROR) {
- jam();
- acckeyref1Lab(signal, tresult);
- return;
- }//if
- operationRecPtr.p->keyinfoPage = spPageptr.i;
- for (Uint32 i = 0; i < signal->theData[4]; i++) {
- spPageptr.p->word32[i] = signal->theData[i + 7];
- }//for
-
- getLongKeyPage(signal);
- if (tresult > ZLIMIT_OF_ERROR) {
- jam();
- acckeyref1Lab(signal, tresult);
- return;
- }//if
- slkPageptr = glkPageptr;
- slkCopyPageptr.i = operationRecPtr.p->keyinfoPage;
- ptrCheckGuard(slkCopyPageptr, cpagesize, page8);
- tslkKeyLen = operationRecPtr.p->tupkeylen;
- storeLongKeys(signal);
- ckeys[0] = (slkPageptr.p->word32[ZPOS_PAGE_ID] << 10) + tslkPageIndex;
- tinsKeyLen = ZACTIVE_LONG_KEY_LEN;
- rpPageptr.i = operationRecPtr.p->keyinfoPage;
- ptrCheckGuard(rpPageptr, cpagesize, page8);
- releasePage(signal);
- operationRecPtr.p->keyinfoPage = RNIL;
- }//if
signal->theData[0] = operationRecPtr.p->userptr;
Uint32 blockNo = refToBlock(operationRecPtr.p->userblockref);
@@ -1903,7 +2001,6 @@ void Dbacc::insertelementLab(Signal* signal)
idrPageptr = gdiPageptr;
tidrPageindex = tgdiPageindex;
tidrForward = ZTRUE;
- tidrKeyLen = tinsKeyLen;
idrOperationRecPtr = operationRecPtr;
clocalkey[0] = localKey;
operationRecPtr.p->localdata[0] = localKey;
@@ -2343,14 +2440,14 @@ void Dbacc::execACC_COMMITREQ(Signal* signal)
operationRecPtr.p->transactionstate = IDLE;
operationRecPtr.p->operation = ZUNDEFINED_OP;
if(Toperation != ZREAD){
+ rootfragrecptr.i = fragrecptr.p->myroot;
+ ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
rootfragrecptr.p->m_commit_count++;
if (Toperation != ZINSERT) {
if (Toperation != ZDELETE) {
return;
} else {
jam();
- rootfragrecptr.i = fragrecptr.p->myroot;
- ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
rootfragrecptr.p->noOfElements--;
fragrecptr.p->slack += operationRecPtr.p->insertDeleteLen;
if (fragrecptr.p->slack > fragrecptr.p->slackCheck) {
@@ -2370,8 +2467,6 @@ void Dbacc::execACC_COMMITREQ(Signal* signal)
}//if
} else {
jam(); /* EXPAND PROCESS HANDLING */
- rootfragrecptr.i = fragrecptr.p->myroot;
- ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec);
rootfragrecptr.p->noOfElements++;
fragrecptr.p->slack -= operationRecPtr.p->insertDeleteLen;
if (fragrecptr.p->slack >= (1u << 31)) {
@@ -2489,6 +2584,7 @@ void Dbacc::execACC_LOCKREQ(Signal* signal)
signal->theData[4] = 1; // fake primKeyLen
signal->theData[5] = req->transId1;
signal->theData[6] = req->transId2;
+ // enter local key in place of PK
signal->theData[7] = req->tupAddr;
EXECUTE_DIRECT(DBACC, GSN_ACCKEYREQ, signal, 8);
// translate the result
@@ -2513,26 +2609,6 @@ void Dbacc::execACC_LOCKREQ(Signal* signal)
*sig = *req;
return;
}
- operationRecPtr.i = req->accOpPtr;
- ptrCheckGuard(operationRecPtr, coprecsize, operationrec);
- fragrecptr.i = operationRecPtr.p->fragptr;
- ptrCheckGuard(fragrecptr, cfragmentsize, fragmentrec);
- if (fragrecptr.p->keyLength == 0 &&
- // should test some state variable
- operationRecPtr.p->elementPage != RNIL) {
- jam();
- // re-compute long key vars
- Page8Ptr tPageptr;
- tPageptr.i = operationRecPtr.p->elementPage;
- ptrCheckGuard(tPageptr, cpagesize, page8);
- Uint32 tKeyptr =
- operationRecPtr.p->elementPointer +
- operationRecPtr.p->elementIsforward *
- (ZELEM_HEAD_SIZE + fragrecptr.p->localkeylen);
- tslcPageIndex = tPageptr.p->word32[tKeyptr] & 0x3ff;
- tslcPagedir = tPageptr.p->word32[tKeyptr] >> 10;
- searchLongKey(signal, false);
- }
if (lockOp == AccLockReq::Unlock) {
jam();
// do unlock via ACC_COMMITREQ (immediate)
@@ -2886,14 +2962,6 @@ void Dbacc::insertContainer(Signal* signal)
idrPageptr.p->word32[tidrIndex] = clocalkey[tidrInputIndex]; /* INSERTS LOCALKEY */
tidrIndex += tidrForward;
}//for
- guard26 = tidrKeyLen - 1;
- arrGuard(guard26, 8);
- for (tidrInputIndex = 0; tidrInputIndex <= guard26; tidrInputIndex++) {
- dbgWord32(idrPageptr, tidrIndex, ckeys[tidrInputIndex]);
- arrGuard(tidrIndex, 2048);
- idrPageptr.p->word32[tidrIndex] = ckeys[tidrInputIndex]; /* INSERTS TUPLE KEY */
- tidrIndex += tidrForward;
- }//for
tidrContLen = idrPageptr.p->word32[tidrContainerptr] << 6;
tidrContLen = tidrContLen >> 6;
dbgWord32(idrPageptr, tidrContainerptr, (tidrContainerlen << 26) | tidrContLen);
@@ -3227,1215 +3295,6 @@ void Dbacc::seizeRightlist(Signal* signal)
increaselistcont(signal);
}//Dbacc::seizeRightlist()
-
-//---------------------------------------------------------------------------------
-// ALLOC_SPECIFIC_LONG_OVERFLOW_PAGE
-//
-// DESCRIPTION: ALLOCATES A LONG OVER FLOW PAGE AND PUTS IT IN A SPECIFIED
-// DIRINDEX. THIS IS TO SUPPORT AN UNDO_DELETE AFTER AN
-// UNDO_INSERT ON THE SAME LONG KEY IN A LCP.
-// UNDO_INSERT ONLY HAVE A REFERENCE TO THE KEY AND TO MAKE
-// IT POSSIBLE TO DELETE THE KEY, THE REFERENCE MUST BE
-// ACCURATE, WHICH MEANS THE KEY MUST BE SAVED ON THE SAME
-// PLACE IT WAS DELETED FROM.
-//---------------------------------------------------------------------------------
-void Dbacc::allocSpecificLongOverflowPage(Signal* signal)
-{
- DirRangePtr aloDirRangePtr;
- DirectoryarrayPtr aloOverflowDirptr;
-
- if ((cfirstfreepage == RNIL) &&
- (cfreepage >= cpagesize)) {
- jam();
- zpagesize_error("Dbacc::allocSpecificLongOverflowPage");
- tresult = ZPAGESIZE_ERROR;
- return;
- }
-
- if ((cfirstfreedir == RNIL) &&
- (cdirarraysize <= cdirmemory)) {
- jam();
- tresult = ZDIRSIZE_ERROR;
- return;
- }
-
- tmpP = taslpDirIndex;
- aloDirRangePtr.i = fragrecptr.p->overflowdir;
- tmpP2 = tmpP >> 8;
- tmpP = tmpP & 0xff;
- ptrCheckGuard(aloDirRangePtr, cdirrangesize, dirRange);
- arrGuard(tmpP2, 256);
-
- if (aloDirRangePtr.p->dirArray[tmpP2] == RNIL) {
- jam();
- seizeDirectory(signal);
- if (tresult > ZLIMIT_OF_ERROR) {
- jam();
- sendSystemerror(signal);
- return;
- }
- aloDirRangePtr.p->dirArray[tmpP2] = sdDirptr.i;
- } else {
- jam();
- sdDirptr.i = RNIL;
- ptrNull(sdDirptr);
- }
-
- aloOverflowDirptr.i = aloDirRangePtr.p->dirArray[tmpP2];
- ptrCheckGuard(aloOverflowDirptr, cdirarraysize, directoryarray);
- seizePage(signal);
- if (tresult > ZLIMIT_OF_ERROR) {
- jam();
- sendSystemerror(signal);
- return;
- }//if
-
- if (aloOverflowDirptr.p->pagep[tmpP] != RNIL) {
- jam();
- sendSystemerror(signal);
- return;
- }
-
- aloOverflowDirptr.p->pagep[tmpP] = spPageptr.i;
- iloPageptr.p = spPageptr.p;
- iloPageptr.i = spPageptr.i;
- tiloIndex = taslpDirIndex;
- initLongOverpage(signal);
- aslpPageptr.i = spPageptr.i;
- aslpPageptr.p = spPageptr.p;
-}//Dbacc::allocSpecificLongOverflowPage
-
-/* --------------------------------------------------------------------------------- */
-/* ALLOC_LONG_OVERFLOW_PAGE */
-/* DESCRIPTION: */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::allocLongOverflowPage(Signal* signal)
-{
- DirRangePtr aloDirRangePtr;
- DirectoryarrayPtr aloOverflowDirptr;
- OverflowRecordPtr aloOverflowRecPtr;
- Uint32 taloIndex;
-
- if ((cfirstfreepage == RNIL) &&
- (cfreepage >= cpagesize)) {
- jam();
- zpagesize_error("Dbacc::allocLongOverflowPage");
- tresult = ZPAGESIZE_ERROR;
- return;
- }//if
- if ((cfirstfreedir == RNIL) &&
- (cdirarraysize <= cdirmemory)) {
- jam();
- tresult = ZDIRSIZE_ERROR;
- return;
- }//if
- if (fragrecptr.p->firstFreeDirindexRec != RNIL) {
- jam();
- aloOverflowRecPtr.i = fragrecptr.p->firstFreeDirindexRec;
- ptrCheckGuard(aloOverflowRecPtr, coverflowrecsize, overflowRecord);
- troOverflowRecPtr.p = aloOverflowRecPtr.p;
- takeRecOutOfFreeOverdir(signal);
- taloIndex = aloOverflowRecPtr.p->dirindex;
- rorOverflowRecPtr = aloOverflowRecPtr;
- releaseOverflowRec(signal);
- } else {
- jam();
- taloIndex = fragrecptr.p->lastOverIndex;
- fragrecptr.p->lastOverIndex++;
- }//if
- tmpP = taloIndex;
- aloDirRangePtr.i = fragrecptr.p->overflowdir;
- tmpP2 = tmpP >> 8;
- tmpP = tmpP & 0xff;
- ptrCheckGuard(aloDirRangePtr, cdirrangesize, dirRange);
- arrGuard(tmpP2, 256);
- if (aloDirRangePtr.p->dirArray[tmpP2] == RNIL) {
- jam();
- seizeDirectory(signal);
- ndbrequire(tresult <= ZLIMIT_OF_ERROR);
- aloDirRangePtr.p->dirArray[tmpP2] = sdDirptr.i;
- } else {
- jam();
- sdDirptr.i = RNIL;
- ptrNull(sdDirptr);
- }//if
- aloOverflowDirptr.i = aloDirRangePtr.p->dirArray[tmpP2];
- ptrCheckGuard(aloOverflowDirptr, cdirarraysize, directoryarray);
- seizePage(signal);
- ndbrequire(tresult <= ZLIMIT_OF_ERROR);
- aloOverflowDirptr.p->pagep[tmpP] = spPageptr.i;
- iloPageptr = spPageptr;
- tiloIndex = taloIndex;
- initLongOverpage(signal);
- alpPageptr = spPageptr;
- ipaPagePtr = spPageptr;
- tipaArrayPos = 3;
- insertPageArrayList(signal);
-}//Dbacc::allocLongOverflowPage()
-
-/* --------------------------------------------------------------------------------- */
-/* GET_LONG_KEY_PAGE */
-/* DESCRIPTION: SEARCH FOR A FREE OVERFLOW PAGE TO STORE A LONG KEY. */
-/* LONG_KEY_PAGE_PTR IS RETURNED. */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::getLongKeyPage(Signal* signal)
-{
- LongKeyPage *glkPage;
-
- jam();
-
- Uint32 tglkLongIndex = 0;
-
- ndbrequire(operationRecPtr.p->tupkeylen <= ZWORDS_IN_PAGE - ZHEAD_SIZE);
-
- // Do not look in longKeyPageArray[tglkLongIndex] where the pages are to small.
- if(operationRecPtr.p->tupkeylen < 128) {
- jam();
- tglkLongIndex = 0;
- } else {
- jam();
- tglkLongIndex = (operationRecPtr.p->tupkeylen - 128) / 512;
- }//if
-
- // Go through the longKeyPageArray and search for a page.
- for (; tglkLongIndex <= ZMAX_LONG_KEY_ARRAY_INDEX; tglkLongIndex++) {
- jam();
- glkPageptr.i = fragrecptr.p->longKeyPageArray[tglkLongIndex];
-
- if (glkPageptr.i != RNIL) {
- // A page is found.
- jam();
- do {
- ptrCheckGuard(glkPageptr, cpagesize, page8);
- glkPage = (LongKeyPage *) &glkPageptr.p->word32[0];
-
- // Check page if there is enough memory available. Accept only page
- // with free_area > tupkeylen, this leaves at least one word for eventually
- // an increase in the index area.
- if (glkPage->header.freeArea > operationRecPtr.p->tupkeylen){
- // The page found is OK
- jam();
- return;
- } else {
- // Not enough space in page, look in the next page if not RNIL,
- // otherwise continue with for-loop.
- jam();
- glkPageptr.i = glkPage->header.nextPage;
- }
- }//do
- while (glkPageptr.i != RNIL);
- }//if
- }//for
-
- // No page with enough space was available, allocate a new page!
- jam();
- allocLongOverflowPage(signal);
- glkPageptr = alpPageptr;
-}//Dbacc::getLongKeyPage()
-
-/* --------------------------------------------------------------------------------- */
-/* INIT_LONG_OVERPAGE */
-/* INPUT. ILO_PAGEPTR, POINTER TO AN OVERFLOW PAGE RECORD */
-/* DESCRIPTION: CONTAINERS AND FREE LISTS OF THE PAGE, GET INITIALE VALUE */
-/* ACCORDING TO LH3 AND PAGE STRUCTOR DISACRIPTION OF NDBACC BLOCK */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::initLongOverpage(Signal* signal)
-{
- iloPageptr.p->word32[ZPOS_PAGE_ID] = tiloIndex;
- iloPageptr.p->word32[ZPOS_PAGE_TYPE] = ZLONG_PAGE_TYPE << ZPOS_PAGE_TYPE_BIT;
- iloPageptr.p->word32[ZPOS_NO_ELEM_IN_PAGE] = 0;
- iloPageptr.p->word32[ZPOS_OVERFLOWREC] = RNIL;
- iloPageptr.p->word32[ZPOS_FREE_AREA_IN_PAGE] = ZWORDS_IN_PAGE - ZHEAD_SIZE;
- iloPageptr.p->word32[ZPOS_LAST_INDEX] = 0;
- iloPageptr.p->word32[ZPOS_INSERT_INDEX] = ZHEAD_SIZE;
- iloPageptr.p->word32[ZPOS_ARRAY_POS] = ZDEFAULT_LIST;
- iloPageptr.p->word32[ZPOS_NEXT_FREE_INDEX] = 0;
- iloPageptr.p->word32[ZPOS_NEXT_PAGE] = RNIL;
- iloPageptr.p->word32[ZPOS_PREV_PAGE] = RNIL;
- iloPageptr.p->word32[12] = 0;
- iloPageptr.p->word32[13] = 0;
- iloPageptr.p->word32[14] = 0;
- iloPageptr.p->word32[15] = 0;
- // Initialize free indexes
- for (int i = 1; i < (ZWORDS_IN_PAGE - ZHEAD_SIZE); i++)
- iloPageptr.p->word32[ZWORDS_IN_PAGE - i] = i + 1;
-}//Dbacc::initLongOverpage()
-
-//---------------------------------------------------------------------------------
-// STORE_LONG_KEYS_AT_POS
-//
-// INPUT: SLKAP_PAGEPTR
-// SLKAP_COPY_PAGEPTR
-// TSLKAP_KEY_LEN
-// TSLKAP_PAGE_INDEX
-//
-// DESCRIPTION: A LONG ELEMENT IS STORED ON A LONG_KEY_PAGE AT A
-// SPECIFIC POSITION. THIS FUNCTION IS USED BY UNDO_DELETE.
-//---------------------------------------------------------------------------------
-void Dbacc::storeLongKeysAtPos(Signal* signal)
-{
- Uint32 tslkapHighestIndex;
- Uint32 tslkapLastSize;
- Uint32 tslkapInsertIndex;
- Uint32 tslkapIndexIncreaseSize;
- Uint32 tslkapTmp;
-
- LongKeyPage *slkapPage;
-
- jam();
- slkapPage = (LongKeyPage *) &slkapPageptr.p->word32[0];
-
-#ifdef VM_TRACE
- checkIndexInLongKeyPage(slkapPageptr.i, "storeLongKeysAtPos");
-#endif
-
- // if (csystemRestart != ZTRUE) {
- if (cundoLogActive != ZTRUE) {
- //-------------------------------------------------------------
- // This function is only allowed to be called during
- // undolog execution.
- //-------------------------------------------------------------
- jam();
- sendSystemerror(signal);
- return;
- }
-
- if (slkapPage->word32[ZWORDS_IN_PAGE - tslkapPageIndex] >> 16 != 0 ) {
- //-------------------------------------------------------------
- // The index should be empty, we have a serious problem.
- //-------------------------------------------------------------
- jam();
- sendSystemerror(signal);
- return;
- }
-
- //-------------------------------------------------------------
- // Calculate some variables to use later.
- //-------------------------------------------------------------
- tslkapHighestIndex = slkapPage->header.highestIndex;
- tslkapPageIndex > tslkapHighestIndex ?
- tslkapIndexIncreaseSize = tslkapPageIndex - tslkapHighestIndex :
- tslkapIndexIncreaseSize = 0;
-
- slkapPage->header.highestIndex += tslkapIndexIncreaseSize;
-
- if ((slkapPage->header.freeArea - tslkapIndexIncreaseSize)
- < tslkapKeyLen) {
- //-------------------------------------------------------------
- // Not enough area in the page, a serious problem.
- //-------------------------------------------------------------
- jam();
- sendSystemerror(signal);
- return;
- }
-
- //-------------------------------------------------------------
- // Fix the free index list. We might put in a key in the
- // middle of the list, so we must fix the free list and the
- // free index pointers.
- //-------------------------------------------------------------
- slkapPage->header.nextFreeIndex = 0;
-
- for (Uint32 i = tslkapHighestIndex + tslkapIndexIncreaseSize; i > 0; i--) {
- if (i == tslkapPageIndex) {
- // The key index shall not be in the free list.
- continue;
- }
-
- if (slkapPage->word32[ZWORDS_IN_PAGE - i] >> 16 == 0 ) {
- // Go through all empty indexes.
- slkapPage->word32[ZWORDS_IN_PAGE - i] = slkapPage->header.nextFreeIndex;
- arrGuard(i, 2048);
- slkapPage->header.nextFreeIndex = i;
- }
- }
-
- //-------------------------------------------------------------
- // Decrement the free area in page according to the above
- // increase in index size.
- //-------------------------------------------------------------
- slkapPage->header.freeArea -= tslkapIndexIncreaseSize;
-
- tslkapLastSize = ZWORDS_IN_PAGE - slkapPage->header.highestIndex
- - slkapPage->header.insertPos;
-
- //-------------------------------------------------------------
- // Check if we have to reorganize the page.
- //-------------------------------------------------------------
- if (tslkapLastSize >= tslkapKeyLen) {
- jam();
- } else {
- jam();
- relpPageptr.p = slkapPageptr.p;
- reorgLongPage(signal);
- }
-
- //-------------------------------------------------------------
- // Insert the key and update page attributes.
- //-------------------------------------------------------------
- jam();
- // Increase the number of element in the page.
- slkapPage->header.noOfElements++;
- jam();
- // Put in the key reference into the index. The reference
- // consists of key length and insert position.
- arrGuard(ZWORDS_IN_PAGE - tslkapPageIndex, 2048);
- slkapPage->word32[ZWORDS_IN_PAGE - tslkapPageIndex] =
- slkapPage->header.insertPos | (tslkapKeyLen << 16);
- jam();
- // Increase the key insert position.
- tslkapInsertIndex = slkapPage->header.insertPos;
- slkapPage->header.insertPos += tslkapKeyLen;
- jam();
- // Decrease the free area.
- slkapPage->header.freeArea -= tslkapKeyLen;
- jam();
-
- // Update pageArrayPos. insertPageArrayList() called from execACC_OVER_REC
- // needs this value.
- if (slkapPage->header.freeArea < 128) {
- jam();
- slkapPage->header.pageArrayPos = 4;
- } else {
- jam();
- slkapPage->header.pageArrayPos = (slkapPage->header.freeArea - 128) / 512;
- }//if
-
- // Store the actual key at the insert position.
- Uint32 guard27 = tslkapKeyLen - 1;
- arrGuard(guard27 + tslkapInsertIndex, 2048);
- for (tslkapTmp = 0; tslkapTmp <= guard27; tslkapTmp++) {
- jam();
- slkapPage->word32[tslkapTmp + tslkapInsertIndex] = slkapCopyPageptr.p->word32[tslkapTmp];
- }//for
-}//Dbacc::storeLongKeysAtPos
-
-/* --------------------------------------------------------------------------------- */
-/* STORE_LONG_KEYS */
-/* INPUT: SLK_PAGEPTR */
-/* SLK_COPY_PAGEPTR */
-/* TSLK_KEY_LEN */
-/* OUTPUT: TSLK_PAGE_INDEX */
-/* */
-/* DESCRIPTION: A LONG ELEMENT IS STORED ON A LONG_KEY_PAGE. */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::storeLongKeys(Signal* signal)
-{
- Uint32 tslkLastSize;
- Uint32 tslkInsertIndex;
- Uint32 tslkArrayPos;
- Uint32 tslkTmp;
- Uint32 guard27;
- LongKeyPage *slkPage;
-
- jam();
- slkPage = (LongKeyPage *) &slkPageptr.p->word32[0];
-
-#ifdef VM_TRACE
- checkIndexInLongKeyPage(slkPageptr.i, "storeLongKeys1");
-#endif
-
- // Accept only page with free_area > tupkeylen, this leaves at least
- // one word for eventually an increase in the index area.
- ndbrequire(slkPage->header.freeArea > tslkKeyLen);
-
- dbgWord32(slkPageptr, ZPOS_LAST_INDEX, slkPage->header.highestIndex);
- dbgWord32(slkPageptr, ZPOS_INSERT_INDEX, slkPage->header.insertPos);
-
- tslkLastSize = ZWORDS_IN_PAGE - slkPage->header.highestIndex - slkPage->header.insertPos;
-
- if (tslkLastSize > operationRecPtr.p->tupkeylen) {
- // WE DO NOT NEED TO REORGANIZE THE PAGE TO INSERT THE NEW KEY. IT FITS INTO THE
- // SIZE REMAINING AT THE END.
- jam();
- } else {
- // THE KEY FITS INTO THE PAGE BUT ONLY AFTER REORGANISING THE PAGE.
- jam();
- relpPageptr.p = slkPageptr.p;
- reorgLongPage(signal);
- }//if
-
- if (slkPage->header.nextFreeIndex == 0) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* THE PAGE INDEX HAS NO EMPTY SLOTS. WE MUST EXTEND THE PAGE INDEX BY ONE NEW SLOT.*/
- /* --------------------------------------------------------------------------------- */
- tslkPageIndex = slkPage->header.highestIndex + 1;
- } else {
- jam();
- tslkPageIndex = slkPage->header.nextFreeIndex;
- }//if
-
- if (fragrecptr.p->createLcp == ZTRUE) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* ON LONG PAGES WE USE A PHYSIOLOGICAL LOGGING SCHEME. THIS MEANS THAT WE ONLY NEED*/
- /* TO SPECIFY WHICH INDEX TO DELETE IN ORDER TO UNDO THE CHANGES WE DO. THE */
- /* POSSIBLE REORGANISATION DO NOT CHANGE THE LOGICAL LAYOUT OF THE PAGE. */
- /* --------------------------------------------------------------------------------- */
- datapageptr.p = slkPageptr.p;
- cundoElemIndex = tslkPageIndex;
- cundoinfolength = 0;
- undoWritingProcess(signal);
- }//if
-
- if (slkPage->header.nextFreeIndex == 0) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* THE PAGE INDEX HAS NO EMPTY SLOTS. WE MUST EXTEND THE PAGE INDEX BY ONE NEW SLOT.*/
- /* --------------------------------------------------------------------------------- */
- dbgWord32(slkPageptr, ZPOS_LAST_INDEX, slkPage->header.highestIndex + 1);
- slkPage->header.highestIndex++;
- ndbrequire(slkPage->header.insertPos < (ZWORDS_IN_PAGE - slkPage->header.highestIndex));
- // Reset index. We have already checked that we can increase "highestIndex" value
- // without overwriting the data part.
- slkPage->word32[ZWORDS_IN_PAGE - slkPage->header.highestIndex] = 0;
- dbgWord32(slkPageptr, ZPOS_FREE_AREA_IN_PAGE, slkPage->header.freeArea - 1);
- slkPage->header.freeArea--;
- } else {
- jam();
- dbgWord32(slkPageptr, ZPOS_NEXT_FREE_INDEX, slkPage->word32[ZWORDS_IN_PAGE - tslkPageIndex]);
- arrGuard(ZWORDS_IN_PAGE - tslkPageIndex, 2048);
- arrGuard(slkPage->word32[ZWORDS_IN_PAGE - tslkPageIndex], 2048);
-
- slkPage->header.nextFreeIndex = slkPage->word32[ZWORDS_IN_PAGE - tslkPageIndex];
- if(slkPage->header.nextFreeIndex > slkPage->header.highestIndex){
- slkPage->header.nextFreeIndex = 0;
- dbgWord32(slkPageptr, ZPOS_NEXT_FREE_INDEX, slkPage->header.nextFreeIndex);
- }
- }//if
-
- dbgWord32(slkPageptr, ZWORDS_IN_PAGE - tslkPageIndex, tslkKeyLen);
- dbgWord32(slkPageptr, ZWORDS_IN_PAGE - tslkPageIndex, slkPage->header.insertPos);
- arrGuard(ZWORDS_IN_PAGE - tslkPageIndex, 2048);
- slkPage->word32[ZWORDS_IN_PAGE - tslkPageIndex] =
- slkPage->header.insertPos | (tslkKeyLen << 16);
-
- dbgWord32(slkPageptr, ZPOS_INSERT_INDEX, slkPage->header.insertPos);
- tslkInsertIndex = slkPage->header.insertPos;
- slkPage->header.insertPos += tslkKeyLen;
-
- dbgWord32(slkPageptr, ZPOS_FREE_AREA_IN_PAGE, slkPage->header.freeArea - tslkKeyLen);
- slkPage->header.freeArea = slkPage->header.freeArea - tslkKeyLen;
- if (slkPage->header.freeArea < 128) {
- jam();
- tslkArrayPos = 4;
- } else {
- jam();
- tslkArrayPos = (slkPage->header.freeArea - 128) / 512;
- }//if
-
- if (tslkArrayPos != slkPage->header.pageArrayPos) {
- jam();
- if (cundoLogActive != ZTRUE) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* WE ONLY HANDLE THE LISTS WHEN WE ARE NOT IN A SYSTEM RESTART. */
- /* --------------------------------------------------------------------------------- */
- rfpPageptr = slkPageptr;
- trfpArrayPos = slkPage->header.pageArrayPos;
- removeFromPageArrayList(signal);
- ipaPagePtr = slkPageptr;
- tipaArrayPos = tslkArrayPos;
- slkPage->header.pageArrayPos = tipaArrayPos;
- if (tslkArrayPos != 4) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* THE PAGE WILL STILL BE ON ONE OF THE FREE LISTS SINCE AT LEAST 128 * 4 */
- /* BYTES OF FREE SPACE REMAINS ON THE PAGE. */
- /* --------------------------------------------------------------------------------- */
- insertPageArrayList(signal);
- }//if
- } else {
- // This should never happen. Should use storeLongKeysAtPos() instead when executing
- // undolog.
- ndbrequire(false);
- }
- }//if
- /* --------------------------------------------------------------------------------- */
- /* INCREASE THE NUMBER OF ELEMENTS IN THE PAGE. */
- /* --------------------------------------------------------------------------------- */
- dbgWord32(slkPageptr, ZPOS_NO_ELEM_IN_PAGE, slkPage->header.noOfElements + 1);
- slkPage->header.noOfElements++;
-
- guard27 = tslkKeyLen - 1;
- arrGuard(guard27 + tslkInsertIndex, 2048);
- for (tslkTmp = 0; tslkTmp <= guard27; tslkTmp++) {
- dbgWord32(slkPageptr, tslkTmp + tslkInsertIndex, slkCopyPageptr.p->word32[tslkTmp]);
- slkPage->word32[tslkTmp + tslkInsertIndex] = slkCopyPageptr.p->word32[tslkTmp];
- }//for
-
- // Used by abortoperation() in case of an abort.
- operationRecPtr.p->longPagePtr = slkPageptr.i;
-
- // This is for an eventual LCP start in the middle of this locked operation.
- operationRecPtr.p->longKeyPageIndex = tslkPageIndex;
-
-#ifdef VM_TRACE
- if (cundoLogActive != ZTRUE) checkPageArrayList(signal, "storeLongKeys");
- checkIndexInLongKeyPage(slkPageptr.i, "storeLongKeys2");
-#endif
-
-}//Dbacc::storeLongKeys()
-
-/* --------------------------------------------------------------------------------- */
-/* REORGANIZE THE PAGE BY COPYING IT TEMPORARILY TO A NEW AREA AND THEN SIMPLY */
-/* PUTTING THE OBJECTS BACK ON THE PAGE IN THE SAME ORDER AS THEY ARE PLACED IN THE */
-/* INDEX. */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::reorgLongPage(Signal* signal)
-{
- Uint32 indexStartPos;
- Uint32 pagePos;
- Uint32 pagePos2;
- Uint32 indexNo;
- Uint32 insertPos;
- Uint32 indexValue;
- Uint32 keyLength;
- Uint32 keyPos;
- Uint32 keyEndPos;
- LongKeyPage *reOrgPage;
-
- ptrGuard(relpPageptr);
- reOrgPage = (LongKeyPage *) &relpPageptr.p->word32[0];
-
- dbgWord32(relpPageptr, ZPOS_LAST_INDEX, reOrgPage->header.highestIndex);
- indexStartPos = ZWORDS_IN_PAGE - reOrgPage->header.highestIndex;
-
- // Copy key data part of page to a temporary page.
- for (pagePos = ZHEAD_SIZE; pagePos < indexStartPos; pagePos++) {
- jam();
- arrGuard(pagePos, 2048);
- ckeys[pagePos] = reOrgPage->word32[pagePos];
- }//for
-
- insertPos = ZHEAD_SIZE;
-
- // Walk through all the indexes.
- for (indexNo = 1; indexNo <= reOrgPage->header.highestIndex; indexNo++) {
- jam();
- arrGuard(ZWORDS_IN_PAGE - indexNo, 2048);
- dbgWord32(relpPageptr, ZWORDS_IN_PAGE - indexNo, reOrgPage->word32[ZWORDS_IN_PAGE - indexNo]);
- indexValue = reOrgPage->word32[ZWORDS_IN_PAGE - indexNo];
-
- if ((indexValue >> 16) != 0) {
- // The index contains a reference to a key.
- jam();
- keyPos = indexValue & 0xffff;
- keyLength = indexValue >> 16;
- dbgWord32(relpPageptr, ZWORDS_IN_PAGE - indexNo, insertPos + (keyLength << 16));
- arrGuard(ZWORDS_IN_PAGE - indexNo, 2048);
-
- // Refresh the index data with the new key start position in the data part.
- reOrgPage->word32[ZWORDS_IN_PAGE - indexNo] = insertPos + (keyLength << 16);
- keyEndPos = keyPos + keyLength;
- arrGuard(keyEndPos, 2048);
-
- // Copy the key from the temporary page
- // to the insert position at original page.
- for (pagePos2 = keyPos; pagePos2 < keyEndPos; pagePos2++, insertPos++) {
- jam();
- dbgWord32(relpPageptr, insertPos, ckeys[pagePos2]);
- arrGuard(insertPos, 2048);
- arrGuard(pagePos2, 2048);
- reOrgPage->word32[insertPos] = ckeys[pagePos2];
- }//for
- }//if
- }//for
- dbgWord32(relpPageptr, ZPOS_INSERT_INDEX, insertPos);
- reOrgPage->header.insertPos = insertPos;
-}//Dbacc::reorgLongPage()
-
-
-/* --------------------------------------------------------------------------------- */
-/* DELETE_LONG_KEY */
-/* INPUT: DLK_PAGEPTR PAGE POINTER OF DELETED KEY OBJECT */
-/* TDLK_LOGICAL_PAGE_INDEX LOGICAL PAGE INDEX OF DELETED KEY OBJECT */
-/* */
-/* DESCRIPTION: DELETE AN ELEMENT OF A LONG_KEY_PAGE. */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::deleteLongKey(Signal* signal)
-{
- Uint32 tdlkLastIndex;
- Uint32 tdlkNextPosition;
- Uint32 tdlkFreeArea;
- Uint32 tdlkArrayPos;
- Uint32 tdlkOldArrayPos;
- LongKeyPage *dlkPage;
-
- jam();
- dlkPage = (LongKeyPage *) &dlkPageptr.p->word32[0];
-
-#ifdef VM_TRACE
- checkIndexInLongKeyPage(dlkPageptr.i, "deleteLongKey1");
-#endif
-
- dbgWord32(dlkPageptr, ZWORDS_IN_PAGE - tdlkLogicalPageIndex, dlkPage->word32[ZWORDS_IN_PAGE - tdlkLogicalPageIndex] >> 16);
- dbgWord32(dlkPageptr, ZWORDS_IN_PAGE - tdlkLogicalPageIndex, dlkPage->word32[ZWORDS_IN_PAGE - tdlkLogicalPageIndex] & 0xffff);
- arrGuard(ZWORDS_IN_PAGE - tdlkLogicalPageIndex, 2048);
-
- const Uint32 tdlkIndexValue = dlkPage->word32[ZWORDS_IN_PAGE - tdlkLogicalPageIndex];
- const Uint32 tdlkKeyLen = tdlkIndexValue >> 16;
- const Uint32 tdlkPhysPageIndex = tdlkIndexValue & 0xffff;
-
- if (fragrecptr.p->createLcp == ZTRUE) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* WE LOG THE DELETE LONG KEY BY LOGGING THE DELETED KEY AND ITS LOGICAL INDEX.*/
- /* --------------------------------------------------------------------------------- */
- datapageptr.p = dlkPageptr.p;
- cundoElemIndex = tdlkLogicalPageIndex;
- cundoinfolength = tdlkKeyLen;
- undoWritingProcess(signal);
- }//if
- /* --------------------------------------------------------------------------------- */
- /* DECREASE THE NUMBER OF ELEMENTS IN THE PAGE. */
- /* --------------------------------------------------------------------------------- */
- dbgWord32(dlkPageptr, ZPOS_NO_ELEM_IN_PAGE, dlkPage->header.noOfElements - 1);
- dlkPage->header.noOfElements--;
-
- arrGuard(dlkPage->header.noOfElements, ZMAX_NO_OF_LONGKEYS_IN_PAGE);
-
- /* --------------------------------------------------------------------------------- */
- /* INCREASE THE FREE AREA IN THE PAGE. */
- /* --------------------------------------------------------------------------------- */
- dbgWord32(dlkPageptr, ZPOS_FREE_AREA_IN_PAGE, dlkPage->header.freeArea + tdlkKeyLen);
- dbgWord32(dlkPageptr, ZPOS_LAST_INDEX, dlkPage->header.highestIndex);
-
- dlkPage->header.freeArea += tdlkKeyLen;
-
- if (dlkPage->header.noOfElements == 0) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* THE PAGE IS NOW EMPTY, WE CAN RELEASE IT. */
- /* --------------------------------------------------------------------------------- */
- if (dlkPage->header.freeArea !=
- (ZWORDS_IN_PAGE - ZHEAD_SIZE - dlkPage->header.highestIndex )) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* SOME AREA IN THE PAGE IS STILL LEFT BUT NO ELEMENTS, INCONSISTENT */
- /* --------------------------------------------------------------------------------- */
- sendSystemerror(signal);
- }//if
- /* --------------------------------------------------------------------------------- */
- /* WE REMOVE THE PAGE FROM THE LIST OF FREE LONG PAGES. THERE IS NO RISK THAT IT */
- /* DID NOT BELONG TO ANY SINCE IT IS NOT ALLOWED TO HAVE THAT LARGE KEYS. */
- /* --------------------------------------------------------------------------------- */
-
- if (cundoLogActive != ZTRUE) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* WHEN DELETING KEYS DURING SYSTEM RESTART WE NEED NOT UPDATE THE LISTS. */
- /* --------------------------------------------------------------------------------- */
- // REMOVEFROMLIST is done by releaseLongPage(). EDTJAMO.
- // rfpPageptr = dlkPageptr;
- // trfpArrayPos = dlkPage->header.pageArrayPos;
- // removeFromPageArrayList(signal, "deleteLongKey");
- rlopPageptr = dlkPageptr;
- releaseLongPage(signal);
- return;
- } else {
- // Must remove reference to the removed key, otherwise left in index. EDTJAMO.
- arrGuard(ZWORDS_IN_PAGE - tdlkLogicalPageIndex, 2048);
- arrGuard(tdlkLogicalPageIndex, 2048);
-
- tdlkNextPosition = dlkPage->header.nextFreeIndex;
- dlkPage->header.nextFreeIndex = tdlkLogicalPageIndex;
- dbgWord32(dlkPageptr, ZWORDS_IN_PAGE - tdlkLogicalPageIndex, tdlkNextPosition);
- dlkPage->word32[ZWORDS_IN_PAGE - tdlkLogicalPageIndex] = tdlkNextPosition;
- }
- } else {
- /* --------------------------------------------------------------------------------- */
- /* THE PAGE IS NOT EMPTY SO WE WILL REMOVE THE KEY OBJECT AND UPDATE THE */
- /* HEADER INFORMATION AND PLACE THE PAGE IN THE PROPER PAGE LIST. */
- /* --------------------------------------------------------------------------------- */
- tdlkLastIndex = dlkPage->header.highestIndex;
- arrGuard(ZWORDS_IN_PAGE - tdlkLastIndex, 2048);
- if (tdlkLastIndex == tdlkLogicalPageIndex) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* WE DELETE THE LAST PAGE INDEX SO WE NEED TO UPDATE THE VALUE. WE MOVE */
- /* BACKWARDS UNTIL WE EITHER FIND A USED INDEX OR THAT WE COME TO INDEX ZERO. */
- /* --------------------------------------------------------------------------------- */
- tdlkLastIndex--;
- while( (tdlkLastIndex > 1) &&
- (dlkPage->word32[ZWORDS_IN_PAGE - tdlkLastIndex] >> 16) == 0 ) {
- jam();
- tdlkLastIndex--;
- }
- //-----------------------------------------------------
- // Reorganize the rest of the index. Set up the free
- // list and the free index.
- //-----------------------------------------------------
- UintR dlkTmp = tdlkLastIndex;
- dlkPage->header.nextFreeIndex = 0;
- while( dlkTmp > 0) {
- if ( (dlkPage->word32[ZWORDS_IN_PAGE - dlkTmp] >> 16) == 0 ) {
- jam();
- dlkPage->word32[ZWORDS_IN_PAGE - dlkTmp] = dlkPage->header.nextFreeIndex;
- arrGuard(dlkTmp, 2048);
- dlkPage->header.nextFreeIndex = dlkTmp;
- }
- dlkTmp--;
- }
- //-----------------------------------------------------
- // Update free area in page and last index.
- //-----------------------------------------------------
- dbgWord32(dlkPageptr, ZPOS_LAST_INDEX, tdlkLastIndex);
- dlkPage->header.highestIndex = tdlkLastIndex;
- dlkPage->header.freeArea = tdlkLogicalPageIndex +
- dlkPage->header.freeArea - tdlkLastIndex;
- tdlkNextPosition = 0;
- } else {
- if (dlkPage->header.highestIndex > tdlkLogicalPageIndex) {
- jam();
- tdlkNextPosition = dlkPage->header.nextFreeIndex;
- dbgWord32(dlkPageptr, ZPOS_NEXT_FREE_INDEX, tdlkLogicalPageIndex);
- arrGuard(tdlkLogicalPageIndex, 2048);
- dlkPage->header.nextFreeIndex = tdlkLogicalPageIndex;
- } else {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* LOGICAL PAGE INDEX LARGER THAN LARGEST INDEX, INCONSISTENT. */
- /* --------------------------------------------------------------------------------- */
- sendSystemerror(signal);
- return; // Just to keep compiler happy
- }//if
- }//if
- /* --------------------------------------------------------------------------------- */
- /* WE INSERT ZERO INTO THE LENGTH PART TO INDICATE A FREE INDEX POSITION. */
- /* WE INSERT A POINTER TO THE NEXT FREE INDEX TO AS TO PUT IT INTO A FREE */
- /* LIST OF INDEX POSITIONS. WE ONLY DO SO IF IT WAS NOT THE LAST INDEX. */
- /* --------------------------------------------------------------------------------- */
- dbgWord32(dlkPageptr, ZWORDS_IN_PAGE - tdlkLogicalPageIndex, tdlkNextPosition);
- arrGuard(ZWORDS_IN_PAGE - tdlkLogicalPageIndex, 2048);
- dlkPage->word32[ZWORDS_IN_PAGE - tdlkLogicalPageIndex] = tdlkNextPosition;
- if (dlkPage->header.insertPos == (tdlkPhysPageIndex + tdlkKeyLen)) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* THIS ENTRY IS THE LAST ON THE PAGE SO WE WILL UPDATE THE INSERT INDEX */
- /* --------------------------------------------------------------------------------- */
- dbgWord32(dlkPageptr, ZPOS_INSERT_INDEX, tdlkPhysPageIndex);
- dlkPage->header.insertPos = tdlkPhysPageIndex;
- }//if
- }//if
- dbgWord32(dlkPageptr, ZPOS_FREE_AREA_IN_PAGE, dlkPage->header.freeArea);
- tdlkFreeArea = dlkPage->header.freeArea;
- ndbrequire(tdlkFreeArea <= (ZWORDS_IN_PAGE - ZHEAD_SIZE));
- if (tdlkFreeArea < 128) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* FREE AREA IS STILL LESS THAN 128 WORDS SO IT SHOULD NOT BE PLACED IN ANY OF THE */
- /* FREE LISTS. */
- /* --------------------------------------------------------------------------------- */
- dbgWord32(dlkPageptr, ZPOS_ARRAY_POS, dlkPage->header.pageArrayPos);
- ndbrequire(dlkPage->header.pageArrayPos == 4);
- } else {
- jam();
- // Calculate an eventually new arraypos.
- dbgWord32(dlkPageptr, 0, (tdlkFreeArea - 128) / 512);
- tdlkArrayPos = (tdlkFreeArea - 128) / 512;
-
- if (cundoLogActive != ZTRUE) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* WHEN DELETING KEYS DURING SYSTEM RESTART WE NEED NOT UPDATE THE LISTS. */
- /* --------------------------------------------------------------------------------- */
- dbgWord32(dlkPageptr, ZPOS_ARRAY_POS, dlkPage->header.pageArrayPos);
- tdlkOldArrayPos = dlkPage->header.pageArrayPos;
- if (tdlkArrayPos != tdlkOldArrayPos) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* THE NEW MEMORY AREA HAS ENABLED THE PAGE TO MOVE TO A NEW FREE PAGE LIST */
- /* --------------------------------------------------------------------------------- */
- rfpPageptr = dlkPageptr;
- trfpArrayPos = tdlkOldArrayPos;
- if (tdlkOldArrayPos != 4) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* THERE WAS A FREE PAGE LIST TO REMOVE THE PAGE FROM. IF FREE SPACE IS LESS THAN */
- /* 128 BYTES THEN IT IS NOT ON ANY FREE LIST. */
- /* --------------------------------------------------------------------------------- */
- removeFromPageArrayList(signal);
- }//if
- dlkPage->header.pageArrayPos = tdlkArrayPos;
- ipaPagePtr = dlkPageptr;
- tipaArrayPos = tdlkArrayPos;
- insertPageArrayList(signal);
- }//if
- } else {
- // Update pageArrayPos. We are in a SR, executing undolog, insertPageArrayList() called
- // from execACC_OVER_REC needs this value later.
- dlkPage->header.pageArrayPos = tdlkArrayPos;
- }
- }//if
-#ifdef VM_TRACE
- if (cundoLogActive != ZTRUE) checkPageArrayList(signal, "deleteLongKey");
- checkIndexInLongKeyPage(dlkPageptr.i, "deleteLongKey2");
-#endif
-}//Dbacc::deleteLongKey()
-
-
-void Dbacc::checkIndexInLongKeyPage(Uint32 pageId, const char *calledFrom) {
- Page8Ptr pagePtr;
- LongKeyPage *page;
- Uint32 indexNo;
- Uint32 indexValue;
- Uint32 keyLength;
- Uint32 keyPos;
-
- pagePtr.i = pageId;
- ptrCheckGuard(pagePtr, cpagesize, page8);
- page = (LongKeyPage *) &pagePtr.p->word32[0];
-
- // Check the header variables.
- if (page->header.nextFreeIndex > 2048 ||
- page->header.highestIndex > 2048 ||
- page->header.insertPos > 2048 ||
- page->header.freeArea > 2048 ||
- page->header.noOfElements > 225) {
- ndbout << " ERROR in checkIndexInLongKeyPage, called from " << calledFrom << endl
- << " pagePtr.i = " << pageId << endl;
- printoutInfoAndShutdown(page);
- }
-
- // Walk through all the indexes.
- for (indexNo = 1; indexNo <= page->header.highestIndex; indexNo++) {
- jam();
- indexValue = page->word32[ZWORDS_IN_PAGE - indexNo];
-
- if ((indexValue >> 16) == 0) {
- ; // key length is 0, means no key reference at this position in index.
- } else {
- // The index contains a reference to a key.
- jam();
- keyPos = indexValue & 0xffff;
- keyLength = indexValue >> 16;
- if (keyPos >= ZWORDS_IN_PAGE || keyLength >= ZWORDS_IN_PAGE) {
- jam();
- ndbout << " ERROR in checkIndexInLongKeyPage, called from " << calledFrom << endl
- << " keyPos = " << keyPos << endl
- << " keyLength = " << keyLength << endl
- << " page->header.noOfElements = " << page->header.noOfElements << endl
- << " page->header.freeArea = " << page->header.freeArea << endl
- << " indexNo = " << indexNo << endl
- << " page->header.highestIndex = " << page->header.highestIndex << endl;
- ndbrequire(false);
- }
- }
- }
-}//Dbacc::checkIndexInLongKeyPage
-
-
-/* --------------------------------------------------------------------------------- */
-/* REMOVE A PAGE FROM THE PAGE ARRAY LIST. */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::removeFromPageArrayList(Signal* signal)
-{
- Page8Ptr rfpPrevPageptr;
- Page8Ptr rfpNextPageptr;
- LongKeyPage *page;
- LongKeyPage *prevPage;
- LongKeyPage *nextPage;
-
- jam();
-
-#ifdef VM_TRACE
- checkPageB4Remove(rfpPageptr.i, "removeFromPageArrayList");
-#endif
-
- page = (LongKeyPage *) &rfpPageptr.p->word32[0];
-
- if (page->header.prevPage == RNIL) {
- jam();
- arrGuard(trfpArrayPos, 4);
- // This page was first in list, remove reference
- // to this page from the start of the list.
- ndbrequire(fragrecptr.p->longKeyPageArray[trfpArrayPos] == rfpPageptr.i);
- fragrecptr.p->longKeyPageArray[trfpArrayPos] = page->header.nextPage;
- } else {
- jam();
- rfpPrevPageptr.i = page->header.prevPage;
- ptrCheckGuard(rfpPrevPageptr, cpagesize, page8);
- prevPage = (LongKeyPage *) &rfpPrevPageptr.p->word32[0];
- // This page wasn't first in list, remove reference
- // to this page from the previous page.
- ndbrequire(prevPage->header.nextPage == rfpPageptr.i);
- prevPage->header.nextPage = page->header.nextPage;
- }//if
-
- if (page->header.nextPage != RNIL) {
- jam();
- rfpNextPageptr.i = page->header.nextPage;
- ptrCheckGuard(rfpNextPageptr, cpagesize, page8);
- nextPage = (LongKeyPage *) &rfpNextPageptr.p->word32[0];
- // This page wasn't last in list, remove reference
- // to this page from the next page.
- ndbrequire(nextPage->header.prevPage == rfpPageptr.i);
- nextPage->header.prevPage = page->header.prevPage;
- // Remove reference to next page in list.
- page->header.nextPage = RNIL;
- }//if
-
- // This couldn't be set until now.
- // Remove reference to previous page in list.
- page->header.prevPage = RNIL;
-
-#ifdef VM_TRACE
- checkPageArrayList(signal, "removeFromPageArrayList");
-#endif
-}//Dbacc::removeFromPageArrayList()
-
-/* --------------------------------------------------------------------------------- */
-/* INSERT A PAGE INTO THE PAGE ARRAY LIST. */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::insertPageArrayList(Signal* signal)
-{
- Page8Ptr ipaNextPagePtr;
- LongKeyPage *page;
- LongKeyPage *nextPage;
-
- jam();
-
-#ifdef VM_TRACE
- checkPageArrayList(signal, "insertPageArrayList1");
- checkPageB4Insert(ipaPagePtr.i, "insertPageArrayList1");
-#endif
-
- page = (LongKeyPage *) &ipaPagePtr.p->word32[0];
-
- arrGuard(tipaArrayPos, 4);
-
- if (fragrecptr.p->longKeyPageArray[tipaArrayPos] != RNIL) {
- jam();
- ipaNextPagePtr.i = fragrecptr.p->longKeyPageArray[tipaArrayPos];
- ptrCheckGuard(ipaNextPagePtr, cpagesize, page8);
- nextPage = (LongKeyPage *) &ipaNextPagePtr.p->word32[0];
-
- // A page already existed in the list, add reference
- // to this page in the next page.
- nextPage->header.prevPage = ipaPagePtr.i;
- }//if
-
- page->header.prevPage = RNIL;
- page->header.nextPage = fragrecptr.p->longKeyPageArray[tipaArrayPos];
- page->header.pageArrayPos = tipaArrayPos;
-
- fragrecptr.p->longKeyPageArray[tipaArrayPos] = ipaPagePtr.i;
-
-#ifdef VM_TRACE
- checkPageArrayList(signal, "insertPageArrayList2");
-#endif
-}//Dbacc::insertPageArrayList()
-
-// --------------------------------------------------------------------------------- */
-// Check the page array list.
-// --------------------------------------------------------------------------------- */
-void Dbacc::checkPageArrayList(Signal* signal, const char *calledFrom)
-{
- Page8Ptr pagePtr;
- Uint32 pageArrayIndex;
- LongKeyPage *page;
- Uint32 prevPage;
-
- // Go through the longKeyPageArray and search for a page.
- for (pageArrayIndex = 0; pageArrayIndex <= ZMAX_LONG_KEY_ARRAY_INDEX; pageArrayIndex++) {
- jam();
- pagePtr.i = fragrecptr.p->longKeyPageArray[pageArrayIndex];
- prevPage = RNIL;
-
- if (pagePtr.i != RNIL) {
- // A page is found.
- jam();
- do {
- ptrCheckGuard(pagePtr, cpagesize, page8);
- page = (LongKeyPage *) &pagePtr.p->word32[0];
-
- if ((page->header.freeArea >= 128) &&
- (((page->header.freeArea - 128) / 512) == page->header.pageArrayPos) &&
- (pageArrayIndex == page->header.pageArrayPos) &&
- (page->header.prevPage == prevPage)) {
- // The page found is OK, test next page.
- prevPage = pagePtr.i;
- pagePtr.i = page->header.nextPage;
- jam();
- } else {
- jam();
- ndbout << " ERROR in checkPageArrayList, called from " << calledFrom << endl
- << " pagePtr.i = " << pagePtr.i << endl
- << " prevPage = " << prevPage << endl
- << " pageArrayIndex = " << pageArrayIndex << endl;
- printoutInfoAndShutdown(page);
- }
- }//do
- while (pagePtr.i != RNIL);
- }//if
- }//for
-}//Dbacc::checkPageArrayList()
-
-// --------------------------------------------------------------------------------- */
-// Check the page to put into the pageArrayList.
-// --------------------------------------------------------------------------------- */
-void Dbacc::checkPageB4Insert(Uint32 pageId, const char *calledFrom) {
- Page8Ptr pagePtr;
- Uint32 pageArrayIndex;
- LongKeyPage *page;
-
- pagePtr.i = pageId;
- ptrCheckGuard(pagePtr, cpagesize, page8);
- page = (LongKeyPage *) &pagePtr.p->word32[0];
-
- if ((page->header.nextPage != RNIL) ||
- (page->header.prevPage != RNIL)) {
- jam();
- ndbout << " ERROR in checkPageB4Insert, called from " << calledFrom << endl
- << " pagePtr.i = " << pagePtr.i << endl
- << " page->header.nextPage = " << page->header.nextPage << endl
- << " page->header.prevPage = " << page->header.prevPage << endl;
- ndbrequire(false);
- }
-
- // Page should not be inserted in list if free area is less than 512 byte.
- if (page->header.freeArea < 128) {
- jam();
- ndbout << " ERROR in checkPageB4Insert, called from " << calledFrom << endl
- << " Page has to little free area to be in list." << endl
- << " pagePtr.i = " << pagePtr.i << endl
- << " tipaArrayPos = " << tipaArrayPos << endl;
- printoutInfoAndShutdown(page);
- }
-
- // Check if position in list is correct
- if ((((page->header.freeArea - 128) / 512) != page->header.pageArrayPos) ||
- (page->header.pageArrayPos != tipaArrayPos)) {
- ndbout << " ERROR in checkPageB4Insert, called from " << calledFrom << endl
- << " Incorrect position in list." << endl
- << " pagePtr.i = " << pagePtr.i << endl
- << " tipaArrayPos = " << tipaArrayPos << endl;
- printoutInfoAndShutdown(page);
- }
-
- // Check if page is already in list.
- for (pageArrayIndex = 0; pageArrayIndex <= ZMAX_LONG_KEY_ARRAY_INDEX; pageArrayIndex++) {
- jam();
- pagePtr.i = fragrecptr.p->longKeyPageArray[pageArrayIndex];
-
- if (pagePtr.i != RNIL) {
- // A page is found.
- jam();
- do {
- ptrCheckGuard(pagePtr, cpagesize, page8);
- page = (LongKeyPage *) &pagePtr.p->word32[0];
- if (pagePtr.i == pageId) {
- jam();
- ndbout << "ERROR in checkPageB4Insert, called from " << calledFrom << endl
- << "Page exists already in list." << endl
- << " pagePtr.i = " << pagePtr.i << endl;
- printoutInfoAndShutdown(page);
- }
- pagePtr.i = page->header.nextPage;
- }//do
- while (pagePtr.i != RNIL);
- }//if
- }//for
-}//Dbacc::checkPageB4Insert()
-
-// --------------------------------------------------------------------------------- */
-// Check the page to remove from the pageArrayList.
-// --------------------------------------------------------------------------------- */
-void Dbacc::checkPageB4Remove(Uint32 pageId, const char *calledFrom) {
- Page8Ptr pagePtr;
- Uint32 pageArrayIndex;
- Uint32 noOfOccurrence = 0;
- Uint32 noOfPagesInList = 0;
- LongKeyPage *page;
-
- LongKeyPage *prevPage;
- LongKeyPage *nextPage;
- Page8Ptr rfpPrevPageptr;
- Page8Ptr rfpNextPageptr;
-
-
- pagePtr.i = pageId;
- ptrCheckGuard(pagePtr, cpagesize, page8);
- page = (LongKeyPage *) &pagePtr.p->word32[0];
-
- // Check that page is in list.
- for (pageArrayIndex = 0; pageArrayIndex <= ZMAX_LONG_KEY_ARRAY_INDEX; pageArrayIndex++) {
- jam();
- pagePtr.i = fragrecptr.p->longKeyPageArray[pageArrayIndex];
-
- if (pagePtr.i != RNIL) {
- // A page is found.
- jam();
- do {
- noOfPagesInList++;
- ptrCheckGuard(pagePtr, cpagesize, page8);
- page = (LongKeyPage *) &pagePtr.p->word32[0];
- if (pagePtr.i == pageId) {
- // Check the consistent in list.
- if (page->header.prevPage != RNIL) {
- rfpPrevPageptr.i = page->header.prevPage;
- ptrCheckGuard(rfpPrevPageptr, cpagesize, page8);
- prevPage = (LongKeyPage *) &rfpPrevPageptr.p->word32[0];
- if (prevPage->header.nextPage != pageId) {
- ndbout << "ERROR: inconsistent in checkPageB4Remove, called from " << calledFrom << endl
- << "prevPage->header.nextPage = " << prevPage->header.nextPage << endl
- << "pageId = " << pageId << endl;
- printoutInfoAndShutdown(page);
- }
- }
- // Check the consistent in list.
- if (page->header.nextPage != RNIL) {
- rfpNextPageptr.i = page->header.nextPage;
- ptrCheckGuard(rfpNextPageptr, cpagesize, page8);
- nextPage = (LongKeyPage *) &rfpNextPageptr.p->word32[0];
- if (nextPage->header.prevPage != pageId) {
- ndbout << "ERROR: inconsistent in checkPageB4Remove, called from " << calledFrom << endl
- << "nextPage->header.prevPage = " << nextPage->header.prevPage << endl
- << "pageId = " << pageId << endl;
- printoutInfoAndShutdown(page);
- }
- }
- jam();
- noOfOccurrence++;
- }
- pagePtr.i = page->header.nextPage;
- }//do
- while (pagePtr.i != RNIL);
- }//if
- }//for
-
- if (noOfOccurrence != 1) {
- pagePtr.i = pageId;
- ptrCheckGuard(pagePtr, cpagesize, page8);
- page = (LongKeyPage *) &pagePtr.p->word32[0];
- ndbout << "ERROR in checkPageB4Remove, called from " << calledFrom << endl
- << "Page occur " << noOfOccurrence << " times in list" << endl
- << "pageId = " << pageId << endl;
- printoutInfoAndShutdown(page);
- }
-}//Dbacc::checkPageB4Remove()
-
-
-// --------------------------------------------------------------------------------- */
-// Printout an error message and shutdown node.
-// --------------------------------------------------------------------------------- */
-void Dbacc::printoutInfoAndShutdown(LongKeyPage *page) {
- ndbout << " page->header.pageArrayPos = " << page->header.pageArrayPos << endl
- << " ((page->header.freeArea - 128) / 512) = "
- << ((page->header.freeArea - 128) / 512) << endl
- << " page->header.freeArea = " << page->header.freeArea << endl
- << " page->header.noOfElements = " << page->header.noOfElements << endl
- << " page->header.nextPage = " << page->header.nextPage << endl
- << " page->header.prevPage = " << page->header.prevPage << endl
- << " page->header.nextFreeIndex = " << page->header.nextFreeIndex << endl
- << " page->header.insertPos = " << page->header.insertPos << endl
- << " page->header.highestIndex = " << page->header.highestIndex << endl
- << " page->header.pageId = " << page->header.pageId << endl;
- ndbrequire(false);
-}//Dbacc::printoutInfoAndShutdown()
-
/* --------------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------- */
@@ -4448,7 +3307,7 @@ void Dbacc::printoutInfoAndShutdown(LongKeyPage *page) {
/* --------------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------- */
/* */
-/* MODULE: READ */
+/* MODULE: GET_ELEMENT */
/* THE FOLLOWING SUBROUTINES ARE ONLY USED BY GET_ELEMENT AND */
/* GETDIRINDEX. THIS ROUTINE IS THE SOLE INTERFACE TO GET ELEMENTS */
/* FROM THE INDEX. CURRENT USERS ARE ALL REQUESTS AND EXECUTE UNDO LOG */
@@ -4509,6 +3368,21 @@ void Dbacc::getdirindex(Signal* signal)
ptrCheckGuard(gdiPageptr, cpagesize, page8);
}//Dbacc::getdirindex()
+Uint32
+Dbacc::readTablePk(Uint32 localkey1)
+{
+ Uint32 tableId = fragrecptr.p->myTableId;
+ Uint32 fragId = fragrecptr.p->myfid;
+ Uint32 fragPageId = localkey1 >> MAX_TUPLES_BITS;
+ Uint32 pageIndex = localkey1 & ((1 << MAX_TUPLES_BITS ) - 1);
+#ifdef VM_TRACE
+ memset(ckeys, 0x1f, (fragrecptr.p->keyLength * MAX_XFRM_MULTIPLY) << 2);
+#endif
+ int ret = c_tup->accReadPk(tableId, fragId, fragPageId, pageIndex, ckeys, true);
+ ndbrequire(ret > 0);
+ return ret;
+}
+
/* --------------------------------------------------------------------------------- */
/* GET_ELEMENT */
/* INPUT: */
@@ -4550,7 +3424,6 @@ void Dbacc::getElement(Signal* signal)
Uint32 tgeNextptrtype;
register Uint32 tgeKeyptr;
register Uint32 tgeRemLen;
- register Uint32 tgeCompareLen;
register Uint32 TelemLen = fragrecptr.p->elementLength;
register Uint32* Tkeydata = (Uint32*)&signal->theData[7];
@@ -4558,20 +3431,15 @@ void Dbacc::getElement(Signal* signal)
tgePageindex = tgdiPageindex;
gePageptr = gdiPageptr;
tgeResult = ZFALSE;
- tgeCompareLen = fragrecptr.p->keyLength;
- const Uint32 isAccLockReq = operationRecPtr.p->isAccLockReq;
- if (isAccLockReq) {
- jam();
- tgeCompareLen = 0;
- }
+ /*
+ * The value seached is
+ * - table key for ACCKEYREQ, stored in TUP
+ * - local key (1 word) for ACC_LOCKREQ and UNDO, stored in ACC
+ */
+ const bool searchLocalKey =
+ operationRecPtr.p->isAccLockReq || operationRecPtr.p->isUndoLogReq;
- // We can handle keylength up to 8, but not more (0 means dynamic)
- if (tgeCompareLen >= 9) {
- ACCKEY_error(2); return;
- }//if
- if (TelemLen < 3) {
- ACCKEY_error(3); return;
- }//if
+ ndbrequire(TelemLen == ZELEM_HEAD_SIZE + fragrecptr.p->localkeylen);
tgeNextptrtype = ZLEFT;
tgeLocked = 0;
@@ -4602,7 +3470,7 @@ void Dbacc::getElement(Signal* signal)
} else {
ACCKEY_error(6); return;
}//if
- if (tgeRemLen >= TelemLen) {
+ if (tgeRemLen >= ZCON_HEAD_SIZE + TelemLen) {
if (tgeRemLen > ZBUF_SIZE) {
ACCKEY_error(7); return;
}//if
@@ -4610,151 +3478,46 @@ void Dbacc::getElement(Signal* signal)
// There is at least one element in this container. Check if it is the element
// searched for.
/* --------------------------------------------------------------------------------- */
- if (tgeCompareLen != 0) {
- /* --------------------------------------------------------------------------------- */
- /* THIS PART IS USED TO SEARCH FOR KEYS WITH FIXED SIZE. THE LOOP TAKES CARE */
- /* OF SEARCHING THROUGH ALL ELEMENTS IN ONE CONTAINER. */
- /* --------------------------------------------------------------------------------- */
- do {
- register Uint32 TdataIndex = 0;
- register Uint32 TgeIndex = 0;
+ do {
+ tgeElementHeader = gePageptr.p->word32[tgeElementptr];
+ tgeRemLen = tgeRemLen - TelemLen;
+ Uint32 hashValuePart;
+ if (ElementHeader::getLocked(tgeElementHeader)) {
jam();
- tgeRemLen = tgeRemLen - TelemLen;
- do {
- if (gePageptr.p->word32[tgeKeyptr + TgeIndex] != Tkeydata[TdataIndex]) {
- goto compare_next;
- }//if
- TdataIndex++;
- TgeIndex += tgeForward;
- } while (TdataIndex < tgeCompareLen);
- /* --------------------------------------------------------------------------------- */
- /* WE HAVE FOUND THE ELEMENT. GET THE LOCK INDICATOR AND RETURN FOUND. */
- /* --------------------------------------------------------------------------------- */
+ geTmpOperationRecPtr.i = ElementHeader::getOpPtrI(tgeElementHeader);
+ ptrCheckGuard(geTmpOperationRecPtr, coprecsize, operationrec);
+ hashValuePart = geTmpOperationRecPtr.p->hashvaluePart;
+ } else {
jam();
-#if __ia64 == 1
-#if __INTEL_COMPILER == 810
- // prevents SIGSEGV under icc -O1
- ndb_acc_ia64_icc810_dummy_func();
-#endif
-#endif
- tgeLocked = ElementHeader::getLocked(gePageptr.p->word32[tgeElementptr]);
- tgeResult = ZTRUE;
- TdataIndex = tgeElementptr + tgeForward;
- TgeIndex = TdataIndex + tgeForward;
- operationRecPtr.p->localdata[0] = gePageptr.p->word32[TdataIndex];
- operationRecPtr.p->localdata[1] = gePageptr.p->word32[TgeIndex];
- return;
- /* --------------------------------------------------------------------------------- */
- /* COMPARE NEXT ELEMENT */
- /* --------------------------------------------------------------------------------- */
- compare_next:
- if (tgeRemLen <= ZCON_HEAD_SIZE) {
- break;
- }//if
- tgeKeyptr = tgeKeyptr + tgeElemStep;
- tgeElementptr = tgeElementptr + tgeElemStep;
- } while (1);
- } else if (! isAccLockReq) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* THIS PART IS USED TO SEARCH FOR KEYS WITH VARIABLE LENGTH OR FIXED LENGTH */
- /* GREATER THAN 32 BYTES. IN THIS CASE THE KEY PART IS STORED IN A SPECIAL */
- /* LONG PAGE PART AND THE HASH INDEX CONTAINS A REFERENCE TO THERE PLUS A */
- /* PART OF THE HASH VALUE. */
- /* --------------------------------------------------------------------------------- */
- do {
- tgeElementHeader = gePageptr.p->word32[tgeElementptr];
- tgeRemLen = tgeRemLen - TelemLen;
- Uint32 hashValuePart;
- if (ElementHeader::getLocked(tgeElementHeader)) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* IN THIS CASE THE HASH VALUE PART OF THE ELEMENT HEADER IS STORED IN THE */
- /* OPERATION THAT OWNS THE LOCK. IN THIS CASE WE MIGHT AS WELL GO AHEAD AND */
- /* CHECK THE KEY IN THE LONG PAGE. */
- /* --------------------------------------------------------------------------------- */
- geTmpOperationRecPtr.i =
- ElementHeader::getOpPtrI(tgeElementHeader);
- ptrCheckGuard(geTmpOperationRecPtr, coprecsize, operationrec);
- hashValuePart = geTmpOperationRecPtr.p->hashvaluePart;
+ hashValuePart = ElementHeader::getHashValuePart(tgeElementHeader);
+ }
+ if (hashValuePart == opHashValuePart) {
+ jam();
+ Uint32 localkey1 = gePageptr.p->word32[tgeElementptr + tgeForward];
+ Uint32 localkey2 = 0;
+ bool found;
+ if (! searchLocalKey) {
+ Uint32 len = readTablePk(localkey1);
+ found = (len == operationRecPtr.p->xfrmtupkeylen) &&
+ (memcmp(Tkeydata, ckeys, len << 2) == 0);
} else {
jam();
- /* --------------------------------------------------------------------------------- */
- /* IN THIS CASE THE HASH VALUE PART CAN BE CHECKED TO SEE IF THE HASH VALUE */
- /* GIVES US A REASON TO CONTINUE CHECKING THE FULL KEY. */
- /* --------------------------------------------------------------------------------- */
- hashValuePart = ElementHeader::getHashValuePart(tgeElementHeader);
- }//if
-
- if (hashValuePart == opHashValuePart) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* IF THE HASH VALUES ARE EQUAL THEN XOR-ING THEM WILL GIVE THE RESULT 0. */
- /* --------------------------------------------------------------------------------- */
- /* WE HAVE FOUND A KEY WITH IDENTICAL HASH VALUE. MOST LIKELY WE HAVE FOUND THE*/
- /* ELEMENT BUT FIRST WE NEED TO PERFORM A KEY COMPARISON. */
- /* --------------------------------------------------------------------------------- */
- tslcPageIndex = gePageptr.p->word32[tgeKeyptr] & 0x3ff;
- tslcPagedir = gePageptr.p->word32[tgeKeyptr] >> 10;
- searchLongKey(signal, true);
- if (tslcResult == ZTRUE) {
- register Uint32 TlocData1, TlocData2;
- jam();
- /* --------------------------------------------------------------------------------- */
- /* WE HAVE FOUND THE ELEMENT. GET THE LOCK INDICATOR AND RETURN FOUND. */
- /* --------------------------------------------------------------------------------- */
- tgeLocked = ElementHeader::getLocked(tgeElementHeader);
- tgeResult = ZTRUE;
- TlocData1 = tgeElementptr + tgeForward;
- TlocData2 = TlocData1 + tgeForward;
- operationRecPtr.p->localdata[0] = gePageptr.p->word32[TlocData1];
- operationRecPtr.p->localdata[1] = gePageptr.p->word32[TlocData2];
- return;
- }//if
+ found = (localkey1 == Tkeydata[0]);
}
- /* --------------------------------------------------------------------------------- */
- /* COMPARE NEXT ELEMENT */
- /* --------------------------------------------------------------------------------- */
- if (tgeRemLen <= ZCON_HEAD_SIZE) {
- break;
- }//if
- tgeKeyptr = tgeKeyptr + tgeElemStep;
- tgeElementptr = tgeElementptr + tgeElemStep;
- } while (1);
- } else {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* Search for local key in a lock request */
- /* --------------------------------------------------------------------------------- */
- do {
- tgeRemLen = tgeRemLen - TelemLen;
- // position of local key word 1
- Uint32 TdataIndex = tgeElementptr + tgeForward;
- // XXX assume localkeylen is 1
- if (gePageptr.p->word32[TdataIndex] == Tkeydata[0]) {
+ if (found) {
jam();
- tgeLocked = ElementHeader::getLocked(gePageptr.p->word32[tgeElementptr]);
+ tgeLocked = ElementHeader::getLocked(tgeElementHeader);
tgeResult = ZTRUE;
- // position of local key word 2
- Uint32 TgeIndex = TdataIndex + tgeForward;
- operationRecPtr.p->localdata[0] = gePageptr.p->word32[TdataIndex];
- operationRecPtr.p->localdata[1] = gePageptr.p->word32[TgeIndex];
-
- if (fragrecptr.p->keyLength == 0) {
- // set up long key variables in operation record
- tslcPageIndex = gePageptr.p->word32[tgeKeyptr] & 0x3ff;
- tslcPagedir = gePageptr.p->word32[tgeKeyptr] >> 10;
- // no verification since we have no key data
- searchLongKey(signal, false);
- }
+ operationRecPtr.p->localdata[0] = localkey1;
+ operationRecPtr.p->localdata[1] = localkey2;
return;
- }//if
- if (tgeRemLen <= ZCON_HEAD_SIZE) {
- break;
- }//if
- tgeElementptr = tgeElementptr + tgeElemStep;
- } while (1);
- }//if
+ }
+ }
+ if (tgeRemLen <= ZCON_HEAD_SIZE) {
+ break;
+ }
+ tgeElementptr = tgeElementptr + tgeElemStep;
+ } while (true);
}//if
if (tgeRemLen != ZCON_HEAD_SIZE) {
ACCKEY_error(8); return;
@@ -4785,71 +3548,6 @@ void Dbacc::getElement(Signal* signal)
}//Dbacc::getElement()
/* --------------------------------------------------------------------------------- */
-/* SEARCH_LONG_KEY */
-/* INPUT: */
-/* TSLC_PAGEDIR PAGE DIRECTORY OF LONG PAGE */
-/* TSLC_PAGE_INDEX PAGE INDEX IN LONG PAGE */
-/* GE_OPERATION_REC_PTR */
-/* OUTPUT: */
-/* TSLC_RESULT */
-/* DESCRIPTION: SEARCH FOR AN ELEMENT IN A LONG_KEY_PAGE. */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::searchLongKey(Signal* signal, bool verify)
-{
- DirRangePtr slcOverflowrangeptr;
- DirectoryarrayPtr slcOverflowDirptr;
- Page8Ptr slcPageptr;
- Uint32 tslcIndexValue;
- Uint32 tslcStartIndex;
- Uint32 tslcIndex;
- Uint32 guard30;
- Uint32* Tkeydata = (Uint32*)&signal->theData[7];
-
-
- slcOverflowrangeptr.i = fragrecptr.p->overflowdir;
- ptrCheckGuard(slcOverflowrangeptr, cdirrangesize, dirRange);
- arrGuard((tslcPagedir >> 8), 256);
- slcOverflowDirptr.i = slcOverflowrangeptr.p->dirArray[tslcPagedir >> 8];
- ptrCheckGuard(slcOverflowDirptr, cdirarraysize, directoryarray);
-
- // dbgWord32(slcOverflowDirptr, (int) (tslcPagedir & 0xff), slcOverflowDirptr.p->pagep[tslcPagedir & 0xff]);
-
- slcPageptr.i = slcOverflowDirptr.p->pagep[tslcPagedir & 0xff];
- ptrCheckGuard(slcPageptr, cpagesize, page8);
- arrGuard(ZWORDS_IN_PAGE - tslcPageIndex, 2048);
- dbgWord32(slcPageptr, ZWORDS_IN_PAGE - tslcPageIndex, (int)slcPageptr.p->word32[ZWORDS_IN_PAGE - tslcPageIndex] & 0xffff);
- dbgWord32(slcPageptr, ZWORDS_IN_PAGE - tslcPageIndex, slcPageptr.p->word32[ZWORDS_IN_PAGE - tslcPageIndex] >> 16);
- tslcIndexValue = slcPageptr.p->word32[ZWORDS_IN_PAGE - tslcPageIndex];
- if (verify) {
- if ((tslcIndexValue >> 16) != operationRecPtr.p->tupkeylen) {
- jam();
- tslcResult = ZFALSE;
- return;
- }//if
- }
- tslcStartIndex = tslcIndexValue & 0xffff;
- guard30 = operationRecPtr.p->tupkeylen - 1;
- arrGuard(guard30, 2048);
- arrGuard(guard30 + tslcStartIndex, 2048);
- if (verify) {
- for (tslcIndex = 0; tslcIndex <= guard30; tslcIndex++) {
- dbgWord32(slcPageptr, tslcIndex + tslcStartIndex, slcPageptr.p->word32[tslcIndex + tslcStartIndex]);
- if (slcPageptr.p->word32[tslcIndex + tslcStartIndex] != Tkeydata[tslcIndex]) {
- jam();
- tslcResult = ZFALSE;
- return;
- }//if
- }//for
- }
- jam();
- tslcResult = ZTRUE;
- operationRecPtr.p->longPagePtr = slcPageptr.i;
- operationRecPtr.p->longKeyPageIndex = tslcPageIndex;
- arrGuard(tslcPageIndex, ZMAX_NO_OF_LONGKEYS_IN_PAGE);
- arrGuard(slcPageptr.i, cpagesize);
-}//Dbacc::searchLongKey()
-
-/* --------------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------------- */
/* */
@@ -4892,13 +3590,6 @@ void Dbacc::commitdelete(Signal* signal, bool systemRestart)
EXECUTE_DIRECT(DBTUP, GSN_TUP_DEALLOCREQ, signal, 4);
jamEntry();
}//if
- if (fragrecptr.p->keyLength == 0) {
- jam();
- tdlkLogicalPageIndex = operationRecPtr.p->longKeyPageIndex;
- dlkPageptr.i = operationRecPtr.p->longPagePtr;
- ptrCheckGuard(dlkPageptr, cpagesize, page8);
- deleteLongKey(signal);
- }//if
getdirindex(signal);
tlastPageindex = tgdiPageindex;
lastPageptr.i = gdiPageptr.i;
@@ -5457,50 +4148,6 @@ void Dbacc::checkoverfreelist(Signal* signal)
}//if
}//Dbacc::checkoverfreelist()
-/* --------------------------------------------------------------------------------- */
-/* RELEASE_LONG_PAGE */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::releaseLongPage(Signal* signal)
-{
- DirRangePtr rlpOverflowrangeptr;
- DirectoryarrayPtr rlpOverflowDirptr;
- Uint32 trlpTmp1;
- Uint32 trlpTmp2;
- Uint32 trlpTmp3;
-
- jam();
- seizeOverRec(signal);
- sorOverflowRecPtr.p->dirindex = rlopPageptr.p->word32[ZPOS_PAGE_ID];
- sorOverflowRecPtr.p->overpage = RNIL;
- priOverflowRecPtr = sorOverflowRecPtr;
- putRecInFreeOverdir(signal);
- trlpTmp1 = sorOverflowRecPtr.p->dirindex;
- rlpOverflowrangeptr.i = fragrecptr.p->overflowdir;
- trlpTmp2 = trlpTmp1 >> 8;
- trlpTmp3 = trlpTmp1 & 0xff;
- ptrCheckGuard(rlpOverflowrangeptr, cdirrangesize, dirRange);
- arrGuard(trlpTmp2, 256);
- rlpOverflowDirptr.i = rlpOverflowrangeptr.p->dirArray[trlpTmp2];
- ptrCheckGuard(rlpOverflowDirptr, cdirarraysize, directoryarray);
- rlpOverflowDirptr.p->pagep[trlpTmp3] = RNIL;
-
- if (cundoLogActive != ZTRUE) {
- // Remove from page array.
- trfpArrayPos = rlopPageptr.p->word32[ZPOS_ARRAY_POS];
- rfpPageptr = rlopPageptr;
- removeFromPageArrayList(signal);
- }
-
- // Reset page header
- iloPageptr = rlopPageptr;
- tiloIndex = rlopPageptr.p->word32[ZPOS_PAGE_ID];
- initLongOverpage(signal);
-
- rpPageptr = rlopPageptr;
- releasePage(signal);
-}//Dbacc::releaseLongPage()
-
-
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
@@ -6791,14 +5438,8 @@ void Dbacc::expandcontainer(Signal* signal)
Uint32 texcHashvalue;
Uint32 texcTmp;
Uint32 texcIndex;
- Uint32 texpKeyLen;
Uint32 guard20;
- texpKeyLen = fragrecptr.p->keyLength;
- if (texpKeyLen == 0) {
- jam();
- texpKeyLen = ZACTIVE_LONG_KEY_LEN;
- }//if
cexcPrevpageptr = RNIL;
cexcPrevconptr = 0;
cexcForward = ZTRUE;
@@ -6885,18 +5526,10 @@ void Dbacc::expandcontainer(Signal* signal)
clocalkey[texcIndex] = excPageptr.p->word32[texcTmp];
texcTmp = texcTmp + cexcForward;
}//for
- guard20 = texpKeyLen - 1;
- for (texcIndex = 0; texcIndex <= guard20; texcIndex++) {
- arrGuard(texcIndex, 2048);
- arrGuard(texcTmp, 2048);
- ckeys[texcIndex] = excPageptr.p->word32[texcTmp];
- texcTmp = texcTmp + cexcForward;
- }//for
tidrPageindex = fragrecptr.p->expReceiveIndex;
idrPageptr.i = fragrecptr.p->expReceivePageptr;
ptrCheckGuard(idrPageptr, cpagesize, page8);
tidrForward = fragrecptr.p->expReceiveForward;
- tidrKeyLen = texpKeyLen;
insertElement(signal);
fragrecptr.p->expReceiveIndex = tidrPageindex;
fragrecptr.p->expReceivePageptr = idrPageptr.i;
@@ -6978,17 +5611,10 @@ void Dbacc::expandcontainer(Signal* signal)
clocalkey[texcIndex] = lastPageptr.p->word32[texcTmp];
texcTmp = texcTmp + tlastForward;
}//for
- for (texcIndex = 0; texcIndex < texpKeyLen; texcIndex++) {
- arrGuard(texcIndex, 2048);
- arrGuard(texcTmp, 2048);
- ckeys[texcIndex] = lastPageptr.p->word32[texcTmp];
- texcTmp = texcTmp + tlastForward;
- }//for
tidrPageindex = fragrecptr.p->expReceiveIndex;
idrPageptr.i = fragrecptr.p->expReceivePageptr;
ptrCheckGuard(idrPageptr, cpagesize, page8);
tidrForward = fragrecptr.p->expReceiveForward;
- tidrKeyLen = texpKeyLen;
insertElement(signal);
fragrecptr.p->expReceiveIndex = tidrPageindex;
fragrecptr.p->expReceivePageptr = idrPageptr.i;
@@ -7469,18 +6095,12 @@ void Dbacc::shrinkcontainer(Signal* signal)
Uint32 tshrElementptr;
Uint32 tshrRemLen;
Uint32 tshrInc;
- Uint32 tshrKeyLen;
Uint32 tshrTmp;
Uint32 tshrIndex;
Uint32 guard21;
tshrRemLen = cexcContainerlen - ZCON_HEAD_SIZE;
- tshrKeyLen = fragrecptr.p->keyLength;
- if (tshrKeyLen == 0) {
- jam();
- tshrKeyLen = ZACTIVE_LONG_KEY_LEN;
- }//if
- tshrInc = (ZELEM_HEAD_SIZE + tshrKeyLen) + fragrecptr.p->localkeylen;
+ tshrInc = fragrecptr.p->elementLength;
if (cexcForward == ZTRUE) {
jam();
tshrElementptr = cexcContainerptr + ZCON_HEAD_SIZE;
@@ -7529,18 +6149,10 @@ void Dbacc::shrinkcontainer(Signal* signal)
clocalkey[tshrIndex] = excPageptr.p->word32[tshrTmp];
tshrTmp = tshrTmp + cexcForward;
}//for
- guard21 = tshrKeyLen - 1;
- for (tshrIndex = 0; tshrIndex <= guard21; tshrIndex++) {
- arrGuard(tshrIndex, 2048);
- arrGuard(tshrTmp, 2048);
- ckeys[tshrIndex] = excPageptr.p->word32[tshrTmp];
- tshrTmp = tshrTmp + cexcForward;
- }//for
tidrPageindex = fragrecptr.p->expReceiveIndex;
idrPageptr.i = fragrecptr.p->expReceivePageptr;
ptrCheckGuard(idrPageptr, cpagesize, page8);
tidrForward = fragrecptr.p->expReceiveForward;
- tidrKeyLen = tshrKeyLen;
insertElement(signal);
/* --------------------------------------------------------------------------------- */
/* TAKE CARE OF RESULT FROM INSERT_ELEMENT. */
@@ -8268,14 +6880,6 @@ void Dbacc::saveOverPagesLab(Signal* signal)
jam();
ropPageptr = sopPageptr;
releaseOverpage(signal);
- } else if (((sopPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) ==
- ZLONG_PAGE_TYPE) {
- //----------------------------------------------------------------------
- // The long key page is empty, release it.
- //----------------------------------------------------------------------
- jam();
- rlopPageptr = sopPageptr;
- releaseLongPage(signal);
} else {
jam();
sendSystemerror(signal);
@@ -8667,66 +7271,63 @@ void Dbacc::lcpCopyPage(Signal* signal)
}//for
}//for
tlcnChecksum = Tchs;
- if (((lcnCopyPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) != ZLONG_PAGE_TYPE) {
- jam();
- if (((lcnCopyPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) == ZNORMAL_PAGE_TYPE) {
- jam();
- /*-----------------------------------------------------------------*/
- /* TAKE CARE OF ALL 64 BUFFERS ADDRESSED BY ALGORITHM IN */
- /* FIRST PAGE. IF THEY ARE EMPTY THEY STILL HAVE A CONTAINER */
- /* HEADER OF 2 WORDS. */
- /*-----------------------------------------------------------------*/
- tlcnConIndex = ZHEAD_SIZE;
- tlupForward = 1;
- for (tlcnIndex = 0; tlcnIndex <= ZNO_CONTAINERS - 1; tlcnIndex++) {
- tlupIndex = tlcnConIndex;
- tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
- lcpUpdatePage(signal);
- tlcnConIndex = tlcnConIndex + ZBUF_SIZE;
- }//for
- }//if
+ if (((lcnCopyPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) == ZNORMAL_PAGE_TYPE) {
+ jam();
/*-----------------------------------------------------------------*/
- /* TAKE CARE OF ALL USED BUFFERS ON THE LEFT SIDE. */
+ /* TAKE CARE OF ALL 64 BUFFERS ADDRESSED BY ALGORITHM IN */
+ /* FIRST PAGE. IF THEY ARE EMPTY THEY STILL HAVE A CONTAINER */
+ /* HEADER OF 2 WORDS. */
/*-----------------------------------------------------------------*/
- tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 23) & 0x7f;
- while (tlcnNextContainer < ZEMPTYLIST) {
- tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
- tlcnConIndex = tlcnConIndex + ZHEAD_SIZE;
+ tlcnConIndex = ZHEAD_SIZE;
+ tlupForward = 1;
+ for (tlcnIndex = 0; tlcnIndex <= ZNO_CONTAINERS - 1; tlcnIndex++) {
tlupIndex = tlcnConIndex;
tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
- tlupForward = 1;
lcpUpdatePage(signal);
- tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
- }//while
- if (tlcnNextContainer == ZEMPTYLIST) {
- jam();
- /*empty*/;
- } else {
- jam();
- sendSystemerror(signal);
- return;
- }//if
- /*-----------------------------------------------------------------*/
- /* TAKE CARE OF ALL USED BUFFERS ON THE RIGHT SIDE. */
- /*-----------------------------------------------------------------*/
- tlupForward = cminusOne;
- tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 16) & 0x7f;
- while (tlcnNextContainer < ZEMPTYLIST) {
- tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
- tlcnConIndex = tlcnConIndex + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
- tlupIndex = tlcnConIndex;
- tlupElemIndex = tlcnConIndex - 1;
- lcpUpdatePage(signal);
- tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
- }//while
- if (tlcnNextContainer == ZEMPTYLIST) {
- jam();
- /*empty*/;
- } else {
- jam();
- sendSystemerror(signal);
- return;
- }//if
+ tlcnConIndex = tlcnConIndex + ZBUF_SIZE;
+ }//for
+ }//if
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL USED BUFFERS ON THE LEFT SIDE. */
+ /*-----------------------------------------------------------------*/
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 23) & 0x7f;
+ while (tlcnNextContainer < ZEMPTYLIST) {
+ tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
+ tlcnConIndex = tlcnConIndex + ZHEAD_SIZE;
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
+ tlupForward = 1;
+ lcpUpdatePage(signal);
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
+ }//while
+ if (tlcnNextContainer == ZEMPTYLIST) {
+ jam();
+ /*empty*/;
+ } else {
+ jam();
+ sendSystemerror(signal);
+ return;
+ }//if
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL USED BUFFERS ON THE RIGHT SIDE. */
+ /*-----------------------------------------------------------------*/
+ tlupForward = cminusOne;
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 16) & 0x7f;
+ while (tlcnNextContainer < ZEMPTYLIST) {
+ tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
+ tlcnConIndex = tlcnConIndex + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex - 1;
+ lcpUpdatePage(signal);
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
+ }//while
+ if (tlcnNextContainer == ZEMPTYLIST) {
+ jam();
+ /*empty*/;
+ } else {
+ jam();
+ sendSystemerror(signal);
+ return;
}//if
lcnCopyPageptr.p->word32[ZPOS_CHECKSUM] = tlcnChecksum;
}//Dbacc::lcpCopyPage()
@@ -8787,78 +7388,75 @@ void Dbacc::srCheckPage(Signal* signal)
Uint32 tlcnIndex;
lupPageptr.p = lcnCopyPageptr.p;
- if (((lcnCopyPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) != ZLONG_PAGE_TYPE) {
- jam();
- if (((lcnCopyPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) == ZNORMAL_PAGE_TYPE) {
- jam();
- /*-----------------------------------------------------------------*/
- /* TAKE CARE OF ALL 64 BUFFERS ADDRESSED BY ALGORITHM IN */
- /* FIRST PAGE. IF THEY ARE EMPTY THEY STILL HAVE A CONTAINER */
- /* HEADER OF 2 WORDS. */
- /*-----------------------------------------------------------------*/
- tlcnConIndex = ZHEAD_SIZE;
- tlupForward = 1;
- for (tlcnIndex = 0; tlcnIndex <= ZNO_CONTAINERS - 1; tlcnIndex++) {
- tlupIndex = tlcnConIndex;
- tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
- srCheckContainer(signal);
- if (tresult != 0) {
- jam();
- return;
- }//if
- tlcnConIndex = tlcnConIndex + ZBUF_SIZE;
- }//for
- }//if
+ if (((lcnCopyPageptr.p->word32[ZPOS_PAGE_TYPE] >> ZPOS_PAGE_TYPE_BIT) & 3) == ZNORMAL_PAGE_TYPE) {
+ jam();
/*-----------------------------------------------------------------*/
- /* TAKE CARE OF ALL USED BUFFERS ON THE LEFT SIDE. */
+ /* TAKE CARE OF ALL 64 BUFFERS ADDRESSED BY ALGORITHM IN */
+ /* FIRST PAGE. IF THEY ARE EMPTY THEY STILL HAVE A CONTAINER */
+ /* HEADER OF 2 WORDS. */
/*-----------------------------------------------------------------*/
- tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 23) & 0x7f;
- while (tlcnNextContainer < ZEMPTYLIST) {
- tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
- tlcnConIndex = tlcnConIndex + ZHEAD_SIZE;
+ tlcnConIndex = ZHEAD_SIZE;
+ tlupForward = 1;
+ for (tlcnIndex = 0; tlcnIndex <= ZNO_CONTAINERS - 1; tlcnIndex++) {
tlupIndex = tlcnConIndex;
tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
- tlupForward = 1;
srCheckContainer(signal);
if (tresult != 0) {
jam();
return;
}//if
- tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
- }//while
- if (tlcnNextContainer == ZEMPTYLIST) {
- jam();
- /*empty*/;
- } else {
+ tlcnConIndex = tlcnConIndex + ZBUF_SIZE;
+ }//for
+ }//if
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL USED BUFFERS ON THE LEFT SIDE. */
+ /*-----------------------------------------------------------------*/
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 23) & 0x7f;
+ while (tlcnNextContainer < ZEMPTYLIST) {
+ tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
+ tlcnConIndex = tlcnConIndex + ZHEAD_SIZE;
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex + ZCON_HEAD_SIZE;
+ tlupForward = 1;
+ srCheckContainer(signal);
+ if (tresult != 0) {
jam();
- tresult = 4;
return;
}//if
- /*-----------------------------------------------------------------*/
- /* TAKE CARE OF ALL USED BUFFERS ON THE RIGHT SIDE. */
- /*-----------------------------------------------------------------*/
- tlupForward = cminusOne;
- tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 16) & 0x7f;
- while (tlcnNextContainer < ZEMPTYLIST) {
- tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
- tlcnConIndex = tlcnConIndex + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
- tlupIndex = tlcnConIndex;
- tlupElemIndex = tlcnConIndex - 1;
- srCheckContainer(signal);
- if (tresult != 0) {
- jam();
- return;
- }//if
- tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
- }//while
- if (tlcnNextContainer == ZEMPTYLIST) {
- jam();
- /*empty*/;
- } else {
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
+ }//while
+ if (tlcnNextContainer == ZEMPTYLIST) {
+ jam();
+ /*empty*/;
+ } else {
+ jam();
+ tresult = 4;
+ return;
+ }//if
+ /*-----------------------------------------------------------------*/
+ /* TAKE CARE OF ALL USED BUFFERS ON THE RIGHT SIDE. */
+ /*-----------------------------------------------------------------*/
+ tlupForward = cminusOne;
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[ZPOS_EMPTY_LIST] >> 16) & 0x7f;
+ while (tlcnNextContainer < ZEMPTYLIST) {
+ tlcnConIndex = (tlcnNextContainer << ZSHIFT_PLUS) - (tlcnNextContainer << ZSHIFT_MINUS);
+ tlcnConIndex = tlcnConIndex + ((ZHEAD_SIZE + ZBUF_SIZE) - ZCON_HEAD_SIZE);
+ tlupIndex = tlcnConIndex;
+ tlupElemIndex = tlcnConIndex - 1;
+ srCheckContainer(signal);
+ if (tresult != 0) {
jam();
- tresult = 4;
return;
}//if
+ tlcnNextContainer = (lcnCopyPageptr.p->word32[tlcnConIndex] >> 11) & 0x7f;
+ }//while
+ if (tlcnNextContainer == ZEMPTYLIST) {
+ jam();
+ /*empty*/;
+ } else {
+ jam();
+ tresult = 4;
+ return;
}//if
}//Dbacc::srCheckPage()
@@ -9042,50 +7640,14 @@ void Dbacc::undoWritingProcess(Signal* signal)
writeUndoDataInfo(signal);
checkUndoPages(signal);
}//if
- } else if (tpageType != ZLONG_PAGE_TYPE) {
+ } else {
jam();
/* --------------------------------------------------------------------------- */
/* ONLY PAGE INFO AND OVERFLOW PAGE INFO CAN BE LOGGED BY THIS ROUTINE. A */
/* SERIOUS ERROR. */
/* --------------------------------------------------------------------------- */
sendSystemerror(signal);
- } else {
- /* --------------------------------------------------------------------------------- */
- /* THIS LOG RECORD IS GENERATED ON A LONG KEY PAGE. THESE PAGES USE LOGICAL */
- /* LOGGING. */
- /* --------------------------------------------------------------------------------- */
- if (tactivePageDir >= fragrecptr.p->lcpMaxOverDirIndex) {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* OBVIOUSLY THE FRAGMENT HAS EXPANDED THE NUMBER OF OVERFLOW PAGES SINCE THE */
- /* START OF THE LOCAL CHECKPOINT. WE NEED NOT LOG ANY UPDATES OF PAGES THAT DID*/
- /* NOT EXIST AT START OF LCP. */
- /* --------------------------------------------------------------------------------- */
- /*empty*/;
- } else {
- jam();
- /* --------------------------------------------------------------------------------- */
- /* LOGICAL LOGGING OF LONG KEY PAGES CAN EITHER BE UNDO OF AN INSERT OR UNDO */
- /* OF A DELETE KEY. UNDO OF DELETE NEEDS TO LOG THE KEY TO BE REINSERTED WHILE */
- /* UNDO OF INSERT ONLY NEEDS TO LOG THE INDEX TO BE DELETED. */
- /* --------------------------------------------------------------------------------- */
- undopageptr.i = (cundoposition >> ZUNDOPAGEINDEXBITS) & (cundopagesize - 1);
- ptrAss(undopageptr, undopage);
- theadundoindex = cundoposition & ZUNDOPAGEINDEX_MASK;
- tundoindex = theadundoindex + ZUNDOHEADSIZE;
- if (cundoinfolength == 0) {
- jam();
- writeUndoHeader(signal, tactivePageDir, UndoHeader::ZUNDO_INSERT_LONG_KEY);
- } else {
- jam();
- writeUndoHeader(signal, tactivePageDir, UndoHeader::ZUNDO_DELETE_LONG_KEY);
- arrGuard(ZWORDS_IN_PAGE - cundoElemIndex, 2048);
- tundoElemIndex = datapageptr.p->word32[ZWORDS_IN_PAGE - cundoElemIndex] & 0xffff;
- writeUndoDataInfo(signal);
- }//if
- checkUndoPages(signal);
- }//if
- }//if
+ }
} else {
if (fragrecptr.p->fragState == LCP_SEND_OVER_PAGES) {
jam();
@@ -9120,46 +7682,7 @@ void Dbacc::undoWritingProcess(Signal* signal)
checkUndoPages(signal);
}//if
}//if
- } else if (tpageType == ZLONG_PAGE_TYPE) {
- if (tactivePageDir < fragrecptr.p->lcpDirIndex) {
- jam();
- // -------------------------------------------------------------
- // THIS PAGE HAS ALREADY BEEN WRITTEN IN THE LOCAL CHECKPOINT.
- // -------------------------------------------------------------
- } else {
- if (tactivePageDir >= fragrecptr.p->lcpMaxOverDirIndex) {
- jam();
- // -------------------------------------------------------------
- // OBVIOUSLY THE FRAGMENT HAS EXPANDED THE NUMBER OF OVERFLOW
- // PAGES SINCE THE START OF THE LOCAL CHECKPOINT. WE NEED NOT
- // LOG ANY UPDATES OF PAGES THAT DID NOT EXIST AT START OF LCP.
- // -------------------------------------------------------------
- } else {
- jam();
- // -------------------------------------------------------------
- // LOGICAL LOGGING OF LONG KEY PAGES CAN EITHER BE UNDO OF AN
- // INSERT OR UNDO OF A DELETE KEY. UNDO OF DELETE NEEDS TO LOG
- // THE KEY TO BE REINSERTED WHILE UNDO OF INSERT ONLY NEEDS TO
- // LOG THE INDEX TO BE DELETED.
- // -------------------------------------------------------------
- undopageptr.i = (cundoposition >> ZUNDOPAGEINDEXBITS) & (cundopagesize - 1);
- ptrAss(undopageptr, undopage);
- theadundoindex = cundoposition & ZUNDOPAGEINDEX_MASK;
- tundoindex = theadundoindex + ZUNDOHEADSIZE;
- if (cundoinfolength == 0) {
- jam();
- writeUndoHeader(signal, tactivePageDir, UndoHeader::ZUNDO_INSERT_LONG_KEY);
- } else {
- jam();
- writeUndoHeader(signal, tactivePageDir, UndoHeader::ZUNDO_DELETE_LONG_KEY);
- arrGuard(ZWORDS_IN_PAGE - cundoElemIndex, 2048);
- tundoElemIndex = datapageptr.p->word32[ZWORDS_IN_PAGE - cundoElemIndex] & 0xffff;
- writeUndoDataInfo(signal);
- }//if
- checkUndoPages(signal);
- }//if
- }//if
- }//if
+ }
}//if
}//if
}//Dbacc::undoWritingProcess()
@@ -9212,8 +7735,9 @@ void Dbacc::writeUndoHeader(Signal* signal,
(UndoHeader *) &undopageptr.p->undoword[theadundoindex];
undoHeaderPtr->tableId = rootfragrecptr.p->mytabptr;
- undoHeaderPtr->rootFragId = rootfragrecptr.p->fragmentid[0];
+ undoHeaderPtr->rootFragId = rootfragrecptr.p->fragmentid[0] >> 1;
undoHeaderPtr->localFragId = fragrecptr.p->myfid;
+ ndbrequire((undoHeaderPtr->localFragId >> 1) == undoHeaderPtr->rootFragId);
Uint32 Ttmp = cundoinfolength;
Ttmp = (Ttmp << 4) + pageType;
Ttmp = Ttmp << 14;
@@ -9243,52 +7767,16 @@ void Dbacc::writeUndoOpInfo(Signal* signal)
undopageptr.p->undoword[tundoindex + 1] = operationRecPtr.p->hashValue;
undopageptr.p->undoword[tundoindex + 2] = operationRecPtr.p->tupkeylen;
tundoindex = tundoindex + 3;
- if (fragrecptr.p->keyLength != 0) {
- // Fixed size keys
- jam();
- locPageptr.i = operationRecPtr.p->elementPage;
- ptrCheckGuard(locPageptr, cpagesize, page8);
- Uint32 Tforward = operationRecPtr.p->elementIsforward;
- Uint32 TelemPtr = operationRecPtr.p->elementPointer;
- TelemPtr += Tforward;
- TelemPtr += Tforward;
- //---------------------------------------------------------------------------------
- // Now the pointer is at the start of the key part of the element. Now copy from there
- // to the UNDO log.
- //---------------------------------------------------------------------------------
- Uint32 keyLen = operationRecPtr.p->tupkeylen;
- ndbrequire(keyLen <= 8);
- arrGuard(tundoindex+keyLen, 8192);
- for (Uint32 twuoiIndex = 0; twuoiIndex < keyLen; twuoiIndex++) {
- jam();
- arrGuard(TelemPtr, 2048);
- undopageptr.p->undoword[tundoindex] = locPageptr.p->word32[TelemPtr];
- tundoindex++;
- TelemPtr += Tforward;
- }//for
- cundoinfolength = ZOP_HEAD_INFO_LN + operationRecPtr.p->tupkeylen;
- } else {
- // Long keys
- jam();
-
- arrGuard(operationRecPtr.p->longKeyPageIndex, ZMAX_NO_OF_LONGKEYS_IN_PAGE);
- locPageptr.i = operationRecPtr.p->longPagePtr;
- ptrCheckGuard(locPageptr, cpagesize, page8);
-
- Uint32 indexValue =
- locPageptr.p->word32[ZWORDS_IN_PAGE - operationRecPtr.p->longKeyPageIndex];
- Uint32 keyLen = indexValue >> 16;
- Uint32 physPageIndex = indexValue & 0xffff;
- ndbrequire(keyLen == operationRecPtr.p->tupkeylen);
-
- arrGuard(tundoindex+keyLen, 8192);
- arrGuard(physPageIndex+keyLen, 2048);
- for (Uint32 i = 0; i < keyLen; i++){
- undopageptr.p->undoword[tundoindex + i] = locPageptr.p->word32[physPageIndex+i];
- }
- tundoindex = tundoindex + keyLen;
- cundoinfolength = ZOP_HEAD_INFO_LN + keyLen;
- }//if
+ // log localkey1
+ locPageptr.i = operationRecPtr.p->elementPage;
+ ptrCheckGuard(locPageptr, cpagesize, page8);
+ Uint32 Tforward = operationRecPtr.p->elementIsforward;
+ Uint32 TelemPtr = operationRecPtr.p->elementPointer;
+ TelemPtr += Tforward; // ZELEM_HEAD_SIZE
+ arrGuard(tundoindex+1, 8192);
+ undopageptr.p->undoword[tundoindex] = locPageptr.p->word32[TelemPtr];
+ tundoindex++;
+ cundoinfolength = ZOP_HEAD_INFO_LN + 1;
}//Dbacc::writeUndoOpInfo()
/* --------------------------------------------------------------------------------- */
@@ -9472,7 +7960,7 @@ void Dbacc::initFragAdd(Signal* signal,
}//if
regFragPtr.p->fragState = ACTIVEFRAG;
// NOTE: next line must match calculation in Dblqh::execLQHFRAGREQ
- regFragPtr.p->myfid = (rootFragIndex << (lhFragBits - 1)) | req->fragId;
+ regFragPtr.p->myfid = (req->fragId << 1) | rootFragIndex;
regFragPtr.p->myroot = rootIndex;
regFragPtr.p->myTableId = req->tableId;
ndbrequire(req->kValue == 6);
@@ -9500,13 +7988,8 @@ void Dbacc::initFragAdd(Signal* signal,
regFragPtr.p->dirsize = 1;
regFragPtr.p->loadingFlag = ZFALSE;
regFragPtr.p->keyLength = req->keyLength;
- if (req->keyLength == 0) {
- jam();
- regFragPtr.p->elementLength = (1 + ZELEM_HEAD_SIZE) + regFragPtr.p->localkeylen;
- } else {
- jam();
- regFragPtr.p->elementLength = (ZELEM_HEAD_SIZE + regFragPtr.p->localkeylen) + regFragPtr.p->keyLength;
- }//if
+ ndbrequire(req->keyLength != 0);
+ regFragPtr.p->elementLength = ZELEM_HEAD_SIZE + regFragPtr.p->localkeylen;
Uint32 Tmp1 = (regFragPtr.p->maxp + 1) + regFragPtr.p->p;
Uint32 Tmp2 = regFragPtr.p->maxloadfactor - regFragPtr.p->minloadfactor;
Tmp2 = Tmp1 * Tmp2;
@@ -9530,6 +8013,7 @@ void Dbacc::initFragGeneral(FragmentrecPtr regFragPtr)
regFragPtr.p->activeDataPage = 0;
regFragPtr.p->createLcp = ZFALSE;
regFragPtr.p->stopQueOp = ZFALSE;
+ regFragPtr.p->hasCharAttr = ZFALSE;
regFragPtr.p->nextAllocPage = 0;
regFragPtr.p->nrWaitWriteUndoExit = 0;
regFragPtr.p->lastUndoIsStored = ZFALSE;
@@ -10115,7 +8599,7 @@ void Dbacc::startUndoLab(Signal* signal)
}//for
// Send report of how many undo log records where executed
- signal->theData[0] = EventReport::UNDORecordsExecuted;
+ signal->theData[0] = NDB_LE_UNDORecordsExecuted;
signal->theData[1] = DBACC; // From block
signal->theData[2] = 0; // Total records executed
for (int i = 0; i < 10; i++){
@@ -10308,6 +8792,7 @@ void Dbacc::srDoUndoLab(Signal* signal)
// ROOT FRAGMENT ID
tfid = undoHeaderPtr->rootFragId;
+ ndbrequire((undoHeaderPtr->localFragId >> 1) == undoHeaderPtr->rootFragId);
if (!getrootfragmentrec(signal, rootfragrecptr, tfid)) {
jam();
/*---------------------------------------------------------------------*/
@@ -10317,7 +8802,10 @@ void Dbacc::srDoUndoLab(Signal* signal)
creadyUndoaddress = cprevUndoaddress;
// PREVIOUS UNDO LOG RECORD FOR ALL FRAGMENTS
cprevUndoaddress = undoHeaderPtr->prevUndoAddress;
- undoNext2Lab(signal);
+ undoNext2Lab(signal);
+#ifdef VM_TRACE
+ ndbout_c("ignoring root fid %d", (int)tfid);
+#endif
return;
}//if
/*-----------------------------------------------------------------------*/
@@ -10427,103 +8915,6 @@ void Dbacc::srDoUndoLab(Signal* signal)
break;
}
- case UndoHeader::ZUNDO_INSERT_LONG_KEY:{
- jam();
- /*---------------------------------------------------------------------*/
- /* WE WILL UNDO AN INSERT OF A LONG KEY. THIS IS PERFORMED BY DELETING */
- /* THE LONG KEY. */
- /*---------------------------------------------------------------------*/
- souDirRangePtr.i = fragrecptr.p->overflowdir;
- tmpP2 = tmpP >> 8;
- tmpP = tmpP & 0xff;
- arrGuard(tmpP2, 256);
- ptrCheckGuard(souDirRangePtr, cdirrangesize, dirRange);
- souDirptr.i = souDirRangePtr.p->dirArray[tmpP2];
- ptrCheckGuard(souDirptr, cdirarraysize, directoryarray);
- dlkPageptr.i = souDirptr.p->pagep[tmpP];
- ptrCheckGuard(dlkPageptr, cpagesize, page8);
- tdlkLogicalPageIndex = tundoPageindex;
- deleteLongKey(signal);
- break;
- }
-
- case UndoHeader::ZUNDO_DELETE_LONG_KEY: {
- jam();
- /*----------------------------------------------------------------------*/
- /* WE WILL UNDO DELETE OF A LONG KEY. THIS IS PERFORMED BY INSERTING */
- /* IT AGAIN. */
- /*----------------------------------------------------------------------*/
- souDirRangePtr.i = fragrecptr.p->overflowdir;
- taslpDirIndex = tmpP;
- tmpP2 = tmpP >> 8;
- tmpP = tmpP & 0xff;
- ptrCheckGuard(souDirRangePtr, cdirrangesize, dirRange);
- arrGuard(tmpP2, 256);
- souDirptr.i = souDirRangePtr.p->dirArray[tmpP2];
-
- if(souDirptr.i == RNIL) {
- //----------------------------------------------------------------
- // Allocate a directory.
- //----------------------------------------------------------------
- jam();
- seizeDirectory(signal);
- if (tresult > ZLIMIT_OF_ERROR) {
- jam();
- sendSystemerror(signal);
- return;
- }
- souDirRangePtr.p->dirArray[tmpP2] = sdDirptr.i;
- souDirptr.i = souDirRangePtr.p->dirArray[tmpP2];
- }
-
- ptrCheckGuard(souDirptr, cdirarraysize, directoryarray);
- slkapPageptr.i = souDirptr.p->pagep[tmpP];
-
- if(slkapPageptr.i == RNIL) {
- //----------------------------------------------------------------
- // The delete operation was probably the last on the page and the
- // page was released and not written down to disk. We need to
- // allocate a page and put it in the same dirindex as it was in
- // before it was released.
- // This is because an eventual UNDO_INSERT on the same key in the
- // same LCP must be able to find the key and it has only the
- // dirindex to go on, the key itself is not saved on disk in a
- // UNDO_INSERT.
- //----------------------------------------------------------------
- jam();
- allocSpecificLongOverflowPage(signal);
- slkapPageptr.i = aslpPageptr.i;
- }
-
- ptrCheckGuard(slkapPageptr, cpagesize, page8);
- seizePage(signal);
- ndbrequire(tresult <= ZLIMIT_OF_ERROR);
-
- slkapCopyPageptr = spPageptr;
- ndbrequire(cundoinfolength <= 2048);
-
- for (Uint32 tmp = 0; tmp < cundoinfolength; tmp++) {
- dbgWord32(slkapCopyPageptr, tmp, undopageptr.p->undoword[tmpindex]);
- slkapCopyPageptr.p->word32[tmp] = undopageptr.p->undoword[tmpindex];
- tmpindex = tmpindex + 1;
- }//for
- jam();
- //----------------------------------------------------------------
- // We must store the key at the same place it was deleted from.
- // This is because an eventual UNDO_INSERT on the same key in the
- // same LCP must be able to find the key and it has only the index
- // information stored on disk to go on, the key itself is not
- // saved on disk in an UNDO_INSERT.
- //----------------------------------------------------------------
- tslkapKeyLen = cundoinfolength;
- tslkapPageIndex = tundoPageindex;
- storeLongKeysAtPos(signal);
-
- rpPageptr = slkapCopyPageptr;
- releasePage(signal);
- break;
- }
-
case UndoHeader::ZOP_INFO: {
jam();
/*---------------------------------------------------------------------*/
@@ -10562,6 +8953,7 @@ void Dbacc::srDoUndoLab(Signal* signal)
operationRecPtr.p->longKeyPageIndex = RNIL;
operationRecPtr.p->scanRecPtr = RNIL;
operationRecPtr.p->isAccLockReq = ZFALSE;
+ operationRecPtr.p->isUndoLogReq = ZTRUE;
// Read operation values from undo page
operationRecPtr.p->operation = undopageptr.p->undoword[tmpindex];
@@ -10571,17 +8963,15 @@ void Dbacc::srDoUndoLab(Signal* signal)
const Uint32 tkeylen = undopageptr.p->undoword[tmpindex];
tmpindex++;
operationRecPtr.p->tupkeylen = tkeylen;
+ operationRecPtr.p->xfrmtupkeylen = 0; // not used
operationRecPtr.p->fragptr = fragrecptr.i;
- ndbrequire((fragrecptr.p->keyLength == 0) ||
- ((fragrecptr.p->keyLength != 0) &&
- (fragrecptr.p->keyLength == tkeylen)));
+ ndbrequire(fragrecptr.p->keyLength != 0 &&
+ fragrecptr.p->keyLength == tkeylen);
- // Read keydata from undo page
- for (Uint32 tmp = 0; tmp < tkeylen; tmp++) {
- signal->theData[7+tmp] = undopageptr.p->undoword[tmpindex];
- tmpindex = tmpindex + 1;
- }//for
+ // Read localkey1 from undo page
+ signal->theData[7 + 0] = undopageptr.p->undoword[tmpindex];
+ tmpindex = tmpindex + 1;
arrGuard((tmpindex - 1), 8192);
getElement(signal);
if (tgeResult != ZTRUE) {
@@ -10764,43 +9154,25 @@ void Dbacc::execACC_OVER_REC(Signal* signal)
ptrCheckGuard(pnoPageidptr, cpagesize, page8);
tpnoPageType = pnoPageidptr.p->word32[ZPOS_PAGE_TYPE];
tpnoPageType = (tpnoPageType >> ZPOS_PAGE_TYPE_BIT) & 3;
- if (tpnoPageType == ZLONG_PAGE_TYPE) {
+ if (pnoPageidptr.p->word32[ZPOS_ALLOC_CONTAINERS] > ZFREE_LIMIT) {
jam();
- // This is to clean the list parameters.
- pnoPageidptr.p->word32[ZPOS_PREV_PAGE] = RNIL;
- pnoPageidptr.p->word32[ZPOS_NEXT_PAGE] = RNIL;
- if (pnoPageidptr.p->word32[ZPOS_ARRAY_POS] != 4) {
- jam();
- /*---------------------------------------------------------------------------*/
- /* THE PAGE WAS A LONG PAGE AND IT BELONGED TO A FREE LIST. PUT IT INTO ONE */
- /* OF THE FREE LIST THEN. */
- /*---------------------------------------------------------------------------*/
- // Insert page!
- ipaPagePtr = pnoPageidptr;
- tipaArrayPos = pnoPageidptr.p->word32[ZPOS_ARRAY_POS];
- insertPageArrayList(signal);
- }//if
+ dbgWord32(pnoPageidptr, ZPOS_OVERFLOWREC, RNIL);
+ pnoPageidptr.p->word32[ZPOS_OVERFLOWREC] = RNIL;
+ ndbrequire(pnoPageidptr.p->word32[ZPOS_PAGE_ID] == fragrecptr.p->nextAllocPage);
} else {
- if (pnoPageidptr.p->word32[ZPOS_ALLOC_CONTAINERS] > ZFREE_LIMIT) {
- jam();
- dbgWord32(pnoPageidptr, ZPOS_OVERFLOWREC, RNIL);
- pnoPageidptr.p->word32[ZPOS_OVERFLOWREC] = RNIL;
- ndbrequire(pnoPageidptr.p->word32[ZPOS_PAGE_ID] == fragrecptr.p->nextAllocPage);
- } else {
+ jam();
+ seizeOverRec(signal);
+ sorOverflowRecPtr.p->dirindex = pnoPageidptr.p->word32[ZPOS_PAGE_ID];
+ ndbrequire(sorOverflowRecPtr.p->dirindex == fragrecptr.p->nextAllocPage);
+ dbgWord32(pnoPageidptr, ZPOS_OVERFLOWREC, sorOverflowRecPtr.i);
+ pnoPageidptr.p->word32[ZPOS_OVERFLOWREC] = sorOverflowRecPtr.i;
+ sorOverflowRecPtr.p->overpage = pnoPageidptr.i;
+ porOverflowRecPtr = sorOverflowRecPtr;
+ putOverflowRecInFrag(signal);
+ if (pnoPageidptr.p->word32[ZPOS_ALLOC_CONTAINERS] == 0) {
jam();
- seizeOverRec(signal);
- sorOverflowRecPtr.p->dirindex = pnoPageidptr.p->word32[ZPOS_PAGE_ID];
- ndbrequire(sorOverflowRecPtr.p->dirindex == fragrecptr.p->nextAllocPage);
- dbgWord32(pnoPageidptr, ZPOS_OVERFLOWREC, sorOverflowRecPtr.i);
- pnoPageidptr.p->word32[ZPOS_OVERFLOWREC] = sorOverflowRecPtr.i;
- sorOverflowRecPtr.p->overpage = pnoPageidptr.i;
- porOverflowRecPtr = sorOverflowRecPtr;
- putOverflowRecInFrag(signal);
- if (pnoPageidptr.p->word32[ZPOS_ALLOC_CONTAINERS] == 0) {
- jam();
- ropPageptr = pnoPageidptr;
- releaseOverpage(signal);
- }//if
+ ropPageptr = pnoPageidptr;
+ releaseOverpage(signal);
}//if
}//if
}//if
@@ -10875,7 +9247,6 @@ void Dbacc::execACC_SCANREQ(Signal* signal)
rootfragrecptr.p->scan[i] = scanPtr.i;
scanPtr.p->scanBucketState = ScanRec::FIRST_LAP;
scanPtr.p->scanLockMode = AccScanReq::getLockMode(tscanFlag);
- scanPtr.p->scanKeyinfoFlag = AccScanReq::getKeyinfoFlag(tscanFlag);
scanPtr.p->scanReadCommittedFlag = AccScanReq::getReadCommittedFlag(tscanFlag);
/* TWELVE BITS OF THE ELEMENT HEAD ARE SCAN */
@@ -11623,11 +9994,6 @@ void Dbacc::initScanOpRec(Signal* signal)
Uint32 tisoTmp;
Uint32 tisoLocalPtr;
Uint32 guard24;
- Uint32 tisoPageIndex;
- Uint32 tisoPagedir;
- DirRangePtr tisoOverflowrangeptr;
- DirectoryarrayPtr tisoOverflowDirptr;
- Page8Ptr tisoPageptr;
scanPtr.p->scanOpsAllocated++;
@@ -11656,6 +10022,7 @@ void Dbacc::initScanOpRec(Signal* signal)
operationRecPtr.p->elementPointer = tisoElementptr;
operationRecPtr.p->elementPage = isoPageptr.i;
operationRecPtr.p->isAccLockReq = ZFALSE;
+ operationRecPtr.p->isUndoLogReq = ZFALSE;
tisoLocalPtr = tisoElementptr + tisoIsforward;
guard24 = fragrecptr.p->localkeylen - 1;
for (tisoTmp = 0; tisoTmp <= guard24; tisoTmp++) {
@@ -11666,40 +10033,8 @@ void Dbacc::initScanOpRec(Signal* signal)
}//for
arrGuard(tisoLocalPtr, 2048);
operationRecPtr.p->keydata[0] = isoPageptr.p->word32[tisoLocalPtr];
- if (fragrecptr.p->keyLength != 0) {
- jam();
- operationRecPtr.p->tupkeylen = fragrecptr.p->keyLength;
- guard24 = fragrecptr.p->keyLength - 1;
- for (tisoTmp = 0; tisoTmp <= guard24; tisoTmp++) {
- arrGuard(tisoTmp, 8);
- arrGuard(tisoLocalPtr, 2048);
- operationRecPtr.p->keydata[tisoTmp] = isoPageptr.p->word32[tisoLocalPtr];
- tisoLocalPtr = tisoLocalPtr + tisoIsforward;
- }//for
- } else {
- // Long key handling. Put the long key reference in the operation records.
- tisoPageIndex = operationRecPtr.p->keydata[0] & 0x3ff;
- arrGuard(ZWORDS_IN_PAGE - tisoPageIndex, 2048);
-
- tisoPagedir = operationRecPtr.p->keydata[0] >> 10;
- arrGuard((tisoPagedir >> 8), 256);
-
- tisoOverflowrangeptr.i = fragrecptr.p->overflowdir;
- ptrCheckGuard(tisoOverflowrangeptr, cdirrangesize, dirRange);
-
- tisoOverflowDirptr.i = tisoOverflowrangeptr.p->dirArray[tisoPagedir >> 8];
- ptrCheckGuard(tisoOverflowDirptr, cdirarraysize, directoryarray);
-
- tisoPageptr.i = tisoOverflowDirptr.p->pagep[tisoPagedir & 0xff];
- ptrCheckGuard(tisoPageptr, cpagesize, page8);
-
- operationRecPtr.p->longPagePtr = tisoPageptr.i;
- operationRecPtr.p->longKeyPageIndex = tisoPageIndex;
-
- // Read length of key from page
- Uint32 tmp = tisoPageptr.p->word32[ZWORDS_IN_PAGE - tisoPageIndex];
- operationRecPtr.p->tupkeylen = tmp >> 16;
- }
+ operationRecPtr.p->tupkeylen = fragrecptr.p->keyLength;
+ operationRecPtr.p->xfrmtupkeylen = 0; // not used
}//Dbacc::initScanOpRec()
/* --------------------------------------------------------------------------------- */
@@ -11894,21 +10229,15 @@ void Dbacc::releaseScanContainer(Signal* signal)
Uint32 trscElemlens;
Uint32 trscElemlen;
- if (trscContainerlen < 5) {
+ if (trscContainerlen < 4) {
if (trscContainerlen != ZCON_HEAD_SIZE) {
jam();
sendSystemerror(signal);
}//if
- return; /* 3 IS THE MINIMUM SIZE OF THE ELEMENT */
- }//if
- trscElemlens = trscContainerlen - 2;
- if (fragrecptr.p->keyLength != 0) {
- jam();
- trscElemlen = (1 + fragrecptr.p->keyLength) + fragrecptr.p->localkeylen; /* LENGTH OF THE ELEMENT */
- } else {
- jam();
- trscElemlen = (1 + ZACTIVE_LONG_KEY_LEN) + fragrecptr.p->localkeylen; /* LENGTH OF THE ELEMENT */
+ return; /* 2 IS THE MINIMUM SIZE OF THE ELEMENT */
}//if
+ trscElemlens = trscContainerlen - ZCON_HEAD_SIZE;
+ trscElemlen = fragrecptr.p->elementLength;
if (trscIsforward == 1) {
jam();
trscElementptr = trscContainerptr + ZCON_HEAD_SIZE;
@@ -11935,7 +10264,7 @@ void Dbacc::releaseScanContainer(Signal* signal)
}//if
trscElemlens = trscElemlens - trscElemlen;
trscElementptr = trscElementptr + trscElemStep;
- } while (trscElemlens > 2);
+ } while (trscElemlens > 1);
if (trscElemlens != 0) {
jam();
sendSystemerror(signal);
@@ -11994,19 +10323,12 @@ bool Dbacc::searchScanContainer(Signal* signal)
Uint32 tsscElemlen;
Uint32 tsscElemStep;
- if (tsscContainerlen < 5) {
+ if (tsscContainerlen < 4) {
jam();
- return false; /* 3 IS THE MINIMUM SIZE OF THE ELEMENT */
+ return false; /* 2 IS THE MINIMUM SIZE OF THE ELEMENT */
}//if
tsscElemlens = tsscContainerlen - ZCON_HEAD_SIZE;
- if (fragrecptr.p->keyLength == 0) {
- jam();
- tsscElemlen = (ZELEM_HEAD_SIZE + ZACTIVE_LONG_KEY_LEN) + fragrecptr.p->localkeylen;
- } else {
- jam();
- /* LENGTH OF THE ELEMENT */
- tsscElemlen = (ZELEM_HEAD_SIZE + fragrecptr.p->keyLength) + fragrecptr.p->localkeylen;
- }//if
+ tsscElemlen = fragrecptr.p->elementLength;
/* LENGTH OF THE ELEMENT */
if (tsscIsforward == 1) {
jam();
@@ -12044,7 +10366,7 @@ bool Dbacc::searchScanContainer(Signal* signal)
/* THE ELEMENT IS ALREADY SENT. */
/* SEARCH FOR NEXT ONE */
tsscElemlens = tsscElemlens - tsscElemlen;
- if (tsscElemlens > 2) {
+ if (tsscElemlens > 1) {
jam();
tsscElementptr = tsscElementptr + tsscElemStep;
goto SCANELEMENTLOOP001;
@@ -12059,172 +10381,20 @@ void Dbacc::sendNextScanConf(Signal* signal)
{
scanPtr.p->scanTimer = scanPtr.p->scanContinuebCounter;
Uint32 blockNo = refToBlock(scanPtr.p->scanUserblockref);
- if (!scanPtr.p->scanKeyinfoFlag){
- jam();
- /** ---------------------------------------------------------------------
- * LQH WILL NOT HAVE ANY USE OF THE TUPLE KEY LENGTH IN THIS CASE AND
- * SO WE DO NOT PROVIDE IT. IN THIS CASE THESE VALUES ARE UNDEFINED.
- * ---------------------------------------------------------------------- */
- signal->theData[0] = scanPtr.p->scanUserptr;
- signal->theData[1] = operationRecPtr.i;
- signal->theData[2] = operationRecPtr.p->fid;
- signal->theData[3] = operationRecPtr.p->localdata[0];
- signal->theData[4] = operationRecPtr.p->localdata[1];
- signal->theData[5] = fragrecptr.p->localkeylen;
- EXECUTE_DIRECT(blockNo, GSN_NEXT_SCANCONF, signal, 6);
- return;
- }//if
-
- if (fragrecptr.p->keyLength != 0) {
- jam();
- signal->theData[0] = scanPtr.p->scanUserptr;
- signal->theData[1] = operationRecPtr.i;
- signal->theData[2] = operationRecPtr.p->fid;
- signal->theData[3] = operationRecPtr.p->localdata[0];
- signal->theData[4] = operationRecPtr.p->localdata[1];
- signal->theData[5] = fragrecptr.p->localkeylen;
- signal->theData[6] = fragrecptr.p->keyLength;
- signal->theData[7] = operationRecPtr.p->keydata[0];
- signal->theData[8] = operationRecPtr.p->keydata[1];
- signal->theData[9] = operationRecPtr.p->keydata[2];
- signal->theData[10] = operationRecPtr.p->keydata[3];
- EXECUTE_DIRECT(blockNo, GSN_NEXT_SCANCONF, signal, 11);
- if (fragrecptr.p->keyLength > ZKEYINKEYREQ) {
- jam();
- /* = 4 */
- signal->theData[0] = scanPtr.p->scanUserptr;
- signal->theData[1] = operationRecPtr.i;
- signal->theData[2] = operationRecPtr.p->fid;
- signal->theData[3] = fragrecptr.p->keyLength - ZKEYINKEYREQ;
- signal->theData[4] = operationRecPtr.p->keydata[4];
- signal->theData[5] = operationRecPtr.p->keydata[5];
- signal->theData[6] = operationRecPtr.p->keydata[6];
- signal->theData[7] = operationRecPtr.p->keydata[7];
- EXECUTE_DIRECT(blockNo, GSN_ACC_SCAN_INFO, signal, 8);
- return;
- }//if
- } else {
- jam();
- sendScaninfo(signal);
- return;
- }//if
-}//Dbacc::sendNextScanConf()
-
-/* --------------------------------------------------------------------------------- */
-/* SEND_SCANINFO */
-/* DESCRIPTION: SCAN AN ELEMENT OF A LONG_KEY_PAGE. */
-/* --------------------------------------------------------------------------------- */
-void Dbacc::sendScaninfo(Signal* signal)
-{
- DirRangePtr ssiOverflowrangeptr;
- DirectoryarrayPtr ssiOverflowDirptr;
- Page8Ptr ssiPageptr;
- Uint32 tssiPageIndex;
- Uint32 tssiPagedir;
- Uint32 tssiKeyLen;
- Uint32 tssiStartIndex;
- Uint32 tssiIndexValue;
- Uint32 tssiTmp;
-
- Uint32 blockNo = refToBlock(scanPtr.p->scanUserblockref);
-
- tssiPageIndex = operationRecPtr.p->keydata[0] & 0x3ff;
- tssiPagedir = operationRecPtr.p->keydata[0] >> 10;
- ssiOverflowrangeptr.i = fragrecptr.p->overflowdir;
- ptrCheckGuard(ssiOverflowrangeptr, cdirrangesize, dirRange);
- arrGuard((tssiPagedir >> 8), 256);
- ssiOverflowDirptr.i = ssiOverflowrangeptr.p->dirArray[tssiPagedir >> 8];
- ptrCheckGuard(ssiOverflowDirptr, cdirarraysize, directoryarray);
- ssiPageptr.i = ssiOverflowDirptr.p->pagep[tssiPagedir & 0xff];
- ptrCheckGuard(ssiPageptr, cpagesize, page8);
- arrGuard(ZWORDS_IN_PAGE - tssiPageIndex, 2048);
- tssiIndexValue = ssiPageptr.p->word32[ZWORDS_IN_PAGE - tssiPageIndex];
- tssiStartIndex = tssiIndexValue & 0xffff;
- tssiKeyLen = tssiIndexValue >> 16;
+ jam();
+ /** ---------------------------------------------------------------------
+ * LQH WILL NOT HAVE ANY USE OF THE TUPLE KEY LENGTH IN THIS CASE AND
+ * SO WE DO NOT PROVIDE IT. IN THIS CASE THESE VALUES ARE UNDEFINED.
+ * ---------------------------------------------------------------------- */
signal->theData[0] = scanPtr.p->scanUserptr;
signal->theData[1] = operationRecPtr.i;
signal->theData[2] = operationRecPtr.p->fid;
signal->theData[3] = operationRecPtr.p->localdata[0];
signal->theData[4] = operationRecPtr.p->localdata[1];
signal->theData[5] = fragrecptr.p->localkeylen;
- signal->theData[6] = tssiKeyLen;
- arrGuard(tssiStartIndex + 3, 2048);
- signal->theData[7] = ssiPageptr.p->word32[tssiStartIndex];
- signal->theData[8] = ssiPageptr.p->word32[tssiStartIndex + 1];
- signal->theData[9] = ssiPageptr.p->word32[tssiStartIndex + 2];
- signal->theData[10] = ssiPageptr.p->word32[tssiStartIndex + 3];
- EXECUTE_DIRECT(blockNo, GSN_NEXT_SCANCONF, signal, 11);
- if (tssiKeyLen > 4) {
- tssiKeyLen = tssiKeyLen - 4;
- tssiStartIndex = tssiStartIndex + 4;
- SSI_LOOP_10:
- jamEntry();
- if (tssiKeyLen > ZMAXSCANSIGNALLEN) {
- jam();
- signal->theData[0] = scanPtr.p->scanUserptr;
- signal->theData[1] = operationRecPtr.i;
- signal->theData[2] = operationRecPtr.p->fid;
- signal->theData[3] = ZMAXSCANSIGNALLEN;
- arrGuard(tssiStartIndex + 19, 2048);
- signal->theData[4] = ssiPageptr.p->word32[tssiStartIndex];
- signal->theData[5] = ssiPageptr.p->word32[tssiStartIndex + 1];
- signal->theData[6] = ssiPageptr.p->word32[tssiStartIndex + 2];
- signal->theData[7] = ssiPageptr.p->word32[tssiStartIndex + 3];
- signal->theData[8] = ssiPageptr.p->word32[tssiStartIndex + 4];
- signal->theData[9] = ssiPageptr.p->word32[tssiStartIndex + 5];
- signal->theData[10] = ssiPageptr.p->word32[tssiStartIndex + 6];
- signal->theData[11] = ssiPageptr.p->word32[tssiStartIndex + 7];
- signal->theData[12] = ssiPageptr.p->word32[tssiStartIndex + 8];
- signal->theData[13] = ssiPageptr.p->word32[tssiStartIndex + 9];
- signal->theData[14] = ssiPageptr.p->word32[tssiStartIndex + 10];
- signal->theData[15] = ssiPageptr.p->word32[tssiStartIndex + 11];
- signal->theData[16] = ssiPageptr.p->word32[tssiStartIndex + 12];
- signal->theData[17] = ssiPageptr.p->word32[tssiStartIndex + 13];
- signal->theData[18] = ssiPageptr.p->word32[tssiStartIndex + 14];
- signal->theData[19] = ssiPageptr.p->word32[tssiStartIndex + 15];
- signal->theData[20] = ssiPageptr.p->word32[tssiStartIndex + 16];
- signal->theData[21] = ssiPageptr.p->word32[tssiStartIndex + 17];
- signal->theData[22] = ssiPageptr.p->word32[tssiStartIndex + 18];
- signal->theData[23] = ssiPageptr.p->word32[tssiStartIndex + 19];
- EXECUTE_DIRECT(blockNo, GSN_ACC_SCAN_INFO24, signal, 24);
- tssiStartIndex = tssiStartIndex + ZMAXSCANSIGNALLEN;
- tssiKeyLen = tssiKeyLen - ZMAXSCANSIGNALLEN;
- goto SSI_LOOP_10;
- } else {
- jam();
- ndbrequire((tssiStartIndex + tssiKeyLen) <= 2048);
- for (tssiTmp = 0; tssiTmp < tssiKeyLen; tssiTmp++) {
- ckeys[tssiTmp] = ssiPageptr.p->word32[tssiStartIndex + tssiTmp];
- }//for
- signal->theData[0] = scanPtr.p->scanUserptr;
- signal->theData[1] = operationRecPtr.i;
- signal->theData[2] = operationRecPtr.p->fid;
- /* LOCAL FRAGMENT IDENTITY */
- signal->theData[3] = tssiKeyLen;
- signal->theData[4] = ckeys[0];
- signal->theData[5] = ckeys[1];
- signal->theData[6] = ckeys[2];
- signal->theData[7] = ckeys[3];
- signal->theData[8] = ckeys[4];
- signal->theData[9] = ckeys[5];
- signal->theData[10] = ckeys[6];
- signal->theData[11] = ckeys[7];
- signal->theData[12] = ckeys[8];
- signal->theData[13] = ckeys[9];
- signal->theData[14] = ckeys[10];
- signal->theData[15] = ckeys[11];
- signal->theData[16] = ckeys[12];
- signal->theData[17] = ckeys[13];
- signal->theData[18] = ckeys[14];
- signal->theData[19] = ckeys[15];
- signal->theData[20] = ckeys[16];
- signal->theData[21] = ckeys[17];
- signal->theData[22] = ckeys[18];
- signal->theData[23] = ckeys[19];
- EXECUTE_DIRECT(blockNo, GSN_ACC_SCAN_INFO24, signal, 24);
- }//if
- }//if
-}//Dbacc::sendScaninfo()
+ EXECUTE_DIRECT(blockNo, GSN_NEXT_SCANCONF, signal, 6);
+ return;
+}//Dbacc::sendNextScanConf()
/*---------------------------------------------------------------------------
* sendScanHbRep
@@ -13277,7 +11447,7 @@ void Dbacc::takeRecOutOfFreeOverpage(Signal* signal)
void
Dbacc::reportMemoryUsage(Signal* signal, int gth){
- signal->theData[0] = EventReport::MemoryUsage;
+ signal->theData[0] = NDB_LE_MemoryUsage;
signal->theData[1] = gth;
signal->theData[2] = sizeof(* rpPageptr.p);
signal->theData[3] = cnoOfAllocatedPages;
@@ -13327,13 +11497,12 @@ Dbacc::execDUMP_STATE_ORD(Signal* signal)
scanPtr.p->minBucketIndexToRescan,
scanPtr.p->maxBucketIndexToRescan);
infoEvent(" scanBucketState=%d, scanLockHeld=%d, userBlockRef=%d, "
- "scanMask=%d scanLockMode=%d, keyInfoFlag=%d",
+ "scanMask=%d scanLockMode=%d",
scanPtr.p->scanBucketState,
scanPtr.p->scanLockHeld,
scanPtr.p->scanUserblockref,
scanPtr.p->scanMask,
- scanPtr.p->scanLockMode,
- scanPtr.p->scanKeyinfoFlag);
+ scanPtr.p->scanLockMode);
return;
}
diff --git a/ndb/src/kernel/blocks/dbacc/Makefile.am b/ndb/src/kernel/blocks/dbacc/Makefile.am
index e44524c3edd..ca1b1efac37 100644
--- a/ndb/src/kernel/blocks/dbacc/Makefile.am
+++ b/ndb/src/kernel/blocks/dbacc/Makefile.am
@@ -3,6 +3,8 @@ noinst_LIBRARIES = libdbacc.a
libdbacc_a_SOURCES = DbaccInit.cpp DbaccMain.cpp
+INCLUDES_LOC = -I$(top_srcdir)/ndb/src/kernel/blocks/dbtup
+
include $(top_srcdir)/ndb/config/common.mk.am
include $(top_srcdir)/ndb/config/type_kernel.mk.am
diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
index 184db794057..3d5340494ab 100644
--- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
+++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
@@ -206,7 +206,7 @@ void Dbdict::packTableIntoPages(Signal* signal, Uint32 tableId, Uint32 pageId)
8 * ZSIZE_OF_PAGES_IN_WORDS);
w.first();
- packTableIntoPagesImpl(w, tablePtr);
+ packTableIntoPagesImpl(w, tablePtr, signal);
Uint32 wordsOfTable = w.getWordsUsed();
Uint32 pagesUsed =
@@ -235,7 +235,8 @@ void Dbdict::packTableIntoPages(Signal* signal, Uint32 tableId, Uint32 pageId)
void
Dbdict::packTableIntoPagesImpl(SimpleProperties::Writer & w,
- TableRecordPtr tablePtr){
+ TableRecordPtr tablePtr,
+ Signal* signal){
w.add(DictTabInfo::TableName, tablePtr.p->tableName);
w.add(DictTabInfo::TableId, tablePtr.i);
@@ -256,9 +257,32 @@ Dbdict::packTableIntoPagesImpl(SimpleProperties::Writer & w,
w.add(DictTabInfo::MaxLoadFactor, tablePtr.p->maxLoadFactor);
w.add(DictTabInfo::TableKValue, tablePtr.p->kValue);
w.add(DictTabInfo::FragmentTypeVal, tablePtr.p->fragmentType);
- w.add(DictTabInfo::FragmentKeyTypeVal, tablePtr.p->fragmentKeyType);
w.add(DictTabInfo::TableTypeVal, tablePtr.p->tableType);
- w.add(DictTabInfo::FragmentCount, tablePtr.p->fragmentCount);
+
+ if(!signal)
+ {
+ w.add(DictTabInfo::FragmentCount, tablePtr.p->fragmentCount);
+ }
+ else
+ {
+ Uint32 * theData = signal->getDataPtrSend();
+ CreateFragmentationReq * const req = (CreateFragmentationReq*)theData;
+ req->senderRef = 0;
+ req->senderData = RNIL;
+ req->fragmentationType = tablePtr.p->fragmentType;
+ req->noOfFragments = 0;
+ req->fragmentNode = 0;
+ req->primaryTableId = tablePtr.i;
+ EXECUTE_DIRECT(DBDIH, GSN_CREATE_FRAGMENTATION_REQ, signal,
+ CreateFragmentationReq::SignalLength);
+ if(signal->theData[0] == 0)
+ {
+ Uint16 *data = (Uint16*)&signal->theData[25];
+ Uint32 count = 2 + data[0] * data[1];
+ w.add(DictTabInfo::FragmentDataLen, 2*count);
+ w.add(DictTabInfo::FragmentData, data, 2*count);
+ }
+ }
if (tablePtr.p->primaryTableId != RNIL){
TableRecordPtr primTab;
@@ -289,18 +313,14 @@ Dbdict::packTableIntoPagesImpl(SimpleProperties::Writer & w,
const Uint32 attrSize = AttributeDescriptor::getSize(desc);
const Uint32 arraySize = AttributeDescriptor::getArraySize(desc);
const Uint32 nullable = AttributeDescriptor::getNullable(desc);
- const Uint32 DGroup = AttributeDescriptor::getDGroup(desc);
const Uint32 DKey = AttributeDescriptor::getDKey(desc);
- const Uint32 attrStoredInd = AttributeDescriptor::getStoredInTup(desc);
- w.add(DictTabInfo::AttributeType, attrType);
+ // AttributeType deprecated
w.add(DictTabInfo::AttributeSize, attrSize);
w.add(DictTabInfo::AttributeArraySize, arraySize);
w.add(DictTabInfo::AttributeNullableFlag, nullable);
- w.add(DictTabInfo::AttributeDGroup, DGroup);
w.add(DictTabInfo::AttributeDKey, DKey);
- w.add(DictTabInfo::AttributeStoredInd, attrStoredInd);
- w.add(DictTabInfo::AttributeExtType, attrPtr.p->extType);
+ w.add(DictTabInfo::AttributeExtType, attrType);
w.add(DictTabInfo::AttributeExtPrecision, attrPtr.p->extPrecision);
w.add(DictTabInfo::AttributeExtScale, attrPtr.p->extScale);
w.add(DictTabInfo::AttributeExtLength, attrPtr.p->extLength);
@@ -1340,10 +1360,8 @@ void Dbdict::initialiseTableRecord(TableRecordPtr tablePtr)
tablePtr.p->tableVersion = (Uint32)-1;
tablePtr.p->tabState = TableRecord::NOT_DEFINED;
tablePtr.p->tabReturnState = TableRecord::TRS_IDLE;
- tablePtr.p->storageType = DictTabInfo::MainMemory;
tablePtr.p->myConnect = RNIL;
tablePtr.p->fragmentType = DictTabInfo::AllNodesSmallTable;
- tablePtr.p->fragmentKeyType = DictTabInfo::PrimaryKey;
memset(tablePtr.p->tableName, 0, sizeof(tablePtr.p->tableName));
tablePtr.p->gciTableCreated = 0;
tablePtr.p->noOfAttributes = ZNIL;
@@ -2228,7 +2246,7 @@ void Dbdict::checkSchemaStatus(Signal* signal)
return;
}//if
}
- ndbrequire(ok);
+ ndbrequire(ok);
break;
}
case SchemaFile::DROP_TABLE_STARTED:
@@ -4104,14 +4122,14 @@ Dbdict::execADD_FRAGREQ(Signal* signal) {
req->maxLoadFactor = tabPtr.p->maxLoadFactor;
req->minLoadFactor = tabPtr.p->minLoadFactor;
req->kValue = tabPtr.p->kValue;
- req->lh3DistrBits = lhDistrBits;
- req->lh3PageBits = lhPageBits;
+ req->lh3DistrBits = 0; //lhDistrBits;
+ req->lh3PageBits = 0; //lhPageBits;
req->noOfAttributes = tabPtr.p->noOfAttributes;
- req->noOfNullAttributes = tabPtr.p->noOfNullAttr;
+ req->noOfNullAttributes = tabPtr.p->noOfNullBits;
req->noOfPagesToPreAllocate = 0;
req->schemaVersion = tabPtr.p->tableVersion;
Uint32 keyLen = tabPtr.p->tupKeyLength;
- req->keyLength = keyLen > 8 ? 0 : keyLen; // Put this into ACC instead
+ req->keyLength = keyLen; // wl-2066 no more "long keys"
req->nextLCP = lcpNo;
req->noOfKeyAttr = tabPtr.p->noOfPrimkey;
@@ -4178,7 +4196,7 @@ Dbdict::sendLQHADDATTRREQ(Signal* signal,
LqhAddAttrReq::Entry& entry = req->attributes[i];
entry.attrId = attrPtr.p->attributeId;
entry.attrDescriptor = attrPtr.p->attributeDescriptor;
- entry.extTypeInfo = attrPtr.p->extType;
+ entry.extTypeInfo = 0;
// charset number passed to TUP, TUX in upper half
entry.extTypeInfo |= (attrPtr.p->extPrecision & ~0xFFFF);
if (tabPtr.p->isIndex()) {
@@ -4320,7 +4338,29 @@ Dbdict::execTAB_COMMITCONF(Signal* signal){
signal->theData[3] = reference();
signal->theData[4] = (Uint32)tabPtr.p->tableType;
signal->theData[5] = createTabPtr.p->key;
- sendSignal(DBTC_REF, GSN_TC_SCHVERREQ, signal, 6, JBB);
+ signal->theData[6] = (Uint32)tabPtr.p->noOfPrimkey;
+
+ Uint32 buf[2 * MAX_ATTRIBUTES_IN_INDEX];
+ Uint32 sz = 0;
+ Uint32 tAttr = tabPtr.p->firstAttribute;
+ while (tAttr != RNIL) {
+ jam();
+ AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr);
+ if (aRec->tupleKey) {
+ buf[sz++] = aRec->attributeDescriptor;
+ buf[sz++] = (aRec->extPrecision >> 16); // charset number
+ }
+ tAttr = aRec->nextAttrInTable;
+ }
+ ndbrequire((int)sz == 2 * tabPtr.p->noOfPrimkey);
+
+ LinearSectionPtr lsPtr[3];
+ lsPtr[0].p = buf;
+ lsPtr[0].sz = sz;
+ // note: ACC does not reply
+ if (tabPtr.p->isTable() || tabPtr.p->isHashIndex())
+ sendSignal(DBACC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1);
+ sendSignal(DBTC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1);
return;
}
@@ -4679,7 +4719,6 @@ void Dbdict::handleTabInfoInit(SimpleProperties::Reader & it,
tablePtr.p->minLoadFactor = tableDesc.MinLoadFactor;
tablePtr.p->maxLoadFactor = tableDesc.MaxLoadFactor;
tablePtr.p->fragmentType = (DictTabInfo::FragmentType)tableDesc.FragmentType;
- tablePtr.p->fragmentKeyType = (DictTabInfo::FragmentKeyType)tableDesc.FragmentKeyType;
tablePtr.p->tableType = (DictTabInfo::TableType)tableDesc.TableType;
tablePtr.p->kValue = tableDesc.TableKValue;
tablePtr.p->fragmentCount = tableDesc.FragmentCount;
@@ -4728,6 +4767,7 @@ void Dbdict::handleTabInfo(SimpleProperties::Reader & it,
Uint32 keyLength = 0;
Uint32 attrCount = tablePtr.p->noOfAttributes;
Uint32 nullCount = 0;
+ Uint32 nullBits = 0;
Uint32 noOfCharsets = 0;
Uint16 charsets[128];
Uint32 recordLength = 0;
@@ -4780,19 +4820,24 @@ void Dbdict::handleTabInfo(SimpleProperties::Reader & it,
attrPtr.p->attributeId = attrDesc.AttributeId;
attrPtr.p->tupleKey = (keyCount + 1) * attrDesc.AttributeKeyFlag;
- attrPtr.p->extType = attrDesc.AttributeExtType;
attrPtr.p->extPrecision = attrDesc.AttributeExtPrecision;
attrPtr.p->extScale = attrDesc.AttributeExtScale;
attrPtr.p->extLength = attrDesc.AttributeExtLength;
// charset in upper half of precision
unsigned csNumber = (attrPtr.p->extPrecision >> 16);
if (csNumber != 0) {
+ /*
+ * A new charset is first accessed here on this node.
+ * TODO use separate thread (e.g. via NDBFS) if need to load from file
+ */
CHARSET_INFO* cs = get_charset(csNumber, MYF(0));
if (cs == NULL) {
parseP->errorCode = CreateTableRef::InvalidCharset;
parseP->errorLine = __LINE__;
return;
}
+ // XXX should be done somewhere in mysql
+ all_charsets[cs->number] = cs;
unsigned i = 0;
while (i < noOfCharsets) {
if (charsets[i] == csNumber)
@@ -4810,9 +4855,7 @@ void Dbdict::handleTabInfo(SimpleProperties::Reader & it,
}
}
- /**
- * Ignore incoming old-style type and recompute it.
- */
+ // compute attribute size and array size
bool translateOk = attrDesc.translateExtType();
tabRequire(translateOk, CreateTableRef::Inconsistency);
@@ -4825,15 +4868,12 @@ void Dbdict::handleTabInfo(SimpleProperties::Reader & it,
}
Uint32 desc = 0;
- AttributeDescriptor::setType(desc, attrDesc.AttributeType);
+ AttributeDescriptor::setType(desc, attrDesc.AttributeExtType);
AttributeDescriptor::setSize(desc, attrDesc.AttributeSize);
AttributeDescriptor::setArray(desc, attrDesc.AttributeArraySize);
AttributeDescriptor::setNullable(desc, attrDesc.AttributeNullableFlag);
- AttributeDescriptor::setDGroup(desc, attrDesc.AttributeDGroup);
AttributeDescriptor::setDKey(desc, attrDesc.AttributeDKey);
AttributeDescriptor::setPrimaryKey(desc, attrDesc.AttributeKeyFlag);
-
- AttributeDescriptor::setStoredInTup(desc, attrDesc.AttributeStoredInd);
attrPtr.p->attributeDescriptor = desc;
attrPtr.p->autoIncrement = attrDesc.AttributeAutoIncrement;
strcpy(attrPtr.p->defaultValue, attrDesc.AttributeDefaultValue);
@@ -4845,7 +4885,25 @@ void Dbdict::handleTabInfo(SimpleProperties::Reader & it,
nullCount += attrDesc.AttributeNullableFlag;
const Uint32 aSz = (1 << attrDesc.AttributeSize);
- const Uint32 sz = ((aSz * attrDesc.AttributeArraySize) + 31) >> 5;
+ Uint32 sz;
+ if(aSz != 1)
+ {
+ sz = ((aSz * attrDesc.AttributeArraySize) + 31) >> 5;
+ }
+ else
+ {
+ sz = 0;
+ nullBits += attrDesc.AttributeArraySize;
+ }
+
+ if(attrDesc.AttributeArraySize == 0)
+ {
+ parseP->errorCode = CreateTableRef::InvalidArraySize;
+ parseP->status = status;
+ parseP->errorKey = it.getKey();
+ parseP->errorLine = __LINE__;
+ return;
+ }
recordLength += sz;
if(attrDesc.AttributeKeyFlag){
@@ -4874,6 +4932,7 @@ void Dbdict::handleTabInfo(SimpleProperties::Reader & it,
tablePtr.p->noOfNullAttr = nullCount;
tablePtr.p->noOfCharsets = noOfCharsets;
tablePtr.p->tupKeyLength = keyLength;
+ tablePtr.p->noOfNullBits = nullCount + nullBits;
tabRequire(recordLength<= MAX_TUPLE_SIZE_IN_WORDS,
CreateTableRef::RecordTooBig);
@@ -5666,7 +5725,10 @@ void Dbdict::sendGET_TABLEID_REF(Signal* signal,
void Dbdict::execGET_TABINFOREQ(Signal* signal)
{
jamEntry();
- if(!assembleFragments(signal)) { return; }
+ if(!assembleFragments(signal))
+ {
+ return;
+ }
GetTabInfoReq * const req = (GetTabInfoReq *)&signal->theData[0];
@@ -6252,6 +6314,7 @@ Dbdict::createIndex_slavePrepare(Signal* signal, OpCreateIndexPtr opPtr)
void
Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr)
{
+ Uint32 attrid_map[MAX_ATTRIBUTES_IN_INDEX];
Uint32 k;
jam();
const CreateIndxReq* const req = &opPtr.p->m_request;
@@ -6320,39 +6383,49 @@ Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr)
// tree node size in words (make configurable later)
indexPtr.p->tupKeyLength = MAX_TTREE_NODE_SIZE;
}
- // hash index attributes must currently be in table order
- Uint32 prevAttrId = RNIL;
+
+ AttributeMask mask;
+ mask.clear();
for (k = 0; k < opPtr.p->m_attrList.sz; k++) {
jam();
- bool found = false;
- for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) {
- AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr);
- tAttr = aRec->nextAttrInTable;
- if (aRec->attributeId != opPtr.p->m_attrList.id[k])
+ unsigned current_id= opPtr.p->m_attrList.id[k];
+ AttributeRecord* aRec= NULL;
+ Uint32 tAttr= tablePtr.p->firstAttribute;
+ for (; tAttr != RNIL; tAttr= aRec->nextAttrInTable)
+ {
+ aRec = c_attributeRecordPool.getPtr(tAttr);
+ if (aRec->attributeId != current_id)
continue;
jam();
- found = true;
- const Uint32 a = aRec->attributeDescriptor;
- if (indexPtr.p->isHashIndex()) {
- const Uint32 s1 = AttributeDescriptor::getSize(a);
- const Uint32 s2 = AttributeDescriptor::getArraySize(a);
- indexPtr.p->tupKeyLength += ((1 << s1) * s2 + 31) >> 5;
- }
+ break;
}
- if (! found) {
+ if (tAttr == RNIL) {
jam();
opPtr.p->m_errorCode = CreateIndxRef::BadRequestType;
opPtr.p->m_errorLine = __LINE__;
return;
}
- if (indexPtr.p->isHashIndex() &&
- k > 0 && prevAttrId >= opPtr.p->m_attrList.id[k]) {
+ if (mask.get(current_id))
+ {
jam();
- opPtr.p->m_errorCode = CreateIndxRef::InvalidAttributeOrder;
+ opPtr.p->m_errorCode = CreateIndxRef::DuplicateAttributes;
opPtr.p->m_errorLine = __LINE__;
return;
}
- prevAttrId = opPtr.p->m_attrList.id[k];
+ mask.set(current_id);
+
+ const Uint32 a = aRec->attributeDescriptor;
+ unsigned kk= k;
+ if (indexPtr.p->isHashIndex()) {
+ const Uint32 s1 = AttributeDescriptor::getSize(a);
+ const Uint32 s2 = AttributeDescriptor::getArraySize(a);
+ indexPtr.p->tupKeyLength += ((1 << s1) * s2 + 31) >> 5;
+ // reorder the attributes according to the tableid order
+ // for unque indexes
+ for (; kk > 0 && current_id < attrid_map[kk-1]>>16; kk--)
+ attrid_map[kk]= attrid_map[kk-1];
+ }
+ attrid_map[kk]= k | (current_id << 16);
}
indexPtr.p->noOfPrimkey = indexPtr.p->noOfAttributes;
// plus concatenated primary table key attribute
@@ -6373,15 +6446,21 @@ Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr)
AttributeRecordPtr aRecPtr;
c_attributeRecordPool.getPtr(aRecPtr, tablePtr.p->firstAttribute);
for (k = 0; k < opPtr.p->m_attrList.sz; k++) {
+ // insert the attributes in the order decided above in attrid_map
+ // k is new order, current_id is in previous order
+ // ToDo: make sure "current_id" is stored with the table and
+ // passed up to NdbDictionary
+ unsigned current_id= opPtr.p->m_attrList.id[attrid_map[k] & 0xffff];
jam();
for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) {
AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr);
tAttr = aRec->nextAttrInTable;
- if (aRec->attributeId != opPtr.p->m_attrList.id[k])
+ if (aRec->attributeId != current_id)
continue;
jam();
const Uint32 a = aRec->attributeDescriptor;
bool isNullable = AttributeDescriptor::getNullable(a);
+ Uint32 attrType = AttributeDescriptor::getType(a);
w.add(DictTabInfo::AttributeName, aRec->attributeName);
w.add(DictTabInfo::AttributeId, k);
if (indexPtr.p->isHashIndex()) {
@@ -6392,9 +6471,7 @@ Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr)
w.add(DictTabInfo::AttributeKeyFlag, (Uint32)false);
w.add(DictTabInfo::AttributeNullableFlag, (Uint32)isNullable);
}
- w.add(DictTabInfo::AttributeStoredInd, (Uint32)DictTabInfo::Stored);
- // ext type overrides
- w.add(DictTabInfo::AttributeExtType, aRec->extType);
+ w.add(DictTabInfo::AttributeExtType, attrType);
w.add(DictTabInfo::AttributeExtPrecision, aRec->extPrecision);
w.add(DictTabInfo::AttributeExtScale, aRec->extScale);
w.add(DictTabInfo::AttributeExtLength, aRec->extLength);
@@ -6407,9 +6484,7 @@ Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr)
w.add(DictTabInfo::AttributeName, "NDB$PK");
w.add(DictTabInfo::AttributeId, opPtr.p->m_attrList.sz);
w.add(DictTabInfo::AttributeKeyFlag, (Uint32)false);
- w.add(DictTabInfo::AttributeStoredInd, (Uint32)DictTabInfo::Stored);
w.add(DictTabInfo::AttributeNullableFlag, (Uint32)false);
- // ext type overrides
w.add(DictTabInfo::AttributeExtType, (Uint32)DictTabInfo::ExtUnsigned);
w.add(DictTabInfo::AttributeExtLength, tablePtr.p->tupKeyLength);
w.add(DictTabInfo::AttributeEnd, (Uint32)true);
@@ -6420,9 +6495,7 @@ Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr)
w.add(DictTabInfo::AttributeName, "NDB$TNODE");
w.add(DictTabInfo::AttributeId, opPtr.p->m_attrList.sz);
w.add(DictTabInfo::AttributeKeyFlag, (Uint32)true);
- w.add(DictTabInfo::AttributeStoredInd, (Uint32)DictTabInfo::Stored);
w.add(DictTabInfo::AttributeNullableFlag, (Uint32)false);
- // ext type overrides
w.add(DictTabInfo::AttributeExtType, (Uint32)DictTabInfo::ExtUnsigned);
w.add(DictTabInfo::AttributeExtLength, indexPtr.p->tupKeyLength);
w.add(DictTabInfo::AttributeEnd, (Uint32)true);
@@ -7831,7 +7904,7 @@ void Dbdict::createEventUTIL_EXECUTE(Signal *signal,
break;
case ZALREADYEXIST:
jam();
- evntRecPtr.p->m_errorCode = CreateEvntRef::EventExists;
+ evntRecPtr.p->m_errorCode = CreateEvntRef::EventNameExists;
break;
default:
jam();
diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
index 5fc4742e829..73fbdcc8e16 100644
--- a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
+++ b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
@@ -213,7 +213,9 @@ public:
IL_CREATED_TC = 1 << 0 // created in TC
};
Uint32 indexLocal;
-
+
+ Uint32 noOfNullBits;
+
inline bool equal(TableRecord & rec) const {
return strcmp(tableName, rec.tableName) == 0;
}
@@ -1580,7 +1582,8 @@ private:
bool getNewAttributeRecord(TableRecordPtr tablePtr,
AttributeRecordPtr & attrPtr);
void packTableIntoPages(Signal* signal, Uint32 tableId, Uint32 pageId);
- void packTableIntoPagesImpl(SimpleProperties::Writer &, TableRecordPtr);
+ void packTableIntoPagesImpl(SimpleProperties::Writer &, TableRecordPtr,
+ Signal* signal= 0);
void sendGET_TABINFOREQ(Signal* signal,
Uint32 tableId);
diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
index efd1740651c..b2ed7acd347 100644
--- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
+++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
@@ -247,7 +247,7 @@ void Dbdih::sendSTART_RECREQ(Signal* signal, Uint32 nodeId)
req->newestGci = SYSFILE->newestRestorableGCI;
sendSignal(ref, GSN_START_RECREQ, signal, StartRecReq::SignalLength, JBB);
- signal->theData[0] = EventReport::StartREDOLog;
+ signal->theData[0] = NDB_LE_StartREDOLog;
signal->theData[1] = nodeId;
signal->theData[2] = SYSFILE->keepGCI;
signal->theData[3] = SYSFILE->lastCompletedGCI[nodeId];
@@ -1795,7 +1795,7 @@ void Dbdih::nodeDictStartConfLab(Signal* signal)
/*-----------------------------------------------------------------*/
// Report that node restart has completed copy of dictionary.
/*-----------------------------------------------------------------*/
- signal->theData[0] = EventReport::NR_CopyDict;
+ signal->theData[0] = NDB_LE_NR_CopyDict;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 1, JBB);
}//Dbdih::nodeDictStartConfLab()
@@ -1816,7 +1816,7 @@ void Dbdih::gcpBlockedLab(Signal* signal)
/*-----------------------------------------------------------------*/
// Report that node restart has completed copy of distribution info.
/*-----------------------------------------------------------------*/
- signal->theData[0] = EventReport::NR_CopyDistr;
+ signal->theData[0] = NDB_LE_NR_CopyDistr;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 1, JBB);
/**
@@ -1971,7 +1971,7 @@ void Dbdih::execSTART_COPYREQ(Signal* signal)
/*-------------------------------------------------------------------------*/
// REPORT Copy process of node restart is now about to start up.
/*-------------------------------------------------------------------------*/
- signal->theData[0] = EventReport::NR_CopyFragsStarted;
+ signal->theData[0] = NDB_LE_NR_CopyFragsStarted;
signal->theData[1] = startNodeId;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -2936,7 +2936,7 @@ void Dbdih::execCREATE_FRAGCONF(Signal* signal)
/* --------------------------------------------------------------------- */
// REPORT that copy of fragment has been completed.
/* --------------------------------------------------------------------- */
- signal->theData[0] = EventReport::NR_CopyFragDone;
+ signal->theData[0] = NDB_LE_NR_CopyFragDone;
signal->theData[1] = takeOverPtr.p->toStartingNode;
signal->theData[2] = tabPtr.i;
signal->theData[3] = takeOverPtr.p->toCurrentFragid;
@@ -3174,7 +3174,7 @@ Dbdih::switchPrimaryMutex_locked(Signal* signal, Uint32 toPtrI, Uint32 retVal){
void Dbdih::toCopyCompletedLab(Signal * signal, TakeOverRecordPtr takeOverPtr)
{
- signal->theData[0] = EventReport::NR_CopyFragsCompleted;
+ signal->theData[0] = NDB_LE_NR_CopyFragsCompleted;
signal->theData[1] = takeOverPtr.p->toStartingNode;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -4459,7 +4459,7 @@ void Dbdih::startGcpMasterTakeOver(Signal* signal, Uint32 oldMasterId){
sendLoopMacro(MASTER_GCPREQ, sendMASTER_GCPREQ);
cgcpMasterTakeOverState = GMTOS_INITIAL;
- signal->theData[0] = EventReport::GCP_TakeoverStarted;
+ signal->theData[0] = NDB_LE_GCP_TakeoverStarted;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 1, JBB);
setLocalNodefailHandling(signal, oldMasterId, NF_GCP_TAKE_OVER);
@@ -4968,7 +4968,7 @@ void Dbdih::MASTER_GCPhandling(Signal* signal, Uint32 failedNodeId)
break;
}//switch
- signal->theData[0] = EventReport::GCP_TakeoverCompleted;
+ signal->theData[0] = NDB_LE_GCP_TakeoverCompleted;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 1, JBB);
/*--------------------------------------------------*/
@@ -5400,7 +5400,7 @@ Dbdih::checkEmptyLcpComplete(Signal *signal){
if(isMaster()){
jam();
- signal->theData[0] = EventReport::LCP_TakeoverStarted;
+ signal->theData[0] = NDB_LE_LCP_TakeoverStarted;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 1, JBB);
signal->theData[0] = 7012;
@@ -5872,7 +5872,7 @@ void Dbdih::MASTER_LCPhandling(Signal* signal, Uint32 failedNodeId)
ndbrequire(false);
break;
}//switch
- signal->theData[0] = EventReport::LCP_TakeoverCompleted;
+ signal->theData[0] = NDB_LE_LCP_TakeoverCompleted;
signal->theData[1] = c_lcpMasterTakeOverState.state;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -5907,7 +5907,7 @@ void Dbdih::execNF_COMPLETEREP(Signal* signal)
/* -------------------------------------------------------------------- */
// Report the event that DBTC completed node failure handling.
/* -------------------------------------------------------------------- */
- signal->theData[0] = EventReport::NodeFailCompleted;
+ signal->theData[0] = NDB_LE_NodeFailCompleted;
signal->theData[1] = DBTC;
signal->theData[2] = failedNodePtr.i;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
@@ -5920,7 +5920,7 @@ void Dbdih::execNF_COMPLETEREP(Signal* signal)
/* --------------------------------------------------------------------- */
// Report the event that DBDICT completed node failure handling.
/* --------------------------------------------------------------------- */
- signal->theData[0] = EventReport::NodeFailCompleted;
+ signal->theData[0] = NDB_LE_NodeFailCompleted;
signal->theData[1] = DBDICT;
signal->theData[2] = failedNodePtr.i;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
@@ -5933,7 +5933,7 @@ void Dbdih::execNF_COMPLETEREP(Signal* signal)
/* --------------------------------------------------------------------- */
// Report the event that DBDIH completed node failure handling.
/* --------------------------------------------------------------------- */
- signal->theData[0] = EventReport::NodeFailCompleted;
+ signal->theData[0] = NDB_LE_NodeFailCompleted;
signal->theData[1] = DBDIH;
signal->theData[2] = failedNodePtr.i;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
@@ -5946,7 +5946,7 @@ void Dbdih::execNF_COMPLETEREP(Signal* signal)
/* --------------------------------------------------------------------- */
// Report the event that DBDIH completed node failure handling.
/* --------------------------------------------------------------------- */
- signal->theData[0] = EventReport::NodeFailCompleted;
+ signal->theData[0] = NDB_LE_NodeFailCompleted;
signal->theData[1] = DBLQH;
signal->theData[2] = failedNodePtr.i;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
@@ -5981,7 +5981,7 @@ void Dbdih::execNF_COMPLETEREP(Signal* signal)
/* -------------------------------------------------------------------- */
// Report the event that nodeId has completed node failure handling.
/* -------------------------------------------------------------------- */
- signal->theData[0] = EventReport::NodeFailCompleted;
+ signal->theData[0] = NDB_LE_NodeFailCompleted;
signal->theData[1] = 0;
signal->theData[2] = failedNodePtr.i;
signal->theData[3] = nodeId;
@@ -6054,7 +6054,7 @@ void Dbdih::nodeFailCompletedCheckLab(Signal* signal,
/* ---------------------------------------------------------------------- */
// Report the event that all nodes completed node failure handling.
/* ---------------------------------------------------------------------- */
- signal->theData[0] = EventReport::NodeFailCompleted;
+ signal->theData[0] = NDB_LE_NodeFailCompleted;
signal->theData[1] = 0;
signal->theData[2] = failedNodePtr.i;
signal->theData[3] = 0;
@@ -6209,9 +6209,12 @@ void Dbdih::execCREATE_FRAGMENTATION_REQ(Signal * signal){
if (primaryTableId == RNIL) {
if(fragmentNode == 0){
jam();
- // needs to be fixed for single fragment tables
- NGPtr.i = 0; //c_nextNodeGroup;
- c_nextNodeGroup = (NGPtr.i + 1 == cnoOfNodeGroups ? 0 : NGPtr.i + 1);
+ NGPtr.i = 0;
+ if(noOfFragments < csystemnodes)
+ {
+ NGPtr.i = c_nextNodeGroup;
+ c_nextNodeGroup = (NGPtr.i + 1 == cnoOfNodeGroups ? 0 : NGPtr.i + 1);
+ }
} else if(! (fragmentNode < MAX_NDB_NODES)) {
jam();
err = CreateFragmentationRef::InvalidNodeId;
@@ -6264,33 +6267,28 @@ void Dbdih::execCREATE_FRAGMENTATION_REQ(Signal * signal){
}
}
- //@todo use section writer
Uint32 count = 2;
- Uint32 fragments[2 + 8*MAX_REPLICAS*MAX_NDB_NODES];
- Uint32 next_replica_node[MAX_NDB_NODES];
- memset(next_replica_node,0,sizeof(next_replica_node));
+ Uint16 *fragments = (Uint16*)(signal->theData+25);
if (primaryTableId == RNIL) {
jam();
+ Uint8 next_replica_node[MAX_NDB_NODES];
+ memset(next_replica_node,0,sizeof(next_replica_node));
for(Uint32 fragNo = 0; fragNo<noOfFragments; fragNo++){
jam();
ptrCheckGuard(NGPtr, MAX_NDB_NODES, nodeGroupRecord);
-
- Uint32 ind = next_replica_node[NGPtr.i];
const Uint32 max = NGPtr.p->nodeCount;
-
- //-------------------------------------------------------------------
- // We make an extra step to ensure that the primary replicas are
- // spread among the nodes.
- //-------------------------------------------------------------------
- next_replica_node[NGPtr.i] = (ind + 1 >= max ? 0 : ind + 1);
-
- for(Uint32 replicaNo = 0; replicaNo<noOfReplicas; replicaNo++){
+
+ Uint32 tmp= next_replica_node[NGPtr.i];
+ for(Uint32 replicaNo = 0; replicaNo<noOfReplicas; replicaNo++)
+ {
jam();
- const Uint32 nodeId = NGPtr.p->nodesInGroup[ind++];
+ const Uint32 nodeId = NGPtr.p->nodesInGroup[tmp++];
fragments[count++] = nodeId;
- ind = (ind == max ? 0 : ind);
+ tmp = (tmp >= max ? 0 : tmp);
}
-
+ tmp++;
+ next_replica_node[NGPtr.i]= (tmp >= max ? 0 : tmp);
+
/**
* Next node group for next fragment
*/
@@ -6339,26 +6337,42 @@ void Dbdih::execCREATE_FRAGMENTATION_REQ(Signal * signal){
fragments[0] = noOfReplicas;
fragments[1] = noOfFragments;
- LinearSectionPtr ptr[3];
- ptr[0].p = &fragments[0];
- ptr[0].sz = count;
- sendSignal(senderRef,
- GSN_CREATE_FRAGMENTATION_CONF,
- signal,
- CreateFragmentationConf::SignalLength,
- JBB,
- ptr,
- 1);
+ if(senderRef != 0)
+ {
+ LinearSectionPtr ptr[3];
+ ptr[0].p = (Uint32*)&fragments[0];
+ ptr[0].sz = (count + 1) / 2;
+ sendSignal(senderRef,
+ GSN_CREATE_FRAGMENTATION_CONF,
+ signal,
+ CreateFragmentationConf::SignalLength,
+ JBB,
+ ptr,
+ 1);
+ }
+ else
+ {
+ // Execute direct
+ signal->theData[0] = 0;
+ }
return;
} while(false);
-
- CreateFragmentationRef * const ref =
- (CreateFragmentationRef*)signal->getDataPtrSend();
- ref->senderRef = reference();
- ref->senderData = senderData;
- ref->errorCode = err;
- sendSignal(senderRef, GSN_CREATE_FRAGMENTATION_REF, signal,
- CreateFragmentationRef::SignalLength, JBB);
+
+ if(senderRef != 0)
+ {
+ CreateFragmentationRef * const ref =
+ (CreateFragmentationRef*)signal->getDataPtrSend();
+ ref->senderRef = reference();
+ ref->senderData = senderData;
+ ref->errorCode = err;
+ sendSignal(senderRef, GSN_CREATE_FRAGMENTATION_REF, signal,
+ CreateFragmentationRef::SignalLength, JBB);
+ }
+ else
+ {
+ // Execute direct
+ signal->theData[0] = err;
+ }
}
void Dbdih::execDIADDTABREQ(Signal* signal)
@@ -6426,12 +6440,15 @@ void Dbdih::execDIADDTABREQ(Signal* signal)
tabPtr.p->method = TabRecord::HASH;
tabPtr.p->kvalue = req->kValue;
- Uint32 fragments[2 + 8*MAX_REPLICAS*MAX_NDB_NODES];
+ union {
+ Uint16 fragments[2 + MAX_FRAG_PER_NODE*MAX_REPLICAS*MAX_NDB_NODES];
+ Uint32 align;
+ };
SegmentedSectionPtr fragDataPtr;
signal->getSection(fragDataPtr, DiAddTabReq::FRAGMENTATION);
- copy(fragments, fragDataPtr);
+ copy((Uint32*)fragments, fragDataPtr);
releaseSections(signal);
-
+
const Uint32 noReplicas = fragments[0];
const Uint32 noFragments = fragments[1];
@@ -6859,8 +6876,7 @@ void Dbdih::execDIGETNODESREQ(Signal* signal)
TabRecord* regTabDesc = tabRecord;
jamEntry();
ptrCheckGuard(tabPtr, ttabFileSize, regTabDesc);
- hashValue = hashValue >> tabPtr.p->kvalue;
- Uint32 fragId = tabPtr.p->mask & hashValue;
+ Uint32 fragId = hashValue & tabPtr.p->mask;
ndbrequire(tabPtr.p->tabStatus == TabRecord::TS_ACTIVE);
if (fragId < tabPtr.p->hashpointer) {
jam();
@@ -7221,7 +7237,7 @@ void Dbdih::startGcpLab(Signal* signal, Uint32 aWaitTime)
/***************************************************************************/
// Report the event that a global checkpoint has started.
/***************************************************************************/
- signal->theData[0] = EventReport::GlobalCheckpointStarted; //Event type
+ signal->theData[0] = NDB_LE_GlobalCheckpointStarted; //Event type
signal->theData[1] = cnewgcp;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -7466,6 +7482,22 @@ void Dbdih::execDIHNDBTAMPER(Signal* signal)
#ifdef ERROR_INSERT
case 5:
jam();
+ if(tuserpointer == 0)
+ {
+ jam();
+ signal->theData[0] = 0;
+ sendSignal(QMGR_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ sendSignal(NDBCNTR_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ sendSignal(NDBFS_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ sendSignal(DBACC_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ sendSignal(DBTUP_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ sendSignal(DBLQH_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ sendSignal(DBDICT_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ sendSignal(DBDIH_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ sendSignal(DBTC_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ sendSignal(CMVMI_REF, GSN_NDB_TAMPER, signal, 1, JBB);
+ return;
+ }
/*----------------------------------------------------------------------*/
// Insert errors.
/*----------------------------------------------------------------------*/
@@ -7684,7 +7716,7 @@ void Dbdih::execCOPY_GCICONF(Signal* signal)
// Report the event that a global checkpoint has completed.
/************************************************************************/
signal->setTrace(0);
- signal->theData[0] = EventReport::GlobalCheckpointCompleted; //Event type
+ signal->theData[0] = NDB_LE_GlobalCheckpointCompleted; //Event type
signal->theData[1] = coldgcp;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -9187,7 +9219,7 @@ void Dbdih::execTCGETOPSIZECONF(Signal* signal)
ndbrequire(((int)c_lcpState.oldestRestorableGci) > 0);
if (ERROR_INSERTED(7011)) {
- signal->theData[0] = EventReport::LCPStoppedInCalcKeepGci;
+ signal->theData[0] = NDB_LE_LCPStoppedInCalcKeepGci;
signal->theData[1] = 0;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
return;
@@ -9273,7 +9305,7 @@ void Dbdih::storeNewLcpIdLab(Signal* signal)
/***************************************************************************/
// Report the event that a local checkpoint has started.
/***************************************************************************/
- signal->theData[0] = EventReport::LocalCheckpointStarted; //Event type
+ signal->theData[0] = NDB_LE_LocalCheckpointStarted; //Event type
signal->theData[1] = SYSFILE->latestLCP_ID + 1;
signal->theData[2] = c_lcpState.keepGci;
signal->theData[3] = c_lcpState.oldestRestorableGci;
@@ -9650,7 +9682,7 @@ void Dbdih::execLCP_FRAG_REP(Signal* signal)
/* --------------------------------------------------------------------- */
// REPORT that local checkpoint have completed this fragment.
/* --------------------------------------------------------------------- */
- signal->theData[0] = EventReport::LCPFragmentCompleted;
+ signal->theData[0] = NDB_LE_LCPFragmentCompleted;
signal->theData[1] = nodeId;
signal->theData[2] = tableId;
signal->theData[3] = fragId;
@@ -10099,7 +10131,7 @@ void Dbdih::allNodesLcpCompletedLab(Signal* signal)
/***************************************************************************/
// Report the event that a local checkpoint has completed.
/***************************************************************************/
- signal->theData[0] = EventReport::LocalCheckpointCompleted; //Event type
+ signal->theData[0] = NDB_LE_LocalCheckpointCompleted; //Event type
signal->theData[1] = SYSFILE->latestLCP_ID;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -11427,7 +11459,6 @@ void Dbdih::makeNodeGroups(Uint32 nodeArray[])
NodeRecordPtr mngNodeptr;
Uint32 tmngNode;
Uint32 tmngNodeGroup;
- Uint32 tmngReplica;
Uint32 tmngLimit;
Uint32 i;
@@ -11436,7 +11467,6 @@ void Dbdih::makeNodeGroups(Uint32 nodeArray[])
* TO NODE GROUP ZNIL
*-----------------------------------------------------------------------*/
tmngNodeGroup = 0;
- tmngReplica = 0;
tmngLimit = csystemnodes - cnoHotSpare;
ndbrequire(tmngLimit < MAX_NDB_NODES);
for (i = 0; i < tmngLimit; i++) {
@@ -11448,13 +11478,11 @@ void Dbdih::makeNodeGroups(Uint32 nodeArray[])
mngNodeptr.p->nodeGroup = tmngNodeGroup;
NGPtr.i = tmngNodeGroup;
ptrCheckGuard(NGPtr, MAX_NDB_NODES, nodeGroupRecord);
- arrGuard(tmngReplica, MAX_REPLICAS);
- NGPtr.p->nodesInGroup[tmngReplica] = mngNodeptr.i;
- tmngReplica++;
- if (tmngReplica == cnoReplicas) {
+ arrGuard(NGPtr.p->nodeCount, MAX_REPLICAS);
+ NGPtr.p->nodesInGroup[NGPtr.p->nodeCount++] = mngNodeptr.i;
+ if (NGPtr.p->nodeCount == cnoReplicas) {
jam();
tmngNodeGroup++;
- tmngReplica = 0;
}//if
}//for
cnoOfNodeGroups = tmngNodeGroup;
diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
index 19e055a3011..f5d2dbc0a6c 100644
--- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
+++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
@@ -29,6 +29,9 @@
#include <signaldata/LqhTransConf.hpp>
#include <signaldata/LqhFrag.hpp>
+// primary key is stored in TUP
+#include <../dbtup/Dbtup.hpp>
+
#ifdef DBLQH_C
// Constants
/* ------------------------------------------------------------------------- */
@@ -500,9 +503,7 @@ public:
WAIT_DELETE_STORED_PROC_ID_COPY = 6,
WAIT_ACC_COPY = 7,
WAIT_ACC_SCAN = 8,
- WAIT_SCAN_KEYINFO = 9,
WAIT_SCAN_NEXTREQ = 10,
- WAIT_COPY_KEYINFO = 11,
WAIT_CLOSE_SCAN = 12,
WAIT_CLOSE_COPY = 13,
WAIT_RELEASE_LOCK = 14,
@@ -571,6 +572,7 @@ public:
Uint8 scanLockMode;
Uint8 readCommitted;
Uint8 rangeScan;
+ Uint8 descending;
Uint8 scanTcWaiting;
Uint8 scanKeyinfoFlag;
Uint8 m_last_row;
@@ -867,10 +869,6 @@ public:
*/
Uint8 fragDistributionKey;
/**
- * Used to calculate which local fragment to use.
- */
- Uint8 hashCheckBit;
- /**
* The identity of the next local checkpoint this fragment
* should perform.
*/
@@ -2010,8 +2008,10 @@ public:
BlockReference tcTuxBlockref;
BlockReference tcTupBlockref;
Uint32 commitAckMarker;
- UintR noFiredTriggers;
-
+ union {
+ Uint32 m_scan_curr_range_no;
+ UintR noFiredTriggers;
+ };
Uint16 errorCode;
Uint16 logStartPageIndex;
Uint16 logStartPageNo;
@@ -2033,6 +2033,7 @@ public:
Uint8 opExec;
Uint8 operation;
Uint8 reclenAiLqhkey;
+ Uint8 m_offset_current_keybuf;
Uint8 replicaType;
Uint8 simpleRead;
Uint8 seqNoReplica;
@@ -2136,8 +2137,6 @@ private:
void execACC_SCANREF(Signal* signal);
void execNEXT_SCANCONF(Signal* signal);
void execNEXT_SCANREF(Signal* signal);
- void execACC_SCAN_INFO(Signal* signal);
- void execACC_SCAN_INFO24(Signal* signal);
void execACC_TO_REF(Signal* signal);
void execSTORED_PROCCONF(Signal* signal);
void execSTORED_PROCREF(Signal* signal);
@@ -2258,7 +2257,7 @@ private:
void finishScanrec(Signal* signal);
void releaseScanrec(Signal* signal);
void seizeScanrec(Signal* signal);
- void sendKeyinfo20(Signal* signal, ScanRecord *, TcConnectionrec *);
+ Uint32 sendKeyinfo20(Signal* signal, ScanRecord *, TcConnectionrec *);
void sendScanFragConf(Signal* signal, Uint32 scanCompleted);
void initCopyrec(Signal* signal);
void initCopyTc(Signal* signal);
@@ -2387,6 +2386,8 @@ private:
void seizeAttrinbuf(Signal* signal);
Uint32 seize_attrinbuf();
Uint32 release_attrinbuf(Uint32);
+ Uint32 copy_bounds(Uint32 * dst, TcConnectionrec*);
+
void seizeFragmentrec(Signal* signal);
void seizePageRef(Signal* signal);
void seizeTcrec();
@@ -2433,7 +2434,6 @@ private:
void localCommitLab(Signal* signal);
void abortErrorLab(Signal* signal);
void continueAfterReceivingAllAiLab(Signal* signal);
- void sendScanFragRefLateLab(Signal* signal);
void abortStateHandlerLab(Signal* signal);
void writeAttrinfoLab(Signal* signal);
void scanAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length);
@@ -2500,7 +2500,7 @@ private:
void nextScanConfScanLab(Signal* signal);
void nextScanConfCopyLab(Signal* signal);
void continueScanNextReqLab(Signal* signal);
- bool keyinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length);
+ void keyinfoLab(const Uint32 * src, const Uint32 * end);
void copySendTupkeyReqLab(Signal* signal);
void storedProcConfScanLab(Signal* signal);
void storedProcConfCopyLab(Signal* signal);
@@ -2556,7 +2556,6 @@ private:
void accScanConfScanLab(Signal* signal);
void accScanConfCopyLab(Signal* signal);
void scanLockReleasedLab(Signal* signal);
- void accScanInfoEnterLab(Signal* signal, Uint32* dataPtr, Uint32 length);
void openSrFourthNextLab(Signal* signal);
void closingInitLab(Signal* signal);
void closeExecSrCompletedLab(Signal* signal);
@@ -2571,6 +2570,8 @@ private:
void initData();
void initRecords();
+ Dbtup* c_tup;
+ Uint32 readPrimaryKeys(ScanRecord*, TcConnectionrec*, Uint32 * dst);
// ----------------------------------------------------------------
// These are variables handling the records. For most records one
// pointer to the array of structs, one pointer-struct, a file size
diff --git a/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp b/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp
index ec29489180c..e39d0ca68a6 100644
--- a/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp
+++ b/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp
@@ -273,8 +273,6 @@ Dblqh::Dblqh(const class Configuration & conf):
addRecSignal(GSN_ACC_SCANREF, &Dblqh::execACC_SCANREF);
addRecSignal(GSN_NEXT_SCANCONF, &Dblqh::execNEXT_SCANCONF);
addRecSignal(GSN_NEXT_SCANREF, &Dblqh::execNEXT_SCANREF);
- addRecSignal(GSN_ACC_SCAN_INFO, &Dblqh::execACC_SCAN_INFO);
- addRecSignal(GSN_ACC_SCAN_INFO24, &Dblqh::execACC_SCAN_INFO24);
addRecSignal(GSN_STORED_PROCCONF, &Dblqh::execSTORED_PROCCONF);
addRecSignal(GSN_STORED_PROCREF, &Dblqh::execSTORED_PROCREF);
addRecSignal(GSN_COPY_FRAGREQ, &Dblqh::execCOPY_FRAGREQ);
diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
index 3967098b8e9..50ee4c4b06e 100644
--- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
+++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
@@ -420,7 +420,7 @@ void Dblqh::execCONTINUEB(Signal* signal)
// Report information about transaction activity once per second.
/* --------------------------------------------------------------------- */
if (signal->theData[1] == 0) {
- signal->theData[0] = EventReport::OperationReportCounters;
+ signal->theData[0] = NDB_LE_OperationReportCounters;
signal->theData[1] = c_Counters.operations;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
}//if
@@ -490,6 +490,8 @@ void Dblqh::execSTTOR(Signal* signal)
jam();
cstartPhase = tstartPhase;
sttorStartphase1Lab(signal);
+ c_tup = (Dbtup*)globalData.getBlock(DBTUP);
+ ndbrequire(c_tup != 0);
return;
break;
default:
@@ -1087,8 +1089,8 @@ void Dblqh::execLQHFRAGREQ(Signal* signal)
if (DictTabInfo::isOrderedIndex(tableType)) {
jam();
// NOTE: next 2 lines stolen from ACC
- addfragptr.p->fragid1 = (0 << tlhstar) | fragId;
- addfragptr.p->fragid2 = (1 << tlhstar) | fragId;
+ addfragptr.p->fragid1 = (fragId << 1) | 0;
+ addfragptr.p->fragid2 = (fragId << 1) | 1;
addfragptr.p->addfragStatus = AddFragRecord::WAIT_TWO_TUP;
sendAddFragReq(signal);
return;
@@ -1108,7 +1110,6 @@ void Dblqh::execACCFRAGCONF(Signal* signal)
Uint32 fragId2 = signal->theData[3];
Uint32 accFragPtr1 = signal->theData[4];
Uint32 accFragPtr2 = signal->theData[5];
- Uint32 hashCheckBit = signal->theData[6];
ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord);
ndbrequire(addfragptr.p->addfragStatus == AddFragRecord::ACC_ADDFRAG);
@@ -1119,7 +1120,6 @@ void Dblqh::execACCFRAGCONF(Signal* signal)
ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord);
fragptr.p->accFragptr[0] = accFragPtr1;
fragptr.p->accFragptr[1] = accFragPtr2;
- fragptr.p->hashCheckBit = hashCheckBit;
addfragptr.p->addfragStatus = AddFragRecord::WAIT_TWO_TUP;
sendAddFragReq(signal);
@@ -1277,7 +1277,7 @@ Dblqh::sendAddFragReq(Signal* signal)
tuxreq->noOfAttr = addfragptr.p->noOfAttr - 1; /* skip NDB$TNODE */
tuxreq->fragId =
addfragptr.p->addfragStatus == AddFragRecord::WAIT_TWO_TUX
- ? addfragptr.p->fragid1 : addfragptr.p->fragid2;
+ ? addfragptr.p->fragid1: addfragptr.p->fragid2;
tuxreq->fragOff = addfragptr.p->lh3DistrBits;
tuxreq->tableType = addfragptr.p->tableType;
tuxreq->primaryTableId = addfragptr.p->primaryTableId;
@@ -2075,7 +2075,7 @@ void Dblqh::execTIME_SIGNAL(Signal* signal)
if ((cCounterAccCommitBlocked > 0) ||
(cCounterTupCommitBlocked > 0)) {
jam();
- signal->theData[0] = EventReport::UndoLogBlocked;
+ signal->theData[0] = NDB_LE_UndoLogBlocked;
signal->theData[1] = cCounterTupCommitBlocked;
signal->theData[2] = cCounterAccCommitBlocked;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
@@ -2619,12 +2619,20 @@ Dblqh::execREAD_PSUEDO_REQ(Signal* signal){
regTcPtr.i = signal->theData[0];
ptrCheckGuard(regTcPtr, ctcConnectrecFileSize, tcConnectionrec);
- FragrecordPtr regFragptr;
- regFragptr.i = regTcPtr.p->fragmentptr;
- ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord);
-
- signal->theData[0] = regFragptr.p->accFragptr[regTcPtr.p->localFragptr];
- EXECUTE_DIRECT(DBACC, GSN_READ_PSUEDO_REQ, signal, 2);
+ if(signal->theData[1] != AttributeHeader::RANGE_NO)
+ {
+ jam();
+ FragrecordPtr regFragptr;
+ regFragptr.i = regTcPtr.p->fragmentptr;
+ ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord);
+
+ signal->theData[0] = regFragptr.p->accFragptr[regTcPtr.p->localFragptr];
+ EXECUTE_DIRECT(DBACC, GSN_READ_PSUEDO_REQ, signal, 2);
+ }
+ else
+ {
+ signal->theData[0] = regTcPtr.p->m_scan_curr_range_no;
+ }
}
/* ************>> */
@@ -2639,11 +2647,11 @@ void Dblqh::execTUPKEYCONF(Signal* signal)
jamEntry();
tcConnectptr.i = tcIndex;
ptrCheckGuard(tcConnectptr, ttcConnectrecFileSize, regTcConnectionrec);
- if (tcConnectptr.p->seqNoReplica == 0) // Primary replica
- tcConnectptr.p->noFiredTriggers = tupKeyConf->noFiredTriggers;
switch (tcConnectptr.p->transactionState) {
case TcConnectionrec::WAIT_TUP:
jam();
+ if (tcConnectptr.p->seqNoReplica == 0) // Primary replica
+ tcConnectptr.p->noFiredTriggers = tupKeyConf->noFiredTriggers;
tupkeyConfLab(signal);
break;
case TcConnectionrec::COPY_TUPKEY:
@@ -3524,7 +3532,7 @@ void Dblqh::execLQHKEYREQ(Signal* signal)
LQHKEY_error(signal, 6);
return;
}//if
- regTcPtr->localFragptr = (regTcPtr->hashValue >> fragptr.p->hashCheckBit) & 1;
+ regTcPtr->localFragptr = regTcPtr->hashValue & 1;
Uint8 TcopyType = fragptr.p->fragCopy;
tfragDistKey = fragptr.p->fragDistributionKey;
if (fragptr.p->fragStatus == Fragrecord::ACTIVE_CREATION) {
@@ -6833,49 +6841,6 @@ Dblqh::scanMarkers(Signal* signal,
* ALL TUPLES IN THE FRAGMENT. TUP PERFORMS THE NECESSARY SEARCH CONDITIONS
* TO ENSURE THAT ONLY VALID TUPLES ARE RETURNED TO THE APPLICATION.
* ------------------------------------------------------------------------- */
-
-void Dblqh::execACC_SCAN_INFO(Signal* signal)
-{
- jamEntry();
- scanptr.i = signal->theData[0];
- c_scanRecordPool.getPtr(scanptr);
- Uint32 length = signal->theData[3];
- ndbrequire(length <= 4);
- accScanInfoEnterLab(signal, &signal->theData[4], length);
-}//Dblqh::execACC_SCAN_INFO()
-
-
-void Dblqh::execACC_SCAN_INFO24(Signal* signal)
-{
- jamEntry();
- scanptr.i = signal->theData[0];
- c_scanRecordPool.getPtr(scanptr);
- Uint32 length = signal->theData[3];
- ndbrequire(length <= 20);
- accScanInfoEnterLab(signal, &signal->theData[4], length);
-}//Dblqh::execACC_SCAN_INFO24()
-
-void Dblqh::accScanInfoEnterLab(Signal* signal,
- Uint32* dataPtr,
- Uint32 length)
-{
- ndbrequire(length != 0);
- if (scanptr.p->scanState == ScanRecord::WAIT_SCAN_KEYINFO) {
- jam();
- if (keyinfoLab(signal, dataPtr, length)) {
- jam();
- nextScanConfLoopLab(signal);
- }//if
- } else {
- ndbrequire(scanptr.p->scanState == ScanRecord::WAIT_COPY_KEYINFO);
- jam();
- if (keyinfoLab(signal, dataPtr, length)) {
- jam();
- copySendTupkeyReqLab(signal);
- }//if
- }//if
-}//Dblqh::accScanInfoEnterLab()
-
/* *************** */
/* ACC_SCANCONF > */
/* *************** */
@@ -7005,6 +6970,7 @@ void Dblqh::execSTORED_PROCREF(Signal* signal)
switch (scanptr.p->scanState) {
case ScanRecord::WAIT_STORED_PROC_SCAN:
jam();
+ scanptr.p->scanCompletedStatus = ZTRUE;
scanptr.p->scanStoredProcId = signal->theData[2];
tcConnectptr.p->errorCode = errorCode;
closeScanLab(signal);
@@ -7241,7 +7207,6 @@ void Dblqh::closeScanRequestLab(Signal* signal)
jam();
tupScanCloseConfLab(signal);
break;
- case ScanRecord::WAIT_SCAN_KEYINFO:
case ScanRecord::WAIT_NEXT_SCAN:
jam();
/* -------------------------------------------------------------------
@@ -7305,6 +7270,7 @@ void Dblqh::closeScanRequestLab(Signal* signal)
* WE ARE STILL WAITING FOR THE ATTRIBUTE INFORMATION THAT
* OBVIOUSLY WILL NOT ARRIVE. WE CAN QUIT IMMEDIATELY HERE.
* --------------------------------------------------------------------- */
+ //XXX jonas this have to be wrong...
releaseOprec(signal);
if (tcConnectptr.p->abortState == TcConnectionrec::NEW_FROM_TC) {
jam();
@@ -7670,8 +7636,8 @@ void Dblqh::continueAfterReceivingAllAiLab(Signal* signal)
req->fragmentNo = tcConnectptr.p->fragmentid;
req->requestInfo = 0;
AccScanReq::setLockMode(req->requestInfo, scanptr.p->scanLockMode);
- AccScanReq::setKeyinfoFlag(req->requestInfo, scanptr.p->scanKeyinfoFlag);
AccScanReq::setReadCommittedFlag(req->requestInfo, scanptr.p->readCommitted);
+ AccScanReq::setDescendingFlag(req->requestInfo, scanptr.p->descending);
req->transId1 = tcConnectptr.p->transid[0];
req->transId2 = tcConnectptr.p->transid[1];
req->savePointId = tcConnectptr.p->savePointId;
@@ -7775,11 +7741,6 @@ void Dblqh::execSCAN_HBREP(Signal* signal)
}
}
-void Dblqh::sendScanFragRefLateLab(Signal* signal)
-{
-}//Dblqh::sendScanFragRefLateLab()
-
-
void Dblqh::accScanConfScanLab(Signal* signal)
{
AccScanConf * const accScanConf = (AccScanConf *)&signal->theData[0];
@@ -7798,17 +7759,15 @@ void Dblqh::accScanConfScanLab(Signal* signal)
return;
}//if
scanptr.p->scanAccPtr = accScanConf->accPtr;
- Uint32 boundAiLength = tcConnectptr.p->primKeyLen - 4;
if (scanptr.p->rangeScan) {
jam();
- TuxBoundInfo* const req = (TuxBoundInfo*)signal->getDataPtrSend();
+ TuxBoundInfo* req = (TuxBoundInfo*)signal->getDataPtrSend();
req->errorCode = RNIL;
req->tuxScanPtrI = scanptr.p->scanAccPtr;
- req->boundAiLength = boundAiLength;
- if(boundAiLength > 0)
- sendKeyinfoAcc(signal, TuxBoundInfo::SignalLength);
- EXECUTE_DIRECT(DBTUX, GSN_TUX_BOUND_INFO,
- signal, TuxBoundInfo::SignalLength + boundAiLength);
+ Uint32 len = req->boundAiLength = copy_bounds(req->data, tcConnectptr.p);
+ EXECUTE_DIRECT(DBTUX, GSN_TUX_BOUND_INFO, signal,
+ TuxBoundInfo::SignalLength + len);
+
jamEntry();
if (req->errorCode != 0) {
jam();
@@ -7820,35 +7779,176 @@ void Dblqh::accScanConfScanLab(Signal* signal)
tcConnectptr.p->errorCode = req->errorCode;
}
}
- scanptr.p->scanState = ScanRecord::WAIT_STORED_PROC_SCAN;
- signal->theData[0] = tcConnectptr.p->tupConnectrec;
- signal->theData[1] = tcConnectptr.p->tableref;
- signal->theData[2] = scanptr.p->scanSchemaVersion;
- signal->theData[3] = ZSTORED_PROC_SCAN;
-
- signal->theData[4] = scanptr.p->scanAiLength;
- sendSignal(tcConnectptr.p->tcTupBlockref,
- GSN_STORED_PROCREQ, signal, 5, JBB);
- signal->theData[0] = tcConnectptr.p->tupConnectrec;
- AttrbufPtr regAttrinbufptr;
- regAttrinbufptr.i = tcConnectptr.p->firstAttrinbuf;
- while (regAttrinbufptr.i != RNIL) {
- ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf);
+ scanptr.p->scanState = ScanRecord::WAIT_STORED_PROC_SCAN;
+ if(scanptr.p->scanStoredProcId == RNIL)
+ {
jam();
- Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN];
- ndbrequire(dataLen != 0);
- // first 3 words already set in STORED_PROCREQ
- MEMCOPY_NO_WORDS(&signal->theData[3],
- &regAttrinbufptr.p->attrbuf[0],
- dataLen);
+ signal->theData[0] = tcConnectptr.p->tupConnectrec;
+ signal->theData[1] = tcConnectptr.p->tableref;
+ signal->theData[2] = scanptr.p->scanSchemaVersion;
+ signal->theData[3] = ZSTORED_PROC_SCAN;
+
+ signal->theData[4] = scanptr.p->scanAiLength;
sendSignal(tcConnectptr.p->tcTupBlockref,
- GSN_ATTRINFO, signal, dataLen + 3, JBB);
- regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT];
- }//while
- releaseOprec(signal);
+ GSN_STORED_PROCREQ, signal, 5, JBB);
+
+ signal->theData[0] = tcConnectptr.p->tupConnectrec;
+ AttrbufPtr regAttrinbufptr;
+ Uint32 firstAttr = regAttrinbufptr.i = tcConnectptr.p->firstAttrinbuf;
+ while (regAttrinbufptr.i != RNIL) {
+ ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf);
+ jam();
+ Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN];
+ ndbrequire(dataLen != 0);
+ // first 3 words already set in STORED_PROCREQ
+ MEMCOPY_NO_WORDS(&signal->theData[3],
+ &regAttrinbufptr.p->attrbuf[0],
+ dataLen);
+ sendSignal(tcConnectptr.p->tcTupBlockref,
+ GSN_ATTRINFO, signal, dataLen + 3, JBB);
+ regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT];
+ c_no_attrinbuf_recs++;
+ }//while
+
+ /**
+ * Release attr info
+ */
+ if(firstAttr != RNIL)
+ {
+ regAttrinbufptr.p->attrbuf[ZINBUF_NEXT] = cfirstfreeAttrinbuf;
+ cfirstfreeAttrinbuf = firstAttr;
+ tcConnectptr.p->firstAttrinbuf = tcConnectptr.p->lastAttrinbuf = RNIL;
+ }
+ }
+ else
+ {
+ jam();
+ storedProcConfScanLab(signal);
+ }
}//Dblqh::accScanConfScanLab()
+#define print_buf(s,idx,len) {\
+ printf(s); Uint32 t2=len; DatabufPtr t3; t3.i = idx; \
+ while(t3.i != RNIL && t2-- > 0){\
+ ptrCheckGuard(t3, cdatabufFileSize, databuf);\
+ printf("%d ", t3.i); t3.i= t3.p->nextDatabuf;\
+ } printf("\n"); }
+
+Uint32
+Dblqh::copy_bounds(Uint32 * dst, TcConnectionrec* tcPtrP)
+{
+ /**
+ * copy_bounds handles multiple bounds by
+ * in the 16 upper bits of the first words (used to specify bound type)
+ * setting the length of this specific bound
+ *
+ */
+
+ DatabufPtr regDatabufptr;
+ Uint32 left = 4 - tcPtrP->m_offset_current_keybuf; // left in buf
+ Uint32 totalLen = tcPtrP->primKeyLen - 4;
+ regDatabufptr.i = tcPtrP->firstTupkeybuf;
+
+ ndbassert(tcPtrP->primKeyLen >= 4);
+ ndbassert(tcPtrP->m_offset_current_keybuf < 4);
+ ndbassert(!(totalLen == 0 && regDatabufptr.i != RNIL));
+ ndbassert(!(totalLen != 0 && regDatabufptr.i == RNIL));
+
+ if(totalLen)
+ {
+ ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf);
+ Uint32 sig0 = regDatabufptr.p->data[0];
+ Uint32 sig1 = regDatabufptr.p->data[1];
+ Uint32 sig2 = regDatabufptr.p->data[2];
+ Uint32 sig3 = regDatabufptr.p->data[3];
+
+ switch(left){
+ case 4:
+ * dst++ = sig0;
+ case 3:
+ * dst++ = sig1;
+ case 2:
+ * dst++ = sig2;
+ case 1:
+ * dst++ = sig3;
+ }
+
+ Uint32 first = (* (dst - left)); // First word in range
+
+ // Length of this range
+ Uint8 offset;
+ const Uint32 len = (first >> 16) ? (first >> 16) : totalLen;
+ tcPtrP->m_scan_curr_range_no = (first & 0xFFF0) >> 4;
+ (* (dst - left)) = (first & 0xF); // Remove length & range no
+
+ if(len < left)
+ {
+ offset = len;
+ }
+ else
+ {
+ Databuf * lastP;
+ left = (len - left);
+ regDatabufptr.i = regDatabufptr.p->nextDatabuf;
+
+ while(left >= 4)
+ {
+ left -= 4;
+ lastP = regDatabufptr.p;
+ ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf);
+ sig0 = regDatabufptr.p->data[0];
+ sig1 = regDatabufptr.p->data[1];
+ sig2 = regDatabufptr.p->data[2];
+ sig3 = regDatabufptr.p->data[3];
+ regDatabufptr.i = regDatabufptr.p->nextDatabuf;
+
+ * dst++ = sig0;
+ * dst++ = sig1;
+ * dst++ = sig2;
+ * dst++ = sig3;
+ }
+
+ if(left > 0)
+ {
+ lastP = regDatabufptr.p;
+ ptrCheckGuard(regDatabufptr, cdatabufFileSize, databuf);
+ sig0 = regDatabufptr.p->data[0];
+ sig1 = regDatabufptr.p->data[1];
+ sig2 = regDatabufptr.p->data[2];
+ sig3 = regDatabufptr.p->data[3];
+ * dst++ = sig0;
+ * dst++ = sig1;
+ * dst++ = sig2;
+ * dst++ = sig3;
+ }
+ else
+ {
+ lastP = regDatabufptr.p;
+ }
+ offset = left & 3;
+ lastP->nextDatabuf = cfirstfreeDatabuf;
+ cfirstfreeDatabuf = tcPtrP->firstTupkeybuf;
+ ndbassert(cfirstfreeDatabuf != RNIL);
+ }
+
+ if(len == totalLen && regDatabufptr.i != RNIL)
+ {
+ regDatabufptr.p->nextDatabuf = cfirstfreeDatabuf;
+ cfirstfreeDatabuf = regDatabufptr.i;
+ tcPtrP->lastTupkeybuf = regDatabufptr.i = RNIL;
+ ndbassert(cfirstfreeDatabuf != RNIL);
+ }
+
+ tcPtrP->m_offset_current_keybuf = offset;
+ tcPtrP->firstTupkeybuf = regDatabufptr.i;
+ tcPtrP->primKeyLen = 4 + totalLen - len;
+
+ return len;
+ }
+ return totalLen;
+}
+
/* -------------------------------------------------------------------------
* ENTER STORED_PROCCONF WITH
* TC_CONNECTPTR,
@@ -7899,7 +7999,6 @@ void Dblqh::continueFirstScanAfterBlockedLab(Signal* signal)
scanptr.i = tcConnectptr.p->tcScanRec;
c_scanRecordPool.getPtr(scanptr);
scanptr.p->scanState = ScanRecord::WAIT_NEXT_SCAN;
- init_acc_ptr_list(scanptr.p);
signal->theData[0] = scanptr.p->scanAccPtr;
signal->theData[1] = RNIL;
signal->theData[2] = NextScanReq::ZSCAN_NEXT;
@@ -8027,7 +8126,10 @@ void Dblqh::nextScanConfScanLab(Signal* signal)
if (scanptr.p->m_curr_batch_size_rows > 0) {
jam();
- scanptr.p->scanCompletedStatus = ZTRUE;
+
+ if((tcConnectptr.p->primKeyLen - 4) == 0)
+ scanptr.p->scanCompletedStatus = ZTRUE;
+
scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ;
sendScanFragConf(signal, ZFALSE);
return;
@@ -8082,22 +8184,6 @@ void Dblqh::nextScanConfScanLab(Signal* signal)
scanptr.p->scanLocalref[0] = nextScanConf->localKey[0];
scanptr.p->scanLocalref[1] = nextScanConf->localKey[1];
scanptr.p->scanLocalFragid = nextScanConf->fragId;
- if (scanptr.p->scanKeyinfoFlag) {
- jam();
- tcConnectptr.p->primKeyLen = nextScanConf->keyLength;
- seizeTupkeybuf(signal);
- databufptr.p->data[0] = nextScanConf->key[0];
- databufptr.p->data[1] = nextScanConf->key[1];
- databufptr.p->data[2] = nextScanConf->key[2];
- databufptr.p->data[3] = nextScanConf->key[3];
- if (nextScanConf->keyLength > 4) {
- jam();
- tcConnectptr.p->save1 = 4;
- scanptr.p->scanState = ScanRecord::WAIT_SCAN_KEYINFO;
- return;
- }//if
- }//if
- jam();
nextScanConfLoopLab(signal);
}//Dblqh::nextScanConfScanLab()
@@ -8109,7 +8195,6 @@ void Dblqh::nextScanConfLoopLab(Signal* signal)
if (scanptr.p->scanCompletedStatus == ZTRUE) {
jam();
releaseActiveFrag(signal);
- releaseOprec(signal);
if ((scanptr.p->scanLockHold == ZTRUE) &&
(scanptr.p->m_curr_batch_size_rows > 0)) {
jam();
@@ -8131,13 +8216,7 @@ void Dblqh::nextScanConfLoopLab(Signal* signal)
ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord);
if (! scanptr.p->rangeScan) {
tableRef = tcConnectptr.p->tableref;
- if (fragptr.p->fragId == scanptr.p->scanLocalFragid) {
- jam();
- tupFragPtr = fragptr.p->tupFragptr[0];
- } else {
- jam();
- tupFragPtr = fragptr.p->tupFragptr[1];
- }//if
+ tupFragPtr = fragptr.p->tupFragptr[scanptr.p->scanLocalFragid & 1];
} else {
jam();
// for ordered index use primary table
@@ -8145,13 +8224,7 @@ void Dblqh::nextScanConfLoopLab(Signal* signal)
tFragPtr.i = fragptr.p->tableFragptr;
ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord);
tableRef = tFragPtr.p->tabRef;
- if (tFragPtr.p->fragId == scanptr.p->scanLocalFragid) {
- jam();
- tupFragPtr = tFragPtr.p->tupFragptr[0];
- } else {
- jam();
- tupFragPtr = tFragPtr.p->tupFragptr[1];
- }//if
+ tupFragPtr = tFragPtr.p->tupFragptr[scanptr.p->scanLocalFragid & 1];
}
{
jam();
@@ -8186,33 +8259,46 @@ void Dblqh::nextScanConfLoopLab(Signal* signal)
* -------------------------------------------------------------------------
* PRECONDITION: SCAN_STATE = WAIT_SCAN_KEYINFO
* ------------------------------------------------------------------------- */
-bool Dblqh::keyinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length)
+void
+Dblqh::keyinfoLab(const Uint32 * src, const Uint32 * end)
{
- tcConnectptr.i = scanptr.p->scanTcrec;
- ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
- Uint32 index = 0;
do {
jam();
- seizeTupkeybuf(signal);
- databufptr.p->data[0] = dataPtr[index];
- databufptr.p->data[1] = dataPtr[index + 1];
- databufptr.p->data[2] = dataPtr[index + 2];
- databufptr.p->data[3] = dataPtr[index + 3];
- index += 4;
- tcConnectptr.p->save1 = tcConnectptr.p->save1 + 4;
- if (tcConnectptr.p->save1 >= tcConnectptr.p->primKeyLen) {
- jam();
- return true;
- }//if
- if (index >= length) {
- jam();
- return false;
- }//if
- } while (index < 20);
- ndbrequire(false);
- return false;
+ seizeTupkeybuf(0);
+ databufptr.p->data[0] = * src ++;
+ databufptr.p->data[1] = * src ++;
+ databufptr.p->data[2] = * src ++;
+ databufptr.p->data[3] = * src ++;
+ } while (src < end);
}//Dblqh::keyinfoLab()
+Uint32
+Dblqh::readPrimaryKeys(ScanRecord *scanP, TcConnectionrec *tcConP, Uint32 *dst)
+{
+ Uint32 tableId = tcConP->tableref;
+ Uint32 fragId = scanP->scanLocalFragid;
+ Uint32 fragPageId = scanP->scanLocalref[0];
+ Uint32 pageIndex = scanP->scanLocalref[1];
+
+ if(scanP->rangeScan)
+ {
+ jam();
+ // for ordered index use primary table
+ FragrecordPtr tFragPtr;
+ tFragPtr.i = fragptr.p->tableFragptr;
+ ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord);
+ tableId = tFragPtr.p->tabRef;
+ }
+
+ int ret = c_tup->accReadPk(tableId, fragId, fragPageId, pageIndex, dst, false);
+ if(0)
+ ndbout_c("readPrimaryKeys(table: %d fragment: %d [ %d %d ] -> %d",
+ tableId, fragId, fragPageId, pageIndex, ret);
+ ndbassert(ret > 0);
+
+ return ret;
+}
+
/* -------------------------------------------------------------------------
* ENTER TUPKEYCONF
* -------------------------------------------------------------------------
@@ -8232,7 +8318,6 @@ void Dblqh::scanTupkeyConfLab(Signal* signal)
/* ---------------------------------------------------------------------
* STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED.
* --------------------------------------------------------------------- */
- releaseOprec(signal);
if ((scanptr.p->scanLockHold == ZTRUE) &&
(scanptr.p->m_curr_batch_size_rows > 0)) {
jam();
@@ -8246,10 +8331,8 @@ void Dblqh::scanTupkeyConfLab(Signal* signal)
}//if
if (scanptr.p->scanKeyinfoFlag) {
jam();
- sendKeyinfo20(signal, scanptr.p, tcConnectptr.p);
- releaseOprec(signal);
-
- tdata4 += tcConnectptr.p->primKeyLen;// Inform API about keyinfo len aswell
+ // Inform API about keyinfo len aswell
+ tdata4 += sendKeyinfo20(signal, scanptr.p, tcConnectptr.p);
}//if
ndbrequire(scanptr.p->m_curr_batch_size_rows < MAX_PARALLEL_OP_PER_SCAN);
scanptr.p->m_curr_batch_size_bytes+= tdata4;
@@ -8351,7 +8434,6 @@ void Dblqh::scanTupkeyRefLab(Signal* signal)
tcConnectptr.p->transactionState = TcConnectionrec::SCAN_STATE_USED;
scanptr.i = tcConnectptr.p->tcScanRec;
releaseActiveFrag(signal);
- releaseOprec(signal);
c_scanRecordPool.getPtr(scanptr);
if (scanptr.p->scanCompletedStatus == ZTRUE) {
/* ---------------------------------------------------------------------
@@ -8473,8 +8555,18 @@ void Dblqh::continueCloseScanAfterBlockedLab(Signal* signal)
void Dblqh::accScanCloseConfLab(Signal* signal)
{
tcConnectptr.i = scanptr.p->scanTcrec;
- scanptr.p->scanState = ScanRecord::WAIT_DELETE_STORED_PROC_ID_SCAN;
ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec);
+
+ if((tcConnectptr.p->primKeyLen - 4) > 0 &&
+ scanptr.p->scanCompletedStatus != ZTRUE)
+ {
+ jam();
+ releaseActiveFrag(signal);
+ continueAfterReceivingAllAiLab(signal);
+ return;
+ }
+
+ scanptr.p->scanState = ScanRecord::WAIT_DELETE_STORED_PROC_ID_SCAN;
signal->theData[0] = tcConnectptr.p->tupConnectrec;
signal->theData[1] = tcConnectptr.p->tableref;
signal->theData[2] = scanptr.p->scanSchemaVersion;
@@ -8537,6 +8629,7 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq)
const Uint32 keyinfo = ScanFragReq::getKeyinfoFlag(reqinfo);
const Uint32 readCommitted = ScanFragReq::getReadCommittedFlag(reqinfo);
const Uint32 idx = ScanFragReq::getRangeScanFlag(reqinfo);
+ const Uint32 descending = ScanFragReq::getDescendingFlag(reqinfo);
const Uint32 attrLen = ScanFragReq::getAttrLen(reqinfo);
const Uint32 scanPrio = ScanFragReq::getScanPrio(reqinfo);
@@ -8558,6 +8651,7 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq)
scanptr.p->scanLockMode = scanLockMode;
scanptr.p->readCommitted = readCommitted;
scanptr.p->rangeScan = idx;
+ scanptr.p->descending = descending;
scanptr.p->scanState = ScanRecord::SCAN_FREE;
scanptr.p->scanFlag = ZFALSE;
scanptr.p->scanLocalref[0] = 0;
@@ -8567,6 +8661,7 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq)
scanptr.p->scanNumber = ~0;
scanptr.p->scanApiOpPtr = scanFragReq->clientOpPtr;
scanptr.p->m_last_row = 0;
+ scanptr.p->scanStoredProcId = RNIL;
if (max_rows == 0 || (max_bytes > 0 && max_rows > max_bytes)){
jam();
@@ -8625,7 +8720,8 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq)
#ifdef TRACE_SCAN_TAKEOVER
ndbout_c("adding (%d %d) table: %d fragId: %d frag.i: %d tableFragptr: %d",
scanptr.p->scanNumber, scanptr.p->fragPtrI,
- tabptr.i, scanFragReq->fragmentNo, fragptr.i, fragptr.p->tableFragptr);
+ tabptr.i, scanFragReq->fragmentNoKeyLen & 0xFFFF,
+ fragptr.i, fragptr.p->tableFragptr);
#endif
c_scanTakeOverHash.add(scanptr);
}
@@ -8661,6 +8757,8 @@ void Dblqh::initScanTc(Signal* signal,
tcConnectptr.p->operation = ZREAD;
tcConnectptr.p->listState = TcConnectionrec::NOT_IN_LIST;
tcConnectptr.p->commitAckMarker = RNIL;
+ tcConnectptr.p->m_offset_current_keybuf = 0;
+ tcConnectptr.p->m_scan_curr_range_no = 0;
tabptr.p->usageCount++;
}//Dblqh::initScanTc()
@@ -8775,23 +8873,17 @@ void Dblqh::releaseScanrec(Signal* signal)
* ------- SEND KEYINFO20 TO API -------
*
* ------------------------------------------------------------------------ */
-void Dblqh::sendKeyinfo20(Signal* signal,
- ScanRecord * scanP,
- TcConnectionrec * tcConP)
+Uint32 Dblqh::sendKeyinfo20(Signal* signal,
+ ScanRecord * scanP,
+ TcConnectionrec * tcConP)
{
ndbrequire(scanP->m_curr_batch_size_rows < MAX_PARALLEL_OP_PER_SCAN);
KeyInfo20 * keyInfo = (KeyInfo20 *)&signal->theData[0];
- DatabufPtr TdataBuf;
- TdataBuf.i = tcConP->firstTupkeybuf;
- Uint32 keyLen = tcConP->primKeyLen;
- const Uint32 dataBufSz = cdatabufFileSize;
-
/**
* Note that this code requires signal->theData to be big enough for
* a entire key
*/
- ndbrequire(keyLen * 4 <= sizeof(signal->theData));
const BlockReference ref = scanP->scanApiBlockref;
const Uint32 scanOp = scanP->m_curr_batch_size_rows;
const Uint32 nodeId = refToNode(ref);
@@ -8804,24 +8896,12 @@ void Dblqh::sendKeyinfo20(Signal* signal,
Uint32 * dst = keyInfo->keyData;
dst += nodeId == getOwnNodeId() ? 0 : KeyInfo20::DataLength;
- /**
- * Copy keydata from data buffer into signal
- *
- */
- for(Uint32 i = 0; i < keyLen; i += 4){
- ptrCheckGuard(TdataBuf, dataBufSz, databuf);
- * dst++ = TdataBuf.p->data[0];
- * dst++ = TdataBuf.p->data[1];
- * dst++ = TdataBuf.p->data[2];
- * dst++ = TdataBuf.p->data[3];
- TdataBuf.i = TdataBuf.p->nextDatabuf;
- }
-
+ Uint32 keyLen = readPrimaryKeys(scanP, tcConP, dst);
+ Uint32 fragId = tcConP->fragmentid;
keyInfo->clientOpPtr = scanP->scanApiOpPtr;
keyInfo->keyLen = keyLen;
- keyInfo->scanInfo_Node = KeyInfo20::setScanInfo(scanOp,
- scanP->scanNumber)+
- (getOwnNodeId() << 20);
+ keyInfo->scanInfo_Node =
+ KeyInfo20::setScanInfo(scanOp, scanP->scanNumber) + (fragId << 20);
keyInfo->transId1 = tcConP->transid[0];
keyInfo->transId2 = tcConP->transid[1];
@@ -8844,7 +8924,7 @@ void Dblqh::sendKeyinfo20(Signal* signal,
MEMCOPY_NO_WORDS(keyInfo->keyData, src, keyLen);
sendSignal(ref, GSN_KEYINFO20, signal,
KeyInfo20::HeaderLength+keyLen, JBB);
- return;
+ return keyLen;
}
LinearSectionPtr ptr[3];
@@ -8852,13 +8932,13 @@ void Dblqh::sendKeyinfo20(Signal* signal,
ptr[0].sz = keyLen;
sendSignal(ref, GSN_KEYINFO20, signal, KeyInfo20::HeaderLength,
JBB, ptr, 1);
- return;
+ return keyLen;
}
EXECUTE_DIRECT(refToBlock(ref), GSN_KEYINFO20, signal,
KeyInfo20::HeaderLength + keyLen);
jamEntry();
- return;
+ return keyLen;
}
/**
@@ -8884,7 +8964,7 @@ void Dblqh::sendKeyinfo20(Signal* signal,
keyInfo->keyData[keyLen] = ref;
sendSignal(routeBlockref, GSN_KEYINFO20_R, signal,
KeyInfo20::HeaderLength+keyLen+1, JBB);
- return;
+ return keyLen;
}
keyInfo->keyData[0] = ref;
@@ -8893,7 +8973,7 @@ void Dblqh::sendKeyinfo20(Signal* signal,
ptr[0].sz = keyLen;
sendSignal(routeBlockref, GSN_KEYINFO20_R, signal,
KeyInfo20::HeaderLength+1, JBB, ptr, 1);
- return;
+ return keyLen;
}
/* ------------------------------------------------------------------------
@@ -9069,7 +9149,6 @@ void Dblqh::execCOPY_FRAGREQ(Signal* signal)
req->fragmentNo = fragId;
req->requestInfo = 0;
AccScanReq::setLockMode(req->requestInfo, 0);
- AccScanReq::setKeyinfoFlag(req->requestInfo, 1);
AccScanReq::setReadCommittedFlag(req->requestInfo, 0);
req->transId1 = tcConnectptr.p->transid[0];
req->transId2 = tcConnectptr.p->transid[1];
@@ -9222,12 +9301,6 @@ void Dblqh::nextScanConfCopyLab(Signal* signal)
set_acc_ptr_in_scan_record(scanptr.p, 0, nextScanConf->accOperationPtr);
initCopyTc(signal);
- if (tcConnectptr.p->primKeyLen > 4) {
- jam();
- tcConnectptr.p->save1 = 4;
- scanptr.p->scanState = ScanRecord::WAIT_COPY_KEYINFO;
- return;
- }//if
copySendTupkeyReqLab(signal);
return;
}//Dblqh::nextScanConfCopyLab()
@@ -9243,13 +9316,7 @@ void Dblqh::copySendTupkeyReqLab(Signal* signal)
scanptr.p->scanState = ScanRecord::WAIT_TUPKEY_COPY;
fragptr.i = tcConnectptr.p->fragmentptr;
ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord);
- if (fragptr.p->fragId == scanptr.p->scanLocalFragid) {
- jam();
- tupFragPtr = fragptr.p->tupFragptr[0];
- } else {
- jam();
- tupFragPtr = fragptr.p->tupFragptr[1];
- }//if
+ tupFragPtr = fragptr.p->tupFragptr[scanptr.p->scanLocalFragid & 1];
{
TupKeyReq * const tupKeyReq = (TupKeyReq *)signal->getDataPtrSend();
@@ -9327,6 +9394,7 @@ void Dblqh::copyTupkeyConfLab(Signal* signal)
scanptr.i = tcConnectptr.p->tcScanRec;
c_scanRecordPool.getPtr(scanptr);
+ ScanRecord* scanP = scanptr.p;
releaseActiveFrag(signal);
if (tcConnectptr.p->errorCode != 0) {
jam();
@@ -9341,9 +9409,23 @@ void Dblqh::copyTupkeyConfLab(Signal* signal)
closeCopyLab(signal);
return;
}//if
+ TcConnectionrec * tcConP = tcConnectptr.p;
tcConnectptr.p->totSendlenAi = readLength;
tcConnectptr.p->connectState = TcConnectionrec::COPY_CONNECTED;
- calculateHash(signal);
+
+ // Read primary keys (used to get here via scan keyinfo)
+ Uint32* tmp = signal->getDataPtrSend()+24;
+ Uint32 len= tcConnectptr.p->primKeyLen = readPrimaryKeys(scanP, tcConP, tmp);
+
+ // Calculate hash (no need to linearies key)
+ tcConnectptr.p->hashValue = md5_hash((Uint64*)tmp, len);
+
+ // Move into databuffer to make packLqhkeyreqLab happy
+ memcpy(tcConP->tupkeyData, tmp, 4*4);
+ if(len > 4)
+ keyinfoLab(tmp+4, tmp + len);
+ LqhKeyReq::setKeyLen(tcConP->reqinfo, len);
+
/*---------------------------------------------------------------------------*/
// To avoid using up to many operation records in ACC we will increase the
// constant to ensure that we never send more than 40 records at a time.
@@ -9354,7 +9436,7 @@ void Dblqh::copyTupkeyConfLab(Signal* signal)
// records to ensure that node recovery does not fail because of simultaneous
// scanning.
/*---------------------------------------------------------------------------*/
- UintR TnoOfWords = readLength + tcConnectptr.p->primKeyLen;
+ UintR TnoOfWords = readLength + len;
TnoOfWords = TnoOfWords + MAGIC_CONSTANT;
TnoOfWords = TnoOfWords + (TnoOfWords >> 2);
@@ -9676,7 +9758,6 @@ void Dblqh::closeCopyRequestLab(Signal* signal)
scanptr.p->scanErrorCounter++;
switch (scanptr.p->scanState) {
case ScanRecord::WAIT_TUPKEY_COPY:
- case ScanRecord::WAIT_COPY_KEYINFO:
case ScanRecord::WAIT_NEXT_SCAN_COPY:
jam();
/*---------------------------------------------------------------------------*/
@@ -9907,11 +9988,6 @@ void Dblqh::execCOPY_STATEREQ(Signal* signal)
void Dblqh::initCopyTc(Signal* signal)
{
const NextScanConf * const nextScanConf = (NextScanConf *)&signal->theData[0];
- tcConnectptr.p->primKeyLen = nextScanConf->keyLength;
- tcConnectptr.p->tupkeyData[0] = nextScanConf->key[0];
- tcConnectptr.p->tupkeyData[1] = nextScanConf->key[1];
- tcConnectptr.p->tupkeyData[2] = nextScanConf->key[2];
- tcConnectptr.p->tupkeyData[3] = nextScanConf->key[3];
scanptr.p->scanLocalref[0] = nextScanConf->localKey[0];
scanptr.p->scanLocalref[1] = nextScanConf->localKey[1];
scanptr.p->scanLocalFragid = nextScanConf->fragId;
@@ -9920,7 +9996,6 @@ void Dblqh::initCopyTc(Signal* signal)
tcConnectptr.p->opExec = 0; /* NOT INTERPRETED MODE */
tcConnectptr.p->schemaVersion = scanptr.p->scanSchemaVersion;
Uint32 reqinfo = 0;
- LqhKeyReq::setKeyLen(reqinfo, nextScanConf->keyLength);
LqhKeyReq::setLockType(reqinfo, ZINSERT);
LqhKeyReq::setDirtyFlag(reqinfo, 1);
LqhKeyReq::setSimpleFlag(reqinfo, 1);
@@ -13495,7 +13570,6 @@ void Dblqh::execSR_FRAGIDCONF(Signal* signal)
ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord);
fragptr.p->accFragptr[0] = srFragidConf->fragPtr[0];
fragptr.p->accFragptr[1] = srFragidConf->fragPtr[1];
- fragptr.p->hashCheckBit = srFragidConf->hashCheckBit;
Uint32 noLocFrag = srFragidConf->noLocFrag;
ndbrequire(noLocFrag == 2);
Uint32 fragid[2];
diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
index fb90ccc8c90..2baa4400409 100644
--- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
+++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
@@ -561,7 +561,7 @@ public:
Uint32 expectedTransIdAI;
AttributeBuffer transIdAI; // For accumulating TransId_AI
- TcIndxReq tcIndxReq;
+ TcKeyReq tcIndxReq;
UintR connectionIndex;
UintR indexReadTcConnect; //
@@ -897,11 +897,11 @@ public:
UintR hashValue; /* THE HASH VALUE USED TO LOCATE FRAGMENT */
Uint8 distributionKeyIndicator;
- Uint8 distributionGroupIndicator;
- Uint8 distributionGroupType;
+ Uint8 m_special_hash; // collation or distribution key
+ Uint8 unused2;
Uint8 lenAiInTckeyreq; /* LENGTH OF ATTRIBUTE INFORMATION IN TCKEYREQ */
- Uint8 distributionKey;
+ Uint8 fragmentDistributionKey; /* DIH generation no */
/**
* EXECUTION MODE OF OPERATION
@@ -925,16 +925,16 @@ public:
// Second 16 byte cache line in second 64 byte cache
// line. Diverse use.
//---------------------------------------------------
- UintR distributionGroup;
+ UintR distributionKey;
UintR nextCacheRec;
- UintR distributionKeySize;
+ UintR unused3;
Uint32 scanInfo;
//---------------------------------------------------
// Third 16 byte cache line in second 64
// byte cache line. Diverse use.
//---------------------------------------------------
- Uint32 scanNode;
+ Uint32 unused4;
Uint32 scanTakeOverInd;
UintR firstKeybuf; /* POINTER THE LINKED LIST OF KEY BUFFERS */
UintR lastKeybuf; /* VARIABLE POINTING TO THE LAST KEY BUFFER */
@@ -972,6 +972,7 @@ public:
typedef Ptr<HostRecord> HostRecordPtr;
/* *********** TABLE RECORD ********************************************* */
+
/********************************************************/
/* THIS RECORD CONTAINS THE CURRENT SCHEMA VERSION OF */
/* ALL TABLES IN THE SYSTEM. */
@@ -982,13 +983,22 @@ public:
Uint8 dropping;
Uint8 tableType;
Uint8 storedTable;
+
+ Uint8 noOfKeyAttr;
+ Uint8 hasCharAttr;
+ Uint8 noOfDistrKeys;
+ struct KeyAttr {
+ Uint32 attributeDescriptor;
+ CHARSET_INFO* charsetInfo;
+ } keyAttr[MAX_ATTRIBUTES_IN_INDEX];
+
bool checkTable(Uint32 schemaVersion) const {
return enabled && !dropping && (schemaVersion == currentSchemaVersion);
}
-
+
Uint32 getErrorCode(Uint32 schemaVersion) const;
-
+
struct DropTable {
Uint32 senderRef;
Uint32 senderData;
@@ -1167,7 +1177,7 @@ public:
Uint32 nextScan;
// Length of expected attribute information
- Uint32 scanAiLength;
+ union { Uint32 scanAiLength; Uint32 m_booked_fragments_count; };
Uint32 scanKeyLen;
@@ -1436,6 +1446,10 @@ private:
void gcpTcfinished(Signal* signal);
void handleGcp(Signal* signal);
void hash(Signal* signal);
+ bool handle_special_hash(Uint32 dstHash[4],
+ Uint32* src, Uint32 srcLen,
+ Uint32 tabPtrI, bool distr);
+
void initApiConnect(Signal* signal);
void initApiConnectRec(Signal* signal,
ApiConnectRecord * const regApiPtr,
@@ -1688,7 +1702,7 @@ private:
c_scan_count = c_range_scan_count = 0;
}
Uint32 report(Signal* signal){
- signal->theData[0] = EventReport::TransReportCounters;
+ signal->theData[0] = NDB_LE_TransReportCounters;
signal->theData[1] = ctransCount;
signal->theData[2] = ccommitCount;
signal->theData[3] = creadCount;
diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
index efd4c2a46d0..c8260223004 100644
--- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
+++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
@@ -20,6 +20,7 @@
#include "md5_hash.hpp"
#include <RefConvert.hpp>
#include <ndb_limits.h>
+#include <my_sys.h>
#include <signaldata/EventReport.hpp>
#include <signaldata/TcKeyReq.hpp>
@@ -63,6 +64,8 @@
#include <signaldata/PackedSignal.hpp>
#include <AttributeHeader.hpp>
#include <signaldata/DictTabInfo.hpp>
+#include <AttributeDescriptor.hpp>
+#include <SectionReader.hpp>
#include <NdbOut.hpp>
#include <DebuggerNames.hpp>
@@ -313,6 +316,10 @@ void Dbtc::execREAD_NODESREF(Signal* signal)
void Dbtc::execTC_SCHVERREQ(Signal* signal)
{
jamEntry();
+ if (! assembleFragments(signal)) {
+ jam();
+ return;
+ }
tabptr.i = signal->theData[0];
ptrCheckGuard(tabptr, ctabrecFilesize, tableRecord);
tabptr.p->currentSchemaVersion = signal->theData[1];
@@ -320,10 +327,44 @@ void Dbtc::execTC_SCHVERREQ(Signal* signal)
BlockReference retRef = signal->theData[3];
tabptr.p->tableType = (Uint8)signal->theData[4];
BlockReference retPtr = signal->theData[5];
+ Uint32 noOfKeyAttr = signal->theData[6];
+ ndbrequire(noOfKeyAttr <= MAX_ATTRIBUTES_IN_INDEX);
+ Uint32 hasCharAttr = 0;
+ Uint32 noOfDistrKeys = 0;
+ SegmentedSectionPtr s0Ptr;
+ signal->getSection(s0Ptr, 0);
+ SectionReader r0(s0Ptr, getSectionSegmentPool());
+ Uint32 i = 0;
+ while (i < noOfKeyAttr) {
+ jam();
+ Uint32 attributeDescriptor = ~0;
+ Uint32 csNumber = ~0;
+ if (! r0.getWord(&attributeDescriptor) ||
+ ! r0.getWord(&csNumber)) {
+ jam();
+ break;
+ }
+ CHARSET_INFO* cs = 0;
+ if (csNumber != 0) {
+ cs = all_charsets[csNumber];
+ ndbrequire(cs != 0);
+ hasCharAttr = 1;
+ }
+
+ noOfDistrKeys += AttributeDescriptor::getDKey(attributeDescriptor);
+ tabptr.p->keyAttr[i].attributeDescriptor = attributeDescriptor;
+ tabptr.p->keyAttr[i].charsetInfo = cs;
+ i++;
+ }
+ ndbrequire(i == noOfKeyAttr);
+ releaseSections(signal);
ndbrequire(tabptr.p->enabled == false);
tabptr.p->enabled = true;
tabptr.p->dropping = false;
+ tabptr.p->noOfKeyAttr = noOfKeyAttr;
+ tabptr.p->hasCharAttr = hasCharAttr;
+ tabptr.p->noOfDistrKeys = noOfDistrKeys;
signal->theData[0] = tabptr.i;
signal->theData[1] = retPtr;
@@ -2221,11 +2262,10 @@ void Dbtc::hash(Signal* signal)
UintR Tdata2;
UintR Tdata3;
UintR* Tdata32;
- Uint64 Tdata[512];
-
+
CacheRecord * const regCachePtr = cachePtr.p;
- Tdata32 = (UintR*)&Tdata[0];
-
+ Tdata32 = signal->theData;
+
Tdata0 = regCachePtr->keydata[0];
Tdata1 = regCachePtr->keydata[1];
Tdata2 = regCachePtr->keydata[2];
@@ -2251,31 +2291,147 @@ void Dbtc::hash(Signal* signal)
ti += 4;
}//while
}//if
- UintR ThashValue;
- UintR TdistrHashValue;
- ThashValue = md5_hash((Uint64*)&Tdata32[0], (UintR)regCachePtr->keylen);
- if (regCachePtr->distributionGroupIndicator == 1) {
- if (regCachePtr->distributionGroupType == 1) {
- jam();
- TdistrHashValue = (regCachePtr->distributionGroup << 6);
- } else {
- jam();
- Tdata32[0] = regCachePtr->distributionGroup;
- TdistrHashValue = md5_hash((Uint64*)&Tdata32[0], (UintR)1);
- }//if
- } else if (regCachePtr->distributionKeyIndicator == 1) {
+ UintR keylen = (UintR)regCachePtr->keylen;
+ Uint32 distKey = regCachePtr->distributionKeyIndicator;
+
+ Uint32 tmp[4];
+ if(!regCachePtr->m_special_hash)
+ {
+ md5_hash(tmp, (Uint64*)&Tdata32[0], keylen);
+ }
+ else
+ {
+ handle_special_hash(tmp, Tdata32, keylen, regCachePtr->tableref, !distKey);
+ }
+
+ thashValue = tmp[0];
+ if (distKey){
jam();
- TdistrHashValue = md5_hash((Uint64*)&Tdata32[0],
- (UintR)regCachePtr->distributionKeySize);
+ tdistrHashValue = regCachePtr->distributionKey;
} else {
jam();
- TdistrHashValue = ThashValue;
+ tdistrHashValue = tmp[1];
}//if
- thashValue = ThashValue;
- tdistrHashValue = TdistrHashValue;
}//Dbtc::hash()
+bool
+Dbtc::handle_special_hash(Uint32 dstHash[4], Uint32* src, Uint32 srcLen,
+ Uint32 tabPtrI,
+ bool distr)
+{
+ Uint64 Tmp[MAX_KEY_SIZE_IN_WORDS * 4 * MAX_XFRM_MULTIPLY];
+ const Uint32 dstSize = sizeof(Tmp) / 4;
+ const TableRecord* tabPtrP = &tableRecord[tabPtrI];
+ const Uint32 noOfKeyAttr = tabPtrP->noOfKeyAttr;
+ Uint32 noOfDistrKeys = tabPtrP->noOfDistrKeys;
+ const bool hasCharAttr = tabPtrP->hasCharAttr;
+
+ Uint32 *dst = (Uint32*)Tmp;
+ Uint32 dstPos = 0;
+ Uint32 srcPos = 0;
+ Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX];
+ if(hasCharAttr){
+ Uint32 i = 0;
+ while (i < noOfKeyAttr) {
+ const TableRecord::KeyAttr& keyAttr = tabPtrP->keyAttr[i];
+
+ Uint32 srcBytes =
+ AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor);
+ Uint32 srcWords = (srcBytes + 3) / 4;
+ Uint32 dstWords = ~0;
+ uchar* dstPtr = (uchar*)&dst[dstPos];
+ const uchar* srcPtr = (const uchar*)&src[srcPos];
+ CHARSET_INFO* cs = keyAttr.charsetInfo;
+
+ if (cs == NULL) {
+ jam();
+ memcpy(dstPtr, srcPtr, srcWords << 2);
+ dstWords = srcWords;
+ } else {
+ jam();
+ Uint32 typeId =
+ AttributeDescriptor::getType(keyAttr.attributeDescriptor);
+ Uint32 lb, len;
+ bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len);
+ ndbrequire(ok);
+ Uint32 xmul = cs->strxfrm_multiply;
+ if (xmul == 0)
+ xmul = 1;
+ /*
+ * Varchar is really Char. End spaces do not matter. To get
+ * same hash we blank-pad to maximum length via strnxfrm.
+ * TODO use MySQL charset-aware hash function instead
+ */
+ Uint32 dstLen = xmul * (srcBytes - lb);
+ ndbrequire(dstLen <= ((dstSize - dstPos) << 2));
+ int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len);
+ ndbrequire(n != -1);
+ while ((n & 3) != 0) {
+ dstPtr[n++] = 0;
+ }
+ dstWords = (n >> 2);
+ }
+ dstPos += dstWords;
+ srcPos += srcWords;
+ keyPartLen[i++] = dstWords;
+ }
+ }
+ else
+ {
+ dst = src;
+ dstPos = srcLen;
+ }
+
+ md5_hash(dstHash, (Uint64*)dst, dstPos);
+
+ if(distr && noOfDistrKeys)
+ {
+ jam();
+ src = dst;
+ dstPos = 0;
+ Uint32 i = 0;
+ if(hasCharAttr)
+ {
+ while (i < noOfKeyAttr && noOfDistrKeys)
+ {
+ const TableRecord::KeyAttr& keyAttr = tabPtrP->keyAttr[i];
+ Uint32 len = keyPartLen[i];
+ if(AttributeDescriptor::getDKey(keyAttr.attributeDescriptor))
+ {
+ noOfDistrKeys--;
+ memmove(dst+dstPos, src, len << 2);
+ dstPos += len;
+ }
+ src += len;
+ i++;
+ }
+ }
+ else
+ {
+ while (i < noOfKeyAttr && noOfDistrKeys)
+ {
+ const TableRecord::KeyAttr& keyAttr = tabPtrP->keyAttr[i];
+ Uint32 len =
+ AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor);
+ len = (len + 3) / 4;
+ if(AttributeDescriptor::getDKey(keyAttr.attributeDescriptor))
+ {
+ noOfDistrKeys--;
+ memmove(dst+dstPos, src, len << 2);
+ dstPos += len;
+ }
+ src += len;
+ i++;
+ }
+ }
+ Uint32 tmp[4];
+ md5_hash(tmp, (Uint64*)dst, dstPos);
+ dstHash[1] = tmp[1];
+ }
+ return true; // success
+}
+
/*
INIT_API_CONNECT_REC
---------------------------
@@ -2667,18 +2823,13 @@ void Dbtc::execTCKEYREQ(Signal* signal)
Uint8 TSimpleFlag = tcKeyReq->getSimpleFlag(Treqinfo);
Uint8 TDirtyFlag = tcKeyReq->getDirtyFlag(Treqinfo);
Uint8 TInterpretedFlag = tcKeyReq->getInterpretedFlag(Treqinfo);
- Uint8 TDistrGroupFlag = tcKeyReq->getDistributionGroupFlag(Treqinfo);
- Uint8 TDistrGroupTypeFlag = tcKeyReq->getDistributionGroupTypeFlag(Treqinfo);
Uint8 TDistrKeyFlag = tcKeyReq->getDistributionKeyFlag(Treqinfo);
Uint8 TexecuteFlag = TexecFlag;
regCachePtr->opSimple = TSimpleFlag;
regCachePtr->opExec = TInterpretedFlag;
regTcPtr->dirtyOp = TDirtyFlag;
-
- regCachePtr->distributionGroupIndicator = TDistrGroupFlag;
- regCachePtr->distributionGroupType = TDistrGroupTypeFlag;
- regCachePtr->distributionKeyIndicator = TDistrKeyFlag;
+ regCachePtr->distributionKeyIndicator = TDistrKeyFlag;
//-------------------------------------------------------------
// The next step is to read the upto three conditional words.
@@ -2687,17 +2838,14 @@ void Dbtc::execTCKEYREQ(Signal* signal)
Uint32* TOptionalDataPtr = (Uint32*)&tcKeyReq->scanInfo;
{
Uint32 TDistrGHIndex = tcKeyReq->getScanIndFlag(Treqinfo);
- Uint32 TDistrKeyIndex = TDistrGHIndex + TDistrGroupFlag;
+ Uint32 TDistrKeyIndex = TDistrGHIndex;
- Uint32 TscanNode = tcKeyReq->getTakeOverScanNode(TOptionalDataPtr[0]);
Uint32 TscanInfo = tcKeyReq->getTakeOverScanInfo(TOptionalDataPtr[0]);
regCachePtr->scanTakeOverInd = TDistrGHIndex;
- regCachePtr->scanNode = TscanNode;
regCachePtr->scanInfo = TscanInfo;
- regCachePtr->distributionGroup = TOptionalDataPtr[TDistrGHIndex];
- regCachePtr->distributionKeySize = TOptionalDataPtr[TDistrKeyIndex];
+ regCachePtr->distributionKey = TOptionalDataPtr[TDistrKeyIndex];
TkeyIndex = TDistrKeyIndex + TDistrKeyFlag;
}
@@ -2731,7 +2879,8 @@ void Dbtc::execTCKEYREQ(Signal* signal)
regCachePtr->keylen = TkeyLength;
regCachePtr->lenAiInTckeyreq = titcLenAiInTckeyreq;
regCachePtr->currReclenAi = titcLenAiInTckeyreq;
-
+ regCachePtr->m_special_hash =
+ localTabptr.p->hasCharAttr | (localTabptr.p->noOfDistrKeys > 0);
Tdata1 = TAIDataPtr[0];
Tdata2 = TAIDataPtr[1];
Tdata3 = TAIDataPtr[2];
@@ -2934,6 +3083,15 @@ void Dbtc::tckeyreq050Lab(Signal* signal)
execDIGETNODESREF(signal);
return;
}
+
+ if(ERROR_INSERTED(8050) && signal->theData[3] != getOwnNodeId())
+ {
+ ndbassert(false);
+ signal->theData[1] = 626;
+ execDIGETNODESREF(signal);
+ return;
+ }
+
/****************>>*/
/* DIGETNODESCONF >*/
/* ***************>*/
@@ -2958,7 +3116,7 @@ void Dbtc::tckeyreq050Lab(Signal* signal)
tnoOfBackup = tnodeinfo & 3;
tnoOfStandby = (tnodeinfo >> 8) & 3;
- regCachePtr->distributionKey = (tnodeinfo >> 16) & 255;
+ regCachePtr->fragmentDistributionKey = (tnodeinfo >> 16) & 255;
if (Toperation == ZREAD) {
if (Tdirty == 1) {
jam();
@@ -3048,8 +3206,6 @@ void Dbtc::attrinfoDihReceivedLab(Signal* signal)
CacheRecord * const regCachePtr = cachePtr.p;
TcConnectRecord * const regTcPtr = tcConnectptr.p;
Uint16 Tnode = regTcPtr->tcNodedata[0];
- Uint16 TscanTakeOverInd = regCachePtr->scanTakeOverInd;
- Uint16 TscanNode = regCachePtr->scanNode;
TableRecordPtr localTabptr;
localTabptr.i = regCachePtr->tableref;
@@ -3062,11 +3218,6 @@ void Dbtc::attrinfoDihReceivedLab(Signal* signal)
TCKEY_abort(signal, 58);
return;
}
- if ((TscanTakeOverInd == 1) &&
- (Tnode != TscanNode)) {
- TCKEY_abort(signal, 15);
- return;
- }//if
arrGuard(Tnode, MAX_NDB_NODES);
packLqhkeyreq(signal, calcLqhBlockRef(Tnode));
}//Dbtc::attrinfoDihReceivedLab()
@@ -3128,7 +3279,7 @@ void Dbtc::sendlqhkeyreq(Signal* signal,
/* ---------------------------------------------------------------------- */
// Bit16 == 0 since StoredProcedures are not yet supported.
/* ---------------------------------------------------------------------- */
- LqhKeyReq::setDistributionKey(tslrAttrLen, regCachePtr->distributionKey);
+ LqhKeyReq::setDistributionKey(tslrAttrLen, regCachePtr->fragmentDistributionKey);
LqhKeyReq::setScanTakeOverFlag(tslrAttrLen, regCachePtr->scanTakeOverInd);
Tdata10 = 0;
@@ -8486,7 +8637,7 @@ void Dbtc::systemErrorLab(Signal* signal)
void Dbtc::execSCAN_TABREQ(Signal* signal)
{
const ScanTabReq * const scanTabReq = (ScanTabReq *)&signal->theData[0];
- const Uint32 reqinfo = scanTabReq->requestInfo;
+ const Uint32 ri = scanTabReq->requestInfo;
const Uint32 aiLength = (scanTabReq->attrLenKeyLen & 0xFFFF);
const Uint32 keyLen = scanTabReq->attrLenKeyLen >> 16;
const Uint32 schemaVersion = scanTabReq->tableSchemaVersion;
@@ -8496,8 +8647,8 @@ void Dbtc::execSCAN_TABREQ(Signal* signal)
const Uint32 buddyPtr = (tmpXX == 0xFFFFFFFF ? RNIL : tmpXX);
Uint32 currSavePointId = 0;
- Uint32 scanConcurrency = scanTabReq->getParallelism(reqinfo);
- Uint32 noOprecPerFrag = ScanTabReq::getScanBatch(reqinfo);
+ Uint32 scanConcurrency = scanTabReq->getParallelism(ri);
+ Uint32 noOprecPerFrag = ScanTabReq::getScanBatch(ri);
Uint32 scanParallel = scanConcurrency;
Uint32 errCode;
ScanRecordPtr scanptr;
@@ -8581,6 +8732,8 @@ void Dbtc::execSCAN_TABREQ(Signal* signal)
seizeCacheRecord(signal);
cachePtr.p->keylen = keyLen;
cachePtr.p->save1 = 0;
+ cachePtr.p->distributionKey = scanTabReq->distributionKey;
+ cachePtr.p->distributionKeyIndicator= ScanTabReq::getDistributionKeyFlag(ri);
scanptr = seizeScanrec(signal);
ndbrequire(transP->apiScanRec == RNIL);
@@ -8667,6 +8820,7 @@ void Dbtc::initScanrec(ScanRecordPtr scanptr,
UintR scanParallel,
UintR noOprecPerFrag)
{
+ const UintR ri = scanTabReq->requestInfo;
scanptr.p->scanTcrec = tcConnectptr.i;
scanptr.p->scanApiRec = apiConnectptr.i;
scanptr.p->scanAiLength = scanTabReq->attrLenKeyLen & 0xFFFF;
@@ -8679,12 +8833,12 @@ void Dbtc::initScanrec(ScanRecordPtr scanptr,
scanptr.p->batch_size_rows = noOprecPerFrag;
Uint32 tmp = 0;
- const UintR ri = scanTabReq->requestInfo;
ScanFragReq::setLockMode(tmp, ScanTabReq::getLockMode(ri));
ScanFragReq::setHoldLockFlag(tmp, ScanTabReq::getHoldLockFlag(ri));
ScanFragReq::setKeyinfoFlag(tmp, ScanTabReq::getKeyinfoFlag(ri));
ScanFragReq::setReadCommittedFlag(tmp,ScanTabReq::getReadCommittedFlag(ri));
ScanFragReq::setRangeScanFlag(tmp, ScanTabReq::getRangeScanFlag(ri));
+ ScanFragReq::setDescendingFlag(tmp, ScanTabReq::getDescendingFlag(ri));
ScanFragReq::setAttrLen(tmp, scanTabReq->attrLenKeyLen & 0xFFFF);
scanptr.p->scanRequestInfo = tmp;
@@ -8794,14 +8948,43 @@ void Dbtc::diFcountReqLab(Signal* signal, ScanRecordPtr scanptr)
return;
}
+ scanptr.p->scanNextFragId = 0;
+ scanptr.p->m_booked_fragments_count= 0;
scanptr.p->scanState = ScanRecord::WAIT_FRAGMENT_COUNT;
- /*************************************************
- * THE FIRST STEP TO RECEIVE IS SUCCESSFULLY COMPLETED.
- * WE MUST FIRST GET THE NUMBER OF FRAGMENTS IN THE TABLE.
- ***************************************************/
- signal->theData[0] = tcConnectptr.p->dihConnectptr;
- signal->theData[1] = scanptr.p->scanTableref;
- sendSignal(cdihblockref, GSN_DI_FCOUNTREQ, signal, 2, JBB);
+
+ if(!cachePtr.p->distributionKeyIndicator)
+ {
+ jam();
+ /*************************************************
+ * THE FIRST STEP TO RECEIVE IS SUCCESSFULLY COMPLETED.
+ * WE MUST FIRST GET THE NUMBER OF FRAGMENTS IN THE TABLE.
+ ***************************************************/
+ signal->theData[0] = tcConnectptr.p->dihConnectptr;
+ signal->theData[1] = scanptr.p->scanTableref;
+ sendSignal(cdihblockref, GSN_DI_FCOUNTREQ, signal, 2, JBB);
+ }
+ else
+ {
+ signal->theData[0] = tcConnectptr.p->dihConnectptr;
+ signal->theData[1] = tabPtr.i;
+ signal->theData[2] = cachePtr.p->distributionKey;
+ EXECUTE_DIRECT(DBDIH, GSN_DIGETNODESREQ, signal, 3);
+ UintR TerrorIndicator = signal->theData[0];
+ jamEntry();
+ if (TerrorIndicator != 0) {
+ signal->theData[0] = tcConnectptr.i;
+ //signal->theData[1] Contains error
+ execDI_FCOUNTREF(signal);
+ return;
+ }
+
+ UintR Tdata1 = signal->theData[1];
+ scanptr.p->scanNextFragId = Tdata1;
+
+ signal->theData[0] = tcConnectptr.i;
+ signal->theData[1] = 1; // Frag count
+ execDI_FCOUNTCONF(signal);
+ }
return;
}//Dbtc::diFcountReqLab()
@@ -8818,7 +9001,7 @@ void Dbtc::execDI_FCOUNTCONF(Signal* signal)
{
jamEntry();
tcConnectptr.i = signal->theData[0];
- const UintR tfragCount = signal->theData[1];
+ Uint32 tfragCount = signal->theData[1];
ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord);
apiConnectptr.i = tcConnectptr.p->apiConnect;
ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord);
@@ -8852,24 +9035,17 @@ void Dbtc::execDI_FCOUNTCONF(Signal* signal)
return;
}
- if(scanptr.p->scanParallel > tfragCount){
- jam();
- abortScanLab(signal, scanptr, ZTOO_HIGH_CONCURRENCY_ERROR);
- return;
- }
-
scanptr.p->scanParallel = tfragCount;
scanptr.p->scanNoFrag = tfragCount;
- scanptr.p->scanNextFragId = 0;
scanptr.p->scanState = ScanRecord::RUNNING;
setApiConTimer(apiConnectptr.i, 0, __LINE__);
updateBuddyTimer(apiConnectptr);
ScanFragRecPtr ptr;
- ScanFragList list(c_scan_frag_pool,
- scanptr.p->m_running_scan_frags);
- for (list.first(ptr); !ptr.isNull(); list.next(ptr)){
+ ScanFragList list(c_scan_frag_pool, scanptr.p->m_running_scan_frags);
+ for (list.first(ptr); !ptr.isNull() && tfragCount;
+ list.next(ptr), tfragCount--){
jam();
ptr.p->lqhBlockref = 0;
@@ -8884,6 +9060,22 @@ void Dbtc::execDI_FCOUNTCONF(Signal* signal)
signal->theData[3] = ptr.p->scanFragId;
sendSignal(cdihblockref, GSN_DIGETPRIMREQ, signal, 4, JBB);
}//for
+
+ ScanFragList queued(c_scan_frag_pool, scanptr.p->m_queued_scan_frags);
+ for (; !ptr.isNull();)
+ {
+ ptr.p->m_ops = 0;
+ ptr.p->m_totalLen = 0;
+ ptr.p->m_scan_frag_conf_status = 1;
+ ptr.p->scanFragState = ScanFragRec::QUEUED_FOR_DELIVERY;
+ ptr.p->stopFragTimer();
+
+ ScanFragRecPtr tmp = ptr;
+ list.next(ptr);
+ list.remove(tmp);
+ queued.add(tmp);
+ scanptr.p->m_queued_count++;
+ }
}//Dbtc::execDI_FCOUNTCONF()
/******************************************************
@@ -9234,7 +9426,7 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal)
}
if(noCompletedOps == 0 && status != 0 &&
- scanptr.p->scanNextFragId < scanptr.p->scanNoFrag){
+ scanptr.p->scanNextFragId+scanptr.p->m_booked_fragments_count < scanptr.p->scanNoFrag){
/**
* Start on next fragment
*/
@@ -9404,6 +9596,9 @@ void Dbtc::execSCAN_NEXTREQ(Signal* signal)
*/
jam();
ndbrequire(scanptr.p->scanNextFragId < scanptr.p->scanNoFrag);
+ jam();
+ ndbassert(scanptr.p->m_booked_fragments_count);
+ scanptr.p->m_booked_fragments_count--;
scanFragptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF;
tcConnectptr.i = scanptr.p->scanTcrec;
@@ -9645,8 +9840,9 @@ void Dbtc::sendScanTabConf(Signal* signal, ScanRecordPtr scanPtr) {
jam();
ops += 21;
}
-
- Uint32 left = scanPtr.p->scanNoFrag - scanPtr.p->scanNextFragId;
+
+ int left = scanPtr.p->scanNoFrag - scanPtr.p->scanNextFragId;
+ Uint32 booked = scanPtr.p->m_booked_fragments_count;
ScanTabConf * conf = (ScanTabConf*)&signal->theData[0];
conf->apiConnectPtr = apiConnectptr.p->ndbapiConnect;
@@ -9662,8 +9858,10 @@ void Dbtc::sendScanTabConf(Signal* signal, ScanRecordPtr scanPtr) {
ScanFragRecPtr curr = ptr; // Remove while iterating...
queued.next(ptr);
- bool done = curr.p->m_scan_frag_conf_status && --left;
-
+ bool done = curr.p->m_scan_frag_conf_status && (left <= (int)booked);
+ if(curr.p->m_scan_frag_conf_status)
+ booked++;
+
* ops++ = curr.p->m_apiPtr;
* ops++ = done ? RNIL : curr.i;
* ops++ = (curr.p->m_totalLen << 10) + curr.p->m_ops;
@@ -9681,8 +9879,10 @@ void Dbtc::sendScanTabConf(Signal* signal, ScanRecordPtr scanPtr) {
}
}
+ scanPtr.p->m_booked_fragments_count = booked;
if(scanPtr.p->m_delivered_scan_frags.isEmpty() &&
- scanPtr.p->m_running_scan_frags.isEmpty()){
+ scanPtr.p->m_running_scan_frags.isEmpty())
+ {
conf->requestInfo = op_count | ScanTabConf::EndOfData;
releaseScanResources(scanPtr);
}
@@ -9994,6 +10194,13 @@ void Dbtc::initTable(Signal* signal)
tabptr.p->tableType = 0;
tabptr.p->enabled = false;
tabptr.p->dropping = false;
+ tabptr.p->noOfKeyAttr = 0;
+ tabptr.p->hasCharAttr = 0;
+ tabptr.p->noOfDistrKeys = 0;
+ for (unsigned k = 0; k < MAX_ATTRIBUTES_IN_INDEX; k++) {
+ tabptr.p->keyAttr[k].attributeDescriptor = 0;
+ tabptr.p->keyAttr[k].charsetInfo = 0;
+ }
}//for
}//Dbtc::initTable()
@@ -11134,7 +11341,7 @@ void Dbtc::execTCINDXREQ(Signal* signal)
{
jamEntry();
- TcIndxReq * const tcIndxReq = (TcIndxReq *)signal->getDataPtr();
+ TcKeyReq * const tcIndxReq = (TcKeyReq *)signal->getDataPtr();
const UintR TapiIndex = tcIndxReq->apiConnectPtr;
Uint32 tcIndxRequestInfo = tcIndxReq->requestInfo;
Uint32 startFlag = tcIndxReq->getStartFlag(tcIndxRequestInfo);
@@ -11165,14 +11372,14 @@ void Dbtc::execTCINDXREQ(Signal* signal)
if (!seizeIndexOperation(regApiPtr, indexOpPtr)) {
jam();
// Failed to allocate index operation
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
tcIndxRef->connectPtr = tcIndxReq->senderData;
tcIndxRef->transId[0] = regApiPtr->transid[0];
tcIndxRef->transId[1] = regApiPtr->transid[1];
tcIndxRef->errorCode = 4000;
sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcIndxRef::SignalLength, JBB);
+ TcKeyRef::SignalLength, JBB);
return;
}
TcIndexOperation* indexOp = indexOpPtr.p;
@@ -11185,7 +11392,7 @@ void Dbtc::execTCINDXREQ(Signal* signal)
// If operation is readTupleExclusive or updateTuple then read index
// table with exclusive lock
- Uint32 indexLength = TcIndxReq::getIndexLength(tcIndxRequestInfo);
+ Uint32 indexLength = TcKeyReq::getKeyLength(tcIndxRequestInfo);
Uint32 attrLength = tcIndxReq->attrLen;
indexOp->expectedKeyInfo = indexLength;
Uint32 includedIndexLength = MIN(indexLength, indexBufSize);
@@ -11486,14 +11693,14 @@ void Dbtc::execTCKEYCONF(Signal* signal)
case(IOS_NOOP): {
jam();
// Should never happen, abort
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
tcIndxRef->transId[0] = regApiPtr->transid[0];
tcIndxRef->transId[1] = regApiPtr->transid[1];
tcIndxRef->errorCode = 4349;
sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcIndxRef::SignalLength, JBB);
+ TcKeyRef::SignalLength, JBB);
return;
}
case(IOS_INDEX_ACCESS): {
@@ -11505,14 +11712,14 @@ void Dbtc::execTCKEYCONF(Signal* signal)
case(IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI): {
jam();
// Double TCKEYCONF, should never happen, abort
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
tcIndxRef->transId[0] = regApiPtr->transid[0];
tcIndxRef->transId[1] = regApiPtr->transid[1];
tcIndxRef->errorCode = 4349;
sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcIndxRef::SignalLength, JBB);
+ TcKeyRef::SignalLength, JBB);
return;
}
case(IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF): {
@@ -11598,8 +11805,8 @@ void Dbtc::execTCKEYREF(Signal* signal)
// Send TCINDXREF
jam();
- TcIndxReq * const tcIndxReq = &indexOp->tcIndxReq;
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyReq * const tcIndxReq = &indexOp->tcIndxReq;
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
ndbassert(regApiPtr->noIndexOp);
regApiPtr->noIndexOp--; // Decrease count
@@ -11608,7 +11815,7 @@ void Dbtc::execTCKEYREF(Signal* signal)
tcIndxRef->transId[1] = tcKeyRef->transId[1];
tcIndxRef->errorCode = tcKeyRef->errorCode;
sendSignal(regApiPtr->ndbapiBlockref,
- GSN_TCINDXREF, signal, TcIndxRef::SignalLength, JBB);
+ GSN_TCINDXREF, signal, TcKeyRef::SignalLength, JBB);
return;
}
}
@@ -11675,14 +11882,14 @@ void Dbtc::execTRANSID_AI(Signal* signal)
signal->getLength() - TransIdAI::HeaderLength)) {
jam();
// Failed to allocate space for TransIdAI
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
tcIndxRef->transId[0] = regApiPtr->transid[0];
tcIndxRef->transId[1] = regApiPtr->transid[1];
tcIndxRef->errorCode = 4000;
sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcIndxRef::SignalLength, JBB);
+ TcKeyRef::SignalLength, JBB);
return;
}
@@ -11690,14 +11897,14 @@ void Dbtc::execTRANSID_AI(Signal* signal)
case(IOS_NOOP): {
jam();
// Should never happen, abort
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
tcIndxRef->transId[0] = regApiPtr->transid[0];
tcIndxRef->transId[1] = regApiPtr->transid[1];
tcIndxRef->errorCode = 4349;
sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcIndxRef::SignalLength, JBB);
+ TcKeyRef::SignalLength, JBB);
return;
break;
}
@@ -11718,14 +11925,14 @@ void Dbtc::execTRANSID_AI(Signal* signal)
#endif
/*
// Too many TRANSID_AI
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
tcIndexRef->connectPtr = indexOp->tcIndxReq.senderData;
tcIndxRef->transId[0] = regApiPtr->transid[0];
tcIndxRef->transId[1] = regApiPtr->transid[1];
tcIndxRef->errorCode = 4349;
sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcIndxRef::SignalLength, JBB);
+ TcKeyRef::SignalLength, JBB);
*/
break;
}
@@ -11743,14 +11950,14 @@ void Dbtc::execTRANSID_AI(Signal* signal)
case(IOS_INDEX_OPERATION): {
// Should never receive TRANSID_AI in this state!!
jam();
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
tcIndxRef->transId[0] = regApiPtr->transid[0];
tcIndxRef->transId[1] = regApiPtr->transid[1];
tcIndxRef->errorCode = 4349;
sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcIndxRef::SignalLength, JBB);
+ TcKeyRef::SignalLength, JBB);
return;
}
}
@@ -11793,24 +12000,24 @@ void Dbtc::readIndexTable(Signal* signal,
(Operation_t)TcKeyReq::getOperationType(tcKeyRequestInfo);
// Find index table
- if ((indexData = c_theIndexes.getPtr(indexOp->tcIndxReq.indexId)) == NULL) {
+ if ((indexData = c_theIndexes.getPtr(indexOp->tcIndxReq.tableId)) == NULL) {
jam();
// Failed to find index record
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
tcIndxRef->transId[0] = regApiPtr->transid[0];
tcIndxRef->transId[1] = regApiPtr->transid[1];
tcIndxRef->errorCode = 4000;
sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcIndxRef::SignalLength, JBB);
+ TcKeyRef::SignalLength, JBB);
return;
}
tcKeyReq->transId1 = transId1;
tcKeyReq->transId2 = transId2;
tcKeyReq->tableId = indexData->indexId;
tcKeyLength += MIN(keyLength, keyBufSize);
- tcKeyReq->tableSchemaVersion = indexOp->tcIndxReq.indexSchemaVersion;
+ tcKeyReq->tableSchemaVersion = indexOp->tcIndxReq.tableSchemaVersion;
TcKeyReq::setOperationType(tcKeyRequestInfo,
opType == ZREAD ? ZREAD : ZREAD_EX);
TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 1); // Allways send one AttrInfo
@@ -11902,7 +12109,7 @@ void Dbtc::executeIndexOperation(Signal* signal,
Uint32 keyBufSize = 8; // Maximum for key in TCKEYREQ
Uint32 attrBufSize = 5;
Uint32 dataPos = 0;
- TcIndxReq * const tcIndxReq = &indexOp->tcIndxReq;
+ TcKeyReq * const tcIndxReq = &indexOp->tcIndxReq;
TcKeyReq * const tcKeyReq = (TcKeyReq *)signal->getDataPtrSend();
Uint32 * dataPtr = &tcKeyReq->scanInfo;
Uint32 tcKeyLength = TcKeyReq::StaticLength;
@@ -11913,17 +12120,17 @@ void Dbtc::executeIndexOperation(Signal* signal,
bool moreKeyData = indexOp->transIdAI.first(aiIter);
// Find index table
- if ((indexData = c_theIndexes.getPtr(tcIndxReq->indexId)) == NULL) {
+ if ((indexData = c_theIndexes.getPtr(tcIndxReq->tableId)) == NULL) {
jam();
// Failed to find index record
- TcIndxRef * const tcIndxRef = (TcIndxRef *)signal->getDataPtrSend();
+ TcKeyRef * const tcIndxRef = (TcKeyRef *)signal->getDataPtrSend();
tcIndxRef->connectPtr = indexOp->tcIndxReq.senderData;
tcIndxRef->transId[0] = regApiPtr->transid[0];
tcIndxRef->transId[1] = regApiPtr->transid[1];
tcIndxRef->errorCode = 4349;
sendSignal(regApiPtr->ndbapiBlockref, GSN_TCINDXREF, signal,
- TcIndxRef::SignalLength, JBB);
+ TcKeyRef::SignalLength, JBB);
return;
}
// Find schema version of primary table
diff --git a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
index 06cfd420eac..a0103f56add 100644
--- a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
+++ b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
@@ -207,6 +207,8 @@
#define ZTUPLE_DELETED_ERROR 626
#define ZINSERT_ERROR 630
+#define ZINVALID_CHAR_FORMAT 744
+
/* SOME WORD POSITIONS OF FIELDS IN SOME HEADERS */
#define ZPAGE_STATE_POS 0 /* POSITION OF PAGE STATE */
@@ -500,7 +502,8 @@ struct Fragoperrec {
Uint32 tableidFrag;
Uint32 fragPointer;
Uint32 attributeCount;
- Uint32 freeNullBit;
+ Uint32 currNullBit;
+ Uint32 noOfNullBits;
Uint32 noOfNewAttrCount;
Uint32 charsetIndex;
BlockReference lqhBlockrefFrag;
@@ -1019,7 +1022,14 @@ public:
* for md5 summing and when returning keyinfo. Returns number of
* words or negative (-terrorCode) on error.
*/
- int tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* dataOut);
+ int tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* dataOut, bool xfrmFlag);
+
+ /*
+ * ACC reads primary key without headers into an array of words. At
+ * this point in ACC deconstruction, ACC still uses logical references
+ * to fragment and tuple.
+ */
+ int accReadPk(Uint32 tableId, Uint32 fragId, Uint32 fragPageId, Uint32 pageIndex, Uint32* dataOut, bool xfrmFlag);
/*
* TUX checks if tuple is visible to scan.
@@ -1623,19 +1633,11 @@ private:
Uint32 attrDescriptor,
Uint32 attrDes2);
-// *****************************************************************
-// Read char routines optionally (tXfrmFlag) apply strxfrm
-// *****************************************************************
-
- bool readCharNotNULL(Uint32* outBuffer,
- AttributeHeader* ahOut,
- Uint32 attrDescriptor,
- Uint32 attrDes2);
- bool readCharNULLable(Uint32* outBuffer,
- AttributeHeader* ahOut,
- Uint32 attrDescriptor,
- Uint32 attrDes2);
+ bool readBitsNULLable(Uint32* outBuffer, AttributeHeader*, Uint32, Uint32);
+ bool updateBitsNULLable(Uint32* inBuffer, Uint32, Uint32);
+ bool readBitsNotNULL(Uint32* outBuffer, AttributeHeader*, Uint32, Uint32);
+ bool updateBitsNotNULL(Uint32* inBuffer, Uint32, Uint32);
//------------------------------------------------------------------
//------------------------------------------------------------------
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp b/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp
index 808cfd33696..8c43de52a75 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp
@@ -68,7 +68,7 @@ struct Chunk {
void
Dbtup::reportMemoryUsage(Signal* signal, int incDec){
- signal->theData[0] = EventReport::MemoryUsage;
+ signal->theData[0] = NDB_LE_MemoryUsage;
signal->theData[1] = incDec;
signal->theData[2] = sizeof(Page);
signal->theData[3] = cnoOfAllocatedPages;
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
index 8e3ca6528c2..761f959acdc 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
@@ -858,6 +858,8 @@ void Dbtup::sendTUPKEYCONF(Signal* signal,
return;
}//Dbtup::sendTUPKEYCONF()
+#define MAX_READ (sizeof(signal->theData) > MAX_MESSAGE_SIZE ? MAX_MESSAGE_SIZE : sizeof(signal->theData))
+
/* ---------------------------------------------------------------- */
/* ----------------------------- READ ---------------------------- */
/* ---------------------------------------------------------------- */
@@ -878,7 +880,7 @@ int Dbtup::handleReadReq(Signal* signal,
}//if
Uint32 * dst = &signal->theData[25];
- Uint32 dstLen = (sizeof(signal->theData) / 4) - 25;
+ Uint32 dstLen = (MAX_READ / 4) - 25;
const Uint32 node = refToNode(sendBref);
if(node != 0 && node != getOwnNodeId()) {
;
@@ -888,7 +890,7 @@ int Dbtup::handleReadReq(Signal* signal,
* execute direct
*/
dst = &signal->theData[3];
- dstLen = (sizeof(signal->theData) / 4) - 3;
+ dstLen = (MAX_READ / 4) - 3;
}
if (regOperPtr->interpretedExec != 1) {
@@ -1228,7 +1230,7 @@ int Dbtup::interpreterStartLab(Signal* signal,
const BlockReference sendBref = regOperPtr->recBlockref;
Uint32 * dst = &signal->theData[25];
- Uint32 dstLen = (sizeof(signal->theData) / 4) - 25;
+ Uint32 dstLen = (MAX_READ / 4) - 25;
const Uint32 node = refToNode(sendBref);
if(node != 0 && node != getOwnNodeId()) {
;
@@ -1238,7 +1240,7 @@ int Dbtup::interpreterStartLab(Signal* signal,
* execute direct
*/
dst = &signal->theData[3];
- dstLen = (sizeof(signal->theData) / 4) - 3;
+ dstLen = (MAX_READ / 4) - 3;
}
RtotalLen = RinitReadLen;
@@ -1538,13 +1540,8 @@ int Dbtup::interpreterNextLab(Signal* signal,
// Calculate the number of words of this attribute.
// We allow writes into arrays as long as they fit into the 64 bit
// register size.
- //TEST_MR See to that TattrNoOfWords can be
- // read faster from attribute description.
/* --------------------------------------------------------------- */
- Uint32 TarraySize = (TattrDesc1 >> 16);
- Uint32 TattrLogLen = (TattrDesc1 >> 4) & 0xf;
- Uint32 TattrNoOfBits = TarraySize << TattrLogLen;
- Uint32 TattrNoOfWords = (TattrNoOfBits + 31) >> 5;
+ Uint32 TattrNoOfWords = AttributeDescriptor::getSizeInWords(TattrDesc1);
Uint32 Toptype = operPtr.p->optype;
Uint32 TdataForUpdate[3];
@@ -1821,9 +1818,6 @@ int Dbtup::interpreterNextLab(Signal* signal,
case Interpreter::BRANCH_ATTR_OP_ARG:{
jam();
Uint32 cond = Interpreter::getBinaryCondition(theInstruction);
- Uint32 diff = Interpreter::getArrayLengthDiff(theInstruction);
- Uint32 vchr = Interpreter::isVarchar(theInstruction);
- Uint32 nopad =Interpreter::isNopad(theInstruction);
Uint32 ins2 = TcurrentProgram[TprogramCounter];
Uint32 attrId = Interpreter::getBranchCol_AttrId(ins2) << 16;
Uint32 argLen = Interpreter::getBranchCol_Len(ins2);
@@ -1842,84 +1836,93 @@ int Dbtup::interpreterNextLab(Signal* signal,
}
tmpHabitant = attrId;
}
-
- AttributeHeader ah(tmpArea[0]);
+ // get type
+ attrId >>= 16;
+ Uint32 TattrDescrIndex = tabptr.p->tabDescriptor +
+ (attrId << ZAD_LOG_SIZE);
+ Uint32 TattrDesc1 = tableDescriptor[TattrDescrIndex].tabDescr;
+ Uint32 TattrDesc2 = tableDescriptor[TattrDescrIndex+1].tabDescr;
+ Uint32 typeId = AttributeDescriptor::getType(TattrDesc1);
+ void * cs = 0;
+ if(AttributeOffset::getCharsetFlag(TattrDesc2))
+ {
+ Uint32 pos = AttributeOffset::getCharsetPos(TattrDesc2);
+ cs = tabptr.p->charsetArray[pos];
+ }
+ const NdbSqlUtil::Type& sqlType = NdbSqlUtil::getType(typeId);
+
+ // get data
+ AttributeHeader ah(tmpArea[0]);
const char* s1 = (char*)&tmpArea[1];
const char* s2 = (char*)&TcurrentProgram[TprogramCounter+1];
- Uint32 attrLen = (4 * ah.getDataSize()) - diff;
- if (vchr) {
-#if NDB_VERSION_MAJOR >= 3
- bool vok = false;
- if (attrLen >= 2) {
- Uint32 vlen = (s1[0] << 8) | s1[1]; // big-endian
- s1 += 2;
- attrLen -= 2;
- if (attrLen >= vlen) {
- attrLen = vlen;
- vok = true;
- }
+ // fixed length in 5.0
+ Uint32 attrLen = AttributeDescriptor::getSizeInBytes(TattrDesc1);
+
+ bool r1_null = ah.isNULL();
+ bool r2_null = argLen == 0;
+ int res1;
+ if (cond != Interpreter::LIKE &&
+ cond != Interpreter::NOT_LIKE) {
+ if (r1_null || r2_null) {
+ // NULL==NULL and NULL<not-NULL
+ res1 = r1_null && r2_null ? 0 : r1_null ? -1 : 1;
+ } else {
+ res1 = (*sqlType.m_cmp)(cs, s1, attrLen, s2, argLen, true);
}
- if (!vok) {
- terrorCode = ZREGISTER_INIT_ERROR;
- tupkeyErrorLab(signal);
- return -1;
- }
-#else
- Uint32 tmp;
- if (attrLen >= 2) {
- unsigned char* ss = (unsigned char*)&s1[attrLen - 2];
- tmp = (ss[0] << 8) | ss[1];
- if (tmp <= attrLen - 2)
- attrLen = tmp;
+ } else {
+ if (r1_null || r2_null) {
+ // NULL like NULL is true (has no practical use)
+ res1 = r1_null && r2_null ? 0 : -1;
+ } else {
+ res1 = (*sqlType.m_like)(cs, s1, attrLen, s2, argLen);
}
- // XXX handle bad data
-#endif
}
- bool res = false;
+ int res = 0;
switch ((Interpreter::BinaryCondition)cond) {
case Interpreter::EQ:
- res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) == 0;
+ res = (res1 == 0);
break;
case Interpreter::NE:
- res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) != 0;
+ res = (res1 != 0);
break;
// note the condition is backwards
case Interpreter::LT:
- res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) > 0;
+ res = (res1 > 0);
break;
case Interpreter::LE:
- res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) >= 0;
+ res = (res1 >= 0);
break;
case Interpreter::GT:
- res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) < 0;
+ res = (res1 < 0);
break;
case Interpreter::GE:
- res = NdbSqlUtil::char_compare(s1, attrLen, s2, argLen, !nopad) <= 0;
+ res = (res1 <= 0);
break;
case Interpreter::LIKE:
- res = NdbSqlUtil::char_like(s1, attrLen, s2, argLen, !nopad);
+ res = (res1 == 0);
break;
case Interpreter::NOT_LIKE:
- res = ! NdbSqlUtil::char_like(s1, attrLen, s2, argLen, !nopad);
+ res = (res1 == 1);
break;
- // XXX handle invalid value
+ // XXX handle invalid value
}
#ifdef TRACE_INTERPRETER
- ndbout_c("cond=%u diff=%d vc=%d nopad=%d attr(%d) = >%.*s<(%d) str=>%.*s<(%d) -> res = %d",
- cond, diff, vchr, nopad,
- attrId >> 16, attrLen, s1, attrLen, argLen, s2, argLen, res);
+ ndbout_c("cond=%u attr(%d)='%.*s'(%d) str='%.*s'(%d) res1=%d res=%d",
+ cond, attrId >> 16,
+ attrLen, s1, attrLen, argLen, s2, argLen, res1, res);
#endif
if (res)
TprogramCounter = brancher(theInstruction, TprogramCounter);
- else {
- Uint32 tmp = (Interpreter::mod4(argLen) >> 2) + 1;
+ else
+ {
+ Uint32 tmp = ((argLen + 3) >> 2) + 1;
TprogramCounter += tmp;
}
break;
}
-
+
case Interpreter::BRANCH_ATTR_EQ_NULL:{
jam();
Uint32 ins2 = TcurrentProgram[TprogramCounter];
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp b/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
index 5a8642c4d2e..ab6e0642e11 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
@@ -173,7 +173,7 @@ Dbtup::tuxReadAttrs(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32 tu
}
int
-Dbtup::tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* dataOut)
+Dbtup::tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* dataOut, bool xfrmFlag)
{
ljamEntry();
// use own variables instead of globals
@@ -200,8 +200,7 @@ Dbtup::tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* data
operPtr.i = RNIL;
operPtr.p = NULL;
// do it
- int ret = readAttributes(pagePtr.p, pageOffset, attrIds,
- numAttrs, dataOut, ZNIL, true);
+ int ret = readAttributes(pagePtr.p, pageOffset, attrIds, numAttrs, dataOut, ZNIL, xfrmFlag);
// restore globals
tabptr = tabptr_old;
fragptr = fragptr_old;
@@ -229,6 +228,27 @@ Dbtup::tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* data
return ret;
}
+int
+Dbtup::accReadPk(Uint32 tableId, Uint32 fragId, Uint32 fragPageId, Uint32 pageIndex, Uint32* dataOut, bool xfrmFlag)
+{
+ ljamEntry();
+ // get table
+ TablerecPtr tablePtr;
+ tablePtr.i = tableId;
+ ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
+ // get fragment
+ FragrecordPtr fragPtr;
+ getFragmentrec(fragPtr, fragId, tablePtr.p);
+ // get real page id and tuple offset
+ PagePtr pagePtr;
+ Uint32 pageId = getRealpid(fragPtr.p, fragPageId);
+ ndbrequire((pageIndex & 0x1) == 0);
+ Uint32 pageOffset = ZPAGE_HEADER_SIZE + (pageIndex >> 1) * tablePtr.p->tupheadsize;
+ // use TUX routine - optimize later
+ int ret = tuxReadPk(fragPtr.i, pageId, pageOffset, dataOut, xfrmFlag);
+ return ret;
+}
+
bool
Dbtup::tuxQueryTh(Uint32 fragPtrI, Uint32 tupAddr, Uint32 tupVersion, Uint32 transId1, Uint32 transId2, Uint32 savePointId)
{
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp b/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
index 405f790954e..4ce807528c4 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
@@ -96,9 +96,10 @@ void Dbtup::execTUPFRAGREQ(Signal* signal)
fragOperPtr.p->fragidFrag = fragId;
fragOperPtr.p->tableidFrag = regTabPtr.i;
fragOperPtr.p->attributeCount = noOfAttributes;
- fragOperPtr.p->freeNullBit = noOfNullAttr;
+ fragOperPtr.p->noOfNullBits = noOfNullAttr;
fragOperPtr.p->noOfNewAttrCount = noOfNewAttr;
fragOperPtr.p->charsetIndex = 0;
+ fragOperPtr.p->currNullBit = 0;
ndbrequire(reqinfo == ZADDFRAG);
@@ -287,8 +288,7 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal* signal)
ptrCheckGuard(fragOperPtr, cnoOfFragoprec, fragoperrec);
Uint32 attrId = signal->theData[2];
Uint32 attrDescriptor = signal->theData[3];
- // DICT sends extended type (ignored) and charset number
- Uint32 extType = (signal->theData[4] & 0xFF);
+ // DICT sends charset number in upper half
Uint32 csNumber = (signal->theData[4] >> 16);
regTabPtr.i = fragOperPtr.p->tableidFrag;
@@ -309,13 +309,13 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal* signal)
Uint32 firstTabDesIndex = regTabPtr.p->tabDescriptor + (attrId * ZAD_SIZE);
setTabDescrWord(firstTabDesIndex, attrDescriptor);
Uint32 attrLen = AttributeDescriptor::getSize(attrDescriptor);
- Uint32 nullBitPos = 0; /* Default pos for NOT NULL attributes */
+ Uint32 nullBitPos = fragOperPtr.p->currNullBit;
+ Uint32 bitCount = 0;
+
if (AttributeDescriptor::getNullable(attrDescriptor)) {
if (!AttributeDescriptor::getDynamic(attrDescriptor)) {
- ljam(); /* NULL ATTR */
- fragOperPtr.p->freeNullBit--; /* STORE NULL BIT POSTITION */
- nullBitPos = fragOperPtr.p->freeNullBit;
- ndbrequire(fragOperPtr.p->freeNullBit < ZNIL); /* Check not below zero */
+ ljam(); /* NULL ATTR */
+ fragOperPtr.p->currNullBit++;
}//if
} else {
ljam();
@@ -331,27 +331,40 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal* signal)
case 2:
{
ljam();
- Uint32 bitsUsed = AttributeDescriptor::getArraySize(attrDescriptor) * (1 << attrLen);
- regTabPtr.p->tupheadsize += ((bitsUsed + 31) >> 5);
- break;
+ if(attrLen != 0)
+ {
+ ljam();
+ Uint32 bitsUsed =
+ AttributeDescriptor::getArraySize(attrDescriptor) * (1 << attrLen);
+ regTabPtr.p->tupheadsize += ((bitsUsed + 31) >> 5);
+ break;
+ }
+ else
+ {
+ ljam();
+ bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+ fragOperPtr.p->currNullBit += bitCount;
+ break;
+ }
}
default:
ndbrequire(false);
break;
}//switch
+ if(nullBitPos + bitCount + 1 >= MAX_NULL_BITS)
+ {
+ terrorCode = TupAddAttrRef::TooManyBitsUsed;
+ addattrrefuseLab(signal, regFragPtr, fragOperPtr, regTabPtr.p, fragId);
+ return;
+ }
AttributeOffset::setOffset(attrDes2, attributePos);
AttributeOffset::setNullFlagPos(attrDes2, nullBitPos);
} else {
ndbrequire(false);
}//if
if (csNumber != 0) {
- CHARSET_INFO* cs = get_charset(csNumber, MYF(0));
- if (cs == NULL) {
- ljam();
- terrorCode = TupAddAttrRef::InvalidCharset;
- addattrrefuseLab(signal, regFragPtr, fragOperPtr, regTabPtr.p, fragId);
- return;
- }
+ CHARSET_INFO* cs = all_charsets[csNumber];
+ ndbrequire(cs != NULL);
Uint32 i = 0;
while (i < fragOperPtr.p->charsetIndex) {
ljam();
@@ -375,7 +388,9 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal* signal)
addattrrefuseLab(signal, regFragPtr, fragOperPtr, regTabPtr.p, fragId);
return;
}//if
- if (lastAttr && (fragOperPtr.p->freeNullBit != 0)) {
+ if (lastAttr &&
+ (fragOperPtr.p->currNullBit != fragOperPtr.p->noOfNullBits))
+ {
ljam();
terrorCode = ZINCONSISTENT_NULL_ATTRIBUTE_COUNT;
addattrrefuseLab(signal, regFragPtr, fragOperPtr, regTabPtr.p, fragId);
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp
index cbb165c3eb1..3170d23499a 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp
@@ -40,7 +40,11 @@ Dbtup::setUpQueryRoutines(Tablerec* const regTabPtr)
if ((AttributeDescriptor::getArrayType(attrDescriptor) == ZNON_ARRAY) ||
(AttributeDescriptor::getArrayType(attrDescriptor) == ZFIXED_ARRAY)) {
if (!AttributeDescriptor::getNullable(attrDescriptor)) {
- if (AttributeDescriptor::getSizeInWords(attrDescriptor) == 1) {
+ if (AttributeDescriptor::getSize(attrDescriptor) == 0){
+ ljam();
+ regTabPtr->readFunctionArray[i] = &Dbtup::readBitsNotNULL;
+ regTabPtr->updateFunctionArray[i] = &Dbtup::updateBitsNotNULL;
+ } else if (AttributeDescriptor::getSizeInWords(attrDescriptor) == 1){
ljam();
regTabPtr->readFunctionArray[i] = &Dbtup::readFixedSizeTHOneWordNotNULL;
regTabPtr->updateFunctionArray[i] = &Dbtup::updateFixedSizeTHOneWordNotNULL;
@@ -55,13 +59,18 @@ Dbtup::setUpQueryRoutines(Tablerec* const regTabPtr)
} else {
ndbrequire(false);
}//if
- // replace read function of char attribute
+ // replace functions for char attribute
if (AttributeOffset::getCharsetFlag(attrOffset)) {
ljam();
- regTabPtr->readFunctionArray[i] = &Dbtup::readCharNotNULL;
+ regTabPtr->readFunctionArray[i] = &Dbtup::readFixedSizeTHManyWordNotNULL;
+ regTabPtr->updateFunctionArray[i] = &Dbtup::updateFixedSizeTHManyWordNotNULL;
}
} else {
- if (AttributeDescriptor::getSizeInWords(attrDescriptor) == 1) {
+ if (AttributeDescriptor::getSize(attrDescriptor) == 0){
+ ljam();
+ regTabPtr->readFunctionArray[i] = &Dbtup::readBitsNULLable;
+ regTabPtr->updateFunctionArray[i] = &Dbtup::updateBitsNULLable;
+ } else if (AttributeDescriptor::getSizeInWords(attrDescriptor) == 1){
ljam();
regTabPtr->readFunctionArray[i] = &Dbtup::readFixedSizeTHOneWordNULLable;
regTabPtr->updateFunctionArray[i] = &Dbtup::updateFixedSizeTHManyWordNULLable;
@@ -78,10 +87,11 @@ Dbtup::setUpQueryRoutines(Tablerec* const regTabPtr)
regTabPtr->readFunctionArray[i] = &Dbtup::readFixedSizeTHZeroWordNULLable;
regTabPtr->updateFunctionArray[i] = &Dbtup::updateFixedSizeTHManyWordNULLable;
}//if
- // replace read function of char attribute
+ // replace functions for char attribute
if (AttributeOffset::getCharsetFlag(attrOffset)) {
ljam();
- regTabPtr->readFunctionArray[i] = &Dbtup::readCharNULLable;
+ regTabPtr->readFunctionArray[i] = &Dbtup::readFixedSizeTHManyWordNULLable;
+ regTabPtr->updateFunctionArray[i] = &Dbtup::updateFixedSizeTHManyWordNULLable;
}
}//if
} else if (AttributeDescriptor::getArrayType(attrDescriptor) == ZVAR_ARRAY) {
@@ -329,25 +339,68 @@ Dbtup::readFixedSizeTHManyWordNotNULL(Uint32* outBuffer,
Uint32 attrDes2)
{
Uint32 indexBuf = tOutBufIndex;
+ Uint32 charsetFlag = AttributeOffset::getCharsetFlag(attrDes2);
Uint32 readOffset = AttributeOffset::getOffset(attrDes2);
Uint32 attrNoOfWords = AttributeDescriptor::getSizeInWords(attrDescriptor);
- Uint32 newIndexBuf = indexBuf + attrNoOfWords;
Uint32 maxRead = tMaxRead;
ndbrequire((readOffset + attrNoOfWords - 1) < tCheckOffset);
- if (newIndexBuf <= maxRead) {
- ljam();
- ahOut->setDataSize(attrNoOfWords);
- MEMCOPY_NO_WORDS(&outBuffer[indexBuf],
- &tTupleHeader[readOffset],
- attrNoOfWords);
- tOutBufIndex = newIndexBuf;
- return true;
+ if (! charsetFlag || ! tXfrmFlag) {
+ Uint32 newIndexBuf = indexBuf + attrNoOfWords;
+ if (newIndexBuf <= maxRead) {
+ ljam();
+ ahOut->setDataSize(attrNoOfWords);
+ MEMCOPY_NO_WORDS(&outBuffer[indexBuf],
+ &tTupleHeader[readOffset],
+ attrNoOfWords);
+ tOutBufIndex = newIndexBuf;
+ return true;
+ } else {
+ ljam();
+ terrorCode = ZTRY_TO_READ_TOO_MUCH_ERROR;
+ }//if
} else {
ljam();
- terrorCode = ZTRY_TO_READ_TOO_MUCH_ERROR;
- return false;
- }//if
+ Tablerec* regTabPtr = tabptr.p;
+ Uint32 srcBytes = AttributeDescriptor::getSizeInBytes(attrDescriptor);
+ uchar* dstPtr = (uchar*)&outBuffer[indexBuf];
+ const uchar* srcPtr = (uchar*)&tTupleHeader[readOffset];
+ Uint32 i = AttributeOffset::getCharsetPos(attrDes2);
+ ndbrequire(i < regTabPtr->noOfCharsets);
+ CHARSET_INFO* cs = regTabPtr->charsetArray[i];
+ Uint32 typeId = AttributeDescriptor::getType(attrDescriptor);
+ Uint32 lb, len;
+ bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len);
+ if (ok) {
+ Uint32 xmul = cs->strxfrm_multiply;
+ if (xmul == 0)
+ xmul = 1;
+ // see comment in DbtcMain.cpp
+ Uint32 dstLen = xmul * (srcBytes - lb);
+ Uint32 maxIndexBuf = indexBuf + (dstLen >> 2);
+ if (maxIndexBuf <= maxRead) {
+ ljam();
+ int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len);
+ ndbrequire(n != -1);
+ while ((n & 3) != 0) {
+ dstPtr[n++] = 0;
+ }
+ Uint32 dstWords = (n >> 2);
+ ahOut->setDataSize(dstWords);
+ Uint32 newIndexBuf = indexBuf + dstWords;
+ ndbrequire(newIndexBuf <= maxRead);
+ tOutBufIndex = newIndexBuf;
+ return true;
+ } else {
+ ljam();
+ terrorCode = ZTRY_TO_READ_TOO_MUCH_ERROR;
+ }
+ } else {
+ ljam();
+ terrorCode = ZTUPLE_CORRUPTED_ERROR;
+ }
+ }
+ return false;
}//Dbtup::readFixedSizeTHManyWordNotNULL()
bool
@@ -394,7 +447,6 @@ Dbtup::readFixedSizeTHManyWordNULLable(Uint32* outBuffer,
Uint32 attrDescriptor,
Uint32 attrDes2)
{
-ljam();
if (!nullFlagCheck(attrDes2)) {
ljam();
return readFixedSizeTHManyWordNotNULL(outBuffer,
@@ -555,74 +607,6 @@ Dbtup::readDynSmallVarSize(Uint32* outBuffer,
return false;
}//Dbtup::readDynSmallVarSize()
-
-bool
-Dbtup::readCharNotNULL(Uint32* outBuffer,
- AttributeHeader* ahOut,
- Uint32 attrDescriptor,
- Uint32 attrDes2)
-{
- Uint32 indexBuf = tOutBufIndex;
- Uint32 readOffset = AttributeOffset::getOffset(attrDes2);
- Uint32 attrNoOfWords = AttributeDescriptor::getSizeInWords(attrDescriptor);
- Uint32 newIndexBuf = indexBuf + attrNoOfWords;
- Uint32 maxRead = tMaxRead;
-
- ndbrequire((readOffset + attrNoOfWords - 1) < tCheckOffset);
- if (newIndexBuf <= maxRead) {
- ljam();
- ahOut->setDataSize(attrNoOfWords);
- if (! tXfrmFlag) {
- MEMCOPY_NO_WORDS(&outBuffer[indexBuf],
- &tTupleHeader[readOffset],
- attrNoOfWords);
- } else {
- ljam();
- Tablerec* regTabPtr = tabptr.p;
- Uint32 i = AttributeOffset::getCharsetPos(attrDes2);
- ndbrequire(i < tabptr.p->noOfCharsets);
- // not const in MySQL
- CHARSET_INFO* cs = tabptr.p->charsetArray[i];
- // XXX should strip Uint32 null padding
- const unsigned nBytes = attrNoOfWords << 2;
- unsigned n =
- (*cs->coll->strnxfrm)(cs,
- (uchar*)&outBuffer[indexBuf],
- nBytes,
- (const uchar*)&tTupleHeader[readOffset],
- nBytes);
- // pad with ascii spaces
- while (n < nBytes)
- ((uchar*)&outBuffer[indexBuf])[n++] = 0x20;
- }
- tOutBufIndex = newIndexBuf;
- return true;
- } else {
- ljam();
- terrorCode = ZTRY_TO_READ_TOO_MUCH_ERROR;
- return false;
- }
-}
-
-bool
-Dbtup::readCharNULLable(Uint32* outBuffer,
- AttributeHeader* ahOut,
- Uint32 attrDescriptor,
- Uint32 attrDes2)
-{
- if (!nullFlagCheck(attrDes2)) {
- ljam();
- return readCharNotNULL(outBuffer,
- ahOut,
- attrDescriptor,
- attrDes2);
- } else {
- ljam();
- ahOut->setNULL();
- return true;
- }
-}
-
/* ---------------------------------------------------------------------- */
/* THIS ROUTINE IS USED TO UPDATE A NUMBER OF ATTRIBUTES. IT IS */
/* USED BY THE INSERT ROUTINE, THE UPDATE ROUTINE AND IT CAN BE */
@@ -810,6 +794,7 @@ Dbtup::updateFixedSizeTHManyWordNotNULL(Uint32* inBuffer,
Uint32 indexBuf = tInBufIndex;
Uint32 inBufLen = tInBufLen;
Uint32 updateOffset = AttributeOffset::getOffset(attrDes2);
+ Uint32 charsetFlag = AttributeOffset::getCharsetFlag(attrDes2);
AttributeHeader ahIn(inBuffer[indexBuf]);
Uint32 nullIndicator = ahIn.isNULL();
Uint32 noOfWords = AttributeDescriptor::getSizeInWords(attrDescriptor);
@@ -819,6 +804,31 @@ Dbtup::updateFixedSizeTHManyWordNotNULL(Uint32* inBuffer,
if (newIndex <= inBufLen) {
if (!nullIndicator) {
ljam();
+ if (charsetFlag) {
+ ljam();
+ Tablerec* regTabPtr = tabptr.p;
+ Uint32 typeId = AttributeDescriptor::getType(attrDescriptor);
+ Uint32 bytes = AttributeDescriptor::getSizeInBytes(attrDescriptor);
+ Uint32 i = AttributeOffset::getCharsetPos(attrDes2);
+ ndbrequire(i < regTabPtr->noOfCharsets);
+ // not const in MySQL
+ CHARSET_INFO* cs = regTabPtr->charsetArray[i];
+ int not_used;
+ const char* ssrc = (const char*)&inBuffer[tInBufIndex + 1];
+ Uint32 lb, len;
+ if (! NdbSqlUtil::get_var_length(typeId, ssrc, bytes, lb, len)) {
+ ljam();
+ terrorCode = ZINVALID_CHAR_FORMAT;
+ return false;
+ }
+ // fast fix bug#7340
+ if (typeId != NDB_TYPE_TEXT &&
+ (*cs->cset->well_formed_len)(cs, ssrc + lb, ssrc + lb + len, ZNIL, &not_used) != len) {
+ ljam();
+ terrorCode = ZINVALID_CHAR_FORMAT;
+ return false;
+ }
+ }
tInBufIndex = newIndex;
MEMCOPY_NO_WORDS(&tTupleHeader[updateOffset],
&inBuffer[indexBuf + 1],
@@ -990,18 +1000,187 @@ Dbtup::read_psuedo(Uint32 attrId, Uint32* outBuffer){
Signal * signal = (Signal*)&tmp;
switch(attrId){
case AttributeHeader::FRAGMENT:
- * outBuffer = operPtr.p->fragId;
+ * outBuffer = operPtr.p->fragId >> 1; // remove "hash" bit
+ return 1;
+ case AttributeHeader::FRAGMENT_MEMORY:
+ {
+ Uint64 tmp= fragptr.p->noOfPages;
+ tmp*= 32768;
+ memcpy(outBuffer,&tmp,8);
+ }
+ return 2;
+ case AttributeHeader::ROW_SIZE:
+ * outBuffer = tabptr.p->tupheadsize << 2;
return 1;
case AttributeHeader::ROW_COUNT:
case AttributeHeader::COMMIT_COUNT:
signal->theData[0] = operPtr.p->userpointer;
signal->theData[1] = attrId;
-
+
EXECUTE_DIRECT(DBLQH, GSN_READ_PSUEDO_REQ, signal, 2);
outBuffer[0] = signal->theData[0];
outBuffer[1] = signal->theData[1];
return 2;
+ case AttributeHeader::RANGE_NO:
+ signal->theData[0] = operPtr.p->userpointer;
+ signal->theData[1] = attrId;
+
+ EXECUTE_DIRECT(DBLQH, GSN_READ_PSUEDO_REQ, signal, 2);
+ outBuffer[0] = signal->theData[0];
+ return 1;
default:
return 0;
}
}
+
+bool
+Dbtup::readBitsNotNULL(Uint32* outBuffer,
+ AttributeHeader* ahOut,
+ Uint32 attrDescriptor,
+ Uint32 attrDes2)
+{
+ Tablerec* const regTabPtr = tabptr.p;
+ Uint32 pos = AttributeOffset::getNullFlagPos(attrDes2);
+ Uint32 bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+ Uint32 indexBuf = tOutBufIndex;
+ Uint32 newIndexBuf = indexBuf + ((bitCount + 31) >> 5);
+ Uint32 maxRead = tMaxRead;
+
+ if (newIndexBuf <= maxRead) {
+ ljam();
+ ahOut->setDataSize((bitCount + 31) >> 5);
+ tOutBufIndex = newIndexBuf;
+
+ BitmaskImpl::getField(regTabPtr->tupNullWords,
+ tTupleHeader+regTabPtr->tupNullIndex,
+ pos,
+ bitCount,
+ outBuffer+indexBuf);
+
+ return true;
+ } else {
+ ljam();
+ terrorCode = ZTRY_TO_READ_TOO_MUCH_ERROR;
+ return false;
+ }//if
+}
+
+bool
+Dbtup::readBitsNULLable(Uint32* outBuffer,
+ AttributeHeader* ahOut,
+ Uint32 attrDescriptor,
+ Uint32 attrDes2)
+{
+ Tablerec* const regTabPtr = tabptr.p;
+ Uint32 pos = AttributeOffset::getNullFlagPos(attrDes2);
+ Uint32 bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+
+ Uint32 indexBuf = tOutBufIndex;
+ Uint32 newIndexBuf = indexBuf + ((bitCount + 31) >> 5);
+ Uint32 maxRead = tMaxRead;
+
+ if(BitmaskImpl::get(regTabPtr->tupNullWords,
+ tTupleHeader+regTabPtr->tupNullIndex,
+ pos))
+ {
+ ljam();
+ ahOut->setNULL();
+ return true;
+ }
+
+
+ if (newIndexBuf <= maxRead) {
+ ljam();
+ ahOut->setDataSize((bitCount + 31) >> 5);
+ tOutBufIndex = newIndexBuf;
+ BitmaskImpl::getField(regTabPtr->tupNullWords,
+ tTupleHeader+regTabPtr->tupNullIndex,
+ pos+1,
+ bitCount,
+ outBuffer+indexBuf);
+ return true;
+ } else {
+ ljam();
+ terrorCode = ZTRY_TO_READ_TOO_MUCH_ERROR;
+ return false;
+ }//if
+}
+
+bool
+Dbtup::updateBitsNotNULL(Uint32* inBuffer,
+ Uint32 attrDescriptor,
+ Uint32 attrDes2)
+{
+ Tablerec* const regTabPtr = tabptr.p;
+ Uint32 indexBuf = tInBufIndex;
+ Uint32 inBufLen = tInBufLen;
+ AttributeHeader ahIn(inBuffer[indexBuf]);
+ Uint32 nullIndicator = ahIn.isNULL();
+ Uint32 pos = AttributeOffset::getNullFlagPos(attrDes2);
+ Uint32 bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+ Uint32 newIndex = indexBuf + 1 + ((bitCount + 31) >> 5);
+
+ if (newIndex <= inBufLen) {
+ if (!nullIndicator) {
+ BitmaskImpl::setField(regTabPtr->tupNullWords,
+ tTupleHeader+regTabPtr->tupNullIndex,
+ pos,
+ bitCount,
+ inBuffer+indexBuf+1);
+ tInBufIndex = newIndex;
+ return true;
+ } else {
+ ljam();
+ terrorCode = ZNOT_NULL_ATTR;
+ return false;
+ }//if
+ } else {
+ ljam();
+ terrorCode = ZAI_INCONSISTENCY_ERROR;
+ return false;
+ }//if
+ return true;
+}
+
+bool
+Dbtup::updateBitsNULLable(Uint32* inBuffer,
+ Uint32 attrDescriptor,
+ Uint32 attrDes2)
+{
+ Tablerec* const regTabPtr = tabptr.p;
+ AttributeHeader ahIn(inBuffer[tInBufIndex]);
+ Uint32 indexBuf = tInBufIndex;
+ Uint32 nullIndicator = ahIn.isNULL();
+ Uint32 pos = AttributeOffset::getNullFlagPos(attrDes2);
+ Uint32 bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+
+ if (!nullIndicator) {
+ BitmaskImpl::clear(regTabPtr->tupNullWords,
+ tTupleHeader+regTabPtr->tupNullIndex,
+ pos);
+ BitmaskImpl::setField(regTabPtr->tupNullWords,
+ tTupleHeader+regTabPtr->tupNullIndex,
+ pos+1,
+ bitCount,
+ inBuffer+indexBuf+1);
+
+ Uint32 newIndex = indexBuf + 1 + ((bitCount + 31) >> 5);
+ tInBufIndex = newIndex;
+ return true;
+ } else {
+ Uint32 newIndex = tInBufIndex + 1;
+ if (newIndex <= tInBufLen) {
+ ljam();
+ BitmaskImpl::set(regTabPtr->tupNullWords,
+ tTupleHeader+regTabPtr->tupNullIndex,
+ pos);
+
+ tInBufIndex = newIndex;
+ return true;
+ } else {
+ ljam();
+ terrorCode = ZAI_INCONSISTENCY_ERROR;
+ return false;
+ }//if
+ }//if
+}
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupSystemRestart.cpp b/ndb/src/kernel/blocks/dbtup/DbtupSystemRestart.cpp
index ed835dc057a..33d63e8ce49 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupSystemRestart.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupSystemRestart.cpp
@@ -418,7 +418,7 @@ void Dbtup::xlcRestartCompletedLab(Signal* signal)
{
cnoOfLocalLogInfo = 0;
- signal->theData[0] = EventReport::UNDORecordsExecuted;
+ signal->theData[0] = NDB_LE_UNDORecordsExecuted;
signal->theData[1] = DBTUP; // From block
signal->theData[2] = 0; // Total records executed
for (int i = 0; i < 10; i++) {
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp b/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp
index 575d08efffc..2b65a8402c2 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp
@@ -753,7 +753,7 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr,
regTabPtr->noOfKeyAttr,
keyBuffer,
ZATTR_BUFFER_SIZE,
- true);
+ false);
ndbrequire(ret != -1);
noPrimKey= ret;
@@ -796,7 +796,7 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr,
numAttrsToRead,
mainBuffer,
ZATTR_BUFFER_SIZE,
- true);
+ false);
ndbrequire(ret != -1);
noMainWords= ret;
} else {
@@ -822,7 +822,7 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr,
numAttrsToRead,
copyBuffer,
ZATTR_BUFFER_SIZE,
- true);
+ false);
ndbrequire(ret != -1);
noCopyWords = ret;
diff --git a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
index 2c96271eb5d..5c12472a0f7 100644
--- a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
+++ b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
@@ -405,7 +405,7 @@ private:
Uint32 m_accLockOp;
Uint8 m_readCommitted; // no locking
Uint8 m_lockMode;
- Uint8 m_keyInfo;
+ Uint8 m_descending;
ScanBound m_boundMin;
ScanBound m_boundMax;
ScanBound* m_bound[2]; // pointers to above 2
@@ -448,7 +448,7 @@ private:
State m_state;
DictTabInfo::TableType m_tableType;
Uint32 m_tableId;
- Uint16 m_fragOff; // offset for duplicate fragId bits
+ Uint16 unused;
Uint16 m_numFrags;
Uint32 m_fragId[MaxIndexFragments];
Uint32 m_fragPtrI[MaxIndexFragments];
@@ -474,7 +474,7 @@ private:
struct Frag {
Uint32 m_tableId; // copy from index level
Uint32 m_indexId;
- Uint16 m_fragOff;
+ Uint16 unused;
Uint16 m_fragId;
Uint32 m_descPage; // copy from index level
Uint16 m_descOff;
@@ -638,7 +638,7 @@ private:
void execACCKEYREF(Signal* signal);
void execACC_ABORTCONF(Signal* signal);
void scanFirst(ScanOpPtr scanPtr);
- void scanNext(ScanOpPtr scanPtr);
+ void scanNext(ScanOpPtr scanPtr, bool fromMaintReq);
bool scanVisible(ScanOpPtr scanPtr, TreeEnt ent);
void scanClose(Signal* signal, ScanOpPtr scanPtr);
void addAccLockOp(ScanOp& scan, Uint32 accLockOp);
@@ -650,7 +650,9 @@ private:
*/
void searchToAdd(Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos);
void searchToRemove(Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos);
- void searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos);
+ void searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, bool descending, TreePos& treePos);
+ void searchToScanAscending(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos);
+ void searchToScanDescending(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos);
/*
* DbtuxCmp.cpp
@@ -1029,7 +1031,7 @@ Dbtux::ScanOp::ScanOp(ScanBoundPool& scanBoundPool) :
m_accLockOp(RNIL),
m_readCommitted(0),
m_lockMode(0),
- m_keyInfo(0),
+ m_descending(0),
m_boundMin(scanBoundPool),
m_boundMax(scanBoundPool),
m_scanPos(),
@@ -1073,7 +1075,6 @@ inline
Dbtux::Frag::Frag(ArrayPool<ScanOp>& scanOpPool) :
m_tableId(RNIL),
m_indexId(RNIL),
- m_fragOff(ZNIL),
m_fragId(ZNIL),
m_descPage(RNIL),
m_descOff(0),
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp
index ddab77b97b5..cf815b14c1a 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp
@@ -18,24 +18,26 @@
#include "Dbtux.hpp"
/*
- * Search key vs node prefix or entry
+ * Search key vs node prefix or entry.
*
* The comparison starts at given attribute position. The position is
* updated by number of equal initial attributes found. The entry data
* may be partial in which case CmpUnknown may be returned.
+ *
+ * The attributes are normalized and have variable size given in words.
*/
int
Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, ConstData searchKey, ConstData entryData, unsigned maxlen)
{
const unsigned numAttrs = frag.m_numAttrs;
const DescEnt& descEnt = getDescEnt(frag.m_descPage, frag.m_descOff);
- // number of words of attribute data left
- unsigned len2 = maxlen;
// skip to right position in search key only
for (unsigned i = 0; i < start; i++) {
jam();
searchKey += AttributeHeaderSize + searchKey.ah().getDataSize();
}
+ // number of words of entry data left
+ unsigned len2 = maxlen;
int ret = 0;
while (start < numAttrs) {
if (len2 <= AttributeHeaderSize) {
@@ -47,18 +49,20 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, ConstData searchKey, Cons
if (! searchKey.ah().isNULL()) {
if (! entryData.ah().isNULL()) {
jam();
- // current attribute
+ // verify attribute id
const DescAttr& descAttr = descEnt.m_descAttr[start];
- // full data size
- const unsigned size1 = AttributeDescriptor::getSizeInWords(descAttr.m_attrDesc);
- ndbrequire(size1 != 0 && size1 == entryData.ah().getDataSize());
- const unsigned size2 = min(size1, len2);
+ ndbrequire(searchKey.ah().getAttributeId() == descAttr.m_primaryAttrId);
+ ndbrequire(entryData.ah().getAttributeId() == descAttr.m_primaryAttrId);
+ // sizes
+ const unsigned size1 = searchKey.ah().getDataSize();
+ const unsigned size2 = min(entryData.ah().getDataSize(), len2);
len2 -= size2;
// compare
NdbSqlUtil::Cmp* const cmp = c_sqlCmp[start];
const Uint32* const p1 = &searchKey[AttributeHeaderSize];
const Uint32* const p2 = &entryData[AttributeHeaderSize];
- ret = (*cmp)(0, p1, p2, size1, size2);
+ const bool full = (maxlen == MaxAttrDataSize);
+ ret = (*cmp)(0, p1, size1 << 2, p2, size2 << 2, full);
if (ret != 0) {
jam();
break;
@@ -99,18 +103,20 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, ConstData searchKey, Cons
*
* Following example illustrates this. We are at (a=2, b=3).
*
- * dir bounds strict return
+ * idir bounds strict return
* 0 a >= 2 and b >= 3 no -1
* 0 a >= 2 and b > 3 yes +1
* 1 a <= 2 and b <= 3 no +1
* 1 a <= 2 and b < 3 yes -1
+ *
+ * The attributes are normalized and have variable size given in words.
*/
int
-Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigned boundCount, ConstData entryData, unsigned maxlen)
+Dbtux::cmpScanBound(const Frag& frag, unsigned idir, ConstData boundInfo, unsigned boundCount, ConstData entryData, unsigned maxlen)
{
const DescEnt& descEnt = getDescEnt(frag.m_descPage, frag.m_descOff);
// direction 0-lower 1-upper
- ndbrequire(dir <= 1);
+ ndbrequire(idir <= 1);
// number of words of data left
unsigned len2 = maxlen;
// in case of no bounds, init last type to something non-strict
@@ -127,21 +133,21 @@ Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigne
if (! boundInfo.ah().isNULL()) {
if (! entryData.ah().isNULL()) {
jam();
- // current attribute
- const unsigned index = boundInfo.ah().getAttributeId();
+ // verify attribute id
+ const Uint32 index = boundInfo.ah().getAttributeId();
ndbrequire(index < frag.m_numAttrs);
const DescAttr& descAttr = descEnt.m_descAttr[index];
ndbrequire(entryData.ah().getAttributeId() == descAttr.m_primaryAttrId);
- // full data size
+ // sizes
const unsigned size1 = boundInfo.ah().getDataSize();
- ndbrequire(size1 != 0 && size1 == entryData.ah().getDataSize());
- const unsigned size2 = min(size1, len2);
+ const unsigned size2 = min(entryData.ah().getDataSize(), len2);
len2 -= size2;
// compare
NdbSqlUtil::Cmp* const cmp = c_sqlCmp[index];
const Uint32* const p1 = &boundInfo[AttributeHeaderSize];
const Uint32* const p2 = &entryData[AttributeHeaderSize];
- int ret = (*cmp)(0, p1, p2, size1, size2);
+ const bool full = (maxlen == MaxAttrDataSize);
+ int ret = (*cmp)(0, p1, size1 << 2, p2, size2 << 2, full);
if (ret != 0) {
jam();
return ret;
@@ -165,5 +171,5 @@ Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigne
}
// all attributes were equal
const int strict = (type & 0x1);
- return (dir == 0 ? (strict == 0 ? -1 : +1) : (strict == 0 ? +1 : -1));
+ return (idir == 0 ? (strict == 0 ? -1 : +1) : (strict == 0 ? +1 : -1));
}
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
index 1e1b0d1d5b6..ed29dc57915 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
@@ -340,14 +340,14 @@ operator<<(NdbOut& out, const Dbtux::ScanOp& scan)
out << " [savePointId " << dec << scan.m_savePointId << "]";
out << " [accLockOp " << hex << scan.m_accLockOp << "]";
out << " [accLockOps";
- for (unsigned i = 0; i < Dbtux::MaxAccLockOps; i++) {
+ for (unsigned i = 0; i < scan.m_maxAccLockOps; i++) {
if (scan.m_accLockOps[i] != RNIL)
out << " " << hex << scan.m_accLockOps[i];
}
out << "]";
out << " [readCommitted " << dec << scan.m_readCommitted << "]";
out << " [lockMode " << dec << scan.m_lockMode << "]";
- out << " [keyInfo " << dec << scan.m_keyInfo << "]";
+ out << " [descending " << dec << scan.m_descending << "]";
out << " [pos " << scan.m_scanPos << "]";
out << " [ent " << scan.m_scanEnt << "]";
for (unsigned i = 0; i <= 1; i++) {
@@ -370,7 +370,6 @@ operator<<(NdbOut& out, const Dbtux::Index& index)
{
out << "[Index " << hex << &index;
out << " [tableId " << dec << index.m_tableId << "]";
- out << " [fragOff " << dec << index.m_fragOff << "]";
out << " [numFrags " << dec << index.m_numFrags << "]";
for (unsigned i = 0; i < index.m_numFrags; i++) {
out << " [frag " << dec << i << " ";
@@ -393,7 +392,6 @@ operator<<(NdbOut& out, const Dbtux::Frag& frag)
out << "[Frag " << hex << &frag;
out << " [tableId " << dec << frag.m_tableId << "]";
out << " [indexId " << dec << frag.m_indexId << "]";
- out << " [fragOff " << dec << frag.m_fragOff << "]";
out << " [fragId " << dec << frag.m_fragId << "]";
out << " [descPage " << hex << frag.m_descPage << "]";
out << " [descOff " << dec << frag.m_descOff << "]";
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
index 8990d6c86b6..5640fdf2899 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
@@ -217,6 +217,7 @@ Dbtux::setKeyAttrs(const Frag& frag)
const unsigned numAttrs = frag.m_numAttrs;
const DescEnt& descEnt = getDescEnt(frag.m_descPage, frag.m_descOff);
for (unsigned i = 0; i < numAttrs; i++) {
+ jam();
const DescAttr& descAttr = descEnt.m_descAttr[i];
Uint32 size = AttributeDescriptor::getSizeInWords(descAttr.m_attrDesc);
// set attr id and fixed size
@@ -244,6 +245,26 @@ Dbtux::readKeyAttrs(const Frag& frag, TreeEnt ent, unsigned start, Data keyData)
jamEntry();
// TODO handle error
ndbrequire(ret > 0);
+#ifdef VM_TRACE
+ if (debugFlags & (DebugMaint | DebugScan)) {
+ debugOut << "readKeyAttrs:" << endl;
+ ConstData data = keyData;
+ Uint32 totalSize = 0;
+ for (Uint32 i = start; i < frag.m_numAttrs; i++) {
+ Uint32 attrId = data.ah().getAttributeId();
+ Uint32 dataSize = data.ah().getDataSize();
+ debugOut << i << " attrId=" << attrId << " size=" << dataSize;
+ data += 1;
+ for (Uint32 j = 0; j < dataSize; j++) {
+ debugOut << " " << hex << data[0];
+ data += 1;
+ }
+ debugOut << endl;
+ totalSize += 1 + dataSize;
+ }
+ ndbassert((int)totalSize == ret);
+ }
+#endif
}
void
@@ -251,7 +272,7 @@ Dbtux::readTablePk(const Frag& frag, TreeEnt ent, Data pkData, unsigned& pkSize)
{
const Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[ent.m_fragBit];
const TupLoc tupLoc = ent.m_tupLoc;
- int ret = c_tup->tuxReadPk(tableFragPtrI, tupLoc.getPageId(), tupLoc.getPageOffset(), pkData);
+ int ret = c_tup->tuxReadPk(tableFragPtrI, tupLoc.getPageId(), tupLoc.getPageOffset(), pkData, true);
jamEntry();
// TODO handle error
ndbrequire(ret > 0);
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
index 30afb51e7d7..4b568badc67 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp
@@ -57,9 +57,8 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal)
c_indexPool.getPtr(indexPtr, req->indexId);
ndbrequire(indexPtr.p->m_tableId == req->tableId);
// get base fragment id and extra bits
- const Uint32 fragOff = indexPtr.p->m_fragOff;
- const Uint32 fragId = req->fragId & ((1 << fragOff) - 1);
- const Uint32 fragBit = req->fragId >> fragOff;
+ const Uint32 fragId = req->fragId & ~1;
+ const Uint32 fragBit = req->fragId & 1;
// get the fragment
FragPtr fragPtr;
fragPtr.i = RNIL;
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
index b7526593a08..93c4a583624 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp
@@ -16,6 +16,7 @@
#define DBTUX_META_CPP
#include "Dbtux.hpp"
+#include <my_sys.h>
/*
* Create index.
@@ -84,7 +85,6 @@ Dbtux::execTUXFRAGREQ(Signal* signal)
new (fragPtr.p) Frag(c_scanOpPool);
fragPtr.p->m_tableId = req->primaryTableId;
fragPtr.p->m_indexId = req->tableId;
- fragPtr.p->m_fragOff = req->fragOff;
fragPtr.p->m_fragId = req->fragId;
fragPtr.p->m_numAttrs = req->noOfAttr;
fragPtr.p->m_storeNullKey = true; // not yet configurable
@@ -112,7 +112,6 @@ Dbtux::execTUXFRAGREQ(Signal* signal)
indexPtr.p->m_state = Index::Defining;
indexPtr.p->m_tableType = (DictTabInfo::TableType)req->tableType;
indexPtr.p->m_tableId = req->primaryTableId;
- indexPtr.p->m_fragOff = req->fragOff;
indexPtr.p->m_numAttrs = req->noOfAttr;
indexPtr.p->m_storeNullKey = true; // not yet configurable
// allocate attribute descriptors
@@ -128,7 +127,6 @@ Dbtux::execTUXFRAGREQ(Signal* signal)
indexPtr.p->m_state == Index::Defining &&
indexPtr.p->m_tableType == (DictTabInfo::TableType)req->tableType &&
indexPtr.p->m_tableId == req->primaryTableId &&
- indexPtr.p->m_fragOff == req->fragOff &&
indexPtr.p->m_numAttrs == req->noOfAttr);
}
// copy metadata address to each fragment
@@ -203,7 +201,7 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal)
DescAttr& descAttr = descEnt.m_descAttr[attrId];
descAttr.m_attrDesc = req->attrDescriptor;
descAttr.m_primaryAttrId = req->primaryAttrId;
- descAttr.m_typeId = req->extTypeInfo & 0xFF;
+ descAttr.m_typeId = AttributeDescriptor::getType(req->attrDescriptor);
descAttr.m_charset = (req->extTypeInfo >> 16);
#ifdef VM_TRACE
if (debugFlags & DebugMeta) {
@@ -218,17 +216,15 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal)
errorCode = TuxAddAttrRef::InvalidAttributeType;
break;
}
-#ifdef dbtux_uses_charset
if (descAttr.m_charset != 0) {
- CHARSET_INFO *cs = get_charset(descAttr.m_charset, MYF(0));
- // here use the non-binary type
+ CHARSET_INFO *cs = all_charsets[descAttr.m_charset];
+ ndbrequire(cs != 0);
if (! NdbSqlUtil::usable_in_ordered_index(descAttr.m_typeId, cs)) {
jam();
errorCode = TuxAddAttrRef::InvalidCharset;
break;
}
}
-#endif
const bool lastAttr = (indexPtr.p->m_numAttrs == fragOpPtr.p->m_numAttrsRecvd);
if (ERROR_INSERTED(12003) && fragOpPtr.p->m_fragNo == 0 && attrId == 0 ||
ERROR_INSERTED(12004) && fragOpPtr.p->m_fragNo == 0 && lastAttr ||
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp
index 9f9d4cb68e3..68a3e78ce9e 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp
@@ -502,7 +502,7 @@ Dbtux::moveScanList(NodeHandle& node, unsigned pos)
debugOut << "At pos=" << pos << " " << node << endl;
}
#endif
- scanNext(scanPtr);
+ scanNext(scanPtr, true);
ndbrequire(! (scanPos.m_loc == node.m_loc && scanPos.m_pos == pos));
}
scanPtr.i = nextPtrI;
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
index 8677ae741b3..a61b7c1f5ca 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
@@ -16,6 +16,7 @@
#define DBTUX_SCAN_CPP
#include "Dbtux.hpp"
+#include <my_sys.h>
void
Dbtux::execACC_SCANREQ(Signal* signal)
@@ -34,7 +35,7 @@ Dbtux::execACC_SCANREQ(Signal* signal)
fragPtr.i = RNIL;
for (unsigned i = 0; i < indexPtr.p->m_numFrags; i++) {
jam();
- if (indexPtr.p->m_fragId[i] == req->fragmentNo) {
+ if (indexPtr.p->m_fragId[i] == req->fragmentNo << 1) {
jam();
c_fragPool.getPtr(fragPtr, indexPtr.p->m_fragPtrI[i]);
break;
@@ -43,7 +44,6 @@ Dbtux::execACC_SCANREQ(Signal* signal)
ndbrequire(fragPtr.i != RNIL);
Frag& frag = *fragPtr.p;
// must be normal DIH/TC fragment
- ndbrequire(frag.m_fragId < (1 << frag.m_fragOff));
TreeHead& tree = frag.m_tree;
// check for empty fragment
if (tree.m_root == NullTupLoc) {
@@ -74,18 +74,18 @@ Dbtux::execACC_SCANREQ(Signal* signal)
scanPtr.p->m_savePointId = req->savePointId;
scanPtr.p->m_readCommitted = AccScanReq::getReadCommittedFlag(req->requestInfo);
scanPtr.p->m_lockMode = AccScanReq::getLockMode(req->requestInfo);
- scanPtr.p->m_keyInfo = AccScanReq::getKeyinfoFlag(req->requestInfo);
-#ifdef VM_TRACE
- if (debugFlags & DebugScan) {
- debugOut << "Seize scan " << scanPtr.i << " " << *scanPtr.p << endl;
- }
-#endif
+ scanPtr.p->m_descending = AccScanReq::getDescendingFlag(req->requestInfo);
/*
* readCommitted lockMode keyInfo
* 1 0 0 - read committed (no lock)
* 0 0 0 - read latest (read lock)
* 0 1 1 - read exclusive (write lock)
*/
+#ifdef VM_TRACE
+ if (debugFlags & DebugScan) {
+ debugOut << "Seize scan " << scanPtr.i << " " << *scanPtr.p << endl;
+ }
+#endif
// conf
AccScanConf* const conf = (AccScanConf*)signal->getDataPtrSend();
conf->scanPtr = req->senderData;
@@ -114,50 +114,100 @@ Dbtux::execACC_SCANREQ(Signal* signal)
* keys and that all but possibly last bound is non-strict.
*
* Finally save the sets of lower and upper bounds (i.e. start key and
- * end key). Full bound type (< 4) is included but only the strict bit
- * is used since lower and upper have now been separated.
+ * end key). Full bound type is included but only the strict bit is
+ * used since lower and upper have now been separated.
*/
void
Dbtux::execTUX_BOUND_INFO(Signal* signal)
{
jamEntry();
- struct BoundInfo {
- int type;
- unsigned offset;
- unsigned size;
- };
- TuxBoundInfo* const sig = (TuxBoundInfo*)signal->getDataPtrSend();
- const TuxBoundInfo reqCopy = *(const TuxBoundInfo*)sig;
- const TuxBoundInfo* const req = &reqCopy;
// get records
+ TuxBoundInfo* const sig = (TuxBoundInfo*)signal->getDataPtrSend();
+ const TuxBoundInfo* const req = (const TuxBoundInfo*)sig;
ScanOp& scan = *c_scanOpPool.getPtr(req->tuxScanPtrI);
- Index& index = *c_indexPool.getPtr(scan.m_indexId);
- // collect lower and upper bounds
+ const Index& index = *c_indexPool.getPtr(scan.m_indexId);
+ const DescEnt& descEnt = getDescEnt(index.m_descPage, index.m_descOff);
+ // collect normalized lower and upper bounds
+ struct BoundInfo {
+ int type2; // with EQ -> LE/GE
+ Uint32 offset; // offset in xfrmData
+ Uint32 size;
+ };
BoundInfo boundInfo[2][MaxIndexAttributes];
+ const unsigned dstSize = 1024 * MAX_XFRM_MULTIPLY;
+ Uint32 xfrmData[dstSize];
+ Uint32 dstPos = 0;
// largest attrId seen plus one
Uint32 maxAttrId[2] = { 0, 0 };
- unsigned offset = 0;
- const Uint32* const data = (Uint32*)sig + TuxBoundInfo::SignalLength;
// walk through entries
+ const Uint32* const data = (Uint32*)sig + TuxBoundInfo::SignalLength;
+ Uint32 offset = 0;
while (offset + 2 <= req->boundAiLength) {
jam();
const unsigned type = data[offset];
- if (type > 4) {
- jam();
- scan.m_state = ScanOp::Invalid;
- sig->errorCode = TuxBoundInfo::InvalidAttrInfo;
- return;
- }
const AttributeHeader* ah = (const AttributeHeader*)&data[offset + 1];
const Uint32 attrId = ah->getAttributeId();
const Uint32 dataSize = ah->getDataSize();
- if (attrId >= index.m_numAttrs) {
+ if (type > 4 || attrId >= index.m_numAttrs || dstPos + 2 + dataSize > dstSize) {
jam();
scan.m_state = ScanOp::Invalid;
sig->errorCode = TuxBoundInfo::InvalidAttrInfo;
return;
}
+ // copy header
+ xfrmData[dstPos + 0] = data[offset + 0];
+ xfrmData[dstPos + 1] = data[offset + 1];
+ // copy bound value
+ Uint32 dstWords = 0;
+ if (! ah->isNULL()) {
+ jam();
+ const DescAttr& descAttr = descEnt.m_descAttr[attrId];
+ Uint32 srcBytes = AttributeDescriptor::getSizeInBytes(descAttr.m_attrDesc);
+ Uint32 srcWords = (srcBytes + 3) / 4;
+ if (srcWords != dataSize) {
+ jam();
+ scan.m_state = ScanOp::Invalid;
+ sig->errorCode = TuxBoundInfo::InvalidAttrInfo;
+ return;
+ }
+ uchar* dstPtr = (uchar*)&xfrmData[dstPos + 2];
+ const uchar* srcPtr = (const uchar*)&data[offset + 2];
+ if (descAttr.m_charset == 0) {
+ memcpy(dstPtr, srcPtr, srcWords << 2);
+ dstWords = srcWords;
+ } else {
+ jam();
+ Uint32 typeId = descAttr.m_typeId;
+ Uint32 lb, len;
+ bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len);
+ if (! ok) {
+ jam();
+ scan.m_state = ScanOp::Invalid;
+ sig->errorCode = TuxBoundInfo::InvalidCharFormat;
+ return;
+ }
+ CHARSET_INFO* cs = all_charsets[descAttr.m_charset];
+ Uint32 xmul = cs->strxfrm_multiply;
+ if (xmul == 0)
+ xmul = 1;
+ // see comment in DbtcMain.cpp
+ Uint32 dstLen = xmul * (srcBytes - lb);
+ if (dstLen > ((dstSize - dstPos) << 2)) {
+ jam();
+ scan.m_state = ScanOp::Invalid;
+ sig->errorCode = TuxBoundInfo::TooMuchAttrInfo;
+ return;
+ }
+ int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len);
+ ndbrequire(n != -1);
+ while ((n & 3) != 0) {
+ dstPtr[n++] = 0;
+ }
+ dstWords = n / 4;
+ }
+ }
for (unsigned j = 0; j <= 1; j++) {
+ jam();
// check if lower/upper bit matches
const unsigned luBit = (j << 1);
if ((type & 0x2) != luBit && type != 4)
@@ -166,29 +216,35 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal)
const unsigned type2 = (type & 0x1) | luBit;
// fill in any gap
while (maxAttrId[j] <= attrId) {
+ jam();
BoundInfo& b = boundInfo[j][maxAttrId[j]++];
- b.type = -1;
+ b.type2 = -1;
}
BoundInfo& b = boundInfo[j][attrId];
- if (b.type != -1) {
- // compare with previous bound
- if (b.type != (int)type2 ||
- b.size != 2 + dataSize ||
- memcmp(&data[b.offset + 2], &data[offset + 2], dataSize << 2) != 0) {
+ if (b.type2 != -1) {
+ // compare with previously defined bound
+ if (b.type2 != (int)type2 ||
+ b.size != 2 + dstWords ||
+ memcmp(&xfrmData[b.offset + 2], &xfrmData[dstPos + 2], dstWords << 2) != 0) {
jam();
scan.m_state = ScanOp::Invalid;
sig->errorCode = TuxBoundInfo::InvalidBounds;
return;
}
} else {
+ // fix length
+ AttributeHeader* ah = (AttributeHeader*)&xfrmData[dstPos + 1];
+ ah->setDataSize(dstWords);
// enter new bound
- b.type = type2;
- b.offset = offset;
- b.size = 2 + dataSize;
+ jam();
+ b.type2 = type2;
+ b.offset = dstPos;
+ b.size = 2 + dstWords;
}
}
// jump to next
offset += 2 + dataSize;
+ dstPos += 2 + dstWords;
}
if (offset != req->boundAiLength) {
jam();
@@ -202,13 +258,13 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal)
jam();
const BoundInfo& b = boundInfo[j][i];
// check for gap or strict bound before last
- if (b.type == -1 || (i + 1 < maxAttrId[j] && (b.type & 0x1))) {
+ if (b.type2 == -1 || (i + 1 < maxAttrId[j] && (b.type2 & 0x1))) {
jam();
scan.m_state = ScanOp::Invalid;
sig->errorCode = TuxBoundInfo::InvalidBounds;
return;
}
- bool ok = scan.m_bound[j]->append(&data[b.offset], b.size);
+ bool ok = scan.m_bound[j]->append(&xfrmData[b.offset], b.size);
if (! ok) {
jam();
scan.m_state = ScanOp::Invalid;
@@ -354,7 +410,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
NextScanConf* const conf = (NextScanConf*)signal->getDataPtrSend();
conf->scanPtr = scan.m_userPtr;
conf->accOperationPtr = RNIL; // no tuple returned
- conf->fragId = frag.m_fragId | (ent.m_fragBit << frag.m_fragOff);
+ conf->fragId = frag.m_fragId | ent.m_fragBit;
unsigned signalLength = 3;
// if TC has ordered scan close, it will be detected here
sendSignal(scan.m_userRef, GSN_NEXT_SCANCONF,
@@ -374,7 +430,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
if (scan.m_state == ScanOp::Next) {
jam();
// look for next
- scanNext(scanPtr);
+ scanNext(scanPtr, false);
}
// for reading tuple key in Current or Locked state
Data pkData = c_dataBuffer;
@@ -397,7 +453,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
lockReq->userPtr = scanPtr.i;
lockReq->userRef = reference();
lockReq->tableId = scan.m_tableId;
- lockReq->fragId = frag.m_fragId | (ent.m_fragBit << frag.m_fragOff);
+ lockReq->fragId = frag.m_fragId | ent.m_fragBit;
lockReq->fragPtrI = frag.m_accTableFragPtrI[ent.m_fragBit];
const Uint32* const buf32 = static_cast<Uint32*>(pkData);
const Uint64* const buf64 = reinterpret_cast<const Uint64*>(buf32);
@@ -474,13 +530,6 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
jam();
// read keys if not already done (uses signal)
const TreeEnt ent = scan.m_scanEnt;
- if (scan.m_keyInfo) {
- jam();
- if (pkSize == 0) {
- jam();
- readTablePk(frag, ent, pkData, pkSize);
- }
- }
// conf signal
NextScanConf* const conf = (NextScanConf*)signal->getDataPtrSend();
conf->scanPtr = scan.m_userPtr;
@@ -496,21 +545,12 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
accLockOp = (Uint32)-1;
}
conf->accOperationPtr = accLockOp;
- conf->fragId = frag.m_fragId | (ent.m_fragBit << frag.m_fragOff);
+ conf->fragId = frag.m_fragId | ent.m_fragBit;
conf->localKey[0] = getTupAddr(frag, ent);
conf->localKey[1] = 0;
conf->localKeyLength = 1;
unsigned signalLength = 6;
// add key info
- if (scan.m_keyInfo) {
- jam();
- conf->keyLength = pkSize;
- // piggy-back first 4 words of key data
- for (unsigned i = 0; i < 4; i++) {
- conf->key[i] = i < pkSize ? pkData[i] : 0;
- }
- signalLength = 11;
- }
if (! scan.m_readCommitted) {
sendSignal(scan.m_userRef, GSN_NEXT_SCANCONF,
signal, signalLength, JBB);
@@ -518,24 +558,6 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal)
Uint32 blockNo = refToBlock(scan.m_userRef);
EXECUTE_DIRECT(blockNo, GSN_NEXT_SCANCONF, signal, signalLength);
}
- // send rest of key data
- if (scan.m_keyInfo && pkSize > 4) {
- unsigned total = 4;
- while (total < pkSize) {
- jam();
- unsigned length = pkSize - total;
- if (length > 20)
- length = 20;
- signal->theData[0] = scan.m_userPtr;
- signal->theData[1] = 0;
- signal->theData[2] = 0;
- signal->theData[3] = length;
- memcpy(&signal->theData[4], &pkData[total], length << 2);
- sendSignal(scan.m_userRef, GSN_ACC_SCAN_INFO24,
- signal, 4 + length, JBB);
- total += length;
- }
- }
// next time look for next entry
scan.m_state = ScanOp::Next;
return;
@@ -687,8 +709,10 @@ Dbtux::scanFirst(ScanOpPtr scanPtr)
TreeHead& tree = frag.m_tree;
// set up index keys for this operation
setKeyAttrs(frag);
- // unpack lower bound into c_dataBuffer
- const ScanBound& bound = *scan.m_bound[0];
+ // scan direction 0, 1
+ const unsigned idir = scan.m_descending;
+ // unpack start key into c_dataBuffer
+ const ScanBound& bound = *scan.m_bound[idir];
ScanBoundIterator iter;
bound.first(iter);
for (unsigned j = 0; j < bound.getSize(); j++) {
@@ -696,11 +720,10 @@ Dbtux::scanFirst(ScanOpPtr scanPtr)
c_dataBuffer[j] = *iter.data;
bound.next(iter);
}
- // search for scan start position
TreePos treePos;
- searchToScan(frag, c_dataBuffer, scan.m_boundCnt[0], treePos);
+ searchToScan(frag, c_dataBuffer, scan.m_boundCnt[idir], scan.m_descending, treePos);
if (treePos.m_loc == NullTupLoc) {
- // empty tree
+ // empty result set
jam();
scan.m_state = ScanOp::Last;
return;
@@ -718,7 +741,8 @@ Dbtux::scanFirst(ScanOpPtr scanPtr)
* Move to next entry. The scan is already linked to some node. When
* we leave, if an entry was found, it will be linked to a possibly
* different node. The scan has a position, and a direction which tells
- * from where we came to this position. This is one of:
+ * from where we came to this position. This is one of (all comments
+ * are in terms of ascending scan):
*
* 0 - up from left child (scan this node next)
* 1 - up from right child (proceed to parent)
@@ -730,7 +754,7 @@ Dbtux::scanFirst(ScanOpPtr scanPtr)
* re-organizations need not worry about scan direction.
*/
void
-Dbtux::scanNext(ScanOpPtr scanPtr)
+Dbtux::scanNext(ScanOpPtr scanPtr, bool fromMaintReq)
{
ScanOp& scan = *scanPtr.p;
Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI);
@@ -743,8 +767,11 @@ Dbtux::scanNext(ScanOpPtr scanPtr)
ndbrequire(scan.m_state != ScanOp::Locked);
// set up index keys for this operation
setKeyAttrs(frag);
- // unpack upper bound into c_dataBuffer
- const ScanBound& bound = *scan.m_bound[1];
+ // scan direction
+ const unsigned idir = scan.m_descending; // 0, 1
+ const int jdir = 1 - 2 * (int)idir; // 1, -1
+ // unpack end key into c_dataBuffer
+ const ScanBound& bound = *scan.m_bound[1 - idir];
ScanBoundIterator iter;
bound.first(iter);
for (unsigned j = 0; j < bound.getSize(); j++) {
@@ -764,6 +791,11 @@ Dbtux::scanNext(ScanOpPtr scanPtr)
TreeEnt ent;
while (true) {
jam();
+#ifdef VM_TRACE
+ if (debugFlags & DebugScan) {
+ debugOut << "Scan next pos " << pos << " " << node << endl;
+ }
+#endif
if (pos.m_dir == 2) {
// coming up from root ends the scan
jam();
@@ -778,7 +810,7 @@ Dbtux::scanNext(ScanOpPtr scanPtr)
if (pos.m_dir == 4) {
// coming down from parent proceed to left child
jam();
- TupLoc loc = node.getLink(0);
+ TupLoc loc = node.getLink(idir);
if (loc != NullTupLoc) {
jam();
pos.m_loc = loc;
@@ -786,34 +818,42 @@ Dbtux::scanNext(ScanOpPtr scanPtr)
continue;
}
// pretend we came from left child
- pos.m_dir = 0;
+ pos.m_dir = idir;
+ }
+ const unsigned occup = node.getOccup();
+ if (occup == 0) {
+ jam();
+ ndbrequire(fromMaintReq);
+ // move back to parent - see comment in treeRemoveInner
+ pos.m_loc = node.getLink(2);
+ pos.m_dir = node.getSide();
+ continue;
}
- if (pos.m_dir == 0) {
+ if (pos.m_dir == idir) {
// coming up from left child scan current node
jam();
- pos.m_pos = 0;
+ pos.m_pos = idir == 0 ? 0 : occup - 1;
pos.m_match = false;
pos.m_dir = 3;
}
if (pos.m_dir == 3) {
// within node
jam();
- unsigned occup = node.getOccup();
- ndbrequire(occup >= 1);
// advance position
if (! pos.m_match)
pos.m_match = true;
else
- pos.m_pos++;
+ // becomes ZNIL (which is > occup) if 0 and scan descending
+ pos.m_pos += jdir;
if (pos.m_pos < occup) {
jam();
ent = node.getEnt(pos.m_pos);
pos.m_dir = 3; // unchanged
// read and compare all attributes
readKeyAttrs(frag, ent, 0, c_entryKey);
- int ret = cmpScanBound(frag, 1, c_dataBuffer, scan.m_boundCnt[1], c_entryKey);
+ int ret = cmpScanBound(frag, 1 - idir, c_dataBuffer, scan.m_boundCnt[1 - idir], c_entryKey);
ndbrequire(ret != NdbSqlUtil::CmpUnknown);
- if (ret < 0) {
+ if (jdir * ret < 0) {
jam();
// hit upper bound of single range scan
pos.m_loc = NullTupLoc;
@@ -830,7 +870,7 @@ Dbtux::scanNext(ScanOpPtr scanPtr)
break;
}
// after node proceed to right child
- TupLoc loc = node.getLink(1);
+ TupLoc loc = node.getLink(1 - idir);
if (loc != NullTupLoc) {
jam();
pos.m_loc = loc;
@@ -838,9 +878,9 @@ Dbtux::scanNext(ScanOpPtr scanPtr)
continue;
}
// pretend we came from right child
- pos.m_dir = 1;
+ pos.m_dir = 1 - idir;
}
- if (pos.m_dir == 1) {
+ if (pos.m_dir == 1 - idir) {
// coming up from right child proceed to parent
jam();
pos.m_loc = node.getLink(2);
@@ -890,7 +930,7 @@ Dbtux::scanVisible(ScanOpPtr scanPtr, TreeEnt ent)
const Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI);
Uint32 fragBit = ent.m_fragBit;
Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[fragBit];
- Uint32 fragId = frag.m_fragId | (fragBit << frag.m_fragOff);
+ Uint32 fragId = frag.m_fragId | fragBit;
Uint32 tupAddr = getTupAddr(frag, ent);
Uint32 tupVersion = ent.m_tupVersion;
// check for same tuple twice in row
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp
index 7057d74c3ad..b0e2a664bfd 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp
@@ -253,22 +253,33 @@ Dbtux::searchToRemove(Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePo
/*
* Search for scan start position.
*
- * Similar to searchToAdd.
+ * Similar to searchToAdd. The routines differ somewhat depending on
+ * scan direction and are done by separate methods.
*/
void
-Dbtux::searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos)
+Dbtux::searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, bool descending, TreePos& treePos)
{
const TreeHead& tree = frag.m_tree;
- NodeHandle currNode(frag);
- currNode.m_loc = tree.m_root;
- if (currNode.m_loc == NullTupLoc) {
- // empty tree
- jam();
- treePos.m_match = false;
+ if (tree.m_root != NullTupLoc) {
+ if (! descending)
+ searchToScanAscending(frag, boundInfo, boundCount, treePos);
+ else
+ searchToScanDescending(frag, boundInfo, boundCount, treePos);
return;
}
+ // empty tree
+}
+
+void
+Dbtux::searchToScanAscending(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos)
+{
+ const TreeHead& tree = frag.m_tree;
+ NodeHandle currNode(frag);
+ currNode.m_loc = tree.m_root;
NodeHandle glbNode(frag); // potential g.l.b of final node
NodeHandle bottomNode(frag);
+ // always before entry
+ treePos.m_match = false;
while (true) {
jam();
selectNode(currNode, currNode.m_loc);
@@ -283,6 +294,7 @@ Dbtux::searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePo
ndbrequire(ret != NdbSqlUtil::CmpUnknown);
}
if (ret < 0) {
+ // bound is left of this node
jam();
const TupLoc loc = currNode.getLink(0);
if (loc != NullTupLoc) {
@@ -300,11 +312,11 @@ Dbtux::searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePo
// start scanning this node
treePos.m_loc = currNode.m_loc;
treePos.m_pos = 0;
- treePos.m_match = false;
treePos.m_dir = 3;
return;
}
} else if (ret > 0) {
+ // bound is at or right of this node
jam();
const TupLoc loc = currNode.getLink(1);
if (loc != NullTupLoc) {
@@ -316,7 +328,7 @@ Dbtux::searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePo
continue;
}
} else {
- ndbassert(false);
+ ndbrequire(false);
}
break;
}
@@ -328,20 +340,19 @@ Dbtux::searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePo
ret = cmpScanBound(frag, 0, boundInfo, boundCount, c_entryKey);
ndbrequire(ret != NdbSqlUtil::CmpUnknown);
if (ret < 0) {
- // start scanning from current entry
+ // found first entry satisfying the bound
treePos.m_loc = currNode.m_loc;
treePos.m_pos = j;
- treePos.m_match = false;
treePos.m_dir = 3;
return;
}
}
+ // bound is to right of this node
if (! bottomNode.isNull()) {
jam();
// start scanning the l.u.b
treePos.m_loc = bottomNode.m_loc;
treePos.m_pos = 0;
- treePos.m_match = false;
treePos.m_dir = 3;
return;
}
@@ -349,3 +360,90 @@ Dbtux::searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePo
treePos.m_loc = currNode.m_loc;
treePos.m_dir = 1;
}
+
+void
+Dbtux::searchToScanDescending(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos)
+{
+ const TreeHead& tree = frag.m_tree;
+ NodeHandle currNode(frag);
+ currNode.m_loc = tree.m_root;
+ NodeHandle glbNode(frag); // potential g.l.b of final node
+ NodeHandle bottomNode(frag);
+ // always before entry
+ treePos.m_match = false;
+ while (true) {
+ jam();
+ selectNode(currNode, currNode.m_loc);
+ int ret;
+ // compare prefix
+ ret = cmpScanBound(frag, 1, boundInfo, boundCount, currNode.getPref(), tree.m_prefSize);
+ if (ret == NdbSqlUtil::CmpUnknown) {
+ jam();
+ // read and compare all attributes
+ readKeyAttrs(frag, currNode.getMinMax(0), 0, c_entryKey);
+ ret = cmpScanBound(frag, 1, boundInfo, boundCount, c_entryKey);
+ ndbrequire(ret != NdbSqlUtil::CmpUnknown);
+ }
+ if (ret < 0) {
+ // bound is left of this node
+ jam();
+ const TupLoc loc = currNode.getLink(0);
+ if (loc != NullTupLoc) {
+ jam();
+ // continue to left subtree
+ currNode.m_loc = loc;
+ continue;
+ }
+ if (! glbNode.isNull()) {
+ jam();
+ // move up to the g.l.b but remember the bottom node
+ bottomNode = currNode;
+ currNode = glbNode;
+ } else {
+ // empty result set
+ return;
+ }
+ } else if (ret > 0) {
+ // bound is at or right of this node
+ jam();
+ const TupLoc loc = currNode.getLink(1);
+ if (loc != NullTupLoc) {
+ jam();
+ // save potential g.l.b
+ glbNode = currNode;
+ // continue to right subtree
+ currNode.m_loc = loc;
+ continue;
+ }
+ } else {
+ ndbrequire(false);
+ }
+ break;
+ }
+ for (unsigned j = 0, occup = currNode.getOccup(); j < occup; j++) {
+ jam();
+ int ret;
+ // read and compare attributes
+ readKeyAttrs(frag, currNode.getEnt(j), 0, c_entryKey);
+ ret = cmpScanBound(frag, 1, boundInfo, boundCount, c_entryKey);
+ ndbrequire(ret != NdbSqlUtil::CmpUnknown);
+ if (ret < 0) {
+ if (j > 0) {
+ // start scanning from previous entry
+ treePos.m_loc = currNode.m_loc;
+ treePos.m_pos = j - 1;
+ treePos.m_dir = 3;
+ return;
+ }
+ // start scanning upwards (pretend we came from left child)
+ treePos.m_loc = currNode.m_loc;
+ treePos.m_pos = 0;
+ treePos.m_dir = 0;
+ return;
+ }
+ }
+ // start scanning this node
+ treePos.m_loc = currNode.m_loc;
+ treePos.m_pos = currNode.getOccup() - 1;
+ treePos.m_dir = 3;
+}
diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
index b9e3b593a00..5107a8d8e31 100644
--- a/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
+++ b/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp
@@ -226,6 +226,9 @@ Dbtux::treeRemoveInner(Frag& frag, NodeHandle lubNode, unsigned pos)
// borrow max entry from semi/leaf
Uint32 scanList = RNIL;
nodePopDown(glbNode, glbNode.getOccup() - 1, ent, &scanList);
+ // g.l.b may be empty now
+ // a descending scan may try to enter the empty g.l.b
+ // we prevent this in scanNext
nodePopUp(lubNode, pos, ent, scanList);
if (glbNode.getLink(0) != NullTupLoc) {
jam();
diff --git a/ndb/src/kernel/blocks/dbtux/Times.txt b/ndb/src/kernel/blocks/dbtux/Times.txt
index 1e6d0a0a329..68120084846 100644
--- a/ndb/src/kernel/blocks/dbtux/Times.txt
+++ b/ndb/src/kernel/blocks/dbtux/Times.txt
@@ -138,6 +138,14 @@ before mc02/c 5 ms 13 ms 126 pct
after mc02/c 5 ms 10 ms 70 pct
mc02/d 178 ms 242 ms 69 pct
-[ prelim preformance fix for max batch size 16 -> 992 ]
+[ prelim performance fix for max batch size 16 -> 992 ]
+
+wl-2066 mc02/c 5 ms 10 ms 87 pct
+before mc02/d 140 ms 237 ms 69 pct
+
+wl-2066 mc02/c 5 ms 10 ms 69 pct
+after mc02/d 150 ms 229 ms 52 pct
+
+[ wl-2066 = remove ACC storage, use TUX test to see effect ]
vim: set et:
diff --git a/ndb/src/kernel/blocks/grep/Grep.cpp b/ndb/src/kernel/blocks/grep/Grep.cpp
index e89361dab06..0527c5415ab 100644
--- a/ndb/src/kernel/blocks/grep/Grep.cpp
+++ b/ndb/src/kernel/blocks/grep/Grep.cpp
@@ -599,7 +599,7 @@ Grep::PSCoord::execCREATE_SUBID_CONF(Signal* signal)
c_subCoordinatorPool.release(subData);
m_grep->sendEventRep(signal,
- EventReport::GrepSubscriptionInfo,
+ NDB_LE_GrepSubscriptionInfo,
GrepEvent::GrepPS_CreateSubIdConf,
subId,
subKey,
@@ -863,7 +863,7 @@ Grep::PSCoord::execGREP_CREATE_CONF(Signal* signal)
* Send event report
*/
m_grep->sendEventRep(signal,
- EventReport::GrepSubscriptionInfo,
+ NDB_LE_GrepSubscriptionInfo,
GrepEvent::GrepPS_SubCreateConf,
subId,
subKey,
@@ -1099,7 +1099,7 @@ Grep::PSCoord::execGREP_START_CONF(Signal* signal)
* Send event report
*/
m_grep->sendEventRep(signal,
- EventReport::GrepSubscriptionInfo,
+ NDB_LE_GrepSubscriptionInfo,
GrepEvent::GrepPS_SubStartMetaConf,
subId, subKey,
(Uint32)GrepError::GE_NO_ERROR);
@@ -1115,7 +1115,7 @@ Grep::PSCoord::execGREP_START_CONF(Signal* signal)
* Send event report
*/
m_grep->sendEventRep(signal,
- EventReport::GrepSubscriptionInfo,
+ NDB_LE_GrepSubscriptionInfo,
GrepEvent::GrepPS_SubStartDataConf,
subId, subKey,
(Uint32)GrepError::GE_NO_ERROR);
@@ -1339,7 +1339,7 @@ Grep::PSCoord::execGREP_REMOVE_CONF(Signal* signal)
*************************/
m_grep->sendEventRep(signal,
- EventReport::GrepSubscriptionInfo,
+ NDB_LE_GrepSubscriptionInfo,
GrepEvent::GrepPS_SubRemoveConf,
subId, subKey,
GrepError::GE_NO_ERROR);
@@ -1675,7 +1675,7 @@ Grep::PSCoord::execGREP_SYNC_CONF(Signal* signal)
event = GrepEvent::GrepPS_SubSyncDataConf;
/* @todo Johan: Add firstGCI here. /Lars */
- m_grep->sendEventRep(signal, EventReport::GrepSubscriptionInfo,
+ m_grep->sendEventRep(signal, NDB_LE_GrepSubscriptionInfo,
event, subId, subKey,
(Uint32)GrepError::GE_NO_ERROR,
lastGCI);
@@ -1799,7 +1799,7 @@ Grep::PSCoord::sendRefToSS(Signal * signal,
* Send event report
*/
m_grep->sendEventRep(signal,
- EventReport::GrepSubscriptionAlert,
+ NDB_LE_GrepSubscriptionAlert,
event,
sub.m_subscriptionId,
sub.m_subscriptionKey,
@@ -1831,7 +1831,7 @@ Grep::PSCoord::sendRefToSS(Signal * signal,
* Finally, send an event.
*/
m_grep->sendEventRep(signal,
- EventReport::GrepSubscriptionAlert,
+ NDB_LE_GrepSubscriptionAlert,
event,
sub.m_subscriptionId,
sub.m_subscriptionKey,
@@ -1920,7 +1920,7 @@ Grep::PSPart::sendRefToPSCoord(Signal * signal,
* Finally, send an event.
*/
m_grep->sendEventRep(signal,
- EventReport::GrepSubscriptionAlert,
+ NDB_LE_GrepSubscriptionAlert,
event,
sub.m_subscriptionId,
sub.m_subscriptionKey,
@@ -1988,7 +1988,7 @@ Grep::PSPart::execSUB_SYNC_CONTINUE_REQ(Signal* signal)
void
Grep::sendEventRep(Signal * signal,
- EventReport::EventType type,
+ Ndb_logevent_type type,
GrepEvent::Subscription event,
Uint32 subId,
Uint32 subKey,
diff --git a/ndb/src/kernel/blocks/grep/Grep.hpp b/ndb/src/kernel/blocks/grep/Grep.hpp
index 7d3dd916ecc..a14143294e1 100644
--- a/ndb/src/kernel/blocks/grep/Grep.hpp
+++ b/ndb/src/kernel/blocks/grep/Grep.hpp
@@ -268,7 +268,7 @@ private:
pspart.execSUB_GCP_COMPLETE_REP(s); };
void sendEventRep(Signal * signal,
- EventReport::EventType type,
+ Ndb_logevent_type type,
GrepEvent::Subscription event,
Uint32 subId,
Uint32 subKey,
diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
index 9eaa203b098..524a40697bf 100644
--- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
+++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
@@ -1460,7 +1460,7 @@ void Ndbcntr::execNODE_FAILREP(Signal* signal)
while(!allFailed.isclear()){
nodeId = allFailed.find(nodeId + 1);
allFailed.clear(nodeId);
- signal->theData[0] = EventReport::NODE_FAILREP;
+ signal->theData[0] = NDB_LE_NODE_FAILREP;
signal->theData[1] = nodeId;
signal->theData[2] = 0;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
@@ -1576,13 +1576,9 @@ void Ndbcntr::createSystableLab(Signal* signal, unsigned index)
ndbassert(column.pos == i);
w.add(DictTabInfo::AttributeName, column.name);
w.add(DictTabInfo::AttributeId, (Uint32)column.pos);
- //w.add(DictTabInfo::AttributeType, DictTabInfo::UnSignedType);
- //w.add(DictTabInfo::AttributeSize, DictTabInfo::a32Bit);
- //w.add(DictTabInfo::AttributeArraySize, 1);
w.add(DictTabInfo::AttributeKeyFlag, (Uint32)column.keyFlag);
//w.add(DictTabInfo::AttributeStorage, (Uint32)DictTabInfo::MainMemory);
w.add(DictTabInfo::AttributeNullableFlag, (Uint32)column.nullable);
- // ext type overrides
w.add(DictTabInfo::AttributeExtType, (Uint32)column.type);
w.add(DictTabInfo::AttributeExtLength, (Uint32)column.length);
w.add(DictTabInfo::AttributeEnd, (Uint32)true);
@@ -2046,7 +2042,7 @@ Ndbcntr::execSTOP_REQ(Signal* signal){
}
}
- signal->theData[0] = EventReport::NDBStopStarted;
+ signal->theData[0] = NDB_LE_NDBStopStarted;
signal->theData[1] = StopReq::getSystemStop(c_stopRec.stopReq.requestInfo) ? 1 : 0;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -2135,7 +2131,7 @@ Ndbcntr::StopRecord::checkNodeFail(Signal* signal){
cntr.updateNodeState(signal, newState);
- signal->theData[0] = EventReport::NDBStopAborted;
+ signal->theData[0] = NDB_LE_NDBStopAborted;
cntr.sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 1, JBB);
return false;
@@ -2420,7 +2416,7 @@ Ndbcntr::execFSREMOVECONF(Signal* signal){
}
void Ndbcntr::Missra::execSTART_ORD(Signal* signal){
- signal->theData[0] = EventReport::NDBStartStarted;
+ signal->theData[0] = NDB_LE_NDBStartStarted;
signal->theData[1] = NDB_VERSION;
cntr.sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -2542,14 +2538,14 @@ void Ndbcntr::Missra::sendNextSTTOR(Signal* signal){
* At least one wanted this start phase, report it
*/
jam();
- signal->theData[0] = EventReport::StartPhaseCompleted;
+ signal->theData[0] = NDB_LE_StartPhaseCompleted;
signal->theData[1] = currentStartPhase;
signal->theData[2] = cntr.ctypeOfStart;
cntr.sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
}
}
- signal->theData[0] = EventReport::NDBStartCompleted;
+ signal->theData[0] = NDB_LE_NDBStartCompleted;
signal->theData[1] = NDB_VERSION;
cntr.sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
diff --git a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
index 0ff7cea6d9f..bff79215264 100644
--- a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
+++ b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
@@ -303,7 +303,7 @@ private:
void stateArbitChoose(Signal* signal);
void stateArbitCrash(Signal* signal);
void computeArbitNdbMask(NodeBitmask& aMask);
- void reportArbitEvent(Signal* signal, EventReport::EventType type);
+ void reportArbitEvent(Signal* signal, Ndb_logevent_type type);
// Initialisation
void initData();
diff --git a/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp b/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
index d6960ce154e..ecaeadff47a 100644
--- a/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
+++ b/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
@@ -35,6 +35,9 @@ void Qmgr::initData()
Uint32 hbDBAPI = 500;
setHbApiDelay(hbDBAPI);
+
+ c_connectedNodes.clear();
+ c_connectedNodes.set(getOwnNodeId());
}//Qmgr::initData()
void Qmgr::initRecords()
diff --git a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
index da8596076ec..04373dae93c 100644
--- a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
+++ b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
@@ -608,7 +608,7 @@ void Qmgr::execCM_REGCONF(Signal* signal)
// Send this as an EVENT REPORT to inform about hearing about
// other NDB node proclaiming to be president.
/*--------------------------------------------------------------*/
- signal->theData[0] = EventReport::CM_REGCONF;
+ signal->theData[0] = NDB_LE_CM_REGCONF;
signal->theData[1] = getOwnNodeId();
signal->theData[2] = cpresident;
signal->theData[3] = TdynamicId;
@@ -734,7 +734,7 @@ void Qmgr::execCM_REGREF(Signal* signal)
// Send this as an EVENT REPORT to inform about hearing about
// other NDB node proclaiming not to be president.
/*--------------------------------------------------------------*/
- signal->theData[0] = EventReport::CM_REGREF;
+ signal->theData[0] = NDB_LE_CM_REGREF;
signal->theData[1] = getOwnNodeId();
signal->theData[2] = TaddNodeno;
//-----------------------------------------
@@ -1303,7 +1303,7 @@ void Qmgr::findNeighbours(Signal* signal)
}//if
}//if
- signal->theData[0] = EventReport::FIND_NEIGHBOURS;
+ signal->theData[0] = NDB_LE_FIND_NEIGHBOURS;
signal->theData[1] = getOwnNodeId();
signal->theData[2] = cneighbourl;
signal->theData[3] = cneighbourh;
@@ -1529,7 +1529,7 @@ void Qmgr::sendHeartbeat(Signal* signal)
sendSignal(localNodePtr.p->blockRef, GSN_CM_HEARTBEAT, signal, 1, JBA);
#ifdef VM_TRACE
- signal->theData[0] = EventReport::SentHeartbeat;
+ signal->theData[0] = NDB_LE_SentHeartbeat;
signal->theData[1] = localNodePtr.i;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
#endif
@@ -1555,7 +1555,7 @@ void Qmgr::checkHeartbeat(Signal* signal)
ndbrequire(getNodeInfo(nodePtr.i).m_type == NodeInfo::DB);
if(nodePtr.p->alarmCount > 2){
- signal->theData[0] = EventReport::MissedHeartbeat;
+ signal->theData[0] = NDB_LE_MissedHeartbeat;
signal->theData[1] = nodePtr.i;
signal->theData[2] = nodePtr.p->alarmCount - 1;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
@@ -1567,7 +1567,7 @@ void Qmgr::checkHeartbeat(Signal* signal)
* OUR LEFT NEIGHBOUR HAVE KEPT QUIET FOR THREE CONSECUTIVE HEARTBEAT
* PERIODS. THUS WE DECLARE HIM DOWN.
*----------------------------------------------------------------------*/
- signal->theData[0] = EventReport::DeadDueToHeartbeat;
+ signal->theData[0] = NDB_LE_DeadDueToHeartbeat;
signal->theData[1] = nodePtr.i;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -1596,7 +1596,7 @@ void Qmgr::apiHbHandlingLab(Signal* signal)
TnodePtr.p->alarmCount ++;
if(TnodePtr.p->alarmCount > 2){
- signal->theData[0] = EventReport::MissedHeartbeat;
+ signal->theData[0] = NDB_LE_MissedHeartbeat;
signal->theData[1] = nodeId;
signal->theData[2] = TnodePtr.p->alarmCount - 1;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
@@ -1611,7 +1611,7 @@ void Qmgr::apiHbHandlingLab(Signal* signal)
/*------------------------------------------------------------------*/
/* We call node_failed to release all connections for this api node */
/*------------------------------------------------------------------*/
- signal->theData[0] = EventReport::DeadDueToHeartbeat;
+ signal->theData[0] = NDB_LE_DeadDueToHeartbeat;
signal->theData[1] = nodeId;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
@@ -3067,7 +3067,7 @@ Qmgr::handleArbitApiFail(Signal* signal, Uint16 nodeId)
jam();
return;
}
- reportArbitEvent(signal, EventReport::ArbitState);
+ reportArbitEvent(signal, NDB_LE_ArbitState);
arbitRec.node = 0;
switch (arbitRec.state) {
case ARBIT_NULL: // should not happen
@@ -3238,7 +3238,7 @@ Qmgr::handleArbitCheck(Signal* signal)
arbitRec.newstate = true;
break;
}
- reportArbitEvent(signal, EventReport::ArbitResult);
+ reportArbitEvent(signal, NDB_LE_ArbitResult);
switch (arbitRec.state) {
default:
jam();
@@ -3265,7 +3265,7 @@ Qmgr::startArbitThread(Signal* signal)
jam();
ndbrequire(cpresident == getOwnNodeId());
arbitRec.code = ArbitCode::ThreadStart;
- reportArbitEvent(signal, EventReport::ArbitState);
+ reportArbitEvent(signal, NDB_LE_ArbitState);
signal->theData[1] = ++arbitRec.thread;
runArbitThread(signal);
}
@@ -3509,7 +3509,7 @@ Qmgr::execARBIT_PREPREQ(Signal* signal)
arbitRec.node = sd->node;
arbitRec.ticket = sd->ticket;
arbitRec.code = sd->code;
- reportArbitEvent(signal, EventReport::ArbitState);
+ reportArbitEvent(signal, NDB_LE_ArbitState);
arbitRec.state = ARBIT_RUN;
arbitRec.newstate = true;
if (sd->code == ArbitCode::PrepAtrun) {
@@ -3596,7 +3596,7 @@ Qmgr::stateArbitStart(Signal* signal)
}
if (arbitRec.recvCount) {
jam();
- reportArbitEvent(signal, EventReport::ArbitState);
+ reportArbitEvent(signal, NDB_LE_ArbitState);
if (arbitRec.code == ArbitCode::ApiStart) {
jam();
arbitRec.state = ARBIT_RUN;
@@ -3610,7 +3610,7 @@ Qmgr::stateArbitStart(Signal* signal)
if (arbitRec.getTimediff() > getArbitTimeout()) {
jam();
arbitRec.code = ArbitCode::ErrTimeout;
- reportArbitEvent(signal, EventReport::ArbitState);
+ reportArbitEvent(signal, NDB_LE_ArbitState);
arbitRec.state = ARBIT_INIT;
arbitRec.newstate = true;
return;
@@ -3717,7 +3717,7 @@ Qmgr::stateArbitChoose(Signal* signal)
}
if (arbitRec.recvCount) {
jam();
- reportArbitEvent(signal, EventReport::ArbitResult);
+ reportArbitEvent(signal, NDB_LE_ArbitResult);
if (arbitRec.code == ArbitCode::WinChoose) {
jam();
sendCommitFailReq(signal); // start commit of failed nodes
@@ -3733,7 +3733,7 @@ Qmgr::stateArbitChoose(Signal* signal)
if (arbitRec.getTimediff() > getArbitTimeout()) {
jam();
arbitRec.code = ArbitCode::ErrTimeout;
- reportArbitEvent(signal, EventReport::ArbitState);
+ reportArbitEvent(signal, NDB_LE_ArbitState);
arbitRec.state = ARBIT_CRASH;
arbitRec.newstate = true;
stateArbitCrash(signal); // do it at once
@@ -3834,7 +3834,7 @@ Qmgr::computeArbitNdbMask(NodeBitmask& aMask)
* where sender (word 0) is event type.
*/
void
-Qmgr::reportArbitEvent(Signal* signal, EventReport::EventType type)
+Qmgr::reportArbitEvent(Signal* signal, Ndb_logevent_type type)
{
ArbitSignalData* sd = (ArbitSignalData*)&signal->theData[0];
sd->sender = type;
diff --git a/ndb/src/kernel/blocks/suma/Suma.cpp b/ndb/src/kernel/blocks/suma/Suma.cpp
index 44ac054dd67..ed54505b729 100644
--- a/ndb/src/kernel/blocks/suma/Suma.cpp
+++ b/ndb/src/kernel/blocks/suma/Suma.cpp
@@ -50,6 +50,17 @@
//#define EVENT_DEBUG
//#define EVENT_PH3_DEBUG
//#define EVENT_DEBUG2
+#if 0
+#undef DBUG_ENTER
+#undef DBUG_PRINT
+#undef DBUG_RETURN
+#undef DBUG_VOID_RETURN
+
+#define DBUG_ENTER(a) {ndbout_c("%s:%d >%s", __FILE__, __LINE__, a);}
+#define DBUG_PRINT(a,b) {ndbout << __FILE__ << ":" << __LINE__ << " " << a << ": "; ndbout_c b ;}
+#define DBUG_RETURN(a) { ndbout_c("%s:%d <", __FILE__, __LINE__); return(a); }
+#define DBUG_VOID_RETURN { ndbout_c("%s:%d <", __FILE__, __LINE__); return; }
+#endif
/**
* @todo:
@@ -112,15 +123,12 @@ Suma::getNodeGroupMembers(Signal* signal) {
void
Suma::execSTTOR(Signal* signal) {
jamEntry();
-
+
+ DBUG_ENTER("Suma::execSTTOR");
const Uint32 startphase = signal->theData[1];
const Uint32 typeOfStart = signal->theData[7];
-#ifdef NODEFAIL_DEBUG
- ndbout_c ("SUMA::execSTTOR startphase = %u, typeOfStart = %u",
- startphase, typeOfStart);
-
-#endif
+ DBUG_PRINT("info",("startphase = %u, typeOfStart = %u", startphase, typeOfStart));
if(startphase == 1){
jam();
@@ -155,7 +163,7 @@ Suma::execSTTOR(Signal* signal) {
g_subPtrI = subPtr.i;
// sendSTTORRY(signal);
#endif
- return;
+ DBUG_VOID_RETURN;
}
if(startphase == 5) {
@@ -178,9 +186,7 @@ Suma::execSTTOR(Signal* signal) {
for( int i = 0; i < NO_OF_BUCKETS; i++) {
if (getResponsibleSumaNodeId(i) == refToNode(reference())) {
// I'm running this bucket
-#ifdef EVENT_DEBUG
- ndbout_c("bucket %u set to true", i);
-#endif
+ DBUG_PRINT("info",("bucket %u set to true", i));
c_buckets[i].active = true;
}
}
@@ -190,32 +196,31 @@ Suma::execSTTOR(Signal* signal) {
c_masterNodeId == getOwnNodeId()) {
jam();
createSequence(signal);
- return;
+ DBUG_VOID_RETURN;
}//if
}//if
sendSTTORRY(signal);
- return;
+ DBUG_VOID_RETURN;
}
void
Suma::createSequence(Signal* signal)
{
jam();
+ DBUG_ENTER("Suma::createSequence");
UtilSequenceReq * req = (UtilSequenceReq*)signal->getDataPtrSend();
req->senderData = RNIL;
req->sequenceId = SUMA_SEQUENCE;
req->requestType = UtilSequenceReq::Create;
-#ifdef DEBUG_SUMA_SEQUENCE
- ndbout_c("SUMA: Create sequence");
-#endif
sendSignal(DBUTIL_REF, GSN_UTIL_SEQUENCE_REQ,
signal, UtilSequenceReq::SignalLength, JBB);
// execUTIL_SEQUENCE_CONF will call createSequenceReply()
+ DBUG_VOID_RETURN;
}
void
@@ -338,6 +343,7 @@ SumaParticipant::execCONTINUEB(Signal* signal)
void Suma::execAPI_FAILREQ(Signal* signal)
{
jamEntry();
+ DBUG_ENTER("Suma::execAPI_FAILREQ");
Uint32 failedApiNode = signal->theData[0];
//BlockReference retRef = signal->theData[1];
@@ -348,11 +354,13 @@ void Suma::execAPI_FAILREQ(Signal* signal)
jam();
c_failedApiNodes.clear(failedApiNode);
}
+ DBUG_VOID_RETURN;
}//execAPI_FAILREQ()
bool
SumaParticipant::removeSubscribersOnNode(Signal *signal, Uint32 nodeId)
{
+ DBUG_ENTER("SumaParticipant::removeSubscribersOnNode");
bool found = false;
SubscriberPtr i_subbPtr;
@@ -372,20 +380,15 @@ SumaParticipant::removeSubscribersOnNode(Signal *signal, Uint32 nodeId)
jam();
sendSubStopReq(signal);
}
- return found;
+ DBUG_RETURN(found);
}
void
-SumaParticipant::sendSubStopReq(Signal *signal){
+SumaParticipant::sendSubStopReq(Signal *signal, bool unlock){
+ DBUG_ENTER("SumaParticipant::sendSubStopReq");
static bool remove_lock = false;
jam();
- if(remove_lock) {
- jam();
- return;
- }
- remove_lock = true;
-
SubscriberPtr subbPtr;
c_removeDataSubscribers.first(subbPtr);
if (subbPtr.isNull()){
@@ -398,9 +401,15 @@ SumaParticipant::sendSubStopReq(Signal *signal){
c_failedApiNodes.clear();
remove_lock = false;
- return;
+ DBUG_VOID_RETURN;
}
+ if(remove_lock && !unlock) {
+ jam();
+ DBUG_VOID_RETURN;
+ }
+ remove_lock = true;
+
SubscriptionPtr subPtr;
c_subscriptions.getPtr(subPtr, subbPtr.p->m_subPtrI);
@@ -414,11 +423,13 @@ SumaParticipant::sendSubStopReq(Signal *signal){
req->part = SubscriptionData::TableData;
sendSignal(SUMA_REF, GSN_SUB_STOP_REQ, signal, SubStopReq::SignalLength, JBB);
+ DBUG_VOID_RETURN;
}
void
SumaParticipant::execSUB_STOP_CONF(Signal* signal){
jamEntry();
+ DBUG_ENTER("SumaParticipant::execSUB_STOP_CONF");
SubStopConf * const conf = (SubStopConf*)signal->getDataPtr();
@@ -444,12 +455,15 @@ SumaParticipant::execSUB_STOP_CONF(Signal* signal){
}
}
- sendSubStopReq(signal);
+ sendSubStopReq(signal,true);
+ DBUG_VOID_RETURN;
}
void
SumaParticipant::execSUB_STOP_REF(Signal* signal){
jamEntry();
+ DBUG_ENTER("SumaParticipant::execSUB_STOP_REF");
+
SubStopRef * const ref = (SubStopRef*)signal->getDataPtr();
Uint32 subscriptionId = ref->subscriptionId;
@@ -471,11 +485,14 @@ SumaParticipant::execSUB_STOP_REF(Signal* signal){
req->part = part;
sendSignal(SUMA_REF, GSN_SUB_STOP_REQ, signal, SubStopReq::SignalLength, JBB);
+
+ DBUG_VOID_RETURN;
}
void
Suma::execNODE_FAILREP(Signal* signal){
jamEntry();
+ DBUG_ENTER("Suma::execNODE_FAILREP");
NodeFailRep * const rep = (NodeFailRep*)signal->getDataPtr();
@@ -541,6 +558,7 @@ Suma::execNODE_FAILREP(Signal* signal){
c_aliveNodes.clear(nodePtr.p->nodeId); // this has to be done after the loop above
}
}
+ DBUG_VOID_RETURN;
}
void
@@ -610,6 +628,19 @@ Suma::execSIGNAL_DROPPED_REP(Signal* signal){
*
*/
+static unsigned
+count_subscribers(const DLList<SumaParticipant::Subscriber> &subs)
+{
+ unsigned n= 0;
+ SumaParticipant::SubscriberPtr i_subbPtr;
+ subs.first(i_subbPtr);
+ while(!i_subbPtr.isNull()){
+ n++;
+ subs.next(i_subbPtr);
+ }
+ return n;
+}
+
void
Suma::execDUMP_STATE_ORD(Signal* signal){
jamEntry();
@@ -664,6 +695,15 @@ Suma::execDUMP_STATE_ORD(Signal* signal){
infoEvent("Suma: c_dataBufferPool size: %d free: %d",
c_dataBufferPool.getSize(),
c_dataBufferPool.getNoOfFree());
+
+ infoEvent("Suma: c_metaSubscribers count: %d",
+ count_subscribers(c_metaSubscribers));
+ infoEvent("Suma: c_dataSubscribers count: %d",
+ count_subscribers(c_dataSubscribers));
+ infoEvent("Suma: c_prepDataSubscribers count: %d",
+ count_subscribers(c_prepDataSubscribers));
+ infoEvent("Suma: c_removeDataSubscribers count: %d",
+ count_subscribers(c_removeDataSubscribers));
}
}
@@ -812,16 +852,14 @@ Suma::execUTIL_SEQUENCE_CONF(Signal* signal)
{
jamEntry();
+ DBUG_ENTER("Suma::execUTIL_SEQUENCE_CONF");
CRASH_INSERTION(13002);
UtilSequenceConf * conf = (UtilSequenceConf*)signal->getDataPtr();
-#ifdef DEBUG_SUMA_SEQUENCE
- ndbout_c("SUMA: Create sequence conf");
-#endif
if(conf->requestType == UtilSequenceReq::Create) {
jam();
createSequenceReply(signal, conf, NULL);
- return;
+ DBUG_VOID_RETURN;
}
Uint64 subId;
@@ -841,18 +879,21 @@ Suma::execUTIL_SEQUENCE_CONF(Signal* signal)
CreateSubscriptionIdConf::SignalLength, JBB);
c_subscriberPool.release(subbPtr);
+
+ DBUG_VOID_RETURN;
}
void
Suma::execUTIL_SEQUENCE_REF(Signal* signal)
{
jamEntry();
+ DBUG_ENTER("Suma::execUTIL_SEQUENCE_REF");
UtilSequenceRef * ref = (UtilSequenceRef*)signal->getDataPtr();
if(ref->requestType == UtilSequenceReq::Create) {
jam();
createSequenceReply(signal, NULL, ref);
- return;
+ DBUG_VOID_RETURN;
}
Uint32 subData = ref->senderData;
@@ -861,7 +902,7 @@ Suma::execUTIL_SEQUENCE_REF(Signal* signal)
c_subscriberPool.getPtr(subbPtr,subData);
sendSubIdRef(signal, GrepError::SEQUENCE_ERROR);
c_subscriberPool.release(subbPtr);
- return;
+ DBUG_VOID_RETURN;
}//execUTIL_SEQUENCE_REF()
@@ -1429,7 +1470,7 @@ SumaParticipant::execDIGETPRIMCONF(Signal* signal){
void
SumaParticipant::execCREATE_TRIG_CONF(Signal* signal){
jamEntry();
-
+ DBUG_ENTER("SumaParticipant::execCREATE_TRIG_CONF");
CRASH_INSERTION(13009);
CreateTrigConf * const conf = (CreateTrigConf*)signal->getDataPtr();
@@ -1442,6 +1483,7 @@ SumaParticipant::execCREATE_TRIG_CONF(Signal* signal){
* dodido
* @todo: I (Johan) dont know what to do here. Jonas, what do you mean?
*/
+ DBUG_VOID_RETURN;
}
void
@@ -1453,7 +1495,7 @@ SumaParticipant::execCREATE_TRIG_REF(Signal* signal){
void
SumaParticipant::execDROP_TRIG_CONF(Signal* signal){
jamEntry();
-
+ DBUG_ENTER("SumaParticipant::execDROP_TRIG_CONF");
CRASH_INSERTION(13010);
DropTrigConf * const conf = (DropTrigConf*)signal->getDataPtr();
@@ -1461,17 +1503,19 @@ SumaParticipant::execDROP_TRIG_CONF(Signal* signal){
const Uint32 senderData = conf->getConnectionPtr();
SyncRecord* tmp = c_syncPool.getPtr(senderData);
tmp->runDROP_TRIG_CONF(signal);
+ DBUG_VOID_RETURN;
}
void
SumaParticipant::execDROP_TRIG_REF(Signal* signal){
jamEntry();
-
+ DBUG_ENTER("SumaParticipant::execDROP_TRIG_CONF");
DropTrigRef * const ref = (DropTrigRef*)signal->getDataPtr();
const Uint32 senderData = ref->getConnectionPtr();
SyncRecord* tmp = c_syncPool.getPtr(senderData);
tmp->runDROP_TRIG_CONF(signal);
+ DBUG_VOID_RETURN;
}
/*************************************************************************
@@ -2055,9 +2099,7 @@ SumaParticipant::execSCAN_HBREP(Signal* signal){
void
SumaParticipant::execSUB_START_REQ(Signal* signal){
jamEntry();
-#ifdef NODEFAIL_DEBUG
- ndbout_c("Suma::execSUB_START_REQ");
-#endif
+ DBUG_ENTER("SumaParticipant::execSUB_START_REQ");
CRASH_INSERTION(13013);
@@ -2067,7 +2109,7 @@ SumaParticipant::execSUB_START_REQ(Signal* signal){
if (RtoI(signal->getSendersBlockRef(), false) == RNIL) {
jam();
sendSubStartRef(signal, /** Error Code */ 0, true);
- return;
+ DBUG_VOID_RETURN;
}
// only allow other Suma's in the nodegroup to come through for restart purposes
}
@@ -2088,7 +2130,7 @@ SumaParticipant::execSUB_START_REQ(Signal* signal){
if(!c_subscriptions.find(subPtr, key)){
jam();
sendSubStartRef(signal, /** Error Code */ 0);
- return;
+ DBUG_VOID_RETURN;
}
Ptr<SyncRecord> syncPtr;
@@ -2099,7 +2141,7 @@ SumaParticipant::execSUB_START_REQ(Signal* signal){
ndbout_c("Locked");
#endif
sendSubStartRef(signal, /** Error Code */ 0, true);
- return;
+ DBUG_VOID_RETURN;
}
syncPtr.p->m_locked = true;
@@ -2108,7 +2150,7 @@ SumaParticipant::execSUB_START_REQ(Signal* signal){
jam();
syncPtr.p->m_locked = false;
sendSubStartRef(signal, /** Error Code */ 0);
- return;
+ DBUG_VOID_RETURN;
}
Uint32 type = subPtr.p->m_subscriptionType;
@@ -2175,6 +2217,7 @@ SumaParticipant::execSUB_START_REQ(Signal* signal){
break;
}
ndbrequire(ok);
+ DBUG_VOID_RETURN;
}
void
@@ -2799,7 +2842,7 @@ SumaParticipant::decideWhoToSend(Uint32 nBucket, Uint32 gci){
void
SumaParticipant::execFIRE_TRIG_ORD(Signal* signal){
jamEntry();
-
+ DBUG_ENTER("SumaParticipant::execFIRE_TRIG_ORD");
CRASH_INSERTION(13016);
FireTrigOrd* const trg = (FireTrigOrd*)signal->getDataPtr();
const Uint32 trigId = trg->getTriggerId();
@@ -2927,6 +2970,7 @@ SumaParticipant::execFIRE_TRIG_ORD(Signal* signal){
}
}
#endif
+ DBUG_PRINT("info",("GSN_SUB_TABLE_DATA to node %d", refToNode(ref)));
sendSignal(ref, GSN_SUB_TABLE_DATA, signal,
SubTableData::SignalLength, JBB, ptr, nptr);
data->logType = tmp;
@@ -2960,6 +3004,8 @@ SumaParticipant::execFIRE_TRIG_ORD(Signal* signal){
*/
f_bufferLock = 0;
b_bufferLock = 0;
+
+ DBUG_VOID_RETURN;
}
void
@@ -3225,6 +3271,7 @@ bool SumaParticipant::FailoverBuffer::nodeFailRep()
void
SumaParticipant::execSUB_STOP_REQ(Signal* signal){
jamEntry();
+ DBUG_ENTER("SumaParticipant::execSUB_STOP_REQ");
CRASH_INSERTION(13019);
@@ -3254,7 +3301,7 @@ SumaParticipant::execSUB_STOP_REQ(Signal* signal){
SubStopConf::SignalLength, JBB);
removeSubscribersOnNode(signal, refToNode(subscriberRef));
- return;
+ DBUG_VOID_RETURN;
}
if(!c_subscriptions.find(subPtr, key)){
@@ -3280,7 +3327,7 @@ SumaParticipant::execSUB_STOP_REQ(Signal* signal){
for (;!subbPtr.isNull(); c_dataSubscribers.next(subbPtr)){
jam();
if (subbPtr.p->m_subPtrI == subPtr.i &&
- subbPtr.p->m_subscriberRef == subscriberRef &&
+ refToNode(subbPtr.p->m_subscriberRef) == refToNode(subscriberRef) &&
subbPtr.p->m_subscriberData == subscriberData){
// ndbout_c("STOP_REQ: before c_dataSubscribers.release");
jam();
@@ -3295,7 +3342,7 @@ SumaParticipant::execSUB_STOP_REQ(Signal* signal){
if (!found) {
jam();
sendSubStopRef(signal, GrepError::SUBSCRIBER_NOT_FOUND);
- return;
+ DBUG_VOID_RETURN;
}
}
@@ -3308,11 +3355,12 @@ SumaParticipant::execSUB_STOP_REQ(Signal* signal){
if (syncPtr.p->m_locked) {
jam();
sendSubStopRef(signal, /** Error Code */ 0, true);
- return;
+ DBUG_VOID_RETURN;
}
syncPtr.p->m_locked = true;
syncPtr.p->startDropTrigger(signal);
+ DBUG_VOID_RETURN;
}
void
@@ -3508,6 +3556,8 @@ SumaParticipant::sendSubRemoveRef(Signal* signal, const SubRemoveReq& req,
jam();
SubRemoveRef * ref = (SubRemoveRef *)signal->getDataPtrSend();
ref->senderRef = reference();
+ ref->subscriptionId = req.subscriptionId;
+ ref->subscriptionKey = req.subscriptionKey;
ref->senderData = req.senderData;
ref->err = errCode;
if (temporary)
diff --git a/ndb/src/kernel/blocks/suma/Suma.hpp b/ndb/src/kernel/blocks/suma/Suma.hpp
index 08987fa9420..65869f44423 100644
--- a/ndb/src/kernel/blocks/suma/Suma.hpp
+++ b/ndb/src/kernel/blocks/suma/Suma.hpp
@@ -376,7 +376,7 @@ public:
void sendSubStartComplete(Signal*, SubscriberPtr, Uint32,
SubscriptionData::Part);
void sendSubStopComplete(Signal*, SubscriberPtr);
- void sendSubStopReq(Signal* signal);
+ void sendSubStopReq(Signal* signal, bool unlock= false);
void completeSubRemoveReq(Signal* signal, SubscriptionPtr subPtr);
diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp
index 1e5cd5270e4..543757153d3 100644
--- a/ndb/src/kernel/main.cpp
+++ b/ndb/src/kernel/main.cpp
@@ -19,6 +19,7 @@
#include <ndb_version.h>
#include "Configuration.hpp"
+#include <ConfigRetriever.hpp>
#include <TransporterRegistry.hpp>
#include "vm/SimBlockList.hpp"
@@ -36,6 +37,8 @@
#include <NdbAutoPtr.hpp>
+#include <mgmapi_debug.h>
+
#if defined NDB_SOLARIS // ok
#include <sys/processor.h> // For system informatio
#endif
@@ -90,7 +93,7 @@ int main(int argc, char** argv)
return 1;
}
}
-
+
#ifndef NDB_WIN32
for(pid_t child = fork(); child != 0; child = fork()){
/**
@@ -189,6 +192,13 @@ int main(int argc, char** argv)
exit(-1);
}
+ // Re-use the mgm handle as a transporter
+ if(!globalTransporterRegistry.connect_client(
+ theConfig->get_config_retriever()->get_mgmHandlePtr()))
+ ERROR_SET(fatal, ERR_INVALID_CONFIG,
+ "Connection to mgmd terminated before setup was complete",
+ "StopOnError missing");
+
if (!globalTransporterRegistry.start_clients()){
ndbout_c("globalTransporterRegistry.start_clients() failed");
exit(-1);
diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp
index de78a4e927c..650d914035f 100644
--- a/ndb/src/kernel/vm/Configuration.cpp
+++ b/ndb/src/kernel/vm/Configuration.cpp
@@ -88,13 +88,6 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt,
- argument ? argument : "d:t:O,/tmp/ndbd.trace");
-}
bool
Configuration::init(int argc, char** argv)
@@ -103,7 +96,11 @@ Configuration::init(int argc, char** argv)
load_defaults("my",load_default_groups,&argc,&argv);
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndbd.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
exit(ho_error);
if (_no_daemon) {
@@ -156,6 +153,7 @@ Configuration::Configuration()
_daemonMode = false;
m_config_retriever= 0;
m_clusterConfig= 0;
+ m_clusterConfigIter= 0;
}
Configuration::~Configuration(){
@@ -191,7 +189,6 @@ Configuration::fetch_configuration(){
}
m_mgmd_port= 0;
- m_mgmd_host= 0;
m_config_retriever= new ConfigRetriever(getConnectString(),
NDB_VERSION, NODE_TYPE_DB);
@@ -213,7 +210,7 @@ Configuration::fetch_configuration(){
}
m_mgmd_port= m_config_retriever->get_mgmd_port();
- m_mgmd_host= m_config_retriever->get_mgmd_host();
+ m_mgmd_host.assign(m_config_retriever->get_mgmd_host());
ConfigRetriever &cr= *m_config_retriever;
@@ -372,6 +369,8 @@ Configuration::setupConfiguration(){
ConfigValues* cf = ConfigValuesFactory::extractCurrentSection(iter.m_config);
+ if(m_clusterConfigIter)
+ ndb_mgm_destroy_iterator(m_clusterConfigIter);
m_clusterConfigIter = ndb_mgm_create_configuration_iterator
(p, CFG_SECTION_NODE);
diff --git a/ndb/src/kernel/vm/Configuration.hpp b/ndb/src/kernel/vm/Configuration.hpp
index acf0e163a84..6ca6d9a1f17 100644
--- a/ndb/src/kernel/vm/Configuration.hpp
+++ b/ndb/src/kernel/vm/Configuration.hpp
@@ -17,6 +17,7 @@
#ifndef Configuration_H
#define Configuration_H
+#include <util/BaseString.hpp>
#include <mgmapi.h>
#include <ndb_types.h>
@@ -67,7 +68,8 @@ public:
const ndb_mgm_configuration_iterator * getOwnConfigIterator() const;
Uint32 get_mgmd_port() const {return m_mgmd_port;};
- const char *get_mgmd_host() const {return m_mgmd_host;};
+ const char *get_mgmd_host() const {return m_mgmd_host.c_str();};
+ ConfigRetriever* get_config_retriever() { return m_config_retriever; };
class LogLevel * m_logLevel;
private:
@@ -98,7 +100,7 @@ private:
bool _initialStart;
char * _connectString;
Uint32 m_mgmd_port;
- const char *m_mgmd_host;
+ BaseString m_mgmd_host;
bool _daemonMode;
void calcSizeAlt(class ConfigValues * );
diff --git a/ndb/src/kernel/vm/FastScheduler.cpp b/ndb/src/kernel/vm/FastScheduler.cpp
index d0b7af27463..a2d806571fe 100644
--- a/ndb/src/kernel/vm/FastScheduler.cpp
+++ b/ndb/src/kernel/vm/FastScheduler.cpp
@@ -487,7 +487,7 @@ FastScheduler::reportDoJobStatistics(Uint32 tMeanLoopCount) {
Signal signal;
memset(&signal.header, 0, sizeof(signal.header));
- signal.theData[0] = EventReport::JobStatistic;
+ signal.theData[0] = NDB_LE_JobStatistic;
signal.theData[1] = tMeanLoopCount;
memset(&signal.header, 0, sizeof(SignalHeader));
diff --git a/ndb/src/kernel/vm/MetaData.hpp b/ndb/src/kernel/vm/MetaData.hpp
index 11e262664c1..1000114a421 100644
--- a/ndb/src/kernel/vm/MetaData.hpp
+++ b/ndb/src/kernel/vm/MetaData.hpp
@@ -86,15 +86,9 @@ public:
/* Primary table of index otherwise RNIL */
Uint32 primaryTableId;
- /* Type of storage (memory/disk, not used) */
- DictTabInfo::StorageType storageType;
-
/* Type of fragmentation (small/medium/large) */
DictTabInfo::FragmentType fragmentType;
- /* Key type of fragmentation (pk/dist key/dist group) */
- DictTabInfo::FragmentKeyType fragmentKeyType;
-
/* Global checkpoint identity when table created */
Uint32 gciTableCreated;
@@ -166,7 +160,6 @@ public:
Uint32 attributeDescriptor;
/* Extended attributes */
- Uint32 extType;
Uint32 extPrecision;
Uint32 extScale;
Uint32 extLength;
diff --git a/ndb/src/kernel/vm/SimulatedBlock.cpp b/ndb/src/kernel/vm/SimulatedBlock.cpp
index 94fd5769406..35c0781a24d 100644
--- a/ndb/src/kernel/vm/SimulatedBlock.cpp
+++ b/ndb/src/kernel/vm/SimulatedBlock.cpp
@@ -735,7 +735,7 @@ SimulatedBlock::infoEvent(const char * msg, ...) const {
return;
Uint32 theData[25];
- theData[0] = EventReport::InfoEvent;
+ theData[0] = NDB_LE_InfoEvent;
char * buf = (char *)&(theData[1]);
va_list ap;
@@ -776,7 +776,7 @@ SimulatedBlock::warningEvent(const char * msg, ...) const {
return;
Uint32 theData[25];
- theData[0] = EventReport::WarningEvent;
+ theData[0] = NDB_LE_WarningEvent;
char * buf = (char *)&(theData[1]);
va_list ap;
diff --git a/ndb/src/kernel/vm/TransporterCallback.cpp b/ndb/src/kernel/vm/TransporterCallback.cpp
index ba929b7ea7a..0f292143c21 100644
--- a/ndb/src/kernel/vm/TransporterCallback.cpp
+++ b/ndb/src/kernel/vm/TransporterCallback.cpp
@@ -337,9 +337,9 @@ reportError(void * callbackObj, NodeId nodeId, TransporterError errorCode){
if(errorCode & 0x8000)
- signal.theData[0] = EventReport::TransporterError;
+ signal.theData[0] = NDB_LE_TransporterError;
else
- signal.theData[0] = EventReport::TransporterWarning;
+ signal.theData[0] = NDB_LE_TransporterWarning;
signal.theData[1] = nodeId;
signal.theData[2] = errorCode;
@@ -363,7 +363,7 @@ reportSendLen(void * callbackObj,
signal.header.theLength = 3;
signal.header.theSendersSignalId = 0;
signal.header.theSendersBlockRef = numberToRef(0, globalData.ownId);
- signal.theData[0] = EventReport::SendBytesStatistic;
+ signal.theData[0] = NDB_LE_SendBytesStatistic;
signal.theData[1] = nodeId;
signal.theData[2] = (bytes/count);
globalScheduler.execute(&signal, JBA, CMVMI, GSN_EVENT_REP);
@@ -382,7 +382,7 @@ reportReceiveLen(void * callbackObj,
signal.header.theLength = 3;
signal.header.theSendersSignalId = 0;
signal.header.theSendersBlockRef = numberToRef(0, globalData.ownId);
- signal.theData[0] = EventReport::ReceiveBytesStatistic;
+ signal.theData[0] = NDB_LE_ReceiveBytesStatistic;
signal.theData[1] = nodeId;
signal.theData[2] = (bytes/count);
globalScheduler.execute(&signal, JBA, CMVMI, GSN_EVENT_REP);
diff --git a/ndb/src/kernel/vm/VMSignal.hpp b/ndb/src/kernel/vm/VMSignal.hpp
index 9111ee7949c..45543c5d174 100644
--- a/ndb/src/kernel/vm/VMSignal.hpp
+++ b/ndb/src/kernel/vm/VMSignal.hpp
@@ -78,10 +78,16 @@ public:
#define VMS_DATA_SIZE \
(MAX_ATTRIBUTES_IN_TABLE + MAX_TUPLE_SIZE_IN_WORDS + MAX_KEY_SIZE_IN_WORDS)
+#if VMS_DATA_SIZE > 8192
+#error "VMSignal buffer is too small"
+#endif
+
SignalHeader header; // 28 bytes
SegmentedSectionPtr m_sectionPtr[3];
- Uint32 theData[25+VMS_DATA_SIZE]; // 2048 32-bit words -> 8K Bytes
-
+ union {
+ Uint32 theData[8192]; // 8192 32-bit words -> 32K Bytes
+ Uint64 dummyAlign;
+ };
void garbage_register();
};
diff --git a/ndb/src/mgmapi/LocalConfig.cpp b/ndb/src/mgmapi/LocalConfig.cpp
index 0265f982df3..75ad8b40a1f 100644
--- a/ndb/src/mgmapi/LocalConfig.cpp
+++ b/ndb/src/mgmapi/LocalConfig.cpp
@@ -27,7 +27,9 @@ LocalConfig::LocalConfig(){
bool
LocalConfig::init(const char *connectString,
- const char *fileName) {
+ const char *fileName)
+{
+ DBUG_ENTER("LocalConfig::init");
/**
* Escalation:
* 1. Check connectString
@@ -38,21 +40,25 @@ LocalConfig::init(const char *connectString,
* 6. Check defaultConnectString
*/
+ _ownNodeId= 0;
+
//1. Check connectString
if(connectString != 0 && connectString[0] != 0){
if(readConnectString(connectString, "connect string")){
- return true;
- }
- return false;
+ if (ids.size())
+ DBUG_RETURN(true);
+ // only nodeid given, continue to find hosts
+ } else
+ DBUG_RETURN(false);
}
//2. Check given filename
if (fileName && strlen(fileName) > 0) {
bool fopenError;
if(readFile(fileName, fopenError)){
- return true;
+ DBUG_RETURN(true);
}
- return false;
+ DBUG_RETURN(false);
}
//3. Check environment variable
@@ -60,9 +66,9 @@ LocalConfig::init(const char *connectString,
if(NdbEnv_GetEnv("NDB_CONNECTSTRING", buf, sizeof(buf)) &&
strlen(buf) != 0){
if(readConnectString(buf, "NDB_CONNECTSTRING")){
- return true;
+ DBUG_RETURN(true);
}
- return false;
+ DBUG_RETURN(false);
}
//4. Check Ndb.cfg in NDB_HOME
@@ -71,9 +77,9 @@ LocalConfig::init(const char *connectString,
char *buf= NdbConfig_NdbCfgName(1 /*true*/);
NdbAutoPtr<char> tmp_aptr(buf);
if(readFile(buf, fopenError))
- return true;
+ DBUG_RETURN(true);
if (!fopenError)
- return false;
+ DBUG_RETURN(false);
}
//5. Check Ndb.cfg in cwd
@@ -82,9 +88,9 @@ LocalConfig::init(const char *connectString,
char *buf= NdbConfig_NdbCfgName(0 /*false*/);
NdbAutoPtr<char> tmp_aptr(buf);
if(readFile(buf, fopenError))
- return true;
+ DBUG_RETURN(true);
if (!fopenError)
- return false;
+ DBUG_RETURN(false);
}
//7. Check
@@ -92,12 +98,12 @@ LocalConfig::init(const char *connectString,
char buf[256];
BaseString::snprintf(buf, sizeof(buf), "host=localhost:%s", NDB_PORT);
if(readConnectString(buf, "default connect string"))
- return true;
+ DBUG_RETURN(true);
}
setError(0, "");
- return false;
+ DBUG_RETURN(false);
}
LocalConfig::~LocalConfig(){
@@ -142,6 +148,7 @@ const char *nodeIdTokens[] = {
const char *hostNameTokens[] = {
"host://%[^:]:%i",
"host=%[^:]:%i",
+ "mgmd=%[^:]:%i",
"%[^:^=^ ]:%i",
"%s %i",
0
@@ -207,36 +214,22 @@ LocalConfig::parseString(const char * connectString, BaseString &err){
char * copy = strdup(connectString);
NdbAutoPtr<char> tmp_aptr(copy);
- bool b_nodeId = false;
- bool found_other = false;
-
for (char *tok = strtok_r(copy,";,",&for_strtok); tok != 0;
tok = strtok_r(NULL, ";,", &for_strtok)) {
if (tok[0] == '#') continue;
- if (!b_nodeId) // only one nodeid definition allowed
- if (b_nodeId = parseNodeId(tok))
+ if (!_ownNodeId) // only one nodeid definition allowed
+ if (parseNodeId(tok))
continue;
- if (found_other = parseHostName(tok))
+ if (parseHostName(tok))
continue;
- if (found_other = parseFileName(tok))
+ if (parseFileName(tok))
continue;
err.assfmt("Unexpected entry: \"%s\"", tok);
return false;
}
- if (b_nodeId && !found_other)
- {
- BaseString tmp;
- tmp.assfmt("host=localhost:%s", NDB_PORT);
- if(parseHostName(tmp.c_str()))
- return true;
-
- err.appfmt("Missing host/file name extry in \"%s\"", connectString);
- return false;
- }
-
return true;
}
diff --git a/ndb/src/mgmapi/Makefile.am b/ndb/src/mgmapi/Makefile.am
index 2f2fb407e46..db730bf8c89 100644
--- a/ndb/src/mgmapi/Makefile.am
+++ b/ndb/src/mgmapi/Makefile.am
@@ -1,7 +1,7 @@
noinst_LTLIBRARIES = libmgmapi.la
-libmgmapi_la_SOURCES = mgmapi.cpp mgmapi_configuration.cpp LocalConfig.cpp
+libmgmapi_la_SOURCES = mgmapi.cpp ndb_logevent.cpp mgmapi_configuration.cpp LocalConfig.cpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/include/mgmapi
diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp
index a8931fb32ea..ab32de5b9ca 100644
--- a/ndb/src/mgmapi/mgmapi.cpp
+++ b/ndb/src/mgmapi/mgmapi.cpp
@@ -22,8 +22,9 @@
#include <NdbSleep.h>
#include <NdbTCP.h>
-#include "mgmapi.h"
-#include "mgmapi_debug.h"
+#include <mgmapi.h>
+#include <mgmapi_internal.h>
+#include <mgmapi_debug.h>
#include "mgmapi_configuration.hpp"
#include <socket_io.h>
@@ -143,6 +144,7 @@ extern "C"
NdbMgmHandle
ndb_mgm_create_handle()
{
+ DBUG_ENTER("ndb_mgm_create_handle");
NdbMgmHandle h =
(NdbMgmHandle)my_malloc(sizeof(ndb_mgm_handle),MYF(MY_WME));
h->connected = 0;
@@ -151,7 +153,7 @@ ndb_mgm_create_handle()
h->socket = NDB_INVALID_SOCKET;
h->read_timeout = 50000;
h->write_timeout = 100;
- h->cfg_i = 0;
+ h->cfg_i = -1;
strncpy(h->last_error_desc, "No error", NDB_MGM_MAX_ERR_DESC_SIZE);
@@ -162,24 +164,29 @@ ndb_mgm_create_handle()
h->logfile = 0;
#endif
- return h;
+ DBUG_PRINT("info", ("handle=0x%x", (UintPtr)h));
+ DBUG_RETURN(h);
}
extern "C"
int
ndb_mgm_set_connectstring(NdbMgmHandle handle, const char * mgmsrv)
{
+ DBUG_ENTER("ndb_mgm_set_connectstring");
+ DBUG_PRINT("info", ("handle=0x%x", (UintPtr)handle));
+ handle->cfg.~LocalConfig();
new (&(handle->cfg)) LocalConfig;
if (!handle->cfg.init(mgmsrv, 0) ||
handle->cfg.ids.size() == 0)
{
+ handle->cfg.~LocalConfig();
new (&(handle->cfg)) LocalConfig;
- handle->cfg.init(0, 0); /* reset the LocalCongig */
+ handle->cfg.init(0, 0); /* reset the LocalConfig */
SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, "");
- return -1;
+ DBUG_RETURN(-1);
}
- handle->cfg_i= 0;
- return 0;
+ handle->cfg_i= -1;
+ DBUG_RETURN(0);
}
/**
@@ -189,8 +196,14 @@ extern "C"
void
ndb_mgm_destroy_handle(NdbMgmHandle * handle)
{
+ DBUG_ENTER("ndb_mgm_destroy_handle");
if(!handle)
- return;
+ DBUG_VOID_RETURN;
+ DBUG_PRINT("info", ("handle=0x%x", (UintPtr)(* handle)));
+ /**
+ * important! only disconnect if connected
+ * other code relies on this
+ */
if((* handle)->connected){
ndb_mgm_disconnect(* handle);
}
@@ -203,6 +216,7 @@ ndb_mgm_destroy_handle(NdbMgmHandle * handle)
(*handle)->cfg.~LocalConfig();
my_free((char*)* handle,MYF(MY_ALLOW_ZERO_PTR));
* handle = 0;
+ DBUG_VOID_RETURN;
}
/*****************************************************************************
@@ -287,8 +301,11 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply,
out.println("%s: %s", name, val_s.c_str());
break;
case PropertiesType_Properties:
+ DBUG_PRINT("info",("Ignoring PropertiesType_Properties."));
/* Ignore */
break;
+ default:
+ DBUG_PRINT("info",("Ignoring PropertiesType: %d.",t));
}
}
#ifdef MGMAPI_LOG
@@ -304,14 +321,17 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply,
ParserDummy session(handle->socket);
Parser_t parser(command_reply, in, true, true, true);
-#if 1
const Properties* p = parser.parse(ctx, session);
if (p == NULL){
/**
* Print some info about why the parser returns NULL
*/
- //ndbout << " status=" << ctx.m_status << ", curr="
- //<< ctx.m_currentToken << endl;
+ ndbout << "Error in mgm protocol parser. "
+ << "cmd: '" << cmd
+ << "' status=" << (Uint32)ctx.m_status
+ << ", curr=" << ctx.m_currentToken
+ << endl;
+ DBUG_PRINT("info",("parser.parse returned NULL"));
}
#ifdef MGMAPI_LOG
else {
@@ -322,9 +342,17 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply,
}
#endif
return p;
-#else
- return parser.parse(ctx, session);
-#endif
+}
+
+/**
+ * Returns true if connected
+ */
+extern "C"
+int ndb_mgm_is_connected(NdbMgmHandle handle)
+{
+ if(!handle)
+ return 0;
+ return handle->connected;
}
/**
@@ -338,6 +366,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries,
SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_connect");
CHECK_HANDLE(handle, -1);
+ DBUG_ENTER("ndb_mgm_connect");
#ifdef MGMAPI_LOG
/**
* Open the log file
@@ -367,6 +396,13 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries,
}
if (sockfd != NDB_INVALID_SOCKET)
break;
+#ifndef DBUG_OFF
+ {
+ char buf[1024];
+ DBUG_PRINT("info",("Unable to connect with connect string: %s",
+ cfg.makeConnectString(buf,sizeof(buf))));
+ }
+#endif
if (verbose > 0) {
char buf[1024];
ndbout_c("Unable to connect with connect string: %s",
@@ -380,7 +416,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries,
cfg.makeConnectString(buf,sizeof(buf)));
if (verbose == -2)
ndbout << ", failed." << endl;
- return -1;
+ DBUG_RETURN(-1);
}
if (verbose == -1) {
ndbout << "Retrying every " << retry_delay_in_seconds << " seconds";
@@ -408,7 +444,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries,
handle->socket = sockfd;
handle->connected = 1;
- return 0;
+ DBUG_RETURN(0);
}
/**
@@ -626,7 +662,6 @@ ndb_mgm_get_status(NdbMgmHandle handle)
malloc(sizeof(ndb_mgm_cluster_state)+
noOfNodes*(sizeof(ndb_mgm_node_state)+sizeof("000.000.000.000#")));
- state->hostname= 0;
state->no_of_nodes= noOfNodes;
ndb_mgm_node_state * ptr = &state->node_states[0];
int nodeId = 0;
@@ -914,67 +949,68 @@ ndb_mgm_restart(NdbMgmHandle handle, int no_of_nodes, const int *node_list)
return ndb_mgm_restart2(handle, no_of_nodes, node_list, 0, 0, 0);
}
-static const char *clusterlog_level_names[]=
+static const char *clusterlog_severity_names[]=
{ "enabled", "debug", "info", "warning", "error", "critical", "alert" };
-struct ndb_mgm_clusterlog_levels
+struct ndb_mgm_event_severities
{
const char* name;
- enum ndb_mgm_clusterlog_level level;
-} clusterlog_levels[] = {
- { clusterlog_level_names[0], NDB_MGM_CLUSTERLOG_ON },
- { clusterlog_level_names[1], NDB_MGM_CLUSTERLOG_DEBUG },
- { clusterlog_level_names[2], NDB_MGM_CLUSTERLOG_INFO },
- { clusterlog_level_names[3], NDB_MGM_CLUSTERLOG_WARNING },
- { clusterlog_level_names[4], NDB_MGM_CLUSTERLOG_ERROR },
- { clusterlog_level_names[5], NDB_MGM_CLUSTERLOG_CRITICAL },
- { clusterlog_level_names[6], NDB_MGM_CLUSTERLOG_ALERT },
- { "all", NDB_MGM_CLUSTERLOG_ALL },
- { 0, NDB_MGM_ILLEGAL_CLUSTERLOG_LEVEL },
+ enum ndb_mgm_event_severity severity;
+} clusterlog_severities[] = {
+ { clusterlog_severity_names[0], NDB_MGM_EVENT_SEVERITY_ON },
+ { clusterlog_severity_names[1], NDB_MGM_EVENT_SEVERITY_DEBUG },
+ { clusterlog_severity_names[2], NDB_MGM_EVENT_SEVERITY_INFO },
+ { clusterlog_severity_names[3], NDB_MGM_EVENT_SEVERITY_WARNING },
+ { clusterlog_severity_names[4], NDB_MGM_EVENT_SEVERITY_ERROR },
+ { clusterlog_severity_names[5], NDB_MGM_EVENT_SEVERITY_CRITICAL },
+ { clusterlog_severity_names[6], NDB_MGM_EVENT_SEVERITY_ALERT },
+ { "all", NDB_MGM_EVENT_SEVERITY_ALL },
+ { 0, NDB_MGM_ILLEGAL_EVENT_SEVERITY },
};
extern "C"
-ndb_mgm_clusterlog_level
-ndb_mgm_match_clusterlog_level(const char * name)
+ndb_mgm_event_severity
+ndb_mgm_match_event_severity(const char * name)
{
if(name == 0)
- return NDB_MGM_ILLEGAL_CLUSTERLOG_LEVEL;
+ return NDB_MGM_ILLEGAL_EVENT_SEVERITY;
- for(int i = 0; clusterlog_levels[i].name !=0 ; i++)
- if(strcasecmp(name, clusterlog_levels[i].name) == 0)
- return clusterlog_levels[i].level;
+ for(int i = 0; clusterlog_severities[i].name !=0 ; i++)
+ if(strcasecmp(name, clusterlog_severities[i].name) == 0)
+ return clusterlog_severities[i].severity;
- return NDB_MGM_ILLEGAL_CLUSTERLOG_LEVEL;
+ return NDB_MGM_ILLEGAL_EVENT_SEVERITY;
}
extern "C"
const char *
-ndb_mgm_get_clusterlog_level_string(enum ndb_mgm_clusterlog_level level)
+ndb_mgm_get_event_severity_string(enum ndb_mgm_event_severity severity)
{
- int i= (int)level;
- if (i >= 0 && i < (int)NDB_MGM_CLUSTERLOG_ALL)
- return clusterlog_level_names[i];
- for(i = (int)NDB_MGM_CLUSTERLOG_ALL; clusterlog_levels[i].name != 0; i++)
- if(clusterlog_levels[i].level == level)
- return clusterlog_levels[i].name;
+ int i= (int)severity;
+ if (i >= 0 && i < (int)NDB_MGM_EVENT_SEVERITY_ALL)
+ return clusterlog_severity_names[i];
+ for(i = (int)NDB_MGM_EVENT_SEVERITY_ALL; clusterlog_severities[i].name != 0; i++)
+ if(clusterlog_severities[i].severity == severity)
+ return clusterlog_severities[i].name;
return 0;
}
extern "C"
-unsigned int *
-ndb_mgm_get_logfilter(NdbMgmHandle handle)
+const unsigned int *
+ndb_mgm_get_clusterlog_severity_filter(NdbMgmHandle handle)
{
- SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_get_logfilter");
- static Uint32 enabled[(int)NDB_MGM_CLUSTERLOG_ALL] = {0,0,0,0,0,0,0};
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_get_clusterlog_severity_filter");
+ static unsigned int enabled[(int)NDB_MGM_EVENT_SEVERITY_ALL]=
+ {0,0,0,0,0,0,0};
const ParserRow<ParserDummy> getinfo_reply[] = {
MGM_CMD("clusterlog", NULL, ""),
- MGM_ARG(clusterlog_level_names[0], Int, Mandatory, ""),
- MGM_ARG(clusterlog_level_names[1], Int, Mandatory, ""),
- MGM_ARG(clusterlog_level_names[2], Int, Mandatory, ""),
- MGM_ARG(clusterlog_level_names[3], Int, Mandatory, ""),
- MGM_ARG(clusterlog_level_names[4], Int, Mandatory, ""),
- MGM_ARG(clusterlog_level_names[5], Int, Mandatory, ""),
- MGM_ARG(clusterlog_level_names[6], Int, Mandatory, ""),
+ MGM_ARG(clusterlog_severity_names[0], Int, Mandatory, ""),
+ MGM_ARG(clusterlog_severity_names[1], Int, Mandatory, ""),
+ MGM_ARG(clusterlog_severity_names[2], Int, Mandatory, ""),
+ MGM_ARG(clusterlog_severity_names[3], Int, Mandatory, ""),
+ MGM_ARG(clusterlog_severity_names[4], Int, Mandatory, ""),
+ MGM_ARG(clusterlog_severity_names[5], Int, Mandatory, ""),
+ MGM_ARG(clusterlog_severity_names[6], Int, Mandatory, ""),
};
CHECK_HANDLE(handle, NULL);
CHECK_CONNECTED(handle, NULL);
@@ -984,20 +1020,21 @@ ndb_mgm_get_logfilter(NdbMgmHandle handle)
reply = ndb_mgm_call(handle, getinfo_reply, "get info clusterlog", &args);
CHECK_REPLY(reply, NULL);
- for(int i=0; i < (int)NDB_MGM_CLUSTERLOG_ALL; i++) {
- reply->get(clusterlog_level_names[i], &enabled[i]);
+ for(int i=0; i < (int)NDB_MGM_EVENT_SEVERITY_ALL; i++) {
+ reply->get(clusterlog_severity_names[i], &enabled[i]);
}
return enabled;
}
extern "C"
int
-ndb_mgm_filter_clusterlog(NdbMgmHandle handle,
- enum ndb_mgm_clusterlog_level level,
- int enable,
- struct ndb_mgm_reply* /*reply*/)
+ndb_mgm_set_clusterlog_severity_filter(NdbMgmHandle handle,
+ enum ndb_mgm_event_severity severity,
+ int enable,
+ struct ndb_mgm_reply* /*reply*/)
{
- SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_filter_clusterlog");
+ SET_ERROR(handle, NDB_MGM_NO_ERROR,
+ "Executing: ndb_mgm_set_clusterlog_severity_filter");
const ParserRow<ParserDummy> filter_reply[] = {
MGM_CMD("set logfilter reply", NULL, ""),
MGM_ARG("result", String, Mandatory, "Error message"),
@@ -1008,7 +1045,7 @@ ndb_mgm_filter_clusterlog(NdbMgmHandle handle,
CHECK_CONNECTED(handle, -1);
Properties args;
- args.put("level", level);
+ args.put("level", severity);
args.put("enable", enable);
const Properties *reply;
@@ -1044,8 +1081,8 @@ struct ndb_mgm_event_categories
{ "DEBUG", NDB_MGM_EVENT_CATEGORY_DEBUG },
{ "INFO", NDB_MGM_EVENT_CATEGORY_INFO },
{ "ERROR", NDB_MGM_EVENT_CATEGORY_ERROR },
- { "GREP", NDB_MGM_EVENT_CATEGORY_GREP },
{ "BACKUP", NDB_MGM_EVENT_CATEGORY_BACKUP },
+ { "CONGESTION", NDB_MGM_EVENT_CATEGORY_CONGESTION },
{ 0, NDB_MGM_ILLEGAL_EVENT_CATEGORY }
};
@@ -1077,13 +1114,13 @@ ndb_mgm_get_event_category_string(enum ndb_mgm_event_category status)
extern "C"
int
-ndb_mgm_set_loglevel_clusterlog(NdbMgmHandle handle, int nodeId,
+ndb_mgm_set_clusterlog_loglevel(NdbMgmHandle handle, int nodeId,
enum ndb_mgm_event_category cat,
int level,
struct ndb_mgm_reply* /*reply*/)
{
SET_ERROR(handle, NDB_MGM_NO_ERROR,
- "Executing: ndb_mgm_set_loglevel_clusterlog");
+ "Executing: ndb_mgm_set_clusterlog_loglevel");
const ParserRow<ParserDummy> clusterlog_reply[] = {
MGM_CMD("set cluster loglevel reply", NULL, ""),
MGM_ARG("result", String, Mandatory, "Error message"),
@@ -1102,7 +1139,7 @@ ndb_mgm_set_loglevel_clusterlog(NdbMgmHandle handle, int nodeId,
"set cluster loglevel", &args);
CHECK_REPLY(reply, -1);
- DBUG_ENTER("ndb_mgm_set_loglevel_clusterlog");
+ DBUG_ENTER("ndb_mgm_set_clusterlog_loglevel");
DBUG_PRINT("enter",("node=%d, category=%d, level=%d", nodeId, cat, level));
BaseString result;
@@ -1152,9 +1189,9 @@ ndb_mgm_set_loglevel_node(NdbMgmHandle handle, int nodeId,
return 0;
}
-extern "C"
int
-ndb_mgm_listen_event(NdbMgmHandle handle, int filter[])
+ndb_mgm_listen_event_internal(NdbMgmHandle handle, const int filter[],
+ int parsable)
{
SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_listen_event");
const ParserRow<ParserDummy> stat_reply[] = {
@@ -1176,6 +1213,9 @@ ndb_mgm_listen_event(NdbMgmHandle handle, int filter[])
}
Properties args;
+
+ if (parsable)
+ args.put("parsable", parsable);
{
BaseString tmp;
for(int i = 0; filter[i] != 0; i += 2){
@@ -1192,11 +1232,21 @@ ndb_mgm_listen_event(NdbMgmHandle handle, int filter[])
handle->socket = tmp;
- CHECK_REPLY(reply, -1);
+ if(reply == NULL) {
+ close(sockfd);
+ CHECK_REPLY(reply, -1);
+ }
return sockfd;
}
extern "C"
+int
+ndb_mgm_listen_event(NdbMgmHandle handle, const int filter[])
+{
+ return ndb_mgm_listen_event_internal(handle,filter,0);
+}
+
+extern "C"
int
ndb_mgm_get_stat_port(NdbMgmHandle handle, struct ndb_mgm_reply* /*reply*/)
{
@@ -1740,13 +1790,19 @@ ndb_mgm_get_configuration_nodeid(NdbMgmHandle handle)
extern "C"
int ndb_mgm_get_connected_port(NdbMgmHandle handle)
{
- return handle->cfg.ids[handle->cfg_i].port;
+ if (handle->cfg_i >= 0)
+ return handle->cfg.ids[handle->cfg_i].port;
+ else
+ return 0;
}
extern "C"
const char *ndb_mgm_get_connected_host(NdbMgmHandle handle)
{
- return handle->cfg.ids[handle->cfg_i].name.c_str();
+ if (handle->cfg_i >= 0)
+ return handle->cfg.ids[handle->cfg_i].name.c_str();
+ else
+ return 0;
}
extern "C"
@@ -1860,9 +1916,9 @@ ndb_mgm_set_int_parameter(NdbMgmHandle handle,
CHECK_CONNECTED(handle, 0);
Properties args;
- args.put("node: ", node);
- args.put("param: ", param);
- args.put("value: ", value);
+ args.put("node", node);
+ args.put("param", param);
+ args.put("value", value);
const ParserRow<ParserDummy> reply[]= {
MGM_CMD("set parameter reply", NULL, ""),
@@ -1899,9 +1955,9 @@ ndb_mgm_set_int64_parameter(NdbMgmHandle handle,
CHECK_CONNECTED(handle, 0);
Properties args;
- args.put("node: ", node);
- args.put("param: ", param);
- args.put("value: ", value);
+ args.put("node", node);
+ args.put("param", param);
+ args.put("value", value);
const ParserRow<ParserDummy> reply[]= {
MGM_CMD("set parameter reply", NULL, ""),
@@ -1942,9 +1998,9 @@ ndb_mgm_set_string_parameter(NdbMgmHandle handle,
CHECK_CONNECTED(handle, 0);
Properties args;
- args.put("node: ", node);
- args.put("parameter: ", param);
- args.put("value: ", value);
+ args.put("node", node);
+ args.put("parameter", param);
+ args.put("value", value);
const ParserRow<ParserDummy> reply[]= {
MGM_CMD("set parameter reply", NULL, ""),
@@ -2050,4 +2106,146 @@ ndb_mgm_check_connection_error:
return -1;
}
+extern "C"
+int
+ndb_mgm_set_connection_int_parameter(NdbMgmHandle handle,
+ int node1,
+ int node2,
+ int param,
+ int value,
+ struct ndb_mgm_reply* mgmreply){
+ DBUG_ENTER("ndb_mgm_set_connection_int_parameter");
+ CHECK_HANDLE(handle, 0);
+ CHECK_CONNECTED(handle, 0);
+
+ Properties args;
+ args.put("node1", node1);
+ args.put("node2", node2);
+ args.put("param", param);
+ args.put("value", (Uint32)value);
+
+ const ParserRow<ParserDummy> reply[]= {
+ MGM_CMD("set connection parameter reply", NULL, ""),
+ MGM_ARG("message", String, Mandatory, "Error Message"),
+ MGM_ARG("result", String, Mandatory, "Status Result"),
+ MGM_END()
+ };
+
+ const Properties *prop;
+ prop= ndb_mgm_call(handle, reply, "set connection parameter", &args);
+ CHECK_REPLY(prop, -1);
+
+ int res= -1;
+ do {
+ const char * buf;
+ if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){
+ ndbout_c("ERROR Message: %s\n", buf);
+ break;
+ }
+ res= 0;
+ } while(0);
+
+ delete prop;
+ DBUG_RETURN(res);
+}
+
+extern "C"
+int
+ndb_mgm_get_connection_int_parameter(NdbMgmHandle handle,
+ int node1,
+ int node2,
+ int param,
+ int *value,
+ struct ndb_mgm_reply* mgmreply){
+ DBUG_ENTER("ndb_mgm_get_connection_int_parameter");
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -2);
+
+ Properties args;
+ args.put("node1", node1);
+ args.put("node2", node2);
+ args.put("param", param);
+
+ const ParserRow<ParserDummy> reply[]= {
+ MGM_CMD("get connection parameter reply", NULL, ""),
+ MGM_ARG("value", Int, Mandatory, "Current Value"),
+ MGM_ARG("result", String, Mandatory, "Result"),
+ MGM_END()
+ };
+
+ const Properties *prop;
+ prop = ndb_mgm_call(handle, reply, "get connection parameter", &args);
+ CHECK_REPLY(prop, -3);
+
+ int res= -1;
+ do {
+ const char * buf;
+ if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){
+ ndbout_c("ERROR Message: %s\n", buf);
+ break;
+ }
+ res= 0;
+ } while(0);
+
+ if(!prop->get("value",(Uint32*)value)){
+ ndbout_c("Unable to get value");
+ res = -4;
+ }
+
+ delete prop;
+ DBUG_RETURN(res);
+}
+
+extern "C"
+NDB_SOCKET_TYPE
+ndb_mgm_convert_to_transporter(NdbMgmHandle *handle)
+{
+ NDB_SOCKET_TYPE s;
+
+ CHECK_HANDLE((*handle), NDB_INVALID_SOCKET);
+ CHECK_CONNECTED((*handle), NDB_INVALID_SOCKET);
+
+ (*handle)->connected= 0; // we pretend we're disconnected
+ s= (*handle)->socket;
+
+ SocketOutputStream s_output(s);
+ s_output.println("transporter connect");
+ s_output.println("");
+
+ ndb_mgm_destroy_handle(handle); // set connected=0, so won't disconnect
+
+ return s;
+}
+
+extern "C"
+Uint32
+ndb_mgm_get_mgmd_nodeid(NdbMgmHandle handle)
+{
+ Uint32 nodeid=0;
+
+ DBUG_ENTER("ndb_mgm_get_mgmd_nodeid");
+ CHECK_HANDLE(handle, 0);
+ CHECK_CONNECTED(handle, 0);
+
+ Properties args;
+
+ const ParserRow<ParserDummy> reply[]= {
+ MGM_CMD("get mgmd nodeid reply", NULL, ""),
+ MGM_ARG("nodeid", Int, Mandatory, "Node ID"),
+ MGM_END()
+ };
+
+ const Properties *prop;
+ prop = ndb_mgm_call(handle, reply, "get mgmd nodeid", &args);
+ CHECK_REPLY(prop, 0);
+
+ if(!prop->get("nodeid",&nodeid)){
+ ndbout_c("Unable to get value");
+ return 0;
+ }
+
+ delete prop;
+ DBUG_RETURN(nodeid);
+}
+
template class Vector<const ParserRow<ParserDummy>*>;
diff --git a/ndb/src/mgmapi/mgmapi_configuration.hpp b/ndb/src/mgmapi/mgmapi_configuration.hpp
index 9e94b3311bf..7d60a4842a1 100644
--- a/ndb/src/mgmapi/mgmapi_configuration.hpp
+++ b/ndb/src/mgmapi/mgmapi_configuration.hpp
@@ -1,3 +1,19 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
#ifndef MGMAPI_CONFIGURATION_HPP
#define MGMAPI_CONFIGURATION_HPP
diff --git a/ndb/src/mgmapi/mgmapi_internal.h b/ndb/src/mgmapi/mgmapi_internal.h
new file mode 100644
index 00000000000..90f93129f2a
--- /dev/null
+++ b/ndb/src/mgmapi/mgmapi_internal.h
@@ -0,0 +1,77 @@
+/* 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 */
+
+#ifndef MGMAPI_INTERNAL_H
+#define MGMAPI_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <NdbTCP.h>
+
+ /**
+ * Set an integer parameter for a connection
+ *
+ * @param handle the NDB management handle.
+ * @param node1 the node1 id
+ * @param node2 the node2 id
+ * @param param the parameter (e.g. CFG_CONNECTION_SERVER_PORT)
+ * @param value what to set it to
+ * @param reply from ndb_mgmd
+ */
+ int ndb_mgm_set_connection_int_parameter(NdbMgmHandle handle,
+ int node1,
+ int node2,
+ int param,
+ int value,
+ struct ndb_mgm_reply* reply);
+
+ /**
+ * Get an integer parameter for a connection
+ *
+ * @param handle the NDB management handle.
+ * @param node1 the node1 id
+ * @param node2 the node2 id
+ * @param param the parameter (e.g. CFG_CONNECTION_SERVER_PORT)
+ * @param value where to store the retreived value. In the case of
+ * error, value is not changed.
+ * @param reply from ndb_mgmd
+ * @return 0 on success. < 0 on error.
+ */
+ int ndb_mgm_get_connection_int_parameter(NdbMgmHandle handle,
+ int node1,
+ int node2,
+ int param,
+ int *value,
+ struct ndb_mgm_reply* reply);
+
+ /**
+ * Convert connection to transporter
+ * @param handle NDB management handle.
+ *
+ * @return socket
+ *
+ * @note the socket is now able to be used as a transporter connection
+ */
+ NDB_SOCKET_TYPE ndb_mgm_convert_to_transporter(NdbMgmHandle *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/ndb/src/mgmapi/ndb_logevent.cpp b/ndb/src/mgmapi/ndb_logevent.cpp
new file mode 100644
index 00000000000..2817abcfdbb
--- /dev/null
+++ b/ndb/src/mgmapi/ndb_logevent.cpp
@@ -0,0 +1,483 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include <my_sys.h>
+#include <mgmapi.h>
+
+#include <NdbOut.hpp>
+#include <Properties.hpp>
+#include <socket_io.h>
+#include <InputStream.hpp>
+
+#include <debugger/EventLogger.hpp>
+
+#include "ndb_logevent.hpp"
+
+extern
+int ndb_mgm_listen_event_internal(NdbMgmHandle, const int filter[], int);
+
+struct ndb_logevent_error_msg {
+ enum ndb_logevent_handle_error code;
+ const char *msg;
+};
+
+struct ndb_logevent_error_msg ndb_logevent_error_messages[]= {
+ { NDB_LEH_READ_ERROR, "Read error" },
+ { NDB_LEH_MISSING_EVENT_SPECIFIER, "Missing event specifier" },
+ { NDB_LEH_UNKNOWN_EVENT_VARIABLE, "Unknown event variable" },
+ { NDB_LEH_UNKNOWN_EVENT_TYPE, "Unknown event type" },
+ { NDB_LEH_INTERNAL_ERROR, "Unknown internal error" },
+ { NDB_LEH_NO_ERROR,0}
+};
+
+struct ndb_logevent_handle {
+ NDB_SOCKET_TYPE socket;
+ enum ndb_logevent_handle_error m_error;
+};
+
+extern "C"
+NdbLogEventHandle
+ndb_mgm_create_logevent_handle(NdbMgmHandle mh,
+ const int filter[])
+{
+ int fd= ndb_mgm_listen_event_internal(mh, filter, 1);
+
+ if (fd == -1)
+ return 0;
+
+ NdbLogEventHandle h=
+ (NdbLogEventHandle)my_malloc(sizeof(ndb_logevent_handle),MYF(MY_WME));
+
+ h->socket= fd;
+
+ return h;
+}
+
+extern "C"
+void ndb_mgm_destroy_logevent_handle(NdbLogEventHandle * h)
+{
+ if( !h )
+ return;
+
+ if ( *h )
+ close((*h)->socket);
+
+ my_free((char*)* h,MYF(MY_ALLOW_ZERO_PTR));
+ * h = 0;
+}
+
+#define ROW(a,b,c,d) \
+{ NDB_LE_ ## a, b, c, 0, offsetof(struct ndb_logevent, a.d), \
+ sizeof(((struct ndb_logevent *)0)->a.d) }
+
+#define ROW_FN(a,b,c,d,e) \
+{ NDB_LE_ ## a, b, c, e, offsetof(struct ndb_logevent, a.d), \
+ sizeof(((struct ndb_logevent *)0)->a.d) }
+
+static int ref_to_node(int ref){
+ return ref & 0xFFFF;
+}
+
+struct Ndb_logevent_body_row ndb_logevent_body[]= {
+
+ // Connection
+ ROW( Connected, "node", 1, node),
+
+ ROW( Disconnected, "node", 1, node),
+
+ ROW( CommunicationClosed, "node", 1, node),
+
+ ROW( CommunicationOpened, "node", 1, node),
+
+ ROW( ConnectedApiVersion, "node", 1, node),
+ ROW( ConnectedApiVersion, "version", 2, version),
+
+ /* CHECKPOINT */
+
+ ROW( GlobalCheckpointStarted, "gci", 1, gci),
+
+ ROW( GlobalCheckpointCompleted, "gci", 1, gci),
+
+ ROW( LocalCheckpointStarted, "lci", 1, lci),
+ ROW( LocalCheckpointStarted, "keep_gci", 2, keep_gci),
+ ROW( LocalCheckpointStarted, "restore_gci", 3, restore_gci),
+
+ ROW( LocalCheckpointCompleted, "lci", 1, lci),
+
+ ROW( LCPStoppedInCalcKeepGci, "data", 1, data),
+
+ ROW( LCPFragmentCompleted, "node", 1, node),
+ ROW( LCPFragmentCompleted, "table_id", 2, table_id),
+ ROW( LCPFragmentCompleted, "fragment_id", 3, fragment_id),
+
+ ROW( UndoLogBlocked, "acc_count", 1, acc_count),
+ ROW( UndoLogBlocked, "tup_count", 2, tup_count),
+
+ /* STARTUP */
+ ROW( NDBStartStarted, "version", 1, version),
+
+ ROW( NDBStartCompleted, "version", 1, version),
+
+// ROW( STTORRYRecieved),
+
+ ROW( StartPhaseCompleted, "phase", 1, phase),
+ ROW( StartPhaseCompleted, "starttype", 2, starttype),
+
+ ROW( CM_REGCONF, "own_id", 1, own_id),
+ ROW( CM_REGCONF, "president_id", 2, president_id),
+ ROW( CM_REGCONF, "dynamic_id", 3, dynamic_id),
+
+ ROW( CM_REGREF, "own_id", 1, own_id),
+ ROW( CM_REGREF, "other_id", 2, other_id),
+ ROW( CM_REGREF, "cause", 3, cause),
+
+ ROW( FIND_NEIGHBOURS, "own_id", 1, own_id),
+ ROW( FIND_NEIGHBOURS, "left_id", 3, left_id),
+ ROW( FIND_NEIGHBOURS, "right_id", 3, right_id),
+ ROW( FIND_NEIGHBOURS, "dynamic_id", 4, dynamic_id),
+
+ ROW( NDBStopStarted, "stoptype", 1, stoptype),
+
+// ROW( NDBStopAborted),
+
+ ROW( StartREDOLog, "node", 1, node),
+ ROW( StartREDOLog, "keep_gci", 2, keep_gci),
+ ROW( StartREDOLog, "completed_gci", 3, completed_gci),
+ ROW( StartREDOLog, "restorable_gci", 4, restorable_gci),
+
+ ROW( StartLog, "log_part", 1, log_part),
+ ROW( StartLog, "start_mb", 2, start_mb),
+ ROW( StartLog, "stop_mb", 3, stop_mb),
+ ROW( StartLog, "gci", 4, gci),
+
+ ROW( UNDORecordsExecuted, "block", 1, block),
+ ROW( UNDORecordsExecuted, "data1", 2, data1),
+ ROW( UNDORecordsExecuted, "data2", 3, data2),
+ ROW( UNDORecordsExecuted, "data3", 4, data3),
+ ROW( UNDORecordsExecuted, "data4", 5, data4),
+ ROW( UNDORecordsExecuted, "data5", 6, data5),
+ ROW( UNDORecordsExecuted, "data6", 7, data6),
+ ROW( UNDORecordsExecuted, "data7", 8, data7),
+ ROW( UNDORecordsExecuted, "data8", 9, data8),
+ ROW( UNDORecordsExecuted, "data9", 10, data9),
+ ROW( UNDORecordsExecuted, "data10", 11, data10),
+
+ /* NODERESTART */
+// ROW( NR_CopyDict),
+
+// ROW( NR_CopyDistr),
+
+ ROW( NR_CopyFragsStarted, "dest_node", 1, dest_node),
+
+ ROW( NR_CopyFragDone, "dest_node", 1, dest_node),
+ ROW( NR_CopyFragDone, "table_id", 2, table_id),
+ ROW( NR_CopyFragDone, "fragment_id", 3, fragment_id),
+
+ ROW( NR_CopyFragsCompleted, "dest_node", 1, dest_node),
+
+ ROW( NodeFailCompleted, "block", 1, block), /* 0 = all */
+ ROW( NodeFailCompleted, "failed_node", 2, failed_node),
+ ROW( NodeFailCompleted, "completing_node", 3, completing_node), /* 0 = all */
+
+ ROW( NODE_FAILREP, "failed_node", 1, failed_node),
+ ROW( NODE_FAILREP, "failure_state", 2, failure_state),
+
+ /* TODO */
+ ROW( ArbitState, "code", 1, code),
+ ROW( ArbitState, "arbit_node", 2, arbit_node),
+ ROW( ArbitState, "ticket_0", 3, ticket_0),
+ ROW( ArbitState, "ticket_1", 4, ticket_1),
+
+ /* TODO */
+ ROW( ArbitResult, "code", 1, code),
+ ROW( ArbitResult, "arbit_node", 2, arbit_node),
+ ROW( ArbitResult, "ticket_0", 3, ticket_0),
+ ROW( ArbitResult, "ticket_1", 4, ticket_1),
+
+// ROW( GCP_TakeoverStarted),
+
+// ROW( GCP_TakeoverCompleted),
+
+// ROW( LCP_TakeoverStarted),
+
+ ROW( LCP_TakeoverCompleted, "state", 1, state),
+
+ /* STATISTIC */
+ ROW( TransReportCounters, "trans_count", 1, trans_count),
+ ROW( TransReportCounters, "commit_count", 2, commit_count),
+ ROW( TransReportCounters, "read_count", 3, read_count),
+ ROW( TransReportCounters, "simple_read_count", 4, simple_read_count),
+ ROW( TransReportCounters, "write_count", 5, write_count),
+ ROW( TransReportCounters, "attrinfo_count", 6, attrinfo_count),
+ ROW( TransReportCounters, "conc_op_count", 7, conc_op_count),
+ ROW( TransReportCounters, "abort_count", 8, abort_count),
+ ROW( TransReportCounters, "scan_count", 9, scan_count),
+ ROW( TransReportCounters, "range_scan_count", 10, range_scan_count),
+
+ ROW( OperationReportCounters, "ops", 1, ops),
+
+ ROW( TableCreated, "table_id", 1, table_id),
+
+ ROW( JobStatistic, "mean_loop_count", 1, mean_loop_count),
+
+ ROW( SendBytesStatistic, "to_node", 1, to_node),
+ ROW( SendBytesStatistic, "mean_sent_bytes", 2, mean_sent_bytes),
+
+ ROW( ReceiveBytesStatistic, "from_node", 1, from_node),
+ ROW( ReceiveBytesStatistic, "mean_received_bytes", 2, mean_received_bytes),
+
+ ROW( MemoryUsage, "gth", 1, gth),
+ ROW( MemoryUsage, "page_size_kb", 2, page_size_kb),
+ ROW( MemoryUsage, "pages_used", 3, pages_used),
+ ROW( MemoryUsage, "pages_total", 4, pages_total),
+ ROW( MemoryUsage, "block", 5, block),
+
+ /* ERROR */
+ ROW( TransporterError, "to_node", 1, to_node),
+ ROW( TransporterError, "code", 2, code),
+
+ ROW( TransporterWarning, "to_node", 1, to_node),
+ ROW( TransporterWarning, "code", 2, code),
+
+ ROW( MissedHeartbeat, "node", 1, node),
+ ROW( MissedHeartbeat, "count", 2, count),
+
+ ROW( DeadDueToHeartbeat, "node", 1, node),
+
+ /* TODO */
+// ROW( WarningEvent),
+
+ /* INFO */
+ ROW( SentHeartbeat, "node", 1, node),
+
+ ROW( CreateLogBytes, "node", 1, node),
+
+ /* TODO */
+// ROW( InfoEvent),
+
+ // Backup
+ ROW_FN( BackupStarted, "starting_node", 1, starting_node, ref_to_node),
+ ROW( BackupStarted, "backup_id", 2, backup_id),
+
+ ROW_FN(BackupFailedToStart,"starting_node",1, starting_node, ref_to_node),
+ ROW( BackupFailedToStart, "error", 2, error),
+
+ ROW_FN( BackupCompleted, "starting_node", 1, starting_node, ref_to_node),
+ ROW( BackupCompleted, "backup_id", 2, backup_id),
+ ROW( BackupCompleted, "start_gci", 3, start_gci),
+ ROW( BackupCompleted, "stop_gci", 4, stop_gci),
+ ROW( BackupCompleted, "n_bytes", 5, n_bytes),
+ ROW( BackupCompleted, "n_records", 6, n_records),
+ ROW( BackupCompleted, "n_log_bytes", 7, n_log_bytes),
+ ROW( BackupCompleted, "n_log_records", 8, n_log_records),
+
+ ROW_FN( BackupAborted, "starting_node", 1, starting_node, ref_to_node),
+ ROW( BackupAborted, "backup_id", 2, backup_id),
+ ROW( BackupAborted, "error", 3, error),
+
+ { NDB_LE_ILLEGAL_TYPE, 0, 0, 0, 0, 0}
+};
+
+struct Ndb_logevent_header_row {
+ const char *token; // token to use for text transfer
+ int offset; // offset into struct ndb_logevent
+ int size;
+};
+
+#define ROW2(a,b) \
+{ a, offsetof(struct ndb_logevent, b), \
+ sizeof(((struct ndb_logevent *)0)->b) }
+
+struct Ndb_logevent_header_row ndb_logevent_header[]= {
+ ROW2( "type", type),
+ ROW2( "time", time),
+ ROW2( "source_nodeid", source_nodeid),
+ { 0, 0, 0 }
+};
+
+static int
+insert_row(const char * pair, Properties & p){
+ BaseString tmp(pair);
+
+ tmp.trim(" \t\n\r");
+ Vector<BaseString> split;
+ tmp.split(split, ":=", 2);
+ if(split.size() != 2)
+ return -1;
+ p.put(split[0].trim().c_str(), split[1].trim().c_str());
+
+ return 0;
+}
+
+static
+int memcpy_atoi(void *dst, const char *str, int sz)
+{
+ switch (sz)
+ {
+ case 1:
+ {
+ Int8 val= atoi(str);
+ memcpy(dst,&val,sz);
+ return 0;
+ }
+ case 2:
+ {
+ Int16 val= atoi(str);
+ memcpy(dst,&val,sz);
+ return 0;
+ }
+ case 4:
+ {
+ Int32 val= atoi(str);
+ memcpy(dst,&val,sz);
+ return 0;
+ }
+ case 8:
+ {
+ Int64 val= atoi(str);
+ memcpy(dst,&val,sz);
+ return 0;
+ }
+ default:
+ {
+ return -1;
+ }
+ }
+}
+
+extern "C"
+int ndb_logevent_get_next(const NdbLogEventHandle h,
+ struct ndb_logevent *dst,
+ unsigned timeout_in_milliseconds)
+{
+ SocketInputStream in(h->socket, timeout_in_milliseconds);
+
+ Properties p;
+ char buf[256];
+
+ /* header */
+ while (1) {
+ if (in.gets(buf,sizeof(buf)) == 0)
+ {
+ h->m_error= NDB_LEH_READ_ERROR;
+ return -1;
+ }
+ if ( buf[0] == 0 )
+ {
+ // timed out
+ return 0;
+ }
+ if ( strcmp("log event reply\n", buf) == 0 )
+ break;
+ ndbout_c("skipped: %s", buf);
+ }
+
+ /* read name-value pairs into properties object */
+ while (1)
+ {
+ if (in.gets(buf,sizeof(buf)) == 0)
+ {
+ h->m_error= NDB_LEH_READ_ERROR;
+ return -1;
+ }
+ if ( buf[0] == 0 )
+ {
+ // timed out
+ return 0;
+ }
+ if ( buf[0] == '\n' )
+ {
+ break;
+ }
+ if (insert_row(buf,p))
+ {
+ h->m_error= NDB_LEH_READ_ERROR;
+ return -1;
+ }
+ }
+
+ int i;
+ const char *val;
+
+ dst->type= (enum Ndb_logevent_type)-1;
+ /* fill in header info from p*/
+ for (i= 0; ndb_logevent_header[i].token; i++)
+ {
+ if ( p.get(ndb_logevent_header[i].token, &val) == 0 )
+ {
+ ndbout_c("missing: %s\n", ndb_logevent_header[i].token);
+ h->m_error= NDB_LEH_MISSING_EVENT_SPECIFIER;
+ return -1;
+ }
+ if ( memcpy_atoi((char *)dst+ndb_logevent_header[i].offset, val,
+ ndb_logevent_header[i].size) )
+ {
+ h->m_error= NDB_LEH_INTERNAL_ERROR;
+ return -1;
+ }
+ }
+
+ Uint32 level;
+ LogLevel::EventCategory category;
+ Logger::LoggerLevel severity;
+ EventLoggerBase::EventTextFunction text_fn;
+
+ /* fill in rest of header info event_lookup */
+ if (EventLoggerBase::event_lookup(dst->type,category,level,severity,text_fn))
+ {
+ ndbout_c("unknown type: %d\n", dst->type);
+ h->m_error= NDB_LEH_UNKNOWN_EVENT_TYPE;
+ return -1;
+ }
+ dst->category= (enum ndb_mgm_event_category)category;
+ dst->severity= (enum ndb_mgm_event_severity)severity;
+ dst->level= level;
+
+ /* fill in header info from p */
+ for (i= 0; ndb_logevent_body[i].token; i++)
+ {
+ if ( ndb_logevent_body[i].type != dst->type )
+ continue;
+ if ( p.get(ndb_logevent_body[i].token, &val) == 0 )
+ {
+ h->m_error= NDB_LEH_UNKNOWN_EVENT_VARIABLE;
+ return -1;
+ }
+ if ( memcpy_atoi((char *)dst+ndb_logevent_body[i].offset, val,
+ ndb_logevent_body[i].size) )
+ {
+ h->m_error= NDB_LEH_INTERNAL_ERROR;
+ return -1;
+ }
+ }
+ return 1;
+}
+
+extern "C"
+int ndb_logevent_get_latest_error(const NdbLogEventHandle h)
+{
+ return h->m_error;
+}
+
+extern "C"
+const char *ndb_logevent_get_latest_error_msg(const NdbLogEventHandle h)
+{
+ for (int i= 0; ndb_logevent_error_messages[i].msg; i++)
+ if (ndb_logevent_error_messages[i].code == h->m_error)
+ return ndb_logevent_error_messages[i].msg;
+ return "<unknown error msg>";
+}
diff --git a/ndb/include/ndbapi/NdbCursorOperation.hpp b/ndb/src/mgmapi/ndb_logevent.hpp
index e7eeb54ba2d..cb1a0e388e5 100644
--- a/ndb/include/ndbapi/NdbCursorOperation.hpp
+++ b/ndb/src/mgmapi/ndb_logevent.hpp
@@ -14,7 +14,21 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#ifndef NdbCursorOperation_H
-#define NdbCursorOperation_H
+#ifndef NDB_LOGEVENT_HPP
+#define NDB_LOGEVENT_HPP
+
+#include <ndb_logevent.h>
+
+struct Ndb_logevent_body_row {
+ enum Ndb_logevent_type type; // type
+ const char *token; // token to use for text transfer
+ int index; // index into theData array
+ int (*index_fn)(int); // conversion function on the data array[index]
+ int offset; // offset into struct ndb_logevent
+ int size; // offset into struct ndb_logevent
+};
+
+extern
+struct Ndb_logevent_body_row ndb_logevent_body[];
#endif
diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp
index c3b0ee7fe97..389fc08b97c 100644
--- a/ndb/src/mgmclient/CommandInterpreter.cpp
+++ b/ndb/src/mgmclient/CommandInterpreter.cpp
@@ -389,7 +389,7 @@ CommandInterpreter::CommandInterpreter(const char *_host,int verbose)
}
m_mgmsrv2 = ndb_mgm_create_handle();
if(m_mgmsrv2 == NULL) {
- ndbout_c("Cannot create handle to management server.");
+ ndbout_c("Cannot create 2:nd handle to management server.");
exit(-1);
}
if (ndb_mgm_set_connectstring(m_mgmsrv, _host))
@@ -482,17 +482,20 @@ event_thread_run(void* m)
bool
CommandInterpreter::connect()
{
+ DBUG_ENTER("CommandInterpreter::connect");
if(!m_connected)
{
if(!ndb_mgm_connect(m_mgmsrv, try_reconnect-1, 5, 1))
{
const char *host= ndb_mgm_get_connected_host(m_mgmsrv);
unsigned port= ndb_mgm_get_connected_port(m_mgmsrv);
- if(!ndb_mgm_set_connectstring(m_mgmsrv2,
- BaseString(host).appfmt(":%d",port).c_str())
- &&
+ BaseString constr;
+ constr.assfmt("%s:%d",host,port);
+ if(!ndb_mgm_set_connectstring(m_mgmsrv2, constr.c_str()) &&
!ndb_mgm_connect(m_mgmsrv2, try_reconnect-1, 5, 1))
{
+ DBUG_PRINT("info",("2:ndb connected to Management Server ok at: %s:%d",
+ host, port));
assert(m_event_thread == 0);
assert(do_event_thread == 0);
do_event_thread= 0;
@@ -503,6 +506,7 @@ CommandInterpreter::connect()
NDB_THREAD_PRIO_LOW);
if (m_event_thread != 0)
{
+ DBUG_PRINT("info",("Thread created ok, waiting for started..."));
int iter= 1000; // try for 30 seconds
while(do_event_thread == 0 &&
iter-- > 0)
@@ -512,15 +516,25 @@ 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");
do_event_thread= 0;
}
}
else
{
+ DBUG_PRINT("warning",
+ ("Could not do 2:nd connect to mgmtserver for event listening"));
+ DBUG_PRINT("info", ("code: %d, msg: %s",
+ ndb_mgm_get_latest_error(m_mgmsrv2),
+ ndb_mgm_get_latest_error_msg(m_mgmsrv2)));
printf("Warning, event connect failed, degraded printouts as result\n");
+ printf("code: %d, msg: %s\n",
+ ndb_mgm_get_latest_error(m_mgmsrv2),
+ ndb_mgm_get_latest_error_msg(m_mgmsrv2));
}
m_connected= true;
+ DBUG_PRINT("info",("Connected to Management Server at: %s:%d", host, port));
if (m_verbose)
{
printf("Connected to Management Server at: %s:%d\n",
@@ -528,7 +542,7 @@ CommandInterpreter::connect()
}
}
}
- return m_connected;
+ DBUG_RETURN(m_connected);
}
bool
@@ -1245,7 +1259,7 @@ CommandInterpreter::executeClusterLog(char* parameters)
DBUG_VOID_RETURN;
}
- enum ndb_mgm_clusterlog_level severity = NDB_MGM_CLUSTERLOG_ALL;
+ enum ndb_mgm_event_severity severity = NDB_MGM_EVENT_SEVERITY_ALL;
char * tmpString = my_strdup(parameters,MYF(MY_WME));
My_auto_ptr<char> ap1(tmpString);
@@ -1253,7 +1267,7 @@ CommandInterpreter::executeClusterLog(char* parameters)
char * item = strtok_r(tmpString, " ", &tmpPtr);
int enable;
- Uint32 *enabled = ndb_mgm_get_logfilter(m_mgmsrv);
+ const unsigned int *enabled= ndb_mgm_get_logfilter(m_mgmsrv);
if(enabled == NULL) {
ndbout << "Couldn't get status" << endl;
printError();
@@ -1275,8 +1289,8 @@ CommandInterpreter::executeClusterLog(char* parameters)
printf("enabled[%d] = %d\n", i, enabled[i]);
#endif
ndbout << "Severities enabled: ";
- for(i = 1; i < (int)NDB_MGM_CLUSTERLOG_ALL; i++) {
- const char *str= ndb_mgm_get_clusterlog_level_string((ndb_mgm_clusterlog_level)i);
+ for(i = 1; i < (int)NDB_MGM_EVENT_SEVERITY_ALL; i++) {
+ const char *str= ndb_mgm_get_event_severity_string((ndb_mgm_event_severity)i);
if (str == 0)
{
DBUG_ASSERT(false);
@@ -1310,8 +1324,10 @@ CommandInterpreter::executeClusterLog(char* parameters)
int res_enable;
item = strtok_r(NULL, " ", &tmpPtr);
if (item == NULL) {
- res_enable= ndb_mgm_filter_clusterlog(m_mgmsrv,
- NDB_MGM_CLUSTERLOG_ON, enable, NULL);
+ res_enable=
+ ndb_mgm_set_clusterlog_severity_filter(m_mgmsrv,
+ NDB_MGM_EVENT_SEVERITY_ON,
+ enable, NULL);
if (res_enable < 0)
{
ndbout << "Couldn't set filter" << endl;
@@ -1323,32 +1339,33 @@ CommandInterpreter::executeClusterLog(char* parameters)
}
do {
- severity= NDB_MGM_ILLEGAL_CLUSTERLOG_LEVEL;
+ severity= NDB_MGM_ILLEGAL_EVENT_SEVERITY;
if (strcasecmp(item, "ALL") == 0) {
- severity = NDB_MGM_CLUSTERLOG_ALL;
+ severity = NDB_MGM_EVENT_SEVERITY_ALL;
} else if (strcasecmp(item, "ALERT") == 0) {
- severity = NDB_MGM_CLUSTERLOG_ALERT;
+ severity = NDB_MGM_EVENT_SEVERITY_ALERT;
} else if (strcasecmp(item, "CRITICAL") == 0) {
- severity = NDB_MGM_CLUSTERLOG_CRITICAL;
+ severity = NDB_MGM_EVENT_SEVERITY_CRITICAL;
} else if (strcasecmp(item, "ERROR") == 0) {
- severity = NDB_MGM_CLUSTERLOG_ERROR;
+ severity = NDB_MGM_EVENT_SEVERITY_ERROR;
} else if (strcasecmp(item, "WARNING") == 0) {
- severity = NDB_MGM_CLUSTERLOG_WARNING;
+ severity = NDB_MGM_EVENT_SEVERITY_WARNING;
} else if (strcasecmp(item, "INFO") == 0) {
- severity = NDB_MGM_CLUSTERLOG_INFO;
+ severity = NDB_MGM_EVENT_SEVERITY_INFO;
} else if (strcasecmp(item, "DEBUG") == 0) {
- severity = NDB_MGM_CLUSTERLOG_DEBUG;
+ severity = NDB_MGM_EVENT_SEVERITY_DEBUG;
} else if (strcasecmp(item, "OFF") == 0 ||
strcasecmp(item, "ON") == 0) {
if (enable < 0) // only makes sense with toggle
- severity = NDB_MGM_CLUSTERLOG_ON;
+ severity = NDB_MGM_EVENT_SEVERITY_ON;
}
- if (severity == NDB_MGM_ILLEGAL_CLUSTERLOG_LEVEL) {
+ if (severity == NDB_MGM_ILLEGAL_EVENT_SEVERITY) {
ndbout << "Invalid severity level: " << item << endl;
DBUG_VOID_RETURN;
}
- res_enable = ndb_mgm_filter_clusterlog(m_mgmsrv, severity, enable, NULL);
+ res_enable= ndb_mgm_set_clusterlog_severity_filter(m_mgmsrv, severity,
+ enable, NULL);
if (res_enable < 0)
{
ndbout << "Couldn't set filter" << endl;
diff --git a/ndb/src/mgmclient/main.cpp b/ndb/src/mgmclient/main.cpp
index 73f0bad86c0..19c84f6ec8d 100644
--- a/ndb/src/mgmclient/main.cpp
+++ b/ndb/src/mgmclient/main.cpp
@@ -87,13 +87,6 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_mgm.trace");
-}
static int
read_and_execute(int _try_reconnect)
@@ -136,7 +129,11 @@ int main(int argc, char** argv){
load_defaults("my",load_default_groups,&argc,&argv);
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_mgm.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
exit(ho_error);
char buf[MAXHOSTNAMELEN+10];
diff --git a/ndb/src/mgmsrv/CommandInterpreter.cpp b/ndb/src/mgmsrv/CommandInterpreter.cpp
deleted file mode 100644
index 686155415d5..00000000000
--- a/ndb/src/mgmsrv/CommandInterpreter.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include "CommandInterpreter.hpp"
-
-#include <string.h>
-#include <ctype.h>
-
-#include "MgmtSrvr.hpp"
-#include "MgmtErrorReporter.hpp"
-#include <NdbOut.hpp>
-#include "convertStrToInt.hpp"
-#include <EventLogger.hpp>
-#include <signaldata/SetLogLevelOrd.hpp>
-#include "ConfigInfo.hpp"
-
-#include <version.h>
-#include <m_string.h>
-
-//******************************************************************************
-//******************************************************************************
-CommandInterpreter::CommandInterpreter(MgmtSrvr& mgmtSrvr) :
- _mgmtSrvr(mgmtSrvr) {
-}
-
-
-bool emptyString(const char* s) {
- if (s == NULL) {
- return true;
- }
-
- for (unsigned int i = 0; i < strlen(s); ++i) {
- if (! isspace(s[i])) {
- return false;
- }
- }
-
- return true;
-}
-
-class AutoPtr {
-public:
- AutoPtr(void * ptr) : m_ptr(ptr) {}
- ~AutoPtr() { free(m_ptr);}
-private:
- void * m_ptr;
-};
-
-const char *CommandInterpreter::get_error_text(int err_no)
-{
- return _mgmtSrvr.getErrorText(err_no, m_err_str, sizeof(m_err_str));
-}
-
-//*****************************************************************************
-//*****************************************************************************
-int CommandInterpreter::readAndExecute() {
-
- char* _line = readline_gets();
- char * line;
- if(_line == NULL) {
- ndbout << endl;
- return true;
- }
-
- line = strdup(_line);
-
- AutoPtr ptr(line);
-
- if (emptyString(line)) {
- return true;
- }
-
- for (unsigned int i = 0; i < strlen(line); ++i) {
- line[i] = toupper(line[i]);
- }
-
- // if there is anything in the line proceed
- char* firstToken = strtok(line, " ");
- char* allAfterFirstToken = strtok(NULL, "\0");
-
- if (strcmp(firstToken, "ALL") == 0) {
- analyseAfterFirstToken(-1, allAfterFirstToken);
- }
- else if(strcmp(firstToken, "QUIT") == 0 ||
- strcmp(firstToken, "EXIT") == 0 ||
- strcmp(firstToken, "BYE") == 0){
- return false;
- } else {
- // First token should be a digit, process ID
-
- int processId;
- if (! convert(firstToken, processId)) {
- ndbout << "Invalid command: " << _line << "." << endl;
- return true;
- }
- if (processId < 0) {
- ndbout << "Invalid process ID: " << firstToken << "." << endl;
- return true;
- }
-
- analyseAfterFirstToken(processId, allAfterFirstToken);
-
- } // else
- return true;
-}
-
-
-static const CommandInterpreter::CommandFunctionPair commands[] = {
- { "TRACE", &CommandInterpreter::executeTrace }
- ,{ "LOGIN", &CommandInterpreter::executeLogIn }
- ,{ "LOGOUT", &CommandInterpreter::executeLogOut }
- ,{ "LOGOFF", &CommandInterpreter::executeLogOff }
-};
-
-
-//*****************************************************************************
-//*****************************************************************************
-void
-CommandInterpreter::analyseAfterFirstToken(int processId,
- char* allAfterFirstToken) {
-
- if (emptyString(allAfterFirstToken)) {
- if (processId == -1) {
- ndbout << "Expected a command after ALL." << endl;
- }
- else {
- ndbout << "Expected a command after process ID." << endl;
- }
- return;
- }
-
-
- char* secondToken = strtok(allAfterFirstToken, " ");
- char* allAfterSecondToken = strtok(NULL, "\0");
-
- const int tmpSize = sizeof(commands)/sizeof(CommandFunctionPair);
- ExecuteFunction fun = 0;
- const char * command = 0;
- for(int i = 0; i<tmpSize; i++){
- if(strcmp(secondToken, commands[i].command) == 0){
- fun = commands[i].executeFunction;
- command = commands[i].command;
- break;
- }
- }
-
- if(fun == 0){
- ndbout << "Invalid command: " << secondToken << "." << endl;
- return;
- }
-
- if(processId == -1){
- executeForAll(command, fun, allAfterSecondToken);
- } else {
- ndbout << "Executing " << command << " on node: "
- << processId << endl << endl;
- (this->*fun)(processId, allAfterSecondToken, false);
- ndbout << endl;
- }
-}
-
-void
-CommandInterpreter::executeForAll(const char * cmd, ExecuteFunction fun,
- const char * allAfterSecondToken){
-
- NodeId nodeId = 0;
- while(_mgmtSrvr.getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)){
- ndbout << "Executing " << cmd << " on node: "
- << nodeId << endl << endl;
- (this->*fun)(nodeId, allAfterSecondToken, true);
- ndbout << endl;
- }
-}
-
-//*****************************************************************************
-//*****************************************************************************
-bool CommandInterpreter::parseBlockSpecification(const char* allAfterLog,
- Vector<BaseString>& blocks) {
-
- // Parse: [BLOCK = {ALL|<blockName>+}]
-
- if (emptyString(allAfterLog)) {
- return true;
- }
-
- // Copy allAfterLog since strtok will modify it
- char* newAllAfterLog = strdup(allAfterLog);
- char* firstTokenAfterLog = strtok(newAllAfterLog, " ");
- for (unsigned int i = 0; i < strlen(firstTokenAfterLog); ++i) {
- firstTokenAfterLog[i] = toupper(firstTokenAfterLog[i]);
- }
-
- if (strcmp(firstTokenAfterLog, "BLOCK") != 0) {
- ndbout << "Unexpected value: " << firstTokenAfterLog
- << ". Expected BLOCK." << endl;
- free(newAllAfterLog);
- return false;
- }
-
- char* allAfterFirstToken = strtok(NULL, "\0");
- if (emptyString(allAfterFirstToken)) {
- ndbout << "Expected =." << endl;
- free(newAllAfterLog);
- return false;
- }
-
- char* secondTokenAfterLog = strtok(allAfterFirstToken, " ");
- if (strcmp(secondTokenAfterLog, "=") != 0) {
- ndbout << "Unexpected value: " << secondTokenAfterLog
- << ". Expected =." << endl;
- free(newAllAfterLog);
- return false;
- }
-
- char* blockName = strtok(NULL, " ");
- bool all = false;
- if (blockName != NULL && (strcmp(blockName, "ALL") == 0)) {
- all = true;
- }
- while (blockName != NULL) {
- blocks.push_back(BaseString(blockName));
- blockName = strtok(NULL, " ");
- }
-
- if (blocks.size() == 0) {
- ndbout << "No block specified." << endl;
- free(newAllAfterLog);
- return false;
- }
- if (blocks.size() > 1 && all) {
- // More than "ALL" specified
- ndbout << "Nothing expected after ALL." << endl;
- free(newAllAfterLog);
- return false;
- }
-
- free(newAllAfterLog);
- return true;
-}
-
-void CommandInterpreter::executeLogIn(int processId,
- const char* parameters, bool all) {
-
- (void)all; // Don't want compiler warning
-
- Vector<BaseString> blocks;
- if (! parseBlockSpecification(parameters, blocks)) {
- return;
- }
-
- int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::In, blocks);
- if (result != 0) {
- ndbout << get_error_text(result) << endl;
- }
-}
-
-//******************************************************************************
-//******************************************************************************
-void CommandInterpreter::executeLogOut(int processId,
- const char* parameters, bool all) {
-
- (void)all; // Don't want compiler warning
-
- Vector<BaseString> blocks;
- if (! parseBlockSpecification(parameters, blocks)) {
- return;
- }
-
-
- int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Out, blocks);
- if (result != 0) {
- ndbout << get_error_text(result) << endl;
- }
-
-}
-
-
-//******************************************************************************
-//******************************************************************************
-void CommandInterpreter::executeLogOff(int processId,
- const char* parameters, bool all) {
-
- (void)all; // Don't want compiler warning
-
- Vector<BaseString> blocks;
- if (! parseBlockSpecification(parameters, blocks)) {
- return;
- }
-
-
- int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Off, blocks);
- if (result != 0) {
- ndbout << get_error_text(result) << endl;
- }
-
-}
-
-void CommandInterpreter::executeTrace(int processId,
- const char* parameters, bool all) {
-
- (void)all; // Don't want compiler warning
-
- if (emptyString(parameters)) {
- ndbout << "Missing trace number." << endl;
- return;
- }
-
- char* newpar = strdup(parameters);
- char* firstParameter = strtok(newpar, " ");
-
-
- int traceNo;
- if (! convert(firstParameter, traceNo)) {
- ndbout << "Expected an integer." << endl;
- free(newpar);
- return;
- }
-
- char* allAfterFirstParameter = strtok(NULL, "\0");
-
- if (! emptyString(allAfterFirstParameter)) {
- ndbout << "Nothing expected after trace number." << endl;
- free(newpar);
- return;
- }
-
- int result = _mgmtSrvr.setTraceNo(processId, traceNo);
- if (result != 0) {
- ndbout << get_error_text(result) << endl;
- }
- free(newpar);
-}
diff --git a/ndb/src/mgmsrv/CommandInterpreter.hpp b/ndb/src/mgmsrv/CommandInterpreter.hpp
deleted file mode 100644
index 6b67d1a5a5f..00000000000
--- a/ndb/src/mgmsrv/CommandInterpreter.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#ifndef CommandInterpreter_H
-#define CommandInterpreter_H
-
-#include <ndb_global.h>
-#include <Vector.hpp>
-#include <BaseString.hpp>
-
-class MgmtSrvr;
-
-class CommandInterpreter {
-public:
- CommandInterpreter(MgmtSrvr& mgmtSrvr);
- int readAndExecute();
-
-private:
- char m_err_str[1024];
- const char *get_error_text(int err_no);
-
- char *readline_gets ()
- {
- static char linebuffer[254];
- static char *line_read = (char *)NULL;
-
- /* If the buffer has already been allocated, return the memory
- to the free pool. */
- if (line_read)
- {
- free (line_read);
- line_read = (char *)NULL;
- }
-
- /* Get a line from the user. */
- fputs("ndb_mgmd> ", stdout);
- linebuffer[sizeof(linebuffer)-1]=0;
- line_read = fgets(linebuffer, sizeof(linebuffer)-1, stdin);
- if (line_read == linebuffer) {
- char *q=linebuffer;
- while (*q > 31) q++;
- *q=0;
- line_read= strdup(linebuffer);
- }
- return (line_read);
- }
-
- void analyseAfterFirstToken(int processId, char* allAfterFirstTokenCstr);
- bool parseBlockSpecification(const char* allAfterLog,
- Vector<BaseString>& blocks);
-
-public:
- void executeTrace(int processId, const char* parameters, bool all);
- void executeLogIn(int processId, const char* parameters, bool all);
- void executeLogOut(int processId, const char* parameters, bool all);
- void executeLogOff(int processId, const char* parameters, bool all);
-
-public:
- typedef void (CommandInterpreter::* ExecuteFunction)(int processId,
- const char * param,
- bool all);
-
- struct CommandFunctionPair {
- const char * command;
- ExecuteFunction executeFunction;
- };
-private:
- /**
- *
- */
- void executeForAll(const char * cmd, ExecuteFunction fun, const char * param);
-
- /**
- * Management server to use when executing commands
- */
- MgmtSrvr& _mgmtSrvr;
-};
-
-#endif // CommandInterpreter_H
diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp
index a0ace4b30db..67bf09fab10 100644
--- a/ndb/src/mgmsrv/ConfigInfo.cpp
+++ b/ndb/src/mgmsrv/ConfigInfo.cpp
@@ -1109,6 +1109,18 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
"15" },
{
+ CFG_LOGLEVEL_CONGESTION,
+ "LogLevelCongestion",
+ DB_TOKEN,
+ "Congestion info printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
CFG_LOGLEVEL_ERROR,
"LogLevelError",
DB_TOKEN,
@@ -3119,8 +3131,8 @@ fixPortNumber(InitConfigFileParser::Context & ctx, const char * data){
const Properties * node;
require(ctx.m_config->get("Node", id1, &node));
+
BaseString hostname(hostName1);
- // require(node->get("HostName", hostname));
if (hostname.c_str()[0] == 0) {
ctx.reportError("Hostname required on nodeid %d since it will "
@@ -3129,29 +3141,51 @@ fixPortNumber(InitConfigFileParser::Context & ctx, const char * data){
}
Uint32 port= 0;
- if (!node->get("ServerPort", &port) &&
- !ctx.m_userProperties.get("ServerPort_", id1, &port)) {
- Uint32 adder= 0;
- {
- BaseString server_port_adder(hostname);
- server_port_adder.append("_ServerPortAdder");
- ctx.m_userProperties.get(server_port_adder.c_str(), &adder);
- ctx.m_userProperties.put(server_port_adder.c_str(), adder+1, true);
- }
+ const char * type1;
+ const char * type2;
+ const Properties * node2;
+
+ node->get("Type", &type1);
+ ctx.m_config->get("Node", id2, &node2);
+ node2->get("Type", &type2);
+
+ if(strcmp(type1, MGM_TOKEN)==0)
+ node->get("PortNumber",&port);
+ else if(strcmp(type2, MGM_TOKEN)==0)
+ node2->get("PortNumber",&port);
+ if (!port &&
+ !node->get("ServerPort", &port) &&
+ !ctx.m_userProperties.get("ServerPort_", id1, &port))
+ {
Uint32 base= 0;
- if (!ctx.m_userProperties.get("ServerPortBase", &base)){
- if(!(ctx.m_userDefaults &&
+ /*
+ * If the connection doesn't involve an mgm server,
+ * and a default port number has been set, behave the old
+ * way of allocating port numbers for transporters.
+ */
+ if(ctx.m_userDefaults && ctx.m_userDefaults->get("PortNumber", &base))
+ {
+ Uint32 adder= 0;
+ {
+ BaseString server_port_adder(hostname);
+ server_port_adder.append("_ServerPortAdder");
+ ctx.m_userProperties.get(server_port_adder.c_str(), &adder);
+ ctx.m_userProperties.put(server_port_adder.c_str(), adder+1, true);
+ }
+
+ if (!ctx.m_userProperties.get("ServerPortBase", &base)){
+ if(!(ctx.m_userDefaults &&
ctx.m_userDefaults->get("PortNumber", &base)) &&
- !ctx.m_systemDefaults->get("PortNumber", &base)) {
- base= strtoll(NDB_TCP_BASE_PORT,0,0);
- // ctx.reportError("Cannot retrieve base port number");
- // return false;
+ !ctx.m_systemDefaults->get("PortNumber", &base)) {
+ base= strtoll(NDB_TCP_BASE_PORT,0,0);
+ }
+ ctx.m_userProperties.put("ServerPortBase", base);
}
- ctx.m_userProperties.put("ServerPortBase", base);
+
+ port= base + adder;
+ ctx.m_userProperties.put("ServerPort_", id1, port);
}
- port= base + adder;
- ctx.m_userProperties.put("ServerPort_", id1, port);
}
if(ctx.m_currentSection->contains("PortNumber")) {
@@ -3164,6 +3198,7 @@ fixPortNumber(InitConfigFileParser::Context & ctx, const char * data){
{
ctx.m_currentSection->put("PortNumber", port);
}
+
DBUG_PRINT("info", ("connection %d-%d port %d host %s",
id1, id2, port, hostname.c_str()));
diff --git a/ndb/src/mgmsrv/Makefile.am b/ndb/src/mgmsrv/Makefile.am
index 50e0b6023ad..7fd3fa66b43 100644
--- a/ndb/src/mgmsrv/Makefile.am
+++ b/ndb/src/mgmsrv/Makefile.am
@@ -16,17 +16,20 @@ ndb_mgmd_SOURCES = \
MgmtSrvrConfig.cpp \
ConfigInfo.cpp \
InitConfigFileParser.cpp \
- Config.cpp \
- CommandInterpreter.cpp
+ Config.cpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/src/ndbapi \
-I$(top_srcdir)/ndb/src/mgmapi \
- -I$(top_srcdir)/ndb/src/common/mgmcommon
+ -I$(top_srcdir)/ndb/src/common/mgmcommon \
+ -I$(top_srcdir)/ndb/src/mgmclient
-LDADD_LOC = $(top_builddir)/ndb/src/libndbclient.la \
+LDADD_LOC = $(top_srcdir)/ndb/src/mgmclient/CommandInterpreter.o \
+ $(top_builddir)/ndb/src/libndbclient.la \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/mysys/libmysys.a \
- $(top_builddir)/strings/libmystrings.a @NDB_SCI_LIBS@
+ $(top_builddir)/strings/libmystrings.a \
+ @readline_link@ \
+ @NDB_SCI_LIBS@ \
@TERMCAP_LIB@
DEFS_LOC = -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp
index ceaedc9955b..6b9bf7a0978 100644
--- a/ndb/src/mgmsrv/MgmtSrvr.cpp
+++ b/ndb/src/mgmsrv/MgmtSrvr.cpp
@@ -189,16 +189,16 @@ MgmtSrvr::logLevelThreadRun()
void
MgmtSrvr::startEventLog()
{
+ NdbMutex_Lock(m_configMutex);
+
g_eventLogger.setCategory("MgmSrvr");
- ndb_mgm_configuration_iterator * iter = ndb_mgm_create_configuration_iterator
- ((ndb_mgm_configuration*)_config->m_configValues, CFG_SECTION_NODE);
- if(iter == 0)
- return ;
-
- if(ndb_mgm_find(iter, CFG_NODE_ID, _ownNodeId) != 0){
- ndb_mgm_destroy_iterator(iter);
- return ;
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+
+ if(iter.find(CFG_NODE_ID, _ownNodeId) != 0){
+ NdbMutex_Unlock(m_configMutex);
+ return;
}
const char * tmp;
@@ -206,10 +206,10 @@ MgmtSrvr::startEventLog()
char *clusterLog= NdbConfig_ClusterLogFileName(_ownNodeId);
NdbAutoPtr<char> tmp_aptr(clusterLog);
- if(ndb_mgm_get_string_parameter(iter, CFG_LOG_DESTINATION, &tmp) == 0){
+ if(iter.get(CFG_LOG_DESTINATION, &tmp) == 0){
logdest.assign(tmp);
}
- ndb_mgm_destroy_iterator(iter);
+ NdbMutex_Unlock(m_configMutex);
if(logdest.length() == 0 || logdest == "") {
logdest.assfmt("FILE:filename=%s,maxsize=1000000,maxfiles=6",
@@ -343,42 +343,41 @@ MgmtSrvr::getNodeCount(enum ndb_mgm_node_type type) const
}
int
-MgmtSrvr::getPort() const {
- const Properties *mgmProps;
-
- ndb_mgm_configuration_iterator * iter =
- ndb_mgm_create_configuration_iterator(_config->m_configValues,
- CFG_SECTION_NODE);
- if(iter == 0)
+MgmtSrvr::getPort() const
+{
+ if(NdbMutex_Lock(m_configMutex))
return 0;
- if(ndb_mgm_find(iter, CFG_NODE_ID, getOwnNodeId()) != 0){
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+
+ if(iter.find(CFG_NODE_ID, getOwnNodeId()) != 0){
ndbout << "Could not retrieve configuration for Node "
<< getOwnNodeId() << " in config file." << endl
<< "Have you set correct NodeId for this node?" << endl;
- ndb_mgm_destroy_iterator(iter);
+ NdbMutex_Unlock(m_configMutex);
return 0;
}
unsigned type;
- if(ndb_mgm_get_int_parameter(iter, CFG_TYPE_OF_SECTION, &type) != 0 ||
+ if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0 ||
type != NODE_TYPE_MGM){
ndbout << "Local node id " << getOwnNodeId()
<< " is not defined as management server" << endl
<< "Have you set correct NodeId for this node?" << endl;
- ndb_mgm_destroy_iterator(iter);
+ NdbMutex_Unlock(m_configMutex);
return 0;
}
Uint32 port = 0;
- if(ndb_mgm_get_int_parameter(iter, CFG_MGM_PORT, &port) != 0){
+ if(iter.get(CFG_MGM_PORT, &port) != 0){
ndbout << "Could not find PortNumber in the configuration file." << endl;
- ndb_mgm_destroy_iterator(iter);
+ NdbMutex_Unlock(m_configMutex);
return 0;
}
- ndb_mgm_destroy_iterator(iter);
-
+ NdbMutex_Unlock(m_configMutex);
+
return port;
}
@@ -472,14 +471,14 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server,
{
ndb_mgm_configuration_iterator
- *iter = ndb_mgm_create_configuration_iterator(_config->m_configValues,
- CFG_SECTION_NODE);
- for(ndb_mgm_first(iter); ndb_mgm_valid(iter); ndb_mgm_next(iter)){
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+
+ for(iter.first(); iter.valid(); iter.next()){
unsigned type, id;
- if(ndb_mgm_get_int_parameter(iter, CFG_TYPE_OF_SECTION, &type) != 0)
+ if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0)
continue;
- if(ndb_mgm_get_int_parameter(iter, CFG_NODE_ID, &id) != 0)
+ if(iter.get(CFG_NODE_ID, &id) != 0)
continue;
MGM_REQUIRE(id < MAX_NODES);
@@ -502,7 +501,6 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server,
break;
}
}
- ndb_mgm_destroy_iterator(iter);
}
_props = NULL;
@@ -577,7 +575,8 @@ MgmtSrvr::start(BaseString &error_string)
return false;
}
}
- theFacade= TransporterFacade::theFacadeInstance= new TransporterFacade();
+ theFacade= TransporterFacade::theFacadeInstance
+ = new TransporterFacade();
if(theFacade == 0) {
DEBUG("MgmtSrvr.cpp: theFacade is NULL.");
@@ -605,6 +604,26 @@ MgmtSrvr::start(BaseString &error_string)
theFacade = 0;
return false;
}
+
+ TransporterRegistry *reg = theFacade->get_registry();
+ for(unsigned int i=0;i<reg->m_transporter_interface.size();i++) {
+ BaseString msg;
+ DBUG_PRINT("info",("Setting dynamic port %d->%d : %d",
+ reg->get_localNodeId(),
+ reg->m_transporter_interface[i].m_remote_nodeId,
+ reg->m_transporter_interface[i].m_s_service_port
+ )
+ );
+ int res = setConnectionDbParameter((int)reg->get_localNodeId(),
+ (int)reg->m_transporter_interface[i]
+ .m_remote_nodeId,
+ (int)CFG_CONNECTION_SERVER_PORT,
+ reg->m_transporter_interface[i]
+ .m_s_service_port,
+ msg);
+ DBUG_PRINT("info",("Set result: %d: %s",res,msg.c_str()));
+ }
+
_ownReference = numberToRef(_blockNumber, _ownNodeId);
@@ -1863,8 +1882,6 @@ void
MgmtSrvr::handleReceivedSignal(NdbApiSignal* signal)
{
// The way of handling a received signal is taken from the Ndb class.
- int returnCode;
-
int gsn = signal->readSignalNumber();
switch (gsn) {
@@ -2070,9 +2087,9 @@ MgmtSrvr::handleStatus(NodeId nodeId, bool alive, bool nfComplete)
theData[1] = nodeId;
if (alive) {
m_started_nodes.push_back(nodeId);
- theData[0] = EventReport::Connected;
+ theData[0] = NDB_LE_Connected;
} else {
- theData[0] = EventReport::Disconnected;
+ theData[0] = NDB_LE_Disconnected;
if(nfComplete)
{
handleStopReply(nodeId, 0);
@@ -2134,10 +2151,7 @@ MgmtSrvr::get_connected_nodes(NodeBitmask &connected_nodes) const
if (getNodeType(i) == NDB_MGM_NODE_TYPE_NDB)
{
const ClusterMgr::Node &node= theFacade->theClusterMgr->getNodeInfo(i);
- if (node.connected)
- {
- connected_nodes.bitOR(node.m_state.m_connected_nodes);
- }
+ connected_nodes.bitOR(node.m_state.m_connected_nodes);
}
}
}
@@ -2179,8 +2193,13 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId,
int r_config_addr= -1;
unsigned type_c= 0;
+ if(NdbMutex_Lock(m_configMutex))
+ {
+ error_string.appfmt("unable to lock configuration mutex");
+ return false;
+ }
ndb_mgm_configuration_iterator
- iter(*(ndb_mgm_configuration *)_config->m_configValues, CFG_SECTION_NODE);
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
for(iter.first(); iter.valid(); iter.next()) {
unsigned tmp= 0;
if(iter.get(CFG_NODE_ID, &tmp)) abort();
@@ -2247,6 +2266,7 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId,
"Suggest specifying node id in connectstring,\n"
"or specifying unique host names in config file.",
id_found, tmp);
+ NdbMutex_Unlock(m_configMutex);
DBUG_RETURN(false);
}
if (config_hostname == 0) {
@@ -2259,6 +2279,7 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId,
}
id_found= tmp; // mgmt server matched, check for more matches
}
+ NdbMutex_Unlock(m_configMutex);
if (id_found)
{
@@ -2401,7 +2422,7 @@ MgmtSrvr::eventReport(NodeId nodeId, const Uint32 * theData)
{
const EventReport * const eventReport = (EventReport *)&theData[0];
- EventReport::EventType type = eventReport->getEventType();
+ Ndb_logevent_type type = eventReport->getEventType();
// Log event
g_eventLogger.log(type, theData, nodeId,
&m_event_listner[0].m_logLevel);
@@ -2655,13 +2676,18 @@ MgmtSrvr::Allocated_resources::get_nodeid() const
int
MgmtSrvr::setDbParameter(int node, int param, const char * value,
BaseString& msg){
+
+ if(NdbMutex_Lock(m_configMutex))
+ return -1;
+
/**
* Check parameter
*/
- ndb_mgm_configuration_iterator iter(* _config->m_configValues,
- CFG_SECTION_NODE);
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
if(iter.first() != 0){
msg.assign("Unable to find node section (iter.first())");
+ NdbMutex_Unlock(m_configMutex);
return -1;
}
@@ -2669,16 +2695,19 @@ MgmtSrvr::setDbParameter(int node, int param, const char * value,
if(node != 0){
if(iter.find(CFG_NODE_ID, node) != 0){
msg.assign("Unable to find node (iter.find())");
+ NdbMutex_Unlock(m_configMutex);
return -1;
}
if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0){
msg.assign("Unable to get node type(iter.get(CFG_TYPE_OF_SECTION))");
+ NdbMutex_Unlock(m_configMutex);
return -1;
}
} else {
do {
if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0){
msg.assign("Unable to get node type(iter.get(CFG_TYPE_OF_SECTION))");
+ NdbMutex_Unlock(m_configMutex);
return -1;
}
if(type == NODE_TYPE_DB)
@@ -2689,6 +2718,7 @@ MgmtSrvr::setDbParameter(int node, int param, const char * value,
if(type != NODE_TYPE_DB){
msg.assfmt("Invalid node type or no such node (%d %d)",
type, NODE_TYPE_DB);
+ NdbMutex_Unlock(m_configMutex);
return -1;
}
@@ -2714,6 +2744,7 @@ MgmtSrvr::setDbParameter(int node, int param, const char * value,
break;
}
msg.assign("Could not get parameter");
+ NdbMutex_Unlock(m_configMutex);
return -1;
} while(0);
@@ -2751,9 +2782,144 @@ MgmtSrvr::setDbParameter(int node, int param, const char * value,
} while(node == 0 && iter.next() == 0);
msg.assign("Success");
+ NdbMutex_Unlock(m_configMutex);
return 0;
}
+int
+MgmtSrvr::setConnectionDbParameter(int node1,
+ int node2,
+ int param,
+ int value,
+ BaseString& msg){
+ Uint32 current_value,new_value;
+
+ DBUG_ENTER("MgmtSrvr::setConnectionDbParameter");
+
+ if(NdbMutex_Lock(m_configMutex))
+ {
+ DBUG_RETURN(-1);
+ }
+
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_CONNECTION);
+
+ if(iter.first() != 0){
+ msg.assign("Unable to find connection section (iter.first())");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-1);
+ }
+
+ for(;iter.valid();iter.next()) {
+ Uint32 n1,n2;
+ iter.get(CFG_CONNECTION_NODE_1, &n1);
+ iter.get(CFG_CONNECTION_NODE_2, &n2);
+ if((n1 == (unsigned)node1 && n2 == (unsigned)node2)
+ || (n1 == (unsigned)node2 && n2 == (unsigned)node1))
+ break;
+ }
+ if(!iter.valid()) {
+ msg.assign("Unable to find connection between nodes");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-2);
+ }
+
+ if(iter.get(param, &current_value) != 0) {
+ msg.assign("Unable to get current value of parameter");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-3);
+ }
+
+ ConfigValues::Iterator i2(_config->m_configValues->m_config,
+ iter.m_config);
+
+ if(i2.set(param, (unsigned)value) == false) {
+ msg.assign("Unable to set new value of parameter");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-4);
+ }
+
+ if(iter.get(param, &new_value) != 0) {
+ msg.assign("Unable to get parameter after setting it.");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-5);
+ }
+
+ msg.assfmt("%u -> %u",current_value,new_value);
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(1);
+}
+
+
+int
+MgmtSrvr::getConnectionDbParameter(int node1,
+ int node2,
+ int param,
+ int *value,
+ BaseString& msg){
+ DBUG_ENTER("MgmtSrvr::getConnectionDbParameter");
+
+ if(NdbMutex_Lock(m_configMutex))
+ {
+ DBUG_RETURN(-1);
+ }
+
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_CONNECTION);
+
+ if(iter.first() != 0){
+ msg.assign("Unable to find connection section (iter.first())");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-1);
+ }
+
+ for(;iter.valid();iter.next()) {
+ Uint32 n1=0,n2=0;
+ iter.get(CFG_CONNECTION_NODE_1, &n1);
+ iter.get(CFG_CONNECTION_NODE_2, &n2);
+ if((n1 == (unsigned)node1 && n2 == (unsigned)node2)
+ || (n1 == (unsigned)node2 && n2 == (unsigned)node1))
+ break;
+ }
+ if(!iter.valid()) {
+ msg.assign("Unable to find connection between nodes");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-1);
+ }
+
+ if(iter.get(param, (Uint32*)value) != 0) {
+ msg.assign("Unable to get current value of parameter");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-1);
+ }
+
+ msg.assfmt("%d",*value);
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(1);
+}
+
+void MgmtSrvr::transporter_connect(NDB_SOCKET_TYPE sockfd)
+{
+ if (theFacade->get_registry()->connect_server(sockfd))
+ {
+ /**
+ * Force an update_connections() so that the
+ * ClusterMgr and TransporterFacade is up to date
+ * with the new connection.
+ * Important for correct node id reservation handling
+ */
+ NdbMutex_Lock(theFacade->theMutexPtr);
+ theFacade->get_registry()->update_connections();
+ NdbMutex_Unlock(theFacade->theMutexPtr);
+ }
+}
+
+int MgmtSrvr::set_connect_string(const char *str)
+{
+ return ndb_mgm_set_connectstring(m_config_retriever->get_mgmHandle(),str);
+}
+
+
template class Vector<SigMatch>;
#if __SUNPRO_CC != 0x560
template bool SignalQueue::waitFor<SigMatch>(Vector<SigMatch>&, SigMatch**, NdbApiSignal**, unsigned);
diff --git a/ndb/src/mgmsrv/MgmtSrvr.hpp b/ndb/src/mgmsrv/MgmtSrvr.hpp
index ce78983b3c3..7e13b41438f 100644
--- a/ndb/src/mgmsrv/MgmtSrvr.hpp
+++ b/ndb/src/mgmsrv/MgmtSrvr.hpp
@@ -49,6 +49,7 @@ class Ndb_mgmd_event_service : public EventLoggerBase
public:
struct Event_listener : public EventLoggerBase {
NDB_SOCKET_TYPE m_socket;
+ Uint32 m_parsable;
};
private:
@@ -507,7 +508,17 @@ public:
int getPort() const;
int setDbParameter(int node, int parameter, const char * value, BaseString&);
-
+ int setConnectionDbParameter(int node1, int node2, int param, int value,
+ BaseString& msg);
+ int getConnectionDbParameter(int node1, int node2, int param,
+ int *value, BaseString& msg);
+
+ int set_connect_string(const char *str);
+
+ void transporter_connect(NDB_SOCKET_TYPE sockfd);
+
+ ConfigRetriever *get_config_retriever() { return m_config_retriever; };
+
const char *get_connect_address(Uint32 node_id) { return inet_ntoa(m_connect_address[node_id]); }
void get_connected_nodes(NodeBitmask &connected_nodes) const;
SocketServer *get_socket_server() { return m_socket_server; }
diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp
index 8ba8c2fe87e..bbd3db1e734 100644
--- a/ndb/src/mgmsrv/Services.cpp
+++ b/ndb/src/mgmsrv/Services.cpp
@@ -31,6 +31,7 @@
#include <mgmapi_configuration.hpp>
#include <Vector.hpp>
#include "Services.hpp"
+#include "../mgmapi/ndb_logevent.hpp"
extern bool g_StopServer;
@@ -241,14 +242,32 @@ ParserRow<MgmApiSession> commands[] = {
MGM_ARG("parameter", String, Mandatory, "Parameter"),
MGM_ARG("value", String, Mandatory, "Value"),
+ MGM_CMD("set connection parameter",
+ &MgmApiSession::setConnectionParameter, ""),
+ MGM_ARG("node1", String, Mandatory, "Node1 ID"),
+ MGM_ARG("node2", String, Mandatory, "Node2 ID"),
+ MGM_ARG("param", String, Mandatory, "Parameter"),
+ MGM_ARG("value", String, Mandatory, "Value"),
+
+ MGM_CMD("get connection parameter",
+ &MgmApiSession::getConnectionParameter, ""),
+ MGM_ARG("node1", String, Mandatory, "Node1 ID"),
+ MGM_ARG("node2", String, Mandatory, "Node2 ID"),
+ MGM_ARG("param", String, Mandatory, "Parameter"),
+
MGM_CMD("listen event", &MgmApiSession::listen_event, ""),
MGM_ARG("node", Int, Optional, "Node"),
+ MGM_ARG("parsable", Int, Optional, "Parsable"),
MGM_ARG("filter", String, Mandatory, "Event category"),
MGM_CMD("purge stale sessions", &MgmApiSession::purge_stale_sessions, ""),
MGM_CMD("check connection", &MgmApiSession::check_connection, ""),
+ MGM_CMD("transporter connect", &MgmApiSession::transporter_connect, ""),
+
+ MGM_CMD("get mgmd nodeid", &MgmApiSession::get_mgmd_nodeid, ""),
+
MGM_END()
};
@@ -301,7 +320,7 @@ MgmApiSession::runSession() {
break;
}
}
- if(m_socket >= 0)
+ if(m_socket != NDB_INVALID_SOCKET)
NDB_CLOSE_SOCKET(m_socket);
}
@@ -555,11 +574,13 @@ MgmApiSession::getConfig_common(Parser_t::Context &,
}
}
+ NdbMutex_Lock(m_mgmsrv.m_configMutex);
const ConfigValues * cfg = &conf->m_configValues->m_config;
const Uint32 size = cfg->getPackedSize();
UtilBuffer src;
cfg->pack(src);
+ NdbMutex_Unlock(m_mgmsrv.m_configMutex);
BaseString str;
int res = base64_encode(src, str);
@@ -1171,13 +1192,13 @@ MgmApiSession::startAll(Parser<MgmApiSession>::Context &,
void
MgmApiSession::setLogFilter(Parser_t::Context &ctx,
const class Properties &args) {
- Uint32 level;
+ Uint32 severity;
Uint32 enable;
- args.get("level", &level);
+ args.get("level", &severity);
args.get("enable", &enable);
- int result = m_mgmsrv.setEventLogFilter(level, enable);
+ int result = m_mgmsrv.setEventLogFilter(severity, enable);
m_output->println("set logfilter reply");
m_output->println("result: %d", result);
@@ -1236,25 +1257,49 @@ Ndb_mgmd_event_service::log(int eventType, const Uint32* theData, NodeId nodeId)
Uint32 threshold;
LogLevel::EventCategory cat;
Logger::LoggerLevel severity;
+ EventLoggerBase::EventTextFunction textF;
int i;
DBUG_ENTER("Ndb_mgmd_event_service::log");
DBUG_PRINT("enter",("eventType=%d, nodeid=%d", eventType, nodeId));
- if (EventLoggerBase::event_lookup(eventType,cat,threshold,severity))
+ if (EventLoggerBase::event_lookup(eventType,cat,threshold,severity,textF))
DBUG_VOID_RETURN;
char m_text[256];
- EventLogger::getText(m_text, sizeof(m_text), eventType, theData, nodeId);
+ EventLogger::getText(m_text, sizeof(m_text),
+ textF, theData, nodeId);
+
+ BaseString str("log event reply\n");
+ str.appfmt("type=%d\n", eventType);
+ str.appfmt("time=%d\n", 0);
+ str.appfmt("source_nodeid=%d\n", nodeId);
+ for (i= 0; ndb_logevent_body[i].token; i++)
+ {
+ if ( ndb_logevent_body[i].type != eventType)
+ continue;
+ int val= theData[ndb_logevent_body[i].index];
+ if (ndb_logevent_body[i].index_fn)
+ val= (*(ndb_logevent_body[i].index_fn))(val);
+ str.appfmt("%s=%d\n",ndb_logevent_body[i].token, val);
+ }
- Vector<NDB_SOCKET_TYPE> copy;
+ 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 &&
- println_socket(m_clients[i].m_socket,
- MAX_WRITE_TIMEOUT, m_text) == -1){
- copy.push_back(m_clients[i].m_socket);
- m_clients.erase(i, false);
+ if(m_clients[i].m_socket != NDB_INVALID_SOCKET)
+ {
+ int r;
+ if (m_clients[i].m_parsable)
+ r= println_socket(m_clients[i].m_socket,
+ MAX_WRITE_TIMEOUT, str.c_str());
+ else
+ r= println_socket(m_clients[i].m_socket,
+ MAX_WRITE_TIMEOUT, m_text);
+ if (r == -1) {
+ copy.push_back(m_clients[i].m_socket);
+ m_clients.erase(i, false);
+ }
}
}
}
@@ -1335,17 +1380,64 @@ MgmApiSession::setParameter(Parser_t::Context &,
}
void
+MgmApiSession::setConnectionParameter(Parser_t::Context &ctx,
+ Properties const &args) {
+ BaseString node1, node2, param, value;
+ args.get("node1", node1);
+ args.get("node2", node2);
+ args.get("param", param);
+ args.get("value", value);
+
+ BaseString result;
+ int ret = m_mgmsrv.setConnectionDbParameter(atoi(node1.c_str()),
+ atoi(node2.c_str()),
+ atoi(param.c_str()),
+ atoi(value.c_str()),
+ result);
+
+ m_output->println("set connection parameter reply");
+ m_output->println("message: %s", result.c_str());
+ m_output->println("result: %s", (ret>0)?"Ok":"Failed");
+ m_output->println("");
+}
+
+void
+MgmApiSession::getConnectionParameter(Parser_t::Context &ctx,
+ Properties const &args) {
+ BaseString node1, node2, param;
+ int value = 0;
+
+ args.get("node1", node1);
+ args.get("node2", node2);
+ args.get("param", param);
+
+ BaseString result;
+ int ret = m_mgmsrv.getConnectionDbParameter(atoi(node1.c_str()),
+ atoi(node2.c_str()),
+ atoi(param.c_str()),
+ &value,
+ result);
+
+ m_output->println("get connection parameter reply");
+ m_output->println("value: %d", value);
+ m_output->println("result: %s", (ret>0)?"Ok":result.c_str());
+ m_output->println("");
+}
+
+void
MgmApiSession::listen_event(Parser<MgmApiSession>::Context & ctx,
Properties const & args) {
-
+ Uint32 parsable= 0;
BaseString node, param, value;
args.get("node", node);
args.get("filter", param);
+ args.get("parsable", &parsable);
int result = 0;
BaseString msg;
Ndb_mgmd_event_service::Event_listener le;
+ le.m_parsable = parsable;
le.m_socket = m_socket;
Vector<BaseString> list;
@@ -1452,6 +1544,25 @@ MgmApiSession::check_connection(Parser_t::Context &ctx,
m_output->println("");
}
+void
+MgmApiSession::transporter_connect(Parser_t::Context &ctx,
+ Properties const &args)
+{
+ m_mgmsrv.transporter_connect(m_socket);
+
+ m_stop= true;
+ m_stopped= true; // force a stop (no closing socket)
+ m_socket= NDB_INVALID_SOCKET; // so nobody closes it
+}
+
+void
+MgmApiSession::get_mgmd_nodeid(Parser_t::Context &ctx,
+ Properties const &args)
+{
+ m_output->println("get mgmd nodeid reply");
+ m_output->println("nodeid:%u",m_mgmsrv.getOwnNodeId());
+ m_output->println("");
+}
+
template class MutexVector<int>;
template class Vector<ParserRow<MgmApiSession> const*>;
-template class Vector<unsigned short>;
diff --git a/ndb/src/mgmsrv/Services.hpp b/ndb/src/mgmsrv/Services.hpp
index 8627343b1cf..ff9008b05a8 100644
--- a/ndb/src/mgmsrv/Services.hpp
+++ b/ndb/src/mgmsrv/Services.hpp
@@ -88,10 +88,19 @@ public:
void configChange(Parser_t::Context &ctx, const class Properties &args);
void setParameter(Parser_t::Context &ctx, const class Properties &args);
+ void setConnectionParameter(Parser_t::Context &ctx,
+ const class Properties &args);
+ void getConnectionParameter(Parser_t::Context &ctx,
+ Properties const &args);
+
void listen_event(Parser_t::Context &ctx, const class Properties &args);
void purge_stale_sessions(Parser_t::Context &ctx, const class Properties &args);
void check_connection(Parser_t::Context &ctx, const class Properties &args);
+
+ void transporter_connect(Parser_t::Context &ctx, Properties const &args);
+
+ void get_mgmd_nodeid(Parser_t::Context &ctx, Properties const &args);
void repCommand(Parser_t::Context &ctx, const class Properties &args);
};
diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp
index 61b83b86538..3335fdc827c 100644
--- a/ndb/src/mgmsrv/main.cpp
+++ b/ndb/src/mgmsrv/main.cpp
@@ -40,7 +40,7 @@
#if defined NDB_OSE || defined NDB_SOFTOSE
#include <efs.h>
#else
-#include "CommandInterpreter.hpp"
+#include <ndb_mgmclient.hpp>
#endif
#undef DEBUG
@@ -48,11 +48,54 @@
const char progname[] = "mgmtsrvr";
+// copied from mysql.cc to get readline
+extern "C" {
+#if defined( __WIN__) || defined(OS2)
+#include <conio.h>
+#elif !defined(__NETWARE__)
+#include <readline/readline.h>
+extern "C" int add_history(const char *command); /* From readline directory */
+#define HAVE_READLINE
+#endif
+}
+
+static int
+read_and_execute(Ndb_mgmclient* com, const char * prompt, int _try_reconnect)
+{
+ static char *line_read = (char *)NULL;
+
+ /* If the buffer has already been allocated, return the memory
+ to the free pool. */
+ if (line_read)
+ {
+ free (line_read);
+ line_read = (char *)NULL;
+ }
+#ifdef HAVE_READLINE
+ /* Get a line from the user. */
+ line_read = readline (prompt);
+ /* If the line has any text in it, save it on the history. */
+ if (line_read && *line_read)
+ add_history (line_read);
+#else
+ static char linebuffer[254];
+ fputs(prompt, stdout);
+ linebuffer[sizeof(linebuffer)-1]=0;
+ line_read = fgets(linebuffer, sizeof(linebuffer)-1, stdin);
+ if (line_read == linebuffer) {
+ char *q=linebuffer;
+ while (*q > 31) q++;
+ *q=0;
+ line_read= strdup(linebuffer);
+ }
+#endif
+ return com->execute(line_read,_try_reconnect);
+}
/**
* @struct MgmGlobals
* @brief Global Variables used in the management server
- ******************************************************************************/
+ *****************************************************************************/
struct MgmGlobals {
MgmGlobals();
~MgmGlobals();
@@ -67,7 +110,7 @@ struct MgmGlobals {
NodeId localNodeId;
bool use_specific_ip;
char * interface_name;
- int port;
+ short unsigned int port;
/** The Mgmt Server */
MgmtSrvr * mgmObject;
@@ -97,13 +140,6 @@ enum ndb_mgmd_options {
};
NDB_STD_OPTS_VARS;
-#if NDB_VERSION_MAJOR <= 4
-#undef OPT_NDB_CONNECTSTRING
-#define OPT_NDB_CONNECTSTRING 1023
-#else
-
-#endif
-
static struct my_option my_long_options[] =
{
NDB_STD_OPTS("ndb_mgmd"),
@@ -125,15 +161,9 @@ static struct my_option my_long_options[] =
"Don't run as daemon, but don't read from stdin",
(gptr*) &glob.non_interactive, (gptr*) &glob.non_interactive, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
-#if NDB_VERSION_MAJOR <= 4
- { "config-file", 'c',
- "-c provided for backwards compatability, will be removed in 5.0."
- " Use -f instead",
- (gptr*) &glob.config_filename, (gptr*) &glob.config_filename, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
-#endif
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
+
static void short_usage_sub(void)
{
printf("Usage: %s [OPTIONS]\n", my_progname);
@@ -145,21 +175,6 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_mgmd.trace");
-#if NDB_VERSION_MAJOR <= 4
- switch (optid) {
- case 'c':
- printf("Warning: -c will be removed in 5.0, use -f instead\n");
- break;
- }
-#endif
- return 0;
-}
/*
* MAIN
@@ -183,7 +198,11 @@ int main(int argc, char** argv)
load_defaults("my",load_default_groups,&argc,&argv);
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_mgmd.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
exit(ho_error);
if (glob.interactive ||
@@ -235,7 +254,7 @@ int main(int argc, char** argv)
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"
@@ -244,13 +263,36 @@ int main(int argc, char** argv)
delete mapi;
goto error_end;
}
-
+
+ /* 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());
+ opt_connect_str= connect_str;
+ }
+ glob.mgmObject->set_connect_string(opt_connect_str);
+
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;
}
+ /*
+ * Connect back to ourselves so we can use mgmapi to fetch
+ * config info
+ */
+ int mgm_connect_result;
+ mgm_connect_result = glob.mgmObject->get_config_retriever()->
+ do_connect(0,0,0);
+
+ if(mgm_connect_result<0) {
+ ndbout_c("Unable to connect to our own ndb_mgmd (Error %d)",
+ mgm_connect_result);
+ ndbout_c("This is probably a bug.");
+ }
+
+
if (glob.daemon) {
// Become a daemon
char *lockfile= NdbConfig_PidFileName(glob.localNodeId);
@@ -295,14 +337,19 @@ int main(int argc, char** argv)
#if ! defined NDB_OSE && ! defined NDB_SOFTOSE
if(glob.interactive) {
- CommandInterpreter com(* glob.mgmObject);
- while(com.readAndExecute());
+ BaseString con_str;
+ if(glob.interface_name)
+ con_str.appfmt("host=%s:%d", glob.interface_name, glob.port);
+ else
+ 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
#endif
- {
- while(g_StopServer != true)
- NdbSleep_MilliSleep(500);
- }
+ {
+ while(g_StopServer != true)
+ NdbSleep_MilliSleep(500);
+ }
g_eventLogger.info("Shutting down server...");
glob.socketServer->stopServer();
diff --git a/ndb/src/ndbapi/ClusterMgr.cpp b/ndb/src/ndbapi/ClusterMgr.cpp
index 1fe0cedbd6c..71938e27037 100644
--- a/ndb/src/ndbapi/ClusterMgr.cpp
+++ b/ndb/src/ndbapi/ClusterMgr.cpp
@@ -260,6 +260,7 @@ ClusterMgr::Node::Node()
: m_state(NodeState::SL_NOTHING) {
compatible = nfCompleteRep = true;
connected = defined = m_alive = false;
+ m_state.m_connected_nodes.clear();
}
/******************************************************************************
@@ -410,7 +411,13 @@ ClusterMgr::reportConnected(NodeId nodeId){
theNode.connected = true;
theNode.hbSent = 0;
theNode.hbCounter = 0;
-
+
+ /**
+ * make sure the node itself is marked connected even
+ * if first API_REGCONF has not arrived
+ */
+ theNode.m_state.m_connected_nodes.set(nodeId);
+
if (theNode.m_info.m_type != NodeInfo::REP) {
theNode.hbFrequency = 0;
}
@@ -428,7 +435,9 @@ ClusterMgr::reportDisconnected(NodeId nodeId){
noOfConnectedNodes--;
theNodes[nodeId].connected = false;
- theNodes[nodeId].m_info.m_connectCount ++;
+
+ theNodes[nodeId].m_state.m_connected_nodes.clear();
+
reportNodeFailed(nodeId);
}
@@ -438,18 +447,22 @@ ClusterMgr::reportNodeFailed(NodeId nodeId){
Node & theNode = theNodes[nodeId];
theNode.m_alive = false;
+ theNode.m_info.m_connectCount ++;
+
if(theNode.connected)
+ {
theFacade.doDisconnect(nodeId);
-
+ }
const bool report = (theNode.m_state.startLevel != NodeState::SL_NOTHING);
theNode.m_state.startLevel = NodeState::SL_NOTHING;
- if(report){
+ if(report)
+ {
theFacade.ReportNodeDead(nodeId);
- }
-
+ }
+
theNode.nfCompleteRep = false;
-
+
if(noOfConnectedNodes == 0){
NFCompleteRep rep;
for(Uint32 i = 1; i<MAX_NODES; i++){
diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp
index 9cdd68272ad..da9d5b70d47 100644
--- a/ndb/src/ndbapi/DictCache.cpp
+++ b/ndb/src/ndbapi/DictCache.cpp
@@ -24,7 +24,7 @@
Ndb_local_table_info *
Ndb_local_table_info::create(NdbTableImpl *table_impl, Uint32 sz)
{
- Uint32 tot_size= sizeof(NdbTableImpl *) + ((sz+7)>>3)<<3; // round to Uint64
+ Uint32 tot_size= sizeof(NdbTableImpl *) + ((sz+7) & ~7); // round to Uint64
void *data= malloc(tot_size);
if (data == 0)
return 0;
diff --git a/ndb/src/ndbapi/Makefile.am b/ndb/src/ndbapi/Makefile.am
index 9f8a851b995..b734e058b87 100644
--- a/ndb/src/ndbapi/Makefile.am
+++ b/ndb/src/ndbapi/Makefile.am
@@ -14,15 +14,14 @@ libndbapi_la_SOURCES = \
Ndberr.cpp \
ndberror.c \
NdbErrorOut.cpp \
- NdbConnection.cpp \
- NdbConnectionScan.cpp \
+ NdbTransaction.cpp \
+ NdbTransactionScan.cpp \
NdbOperation.cpp \
NdbOperationSearch.cpp \
NdbOperationScan.cpp \
NdbOperationInt.cpp \
NdbOperationDefine.cpp \
NdbOperationExec.cpp \
- NdbResultSet.cpp \
NdbScanOperation.cpp NdbScanFilter.cpp \
NdbIndexOperation.cpp \
NdbEventOperation.cpp \
diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp
index 9d520d5eac9..c01ce823dc0 100644
--- a/ndb/src/ndbapi/Ndb.cpp
+++ b/ndb/src/ndbapi/Ndb.cpp
@@ -27,7 +27,7 @@ Name: Ndb.cpp
#include "NdbApiSignal.hpp"
#include "NdbImpl.hpp"
#include <NdbOperation.hpp>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <NdbEventOperation.hpp>
#include <NdbRecAttr.hpp>
#include <md5_hash.hpp>
@@ -43,11 +43,13 @@ void connect();
Connect to any node which has no connection at the moment.
****************************************************************************/
-NdbConnection* Ndb::doConnect(Uint32 tConNode)
+NdbTransaction* Ndb::doConnect(Uint32 tConNode)
{
Uint32 tNode;
Uint32 tAnyAlive = 0;
- int TretCode;
+ int TretCode= 0;
+
+ DBUG_ENTER("Ndb::doConnect");
if (tConNode != 0) {
TretCode = NDB_connect(tConNode);
@@ -55,7 +57,7 @@ NdbConnection* Ndb::doConnect(Uint32 tConNode)
//****************************************************************************
// We have connections now to the desired node. Return
//****************************************************************************
- return getConnectedNdbConnection(tConNode);
+ DBUG_RETURN(getConnectedNdbTransaction(tConNode));
} else if (TretCode != 0) {
tAnyAlive = 1;
}//if
@@ -78,10 +80,13 @@ NdbConnection* Ndb::doConnect(Uint32 tConNode)
//****************************************************************************
// We have connections now to the desired node. Return
//****************************************************************************
- return getConnectedNdbConnection(tNode);
+ DBUG_RETURN(getConnectedNdbTransaction(tNode));
} else if (TretCode != 0) {
tAnyAlive= 1;
}//if
+ DBUG_PRINT("info",("tried node %d, TretCode %d, error code %d, %s",
+ tNode, TretCode, getNdbError().code,
+ getNdbError().message));
}
}
else // just do a regular round robin
@@ -103,10 +108,11 @@ NdbConnection* Ndb::doConnect(Uint32 tConNode)
//****************************************************************************
// We have connections now to the desired node. Return
//****************************************************************************
- return getConnectedNdbConnection(tNode);
+ DBUG_RETURN(getConnectedNdbTransaction(tNode));
} else if (TretCode != 0) {
tAnyAlive= 1;
}//if
+ DBUG_PRINT("info",("tried node %d TretCode %d", tNode, TretCode));
} while (Tcount < tNoOfDbNodes);
}
//****************************************************************************
@@ -121,7 +127,7 @@ NdbConnection* Ndb::doConnect(Uint32 tConNode)
} else {
theError.code = 4009;
}//if
- return NULL;
+ DBUG_RETURN(NULL);
}
int
@@ -134,36 +140,38 @@ Ndb::NDB_connect(Uint32 tNode)
int tReturnCode;
TransporterFacade *tp = TransporterFacade::instance();
+ DBUG_ENTER("Ndb::NDB_connect");
+
bool nodeAvail = tp->get_node_alive(tNode);
if(nodeAvail == false){
- return 0;
+ DBUG_RETURN(0);
}
- NdbConnection * tConArray = theConnectionArray[tNode];
+ NdbTransaction * tConArray = theConnectionArray[tNode];
if (tConArray != NULL) {
- return 2;
+ DBUG_RETURN(2);
}
- NdbConnection * tNdbCon = getNdbCon(); // Get free connection object.
+ NdbTransaction * tNdbCon = getNdbCon(); // Get free connection object.
if (tNdbCon == NULL) {
- return 4;
+ DBUG_RETURN(4);
}//if
NdbApiSignal* tSignal = getSignal(); // Get signal object
if (tSignal == NULL) {
releaseNdbCon(tNdbCon);
- return 4;
+ DBUG_RETURN(4);
}//if
if (tSignal->setSignal(GSN_TCSEIZEREQ) == -1) {
releaseNdbCon(tNdbCon);
releaseSignal(tSignal);
- return 4;
+ DBUG_RETURN(4);
}//if
tSignal->setData(tNdbCon->ptr2int(), 1);
//************************************************
-// Set connection pointer as NdbConnection object
+// Set connection pointer as NdbTransaction object
//************************************************
tSignal->setData(theMyRef, 2); // Set my block reference
- tNdbCon->Status(NdbConnection::Connecting); // Set status to connecting
+ tNdbCon->Status(NdbTransaction::Connecting); // Set status to connecting
Uint32 nodeSequence;
{ // send and receive signal
Guard guard(tp->theMutexPtr);
@@ -182,34 +190,37 @@ Ndb::NDB_connect(Uint32 tNode)
tReturnCode = -1;
}//if
}
- if ((tReturnCode == 0) && (tNdbCon->Status() == NdbConnection::Connected)) {
+ if ((tReturnCode == 0) && (tNdbCon->Status() == NdbTransaction::Connected)) {
//************************************************
// Send and receive was successful
//************************************************
- NdbConnection* tPrevFirst = theConnectionArray[tNode];
+ NdbTransaction* tPrevFirst = theConnectionArray[tNode];
tNdbCon->setConnectedNodeId(tNode, nodeSequence);
tNdbCon->setMyBlockReference(theMyRef);
theConnectionArray[tNode] = tNdbCon;
tNdbCon->theNext = tPrevFirst;
- return 1;
+ DBUG_RETURN(1);
} else {
releaseNdbCon(tNdbCon);
//****************************************************************************
// Unsuccessful connect is indicated by 3.
//****************************************************************************
- return 3;
+ DBUG_PRINT("info",
+ ("unsuccessful connect tReturnCode %d, tNdbCon->Status() %d",
+ tReturnCode, tNdbCon->Status()));
+ DBUG_RETURN(3);
}//if
}//Ndb::NDB_connect()
-NdbConnection *
-Ndb::getConnectedNdbConnection(Uint32 nodeId){
- NdbConnection* next = theConnectionArray[nodeId];
+NdbTransaction *
+Ndb::getConnectedNdbTransaction(Uint32 nodeId){
+ NdbTransaction* next = theConnectionArray[nodeId];
theConnectionArray[nodeId] = next->theNext;
next->theNext = NULL;
return next;
-}//Ndb::getConnectedNdbConnection()
+}//Ndb::getConnectedNdbTransaction()
/*****************************************************************************
disconnect();
@@ -220,7 +231,7 @@ void
Ndb::doDisconnect()
{
DBUG_ENTER("Ndb::doDisconnect");
- NdbConnection* tNdbCon;
+ NdbTransaction* tNdbCon;
CHECK_STATUS_MACRO_VOID;
Uint32 tNoOfDbNodes = theImpl->theNoOfDBnodes;
@@ -231,14 +242,14 @@ Ndb::doDisconnect()
Uint32 tNode = theDBnodes[i];
tNdbCon = theConnectionArray[tNode];
while (tNdbCon != NULL) {
- NdbConnection* tmpNdbCon = tNdbCon;
+ NdbTransaction* tmpNdbCon = tNdbCon;
tNdbCon = tNdbCon->theNext;
releaseConnectToNdb(tmpNdbCon);
}//while
}//for
tNdbCon = theTransactionList;
while (tNdbCon != NULL) {
- NdbConnection* tmpNdbCon = tNdbCon;
+ NdbTransaction* tmpNdbCon = tNdbCon;
tNdbCon = tNdbCon->theNext;
releaseConnectToNdb(tmpNdbCon);
}//while
@@ -292,34 +303,58 @@ Ndb::waitUntilReady(int timeout)
}
/*****************************************************************************
-NdbConnection* startTransaction();
+NdbTransaction* startTransaction();
Return Value: Returns a pointer to a connection object.
Return NULL otherwise.
Remark: Start transaction. Synchronous.
*****************************************************************************/
-NdbConnection*
-Ndb::startTransaction(Uint32 aPriority, const char * keyData, Uint32 keyLen)
+NdbTransaction*
+Ndb::startTransaction(const NdbDictionary::Table *table,
+ const char * keyData, Uint32 keyLen)
{
DBUG_ENTER("Ndb::startTransaction");
if (theInitState == Initialised) {
theError.code = 0;
checkFailedNode();
- /**
- * If the user supplied key data
- * We will make a qualified quess to which node is the primary for the
- * the fragment and contact that node
- */
+ /**
+ * If the user supplied key data
+ * We will make a qualified quess to which node is the primary for the
+ * the fragment and contact that node
+ */
Uint32 nodeId;
- if(keyData != 0) {
- nodeId = 0; // guess not supported
- // nodeId = m_ndb_cluster_connection->guess_primary_node(keyData, keyLen);
+ NdbTableImpl* impl;
+ if(table != 0 && keyData != 0 && (impl= &NdbTableImpl::getImpl(*table)))
+ {
+ Uint32 hashValue;
+ {
+ Uint32 buf[4];
+ if((UintPtr(keyData) & 7) == 0 && (keyLen & 3) == 0)
+ {
+ md5_hash(buf, (const Uint64*)keyData, keyLen >> 2);
+ }
+ else
+ {
+ Uint64 tmp[1000];
+ tmp[keyLen/8] = 0;
+ memcpy(tmp, keyData, keyLen);
+ md5_hash(buf, tmp, (keyLen+3) >> 2);
+ }
+ hashValue= buf[1];
+ }
+ const Uint16 *nodes;
+ Uint32 cnt= impl->get_nodes(hashValue, &nodes);
+ if(cnt)
+ nodeId= nodes[0];
+ else
+ nodeId= 0;
} else {
nodeId = 0;
}//if
+
{
- NdbConnection *trans= startTransactionLocal(aPriority, nodeId);
+ NdbTransaction *trans= startTransactionLocal(0, nodeId);
DBUG_PRINT("exit",("start trans: 0x%x transid: 0x%llx",
trans, trans ? trans->getTransactionId() : 0));
DBUG_RETURN(trans);
@@ -330,15 +365,15 @@ Ndb::startTransaction(Uint32 aPriority, const char * keyData, Uint32 keyLen)
}//Ndb::startTransaction()
/*****************************************************************************
-NdbConnection* hupp(NdbConnection* pBuddyTrans);
+NdbTransaction* hupp(NdbTransaction* pBuddyTrans);
Return Value: Returns a pointer to a connection object.
Connected to the same node as pBuddyTrans
and also using the same transction id
Remark: Start transaction. Synchronous.
*****************************************************************************/
-NdbConnection*
-Ndb::hupp(NdbConnection* pBuddyTrans)
+NdbTransaction*
+Ndb::hupp(NdbTransaction* pBuddyTrans)
{
DBUG_ENTER("Ndb::hupp");
@@ -354,7 +389,7 @@ Ndb::hupp(NdbConnection* pBuddyTrans)
checkFailedNode();
Uint32 nodeId = pBuddyTrans->getConnectedNodeId();
- NdbConnection* pCon = startTransactionLocal(aPriority, nodeId);
+ NdbTransaction* pCon = startTransactionLocal(aPriority, nodeId);
if(pCon == NULL)
DBUG_RETURN(NULL);
@@ -375,8 +410,7 @@ Ndb::hupp(NdbConnection* pBuddyTrans)
}//if
}//Ndb::hupp()
-
-NdbConnection*
+NdbTransaction*
Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId)
{
#ifdef VM_TRACE
@@ -390,13 +424,13 @@ Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId)
DBUG_ENTER("Ndb::startTransactionLocal");
DBUG_PRINT("enter", ("nodeid: %d", nodeId));
- NdbConnection* tConnection;
+ NdbTransaction* tConnection;
Uint64 tFirstTransId = theFirstTransId;
tConnection = doConnect(nodeId);
if (tConnection == NULL) {
DBUG_RETURN(NULL);
}//if
- NdbConnection* tConNext = theTransactionList;
+ NdbTransaction* tConNext = theTransactionList;
tConnection->init();
theTransactionList = tConnection; // into a transaction list.
tConnection->next(tConNext); // Add the active connection object
@@ -412,7 +446,7 @@ Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId)
theFirstTransId = tFirstTransId + 1;
}//if
#ifdef VM_TRACE
- if (tConnection->theListState != NdbConnection::NotInList) {
+ if (tConnection->theListState != NdbTransaction::NotInList) {
printState("startTransactionLocal %x", tConnection);
abort();
}
@@ -421,17 +455,17 @@ Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId)
}//Ndb::startTransactionLocal()
/*****************************************************************************
-void closeTransaction(NdbConnection* aConnection);
+void closeTransaction(NdbTransaction* aConnection);
Parameters: aConnection: the connection used in the transaction.
Remark: Close transaction by releasing the connection and all operations.
*****************************************************************************/
void
-Ndb::closeTransaction(NdbConnection* aConnection)
+Ndb::closeTransaction(NdbTransaction* aConnection)
{
DBUG_ENTER("Ndb::closeTransaction");
- NdbConnection* tCon;
- NdbConnection* tPreviousCon;
+ NdbTransaction* tCon;
+ NdbTransaction* tPreviousCon;
if (aConnection == NULL) {
//-----------------------------------------------------
@@ -464,12 +498,12 @@ Ndb::closeTransaction(NdbConnection* aConnection)
if(aConnection->theError.code == 4008){
/**
- * When a SCAN timed-out, returning the NdbConnection leads
+ * When a SCAN timed-out, returning the NdbTransaction leads
* to reuse. And TC crashes when the API tries to reuse it to
* something else...
*/
#ifdef VM_TRACE
- printf("Scan timeout:ed NdbConnection-> "
+ printf("Scan timeout:ed NdbTransaction-> "
"not returning it-> memory leak\n");
#endif
DBUG_VOID_RETURN;
@@ -491,12 +525,12 @@ Ndb::closeTransaction(NdbConnection* aConnection)
if(aConnection->theError.code == 4008){
/**
- * Something timed-out, returning the NdbConnection leads
+ * Something timed-out, returning the NdbTransaction leads
* to reuse. And TC crashes when the API tries to reuse it to
* something else...
*/
#ifdef VM_TRACE
- printf("Con timeout:ed NdbConnection-> not returning it-> memory leak\n");
+ printf("Con timeout:ed NdbTransaction-> not returning it-> memory leak\n");
#endif
DBUG_VOID_RETURN;
}
@@ -535,7 +569,7 @@ Remark: Sends a signal to DIH.
int
Ndb::NdbTamper(TamperType aAction, int aNode)
{
- NdbConnection* tNdbConn;
+ NdbTransaction* tNdbConn;
NdbApiSignal tSignal(theMyRef);
int tNode;
int tAction;
@@ -577,7 +611,7 @@ Ndb::NdbTamper(TamperType aAction, int aNode)
tSignal.setData (tAction, 1);
tSignal.setData(tNdbConn->ptr2int(),2);
tSignal.setData(theMyRef,3); // Set return block reference
- tNdbConn->Status(NdbConnection::Connecting); // Set status to connecting
+ tNdbConn->Status(NdbTransaction::Connecting); // Set status to connecting
TransporterFacade *tp = TransporterFacade::instance();
if (tAction == 3) {
tp->lock_mutex();
@@ -610,7 +644,7 @@ Ndb::NdbTamper(TamperType aAction, int aNode)
}//if
ret_code = sendRecSignal(tNode, WAIT_NDB_TAMPER, &tSignal, 0);
if (ret_code == 0) {
- if (tNdbConn->Status() != NdbConnection::Connected) {
+ if (tNdbConn->Status() != NdbTransaction::Connected) {
theRestartGCI = 0;
}//if
releaseNdbCon(tNdbConn);
@@ -873,10 +907,11 @@ Ndb::setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase )
Uint64
Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op)
{
- DEBUG_TRACE("opTupleIdOnNdb");
+ DBUG_ENTER("Ndb::opTupleIdOnNdb");
+ DBUG_PRINT("enter", ("table=%u value=%llu op=%u", aTableId, opValue, op));
- NdbConnection* tConnection;
- NdbOperation* tOperation;
+ NdbTransaction* tConnection;
+ NdbOperation* tOperation= 0; // Compiler warning if not initialized
Uint64 tValue;
NdbRecAttr* tRecAttrResult;
int result;
@@ -969,7 +1004,7 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op)
setDatabaseName(currentDb.c_str());
setDatabaseSchemaName(currentSchema.c_str());
- return ret;
+ DBUG_RETURN(ret);
error_handler:
theError.code = tConnection->theError.code;
@@ -979,7 +1014,11 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op)
setDatabaseName(currentDb.c_str());
setDatabaseSchemaName(currentSchema.c_str());
- return ~(Uint64)0;
+ DBUG_PRINT("error", ("ndb=%d con=%d op=%d",
+ theError.code,
+ tConnection ? tConnection->theError.code : -1,
+ tOperation ? tOperation->theError.code : -1));
+ DBUG_RETURN(~(Uint64)0);
}
Uint32
@@ -1181,7 +1220,14 @@ NdbEventOperation* Ndb::createEventOperation(const char* eventName,
tOp = new NdbEventOperation(this, eventName, bufferLength);
- if (tOp->getState() != NdbEventOperation::CREATED) {
+ if (tOp == 0)
+ {
+ theError.code= 4000;
+ return NULL;
+ }
+
+ if (tOp->getState() != NdbEventOperation::EO_CREATED) {
+ theError.code= tOp->getNdbError().code;
delete tOp;
tOp = NULL;
}
@@ -1217,7 +1263,7 @@ Ndb::pollEvents(int aMillisecondNumber)
extern NdbMutex *ndb_print_state_mutex;
static bool
-checkdups(NdbConnection** list, unsigned no)
+checkdups(NdbTransaction** list, unsigned no)
{
for (unsigned i = 0; i < no; i++)
for (unsigned j = i + 1; j < no; j++)
@@ -1242,7 +1288,7 @@ Ndb::printState(const char* fmt, ...)
#endif
ndbout << endl;
for (unsigned n = 0; n < MAX_NDB_NODES; n++) {
- NdbConnection* con = theConnectionArray[n];
+ NdbTransaction* con = theConnectionArray[n];
if (con != 0) {
ndbout << "conn " << n << ":" << endl;
while (con != 0) {
diff --git a/ndb/src/ndbapi/NdbApiSignal.cpp b/ndb/src/ndbapi/NdbApiSignal.cpp
index a1d34896968..b1671e593e1 100644
--- a/ndb/src/ndbapi/NdbApiSignal.cpp
+++ b/ndb/src/ndbapi/NdbApiSignal.cpp
@@ -213,7 +213,7 @@ NdbApiSignal::setSignal(int aNdbSignalType)
theTrace = TestOrd::TraceAPI;
theReceiversBlockNumber = DBTC;
theVerId_signalNumber = GSN_TCINDXREQ;
- theLength = TcIndxReq::SignalLength;
+ theLength = TcKeyReq::SignalLength;
}
break;
diff --git a/ndb/src/ndbapi/NdbApiSignal.hpp b/ndb/src/ndbapi/NdbApiSignal.hpp
index 52c3be2256c..353c575d420 100644
--- a/ndb/src/ndbapi/NdbApiSignal.hpp
+++ b/ndb/src/ndbapi/NdbApiSignal.hpp
@@ -93,7 +93,7 @@ private:
void setDataPtr(Uint32 *);
- friend class NdbConnection;
+ friend class NdbTransaction;
friend class NdbScanReceiver;
friend class Table;
void copyFrom(const NdbApiSignal * src);
diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp
index f72361b86ac..0638f6e4c51 100644
--- a/ndb/src/ndbapi/NdbBlob.cpp
+++ b/ndb/src/ndbapi/NdbBlob.cpp
@@ -16,7 +16,7 @@
#include <Ndb.hpp>
#include <NdbDictionaryImpl.hpp>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <NdbOperation.hpp>
#include <NdbIndexOperation.hpp>
#include <NdbRecAttr.hpp>
@@ -100,8 +100,8 @@ NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnIm
bt.setFragmentType(t->getFragmentType());
{ NdbDictionary::Column bc("PK");
bc.setType(NdbDictionary::Column::Unsigned);
- assert(t->m_sizeOfKeysInWords != 0);
- bc.setLength(t->m_sizeOfKeysInWords);
+ assert(t->m_keyLenInWords != 0);
+ bc.setLength(t->m_keyLenInWords);
bc.setPrimaryKey(true);
bc.setDistributionKey(true);
bt.addColumn(bc);
@@ -347,7 +347,7 @@ int
NdbBlob::setTableKeyValue(NdbOperation* anOp)
{
const Uint32* data = (const Uint32*)theKeyBuf.data;
- DBG("setTableKeyValue key=" << ndb_blob_debug(data, theTable->m_sizeOfKeysInWords));
+ 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++) {
@@ -370,7 +370,7 @@ int
NdbBlob::setAccessKeyValue(NdbOperation* anOp)
{
const Uint32* data = (const Uint32*)theAccessKeyBuf.data;
- DBG("setAccessKeyValue key=" << ndb_blob_debug(data, theAccessTable->m_sizeOfKeysInWords));
+ 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++) {
@@ -393,7 +393,7 @@ int
NdbBlob::setPartKeyValue(NdbOperation* anOp, Uint32 part)
{
Uint32* data = (Uint32*)theKeyBuf.data;
- unsigned size = theTable->m_sizeOfKeysInWords;
+ 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 ||
@@ -875,7 +875,7 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count)
setErrorCode(tOp);
return -1;
}
- tOp->m_abortOption = AbortOnError;
+ tOp->m_abortOption = NdbTransaction::AbortOnError;
buf += thePartSize;
n++;
thePendingBlobOps |= (1 << NdbOperation::ReadRequest);
@@ -898,7 +898,7 @@ NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count)
setErrorCode(tOp);
return -1;
}
- tOp->m_abortOption = AbortOnError;
+ tOp->m_abortOption = NdbTransaction::AbortOnError;
buf += thePartSize;
n++;
thePendingBlobOps |= (1 << NdbOperation::InsertRequest);
@@ -921,7 +921,7 @@ NdbBlob::updateParts(const char* buf, Uint32 part, Uint32 count)
setErrorCode(tOp);
return -1;
}
- tOp->m_abortOption = AbortOnError;
+ tOp->m_abortOption = NdbTransaction::AbortOnError;
buf += thePartSize;
n++;
thePendingBlobOps |= (1 << NdbOperation::UpdateRequest);
@@ -943,7 +943,7 @@ NdbBlob::deleteParts(Uint32 part, Uint32 count)
setErrorCode(tOp);
return -1;
}
- tOp->m_abortOption = AbortOnError;
+ tOp->m_abortOption = NdbTransaction::AbortOnError;
n++;
thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
theNdbCon->thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
@@ -976,11 +976,11 @@ NdbBlob::deletePartsUnknown(Uint32 part)
setErrorCode(tOp);
return -1;
}
- tOp->m_abortOption = AO_IgnoreError;
+ tOp->m_abortOption= NdbTransaction::AO_IgnoreError;
n++;
}
DBG("deletePartsUnknown: executeNoBlobs [in] bat=" << bat);
- if (theNdbCon->executeNoBlobs(NoCommit) == -1)
+ if (theNdbCon->executeNoBlobs(NdbTransaction::NoCommit) == -1)
return -1;
DBG("deletePartsUnknown: executeNoBlobs [out]");
n = 0;
@@ -1012,7 +1012,7 @@ NdbBlob::executePendingBlobReads()
Uint8 flags = (1 << NdbOperation::ReadRequest);
if (thePendingBlobOps & flags) {
DBG("executePendingBlobReads: executeNoBlobs [in]");
- if (theNdbCon->executeNoBlobs(NoCommit) == -1)
+ if (theNdbCon->executeNoBlobs(NdbTransaction::NoCommit) == -1)
return -1;
DBG("executePendingBlobReads: executeNoBlobs [out]");
thePendingBlobOps = 0;
@@ -1027,7 +1027,7 @@ NdbBlob::executePendingBlobWrites()
Uint8 flags = 0xFF & ~(1 << NdbOperation::ReadRequest);
if (thePendingBlobOps & flags) {
DBG("executePendingBlobWrites: executeNoBlobs [in]");
- if (theNdbCon->executeNoBlobs(NoCommit) == -1)
+ if (theNdbCon->executeNoBlobs(NdbTransaction::NoCommit) == -1)
return -1;
DBG("executePendingBlobWrites: executeNoBlobs [out]");
thePendingBlobOps = 0;
@@ -1060,7 +1060,7 @@ NdbBlob::invokeActiveHook()
* data. For read operation adds read of head+inline.
*/
int
-NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn)
+NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn)
{
assert(theState == Idle);
// ndb api stuff
@@ -1106,8 +1106,8 @@ NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl*
theBlobTable = &NdbTableImpl::getImpl(*bt);
}
// buffers
- theKeyBuf.alloc(theTable->m_sizeOfKeysInWords << 2);
- theAccessKeyBuf.alloc(theAccessTable->m_sizeOfKeysInWords << 2);
+ theKeyBuf.alloc(theTable->m_keyLenInWords << 2);
+ theAccessKeyBuf.alloc(theAccessTable->m_keyLenInWords << 2);
theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize);
theHeadInlineCopyBuf.alloc(sizeof(Head) + theInlineSize);
thePartBuf.alloc(thePartSize);
@@ -1119,7 +1119,7 @@ NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl*
if (isTableOp()) {
// get table key
Uint32* data = (Uint32*)theKeyBuf.data;
- unsigned size = theTable->m_sizeOfKeysInWords;
+ unsigned size = theTable->m_keyLenInWords;
if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
setErrorCode(NdbBlobImpl::ErrUsage);
return -1;
@@ -1128,7 +1128,7 @@ NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl*
if (isIndexOp()) {
// get index key
Uint32* data = (Uint32*)theAccessKeyBuf.data;
- unsigned size = theAccessTable->m_sizeOfKeysInWords;
+ unsigned size = theAccessTable->m_keyLenInWords;
if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
setErrorCode(NdbBlobImpl::ErrUsage);
return -1;
@@ -1175,7 +1175,7 @@ NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl*
* back after postExecute.
*/
int
-NdbBlob::preExecute(ExecType anExecType, bool& batch)
+NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch)
{
DBG("preExecute [in]");
if (theState == Invalid)
@@ -1224,7 +1224,7 @@ NdbBlob::preExecute(ExecType anExecType, bool& batch)
return -1;
}
if (isWriteOp()) {
- tOp->m_abortOption = AO_IgnoreError;
+ tOp->m_abortOption = NdbTransaction::AO_IgnoreError;
}
theHeadInlineReadOp = tOp;
// execute immediately
@@ -1270,7 +1270,7 @@ NdbBlob::preExecute(ExecType anExecType, bool& batch)
return -1;
}
if (isWriteOp()) {
- tOp->m_abortOption = AO_IgnoreError;
+ tOp->m_abortOption = NdbTransaction::AO_IgnoreError;
}
theHeadInlineReadOp = tOp;
// execute immediately
@@ -1316,18 +1316,18 @@ NdbBlob::preExecute(ExecType anExecType, bool& batch)
* any remaining prepared operations.
*/
int
-NdbBlob::postExecute(ExecType anExecType)
+NdbBlob::postExecute(NdbTransaction::ExecType anExecType)
{
DBG("postExecute [in] type=" << anExecType);
if (theState == Invalid)
return -1;
if (theState == Active) {
- setState(anExecType == NoCommit ? Active : Closed);
+ setState(anExecType == NdbTransaction::NoCommit ? Active : Closed);
DBG("postExecute [skip]");
return 0;
}
assert(theState == Prepared);
- setState(anExecType == NoCommit ? Active : Closed);
+ setState(anExecType == NdbTransaction::NoCommit ? Active : Closed);
assert(isKeyOp());
if (isIndexOp()) {
NdbBlob* tFirstBlob = theNdbOp->theBlobList;
@@ -1343,14 +1343,15 @@ NdbBlob::postExecute(ExecType anExecType)
return -1;
if (theGetFlag) {
assert(theGetSetBytes == 0 || theGetBuf != 0);
- assert(theGetSetBytes <= theInlineSize || anExecType == NoCommit);
+ assert(theGetSetBytes <= theInlineSize ||
+ anExecType == NdbTransaction::NoCommit);
Uint32 bytes = theGetSetBytes;
if (readDataPrivate(theGetBuf, bytes) == -1)
return -1;
}
}
if (isUpdateOp()) {
- assert(anExecType == NoCommit);
+ assert(anExecType == NdbTransaction::NoCommit);
getHeadFromRecAttr();
if (theSetFlag) {
// setValue overwrites everything
@@ -1367,7 +1368,7 @@ NdbBlob::postExecute(ExecType anExecType)
}
}
if (isWriteOp() && isTableOp()) {
- assert(anExecType == NoCommit);
+ assert(anExecType == NdbTransaction::NoCommit);
if (theHeadInlineReadOp->theError.code == 0) {
int tNullFlag = theNullFlag;
Uint64 tLength = theLength;
@@ -1418,18 +1419,18 @@ NdbBlob::postExecute(ExecType anExecType)
}
}
if (isDeleteOp()) {
- assert(anExecType == NoCommit);
+ assert(anExecType == NdbTransaction::NoCommit);
getHeadFromRecAttr();
if (deleteParts(0, getPartCount()) == -1)
return -1;
}
- setState(anExecType == NoCommit ? Active : Closed);
+ setState(anExecType == NdbTransaction::NoCommit ? Active : Closed);
// activation callback
if (theActiveHook != NULL) {
if (invokeActiveHook() == -1)
return -1;
}
- if (anExecType == NoCommit && theHeadInlineUpdateFlag) {
+ if (anExecType == NdbTransaction::NoCommit && theHeadInlineUpdateFlag) {
NdbOperation* tOp = theNdbCon->getNdbOperation(theTable);
if (tOp == NULL ||
tOp->updateTuple() == -1 ||
@@ -1438,7 +1439,7 @@ NdbBlob::postExecute(ExecType anExecType)
setErrorCode(NdbBlobImpl::ErrAbort);
return -1;
}
- tOp->m_abortOption = AbortOnError;
+ tOp->m_abortOption = NdbTransaction::AbortOnError;
DBG("added op to update head+inline");
}
DBG("postExecute [out]");
@@ -1468,7 +1469,7 @@ NdbBlob::preCommit()
setErrorCode(NdbBlobImpl::ErrAbort);
return -1;
}
- tOp->m_abortOption = AbortOnError;
+ tOp->m_abortOption = NdbTransaction::AbortOnError;
DBG("added op to update head+inline");
}
}
@@ -1488,7 +1489,7 @@ NdbBlob::atNextResult()
assert(isScanOp());
// get primary key
{ Uint32* data = (Uint32*)theKeyBuf.data;
- unsigned size = theTable->m_sizeOfKeysInWords;
+ unsigned size = theTable->m_keyLenInWords;
if (((NdbScanOperation*)theNdbOp)->getKeyFromKEYINFO20(data, size) == -1) {
setErrorCode(NdbBlobImpl::ErrUsage);
return -1;
@@ -1551,7 +1552,7 @@ NdbBlob::setErrorCode(NdbOperation* anOp, bool invalidFlag)
}
void
-NdbBlob::setErrorCode(NdbConnection* aCon, bool invalidFlag)
+NdbBlob::setErrorCode(NdbTransaction* aCon, bool invalidFlag)
{
int code = 0;
if (theNdbCon != NULL && (code = theNdbCon->theError.code) != 0)
diff --git a/ndb/src/ndbapi/NdbCursorOperation.cpp b/ndb/src/ndbapi/NdbCursorOperation.cpp
deleted file mode 100644
index a9f84c4c110..00000000000
--- a/ndb/src/ndbapi/NdbCursorOperation.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*****************************************************************************
- * Name: NdbCursorOperation.cpp
- * Include:
- * Link:
- * Author: UABMASD Martin Sköld INN/V Alzato
- * Date: 2002-04-01
- * Version: 0.1
- * Description: Cursor support
- * Documentation:
- * Adjust: 2002-04-01 UABMASD First version.
- ****************************************************************************/
-
-#include <NdbCursorOperation.hpp>
-#include <NdbResultSet.hpp>
-
-NdbCursorOperation::NdbCursorOperation(Ndb* aNdb) :
-{
-}
-
-NdbCursorOperation::~NdbCursorOperation()
-{
- if (m_resultSet)
- delete m_resultSet;
-}
-
-void NdbCursorOperation::cursInit()
-{
- // Initialize result set
-}
-
-NdbResultSet* NdbCursorOperation::getResultSet()
-{
-}
-
-
diff --git a/ndb/src/ndbapi/NdbDictionary.cpp b/ndb/src/ndbapi/NdbDictionary.cpp
index 00db5704949..4cc47543cec 100644
--- a/ndb/src/ndbapi/NdbDictionary.cpp
+++ b/ndb/src/ndbapi/NdbDictionary.cpp
@@ -176,52 +176,16 @@ NdbDictionary::Column::getPrimaryKey() const {
return m_impl.m_pk;
}
-void
-NdbDictionary::Column::setTupleKey(bool val){
- m_impl.m_tupleKey = val;
-}
-
-bool
-NdbDictionary::Column::getTupleKey() const {
- return m_impl.m_tupleKey;
-}
-
void
-NdbDictionary::Column::setDistributionKey(bool val){
+NdbDictionary::Column::setPartitionKey(bool val){
m_impl.m_distributionKey = val;
}
bool
-NdbDictionary::Column::getDistributionKey() const{
+NdbDictionary::Column::getPartitionKey() const{
return m_impl.m_distributionKey;
}
-void
-NdbDictionary::Column::setDistributionGroup(bool val, int bits){
- m_impl.m_distributionGroup = val;
- m_impl.m_distributionGroupBits = bits;
-}
-
-bool
-NdbDictionary::Column::getDistributionGroup() const {
- return m_impl.m_distributionGroup;
-}
-
-int
-NdbDictionary::Column::getDistributionGroupBits() const{
- return m_impl.m_distributionGroupBits;
-}
-
-void
-NdbDictionary::Column::setIndexOnlyStorage(bool val){
- m_impl.m_indexOnly = val;
-}
-
-bool
-NdbDictionary::Column::getIndexOnlyStorage() const {
- return m_impl.m_indexOnly;
-}
-
const NdbDictionary::Table *
NdbDictionary::Column::getBlobTable() const {
NdbTableImpl * t = m_impl.m_blobTable;
@@ -267,6 +231,12 @@ NdbDictionary::Column::equal(const NdbDictionary::Column & col) const {
return m_impl.equal(col.m_impl);
}
+int
+NdbDictionary::Column::getSizeInBytes() const
+{
+ return m_impl.m_attrSize * m_impl.m_arraySize;
+}
+
/*****************************************************************
* Table facade
*/
@@ -462,13 +432,17 @@ NdbDictionary::Table::getRowSizeInBytes() const {
int sz = 0;
for(int i = 0; i<getNoOfColumns(); i++){
const NdbDictionary::Column * c = getColumn(i);
- const NdbColumnImpl & col = NdbColumnImpl::getImpl(* c);
- sz += (((col.m_attrSize * col.m_arraySize) + 3) / 4);
+ sz += (c->getSizeInBytes()+ 3) / 4;
}
return sz * 4;
}
int
+NdbDictionary::Table::getReplicaCount() const {
+ return m_impl.m_replicaCount;
+}
+
+int
NdbDictionary::Table::createTableInDb(Ndb* pNdb, bool equalOk) const {
const NdbDictionary::Table * pTab =
pNdb->getDictionary()->getTable(getName());
@@ -621,6 +595,13 @@ NdbDictionary::Event::Event(const char * name)
setName(name);
}
+NdbDictionary::Event::Event(const char * name, const Table& table)
+ : m_impl(* new NdbEventImpl(* this))
+{
+ setName(name);
+ setTable(table);
+}
+
NdbDictionary::Event::Event(NdbEventImpl & impl)
: m_impl(impl)
{
@@ -640,12 +621,30 @@ NdbDictionary::Event::setName(const char * name)
m_impl.setName(name);
}
+const char *
+NdbDictionary::Event::getName() const
+{
+ return m_impl.getName();
+}
+
+void
+NdbDictionary::Event::setTable(const Table& table)
+{
+ m_impl.setTable(table);
+}
+
void
NdbDictionary::Event::setTable(const char * table)
{
m_impl.setTable(table);
}
+const char*
+NdbDictionary::Event::getTableName() const
+{
+ return m_impl.getTableName();
+}
+
void
NdbDictionary::Event::addTableEvent(const TableEvent t)
{
@@ -653,11 +652,17 @@ NdbDictionary::Event::addTableEvent(const TableEvent t)
}
void
-NdbDictionary::Event::setDurability(const EventDurability d)
+NdbDictionary::Event::setDurability(EventDurability d)
{
m_impl.setDurability(d);
}
+NdbDictionary::Event::EventDurability
+NdbDictionary::Event::getDurability() const
+{
+ return m_impl.getDurability();
+}
+
void
NdbDictionary::Event::addColumn(const Column & c){
NdbColumnImpl* col = new NdbColumnImpl;
@@ -685,6 +690,11 @@ NdbDictionary::Event::addEventColumns(int n, const char ** names)
addEventColumn(names[i]);
}
+int NdbDictionary::Event::getNoOfEventColumns() const
+{
+ return m_impl.getNoOfEventColumns();
+}
+
NdbDictionary::Object::Status
NdbDictionary::Event::getObjectStatus() const
{
@@ -742,7 +752,8 @@ NdbDictionary::Dictionary::alterTable(const Table & t){
}
const NdbDictionary::Table *
-NdbDictionary::Dictionary::getTable(const char * name, void **data){
+NdbDictionary::Dictionary::getTable(const char * name, void **data) const
+{
NdbTableImpl * t = m_impl.getTable(name, data);
if(t)
return t->m_facade;
@@ -755,7 +766,8 @@ void NdbDictionary::Dictionary::set_local_table_data_size(unsigned sz)
}
const NdbDictionary::Table *
-NdbDictionary::Dictionary::getTable(const char * name){
+NdbDictionary::Dictionary::getTable(const char * name) const
+{
return getTable(name, 0);
}
@@ -788,7 +800,7 @@ NdbDictionary::Dictionary::dropIndex(const char * indexName,
const NdbDictionary::Index *
NdbDictionary::Dictionary::getIndex(const char * indexName,
- const char * tableName)
+ const char * tableName) const
{
NdbIndexImpl * i = m_impl.getIndex(indexName, tableName);
if(i)
@@ -818,7 +830,7 @@ NdbDictionary::Dictionary::removeCachedIndex(const char * indexName,
const NdbDictionary::Table *
NdbDictionary::Dictionary::getIndexTable(const char * indexName,
- const char * tableName)
+ const char * tableName) const
{
NdbIndexImpl * i = m_impl.getIndex(indexName, tableName);
NdbTableImpl * t = m_impl.getTable(tableName);
@@ -858,6 +870,12 @@ NdbDictionary::Dictionary::listObjects(List& list, Object::Type type)
}
int
+NdbDictionary::Dictionary::listObjects(List& list, Object::Type type) const
+{
+ return m_impl.listObjects(list, type);
+}
+
+int
NdbDictionary::Dictionary::listIndexes(List& list, const char * tableName)
{
const NdbDictionary::Table* tab= getTable(tableName);
@@ -868,6 +886,18 @@ NdbDictionary::Dictionary::listIndexes(List& list, const char * tableName)
return m_impl.listIndexes(list, tab->getTableId());
}
+int
+NdbDictionary::Dictionary::listIndexes(List& list,
+ const char * tableName) const
+{
+ const NdbDictionary::Table* tab= getTable(tableName);
+ if(tab == 0)
+ {
+ return -1;
+ }
+ return m_impl.listIndexes(list, tab->getTableId());
+}
+
const struct NdbError &
NdbDictionary::Dictionary::getNdbError() const {
return m_impl.getNdbError();
@@ -924,6 +954,12 @@ operator<<(NdbOut& out, const NdbDictionary::Column& col)
case NdbDictionary::Column::Olddecimalunsigned:
out << "Olddecimalunsigned(" << col.getPrecision() << "," << col.getScale() << ")";
break;
+ case NdbDictionary::Column::Decimal:
+ out << "Decimal(" << col.getPrecision() << "," << col.getScale() << ")";
+ break;
+ case NdbDictionary::Column::Decimalunsigned:
+ out << "Decimalunsigned(" << col.getPrecision() << "," << col.getScale() << ")";
+ break;
case NdbDictionary::Column::Char:
out << "Char(" << col.getLength() << ";" << csname << ")";
break;
@@ -962,10 +998,37 @@ operator<<(NdbOut& out, const NdbDictionary::Column& col)
case NdbDictionary::Column::Undefined:
out << "Undefined";
break;
+ case NdbDictionary::Column::Bit:
+ out << "Bit(" << col.getLength() << ")";
+ break;
+ case NdbDictionary::Column::Longvarchar:
+ out << "Longvarchar(" << col.getLength() << ";" << csname << ")";
+ break;
+ case NdbDictionary::Column::Longvarbinary:
+ out << "Longvarbinary(" << col.getLength() << ")";
+ break;
default:
out << "Type" << (Uint32)col.getType();
break;
}
+ // show unusual (non-MySQL) array size
+ if (col.getLength() != 1) {
+ switch (col.getType()) {
+ case NdbDictionary::Column::Char:
+ case NdbDictionary::Column::Varchar:
+ case NdbDictionary::Column::Binary:
+ case NdbDictionary::Column::Varbinary:
+ case NdbDictionary::Column::Blob:
+ case NdbDictionary::Column::Text:
+ case NdbDictionary::Column::Bit:
+ case NdbDictionary::Column::Longvarchar:
+ case NdbDictionary::Column::Longvarbinary:
+ break;
+ default:
+ out << " [" << col.getLength() << "]";
+ break;
+ }
+ }
if (col.getPrimaryKey())
out << " PRIMARY KEY";
else if (! col.getNullable())
@@ -973,13 +1036,15 @@ operator<<(NdbOut& out, const NdbDictionary::Column& col)
else
out << " NULL";
- if (col.getDistributionKey())
+ if(col.getDistributionKey())
out << " DISTRIBUTION KEY";
-
+
return out;
}
const NdbDictionary::Column * NdbDictionary::Column::FRAGMENT = 0;
+const NdbDictionary::Column * NdbDictionary::Column::FRAGMENT_MEMORY = 0;
const NdbDictionary::Column * NdbDictionary::Column::ROW_COUNT = 0;
const NdbDictionary::Column * NdbDictionary::Column::COMMIT_COUNT = 0;
-
+const NdbDictionary::Column * NdbDictionary::Column::ROW_SIZE = 0;
+const NdbDictionary::Column * NdbDictionary::Column::RANGE_NO = 0;
diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
index 4523ae2c261..96c8f6020e5 100644
--- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp
+++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
@@ -70,16 +70,11 @@ NdbColumnImpl::operator=(const NdbColumnImpl& col)
m_scale = col.m_scale;
m_length = col.m_length;
m_pk = col.m_pk;
- m_tupleKey = col.m_tupleKey;
m_distributionKey = col.m_distributionKey;
- m_distributionGroup = col.m_distributionGroup;
- m_distributionGroupBits = col.m_distributionGroupBits;
m_nullable = col.m_nullable;
- m_indexOnly = col.m_indexOnly;
m_autoIncrement = col.m_autoIncrement;
m_autoIncrementInitialValue = col.m_autoIncrementInitialValue;
m_defaultValue = col.m_defaultValue;
- m_attrType = col.m_attrType;
m_attrSize = col.m_attrSize;
m_arraySize = col.m_arraySize;
m_keyInfoPos = col.m_keyInfoPos;
@@ -116,6 +111,8 @@ NdbColumnImpl::init(Type t)
break;
case Olddecimal:
case Olddecimalunsigned:
+ case Decimal:
+ case Decimalunsigned:
m_precision = 10;
m_scale = 0;
m_length = 1;
@@ -157,17 +154,31 @@ NdbColumnImpl::init(Type t)
m_length = 1;
m_cs = NULL;
break;
+ case Bit:
+ m_precision = 0;
+ m_scale = 0;
+ m_length = 1;
+ m_cs = NULL;
+ break;
+ case Longvarchar:
+ m_precision = 0;
+ m_scale = 0;
+ m_length = 1; // legal
+ m_cs = default_cs;
+ break;
+ case Longvarbinary:
+ m_precision = 0;
+ m_scale = 0;
+ m_length = 1; // legal
+ m_cs = NULL;
+ break;
case Undefined:
assert(false);
break;
}
m_pk = false;
m_nullable = false;
- m_tupleKey = false;
- m_indexOnly = false;
m_distributionKey = false;
- m_distributionGroup = false;
- m_distributionGroupBits = 8;
m_keyInfoPos = 0;
// next 2 are set at run time
m_attrSize = 0;
@@ -184,50 +195,38 @@ NdbColumnImpl::~NdbColumnImpl()
bool
NdbColumnImpl::equal(const NdbColumnImpl& col) const
{
+ DBUG_ENTER("NdbColumnImpl::equal");
if(strcmp(m_name.c_str(), col.m_name.c_str()) != 0){
- return false;
+ DBUG_RETURN(false);
}
if(m_type != col.m_type){
- return false;
+ DBUG_RETURN(false);
}
if(m_pk != col.m_pk){
- return false;
+ DBUG_RETURN(false);
}
if(m_nullable != col.m_nullable){
- return false;
+ DBUG_RETURN(false);
}
if(m_pk){
- if(m_tupleKey != col.m_tupleKey){
- return false;
- }
- if(m_indexOnly != col.m_indexOnly){
- return false;
- }
if(m_distributionKey != col.m_distributionKey){
- return false;
- }
- if(m_distributionGroup != col.m_distributionGroup){
- return false;
- }
- if(m_distributionGroup &&
- (m_distributionGroupBits != col.m_distributionGroupBits)){
- return false;
+ DBUG_RETURN(false);
}
}
if (m_precision != col.m_precision ||
m_scale != col.m_scale ||
m_length != col.m_length ||
m_cs != col.m_cs) {
- return false;
+ DBUG_RETURN(false);
}
if (m_autoIncrement != col.m_autoIncrement){
- return false;
+ DBUG_RETURN(false);
}
if(strcmp(m_defaultValue.c_str(), col.m_defaultValue.c_str()) != 0){
- return false;
+ DBUG_RETURN(false);
}
- return true;
+ DBUG_RETURN(true);
}
NdbDictionary::Column *
@@ -239,6 +238,11 @@ NdbColumnImpl::create_psuedo(const char * name){
col->m_impl.m_attrId = AttributeHeader::FRAGMENT;
col->m_impl.m_attrSize = 4;
col->m_impl.m_arraySize = 1;
+ } else if(!strcmp(name, "NDB$FRAGMENT_MEMORY")){
+ col->setType(NdbDictionary::Column::Bigunsigned);
+ col->m_impl.m_attrId = AttributeHeader::FRAGMENT_MEMORY;
+ col->m_impl.m_attrSize = 8;
+ col->m_impl.m_arraySize = 1;
} else if(!strcmp(name, "NDB$ROW_COUNT")){
col->setType(NdbDictionary::Column::Bigunsigned);
col->m_impl.m_attrId = AttributeHeader::ROW_COUNT;
@@ -249,6 +253,16 @@ NdbColumnImpl::create_psuedo(const char * name){
col->m_impl.m_attrId = AttributeHeader::COMMIT_COUNT;
col->m_impl.m_attrSize = 8;
col->m_impl.m_arraySize = 1;
+ } else if(!strcmp(name, "NDB$ROW_SIZE")){
+ col->setType(NdbDictionary::Column::Unsigned);
+ col->m_impl.m_attrId = AttributeHeader::ROW_SIZE;
+ col->m_impl.m_attrSize = 4;
+ col->m_impl.m_arraySize = 1;
+ } else if(!strcmp(name, "NDB$RANGE_NO")){
+ col->setType(NdbDictionary::Column::Unsigned);
+ col->m_impl.m_attrId = AttributeHeader::RANGE_NO;
+ col->m_impl.m_attrSize = 4;
+ col->m_impl.m_arraySize = 1;
} else {
abort();
}
@@ -295,57 +309,71 @@ NdbTableImpl::init(){
m_indexType = NdbDictionary::Index::Undefined;
m_noOfKeys = 0;
+ m_noOfDistributionKeys = 0;
m_fragmentCount = 0;
- m_sizeOfKeysInWords = 0;
+ m_keyLenInWords = 0;
m_noOfBlobs = 0;
}
bool
NdbTableImpl::equal(const NdbTableImpl& obj) const
{
+ DBUG_ENTER("NdbTableImpl::equal");
if ((m_internalName.c_str() == NULL) ||
(strcmp(m_internalName.c_str(), "") == 0) ||
(obj.m_internalName.c_str() == NULL) ||
(strcmp(obj.m_internalName.c_str(), "") == 0)) {
// Shallow equal
if(strcmp(getName(), obj.getName()) != 0){
- return false;
+ DBUG_PRINT("info",("name %s != %s",getName(),obj.getName()));
+ DBUG_RETURN(false);
}
} else
// Deep equal
if(strcmp(m_internalName.c_str(), obj.m_internalName.c_str()) != 0){
- return false;
+ {
+ DBUG_PRINT("info",("m_internalName %s != %s",
+ m_internalName.c_str(),obj.m_internalName.c_str()));
+ DBUG_RETURN(false);
+ }
}
if(m_fragmentType != obj.m_fragmentType){
- return false;
+ DBUG_PRINT("info",("m_fragmentType %d != %d",m_fragmentType,obj.m_fragmentType));
+ DBUG_RETURN(false);
}
if(m_columns.size() != obj.m_columns.size()){
- return false;
+ DBUG_PRINT("info",("m_columns.size %d != %d",m_columns.size(),obj.m_columns.size()));
+ DBUG_RETURN(false);
}
for(unsigned i = 0; i<obj.m_columns.size(); i++){
if(!m_columns[i]->equal(* obj.m_columns[i])){
- return false;
+ DBUG_PRINT("info",("m_columns [%d] != [%d]",i,i));
+ DBUG_RETURN(false);
}
}
if(m_logging != obj.m_logging){
- return false;
+ DBUG_PRINT("info",("m_logging %d != %d",m_logging,obj.m_logging));
+ DBUG_RETURN(false);
}
if(m_kvalue != obj.m_kvalue){
- return false;
+ DBUG_PRINT("info",("m_kvalue %d != %d",m_kvalue,obj.m_kvalue));
+ DBUG_RETURN(false);
}
if(m_minLoadFactor != obj.m_minLoadFactor){
- return false;
+ DBUG_PRINT("info",("m_minLoadFactor %d != %d",m_minLoadFactor,obj.m_minLoadFactor));
+ DBUG_RETURN(false);
}
if(m_maxLoadFactor != obj.m_maxLoadFactor){
- return false;
+ DBUG_PRINT("info",("m_maxLoadFactor %d != %d",m_maxLoadFactor,obj.m_maxLoadFactor));
+ DBUG_RETURN(false);
}
- return true;
+ DBUG_RETURN(true);
}
void
@@ -375,8 +403,9 @@ NdbTableImpl::assign(const NdbTableImpl& org)
delete m_index;
m_index = org.m_index;
+ m_noOfDistributionKeys = org.m_noOfDistributionKeys;
m_noOfKeys = org.m_noOfKeys;
- m_sizeOfKeysInWords = org.m_sizeOfKeysInWords;
+ m_keyLenInWords = org.m_keyLenInWords;
m_noOfBlobs = org.m_noOfBlobs;
m_version = org.m_version;
@@ -477,6 +506,26 @@ NdbTableImpl::buildColumnHash(){
}
#endif
}
+
+Uint32
+NdbTableImpl::get_nodes(Uint32 hashValue, const Uint16 ** nodes) const
+{
+ if(m_replicaCount > 0)
+ {
+ Uint32 fragmentId = hashValue & m_hashValueMask;
+ if(fragmentId < m_hashpointerValue)
+ {
+ fragmentId = hashValue & ((m_hashValueMask << 1) + 1);
+ }
+ Uint32 pos = fragmentId * m_replicaCount;
+ if(pos + m_replicaCount <= m_fragments.size())
+ {
+ * nodes = m_fragments.getBase()+pos;
+ return m_replicaCount;
+ }
+ }
+ return 0;
+}
/**
* NdbIndexImpl
@@ -565,24 +614,30 @@ void NdbEventImpl::setName(const char * name)
m_externalName.assign(name);
}
+const char *NdbEventImpl::getName() const
+{
+ return m_externalName.c_str();
+}
+
+void
+NdbEventImpl::setTable(const NdbDictionary::Table& table)
+{
+ m_tableImpl= &NdbTableImpl::getImpl(table);
+ m_tableName.assign(m_tableImpl->getName());
+}
+
void
NdbEventImpl::setTable(const char * table)
{
m_tableName.assign(table);
}
-const char *
-NdbEventImpl::getTable() const
+const char *
+NdbEventImpl::getTableName() const
{
return m_tableName.c_str();
}
-const char *
-NdbEventImpl::getName() const
-{
- return m_externalName.c_str();
-}
-
void
NdbEventImpl::addTableEvent(const NdbDictionary::Event::TableEvent t = NdbDictionary::Event::TE_ALL)
{
@@ -595,11 +650,22 @@ NdbEventImpl::addTableEvent(const NdbDictionary::Event::TableEvent t = NdbDicti
}
void
-NdbEventImpl::setDurability(const NdbDictionary::Event::EventDurability d)
+NdbEventImpl::setDurability(NdbDictionary::Event::EventDurability d)
{
m_dur = d;
}
+NdbDictionary::Event::EventDurability
+NdbEventImpl::getDurability() const
+{
+ return m_dur;
+}
+
+int NdbEventImpl::getNoOfEventColumns() const
+{
+ return m_attrIds.size() + m_columns.size();
+}
+
/**
* NdbDictionaryImpl
*/
@@ -643,11 +709,15 @@ NdbDictionaryImpl::~NdbDictionaryImpl()
m_globalHash->lock();
if(--f_dictionary_count == 0){
delete NdbDictionary::Column::FRAGMENT;
+ delete NdbDictionary::Column::FRAGMENT_MEMORY;
delete NdbDictionary::Column::ROW_COUNT;
delete NdbDictionary::Column::COMMIT_COUNT;
+ delete NdbDictionary::Column::ROW_SIZE;
NdbDictionary::Column::FRAGMENT= 0;
+ NdbDictionary::Column::FRAGMENT_MEMORY= 0;
NdbDictionary::Column::ROW_COUNT= 0;
NdbDictionary::Column::COMMIT_COUNT= 0;
+ NdbDictionary::Column::ROW_SIZE= 0;
}
m_globalHash->unlock();
} else {
@@ -710,10 +780,16 @@ NdbDictionaryImpl::setTransporter(class Ndb* ndb,
if(f_dictionary_count++ == 0){
NdbDictionary::Column::FRAGMENT=
NdbColumnImpl::create_psuedo("NDB$FRAGMENT");
+ NdbDictionary::Column::FRAGMENT_MEMORY=
+ NdbColumnImpl::create_psuedo("NDB$FRAGMENT_MEMORY");
NdbDictionary::Column::ROW_COUNT=
NdbColumnImpl::create_psuedo("NDB$ROW_COUNT");
NdbDictionary::Column::COMMIT_COUNT=
NdbColumnImpl::create_psuedo("NDB$COMMIT_COUNT");
+ NdbDictionary::Column::ROW_SIZE=
+ NdbColumnImpl::create_psuedo("NDB$ROW_SIZE");
+ NdbDictionary::Column::RANGE_NO=
+ NdbColumnImpl::create_psuedo("NDB$RANGE_NO");
}
m_globalHash->unlock();
return true;
@@ -745,7 +821,7 @@ NdbDictInterface::setTransporter(class TransporterFacade * tf)
execNodeStatus);
if ( m_blockNumber == -1 ) {
- m_error.code = 4105;
+ m_error.code= 4105;
return false; // no more free blocknumbers
}//if
Uint32 theNode = tf->ownId();
@@ -899,7 +975,7 @@ NdbDictInterface::dictSignal(NdbApiSignal* signal,
aNodeId = m_transporter->get_an_alive_node();
}
if(aNodeId == 0){
- m_error.code = 4009;
+ m_error.code= 4009;
m_transporter->unlock_mutex();
DBUG_RETURN(-1);
}
@@ -926,7 +1002,7 @@ NdbDictInterface::dictSignal(NdbApiSignal* signal,
}
}
- m_error.code = 0;
+ m_error.code= 0;
m_waiter.m_node = aNodeId;
m_waiter.m_state = wst;
@@ -960,7 +1036,7 @@ NdbDictInterface::dictSignal(NdbApiSignal* signal,
for (int j=0; j < noerrcodes; j++)
if(m_error.code == errcodes[j]) {
doContinue = 1;
- continue;
+ break;
}
if (doContinue)
continue;
@@ -1000,7 +1076,7 @@ NdbDictInterface::getTable(const char * name, bool fullyQualifiedNames)
const Uint32 strLen = strlen(name) + 1; // NULL Terminated
if(strLen > MAX_TAB_NAME_SIZE) {//sizeof(req->tableName)){
- m_error.code = 4307;
+ m_error.code= 4307;
return 0;
}
@@ -1026,18 +1102,20 @@ NdbDictInterface::getTable(class NdbApiSignal * signal,
Uint32 noOfSections, bool fullyQualifiedNames)
{
//GetTabInfoReq * const req = CAST_PTR(GetTabInfoReq, signal->getDataPtrSend());
+ int errCodes[] = {GetTabInfoRef::Busy };
+
int r = dictSignal(signal,ptr,noOfSections,
0/*do not use masternode id*/,
100,
WAIT_GET_TAB_INFO_REQ,
WAITFOR_RESPONSE_TIMEOUT,
- NULL,0);
+ errCodes, 1);
if (r) return 0;
NdbTableImpl * rt = 0;
- m_error.code = parseTableInfo(&rt,
- (Uint32*)m_buffer.get_data(),
- m_buffer.length() / 4, fullyQualifiedNames);
+ m_error.code= parseTableInfo(&rt,
+ (Uint32*)m_buffer.get_data(),
+ m_buffer.length() / 4, fullyQualifiedNames);
rt->buildColumnHash();
return rt;
}
@@ -1072,7 +1150,7 @@ NdbDictInterface::execGET_TABINFO_REF(NdbApiSignal * signal,
{
const GetTabInfoRef* ref = CAST_CONSTPTR(GetTabInfoRef, signal->getDataPtr());
- m_error.code = ref->errorCode;
+ m_error.code= ref->errorCode;
m_waiter.signal(NO_WAIT);
}
@@ -1128,8 +1206,6 @@ objectTypeMapping[] = {
{ DictTabInfo::SystemTable, NdbDictionary::Object::SystemTable },
{ DictTabInfo::UserTable, NdbDictionary::Object::UserTable },
{ DictTabInfo::UniqueHashIndex, NdbDictionary::Object::UniqueHashIndex },
- { DictTabInfo::HashIndex, NdbDictionary::Object::HashIndex },
- { DictTabInfo::UniqueOrderedIndex, NdbDictionary::Object::UniqueOrderedIndex },
{ DictTabInfo::OrderedIndex, NdbDictionary::Object::OrderedIndex },
{ DictTabInfo::HashIndexTrigger, NdbDictionary::Object::HashIndexTrigger },
{ DictTabInfo::IndexTrigger, NdbDictionary::Object::IndexTrigger },
@@ -1161,49 +1237,17 @@ static const
ApiKernelMapping
indexTypeMapping[] = {
{ DictTabInfo::UniqueHashIndex, NdbDictionary::Index::UniqueHashIndex },
- { DictTabInfo::HashIndex, NdbDictionary::Index::HashIndex },
- { DictTabInfo::UniqueOrderedIndex, NdbDictionary::Index::UniqueOrderedIndex},
{ DictTabInfo::OrderedIndex, NdbDictionary::Index::OrderedIndex },
{ -1, -1 }
};
-// TODO: remove, api-kernel type codes must match now
-static const
-ApiKernelMapping
-columnTypeMapping[] = {
- { DictTabInfo::ExtTinyint, NdbDictionary::Column::Tinyint },
- { DictTabInfo::ExtTinyunsigned, NdbDictionary::Column::Tinyunsigned },
- { DictTabInfo::ExtSmallint, NdbDictionary::Column::Smallint },
- { DictTabInfo::ExtSmallunsigned, NdbDictionary::Column::Smallunsigned },
- { DictTabInfo::ExtMediumint, NdbDictionary::Column::Mediumint },
- { DictTabInfo::ExtMediumunsigned, NdbDictionary::Column::Mediumunsigned },
- { DictTabInfo::ExtInt, NdbDictionary::Column::Int },
- { DictTabInfo::ExtUnsigned, NdbDictionary::Column::Unsigned },
- { DictTabInfo::ExtBigint, NdbDictionary::Column::Bigint },
- { DictTabInfo::ExtBigunsigned, NdbDictionary::Column::Bigunsigned },
- { DictTabInfo::ExtFloat, NdbDictionary::Column::Float },
- { DictTabInfo::ExtDouble, NdbDictionary::Column::Double },
- { DictTabInfo::ExtOlddecimal, NdbDictionary::Column::Olddecimal },
- { DictTabInfo::ExtOlddecimalunsigned, NdbDictionary::Column::Olddecimalunsigned },
- { DictTabInfo::ExtChar, NdbDictionary::Column::Char },
- { DictTabInfo::ExtVarchar, NdbDictionary::Column::Varchar },
- { DictTabInfo::ExtBinary, NdbDictionary::Column::Binary },
- { DictTabInfo::ExtVarbinary, NdbDictionary::Column::Varbinary },
- { DictTabInfo::ExtDatetime, NdbDictionary::Column::Datetime },
- { DictTabInfo::ExtDate, NdbDictionary::Column::Date },
- { DictTabInfo::ExtBlob, NdbDictionary::Column::Blob },
- { DictTabInfo::ExtText, NdbDictionary::Column::Text },
- { DictTabInfo::ExtTime, NdbDictionary::Column::Time },
- { DictTabInfo::ExtYear, NdbDictionary::Column::Year },
- { DictTabInfo::ExtTimestamp, NdbDictionary::Column::Timestamp },
- { -1, -1 }
-};
-
int
NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
const Uint32 * data, Uint32 len,
bool fullyQualifiedNames)
{
+ DBUG_ENTER("NdbDictInterface::parseTableInfo");
+
SimplePropertiesLinearReader it(data, len);
DictTabInfo::Table tableDesc; tableDesc.init();
SimpleProperties::UnpackStatus s;
@@ -1213,7 +1257,7 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
true, true);
if(s != SimpleProperties::Break){
- return 703;
+ DBUG_RETURN(703);
}
const char * internalName = tableDesc.TableName;
const char * externalName = Ndb::externalizeTableName(internalName, fullyQualifiedNames);
@@ -1236,7 +1280,6 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
impl->m_kvalue = tableDesc.TableKValue;
impl->m_minLoadFactor = tableDesc.MinLoadFactor;
impl->m_maxLoadFactor = tableDesc.MaxLoadFactor;
- impl->m_fragmentCount = tableDesc.FragmentCount;
impl->m_indexType = (NdbDictionary::Index::Type)
getApiConstant(tableDesc.TableType,
@@ -1253,8 +1296,10 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
Uint32 keyInfoPos = 0;
Uint32 keyCount = 0;
Uint32 blobCount = 0;
+ Uint32 distKeys = 0;
- for(Uint32 i = 0; i < tableDesc.NoOfAttributes; i++) {
+ Uint32 i;
+ for(i = 0; i < tableDesc.NoOfAttributes; i++) {
DictTabInfo::Attribute attrDesc; attrDesc.init();
s = SimpleProperties::unpack(it,
&attrDesc,
@@ -1263,21 +1308,19 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
true, true);
if(s != SimpleProperties::Break){
delete impl;
- return 703;
+ DBUG_RETURN(703);
}
NdbColumnImpl * col = new NdbColumnImpl();
col->m_attrId = attrDesc.AttributeId;
col->setName(attrDesc.AttributeName);
- col->m_type = (NdbDictionary::Column::Type)
- getApiConstant(attrDesc.AttributeExtType,
- columnTypeMapping,
- NdbDictionary::Column::Undefined);
- if (col->m_type == NdbDictionary::Column::Undefined) {
+
+ // check type and compute attribute size and array size
+ if (! attrDesc.translateExtType()) {
delete impl;
- return 703;
+ DBUG_RETURN(703);
}
- col->m_extType = attrDesc.AttributeExtType;
+ col->m_type = (NdbDictionary::Column::Type)attrDesc.AttributeExtType;
col->m_precision = (attrDesc.AttributeExtPrecision & 0xFFFF);
col->m_scale = attrDesc.AttributeExtScale;
col->m_length = attrDesc.AttributeExtLength;
@@ -1286,32 +1329,26 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
// charset is defined exactly for char types
if (col->getCharType() != (cs_number != 0)) {
delete impl;
- return 703;
+ DBUG_RETURN(703);
}
if (col->getCharType()) {
col->m_cs = get_charset(cs_number, MYF(0));
if (col->m_cs == NULL) {
delete impl;
- return 743;
+ DBUG_RETURN(743);
}
}
-
- // translate to old kernel types and sizes
- if (! attrDesc.translateExtType()) {
- delete impl;
- return 703;
- }
- col->m_attrType =attrDesc.AttributeType;
col->m_attrSize = (1 << attrDesc.AttributeSize) / 8;
col->m_arraySize = attrDesc.AttributeArraySize;
+ if(attrDesc.AttributeSize == 0)
+ {
+ col->m_attrSize = 4;
+ col->m_arraySize = (attrDesc.AttributeArraySize + 31) >> 5;
+ }
col->m_pk = attrDesc.AttributeKeyFlag;
- col->m_tupleKey = 0;
col->m_distributionKey = attrDesc.AttributeDKey;
- col->m_distributionGroup = attrDesc.AttributeDGroup;
- col->m_distributionGroupBits = 16;
col->m_nullable = attrDesc.AttributeNullableFlag;
- col->m_indexOnly = (attrDesc.AttributeStoredInd ? false : true);
col->m_autoIncrement = (attrDesc.AttributeAutoIncrement ? true : false);
col->m_autoIncrementInitialValue = ~0;
col->m_defaultValue.assign(attrDesc.AttributeDefaultValue);
@@ -1320,6 +1357,9 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
col->m_keyInfoPos = keyInfoPos + 1;
keyInfoPos += ((col->m_attrSize * col->m_arraySize + 3) / 4);
keyCount++;
+
+ if(attrDesc.AttributeDKey)
+ distKeys++;
} else {
col->m_keyInfoPos = 0;
}
@@ -1330,7 +1370,7 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
if(impl->m_columns[attrDesc.AttributeId] != 0){
delete col;
delete impl;
- return 703;
+ DBUG_RETURN(703);
}
impl->m_columns[attrDesc.AttributeId] = col;
it.next();
@@ -1338,10 +1378,49 @@ NdbDictInterface::parseTableInfo(NdbTableImpl ** ret,
impl->m_noOfKeys = keyCount;
impl->m_keyLenInWords = keyInfoPos;
- impl->m_sizeOfKeysInWords = keyInfoPos;
impl->m_noOfBlobs = blobCount;
+ impl->m_noOfDistributionKeys = distKeys;
+
+ if(tableDesc.FragmentDataLen > 0)
+ {
+ Uint32 replicaCount = tableDesc.FragmentData[0];
+ Uint32 fragCount = tableDesc.FragmentData[1];
+
+ impl->m_replicaCount = replicaCount;
+ impl->m_fragmentCount = fragCount;
+
+ for(i = 0; i<(fragCount*replicaCount); i++)
+ {
+ impl->m_fragments.push_back(tableDesc.FragmentData[i+2]);
+ }
+
+ Uint32 topBit = (1 << 31);
+ for(; topBit && !(fragCount & topBit); ){
+ topBit >>= 1;
+ }
+ impl->m_hashValueMask = topBit - 1;
+ impl->m_hashpointerValue = fragCount - (impl->m_hashValueMask + 1);
+ }
+ else
+ {
+ impl->m_fragmentCount = tableDesc.FragmentCount;
+ impl->m_replicaCount = 0;
+ impl->m_hashValueMask = 0;
+ impl->m_hashpointerValue = 0;
+ }
+
+ if(distKeys == 0)
+ {
+ for(i = 0; i < tableDesc.NoOfAttributes; i++)
+ {
+ if(impl->m_columns[i]->getPrimaryKey())
+ impl->m_columns[i]->m_distributionKey = true;
+ }
+ }
+
* ret = impl;
- return 0;
+
+ DBUG_RETURN(0);
}
/*****************************************************************
@@ -1358,13 +1437,13 @@ NdbDictionaryImpl::createTable(NdbTableImpl &t)
Ndb_local_table_info *info=
get_local_table_info(t.m_internalName.c_str(),false);
if (info == NULL) {
- m_error.code = 709;
+ m_error.code= 709;
return -1;
}
if (createBlobTables(*(info->m_table_impl)) != 0) {
int save_code = m_error.code;
(void)dropTable(t);
- m_error.code = save_code;
+ m_error.code= save_code;
return -1;
}
return 0;
@@ -1430,11 +1509,10 @@ int NdbDictionaryImpl::alterTable(NdbTableImpl &impl)
BaseString internalName = impl.m_internalName;
const char * originalInternalName = internalName.c_str();
BaseString externalName = impl.m_externalName;
- const char * originalExternalName = externalName.c_str();
DBUG_ENTER("NdbDictionaryImpl::alterTable");
if(!get_local_table_info(originalInternalName, false)){
- m_error.code = 709;
+ m_error.code= 709;
DBUG_RETURN(-1);
}
// Alter the table
@@ -1471,12 +1549,12 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
DBUG_ENTER("NdbDictInterface::createOrAlterTable");
unsigned i;
if((unsigned)impl.getNoOfPrimaryKeys() > NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY){
- m_error.code = 4317;
+ m_error.code= 4317;
DBUG_RETURN(-1);
}
unsigned sz = impl.m_columns.size();
if (sz > NDB_MAX_ATTRIBUTES_IN_TABLE){
- m_error.code = 4318;
+ m_error.code= 4318;
DBUG_RETURN(-1);
}
@@ -1501,7 +1579,7 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
continue;
if (col->m_autoIncrement) {
if (haveAutoIncrement) {
- m_error.code = 4335;
+ m_error.code= 4335;
DBUG_RETURN(-1);
}
haveAutoIncrement = true;
@@ -1511,7 +1589,7 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
// Check max length of frm data
if (impl.m_frm.length() > MAX_FRM_DATA_SIZE){
- m_error.code = 1229;
+ m_error.code= 1229;
DBUG_RETURN(-1);
}
tmpTab.FrmLen = impl.m_frm.length();
@@ -1539,6 +1617,7 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
abort();
}
+ int distKeys= impl.m_noOfDistributionKeys;
for(i = 0; i<sz; i++){
const NdbColumnImpl * col = impl.m_columns[i];
if(col == 0)
@@ -1548,27 +1627,33 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
BaseString::snprintf(tmpAttr.AttributeName, sizeof(tmpAttr.AttributeName),
col->m_name.c_str());
tmpAttr.AttributeId = i;
- tmpAttr.AttributeKeyFlag = col->m_pk || col->m_tupleKey;
+ tmpAttr.AttributeKeyFlag = col->m_pk;
tmpAttr.AttributeNullableFlag = col->m_nullable;
- tmpAttr.AttributeStoredInd = (col->m_indexOnly ? 0 : 1);
tmpAttr.AttributeDKey = col->m_distributionKey;
- tmpAttr.AttributeDGroup = col->m_distributionGroup;
- tmpAttr.AttributeExtType =
- getKernelConstant(col->m_type,
- columnTypeMapping,
- DictTabInfo::ExtUndefined);
+ tmpAttr.AttributeExtType = (Uint32)col->m_type;
tmpAttr.AttributeExtPrecision = ((unsigned)col->m_precision & 0xFFFF);
tmpAttr.AttributeExtScale = col->m_scale;
tmpAttr.AttributeExtLength = col->m_length;
+
+ // check type and compute attribute size and array size
+ if (! tmpAttr.translateExtType()) {
+ m_error.code= 703;
+ DBUG_RETURN(-1);
+ }
// charset is defined exactly for char types
if (col->getCharType() != (col->m_cs != NULL)) {
- m_error.code = 703;
+ m_error.code= 703;
DBUG_RETURN(-1);
}
// primary key type check
if (col->m_pk && ! NdbSqlUtil::usable_in_pk(col->m_type, col->m_cs)) {
- m_error.code = 743;
+ m_error.code= (col->m_cs != 0 ? 743 : 739);
+ DBUG_RETURN(-1);
+ }
+ // distribution key not supported for Char attribute
+ if (distKeys && col->m_distributionKey && col->m_cs != NULL) {
+ m_error.code= 745;
DBUG_RETURN(-1);
}
// charset in upper half of precision
@@ -1576,9 +1661,6 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
tmpAttr.AttributeExtPrecision |= (col->m_cs->number << 16);
}
- // DICT will ignore and recompute this
- (void)tmpAttr.translateExtType();
-
tmpAttr.AttributeAutoIncrement = col->m_autoIncrement;
BaseString::snprintf(tmpAttr.AttributeDefaultValue,
sizeof(tmpAttr.AttributeDefaultValue),
@@ -1629,7 +1711,7 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
if (!ndb.setAutoIncrementValue(impl.m_externalName.c_str(),
autoIncrementValue)) {
if (ndb.theError.code == 0) {
- m_error.code = 4336;
+ m_error.code= 4336;
ndb.theError = m_error;
} else
m_error= ndb.theError;
@@ -1665,11 +1747,12 @@ void
NdbDictInterface::execCREATE_TABLE_CONF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
+#if 0
const CreateTableConf* const conf=
CAST_CONSTPTR(CreateTableConf, signal->getDataPtr());
Uint32 tableId= conf->tableId;
Uint32 tableVersion= conf->tableVersion;
-
+#endif
m_waiter.signal(NO_WAIT);
}
@@ -1679,7 +1762,7 @@ NdbDictInterface::execCREATE_TABLE_REF(NdbApiSignal * signal,
{
const CreateTableRef* const ref=
CAST_CONSTPTR(CreateTableRef, signal->getDataPtr());
- m_error.code = ref->errorCode;
+ m_error.code= ref->errorCode;
m_masterNodeId = ref->masterNodeId;
m_waiter.signal(NO_WAIT);
}
@@ -1723,7 +1806,7 @@ NdbDictInterface::execALTER_TABLE_REF(NdbApiSignal * signal,
{
const AlterTableRef * const ref =
CAST_CONSTPTR(AlterTableRef, signal->getDataPtr());
- m_error.code = ref->errorCode;
+ m_error.code= ref->errorCode;
m_masterNodeId = ref->masterNodeId;
m_waiter.signal(NO_WAIT);
}
@@ -1738,7 +1821,7 @@ NdbDictionaryImpl::dropTable(const char * name)
DBUG_PRINT("enter",("name: %s", name));
NdbTableImpl * tab = getTable(name);
if(tab == 0){
- return -1;
+ DBUG_RETURN(-1);
}
int ret = dropTable(* tab);
// If table stored in cache is incompatible with the one in the kernel
@@ -1768,7 +1851,7 @@ NdbDictionaryImpl::dropTable(NdbTableImpl & impl)
}
if (impl.m_indexType != NdbDictionary::Index::Undefined) {
- m_receiver.m_error.code = 1228;
+ m_receiver.m_error.code= 1228;
return -1;
}
@@ -1869,19 +1952,23 @@ void
NdbDictInterface::execDROP_TABLE_CONF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
+ DBUG_ENTER("NdbDictInterface::execDROP_TABLE_CONF");
//DropTableConf* const conf = CAST_CONSTPTR(DropTableConf, signal->getDataPtr());
m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
void
NdbDictInterface::execDROP_TABLE_REF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
+ DBUG_ENTER("NdbDictInterface::execDROP_TABLE_REF");
const DropTableRef* const ref = CAST_CONSTPTR(DropTableRef, signal->getDataPtr());
- m_error.code = ref->errorCode;
+ m_error.code= ref->errorCode;
m_masterNodeId = ref->masterNodeId;
m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
int
@@ -1954,7 +2041,7 @@ NdbDictionaryImpl::getIndexImpl(const char * externalName,
int
NdbDictInterface::create_index_obj_from_table(NdbIndexImpl** dst,
- const NdbTableImpl* tab,
+ NdbTableImpl* tab,
const NdbTableImpl* prim){
NdbIndexImpl *idx = new NdbIndexImpl();
idx->m_version = tab->m_version;
@@ -1962,22 +2049,49 @@ NdbDictInterface::create_index_obj_from_table(NdbIndexImpl** dst,
idx->m_indexId = tab->m_tableId;
idx->m_externalName.assign(tab->getName());
idx->m_tableName.assign(prim->m_externalName);
- idx->m_type = tab->m_indexType;
+ NdbDictionary::Index::Type type = idx->m_type = tab->m_indexType;
idx->m_logging = tab->m_logging;
// skip last attribute (NDB$PK or NDB$TNODE)
- for(unsigned i = 0; i+1<tab->m_columns.size(); i++){
+
+ const Uint32 distKeys = prim->m_noOfDistributionKeys;
+ Uint32 keyCount = (distKeys ? distKeys : prim->m_noOfKeys);
+
+ unsigned i;
+ for(i = 0; i+1<tab->m_columns.size(); i++){
+ NdbColumnImpl* org = tab->m_columns[i];
+
NdbColumnImpl* col = new NdbColumnImpl;
// Copy column definition
- *col = *tab->m_columns[i];
+ *col = * org;
idx->m_columns.push_back(col);
+
/**
* reverse map
*/
- int key_id = prim->getColumn(col->getName())->getColumnNo();
+ const NdbColumnImpl* primCol = prim->getColumn(col->getName());
+ int key_id = primCol->getColumnNo();
int fill = -1;
idx->m_key_ids.fill(key_id, fill);
idx->m_key_ids[key_id] = i;
col->m_keyInfoPos = key_id;
+
+ if(type == NdbDictionary::Index::OrderedIndex &&
+ (primCol->m_distributionKey ||
+ (distKeys == 0 && primCol->getPrimaryKey())))
+ {
+ keyCount--;
+ org->m_distributionKey = 1;
+ }
+ }
+
+ if(keyCount == 0)
+ {
+ tab->m_noOfDistributionKeys = (distKeys ? distKeys : prim->m_noOfKeys);
+ }
+ else
+ {
+ for(i = 0; i+1<tab->m_columns.size(); i++)
+ tab->m_columns[i]->m_distributionKey = 0;
}
* dst = idx;
@@ -2056,10 +2170,6 @@ NdbDictInterface::createIndex(Ndb & ndb,
// Copy column definition
*impl.m_columns[i] = *col;
- if(col->m_pk && col->m_indexOnly){
- m_error.code = 4245;
- return -1;
- }
// index key type check
if (it == DictTabInfo::UniqueHashIndex &&
! NdbSqlUtil::usable_in_hash_index(col->m_type, col->m_cs) ||
@@ -2070,26 +2180,6 @@ NdbDictInterface::createIndex(Ndb & ndb,
}
attributeList.id[i] = col->m_attrId;
}
- if (it == DictTabInfo::UniqueHashIndex) {
- // Sort index attributes according to primary table (using insertion sort)
- for(i = 1; i < attributeList.sz; i++) {
- unsigned int temp = attributeList.id[i];
- unsigned int j = i;
- while((j > 0) && (attributeList.id[j - 1] > temp)) {
- attributeList.id[j] = attributeList.id[j - 1];
- j--;
- }
- attributeList.id[j] = temp;
- }
- // Check for illegal duplicate attributes
- for(i = 0; i<attributeList.sz; i++) {
- if ((i != (attributeList.sz - 1)) &&
- (attributeList.id[i] == attributeList.id[i+1])) {
- m_error.code = 4258;
- return -1;
- }
- }
- }
LinearSectionPtr ptr[3];
ptr[0].p = (Uint32*)&attributeList;
ptr[0].sz = 1 + attributeList.sz;
@@ -2266,13 +2356,12 @@ int
NdbDictionaryImpl::createEvent(NdbEventImpl & evnt)
{
int i;
- NdbTableImpl* tab = getTable(evnt.getTable());
+ NdbTableImpl* tab = getTable(evnt.getTableName());
if(tab == 0){
- // m_error.code = 3249;
- ndbout_c(":createEvent: table %s not found", evnt.getTable());
#ifdef EVENT_DEBUG
- ndbout_c("NdbDictionaryImpl::createEvent: table not found: %s", evnt.getTable());
+ ndbout_c("NdbDictionaryImpl::createEvent: table not found: %s",
+ evnt.getTableName());
#endif
return -1;
}
@@ -2294,7 +2383,8 @@ NdbDictionaryImpl::createEvent(NdbEventImpl & evnt)
evnt.m_facade->addColumn(*(col_impl->m_facade));
} else {
ndbout_c("Attr id %u in table %s not found", evnt.m_attrIds[i],
- evnt.getTable());
+ evnt.getTableName());
+ m_error.code= 4713;
return -1;
}
}
@@ -2313,7 +2403,7 @@ NdbDictionaryImpl::createEvent(NdbEventImpl & evnt)
const NdbColumnImpl* col =
table.getColumn(evnt.m_columns[i]->m_name.c_str());
if(col == 0){
- m_error.code = 4247;
+ m_error.code= 4247;
return -1;
}
// Copy column definition
@@ -2339,7 +2429,7 @@ NdbDictionaryImpl::createEvent(NdbEventImpl & evnt)
// Check for illegal duplicate attributes
for(i = 1; i<attributeList_sz; i++) {
if (evnt.m_columns[i-1]->m_attrId == evnt.m_columns[i]->m_attrId) {
- m_error.code = 4258;
+ m_error.code= 4258;
return -1;
}
}
@@ -2387,7 +2477,7 @@ NdbDictInterface::createEvent(class Ndb & ndb,
const size_t len = strlen(evnt.m_externalName.c_str()) + 1;
if(len > MAX_TAB_NAME_SIZE) {
- m_error.code = 4241;
+ m_error.code= 4241;
return -1;
}
@@ -2460,6 +2550,7 @@ int
NdbDictInterface::executeSubscribeEvent(class Ndb & ndb,
NdbEventImpl & evnt)
{
+ DBUG_ENTER("NdbDictInterface::executeSubscribeEvent");
NdbApiSignal tSignal(m_reference);
// tSignal.theReceiversBlockNumber = SUMA;
tSignal.theReceiversBlockNumber = DBDICT;
@@ -2474,7 +2565,7 @@ NdbDictInterface::executeSubscribeEvent(class Ndb & ndb,
sumaStart->subscriberData = evnt.m_bufferId & 0xFF;
sumaStart->subscriberRef = m_reference;
- return executeSubscribeEvent(&tSignal, NULL);
+ DBUG_RETURN(executeSubscribeEvent(&tSignal, NULL));
}
int
@@ -2500,9 +2591,7 @@ int
NdbDictInterface::stopSubscribeEvent(class Ndb & ndb,
NdbEventImpl & evnt)
{
-#ifdef EVENT_DEBUG
- ndbout_c("SUB_STOP_REQ");
-#endif
+ DBUG_ENTER("NdbDictInterface::stopSubscribeEvent");
NdbApiSignal tSignal(m_reference);
// tSignal.theReceiversBlockNumber = SUMA;
@@ -2518,7 +2607,7 @@ NdbDictInterface::stopSubscribeEvent(class Ndb & ndb,
sumaStop->part = (Uint32) SubscriptionData::TableData;
sumaStop->subscriberRef = m_reference;
- return stopSubscribeEvent(&tSignal, NULL);
+ DBUG_RETURN(stopSubscribeEvent(&tSignal, NULL));
}
int
@@ -2552,8 +2641,8 @@ NdbDictionaryImpl::getEvent(const char * eventName)
}
// We only have the table name with internal name
- ev->setTable(m_ndb.externalizeTableName(ev->getTable()));
- ev->m_tableImpl = getTable(ev->getTable());
+ ev->setTable(m_ndb.externalizeTableName(ev->getTableName()));
+ ev->m_tableImpl = getTable(ev->getTableName());
// get the columns from the attrListBitmask
@@ -2578,7 +2667,7 @@ NdbDictionaryImpl::getEvent(const char * eventName)
#ifdef EVENT_DEBUG
ndbout_c("NdbDictionaryImpl::getEvent could not find column id %d", id);
#endif
- m_error.code = 4247;
+ m_error.code= 4247;
delete ev;
return NULL;
}
@@ -2596,9 +2685,8 @@ void
NdbDictInterface::execCREATE_EVNT_CONF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
-#ifdef EVENT_DEBUG
- ndbout << "NdbDictionaryImpl.cpp: execCREATE_EVNT_CONF" << endl;
-#endif
+ DBUG_ENTER("NdbDictInterface::execCREATE_EVNT_CONF");
+
m_buffer.clear();
unsigned int len = signal->getLength() << 2;
m_buffer.append((char *)&len, sizeof(len));
@@ -2608,118 +2696,123 @@ NdbDictInterface::execCREATE_EVNT_CONF(NdbApiSignal * signal,
m_buffer.append((char *)ptr[0].p, strlen((char *)ptr[0].p)+1);
}
+ const CreateEvntConf * const createEvntConf=
+ CAST_CONSTPTR(CreateEvntConf, signal->getDataPtr());
+
+ Uint32 subscriptionId = createEvntConf->getEventId();
+ Uint32 subscriptionKey = createEvntConf->getEventKey();
+
+ DBUG_PRINT("info",("subscriptionId=%d,subscriptionKey=%d",
+ subscriptionId,subscriptionKey));
m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
void
NdbDictInterface::execCREATE_EVNT_REF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
-#ifdef EVENT_DEBUG
- ndbout << "NdbDictionaryImpl.cpp: execCREATE_EVNT_REF" << endl;
- ndbout << "Exiting" << endl;
- exit(-1);
-#endif
+ DBUG_ENTER("NdbDictInterface::execCREATE_EVNT_REF");
- const CreateEvntRef* const ref = CAST_CONSTPTR(CreateEvntRef, signal->getDataPtr());
- m_error.code = ref->getErrorCode();
-#ifdef EVENT_DEBUG
- ndbout_c("execCREATE_EVNT_REF");
- ndbout_c("ErrorCode %u", ref->getErrorCode());
- ndbout_c("Errorline %u", ref->getErrorLine());
- ndbout_c("ErrorNode %u", ref->getErrorNode());
-#endif
- m_waiter.signal(NO_WAIT);
+ const CreateEvntRef* const ref=
+ CAST_CONSTPTR(CreateEvntRef, signal->getDataPtr());
+ m_error.code= ref->getErrorCode();
+ DBUG_PRINT("error",("error=%d,line=%d,node=%d",ref->getErrorCode(),
+ ref->getErrorLine(),ref->getErrorNode()));
+ m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
void
NdbDictInterface::execSUB_STOP_CONF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
-#ifdef EVENT_DEBUG
- ndbout << "Got GSN_SUB_STOP_CONF" << endl;
-#endif
- // SubRemoveConf * const sumaRemoveConf = CAST_CONSTPTR(SubRemoveConf, signal->getDataPtr());
+ DBUG_ENTER("NdbDictInterface::execSUB_STOP_CONF");
+ const SubStopConf * const subStopConf=
+ CAST_CONSTPTR(SubStopConf, signal->getDataPtr());
- // Uint32 subscriptionId = sumaRemoveConf->subscriptionId;
- // Uint32 subscriptionKey = sumaRemoveConf->subscriptionKey;
- // Uint32 senderData = sumaRemoveConf->senderData;
+ Uint32 subscriptionId = subStopConf->subscriptionId;
+ Uint32 subscriptionKey = subStopConf->subscriptionKey;
+ Uint32 subscriberData = subStopConf->subscriberData;
+ DBUG_PRINT("info",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d",
+ subscriptionId,subscriptionKey,subscriberData));
m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
void
NdbDictInterface::execSUB_STOP_REF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
-#ifdef EVENT_DEBUG
- ndbout << "Got GSN_SUB_STOP_REF" << endl;
-#endif
- // SubRemoveConf * const sumaRemoveRef = CAST_CONSTPTR(SubRemoveRef, signal->getDataPtr());
+ DBUG_ENTER("NdbDictInterface::execSUB_STOP_REF");
+ const SubStopRef * const subStopRef=
+ CAST_CONSTPTR(SubStopRef, signal->getDataPtr());
- // Uint32 subscriptionId = sumaRemoveRef->subscriptionId;
- // Uint32 subscriptionKey = sumaRemoveRef->subscriptionKey;
- // Uint32 senderData = sumaRemoveRef->senderData;
+ Uint32 subscriptionId = subStopRef->subscriptionId;
+ Uint32 subscriptionKey = subStopRef->subscriptionKey;
+ Uint32 subscriberData = subStopRef->subscriberData;
+ m_error.code= subStopRef->errorCode;
- m_error.code = 1;
+ DBUG_PRINT("error",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d,error=%d",
+ subscriptionId,subscriptionKey,subscriberData,m_error.code));
m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
void
NdbDictInterface::execSUB_START_CONF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
-#ifdef EVENT_DEBUG
- ndbout << "Got GSN_SUB_START_CONF" << endl;
-#endif
- const SubStartConf * const sumaStartConf = CAST_CONSTPTR(SubStartConf, signal->getDataPtr());
+ DBUG_ENTER("NdbDictInterface::execSUB_START_CONF");
+ const SubStartConf * const subStartConf=
+ CAST_CONSTPTR(SubStartConf, signal->getDataPtr());
- // Uint32 subscriptionId = sumaStartConf->subscriptionId;
- // Uint32 subscriptionKey = sumaStartConf->subscriptionKey;
+ Uint32 subscriptionId = subStartConf->subscriptionId;
+ Uint32 subscriptionKey = subStartConf->subscriptionKey;
SubscriptionData::Part part =
- (SubscriptionData::Part)sumaStartConf->part;
- // Uint32 subscriberData = sumaStartConf->subscriberData;
+ (SubscriptionData::Part)subStartConf->part;
+ Uint32 subscriberData = subStartConf->subscriberData;
switch(part) {
case SubscriptionData::MetaData: {
-#ifdef EVENT_DEBUG
- ndbout << "SubscriptionData::MetaData" << endl;
-#endif
- m_error.code = 1;
+ DBUG_PRINT("error",("SubscriptionData::MetaData"));
+ m_error.code= 1;
break;
}
case SubscriptionData::TableData: {
-#ifdef EVENT_DEBUG
- ndbout << "SubscriptionData::TableData" << endl;
-#endif
+ DBUG_PRINT("info",("SubscriptionData::TableData"));
break;
}
default: {
-#ifdef EVENT_DEBUG
- ndbout_c("NdbDictInterface::execSUB_START_CONF wrong data");
-#endif
- m_error.code = 1;
+ DBUG_PRINT("error",("wrong data"));
+ m_error.code= 2;
break;
}
}
+ DBUG_PRINT("info",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d",
+ subscriptionId,subscriptionKey,subscriberData));
m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
void
NdbDictInterface::execSUB_START_REF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
-#ifdef EVENT_DEBUG
- ndbout << "Got GSN_SUB_START_REF" << endl;
-#endif
- m_error.code = 1;
- m_waiter.signal(NO_WAIT);
+ DBUG_ENTER("NdbDictInterface::execSUB_START_REF");
+ const SubStartRef * const subStartRef=
+ CAST_CONSTPTR(SubStartRef, signal->getDataPtr());
+ m_error.code= subStartRef->errorCode;
+ m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
void
NdbDictInterface::execSUB_GCP_COMPLETE_REP(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
- const SubGcpCompleteRep * const rep = CAST_CONSTPTR(SubGcpCompleteRep, signal->getDataPtr());
+ const SubGcpCompleteRep * const rep=
+ CAST_CONSTPTR(SubGcpCompleteRep, signal->getDataPtr());
const Uint32 gci = rep->gci;
// const Uint32 senderRef = rep->senderRef;
@@ -2730,7 +2823,8 @@ NdbDictInterface::execSUB_GCP_COMPLETE_REP(NdbApiSignal * signal,
const Uint32 ref = signal->theSendersBlockRef;
NdbApiSignal tSignal(m_reference);
- SubGcpCompleteAcc * acc = CAST_PTR(SubGcpCompleteAcc, tSignal.getDataPtrSend());
+ SubGcpCompleteAcc * acc=
+ CAST_PTR(SubGcpCompleteAcc, tSignal.getDataPtrSend());
acc->rep = *rep;
@@ -2788,9 +2882,9 @@ NdbDictInterface::execSUB_TABLE_DATA(NdbApiSignal * signal,
int
NdbDictionaryImpl::dropEvent(const char * eventName)
{
- NdbEventImpl *ev = new NdbEventImpl();
+ NdbEventImpl *ev= new NdbEventImpl();
ev->setName(eventName);
- int ret = m_receiver.dropEvent(*ev);
+ int ret= m_receiver.dropEvent(*ev);
delete ev;
// printf("__________________RET %u\n", ret);
@@ -2839,31 +2933,25 @@ void
NdbDictInterface::execDROP_EVNT_CONF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
-#ifdef EVENT_DEBUG
- ndbout << "NdbDictionaryImpl.cpp: execDROP_EVNT_CONF" << endl;
-#endif
-
+ DBUG_ENTER("NdbDictInterface::execDROP_EVNT_CONF");
m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
void
NdbDictInterface::execDROP_EVNT_REF(NdbApiSignal * signal,
LinearSectionPtr ptr[3])
{
-#ifdef EVENT_DEBUG
- ndbout << "NdbDictionaryImpl.cpp: execDROP_EVNT_REF" << endl;
-#endif
- const DropEvntRef* const ref = CAST_CONSTPTR(DropEvntRef, signal->getDataPtr());
- m_error.code = ref->getErrorCode();
+ DBUG_ENTER("NdbDictInterface::execDROP_EVNT_REF");
+ const DropEvntRef* const ref=
+ CAST_CONSTPTR(DropEvntRef, signal->getDataPtr());
+ m_error.code= ref->getErrorCode();
-#if 0
- ndbout_c("execDROP_EVNT_REF");
- ndbout_c("ErrorCode %u", ref->getErrorCode());
- ndbout_c("Errorline %u", ref->getErrorLine());
- ndbout_c("ErrorNode %u", ref->getErrorNode());
-#endif
+ DBUG_PRINT("info",("ErrorCode=%u Errorline=%u ErrorNode=%u",
+ ref->getErrorCode(), ref->getErrorLine(), ref->getErrorNode()));
- m_waiter.signal(NO_WAIT);
+ m_waiter.signal(NO_WAIT);
+ DBUG_VOID_RETURN;
}
/*****************************************************************
@@ -2928,7 +3016,7 @@ NdbDictInterface::listObjects(NdbDictionary::Dictionary::List& list,
}
if (! ok) {
// bad signal data
- m_error.code = 4213;
+ m_error.code= 4213;
return -1;
}
list.count = count;
@@ -2950,8 +3038,6 @@ NdbDictInterface::listObjects(NdbDictionary::Dictionary::List& list,
BaseString schemaName;
BaseString objectName;
if ((element.type == NdbDictionary::Object::UniqueHashIndex) ||
- (element.type == NdbDictionary::Object::HashIndex) ||
- (element.type == NdbDictionary::Object::UniqueOrderedIndex) ||
(element.type == NdbDictionary::Object::OrderedIndex)) {
char * indexName = new char[n << 2];
memcpy(indexName, &data[pos], n << 2);
@@ -2996,7 +3082,7 @@ NdbDictInterface::listObjects(NdbApiSignal* signal)
m_transporter->lock_mutex();
Uint16 aNodeId = m_transporter->get_an_alive_node();
if (aNodeId == 0) {
- m_error.code = 4009;
+ m_error.code= 4009;
m_transporter->unlock_mutex();
return -1;
}
@@ -3004,7 +3090,7 @@ NdbDictInterface::listObjects(NdbApiSignal* signal)
m_transporter->unlock_mutex();
continue;
}
- m_error.code = 0;
+ m_error.code= 0;
m_waiter.m_node = aNodeId;
m_waiter.m_state = WAIT_LIST_TABLES_CONF;
m_waiter.wait(WAITFOR_RESPONSE_TIMEOUT);
@@ -3033,6 +3119,7 @@ NdbDictInterface::execLIST_TABLES_CONF(NdbApiSignal* signal,
}
template class Vector<int>;
+template class Vector<Uint16>;
template class Vector<Uint32>;
template class Vector<Vector<Uint32> >;
template class Vector<NdbTableImpl*>;
diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/ndb/src/ndbapi/NdbDictionaryImpl.hpp
index 602a2d6b6ca..59a5956715a 100644
--- a/ndb/src/ndbapi/NdbDictionaryImpl.hpp
+++ b/ndb/src/ndbapi/NdbDictionaryImpl.hpp
@@ -63,12 +63,8 @@ public:
CHARSET_INFO * m_cs; // not const in MySQL
bool m_pk;
- bool m_tupleKey;
bool m_distributionKey;
- bool m_distributionGroup;
- int m_distributionGroupBits;
bool m_nullable;
- bool m_indexOnly;
bool m_autoIncrement;
Uint64 m_autoIncrementInitialValue;
BaseString m_defaultValue;
@@ -77,13 +73,13 @@ public:
/**
* Internal types and sizes, and aggregates
*/
- Uint32 m_attrType; // type outsize API and DICT
Uint32 m_attrSize; // element size (size when arraySize==1)
Uint32 m_arraySize; // length or length+2 for Var* types
Uint32 m_keyInfoPos;
- Uint32 m_extType; // used by restore (kernel type in versin v2x)
+ // TODO: use bits in attr desc 2
bool getInterpretableType() const ;
bool getCharType() const;
+ bool getStringType() const;
bool getBlobType() const;
/**
@@ -123,13 +119,20 @@ public:
Vector<Uint32> m_columnHash;
Vector<NdbColumnImpl *> m_columns;
void buildColumnHash();
-
+
+ /**
+ * Fragment info
+ */
+ Uint32 m_hashValueMask;
+ Uint32 m_hashpointerValue;
+ Vector<Uint16> m_fragments;
+
bool m_logging;
int m_kvalue;
int m_minLoadFactor;
int m_maxLoadFactor;
- int m_keyLenInWords;
- int m_fragmentCount;
+ Uint16 m_keyLenInWords;
+ Uint16 m_fragmentCount;
NdbDictionaryImpl * m_dictionary;
NdbIndexImpl * m_index;
@@ -147,9 +150,11 @@ public:
/**
* Aggregates
*/
- Uint32 m_noOfKeys;
- unsigned short m_sizeOfKeysInWords;
- unsigned short m_noOfBlobs;
+ Uint8 m_noOfKeys;
+ Uint8 m_noOfDistributionKeys;
+ Uint8 m_noOfBlobs;
+
+ Uint8 m_replicaCount;
/**
* Equality/assign
@@ -162,6 +167,11 @@ public:
static NdbTableImpl & getImpl(NdbDictionary::Table & t);
static NdbTableImpl & getImpl(const NdbDictionary::Table & t);
NdbDictionary::Table * m_facade;
+
+ /**
+ * Return count
+ */
+ Uint32 get_nodes(Uint32 hashValue, const Uint16** nodes) const ;
};
class NdbIndexImpl : public NdbDictionary::Index, public NdbDictObjectImpl {
@@ -201,11 +211,14 @@ public:
void setName(const char * name);
const char * getName() const;
+ void setTable(const NdbDictionary::Table& table);
void setTable(const char * table);
- const char * getTable() const;
+ const char * getTableName() const;
void addTableEvent(const NdbDictionary::Event::TableEvent t);
- void setDurability(const NdbDictionary::Event::EventDurability d);
+ void setDurability(NdbDictionary::Event::EventDurability d);
+ NdbDictionary::Event::EventDurability getDurability() const;
void addEventColumn(const NdbColumnImpl &c);
+ int getNoOfEventColumns() const;
void print() {
ndbout_c("NdbEventImpl: id=%d, key=%d",
@@ -307,8 +320,8 @@ public:
bool fullyQualifiedNames);
static int create_index_obj_from_table(NdbIndexImpl ** dst,
- const NdbTableImpl*,
- const NdbTableImpl*);
+ NdbTableImpl* index_table,
+ const NdbTableImpl* primary_table);
NdbError & m_error;
private:
@@ -454,7 +467,19 @@ bool
NdbColumnImpl::getCharType() const {
return (m_type == NdbDictionary::Column::Char ||
m_type == NdbDictionary::Column::Varchar ||
- m_type == NdbDictionary::Column::Text);
+ m_type == NdbDictionary::Column::Text ||
+ m_type == NdbDictionary::Column::Longvarchar);
+}
+
+inline
+bool
+NdbColumnImpl::getStringType() const {
+ return (m_type == NdbDictionary::Column::Char ||
+ m_type == NdbDictionary::Column::Varchar ||
+ m_type == NdbDictionary::Column::Longvarchar ||
+ m_type == NdbDictionary::Column::Binary ||
+ m_type == NdbDictionary::Column::Varbinary ||
+ m_type == NdbDictionary::Column::Longvarbinary);
}
inline
@@ -535,7 +560,7 @@ NdbTableImpl::getColumn(const char * name){
do {
if(hashValue == (tmp & 0xFFFE)){
NdbColumnImpl* col = cols[tmp >> 16];
- if(strcmp(name, col->m_name.c_str()) == 0){
+ if(strncmp(name, col->m_name.c_str(), NDB_MAX_ATTR_NAME_SIZE-1) == 0){
return col;
}
}
@@ -553,7 +578,7 @@ NdbTableImpl::getColumn(const char * name){
} else {
for(Uint32 i = 0; i<sz; i++){
NdbColumnImpl* col = * cols++;
- if(col != 0 && strcmp(name, col->m_name.c_str()) == 0)
+ if(col != 0 && strncmp(name, col->m_name.c_str(), NDB_MAX_ATTR_NAME_SIZE-1) == 0)
return col;
}
}
diff --git a/ndb/src/ndbapi/NdbEventOperation.cpp b/ndb/src/ndbapi/NdbEventOperation.cpp
index d209293f8b0..e99cad918c5 100644
--- a/ndb/src/ndbapi/NdbEventOperation.cpp
+++ b/ndb/src/ndbapi/NdbEventOperation.cpp
@@ -15,23 +15,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*****************************************************************************
- * Name: NdbEventOperation.cpp
- * Include:
- * Link:
- * Author: Tomas Ulin MySQL AB
- * Date: 2003-11-21
- * Version: 0.1
- * Description: Event support
- * Documentation:
- * Adjust: 2003-11-21 Tomas Ulin First version.
- ****************************************************************************/
-
#include <Ndb.hpp>
-#include <signaldata/SumaImpl.hpp>
+#include <NdbError.hpp>
#include <portlib/NdbMem.h>
-#include <transporter/TransporterDefinitions.hpp>
-#include <NdbEventOperation.hpp>
#include "NdbEventOperationImpl.hpp"
#include "NdbDictionaryImpl.hpp"
@@ -123,3 +109,7 @@ NdbEventOperation::wait(void *p, int aMillisecondNumber)
NdbEventOperation::NdbEventOperation(NdbEventOperationImpl& impl)
: m_impl(impl) {}
+const struct NdbError &
+NdbEventOperation::getNdbError() const {
+ return m_impl.getNdbError();
+}
diff --git a/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/ndb/src/ndbapi/NdbEventOperationImpl.cpp
index 87bbca5fc71..208525bfc15 100644
--- a/ndb/src/ndbapi/NdbEventOperationImpl.cpp
+++ b/ndb/src/ndbapi/NdbEventOperationImpl.cpp
@@ -55,14 +55,17 @@ NdbEventOperationImpl::NdbEventOperationImpl(NdbEventOperation &N,
const char* eventName,
const int bufferLength)
: NdbEventOperation(*this), m_ndb(theNdb),
- m_state(ERROR), m_bufferL(bufferLength)
+ m_state(EO_ERROR), m_bufferL(bufferLength)
{
-
m_eventId = 0;
- theFirstRecAttrs[0] = NULL;
- theCurrentRecAttrs[0] = NULL;
- theFirstRecAttrs[1] = NULL;
- theCurrentRecAttrs[1] = NULL;
+ theFirstPkAttrs[0] = NULL;
+ theCurrentPkAttrs[0] = NULL;
+ theFirstPkAttrs[1] = NULL;
+ theCurrentPkAttrs[1] = NULL;
+ theFirstDataAttrs[0] = NULL;
+ theCurrentDataAttrs[0] = NULL;
+ theFirstDataAttrs[1] = NULL;
+ theCurrentDataAttrs[1] = NULL;
sdata = NULL;
ptr[0].p = NULL;
ptr[1].p = NULL;
@@ -71,16 +74,17 @@ NdbEventOperationImpl::NdbEventOperationImpl(NdbEventOperation &N,
// we should lookup id in Dictionary, TODO
// also make sure we only have one listener on each event
- if (!m_ndb) { ndbout_c("m_ndb=NULL"); return; }
+ if (!m_ndb) abort();
NdbDictionary::Dictionary *myDict = m_ndb->getDictionary();
- if (!myDict) { ndbout_c("getDictionary=NULL"); return; }
+ if (!myDict) { m_error.code= m_ndb->getNdbError().code; return; }
const NdbDictionary::Event *myEvnt = myDict->getEvent(eventName);
- if (!myEvnt) { ndbout_c("getEvent()=NULL"); return; }
+ if (!myEvnt) { m_error.code= myDict->getNdbError().code; return; }
m_eventImpl = &myEvnt->m_impl;
- if (!m_eventImpl) { ndbout_c("m_impl=NULL"); return; }
+
+ m_eventId = m_eventImpl->m_eventId;
m_bufferHandle = m_ndb->getGlobalEventBufferHandle();
if (m_bufferHandle->m_bufferL > 0)
@@ -88,25 +92,30 @@ NdbEventOperationImpl::NdbEventOperationImpl(NdbEventOperation &N,
else
m_bufferHandle->m_bufferL = m_bufferL;
- m_state = CREATED;
+ m_state = EO_CREATED;
}
NdbEventOperationImpl::~NdbEventOperationImpl()
{
int i;
- if (sdata) NdbMem_Free(sdata);
- for (i=0 ; i<3; i++) {
- if (ptr[i].p) NdbMem_Free(ptr[i].p);
+ if (sdata) NdbMem_Free((char*)sdata);
+ for (i=0 ; i<2; i++) {
+ NdbRecAttr *p = theFirstPkAttrs[i];
+ while (p) {
+ NdbRecAttr *p_next = p->next();
+ m_ndb->releaseRecAttr(p);
+ p = p_next;
+ }
}
for (i=0 ; i<2; i++) {
- NdbRecAttr *p = theFirstRecAttrs[i];
+ NdbRecAttr *p = theFirstDataAttrs[i];
while (p) {
NdbRecAttr *p_next = p->next();
m_ndb->releaseRecAttr(p);
p = p_next;
}
}
- if (m_state == NdbEventOperation::EXECUTING) {
+ if (m_state == EO_EXECUTING) {
stop();
// m_bufferHandle->dropSubscribeEvent(m_bufferId);
; // We should send stop signal here
@@ -122,36 +131,50 @@ NdbEventOperationImpl::getState()
NdbRecAttr*
NdbEventOperationImpl::getValue(const char *colName, char *aValue, int n)
{
- if (m_state != NdbEventOperation::CREATED) {
+ DBUG_ENTER("NdbEventOperationImpl::getValue");
+ if (m_state != EO_CREATED) {
ndbout_c("NdbEventOperationImpl::getValue may only be called between instantiation and execute()");
- return NULL;
+ DBUG_RETURN(NULL);
}
NdbColumnImpl *tAttrInfo = m_eventImpl->m_tableImpl->getColumn(colName);
if (tAttrInfo == NULL) {
ndbout_c("NdbEventOperationImpl::getValue attribute %s not found",colName);
- return NULL;
+ DBUG_RETURN(NULL);
}
- return NdbEventOperationImpl::getValue(tAttrInfo, aValue, n);
+ DBUG_RETURN(NdbEventOperationImpl::getValue(tAttrInfo, aValue, n));
}
NdbRecAttr*
NdbEventOperationImpl::getValue(const NdbColumnImpl *tAttrInfo, char *aValue, int n)
{
+ DBUG_ENTER("NdbEventOperationImpl::getValue");
// Insert Attribute Id into ATTRINFO part.
- NdbRecAttr *&theFirstRecAttr = theFirstRecAttrs[n];
- NdbRecAttr *&theCurrentRecAttr = theCurrentRecAttrs[n];
-
+
+ NdbRecAttr **theFirstAttr;
+ NdbRecAttr **theCurrentAttr;
+
+ if (tAttrInfo->getPrimaryKey())
+ {
+ theFirstAttr = &theFirstPkAttrs[n];
+ theCurrentAttr = &theCurrentPkAttrs[n];
+ }
+ else
+ {
+ theFirstAttr = &theFirstDataAttrs[n];
+ theCurrentAttr = &theCurrentDataAttrs[n];
+ }
+
/************************************************************************
* Get a Receive Attribute object and link it into the operation object.
************************************************************************/
- NdbRecAttr *tRecAttr = m_ndb->getRecAttr();
- if (tRecAttr == NULL) {
+ NdbRecAttr *tAttr = m_ndb->getRecAttr();
+ if (tAttr == NULL) {
exit(-1);
//setErrorCodeAbort(4000);
- return NULL;
+ DBUG_RETURN(NULL);
}
/**********************************************************************
@@ -159,63 +182,65 @@ NdbEventOperationImpl::getValue(const NdbColumnImpl *tAttrInfo, char *aValue, in
* the RecAttr object
* Also set attribute size, array size and attribute type
********************************************************************/
- if (tRecAttr->setup(tAttrInfo, aValue)) {
+ if (tAttr->setup(tAttrInfo, aValue)) {
//setErrorCodeAbort(4000);
- m_ndb->releaseRecAttr(tRecAttr);
+ m_ndb->releaseRecAttr(tAttr);
exit(-1);
- return NULL;
+ DBUG_RETURN(NULL);
}
//theErrorLine++;
- tRecAttr->setNULL();
+ tAttr->setUNDEFINED();
// We want to keep the list sorted to make data insertion easier later
- if (theFirstRecAttr == NULL) {
- theFirstRecAttr = tRecAttr;
- theCurrentRecAttr = tRecAttr;
- tRecAttr->next(NULL);
+
+ if (*theFirstAttr == NULL) {
+ *theFirstAttr = tAttr;
+ *theCurrentAttr = tAttr;
+ tAttr->next(NULL);
} else {
Uint32 tAttrId = tAttrInfo->m_attrId;
- if (tAttrId > theCurrentRecAttr->attrId()) { // right order
- theCurrentRecAttr->next(tRecAttr);
- tRecAttr->next(NULL);
- theCurrentRecAttr = tRecAttr;
- } else if (theFirstRecAttr->next() == NULL || // only one in list
- theFirstRecAttr->attrId() > tAttrId) {// or first
- tRecAttr->next(theFirstRecAttr);
- theFirstRecAttr = tRecAttr;
+ if (tAttrId > (*theCurrentAttr)->attrId()) { // right order
+ (*theCurrentAttr)->next(tAttr);
+ tAttr->next(NULL);
+ *theCurrentAttr = tAttr;
+ } else if ((*theFirstAttr)->next() == NULL || // only one in list
+ (*theFirstAttr)->attrId() > tAttrId) {// or first
+ tAttr->next(*theFirstAttr);
+ *theFirstAttr = tAttr;
} else { // at least 2 in list and not first and not last
- NdbRecAttr *p = theFirstRecAttr;
+ NdbRecAttr *p = *theFirstAttr;
NdbRecAttr *p_next = p->next();
while (tAttrId > p_next->attrId()) {
p = p_next;
p_next = p->next();
}
if (tAttrId == p_next->attrId()) { // Using same attribute twice
- tRecAttr->release(); // do I need to do this?
- m_ndb->releaseRecAttr(tRecAttr);
+ tAttr->release(); // do I need to do this?
+ m_ndb->releaseRecAttr(tAttr);
exit(-1);
- return NULL;
+ DBUG_RETURN(NULL);
}
// this is it, between p and p_next
- p->next(tRecAttr);
- tRecAttr->next(p_next);
+ p->next(tAttr);
+ tAttr->next(p_next);
}
}
-
- return tRecAttr;
+ DBUG_RETURN(tAttr);
}
int
NdbEventOperationImpl::execute()
{
+ DBUG_ENTER("NdbEventOperationImpl::execute");
NdbDictionary::Dictionary *myDict = m_ndb->getDictionary();
if (!myDict) {
- ndbout_c("NdbEventOperation::execute(): getDictionary=NULL");
- return 0;
+ m_error.code= m_ndb->getNdbError().code;
+ DBUG_RETURN(-1);
}
- if (theFirstRecAttrs[0] == NULL) { // defaults to get all
+ if (theFirstPkAttrs[0] == NULL &&
+ theFirstDataAttrs[0] == NULL) { // defaults to get all
}
@@ -223,13 +248,18 @@ NdbEventOperationImpl::execute()
int hasSubscriber;
- m_bufferId =
- m_bufferHandle->prepareAddSubscribeEvent(m_eventImpl->m_eventId,
- hasSubscriber /* return value */);
+ int r= m_bufferHandle->prepareAddSubscribeEvent(this,
+ hasSubscriber /*return value*/);
+ m_error.code= 4709;
+
+ if (r < 0)
+ {
+ DBUG_RETURN(-1);
+ }
- m_eventImpl->m_bufferId = m_bufferId;
+ m_eventImpl->m_bufferId = m_bufferId = (Uint32)r;
- int r = -1;
+ r = -1;
if (m_bufferId >= 0) {
// now we check if there's already a subscriber
@@ -241,30 +271,33 @@ NdbEventOperationImpl::execute()
if (r) {
//Error
m_bufferHandle->unprepareAddSubscribeEvent(m_bufferId);
- m_state = NdbEventOperation::ERROR;
+ m_state = EO_ERROR;
} else {
m_bufferHandle->addSubscribeEvent(m_bufferId, this);
- m_state = NdbEventOperation::EXECUTING;
+ m_state = EO_EXECUTING;
}
} else {
//Error
- m_state = NdbEventOperation::ERROR;
+ m_state = EO_ERROR;
}
- return r;
+ DBUG_RETURN(r);
}
int
NdbEventOperationImpl::stop()
{
- if (m_state != NdbEventOperation::EXECUTING)
- return -1;
+ DBUG_ENTER("NdbEventOperationImpl::stop");
+ if (m_state != EO_EXECUTING)
+ {
+ DBUG_RETURN(-1);
+ }
// ndbout_c("NdbEventOperation::stopping()");
NdbDictionary::Dictionary *myDict = m_ndb->getDictionary();
if (!myDict) {
- ndbout_c("NdbEventOperation::stop(): getDictionary=NULL");
- return 0;
+ m_error.code= m_ndb->getNdbError().code;
+ DBUG_RETURN(-1);
}
NdbDictionaryImpl & myDictImpl = NdbDictionaryImpl::getImpl(*myDict);
@@ -275,8 +308,8 @@ NdbEventOperationImpl::stop()
hasSubscriber /* return value */);
if (ret < 0) {
- ndbout_c("prepareDropSubscribeEvent failed");
- return -1;
+ m_error.code= 4712;
+ DBUG_RETURN(-1);
}
// m_eventImpl->m_bufferId = m_bufferId;
@@ -293,17 +326,17 @@ NdbEventOperationImpl::stop()
if (r) {
//Error
m_bufferHandle->unprepareDropSubscribeEvent(m_bufferId);
- m_state = NdbEventOperation::ERROR;
+ m_error.code= myDictImpl.m_error.code;
+ m_state = EO_ERROR;
} else {
#ifdef EVENT_DEBUG
ndbout_c("NdbEventOperation::dropping()");
#endif
m_bufferHandle->dropSubscribeEvent(m_bufferId);
- m_state = NdbEventOperation::CREATED;
+ m_state = EO_CREATED;
}
-
- return r;
+ DBUG_RETURN(r);
}
bool
@@ -327,6 +360,7 @@ NdbEventOperationImpl::getLatestGCI()
int
NdbEventOperationImpl::next(int *pOverrun)
{
+ DBUG_ENTER("NdbEventOperationImpl::next");
int nr = 10000; // a high value
int tmpOverrun = 0;
int *ptmpOverrun;
@@ -343,7 +377,10 @@ NdbEventOperationImpl::next(int *pOverrun)
*pOverrun = tmpOverrun;
}
- if (r <= 0) return r; // no data
+ if (r <= 0)
+ {
+ DBUG_RETURN(r); // no data
+ }
if (r < nr) r = nr; else nr--; // we don't want to be stuck here forever
@@ -352,8 +389,13 @@ NdbEventOperationImpl::next(int *pOverrun)
#endif
// now move the data into the RecAttrs
- if ((theFirstRecAttrs[0] == NULL) &&
- (theFirstRecAttrs[1] == NULL)) return r;
+ if ((theFirstPkAttrs[0] == NULL) &&
+ (theFirstPkAttrs[1] == NULL) &&
+ (theFirstDataAttrs[0] == NULL) &&
+ (theFirstDataAttrs[1] == NULL))
+ {
+ DBUG_RETURN(r);
+ }
// no copying since no RecAttr's
@@ -364,20 +406,37 @@ NdbEventOperationImpl::next(int *pOverrun)
#ifdef EVENT_DEBUG
int i;
printf("after values sz=%u\n", ptr[1].sz);
- for (i=0; i < ptr[1].sz; i++)
+ for(i=0; i < (int)ptr[1].sz; i++)
printf ("H'%.8X ",ptr[1].p[i]);
printf("\n");
printf("before values sz=%u\n", ptr[2].sz);
- for (i=0; i < ptr[2].sz; i++)
+ for(i=0; i < (int)ptr[2].sz; i++)
printf ("H'%.8X ",ptr[2].p[i]);
printf("\n");
#endif
- NdbRecAttr *tWorkingRecAttr = theFirstRecAttrs[0];
-
// copy data into the RecAttr's
// we assume that the respective attribute lists are sorted
+ // first the pk's
+ {
+ NdbRecAttr *tAttr= theFirstPkAttrs[0];
+ while(tAttr)
+ {
+ assert(aAttrPtr < aAttrEndPtr);
+ unsigned tDataSz= AttributeHeader(*aAttrPtr).getDataSize();
+ assert(tAttr->attrId() ==
+ AttributeHeader(*aAttrPtr).getAttributeId());
+ assert(tAttr->receive_data(aDataPtr, tDataSz));
+ // next
+ aAttrPtr++;
+ aDataPtr+= tDataSz;
+ tAttr= tAttr->next();
+ }
+ }
+
+ NdbRecAttr *tWorkingRecAttr = theFirstDataAttrs[0];
+
Uint32 tRecAttrId;
Uint32 tAttrId;
Uint32 tDataSz;
@@ -389,7 +448,7 @@ NdbEventOperationImpl::next(int *pOverrun)
while (tAttrId > tRecAttrId) {
//printf("[%u] %u %u [%u]\n", tAttrId, tDataSz, *aDataPtr, tRecAttrId);
- tWorkingRecAttr->setNULL();
+ tWorkingRecAttr->setUNDEFINED();
tWorkingRecAttr = tWorkingRecAttr->next();
if (tWorkingRecAttr == NULL)
break;
@@ -401,32 +460,25 @@ NdbEventOperationImpl::next(int *pOverrun)
//printf("[%u] %u %u [%u]\n", tAttrId, tDataSz, *aDataPtr, tRecAttrId);
if (tAttrId == tRecAttrId) {
- if (!m_eventImpl->m_tableImpl->getColumn(tRecAttrId)->getPrimaryKey())
- hasSomeData++;
+ hasSomeData++;
//printf("set!\n");
- tWorkingRecAttr->receive_data(aDataPtr, tDataSz);
-
- // move forward, data has already moved forward
- aAttrPtr++;
- aDataPtr += tDataSz;
+ assert(tWorkingRecAttr->receive_data(aDataPtr, tDataSz));
tWorkingRecAttr = tWorkingRecAttr->next();
- } else {
- // move only attr forward
- aAttrPtr++;
- aDataPtr += tDataSz;
}
+ aAttrPtr++;
+ aDataPtr += tDataSz;
}
while (tWorkingRecAttr != NULL) {
tRecAttrId = tWorkingRecAttr->attrId();
//printf("set undefined [%u] %u %u [%u]\n", tAttrId, tDataSz, *aDataPtr, tRecAttrId);
- tWorkingRecAttr->setNULL();
+ tWorkingRecAttr->setUNDEFINED();
tWorkingRecAttr = tWorkingRecAttr->next();
}
- tWorkingRecAttr = theFirstRecAttrs[1];
+ tWorkingRecAttr = theFirstDataAttrs[1];
aDataPtr = ptr[2].p;
Uint32 *aDataEndPtr = aDataPtr + ptr[2].sz;
while ((aDataPtr < aDataEndPtr) && (tWorkingRecAttr != NULL)) {
@@ -435,7 +487,7 @@ NdbEventOperationImpl::next(int *pOverrun)
tDataSz = AttributeHeader(*aDataPtr).getDataSize();
aDataPtr++;
while (tAttrId > tRecAttrId) {
- tWorkingRecAttr->setNULL();
+ tWorkingRecAttr->setUNDEFINED();
tWorkingRecAttr = tWorkingRecAttr->next();
if (tWorkingRecAttr == NULL)
break;
@@ -444,27 +496,25 @@ NdbEventOperationImpl::next(int *pOverrun)
if (tWorkingRecAttr == NULL)
break;
if (tAttrId == tRecAttrId) {
- if (!m_eventImpl->m_tableImpl->getColumn(tRecAttrId)->getPrimaryKey())
- hasSomeData++;
+ assert(!m_eventImpl->m_tableImpl->getColumn(tRecAttrId)->getPrimaryKey());
+ hasSomeData++;
- tWorkingRecAttr->receive_data(aDataPtr, tDataSz);
- aDataPtr += tDataSz;
- // move forward, data+attr has already moved forward
+ assert(tWorkingRecAttr->receive_data(aDataPtr, tDataSz));
tWorkingRecAttr = tWorkingRecAttr->next();
- } else {
- // move only data+attr forward
- aDataPtr += tDataSz;
}
+ aDataPtr += tDataSz;
}
while (tWorkingRecAttr != NULL) {
- tWorkingRecAttr->setNULL();
+ tWorkingRecAttr->setUNDEFINED();
tWorkingRecAttr = tWorkingRecAttr->next();
}
if (hasSomeData)
- return r;
+ {
+ DBUG_RETURN(r);
+ }
}
- return 0;
+ DBUG_RETURN(0);
}
NdbDictionary::Event::TableEvent
@@ -487,10 +537,20 @@ NdbEventOperationImpl::getEventType()
void
NdbEventOperationImpl::print()
{
+ int i;
ndbout << "EventId " << m_eventId << "\n";
- for (int i = 0; i < 2; i++) {
- NdbRecAttr *p = theFirstRecAttrs[i];
+ for (i = 0; i < 2; i++) {
+ NdbRecAttr *p = theFirstPkAttrs[i];
+ ndbout << " %u " << i;
+ while (p) {
+ ndbout << " : " << p->attrId() << " = " << *p;
+ p = p->next();
+ }
+ ndbout << "\n";
+ }
+ for (i = 0; i < 2; i++) {
+ NdbRecAttr *p = theFirstDataAttrs[i];
ndbout << " %u " << i;
while (p) {
ndbout << " : " << p->attrId() << " = " << *p;
@@ -639,23 +699,28 @@ NdbGlobalEventBufferHandle::~NdbGlobalEventBufferHandle()
void
NdbGlobalEventBufferHandle::addBufferId(int bufferId)
{
+ DBUG_ENTER("NdbGlobalEventBufferHandle::addBufferId");
+ DBUG_PRINT("enter",("bufferId=%d",bufferId));
if (m_nids >= NDB_MAX_ACTIVE_EVENTS) {
ndbout_c("NdbGlobalEventBufferHandle::addBufferId error in paramerer setting");
exit(-1);
}
m_bufferIds[m_nids] = bufferId;
m_nids++;
+ DBUG_VOID_RETURN;
}
void
NdbGlobalEventBufferHandle::dropBufferId(int bufferId)
{
+ DBUG_ENTER("NdbGlobalEventBufferHandle::dropBufferId");
+ DBUG_PRINT("enter",("bufferId=%d",bufferId));
for (int i = 0; i < m_nids; i++)
if (m_bufferIds[i] == bufferId) {
m_nids--;
for (; i < m_nids; i++)
m_bufferIds[i] = m_bufferIds[i+1];
- return;
+ DBUG_VOID_RETURN;
}
ndbout_c("NdbGlobalEventBufferHandle::dropBufferId %d does not exist",
bufferId);
@@ -674,10 +739,11 @@ NdbGlobalEventBufferHandle::drop(NdbGlobalEventBufferHandle *handle)
}
*/
int
-NdbGlobalEventBufferHandle::prepareAddSubscribeEvent(Uint32 eventId,
- int& hasSubscriber)
+NdbGlobalEventBufferHandle::prepareAddSubscribeEvent
+(NdbEventOperationImpl *eventOp, int& hasSubscriber)
{
- ADD_DROP_LOCK_GUARDR(int,real_prepareAddSubscribeEvent(this, eventId, hasSubscriber));
+ ADD_DROP_LOCK_GUARDR(int,real_prepareAddSubscribeEvent(this, eventOp,
+ hasSubscriber));
}
void
NdbGlobalEventBufferHandle::addSubscribeEvent
@@ -830,57 +896,68 @@ NdbGlobalEventBuffer::~NdbGlobalEventBuffer()
// NdbMem_Deallocate(m_eventBufferIdToEventId);
}
void
-NdbGlobalEventBuffer::real_init (NdbGlobalEventBufferHandle *h,
+NdbGlobalEventBuffer::real_init (NdbGlobalEventBufferHandle *h,
int MAX_NUMBER_ACTIVE_EVENTS)
{
- if (m_handlers.size() == 0) { // First init
+ DBUG_ENTER("NdbGlobalEventBuffer::real_init");
+ DBUG_PRINT("enter",("m_handles.size()=%u %u", m_handlers.size(), h));
+ if (m_handlers.size() == 0)
+ { // First init
+ DBUG_PRINT("info",("first to come"));
m_max = MAX_NUMBER_ACTIVE_EVENTS;
m_buf = new BufItem[m_max];
- // (BufItem *)NdbMem_Allocate(m_max*sizeof(BufItem));
-
for (int i=0; i<m_max; i++) {
- m_buf[i].gId = 0;
+ m_buf[i].gId= 0;
}
}
+ assert(m_max == MAX_NUMBER_ACTIVE_EVENTS);
// TODO make sure we don't hit roof
- // m_handlers[m_nhandlers] = h;
m_handlers.push_back(h);
- // ndbout_c("NdbGlobalEventBuffer::real_init(), m_handles=%u %u", m_nhandlers, h);
+ DBUG_VOID_RETURN;
}
void
NdbGlobalEventBuffer::real_remove(NdbGlobalEventBufferHandle *h)
{
- // ndbout_c("NdbGlobalEventBuffer::real_init_remove(), m_handles=%u %u", m_nhandlers, h);
- for (Uint32 i=0 ; i < m_handlers.size(); i++) {
- // ndbout_c("%u %u %u", i, m_handlers[i], h);
- if (m_handlers[i] == h) {
+ DBUG_ENTER("NdbGlobalEventBuffer::real_remove");
+ DBUG_PRINT("enter",("m_handles.size()=%u %u", m_handlers.size(), h));
+ for (Uint32 i=0 ; i < m_handlers.size(); i++)
+ {
+ DBUG_PRINT("info",("m_handlers[%u] %u", i, m_handlers[i]));
+ if (m_handlers[i] == h)
+ {
m_handlers.erase(i);
- if (m_handlers.size() == 0) {
- // ndbout_c("last to go");
+ if (m_handlers.size() == 0)
+ {
+ DBUG_PRINT("info",("last to go"));
delete[] m_buf;
m_buf = NULL;
- // NdbMem_Free((char*)m_buf);
}
- return;
+ DBUG_VOID_RETURN;
}
}
- ndbout_c("NdbGlobalEventBuffer::real_init_remove() non-existing handle");
- exit(-1);
+ ndbout_c("NdbGlobalEventBuffer::real_remove() non-existing handle");
+ DBUG_PRINT("error",("non-existing handle"));
+ abort();
+ DBUG_VOID_RETURN;
}
-int
+int
NdbGlobalEventBuffer::real_prepareAddSubscribeEvent
-(NdbGlobalEventBufferHandle *aHandle, Uint32 eventId, int& hasSubscriber)
+(NdbGlobalEventBufferHandle *aHandle, NdbEventOperationImpl *eventOp,
+ int& hasSubscriber)
{
+ DBUG_ENTER("NdbGlobalEventBuffer::real_prepareAddSubscribeEvent");
int i;
- int bufferId = -1;
+ int bufferId= -1;
+ Uint32 eventId= eventOp->m_eventId;
+ DBUG_PRINT("enter",("eventId: %u", eventId));
// add_drop_lock(); // only one thread can do add or drop at a time
// Find place where eventId already set
for (i=0; i<m_no; i++) {
if (m_buf[i].gId == eventId) {
- bufferId = i;
+ bufferId= i;
break;
}
}
@@ -888,53 +965,55 @@ NdbGlobalEventBuffer::real_prepareAddSubscribeEvent
// find space for new bufferId
for (i=0; i<m_no; i++) {
if (m_buf[i].gId == 0) {
- bufferId = i; // we found an empty spot
- break;
+ bufferId= i; // we found an empty spot
+ goto found_bufferId;
}
}
if (bufferId < 0 &&
m_no < m_max) {
// room for more so get that
- bufferId=m_no;
- m_buf[m_no].gId = 0;
+ bufferId= m_no;
+ m_buf[m_no].gId= 0;
m_no++;
} else {
- ndbout_c("prepareAddSubscribeEvent: Can't accept more subscribers");
- // add_drop_unlock();
- return -1;
+ // add_drop_unlock();
+ DBUG_PRINT("error",("Can't accept more subscribers:"
+ " bufferId=%d, m_no=%d, m_max=%d",
+ bufferId, m_no, m_max));
+ DBUG_RETURN(-1);
}
}
+found_bufferId:
- BufItem &b = m_buf[ID(bufferId)];
+ BufItem &b= m_buf[ID(bufferId)];
if (b.gId == 0) { // first subscriber needs some initialization
- bufferId = NO_ID(0, bufferId);
+ bufferId= NO_ID(0, bufferId);
- b.gId = eventId;
+ b.gId= eventId;
+ b.eventType= (Uint32)eventOp->m_eventImpl->mi_type;
- if ((b.p_buf_mutex = NdbMutex_Create()) == NULL) {
+ if ((b.p_buf_mutex= NdbMutex_Create()) == NULL) {
ndbout_c("NdbGlobalEventBuffer: NdbMutex_Create() failed");
- exit(-1);
+ abort();
}
- b.subs = 0;
- b.f = 0;
- b.sz = 0;
- b.max_sz = aHandle->m_bufferL;
- b.data =
+ b.subs= 0;
+ b.f= 0;
+ b.sz= 0;
+ b.max_sz= aHandle->m_bufferL;
+ b.data=
(BufItem::Data *)NdbMem_Allocate(b.max_sz*sizeof(BufItem::Data));
for (int i = 0; i < b.max_sz; i++) {
- b.data[i].sdata = NULL;
- b.data[i].ptr[0].p = NULL;
- b.data[i].ptr[1].p = NULL;
- b.data[i].ptr[2].p = NULL;
+ b.data[i].sdata= NULL;
+ b.data[i].ptr[0].p= NULL;
+ b.data[i].ptr[1].p= NULL;
+ b.data[i].ptr[2].p= NULL;
}
} else {
-#ifdef EVENT_DEBUG
- ndbout_c("NdbGlobalEventBuffer::prepareAddSubscribeEvent: TRYING handle one subscriber per event b.subs = %u", b.subs);
-#endif
-
+ DBUG_PRINT("info",
+ ("TRYING handle one subscriber per event b.subs=%u",b.subs));
int ni = -1;
for(int i=0; i < b.subs;i++) {
if (b.ps[i].theHandle == NULL) {
@@ -946,9 +1025,10 @@ NdbGlobalEventBuffer::real_prepareAddSubscribeEvent
if (b.subs < MAX_SUBSCRIBERS_PER_EVENT) {
ni = b.subs;
} else {
- ndbout_c("prepareAddSubscribeEvent: Can't accept more subscribers");
+ DBUG_PRINT("error",
+ ("Can't accept more subscribers: b.subs=%d",b.subs));
// add_drop_unlock();
- return -1;
+ DBUG_RETURN(-1);
}
}
bufferId = NO_ID(ni, bufferId);
@@ -969,23 +1049,25 @@ NdbGlobalEventBuffer::real_prepareAddSubscribeEvent
else
hasSubscriber = 0;
-#ifdef EVENT_DEBUG
- ndbout_c("prepareAddSubscribeEvent: handed out bufferId %d for eventId %d",
- bufferId, eventId);
-#endif
+ DBUG_PRINT("info",("handed out bufferId=%d for eventId=%d hasSubscriber=%d",
+ bufferId, eventId, hasSubscriber));
/* we now have a lock on the prepare so that no one can mess with this
* unlock comes in unprepareAddSubscribeEvent or addSubscribeEvent
*/
- return bufferId;
+ DBUG_RETURN(bufferId);
}
void
NdbGlobalEventBuffer::real_unprepareAddSubscribeEvent(int bufferId)
{
+ DBUG_ENTER("NdbGlobalEventBuffer::real_unprepareAddSubscribeEvent");
BufItem &b = m_buf[ID(bufferId)];
int n = NO(bufferId);
+ DBUG_PRINT("enter", ("bufferId=%d,ID(bufferId)=%d,NO(bufferId)=%d",
+ bufferId, ID(bufferId), NO(bufferId)));
+
b.ps[n].theHandle = NULL;
// remove subscribers from the end,
@@ -998,10 +1080,8 @@ NdbGlobalEventBuffer::real_unprepareAddSubscribeEvent(int bufferId)
break;
if (b.subs == 0) {
-#ifdef EVENT_DEBUG
- ndbout_c("unprepareAddSubscribeEvent: no more subscribers left on eventId %d", b.gId);
-#endif
- b.gId = 0; // We don't have any subscribers, reuse BufItem
+ DBUG_PRINT("info",("no more subscribers left on eventId %d", b.gId));
+ b.gId= 0; // We don't have any subscribers, reuse BufItem
if (b.data) {
NdbMem_Free((void *)b.data);
b.data = NULL;
@@ -1012,12 +1092,14 @@ NdbGlobalEventBuffer::real_unprepareAddSubscribeEvent(int bufferId)
}
}
// add_drop_unlock();
+ DBUG_VOID_RETURN;
}
void
NdbGlobalEventBuffer::real_addSubscribeEvent(int bufferId,
void *ndbEventOperation)
{
+ DBUG_ENTER("NdbGlobalEventBuffer::real_addSubscribeEvent");
BufItem &b = m_buf[ID(bufferId)];
int n = NO(bufferId);
@@ -1025,9 +1107,8 @@ NdbGlobalEventBuffer::real_addSubscribeEvent(int bufferId,
b.ps[n].theHandle->addBufferId(bufferId);
// add_drop_unlock();
-#ifdef EVENT_DEBUG
- ndbout_c("addSubscribeEvent:: added bufferId %d", bufferId);
-#endif
+ DBUG_PRINT("info",("added bufferId %d", bufferId));
+ DBUG_VOID_RETURN;
}
void
@@ -1040,6 +1121,7 @@ int
NdbGlobalEventBuffer::real_prepareDropSubscribeEvent(int bufferId,
int& hasSubscriber)
{
+ DBUG_ENTER("NdbGlobalEventBuffer::real_prepareDropSubscribeEvent");
// add_drop_lock(); // only one thread can do add or drop at a time
BufItem &b = m_buf[ID(bufferId)];
@@ -1055,14 +1137,17 @@ NdbGlobalEventBuffer::real_prepareDropSubscribeEvent(int bufferId,
else if (n == 1)
hasSubscriber = 0;
else
- return -1;
+ {
+ DBUG_RETURN(-1);
+ }
- return 0;
+ DBUG_RETURN(0);
}
void
NdbGlobalEventBuffer::real_dropSubscribeEvent(int bufferId)
{
+ DBUG_ENTER("NdbGlobalEventBuffer::real_dropSubscribeEvent");
// add_drop_lock(); // only one thread can do add-drop at a time
BufItem &b = m_buf[ID(bufferId)];
@@ -1078,6 +1163,7 @@ NdbGlobalEventBuffer::real_dropSubscribeEvent(int bufferId)
#ifdef EVENT_DEBUG
ndbout_c("dropSubscribeEvent:: dropped bufferId %d", bufferId);
#endif
+ DBUG_VOID_RETURN;
}
void
@@ -1100,10 +1186,13 @@ NdbGlobalEventBuffer::real_insertDataL(int bufferId,
const SubTableData * const sdata,
LinearSectionPtr ptr[3])
{
+ DBUG_ENTER("NdbGlobalEventBuffer::real_insertDataL");
BufItem &b = m_buf[ID(bufferId)];
#ifdef EVENT_DEBUG
int n = NO(bufferId);
#endif
+
+ if ( b.eventType & (1 << (Uint32)sdata->operation) )
{
if (b.subs) {
#ifdef EVENT_DEBUG
@@ -1112,7 +1201,9 @@ NdbGlobalEventBuffer::real_insertDataL(int bufferId,
// move front forward
if (copy_data_alloc(sdata, ptr,
b.data[b.f].sdata, b.data[b.f].ptr))
- return -1;
+ {
+ DBUG_RETURN(-1);
+ }
for (int i=0; i < b.subs; i++) {
NdbGlobalEventBuffer::BufItem::Ps &e = b.ps[i];
if (e.theHandle) { // active subscriber
@@ -1120,7 +1211,7 @@ NdbGlobalEventBuffer::real_insertDataL(int bufferId,
if (e.bufferempty == 0) {
e.overrun++; // another item has been overwritten
e.b++; // move next-to-read next since old item was overwritten
- if (e.b == b.max_sz) e.b = 0; // start from beginning
+ if (e.b == b.max_sz) e.b= 0; // start from beginning
}
}
e.bufferempty = 0;
@@ -1140,21 +1231,35 @@ NdbGlobalEventBuffer::real_insertDataL(int bufferId,
#endif
}
}
- return 0;
+ else
+ {
+#ifdef EVENT_DEBUG
+ ndbout_c("skipped");
+#endif
+ }
+
+ DBUG_RETURN(0);
}
int NdbGlobalEventBuffer::hasData(int bufferId) {
+ DBUG_ENTER("NdbGlobalEventBuffer::hasData");
BufItem &b = m_buf[ID(bufferId)];
int n = NO(bufferId);
NdbGlobalEventBuffer::BufItem::Ps &e = b.ps[n];
if(e.bufferempty)
- return 0;
+ {
+ DBUG_RETURN(0);
+ }
if (b.f <= e.b)
- return b.max_sz-e.b + b.f;
+ {
+ DBUG_RETURN(b.max_sz-e.b + b.f);
+ }
else
- return b.f-e.b;
+ {
+ DBUG_RETURN(b.f-e.b);
+ }
}
int NdbGlobalEventBuffer::real_getDataL(const int bufferId,
@@ -1162,6 +1267,7 @@ int NdbGlobalEventBuffer::real_getDataL(const int bufferId,
LinearSectionPtr ptr[3],
int *pOverrun)
{
+ DBUG_ENTER("NdbGlobalEventBuffer::real_getDataL");
BufItem &b = m_buf[ID(bufferId)];
int n = NO(bufferId);
NdbGlobalEventBuffer::BufItem::Ps &e = b.ps[n];
@@ -1172,13 +1278,20 @@ int NdbGlobalEventBuffer::real_getDataL(const int bufferId,
}
if (e.bufferempty)
- return 0; // nothing to get
+ {
+ DBUG_RETURN(0); // nothing to get
+ }
+
+ DBUG_PRINT("info",("ID(bufferId) %d NO(bufferId) %d e.b %d",
+ ID(bufferId), NO(bufferId), e.b));
if (copy_data_alloc(b.data[e.b].sdata, b.data[e.b].ptr,
sdata, ptr))
- return -1;
+ {
+ DBUG_RETURN(-1);
+ }
- e.b++; if (e.b == b.max_sz) e.b = 0; // move next-to-read forward
+ e.b++; if (e.b == b.max_sz) e.b= 0; // move next-to-read forward
if (b.f == e.b) // back has cought up with front
e.bufferempty = 1;
@@ -1187,7 +1300,7 @@ int NdbGlobalEventBuffer::real_getDataL(const int bufferId,
ndbout_c("getting data from buffer %d with eventId %d", bufferId, b.gId);
#endif
- return hasData(bufferId)+1;
+ DBUG_RETURN(hasData(bufferId)+1);
}
int
NdbGlobalEventBuffer::copy_data_alloc(const SubTableData * const f_sdata,
@@ -1195,49 +1308,59 @@ NdbGlobalEventBuffer::copy_data_alloc(const SubTableData * const f_sdata,
SubTableData * &t_sdata,
LinearSectionPtr t_ptr[3])
{
- if (t_sdata == NULL) {
- t_sdata = (SubTableData *)NdbMem_Allocate(sizeof(SubTableData));
- }
+ DBUG_ENTER("NdbGlobalEventBuffer::copy_data_alloc");
+ unsigned sz4= (sizeof(SubTableData)+3)>>2;
+ Uint32 *ptr= (Uint32*)NdbMem_Allocate((sz4 +
+ f_ptr[0].sz +
+ f_ptr[1].sz +
+ f_ptr[2].sz) * sizeof(Uint32));
+ if (t_sdata)
+ NdbMem_Free((char*)t_sdata);
+ t_sdata= (SubTableData *)ptr;
memcpy(t_sdata,f_sdata,sizeof(SubTableData));
+ ptr+= sz4;
+
for (int i = 0; i < 3; i++) {
LinearSectionPtr & f_p = f_ptr[i];
LinearSectionPtr & t_p = t_ptr[i];
if (f_p.sz > 0) {
- if (t_p.p == NULL) {
- t_p.p = (Uint32 *)NdbMem_Allocate(sizeof(Uint32)*f_p.sz);
- } else if (t_p.sz != f_p.sz) {
- NdbMem_Free(t_p.p);
- t_p.p = (Uint32 *)NdbMem_Allocate(sizeof(Uint32)*f_p.sz);
- }
+ t_p.p= (Uint32 *)ptr;
memcpy(t_p.p, f_p.p, sizeof(Uint32)*f_p.sz);
- } else if (t_p.p != NULL) {
- NdbMem_Free(t_p.p);
- t_p.p = NULL;
+ ptr+= f_p.sz;
+ t_p.sz= f_p.sz;
+ } else {
+ t_p.p= NULL;
+ t_p.sz= 0;
}
- t_p.sz = f_p.sz;
}
- return 0;
+ DBUG_RETURN(0);
}
int
NdbGlobalEventBuffer::real_wait(NdbGlobalEventBufferHandle *h,
int aMillisecondNumber)
{
+ DBUG_ENTER("NdbGlobalEventBuffer::real_wait");
// check if there are anything in any of the buffers
int i;
int n = 0;
for (i = 0; i < h->m_nids; i++)
n += hasData(h->m_bufferIds[i]);
- if (n) return n;
+ if (n)
+ {
+ DBUG_RETURN(n);
+ }
int r = NdbCondition_WaitTimeout(h->p_cond, ndb_global_event_buffer_mutex,
aMillisecondNumber);
if (r > 0)
- return -1;
+ {
+ DBUG_RETURN(-1);
+ }
n = 0;
for (i = 0; i < h->m_nids; i++)
n += hasData(h->m_bufferIds[i]);
- return n;
+ DBUG_RETURN(n);
}
template class Vector<NdbGlobalEventBufferHandle*>;
diff --git a/ndb/src/ndbapi/NdbEventOperationImpl.hpp b/ndb/src/ndbapi/NdbEventOperationImpl.hpp
index f67c998e639..96958979c76 100644
--- a/ndb/src/ndbapi/NdbEventOperationImpl.hpp
+++ b/ndb/src/ndbapi/NdbEventOperationImpl.hpp
@@ -14,21 +14,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*****************************************************************************
- * Name: NdbEventOperationImpl.hpp
- * Include:
- * Link:
- * Author: Tomas Ulin MySQL AB
- * Date: 2003-11-21
- * Version: 0.1
- * Description: Event support
- * Documentation:
- * Adjust: 2003-11-21 Tomas Ulin First version.
- ****************************************************************************/
-
#ifndef NdbEventOperationImpl_H
#define NdbEventOperationImpl_H
+#include <NdbEventOperation.hpp>
+#include <signaldata/SumaImpl.hpp>
+#include <transporter/TransporterDefinitions.hpp>
+
class NdbGlobalEventBufferHandle;
class NdbEventOperationImpl : public NdbEventOperation {
public:
@@ -61,12 +53,17 @@ public:
void print();
void printAll();
+ const NdbError & getNdbError() const;
+ NdbError m_error;
+
Ndb *m_ndb;
NdbEventImpl *m_eventImpl;
NdbGlobalEventBufferHandle *m_bufferHandle;
- NdbRecAttr *theFirstRecAttrs[2];
- NdbRecAttr *theCurrentRecAttrs[2];
+ NdbRecAttr *theFirstPkAttrs[2];
+ NdbRecAttr *theCurrentPkAttrs[2];
+ NdbRecAttr *theFirstDataAttrs[2];
+ NdbRecAttr *theCurrentDataAttrs[2];
NdbEventOperation::State m_state;
Uint32 m_eventId;
@@ -84,7 +81,7 @@ public:
//static NdbGlobalEventBufferHandle *init(int MAX_NUMBER_ACTIVE_EVENTS);
// returns bufferId 0-N if ok otherwise -1
- int prepareAddSubscribeEvent(Uint32 eventId, int& hasSubscriber);
+ int prepareAddSubscribeEvent(NdbEventOperationImpl *, int& hasSubscriber);
void unprepareAddSubscribeEvent(int bufferId);
void addSubscribeEvent(int bufferId,
NdbEventOperationImpl *ndbEventOperationImpl);
@@ -138,7 +135,8 @@ private:
int MAX_NUMBER_ACTIVE_EVENTS);
int real_prepareAddSubscribeEvent(NdbGlobalEventBufferHandle *h,
- Uint32 eventId, int& hasSubscriber);
+ NdbEventOperationImpl *,
+ int& hasSubscriber);
void real_unprepareAddSubscribeEvent(int bufferId);
void real_addSubscribeEvent(int bufferId, void *ndbEventOperation);
@@ -182,6 +180,7 @@ private:
// local mutex for each event/buffer
NdbMutex *p_buf_mutex;
Uint32 gId;
+ Uint32 eventType;
struct Data {
SubTableData *sdata;
LinearSectionPtr ptr[3];
diff --git a/ndb/src/ndbapi/NdbImpl.hpp b/ndb/src/ndbapi/NdbImpl.hpp
index 00a8ef19f3a..d649b39c5eb 100644
--- a/ndb/src/ndbapi/NdbImpl.hpp
+++ b/ndb/src/ndbapi/NdbImpl.hpp
@@ -89,9 +89,9 @@ Ndb::void2rec(void* val){
}
inline
-NdbConnection *
+NdbTransaction *
Ndb::void2con(void* val){
- return (NdbConnection*)val;
+ return (NdbTransaction*)val;
}
inline
@@ -107,7 +107,7 @@ Ndb::void2rec_iop(void* val){
}
inline
-NdbConnection *
+NdbTransaction *
NdbReceiver::getTransaction(){
return ((NdbOperation*)m_owner)->theNdbCon;
}
diff --git a/ndb/src/ndbapi/NdbIndexOperation.cpp b/ndb/src/ndbapi/NdbIndexOperation.cpp
index 39da9c5f5d0..4cedffed4a2 100644
--- a/ndb/src/ndbapi/NdbIndexOperation.cpp
+++ b/ndb/src/ndbapi/NdbIndexOperation.cpp
@@ -16,9 +16,8 @@
#include <ndb_global.h>
#include <NdbIndexOperation.hpp>
-#include <NdbResultSet.hpp>
#include <Ndb.hpp>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include "NdbApiSignal.hpp"
#include <AttributeHeader.hpp>
#include <signaldata/TcIndx.hpp>
@@ -28,9 +27,7 @@
NdbIndexOperation::NdbIndexOperation(Ndb* aNdb) :
NdbOperation(aNdb),
- m_theIndex(NULL),
- m_theIndexLen(0),
- m_theNoOfIndexDefined(0)
+ m_theIndex(NULL)
{
m_tcReqGSN = GSN_TCINDXREQ;
m_attrInfoGSN = GSN_INDXATTRINFO;
@@ -56,7 +53,7 @@ NdbIndexOperation::~NdbIndexOperation()
int
NdbIndexOperation::indxInit(const NdbIndexImpl * anIndex,
const NdbTableImpl * aTable,
- NdbConnection* myConnection)
+ NdbTransaction* myConnection)
{
NdbOperation::init(aTable, myConnection);
@@ -64,25 +61,13 @@ NdbIndexOperation::indxInit(const NdbIndexImpl * anIndex,
case(NdbDictionary::Index::UniqueHashIndex):
break;
case(NdbDictionary::Index::Undefined):
- case(NdbDictionary::Index::HashIndex):
- case(NdbDictionary::Index::UniqueOrderedIndex):
case(NdbDictionary::Index::OrderedIndex):
setErrorCodeAbort(4003);
return -1;
}
m_theIndex = anIndex;
- m_thePrimaryTable = aTable;
m_accessTable = anIndex->m_table;
- m_theIndexLen = 0;
- m_theNoOfIndexDefined = 0;
- for (Uint32 i=0; i<NDB_MAX_ATTRIBUTES_IN_INDEX; i++)
- for (int j=0; j<3; j++)
- m_theIndexDefined[i][j] = false;
-
- TcIndxReq * const tcIndxReq = CAST_PTR(TcIndxReq, theTCREQ->getDataPtrSend());
- tcIndxReq->scanInfo = 0;
- theKEYINFOptr = &tcIndxReq->keyInfo[0];
- theATTRINFOptr = &tcIndxReq->attrInfo[0];
+ theNoOfTupKeyLeft = m_accessTable->getNoOfPrimaryKeys();
return 0;
}
@@ -179,312 +164,6 @@ int NdbIndexOperation::interpretedDeleteTuple()
return NdbOperation::interpretedDeleteTuple();
}
-int NdbIndexOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
- const char* aValuePassed,
- Uint32 aVariableKeyLen)
-{
- register Uint32 tAttrId;
-
- Uint32 tData;
- Uint32 tKeyInfoPosition;
- const char* aValue = aValuePassed;
- Uint32 xfrmData[1024];
- Uint32 tempData[1024];
-
- if ((theStatus == OperationDefined) &&
- (aValue != NULL) &&
- (tAttrInfo != NULL )) {
- /************************************************************************
- * Start by checking that the attribute is an index key.
- * This value is also the word order in the tuple key of this
- * tuple key attribute.
- * Then check that this tuple key has not already been defined.
- * Finally check if all tuple key attributes have been defined. If
- * this is true then set Operation state to tuple key defined.
- ************************************************************************/
- tAttrId = tAttrInfo->m_attrId;
- tKeyInfoPosition = tAttrInfo->m_keyInfoPos;
- Uint32 i = 0;
-
- // Check that the attribute is part if the index attributes
- // by checking if it is a primary key attribute of index table
- if (tAttrInfo->m_pk) {
- Uint32 tKeyDefined = theTupleKeyDefined[0][2];
- Uint32 tKeyAttrId = theTupleKeyDefined[0][0];
- do {
- if (tKeyDefined == false) {
- goto keyEntryFound;
- } else {
- if (tKeyAttrId != tAttrId) {
- /******************************************************************
- * We read the key defined variable in advance.
- * It could potentially read outside its area when
- * i = MAXNROFTUPLEKEY - 1,
- * it is not a problem as long as the variable
- * theTupleKeyDefined is defined
- * in the middle of the object.
- * Reading wrong data and not using it causes no problems.
- *****************************************************************/
- i++;
- tKeyAttrId = theTupleKeyDefined[i][0];
- tKeyDefined = theTupleKeyDefined[i][2];
- continue;
- } else {
- goto equal_error2;
- }//if
- }//if
- } while (i < NDB_MAX_ATTRIBUTES_IN_INDEX);
- goto equal_error2;
- } else {
- goto equal_error1;
- }
- /**************************************************************************
- * Now it is time to retrieve the tuple key data from the pointer supplied
- * by the application.
- * We have to retrieve the size of the attribute in words and bits.
- *************************************************************************/
- keyEntryFound:
- m_theIndexDefined[i][0] = tAttrId;
- m_theIndexDefined[i][1] = tKeyInfoPosition;
- m_theIndexDefined[i][2] = true;
-
- Uint32 sizeInBytes = tAttrInfo->m_attrSize * tAttrInfo->m_arraySize;
- {
- /*************************************************************************
- * Check if the pointer of the value passed is aligned on a 4 byte
- * boundary. If so only assign the pointer to the internal variable
- * aValue. If it is not aligned then we start by copying the value to
- * tempData and use this as aValue instead.
- *************************************************************************/
- const int attributeSize = sizeInBytes;
- const int slack = sizeInBytes & 3;
- if ((((UintPtr)aValue & 3) != 0) || (slack != 0)){
- memcpy(&tempData[0], aValue, attributeSize);
- aValue = (char*)&tempData[0];
- if(slack != 0) {
- char * tmp = (char*)&tempData[0];
- memset(&tmp[attributeSize], 0, (4 - slack));
- }//if
- }//if
- }
- const char* aValueToWrite = aValue;
-
- CHARSET_INFO* cs = tAttrInfo->m_cs;
- if (cs != 0) {
- // current limitation: strxfrm does not increase length
- assert(cs->strxfrm_multiply <= 1);
- unsigned n =
- (*cs->coll->strnxfrm)(cs,
- (uchar*)xfrmData, sizeof(xfrmData),
- (const uchar*)aValue, sizeInBytes);
- while (n < sizeInBytes)
- ((uchar*)xfrmData)[n++] = 0x20;
- aValue = (char*)xfrmData;
- }
-
- Uint32 bitsInLastWord = 8 * (sizeInBytes & 3) ;
- Uint32 totalSizeInWords = (sizeInBytes + 3)/4;// Inc. bits in last word
- Uint32 sizeInWords = sizeInBytes / 4; // Exc. bits in last word
-
- if (true){ //tArraySize != 0) {
- Uint32 tIndexLen = m_theIndexLen;
-
- m_theIndexLen = tIndexLen + totalSizeInWords;
- if ((aVariableKeyLen == sizeInBytes) ||
- (aVariableKeyLen == 0)) {
- ;
- } else {
- goto equal_error3;
- }
- }
-#if 0
- else {
- /************************************************************************
- * The attribute is a variable array. We need to use the length parameter
- * to know the size of this attribute in the key information and
- * variable area. A key is however not allowed to be larger than 4
- * kBytes and this is checked for variable array attributes
- * used as keys.
- ***********************************************************************/
- Uint32 tMaxVariableKeyLenInWord = (MAXTUPLEKEYLENOFATTERIBUTEINWORD -
- tKeyInfoPosition);
- tAttrSizeInBits = aVariableKeyLen << 3;
- tAttrSizeInWords = tAttrSizeInBits >> 5;
- tAttrBitsInLastWord = tAttrSizeInBits - (tAttrSizeInWords << 5);
- tAttrLenInWords = ((tAttrSizeInBits + 31) >> 5);
- if (tAttrLenInWords > tMaxVariableKeyLenInWord) {
- setErrorCodeAbort(4207);
- return -1;
- }//if
- m_theIndexLen = m_theIndexLen + tAttrLenInWords;
- }//if
-#endif
- int tDistrKey = tAttrInfo->m_distributionKey;
- int tDistrGroup = tAttrInfo->m_distributionGroup;
- OperationType tOpType = theOperationType;
- if ((tDistrKey != 1) && (tDistrGroup != 1)) {
- ;
- } else if (tDistrKey == 1) {
- theDistrKeySize += totalSizeInWords;
- theDistrKeyIndicator = 1;
- } else {
- Uint32 TsizeInBytes = sizeInBytes;
- Uint32 TbyteOrderFix = 0;
- char* TcharByteOrderFix = (char*)&TbyteOrderFix;
- if (tAttrInfo->m_distributionGroupBits == 8) {
- char tFirstChar = aValue[TsizeInBytes - 2];
- char tSecondChar = aValue[TsizeInBytes - 2];
- TcharByteOrderFix[0] = tFirstChar;
- TcharByteOrderFix[1] = tSecondChar;
- TcharByteOrderFix[2] = 0x30;
- TcharByteOrderFix[3] = 0x30;
- theDistrGroupType = 0;
- } else {
- TbyteOrderFix = ((aValue[TsizeInBytes - 2] - 0x30) * 10)
- + (aValue[TsizeInBytes - 1] - 0x30);
- theDistrGroupType = 1;
- }//if
- theDistributionGroup = TbyteOrderFix;
- theDistrGroupIndicator = 1;
- }//if
- /**************************************************************************
- * If the operation is a write request and the attribute is stored then
- * we also set the value in the stored part through putting the
- * information in the INDXATTRINFO signals.
- *************************************************************************/
- if ((tOpType == WriteRequest)) {
- if (!tAttrInfo->m_indexOnly){
- int dummy_error;
- // invalid data can crash kernel
- if (cs != NULL &&
- (*cs->cset->well_formed_len)(cs,
- aValueToWrite,
- aValueToWrite + sizeInBytes,
- sizeInBytes,
- &dummy_error) != sizeInBytes)
- goto equal_error4;
- Uint32 ahValue;
- Uint32 sz = totalSizeInWords;
- /*
- * XXX should be linked in metadata but cannot now because
- * things can be defined in arbitrary order
- */
- const NdbColumnImpl* primaryCol = m_thePrimaryTable->getColumn(tAttrInfo->m_name.c_str());
- assert(primaryCol != NULL);
- AttributeHeader::init(&ahValue, primaryCol->m_attrId, sz);
- insertATTRINFO( ahValue );
- insertATTRINFOloop((Uint32*)aValueToWrite, sizeInWords);
- if (bitsInLastWord != 0) {
- tData = *(Uint32*)(aValueToWrite + (sizeInWords << 2));
- tData = convertEndian(tData);
- tData = tData & ((1 << bitsInLastWord) - 1);
- tData = convertEndian(tData);
- insertATTRINFO( tData );
- }//if
- }//if
- }//if
- /**************************************************************************
- * Store the Key information in the TCINDXREQ and INDXKEYINFO signals.
- *************************************************************************/
- if (insertKEYINFO(aValue, tKeyInfoPosition,
- totalSizeInWords, bitsInLastWord) != -1) {
- /************************************************************************
- * Add one to number of tuple key attributes defined.
- * If all have been defined then set the operation state to indicate
- * that tuple key is defined.
- * Thereby no more search conditions are allowed in this version.
- ***********************************************************************/
- Uint32 tNoIndexDef = m_theNoOfIndexDefined;
- Uint32 tErrorLine = theErrorLine;
- int tNoIndexAttrs = m_theIndex->m_columns.size();
- unsigned char tInterpretInd = theInterpretIndicator;
- tNoIndexDef++;
- m_theNoOfIndexDefined = tNoIndexDef;
- tErrorLine++;
- theErrorLine = tErrorLine;
- if (int(tNoIndexDef) == tNoIndexAttrs) {
- if (tOpType == UpdateRequest) {
- if (tInterpretInd == 1) {
- theStatus = GetValue;
- } else {
- theStatus = SetValue;
- }//if
- return 0;
- } else if ((tOpType == ReadRequest) || (tOpType == DeleteRequest) ||
- (tOpType == ReadExclusive)) {
- theStatus = GetValue;
- // create blob handles automatically
- if (tOpType == DeleteRequest && m_currentTable->m_noOfBlobs != 0) {
- for (unsigned i = 0; i < m_currentTable->m_columns.size(); i++) {
- NdbColumnImpl* c = m_currentTable->m_columns[i];
- assert(c != 0);
- if (c->getBlobType()) {
- if (getBlobHandle(theNdbCon, c) == NULL)
- return -1;
- }
- }
- }
- return 0;
- } else if ((tOpType == InsertRequest) || (tOpType == WriteRequest)) {
- theStatus = SetValue;
- return 0;
- } else {
- setErrorCodeAbort(4005);
- return -1;
- }//if
- }//if
- return 0;
- } else {
-
- return -1;
- }//if
- } else {
- if (theStatus != OperationDefined) {
- return -1;
- }//if
-
- if (aValue == NULL) {
- setErrorCodeAbort(4505);
- return -1;
- }//if
-
- if ( tAttrInfo == NULL ) {
- setErrorCodeAbort(4004);
- return -1;
- }//if
- }//if
- return -1;
-
- equal_error1:
- setErrorCodeAbort(4205);
- return -1;
-
- equal_error2:
- setErrorCodeAbort(4206);
- return -1;
-
- equal_error3:
- setErrorCodeAbort(4209);
- return -1;
-
- equal_error4:
- setErrorCodeAbort(744);
- return -1;
-}
-
-int NdbIndexOperation::executeCursor(int aProcessorId)
-{
- printf("NdbIndexOperation::executeCursor NYI\n");
- // NYI
- return -1;
-}
-void
-NdbIndexOperation::setLastFlag(NdbApiSignal* signal, Uint32 lastFlag)
-{
- TcIndxReq * const req = CAST_PTR(TcIndxReq, signal->getDataPtrSend());
- TcKeyReq::setExecuteFlag(req->requestInfo, lastFlag);
-}
-
int
NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
{
@@ -525,18 +204,18 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
// We start by filling in the first 8 unconditional words of the
// TCINDXREQ signal.
//-------------------------------------------------------------
- TcIndxReq * const tcIndxReq =
- CAST_PTR(TcIndxReq, theTCREQ->getDataPtrSend());
+ TcKeyReq * tcKeyReq =
+ CAST_PTR(TcKeyReq, theTCREQ->getDataPtrSend());
Uint32 tTotalCurrAI_Len = theTotalCurrAI_Len;
Uint32 tIndexId = m_theIndex->m_indexId;
Uint32 tSchemaVersion = m_theIndex->m_version;
- tcIndxReq->apiConnectPtr = aTC_ConnectPtr;
- tcIndxReq->senderData = ptr2int();
- tcIndxReq->attrLen = tTotalCurrAI_Len;
- tcIndxReq->indexId = tIndexId;
- tcIndxReq->indexSchemaVersion = tSchemaVersion;
+ tcKeyReq->apiConnectPtr = aTC_ConnectPtr;
+ tcKeyReq->senderData = ptr2int();
+ tcKeyReq->attrLen = tTotalCurrAI_Len;
+ tcKeyReq->tableId = tIndexId;
+ tcKeyReq->tableSchemaVersion = tSchemaVersion;
tTransId1 = (Uint32) aTransactionId;
tTransId2 = (Uint32) (aTransactionId >> 32);
@@ -564,59 +243,53 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
Uint8 tSimpleState = tReadInd & tSimpleAlt;
//theNdbCon->theSimpleState = tSimpleState;
- tcIndxReq->transId1 = tTransId1;
- tcIndxReq->transId2 = tTransId2;
+ tcKeyReq->transId1 = tTransId1;
+ tcKeyReq->transId2 = tTransId2;
tReqInfo = 0;
- if (tTotalCurrAI_Len <= TcIndxReq::MaxAttrInfo) {
- tcIndxReq->setAIInTcIndxReq(tReqInfo, tTotalCurrAI_Len);
+ if (tTotalCurrAI_Len <= TcKeyReq::MaxAttrInfo) {
+ tcKeyReq->setAIInTcKeyReq(tReqInfo, tTotalCurrAI_Len);
} else {
- tcIndxReq->setAIInTcIndxReq(tReqInfo, TcIndxReq::MaxAttrInfo);
+ tcKeyReq->setAIInTcKeyReq(tReqInfo, TcKeyReq::MaxAttrInfo);
}//if
- tcIndxReq->setSimpleFlag(tReqInfo, tSimpleIndicator);
- tcIndxReq->setCommitFlag(tReqInfo, tCommitIndicator);
- tcIndxReq->setStartFlag(tReqInfo, tStartIndicator);
+ tcKeyReq->setSimpleFlag(tReqInfo, tSimpleIndicator);
+ tcKeyReq->setCommitFlag(tReqInfo, tCommitIndicator);
+ tcKeyReq->setStartFlag(tReqInfo, tStartIndicator);
const Uint8 tInterpretIndicator = theInterpretIndicator;
- tcIndxReq->setInterpretedFlag(tReqInfo, tInterpretIndicator);
+ tcKeyReq->setInterpretedFlag(tReqInfo, tInterpretIndicator);
Uint8 tDirtyIndicator = theDirtyIndicator;
OperationType tOperationType = theOperationType;
- Uint32 tIndexLen = m_theIndexLen;
+ Uint32 tIndexLen = theTupKeyLen;
Uint8 abortOption = theNdbCon->m_abortOption;
- tcIndxReq->setDirtyFlag(tReqInfo, tDirtyIndicator);
- tcIndxReq->setOperationType(tReqInfo, tOperationType);
- tcIndxReq->setIndexLength(tReqInfo, tIndexLen);
- tcIndxReq->setCommitType(tReqInfo, abortOption);
+ tcKeyReq->setDirtyFlag(tReqInfo, tDirtyIndicator);
+ tcKeyReq->setOperationType(tReqInfo, tOperationType);
+ tcKeyReq->setKeyLength(tReqInfo, tIndexLen);
+ tcKeyReq->setAbortOption(tReqInfo, abortOption);
- Uint8 tDistrKeyIndicator = theDistrKeyIndicator;
- Uint8 tDistrGroupIndicator = theDistrGroupIndicator;
- Uint8 tDistrGroupType = theDistrGroupType;
+ Uint8 tDistrKeyIndicator = theDistrKeyIndicator_;
Uint8 tScanIndicator = theScanInfo & 1;
- tcIndxReq->setDistributionGroupFlag(tReqInfo, tDistrGroupIndicator);
- tcIndxReq->setDistributionGroupTypeFlag(tReqInfo, tDistrGroupType);
- tcIndxReq->setDistributionKeyFlag(tReqInfo, tDistrKeyIndicator);
- tcIndxReq->setScanIndFlag(tReqInfo, tScanIndicator);
+ tcKeyReq->setDistributionKeyFlag(tReqInfo, tDistrKeyIndicator);
+ tcKeyReq->setScanIndFlag(tReqInfo, tScanIndicator);
- tcIndxReq->requestInfo = tReqInfo;
+ tcKeyReq->requestInfo = tReqInfo;
//-------------------------------------------------------------
// The next step is to fill in the upto three conditional words.
//-------------------------------------------------------------
- Uint32* tOptionalDataPtr = &tcIndxReq->scanInfo;
+ Uint32* tOptionalDataPtr = &tcKeyReq->scanInfo;
Uint32 tDistrGHIndex = tScanIndicator;
- Uint32 tDistrKeyIndex = tDistrGHIndex + tDistrGroupIndicator;
+ Uint32 tDistrKeyIndex = tDistrGHIndex;
Uint32 tScanInfo = theScanInfo;
- Uint32 tDistributionGroup = theDistributionGroup;
- Uint32 tDistrKeySize = theDistrKeySize;
+ Uint32 tDistrKey = theDistributionKey;
tOptionalDataPtr[0] = tScanInfo;
- tOptionalDataPtr[tDistrGHIndex] = tDistributionGroup;
- tOptionalDataPtr[tDistrKeyIndex] = tDistrKeySize;
+ tOptionalDataPtr[tDistrKeyIndex] = tDistrKey;
//-------------------------------------------------------------
// The next is step is to compress the key data part of the
@@ -624,10 +297,10 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
//-------------------------------------------------------------
Uint32 tKeyIndex = tDistrKeyIndex + tDistrKeyIndicator;
Uint32* tKeyDataPtr = &tOptionalDataPtr[tKeyIndex];
- Uint32 Tdata1 = tcIndxReq->keyInfo[0];
- Uint32 Tdata2 = tcIndxReq->keyInfo[1];
- Uint32 Tdata3 = tcIndxReq->keyInfo[2];
- Uint32 Tdata4 = tcIndxReq->keyInfo[3];
+ Uint32 Tdata1 = tcKeyReq->keyInfo[0];
+ Uint32 Tdata2 = tcKeyReq->keyInfo[1];
+ Uint32 Tdata3 = tcKeyReq->keyInfo[2];
+ Uint32 Tdata4 = tcKeyReq->keyInfo[3];
Uint32 Tdata5;
tKeyDataPtr[0] = Tdata1;
@@ -635,10 +308,10 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
tKeyDataPtr[2] = Tdata3;
tKeyDataPtr[3] = Tdata4;
if (tIndexLen > 4) {
- Tdata1 = tcIndxReq->keyInfo[4];
- Tdata2 = tcIndxReq->keyInfo[5];
- Tdata3 = tcIndxReq->keyInfo[6];
- Tdata4 = tcIndxReq->keyInfo[7];
+ Tdata1 = tcKeyReq->keyInfo[4];
+ Tdata2 = tcKeyReq->keyInfo[5];
+ Tdata3 = tcKeyReq->keyInfo[6];
+ Tdata4 = tcKeyReq->keyInfo[7];
tKeyDataPtr[4] = Tdata1;
tKeyDataPtr[5] = Tdata2;
@@ -652,12 +325,12 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
//-------------------------------------------------------------
Uint32 tAttrInfoIndex;
- if (tIndexLen > TcIndxReq::MaxKeyInfo) {
+ if (tIndexLen > TcKeyReq::MaxKeyInfo) {
/**
* Set transid and TC connect ptr in the INDXKEYINFO signals
*/
- NdbApiSignal* tSignal = theFirstKEYINFO;
- Uint32 remainingKey = tIndexLen - TcIndxReq::MaxKeyInfo;
+ NdbApiSignal* tSignal = theTCREQ->next();
+ Uint32 remainingKey = tIndexLen - TcKeyReq::MaxKeyInfo;
do {
Uint32* tSigDataPtr = tSignal->getDataPtrSend();
@@ -678,7 +351,7 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
}
tSignal = tnextSignal;
} while (tSignal != NULL);
- tAttrInfoIndex = tKeyIndex + TcIndxReq::MaxKeyInfo;
+ tAttrInfoIndex = tKeyIndex + TcKeyReq::MaxKeyInfo;
} else {
tAttrInfoIndex = tKeyIndex + tIndexLen;
}//if
@@ -688,14 +361,14 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
// above.
//-------------------------------------------------------------
Uint32* tAIDataPtr = &tOptionalDataPtr[tAttrInfoIndex];
- Tdata1 = tcIndxReq->attrInfo[0];
- Tdata2 = tcIndxReq->attrInfo[1];
- Tdata3 = tcIndxReq->attrInfo[2];
- Tdata4 = tcIndxReq->attrInfo[3];
- Tdata5 = tcIndxReq->attrInfo[4];
-
- theTCREQ->setLength(tcIndxReq->getAIInTcIndxReq(tReqInfo) +
- tAttrInfoIndex + TcIndxReq::StaticLength);
+ Tdata1 = tcKeyReq->attrInfo[0];
+ Tdata2 = tcKeyReq->attrInfo[1];
+ Tdata3 = tcKeyReq->attrInfo[2];
+ Tdata4 = tcKeyReq->attrInfo[3];
+ Tdata5 = tcKeyReq->attrInfo[4];
+
+ theTCREQ->setLength(tcKeyReq->getAIInTcKeyReq(tReqInfo) +
+ tAttrInfoIndex + TcKeyReq::StaticLength);
tAIDataPtr[0] = Tdata1;
tAIDataPtr[1] = Tdata2;
tAIDataPtr[2] = Tdata3;
@@ -724,11 +397,6 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId)
return 0;
}
-void NdbIndexOperation::closeScan()
-{
- printf("NdbIndexOperation::closeScan NYI\n");
-}
-
/***************************************************************************
int receiveTCINDXREF( NdbApiSignal* aSignal)
@@ -740,17 +408,5 @@ Remark: Handles the reception of the TCKEYREF signal.
int
NdbIndexOperation::receiveTCINDXREF( NdbApiSignal* aSignal)
{
- const TcIndxRef * const tcIndxRef = CAST_CONSTPTR(TcIndxRef, aSignal->getDataPtr());
-
- if (checkState_TransId(aSignal) == -1) {
- return -1;
- }//if
-
- theStatus = Finished;
-
- theNdbCon->theReturnStatus = NdbConnection::ReturnFailure;
- Uint32 errorCode = tcIndxRef->errorCode;
- theError.code = errorCode;
- theNdbCon->setOperationErrorCodeAbort(errorCode);
- return theNdbCon->OpCompleteFailure(theNdbCon->m_abortOption);
+ return receiveTCKEYREF(aSignal);
}//NdbIndexOperation::receiveTCINDXREF()
diff --git a/ndb/src/ndbapi/NdbOperation.cpp b/ndb/src/ndbapi/NdbOperation.cpp
index 88d8a000d50..c9143444908 100644
--- a/ndb/src/ndbapi/NdbOperation.cpp
+++ b/ndb/src/ndbapi/NdbOperation.cpp
@@ -15,7 +15,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <ndb_global.h>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <NdbOperation.hpp>
#include "NdbApiSignal.hpp"
#include "NdbRecAttr.hpp"
@@ -49,7 +49,6 @@ NdbOperation::NdbOperation(Ndb* aNdb) :
theCurrentATTRINFO(NULL),
theTotalCurrAI_Len(0),
theAI_LenInCurrAI(0),
- theFirstKEYINFO(NULL),
theLastKEYINFO(NULL),
theFirstLabel(NULL),
@@ -68,13 +67,11 @@ NdbOperation::NdbOperation(Ndb* aNdb) :
//theSchemaVersion(0),
theTotalNrOfKeyWordInSignal(8),
theTupKeyLen(0),
- theNoOfTupKeyDefined(0),
+ theNoOfTupKeyLeft(0),
theOperationType(NotDefined),
theStatus(Init),
theMagicNumber(0xFE11D0),
theScanInfo(0),
- theDistrKeySize(0),
- theDistributionGroup(0),
m_tcReqGSN(GSN_TCKEYREQ),
m_keyInfoGSN(GSN_KEYINFO),
m_attrInfoGSN(GSN_ATTRINFO),
@@ -131,7 +128,7 @@ NdbOperation::setErrorCodeAbort(int anErrorCode)
*****************************************************************************/
int
-NdbOperation::init(const NdbTableImpl* tab, NdbConnection* myConnection){
+NdbOperation::init(const NdbTableImpl* tab, NdbTransaction* myConnection){
NdbApiSignal* tSignal;
theStatus = Init;
theError.code = 0;
@@ -145,14 +142,11 @@ NdbOperation::init(const NdbTableImpl* tab, NdbConnection* myConnection){
theFirstATTRINFO = NULL;
theCurrentATTRINFO = NULL;
- theFirstKEYINFO = NULL;
theLastKEYINFO = NULL;
- theTupKeyLen = 0;
- theNoOfTupKeyDefined = 0;
- theDistrKeySize = 0;
- theDistributionGroup = 0;
+ theTupKeyLen = 0;
+ theNoOfTupKeyLeft = tab->getNoOfPrimaryKeys();
theTotalCurrAI_Len = 0;
theAI_LenInCurrAI = 0;
@@ -161,9 +155,7 @@ NdbOperation::init(const NdbTableImpl* tab, NdbConnection* myConnection){
theSimpleIndicator = 0;
theDirtyIndicator = 0;
theInterpretIndicator = 0;
- theDistrGroupIndicator= 0;
- theDistrGroupType = 0;
- theDistrKeyIndicator = 0;
+ theDistrKeyIndicator_ = 0;
theScanInfo = 0;
theTotalNrOfKeyWordInSignal = 8;
theMagicNumber = 0xABCDEF01;
@@ -210,11 +202,16 @@ NdbOperation::release()
NdbBlob* tBlob;
NdbBlob* tSaveBlob;
- if (theTCREQ != NULL)
+ tSignal = theTCREQ;
+ while (tSignal != NULL)
{
- theNdb->releaseSignal(theTCREQ);
- }
+ tSaveSignal = tSignal;
+ tSignal = tSignal->next();
+ theNdb->releaseSignal(tSaveSignal);
+ }
theTCREQ = NULL;
+ theLastKEYINFO = NULL;
+
tSignal = theFirstATTRINFO;
while (tSignal != NULL)
{
@@ -224,15 +221,7 @@ NdbOperation::release()
}
theFirstATTRINFO = NULL;
theCurrentATTRINFO = NULL;
- tSignal = theFirstKEYINFO;
- while (tSignal != NULL)
- {
- tSaveSignal = tSignal;
- tSignal = tSignal->next();
- theNdb->releaseSignal(tSaveSignal);
- }
- theFirstKEYINFO = NULL;
- theLastKEYINFO = NULL;
+
if (theInterpretIndicator == 1)
{
tBranch = theFirstBranch;
@@ -403,3 +392,9 @@ NdbOperation::getTableName() const
{
return m_currentTable->m_externalName.c_str();
}
+
+const NdbDictionary::Table*
+NdbOperation::getTable() const
+{
+ return m_currentTable;
+}
diff --git a/ndb/src/ndbapi/NdbOperationDefine.cpp b/ndb/src/ndbapi/NdbOperationDefine.cpp
index dfc54133e6c..835e33dfb40 100644
--- a/ndb/src/ndbapi/NdbOperationDefine.cpp
+++ b/ndb/src/ndbapi/NdbOperationDefine.cpp
@@ -14,28 +14,17 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*****************************************************************************
- * Name: NdbOperationDefine.C
- * Include:
- * Link:
- * Author: UABMNST Mona Natterkvist UAB/B/SD
- * Date: 970829
- * Version: 0.1
- * Description: Interface between TIS and NDB
- * Documentation:
- * Adjust: 971022 UABMNST First version.
- *****************************************************************************/
-#include "NdbOperation.hpp"
+#include <ndb_global.h>
+#include <NdbOperation.hpp>
#include "NdbApiSignal.hpp"
-#include "NdbConnection.hpp"
-#include "Ndb.hpp"
-#include "NdbRecAttr.hpp"
+#include <NdbTransaction.hpp>
+#include <Ndb.hpp>
+#include <NdbRecAttr.hpp>
#include "NdbUtil.hpp"
#include "NdbOut.hpp"
#include "NdbImpl.hpp"
#include <NdbIndexScanOperation.hpp>
-#include "NdbBlob.hpp"
+#include <NdbBlob.hpp>
#include <Interpreter.hpp>
@@ -48,7 +37,7 @@
int
NdbOperation::insertTuple()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -68,7 +57,7 @@ NdbOperation::insertTuple()
int
NdbOperation::updateTuple()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -88,7 +77,7 @@ NdbOperation::updateTuple()
int
NdbOperation::writeTuple()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -128,7 +117,7 @@ NdbOperation::readTuple(NdbOperation::LockMode lm)
int
NdbOperation::readTuple()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -149,7 +138,7 @@ NdbOperation::readTuple()
int
NdbOperation::deleteTuple()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -170,7 +159,7 @@ NdbOperation::deleteTuple()
int
NdbOperation::readTupleExclusive()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -247,7 +236,7 @@ NdbOperation::committedRead()
int
NdbOperation::dirtyUpdate()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -270,7 +259,7 @@ NdbOperation::dirtyUpdate()
int
NdbOperation::dirtyWrite()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -293,7 +282,7 @@ NdbOperation::dirtyWrite()
int
NdbOperation::interpretedUpdateTuple()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -316,7 +305,7 @@ NdbOperation::interpretedUpdateTuple()
int
NdbOperation::interpretedDeleteTuple()
{
- NdbConnection* tNdbCon = theNdbCon;
+ NdbTransaction* tNdbCon = theNdbCon;
int tErrorLine = theErrorLine;
if (theStatus == Init) {
theStatus = OperationDefined;
@@ -350,7 +339,6 @@ NdbOperation::getValue_impl(const NdbColumnImpl* tAttrInfo, char* aValue)
{
NdbRecAttr* tRecAttr;
if ((tAttrInfo != NULL) &&
- (!tAttrInfo->m_indexOnly) &&
(theStatus != Init)){
if (theStatus != GetValue) {
if (theInterpretIndicator == 1) {
@@ -398,10 +386,6 @@ NdbOperation::getValue_impl(const NdbColumnImpl* tAttrInfo, char* aValue)
setErrorCodeAbort(4004);
return NULL;
}//if
- if (tAttrInfo->m_indexOnly){
- setErrorCodeAbort(4208);
- return NULL;
- }//if
}//if
setErrorCodeAbort(4200);
return NULL;
@@ -422,6 +406,14 @@ int
NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
const char* aValuePassed, Uint32 len)
{
+ DBUG_ENTER("NdbOperation::setValue");
+ DBUG_PRINT("enter", ("col=%s op=%d val=0x%x len=%u",
+ tAttrInfo->m_name.c_str(),
+ theOperationType,
+ aValuePassed, len));
+ if (aValuePassed != NULL)
+ DBUG_DUMP("value", (char*)aValuePassed, len);
+
int tReturnCode;
Uint32 tAttrId;
Uint32 tData;
@@ -437,7 +429,7 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
;
} else {
setErrorCodeAbort(4234);
- return -1;
+ DBUG_RETURN(-1);
}//if
} else {
if (tStatus == GetValue) {
@@ -448,7 +440,7 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
// to set values in the tuple by setValue.
//--------------------------------------------------------------------
if (insertATTRINFO(Interpreter::EXIT_OK) == -1){
- return -1;
+ DBUG_RETURN(-1);
}
theInterpretedSize = theTotalCurrAI_Len -
(theInitialReadSize + 5);
@@ -459,47 +451,47 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
// setValue used in the wrong context. Application coding error.
//-------------------------------------------------------------------
setErrorCodeAbort(4234); //Wrong error code
- return -1;
+ DBUG_RETURN(-1);
}//if
theStatus = SetValueInterpreted;
}//if
} else if (tOpType == InsertRequest) {
if ((theStatus != SetValue) && (theStatus != OperationDefined)) {
setErrorCodeAbort(4234);
- return -1;
+ DBUG_RETURN(-1);
}//if
} else if (tOpType == ReadRequest || tOpType == ReadExclusive) {
setErrorCodeAbort(4504);
- return -1;
+ DBUG_RETURN(-1);
} else if (tOpType == DeleteRequest) {
setErrorCodeAbort(4504);
- return -1;
+ DBUG_RETURN(-1);
} else if (tOpType == OpenScanRequest || tOpType == OpenRangeScanRequest) {
setErrorCodeAbort(4228);
- return -1;
+ DBUG_RETURN(-1);
} else {
//---------------------------------------------------------------------
// setValue with undefined operation type.
// Probably application coding error.
//---------------------------------------------------------------------
setErrorCodeAbort(4108);
- return -1;
+ DBUG_RETURN(-1);
}//if
if (tAttrInfo == NULL) {
setErrorCodeAbort(4004);
- return -1;
+ DBUG_RETURN(-1);
}//if
if (tAttrInfo->m_pk) {
if (theOperationType == InsertRequest) {
- return equal_impl(tAttrInfo, aValuePassed, len);
+ DBUG_RETURN(equal_impl(tAttrInfo, aValuePassed, len));
} else {
setErrorCodeAbort(4202);
- return -1;
+ DBUG_RETURN(-1);
}//if
}//if
if (len > 8000) {
setErrorCodeAbort(4216);
- return -1;
+ DBUG_RETURN(-1);
}//if
tAttrId = tAttrInfo->m_attrId;
@@ -512,33 +504,19 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
insertATTRINFO(ahValue);
// Insert Attribute Id with the value
// NULL into ATTRINFO part.
- return 0;
+ DBUG_RETURN(0);
} else {
/***********************************************************************
* Setting a NULL value on a NOT NULL attribute is not allowed.
**********************************************************************/
setErrorCodeAbort(4203);
- return -1;
+ DBUG_RETURN(-1);
}//if
}//if
// Insert Attribute Id into ATTRINFO part.
const Uint32 sizeInBytes = tAttrInfo->m_attrSize * tAttrInfo->m_arraySize;
- CHARSET_INFO* cs = tAttrInfo->m_cs;
- int dummy_error;
- // invalid data can crash kernel
- if (cs != NULL &&
- // fast fix bug#7340
- tAttrInfo->m_type != NdbDictionary::Column::Text &&
- (*cs->cset->well_formed_len)(cs,
- aValue,
- aValue + sizeInBytes,
- sizeInBytes,
- &dummy_error) != sizeInBytes) {
- setErrorCodeAbort(744);
- return -1;
- }
#if 0
tAttrSize = tAttrInfo->theAttrSize;
tArraySize = tAttrInfo->theArraySize;
@@ -552,7 +530,7 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
const Uint32 bitsInLastWord = 8 * (sizeInBytes & 3) ;
if (len != sizeInBytes && (len != 0)) {
setErrorCodeAbort(4209);
- return -1;
+ DBUG_RETURN(-1);
}//if
const Uint32 totalSizeInWords = (sizeInBytes + 3)/4; // Including bits in last word
const Uint32 sizeInWords = sizeInBytes / 4; // Excluding bits in last word
@@ -580,7 +558,7 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
tReturnCode = insertATTRINFOloop((Uint32*)aValue, sizeInWords);
if (tReturnCode == -1) {
- return tReturnCode;
+ DBUG_RETURN(tReturnCode);
}//if
if (bitsInLastWord != 0) {
tData = *(Uint32*)(aValue + sizeInWords*4);
@@ -589,15 +567,15 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo,
tData = convertEndian(tData);
tReturnCode = insertATTRINFO(tData);
if (tReturnCode == -1) {
- return tReturnCode;
+ DBUG_RETURN(tReturnCode);
}//if
}//if
theErrorLine++;
- return 0;
+ DBUG_RETURN(0);
}//NdbOperation::setValue()
NdbBlob*
-NdbOperation::getBlobHandle(NdbConnection* aCon, const NdbColumnImpl* tAttrInfo)
+NdbOperation::getBlobHandle(NdbTransaction* aCon, const NdbColumnImpl* tAttrInfo)
{
NdbBlob* tBlob = theBlobList;
NdbBlob* tLastBlob = NULL;
diff --git a/ndb/src/ndbapi/NdbOperationExec.cpp b/ndb/src/ndbapi/NdbOperationExec.cpp
index afa3609e11c..4200300615d 100644
--- a/ndb/src/ndbapi/NdbOperationExec.cpp
+++ b/ndb/src/ndbapi/NdbOperationExec.cpp
@@ -16,7 +16,7 @@
#include <ndb_global.h>
#include <NdbOperation.hpp>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include "NdbApiSignal.hpp"
#include <Ndb.hpp>
#include <NdbRecAttr.hpp>
@@ -65,7 +65,7 @@ NdbOperation::doSend(int aNodeId, Uint32 lastFlag)
if (tReturnCode == -1) {
return -1;
}
- NdbApiSignal *tSignal = theFirstKEYINFO;
+ NdbApiSignal *tSignal = theTCREQ->next();
while (tSignal != NULL) {
NdbApiSignal* tnextSignal = tSignal->next();
tReturnCode = tp->sendSignal(tSignal, aNodeId);
@@ -202,13 +202,9 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransId)
abortOption = tSimpleIndicator ? AO_IgnoreError : abortOption;
tcKeyReq->setAbortOption(tReqInfo, abortOption);
- Uint8 tDistrKeyIndicator = theDistrKeyIndicator;
- Uint8 tDistrGroupIndicator = theDistrGroupIndicator;
- Uint8 tDistrGroupType = theDistrGroupType;
+ Uint8 tDistrKeyIndicator = theDistrKeyIndicator_;
Uint8 tScanIndicator = theScanInfo & 1;
- tcKeyReq->setDistributionGroupFlag(tReqInfo, tDistrGroupIndicator);
- tcKeyReq->setDistributionGroupTypeFlag(tReqInfo, tDistrGroupType);
tcKeyReq->setDistributionKeyFlag(tReqInfo, tDistrKeyIndicator);
tcKeyReq->setScanIndFlag(tReqInfo, tScanIndicator);
@@ -219,15 +215,13 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransId)
//-------------------------------------------------------------
Uint32* tOptionalDataPtr = &tcKeyReq->scanInfo;
Uint32 tDistrGHIndex = tScanIndicator;
- Uint32 tDistrKeyIndex = tDistrGHIndex + tDistrGroupIndicator;
+ Uint32 tDistrKeyIndex = tDistrGHIndex;
Uint32 tScanInfo = theScanInfo;
- Uint32 tDistributionGroup = theDistributionGroup;
- Uint32 tDistrKeySize = theDistrKeySize;
+ Uint32 tDistrKey = theDistributionKey;
tOptionalDataPtr[0] = tScanInfo;
- tOptionalDataPtr[tDistrGHIndex] = tDistributionGroup;
- tOptionalDataPtr[tDistrKeyIndex] = tDistrKeySize;
+ tOptionalDataPtr[tDistrKeyIndex] = tDistrKey;
//-------------------------------------------------------------
// The next is step is to compress the key data part of the
@@ -267,7 +261,7 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransId)
/**
* Set transid, TC connect ptr and length in the KEYINFO signals
*/
- NdbApiSignal* tSignal = theFirstKEYINFO;
+ NdbApiSignal* tSignal = theTCREQ->next();
Uint32 remainingKey = tTupKeyLen - TcKeyReq::MaxKeyInfo;
do {
Uint32* tSigDataPtr = tSignal->getDataPtrSend();
@@ -549,10 +543,11 @@ NdbOperation::receiveTCKEYREF( NdbApiSignal* aSignal)
theStatus = Finished;
// blobs want this
if (m_abortOption != AO_IgnoreError)
- theNdbCon->theReturnStatus = NdbConnection::ReturnFailure;
-
+ {
+ theNdbCon->theReturnStatus = NdbTransaction::ReturnFailure;
+ }
theError.code = aSignal->readData(4);
- theNdbCon->setOperationErrorCodeAbort(aSignal->readData(4), m_abortOption);
+ theNdbCon->setOperationErrorCodeAbort(aSignal->readData(4), ao);
if(theOperationType != ReadRequest || !theSimpleIndicator) // not simple read
return theNdbCon->OpCompleteFailure(ao, m_abortOption != AO_IgnoreError);
diff --git a/ndb/src/ndbapi/NdbOperationInt.cpp b/ndb/src/ndbapi/NdbOperationInt.cpp
index ace90e35ca4..41e0cb1d140 100644
--- a/ndb/src/ndbapi/NdbOperationInt.cpp
+++ b/ndb/src/ndbapi/NdbOperationInt.cpp
@@ -14,13 +14,12 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
#include <ndb_global.h>
#include <NdbOperation.hpp>
#include "NdbApiSignal.hpp"
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <Ndb.hpp>
-#include "NdbRecAttr.hpp"
+#include <NdbRecAttr.hpp>
#include "NdbUtil.hpp"
#include "Interpreter.hpp"
#include <NdbIndexScanOperation.hpp>
@@ -84,7 +83,7 @@ NdbOperation::incCheck(const NdbColumnImpl* tNdbColumnImpl)
}
return tNdbColumnImpl->m_attrId;
} else {
- if (theNdbCon->theCommitStatus == NdbConnection::Started)
+ if (theNdbCon->theCommitStatus == NdbTransaction::Started)
setErrorCodeAbort(4200);
}
return -1;
@@ -136,7 +135,7 @@ NdbOperation::write_attrCheck(const NdbColumnImpl* tNdbColumnImpl)
}
return tNdbColumnImpl->m_attrId;
} else {
- if (theNdbCon->theCommitStatus == NdbConnection::Started)
+ if (theNdbCon->theCommitStatus == NdbTransaction::Started)
setErrorCodeAbort(4200);
}
return -1;
@@ -184,7 +183,7 @@ NdbOperation::read_attrCheck(const NdbColumnImpl* tNdbColumnImpl)
}
return tNdbColumnImpl->m_attrId;
} else {
- if (theNdbCon->theCommitStatus == NdbConnection::Started)
+ if (theNdbCon->theCommitStatus == NdbTransaction::Started)
setErrorCodeAbort(4200);
}
return -1;
@@ -220,7 +219,7 @@ NdbOperation::initial_interpreterCheck()
}
return 0;
} else {
- if (theNdbCon->theCommitStatus == NdbConnection::Started)
+ if (theNdbCon->theCommitStatus == NdbTransaction::Started)
setErrorCodeAbort(4200);
}
return -1;
@@ -246,7 +245,7 @@ NdbOperation::labelCheck()
}
return 0;
} else {
- if (theNdbCon->theCommitStatus == NdbConnection::Started)
+ if (theNdbCon->theCommitStatus == NdbTransaction::Started)
setErrorCodeAbort(4200);
}
return -1;
@@ -266,7 +265,7 @@ NdbOperation::intermediate_interpreterCheck()
}
return 0;
} else {
- if (theNdbCon->theCommitStatus == NdbConnection::Started)
+ if (theNdbCon->theCommitStatus == NdbTransaction::Started)
setErrorCodeAbort(4200);
}
return -1;
@@ -1012,33 +1011,56 @@ NdbOperation::insertCall(Uint32 aCall)
int
NdbOperation::branch_col(Uint32 type,
- Uint32 ColId, const char * val, Uint32 len,
+ Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label){
+ DBUG_ENTER("NdbOperation::branch_col");
+ DBUG_PRINT("enter", ("type=%u col=%u val=0x%x len=%u label=%u",
+ type, ColId, val, len, Label));
+ if (val != NULL)
+ DBUG_DUMP("value", (char*)val, len);
+
if (initial_interpreterCheck() == -1)
- return -1;
+ DBUG_RETURN(-1);
Interpreter::BinaryCondition c = (Interpreter::BinaryCondition)type;
-
- const NdbDictionary::Column * col =
+
+ const NdbColumnImpl * col =
m_currentTable->getColumn(ColId);
if(col == 0){
abort();
}
- Uint32 vc = col->getType() == NdbDictionary::Column::Varchar;
- Uint32 colLen = col->getLength() + 2 * vc;
- Uint32 al = (4 - (colLen & 3)) & 0x3;
-
- if (insertATTRINFO(Interpreter::BranchCol(c, al, vc, nopad)) == -1)
- return -1;
+ if (val == NULL)
+ len = 0;
+ else {
+ if (! col->getStringType()) {
+ // prevent assert in NdbSqlUtil on length error
+ Uint32 sizeInBytes = col->m_attrSize * col->m_arraySize;
+ if (len != 0 && len != sizeInBytes)
+ {
+ setErrorCodeAbort(4209);
+ DBUG_RETURN(-1);
+ }
+ len = sizeInBytes;
+ }
+ }
+
+ Uint32 tempData[2000];
+ if (((UintPtr)val & 3) != 0) {
+ memcpy(tempData, val, len);
+ val = tempData;
+ }
+
+ if (insertATTRINFO(Interpreter::BranchCol(c, 0, 0, false)) == -1)
+ DBUG_RETURN(-1);
if (insertBranch(Label) == -1)
- return -1;
+ DBUG_RETURN(-1);
if (insertATTRINFO(Interpreter::BranchCol_2(ColId, len)))
- return -1;
+ DBUG_RETURN(-1);
Uint32 len2 = Interpreter::mod4(len);
if(len2 == len){
@@ -1049,64 +1071,64 @@ NdbOperation::branch_col(Uint32 type,
Uint32 tmp = 0;
for (Uint32 i = 0; i < len-len2; i++) {
char* p = (char*)&tmp;
- p[i] = val[len2+i];
+ p[i] = ((char*)val)[len2+i];
}
insertATTRINFO(tmp);
}
theErrorLine++;
- return 0;
+ DBUG_RETURN(0);
}
int
-NdbOperation::branch_col_eq(Uint32 ColId, const char * val, Uint32 len,
+NdbOperation::branch_col_eq(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label){
INT_DEBUG(("branch_col_eq %u %.*s(%u,%d) -> %u", ColId, len, val, len, nopad, Label));
return branch_col(Interpreter::EQ, ColId, val, len, nopad, Label);
}
int
-NdbOperation::branch_col_ne(Uint32 ColId, const char * val, Uint32 len,
+NdbOperation::branch_col_ne(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label){
INT_DEBUG(("branch_col_ne %u %.*s(%u,%d) -> %u", ColId, len, val, len, nopad, Label));
return branch_col(Interpreter::NE, ColId, val, len, nopad, Label);
}
int
-NdbOperation::branch_col_lt(Uint32 ColId, const char * val, Uint32 len,
+NdbOperation::branch_col_lt(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label){
INT_DEBUG(("branch_col_lt %u %.*s(%u,%d) -> %u", ColId, len, val, len, nopad, Label));
return branch_col(Interpreter::LT, ColId, val, len, nopad, Label);
}
int
-NdbOperation::branch_col_le(Uint32 ColId, const char * val, Uint32 len,
+NdbOperation::branch_col_le(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label){
INT_DEBUG(("branch_col_le %u %.*s(%u,%d) -> %u", ColId, len, val, len, nopad, Label));
return branch_col(Interpreter::LE, ColId, val, len, nopad, Label);
}
int
-NdbOperation::branch_col_gt(Uint32 ColId, const char * val, Uint32 len,
+NdbOperation::branch_col_gt(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label){
INT_DEBUG(("branch_col_gt %u %.*s(%u,%d) -> %u", ColId, len, val, len, nopad, Label));
return branch_col(Interpreter::GT, ColId, val, len, nopad, Label);
}
int
-NdbOperation::branch_col_ge(Uint32 ColId, const char * val, Uint32 len,
+NdbOperation::branch_col_ge(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label){
INT_DEBUG(("branch_col_ge %u %.*s(%u,%d) -> %u", ColId, len, val, len, nopad, Label));
return branch_col(Interpreter::GE, ColId, val, len, nopad, Label);
}
int
-NdbOperation::branch_col_like(Uint32 ColId, const char * val, Uint32 len,
+NdbOperation::branch_col_like(Uint32 ColId, const void * val, Uint32 len,
bool nopad, Uint32 Label){
INT_DEBUG(("branch_col_like %u %.*s(%u,%d) -> %u", ColId, len, val, len, nopad, Label));
return branch_col(Interpreter::LIKE, ColId, val, len, nopad, Label);
}
int
-NdbOperation::branch_col_notlike(Uint32 ColId, const char * val, Uint32 len,
- bool nopad, Uint32 Label){
+NdbOperation::branch_col_notlike(Uint32 ColId, const void * val, Uint32 len,
+ bool nopad, Uint32 Label){
INT_DEBUG(("branch_col_notlike %u %.*s(%u,%d) -> %u", ColId,len,val,len,nopad,Label));
return branch_col(Interpreter::NOT_LIKE, ColId, val, len, nopad, Label);
}
diff --git a/ndb/src/ndbapi/NdbOperationSearch.cpp b/ndb/src/ndbapi/NdbOperationSearch.cpp
index 97b2393e5ed..06d8ddd412b 100644
--- a/ndb/src/ndbapi/NdbOperationSearch.cpp
+++ b/ndb/src/ndbapi/NdbOperationSearch.cpp
@@ -31,14 +31,16 @@ Adjust: 971022 UABMNST First version.
#include <NdbOperation.hpp>
#include "NdbApiSignal.hpp"
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <Ndb.hpp>
#include "NdbImpl.hpp"
#include <NdbOut.hpp>
#include <AttributeHeader.hpp>
#include <signaldata/TcKeyReq.hpp>
+#include <signaldata/KeyInfo.hpp>
#include "NdbDictionaryImpl.hpp"
+#include <md5_hash.hpp>
/******************************************************************************
CondIdType equal(const char* anAttrName, char* aValue, Uint32 aVarKeylen);
@@ -55,13 +57,20 @@ NdbOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
const char* aValuePassed,
Uint32 aVariableKeyLen)
{
- register Uint32 tAttrId;
+ DBUG_ENTER("NdbOperation::equal_impl");
+ DBUG_PRINT("enter", ("col=%s op=%d val=0x%x len=%u",
+ tAttrInfo->m_name.c_str(),
+ theOperationType,
+ aValuePassed, aVariableKeyLen));
+ if (aValuePassed != NULL)
+ DBUG_DUMP("value", (char*)aValuePassed, aVariableKeyLen);
+ register Uint32 tAttrId;
+
Uint32 tData;
Uint32 tKeyInfoPosition;
const char* aValue = aValuePassed;
- Uint32 xfrmData[1024];
- Uint32 tempData[1024];
+ Uint64 tempData[512];
if ((theStatus == OperationDefined) &&
(aValue != NULL) &&
@@ -76,6 +85,8 @@ NdbOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
*****************************************************************************/
tAttrId = tAttrInfo->m_attrId;
tKeyInfoPosition = tAttrInfo->m_keyInfoPos;
+ bool tDistrKey = tAttrInfo->m_distributionKey;
+
Uint32 i = 0;
if (tAttrInfo->m_pk) {
Uint32 tKeyDefined = theTupleKeyDefined[0][2];
@@ -117,44 +128,29 @@ NdbOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
theTupleKeyDefined[i][1] = tKeyInfoPosition;
theTupleKeyDefined[i][2] = true;
+ OperationType tOpType = theOperationType;
Uint32 sizeInBytes = tAttrInfo->m_attrSize * tAttrInfo->m_arraySize;
+
{
- /***************************************************************************
- * Check if the pointer of the value passed is aligned on a 4 byte
- * boundary. If so only assign the pointer to the internal variable
- * aValue. If it is not aligned then we start by copying the value to
- * tempData and use this as aValue instead.
- *****************************************************************************/
+ /************************************************************************
+ * Check if the pointer of the value passed is aligned on a 4 byte
+ * boundary. If so only assign the pointer to the internal variable
+ * aValue. If it is not aligned then we start by copying the value to
+ * tempData and use this as aValue instead.
+ ***********************************************************************/
const int attributeSize = sizeInBytes;
const int slack = sizeInBytes & 3;
-
- if ((((UintPtr)aValue & 3) != 0) || (slack != 0)){
+ const int align = UintPtr(aValue) & 7;
+
+ if (((align & 3) != 0) || (slack != 0) || (tDistrKey && (align != 0)))
+ {
+ ((Uint32*)tempData)[attributeSize >> 2] = 0;
memcpy(&tempData[0], aValue, attributeSize);
aValue = (char*)&tempData[0];
- if(slack != 0) {
- char * tmp = (char*)&tempData[0];
- memset(&tmp[attributeSize], 0, (4 - slack));
- }//if
}//if
}
- const char* aValueToWrite = aValue;
-
- CHARSET_INFO* cs = tAttrInfo->m_cs;
- if (cs != 0) {
- // current limitation: strxfrm does not increase length
- assert(cs->strxfrm_multiply <= 1);
- unsigned n =
- (*cs->coll->strnxfrm)(cs,
- (uchar*)xfrmData, sizeof(xfrmData),
- (const uchar*)aValue, sizeInBytes);
- while (n < sizeInBytes)
- ((uchar*)xfrmData)[n++] = 0x20;
- aValue = (char*)xfrmData;
- }
- Uint32 bitsInLastWord = 8 * (sizeInBytes & 3) ;
Uint32 totalSizeInWords = (sizeInBytes + 3)/4; // Inc. bits in last word
- Uint32 sizeInWords = sizeInBytes / 4; // Exc. bits in last word
if (true){ //tArraySize != 0) {
Uint32 tTupKeyLen = theTupKeyLen;
@@ -190,93 +186,58 @@ NdbOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
}//if
#endif
- int tDistrKey = tAttrInfo->m_distributionKey;
- int tDistrGroup = tAttrInfo->m_distributionGroup;
- OperationType tOpType = theOperationType;
- if ((tDistrKey != 1) && (tDistrGroup != 1)) {
- ;
- } else if (tDistrKey == 1) {
- theDistrKeySize += totalSizeInWords;
- theDistrKeyIndicator = 1;
- } else {
- Uint32 TsizeInBytes = sizeInBytes;
- Uint32 TbyteOrderFix = 0;
- char* TcharByteOrderFix = (char*)&TbyteOrderFix;
- if (tAttrInfo->m_distributionGroupBits == 8) {
- char tFirstChar = aValue[TsizeInBytes - 2];
- char tSecondChar = aValue[TsizeInBytes - 2];
- TcharByteOrderFix[0] = tFirstChar;
- TcharByteOrderFix[1] = tSecondChar;
- TcharByteOrderFix[2] = 0x30;
- TcharByteOrderFix[3] = 0x30;
- theDistrGroupType = 0;
- } else {
- TbyteOrderFix = ((aValue[TsizeInBytes - 2] - 0x30) * 10)
- + (aValue[TsizeInBytes - 1] - 0x30);
- theDistrGroupType = 1;
- }//if
- theDistributionGroup = TbyteOrderFix;
- theDistrGroupIndicator = 1;
- }//if
- /******************************************************************************
+ /**************************************************************************
* If the operation is an insert request and the attribute is stored then
* we also set the value in the stored part through putting the
* information in the ATTRINFO signals.
- *****************************************************************************/
+ *************************************************************************/
if ((tOpType == InsertRequest) ||
(tOpType == WriteRequest)) {
- if (!tAttrInfo->m_indexOnly){
- int dummy_error;
- // invalid data can crash kernel
- if (cs != NULL &&
- (*cs->cset->well_formed_len)(cs,
- aValueToWrite,
- aValueToWrite + sizeInBytes,
- sizeInBytes,
- &dummy_error) != sizeInBytes)
- goto equal_error4;
- Uint32 ahValue;
- const Uint32 sz = totalSizeInWords;
+ Uint32 ahValue;
+ const Uint32 sz = totalSizeInWords;
+
+ // XXX
+ if(m_accessTable == m_currentTable)
+ {
AttributeHeader::init(&ahValue, tAttrId, sz);
- insertATTRINFO( ahValue );
- insertATTRINFOloop((Uint32*)aValueToWrite, sizeInWords);
- if (bitsInLastWord != 0) {
- tData = *(Uint32*)(aValueToWrite + (sizeInWords << 2));
- tData = convertEndian(tData);
- tData = tData & ((1 << bitsInLastWord) - 1);
- tData = convertEndian(tData);
- insertATTRINFO( tData );
- }//if
- }//if
+ }
+ else
+ {
+ assert(m_accessTable->m_index);
+ int attr_id_current_table =
+ m_accessTable->m_index->m_columns[tAttrId]->m_keyInfoPos;
+ AttributeHeader::init(&ahValue, attr_id_current_table, sz);
+ }
+
+ insertATTRINFO( ahValue );
+ insertATTRINFOloop((Uint32*)aValue, sz);
}//if
- /***************************************************************************
+ /**************************************************************************
* Store the Key information in the TCKEYREQ and KEYINFO signals.
- **************************************************************************/
- if (insertKEYINFO(aValue, tKeyInfoPosition,
- totalSizeInWords, bitsInLastWord) != -1) {
- /*************************************************************************
+ *************************************************************************/
+ if (insertKEYINFO(aValue, tKeyInfoPosition, totalSizeInWords) != -1) {
+ /************************************************************************
* Add one to number of tuple key attributes defined.
* If all have been defined then set the operation state to indicate
* that tuple key is defined.
* Thereby no more search conditions are allowed in this version.
- ************************************************************************/
- Uint32 tNoKeysDef = theNoOfTupKeyDefined;
+ ***********************************************************************/
+ Uint32 tNoKeysDef = theNoOfTupKeyLeft - 1;
Uint32 tErrorLine = theErrorLine;
- int tNoTableKeys = m_currentTable->m_noOfKeys;
unsigned char tInterpretInd = theInterpretIndicator;
- tNoKeysDef++;
- theNoOfTupKeyDefined = tNoKeysDef;
+ theNoOfTupKeyLeft = tNoKeysDef;
tErrorLine++;
theErrorLine = tErrorLine;
- if (int(tNoKeysDef) == tNoTableKeys) {
+
+ if (tNoKeysDef == 0) {
if (tOpType == UpdateRequest) {
if (tInterpretInd == 1) {
theStatus = GetValue;
} else {
theStatus = SetValue;
}//if
- return 0;
+ DBUG_RETURN(0);
} else if ((tOpType == ReadRequest) || (tOpType == DeleteRequest) ||
(tOpType == ReadExclusive)) {
theStatus = GetValue;
@@ -287,89 +248,62 @@ NdbOperation::equal_impl(const NdbColumnImpl* tAttrInfo,
assert(c != 0);
if (c->getBlobType()) {
if (getBlobHandle(theNdbCon, c) == NULL)
- return -1;
+ DBUG_RETURN(-1);
}
}
}
- return 0;
+ DBUG_RETURN(0);
} else if ((tOpType == InsertRequest) || (tOpType == WriteRequest)) {
theStatus = SetValue;
- return 0;
+ DBUG_RETURN(0);
} else {
setErrorCodeAbort(4005);
- return -1;
+ DBUG_RETURN(-1);
}//if
+ DBUG_RETURN(0);
}//if
- return 0;
} else {
- return -1;
+ DBUG_RETURN(-1);
}//if
+ DBUG_RETURN(0);
}
-
+
if (aValue == NULL) {
// NULL value in primary key
setErrorCodeAbort(4505);
- return -1;
+ DBUG_RETURN(-1);
}//if
if ( tAttrInfo == NULL ) {
// Attribute name not found in table
setErrorCodeAbort(4004);
- return -1;
+ DBUG_RETURN(-1);
}//if
if (theStatus == GetValue || theStatus == SetValue){
// All pk's defined
setErrorCodeAbort(4225);
- return -1;
+ DBUG_RETURN(-1);
}//if
+
+ ndbout_c("theStatus: %d", theStatus);
// If we come here, set a general errorcode
// and exit
setErrorCodeAbort(4200);
- return -1;
+ DBUG_RETURN(-1);
equal_error1:
setErrorCodeAbort(4205);
- return -1;
+ DBUG_RETURN(-1);
equal_error2:
setErrorCodeAbort(4206);
- return -1;
+ DBUG_RETURN(-1);
equal_error3:
setErrorCodeAbort(4209);
- return -1;
-
- equal_error4:
- setErrorCodeAbort(744);
- return -1;
-}
-
-/******************************************************************************
- * Uint64 setTupleId( void )
- *
- * Return Value: Return > 0: OK
- * Return 0 : setTupleId failed
- * Parameters:
- * Remark:
- *****************************************************************************/
-Uint64
-NdbOperation::setTupleId()
-{
- if (theStatus != OperationDefined)
- {
- return 0;
- }
- Uint64 tTupleId = theNdb->getTupleIdFromNdb(m_currentTable->m_tableId);
- if (tTupleId == ~(Uint64)0){
- setErrorCodeAbort(theNdb->theError.code);
- return 0;
- }
- if (equal((Uint32)0, tTupleId) == -1)
- return 0;
-
- return tTupleId;
+ DBUG_RETURN(-1);
}
/******************************************************************************
@@ -389,8 +323,7 @@ NdbOperation::setTupleId()
int
NdbOperation::insertKEYINFO(const char* aValue,
register Uint32 aStartPosition,
- register Uint32 anAttrSizeInWords,
- register Uint32 anAttrBitsInLastWord)
+ register Uint32 anAttrSizeInWords)
{
NdbApiSignal* tSignal;
NdbApiSignal* tCurrentKEYINFO;
@@ -410,7 +343,7 @@ NdbOperation::insertKEYINFO(const char* aValue,
*****************************************************************************/
tEndPos = aStartPosition + anAttrSizeInWords - 1;
- if ((tEndPos < 9) && (anAttrBitsInLastWord == 0)) {
+ if ((tEndPos < 9)) {
register Uint32 tkeyData = *(Uint32*)aValue;
//TcKeyReq* tcKeyReq = CAST_PTR(TcKeyReq, tTCREQ->getDataPtrSend());
register Uint32* tDataPtr = (Uint32*)aValue;
@@ -451,10 +384,11 @@ NdbOperation::insertKEYINFO(const char* aValue,
setErrorCodeAbort(4001);
return -1;
}
- if (theFirstKEYINFO != NULL)
+ if (theTCREQ->next() != NULL)
theLastKEYINFO->next(tSignal);
else
- theFirstKEYINFO = tSignal;
+ theTCREQ->next(tSignal);
+
theLastKEYINFO = tSignal;
theLastKEYINFO->next(NULL);
theTotalNrOfKeyWordInSignal += 20;
@@ -467,7 +401,7 @@ NdbOperation::insertKEYINFO(const char* aValue,
* this is the first word in a KEYINFO signal. *
*****************************************************************************/
tPosition = aStartPosition;
- tCurrentKEYINFO = theFirstKEYINFO;
+ tCurrentKEYINFO = theTCREQ->next();
/*****************************************************************************
* Start by filling up Key information in the 8 words allocated in the *
@@ -520,39 +454,20 @@ NdbOperation::insertKEYINFO(const char* aValue,
} while (1);
LastWordLabel:
-
-/*****************************************************************************
- * There could be a last word that only contains partial data. This word*
- * will contain zeroes in the rest of the bits since the index expects *
- * a certain number of words and do not care for parts of words. *
- *****************************************************************************/
- if (anAttrBitsInLastWord != 0) {
- tData = *(Uint32*)(aValue + (anAttrSizeInWords - 1) * 4);
- tData = convertEndian(tData);
- tData = tData & ((1 << anAttrBitsInLastWord) - 1);
- tData = convertEndian(tData);
- if (tPosition > 8) {
- tCurrentKEYINFO->setData(tData, signalCounter);
- signalCounter++;
- } else {
- theTCREQ->setData(tData, (12 + tPosition));
- }//if
- }//if
-
return 0;
}
int
NdbOperation::getKeyFromTCREQ(Uint32* data, unsigned size)
{
- assert(m_accessTable != 0 && m_accessTable->m_sizeOfKeysInWords != 0);
- assert(m_accessTable->m_sizeOfKeysInWords == size);
+ assert(m_accessTable != 0 && m_accessTable->m_keyLenInWords != 0);
+ assert(m_accessTable->m_keyLenInWords == size);
unsigned pos = 0;
while (pos < 8 && pos < size) {
data[pos] = theKEYINFOptr[pos];
pos++;
}
- NdbApiSignal* tSignal = theFirstKEYINFO;
+ NdbApiSignal* tSignal = theTCREQ->next();
unsigned n = 0;
while (pos < size) {
if (n == 20) {
@@ -563,3 +478,115 @@ NdbOperation::getKeyFromTCREQ(Uint32* data, unsigned size)
}
return 0;
}
+
+int
+NdbOperation::handle_distribution_key(const Uint64* value, Uint32 len)
+{
+ if(theDistrKeyIndicator_ == 1 ||
+ (theNoOfTupKeyLeft > 0 && m_accessTable->m_noOfDistributionKeys > 1))
+ {
+ return 0;
+ }
+
+ if(m_accessTable->m_noOfDistributionKeys == 1)
+ {
+ setPartitionHash(value, len);
+ }
+ else if(theTCREQ->readSignalNumber() == GSN_TCKEYREQ)
+ {
+ // No support for combined distribution key and scan
+
+ /**
+ * Copy distribution key to linear memory
+ */
+ NdbColumnImpl* const * cols = m_accessTable->m_columns.getBase();
+ Uint32 len = 0;
+ Uint64 tmp[1000];
+
+ Uint32 chunk = 8;
+ Uint32* dst = (Uint32*)tmp;
+ NdbApiSignal* tSignal = theTCREQ;
+ Uint32* src = ((TcKeyReq*)tSignal->getDataPtrSend())->keyInfo;
+ if(tSignal->readSignalNumber() == GSN_SCAN_TABREQ)
+ {
+ tSignal = tSignal->next();
+ src = ((KeyInfo*)tSignal->getDataPtrSend())->keyData;
+ chunk = KeyInfo::DataLength;
+ }
+
+ for(unsigned i = m_accessTable->m_columns.size(); i>0; cols++, i--)
+ {
+ if (!(* cols)->getPrimaryKey())
+ continue;
+
+ NdbColumnImpl* tAttrInfo = * cols;
+ Uint32 sizeInBytes = tAttrInfo->m_attrSize * tAttrInfo->m_arraySize;
+ Uint32 currLen = (sizeInBytes + 3) >> 2;
+ if (tAttrInfo->getDistributionKey())
+ {
+ while (currLen >= chunk)
+ {
+ memcpy(dst, src, 4*chunk);
+ dst += chunk;
+ tSignal = tSignal->next();
+ src = ((KeyInfo*)tSignal->getDataPtrSend())->keyData;
+ currLen -= chunk;
+ chunk = KeyInfo::DataLength;
+ }
+
+ memcpy(dst, src, 4*currLen);
+ dst += currLen;
+ src += currLen;
+ chunk -= currLen;
+ }
+ else
+ {
+ while (currLen >= chunk)
+ {
+ tSignal = tSignal->next();
+ src = ((KeyInfo*)tSignal->getDataPtrSend())->keyData;
+ currLen -= chunk;
+ chunk = KeyInfo::DataLength;
+ }
+
+ src += currLen;
+ chunk -= currLen;
+ }
+ }
+ setPartitionHash(tmp, dst - (Uint32*)tmp);
+ }
+ return 0;
+}
+
+void
+NdbOperation::setPartitionHash(Uint32 value)
+{
+ union {
+ Uint32 tmp32;
+ Uint64 tmp64;
+ };
+
+ tmp32 = value;
+ setPartitionHash(&tmp64, 1);
+}
+
+void
+NdbOperation::setPartitionHash(const Uint64* value, Uint32 len)
+{
+ Uint32 buf[4];
+ md5_hash(buf, value, len);
+ setPartitionId(buf[1]);
+}
+
+void
+NdbOperation::setPartitionId(Uint32 value)
+{
+ theDistributionKey = value;
+ theDistrKeyIndicator_ = 1;
+}
+
+Uint32
+NdbOperation::getPartitionId() const
+{
+ return theDistributionKey;
+}
diff --git a/ndb/src/ndbapi/NdbPool.cpp b/ndb/src/ndbapi/NdbPool.cpp
index ba58520c1dc..a8263f564f1 100644
--- a/ndb/src/ndbapi/NdbPool.cpp
+++ b/ndb/src/ndbapi/NdbPool.cpp
@@ -21,14 +21,16 @@
static NdbPool* m_pool = 0;
bool
-create_instance(Uint32 max_ndb_objects,
+create_instance(Ndb_cluster_connection* cc,
+ Uint32 max_ndb_objects,
Uint32 no_conn_obj,
Uint32 init_no_ndb_objects)
{
if (m_pool != NULL) {
return false;
}
- m_pool = NdbPool::create_instance(max_ndb_objects,
+ m_pool = NdbPool::create_instance(cc,
+ max_ndb_objects,
no_conn_obj,
init_no_ndb_objects);
if (m_pool == NULL) {
diff --git a/ndb/src/ndbapi/NdbPoolImpl.cpp b/ndb/src/ndbapi/NdbPoolImpl.cpp
index 131edc74246..32e0a6f1410 100644
--- a/ndb/src/ndbapi/NdbPoolImpl.cpp
+++ b/ndb/src/ndbapi/NdbPoolImpl.cpp
@@ -20,7 +20,8 @@ NdbMutex *NdbPool::pool_mutex = NULL;
NdbPool *the_pool = NULL;
NdbPool*
-NdbPool::create_instance(Uint32 max_ndb_obj,
+NdbPool::create_instance(Ndb_cluster_connection* cc,
+ Uint32 max_ndb_obj,
Uint32 no_conn_obj,
Uint32 init_no_ndb_objects)
{
@@ -32,7 +33,7 @@ NdbPool::create_instance(Uint32 max_ndb_obj,
if (the_pool != NULL) {
a_pool = NULL;
} else {
- the_pool = new NdbPool(max_ndb_obj, no_conn_obj);
+ the_pool = new NdbPool(cc, max_ndb_obj, no_conn_obj);
if (!the_pool->init(init_no_ndb_objects)) {
delete the_pool;
the_pool = NULL;
@@ -76,7 +77,8 @@ NdbPool::initPoolMutex()
return ret_result;
}
-NdbPool::NdbPool(Uint32 max_no_objects,
+NdbPool::NdbPool(Ndb_cluster_connection* cc,
+ Uint32 max_no_objects,
Uint32 no_conn_objects)
{
if (no_conn_objects > 1024) {
@@ -101,6 +103,7 @@ NdbPool::NdbPool(Uint32 max_no_objects,
m_output_queue = 0;
m_input_queue = 0;
m_signal_count = 0;
+ m_cluster_connection = cc;
}
NdbPool::~NdbPool()
@@ -294,9 +297,9 @@ NdbPool::allocate_ndb(Uint32 &id,
return false;
}
if (a_schema_name) {
- a_ndb = new Ndb(a_schema_name, a_catalog_name);
+ a_ndb = new Ndb(m_cluster_connection, a_schema_name, a_catalog_name);
} else {
- a_ndb = new Ndb("");
+ a_ndb = new Ndb(m_cluster_connection, "");
}
if (a_ndb == NULL) {
return false;
diff --git a/ndb/src/ndbapi/NdbPoolImpl.hpp b/ndb/src/ndbapi/NdbPoolImpl.hpp
index af6cf4708cf..cd36f30e90b 100644
--- a/ndb/src/ndbapi/NdbPoolImpl.hpp
+++ b/ndb/src/ndbapi/NdbPoolImpl.hpp
@@ -92,7 +92,8 @@ class NdbPool {
Uint16 prev_db_object;
};
public:
- static NdbPool* create_instance(Uint32 max_ndb_objects = 240,
+ static NdbPool* create_instance(Ndb_cluster_connection*,
+ Uint32 max_ndb_objects = 240,
Uint32 no_conn_obj = 4,
Uint32 init_no_ndb_objects = 8);
static void drop_instance();
@@ -104,7 +105,8 @@ class NdbPool {
bool init(Uint32 initial_no_of_ndb_objects = 8);
void release_all();
static bool initPoolMutex();
- NdbPool(Uint32 max_no_of_ndb_objects, Uint32 no_conn_objects);
+ NdbPool(Ndb_cluster_connection*,
+ Uint32 max_no_of_ndb_objects, Uint32 no_conn_objects);
~NdbPool();
/*
We have three lists:
@@ -158,5 +160,7 @@ class NdbPool {
Uint16 m_input_queue;
Uint16 m_output_queue;
Uint16 m_signal_count;
+
+ Ndb_cluster_connection * m_cluster_connection;
};
#endif
diff --git a/ndb/src/ndbapi/NdbRecAttr.cpp b/ndb/src/ndbapi/NdbRecAttr.cpp
index db83e9c5fcf..5e5306fc33a 100644
--- a/ndb/src/ndbapi/NdbRecAttr.cpp
+++ b/ndb/src/ndbapi/NdbRecAttr.cpp
@@ -15,17 +15,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/************************************************************************************************
-Name: NdbRecAttr.C
-Include:
-Link:
-Author: UABRONM Mikael Ronström UAB/B/SD
-Date: 971206
-Version: 0.1
-Description: Interface between TIS and NDB
-Documentation:
-Adjust: 971206 UABRONM First version
-************************************************************************************************/
#include <ndb_global.h>
#include <NdbOut.hpp>
#include <NdbRecAttr.hpp>
@@ -148,6 +137,40 @@ NdbRecAttr::receive_data(const Uint32 * data, Uint32 sz){
return false;
}
+static void
+ndbrecattr_print_string(NdbOut& out, const char *type,
+ const char *aref, unsigned sz)
+{
+ const unsigned char* ref = (const unsigned char*)aref;
+ int i, len, printable= 1;
+ // trailing zeroes are not printed
+ for (i=sz-1; i >= 0; i--)
+ if (ref[i] == 0) sz--;
+ else break;
+ if (sz == 0) return; // empty
+
+ for (len=0; len < (int)sz && ref[i] != 0; len++)
+ if (printable && !isprint((int)ref[i]))
+ printable= 0;
+
+ if (printable)
+ out.print("%.*s", len, ref);
+ else
+ {
+ out.print("0x");
+ for (i=0; i < len; i++)
+ out.print("%02X", (int)ref[i]);
+ }
+ if (len != (int)sz)
+ {
+ out.print("[");
+ for (i= len+1; ref[i] != 0; i++)
+ out.print("%u]",len-i);
+ assert((int)sz > i);
+ ndbrecattr_print_string(out,type,aref+i,sz-i);
+ }
+}
+
NdbOut& operator<<(NdbOut& out, const NdbRecAttr &r)
{
if (r.isNULL())
@@ -171,6 +194,9 @@ NdbOut& operator<<(NdbOut& out, const NdbRecAttr &r)
case NdbDictionary::Column::Bigunsigned:
out << r.u_64_value();
break;
+ case NdbDictionary::Column::Bit:
+ out << hex << "H'" << r.u_32_value() << dec;
+ break;
case NdbDictionary::Column::Unsigned:
out << r.u_32_value();
break;
@@ -192,17 +218,21 @@ NdbOut& operator<<(NdbOut& out, const NdbRecAttr &r)
case NdbDictionary::Column::Tinyint:
out << (int) r.char_value();
break;
+ case NdbDictionary::Column::Binary:
+ ndbrecattr_print_string(out,"Binary",r.aRef(),r.arraySize());
+ j = r.arraySize();
+ break;
case NdbDictionary::Column::Char:
- out.print("%.*s", r.arraySize(), r.aRef());
+ ndbrecattr_print_string(out,"Char",r.aRef(),r.arraySize());
j = length;
break;
case NdbDictionary::Column::Varchar:
- {
- short len = ntohs(r.u_short_value());
- out.print("%.*s", len, r.aRef()+2);
- }
- j = length;
- break;
+ {
+ unsigned len = *(const unsigned char*)r.aRef();
+ ndbrecattr_print_string(out,"Varchar", r.aRef()+1,len);
+ j = length;
+ }
+ break;
case NdbDictionary::Column::Float:
out << r.float_value();
break;
@@ -221,6 +251,10 @@ NdbOut& operator<<(NdbOut& out, const NdbRecAttr &r)
out.print("%.*s", len, r.aRef());
}
break;
+ case NdbDictionary::Column::Decimal:
+ case NdbDictionary::Column::Decimalunsigned:
+ goto unknown; // TODO
+ break;
// for dates cut-and-paste from field.cc
case NdbDictionary::Column::Datetime:
{
@@ -323,6 +357,14 @@ NdbOut& operator<<(NdbOut& out, const NdbRecAttr &r)
j = length;
}
break;
+ case NdbDictionary::Column::Longvarchar:
+ {
+ unsigned len = uint2korr(r.aRef());
+ ndbrecattr_print_string(out,"Longvarchar", r.aRef()+2,len);
+ j = length;
+ }
+ break;
+ unknown:
default: /* no print functions for the rest, just print type */
out << (int) r.getType();
j = length;
diff --git a/ndb/src/ndbapi/NdbReceiver.cpp b/ndb/src/ndbapi/NdbReceiver.cpp
index cad247512b2..df16ae66915 100644
--- a/ndb/src/ndbapi/NdbReceiver.cpp
+++ b/ndb/src/ndbapi/NdbReceiver.cpp
@@ -20,7 +20,7 @@
#include "NdbDictionaryImpl.hpp"
#include <NdbRecAttr.hpp>
#include <AttributeHeader.hpp>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <TransporterFacade.hpp>
#include <signaldata/TcKeyConf.hpp>
@@ -140,7 +140,10 @@ NdbReceiver::calculate_batch_size(Uint32 key_size,
}
void
-NdbReceiver::do_get_value(NdbReceiver * org, Uint32 rows, Uint32 key_size){
+NdbReceiver::do_get_value(NdbReceiver * org,
+ Uint32 rows,
+ Uint32 key_size,
+ Uint32 range_no){
if(rows > m_defined_rows){
delete[] m_rows;
m_defined_rows = rows;
@@ -155,7 +158,7 @@ NdbReceiver::do_get_value(NdbReceiver * org, Uint32 rows, Uint32 key_size){
key.m_attrSize = 4;
key.m_nullable = true; // So that receive works w.r.t KEYINFO20
}
- m_key_info = key_size;
+ m_hidden_count = (key_size ? 1 : 0) + range_no ;
for(Uint32 i = 0; i<rows; i++){
NdbRecAttr * prev = theCurrentRecAttr;
@@ -167,6 +170,12 @@ NdbReceiver::do_get_value(NdbReceiver * org, Uint32 rows, Uint32 key_size){
return ; // -1
}
+ if(range_no &&
+ !getValue(&NdbColumnImpl::getImpl(* NdbDictionary::Column::RANGE_NO),0))
+ {
+ abort();
+ }
+
NdbRecAttr* tRecAttr = org->theFirstRecAttr;
while(tRecAttr != 0){
if(getValue(&NdbColumnImpl::getImpl(*tRecAttr->m_column), (char*)0) != 0)
@@ -192,14 +201,14 @@ NdbReceiver::do_get_value(NdbReceiver * org, Uint32 rows, Uint32 key_size){
return;
}
-void
+NdbRecAttr*
NdbReceiver::copyout(NdbReceiver & dstRec){
- NdbRecAttr* src = m_rows[m_current_row++];
- NdbRecAttr* dst = dstRec.theFirstRecAttr;
- Uint32 tmp = m_key_info;
- if(tmp > 0){
+ NdbRecAttr *src = m_rows[m_current_row++];
+ NdbRecAttr *dst = dstRec.theFirstRecAttr;
+ NdbRecAttr *start = src;
+ Uint32 tmp = m_hidden_count;
+ while(tmp--)
src = src->next();
- }
while(dst){
Uint32 len = ((src->theAttrSize * src->theArraySize)+3)/4;
@@ -207,6 +216,8 @@ NdbReceiver::copyout(NdbReceiver & dstRec){
src = src->next();
dst = dst->next();
}
+
+ return start;
}
int
diff --git a/ndb/src/ndbapi/NdbResultSet.cpp b/ndb/src/ndbapi/NdbResultSet.cpp
deleted file mode 100644
index 87b304126ba..00000000000
--- a/ndb/src/ndbapi/NdbResultSet.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*****************************************************************************
- * Name: NdbResultSet.cpp
- * Include:
- * Link:
- * Author: UABMASD Martin Sköld INN/V Alzato
- * Date: 2002-04-01
- * Version: 0.1
- * Description: Cursor class
- * Documentation:
- * Adjust: 2002-04-01 UABMASD First version.
- ****************************************************************************/
-
-#include <Ndb.hpp>
-#include <NdbConnection.hpp>
-#include <NdbResultSet.hpp>
-#include <NdbBlob.hpp>
-
-NdbResultSet::NdbResultSet(NdbScanOperation *owner)
-: m_operation(owner)
-{
-}
-
-NdbResultSet::~NdbResultSet()
-{
-}
-
-void NdbResultSet::init()
-{
-}
-
-int NdbResultSet::nextResult(bool fetchAllowed, bool forceSend)
-{
- int res;
- if ((res = m_operation->nextResult(fetchAllowed, forceSend)) == 0) {
- // handle blobs
- NdbBlob* tBlob = m_operation->theBlobList;
- while (tBlob != 0) {
- if (tBlob->atNextResult() == -1)
- return -1;
- tBlob = tBlob->theNext;
- }
- /*
- * Flush blob part ops on behalf of user because
- * - nextResult is analogous to execute(NoCommit)
- * - user is likely to want blob value before next execute
- */
- if (m_operation->m_transConnection->executePendingBlobOps() == -1)
- return -1;
- return 0;
- }
- return res;
-}
-
-void NdbResultSet::close(bool forceSend)
-{
- m_operation->closeScan(forceSend, true);
-}
-
-NdbOperation*
-NdbResultSet::updateTuple(){
- return updateTuple(m_operation->m_transConnection);
-}
-
-NdbOperation*
-NdbResultSet::updateTuple(NdbConnection* takeOverTrans){
- return m_operation->takeOverScanOp(NdbOperation::UpdateRequest,
- takeOverTrans);
-}
-
-int
-NdbResultSet::deleteTuple(){
- return deleteTuple(m_operation->m_transConnection);
-}
-
-int
-NdbResultSet::deleteTuple(NdbConnection * takeOverTrans){
- void * res = m_operation->takeOverScanOp(NdbOperation::DeleteRequest,
- takeOverTrans);
- if(res == 0)
- return -1;
- return 0;
-}
-
-int
-NdbResultSet::restart(bool forceSend){
- return m_operation->restart(forceSend);
-}
diff --git a/ndb/src/ndbapi/NdbScanFilter.cpp b/ndb/src/ndbapi/NdbScanFilter.cpp
index 0c851427ba5..b39fd10fe95 100644
--- a/ndb/src/ndbapi/NdbScanFilter.cpp
+++ b/ndb/src/ndbapi/NdbScanFilter.cpp
@@ -48,11 +48,8 @@ public:
int cond_col(Interpreter::UnaryCondition, Uint32 attrId);
- template<typename T>
- int cond_col_const(Interpreter::BinaryCondition, Uint32 attrId, T value);
-
int cond_col_const(Interpreter::BinaryCondition, Uint32 attrId,
- const char * value, Uint32 len, bool nopad);
+ const void * value, Uint32 len);
};
const Uint32 LabelExit = ~0;
@@ -247,68 +244,7 @@ NdbScanFilter::isfalse(){
typedef int (NdbOperation:: * Branch1)(Uint32, Uint32 label);
-typedef int (NdbOperation:: * Branch2)(Uint32, Uint32, Uint32 label);
-typedef int (NdbOperation:: * StrBranch2)(Uint32, const char*,Uint32,bool,Uint32);
-
-struct tab {
- Branch2 m_branches[5];
-};
-
-static const tab table[] = {
- /**
- * EQ (AND, OR, NAND, NOR)
- */
- { { 0,
- &NdbOperation::branch_ne,
- &NdbOperation::branch_eq,
- &NdbOperation::branch_eq,
- &NdbOperation::branch_ne } }
-
- /**
- * NEQ
- */
- ,{ { 0,
- &NdbOperation::branch_eq,
- &NdbOperation::branch_ne,
- &NdbOperation::branch_ne,
- &NdbOperation::branch_eq } }
-
- /**
- * LT
- */
- ,{ { 0,
- &NdbOperation::branch_le,
- &NdbOperation::branch_gt,
- &NdbOperation::branch_gt,
- &NdbOperation::branch_le } }
-
- /**
- * LE
- */
- ,{ { 0,
- &NdbOperation::branch_lt,
- &NdbOperation::branch_ge,
- &NdbOperation::branch_ge,
- &NdbOperation::branch_lt } }
-
- /**
- * GT
- */
- ,{ { 0,
- &NdbOperation::branch_ge,
- &NdbOperation::branch_lt,
- &NdbOperation::branch_lt,
- &NdbOperation::branch_ge } }
-
- /**
- * GE
- */
- ,{ { 0,
- &NdbOperation::branch_gt,
- &NdbOperation::branch_le,
- &NdbOperation::branch_le,
- &NdbOperation::branch_gt } }
-};
+typedef int (NdbOperation:: * StrBranch2)(Uint32, const void*, Uint32, bool, Uint32);
struct tab2 {
Branch1 m_branches[5];
@@ -334,134 +270,9 @@ static const tab2 table2[] = {
&NdbOperation::branch_col_eq_null } }
};
-const int tab_sz = sizeof(table)/sizeof(table[0]);
const int tab2_sz = sizeof(table2)/sizeof(table2[0]);
int
-matchType(const NdbDictionary::Column * col){
- return 1;
-}
-
-template<typename T> int load_const(NdbOperation* op, T value, Uint32 reg);
-
-template<>
-int
-load_const(NdbOperation* op, Uint32 value, Uint32 reg){
- return op->load_const_u32(reg, value);
-}
-
-template<>
-int
-load_const(NdbOperation* op, Uint64 value, Uint32 reg){
- return op->load_const_u64(reg, value);
-}
-
-template<typename T>
-int
-NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition op,
- Uint32 AttrId, T value){
-
- if(op < 0 || op >= tab_sz){
- m_operation->setErrorCodeAbort(4262);
- return -1;
- }
-
- if(m_current.m_group < NdbScanFilter::AND ||
- m_current.m_group > NdbScanFilter::NOR){
- m_operation->setErrorCodeAbort(4260);
- return -1;
- }
-
- Branch2 branch = table[op].m_branches[m_current.m_group];
- const NdbDictionary::Column * col =
- m_operation->m_currentTable->getColumn(AttrId);
-
- if(col == 0){
- m_operation->setErrorCodeAbort(4261);
- return -1;
- }
-
- if(!matchType(col)){
- /**
- * Code not reached
- */
- return -1;
- }
-
- if(m_latestAttrib != AttrId){
- m_operation->read_attr(&NdbColumnImpl::getImpl(* col), 4);
- m_latestAttrib = AttrId;
- }
-
- load_const<T>(m_operation, value, 5);
- (m_operation->* branch)(4, 5, m_current.m_ownLabel);
-
- return 0;
-}
-
-int
-NdbScanFilter::eq(int AttrId, Uint32 value){
- return m_impl.cond_col_const(Interpreter::EQ, AttrId, value);
-}
-
-int
-NdbScanFilter::ne(int AttrId, Uint32 value){
- return m_impl.cond_col_const(Interpreter::NE, AttrId, value);
-}
-
-int
-NdbScanFilter::lt(int AttrId, Uint32 value){
- return m_impl.cond_col_const(Interpreter::LT, AttrId, value);
-}
-
-int
-NdbScanFilter::le(int AttrId, Uint32 value){
- return m_impl.cond_col_const(Interpreter::LE, AttrId, value);
-}
-
-int
-NdbScanFilter::gt(int AttrId, Uint32 value){
- return m_impl.cond_col_const(Interpreter::GT, AttrId, value);
-}
-
-int
-NdbScanFilter::ge(int AttrId, Uint32 value){
- return m_impl.cond_col_const(Interpreter::GE, AttrId, value);
-}
-
-
-int
-NdbScanFilter::eq(int AttrId, Uint64 value){
- return m_impl.cond_col_const(Interpreter::EQ, AttrId, value);
-}
-
-int
-NdbScanFilter::ne(int AttrId, Uint64 value){
- return m_impl.cond_col_const(Interpreter::NE, AttrId, value);
-}
-
-int
-NdbScanFilter::lt(int AttrId, Uint64 value){
- return m_impl.cond_col_const(Interpreter::LT, AttrId, value);
-}
-
-int
-NdbScanFilter::le(int AttrId, Uint64 value){
- return m_impl.cond_col_const(Interpreter::LE, AttrId, value);
-}
-
-int
-NdbScanFilter::gt(int AttrId, Uint64 value){
- return m_impl.cond_col_const(Interpreter::GT, AttrId, value);
-}
-
-int
-NdbScanFilter::ge(int AttrId, Uint64 value){
- return m_impl.cond_col_const(Interpreter::GE, AttrId, value);
-}
-
-
-int
NdbScanFilterImpl::cond_col(Interpreter::UnaryCondition op, Uint32 AttrId){
if(op < 0 || op >= tab2_sz){
@@ -570,11 +381,10 @@ static const tab3 table3[] = {
const int tab3_sz = sizeof(table3)/sizeof(table3[0]);
-
int
NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition op,
Uint32 AttrId,
- const char * value, Uint32 len, bool nopad){
+ const void * value, Uint32 len){
if(op < 0 || op >= tab3_sz){
m_operation->setErrorCodeAbort(4260);
return -1;
@@ -595,49 +405,35 @@ NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition op,
return -1;
}
- (m_operation->* branch)(AttrId, value, len, nopad, m_current.m_ownLabel);
- return 0;
-}
-
-int
-NdbScanFilter::eq(int ColId, const char * val, Uint32 len, bool nopad){
- return m_impl.cond_col_const(Interpreter::EQ, ColId, val, len, nopad);
-}
-
-int
-NdbScanFilter::ne(int ColId, const char * val, Uint32 len, bool nopad){
- return m_impl.cond_col_const(Interpreter::NE, ColId, val, len, nopad);
-}
-
-int
-NdbScanFilter::lt(int ColId, const char * val, Uint32 len, bool nopad){
- return m_impl.cond_col_const(Interpreter::LT, ColId, val, len, nopad);
+ int ret = (m_operation->* branch)(AttrId, value, len, false, m_current.m_ownLabel);
+ return ret;
}
int
-NdbScanFilter::le(int ColId, const char * val, Uint32 len, bool nopad){
- return m_impl.cond_col_const(Interpreter::LE, ColId, val, len, nopad);
-}
-
-int
-NdbScanFilter::gt(int ColId, const char * val, Uint32 len, bool nopad){
- return m_impl.cond_col_const(Interpreter::GT, ColId, val, len, nopad);
-}
-
-int
-NdbScanFilter::ge(int ColId, const char * val, Uint32 len, bool nopad){
- return m_impl.cond_col_const(Interpreter::GE, ColId, val, len, nopad);
-}
-
-int
-NdbScanFilter::like(int ColId, const char * val, Uint32 len, bool nopad){
- return m_impl.cond_col_const(Interpreter::LIKE, ColId, val, len, nopad);
-}
+NdbScanFilter::cmp(BinaryCondition cond, int ColId,
+ const void *val, Uint32 len)
+{
+ switch(cond){
+ case COND_LE:
+ return m_impl.cond_col_const(Interpreter::LE, ColId, val, len);
+ case COND_LT:
+ return m_impl.cond_col_const(Interpreter::LT, ColId, val, len);
+ case COND_GE:
+ return m_impl.cond_col_const(Interpreter::GE, ColId, val, len);
+ case COND_GT:
+ return m_impl.cond_col_const(Interpreter::GT, ColId, val, len);
+ case COND_EQ:
+ return m_impl.cond_col_const(Interpreter::EQ, ColId, val, len);
+ case COND_NE:
+ return m_impl.cond_col_const(Interpreter::NE, ColId, val, len);
+ case COND_LIKE:
+ return m_impl.cond_col_const(Interpreter::LIKE, ColId, val, len);
+ case COND_NOT_LIKE:
+ return m_impl.cond_col_const(Interpreter::NOT_LIKE, ColId, val, len);
+ }
+ return -1;
+}
-int
-NdbScanFilter::notlike(int ColId, const char * val, Uint32 len, bool nopad){
- return m_impl.cond_col_const(Interpreter::NOT_LIKE, ColId, val, len, nopad);
-}
#if 0
int
@@ -778,10 +574,4 @@ main(void){
#endif
template class Vector<NdbScanFilterImpl::State>;
-#if __SUNPRO_CC != 0x560
-#ifndef _FORTEC_
-template int NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition, Uint32 attrId, Uint32);
-template int NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition, Uint32 attrId, Uint64);
-#endif
-#endif
diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp
index fc5a22cce17..5980f2588bc 100644
--- a/ndb/src/ndbapi/NdbScanOperation.cpp
+++ b/ndb/src/ndbapi/NdbScanOperation.cpp
@@ -18,11 +18,11 @@
#include <Ndb.hpp>
#include <NdbScanOperation.hpp>
#include <NdbIndexScanOperation.hpp>
-#include <NdbConnection.hpp>
-#include <NdbResultSet.hpp>
+#include <NdbTransaction.hpp>
#include "NdbApiSignal.hpp"
#include <NdbOut.hpp>
#include "NdbDictionaryImpl.hpp"
+#include <NdbBlob.hpp>
#include <NdbRecAttr.hpp>
#include <NdbReceiver.hpp>
@@ -39,7 +39,6 @@
NdbScanOperation::NdbScanOperation(Ndb* aNdb) :
NdbOperation(aNdb),
- m_resultSet(0),
m_transConnection(NULL)
{
theParallelism = 0;
@@ -60,24 +59,11 @@ NdbScanOperation::~NdbScanOperation()
theNdb->releaseNdbScanRec(m_receivers[i]);
}
delete[] m_array;
- if (m_resultSet)
- delete m_resultSet;
}
-NdbResultSet*
-NdbScanOperation::getResultSet()
-{
- if (!m_resultSet)
- m_resultSet = new NdbResultSet(this);
-
- return m_resultSet;
-}
-
-
-
void
NdbScanOperation::setErrorCode(int aErrorCode){
- NdbConnection* tmp = theNdbCon;
+ NdbTransaction* tmp = theNdbCon;
theNdbCon = m_transConnection;
NdbOperation::setErrorCode(aErrorCode);
theNdbCon = tmp;
@@ -85,7 +71,7 @@ NdbScanOperation::setErrorCode(int aErrorCode){
void
NdbScanOperation::setErrorCodeAbort(int aErrorCode){
- NdbConnection* tmp = theNdbCon;
+ NdbTransaction* tmp = theNdbCon;
theNdbCon = m_transConnection;
NdbOperation::setErrorCodeAbort(aErrorCode);
theNdbCon = tmp;
@@ -100,11 +86,11 @@ NdbScanOperation::setErrorCodeAbort(int aErrorCode){
* Remark: Initiates operation record after allocation.
*****************************************************************************/
int
-NdbScanOperation::init(const NdbTableImpl* tab, NdbConnection* myConnection)
+NdbScanOperation::init(const NdbTableImpl* tab, NdbTransaction* myConnection)
{
m_transConnection = myConnection;
- //NdbConnection* aScanConnection = theNdb->startTransaction(myConnection);
- NdbConnection* aScanConnection = theNdb->hupp(myConnection);
+ //NdbTransaction* aScanConnection = theNdb->startTransaction(myConnection);
+ NdbTransaction* aScanConnection = theNdb->hupp(myConnection);
if (!aScanConnection){
setErrorCodeAbort(theNdb->getNdbError().code);
return -1;
@@ -120,16 +106,17 @@ NdbScanOperation::init(const NdbTableImpl* tab, NdbConnection* myConnection)
theStatus = GetValue;
theOperationType = OpenScanRequest;
theNdbCon->theMagicNumber = 0xFE11DF;
-
+ theNoOfTupKeyLeft = tab->m_noOfDistributionKeys;
+ m_read_range_no = 0;
return 0;
}
-NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm,
- Uint32 batch,
- Uint32 parallel)
+int
+NdbScanOperation::readTuples(NdbScanOperation::LockMode lm,
+ Uint32 batch,
+ Uint32 parallel)
{
- m_ordered = 0;
-
+ m_ordered = m_descending = false;
Uint32 fragCount = m_currentTable->m_fragmentCount;
if (parallel > fragCount || parallel == 0) {
@@ -142,7 +129,7 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm,
// 3. theScanOp contains a NdbScanOperation
if (theNdbCon->theScanningOp != NULL){
setErrorCode(4605);
- return 0;
+ return -1;
}
theNdbCon->theScanningOp = this;
@@ -167,14 +154,14 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm,
break;
default:
setErrorCode(4003);
- return 0;
+ return -1;
}
m_keyInfo = lockExcl ? 1 : 0;
bool range = false;
- if (m_accessTable->m_indexType == NdbDictionary::Index::OrderedIndex ||
- m_accessTable->m_indexType == NdbDictionary::Index::UniqueOrderedIndex){
+ if (m_accessTable->m_indexType == NdbDictionary::Index::OrderedIndex)
+ {
if (m_currentTable == m_accessTable){
// Old way of scanning indexes, should not be allowed
m_currentTable = theNdb->theDictionary->
@@ -192,15 +179,16 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm,
if(fix_receivers(parallel) == -1){
setErrorCodeAbort(4000);
- return 0;
+ return -1;
}
theSCAN_TABREQ = (!theSCAN_TABREQ ? theNdb->getSignal() : theSCAN_TABREQ);
if (theSCAN_TABREQ == NULL) {
setErrorCodeAbort(4000);
- return 0;
+ return -1;
}//if
+ theSCAN_TABREQ->setSignal(GSN_SCAN_TABREQ);
ScanTabReq * req = CAST_PTR(ScanTabReq, theSCAN_TABREQ->getDataPtrSend());
req->apiConnectPtr = theNdbCon->theTCConPtr;
req->tableId = m_accessTable->m_tableId;
@@ -221,10 +209,11 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm,
req->transId1 = (Uint32) transId;
req->transId2 = (Uint32) (transId >> 32);
- NdbApiSignal* tSignal =
- theFirstKEYINFO;
-
- theFirstKEYINFO = (tSignal ? tSignal : tSignal = theNdb->getSignal());
+ NdbApiSignal* tSignal = theSCAN_TABREQ->next();
+ if(!tSignal)
+ {
+ theSCAN_TABREQ->next(tSignal = theNdb->getSignal());
+ }
theLastKEYINFO = tSignal;
tSignal->setSignal(GSN_KEYINFO);
@@ -232,7 +221,7 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm,
theTotalNrOfKeyWordInSignal= 0;
getFirstATTRINFOScan();
- return getResultSet();
+ return 0;
}
int
@@ -356,65 +345,11 @@ NdbScanOperation::getFirstATTRINFOScan()
#define FAKE_PTR 2
#define API_PTR 3
-
-/*
- * After setBound() are done, move the accumulated ATTRINFO signals to
- * a separate list. Then continue with normal scan.
- */
-#if 0
-int
-NdbIndexScanOperation::saveBoundATTRINFO()
-{
- theCurrentATTRINFO->setLength(theAI_LenInCurrAI);
- theBoundATTRINFO = theFirstATTRINFO;
- theTotalBoundAI_Len = theTotalCurrAI_Len;
- theTotalCurrAI_Len = 5;
- theBoundATTRINFO->setData(theTotalBoundAI_Len, 4);
- theBoundATTRINFO->setData(0, 5);
- theBoundATTRINFO->setData(0, 6);
- theBoundATTRINFO->setData(0, 7);
- theBoundATTRINFO->setData(0, 8);
- theStatus = GetValue;
-
- int res = getFirstATTRINFOScan();
-
- /**
- * Define each key with getValue (if ordered)
- * unless the one's with EqBound
- */
- if(!res && m_ordered){
-
- /**
- * If setBound EQ
- */
- Uint32 i = 0;
- while(theTupleKeyDefined[i][0] == SETBOUND_EQ)
- i++;
-
-
- Uint32 cnt = m_accessTable->getNoOfColumns() - 1;
- m_sort_columns = cnt - i;
- for(; i<cnt; i++){
- const NdbColumnImpl* key = m_accessTable->m_index->m_columns[i];
- const NdbColumnImpl* col = m_currentTable->getColumn(key->m_keyInfoPos);
- NdbRecAttr* tmp = NdbScanOperation::getValue_impl(col, (char*)-1);
- UintPtr newVal = UintPtr(tmp);
- theTupleKeyDefined[i][0] = FAKE_PTR;
- theTupleKeyDefined[i][1] = (newVal & 0xFFFFFFFF);
-#if (SIZEOF_CHARP == 8)
- theTupleKeyDefined[i][2] = (newVal >> 32);
-#endif
- }
- }
- return res;
-}
-#endif
-
#define WAITFOR_SCAN_TIMEOUT 120000
int
NdbScanOperation::executeCursor(int nodeId){
- NdbConnection * tCon = theNdbCon;
+ NdbTransaction * tCon = theNdbCon;
TransporterFacade* tp = TransporterFacade::instance();
Guard guard(tp->theMutexPtr);
@@ -448,7 +383,7 @@ NdbScanOperation::executeCursor(int nodeId){
TRACE_DEBUG("The node is stopping when attempting to start a scan");
setErrorCode(4030);
}//if
- tCon->theCommitStatus = NdbConnection::Aborted;
+ tCon->theCommitStatus = NdbTransaction::Aborted;
}//if
return -1;
}
@@ -456,6 +391,29 @@ NdbScanOperation::executeCursor(int nodeId){
int NdbScanOperation::nextResult(bool fetchAllowed, bool forceSend)
{
+ int res;
+ if ((res = nextResultImpl(fetchAllowed, forceSend)) == 0) {
+ // handle blobs
+ NdbBlob* tBlob = theBlobList;
+ while (tBlob != 0) {
+ if (tBlob->atNextResult() == -1)
+ return -1;
+ tBlob = tBlob->theNext;
+ }
+ /*
+ * Flush blob part ops on behalf of user because
+ * - nextResult is analogous to execute(NoCommit)
+ * - user is likely to want blob value before next execute
+ */
+ if (m_transConnection->executePendingBlobOps() == -1)
+ return -1;
+ return 0;
+ }
+ return res;
+}
+
+int NdbScanOperation::nextResultImpl(bool fetchAllowed, bool forceSend)
+{
if(m_ordered)
return ((NdbIndexScanOperation*)this)->next_result_ordered(fetchAllowed,
forceSend);
@@ -466,6 +424,7 @@ int NdbScanOperation::nextResult(bool fetchAllowed, bool forceSend)
int retVal = 2;
Uint32 idx = m_current_api_receiver;
Uint32 last = m_api_receivers_count;
+ m_curr_row = 0;
if(DEBUG_NEXT_RESULT)
ndbout_c("nextResult(%d) idx=%d last=%d", fetchAllowed, idx, last);
@@ -476,7 +435,7 @@ int NdbScanOperation::nextResult(bool fetchAllowed, bool forceSend)
for(; idx < last; idx++){
NdbReceiver* tRec = m_api_receivers[idx];
if(tRec->nextResult()){
- tRec->copyout(theReceiver);
+ m_curr_row = tRec->copyout(theReceiver);
retVal = 0;
break;
}
@@ -552,7 +511,7 @@ int NdbScanOperation::nextResult(bool fetchAllowed, bool forceSend)
for(; idx < last; idx++){
NdbReceiver* tRec = m_api_receivers[idx];
if(tRec->nextResult()){
- tRec->copyout(theReceiver);
+ m_curr_row = tRec->copyout(theReceiver);
retVal = 0;
break;
}
@@ -674,11 +633,17 @@ NdbScanOperation::doSend(int ProcessorId)
return 0;
}
-void NdbScanOperation::closeScan(bool forceSend, bool releaseOp)
+void NdbScanOperation::close(bool forceSend, bool releaseOp)
{
+ DBUG_ENTER("NdbScanOperation::close");
+ DBUG_PRINT("enter", ("this=%x tcon=%x con=%x force=%d release=%d",
+ (UintPtr)this,
+ (UintPtr)m_transConnection, (UintPtr)theNdbCon,
+ forceSend, releaseOp));
+
if(m_transConnection){
if(DEBUG_NEXT_RESULT)
- ndbout_c("closeScan() theError.code = %d "
+ ndbout_c("close() theError.code = %d "
"m_api_receivers_count = %d "
"m_conf_receivers_count = %d "
"m_sent_receivers_count = %d",
@@ -705,6 +670,7 @@ void NdbScanOperation::closeScan(bool forceSend, bool releaseOp)
tCon->theScanningOp = 0;
theNdb->closeTransaction(tCon);
+ DBUG_VOID_RETURN;
}
void
@@ -716,17 +682,19 @@ NdbScanOperation::execCLOSE_SCAN_REP(){
void NdbScanOperation::release()
{
if(theNdbCon != 0 || m_transConnection != 0){
- closeScan();
+ close();
}
for(Uint32 i = 0; i<m_allocated_receivers; i++){
m_receivers[i]->release();
}
+
+ NdbOperation::release();
+
if(theSCAN_TABREQ)
{
theNdb->releaseSignal(theSCAN_TABREQ);
theSCAN_TABREQ = 0;
}
- NdbOperation::release();
}
/***************************************************************************
@@ -793,7 +761,9 @@ int NdbScanOperation::prepareSendScan(Uint32 aTC_ConnectPtr,
req->requestInfo = reqInfo;
for(Uint32 i = 0; i<theParallelism; i++){
- m_receivers[i]->do_get_value(&theReceiver, batch_size, key_size);
+ m_receivers[i]->do_get_value(&theReceiver, batch_size,
+ key_size,
+ m_read_range_no);
}
return 0;
}
@@ -821,10 +791,6 @@ NdbScanOperation::doSendScan(int aProcessorId)
assert(theSCAN_TABREQ != NULL);
tSignal = theSCAN_TABREQ;
- if (tSignal->setSignal(GSN_SCAN_TABREQ) == -1) {
- setErrorCode(4001);
- return -1;
- }
Uint32 tupKeyLen = theTupKeyLen;
Uint32 len = theTotalNrOfKeyWordInSignal;
@@ -836,7 +802,12 @@ NdbScanOperation::doSendScan(int aProcessorId)
// we created the ATTRINFO signals after the SCAN_TABREQ signal.
ScanTabReq * const req = CAST_PTR(ScanTabReq, tSignal->getDataPtrSend());
req->attrLenKeyLen = (tupKeyLen << 16) | theTotalCurrAI_Len;
-
+ Uint32 tmp = req->requestInfo;
+ ScanTabReq::setDistributionKeyFlag(tmp, theDistrKeyIndicator_);
+ req->distributionKey = theDistributionKey;
+ req->requestInfo = tmp;
+ tSignal->setLength(ScanTabReq::StaticLength + theDistrKeyIndicator_);
+
TransporterFacade *tp = TransporterFacade::instance();
LinearSectionPtr ptr[3];
ptr[0].p = m_prepared_receivers;
@@ -852,8 +823,8 @@ NdbScanOperation::doSendScan(int aProcessorId)
tSignal = theLastKEYINFO;
tSignal->setLength(KeyInfo::HeaderLength + theTotalNrOfKeyWordInSignal);
- assert(theFirstKEYINFO != NULL);
- tSignal = theFirstKEYINFO;
+ assert(theSCAN_TABREQ->next() != NULL);
+ tSignal = theSCAN_TABREQ->next();
NdbApiSignal* last;
do {
@@ -889,6 +860,7 @@ NdbScanOperation::doSendScan(int aProcessorId)
}
theStatus = WaitResponse;
+ m_curr_row = 0;
m_sent_receivers_count = theParallelism;
if(m_ordered)
{
@@ -900,9 +872,9 @@ NdbScanOperation::doSendScan(int aProcessorId)
}//NdbOperation::doSendScan()
/*****************************************************************************
- * NdbOperation* takeOverScanOp(NdbConnection* updateTrans);
+ * NdbOperation* takeOverScanOp(NdbTransaction* updateTrans);
*
- * Parameters: The update transactions NdbConnection pointer.
+ * Parameters: The update transactions NdbTransaction pointer.
* Return Value: A reference to the transferred operation object
* or NULL if no success.
* Remark: Take over the scanning transactions NdbOperation
@@ -912,8 +884,8 @@ NdbScanOperation::doSendScan(int aProcessorId)
*
* FUTURE IMPLEMENTATION: (This note was moved from header file.)
* In the future, it will even be possible to transfer
- * to a NdbConnection on another Ndb-object.
- * In this case the receiving NdbConnection-object must call
+ * to a NdbTransaction on another Ndb-object.
+ * In this case the receiving NdbTransaction-object must call
* a method receiveOpFromScan to actually receive the information.
* This means that the updating transactions can be placed
* in separate threads and thus increasing the parallelism during
@@ -922,16 +894,9 @@ NdbScanOperation::doSendScan(int aProcessorId)
int
NdbScanOperation::getKeyFromKEYINFO20(Uint32* data, unsigned size)
{
- Uint32 idx = m_current_api_receiver;
- Uint32 last = m_api_receivers_count;
-
- Uint32 row;
- NdbReceiver * tRec;
- NdbRecAttr * tRecAttr;
- if(idx < last && (tRec = m_api_receivers[idx])
- && ((row = tRec->m_current_row) <= tRec->m_defined_rows)
- && (tRecAttr = tRec->m_rows[row-1])){
-
+ NdbRecAttr * tRecAttr = m_curr_row;
+ if(tRecAttr)
+ {
const Uint32 * src = (Uint32*)tRecAttr->aRef();
memcpy(data, src, 4*size);
return 0;
@@ -940,18 +905,12 @@ NdbScanOperation::getKeyFromKEYINFO20(Uint32* data, unsigned size)
}
NdbOperation*
-NdbScanOperation::takeOverScanOp(OperationType opType, NdbConnection* pTrans){
+NdbScanOperation::takeOverScanOp(OperationType opType, NdbTransaction* pTrans)
+{
- Uint32 idx = m_current_api_receiver;
- Uint32 last = m_api_receivers_count;
-
- Uint32 row;
- NdbReceiver * tRec;
- NdbRecAttr * tRecAttr;
- if(idx < last && (tRec = m_api_receivers[idx])
- && ((row = tRec->m_current_row) <= tRec->m_defined_rows)
- && (tRecAttr = tRec->m_rows[row-1])){
-
+ NdbRecAttr * tRecAttr = m_curr_row;
+ if(tRecAttr)
+ {
NdbOperation * newOp = pTrans->getNdbOperation(m_currentTable);
if (newOp == NULL){
return NULL;
@@ -970,13 +929,15 @@ NdbScanOperation::takeOverScanOp(OperationType opType, NdbConnection* pTrans){
const Uint32 * src = (Uint32*)tRecAttr->aRef();
const Uint32 tScanInfo = src[len] & 0x3FFFF;
- const Uint32 tTakeOverNode = src[len] >> 20;
+ const Uint32 tTakeOverFragment = src[len] >> 20;
{
UintR scanInfo = 0;
TcKeyReq::setTakeOverScanFlag(scanInfo, 1);
- TcKeyReq::setTakeOverScanNode(scanInfo, tTakeOverNode);
+ TcKeyReq::setTakeOverScanFragment(scanInfo, tTakeOverFragment);
TcKeyReq::setTakeOverScanInfo(scanInfo, tScanInfo);
newOp->theScanInfo = scanInfo;
+ newOp->theDistrKeyIndicator_ = 1;
+ newOp->theDistributionKey = tTakeOverFragment;
}
// Copy the first 8 words of key info from KEYINF20 into TCKEYREQ
@@ -988,7 +949,7 @@ NdbScanOperation::takeOverScanOp(OperationType opType, NdbConnection* pTrans){
if(i < len){
NdbApiSignal* tSignal = theNdb->getSignal();
- newOp->theFirstKEYINFO = tSignal;
+ newOp->theTCREQ->next(tSignal);
Uint32 left = len - i;
while(tSignal && left > KeyInfo::DataLength){
@@ -1123,37 +1084,28 @@ NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo,
Uint32 currLen = theTotalNrOfKeyWordInSignal;
Uint32 remaining = KeyInfo::DataLength - currLen;
Uint32 sizeInBytes = tAttrInfo->m_attrSize * tAttrInfo->m_arraySize;
+ bool tDistrKey = tAttrInfo->m_distributionKey;
- // normalize char bound
- CHARSET_INFO* cs = tAttrInfo->m_cs;
- Uint32 xfrmData[2000];
- if (cs != NULL && aValue != NULL) {
- // current limitation: strxfrm does not increase length
- assert(cs->strxfrm_multiply <= 1);
- unsigned n =
- (*cs->coll->strnxfrm)(cs,
- (uchar*)xfrmData, sizeof(xfrmData),
- (const uchar*)aValue, sizeInBytes);
- while (n < sizeInBytes)
- ((uchar*)xfrmData)[n++] = 0x20;
- aValue = (char*)xfrmData;
- }
+ len = aValue != NULL ? sizeInBytes : 0;
if (len != sizeInBytes && (len != 0)) {
setErrorCodeAbort(4209);
return -1;
}
+
// insert attribute header
- len = aValue != NULL ? sizeInBytes : 0;
Uint32 tIndexAttrId = tAttrInfo->m_attrId;
Uint32 sizeInWords = (len + 3) / 4;
AttributeHeader ah(tIndexAttrId, sizeInWords);
const Uint32 ahValue = ah.m_value;
- const bool aligned = (UintPtr(aValue) & 3) == 0;
+ const Uint32 align = (UintPtr(aValue) & 7);
+ const bool aligned = (tDistrKey && type == BoundEQ) ?
+ (align == 0) : (align & 3) == 0;
+
const bool nobytes = (len & 0x3) == 0;
const Uint32 totalLen = 2 + sizeInWords;
Uint32 tupKeyLen = theTupKeyLen;
- if(remaining > totalLen && aligned && nobytes){
+ if(remaining > totalLen && aligned && nobytes){
Uint32 * dst = theKEYINFOptr + currLen;
* dst ++ = type;
* dst ++ = ahValue;
@@ -1161,12 +1113,12 @@ NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo,
theTotalNrOfKeyWordInSignal = currLen + totalLen;
} else {
if(!aligned || !nobytes){
- Uint32 tempData[2002];
+ Uint32 tempData[2000];
tempData[0] = type;
tempData[1] = ahValue;
+ tempData[2 + (len >> 2)] = 0;
memcpy(tempData+2, aValue, len);
- while ((len & 0x3) != 0)
- ((char*)&tempData[2])[len++] = 0;
+
insertBOUNDS(tempData, 2+sizeInWords);
} else {
Uint32 buf[2] = { type, ahValue };
@@ -1185,11 +1137,11 @@ NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo,
* so it's safe to use [tIndexAttrId]
* (instead of looping as is NdbOperation::equal_impl)
*/
- if(type == BoundEQ && !theTupleKeyDefined[tIndexAttrId][0]){
- theNoOfTupKeyDefined++;
- theTupleKeyDefined[tIndexAttrId][0] = SETBOUND_EQ;
+ if(type == BoundEQ && tDistrKey)
+ {
+ theNoOfTupKeyLeft--;
+ return handle_distribution_key((Uint64*)aValue, sizeInWords);
}
-
return 0;
} else {
setErrorCodeAbort(4228); // XXX wrong code
@@ -1237,14 +1189,29 @@ error:
return -1;
}
-NdbResultSet*
+int
NdbIndexScanOperation::readTuples(LockMode lm,
Uint32 batch,
Uint32 parallel,
- bool order_by){
- NdbResultSet * rs = NdbScanOperation::readTuples(lm, batch, 0);
- if(rs && order_by){
- m_ordered = 1;
+ bool order_by,
+ bool order_desc,
+ bool read_range_no){
+ int res = NdbScanOperation::readTuples(lm, batch, 0);
+ if(!res && read_range_no)
+ {
+ m_read_range_no = 1;
+ Uint32 word = 0;
+ AttributeHeader::init(&word, AttributeHeader::RANGE_NO, 0);
+ if(insertATTRINFO(word) == -1)
+ res = -1;
+ }
+ if(!res && order_by){
+ m_ordered = true;
+ if (order_desc) {
+ m_descending = true;
+ ScanTabReq * req = CAST_PTR(ScanTabReq, theSCAN_TABREQ->getDataPtrSend());
+ ScanTabReq::setDescendingFlag(req->requestInfo, true);
+ }
Uint32 cnt = m_accessTable->getNoOfColumns() - 1;
m_sort_columns = cnt; // -1 for NDB$NODE
m_current_api_receiver = m_sent_receivers_count;
@@ -1263,7 +1230,10 @@ NdbIndexScanOperation::readTuples(LockMode lm,
#endif
}
}
- return rs;
+ m_this_bound_start = 0;
+ m_first_bound_word = theKEYINFOptr;
+
+ return res;
}
void
@@ -1305,22 +1275,23 @@ NdbIndexScanOperation::compare(Uint32 skip, Uint32 cols,
r1 = (skip ? r1->next() : r1);
r2 = (skip ? r2->next() : r2);
-
+ const int jdir = 1 - 2 * (int)m_descending;
+ assert(jdir == 1 || jdir == -1);
while(cols > 0){
Uint32 * d1 = (Uint32*)r1->aRef();
Uint32 * d2 = (Uint32*)r2->aRef();
unsigned r1_null = r1->isNULL();
if((r1_null ^ (unsigned)r2->isNULL())){
- return (r1_null ? -1 : 1);
+ return (r1_null ? -1 : 1) * jdir;
}
const NdbColumnImpl & col = NdbColumnImpl::getImpl(* r1->m_column);
- Uint32 size = (r1->theAttrSize * r1->theArraySize + 3) / 4;
+ Uint32 len = r1->theAttrSize * r1->theArraySize;
if(!r1_null){
- const NdbSqlUtil::Type& sqlType = NdbSqlUtil::getType(col.m_extType);
- int r = (*sqlType.m_cmp)(col.m_cs, d1, d2, size, size);
+ const NdbSqlUtil::Type& sqlType = NdbSqlUtil::getType(col.m_type);
+ int r = (*sqlType.m_cmp)(col.m_cs, d1, len, d2, len, true);
if(r){
assert(r != NdbSqlUtil::CmpUnknown);
- return r;
+ return r * jdir;
}
}
cols--;
@@ -1334,6 +1305,7 @@ int
NdbIndexScanOperation::next_result_ordered(bool fetchAllowed,
bool forceSend){
+ m_curr_row = 0;
Uint32 u_idx = 0, u_last = 0;
Uint32 s_idx = m_current_api_receiver; // first sorted
Uint32 s_last = theParallelism; // last sorted
@@ -1407,7 +1379,7 @@ NdbIndexScanOperation::next_result_ordered(bool fetchAllowed,
s_idx, s_last);
- Uint32 cols = m_sort_columns;
+ Uint32 cols = m_sort_columns + m_read_range_no;
Uint32 skip = m_keyInfo;
while(u_idx < u_last){
u_last--;
@@ -1444,7 +1416,7 @@ NdbIndexScanOperation::next_result_ordered(bool fetchAllowed,
tRec = m_api_receivers[s_idx];
if(s_idx < s_last && tRec->nextResult()){
- tRec->copyout(theReceiver);
+ m_curr_row = tRec->copyout(theReceiver);
if(DEBUG_NEXT_RESULT) ndbout_c("return 0");
return 0;
}
@@ -1663,10 +1635,14 @@ NdbIndexScanOperation::reset_bounds(bool forceSend){
theError.code = 0;
reset_receivers(theParallelism, m_ordered);
- theLastKEYINFO = theFirstKEYINFO;
- theKEYINFOptr = ((KeyInfo*)theFirstKEYINFO->getDataPtrSend())->keyData;
+ theLastKEYINFO = theSCAN_TABREQ->next();
+ theKEYINFOptr = ((KeyInfo*)theLastKEYINFO->getDataPtrSend())->keyData;
theTupKeyLen = 0;
theTotalNrOfKeyWordInSignal = 0;
+ theNoOfTupKeyLeft = m_accessTable->m_noOfDistributionKeys;
+ theDistrKeyIndicator_ = 0;
+ m_this_bound_start = 0;
+ m_first_bound_word = theKEYINFOptr;
m_transConnection
->remove_list((NdbOperation*&)m_transConnection->m_firstExecutedScanOp,
this);
@@ -1675,3 +1651,33 @@ NdbIndexScanOperation::reset_bounds(bool forceSend){
}
return res;
}
+
+int
+NdbIndexScanOperation::end_of_bound(Uint32 no)
+{
+ if(no < (1 << 13)) // Only 12-bits no of ranges
+ {
+ Uint32 bound_head = * m_first_bound_word;
+ bound_head |= (theTupKeyLen - m_this_bound_start) << 16 | (no << 4);
+ * m_first_bound_word = bound_head;
+
+ m_first_bound_word = theKEYINFOptr + theTotalNrOfKeyWordInSignal;;
+ m_this_bound_start = theTupKeyLen;
+ return 0;
+ }
+ return -1;
+}
+
+int
+NdbIndexScanOperation::get_range_no()
+{
+ NdbRecAttr* tRecAttr = m_curr_row;
+ if(m_read_range_no && tRecAttr)
+ {
+ if(m_keyInfo)
+ tRecAttr = tRecAttr->next();
+ Uint32 ret = *(Uint32*)tRecAttr->aRef();
+ return ret;
+ }
+ return -1;
+}
diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbTransaction.cpp
index e1f70160fb7..e32a7ddf70a 100644
--- a/ndb/src/ndbapi/NdbConnection.cpp
+++ b/ndb/src/ndbapi/NdbTransaction.cpp
@@ -16,7 +16,7 @@
#include <ndb_global.h>
#include <NdbOut.hpp>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <NdbOperation.hpp>
#include <NdbScanOperation.hpp>
#include <NdbIndexScanOperation.hpp>
@@ -34,13 +34,13 @@
#include <signaldata/TcHbRep.hpp>
/*****************************************************************************
-NdbConnection( Ndb* aNdb );
+NdbTransaction( Ndb* aNdb );
Return Value: None
Parameters: aNdb: Pointers to the Ndb object
Remark: Creates a connection object.
*****************************************************************************/
-NdbConnection::NdbConnection( Ndb* aNdb ) :
+NdbTransaction::NdbTransaction( Ndb* aNdb ) :
theSendStatus(NotInit),
theCallbackFunction(NULL),
theCallbackObject(NULL),
@@ -89,19 +89,19 @@ NdbConnection::NdbConnection( Ndb* aNdb ) :
CHECK_SZ(m_db_nodes, NdbNodeBitmask::Size);
CHECK_SZ(m_failed_db_nodes, NdbNodeBitmask::Size);
-}//NdbConnection::NdbConnection()
+}//NdbTransaction::NdbTransaction()
/*****************************************************************************
-~NdbConnection();
+~NdbTransaction();
Remark: Deletes the connection object.
*****************************************************************************/
-NdbConnection::~NdbConnection()
+NdbTransaction::~NdbTransaction()
{
- DBUG_ENTER("NdbConnection::~NdbConnection");
+ DBUG_ENTER("NdbTransaction::~NdbTransaction");
theNdb->theImpl->theNdbObjectIdMap.unmap(theId, this);
DBUG_VOID_RETURN;
-}//NdbConnection::~NdbConnection()
+}//NdbTransaction::~NdbTransaction()
/*****************************************************************************
void init();
@@ -109,7 +109,7 @@ void init();
Remark: Initialise connection object for new transaction.
*****************************************************************************/
void
-NdbConnection::init()
+NdbTransaction::init()
{
theListState = NotInList;
theInUseState = true;
@@ -149,7 +149,7 @@ NdbConnection::init()
//
theBlobFlag = false;
thePendingBlobOps = 0;
-}//NdbConnection::init()
+}//NdbTransaction::init()
/*****************************************************************************
setOperationErrorCode(int error);
@@ -158,9 +158,9 @@ Remark: Sets an error code on the connection object from an
operation object.
*****************************************************************************/
void
-NdbConnection::setOperationErrorCode(int error)
+NdbTransaction::setOperationErrorCode(int error)
{
- DBUG_ENTER("NdbConnection::setOperationErrorCode");
+ DBUG_ENTER("NdbTransaction::setOperationErrorCode");
setErrorCode(error);
DBUG_VOID_RETURN;
}
@@ -172,9 +172,9 @@ Remark: Sets an error code on the connection object from an
operation object.
*****************************************************************************/
void
-NdbConnection::setOperationErrorCodeAbort(int error, int abortOption)
+NdbTransaction::setOperationErrorCodeAbort(int error, int abortOption)
{
- DBUG_ENTER("NdbConnection::setOperationErrorCodeAbort");
+ DBUG_ENTER("NdbTransaction::setOperationErrorCodeAbort");
if (abortOption == -1)
abortOption = m_abortOption;
if (theTransactionIsStarted == false) {
@@ -194,20 +194,20 @@ setErrorCode(int anErrorCode);
Remark: Sets an error indication on the connection object.
*****************************************************************************/
void
-NdbConnection::setErrorCode(int error)
+NdbTransaction::setErrorCode(int error)
{
- DBUG_ENTER("NdbConnection::setErrorCode");
+ DBUG_ENTER("NdbTransaction::setErrorCode");
DBUG_PRINT("enter", ("error: %d, theError.code: %d", error, theError.code));
if (theError.code == 0)
theError.code = error;
DBUG_VOID_RETURN;
-}//NdbConnection::setErrorCode()
+}//NdbTransaction::setErrorCode()
int
-NdbConnection::restart(){
- DBUG_ENTER("NdbConnection::restart");
+NdbTransaction::restart(){
+ DBUG_ENTER("NdbTransaction::restart");
if(theCompletionStatus == CompletedSuccess){
releaseCompletedOperations();
Uint64 tTransid = theNdb->theFirstTransId;
@@ -232,23 +232,8 @@ void handleExecuteCompletion(void);
Remark: Handle time-out on a transaction object.
*****************************************************************************/
void
-NdbConnection::handleExecuteCompletion()
+NdbTransaction::handleExecuteCompletion()
{
-
- if (theCompletionStatus == CompletedFailure) {
- NdbOperation* tOpTemp = theFirstExecOpInList;
- while (tOpTemp != NULL) {
-/*****************************************************************************
- * Ensure that all executing operations report failed for each
- * read attribute when failure occurs.
- * We do not want any operations to report both failure and
- * success on different read attributes.
- ****************************************************************************/
- tOpTemp->handleFailedAI_ElemLen();
- tOpTemp = tOpTemp->next();
- }//while
- theReturnStatus = ReturnFailure;
- }//if
/***************************************************************************
* Move the NdbOperation objects from the list of executing
* operations to list of completed
@@ -265,7 +250,7 @@ NdbConnection::handleExecuteCompletion()
}//if
theSendStatus = InitState;
return;
-}//NdbConnection::handleExecuteCompletion()
+}//NdbTransaction::handleExecuteCompletion()
/*****************************************************************************
int execute(ExecType aTypeOfExec, CommitType aTypeOfCommit, int forceSend);
@@ -276,11 +261,11 @@ Parameters : aTypeOfExec: Type of execute.
Remark: Initialise connection object for new transaction.
*****************************************************************************/
int
-NdbConnection::execute(ExecType aTypeOfExec,
+NdbTransaction::execute(ExecType aTypeOfExec,
AbortOption abortOption,
int forceSend)
{
- DBUG_ENTER("NdbConnection::execute");
+ DBUG_ENTER("NdbTransaction::execute");
DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
aTypeOfExec, abortOption));
@@ -410,11 +395,11 @@ NdbConnection::execute(ExecType aTypeOfExec,
}
int
-NdbConnection::executeNoBlobs(ExecType aTypeOfExec,
+NdbTransaction::executeNoBlobs(ExecType aTypeOfExec,
AbortOption abortOption,
int forceSend)
{
- DBUG_ENTER("NdbConnection::executeNoBlobs");
+ DBUG_ENTER("NdbTransaction::executeNoBlobs");
DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
aTypeOfExec, abortOption));
@@ -423,7 +408,7 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec,
// since last execute or since beginning. If this works ok we will continue
// by calling the poll with wait method. This method will return when
// the NDB kernel has completed its task or when 10 seconds have passed.
-// The NdbConnectionCallBack-method will receive the return code of the
+// The NdbTransactionCallBack-method will receive the return code of the
// transaction. The normal methods of reading error codes still apply.
//------------------------------------------------------------------------
Ndb* tNdb = theNdb;
@@ -471,7 +456,7 @@ NdbConnection::executeNoBlobs(ExecType aTypeOfExec,
}
thePendingBlobOps = 0;
DBUG_RETURN(0);
-}//NdbConnection::execute()
+}//NdbTransaction::execute()
/*****************************************************************************
void executeAsynchPrepare(ExecType aTypeOfExec,
@@ -489,12 +474,12 @@ Parameters : aTypeOfExec: Type of execute.
Remark: Prepare a part of a transaction in an asynchronous manner.
*****************************************************************************/
void
-NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
+NdbTransaction::executeAsynchPrepare( ExecType aTypeOfExec,
NdbAsynchCallback aCallback,
void* anyObject,
AbortOption abortOption)
{
- DBUG_ENTER("NdbConnection::executeAsynchPrepare");
+ DBUG_ENTER("NdbTransaction::executeAsynchPrepare");
DBUG_PRINT("enter", ("aTypeOfExec: %d, aCallback: %x, anyObject: %x",
aTypeOfExec, aCallback, anyObject));
@@ -657,14 +642,14 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec,
NdbNodeBitmask::clear(m_db_nodes);
NdbNodeBitmask::clear(m_failed_db_nodes);
DBUG_VOID_RETURN;
-}//NdbConnection::executeAsynchPrepare()
+}//NdbTransaction::executeAsynchPrepare()
-void NdbConnection::close()
+void NdbTransaction::close()
{
theNdb->closeTransaction(this);
}
-int NdbConnection::refresh(){
+int NdbTransaction::refresh(){
return sendTC_HBREP();
}
@@ -676,7 +661,7 @@ Parameters : None.
Remark: Order NDB to refresh the timeout counter of the transaction.
******************************************************************************/
int
-NdbConnection::sendTC_HBREP() // Send a TC_HBREP signal;
+NdbTransaction::sendTC_HBREP() // Send a TC_HBREP signal;
{
NdbApiSignal* tSignal;
Ndb* tNdb = theNdb;
@@ -711,7 +696,7 @@ NdbConnection::sendTC_HBREP() // Send a TC_HBREP signal;
}
return 0;
-}//NdbConnection::sendTC_HBREP()
+}//NdbTransaction::sendTC_HBREP()
/*****************************************************************************
int doSend();
@@ -723,9 +708,9 @@ Remark: Send all operations belonging to this connection.
object from the prepared transactions array on the Ndb-object.
*****************************************************************************/
int
-NdbConnection::doSend()
+NdbTransaction::doSend()
{
- DBUG_ENTER("NdbConnection::doSend");
+ DBUG_ENTER("NdbTransaction::doSend");
/*
This method assumes that at least one operation have been defined. This
@@ -784,7 +769,7 @@ NdbConnection::doSend()
theTransactionIsStarted = false;
theCommitStatus = Aborted;
DBUG_RETURN(-1);
-}//NdbConnection::doSend()
+}//NdbTransaction::doSend()
/**************************************************************************
int sendROLLBACK();
@@ -794,7 +779,7 @@ Parameters : None.
Remark: Order NDB to rollback the transaction.
**************************************************************************/
int
-NdbConnection::sendROLLBACK() // Send a TCROLLBACKREQ signal;
+NdbTransaction::sendROLLBACK() // Send a TCROLLBACKREQ signal;
{
Ndb* tNdb = theNdb;
if ((theTransactionIsStarted == true) &&
@@ -838,7 +823,7 @@ NdbConnection::sendROLLBACK() // Send a TCROLLBACKREQ signal;
return 0;
;
}//if
-}//NdbConnection::sendROLLBACK()
+}//NdbTransaction::sendROLLBACK()
/***************************************************************************
int sendCOMMIT();
@@ -849,7 +834,7 @@ Parameters : None.
Remark: Order NDB to commit the transaction.
***************************************************************************/
int
-NdbConnection::sendCOMMIT() // Send a TC_COMMITREQ signal;
+NdbTransaction::sendCOMMIT() // Send a TC_COMMITREQ signal;
{
NdbApiSignal tSignal(theNdb->theMyRef);
Uint32 tTransId1, tTransId2;
@@ -871,7 +856,7 @@ NdbConnection::sendCOMMIT() // Send a TC_COMMITREQ signal;
} else {
return -1;
}//if
-}//NdbConnection::sendCOMMIT()
+}//NdbTransaction::sendCOMMIT()
/******************************************************************************
void release();
@@ -879,7 +864,7 @@ void release();
Remark: Release all operations.
******************************************************************************/
void
-NdbConnection::release(){
+NdbTransaction::release(){
releaseOperations();
if ( (theTransactionIsStarted == true) &&
((theCommitStatus != Committed) &&
@@ -898,10 +883,10 @@ NdbConnection::release(){
abort();
}
#endif
-}//NdbConnection::release()
+}//NdbTransaction::release()
void
-NdbConnection::releaseOps(NdbOperation* tOp){
+NdbTransaction::releaseOps(NdbOperation* tOp){
while (tOp != NULL) {
NdbOperation* tmp = tOp;
tOp->release();
@@ -916,7 +901,7 @@ void releaseOperations();
Remark: Release all operations.
******************************************************************************/
void
-NdbConnection::releaseOperations()
+NdbTransaction::releaseOperations()
{
// Release any open scans
releaseScanOperations(m_theFirstScanOperation);
@@ -936,15 +921,15 @@ NdbConnection::releaseOperations()
m_theFirstScanOperation = NULL;
m_theLastScanOperation = NULL;
m_firstExecutedScanOp = NULL;
-}//NdbConnection::releaseOperations()
+}//NdbTransaction::releaseOperations()
void
-NdbConnection::releaseCompletedOperations()
+NdbTransaction::releaseCompletedOperations()
{
releaseOps(theCompletedFirstOp);
theCompletedFirstOp = NULL;
theCompletedLastOp = NULL;
-}//NdbConnection::releaseOperations()
+}//NdbTransaction::releaseOperations()
/******************************************************************************
void releaseScanOperations();
@@ -953,7 +938,7 @@ Remark: Release all cursor operations.
(NdbScanOperation and NdbIndexOperation)
******************************************************************************/
void
-NdbConnection::releaseScanOperations(NdbIndexScanOperation* cursorOp)
+NdbTransaction::releaseScanOperations(NdbIndexScanOperation* cursorOp)
{
while(cursorOp != 0){
NdbIndexScanOperation* next = (NdbIndexScanOperation*)cursorOp->next();
@@ -961,7 +946,7 @@ NdbConnection::releaseScanOperations(NdbIndexScanOperation* cursorOp)
theNdb->releaseScanOperation(cursorOp);
cursorOp = next;
}
-}//NdbConnection::releaseScanOperations()
+}//NdbTransaction::releaseScanOperations()
/*****************************************************************************
void releaseExecutedScanOperation();
@@ -969,9 +954,9 @@ void releaseExecutedScanOperation();
Remark: Release scan op when hupp'ed trans closed (save memory)
******************************************************************************/
void
-NdbConnection::releaseExecutedScanOperation(NdbIndexScanOperation* cursorOp)
+NdbTransaction::releaseExecutedScanOperation(NdbIndexScanOperation* cursorOp)
{
- DBUG_ENTER("NdbConnection::releaseExecutedScanOperation");
+ DBUG_ENTER("NdbTransaction::releaseExecutedScanOperation");
DBUG_PRINT("enter", ("this=0x%x op=0x%x", (UintPtr)this, (UintPtr)cursorOp))
// here is one reason to make op lists doubly linked
@@ -992,7 +977,7 @@ NdbConnection::releaseExecutedScanOperation(NdbIndexScanOperation* cursorOp)
}
}
DBUG_VOID_RETURN;
-}//NdbConnection::releaseExecutedScanOperation()
+}//NdbTransaction::releaseExecutedScanOperation()
/*****************************************************************************
NdbOperation* getNdbOperation(const char* aTableName);
@@ -1002,13 +987,13 @@ Return Value Return a pointer to a NdbOperation object if getNdbOperation
Return NULL : In all other case.
Parameters: aTableName : Name of the database table.
Remark: Get an operation from NdbOperation idlelist and get the
- NdbConnection object
+ NdbTransaction object
who was fetch by startTransaction pointing to this operation
getOperation will set the theTableId in the NdbOperation object.
synchronous
******************************************************************************/
NdbOperation*
-NdbConnection::getNdbOperation(const char* aTableName)
+NdbTransaction::getNdbOperation(const char* aTableName)
{
if (theCommitStatus == Started){
NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
@@ -1023,7 +1008,7 @@ NdbConnection::getNdbOperation(const char* aTableName)
setOperationErrorCodeAbort(4114);
return NULL;
-}//NdbConnection::getNdbOperation()
+}//NdbTransaction::getNdbOperation()
/*****************************************************************************
NdbOperation* getNdbOperation(int aTableId);
@@ -1033,13 +1018,13 @@ Return Value Return a pointer to a NdbOperation object if getNdbOperation
Return NULL: In all other case.
Parameters: tableId : Id of the database table beeing deleted.
Remark: Get an operation from NdbOperation object idlelist and
- get the NdbConnection object who was fetch by
+ get the NdbTransaction object who was fetch by
startTransaction pointing to this operation
getOperation will set the theTableId in the NdbOperation
object, synchronous.
*****************************************************************************/
NdbOperation*
-NdbConnection::getNdbOperation(const NdbTableImpl * tab, NdbOperation* aNextOp)
+NdbTransaction::getNdbOperation(const NdbTableImpl * tab, NdbOperation* aNextOp)
{
NdbOperation* tOp;
@@ -1083,15 +1068,15 @@ NdbConnection::getNdbOperation(const NdbTableImpl * tab, NdbOperation* aNextOp)
getNdbOp_error1:
setOperationErrorCodeAbort(4000);
return NULL;
-}//NdbConnection::getNdbOperation()
+}//NdbTransaction::getNdbOperation()
-NdbOperation* NdbConnection::getNdbOperation(const NdbDictionary::Table * table)
+NdbOperation* NdbTransaction::getNdbOperation(const NdbDictionary::Table * table)
{
if (table)
return getNdbOperation(& NdbTableImpl::getImpl(*table));
else
return NULL;
-}//NdbConnection::getNdbOperation()
+}//NdbTransaction::getNdbOperation()
// NdbScanOperation
/*****************************************************************************
@@ -1100,12 +1085,12 @@ NdbScanOperation* getNdbScanOperation(const char* aTableName);
Return Value Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
Return NULL : In all other case.
Parameters: aTableName : Name of the database table.
-Remark: Get an operation from NdbScanOperation idlelist and get the NdbConnection object
+Remark: Get an operation from NdbScanOperation idlelist and get the NdbTransaction object
who was fetch by startTransaction pointing to this operation
getOperation will set the theTableId in the NdbOperation object.synchronous
******************************************************************************/
NdbScanOperation*
-NdbConnection::getNdbScanOperation(const char* aTableName)
+NdbTransaction::getNdbScanOperation(const char* aTableName)
{
if (theCommitStatus == Started){
NdbTableImpl* tab = theNdb->theDictionary->getTable(aTableName);
@@ -1119,78 +1104,104 @@ NdbConnection::getNdbScanOperation(const char* aTableName)
setOperationErrorCodeAbort(4114);
return NULL;
-}//NdbConnection::getNdbScanOperation()
+}//NdbTransaction::getNdbScanOperation()
/*****************************************************************************
-NdbScanOperation* getNdbScanOperation(const char* anIndexName, const char* aTableName);
+NdbScanOperation* getNdbIndexScanOperation(const char* anIndexName, const char* aTableName);
-Return Value Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
+Return Value Return a pointer to a NdbIndexScanOperation object if getNdbIndexScanOperation was succesful.
Return NULL : In all other case.
Parameters: anIndexName : Name of the index to use.
aTableName : Name of the database table.
-Remark: Get an operation from NdbScanOperation idlelist and get the NdbConnection object
+Remark: Get an operation from NdbIndexScanOperation idlelist and get the NdbTransaction object
who was fetch by startTransaction pointing to this operation
- getOperation will set the theTableId in the NdbOperation object.synchronous
+ getOperation will set the theTableId in the NdbIndexScanOperation object.synchronous
******************************************************************************/
NdbIndexScanOperation*
-NdbConnection::getNdbIndexScanOperation(const char* anIndexName,
+NdbTransaction::getNdbIndexScanOperation(const char* anIndexName,
const char* aTableName)
{
NdbIndexImpl* index =
theNdb->theDictionary->getIndex(anIndexName, aTableName);
+ if (index == 0)
+ {
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return 0;
+ }
NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
+ if (table == 0)
+ {
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return 0;
+ }
return getNdbIndexScanOperation(index, table);
}
NdbIndexScanOperation*
-NdbConnection::getNdbIndexScanOperation(const NdbIndexImpl* index,
+NdbTransaction::getNdbIndexScanOperation(const NdbIndexImpl* index,
const NdbTableImpl* table)
{
if (theCommitStatus == Started){
const NdbTableImpl * indexTable = index->getIndexTable();
if (indexTable != 0){
- NdbIndexScanOperation* tOp =
- getNdbScanOperation((NdbTableImpl *) indexTable);
+ NdbIndexScanOperation* tOp = getNdbScanOperation(indexTable);
if(tOp)
{
tOp->m_currentTable = table;
- tOp->m_cursor_type = NdbScanOperation::IndexCursor;
}
return tOp;
} else {
- setOperationErrorCodeAbort(theNdb->theError.code);
+ setOperationErrorCodeAbort(4271);
return NULL;
}//if
}
setOperationErrorCodeAbort(4114);
return NULL;
-}//NdbConnection::getNdbIndexScanOperation()
+}//NdbTransaction::getNdbIndexScanOperation()
+
+NdbIndexScanOperation*
+NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index)
+{
+ if (index)
+ {
+ const NdbDictionary::Table *table=
+ theNdb->theDictionary->getTable(index->getTable());
+
+ if (table)
+ return getNdbIndexScanOperation(index, table);
+
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return NULL;
+ }
+ setOperationErrorCodeAbort(4271);
+ return NULL;
+}
NdbIndexScanOperation*
-NdbConnection::getNdbIndexScanOperation(const NdbDictionary::Index * index,
+NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index,
const NdbDictionary::Table * table)
{
if (index && table)
return getNdbIndexScanOperation(& NdbIndexImpl::getImpl(*index),
& NdbTableImpl::getImpl(*table));
- else
- return NULL;
-}//NdbConnection::getNdbIndexScanOperation()
+ setOperationErrorCodeAbort(4271);
+ return NULL;
+}//NdbTransaction::getNdbIndexScanOperation()
/*****************************************************************************
NdbScanOperation* getNdbScanOperation(int aTableId);
-Return Value Return a pointer to a NdbOperation object if getNdbOperation was succesful.
+Return Value Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
Return NULL: In all other case.
Parameters: tableId : Id of the database table beeing deleted.
-Remark: Get an operation from NdbScanOperation object idlelist and get the NdbConnection
+Remark: Get an operation from NdbScanOperation object idlelist and get the NdbTransaction
object who was fetch by startTransaction pointing to this operation
- getOperation will set the theTableId in the NdbOperation object, synchronous.
+ getOperation will set the theTableId in the NdbScanOperation object, synchronous.
*****************************************************************************/
NdbIndexScanOperation*
-NdbConnection::getNdbScanOperation(const NdbTableImpl * tab)
+NdbTransaction::getNdbScanOperation(const NdbTableImpl * tab)
{
NdbIndexScanOperation* tOp;
@@ -1209,10 +1220,10 @@ NdbConnection::getNdbScanOperation(const NdbTableImpl * tab)
getNdbOp_error1:
setOperationErrorCodeAbort(4000);
return NULL;
-}//NdbConnection::getNdbScanOperation()
+}//NdbTransaction::getNdbScanOperation()
void
-NdbConnection::remove_list(NdbOperation*& list, NdbOperation* op){
+NdbTransaction::remove_list(NdbOperation*& list, NdbOperation* op){
NdbOperation* tmp= list;
if(tmp == op)
list = op->next();
@@ -1225,7 +1236,7 @@ NdbConnection::remove_list(NdbOperation*& list, NdbOperation* op){
}
void
-NdbConnection::define_scan_op(NdbIndexScanOperation * tOp){
+NdbTransaction::define_scan_op(NdbIndexScanOperation * tOp){
// Link scan operation into list of cursor operations
if (m_theLastScanOperation == NULL)
m_theFirstScanOperation = m_theLastScanOperation = tOp;
@@ -1237,13 +1248,13 @@ NdbConnection::define_scan_op(NdbIndexScanOperation * tOp){
}
NdbScanOperation*
-NdbConnection::getNdbScanOperation(const NdbDictionary::Table * table)
+NdbTransaction::getNdbScanOperation(const NdbDictionary::Table * table)
{
if (table)
return getNdbScanOperation(& NdbTableImpl::getImpl(*table));
else
return NULL;
-}//NdbConnection::getNdbScanOperation()
+}//NdbTransaction::getNdbScanOperation()
// IndexOperation
@@ -1251,21 +1262,40 @@ NdbConnection::getNdbScanOperation(const NdbDictionary::Table * table)
NdbIndexOperation* getNdbIndexOperation(const char* anIndexName,
const char* aTableName);
-Return Value Return a pointer to a NdbOperation object if getNdbScanOperation was succesful.
+Return Value Return a pointer to a NdbOperation object if getNdbIndexOperation was succesful.
Return NULL : In all other case.
Parameters: aTableName : Name of the database table.
-Remark: Get an operation from NdbScanOperation idlelist and get the NdbConnection object
- who was fetch by startTransaction pointing to this operation
- getOperation will set the theTableId in the NdbScanOperation object.synchronous
+Remark: Get an operation from NdbIndexOperation idlelist and get the NdbTransaction object
+ who was fetch by startTransaction pointing to this operation
+ getOperation will set the theTableId in the NdbIndexOperation object.synchronous
******************************************************************************/
NdbIndexOperation*
-NdbConnection::getNdbIndexOperation(const char* anIndexName,
+NdbTransaction::getNdbIndexOperation(const char* anIndexName,
const char* aTableName)
{
if (theCommitStatus == Started) {
NdbTableImpl * table = theNdb->theDictionary->getTable(aTableName);
- NdbIndexImpl * index = theNdb->theDictionary->getIndex(anIndexName,
- aTableName);
+ NdbIndexImpl * index;
+
+ if (table == 0)
+ {
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return NULL;
+ }
+
+ if (table->m_frm.get_data())
+ {
+ // 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,
+ aTableName);
+ }
+ else
+ index = theNdb->theDictionary->getIndex(anIndexName,
+ aTableName);
if(table != 0 && index != 0){
return getNdbIndexOperation(index, table);
}
@@ -1275,14 +1305,13 @@ NdbConnection::getNdbIndexOperation(const char* anIndexName,
return NULL;
}
- // table == 0
- setOperationErrorCodeAbort(theNdb->theError.code);
+ setOperationErrorCodeAbort(4243);
return NULL;
}
setOperationErrorCodeAbort(4114);
return 0;
-}//NdbConnection::getNdbIndexOperation()
+}//NdbTransaction::getNdbIndexOperation()
/*****************************************************************************
NdbIndexOperation* getNdbIndexOperation(int anIndexId, int aTableId);
@@ -1290,12 +1319,12 @@ NdbIndexOperation* getNdbIndexOperation(int anIndexId, int aTableId);
Return Value Return a pointer to a NdbIndexOperation object if getNdbIndexOperation was succesful.
Return NULL: In all other case.
Parameters: tableId : Id of the database table beeing deleted.
-Remark: Get an operation from NdbIndexOperation object idlelist and get the NdbConnection
+Remark: Get an operation from NdbIndexOperation object idlelist and get the NdbTransaction
object who was fetch by startTransaction pointing to this operation
getOperation will set the theTableId in the NdbIndexOperation object, synchronous.
*****************************************************************************/
NdbIndexOperation*
-NdbConnection::getNdbIndexOperation(const NdbIndexImpl * anIndex,
+NdbTransaction::getNdbIndexOperation(const NdbIndexImpl * anIndex,
const NdbTableImpl * aTable,
NdbOperation* aNextOp)
{
@@ -1336,18 +1365,37 @@ NdbConnection::getNdbIndexOperation(const NdbIndexImpl * anIndex,
getNdbOp_error1:
setOperationErrorCodeAbort(4000);
return NULL;
-}//NdbConnection::getNdbIndexOperation()
+}//NdbTransaction::getNdbIndexOperation()
NdbIndexOperation*
-NdbConnection::getNdbIndexOperation(const NdbDictionary::Index * index,
+NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index)
+{
+ if (index)
+ {
+ const NdbDictionary::Table *table=
+ theNdb->theDictionary->getTable(index->getTable());
+
+ if (table)
+ return getNdbIndexOperation(index, table);
+
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return NULL;
+ }
+ setOperationErrorCodeAbort(4271);
+ return NULL;
+}
+
+NdbIndexOperation*
+NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index,
const NdbDictionary::Table * table)
{
if (index && table)
return getNdbIndexOperation(& NdbIndexImpl::getImpl(*index),
& NdbTableImpl::getImpl(*table));
- else
- return NULL;
-}//NdbConnection::getNdbIndexOperation()
+
+ setOperationErrorCodeAbort(4271);
+ return NULL;
+}//NdbTransaction::getNdbIndexOperation()
/*******************************************************************************
@@ -1359,7 +1407,7 @@ Parameters: aSignal: The signal object pointer.
Remark: Sets theRestartGCI in the NDB object.
*******************************************************************************/
int
-NdbConnection::receiveDIHNDBTAMPER(NdbApiSignal* aSignal)
+NdbTransaction::receiveDIHNDBTAMPER(NdbApiSignal* aSignal)
{
if (theStatus != Connecting) {
return -1;
@@ -1368,7 +1416,7 @@ NdbConnection::receiveDIHNDBTAMPER(NdbApiSignal* aSignal)
theStatus = Connected;
}//if
return 0;
-}//NdbConnection::receiveDIHNDBTAMPER()
+}//NdbTransaction::receiveDIHNDBTAMPER()
/*******************************************************************************
int receiveTCSEIZECONF(NdbApiSignal* aSignal);
@@ -1379,7 +1427,7 @@ Parameters: aSignal: The signal object pointer.
Remark: Sets TC Connect pointer at reception of TCSEIZECONF.
*******************************************************************************/
int
-NdbConnection::receiveTCSEIZECONF(NdbApiSignal* aSignal)
+NdbTransaction::receiveTCSEIZECONF(NdbApiSignal* aSignal)
{
if (theStatus != Connecting)
{
@@ -1390,7 +1438,7 @@ NdbConnection::receiveTCSEIZECONF(NdbApiSignal* aSignal)
theStatus = Connected;
}
return 0;
-}//NdbConnection::receiveTCSEIZECONF()
+}//NdbTransaction::receiveTCSEIZECONF()
/*******************************************************************************
int receiveTCSEIZEREF(NdbApiSignal* aSignal);
@@ -1401,18 +1449,22 @@ Parameters: aSignal: The signal object pointer.
Remark: Sets TC Connect pointer.
*******************************************************************************/
int
-NdbConnection::receiveTCSEIZEREF(NdbApiSignal* aSignal)
+NdbTransaction::receiveTCSEIZEREF(NdbApiSignal* aSignal)
{
+ DBUG_ENTER("NdbTransaction::receiveTCSEIZEREF");
if (theStatus != Connecting)
{
- return -1;
+ DBUG_RETURN(-1);
} else
{
theStatus = ConnectFailure;
theNdb->theError.code = aSignal->readData(2);
- return 0;
+ DBUG_PRINT("info",("error code %d, %s",
+ theNdb->getNdbError().code,
+ theNdb->getNdbError().message));
+ DBUG_RETURN(0);
}
-}//NdbConnection::receiveTCSEIZEREF()
+}//NdbTransaction::receiveTCSEIZEREF()
/*******************************************************************************
int receiveTCRELEASECONF(NdbApiSignal* aSignal);
@@ -1423,7 +1475,7 @@ Parameters: aSignal: The signal object pointer.
Remark: DisConnect TC Connect pointer to NDBAPI.
*******************************************************************************/
int
-NdbConnection::receiveTCRELEASECONF(NdbApiSignal* aSignal)
+NdbTransaction::receiveTCRELEASECONF(NdbApiSignal* aSignal)
{
if (theStatus != DisConnecting)
{
@@ -1433,7 +1485,7 @@ NdbConnection::receiveTCRELEASECONF(NdbApiSignal* aSignal)
theStatus = NotConnected;
}
return 0;
-}//NdbConnection::receiveTCRELEASECONF()
+}//NdbTransaction::receiveTCRELEASECONF()
/*******************************************************************************
int receiveTCRELEASEREF(NdbApiSignal* aSignal);
@@ -1444,7 +1496,7 @@ Parameters: aSignal: The signal object pointer.
Remark: DisConnect TC Connect pointer to NDBAPI Failure.
*******************************************************************************/
int
-NdbConnection::receiveTCRELEASEREF(NdbApiSignal* aSignal)
+NdbTransaction::receiveTCRELEASEREF(NdbApiSignal* aSignal)
{
if (theStatus != DisConnecting) {
return -1;
@@ -1453,7 +1505,7 @@ NdbConnection::receiveTCRELEASEREF(NdbApiSignal* aSignal)
theNdb->theError.code = aSignal->readData(2);
return 0;
}//if
-}//NdbConnection::receiveTCRELEASEREF()
+}//NdbTransaction::receiveTCRELEASEREF()
/******************************************************************************
int receiveTC_COMMITCONF(NdbApiSignal* aSignal);
@@ -1464,7 +1516,7 @@ Parameters: aSignal: The signal object pointer.
Remark:
******************************************************************************/
int
-NdbConnection::receiveTC_COMMITCONF(const TcCommitConf * commitConf)
+NdbTransaction::receiveTC_COMMITCONF(const TcCommitConf * commitConf)
{
if(checkState_TransId(&commitConf->transId1)){
theCommitStatus = Committed;
@@ -1476,7 +1528,7 @@ NdbConnection::receiveTC_COMMITCONF(const TcCommitConf * commitConf)
#endif
}
return -1;
-}//NdbConnection::receiveTC_COMMITCONF()
+}//NdbTransaction::receiveTC_COMMITCONF()
/******************************************************************************
int receiveTC_COMMITREF(NdbApiSignal* aSignal);
@@ -1487,13 +1539,14 @@ Parameters: aSignal: The signal object pointer.
Remark:
******************************************************************************/
int
-NdbConnection::receiveTC_COMMITREF(NdbApiSignal* aSignal)
+NdbTransaction::receiveTC_COMMITREF(NdbApiSignal* aSignal)
{
const TcCommitRef * ref = CAST_CONSTPTR(TcCommitRef, aSignal->getDataPtr());
if(checkState_TransId(&ref->transId1)){
setOperationErrorCodeAbort(ref->errorCode);
theCommitStatus = Aborted;
theCompletionStatus = CompletedFailure;
+ theReturnStatus = ReturnFailure;
return 0;
} else {
#ifdef NDB_NO_DROPPED_SIGNAL
@@ -1502,7 +1555,7 @@ NdbConnection::receiveTC_COMMITREF(NdbApiSignal* aSignal)
}
return -1;
-}//NdbConnection::receiveTC_COMMITREF()
+}//NdbTransaction::receiveTC_COMMITREF()
/******************************************************************************
int receiveTCROLLBACKCONF(NdbApiSignal* aSignal);
@@ -1513,7 +1566,7 @@ Parameters: aSignal: The signal object pointer.
Remark:
******************************************************************************/
int
-NdbConnection::receiveTCROLLBACKCONF(NdbApiSignal* aSignal)
+NdbTransaction::receiveTCROLLBACKCONF(NdbApiSignal* aSignal)
{
if(checkState_TransId(aSignal->getDataPtr() + 1)){
theCommitStatus = Aborted;
@@ -1526,7 +1579,7 @@ NdbConnection::receiveTCROLLBACKCONF(NdbApiSignal* aSignal)
}
return -1;
-}//NdbConnection::receiveTCROLLBACKCONF()
+}//NdbTransaction::receiveTCROLLBACKCONF()
/*******************************************************************************
int receiveTCROLLBACKREF(NdbApiSignal* aSignal);
@@ -1537,12 +1590,13 @@ Parameters: aSignal: The signal object pointer.
Remark:
*******************************************************************************/
int
-NdbConnection::receiveTCROLLBACKREF(NdbApiSignal* aSignal)
+NdbTransaction::receiveTCROLLBACKREF(NdbApiSignal* aSignal)
{
if(checkState_TransId(aSignal->getDataPtr() + 1)){
setOperationErrorCodeAbort(aSignal->readData(4));
theCommitStatus = Aborted;
theCompletionStatus = CompletedFailure;
+ theReturnStatus = ReturnFailure;
return 0;
} else {
#ifdef NDB_NO_DROPPED_SIGNAL
@@ -1551,7 +1605,7 @@ NdbConnection::receiveTCROLLBACKREF(NdbApiSignal* aSignal)
}
return -1;
-}//NdbConnection::receiveTCROLLBACKREF()
+}//NdbTransaction::receiveTCROLLBACKREF()
/*****************************************************************************
int receiveTCROLLBACKREP( NdbApiSignal* aSignal)
@@ -1563,7 +1617,7 @@ Parameters: aSignal: the signal object that contains the
Remark: Handles the reception of the ROLLBACKREP signal.
*****************************************************************************/
int
-NdbConnection::receiveTCROLLBACKREP( NdbApiSignal* aSignal)
+NdbTransaction::receiveTCROLLBACKREP( NdbApiSignal* aSignal)
{
/****************************************************************************
Check that we are expecting signals from this transaction and that it doesn't
@@ -1582,6 +1636,7 @@ transactions.
/**********************************************************************/
theCompletionStatus = CompletedFailure;
theCommitStatus = Aborted;
+ theReturnStatus = ReturnFailure;
return 0;
} else {
#ifdef NDB_NO_DROPPED_SIGNAL
@@ -1590,7 +1645,7 @@ transactions.
}
return -1;
-}//NdbConnection::receiveTCROLLBACKREP()
+}//NdbTransaction::receiveTCROLLBACKREP()
/*******************************************************************************
int receiveTCKEYCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
@@ -1601,7 +1656,7 @@ Parameters: aSignal: The signal object pointer.
Remark:
*******************************************************************************/
int
-NdbConnection::receiveTCKEYCONF(const TcKeyConf * keyConf, Uint32 aDataLength)
+NdbTransaction::receiveTCKEYCONF(const TcKeyConf * keyConf, Uint32 aDataLength)
{
NdbReceiver* tOp;
const Uint32 tTemp = keyConf->confInfo;
@@ -1630,6 +1685,7 @@ from other transactions.
done = 1;
tOp->setErrorCode(4119);
theCompletionStatus = CompletedFailure;
+ theReturnStatus = NdbTransaction::ReturnFailure;
}
}
tNoComp += done;
@@ -1659,6 +1715,7 @@ from other transactions.
/**********************************************************************/
theError.code = 4011;
theCompletionStatus = CompletedFailure;
+ theReturnStatus = NdbTransaction::ReturnFailure;
theCommitStatus = Aborted;
return 0;
}//if
@@ -1673,7 +1730,7 @@ from other transactions.
}
return -1;
-}//NdbConnection::receiveTCKEYCONF()
+}//NdbTransaction::receiveTCKEYCONF()
/*****************************************************************************
int receiveTCKEY_FAILCONF( NdbApiSignal* aSignal)
@@ -1685,7 +1742,7 @@ Parameters: aSignal: the signal object that contains the
Remark: Handles the reception of the TCKEY_FAILCONF signal.
*****************************************************************************/
int
-NdbConnection::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)
+NdbTransaction::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)
{
NdbOperation* tOp;
/*
@@ -1718,6 +1775,7 @@ NdbConnection::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)
case NdbOperation::OpenScanRequest:
case NdbOperation::OpenRangeScanRequest:
theCompletionStatus = CompletedFailure;
+ theReturnStatus = NdbTransaction::ReturnFailure;
setOperationErrorCodeAbort(4115);
tOp = NULL;
break;
@@ -1735,7 +1793,7 @@ NdbConnection::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)
#endif
}
return -1;
-}//NdbConnection::receiveTCKEY_FAILCONF()
+}//NdbTransaction::receiveTCKEY_FAILCONF()
/*************************************************************************
int receiveTCKEY_FAILREF( NdbApiSignal* aSignal)
@@ -1747,7 +1805,7 @@ Parameters: aSignal: the signal object that contains the
Remark: Handles the reception of the TCKEY_FAILREF signal.
**************************************************************************/
int
-NdbConnection::receiveTCKEY_FAILREF(NdbApiSignal* aSignal)
+NdbTransaction::receiveTCKEY_FAILREF(NdbApiSignal* aSignal)
{
/*
Check that we are expecting signals from this transaction and
@@ -1759,18 +1817,19 @@ NdbConnection::receiveTCKEY_FAILREF(NdbApiSignal* aSignal)
We received an indication of that this transaction was aborted due to a
node failure.
*/
- if (theSendStatus == NdbConnection::sendTC_ROLLBACK) {
+ if (theSendStatus == NdbTransaction::sendTC_ROLLBACK) {
/*
We were in the process of sending a rollback anyways. We will
report it as a success.
*/
- theCompletionStatus = NdbConnection::CompletedSuccess;
+ theCompletionStatus = NdbTransaction::CompletedSuccess;
} else {
- theCompletionStatus = NdbConnection::CompletedFailure;
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ theCompletionStatus = NdbTransaction::CompletedFailure;
theError.code = 4031;
}//if
theReleaseOnClose = true;
- theCommitStatus = NdbConnection::Aborted;
+ theCommitStatus = NdbTransaction::Aborted;
return 0;
} else {
#ifdef VM_TRACE
@@ -1778,7 +1837,7 @@ NdbConnection::receiveTCKEY_FAILREF(NdbApiSignal* aSignal)
#endif
}
return -1;
-}//NdbConnection::receiveTCKEY_FAILREF()
+}//NdbTransaction::receiveTCKEY_FAILREF()
/******************************************************************************
int receiveTCINDXCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
@@ -1789,7 +1848,7 @@ Parameters: aSignal: The signal object pointer.
Remark:
******************************************************************************/
int
-NdbConnection::receiveTCINDXCONF(const TcIndxConf * indxConf,
+NdbTransaction::receiveTCINDXCONF(const TcIndxConf * indxConf,
Uint32 aDataLength)
{
if(checkState_TransId(&indxConf->transId1)){
@@ -1823,8 +1882,9 @@ NdbConnection::receiveTCINDXCONF(const TcIndxConf * indxConf,
// no Commit flag set. This is clearly an anomaly.
/**********************************************************************/
theError.code = 4011;
- theCompletionStatus = NdbConnection::CompletedFailure;
- theCommitStatus = NdbConnection::Aborted;
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ theCommitStatus = NdbTransaction::Aborted;
+ theReturnStatus = NdbTransaction::ReturnFailure;
return 0;
}//if
if (tNoComp >= tNoSent) {
@@ -1838,7 +1898,7 @@ NdbConnection::receiveTCINDXCONF(const TcIndxConf * indxConf,
}
return -1;
-}//NdbConnection::receiveTCINDXCONF()
+}//NdbTransaction::receiveTCINDXCONF()
/*****************************************************************************
int receiveTCINDXREF( NdbApiSignal* aSignal)
@@ -1850,7 +1910,7 @@ Parameters: aSignal: the signal object that contains the
Remark: Handles the reception of the TCINDXREF signal.
*****************************************************************************/
int
-NdbConnection::receiveTCINDXREF( NdbApiSignal* aSignal)
+NdbTransaction::receiveTCINDXREF( NdbApiSignal* aSignal)
{
if(checkState_TransId(aSignal->getDataPtr()+1)){
theError.code = aSignal->readData(4); // Override any previous errors
@@ -1862,8 +1922,9 @@ NdbConnection::receiveTCINDXREF( NdbApiSignal* aSignal)
/* and we only need to report completion and return with the */
/* error code to the application. */
/**********************************************************************/
- theCompletionStatus = NdbConnection::CompletedFailure;
- theCommitStatus = NdbConnection::Aborted;
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ theCommitStatus = NdbTransaction::Aborted;
+ theReturnStatus = NdbTransaction::ReturnFailure;
return 0;
} else {
#ifdef NDB_NO_DROPPED_SIGNAL
@@ -1872,7 +1933,7 @@ NdbConnection::receiveTCINDXREF( NdbApiSignal* aSignal)
}
return -1;
-}//NdbConnection::receiveTCINDXREF()
+}//NdbTransaction::receiveTCINDXREF()
/*******************************************************************************
int OpCompletedFailure();
@@ -1883,12 +1944,12 @@ Parameters: aErrorCode: The error code.
Remark: An operation was completed with failure.
*******************************************************************************/
int
-NdbConnection::OpCompleteFailure(Uint8 abortOption, bool setFailure)
+NdbTransaction::OpCompleteFailure(Uint8 abortOption, bool setFailure)
{
Uint32 tNoComp = theNoOfOpCompleted;
Uint32 tNoSent = theNoOfOpSent;
if (setFailure)
- theCompletionStatus = NdbConnection::CompletedFailure;
+ theCompletionStatus = NdbTransaction::CompletedFailure;
tNoComp++;
theNoOfOpCompleted = tNoComp;
if (tNoComp == tNoSent) {
@@ -1913,7 +1974,7 @@ NdbConnection::OpCompleteFailure(Uint8 abortOption, bool setFailure)
} else {
return -1; // Continue waiting for more signals
}//if
-}//NdbConnection::OpCompleteFailure()
+}//NdbTransaction::OpCompleteFailure()
/******************************************************************************
int OpCompleteSuccess();
@@ -1923,7 +1984,7 @@ Return Value: Return 0 : OpCompleteSuccess was successful.
Remark: An operation was completed with success.
*******************************************************************************/
int
-NdbConnection::OpCompleteSuccess()
+NdbTransaction::OpCompleteSuccess()
{
Uint32 tNoComp = theNoOfOpCompleted;
Uint32 tNoSent = theNoOfOpSent;
@@ -1936,10 +1997,11 @@ NdbConnection::OpCompleteSuccess()
} else {
setOperationErrorCodeAbort(4113); // Too many operations,
// stop waiting for more
- theCompletionStatus = NdbConnection::CompletedFailure;
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ theReturnStatus = NdbTransaction::ReturnFailure;
return 0;
}//if
-}//NdbConnection::OpCompleteSuccess()
+}//NdbTransaction::OpCompleteSuccess()
/******************************************************************************
int getGCI();
@@ -1947,13 +2009,13 @@ NdbConnection::OpCompleteSuccess()
Remark: Get global checkpoint identity of the transaction
*******************************************************************************/
int
-NdbConnection::getGCI()
+NdbTransaction::getGCI()
{
- if (theCommitStatus == NdbConnection::Committed) {
+ if (theCommitStatus == NdbTransaction::Committed) {
return theGlobalCheckpointId;
}//if
return 0;
-}//NdbConnection::getGCI()
+}//NdbTransaction::getGCI()
/*******************************************************************************
Uint64 getTransactionId(void);
@@ -1961,31 +2023,31 @@ Uint64 getTransactionId(void);
Remark: Get the transaction identity.
*******************************************************************************/
Uint64
-NdbConnection::getTransactionId()
+NdbTransaction::getTransactionId()
{
return theTransactionId;
-}//NdbConnection::getTransactionId()
+}//NdbTransaction::getTransactionId()
-NdbConnection::CommitStatusType
-NdbConnection::commitStatus()
+NdbTransaction::CommitStatusType
+NdbTransaction::commitStatus()
{
return theCommitStatus;
-}//NdbConnection::commitStatus()
+}//NdbTransaction::commitStatus()
int
-NdbConnection::getNdbErrorLine()
+NdbTransaction::getNdbErrorLine()
{
return theErrorLine;
}
NdbOperation*
-NdbConnection::getNdbErrorOperation()
+NdbTransaction::getNdbErrorOperation()
{
return theErrorOperation;
-}//NdbConnection::getNdbErrorOperation()
+}//NdbTransaction::getNdbErrorOperation()
const NdbOperation *
-NdbConnection::getNextCompletedOperation(const NdbOperation * current) const {
+NdbTransaction::getNextCompletedOperation(const NdbOperation * current) const {
if(current == 0)
return theCompletedFirstOp;
return current->theNext;
@@ -1994,7 +2056,7 @@ NdbConnection::getNextCompletedOperation(const NdbOperation * current) const {
#ifdef VM_TRACE
#define CASE(x) case x: ndbout << " " << #x; break
void
-NdbConnection::printState()
+NdbTransaction::printState()
{
ndbout << "con=" << hex << this << dec;
ndbout << " node=" << getConnectedNodeId();
@@ -2047,7 +2109,7 @@ NdbConnection::printState()
#endif
int
-NdbConnection::report_node_failure(Uint32 id){
+NdbTransaction::report_node_failure(Uint32 id){
NdbNodeBitmask::set(m_failed_db_nodes, id);
if(!NdbNodeBitmask::get(m_db_nodes, id))
{
@@ -2066,22 +2128,28 @@ NdbConnection::report_node_failure(Uint32 id){
const Uint32 len = TcKeyConf::SimpleReadBit | id;
Uint32 tNoComp = theNoOfOpCompleted;
Uint32 tNoSent = theNoOfOpSent;
+ Uint32 count = 0;
while(tmp != 0)
{
if(tmp->theReceiver.m_expected_result_length == len &&
tmp->theReceiver.m_received_result_length == 0)
{
- tNoComp++;
+ count++;
tmp->theError.code = 4119;
}
tmp = tmp->next();
}
+ tNoComp += count;
theNoOfOpCompleted = tNoComp;
- if(tNoComp == tNoSent)
+ if(count)
{
- theError.code = 4119;
- theCompletionStatus = NdbConnection::CompletedFailure;
- return 1;
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ if(tNoComp == tNoSent)
+ {
+ theError.code = 4119;
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ return 1;
+ }
}
return 0;
}
diff --git a/ndb/src/ndbapi/NdbConnectionScan.cpp b/ndb/src/ndbapi/NdbTransactionScan.cpp
index b0c546c512a..4c507f6ab8c 100644
--- a/ndb/src/ndbapi/NdbConnectionScan.cpp
+++ b/ndb/src/ndbapi/NdbTransactionScan.cpp
@@ -15,22 +15,10 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*****************************************************************************
- * Name: NdbConnectionScan.cpp
- * Include:
- * Link:
- * Author: UABRONM MikaelRonström UAB/M/MT
- * QABJKAM Jonas Kamf UAB/M/MT
- * Date: 2000-06-12
- * Version: 0.1
- * Description: Interface between Application and NDB
- * Documentation:
- * Adjust: 2000-06-12 UABRONM First version.
- ****************************************************************************/
#include <ndb_global.h>
#include <Ndb.hpp>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <NdbOperation.hpp>
#include <NdbScanOperation.hpp>
#include "NdbApiSignal.hpp"
@@ -52,7 +40,7 @@
*
****************************************************************************/
int
-NdbConnection::receiveSCAN_TABREF(NdbApiSignal* aSignal){
+NdbTransaction::receiveSCAN_TABREF(NdbApiSignal* aSignal){
const ScanTabRef * ref = CAST_CONSTPTR(ScanTabRef, aSignal->getDataPtr());
if(checkState_TransId(&ref->transId1)){
@@ -93,7 +81,7 @@ NdbConnection::receiveSCAN_TABREF(NdbApiSignal* aSignal){
*
*****************************************************************************/
int
-NdbConnection::receiveSCAN_TABCONF(NdbApiSignal* aSignal,
+NdbTransaction::receiveSCAN_TABCONF(NdbApiSignal* aSignal,
const Uint32 * ops, Uint32 len)
{
const ScanTabConf * conf = CAST_CONSTPTR(ScanTabConf, aSignal->getDataPtr());
diff --git a/ndb/src/ndbapi/Ndberr.cpp b/ndb/src/ndbapi/Ndberr.cpp
index a8b968da03f..b05818de6f1 100644
--- a/ndb/src/ndbapi/Ndberr.cpp
+++ b/ndb/src/ndbapi/Ndberr.cpp
@@ -19,9 +19,9 @@
#include "NdbImpl.hpp"
#include "NdbDictionaryImpl.hpp"
#include <NdbOperation.hpp>
-#include <NdbConnection.hpp>
+#include <NdbTransaction.hpp>
#include <NdbBlob.hpp>
-
+#include "NdbEventOperationImpl.hpp"
static void
update(const NdbError & _err){
@@ -55,7 +55,7 @@ NdbDictionaryImpl::getNdbError() const {
const
NdbError &
-NdbConnection::getNdbError() const {
+NdbTransaction::getNdbError() const {
update(theError);
return theError;
}
@@ -73,3 +73,10 @@ NdbBlob::getNdbError() const {
update(theError);
return theError;
}
+
+const
+NdbError &
+NdbEventOperationImpl::getNdbError() const {
+ update(m_error);
+ return m_error;
+}
diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp
index 1caebe436ef..c550701229c 100644
--- a/ndb/src/ndbapi/Ndbif.cpp
+++ b/ndb/src/ndbapi/Ndbif.cpp
@@ -19,12 +19,12 @@
#include "NdbApiSignal.hpp"
#include "NdbImpl.hpp"
-#include "NdbOperation.hpp"
-#include "NdbIndexOperation.hpp"
-#include "NdbScanOperation.hpp"
-#include "NdbConnection.hpp"
-#include "NdbRecAttr.hpp"
-#include "NdbReceiver.hpp"
+#include <NdbTransaction.hpp>
+#include <NdbOperation.hpp>
+#include <NdbIndexOperation.hpp>
+#include <NdbScanOperation.hpp>
+#include <NdbRecAttr.hpp>
+#include <NdbReceiver.hpp>
#include "API.hpp"
#include <signaldata/TcCommit.hpp>
@@ -113,9 +113,9 @@ Ndb::init(int aMaxNoOfTransactions)
}//if
theMaxNoOfTransactions = tMaxNoOfTransactions;
- thePreparedTransactionsArray = new NdbConnection* [tMaxNoOfTransactions];
- theSentTransactionsArray = new NdbConnection* [tMaxNoOfTransactions];
- theCompletedTransactionsArray = new NdbConnection* [tMaxNoOfTransactions];
+ thePreparedTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions];
+ theSentTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions];
+ theCompletedTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions];
if ((thePreparedTransactionsArray == NULL) ||
(theSentTransactionsArray == NULL) ||
@@ -272,11 +272,11 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId)
{
Uint32 tNoSentTransactions = theNoOfSentTransactions;
for (int i = tNoSentTransactions - 1; i >= 0; i--) {
- NdbConnection* localCon = theSentTransactionsArray[i];
+ NdbTransaction* localCon = theSentTransactionsArray[i];
if (localCon->getConnectedNodeId() == aNodeId) {
- const NdbConnection::SendStatusType sendStatus = localCon->theSendStatus;
- if (sendStatus == NdbConnection::sendTC_OP ||
- sendStatus == NdbConnection::sendTC_COMMIT) {
+ const NdbTransaction::SendStatusType sendStatus = localCon->theSendStatus;
+ if (sendStatus == NdbTransaction::sendTC_OP ||
+ sendStatus == NdbTransaction::sendTC_COMMIT) {
/*
A transaction was interrupted in the prepare phase by a node
failure. Since the transaction was not found in the phase
@@ -284,13 +284,13 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId)
we report a normal node failure abort.
*/
localCon->setOperationErrorCodeAbort(4010);
- localCon->theCompletionStatus = NdbConnection::CompletedFailure;
- } else if (sendStatus == NdbConnection::sendTC_ROLLBACK) {
+ localCon->theCompletionStatus = NdbTransaction::CompletedFailure;
+ } else if (sendStatus == NdbTransaction::sendTC_ROLLBACK) {
/*
We aimed for abort and abort we got even if it was by a node
failure. We will thus report it as a success.
*/
- localCon->theCompletionStatus = NdbConnection::CompletedSuccess;
+ localCon->theCompletionStatus = NdbTransaction::CompletedSuccess;
} else {
#ifdef VM_TRACE
printState("abortTransactionsAfterNodeFailure %x", this);
@@ -302,7 +302,8 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId)
intact since the node was failing and they were aborted. Thus we
set commit state to Aborted and set state to release on close.
*/
- localCon->theCommitStatus = NdbConnection::Aborted;
+ localCon->theReturnStatus = NdbTransaction::ReturnFailure;
+ localCon->theCommitStatus = NdbTransaction::Aborted;
localCon->theReleaseOnClose = true;
completedTransaction(localCon);
}
@@ -325,7 +326,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
{
NdbOperation* tOp;
NdbIndexOperation* tIndexOp;
- NdbConnection* tCon;
+ NdbTransaction* tCon;
int tReturnCode = -1;
const Uint32* tDataPtr = aSignal->getDataPtr();
const Uint32 tWaitState = theImpl->theWaiter.m_state;
@@ -355,14 +356,14 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
tCon = void2con(tFirstDataPtr);
if ((tCon->checkMagicNumber() == 0) &&
- (tCon->theSendStatus == NdbConnection::sendTC_OP)) {
+ (tCon->theSendStatus == NdbTransaction::sendTC_OP)) {
tReturnCode = tCon->receiveTCKEYCONF(keyConf, tLen);
if (tReturnCode != -1) {
completedTransaction(tCon);
}//if
if(TcKeyConf::getMarkerFlag(keyConf->confInfo)){
- NdbConnection::sendTC_COMMIT_ACK(theCommitAckSignal,
+ NdbTransaction::sendTC_COMMIT_ACK(theCommitAckSignal,
keyConf->transId1,
keyConf->transId2,
aTCRef);
@@ -387,24 +388,24 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
com = tRec->execTRANSID_AI(tDataPtr + TransIdAI::HeaderLength,
tLen - TransIdAI::HeaderLength);
}
+
+ if(com == 0)
+ return;
- if(com == 1){
- switch(tRec->getType()){
- case NdbReceiver::NDB_OPERATION:
- case NdbReceiver::NDB_INDEX_OPERATION:
- if(tCon->OpCompleteSuccess() != -1){
- completedTransaction(tCon);
- return;
- }
- break;
- case NdbReceiver::NDB_SCANRECEIVER:
- tCon->theScanningOp->receiver_delivered(tRec);
- theImpl->theWaiter.m_state = (((WaitSignalType) tWaitState) == WAIT_SCAN ?
- (Uint32) NO_WAIT : tWaitState);
- break;
- default:
- goto InvalidSignal;
+ switch(tRec->getType()){
+ case NdbReceiver::NDB_OPERATION:
+ case NdbReceiver::NDB_INDEX_OPERATION:
+ if(tCon->OpCompleteSuccess() != -1){
+ completedTransaction(tCon);
}
+ return;
+ case NdbReceiver::NDB_SCANRECEIVER:
+ tCon->theScanningOp->receiver_delivered(tRec);
+ theImpl->theWaiter.m_state = (((WaitSignalType) tWaitState) == WAIT_SCAN ?
+ (Uint32) NO_WAIT : tWaitState);
+ break;
+ default:
+ goto InvalidSignal;
}
break;
} else {
@@ -426,8 +427,8 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
if (tOp->checkMagicNumber(false) == 0) {
tCon = tOp->theNdbCon;
if (tCon != NULL) {
- if ((tCon->theSendStatus == NdbConnection::sendTC_OP) ||
- (tCon->theSendStatus == NdbConnection::sendTC_COMMIT)) {
+ if ((tCon->theSendStatus == NdbTransaction::sendTC_OP) ||
+ (tCon->theSendStatus == NdbTransaction::sendTC_COMMIT)) {
tReturnCode = tCon->receiveTCKEY_FAILCONF(failConf);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -441,7 +442,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
#endif
}
if(tFirstData & 1){
- NdbConnection::sendTC_COMMIT_ACK(theCommitAckSignal,
+ NdbTransaction::sendTC_COMMIT_ACK(theCommitAckSignal,
failConf->transId1,
failConf->transId2,
aTCRef);
@@ -456,8 +457,8 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
if (tOp->checkMagicNumber(false) == 0) {
tCon = tOp->theNdbCon;
if (tCon != NULL) {
- if ((tCon->theSendStatus == NdbConnection::sendTC_OP) ||
- (tCon->theSendStatus == NdbConnection::sendTC_ROLLBACK)) {
+ if ((tCon->theSendStatus == NdbTransaction::sendTC_OP) ||
+ (tCon->theSendStatus == NdbTransaction::sendTC_ROLLBACK)) {
tReturnCode = tCon->receiveTCKEY_FAILREF(aSignal);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -482,7 +483,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
if (tOp->checkMagicNumber() == 0) {
tCon = tOp->theNdbCon;
if (tCon != NULL) {
- if (tCon->theSendStatus == NdbConnection::sendTC_OP) {
+ if (tCon->theSendStatus == NdbTransaction::sendTC_OP) {
tReturnCode = tOp->receiveTCKEYREF(aSignal);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -505,14 +506,14 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
tCon = void2con(tFirstDataPtr);
if ((tCon->checkMagicNumber() == 0) &&
- (tCon->theSendStatus == NdbConnection::sendTC_COMMIT)) {
+ (tCon->theSendStatus == NdbTransaction::sendTC_COMMIT)) {
tReturnCode = tCon->receiveTC_COMMITCONF(commitConf);
if (tReturnCode != -1) {
completedTransaction(tCon);
}//if
if(tFirstData & 1){
- NdbConnection::sendTC_COMMIT_ACK(theCommitAckSignal,
+ NdbTransaction::sendTC_COMMIT_ACK(theCommitAckSignal,
commitConf->transId1,
commitConf->transId2,
aTCRef);
@@ -530,7 +531,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
tCon = void2con(tFirstDataPtr);
if ((tCon->checkMagicNumber() == 0) &&
- (tCon->theSendStatus == NdbConnection::sendTC_COMMIT)) {
+ (tCon->theSendStatus == NdbTransaction::sendTC_COMMIT)) {
tReturnCode = tCon->receiveTC_COMMITREF(aSignal);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -545,7 +546,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
tCon = void2con(tFirstDataPtr);
if ((tCon->checkMagicNumber() == 0) &&
- (tCon->theSendStatus == NdbConnection::sendTC_ROLLBACK)) {
+ (tCon->theSendStatus == NdbTransaction::sendTC_ROLLBACK)) {
tReturnCode = tCon->receiveTCROLLBACKCONF(aSignal);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -560,7 +561,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
tCon = void2con(tFirstDataPtr);
if ((tCon->checkMagicNumber() == 0) &&
- (tCon->theSendStatus == NdbConnection::sendTC_ROLLBACK)) {
+ (tCon->theSendStatus == NdbTransaction::sendTC_ROLLBACK)) {
tReturnCode = tCon->receiveTCROLLBACKREF(aSignal);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -797,7 +798,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
const BlockReference aTCRef = aSignal->theSendersBlockRef;
tCon = void2con(tFirstDataPtr);
if ((tCon->checkMagicNumber() == 0) &&
- (tCon->theSendStatus == NdbConnection::sendTC_OP)) {
+ (tCon->theSendStatus == NdbTransaction::sendTC_OP)) {
tReturnCode = tCon->receiveTCINDXCONF(indxConf, tLen);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -805,7 +806,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
}//if
if(TcIndxConf::getMarkerFlag(indxConf->confInfo)){
- NdbConnection::sendTC_COMMIT_ACK(theCommitAckSignal,
+ NdbTransaction::sendTC_COMMIT_ACK(theCommitAckSignal,
indxConf->transId1,
indxConf->transId2,
aTCRef);
@@ -820,7 +821,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
if (tIndexOp->checkMagicNumber() == 0) {
tCon = tIndexOp->theNdbCon;
if (tCon != NULL) {
- if (tCon->theSendStatus == NdbConnection::sendTC_OP) {
+ if (tCon->theSendStatus == NdbTransaction::sendTC_OP) {
tReturnCode = tIndexOp->receiveTCINDXREF(aSignal);
if (tReturnCode != -1) {
completedTransaction(tCon);
@@ -861,7 +862,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
/*****************************************************************************
-void completedTransaction(NdbConnection* aCon);
+void completedTransaction(NdbTransaction* aCon);
Remark: One transaction has been completed.
Remove it from send array and put it into the completed
@@ -869,14 +870,14 @@ Remark: One transaction has been completed.
up a poller.
******************************************************************************/
void
-Ndb::completedTransaction(NdbConnection* aCon)
+Ndb::completedTransaction(NdbTransaction* aCon)
{
Uint32 tTransArrayIndex = aCon->theTransArrayIndex;
Uint32 tNoSentTransactions = theNoOfSentTransactions;
Uint32 tNoCompletedTransactions = theNoOfCompletedTransactions;
- if ((tNoSentTransactions > 0) && (aCon->theListState == NdbConnection::InSendList) &&
+ if ((tNoSentTransactions > 0) && (aCon->theListState == NdbTransaction::InSendList) &&
(tTransArrayIndex < tNoSentTransactions)) {
- NdbConnection* tMoveCon = theSentTransactionsArray[tNoSentTransactions - 1];
+ NdbTransaction* tMoveCon = theSentTransactionsArray[tNoSentTransactions - 1];
theCompletedTransactionsArray[tNoCompletedTransactions] = aCon;
aCon->theTransArrayIndex = tNoCompletedTransactions;
@@ -888,7 +889,7 @@ Ndb::completedTransaction(NdbConnection* aCon)
theNoOfCompletedTransactions = tNoCompletedTransactions + 1;
theNoOfSentTransactions = tNoSentTransactions - 1;
- aCon->theListState = NdbConnection::InCompletedList;
+ aCon->theListState = NdbTransaction::InCompletedList;
aCon->handleExecuteCompletion();
if ((theMinNoOfEventsToWakeUp != 0) &&
(theNoOfCompletedTransactions >= theMinNoOfEventsToWakeUp)) {
@@ -909,12 +910,12 @@ Ndb::completedTransaction(NdbConnection* aCon)
}//Ndb::completedTransaction()
/*****************************************************************************
-void reportCallback(NdbConnection** aCopyArray, Uint32 aNoOfCompletedTrans);
+void reportCallback(NdbTransaction** aCopyArray, Uint32 aNoOfCompletedTrans);
Remark: Call the callback methods of the completed transactions.
******************************************************************************/
void
-Ndb::reportCallback(NdbConnection** aCopyArray, Uint32 aNoOfCompletedTrans)
+Ndb::reportCallback(NdbTransaction** aCopyArray, Uint32 aNoOfCompletedTrans)
{
Uint32 i;
if (aNoOfCompletedTrans > 0) {
@@ -923,7 +924,7 @@ Ndb::reportCallback(NdbConnection** aCopyArray, Uint32 aNoOfCompletedTrans)
NdbAsynchCallback aCallback = aCopyArray[i]->theCallbackFunction;
int tResult = 0;
if (aCallback != NULL) {
- if (aCopyArray[i]->theReturnStatus == NdbConnection::ReturnFailure) {
+ if (aCopyArray[i]->theReturnStatus == NdbTransaction::ReturnFailure) {
tResult = -1;
}//if
(*aCallback)(tResult, aCopyArray[i], anyObject);
@@ -933,13 +934,13 @@ Ndb::reportCallback(NdbConnection** aCopyArray, Uint32 aNoOfCompletedTrans)
}//Ndb::reportCallback()
/*****************************************************************************
-Uint32 pollCompleted(NdbConnection** aCopyArray);
+Uint32 pollCompleted(NdbTransaction** aCopyArray);
Remark: Transfer the data from the completed transaction to a local array.
This support is used by a number of the poll-methods.
******************************************************************************/
Uint32
-Ndb::pollCompleted(NdbConnection** aCopyArray)
+Ndb::pollCompleted(NdbTransaction** aCopyArray)
{
check_send_timeout();
Uint32 i;
@@ -947,13 +948,13 @@ Ndb::pollCompleted(NdbConnection** aCopyArray)
if (tNoCompletedTransactions > 0) {
for (i = 0; i < tNoCompletedTransactions; i++) {
aCopyArray[i] = theCompletedTransactionsArray[i];
- if (aCopyArray[i]->theListState != NdbConnection::InCompletedList) {
+ if (aCopyArray[i]->theListState != NdbTransaction::InCompletedList) {
ndbout << "pollCompleted error ";
ndbout << (int) aCopyArray[i]->theListState << endl;
abort();
}//if
theCompletedTransactionsArray[i] = NULL;
- aCopyArray[i]->theListState = NdbConnection::NotInList;
+ aCopyArray[i]->theListState = NdbTransaction::NotInList;
}//for
}//if
theNoOfCompletedTransactions = 0;
@@ -968,7 +969,7 @@ Ndb::check_send_timeout()
the_last_check_time = current_time;
Uint32 no_of_sent = theNoOfSentTransactions;
for (Uint32 i = 0; i < no_of_sent; i++) {
- NdbConnection* a_con = theSentTransactionsArray[i];
+ NdbTransaction* a_con = theSentTransactionsArray[i];
if ((current_time - a_con->theStartTransTime) >
WAITFOR_RESPONSE_TIMEOUT) {
#ifdef VM_TRACE
@@ -979,8 +980,8 @@ Ndb::check_send_timeout()
abort();
#endif
a_con->setOperationErrorCodeAbort(4012);
- a_con->theCommitStatus = NdbConnection::Aborted;
- a_con->theCompletionStatus = NdbConnection::CompletedFailure;
+ a_con->theCommitStatus = NdbTransaction::Aborted;
+ a_con->theCompletionStatus = NdbTransaction::CompletedFailure;
a_con->handleExecuteCompletion();
remove_sent_list(i);
insert_completed_list(a_con);
@@ -996,7 +997,7 @@ Ndb::remove_sent_list(Uint32 list_index)
{
Uint32 last_index = theNoOfSentTransactions - 1;
if (list_index < last_index) {
- NdbConnection* t_con = theSentTransactionsArray[last_index];
+ NdbTransaction* t_con = theSentTransactionsArray[last_index];
theSentTransactionsArray[list_index] = t_con;
}//if
theNoOfSentTransactions = last_index;
@@ -1004,23 +1005,23 @@ Ndb::remove_sent_list(Uint32 list_index)
}
Uint32
-Ndb::insert_completed_list(NdbConnection* a_con)
+Ndb::insert_completed_list(NdbTransaction* a_con)
{
Uint32 no_of_comp = theNoOfCompletedTransactions;
theCompletedTransactionsArray[no_of_comp] = a_con;
theNoOfCompletedTransactions = no_of_comp + 1;
- a_con->theListState = NdbConnection::InCompletedList;
+ a_con->theListState = NdbTransaction::InCompletedList;
a_con->theTransArrayIndex = no_of_comp;
return no_of_comp;
}
Uint32
-Ndb::insert_sent_list(NdbConnection* a_con)
+Ndb::insert_sent_list(NdbTransaction* a_con)
{
Uint32 no_of_sent = theNoOfSentTransactions;
theSentTransactionsArray[no_of_sent] = a_con;
theNoOfSentTransactions = no_of_sent + 1;
- a_con->theListState = NdbConnection::InSendList;
+ a_con->theListState = NdbTransaction::InSendList;
a_con->theTransArrayIndex = no_of_sent;
return no_of_sent;
}
@@ -1052,16 +1053,16 @@ Ndb::sendPrepTrans(int forceSend)
TransporterFacade* tp = TransporterFacade::instance();
Uint32 no_of_prep_trans = theNoOfPreparedTransactions;
for (i = 0; i < no_of_prep_trans; i++) {
- NdbConnection * a_con = thePreparedTransactionsArray[i];
+ NdbTransaction * a_con = thePreparedTransactionsArray[i];
thePreparedTransactionsArray[i] = NULL;
Uint32 node_id = a_con->getConnectedNodeId();
if ((tp->getNodeSequence(node_id) == a_con->theNodeSequence) &&
tp->get_node_alive(node_id) ||
(tp->get_node_stopping(node_id) &&
- ((a_con->theSendStatus == NdbConnection::sendABORT) ||
- (a_con->theSendStatus == NdbConnection::sendABORTfail) ||
- (a_con->theSendStatus == NdbConnection::sendCOMMITstate) ||
- (a_con->theSendStatus == NdbConnection::sendCompleted)))) {
+ ((a_con->theSendStatus == NdbTransaction::sendABORT) ||
+ (a_con->theSendStatus == NdbTransaction::sendABORTfail) ||
+ (a_con->theSendStatus == NdbTransaction::sendCOMMITstate) ||
+ (a_con->theSendStatus == NdbTransaction::sendCompleted)))) {
/*
We will send if
1) Node is alive and sequences are correct OR
@@ -1093,13 +1094,13 @@ Ndb::sendPrepTrans(int forceSend)
again and will thus set the state to Aborted to avoid a more or
less eternal loop of tries.
*/
- if (a_con->theSendStatus == NdbConnection::sendOperations) {
+ if (a_con->theSendStatus == NdbTransaction::sendOperations) {
a_con->setOperationErrorCodeAbort(4021);
- a_con->theCommitStatus = NdbConnection::NeedAbort;
+ a_con->theCommitStatus = NdbTransaction::NeedAbort;
TRACE_DEBUG("Send buffer full and sendOperations");
} else {
a_con->setOperationErrorCodeAbort(4026);
- a_con->theCommitStatus = NdbConnection::Aborted;
+ a_con->theCommitStatus = NdbTransaction::Aborted;
TRACE_DEBUG("Send buffer full, set state to Aborted");
}//if
}//if
@@ -1116,7 +1117,7 @@ Ndb::sendPrepTrans(int forceSend)
*/
TRACE_DEBUG("Abort a transaction when stopping a node");
a_con->setOperationErrorCodeAbort(4023);
- a_con->theCommitStatus = NdbConnection::NeedAbort;
+ a_con->theCommitStatus = NdbTransaction::NeedAbort;
} else {
/*
The node is hard dead and we cannot continue. We will also release
@@ -1126,10 +1127,11 @@ Ndb::sendPrepTrans(int forceSend)
a_con->setOperationErrorCodeAbort(4025);
a_con->theReleaseOnClose = true;
a_con->theTransactionIsStarted = false;
- a_con->theCommitStatus = NdbConnection::Aborted;
+ a_con->theCommitStatus = NdbTransaction::Aborted;
}//if
}//if
- a_con->theCompletionStatus = NdbConnection::CompletedFailure;
+ a_con->theReturnStatus = NdbTransaction::ReturnFailure;
+ a_con->theCompletionStatus = NdbTransaction::CompletedFailure;
a_con->handleExecuteCompletion();
insert_completed_list(a_con);
}//for
@@ -1203,7 +1205,7 @@ Remark: First send all prepared operations and then check if there are any
int
Ndb::sendPollNdb(int aMillisecondNumber, int minNoOfEventsToWakeup, int forceSend)
{
- NdbConnection* tConArray[1024];
+ NdbTransaction* tConArray[1024];
Uint32 tNoCompletedTransactions;
//theCurrentConnectCounter = 0;
@@ -1236,7 +1238,7 @@ Remark: Check if there are any transactions already completed. Wait for not
int
Ndb::pollNdb(int aMillisecondNumber, int minNoOfEventsToWakeup)
{
- NdbConnection* tConArray[1024];
+ NdbTransaction* tConArray[1024];
Uint32 tNoCompletedTransactions;
//theCurrentConnectCounter = 0;
@@ -1343,7 +1345,7 @@ Ndb::sendRecSignal(Uint16 node_id,
}//Ndb::sendRecSignal()
void
-NdbConnection::sendTC_COMMIT_ACK(NdbApiSignal * aSignal,
+NdbTransaction::sendTC_COMMIT_ACK(NdbApiSignal * aSignal,
Uint32 transId1, Uint32 transId2,
Uint32 aTCRef){
#ifdef MARKER_TRACE
diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp
index a11dd842495..4db9d05b59c 100644
--- a/ndb/src/ndbapi/Ndbinit.cpp
+++ b/ndb/src/ndbapi/Ndbinit.cpp
@@ -19,12 +19,12 @@
#include "NdbApiSignal.hpp"
#include "NdbImpl.hpp"
-#include "NdbOperation.hpp"
-#include "NdbConnection.hpp"
-#include "NdbRecAttr.hpp"
-#include "IPCConfig.hpp"
+#include <NdbOperation.hpp>
+#include <NdbTransaction.hpp>
+#include <NdbRecAttr.hpp>
+#include <IPCConfig.hpp>
#include "TransporterFacade.hpp"
-#include "ConfigRetriever.hpp"
+#include <ConfigRetriever.hpp>
#include <ndb_limits.h>
#include <NdbOut.hpp>
#include <NdbSleep.h>
@@ -34,48 +34,12 @@ class NdbGlobalEventBufferHandle;
NdbGlobalEventBufferHandle *NdbGlobalEventBuffer_init(int);
void NdbGlobalEventBuffer_drop(NdbGlobalEventBufferHandle *);
-/**
- * Static object for NDB
- */
-
-// only needed for backwards compatability, before ndb_cluster_connection
-static char *ndbConnectString = 0;
-static int theNoOfNdbObjects = 0;
-static Ndb_cluster_connection *global_ndb_cluster_connection= 0;
-
-
-/***************************************************************************
-Ndb(const char* aDataBase);
-
-Parameters: aDataBase : Name of the database.
-Remark: Connect to the database.
-***************************************************************************/
-Ndb::Ndb( const char* aDataBase , const char* aSchema)
- : theImpl(NULL)
-{
- DBUG_ENTER("Ndb::Ndb()");
- DBUG_PRINT("enter",("(old)Ndb::Ndb this=0x%x", this));
- if (theNoOfNdbObjects < 0)
- abort(); // old and new Ndb constructor used mixed
- theNoOfNdbObjects++;
- if (global_ndb_cluster_connection == 0) {
- global_ndb_cluster_connection= new Ndb_cluster_connection(ndbConnectString);
- global_ndb_cluster_connection->connect(12,5,1);
- }
- setup(global_ndb_cluster_connection, aDataBase, aSchema);
- DBUG_VOID_RETURN;
-}
-
Ndb::Ndb( Ndb_cluster_connection *ndb_cluster_connection,
const char* aDataBase , const char* aSchema)
: theImpl(NULL)
{
DBUG_ENTER("Ndb::Ndb()");
DBUG_PRINT("enter",("Ndb::Ndb this=0x%x", this));
- if (global_ndb_cluster_connection != 0 &&
- global_ndb_cluster_connection != ndb_cluster_connection)
- abort(); // old and new Ndb constructor used mixed
- theNoOfNdbObjects= -1;
setup(ndb_cluster_connection, aDataBase, aSchema);
DBUG_VOID_RETURN;
}
@@ -177,16 +141,6 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection,
}
-void Ndb::setConnectString(const char * connectString)
-{
- if (ndbConnectString != 0) {
- free(ndbConnectString);
- ndbConnectString = 0;
- }
- if (connectString)
- ndbConnectString = strdup(connectString);
-}
-
/*****************************************************************************
* ~Ndb();
*
@@ -241,19 +195,6 @@ Ndb::~Ndb()
delete theImpl;
- /**
- * This needs to be put after delete theImpl
- * as TransporterFacade::instance is delete by global_ndb_cluster_connection
- * and used by theImpl
- */
- if (global_ndb_cluster_connection != 0) {
- theNoOfNdbObjects--;
- if(theNoOfNdbObjects == 0){
- delete global_ndb_cluster_connection;
- global_ndb_cluster_connection= 0;
- }
- }//if
-
/**
* This sleep is to make sure that the transporter
* send thread will come in and send any
diff --git a/ndb/src/ndbapi/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp
index 5902aa413dc..6dfd76c160b 100644
--- a/ndb/src/ndbapi/Ndblist.cpp
+++ b/ndb/src/ndbapi/Ndblist.cpp
@@ -19,7 +19,6 @@
#include <NdbOperation.hpp>
#include <NdbIndexOperation.hpp>
#include <NdbIndexScanOperation.hpp>
-#include <NdbConnection.hpp>
#include "NdbApiSignal.hpp"
#include <NdbRecAttr.hpp>
#include "NdbUtil.hpp"
@@ -51,10 +50,10 @@ Ndb::checkFailedNode()
/**
* Release all connections in idle list (for node)
*/
- NdbConnection * tNdbCon = theConnectionArray[node_id];
+ NdbTransaction * tNdbCon = theConnectionArray[node_id];
theConnectionArray[node_id] = NULL;
while (tNdbCon != NULL) {
- NdbConnection* tempNdbCon = tNdbCon;
+ NdbTransaction* tempNdbCon = tNdbCon;
tNdbCon = tNdbCon->next();
releaseNdbCon(tempNdbCon);
}
@@ -71,14 +70,14 @@ Ndb::checkFailedNode()
* if createConIdleList was succesful
* Return -1: In all other case.
* Parameters: aNrOfCon : Number of connections offered to the application.
- * Remark: Create connection idlelist with NdbConnection objects.
+ * Remark: Create connection idlelist with NdbTransaction objects.
***************************************************************************/
int
Ndb::createConIdleList(int aNrOfCon)
{
for (int i = 0; i < aNrOfCon; i++)
{
- NdbConnection* tNdbCon = new NdbConnection(this);
+ NdbTransaction* tNdbCon = new NdbTransaction(this);
if (tNdbCon == NULL)
{
return -1;
@@ -92,7 +91,7 @@ Ndb::createConIdleList(int aNrOfCon)
tNdbCon->next(theConIdleList);
theConIdleList = tNdbCon;
}
- tNdbCon->Status(NdbConnection::NotConnected);
+ tNdbCon->Status(NdbTransaction::NotConnected);
}
theNoOfAllocatedTransactions = aNrOfCon;
return aNrOfCon;
@@ -183,19 +182,19 @@ Ndb::getNdbCall()
}
/***************************************************************************
- * NdbConnection* getNdbCon();
+ * NdbTransaction* getNdbCon();
*
* Return Value: Return a connection if the getNdbCon was successful.
* Return NULL : In all other case.
* Remark: Get a connection from theConIdleList and return the object .
***************************************************************************/
-NdbConnection*
+NdbTransaction*
Ndb::getNdbCon()
{
- NdbConnection* tNdbCon;
+ NdbTransaction* tNdbCon;
if ( theConIdleList == NULL ) {
if (theNoOfAllocatedTransactions < theMaxNoOfTransactions) {
- tNdbCon = new NdbConnection(this);
+ tNdbCon = new NdbTransaction(this);
if (tNdbCon == NULL) {
return NULL;
}//if
@@ -467,13 +466,13 @@ Ndb::releaseNdbCall(NdbCall* aNdbCall)
}
/***************************************************************************
-void releaseNdbCon(NdbConnection* aNdbCon);
+void releaseNdbCon(NdbTransaction* aNdbCon);
-Parameters: aNdbCon: The NdbConnection object.
+Parameters: aNdbCon: The NdbTransaction object.
Remark: Add a Connection object into the signal idlelist.
***************************************************************************/
void
-Ndb::releaseNdbCon(NdbConnection* aNdbCon)
+Ndb::releaseNdbCon(NdbTransaction* aNdbCon)
{
aNdbCon->next(theConIdleList);
aNdbCon->theMagicNumber = 0xFE11DD;
@@ -551,10 +550,21 @@ Remark: Add a NdbScanOperation object into the signal idlelist.
void
Ndb::releaseScanOperation(NdbIndexScanOperation* aScanOperation)
{
+ DBUG_ENTER("Ndb::releaseScanOperation");
+ DBUG_PRINT("enter", ("op=%x", (UintPtr)aScanOperation));
+#ifdef ndb_release_check_dup
+ { NdbIndexScanOperation* tOp = theScanOpIdleList;
+ while (tOp != NULL) {
+ assert(tOp != aScanOperation);
+ tOp = (NdbIndexScanOperation*)tOp->theNext;
+ }
+ }
+#endif
aScanOperation->next(theScanOpIdleList);
aScanOperation->theNdbCon = NULL;
aScanOperation->theMagicNumber = 0xFE11D2;
theScanOpIdleList = aScanOperation;
+ DBUG_VOID_RETURN;
}
/***************************************************************************
@@ -703,7 +713,7 @@ Remark: Always release the first item in the free list
void
Ndb::freeNdbCon()
{
- NdbConnection* tNdbCon = theConIdleList;
+ NdbTransaction* tNdbCon = theConIdleList;
theConIdleList = theConIdleList->next();
delete tNdbCon;
}
@@ -772,14 +782,14 @@ Ndb::freeNdbBlob()
}
/****************************************************************************
-int releaseConnectToNdb(NdbConnection* aConnectConnection);
+int releaseConnectToNdb(NdbTransaction* aConnectConnection);
Return Value: -1 if error
Parameters: aConnectConnection : Seized schema connection to DBTC
Remark: Release and disconnect from DBTC a connection and seize it to theConIdleList.
*****************************************************************************/
void
-Ndb::releaseConnectToNdb(NdbConnection* a_con)
+Ndb::releaseConnectToNdb(NdbTransaction* a_con)
{
DBUG_ENTER("Ndb::releaseConnectToNdb");
NdbApiSignal tSignal(theMyRef);
@@ -797,7 +807,7 @@ Ndb::releaseConnectToNdb(NdbConnection* a_con)
tSignal.setData((tConPtr = a_con->getTC_ConnectPtr()), 1);
tSignal.setData(theMyRef, 2);
tSignal.setData(a_con->ptr2int(), 3);
- a_con->Status(NdbConnection::DisConnecting);
+ a_con->Status(NdbTransaction::DisConnecting);
a_con->theMagicNumber = 0x37412619;
int ret_code = sendRecSignal(node_id,
WAIT_TC_RELEASE,
diff --git a/ndb/src/ndbapi/TransporterFacade.cpp b/ndb/src/ndbapi/TransporterFacade.cpp
index 93cec59ada6..e2aa6631841 100644
--- a/ndb/src/ndbapi/TransporterFacade.cpp
+++ b/ndb/src/ndbapi/TransporterFacade.cpp
@@ -513,43 +513,32 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props)
iter.first();
theClusterMgr->init(iter);
- /**
- * Unless there is a "Name", the initiated transporter is within
- * an NDB Cluster. (If "Name" is defined, then the transporter
- * is used to connect to a different system, i.e. NDB Cluster.)
- */
-#if 0
- if (!props->contains("Name")) {
-#endif
- iter.first();
- if(iter.find(CFG_NODE_ID, nodeId)){
- TRP_DEBUG( "Node info missing from config." );
- return false;
- }
-
- Uint32 rank = 0;
- if(!iter.get(CFG_NODE_ARBIT_RANK, &rank) && rank>0){
- theArbitMgr = new ArbitMgr(* this);
- theArbitMgr->setRank(rank);
- Uint32 delay = 0;
- iter.get(CFG_NODE_ARBIT_DELAY, &delay);
- theArbitMgr->setDelay(delay);
- }
- Uint32 scan_batch_size= 0;
- if (!iter.get(CFG_MAX_SCAN_BATCH_SIZE, &scan_batch_size)) {
- m_scan_batch_size= scan_batch_size;
- }
- Uint32 batch_byte_size= 0;
- if (!iter.get(CFG_BATCH_BYTE_SIZE, &batch_byte_size)) {
- m_batch_byte_size= batch_byte_size;
- }
- Uint32 batch_size= 0;
- if (!iter.get(CFG_BATCH_SIZE, &batch_size)) {
- m_batch_size= batch_size;
- }
-#if 0
+ iter.first();
+ if(iter.find(CFG_NODE_ID, nodeId)){
+ TRP_DEBUG( "Node info missing from config." );
+ return false;
+ }
+
+ Uint32 rank = 0;
+ if(!iter.get(CFG_NODE_ARBIT_RANK, &rank) && rank>0){
+ theArbitMgr = new ArbitMgr(* this);
+ theArbitMgr->setRank(rank);
+ Uint32 delay = 0;
+ iter.get(CFG_NODE_ARBIT_DELAY, &delay);
+ theArbitMgr->setDelay(delay);
+ }
+ Uint32 scan_batch_size= 0;
+ if (!iter.get(CFG_MAX_SCAN_BATCH_SIZE, &scan_batch_size)) {
+ m_scan_batch_size= scan_batch_size;
+ }
+ Uint32 batch_byte_size= 0;
+ if (!iter.get(CFG_BATCH_BYTE_SIZE, &batch_byte_size)) {
+ m_batch_byte_size= batch_byte_size;
+ }
+ Uint32 batch_size= 0;
+ if (!iter.get(CFG_BATCH_SIZE, &batch_size)) {
+ m_batch_size= batch_size;
}
-#endif
if (!theTransporterRegistry->start_service(m_socket_server)){
ndbout_c("Unable to start theTransporterRegistry->start_service");
diff --git a/ndb/src/ndbapi/TransporterFacade.hpp b/ndb/src/ndbapi/TransporterFacade.hpp
index 99edea846c1..e74f4b51e00 100644
--- a/ndb/src/ndbapi/TransporterFacade.hpp
+++ b/ndb/src/ndbapi/TransporterFacade.hpp
@@ -24,6 +24,7 @@
#include <NdbMutex.h>
#include "DictCache.hpp"
#include <BlockNumbers.h>
+#include <mgmapi.h>
class ClusterMgr;
class ArbitMgr;
@@ -43,10 +44,6 @@ extern "C" {
void atexit_stop_instance();
}
-/**
- * Max number of Ndb objects in different threads.
- * (Ndb objects should not be shared by different threads.)
- */
class TransporterFacade
{
public:
@@ -115,6 +112,8 @@ public:
Uint32 get_batch_byte_size();
Uint32 get_batch_size();
+ TransporterRegistry* get_registry() { return theTransporterRegistry;};
+
private:
/**
* Send a signal unconditional of node status (used by ClusterMgr)
@@ -133,7 +132,7 @@ private:
bool isConnected(NodeId aNodeId);
void doStop();
-
+
TransporterRegistry* theTransporterRegistry;
SocketServer m_socket_server;
int sendPerformedLastInterval;
@@ -171,6 +170,10 @@ private:
* Block number handling
*/
public:
+ /**
+ * Max number of Ndb objects.
+ * (Ndb objects should not be shared by different threads.)
+ */
STATIC_CONST( MAX_NO_THREADS = 4711 );
private:
diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp
index 4fcf4d08396..49aded8e0ac 100644
--- a/ndb/src/ndbapi/ndb_cluster_connection.cpp
+++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp
@@ -28,7 +28,8 @@
#include <ndb_limits.h>
#include <ConfigRetriever.hpp>
#include <ndb_version.h>
-#include <Vector.hpp>
+#include <mgmapi_debug.h>
+#include <mgmapi_internal.h>
#include <md5_hash.hpp>
#include <EventLogger.hpp>
@@ -180,6 +181,12 @@ Ndb_cluster_connection::no_db_nodes()
return m_impl.m_all_nodes.size();
}
+unsigned
+Ndb_cluster_connection::node_id()
+{
+ return m_impl.m_transporter_facade->ownId();
+}
+
int
Ndb_cluster_connection::wait_until_ready(int timeout,
@@ -253,9 +260,6 @@ Ndb_cluster_connection_impl::Ndb_cluster_connection_impl(const char *
g_eventLogger.createConsoleHandler();
g_eventLogger.setCategory("NdbApi");
g_eventLogger.enable(Logger::LL_ON, Logger::LL_ERROR);
-
- m_transporter_facade=
- TransporterFacade::theFacadeInstance= new TransporterFacade();
m_connect_thread= 0;
m_connect_callback= 0;
@@ -280,6 +284,10 @@ Ndb_cluster_connection_impl::Ndb_cluster_connection_impl(const char *
m_config_retriever= 0;
}
+ m_transporter_facade=
+ TransporterFacade::theFacadeInstance=
+ new TransporterFacade();
+
DBUG_VOID_RETURN;
}
@@ -465,6 +473,8 @@ Ndb_cluster_connection_impl::do_test()
int Ndb_cluster_connection::connect(int no_retries, int retry_delay_in_seconds,
int verbose)
{
+ struct ndb_mgm_reply mgm_reply;
+
DBUG_ENTER("Ndb_cluster_connection::connect");
const char* error = 0;
do {
@@ -482,10 +492,24 @@ int Ndb_cluster_connection::connect(int no_retries, int retry_delay_in_seconds,
ndb_mgm_configuration * props = m_impl.m_config_retriever->getConfig();
if(props == 0)
break;
- m_impl.m_transporter_facade->start_instance(nodeId, props);
+ m_impl.m_transporter_facade->start_instance(nodeId, props);
m_impl.init_nodes_vector(nodeId, *props);
+ for(unsigned i=0;
+ i<m_impl.m_transporter_facade->get_registry()->m_transporter_interface.size();
+ i++)
+ ndb_mgm_set_connection_int_parameter(m_impl.m_config_retriever->get_mgmHandle(),
+ nodeId,
+ m_impl.m_transporter_facade->get_registry()
+ ->m_transporter_interface[i]
+ .m_remote_nodeId,
+ CFG_CONNECTION_SERVER_PORT,
+ m_impl.m_transporter_facade->get_registry()
+ ->m_transporter_interface[i]
+ .m_s_service_port,
+ &mgm_reply);
+
ndb_mgm_destroy_configuration(props);
m_impl.m_transporter_facade->connected();
DBUG_RETURN(0);
@@ -522,110 +546,5 @@ void Ndb_cluster_connection_impl::connect_thread()
DBUG_VOID_RETURN;
}
-/*
- * Hint handling to select node
- * ToDo: fix this
- */
-
-void
-Ndb_cluster_connection_impl::FragmentToNodeMap::init(Uint32 noOfNodes,
- Uint8 nodeIds[])
-{
- kValue = 6;
- noOfFragments = 2 * noOfNodes;
-
- /**
- * Compute hashValueMask and hashpointerValue
- */
- {
- Uint32 topBit = (1 << 31);
- for(int i = 31; i>=0; i--){
- if((noOfFragments & topBit) != 0)
- break;
- topBit >>= 1;
- }
- hashValueMask = topBit - 1;
- hashpointerValue = noOfFragments - (hashValueMask + 1);
- }
-
- /**
- * This initialization depends on
- * the fact that:
- * primary node for fragment i = i % noOfNodes
- *
- * This algorithm should be implemented in Dbdih
- */
- {
- if (fragment2PrimaryNodeMap != 0)
- abort();
-
- fragment2PrimaryNodeMap = new Uint32[noOfFragments];
- Uint32 i;
- for(i = 0; i<noOfNodes; i++){
- fragment2PrimaryNodeMap[i] = nodeIds[i];
- }
-
- // Sort them (bubble sort)
- for(i = 0; i<noOfNodes-1; i++)
- for(Uint32 j = i+1; j<noOfNodes; j++)
- if(fragment2PrimaryNodeMap[i] > fragment2PrimaryNodeMap[j]){
- Uint32 tmp = fragment2PrimaryNodeMap[i];
- fragment2PrimaryNodeMap[i] = fragment2PrimaryNodeMap[j];
- fragment2PrimaryNodeMap[j] = tmp;
- }
-
- for(i = 0; i<noOfNodes; i++){
- fragment2PrimaryNodeMap[i+noOfNodes] = fragment2PrimaryNodeMap[i];
- }
- }
-}
-
-void
-Ndb_cluster_connection_impl::FragmentToNodeMap::release(){
- delete [] fragment2PrimaryNodeMap;
- fragment2PrimaryNodeMap = 0;
-}
-
-static const Uint32 MAX_KEY_LEN_64_WORDS = 4;
-Uint32
-Ndb_cluster_connection_impl::guess_primary_node(const char *keyData,
- Uint32 keyLen)
-{
- Uint64 tempData[MAX_KEY_LEN_64_WORDS];
-
- const Uint32 usedKeyLen = (keyLen + 3) >> 2; // In words
- const char * usedKeyData = 0;
-
- /**
- * If key data buffer is not aligned (on 64 bit boundary)
- * or key len is not a multiple of 4
- * Use temp data
- */
- if(((((UintPtr)keyData) & 7) == 0) && ((keyLen & 3) == 0)) {
- usedKeyData = keyData;
- } else {
- memcpy(&tempData[0], keyData, keyLen);
- const int slack = keyLen & 3;
- if(slack > 0) {
- memset(&((char *)&tempData[0])[keyLen], 0, (4 - slack));
- }//if
- usedKeyData = (char *)&tempData[0];
- }//if
-
- Uint32 hashValue = md5_hash((Uint64 *)usedKeyData, usedKeyLen);
-
- hashValue >>= fragmentToNodeMap.kValue;
-
- Uint32 fragmentId = hashValue &
- fragmentToNodeMap.hashValueMask;
-
- if(fragmentId < fragmentToNodeMap.hashpointerValue) {
- fragmentId = hashValue &
- ((fragmentToNodeMap.hashValueMask << 1) + 1);
- }//if
- return fragmentId;
-}
-
-
template class Vector<Ndb_cluster_connection_impl::Node>;
diff --git a/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp b/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp
index 620eac296a3..05652f3316a 100644
--- a/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp
+++ b/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp
@@ -54,22 +54,6 @@ private:
friend class NdbImpl;
friend void* run_ndb_cluster_connection_connect_thread(void*);
friend class Ndb_cluster_connection;
-
- /**
- * Structure containing values for guessing primary node
- */
- struct FragmentToNodeMap {
- FragmentToNodeMap():
- fragment2PrimaryNodeMap(0) {};
- Uint32 kValue;
- Uint32 hashValueMask;
- Uint32 hashpointerValue;
- Uint32 noOfFragments;
- Uint32 *fragment2PrimaryNodeMap;
-
- void init(Uint32 noOfNodes, Uint8 nodeIds[]);
- void release();
- } fragmentToNodeMap;
struct Node
{
@@ -85,8 +69,6 @@ private:
Vector<Node> m_all_nodes;
void init_nodes_vector(Uint32 nodeid, const ndb_mgm_configuration &config);
- Uint32 guess_primary_node(const char * keyData, Uint32 keyLen);
-
void connect_thread();
TransporterFacade *m_transporter_facade;
diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c
index bbc82a21324..6bbd38c9bbb 100644
--- a/ndb/src/ndbapi/ndberror.c
+++ b/ndb/src/ndbapi/ndberror.c
@@ -55,6 +55,8 @@ typedef struct ErrorBundle {
#define NI ndberror_cl_function_not_implemented
#define UE ndberror_cl_unknown_error_code
+#define OE ndberror_cl_schema_object_already_exists
+
static const char REDO_BUFFER_MSG[]=
"REDO log buffers overloaded, consult online manual (increase RedoBuffer, and|or decrease TimeBetweenLocalCheckpoints, and|or increase NoOfFragmentLogFiles)";
@@ -69,6 +71,7 @@ static const char* empty_string = "";
* 600 - ACC
* 700 - DICT
* 800 - TUP
+ * 900 - TUX
* 1200 - LQH
* 1300 - BACKUP
* 4000 - API
@@ -78,6 +81,7 @@ static const char* empty_string = "";
* 4400 - ""
* 4500 - ""
* 4600 - ""
+ * 4700 - "" Event
* 5000 - Management server
*/
@@ -176,11 +180,13 @@ ErrorBundle ErrorCodes[] = {
{ 623, IS, "623" },
{ 624, IS, "624" },
{ 625, IS, "Out of memory in Ndb Kernel, hash index part (increase IndexMemory)" },
- { 800, IS, "Too many ordered indexes (increase MaxNoOfOrderedIndexes)" },
+ { 640, IS, "Too many hash indexes (should not happen)" },
{ 826, IS, "Too many tables and attributes (increase MaxNoOfAttributes or MaxNoOfTables)" },
{ 827, IS, "Out of memory in Ndb Kernel, table data (increase DataMemory)" },
{ 902, IS, "Out of memory in Ndb Kernel, ordered index data (increase DataMemory)" },
- { 832, IS, "832" },
+ { 903, IS, "Too many ordered indexes (increase MaxNoOfOrderedIndexes)" },
+ { 904, IS, "Out of fragment records (increase MaxNoOfOrderedIndexes)" },
+ { 905, IS, "Out of attribute records (increase MaxNoOfAttributes)" },
/**
* TimeoutExpired
@@ -206,6 +212,7 @@ ErrorBundle ErrorCodes[] = {
* Internal errors
*/
{ 892, IE, "Inconsistent hash index. The index needs to be dropped and recreated" },
+ { 896, IE, "Tuple corrupted - wrong checksum or column data in invalid format" },
{ 901, IE, "Inconsistent ordered index. The index needs to be dropped and recreated" },
{ 202, IE, "202" },
{ 203, IE, "203" },
@@ -261,6 +268,7 @@ ErrorBundle ErrorCodes[] = {
* Application error
*/
{ 823, AE, "Too much attrinfo from application in tuple manager" },
+ { 831, AE, "Too many nullable/bitfields in table definition" },
{ 876, AE, "876" },
{ 877, AE, "877" },
{ 878, AE, "878" },
@@ -272,7 +280,7 @@ ErrorBundle ErrorCodes[] = {
{ 897, AE, "Update attempt of primary key via ndbcluster internal api (if this occurs via the MySQL server it is a bug, please report)" },
{ 4256, AE, "Must call Ndb::init() before this function" },
{ 4257, AE, "Tried to read too much - too many getValue calls" },
-
+
/**
* Scan application errors
*/
@@ -291,6 +299,30 @@ ErrorBundle ErrorCodes[] = {
{ 4232, AE, "Parallelism can only be between 1 and 240" },
{ 290, AE, "Scan not started or has been closed by kernel due to timeout" },
+ /**
+ * Event schema errors
+ */
+
+ { 4713, SE, "Column defined in event does not exist in table"},
+
+ /**
+ * Event application errors
+ */
+
+ { 4707, AE, "Too many event have been defined"},
+ { 4708, AE, "Event name is too long"},
+ { 4709, AE, "Can't accept more subscribers"},
+ { 746, OE, "Event name already exists"},
+ { 4710, AE, "Event not found"},
+ { 4711, AE, "Creation of event failed"},
+ { 4712, AE, "Stopped event operation does not exist. Already stopped?"},
+
+ /**
+ * Event internal errors
+ */
+
+ { 4731, IE, "Event not found"},
+
/**
* SchemaError
*/
@@ -301,22 +333,25 @@ ErrorBundle ErrorCodes[] = {
{ 707, SE, "No more table metadata records" },
{ 708, SE, "No more attribute metadata records" },
{ 709, SE, "No such table existed" },
- { 721, SE, "Table or index with given name already exists" },
+ { 721, OE, "Table or index with given name already exists" },
{ 723, SE, "No such table existed" },
- { 736, SE, "Wrong attribute size" },
+ { 736, SE, "Unsupported array size" },
{ 737, SE, "Attribute array size too big" },
{ 738, SE, "Record too big" },
{ 739, SE, "Unsupported primary key length" },
{ 740, SE, "Nullable primary key not supported" },
{ 741, SE, "Unsupported alter table" },
- { 742, SE, "Unsupported attribute type in index" },
{ 743, SE, "Unsupported character set in table or index" },
{ 744, SE, "Character string is invalid for given character set" },
+ { 745, SE, "Distribution key not supported for char attribute (use binary attribute)" },
{ 241, SE, "Invalid schema object version" },
{ 283, SE, "Table is being dropped" },
{ 284, SE, "Table not defined in transaction coordinator" },
{ 285, SE, "Unknown table error in transaction coordinator" },
{ 881, SE, "Unable to create table, out of data pages (increase DataMemory) " },
+ { 906, SE, "Unsupported attribute type in index" },
+ { 907, SE, "Unsupported character set in table or index" },
+ { 908, IS, "Invalid ordered index tree node size" },
{ 1225, SE, "Table not defined in local query handler" },
{ 1226, SE, "Table is being dropped" },
{ 1228, SE, "Cannot use drop table for drop index" },
@@ -461,8 +496,7 @@ ErrorBundle ErrorCodes[] = {
{ 4241, AE, "Index name too long" },
{ 4242, AE, "Too many indexes" },
{ 4243, AE, "Index not found" },
- { 4244, AE, "Index or table with given name already exists" },
- { 4245, AE, "Index attribute must be defined as stored, i.e. the StorageAttributeType must be defined as NormalStorageAttribute"},
+ { 4244, OE, "Index or table with given name already exists" },
{ 4247, AE, "Illegal index/trigger create/drop/alter request" },
{ 4248, AE, "Trigger/index name invalid" },
{ 4249, AE, "Invalid table" },
@@ -483,9 +517,10 @@ ErrorBundle ErrorCodes[] = {
{ 4266, AE, "Invalid blob seek position" },
{ 4267, IE, "Corrupted blob value" },
{ 4268, IE, "Error in blob head update forced rollback of transaction" },
- { 4268, IE, "Unknown blob error" },
{ 4269, IE, "No connection to ndb management server" },
- { 4335, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" }
+ { 4270, IE, "Unknown blob error" },
+ { 4335, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" },
+ { 4271, AE, "Invalid index object, not retrieved via getIndex()" }
};
static
diff --git a/ndb/test/include/HugoCalculator.hpp b/ndb/test/include/HugoCalculator.hpp
index b782eb003a3..03de46cd7ea 100644
--- a/ndb/test/include/HugoCalculator.hpp
+++ b/ndb/test/include/HugoCalculator.hpp
@@ -31,14 +31,7 @@ class HugoCalculator {
public:
HugoCalculator(const NdbDictionary::Table& tab);
Int32 calcValue(int record, int attrib, int updates) const;
-#if 0
- U_Int32 calcValue(int record, int attrib, int updates) const;
- U_Int64 calcValue(int record, int attrib, int updates) const;
- Int64 calcValue(int record, int attrib, int updates) const;
- float calcValue(int record, int attrib, int updates) const;
- double calcValue(int record, int attrib, int updates) const;
-#endif
- const char* calcValue(int record, int attrib, int updates, char* buf) const;
+ const char* calcValue(int record, int attrib, int updates, char* buf, int len) const;
int verifyRowValues(NDBT_ResultRow* const pRow) const;
int getIdValue(NDBT_ResultRow* const pRow) const;
diff --git a/ndb/test/include/HugoOperations.hpp b/ndb/test/include/HugoOperations.hpp
index a23d3018f47..05137710609 100644
--- a/ndb/test/include/HugoOperations.hpp
+++ b/ndb/test/include/HugoOperations.hpp
@@ -24,11 +24,14 @@
class HugoOperations : public UtilTransactions {
public:
- HugoOperations(const NdbDictionary::Table&);
+ HugoOperations(const NdbDictionary::Table&,
+ const NdbDictionary::Index* idx = 0);
+
~HugoOperations();
int startTransaction(Ndb*);
+ int setTransaction(NdbTransaction*);
int closeTransaction(Ndb*);
- NdbConnection* getTransaction();
+ NdbTransaction* getTransaction();
void refresh();
void setTransactionId(Uint64);
@@ -68,10 +71,13 @@ public:
int attrId,
int rowId,
int updateId);
+
int equalForAttr(NdbOperation*,
int attrId,
int rowId);
-
+
+ int setValues(NdbOperation*, int rowId, int updateId);
+
int verifyUpdatesValue(int updatesValue, int _numRows = 0);
int indexReadRecords(Ndb*, const char * idxName, int recordNo,
@@ -88,6 +94,9 @@ public:
NdbScanOperation::LM_CommittedRead,
int numRecords = 1);
+ NdbIndexScanOperation* pIndexScanOp;
+
+ NDBT_ResultRow& get_row(Uint32 idx) { return *rows[idx];}
protected:
void allocRows(int rows);
void deallocRows();
@@ -97,11 +106,9 @@ protected:
Vector<BaseString> savedRecords;
- struct RsPair { NdbResultSet* m_result_set; int records; };
+ struct RsPair { NdbScanOperation* m_result_set; int records; };
Vector<RsPair> m_result_sets;
Vector<RsPair> m_executed_result_sets;
-
- NdbConnection* pTrans;
};
#endif
diff --git a/ndb/test/include/HugoTransactions.hpp b/ndb/test/include/HugoTransactions.hpp
index b833f2ac629..83493bcc2a4 100644
--- a/ndb/test/include/HugoTransactions.hpp
+++ b/ndb/test/include/HugoTransactions.hpp
@@ -25,7 +25,8 @@
class HugoTransactions : public HugoOperations {
public:
- HugoTransactions(const NdbDictionary::Table&);
+ HugoTransactions(const NdbDictionary::Table&,
+ const NdbDictionary::Index* idx = 0);
~HugoTransactions();
int createEvent(Ndb*);
int eventOperation(Ndb*, void* stats,
diff --git a/ndb/test/include/NDBT_Error.hpp b/ndb/test/include/NDBT_Error.hpp
index ef107072465..6775a107196 100644
--- a/ndb/test/include/NDBT_Error.hpp
+++ b/ndb/test/include/NDBT_Error.hpp
@@ -91,7 +91,11 @@ private:
; \
}
-#define ERR(error) ERR_OUT(g_err, error)
+#define ERR(error) \
+{ \
+ const NdbError &_error= (error); \
+ ERR_OUT(g_err, _error); \
+}
#define ERR_INFO(error) ERR_OUT(g_info, error)
#endif
diff --git a/ndb/test/include/NDBT_ResultRow.hpp b/ndb/test/include/NDBT_ResultRow.hpp
index 6072d0ea510..cbb5d7f6c6a 100644
--- a/ndb/test/include/NDBT_ResultRow.hpp
+++ b/ndb/test/include/NDBT_ResultRow.hpp
@@ -27,7 +27,7 @@ public:
const NdbRecAttr * attributeStore(int i) const ;
const NdbRecAttr * attributeStore(const char* name) const ;
- BaseString c_str();
+ BaseString c_str() const ;
NdbOut & header (NdbOut &) const;
friend NdbOut & operator << (NdbOut&, const NDBT_ResultRow &);
@@ -36,6 +36,11 @@ public:
* Make copy of NDBT_ResultRow
*/
NDBT_ResultRow * clone() const;
+
+ bool operator==(const NDBT_ResultRow&) const ;
+ bool operator!=(const NDBT_ResultRow& other) const {
+ return ! (*this == other);
+ }
private:
int cols;
diff --git a/ndb/test/include/NDBT_Tables.hpp b/ndb/test/include/NDBT_Tables.hpp
index aa78f7d4e2c..fb0df8aa35b 100644
--- a/ndb/test/include/NDBT_Tables.hpp
+++ b/ndb/test/include/NDBT_Tables.hpp
@@ -23,11 +23,13 @@
#include <NdbDictionary.hpp>
#include <NDBT_Table.hpp>
+typedef int (* NDBT_CreateTableHook)(Ndb*, NdbDictionary::Table&, int when);
+
class NDBT_Tables {
public:
-
+
static int createTable(Ndb* pNdb, const char* _name, bool _temp = false,
- bool existsOK = false);
+ bool existsOK = false, NDBT_CreateTableHook = 0);
static int createAllTables(Ndb* pNdb, bool _temp, bool existsOK = false);
static int createAllTables(Ndb* pNdb);
diff --git a/ndb/test/include/NDBT_Test.hpp b/ndb/test/include/NDBT_Test.hpp
index a60228c1a5d..1b9c2751f64 100644
--- a/ndb/test/include/NDBT_Test.hpp
+++ b/ndb/test/include/NDBT_Test.hpp
@@ -25,6 +25,7 @@
#include <NdbCondition.h>
#include <NdbTimer.hpp>
#include <Vector.hpp>
+#include <NdbApi.hpp>
#include <NdbDictionary.hpp>
class NDBT_Step;
@@ -34,7 +35,9 @@ class NDBT_TestCaseImpl1;
class NDBT_Context {
public:
- NDBT_Context();
+ Ndb_cluster_connection& m_cluster_connection;
+
+ NDBT_Context(Ndb_cluster_connection&);
~NDBT_Context();
const NdbDictionary::Table* getTab();
NDBT_TestSuite* getSuite();
@@ -120,7 +123,7 @@ public:
NDBT_TESTFUNC* pfunc);
virtual ~NDBT_Step() {}
int execute(NDBT_Context*);
- virtual int setUp() = 0;
+ virtual int setUp(Ndb_cluster_connection&) = 0;
virtual void tearDown() = 0;
void setContext(NDBT_Context*);
NDBT_Context* getContext();
@@ -142,7 +145,7 @@ public:
const char* pname,
NDBT_TESTFUNC* pfunc);
virtual ~NDBT_NdbApiStep() {}
- virtual int setUp();
+ virtual int setUp(Ndb_cluster_connection&);
virtual void tearDown();
Ndb* getNdb();
@@ -349,10 +352,13 @@ public:
int addTest(NDBT_TestCase* pTest);
private:
- int executeOne(const char* _tabname, const char* testname = NULL);
- int executeAll(const char* testname = NULL);
-
- void execute(Ndb*, const NdbDictionary::Table*, const char* testname = NULL);
+ int executeOne(Ndb_cluster_connection&,
+ const char* _tabname, const char* testname = NULL);
+ int executeAll(Ndb_cluster_connection&,
+ const char* testname = NULL);
+ void execute(Ndb_cluster_connection&,
+ Ndb*, const NdbDictionary::Table*, const char* testname = NULL);
+
int report(const char* _tcname = NULL);
int reportAllTables(const char* );
const char* name;
@@ -425,7 +431,7 @@ C##suitname():NDBT_TestSuite(#suitname){ \
pt->addTable(tableName, false);
#define NDBT_TESTSUITE_END(suitname) \
- } } ; C##suitname suitname;
+ } } ; C##suitname suitname
// Helper functions for retrieving variables from NDBT_Step
#define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb()
diff --git a/ndb/test/include/NdbSchemaOp.hpp b/ndb/test/include/NdbSchemaOp.hpp
index e8ab542b00a..1edbc155643 100644
--- a/ndb/test/include/NdbSchemaOp.hpp
+++ b/ndb/test/include/NdbSchemaOp.hpp
@@ -79,29 +79,6 @@
};
/**
- * Where attribute is stored.
- *
- * This is used to indicate whether a primary key
- * should only be stored in the index storage and not in the data storage
- * or if it should be stored in both places.
- * The first alternative makes the attribute take less space,
- * but makes it impossible to scan using attribute.
- *
- * @note Use NormalStorageAttribute for most cases.
- * (IndexStorageAttribute should only be used on primary key
- * attributes and only if you do not want to scan using the attribute.)
- */
- enum StorageAttributeType {
- NoStorageAttributeTypeDefined = -1, ///< <i>Missing explanation</i>
- IndexStorageAttribute, ///< Attribute is only stored in
- ///< index storage (ACC)
- NormalStorageAttribute ///< Attribute values are stored
- ///< both in the index (ACC) and
- ///< in the data storage (TUP)
- };
-
-
- /**
* Type of fragmentation used for a table
*/
enum FragmentType {
@@ -405,27 +382,7 @@ public:
* the attribute.
* <br>
* Legal values: true, false
- * @param aStType Stored in both index and data storage or
- * only store in index data storage.
- * <br>
- * This parameter is only of interest for tuple
- * key attributes.
- * All tuple key attributes values are always stored
- * in the index storage part.
- * If this parameter is set to
- * IndexStorageAttribute, then the attribute values
- * will <em>only</em> be stored in the index
- * storage part and <em>not</em> in the data
- * storage part.
- * <br>
- * If there will be no scans using the primary
- * key attribute and if the size of the attribute
- * is large, then this might be of interest.
- * A typical example is a table where
- * http-addresses are used as primary key.
- * <br>
- * Legal values: NormalStorageAttribute,
- * IndexStorageAttribute
+ * @param aStType Obsolete since wl-2066
* @param aDistributionKey Sometimes it is preferable to use a subset
* of the primary key as the distribution key.
* An example is TPC-C where it might be
@@ -474,7 +431,7 @@ public:
AttrType aAttrType = UnSigned,
StorageMode aStorageMode = MMBased,
bool nullable = false,
- StorageAttributeType aStType= NormalStorageAttribute,
+ int aStType= 0, // obsolete
int aDistributionKey = 0,
int aDistributionGroup = 0,
int aDistributionGroupNoOfBits = 16,
@@ -491,7 +448,7 @@ public:
AttrType aAttrType,
StorageMode aStorageMode,
NullAttributeType aNullAttr,
- StorageAttributeType aStType = NormalStorageAttribute,
+ int aStType, // obsolete
int aDistributionKey = 0,
int aDistributionGroup = 0,
int aDistributionGroupNoOfBits = 16){
@@ -569,6 +526,8 @@ convertColumnTypeToAttrType(NdbDictionary::Column::Type _type)
case NdbDictionary::Column::Float:
case NdbDictionary::Column::Olddecimal:
case NdbDictionary::Column::Olddecimalunsigned:
+ case NdbDictionary::Column::Decimal:
+ case NdbDictionary::Column::Decimalunsigned:
case NdbDictionary::Column::Double:
return Float;
case NdbDictionary::Column::Char:
diff --git a/ndb/test/include/UtilTransactions.hpp b/ndb/test/include/UtilTransactions.hpp
index 23902f3b317..afdbc5c3445 100644
--- a/ndb/test/include/UtilTransactions.hpp
+++ b/ndb/test/include/UtilTransactions.hpp
@@ -23,15 +23,11 @@ typedef int (ReadCallBackFn)(NDBT_ResultRow*);
class UtilTransactions {
public:
- enum ScanLock {
- SL_Read = 0,
- SL_ReadHold = 1,
- SL_Exclusive = 2
- };
-
- UtilTransactions(const NdbDictionary::Table&);
- UtilTransactions(Ndb* ndb, const char * tableName);
-
+ UtilTransactions(const NdbDictionary::Table&,
+ const NdbDictionary::Index* idx = 0);
+ UtilTransactions(Ndb* ndb,
+ const char * tableName, const char * indexName = 0);
+
int clearTable(Ndb*,
int records = 0,
int parallelism = 0);
@@ -70,6 +66,14 @@ public:
int copyTableData(Ndb*,
const char* destName);
+ /**
+ * Compare this table with other_table
+ *
+ * return 0 - on equality
+ * -1 - on error
+ * >0 - otherwise
+ */
+ int compare(Ndb*, const char * other_table, int flags);
private:
static int takeOverAndDeleteRecord(Ndb*,
@@ -114,6 +118,12 @@ private:
protected:
int m_defaultClearMethod;
const NdbDictionary::Table& tab;
+ const NdbDictionary::Index* idx;
+ NdbConnection* pTrans;
+
+ NdbOperation* getOperation(NdbConnection*,
+ NdbOperation::OperationType);
+ NdbScanOperation* getScanOperation(NdbConnection*);
};
#endif
diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am
index 6f04ac3fce2..1d2dfb3f948 100644
--- a/ndb/test/ndbapi/Makefile.am
+++ b/ndb/test/ndbapi/Makefile.am
@@ -31,7 +31,10 @@ testTimeout \
testTransactions \
testDeadlock \
test_event ndbapi_slow_select testReadPerf testLcp \
-DbCreate DbAsyncGenerator
+testPartitioning \
+testBitfield \
+DbCreate DbAsyncGenerator \
+test_event_multi_table
#flexTimedAsynch
#testBlobs
@@ -70,8 +73,11 @@ test_event_SOURCES = test_event.cpp
ndbapi_slow_select_SOURCES = slow_select.cpp
testReadPerf_SOURCES = testReadPerf.cpp
testLcp_SOURCES = testLcp.cpp
-DbCreate_SOURCES= bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp bench/dbPopulate.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
-DbAsyncGenerator_SOURCES= bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
+testPartitioning_SOURCES = testPartitioning.cpp
+testBitfield_SOURCES = testBitfield.cpp
+DbCreate_SOURCES = bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp bench/dbPopulate.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
+DbAsyncGenerator_SOURCES = bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
+test_event_multi_table_SOURCES = test_event_multi_table.cpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel
@@ -87,6 +93,8 @@ testBackup_LDADD = $(LDADD) bank/libbank.a
# Don't update the files from bitkeeper
%::SCCS/s.%
+
+
windoze-dsp: flexBench.dsp testBasic.dsp testBlobs.dsp \
testScan.dsp
diff --git a/ndb/test/ndbapi/ScanFunctions.hpp b/ndb/test/ndbapi/ScanFunctions.hpp
index 6964f8c73a8..37389d9b7de 100644
--- a/ndb/test/ndbapi/ScanFunctions.hpp
+++ b/ndb/test/ndbapi/ScanFunctions.hpp
@@ -81,7 +81,6 @@ ScanFunctions::scanReadFunctions(Ndb* pNdb,
int check;
NdbConnection *pTrans = 0;
NdbScanOperation *pOp = 0;
- NdbResultSet *rs = 0;
while (true){
if (retryAttempt >= retryMax){
@@ -111,12 +110,9 @@ ScanFunctions::scanReadFunctions(Ndb* pNdb,
return NDBT_FAILED;
}
-
- rs = pOp->readTuples(exclusive ?
- NdbScanOperation::LM_Exclusive :
- NdbScanOperation::LM_Read);
-
- if( rs == 0 ) {
+ if( pOp->readTuples(exclusive ?
+ NdbScanOperation::LM_Exclusive :
+ NdbScanOperation::LM_Read) ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -125,8 +121,7 @@ ScanFunctions::scanReadFunctions(Ndb* pNdb,
if (action == OnlyOpenScanOnce){
// Call openScan one more time when it's already defined
- NdbResultSet* rs2 = pOp->readTuples(NdbScanOperation::LM_Read);
- if( rs2 == 0 ) {
+ if( pOp->readTuples(NdbScanOperation::LM_Read) ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -168,7 +163,7 @@ ScanFunctions::scanReadFunctions(Ndb* pNdb,
bool abortTrans = (action==CloseWithoutStop);
int eof;
int rows = 0;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
while(eof == 0){
rows++;
@@ -178,7 +173,7 @@ ScanFunctions::scanReadFunctions(Ndb* pNdb,
if (action != CloseWithoutStop){
// Test that we can closeTrans without stopScan
- rs->close();
+ pOp->close();
if( check == -1 ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
@@ -201,7 +196,7 @@ ScanFunctions::scanReadFunctions(Ndb* pNdb,
}
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
const NdbError err = pTrans->getNdbError();
@@ -211,7 +206,7 @@ ScanFunctions::scanReadFunctions(Ndb* pNdb,
// Be cruel, call nextScanResult after error
for(int i=0; i<10; i++){
- eof = rs->nextResult();
+ eof = pOp->nextResult();
if(eof == 0){
g_err << "nextScanResult returned eof = " << eof << endl
<< " That is an error when there are no more records" << endl;
@@ -241,7 +236,7 @@ ScanFunctions::scanReadFunctions(Ndb* pNdb,
if (action == NextScanWhenNoMore){
g_info << "Calling nextScanresult when there are no more records" << endl;
for(int i=0; i<10; i++){
- eof = rs->nextResult();
+ eof = pOp->nextResult();
if(eof == 0){
g_err << "nextScanResult returned eof = " << eof << endl
<< " That is an error when there are no more records" << endl;
diff --git a/ndb/test/ndbapi/ScanInterpretTest.hpp b/ndb/test/ndbapi/ScanInterpretTest.hpp
index e8a0d4b6dca..d4e9bbecc81 100644
--- a/ndb/test/ndbapi/ScanInterpretTest.hpp
+++ b/ndb/test/ndbapi/ScanInterpretTest.hpp
@@ -227,10 +227,7 @@ ScanInterpretTest::scanRead(Ndb* pNdb,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples(NdbScanOperation::LM_Read,
- 0, parallelism);
-
- if( rs == 0 ) {
+ if( pOp->readTuples(NdbScanOperation::LM_Read, 0, parallelism) ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -262,14 +259,14 @@ ScanInterpretTest::scanRead(Ndb* pNdb,
int rows = 0;
NdbConnection* pInsTrans;
- while((eof = rs->nextResult(true)) == 0){
+ while((eof = pOp->nextResult(true)) == 0){
do {
rows++;
if (addRowToInsert(pNdb, pTrans) != 0){
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
}
- } while((eof = rs->nextResult(false)) == 0);
+ } while((eof = pOp->nextResult(false)) == 0);
check = pTrans->execute(Commit);
if( check == -1 ) {
@@ -349,9 +346,7 @@ ScanInterpretTest::scanReadVerify(Ndb* pNdb,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples(NdbScanOperation::LM_Read,
- 0, parallelism);
- if( rs == 0 ) {
+ if( pOp->readTuples(NdbScanOperation::LM_Read, 0, parallelism) ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -392,7 +387,7 @@ ScanInterpretTest::scanReadVerify(Ndb* pNdb,
NdbConnection* pExistTrans;
NdbConnection* pNoExistTrans;
- while((eof = rs->nextResult(true)) == 0){
+ while((eof = pOp->nextResult(true)) == 0){
pExistTrans = pNdb->startTransaction();
if (pExistTrans == NULL) {
const NdbError err = pNdb->getNdbError();
@@ -424,7 +419,7 @@ ScanInterpretTest::scanReadVerify(Ndb* pNdb,
return NDBT_FAILED;
}
}
- } while((eof = rs->nextResult(false)) == 0);
+ } while((eof = pOp->nextResult(false)) == 0);
// Execute the transaction containing reads of
diff --git a/ndb/test/ndbapi/bank/Bank.cpp b/ndb/test/ndbapi/bank/Bank.cpp
index c6029259357..40819ecc849 100644
--- a/ndb/test/ndbapi/bank/Bank.cpp
+++ b/ndb/test/ndbapi/bank/Bank.cpp
@@ -19,8 +19,8 @@
#include <NdbSleep.h>
#include <UtilTransactions.hpp>
-Bank::Bank():
- m_ndb("BANK"),
+Bank::Bank(Ndb_cluster_connection& con):
+ m_ndb(&con, "BANK"),
m_maxAccount(-1),
m_initialized(false)
{
@@ -669,8 +669,7 @@ int Bank::findLastGL(Uint64 &lastTime){
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples();
- if( rs == 0 ) {
+ if( pOp->readTuples() ) {
ERR(pScanTrans->getNdbError());
m_ndb.closeTransaction(pScanTrans);
return NDBT_FAILED;
@@ -699,7 +698,7 @@ int Bank::findLastGL(Uint64 &lastTime){
int eof;
int rows = 0;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
lastTime = 0;
while(eof == 0){
@@ -709,7 +708,7 @@ int Bank::findLastGL(Uint64 &lastTime){
if (t > lastTime)
lastTime = t;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
ERR(pScanTrans->getNdbError());
@@ -1001,8 +1000,7 @@ int Bank::sumTransactionsForGL(const Uint64 glTime,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuplesExclusive();
- if( rs == 0 ) {
+ if( pOp->readTuplesExclusive()) {
ERR(pScanTrans->getNdbError());
m_ndb.closeTransaction(pScanTrans);
return NDBT_FAILED;
@@ -1053,7 +1051,7 @@ int Bank::sumTransactionsForGL(const Uint64 glTime,
int eof;
int rows = 0;
int rowsFound = 0;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
while(eof == 0){
rows++;
@@ -1077,7 +1075,7 @@ int Bank::sumTransactionsForGL(const Uint64 glTime,
}
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
if ((rows % 100) == 0){
// "refresh" ownner transaction every 100th row
@@ -1161,8 +1159,7 @@ int Bank::performValidateGL(Uint64 glTime){
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples();
- if( rs == 0 ) {
+ if( pOp->readTuples() ) {
ERR(pScanTrans->getNdbError());
m_ndb.closeTransaction(pScanTrans);
return NDBT_FAILED;
@@ -1241,7 +1238,7 @@ int Bank::performValidateGL(Uint64 glTime){
int rows = 0;
int countGlRecords = 0;
int result = NDBT_OK;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
while(eof == 0){
rows++;
@@ -1328,7 +1325,7 @@ int Bank::performValidateGL(Uint64 glTime){
}
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
ERR(pScanTrans->getNdbError());
@@ -1425,8 +1422,7 @@ int Bank::getOldestPurgedGL(const Uint32 accountType,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples();
- if( rs == 0 ) {
+ if( pOp->readTuples() ) {
ERR(pScanTrans->getNdbError());
m_ndb.closeTransaction(pScanTrans);
return NDBT_FAILED;
@@ -1469,7 +1465,7 @@ int Bank::getOldestPurgedGL(const Uint32 accountType,
int eof;
int rows = 0;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
oldest = 0;
while(eof == 0){
@@ -1483,7 +1479,7 @@ int Bank::getOldestPurgedGL(const Uint32 accountType,
if (t > oldest)
oldest = t;
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
ERR(pScanTrans->getNdbError());
@@ -1517,8 +1513,7 @@ int Bank::getOldestNotPurgedGL(Uint64 &oldest,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples();
- if( rs == 0 ) {
+ if( pOp->readTuples() ) {
ERR(pScanTrans->getNdbError());
m_ndb.closeTransaction(pScanTrans);
return NDBT_FAILED;
@@ -1561,7 +1556,7 @@ int Bank::getOldestNotPurgedGL(Uint64 &oldest,
int eof;
int rows = 0;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
oldest = (Uint64)-1;
found = false;
@@ -1578,7 +1573,7 @@ int Bank::getOldestNotPurgedGL(Uint64 &oldest,
accountTypeId = a;
}
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
ERR(pScanTrans->getNdbError());
@@ -1614,8 +1609,7 @@ int Bank::checkNoTransactionsOlderThan(const Uint32 accountType,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples();
- if( rs == 0 ) {
+ if( pOp->readTuples() ) {
ERR(pScanTrans->getNdbError());
m_ndb.closeTransaction(pScanTrans);
return NDBT_FAILED;
@@ -1659,7 +1653,7 @@ int Bank::checkNoTransactionsOlderThan(const Uint32 accountType,
int eof;
int rows = 0;
int found = 0;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
while(eof == 0){
rows++;
@@ -1675,7 +1669,7 @@ int Bank::checkNoTransactionsOlderThan(const Uint32 accountType,
<< " ti = " << ti << endl;
found++;
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
ERR(pScanTrans->getNdbError());
@@ -1858,8 +1852,7 @@ int Bank::findTransactionsToPurge(const Uint64 glTime,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuplesExclusive();
- if( rs == 0 ) {
+ if( pOp->readTuplesExclusive() ) {
ERR(pScanTrans->getNdbError());
m_ndb.closeTransaction(pScanTrans);
return NDBT_FAILED;
@@ -1896,7 +1889,7 @@ int Bank::findTransactionsToPurge(const Uint64 glTime,
int eof;
int rows = 0;
int rowsFound = 0;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
while(eof == 0){
rows++;
@@ -1906,7 +1899,7 @@ int Bank::findTransactionsToPurge(const Uint64 glTime,
if (a == accountType && t == glTime){
rowsFound++;
// One record found
- check = rs->deleteTuple(pTrans);
+ check = pOp->deleteCurrentTuple(pTrans);
if (check == -1){
ERR(m_ndb.getNdbError());
m_ndb.closeTransaction(pScanTrans);
@@ -1921,7 +1914,7 @@ int Bank::findTransactionsToPurge(const Uint64 glTime,
return NDBT_FAILED;
}
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
ERR(pScanTrans->getNdbError());
@@ -2367,8 +2360,7 @@ int Bank::getSumAccounts(Uint32 &sumAccounts,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuplesExclusive();
- if( rs == 0 ) {
+ if( pOp->readTuplesExclusive() ) {
ERR(pScanTrans->getNdbError());
m_ndb.closeTransaction(pScanTrans);
return NDBT_FAILED;
@@ -2403,7 +2395,7 @@ int Bank::getSumAccounts(Uint32 &sumAccounts,
}
int eof;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
while(eof == 0){
Uint32 b = balanceRec->u_32_value();
@@ -2415,7 +2407,7 @@ int Bank::getSumAccounts(Uint32 &sumAccounts,
// << ", sum="<< sumAccounts << endl;
// Take over the operation so that the lock is kept in db
- NdbOperation* pLockOp = rs->updateTuple(pTrans);
+ NdbOperation* pLockOp = pOp->updateCurrentTuple(pTrans);
if (pLockOp == NULL){
ERR(m_ndb.getNdbError());
m_ndb.closeTransaction(pScanTrans);
@@ -2441,7 +2433,7 @@ int Bank::getSumAccounts(Uint32 &sumAccounts,
return NDBT_FAILED;
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
ERR(pScanTrans->getNdbError());
diff --git a/ndb/test/ndbapi/bank/Bank.hpp b/ndb/test/ndbapi/bank/Bank.hpp
index 34c5ff51cc2..d9dd7b25944 100644
--- a/ndb/test/ndbapi/bank/Bank.hpp
+++ b/ndb/test/ndbapi/bank/Bank.hpp
@@ -27,7 +27,7 @@
class Bank {
public:
- Bank();
+ Bank(Ndb_cluster_connection&);
int createAndLoadBank(bool overWrite, int num_accounts=10);
int dropBank();
diff --git a/ndb/test/ndbapi/bank/BankLoad.cpp b/ndb/test/ndbapi/bank/BankLoad.cpp
index 39dc8097115..34947019a51 100644
--- a/ndb/test/ndbapi/bank/BankLoad.cpp
+++ b/ndb/test/ndbapi/bank/BankLoad.cpp
@@ -321,7 +321,7 @@ int Bank::loadGl(){
m_ndb.closeTransaction(pTrans);
return NDBT_OK;
-};
+}
int Bank::getBalanceForAccountType(const Uint32 accountType,
@@ -342,8 +342,7 @@ int Bank::getBalanceForAccountType(const Uint32 accountType,
return NDBT_FAILED;
}
- NdbResultSet* rs = pOp->readTuples();
- if( rs == 0 ) {
+ if( pOp->readTuples() ) {
ERR(pScanTrans->getNdbError());
m_ndb.closeTransaction(pScanTrans);
return NDBT_FAILED;
@@ -379,7 +378,7 @@ int Bank::getBalanceForAccountType(const Uint32 accountType,
int eof;
int rows = 0;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
while(eof == 0){
rows++;
@@ -391,7 +390,7 @@ int Bank::getBalanceForAccountType(const Uint32 accountType,
balance += b;
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
ERR(pScanTrans->getNdbError());
@@ -460,7 +459,7 @@ int Bank::loadAccountType(){
m_ndb.closeTransaction(pTrans);
return NDBT_OK;
-};
+}
/**
* Load ACCOUNT table
diff --git a/ndb/test/ndbapi/bank/bankCreator.cpp b/ndb/test/ndbapi/bank/bankCreator.cpp
index 301d8bda6d2..257255babc8 100644
--- a/ndb/test/ndbapi/bank/bankCreator.cpp
+++ b/ndb/test/ndbapi/bank/bankCreator.cpp
@@ -43,7 +43,13 @@ int main(int argc, const char** argv){
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Bank bank;
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ Bank bank(con);
int overWriteExisting = true;
if (bank.createAndLoadBank(overWriteExisting) != NDBT_OK)
return NDBT_ProgramExit(NDBT_FAILED);
diff --git a/ndb/test/ndbapi/bank/bankMakeGL.cpp b/ndb/test/ndbapi/bank/bankMakeGL.cpp
index 9e2762ed8ae..cf373481e3e 100644
--- a/ndb/test/ndbapi/bank/bankMakeGL.cpp
+++ b/ndb/test/ndbapi/bank/bankMakeGL.cpp
@@ -43,7 +43,13 @@ int main(int argc, const char** argv){
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Bank bank;
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ Bank bank(con);
if (bank.performMakeGLs() != 0)
return NDBT_ProgramExit(NDBT_FAILED);
diff --git a/ndb/test/ndbapi/bank/bankSumAccounts.cpp b/ndb/test/ndbapi/bank/bankSumAccounts.cpp
index b576161b27b..034f70f8f95 100644
--- a/ndb/test/ndbapi/bank/bankSumAccounts.cpp
+++ b/ndb/test/ndbapi/bank/bankSumAccounts.cpp
@@ -43,7 +43,13 @@ int main(int argc, const char** argv){
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Bank bank;
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ Bank bank(con);
if (bank.performSumAccounts() != 0)
return NDBT_ProgramExit(NDBT_FAILED);
diff --git a/ndb/test/ndbapi/bank/bankTimer.cpp b/ndb/test/ndbapi/bank/bankTimer.cpp
index 874afd9c21e..298f85e1e43 100644
--- a/ndb/test/ndbapi/bank/bankTimer.cpp
+++ b/ndb/test/ndbapi/bank/bankTimer.cpp
@@ -46,7 +46,13 @@ int main(int argc, const char** argv){
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Bank bank;
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ Bank bank(con);
if (bank.performIncreaseTime(_wait) != 0)
return NDBT_ProgramExit(NDBT_FAILED);
diff --git a/ndb/test/ndbapi/bank/bankTransactionMaker.cpp b/ndb/test/ndbapi/bank/bankTransactionMaker.cpp
index e5ff9aeb918..f8e646b6553 100644
--- a/ndb/test/ndbapi/bank/bankTransactionMaker.cpp
+++ b/ndb/test/ndbapi/bank/bankTransactionMaker.cpp
@@ -46,7 +46,13 @@ int main(int argc, const char** argv){
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Bank bank;
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ Bank bank(con);
if (bank.performTransactions(_wait) != 0)
return NDBT_ProgramExit(NDBT_FAILED);
diff --git a/ndb/test/ndbapi/bank/bankValidateAllGLs.cpp b/ndb/test/ndbapi/bank/bankValidateAllGLs.cpp
index cf298ecc8e3..0c268121d8a 100644
--- a/ndb/test/ndbapi/bank/bankValidateAllGLs.cpp
+++ b/ndb/test/ndbapi/bank/bankValidateAllGLs.cpp
@@ -44,7 +44,13 @@ int main(int argc, const char** argv){
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Bank bank;
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ Bank bank(con);
if (bank.performValidateAllGLs() != 0)
return NDBT_ProgramExit(NDBT_FAILED);
diff --git a/ndb/test/ndbapi/bank/testBank.cpp b/ndb/test/ndbapi/bank/testBank.cpp
index 3ef2799cd3c..6be66d528b1 100644
--- a/ndb/test/ndbapi/bank/testBank.cpp
+++ b/ndb/test/ndbapi/bank/testBank.cpp
@@ -32,7 +32,7 @@
#include "Bank.hpp"
int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int overWriteExisting = true;
if (bank.createAndLoadBank(overWriteExisting) != NDBT_OK)
return NDBT_FAILED;
@@ -40,7 +40,7 @@ int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){
}
int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int wait = 30; // Max seconds between each "day"
int yield = 1; // Loops before bank returns
@@ -51,7 +51,7 @@ int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){
}
int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int wait = 10; // Max ms between each transaction
int yield = 100; // Loops before bank returns
@@ -62,7 +62,7 @@ int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){
}
int runBankGL(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int yield = 20; // Loops before bank returns
int result = NDBT_OK;
@@ -76,7 +76,7 @@ int runBankGL(NDBT_Context* ctx, NDBT_Step* step){
}
int runBankSum(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int wait = 2000; // Max ms between each sum of accounts
int yield = 1; // Loops before bank returns
int result = NDBT_OK;
@@ -91,7 +91,7 @@ int runBankSum(NDBT_Context* ctx, NDBT_Step* step){
}
int runDropBank(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
if (bank.dropBank() != NDBT_OK)
return NDBT_FAILED;
return NDBT_OK;
diff --git a/ndb/test/ndbapi/bench/userInterface.cpp b/ndb/test/ndbapi/bench/userInterface.cpp
index 683552c3133..35e88183230 100644
--- a/ndb/test/ndbapi/bench/userInterface.cpp
+++ b/ndb/test/ndbapi/bench/userInterface.cpp
@@ -173,7 +173,7 @@ create_table_server(Ndb * pNdb){
String,
MMBased,
NotNullAttribute,
- NormalStorageAttribute,
+ 0,
0,
1,
16);
@@ -376,7 +376,7 @@ create_table_subscriber(Ndb * pNdb){
String,
MMBased,
NotNullAttribute,
- NormalStorageAttribute,
+ 0,
0,
1,
16);
@@ -494,7 +494,7 @@ create_table_session(Ndb * pNdb){
String,
MMBased,
NotNullAttribute,
- NormalStorageAttribute,
+ 0,
0,
1,
16);
diff --git a/ndb/test/ndbapi/bench/userInterface.h b/ndb/test/ndbapi/bench/userInterface.h
index 9e3b6f8f2a5..bad61fcf171 100644
--- a/ndb/test/ndbapi/bench/userInterface.h
+++ b/ndb/test/ndbapi/bench/userInterface.h
@@ -101,7 +101,7 @@ extern "C" {
typedef struct {
struct Ndb_cluster_connection* pNCC;
struct Ndb * pNDB;
- struct NdbConnection * pCurrTrans;
+ struct NdbTransaction * pCurrTrans;
} UserHandle;
/***************************************************************
diff --git a/ndb/test/ndbapi/create_all_tabs.cpp b/ndb/test/ndbapi/create_all_tabs.cpp
index 97236b98b36..f06078d67a2 100644
--- a/ndb/test/ndbapi/create_all_tabs.cpp
+++ b/ndb/test/ndbapi/create_all_tabs.cpp
@@ -47,7 +47,12 @@ int main(int argc, const char** argv){
}
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/ndbapi/create_tab.cpp b/ndb/test/ndbapi/create_tab.cpp
index f3f18982ed0..b35c8655236 100644
--- a/ndb/test/ndbapi/create_tab.cpp
+++ b/ndb/test/ndbapi/create_tab.cpp
@@ -77,8 +77,12 @@ int main(int argc, const char** argv){
*/
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
- MyNdb.setConnectString(_connectstr);
+ Ndb_cluster_connection con(_connectstr);
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/ndbapi/drop_all_tabs.cpp b/ndb/test/ndbapi/drop_all_tabs.cpp
index c024a81a5e6..f12d750916e 100644
--- a/ndb/test/ndbapi/drop_all_tabs.cpp
+++ b/ndb/test/ndbapi/drop_all_tabs.cpp
@@ -40,7 +40,13 @@ int main(int argc, const char** argv){
}
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/ndbapi/flexAsynch.cpp b/ndb/test/ndbapi/flexAsynch.cpp
index 4b87b2c70ed..8a7dbec1561 100644
--- a/ndb/test/ndbapi/flexAsynch.cpp
+++ b/ndb/test/ndbapi/flexAsynch.cpp
@@ -16,6 +16,7 @@
+#include <ndb_global.h>
#include "NdbApi.hpp"
#include <NdbSchemaCon.hpp>
#include <NdbMain.h>
@@ -143,6 +144,8 @@ tellThreads(StartType what)
ThreadStart[i] = what;
}
+static Ndb_cluster_connection *g_cluster_connection= 0;
+
NDB_COMMAND(flexAsynch, "flexAsynch", "flexAsynch", "flexAsynch", 65535)
{
ndb_init();
@@ -200,7 +203,14 @@ NDB_COMMAND(flexAsynch, "flexAsynch", "flexAsynch", "flexAsynch", 65535)
setAttrNames();
setTableNames();
- Ndb * pNdb = new Ndb("TEST_DB");
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ g_cluster_connection= &con;
+
+ Ndb * pNdb = new Ndb(g_cluster_connection, "TEST_DB");
pNdb->init();
tNodeId = pNdb->getNodeId();
@@ -225,7 +235,7 @@ NDB_COMMAND(flexAsynch, "flexAsynch", "flexAsynch", "flexAsynch", 65535)
* Create NDB objects. *
****************************************************************/
resetThreads();
- for (int i = 0; i < tNoOfThreads ; i++) {
+ for (i = 0; i < tNoOfThreads ; i++) {
pThreadData[i].ThreadNo = i
;
threadLife[i] = NdbThread_Create(threadLoop,
@@ -468,7 +478,7 @@ threadLoop(void* ThreadData)
StartType tType;
ThreadNdb* tabThread = (ThreadNdb*)ThreadData;
int threadNo = tabThread->ThreadNo;
- localNdb = new Ndb("TEST_DB");
+ localNdb = new Ndb(g_cluster_connection, "TEST_DB");
localNdb->init(1024);
localNdb->waitUntilReady(10000);
unsigned int threadBase = (threadNo << 16) + tNodeId ;
diff --git a/ndb/test/ndbapi/flexBench.cpp b/ndb/test/ndbapi/flexBench.cpp
index cc2bfb391da..abddecfdc40 100644
--- a/ndb/test/ndbapi/flexBench.cpp
+++ b/ndb/test/ndbapi/flexBench.cpp
@@ -49,6 +49,7 @@ Arguments:
* *************************************************** */
+#include <ndb_global.h>
#include "NdbApi.hpp"
#include <NdbMain.h>
@@ -279,6 +280,8 @@ tellThreads(ThreadData* pt, StartType what)
pt[i].threadStart = what;
}
+static Ndb_cluster_connection *g_cluster_connection= 0;
+
NDB_COMMAND(flexBench, "flexBench", "flexBench", "flexbench", 65535)
{
ndb_init();
@@ -326,8 +329,16 @@ NDB_COMMAND(flexBench, "flexBench", "flexBench", "flexbench", 65535)
NdbThread_SetConcurrencyLevel(tNoOfThreads + 2);
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ g_cluster_connection= &con;
+
Ndb* pNdb;
- pNdb = new Ndb( "TEST_DB" );
+ pNdb = new Ndb(&con, "TEST_DB" );
pNdb->init();
tNodeId = pNdb->getNodeId();
@@ -605,7 +616,7 @@ static void* flexBenchThread(void* pArg)
attrValue = (int*)malloc(nReadBuffSize) ;
attrRefValue = (int*)malloc(nRefBuffSize) ;
pOps = (NdbOperation**)malloc(tNoOfTables*sizeof(NdbOperation*)) ;
- pNdb = new Ndb( "TEST_DB" );
+ pNdb = new Ndb(g_cluster_connection, "TEST_DB" );
if(!attrValue || !attrRefValue || !pOps || !pNdb){
// Check allocations to make sure we got all the memory we asked for
diff --git a/ndb/test/ndbapi/flexHammer.cpp b/ndb/test/ndbapi/flexHammer.cpp
index 13cd2d5e561..f254b1e5ccf 100644
--- a/ndb/test/ndbapi/flexHammer.cpp
+++ b/ndb/test/ndbapi/flexHammer.cpp
@@ -47,6 +47,7 @@ Revision history:
* *************************************************** */
+#include <ndb_global.h>
#include <NdbApi.hpp>
#include <NdbMain.h>
@@ -174,6 +175,8 @@ tellThreads(ThreadNdb* threadArrayP, const StartType what)
threadArrayP[i].threadStart = what;
} // for
} // tellThreads
+
+static Ndb_cluster_connection *g_cluster_connection= 0;
NDB_COMMAND(flexHammer, "flexHammer", "flexHammer", "flexHammer", 65535)
//main(int argc, const char** argv)
@@ -213,7 +216,13 @@ NDB_COMMAND(flexHammer, "flexHammer", "flexHammer", "flexHammer", 65535)
// NdbThread_SetConcurrencyLevel(tNoOfThreads + 2);
// Create and init Ndb object
- pMyNdb = new Ndb("TEST_DB");
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ g_cluster_connection= &con;
+ pMyNdb = new Ndb(g_cluster_connection, "TEST_DB");
pMyNdb->init();
// Wait for Ndb to become ready
@@ -345,7 +354,7 @@ flexHammerThread(void* pArg)
for (i = 0; i < MAXATTRSIZE; i++)
attrValue[i] = 0;
// Ndb object for each thread
- pMyNdb = new Ndb( "TEST_DB" );
+ pMyNdb = new Ndb(g_cluster_connection, "TEST_DB" );
pMyNdb->init();
if (pMyNdb->waitUntilReady(10000) != 0) {
// Error, NDB is not ready
diff --git a/ndb/test/ndbapi/flexTT.cpp b/ndb/test/ndbapi/flexTT.cpp
index 8d5be2bb399..7cd5ac8e3b4 100644
--- a/ndb/test/ndbapi/flexTT.cpp
+++ b/ndb/test/ndbapi/flexTT.cpp
@@ -169,6 +169,8 @@ tellThreads(StartType what)
ThreadStart[i] = what;
}
+static Ndb_cluster_connection *g_cluster_connection= 0;
+
NDB_COMMAND(flexTT, "flexTT", "flexTT", "flexTT", 65535)
{
ndb_init();
@@ -226,7 +228,14 @@ NDB_COMMAND(flexTT, "flexTT", "flexTT", "flexTT", 65535)
setAttrNames();
setTableNames();
- Ndb * pNdb = new Ndb("TEST_DB");
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ g_cluster_connection= &con;
+
+ Ndb * pNdb = new Ndb(g_cluster_connection, "TEST_DB");
pNdb->init();
tNodeId = pNdb->getNodeId();
@@ -334,7 +343,7 @@ threadLoop(void* ThreadData)
void * mem = malloc(sizeof(TransNdb)*tNoOfParallelTrans);
TransNdb* pTransData = (TransNdb*)mem;
- localNdb = new Ndb("TEST_DB");
+ localNdb = new Ndb(g_cluster_connection, "TEST_DB");
localNdb->init(1024);
localNdb->waitUntilReady();
diff --git a/ndb/test/ndbapi/flex_bench_mysql.cpp b/ndb/test/ndbapi/flex_bench_mysql.cpp
index c15175bfb00..3efb7ee2094 100644
--- a/ndb/test/ndbapi/flex_bench_mysql.cpp
+++ b/ndb/test/ndbapi/flex_bench_mysql.cpp
@@ -397,6 +397,7 @@ NDB_COMMAND(flexBench, "flexBench", "flexBench", "flexbench", 65535)
ndbout << "Connect failed" <<endl;
returnValue = NDBT_FAILED;
}
+ mysql.reconnect= 1;
}
if(returnValue == NDBT_OK){
mysql_set_server_option(&mysql, MYSQL_OPTION_MULTI_STATEMENTS_ON);
@@ -712,6 +713,7 @@ static void* flexBenchThread(void* pArg)
ndbout << "failed" << endl;
return 0;
}
+ mysql.reconnect= 1;
ndbout << "ok" << endl;
int r;
diff --git a/ndb/test/ndbapi/slow_select.cpp b/ndb/test/ndbapi/slow_select.cpp
index 625dbc34457..8d615fa5771 100644
--- a/ndb/test/ndbapi/slow_select.cpp
+++ b/ndb/test/ndbapi/slow_select.cpp
@@ -1,4 +1,5 @@
+#include <ndb_global.h>
#include <NdbApi.hpp>
#include <NdbOut.hpp>
#include <NdbTick.h>
@@ -8,18 +9,17 @@ S_Scan {
const char * m_table;
const char * m_index;
NdbIndexScanOperation * m_scan;
- NdbResultSet * m_result;
Uint32 metaid;
Uint32 match_count;
Uint32 row_count;
};
static S_Scan g_scans[] = {
- { "affiliatestometa", "ind_affiliatestometa", 0, 0, 0, 0, 0 },
- { "media", "metaid", 0, 0, 0, 0, 0 },
- { "meta", "PRIMARY", 0, 0, 0, 0, 0 },
- { "artiststometamap", "PRIMARY", 0, 0, 0, 0, 0 },
- { "subgenrestometamap", "metaid", 0, 0, 0, 0, 0 }
+ { "affiliatestometa", "ind_affiliatestometa", 0, 0, 0, 0 },
+ { "media", "metaid", 0, 0, 0, 0 },
+ { "meta", "PRIMARY", 0, 0, 0, 0 },
+ { "artiststometamap", "PRIMARY", 0, 0, 0, 0 },
+ { "subgenrestometamap", "metaid", 0, 0, 0, 0 }
};
#define require(x) if(!(x)) { ndbout << "LINE: " << __LINE__ << endl;abort(); }
@@ -37,7 +37,14 @@ static void lookup();
int
main(void){
ndb_init();
- Ndb g_ndb("test");
+
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return 1;
+ }
+
+ Ndb g_ndb(&con, "test");
g_ndb.init(1024);
require(g_ndb.waitUntilReady() == 0);
@@ -58,9 +65,8 @@ main(void){
g_scans[i].m_table);
NdbIndexScanOperation* scan = g_scans[i].m_scan;
require(scan);
- g_scans[i].m_result = scan->readTuples(NdbScanOperation::LM_CommittedRead,
- 0, 0, true);
- require(g_scans[i].m_result);
+ require(scan->readTuples(NdbScanOperation::LM_CommittedRead,
+ 0, 0, true) == 0);
}
require(!g_scans[0].m_scan->setBound((Uint32)0,
@@ -125,7 +131,7 @@ main(void){
//ndbout_c("%s - %d", g_scans[i].m_table, g_scans[i].metaid);
for(i = 0; i<prev_F_sz; i++){
- int res = F[i]->m_result->nextResult();
+ int res = F[i]->m_scan->nextResult();
if(res == -1)
abort();
diff --git a/ndb/test/ndbapi/testBackup.cpp b/ndb/test/ndbapi/testBackup.cpp
index bea5d5307e2..7a6f11a6bb9 100644
--- a/ndb/test/ndbapi/testBackup.cpp
+++ b/ndb/test/ndbapi/testBackup.cpp
@@ -216,7 +216,7 @@ int runDropTable(NDBT_Context* ctx, NDBT_Step* step){
#include "bank/Bank.hpp"
int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int overWriteExisting = true;
if (bank.createAndLoadBank(overWriteExisting, 10) != NDBT_OK)
return NDBT_FAILED;
@@ -224,7 +224,7 @@ int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){
}
int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int wait = 30; // Max seconds between each "day"
int yield = 1; // Loops before bank returns
@@ -235,7 +235,7 @@ int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){
}
int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int wait = 10; // Max ms between each transaction
int yield = 100; // Loops before bank returns
@@ -246,7 +246,7 @@ int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){
}
int runBankGL(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int yield = 20; // Loops before bank returns
int result = NDBT_OK;
@@ -260,7 +260,7 @@ int runBankGL(NDBT_Context* ctx, NDBT_Step* step){
}
int runBankSum(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int wait = 2000; // Max ms between each sum of accounts
int yield = 1; // Loops before bank returns
int result = NDBT_OK;
@@ -275,7 +275,7 @@ int runBankSum(NDBT_Context* ctx, NDBT_Step* step){
}
int runDropBank(NDBT_Context* ctx, NDBT_Step* step){
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
if (bank.dropBank() != NDBT_OK)
return NDBT_FAILED;
return NDBT_OK;
@@ -349,7 +349,7 @@ int runRestoreBankAndVerify(NDBT_Context* ctx, NDBT_Step* step){
// To erase all tables from cache(s)
// To be removed, maybe replaced by ndb.invalidate();
{
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
if (bank.dropBank() != NDBT_OK){
result = NDBT_FAILED;
@@ -372,7 +372,7 @@ int runRestoreBankAndVerify(NDBT_Context* ctx, NDBT_Step* step){
ndbout << "Backup " << backupId << " restored" << endl;
// Let bank verify
- Bank bank;
+ Bank bank(ctx->m_cluster_connection);
int wait = 0;
int yield = 1;
diff --git a/ndb/test/ndbapi/testBitfield.cpp b/ndb/test/ndbapi/testBitfield.cpp
new file mode 100644
index 00000000000..e26f495f5a4
--- /dev/null
+++ b/ndb/test/ndbapi/testBitfield.cpp
@@ -0,0 +1,198 @@
+
+#include <ndb_global.h>
+#include <ndb_opts.h>
+#include <NDBT.hpp>
+#include <NdbApi.hpp>
+#include <HugoTransactions.hpp>
+
+static const char* _dbname = "TEST_DB";
+static int g_loops = 7;
+
+static void usage()
+{
+ ndb_std_print_version();
+}
+#if 0
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ const char *argument)
+{
+ return ndb_std_get_one_option(optid, opt, argument ? argument :
+ "d:t:O,/tmp/testBitfield.trace");
+}
+#endif
+
+static const NdbDictionary::Table* create_random_table(Ndb*);
+static int transactions(Ndb*, const NdbDictionary::Table* tab);
+static int unique_indexes(Ndb*, const NdbDictionary::Table* tab);
+static int ordered_indexes(Ndb*, const NdbDictionary::Table* tab);
+static int node_restart(Ndb*, const NdbDictionary::Table* tab);
+static int system_restart(Ndb*, const NdbDictionary::Table* tab);
+
+int
+main(int argc, char** argv){
+ NDB_INIT(argv[0]);
+ const char *load_default_groups[]= { "mysql_cluster",0 };
+ load_defaults("my",load_default_groups,&argc,&argv);
+ int ho_error;
+
+ argc--;
+ argv++;
+
+ Ndb_cluster_connection con(opt_connect_str);
+ if(con.connect(12, 5, 1))
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+
+ Ndb* pNdb;
+ pNdb = new Ndb(&con, _dbname);
+ pNdb->init();
+ while (pNdb->waitUntilReady() != 0);
+ int res = NDBT_FAILED;
+
+ NdbDictionary::Dictionary * dict = pNdb->getDictionary();
+
+ const NdbDictionary::Table* pTab = 0;
+ for (int i = 0; i < (argc ? argc : g_loops) ; i++)
+ {
+ res = NDBT_FAILED;
+ if(argc == 0)
+ {
+ pTab = create_random_table(pNdb);
+ }
+ else
+ {
+ dict->dropTable(argv[i]);
+ NDBT_Tables::createTable(pNdb, argv[i]);
+ pTab = dict->getTable(argv[i]);
+ }
+
+ if (pTab == 0)
+ {
+ ndbout << "Failed to create table" << endl;
+ ndbout << dict->getNdbError() << endl;
+ break;
+ }
+
+ if(transactions(pNdb, pTab))
+ break;
+
+ if(unique_indexes(pNdb, pTab))
+ break;
+
+ if(ordered_indexes(pNdb, pTab))
+ break;
+
+ if(node_restart(pNdb, pTab))
+ break;
+
+ if(system_restart(pNdb, pTab))
+ break;
+
+ dict->dropTable(pTab->getName());
+ res = NDBT_OK;
+ }
+
+ if(res != NDBT_OK && pTab)
+ {
+ dict->dropTable(pTab->getName());
+ }
+
+ delete pNdb;
+ return NDBT_ProgramExit(res);
+}
+
+static
+const NdbDictionary::Table*
+create_random_table(Ndb* pNdb)
+{
+ do {
+ NdbDictionary::Table tab;
+ Uint32 cols = 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 1));
+ Uint32 keys = NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY;
+ Uint32 length = 4090;
+ Uint32 key_size = NDB_MAX_KEYSIZE_IN_WORDS;
+
+ BaseString name;
+ name.assfmt("TAB_%d", rand() & 65535);
+ tab.setName(name.c_str());
+ for(int i = 0; i<cols && length > 2; i++)
+ {
+ NdbDictionary::Column col;
+ name.assfmt("COL_%d", i);
+ col.setName(name.c_str());
+ if(i == 0 || i == 1)
+ {
+ col.setType(NdbDictionary::Column::Unsigned);
+ col.setLength(1);
+ col.setNullable(false);
+ col.setPrimaryKey(i == 0);
+ tab.addColumn(col);
+ continue;
+ }
+
+ col.setType(NdbDictionary::Column::Bit);
+
+ Uint32 len = 1 + (rand() % (length - 1));
+ col.setLength(len); length -= len;
+ int nullable = (rand() >> 16) & 1;
+ col.setNullable(nullable); length -= nullable;
+ col.setPrimaryKey(false);
+ tab.addColumn(col);
+ }
+
+ pNdb->getDictionary()->dropTable(tab.getName());
+ if(pNdb->getDictionary()->createTable(tab) == 0)
+ {
+ ndbout << (NDBT_Table&)tab << endl;
+ return pNdb->getDictionary()->getTable(tab.getName());
+ }
+ } while(0);
+ return 0;
+}
+
+static
+int
+transactions(Ndb* pNdb, const NdbDictionary::Table* tab)
+{
+ int i = 0;
+ HugoTransactions trans(* tab);
+ i |= trans.loadTable(pNdb, 1000);
+ i |= trans.pkReadRecords(pNdb, 1000, 13);
+ i |= trans.scanReadRecords(pNdb, 1000, 25);
+ i |= trans.pkUpdateRecords(pNdb, 1000, 37);
+ i |= trans.scanUpdateRecords(pNdb, 1000, 25);
+ i |= trans.pkDelRecords(pNdb, 500, 23);
+ i |= trans.clearTable(pNdb);
+ return i;
+}
+
+static
+int
+unique_indexes(Ndb* pNdb, const NdbDictionary::Table* tab)
+{
+ return 0;
+}
+
+static
+int
+ordered_indexes(Ndb* pNdb, const NdbDictionary::Table* tab)
+{
+ return 0;
+}
+
+static
+int
+node_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
+{
+ return 0;
+}
+
+static
+int
+system_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
+{
+ return 0;
+}
diff --git a/ndb/test/ndbapi/testBlobs.cpp b/ndb/test/ndbapi/testBlobs.cpp
index 7b30777456f..3f5d1982522 100644
--- a/ndb/test/ndbapi/testBlobs.cpp
+++ b/ndb/test/ndbapi/testBlobs.cpp
@@ -741,10 +741,9 @@ verifyBlobTable(const Bcol& b, const Bval& v, Uint32 pk1, bool exists)
NdbRecAttr* ra_pk;
NdbRecAttr* ra_part;
NdbRecAttr* ra_data;
- NdbResultSet* rs;
CHK((g_con = g_ndb->startTransaction()) != 0);
CHK((g_ops = g_con->getNdbScanOperation(b.m_btname)) != 0);
- CHK((rs = g_ops->readTuples()) != 0);
+ CHK(g_ops->readTuples() == 0);
CHK((ra_pk = g_ops->getValue("PK")) != 0);
CHK((ra_part = g_ops->getValue("PART")) != 0);
CHK((ra_data = g_ops->getValue("DATA")) != 0);
@@ -758,7 +757,7 @@ verifyBlobTable(const Bcol& b, const Bval& v, Uint32 pk1, bool exists)
memset(seen, 0, partcount);
while (1) {
int ret;
- CHK((ret = rs->nextResult()) == 0 || ret == 1);
+ CHK((ret = g_ops->nextResult()) == 0 || ret == 1);
if (ret == 1)
break;
if (pk1 != ra_pk->u_32_value())
@@ -1106,14 +1105,13 @@ readScan(int style, bool idx)
DBG("--- " << "readScan" << (idx ? "Idx" : "") << " " << stylename[style] << " ---");
Tup tup;
tup.alloc(); // allocate buffers
- NdbResultSet* rs;
CHK((g_con = g_ndb->startTransaction()) != 0);
if (! idx) {
CHK((g_ops = g_con->getNdbScanOperation(g_opt.m_tname)) != 0);
} else {
CHK((g_ops = g_con->getNdbIndexScanOperation(g_opt.m_x2name, g_opt.m_tname)) != 0);
}
- CHK((rs = g_ops->readTuples(NdbScanOperation::LM_Read)) != 0);
+ CHK(g_ops->readTuples(NdbScanOperation::LM_Read) == 0);
CHK(g_ops->getValue("PK1", (char*)&tup.m_pk1) != 0);
if (g_opt.m_pk2len != 0)
CHK(g_ops->getValue("PK2", tup.m_pk2) != 0);
@@ -1129,7 +1127,7 @@ readScan(int style, bool idx)
int ret;
tup.m_pk1 = (Uint32)-1;
memset(tup.m_pk2, 'x', g_opt.m_pk2len);
- CHK((ret = rs->nextResult(true)) == 0 || ret == 1);
+ CHK((ret = g_ops->nextResult(true)) == 0 || ret == 1);
if (ret == 1)
break;
DBG("readScan" << (idx ? "Idx" : "") << " pk1=" << hex << tup.m_pk1);
@@ -1159,14 +1157,13 @@ updateScan(int style, bool idx)
DBG("--- " << "updateScan" << (idx ? "Idx" : "") << " " << stylename[style] << " ---");
Tup tup;
tup.alloc(); // allocate buffers
- NdbResultSet* rs;
CHK((g_con = g_ndb->startTransaction()) != 0);
if (! idx) {
CHK((g_ops = g_con->getNdbScanOperation(g_opt.m_tname)) != 0);
} else {
CHK((g_ops = g_con->getNdbIndexScanOperation(g_opt.m_x2name, g_opt.m_tname)) != 0);
}
- CHK((rs = g_ops->readTuples(NdbScanOperation::LM_Exclusive)) != 0);
+ CHK(g_ops->readTuples(NdbScanOperation::LM_Exclusive) == 0);
CHK(g_ops->getValue("PK1", (char*)&tup.m_pk1) != 0);
if (g_opt.m_pk2len != 0)
CHK(g_ops->getValue("PK2", tup.m_pk2) != 0);
@@ -1176,7 +1173,7 @@ updateScan(int style, bool idx)
int ret;
tup.m_pk1 = (Uint32)-1;
memset(tup.m_pk2, 'x', g_opt.m_pk2len);
- CHK((ret = rs->nextResult(true)) == 0 || ret == 1);
+ CHK((ret = g_ops->nextResult(true)) == 0 || ret == 1);
if (ret == 1)
break;
DBG("updateScan" << (idx ? "Idx" : "") << " pk1=" << hex << tup.m_pk1);
@@ -1185,7 +1182,7 @@ updateScan(int style, bool idx)
// calculate new blob values
calcBval(g_tups[k], false);
tup.copyfrom(g_tups[k]);
- CHK((g_opr = rs->updateTuple()) != 0);
+ CHK((g_opr = g_ops->updateCurrentTuple()) != 0);
CHK(getBlobHandles(g_opr) == 0);
if (style == 0) {
CHK(setBlobValue(tup) == 0);
@@ -1212,14 +1209,13 @@ deleteScan(bool idx)
{
DBG("--- " << "deleteScan" << (idx ? "Idx" : "") << " ---");
Tup tup;
- NdbResultSet* rs;
CHK((g_con = g_ndb->startTransaction()) != 0);
if (! idx) {
CHK((g_ops = g_con->getNdbScanOperation(g_opt.m_tname)) != 0);
} else {
CHK((g_ops = g_con->getNdbIndexScanOperation(g_opt.m_x2name, g_opt.m_tname)) != 0);
}
- CHK((rs = g_ops->readTuples(NdbScanOperation::LM_Exclusive)) != 0);
+ CHK(g_ops->readTuples(NdbScanOperation::LM_Exclusive) == 0);
CHK(g_ops->getValue("PK1", (char*)&tup.m_pk1) != 0);
if (g_opt.m_pk2len != 0)
CHK(g_ops->getValue("PK2", tup.m_pk2) != 0);
@@ -1229,11 +1225,11 @@ deleteScan(bool idx)
int ret;
tup.m_pk1 = (Uint32)-1;
memset(tup.m_pk2, 'x', g_opt.m_pk2len);
- CHK((ret = rs->nextResult()) == 0 || ret == 1);
+ CHK((ret = g_ops->nextResult()) == 0 || ret == 1);
if (ret == 1)
break;
DBG("deleteScan" << (idx ? "Idx" : "") << " pk1=" << hex << tup.m_pk1);
- CHK(rs->deleteTuple() == 0);
+ CHK(g_ops->deleteCurrentTuple() == 0);
CHK(g_con->execute(NoCommit) == 0);
Uint32 k = tup.m_pk1 - g_opt.m_pk1off;
CHK(k < g_opt.m_rows && g_tups[k].m_exists);
@@ -1610,12 +1606,11 @@ testperf()
// scan read char
{
DBG("--- scan read char ---");
- NdbResultSet* rs;
Uint32 a;
char b[20];
CHK((g_con = g_ndb->startTransaction()) != 0);
CHK((g_ops = g_con->getNdbScanOperation(tab.getName())) != 0);
- CHK((rs = g_ops->readTuples(NdbScanOperation::LM_Read)) != 0);
+ CHK(g_ops->readTuples(NdbScanOperation::LM_Read) == 0);
CHK(g_ops->getValue(cA, (char*)&a) != 0);
CHK(g_ops->getValue(cB, b) != 0);
CHK(g_con->execute(NoCommit) == 0);
@@ -1625,7 +1620,7 @@ testperf()
a = (Uint32)-1;
b[0] = 0;
int ret;
- CHK((ret = rs->nextResult(true)) == 0 || ret == 1);
+ CHK((ret = g_ops->nextResult(true)) == 0 || ret == 1);
if (ret == 1)
break;
CHK(a < g_opt.m_rowsperf && strcmp(b, "b") == 0);
@@ -1640,12 +1635,11 @@ testperf()
// scan read text
{
DBG("--- read text ---");
- NdbResultSet* rs;
Uint32 a;
char c[20];
CHK((g_con = g_ndb->startTransaction()) != 0);
CHK((g_ops = g_con->getNdbScanOperation(tab.getName())) != 0);
- CHK((rs = g_ops->readTuples(NdbScanOperation::LM_Read)) != 0);
+ CHK(g_ops->readTuples(NdbScanOperation::LM_Read) == 0);
CHK(g_ops->getValue(cA, (char*)&a) != 0);
CHK((g_bh1 = g_ops->getBlobHandle(cC)) != 0);
CHK(g_con->execute(NoCommit) == 0);
@@ -1655,7 +1649,7 @@ testperf()
a = (Uint32)-1;
c[0] = 0;
int ret;
- CHK((ret = rs->nextResult(true)) == 0 || ret == 1);
+ CHK((ret = g_ops->nextResult(true)) == 0 || ret == 1);
if (ret == 1)
break;
Uint32 m = 20;
diff --git a/ndb/test/ndbapi/testDataBuffers.cpp b/ndb/test/ndbapi/testDataBuffers.cpp
index 03d52252334..aaecb6ee61e 100644
--- a/ndb/test/ndbapi/testDataBuffers.cpp
+++ b/ndb/test/ndbapi/testDataBuffers.cpp
@@ -209,7 +209,7 @@ makeOff(int k)
}
static int
-testcase(int flag)
+testcase(Ndb_cluster_connection&cc, int flag)
{
ndbout << "--- case " << flag << " ---" << endl;
sprintf(tab, "TB%02d", flag);
@@ -254,7 +254,7 @@ testcase(int flag)
ndbout << "tab=" << tab << " cols=" << attrcnt
<< " size max=" << smax << " tot=" << stot << endl;
- ndb = new Ndb("TEST_DB");
+ ndb = new Ndb(&cc, "TEST_DB");
if (ndb->init() != 0)
return ndberror("init");
if (ndb->waitUntilReady(30) < 0)
@@ -443,9 +443,9 @@ testcase(int flag)
if ((con = ndb->startTransaction()) == 0)
return ndberror("startTransaction key=%d", key);
if ((op = sop = con->getNdbScanOperation(tab)) == 0)
- return ndberror("getNdbOperation key=%d", key);
- if ((rs = sop->readTuples(1)) == 0)
- return ndberror("openScanRead key=%d", key);
+ return ndberror("getNdbOperation key=%d", key);
+ if (sop->readTuples(1))
+ return ndberror("openScanRead key=%d", key);
{
col& c = ccol[0];
if (op->load_const_u32(1, key) < 0)
@@ -488,7 +488,7 @@ testcase(int flag)
if (con->execute(NoCommit) < 0)
return ndberror("executeScan key=%d", key);
int ret, cnt = 0;
- while ((ret = rs->nextResult()) == 0) {
+ while ((ret = sop->nextResult()) == 0) {
if (key != newkey)
return ndberror("unexpected key=%d newkey=%d", key, newkey);
for (i = 1; i < attrcnt; i++) {
@@ -606,10 +606,17 @@ NDB_COMMAND(testDataBuffers, "testDataBuffers", "testDataBuffers", "testDataBuff
}
}
unsigned ok = true;
+
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1))
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
for (i = 1; 0 == loopcnt || i <= loopcnt; i++) {
ndbout << "=== loop " << i << " ===" << endl;
for (int flag = 0; flag < (1<<testbits); flag++) {
- if (testcase(flag) < 0) {
+ if (testcase(con, flag) < 0) {
ok = false;
if (! kontinue)
goto out;
diff --git a/ndb/test/ndbapi/testDeadlock.cpp b/ndb/test/ndbapi/testDeadlock.cpp
index eb985e815ac..0070a7ecc83 100644
--- a/ndb/test/ndbapi/testDeadlock.cpp
+++ b/ndb/test/ndbapi/testDeadlock.cpp
@@ -49,7 +49,7 @@ printusage()
static Opt g_opt;
static NdbMutex *ndbout_mutex= NULL;
-
+static Ndb_cluster_connection *g_cluster_connection= 0;
#define DBG(x) \
do { \
if (! g_opt.m_dbg) break; \
@@ -91,7 +91,6 @@ struct Thr {
NdbConnection* m_con;
NdbScanOperation* m_scanop;
NdbIndexScanOperation* m_indexscanop;
- NdbResultSet* m_rs;
//
Thr(int no);
~Thr();
@@ -136,7 +135,6 @@ Thr::Thr(int no)
m_con = 0;
m_scanop = 0;
m_indexscanop = 0;
- m_rs = 0;
}
Thr::~Thr()
@@ -219,7 +217,7 @@ Thr::exit()
static int
runstep_connect(Thr& thr)
{
- Ndb* ndb = thr.m_ndb = new Ndb("TEST_DB");
+ Ndb* ndb = thr.m_ndb = new Ndb(g_cluster_connection, "TEST_DB");
CHN(ndb, ndb->init() == 0);
CHN(ndb, ndb->waitUntilReady() == 0);
DBG(thr << " connected");
@@ -374,7 +372,7 @@ wl1822_tx2_scanXY(Thr& thr)
CHN(con, (scanop = thr.m_scanop = indexscanop = thr.m_indexscanop = con->getNdbIndexScanOperation(g_opt.m_xname, g_opt.m_tname)) != 0);
DBG("tx2 scan exclusive " << g_opt.m_xname);
}
- CHN(scanop, (rs = thr.m_rs = scanop->readTuplesExclusive(16)) != 0);
+ CHN(scanop, scanop->readTuplesExclusive(16) == 0);
CHN(scanop, scanop->getValue("A", (char*)&wl1822_bufA) != 0);
CHN(scanop, scanop->getValue("B", (char*)&wl1822_bufB) != 0);
CHN(con, con->execute(NoCommit) == 0);
@@ -383,7 +381,7 @@ wl1822_tx2_scanXY(Thr& thr)
DBG("before row " << row);
int ret;
wl1822_bufA = wl1822_bufB = ~0;
- CHN(con, (ret = rs->nextResult(true)) == 0);
+ CHN(con, (ret = scanop->nextResult(true)) == 0);
DBG("got row " << row << " a=" << wl1822_bufA << " b=" << wl1822_bufB);
CHK(wl1822_bufA == wl1822_valA[wl1822_r2k[row]]);
CHK(wl1822_bufB == wl1822_valB[wl1822_r2k[row]]);
@@ -419,14 +417,13 @@ wl1822_tx2_scanZ_close(Thr& thr)
Ndb* ndb = thr.m_ndb;
NdbConnection* con = thr.m_con;
NdbScanOperation* scanop = thr.m_scanop;
- NdbResultSet* rs = thr.m_rs;
- assert(ndb != 0 && con != 0 && scanop != 0 && rs != 0);
+ assert(ndb != 0 && con != 0 && scanop != 0);
unsigned row = 2;
while (true) {
DBG("before row " << row);
int ret;
wl1822_bufA = wl1822_bufB = ~0;
- CHN(con, (ret = rs->nextResult(true)) == 0 || ret == 1);
+ CHN(con, (ret = scanop->nextResult(true)) == 0 || ret == 1);
if (ret == 1)
break;
DBG("got row " << row << " a=" << wl1822_bufA << " b=" << wl1822_bufB);
@@ -467,7 +464,7 @@ wl1822_main(char scantx)
// run the steps
for (unsigned i = 0; i < wl1822_stepcount; i++) {
DBG("step " << i << " start");
- for (int n = 0; n < thrcount; n++) {
+ for (n = 0; n < thrcount; n++) {
Thr& thr = *thrlist[n];
Runstep runstep = wl1822_step[i][n];
if (runstep != 0)
@@ -506,10 +503,18 @@ NDB_COMMAND(testOdbcDriver, "testDeadlock", "testDeadlock", "testDeadlock", 6553
printusage();
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
+
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ g_cluster_connection= &con;
+
if (
strchr(g_opt.m_scan, 't') != 0 && wl1822_main('t') == -1 ||
strchr(g_opt.m_scan, 'x') != 0 && wl1822_main('x') == -1
- ) {
+ ) {
return NDBT_ProgramExit(NDBT_FAILED);
}
return NDBT_ProgramExit(NDBT_OK);
diff --git a/ndb/test/ndbapi/testDict.cpp b/ndb/test/ndbapi/testDict.cpp
index 5f88342705a..5240735dcc6 100644
--- a/ndb/test/ndbapi/testDict.cpp
+++ b/ndb/test/ndbapi/testDict.cpp
@@ -125,6 +125,16 @@ int runCreateTheTable(NDBT_Context* ctx, NDBT_Step* step){
return NDBT_OK;
}
+int runDropTheTable(NDBT_Context* ctx, NDBT_Step* step){
+ Ndb* pNdb = GETNDB(step);
+ const NdbDictionary::Table* pTab = ctx->getTab();
+
+ // Try to create table in db
+ pNdb->getDictionary()->dropTable(pTab->getName());
+
+ return NDBT_OK;
+}
+
int runCreateTableWhenDbIsFull(NDBT_Context* ctx, NDBT_Step* step){
Ndb* pNdb = GETNDB(step);
int result = NDBT_OK;
@@ -524,13 +534,6 @@ int runTestFragmentTypes(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
NdbRestarter restarter;
- // enum FragmentType {
- // Unknown = 0,
- // Single = 1, ///< Only one fragment
- // All = 2, ///< Default value. One fragment per node group
- // AllLarge = 3 ///< Sixten fragments per node group.
- // };
-
if (pNdb->waitUntilReady(30) != 0){
// Db is not ready, return with failure
return NDBT_FAILED;
@@ -547,6 +550,7 @@ int runTestFragmentTypes(NDBT_Context* ctx, NDBT_Step* step){
if (newTab.createTableInDb(pNdb) != 0){
ndbout << newTab.getName() << " could not be created"
<< ", fragmentType = "<<fragTtype <<endl;
+ ndbout << pNdb->getDictionary()->getNdbError() << endl;
return NDBT_FAILED;
}
@@ -564,13 +568,17 @@ int runTestFragmentTypes(NDBT_Context* ctx, NDBT_Step* step){
result = NDBT_FAILED;
goto drop_the_tab;
}
-
+/**
+ This test does not work since fragmentation is
+ decided by the kernel, hence the fragementation
+ attribute on the column will differ
+
if (newTab.equal(*pTab3) == false){
ndbout << "It was not equal" << endl;
result = NDBT_FAILED;
goto drop_the_tab;
}
-
+*/
do {
HugoTransactions hugoTrans(*pTab3);
@@ -1583,21 +1591,26 @@ TESTCASE("CreateTableWhenDbIsFull",
INITIALIZER(runFillTable);
INITIALIZER(runCreateTableWhenDbIsFull);
INITIALIZER(runDropTableWhenDbIsFull);
- FINALIZER(runClearTable);
+ FINALIZER(runDropTheTable);
}
TESTCASE("FragmentTypeSingle",
"Create the table with fragment type Single\n"){
- TC_PROPERTY("FragmentType", 1);
+ TC_PROPERTY("FragmentType", NdbDictionary::Table::FragSingle);
+ INITIALIZER(runTestFragmentTypes);
+}
+TESTCASE("FragmentTypeAllSmall",
+ "Create the table with fragment type AllSmall\n"){
+ TC_PROPERTY("FragmentType", NdbDictionary::Table::FragAllSmall);
INITIALIZER(runTestFragmentTypes);
}
-TESTCASE("FragmentTypeAll",
- "Create the table with fragment type All\n"){
- TC_PROPERTY("FragmentType", 2);
+TESTCASE("FragmentTypeAllMedium",
+ "Create the table with fragment type AllMedium\n"){
+ TC_PROPERTY("FragmentType", NdbDictionary::Table::FragAllMedium);
INITIALIZER(runTestFragmentTypes);
}
TESTCASE("FragmentTypeAllLarge",
"Create the table with fragment type AllLarge\n"){
- TC_PROPERTY("FragmentType", 3);
+ TC_PROPERTY("FragmentType", NdbDictionary::Table::FragAllLarge);
INITIALIZER(runTestFragmentTypes);
}
TESTCASE("TemporaryTables",
diff --git a/ndb/test/ndbapi/testIndex.cpp b/ndb/test/ndbapi/testIndex.cpp
index d359f83257f..5785db232c4 100644
--- a/ndb/test/ndbapi/testIndex.cpp
+++ b/ndb/test/ndbapi/testIndex.cpp
@@ -1145,20 +1145,18 @@ runUniqueNullTransactions(NDBT_Context* ctx, NDBT_Step* step){
pTrans = pNdb->startTransaction();
NdbScanOperation * sOp;
NdbOperation * uOp;
- NdbResultSet * rs;
int eof;
if(!pTrans) goto done;
sOp = pTrans->getNdbScanOperation(pTab->getName());
if(!sOp) goto done;
- rs = sOp->readTuples(NdbScanOperation::LM_Exclusive);
- if(!rs) goto done;
+ if(sOp->readTuples(NdbScanOperation::LM_Exclusive)) goto done;
if(pTrans->execute(NoCommit) == -1) goto done;
- while((eof = rs->nextResult(true)) == 0){
+ while((eof = sOp->nextResult(true)) == 0){
do {
- NdbOperation * uOp = rs->updateTuple();
+ NdbOperation * uOp = sOp->updateCurrentTuple();
if(uOp == 0) goto done;
uOp->setValue(colId, 0);
- } while((eof = rs->nextResult(false)) == 0);
+ } while((eof = sOp->nextResult(false)) == 0);
eof = pTrans->execute(Commit);
if(eof == -1) goto done;
}
@@ -1279,7 +1277,7 @@ TESTCASE("CreateLoadDrop_O",
TESTCASE("NFNR1",
"Test that indexes are correctly maintained during node fail and node restart"){
TC_PROPERTY("LoggedIndexes", (unsigned)0);
- //TC_PROPERTY("Threads", 2);
+ TC_PROPERTY("PauseThreads", 2);
INITIALIZER(runClearTable);
INITIALIZER(createRandomIndex);
INITIALIZER(runLoadTable);
@@ -1294,6 +1292,7 @@ TESTCASE("NFNR1_O",
"Test that indexes are correctly maintained during node fail and node restart"){
TC_PROPERTY("OrderedIndex", 1);
TC_PROPERTY("LoggedIndexes", (unsigned)0);
+ TC_PROPERTY("PauseThreads", 2);
INITIALIZER(runClearTable);
INITIALIZER(createRandomIndex);
INITIALIZER(runLoadTable);
@@ -1307,6 +1306,7 @@ TESTCASE("NFNR1_O",
TESTCASE("NFNR2",
"Test that indexes are correctly maintained during node fail and node restart"){
TC_PROPERTY("LoggedIndexes", (unsigned)0);
+ TC_PROPERTY("PauseThreads", 2);
INITIALIZER(runClearTable);
INITIALIZER(createRandomIndex);
INITIALIZER(createPkIndex);
@@ -1323,6 +1323,7 @@ TESTCASE("NFNR2_O",
"Test that indexes are correctly maintained during node fail and node restart"){
TC_PROPERTY("OrderedIndex", 1);
TC_PROPERTY("LoggedIndexes", (unsigned)0);
+ TC_PROPERTY("PauseThreads", 1);
INITIALIZER(runClearTable);
INITIALIZER(createRandomIndex);
INITIALIZER(createPkIndex);
@@ -1338,6 +1339,7 @@ TESTCASE("NFNR2_O",
TESTCASE("NFNR3",
"Test that indexes are correctly maintained during node fail and node restart"){
TC_PROPERTY("LoggedIndexes", (unsigned)0);
+ TC_PROPERTY("PauseThreads", 2);
INITIALIZER(runClearTable);
INITIALIZER(createRandomIndex);
INITIALIZER(createPkIndex);
@@ -1353,6 +1355,7 @@ TESTCASE("NFNR3_O",
"Test that indexes are correctly maintained during node fail and node restart"){
TC_PROPERTY("OrderedIndex", 1);
TC_PROPERTY("LoggedIndexes", (unsigned)0);
+ TC_PROPERTY("PauseThreads", 2);
INITIALIZER(runClearTable);
INITIALIZER(createRandomIndex);
INITIALIZER(createPkIndex);
@@ -1367,6 +1370,7 @@ TESTCASE("NFNR3_O",
TESTCASE("NFNR4",
"Test that indexes are correctly maintained during node fail and node restart"){
TC_PROPERTY("LoggedIndexes", (unsigned)0);
+ TC_PROPERTY("PauseThreads", 4);
INITIALIZER(runClearTable);
INITIALIZER(createRandomIndex);
INITIALIZER(createPkIndex);
@@ -1385,6 +1389,7 @@ TESTCASE("NFNR4_O",
"Test that indexes are correctly maintained during node fail and node restart"){
TC_PROPERTY("OrderedIndex", 1);
TC_PROPERTY("LoggedIndexes", (unsigned)0);
+ TC_PROPERTY("PauseThreads", 4);
INITIALIZER(runClearTable);
INITIALIZER(createRandomIndex);
INITIALIZER(createPkIndex);
diff --git a/ndb/test/ndbapi/testLcp.cpp b/ndb/test/ndbapi/testLcp.cpp
index d11692db761..8bfc7ccf9b9 100644
--- a/ndb/test/ndbapi/testLcp.cpp
+++ b/ndb/test/ndbapi/testLcp.cpp
@@ -30,6 +30,7 @@ static CASE g_ops[] =
const size_t OP_COUNT = (sizeof(g_ops)/sizeof(g_ops[0]));
static Ndb* g_ndb = 0;
+static Ndb_cluster_connection *g_cluster_connection= 0;
static CASE* g_cases;
static HugoOperations* g_hugo_ops;
@@ -122,6 +123,7 @@ main(int argc, char ** argv){
static int init_ndb(int argc, char** argv)
{
+ ndb_init();
return 0;
}
@@ -132,7 +134,13 @@ static int parse_args(int argc, char** argv)
static int connect_ndb()
{
- g_ndb = new Ndb("TEST_DB");
+ g_cluster_connection = new Ndb_cluster_connection();
+ if(g_cluster_connection->connect(12, 5, 1) != 0)
+ {
+ return 1;
+ }
+
+ g_ndb = new Ndb(g_cluster_connection, "TEST_DB");
g_ndb->init();
if(g_ndb->waitUntilReady(30) == 0){
int args[] = { DumpStateOrd::DihMaxTimeBetweenLCP };
@@ -144,8 +152,10 @@ static int connect_ndb()
static int disconnect_ndb()
{
delete g_ndb;
+ delete g_cluster_connection;
g_ndb = 0;
g_table = 0;
+ g_cluster_connection= 0;
return 0;
}
diff --git a/ndb/test/ndbapi/testNdbApi.cpp b/ndb/test/ndbapi/testNdbApi.cpp
index 69e534e6860..4867ea11a9a 100644
--- a/ndb/test/ndbapi/testNdbApi.cpp
+++ b/ndb/test/ndbapi/testNdbApi.cpp
@@ -56,7 +56,7 @@ int runTestMaxNdb(NDBT_Context* ctx, NDBT_Step* step){
int init = 0;
do {
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
errors++;
@@ -108,7 +108,7 @@ int runTestMaxTransaction(NDBT_Context* ctx, NDBT_Step* step){
int oldi = 0;
int result = NDBT_OK;
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
@@ -119,6 +119,9 @@ int runTestMaxTransaction(NDBT_Context* ctx, NDBT_Step* step){
return NDBT_FAILED;
}
+ const NdbDictionary::Table* pTab = ctx->getTab();
+ if (pTab == 0) abort();
+
while (l < loops && result == NDBT_OK){
int errors = 0;
int maxErrors = 5;
@@ -131,39 +134,25 @@ int runTestMaxTransaction(NDBT_Context* ctx, NDBT_Step* step){
NdbConnection* pCon;
- int type = i%4;
+ int type = i%2;
switch (type){
case 0:
pCon = pNdb->startTransaction();
break;
case 1:
- pCon = pNdb->startTransaction(2,
- "DATA",
- 4);
- break;
- case 2:
- ndbout_c("startTransactionDGroup not supported");
- abort();
- /*
- pCon = pNdb->startTransactionDGroup(1,
- "TEST",
- 0);
- */
- break;
- case 3:
- ndbout_c("startTransactionDGroup not supported");
- abort();
- /*
- pCon = pNdb->startTransactionDGroup(2,
- "TEST",
- 1);
- */
- break;
-
+ {
+ BaseString key;
+ key.appfmt("DATA-%d", i);
+ ndbout_c("%s", key.c_str());
+ pCon = pNdb->startTransaction(pTab,
+ key.c_str(),
+ key.length());
+ }
+ break;
default:
abort();
}
-
+
if (pCon == NULL){
ERR(pNdb->getNdbError());
errors++;
@@ -209,7 +198,7 @@ int runTestMaxOperations(NDBT_Context* ctx, NDBT_Step* step){
int maxOpsLimit = 1;
const NdbDictionary::Table* pTab = ctx->getTab();
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
@@ -281,7 +270,7 @@ int runTestGetValue(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
const NdbDictionary::Table* pTab = ctx->getTab();
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
@@ -381,7 +370,7 @@ int runTestEqual(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
const NdbDictionary::Table* pTab = ctx->getTab();
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
@@ -502,7 +491,7 @@ int runTestDeleteNdb(NDBT_Context* ctx, NDBT_Step* step){
// Create 5 ndb objects
for( int i = 0; i < 5; i++){
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
result = NDBT_FAILED;
@@ -583,7 +572,7 @@ int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
int runTestWaitUntilReady(NDBT_Context* ctx, NDBT_Step* step){
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
// Forget about calling pNdb->init();
@@ -604,7 +593,7 @@ int runTestWaitUntilReady(NDBT_Context* ctx, NDBT_Step* step){
int runGetNdbOperationNoTab(NDBT_Context* ctx, NDBT_Step* step){
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
@@ -645,7 +634,7 @@ int runMissingOperation(NDBT_Context* ctx, NDBT_Step* step){
const NdbDictionary::Table* pTab = ctx->getTab();
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
@@ -695,7 +684,7 @@ int runMissingOperation(NDBT_Context* ctx, NDBT_Step* step){
int runGetValueInUpdate(NDBT_Context* ctx, NDBT_Step* step){
const NdbDictionary::Table* pTab = ctx->getTab();
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
@@ -761,7 +750,7 @@ int runUpdateWithoutValues(NDBT_Context* ctx, NDBT_Step* step){
HugoOperations hugoOps(*pTab);
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
@@ -807,13 +796,13 @@ int runUpdateWithoutValues(NDBT_Context* ctx, NDBT_Step* step){
// Dont' call any setValues
- // Execute should not work
+ // Execute should work
int check = pCon->execute(Commit);
if (check == 0){
ndbout << "execute worked" << endl;
- result = NDBT_FAILED;
} else {
ERR(pCon->getNdbError());
+ result = NDBT_FAILED;
}
pNdb->closeTransaction(pCon);
@@ -827,7 +816,7 @@ int runUpdateWithoutKeys(NDBT_Context* ctx, NDBT_Step* step){
const NdbDictionary::Table* pTab = ctx->getTab();
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
@@ -881,7 +870,7 @@ int runCheckGetNdbErrorOperation(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
const NdbDictionary::Table* pTab = ctx->getTab();
- Ndb* pNdb = new Ndb("TEST_DB");
+ Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
if (pNdb == NULL){
ndbout << "pNdb == NULL" << endl;
return NDBT_FAILED;
diff --git a/ndb/test/ndbapi/testNodeRestart.cpp b/ndb/test/ndbapi/testNodeRestart.cpp
index a50df91908c..1ce934a19ca 100644
--- a/ndb/test/ndbapi/testNodeRestart.cpp
+++ b/ndb/test/ndbapi/testNodeRestart.cpp
@@ -311,7 +311,7 @@ int runDirtyRead(NDBT_Context* ctx, NDBT_Step* step){
int id = i % restarter.getNumDbNodes();
int nodeId = restarter.getDbNodeId(id);
ndbout << "Restart node " << nodeId << endl;
- restarter.insertErrorInAllNodes(5041);
+ restarter.insertErrorInNode(nodeId, 5041);
restarter.insertErrorInAllNodes(8048 + (i & 1));
for(int j = 0; j<records; j++){
diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp
index 9f8da850ff4..c7c9f417d1a 100644
--- a/ndb/test/ndbapi/testOIBasic.cpp
+++ b/ndb/test/ndbapi/testOIBasic.cpp
@@ -28,7 +28,9 @@
#include <NdbCondition.h>
#include <NdbThread.h>
#include <NdbTick.h>
+#include <NdbSleep.h>
#include <my_sys.h>
+#include <NdbSqlUtil.hpp>
// options
@@ -37,6 +39,7 @@ struct Opt {
unsigned m_batch;
const char* m_bound;
const char* m_case;
+ bool m_collsp;
bool m_core;
const char* m_csname;
CHARSET_INFO* m_cs;
@@ -55,17 +58,18 @@ struct Opt {
unsigned m_scanbat;
unsigned m_scanpar;
unsigned m_scanstop;
- unsigned m_seed;
+ int m_seed;
unsigned m_subloop;
const char* m_table;
unsigned m_threads;
- int m_v;
+ int m_v; // int for lint
Opt() :
m_batch(32),
m_bound("01234"),
m_case(0),
+ m_collsp(false),
m_core(false),
- m_csname("latin1_bin"),
+ m_csname("random"),
m_cs(0),
m_die(0),
m_dups(false),
@@ -82,10 +86,10 @@ struct Opt {
m_scanbat(0),
m_scanpar(0),
m_scanstop(0),
- m_seed(0),
+ m_seed(-1),
m_subloop(4),
m_table(0),
- m_threads(10),
+ m_threads(4),
m_v(1) {
}
};
@@ -104,12 +108,13 @@ printhelp()
<< " -batch N pk operations in batch [" << d.m_batch << "]" << endl
<< " -bound xyz use only these bound types 0-4 [" << d.m_bound << "]" << endl
<< " -case abc only given test cases (letters a-z)" << endl
+ << " -collsp use strnncollsp instead of strnxfrm" << endl
<< " -core core dump on error [" << d.m_core << "]" << endl
- << " -csname S charset (collation) of non-pk char column [" << d.m_csname << "]" << endl
+ << " -csname S charset or collation [" << d.m_csname << "]" << endl
<< " -die nnn exit immediately on NDB error code nnn" << endl
<< " -dups allow duplicate tuples from index scan [" << d.m_dups << "]" << endl
<< " -fragtype T fragment type single/small/medium/large" << endl
- << " -index xyz only given index numbers (digits 1-9)" << endl
+ << " -index xyz only given index numbers (digits 0-9)" << endl
<< " -loop N loop count full suite 0=forever [" << d.m_loop << "]" << endl
<< " -nologging create tables in no-logging mode" << endl
<< " -noverify skip index verifications" << endl
@@ -118,9 +123,9 @@ printhelp()
<< " -samples N samples for some timings (0=all) [" << d.m_samples << "]" << endl
<< " -scanbat N scan batch per fragment (ignored by ndb api) [" << d.m_scanbat << "]" << endl
<< " -scanpar N scan parallelism [" << d.m_scanpar << "]" << endl
- << " -seed N srandom seed 0=loop number[" << d.m_seed << "]" << endl
+ << " -seed N srandom seed 0=loop number -1=random [" << d.m_seed << "]" << endl
<< " -subloop N subtest loop count [" << d.m_subloop << "]" << endl
- << " -table xyz only given table numbers (digits 1-9)" << endl
+ << " -table xyz only given table numbers (digits 0-9)" << endl
<< " -threads N number of threads [" << d.m_threads << "]" << endl
<< " -vN verbosity [" << d.m_v << "]" << endl
<< " -h or -help print this help text" << endl
@@ -135,9 +140,43 @@ static const bool g_store_null_key = true;
// compare NULL like normal value (NULL < not NULL, NULL == NULL)
static const bool g_compare_null = true;
+static const char* hexstr = "0123456789abcdef";
+
+// random ints
+
+static unsigned
+urandom(unsigned n)
+{
+ if (n == 0)
+ return 0;
+ unsigned i = random() % n;
+ return i;
+}
+
+static int
+irandom(unsigned n)
+{
+ if (n == 0)
+ return 0;
+ int i = random() % n;
+ if (random() & 0x1)
+ i = -i;
+ return i;
+}
+
+static bool
+randompct(unsigned pct)
+{
+ if (pct == 0)
+ return false;
+ if (pct >= 100)
+ return true;
+ return urandom(100) < pct;
+}
+
// log and error macros
-static NdbMutex *ndbout_mutex= NULL;
+static NdbMutex *ndbout_mutex = NULL;
static unsigned getthrno();
@@ -198,7 +237,7 @@ getthrstr()
return -1; \
} while (0)
-// method parameters base class
+// method parameters
class Thr;
class Con;
@@ -222,6 +261,8 @@ struct Par : public Opt {
// value calculation
unsigned m_range;
unsigned m_pctrange;
+ unsigned m_pctbrange;
+ int m_bdir;
// choice of key
bool m_randomkey;
// do verify after read
@@ -230,6 +271,10 @@ struct Par : public Opt {
bool m_deadlock;
// abort percentabge
unsigned m_abortpct;
+ NdbOperation::LockMode m_lockmode;
+ // ordered range scan
+ bool m_ordered;
+ bool m_descending;
// timer location
Par(const Opt& opt) :
Opt(opt),
@@ -242,24 +287,29 @@ struct Par : public Opt {
m_slno(0),
m_totrows(m_threads * m_rows),
m_range(m_rows),
- m_pctrange(0),
+ m_pctrange(40),
+ m_pctbrange(80),
+ m_bdir(0),
m_randomkey(false),
m_verify(false),
m_deadlock(false),
- m_abortpct(0) {
+ m_abortpct(0),
+ m_lockmode(NdbOperation::LM_Read),
+ m_ordered(false),
+ m_descending(false) {
}
};
static bool
-usetable(unsigned i)
+usetable(Par par, unsigned i)
{
- return g_opt.m_table == 0 || strchr(g_opt.m_table, '1' + i) != 0;
+ return par.m_table == 0 || strchr(par.m_table, '0' + i) != 0;
}
static bool
-useindex(unsigned i)
+useindex(Par par, unsigned i)
{
- return g_opt.m_index == 0 || strchr(g_opt.m_index, '1' + i) != 0;
+ return par.m_index == 0 || strchr(par.m_index, '0' + i) != 0;
}
static unsigned
@@ -385,38 +435,285 @@ Lst::reset()
m_cnt = 0;
}
+// character sets
+
+static const unsigned maxcsnumber = 512;
+static const unsigned maxcharcount = 32;
+static const unsigned maxcharsize = 4;
+static const unsigned maxxmulsize = 8;
+
+// single mb char
+struct Chr {
+ unsigned char m_bytes[maxcharsize];
+ unsigned char m_xbytes[maxxmulsize * maxcharsize];
+ unsigned m_size;
+ Chr();
+};
+
+Chr::Chr()
+{
+ memset(m_bytes, 0, sizeof(m_bytes));
+ memset(m_xbytes, 0, sizeof(m_xbytes));
+ m_size = 0;
+}
+
+// charset and random valid chars to use
+struct Chs {
+ CHARSET_INFO* m_cs;
+ unsigned m_xmul;
+ Chr* m_chr;
+ Chs(CHARSET_INFO* cs);
+ ~Chs();
+};
+
+static NdbOut&
+operator<<(NdbOut& out, const Chs& chs);
+
+Chs::Chs(CHARSET_INFO* cs) :
+ m_cs(cs)
+{
+ m_xmul = m_cs->strxfrm_multiply;
+ if (m_xmul == 0)
+ m_xmul = 1;
+ assert(m_xmul <= maxxmulsize);
+ m_chr = new Chr [maxcharcount];
+ unsigned i = 0;
+ unsigned miss1 = 0;
+ unsigned miss2 = 0;
+ unsigned miss3 = 0;
+ unsigned miss4 = 0;
+ while (i < maxcharcount) {
+ unsigned char* bytes = m_chr[i].m_bytes;
+ unsigned char* xbytes = m_chr[i].m_xbytes;
+ unsigned& size = m_chr[i].m_size;
+ bool ok;
+ size = m_cs->mbminlen + urandom(m_cs->mbmaxlen - m_cs->mbminlen + 1);
+ assert(m_cs->mbminlen <= size && size <= m_cs->mbmaxlen);
+ // prefer longer chars
+ if (size == m_cs->mbminlen && m_cs->mbminlen < m_cs->mbmaxlen && urandom(5) != 0)
+ continue;
+ for (unsigned j = 0; j < size; j++) {
+ bytes[j] = urandom(256);
+ }
+ int not_used;
+ // check wellformed
+ const char* sbytes = (const char*)bytes;
+ if ((*cs->cset->well_formed_len)(cs, sbytes, sbytes + size, 1, &not_used) != size) {
+ miss1++;
+ continue;
+ }
+ // check no proper prefix wellformed
+ ok = true;
+ for (unsigned j = 1; j < size; j++) {
+ if ((*cs->cset->well_formed_len)(cs, sbytes, sbytes + j, 1, &not_used) == j) {
+ ok = false;
+ break;
+ }
+ }
+ if (! ok) {
+ miss2++;
+ continue;
+ }
+ // normalize
+ memset(xbytes, 0, sizeof(xbytes));
+ // currently returns buffer size always
+ int xlen = (*cs->coll->strnxfrm)(cs, xbytes, m_xmul * size, bytes, size);
+ // check we got something
+ ok = false;
+ for (unsigned j = 0; j < xlen; j++) {
+ if (xbytes[j] != 0) {
+ ok = true;
+ break;
+ }
+ }
+ if (! ok) {
+ miss3++;
+ continue;
+ }
+ // check for duplicate (before normalize)
+ ok = true;
+ for (unsigned j = 0; j < i; j++) {
+ const Chr& chr = m_chr[j];
+ if (chr.m_size == size && memcmp(chr.m_bytes, bytes, size) == 0) {
+ ok = false;
+ break;
+ }
+ }
+ if (! ok) {
+ miss4++;
+ continue;
+ }
+ i++;
+ }
+ bool disorder = true;
+ unsigned bubbles = 0;
+ while (disorder) {
+ disorder = false;
+ for (unsigned i = 1; i < maxcharcount; i++) {
+ unsigned len = sizeof(m_chr[i].m_xbytes);
+ if (memcmp(m_chr[i-1].m_xbytes, m_chr[i].m_xbytes, len) > 0) {
+ Chr chr = m_chr[i];
+ m_chr[i] = m_chr[i-1];
+ m_chr[i-1] = chr;
+ disorder = true;
+ bubbles++;
+ }
+ }
+ }
+ LL3("inited charset " << *this << " miss=" << miss1 << "," << miss2 << "," << miss3 << "," << miss4 << " bubbles=" << bubbles);
+}
+
+Chs::~Chs()
+{
+ delete [] m_chr;
+}
+
+static NdbOut&
+operator<<(NdbOut& out, const Chs& chs)
+{
+ CHARSET_INFO* cs = chs.m_cs;
+ out << cs->name << "[" << cs->mbminlen << "-" << cs->mbmaxlen << "," << chs.m_xmul << "]";
+ return out;
+}
+
+static Chs* cslist[maxcsnumber];
+
+static void
+resetcslist()
+{
+ for (unsigned i = 0; i < maxcsnumber; i++) {
+ delete cslist[i];
+ cslist[i] = 0;
+ }
+}
+
+static Chs*
+getcs(Par par)
+{
+ CHARSET_INFO* cs;
+ if (par.m_cs != 0) {
+ cs = par.m_cs;
+ } else {
+ while (1) {
+ unsigned n = urandom(maxcsnumber);
+ cs = get_charset(n, MYF(0));
+ if (cs != 0) {
+ // prefer complex charsets
+ if (cs->mbmaxlen != 1 || urandom(5) == 0)
+ break;
+ }
+ }
+ }
+ if (cslist[cs->number] == 0)
+ cslist[cs->number] = new Chs(cs);
+ return cslist[cs->number];
+}
+
// tables and indexes
// Col - table column
struct Col {
+ enum Type {
+ Unsigned = NdbDictionary::Column::Unsigned,
+ Char = NdbDictionary::Column::Char,
+ Varchar = NdbDictionary::Column::Varchar,
+ Longvarchar = NdbDictionary::Column::Longvarchar
+ };
+ const class Tab& m_tab;
unsigned m_num;
const char* m_name;
bool m_pk;
- NdbDictionary::Column::Type m_type;
+ Type m_type;
unsigned m_length;
+ unsigned m_bytelength; // multiplied by char width
+ unsigned m_attrsize; // base type size
+ unsigned m_headsize; // length bytes
+ unsigned m_bytesize; // full value size
bool m_nullable;
- void verify(const void* addr) const;
+ const Chs* m_chs;
+ Col(const class Tab& tab, unsigned num, const char* name, bool pk, Type type, unsigned length, bool nullable, const Chs* chs);
+ ~Col();
+ bool equal(const Col& col2) const;
+ void wellformed(const void* addr) const;
};
+Col::Col(const class Tab& tab, unsigned num, const char* name, bool pk, Type type, unsigned length, bool nullable, const Chs* chs) :
+ m_tab(tab),
+ m_num(num),
+ m_name(strcpy(new char [strlen(name) + 1], name)),
+ m_pk(pk),
+ m_type(type),
+ m_length(length),
+ m_bytelength(length * (chs == 0 ? 1 : chs->m_cs->mbmaxlen)),
+ m_attrsize(
+ type == Unsigned ? sizeof(Uint32) :
+ type == Char ? sizeof(char) :
+ type == Varchar ? sizeof(char) :
+ type == Longvarchar ? sizeof(char) : ~0),
+ m_headsize(
+ type == Unsigned ? 0 :
+ type == Char ? 0 :
+ type == Varchar ? 1 :
+ type == Longvarchar ? 2 : ~0),
+ m_bytesize(m_headsize + m_attrsize * m_bytelength),
+ m_nullable(nullable),
+ m_chs(chs)
+{
+ // fix long varchar
+ if (type == Varchar && m_bytelength > 255) {
+ m_type = Longvarchar;
+ m_headsize += 1;
+ m_bytesize += 1;
+ }
+}
+
+Col::~Col()
+{
+ delete [] m_name;
+}
+
+bool
+Col::equal(const Col& col2) const
+{
+ return m_type == col2.m_type && m_length == col2.m_length && m_chs == col2.m_chs;
+}
+
void
-Col::verify(const void* addr) const
+Col::wellformed(const void* addr) const
{
switch (m_type) {
- case NdbDictionary::Column::Unsigned:
+ case Col::Unsigned:
break;
- case NdbDictionary::Column::Varchar:
+ case Col::Char:
{
- const unsigned char* p = (const unsigned char*)addr;
- unsigned n = (p[0] << 8) | p[1];
- assert(n <= m_length);
- unsigned i;
- for (i = 0; i < n; i++) {
- assert(p[2 + i] != 0);
- }
- for (i = n; i < m_length; i++) {
- assert(p[2 + i] == 0);
- }
+ CHARSET_INFO* cs = m_chs->m_cs;
+ const char* src = (const char*)addr;
+ unsigned len = m_bytelength;
+ int not_used;
+ assert((*cs->cset->well_formed_len)(cs, src, src + len, 0xffff, &not_used) == len);
+ }
+ break;
+ case Col::Varchar:
+ {
+ CHARSET_INFO* cs = m_chs->m_cs;
+ const unsigned char* src = (const unsigned char*)addr;
+ const char* ssrc = (const char*)src;
+ unsigned len = src[0];
+ int not_used;
+ assert(len <= m_bytelength);
+ assert((*cs->cset->well_formed_len)(cs, ssrc + 1, ssrc + 1 + len, 0xffff, &not_used) == len);
+ }
+ break;
+ case Col::Longvarchar:
+ {
+ CHARSET_INFO* cs = m_chs->m_cs;
+ const unsigned char* src = (const unsigned char*)addr;
+ const char* ssrc = (const char*)src;
+ unsigned len = src[0] + (src[1] << 8);
+ int not_used;
+ assert(len <= m_bytelength);
+ assert((*cs->cset->well_formed_len)(cs, ssrc + 2, ssrc + 2 + len, 0xffff, &not_used) == len);
}
break;
default:
@@ -428,14 +725,28 @@ Col::verify(const void* addr) const
static NdbOut&
operator<<(NdbOut& out, const Col& col)
{
- out << "col " << col.m_num;
- out << " " << col.m_name;
+ out << "col[" << col.m_num << "] " << col.m_name;
switch (col.m_type) {
- case NdbDictionary::Column::Unsigned:
+ case Col::Unsigned:
out << " unsigned";
break;
- case NdbDictionary::Column::Varchar:
- out << " varchar(" << col.m_length << ")";
+ case Col::Char:
+ {
+ CHARSET_INFO* cs = col.m_chs->m_cs;
+ out << " char(" << col.m_length << "*" << cs->mbmaxlen << ";" << cs->name << ")";
+ }
+ break;
+ case Col::Varchar:
+ {
+ CHARSET_INFO* cs = col.m_chs->m_cs;
+ out << " varchar(" << col.m_length << "*" << cs->mbmaxlen << ";" << cs->name << ")";
+ }
+ break;
+ case Col::Longvarchar:
+ {
+ CHARSET_INFO* cs = col.m_chs->m_cs;
+ out << " longvarchar(" << col.m_length << "*" << cs->mbmaxlen << ";" << cs->name << ")";
+ }
break;
default:
out << "type" << (int)col.m_type;
@@ -450,25 +761,84 @@ operator<<(NdbOut& out, const Col& col)
// ICol - index column
struct ICol {
+ const class ITab& m_itab;
unsigned m_num;
- struct Col m_col;
+ const Col& m_col;
+ ICol(const class ITab& itab, unsigned num, const Col& col);
+ ~ICol();
};
+ICol::ICol(const class ITab& itab, unsigned num, const Col& col) :
+ m_itab(itab),
+ m_num(num),
+ m_col(col)
+{
+}
+
+ICol::~ICol()
+{
+}
+
+static NdbOut&
+operator<<(NdbOut& out, const ICol& icol)
+{
+ out << "icol[" << icol.m_num << "] " << icol.m_col;
+ return out;
+}
+
// ITab - index
struct ITab {
+ enum Type {
+ OrderedIndex = NdbDictionary::Index::OrderedIndex,
+ UniqueHashIndex = NdbDictionary::Index::UniqueHashIndex
+ };
+ const class Tab& m_tab;
const char* m_name;
+ Type m_type;
unsigned m_icols;
- const ICol* m_icol;
+ const ICol** m_icol;
+ unsigned m_colmask;
+ ITab(const class Tab& tab, const char* name, Type type, unsigned icols);
+ ~ITab();
+ void icoladd(unsigned k, const ICol* icolptr);
};
+ITab::ITab(const class Tab& tab, const char* name, Type type, unsigned icols) :
+ m_tab(tab),
+ m_name(strcpy(new char [strlen(name) + 1], name)),
+ m_type(type),
+ m_icols(icols),
+ m_icol(new const ICol* [icols + 1]),
+ m_colmask(0)
+{
+ for (unsigned k = 0; k <= m_icols; k++)
+ m_icol[k] = 0;
+}
+
+ITab::~ITab()
+{
+ delete [] m_name;
+ for (unsigned i = 0; i < m_icols; i++)
+ delete m_icol[i];
+ delete [] m_icol;
+}
+
+void
+ITab::icoladd(unsigned k, const ICol* icolptr)
+{
+ assert(k == icolptr->m_num && k < m_icols && m_icol[k] == 0);
+ m_icol[k] = icolptr;
+ m_colmask |= (1 << icolptr->m_col.m_num);
+}
+
static NdbOut&
operator<<(NdbOut& out, const ITab& itab)
{
- out << "itab " << itab.m_name << " " << itab.m_icols;
+ out << "itab " << itab.m_name << " icols=" << itab.m_icols;
for (unsigned k = 0; k < itab.m_icols; k++) {
- out << endl;
- out << "icol " << k << " " << itab.m_icol[k].m_col;
+ const ICol& icol = *itab.m_icol[k];
+ out << endl << icol;
}
return out;
}
@@ -478,200 +848,298 @@ operator<<(NdbOut& out, const ITab& itab)
struct Tab {
const char* m_name;
unsigned m_cols;
- const Col* m_col;
+ const Col** m_col;
unsigned m_itabs;
- const ITab* m_itab;
+ const ITab** m_itab;
+ // pk must contain an Unsigned column
+ unsigned m_keycol;
+ void coladd(unsigned k, Col* colptr);
+ void itabadd(unsigned j, ITab* itab);
+ Tab(const char* name, unsigned cols, unsigned itabs, unsigned keycol);
+ ~Tab();
};
+Tab::Tab(const char* name, unsigned cols, unsigned itabs, unsigned keycol) :
+ m_name(strcpy(new char [strlen(name) + 1], name)),
+ m_cols(cols),
+ m_col(new const Col* [cols + 1]),
+ m_itabs(itabs),
+ m_itab(new const ITab* [itabs + 1]),
+ m_keycol(keycol)
+{
+ for (unsigned k = 0; k <= cols; k++)
+ m_col[k] = 0;
+ for (unsigned j = 0; j <= itabs; j++)
+ m_itab[j] = 0;
+}
+
+Tab::~Tab()
+{
+ delete [] m_name;
+ for (unsigned i = 0; i < m_cols; i++)
+ delete m_col[i];
+ delete [] m_col;
+ for (unsigned i = 0; i < m_itabs; i++)
+ delete m_itab[i];
+ delete [] m_itab;
+}
+
+void
+Tab::coladd(unsigned k, Col* colptr)
+{
+ assert(k == colptr->m_num && k < m_cols && m_col[k] == 0);
+ m_col[k] = colptr;
+}
+
+void
+Tab::itabadd(unsigned j, ITab* itabptr)
+{
+ assert(j < m_itabs && m_itab[j] == 0);
+ m_itab[j] = itabptr;
+}
+
static NdbOut&
operator<<(NdbOut& out, const Tab& tab)
{
- out << "tab " << tab.m_name << " " << tab.m_cols;
+ out << "tab " << tab.m_name << " cols=" << tab.m_cols;
for (unsigned k = 0; k < tab.m_cols; k++) {
- out << endl;
- out << tab.m_col[k];
+ const Col& col = *tab.m_col[k];
+ out << endl << col;
}
for (unsigned i = 0; i < tab.m_itabs; i++) {
- if (! useindex(i))
+ if (tab.m_itab[i] == 0)
continue;
- out << endl;
- out << tab.m_itab[i];
+ const ITab& itab = *tab.m_itab[i];
+ out << endl << itab;
}
return out;
}
-// tt1 + tt1x1 tt1x2 tt1x3 tt1x4 tt1x5
+// make table structs
-static const Col
-tt1col[] = {
- { 0, "A", 1, NdbDictionary::Column::Unsigned, 1, 0 },
- { 1, "B", 0, NdbDictionary::Column::Unsigned, 1, 1 },
- { 2, "C", 0, NdbDictionary::Column::Unsigned, 1, 1 },
- { 3, "D", 0, NdbDictionary::Column::Unsigned, 1, 1 },
- { 4, "E", 0, NdbDictionary::Column::Unsigned, 1, 1 }
-};
-
-static const ICol
-tt1x1col[] = {
- { 0, tt1col[0] }
-};
-
-static const ICol
-tt1x2col[] = {
- { 0, tt1col[1] }
-};
-
-static const ICol
-tt1x3col[] = {
- { 0, tt1col[1] },
- { 1, tt1col[2] }
-};
-
-static const ICol
-tt1x4col[] = {
- { 0, tt1col[3] },
- { 1, tt1col[2] },
- { 2, tt1col[1] }
-};
-
-static const ICol
-tt1x5col[] = {
- { 0, tt1col[1] },
- { 1, tt1col[4] },
- { 2, tt1col[2] },
- { 3, tt1col[3] }
-};
-
-static const ITab
-tt1x1 = {
- "TT1X1", 1, tt1x1col
-};
-
-static const ITab
-tt1x2 = {
- "TT1X2", 1, tt1x2col
-};
+static const Tab** tablist = 0;
+static unsigned tabcount = 0;
-static const ITab
-tt1x3 = {
- "TT1X3", 2, tt1x3col
-};
-
-static const ITab
-tt1x4 = {
- "TT1X4", 3, tt1x4col
-};
-
-static const ITab
-tt1x5 = {
- "TT1X5", 4, tt1x5col
-};
-
-static const ITab
-tt1itab[] = {
- tt1x1,
- tt1x2,
- tt1x3,
- tt1x4,
- tt1x5
-};
-
-static const Tab
-tt1 = {
- "TT1", 5, tt1col, 5, tt1itab
-};
-
-// tt2 + tt2x1 tt2x2 tt2x3 tt2x4 tt2x5
-
-static const Col
-tt2col[] = {
- { 0, "A", 1, NdbDictionary::Column::Unsigned, 1, 0 },
- { 1, "B", 0, NdbDictionary::Column::Unsigned, 1, 1 },
- { 2, "C", 0, NdbDictionary::Column::Varchar, 20, 1 },
- { 3, "D", 0, NdbDictionary::Column::Varchar, 5, 1 },
- { 4, "E", 0, NdbDictionary::Column::Varchar, 5, 1 }
-};
-
-static const ICol
-tt2x1col[] = {
- { 0, tt2col[0] }
-};
-
-static const ICol
-tt2x2col[] = {
- { 0, tt2col[1] },
- { 1, tt2col[2] }
-};
-
-static const ICol
-tt2x3col[] = {
- { 0, tt2col[2] },
- { 1, tt2col[1] }
-};
-
-static const ICol
-tt2x4col[] = {
- { 0, tt2col[3] },
- { 1, tt2col[4] }
-};
-
-static const ICol
-tt2x5col[] = {
- { 0, tt2col[4] },
- { 1, tt2col[3] },
- { 2, tt2col[2] },
- { 3, tt2col[1] }
-};
-
-static const ITab
-tt2x1 = {
- "TT2X1", 1, tt2x1col
-};
-
-static const ITab
-tt2x2 = {
- "TT2X2", 2, tt2x2col
-};
-
-static const ITab
-tt2x3 = {
- "TT2X3", 2, tt2x3col
-};
-
-static const ITab
-tt2x4 = {
- "TT2X4", 2, tt2x4col
-};
-
-static const ITab
-tt2x5 = {
- "TT2X5", 4, tt2x5col
-};
-
-static const ITab
-tt2itab[] = {
- tt2x1,
- tt2x2,
- tt2x3,
- tt2x4,
- tt2x5
-};
-
-static const Tab
-tt2 = {
- "TT2", 5, tt2col, 5, tt2itab
-};
-
-// all tables
-
-static const Tab
-tablist[] = {
- tt1,
- tt2
-};
+static void
+verifytables()
+{
+ for (unsigned j = 0; j < tabcount; j++) {
+ const Tab* t = tablist[j];
+ if (t == 0)
+ continue;
+ assert(t->m_cols != 0 && t->m_col != 0);
+ for (unsigned k = 0; k < t->m_cols; k++) {
+ const Col* c = t->m_col[k];
+ assert(c != 0 && c->m_num == k);
+ assert(! (c->m_pk && c->m_nullable));
+ }
+ assert(t->m_col[t->m_cols] == 0);
+ {
+ assert(t->m_keycol < t->m_cols);
+ const Col* c = t->m_col[t->m_keycol];
+ assert(c->m_pk && c->m_type == Col::Unsigned);
+ }
+ assert(t->m_itabs != 0 && t->m_itab != 0);
+ for (unsigned i = 0; i < t->m_itabs; i++) {
+ const ITab* x = t->m_itab[i];
+ if (x == 0)
+ continue;
+ assert(x != 0 && x->m_icols != 0 && x->m_icol != 0);
+ for (unsigned k = 0; k < x->m_icols; k++) {
+ const ICol* c = x->m_icol[k];
+ assert(c != 0 && c->m_num == k && c->m_col.m_num < t->m_cols);
+ if (x->m_type == ITab::UniqueHashIndex) {
+ assert(! c->m_col.m_nullable);
+ }
+ }
+ }
+ assert(t->m_itab[t->m_itabs] == 0);
+ }
+}
-static const unsigned
-tabcount = sizeof(tablist) / sizeof(tablist[0]);
+static void
+makebuiltintables(Par par)
+{
+ LL2("makebuiltintables");
+ resetcslist();
+ tabcount = 3;
+ if (tablist == 0) {
+ tablist = new const Tab* [tabcount];
+ for (unsigned j = 0; j < tabcount; j++) {
+ tablist[j] = 0;
+ }
+ } else {
+ for (unsigned j = 0; j < tabcount; j++) {
+ delete tablist[j];
+ tablist[j] = 0;
+ }
+ }
+ // ti0 - basic
+ if (usetable(par, 0)) {
+ Tab* t = new Tab("ti0", 5, 7, 0);
+ // name - pk - type - length - nullable - cs
+ t->coladd(0, new Col(*t, 0, "a", 1, Col::Unsigned, 1, 0, 0));
+ t->coladd(1, new Col(*t, 1, "b", 0, Col::Unsigned, 1, 1, 0));
+ t->coladd(2, new Col(*t, 2, "c", 0, Col::Unsigned, 1, 0, 0));
+ t->coladd(3, new Col(*t, 3, "d", 0, Col::Unsigned, 1, 1, 0));
+ t->coladd(4, new Col(*t, 4, "e", 0, Col::Unsigned, 1, 0, 0));
+ if (useindex(par, 0)) {
+ // a
+ ITab* x = new ITab(*t, "ti0x0", ITab::OrderedIndex, 1);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
+ t->itabadd(0, x);
+ }
+ if (useindex(par, 1)) {
+ // b
+ ITab* x = new ITab(*t, "ti0x1", ITab::OrderedIndex, 1);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
+ t->itabadd(1, x);
+ }
+ if (useindex(par, 2)) {
+ // b, c
+ ITab* x = new ITab(*t, "ti0x2", ITab::OrderedIndex, 2);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
+ t->itabadd(2, x);
+ }
+ if (useindex(par, 3)) {
+ // b, e, c, d
+ ITab* x = new ITab(*t, "ti0x3", ITab::OrderedIndex, 4);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[4]));
+ x->icoladd(2, new ICol(*x, 2, *t->m_col[2]));
+ x->icoladd(3, new ICol(*x, 3, *t->m_col[3]));
+ t->itabadd(3, x);
+ }
+ if (useindex(par, 4)) {
+ // a, c
+ ITab* x = new ITab(*t, "ti0z4", ITab::UniqueHashIndex, 2);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
+ t->itabadd(4, x);
+ }
+ if (useindex(par, 5)) {
+ // a, e
+ ITab* x = new ITab(*t, "ti0z5", ITab::UniqueHashIndex, 2);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[4]));
+ t->itabadd(5, x);
+ }
+ tablist[0] = t;
+ }
+ // ti1 - simple char fields
+ if (usetable(par, 1)) {
+ Tab* t = new Tab("ti1", 5, 7, 1);
+ // 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(4, new Col(*t, 4, "e", 0, Col::Longvarchar, 5, 1, getcs(par)));
+ if (useindex(par, 0)) {
+ // b
+ ITab* x = new ITab(*t, "ti1x0", ITab::OrderedIndex, 1);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
+ t->itabadd(0, x);
+ }
+ if (useindex(par, 1)) {
+ // c, a
+ ITab* x = new ITab(*t, "ti1x1", ITab::OrderedIndex, 2);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[2]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[0]));
+ t->itabadd(1, x);
+ }
+ if (useindex(par, 2)) {
+ // d
+ ITab* x = new ITab(*t, "ti1x2", ITab::OrderedIndex, 1);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[3]));
+ t->itabadd(2, x);
+ }
+ if (useindex(par, 3)) {
+ // e, d, c, b
+ ITab* x = new ITab(*t, "ti1x3", ITab::OrderedIndex, 4);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[4]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[3]));
+ x->icoladd(2, new ICol(*x, 2, *t->m_col[2]));
+ x->icoladd(3, new ICol(*x, 3, *t->m_col[1]));
+ t->itabadd(3, x);
+ }
+ if (useindex(par, 4)) {
+ // a, b
+ ITab* x = new ITab(*t, "ti1z4", ITab::UniqueHashIndex, 2);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[1]));
+ t->itabadd(4, x);
+ }
+ if (useindex(par, 5)) {
+ // a, b, 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(2, new ICol(*x, 2, *t->m_col[3]));
+ t->itabadd(5, x);
+ }
+ tablist[1] = t;
+ }
+ // ti2 - complex char fields
+ if (usetable(par, 2)) {
+ Tab* t = new Tab("ti2", 5, 7, 2);
+ // name - pk - type - length - nullable - cs
+ t->coladd(0, new Col(*t, 0, "a", 1, Col::Char, 31, 0, getcs(par)));
+ t->coladd(1, new Col(*t, 1, "b", 0, Col::Char, 4, 1, getcs(par)));
+ t->coladd(2, new Col(*t, 2, "c", 1, Col::Unsigned, 1, 0, 0));
+ t->coladd(3, new Col(*t, 3, "d", 1, Col::Varchar, 128, 0, getcs(par)));
+ t->coladd(4, new Col(*t, 4, "e", 0, Col::Varchar, 7, 0, getcs(par)));
+ if (useindex(par, 0)) {
+ // a, c, d
+ ITab* x = new ITab(*t, "ti2x0", ITab::OrderedIndex, 3);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
+ x->icoladd(2, new ICol(*x, 2, *t->m_col[3]));
+ t->itabadd(0, x);
+ }
+ if (useindex(par, 1)) {
+ // e, d, c, b, a
+ ITab* x = new ITab(*t, "ti2x1", ITab::OrderedIndex, 5);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[4]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[3]));
+ x->icoladd(2, new ICol(*x, 2, *t->m_col[2]));
+ x->icoladd(3, new ICol(*x, 3, *t->m_col[1]));
+ x->icoladd(4, new ICol(*x, 4, *t->m_col[0]));
+ t->itabadd(1, x);
+ }
+ if (useindex(par, 2)) {
+ // d
+ ITab* x = new ITab(*t, "ti2x2", ITab::OrderedIndex, 1);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[3]));
+ t->itabadd(2, x);
+ }
+ if (useindex(par, 3)) {
+ // b
+ ITab* x = new ITab(*t, "ti2x3", ITab::OrderedIndex, 1);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[1]));
+ t->itabadd(3, x);
+ }
+ if (useindex(par, 4)) {
+ // a, c
+ ITab* x = new ITab(*t, "ti2z4", ITab::UniqueHashIndex, 2);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
+ t->itabadd(4, x);
+ }
+ if (useindex(par, 5)) {
+ // a, c, d, e
+ ITab* x = new ITab(*t, "ti2z5", ITab::UniqueHashIndex, 4);
+ x->icoladd(0, new ICol(*x, 0, *t->m_col[0]));
+ x->icoladd(1, new ICol(*x, 1, *t->m_col[2]));
+ x->icoladd(2, new ICol(*x, 2, *t->m_col[3]));
+ x->icoladd(3, new ICol(*x, 3, *t->m_col[4]));
+ t->itabadd(5, x);
+ }
+ tablist[2] = t;
+ }
+ verifytables();
+}
// connections
@@ -682,16 +1150,18 @@ struct Con {
NdbDictionary::Dictionary* m_dic;
NdbConnection* m_tx;
NdbOperation* m_op;
+ NdbIndexOperation* m_indexop;
NdbScanOperation* m_scanop;
NdbIndexScanOperation* m_indexscanop;
- NdbResultSet* m_resultset;
+ NdbScanFilter* m_scanfilter;
enum ScanMode { ScanNo = 0, Committed, Latest, Exclusive };
ScanMode m_scanmode;
enum ErrType { ErrNone = 0, ErrDeadlock, ErrNospace, ErrOther };
ErrType m_errtype;
Con() :
- m_ndb(0), m_dic(0), m_tx(0), m_op(0),
- m_scanop(0), m_indexscanop(0), m_resultset(0), m_scanmode(ScanNo), m_errtype(ErrNone) {}
+ m_ndb(0), m_dic(0), m_tx(0), m_op(0), m_indexop(0),
+ m_scanop(0), m_indexscanop(0), m_scanfilter(0),
+ m_scanmode(ScanNo), m_errtype(ErrNone) {}
~Con() {
if (m_tx != 0)
closeTransaction();
@@ -701,16 +1171,23 @@ struct Con {
void disconnect();
int startTransaction();
int getNdbOperation(const Tab& tab);
+ int getNdbIndexOperation1(const ITab& itab, const Tab& tab);
+ int getNdbIndexOperation(const ITab& itab, const Tab& tab);
int getNdbScanOperation(const Tab& tab);
- int getNdbScanOperation(const ITab& itab, const Tab& tab);
+ int getNdbIndexScanOperation1(const ITab& itab, const Tab& tab);
+ int getNdbIndexScanOperation(const ITab& itab, const Tab& tab);
+ int getNdbScanFilter();
int equal(int num, const char* addr);
int getValue(int num, NdbRecAttr*& rec);
int setValue(int num, const char* addr);
int setBound(int num, int type, const void* value);
+ int beginFilter(int group);
+ int endFilter();
+ int setFilter(int num, int cond, const void* value, unsigned len);
int execute(ExecType t);
int execute(ExecType t, bool& deadlock, bool& nospace);
- int openScanRead(unsigned scanbat, unsigned scanpar);
- int openScanExclusive(unsigned scanbat, unsigned scanpar);
+ int readTuples(Par par);
+ int readIndexTuples(Par par);
int executeScan();
int nextScanResult(bool fetchAllowed);
int nextScanResult(bool fetchAllowed, bool& deadlock);
@@ -765,6 +1242,28 @@ Con::getNdbOperation(const Tab& tab)
}
int
+Con::getNdbIndexOperation1(const ITab& itab, const Tab& tab)
+{
+ assert(m_tx != 0);
+ CHKCON((m_op = m_indexop = m_tx->getNdbIndexOperation(itab.m_name, tab.m_name)) != 0, *this);
+ return 0;
+}
+
+int
+Con::getNdbIndexOperation(const ITab& itab, const Tab& tab)
+{
+ assert(m_tx != 0);
+ unsigned tries = 0;
+ while (1) {
+ if (getNdbIndexOperation1(itab, tab) == 0)
+ break;
+ CHK(++tries < 10);
+ NdbSleep_MilliSleep(100);
+ }
+ return 0;
+}
+
+int
Con::getNdbScanOperation(const Tab& tab)
{
assert(m_tx != 0);
@@ -773,7 +1272,7 @@ Con::getNdbScanOperation(const Tab& tab)
}
int
-Con::getNdbScanOperation(const ITab& itab, const Tab& tab)
+Con::getNdbIndexScanOperation1(const ITab& itab, const Tab& tab)
{
assert(m_tx != 0);
CHKCON((m_op = m_scanop = m_indexscanop = m_tx->getNdbIndexScanOperation(itab.m_name, tab.m_name)) != 0, *this);
@@ -781,6 +1280,29 @@ Con::getNdbScanOperation(const ITab& itab, const Tab& tab)
}
int
+Con::getNdbIndexScanOperation(const ITab& itab, const Tab& tab)
+{
+ assert(m_tx != 0);
+ unsigned tries = 0;
+ while (1) {
+ if (getNdbIndexScanOperation1(itab, tab) == 0)
+ break;
+ CHK(++tries < 10);
+ NdbSleep_MilliSleep(100);
+ }
+ return 0;
+}
+
+int
+Con::getNdbScanFilter()
+{
+ assert(m_tx != 0 && m_scanop != 0);
+ delete m_scanfilter;
+ m_scanfilter = new NdbScanFilter(m_scanop);
+ return 0;
+}
+
+int
Con::equal(int num, const char* addr)
{
assert(m_tx != 0 && m_op != 0);
@@ -807,12 +1329,36 @@ Con::setValue(int num, const char* addr)
int
Con::setBound(int num, int type, const void* value)
{
- assert(m_tx != 0 && m_op != 0);
+ assert(m_tx != 0 && m_indexscanop != 0);
CHKCON(m_indexscanop->setBound(num, type, value) == 0, *this);
return 0;
}
int
+Con::beginFilter(int group)
+{
+ assert(m_tx != 0 && m_scanfilter != 0);
+ CHKCON(m_scanfilter->begin((NdbScanFilter::Group)group) == 0, *this);
+ return 0;
+}
+
+int
+Con::endFilter()
+{
+ assert(m_tx != 0 && m_scanfilter != 0);
+ CHKCON(m_scanfilter->end() == 0, *this);
+ return 0;
+}
+
+int
+Con::setFilter(int num, int cond, const void* value, unsigned len)
+{
+ assert(m_tx != 0 && m_scanfilter != 0);
+ CHKCON(m_scanfilter->cmp((NdbScanFilter::BinaryCondition)cond, num, value, len) == 0, *this);
+ return 0;
+}
+
+int
Con::execute(ExecType t)
{
assert(m_tx != 0);
@@ -841,20 +1387,18 @@ Con::execute(ExecType t, bool& deadlock, bool& nospace)
}
int
-Con::openScanRead(unsigned scanbat, unsigned scanpar)
+Con::readTuples(Par par)
{
- assert(m_tx != 0 && m_op != 0);
- NdbOperation::LockMode lm = NdbOperation::LM_Read;
- CHKCON((m_resultset = m_scanop->readTuples(lm, scanbat, scanpar)) != 0, *this);
+ assert(m_tx != 0 && m_scanop != 0);
+ CHKCON(m_scanop->readTuples(par.m_lockmode, par.m_scanbat, par.m_scanpar) == 0, *this);
return 0;
}
int
-Con::openScanExclusive(unsigned scanbat, unsigned scanpar)
+Con::readIndexTuples(Par par)
{
- assert(m_tx != 0 && m_op != 0);
- NdbOperation::LockMode lm = NdbOperation::LM_Exclusive;
- CHKCON((m_resultset = m_scanop->readTuples(lm, scanbat, scanpar)) != 0, *this);
+ assert(m_tx != 0 && m_indexscanop != 0);
+ CHKCON(m_indexscanop->readTuples(par.m_lockmode, par.m_scanbat, par.m_scanpar, par.m_ordered, par.m_descending) == 0, *this);
return 0;
}
@@ -869,8 +1413,8 @@ int
Con::nextScanResult(bool fetchAllowed)
{
int ret;
- assert(m_resultset != 0);
- CHKCON((ret = m_resultset->nextResult(fetchAllowed)) != -1, *this);
+ assert(m_scanop != 0);
+ CHKCON((ret = m_scanop->nextResult(fetchAllowed)) != -1, *this);
assert(ret == 0 || ret == 1 || (! fetchAllowed && ret == 2));
return ret;
}
@@ -895,7 +1439,7 @@ int
Con::updateScanTuple(Con& con2)
{
assert(con2.m_tx != 0);
- CHKCON((con2.m_op = m_resultset->updateTuple(con2.m_tx)) != 0, *this);
+ CHKCON((con2.m_op = m_scanop->updateCurrentTuple(con2.m_tx)) != 0, *this);
return 0;
}
@@ -903,16 +1447,16 @@ int
Con::deleteScanTuple(Con& con2)
{
assert(con2.m_tx != 0);
- CHKCON(m_resultset->deleteTuple(con2.m_tx) == 0, *this);
+ CHKCON(m_scanop->deleteCurrentTuple(con2.m_tx) == 0, *this);
return 0;
}
void
Con::closeScan()
{
- assert(m_resultset != 0);
- m_resultset->close();
- m_scanop = 0, m_indexscanop = 0, m_resultset = 0;
+ assert(m_scanop != 0);
+ m_scanop->close();
+ m_scanop = 0, m_indexscanop = 0;
}
@@ -922,7 +1466,7 @@ Con::closeTransaction()
assert(m_ndb != 0 && m_tx != 0);
m_ndb->closeTransaction(m_tx);
m_tx = 0, m_op = 0;
- m_scanop = 0, m_indexscanop = 0, m_resultset = 0;
+ m_scanop = 0, m_indexscanop = 0;
}
void
@@ -945,7 +1489,8 @@ Con::printerror(NdbOut& out)
if ((code = m_tx->getNdbError().code) != 0) {
LL0(++any << " con: error " << m_tx->getNdbError());
die += (code == g_opt.m_die);
- if (code == 266 || code == 274 || code == 296 || code == 297 || code == 499)
+ // 631 is new, occurs only on 4 db nodes, needs to be checked out
+ if (code == 266 || code == 274 || code == 296 || code == 297 || code == 499 || code == 631)
m_errtype = ErrDeadlock;
if (code == 826 || code == 827 || code == 902)
m_errtype = ErrNospace;
@@ -983,9 +1528,9 @@ invalidateindex(Par par)
Con& con = par.con();
const Tab& tab = par.tab();
for (unsigned i = 0; i < tab.m_itabs; i++) {
- if (! useindex(i))
+ if (tab.m_itab[i] == 0)
continue;
- const ITab& itab = tab.m_itab[i];
+ const ITab& itab = *tab.m_itab[i];
invalidateindex(par, itab);
}
return 0;
@@ -1033,16 +1578,14 @@ createtable(Par par)
t.setLogging(false);
}
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Col& col = tab.m_col[k];
+ const Col& col = *tab.m_col[k];
NdbDictionary::Column c(col.m_name);
- c.setType(col.m_type);
- c.setLength(col.m_length);
+ c.setType((NdbDictionary::Column::Type)col.m_type);
+ c.setLength(col.m_bytelength); // for char NDB API uses length in bytes
c.setPrimaryKey(col.m_pk);
c.setNullable(col.m_nullable);
- if (c.getCharset()) { // test if char type
- if (! col.m_pk)
- c.setCharset(par.m_cs);
- }
+ if (col.m_chs != 0)
+ c.setCharset(col.m_chs->m_cs);
t.addColumn(c);
}
con.m_dic = con.m_ndb->getDictionary();
@@ -1073,9 +1616,9 @@ dropindex(Par par)
{
const Tab& tab = par.tab();
for (unsigned i = 0; i < tab.m_itabs; i++) {
- if (! useindex(i))
+ if (tab.m_itab[i] == 0)
continue;
- const ITab& itab = tab.m_itab[i];
+ const ITab& itab = *tab.m_itab[i];
CHK(dropindex(par, itab) == 0);
}
return 0;
@@ -1090,10 +1633,13 @@ createindex(Par par, const ITab& itab)
LL4(itab);
NdbDictionary::Index x(itab.m_name);
x.setTable(tab.m_name);
- x.setType(NdbDictionary::Index::OrderedIndex);
- x.setLogging(false);
+ x.setType((NdbDictionary::Index::Type)itab.m_type);
+ if (par.m_nologging || itab.m_type == ITab::OrderedIndex) {
+ x.setLogging(false);
+ }
for (unsigned k = 0; k < itab.m_icols; k++) {
- const Col& col = itab.m_icol[k].m_col;
+ const ICol& icol = *itab.m_icol[k];
+ const Col& col = icol.m_col;
x.addColumnName(col.m_name);
}
con.m_dic = con.m_ndb->getDictionary();
@@ -1107,9 +1653,9 @@ createindex(Par par)
{
const Tab& tab = par.tab();
for (unsigned i = 0; i < tab.m_itabs; i++) {
- if (! useindex(i))
+ if (tab.m_itab[i] == 0)
continue;
- const ITab& itab = tab.m_itab[i];
+ const ITab& itab = *tab.m_itab[i];
CHK(createindex(par, itab) == 0);
}
return 0;
@@ -1117,43 +1663,15 @@ createindex(Par par)
// data sets
-static unsigned
-urandom(unsigned n)
-{
- if (n == 0)
- return 0;
- unsigned i = random() % n;
- return i;
-}
-
-static int
-irandom(unsigned n)
-{
- if (n == 0)
- return 0;
- int i = random() % n;
- if (random() & 0x1)
- i = -i;
- return i;
-}
-
-static bool
-randompct(unsigned pct)
-{
- if (pct == 0)
- return false;
- if (pct >= 100)
- return true;
- return urandom(100) < pct;
-}
-
// Val - typed column value
struct Val {
const Col& m_col;
union {
Uint32 m_uint32;
- char* m_varchar;
+ unsigned char* m_char;
+ unsigned char* m_varchar;
+ unsigned char* m_longvarchar;
};
Val(const Col& col);
~Val();
@@ -1161,10 +1679,17 @@ struct Val {
void copy(const void* addr);
const void* dataaddr() const;
bool m_null;
+ int equal(Par par) const;
+ int equal(Par par, const ICol& icol) const;
int setval(Par par) const;
void calc(Par par, unsigned i);
- int verify(const Val& val2) const;
- int cmp(const Val& val2) const;
+ void calckey(Par par, unsigned i);
+ void calckeychars(Par par, unsigned i, unsigned& n, unsigned char* buf);
+ void calcnokey(Par par);
+ void calcnokeychars(Par par, unsigned& n, unsigned char* buf);
+ int verify(Par par, const Val& val2) const;
+ int cmp(Par par, const Val& val2) const;
+ int cmpchars(Par par, const unsigned char* buf1, unsigned len1, const unsigned char* buf2, unsigned len2) const;
private:
Val& operator=(const Val& val2);
};
@@ -1176,10 +1701,16 @@ Val::Val(const Col& col) :
m_col(col)
{
switch (col.m_type) {
- case NdbDictionary::Column::Unsigned:
+ case Col::Unsigned:
+ break;
+ case Col::Char:
+ m_char = new unsigned char [col.m_bytelength];
break;
- case NdbDictionary::Column::Varchar:
- m_varchar = new char [2 + col.m_length];
+ case Col::Varchar:
+ m_varchar = new unsigned char [1 + col.m_bytelength];
+ break;
+ case Col::Longvarchar:
+ m_longvarchar = new unsigned char [2 + col.m_bytelength];
break;
default:
assert(false);
@@ -1191,11 +1722,17 @@ Val::~Val()
{
const Col& col = m_col;
switch (col.m_type) {
- case NdbDictionary::Column::Unsigned:
+ case Col::Unsigned:
+ break;
+ case Col::Char:
+ delete [] m_char;
break;
- case NdbDictionary::Column::Varchar:
+ case Col::Varchar:
delete [] m_varchar;
break;
+ case Col::Longvarchar:
+ delete [] m_longvarchar;
+ break;
default:
assert(false);
break;
@@ -1220,11 +1757,17 @@ Val::copy(const void* addr)
{
const Col& col = m_col;
switch (col.m_type) {
- case NdbDictionary::Column::Unsigned:
+ case Col::Unsigned:
m_uint32 = *(const Uint32*)addr;
break;
- case NdbDictionary::Column::Varchar:
- memcpy(m_varchar, addr, 2 + col.m_length);
+ case Col::Char:
+ memcpy(m_char, addr, col.m_bytelength);
+ break;
+ case Col::Varchar:
+ memcpy(m_varchar, addr, 1 + col.m_bytelength);
+ break;
+ case Col::Longvarchar:
+ memcpy(m_longvarchar, addr, 2 + col.m_bytelength);
break;
default:
assert(false);
@@ -1238,10 +1781,14 @@ Val::dataaddr() const
{
const Col& col = m_col;
switch (col.m_type) {
- case NdbDictionary::Column::Unsigned:
+ case Col::Unsigned:
return &m_uint32;
- case NdbDictionary::Column::Varchar:
+ case Col::Char:
+ return m_char;
+ case Col::Varchar:
return m_varchar;
+ case Col::Longvarchar:
+ return m_longvarchar;
default:
break;
}
@@ -1250,18 +1797,37 @@ Val::dataaddr() const
}
int
-Val::setval(Par par) const
+Val::equal(Par par) const
{
Con& con = par.con();
const Col& col = m_col;
+ assert(col.m_pk && ! m_null);
const char* addr = (const char*)dataaddr();
- if (m_null)
- addr = 0;
- if (col.m_pk)
- CHK(con.equal(col.m_num, addr) == 0);
- else
- CHK(con.setValue(col.m_num, addr) == 0);
- LL5("setval [" << m_col << "] " << *this);
+ LL5("equal [" << col << "] " << *this);
+ CHK(con.equal(col.m_num, addr) == 0);
+ return 0;
+}
+
+int
+Val::equal(Par par, const ICol& icol) const
+{
+ Con& con = par.con();
+ assert(! m_null);
+ const char* addr = (const char*)dataaddr();
+ LL5("equal [" << icol << "] " << *this);
+ CHK(con.equal(icol.m_num, addr) == 0);
+ return 0;
+}
+
+int
+Val::setval(Par par) const
+{
+ Con& con = par.con();
+ const Col& col = m_col;
+ assert(! col.m_pk);
+ const char* addr = ! m_null ? (const char*)dataaddr() : 0;
+ LL5("setval [" << col << "] " << *this);
+ CHK(con.setValue(col.m_num, addr) == 0);
return 0;
}
@@ -1269,58 +1835,170 @@ void
Val::calc(Par par, unsigned i)
{
const Col& col = m_col;
+ col.m_pk ? calckey(par, i) : calcnokey(par);
+ if (! m_null)
+ col.wellformed(dataaddr());
+}
+
+void
+Val::calckey(Par par, unsigned i)
+{
+ const Col& col = m_col;
m_null = false;
- if (col.m_pk) {
+ switch (col.m_type) {
+ case Col::Unsigned:
m_uint32 = i;
- return;
+ break;
+ case Col::Char:
+ {
+ const Chs* chs = col.m_chs;
+ CHARSET_INFO* cs = chs->m_cs;
+ unsigned n = 0;
+ calckeychars(par, i, n, m_char);
+ // extend by appropriate space
+ (*cs->cset->fill)(cs, (char*)&m_char[n], col.m_bytelength - n, 0x20);
+ }
+ break;
+ case Col::Varchar:
+ {
+ unsigned n = 0;
+ calckeychars(par, i, n, m_varchar + 1);
+ // set length and pad with nulls
+ m_varchar[0] = n;
+ memset(&m_varchar[1 + n], 0, col.m_bytelength - n);
+ }
+ break;
+ case Col::Longvarchar:
+ {
+ unsigned n = 0;
+ calckeychars(par, i, n, m_longvarchar + 2);
+ // set length and pad with nulls
+ m_longvarchar[0] = (n & 0xff);
+ m_longvarchar[1] = (n >> 8);
+ memset(&m_longvarchar[2 + n], 0, col.m_bytelength - n);
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+void
+Val::calckeychars(Par par, unsigned i, unsigned& n, unsigned char* buf)
+{
+ const Col& col = m_col;
+ const Chs* chs = col.m_chs;
+ CHARSET_INFO* cs = chs->m_cs;
+ n = 0;
+ unsigned len = 0;
+ while (len < col.m_length) {
+ if (i % (1 + n) == 0) {
+ break;
+ }
+ const Chr& chr = chs->m_chr[i % maxcharcount];
+ assert(n + chr.m_size <= col.m_bytelength);
+ memcpy(buf + n, chr.m_bytes, chr.m_size);
+ n += chr.m_size;
+ len++;
}
+}
+
+void
+Val::calcnokey(Par par)
+{
+ const Col& col = m_col;
+ m_null = false;
if (col.m_nullable && urandom(100) < par.m_pctnull) {
m_null = true;
return;
}
- unsigned v = par.m_range + irandom((par.m_pctrange * par.m_range) / 100);
+ int r = irandom((par.m_pctrange * par.m_range) / 100);
+ if (par.m_bdir != 0 && urandom(10) != 0) {
+ if (r < 0 && par.m_bdir > 0 || r > 0 && par.m_bdir < 0)
+ r = -r;
+ }
+ unsigned v = par.m_range + r;
switch (col.m_type) {
- case NdbDictionary::Column::Unsigned:
+ case Col::Unsigned:
m_uint32 = v;
break;
- case NdbDictionary::Column::Varchar:
+ case Col::Char:
{
+ const Chs* chs = col.m_chs;
+ CHARSET_INFO* cs = chs->m_cs;
unsigned n = 0;
- while (n < col.m_length) {
- if (urandom(1 + col.m_length) == 0) {
- // nice distribution on lengths
- break;
- }
- m_varchar[2 + n++] = 'a' + urandom((par.m_pctrange * 10) / 100);
- }
- m_varchar[0] = (n >> 8);
- m_varchar[1] = (n & 0xff);
- while (n < col.m_length) {
- m_varchar[2 + n++] = 0;
- }
+ calcnokeychars(par, n, m_char);
+ // extend by appropriate space
+ (*cs->cset->fill)(cs, (char*)&m_char[n], col.m_bytelength - n, 0x20);
+ }
+ break;
+ case Col::Varchar:
+ {
+ unsigned n = 0;
+ calcnokeychars(par, n, m_varchar + 1);
+ // set length and pad with nulls
+ m_varchar[0] = n;
+ memset(&m_varchar[1 + n], 0, col.m_bytelength - n);
+ }
+ break;
+ case Col::Longvarchar:
+ {
+ unsigned n = 0;
+ calcnokeychars(par, n, m_longvarchar + 2);
+ // set length and pad with nulls
+ m_longvarchar[0] = (n & 0xff);
+ m_longvarchar[1] = (n >> 8);
+ memset(&m_longvarchar[2 + n], 0, col.m_bytelength - n);
}
break;
default:
assert(false);
break;
}
- // verify format
- col.verify(dataaddr());
+}
+
+void
+Val::calcnokeychars(Par par, unsigned& n, unsigned char* buf)
+{
+ const Col& col = m_col;
+ const Chs* chs = col.m_chs;
+ CHARSET_INFO* cs = chs->m_cs;
+ n = 0;
+ unsigned len = 0;
+ while (len < col.m_length) {
+ if (urandom(1 + col.m_bytelength) == 0) {
+ break;
+ }
+ unsigned half = maxcharcount / 2;
+ int r = irandom((par.m_pctrange * half) / 100);
+ if (par.m_bdir != 0 && urandom(10) != 0) {
+ if (r < 0 && par.m_bdir > 0 || r > 0 && par.m_bdir < 0)
+ r = -r;
+ }
+ unsigned i = half + r;
+ assert(i < maxcharcount);
+ const Chr& chr = chs->m_chr[i];
+ assert(n + chr.m_size <= col.m_bytelength);
+ memcpy(buf + n, chr.m_bytes, chr.m_size);
+ n += chr.m_size;
+ len++;
+ }
}
int
-Val::verify(const Val& val2) const
+Val::verify(Par par, const Val& val2) const
{
- CHK(cmp(val2) == 0);
+ CHK(cmp(par, val2) == 0);
return 0;
}
int
-Val::cmp(const Val& val2) const
+Val::cmp(Par par, const Val& val2) const
{
const Col& col = m_col;
const Col& col2 = val2.m_col;
- assert(col.m_type == col2.m_type && col.m_length == col2.m_length);
+ assert(col.equal(col2));
if (m_null || val2.m_null) {
if (! m_null)
return +1;
@@ -1329,18 +2007,39 @@ Val::cmp(const Val& val2) const
return 0;
}
// verify data formats
- col.verify(dataaddr());
- col.verify(val2.dataaddr());
+ col.wellformed(dataaddr());
+ col.wellformed(val2.dataaddr());
// compare
switch (col.m_type) {
- case NdbDictionary::Column::Unsigned:
- if (m_uint32 < val2.m_uint32)
- return -1;
- if (m_uint32 > val2.m_uint32)
- return +1;
- return 0;
- case NdbDictionary::Column::Varchar:
- return memcmp(&m_varchar[2], &val2.m_varchar[2], col.m_length);
+ case Col::Unsigned:
+ {
+ if (m_uint32 < val2.m_uint32)
+ return -1;
+ if (m_uint32 > val2.m_uint32)
+ return +1;
+ return 0;
+ }
+ break;
+ case Col::Char:
+ {
+ unsigned len = col.m_bytelength;
+ return cmpchars(par, m_char, len, val2.m_char, len);
+ }
+ break;
+ case Col::Varchar:
+ {
+ unsigned len1 = m_varchar[0];
+ unsigned len2 = val2.m_varchar[0];
+ return cmpchars(par, m_varchar + 1, len1, val2.m_varchar + 1, len2);
+ }
+ break;
+ case Col::Longvarchar:
+ {
+ unsigned len1 = m_longvarchar[0] + (m_longvarchar[1] << 8);
+ unsigned len2 = val2.m_longvarchar[0] + (val2.m_longvarchar[1] << 8);
+ return cmpchars(par, m_longvarchar + 2, len1, val2.m_longvarchar + 2, len2);
+ }
+ break;
default:
break;
}
@@ -1348,6 +2047,56 @@ Val::cmp(const Val& val2) const
return 0;
}
+int
+Val::cmpchars(Par par, const unsigned char* buf1, unsigned len1, const unsigned char* buf2, unsigned len2) const
+{
+ const Col& col = m_col;
+ const Chs* chs = col.m_chs;
+ CHARSET_INFO* cs = chs->m_cs;
+ int k;
+ if (! par.m_collsp) {
+ unsigned char x1[maxxmulsize * 8000];
+ unsigned char x2[maxxmulsize * 8000];
+ // make strxfrm pad both to same length
+ unsigned len = maxxmulsize * col.m_bytelength;
+ int n1 = NdbSqlUtil::strnxfrm_bug7284(cs, x1, chs->m_xmul * len, buf1, len1);
+ int n2 = NdbSqlUtil::strnxfrm_bug7284(cs, x2, chs->m_xmul * len, buf2, len2);
+ assert(n1 != -1 && n1 == n2);
+ k = memcmp(x1, x2, n1);
+ } else {
+ k = (*cs->coll->strnncollsp)(cs, buf1, len1, buf2, len2, false);
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : 0;
+}
+
+static void
+printstring(NdbOut& out, const unsigned char* str, unsigned len, bool showlen)
+{
+ char buf[4 * 8000];
+ char *p = buf;
+ *p++ = '[';
+ if (showlen) {
+ sprintf(p, "%u:", len);
+ p += strlen(p);
+ }
+ for (unsigned i = 0; i < len; i++) {
+ unsigned char c = str[i];
+ if (c == '\\') {
+ *p++ = '\\';
+ *p++ = c;
+ } else if (0x20 <= c && c < 0x7e) {
+ *p++ = c;
+ } else {
+ *p++ = '\\';
+ *p++ = hexstr[c >> 4];
+ *p++ = hexstr[c & 15];
+ }
+ }
+ *p++ = ']';
+ *p = 0;
+ out << buf;
+}
+
static NdbOut&
operator<<(NdbOut& out, const Val& val)
{
@@ -1357,16 +2106,25 @@ operator<<(NdbOut& out, const Val& val)
return out;
}
switch (col.m_type) {
- case NdbDictionary::Column::Unsigned:
+ case Col::Unsigned:
out << val.m_uint32;
break;
- case NdbDictionary::Column::Varchar:
+ case Col::Char:
+ {
+ unsigned len = col.m_bytelength;
+ printstring(out, val.m_char, len, false);
+ }
+ break;
+ case Col::Varchar:
{
- char buf[8000];
- unsigned n = (val.m_varchar[0] << 8) | val.m_varchar[1];
- assert(n <= col.m_length);
- sprintf(buf, "'%.*s'[%d]", n, &val.m_varchar[2], n);
- out << buf;
+ unsigned len = val.m_varchar[0];
+ printstring(out, val.m_varchar + 1, len, true);
+ }
+ break;
+ case Col::Longvarchar:
+ {
+ unsigned len = val.m_longvarchar[0] + (val.m_longvarchar[1] << 8);
+ printstring(out, val.m_longvarchar + 2, len, true);
}
break;
default:
@@ -1383,19 +2141,25 @@ struct Row {
const Tab& m_tab;
Val** m_val;
bool m_exist;
- enum Op { NoOp = 0, ReadOp, InsOp, UpdOp, DelOp };
+ enum Op { NoOp = 0, ReadOp = 1, InsOp = 2, UpdOp = 4, DelOp = 8, AnyOp = 15 };
Op m_pending;
+ Row* m_dbrow; // copy of db row before update
Row(const Tab& tab);
~Row();
void copy(const Row& row2);
- void calc(Par par, unsigned i);
- int verify(const Row& row2) const;
+ void calc(Par par, unsigned i, unsigned mask = 0);
+ const Row& dbrow() const;
+ int verify(Par par, const Row& row2) const;
int insrow(Par par);
int updrow(Par par);
+ int updrow(Par par, const ITab& itab);
int delrow(Par par);
+ int delrow(Par par, const ITab& itab);
int selrow(Par par);
+ int selrow(Par par, const ITab& itab);
int setrow(Par par);
- int cmp(const Row& row2) const;
+ int cmp(Par par, const Row& row2) const;
+ int cmp(Par par, const Row& row2, const ITab& itab) const;
private:
Row& operator=(const Row& row2);
};
@@ -1405,11 +2169,12 @@ Row::Row(const Tab& tab) :
{
m_val = new Val* [tab.m_cols];
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Col& col = tab.m_col[k];
+ const Col& col = *tab.m_col[k];
m_val[k] = new Val(col);
}
m_exist = false;
m_pending = NoOp;
+ m_dbrow = 0;
}
Row::~Row()
@@ -1419,6 +2184,7 @@ Row::~Row()
delete m_val[k];
}
delete [] m_val;
+ delete m_dbrow;
}
void
@@ -1431,27 +2197,49 @@ Row::copy(const Row& row2)
const Val& val2 = *row2.m_val[k];
val.copy(val2);
}
+ m_exist = row2.m_exist;
+ m_pending = row2.m_pending;
+ if (row2.m_dbrow == 0) {
+ m_dbrow = 0;
+ } else {
+ assert(row2.m_dbrow->m_dbrow == 0);
+ if (m_dbrow == 0)
+ m_dbrow = new Row(tab);
+ m_dbrow->copy(*row2.m_dbrow);
+ }
}
void
-Row::calc(Par par, unsigned i)
+Row::calc(Par par, unsigned i, unsigned mask)
{
const Tab& tab = m_tab;
for (unsigned k = 0; k < tab.m_cols; k++) {
- Val& val = *m_val[k];
- val.calc(par, i);
+ if (! (mask & (1 << k))) {
+ Val& val = *m_val[k];
+ val.calc(par, i);
+ }
}
}
+const Row&
+Row::dbrow() const
+{
+ if (m_dbrow == 0)
+ return *this;
+ assert(m_pending == Row::UpdOp || m_pending == Row::DelOp);
+ return *m_dbrow;
+}
+
int
-Row::verify(const Row& row2) const
+Row::verify(Par par, const Row& row2) const
{
const Tab& tab = m_tab;
- assert(&tab == &row2.m_tab && m_exist && row2.m_exist);
+ const Row& row1 = *this;
+ assert(&row1.m_tab == &row2.m_tab && row1.m_exist && row2.m_exist);
for (unsigned k = 0; k < tab.m_cols; k++) {
- const Val& val = *m_val[k];
+ const Val& val1 = *row1.m_val[k];
const Val& val2 = *row2.m_val[k];
- CHK(val.verify(val2) == 0);
+ CHK(val1.verify(par, val2) == 0);
}
return 0;
}
@@ -1466,7 +2254,15 @@ Row::insrow(Par par)
CHKCON(con.m_op->insertTuple() == 0, con);
for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k];
- CHK(val.setval(par) == 0);
+ const Col& col = val.m_col;
+ if (col.m_pk)
+ CHK(val.equal(par) == 0);
+ }
+ for (unsigned k = 0; k < tab.m_cols; k++) {
+ const Val& val = *m_val[k];
+ const Col& col = val.m_col;
+ if (! col.m_pk)
+ CHK(val.setval(par) == 0);
}
m_pending = InsOp;
return 0;
@@ -1482,7 +2278,41 @@ Row::updrow(Par par)
CHKCON(con.m_op->updateTuple() == 0, con);
for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k];
- CHK(val.setval(par) == 0);
+ const Col& col = val.m_col;
+ if (col.m_pk)
+ CHK(val.equal(par) == 0);
+ }
+ for (unsigned k = 0; k < tab.m_cols; k++) {
+ const Val& val = *m_val[k];
+ const Col& col = val.m_col;
+ if (! col.m_pk)
+ CHK(val.setval(par) == 0);
+ }
+ m_pending = UpdOp;
+ return 0;
+}
+
+int
+Row::updrow(Par par, const ITab& itab)
+{
+ Con& con = par.con();
+ const Tab& tab = m_tab;
+ assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
+ assert(m_exist);
+ CHK(con.getNdbIndexOperation(itab, tab) == 0);
+ CHKCON(con.m_op->updateTuple() == 0, con);
+ for (unsigned k = 0; k < itab.m_icols; k++) {
+ const ICol& icol = *itab.m_icol[k];
+ const Col& col = icol.m_col;
+ unsigned m = col.m_num;
+ const Val& val = *m_val[m];
+ CHK(val.equal(par, icol) == 0);
+ }
+ for (unsigned k = 0; k < tab.m_cols; k++) {
+ const Val& val = *m_val[k];
+ const Col& col = val.m_col;
+ if (! col.m_pk)
+ CHK(val.setval(par) == 0);
}
m_pending = UpdOp;
return 0;
@@ -1500,7 +2330,27 @@ Row::delrow(Par par)
const Val& val = *m_val[k];
const Col& col = val.m_col;
if (col.m_pk)
- CHK(val.setval(par) == 0);
+ CHK(val.equal(par) == 0);
+ }
+ m_pending = DelOp;
+ return 0;
+}
+
+int
+Row::delrow(Par par, const ITab& itab)
+{
+ Con& con = par.con();
+ const Tab& tab = m_tab;
+ assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
+ assert(m_exist);
+ CHK(con.getNdbIndexOperation(itab, tab) == 0);
+ CHKCON(con.m_op->deleteTuple() == 0, con);
+ for (unsigned k = 0; k < itab.m_icols; k++) {
+ const ICol& icol = *itab.m_icol[k];
+ const Col& col = icol.m_col;
+ unsigned m = col.m_num;
+ const Val& val = *m_val[m];
+ CHK(val.equal(par, icol) == 0);
}
m_pending = DelOp;
return 0;
@@ -1517,7 +2367,25 @@ Row::selrow(Par par)
const Val& val = *m_val[k];
const Col& col = val.m_col;
if (col.m_pk)
- CHK(val.setval(par) == 0);
+ CHK(val.equal(par) == 0);
+ }
+ return 0;
+}
+
+int
+Row::selrow(Par par, const ITab& itab)
+{
+ Con& con = par.con();
+ const Tab& tab = m_tab;
+ assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab);
+ CHK(con.getNdbIndexOperation(itab, tab) == 0);
+ CHKCON(con.m_op->readTuple() == 0, con);
+ for (unsigned k = 0; k < itab.m_icols; k++) {
+ const ICol& icol = *itab.m_icol[k];
+ const Col& col = icol.m_col;
+ unsigned m = col.m_num;
+ const Val& val = *m_val[m];
+ CHK(val.equal(par, icol) == 0);
}
return 0;
}
@@ -1538,7 +2406,7 @@ Row::setrow(Par par)
}
int
-Row::cmp(const Row& row2) const
+Row::cmp(Par par, const Row& row2) const
{
const Tab& tab = m_tab;
assert(&tab == &row2.m_tab);
@@ -1546,13 +2414,47 @@ Row::cmp(const Row& row2) const
for (unsigned k = 0; k < tab.m_cols; k++) {
const Val& val = *m_val[k];
const Val& val2 = *row2.m_val[k];
- if ((c = val.cmp(val2)) != 0)
+ if ((c = val.cmp(par, val2)) != 0)
+ break;
+ }
+ return c;
+}
+
+int
+Row::cmp(Par par, const Row& row2, const ITab& itab) const
+{
+ const Tab& tab = m_tab;
+ int c = 0;
+ for (unsigned i = 0; i < itab.m_icols; i++) {
+ const ICol& icol = *itab.m_icol[i];
+ const Col& col = icol.m_col;
+ unsigned k = col.m_num;
+ assert(k < tab.m_cols);
+ const Val& val = *m_val[k];
+ const Val& val2 = *row2.m_val[k];
+ if ((c = val.cmp(par, val2)) != 0)
break;
}
return c;
}
static NdbOut&
+operator<<(NdbOut& out, const Row::Op op)
+{
+ if (op == Row::NoOp)
+ out << "NoOp";
+ else if (op == Row::InsOp)
+ out << "InsOp";
+ else if (op == Row::UpdOp)
+ out << "UpdOp";
+ else if (op == Row::DelOp)
+ out << "DelOp";
+ else
+ out << op;
+ return out;
+}
+
+static NdbOut&
operator<<(NdbOut& out, const Row& row)
{
const Tab& tab = row.m_tab;
@@ -1561,10 +2463,21 @@ operator<<(NdbOut& out, const Row& row)
out << " ";
out << *row.m_val[i];
}
- out << " [exist=" << row.m_exist;
+ out << " exist=" << row.m_exist;
if (row.m_pending)
out << " pending=" << row.m_pending;
- out << "]";
+ if (row.m_dbrow != 0)
+ out << " [dbrow=" << *row.m_dbrow << "]";
+ return out;
+}
+
+static NdbOut&
+operator<<(NdbOut& out, const Row* rowptr)
+{
+ if (rowptr == 0)
+ out << "null";
+ else
+ out << *rowptr;
return out;
}
@@ -1574,38 +2487,47 @@ struct Set {
const Tab& m_tab;
unsigned m_rows;
Row** m_row;
- Row** m_saverow;
+ unsigned* m_rowkey; // maps row number (from 0) in scan to tuple key
Row* m_keyrow;
NdbRecAttr** m_rec;
Set(const Tab& tab, unsigned rows);
~Set();
void reset();
unsigned count() const;
- // row methods
+ // old and new values
bool exist(unsigned i) const;
- Row::Op pending(unsigned i) const;
+ void dbsave(unsigned i);
+ void calc(Par par, unsigned i, unsigned mask = 0);
+ bool pending(unsigned i, unsigned mask) const;
void notpending(unsigned i, ExecType et = Commit);
void notpending(const Lst& lst, ExecType et = Commit);
- void calc(Par par, unsigned i);
+ void dbdiscard(unsigned i);
+ void dbdiscard(const Lst& lst);
+ const Row& dbrow(unsigned i) const;
+ // operations
int insrow(Par par, unsigned i);
int updrow(Par par, unsigned i);
+ int updrow(Par par, const ITab& itab, unsigned i);
int delrow(Par par, unsigned i);
- int selrow(Par par, unsigned i);
+ int delrow(Par par, const ITab& itab, unsigned i);
+ int selrow(Par par, const Row& keyrow);
+ int selrow(Par par, const ITab& itab, const Row& keyrow);
+ // set and get
+ void setkey(Par par, const Row& keyrow);
+ void setkey(Par par, const ITab& itab, const Row& keyrow);
int setrow(Par par, unsigned i);
int getval(Par par);
int getkey(Par par, unsigned* i);
- int putval(unsigned i, bool force);
- // set methods
- int verify(const Set& set2) const;
- void savepoint();
- void commit();
- void rollback();
+ int putval(unsigned i, bool force, unsigned n = ~0);
+ // verify
+ int verify(Par par, const Set& set2) const;
+ int verifyorder(Par par, const ITab& itab, bool descending) const;
// protect structure
NdbMutex* m_mutex;
- void lock() {
+ void lock() const {
NdbMutex_Lock(m_mutex);
}
- void unlock() {
+ void unlock() const {
NdbMutex_Unlock(m_mutex);
}
private:
@@ -1621,7 +2543,11 @@ Set::Set(const Tab& tab, unsigned rows) :
// allocate on need to save space
m_row[i] = 0;
}
- m_saverow = 0;
+ m_rowkey = new unsigned [m_rows];
+ for (unsigned n = 0; n < m_rows; n++) {
+ // initialize to null
+ m_rowkey[n] = ~0;
+ }
m_keyrow = new Row(tab);
m_rec = new NdbRecAttr* [tab.m_cols];
for (unsigned k = 0; k < tab.m_cols; k++) {
@@ -1635,11 +2561,9 @@ Set::~Set()
{
for (unsigned i = 0; i < m_rows; i++) {
delete m_row[i];
- if (m_saverow != 0)
- delete m_saverow[i];
}
delete [] m_row;
- delete [] m_saverow;
+ delete [] m_rowkey;
delete m_keyrow;
delete [] m_rec;
NdbMutex_Destroy(m_mutex);
@@ -1670,6 +2594,8 @@ Set::count() const
return count;
}
+// old and new values
+
bool
Set::exist(unsigned i) const
{
@@ -1679,27 +2605,97 @@ Set::exist(unsigned i) const
return m_row[i]->m_exist;
}
-Row::Op
-Set::pending(unsigned i) const
+void
+Set::dbsave(unsigned i)
{
- assert(i < m_rows);
- if (m_row[i] == 0) // not allocated => not pending
- return Row::NoOp;
- return m_row[i]->m_pending;
+ const Tab& tab = m_tab;
+ assert(i < m_rows && m_row[i] != 0);
+ Row& row = *m_row[i];
+ LL5("dbsave " << i << ": " << row);
+ assert(row.m_exist && ! row.m_pending && row.m_dbrow == 0);
+ // could swap pointers but making copy is safer
+ Row* rowptr = new Row(tab);
+ rowptr->copy(row);
+ row.m_dbrow = rowptr;
}
void
-Set::calc(Par par, unsigned i)
+Set::calc(Par par, unsigned i, unsigned mask)
{
const Tab& tab = m_tab;
if (m_row[i] == 0)
m_row[i] = new Row(tab);
Row& row = *m_row[i];
- // value generation parameters
- par.m_pctrange = 40;
- row.calc(par, i);
+ row.calc(par, i, mask);
}
+bool
+Set::pending(unsigned i, unsigned mask) const
+{
+ assert(i < m_rows);
+ if (m_row[i] == 0) // not allocated => not pending
+ return Row::NoOp;
+ return m_row[i]->m_pending & mask;
+}
+
+void
+Set::notpending(unsigned i, ExecType et)
+{
+ assert(m_row[i] != 0);
+ Row& row = *m_row[i];
+ if (et == Commit) {
+ if (row.m_pending == Row::InsOp)
+ row.m_exist = true;
+ if (row.m_pending == Row::DelOp)
+ row.m_exist = false;
+ } else {
+ if (row.m_pending == Row::InsOp)
+ row.m_exist = false;
+ if (row.m_pending == Row::DelOp)
+ row.m_exist = true;
+ }
+ row.m_pending = Row::NoOp;
+}
+
+void
+Set::notpending(const Lst& lst, ExecType et)
+{
+ for (unsigned j = 0; j < lst.m_cnt; j++) {
+ unsigned i = lst.m_arr[j];
+ notpending(i, et);
+ }
+}
+
+void
+Set::dbdiscard(unsigned i)
+{
+ assert(m_row[i] != 0);
+ Row& row = *m_row[i];
+ LL5("dbdiscard " << i << ": " << row);
+ assert(row.m_dbrow != 0);
+ delete row.m_dbrow;
+ row.m_dbrow = 0;
+}
+
+const Row&
+Set::dbrow(unsigned i) const
+{
+ assert(m_row[i] != 0);
+ Row& row = *m_row[i];
+ return row.dbrow();
+}
+
+void
+Set::dbdiscard(const Lst& lst)
+{
+ for (unsigned j = 0; j < lst.m_cnt; j++) {
+ unsigned i = lst.m_arr[j];
+ dbdiscard(i);
+ }
+}
+
+// operations
+
int
Set::insrow(Par par, unsigned i)
{
@@ -1719,6 +2715,15 @@ Set::updrow(Par par, unsigned i)
}
int
+Set::updrow(Par par, const ITab& itab, unsigned i)
+{
+ assert(m_row[i] != 0);
+ Row& row = *m_row[i];
+ CHK(row.updrow(par, itab) == 0);
+ return 0;
+}
+
+int
Set::delrow(Par par, unsigned i)
{
assert(m_row[i] != 0);
@@ -1728,16 +2733,68 @@ Set::delrow(Par par, unsigned i)
}
int
-Set::selrow(Par par, unsigned i)
+Set::delrow(Par par, const ITab& itab, unsigned i)
+{
+ assert(m_row[i] != 0);
+ Row& row = *m_row[i];
+ CHK(row.delrow(par, itab) == 0);
+ return 0;
+}
+
+int
+Set::selrow(Par par, const Row& keyrow)
{
Con& con = par.con();
- m_keyrow->calc(par, i);
+ const Tab& tab = par.tab();
+ setkey(par, keyrow);
+ LL5("selrow " << tab.m_name << ": keyrow: " << keyrow);
CHK(m_keyrow->selrow(par) == 0);
CHK(getval(par) == 0);
return 0;
}
int
+Set::selrow(Par par, const ITab& itab, const Row& keyrow)
+{
+ Con& con = par.con();
+ setkey(par, itab, keyrow);
+ LL5("selrow " << itab.m_name << ": keyrow: " << keyrow);
+ CHK(m_keyrow->selrow(par, itab) == 0);
+ CHK(getval(par) == 0);
+ return 0;
+}
+
+// set and get
+
+void
+Set::setkey(Par par, const Row& keyrow)
+{
+ const Tab& tab = m_tab;
+ for (unsigned k = 0; k < tab.m_cols; k++) {
+ const Col& col = *tab.m_col[k];
+ if (col.m_pk) {
+ Val& val1 = *m_keyrow->m_val[k];
+ const Val& val2 = *keyrow.dbrow().m_val[k];
+ val1.copy(val2);
+ }
+ }
+}
+
+void
+Set::setkey(Par par, const ITab& itab, const Row& keyrow)
+{
+ const Tab& tab = m_tab;
+ for (unsigned k = 0; k < itab.m_icols; k++) {
+ const ICol& icol = *itab.m_icol[k];
+ const Col& col = icol.m_col;
+ unsigned m = col.m_num;
+ Val& val1 = *m_keyrow->m_val[m];
+ const Val& val2 = *keyrow.dbrow().m_val[m];
+ val1.copy(val2);
+ }
+}
+
+int
Set::setrow(Par par, unsigned i)
{
Con& con = par.con();
@@ -1760,16 +2817,18 @@ Set::getval(Par par)
int
Set::getkey(Par par, unsigned* i)
{
- assert(m_rec[0] != 0);
- const char* aRef0 = m_rec[0]->aRef();
- Uint32 key = *(const Uint32*)aRef0;
+ const Tab& tab = m_tab;
+ unsigned k = tab.m_keycol;
+ assert(m_rec[k] != 0);
+ const char* aRef = m_rec[k]->aRef();
+ Uint32 key = *(const Uint32*)aRef;
CHK(key < m_rows);
*i = key;
return 0;
}
int
-Set::putval(unsigned i, bool force)
+Set::putval(unsigned i, bool force, unsigned n)
{
const Tab& tab = m_tab;
if (m_row[i] == 0)
@@ -1790,82 +2849,53 @@ Set::putval(unsigned i, bool force)
}
if (! row.m_exist)
row.m_exist = true;
+ if (n != ~0)
+ m_rowkey[n] = i;
return 0;
}
-void
-Set::notpending(unsigned i, ExecType et)
-{
- assert(m_row[i] != 0);
- Row& row = *m_row[i];
- if (et == Commit) {
- if (row.m_pending == Row::InsOp)
- row.m_exist = true;
- if (row.m_pending == Row::DelOp)
- row.m_exist = false;
- } else {
- if (row.m_pending == Row::InsOp)
- row.m_exist = false;
- if (row.m_pending == Row::DelOp)
- row.m_exist = true;
- }
- row.m_pending = Row::NoOp;
-}
-
-void
-Set::notpending(const Lst& lst, ExecType et)
-{
- for (unsigned j = 0; j < lst.m_cnt; j++) {
- unsigned i = lst.m_arr[j];
- notpending(i, et);
- }
-}
-
int
-Set::verify(const Set& set2) const
+Set::verify(Par par, const Set& set2) const
{
- const Tab& tab = m_tab;
- assert(&tab == &set2.m_tab && m_rows == set2.m_rows);
+ assert(&m_tab == &set2.m_tab && m_rows == set2.m_rows);
+ LL4("verify set1 count=" << count() << " vs set2 count=" << set2.count());
for (unsigned i = 0; i < m_rows; i++) {
- CHK(exist(i) == set2.exist(i));
- if (! exist(i))
- continue;
- Row& row = *m_row[i];
- Row& row2 = *set2.m_row[i];
- CHK(row.verify(row2) == 0);
+ bool ok = true;
+ if (exist(i) != set2.exist(i)) {
+ ok = false;
+ } else if (exist(i)) {
+ if (dbrow(i).verify(par, set2.dbrow(i)) != 0)
+ ok = false;
+ }
+ if (! ok) {
+ LL1("verify failed: key=" << i << " row1=" << m_row[i] << " row2=" << set2.m_row[i]);
+ CHK(0 == 1);
+ }
}
return 0;
}
-void
-Set::savepoint()
+int
+Set::verifyorder(Par par, const ITab& itab, bool descending) const
{
const Tab& tab = m_tab;
- assert(m_saverow == 0);
- m_saverow = new Row* [m_rows];
- for (unsigned i = 0; i < m_rows; i++) {
- if (m_row[i] == 0)
- m_saverow[i] = 0;
- else {
- m_saverow[i] = new Row(tab);
- m_saverow[i]->copy(*m_row[i]);
- }
+ for (unsigned n = 0; n < m_rows; n++) {
+ unsigned i2 = m_rowkey[n];
+ if (i2 == ~0)
+ break;
+ if (n == 0)
+ continue;
+ unsigned i1 = m_rowkey[n - 1];
+ assert(i1 < m_rows && i2 < m_rows);
+ const Row& row1 = *m_row[i1];
+ const Row& row2 = *m_row[i2];
+ assert(row1.m_exist && row2.m_exist);
+ if (! descending)
+ CHK(row1.cmp(par, row2, itab) <= 0);
+ else
+ CHK(row1.cmp(par, row2, itab) >= 0);
}
-}
-
-void
-Set::commit()
-{
- delete [] m_saverow;
- m_saverow = 0;
-}
-
-void
-Set::rollback()
-{
- assert(m_saverow != 0);
- m_row = m_saverow;
- m_saverow = 0;
+ return 0;
}
static NdbOut&
@@ -1887,6 +2917,7 @@ struct BVal : public Val {
int m_type;
BVal(const ICol& icol);
int setbnd(Par par) const;
+ int setflt(Par par) const;
};
BVal::BVal(const ICol& icol) :
@@ -1906,16 +2937,37 @@ BVal::setbnd(Par par) const
return 0;
}
+int
+BVal::setflt(Par par) const
+{
+ static unsigned index_bound_to_filter_bound[5] = {
+ NdbScanFilter::COND_GE,
+ NdbScanFilter::COND_GT,
+ NdbScanFilter::COND_LE,
+ NdbScanFilter::COND_LT,
+ NdbScanFilter::COND_EQ
+ };
+ Con& con = par.con();
+ assert(g_compare_null || ! m_null);
+ const char* addr = ! m_null ? (const char*)dataaddr() : 0;
+ const ICol& icol = m_icol;
+ const Col& col = icol.m_col;
+ unsigned length = col.m_bytesize;
+ unsigned cond = index_bound_to_filter_bound[m_type];
+ CHK(con.setFilter(col.m_num, cond, addr, length) == 0);
+ return 0;
+}
+
static NdbOut&
operator<<(NdbOut& out, const BVal& bval)
{
const ICol& icol = bval.m_icol;
const Col& col = icol.m_col;
const Val& val = bval;
- out << "type " << bval.m_type;
- out << " icol " << icol.m_num;
- out << " col " << col.m_name << "(" << col.m_num << ")";
- out << " value " << val;
+ out << "type=" << bval.m_type;
+ out << " icol=" << icol.m_num;
+ out << " col=" << col.m_num << "," << col.m_name;
+ out << " value=" << val;
return out;
}
@@ -1933,7 +2985,8 @@ struct BSet {
void calc(Par par);
void calcpk(Par par, unsigned i);
int setbnd(Par par) const;
- void filter(const Set& set, Set& set2) const;
+ int setflt(Par par) const;
+ void filter(Par par, const Set& set, Set& set2) const;
};
BSet::BSet(const Tab& tab, const ITab& itab, unsigned rows) :
@@ -1967,12 +3020,15 @@ void
BSet::calc(Par par)
{
const ITab& itab = m_itab;
+ par.m_pctrange = par.m_pctbrange;
reset();
for (unsigned k = 0; k < itab.m_icols; k++) {
- const ICol& icol = itab.m_icol[k];
+ const ICol& icol = *itab.m_icol[k];
const Col& col = icol.m_col;
for (unsigned i = 0; i <= 1; i++) {
- if (urandom(10) == 0)
+ if (m_bvals == 0 && urandom(100) == 0)
+ return;
+ if (m_bvals != 0 && urandom(3) == 0)
return;
assert(m_bvals < m_alloc);
BVal& bval = *new BVal(icol);
@@ -1991,17 +3047,19 @@ BSet::calc(Par par)
bval.m_type = 4;
if (k + 1 < itab.m_icols)
bval.m_type = 4;
- // value generation parammeters
if (! g_compare_null)
par.m_pctnull = 0;
- par.m_pctrange = 50; // bit higher
+ if (bval.m_type == 0 || bval.m_type == 1)
+ par.m_bdir = -1;
+ if (bval.m_type == 2 || bval.m_type == 3)
+ par.m_bdir = +1;
do {
- bval.calc(par, 0);
+ bval.calcnokey(par);
if (i == 1) {
assert(m_bvals >= 2);
const BVal& bv1 = *m_bval[m_bvals - 2];
const BVal& bv2 = *m_bval[m_bvals - 1];
- if (bv1.cmp(bv2) > 0 && urandom(100) != 0)
+ if (bv1.cmp(par, bv2) > 0 && urandom(100) != 0)
continue;
}
} while (0);
@@ -2018,7 +3076,7 @@ BSet::calcpk(Par par, unsigned i)
const ITab& itab = m_itab;
reset();
for (unsigned k = 0; k < itab.m_icols; k++) {
- const ICol& icol = itab.m_icol[k];
+ const ICol& icol = *itab.m_icol[k];
const Col& col = icol.m_col;
assert(col.m_pk);
assert(m_bvals < m_alloc);
@@ -2051,8 +3109,35 @@ BSet::setbnd(Par par) const
return 0;
}
+int
+BSet::setflt(Par par) const
+{
+ Con& con = par.con();
+ 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];
+ CHK(bval.setflt(par) == 0);
+ }
+ // duplicate
+ if (urandom(5) == 0) {
+ unsigned k = urandom(m_bvals);
+ const BVal& bval = *m_bval[k];
+ CHK(bval.setflt(par) == 0);
+ }
+ }
+ CHK(con.endFilter() == 0);
+ return 0;
+}
+
void
-BSet::filter(const Set& set, Set& set2) const
+BSet::filter(Par par, const Set& set, Set& set2) const
{
const Tab& tab = m_tab;
const ITab& itab = m_itab;
@@ -2061,11 +3146,13 @@ BSet::filter(const Set& set, Set& set2) const
for (unsigned i = 0; i < set.m_rows; i++) {
if (! set.exist(i))
continue;
- const Row& row = *set.m_row[i];
+ set.lock();
+ const Row& row = set.dbrow(i);
+ set.unlock();
if (! g_store_null_key) {
bool ok1 = false;
for (unsigned k = 0; k < itab.m_icols; k++) {
- const ICol& icol = itab.m_icol[k];
+ const ICol& icol = *itab.m_icol[k];
const Col& col = icol.m_col;
const Val& val = *row.m_val[col.m_num];
if (! val.m_null) {
@@ -2082,7 +3169,8 @@ BSet::filter(const Set& set, Set& set2) const
const ICol& icol = bval.m_icol;
const Col& col = icol.m_col;
const Val& val = *row.m_val[col.m_num];
- int ret = bval.cmp(val);
+ int ret = bval.cmp(par, val);
+ LL5("cmp: ret=" << ret << " " << bval << " vs " << val);
if (bval.m_type == 0)
ok2 = (ret <= 0);
else if (bval.m_type == 1)
@@ -2106,7 +3194,6 @@ BSet::filter(const Set& set, Set& set2) const
Row& row2 = *set2.m_row[i];
assert(! row2.m_exist);
row2.copy(row);
- row2.m_exist = true;
}
}
@@ -2115,9 +3202,8 @@ operator<<(NdbOut& out, const BSet& bset)
{
out << "bounds=" << bset.m_bvals;
for (unsigned j = 0; j < bset.m_bvals; j++) {
- out << endl;
const BVal& bval = *bset.m_bval[j];
- out << "bound " << j << ": " << bval;
+ out << " [bound " << j << ": " << bval << "]";
}
return out;
}
@@ -2128,15 +3214,16 @@ static int
pkinsert(Par par)
{
Con& con = par.con();
+ const Tab& tab = par.tab();
Set& set = par.set();
- LL3("pkinsert");
+ LL3("pkinsert " << tab.m_name);
CHK(con.startTransaction() == 0);
Lst lst;
for (unsigned j = 0; j < par.m_rows; j++) {
unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
unsigned i = thrrow(par, j2);
set.lock();
- if (set.exist(i) || set.pending(i)) {
+ if (set.exist(i) || set.pending(i, Row::AnyOp)) {
set.unlock();
continue;
}
@@ -2152,7 +3239,7 @@ pkinsert(Par par)
CHK(con.execute(et, deadlock, nospace) == 0);
con.closeTransaction();
if (deadlock) {
- LL1("pkinsert: stop on deadlock");
+ LL1("pkinsert: stop on deadlock [at 1]");
return 0;
}
if (nospace) {
@@ -2173,7 +3260,7 @@ pkinsert(Par par)
CHK(con.execute(et, deadlock, nospace) == 0);
con.closeTransaction();
if (deadlock) {
- LL1("pkinsert: stop on deadlock");
+ LL1("pkinsert: stop on deadlock [at 2]");
return 0;
}
if (nospace) {
@@ -2187,14 +3274,15 @@ pkinsert(Par par)
}
con.closeTransaction();
return 0;
-};
+}
static int
pkupdate(Par par)
{
Con& con = par.con();
+ const Tab& tab = par.tab();
Set& set = par.set();
- LL3("pkupdate");
+ LL3("pkupdate " << tab.m_name);
CHK(con.startTransaction() == 0);
Lst lst;
bool deadlock = false;
@@ -2203,10 +3291,11 @@ pkupdate(Par par)
unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
unsigned i = thrrow(par, j2);
set.lock();
- if (! set.exist(i) || set.pending(i)) {
+ if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
set.unlock();
continue;
}
+ set.dbsave(i);
set.calc(par, i);
CHK(set.updrow(par, i) == 0);
set.unlock();
@@ -2218,16 +3307,17 @@ pkupdate(Par par)
ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
CHK(con.execute(et, deadlock, nospace) == 0);
if (deadlock) {
- LL1("pkupdate: stop on deadlock");
+ LL1("pkupdate: stop on deadlock [at 1]");
break;
}
if (nospace) {
- LL1("pkupdate: cnt=" << j << " stop on nospace");
+ LL1("pkupdate: cnt=" << j << " stop on nospace [at 1]");
break;
}
con.closeTransaction();
set.lock();
set.notpending(lst, et);
+ set.dbdiscard(lst);
set.unlock();
lst.reset();
CHK(con.startTransaction() == 0);
@@ -2239,25 +3329,27 @@ pkupdate(Par par)
ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
CHK(con.execute(et, deadlock, nospace) == 0);
if (deadlock) {
- LL1("pkupdate: stop on deadlock");
+ LL1("pkupdate: stop on deadlock [at 2]");
} else if (nospace) {
- LL1("pkupdate: end: stop on nospace");
+ LL1("pkupdate: end: stop on nospace [at 2]");
} else {
set.lock();
set.notpending(lst, et);
+ set.dbdiscard(lst);
set.unlock();
}
}
con.closeTransaction();
return 0;
-};
+}
static int
pkdelete(Par par)
{
Con& con = par.con();
+ const Tab& tab = par.tab();
Set& set = par.set();
- LL3("pkdelete");
+ LL3("pkdelete " << tab.m_name);
CHK(con.startTransaction() == 0);
Lst lst;
bool deadlock = false;
@@ -2266,7 +3358,7 @@ pkdelete(Par par)
unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
unsigned i = thrrow(par, j2);
set.lock();
- if (! set.exist(i) || set.pending(i)) {
+ if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
set.unlock();
continue;
}
@@ -2280,7 +3372,7 @@ pkdelete(Par par)
ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
CHK(con.execute(et, deadlock, nospace) == 0);
if (deadlock) {
- LL1("pkdelete: stop on deadlock");
+ LL1("pkdelete: stop on deadlock [at 1]");
break;
}
con.closeTransaction();
@@ -2297,7 +3389,7 @@ pkdelete(Par par)
ExecType et = randompct(par.m_abortpct) ? Rollback : Commit;
CHK(con.execute(et, deadlock, nospace) == 0);
if (deadlock) {
- LL1("pkdelete: stop on deadlock");
+ LL1("pkdelete: stop on deadlock [at 2]");
} else {
set.lock();
set.notpending(lst, et);
@@ -2306,7 +3398,7 @@ pkdelete(Par par)
}
con.closeTransaction();
return 0;
-};
+}
static int
pkread(Par par)
@@ -2314,19 +3406,19 @@ pkread(Par par)
Con& con = par.con();
const Tab& tab = par.tab();
Set& set = par.set();
- LL3((par.m_verify ? "pkverify " : "pkread ") << tab.m_name);
+ LL3("pkread " << tab.m_name << " verify=" << par.m_verify);
// expected
const Set& set1 = set;
Set set2(tab, set.m_rows);
for (unsigned i = 0; i < set.m_rows; i++) {
set.lock();
- if (! set.exist(i) || set.pending(i)) {
+ if (! set.exist(i)) {
set.unlock();
continue;
}
set.unlock();
CHK(con.startTransaction() == 0);
- CHK(set2.selrow(par, i) == 0);
+ CHK(set2.selrow(par, *set1.m_row[i]) == 0);
CHK(con.execute(Commit) == 0);
unsigned i2 = (unsigned)-1;
CHK(set2.getkey(par, &i2) == 0 && i == i2);
@@ -2335,7 +3427,7 @@ pkread(Par par)
con.closeTransaction();
}
if (par.m_verify)
- CHK(set1.verify(set2) == 0);
+ CHK(set1.verify(par, set2) == 0);
return 0;
}
@@ -2364,6 +3456,148 @@ pkreadfast(Par par, unsigned count)
return 0;
}
+// hash index operations
+
+static int
+hashindexupdate(Par par, const ITab& itab)
+{
+ Con& con = par.con();
+ Set& set = par.set();
+ LL3("hashindexupdate " << itab.m_name);
+ CHK(con.startTransaction() == 0);
+ Lst lst;
+ bool deadlock = false;
+ bool nospace = false;
+ for (unsigned j = 0; j < par.m_rows; j++) {
+ unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
+ unsigned i = thrrow(par, j2);
+ set.lock();
+ if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
+ set.unlock();
+ continue;
+ }
+ set.dbsave(i);
+ // index key columns are not re-calculated
+ set.calc(par, i, itab.m_colmask);
+ CHK(set.updrow(par, itab, i) == 0);
+ set.unlock();
+ LL4("hashindexupdate " << i << ": " << *set.m_row[i]);
+ lst.push(i);
+ if (lst.cnt() == par.m_batch) {
+ deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock, nospace) == 0);
+ if (deadlock) {
+ LL1("hashindexupdate: stop on deadlock [at 1]");
+ break;
+ }
+ con.closeTransaction();
+ set.lock();
+ set.notpending(lst);
+ set.dbdiscard(lst);
+ set.unlock();
+ lst.reset();
+ CHK(con.startTransaction() == 0);
+ }
+ }
+ if (! deadlock && lst.cnt() != 0) {
+ deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock, nospace) == 0);
+ if (deadlock) {
+ LL1("hashindexupdate: stop on deadlock [at 2]");
+ } else {
+ set.lock();
+ set.notpending(lst);
+ set.dbdiscard(lst);
+ set.unlock();
+ }
+ }
+ con.closeTransaction();
+ return 0;
+}
+
+static int
+hashindexdelete(Par par, const ITab& itab)
+{
+ Con& con = par.con();
+ Set& set = par.set();
+ LL3("hashindexdelete " << itab.m_name);
+ CHK(con.startTransaction() == 0);
+ Lst lst;
+ bool deadlock = false;
+ bool nospace = false;
+ for (unsigned j = 0; j < par.m_rows; j++) {
+ unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows);
+ unsigned i = thrrow(par, j2);
+ set.lock();
+ if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
+ set.unlock();
+ continue;
+ }
+ CHK(set.delrow(par, itab, i) == 0);
+ set.unlock();
+ LL4("hashindexdelete " << i << ": " << *set.m_row[i]);
+ lst.push(i);
+ if (lst.cnt() == par.m_batch) {
+ deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock, nospace) == 0);
+ if (deadlock) {
+ LL1("hashindexdelete: stop on deadlock [at 1]");
+ break;
+ }
+ con.closeTransaction();
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ lst.reset();
+ CHK(con.startTransaction() == 0);
+ }
+ }
+ if (! deadlock && lst.cnt() != 0) {
+ deadlock = par.m_deadlock;
+ CHK(con.execute(Commit, deadlock, nospace) == 0);
+ if (deadlock) {
+ LL1("hashindexdelete: stop on deadlock [at 2]");
+ } else {
+ set.lock();
+ set.notpending(lst);
+ set.unlock();
+ }
+ }
+ con.closeTransaction();
+ return 0;
+}
+
+static int
+hashindexread(Par par, const ITab& itab)
+{
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ Set& set = par.set();
+ LL3("hashindexread " << itab.m_name << " verify=" << par.m_verify);
+ // expected
+ const Set& set1 = set;
+ Set set2(tab, set.m_rows);
+ for (unsigned i = 0; i < set.m_rows; i++) {
+ set.lock();
+ if (! set.exist(i)) {
+ set.unlock();
+ continue;
+ }
+ set.unlock();
+ CHK(con.startTransaction() == 0);
+ CHK(set2.selrow(par, itab, *set1.m_row[i]) == 0);
+ CHK(con.execute(Commit) == 0);
+ unsigned i2 = (unsigned)-1;
+ CHK(set2.getkey(par, &i2) == 0 && i == i2);
+ CHK(set2.putval(i, false) == 0);
+ LL4("row " << set2.count() << ": " << *set2.m_row[i]);
+ con.closeTransaction();
+ }
+ if (par.m_verify)
+ CHK(set1.verify(par, set2) == 0);
+ return 0;
+}
+
// scan read
static int
@@ -2374,26 +3608,35 @@ scanreadtable(Par par)
const Set& set = par.set();
// expected
const Set& set1 = set;
- LL3((par.m_verify ? "scanverify " : "scanread ") << tab.m_name);
+ LL3("scanread " << tab.m_name << " lockmode=" << par.m_lockmode << " expect=" << set1.count() << " verify=" << par.m_verify);
Set set2(tab, set.m_rows);
CHK(con.startTransaction() == 0);
CHK(con.getNdbScanOperation(tab) == 0);
- CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0);
+ CHK(con.readTuples(par) == 0);
set2.getval(par);
CHK(con.executeScan() == 0);
+ unsigned n = 0;
+ bool deadlock = false;
while (1) {
int ret;
- CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
+ deadlock = par.m_deadlock;
+ CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
if (ret == 1)
break;
+ if (deadlock) {
+ LL1("scanreadtable: stop on deadlock");
+ break;
+ }
unsigned i = (unsigned)-1;
CHK(set2.getkey(par, &i) == 0);
- CHK(set2.putval(i, false) == 0);
- LL4("row " << set2.count() << ": " << *set2.m_row[i]);
+ CHK(set2.putval(i, false, n) == 0);
+ LL4("row " << n << ": " << *set2.m_row[i]);
+ n++;
}
con.closeTransaction();
if (par.m_verify)
- CHK(set1.verify(set2) == 0);
+ CHK(set1.verify(par, set2) == 0);
+ LL3("scanread " << tab.m_name << " done rows=" << n);
return 0;
}
@@ -2406,7 +3649,7 @@ scanreadtablefast(Par par, unsigned countcheck)
LL3("scanfast " << tab.m_name);
CHK(con.startTransaction() == 0);
CHK(con.getNdbScanOperation(tab) == 0);
- CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0);
+ CHK(con.readTuples(par) == 0);
// get 1st column
NdbRecAttr* rec;
CHK(con.getValue((Uint32)0, rec) == 0);
@@ -2425,37 +3668,60 @@ scanreadtablefast(Par par, unsigned countcheck)
}
static int
-scanreadindex(Par par, const ITab& itab, const BSet& bset)
+scanreadindex(Par par, const ITab& itab, BSet& bset, bool calc)
{
Con& con = par.con();
const Tab& tab = par.tab();
const Set& set = par.set();
- // expected
Set set1(tab, set.m_rows);
- bset.filter(set, set1);
- LL3((par.m_verify ? "scanverify " : "scanread ") << itab.m_name << " bounds=" << bset.m_bvals);
- LL4(bset);
+ if (calc) {
+ while (true) {
+ bset.calc(par);
+ bset.filter(par, set, set1);
+ unsigned n = set1.count();
+ // prefer proper subset
+ if (0 < n && n < set.m_rows)
+ break;
+ if (urandom(3) == 0)
+ break;
+ set1.reset();
+ }
+ } else {
+ bset.filter(par, set, set1);
+ }
+ LL3("scanread " << itab.m_name << " " << bset << " lockmode=" << par.m_lockmode << " expect=" << set1.count() << " verify=" << par.m_verify << " ordered=" << par.m_ordered << " descending=" << par.m_descending);
Set set2(tab, set.m_rows);
CHK(con.startTransaction() == 0);
- CHK(con.getNdbScanOperation(itab, tab) == 0);
- CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0);
+ CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
+ CHK(con.readIndexTuples(par) == 0);
CHK(bset.setbnd(par) == 0);
set2.getval(par);
CHK(con.executeScan() == 0);
+ unsigned n = 0;
+ bool deadlock = false;
while (1) {
int ret;
- CHK((ret = con.nextScanResult(true)) == 0 || ret == 1);
+ deadlock = par.m_deadlock;
+ CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
if (ret == 1)
break;
+ if (deadlock) {
+ LL1("scanreadindex: stop on deadlock");
+ break;
+ }
unsigned i = (unsigned)-1;
CHK(set2.getkey(par, &i) == 0);
- LL4("key " << i);
- CHK(set2.putval(i, par.m_dups) == 0);
- LL4("row " << set2.count() << ": " << *set2.m_row[i]);
+ CHK(set2.putval(i, par.m_dups, n) == 0);
+ LL4("key " << i << " row " << n << ": " << *set2.m_row[i]);
+ n++;
}
con.closeTransaction();
- if (par.m_verify)
- CHK(set1.verify(set2) == 0);
+ if (par.m_verify) {
+ CHK(set1.verify(par, set2) == 0);
+ if (par.m_ordered)
+ CHK(set2.verifyorder(par, itab, par.m_descending) == 0);
+ }
+ LL3("scanread " << itab.m_name << " done rows=" << n);
return 0;
}
@@ -2465,11 +3731,11 @@ scanreadindexfast(Par par, const ITab& itab, const BSet& bset, unsigned countche
Con& con = par.con();
const Tab& tab = par.tab();
const Set& set = par.set();
- LL3("scanfast " << itab.m_name << " bounds=" << bset.m_bvals);
+ LL3("scanfast " << itab.m_name << " " << bset);
LL4(bset);
CHK(con.startTransaction() == 0);
- CHK(con.getNdbScanOperation(itab, tab) == 0);
- CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0);
+ CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
+ CHK(con.readIndexTuples(par) == 0);
CHK(bset.setbnd(par) == 0);
// get 1st column
NdbRecAttr* rec;
@@ -2489,13 +3755,71 @@ scanreadindexfast(Par par, const ITab& itab, const BSet& bset, unsigned countche
}
static int
+scanreadfilter(Par par, const ITab& itab, BSet& bset, bool calc)
+{
+ Con& con = par.con();
+ const Tab& tab = par.tab();
+ const Set& set = par.set();
+ Set set1(tab, set.m_rows);
+ if (calc) {
+ while (true) {
+ bset.calc(par);
+ bset.filter(par, set, set1);
+ unsigned n = set1.count();
+ // prefer proper subset
+ if (0 < n && n < set.m_rows)
+ break;
+ if (urandom(3) == 0)
+ break;
+ set1.reset();
+ }
+ } else {
+ bset.filter(par, set, set1);
+ }
+ LL3("scanfilter " << itab.m_name << " " << bset << " lockmode=" << par.m_lockmode << " expect=" << set1.count() << " verify=" << par.m_verify);
+ Set set2(tab, set.m_rows);
+ CHK(con.startTransaction() == 0);
+ CHK(con.getNdbScanOperation(tab) == 0);
+ CHK(con.readTuples(par) == 0);
+ CHK(bset.setflt(par) == 0);
+ set2.getval(par);
+ CHK(con.executeScan() == 0);
+ unsigned n = 0;
+ bool deadlock = false;
+ while (1) {
+ int ret;
+ deadlock = par.m_deadlock;
+ CHK((ret = con.nextScanResult(true, deadlock)) == 0 || ret == 1);
+ if (ret == 1)
+ break;
+ if (deadlock) {
+ LL1("scanfilter: stop on deadlock");
+ break;
+ }
+ unsigned i = (unsigned)-1;
+ CHK(set2.getkey(par, &i) == 0);
+ CHK(set2.putval(i, par.m_dups, n) == 0);
+ LL4("key " << i << " row " << n << ": " << *set2.m_row[i]);
+ n++;
+ }
+ con.closeTransaction();
+ if (par.m_verify) {
+ CHK(set1.verify(par, set2) == 0);
+ }
+ LL3("scanfilter " << itab.m_name << " done rows=" << n);
+ return 0;
+}
+
+static int
scanreadindex(Par par, const ITab& itab)
{
const Tab& tab = par.tab();
for (unsigned i = 0; i < par.m_subsubloop; i++) {
- BSet bset(tab, itab, par.m_rows);
- bset.calc(par);
- CHK(scanreadindex(par, itab, bset) == 0);
+ if (itab.m_type == ITab::OrderedIndex) {
+ BSet bset(tab, itab, par.m_rows);
+ CHK(scanreadfilter(par, itab, bset, true) == 0);
+ CHK(scanreadindex(par, itab, bset, true) == 0);
+ }
}
return 0;
}
@@ -2505,10 +3829,14 @@ scanreadindex(Par par)
{
const Tab& tab = par.tab();
for (unsigned i = 0; i < tab.m_itabs; i++) {
- if (! useindex(i))
+ if (tab.m_itab[i] == 0)
continue;
- const ITab& itab = tab.m_itab[i];
- CHK(scanreadindex(par, itab) == 0);
+ const ITab& itab = *tab.m_itab[i];
+ if (itab.m_type == ITab::OrderedIndex) {
+ CHK(scanreadindex(par, itab) == 0);
+ } else {
+ CHK(hashindexread(par, itab) == 0);
+ }
}
return 0;
}
@@ -2516,8 +3844,7 @@ scanreadindex(Par par)
static int
scanreadall(Par par)
{
- if (par.m_no < 11)
- CHK(scanreadtable(par) == 0);
+ CHK(scanreadtable(par) == 0);
CHK(scanreadindex(par) == 0);
return 0;
}
@@ -2537,7 +3864,7 @@ static int
timescanpkindex(Par par)
{
const Tab& tab = par.tab();
- const ITab& itab = tab.m_itab[0]; // 1st index is on PK
+ const ITab& itab = *tab.m_itab[0]; // 1st index is on PK
BSet bset(tab, itab, par.m_rows);
par.tmr().on();
CHK(scanreadindexfast(par, itab, bset, par.m_totrows) == 0);
@@ -2561,7 +3888,7 @@ static int
timepkreadindex(Par par)
{
const Tab& tab = par.tab();
- const ITab& itab = tab.m_itab[0]; // 1st index is on PK
+ const ITab& itab = *tab.m_itab[0]; // 1st index is on PK
BSet bset(tab, itab, par.m_rows);
unsigned count = par.m_samples;
if (count == 0)
@@ -2586,9 +3913,10 @@ scanupdatetable(Par par)
Set& set = par.set();
LL3("scan update " << tab.m_name);
Set set2(tab, set.m_rows);
+ par.m_lockmode = NdbOperation::LM_Exclusive;
CHK(con.startTransaction() == 0);
CHK(con.getNdbScanOperation(tab) == 0);
- CHK(con.openScanExclusive(par.m_scanbat, par.m_scanpar) == 0);
+ CHK(con.readTuples(par) == 0);
set2.getval(par);
CHK(con.executeScan() == 0);
unsigned count = 0;
@@ -2598,6 +3926,7 @@ scanupdatetable(Par par)
CHK(con2.startTransaction() == 0);
Lst lst;
bool deadlock = false;
+ bool nospace = false;
while (1) {
int ret;
deadlock = par.m_deadlock;
@@ -2605,7 +3934,7 @@ scanupdatetable(Par par)
if (ret == 1)
break;
if (deadlock) {
- LL1("scanupdatetable: stop on deadlock");
+ LL1("scanupdatetable: stop on deadlock [at 1]");
break;
}
if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
@@ -2617,13 +3946,14 @@ scanupdatetable(Par par)
CHK(set2.getkey(par, &i) == 0);
const Row& row = *set.m_row[i];
set.lock();
- if (! set.exist(i) || set.pending(i)) {
+ if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
LL4("scan update " << tab.m_name << ": skip: " << row);
} else {
CHKTRY(set2.putval(i, false) == 0, set.unlock());
CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
Par par2 = par;
par2.m_con = &con2;
+ set.dbsave(i);
set.calc(par, i);
CHKTRY(set.setrow(par2, i) == 0, set.unlock());
LL4("scan update " << tab.m_name << ": " << row);
@@ -2631,10 +3961,16 @@ scanupdatetable(Par par)
}
set.unlock();
if (lst.cnt() == par.m_batch) {
- CHK(con2.execute(Commit) == 0);
+ deadlock = par.m_deadlock;
+ CHK(con2.execute(Commit, deadlock, nospace) == 0);
+ if (deadlock) {
+ LL1("scanupdatetable: stop on deadlock [at 2]");
+ goto out;
+ }
con2.closeTransaction();
set.lock();
set.notpending(lst);
+ set.dbdiscard(lst);
set.unlock();
count += lst.cnt();
lst.reset();
@@ -2642,10 +3978,16 @@ scanupdatetable(Par par)
}
CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2);
if (ret == 2 && lst.cnt() != 0) {
- CHK(con2.execute(Commit) == 0);
+ deadlock = par.m_deadlock;
+ CHK(con2.execute(Commit, deadlock, nospace) == 0);
+ if (deadlock) {
+ LL1("scanupdatetable: stop on deadlock [at 3]");
+ goto out;
+ }
con2.closeTransaction();
set.lock();
set.notpending(lst);
+ set.dbdiscard(lst);
set.unlock();
count += lst.cnt();
lst.reset();
@@ -2655,6 +3997,7 @@ scanupdatetable(Par par)
if (ret == 1)
break;
}
+out:
con2.closeTransaction();
LL3("scan update " << tab.m_name << " rows updated=" << count);
con.closeTransaction();
@@ -2669,9 +4012,10 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
Set& set = par.set();
LL3("scan update " << itab.m_name);
Set set2(tab, set.m_rows);
+ par.m_lockmode = NdbOperation::LM_Exclusive;
CHK(con.startTransaction() == 0);
- CHK(con.getNdbScanOperation(itab, tab) == 0);
- CHK(con.openScanExclusive(par.m_scanbat, par.m_scanpar) == 0);
+ CHK(con.getNdbIndexScanOperation(itab, tab) == 0);
+ CHK(con.readTuples(par) == 0);
CHK(bset.setbnd(par) == 0);
set2.getval(par);
CHK(con.executeScan() == 0);
@@ -2682,6 +4026,7 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
CHK(con2.startTransaction() == 0);
Lst lst;
bool deadlock = false;
+ bool nospace = false;
while (1) {
int ret;
deadlock = par.m_deadlock;
@@ -2689,7 +4034,7 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
if (ret == 1)
break;
if (deadlock) {
- LL1("scanupdateindex: stop on deadlock");
+ LL1("scanupdateindex: stop on deadlock [at 1]");
break;
}
if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) {
@@ -2701,13 +4046,14 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
CHK(set2.getkey(par, &i) == 0);
const Row& row = *set.m_row[i];
set.lock();
- if (! set.exist(i) || set.pending(i)) {
+ if (! set.exist(i) || set.pending(i, Row::AnyOp)) {
LL4("scan update " << itab.m_name << ": skip: " << row);
} else {
CHKTRY(set2.putval(i, par.m_dups) == 0, set.unlock());
CHKTRY(con.updateScanTuple(con2) == 0, set.unlock());
Par par2 = par;
par2.m_con = &con2;
+ set.dbsave(i);
set.calc(par, i);
CHKTRY(set.setrow(par2, i) == 0, set.unlock());
LL4("scan update " << itab.m_name << ": " << row);
@@ -2715,10 +4061,16 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
}
set.unlock();
if (lst.cnt() == par.m_batch) {
- CHK(con2.execute(Commit) == 0);
+ deadlock = par.m_deadlock;
+ CHK(con2.execute(Commit, deadlock, nospace) == 0);
+ if (deadlock) {
+ LL1("scanupdateindex: stop on deadlock [at 2]");
+ goto out;
+ }
con2.closeTransaction();
set.lock();
set.notpending(lst);
+ set.dbdiscard(lst);
set.unlock();
count += lst.cnt();
lst.reset();
@@ -2726,10 +4078,16 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
}
CHK((ret = con.nextScanResult(false)) == 0 || ret == 1 || ret == 2);
if (ret == 2 && lst.cnt() != 0) {
- CHK(con2.execute(Commit) == 0);
+ deadlock = par.m_deadlock;
+ CHK(con2.execute(Commit, deadlock, nospace) == 0);
+ if (deadlock) {
+ LL1("scanupdateindex: stop on deadlock [at 3]");
+ goto out;
+ }
con2.closeTransaction();
set.lock();
set.notpending(lst);
+ set.dbdiscard(lst);
set.unlock();
count += lst.cnt();
lst.reset();
@@ -2737,6 +4095,7 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset)
}
} while (ret == 0);
}
+out:
con2.closeTransaction();
LL3("scan update " << itab.m_name << " rows updated=" << count);
con.closeTransaction();
@@ -2748,9 +4107,13 @@ scanupdateindex(Par par, const ITab& itab)
{
const Tab& tab = par.tab();
for (unsigned i = 0; i < par.m_subsubloop; i++) {
- BSet bset(tab, itab, par.m_rows);
- bset.calc(par);
- CHK(scanupdateindex(par, itab, bset) == 0);
+ if (itab.m_type == ITab::OrderedIndex) {
+ BSet bset(tab, itab, par.m_rows);
+ bset.calc(par);
+ CHK(scanupdateindex(par, itab, bset) == 0);
+ } else {
+ CHK(hashindexupdate(par, itab) == 0);
+ }
}
return 0;
}
@@ -2760,9 +4123,9 @@ scanupdateindex(Par par)
{
const Tab& tab = par.tab();
for (unsigned i = 0; i < tab.m_itabs; i++) {
- if (! useindex(i))
+ if (tab.m_itab[i] == 0)
continue;
- const ITab& itab = tab.m_itab[i];
+ const ITab& itab = *tab.m_itab[i];
CHK(scanupdateindex(par, itab) == 0);
}
return 0;
@@ -2788,6 +4151,7 @@ readverify(Par par)
LL2("skip verify in this version"); // implement in 5.0 version
par.m_verify = false;
}
+ par.m_lockmode = NdbOperation::LM_CommittedRead;
CHK(pkread(par) == 0);
CHK(scanreadall(par) == 0);
return 0;
@@ -2799,43 +4163,102 @@ readverifyfull(Par par)
if (par.m_noverify)
return 0;
par.m_verify = true;
- if (par.m_no == 0)
+ if (par.m_abortpct != 0) {
+ LL2("skip verify in this version"); // implement in 5.0 version
+ par.m_verify = false;
+ }
+ par.m_lockmode = NdbOperation::LM_CommittedRead;
+ const Tab& tab = par.tab();
+ if (par.m_no == 0) {
+ // thread 0 scans table
CHK(scanreadtable(par) == 0);
- else {
- const Tab& tab = par.tab();
- unsigned i = par.m_no;
- if (i <= tab.m_itabs && useindex(i)) {
- const ITab& itab = tab.m_itab[i - 1];
+ }
+ // each thread scans different indexes
+ for (unsigned i = 0; i < tab.m_itabs; i++) {
+ if (i % par.m_threads != par.m_no)
+ continue;
+ if (tab.m_itab[i] == 0)
+ continue;
+ const ITab& itab = *tab.m_itab[i];
+ if (itab.m_type == ITab::OrderedIndex) {
BSet bset(tab, itab, par.m_rows);
- CHK(scanreadindex(par, itab, bset) == 0);
+ CHK(scanreadindex(par, itab, bset, false) == 0);
+ } else {
+ CHK(hashindexread(par, itab) == 0);
}
}
return 0;
}
static int
+readverifyindex(Par par)
+{
+ if (par.m_noverify)
+ return 0;
+ par.m_verify = true;
+ par.m_lockmode = NdbOperation::LM_CommittedRead;
+ unsigned sel = urandom(10);
+ if (sel < 9) {
+ par.m_ordered = true;
+ par.m_descending = (sel < 5);
+ }
+ CHK(scanreadindex(par) == 0);
+ return 0;
+}
+
+static int
pkops(Par par)
{
+ const Tab& tab = par.tab();
par.m_randomkey = true;
for (unsigned i = 0; i < par.m_subsubloop; i++) {
+ unsigned j = 0;
+ while (j < tab.m_itabs) {
+ if (tab.m_itab[j] != 0) {
+ const ITab& itab = *tab.m_itab[j];
+ if (itab.m_type == ITab::UniqueHashIndex && urandom(5) == 0)
+ break;
+ }
+ j++;
+ }
unsigned sel = urandom(10);
if (par.m_slno % 2 == 0) {
// favor insert
if (sel < 8) {
CHK(pkinsert(par) == 0);
} else if (sel < 9) {
- CHK(pkupdate(par) == 0);
+ if (j == tab.m_itabs)
+ CHK(pkupdate(par) == 0);
+ else {
+ const ITab& itab = *tab.m_itab[j];
+ CHK(hashindexupdate(par, itab) == 0);
+ }
} else {
- CHK(pkdelete(par) == 0);
+ if (j == tab.m_itabs)
+ CHK(pkdelete(par) == 0);
+ else {
+ const ITab& itab = *tab.m_itab[j];
+ CHK(hashindexdelete(par, itab) == 0);
+ }
}
} else {
// favor delete
if (sel < 1) {
CHK(pkinsert(par) == 0);
} else if (sel < 2) {
- CHK(pkupdate(par) == 0);
+ if (j == tab.m_itabs)
+ CHK(pkupdate(par) == 0);
+ else {
+ const ITab& itab = *tab.m_itab[j];
+ CHK(hashindexupdate(par, itab) == 0);
+ }
} else {
- CHK(pkdelete(par) == 0);
+ if (j == tab.m_itabs)
+ CHK(pkdelete(par) == 0);
+ else {
+ const ITab& itab = *tab.m_itab[j];
+ CHK(hashindexdelete(par, itab) == 0);
+ }
}
}
}
@@ -2846,6 +4269,7 @@ static int
pkupdatescanread(Par par)
{
par.m_dups = true;
+ par.m_deadlock = true;
unsigned sel = urandom(10);
if (sel < 5) {
CHK(pkupdate(par) == 0);
@@ -2854,6 +4278,10 @@ pkupdatescanread(Par par)
CHK(scanreadtable(par) == 0);
} else {
par.m_verify = false;
+ if (sel < 8) {
+ par.m_ordered = true;
+ par.m_descending = (sel < 7);
+ }
CHK(scanreadindex(par) == 0);
}
return 0;
@@ -2873,6 +4301,10 @@ mixedoperations(Par par)
} else if (sel < 6) {
CHK(scanupdatetable(par) == 0);
} else {
+ if (sel < 8) {
+ par.m_ordered = true;
+ par.m_descending = (sel < 7);
+ }
CHK(scanupdateindex(par) == 0);
}
return 0;
@@ -3134,6 +4566,24 @@ tbuild(Par par)
}
static int
+tindexscan(Par par)
+{
+ RUNSTEP(par, droptable, ST);
+ RUNSTEP(par, createtable, ST);
+ RUNSTEP(par, invalidatetable, MT);
+ RUNSTEP(par, createindex, ST);
+ RUNSTEP(par, invalidateindex, MT);
+ RUNSTEP(par, pkinsert, MT);
+ RUNSTEP(par, readverifyfull, MT);
+ for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) {
+ LL4("subloop " << par.m_slno);
+ RUNSTEP(par, readverifyindex, MT);
+ }
+ return 0;
+}
+
+
+static int
tpkops(Par par)
{
RUNSTEP(par, droptable, ST);
@@ -3266,6 +4716,10 @@ ttimemaint(Par par)
static int
ttimescan(Par par)
{
+ if (par.tab().m_itab[0] == 0) {
+ LL1("ttimescan - no index 0, skipped");
+ return 0;
+ }
Tmr t1, t2;
RUNSTEP(par, droptable, ST);
RUNSTEP(par, createtable, ST);
@@ -3288,6 +4742,10 @@ ttimescan(Par par)
static int
ttimepkread(Par par)
{
+ if (par.tab().m_itab[0] == 0) {
+ LL1("ttimescan - no index 0, skipped");
+ return 0;
+ }
Tmr t1, t2;
RUNSTEP(par, droptable, ST);
RUNSTEP(par, createtable, ST);
@@ -3328,7 +4786,7 @@ struct TCase {
static const TCase
tcaselist[] = {
TCase("a", tbuild, "index build"),
- // "b" in 5.0
+ TCase("b", tindexscan, "index scans"),
TCase("c", tpkops, "pk operations"),
TCase("d", tpkopsread, "pk operations and scan reads"),
TCase("e", tmixedops, "pk operations and scan operations"),
@@ -3357,13 +4815,32 @@ printcases()
static void
printtables()
{
- ndbout << "tables and indexes (X1 is on table PK):" << endl;
+ Par par(g_opt);
+ makebuiltintables(par);
+ ndbout << "tables and indexes (x=ordered z=hash x0=on pk):" << endl;
for (unsigned j = 0; j < tabcount; j++) {
- const Tab& tab = tablist[j];
- ndbout << " " << tab.m_name;
+ if (tablist[j] == 0)
+ continue;
+ const Tab& tab = *tablist[j];
+ const char* tname = tab.m_name;
+ ndbout << " " << tname;
for (unsigned i = 0; i < tab.m_itabs; i++) {
- const ITab& itab = tab.m_itab[i];
- ndbout << " " << itab.m_name;
+ if (tab.m_itab[i] == 0)
+ continue;
+ const ITab& itab = *tab.m_itab[i];
+ const char* iname = itab.m_name;
+ if (strncmp(tname, iname, strlen(tname)) == 0)
+ iname += strlen(tname);
+ ndbout << " " << iname;
+ ndbout << "(";
+ for (unsigned k = 0; k < itab.m_icols; k++) {
+ if (k != 0)
+ ndbout << ",";
+ const ICol& icol = *itab.m_icol[k];
+ const Col& col = icol.m_col;
+ ndbout << col.m_name;
+ }
+ ndbout << ")";
}
ndbout << endl;
}
@@ -3373,15 +4850,29 @@ static int
runtest(Par par)
{
LL1("start");
- if (par.m_seed != 0)
+ if (par.m_seed == -1) {
+ // good enough for daily run
+ unsigned short seed = (getpid() ^ time(0));
+ LL1("random seed: " << seed);
+ srandom((unsigned)seed);
+ } else if (par.m_seed != 0) {
+ LL1("random seed: " << par.m_seed);
srandom(par.m_seed);
+ } else {
+ LL1("random seed: loop number");
+ }
+ // cs
assert(par.m_csname != 0);
- CHARSET_INFO* cs;
- CHK((cs = get_charset_by_name(par.m_csname, MYF(0))) != 0 || (cs = get_charset_by_csname(par.m_csname, MY_CS_PRIMARY, MYF(0))) != 0);
- par.m_cs = cs;
+ if (strcmp(par.m_csname, "random") != 0) {
+ CHARSET_INFO* cs;
+ CHK((cs = get_charset_by_name(par.m_csname, MYF(0))) != 0 || (cs = get_charset_by_csname(par.m_csname, MY_CS_PRIMARY, MYF(0))) != 0);
+ par.m_cs = cs;
+ }
+ // con
Con con;
CHK(con.connect() == 0);
par.m_con = &con;
+ // threads
g_thrlist = new Thr* [par.m_threads];
unsigned n;
for (n = 0; n < par.m_threads; n++) {
@@ -3400,16 +4891,18 @@ runtest(Par par)
const TCase& tcase = tcaselist[i];
if (par.m_case != 0 && strchr(par.m_case, tcase.m_name[0]) == 0)
continue;
+ makebuiltintables(par);
LL1("case " << tcase.m_name << " - " << tcase.m_desc);
for (unsigned j = 0; j < tabcount; j++) {
- if (! usetable(j))
+ if (tablist[j] == 0)
continue;
- const Tab& tab = tablist[j];
+ const Tab& tab = *tablist[j];
par.m_tab = &tab;
- delete par.m_set;
par.m_set = new Set(tab, par.m_totrows);
LL1("table " << tab.m_name);
CHK(tcase.m_func(par) == 0);
+ delete par.m_set;
+ par.m_set = 0;
}
}
}
@@ -3433,7 +4926,7 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
{
ndb_init();
if (ndbout_mutex == NULL)
- ndbout_mutex= NdbMutex_Create();
+ ndbout_mutex = NdbMutex_Create();
while (++argv, --argc > 0) {
const char* arg = argv[0];
if (*arg != '-') {
@@ -3461,6 +4954,10 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
continue;
}
}
+ if (strcmp(arg, "-collsp") == 0) {
+ g_opt.m_collsp = true;
+ continue;
+ }
if (strcmp(arg, "-core") == 0) {
g_opt.m_core = true;
continue;
@@ -3572,7 +5069,8 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
if (strcmp(arg, "-threads") == 0) {
if (++argv, --argc > 0) {
g_opt.m_threads = atoi(argv[0]);
- continue;
+ if (1 <= g_opt.m_threads)
+ continue;
}
}
if (strcmp(arg, "-v") == 0) {
@@ -3589,7 +5087,7 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
printhelp();
goto wrongargs;
}
- ndbout << "testOIBasic: unknown option " << arg;
+ ndbout << "testOIBasic: bad or unknown option " << arg;
goto usage;
}
{
@@ -3600,7 +5098,6 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535)
delete g_ncc;
g_ncc = 0;
}
- // always exit with NDBT code
ok:
return NDBT_ProgramExit(NDBT_OK);
failed:
diff --git a/ndb/test/ndbapi/testPartitioning.cpp b/ndb/test/ndbapi/testPartitioning.cpp
new file mode 100644
index 00000000000..9d67c27354b
--- /dev/null
+++ b/ndb/test/ndbapi/testPartitioning.cpp
@@ -0,0 +1,430 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <NDBT_Test.hpp>
+#include <NDBT_ReturnCodes.h>
+#include <HugoTransactions.hpp>
+#include <UtilTransactions.hpp>
+#include <NdbRestarter.hpp>
+
+#define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb()
+
+static Uint32 max_dks = 0;
+
+static
+int
+run_drop_table(NDBT_Context* ctx, NDBT_Step* step)
+{
+ NdbDictionary::Dictionary* dict = GETNDB(step)->getDictionary();
+ dict->dropTable(ctx->getTab()->getName());
+ return 0;
+}
+
+static
+int
+add_distribution_key(Ndb*, NdbDictionary::Table& tab, int when)
+{
+ switch(when){
+ case 0: // Before
+ break;
+ case 1: // After
+ return 0;
+ default:
+ return 0;
+ }
+
+ int keys = tab.getNoOfPrimaryKeys();
+ int dks = (2 * keys + 2) / 3; dks = (dks > max_dks ? max_dks : dks);
+ int cnt = 0;
+
+ for(unsigned i = 0; i<tab.getNoOfColumns(); i++)
+ if(tab.getColumn(i)->getPrimaryKey() &&
+ tab.getColumn(i)->getCharset() != 0)
+ keys--;
+
+ Uint32 max = NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY - tab.getNoOfPrimaryKeys();
+
+ if(max_dks < max)
+ max = max_dks;
+
+ if(keys <= 1 && max > 0)
+ {
+ dks = 1 + (rand() % max);
+ ndbout_c("%s pks: %d dks: %d", tab.getName(), keys, dks);
+ while(dks--)
+ {
+ NdbDictionary::Column col;
+ BaseString name;
+ name.assfmt("PK_DK_%d", dks);
+ col.setName(name.c_str());
+ col.setType(NdbDictionary::Column::Unsigned);
+ col.setLength(1);
+ col.setNullable(false);
+ col.setPrimaryKey(true);
+ col.setDistributionKey(true);
+ tab.addColumn(col);
+ }
+ }
+ else
+ {
+ for(unsigned i = 0; i<tab.getNoOfColumns(); i++)
+ {
+ NdbDictionary::Column* col = tab.getColumn(i);
+ if(col->getPrimaryKey() && col->getCharset() == 0)
+ {
+ if(dks >= keys || (rand() % 100) > 50)
+ {
+ col->setDistributionKey(true);
+ dks--;
+ }
+ keys--;
+ }
+ }
+ }
+ ndbout << (NDBT_Table&)tab << endl;
+
+ return 0;
+}
+
+static int
+run_create_table(NDBT_Context* ctx, NDBT_Step* step)
+{
+ max_dks = ctx->getProperty("distributionkey", (unsigned)0);
+
+ if(NDBT_Tables::createTable(GETNDB(step),
+ ctx->getTab()->getName(),
+ false, false,
+ max_dks?add_distribution_key:0) == NDBT_OK)
+ {
+ return NDBT_OK;
+ }
+
+ if(GETNDB(step)->getDictionary()->getNdbError().code == 745)
+ return NDBT_OK;
+
+ return NDBT_FAILED;
+}
+
+static int
+run_create_pk_index(NDBT_Context* ctx, NDBT_Step* step){
+ bool orderedIndex = ctx->getProperty("OrderedIndex", (unsigned)0);
+
+ Ndb* pNdb = GETNDB(step);
+ const NdbDictionary::Table *pTab =
+ pNdb->getDictionary()->getTable(ctx->getTab()->getName());
+
+ if(!pTab)
+ return NDBT_OK;
+
+ bool logged = ctx->getProperty("LoggedIndexes", orderedIndex ? 0 : 1);
+
+ BaseString name;
+ name.assfmt("IND_%s_PK_%c", pTab->getName(), orderedIndex ? 'O' : 'U');
+
+ // Create index
+ if (orderedIndex)
+ ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "ordered index "
+ << name.c_str() << " (";
+ else
+ ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "unique index "
+ << name.c_str() << " (";
+
+ NdbDictionary::Index pIdx(name.c_str());
+ pIdx.setTable(pTab->getName());
+ if (orderedIndex)
+ pIdx.setType(NdbDictionary::Index::OrderedIndex);
+ else
+ pIdx.setType(NdbDictionary::Index::UniqueHashIndex);
+ for (int c = 0; c< pTab->getNoOfColumns(); c++){
+ const NdbDictionary::Column * col = pTab->getColumn(c);
+ if(col->getPrimaryKey()){
+ pIdx.addIndexColumn(col->getName());
+ ndbout << col->getName() <<" ";
+ }
+ }
+
+ pIdx.setStoredIndex(logged);
+ ndbout << ") ";
+ if (pNdb->getDictionary()->createIndex(pIdx) != 0){
+ ndbout << "FAILED!" << endl;
+ const NdbError err = pNdb->getDictionary()->getNdbError();
+ ERR(err);
+ return NDBT_FAILED;
+ }
+
+ ndbout << "OK!" << endl;
+ return NDBT_OK;
+}
+
+static int run_create_pk_index_drop(NDBT_Context* ctx, NDBT_Step* step){
+ bool orderedIndex = ctx->getProperty("OrderedIndex", (unsigned)0);
+
+ Ndb* pNdb = GETNDB(step);
+ const NdbDictionary::Table *pTab =
+ pNdb->getDictionary()->getTable(ctx->getTab()->getName());
+
+ if(!pTab)
+ return NDBT_OK;
+
+ BaseString name;
+ name.assfmt("IND_%s_PK_%c", pTab->getName(), orderedIndex ? 'O' : 'U');
+
+ ndbout << "Dropping index " << name.c_str() << " ";
+ if (pNdb->getDictionary()->dropIndex(name.c_str(), pTab->getName()) != 0){
+ ndbout << "FAILED!" << endl;
+ ERR(pNdb->getDictionary()->getNdbError());
+ return NDBT_FAILED;
+ } else {
+ ndbout << "OK!" << endl;
+ }
+
+ return NDBT_OK;
+}
+
+static int
+run_tests(Ndb* p_ndb, HugoTransactions& hugoTrans, int records)
+{
+ if (hugoTrans.loadTable(p_ndb, records) != 0)
+ {
+ return NDBT_FAILED;
+ }
+
+ if(hugoTrans.pkReadRecords(p_ndb, records) != 0)
+ {
+ return NDBT_FAILED;
+ }
+
+ if(hugoTrans.pkUpdateRecords(p_ndb, records) != 0)
+ {
+ return NDBT_FAILED;
+ }
+
+ if(hugoTrans.pkDelRecords(p_ndb, records) != 0)
+ {
+ return NDBT_FAILED;
+ }
+
+ if (hugoTrans.loadTable(p_ndb, records) != 0)
+ {
+ return NDBT_FAILED;
+ }
+
+ if(hugoTrans.scanUpdateRecords(p_ndb, records) != 0)
+ {
+ return NDBT_FAILED;
+ }
+
+ Uint32 abort = 23;
+ for(Uint32 j = 0; j<5; j++){
+ Uint32 parallelism = (j == 1 ? 1 : j * 3);
+ ndbout_c("parallelism: %d", parallelism);
+ if (hugoTrans.scanReadRecords(p_ndb, records, abort, parallelism,
+ NdbOperation::LM_Read) != 0)
+ {
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.scanReadRecords(p_ndb, records, abort, parallelism,
+ NdbOperation::LM_Exclusive) != 0)
+ {
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.scanReadRecords(p_ndb, records, abort, parallelism,
+ NdbOperation::LM_CommittedRead) != 0)
+ {
+ return NDBT_FAILED;
+ }
+ }
+
+ if(hugoTrans.clearTable(p_ndb, records) != 0)
+ {
+ return NDBT_FAILED;
+ }
+
+ return 0;
+}
+
+static int
+run_pk_dk(NDBT_Context* ctx, NDBT_Step* step)
+{
+ Ndb* p_ndb = GETNDB(step);
+ int records = ctx->getNumRecords();
+ const NdbDictionary::Table *tab =
+ p_ndb->getDictionary()->getTable(ctx->getTab()->getName());
+
+ if(!tab)
+ return NDBT_OK;
+
+ HugoTransactions hugoTrans(*tab);
+
+ return run_tests(p_ndb, hugoTrans, records);
+}
+
+int
+run_index_dk(NDBT_Context* ctx, NDBT_Step* step)
+{
+ Ndb* p_ndb = GETNDB(step);
+ int records = ctx->getNumRecords();
+ const NdbDictionary::Table *pTab =
+ p_ndb->getDictionary()->getTable(ctx->getTab()->getName());
+
+ if(!pTab)
+ return NDBT_OK;
+
+ bool orderedIndex = ctx->getProperty("OrderedIndex", (unsigned)0);
+
+ BaseString name;
+ name.assfmt("IND_%s_PK_%c", pTab->getName(), orderedIndex ? 'O' : 'U');
+
+ const NdbDictionary::Index * idx =
+ p_ndb->getDictionary()->getIndex(name.c_str(), pTab->getName());
+
+ if(!idx)
+ {
+ ndbout << "Failed to retreive index: " << name.c_str() << endl;
+ return NDBT_FAILED;
+ }
+
+ HugoTransactions hugoTrans(*pTab, idx);
+
+ return run_tests(p_ndb, hugoTrans, records);
+}
+
+static int
+run_startHint(NDBT_Context* ctx, NDBT_Step* step)
+{
+ Ndb* p_ndb = GETNDB(step);
+ int records = ctx->getNumRecords();
+ const NdbDictionary::Table *tab =
+ p_ndb->getDictionary()->getTable(ctx->getTab()->getName());
+
+ if(!tab)
+ return NDBT_OK;
+
+ HugoTransactions hugoTrans(*tab);
+ if (hugoTrans.loadTable(p_ndb, records) != 0)
+ {
+ return NDBT_FAILED;
+ }
+
+ NdbRestarter restarter;
+ if(restarter.insertErrorInAllNodes(8050) != 0)
+ return NDBT_FAILED;
+
+ HugoCalculator dummy(*tab);
+ int result = NDBT_OK;
+ for(int i = 0; i<records && result == NDBT_OK; i++)
+ {
+ char buffer[8000];
+ char* start= buffer + (rand() & 7);
+ char* pos= start;
+
+ for(int j = 0; j<tab->getNoOfColumns(); j++)
+ {
+ if(tab->getColumn(j)->getPartitionKey())
+ {
+ ndbout_c(tab->getColumn(j)->getName());
+ int sz = tab->getColumn(j)->getSizeInBytes();
+ int aligned_size = 4 * ((sz + 3) >> 2);
+ memset(pos, 0, aligned_size);
+ dummy.calcValue(i, j, 0, pos, sz);
+ pos += aligned_size;
+ }
+ }
+ // Now we have the pk
+ NdbTransaction* pTrans= p_ndb->startTransaction(tab, start,(pos - start));
+ HugoOperations ops(*tab);
+ ops.setTransaction(pTrans);
+ if(ops.pkReadRecord(p_ndb, i, 1) != NDBT_OK)
+ {
+ result = NDBT_FAILED;
+ break;
+ }
+
+ if(ops.execute_Commit(p_ndb) != 0)
+ {
+ result = NDBT_FAILED;
+ break;
+ }
+
+ ops.closeTransaction(p_ndb);
+ }
+ restarter.insertErrorInAllNodes(0);
+ return result;
+}
+
+
+NDBT_TESTSUITE(testPartitioning);
+TESTCASE("pk_dk",
+ "Primary key operations with distribution key")
+{
+ TC_PROPERTY("distributionkey", ~0);
+ INITIALIZER(run_drop_table);
+ INITIALIZER(run_create_table);
+ INITIALIZER(run_pk_dk);
+ INITIALIZER(run_drop_table);
+}
+TESTCASE("hash_index_dk",
+ "Unique index operatations with distribution key")
+{
+ TC_PROPERTY("distributionkey", ~0);
+ TC_PROPERTY("OrderedIndex", (unsigned)0);
+ INITIALIZER(run_drop_table);
+ INITIALIZER(run_create_table);
+ INITIALIZER(run_create_pk_index);
+ INITIALIZER(run_index_dk);
+ INITIALIZER(run_create_pk_index_drop);
+ INITIALIZER(run_drop_table);
+}
+TESTCASE("ordered_index_dk",
+ "Ordered index operatations with distribution key")
+{
+ TC_PROPERTY("distributionkey", (unsigned)1);
+ TC_PROPERTY("OrderedIndex", (unsigned)1);
+ INITIALIZER(run_drop_table);
+ INITIALIZER(run_create_table);
+ INITIALIZER(run_create_pk_index);
+ INITIALIZER(run_index_dk);
+ INITIALIZER(run_create_pk_index_drop);
+ INITIALIZER(run_drop_table);
+}
+TESTCASE("startTransactionHint",
+ "Test startTransactionHint wo/ distribution key")
+{
+ TC_PROPERTY("distributionkey", (unsigned)0);
+ INITIALIZER(run_drop_table);
+ INITIALIZER(run_create_table);
+ INITIALIZER(run_startHint);
+ INITIALIZER(run_drop_table);
+}
+TESTCASE("startTransactionHint_dk",
+ "Test startTransactionHint with distribution key")
+{
+ TC_PROPERTY("distributionkey", (unsigned)~0);
+ INITIALIZER(run_drop_table);
+ INITIALIZER(run_create_table);
+ INITIALIZER(run_startHint);
+ INITIALIZER(run_drop_table);
+}
+NDBT_TESTSUITE_END(testPartitioning);
+
+int main(int argc, const char** argv){
+ ndb_init();
+ testPartitioning.setCreateTable(false);
+ return testPartitioning.execute(argc, argv);
+}
+
+
+
diff --git a/ndb/test/ndbapi/testReadPerf.cpp b/ndb/test/ndbapi/testReadPerf.cpp
index 3adcb5a2d9b..ba5f3c4232d 100644
--- a/ndb/test/ndbapi/testReadPerf.cpp
+++ b/ndb/test/ndbapi/testReadPerf.cpp
@@ -119,7 +119,13 @@ main(int argc, const char** argv){
myRandom48Init(NdbTick_CurrentMillisecond());
memset(g_times, 0, sizeof(g_times));
- g_ndb = new Ndb("TEST_DB");
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1))
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ g_ndb = new Ndb(&con, "TEST_DB");
if(g_ndb->init() != 0){
g_err << "init() failed" << endl;
goto error;
@@ -266,7 +272,6 @@ run_read(){
NdbScanOperation * pSp;
NdbIndexOperation * pUp;
NdbIndexScanOperation * pIp;
- NdbResultSet * rs = (NdbResultSet*)~0;
Uint32 start_row = rand() % (rows - range);
Uint32 stop_row = start_row + range;
@@ -319,27 +324,27 @@ run_read(){
}
break;
case 4:
- pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
- rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
+ pOp = pSp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
+ pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
check = pIp->setBound(pk, NdbIndexScanOperation::BoundEQ, &start_row);
break;
case 5:
- pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
- rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
+ pOp = pSp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
+ pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
start_row = stop_row;
break;
case 6:
- pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
- rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0, true);
+ pOp = pSp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
+ pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0, true);
check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
start_row = stop_row;
break;
case 7:
pOp = pSp = pTrans->getNdbScanOperation(g_table);
- rs = pSp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
+ pSp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
NdbScanFilter filter(pOp) ;
filter.begin(NdbScanFilter::AND);
filter.ge(pk, start_row);
@@ -355,7 +360,6 @@ run_read(){
ndbout << pTrans->getNdbError() << endl;
}
assert(check == 0);
- assert(rs);
for(int j = 0; j<g_tab->getNoOfColumns(); j++){
res = pOp->getValue(j);
@@ -368,7 +372,7 @@ run_read(){
}
assert(check == 0);
if(g_paramters[P_OPER].value >= 4){
- while((check = rs->nextResult(true)) == 0){
+ while((check = pSp->nextResult(true)) == 0){
cnt++;
}
@@ -377,13 +381,13 @@ run_read(){
return -1;
}
assert(check == 1);
- rs->close();
+ pSp->close();
}
}
assert(g_paramters[P_OPER].value < 4 || (cnt == range));
-
+
pTrans->close();
-
+
stop = NdbTick_CurrentMillisecond();
g_times[g_paramters[P_OPER].value] += (stop - start1);
return 0;
diff --git a/ndb/test/ndbapi/testScan.cpp b/ndb/test/ndbapi/testScan.cpp
index f1018d29846..3b52778a013 100644
--- a/ndb/test/ndbapi/testScan.cpp
+++ b/ndb/test/ndbapi/testScan.cpp
@@ -1013,8 +1013,7 @@ int runScanRestart(NDBT_Context* ctx, NDBT_Step* step){
return NDBT_FAILED;
}
- NdbResultSet* rs = pOp->readTuples();
- if( rs == 0 ) {
+ if( pOp->readTuples() ) {
ERR(pCon->getNdbError());
return NDBT_FAILED;
}
@@ -1042,7 +1041,7 @@ int runScanRestart(NDBT_Context* ctx, NDBT_Step* step){
int res;
int row = 0;
- while(row < record && (res = rs->nextResult()) == 0) {
+ while(row < record && (res = pOp->nextResult()) == 0) {
if(calc.verifyRowValues(&tmpRow) != 0){
abort();
return NDBT_FAILED;
@@ -1055,14 +1054,14 @@ int runScanRestart(NDBT_Context* ctx, NDBT_Step* step){
return NDBT_FAILED;
}
g_info << " restarting" << endl;
- if((res = rs->restart()) != 0){
+ if((res = pOp->restart()) != 0){
ERR(pCon->getNdbError());
abort();
return NDBT_FAILED;
}
row = 0;
- while((res = rs->nextResult()) == 0) {
+ while((res = pOp->nextResult()) == 0) {
if(calc.verifyRowValues(&tmpRow) != 0){
abort();
return NDBT_FAILED;
@@ -1080,6 +1079,44 @@ int runScanRestart(NDBT_Context* ctx, NDBT_Step* step){
}
+int
+runScanParallelism(NDBT_Context* ctx, NDBT_Step* step){
+ int loops = ctx->getNumLoops() + 3;
+ int records = ctx->getNumRecords();
+ int abort = ctx->getProperty("AbortProb", 15);
+
+ Uint32 fib[] = { 1, 2 };
+ Uint32 parallelism = 0; // start with 0
+ int i = 0;
+ HugoTransactions hugoTrans(*ctx->getTab());
+ while (i<loops && !ctx->isTestStopped()) {
+ g_info << i << ": ";
+
+ if (hugoTrans.scanReadRecords(GETNDB(step), records, abort, parallelism,
+ NdbOperation::LM_Read) != 0){
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.scanReadRecords(GETNDB(step), records, abort, parallelism,
+ NdbOperation::LM_Exclusive) != 0){
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.scanReadRecords(GETNDB(step), records, abort, parallelism,
+ NdbOperation::LM_CommittedRead) != 0){
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.scanUpdateRecords(GETNDB(step), records, abort, parallelism)
+ != 0){
+ return NDBT_FAILED;
+ }
+ i++;
+ parallelism = fib[0];
+ Uint32 next = fib[0] + fib[1];
+ fib[0] = fib[1];
+ fib[1] = next;
+ }
+ return NDBT_OK;
+}
+
NDBT_TESTSUITE(testScan);
TESTCASE("ScanRead",
"Verify scan requirement: It should be possible "\
@@ -1540,6 +1577,12 @@ TESTCASE("ScanRestart",
STEP(runScanRestart);
FINALIZER(runClearTable);
}
+TESTCASE("ScanParallelism",
+ "Test scan with different parallelism"){
+ INITIALIZER(runLoadTable);
+ STEP(runScanParallelism);
+ FINALIZER(runClearTable);
+}
NDBT_TESTSUITE_END(testScan);
int main(int argc, const char** argv){
diff --git a/ndb/test/ndbapi/testScanPerf.cpp b/ndb/test/ndbapi/testScanPerf.cpp
index 45f0468bc70..8ac81297ac3 100644
--- a/ndb/test/ndbapi/testScanPerf.cpp
+++ b/ndb/test/ndbapi/testScanPerf.cpp
@@ -38,10 +38,10 @@ struct Parameter {
#define P_ROWS 7
#define P_LOOPS 8
#define P_CREATE 9
-#define P_LOAD 10
#define P_RESET 11
+#define P_MULTI 12
-#define P_MAX 12
+#define P_MAX 13
static
Parameter
@@ -57,7 +57,8 @@ g_paramters[] = {
{ "iterations", 3, 1, ~0 },
{ "create_drop", 1, 0, 1 },
{ "data", 1, 0, 1 },
- { "q-reset bounds", 0, 1, 0 }
+ { "q-reset bounds", 0, 1, 0 },
+ { "multi read range", 1000, 1, ~0 }
};
static Ndb* g_ndb = 0;
@@ -67,10 +68,7 @@ static char g_tablename[256];
static char g_indexname[256];
int create_table();
-int load_table();
int run_scan();
-int clear_table();
-int drop_table();
int
main(int argc, const char** argv){
@@ -101,7 +99,13 @@ main(int argc, const char** argv){
myRandom48Init(NdbTick_CurrentMillisecond());
- g_ndb = new Ndb("TEST_DB");
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1))
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ g_ndb = new Ndb(&con, "TEST_DB");
if(g_ndb->init() != 0){
g_err << "init() failed" << endl;
goto error;
@@ -117,14 +121,8 @@ main(int argc, const char** argv){
BaseString::snprintf(g_indexname, sizeof(g_indexname), "IDX_%s", T);
if(create_table())
goto error;
- if(load_table())
- goto error;
if(run_scan())
goto error;
- if(clear_table())
- goto error;
- if(drop_table())
- goto error;
}
if(g_ndb) delete g_ndb;
@@ -139,6 +137,7 @@ create_table(){
NdbDictionary::Dictionary* dict = g_ndb->getDictionary();
assert(dict);
if(g_paramters[P_CREATE].value){
+ g_ndb->getDictionary()->dropTable(g_tablename);
const NdbDictionary::Table * pTab = NDBT_Tables::getTable(g_tablename);
assert(pTab);
NdbDictionary::Table copy = * pTab;
@@ -167,46 +166,18 @@ create_table(){
g_index = dict->getIndex(g_indexname, g_tablename);
assert(g_table);
assert(g_index);
- return 0;
-}
-int
-drop_table(){
- if(!g_paramters[P_CREATE].value)
- return 0;
- if(g_ndb->getDictionary()->dropTable(g_table->getName()) != 0){
- g_err << "Failed to drop table: " << g_table->getName() << endl;
- return -1;
- }
- g_table = 0;
- return 0;
-}
-
-int
-load_table(){
- if(!g_paramters[P_LOAD].value)
- return 0;
-
- int rows = g_paramters[P_ROWS].value;
- HugoTransactions hugoTrans(* g_table);
- if (hugoTrans.loadTable(g_ndb, rows)){
- g_err.println("Failed to load %s with %d rows", g_table->getName(), rows);
- return -1;
+ if(g_paramters[P_CREATE].value)
+ {
+ int rows = g_paramters[P_ROWS].value;
+ HugoTransactions hugoTrans(* g_table);
+ if (hugoTrans.loadTable(g_ndb, rows)){
+ g_err.println("Failed to load %s with %d rows",
+ g_table->getName(), rows);
+ return -1;
+ }
}
- return 0;
-}
-
-int
-clear_table(){
- if(!g_paramters[P_LOAD].value)
- return 0;
- int rows = g_paramters[P_ROWS].value;
- UtilTransactions utilTrans(* g_table);
- if (utilTrans.clearTable(g_ndb, rows) != 0){
- g_err.println("Failed to clear table %s", g_table->getName());
- return -1;
- }
return 0;
}
@@ -227,13 +198,12 @@ run_scan(){
Uint32 tot = g_paramters[P_ROWS].value;
- if(g_paramters[P_BOUND].value == 2 || g_paramters[P_FILT].value == 2)
+ if(g_paramters[P_BOUND].value >= 2 || g_paramters[P_FILT].value == 2)
iter *= g_paramters[P_ROWS].value;
NdbScanOperation * pOp = 0;
NdbIndexScanOperation * pIOp = 0;
NdbConnection * pTrans = 0;
- NdbResultSet * rs = 0;
int check = 0;
for(int i = 0; i<iter; i++){
@@ -265,13 +235,13 @@ run_scan(){
if(g_paramters[P_ACCESS].value == 0){
pOp = pTrans->getNdbScanOperation(g_tablename);
assert(pOp);
- rs = pOp->readTuples(lm, bat, par);
+ pOp->readTuples(lm, bat, par);
} else {
if(g_paramters[P_RESET].value == 0 || pIOp == 0)
{
pOp= pIOp= pTrans->getNdbIndexScanOperation(g_indexname, g_tablename);
bool ord = g_paramters[P_ACCESS].value == 2;
- rs = pIOp->readTuples(lm, bat, par, ord);
+ pIOp->readTuples(lm, bat, par, ord);
}
else
{
@@ -294,14 +264,26 @@ run_scan(){
#else
pIOp->setBound((Uint32)0, NdbIndexScanOperation::BoundEQ, &row);
#endif
+ if(g_paramters[P_RESET].value == 2)
+ goto execute;
+ break;
+ }
+ case 3: { // read multi
+ int multi = g_paramters[P_MULTI].value;
+ int tot = g_paramters[P_ROWS].value;
+ for(; multi > 0 && i < iter; --multi, i++)
+ {
+ int row = rand() % tot;
+ pIOp->setBound((Uint32)0, NdbIndexScanOperation::BoundEQ, &row);
+ pIOp->end_of_bound(i);
+ }
+ if(g_paramters[P_RESET].value == 2)
+ goto execute;
break;
}
}
- if(g_paramters[P_RESET].value == 2)
- goto execute;
}
assert(pOp);
- assert(rs);
switch(g_paramters[P_FILT].value){
case 0: // All
@@ -337,15 +319,18 @@ run_scan(){
for(int i = 0; i<g_table->getNoOfColumns(); i++){
pOp->getValue(i);
}
+
+ if(g_paramters[P_RESET].value == 1)
+ g_paramters[P_RESET].value = 2;
execute:
int rows = 0;
check = pTrans->execute(NoCommit);
assert(check == 0);
int fetch = g_paramters[P_FETCH].value;
- while((check = rs->nextResult(true)) == 0){
+ while((check = pOp->nextResult(true)) == 0){
do {
rows++;
- } while(!fetch && ((check = rs->nextResult(false)) == 0));
+ } while(!fetch && ((check = pOp->nextResult(false)) == 0));
if(check == -1){
err(pTrans->getNdbError());
return -1;
diff --git a/ndb/test/ndbapi/testTimeout.cpp b/ndb/test/ndbapi/testTimeout.cpp
index e310e12df81..ac4f257f12c 100644
--- a/ndb/test/ndbapi/testTimeout.cpp
+++ b/ndb/test/ndbapi/testTimeout.cpp
@@ -87,45 +87,6 @@ int runClearTable(NDBT_Context* ctx, NDBT_Step* step){
result = NDBT_FAILED; \
break; }
-int runTimeoutTrans(NDBT_Context* ctx, NDBT_Step* step){
- int result = NDBT_OK;
- int loops = ctx->getNumLoops();
- NdbConfig conf(GETNDB(step)->getNodeId()+1);
- unsigned int nodeId = conf.getMasterNodeId();
- int stepNo = step->getStepNo();
-
- int minSleep = (int)(TIMEOUT * 1.5);
- int maxSleep = TIMEOUT * 2;
- ndbout << "TransactionInactiveTimeout="<< TIMEOUT
- << ", minSleep="<<minSleep
- << ", maxSleep="<<maxSleep<<endl;
-
- HugoOperations hugoOps(*ctx->getTab());
- Ndb* pNdb = GETNDB(step);
-
- for (int l = 0; l < loops && result == NDBT_OK; l++){
-
- do{
- // Commit transaction
- CHECK(hugoOps.startTransaction(pNdb) == 0);
- CHECK(hugoOps.pkReadRecord(pNdb, stepNo) == 0);
- CHECK(hugoOps.execute_NoCommit(pNdb) == 0);
-
- int sleep = minSleep + myRandom48(maxSleep-minSleep);
- ndbout << "Sleeping for " << sleep << " milliseconds" << endl;
- NdbSleep_MilliSleep(sleep);
-
- // Expect that transaction has timed-out
- CHECK(hugoOps.execute_Commit(pNdb) == 237);
-
- } while(false);
-
- hugoOps.closeTransaction(pNdb);
- }
-
- return result;
-}
-
int runTimeoutTrans2(NDBT_Context* ctx, NDBT_Step* step){
int result = NDBT_OK;
int loops = ctx->getNumLoops();
@@ -345,27 +306,6 @@ TESTCASE("DontTimeoutTransaction5",
FINALIZER(resetTransactionTimeout);
FINALIZER(runClearTable);
}
-TESTCASE("TimeoutTransaction",
- "Test that the transaction does timeout "\
- "if we sleep during the transaction. Use a sleep "\
- "value which is larger than TransactionInactiveTimeout"){
- INITIALIZER(runLoadTable);
- INITIALIZER(setTransactionTimeout);
- STEPS(runTimeoutTrans, 1);
- FINALIZER(resetTransactionTimeout);
- FINALIZER(runClearTable);
-}
-TESTCASE("TimeoutTransaction5",
- "Test that the transaction does timeout " \
- "if we sleep during the transaction. Use a sleep " \
- "value which is larger than TransactionInactiveTimeout" \
- "Five simultaneous threads"){
- INITIALIZER(runLoadTable);
- INITIALIZER(setTransactionTimeout);
- STEPS(runTimeoutTrans, 5);
- FINALIZER(resetTransactionTimeout);
- FINALIZER(runClearTable);
-}
TESTCASE("TimeoutRandTransaction",
"Test that the transaction does timeout "\
"if we sleep during the transaction. Use a sleep "\
diff --git a/ndb/test/ndbapi/test_event.cpp b/ndb/test/ndbapi/test_event.cpp
index cb2793e42b9..2df50f21e43 100644
--- a/ndb/test/ndbapi/test_event.cpp
+++ b/ndb/test/ndbapi/test_event.cpp
@@ -14,11 +14,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include "NDBT_Test.hpp"
-#include "NDBT_ReturnCodes.h"
-#include "HugoTransactions.hpp"
-#include "UtilTransactions.hpp"
-#include "TestNdbEventOperation.hpp"
+#include <NDBT_Test.hpp>
+#include <NDBT_ReturnCodes.h>
+#include <HugoTransactions.hpp>
+#include <UtilTransactions.hpp>
+#include <TestNdbEventOperation.hpp>
#define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb()
@@ -32,6 +32,69 @@ int runCreateEvent(NDBT_Context* ctx, NDBT_Step* step)
return NDBT_OK;
}
+int runCreateShadowTable(NDBT_Context* ctx, NDBT_Step* step)
+{
+ const NdbDictionary::Table *table= ctx->getTab();
+ char buf[1024];
+ sprintf(buf, "%s_SHADOW", table->getName());
+
+ GETNDB(step)->getDictionary()->dropTable(buf);
+ if (GETNDB(step)->getDictionary()->getTable(buf))
+ {
+ g_err << "unsucessful drop of " << buf << endl;
+ return NDBT_FAILED;
+ }
+
+ NdbDictionary::Table table_shadow(*table);
+ table_shadow.setName(buf);
+ GETNDB(step)->getDictionary()->createTable(table_shadow);
+ if (GETNDB(step)->getDictionary()->getTable(buf))
+ return NDBT_OK;
+
+ g_err << "unsucessful create of " << buf << endl;
+ return NDBT_FAILED;
+}
+
+int runCreateDropEventOperation(NDBT_Context* ctx, NDBT_Step* step)
+{
+ int loops = ctx->getNumLoops();
+ int records = ctx->getNumRecords();
+ HugoTransactions hugoTrans(*ctx->getTab());
+ EventOperationStats stats;
+
+ Ndb *pNdb=GETNDB(step);
+ const NdbDictionary::Table& tab= *ctx->getTab();
+ NdbEventOperation *pOp;
+ char eventName[1024];
+ sprintf(eventName,"%s_EVENT",tab.getName());
+ int noEventColumnName = tab.getNoOfColumns();
+
+ for (int i= 0; i < loops; i++)
+ {
+#if 1
+ if (hugoTrans.eventOperation(GETNDB(step), (void*)&stats, 0) != 0){
+ return NDBT_FAILED;
+ }
+#else
+ g_info << "create EventOperation\n";
+ pOp = pNdb->createEventOperation(eventName, 100);
+ if ( pOp == NULL ) {
+ g_err << "Event operation creation failed\n";
+ return NDBT_FAILED;
+ }
+
+ g_info << "dropping event operation" << endl;
+ int res = pNdb->dropEventOperation(pOp);
+ if (res != 0) {
+ g_err << "operation execution failed\n";
+ return NDBT_FAILED;
+ }
+#endif
+ }
+
+ return NDBT_OK;
+}
+
int theThreadIdCounter = 0;
int runEventOperation(NDBT_Context* ctx, NDBT_Step* step)
@@ -43,7 +106,7 @@ int runEventOperation(NDBT_Context* ctx, NDBT_Step* step)
EventOperationStats stats;
- g_info << "***** Id " << tId << endl;
+ g_info << "***** start Id " << tId << endl;
// sleep(tId);
@@ -62,12 +125,13 @@ int runEventOperation(NDBT_Context* ctx, NDBT_Step* step)
ret = NDBT_FAILED;
if (ret == NDBT_FAILED) {
- ndbout << "n_inserts = " << stats.n_inserts << endl;
- ndbout << "n_deletes = " << stats.n_deletes << endl;
- ndbout << "n_updates = " << stats.n_updates << endl;
- ndbout << "n_consecutive = " << stats.n_consecutive << endl;
- ndbout << "n_duplicates = " << stats.n_duplicates << endl;
- ndbout << "n_inconsistent_gcis = " << stats.n_inconsistent_gcis << endl;
+ g_info << "***** end Id " << tId << endl;
+ ndbout_c("n_inserts = %d (%d)", stats.n_inserts, records);
+ ndbout_c("n_deletes = %d (%d)", stats.n_deletes, records);
+ ndbout_c("n_updates = %d (%d)", stats.n_updates, records);
+ ndbout_c("n_consecutive = %d (%d)", stats.n_consecutive, 3);
+ ndbout_c("n_duplicates = %d (%d)", stats.n_duplicates, 0);
+ ndbout_c("n_inconsistent_gcis = %d (%d)", stats.n_inconsistent_gcis, 0);
}
return ret;
@@ -94,6 +158,36 @@ int runEventLoad(NDBT_Context* ctx, NDBT_Step* step)
return NDBT_OK;
}
+int runEventMixedLoad(NDBT_Context* ctx, NDBT_Step* step)
+{
+ int loops = ctx->getNumLoops();
+ int records = ctx->getNumRecords();
+ HugoTransactions hugoTrans(*ctx->getTab());
+
+ sleep(5);
+
+ if (hugoTrans.loadTable(GETNDB(step), 3*records, 1, true, 1) != 0){
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.pkDelRecords(GETNDB(step), 3*records, 1, true, 1) != 0){
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.loadTable(GETNDB(step), records, 1, true, 1) != 0){
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.pkUpdateRecords(GETNDB(step), records, 1, 1) != 0){
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.pkUpdateRecords(GETNDB(step), records, 1, 1) != 0){
+ return NDBT_FAILED;
+ }
+ if (hugoTrans.pkUpdateRecords(GETNDB(step), records, 1, 1) != 0){
+ return NDBT_FAILED;
+ }
+
+ return NDBT_OK;
+}
+
int runDropEvent(NDBT_Context* ctx, NDBT_Step* step)
{
HugoTransactions hugoTrans(*ctx->getTab());
@@ -105,6 +199,246 @@ int runDropEvent(NDBT_Context* ctx, NDBT_Step* step)
return NDBT_OK;
}
+int runVerify(NDBT_Context* ctx, NDBT_Step* step)
+{
+ int records = ctx->getNumRecords();
+ const NdbDictionary::Table * table= ctx->getTab();
+ char buf[1024];
+
+ sprintf(buf, "%s_SHADOW", table->getName());
+
+ HugoTransactions hugoTrans(*table);
+ if (hugoTrans.compare(GETNDB(step), buf, 0))
+ {
+ return NDBT_FAILED;
+ }
+
+ return NDBT_OK;
+}
+
+int runEventApplier(NDBT_Context* ctx, NDBT_Step* step)
+{
+ DBUG_ENTER("runEventApplier");
+
+ int records = ctx->getNumRecords();
+ int loops = ctx->getNumLoops();
+ const NdbDictionary::Table * table= ctx->getTab();
+ char buf[1024];
+
+ sprintf(buf, "%s_SHADOW", table->getName());
+ const NdbDictionary::Table * table_shadow;
+ if ((table_shadow = GETNDB(step)->getDictionary()->getTable(buf)) == 0)
+ {
+ g_err << "Unable to get table " << buf << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+
+ sprintf(buf, "%s_EVENT", table->getName());
+ NdbEventOperation *pOp;
+ pOp = GETNDB(step)->createEventOperation(buf, 10*records);
+ if ( pOp == NULL ) {
+ g_err << "Event operation creation failed on %s" << buf << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+
+ int i;
+ int n_columns= table->getNoOfColumns();
+ NdbRecAttr* recAttr[1024];
+ NdbRecAttr* recAttrPre[1024];
+ for (i = 0; i < n_columns; i++) {
+ recAttr[i] = pOp->getValue(table->getColumn(i)->getName());
+ recAttrPre[i] = pOp->getPreValue(table->getColumn(i)->getName());
+ }
+
+ if (pOp->execute()) { // This starts changes to "start flowing"
+ g_err << "execute operation execution failed: \n";
+ g_err << pOp->getNdbError().code << " "
+ << pOp->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+
+ int r= 0;
+ int res;
+ while (r < 10*records){
+ //printf("now waiting for event...\n");
+ res= GETNDB(step)->pollEvents(1000); // wait for event or 1000 ms
+ if (res <= 0)
+ {
+ ndbout_c("********************");
+ continue;
+ }
+
+ //printf("got data! %d\n", r);
+ int overrun= 0;
+ while (pOp->next(&overrun) > 0)
+ {
+ if (overrun)
+ {
+ g_err << "buffer overrun\n";
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ r++;
+
+ Uint32 gci= pOp->getGCI();
+
+ if (!pOp->isConsistent()) {
+ g_err << "A node failure has occured and events might be missing\n";
+ DBUG_RETURN(NDBT_FAILED);
+ }
+
+ int noRetries= 0;
+ do
+ {
+ NdbTransaction *trans= GETNDB(step)->startTransaction();
+ if (trans == 0)
+ {
+ g_err << "startTransaction failed "
+ << GETNDB(step)->getNdbError().code << " "
+ << GETNDB(step)->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+
+ NdbOperation *op= trans->getNdbOperation(table_shadow);
+ if (op == 0)
+ {
+ g_err << "getNdbOperation failed "
+ << trans->getNdbError().code << " "
+ << trans->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+
+ switch (pOp->getEventType()) {
+ case NdbDictionary::Event::TE_INSERT:
+ if (op->insertTuple())
+ {
+ g_err << "insertTuple "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ break;
+ case NdbDictionary::Event::TE_DELETE:
+ if (op->deleteTuple())
+ {
+ g_err << "deleteTuple "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ break;
+ case NdbDictionary::Event::TE_UPDATE:
+ if (op->updateTuple())
+ {
+ g_err << "updateTuple "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ break;
+ default:
+ abort();
+ }
+
+ for (i= 0; i < n_columns; i++)
+ {
+ if (recAttr[i]->isNULL())
+ {
+ if (table->getColumn(i)->getPrimaryKey())
+ {
+ g_err << "internal error: primary key isNull()="
+ << recAttr[i]->isNULL() << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ switch (pOp->getEventType()) {
+ case NdbDictionary::Event::TE_INSERT:
+ if (recAttr[i]->isNULL() < 0)
+ {
+ g_err << "internal error: missing value for insert\n";
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ break;
+ case NdbDictionary::Event::TE_DELETE:
+ break;
+ case NdbDictionary::Event::TE_UPDATE:
+ break;
+ default:
+ abort();
+ }
+ }
+ if (table->getColumn(i)->getPrimaryKey() &&
+ op->equal(i,recAttr[i]->aRef()))
+ {
+ g_err << "equal " << i << " "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ }
+
+ switch (pOp->getEventType()) {
+ case NdbDictionary::Event::TE_INSERT:
+ for (i= 0; i < n_columns; i++)
+ {
+ if (!table->getColumn(i)->getPrimaryKey() &&
+ op->setValue(i,recAttr[i]->isNULL() ? 0:recAttr[i]->aRef()))
+ {
+ g_err << "setValue(insert) " << i << " "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ }
+ break;
+ case NdbDictionary::Event::TE_DELETE:
+ break;
+ case NdbDictionary::Event::TE_UPDATE:
+ for (i= 0; i < n_columns; i++)
+ {
+ if (!table->getColumn(i)->getPrimaryKey() &&
+ recAttr[i]->isNULL() >= 0 &&
+ op->setValue(i,recAttr[i]->isNULL() ? 0:recAttr[i]->aRef()))
+ {
+ g_err << "setValue(update) " << i << " "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ }
+ break;
+ case NdbDictionary::Event::TE_ALL:
+ abort();
+ }
+ if (trans->execute(Commit) == 0)
+ {
+ trans->close();
+ // everything ok
+ break;
+ }
+ if (noRetries++ == 10 ||
+ trans->getNdbError().status != NdbError::TemporaryError)
+ {
+ g_err << "execute " << r << " failed "
+ << trans->getNdbError().code << " "
+ << trans->getNdbError().message << endl;
+ trans->close();
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ trans->close();
+ NdbSleep_MilliSleep(100); // sleep before retying
+ } while(1);
+ }
+ }
+
+ if (GETNDB(step)->dropEventOperation(pOp)) {
+ g_err << "dropEventOperation execution failed "
+ << GETNDB(step)->getNdbError().code << " "
+ << GETNDB(step)->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+
+ DBUG_RETURN(NDBT_OK);
+}
+
// INITIALIZER(runInsert);
// STEP(runPkRead);
// VERIFIER(runVerifyInsert);
@@ -116,25 +450,37 @@ TESTCASE("BasicEventOperation",
"NOTE! No errors are allowed!" ){
INITIALIZER(runCreateEvent);
STEP(runEventOperation);
- STEP(runEventOperation);
- STEP(runEventOperation);
- STEP(runEventOperation);
STEP(runEventLoad);
FINALIZER(runDropEvent);
}
-NDBT_TESTSUITE_END(test_event);
-
-#if 0
-NDBT_TESTSUITE(test_event);
+TESTCASE("CreateDropEventOperation",
+ "Verify that we can Create and Drop many times"
+ "NOTE! No errors are allowed!" ){
+ INITIALIZER(runCreateEvent);
+ STEP(runCreateDropEventOperation);
+ FINALIZER(runDropEvent);
+}
TESTCASE("ParallellEventOperation",
- "Verify that we can listen to Events in Parallell"
+ "Verify that we can listen to Events in parallell"
"NOTE! No errors are allowed!" ){
- INITIALIZER(runCreateAllEvent);
+ INITIALIZER(runCreateEvent);
+ STEP(runEventOperation);
STEP(runEventOperation);
+ STEP(runEventLoad);
+ FINALIZER(runDropEvent);
+}
+TESTCASE("EventOperationApplier",
+ "Verify that if we apply the data we get from event "
+ "operation is the same as the original table"
+ "NOTE! No errors are allowed!" ){
+ INITIALIZER(runCreateEvent);
+ INITIALIZER(runCreateShadowTable);
+ STEP(runEventApplier);
+ STEP(runEventMixedLoad);
FINALIZER(runDropEvent);
+ FINALIZER(runVerify);
}
NDBT_TESTSUITE_END(test_event);
-#endif
int main(int argc, const char** argv){
ndb_init();
diff --git a/ndb/test/ndbapi/test_event_multi_table.cpp b/ndb/test/ndbapi/test_event_multi_table.cpp
new file mode 100644
index 00000000000..f16504029fa
--- /dev/null
+++ b/ndb/test/ndbapi/test_event_multi_table.cpp
@@ -0,0 +1,487 @@
+/* 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 <ndb_global.h>
+#include <ndb_opts.h>
+#include <NDBT_Test.hpp>
+#include <NDBT_ReturnCodes.h>
+#include <HugoTransactions.hpp>
+#include <UtilTransactions.hpp>
+#include <TestNdbEventOperation.hpp>
+
+static void usage()
+{
+ ndb_std_print_version();
+}
+
+static int start_transaction(Ndb *ndb, Vector<HugoOperations*> &ops)
+{
+ if (ops[0]->startTransaction(ndb) != NDBT_OK)
+ return -1;
+ NdbTransaction * t= ops[0]->getTransaction();
+ for (int i= ops.size()-1; i > 0; i--)
+ {
+ ops[i]->setTransaction(t);
+ }
+ return 0;
+}
+
+static int close_transaction(Ndb *ndb, Vector<HugoOperations*> &ops)
+{
+ if (ops[0]->closeTransaction(ndb) != NDBT_OK)
+ return -1;
+ for (int i= ops.size()-1; i > 0; i--)
+ {
+ ops[i]->setTransaction(NULL);
+ }
+ return 0;
+}
+
+static int execute_commit(Ndb *ndb, Vector<HugoOperations*> &ops)
+{
+ if (ops[0]->execute_Commit(ndb) != NDBT_OK)
+ return -1;
+ return 0;
+}
+
+static int copy_events(Ndb *ndb,
+ Vector<NdbEventOperation *> &ops,
+ Vector<const NdbDictionary::Table *> &tabs,
+ Vector<Vector<NdbRecAttr *> > &values)
+{
+ DBUG_ENTER("copy_events");
+ int r= 0;
+ while (1)
+ {
+ int res= ndb->pollEvents(1000); // wait for event or 1000 ms
+ DBUG_PRINT("info", ("pollEvents res=%d", r));
+ if (res <= 0)
+ {
+ break;
+ }
+ for (unsigned i_ops= 0; i_ops < ops.size(); i_ops++)
+ {
+ NdbEventOperation *pOp= ops[i_ops];
+ const NdbDictionary::Table *table= tabs[i_ops];
+ Vector<NdbRecAttr *> &recAttr= values[i_ops];
+
+ int overrun= 0;
+ unsigned i;
+ unsigned n_columns= table->getNoOfColumns();
+ while (pOp->next(&overrun) > 0)
+ {
+ if (overrun)
+ {
+ g_err << "buffer overrun\n";
+ DBUG_RETURN(-1);
+ }
+ r++;
+
+ Uint32 gci= pOp->getGCI();
+
+ if (!pOp->isConsistent()) {
+ g_err << "A node failure has occured and events might be missing\n";
+ DBUG_RETURN(-1);
+ }
+
+ int noRetries= 0;
+ do
+ {
+ NdbTransaction *trans= ndb->startTransaction();
+ if (trans == 0)
+ {
+ g_err << "startTransaction failed "
+ << ndb->getNdbError().code << " "
+ << ndb->getNdbError().message << endl;
+ DBUG_RETURN(-1);
+ }
+
+ NdbOperation *op= trans->getNdbOperation(table);
+ if (op == 0)
+ {
+ g_err << "getNdbOperation failed "
+ << trans->getNdbError().code << " "
+ << trans->getNdbError().message << endl;
+ DBUG_RETURN(-1);
+ }
+
+ switch (pOp->getEventType()) {
+ case NdbDictionary::Event::TE_INSERT:
+ if (op->insertTuple())
+ {
+ g_err << "insertTuple "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(-1);
+ }
+ break;
+ case NdbDictionary::Event::TE_DELETE:
+ if (op->deleteTuple())
+ {
+ g_err << "deleteTuple "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(-1);
+ }
+ break;
+ case NdbDictionary::Event::TE_UPDATE:
+ if (op->updateTuple())
+ {
+ g_err << "updateTuple "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(-1);
+ }
+ break;
+ default:
+ abort();
+ }
+
+ for (i= 0; i < n_columns; i++)
+ {
+ if (recAttr[i]->isNULL())
+ {
+ if (table->getColumn(i)->getPrimaryKey())
+ {
+ g_err << "internal error: primary key isNull()="
+ << recAttr[i]->isNULL() << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ switch (pOp->getEventType()) {
+ case NdbDictionary::Event::TE_INSERT:
+ if (recAttr[i]->isNULL() < 0)
+ {
+ g_err << "internal error: missing value for insert\n";
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ break;
+ case NdbDictionary::Event::TE_DELETE:
+ break;
+ case NdbDictionary::Event::TE_UPDATE:
+ break;
+ default:
+ abort();
+ }
+ }
+ if (table->getColumn(i)->getPrimaryKey() &&
+ op->equal(i,recAttr[i]->aRef()))
+ {
+ g_err << "equal " << i << " "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ }
+
+ switch (pOp->getEventType()) {
+ case NdbDictionary::Event::TE_INSERT:
+ for (i= 0; i < n_columns; i++)
+ {
+ if (!table->getColumn(i)->getPrimaryKey() &&
+ op->setValue(i,recAttr[i]->isNULL() ? 0:recAttr[i]->aRef()))
+ {
+ g_err << "setValue(insert) " << i << " "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(-1);
+ }
+ }
+ break;
+ case NdbDictionary::Event::TE_DELETE:
+ break;
+ case NdbDictionary::Event::TE_UPDATE:
+ for (i= 0; i < n_columns; i++)
+ {
+ if (!table->getColumn(i)->getPrimaryKey() &&
+ recAttr[i]->isNULL() >= 0 &&
+ op->setValue(i,recAttr[i]->isNULL() ? 0:recAttr[i]->aRef()))
+ {
+ g_err << "setValue(update) " << i << " "
+ << op->getNdbError().code << " "
+ << op->getNdbError().message << endl;
+ DBUG_RETURN(NDBT_FAILED);
+ }
+ }
+ break;
+ case NdbDictionary::Event::TE_ALL:
+ abort();
+ }
+ if (trans->execute(Commit) == 0)
+ {
+ trans->close();
+ // everything ok
+ break;
+ }
+ if (noRetries++ == 10 ||
+ trans->getNdbError().status != NdbError::TemporaryError)
+ {
+ g_err << "execute " << r << " failed "
+ << trans->getNdbError().code << " "
+ << trans->getNdbError().message << endl;
+ trans->close();
+ DBUG_RETURN(-1);
+ }
+ trans->close();
+ NdbSleep_MilliSleep(100); // sleep before retying
+ } while(1);
+ }
+ }
+ }
+ DBUG_RETURN(r);
+}
+
+static int verify_copy(Ndb *ndb,
+ Vector<const NdbDictionary::Table *> &tabs1,
+ Vector<const NdbDictionary::Table *> &tabs2)
+{
+ for (unsigned i= 0; i < tabs1.size(); i++)
+ if (tabs1[i])
+ {
+ HugoTransactions hugoTrans(*tabs1[i]);
+ if (hugoTrans.compare(ndb, tabs2[i]->getName(), 0))
+ return -1;
+ }
+ return 0;
+}
+
+NDB_STD_OPTS_VARS;
+
+static const char* _dbname = "TEST_DB";
+static struct my_option my_long_options[] =
+{
+ NDB_STD_OPTS(""),
+ { "database", 'd', "Name of database table is in",
+ (gptr*) &_dbname, (gptr*) &_dbname, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+int
+main(int argc, char** argv)
+{
+ NDB_INIT(argv[0]);
+ const char *load_default_groups[]= { "mysql_cluster",0 };
+ load_defaults("my",load_default_groups,&argc,&argv);
+
+ int ho_error;
+#ifndef DBUG_OFF
+ opt_debug= "d:t:F:L";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
+ return NDBT_ProgramExit(NDBT_WRONGARGS);
+
+ DBUG_ENTER("main");
+ Ndb_cluster_connection con(opt_connect_str);
+ if(con.connect(12, 5, 1))
+ {
+ DBUG_RETURN(NDBT_ProgramExit(NDBT_FAILED));
+ }
+
+
+ Ndb ndb(&con,_dbname);
+ ndb.init();
+ while (ndb.waitUntilReady() != 0);
+
+ NdbDictionary::Dictionary * dict = ndb.getDictionary();
+ int no_error= 1;
+ int i;
+
+ // create all tables
+ Vector<const NdbDictionary::Table*> pTabs;
+ for (i= 0; no_error && argc; argc--, i++)
+ {
+ dict->dropTable(argv[i]);
+ NDBT_Tables::createTable(&ndb, argv[i]);
+ const NdbDictionary::Table *pTab= dict->getTable(argv[i]);
+ if (pTab == 0)
+ {
+ ndbout << "Failed to create table" << endl;
+ ndbout << dict->getNdbError() << endl;
+ no_error= 0;
+ break;
+ }
+ pTabs.push_back(pTab);
+ }
+ pTabs.push_back(NULL);
+
+ // create an event for each table
+ for (i= 0; no_error && pTabs[i]; i++)
+ {
+ HugoTransactions ht(*pTabs[i]);
+ if (ht.createEvent(&ndb)){
+ no_error= 0;
+ break;
+ }
+ }
+
+ // create an event operation for each event
+ Vector<NdbEventOperation *> pOps;
+ for (i= 0; no_error && pTabs[i]; i++)
+ {
+ char buf[1024];
+ sprintf(buf, "%s_EVENT", pTabs[i]->getName());
+ NdbEventOperation *pOp= ndb.createEventOperation(buf, 1000);
+ if ( pOp == NULL )
+ {
+ no_error= 0;
+ break;
+ }
+ pOps.push_back(pOp);
+ }
+
+ // get storage for each event operation
+ Vector<Vector<NdbRecAttr*> > values;
+ Vector<Vector<NdbRecAttr*> > pre_values;
+ for (i= 0; no_error && pTabs[i]; i++)
+ {
+ int n_columns= pTabs[i]->getNoOfColumns();
+ Vector<NdbRecAttr*> tmp_a;
+ Vector<NdbRecAttr*> tmp_b;
+ for (int j = 0; j < n_columns; j++) {
+ tmp_a.push_back(pOps[i]->getValue(pTabs[i]->getColumn(j)->getName()));
+ tmp_b.push_back(pOps[i]->getPreValue(pTabs[i]->getColumn(j)->getName()));
+ }
+ values.push_back(tmp_a);
+ pre_values.push_back(tmp_b);
+ }
+
+ // start receiving events
+ for (i= 0; no_error && pTabs[i]; i++)
+ {
+ if ( pOps[i]->execute() )
+ {
+ no_error= 0;
+ break;
+ }
+ }
+
+ // create a "shadow" table for each table
+ Vector<const NdbDictionary::Table*> pShadowTabs;
+ for (i= 0; no_error && pTabs[i]; i++)
+ {
+ char buf[1024];
+ sprintf(buf, "%s_SHADOW", pTabs[i]->getName());
+
+ dict->dropTable(buf);
+ if (dict->getTable(buf))
+ {
+ no_error= 0;
+ break;
+ }
+
+ NdbDictionary::Table table_shadow(*pTabs[i]);
+ table_shadow.setName(buf);
+ dict->createTable(table_shadow);
+ pShadowTabs.push_back(dict->getTable(buf));
+ if (!pShadowTabs[i])
+ {
+ no_error= 0;
+ break;
+ }
+ }
+
+ // create a hugo operation per table
+ Vector<HugoOperations *> hugo_ops;
+ for (i= 0; no_error && pTabs[i]; i++)
+ {
+ hugo_ops.push_back(new HugoOperations(*pTabs[i]));
+ }
+
+ sleep(5);
+
+ // insert 3 records per table
+ do {
+ if (start_transaction(&ndb, hugo_ops))
+ {
+ no_error= 0;
+ break;
+ }
+ for (i= 0; no_error && pTabs[i]; i++)
+ {
+ hugo_ops[i]->pkInsertRecord(&ndb, 0, 3);
+ }
+ if (execute_commit(&ndb, hugo_ops))
+ {
+ no_error= 0;
+ break;
+ }
+ if(close_transaction(&ndb, hugo_ops))
+ {
+ no_error= 0;
+ break;
+ }
+ } while(0);
+
+ // copy events and verify
+ do {
+ if (copy_events(&ndb, pOps, pShadowTabs, values) < 0)
+ {
+ no_error= 0;
+ break;
+ }
+ if (verify_copy(&ndb, pTabs, pShadowTabs))
+ {
+ no_error= 0;
+ break;
+ }
+ } while (0);
+
+ // update 2 records in first table
+ do {
+ if (start_transaction(&ndb, hugo_ops))
+ {
+ no_error= 0;
+ break;
+ }
+
+ hugo_ops[0]->pkUpdateRecord(&ndb, 2);
+
+ if (execute_commit(&ndb, hugo_ops))
+ {
+ no_error= 0;
+ break;
+ }
+ if(close_transaction(&ndb, hugo_ops))
+ {
+ no_error= 0;
+ break;
+ }
+ } while(0);
+
+ // copy events and verify
+ do {
+ if (copy_events(&ndb, pOps, pShadowTabs, values) < 0)
+ {
+ no_error= 0;
+ break;
+ }
+ if (verify_copy(&ndb, pTabs, pShadowTabs))
+ {
+ no_error= 0;
+ break;
+ }
+ } while (0);
+
+ if (no_error)
+ DBUG_RETURN(NDBT_ProgramExit(NDBT_OK));
+ DBUG_RETURN(NDBT_ProgramExit(NDBT_FAILED));
+}
+
+template class Vector<HugoOperations *>;
+template class Vector<NdbEventOperation *>;
+template class Vector<NdbRecAttr*>;
+template class Vector<Vector<NdbRecAttr*> >;
diff --git a/ndb/test/run-test/16node-tests.txt b/ndb/test/run-test/16node-tests.txt
new file mode 100644
index 00000000000..11ade56c28c
--- /dev/null
+++ b/ndb/test/run-test/16node-tests.txt
@@ -0,0 +1,733 @@
+# BASIC FUNCTIONALITY
+max-time: 500
+cmd: testBasic
+args: -n PkRead
+
+max-time: 500
+cmd: testBasic
+args: -n PkUpdate
+
+max-time: 500
+cmd: testBasic
+args: -n PkDelete
+
+max-time: 500
+cmd: testBasic
+args: -n PkInsert
+
+max-time: 600
+cmd: testBasic
+args: -n UpdateAndRead
+
+max-time: 500
+cmd: testBasic
+args: -n PkReadAndLocker T6
+
+max-time: 500
+cmd: testBasic
+args: -n PkReadAndLocker2 T6
+
+max-time: 500
+cmd: testBasic
+args: -n PkReadUpdateAndLocker T6
+
+max-time: 500
+cmd: testBasic
+args: -n ReadWithLocksAndInserts T6
+
+max-time: 500
+cmd: testBasic
+args: -n PkInsertTwice T1 T6 T10
+
+max-time: 1500
+cmd: testBasic
+args: -n Fill T13
+
+max-time: 1500
+cmd: testBasic
+args: -n Fill T6
+
+max-time: 500
+cmd: testBasic
+args: -n NoCommitSleep T6
+
+max-time: 500
+cmd: testBasic
+args: -n NoCommit626 T6
+
+max-time: 500
+cmd: testBasic
+args: -n NoCommitAndClose T6
+
+max-time: 500
+cmd: testBasic
+args: -n Commit626 T6
+
+max-time: 500
+cmd: testBasic
+args: -n CommitTry626 T6
+
+max-time: 500
+cmd: testBasic
+args: -n CommitAsMuch626 T6
+
+max-time: 500
+cmd: testBasic
+args: -n NoCommit626 T6
+
+max-time: 500
+cmd: testBasic
+args: -n NoCommitRollback626 T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n Commit630 T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n CommitTry630 T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n CommitAsMuch630 T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n NoCommit630 T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n NoCommitRollback630 T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n NoCommitAndClose T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n RollbackUpdate T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n RollbackDeleteMultiple T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n ImplicitRollbackDelete T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n CommitDelete T1 T6
+
+max-time: 500
+cmd: testBasic
+args: -n RollbackNothing T1 T6
+
+max-time: 500
+cmd: testBasicAsynch
+args: -n PkInsertAsynch
+
+max-time: 500
+cmd: testBasicAsynch
+args: -n PkReadAsynch
+
+max-time: 500
+cmd: testBasicAsynch
+args: -n PkUpdateAsynch
+
+max-time: 500
+cmd: testBasicAsynch
+args: -n PkDeleteAsynch
+
+max-time: 500
+cmd: testBasic
+args: -n MassiveRollback T1 T6 T13
+
+max-time: 500
+cmd: testBasic
+args: -n MassiveRollback2 T1 T6 T13
+
+max-time: 500
+cmd: testTimeout
+args: T1
+
+# SCAN TESTS
+#
+max-time: 500
+cmd: testScan
+args: -n ScanRead16
+
+max-time: 500
+cmd: testScan
+args: -n ScanRead240
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadCommitted240
+
+max-time: 500
+cmd: testScan
+args: -n ScanUpdate
+
+max-time: 500
+cmd: testScan
+args: -n ScanUpdate2 T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanDelete
+
+max-time: 500
+cmd: testScan
+args: -n ScanDelete2 T10
+
+max-time: 500
+cmd: testScan
+args: -n ScanUpdateAndScanRead T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadAndLocker T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadAndPkRead T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanRead488 -l 10 T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanRead488O -l 10 T6
+
+max-time: 1000
+cmd: testScan
+args: -n ScanRead488_Mixed -l 10 T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanRead488Timeout -l 10 T6
+
+max-time: 600
+cmd: testScan
+args: -n ScanRead40 -l 100 T2
+
+max-time: 1800
+cmd: testScan
+args: -n ScanRead100 -l 100 T1
+
+max-time: 600
+cmd: testScan
+args: -n ScanRead40 -l 100 T1
+
+max-time: 1800
+cmd: testScan
+args: -n ScanRead40RandomTable -l 100 T1
+
+max-time: 500
+cmd: testScan
+args: -n ScanWithLocksAndInserts T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadAbort T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadAbort15 T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadAbort240 T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanUpdateAbort16 T6
+
+max-time: 3600
+cmd: testScan
+args: -n ScanReadRestart T1 T6 T13
+
+max-time: 500
+cmd: testScan
+args: -n ScanUpdateRestart T6
+
+max-time: 500
+cmd: testScan
+args: -n CheckGetValue T6
+
+max-time: 500
+cmd: testScan
+args: -n CloseWithoutStop T6
+
+max-time: 500
+cmd: testScan
+args: -n NextScanWhenNoMore T6
+
+max-time: 500
+cmd: testScan
+args: -n ExecuteScanWithoutOpenScan T6
+
+max-time: 500
+cmd: testScan
+args: -n OnlyOpenScanOnce T6
+
+max-time: 500
+cmd: testScan
+args: -n OnlyOneOpInScanTrans T6
+
+max-time: 500
+cmd: testScan
+args: -n OnlyOneOpBeforeOpenScan T6
+
+max-time: 500
+cmd: testScan
+args: -n OnlyOneScanPerTrans T6
+
+max-time: 500
+cmd: testScan
+args: -n NoCloseTransaction T6
+
+max-time: 500
+cmd: testScan
+args: -n CheckInactivityTimeOut T6
+
+max-time: 500
+cmd: testScan
+args: -n CheckInactivityBeforeClose T6
+
+max-time: 500
+cmd: testScan
+args: -n CheckAfterTerror T6
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadError5021 T1
+
+max-time: 500
+cmd: testScan
+args: -n ScanReaderror5022 T1
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadError5023 T1
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadError5024 T1
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadError5025 T1
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadError5030 T1
+
+max-time: 500
+cmd: testScan
+args: -n InsertDelete T1 T6
+
+max-time: 500
+cmd: testScan
+args: -n CheckAfterTerror T1
+
+max-time: 500
+cmd: testScan
+args: -n ScanReadWhileNodeIsDown T1
+
+max-time: 500
+cmd: testScan
+args: -n ScanRestart T1
+
+max-time: 500
+cmd: testScan
+args: -n ScanParallelism
+
+#
+# DICT TESTS
+max-time: 1500
+cmd: testDict
+args: -n CreateAndDrop
+
+max-time: 1500
+cmd: testDict
+args: -n CreateAndDropWithData
+
+max-time: 1500
+cmd: testDict
+args: -n CreateAndDropDuring T6 T10
+
+max-time: 1500
+cmd: testDict
+args: -n CreateInvalidTables
+
+max-time: 1500
+cmd: testDict
+args: -n CreateTableWhenDbIsFull T6
+
+max-time: 1500
+cmd: testDict
+args: -n CreateMaxTables T6
+
+max-time: 500
+cmd: testDict
+args: -n FragmentTypeSingle T1
+
+max-time: 1500
+cmd: testDict
+args: -n FragmentTypeAllSmall T1 T6 T7 T8
+
+max-time: 1500
+cmd: testDict
+args: -n FragmentTypeAllLarge T1 T6 T7 T8
+
+max-time: 1500
+cmd: testDict
+args: -n TemporaryTables T1 T6 T7 T8
+
+#
+# TEST NDBAPI
+#
+max-time: 500
+cmd: testDataBuffers
+args:
+
+# Testsuite: testNdbApi
+# Number of tests: 5
+max-time: 500
+cmd: testNdbApi
+args: -n MaxNdb T6
+
+max-time: 500
+cmd: testNdbApi
+args: -n MaxTransactions T1 T6 T7 T8 T13
+
+max-time: 500
+cmd: testNdbApi
+args: -n MaxOperations T1 T6 T7 T8 T13
+
+max-time: 500
+cmd: testNdbApi
+args: -n MaxGetValue T1 T6 T7 T8 T13
+
+max-time: 500
+cmd: testNdbApi
+args: -n MaxEqual
+
+max-time: 500
+cmd: testNdbApi
+args: -n DeleteNdb T1 T6
+
+max-time: 500
+cmd: testNdbApi
+args: -n WaitUntilReady T1 T6 T7 T8 T13
+
+max-time: 500
+cmd: testNdbApi
+args: -n GetOperationNoTab T6
+
+max-time: 500
+cmd: testNdbApi
+args: -n NdbErrorOperation T6
+
+max-time: 500
+cmd: testNdbApi
+args: -n MissingOperation T6
+
+max-time: 500
+cmd: testNdbApi
+args: -n GetValueInUpdate T6
+
+max-time: 500
+cmd: testNdbApi
+args: -n UpdateWithoutKeys T6
+
+max-time: 500
+cmd: testNdbApi
+args: -n UpdateWithoutValues T6
+
+#max-time: 500
+#cmd: testInterpreter
+#args: T1
+#
+max-time: 150000
+cmd: testOperations
+args:
+
+max-time: 15000
+cmd: testTransactions
+args:
+
+max-time: 1500
+cmd: testRestartGci
+args: T6
+
+max-time: 600
+cmd: testBlobs
+args:
+
+max-time: 5000
+cmd: testOIBasic
+args:
+
+max-time: 2500
+cmd: testBitfield
+args:
+
+max-time: 2500
+cmd: testPartitioning
+args:
+
+max-time: 25000
+cmd: atrt-mysql-test-run
+args: --force
+
+#
+# INDEX
+#
+max-time: 1500
+cmd: testIndex
+args: -n CreateAll T1 T6 T13
+
+#-m 7200 1: testIndex -n InsertDeleteGentle T7
+max-time: 3600
+cmd: testIndex
+args: -n InsertDelete T1 T10
+
+#-m 3600 1: testIndex -n CreateLoadDropGentle T7
+max-time: 3600
+cmd: testIndex
+args: -n CreateLoadDrop T1 T10
+
+#
+# BACKUP
+#
+max-time: 600
+cmd: atrt-testBackup
+args: -n BackupOne T1 T6 T3 I3
+
+#
+#
+# SYSTEM RESTARTS
+#
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR3 T6
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR4 T6
+
+#
+# NODE RESTARTS
+#
+max-time: 2500
+cmd: testNodeRestart
+args: -n NoLoad T6
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n MixedPkRead T6 T8 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -l 1 -n MixedPkReadPkUpdate
+
+max-time: 2500
+cmd: testNodeRestart
+args: -l 1 -n MixedReadUpdateScan
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n CommittedRead T1
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n FullDb T6 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n RestartRandomNode T6 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n RestartRandomNodeError T6 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n RestartRandomNodeInitial T6 T13
+
+max-time: 3600
+cmd: testNodeRestart
+args: -l 1 -n RestartNFDuringNR T6 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n RestartMasterNodeError T6 T8 T13
+
+max-time: 3600
+cmd: testNodeRestart
+args: -n RestartNodeDuringLCP T6
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n TwoNodeFailure T6 T8 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n TwoMasterNodeFailure T6 T8 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n FiftyPercentFail T6 T8 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n RestartAllNodes T6 T8 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n RestartAllNodesAbort T6 T8 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n RestartAllNodesError9999 T6 T8 T13
+
+max-time: 2500
+cmd: testNodeRestart
+args: -n FiftyPercentStopAndWait T6 T8 T13
+
+#max-time: 500
+#cmd: testNodeRestart
+#args: -n StopOnError T1
+#
+#
+max-time: 2500
+cmd: testIndex
+args: -n NFNR1 T6 T13
+
+max-time: 2500
+cmd: testIndex
+args: -n NFNR2 T6 T13
+
+max-time: 2500
+cmd: testIndex
+args: -n NFNR3 T6 T13
+
+max-time: 2500
+cmd: testIndex
+args: -n BuildDuring T6
+
+max-time: 2500
+cmd: testIndex
+args: -l 2 -n SR1 T6 T13
+
+max-time: 2500
+cmd: testIndex
+args: -n NFNR1_O T6 T13
+
+max-time: 2500
+cmd: testIndex
+args: -n NFNR2_O T6 T13
+
+max-time: 2500
+cmd: testIndex
+args: -n NFNR3_O T6 T13
+
+max-time: 2500
+cmd: testIndex
+args: -n BuildDuring_O T6
+
+max-time: 2500
+cmd: testIndex
+args: -l 2 -n SR1_O T6 T13
+
+max-time: 500
+cmd: testIndex
+args: -n MixedTransaction T1
+
+max-time: 2500
+cmd: testDict
+args: -n NF1 T1 T6 T13
+
+#
+max-time: 1500
+cmd: testSystemRestart
+args: -l 1 -n SR6 T1
+
+max-time: 1500
+cmd: testSystemRestart
+args: -l 1 -n SR7 T1
+
+max-time: 1500
+cmd: testSystemRestart
+args: -l 1 -n SR8 T1
+
+max-time: 1500
+cmd: testSystemRestart
+args: -l 1 -n SR9 T1
+
+#
+max-time: 2500
+cmd: test_event
+args: -n BasicEventOperation T1 T6
+
+#
+#
+# SYSTEM RESTARTS
+#
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR1 T1
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR1 T6
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR1 T7
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR1 T8
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR2 T1
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR2 T6
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR2 T7
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR_UNDO T1
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR_UNDO T6
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR_UNDO T7
+
+max-time: 1500
+cmd: testSystemRestart
+args: -n SR_UNDO T8
+
+# OLD FLEX
+max-time: 500
+cmd: flexBench
+args: -c 25 -t 10
+
+max-time: 500
+cmd: flexHammer
+args: -r 5 -t 32
+
diff --git a/ndb/test/run-test/Makefile.am b/ndb/test/run-test/Makefile.am
index 6b3ba0bff09..1067328dcc3 100644
--- a/ndb/test/run-test/Makefile.am
+++ b/ndb/test/run-test/Makefile.am
@@ -6,7 +6,7 @@ include $(top_srcdir)/ndb/config/type_util.mk.am
include $(top_srcdir)/ndb/config/type_mgmapiclient.mk.am
test_PROGRAMS = atrt
-test_DATA=daily-basic-tests.txt daily-devel-tests.txt
+test_DATA=daily-basic-tests.txt daily-devel-tests.txt 16node-tests.txt
test_SCRIPTS=atrt-analyze-result.sh atrt-gather-result.sh atrt-setup.sh \
atrt-clear-result.sh make-config.sh make-index.sh make-html-reports.sh
diff --git a/ndb/test/run-test/basic.txt b/ndb/test/run-test/basic.txt
index a952320db08..ec9e21359e5 100644
--- a/ndb/test/run-test/basic.txt
+++ b/ndb/test/run-test/basic.txt
@@ -374,7 +374,7 @@ args: -n FragmentTypeSingle T1
max-time: 1500
cmd: testDict
-args: -n FragmentTypeAll T1 T6 T7 T8
+args: -n FragmentTypeAllSmall T1 T6 T7 T8
max-time: 1500
cmd: testDict
diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt
index e7753f758a1..b2d809ef6be 100644
--- a/ndb/test/run-test/daily-basic-tests.txt
+++ b/ndb/test/run-test/daily-basic-tests.txt
@@ -71,7 +71,7 @@ max-time: 500
cmd: testBasic
args: -n PkInsert
-max-time: 600
+max-time: 660
cmd: testBasic
args: -n UpdateAndRead
@@ -203,34 +203,9 @@ max-time: 500
cmd: testBasic
args: -n MassiveRollback2 T1 T6 T13
-#-m 500 1: testBasic -n ReadConsistency T6
max-time: 500
cmd: testTimeout
-args: -n DontTimeoutTransaction T1
-
-max-time: 500
-cmd: testTimeout
-args: -n DontTimeoutTransaction5 T1
-
-max-time: 500
-cmd: testTimeout
-args: -n TimeoutTransaction T1
-
-max-time: 500
-cmd: testTimeout
-args: -n TimeoutTransaction5 T1
-
-max-time: 500
-cmd: testTimeout
-args: -n BuddyTransNoTimeout T1
-
-max-time: 500
-cmd: testTimeout
-args: -n BuddyTransNoTimeout5 T1
-
-max-time: 500
-cmd: testTimeout
-args: -n TimeoutRandTransaction T1
+args: T1
# SCAN TESTS
#
@@ -430,14 +405,9 @@ max-time: 500
cmd: testScan
args: -l 100 -n Scan-bug8262 T7
-# OLD FLEX
-max-time: 500
-cmd: flexBench
-args: -c 25 -t 10
-
max-time: 500
-cmd: flexHammer
-args: -r 5 -t 32
+cmd: testScan
+args: -n ScanParallelism
#
# DICT TESTS
@@ -471,7 +441,7 @@ args: -n FragmentTypeSingle T1
max-time: 1500
cmd: testDict
-args: -n FragmentTypeAll T1 T6 T7 T8
+args: -n FragmentTypeAllSmall T1 T6 T7 T8
max-time: 1500
cmd: testDict
@@ -550,7 +520,7 @@ max-time: 150000
cmd: testOperations
args:
-max-time: 150000
+max-time: 15000
cmd: testTransactions
args:
@@ -562,10 +532,18 @@ max-time: 600
cmd: testBlobs
args:
-max-time: 2500
+max-time: 5000
cmd: testOIBasic
args:
+max-time: 2500
+cmd: testBitfield
+args:
+
+max-time: 2500
+cmd: testPartitioning
+args:
+
#
#
# SYSTEM RESTARTS
@@ -613,3 +591,42 @@ args: -n SR_UNDO T7
max-time: 1500
cmd: testSystemRestart
args: -n SR_UNDO T8
+
+# OLD FLEX
+max-time: 500
+cmd: flexBench
+args: -c 25 -t 10
+
+max-time: 500
+cmd: flexHammer
+args: -r 5 -t 32
+
+max-time: 300
+cmd: DbCreate
+args:
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 1
+type: bench
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 25
+type: bench
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 100
+type: bench
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 200
+type: bench
+
+max-time: 180
+cmd: DbAsyncGenerator
+args: -time 60 -p 1 -proc 25
+type: bench
+
diff --git a/ndb/test/run-test/daily-devel-tests.txt b/ndb/test/run-test/daily-devel-tests.txt
index 9812ec2ceaa..20f54e031e5 100644
--- a/ndb/test/run-test/daily-devel-tests.txt
+++ b/ndb/test/run-test/daily-devel-tests.txt
@@ -206,34 +206,5 @@ args: -l 1 -n SR9 T1
#
max-time: 2500
cmd: test_event
-args: -n BasicEventOperation T1 T6
-
-max-time: 300
-cmd: DbCreate
-args:
-
-max-time: 180
-cmd: DbAsyncGenerator
-args: -time 60 -p 1
-type: bench
-
-max-time: 180
-cmd: DbAsyncGenerator
-args: -time 60 -p 25
-type: bench
-
-max-time: 180
-cmd: DbAsyncGenerator
-args: -time 60 -p 100
-type: bench
-
-max-time: 180
-cmd: DbAsyncGenerator
-args: -time 60 -p 200
-type: bench
-
-max-time: 180
-cmd: DbAsyncGenerator
-args: -time 60 -p 1 -proc 25
-type: bench
+args: -n EventOperationApplier
diff --git a/ndb/test/src/HugoAsynchTransactions.cpp b/ndb/test/src/HugoAsynchTransactions.cpp
index f75293f5a14..5d2eb451c0b 100644
--- a/ndb/test/src/HugoAsynchTransactions.cpp
+++ b/ndb/test/src/HugoAsynchTransactions.cpp
@@ -17,11 +17,12 @@
#include <NdbSleep.h>
#include <HugoAsynchTransactions.hpp>
-HugoAsynchTransactions::HugoAsynchTransactions(const NdbDictionary::Table& _tab):
- HugoTransactions(_tab),
- transactionsCompleted(0),
- numTransactions(0),
- transactions(NULL){
+HugoAsynchTransactions::HugoAsynchTransactions(const NdbDictionary::Table& _t)
+ : HugoTransactions(_t),
+ transactionsCompleted(0),
+ numTransactions(0),
+ transactions(NULL)
+{
}
HugoAsynchTransactions::~HugoAsynchTransactions(){
diff --git a/ndb/test/src/HugoCalculator.cpp b/ndb/test/src/HugoCalculator.cpp
index 62c35c54a7a..8e01f6442bb 100644
--- a/ndb/test/src/HugoCalculator.cpp
+++ b/ndb/test/src/HugoCalculator.cpp
@@ -14,8 +14,26 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <ndb_global.h>
#include "HugoCalculator.hpp"
#include <NDBT.hpp>
+#include <Base64.hpp>
+
+static
+Uint32
+myRand(Uint64 * seed)
+{
+ const Uint64 mul= 0x5deece66dull;
+ const Uint64 add= 0xb;
+ Uint64 loc_result = *seed * mul + add;
+
+ * seed= loc_result;
+ return loc_result >> 1;
+}
+
+static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
/* *************************************************************
* HugoCalculator
@@ -40,7 +58,8 @@ HugoCalculator::HugoCalculator(const NdbDictionary::Table& tab) : m_tab(tab) {
// The "number of updates" column for this table is found in the last column
for (i=m_tab.getNoOfColumns()-1; i>=0; i--){
const NdbDictionary::Column* attr = m_tab.getColumn(i);
- if (attr->getType() == NdbDictionary::Column::Unsigned){
+ if (attr->getType() == NdbDictionary::Column::Unsigned &&
+ !attr->getPrimaryKey()){
m_updatesCol = i;
break;
}
@@ -51,29 +70,18 @@ HugoCalculator::HugoCalculator(const NdbDictionary::Table& tab) : m_tab(tab) {
#endif
// Check that idCol is not conflicting with updatesCol
assert(m_idCol != m_updatesCol && m_idCol != -1 && m_updatesCol != -1);
-};
+}
Int32
HugoCalculator::calcValue(int record,
int attrib,
int updates) const {
- const NdbDictionary::Column* attr = m_tab.getColumn(attrib);
- // If this is the "id" column
- if (attrib == m_idCol)
- return record;
-
- // If this is the update column
- if (attrib == m_updatesCol)
- return updates;
-
-
- Int32 val;
- if (attr->getPrimaryKey())
- val = record + attrib;
- else
- val = record + attrib + updates;
- return val;
-};
+
+ Int32 i;
+ calcValue(record, attrib, updates, (char*)&i, sizeof(i));
+
+ return i;
+}
#if 0
HugoCalculator::U_Int32 calcValue(int record, int attrib, int updates) const;
HugoCalculator::U_Int64 calcValue(int record, int attrib, int updates) const;
@@ -81,49 +89,121 @@ HugoCalculator::Int64 calcValue(int record, int attrib, int updates) const;
HugoCalculator::float calcValue(int record, int attrib, int updates) const;
HugoCalculator::double calcValue(int record, int attrib, int updates) const;
#endif
+
const char*
HugoCalculator::calcValue(int record,
int attrib,
int updates,
- char* buf) const {
- const char a[26] = {"UAWBORCTDPEFQGNYHISJMKXLZ"};
+ char* buf,
+ int len) const {
+ Uint64 seed;
const NdbDictionary::Column* attr = m_tab.getColumn(attrib);
- int val = calcValue(record, attrib, updates);
-
- int len;
- if (attr->getPrimaryKey()){
- // Create a string where val is printed as chars in the beginning
- // of the string, then fill with other chars
- // The string length is set to the same size as the attribute
- len = attr->getLength();
- BaseString::snprintf(buf, len, "%d", val);
- for(int i=strlen(buf); i < len; i++)
- buf[i] = a[((val^i)%25)];
- } else{
+ Uint32 val;
+ do
+ {
+ if (attrib == m_idCol)
+ {
+ val= record;
+ memcpy(buf, &val, 4);
+ return buf;
+ }
- // Fill buf with some pattern so that we can detect
- // anomalies in the area that we don't fill with chars
- int i;
- for (i = 0; i<attr->getLength(); i++)
- buf[i] = ((i+2) % 255);
+ // If this is the update column
+ if (attrib == m_updatesCol)
+ {
+ val= updates;
+ memcpy(buf, &val, 4);
+ return buf;
+ }
+
+ if (attr->getPrimaryKey())
+ {
+ seed = record + attrib;
+ }
+ else
+ {
+ seed = record + attrib + updates;
+ }
+ } while (0);
+
+ val = myRand(&seed);
+
+ if(attr->getNullable() && (((val >> 16) & 255) > 220))
+ return NULL;
+
+ int pos= 0;
+ switch(attr->getType()){
+ case NdbDictionary::Column::Tinyint:
+ case NdbDictionary::Column::Tinyunsigned:
+ case NdbDictionary::Column::Smallint:
+ case NdbDictionary::Column::Smallunsigned:
+ case NdbDictionary::Column::Mediumint:
+ case NdbDictionary::Column::Mediumunsigned:
+ case NdbDictionary::Column::Int:
+ case NdbDictionary::Column::Unsigned:
+ case NdbDictionary::Column::Bigint:
+ case NdbDictionary::Column::Bigunsigned:
+ case NdbDictionary::Column::Float:
+ case NdbDictionary::Column::Double:
+ case NdbDictionary::Column::Olddecimal:
+ case NdbDictionary::Column::Olddecimalunsigned:
+ case NdbDictionary::Column::Decimal:
+ case NdbDictionary::Column::Decimalunsigned:
+ case NdbDictionary::Column::Binary:
+ case NdbDictionary::Column::Datetime:
+ case NdbDictionary::Column::Time:
+ case NdbDictionary::Column::Date:
+ case NdbDictionary::Column::Bit:
+ while (len > 4)
+ {
+ memcpy(buf+pos, &val, 4);
+ pos += 4;
+ len -= 4;
+ val= myRand(&seed);
+ }
- // Calculate length of the string to create. We want the string
- // length to be varied between max and min of this attribute.
-
- len = val % (attr->getLength() + 1);
- // If len == 0 return NULL if this is a nullable attribute
- if (len == 0){
- if(attr->getNullable() == true)
- return NULL;
- else
- len++;
+ memcpy(buf+pos, &val, len);
+ if(attr->getType() == NdbDictionary::Column::Bit)
+ {
+ Uint32 bits= attr->getLength();
+ Uint32 tmp = bits >> 5;
+ Uint32 size = bits & 31;
+ ((Uint32*)buf)[tmp] &= ((1 << size) - 1);
}
- for(i=0; i < len; i++)
- buf[i] = a[((val^i)%25)];
- buf[len] = 0;
+ break;
+ case NdbDictionary::Column::Varbinary:
+ case NdbDictionary::Column::Varchar:
+ case NdbDictionary::Column::Text:
+ case NdbDictionary::Column::Char:
+ case NdbDictionary::Column::Longvarchar:
+ case NdbDictionary::Column::Longvarbinary:
+ {
+ char* ptr= (char*)&val;
+ while(len >= 4)
+ {
+ len -= 4;
+ buf[pos++] = base64_table[ptr[0] & 0x3f];
+ buf[pos++] = base64_table[ptr[1] & 0x3f];
+ buf[pos++] = base64_table[ptr[2] & 0x3f];
+ buf[pos++] = base64_table[ptr[3] & 0x3f];
+ val= myRand(&seed);
+ }
+
+ for(; len; len--, pos++)
+ buf[pos] = base64_table[ptr[len] & 0x3f];
+
+ pos--;
+ break;
}
+ case NdbDictionary::Column::Blob:
+ case NdbDictionary::Column::Undefined:
+ abort();
+ break;
+ }
+
+
return buf;
-};
+}
int
HugoCalculator::verifyRowValues(NDBT_ResultRow* const pRow) const{
@@ -131,104 +211,48 @@ HugoCalculator::verifyRowValues(NDBT_ResultRow* const pRow) const{
id = pRow->attributeStore(m_idCol)->u_32_value();
updates = pRow->attributeStore(m_updatesCol)->u_32_value();
-
+ int result = 0;
+
// Check the values of each column
for (int i = 0; i<m_tab.getNoOfColumns(); i++){
if (i != m_updatesCol && id != m_idCol) {
-
const NdbDictionary::Column* attr = m_tab.getColumn(i);
- switch (attr->getType()){
- case NdbDictionary::Column::Char:
- case NdbDictionary::Column::Varchar:
- case NdbDictionary::Column::Binary:
- case NdbDictionary::Column::Varbinary:{
- int result = 0;
- char* buf = new char[attr->getLength()+1];
- const char* res = calcValue(id, i, updates, buf);
- if (res == NULL){
- if (!pRow->attributeStore(i)->isNULL()){
- g_err << "|- NULL ERROR: expected a NULL but the column was not null" << endl;
- g_err << "|- The row: \"" << (*pRow) << "\"" << endl;
- result = -1;
- }
- } else{
- if (memcmp(res, pRow->attributeStore(i)->aRef(), pRow->attributeStore(i)->arraySize()) != 0){
- // if (memcmp(res, pRow->attributeStore(i)->aRef(), pRow->attributeStore(i)->getLength()) != 0){
- g_err << "arraySize(): "
- << pRow->attributeStore(i)->arraySize()
- << ", NdbDict::Column::getLength(): " << attr->getLength()
- << endl;
- const char* buf2 = pRow->attributeStore(i)->aRef();
- for (Uint32 j = 0; j < pRow->attributeStore(i)->arraySize(); j++)
+ Uint32 len = attr->getSizeInBytes();
+ char buf[8000];
+ const char* res = calcValue(id, i, updates, buf, len);
+ if (res == NULL){
+ if (!pRow->attributeStore(i)->isNULL()){
+ g_err << "|- NULL ERROR: expected a NULL but the column was not null" << endl;
+ g_err << "|- The row: \"" << (*pRow) << "\"" << endl;
+ result = -1;
+ }
+ } else{
+ if (memcmp(res, pRow->attributeStore(i)->aRef(), len) != 0){
+ g_err << "Column: " << attr->getName() << endl;
+ const char* buf2 = pRow->attributeStore(i)->aRef();
+ for (Uint32 j = 0; j < len; j++)
+ {
+ g_err << j << ":" << hex << (Uint32)(Uint8)buf[j] << "[" << hex << (Uint32)(Uint8)buf2[j] << "]";
+ if (buf[j] != buf2[j])
{
- g_err << j << ":" << buf[j] << "[" << buf2[j] << "]";
- if (buf[j] != buf2[j])
- {
- g_err << "==>Match failed!";
- }
- g_err << endl;
+ g_err << "==>Match failed!";
}
g_err << endl;
- g_err << "|- Invalid data found in attribute " << i << ": \""
- << pRow->attributeStore(i)->aRef()
- << "\" != \"" << res << "\"" << endl
- << "Length of expected=" << (unsigned)strlen(res) << endl
- << "Lenght of read="
- << (unsigned)strlen(pRow->attributeStore(i)->aRef()) << endl;
- g_err << "|- The row: \"" << (* pRow) << "\"" << endl;
- result = -1;
}
- }
- delete []buf;
- if (result != 0)
- return result;
- }
- break;
- case NdbDictionary::Column::Int:
- case NdbDictionary::Column::Unsigned:{
- Int32 cval = calcValue(id, i, updates);
- Int32 val = pRow->attributeStore(i)->int32_value();
- if (val != cval){
- g_err << "|- Invalid data found: \"" << val << "\" != \""
- << cval << "\"" << endl;
- g_err << "|- The row: \"" << (* pRow) << "\"" << endl;
- return -1;
- }
- break;
- }
- case NdbDictionary::Column::Bigint:
- case NdbDictionary::Column::Bigunsigned:{
- Uint64 cval = calcValue(id, i, updates);
- Uint64 val = pRow->attributeStore(i)->u_64_value();
- if (val != cval){
- g_err << "|- Invalid data found: \"" << val << "\" != \""
- << cval << "\""
- << endl;
+ g_err << endl;
+ g_err << "|- Invalid data found in attribute " << i << ": \""
+ << pRow->attributeStore(i)->aRef()
+ << "\" != \"" << res << "\"" << endl
+ << "Length of expected=" << (unsigned)strlen(res) << endl
+ << "Lenght of read="
+ << (unsigned)strlen(pRow->attributeStore(i)->aRef()) << endl;
g_err << "|- The row: \"" << (* pRow) << "\"" << endl;
- return -1;
+ result = -1;
}
}
- break;
- case NdbDictionary::Column::Float:{
- float cval = calcValue(id, i, updates);
- float val = pRow->attributeStore(i)->float_value();
- if (val != cval){
- g_err << "|- Invalid data found: \"" << val << "\" != \""
- << cval << "\"" << endl;
- g_err << "|- The row: \"" << (* pRow) << "\"" << endl;
- return -1;
- }
- }
- break;
- case NdbDictionary::Column::Undefined:
- default:
- assert(false);
- break;
- }
-
}
}
- return 0;
+ return result;
}
int
diff --git a/ndb/test/src/HugoOperations.cpp b/ndb/test/src/HugoOperations.cpp
index 8e6603ec6ff..3dcbe3d5ffd 100644
--- a/ndb/test/src/HugoOperations.cpp
+++ b/ndb/test/src/HugoOperations.cpp
@@ -32,6 +32,19 @@ int HugoOperations::startTransaction(Ndb* pNdb){
return NDBT_OK;
}
+int HugoOperations::setTransaction(NdbTransaction* new_trans){
+
+ if (pTrans != NULL){
+ ndbout << "HugoOperations::startTransaction, pTrans != NULL" << endl;
+ return NDBT_FAILED;
+ }
+ pTrans = new_trans;
+ if (pTrans == NULL) {
+ return NDBT_FAILED;
+ }
+ return NDBT_OK;
+}
+
void
HugoOperations::setTransactionId(Uint64 id){
if (pTrans != NULL){
@@ -64,8 +77,16 @@ int HugoOperations::pkReadRecord(Ndb* pNdb,
int a;
allocRows(numRecords);
int check;
+
+ NdbOperation* pOp = 0;
+ pIndexScanOp = 0;
+
for(int r=0; r < numRecords; r++){
- NdbOperation* pOp = pTrans->getNdbOperation(tab.getName());
+
+ if(pOp == 0)
+ {
+ pOp = getOperation(pTrans, NdbOperation::ReadRequest);
+ }
if (pOp == NULL) {
ERR(pTrans->getNdbError());
return NDBT_FAILED;
@@ -74,13 +95,16 @@ int HugoOperations::pkReadRecord(Ndb* pNdb,
rand_lock_mode:
switch(lm){
case NdbOperation::LM_Read:
- check = pOp->readTuple();
- break;
case NdbOperation::LM_Exclusive:
- check = pOp->readTupleExclusive();
- break;
case NdbOperation::LM_CommittedRead:
- check = pOp->dirtyRead();
+ if(idx && idx->getType() == NdbDictionary::Index::OrderedIndex &&
+ pIndexScanOp == 0)
+ {
+ pIndexScanOp = ((NdbIndexScanOperation*)pOp);
+ check = pIndexScanOp->readTuples(lm);
+ }
+ else
+ check = pOp->readTuple(lm);
break;
default:
lm = (NdbOperation::LockMode)((rand() >> 16) & 3);
@@ -101,15 +125,22 @@ rand_lock_mode:
}
}
}
+
+ if(pIndexScanOp)
+ pIndexScanOp->end_of_bound(r);
- // Define attributes to read
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if((rows[r]->attributeStore(a) =
- pOp->getValue(tab.getColumn(a)->getName())) == 0) {
- ERR(pTrans->getNdbError());
- return NDBT_FAILED;
- }
- }
+ if(r == 0 || pIndexScanOp == 0)
+ {
+ // Define attributes to read
+ for(a = 0; a<tab.getNoOfColumns(); a++){
+ if((rows[r]->attributeStore(a) =
+ pOp->getValue(tab.getColumn(a)->getName())) == 0) {
+ ERR(pTrans->getNdbError());
+ return NDBT_FAILED;
+ }
+ }
+ }
+ pOp = pIndexScanOp;
}
return NDBT_OK;
}
@@ -122,7 +153,7 @@ int HugoOperations::pkUpdateRecord(Ndb* pNdb,
allocRows(numRecords);
int check;
for(int r=0; r < numRecords; r++){
- NdbOperation* pOp = pTrans->getNdbOperation(tab.getName());
+ NdbOperation* pOp = getOperation(pTrans, NdbOperation::UpdateRequest);
if (pOp == NULL) {
ERR(pTrans->getNdbError());
return NDBT_FAILED;
@@ -134,26 +165,37 @@ int HugoOperations::pkUpdateRecord(Ndb* pNdb,
return NDBT_FAILED;
}
- // Define primary keys
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == true){
- if(equalForAttr(pOp, a, r+recordNo) != 0){
- ERR(pTrans->getNdbError());
- return NDBT_FAILED;
- }
+ if(setValues(pOp, r+recordNo, updatesValue) != NDBT_OK)
+ {
+ return NDBT_FAILED;
+ }
+ }
+ return NDBT_OK;
+}
+
+int
+HugoOperations::setValues(NdbOperation* pOp, int rowId, int updateId)
+{
+ // Define primary keys
+ int a;
+ for(a = 0; a<tab.getNoOfColumns(); a++){
+ if (tab.getColumn(a)->getPrimaryKey() == true){
+ if(equalForAttr(pOp, a, rowId) != 0){
+ ERR(pTrans->getNdbError());
+ return NDBT_FAILED;
}
}
-
- // Define attributes to update
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == false){
- if(setValueForAttr(pOp, a, recordNo+r, updatesValue ) != 0){
- ERR(pTrans->getNdbError());
- return NDBT_FAILED;
- }
+ }
+
+ for(a = 0; a<tab.getNoOfColumns(); a++){
+ if (tab.getColumn(a)->getPrimaryKey() == false){
+ if(setValueForAttr(pOp, a, rowId, updateId ) != 0){
+ ERR(pTrans->getNdbError());
+ return NDBT_FAILED;
}
- }
+ }
}
+
return NDBT_OK;
}
@@ -164,7 +206,7 @@ int HugoOperations::pkInsertRecord(Ndb* pNdb,
int a, check;
for(int r=0; r < numRecords; r++){
- NdbOperation* pOp = pTrans->getNdbOperation(tab.getName());
+ NdbOperation* pOp = getOperation(pTrans, NdbOperation::InsertRequest);
if (pOp == NULL) {
ERR(pTrans->getNdbError());
return NDBT_FAILED;
@@ -176,25 +218,10 @@ int HugoOperations::pkInsertRecord(Ndb* pNdb,
return NDBT_FAILED;
}
- // Define primary keys
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == true){
- if(equalForAttr(pOp, a, r+recordNo) != 0){
- ERR(pTrans->getNdbError());
- return NDBT_FAILED;
- }
- }
+ if(setValues(pOp, r+recordNo, updatesValue) != NDBT_OK)
+ {
+ return NDBT_FAILED;
}
-
- // Define attributes to update
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == false){
- if(setValueForAttr(pOp, a, recordNo+r, updatesValue ) != 0){
- ERR(pTrans->getNdbError());
- return NDBT_FAILED;
- }
- }
- }
}
return NDBT_OK;
}
@@ -205,7 +232,7 @@ int HugoOperations::pkDeleteRecord(Ndb* pNdb,
int a, check;
for(int r=0; r < numRecords; r++){
- NdbOperation* pOp = pTrans->getNdbOperation(tab.getName());
+ NdbOperation* pOp = getOperation(pTrans, NdbOperation::DeleteRequest);
if (pOp == NULL) {
ERR(pTrans->getNdbError());
return NDBT_FAILED;
@@ -229,65 +256,6 @@ int HugoOperations::pkDeleteRecord(Ndb* pNdb,
}
return NDBT_OK;
}
-#if 0
-NdbResultSet*
-HugoOperations::scanReadRecords(Ndb* pNdb, ScanLock lock){
-
- NDBT_ResultRow * m_tmpRow = new NDBT_ResultRow(tab);
-
- NdbScanOperation* pOp = pTrans->getNdbScanOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- return 0;
- }
-
-
- int check = 0;
- NdbResultSet * rs = 0;
- switch(lock){
- case SL_ReadHold:
- rs = pOp->readTuples(NdbScanOperation::LM_Read, 1, 1);
- break;
- case SL_Exclusive:
- rs = pOp->readTuples(NdbScanOperation::LM_Exclusive, 1, 1);
- break;
- case SL_Read:
- default:
- rs = pOp->readTuples(NdbScanOperation::LM_Dirty, 1, 1);
- }
-
- if( rs == 0) {
- ERR(pTrans->getNdbError());
- return 0;
- }
-
- check = pOp->interpret_exit_ok();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- return 0;
- }
-
- // Define attributes to read
- for(int a = 0; a<tab.getNoOfColumns(); a++){
- if((m_tmpRow->attributeStore(a) =
- pOp->getValue(tab.getColumn(a)->getName())) == 0) {
- ERR(pTrans->getNdbError());
- return 0;
- }
- }
- return rs;
-}
-
-int
-HugoOperations::readTuples(NdbResultSet* rs){
- int res = 0;
- while((res = rs->nextResult()) == 0){
- }
- if(res != 1)
- return NDBT_FAILED;
- return NDBT_OK;
-}
-#endif
int HugoOperations::execute_Commit(Ndb* pNdb,
AbortOption eao){
@@ -312,7 +280,7 @@ int HugoOperations::execute_Commit(Ndb* pNdb,
m_executed_result_sets.push_back(m_result_sets[i]);
int rows = m_result_sets[i].records;
- NdbResultSet* rs = m_result_sets[i].m_result_set;
+ NdbScanOperation* rs = m_result_sets[i].m_result_set;
int res = rs->nextResult();
switch(res){
case 1:
@@ -361,7 +329,7 @@ int HugoOperations::execute_NoCommit(Ndb* pNdb, AbortOption eao){
m_executed_result_sets.push_back(m_result_sets[i]);
int rows = m_result_sets[i].records;
- NdbResultSet* rs = m_result_sets[i].m_result_set;
+ NdbScanOperation* rs = m_result_sets[i].m_result_set;
int res = rs->nextResult();
switch(res){
case 1:
@@ -399,11 +367,11 @@ int HugoOperations::execute_Rollback(Ndb* pNdb){
return NDBT_OK;
}
-HugoOperations::HugoOperations(const NdbDictionary::Table& _tab):
- UtilTransactions(_tab),
- calc(_tab),
- pTrans(NULL){
-
+HugoOperations::HugoOperations(const NdbDictionary::Table& _tab,
+ const NdbDictionary::Index* idx):
+ UtilTransactions(_tab, idx),
+ calc(_tab)
+{
}
HugoOperations::~HugoOperations(){
@@ -418,101 +386,32 @@ HugoOperations::~HugoOperations(){
int HugoOperations::equalForAttr(NdbOperation* pOp,
int attrId,
int rowId){
- int check = 0;
+ int check = -1;
const NdbDictionary::Column* attr = tab.getColumn(attrId);
if (attr->getPrimaryKey() == false){
g_info << "Can't call equalForAttr on non PK attribute" << endl;
return NDBT_FAILED;
}
- switch (attr->getType()){
- case NdbDictionary::Column::Char:
- case NdbDictionary::Column::Varchar:
- case NdbDictionary::Column::Binary:
- case NdbDictionary::Column::Varbinary:{
- char buf[8000];
- memset(buf, 0, sizeof(buf));
- check = pOp->equal( attr->getName(), calc.calcValue(rowId, attrId, 0, buf));
- break;
- }
- case NdbDictionary::Column::Int:
- check = pOp->equal( attr->getName(), (Int32)calc.calcValue(rowId, attrId, 0));
- break;
- case NdbDictionary::Column::Unsigned:
- check = pOp->equal( attr->getName(), (Uint32)calc.calcValue(rowId, attrId, 0));
- break;
- case NdbDictionary::Column::Bigint:
- check = pOp->equal( attr->getName(), (Int64)calc.calcValue(rowId, attrId, 0));
- break;
- case NdbDictionary::Column::Bigunsigned:
- check = pOp->equal( attr->getName(), (Uint64)calc.calcValue(rowId, attrId, 0));
- break;
- case NdbDictionary::Column::Float:
- g_info << "Float not allowed as PK value" << endl;
- check = -1;
- break;
-
- default:
- g_info << "default" << endl;
- check = -1;
- break;
- }
- return check;
+ int len = attr->getSizeInBytes();
+ char buf[8000];
+ memset(buf, 0, sizeof(buf));
+ return pOp->equal( attr->getName(),
+ calc.calcValue(rowId, attrId, 0, buf, len));
}
int HugoOperations::setValueForAttr(NdbOperation* pOp,
int attrId,
int rowId,
int updateId){
- int check = 0;
+ int check = -1;
const NdbDictionary::Column* attr = tab.getColumn(attrId);
-
- if (attr->getTupleKey()){
- // Don't set values for TupleId PKs
- return check;
- }
- switch (attr->getType()){
- case NdbDictionary::Column::Char:
- case NdbDictionary::Column::Varchar:
- case NdbDictionary::Column::Binary:
- case NdbDictionary::Column::Varbinary:{
- char buf[8000];
- check = pOp->setValue( attr->getName(),
- calc.calcValue(rowId, attrId, updateId, buf));
- break;
- }
- case NdbDictionary::Column::Int:{
- Int32 val = calc.calcValue(rowId, attrId, updateId);
- check = pOp->setValue( attr->getName(), val);
- }
- break;
- case NdbDictionary::Column::Bigint:{
- Int64 val = calc.calcValue(rowId, attrId, updateId);
- check = pOp->setValue( attr->getName(),
- val);
- }
- break;
- case NdbDictionary::Column::Unsigned:{
- Uint32 val = calc.calcValue(rowId, attrId, updateId);
- check = pOp->setValue( attr->getName(), val);
- }
- break;
- case NdbDictionary::Column::Bigunsigned:{
- Uint64 val = calc.calcValue(rowId, attrId, updateId);
- check = pOp->setValue( attr->getName(),
- val);
- }
- break;
- case NdbDictionary::Column::Float:
- check = pOp->setValue( attr->getName(),
- (float)calc.calcValue(rowId, attrId, updateId));
- break;
- default:
- check = -1;
- break;
- }
- return check;
+ int len = attr->getSizeInBytes();
+ char buf[8000];
+ memset(buf, 0, sizeof(buf));
+ return pOp->setValue( attr->getName(),
+ calc.calcValue(rowId, attrId, updateId, buf, len));
}
int
@@ -528,7 +427,7 @@ HugoOperations::verifyUpdatesValue(int updatesValue, int _numRows){
result = NDBT_FAILED;
continue;
}
-
+
if(calc.getUpdatesValue(rows[i]) != updatesValue){
result = NDBT_FAILED;
g_err << "Invalid updates value for row " << i << endl
@@ -538,7 +437,7 @@ HugoOperations::verifyUpdatesValue(int updatesValue, int _numRows){
continue;
}
}
-
+
if(_numRows == 0){
g_err << "No rows -> Invalid updates value" << endl;
return NDBT_FAILED;
@@ -548,14 +447,12 @@ HugoOperations::verifyUpdatesValue(int updatesValue, int _numRows){
}
void HugoOperations::allocRows(int _numRows){
- deallocRows();
-
if(_numRows <= 0){
g_info << "Illegal value for num rows : " << _numRows << endl;
abort();
}
- for(int b=0; b<_numRows; b++){
+ for(int b=rows.size(); b<_numRows; b++){
rows.push_back(new NDBT_ResultRow(tab));
}
}
@@ -716,12 +613,10 @@ HugoOperations::scanReadRecords(Ndb* pNdb, NdbScanOperation::LockMode lm,
if(!pOp)
return -1;
- NdbResultSet * rs = pOp->readTuples(lm, 1, 1);
-
- if(!rs){
+ if(pOp->readTuples(lm, 1, 1)){
return -1;
}
-
+
for(int a = 0; a<tab.getNoOfColumns(); a++){
if((rows[0]->attributeStore(a) =
pOp->getValue(tab.getColumn(a)->getName())) == 0) {
@@ -729,8 +624,8 @@ HugoOperations::scanReadRecords(Ndb* pNdb, NdbScanOperation::LockMode lm,
return NDBT_FAILED;
}
}
-
- RsPair p = {rs, records};
+
+ RsPair p = {pOp, records};
m_result_sets.push_back(p);
return 0;
diff --git a/ndb/test/src/HugoTransactions.cpp b/ndb/test/src/HugoTransactions.cpp
index 5d5b2fa99df..bfe7ea72394 100644
--- a/ndb/test/src/HugoTransactions.cpp
+++ b/ndb/test/src/HugoTransactions.cpp
@@ -18,8 +18,9 @@
#include <NdbSleep.h>
-HugoTransactions::HugoTransactions(const NdbDictionary::Table& _tab):
- HugoOperations(_tab),
+HugoTransactions::HugoTransactions(const NdbDictionary::Table& _tab,
+ const NdbDictionary::Index* idx):
+ HugoOperations(_tab, idx),
row(_tab){
m_defaultScanUpdateMethod = 3;
@@ -64,17 +65,14 @@ HugoTransactions::scanReadRecords(Ndb* pNdb,
return NDBT_FAILED;
}
- pOp = pTrans->getNdbScanOperation(tab.getName());
+ pOp = getScanOperation(pTrans);
if (pOp == NULL) {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
return NDBT_FAILED;
}
- NdbResultSet * rs;
- rs = pOp ->readTuples(lm);
-
- if( rs == 0 ) {
+ if( pOp ->readTuples(lm, 0, parallelism) ) {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
return NDBT_FAILED;
@@ -123,7 +121,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb,
int eof;
int rows = 0;
- while((eof = rs->nextResult(true)) == 0){
+ while((eof = pOp->nextResult(true)) == 0){
rows++;
if (calc.verifyRowValues(&row) != 0){
closeTransaction(pNdb);
@@ -133,7 +131,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb,
if (abortCount == rows && abortTrans == true){
ndbout << "Scan is aborted" << endl;
g_info << "Scan is aborted" << endl;
- rs->close();
+ pOp->close();
if( check == -1 ) {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
@@ -226,10 +224,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb,
return NDBT_FAILED;
}
- NdbResultSet * rs;
- rs = pOp ->readTuples(lm, 0, parallelism, sorted);
-
- if( rs == 0 ) {
+ if( pOp ->readTuples(lm, 0, parallelism, sorted) ) {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
return NDBT_FAILED;
@@ -278,7 +273,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb,
int eof;
int rows = 0;
- while((eof = rs->nextResult(true)) == 0){
+ while((eof = pOp->nextResult(true)) == 0){
rows++;
if (calc.verifyRowValues(&row) != 0){
closeTransaction(pNdb);
@@ -288,7 +283,7 @@ HugoTransactions::scanReadRecords(Ndb* pNdb,
if (abortCount == rows && abortTrans == true){
ndbout << "Scan is aborted" << endl;
g_info << "Scan is aborted" << endl;
- rs->close();
+ pOp->close();
if( check == -1 ) {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
@@ -361,161 +356,7 @@ HugoTransactions::scanUpdateRecords1(Ndb* pNdb,
int records,
int abortPercent,
int parallelism){
-#if 1
return scanUpdateRecords3(pNdb, records, abortPercent, 1);
-#else
- int retryAttempt = 0;
- const int retryMax = 100;
- int check, a;
- NdbOperation *pOp;
-
-
- while (true){
-
- if (retryAttempt >= retryMax){
- g_info << "ERROR: has retried this operation " << retryAttempt
- << " times, failing!" << endl;
- return NDBT_FAILED;
- }
-
- pTrans = pNdb->startTransaction();
- if (pTrans == NULL) {
- const NdbError err = pNdb->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
- ERR(err);
- return NDBT_FAILED;
- }
-
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pOp->openScanExclusive(parallelism);
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pOp->interpret_exit_ok();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- // Read all attributes from this table
- for(a=0; a<tab.getNoOfColumns(); a++){
- if((row.attributeStore(a) = pOp->getValue(tab.getColumn(a)->getName())) == NULL){
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
-
- check = pTrans->executeScan();
- if( check == -1 ) {
- const NdbError err = pTrans->getNdbError();
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- closeTransaction(pNdb);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
- ERR(err);
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- // Abort after 1-100 or 1-records rows
- int ranVal = rand();
- int abortCount = ranVal % (records == 0 ? 100 : records);
- bool abortTrans = false;
- if (abort > 0){
- // Abort if abortCount is less then abortPercent
- if (abortCount < abortPercent)
- abortTrans = true;
- }
-
-
- int eof;
- int rows = 0;
-
- eof = pTrans->nextScanResult();
- while(eof == 0){
- rows++;
-
- if (abortCount == rows && abortTrans == true){
- g_info << "Scan is aborted" << endl;
- // This scan should be aborted
- check = pTrans->stopScan();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- closeTransaction(pNdb);
- return NDBT_OK;
- }
- int res = takeOverAndUpdateRecord(pNdb, pOp);
- if(res == RESTART_SCAN){
- eof = -2;
- continue;
- }
- if (res != 0){
- closeTransaction(pNdb);
- return res;
- }
-
- eof = pTrans->nextScanResult();
- }
- if (eof == -1) {
- const NdbError err = pTrans->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- NdbSleep_MilliSleep(50);
- switch (err.code){
- case 488:
- case 245:
- case 490:
- // Too many active scans, no limit on number of retry attempts
- break;
- default:
- retryAttempt++;
- }
- continue;
- }
- ERR(err);
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- if(eof == -2){
- closeTransaction(pNdb);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
-
- closeTransaction(pNdb);
-
- g_info << rows << " rows have been updated" << endl;
- return NDBT_OK;
- }
- return NDBT_FAILED;
-#endif
}
// Scan all records exclusive and update
@@ -527,166 +368,7 @@ HugoTransactions::scanUpdateRecords2(Ndb* pNdb,
int records,
int abortPercent,
int parallelism){
-#if 1
return scanUpdateRecords3(pNdb, records, abortPercent, parallelism);
-#else
- int retryAttempt = 0;
- const int retryMax = 100;
- int check, a;
- NdbOperation *pOp;
-
-
- while (true){
-
- if (retryAttempt >= retryMax){
- g_info << "ERROR: has retried this operation " << retryAttempt
- << " times, failing!" << endl;
- return NDBT_FAILED;
- }
-
- pTrans = pNdb->startTransaction();
- if (pTrans == NULL) {
- const NdbError err = pNdb->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
- ERR(err);
- return NDBT_FAILED;
- }
-
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pOp->openScanExclusive(parallelism);
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pOp->interpret_exit_ok();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- // Read all attributes from this table
- for(a=0; a<tab.getNoOfColumns(); a++){
- if((row.attributeStore(a) = pOp->getValue(tab.getColumn(a)->getName())) == NULL){
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
-
- check = pTrans->executeScan();
- if( check == -1 ) {
- const NdbError err = pTrans->getNdbError();
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- closeTransaction(pNdb);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
- ERR(err);
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- // Abort after 1-100 or 1-records rows
- int ranVal = rand();
- int abortCount = ranVal % (records == 0 ? 100 : records);
- bool abortTrans = false;
- if (abort > 0){
- // Abort if abortCount is less then abortPercent
- if (abortCount < abortPercent)
- abortTrans = true;
- }
-
- int eof;
- int rows = 0;
-
- while((eof = pTrans->nextScanResult(true)) == 0){
- pUpTrans = pNdb->startTransaction();
- if (pUpTrans == NULL) {
- const NdbError err = pNdb->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
- ERR(err);
- return NDBT_FAILED;
- }
- do {
- rows++;
- if (addRowToUpdate(pNdb, pUpTrans, pOp) != 0){
- pNdb->closeTransaction(pUpTrans);
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- } while((eof = pTrans->nextScanResult(false)) == 0);
-
- if (abortCount == rows && abortTrans == true){
- g_info << "Scan is aborted" << endl;
- // This scan should be aborted
- check = pTrans->stopScan();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- pNdb->closeTransaction(pUpTrans);
- return NDBT_FAILED;
- }
-
- closeTransaction(pNdb);
- pNdb->closeTransaction(pUpTrans);
- return NDBT_OK;
- }
-
- check = pUpTrans->execute(Commit);
- if( check == -1 ) {
- const NdbError err = pUpTrans->getNdbError();
- ERR(err);
- pNdb->closeTransaction(pUpTrans);
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- pNdb->closeTransaction(pUpTrans);
- }
- if (eof == -1) {
- const NdbError err = pTrans->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- closeTransaction(pNdb);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
- ERR(err);
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- closeTransaction(pNdb);
-
- g_info << rows << " rows have been updated" << endl;
- return NDBT_OK;
- }
- return NDBT_FAILED;
-#endif
}
int
@@ -719,15 +401,14 @@ restart:
return NDBT_FAILED;
}
- pOp = pTrans->getNdbScanOperation(tab.getName());
+ pOp = getScanOperation(pTrans);
if (pOp == NULL) {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
return NDBT_FAILED;
}
- NdbResultSet *rs = pOp->readTuplesExclusive(parallelism);
- if( rs == 0 ) {
+ if( pOp->readTuplesExclusive(parallelism) ) {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
return NDBT_FAILED;
@@ -765,10 +446,10 @@ restart:
}
int rows = 0;
- while((check = rs->nextResult(true)) == 0){
+ while((check = pOp->nextResult(true)) == 0){
do {
rows++;
- NdbOperation* pUp = rs->updateTuple();
+ NdbOperation* pUp = pOp->updateCurrentTuple();
if(pUp == 0){
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
@@ -792,7 +473,7 @@ restart:
closeTransaction(pNdb);
return NDBT_OK;
}
- } while((check = rs->nextResult(false)) == 0);
+ } while((check = pOp->nextResult(false)) == 0);
if(check != -1){
check = pTrans->execute(Commit);
@@ -858,7 +539,11 @@ HugoTransactions::loadTable(Ndb* pNdb,
g_info << "|- Inserting records..." << endl;
for (int c=0 ; c<records ; ){
- bool closeTrans;
+ bool closeTrans = true;
+
+ if(c + batch > records)
+ batch = records - c;
+
if (retryAttempt >= retryMax){
g_info << "Record " << c << " could not be inserted, has retried "
<< retryAttempt << " times " << endl;
@@ -887,30 +572,11 @@ HugoTransactions::loadTable(Ndb* pNdb,
}
}
- for(int b = 0; b < batch && c+b<records; b++){
-
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pOp->insertTuple();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- // Set a calculated value for each attribute in this table
- for (a = 0; a<tab.getNoOfColumns(); a++){
- if(setValueForAttr(pOp, a, c+b, 0 ) != 0){
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
+ if(pkInsertRecord(pNdb, c, batch) != NDBT_OK)
+ {
+ ERR(pTrans->getNdbError());
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
}
// Execute the transaction and insert the record
@@ -976,6 +642,9 @@ HugoTransactions::loadTable(Ndb* pNdb,
c = c+batch;
retryAttempt = 0;
}
+
+ if(pTrans)
+ closeTransaction(pNdb);
return NDBT_OK;
}
@@ -986,8 +655,20 @@ HugoTransactions::fillTable(Ndb* pNdb,
int retryAttempt = 0;
int retryMax = 5;
NdbOperation *pOp;
+
+ const int org = batch;
+ const int cols = tab.getNoOfColumns();
+ const int brow = tab.getRowSizeInBytes();
+ const int bytes = 12 + brow + 4 * cols;
+ batch = (batch * 256); // -> 512 -> 65536k per commit
+ batch = batch/bytes; //
+ batch = batch == 0 ? 1 : batch;
+
+ if(batch != org){
+ g_info << "batch = " << org << " rowsize = " << bytes
+ << " -> rows/commit = " << batch << endl;
+ }
- g_info << "|- Inserting records..." << endl;
for (int c=0 ; ; ){
if (retryAttempt >= retryMax){
@@ -1012,30 +693,11 @@ HugoTransactions::fillTable(Ndb* pNdb,
return NDBT_FAILED;
}
- for(b = 0; b < batch; b++){
-
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pOp->insertTuple();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- // Set a calculated value for each attribute in this table
- for (a = 0; a<tab.getNoOfColumns(); a++){
- if(setValueForAttr(pOp, a, c+b, 0 ) != 0){
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
+ if(pkInsertRecord(pNdb, c, batch) != NDBT_OK)
+ {
+ ERR(pTrans->getNdbError());
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
}
// Execute the transaction and insert the record
@@ -1113,7 +775,9 @@ HugoTransactions::createEvent(Ndb* pNdb){
NdbDictionary::Dictionary *myDict = pNdb->getDictionary();
if (!myDict) {
- printf("Event Creation failedDictionary not found");
+ g_err << "Dictionary not found "
+ << pNdb->getNdbError().code << " "
+ << pNdb->getNdbError().message << endl;
return NDBT_FAILED;
}
@@ -1134,21 +798,33 @@ HugoTransactions::createEvent(Ndb* pNdb){
if (res == 0)
myEvent.print();
- else {
- g_info << "Event creation failed\n";
- g_info << "trying drop Event, maybe event exists\n";
+ else if (myDict->getNdbError().classification ==
+ NdbError::SchemaObjectExists)
+ {
+ g_info << "Event creation failed event exists\n";
res = myDict->dropEvent(eventName);
if (res) {
- g_err << "failed to drop event\n";
+ g_err << "Failed to drop event: "
+ << myDict->getNdbError().code << " : "
+ << myDict->getNdbError().message << endl;
return NDBT_FAILED;
}
// try again
res = myDict->createEvent(myEvent); // Add event to database
if (res) {
- g_err << "failed to create event\n";
+ g_err << "Failed to create event (1): "
+ << myDict->getNdbError().code << " : "
+ << myDict->getNdbError().message << endl;
return NDBT_FAILED;
}
}
+ else
+ {
+ g_err << "Failed to create event (2): "
+ << myDict->getNdbError().code << " : "
+ << myDict->getNdbError().message << endl;
+ return NDBT_FAILED;
+ }
return NDBT_OK;
}
@@ -1164,6 +840,7 @@ struct receivedEvent {
};
int XXXXX = 0;
+
int
HugoTransactions::eventOperation(Ndb* pNdb, void* pstats,
int records) {
@@ -1234,7 +911,9 @@ HugoTransactions::eventOperation(Ndb* pNdb, void* pstats,
// set up the callbacks
g_info << function << "execute\n";
if (pOp->execute()) { // This starts changes to "start flowing"
- g_err << function << "operation execution failed\n";
+ g_err << function << "operation execution failed: \n";
+ g_err << pOp->getNdbError().code << " "
+ << pOp->getNdbError().message << endl;
return NDBT_FAILED;
}
@@ -1362,36 +1041,36 @@ HugoTransactions::eventOperation(Ndb* pNdb, void* pstats,
stats.n_duplicates += recDeleteEvent[i].count-1;
}
}
-
+
return NDBT_OK;
}
int
HugoTransactions::pkReadRecords(Ndb* pNdb,
int records,
- int batchsize,
+ int batch,
NdbOperation::LockMode lm){
int reads = 0;
int r = 0;
int retryAttempt = 0;
const int retryMax = 100;
int check, a;
- NdbOperation *pOp;
- if (batchsize == 0) {
- g_info << "ERROR: Argument batchsize == 0 in pkReadRecords(). Not allowed." << endl;
+ if (batch == 0) {
+ g_info << "ERROR: Argument batch == 0 in pkReadRecords(). Not allowed." << endl;
return NDBT_FAILED;
}
- allocRows(batchsize);
-
while (r < records){
+ if(r + batch > records)
+ batch = records - r;
+
if (retryAttempt >= retryMax){
g_info << "ERROR: has retried this operation " << retryAttempt
<< " times, failing!" << endl;
return NDBT_FAILED;
}
-
+
pTrans = pNdb->startTransaction();
if (pTrans == NULL) {
const NdbError err = pNdb->getNdbError();
@@ -1405,64 +1084,18 @@ HugoTransactions::pkReadRecords(Ndb* pNdb,
ERR(err);
return NDBT_FAILED;
}
-
- for(int b=0; (b<batchsize) && (r+b < records); b++){
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- rand_lock_mode:
- switch(lm){
- case NdbOperation::LM_Read:
- check = pOp->readTuple();
- break;
- case NdbOperation::LM_Exclusive:
- check = pOp->readTupleExclusive();
- break;
- case NdbOperation::LM_CommittedRead:
- check = pOp->dirtyRead();
- break;
- default:
- lm = (NdbOperation::LockMode)((rand() >> 16) & 3);
- goto rand_lock_mode;
- }
-
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- // Define primary keys
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == true){
- if(equalForAttr(pOp, a, r+b) != 0){
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
- }
-
- // Define attributes to read
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if((rows[b]->attributeStore(a) =
- pOp->getValue(tab.getColumn(a)->getName())) == 0) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
-
+ if(pkReadRecord(pNdb, r, batch, lm) != NDBT_OK)
+ {
+ ERR(pTrans->getNdbError());
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
}
-
+
check = pTrans->execute(Commit);
if( check == -1 ) {
const NdbError err = pTrans->getNdbError();
-
+
if (err.status == NdbError::TemporaryError){
ERR(err);
closeTransaction(pNdb);
@@ -1481,19 +1114,48 @@ HugoTransactions::pkReadRecords(Ndb* pNdb,
closeTransaction(pNdb);
return NDBT_FAILED;
}
- } else{
- for (int b=0; (b<batchsize) && (r+b<records); b++){
- if (calc.verifyRowValues(rows[b]) != 0){
+ } else {
+ if(pIndexScanOp)
+ {
+ int rows_found = 0;
+ while((check = pIndexScanOp->nextResult()) == 0)
+ {
+ rows_found++;
+ if (calc.verifyRowValues(rows[0]) != 0){
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
+ }
+ }
+ if(check != 1 || rows_found > batch)
+ {
closeTransaction(pNdb);
return NDBT_FAILED;
}
- reads++;
- r++;
+ else if(rows_found < batch)
+ {
+ if(batch == 1){
+ g_info << r << ": not found" << endl; abort(); }
+ else
+ g_info << "Found " << rows_found << " of "
+ << batch << " rows" << endl;
+ }
+ r += batch;
+ reads += rows_found;
+ }
+ else
+ {
+ for (int b=0; (b<batch) && (r+b<records); b++){
+ if (calc.verifyRowValues(rows[b]) != 0){
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
+ }
+ reads++;
+ r++;
+ }
}
}
-
+
closeTransaction(pNdb);
-
}
deallocRows();
g_info << reads << " records read" << endl;
@@ -1518,6 +1180,8 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb,
g_info << "|- Updating records (batch=" << batch << ")..." << endl;
while (r < records){
+ if(r + batch > records)
+ batch = records - r;
if (retryAttempt >= retryMax){
g_info << "ERROR: has retried this operation " << retryAttempt
@@ -1542,43 +1206,13 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb,
return NDBT_FAILED;
}
- for(b = 0; b<batch && (r+b) < records; b++){
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pOp->readTupleExclusive();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- // Define primary keys
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == true){
- if(equalForAttr(pOp, a, r+b) != 0){
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
- }
-
- // Define attributes to read
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if((rows[b]->attributeStore(a) =
- pOp->getValue(tab.getColumn(a)->getName())) == 0) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
+ if(pkReadRecord(pNdb, r, batch, NdbOperation::LM_Exclusive) != NDBT_OK)
+ {
+ ERR(pTrans->getNdbError());
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
}
-
+
check = pTrans->execute(NoCommit);
if( check == -1 ) {
const NdbError err = pTrans->getNdbError();
@@ -1594,52 +1228,62 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb,
closeTransaction(pNdb);
return NDBT_FAILED;
}
-
- for(b = 0; b<batch && (b+r)<records; b++){
- if (calc.verifyRowValues(rows[b]) != 0){
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- int updates = calc.getUpdatesValue(rows[b]) + 1;
-
- NdbOperation* pUpdOp;
- pUpdOp = pTrans->getNdbOperation(tab.getName());
- if (pUpdOp == NULL) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pUpdOp->updateTuple();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == true){
- if(equalForAttr(pUpdOp, a, r+b) != 0){
- ERR(pTrans->getNdbError());
+
+ if(pIndexScanOp)
+ {
+ int rows_found = 0;
+ while((check = pIndexScanOp->nextResult(true)) == 0)
+ {
+ do {
+
+ if (calc.verifyRowValues(rows[0]) != 0){
closeTransaction(pNdb);
return NDBT_FAILED;
}
- }
- }
-
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == false){
- if(setValueForAttr(pUpdOp, a, r+b, updates ) != 0){
+
+ int updates = calc.getUpdatesValue(rows[0]) + 1;
+
+ if(pkUpdateRecord(pNdb, r+rows_found, 1, updates) != NDBT_OK)
+ {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
return NDBT_FAILED;
}
+ rows_found++;
+ } while((check = pIndexScanOp->nextResult(false)) == 0);
+
+ if(check != 2)
+ break;
+ if((check = pTrans->execute(NoCommit)) != 0)
+ break;
+ }
+ if(check != 1 || rows_found != batch)
+ {
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
+ }
+ }
+ else
+ {
+ for(b = 0; b<batch && (b+r)<records; b++)
+ {
+ if (calc.verifyRowValues(rows[b]) != 0)
+ {
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
+ }
+
+ int updates = calc.getUpdatesValue(rows[b]) + 1;
+
+ if(pkUpdateRecord(pNdb, r+b, 1, updates) != NDBT_OK)
+ {
+ ERR(pTrans->getNdbError());
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
}
}
+ check = pTrans->execute(Commit);
}
-
- check = pTrans->execute(Commit);
if( check == -1 ) {
const NdbError err = pTrans->getNdbError();
@@ -1658,13 +1302,12 @@ HugoTransactions::pkUpdateRecords(Ndb* pNdb,
else{
updated += batch;
}
-
-
+
closeTransaction(pNdb);
-
+
r += batch; // Read next record
}
-
+
deallocRows();
g_info << "|- " << updated << " records updated" << endl;
return NDBT_OK;
@@ -1713,7 +1356,7 @@ HugoTransactions::pkInterpretedUpdateRecords(Ndb* pNdb,
if( check == -1 ) {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
- return NDBT_FAILED;
+ return NDBT_FAILED;
}
// Define primary keys
@@ -1861,6 +1504,8 @@ HugoTransactions::pkDelRecords(Ndb* pNdb,
g_info << "|- Deleting records..." << endl;
while (r < records){
+ if(r + batch > records)
+ batch = records - r;
if (retryAttempt >= retryMax){
g_info << "ERROR: has retried this operation " << retryAttempt
@@ -1885,30 +1530,13 @@ HugoTransactions::pkDelRecords(Ndb* pNdb,
return NDBT_FAILED;
}
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pOp->deleteTuple();
- if( check == -1 ) {
+ if(pkDeleteRecord(pNdb, r, batch) != NDBT_OK)
+ {
ERR(pTrans->getNdbError());
closeTransaction(pNdb);
return NDBT_FAILED;
}
- // Define primary keys
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == true){
- if(equalForAttr(pOp, a, r) != 0){
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
- }
check = pTrans->execute(Commit);
if( check == -1) {
const NdbError err = pTrans->getNdbError();
@@ -1946,11 +1574,11 @@ HugoTransactions::pkDelRecords(Ndb* pNdb,
}
}
else {
- deleted++;
+ deleted += batch;
}
closeTransaction(pNdb);
-
- r++; // Read next record
+
+ r += batch; // Read next record
}
@@ -1972,6 +1600,7 @@ HugoTransactions::lockRecords(Ndb* pNdb,
const int retryMax = 100;
int check, a, b;
NdbOperation *pOp;
+ NdbOperation::LockMode lm = NdbOperation::LM_Exclusive;
// Calculate how many records to lock in each batch
if (percentToLock <= 0)
@@ -1984,6 +1613,9 @@ HugoTransactions::lockRecords(Ndb* pNdb,
allocRows(lockBatch);
while (r < records){
+ if(r + lockBatch > records)
+ lockBatch = records - r;
+
g_info << "|- Locking " << lockBatch << " records..." << endl;
if (retryAttempt >= retryMax){
@@ -2006,42 +1638,13 @@ HugoTransactions::lockRecords(Ndb* pNdb,
return NDBT_FAILED;
}
- for(b = 0; (b<lockBatch) && (r+b < records); b++){
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- check = pOp->readTupleExclusive();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
-
- // Define primary keys
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey() == true){
- if(equalForAttr(pOp, a, r+b) != 0){
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
- }
-
- // Define attributes to read
- for(a = 0; a<tab.getNoOfColumns(); a++){
- if((rows[b]->attributeStore(a) =
- pOp->getValue(tab.getColumn(a)->getName())) == 0) {
- ERR(pTrans->getNdbError());
- closeTransaction(pNdb);
- return NDBT_FAILED;
- }
- }
+ if(pkReadRecord(pNdb, r, lockBatch, lm) != NDBT_OK)
+ {
+ ERR(pTrans->getNdbError());
+ closeTransaction(pNdb);
+ return NDBT_FAILED;
}
+
// NoCommit lockTime times with 100 millis interval
int sleepInterval = 50;
int lockCount = lockTime / sleepInterval;
@@ -2099,8 +1702,7 @@ HugoTransactions::lockRecords(Ndb* pNdb,
}
closeTransaction(pNdb);
-
-
+
}
deallocRows();
g_info << "|- Record locking completed" << endl;
@@ -2111,7 +1713,7 @@ int
HugoTransactions::indexReadRecords(Ndb* pNdb,
const char * idxName,
int records,
- int batchsize){
+ int batch){
int reads = 0;
int r = 0;
int retryAttempt = 0;
@@ -2119,24 +1721,23 @@ HugoTransactions::indexReadRecords(Ndb* pNdb,
int check, a;
NdbOperation *pOp;
NdbIndexScanOperation *sOp;
- NdbResultSet * rs;
const NdbDictionary::Index* pIndex
= pNdb->getDictionary()->getIndex(idxName, tab.getName());
const bool ordered = (pIndex->getType()==NdbDictionary::Index::OrderedIndex);
- if (batchsize == 0) {
- g_info << "ERROR: Argument batchsize == 0 in indexReadRecords(). "
+ if (batch == 0) {
+ g_info << "ERROR: Argument batch == 0 in indexReadRecords(). "
<< "Not allowed." << endl;
return NDBT_FAILED;
}
if (ordered) {
- batchsize = 1;
+ batch = 1;
}
- allocRows(batchsize);
+ allocRows(batch);
while (r < records){
if (retryAttempt >= retryMax){
@@ -2159,7 +1760,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb,
return NDBT_FAILED;
}
- for(int b=0; (b<batchsize) && (r+b < records); b++){
+ for(int b=0; (b<batch) && (r+b < records); b++){
if(!ordered){
pOp = pTrans->getNdbIndexOperation(idxName, tab.getName());
if (pOp == NULL) {
@@ -2175,9 +1776,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb,
closeTransaction(pNdb);
return NDBT_FAILED;
}
-
- check = 0;
- rs = sOp->readTuples();
+ check = sOp->readTuples();
}
if( check == -1 ) {
@@ -2209,7 +1808,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb,
}
check = pTrans->execute(Commit);
- check = (check == -1 ? -1 : !ordered ? check : rs->nextResult(true));
+ check = (check == -1 ? -1 : !ordered ? check : sOp->nextResult(true));
if( check == -1 ) {
const NdbError err = pTrans->getNdbError();
@@ -2232,7 +1831,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb,
return NDBT_FAILED;
}
} else{
- for (int b=0; (b<batchsize) && (r+b<records); b++){
+ for (int b=0; (b<batch) && (r+b<records); b++){
if (calc.verifyRowValues(rows[b]) != 0){
closeTransaction(pNdb);
return NDBT_FAILED;
@@ -2240,7 +1839,7 @@ HugoTransactions::indexReadRecords(Ndb* pNdb,
reads++;
r++;
}
- if(ordered && rs->nextResult(true) == 0){
+ if(ordered && sOp->nextResult(true) == 0){
ndbout << "Error when comparing records "
<< " - index op next_result to many" << endl;
closeTransaction(pNdb);
@@ -2260,7 +1859,7 @@ int
HugoTransactions::indexUpdateRecords(Ndb* pNdb,
const char * idxName,
int records,
- int batchsize){
+ int batch){
int updated = 0;
int r = 0;
@@ -2269,17 +1868,16 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb,
int check, a, b;
NdbOperation *pOp;
NdbScanOperation * sOp;
- NdbResultSet * rs;
const NdbDictionary::Index* pIndex
= pNdb->getDictionary()->getIndex(idxName, tab.getName());
const bool ordered = (pIndex->getType()==NdbDictionary::Index::OrderedIndex);
if (ordered){
- batchsize = 1;
+ batch = 1;
}
- allocRows(batchsize);
+ allocRows(batch);
while (r < records){
if (retryAttempt >= retryMax){
@@ -2302,7 +1900,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb,
return NDBT_FAILED;
}
- for(b = 0; b<batchsize && (b+r)<records; b++){
+ for(b = 0; b<batch && (b+r)<records; b++){
if(!ordered){
pOp = pTrans->getNdbIndexOperation(idxName, tab.getName());
if (pOp == NULL) {
@@ -2326,7 +1924,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb,
}
check = 0;
- rs = sOp->readTuplesExclusive();
+ sOp->readTuplesExclusive();
}
// Define primary keys
@@ -2352,7 +1950,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb,
}
check = pTrans->execute(NoCommit);
- check = (check == -1 ? -1 : !ordered ? check : rs->nextResult(true));
+ check = (check == -1 ? -1 : !ordered ? check : sOp->nextResult(true));
if( check == -1 ) {
const NdbError err = pTrans->getNdbError();
ERR(err);
@@ -2367,12 +1965,12 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb,
}
if(ordered && check != 0){
- g_err << "Row: " << r << " not found!!" << endl;
+ g_err << check << " - Row: " << r << " not found!!" << endl;
closeTransaction(pNdb);
return NDBT_FAILED;
}
- for(b = 0; b<batchsize && (b+r)<records; b++){
+ for(b = 0; b<batch && (b+r)<records; b++){
if (calc.verifyRowValues(rows[b]) != 0){
closeTransaction(pNdb);
return NDBT_FAILED;
@@ -2385,7 +1983,7 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb,
pUpdOp = pTrans->getNdbIndexOperation(idxName, tab.getName());
check = (pUpdOp == 0 ? -1 : pUpdOp->updateTuple());
} else {
- pUpdOp = rs->updateTuple();
+ pUpdOp = sOp->updateCurrentTuple();
}
if (pUpdOp == NULL) {
@@ -2437,12 +2035,12 @@ HugoTransactions::indexUpdateRecords(Ndb* pNdb,
ndbout << "r = " << r << endl;
return NDBT_FAILED;
} else {
- updated += batchsize;
+ updated += batch;
}
closeTransaction(pNdb);
- r+= batchsize; // Read next record
+ r+= batch; // Read next record
}
g_info << "|- " << updated << " records updated" << endl;
diff --git a/ndb/test/src/NDBT_ResultRow.cpp b/ndb/test/src/NDBT_ResultRow.cpp
index f82963901b1..8e92a57d2e4 100644
--- a/ndb/test/src/NDBT_ResultRow.cpp
+++ b/ndb/test/src/NDBT_ResultRow.cpp
@@ -84,7 +84,7 @@ NDBT_ResultRow::header (NdbOut & out) const {
return out;
}
-BaseString NDBT_ResultRow::c_str() {
+BaseString NDBT_ResultRow::c_str() const {
BaseString str;
@@ -133,3 +133,10 @@ NDBT_ResultRow::clone () const {
return row;
}
+
+bool
+NDBT_ResultRow::operator==(const NDBT_ResultRow& other) const
+{
+ // quick and dirty
+ return c_str() == other.c_str();
+}
diff --git a/ndb/test/src/NDBT_Tables.cpp b/ndb/test/src/NDBT_Tables.cpp
index ff6db3e892c..5a5fecd85c1 100644
--- a/ndb/test/src/NDBT_Tables.cpp
+++ b/ndb/test/src/NDBT_Tables.cpp
@@ -48,7 +48,7 @@ const
NDBT_Attribute T2Attribs[] = {
NDBT_Attribute("KOL1", NdbDictionary::Column::Bigunsigned, 1, true),
NDBT_Attribute("KOL2", NdbDictionary::Column::Unsigned),
- NDBT_Attribute("KOL3", NdbDictionary::Column::Unsigned),
+ NDBT_Attribute("KOL3", NdbDictionary::Column::Bit, 23),
NDBT_Attribute("KOL4", NdbDictionary::Column::Unsigned,
1, false, true), // Nullable
NDBT_Attribute("KOL5", NdbDictionary::Column::Unsigned)
@@ -820,21 +820,25 @@ NDBT_Tables::createAllTables(Ndb* pNdb){
int
NDBT_Tables::createTable(Ndb* pNdb, const char* _name, bool _temp,
- bool existsOk){
+ bool existsOk, NDBT_CreateTableHook f){
const NdbDictionary::Table* tab = NDBT_Tables::getTable(_name);
if (tab == NULL){
ndbout << "Could not create table " << _name
<< ", it doesn't exist in list of tables "\
- "that NDBT_Tables can create!" << endl;
+ "that NDBT_Tables can create!" << endl;
return NDBT_WRONGARGS;
}
-
+
int r = 0;
do {
NdbDictionary::Table tmpTab(* tab);
tmpTab.setStoredTable(_temp ? 0 : 1);
-
+ if(f != 0 && f(pNdb, tmpTab, 0))
+ {
+ ndbout << "Failed to create table" << endl;
+ return NDBT_FAILED;
+ }
r = pNdb->getDictionary()->createTable(tmpTab);
if(r == -1){
if(!existsOk){
@@ -883,6 +887,11 @@ NDBT_Tables::createTable(Ndb* pNdb, const char* _name, bool _temp,
}
}
}
+ if(f != 0 && f(pNdb, tmpTab, 1))
+ {
+ ndbout << "Failed to create table" << endl;
+ return NDBT_FAILED;
+ }
} while(false);
return r;
diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp
index 600a5443f40..7fd92db533e 100644
--- a/ndb/test/src/NDBT_Test.cpp
+++ b/ndb/test/src/NDBT_Test.cpp
@@ -15,6 +15,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <ndb_global.h>
+#include <my_pthread.h>
#include "NDBT.hpp"
#include "NDBT_Test.hpp"
@@ -26,7 +27,9 @@
// No verbose outxput
-NDBT_Context::NDBT_Context(){
+NDBT_Context::NDBT_Context(Ndb_cluster_connection& con)
+ : m_cluster_connection(con)
+{
tab = NULL;
suite = NULL;
testcase = NULL;
@@ -239,7 +242,7 @@ int NDBT_Step::execute(NDBT_Context* ctx) {
g_info << " |- " << name << " started [" << ctx->suite->getDate() << "]"
<< endl;
- result = setUp();
+ result = setUp(ctx->m_cluster_connection);
if (result != NDBT_OK){
return result;
}
@@ -279,10 +282,10 @@ NDBT_NdbApiStep::NDBT_NdbApiStep(NDBT_TestCase* ptest,
int
-NDBT_NdbApiStep::setUp(){
- ndb = new Ndb( "TEST_DB" );
+NDBT_NdbApiStep::setUp(Ndb_cluster_connection& con){
+ ndb = new Ndb(&con, "TEST_DB" );
ndb->init(1024);
-
+
int result = ndb->waitUntilReady(300); // 5 minutes
if (result != 0){
g_err << name << ": Ndb was not ready" << endl;
@@ -615,8 +618,7 @@ int NDBT_TestCase::execute(NDBT_Context* ctx){
<< endl;
}
return res;
-};
-
+}
void NDBT_TestCase::startTimer(NDBT_Context* ctx){
timer.doStart();
@@ -748,14 +750,15 @@ int NDBT_TestSuite::addTest(NDBT_TestCase* pTest){
return 0;
}
-int NDBT_TestSuite::executeAll(const char* _testname){
+int NDBT_TestSuite::executeAll(Ndb_cluster_connection& con,
+ const char* _testname){
if(tests.size() == 0)
return NDBT_FAILED;
- Ndb ndb("TEST_DB");
+ Ndb ndb(&con, "TEST_DB");
ndb.init(1024);
- int result = ndb.waitUntilReady(300); // 5 minutes
+ int result = ndb.waitUntilReady(500); // 5 minutes
if (result != 0){
g_err << name <<": Ndb was not ready" << endl;
return NDBT_FAILED;
@@ -768,18 +771,19 @@ int NDBT_TestSuite::executeAll(const char* _testname){
for (int t=0; t < NDBT_Tables::getNumTables(); t++){
const NdbDictionary::Table* ptab = NDBT_Tables::getTable(t);
ndbout << "|- " << ptab->getName() << endl;
- execute(&ndb, ptab, _testname);
+ execute(con, &ndb, ptab, _testname);
}
testSuiteTimer.doStop();
return reportAllTables(_testname);
}
int
-NDBT_TestSuite::executeOne(const char* _tabname, const char* _testname){
+NDBT_TestSuite::executeOne(Ndb_cluster_connection& con,
+ const char* _tabname, const char* _testname){
if(tests.size() == 0)
return NDBT_FAILED;
- Ndb ndb("TEST_DB");
+ Ndb ndb(&con, "TEST_DB");
ndb.init(1024);
int result = ndb.waitUntilReady(300); // 5 minutes
@@ -796,7 +800,7 @@ NDBT_TestSuite::executeOne(const char* _tabname, const char* _testname){
ndbout << "|- " << ptab->getName() << endl;
- execute(&ndb, ptab, _testname);
+ execute(con, &ndb, ptab, _testname);
if (numTestsFail > 0){
return NDBT_FAILED;
@@ -805,7 +809,8 @@ NDBT_TestSuite::executeOne(const char* _tabname, const char* _testname){
}
}
-void NDBT_TestSuite::execute(Ndb* ndb, const NdbDictionary::Table* pTab,
+void NDBT_TestSuite::execute(Ndb_cluster_connection& con,
+ Ndb* ndb, const NdbDictionary::Table* pTab,
const char* _testname){
int result;
@@ -847,14 +852,14 @@ void NDBT_TestSuite::execute(Ndb* ndb, const NdbDictionary::Table* pTab,
pTab2 = pTab;
}
- ctx = new NDBT_Context();
+ ctx = new NDBT_Context(con);
ctx->setTab(pTab2);
ctx->setNumRecords(records);
ctx->setNumLoops(loops);
if(remote_mgm != NULL)
ctx->setRemoteMgm(remote_mgm);
ctx->setSuite(this);
-
+
result = tests[t]->execute(ctx);
tests[t]->saveTestResult(pTab, result);
if (result != NDBT_OK)
@@ -1026,14 +1031,19 @@ int NDBT_TestSuite::execute(int argc, const char** argv){
loops = _loops;
timer = _timer;
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1))
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
if(optind == argc){
// No table specified
- res = executeAll(_testname);
+ res = executeAll(con, _testname);
} else {
testSuiteTimer.doStart();
- Ndb ndb("TEST_DB"); ndb.init();
for(int i = optind; i<argc; i++){
- executeOne(argv[i], _testname);
+ executeOne(con, argv[i], _testname);
}
testSuiteTimer.doStop();
res = report(_testname);
diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp
index 28724323bd7..fe101b9c80b 100644
--- a/ndb/test/src/NdbBackup.cpp
+++ b/ndb/test/src/NdbBackup.cpp
@@ -342,7 +342,7 @@ NdbBackup::NF(NdbRestarter& _restarter, int *NFDuringBackup_codes, const int sz,
}
return NDBT_OK;
-};
+}
int
FailS_codes[] = {
diff --git a/ndb/test/src/NdbRestarts.cpp b/ndb/test/src/NdbRestarts.cpp
index 607e48c4126..c0f31af84ce 100644
--- a/ndb/test/src/NdbRestarts.cpp
+++ b/ndb/test/src/NdbRestarts.cpp
@@ -213,7 +213,7 @@ NdbRestarts::NdbRestart::NdbRestart(const char* _name,
m_restartFunc = _func;
m_numRequiredNodes = _requiredNodes;
// m_arg1 = arg1;
-};
+}
int NdbRestarts::getNumRestarts(){
@@ -367,7 +367,7 @@ int restartRandomNodeGraceful(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int restartRandomNodeAbort(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -382,7 +382,7 @@ int restartRandomNodeAbort(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int restartRandomNodeError(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -397,7 +397,7 @@ int restartRandomNodeError(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int restartMasterNodeError(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -410,7 +410,7 @@ int restartMasterNodeError(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int restartRandomNodeInitial(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -425,7 +425,7 @@ int restartRandomNodeInitial(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int twoNodeFailure(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -453,7 +453,7 @@ int twoNodeFailure(NdbRestarter& _restarter,
"Could not restart node "<< nodeId);
return NDBT_OK;
-};
+}
int twoMasterNodeFailure(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -478,7 +478,7 @@ int twoMasterNodeFailure(NdbRestarter& _restarter,
"Could not restart node "<< nodeId);
return NDBT_OK;
-};
+}
int get50PercentOfNodes(NdbRestarter& restarter,
int * _nodes){
@@ -519,7 +519,7 @@ int fiftyPercentFail(NdbRestarter& _restarter,
"Could not start all nodes");
return NDBT_OK;
-};
+}
int restartAllNodesGracfeul(NdbRestarter& _restarter,
@@ -533,7 +533,7 @@ int restartAllNodesGracfeul(NdbRestarter& _restarter,
return NDBT_OK;
-};
+}
int restartAllNodesAbort(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -545,7 +545,7 @@ int restartAllNodesAbort(NdbRestarter& _restarter,
"Could not restart all nodes");
return NDBT_OK;
-};
+}
int restartAllNodesError9999(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -557,7 +557,7 @@ int restartAllNodesError9999(NdbRestarter& _restarter,
"Could not restart all nodes ");
return NDBT_OK;
-};
+}
int fiftyPercentStopAndWait(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -590,7 +590,7 @@ int fiftyPercentStopAndWait(NdbRestarter& _restarter,
g_info << _restart->m_name << endl;
return NDBT_OK;
-};
+}
int
NFDuringNR_codes[] = {
@@ -713,7 +713,7 @@ int restartNFDuringNR(NdbRestarter& _restarter,
}
return NDBT_OK;
-};
+}
int
NRDuringLCP_Master_codes[] = {
@@ -864,7 +864,7 @@ int stopOnError(NdbRestarter& _restarter,
} while (false);
return NDBT_OK;
-};
+}
int getRandomNodeId(NdbRestarter& _restarter) {
myRandom48Init(NdbTick_CurrentMillisecond());
diff --git a/ndb/test/src/NdbSchemaOp.cpp b/ndb/test/src/NdbSchemaOp.cpp
index a296094ea9d..4281ceb02c8 100644
--- a/ndb/test/src/NdbSchemaOp.cpp
+++ b/ndb/test/src/NdbSchemaOp.cpp
@@ -113,7 +113,7 @@ NdbSchemaOp::createAttribute( const char* anAttrName,
AttrType anAttrType,
StorageMode aStorageMode,
bool nullable,
- StorageAttributeType aStorageAttr,
+ int aStorageAttr,
int aDistributionKeyFlag,
int aDistributionGroupFlag,
int aDistributionGroupNoOfBits,
@@ -158,7 +158,6 @@ NdbSchemaOp::createAttribute( const char* anAttrName,
col.setPrimaryKey(false);
col.setDistributionKey(aDistributionKeyFlag);
- col.setDistributionGroup(aDistributionGroupFlag,aDistributionGroupNoOfBits);
col.setAutoIncrement(aAutoIncrement);
col.setDefaultValue(aDefaultValue != 0 ? aDefaultValue : "");
diff --git a/ndb/test/src/UtilTransactions.cpp b/ndb/test/src/UtilTransactions.cpp
index 869f7fc76cb..65c1a7ded31 100644
--- a/ndb/test/src/UtilTransactions.cpp
+++ b/ndb/test/src/UtilTransactions.cpp
@@ -20,13 +20,20 @@
#define VERBOSE 0
-UtilTransactions::UtilTransactions(const NdbDictionary::Table& _tab):
- tab(_tab){
+UtilTransactions::UtilTransactions(const NdbDictionary::Table& _tab,
+ const NdbDictionary::Index* _idx):
+ tab(_tab), idx(_idx), pTrans(0)
+{
m_defaultClearMethod = 3;
}
-UtilTransactions::UtilTransactions(Ndb* ndb, const char * name) :
- tab(* ndb->getDictionary()->getTable(name)){
+UtilTransactions::UtilTransactions(Ndb* ndb,
+ const char * name,
+ const char * index) :
+ tab(* ndb->getDictionary()->getTable(name)),
+ idx(index ? ndb->getDictionary()->getIndex(index, name) : 0),
+ pTrans(0)
+{
m_defaultClearMethod = 3;
}
@@ -51,313 +58,29 @@ UtilTransactions::clearTable(Ndb* pNdb,
int
UtilTransactions::clearTable1(Ndb* pNdb,
int records,
- int parallelism){
-#if 1
+ int parallelism)
+{
return clearTable3(pNdb, records, 1);
-#else
- // Scan all records exclusive and delete
- // them one by one
- int retryAttempt = 0;
- const int retryMax = 100;
- int check;
- NdbConnection *pTrans;
- NdbOperation *pOp;
-
- while (true){
-
- if (retryAttempt >= retryMax){
- g_info << "ERROR: Has retried this operation " << retryAttempt
- << " times, failing!" << endl;
- return NDBT_FAILED;
- }
-
-
- pTrans = pNdb->startTransaction();
- if (pTrans == NULL) {
- NdbError err = pNdb->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
- ERR(err);
- RETURN_FAIL(err);
- }
-
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- NdbError err = pNdb->getNdbError();
- ERR(err);
- pNdb->closeTransaction(pTrans);
- RETURN_FAIL(err);
- }
-
- check = pOp->openScanExclusive(parallelism);
- if( check == -1 ) {
- NdbError err = pNdb->getNdbError();
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- RETURN_FAIL(err);
- }
-
- check = pOp->interpret_exit_ok();
- if( check == -1 ) {
- NdbError err = pNdb->getNdbError();
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- RETURN_FAIL(err);
- }
-#if 0
- // It's not necessary to read and PK's
- // Information about the PK's are sent in
- // KEYINFO20 signals anyway and used by takeOverScan
-
- // Read the primary keys from this table
- for(int a=0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey()){
- if(pOp->getValue(tab.getColumn(a)->getName()) == NULL){
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- RETURN_FAIL(err);
- }
- }
- }
-#endif
-
- check = pTrans->executeScan();
- if( check == -1 ) {
- NdbError err = pTrans->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- pNdb->closeTransaction(pTrans);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
- ERR(err);
- pNdb->closeTransaction(pTrans);
- RETURN_FAIL(err);
- }
-
- int eof;
- int rows = 0;
-
- eof = pTrans->nextScanResult();
- while(eof == 0){
- rows++;
-
- int res = takeOverAndDeleteRecord(pNdb, pOp);
- if(res == RESTART_SCAN){
- eof = -2;
- continue;
- }
-
- if (res != 0){
- NdbError err = pNdb->getNdbError(res);
- pNdb->closeTransaction(pTrans);
- RETURN_FAIL(err);
- }
-
- eof = pTrans->nextScanResult();
- }
-
- if (eof == -1) {
- const NdbError err = pTrans->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- pNdb->closeTransaction(pTrans);
- NdbSleep_MilliSleep(50);
- // If error = 488 there should be no limit on number of retry attempts
- if (err.code != 488)
- retryAttempt++;
- continue;
- }
- ERR(err);
- pNdb->closeTransaction(pTrans);
- RETURN_FAIL(err);
- }
-
- if(eof == -2){
- pNdb->closeTransaction(pTrans);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
-
- pNdb->closeTransaction(pTrans);
-
- g_info << rows << " deleted" << endl;
-
- return NDBT_OK;
- }
- return NDBT_FAILED;
-#endif
}
int
UtilTransactions::clearTable2(Ndb* pNdb,
- int records,
- int parallelism){
-#if 1
+ int records,
+ int parallelism)
+{
return clearTable3(pNdb, records, parallelism);
-#else
- // Scan all records exclusive and delete
- // them one by one
- int retryAttempt = 0;
- const int retryMax = 10;
- int deletedRows = 0;
- int check;
- NdbConnection *pTrans;
- NdbOperation *pOp;
-
- while (true){
-
- if (retryAttempt >= retryMax){
- g_info << "ERROR: has retried this operation " << retryAttempt
- << " times, failing!" << endl;
- return NDBT_FAILED;
- }
-
-
- pTrans = pNdb->startTransaction();
- if (pTrans == NULL) {
- const NdbError err = pNdb->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
- ERR(err);
- return NDBT_FAILED;
- }
-
- pOp = pTrans->getNdbOperation(tab.getName());
- if (pOp == NULL) {
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
-
- check = pOp->openScanExclusive(parallelism);
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
-
- check = pOp->interpret_exit_ok();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
-#if 0
- // It's not necessary to read any PK's
- // Information about the PK's are sent in
- // KEYINFO20 signals anyway and used by takeOverScan
-
- // Read the primary keys from this table
- for(int a=0; a<tab.getNoOfColumns(); a++){
- if (tab.getColumn(a)->getPrimaryKey()){
- if(pOp->getValue(tab.getColumn(a)->getName()) == NULL){
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- return -1;
- }
- }
- }
-#endif
-
- check = pTrans->executeScan();
- if( check == -1 ) {
- ERR(pTrans->getNdbError());
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
-
- int eof;
- NdbConnection* pDelTrans;
-
- while((eof = pTrans->nextScanResult(true)) == 0){
- pDelTrans = pNdb->startTransaction();
- if (pDelTrans == NULL) {
- const NdbError err = pNdb->getNdbError();
-#if 0
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- NdbSleep_MilliSleep(50);
- retryAttempt++;
- continue;
- }
-#endif
- ERR(err);
- pNdb->closeTransaction(pDelTrans);
- return NDBT_FAILED;
- }
- do {
- deletedRows++;
- if (addRowToDelete(pNdb, pDelTrans, pOp) != 0){
- pNdb->closeTransaction(pDelTrans);
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
- } while((eof = pTrans->nextScanResult(false)) == 0);
-
- check = pDelTrans->execute(Commit);
- if( check == -1 ) {
- const NdbError err = pDelTrans->getNdbError();
- ERR(err);
- pNdb->closeTransaction(pDelTrans);
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
- pNdb->closeTransaction(pDelTrans);
-
- }
- if (eof == -1) {
- const NdbError err = pTrans->getNdbError();
-
- if (err.status == NdbError::TemporaryError){
- ERR(err);
- pNdb->closeTransaction(pTrans);
- NdbSleep_MilliSleep(50);
- // If error = 488 there should be no limit on number of retry attempts
- if (err.code != 488)
- retryAttempt++;
- continue;
- }
- ERR(err);
- pNdb->closeTransaction(pTrans);
- return NDBT_FAILED;
- }
-
- pNdb->closeTransaction(pTrans);
-
- g_info << deletedRows << " rows deleted" << endl;
-
- return NDBT_OK;
- }
- return NDBT_FAILED;
-#endif
}
int
UtilTransactions::clearTable3(Ndb* pNdb,
- int records,
- int parallelism){
+ int records,
+ int parallelism){
// Scan all records exclusive and delete
// them one by one
int retryAttempt = 0;
const int retryMax = 10;
int deletedRows = 0;
int check;
- NdbConnection *pTrans;
NdbScanOperation *pOp;
NdbError err;
@@ -380,8 +103,8 @@ UtilTransactions::clearTable3(Ndb* pNdb,
}
goto failed;
}
-
- pOp = pTrans->getNdbScanOperation(tab.getName());
+
+ pOp = getScanOperation(pTrans);
if (pOp == NULL) {
err = pTrans->getNdbError();
if(err.status == NdbError::TemporaryError){
@@ -394,8 +117,7 @@ UtilTransactions::clearTable3(Ndb* pNdb,
goto failed;
}
- NdbResultSet * rs = pOp->readTuplesExclusive(par);
- if( rs == 0 ) {
+ if( pOp->readTuplesExclusive(par) ) {
err = pTrans->getNdbError();
goto failed;
}
@@ -411,13 +133,13 @@ UtilTransactions::clearTable3(Ndb* pNdb,
goto failed;
}
- while((check = rs->nextResult(true)) == 0){
+ while((check = pOp->nextResult(true)) == 0){
do {
- if (rs->deleteTuple() != 0){
+ if (pOp->deleteCurrentTuple() != 0){
goto failed;
}
deletedRows++;
- } while((check = rs->nextResult(false)) == 0);
+ } while((check = pOp->nextResult(false)) == 0);
if(check != -1){
check = pTrans->execute(Commit);
@@ -468,7 +190,6 @@ UtilTransactions::copyTableData(Ndb* pNdb,
int insertedRows = 0;
int parallelism = 240;
int check;
- NdbConnection *pTrans;
NdbScanOperation *pOp;
NDBT_ResultRow row(tab);
@@ -502,9 +223,7 @@ UtilTransactions::copyTableData(Ndb* pNdb,
return NDBT_FAILED;
}
- NdbResultSet* rs = pOp->readTuples(NdbScanOperation::LM_Read,
- parallelism);
- if( check == -1 ) {
+ if( pOp->readTuples(NdbScanOperation::LM_Read, parallelism) ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -535,14 +254,14 @@ UtilTransactions::copyTableData(Ndb* pNdb,
}
int eof;
- while((eof = rs->nextResult(true)) == 0){
+ while((eof = pOp->nextResult(true)) == 0){
do {
insertedRows++;
if (addRowToInsert(pNdb, pTrans, row, destName) != 0){
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
}
- } while((eof = rs->nextResult(false)) == 0);
+ } while((eof = pOp->nextResult(false)) == 0);
check = pTrans->execute(Commit);
pTrans->restart();
@@ -628,7 +347,6 @@ UtilTransactions::scanReadRecords(Ndb* pNdb,
int retryAttempt = 0;
const int retryMax = 100;
int check;
- NdbConnection *pTrans;
NdbScanOperation *pOp;
NDBT_ResultRow row(tab);
@@ -654,7 +372,7 @@ UtilTransactions::scanReadRecords(Ndb* pNdb,
return NDBT_FAILED;
}
- pOp = pTrans->getNdbScanOperation(tab.getName());
+ pOp = getScanOperation(pTrans);
if (pOp == NULL) {
const NdbError err = pNdb->getNdbError();
pNdb->closeTransaction(pTrans);
@@ -669,8 +387,7 @@ UtilTransactions::scanReadRecords(Ndb* pNdb,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples(lm, 0, parallelism);
- if( rs == 0 ) {
+ if( pOp->readTuples(lm, 0, parallelism) ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -718,7 +435,7 @@ UtilTransactions::scanReadRecords(Ndb* pNdb,
int rows = 0;
- while((eof = rs->nextResult()) == 0){
+ while((eof = pOp->nextResult()) == 0){
rows++;
// Call callback for each record returned
@@ -768,6 +485,7 @@ UtilTransactions::selectCount(Ndb* pNdb,
if(!pTrans)
pTrans = pNdb->startTransaction();
+
while (true){
if (retryAttempt >= retryMax){
@@ -775,15 +493,14 @@ UtilTransactions::selectCount(Ndb* pNdb,
<< " times, failing!" << endl;
return NDBT_FAILED;
}
- pOp = pTrans->getNdbScanOperation(tab.getName());
+ pOp = getScanOperation(pTrans);
if (pOp == NULL) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples(lm);
- if( rs == 0) {
+ if( pOp->readTuples(lm) ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -815,7 +532,7 @@ UtilTransactions::selectCount(Ndb* pNdb,
int rows = 0;
- while((eof = rs->nextResult()) == 0){
+ while((eof = pOp->nextResult()) == 0){
rows++;
}
if (eof == -1) {
@@ -906,14 +623,13 @@ UtilTransactions::scanAndCompareUniqueIndex(Ndb* pNdb,
int retryAttempt = 0;
const int retryMax = 100;
int check;
- NdbConnection *pTrans;
NdbScanOperation *pOp;
NDBT_ResultRow row(tab);
parallelism = 1;
while (true){
-
+restart:
if (retryAttempt >= retryMax){
g_info << "ERROR: has retried this operation " << retryAttempt
<< " times, failing!" << endl;
@@ -948,14 +664,14 @@ UtilTransactions::scanAndCompareUniqueIndex(Ndb* pNdb,
return NDBT_FAILED;
}
- NdbResultSet* rs;
+ int rs;
if(transactional){
rs = pOp->readTuples(NdbScanOperation::LM_Read, 0, parallelism);
} else {
rs = pOp->readTuples(NdbScanOperation::LM_CommittedRead, 0, parallelism);
}
- if( rs == 0 ) {
+ if( rs != 0 ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -998,16 +714,31 @@ UtilTransactions::scanAndCompareUniqueIndex(Ndb* pNdb,
int rows = 0;
- while((eof = rs->nextResult()) == 0){
+ while((eof = pOp->nextResult()) == 0){
rows++;
// ndbout << row.c_str().c_str() << endl;
-
if (readRowFromTableAndIndex(pNdb,
pTrans,
pIndex,
row) != NDBT_OK){
+
+ while((eof= pOp->nextResult(false)) == 0);
+ if(eof == 2)
+ eof = pOp->nextResult(true); // this should give -1
+ if(eof == -1)
+ {
+ const NdbError err = pTrans->getNdbError();
+
+ if (err.status == NdbError::TemporaryError){
+ ERR(err);
+ pNdb->closeTransaction(pTrans);
+ NdbSleep_MilliSleep(50);
+ retryAttempt++;
+ goto restart;
+ }
+ }
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
}
@@ -1020,7 +751,6 @@ UtilTransactions::scanAndCompareUniqueIndex(Ndb* pNdb,
pNdb->closeTransaction(pTrans);
NdbSleep_MilliSleep(50);
retryAttempt++;
- rows--;
continue;
}
ERR(err);
@@ -1046,7 +776,6 @@ UtilTransactions::readRowFromTableAndIndex(Ndb* pNdb,
const int retryMax = 100;
int check, a;
NdbConnection *pTrans1=NULL;
- NdbResultSet *cursor= NULL;
NdbOperation *pOp;
int return_code= NDBT_FAILED;
@@ -1096,7 +825,6 @@ UtilTransactions::readRowFromTableAndIndex(Ndb* pNdb,
check = pOp->readTuple();
if( check == -1 ) {
ERR(pTrans1->getNdbError());
- pNdb->closeTransaction(pTrans1);
goto close_all;
}
@@ -1174,7 +902,7 @@ UtilTransactions::readRowFromTableAndIndex(Ndb* pNdb,
if (pIndexOp) {
not_ok = pIndexOp->readTuple() == -1;
} else {
- not_ok = (cursor= pScanOp->readTuples()) == 0;
+ not_ok = pScanOp->readTuples();
}
if( not_ok ) {
@@ -1228,7 +956,7 @@ UtilTransactions::readRowFromTableAndIndex(Ndb* pNdb,
#if VERBOSE
printf("\n");
#endif
-
+ scanTrans->refresh();
check = pTrans1->execute(Commit);
if( check == -1 ) {
const NdbError err = pTrans1->getNdbError();
@@ -1251,7 +979,7 @@ UtilTransactions::readRowFromTableAndIndex(Ndb* pNdb,
*/
if(!null_found){
if (pScanOp) {
- if (cursor->nextResult() != 0){
+ if (pScanOp->nextResult() != 0){
const NdbError err = pTrans1->getNdbError();
ERR(err);
ndbout << "Error when comparing records - index op next_result missing" << endl;
@@ -1266,7 +994,7 @@ UtilTransactions::readRowFromTableAndIndex(Ndb* pNdb,
goto close_all;
}
if (pScanOp) {
- if (cursor->nextResult() == 0){
+ if (pScanOp->nextResult() == 0){
ndbout << "Error when comparing records - index op next_result to many" << endl;
ndbout << "row: " << row.c_str().c_str() << endl;
goto close_all;
@@ -1278,8 +1006,6 @@ UtilTransactions::readRowFromTableAndIndex(Ndb* pNdb,
}
close_all:
- if (cursor)
- cursor->close();
if (pTrans1)
pNdb->closeTransaction(pTrans1);
@@ -1295,10 +1021,8 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb,
int retryAttempt = 0;
const int retryMax = 100;
int check;
- NdbConnection *pTrans;
NdbScanOperation *pOp;
NdbIndexScanOperation * iop = 0;
- NdbResultSet* cursor= 0;
NDBT_ResultRow scanRow(tab);
NDBT_ResultRow pkRow(tab);
@@ -1337,10 +1061,7 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb,
return NDBT_FAILED;
}
- NdbResultSet*
- rs = pOp->readTuples(NdbScanOperation::LM_Read, 0, parallelism);
-
- if( rs == 0 ) {
+ if( pOp->readTuples(NdbScanOperation::LM_Read, 0, parallelism) ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -1376,7 +1097,7 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb,
int eof;
int rows = 0;
- while(check == 0 && (eof = rs->nextResult()) == 0){
+ while(check == 0 && (eof = pOp->nextResult()) == 0){
rows++;
bool null_found= false;
@@ -1401,10 +1122,11 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb,
if(!iop && (iop= pTrans->getNdbIndexScanOperation(indexName,
tab.getName())))
{
- cursor= iop->readTuples(NdbScanOperation::LM_CommittedRead,
- parallelism);
+ if(iop->readTuples(NdbScanOperation::LM_CommittedRead,
+ parallelism))
+ goto error;
iop->interpret_exit_ok();
- if(!cursor || get_values(iop, indexRow))
+ if(get_values(iop, indexRow))
goto error;
}
else if(!iop || iop->reset_bounds())
@@ -1431,7 +1153,7 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb,
if(!null_found)
{
- if((res= cursor->nextResult()) != 0){
+ if((res= iop->nextResult()) != 0){
g_err << "Failed to find row using index: " << res << endl;
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
@@ -1446,7 +1168,7 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb,
return NDBT_FAILED;
}
- if(cursor->nextResult() == 0){
+ if(iop->nextResult() == 0){
g_err << "Found extra row!!" << endl;
g_err << " indexRow: \n" << indexRow.c_str().c_str() << endl;
pNdb->closeTransaction(pTrans);
@@ -1521,3 +1243,209 @@ UtilTransactions::equal(const NdbDictionary::Table* pTable,
}
return 0;
}
+
+NdbScanOperation*
+UtilTransactions::getScanOperation(NdbConnection* pTrans)
+{
+ return (NdbScanOperation*)
+ getOperation(pTrans, NdbOperation::OpenScanRequest);
+}
+
+NdbOperation*
+UtilTransactions::getOperation(NdbConnection* pTrans,
+ NdbOperation::OperationType type)
+{
+ switch(type){
+ case NdbOperation::ReadRequest:
+ case NdbOperation::ReadExclusive:
+ if(idx)
+ {
+ switch(idx->getType()){
+ case NdbDictionary::Index::UniqueHashIndex:
+ return pTrans->getNdbIndexOperation(idx->getName(), tab.getName());
+ case NdbDictionary::Index::OrderedIndex:
+ return pTrans->getNdbIndexScanOperation(idx->getName(), tab.getName());
+ }
+ }
+ case NdbOperation::InsertRequest:
+ case NdbOperation::WriteRequest:
+ return pTrans->getNdbOperation(tab.getName());
+ case NdbOperation::UpdateRequest:
+ case NdbOperation::DeleteRequest:
+ if(idx)
+ {
+ switch(idx->getType()){
+ case NdbDictionary::Index::UniqueHashIndex:
+ return pTrans->getNdbIndexOperation(idx->getName(), tab.getName());
+ }
+ }
+ return pTrans->getNdbOperation(tab.getName());
+ case NdbOperation::OpenScanRequest:
+ if(idx)
+ {
+ switch(idx->getType()){
+ case NdbDictionary::Index::OrderedIndex:
+ return pTrans->getNdbIndexScanOperation(idx->getName(), tab.getName());
+ }
+ }
+ return pTrans->getNdbScanOperation(tab.getName());
+ case NdbOperation::OpenRangeScanRequest:
+ if(idx)
+ {
+ switch(idx->getType()){
+ case NdbDictionary::Index::OrderedIndex:
+ return pTrans->getNdbIndexScanOperation(idx->getName(), tab.getName());
+ }
+ }
+ return 0;
+ }
+}
+
+#include <HugoOperations.hpp>
+
+int
+UtilTransactions::compare(Ndb* pNdb, const char* tab_name2, int flags){
+
+
+ NdbError err;
+ int return_code= -1, row_count= 0;
+ int retryAttempt = 0, retryMax = 10;
+
+ HugoCalculator calc(tab);
+ NDBT_ResultRow row(tab);
+ NdbTransaction* pTrans= 0;
+ const NdbDictionary::Table* tmp= pNdb->getDictionary()->getTable(tab_name2);
+ if(tmp == 0)
+ {
+ g_err << "Unable to lookup table: " << tab_name2
+ << endl << pNdb->getDictionary()->getNdbError() << endl;
+ return -1;
+ }
+ const NdbDictionary::Table& tab2= *tmp;
+
+ HugoOperations cmp(tab2);
+ UtilTransactions count(tab2);
+
+ while (true){
+
+ if (retryAttempt++ >= retryMax){
+ g_info << "ERROR: has retried this operation " << retryAttempt
+ << " times, failing!" << endl;
+ return -1;
+ }
+
+ NdbScanOperation *pOp= 0;
+ pTrans = pNdb->startTransaction();
+ if (pTrans == NULL) {
+ err = pNdb->getNdbError();
+ goto error;
+ }
+
+ pOp= pTrans->getNdbScanOperation(tab.getName());
+ if (pOp == NULL) {
+ ERR(err= pTrans->getNdbError());
+ goto error;
+ }
+
+ if( pOp->readTuples(NdbScanOperation::LM_Read) ) {
+ ERR(err= pTrans->getNdbError());
+ goto error;
+ }
+
+ if( pOp->interpret_exit_ok() == -1 ) {
+ ERR(err= pTrans->getNdbError());
+ goto error;
+ }
+
+ // Read all attributes
+ {
+ for (int a = 0; a < tab.getNoOfColumns(); a++){
+ if ((row.attributeStore(a) =
+ pOp->getValue(tab.getColumn(a)->getName())) == 0) {
+ ERR(err= pTrans->getNdbError());
+ goto error;
+ }
+ }
+ }
+
+ if( pTrans->execute(NoCommit) == -1 ) {
+ ERR(err= pTrans->getNdbError());
+ goto error;
+ }
+
+ {
+ int eof;
+ while((eof = pOp->nextResult(true)) == 0)
+ {
+ do {
+ row_count++;
+ if(cmp.startTransaction(pNdb) != NDBT_OK)
+ {
+ ERR(err= pNdb->getNdbError());
+ goto error;
+ }
+ int rowNo= calc.getIdValue(&row);
+ if(cmp.pkReadRecord(pNdb, rowNo, 1) != NDBT_OK)
+ {
+ ERR(err= cmp.getTransaction()->getNdbError());
+ goto error;
+ }
+ if(cmp.execute_Commit(pNdb) != NDBT_OK)
+ {
+ ERR(err= cmp.getTransaction()->getNdbError());
+ goto error;
+ }
+ if(row != cmp.get_row(0))
+ {
+ g_err << "COMPARE FAILED" << endl;
+ g_err << row << endl;
+ g_err << cmp.get_row(0) << endl;
+ return_code= 1;
+ goto close;
+ }
+ retryAttempt= 0;
+ cmp.closeTransaction(pNdb);
+ } while((eof = pOp->nextResult(false)) == 0);
+ }
+ if (eof == -1)
+ {
+ err = pTrans->getNdbError();
+ goto error;
+ }
+ }
+
+ pTrans->close(); pTrans= 0;
+
+ g_info << row_count << " rows compared" << endl;
+ {
+ int row_count2;
+ if(count.selectCount(pNdb, 0, &row_count2) != NDBT_OK)
+ {
+ g_err << "Failed to count rows in tab_name2" << endl;
+ return -1;
+ }
+
+ g_info << row_count2 << " rows in tab_name2" << endl;
+ return (row_count == row_count2 ? 0 : 1);
+ }
+error:
+ if(err.status == NdbError::TemporaryError)
+ {
+ NdbSleep_MilliSleep(50);
+ if(pTrans != 0)
+ {
+ pTrans->close();
+ pTrans= 0;
+ }
+ if(cmp.getTransaction())
+ cmp.closeTransaction(pNdb);
+ continue;
+ }
+ break;
+ }
+
+close:
+ if(pTrans != 0) pTrans->close();
+
+ return return_code;
+}
diff --git a/ndb/test/tools/Makefile.am b/ndb/test/tools/Makefile.am
index a6a013bb263..873136e254d 100644
--- a/ndb/test/tools/Makefile.am
+++ b/ndb/test/tools/Makefile.am
@@ -1,9 +1,8 @@
-ndbtest_PROGRAMS = hugoCalculator hugoLoad hugoFill hugoLockRecords hugoPkDelete hugoPkRead hugoPkReadRecord hugoPkUpdate hugoScanRead hugoScanUpdate restart verify_index copy_tab create_index ndb_cpcc
+ndbtest_PROGRAMS = hugoLoad hugoFill hugoLockRecords hugoPkDelete hugoPkRead hugoPkReadRecord hugoPkUpdate hugoScanRead hugoScanUpdate restart verify_index copy_tab create_index ndb_cpcc
# transproxy
-hugoCalculator_SOURCES = hugoCalculator.cpp
hugoFill_SOURCES = hugoFill.cpp
hugoLoad_SOURCES = hugoLoad.cpp
hugoLockRecords_SOURCES = hugoLockRecords.cpp
diff --git a/ndb/test/tools/copy_tab.cpp b/ndb/test/tools/copy_tab.cpp
index 30141acaa78..97370b170ef 100644
--- a/ndb/test/tools/copy_tab.cpp
+++ b/ndb/test/tools/copy_tab.cpp
@@ -56,9 +56,12 @@ int main(int argc, const char** argv){
_tabname = argv[optind];
_to_tabname = argv[optind+1];
- if (_connectstr)
- Ndb::setConnectString(_connectstr);
- Ndb MyNdb(_dbname);
+ Ndb_cluster_connection con(_connectstr);
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con,_dbname);
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
return NDBT_ProgramExit(NDBT_FAILED);
diff --git a/ndb/test/tools/create_index.cpp b/ndb/test/tools/create_index.cpp
index 6e4c5377f4a..9f9c26aa0da 100644
--- a/ndb/test/tools/create_index.cpp
+++ b/ndb/test/tools/create_index.cpp
@@ -53,8 +53,13 @@ main(int argc, const char** argv){
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
- Ndb MyNdb(_dbname);
+ Ndb MyNdb(&con, _dbname);
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
return NDBT_ProgramExit(NDBT_FAILED);
diff --git a/ndb/test/tools/hugoFill.cpp b/ndb/test/tools/hugoFill.cpp
index 6253bd1bb12..6408b2987f9 100644
--- a/ndb/test/tools/hugoFill.cpp
+++ b/ndb/test/tools/hugoFill.cpp
@@ -51,7 +51,12 @@ int main(int argc, const char** argv){
_tabname = argv[optind];
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/tools/hugoLoad.cpp b/ndb/test/tools/hugoLoad.cpp
index c697ad22aad..7d9d0dafaff 100644
--- a/ndb/test/tools/hugoLoad.cpp
+++ b/ndb/test/tools/hugoLoad.cpp
@@ -54,7 +54,12 @@ int main(int argc, const char** argv){
_tabname = argv[optind];
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/tools/hugoLockRecords.cpp b/ndb/test/tools/hugoLockRecords.cpp
index 629408d401d..c0d0b9f9c5a 100644
--- a/ndb/test/tools/hugoLockRecords.cpp
+++ b/ndb/test/tools/hugoLockRecords.cpp
@@ -59,7 +59,12 @@ int main(int argc, const char** argv){
_tabname = argv[optind];
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/tools/hugoPkDelete.cpp b/ndb/test/tools/hugoPkDelete.cpp
index 78a90ebcb46..84e7ded0add 100644
--- a/ndb/test/tools/hugoPkDelete.cpp
+++ b/ndb/test/tools/hugoPkDelete.cpp
@@ -55,7 +55,12 @@ int main(int argc, const char** argv){
_tabname = argv[optind];
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/tools/hugoPkRead.cpp b/ndb/test/tools/hugoPkRead.cpp
index cf08b137e8e..e3702dc5ca1 100644
--- a/ndb/test/tools/hugoPkRead.cpp
+++ b/ndb/test/tools/hugoPkRead.cpp
@@ -60,7 +60,12 @@ int main(int argc, const char** argv){
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/tools/hugoPkReadRecord.cpp b/ndb/test/tools/hugoPkReadRecord.cpp
index 38b7cae2bf4..c60a994c7d4 100644
--- a/ndb/test/tools/hugoPkReadRecord.cpp
+++ b/ndb/test/tools/hugoPkReadRecord.cpp
@@ -62,7 +62,12 @@ int main(int argc, const char** argv)
<< "Row: " << _row << ", PrimaryKey: " << _primaryKey
<< endl;
- Ndb* ndb = new Ndb("TEST_DB");
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb* ndb = new Ndb(&con, "TEST_DB");
if (ndb->init() == 0 && ndb->waitUntilReady(30) == 0)
{
NdbConnection* conn = ndb->startTransaction();
diff --git a/ndb/test/tools/hugoPkUpdate.cpp b/ndb/test/tools/hugoPkUpdate.cpp
index 286be14a01c..6e7ff39f903 100644
--- a/ndb/test/tools/hugoPkUpdate.cpp
+++ b/ndb/test/tools/hugoPkUpdate.cpp
@@ -57,7 +57,12 @@ int main(int argc, const char** argv){
_tabname = argv[optind];
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/tools/hugoScanRead.cpp b/ndb/test/tools/hugoScanRead.cpp
index 42180207a8a..4f76362ecab 100644
--- a/ndb/test/tools/hugoScanRead.cpp
+++ b/ndb/test/tools/hugoScanRead.cpp
@@ -61,7 +61,12 @@ int main(int argc, const char** argv){
_tabname = argv[optind];
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
@@ -85,8 +90,7 @@ int main(int argc, const char** argv){
if(!pIdx)
ndbout << " Index " << argv[optind+1] << " not found" << endl;
else
- if(pIdx->getType() != NdbDictionary::Index::UniqueOrderedIndex &&
- pIdx->getType() != NdbDictionary::Index::OrderedIndex)
+ if(pIdx->getType() != NdbDictionary::Index::OrderedIndex)
{
ndbout << " Index " << argv[optind+1] << " is not scannable" << endl;
pIdx = 0;
diff --git a/ndb/test/tools/hugoScanUpdate.cpp b/ndb/test/tools/hugoScanUpdate.cpp
index 96a487a02bf..88c343f8fd3 100644
--- a/ndb/test/tools/hugoScanUpdate.cpp
+++ b/ndb/test/tools/hugoScanUpdate.cpp
@@ -58,7 +58,12 @@ int main(int argc, const char** argv){
_tabname = argv[optind];
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/test/tools/verify_index.cpp b/ndb/test/tools/verify_index.cpp
index 6c8e304e1a1..acc97af883b 100644
--- a/ndb/test/tools/verify_index.cpp
+++ b/ndb/test/tools/verify_index.cpp
@@ -53,7 +53,12 @@ int main(int argc, const char** argv){
_indexname = argv[optind+1];
// Connect to Ndb
- Ndb MyNdb( "TEST_DB" );
+ Ndb_cluster_connection con;
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, "TEST_DB" );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
diff --git a/ndb/tools/delete_all.cpp b/ndb/tools/delete_all.cpp
index 21e0c2ac089..2c395a67900 100644
--- a/ndb/tools/delete_all.cpp
+++ b/ndb/tools/delete_all.cpp
@@ -44,35 +44,37 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_delete_all.trace");
-}
int main(int argc, char** argv){
NDB_INIT(argv[0]);
const char *load_default_groups[]= { "mysql_cluster",0 };
load_defaults("my",load_default_groups,&argc,&argv);
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_delete_all.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
- Ndb::setConnectString(opt_connect_str);
- // Connect to Ndb
- Ndb MyNdb(_dbname);
+ Ndb_cluster_connection con(opt_connect_str);
+ if(con.connect(12, 5, 1) != 0)
+ {
+ ndbout << "Unable to connect to management server." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ if (con.wait_until_ready(30,0) < 0)
+ {
+ ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, _dbname );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
return NDBT_ProgramExit(NDBT_FAILED);
}
- // Connect to Ndb and wait for it to become ready
- while(MyNdb.waitUntilReady() != 0)
- ndbout << "Waiting for ndb to become ready..." << endl;
-
// Check if table exists in db
int res = NDBT_OK;
for(int i = 0; i<argc; i++){
@@ -99,7 +101,7 @@ int clear_table(Ndb* pNdb, const NdbDictionary::Table* pTab, int parallelism)
const int retryMax = 10;
int deletedRows = 0;
int check;
- NdbConnection *pTrans;
+ NdbTransaction *pTrans;
NdbScanOperation *pOp;
NdbError err;
@@ -128,12 +130,11 @@ int clear_table(Ndb* pNdb, const NdbDictionary::Table* pTab, int parallelism)
goto failed;
}
- NdbResultSet * rs = pOp->readTuplesExclusive(par);
- if( rs == 0 ) {
+ if( pOp->readTuples(NdbOperation::LM_Exclusive,par) ) {
goto failed;
}
- if(pTrans->execute(NoCommit) != 0){
+ if(pTrans->execute(NdbTransaction::NoCommit) != 0){
err = pTrans->getNdbError();
if(err.status == NdbError::TemporaryError){
ERR(err);
@@ -144,16 +145,16 @@ int clear_table(Ndb* pNdb, const NdbDictionary::Table* pTab, int parallelism)
goto failed;
}
- while((check = rs->nextResult(true)) == 0){
+ while((check = pOp->nextResult(true)) == 0){
do {
- if (rs->deleteTuple() != 0){
+ if (pOp->deleteCurrentTuple() != 0){
goto failed;
}
deletedRows++;
- } while((check = rs->nextResult(false)) == 0);
+ } while((check = pOp->nextResult(false)) == 0);
if(check != -1){
- check = pTrans->execute(Commit);
+ check = pTrans->execute(NdbTransaction::Commit);
pTrans->restart();
}
diff --git a/ndb/tools/desc.cpp b/ndb/tools/desc.cpp
index aac47c9042c..be0f6942db5 100644
--- a/ndb/tools/desc.cpp
+++ b/ndb/tools/desc.cpp
@@ -44,35 +44,38 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_desc.trace");
-}
int main(int argc, char** argv){
NDB_INIT(argv[0]);
const char *load_default_groups[]= { "mysql_cluster",0 };
load_defaults("my",load_default_groups,&argc,&argv);
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_desc.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
- Ndb::setConnectString(opt_connect_str);
-
- Ndb* pMyNdb;
- pMyNdb = new Ndb(_dbname);
- pMyNdb->init();
-
- ndbout << "Waiting...";
- while (pMyNdb->waitUntilReady() != 0) {
- ndbout << "...";
+ Ndb_cluster_connection con(opt_connect_str);
+ if(con.connect(12, 5, 1) != 0)
+ {
+ ndbout << "Unable to connect to management server." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ if (con.wait_until_ready(30,0) < 0)
+ {
+ ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
}
- ndbout << endl;
- NdbDictionary::Dictionary * dict = pMyNdb->getDictionary();
+ Ndb MyNdb(&con, _dbname);
+ if(MyNdb.init() != 0){
+ ERR(MyNdb.getNdbError());
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ const NdbDictionary::Dictionary * dict= MyNdb.getDictionary();
for (int i = 0; i < argc; i++) {
NDBT_Table* pTab = (NDBT_Table*)dict->getTable(argv[i]);
if (pTab != 0){
@@ -112,6 +115,5 @@ int main(int argc, char** argv){
ndbout << argv[i] << ": " << dict->getNdbError() << endl;
}
- delete pMyNdb;
return NDBT_ProgramExit(NDBT_OK);
}
diff --git a/ndb/tools/drop_index.cpp b/ndb/tools/drop_index.cpp
index 2fcba41bd11..e2bf7f0bfae 100644
--- a/ndb/tools/drop_index.cpp
+++ b/ndb/tools/drop_index.cpp
@@ -41,37 +41,40 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_drop_index.trace");
-}
int main(int argc, char** argv){
NDB_INIT(argv[0]);
const char *load_default_groups[]= { "mysql_cluster",0 };
load_defaults("my",load_default_groups,&argc,&argv);
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ "d:t:O,/tmp/ndb_drop_index.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
if (argc < 1) {
usage();
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Ndb::setConnectString(opt_connect_str);
- // Connect to Ndb
- Ndb MyNdb(_dbname);
+ Ndb_cluster_connection con(opt_connect_str);
+ if(con.connect(12, 5, 1) != 0)
+ {
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ if (con.wait_until_ready(30,3) < 0)
+ {
+ ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ Ndb MyNdb(&con, _dbname );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
return NDBT_ProgramExit(NDBT_FAILED);
}
- while(MyNdb.waitUntilReady() != 0)
- ndbout << "Waiting for ndb to become ready..." << endl;
-
int res = 0;
for(int i = 0; i<argc; i++){
ndbout << "Dropping index " << argv[i] << "...";
diff --git a/ndb/tools/drop_tab.cpp b/ndb/tools/drop_tab.cpp
index 091db5cc4b7..991e1505486 100644
--- a/ndb/tools/drop_tab.cpp
+++ b/ndb/tools/drop_tab.cpp
@@ -41,36 +41,41 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_drop_table.trace");
-}
int main(int argc, char** argv){
NDB_INIT(argv[0]);
const char *load_default_groups[]= { "mysql_cluster",0 };
load_defaults("my",load_default_groups,&argc,&argv);
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ "d:t:O,/tmp/ndb_drop_table.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
if (argc < 1) {
usage();
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Ndb::setConnectString(opt_connect_str);
- Ndb MyNdb(_dbname);
+ Ndb_cluster_connection con(opt_connect_str);
+ if(con.connect(12, 5, 1) != 0)
+ {
+ ndbout << "Unable to connect to management server." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ if (con.wait_until_ready(30,3) < 0)
+ {
+ ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+
+ Ndb MyNdb(&con, _dbname );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
return NDBT_ProgramExit(NDBT_FAILED);
}
- while(MyNdb.waitUntilReady() != 0)
- ndbout << "Waiting for ndb to become ready..." << endl;
-
int res = 0;
for(int i = 0; i<argc; i++){
ndbout << "Dropping table " << argv[i] << "...";
diff --git a/ndb/tools/listTables.cpp b/ndb/tools/listTables.cpp
index 064ec299ef9..b4a2235f73b 100644
--- a/ndb/tools/listTables.cpp
+++ b/ndb/tools/listTables.cpp
@@ -29,7 +29,7 @@
static Ndb_cluster_connection *ndb_cluster_connection= 0;
static Ndb* ndb = 0;
-static NdbDictionary::Dictionary* dic = 0;
+static const NdbDictionary::Dictionary * dic = 0;
static int _unqualified = 0;
static void
@@ -196,13 +196,6 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_show_tables.trace");
-}
int main(int argc, char** argv){
NDB_INIT(argv[0]);
@@ -210,22 +203,29 @@ int main(int argc, char** argv){
const char *load_default_groups[]= { "mysql_cluster",0 };
load_defaults("my",load_default_groups,&argc,&argv);
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_show_tables.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
_tabname = argv[0];
ndb_cluster_connection = new Ndb_cluster_connection(opt_connect_str);
if (ndb_cluster_connection->connect(12,5,1))
- fatal("unable to connect");
+ fatal("Unable to connect to management server.");
+ if (ndb_cluster_connection->wait_until_ready(30,0) < 0)
+ fatal("Cluster nodes not ready in 30 seconds.");
+
ndb = new Ndb(ndb_cluster_connection, _dbname);
if (ndb->init() != 0)
fatal("init");
- if (ndb->waitUntilReady(30) < 0)
- fatal("waitUntilReady");
dic = ndb->getDictionary();
for (int i = 0; _loops == 0 || i < _loops; i++) {
list(_tabname, (NdbDictionary::Object::Type)_type);
}
+ delete ndb;
+ delete ndb_cluster_connection;
return NDBT_ProgramExit(NDBT_OK);
}
diff --git a/ndb/tools/ndb_test_platform.cpp b/ndb/tools/ndb_test_platform.cpp
index 72dd146dacd..88f21b31d58 100644
--- a/ndb/tools/ndb_test_platform.cpp
+++ b/ndb/tools/ndb_test_platform.cpp
@@ -33,14 +33,14 @@ int test_snprintf(const char * fmt, int buf_sz, int result)
if(ret < 0)
{
printf("BaseString::snprint returns %d with size=%d and strlen(fmt)=%d\n",
- ret, buf_sz, strlen(fmt));
+ ret, buf_sz, (int) strlen(fmt));
return -1;
}
if(ret+1 == buf_sz)
{
printf("BaseString::snprint truncates returns %d with size=%d and strlen(fmt)=%d\n",
- ret, buf_sz, strlen(fmt));
+ ret, buf_sz, (int) strlen(fmt));
return -1;
}
@@ -87,7 +87,7 @@ main(void)
if (sizeof(UintPtr) != sizeof(Uint32*))
{
printf("sizeof(UintPtr)=%d != sizeof(Uint32*)=%d\n",
- sizeof(UintPtr), sizeof(Uint32*));
+ (int) sizeof(UintPtr), (int) sizeof(Uint32*));
return -1;
}
diff --git a/ndb/tools/restore/consumer.cpp b/ndb/tools/restore/consumer.cpp
index ecbdbbf8f4e..b130c4998d5 100644
--- a/ndb/tools/restore/consumer.cpp
+++ b/ndb/tools/restore/consumer.cpp
@@ -45,9 +45,11 @@ BackupConsumer::create_table_string(const TableS & table,
pos += sprintf(buf+pos, "%s", "float");
break;
case NdbDictionary::Column::Olddecimal:
+ case NdbDictionary::Column::Decimal:
pos += sprintf(buf+pos, "%s", "decimal");
break;
case NdbDictionary::Column::Olddecimalunsigned:
+ case NdbDictionary::Column::Decimalunsigned:
pos += sprintf(buf+pos, "%s", "decimal unsigned");
break;
case NdbDictionary::Column::Char:
diff --git a/ndb/tools/restore/consumer_restore.cpp b/ndb/tools/restore/consumer_restore.cpp
index fbe96cb2a71..d72b82569e2 100644
--- a/ndb/tools/restore/consumer_restore.cpp
+++ b/ndb/tools/restore/consumer_restore.cpp
@@ -21,8 +21,9 @@ extern FilteredNdbOut err;
extern FilteredNdbOut info;
extern FilteredNdbOut debug;
-static void callback(int, NdbConnection*, void*);
+static void callback(int, NdbTransaction*, void*);
+extern const char * g_connect_string;
bool
BackupRestore::init()
{
@@ -31,7 +32,13 @@ BackupRestore::init()
if (!m_restore && !m_restore_meta)
return true;
- m_ndb = new Ndb();
+ m_cluster_connection = new Ndb_cluster_connection(g_connect_string);
+ if(m_cluster_connection->connect(12, 5, 1) != 0)
+ {
+ return -1;
+ }
+
+ m_ndb = new Ndb(m_cluster_connection);
if (m_ndb == NULL)
return false;
@@ -77,6 +84,12 @@ void BackupRestore::release()
delete [] m_callback;
m_callback= 0;
}
+
+ if (m_cluster_connection)
+ {
+ delete m_cluster_connection;
+ m_cluster_connection= 0;
+ }
}
BackupRestore::~BackupRestore()
@@ -201,7 +214,7 @@ BackupRestore::endOfTables(){
NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
for(size_t i = 0; i<m_indexes.size(); i++){
- const NdbTableImpl & indtab = NdbTableImpl::getImpl(* m_indexes[i]);
+ NdbTableImpl & indtab = NdbTableImpl::getImpl(* m_indexes[i]);
BaseString tmp(indtab.m_primaryTable.c_str());
Vector<BaseString> split;
@@ -362,7 +375,8 @@ void BackupRestore::tuple_a(restore_callback_t *cb)
}
// Prepare transaction (the transaction is NOT yet sent to NDB)
- cb->connection->executeAsynchPrepare(Commit, &callback, cb);
+ cb->connection->executeAsynchPrepare(NdbTransaction::Commit,
+ &callback, cb);
m_transactions++;
return;
}
@@ -479,7 +493,7 @@ BackupRestore::logEntry(const LogEntry & tup)
if (!m_restore)
return;
- NdbConnection * trans = m_ndb->startTransaction();
+ NdbTransaction * trans = m_ndb->startTransaction();
if (trans == NULL)
{
// Deep shit, TODO: handle the error
@@ -530,7 +544,7 @@ BackupRestore::logEntry(const LogEntry & tup)
op->setValue(attr->Desc->attrId, dataPtr, length);
}
- const int ret = trans->execute(Commit);
+ const int ret = trans->execute(NdbTransaction::Commit);
if (ret != 0)
{
// Both insert update and delete can fail during log running
@@ -571,12 +585,12 @@ BackupRestore::endOfLogEntrys()
*
* (This function must have three arguments:
* - The result of the transaction,
- * - The NdbConnection object, and
+ * - The NdbTransaction object, and
* - A pointer to an arbitrary object.)
*/
static void
-callback(int result, NdbConnection* trans, void* aObject)
+callback(int result, NdbTransaction* trans, void* aObject)
{
restore_callback_t *cb = (restore_callback_t *)aObject;
(cb->restore)->cback(result, cb);
@@ -590,7 +604,7 @@ BackupRestore::tuple(const TupleS & tup)
return;
while (1)
{
- NdbConnection * trans = m_ndb->startTransaction();
+ NdbTransaction * trans = m_ndb->startTransaction();
if (trans == NULL)
{
// Deep shit, TODO: handle the error
@@ -641,7 +655,7 @@ BackupRestore::tuple(const TupleS & tup)
else
op->setValue(i, dataPtr, length);
}
- int ret = trans->execute(Commit);
+ int ret = trans->execute(NdbTransaction::Commit);
if (ret != 0)
{
ndbout << "execute failed: ";
diff --git a/ndb/tools/restore/consumer_restore.hpp b/ndb/tools/restore/consumer_restore.hpp
index df219cd4412..1bf6d89a912 100644
--- a/ndb/tools/restore/consumer_restore.hpp
+++ b/ndb/tools/restore/consumer_restore.hpp
@@ -22,7 +22,7 @@
struct restore_callback_t {
class BackupRestore *restore;
class TupleS tup;
- class NdbConnection *connection;
+ class NdbTransaction *connection;
int retries;
int error_code;
restore_callback_t *next;
@@ -35,6 +35,7 @@ public:
BackupRestore(Uint32 parallelism=1)
{
m_ndb = 0;
+ m_cluster_connection = 0;
m_logCount = m_dataCount = 0;
m_restore = false;
m_restore_meta = false;
@@ -62,6 +63,7 @@ public:
virtual bool finalize_table(const TableS &);
void connectToMysql();
Ndb * m_ndb;
+ Ndb_cluster_connection * m_cluster_connection;
bool m_restore;
bool m_restore_meta;
Uint32 m_logCount;
diff --git a/ndb/tools/restore/consumer_restorem.cpp b/ndb/tools/restore/consumer_restorem.cpp
index 6a9ec07148a..56179a60ab0 100644
--- a/ndb/tools/restore/consumer_restorem.cpp
+++ b/ndb/tools/restore/consumer_restorem.cpp
@@ -21,8 +21,8 @@ extern FilteredNdbOut err;
extern FilteredNdbOut info;
extern FilteredNdbOut debug;
-static bool asynchErrorHandler(NdbConnection * trans, Ndb * ndb);
-static void callback(int result, NdbConnection* trans, void* aObject);
+static bool asynchErrorHandler(NdbTransaction * trans, Ndb * ndb);
+static void callback(int result, NdbTransaction* trans, void* aObject);
bool
BackupRestore::init()
@@ -80,6 +80,7 @@ BackupRestore::init()
ndbout_c("Connect failed: %s", mysql_error(&mysql));
returnValue = false;
}
+ mysql.reconnect= 1;
ndbout << "Connected to MySQL!!!" <<endl;
}
@@ -370,7 +371,7 @@ BackupRestore::tuple(const TupleS & tup)
return;
while (1)
{
- NdbConnection * trans = m_ndb->startTransaction();
+ NdbTransaction * trans = m_ndb->startTransaction();
if (trans == NULL)
{
// Deep shit, TODO: handle the error
@@ -459,7 +460,7 @@ BackupRestore::logEntry(const LogEntry & tup)
if (!m_restore)
return;
- NdbConnection * trans = m_ndb->startTransaction();
+ NdbTransaction * trans = m_ndb->startTransaction();
if (trans == NULL)
{
// Deep shit, TODO: handle the error
@@ -550,7 +551,7 @@ BackupRestore::endOfLogEntrys()
*
******************************************/
static void restoreCallback(int result, // Result for transaction
- NdbConnection *object, // Transaction object
+ NdbTransaction *object, // Transaction object
void *anything) // Not used
{
static Uint32 counter = 0;
@@ -592,12 +593,12 @@ static void restoreCallback(int result, // Result for transaction
*
* (This function must have three arguments:
* - The result of the transaction,
- * - The NdbConnection object, and
+ * - The NdbTransaction object, and
* - A pointer to an arbitrary object.)
*/
static void
-callback(int result, NdbConnection* trans, void* aObject)
+callback(int result, NdbTransaction* trans, void* aObject)
{
restore_callback_t *cb = (restore_callback_t *)aObject;
(cb->restore)->cback(result, cb);
@@ -609,7 +610,7 @@ callback(int result, NdbConnection* trans, void* aObject)
* false if it is an error that generates an abort.
*/
static
-bool asynchErrorHandler(NdbConnection * trans, Ndb* ndb)
+bool asynchErrorHandler(NdbTransaction * trans, Ndb* ndb)
{
NdbError error = trans->getNdbError();
ndb->closeTransaction(trans);
diff --git a/ndb/tools/restore/restore_main.cpp b/ndb/tools/restore/restore_main.cpp
index 84f9511fe2f..93c40d31adb 100644
--- a/ndb/tools/restore/restore_main.cpp
+++ b/ndb/tools/restore/restore_main.cpp
@@ -109,8 +109,10 @@ static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument)
{
- ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_restore.trace");
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_restore.trace";
+#endif
+ ndb_std_get_one_option(optid, opt, argument);
switch (optid) {
case 'n':
if (ga_nodeId == 0)
@@ -226,6 +228,8 @@ free_data_callback()
g_consumers[i]->tuple_free();
}
+const char * g_connect_string = 0;
+
int
main(int argc, char** argv)
{
@@ -236,7 +240,7 @@ main(int argc, char** argv)
return -1;
}
- Ndb::setConnectString(opt_connect_str);
+ g_connect_string = opt_connect_str;
/**
* we must always load meta data, even if we will only print it to stdout
diff --git a/ndb/tools/select_all.cpp b/ndb/tools/select_all.cpp
index 23fd2290349..baa18db1ebd 100644
--- a/ndb/tools/select_all.cpp
+++ b/ndb/tools/select_all.cpp
@@ -24,7 +24,6 @@
#include <NdbMain.h>
#include <NDBT.hpp>
#include <NdbSleep.h>
-#include <NdbScanFilter.hpp>
int scanReadRecords(Ndb*,
const NdbDictionary::Table*,
@@ -34,14 +33,15 @@ int scanReadRecords(Ndb*,
bool headers,
bool useHexFormat,
char delim,
- bool orderby);
+ bool orderby,
+ bool descending);
NDB_STD_OPTS_VARS;
static const char* _dbname = "TEST_DB";
static const char* _delimiter = "\t";
static int _unqualified, _header, _parallelism, _useHexFormat, _lock,
- _order;
+ _order, _descending;
static struct my_option my_long_options[] =
{
@@ -58,6 +58,9 @@ static struct my_option my_long_options[] =
{ "order", 'o', "Sort resultset according to index",
(gptr*) &_order, (gptr*) &_order, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "descending", 'z', "Sort descending (requires order flag)",
+ (gptr*) &_descending, (gptr*) &_descending, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "header", 'h', "Print header",
(gptr*) &_header, (gptr*) &_header, 0,
GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 },
@@ -82,13 +85,6 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_select_all.trace");
-}
int main(int argc, char** argv){
NDB_INIT(argv[0]);
@@ -96,26 +92,35 @@ int main(int argc, char** argv){
load_defaults("my",load_default_groups,&argc,&argv);
const char* _tabname;
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_select_all.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
if ((_tabname = argv[0]) == 0) {
usage();
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Ndb::setConnectString(opt_connect_str);
- // Connect to Ndb
- Ndb MyNdb(_dbname);
+ Ndb_cluster_connection con(opt_connect_str);
+ if(con.connect(12, 5, 1) != 0)
+ {
+ ndbout << "Unable to connect to management server." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ if (con.wait_until_ready(30,0) < 0)
+ {
+ ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, _dbname );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
return NDBT_ProgramExit(NDBT_FAILED);
}
- // Connect to Ndb and wait for it to become ready
- while(MyNdb.waitUntilReady() != 0)
- ndbout << "Waiting for ndb to become ready..." << endl;
-
// Check if table exists in db
const NdbDictionary::Table* pTab = NDBT_Table::discoverTableFromDb(&MyNdb, _tabname);
const NdbDictionary::Index * pIdx = 0;
@@ -138,6 +143,11 @@ int main(int argc, char** argv){
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
+ if (_descending && ! _order) {
+ ndbout << " Descending flag given without order flag" << endl;
+ return NDBT_ProgramExit(NDBT_WRONGARGS);
+ }
+
if (scanReadRecords(&MyNdb,
pTab,
pIdx,
@@ -145,7 +155,7 @@ int main(int argc, char** argv){
_lock,
_header,
_useHexFormat,
- (char)*_delimiter, _order) != 0){
+ (char)*_delimiter, _order, _descending) != 0){
return NDBT_ProgramExit(NDBT_FAILED);
}
@@ -160,12 +170,12 @@ int scanReadRecords(Ndb* pNdb,
int _lock,
bool headers,
bool useHexFormat,
- char delimiter, bool order){
+ char delimiter, bool order, bool descending){
int retryAttempt = 0;
const int retryMax = 100;
int check;
- NdbConnection *pTrans;
+ NdbTransaction *pTrans;
NdbScanOperation *pOp;
NdbIndexScanOperation * pIOp= 0;
@@ -202,7 +212,7 @@ int scanReadRecords(Ndb* pNdb,
return -1;
}
- NdbResultSet * rs;
+ int rs;
switch(_lock + (3 * order)){
case 1:
rs = pOp->readTuples(NdbScanOperation::LM_Read, 0, parallel);
@@ -212,20 +222,20 @@ int scanReadRecords(Ndb* pNdb,
break;
case 3:
rs = pIOp->readTuples(NdbScanOperation::LM_CommittedRead, 0, parallel,
- true);
+ true, descending);
break;
case 4:
- rs = pIOp->readTuples(NdbScanOperation::LM_Read, 0, parallel, true);
+ rs = pIOp->readTuples(NdbScanOperation::LM_Read, 0, parallel, true, descending);
break;
case 5:
- rs = pIOp->readTuples(NdbScanOperation::LM_Exclusive, 0, parallel, true);
+ rs = pIOp->readTuples(NdbScanOperation::LM_Exclusive, 0, parallel, true, descending);
break;
case 0:
default:
rs = pOp->readTuples(NdbScanOperation::LM_CommittedRead, 0, parallel);
break;
}
- if( rs == 0 ){
+ if( rs != 0 ){
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return -1;
@@ -291,7 +301,7 @@ int scanReadRecords(Ndb* pNdb,
}
}
- check = pTrans->execute(NoCommit);
+ check = pTrans->execute(NdbTransaction::NoCommit);
if( check == -1 ) {
const NdbError err = pTrans->getNdbError();
@@ -311,7 +321,7 @@ int scanReadRecords(Ndb* pNdb,
int eof;
int rows = 0;
- eof = rs->nextResult();
+ eof = pOp->nextResult();
while(eof == 0){
rows++;
@@ -322,7 +332,7 @@ int scanReadRecords(Ndb* pNdb,
ndbout << (*row) << endl;
}
- eof = rs->nextResult();
+ eof = pOp->nextResult();
}
if (eof == -1) {
const NdbError err = pTrans->getNdbError();
diff --git a/ndb/tools/select_count.cpp b/ndb/tools/select_count.cpp
index a9a3e71da67..6fa3c77f15a 100644
--- a/ndb/tools/select_count.cpp
+++ b/ndb/tools/select_count.cpp
@@ -30,7 +30,7 @@ static int
select_count(Ndb* pNdb, const NdbDictionary::Table* pTab,
int parallelism,
int* count_rows,
- UtilTransactions::ScanLock lock);
+ NdbOperation::LockMode lock);
NDB_STD_OPTS_VARS;
@@ -60,39 +60,41 @@ static void usage()
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_select_count.trace");
-}
int main(int argc, char** argv){
NDB_INIT(argv[0]);
const char *load_default_groups[]= { "mysql_cluster",0 };
load_defaults("my",load_default_groups,&argc,&argv);
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_select_count.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
if (argc < 1) {
usage();
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
- Ndb::setConnectString(opt_connect_str);
- // Connect to Ndb
- Ndb MyNdb(_dbname);
+ Ndb_cluster_connection con(opt_connect_str);
+ if(con.connect(12, 5, 1) != 0)
+ {
+ ndbout << "Unable to connect to management server." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ if (con.wait_until_ready(30,0) < 0)
+ {
+ ndbout << "Cluster nodes not ready in 30 seconds." << endl;
+ return NDBT_ProgramExit(NDBT_FAILED);
+ }
+ Ndb MyNdb(&con, _dbname );
if(MyNdb.init() != 0){
ERR(MyNdb.getNdbError());
return NDBT_ProgramExit(NDBT_FAILED);
}
- // Connect to Ndb and wait for it to become ready
- while(MyNdb.waitUntilReady() != 0)
- ndbout << "Waiting for ndb to become ready..." << endl;
-
for(int i = 0; i<argc; i++){
// Check if table exists in db
const NdbDictionary::Table * pTab = NDBT_Table::discoverTableFromDb(&MyNdb, argv[i]);
@@ -103,7 +105,7 @@ int main(int argc, char** argv){
int rows = 0;
if (select_count(&MyNdb, pTab, _parallelism, &rows,
- (UtilTransactions::ScanLock)_lock) != 0){
+ (NdbOperation::LockMode)_lock) != 0){
return NDBT_ProgramExit(NDBT_FAILED);
}
@@ -116,12 +118,12 @@ int
select_count(Ndb* pNdb, const NdbDictionary::Table* pTab,
int parallelism,
int* count_rows,
- UtilTransactions::ScanLock lock){
+ NdbOperation::LockMode lock){
int retryAttempt = 0;
const int retryMax = 100;
int check;
- NdbConnection *pTrans;
+ NdbTransaction *pTrans;
NdbScanOperation *pOp;
while (true){
@@ -151,8 +153,7 @@ select_count(Ndb* pNdb, const NdbDictionary::Table* pTab,
return NDBT_FAILED;
}
- NdbResultSet * rs = pOp->readTuples(NdbScanOperation::LM_Dirty);
- if( rs == 0 ) {
+ if( pOp->readTuples(NdbScanOperation::LM_Dirty) ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
return NDBT_FAILED;
@@ -167,9 +168,10 @@ select_count(Ndb* pNdb, const NdbDictionary::Table* pTab,
}
Uint64 tmp;
+ Uint32 row_size;
pOp->getValue(NdbDictionary::Column::ROW_COUNT, (char*)&tmp);
-
- check = pTrans->execute(NoCommit);
+ pOp->getValue(NdbDictionary::Column::ROW_SIZE, (char*)&row_size);
+ check = pTrans->execute(NdbTransaction::NoCommit);
if( check == -1 ) {
ERR(pTrans->getNdbError());
pNdb->closeTransaction(pTrans);
@@ -178,7 +180,7 @@ select_count(Ndb* pNdb, const NdbDictionary::Table* pTab,
Uint64 row_count = 0;
int eof;
- while((eof = rs->nextResult(true)) == 0){
+ while((eof = pOp->nextResult(true)) == 0){
row_count += tmp;
}
diff --git a/ndb/tools/waiter.cpp b/ndb/tools/waiter.cpp
index cc6a21428c8..db90bd8bd90 100644
--- a/ndb/tools/waiter.cpp
+++ b/ndb/tools/waiter.cpp
@@ -60,24 +60,19 @@ static void usage()
my_print_variables(my_long_options);
}
-static my_bool
-get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
-{
- return ndb_std_get_one_option(optid, opt, argument ? argument :
- "d:t:O,/tmp/ndb_drop_table.trace");
-}
-
int main(int argc, char** argv){
NDB_INIT(argv[0]);
const char *load_default_groups[]= { "mysql_cluster",0 };
load_defaults("my",load_default_groups,&argc,&argv);
const char* _hostName = NULL;
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_waiter.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
- char buf[255];
_hostName = argv[0];
if (_hostName == 0)
diff --git a/netware/BUILD/compile-linux-tools b/netware/BUILD/compile-linux-tools
index 70f07be649e..c21857146e0 100755
--- a/netware/BUILD/compile-linux-tools
+++ b/netware/BUILD/compile-linux-tools
@@ -36,8 +36,6 @@ make clean all-local
(cd heap; make libheap.a)
(cd vio; make libvio.a)
(cd regex; make libregex.a)
-(cd isam; make libnisam.a)
-(cd merge; make libmerge.a)
(cd myisam; make libmyisam.a)
(cd myisammrg; make libmyisammrg.a)
(cd extra; make comp_err)
diff --git a/netware/BUILD/compile-netware-START b/netware/BUILD/compile-netware-START
index 7eef192a907..9918ead87c5 100755
--- a/netware/BUILD/compile-netware-START
+++ b/netware/BUILD/compile-netware-START
@@ -22,5 +22,7 @@ base_configs=" \
--enable-local-infile \
--with-extra-charsets=all \
--prefix=N:/mysql \
+ --without-mysqlmanager \
+ --without-man \
"
diff --git a/netware/BUILD/nwbootstrap b/netware/BUILD/nwbootstrap
index 2bd7150ec0d..48ff2a49667 100755
--- a/netware/BUILD/nwbootstrap
+++ b/netware/BUILD/nwbootstrap
@@ -171,10 +171,10 @@ do
rm $file.org
done
-# create the libmysql.imp file in netware folder from libmysql/libmysql.def file
+# create the libmysql.imp file in netware folder from libmysql/libmysql.def
+# file
echo "generating llibmysql.imp file..."
awk 'BEGIN{x=0;} END{printf("\n");} x==1 {printf(" %s",$1); x++; next} x>1 {printf(",\n %s", $1);next} /EXPORTS/{x=1}' libmysql/libmysql.def > netware/libmysql.imp
-
# build linux tools
echo "compiling linux tools..."
./netware/BUILD/compile-linux-tools
diff --git a/netware/Makefile.am b/netware/Makefile.am
index 2467270f27b..92c8afba896 100644
--- a/netware/Makefile.am
+++ b/netware/Makefile.am
@@ -32,8 +32,6 @@ netware_build_files = client/mysql.def client/mysqladmin.def \
extra/mysql_install.def extra/my_print_defaults.def \
extra/perror.def extra/replace.def \
extra/resolveip.def extra/comp_err.def \
- isam/isamchk.def \
- isam/isamlog.def isam/pack_isam.def \
libmysqld/libmysqld.def myisam/myisamchk.def \
myisam/myisamlog.def myisam/myisampack.def \
sql/mysqld.def extra/mysql_waitpid.def \
@@ -48,7 +46,7 @@ link_sources:
done;
else
EXTRA_DIST= comp_err.def init_db.sql install_test_db.ncf \
- isamchk.def isamlog.def libmysql.def libmysql.imp \
+ libmysql.def libmysql.imp \
libmysqlmain.c my_manage.c my_manage.h \
my_print_defaults.def myisam_ftdump.def myisamchk.def \
myisamlog.def myisampack.def mysql.def mysql.xdc \
@@ -58,7 +56,7 @@ EXTRA_DIST= comp_err.def init_db.sql install_test_db.ncf \
mysql_test_run.def mysql_waitpid.def mysqladmin.def \
mysqlbinlog.def mysqlcheck.def mysqld.def \
mysqld_safe.c mysqld_safe.def mysqldump.def mysqlimport.def \
- mysqlshow.def mysqltest.def pack_isam.def perror.def \
+ mysqlshow.def mysqltest.def perror.def \
replace.def resolve_stack_dump.def resolveip.def test_db.sql \
static_init_db.sql \
BUILD/apply-patch BUILD/compile-AUTOTOOLS \
diff --git a/netware/my_manage.c b/netware/my_manage.c
index 29514837837..d5032da2208 100644
--- a/netware/my_manage.c
+++ b/netware/my_manage.c
@@ -73,7 +73,7 @@ void init_args(arg_list_t *al)
Add an argument to a list.
******************************************************************************/
-void add_arg(arg_list_t *al, char *format, ...)
+void add_arg(arg_list_t *al, const char *format, ...)
{
va_list ap;
char temp[PATH_MAX];
@@ -439,7 +439,7 @@ void del_tree(char *dir)
removef()
******************************************************************************/
-int removef(char *format, ...)
+int removef(const char *format, ...)
{
va_list ap;
char path[PATH_MAX];
diff --git a/netware/my_manage.h b/netware/my_manage.h
index ada02378ee4..480eefbe55a 100644
--- a/netware/my_manage.h
+++ b/netware/my_manage.h
@@ -26,17 +26,41 @@
******************************************************************************/
#include <stdlib.h>
+#ifndef __WIN__
#include <unistd.h>
+#endif
/******************************************************************************
macros
******************************************************************************/
+#ifdef __WIN__
+#define PATH_MAX _MAX_PATH
+#define NAME_MAX _MAX_FNAME
+#define kill(A,B) TerminateProcess((HANDLE)A,0)
+#define NOT_NEED_PID 0
+#define MASTER_PID 1
+#define SLAVE_PID 2
+#define mysqld_timeout 60000
+
+intptr_t master_server;
+intptr_t slave_server;
+int pid_mode;
+bool run_server;
+char win_args[1024];
+bool skip_first_param;
+#endif
+
#define ARG_BUF 10
#define TRY_MAX 5
+#ifdef __NETWARE__
+#define strstr(A,B) strindex(A,B)
+#endif
+
+
/******************************************************************************
structures
@@ -53,6 +77,8 @@ typedef struct
} arg_list_t;
+
+typedef int pid_t;
/******************************************************************************
global variables
@@ -66,7 +92,7 @@ typedef struct
******************************************************************************/
void init_args(arg_list_t *);
-void add_arg(arg_list_t *, char *, ...);
+void add_arg(arg_list_t *, const char *, ...);
void free_args(arg_list_t *);
int sleep_until_file_exists(char *);
@@ -80,8 +106,12 @@ pid_t get_server_pid(char *);
void kill_server(pid_t pid);
void del_tree(char *);
-int removef(char *, ...);
+int removef(const char *, ...);
void get_basedir(char *, char *);
+char mysqladmin_file[PATH_MAX];
+
#endif /* _MY_MANAGE */
+
+
diff --git a/os2/ChangeLog.os2 b/os2/ChangeLog.os2
index 7957906ad7d..18356b840ed 100644
--- a/os2/ChangeLog.os2
+++ b/os2/ChangeLog.os2
@@ -1,5 +1,8 @@
+2005/01/01
+ - removed references to ISAM and MERGE
+
2002/05/02
- now libinit is automatically called on client dll startup
diff --git a/os2/MySQL-Source.icc b/os2/MySQL-Source.icc
index f4ac881c90e..de0ac75ec9c 100644
--- a/os2/MySQL-Source.icc
+++ b/os2/MySQL-Source.icc
@@ -84,8 +84,6 @@ group sql =
"..\\sql\\field_conv.cc",
"..\\sql\\filesort.cc",
"..\\sql\\ha_heap.cc",
- "..\\sql\\ha_isam.cc",
- "..\\sql\\ha_isammrg.cc",
"..\\sql\\ha_myisam.cc",
"..\\sql\\ha_myisammrg.cc",
"..\\sql\\handler.cc",
@@ -151,21 +149,6 @@ group sql =
"..\\sql\\unireg.cc",
"..\\sql\\violite.c"
-group isam =
- "..\\isam\\changed.c", "..\\isam\\close.c",
- "..\\isam\\create.c", "..\\isam\\delete.c", "..\\isam\\extra.c",
- "..\\isam\\info.c", "..\\isam\\log.c", "..\\isam\\open.c",
- "..\\isam\\panic.c", "..\\isam\\range.c",
- "..\\isam\\rfirst.c", "..\\isam\\rkey.c", "..\\isam\\rlast.c",
- "..\\isam\\rnext.c", "..\\isam\\rprev.c", "..\\isam\\rrnd.c",
- "..\\isam\\rsame.c", "..\\isam\\rsamepos.c",
- "..\\isam\\static.c", "..\\isam\\update.c",
- "..\\isam\\write.c", "..\\isam\\_cache.c",
- "..\\isam\\_dbug.c", "..\\isam\\_dynrec.c",
- "..\\isam\\_key.c", "..\\isam\\_locking.c",
- "..\\isam\\_packrec.c", "..\\isam\\_page.c",
- "..\\isam\\_search.c", "..\\isam\\_statrec.c"
-
group strings =
"..\\strings\\bchange.c",
"..\\strings\\bmove.c",
@@ -214,13 +197,6 @@ group strings =
"..\\heap\\hp_write.c", "..\\heap\\_check.c", "..\\heap\\_rectest.c"
- group merge = "..\\merge\\close.c", "..\\merge\\create.c", "..\\merge\\delete.c",
- "..\\merge\\extra.c", "..\\merge\\info.c", "..\\merge\\open.c",
- "..\\merge\\panic.c", "..\\merge\\rrnd.c", "..\\merge\\rsame.c",
- "..\\merge\\static.c", "..\\merge\\update.c",
- "..\\merge\\_locking.c"
-
-
group myisammrg = "..\\myisammrg\\myrg_close.c",
"..\\myisammrg\\myrg_create.c", "..\\myisammrg\\myrg_delete.c",
"..\\myisammrg\\myrg_extra.c", "..\\myisammrg\\myrg_info.c",
diff --git a/os2/MySQL-Sql.icc b/os2/MySQL-Sql.icc
index c1256d5e39e..7c8c61fe7de 100644
--- a/os2/MySQL-Sql.icc
+++ b/os2/MySQL-Sql.icc
@@ -30,8 +30,6 @@ option ProjectOptions = MySQLOptions
source type('cpp') dbug
}
source type('cpp') heap
- source type('cpp') isam
- source type('cpp') merge
source type('cpp') myisam
source type('cpp') myisammrg
source type('cpp') my_sys
diff --git a/os2/MySQL-Util.icc b/os2/MySQL-Util.icc
index 36fd499e520..8eaee41b6a2 100644
--- a/os2/MySQL-Util.icc
+++ b/os2/MySQL-Util.icc
@@ -25,10 +25,8 @@ option ProjectOptions = MySQLOptions
source type('cpp') dbug
}
source type('cpp') heap
- source type('cpp') merge
source type('cpp') myisam
source type('cpp') myisammrg
- source type('cpp') isam
source type('cpp') my_sys
source type('cpp') my_sys_cli
source type('cpp') my_sys_sql
@@ -89,16 +87,6 @@ option ProjectOptions = MySQLOptions
source type('cpp') "..\\sql\\gen_lex_hash.cc"
}
- target "..\\bin\\test\\is_test1.exe"
- {
- // target source files
- source type('cpp') "..\\isam\\test1.c"
- }
- target "..\\bin\\test\\is_test2.exe"
- {
- // target source files
- source type('cpp') "..\\isam\\test2.c"
- }
target "..\\bin\\test\\mi_test1.exe"
{
// target source files
diff --git a/regex/Makefile.am b/regex/Makefile.am
index ee7fc5463b7..07d7a03635d 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 = @MT_INCLUDES@ -I$(top_srcdir)/include
+INCLUDES = -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/regex/engine.c b/regex/engine.c
index 6734560b9bf..c4c4efe7e2f 100644
--- a/regex/engine.c
+++ b/regex/engine.c
@@ -256,7 +256,7 @@ sopno stopst;
register char *ssp; /* start of string matched by subsubRE */
register char *sep; /* end of string matched by subsubRE */
register char *oldssp; /* previous ssp */
- register char *dp;
+ register char *dp; /* used in debug mode to check asserts */
AT("diss", start, stop, startst, stopst);
sp = start;
diff --git a/regex/main.c b/regex/main.c
index 29abca6d9a2..8fe16d74eee 100644
--- a/regex/main.c
+++ b/regex/main.c
@@ -78,7 +78,7 @@ char *argv[];
if (err) {
len = regerror(err, &re, erbuf, sizeof(erbuf));
fprintf(stderr, "error %s, %d/%d `%s'\n",
- eprint(err), len, (int) sizeof(erbuf), erbuf);
+ eprint(err), (int) len, (int) sizeof(erbuf), erbuf);
exit(status);
}
regprint(&re, stdout);
diff --git a/regex/regerror.c b/regex/regerror.c
index 0a7b7c8da2c..9caa5b95a4c 100644
--- a/regex/regerror.c
+++ b/regex/regerror.c
@@ -56,11 +56,7 @@ static struct rerr {
*/
/* ARGSUSED */
size_t
-regerror(errcode, preg, errbuf, errbuf_size)
-int errcode;
-const regex_t *preg;
-char *errbuf;
-size_t errbuf_size;
+regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
{
register struct rerr *r;
register size_t len;
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index e2ef1bba97c..b2fef9acadf 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -88,7 +88,7 @@ CLEANFILES = @server_scripts@ \
make_win_src_distribution \
mysql_create_system_tables
-SUPERCLEANFILES = mysqlbug
+DISTCLEANFILES = mysqlbug
# We want the right version and configure comand line in mysqlbug
mysqlbug: ${top_builddir}/config.status mysqlbug.sh
diff --git a/scripts/fill_func_tables.sh b/scripts/fill_func_tables.sh
index 459afee2fe1..203c730dd9a 100644
--- a/scripts/fill_func_tables.sh
+++ b/scripts/fill_func_tables.sh
@@ -131,8 +131,8 @@ print "USE mysql_help;\n";
print "DROP TABLE IF EXISTS function;\n";
print "CREATE TABLE function (";
print " func_id int unsigned not null auto_increment,";
-print " name varchar(64) not null,";
-print " url varchar(128) not null,";
+print " name char(64) not null,";
+print " url char(128) not null,";
print " description text not null,";
print " example text not null,";
print " min_args tinyint not null,";
@@ -145,8 +145,8 @@ print ") type=myisam;\n\n";
print "DROP TABLE IF EXISTS function_category_name;\n";
print "CREATE TABLE function_category_name (";
print " cat_id smallint unsigned not null auto_increment,";
-print " name varchar(64) not null,";
-print " url varchar(128) not null,";
+print " name char(64) not null,";
+print " url char(128) not null,";
print " date_created datetime not null,";
print " last_modified timestamp not null,";
print " primary key (cat_id)";
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
index 46d1b74d2bf..17a9be17108 100644
--- a/scripts/make_binary_distribution.sh
+++ b/scripts/make_binary_distribution.sh
@@ -96,14 +96,14 @@ do
fi
done
-# Non platform-specific bin dir files:
+# Non platform-specific bin files:
BIN_FILES="extra/comp_err$BS extra/replace$BS extra/perror$BS \
extra/resolveip$BS extra/my_print_defaults$BS \
extra/resolve_stack_dump$BS extra/mysql_waitpid$BS \
- isam/isamchk$BS isam/pack_isam$BS \
myisam/myisamchk$BS myisam/myisampack$BS myisam/myisamlog$BS \
myisam/myisam_ftdump$BS \
sql/mysqld$BS sql/mysql_tzinfo_to_sql$BS \
+ server-tools/instance-manager/mysqlmanager$BS \
client/mysql$BS client/mysqlshow$BS client/mysqladmin$BS \
client/mysqldump$BS client/mysqlimport$BS \
client/mysqltest$BS client/mysqlcheck$BS \
@@ -113,23 +113,23 @@ BIN_FILES="extra/comp_err$BS extra/replace$BS extra/perror$BS \
libmysqld/examples/mysqltest_embedded$BS \
";
-# Platform-specific bin dir files:
+# Platform-specific bin files:
if [ $BASE_SYSTEM = "netware" ] ; then
BIN_FILES="$BIN_FILES \
netware/mysqld_safe$BS netware/mysql_install_db$BS \
netware/init_db.sql netware/test_db.sql netware/mysql_explain_log$BS \
- netware/mysqlhotcopy$BS netware/libmysql$BS netware/init_secure_db.sql
+ netware/mysqlhotcopy$BS netware/libmysql$BS netware/init_secure_db.sql \
";
+# For all other platforms:
else
- # For all other platforms:
BIN_FILES="$BIN_FILES \
- client/mysqlmanagerc \
- client/mysqlmanager-pwgen tools/mysqlmanager \
+ client/mysqltestmanagerc \
+ client/mysqltestmanager-pwgen tools/mysqltestmanager \
client/.libs/mysql client/.libs/mysqlshow client/.libs/mysqladmin \
client/.libs/mysqldump client/.libs/mysqlimport \
client/.libs/mysqltest client/.libs/mysqlcheck \
- client/.libs/mysqlbinlog client/.libs/mysqlmanagerc \
- client/.libs/mysqlmanager-pwgen tools/.libs/mysqlmanager \
+ client/.libs/mysqlbinlog client/.libs/mysqltestmanagerc \
+ client/.libs/mysqltestmanager-pwgen tools/.libs/mysqltestmanager \
tests/.libs/mysql_client_test \
libmysqld/examples/.libs/mysql_client_test_embedded \
libmysqld/examples/.libs/mysqltest_embedded \
@@ -208,6 +208,7 @@ rm -f $MYSQL_SHARE/Makefile* $MYSQL_SHARE/*/*.OLD
for i in mysql-test/mysql-test-run mysql-test/install_test_db \
mysql-test/mysql-test-run.pl mysql-test/README \
+ mysql-test/valgrind.supp \
netware/mysql_test_run.nlm netware/install_test_db.ncf
do
if [ -f $i ]
@@ -219,16 +220,20 @@ 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/std_data/*.dat mysql-test/std_data/*.*001 $BASE/mysql-test/std_data
-$CP mysql-test/std_data/des_key_file $BASE/mysql-test/std_data
-$CP mysql-test/t/*test mysql-test/t/*.opt mysql-test/t/*.slave-mi mysql-test/t/*.sh $BASE/mysql-test/t
-$CP mysql-test/r/*result mysql-test/r/*.require $BASE/mysql-test/r
+$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 \
+ $BASE/mysql-test/std_data
+$CP mysql-test/t/*.test mysql-test/t/*.disabled mysql-test/t/*.opt \
+ mysql-test/t/*.slave-mi mysql-test/t/*.sh $BASE/mysql-test/t
+$CP mysql-test/r/*.result mysql-test/r/*.require \
+ $BASE/mysql-test/r
if [ $BASE_SYSTEM != "netware" ] ; then
chmod a+x $BASE/bin/*
$CP scripts/* $BASE/bin
$BASE/bin/replace \@localstatedir\@ ./data \@bindir\@ ./bin \@scriptdir\@ ./bin \@libexecdir\@ ./bin \@sbindir\@ ./bin \@prefix\@ . \@HOSTNAME\@ @HOSTNAME@ \@pkgdatadir\@ ./support-files < $SOURCE/scripts/mysql_install_db.sh > $BASE/scripts/mysql_install_db
- $BASE/bin/replace \@prefix\@ /usr/local/mysql \@bindir\@ ./bin \@MYSQLD_USER\@ root \@localstatedir\@ /usr/local/mysql/data \@HOSTNAME\@ @HOSTNAME@ < $SOURCE/support-files/mysql.server.sh > $BASE/support-files/mysql.server
+ $BASE/bin/replace \@prefix\@ /usr/local/mysql \@bindir\@ ./bin \@sbindir\@ ./bin \@libexecdir\@ ./bin \@MYSQLD_USER\@ @MYSQLD_USER@ \@localstatedir\@ /usr/local/mysql/data \@HOSTNAME\@ @HOSTNAME@ < $SOURCE/support-files/mysql.server.sh > $BASE/support-files/mysql.server
$BASE/bin/replace /my/gnu/bin/hostname /bin/hostname -- $BASE/bin/mysqld_safe
mv $BASE/support-files/binary-configure $BASE/configure
chmod a+x $BASE/bin/* $BASE/scripts/* $BASE/support-files/mysql-* $BASE/support-files/mysql.server $BASE/configure
@@ -246,10 +251,8 @@ rm -f $BASE/bin/Makefile* $BASE/bin/*.in $BASE/bin/*.sh $BASE/bin/mysql_install_
if [ $BASE_SYSTEM = "netware" ] ; then
echo "CREATE DATABASE mysql;" > $BASE/bin/init_db.sql
echo "CREATE DATABASE test;" >> $BASE/bin/init_db.sql
- sh ./scripts/mysql_create_system_tables.sh real "" "%" 0 >> $BASE/bin/init_db.sql
- sh ./scripts/mysql_create_system_tables.sh test "" "%" 0 > $BASE/bin/test_db.sql
-# cp ./netware/static_init_db.sql ./netware/init_db.sql
-# ./scripts/fill_help_tables < ./Docs/manual.texi >> ./netware/init_db.sql
+ sh ./scripts/mysql_create_system_tables.sh real >> $BASE/bin/init_db.sql
+ sh ./scripts/mysql_create_system_tables.sh test > $BASE/bin/test_db.sql
fi
#
@@ -269,7 +272,9 @@ fi
# Make safe_mysqld a symlink to mysqld_safe for backwards portability
# To be removed in MySQL 4.1
-(cd $BASE/bin ; ln -s mysqld_safe safe_mysqld )
+if [ $BASE_SYSTEM != "netware" ] ; then
+ (cd $BASE/bin ; ln -s mysqld_safe safe_mysqld )
+fi
# Clean up if we did this from a bk tree
if [ -d $BASE/sql-bench/SCCS ] ; then
diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh
index b8dd907920c..8fdf23f3119 100644
--- a/scripts/make_win_src_distribution.sh
+++ b/scripts/make_win_src_distribution.sh
@@ -249,8 +249,8 @@ copy_dir_dirs() {
# Input directories to be copied
#
-for i in client dbug extra heap include isam \
- libmysql libmysqld merge myisam \
+for i in client dbug extra heap include \
+ libmysql libmysqld myisam \
myisammrg mysys regex sql strings sql-common sql/examples \
tools vio zlib
do
@@ -298,6 +298,8 @@ do
fi
done
+cp extra/sql_state.h extra/mysqld_error.h $BASE/include
+
#
# support files
#
diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh
index 4c642423879..e76fc935b03 100644
--- a/scripts/mysql_create_system_tables.sh
+++ b/scripts/mysql_create_system_tables.sh
@@ -41,6 +41,7 @@ c_hk=""
i_ht=""
c_tzn="" c_tz="" c_tzt="" c_tztt="" c_tzls=""
i_tzn="" i_tz="" i_tzt="" i_tztt="" i_tzls=""
+c_p="" c_pp=""
# Check for old tables
if test ! -f $mdata/db.frm
@@ -66,14 +67,19 @@ then
c_d="$c_d Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
c_d="$c_d Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
c_d="$c_d Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_d="$c_d Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
c_d="$c_d PRIMARY KEY Host (Host,Db,User),"
c_d="$c_d KEY User (User)"
c_d="$c_d ) engine=MyISAM"
c_d="$c_d CHARACTER SET utf8 COLLATE utf8_bin"
c_d="$c_d comment='Database privileges';"
- i_d="INSERT INTO db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y');
- INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y');"
+ i_d="INSERT INTO db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N');
+ INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N');"
fi
if test ! -f $mdata/host.frm
@@ -97,6 +103,8 @@ then
c_h="$c_h Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
c_h="$c_h Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
c_h="$c_h Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_h="$c_h Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
c_h="$c_h PRIMARY KEY Host (Host,Db)"
c_h="$c_h ) engine=MyISAM"
c_h="$c_h CHARACTER SET utf8 COLLATE utf8_bin"
@@ -134,6 +142,11 @@ then
c_u="$c_u Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
c_u="$c_u Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
c_u="$c_u Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
+ c_u="$c_u Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,"
c_u="$c_u ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL,"
c_u="$c_u ssl_cipher BLOB NOT NULL,"
c_u="$c_u x509_issuer BLOB NOT NULL,"
@@ -141,6 +154,7 @@ then
c_u="$c_u max_questions int(11) unsigned DEFAULT 0 NOT NULL,"
c_u="$c_u max_updates int(11) unsigned DEFAULT 0 NOT NULL,"
c_u="$c_u max_connections int(11) unsigned DEFAULT 0 NOT NULL,"
+ c_u="$c_u max_user_connections int(11) unsigned DEFAULT 0 NOT NULL,"
c_u="$c_u PRIMARY KEY Host (Host,User)"
c_u="$c_u ) engine=MyISAM"
c_u="$c_u CHARACTER SET utf8 COLLATE utf8_bin"
@@ -148,22 +162,22 @@ then
if test "$1" = "test"
then
- i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);
- INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);
- REPLACE INTO user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);
+ i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
+ INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
+ REPLACE INTO user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
INSERT INTO user (host,user) values ('localhost','');
INSERT INTO user (host,user) values ('$hostname','');"
else
- i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);"
+ i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);"
if test "$windows" = "0"
then
i_u="$i_u
- INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);
+ INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);
INSERT INTO user (host,user) values ('$hostname','');
INSERT INTO user (host,user) values ('localhost','');"
else
i_u="$i_u
- INSERT INTO user VALUES ('localhost','','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);"
+ INSERT INTO user VALUES ('localhost','','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);"
fi
fi
fi
@@ -227,6 +241,27 @@ then
c_c="$c_c comment='Column privileges';"
fi
+if test ! -f $mdata/procs_priv.frm
+then
+ if test "$1" = "verbose" ; then
+ echo "Preparing procs_priv table" 1>&2;
+ fi
+
+ c_pp="$c_pp CREATE TABLE procs_priv ("
+ c_pp="$c_pp Host char(60) binary DEFAULT '' NOT NULL,"
+ c_pp="$c_pp Db char(64) binary DEFAULT '' NOT NULL,"
+ c_pp="$c_pp User char(16) binary DEFAULT '' NOT NULL,"
+ c_pp="$c_pp Routine_name char(64) binary DEFAULT '' NOT NULL,"
+ c_pp="$c_pp Grantor char(77) DEFAULT '' NOT NULL,"
+ c_pp="$c_pp Timestamp timestamp(14),"
+ c_pp="$c_pp Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL,"
+ c_pp="$c_pp PRIMARY KEY (Host,Db,User,Routine_name),"
+ c_pp="$c_pp KEY Grantor (Grantor)"
+ c_pp="$c_pp ) engine=MyISAM"
+ c_pp="$c_pp CHARACTER SET utf8 COLLATE utf8_bin"
+ c_pp="$c_pp comment='Procedure privileges';"
+fi
+
if test ! -f $mdata/help_topic.frm
then
if test "$1" = "verbose" ; then
@@ -235,11 +270,11 @@ then
c_ht="$c_ht CREATE TABLE help_topic ("
c_ht="$c_ht help_topic_id int unsigned not null,"
- c_ht="$c_ht name varchar(64) not null,"
+ c_ht="$c_ht name char(64) not null,"
c_ht="$c_ht help_category_id smallint unsigned not null,"
c_ht="$c_ht description text not null,"
c_ht="$c_ht example text not null,"
- c_ht="$c_ht url varchar(128) not null,"
+ c_ht="$c_ht url char(128) not null,"
c_ht="$c_ht primary key (help_topic_id),"
c_ht="$c_ht unique index (name)"
c_ht="$c_ht ) engine=MyISAM"
@@ -257,9 +292,9 @@ then
c_hc="$c_hc CREATE TABLE help_category ("
c_hc="$c_hc help_category_id smallint unsigned not null,"
- c_hc="$c_hc name varchar(64) not null,"
+ c_hc="$c_hc name char(64) not null,"
c_hc="$c_hc parent_category_id smallint unsigned null,"
- c_hc="$c_hc url varchar(128) not null,"
+ c_hc="$c_hc url char(128) not null,"
c_hc="$c_hc primary key (help_category_id),"
c_hc="$c_hc unique index (name)"
c_hc="$c_hc ) engine=MyISAM"
@@ -275,7 +310,7 @@ then
c_hk="$c_hk CREATE TABLE help_keyword ("
c_hk="$c_hk help_keyword_id int unsigned not null,"
- c_hk="$c_hk name varchar(64) not null,"
+ c_hk="$c_hk name char(64) not null,"
c_hk="$c_hk primary key (help_keyword_id),"
c_hk="$c_hk unique index (name)"
c_hk="$c_hk ) engine=MyISAM"
@@ -627,6 +662,64 @@ then
fi
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 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,"
+ c_p="$c_p language enum('SQL') DEFAULT 'SQL' NOT NULL,"
+ c_p="$c_p sql_data_access enum('CONTAINS_SQL',"
+ c_p="$c_p 'NO_SQL',"
+ c_p="$c_p 'READS_SQL_DATA',"
+ c_p="$c_p 'MODIFIES_SQL_DATA'"
+ c_p="$c_p ) DEFAULT 'CONTAINS_SQL' NOT NULL,"
+ c_p="$c_p is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL,"
+ c_p="$c_p security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL,"
+ 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 created timestamp,"
+ c_p="$c_p modified timestamp,"
+ c_p="$c_p sql_mode set("
+ c_p="$c_p 'REAL_AS_FLOAT',"
+ c_p="$c_p 'PIPES_AS_CONCAT',"
+ c_p="$c_p 'ANSI_QUOTES',"
+ c_p="$c_p 'IGNORE_SPACE',"
+ c_p="$c_p 'NOT_USED',"
+ c_p="$c_p 'ONLY_FULL_GROUP_BY',"
+ c_p="$c_p 'NO_UNSIGNED_SUBTRACTION',"
+ c_p="$c_p 'NO_DIR_IN_CREATE',"
+ c_p="$c_p 'POSTGRESQL',"
+ c_p="$c_p 'ORACLE',"
+ c_p="$c_p 'MSSQL',"
+ c_p="$c_p 'DB2',"
+ c_p="$c_p 'MAXDB',"
+ c_p="$c_p 'NO_KEY_OPTIONS',"
+ c_p="$c_p 'NO_TABLE_OPTIONS',"
+ c_p="$c_p 'NO_FIELD_OPTIONS',"
+ c_p="$c_p 'MYSQL323',"
+ c_p="$c_p 'MYSQL40',"
+ c_p="$c_p 'ANSI',"
+ c_p="$c_p 'NO_AUTO_VALUE_ON_ZERO',"
+ c_p="$c_p 'NO_BACKSLASH_ESCAPES',"
+ c_p="$c_p 'STRICT_TRANS_TABLES',"
+ c_p="$c_p 'STRICT_ALL_TABLES',"
+ c_p="$c_p 'NO_ZERO_IN_DATE',"
+ c_p="$c_p 'NO_ZERO_DATE',"
+ c_p="$c_p 'INVALID_DATES',"
+ c_p="$c_p 'ERROR_FOR_DIVISION_BY_ZERO',"
+ 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 PRIMARY KEY (db,name,type)"
+ c_p="$c_p ) comment='Stored Procedures';"
+fi
+
cat << END_OF_DATA
use mysql;
set table_type=myisam;
@@ -660,5 +753,9 @@ $c_tztt
$i_tztt
$c_tzls
$i_tzls
+
+$c_p
+$c_pp
+
END_OF_DATA
diff --git a/scripts/mysql_fix_privilege_tables.sh b/scripts/mysql_fix_privilege_tables.sh
index 56807a81d7c..d080b68b268 100644
--- a/scripts/mysql_fix_privilege_tables.sh
+++ b/scripts/mysql_fix_privilege_tables.sh
@@ -7,13 +7,14 @@ password=""
host="localhost"
user="root"
sql_only=0
-basedir=""
+basedir="@prefix@"
verbose=0
args=""
port=""
socket=""
database="mysql"
bindir=""
+pkgdatadir="@pkgdatadir@"
print_defaults_bindir="."
file=mysql_fix_privilege_tables.sql
@@ -89,34 +90,23 @@ done
parse_arguments `$print_defaults $defaults mysql_install_db mysql_fix_privilege_tables`
parse_arguments PICK-ARGS-FROM-ARGV "$@"
-if test -z "$basedir"
+if test -z "$password"
then
- basedir=@prefix@
- if test -z "$bindir"
- then
- bindir=@bindir@
- fi
- execdir=@libexecdir@
- pkgdatadir=@pkgdatadir@
-else
- if test -z "$bindir"
- then
- bindir="$basedir/bin"
- fi
- if test -x "$basedir/libexec/mysqld"
- then
- execdir="$basedir/libexec"
- elif test -x "@libexecdir@/mysqld"
- then
- execdir="@libexecdir@"
- else
- execdir="$basedir/bin"
- fi
+ password=$old_style_password
fi
-if test -z "$password"
+# Find where 'mysql' command is located
+
+if test -z "$bindir"
then
- password=$old_style_password
+ for i in @bindir@ $basedir/bin client
+ do
+ if test -f $i/mysql
+ then
+ bindir=$i
+ break
+ fi
+ done
fi
cmd="$bindir/mysql --no-defaults --force --user=$user --host=$host"
@@ -138,7 +128,7 @@ fi
# Find where first mysql_fix_privilege_tables.sql is located
for i in $basedir/support-files $basedir/share $basedir/share/mysql \
- $basedir/scripts @pkgdatadir@ . ./scripts
+ $basedir/scripts $pkgdatadir . ./scripts
do
if test -f $i/$file
then
@@ -167,7 +157,8 @@ s_echo "This script updates all the mysql privilege tables to be usable by"
s_echo "MySQL 4.0 and above."
s_echo ""
s_echo "This is needed if you want to use the new GRANT functions,"
-s_echo "CREATE AGGREGATE FUNCTION, or the more secure passwords in 4.1"
+s_echo "CREATE AGGREGATE FUNCTION, stored procedures, or"
+s_echo "more secure passwords in 4.1"
s_echo ""
if test $verbose = 1
@@ -189,7 +180,7 @@ then
s_echo "done"
else
s_echo "Got a failure from command:"
- s_echo "$cmd"
+ s_echo "cat $sql_file | $cmd"
s_echo "Please check the above output and try again."
if test $verbose = 0
then
diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql
index 0d7d32fd6a9..d18536e1c81 100644
--- a/scripts/mysql_fix_privilege_tables.sql
+++ b/scripts/mysql_fix_privilege_tables.sql
@@ -9,7 +9,7 @@
-- this sql script.
-- On windows you should do 'mysql --force mysql < mysql_fix_privilege_tables.sql'
-set table_type=MyISAM;
+set storage_engine=MyISAM;
CREATE TABLE IF NOT EXISTS func (
name char(64) binary DEFAULT '' NOT NULL,
@@ -64,13 +64,16 @@ CREATE TABLE IF NOT EXISTS tables_priv (
ALTER TABLE tables_priv
modify Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
modify Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL;
+ALTER TABLE procs_priv ENGINE=MyISAM, CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;
+ALTER TABLE procs_priv
+ modify Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL;
CREATE TABLE IF NOT EXISTS columns_priv (
Host char(60) DEFAULT '' NOT NULL,
- Db char(60) DEFAULT '' NOT NULL,
+ Db char(64) DEFAULT '' NOT NULL,
User char(16) DEFAULT '' NOT NULL,
- Table_name char(60) DEFAULT '' NOT NULL,
- Column_name char(59) DEFAULT '' NOT NULL,
+ Table_name char(64) DEFAULT '' NOT NULL,
+ Column_name char(64) DEFAULT '' NOT NULL,
Timestamp timestamp(14),
Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
PRIMARY KEY (Host,Db,User,Table_name,Column_name)
@@ -118,9 +121,9 @@ UPDATE user SET Show_db_priv= Select_priv, Super_priv=Process_priv, Execute_priv
-- for some users.
ALTER TABLE user
-ADD max_questions int(11) NOT NULL AFTER x509_subject,
-ADD max_updates int(11) unsigned NOT NULL AFTER max_questions,
-ADD max_connections int(11) unsigned NOT NULL AFTER max_updates;
+ADD max_questions int(11) NOT NULL DEFAULT 0 AFTER x509_subject,
+ADD max_updates int(11) unsigned NOT NULL DEFAULT 0 AFTER max_questions,
+ADD max_connections int(11) unsigned NOT NULL DEFAULT 0 AFTER max_updates;
--
@@ -134,12 +137,8 @@ ALTER TABLE host
ADD Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
ADD Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL;
-alter table db change Db Db char(64) binary DEFAULT '' NOT NULL;
-alter table host change Db Db char(64) binary DEFAULT '' NOT NULL;
alter table user change max_questions max_questions int(11) unsigned DEFAULT 0 NOT NULL;
-alter table tables_priv change Db Db char(64) binary DEFAULT '' NOT NULL, change Host Host char(60) binary DEFAULT '' NOT NULL, change User User char(16) binary DEFAULT '' NOT NULL, change Table_name Table_name char(64) binary DEFAULT '' NOT NULL;
alter table tables_priv add KEY Grantor (Grantor);
-alter table columns_priv change Db Db char(64) binary DEFAULT '' NOT NULL, change Host Host char(60) binary DEFAULT '' NOT NULL, change User User char(16) binary DEFAULT '' NOT NULL, change Table_name Table_name char(64) binary DEFAULT '' NOT NULL, change Column_name Column_name char(64) binary DEFAULT '' NOT NULL;
alter table db comment='Database privileges';
alter table host comment='Host privileges; Merged with database privileges';
@@ -238,8 +237,88 @@ ALTER TABLE tables_priv
MODIFY Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL;
#
+# Detect whether we had Create_view_priv
+#
+SET @hadCreateViewPriv:=0;
+SELECT @hadCreateViewPriv:=1 FROM user WHERE Create_view_priv LIKE '%';
+
+#
+# Create VIEWs privileges (v5.0)
+#
+ALTER TABLE db ADD Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Lock_tables_priv;
+ALTER TABLE host ADD Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Lock_tables_priv;
+ALTER TABLE user ADD Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Repl_client_priv;
+
+#
+# Show VIEWs privileges (v5.0)
+#
+ALTER TABLE db ADD Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_view_priv;
+ALTER TABLE host ADD Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_view_priv;
+ALTER TABLE user ADD Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_view_priv;
+
+#
+# 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;
+
+#
+#
+#
+SET @hadCreateRoutinePriv:=0;
+SELECT @hadCreateRoutinePriv:=1 FROM user WHERE Create_routine_priv LIKE '%';
+
+#
+# Create PROCEDUREs privileges (v5.0)
+#
+ALTER TABLE db ADD Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Show_view_priv;
+ALTER TABLE user ADD Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Show_view_priv;
+
+#
+# Alter PROCEDUREs privileges (v5.0)
+#
+ALTER TABLE db ADD Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_routine_priv;
+ALTER TABLE user ADD Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_routine_priv;
+
+ALTER TABLE db ADD Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Alter_routine_priv;
+
+#
+# Assign create/alter routine privileges to people who have create privileges
+#
+UPDATE user SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv where user<>"" AND @hadCreateRoutinePriv = 0;
+UPDATE db SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv, Execute_priv=Select_priv where user<>"" AND @hadCreateRoutinePriv = 0;
+
+#
+# Add max_user_connections resource limit
+#
+ALTER TABLE user ADD max_user_connections int(11) unsigned DEFAULT '0' NOT NULL AFTER max_connections;
+
+#
+# user.Create_user_priv
+#
+
+SET @hadCreateUserPriv:=0;
+SELECT @hadCreateUserPriv:=1 FROM user WHERE Create_user_priv LIKE '%';
+
+ALTER TABLE user ADD Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Alter_routine_priv;
+UPDATE user LEFT JOIN db USING (Host,User) SET Create_user_priv='Y'
+ WHERE @hadCreateUserPriv = 0 AND
+ (user.Grant_priv = 'Y' OR db.Grant_priv = 'Y');
+
+#
# Create some possible missing tables
#
+CREATE TABLE IF NOT EXISTS procs_priv (
+Host char(60) binary DEFAULT '' NOT NULL,
+Db char(64) binary DEFAULT '' NOT NULL,
+User char(16) binary DEFAULT '' NOT NULL,
+Routine_name char(64) binary DEFAULT '' NOT NULL,
+Grantor char(77) DEFAULT '' NOT NULL,
+Timestamp timestamp(14),
+Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
+PRIMARY KEY (Host,Db,User,Routine_name),
+KEY Grantor (Grantor)
+) CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges';
+
CREATE TABLE IF NOT EXISTS help_topic (
help_topic_id int unsigned not null,
name varchar(64) not null,
@@ -313,3 +392,104 @@ Correction int signed NOT NULL,
PRIMARY KEY TranTime (Transition_time)
) CHARACTER SET utf8 comment='Leap seconds information for time zones';
+
+#
+# Create proc table if it doesn't exists
+#
+
+CREATE TABLE IF NOT EXISTS proc (
+ db char(64) binary 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,
+ 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,
+ created timestamp,
+ modified timestamp,
+ 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'
+ ) DEFAULT 0 NOT NULL,
+ comment char(64) binary DEFAULT '' NOT NULL,
+ PRIMARY KEY (db,name,type)
+) 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_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'
+ ) DEFAULT 0 NOT NULL;
diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh
index 0b82e02761e..e1e2d4ce148 100644
--- a/scripts/mysql_install_db.sh
+++ b/scripts/mysql_install_db.sh
@@ -3,7 +3,7 @@
# For a more info consult the file COPYRIGHT distributed with this file.
# This scripts creates the privilege tables db, host, user, tables_priv,
-# columns_priv in the mysql database, as well as the func table.
+# columns_priv, procs_priv in the mysql database, as well as the func table.
#
# All unrecognized arguments to this script are passed to mysqld.
diff --git a/scripts/mysql_tableinfo.sh b/scripts/mysql_tableinfo.sh
index f5083a776c6..2ed7e381fa3 100644
--- a/scripts/mysql_tableinfo.sh
+++ b/scripts/mysql_tableinfo.sh
@@ -6,6 +6,14 @@ use DBI;
=head1 NAME
+WARNING: MySQL versions 5.0 and above feature the INFORMATION_SCHEMA
+pseudo-database which contains always up-to-date metadata information
+about all tables. So instead of using this script one can now
+simply query the INFORMATION_SCHEMA.SCHEMATA, INFORMATION_SCHEMA.TABLES,
+INFORMATION_SCHEMA.COLUMNS, INFORMATION_SCHEMA.STATISTICS pseudo-tables.
+Please see the MySQL manual for more information about INFORMATION_SCHEMA.
+This script will be removed from the MySQL distribution in version 5.1.
+
mysql_tableinfo - creates and populates information tables with
the output of SHOW DATABASES, SHOW TABLES (or SHOW TABLE STATUS),
SHOW COLUMNS and SHOW INDEX.
@@ -62,6 +70,19 @@ GetOptions( \%opt,
"quiet|q",
) or usage("Invalid option");
+if (!$opt{'quiet'})
+ {
+ print <<EOF
+WARNING: MySQL versions 5.0 and above feature the INFORMATION_SCHEMA
+pseudo-database which contains always up-to-date metadata information
+about all tables. So instead of using this script one can now
+simply query the INFORMATION_SCHEMA.SCHEMATA, INFORMATION_SCHEMA.TABLES,
+INFORMATION_SCHEMA.COLUMNS, INFORMATION_SCHEMA.STATISTICS pseudo-tables.
+Please see the MySQL manual for more information about INFORMATION_SCHEMA.
+This script will be removed from the MySQL distribution in version 5.1.
+EOF
+ }
+
if ($opt{'help'}) {usage();}
my ($db_to_write,$db_like_wild,$tbl_like_wild);
@@ -104,7 +125,7 @@ $tbl_like_wild=$dbh->quote($tbl_like_wild);
if (!$opt{'quiet'})
{
- print "\n!! This program is doing to do:\n\n";
+ print "\n!! This program is going to do:\n\n";
print "**DROP** TABLE ...\n" if ($opt{'clear'} or $opt{'clear-only'});
print "**DELETE** FROM ... WHERE `Database` LIKE $db_like_wild AND `Table` LIKE $tbl_like_wild
**INSERT** INTO ...
@@ -456,17 +477,14 @@ UNIX domain socket to use when connecting to server
=head1 WARRANTY
-This software is free and comes without warranty of any kind. You
-should never trust backup software without studying the code yourself.
-Study the code inside this script and only rely on it if I<you> believe
-that it does the right thing for you.
+This software is free and comes without warranty of any kind.
Patches adding bug fixes, documentation and new features are welcome.
=head1 TO DO
-Use extended inserts to be faster (for servers with many databases
-or tables). But to do that, must care about net-buffer-length.
+Nothing: starting from MySQL 5.0, this program is replaced by the
+INFORMATION_SCHEMA pseudo-database.
=head1 AUTHOR
diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh
index ba46fd6fa29..642772bca44 100644
--- a/scripts/mysqld_multi.sh
+++ b/scripts/mysqld_multi.sh
@@ -4,7 +4,7 @@ use Getopt::Long;
use POSIX qw(strftime);
$|=1;
-$VER="2.11";
+$VER="2.14";
$opt_config_file = undef();
$opt_example = 0;
@@ -37,13 +37,13 @@ main();
sub main
{
- my ($flag_exit);
+ my $flag_exit= 0;
if (!defined(my_which(my_print_defaults)))
{
# We can't throw out yet, since --version, --help, or --example may
# have been given
- print "WARNING! my_print_defaults command not found!\n";
+ print "WARNING: my_print_defaults command not found.\n";
print "Please make sure you have this command available and\n";
print "in your path. The command is available from the latest\n";
print "MySQL distribution.\n";
@@ -66,6 +66,11 @@ sub main
else
{
$opt_config_file= $1;
+ if (!($opt_config_file =~ m/\//))
+ {
+ # No path. Use current working directory
+ $opt_config_file= "./" . $opt_config_file;
+ }
}
}
}
@@ -76,10 +81,18 @@ sub main
chop @defops;
splice @ARGV, 0, 0, @defops;
}
- GetOptions("help","example","version","mysqld=s","mysqladmin=s",
- "config-file=s","user=s","password=s","log=s","no-log","tcp-ip",
- "silent","verbose")
- || die "Wrong option! See $my_progname --help for detailed information!\n";
+ if (!GetOptions("help","example","version","mysqld=s","mysqladmin=s",
+ "config-file=s","user=s","password=s","log=s","no-log",
+ "tcp-ip", "silent","verbose"))
+ {
+ $flag_exit= 1;
+ }
+ if (defined($opt_config_file) && !($opt_config_file =~ m/\//))
+ {
+ # No path. Use current working directory
+ $opt_config_file= "./" . $opt_config_file;
+ }
+ usage() if ($opt_help);
if ($opt_verbose && $opt_silent)
{
@@ -95,15 +108,14 @@ sub main
exit(0);
}
example() if ($opt_example);
- usage() if ($opt_help);
if ($flag_exit)
{
- print "Error with an option, see $my_progname --help for more info!\n";
+ print "Error with an option, see $my_progname --help for more info.\n";
exit(1);
}
if (!defined(my_which(my_print_defaults)))
{
- print "ABORT: Can't find command 'my_print_defaults'!\n";
+ print "ABORT: Can't find command 'my_print_defaults'.\n";
print "This command is available from the latest MySQL\n";
print "distribution. Please make sure you have the command\n";
print "in your PATH.\n";
@@ -157,6 +169,31 @@ sub main
}
####
+#### Quote option argument. Add double quotes around the argument
+#### and escape the following: $, \, "
+#### This function is needed, because my_print_defaults drops possible
+#### quotes, single or double, from in front of an argument and from
+#### the end.
+####
+
+sub quote_opt_arg
+{
+ my ($option)= @_;
+
+ if ($option =~ m/(\-\-[a-zA-Z0-9\_\-]+)=(.*)/)
+ {
+ $option= $1;
+ $arg= $2;
+ $arg=~ s/\\/\\\\/g; # Escape escape character first to avoid doubling.
+ $arg=~ s/\$/\\\$/g;
+ $arg=~ s/\"/\\\"/g;
+ $arg= "\"" . $arg . "\"";
+ $option= $option . "=" . $arg;
+ }
+ return $option;
+}
+
+####
#### Init log file. Check for appropriate place for log file, in the following
#### order my_print_defaults mysqld datadir, @datadir@, /var/log, /tmp
####
@@ -290,6 +327,7 @@ sub start_mysqlds()
else
{
$options[$j]=~ s/;/\\;/g;
+ $options[$j]= quote_opt_arg($options[$j]);
$tmp.= " $options[$j]";
}
}
@@ -430,6 +468,16 @@ sub find_groups
{
$data[$i] = $line;
}
+ if (defined($ENV{MYSQL_HOME}) && -f "$ENV{MYSQL_HOME}/my.cnf" &&
+ -r "$ENV{MYSQL_HOME}/my.cnf")
+ {
+ open(MY_CNF, "<$ENV{MYSQL_HOME}/my.cnf") && (@tmp=<MY_CNF>) &&
+ close(MY_CNF);
+ }
+ for (; ($line = shift @tmp); $i++)
+ {
+ $data[$i] = $line;
+ }
if (-f "$homedir/.my.cnf" && -r "$homedir/.my.cnf")
{
open(MY_CNF, "<$homedir/.my.cnf") && (@tmp=<MY_CNF>) && close(MY_CNF);
diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh
index 8a232f4f7f9..9ec573737bd 100644
--- a/scripts/mysqld_safe.sh
+++ b/scripts/mysqld_safe.sh
@@ -23,6 +23,29 @@ case "$1" in
;;
esac
+usage () {
+ cat <<EOF
+Usage: $0 [OPTIONS]
+ --no-defaults Don't read the system defaults file
+ --defaults-file=FILE Use the specified defaults file
+ --defaults-extra-file=FILE Also use defaults from the specified file
+ --ledir=DIRECTORY Look for mysqld in the specified directory
+ --log-error=FILE Log errors to the specified log file
+ --open-files-limit=LIMIT Limit the number of open files
+ --core-file-size=LIMIT Limit core files to the specified size
+ --timezone=TZ Set the system timezone
+ --mysqld=FILE Use the specified file as mysqld
+ --mysqld-version=VERSION Use "mysqld-VERSION" as mysqld
+ --nice=NICE Set the scheduling priority of mysqld
+ --skip-kill-mysqld Don't try to kill stray mysqld processes
+
+All other options are passed to the mysqld program.
+
+EOF
+ exit 1
+}
+
+
parse_arguments() {
# We only need to pass arguments through to the server if we don't
# handle them here. So, we collect unrecognized options (passed on
@@ -52,11 +75,7 @@ parse_arguments() {
# mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])!
--ledir=*) ledir=`echo "$arg" | sed -e "s;--ledir=;;"` ;;
- # err-log should be removed in 5.0
- --err-log=*) err_log=`echo "$arg" | sed -e "s;--err-log=;;"` ;;
--log-error=*) err_log=`echo "$arg" | sed -e "s;--log-error=;;"` ;;
- # QQ The --open-files should be removed in 5.0
- --open-files=*) open_files=`echo "$arg" | sed -e "s;--open-files=;;"` ;;
--open-files-limit=*) open_files=`echo "$arg" | sed -e "s;--open-files-limit=;;"` ;;
--core-file-size=*) core_file_size=`echo "$arg" | sed -e "s;--core-file-size=;;"` ;;
--timezone=*) TZ=`echo "$arg" | sed -e "s;--timezone=;;"` ; export TZ; ;;
@@ -71,6 +90,9 @@ parse_arguments() {
fi
;;
--nice=*) niceness=`echo "$arg" | sed -e "s;--nice=;;"` ;;
+ --help)
+ usage
+ ;;
*)
if test -n "$pick_args"
then
@@ -94,7 +116,7 @@ then
DATADIR=$MY_BASEDIR_VERSION/data
if test -z "$defaults"
then
- defaults="--defaults-extra-file=$MY_BASEDIR_VERSION/data/my.cnf"
+ defaults="--defaults-extra-file=$DATADIR/my.cnf"
fi
# Check if this is a 'moved install directory'
elif test -f ./share/mysql/english/errmsg.sys -a \
@@ -109,6 +131,28 @@ else
ledir=@libexecdir@
fi
+if test -z "$MYSQL_HOME"
+then
+ if test -r "$MY_BASEDIR_VERSION/my.cnf" && test -r "$DATADIR/my.cnf"
+ then
+ echo "WARNING: Found two instances of my.cnf -"
+ echo "$MY_BASEDIR_VERSION/my.cnf and"
+ echo "$DATADIR/my.cnf"
+ echo "IGNORING $DATADIR/my.cnf"
+ echo
+ MYSQL_HOME=$MY_BASEDIR_VERSION
+ elif test -r "$DATADIR/my.cnf"
+ then
+ echo "WARNING: Found $DATADIR/my.cnf"
+ echo "Datadir is deprecated place for my.cnf, please move it to $MY_BASEDIR_VERSION"
+ echo
+ MYSQL_HOME=$DATADIR
+ else
+ MYSQL_HOME=$MY_BASEDIR_VERSION
+ fi
+fi
+export MYSQL_HOME
+
user=@MYSQLD_USER@
niceness=0
diff --git a/server-tools/Makefile.am b/server-tools/Makefile.am
new file mode 100644
index 00000000000..ed316b9ac38
--- /dev/null
+++ b/server-tools/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS= instance-manager
diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am
new file mode 100644
index 00000000000..18f62a04bfb
--- /dev/null
+++ b/server-tools/instance-manager/Makefile.am
@@ -0,0 +1,93 @@
+# Copyright (C) 2004 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
+
+INCLUDES= -I$(top_srcdir)/include -I$(top_builddir)/include
+
+DEFS= -DMYSQL_INSTANCE_MANAGER -DMYSQL_SERVER
+
+# As all autoconf variables depend from ${prefix} and being resolved only when
+# make is run, we can not put these defines to a header file (e.g. to
+# default_options.h, generated from default_options.h.in)
+# See automake/autoconf docs for details
+
+noinst_LIBRARIES= liboptions.a libnet.a
+
+liboptions_a_CXXFLAGS= $(CXXFLAGS) \
+ -DDEFAULT_PID_FILE_NAME="$(localstatedir)/mysqlmanager.pid" \
+ -DDEFAULT_LOG_FILE_NAME="$(localstatedir)/mysqlmanager.log" \
+ -DDEFAULT_SOCKET_FILE_NAME="/tmp/mysqlmanager.sock" \
+ -DDEFAULT_PASSWORD_FILE_NAME="$(sysconfdir)/mysqlmanager.passwd" \
+ -DDEFAULT_MYSQLD_PATH="$(libexecdir)/mysqld$(EXEEXT)" \
+ -DDEFAULT_MONITORING_INTERVAL="20" \
+ -DDEFAULT_PORT="2273" \
+ -DPROTOCOL_VERSION=@PROTOCOL_VERSION@
+
+liboptions_a_SOURCES= options.h options.cc priv.h priv.cc
+liboptions_a_LIBADD= $(top_builddir)/libmysql/get_password.$(OBJEXT)
+
+# MySQL sometimes uses symlinks to reuse code
+# All symlinked files are grouped in libnet.a
+
+nodist_libnet_a_SOURCES= net_serv.cc client_settings.h
+libnet_a_LIBADD= $(top_builddir)/sql/password.$(OBJEXT) \
+ $(top_builddir)/sql/pack.$(OBJEXT) \
+ $(top_builddir)/sql/sql_state.$(OBJEXT) \
+ $(top_builddir)/sql/mini_client_errors.$(OBJEXT)\
+ $(top_builddir)/sql/client.$(OBJEXT)
+
+CLEANFILES= net_serv.cc client_settings.h
+
+net_serv.cc:
+ rm -f $(srcdir)/net_serv.cc
+ @LN_CP_F@ $(top_srcdir)/sql/net_serv.cc $(srcdir)/net_serv.cc
+
+client_settings.h:
+ rm -f $(srcdir)/client_settings.h
+ @LN_CP_F@ $(top_srcdir)/sql/client_settings.h $(srcdir)/client_settings.h
+
+libexec_PROGRAMS= mysqlmanager
+
+mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \
+ manager.h manager.cc log.h log.cc \
+ thread_registry.h thread_registry.cc \
+ listener.h listener.cc protocol.h protocol.cc \
+ mysql_connection.h mysql_connection.cc \
+ user_map.h user_map.cc \
+ messages.h messages.cc \
+ commands.h commands.cc \
+ factory.h factory.cc \
+ instance.h instance.cc \
+ instance_map.h instance_map.cc\
+ instance_options.h instance_options.cc \
+ buffer.h buffer.cc parse.cc parse.h \
+ guardian.cc guardian.h \
+ parse_output.cc parse_output.h \
+ mysql_manager_error.h
+
+mysqlmanager_LDADD= liboptions.a \
+ libnet.a \
+ $(top_builddir)/vio/libvio.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/strings/libmystrings.a \
+ $(top_builddir)/dbug/libdbug.a \
+ @openssl_libs@ @ZLIB_LIBS@
+
+
+tags:
+ ctags -R *.h *.cc
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/server-tools/instance-manager/README b/server-tools/instance-manager/README
new file mode 100644
index 00000000000..ac799775003
--- /dev/null
+++ b/server-tools/instance-manager/README
@@ -0,0 +1,11 @@
+Instance Manager - manage MySQL instances locally and remotely.
+
+File description:
+ mysqlmanager.cc - entry point to the manager, main,
+ options.{h,cc} - handle startup options
+ manager.{h,cc} - manager process
+ mysql_connection.{h,cc} - handle one connection with mysql client.
+
+See also instance manager architecture description in mysqlmanager.cc.
+
+
diff --git a/server-tools/instance-manager/buffer.cc b/server-tools/instance-manager/buffer.cc
new file mode 100644
index 00000000000..b000a48d5ae
--- /dev/null
+++ b/server-tools/instance-manager/buffer.cc
@@ -0,0 +1,109 @@
+/* Copyright (C) 2004 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "buffer.h"
+#include <m_string.h>
+
+
+/*
+ Puts the given string to the buffer.
+
+ SYNOPSYS
+ append()
+ position start position in the buffer
+ string string to be put in the buffer
+ len_arg the length of the string. This way we can avoid some
+ strlens.
+
+ DESCRIPTION
+
+ The method puts a string into the buffer, starting from position .
+ In the case when the buffer is too small it reallocs the buffer. The
+ total size of the buffer is restricted with 16.
+
+ RETURN
+ 0 - ok
+ 1 - got an error in reserve()
+*/
+
+int Buffer::append(uint position, const char *string, uint len_arg)
+{
+ if (reserve(position, len_arg))
+ return 1;
+
+ strnmov(buffer + position, string, len_arg);
+ return 0;
+}
+
+
+/*
+ Checks whether the current buffer size is ok to put a string of the length
+ "len_arg" starting from "position" and reallocs it if no.
+
+ SYNOPSYS
+ reserve()
+ position the number starting byte on the buffer to store a buffer
+ len_arg the length of the string.
+
+ DESCRIPTION
+
+ The method checks whether it is possible to pus a string of teh "len_arg"
+ length into the buffer, starting from "position" byte. In the case when the
+ buffer is too small it reallocs the buffer. The total size of the buffer is
+ restricted with 16 Mb.
+
+ RETURN
+ 0 - ok
+ 1 - realloc error or we have come to the 16Mb barrier
+*/
+
+int Buffer::reserve(uint position, uint len_arg)
+{
+ if (position + len_arg >= MAX_BUFFER_SIZE)
+ goto err;
+
+ if (position + len_arg >= buffer_size)
+ {
+ buffer= (char *) my_realloc(buffer,
+ min(MAX_BUFFER_SIZE,
+ max((uint) (buffer_size*1.5),
+ position + len_arg)), MYF(0));
+ if (!(buffer))
+ goto err;
+ buffer_size= (uint) (buffer_size*1.5);
+ }
+ return 0;
+
+err:
+ error= 1;
+ return 1;
+}
+
+
+int Buffer::get_size()
+{
+ return buffer_size;
+}
+
+
+int Buffer::is_error()
+{
+ return error;
+}
diff --git a/server-tools/instance-manager/buffer.h b/server-tools/instance-manager/buffer.h
new file mode 100644
index 00000000000..a94047b11a5
--- /dev/null
+++ b/server-tools/instance-manager/buffer.h
@@ -0,0 +1,66 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H
+/* Copyright (C) 2004 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h>
+#include <my_sys.h>
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+/*
+ This class is a simple implementation of the buffer of varying size.
+ It is used to store MySQL client-server protocol packets. This is why
+ the maximum buffer size if 16Mb. (See internals manual section
+ 7. MySQL Client/Server Protocol)
+*/
+
+class Buffer
+{
+private:
+ enum { BUFFER_INITIAL_SIZE= 4096 };
+ /* maximum buffer size is 16Mb */
+ enum { MAX_BUFFER_SIZE= 16777216 };
+ size_t buffer_size;
+ /* Error flag. Triggered if we get an error of some kind */
+ int error;
+public:
+ Buffer(size_t buffer_size_arg= BUFFER_INITIAL_SIZE)
+ :buffer_size(buffer_size_arg), error(0)
+ {
+ /*
+ As append() will invokes realloc() anyway, it's ok if malloc returns 0
+ */
+ if (!(buffer= (char*) my_malloc(buffer_size, MYF(0))))
+ buffer_size= 0;
+ }
+
+ ~Buffer()
+ {
+ free(buffer);
+ }
+
+public:
+ char *buffer;
+ int get_size();
+ int is_error();
+ int append(uint position, const char *string, uint len_arg);
+ int reserve(uint position, uint len_arg);
+};
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H */
diff --git a/merge/mrg_static.c b/server-tools/instance-manager/command.cc
index 1b7327c870f..818c4b0cae2 100644
--- a/merge/mrg_static.c
+++ b/server-tools/instance-manager/command.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,13 +14,20 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*
- Static variables for pisam library. All definied here for easy making of
- a shared library
-*/
-
-#ifndef stdin
-#include "mrg_def.h"
+#ifdef __GNUC__
+#pragma implementation
#endif
-LIST *mrg_open_list=0;
+#include "command.h"
+
+
+Command::Command(Instance_map *instance_map_arg)
+ :instance_map(instance_map_arg)
+{}
+
+Command::~Command()
+{}
+
+#ifdef __GNUC__
+FIX_GCC_LINKING_PROBLEM
+#endif
diff --git a/server-tools/instance-manager/command.h b/server-tools/instance-manager/command.h
new file mode 100644
index 00000000000..8ae4e33b92f
--- /dev/null
+++ b/server-tools/instance-manager/command.h
@@ -0,0 +1,47 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H
+/* Copyright (C) 2004 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 */
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <my_global.h>
+
+/* Class responsible for allocation of im commands. */
+
+class Instance_map;
+
+/*
+ Command - entry point for any command.
+ GangOf4: 'Command' design pattern
+*/
+
+class Command
+{
+public:
+ Command(Instance_map *instance_map_arg= 0);
+ virtual ~Command();
+
+ /* method of executing: */
+ virtual int execute(struct st_net *net, ulong connection_id) = 0;
+
+protected:
+ Instance_map *instance_map;
+};
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H */
diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc
new file mode 100644
index 00000000000..e1f811ef57d
--- /dev/null
+++ b/server-tools/instance-manager/commands.cc
@@ -0,0 +1,410 @@
+/* Copyright (C) 2004 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 "commands.h"
+
+#include "instance_map.h"
+#include "messages.h"
+#include "mysqld_error.h"
+#include "mysql_manager_error.h"
+#include "protocol.h"
+#include "buffer.h"
+
+#include <m_string.h>
+#include <mysql.h>
+
+
+/* implementation for Show_instances: */
+
+
+/*
+ The method sends a list of instances in the instance map to the client.
+
+ SYNOPSYS
+ Show_instances::do_command()
+ net The network connection to the client.
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+int Show_instances::do_command(struct st_net *net)
+{
+ Buffer send_buff; /* buffer for packets */
+ LIST name, status;
+ NAME_WITH_LENGTH name_field, status_field;
+ LIST *field_list;
+ uint position=0;
+
+ name_field.name= (char *) "instance_name";
+ name_field.length= 20;
+ name.data= &name_field;
+ status_field.name= (char *) "status";
+ status_field.length= 20;
+ status.data= &status_field;
+ field_list= list_add(NULL, &status);
+ field_list= list_add(field_list, &name);
+
+ send_fields(net, field_list);
+
+ {
+ Instance *instance;
+ Instance_map::Iterator iterator(instance_map);
+
+ instance_map->lock();
+ while ((instance= iterator.next()))
+ {
+ position= 0;
+ store_to_string(&send_buff, instance->options.instance_name, &position);
+ if (instance->is_running())
+ store_to_string(&send_buff, (char *) "online", &position);
+ else
+ store_to_string(&send_buff, (char *) "offline", &position);
+ if (my_net_write(net, send_buff.buffer, (uint) position))
+ goto err;
+ }
+ instance_map->unlock();
+ }
+ if (send_eof(net))
+ goto err;
+ if (net_flush(net))
+ goto err;
+
+ return 0;
+err:
+ return 1;
+}
+
+
+int Show_instances::execute(struct st_net *net, ulong connection_id)
+{
+ if (do_command(net))
+ return ER_OUT_OF_RESOURCES;
+
+ return 0;
+}
+
+
+/* implementation for Flush_instances: */
+
+int Flush_instances::execute(struct st_net *net, ulong connection_id)
+{
+ if (instance_map->flush_instances())
+ return ER_OUT_OF_RESOURCES;
+
+ net_send_ok(net, connection_id);
+ return 0;
+}
+
+
+/* implementation for Show_instance_status: */
+
+Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
+ const char *name, uint len)
+ :Command(instance_map_arg)
+{
+ Instance *instance;
+
+ /* we make a search here, since we don't want t store the name */
+ if ((instance= instance_map->find(name, len)))
+ {
+ instance_name= instance->options.instance_name;
+ }
+ else
+ instance_name= NULL;
+}
+
+
+/*
+ The method sends a table with a status of requested instance to the client.
+
+ SYNOPSYS
+ Show_instance_status::do_command()
+ net The network connection to the client.
+ instance_name The name of the instance.
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+
+int Show_instance_status::do_command(struct st_net *net,
+ const char *instance_name)
+{
+ enum { MAX_VERSION_LENGTH= 40 };
+ Buffer send_buff; /* buffer for packets */
+ LIST name, status, version;
+ LIST *field_list;
+ NAME_WITH_LENGTH name_field, status_field, version_field;
+ uint position=0;
+
+ /* create list of the fileds to be passed to send_fields */
+ name_field.name= (char *) "instance_name";
+ name_field.length= 20;
+ name.data= &name_field;
+ status_field.name= (char *) "status";
+ status_field.length= 20;
+ status.data= &status_field;
+ version_field.name= (char *) "version";
+ version_field.length= MAX_VERSION_LENGTH;
+ version.data= &version_field;
+ field_list= list_add(NULL, &version);
+ field_list= list_add(field_list, &status);
+ field_list= list_add(field_list, &name);
+
+ send_fields(net, field_list);
+
+ {
+ Instance *instance;
+
+ store_to_string(&send_buff, (char *) instance_name, &position);
+ if (!(instance= instance_map->find(instance_name, strlen(instance_name))))
+ goto err;
+ if (instance->is_running())
+ {
+ store_to_string(&send_buff, (char *) "online", &position);
+ store_to_string(&send_buff, "unknown", &position);
+ }
+ else
+ {
+ store_to_string(&send_buff, (char *) "offline", &position);
+ store_to_string(&send_buff, (char *) "unknown", &position);
+ }
+
+
+ if (send_buff.is_error() ||
+ my_net_write(net, send_buff.buffer, (uint) position))
+ goto err;
+ }
+
+ send_eof(net);
+ net_flush(net);
+
+ return 0;
+
+err:
+ return 1;
+}
+
+
+int Show_instance_status::execute(struct st_net *net, ulong connection_id)
+{
+ if ((instance_name))
+ {
+ if (do_command(net, instance_name))
+ return ER_OUT_OF_RESOURCES;
+ return 0;
+ }
+ else
+ {
+ return ER_BAD_INSTANCE_NAME;
+ }
+}
+
+
+/* Implementation for Show_instance_options */
+
+Show_instance_options::Show_instance_options(Instance_map *instance_map_arg,
+ const char *name, uint len):
+ Command(instance_map_arg)
+{
+ Instance *instance;
+
+ /* we make a search here, since we don't want t store the name */
+ if ((instance= instance_map->find(name, len)))
+ {
+ instance_name= instance->options.instance_name;
+ }
+ else
+ instance_name= NULL;
+}
+
+
+int Show_instance_options::do_command(struct st_net *net,
+ const char *instance_name)
+{
+ enum { MAX_VERSION_LENGTH= 40 };
+ Buffer send_buff; /* buffer for packets */
+ LIST name, option;
+ LIST *field_list;
+ NAME_WITH_LENGTH name_field, option_field;
+ uint position=0;
+
+ /* create list of the fileds to be passed to send_fields */
+ name_field.name= (char *) "option_name";
+ name_field.length= 20;
+ name.data= &name_field;
+ option_field.name= (char *) "value";
+ option_field.length= 20;
+ option.data= &option_field;
+ field_list= list_add(NULL, &option);
+ field_list= list_add(field_list, &name);
+
+ send_fields(net, field_list);
+
+ {
+ Instance *instance;
+
+ if (!(instance= instance_map->find(instance_name, strlen(instance_name))))
+ goto err;
+ store_to_string(&send_buff, (char *) "instance_name", &position);
+ store_to_string(&send_buff, (char *) instance_name, &position);
+ if (my_net_write(net, send_buff.buffer, (uint) position))
+ goto err;
+ if ((instance->options.mysqld_path))
+ {
+ position= 0;
+ store_to_string(&send_buff, (char *) "mysqld-path", &position);
+ store_to_string(&send_buff,
+ (char *) instance->options.mysqld_path,
+ &position);
+ if (send_buff.is_error() ||
+ my_net_write(net, send_buff.buffer, (uint) position))
+ goto err;
+ }
+
+ if ((instance->options.nonguarded))
+ {
+ position= 0;
+ store_to_string(&send_buff, (char *) "nonguarded", &position);
+ store_to_string(&send_buff, "", &position);
+ if (send_buff.is_error() ||
+ my_net_write(net, send_buff.buffer, (uint) position))
+ goto err;
+ }
+
+ /* loop through the options stored in DYNAMIC_ARRAY */
+ for (uint i= 0; i < instance->options.options_array.elements; i++)
+ {
+ char *tmp_option, *option_value;
+ get_dynamic(&(instance->options.options_array), (gptr) &tmp_option, i);
+ option_value= strchr(tmp_option, '=');
+ /* split the option string into two parts if it has a value */
+
+ position= 0;
+ if (option_value != NULL)
+ {
+ *option_value= 0;
+ store_to_string(&send_buff, tmp_option + 2, &position);
+ store_to_string(&send_buff, option_value + 1, &position);
+ /* join name and the value into the same option again */
+ *option_value= '=';
+ }
+ else store_to_string(&send_buff, tmp_option + 2, &position);
+
+ if (send_buff.is_error() ||
+ my_net_write(net, send_buff.buffer, (uint) position))
+ goto err;
+ }
+ }
+
+ send_eof(net);
+ net_flush(net);
+
+ return 0;
+
+err:
+ return 1;
+}
+
+
+int Show_instance_options::execute(struct st_net *net, ulong connection_id)
+{
+ if ((instance_name))
+ {
+ if (do_command(net, instance_name))
+ return ER_OUT_OF_RESOURCES;
+ return 0;
+ }
+ else
+ {
+ return ER_BAD_INSTANCE_NAME;
+ }
+}
+
+
+/* Implementation for Start_instance */
+
+Start_instance::Start_instance(Instance_map *instance_map_arg,
+ const char *name, uint len)
+ :Command(instance_map_arg)
+{
+ /* we make a search here, since we don't want t store the name */
+ if ((instance= instance_map->find(name, len)))
+ instance_name= instance->options.instance_name;
+}
+
+
+int Start_instance::execute(struct st_net *net, ulong connection_id)
+{
+ uint err_code;
+ if (instance == 0)
+ {
+ return ER_BAD_INSTANCE_NAME; /* haven't found an instance */
+ }
+ else
+ {
+ if ((err_code= instance->start()))
+ return err_code;
+
+ if (!(instance->options.nonguarded))
+ instance_map->guardian->guard(instance);
+
+ net_send_ok(net, connection_id);
+ return 0;
+ }
+}
+
+
+/* Implementation for Stop_instance: */
+
+Stop_instance::Stop_instance(Instance_map *instance_map_arg,
+ const char *name, uint len)
+ :Command(instance_map_arg)
+{
+ /* we make a search here, since we don't want t store the name */
+ if ((instance= instance_map->find(name, len)))
+ instance_name= instance->options.instance_name;
+}
+
+
+int Stop_instance::execute(struct st_net *net, ulong connection_id)
+{
+ uint err_code;
+
+ if (instance == 0)
+ {
+ return ER_BAD_INSTANCE_NAME; /* haven't found an instance */
+ }
+ else
+ {
+ if (!(instance->options.nonguarded))
+ instance_map->guardian->
+ stop_guard(instance);
+ if ((err_code= instance->stop()))
+ return err_code;
+ net_send_ok(net, connection_id);
+ return 0;
+ }
+}
+
+
+int Syntax_error::execute(struct st_net *net, ulong connection_id)
+{
+ return ER_SYNTAX_ERROR;
+}
diff --git a/server-tools/instance-manager/commands.h b/server-tools/instance-manager/commands.h
new file mode 100644
index 00000000000..bab67f9c6b4
--- /dev/null
+++ b/server-tools/instance-manager/commands.h
@@ -0,0 +1,131 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H
+/* Copyright (C) 2004 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 "command.h"
+#include "instance.h"
+
+/*
+ Print all instances of this instance manager.
+ Grammar: SHOW ISTANCES
+*/
+
+class Show_instances : public Command
+{
+public:
+ Show_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
+ {}
+
+ int do_command(struct st_net *net);
+ int execute(struct st_net *net, ulong connection_id);
+};
+
+
+/*
+ Reread configuration file and refresh instance map.
+ Grammar: FLUSH INSTANCES
+*/
+
+class Flush_instances : public Command
+{
+public:
+ Flush_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
+ {}
+
+ int execute(struct st_net *net, ulong connection_id);
+};
+
+
+/*
+ Print status of an instance.
+ Grammar: SHOW ISTANCE STATUS <instance_name>
+*/
+
+class Show_instance_status : public Command
+{
+public:
+
+ Show_instance_status(Instance_map *instance_map_arg, const char *name, uint len);
+ int do_command(struct st_net *net, const char *instance_name);
+ int execute(struct st_net *net, ulong connection_id);
+ const char *instance_name;
+};
+
+
+/*
+ Print options if chosen instance.
+ Grammar: SHOW INSTANCE OPTIONS <instance_name>
+*/
+
+class Show_instance_options : public Command
+{
+public:
+
+ Show_instance_options(Instance_map *instance_map_arg, const char *name, uint len);
+
+ int execute(struct st_net *net, ulong connection_id);
+ int do_command(struct st_net *net, const char *instance_name);
+ const char *instance_name;
+};
+
+
+/*
+ Start an instance.
+ Grammar: START INSTANCE <instance_name>
+*/
+
+class Start_instance : public Command
+{
+public:
+ Start_instance(Instance_map *instance_map_arg, const char *name, uint len);
+
+ int execute(struct st_net *net, ulong connection_id);
+ const char *instance_name;
+ Instance *instance;
+};
+
+
+/*
+ Stop an instance.
+ Grammar: STOP INSTANCE <instance_name>
+*/
+
+class Stop_instance : public Command
+{
+public:
+ Stop_instance(Instance_map *instance_map_arg, const char *name, uint len);
+
+ Instance *instance;
+ int execute(struct st_net *net, ulong connection_id);
+ const char *instance_name;
+};
+
+
+/*
+ Syntax error command. This command is issued if parser reported a syntax error.
+ We need it to distinguish the parse error and the situation when parser internal
+ error occured. E.g. parsing failed because we hadn't had enought memory. In the
+ latter case parse_command() should return an error.
+*/
+
+class Syntax_error : public Command
+{
+public:
+ int execute(struct st_net *net, ulong connection_id);
+};
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */
diff --git a/server-tools/instance-manager/factory.cc b/server-tools/instance-manager/factory.cc
new file mode 100644
index 00000000000..538d9353983
--- /dev/null
+++ b/server-tools/instance-manager/factory.cc
@@ -0,0 +1,55 @@
+/* Copyright (C) 2004 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 "factory.h"
+
+Show_instances *Command_factory::new_Show_instances()
+{
+ return new Show_instances(&instance_map);
+}
+
+Flush_instances *Command_factory::new_Flush_instances()
+{
+ return new Flush_instances(&instance_map);
+}
+
+Show_instance_status *Command_factory::
+ new_Show_instance_status(const char *name, uint len)
+{
+ return new Show_instance_status(&instance_map, name, len);
+}
+
+Show_instance_options *Command_factory::
+ new_Show_instance_options(const char *name, uint len)
+{
+ return new Show_instance_options(&instance_map, name, len);
+}
+
+Start_instance *Command_factory::
+ new_Start_instance(const char *name, uint len)
+{
+ return new Start_instance(&instance_map, name, len);
+}
+
+Stop_instance *Command_factory::new_Stop_instance(const char *name, uint len)
+{
+ return new Stop_instance(&instance_map, name, len);
+}
+
+Syntax_error *Command_factory::new_Syntax_error()
+{
+ return new Syntax_error();
+}
diff --git a/server-tools/instance-manager/factory.h b/server-tools/instance-manager/factory.h
new file mode 100644
index 00000000000..0a1b955d156
--- /dev/null
+++ b/server-tools/instance-manager/factory.h
@@ -0,0 +1,45 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_FACTORY_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_FACTORY_H
+/* Copyright (C) 2004 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 "command.h"
+#include "commands.h"
+#include "instance_map.h"
+
+/*
+ This class could be used to handle various protocols. We could pass to
+ the parser various derived classes. I.e Mylsq_command_factory,
+ Http_command_factory e.t.c. Also see comment in the instance_map.cc
+*/
+
+class Command_factory
+{
+public:
+ Command_factory(Instance_map &instance_map): instance_map(instance_map)
+ {}
+
+ Show_instances *new_Show_instances ();
+ Show_instance_status *new_Show_instance_status (const char *name, uint len);
+ Show_instance_options *new_Show_instance_options (const char *name, uint len);
+ Start_instance *new_Start_instance (const char *name, uint len);
+ Stop_instance *new_Stop_instance (const char *name, uint len);
+ Flush_instances *new_Flush_instances ();
+ Syntax_error *new_Syntax_error ();
+
+ Instance_map &instance_map;
+};
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_FACTORY_H */
diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc
new file mode 100644
index 00000000000..5d89f167f2f
--- /dev/null
+++ b/server-tools/instance-manager/guardian.cc
@@ -0,0 +1,436 @@
+/* Copyright (C) 2004 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 */
+
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "guardian.h"
+
+#include "instance_map.h"
+#include "instance.h"
+#include "mysql_manager_error.h"
+#include "log.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+
+
+
+
+C_MODE_START
+
+pthread_handler_decl(guardian, arg)
+{
+ Guardian_thread *guardian_thread= (Guardian_thread *) arg;
+ guardian_thread->run();
+ return 0;
+}
+
+C_MODE_END
+
+
+Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg,
+ Instance_map *instance_map_arg,
+ uint monitoring_interval_arg) :
+ Guardian_thread_args(thread_registry_arg, instance_map_arg,
+ monitoring_interval_arg),
+ thread_info(pthread_self()), guarded_instances(0)
+{
+ pthread_mutex_init(&LOCK_guardian, 0);
+ pthread_cond_init(&COND_guardian, 0);
+ shutdown_requested= FALSE;
+ stopped= FALSE;
+ init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
+}
+
+
+Guardian_thread::~Guardian_thread()
+{
+ /* delay guardian destruction to the moment when no one needs it */
+ pthread_mutex_lock(&LOCK_guardian);
+ free_root(&alloc, MYF(0));
+ pthread_mutex_unlock(&LOCK_guardian);
+ pthread_mutex_destroy(&LOCK_guardian);
+ pthread_cond_destroy(&COND_guardian);
+}
+
+
+void Guardian_thread::request_shutdown(bool stop_instances_arg)
+{
+ pthread_mutex_lock(&LOCK_guardian);
+ /* stop instances or just clean up Guardian repository */
+ stop_instances(stop_instances_arg);
+ shutdown_requested= TRUE;
+ pthread_mutex_unlock(&LOCK_guardian);
+}
+
+
+void Guardian_thread::process_instance(Instance *instance,
+ GUARD_NODE *current_node,
+ LIST **guarded_instances,
+ LIST *node)
+{
+ uint waitchild= (uint) Instance::DEFAULT_SHUTDOWN_DELAY;
+ /* The amount of times, Guardian attempts to restart an instance */
+ int restart_retry= 100;
+ time_t current_time= time(NULL);
+
+ if (current_node->state == STOPPING)
+ {
+ /* this brach is executed during shutdown */
+ if (instance->options.shutdown_delay_val)
+ waitchild= instance->options.shutdown_delay_val;
+
+ /* this returns true if and only if an instance was stopped for sure */
+ if (instance->is_crashed())
+ *guarded_instances= list_delete(*guarded_instances, node);
+ else if ( (uint) (current_time - current_node->last_checked) > waitchild)
+ {
+ instance->kill_instance(SIGKILL);
+ /*
+ Later we do node= node->next. This is ok, as we are only removing
+ the node from the list. The pointer to the next one is still valid.
+ */
+ *guarded_instances= list_delete(*guarded_instances, node);
+ }
+
+ return;
+ }
+
+ if (instance->is_running())
+ {
+ /* clear status fields */
+ current_node->restart_counter= 0;
+ current_node->crash_moment= 0;
+ current_node->state= STARTED;
+ }
+ else
+ {
+ switch (current_node->state)
+ {
+ case NOT_STARTED:
+ instance->start();
+ current_node->last_checked= current_time;
+ log_info("guardian: starting instance %s",
+ instance->options.instance_name);
+ current_node->state= STARTING;
+ break;
+ case STARTED: /* fallthrough */
+ case STARTING: /* let the instance start or crash */
+ if (instance->is_crashed())
+ {
+ current_node->crash_moment= current_time;
+ current_node->last_checked= current_time;
+ current_node->state= JUST_CRASHED;
+ /* fallthrough -- restart an instance immediately */
+ }
+ else
+ break;
+ case JUST_CRASHED:
+ if (current_time - current_node->crash_moment <= 2)
+ {
+ instance->start();
+ log_info("guardian: starting instance %s",
+ instance->options.instance_name);
+ }
+ else current_node->state= CRASHED;
+ break;
+ case CRASHED: /* just regular restarts */
+ if (current_time - current_node->last_checked >
+ monitoring_interval)
+ {
+ if ((current_node->restart_counter < restart_retry))
+ {
+ instance->start();
+ current_node->last_checked= current_time;
+ current_node->restart_counter++;
+ log_info("guardian: restarting instance %s",
+ instance->options.instance_name);
+ }
+ else
+ current_node->state= CRASHED_AND_ABANDONED;
+ }
+ break;
+ case CRASHED_AND_ABANDONED:
+ break; /* do nothing */
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+}
+
+
+/*
+ Run guardian thread
+
+ SYNOPSYS
+ run()
+
+ DESCRIPTION
+
+ Check for all guarded instances and restart them if needed. If everything
+ is fine go and sleep for some time.
+*/
+
+void Guardian_thread::run()
+{
+ Instance *instance;
+ LIST *node;
+ struct timespec timeout;
+
+ thread_registry.register_thread(&thread_info);
+
+ my_thread_init();
+ pthread_mutex_lock(&LOCK_guardian);
+
+ /* loop, until all instances were shut down at the end */
+ while (!(shutdown_requested && (guarded_instances == NULL)))
+ {
+ node= guarded_instances;
+
+ while (node != NULL)
+ {
+ struct timespec timeout;
+
+ GUARD_NODE *current_node= (GUARD_NODE *) node->data;
+ instance= ((GUARD_NODE *) node->data)->instance;
+ process_instance(instance, current_node, &guarded_instances, node);
+
+ node= node->next;
+ }
+ timeout.tv_sec= time(NULL) + monitoring_interval;
+ timeout.tv_nsec= 0;
+
+ /* check the loop predicate before sleeping */
+ if (!(shutdown_requested && (!(guarded_instances))))
+ pthread_cond_timedwait(&COND_guardian, &LOCK_guardian, &timeout);
+ }
+
+ stopped= TRUE;
+ pthread_mutex_unlock(&LOCK_guardian);
+ /* now, when the Guardian is stopped we can stop the IM */
+ thread_registry.unregister_thread(&thread_info);
+ thread_registry.request_shutdown();
+ my_thread_end();
+}
+
+
+int Guardian_thread::is_stopped()
+{
+ int var;
+ pthread_mutex_lock(&LOCK_guardian);
+ var= stopped;
+ pthread_mutex_unlock(&LOCK_guardian);
+ return var;
+}
+
+
+/*
+ Initialize the list of guarded instances: loop through the Instance_map and
+ add all of the instances, which don't have 'nonguarded' option specified.
+
+ SYNOPSYS
+ Guardian_thread::init()
+
+ NOTE: One should always lock guardian before calling this routine.
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+int Guardian_thread::init()
+{
+ Instance *instance;
+ Instance_map::Iterator iterator(instance_map);
+
+ instance_map->lock();
+ /* clear the list of guarded instances */
+ free_root(&alloc, MYF(0));
+ init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
+ guarded_instances= NULL;
+
+ while ((instance= iterator.next()))
+ {
+ if (!(instance->options.nonguarded))
+ if (guard(instance, TRUE)) /* do not lock guardian */
+ {
+ instance_map->unlock();
+ return 1;
+ }
+ }
+
+ instance_map->unlock();
+ return 0;
+}
+
+
+/*
+ Add instance to the Guardian list
+
+ SYNOPSYS
+ guard()
+ instance the instance to be guarded
+ nolock whether we prefer do not lock Guardian here,
+ but use external locking instead
+
+ DESCRIPTION
+
+ The instance is added to the guarded instances list. Usually guard() is
+ called after we start an instance.
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+int Guardian_thread::guard(Instance *instance, bool nolock)
+{
+ LIST *node;
+ GUARD_NODE *content;
+
+ node= (LIST *) alloc_root(&alloc, sizeof(LIST));
+ content= (GUARD_NODE *) alloc_root(&alloc, sizeof(GUARD_NODE));
+
+ if ((!(node)) || (!(content)))
+ return 1;
+ /* we store the pointers to instances from the instance_map's MEM_ROOT */
+ content->instance= instance;
+ content->restart_counter= 0;
+ content->crash_moment= 0;
+ content->state= NOT_STARTED;
+ node->data= (void *) content;
+
+ if (nolock)
+ guarded_instances= list_add(guarded_instances, node);
+ else
+ {
+ pthread_mutex_lock(&LOCK_guardian);
+ guarded_instances= list_add(guarded_instances, node);
+ pthread_mutex_unlock(&LOCK_guardian);
+ }
+
+ return 0;
+}
+
+
+/*
+ TODO: perhaps it would make sense to create a pool of the LIST nodeents
+ and give them upon request. Now we are loosing a bit of memory when
+ guarded instance was stopped and then restarted (since we cannot free just
+ a piece of the MEM_ROOT).
+*/
+
+int Guardian_thread::stop_guard(Instance *instance)
+{
+ LIST *node;
+
+ pthread_mutex_lock(&LOCK_guardian);
+ node= guarded_instances;
+
+ while (node != NULL)
+ {
+ /*
+ We compare only pointers, as we always use pointers from the
+ instance_map's MEM_ROOT.
+ */
+ if (((GUARD_NODE *) node->data)->instance == instance)
+ {
+ guarded_instances= list_delete(guarded_instances, node);
+ pthread_mutex_unlock(&LOCK_guardian);
+ return 0;
+ }
+ else
+ node= node->next;
+ }
+ pthread_mutex_unlock(&LOCK_guardian);
+ /* if there is nothing to delete it is also fine */
+ return 0;
+}
+
+/*
+ Start Guardian shutdown. Attempt to start instances if requested.
+
+ SYNOPSYS
+ stop_instances()
+ stop_instances_arg whether we should stop instances at shutdown
+
+ DESCRIPTION
+
+ Loops through the guarded_instances list and prepares them for shutdown.
+ If stop_instances was requested, we need to issue a stop command and change
+ the state accordingly. Otherwise we could simply delete an entry.
+ NOTE: Guardian should be locked by the calling function
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+int Guardian_thread::stop_instances(bool stop_instances_arg)
+{
+ LIST *node;
+ node= guarded_instances;
+ while (node != NULL)
+ {
+ if (!stop_instances_arg)
+ {
+ /* just forget about an instance */
+ guarded_instances= list_delete(guarded_instances, node);
+ /*
+ This should still work fine, as we have only removed the
+ node from the list. The pointer to the next one is still valid
+ */
+ node= node->next;
+ }
+ else
+ {
+ GUARD_NODE *current_node= (GUARD_NODE *) node->data;
+ /*
+ If instance is running or was running (and now probably hanging),
+ request stop.
+ */
+ if (current_node->instance->is_running() ||
+ (current_node->state == STARTED))
+ {
+ current_node->state= STOPPING;
+ current_node->last_checked= time(NULL);
+ }
+ else
+ /* otherwise remove it from the list */
+ guarded_instances= list_delete(guarded_instances, node);
+ /* But try to kill it anyway. Just in case */
+ current_node->instance->kill_instance(SIGTERM);
+ node= node->next;
+ }
+ }
+ return 0;
+}
+
+
+int Guardian_thread::lock()
+{
+ return pthread_mutex_lock(&LOCK_guardian);
+}
+
+
+int Guardian_thread::unlock()
+{
+ return pthread_mutex_unlock(&LOCK_guardian);
+}
diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h
new file mode 100644
index 00000000000..502dc86b2ae
--- /dev/null
+++ b/server-tools/instance-manager/guardian.h
@@ -0,0 +1,127 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H
+/* Copyright (C) 2004 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 "thread_registry.h"
+
+#include <my_sys.h>
+#include <my_list.h>
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+class Instance;
+class Instance_map;
+class Thread_registry;
+struct GUARD_NODE;
+
+C_MODE_START
+
+pthread_handler_decl(guardian, arg);
+
+C_MODE_END
+
+struct Guardian_thread_args
+{
+ Thread_registry &thread_registry;
+ Instance_map *instance_map;
+ int monitoring_interval;
+
+ Guardian_thread_args(Thread_registry &thread_registry_arg,
+ Instance_map *instance_map_arg,
+ uint monitoring_interval_arg) :
+ thread_registry(thread_registry_arg),
+ instance_map(instance_map_arg),
+ monitoring_interval(monitoring_interval_arg)
+ {}
+};
+
+
+/*
+ The guardian thread is responsible for monitoring and restarting of guarded
+ instances.
+*/
+
+class Guardian_thread: public Guardian_thread_args
+{
+public:
+ /* states of an instance */
+ enum INSTANCE_STATE { NOT_STARTED= 1, STARTING, STARTED, JUST_CRASHED,
+ CRASHED, CRASHED_AND_ABANDONED, STOPPING };
+
+ /*
+ The Guardian list node structure. Guardian utilizes it to store
+ guarded instances plus some additional info.
+ */
+
+ struct GUARD_NODE
+ {
+ Instance *instance;
+ /* state of an instance (i.e. STARTED, CRASHED, etc.) */
+ INSTANCE_STATE state;
+ /* the amount of attemts to restart instance (cleaned up at success) */
+ int restart_counter;
+ /* triggered at a crash */
+ time_t crash_moment;
+ /* General time field. Used to provide timeouts (at shutdown and restart) */
+ time_t last_checked;
+ };
+
+
+ Guardian_thread(Thread_registry &thread_registry_arg,
+ Instance_map *instance_map_arg,
+ uint monitoring_interval_arg);
+ ~Guardian_thread();
+ /* Main funtion of the thread */
+ void run();
+ /* Initialize or refresh the list of guarded instances */
+ int init();
+ /* Request guardian shutdown. Stop instances if needed */
+ void request_shutdown(bool stop_instances);
+ /* Start instance protection */
+ int guard(Instance *instance, bool nolock= FALSE);
+ /* Stop instance protection */
+ int stop_guard(Instance *instance);
+ /* Returns true if guardian thread is stopped */
+ int is_stopped();
+ int lock();
+ int unlock();
+
+public:
+ pthread_cond_t COND_guardian;
+
+private:
+ /* Prepares Guardian shutdown. Stops instances is needed */
+ int stop_instances(bool stop_instances_arg);
+ /* check instance state and act accordingly */
+ void process_instance(Instance *instance, GUARD_NODE *current_node,
+ LIST **guarded_instances, LIST *elem);
+ int stopped;
+
+private:
+ pthread_mutex_t LOCK_guardian;
+ Thread_info thread_info;
+ LIST *guarded_instances;
+ MEM_ROOT alloc;
+ enum { MEM_ROOT_BLOCK_SIZE= 512 };
+ /* this variable is set to TRUE when we want to stop Guardian thread */
+ bool shutdown_requested;
+};
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc
new file mode 100644
index 00000000000..9fdcab7ce7c
--- /dev/null
+++ b/server-tools/instance-manager/instance.cc
@@ -0,0 +1,334 @@
+/* Copyright (C) 2004 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "instance.h"
+
+#include "mysql_manager_error.h"
+#include "log.h"
+#include "instance_map.h"
+#include "priv.h"
+
+#include <sys/wait.h>
+#include <my_sys.h>
+#include <signal.h>
+#include <m_string.h>
+#include <mysql.h>
+
+C_MODE_START
+
+/*
+ Proxy thread is a simple way to avoid all pitfalls of the threads
+ implementation in the OS (e.g. LinuxThreads). With such a thread we
+ don't have to process SIGCHLD, which is a tricky business if we want
+ to do it in a portable way.
+*/
+
+pthread_handler_decl(proxy, arg)
+{
+ Instance *instance= (Instance *) arg;
+ instance->fork_and_monitor();
+ return 0;
+}
+
+C_MODE_END
+
+
+/*
+ The method starts an instance.
+
+ SYNOPSYS
+ start()
+
+ RETURN
+ 0 ok
+ ER_CANNOT_START_INSTANCE Cannot start instance
+ ER_INSTANCE_ALREADY_STARTED The instance on the specified port/socket
+ is already started
+*/
+
+int Instance::start()
+{
+ pid_t pid;
+
+ /* clear crash flag */
+ pthread_mutex_lock(&LOCK_instance);
+ crashed= 0;
+ pthread_mutex_unlock(&LOCK_instance);
+
+
+ if (!is_running())
+ {
+ if ((pid= options.get_pid()) != 0) /* check the pidfile */
+ if (options.unlink_pidfile()) /* remove stalled pidfile */
+ log_error("cannot remove pidfile for instance %i, this might be \
+ since IM lacks permmissions or hasn't found the pidifle",
+ options.instance_name);
+
+ /*
+ No need to monitor this thread in the Thread_registry, as all
+ instances are to be stopped during shutdown.
+ */
+ pthread_t proxy_thd_id;
+ pthread_attr_t proxy_thd_attr;
+ int rc;
+
+ pthread_attr_init(&proxy_thd_attr);
+ pthread_attr_setdetachstate(&proxy_thd_attr, PTHREAD_CREATE_DETACHED);
+ rc= pthread_create(&proxy_thd_id, &proxy_thd_attr, proxy,
+ this);
+ pthread_attr_destroy(&proxy_thd_attr);
+ if (rc)
+ {
+ log_error("Instance::start(): pthread_create(proxy) failed");
+ return ER_CANNOT_START_INSTANCE;
+ }
+
+ return 0;
+ }
+
+ /* the instance is started already */
+ return ER_INSTANCE_ALREADY_STARTED;
+}
+
+
+void Instance::fork_and_monitor()
+{
+ pid_t pid;
+ log_info("starting instance %s", options.instance_name);
+ switch (pid= fork()) {
+ case 0:
+ execv(options.mysqld_path, options.argv);
+ /* exec never returns */
+ exit(1);
+ case -1:
+ log_info("cannot fork() to start instance %s", options.instance_name);
+ return;
+ default:
+ /*
+ Here we wait for the child created. This process differs for systems
+ running LinuxThreads and POSIX Threads compliant systems. This is because
+ according to POSIX we could wait() for a child in any thread of the
+ process. While LinuxThreads require that wait() is called by the thread,
+ which created the child.
+ On the other hand we could not expect mysqld to return the pid, we
+ got in from fork(), to wait4() fucntion when running on LinuxThreads.
+ This is because MySQL shutdown thread is not the one, which was created
+ by our fork() call.
+ So basically we have two options: whether the wait() call returns only in
+ the creator thread, but we cannot use waitpid() since we have no idea
+ which pid we should wait for (in fact it should be the pid of shutdown
+ thread, but we don't know this one). Or we could use waitpid(), but
+ couldn't use wait(), because it could return in any wait() in the program.
+ */
+ if (linuxthreads)
+ wait(NULL); /* LinuxThreads were detected */
+ else
+ waitpid(pid, NULL, 0);
+ /* set instance state to crashed */
+ pthread_mutex_lock(&LOCK_instance);
+ crashed= 1;
+ pthread_mutex_unlock(&LOCK_instance);
+
+ /*
+ Wake connection threads waiting for an instance to stop. This
+ is needed if a user issued command to stop an instance via
+ mysql connection. This is not the case if Guardian stop the thread.
+ */
+ pthread_cond_signal(&COND_instance_stopped);
+ /* wake guardian */
+ pthread_cond_signal(&instance_map->guardian->COND_guardian);
+ /* thread exits */
+ return;
+ }
+ /* we should never end up here */
+ DBUG_ASSERT(0);
+}
+
+
+Instance::Instance(): crashed(0)
+{
+ pthread_mutex_init(&LOCK_instance, 0);
+ pthread_cond_init(&COND_instance_stopped, 0);
+}
+
+
+Instance::~Instance()
+{
+ pthread_cond_destroy(&COND_instance_stopped);
+ pthread_mutex_destroy(&LOCK_instance);
+}
+
+
+int Instance::is_crashed()
+{
+ int val;
+ pthread_mutex_lock(&LOCK_instance);
+ val= crashed;
+ pthread_mutex_unlock(&LOCK_instance);
+ return val;
+}
+
+
+bool Instance::is_running()
+{
+ MYSQL mysql;
+ uint port= 0;
+ const char *socket= NULL;
+ const char *password= "check_connection";
+ const char *username= "MySQL_Instance_Manager";
+ const char *access_denied_message= "Access denied for user";
+ bool return_val;
+
+ if (options.mysqld_port)
+ port= options.mysqld_port_val;
+
+ if (options.mysqld_socket)
+ socket= strchr(options.mysqld_socket, '=') + 1;
+
+ pthread_mutex_lock(&LOCK_instance);
+
+ mysql_init(&mysql);
+ /* try to connect to a server with a fake username/password pair */
+ if (mysql_real_connect(&mysql, LOCAL_HOST, username,
+ password,
+ NullS, port,
+ socket, 0))
+ {
+ /*
+ We have successfully connected to the server using fake
+ username/password. Write a warning to the logfile.
+ */
+ log_info("The Instance Manager was able to log into you server \
+ with faked compiled-in password while checking server status. \
+ Looks like something is wrong.");
+ pthread_mutex_unlock(&LOCK_instance);
+ return_val= TRUE; /* server is alive */
+ }
+ else
+ {
+ if (!strncmp(access_denied_message, mysql_error(&mysql),
+ sizeof(access_denied_message)-1))
+ {
+ return_val= TRUE;
+ }
+ else
+ return_val= FALSE;
+ }
+
+ mysql_close(&mysql);
+ pthread_mutex_unlock(&LOCK_instance);
+
+ return return_val;
+}
+
+
+/*
+ Stop an instance.
+
+ SYNOPSYS
+ stop()
+
+ RETURN:
+ 0 ok
+ ER_INSTANCE_IS_NOT_STARTED Looks like the instance it is not started
+ ER_STOP_INSTANCE mysql_shutdown reported an error
+*/
+
+int Instance::stop()
+{
+ pid_t pid;
+ struct timespec timeout;
+ uint waitchild= (uint) DEFAULT_SHUTDOWN_DELAY;
+
+ if (options.shutdown_delay_val)
+ waitchild= options.shutdown_delay_val;
+
+ kill_instance(SIGTERM);
+ /* sleep on condition to wait for SIGCHLD */
+
+ timeout.tv_sec= time(NULL) + waitchild;
+ timeout.tv_nsec= 0;
+ if (pthread_mutex_lock(&LOCK_instance))
+ goto err;
+
+ while (options.get_pid() != 0) /* while server isn't stopped */
+ {
+ int status;
+
+ status= pthread_cond_timedwait(&COND_instance_stopped,
+ &LOCK_instance,
+ &timeout);
+ if (status == ETIMEDOUT)
+ break;
+ }
+
+ pthread_mutex_unlock(&LOCK_instance);
+
+ kill_instance(SIGKILL);
+
+ return 0;
+
+ return ER_INSTANCE_IS_NOT_STARTED;
+err:
+ return ER_STOP_INSTANCE;
+}
+
+
+void Instance::kill_instance(int signum)
+{
+ pid_t pid;
+ /* if there are no pid, everything seems to be fine */
+ if ((pid= options.get_pid()) != 0) /* get pid from pidfile */
+ {
+ /*
+ If we cannot kill mysqld, then it has propably crashed.
+ Let us try to remove staled pidfile and return successfully
+ as mysqld is probably stopped.
+ */
+ if (!kill(pid, signum))
+ options.unlink_pidfile();
+ else
+ if (signum == SIGKILL) /* really killed instance with SIGKILL */
+ log_error("The instance %s is being stopped forsibly. Normally \
+ it should not happed. Probably the instance has been \
+ hanging. You should also check your IM setup",
+ options.instance_name);
+ }
+ return;
+}
+
+/*
+ We execute this function to initialize instance parameters.
+ Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
+*/
+
+int Instance::init(const char *name_arg)
+{
+ return options.init(name_arg);
+}
+
+
+int Instance::complete_initialization(Instance_map *instance_map_arg,
+ const char *mysqld_path,
+ int only_instance)
+{
+ instance_map= instance_map_arg;
+ return options.complete_initialization(mysqld_path, only_instance);
+}
diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h
new file mode 100644
index 00000000000..14ef5cfcfb9
--- /dev/null
+++ b/server-tools/instance-manager/instance.h
@@ -0,0 +1,66 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H
+/* Copyright (C) 2004 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 "instance_options.h"
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+class Instance_map;
+
+class Instance
+{
+public:
+ Instance();
+
+ ~Instance();
+ int init(const char *name);
+ int complete_initialization(Instance_map *instance_map_arg,
+ const char *mysqld_path, int only_instance= 0);
+
+ bool is_running();
+ int start();
+ int stop();
+ /* send a signal to the instance */
+ void kill_instance(int signo);
+ int is_crashed();
+ void fork_and_monitor();
+
+public:
+ enum { DEFAULT_SHUTDOWN_DELAY= 35 };
+ Instance_options options;
+
+private:
+ /*
+ Mutex protecting the instance. Currently we use it to avoid the
+ double start of the instance. This happens when the instance is starting
+ and we issue the start command once more.
+ */
+ int crashed;
+ pthread_mutex_t LOCK_instance;
+ /*
+ This condition variable is used to wake threads waiting for instance to
+ stop in Instance::stop()
+ */
+ pthread_cond_t COND_instance_stopped;
+ Instance_map *instance_map;
+};
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc
new file mode 100644
index 00000000000..3e76c24a9a1
--- /dev/null
+++ b/server-tools/instance-manager/instance_map.cc
@@ -0,0 +1,273 @@
+/* Copyright (C) 2004 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "instance_map.h"
+
+#include "buffer.h"
+#include "instance.h"
+
+#include <m_ctype.h>
+#include <mysql_com.h>
+#include <m_string.h>
+
+/*
+ Note: As we are going to suppost different types of connections,
+ we shouldn't have connection-specific functions. To avoid it we could
+ put such functions to the Command-derived class instead.
+ The command could be easily constructed for a specific connection if
+ we would provide a special factory for each connection.
+*/
+
+C_MODE_START
+
+/* Procedure needed for HASH initialization */
+
+static byte* get_instance_key(const byte* u, uint* len,
+ my_bool __attribute__((unused)) t)
+{
+ const Instance *instance= (const Instance *) u;
+ *len= instance->options.instance_name_len;
+ return (byte *) instance->options.instance_name;
+}
+
+static void delete_instance(void *u)
+{
+ Instance *instance= (Instance *) u;
+ delete instance;
+}
+
+/*
+ The option handler to pass to the process_default_option_files finction.
+
+ SYNOPSYS
+ process_option()
+ ctx Handler context. Here it is an instance_map structure.
+ group_name The name of the group the option belongs to.
+ option The very option to be processed. It is already
+ prepared to be used in argv (has -- prefix)
+
+ DESCRIPTION
+
+ This handler checks whether a group is an instance group and adds
+ an option to the appropriate instance class. If this is the first
+ occurence of an instance name, we'll also create the instance
+ with such name and add it to the instance map.
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+static int process_option(void *ctx, const char *group, const char *option)
+{
+ Instance_map *map= NULL;
+ Instance *instance= NULL;
+ static const char prefix[]= { 'm', 'y', 's', 'q', 'l', 'd' };
+
+ map = (Instance_map*) ctx;
+ if (strncmp(group, prefix, sizeof prefix) == 0 &&
+ ((my_isdigit(default_charset_info, group[sizeof prefix]))
+ || group[sizeof(prefix)] == '\0'))
+ {
+ if ((instance= map->find(group, strlen(group))) == NULL)
+ {
+ if ((instance= new Instance) == 0)
+ goto err_new_instance;
+ if (instance->init(group))
+ goto err;
+ if (map->add_instance(instance))
+ goto err;
+ }
+
+ if (instance->options.add_option(option))
+ goto err;
+ }
+
+ return 0;
+
+err:
+ delete instance;
+err_new_instance:
+ return 1;
+}
+
+C_MODE_END
+
+
+Instance_map::Instance_map(const char *default_mysqld_path_arg,
+ const char *first_option_arg):
+mysqld_path(default_mysqld_path_arg), first_option(first_option_arg)
+{
+ pthread_mutex_init(&LOCK_instance_map, 0);
+}
+
+
+int Instance_map::init()
+{
+ if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
+ get_instance_key, delete_instance, 0))
+ return 1;
+ return 0;
+}
+
+Instance_map::~Instance_map()
+{
+ pthread_mutex_lock(&LOCK_instance_map);
+ hash_free(&hash);
+ pthread_mutex_unlock(&LOCK_instance_map);
+ pthread_mutex_destroy(&LOCK_instance_map);
+}
+
+
+int Instance_map::lock()
+{
+ return pthread_mutex_lock(&LOCK_instance_map);
+}
+
+
+int Instance_map::unlock()
+{
+ return pthread_mutex_unlock(&LOCK_instance_map);
+}
+
+
+int Instance_map::flush_instances()
+{
+ int rc;
+
+ guardian->lock();
+ pthread_mutex_lock(&LOCK_instance_map);
+ hash_free(&hash);
+ hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
+ get_instance_key, delete_instance, 0);
+ pthread_mutex_unlock(&LOCK_instance_map);
+ rc= load();
+ guardian->init();
+ guardian->unlock();
+ return rc;
+}
+
+
+int Instance_map::add_instance(Instance *instance)
+{
+ return my_hash_insert(&hash, (byte *) instance);
+}
+
+
+Instance *
+Instance_map::find(const char *name, uint name_len)
+{
+ Instance *instance;
+ pthread_mutex_lock(&LOCK_instance_map);
+ instance= (Instance *) hash_search(&hash, (byte *) name, name_len);
+ pthread_mutex_unlock(&LOCK_instance_map);
+ return instance;
+}
+
+
+int Instance_map::complete_initialization()
+{
+ Instance *instance;
+ uint i= 0;
+
+
+ if (hash.records == 0) /* no instances found */
+ {
+ if ((instance= new Instance) == 0)
+ goto err;
+
+ if (instance->init("mysqld") || add_instance(instance))
+ goto err_instance;
+
+
+ /*
+ After an instance have been added to the instance_map,
+ hash_free should handle it's deletion => goto err, not
+ err_instance.
+ */
+ if (instance->complete_initialization(this, mysqld_path, 1))
+ goto err;
+ }
+ else
+ while (i < hash.records)
+ {
+ instance= (Instance *) hash_element(&hash, i);
+ if (instance->complete_initialization(this, mysqld_path))
+ goto err;
+ i++;
+ }
+
+ return 0;
+err:
+ return 1;
+err_instance:
+ delete instance;
+ return 1;
+}
+
+
+/* load options from config files and create appropriate instance structures */
+
+int Instance_map::load()
+{
+ int argc= 1;
+ /* this is a dummy variable for search_option_files() */
+ uint args_used= 0;
+ const char *argv_options[3];
+ char **argv= (char **) &argv_options;
+
+
+ /* the name of the program may be orbitrary here in fact */
+ argv_options[0]= "mysqlmanager";
+ if (first_option != NULL)
+ {
+ argc= 2;
+ argv_options[1]= first_option;
+ argv_options[2]= '\0';
+ }
+ else
+ argv_options[1]= '\0';
+
+ if (my_search_option_files("my", &argc, (char ***) &argv, &args_used,
+ process_option, (void *) this) ||
+ complete_initialization())
+ return 1;
+
+ return 0;
+}
+
+
+/*--- Implementaton of the Instance map iterator class ---*/
+
+
+void Instance_map::Iterator::go_to_first()
+{
+ current_instance=0;
+}
+
+
+Instance *Instance_map::Iterator::next()
+{
+ if (current_instance < instance_map->hash.records)
+ return (Instance *) hash_element(&instance_map->hash, current_instance++);
+
+ return NULL;
+}
+
diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h
new file mode 100644
index 00000000000..46247c82a16
--- /dev/null
+++ b/server-tools/instance-manager/instance_map.h
@@ -0,0 +1,89 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H
+/* Copyright (C) 2004 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 "protocol.h"
+#include "guardian.h"
+
+#include <my_sys.h>
+#include <hash.h>
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+class Instance;
+extern int load_all_groups(char ***groups, const char *filename);
+extern void free_groups(char **groups);
+
+
+/*
+ Instance_map - stores all existing instances
+*/
+
+class Instance_map
+{
+public:
+ /* Instance_map iterator */
+ class Iterator
+ {
+ private:
+ uint current_instance;
+ Instance_map *instance_map;
+ public:
+ Iterator(Instance_map *instance_map_arg) :
+ current_instance(0), instance_map(instance_map_arg)
+ {}
+
+ void go_to_first();
+ Instance *next();
+ };
+ friend class Iterator;
+public:
+ /* returns a pointer to the instance or NULL, if there is no such instance */
+ Instance *find(const char *name, uint name_len);
+
+ int flush_instances();
+ int lock();
+ int unlock();
+ int init();
+
+ Instance_map(const char *default_mysqld_path_arg,
+ const char *first_option_arg);
+ ~Instance_map();
+
+ /* loads options from config files */
+ int load();
+ /* adds instance to internal hash */
+ int add_instance(Instance *instance);
+ /* inits instances argv's after all options have been loaded */
+ int complete_initialization();
+
+public:
+ const char *mysqld_path;
+ Guardian_thread *guardian;
+
+private:
+ const char *first_option;
+ enum { START_HASH_SIZE = 16 };
+ pthread_mutex_t LOCK_instance_map;
+ HASH hash;
+};
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H */
diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc
new file mode 100644
index 00000000000..0d602f88ad2
--- /dev/null
+++ b/server-tools/instance-manager/instance_options.cc
@@ -0,0 +1,324 @@
+/* Copyright (C) 2004 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "instance_options.h"
+
+#include "parse_output.h"
+#include "buffer.h"
+
+#include <my_sys.h>
+#include <mysql.h>
+#include <signal.h>
+#include <m_string.h>
+
+
+/*
+ Get compiled-in value of default_option
+
+ SYNOPSYS
+ get_default_option()
+ result buffer to put found value
+ result_len buffer size
+ oprion_name the name of the option, prefixed with "--"
+
+ DESCRIPTION
+
+ Get compile-in value of requested option from server
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+int Instance_options::get_default_option(char *result, size_t result_len,
+ const char *option_name)
+{
+ int position= 0;
+ int rc= 1;
+ char verbose_option[]= " --no-defaults --verbose --help";
+
+ Buffer cmd(strlen(mysqld_path)+sizeof(verbose_option)+1);
+ if (cmd.get_size()) /* malloc succeeded */
+ {
+ cmd.append(position, mysqld_path, strlen(mysqld_path));
+ position+= strlen(mysqld_path);
+ cmd.append(position, verbose_option, sizeof(verbose_option) - 1);
+ position+= sizeof(verbose_option) - 1;
+ cmd.append(position, "\0", 1);
+
+ if (cmd.is_error())
+ goto err;
+ /* get the value from "mysqld --help --verbose" */
+ rc= parse_output_and_get_value(cmd.buffer, option_name + 2,
+ result, result_len);
+ }
+
+ return rc;
+err:
+ return 1;
+}
+
+
+int Instance_options::get_pid_filename(char *result)
+{
+ const char *pid_file= mysqld_pid_file;
+ char datadir[MAX_PATH_LEN];
+
+ if (!(mysqld_datadir))
+ {
+ /* we might get an error here if we have wrong path to the mysqld binary */
+ if (get_default_option(datadir, sizeof(datadir), "--datadir"))
+ return 1;
+ }
+ else
+ strxnmov(datadir, MAX_PATH_LEN - 1, strchr(mysqld_datadir, '=') + 1,
+ "/", NullS);
+
+ DBUG_ASSERT(mysqld_pid_file);
+ pid_file= strchr(pid_file, '=') + 1;
+
+ /* get the full path to the pidfile */
+ my_load_path(result, pid_file, datadir);
+ return 0;
+}
+
+
+int Instance_options::unlink_pidfile()
+{
+ return unlink(pid_file_with_path);
+}
+
+
+pid_t Instance_options::get_pid()
+{
+ FILE *pid_file_stream;
+
+ /* get the pid */
+ if ((pid_file_stream= my_fopen(pid_file_with_path,
+ O_RDONLY | O_BINARY, MYF(0))) != NULL)
+ {
+ pid_t pid;
+
+ fscanf(pid_file_stream, "%i", &pid);
+ my_fclose(pid_file_stream, MYF(0));
+ return pid;
+ }
+ else
+ return 0;
+}
+
+
+int Instance_options::complete_initialization(const char *default_path,
+ int only_instance)
+{
+ const char *tmp;
+
+ if (!(mysqld_path))
+ {
+ if (!(mysqld_path= strdup_root(&alloc, default_path)))
+ goto err;
+ }
+
+ if (mysqld_port)
+ mysqld_port_val= atoi(strchr(mysqld_port, '=') + 1);
+
+ if (shutdown_delay)
+ shutdown_delay_val= atoi(shutdown_delay);
+
+ if (!(tmp= strdup_root(&alloc, "--no-defaults")))
+ goto err;
+
+ if (!(mysqld_pid_file))
+ {
+ char pidfilename[MAX_PATH_LEN];
+ char hostname[MAX_PATH_LEN];
+
+ /*
+ If we created only one istance [mysqld], because no config. files were
+ found, we would like to model mysqld pid file values.
+ */
+ if (!gethostname(hostname, sizeof(hostname) - 1))
+ (only_instance == 0) ?
+ strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", instance_name, "-",
+ hostname, ".pid", NullS):
+ strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", hostname,
+ ".pid", NullS);
+
+ else
+ (only_instance == 0) ?
+ strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", instance_name,
+ ".pid", NullS):
+ strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", "mysql",
+ ".pid", NullS);
+
+ add_option(pidfilename);
+ }
+
+ if (get_pid_filename(pid_file_with_path))
+ goto err;
+
+ /* we need to reserve space for the final zero + possible default options */
+ if (!(argv= (char**) alloc_root(&alloc, (options_array.elements + 1
+ + MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*))))
+ goto err;
+
+ /* the path must be first in the argv */
+ if (add_to_argv(mysqld_path))
+ goto err;
+
+ if (add_to_argv(tmp))
+ goto err;
+
+ memcpy((gptr) (argv + filled_default_options), options_array.buffer,
+ options_array.elements*sizeof(char*));
+ argv[filled_default_options + options_array.elements]= 0;
+
+ return 0;
+
+err:
+ return 1;
+}
+
+
+/*
+ Assigns given value to the appropriate option from the class.
+
+ SYNOPSYS
+ add_option()
+ option string with the option prefixed by --
+
+ DESCRIPTION
+
+ The method is called from the option handling routine.
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+int Instance_options::add_option(const char* option)
+{
+ char *tmp;
+ enum { SAVE_VALUE= 1, SAVE_WHOLE, SAVE_WHOLE_AND_ADD };
+ struct selected_options_st
+ {
+ const char *name;
+ uint length;
+ const char **value;
+ uint type;
+ } options[]=
+ {
+ {"--socket=", 9, &mysqld_socket, SAVE_WHOLE_AND_ADD},
+ {"--port=", 7, &mysqld_port, SAVE_WHOLE_AND_ADD},
+ {"--datadir=", 10, &mysqld_datadir, SAVE_WHOLE_AND_ADD},
+ {"--bind-address=", 15, &mysqld_bind_address, SAVE_WHOLE_AND_ADD},
+ {"--pid-file=", 11, &mysqld_pid_file, SAVE_WHOLE_AND_ADD},
+ {"--mysqld-path=", 14, &mysqld_path, SAVE_VALUE},
+ {"--nonguarded", 9, &nonguarded, SAVE_WHOLE},
+ {"--shutdown_delay", 9, &shutdown_delay, SAVE_VALUE},
+ {NULL, 0, NULL, 0}
+ };
+ struct selected_options_st *selected_options;
+
+ if (!(tmp= strdup_root(&alloc, option)))
+ goto err;
+
+ for (selected_options= options; selected_options->name; selected_options++)
+ {
+ if (!strncmp(tmp, selected_options->name, selected_options->length))
+ switch(selected_options->type){
+ case SAVE_WHOLE_AND_ADD:
+ *(selected_options->value)= tmp;
+ insert_dynamic(&options_array,(gptr) &tmp);
+ return 0;
+ case SAVE_VALUE:
+ *(selected_options->value)= strchr(tmp, '=') + 1;
+ return 0;
+ case SAVE_WHOLE:
+ *(selected_options->value)= tmp;
+ return 0;
+ defaut:
+ break;
+ }
+ }
+
+ /* if we haven't returned earlier we should just save the option */
+ insert_dynamic(&options_array,(gptr) &tmp);
+
+ return 0;
+
+err:
+ return 1;
+}
+
+
+int Instance_options::add_to_argv(const char* option)
+{
+ DBUG_ASSERT(filled_default_options < MAX_NUMBER_OF_DEFAULT_OPTIONS);
+
+ if ((option))
+ argv[filled_default_options++]= (char *) option;
+ return 0;
+}
+
+
+/* function for debug purposes */
+void Instance_options::print_argv()
+{
+ int i;
+ printf("printing out an instance %s argv:\n", instance_name);
+ for (i=0; argv[i] != NULL; i++)
+ {
+ printf("argv: %s\n", argv[i]);
+ }
+}
+
+
+/*
+ We execute this function to initialize some options.
+ Return value: 0 - ok. 1 - unable to allocate memory.
+*/
+
+int Instance_options::init(const char *instance_name_arg)
+{
+ instance_name_len= strlen(instance_name_arg);
+
+ init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
+
+ if (my_init_dynamic_array(&options_array, sizeof(char *), 0, 32))
+ goto err;
+
+ if (!(instance_name= strmake_root(&alloc, (char *) instance_name_arg,
+ instance_name_len)))
+ goto err;
+
+ return 0;
+
+err:
+ return 1;
+}
+
+
+Instance_options::~Instance_options()
+{
+ free_root(&alloc, MYF(0));
+ delete_dynamic(&options_array);
+}
+
diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h
new file mode 100644
index 00000000000..06ad0156bc0
--- /dev/null
+++ b/server-tools/instance-manager/instance_options.h
@@ -0,0 +1,90 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H
+/* Copyright (C) 2004 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h>
+#include <my_sys.h>
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+
+/*
+ This class contains options of an instance and methods to operate them.
+
+ We do not provide this class with the means of synchronization as it is
+ supposed that options for instances are all loaded at once during the
+ instance_map initilization and we do not change them later. This way we
+ don't have to synchronize between threads.
+*/
+
+class Instance_options
+{
+public:
+ Instance_options() :
+ mysqld_socket(0), mysqld_datadir(0),
+ mysqld_bind_address(0), mysqld_pid_file(0), mysqld_port(0),
+ mysqld_port_val(0), mysqld_path(0), nonguarded(0), shutdown_delay(0),
+ shutdown_delay_val(0), filled_default_options(0)
+ {}
+ ~Instance_options();
+ /* fills in argv */
+ int complete_initialization(const char *default_path, int only_instance);
+
+ int add_option(const char* option);
+ int init(const char *instance_name_arg);
+ pid_t get_pid();
+ int get_pid_filename(char *result);
+ int unlink_pidfile();
+ void print_argv();
+
+public:
+ /*
+ We need this value to be greater or equal then FN_REFLEN found in
+ my_global.h to use my_load_path()
+ */
+ enum { MAX_PATH_LEN= 512 };
+ enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 };
+ enum { MEM_ROOT_BLOCK_SIZE= 512 };
+ char pid_file_with_path[MAX_PATH_LEN];
+ char **argv;
+ /* We need the some options, so we store them as a separate pointers */
+ const char *mysqld_socket;
+ const char *mysqld_datadir;
+ const char *mysqld_bind_address;
+ const char *mysqld_pid_file;
+ const char *mysqld_port;
+ uint mysqld_port_val;
+ const char *instance_name;
+ uint instance_name_len;
+ const char *mysqld_path;
+ const char *nonguarded;
+ const char *shutdown_delay;
+ uint shutdown_delay_val;
+ /* this value is computed and cashed here */
+ DYNAMIC_ARRAY options_array;
+private:
+ int add_to_argv(const char *option);
+ int get_default_option(char *result, size_t result_len,
+ const char *option_name);
+private:
+ uint filled_default_options;
+ MEM_ROOT alloc;
+};
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */
diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc
new file mode 100644
index 00000000000..946bab11a2e
--- /dev/null
+++ b/server-tools/instance-manager/listener.cc
@@ -0,0 +1,340 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "listener.h"
+
+#include <m_string.h>
+#include <mysql.h>
+#include <violite.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+
+#include "thread_registry.h"
+#include "options.h"
+#include "instance_map.h"
+#include "log.h"
+#include "mysql_connection.h"
+#include "priv.h"
+
+
+/*
+ Listener_thread - incapsulates listening functionality
+*/
+
+class Listener_thread: public Listener_thread_args
+{
+public:
+ Listener_thread(const Listener_thread_args &args);
+ ~Listener_thread();
+ void run();
+private:
+ ulong total_connection_count;
+ Thread_info thread_info;
+private:
+ void handle_new_mysql_connection(Vio *vio);
+};
+
+
+Listener_thread::Listener_thread(const Listener_thread_args &args) :
+ Listener_thread_args(args.thread_registry, args.options, args.user_map,
+ args.instance_map)
+ ,total_connection_count(0)
+ ,thread_info(pthread_self())
+{
+}
+
+
+Listener_thread::~Listener_thread()
+{
+}
+
+
+/*
+ Listener_thread::run() - listen all supported sockets and spawn a thread
+ to handle incoming connection.
+ Using 'die' in case of syscall failure is OK now - we don't hold any
+ resources and 'die' kills the signal thread automatically. To be rewritten
+ one day.
+ See also comments in mysqlmanager.cc to picture general Instance Manager
+ architecture.
+*/
+
+void Listener_thread::run()
+{
+ enum { LISTEN_BACK_LOG_SIZE = 5 }; // standard backlog size
+ int flags;
+ int arg= 1; /* value to be set by setsockopt */
+ int unix_socket;
+ uint im_port;
+ /* we use this var to check whether we are running on LinuxThreads */
+ pid_t thread_pid;
+
+ thread_pid= getpid();
+ /* set global variable */
+ linuxthreads= (thread_pid != manager_pid);
+
+ thread_registry.register_thread(&thread_info);
+
+ my_thread_init();
+
+ /* I. prepare 'listen' sockets */
+
+ int ip_socket= socket(AF_INET, SOCK_STREAM, 0);
+ if (ip_socket == INVALID_SOCKET)
+ {
+ log_error("Listener_thead::run(): socket(AF_INET) failed, %s",
+ strerror(errno));
+ goto err;
+ }
+
+ struct sockaddr_in ip_socket_address;
+ bzero(&ip_socket_address, sizeof(ip_socket_address));
+
+ ulong im_bind_addr;
+ if (options.bind_address != 0)
+ {
+ if ((im_bind_addr= (ulong) inet_addr(options.bind_address)) == INADDR_NONE)
+ im_bind_addr= htonl(INADDR_ANY);
+ }
+ else
+ im_bind_addr= htonl(INADDR_ANY);
+ im_port= options.port_number;
+
+ ip_socket_address.sin_family= AF_INET;
+ ip_socket_address.sin_addr.s_addr = im_bind_addr;
+
+
+ ip_socket_address.sin_port= (unsigned short)
+ htons((unsigned short) im_port);
+
+ setsockopt(ip_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &arg, sizeof(arg));
+ if (bind(ip_socket, (struct sockaddr *) &ip_socket_address,
+ sizeof(ip_socket_address)))
+ {
+ log_error("Listener_thread::run(): bind(ip socket) failed, '%s'",
+ strerror(errno));
+ goto err;
+ }
+
+ if (listen(ip_socket, LISTEN_BACK_LOG_SIZE))
+ {
+ log_error("Listener_thread::run(): listen(ip socket) failed, %s",
+ strerror(errno));
+ goto err;
+ }
+ /* set the socket nonblocking */
+ flags= fcntl(ip_socket, F_GETFL, 0);
+ fcntl(ip_socket, F_SETFL, flags | O_NONBLOCK);
+ /* make sure that instances won't be listening our sockets */
+ flags= fcntl(ip_socket, F_GETFD, 0);
+ fcntl(ip_socket, F_SETFD, flags | FD_CLOEXEC);
+
+ log_info("accepting connections on ip socket");
+
+ /*--------------------------------------------------------------*/
+ unix_socket= socket(AF_UNIX, SOCK_STREAM, 0);
+ if (unix_socket == INVALID_SOCKET)
+ {
+ log_error("Listener_thead::run(): socket(AF_UNIX) failed, %s",
+ strerror(errno));
+ goto err;
+ }
+
+ struct sockaddr_un unix_socket_address;
+ bzero(&unix_socket_address, sizeof(unix_socket_address));
+
+ unix_socket_address.sun_family= AF_UNIX;
+ strmake(unix_socket_address.sun_path, options.socket_file_name,
+ sizeof(unix_socket_address.sun_path));
+ unlink(unix_socket_address.sun_path); // in case we have stale socket file
+
+ {
+ /*
+ POSIX specifies default permissions for a pathname created by bind
+ to be 0777. We need everybody to have access to the socket.
+ */
+ mode_t old_mask= umask(0);
+ if (bind(unix_socket, (struct sockaddr *) &unix_socket_address,
+ sizeof(unix_socket_address)))
+ {
+ log_error("Listener_thread::run(): bind(unix socket) failed, "
+ "socket file name is '%s', error '%s'",
+ unix_socket_address.sun_path, strerror(errno));
+ goto err;
+ }
+ umask(old_mask);
+
+ if (listen(unix_socket, LISTEN_BACK_LOG_SIZE))
+ {
+ log_error("Listener_thread::run(): listen(unix socket) failed, %s",
+ strerror(errno));
+ goto err;
+ }
+
+ /* set the socket nonblocking */
+ flags= fcntl(unix_socket, F_GETFL, 0);
+ fcntl(unix_socket, F_SETFL, flags | O_NONBLOCK);
+ /* make sure that instances won't be listening our sockets */
+ flags= fcntl(unix_socket, F_GETFD, 0);
+ fcntl(unix_socket, F_SETFD, flags | FD_CLOEXEC);
+ }
+ log_info("accepting connections on unix socket %s",
+ unix_socket_address.sun_path);
+
+ /* II. Listen sockets and spawn childs */
+
+ {
+ int n= max(unix_socket, ip_socket) + 1;
+ fd_set read_fds;
+
+ FD_ZERO(&read_fds);
+ FD_SET(unix_socket, &read_fds);
+ FD_SET(ip_socket, &read_fds);
+
+ while (thread_registry.is_shutdown() == false)
+ {
+ fd_set read_fds_arg= read_fds;
+
+ /*
+ When using valgrind 2.0 this syscall doesn't get kicked off by a
+ signal during shutdown. This results in failing assert
+ (Thread_registry::~Thread_registry). Valgrind 2.2 works fine.
+ */
+ int rc= select(n, &read_fds_arg, 0, 0, 0);
+
+
+ if (rc == -1 && errno != EINTR)
+ log_error("Listener_thread::run(): select() failed, %s",
+ strerror(errno));
+ else
+ {
+ /* Assuming that rc > 0 as we asked to wait forever */
+ if (FD_ISSET(unix_socket, &read_fds_arg))
+ {
+ int client_fd= accept(unix_socket, 0, 0);
+ /* accept may return -1 (failure or spurious wakeup) */
+ if (client_fd >= 0) // connection established
+ {
+ if (Vio *vio= vio_new(client_fd, VIO_TYPE_SOCKET, 1))
+ handle_new_mysql_connection(vio);
+ else
+ {
+ shutdown(client_fd, SHUT_RDWR);
+ close(client_fd);
+ }
+ }
+ }
+ else
+ if (FD_ISSET(ip_socket, &read_fds_arg))
+ {
+ int client_fd= accept(ip_socket, 0, 0);
+ /* accept may return -1 (failure or spurious wakeup) */
+ if (client_fd >= 0) // connection established
+ {
+ if (Vio *vio= vio_new(client_fd, VIO_TYPE_TCPIP, 0))
+ {
+ handle_new_mysql_connection(vio);
+ }
+ else
+ {
+ shutdown(client_fd, SHUT_RDWR);
+ close(client_fd);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* III. Release all resources and exit */
+
+ log_info("Listener_thread::run(): shutdown requested, exiting...");
+
+ close(unix_socket);
+ close(ip_socket);
+ unlink(unix_socket_address.sun_path);
+
+ thread_registry.unregister_thread(&thread_info);
+ my_thread_end();
+ return;
+
+err:
+ thread_registry.unregister_thread(&thread_info);
+ thread_registry.request_shutdown();
+ my_thread_end();
+ return;
+}
+
+
+/*
+ Create new mysql connection. Created thread is responsible for deletion of
+ the Mysql_connection_thread_args and Vio instances passed to it.
+ SYNOPSYS
+ handle_new_mysql_connection()
+*/
+
+void Listener_thread::handle_new_mysql_connection(Vio *vio)
+{
+ if (Mysql_connection_thread_args *mysql_thread_args=
+ new Mysql_connection_thread_args(vio, thread_registry, user_map,
+ ++total_connection_count,
+ instance_map)
+ )
+ {
+ /*
+ Initialize thread attributes to create detached thread; it seems
+ easier to do it ad-hoc than have a global variable for attributes.
+ */
+ pthread_t mysql_thd_id;
+ pthread_attr_t mysql_thd_attr;
+ pthread_attr_init(&mysql_thd_attr);
+ pthread_attr_setdetachstate(&mysql_thd_attr, PTHREAD_CREATE_DETACHED);
+ if (pthread_create(&mysql_thd_id, &mysql_thd_attr, mysql_connection,
+ mysql_thread_args))
+ {
+ delete mysql_thread_args;
+ vio_delete(vio);
+ log_error("handle_one_mysql_connection(): pthread_create(mysql) failed");
+ }
+ pthread_attr_destroy(&mysql_thd_attr);
+ }
+ else
+ vio_delete(vio);
+}
+
+
+C_MODE_START
+
+
+pthread_handler_decl(listener, arg)
+{
+ Listener_thread_args *args= (Listener_thread_args *) arg;
+ Listener_thread listener(*args);
+ listener.run();
+ /*
+ args is a stack variable because listener thread lives as long as the
+ manager process itself
+ */
+ return 0;
+}
+
+
+C_MODE_END
+
diff --git a/server-tools/instance-manager/listener.h b/server-tools/instance-manager/listener.h
new file mode 100644
index 00000000000..7a8af49e2b3
--- /dev/null
+++ b/server-tools/instance-manager/listener.h
@@ -0,0 +1,56 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <my_global.h>
+#include <my_pthread.h>
+
+
+C_MODE_START
+
+pthread_handler_decl(listener, arg);
+
+C_MODE_END
+
+class Thread_registry;
+class Options;
+class User_map;
+class Instance_map;
+
+struct Listener_thread_args
+{
+ Thread_registry &thread_registry;
+ const Options &options;
+ const User_map &user_map;
+ Instance_map &instance_map;
+
+ Listener_thread_args(Thread_registry &thread_registry_arg,
+ const Options &options_arg,
+ const User_map &user_map_arg,
+ Instance_map &instance_map_arg) :
+ thread_registry(thread_registry_arg)
+ ,options(options_arg)
+ ,user_map(user_map_arg)
+ ,instance_map(instance_map_arg)
+ {}
+};
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
diff --git a/server-tools/instance-manager/log.cc b/server-tools/instance-manager/log.cc
new file mode 100644
index 00000000000..5491b4e70e9
--- /dev/null
+++ b/server-tools/instance-manager/log.cc
@@ -0,0 +1,169 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h>
+
+#include "log.h"
+
+#include <stdarg.h>
+#include <m_string.h>
+#include <my_sys.h>
+
+/*
+ TODO:
+ - add flexible header support
+ - rewrite all fprintf with fwrite
+ - think about using 'write' instead of fwrite/fprintf on POSIX systems
+*/
+
+/*
+ Format log entry and write it to the given stream.
+ SYNOPSYS
+ log()
+*/
+
+static inline void log(FILE *file, const char *format, va_list args)
+{
+ /*
+ log() should be thread-safe; it implies that we either call fprintf()
+ once per log(), or use flockfile()/funlockfile(). But flockfile() is
+ POSIX, not ANSI C, so we try to vsnprintf the whole message to the
+ stack, and if stack buffer is not enough, to malloced string. When
+ message is formatted, it is fprintf()'ed to the file.
+ */
+
+ /* Format time like MYSQL_LOG does. */
+ time_t now= time(0);
+ struct tm bd_time; // broken-down time
+ localtime_r(&now, &bd_time);
+
+ char buff_date[32];
+ sprintf(buff_date, "%02d%02d%02d %2d:%02d:%02d\t",
+ bd_time.tm_year % 100,
+ bd_time.tm_mon + 1,
+ bd_time.tm_mday,
+ bd_time.tm_hour,
+ bd_time.tm_min,
+ bd_time.tm_sec);
+ /* Format the message */
+ char buff_stack[256];
+
+ int n= vsnprintf(buff_stack, sizeof(buff_stack), format, args);
+ /*
+ return value of vsnprintf can vary, according to various standards;
+ try to check all cases.
+ */
+ char *buff_msg= buff_stack;
+ if (n < 0 || n == sizeof(buff_stack))
+ {
+ int size= sizeof(buff_stack) * 2;
+ buff_msg= (char *) my_malloc(size, 0);
+ while (true)
+ {
+ if (buff_msg == 0)
+ {
+ strmake(buff_stack, "log(): message is too big, my_malloc() failed",
+ sizeof(buff_stack));
+ buff_msg= buff_stack;
+ break;
+ }
+ n = vsnprintf(buff_msg, size, format, args);
+ if (n >= 0 && n < size)
+ break;
+ size*= 2;
+ /* realloc() does unnecessary memcpy */
+ my_free(buff_msg, 0);
+ buff_msg= (char *) my_malloc(size, 0);
+ }
+ }
+ else if ((size_t) n > sizeof(buff_stack))
+ {
+ buff_msg= (char *) my_malloc(n + 1, 0);
+#ifdef DBUG
+ DBUG_ASSERT(n == vsnprintf(buff_msg, n + 1, format, args));
+#else
+ vsnprintf(buff_msg, n + 1, format, args);
+#endif
+ }
+ fprintf(file, "%s%s\n", buff_date, buff_msg);
+ if (buff_msg != buff_stack)
+ my_free(buff_msg, 0);
+
+ /* don't fflush() the file: buffering strategy is set in log_init() */
+}
+
+
+void log_error(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ log(stderr, format, args);
+ va_end(args);
+}
+
+
+void log_info(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ log(stdout, format, args);
+ va_end(args);
+}
+
+/* TODO: rewrite with buffering print */
+void print_info(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stdout, format, args);
+ va_end(args);
+}
+
+void print_error(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+/*
+ log_init()
+ RETURN VALUE
+ 0 ok
+ !0 error
+*/
+
+void log_init()
+{
+ /*
+ stderr is unbuffered by default; there is no good of line buffering,
+ as all logging is performed linewise - so remove buffering from stdout
+ also
+ */
+ setbuf(stdout, 0);
+}
+
+void die(const char *format, ...)
+{
+ va_list args;
+ fprintf(stderr,"%s: ", my_progname);
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit(1);
+}
diff --git a/server-tools/instance-manager/log.h b/server-tools/instance-manager/log.h
new file mode 100644
index 00000000000..825d7515513
--- /dev/null
+++ b/server-tools/instance-manager/log.h
@@ -0,0 +1,81 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Logging facilities.
+
+ Two logging streams are supported: error log and info log. Additionally
+ libdbug may be used for debug information output.
+ ANSI C buffered I/O is used to perform logging.
+ Logging is performed via stdout/stder, so one can reopen them to point to
+ ordinary files. To initialize loggin environment log_init() must be called.
+
+ Rationale:
+ - no MYSQL_LOG as it has BIN mode, and not easy to fetch from sql_class.h
+ - no constructors/desctructors to make logging available all the time
+ Function names are subject to change.
+*/
+
+
+/* Precede error message with date and time and print it to the stdout */
+void log_info(const char *format, ...)
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ ;
+
+
+/* Precede error message with date and time and print it to the stderr */
+void log_error(const char *format, ...)
+#ifdef __GNUC__
+ __attribute__ ((format (printf, 1, 2)))
+#endif
+ ;
+
+
+/*
+ Now this is simple catchouts for printf (no date/time is logged), to be
+ able to replace underlying streams in future.
+*/
+
+void print_info(const char *format, ...)
+#ifdef __GNUC__
+ __attribute__ ((format (printf, 1, 2)))
+#endif
+ ;
+
+
+void print_error(const char *format, ...)
+#ifdef __GNUC__
+ __attribute__ ((format (printf, 1, 2)))
+#endif
+ ;
+
+/* initialize logs */
+void log_init();
+
+
+/* print information to the error log and eixt(1) */
+
+void die(const char *format, ...)
+#ifdef __GNUC__
+ __attribute__ ((format (printf, 1, 2)))
+#endif
+ ;
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H
diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc
new file mode 100644
index 00000000000..fd8673c4d66
--- /dev/null
+++ b/server-tools/instance-manager/manager.cc
@@ -0,0 +1,231 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h>
+#include "manager.h"
+
+#include "priv.h"
+#include "thread_registry.h"
+#include "listener.h"
+#include "instance_map.h"
+#include "options.h"
+#include "user_map.h"
+#include "log.h"
+#include "guardian.h"
+
+#include <my_sys.h>
+#include <m_string.h>
+#include <signal.h>
+#include <thr_alarm.h>
+#include <sys/wait.h>
+
+
+static int create_pid_file(const char *pid_file_name)
+{
+ if (FILE *pid_file= my_fopen(pid_file_name,
+ O_WRONLY | O_CREAT | O_BINARY, MYF(0)))
+ {
+ fprintf(pid_file, "%d\n", (int) getpid());
+ my_fclose(pid_file, MYF(0));
+ }
+ else
+ {
+ log_error("can't create pid file %s: errno=%d, %s",
+ pid_file_name, errno, strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ manager - entry point to the main instance manager process: start
+ listener thread, write pid file and enter into signal handling.
+ See also comments in mysqlmanager.cc to picture general Instance Manager
+ architecture.
+*/
+
+void manager(const Options &options)
+{
+ Thread_registry thread_registry;
+ /*
+ All objects created in the manager() function live as long as
+ thread_registry lives, and thread_registry is alive until there are
+ working threads.
+ */
+
+ User_map user_map;
+ Instance_map instance_map(options.default_mysqld_path, options.first_option);
+ Guardian_thread guardian_thread(thread_registry,
+ &instance_map,
+ options.monitoring_interval);
+
+ Listener_thread_args listener_args(thread_registry, options, user_map,
+ instance_map);
+
+ manager_pid= getpid();
+ instance_map.guardian= &guardian_thread;
+
+ if (instance_map.init() || user_map.init())
+ return;
+
+
+ if (instance_map.load())
+ {
+ log_error("Cannot init instances repository. This might be caused by "
+ "the wrong config file options. For instance, missing mysqld "
+ "binary. Aborting.");
+ return;
+ }
+
+ if (user_map.load(options.password_file_name))
+ return;
+
+ /* write pid file */
+ if (create_pid_file(options.pid_file_name))
+ return;
+
+ /* block signals */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ sigaddset(&mask, SIGPIPE);
+ sigaddset(&mask, SIGHUP);
+ /*
+ We want this signal to be blocked in all theads but the signal
+ one. It is needed for the thr_alarm subsystem to work.
+ */
+ sigaddset(&mask,THR_SERVER_ALARM);
+
+ /* all new threads will inherite this signal mask */
+ pthread_sigmask(SIG_BLOCK, &mask, NULL);
+
+ /* create the listener */
+ {
+ pthread_t listener_thd_id;
+ pthread_attr_t listener_thd_attr;
+ int rc;
+
+ pthread_attr_init(&listener_thd_attr);
+ pthread_attr_setdetachstate(&listener_thd_attr, PTHREAD_CREATE_DETACHED);
+ rc= pthread_create(&listener_thd_id, &listener_thd_attr, listener,
+ &listener_args);
+ pthread_attr_destroy(&listener_thd_attr);
+ if (rc)
+ {
+ log_error("manager(): pthread_create(listener) failed");
+ goto err;
+ }
+
+ }
+
+ /* create guardian thread */
+ {
+ pthread_t guardian_thd_id;
+ pthread_attr_t guardian_thd_attr;
+ int rc;
+
+ /*
+ NOTE: Guardian should be shutdown first. Only then all other threads
+ need to be stopped. This should be done, as guardian is responsible for
+ shutting down the instances, and this is a long operation.
+ */
+
+ pthread_attr_init(&guardian_thd_attr);
+ pthread_attr_setdetachstate(&guardian_thd_attr, PTHREAD_CREATE_DETACHED);
+ rc= pthread_create(&guardian_thd_id, &guardian_thd_attr, guardian,
+ &guardian_thread);
+ pthread_attr_destroy(&guardian_thd_attr);
+ if (rc)
+ {
+ log_error("manager(): pthread_create(guardian) failed");
+ goto err;
+ }
+
+ }
+
+ /*
+ To work nicely with LinuxThreads, the signal thread is the first thread
+ in the process.
+ */
+ int signo;
+ bool shutdown_complete;
+
+ shutdown_complete= FALSE;
+ /*
+ In our case the signal thread also implements functions of alarm thread.
+ Here we init alarm thread functionality. We suppose that we won't have
+ more then 10 alarms at the same time.
+ */
+ init_thr_alarm(10);
+ /* init list of guarded instances */
+ guardian_thread.lock();
+
+ guardian_thread.init();
+
+ guardian_thread.unlock();
+
+ /*
+ After the list of guarded instances have been initialized,
+ Guardian should start them.
+ */
+ pthread_cond_signal(&guardian_thread.COND_guardian);
+
+ signal(SIGPIPE, SIG_IGN);
+
+ while (!shutdown_complete)
+ {
+ int status= 0;
+
+ if ((status= my_sigwait(&mask, &signo)) != 0)
+ {
+ log_error("sigwait() failed");
+ goto err;
+ }
+
+ switch (signo)
+ {
+ case THR_SERVER_ALARM:
+ process_alarm(signo);
+ break;
+ default:
+ {
+ if (!guardian_thread.is_stopped())
+ {
+ bool stop_instances= true;
+ guardian_thread.request_shutdown(stop_instances);
+ pthread_cond_signal(&guardian_thread.COND_guardian);
+ }
+ else
+ {
+ thread_registry.deliver_shutdown();
+ shutdown_complete= TRUE;
+ }
+ }
+ break;
+ }
+ }
+
+err:
+ /* delete the pid file */
+ my_delete(options.pid_file_name, MYF(0));
+
+ /* free alarm structures */
+ end_thr_alarm(1);
+ /* don't pthread_exit to kill all threads who did not shut down in time */
+}
+
diff --git a/merge/mrg_def.h b/server-tools/instance-manager/manager.h
index 8b6be08c32d..d73f4b35f18 100644
--- a/merge/mrg_def.h
+++ b/server-tools/instance-manager/manager.h
@@ -1,4 +1,6 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,16 +16,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Denna fil includeras i alla merge-filer */
+class Options;
-#ifndef N_MAXKEY
-#include "../isam/isamdef.h"
-#endif
+void manager(const Options &options);
-#include "merge.h"
-
-extern LIST *mrg_open_list;
-
-#ifdef THREAD
-extern pthread_mutex_t THR_LOCK_open;
-#endif
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
diff --git a/server-tools/instance-manager/messages.cc b/server-tools/instance-manager/messages.cc
new file mode 100644
index 00000000000..d044c0f65db
--- /dev/null
+++ b/server-tools/instance-manager/messages.cc
@@ -0,0 +1,76 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h>
+#include "messages.h"
+
+#include "mysqld_error.h"
+#include "mysql_manager_error.h"
+
+#include <mysql_com.h>
+#include <assert.h>
+
+
+static const char *mysqld_error_message(unsigned sql_errno)
+{
+ switch (sql_errno) {
+ case ER_HANDSHAKE_ERROR:
+ return "Bad handshake";
+ case ER_OUT_OF_RESOURCES:
+ return "Out of memory; Check if mysqld or some other process"
+ " uses all available memory. If not you may have to use"
+ " 'ulimit' to allow mysqld to use more memory or you can"
+ " add more swap space";
+ case ER_ACCESS_DENIED_ERROR:
+ return "Access denied. Bad username/password pair";
+ case ER_NOT_SUPPORTED_AUTH_MODE:
+ return "Client does not support authentication protocol requested by"
+ " server; consider upgrading MySQL client";
+ case ER_UNKNOWN_COM_ERROR:
+ return "Unknown command";
+ case ER_SYNTAX_ERROR:
+ return "You have an error in your command syntax. Check the manual that"
+ " corresponds to your MySQL Instance Manager version for the right"
+ " syntax to use";
+ case ER_BAD_INSTANCE_NAME:
+ return "Bad instance name. Check that the instance with such a name exists";
+ case ER_INSTANCE_IS_NOT_STARTED:
+ return "Cannot stop instance. Perhaps the instance is not started, or was started"
+ "manually, so IM cannot find the pidfile.";
+ case ER_INSTANCE_ALREADY_STARTED:
+ return "The instance is already started";
+ case ER_CANNOT_START_INSTANCE:
+ return "Cannot start instance. Possible reasons are wrong instance options"
+ " or resources shortage";
+ case ER_STOP_INSTANCE:
+ return "Cannot stop instance";
+ default:
+ DBUG_ASSERT(0);
+ return 0;
+ }
+}
+
+
+const char *message(unsigned sql_errno)
+{
+ return mysqld_error_message(sql_errno);
+}
+
+
+const char *errno_to_sqlstate(unsigned sql_errno)
+{
+ return mysql_errno_to_sqlstate(sql_errno);
+}
diff --git a/merge/mrg_delete.c b/server-tools/instance-manager/messages.h
index 920156be01e..b771efe5e13 100644
--- a/merge/mrg_delete.c
+++ b/server-tools/instance-manager/messages.h
@@ -1,4 +1,6 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,16 +16,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Delete last read record */
+const char *message(unsigned sql_errno);
-#include "mrg_def.h"
+const char *errno_to_sqlstate(unsigned sql_errno);
-int mrg_delete(MRG_INFO *info,const byte *record)
-{
- if (!info->current_table)
- {
- my_errno=HA_ERR_NO_ACTIVE_RECORD;
- return(-1);
- }
- return nisam_delete(info->current_table->table,record);
-}
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H
diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc
new file mode 100644
index 00000000000..215dbe51b58
--- /dev/null
+++ b/server-tools/instance-manager/mysql_connection.cc
@@ -0,0 +1,397 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "mysql_connection.h"
+
+#include "priv.h"
+#include "mysql_manager_error.h"
+#include "mysqld_error.h"
+#include "thread_registry.h"
+#include "log.h"
+#include "user_map.h"
+#include "protocol.h"
+#include "messages.h"
+#include "command.h"
+#include "factory.h"
+#include "parse.h"
+
+#include <mysql.h>
+#include <violite.h>
+#include <mysql_com.h>
+#include <m_string.h>
+#include <my_sys.h>
+
+
+Command *parse_command(Command_factory * factory, const char *text);
+
+Mysql_connection_thread_args::Mysql_connection_thread_args(
+ struct st_vio *vio_arg,
+ Thread_registry &thread_registry_arg,
+ const User_map &user_map_arg,
+ ulong connection_id_arg,
+ Instance_map &instance_map_arg) :
+ vio(vio_arg)
+ ,thread_registry(thread_registry_arg)
+ ,user_map(user_map_arg)
+ ,connection_id(connection_id_arg)
+ ,instance_map(instance_map_arg)
+ {}
+
+/*
+ MySQL connection - handle one connection with mysql command line client
+ See also comments in mysqlmanager.cc to picture general Instance Manager
+ architecture.
+ We use conventional technique to work with classes without exceptions:
+ class acquires all vital resource in init(); Thus if init() succeed,
+ a user must call cleanup(). All other methods are valid only between
+ init() and cleanup().
+*/
+
+class Mysql_connection_thread: public Mysql_connection_thread_args
+{
+public:
+ Mysql_connection_thread(const Mysql_connection_thread_args &args);
+
+ int init();
+ void cleanup();
+
+ void run();
+
+ ~Mysql_connection_thread();
+private:
+ Thread_info thread_info;
+ NET net;
+ struct rand_struct rand_st;
+ char scramble[SCRAMBLE_LENGTH + 1];
+ uint status;
+ ulong client_capabilities;
+private:
+ /* Names are conventionally the same as in mysqld */
+ int check_connection();
+ int do_command();
+ int dispatch_command(enum enum_server_command command,
+ const char *text, uint len);
+};
+
+
+Mysql_connection_thread::Mysql_connection_thread(
+ const Mysql_connection_thread_args &args) :
+ Mysql_connection_thread_args(args.vio,
+ args.thread_registry,
+ args.user_map,
+ args.connection_id,
+ args.instance_map)
+ ,thread_info(pthread_self())
+{
+ thread_registry.register_thread(&thread_info);
+}
+
+
+/*
+ NET subsystem requieres its user to provide my_net_local_init extern
+ C function (exactly as declared below). my_net_local_init is called by
+ my_net_init and is supposed to set NET controlling variables.
+ See also priv.h for variables description.
+*/
+
+C_MODE_START
+
+void my_net_local_init(NET *net)
+{
+ net->max_packet= net_buffer_length;
+ net->read_timeout= net_read_timeout;
+ net->write_timeout= net_write_timeout;
+ net->retry_count= net_retry_count;
+ net->max_packet_size= max_allowed_packet;
+}
+
+C_MODE_END
+
+
+/*
+ Every resource, which we can fail to acquire, is allocated in init().
+ This function is complementary to cleanup().
+*/
+
+int Mysql_connection_thread::init()
+{
+ /* Allocate buffers for network I/O */
+ if (my_net_init(&net, vio))
+ return 1;
+ net.return_status= &status;
+ /* Initialize random number generator */
+ {
+ ulong seed1= (ulong) &rand_st + rand();
+ ulong seed2= rand() + time(0);
+ randominit(&rand_st, seed1, seed2);
+ }
+ /* Fill scramble - server's random message used for handshake */
+ create_random_string(scramble, SCRAMBLE_LENGTH, &rand_st);
+ /* We don't support transactions, every query is atomic */
+ status= SERVER_STATUS_AUTOCOMMIT;
+ return 0;
+}
+
+
+void Mysql_connection_thread::cleanup()
+{
+ net_end(&net);
+}
+
+
+Mysql_connection_thread::~Mysql_connection_thread()
+{
+ /* vio_delete closes the socket if necessary */
+ vio_delete(vio);
+ thread_registry.unregister_thread(&thread_info);
+}
+
+
+void Mysql_connection_thread::run()
+{
+ log_info("accepted mysql connection %d", connection_id);
+
+ my_thread_init();
+
+ if (check_connection())
+ {
+ my_thread_end();
+ return;
+ }
+
+ log_info("connection %d is checked successfully", connection_id);
+
+ vio_keepalive(vio, TRUE);
+
+ while (!net.error && net.vio && !thread_registry.is_shutdown())
+ {
+ if (do_command())
+ break;
+ }
+
+ my_thread_end();
+}
+
+
+int Mysql_connection_thread::check_connection()
+{
+ ulong pkt_len=0; // to hold client reply length
+ /* maximum size of the version string */
+ enum { MAX_VERSION_LENGTH= 80 };
+
+ /* buffer for the first packet */ /* packet contains: */
+ char buff[MAX_VERSION_LENGTH + 1 + // server version, 0-ended
+ 4 + // connection id
+ SCRAMBLE_LENGTH + 2 + // scramble (in 2 pieces)
+ 18]; // server variables: flags,
+ // charset number, status,
+ char *pos= buff;
+ ulong server_flags;
+
+ memcpy(pos, mysqlmanager_version, mysqlmanager_version_length + 1);
+ pos+= mysqlmanager_version_length + 1;
+
+ int4store((uchar*) pos, connection_id);
+ pos+= 4;
+
+ /*
+ Old clients does not understand long scrambles, but can ignore packet
+ tail: that's why first part of the scramble is placed here, and second
+ part at the end of packet (even though we don't support old clients,
+ we must follow standard packet format.)
+ */
+ memcpy(pos, scramble, SCRAMBLE_LENGTH_323);
+ pos+= SCRAMBLE_LENGTH_323;
+ *pos++= '\0';
+
+ server_flags= CLIENT_LONG_FLAG | CLIENT_PROTOCOL_41 |
+ CLIENT_SECURE_CONNECTION;
+
+ /*
+ 18-bytes long section for various flags/variables
+
+ Every flag occupies a bit in first half of ulong; int2store will
+ gracefully pick up all flags.
+ */
+ int2store(pos, server_flags);
+ pos+= 2;
+ *pos++= (char) default_charset_info->number; // global mysys variable
+ int2store(pos, status); // connection status
+ pos+= 2;
+ bzero(pos, 13); // not used now
+ pos+= 13;
+
+ /* second part of the scramble, null-terminated */
+ memcpy(pos, scramble + SCRAMBLE_LENGTH_323,
+ SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1);
+ pos+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1;
+
+ /* write connection message and read reply */
+ enum { MIN_HANDSHAKE_SIZE= 2 };
+ if (net_write_command(&net, protocol_version, "", 0, buff, pos - buff) ||
+ (pkt_len= my_net_read(&net)) == packet_error ||
+ pkt_len < MIN_HANDSHAKE_SIZE)
+ {
+ net_send_error(&net, ER_HANDSHAKE_ERROR);
+ return 1;
+ }
+
+ client_capabilities= uint2korr(net.read_pos);
+ if (!(client_capabilities & CLIENT_PROTOCOL_41))
+ {
+ net_send_error_323(&net, ER_NOT_SUPPORTED_AUTH_MODE);
+ return 1;
+ }
+ client_capabilities|= ((ulong) uint2korr(net.read_pos + 2)) << 16;
+
+ pos= (char *) net.read_pos + 32;
+
+ /* At least one byte for username and one byte for password */
+ if (pos >= (char *) net.read_pos + pkt_len + 2)
+ {
+ /*TODO add user and password handling in error messages*/
+ net_send_error(&net, ER_HANDSHAKE_ERROR);
+ return 1;
+ }
+
+ const char *user= pos;
+ const char *password= strend(user)+1;
+ ulong password_len= *password++;
+ if (password_len != SCRAMBLE_LENGTH)
+ {
+ net_send_error(&net, ER_ACCESS_DENIED_ERROR);
+ return 1;
+ }
+ if (user_map.authenticate(user, password-user-2, password, scramble))
+ {
+ net_send_error(&net, ER_ACCESS_DENIED_ERROR);
+ return 1;
+ }
+ net_send_ok(&net, connection_id);
+ return 0;
+}
+
+
+int Mysql_connection_thread::do_command()
+{
+ char *packet;
+ ulong packet_length;
+
+ /* We start to count packets from 0 for each new command */
+ net.pkt_nr= 0;
+
+ if ((packet_length=my_net_read(&net)) == packet_error)
+ {
+ /* Check if we can continue without closing the connection */
+ if (net.error != 3) // what is 3 - find out
+ {
+ return 1;
+ }
+ if (thread_registry.is_shutdown())
+ return 1;
+ net_send_error(&net, net.last_errno);
+ net.error= 0;
+ return 0;
+ }
+ else
+ {
+ if (thread_registry.is_shutdown())
+ return 1;
+ packet= (char*) net.read_pos;
+ enum enum_server_command command= (enum enum_server_command)
+ (uchar) *packet;
+ log_info("connection %d: packet_length=%d, command=%d",
+ connection_id, packet_length, command);
+ return dispatch_command(command, packet + 1, packet_length - 1);
+ }
+}
+
+int Mysql_connection_thread::dispatch_command(enum enum_server_command command,
+ const char *packet, uint len)
+{
+ switch (command) {
+ case COM_QUIT: // client exit
+ log_info("query for connection %d received quit command", connection_id);
+ return 1;
+ case COM_PING:
+ log_info("query for connection %d received ping command", connection_id);
+ net_send_ok(&net, connection_id);
+ break;
+ case COM_QUERY:
+ {
+ log_info("query for connection %d : ----\n%s\n-------------------------",
+ connection_id,packet);
+ Command_factory commands_factory(instance_map);
+ if (Command *command= parse_command(&commands_factory, packet))
+ {
+ int res= 0;
+ log_info("query for connection %d successefully parsed",connection_id);
+ res= command->execute(&net, connection_id);
+ delete command;
+ if (!res)
+ {
+ log_info("query for connection %d executed ok",connection_id);
+ }
+ else
+ {
+ log_info("query for connection %d executed err=%d",connection_id,res);
+ net_send_error(&net, res);
+ return 0;
+ }
+ }
+ else
+ {
+ net_send_error(&net,ER_OUT_OF_RESOURCES);
+ return 0;
+ }
+ break;
+ }
+ default:
+ log_info("query for connection %d received unknown command",connection_id);
+ net_send_error(&net, ER_UNKNOWN_COM_ERROR);
+ break;
+ }
+ return 0;
+}
+
+
+C_MODE_START
+
+pthread_handler_decl(mysql_connection, arg)
+{
+ Mysql_connection_thread_args *args= (Mysql_connection_thread_args *) arg;
+ Mysql_connection_thread mysql_connection_thread(*args);
+ delete args;
+ if (mysql_connection_thread.init())
+ log_info("mysql_connection(): error initializing thread");
+ else
+ {
+ mysql_connection_thread.run();
+ mysql_connection_thread.cleanup();
+ }
+ return 0;
+}
+
+C_MODE_END
+
+
+/*
+ vim: fdm=marker
+*/
diff --git a/server-tools/instance-manager/mysql_connection.h b/server-tools/instance-manager/mysql_connection.h
new file mode 100644
index 00000000000..e0109ce234f
--- /dev/null
+++ b/server-tools/instance-manager/mysql_connection.h
@@ -0,0 +1,54 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <my_global.h>
+#include <my_pthread.h>
+
+
+C_MODE_START
+
+pthread_handler_decl(mysql_connection, arg);
+
+C_MODE_END
+
+
+class Thread_registry;
+class User_map;
+class Instance_map;
+struct st_vio;
+
+struct Mysql_connection_thread_args
+{
+ struct st_vio *vio;
+ Thread_registry &thread_registry;
+ const User_map &user_map;
+ ulong connection_id;
+ Instance_map &instance_map;
+
+ Mysql_connection_thread_args(struct st_vio *vio_arg,
+ Thread_registry &thread_registry_arg,
+ const User_map &user_map_arg,
+ ulong connection_id_arg,
+ Instance_map &instance_map_arg);
+};
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
diff --git a/merge/mrg_locking.c b/server-tools/instance-manager/mysql_manager_error.h
index bd33e047091..2862e01649d 100644
--- a/merge/mrg_locking.c
+++ b/server-tools/instance-manager/mysql_manager_error.h
@@ -1,4 +1,6 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H
+/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,20 +16,12 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*
- Lock databases against read or write.
-*/
+/* Definefile for instance manager error messagenumbers */
-#include "mrg_def.h"
+#define ER_BAD_INSTANCE_NAME 3000
+#define ER_INSTANCE_IS_NOT_STARTED 3001
+#define ER_INSTANCE_ALREADY_STARTED 3002
+#define ER_CANNOT_START_INSTANCE 3003
+#define ER_STOP_INSTANCE 3004
-int mrg_lock_database(MRG_INFO *info,int lock_type)
-{
- int error,new_error;
- MRG_TABLE *file;
-
- error=0;
- for (file=info->open_tables ; file != info->end_table ; file++)
- if ((new_error=nisam_lock_database(file->table,lock_type)))
- error=new_error;
- return(error);
-}
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */
diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc
new file mode 100644
index 00000000000..262686c3fab
--- /dev/null
+++ b/server-tools/instance-manager/mysqlmanager.cc
@@ -0,0 +1,343 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h>
+#include "manager.h"
+
+#include "options.h"
+#include "log.h"
+
+#include <my_sys.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+/*
+ Few notes about Instance Manager architecture:
+ Instance Manager consisits of two processes: the angel process, and the
+ instance manager process. Responsibilities of the angel process is to
+ monitor the instance manager process, and restart it in case of
+ failure/shutdown. The angel process is started only if startup option
+ '--run-as-service' is provided.
+ The Instance Manager process consists of several
+ subsystems (thread sets):
+ - the signal handling thread: it's responsibilities are to handle
+ user signals and propogate them to the other threads. All other threads
+ are accounted in the signal handler thread Thread Registry.
+ - the listener: listens all sockets. There is a listening
+ socket for each (mysql, http, snmp, rendezvous (?)) subsystem.
+ - mysql subsystem: Instance Manager acts like an ordinary MySQL Server,
+ but with very restricted command set. Each MySQL client connection is
+ handled in a separate thread. All MySQL client connections threads
+ constitute mysql subsystem.
+ - http subsystem: it is also possible to talk with Instance Manager via
+ http. One thread per http connection is used. Threads are pooled.
+ - 'snmp' connections (FIXME: I know nothing about it yet)
+ - rendezvous threads
+*/
+
+static void init_environment(char *progname);
+static void daemonize(const char *log_file_name);
+static void angel(const Options &options);
+static struct passwd *check_user(const char *user);
+static int set_user(const char *user, struct passwd *user_info);
+
+
+/*
+ main, entry point
+ - init environment
+ - handle options
+ - daemonize and run angel process (if necessary)
+ - run manager process
+*/
+
+int main(int argc, char *argv[])
+{
+ init_environment(argv[0]);
+ Options options;
+ struct passwd *user_info;
+
+ if (options.load(argc, argv))
+ goto err;
+
+ if ((user_info= check_user(options.user)))
+ {
+ if (set_user(options.user, user_info))
+ {
+ options.cleanup();
+ return 1;
+ }
+ }
+
+ if (options.run_as_service)
+ {
+ /* forks, and returns only in child */
+ daemonize(options.log_file_name);
+ /* forks again, and returns only in child: parent becomes angel */
+ angel(options);
+ }
+ manager(options);
+ options.cleanup();
+ my_end(0);
+ return 0;
+err:
+ my_end(0);
+ return 1;
+}
+
+/******************* Auxilary functions implementation **********************/
+
+/* Change to run as another user if started with --user */
+
+static struct passwd *check_user(const char *user)
+{
+#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
+ struct passwd *user_info;
+ uid_t user_id= geteuid();
+
+ /* Don't bother if we aren't superuser */
+ if (user_id)
+ {
+ if (user)
+ {
+ /* Don't give a warning, if real user is same as given with --user */
+ user_info= getpwnam(user);
+ if ((!user_info || user_id != user_info->pw_uid))
+ log_info("One can only use the --user switch if running as root\n");
+ }
+ return NULL;
+ }
+ if (!user)
+ {
+ log_info("You are running mysqlmanager as root! This might introduce security problems. It is safer to use --user option istead.\n");
+ return NULL;
+ }
+ if (!strcmp(user, "root"))
+ return NULL; /* Avoid problem with dynamic libraries */
+ if (!(user_info= getpwnam(user)))
+ {
+ /* Allow a numeric uid to be used */
+ const char *pos;
+ for (pos= user; my_isdigit(default_charset_info, *pos); pos++) ;
+ if (*pos) /* Not numeric id */
+ goto err;
+ if (!(user_info= getpwuid(atoi(user))))
+ goto err;
+ else
+ return user_info;
+ }
+ else
+ return user_info;
+
+err:
+ log_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n", user);
+#endif
+ return NULL;
+}
+
+static int set_user(const char *user, struct passwd *user_info)
+{
+ DBUG_ASSERT(user_info);
+#ifdef HAVE_INITGROUPS
+ initgroups((char*) user,user_info->pw_gid);
+#endif
+ if (setgid(user_info->pw_gid) == -1)
+ {
+ log_error("setgid() failed");
+ return 1;
+ }
+ if (setuid(user_info->pw_uid) == -1)
+ {
+ log_error("setuid() failed");
+ return 1;
+ }
+ return 0;
+}
+
+
+
+/*
+ Init environment, common for daemon and non-daemon
+*/
+
+static void init_environment(char *progname)
+{
+ MY_INIT(progname);
+ log_init();
+ umask(0117);
+ srand(time(0));
+}
+
+
+/*
+ Become a UNIX service
+ SYNOPSYS
+ daemonize()
+*/
+
+static void daemonize(const char *log_file_name)
+{
+ pid_t pid= fork();
+ switch (pid) {
+ case -1: // parent, fork error
+ die("daemonize(): fork failed, %s", strerror(errno));
+ case 0: // child, fork ok
+ int fd;
+ /*
+ Become a session leader: setsid must succeed because child is
+ guaranteed not to be a process group leader (it belongs to the
+ process group of the parent.)
+ The goal is not to have a controlling terminal.
+ */
+ setsid();
+ /*
+ As we now don't have a controlling terminal we will not receive
+ tty-related signals - no need to ignore them.
+ */
+
+ close(STDIN_FILENO);
+
+ fd= open(log_file_name, O_WRONLY | O_CREAT | O_APPEND | O_NOCTTY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ if (fd < 0)
+ die("daemonize(): failed to open log file %s, %s", log_file_name,
+ strerror(errno));
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd != STDOUT_FILENO && fd != STDERR_FILENO)
+ close(fd);
+
+ /* TODO: chroot() and/or chdir() here */
+ break;
+ default:
+ /* successfully exit from parent */
+ exit(0);
+ }
+}
+
+
+enum { CHILD_OK= 0, CHILD_NEED_RESPAWN, CHILD_EXIT_ANGEL };
+
+static volatile sig_atomic_t child_status= CHILD_OK;
+
+/*
+ Signal handler for SIGCHLD: reap child, analyze child exit status, and set
+ child_status appropriately.
+*/
+
+void reap_child(int __attribute__((unused)) signo)
+{
+ int child_exit_status;
+ /* As we have only one child, no need to cycle waitpid */
+ if (waitpid(0, &child_exit_status, WNOHANG) > 0)
+ {
+ if (WIFSIGNALED(child_exit_status))
+ child_status= CHILD_NEED_RESPAWN;
+ else
+ /*
+ As reap_child is not called for SIGSTOP, we should be here only
+ if the child exited normally.
+ */
+ child_status= CHILD_EXIT_ANGEL;
+ }
+}
+
+static volatile sig_atomic_t is_terminated= 0;
+
+/*
+ Signal handler for terminate signals - SIGTERM, SIGHUP, SIGINT.
+ Set termination status and return.
+ (q) do we need to handle SIGQUIT?
+*/
+
+void terminate(int signo)
+{
+ is_terminated= signo;
+}
+
+
+/*
+ Fork a child and monitor it.
+ User can explicitly kill the angel process with SIGTERM/SIGHUP/SIGINT.
+ Angel process will exit silently if mysqlmanager exits normally.
+*/
+
+static void angel(const Options &options)
+{
+ /* install signal handlers */
+ sigset_t zeromask; // to sigsuspend in parent
+ struct sigaction sa_chld, sa_term;
+ struct sigaction sa_chld_out, sa_term_out, sa_int_out, sa_hup_out;
+
+ sigemptyset(&zeromask);
+ sigemptyset(&sa_chld.sa_mask);
+ sigemptyset(&sa_term.sa_mask);
+
+ sa_chld.sa_handler= reap_child;
+ sa_chld.sa_flags= SA_NOCLDSTOP;
+ sa_term.sa_handler= terminate;
+ sa_term.sa_flags= 0;
+
+ /* sigaction can fail only on wrong arguments */
+ sigaction(SIGCHLD, &sa_chld, &sa_chld_out);
+ sigaction(SIGTERM, &sa_term, &sa_term_out);
+ sigaction(SIGINT, &sa_term, &sa_int_out);
+ sigaction(SIGHUP, &sa_term, &sa_hup_out);
+
+ /* spawn a child */
+spawn:
+ pid_t pid= fork();
+ switch (pid) {
+ case -1:
+ die("angel(): fork failed, %s", strerror(errno));
+ case 0: // child, success
+ /*
+ restore default actions for signals to let the manager work with
+ signals as he wishes
+ */
+ sigaction(SIGCHLD, &sa_chld_out, 0);
+ sigaction(SIGTERM, &sa_term_out, 0);
+ sigaction(SIGINT, &sa_int_out, 0);
+ sigaction(SIGHUP, &sa_hup_out, 0);
+ /* Here we return to main, and fall into manager */
+ break;
+ default: // parent, success
+ while (child_status == CHILD_OK && is_terminated == 0)
+ sigsuspend(&zeromask);
+
+ if (is_terminated)
+ log_info("angel got signal %d, exiting", is_terminated);
+ else if (child_status == CHILD_NEED_RESPAWN)
+ {
+ child_status= CHILD_OK;
+ log_error("angel(): mysqlmanager exited abnormally: respawning...");
+ sleep(1); /* don't respawn too fast */
+ goto spawn;
+ }
+ /*
+ mysqlmanager successfully exited, let's silently evaporate
+ If we return to main we fall into the manager() function, so let's
+ simply exit().
+ */
+ exit(0);
+ }
+}
+
diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc
new file mode 100644
index 00000000000..4568d6b578d
--- /dev/null
+++ b/server-tools/instance-manager/options.cc
@@ -0,0 +1,238 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "options.h"
+
+#include "priv.h"
+
+#include <my_sys.h>
+#include <my_getopt.h>
+#include <m_string.h>
+#include <mysql_com.h>
+
+#define QUOTE2(x) #x
+#define QUOTE(x) QUOTE2(x)
+
+char Options::run_as_service;
+const char *Options::log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
+const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
+const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
+const char *Options::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
+const char *Options::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
+const char *Options::first_option= 0; /* No default value */
+const char *Options::bind_address= 0; /* No default value */
+const char *Options::user= 0; /* No default value */
+uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
+uint Options::port_number= DEFAULT_PORT;
+/* just to declare */
+char **Options::saved_argv;
+
+/*
+ List of options, accepted by the instance manager.
+ List must be closed with empty option.
+*/
+
+enum options {
+ OPT_LOG= 256,
+ OPT_PID_FILE,
+ OPT_SOCKET,
+ OPT_PASSWORD_FILE,
+ OPT_MYSQLD_PATH,
+ OPT_RUN_AS_SERVICE,
+ OPT_USER,
+ OPT_MONITORING_INTERVAL,
+ OPT_PORT,
+ OPT_BIND_ADDRESS
+};
+
+static struct my_option my_long_options[] =
+{
+ { "help", '?', "Display this help and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "log", OPT_LOG, "Path to log file. Used only with --run-as-service.",
+ (gptr *) &Options::log_file_name, (gptr *) &Options::log_file_name,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "pid-file", OPT_PID_FILE, "Pid file to use.",
+ (gptr *) &Options::pid_file_name, (gptr *) &Options::pid_file_name,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "socket", OPT_SOCKET, "Socket file to use for connection.",
+ (gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "passwd", 'P', "Prepare entry for passwd file and exit.", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.",
+ (gptr *) &Options::bind_address, (gptr *) &Options::bind_address,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "port", OPT_PORT, "Port number to use for connections",
+ (gptr *) &Options::port_number, (gptr *) &Options::port_number,
+ 0, GET_UINT, REQUIRED_ARG, DEFAULT_PORT, 0, 0, 0, 0, 0 },
+
+ { "password-file", OPT_PASSWORD_FILE, "Look for Instane Manager users"
+ " and passwords here.",
+ (gptr *) &Options::password_file_name,
+ (gptr *) &Options::password_file_name,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "default-mysqld-path", OPT_MYSQLD_PATH, "Where to look for MySQL"
+ " Server binary.",
+ (gptr *) &Options::default_mysqld_path, (gptr *) &Options::default_mysqld_path,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor instances"
+ " in seconds.",
+ (gptr *) &Options::monitoring_interval,
+ (gptr *) &Options::monitoring_interval,
+ 0, GET_UINT, REQUIRED_ARG, DEFAULT_MONITORING_INTERVAL,
+ 0, 0, 0, 0, 0 },
+
+ { "run-as-service", OPT_RUN_AS_SERVICE,
+ "Daemonize and start angel process.", (gptr *) &Options::run_as_service,
+ 0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
+
+ { "user", OPT_USER, "Username to start mysqlmanager",
+ (gptr *) &Options::user,
+ (gptr *) &Options::user,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { "version", 'V', "Output version information and exit.", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
+};
+
+static void version()
+{
+ printf("%s Ver %s for %s on %s\n", my_progname, mysqlmanager_version,
+ SYSTEM_TYPE, MACHINE_TYPE);
+}
+
+
+static const char *default_groups[]= { "manager", 0 };
+
+
+static void usage()
+{
+ version();
+
+ printf("Copyright (C) 2003, 2004 MySQL AB\n"
+ "This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
+ "and you are welcome to modify and redistribute it under the GPL license\n");
+ printf("Usage: %s [OPTIONS] \n", my_progname);
+
+ my_print_help(my_long_options);
+ print_defaults("my", default_groups);
+ my_print_variables(my_long_options);
+}
+
+
+static void passwd()
+{
+ char user[1024], *p;
+ const char *pw1, *pw2;
+ char pw1msg[]= "Enter password: ";
+ char pw2msg[]= "Re-type password: ";
+ char crypted_pw[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
+
+ fprintf(stderr, "Creating record for new user.\n");
+ fprintf(stderr, "Enter user name: ");
+ if (! fgets(user, sizeof(user), stdin))
+ {
+ fprintf(stderr, "Unable to read user.\n");
+ return;
+ }
+ if ((p= strchr(user, '\n'))) *p= 0;
+
+ pw1= get_tty_password(pw1msg);
+ pw2= get_tty_password(pw2msg);
+
+ if (strcmp(pw1, pw2))
+ {
+ fprintf(stderr, "Sorry, passwords do not match.\n");
+ return;
+ }
+
+ make_scrambled_password(crypted_pw, pw1);
+ printf("%s:%s\n", user, crypted_pw);
+}
+
+
+C_MODE_START
+
+static my_bool
+get_one_option(int optid,
+ const struct my_option *opt __attribute__((unused)),
+ char *argument __attribute__((unused)))
+{
+ switch(optid) {
+ case 'V':
+ version();
+ exit(0);
+ case 'P':
+ passwd();
+ exit(0);
+ case '?':
+ usage();
+ exit(0);
+ }
+ return 0;
+}
+
+C_MODE_END
+
+
+/*
+ - call load_defaults to load configuration file section
+ - call handle_options to assign defaults and command-line arguments
+ to the class members
+ if either of these function fail, exit the program
+ May not return.
+*/
+
+int Options::load(int argc, char **argv)
+{
+ int rc;
+
+ if (argc >= 2)
+ {
+ if (is_prefix(argv[1],"--defaults-file=") ||
+ is_prefix(argv[1],"--defaults-extra-file="))
+ Options::first_option= argv[1];
+ }
+
+ /* config-file options are prepended to command-line ones */
+ load_defaults("my", default_groups, &argc, &argv);
+
+ if ((rc= handle_options(&argc, &argv, my_long_options, get_one_option)) != 0)
+ return rc;
+ Options::saved_argv= argv;
+ return 0;
+}
+
+void Options::cleanup()
+{
+ /* free_defaults returns nothing */
+ free_defaults(Options::saved_argv);
+}
diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h
new file mode 100644
index 00000000000..3df259864be
--- /dev/null
+++ b/server-tools/instance-manager/options.h
@@ -0,0 +1,50 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+/*
+ Options - all possible options for the instance manager grouped in one
+ struct.
+*/
+#include <my_global.h>
+
+struct Options
+{
+ static char run_as_service; /* handle_options doesn't support bool */
+ static const char *log_file_name;
+ static const char *pid_file_name;
+ static const char *socket_file_name;
+ static const char *password_file_name;
+ static const char *default_mysqld_path;
+ static const char *user;
+ /* the option which should be passed to process_default_option_files */
+ static const char *first_option;
+ static uint monitoring_interval;
+ static uint port_number;
+ static const char *bind_address;
+
+ static char **saved_argv;
+
+ static int load(int argc, char **argv);
+ void cleanup();
+};
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc
new file mode 100644
index 00000000000..d3fb10b7c94
--- /dev/null
+++ b/server-tools/instance-manager/parse.cc
@@ -0,0 +1,184 @@
+/* Copyright (C) 2004 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 "parse.h"
+
+#include <string.h>
+
+enum Token
+{
+ TOK_FLUSH = 0,
+ TOK_INSTANCE,
+ TOK_INSTANCES,
+ TOK_OPTIONS,
+ TOK_START,
+ TOK_STATUS,
+ TOK_STOP,
+ TOK_SHOW,
+ TOK_NOT_FOUND, // must be after all tokens
+ TOK_END
+};
+
+struct tokens_st
+{
+ uint length;
+ const char *tok_name;
+};
+
+static struct tokens_st tokens[]= {
+ {5, "FLUSH"},
+ {8, "INSTANCE"},
+ {9, "INSTANCES"},
+ {7, "OPTIONS"},
+ {5, "START"},
+ {6, "STATUS"},
+ {4, "STOP"},
+ {4, "SHOW"}
+};
+
+
+/*
+ Returns token no if word corresponds to some token, otherwise returns
+ TOK_NOT_FOUND
+*/
+
+inline Token find_token(const char *word, uint word_len)
+{
+ int i= 0;
+ do
+ {
+ if (my_strnncoll(default_charset_info, (const uchar *) tokens[i].tok_name,
+ tokens[i].length, (const uchar *) word, word_len) == 0)
+ break;
+ }
+ while (++i < TOK_NOT_FOUND);
+ return (Token) i;
+}
+
+
+Token get_token(const char **text, uint *word_len)
+{
+ get_word(text, word_len);
+ if (*word_len)
+ return find_token(*text, *word_len);
+ return TOK_END;
+}
+
+
+Token shift_token(const char **text, uint *word_len)
+{
+ Token save= get_token(text, word_len);
+ (*text)+= *word_len;
+ return save;
+}
+
+
+void print_token(const char *token, uint tok_len)
+{
+ for (uint i= 0; i < tok_len; ++i)
+ printf("%c", token[i]);
+}
+
+
+int get_text_id(const char **text, uint *word_len, const char **id)
+{
+ get_word(text, word_len);
+ if (word_len == 0)
+ return 1;
+ *id= *text;
+ return 0;
+}
+
+
+Command *parse_command(Command_factory *factory, const char *text)
+{
+ uint word_len;
+ const char *instance_name;
+ uint instance_name_len;
+ Command *command;
+
+ Token tok1= shift_token(&text, &word_len);
+
+ switch (tok1) {
+ case TOK_START: // fallthrough
+ case TOK_STOP:
+ if (shift_token(&text, &word_len) != TOK_INSTANCE)
+ goto syntax_error;
+ get_word(&text, &word_len);
+ if (word_len == 0)
+ goto syntax_error;
+ instance_name= text;
+ instance_name_len= word_len;
+ text+= word_len;
+ /* it should be the end of command */
+ get_word(&text, &word_len);
+ if (word_len)
+ goto syntax_error;
+
+ command= (tok1 == TOK_START) ? (Command *)
+ factory->new_Start_instance(instance_name, instance_name_len):
+ (Command *)
+ factory->new_Stop_instance(instance_name, instance_name_len);
+ break;
+ case TOK_FLUSH:
+ if (shift_token(&text, &word_len) != TOK_INSTANCES)
+ goto syntax_error;
+
+ get_word(&text, &word_len);
+ if (word_len)
+ goto syntax_error;
+
+ command= factory->new_Flush_instances();
+ break;
+ case TOK_SHOW:
+ switch (shift_token(&text, &word_len)) {
+ case TOK_INSTANCES:
+ get_word(&text, &word_len);
+ if (word_len)
+ goto syntax_error;
+ command= factory->new_Show_instances();
+ break;
+ case TOK_INSTANCE:
+ switch (Token tok2= shift_token(&text, &word_len)) {
+ case TOK_OPTIONS:
+ case TOK_STATUS:
+ get_text_id(&text, &instance_name_len, &instance_name);
+ text+= instance_name_len;
+ get_word(&text, &word_len);
+ if (word_len)
+ goto syntax_error;
+ command= (tok2 == TOK_STATUS) ? (Command *)
+ factory->new_Show_instance_status(instance_name,
+ instance_name_len):
+ (Command *)
+ factory->new_Show_instance_options(instance_name,
+ instance_name_len);
+ break;
+ default:
+ goto syntax_error;
+ }
+ break;
+ default:
+ goto syntax_error;
+ }
+ break;
+ default:
+syntax_error:
+ command= factory->new_Syntax_error();
+ }
+ return command;
+}
+
diff --git a/server-tools/instance-manager/parse.h b/server-tools/instance-manager/parse.h
new file mode 100644
index 00000000000..92519893302
--- /dev/null
+++ b/server-tools/instance-manager/parse.h
@@ -0,0 +1,53 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H
+/* Copyright (C) 2004 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 "factory.h"
+
+Command *parse_command(Command_factory *factory, const char *text);
+
+/* define kinds of the word seek method */
+enum { ALPHANUM= 1, NONSPACE };
+
+/*
+ tries to find next word in the text
+ if found, returns the beginning and puts word length to word_len argument.
+ if not found returns pointer to first non-space or to '\0', word_len == 0
+*/
+
+inline void get_word(const char **text, uint *word_len,
+ int seek_method= ALPHANUM)
+{
+ const char *word_end;
+
+ /* skip space */
+ while (my_isspace(default_charset_info, **text))
+ ++(*text);
+
+ word_end= *text;
+
+ if (seek_method == ALPHANUM)
+ while (my_isalnum(default_charset_info, *word_end))
+ ++word_end;
+ else
+ while (!my_isspace(default_charset_info, *word_end))
+ ++word_end;
+
+ *word_len= word_end - *text;
+}
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */
diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc
new file mode 100644
index 00000000000..77fa40ca352
--- /dev/null
+++ b/server-tools/instance-manager/parse_output.cc
@@ -0,0 +1,101 @@
+/* Copyright (C) 2004 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 "parse.h"
+
+#include <stdio.h>
+#include <my_sys.h>
+#include <string.h>
+
+
+/*
+ Parse output of the given command
+
+ SYNOPSYS
+ parse_output_and_get_value()
+
+ command the command to execue with popen.
+ word the word to look for (usually an option name)
+ result the buffer to store the next word (option value)
+ result_len self-explanatory
+
+ DESCRIPTION
+
+ Parse output of the "command". Find the "word" and return the next one
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+int parse_output_and_get_value(const char *command, const char *word,
+ char *result, size_t result_len)
+{
+ FILE *output;
+ uint wordlen;
+ /* should be enought to store the string from the output */
+ enum { MAX_LINE_LEN= 512 };
+ char linebuf[MAX_LINE_LEN];
+
+ wordlen= strlen(word);
+
+ if (!(output= popen(command, "r")))
+ goto err;
+
+ /*
+ We want fully buffered stream. We also want system to
+ allocate appropriate buffer.
+ */
+ setvbuf(output, NULL, _IOFBF, 0);
+
+ while (fgets(linebuf, sizeof(linebuf) - 1, output))
+ {
+ uint lineword_len= 0;
+ char *linep= linebuf;
+
+ linebuf[sizeof(linebuf) - 1]= '\0'; /* safety */
+
+ /*
+ Get the word, which might contain non-alphanumeric characters. (Usually
+ these are '/', '-' and '.' in the path expressions and filenames)
+ */
+ get_word((const char **) &linep, &lineword_len, NONSPACE);
+ if (!strncmp(word, linep, wordlen))
+ {
+ /*
+ If we have found the word, return the next one. This is usually
+ an option value.
+ */
+ linep+= lineword_len; /* swallow the previous one */
+ get_word((const char **) &linep, &lineword_len, NONSPACE);
+ if (result_len <= lineword_len)
+ goto err;
+ strncpy(result, linep, lineword_len);
+ result[lineword_len]= '\0';
+ goto pclose;
+ }
+ }
+
+pclose:
+ /* we are not interested in the termination status */
+ pclose(output);
+
+ return 0;
+
+err:
+ return 1;
+}
diff --git a/ndb/include/ndb_types.h b/server-tools/instance-manager/parse_output.h
index 6cf9bb40d7f..20503a74629 100644
--- a/ndb/include/ndb_types.h
+++ b/server-tools/instance-manager/parse_output.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 MySQL AB
+/* Copyright (C) 2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,13 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/**
- * @file ndb_types.h
- */
+int parse_output_and_get_value(const char *command, const char *word,
+ char *result, size_t result_len);
-#ifndef NDB_TYPES_H
-#define NDB_TYPES_H
-
-#include "ndb_global.h"
-
-#endif
diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc
new file mode 100644
index 00000000000..dd192370aaf
--- /dev/null
+++ b/server-tools/instance-manager/priv.cc
@@ -0,0 +1,52 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "priv.h"
+
+/* the pid of the manager process (of the signal thread on the LinuxThreads) */
+pid_t manager_pid;
+
+/*
+ This flag is set if mysqlmanager has detected that it is running on the
+ system using LinuxThreads
+*/
+bool linuxthreads;
+
+/*
+ The following string must be less then 80 characters, as
+ mysql_connection.cc relies on it
+*/
+const char mysqlmanager_version[] = "0.2-alpha";
+
+const int mysqlmanager_version_length= sizeof(mysqlmanager_version) - 1;
+
+const unsigned char protocol_version= PROTOCOL_VERSION;
+
+unsigned long net_buffer_length= 16384;
+
+unsigned long max_allowed_packet= 16384;
+
+unsigned long net_read_timeout= 30; // same as in mysqld
+
+unsigned long net_write_timeout= 60; // same as in mysqld
+
+unsigned long net_retry_count= 10; // same as in mysqld
+
+/* needed by net_serv.cc */
+unsigned int test_flags= 0;
+unsigned long bytes_sent = 0L, bytes_received = 0L;
+unsigned long mysqld_net_retry_count = 10L;
+unsigned long open_files_limit;
diff --git a/server-tools/instance-manager/priv.h b/server-tools/instance-manager/priv.h
new file mode 100644
index 00000000000..decc3605dff
--- /dev/null
+++ b/server-tools/instance-manager/priv.h
@@ -0,0 +1,77 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+
+/* the pid of the manager process (of the signal thread on the LinuxThreads) */
+extern pid_t manager_pid;
+
+/*
+ This flag is set if mysqlmanager has detected that it is running on the
+ system using LinuxThreads
+*/
+extern bool linuxthreads;
+
+extern const char mysqlmanager_version[];
+extern const int mysqlmanager_version_length;
+
+/* MySQL client-server protocol version: substituted from configure */
+extern const unsigned char protocol_version;
+
+/*
+ These variables are used in MySQL subsystem to work with mysql clients
+ To be moved to a config file/options one day.
+*/
+
+
+/* Buffer length for TCP/IP and socket communication */
+extern unsigned long net_buffer_length;
+
+
+/* Maximum allowed incoming/ougoung packet length */
+extern unsigned long max_allowed_packet;
+
+
+/*
+ Number of seconds to wait for more data from a connection before aborting
+ the read
+*/
+extern unsigned long net_read_timeout;
+
+
+/*
+ Number of seconds to wait for a block to be written to a connection
+ before aborting the write.
+*/
+extern unsigned long net_write_timeout;
+
+
+/*
+ If a read on a communication port is interrupted, retry this many times
+ before giving up.
+*/
+extern unsigned long net_retry_count;
+
+extern unsigned int test_flags;
+extern unsigned long bytes_sent, bytes_received;
+extern unsigned long mysqld_net_retry_count;
+extern unsigned long open_files_limit;
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc
new file mode 100644
index 00000000000..9c8975a78be
--- /dev/null
+++ b/server-tools/instance-manager/protocol.cc
@@ -0,0 +1,180 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "protocol.h"
+
+#include "messages.h"
+
+#include <mysql_com.h>
+#include <m_string.h>
+
+
+static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */
+
+int net_send_ok(struct st_net *net, unsigned long connection_id)
+{
+ char buff[1 + // packet type code
+ 9 + // affected rows count
+ 9 + // connection id
+ 2 + // thread return status
+ 2]; // warning count
+
+ char *pos= buff;
+ enum { OK_PACKET_CODE= 0 };
+ *pos++= OK_PACKET_CODE;
+ pos= net_store_length(pos, (ulonglong) 0);
+ pos= net_store_length(pos, (ulonglong) connection_id);
+ int2store(pos, *net->return_status);
+ pos+= 2;
+ /* We don't support warnings, so store 0 for total warning count */
+ int2store(pos, 0);
+ pos+= 2;
+
+ return my_net_write(net, buff, pos - buff) || net_flush(net);
+}
+
+
+int net_send_error(struct st_net *net, uint sql_errno)
+{
+ const char *err= message(sql_errno);
+ char buff[1 + // packet type code
+ 2 + // sql error number
+ 1 + SQLSTATE_LENGTH + // sql state
+ MYSQL_ERRMSG_SIZE]; // message
+ char *pos= buff;
+
+ enum { ERROR_PACKET_CODE= 255 };
+ *pos++= ERROR_PACKET_CODE;
+ int2store(pos, sql_errno);
+ pos+= 2;
+ /* The first # is to make the protocol backward compatible */
+ *pos++= '#';
+ memcpy(pos, errno_to_sqlstate(sql_errno), SQLSTATE_LENGTH);
+ pos+= SQLSTATE_LENGTH;
+ pos= strmake(pos, err, MYSQL_ERRMSG_SIZE - 1) + 1;
+ return my_net_write(net, buff, pos - buff) || net_flush(net);
+}
+
+
+int net_send_error_323(struct st_net *net, uint sql_errno)
+{
+ const char *err= message(sql_errno);
+ char buff[1 + // packet type code
+ 2 + // sql error number
+ MYSQL_ERRMSG_SIZE]; // message
+ char *pos= buff;
+
+ enum { ERROR_PACKET_CODE= 255 };
+ *pos++= ERROR_PACKET_CODE;
+ int2store(pos, sql_errno);
+ pos+= 2;
+ pos= strmake(pos, err, MYSQL_ERRMSG_SIZE - 1) + 1;
+ return my_net_write(net, buff, pos - buff) || net_flush(net);
+}
+
+char *net_store_length(char *pkg, uint length)
+{
+ uchar *packet=(uchar*) pkg;
+ if (length < 251)
+ {
+ *packet=(uchar) length;
+ return (char*) packet+1;
+ }
+ *packet++=252;
+ int2store(packet,(uint) length);
+ return (char*) packet+2;
+}
+
+
+int store_to_string(Buffer *buf, const char *string, uint *position)
+{
+ uint currpos;
+ uint string_len;
+
+ string_len= strlen(string);
+ if (buf->reserve(*position, 2))
+ goto err;
+ currpos= (net_store_length(buf->buffer + *position, string_len) - buf->buffer);
+ if (buf->append(currpos, string, string_len))
+ goto err;
+ *position= *position + string_len + (currpos - *position);
+
+ return 0;
+err:
+ return 1;
+}
+
+
+int send_eof(struct st_net *net)
+{
+ char buff[1 + /* eof packet code */
+ 2 + /* warning count */
+ 2]; /* server status */
+
+ buff[0]=254;
+ int2store(buff+1, 0);
+ int2store(buff+3, 0);
+ return my_net_write(net, buff, sizeof buff);
+}
+
+int send_fields(struct st_net *net, LIST *fields)
+{
+ LIST *tmp= fields;
+ Buffer send_buff;
+ char small_buff[4];
+ uint position= 0;
+ NAME_WITH_LENGTH *field;
+
+ /* send the number of fileds */
+ net_store_length(small_buff, (uint) list_length(fields));
+ if (my_net_write(net, small_buff, (uint) 1))
+ goto err;
+
+ while (tmp)
+ {
+ position= 0;
+ field= (NAME_WITH_LENGTH *) tmp->data;
+
+ store_to_string(&send_buff, (char *) "", &position); /* catalog name */
+ store_to_string(&send_buff, (char *) "", &position); /* db name */
+ store_to_string(&send_buff, (char *) "", &position); /* table name */
+ store_to_string(&send_buff, (char *) "", &position); /* table name alias */
+ store_to_string(&send_buff, field->name, &position); /* column name */
+ store_to_string(&send_buff, field->name, &position); /* column name alias */
+ send_buff.reserve(position, 12);
+ if (send_buff.is_error())
+ goto err;
+ send_buff.buffer[position++]= 12;
+ int2store(send_buff.buffer + position, 1); /* charsetnr */
+ int4store(send_buff.buffer + position + 2, field->length); /* field length */
+ send_buff.buffer[position+6]= FIELD_TYPE_STRING; /* type */
+ int2store(send_buff.buffer + position + 7, 0); /* flags */
+ send_buff.buffer[position + 9]= (char) 0; /* decimals */
+ send_buff.buffer[position + 10]= 0;
+ send_buff.buffer[position + 11]= 0;
+ position+= 12;
+ if (my_net_write(net, send_buff.buffer, (uint) position+1))
+ goto err;
+ tmp= rest(tmp);
+ }
+
+ if (my_net_write(net, eof_buff, 1))
+ goto err;
+ return 0;
+
+err:
+ return 1;
+}
diff --git a/server-tools/instance-manager/protocol.h b/server-tools/instance-manager/protocol.h
new file mode 100644
index 00000000000..b7b18b4b76c
--- /dev/null
+++ b/server-tools/instance-manager/protocol.h
@@ -0,0 +1,44 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "buffer.h"
+
+#include <my_list.h>
+
+typedef struct field {
+ char *name;
+ uint length;
+} NAME_WITH_LENGTH;
+
+struct st_net;
+
+int net_send_ok(struct st_net *net, unsigned long connection_id);
+
+int net_send_error(struct st_net *net, unsigned sql_errno);
+
+int net_send_error_323(struct st_net *net, unsigned sql_errno);
+
+int send_fields(struct st_net *net, LIST *fields);
+
+char *net_store_length(char *pkg, uint length);
+
+int store_to_string(Buffer *buf, const char *string, uint *position);
+
+int send_eof(struct st_net *net);
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H */
diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc
new file mode 100644
index 00000000000..16821df4146
--- /dev/null
+++ b/server-tools/instance-manager/thread_registry.cc
@@ -0,0 +1,209 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "thread_registry.h"
+
+#include "log.h"
+
+#include <assert.h>
+#include <signal.h>
+#include <thr_alarm.h>
+
+
+/* Kick-off signal handler */
+
+enum { THREAD_KICK_OFF_SIGNAL= SIGUSR2 };
+
+static void handle_signal(int __attribute__((unused)) sig_no)
+{
+}
+
+
+/*
+ TODO: think about moving signal information (now it's shutdown_in_progress)
+ to Thread_info. It will reduce contention and allow signal deliverence to
+ a particular thread, not to the whole worker crew
+*/
+
+Thread_registry::Thread_registry() :
+ shutdown_in_progress(false)
+ ,sigwait_thread_pid(pthread_self())
+{
+ pthread_mutex_init(&LOCK_thread_registry, 0);
+ pthread_cond_init(&COND_thread_registry_is_empty, 0);
+
+ /* head is used by-value to simplify nodes inserting */
+ head.next= head.prev= &head;
+}
+
+
+Thread_registry::~Thread_registry()
+{
+ /* Check that no one uses the repository. */
+ pthread_mutex_lock(&LOCK_thread_registry);
+
+ /* All threads must unregister */
+ DBUG_ASSERT(head.next == &head);
+
+ pthread_mutex_unlock(&LOCK_thread_registry);
+ pthread_cond_destroy(&COND_thread_registry_is_empty);
+ pthread_mutex_destroy(&LOCK_thread_registry);
+}
+
+
+/*
+ Set signal handler for kick-off thread, and insert a thread info to the
+ repository. New node is appended to the end of the list; head.prev always
+ points to the last node.
+*/
+
+void Thread_registry::register_thread(Thread_info *info)
+{
+ struct sigaction sa;
+ sa.sa_handler= handle_signal;
+ sa.sa_flags= 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(THREAD_KICK_OFF_SIGNAL, &sa, 0);
+
+ info->current_cond= 0;
+
+ pthread_mutex_lock(&LOCK_thread_registry);
+ info->next= &head;
+ info->prev= head.prev;
+ head.prev->next= info;
+ head.prev= info;
+ pthread_mutex_unlock(&LOCK_thread_registry);
+}
+
+
+/*
+ Unregister a thread from the repository and free Thread_info structure.
+ Every registered thread must unregister. Unregistering should be the last
+ thing a thread is doing, otherwise it could have no time to finalize.
+*/
+
+void Thread_registry::unregister_thread(Thread_info *info)
+{
+ pthread_mutex_lock(&LOCK_thread_registry);
+ info->prev->next= info->next;
+ info->next->prev= info->prev;
+ if (head.next == &head)
+ pthread_cond_signal(&COND_thread_registry_is_empty);
+ pthread_mutex_unlock(&LOCK_thread_registry);
+}
+
+
+/*
+ Check whether shutdown is in progress, and if yes, return immediately.
+ Else set info->current_cond and call pthread_cond_wait. When
+ pthread_cond_wait returns, unregister current cond and check the shutdown
+ status again.
+ RETURN VALUE
+ return value from pthread_cond_wait
+*/
+
+int Thread_registry::cond_wait(Thread_info *info, pthread_cond_t *cond,
+ pthread_mutex_t *mutex, bool *is_shutdown)
+{
+ pthread_mutex_lock(&LOCK_thread_registry);
+ *is_shutdown= shutdown_in_progress;
+ if (*is_shutdown)
+ {
+ pthread_mutex_unlock(&LOCK_thread_registry);
+ return 0;
+ }
+ info->current_cond= cond;
+ pthread_mutex_unlock(&LOCK_thread_registry);
+ /* sic: race condition here, cond can be signaled in deliver_shutdown */
+ int rc= pthread_cond_wait(cond, mutex);
+ pthread_mutex_lock(&LOCK_thread_registry);
+ info->current_cond= 0;
+ *is_shutdown= shutdown_in_progress;
+ pthread_mutex_unlock(&LOCK_thread_registry);
+ return rc;
+}
+
+
+/*
+ Deliver shutdown message to the workers crew.
+ As it's impossible to avoid all race conditions, signal latecomers
+ again.
+*/
+
+void Thread_registry::deliver_shutdown()
+{
+ Thread_info *info;
+ struct timespec shutdown_time;
+ set_timespec(shutdown_time, 1);
+
+ pthread_mutex_lock(&LOCK_thread_registry);
+ shutdown_in_progress= true;
+
+ /* to stop reading from the network we need to flush alarm queue */
+ end_thr_alarm(0);
+ /*
+ We have to deliver final alarms this way, as the main thread has already
+ stopped alarm processing.
+ */
+ process_alarm(THR_SERVER_ALARM);
+ for (info= head.next; info != &head; info= info->next)
+ {
+ pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL);
+ /*
+ sic: race condition here, the thread may not yet fall into
+ pthread_cond_wait.
+ */
+ if (info->current_cond)
+ pthread_cond_signal(info->current_cond);
+ }
+ /*
+ The common practice is to test predicate before pthread_cond_wait.
+ I don't do that here because the predicate is practically always false
+ before wait - is_shutdown's been just set, and the lock's still not
+ released - the only case when the predicate is false is when no other
+ threads exist.
+ */
+ while (pthread_cond_timedwait(&COND_thread_registry_is_empty,
+ &LOCK_thread_registry,
+ &shutdown_time) != ETIMEDOUT &&
+ head.next != &head)
+ ;
+ /*
+ If previous signals did not reach some threads, they must be sleeping
+ in pthread_cond_wait or in a blocking syscall. Wake them up:
+ every thread shall check signal variables after each syscall/cond_wait,
+ so this time everybody should be informed (presumably each worker can
+ get CPU during shutdown_time.)
+ */
+ for (info= head.next; info != &head; info= info->next)
+ {
+ pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL);
+ if (info->current_cond)
+ pthread_cond_signal(info->current_cond);
+ }
+
+ pthread_mutex_unlock(&LOCK_thread_registry);
+}
+
+
+void Thread_registry::request_shutdown()
+{
+ pthread_kill(sigwait_thread_pid, SIGTERM);
+}
diff --git a/server-tools/instance-manager/thread_registry.h b/server-tools/instance-manager/thread_registry.h
new file mode 100644
index 00000000000..a25c692b77f
--- /dev/null
+++ b/server-tools/instance-manager/thread_registry.h
@@ -0,0 +1,116 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REGISTRY_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REGISTRY_H
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ A multi-threaded application shall nicely work with signals.
+
+ This means it shall, first of all, shut down nicely on ``quit'' signals:
+ stop all running threads, cleanup and exit.
+
+ Note, that a thread can't be shut down nicely if it doesn't want to be.
+ That's why to perform clean shutdown, all threads consituting a process
+ must observe certain rules. Here we use the rules, described in Butenhof
+ book 'Programming with POSIX threads', namely:
+ - all user signals are handled in 'signal thread' in synchronous manner
+ (by means of sigwait). To guarantee that the signal thread is the only who
+ can receive user signals, all threads block them, and signal thread is
+ the only who calls sigwait() with an apporpriate sigmask.
+ To propogate a signal to the workers the signal thread sets
+ a variable, corresponding to the signal. Additionally the signal thread
+ sends each worker an internal signal (by means of pthread_kill) to kick it
+ out from possible blocking syscall, and possibly pthread_cond_signal if
+ some thread is blocked in pthread_cond_[timed]wait.
+ - a worker handles only internal 'kick' signal (the handler does nothing).
+ In case when a syscall returns 'EINTR' the worker checks all
+ signal-related variables and behaves accordingly.
+ Also these variables shall be checked from time to time in long
+ CPU-bounded operations, and before/after pthread_cond_wait. (It's supposed
+ that a worker thread either waits in a syscall/conditional variable, or
+ computes something.)
+ - to guarantee signal deliverence, there should be some kind of feedback,
+ e. g. all workers shall account in the signal thread Thread Repository and
+ unregister from it on exit.
+
+ Configuration reload (on SIGHUP) and thread timeouts/alarms can be handled
+ in manner, similar to ``quit'' signals.
+*/
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <my_global.h>
+#include <my_pthread.h>
+
+
+/*
+ Thread_info - repository entry for each worker thread
+ All entries comprise double-linked list like:
+ 0 -- entry -- entry -- entry - 0
+ Double-linked list is used to unregister threads easy.
+*/
+
+class Thread_info
+{
+ pthread_cond_t *current_cond;
+ Thread_info *prev, *next;
+ pthread_t thread_id;
+ Thread_info() {}
+ friend class Thread_registry;
+public:
+ Thread_info(pthread_t thread_id_arg) : thread_id(thread_id_arg) {}
+};
+
+
+/*
+ Thread_registry - contains handles for each worker thread to deliver
+ signal information to workers.
+*/
+
+class Thread_registry
+{
+public:
+ Thread_registry();
+ ~Thread_registry();
+
+ void register_thread(Thread_info *info);
+ void unregister_thread(Thread_info *info);
+ void deliver_shutdown();
+ void request_shutdown();
+ inline bool is_shutdown();
+ int cond_wait(Thread_info *info, pthread_cond_t *cond,
+ pthread_mutex_t *mutex, bool *is_shutdown);
+private:
+ Thread_info head;
+ bool shutdown_in_progress;
+ pthread_mutex_t LOCK_thread_registry;
+ pthread_cond_t COND_thread_registry_is_empty;
+ pthread_t sigwait_thread_pid;
+};
+
+
+inline bool Thread_registry::is_shutdown()
+{
+ pthread_mutex_lock(&LOCK_thread_registry);
+ bool res= shutdown_in_progress;
+ pthread_mutex_unlock(&LOCK_thread_registry);
+ return res;
+}
+
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REGISTRY_H */
diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc
new file mode 100644
index 00000000000..7cb2cd67d7f
--- /dev/null
+++ b/server-tools/instance-manager/user_map.cc
@@ -0,0 +1,176 @@
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include "user_map.h"
+
+#include <mysql_com.h>
+#include <m_string.h>
+
+#include "log.h"
+
+struct User
+{
+ char user[USERNAME_LENGTH + 1];
+ uint8 user_length;
+ uint8 salt[SCRAMBLE_LENGTH];
+ int init(const char *line);
+};
+
+
+int User::init(const char *line)
+{
+ const char *name_begin, *name_end, *password;
+
+ if (line[0] == '\'' || line[0] == '"')
+ {
+ name_begin= line + 1;
+ name_end= strchr(name_begin, line[0]);
+ if (name_end == 0 || name_end[1] != ':')
+ goto err;
+ password= name_end + 2;
+ }
+ else
+ {
+ name_begin= line;
+ name_end= strchr(name_begin, ':');
+ if (name_end == 0)
+ goto err;
+ password= name_end + 1;
+ }
+ user_length= name_end - name_begin;
+ if (user_length > USERNAME_LENGTH)
+ goto err;
+
+ /* assume that newline characater is present */
+ if (strlen(password) != SCRAMBLED_PASSWORD_CHAR_LENGTH + 1)
+ goto err;
+
+ memcpy(user, name_begin, user_length);
+ user[user_length]= 0;
+ get_salt_from_password(salt, password);
+ log_info("loaded user %s", user);
+
+ return 0;
+err:
+ log_error("error parsing user and password at line %s", line);
+ return 1;
+}
+
+
+C_MODE_START
+
+static byte* get_user_key(const byte* u, uint* len,
+ my_bool __attribute__((unused)) t)
+{
+ const User *user= (const User *) u;
+ *len= user->user_length;
+ return (byte *) user->user;
+}
+
+static void delete_user(void *u)
+{
+ User *user= (User *) u;
+ delete user;
+}
+
+C_MODE_END
+
+
+int User_map::init()
+{
+ enum { START_HASH_SIZE = 16 };
+ if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
+ get_user_key, delete_user, 0))
+ return 1;
+ return 0;
+}
+
+
+User_map::~User_map()
+{
+ hash_free(&hash);
+}
+
+
+/*
+ Load all users from the password file. Must be called once right after
+ construction.
+ In case of failure, puts error message to the log file and returns 1
+*/
+
+int User_map::load(const char *password_file_name)
+{
+ FILE *file;
+ char line[USERNAME_LENGTH + SCRAMBLED_PASSWORD_CHAR_LENGTH +
+ 2 + /* for possible quotes */
+ 1 + /* for ':' */
+ 1 + /* for newline */
+ 1]; /* for trailing zero */
+ User *user;
+ int rc= 1;
+
+ if ((file= my_fopen(password_file_name, O_RDONLY | O_BINARY, MYF(0))) == 0)
+ {
+ /* Probably the password file wasn't specified. Try to leave without it */
+ log_info("[WARNING] can't open password file %s: errno=%d, %s", password_file_name,
+ errno, strerror(errno));
+ return 0;
+ }
+
+ while (fgets(line, sizeof(line), file))
+ {
+ /* skip comments and empty lines */
+ if (line[0] == '#' || line[0] == '\n' &&
+ (line[1] == '\0' || line[1] == '\r'))
+ continue;
+ if ((user= new User) == 0)
+ goto done;
+ if (user->init(line) || my_hash_insert(&hash, (byte *) user))
+ goto err_init_user;
+ }
+ if (feof(file))
+ rc= 0;
+ goto done;
+err_init_user:
+ delete user;
+done:
+ my_fclose(file, MYF(0));
+ return rc;
+}
+
+
+/*
+ Check if user exists and password is correct
+ RETURN VALUE
+ 0 - user found and password OK
+ 1 - password mismatch
+ 2 - user not found
+*/
+
+int User_map::authenticate(const char *user_name, uint length,
+ const char *scrambled_password,
+ const char *scramble) const
+{
+ const User *user= (const User *) hash_search((HASH *) &hash,
+ (byte *) user_name, length);
+ if (user)
+ return check_scramble(scrambled_password, scramble, user->salt);
+ return 2;
+}
diff --git a/isam/changed.c b/server-tools/instance-manager/user_map.h
index b8132538b86..4c86edd93d9 100644
--- a/isam/changed.c
+++ b/server-tools/instance-manager/user_map.h
@@ -1,4 +1,6 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H
+/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,22 +16,31 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Check if somebody has changed table since last check. */
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <my_global.h>
-#include "isamdef.h"
+#include <my_sys.h>
+#include <hash.h>
- /* Return 0 if table isn't changed */
+/*
+ User_map -- all users and passwords
+*/
-int nisam_is_changed(N_INFO *info)
+class User_map
{
- int result;
- DBUG_ENTER("nisam_is_changed");
-#ifndef NO_LOCKING
- if (_nisam_readinfo(info,F_RDLCK,1)) DBUG_RETURN(-1);
- VOID(_nisam_writeinfo(info,0));
-#endif
- result=(int) info->data_changed;
- info->data_changed=0;
- DBUG_PRINT("exit",("result: %d",result));
- DBUG_RETURN(result);
-}
+public:
+ ~User_map();
+
+ int init();
+ int load(const char *password_file_name);
+ int authenticate(const char *user_name, uint length,
+ const char *scrambled_password,
+ const char *scramble) const;
+private:
+ HASH hash;
+};
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H
diff --git a/sql-bench/limits/mysql-4.0.cfg b/sql-bench/limits/mysql-4.0.cfg
index 35bdc9fa842..6a23be36fce 100644
--- a/sql-bench/limits/mysql-4.0.cfg
+++ b/sql-bench/limits/mysql-4.0.cfg
@@ -84,7 +84,7 @@ alter_drop_unique=with drop key # Alter table drop unique
###< alter table crash_q drop constraint u1 restrict
###> execute error: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 'constraint u1 restrict' at line 1
###
- ###< alter table crash_q drop key c1
+ ###< alter table crash_q drop key u1
###> OK
alter_modify_col=yes # Alter table modify column
###< alter table crash_q modify c1 CHAR(20)
@@ -395,7 +395,7 @@ date_format_inresult=iso # Date format in result
###> OK
###
###< select a from crash_me_d
- ###> 2003-08-27
+ ###> 2003-12-24
###< delete from crash_me_d
###> OK
###< insert into crash_me_d values( sysdate() )
@@ -664,14 +664,14 @@ func_extra_add_months=no # Function ADD_MONTHS
###
###<select add_months('1997-01-01',1) from crash_me_d
###> execute failed: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 '('1997-01-01',1) from crash_me_d' at line 1
-func_extra_adddate=no # Function ADDDATE
+func_extra_adddate=yes # Function ADDDATE
###
###<select ADDDATE('2002-12-01',3) from crash_me_d
- ###> execute failed: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 '3) from crash_me_d' at line 1
-func_extra_addtime=no # Function ADDTIME
+ ###>2002-12-04
+func_extra_addtime=yes # Function ADDTIME
###
###<select ADDTIME('20:02:12','00:00:03')
- ###> execute failed: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 '('20:02:12','00:00:03')' at line 1
+ ###>20:02:15
func_extra_alpha=no # Function ALPHA
###
###<select alpha('Aâ',2)
@@ -754,10 +754,10 @@ func_extra_cosh=no # Function COSH
###
###<select cosh(0)
###> execute failed: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 '(0)' at line 1
-func_extra_date=no # Function DATE
+func_extra_date=yes # Function DATE
###
###<select date('1963-08-16') from crash_me_d
- ###> execute failed: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 '('1963-08-16') from crash_me_d' at line 1
+ ###>1963-08-16
func_extra_date_format=yes # Function DATE_FORMAT
###
###<select date_format('1997-01-02 03:04:05','M W D Y y m d h i s w') from crash_me_d
@@ -769,11 +769,11 @@ func_extra_dateadd=no # Function DATEADD
func_extra_datediff=no # Function DATEDIFF
###
###<select datediff(month,'Oct 21 1997','Nov 30 1997') from crash_me_d
- ###> execute failed: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 '(month,'Oct 21 1997','Nov 30 1997') from crash_me_d' at line 1
-func_extra_datediff2arg=no # Function DATEDIFF (2 arg)
+ ###> execute failed: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 ''Nov 30 1997') from crash_me_d' at line 1
+func_extra_datediff2arg=yes # Function DATEDIFF (2 arg)
###
###<select DATEDIFF('2002-12-04','2002-12-01') from crash_me_d
- ###> execute failed: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 '('2002-12-04','2002-12-01') from crash_me_d' at line 1
+ ###>3
func_extra_datename=no # Function DATENAME
###
###<select datename(month,'Nov 30 1997') from crash_me_d
@@ -782,10 +782,10 @@ func_extra_datepart=no # Function DATEPART
###
###<select datepart(month,'July 20 1997') from crash_me_d
###> execute failed: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 '(month,'July 20 1997') from crash_me_d' at line 1
-func_extra_day=no # Function DAY
+func_extra_day=yes # Function DAY
###
###<select DAY('2002-12-01') from crash_me_d
- ###> execute failed: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 '('2002-12-01') from crash_me_d' at line 1
+ ###>1
func_extra_decode=no # Function DECODE
###
###<select DECODE('S-103','T72',1,'S-103',2,'Leopard',3)
@@ -801,7 +801,7 @@ func_extra_elt=yes # Function ELT
func_extra_encrypt=yes # Function ENCRYPT
###
###<select encrypt('hello')
- ###>tHrzZO8Aq1FG6
+ ###>1Wi1s0yzcGqMY
func_extra_expand2arg=no # Function EXPAND
###
###<select expand('abcd',6)
@@ -878,10 +878,10 @@ func_extra_interval=yes # Function INTERVAL
###
###<select interval(55,10,20,30,40,50,60,70,80,90,100)
###>5
-func_extra_last_day=no # Function LAST_DAY
+func_extra_last_day=yes # Function LAST_DAY
###
###<select last_day('1997-04-01') from crash_me_d
- ###> execute failed: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 '('1997-04-01') from crash_me_d' at line 1
+ ###>1997-04-30
func_extra_last_insert_id=yes # Function LAST_INSERT_ID
###
###<select last_insert_id()
@@ -931,14 +931,14 @@ func_extra_ltrim2arg=no # Function LTRIM (2 arg)
###
###<select ltrim('..abcd..','.')
###> execute failed: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
-func_extra_makedate=no # Function MAKEDATE
+func_extra_makedate=yes # Function MAKEDATE
###
###<select MAKEDATE(1963,228) from crash_me_d
- ###> execute failed: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 '(1963,228) from crash_me_d' at line 1
-func_extra_maketime=no # Function MAKETIME
+ ###>1963-08-16
+func_extra_maketime=yes # Function MAKETIME
###
###<select MAKETIME(20,02,12)
- ###> execute failed: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 '(20,02,12)' at line 1
+ ###>20:02:12
func_extra_mapchar=no # Function MAPCHAR
###
###<select mapchar('Aâ')
@@ -947,10 +947,11 @@ func_extra_mdy=no # Function MDY
###
###<select mdy(7,1,1998) from crash_me_d
###> execute failed: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 '(7,1,1998) from crash_me_d' at line 1
-func_extra_microsecond=no # Function MICROSECOND
+func_extra_microsecond=error # Function MICROSECOND
###
###<select MICROSECOND('19630816200212111111')
- ###> execute failed: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 '('19630816200212111111')' at line 1
+ ###>11
+ ###We expected '111111' but got '11'
func_extra_mid=yes # Function SUBSTRING as MID
###
###<select mid('hello',3,2)
@@ -968,7 +969,7 @@ func_extra_noround=no # Function NOROUND
###> execute error: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 '(22.6)' at line 1
func_extra_not=yes # Function NOT in SELECT
###
- ###<select not 0
+ ###<select not false
###>1
func_extra_not_between=yes # Function NOT BETWEEN in SELECT
###
@@ -985,11 +986,11 @@ func_extra_num=no # Function NUM
func_extra_odbc_convert=no # Function ODBC CONVERT
###
###<select convert(5,SQL_CHAR)
- ###> execute failed: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 'SQL_CHAR)' at line 1
+ ###> execute failed: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
func_extra_password=yes # Function PASSWORD
###
###<select password('hello')
- ###>70de51425df9d787
+ ###>*6B4F89A54E2D27ECD7E8DA05B4AB8FD9D1D8B119
func_extra_paste=no # Function PASTE
###
###<select paste('ABCDEFG',3,2,'1234')
@@ -1074,18 +1075,18 @@ func_extra_stuff=no # Function STUFF
###
###<select stuff('abc',2,3,'xyz')
###> execute failed: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 '('abc',2,3,'xyz')' at line 1
-func_extra_subdate=no # Function SUBDATE
+func_extra_subdate=yes # Function SUBDATE
###
###<select SUBDATE('2002-12-04',3) from crash_me_d
- ###> execute failed: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 '3) from crash_me_d' at line 1
-func_extra_substr2arg=no # Function SUBSTR (2 arg)
+ ###>2002-12-01
+func_extra_substr2arg=yes # Function SUBSTR (2 arg)
###
###<select substr('abcd',2)
- ###> execute failed: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 '('abcd',2)' at line 1
-func_extra_substr3arg=no # Function SUBSTR (3 arg)
+ ###>bcd
+func_extra_substr3arg=yes # Function SUBSTR (3 arg)
###
###<select substr('abcd',2,2)
- ###> execute failed: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 '('abcd',2,2)' at line 1
+ ###>bc
func_extra_substrb=no # Function SUBSTRB
###
###<select SUBSTRB('ABCDEFG',5,4.2)
@@ -1094,14 +1095,14 @@ func_extra_substring_index=yes # Function SUBSTRING_INDEX
###
###<select substring_index('www.tcx.se','.',-2)
###>tcx.se
-func_extra_subtime=no # Function SUBTIME
+func_extra_subtime=yes # Function SUBTIME
###
###<select SUBTIME('20:02:15','00:00:03')
- ###> execute failed: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 '('20:02:15','00:00:03')' at line 1
+ ###>20:02:12
func_extra_sysdate=yes # Function SYSDATE
###
###<select sysdate()
- ###>2003-08-27 19:55:21
+ ###>2003-12-24 09:46:11
func_extra_tail=no # Function TAIL
###
###<select tail('ABCDEFG',3)
@@ -1110,22 +1111,23 @@ func_extra_tanh=no # Function TANH
###
###<select tanh(1)
###> execute failed:You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '(1)' at line 1
-func_extra_time=no # Function TIME
+func_extra_time=yes # Function TIME
###
###<select time('20:02:12')
- ###> execute failed: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 '('20:02:12')' at line 1
+ ###>20:02:12
func_extra_time_to_sec=yes # Function TIME_TO_SEC
###
###<select time_to_sec('01:23:21')
###>5001
-func_extra_timediff=no # Function TIMEDIFF
+func_extra_timediff=yes # Function TIMEDIFF
###
###<select TIMEDIFF('20:02:15','20:02:12')
- ###> execute failed: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 '('20:02:15','20:02:12')' at line 1
-func_extra_timestamp=no # Function TIMESTAMP
+ ###>00:00:03
+func_extra_timestamp=error # Function TIMESTAMP
###
###<select timestamp('19630816','00200212')
- ###> execute failed: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 '('19630816','00200212')' at line 1
+ ###>1963-08-16 20:02:12
+ ###We expected '19630816200212000000' but got '1963-08-16 20:02:12'
func_extra_to_days=yes # Function TO_DAYS
###
###<select to_days('1996-01-01') from crash_me_d
@@ -1166,7 +1168,7 @@ func_extra_uid=no # Function UID
func_extra_unix_timestamp=yes # Function UNIX_TIMESTAMP
###
###<select unix_timestamp()
- ###>1062003321
+ ###>1072251971
func_extra_userenv=no # Function USERENV
###
###<select userenv
@@ -1178,15 +1180,15 @@ func_extra_value=no # Function VALUE
func_extra_version=yes # Function VERSION
###
###<select version()
- ###>4.0.15-debug-log
+ ###>5.0.0-alpha-debug-log
func_extra_weekday=yes # Function WEEKDAY
###
###<select weekday('1997-11-29') from crash_me_d
###>5
-func_extra_weekofyear=no # Function WEEKOFYEAR
+func_extra_weekofyear=yes # Function WEEKOFYEAR
###
###<select WEEKOFYEAR('1963-08-16') from crash_me_d
- ###> execute failed: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 '('1963-08-16') from crash_me_d' at line 1
+ ###>33
func_extra_|=yes # Function | (bitwise or)
###
###<select 1 | 2
@@ -1246,11 +1248,11 @@ func_odbc_cot=yes # Function COT
func_odbc_curdate=yes # Function CURDATE
###
###<select curdate()
- ###>2003-08-27
+ ###>2003-12-24
func_odbc_curtime=yes # Function CURTIME
###
###<select curtime()
- ###>19:55:21
+ ###>09:46:11
func_odbc_database=yes # Function DATABASE
###
###<select database()
@@ -1397,7 +1399,7 @@ func_odbc_monthname=yes # Function MONTHNAME
func_odbc_now=yes # Function NOW
###
###<select now()
- ###>2003-08-27 19:55:21
+ ###>2003-12-24 09:46:11
func_odbc_pi=yes # Function PI
###
###<select pi()
@@ -1476,20 +1478,19 @@ func_odbc_tan=yes # Function TAN
###
###<select tan(1)
###>1.557408
-func_odbc_timestampadd=no # Function TIMESTAMPADD
+func_odbc_timestampadd=yes # Function TIMESTAMPADD
###
###<select timestampadd(SQL_TSI_SECOND,1,'1997-01-01 00:00:00')
- ###> execute failed: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 '(SQL_TSI_SECOND,1,'1997-01-01 00:00:00')' at line 1
- ###
- ###<select {fn timestampadd(SQL_TSI_SECOND,1,{ts '1997-01-01 00:00:00'}) }
- ###> execute failed: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 '(SQL_TSI_SECOND,1,{ts '1997-01-01 00:00:00'}) }' at line 1
-func_odbc_timestampdiff=no # Function TIMESTAMPDIFF
+ ###>1997-01-01 00:00:01
+func_odbc_timestampdiff=error # Function TIMESTAMPDIFF
###
###<select timestampdiff(SQL_TSI_SECOND,'1997-01-01 00:00:02', '1997-01-01 00:00:01')
- ###> execute failed: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 '(SQL_TSI_SECOND,'1997-01-01 00:00:02', '1997-01-01 00:00:01')'
+ ###>-1
+ ###We expected '1' but got '-1'
###
###<select {fn timestampdiff(SQL_TSI_SECOND,{ts '1997-01-01 00:00:02'}, {ts '1997-01-01 00:00:01'}) }
- ###> execute failed: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 '(SQL_TSI_SECOND,{ts '1997-01-01 00:00:02'}, {ts '1997-01-01 00:
+ ###>-1
+ ###We expected '1' but got '-1'
func_odbc_truncate=yes # Function TRUNCATE
###
###<select truncate(18.18,-1)
@@ -1556,15 +1557,15 @@ func_sql_concat_as_||=error # Function concatenation with ||
func_sql_current_date=yes # Function CURRENT_DATE
###
###<select current_date
- ###>2003-08-27
+ ###>2003-12-24
func_sql_current_time=yes # Function CURRENT_TIME
###
###<select current_time
- ###>19:55:21
+ ###>09:46:11
func_sql_current_timestamp=yes # Function CURRENT_TIMESTAMP
###
###<select current_timestamp
- ###>2003-08-27 19:55:21
+ ###>2003-12-24 09:46:11
func_sql_current_user=with_parenthesis # CURRENT_USER
###< select CURRENT_USER
###> execute error:Unknown column 'CURRENT_USER' in 'field list'
@@ -1585,11 +1586,11 @@ func_sql_extract_sql=yes # Function EXTRACT
func_sql_localtime=yes # Function LOCALTIME
###
###<select localtime
- ###>2003-08-27 19:55:21
+ ###>2003-12-24 09:46:11
func_sql_localtimestamp=yes # Function LOCALTIMESTAMP
###
###<select localtimestamp
- ###>2003-08-27 19:55:21
+ ###>2003-12-24 09:46:11
func_sql_lower=yes # Function LOWER
###
###<select LOWER('ABC')
@@ -1682,22 +1683,22 @@ func_where_between=yes # Function BETWEEN
###
###<select a from crash_me where 5 between 4 and 6
###>1
-func_where_eq_all=no # Function = ALL
+func_where_eq_all=yes # Function = ALL
###
###<select a from crash_me where b =all (select b from crash_me)
- ###> execute failed: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 'all (select b from crash_me)' at line 1
-func_where_eq_any=no # Function = ANY
+ ###>1
+func_where_eq_any=yes # Function = ANY
###
###<select a from crash_me where b =any (select b from crash_me)
- ###> execute failed: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 '(select b from crash_me)' at line 1
-func_where_eq_some=no # Function = SOME
+ ###>1
+func_where_eq_some=yes # Function = SOME
###
###<select a from crash_me where b =some (select b from crash_me)
- ###> execute failed: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 '(select b from crash_me)' at line 1
-func_where_exists=no # Function EXISTS
+ ###>1
+func_where_exists=yes # Function EXISTS
###
###<select a from crash_me where exists (select * from crash_me)
- ###> execute failed: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 'exists (select * from crash_me)' at line 1
+ ###>1
func_where_in_num=yes # Function IN on numbers
###
###<select a from crash_me where 2 in (3,2,5,9,5,1)
@@ -1726,10 +1727,10 @@ func_where_not_between=yes # Function NOT BETWEEN
###
###<select a from crash_me where 7 not between 4 and 6
###>1
-func_where_not_exists=no # Function NOT EXISTS
+func_where_not_exists=yes # Function NOT EXISTS
###
###<select a from crash_me where not exists (select * from crash_me where a = 2)
- ###> execute failed: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 'exists (select * from crash_me where a = 2)' at line 1
+ ###>1
func_where_not_like=yes # Function NOT LIKE
###
###<select a from crash_me where b not like 'b%'
@@ -1800,10 +1801,10 @@ group_func_extra_stddev=yes # Group function STDDEV
###
###<select stddev(a),a from crash_me group by a
###>0.0000
-group_func_extra_variance=no # Group function VARIANCE
+group_func_extra_variance=yes # Group function VARIANCE
###
###<select variance(a),a from crash_me group by a
- ###> execute failed:You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '(a),a from crash_me group by a' at line 1
+ ###>0.0000
group_func_sql_any=no # Group function ANY
###
###<select any(a),a from crash_me group by a
@@ -1867,13 +1868,9 @@ group_on_unused=yes # Group on unused column
###> OK
###
###As far as all queries returned OK, result is YES
-has_true_false=no # TRUE and FALSE
- ###< select (1=1)=true
- ###> execute error:Unknown column 'true' in 'field list'
+has_true_false=yes # TRUE and FALSE
###< select (1=1)=true
###> OK
- ###< select (1=1)=true
- ###> execute error:Unknown column 'true' in 'field list'
having=yes # Having
###<select a from crash_me group by a having a > 0
###>1
@@ -2013,10 +2010,10 @@ intersect_incompat=no # intersect (incompatible lists)
###> execute error: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 'select * from crash_me2' at line 1
###
###As far as some queries didnt return OK, result is NO
-join_tables=31 # tables in join
+join_tables=61 # tables in join
###We are trying (example with N=5):
###select crash_me.a,t0.a,t1.a,t2.a,t3.a,t4.a from crash_me,crash_me t0,crash_me t1,crash_me t2,crash_me t3,crash_me t4
- ### 32:FAIL 7:OK 19:OK 25:OK 28:OK 30:OK 31:FAIL
+ ### 32:OK 48:OK 56:OK 60:OK 62:FAIL 61:FAIL
left_outer_join=yes # left outer join
###< select crash_me.a from crash_me left join crash_me2 ON crash_me.a=crash_me2.a
###> OK
@@ -2071,32 +2068,32 @@ logical_value=1 # Value of logical operation (1=1)
###>1
max_big_expressions=10 # big expressions
###We are trying (example with N=5):
- ###select 0+(1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+...(14308)
+ ###select 0+(1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+...(14328)
### 50:FAIL 10:OK 30:FAIL 14:FAIL 11:FAIL
-max_char_size=255 # max char() size
+max_char_size=1048543 # max char() size
###We are trying (example with N=5):
###create table crash_q (q char(5))
###insert into crash_q values ('aaaaa')
###select * from crash_q
- ### 524287:FAIL 104858:FAIL 20972:FAIL 4195:FAIL 839:FAIL 168:OK 503:FAIL 235:OK 369:FAIL 262:FAIL 241:OK 251:OK 256:FAIL 252:OK 254:OK 255:OK
+ ### 524287:OK 786431:OK 917503:OK 983039:OK 1015807:OK 1032191:OK 1040383:OK 1044479:OK 1046527:OK 1047551:OK 1048063:OK 1048319:OK 1048447:OK 1048511:OK 1048543:OK 1048559:FAIL 1048546:FAIL 1048544:FAIL
max_column_name=64 # column name length
###We are trying (example with N=5):
###create table crash_q (qaaaaa integer)
###insert into crash_q (qaaaaa) values(1)
###select qaaaaa from crash_q
### 256:FAIL 51:OK 153:FAIL 72:FAIL 55:OK 63:OK 67:FAIL 64:FAIL
-max_columns=3398 # Columns in table
+max_columns=2599 # Columns in table
###We are trying (example with N=5):
###create table crash_q (a integer ,a0 integer,a1 integer,a2 integer,a3 integer,a4 integer)
- ### 4096:FAIL 819:OK 2457:OK 3276:OK 3686:FAIL 3358:OK 3522:FAIL 3391:OK 3456:FAIL 3404:FAIL 3394:OK 3399:FAIL 3395:OK 3397:OK 3398:FAIL
+ ### 4096:FAIL 819:OK 2457:OK 3276:FAIL 2621:FAIL 2490:OK 2555:OK 2588:OK 2604:FAIL 2591:OK 2597:OK 2600:FAIL 2598:OK 2599:FAIL
max_conditions=85660 # OR and AND in WHERE
###We are trying (example with N=5):
###select a from crash_me where a=1 and b='a' or a=0 and b='0' or a=1 and b='1' or a=2 and b='2' or a=3 and b='3' or a=4 and b='4'
### 27592:OK 41389:OK 48287:FAIL 42769:OK 45528:FAIL 43321:FAIL 42880:FAIL 42791:OK 42835:FAIL 42800:OK 42817:OK 42826:OK 42830:OK 42832:FAIL 42831:FAIL
-max_expressions=1450 # simple expressions
+max_expressions=1452 # simple expressions
###We are trying (example with N=5):
###select 1+1+1+1+1+1
- ### 5000:FAIL 1000:OK 3000:FAIL 1400:OK 2200:FAIL 1560:FAIL 1432:OK 1496:FAIL 1445:OK 1470:FAIL 1450:OK 1460:FAIL 1452:FAIL 1451:FAIL
+ ### 5000:FAIL 1000:OK 3000:FAIL 1400:OK 2200:FAIL 1560:FAIL 1432:OK 1496:FAIL 1445:OK 1470:FAIL 1450:OK 1460:FAIL 1452:OK 1456:FAIL 1453:FAIL
max_index=32 # max index
### max_unique_index=32 ,so max_index must be same
### max_unique_index=32 ,so max_index must be same
@@ -2115,6 +2112,7 @@ max_index_part_length=255 # max index part length
###create table crash_q (q char(5) not null,unique(q))
###insert into crash_q (q) values ('aaaaa')
###select q from crash_q
+ ### 524271:FAIL 104854:FAIL 20971:FAIL 4194:FAIL 839:FAIL 168:OK 503:FAIL 235:OK 369:FAIL 262:FAIL 241:OK 251:OK 256:FAIL 252:OK 254:OK 255:OK
max_index_parts=16 # index parts
###We are trying (example with N=5):
###create table crash_q (q0 integer not null,q1 integer not null,q2 integer not null,q3 integer not null,q4 integer not nul...(1263)
@@ -2126,11 +2124,12 @@ max_index_varchar_part_length=255 # index varchar part length
###create table crash_q (q varchar(5) not null,unique(q))
###insert into crash_q (q) values ('aaaaa')
###select q from crash_q
+ ### 524271:FAIL 104854:FAIL 20971:FAIL 4194:FAIL 839:FAIL 168:OK 503:FAIL 235:OK 369:FAIL 262:FAIL 241:OK 251:OK 256:FAIL 252:OK 254:OK 255:OK
max_row_length=65534 # max table row length (without blobs)
###We are trying (example with N=5):
###create table crash_q (q0 char(5) not null)
###insert into crash_q values ('aaaaa')
- ### 433245:FAIL 86649:FAIL 17330:OK 51989:OK 69319:FAIL 55455:OK 62387:OK 65853:FAIL 63080:OK 64466:OK 65159:OK 65506:OK 65679:FAIL 65541:FAIL 65513:OK 65527:OK 65534:OK 65537:FAIL 65535:FAIL
+ ### 331372:FAIL 66275:FAIL 13255:OK 39765:OK 53020:OK 59647:OK 62961:OK 64618:OK 65446:OK 65860:FAIL 65529:OK 65694:FAIL 65562:FAIL 65536:FAIL 65531:OK 65533:OK 65534:OK 65535:FAIL
max_row_length_with_null=65502 # table row length with nulls (without blobs)
###We are trying (example with N=5):
###create table crash_q (q0 char(5) )
@@ -2139,10 +2138,10 @@ max_row_length_with_null=65502 # table row length with nulls (without blobs)
max_select_alias_name=+512 # select alias name length
###We are trying (example with N=5):
###select b as aaaaa from crash_me
-max_stack_expression=1450 # stacked expressions
+max_stack_expression=1452 # stacked expressions
###We are trying (example with N=5):
###select 1+(1+(1+(1+(1+(1)))))
- ### 1000:OK 1500:FAIL 1100:OK 1300:OK 1400:OK 1450:OK 1475:FAIL 1455:FAIL 1451:FAIL
+ ### 1000:OK 1500:FAIL 1100:OK 1300:OK 1400:OK 1450:OK 1475:FAIL 1455:FAIL 1451:OK 1453:FAIL 1452:OK
max_table_alias_name=+512 # table alias name length
###We are trying (example with N=5):
###select aaaaa.b from crash_me aaaaa
@@ -2164,12 +2163,12 @@ max_unique_index=32 # unique indexes
###insert into crash_q (q,q1,q2,q3,q4,q5) values (1,1,1,1,1,1)
###select q from crash_q
### 32:OK 48:FAIL 35:FAIL 33:FAIL
-max_varchar_size=255 # max varchar() size
+max_varchar_size=1048543 # max varchar() size
###We are trying (example with N=5):
###create table crash_q (q varchar(5))
###insert into crash_q values ('aaaaa')
###select * from crash_q
- ### 524287:FAIL 104858:FAIL 20972:FAIL 4195:FAIL 839:FAIL 168:OK 503:FAIL 235:OK 369:FAIL 262:FAIL 241:OK 251:OK 256:FAIL 252:OK 254:OK 255:OK
+ ### 524287:OK 786431:OK 917503:OK 983039:OK 1015807:OK 1032191:OK 1040383:OK 1044479:OK 1046527:OK 1047551:OK 1048063:OK 1048319:OK 1048447:OK 1048511:OK 1048543:OK 1048559:FAIL 1048546:FAIL 1048544:FAIL
minus=no # minus
###< select * from crash_me minus select * from crash_me3
###> execute error: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 'select * from crash_me3' at line 1
@@ -2426,13 +2425,13 @@ psm_functions=no # PSM functions (ANSI SQL)
###< create table crash_q (a int)
###> OK
###< create function crash_func(in a1 int, in b1 int) returns int language sql deterministic contains sql begin return a1 * b1; end
- ###> execute error: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 '(in a1 int, in b1 int) returns int language sql deterministic c
+ ###> execute error: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 'in a1 int, in b1 int) returns int language sql deterministic co
###< insert into crash_q values(crash_func(2,4))
###> execute error:You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '(2,4))' at line 1
###< select a,crash_func(a,2) from crash_q
###> execute error:You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '(a,2) from crash_q' at line 1
###< drop function crash_func cascade
- ###> execute error: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 'cascade' at line 1
+ ###> execute error:Failed to DROP FUNCTION crash_func
###< drop table crash_q
###> OK
###
@@ -2443,7 +2442,7 @@ psm_modules=no # PSM modules (ANSI SQL)
###< create module crash_m declare procedure crash_proc(in a1 int, in b1 int) language sql modifies sql data begin declare c1 int; set c1 = a1 + b1; insert into crash_q(a,b) values (a1,c1); end; declare procedure crash_proc2(INOUT a int, in b int) contains sql set a = b + 10; end module
###> execute error: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 'module crash_m declare procedure crash_proc(in a1 int, in b1 in
###< call crash_proc(1,10)
- ###> execute error: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 'call crash_proc(1,10)' at line 1
+ ###> execute error:PROCEDURE crash_proc does not exist
###< drop module crash_m cascade
###> execute error: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 'module crash_m cascade' at line 1
###< drop table crash_q cascade
@@ -2454,11 +2453,11 @@ psm_procedures=no # PSM procedures (ANSI SQL)
###< create table crash_q (a int,b int)
###> OK
###< create procedure crash_proc(in a1 int, in b1 int) language sql modifies sql data begin declare c1 int; set c1 = a1 + b1; insert into crash_q(a,b) values (a1,c1); end
- ###> execute error: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 'procedure crash_proc(in a1 int, in b1 int) language sql modifie
+ ###> execute error: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 'sql data begin declare c1 int; set c1 = a1 + b1; insert into cr
###< call crash_proc(1,10)
- ###> execute error: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 'call crash_proc(1,10)' at line 1
+ ###> execute error:PROCEDURE crash_proc does not exist
###< drop procedure crash_proc
- ###> execute error: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 'procedure crash_proc' at line 1
+ ###> execute error:Failed to DROP PROCEDURE crash_proc
###< drop table crash_q
###> OK
###
@@ -2502,6 +2501,9 @@ quote_with_"=yes # Allows ' and " as string markers
###> OK
###
###As far as all queries returned OK, result is YES
+recursive_subqueries=+64 # recursive subqueries
+ ###We are trying (example with N=5):
+ ###select a from crash_me where a in (select a from crash_me where a in (select a from crash_me where a in (select a from c...(82)
remember_end_space=no # Remembers end space in char()
###< create table crash_q (a char(10))
###> OK
@@ -2651,13 +2653,13 @@ reserved_word_ansi-92/99_authorization=no # Keyword AUTHORIZATION
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_before=no # Keyword BEFORE
+reserved_word_ansi-92/99_before=yes # Keyword BEFORE
###< create table crash_me10 (BEFORE int not null)
- ###> OK
+ ###> execute error: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 'BEFORE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_begin=no # Keyword BEGIN
###< create table crash_me10 (BEGIN int not null)
###> OK
@@ -2700,13 +2702,13 @@ reserved_word_ansi-92/99_by=yes # Keyword BY
###> execute error:Unknown table 'crash_me10'
###
###As far as some queries didnt return OK, result is YES
-reserved_word_ansi-92/99_call=no # Keyword CALL
+reserved_word_ansi-92/99_call=yes # Keyword CALL
###< create table crash_me10 (CALL int not null)
- ###> OK
+ ###> execute error: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 'CALL int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_cascade=yes # Keyword CASCADE
###< create table crash_me10 (CASCADE int not null)
###> execute error: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 'CASCADE int not null)' at line 1
@@ -2770,13 +2772,13 @@ reserved_word_ansi-92/99_close=no # Keyword CLOSE
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_collate=no # Keyword COLLATE
+reserved_word_ansi-92/99_collate=yes # Keyword COLLATE
###< create table crash_me10 (COLLATE int not null)
- ###> OK
+ ###> execute error: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 'COLLATE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_collation=no # Keyword COLLATION
###< create table crash_me10 (COLLATION int not null)
###> OK
@@ -2812,13 +2814,13 @@ reserved_word_ansi-92/99_connect=no # Keyword CONNECT
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_connection=no # Keyword CONNECTION
+reserved_word_ansi-92/99_connection=yes # Keyword CONNECTION
###< create table crash_me10 (CONNECTION int not null)
- ###> OK
+ ###> execute error: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 'CONNECTION int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_constraint=yes # Keyword CONSTRAINT
###< create table crash_me10 (CONSTRAINT int not null)
###> execute error: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 'int not null)' at line 1
@@ -2833,13 +2835,13 @@ reserved_word_ansi-92/99_constraints=no # Keyword CONSTRAINTS
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_continue=no # Keyword CONTINUE
+reserved_word_ansi-92/99_continue=yes # Keyword CONTINUE
###< create table crash_me10 (CONTINUE int not null)
- ###> OK
+ ###> execute error: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 'CONTINUE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_corresponding=no # Keyword CORRESPONDING
###< create table crash_me10 (CORRESPONDING int not null)
###> OK
@@ -2896,13 +2898,13 @@ reserved_word_ansi-92/99_current_user=no # Keyword CURRENT_USER
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_cursor=no # Keyword CURSOR
+reserved_word_ansi-92/99_cursor=yes # Keyword CURSOR
###< create table crash_me10 (CURSOR int not null)
- ###> OK
+ ###> execute error: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 'CURSOR int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_cycle=no # Keyword CYCLE
###< create table crash_me10 (CYCLE int not null)
###> OK
@@ -2952,13 +2954,13 @@ reserved_word_ansi-92/99_decimal=yes # Keyword DECIMAL
###> execute error:Unknown table 'crash_me10'
###
###As far as some queries didnt return OK, result is YES
-reserved_word_ansi-92/99_declare=no # Keyword DECLARE
+reserved_word_ansi-92/99_declare=yes # Keyword DECLARE
###< create table crash_me10 (DECLARE int not null)
- ###> OK
+ ###> execute error: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 'DECLARE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_default=yes # Keyword DEFAULT
###< create table crash_me10 (DEFAULT int not null)
###> execute error: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 'DEFAULT int not null)' at line 1
@@ -3078,13 +3080,13 @@ reserved_word_ansi-92/99_else=yes # Keyword ELSE
###> execute error:Unknown table 'crash_me10'
###
###As far as some queries didnt return OK, result is YES
-reserved_word_ansi-92/99_elseif=no # Keyword ELSEIF
+reserved_word_ansi-92/99_elseif=yes # Keyword ELSEIF
###< create table crash_me10 (ELSEIF int not null)
- ###> OK
+ ###> execute error: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 'ELSEIF int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_end=no # Keyword END
###< create table crash_me10 (END int not null)
###> OK
@@ -3148,20 +3150,20 @@ reserved_word_ansi-92/99_external=no # Keyword EXTERNAL
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_false=no # Keyword FALSE
+reserved_word_ansi-92/99_false=yes # Keyword FALSE
###< create table crash_me10 (FALSE int not null)
- ###> OK
+ ###> execute error: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 'FALSE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_fetch=no # Keyword FETCH
+ ###As far as some queries didnt return OK, result is YES
+reserved_word_ansi-92/99_fetch=yes # Keyword FETCH
###< create table crash_me10 (FETCH int not null)
- ###> OK
+ ###> execute error: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 'FETCH int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_first=no # Keyword FIRST
###< create table crash_me10 (FIRST int not null)
###> OK
@@ -3190,13 +3192,13 @@ reserved_word_ansi-92/99_foreign=yes # Keyword FOREIGN
###> execute error:Unknown table 'crash_me10'
###
###As far as some queries didnt return OK, result is YES
-reserved_word_ansi-92/99_found=no # Keyword FOUND
+reserved_word_ansi-92/99_found=yes # Keyword FOUND
###< create table crash_me10 (FOUND int not null)
- ###> OK
+ ###> execute error: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 'FOUND int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_from=yes # Keyword FROM
###< create table crash_me10 (FROM int not null)
###> execute error: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 int not null)' at line 1
@@ -3428,13 +3430,13 @@ reserved_word_ansi-92/99_leading=yes # Keyword LEADING
###> execute error:Unknown table 'crash_me10'
###
###As far as some queries didnt return OK, result is YES
-reserved_word_ansi-92/99_leave=no # Keyword LEAVE
+reserved_word_ansi-92/99_leave=yes # Keyword LEAVE
###< create table crash_me10 (LEAVE int not null)
- ###> OK
+ ###> execute error: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 'LEAVE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_left=yes # Keyword LEFT
###< create table crash_me10 (LEFT int not null)
###> execute error: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 'LEFT int not null)' at line 1
@@ -3458,7 +3460,7 @@ reserved_word_ansi-92/99_level=no # Keyword LEVEL
###As far as all queries returned OK, result is NO
reserved_word_ansi-92/99_like=yes # Keyword LIKE
###< create table crash_me10 (LIKE int not null)
- ###> execute error: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 'LIKE int not null)' at line 1
+ ###> execute error: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 'int not null)' at line 1
###< drop table crash_me10
###> execute error:Unknown table 'crash_me10'
###
@@ -3477,13 +3479,13 @@ reserved_word_ansi-92/99_local=no # Keyword LOCAL
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_loop=no # Keyword LOOP
+reserved_word_ansi-92/99_loop=yes # Keyword LOOP
###< create table crash_me10 (LOOP int not null)
- ###> OK
+ ###> execute error: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 'LOOP int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_match=yes # Keyword MATCH
###< create table crash_me10 (MATCH int not null)
###> execute error: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 'MATCH int not null)' at line 1
@@ -3701,13 +3703,13 @@ reserved_word_ansi-92/99_parameters=no # Keyword PARAMETERS
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_partial=yes # Keyword PARTIAL
+reserved_word_ansi-92/99_partial=no # Keyword PARTIAL
###< create table crash_me10 (PARTIAL int not null)
- ###> execute error: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 'PARTIAL int not null)' at line 1
+ ###> OK
###< drop table crash_me10
- ###> execute error:Unknown table 'crash_me10'
+ ###> OK
###
- ###As far as some queries didnt return OK, result is YES
+ ###As far as all queries returned OK, result is NO
reserved_word_ansi-92/99_precision=yes # Keyword PRECISION
###< create table crash_me10 (PRECISION int not null)
###> execute error: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 'PRECISION int not null)' at line 1
@@ -3834,20 +3836,20 @@ reserved_word_ansi-92/99_restrict=yes # Keyword RESTRICT
###> execute error:Unknown table 'crash_me10'
###
###As far as some queries didnt return OK, result is YES
-reserved_word_ansi-92/99_return=no # Keyword RETURN
+reserved_word_ansi-92/99_return=yes # Keyword RETURN
###< create table crash_me10 (RETURN int not null)
- ###> OK
+ ###> execute error: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 'RETURN int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_returns=yes # Keyword RETURNS
+ ###As far as some queries didnt return OK, result is YES
+reserved_word_ansi-92/99_returns=no # Keyword RETURNS
###< create table crash_me10 (RETURNS int not null)
- ###> execute error: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 'RETURNS int not null)' at line 1
+ ###> OK
###< drop table crash_me10
- ###> execute error:Unknown table 'crash_me10'
+ ###> OK
###
- ###As far as some queries didnt return OK, result is YES
+ ###As far as all queries returned OK, result is NO
reserved_word_ansi-92/99_revoke=yes # Keyword REVOKE
###< create table crash_me10 (REVOKE int not null)
###> execute error: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 'REVOKE int not null)' at line 1
@@ -4009,34 +4011,34 @@ reserved_word_ansi-92/99_space=no # Keyword SPACE
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_sql=no # Keyword SQL
+reserved_word_ansi-92/99_sql=yes # Keyword SQL
###< create table crash_me10 (SQL int not null)
- ###> OK
+ ###> execute error: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 'SQL int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_sqlexception=no # Keyword SQLEXCEPTION
+ ###As far as some queries didnt return OK, result is YES
+reserved_word_ansi-92/99_sqlexception=yes # Keyword SQLEXCEPTION
###< create table crash_me10 (SQLEXCEPTION int not null)
- ###> OK
+ ###> execute error: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 'SQLEXCEPTION int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_sqlstate=no # Keyword SQLSTATE
+ ###As far as some queries didnt return OK, result is YES
+reserved_word_ansi-92/99_sqlstate=yes # Keyword SQLSTATE
###< create table crash_me10 (SQLSTATE int not null)
- ###> OK
+ ###> execute error: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 'SQLSTATE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_sqlwarning=no # Keyword SQLWARNING
+ ###As far as some queries didnt return OK, result is YES
+reserved_word_ansi-92/99_sqlwarning=yes # Keyword SQLWARNING
###< create table crash_me10 (SQLWARNING int not null)
- ###> OK
+ ###> execute error: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 'SQLWARNING int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_structure=no # Keyword STRUCTURE
###< create table crash_me10 (STRUCTURE int not null)
###> OK
@@ -4135,13 +4137,13 @@ reserved_word_ansi-92/99_trigger=no # Keyword TRIGGER
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi-92/99_true=no # Keyword TRUE
+reserved_word_ansi-92/99_true=yes # Keyword TRUE
###< create table crash_me10 (TRUE int not null)
- ###> OK
+ ###> execute error: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 'TRUE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_under=no # Keyword UNDER
###< create table crash_me10 (UNDER int not null)
###> OK
@@ -4261,13 +4263,13 @@ reserved_word_ansi-92/99_where=yes # Keyword WHERE
###> execute error:Unknown table 'crash_me10'
###
###As far as some queries didnt return OK, result is YES
-reserved_word_ansi-92/99_while=no # Keyword WHILE
+reserved_word_ansi-92/99_while=yes # Keyword WHILE
###< create table crash_me10 (WHILE int not null)
- ###> OK
+ ###> execute error: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 'WHILE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi-92/99_with=yes # Keyword WITH
###< create table crash_me10 (WITH int not null)
###> execute error: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 'WITH int not null)' at line 1
@@ -4387,13 +4389,13 @@ reserved_word_ansi92_extract=no # Keyword EXTRACT
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi92_insensitive=no # Keyword INSENSITIVE
+reserved_word_ansi92_insensitive=yes # Keyword INSENSITIVE
###< create table crash_me10 (INSENSITIVE int not null)
- ###> OK
+ ###> execute error: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 'INSENSITIVE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi92_lower=no # Keyword LOWER
###< create table crash_me10 (LOWER int not null)
###> OK
@@ -4492,13 +4494,13 @@ reserved_word_ansi92_replace=yes # Keyword REPLACE
###> execute error:Unknown table 'crash_me10'
###
###As far as some queries didnt return OK, result is YES
-reserved_word_ansi92_sensitive=no # Keyword SENSITIVE
+reserved_word_ansi92_sensitive=yes # Keyword SENSITIVE
###< create table crash_me10 (SENSITIVE int not null)
- ###> OK
+ ###> execute error: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 'SENSITIVE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi92_similar=no # Keyword SIMILAR
###< create table crash_me10 (SIMILAR int not null)
###> OK
@@ -4646,13 +4648,13 @@ reserved_word_ansi99_clob=no # Keyword CLOB
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi99_condition=no # Keyword CONDITION
+reserved_word_ansi99_condition=yes # Keyword CONDITION
###< create table crash_me10 (CONDITION int not null)
- ###> OK
+ ###> execute error: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 'CONDITION int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi99_constructor=no # Keyword CONSTRUCTOR
###< create table crash_me10 (CONSTRUCTOR int not null)
###> OK
@@ -4716,13 +4718,13 @@ reserved_word_ansi99_destructor=no # Keyword DESTRUCTOR
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi99_deterministic=no # Keyword DETERMINISTIC
+reserved_word_ansi99_deterministic=yes # Keyword DETERMINISTIC
###< create table crash_me10 (DETERMINISTIC int not null)
- ###> OK
+ ###> execute error: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 'DETERMINISTIC int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi99_do=no # Keyword DO
###< create table crash_me10 (DO int not null)
###> OK
@@ -4744,13 +4746,13 @@ reserved_word_ansi99_every=no # Keyword EVERY
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi99_exit=no # Keyword EXIT
+reserved_word_ansi99_exit=yes # Keyword EXIT
###< create table crash_me10 (EXIT int not null)
- ###> OK
+ ###> execute error: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 'EXIT int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi99_expand=no # Keyword EXPAND
###< create table crash_me10 (EXPAND int not null)
###> OK
@@ -4814,20 +4816,20 @@ reserved_word_ansi99_initialize=no # Keyword INITIALIZE
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi99_inout=no # Keyword INOUT
+reserved_word_ansi99_inout=yes # Keyword INOUT
###< create table crash_me10 (INOUT int not null)
- ###> OK
+ ###> execute error: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 'INOUT int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
-reserved_word_ansi99_iterate=no # Keyword ITERATE
+ ###As far as some queries didnt return OK, result is YES
+reserved_word_ansi99_iterate=yes # Keyword ITERATE
###< create table crash_me10 (ITERATE int not null)
- ###> OK
+ ###> execute error: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 'ITERATE int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi99_large=no # Keyword LARGE
###< create table crash_me10 (LARGE int not null)
###> OK
@@ -4898,13 +4900,13 @@ reserved_word_ansi99_ordinality=no # Keyword ORDINALITY
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi99_out=no # Keyword OUT
+reserved_word_ansi99_out=yes # Keyword OUT
###< create table crash_me10 (OUT int not null)
- ###> OK
+ ###> execute error: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 'OUT int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi99_parameter=no # Keyword PARAMETER
###< create table crash_me10 (PARAMETER int not null)
###> OK
@@ -4961,13 +4963,13 @@ reserved_word_ansi99_redo=no # Keyword REDO
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi99_repeat=no # Keyword REPEAT
+reserved_word_ansi99_repeat=yes # Keyword REPEAT
###< create table crash_me10 (REPEAT int not null)
- ###> OK
+ ###> execute error: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 'REPEAT int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi99_result=no # Keyword RESULT
###< create table crash_me10 (RESULT int not null)
###> OK
@@ -4989,13 +4991,13 @@ reserved_word_ansi99_sets=no # Keyword SETS
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi99_specific=no # Keyword SPECIFIC
+reserved_word_ansi99_specific=yes # Keyword SPECIFIC
###< create table crash_me10 (SPECIFIC int not null)
- ###> OK
+ ###> execute error: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 'SPECIFIC int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi99_specifictype=no # Keyword SPECIFICTYPE
###< create table crash_me10 (SPECIFICTYPE int not null)
###> OK
@@ -5052,13 +5054,13 @@ reserved_word_ansi99_treat=no # Keyword TREAT
###> OK
###
###As far as all queries returned OK, result is NO
-reserved_word_ansi99_undo=no # Keyword UNDO
+reserved_word_ansi99_undo=yes # Keyword UNDO
###< create table crash_me10 (UNDO int not null)
- ###> OK
+ ###> execute error: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 'UNDO int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_ansi99_until=no # Keyword UNTIL
###< create table crash_me10 (UNTIL int not null)
###> OK
@@ -5955,13 +5957,13 @@ reserved_word_extra_soname=yes # Keyword SONAME
###> execute error:Unknown table 'crash_me10'
###
###As far as some queries didnt return OK, result is YES
-reserved_word_extra_spatial=no # Keyword SPATIAL
+reserved_word_extra_spatial=yes # Keyword SPATIAL
###< create table crash_me10 (SPATIAL int not null)
- ###> OK
+ ###> execute error: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 'int not null)' at line 1
###< drop table crash_me10
- ###> OK
+ ###> execute error:Unknown table 'crash_me10'
###
- ###As far as all queries returned OK, result is NO
+ ###As far as some queries didnt return OK, result is YES
reserved_word_extra_sql_big_result=yes # Keyword SQL_BIG_RESULT
###< create table crash_me10 (SQL_BIG_RESULT int not null)
###> execute error: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 'SQL_BIG_RESULT int not null)' at line 1
@@ -6273,13 +6275,16 @@ select_limit3=yes # SELECT with LIMIT # OFFSET #
select_string_size=1048565 # constant string size in SELECT
###We are trying (example with N=5):
###select 'aaaaa'
-select_table_update=no # Update with sub select
+select_table_update=yes # Update with sub select
###< create table crash_q (a integer,b char(10))
###> OK
###< insert into crash_q values(1,'c')
###> OK
###< update crash_q set b= (select b from crash_me where crash_q.a = crash_me.a)
- ###> execute error: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 'select b from crash_me where crash_q.a = crash_me.a)' at line 1
+ ###> OK
+ ###
+ ###<select b from crash_q
+ ###>a
###
###< drop table crash_q
###> OK
@@ -6288,7 +6293,7 @@ select_without_from=yes # SELECT without FROM
###> OK
###
###As far as all queries returned OK, result is YES
-server_version=MySQL 4.0.20 debug/ # server version
+server_version=MySQL 5.0.0 alpha debug log/ # server version
simple_joins=yes # ANSI SQL simple joins
###< select crash_me.a from crash_me, crash_me t0
###> OK
@@ -6383,11 +6388,11 @@ storage_of_float=round # Storage of float values
###
###< drop table crash_q
###> OK
-subqueries=no # subqueries
+subqueries=yes # subqueries
###< select a from crash_me where crash_me.a in (select max(a) from crash_me)
- ###> execute error: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 'select max(a) from crash_me)' at line 1
+ ###> OK
###
- ###As far as some queries didnt return OK, result is NO
+ ###As far as all queries returned OK, result is YES
table_alias=yes # Table alias
###< select b.a from crash_me as b
###> OK
@@ -6455,21 +6460,7 @@ time_format_inresult=iso # Time format in result
###> OK
###
###< select a from crash_me_t
- ###> 19:55:21
- ###< delete from crash_me_t
- ###> OK
- ###< insert into crash_me_t values(CURRENT_TIME)
- ###> OK
- ###
- ###< select a from crash_me_t
- ###> 13:45:04
- ###< delete from crash_me_t
- ###> OK
- ###< insert into crash_me_t values(CURRENT_TIME)
- ###> OK
- ###
- ###< select a from crash_me_t
- ###> 13:47:18
+ ###> 09:46:11
###< delete from crash_me_t
###> OK
transactions=yes # transactions
@@ -6688,13 +6679,13 @@ type_extra_line=no # Type line
###> execute error:Unknown table 'crash_q'
###
###As far as some queries didnt return OK, result is NO
-type_extra_long=no # Type long
+type_extra_long=yes # Type long
###< create table crash_q (q long)
- ###> execute error: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
+ ###> OK
###< drop table crash_q
- ###> execute error:Unknown table 'crash_q'
+ ###> OK
###
- ###As far as some queries didnt return OK, result is NO
+ ###As far as all queries returned OK, result is YES
type_extra_long_raw=no # Type long raw
###< create table crash_q (q long raw)
###> execute error: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 'raw)' at line 1
@@ -6807,20 +6798,20 @@ type_extra_path=no # Type path
###> execute error:Unknown table 'crash_q'
###
###As far as some queries didnt return OK, result is NO
-type_extra_point=no # Type point
+type_extra_point=yes # Type point
###< create table crash_q (q point)
- ###> execute error: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 'point)' at line 1
+ ###> OK
###< drop table crash_q
- ###> execute error:Unknown table 'crash_q'
+ ###> OK
###
- ###As far as some queries didnt return OK, result is NO
-type_extra_polygon=no # Type polygon
+ ###As far as all queries returned OK, result is YES
+type_extra_polygon=yes # Type polygon
###< create table crash_q (q polygon)
- ###> execute error: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 'polygon)' at line 1
+ ###> OK
###< drop table crash_q
- ###> execute error:Unknown table 'crash_q'
+ ###> OK
###
- ###As far as some queries didnt return OK, result is NO
+ ###As far as all queries returned OK, result is YES
type_extra_raw(1_arg)=no # Type raw(1 arg)
###< create table crash_q (q raw(16))
###> execute error: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 'raw(16))' at line 1
@@ -6842,13 +6833,13 @@ type_extra_rowid=no # Type rowid
###> execute error:Unknown table 'crash_q'
###
###As far as some queries didnt return OK, result is NO
-type_extra_serial=no # Type serial
+type_extra_serial=yes # Type serial
###< create table crash_q (q serial)
- ###> execute error: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 'serial)' at line 1
+ ###> OK
###< drop table crash_q
- ###> execute error:Unknown table 'crash_q'
+ ###> OK
###
- ###As far as some queries didnt return OK, result is NO
+ ###As far as all queries returned OK, result is YES
type_extra_set(1_arg)=yes # Type set(1 arg)
###< create table crash_q (q set('red'))
###> OK
@@ -6884,13 +6875,13 @@ type_extra_text=yes # Type text
###> OK
###
###As far as all queries returned OK, result is YES
-type_extra_text(1_arg)=no # Type text(1 arg)
+type_extra_text(1_arg)=yes # Type text(1 arg)
###< create table crash_q (q text(10))
- ###> execute error: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 '(10))' at line 1
+ ###> OK
###< drop table crash_q
- ###> execute error:Unknown table 'crash_q'
+ ###> OK
###
- ###As far as some queries didnt return OK, result is NO
+ ###As far as all queries returned OK, result is YES
type_extra_timespan=no # Type timespan
###< create table crash_q (q timespan)
###> execute error: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 'timespan)' at line 1
@@ -6975,13 +6966,13 @@ type_sql_bit_varying(1_arg)=no # Type bit varying(1 arg)
###> execute error:Unknown table 'crash_q'
###
###As far as some queries didnt return OK, result is NO
-type_sql_boolean=no # Type boolean
+type_sql_boolean=yes # Type boolean
###< create table crash_q (q boolean)
- ###> execute error: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 'boolean)' at line 1
+ ###> OK
###< drop table crash_q
- ###> execute error:Unknown table 'crash_q'
+ ###> OK
###
- ###As far as some queries didnt return OK, result is NO
+ ###As far as all queries returned OK, result is YES
type_sql_char(1_arg)=yes # Type char(1 arg)
###< create table crash_q (q char(1))
###> OK
@@ -7281,12 +7272,12 @@ unique_null_in_create=yes # unique null in create
###> OK
###
###As far as all queries returned OK, result is YES
-value_of_false=not supported # Value of FALSE
+value_of_false=0 # Value of FALSE
###<select FALSE
- ###> execute failed:Unknown column 'FALSE' in 'field list'
-value_of_true=not supported # Value of TRUE
+ ###>0
+value_of_true=1 # Value of TRUE
###<select TRUE
- ###> execute failed:Unknown column 'TRUE' in 'field list'
+ ###>1
views=no # views
###< create view crash_q as select a from crash_me
###> execute error: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 'view crash_q as select a from crash_me' at line 1
diff --git a/sql-common/client.c b/sql-common/client.c
index c25e0e3de8f..59e27e4090a 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -57,7 +57,7 @@
my_bool net_flush(NET *net);
#else /*EMBEDDED_LIBRARY*/
-#define CLI_MYSQL_REAL_CONNECT mysql_real_connect
+#define CLI_MYSQL_REAL_CONNECT STDCALL mysql_real_connect
#endif /*EMBEDDED_LIBRARY*/
#include <my_sys.h>
#include <mysys_err.h>
@@ -98,9 +98,6 @@ my_bool net_flush(NET *net);
# include <sys/un.h>
#endif
-#ifndef INADDR_NONE
-#define INADDR_NONE -1
-#endif
#if defined(MSDOS) || defined(__WIN__)
#define perror(A)
#else
@@ -664,6 +661,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
}
if (mysql->status != MYSQL_STATUS_READY)
{
+ DBUG_PRINT("error",("state: %d", mysql->status));
set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
return 1;
}
@@ -755,7 +753,7 @@ static void cli_flush_use_result(MYSQL *mysql)
{
if (protocol_41(mysql))
{
- char *pos= (char*) mysql->net.read_pos;
+ char *pos= (char*) mysql->net.read_pos + 1;
mysql->warning_count=uint2korr(pos); pos+=2;
mysql->server_status=uint2korr(pos); pos+=2;
}
@@ -892,6 +890,7 @@ static const char *default_options[]=
"replication-probe", "enable-reads-from-master", "repl-parse-query",
"ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
"multi-results", "multi-statements", "multi-queries", "secure-auth",
+ "report-data-truncation",
NullS
};
@@ -1103,6 +1102,9 @@ void mysql_read_default_options(struct st_mysql_options *options,
case 33: /* secure-auth */
options->secure_auth= TRUE;
break;
+ case 34: /* report-data-truncation */
+ options->report_data_truncation= opt_arg ? test(atoi(opt_arg)) : 1;
+ break;
default:
DBUG_PRINT("warning",("unknown option: %s",option[0]));
}
@@ -1447,6 +1449,7 @@ mysql_init(MYSQL *mysql)
#endif
mysql->options.methods_to_use= MYSQL_OPT_GUESS_CONNECTION;
+ mysql->options.report_data_truncation= TRUE; /* default */
return mysql;
}
@@ -1532,7 +1535,8 @@ static MYSQL_METHODS client_methods=
#endif
};
-MYSQL * STDCALL
+
+MYSQL *
CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,ulong client_flag)
@@ -1554,7 +1558,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
#ifdef HAVE_SYS_UN_H
struct sockaddr_un UNIXaddr;
#endif
-
init_sigpipe_variables
DBUG_ENTER("mysql_real_connect");
LINT_INIT(host_info);
@@ -1607,8 +1610,24 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
port=mysql->options.port;
if (!unix_socket)
unix_socket=mysql->options.unix_socket;
+
+ /*
+ By default we don't reconnect because it could silently corrupt data (after
+ reconnection you potentially lose table locks, user variables, session
+ variables (transactions but they are specifically dealt with in
+ mysql_reconnect()).
+ This is a change: < 5.0.3 mysql->reconnect was set to 1 by default.
+ How this change impacts existing apps:
+ - existing apps which relyed on the default will see a behaviour change;
+ they will have to set reconnect=1 after mysql_real_connect().
+ - existing apps which explicitely asked for reconnection (the only way they
+ could do it was by setting mysql.reconnect to 1 after mysql_real_connect())
+ will not see a behaviour change.
+ - existing apps which explicitely asked for no reconnection
+ (mysql.reconnect=0) will not see a behaviour change.
+ */
+ mysql->reconnect= 0;
- mysql->reconnect=1; /* Reconnect as default */
mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
/*
@@ -1663,7 +1682,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
ER(net->last_errno),socket_errno);
goto error;
}
- net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
+ net->vio= vio_new(sock, VIO_TYPE_SOCKET,
+ VIO_LOCALHOST | VIO_BUFFERED_READ);
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX;
strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1);
@@ -1738,7 +1758,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
ER(net->last_errno),socket_errno);
goto error;
}
- net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
+ net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
bzero((char*) &sock_addr,sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
@@ -2189,6 +2209,7 @@ my_bool mysql_reconnect(MYSQL *mysql)
strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
DBUG_RETURN(1);
}
+ tmp_mysql.reconnect= 1;
tmp_mysql.free_me= mysql->free_me;
/*
@@ -2425,8 +2446,6 @@ get_info:
if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
mysql->server_status|= SERVER_STATUS_IN_TRANS;
- mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
-
if (!(fields=(*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,
protocol_41(mysql) ? 7 : 5)))
DBUG_RETURN(1);
@@ -2636,6 +2655,25 @@ mysql_fetch_row(MYSQL_RES *res)
}
+/**************************************************************************
+ Get column lengths of the current row
+ If one uses mysql_use_result, res->lengths contains the length information,
+ else the lengths are calculated from the offset between pointers.
+**************************************************************************/
+
+ulong * STDCALL
+mysql_fetch_lengths(MYSQL_RES *res)
+{
+ MYSQL_ROW column;
+
+ if (!(column=res->current_row))
+ return 0; /* Something is wrong */
+ if (res->data)
+ (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
+ return res->lengths;
+}
+
+
int STDCALL
mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
{
@@ -2704,6 +2742,9 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
case MYSQL_SECURE_AUTH:
mysql->options.secure_auth= *(my_bool *) arg;
break;
+ case MYSQL_REPORT_DATA_TRUNCATION:
+ mysql->options.report_data_truncation= test(*(my_bool *) arg);
+ break;
default:
DBUG_RETURN(1);
}
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 8dd4801b562..1078259f15d 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -47,6 +47,43 @@ uchar days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
static long my_time_zone=0;
+/* Calc days in one year. works with 0 <= year <= 99 */
+
+uint calc_days_in_year(uint year)
+{
+ return ((year & 3) == 0 && (year%100 || (year%400 == 0 && year)) ?
+ 366 : 365);
+}
+
+/*
+ check date.
+
+ SYNOPOSIS
+ bool check_date()
+ time Date to check.
+
+ NOTES
+ Here we assume that year and month is ok !
+ If month is 0 we allow any date. (This only happens if we allow zero
+ date parts in str_to_datetime())
+
+ RETURN
+ 0 ok
+ 1 errro
+*/
+
+bool check_date(MYSQL_TIME *ltime)
+{
+ if (ltime->month && ltime->day > days_in_month[ltime->month-1])
+ {
+ if (ltime->month != 2 || calc_days_in_year(ltime->year) != 366 ||
+ ltime->day != 29)
+ return 1;
+ }
+ return 0;
+}
+
+
/*
Convert a timestamp string to a MYSQL_TIME value.
@@ -58,8 +95,12 @@ static long my_time_zone=0;
flags Bitmap of following items
TIME_FUZZY_DATE Set if we should allow partial dates
TIME_DATETIME_ONLY Set if we only allow full datetimes.
- was_cut Set to 1 if value was cut during conversion or to 0
- otherwise.
+ TIME_NO_ZERO_IN_DATE Don't allow partial dates
+ TIME_NO_ZERO_DATE Don't allow 0000-00-00 date
+ TIME_INVALID_DATES Allow 2000-02-31
+ was_cut 0 Value ok
+ 1 If value was cut during conversion
+ 2 Date part was withing ranges but date was wrong
DESCRIPTION
At least the following formats are recogniced (based on number of digits)
@@ -127,6 +168,8 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
*was_cut= 1;
DBUG_RETURN(MYSQL_TIMESTAMP_NONE);
}
+ if (flags & TIME_NO_ZERO_IN_DATE)
+ flags&= ~TIME_FUZZY_DATE;
is_internal_format= 0;
/* This has to be changed if want to activate different timestamp formats */
@@ -342,11 +385,22 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
if (year_length == 2 && not_zero_date)
l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);
+ if (!not_zero_date && (flags & TIME_NO_ZERO_DATE))
+ {
+ /*
+ We don't set *was_cut here to signal that the problem was a zero date
+ and not an invalid date
+ */
+ goto err;
+ }
+
if (number_of_fields < 3 ||
l_time->year > 9999 || l_time->month > 12 ||
l_time->day > 31 || l_time->hour > 23 ||
l_time->minute > 59 || l_time->second > 59 ||
- (!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 || l_time->day == 0)))
+ (!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 ||
+ l_time->day == 0) &&
+ not_zero_date))
{
/* Only give warning for a zero date if there is some garbage after */
if (!not_zero_date) /* If zero date */
@@ -360,14 +414,19 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
}
}
}
- if (not_zero_date)
- *was_cut= 1;
+ *was_cut= test(not_zero_date);
goto err;
}
l_time->time_type= (number_of_fields <= 3 ?
MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);
+ if (not_zero_date && !(flags & TIME_INVALID_DATES) && check_date(l_time))
+ {
+ *was_cut= 2; /* Not correct date */
+ goto err;
+ }
+
for (; str != end ; str++)
{
if (!my_isspace(&my_charset_latin1,*str))
@@ -812,3 +871,167 @@ int my_TIME_to_str(const MYSQL_TIME *l_time, char *to)
return 0;
}
}
+
+
+/*
+ Convert datetime value specified as number to broken-down TIME
+ representation and form value of DATETIME type as side-effect.
+
+ SYNOPSIS
+ number_to_datetime()
+ nr - datetime value as number
+ time_res - pointer for structure for broken-down representation
+ fuzzy_date - indicates whenever we allow fuzzy dates
+ was_cut - set ot 1 if there was some kind of error during
+ conversion or to 0 if everything was OK.
+
+ DESCRIPTION
+ Convert a datetime value of formats YYMMDD, YYYYMMDD, YYMMDDHHMSS,
+ YYYYMMDDHHMMSS to broken-down TIME representation. Return value in
+ YYYYMMDDHHMMSS format as side-effect.
+
+ This function also checks if datetime value fits in DATETIME range.
+
+ RETURN VALUE
+ Datetime value in YYYYMMDDHHMMSS format.
+ If input value is not valid datetime value then 0 is returned.
+*/
+
+longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res,
+ my_bool fuzzy_date, int *was_cut)
+{
+ long part1,part2;
+
+ *was_cut= 0;
+
+ if (nr == LL(0) || nr >= LL(10000101000000))
+ goto ok;
+ if (nr < 101)
+ goto err;
+ if (nr <= (YY_PART_YEAR-1)*10000L+1231L)
+ {
+ nr= (nr+20000000L)*1000000L; /* YYMMDD, year: 2000-2069 */
+ goto ok;
+ }
+ if (nr < (YY_PART_YEAR)*10000L+101L)
+ goto err;
+ if (nr <= 991231L)
+ {
+ nr= (nr+19000000L)*1000000L; /* YYMMDD, year: 1970-1999 */
+ goto ok;
+ }
+ if (nr < 10000101L)
+ goto err;
+ if (nr <= 99991231L)
+ {
+ nr= nr*1000000L;
+ goto ok;
+ }
+ if (nr < 101000000L)
+ goto err;
+ if (nr <= (YY_PART_YEAR-1)*LL(10000000000)+LL(1231235959))
+ {
+ nr= nr+LL(20000000000000); /* YYMMDDHHMMSS, 2000-2069 */
+ goto ok;
+ }
+ if (nr < YY_PART_YEAR*LL(10000000000)+ LL(101000000))
+ goto err;
+ if (nr <= LL(991231235959))
+ nr= nr+LL(19000000000000); /* YYMMDDHHMMSS, 1970-1999 */
+
+ ok:
+ part1=(long) (nr/LL(1000000));
+ part2=(long) (nr - (longlong) part1*LL(1000000));
+ time_res->year= (int) (part1/10000L); part1%=10000L;
+ time_res->month= (int) part1 / 100;
+ time_res->day= (int) part1 % 100;
+ time_res->hour= (int) (part2/10000L); part2%=10000L;
+ time_res->minute=(int) part2 / 100;
+ time_res->second=(int) part2 % 100;
+
+ if (time_res->year <= 9999 && time_res->month <= 12 &&
+ time_res->day <= 31 && time_res->hour <= 23 &&
+ time_res->minute <= 59 && time_res->second <= 59 &&
+ (fuzzy_date || (time_res->month != 0 && time_res->day != 0) || nr==0))
+ return nr;
+
+ err:
+
+ *was_cut= 1;
+ return LL(0);
+}
+
+
+/* Convert time value to integer in YYYYMMDDHHMMSS format */
+
+ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *time)
+{
+ return ((ulonglong) (time->year * 10000UL +
+ time->month * 100UL +
+ time->day) * ULL(1000000) +
+ (ulonglong) (time->hour * 10000UL +
+ time->minute * 100UL +
+ time->second));
+}
+
+
+/* Convert TIME value to integer in YYYYMMDD format */
+
+ulonglong TIME_to_ulonglong_date(const MYSQL_TIME *time)
+{
+ return (ulonglong) (time->year * 10000UL + time->month * 100UL + time->day);
+}
+
+
+/*
+ Convert TIME value to integer in HHMMSS format.
+ This function doesn't take into account time->day member:
+ it's assumed that days have been converted to hours already.
+*/
+
+ulonglong TIME_to_ulonglong_time(const MYSQL_TIME *time)
+{
+ return (ulonglong) (time->hour * 10000UL +
+ time->minute * 100UL +
+ time->second);
+}
+
+
+/*
+ Convert struct TIME (date and time split into year/month/day/hour/...
+ to a number in format YYYYMMDDHHMMSS (DATETIME),
+ YYYYMMDD (DATE) or HHMMSS (TIME).
+
+ SYNOPSIS
+ TIME_to_ulonglong()
+
+ DESCRIPTION
+ The function is used when we need to convert value of time item
+ to a number if it's used in numeric context, i. e.:
+ SELECT NOW()+1, CURDATE()+0, CURTIMIE()+0;
+ SELECT ?+1;
+
+ NOTE
+ This function doesn't check that given TIME structure members are
+ in valid range. If they are not, return value won't reflect any
+ valid date either.
+*/
+
+ulonglong TIME_to_ulonglong(const MYSQL_TIME *time)
+{
+ switch (time->time_type) {
+ case MYSQL_TIMESTAMP_DATETIME:
+ return TIME_to_ulonglong_datetime(time);
+ case MYSQL_TIMESTAMP_DATE:
+ return TIME_to_ulonglong_date(time);
+ case MYSQL_TIMESTAMP_TIME:
+ return TIME_to_ulonglong_time(time);
+ case MYSQL_TIMESTAMP_NONE:
+ case MYSQL_TIMESTAMP_ERROR:
+ return ULL(0);
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0;
+}
+
diff --git a/sql/Makefile.am b/sql/Makefile.am
index f812bbe72af..b506d2a767b 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -19,18 +19,17 @@
MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
-INCLUDES = @MT_INCLUDES@ @ZLIB_INCLUDES@ \
+INCLUDES = @ZLIB_INCLUDES@ \
@bdb_includes@ @innodb_includes@ @ndbcluster_includes@ \
-I$(top_srcdir)/include -I$(top_srcdir)/regex \
- -I$(srcdir) $(openssl_includes)
+ -I$(srcdir) $(openssl_includes) -I$(top_builddir)/include
WRAPLIBS= @WRAPLIBS@
SUBDIRS = share
libexec_PROGRAMS = mysqld
noinst_PROGRAMS = gen_lex_hash
bin_PROGRAMS = mysql_tzinfo_to_sql
gen_lex_hash_LDFLAGS = @NOINST_LDFLAGS@
-LDADD = @isam_libs@ \
- $(top_builddir)/myisam/libmyisam.a \
+LDADD = $(top_builddir)/myisam/libmyisam.a \
$(top_builddir)/myisammrg/libmyisammrg.a \
$(top_builddir)/heap/libheap.a \
$(top_builddir)/vio/libvio.a \
@@ -50,8 +49,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
mysql_priv.h item_geofunc.h sql_bitmap.h \
procedure.h sql_class.h sql_lex.h sql_list.h \
sql_manager.h sql_map.h sql_string.h unireg.h \
- field.h handler.h mysqld_suffix.h \
- ha_isammrg.h ha_isam.h ha_myisammrg.h\
+ sql_error.h field.h handler.h mysqld_suffix.h \
+ ha_myisammrg.h\
ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \
ha_ndbcluster.h opt_range.h protocol.h \
sql_select.h structs.h table.h sql_udf.h hash_filo.h\
@@ -59,8 +58,12 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
log_event.h sql_repl.h slave.h \
stacktrace.h sql_sort.h sql_cache.h set_var.h \
spatial.h gstream.h client_settings.h tzfile.h \
- tztime.h examples/ha_example.h examples/ha_archive.h \
- examples/ha_tina.h ha_blackhole.h
+ tztime.h my_decimal.h\
+ sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
+ parse_file.h sql_view.h sql_trigger.h \
+ examples/ha_example.h examples/ha_archive.h \
+ examples/ha_tina.h ha_blackhole.h \
+ ha_federated.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -82,17 +85,21 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
records.cc filesort.cc handler.cc \
ha_heap.cc ha_myisam.cc ha_myisammrg.cc \
ha_berkeley.cc ha_innodb.cc \
- ha_isam.cc ha_isammrg.cc ha_ndbcluster.cc \
+ ha_ndbcluster.cc \
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
client.c sql_client.cc mini_client_errors.c pack.c\
stacktrace.c repl_failsafe.h repl_failsafe.cc \
+ sql_olap.cc sql_view.cc \
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
- tztime.cc my_time.c \
+ tztime.cc my_time.c my_decimal.cc\
+ sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
+ sp_cache.cc parse_file.cc sql_trigger.cc \
examples/ha_example.cc examples/ha_archive.cc \
- examples/ha_tina.cc ha_blackhole.cc
+ examples/ha_tina.cc ha_blackhole.cc \
+ ha_federated.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
@@ -107,6 +114,7 @@ DEFS = -DMYSQL_SERVER \
# Don't put lex_hash.h in BUILT_SOURCES as this will give infinite recursion
BUILT_SOURCES = sql_yacc.cc sql_yacc.h
EXTRA_DIST = udf_example.cc $(BUILT_SOURCES)
+DISTCLEANFILES = lex_hash.h
AM_YFLAGS = -d
mysql_tzinfo_to_sql.cc:
@@ -152,8 +160,5 @@ sql_lex.o: lex_hash.h
udf_example.so: udf_example.cc
$(CXXCOMPILE) -shared -o $@ $<
-distclean:
- rm -f lex_hash.h
-
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/sql/derror.cc b/sql/derror.cc
index 09f43d20044..bee818a14c1 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -24,15 +24,43 @@ static bool read_texts(const char *file_name,const char ***point,
uint error_messages);
static void init_myfunc_errs(void);
- /* Read messages from errorfile */
+/*
+ Read messages from errorfile.
+
+ SYNOPSIS
+ init_errmessage()
+
+ DESCRIPTION
+ This function can be called multiple times to reload the messages.
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
bool init_errmessage(void)
{
+ const char **errmsgs;
DBUG_ENTER("init_errmessage");
- if (read_texts(ERRMSG_FILE,&my_errmsg[ERRMAPP],ER_ERROR_MESSAGES))
+ /*
+ Get a pointer to the old error messages pointer array.
+ read_texts() tries to free it.
+ */
+ errmsgs= my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST);
+
+ /* Read messages from file. */
+ if (read_texts(ERRMSG_FILE, &errmsgs, ER_ERROR_LAST - ER_ERROR_FIRST + 1))
DBUG_RETURN(TRUE);
- errmesg=my_errmsg[ERRMAPP]; /* Init global variabel */
+
+ /* Register messages for use with my_error(). */
+ if (my_error_register(errmsgs, ER_ERROR_FIRST, ER_ERROR_LAST))
+ {
+ x_free((gptr) errmsgs);
+ DBUG_RETURN(TRUE);
+ }
+
+ errmesg= errmsgs; /* Init global variabel */
init_myfunc_errs(); /* Init myfunc messages */
DBUG_RETURN(FALSE);
}
@@ -50,7 +78,6 @@ static bool read_texts(const char *file_name,const char ***point,
char name[FN_REFLEN];
const char *buff;
uchar head[32],*pos;
- CHARSET_INFO *cset; // For future
DBUG_ENTER("read_texts");
*point=0; // If something goes wrong
@@ -76,7 +103,7 @@ Please install the latest version of this file.",name);
}
/* TODO: Convert the character set to server system character set */
- if (!(cset= get_charset(head[30],MYF(MY_WME))))
+ if (!get_charset(head[30],MYF(MY_WME)))
{
sql_print_error("Character set #%d is not supported for messagefile '%s'",
(int)head[30],name);
@@ -148,20 +175,20 @@ static void init_myfunc_errs()
init_glob_errs(); /* Initiate english errors */
if (!(specialflag & SPECIAL_ENGLISH))
{
- globerrs[EE_FILENOTFOUND % ERRMOD] = ER(ER_FILE_NOT_FOUND);
- globerrs[EE_CANTCREATEFILE % ERRMOD]= ER(ER_CANT_CREATE_FILE);
- globerrs[EE_READ % ERRMOD] = ER(ER_ERROR_ON_READ);
- globerrs[EE_WRITE % ERRMOD] = ER(ER_ERROR_ON_WRITE);
- globerrs[EE_BADCLOSE % ERRMOD] = ER(ER_ERROR_ON_CLOSE);
- globerrs[EE_OUTOFMEMORY % ERRMOD] = ER(ER_OUTOFMEMORY);
- globerrs[EE_DELETE % ERRMOD] = ER(ER_CANT_DELETE_FILE);
- globerrs[EE_LINK % ERRMOD] = ER(ER_ERROR_ON_RENAME);
- globerrs[EE_EOFERR % ERRMOD] = ER(ER_UNEXPECTED_EOF);
- globerrs[EE_CANTLOCK % ERRMOD] = ER(ER_CANT_LOCK);
- globerrs[EE_DIR % ERRMOD] = ER(ER_CANT_READ_DIR);
- globerrs[EE_STAT % ERRMOD] = ER(ER_CANT_GET_STAT);
- globerrs[EE_GETWD % ERRMOD] = ER(ER_CANT_GET_WD);
- globerrs[EE_SETWD % ERRMOD] = ER(ER_CANT_SET_WD);
- globerrs[EE_DISK_FULL % ERRMOD] = ER(ER_DISK_FULL);
+ EE(EE_FILENOTFOUND) = ER(ER_FILE_NOT_FOUND);
+ EE(EE_CANTCREATEFILE) = ER(ER_CANT_CREATE_FILE);
+ EE(EE_READ) = ER(ER_ERROR_ON_READ);
+ EE(EE_WRITE) = ER(ER_ERROR_ON_WRITE);
+ EE(EE_BADCLOSE) = ER(ER_ERROR_ON_CLOSE);
+ EE(EE_OUTOFMEMORY) = ER(ER_OUTOFMEMORY);
+ EE(EE_DELETE) = ER(ER_CANT_DELETE_FILE);
+ EE(EE_LINK) = ER(ER_ERROR_ON_RENAME);
+ EE(EE_EOFERR) = ER(ER_UNEXPECTED_EOF);
+ EE(EE_CANTLOCK) = ER(ER_CANT_LOCK);
+ EE(EE_DIR) = ER(ER_CANT_READ_DIR);
+ EE(EE_STAT) = ER(ER_CANT_GET_STAT);
+ EE(EE_GETWD) = ER(ER_CANT_GET_WD);
+ EE(EE_SETWD) = ER(ER_CANT_SET_WD);
+ EE(EE_DISK_FULL) = ER(ER_DISK_FULL);
}
}
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc
index bc4af0c7dc7..231031c9834 100644
--- a/sql/examples/ha_archive.cc
+++ b/sql/examples/ha_archive.cc
@@ -22,6 +22,7 @@
#ifdef HAVE_ARCHIVE_DB
#include "ha_archive.h"
+#include <my_dir.h>
/*
First, if you want to understand storage engines you should look at
@@ -134,6 +135,24 @@ static HASH archive_open_tables;
#define DATA_BUFFER_SIZE 2 // Size of the data used in the data file
#define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption
+/* dummy handlerton - only to have something to return from archive_db_init */
+static handlerton archive_hton = {
+ "archive",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* releas savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0 /* rollback_by_xid */
+};
+
+
/*
Used for hash table that tracks open tables.
*/
@@ -153,19 +172,20 @@ static byte* archive_get_key(ARCHIVE_SHARE *share,uint *length,
void
RETURN
- FALSE OK
- TRUE Error
+ &archive_hton OK
+ 0 Error
*/
-bool archive_db_init()
+handlerton *archive_db_init()
{
archive_inited= 1;
VOID(pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST));
- return (hash_init(&archive_open_tables, system_charset_info, 32, 0, 0,
- (hash_get_key) archive_get_key, 0, 0));
+ if (hash_init(&archive_open_tables, system_charset_info, 32, 0, 0,
+ (hash_get_key) archive_get_key, 0, 0))
+ return 0;
+ return &archive_hton;
}
-
/*
Release the archive handler.
@@ -274,8 +294,7 @@ int ha_archive::read_meta_file(File meta_file, ulonglong *rows)
/*
This method writes out the header of a meta file and returns whether or not it was successful.
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. If we determine during
- a read that the file was dirty we will force a rebuild of this 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)
{
@@ -335,6 +354,7 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table)
share->use_count= 0;
share->table_name_length= length;
share->table_name= tmp_name;
+ share->crashed= FALSE;
fn_format(share->data_file_name,table_name,"",ARZ,MY_REPLACE_EXT|MY_UNPACK_FILENAME);
fn_format(meta_file_name,table_name,"",ARM,MY_REPLACE_EXT|MY_UNPACK_FILENAME);
strmov(share->table_name,table_name);
@@ -345,24 +365,15 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table)
if ((share->meta_file= my_open(meta_file_name, O_RDWR, MYF(0))) == -1)
goto error;
- if (read_meta_file(share->meta_file, &share->rows_recorded))
- {
- /*
- The problem here is that for some reason, probably a crash, the meta
- file has been corrupted. So what do we do? Well we try to rebuild it
- ourself. Once that happens, we reread it, but if that fails we just
- call it quits and return an error.
- */
- if (rebuild_meta_file(share->table_name, share->meta_file))
- goto error;
- if (read_meta_file(share->meta_file, &share->rows_recorded))
- goto error;
- }
/*
After we read, we set the file to dirty. When we close, we will do the
- opposite.
+ opposite. If the meta file will not open we assume it is crashed and
+ leave it up to the user to fix.
*/
- (void)write_meta_file(share->meta_file, share->rows_recorded, TRUE);
+ if (read_meta_file(share->meta_file, &share->rows_recorded))
+ share->crashed= TRUE;
+ else
+ (void)write_meta_file(share->meta_file, share->rows_recorded, TRUE);
/*
It is expensive to open and close the data files and since you can't have
@@ -420,11 +431,20 @@ int ha_archive::free_share(ARCHIVE_SHARE *share)
}
-/*
+/*
We just implement one additional file extension.
*/
+static const char *ha_archive_exts[] = {
+ ARZ,
+ ARN,
+ ARM,
+ NullS
+};
+
const char **ha_archive::bas_ext() const
-{ static const char *ext[]= { ARZ, ARN, ARM, NullS }; return ext; }
+{
+ return ha_archive_exts;
+}
/*
@@ -438,7 +458,7 @@ 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(-1);
thr_lock_data_init(&share->lock,&lock,NULL);
if ((archive= gzopen(share->data_file_name, "rb")) == NULL)
@@ -565,31 +585,38 @@ error:
int ha_archive::write_row(byte * buf)
{
z_off_t written;
- Field_blob **field;
+ uint *ptr, *end;
DBUG_ENTER("ha_archive::write_row");
- statistic_increment(ha_write_count,&LOCK_status);
+ 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->reclength);
- DBUG_PRINT("ha_archive::get_row", ("Wrote %d bytes expected %d", written, table->reclength));
- share->dirty= TRUE;
- if (written != table->reclength)
+ written= gzwrite(share->archive_write, buf, table->s->reclength);
+ DBUG_PRINT("ha_archive::write_row", ("Wrote %d bytes expected %d", written, table->s->reclength));
+ if (!delayed_insert || !bulk_insert)
+ share->dirty= TRUE;
+
+ if (written != table->s->reclength)
goto error;
/*
We should probably mark the table as damagaged if the record is written
but the blob fails.
*/
- for (field= table->blob_field ; *field ; field++)
+ for (ptr= table->s->blob_field, end= ptr + table->s->blob_fields ;
+ ptr != end ;
+ ptr++)
{
- char *ptr;
- uint32 size= (*field)->get_length();
+ char *data_ptr;
+ uint32 size= ((Field_blob*) table->field[*ptr])->get_length();
if (size)
{
- (*field)->get_ptr(&ptr);
- written= gzwrite(share->archive_write, ptr, (unsigned)size);
+ ((Field_blob*) table->field[*ptr])->get_ptr(&data_ptr);
+ written= gzwrite(share->archive_write, data_ptr, (unsigned)size);
if (written != size)
goto error;
}
@@ -613,7 +640,9 @@ error:
int ha_archive::rnd_init(bool scan)
{
DBUG_ENTER("ha_archive::rnd_init");
- int read; // gzread() returns int, and we use this to check the header
+
+ if (share->crashed)
+ DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
/* We rewind the file so that we can read from the beginning if scan */
if (scan)
@@ -651,13 +680,13 @@ int ha_archive::rnd_init(bool scan)
int ha_archive::get_row(gzFile file_to_read, byte *buf)
{
int read; // Bytes read, gzread() returns int
+ uint *ptr, *end;
char *last;
size_t total_blob_length= 0;
- Field_blob **field;
DBUG_ENTER("ha_archive::get_row");
- read= gzread(file_to_read, buf, table->reclength);
- DBUG_PRINT("ha_archive::get_row", ("Read %d bytes expected %d", read, table->reclength));
+ read= gzread(file_to_read, buf, table->s->reclength);
+ DBUG_PRINT("ha_archive::get_row", ("Read %d bytes expected %d", read, table->s->reclength));
if (read == Z_STREAM_ERROR)
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
@@ -666,28 +695,35 @@ int ha_archive::get_row(gzFile file_to_read, byte *buf)
if (read == 0)
DBUG_RETURN(HA_ERR_END_OF_FILE);
- /* If the record is the wrong size, the file is probably damaged */
- if ((ulong) read != table->reclength)
- DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+ /*
+ If the record is the wrong size, the file is probably damaged, unless
+ we are dealing with a delayed insert or a bulk insert.
+ */
+ if ((ulong) read != table->s->reclength)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
/* Calculate blob length, we use this for our buffer */
- for (field=table->blob_field; *field ; field++)
- total_blob_length += (*field)->get_length();
+ for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
+ ptr != end ;
+ ptr++)
+ total_blob_length += ((Field_blob*) table->field[*ptr])->get_length();
/* Adjust our row buffer if we need be */
buffer.alloc(total_blob_length);
last= (char *)buffer.ptr();
/* Loop through our blobs and read them */
- for (field=table->blob_field; *field ; field++)
+ for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
+ ptr != end ;
+ ptr++)
{
- size_t size= (*field)->get_length();
+ size_t size= ((Field_blob*) table->field[*ptr])->get_length();
if (size)
{
read= gzread(file_to_read, last, size);
if ((size_t) read != size)
- DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
- (*field)->set_ptr(size, last);
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ ((Field_blob*) table->field[*ptr])->set_ptr(size, last);
last += size;
}
}
@@ -705,11 +741,15 @@ int ha_archive::rnd_next(byte *buf)
int rc;
DBUG_ENTER("ha_archive::rnd_next");
+ if (share->crashed)
+ DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+
if (!scan_rows)
DBUG_RETURN(HA_ERR_END_OF_FILE);
scan_rows--;
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
current_position= gztell(archive);
rc= get_row(archive, buf);
@@ -721,7 +761,7 @@ int ha_archive::rnd_next(byte *buf)
}
-/*
+/*
Thanks to the table flag HA_REC_NOT_IN_SEQ this will be called after
each call to ha_archive::rnd_next() if an ordering of the rows is
needed.
@@ -730,7 +770,7 @@ int ha_archive::rnd_next(byte *buf)
void ha_archive::position(const byte *record)
{
DBUG_ENTER("ha_archive::position");
- ha_store_ptr(ref, ref_length, current_position);
+ my_store_ptr(ref, ref_length, current_position);
DBUG_VOID_RETURN;
}
@@ -745,30 +785,32 @@ void ha_archive::position(const byte *record)
int ha_archive::rnd_pos(byte * buf, byte *pos)
{
DBUG_ENTER("ha_archive::rnd_pos");
- statistic_increment(ha_read_rnd_count,&LOCK_status);
- current_position= ha_get_ptr(pos, ref_length);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
+ current_position= my_get_ptr(pos, ref_length);
z_off_t seek= gzseek(archive, current_position, SEEK_SET);
DBUG_RETURN(get_row(archive, buf));
}
/*
- This method rebuilds the meta file. It does this by walking the datafile and
+ This method repairs the meta file. It does this by walking the datafile and
rewriting the meta file.
*/
-int ha_archive::rebuild_meta_file(char *table_name, File meta_file)
+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 */
+ 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::rebuild_meta_file");
+ DBUG_ENTER("ha_archive::repair");
/*
Open up the meta file to recreate it.
*/
- fn_format(data_file_name, table_name, "", ARZ,
+ 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);
@@ -781,8 +823,8 @@ int ha_archive::rebuild_meta_file(char *table_name, File meta_file)
I know, this malloc'ing memory but this should be a very
rare event.
*/
- if (!(buf= (byte*) my_malloc(table->rec_buff_length > sizeof(ulonglong) +1 ?
- table->rec_buff_length : sizeof(ulonglong) +1 ,
+ 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;
@@ -798,11 +840,19 @@ int ha_archive::rebuild_meta_file(char *table_name, File meta_file)
*/
if (rc == HA_ERR_END_OF_FILE)
{
- (void)write_meta_file(meta_file, rows_recorded, FALSE);
+ 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);
@@ -821,13 +871,14 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
char block[IO_SIZE];
char writer_filename[FN_REFLEN];
+ /* Closing will cause all data waiting to be flushed */
+ gzclose(share->archive_write);
+ share->archive_write= NULL;
+
/* Lets create a file to contain the new data */
fn_format(writer_filename, share->table_name, "", ARN,
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
- /* Closing will cause all data waiting to be flushed, to be flushed */
- gzclose(share->archive_write);
-
if ((reader= gzopen(share->data_file_name, "rb")) == NULL)
DBUG_RETURN(-1);
@@ -845,29 +896,10 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
my_rename(writer_filename,share->data_file_name,MYF(0));
- /*
- We reopen the file in case some IO is waiting to go through.
- In theory the table is closed right after this operation,
- but it is possible for IO to still happen.
- I may be being a bit too paranoid right here.
- */
- if ((share->archive_write= gzopen(share->data_file_name, "ab")) == NULL)
- DBUG_RETURN(errno ? errno : -1);
- share->dirty= FALSE;
-
DBUG_RETURN(0);
}
-/*
- No transactions yet, so this is pretty dull.
-*/
-int ha_archive::external_lock(THD *thd, int lock_type)
-{
- DBUG_ENTER("ha_archive::external_lock");
- DBUG_RETURN(0);
-}
-
/*
Below is an example of how to setup row level locking.
*/
@@ -875,6 +907,11 @@ THR_LOCK_DATA **ha_archive::store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)
{
+ if (lock_type == TL_WRITE_DELAYED)
+ delayed_insert= TRUE;
+ else
+ delayed_insert= FALSE;
+
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
{
/*
@@ -909,97 +946,61 @@ THR_LOCK_DATA **ha_archive::store_lock(THD *thd,
}
-/******************************************************************************
-
- Everything below here is default, please look at ha_example.cc for
- descriptions.
-
- ******************************************************************************/
-
-int ha_archive::update_row(const byte * old_data, byte * new_data)
-{
-
- DBUG_ENTER("ha_archive::update_row");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-
-int ha_archive::delete_row(const byte * buf)
-{
- DBUG_ENTER("ha_archive::delete_row");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-
-int ha_archive::index_read(byte * buf, const byte * key,
- uint key_len __attribute__((unused)),
- enum ha_rkey_function find_flag
- __attribute__((unused)))
-{
- DBUG_ENTER("ha_archive::index_read");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-
-int ha_archive::index_read_idx(byte * buf, uint index, const byte * key,
- uint key_len __attribute__((unused)),
- enum ha_rkey_function find_flag
- __attribute__((unused)))
-{
- DBUG_ENTER("ha_archive::index_read_idx");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-
-
-int ha_archive::index_next(byte * buf)
-{
- DBUG_ENTER("ha_archive::index_next");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-
-int ha_archive::index_prev(byte * buf)
-{
- DBUG_ENTER("ha_archive::index_prev");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-
-int ha_archive::index_first(byte * buf)
-{
- DBUG_ENTER("ha_archive::index_first");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-
-int ha_archive::index_last(byte * buf)
-{
- DBUG_ENTER("ha_archive::index_last");
- DBUG_RETURN(HA_ERR_WRONG_COMMAND);
-}
-
-
+/*
+ Hints for optimizer, see ha_tina for more information
+*/
void ha_archive::info(uint flag)
{
DBUG_ENTER("ha_archive::info");
-
- /* This is a lie, but you don't want the optimizer to see zero or 1 */
+ /*
+ This should be an accurate number now, though bulk and delayed inserts can
+ cause the number to be inaccurate.
+ */
records= share->rows_recorded;
deleted= 0;
+ /* Costs quite a bit more to get all information */
+ if (flag & HA_STATUS_TIME)
+ {
+ MY_STAT file_stat; // Stat information for the data file
+
+ VOID(my_stat(share->data_file_name, &file_stat, MYF(MY_WME)));
+
+ mean_rec_length= table->s->reclength + buffer.alloced_length();
+ data_file_length= file_stat.st_size;
+ create_time= file_stat.st_ctime;
+ update_time= file_stat.st_mtime;
+ max_data_file_length= share->rows_recorded * mean_rec_length;
+ }
+ delete_length= 0;
+ index_file_length=0;
DBUG_VOID_RETURN;
}
-int ha_archive::extra(enum ha_extra_function operation)
-{
- DBUG_ENTER("ha_archive::extra");
- DBUG_RETURN(0);
-}
-int ha_archive::reset(void)
+/*
+ This method tells us that a bulk insert operation is about to occur. We set
+ a flag which will keep write_row from saying that its data is dirty. This in
+ turn will keep selects from causing a sync to occur.
+ Basically, yet another optimizations to keep compression working well.
+*/
+void ha_archive::start_bulk_insert(ha_rows rows)
{
- DBUG_ENTER("ha_archive::reset");
- DBUG_RETURN(0);
+ DBUG_ENTER("ha_archive::start_bulk_insert");
+ bulk_insert= TRUE;
+ DBUG_VOID_RETURN;
}
-ha_rows ha_archive::records_in_range(uint inx, key_range *min_key,
- key_range *max_key)
+
+/*
+ Other side of start_bulk_insert, is end_bulk_insert. Here we turn off the bulk insert
+ flag, and set the share dirty so that the next select will call sync for us.
+*/
+int ha_archive::end_bulk_insert()
{
- DBUG_ENTER("ha_archive::records_in_range ");
- DBUG_RETURN(records); // HA_ERR_WRONG_COMMAND
+ DBUG_ENTER("ha_archive::end_bulk_insert");
+ bulk_insert= FALSE;
+ share->dirty= TRUE;
+ DBUG_RETURN(0);
}
#endif /* HAVE_ARCHIVE_DB */
diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h
index 855d756368d..e2c40c880a4 100644
--- a/sql/examples/ha_archive.h
+++ b/sql/examples/ha_archive.h
@@ -32,10 +32,11 @@ typedef struct st_archive_share {
uint table_name_length,use_count;
pthread_mutex_t mutex;
THR_LOCK lock;
- File meta_file; /* Meta file we use */
- gzFile archive_write; /* Archive file we are working with */
- bool dirty; /* Flag for if a flush should occur */
- ulonglong rows_recorded; /* Number of rows in tables */
+ File meta_file; /* Meta file we use */
+ 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 */
} ARCHIVE_SHARE;
/*
@@ -53,9 +54,11 @@ class ha_archive: public handler
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 */
+ bool delayed_insert; /* If the insert is delayed */
+ bool bulk_insert; /* If we are performing a bulk insert */
public:
- ha_archive(TABLE *table): handler(table)
+ ha_archive(TABLE *table): handler(table), delayed_insert(0), bulk_insert(0)
{
/* Set our original buffer from pre-allocated memory */
buffer.set(byte_buffer, IO_SIZE, system_charset_info);
@@ -72,37 +75,15 @@ public:
ulong table_flags() const
{
return (HA_REC_NOT_IN_SEQ | HA_NOT_EXACT_COUNT | HA_NO_AUTO_INCREMENT |
- HA_FILE_BASED);
+ HA_FILE_BASED | HA_CAN_INSERT_DELAYED);
}
ulong index_flags(uint idx, uint part, bool all_parts) const
{
return 0;
}
- /*
- Have to put something here, there is no real limit as far as
- archive is concerned.
- */
- uint max_supported_record_length() const { return UINT_MAX; }
- /*
- Called in test_quick_select to determine if indexes should be used.
- */
- virtual double scan_time() { return (double) (records) / 20.0+10; }
- /* The next method will never be called */
- virtual double read_time(uint index, uint ranges, ha_rows rows)
- { return (double) rows / 20.0+1; }
int open(const char *name, int mode, uint test_if_locked);
int close(void);
int write_row(byte * buf);
- int update_row(const byte * old_data, byte * new_data);
- int delete_row(const byte * buf);
- int index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
- int index_read_idx(byte * buf, uint idx, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
- int index_next(byte * buf);
- int index_prev(byte * buf);
- int index_first(byte * buf);
- int index_last(byte * buf);
int rnd_init(bool scan=1);
int rnd_next(byte *buf);
int rnd_pos(byte * buf, byte *pos);
@@ -111,21 +92,20 @@ public:
int write_meta_file(File meta_file, ulonglong rows, bool dirty);
ARCHIVE_SHARE *get_share(const char *table_name, TABLE *table);
int free_share(ARCHIVE_SHARE *share);
- int rebuild_meta_file(char *table_name, File meta_file);
+ bool auto_repair() const { return 1; } // For the moment we just do this
int read_data_header(gzFile file_to_read);
int write_data_header(gzFile file_to_write);
void position(const byte *record);
void info(uint);
- int extra(enum ha_extra_function operation);
- int reset(void);
- int external_lock(THD *thd, int lock_type);
- ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
+ int repair(THD* thd, HA_CHECK_OPT* check_opt);
+ void start_bulk_insert(ha_rows rows);
+ int end_bulk_insert();
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
};
-bool archive_db_init(void);
+handlerton *archive_db_init(void);
bool archive_db_end(void);
diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc
index cb0780ea74d..562b51878bf 100644
--- a/sql/examples/ha_example.cc
+++ b/sql/examples/ha_example.cc
@@ -186,8 +186,14 @@ static int free_share(EXAMPLE_SHARE *share)
exist for the storage engine. This is also used by the default rename_table and
delete_table method in handler.cc.
*/
+static const char *ha_example_exts[] = {
+ NullS
+};
+
const char **ha_example::bas_ext() const
-{ static const char *ext[]= { NullS }; return ext; }
+{
+ return ha_example_exts;
+}
/*
@@ -414,7 +420,7 @@ int ha_example::rnd_next(byte *buf)
position() is called after each call to rnd_next() if the data needs
to be ordered. You can do something like the following to store
the position:
- ha_store_ptr(ref, ref_length, current_position);
+ my_store_ptr(ref, ref_length, current_position);
The server uses ref to store data. ref_length in the above case is
the size needed to store current_position. ref is just a byte array
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc
index 0345a170c3c..9ac446587ec 100644
--- a/sql/examples/ha_tina.cc
+++ b/sql/examples/ha_tina.cc
@@ -375,7 +375,7 @@ int ha_tina::find_current_row(byte *buf)
}
next_position= (end_ptr - share->mapped_file)+1;
/* Maybe use \N for null? */
- memset(buf, 0, table->null_bytes); /* We do not implement nulls! */
+ memset(buf, 0, table->s->null_bytes); /* We do not implement nulls! */
DBUG_RETURN(0);
}
@@ -384,8 +384,15 @@ int ha_tina::find_current_row(byte *buf)
If frm_error() is called in table.cc this is called to find out what file
extensions exist for this handler.
*/
+static const char *ha_tina_exts[] = {
+ ".CSV",
+ NullS
+};
+
const char **ha_tina::bas_ext() const
-{ static const char *ext[]= { ".CSV", NullS }; return ext; }
+{
+ return ha_tina_exts;
+}
/*
@@ -426,7 +433,7 @@ int ha_tina::write_row(byte * buf)
int size;
DBUG_ENTER("ha_tina::write_row");
- statistic_increment(ha_write_count,&LOCK_status);
+ 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();
@@ -462,7 +469,8 @@ int ha_tina::update_row(const byte * old_data, byte * new_data)
int size;
DBUG_ENTER("ha_tina::update_row");
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
@@ -489,7 +497,7 @@ int ha_tina::update_row(const byte * old_data, byte * new_data)
int ha_tina::delete_row(const byte * buf)
{
DBUG_ENTER("ha_tina::delete_row");
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
if (chain_append())
DBUG_RETURN(-1);
@@ -629,7 +637,8 @@ int ha_tina::rnd_next(byte *buf)
{
DBUG_ENTER("ha_tina::rnd_next");
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
current_position= next_position;
if (!share->mapped_file)
@@ -645,7 +654,7 @@ int ha_tina::rnd_next(byte *buf)
In the case of an order by rows will need to be sorted.
::position() is called after each call to ::rnd_next(),
the data it stores is to a byte array. You can store this
- data via ha_store_ptr(). ref_length is a variable defined to the
+ data via my_store_ptr(). ref_length is a variable defined to the
class that is the sizeof() of position being stored. In our case
its just a position. Look at the bdb code if you want to see a case
where something other then a number is stored.
@@ -653,21 +662,22 @@ int ha_tina::rnd_next(byte *buf)
void ha_tina::position(const byte *record)
{
DBUG_ENTER("ha_tina::position");
- ha_store_ptr(ref, ref_length, current_position);
+ my_store_ptr(ref, ref_length, current_position);
DBUG_VOID_RETURN;
}
/*
Used to fetch a row from a posiion stored with ::position().
- ha_get_ptr() retrieves the data for you.
+ my_get_ptr() retrieves the data for you.
*/
int ha_tina::rnd_pos(byte * buf, byte *pos)
{
DBUG_ENTER("ha_tina::rnd_pos");
- statistic_increment(ha_read_rnd_count,&LOCK_status);
- current_position= ha_get_ptr(pos,ref_length);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
+ current_position= my_get_ptr(pos,ref_length);
DBUG_RETURN(find_current_row(buf));
}
diff --git a/sql/field.cc b/sql/field.cc
index d73257a673f..c59d9b63fca 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -55,9 +55,9 @@ const char field_separator=',';
following #defines describe that gap and how to canculate number of fields
and index of field in thia array.
*/
-#define FIELDTYPE_TEAR_FROM (MYSQL_TYPE_NEWDATE+1)
-#define FIELDTYPE_TEAR_TO (MYSQL_TYPE_ENUM-1)
-#define FIELDTYPE_NUM (FIELDTYPE_TEAR_FROM + (255-FIELDTYPE_TEAR_TO))
+#define FIELDTYPE_TEAR_FROM (MYSQL_TYPE_BIT + 1)
+#define FIELDTYPE_TEAR_TO (MYSQL_TYPE_NEWDECIMAL - 1)
+#define FIELDTYPE_NUM (FIELDTYPE_TEAR_FROM + (255 - FIELDTYPE_TEAR_TO))
inline int field_type2index (enum_field_types field_type)
{
return (field_type < FIELDTYPE_TEAR_FROM ?
@@ -70,118 +70,126 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
/* MYSQL_TYPE_DECIMAL -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_DECIMAL, MYSQL_TYPE_DECIMAL,
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_NEWDECIMAL,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_DECIMAL, MYSQL_TYPE_DECIMAL,
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_NEWDECIMAL,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
MYSQL_TYPE_DOUBLE, MYSQL_TYPE_DOUBLE,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_DECIMAL, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
MYSQL_TYPE_DECIMAL, MYSQL_TYPE_DECIMAL,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_TINY -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_TINY,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_TINY, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_TINY, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
MYSQL_TYPE_LONGLONG, MYSQL_TYPE_INT24,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_SHORT -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_DECIMAL, MYSQL_TYPE_SHORT,
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_SHORT,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_SHORT, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_SHORT, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
MYSQL_TYPE_LONGLONG, MYSQL_TYPE_INT24,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_SHORT,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_SHORT,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_LONG -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_DECIMAL, MYSQL_TYPE_LONG,
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_LONG,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
MYSQL_TYPE_LONG, MYSQL_TYPE_LONG,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
MYSQL_TYPE_DOUBLE, MYSQL_TYPE_DOUBLE,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_LONG, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_LONG, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_LONGLONG, MYSQL_TYPE_LONG,
+ MYSQL_TYPE_LONGLONG, MYSQL_TYPE_INT24,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_LONG,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_LONG,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_FLOAT -> */
{
@@ -192,25 +200,27 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_FLOAT, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_FLOAT, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_DOUBLE, MYSQL_TYPE_FLOAT,
+ MYSQL_TYPE_FLOAT, MYSQL_TYPE_INT24,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_FLOAT,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_FLOAT,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_DOUBLE, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_DOUBLE -> */
{
@@ -221,30 +231,32 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
MYSQL_TYPE_DOUBLE, MYSQL_TYPE_DOUBLE,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_DOUBLE, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_DOUBLE, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_DOUBLE, MYSQL_TYPE_DOUBLE,
+ MYSQL_TYPE_DOUBLE, MYSQL_TYPE_INT24,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_DOUBLE,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_DOUBLE,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_DOUBLE, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_NULL -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_TINY,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
@@ -257,192 +269,206 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_TIME,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_NEWDATE,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_ENUM,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_BIT,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_ENUM,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
MYSQL_TYPE_SET, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
MYSQL_TYPE_STRING, MYSQL_TYPE_GEOMETRY
},
/* MYSQL_TYPE_TIMESTAMP -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_TIMESTAMP,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
MYSQL_TYPE_DATETIME, MYSQL_TYPE_DATETIME,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_DATETIME, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_DATETIME,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_DATETIME, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_LONGLONG -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_DECIMAL, MYSQL_TYPE_LONGLONG,
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_LONGLONG,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
MYSQL_TYPE_LONGLONG, MYSQL_TYPE_LONGLONG,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
MYSQL_TYPE_DOUBLE, MYSQL_TYPE_DOUBLE,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_LONGLONG, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_LONGLONG, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
MYSQL_TYPE_LONGLONG, MYSQL_TYPE_LONG,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_LONGLONG,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_LONGLONG,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_INT24 -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_DECIMAL, MYSQL_TYPE_INT24,
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_INT24,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
MYSQL_TYPE_INT24, MYSQL_TYPE_LONG,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_INT24, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_INT24, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
MYSQL_TYPE_LONGLONG, MYSQL_TYPE_INT24,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_INT24,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_INT24,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_DATE -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_DATETIME,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_DATETIME,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_DATETIME, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_NEWDATE,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_DATETIME, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_TIME -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
MYSQL_TYPE_DATETIME, MYSQL_TYPE_TIME,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_DATETIME, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_DATETIME,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_DATETIME, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_DATETIME -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
MYSQL_TYPE_DATETIME, MYSQL_TYPE_DATETIME,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
MYSQL_TYPE_DATETIME, MYSQL_TYPE_DATETIME,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_DATETIME, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_DATETIME,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_DATETIME, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_YEAR -> */
{
@@ -453,112 +479,213 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_YEAR, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_YEAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
MYSQL_TYPE_LONGLONG, MYSQL_TYPE_INT24,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_YEAR,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_YEAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_NEWDATE -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_DATETIME,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_DATETIME,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_DATETIME, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_NEWDATE,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_DATETIME, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
+ },
+ /* MYSQL_TYPE_VARCHAR -> */
+ {
+ //MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_DATE MYSQL_TYPE_TIME
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
+ //MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
+ MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+ //MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR
+ },
+ /* MYSQL_TYPE_BIT -> */
+ {
+ //MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
+ MYSQL_TYPE_BIT, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_DATE MYSQL_TYPE_TIME
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_BIT,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
+ //MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
+ MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+ //MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
+ },
+ /* MYSQL_TYPE_NEWDECIMAL -> */
+ {
+ //MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_NEWDECIMAL,
+ //MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_NEWDECIMAL,
+ //MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
+ MYSQL_TYPE_DOUBLE, MYSQL_TYPE_DOUBLE,
+ //MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_NEWDECIMAL,
+ //MYSQL_TYPE_DATE MYSQL_TYPE_TIME
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_NEWDECIMAL,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
+ //MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
+ MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
+ //MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_ENUM -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_ENUM, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_ENUM, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_SET -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_SET, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_SET, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_TINY_BLOB -> */
{
@@ -576,10 +703,12 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_TINY_BLOB,
- //MYSQL_TYPE_NEWDATE <14>
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_TINY_BLOB,
+ //MYSQL_TYPE_BIT <16>-<245>
MYSQL_TYPE_TINY_BLOB,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_TINY_BLOB,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
@@ -605,10 +734,12 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
- //MYSQL_TYPE_NEWDATE <14>
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
+ //MYSQL_TYPE_BIT <16>-<245>
MYSQL_TYPE_MEDIUM_BLOB,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_MEDIUM_BLOB,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_MEDIUM_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
@@ -634,10 +765,12 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_LONG_BLOB,
- //MYSQL_TYPE_NEWDATE <14>
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_LONG_BLOB,
+ //MYSQL_TYPE_BIT <16>-<245>
MYSQL_TYPE_LONG_BLOB,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_LONG_BLOB,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
@@ -663,10 +796,12 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
MYSQL_TYPE_BLOB, MYSQL_TYPE_BLOB,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
MYSQL_TYPE_BLOB, MYSQL_TYPE_BLOB,
- //MYSQL_TYPE_NEWDATE <14>
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_BLOB,
+ //MYSQL_TYPE_BIT <16>-<245>
MYSQL_TYPE_BLOB,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_BLOB,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_BLOB,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
MYSQL_TYPE_BLOB, MYSQL_TYPE_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
@@ -679,31 +814,33 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
/* MYSQL_TYPE_VAR_STRING -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR
},
/* MYSQL_TYPE_STRING -> */
{
@@ -721,45 +858,49 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
MYSQL_TYPE_STRING, MYSQL_TYPE_STRING,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
MYSQL_TYPE_STRING, MYSQL_TYPE_STRING,
- //MYSQL_TYPE_NEWDATE <14>
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_STRING, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
MYSQL_TYPE_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_STRING,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_STRING, MYSQL_TYPE_STRING,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
MYSQL_TYPE_STRING, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
MYSQL_TYPE_STRING, MYSQL_TYPE_STRING
},
/* MYSQL_TYPE_GEOMETRY -> */
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP
- MYSQL_TYPE_GEOMETRY, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_GEOMETRY, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATE MYSQL_TYPE_TIME
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING,
- //MYSQL_TYPE_NEWDATE <14>
- MYSQL_TYPE_VAR_STRING,
- //<246> MYSQL_TYPE_ENUM
- MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_BIT <16>-<245>
+ MYSQL_TYPE_VARCHAR,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_TINY_BLOB,
+ MYSQL_TYPE_VARCHAR, MYSQL_TYPE_TINY_BLOB,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB,
//MYSQL_TYPE_BLOB MYSQL_TYPE_VAR_STRING
- MYSQL_TYPE_BLOB, MYSQL_TYPE_VAR_STRING,
+ MYSQL_TYPE_BLOB, MYSQL_TYPE_VARCHAR,
//MYSQL_TYPE_STRING MYSQL_TYPE_GEOMETRY
MYSQL_TYPE_STRING, MYSQL_TYPE_GEOMETRY
}
@@ -789,7 +930,7 @@ enum_field_types Field::field_type_merge(enum_field_types a,
static Item_result field_types_result_type [FIELDTYPE_NUM]=
{
//MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY
- REAL_RESULT, INT_RESULT,
+ DECIMAL_RESULT, INT_RESULT,
//MYSQL_TYPE_SHORT MYSQL_TYPE_LONG
INT_RESULT, INT_RESULT,
//MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE
@@ -802,10 +943,12 @@ static Item_result field_types_result_type [FIELDTYPE_NUM]=
STRING_RESULT, STRING_RESULT,
//MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR
STRING_RESULT, INT_RESULT,
- //MYSQL_TYPE_NEWDATE <14>
+ //MYSQL_TYPE_NEWDATE MYSQL_TYPE_VARCHAR
+ STRING_RESULT, STRING_RESULT,
+ //MYSQL_TYPE_BIT <16>-<245>
STRING_RESULT,
- //<246> MYSQL_TYPE_ENUM
- STRING_RESULT,
+ //MYSQL_TYPE_NEWDECIMAL MYSQL_TYPE_ENUM
+ DECIMAL_RESULT, STRING_RESULT,
//MYSQL_TYPE_SET MYSQL_TYPE_TINY_BLOB
STRING_RESULT, STRING_RESULT,
//MYSQL_TYPE_MEDIUM_BLOB MYSQL_TYPE_LONG_BLOB
@@ -839,6 +982,25 @@ Item_result Field::result_merge_type(enum_field_types field_type)
Static help functions
*****************************************************************************/
+/*
+ Numeric fields base class constructor
+*/
+Field_num::Field_num(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg,
+ uint8 dec_arg, bool zero_arg, bool unsigned_arg)
+ :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg),
+ dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg)
+{
+ if (zerofill)
+ flags|=ZEROFILL_FLAG;
+ if (unsigned_flag)
+ flags|=UNSIGNED_FLAG;
+}
+
+
void Field_num::prepend_zeros(String *value)
{
int diff;
@@ -869,33 +1031,78 @@ void Field_num::prepend_zeros(String *value)
Make this multi-byte-character safe
RETURN
- 0 ok
- 1 error
+ 0 OK
+ 1 error. A warning is pushed if field_name != 0
*/
-bool test_if_int(const char *str, int length, const char *int_end,
- CHARSET_INFO *cs)
+bool Field::check_int(const char *str, int length, const char *int_end,
+ CHARSET_INFO *cs)
{
+ const char *end;
if (str == int_end)
- return 0; // Empty string
- const char *end=str+length;
+ {
+ char buff[128];
+ String tmp(buff,(uint32) sizeof(buff), system_charset_info);
+ tmp.copy(str, length, system_charset_info);
+ push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "integer", tmp.c_ptr(), field_name,
+ (ulong) table->in_use->row_count);
+ return 1; // Empty string
+ }
+ end= str+length;
if ((str= int_end) == end)
- return 1; // All digits was used
+ return 0; // OK; All digits was used
/* Allow end .0000 */
if (*str == '.')
{
- for (str++ ; str != end && *str == '0'; str++) ;
+ for (str++ ; str != end && *str == '0'; str++)
+ ;
}
/* Allow end space */
- for (str++ ; str != end ; str++)
+ for ( ; str != end ; str++)
{
if (!my_isspace(cs,*str))
- return 0;
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+ return 1;
+ }
}
- return 1;
+ return 0;
+}
+
+
+/*
+ Process decimal library return codes and issue warnings for overflow and
+ truncation.
+
+ SYNOPSIS
+ Field::warn_if_overflow()
+ op_result decimal library return code (E_DEC_* see include/decimal.h)
+
+ RETURN
+ 1 there was overflow
+ 0 no error or some other errors except overflow
+*/
+
+int Field::warn_if_overflow(int op_result)
+{
+ if (op_result == E_DEC_OVERFLOW)
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ return 1;
+ }
+ if (op_result == E_DEC_TRUNCATED)
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
+ /* We return 0 here as this is not a critical issue */
+ }
+ return 0;
}
+
#ifdef NOT_USED
static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
{
@@ -951,10 +1158,30 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
#endif
-/****************************************************************************
-** Functions for the base classes
-** This is an unpacked number.
-****************************************************************************/
+/*
+ Interpret field value as an integer but return the result as a string.
+
+ This is used for printing bit_fields as numbers while debugging
+*/
+
+String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_flag)
+{
+ CHARSET_INFO *cs= &my_charset_bin;
+ uint length= 21;
+ longlong value= val_int();
+ if (val_buffer->alloc(length))
+ return 0;
+ length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(),
+ length,
+ unsigned_flag ? 10 : -10,
+ value);
+ val_buffer->length(length);
+ return val_buffer;
+}
+
+
+/* This is used as a table name when the table structure is not set up */
+const char *unknown_table_name= 0;
Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -962,7 +1189,7 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
struct st_table *table_arg)
:ptr(ptr_arg),null_ptr(null_ptr_arg),
table(table_arg),orig_table(table_arg),
- table_name(table_arg ? table_arg->table_name : 0),
+ table_name(table_arg ? &table_arg->alias : &unknown_table_name),
field_name(field_name_arg),
query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0),
unireg_check(unireg_check_arg),
@@ -999,6 +1226,14 @@ bool Field::send_binary(Protocol *protocol)
}
+my_decimal *Field::val_decimal(my_decimal *decimal)
+{
+ /* This never have to be called */
+ DBUG_ASSERT(0);
+ return 0;
+}
+
+
void Field_num::add_zerofill_and_unsigned(String &res) const
{
if (unsigned_flag)
@@ -1007,47 +1242,170 @@ void Field_num::add_zerofill_and_unsigned(String &res) const
res.append(" zerofill");
}
-void Field_num::make_field(Send_field *field)
+
+void Field::make_field(Send_field *field)
{
- /* table_cache_key is not set for temp tables */
- if (orig_table->table_cache_key)
+ if (orig_table->s->table_cache_key && *(orig_table->s->table_cache_key))
{
- field->db_name= orig_table->table_cache_key;
- field->org_table_name= orig_table->real_name;
+ field->org_table_name= orig_table->s->table_name;
+ field->db_name= orig_table->s->table_cache_key;
}
else
- {
- field->db_name= field->org_table_name= "";
- }
- field->table_name= orig_table->table_name;
- field->col_name=field->org_col_name=field_name;
+ field->org_table_name= field->db_name= "";
+ field->table_name= orig_table->alias;
+ field->col_name= field->org_col_name= field_name;
field->charsetnr= charset()->number;
field->length=field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
- field->decimals=dec;
+ field->decimals= 0;
}
-void Field_str::make_field(Send_field *field)
+/*
+ Conversion from decimal to longlong with checking overflow and
+ setting correct value (min/max) in case of overflow
+
+ SYNOPSIS
+ Field::convert_decimal2longlong()
+ val value which have to be converted
+ unsigned_flag type of integer in which we convert val
+ err variable to pass error code
+
+ RETURN
+ value converted from val
+*/
+longlong Field::convert_decimal2longlong(const my_decimal *val,
+ bool unsigned_flag, int *err)
{
- /* table_cache_key is not set for temp tables */
- if (orig_table->table_cache_key)
+ longlong i;
+ if (unsigned_flag)
{
- field->db_name= orig_table->table_cache_key;
- field->org_table_name= orig_table->real_name;
+ if (val->sign())
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ i= 0;
+ *err= 1;
+ }
+ else if (warn_if_overflow(my_decimal2int(E_DEC_ERROR &
+ ~E_DEC_OVERFLOW & ~E_DEC_TRUNCATED,
+ val, TRUE, &i)))
+ {
+ i= ~(longlong) 0;
+ *err= 1;
+ }
}
- else
+ else if (warn_if_overflow(my_decimal2int(E_DEC_ERROR &
+ ~E_DEC_OVERFLOW & ~E_DEC_TRUNCATED,
+ val, FALSE, &i)))
{
- field->db_name= field->org_table_name= "";
+ i= (val->sign() ? LONGLONG_MIN : LONGLONG_MAX);
+ *err= 1;
}
- field->table_name= orig_table->table_name;
- field->col_name=field->org_col_name=field_name;
- field->charsetnr= charset()->number;
- field->length=field_length;
- field->type=type();
- field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
- field->decimals=0;
+ return i;
+}
+
+
+/*
+ Storing decimal in integer fields.
+
+ SYNOPSIS
+ Field_num::store_decimal()
+ val value for storing
+
+ NOTE
+ This method is used by all integer fields, real/decimal redefine it
+
+ RETURN
+ 0 OK
+ != 0 error
+*/
+
+int Field_num::store_decimal(const my_decimal *val)
+{
+ int err= 0;
+ longlong i= convert_decimal2longlong(val, unsigned_flag, &err);
+ return test(err | store(i));
+}
+
+
+/*
+ Return decimal value of integer field
+
+ SYNOPSIS
+ Field_num::val_decimal()
+ decimal_value buffer for storing decimal value
+
+ NOTE
+ This method is used by all integer fields, real/decimal redefine it
+ All longlong values fit in our decimal buffer which cal store 8*9=72
+ digits of integer number
+
+ RETURN
+ pointer to decimal buffer with value of field
+*/
+
+my_decimal* Field_num::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(result_type() == INT_RESULT);
+ longlong nr= val_int();
+ int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
+
+Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg,CHARSET_INFO *charset)
+ :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg)
+{
+ field_charset=charset;
+ if (charset->state & MY_CS_BINSORT)
+ flags|=BINARY_FLAG;
+}
+
+
+void Field_num::make_field(Send_field *field)
+{
+ Field::make_field(field);
+ field->decimals= dec;
+}
+
+/*
+ Decimal representation of Field_str
+
+ SYNOPSIS
+ Field_str::store_decimal()
+ d value for storing
+
+ NOTE
+ Field_str is the base class for fields like Field_enum, Field_date and some
+ similar. Some dates use fraction and also string value should be
+ converted to floating point value according our rules, so we use double
+ to store value of decimal in string
+
+ RETURN
+ 0 OK
+ != 0 error
+*/
+
+int Field_str::store_decimal(const my_decimal *d)
+{
+ double val;
+ /* TODO: use decimal2string? */
+ int err= warn_if_overflow(my_decimal2double(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW, d, &val));
+ return err | store(val);
+}
+
+
+my_decimal *Field_str::val_decimal(my_decimal *decimal_value)
+{
+ longlong nr= val_int();
+ int2my_decimal(E_DEC_FATAL_ERROR, nr, 0, decimal_value);
+ return decimal_value;
}
@@ -1060,11 +1418,12 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
{
copy->blob_field=(Field_blob*) this;
copy->strip=0;
- copy->length-=table->blob_ptr_size;
+ copy->length-= table->s->blob_ptr_size;
return copy->length;
}
- else if (!zero_pack() && (type() == FIELD_TYPE_STRING && copy->length > 4 ||
- type() == FIELD_TYPE_VAR_STRING))
+ else if (!zero_pack() &&
+ (type() == MYSQL_TYPE_STRING && copy->length >= 4 &&
+ copy->length < 256))
copy->strip=1; /* Remove end space */
else
copy->strip=0;
@@ -1100,11 +1459,11 @@ bool Field::get_time(TIME *ltime)
Needs to be changed if/when we want to support different time formats
*/
-void Field::store_time(TIME *ltime,timestamp_type type)
+int Field::store_time(TIME *ltime, timestamp_type type)
{
char buff[MAX_DATE_STRING_REP_LENGTH];
uint length= (uint) my_TIME_to_str(ltime, buff);
- store(buff, length, &my_charset_bin);
+ return store(buff, length, &my_charset_bin);
}
@@ -1113,6 +1472,140 @@ bool Field::optimize_range(uint idx, uint part)
return test(table->file->index_flags(idx, part, 1) & HA_READ_RANGE);
}
+
+Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table)
+{
+ Field *tmp;
+ if (!(tmp= (Field*) memdup_root(root,(char*) this,size_of())))
+ return 0;
+
+ if (tmp->table->maybe_null)
+ tmp->flags&= ~NOT_NULL_FLAG;
+ tmp->table= new_table;
+ tmp->key_start.init(0);
+ tmp->part_of_key.init(0);
+ tmp->part_of_sortkey.init(0);
+ tmp->unireg_check=Field::NONE;
+ tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
+ ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
+ tmp->reset_fields();
+ return tmp;
+}
+
+
+Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
+ char *new_ptr, uchar *new_null_ptr,
+ uint new_null_bit)
+{
+ Field *tmp;
+ if ((tmp= new_field(root, new_table)))
+ {
+ tmp->ptr= new_ptr;
+ tmp->null_ptr= new_null_ptr;
+ tmp->null_bit= new_null_bit;
+ }
+ return tmp;
+}
+
+
+/*
+ SYNOPSIS
+ Field::quote_data()
+ unquoted_string Pointer pointing to the value of a field
+
+ DESCRIPTION
+ Simple method that passes the field type to the method "type_quote"
+ To get a true/false value as to whether the value in string1 needs
+ to be enclosed with quotes. This ensures that values in the final
+ sql statement to be passed to the remote server will be quoted properly
+
+ RETURN_VALUE
+ void Immediately - if string doesn't need quote
+ void Upon prepending/appending quotes on each side of variable
+
+*/
+
+bool Field::quote_data(String *unquoted_string)
+{
+ char escaped_string[IO_SIZE];
+ char *unquoted_string_buffer= (char *)(unquoted_string->ptr());
+ DBUG_ENTER("Field::quote_data");
+
+ if (!needs_quotes())
+ DBUG_RETURN(0);
+
+ // this is the same call that mysql_real_escape_string() calls
+ if (escape_string_for_mysql(&my_charset_bin, (char *)escaped_string,
+ sizeof(escaped_string), unquoted_string->ptr(),
+ unquoted_string->length()) == (ulong)~0)
+ DBUG_RETURN(1);
+
+ // reset string, then re-append with quotes and escaped values
+ unquoted_string->length(0);
+ if (unquoted_string->append('\'') ||
+ unquoted_string->append((char *)escaped_string) ||
+ unquoted_string->append('\''))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Quote a field type if needed
+
+ SYNOPSIS
+ Field::type_quote
+
+ DESCRIPTION
+ Simple method to give true/false whether a field should be quoted.
+ Used when constructing INSERT and UPDATE queries to the remote server
+ see write_row and update_row
+
+ RETURN VALUE
+ 0 if value is of type NOT needing quotes
+ 1 if value is of type needing quotes
+*/
+
+bool Field::needs_quotes(void)
+{
+ DBUG_ENTER("Field::type_quote");
+
+ switch (type()) {
+ //FIX this when kernel is fixed
+ case MYSQL_TYPE_VARCHAR :
+ case FIELD_TYPE_STRING :
+ case FIELD_TYPE_VAR_STRING :
+ case FIELD_TYPE_YEAR :
+ case FIELD_TYPE_NEWDATE :
+ case FIELD_TYPE_TIME :
+ case FIELD_TYPE_TIMESTAMP :
+ case FIELD_TYPE_DATE :
+ case FIELD_TYPE_DATETIME :
+ case FIELD_TYPE_TINY_BLOB :
+ case FIELD_TYPE_BLOB :
+ case FIELD_TYPE_MEDIUM_BLOB :
+ case FIELD_TYPE_LONG_BLOB :
+ case FIELD_TYPE_GEOMETRY :
+ DBUG_RETURN(1);
+
+ case FIELD_TYPE_DECIMAL :
+ case FIELD_TYPE_TINY :
+ case FIELD_TYPE_SHORT :
+ case FIELD_TYPE_INT24 :
+ case FIELD_TYPE_LONG :
+ case FIELD_TYPE_FLOAT :
+ case FIELD_TYPE_DOUBLE :
+ case FIELD_TYPE_LONGLONG :
+ case FIELD_TYPE_NULL :
+ case FIELD_TYPE_SET :
+ case FIELD_TYPE_ENUM :
+ DBUG_RETURN(0);
+ default:
+ DBUG_RETURN(0);
+ }
+}
+
+
/****************************************************************************
Field_null, a field that always return NULL
****************************************************************************/
@@ -1175,7 +1668,7 @@ void Field_decimal::overflow(bool negative)
int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff,sizeof(buff), &my_charset_bin);
/* Convert character set if the old one is multi byte */
@@ -1250,7 +1743,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
from++;
if (from == end)
{
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
is_cuted_fields_incr=1;
}
else if (*from == '+' || *from == '-') // Found some sign ?
@@ -1316,7 +1809,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
/*
We only have to generate warnings if count_cuted_fields is set.
This is to avoid extra checks of the number when they are not needed.
- Even if this flag is not set, it's ok to increment warnings, if
+ Even if this flag is not set, it's OK to increment warnings, if
it makes the code easer to read.
*/
@@ -1326,7 +1819,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
for (;from != end && my_isspace(&my_charset_bin, *from); from++) ;
if (from != end) // If still something left, warn
{
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
is_cuted_fields_incr=1;
}
}
@@ -1505,7 +1998,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
{
if (!is_cuted_fields_incr)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, 1);
+ WARN_DATA_TRUNCATED, 1);
return 0;
}
continue;
@@ -1522,7 +2015,13 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
if (tmp_char != '0') // Losing a non zero digit ?
{
if (!is_cuted_fields_incr)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ {
+ /*
+ This is a note, not a warning, as we don't want to abort
+ when we cut decimals in strict mode
+ */
+ set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
+ }
return 0;
}
continue;
@@ -1727,6 +2226,302 @@ void Field_decimal::sql_type(String &res) const
/****************************************************************************
+** Field_new_decimal
+****************************************************************************/
+
+/*
+ Constructors of new decimal field. In case of using NOT_FIXED_DEC it try
+ to use maximally allowed length (DECIMAL_MAX_LENGTH) and number of digits
+ after decimal point maximally close to half of this range
+ (min(DECIMAL_MAX_LENGTH/2, NOT_FIXED_DEC-1))
+*/
+Field_new_decimal::Field_new_decimal(char *ptr_arg,
+ uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg,
+ enum utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg,
+ uint8 dec_arg,bool zero_arg,
+ bool unsigned_arg)
+ :Field_num(ptr_arg,
+ (dec_arg == NOT_FIXED_DEC || len_arg > DECIMAL_MAX_LENGTH ?
+ DECIMAL_MAX_LENGTH : len_arg),
+ null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg,
+ (dec_arg == NOT_FIXED_DEC ?
+ min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) :
+ dec_arg),
+ zero_arg, unsigned_arg)
+{
+ bin_size= my_decimal_get_binary_size(field_length, dec);
+}
+
+
+Field_new_decimal::Field_new_decimal(uint32 len_arg,
+ bool maybe_null,
+ const char *name,
+ struct st_table *t_arg,
+ uint8 dec_arg)
+ :Field_num((char*) 0,
+ (dec_arg == NOT_FIXED_DEC|| len_arg > DECIMAL_MAX_LENGTH ?
+ DECIMAL_MAX_LENGTH : len_arg),
+ maybe_null ? (uchar*) "": 0, 0,
+ NONE, name, t_arg,
+ (dec_arg == NOT_FIXED_DEC ?
+ min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) :
+ dec_arg),
+ 0, 0)
+{
+ bin_size= my_decimal_get_binary_size(field_length, dec);
+}
+
+
+void Field_new_decimal::reset(void)
+{
+ store_value(&decimal_zero);
+}
+
+
+/*
+ Generate max/min decimal value in case of overflow.
+
+ SYNOPSIS
+ Field_new_decimal::set_value_on_overflow();
+ decimal_value buffer for value
+ sign sign of value which caused overflow
+*/
+
+void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
+ bool sign)
+{
+ DBUG_ENTER("Field_new_decimal::set_value_on_overflow");
+ max_my_decimal(decimal_value, field_length, decimals());
+ if (sign)
+ {
+ if (unsigned_flag)
+ my_decimal_set_zero(decimal_value);
+ else
+ decimal_value->sign(TRUE);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Store decimal value in the binary buffer
+
+ SYNOPSIS
+ store_value(const my_decimal *decimal_value)
+ decimal_value my_decimal
+
+ DESCRIPTION
+ checks if decimal_value fits into field size.
+ if it does, stores the decimal in the buffer using binary format.
+ Otherwise sets maximal number that can be stored in the field.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool Field_new_decimal::store_value(const my_decimal *decimal_value)
+{
+ my_decimal *dec= (my_decimal*)decimal_value;
+ int error= 0;
+ DBUG_ENTER("Field_new_decimal::store_value");
+ dbug_print_decimal("enter", "value: %s", dec);
+
+ /* check that we do not try to write negative value in unsigned field */
+ if (unsigned_flag && decimal_value->sign())
+ {
+ DBUG_PRINT("info", ("unsigned overflow"));
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ error= 1;
+ dec= &decimal_zero;
+ }
+ DBUG_PRINT("info", ("saving with precision %d, scale: %d",
+ (int)field_length, (int)decimals()));
+ dbug_print_decimal("info", "value: %s", dec);
+
+ if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW,
+ dec, ptr,
+ field_length,
+ decimals())))
+ {
+ my_decimal buff;
+ DBUG_PRINT("info", ("overflow"));
+ set_value_on_overflow(&buff, dec->sign());
+ my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, field_length, decimals());
+ error= 1;
+ }
+ DBUG_EXECUTE("info", print_decimal_buff(dec, (byte *) ptr, bin_size););
+ DBUG_RETURN(error);
+}
+
+
+int Field_new_decimal::store(const char *from, uint length,
+ CHARSET_INFO *charset)
+{
+ int err;
+ my_decimal decimal_value;
+ DBUG_ENTER("Field_new_decimal::store(char*)");
+
+ switch ((err= str2my_decimal(E_DEC_FATAL_ERROR &
+ ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
+ from, length, charset, &decimal_value))) {
+ case E_DEC_TRUNCATED:
+ set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
+ break;
+ case E_DEC_OVERFLOW:
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ set_value_on_overflow(&decimal_value, decimal_value.sign());
+ break;
+ case E_DEC_BAD_NUM:
+ push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "decimal", from, field_name,
+ (ulong) table->in_use->row_count);
+ my_decimal_set_zero(&decimal_value);
+ break;
+ }
+
+ dbug_print_decimal("enter", "value: %s", &decimal_value);
+ store_value(&decimal_value);
+ DBUG_RETURN(err);
+}
+
+
+int Field_new_decimal::store(double nr)
+{
+ my_decimal decimal_value;
+ int err;
+ DBUG_ENTER("Field_new_decimal::store(double)");
+
+ err= double2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, nr,
+ &decimal_value);
+ /*
+ TODO: fix following when double2my_decimal when double2decimal
+ will return E_DEC_TRUNCATED always correctly
+ */
+ if (!err)
+ {
+ double nr2;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &nr2);
+ if (nr2 != nr)
+ err= E_DEC_TRUNCATED;
+ }
+ if (err)
+ {
+ if (check_overflow(err))
+ set_value_on_overflow(&decimal_value, decimal_value.sign());
+ /* Only issue a warning if store_value doesn't issue an warning */
+ table->in_use->got_warning= 0;
+ }
+ if (store_value(&decimal_value))
+ err= 1;
+ else if (err && !table->in_use->got_warning)
+ err= warn_if_overflow(err);
+ DBUG_RETURN(err);
+}
+
+
+int Field_new_decimal::store(longlong nr)
+{
+ my_decimal decimal_value;
+ int err;
+
+ if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
+ nr, unsigned_flag, &decimal_value)))
+ {
+ if (check_overflow(err))
+ set_value_on_overflow(&decimal_value, decimal_value.sign());
+ /* Only issue a warning if store_value doesn't issue an warning */
+ table->in_use->got_warning= 0;
+ }
+ if (store_value(&decimal_value))
+ err= 1;
+ else if (err && !table->in_use->got_warning)
+ err= warn_if_overflow(err);
+ return err;
+}
+
+
+int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
+{
+ return store_value(decimal_value);
+}
+
+
+double Field_new_decimal::val_real(void)
+{
+ double dbl;
+ my_decimal decimal_value;
+ my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
+ return dbl;
+}
+
+
+longlong Field_new_decimal::val_int(void)
+{
+ longlong i;
+ my_decimal decimal_value;
+ my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
+ unsigned_flag, &i);
+ return i;
+}
+
+
+my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ENTER("Field_new_decimal::val_decimal");
+ binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
+ field_length,
+ decimals());
+ DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr,
+ bin_size););
+ DBUG_RETURN(decimal_value);
+}
+
+
+String *Field_new_decimal::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ my_decimal decimal_value;
+ int fixed_precision= (zerofill ?
+ (field_length + (decimals() ? 1 : 0)) :
+ 0);
+ my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
+ fixed_precision, decimals(), '0',
+ val_buffer);
+ return val_buffer;
+}
+
+
+int Field_new_decimal::cmp(const char *a,const char*b)
+{
+ return memcmp(a, b, bin_size);
+}
+
+
+void Field_new_decimal::sort_string(char *buff,
+ uint length __attribute__((unused)))
+{
+ memcpy(buff, ptr, bin_size);
+}
+
+
+void Field_new_decimal::sql_type(String &str) const
+{
+ CHARSET_INFO *cs= str.charset();
+ str.length(cs->cset->snprintf(cs, (char*) str.ptr(), str.alloced_length(),
+ "decimal(%d,%d)", field_length, (int)dec));
+ add_zerofill_and_unsigned(str);
+}
+
+
+/****************************************************************************
** tiny int
****************************************************************************/
@@ -1751,11 +2546,8 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (table->in_use->count_cuted_fields && !test_if_int(from,len,end,cs))
- {
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
error= 1;
- }
}
else
{
@@ -1771,11 +2563,8 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (table->in_use->count_cuted_fields && !test_if_int(from,len,end,cs))
- {
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
error= 1;
- }
}
ptr[0]= (char) tmp;
return error;
@@ -1818,7 +2607,7 @@ int Field_tiny::store(double nr)
error= 1;
}
else
- *ptr=(char) nr;
+ *ptr=(char) (int) nr;
}
return error;
}
@@ -1949,17 +2738,14 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (tmp > (uint16) ~0)
+ else if (tmp > UINT_MAX16)
{
- tmp=(uint16) ~0;
+ tmp=UINT_MAX16;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (table->in_use->count_cuted_fields && !test_if_int(from,len,end,cs))
- {
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
error= 1;
- }
}
else
{
@@ -1975,14 +2761,11 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (table->in_use->count_cuted_fields && !test_if_int(from,len,end,cs))
- {
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
error= 1;
- }
}
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int2store(ptr,tmp);
}
@@ -2006,9 +2789,9 @@ int Field_short::store(double nr)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (nr > (double) (uint16) ~0)
+ else if (nr > (double) UINT_MAX16)
{
- res=(int16) (uint16) ~0;
+ res=(int16) UINT_MAX16;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
@@ -2030,10 +2813,10 @@ int Field_short::store(double nr)
error= 1;
}
else
- res=(int16) nr;
+ res=(int16) (int) nr;
}
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int2store(ptr,res);
}
@@ -2055,9 +2838,9 @@ int Field_short::store(longlong nr)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (nr > (longlong) (uint16) ~0)
+ else if (nr > (longlong) UINT_MAX16)
{
- res=(int16) (uint16) ~0;
+ res=(int16) UINT_MAX16;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
@@ -2082,7 +2865,7 @@ int Field_short::store(longlong nr)
res=(int16) nr;
}
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int2store(ptr,res);
}
@@ -2097,7 +2880,7 @@ double Field_short::val_real(void)
{
short j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint2korr(ptr);
else
#endif
@@ -2109,7 +2892,7 @@ longlong Field_short::val_int(void)
{
short j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint2korr(ptr);
else
#endif
@@ -2128,7 +2911,7 @@ String *Field_short::val_str(String *val_buffer,
char *to=(char*) val_buffer->ptr();
short j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint2korr(ptr);
else
#endif
@@ -2156,7 +2939,7 @@ int Field_short::cmp(const char *a_ptr, const char *b_ptr)
{
short a,b;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
a=sint2korr(a_ptr);
b=sint2korr(b_ptr);
@@ -2177,7 +2960,7 @@ int Field_short::cmp(const char *a_ptr, const char *b_ptr)
void Field_short::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
- if (!table->db_low_byte_first)
+ if (!table->s->db_low_byte_first)
{
if (unsigned_flag)
to[0] = ptr[0];
@@ -2230,11 +3013,8 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (table->in_use->count_cuted_fields && !test_if_int(from,len,end,cs))
- {
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
error= 1;
- }
}
else
{
@@ -2250,11 +3030,8 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (table->in_use->count_cuted_fields && !test_if_int(from,len,end,cs))
- {
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
error= 1;
- }
}
int3store(ptr,tmp);
@@ -2448,71 +3225,72 @@ static bool test_if_minus(CHARSET_INFO *cs,
int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
{
- long tmp;
- int error= 0;
+ ulong tmp_scan;
+ longlong tmp;
+ long store_tmp;
+ int error;
char *end;
-
- tmp= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
- len-= tmp;
- from+= tmp;
- my_errno=0;
- if (unsigned_flag)
+ tmp_scan= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
+ len-= tmp_scan;
+ from+= tmp_scan;
+
+ end= (char*) from+len;
+ tmp= cs->cset->strtoll10(cs, from, &end, &error);
+
+ if (error != MY_ERRNO_EDOM)
{
- if (!len || test_if_minus(cs, from, from + len))
+ if (unsigned_flag)
{
- tmp=0; // Set negative to 0
- my_errno=ERANGE;
- error= 1;
+ if (error < 0)
+ {
+ error= 1;
+ tmp= 0;
+ }
+ else if ((ulonglong) tmp > (ulonglong) UINT_MAX32)
+ {
+ tmp= UINT_MAX32;
+ error= 1;
+ }
+ else
+ error= 0;
}
else
- tmp=(long) my_strntoul(cs,from,len,10,&end,&error);
- }
- else
- tmp=my_strntol(cs,from,len,10,&end,&error);
- if (error ||
- (from+len != end && table->in_use->count_cuted_fields &&
- !test_if_int(from,len,end,cs)))
- error= 1;
-#if SIZEOF_LONG > 4
- if (unsigned_flag)
- {
- if ((ulong) tmp > UINT_MAX32)
{
- tmp= UINT_MAX32;
- error= 1;
- my_errno=ERANGE;
- }
- }
- else
- {
- if (tmp > INT_MAX32)
- {
- tmp= INT_MAX32;
- error= 1;
- my_errno=ERANGE;
- }
- else if (tmp < INT_MIN32)
- {
- tmp= INT_MIN32;
- error= 1;
- my_errno=ERANGE;
+ if (error < 0)
+ {
+ error= 0;
+ if (tmp < INT_MIN32)
+ {
+ tmp= INT_MIN32;
+ error= 1;
+ }
+ }
+ else if (tmp > INT_MAX32)
+ {
+ tmp= INT_MAX32;
+ error= 1;
+ }
}
}
-#endif
if (error)
{
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
error= 1;
+ 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;
+
+ store_tmp= (long) tmp;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
- int4store(ptr,tmp);
+ int4store(ptr, store_tmp);
}
else
#endif
- longstore(ptr,tmp);
+ longstore(ptr, store_tmp);
return error;
}
@@ -2527,7 +3305,6 @@ int Field_long::store(double nr)
if (nr < 0)
{
res=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
else if (nr > (double) UINT_MAX32)
@@ -2544,20 +3321,21 @@ int Field_long::store(double nr)
if (nr < (double) INT_MIN32)
{
res=(int32) INT_MIN32;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
else if (nr > (double) INT_MAX32)
{
res=(int32) INT_MAX32;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
else
- res=(int32) nr;
+ res=(int32) (longlong) nr;
}
+ if (error)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,res);
}
@@ -2572,26 +3350,18 @@ int Field_long::store(longlong nr)
{
int error= 0;
int32 res;
-
- /*
- This assert has nothing to do with this method per se, it was put here
- only because it is one of the best places for catching places there its
- condition is broken.
- */
- DBUG_ASSERT(table->in_use == current_thd);
+ DBUG_ASSERT(table->in_use == current_thd); // General safety
if (unsigned_flag)
{
if (nr < 0)
{
res=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
else if (nr >= (LL(1) << 32))
{
res=(int32) (uint32) ~0L;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
else
@@ -2602,20 +3372,21 @@ int Field_long::store(longlong nr)
if (nr < (longlong) INT_MIN32)
{
res=(int32) INT_MIN32;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
else if (nr > (longlong) INT_MAX32)
{
res=(int32) INT_MAX32;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
else
res=(int32) nr;
}
+ if (error)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,res);
}
@@ -2630,7 +3401,7 @@ double Field_long::val_real(void)
{
int32 j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint4korr(ptr);
else
#endif
@@ -2644,7 +3415,7 @@ longlong Field_long::val_int(void)
/* See the comment in Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint4korr(ptr);
else
#endif
@@ -2662,7 +3433,7 @@ String *Field_long::val_str(String *val_buffer,
char *to=(char*) val_buffer->ptr();
int32 j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint4korr(ptr);
else
#endif
@@ -2688,7 +3459,7 @@ int Field_long::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
a=sint4korr(a_ptr);
b=sint4korr(b_ptr);
@@ -2707,7 +3478,7 @@ int Field_long::cmp(const char *a_ptr, const char *b_ptr)
void Field_long::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
- if (!table->db_low_byte_first)
+ if (!table->s->db_low_byte_first)
{
if (unsigned_flag)
to[0] = ptr[0];
@@ -2748,17 +3519,15 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
longlong tmp;
int error= 0;
char *end;
-
+
tmp= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
len-= (uint)tmp;
from+= tmp;
- my_errno=0;
if (unsigned_flag)
{
if (!len || test_if_minus(cs, from, from + len))
{
tmp=0; // Set negative to 0
- my_errno= ERANGE;
error= 1;
}
else
@@ -2766,15 +3535,16 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
}
else
tmp=my_strntoll(cs,from,len,10,&end,&error);
- if (error ||
- (from+len != end && table->in_use->count_cuted_fields &&
- !test_if_int(from,len,end,cs)))
+ if (error)
{
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
+ else if (from+len != end && table->in_use->count_cuted_fields &&
+ check_int(from,len,end,cs))
+ error= 1;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int8store(ptr,tmp);
}
@@ -2789,19 +3559,18 @@ int Field_longlong::store(double nr)
{
int error= 0;
longlong res;
- nr=rint(nr);
+
+ nr= rint(nr);
if (unsigned_flag)
{
if (nr < 0)
{
res=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (nr >= (double) ~ (ulonglong) 0)
+ else if (nr >= (double) ULONGLONG_MAX)
{
res= ~(longlong) 0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
else
@@ -2811,21 +3580,22 @@ int Field_longlong::store(double nr)
{
if (nr <= (double) LONGLONG_MIN)
{
- res=(longlong) LONGLONG_MIN;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
+ res= LONGLONG_MIN;
+ error= (nr < (double) LONGLONG_MIN);
}
else if (nr >= (double) (ulonglong) LONGLONG_MAX)
{
- res=(longlong) LONGLONG_MAX;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
+ res= LONGLONG_MAX;
+ error= (nr > (double) LONGLONG_MAX);
}
else
res=(longlong) nr;
}
+ if (error)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int8store(ptr,res);
}
@@ -2839,7 +3609,7 @@ int Field_longlong::store(double nr)
int Field_longlong::store(longlong nr)
{
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int8store(ptr,nr);
}
@@ -2854,7 +3624,7 @@ double Field_longlong::val_real(void)
{
longlong j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
j=sint8korr(ptr);
}
@@ -2875,7 +3645,7 @@ longlong Field_longlong::val_int(void)
{
longlong j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint8korr(ptr);
else
#endif
@@ -2894,7 +3664,7 @@ String *Field_longlong::val_str(String *val_buffer,
char *to=(char*) val_buffer->ptr();
longlong j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint8korr(ptr);
else
#endif
@@ -2919,7 +3689,7 @@ int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
{
longlong a,b;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
a=sint8korr(a_ptr);
b=sint8korr(b_ptr);
@@ -2939,7 +3709,7 @@ int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
- if (!table->db_low_byte_first)
+ if (!table->s->db_low_byte_first)
{
if (unsigned_flag)
to[0] = ptr[0];
@@ -2989,10 +3759,12 @@ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
int error;
char *end;
double nr= my_strntod(cs,(char*) from,len,&end,&error);
- if (error || ((uint) (end-from) != len && table->in_use->count_cuted_fields))
+ if (error || (!len || (uint) (end-from) != len &&
+ table->in_use->count_cuted_fields))
{
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ (error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1);
error= 1;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
}
Field_float::store(nr);
return error;
@@ -3052,7 +3824,7 @@ int Field_float::store(double nr)
}
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float4store(ptr,j);
}
@@ -3068,12 +3840,11 @@ int Field_float::store(longlong nr)
return store((double)nr);
}
-
double Field_float::val_real(void)
{
float j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float4get(j,ptr);
}
@@ -3087,7 +3858,7 @@ longlong Field_float::val_int(void)
{
float j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float4get(j,ptr);
}
@@ -3103,7 +3874,7 @@ String *Field_float::val_str(String *val_buffer,
{
float nr;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float4get(nr,ptr);
}
@@ -3185,7 +3956,7 @@ int Field_float::cmp(const char *a_ptr, const char *b_ptr)
{
float a,b;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float4get(a,a_ptr);
float4get(b,b_ptr);
@@ -3205,7 +3976,7 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused)))
{
float nr;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float4get(nr,ptr);
}
@@ -3275,10 +4046,12 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
int error;
char *end;
double nr= my_strntod(cs,(char*) from, len, &end, &error);
- if (error || ((uint) (end-from) != len && table->in_use->count_cuted_fields))
+ if (error || (!len || (uint) (end-from) != len &&
+ table->in_use->count_cuted_fields))
{
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ (error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1);
error= 1;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
}
Field_double::store(nr);
return error;
@@ -3331,7 +4104,7 @@ int Field_double::store(double nr)
}
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float8store(ptr,nr);
}
@@ -3347,12 +4120,18 @@ int Field_double::store(longlong nr)
return store((double)nr);
}
+int Field_real::store_decimal(const my_decimal *dm)
+{
+ double dbl;
+ my_decimal2double(E_DEC_FATAL_ERROR, dm, &dbl);
+ return store(dbl);
+}
double Field_double::val_real(void)
{
double j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float8get(j,ptr);
}
@@ -3366,7 +4145,7 @@ longlong Field_double::val_int(void)
{
double j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float8get(j,ptr);
}
@@ -3377,12 +4156,19 @@ longlong Field_double::val_int(void)
}
+my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
+{
+ double2my_decimal(E_DEC_FATAL_ERROR, val_real(), decimal_value);
+ return decimal_value;
+}
+
+
String *Field_double::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
double nr;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float8get(nr,ptr);
}
@@ -3470,7 +4256,7 @@ int Field_double::cmp(const char *a_ptr, const char *b_ptr)
{
double a,b;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float8get(a,a_ptr);
float8get(b,b_ptr);
@@ -3493,7 +4279,7 @@ void Field_double::sort_string(char *to,uint length __attribute__((unused)))
{
double nr;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
float8get(nr,ptr);
}
@@ -3544,7 +4330,7 @@ void Field_double::sql_type(String &res) const
TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with
auto-set-on-update (or now() as default) in this table before, then this
field has NOW() as default and is updated when row changes, else it is
- field which has 0 as default value and is not automaitcally updated.
+ field which has 0 as default value and is not automatically updated.
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
automatically (TIMESTAMP DEFAULT NOW())
TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
@@ -3606,7 +4392,7 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
return TIMESTAMP_AUTO_SET_ON_UPDATE;
case TIMESTAMP_OLD_FIELD:
/*
- Altough we can have several such columns in legacy tables this
+ Although we can have several such columns in legacy tables this
function should be called only for first of them (i.e. the one
having auto-set property).
*/
@@ -3634,14 +4420,22 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
bool in_dst_time_gap;
THD *thd= table->in_use;
- have_smth_to_conv= (str_to_datetime(from, len, &l_time, 0, &error) >
+ have_smth_to_conv= (str_to_datetime(from, len, &l_time,
+ ((table->in_use->variables.sql_mode &
+ MODE_NO_ZERO_DATE) |
+ MODE_NO_ZERO_IN_DATE),
+ &error) >
MYSQL_TIMESTAMP_ERROR);
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
+ if (error || !have_smth_to_conv)
+ {
+ error= 1;
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_DATETIME, 1);
+ }
- if (have_smth_to_conv)
+ /* Only convert a correct date (not a zero date) */
+ if (have_smth_to_conv && l_time.month)
{
if (!(tmp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
{
@@ -3661,7 +4455,7 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
}
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,tmp);
}
@@ -3671,6 +4465,7 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
return error;
}
+
int Field_timestamp::store(double nr)
{
int error= 0;
@@ -3695,7 +4490,7 @@ int Field_timestamp::store(longlong nr)
bool in_dst_time_gap;
THD *thd= table->in_use;
- if (number_to_TIME(nr, &l_time, 0, &error))
+ if (number_to_datetime(nr, &l_time, 0, &error))
{
if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
{
@@ -3715,11 +4510,18 @@ int Field_timestamp::store(longlong nr)
}
else if (error)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED,
+ WARN_DATA_TRUNCATED,
+ nr, MYSQL_TIMESTAMP_DATETIME, 1);
+ if (!error && timestamp == 0 &&
+ (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE))
+ {
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED,
nr, MYSQL_TIMESTAMP_DATETIME, 1);
+ }
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,timestamp);
}
@@ -3743,7 +4545,7 @@ longlong Field_timestamp::val_int(void)
THD *thd= table->in_use;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
temp=uint4korr(ptr);
else
#endif
@@ -3773,7 +4575,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
val_buffer->length(field_length);
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
temp=uint4korr(ptr);
else
#endif
@@ -3838,14 +4640,14 @@ bool Field_timestamp::get_date(TIME *ltime, uint fuzzydate)
long temp;
THD *thd= table->in_use;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
temp=uint4korr(ptr);
else
#endif
longget(temp,ptr);
if (temp == 0L)
{ /* Zero time is "000000" */
- if (!fuzzydate)
+ if (fuzzydate & TIME_NO_ZERO_DATE)
return 1;
bzero((char*) ltime,sizeof(*ltime));
}
@@ -3866,7 +4668,7 @@ bool Field_timestamp::get_time(TIME *ltime)
bool Field_timestamp::send_binary(Protocol *protocol)
{
TIME tm;
- Field_timestamp::get_date(&tm, TIME_FUZZY_DATE);
+ Field_timestamp::get_date(&tm, 0);
return protocol->store(&tm);
}
@@ -3875,7 +4677,7 @@ int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
a=sint4korr(a_ptr);
b=sint4korr(b_ptr);
@@ -3893,7 +4695,7 @@ int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
- if (!table->db_low_byte_first)
+ if (!table->s->db_low_byte_first)
{
to[0] = ptr[0];
to[1] = ptr[1];
@@ -3922,7 +4724,7 @@ void Field_timestamp::set_time()
long tmp= (long) table->in_use->query_start();
set_notnull();
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,tmp);
}
@@ -3948,14 +4750,14 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
{
tmp=0L;
error= 1;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_TIME, 1);
}
else
{
if (error)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED,
+ WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_TIME, 1);
if (ltime.month)
@@ -3978,6 +4780,16 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
}
+int Field_time::store_time(TIME *ltime, timestamp_type type)
+{
+ long tmp= ((ltime->month ? 0 : ltime->day * 24L) + ltime->hour) * 10000L +
+ (ltime->minute * 100 + ltime->second);
+ if (ltime->neg)
+ tmp= -tmp;
+ return Field_time::store((longlong) tmp);
+}
+
+
int Field_time::store(double nr)
{
long tmp;
@@ -4091,7 +4903,7 @@ String *Field_time::val_str(String *val_buffer,
/*
- Normally we would not consider 'time' as a vaild date, but we allow
+ Normally we would not consider 'time' as a valid date, but we allow
get_date() here to be able to do things like
DATE_FORMAT(time, "%l.%i %p")
*/
@@ -4099,7 +4911,7 @@ String *Field_time::val_str(String *val_buffer,
bool Field_time::get_date(TIME *ltime, uint fuzzydate)
{
long tmp;
- if (!fuzzydate)
+ if (!(fuzzydate & TIME_FUZZY_DATE))
{
push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
@@ -4181,26 +4993,19 @@ void Field_time::sql_type(String &res) const
int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
{
- int err;
char *end;
- long nr= my_strntol(cs, from, len, 10, &end, &err);
-
- if (err)
- {
- if (table->in_use->count_cuted_fields)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- *ptr= 0;
- return 0;
- }
+ int error;
+ long nr= my_strntol(cs, from, len, 10, &end, &error);
- if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
+ if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155 || error)
{
*ptr=0;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
}
- if (table->in_use->count_cuted_fields && !test_if_int(from,len,end,cs))
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
+ error= 1;
+
if (nr != 0 || len != 4)
{
if (nr < YY_PART_YEAR)
@@ -4209,7 +5014,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
nr-= 1900;
}
*ptr= (char) (unsigned char) nr;
- return 0;
+ return error;
}
@@ -4295,7 +5100,11 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
uint32 tmp;
int error;
- if (str_to_datetime(from, len, &l_time, 1, &error) <= MYSQL_TIMESTAMP_ERROR)
+ if (str_to_datetime(from, len, &l_time, TIME_FUZZY_DATE |
+ (table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES)),
+ &error) <= MYSQL_TIMESTAMP_ERROR)
{
tmp=0;
error= 1;
@@ -4304,11 +5113,11 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day);
if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_DATE, 1);
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,tmp);
}
@@ -4335,8 +5144,14 @@ int Field_date::store(double nr)
}
else
tmp=(long) rint(nr);
+
+ /*
+ We don't need to check for zero dates here as this date type is only
+ used in .frm tables from very old MySQL versions
+ */
+
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,tmp);
}
@@ -4363,8 +5178,9 @@ int Field_date::store(longlong nr)
}
else
tmp=(long) nr;
+
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,tmp);
}
@@ -4390,7 +5206,7 @@ double Field_date::val_real(void)
{
int32 j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint4korr(ptr);
else
#endif
@@ -4402,7 +5218,7 @@ longlong Field_date::val_int(void)
{
int32 j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint4korr(ptr);
else
#endif
@@ -4417,7 +5233,7 @@ String *Field_date::val_str(String *val_buffer,
val_buffer->alloc(field_length);
int32 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
tmp=sint4korr(ptr);
else
#endif
@@ -4435,7 +5251,7 @@ int Field_date::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
a=sint4korr(a_ptr);
b=sint4korr(b_ptr);
@@ -4453,7 +5269,7 @@ int Field_date::cmp(const char *a_ptr, const char *b_ptr)
void Field_date::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
- if (!table->db_low_byte_first)
+ if (!table->s->db_low_byte_first)
{
to[0] = ptr[0];
to[1] = ptr[1];
@@ -4475,6 +5291,7 @@ void Field_date::sql_type(String &res) const
res.set_ascii("date", 4);
}
+
/****************************************************************************
** The new date type
** This is identical to the old date type, but stored on 3 bytes instead of 4
@@ -4486,7 +5303,12 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
TIME l_time;
long tmp;
int error;
- if (str_to_datetime(from, len, &l_time, 1, &error) <= MYSQL_TIMESTAMP_ERROR)
+ if (str_to_datetime(from, len, &l_time,
+ (TIME_FUZZY_DATE |
+ (table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))),
+ &error) <= MYSQL_TIMESTAMP_ERROR)
{
tmp=0L;
error= 1;
@@ -4495,24 +5317,24 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_DATE, 1);
int3store(ptr,tmp);
return error;
}
+
int Field_newdate::store(double nr)
{
if (nr < 0.0 || nr > 99991231235959.0)
{
- (void) Field_newdate::store((longlong) -1);
+ int3store(ptr,(int32) 0);
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE);
+ WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE);
return 1;
}
- else
- return Field_newdate::store((longlong) rint(nr));
+ return Field_newdate::store((longlong) rint(nr));
}
@@ -4532,6 +5354,8 @@ int Field_newdate::store(longlong nr)
}
else
{
+ uint month, day;
+
tmp=(int32) nr;
if (tmp)
{
@@ -4539,37 +5363,50 @@ int Field_newdate::store(longlong nr)
tmp+= (uint32) 20000000L;
else if (tmp < 999999L)
tmp+= (uint32) 19000000L;
+
+ month= (uint) ((tmp/100) % 100);
+ day= (uint) (tmp%100);
+ if (month > 12 || day > 31)
+ {
+ tmp=0L; // Don't allow date to change
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DATA_OUT_OF_RANGE, nr,
+ MYSQL_TIMESTAMP_DATE, 1);
+ error= 1;
+ }
+ else
+ tmp= day + month*32 + (tmp/10000)*16*32;
}
- uint month= (uint) ((tmp/100) % 100);
- uint day= (uint) (tmp%100);
- if (month > 12 || day > 31)
+ else if (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE)
{
- tmp=0L; // Don't allow date to change
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_DATE, 1);
+ ER_WARN_DATA_OUT_OF_RANGE,
+ 0, MYSQL_TIMESTAMP_DATE);
error= 1;
}
- else
- tmp= day + month*32 + (tmp/10000)*16*32;
}
- int3store(ptr,(int32) tmp);
+ int3store(ptr, tmp);
return error;
}
-void Field_newdate::store_time(TIME *ltime,timestamp_type type)
+
+int Field_newdate::store_time(TIME *ltime,timestamp_type type)
{
long tmp;
+ int error= 0;
if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
tmp=ltime->year*16*32+ltime->month*32+ltime->day;
else
{
tmp=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ error= 1;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
}
int3store(ptr,tmp);
+ return error;
}
+
bool Field_newdate::send_binary(Protocol *protocol)
{
TIME tm;
@@ -4577,11 +5414,13 @@ bool Field_newdate::send_binary(Protocol *protocol)
return protocol->store_date(&tm);
}
+
double Field_newdate::val_real(void)
{
return (double) Field_newdate::val_int();
}
+
longlong Field_newdate::val_int(void)
{
ulong j= uint3korr(ptr);
@@ -4589,6 +5428,7 @@ longlong Field_newdate::val_int(void)
return (longlong) j;
}
+
String *Field_newdate::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
@@ -4616,24 +5456,26 @@ String *Field_newdate::val_str(String *val_buffer,
return val_buffer;
}
+
bool Field_newdate::get_date(TIME *ltime,uint fuzzydate)
{
- if (is_null())
- return 1;
uint32 tmp=(uint32) uint3korr(ptr);
ltime->day= tmp & 31;
ltime->month= (tmp >> 5) & 15;
ltime->year= (tmp >> 9);
ltime->time_type= MYSQL_TIMESTAMP_DATE;
ltime->hour= ltime->minute= ltime->second= ltime->second_part= ltime->neg= 0;
- return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0;
+ return ((!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ?
+ 1 : 0);
}
+
bool Field_newdate::get_time(TIME *ltime)
{
return Field_newdate::get_date(ltime,0);
}
+
int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
{
uint32 a,b;
@@ -4642,6 +5484,7 @@ int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
+
void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
{
to[0] = ptr[2];
@@ -4649,6 +5492,7 @@ void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
to[2] = ptr[0];
}
+
void Field_newdate::sql_type(String &res) const
{
res.set_ascii("date", 4);
@@ -4667,17 +5511,26 @@ int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
TIME time_tmp;
int error;
ulonglong tmp= 0;
+ enum enum_mysql_timestamp_type func_res;
- if (str_to_datetime(from, len, &time_tmp, 1, &error) > MYSQL_TIMESTAMP_ERROR)
+ func_res= str_to_datetime(from, len, &time_tmp,
+ (TIME_FUZZY_DATE |
+ (table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))),
+ &error);
+ if ((int) func_res > (int) MYSQL_TIMESTAMP_ERROR)
tmp= TIME_to_ulonglong_datetime(&time_tmp);
-
+ else
+ error= 1; // Fix if invalid zero date
+
if (error)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
from, len, MYSQL_TIMESTAMP_DATETIME, 1);
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int8store(ptr,tmp);
}
@@ -4696,10 +5549,10 @@ int Field_datetime::store(double nr)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
nr, MYSQL_TIMESTAMP_DATETIME);
- nr=0.0;
+ nr= 0.0;
error= 1;
}
- error |= Field_datetime::store((longlong) rint(nr));
+ error|= Field_datetime::store((longlong) rint(nr));
return error;
}
@@ -4710,15 +5563,22 @@ int Field_datetime::store(longlong nr)
int error;
longlong initial_nr= nr;
- nr= number_to_TIME(nr, &not_used, 1, &error);
+ nr= number_to_datetime(nr, &not_used, 1, &error);
if (error)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, initial_nr,
+ WARN_DATA_TRUNCATED, initial_nr,
MYSQL_TIMESTAMP_DATETIME, 1);
+ else if (nr == 0 && table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE)
+ {
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DATA_OUT_OF_RANGE,
+ initial_nr, MYSQL_TIMESTAMP_DATE, 1);
+ error= 1;
+ }
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int8store(ptr,nr);
}
@@ -4729,9 +5589,10 @@ int Field_datetime::store(longlong nr)
}
-void Field_datetime::store_time(TIME *ltime,timestamp_type type)
+int Field_datetime::store_time(TIME *ltime,timestamp_type type)
{
longlong tmp;
+ int error= 0;
/*
We don't perform range checking here since values stored in TIME
structure always fit into DATETIME range.
@@ -4742,16 +5603,18 @@ void Field_datetime::store_time(TIME *ltime,timestamp_type type)
else
{
tmp=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ error= 1;
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
}
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int8store(ptr,tmp);
}
else
#endif
longlongstore(ptr,tmp);
+ return error;
}
bool Field_datetime::send_binary(Protocol *protocol)
@@ -4771,7 +5634,7 @@ longlong Field_datetime::val_int(void)
{
longlong j;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
j=sint8korr(ptr);
else
#endif
@@ -4791,14 +5654,14 @@ String *Field_datetime::val_str(String *val_buffer,
int part3;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
tmp=sint8korr(ptr);
else
#endif
longlongget(tmp,ptr);
/*
- Avoid problem with slow longlong aritmetic and sprintf
+ Avoid problem with slow longlong arithmetic and sprintf
*/
part1=(long) (tmp/LL(1000000));
@@ -4844,7 +5707,7 @@ bool Field_datetime::get_date(TIME *ltime, uint fuzzydate)
ltime->day= (int) (part1%100);
ltime->month= (int) (part1/100%100);
ltime->year= (int) (part1/10000);
- return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0;
+ return (!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ? 1 : 0;
}
bool Field_datetime::get_time(TIME *ltime)
@@ -4856,7 +5719,7 @@ int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
{
longlong a,b;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
a=sint8korr(a_ptr);
b=sint8korr(b_ptr);
@@ -4874,7 +5737,7 @@ int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
void Field_datetime::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
- if (!table->db_low_byte_first)
+ if (!table->s->db_low_byte_first)
{
to[0] = ptr[0];
to[1] = ptr[1];
@@ -4916,14 +5779,14 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{
int error= 0, well_formed_error;
uint32 not_used;
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
uint copy_length;
/* See the comment for Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if (String::needs_conversion(length, cs, field_charset, &not_used))
{
uint conv_errors;
@@ -4958,7 +5821,12 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
error= 1;
}
if (error)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ {
+ if (table->in_use->abort_on_warning)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ else
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+ }
return error;
}
@@ -4986,7 +5854,7 @@ int Field_str::store(double nr)
double anr= fabs(nr);
int neg= (nr < 0.0) ? 1 : 0;
if (field_length > 4 && field_length < 32 &&
- (anr < 1.0 ? anr > 1/(log_10[max(0,field_length-neg-2)]) /* -2 for "0." */
+ (anr < 1.0 ? anr > 1/(log_10[max(0,(int) field_length-neg-2)]) /* -2 for "0." */
: anr < log_10[field_length-neg]-1))
use_scientific_notation= FALSE;
@@ -5018,20 +5886,38 @@ int Field_string::store(longlong nr)
}
+int Field_longstr::store_decimal(const my_decimal *d)
+{
+ char buff[DECIMAL_MAX_STR_LENGTH+1];
+ String str(buff, sizeof(buff), &my_charset_bin);
+ my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
+ return store(str.ptr(), str.length(), str.charset());
+}
+
+
double Field_string::val_real(void)
{
int not_used;
char *end_not_used;
- CHARSET_INFO *cs=charset();
- return my_strntod(cs, ptr, field_length, &end_not_used, &not_used);
+ CHARSET_INFO *cs= charset();
+ return my_strntod(cs,ptr,field_length,&end_not_used,&not_used);
}
longlong Field_string::val_int(void)
{
int not_used;
+ char *end_not_used;
CHARSET_INFO *cs=charset();
- return my_strntoll(cs,ptr,field_length,10,NULL,&not_used);
+ return my_strntoll(cs,ptr,field_length,10,&end_not_used,&not_used);
+}
+
+
+my_decimal *Field_longstr::val_decimal(my_decimal *decimal_value)
+{
+ str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(),
+ decimal_value);
+ return decimal_value;
}
@@ -5059,7 +5945,7 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr)
return field_charset->coll->strnncollsp(field_charset,
(const uchar*) a_ptr, field_length,
(const uchar*) b_ptr,
- field_length);
+ field_length, 0);
}
if (field_charset->mbmaxlen != 1)
{
@@ -5087,20 +5973,22 @@ void Field_string::sql_type(String &res) const
{
THD *thd= table->in_use;
CHARSET_INFO *cs=res.charset();
- ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
- res.alloced_length(), "%s(%d)",
- (field_length > 3 &&
- (table->db_options_in_use &
- HA_OPTION_PACK_RECORD) ?
- (has_charset() ? "varchar" : "varbinary") :
+ ulong length;
+
+ length= cs->cset->snprintf(cs,(char*) res.ptr(),
+ res.alloced_length(), "%s(%d)",
+ ((type() == MYSQL_TYPE_VAR_STRING &&
+ !thd->variables.new_mode) ?
+ (has_charset() ? "varchar" : "varbinary") :
(has_charset() ? "char" : "binary")),
- (int) field_length / charset()->mbmaxlen);
+ (int) field_length / charset()->mbmaxlen);
res.length(length);
if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
has_charset() && (charset()->state & MY_CS_BINSORT))
res.append(" binary");
}
+
char *Field_string::pack(char *to, const char *from, uint max_length)
{
uint length= min(field_length,max_length);
@@ -5134,10 +6022,27 @@ const char *Field_string::unpack(char *to, const char *from)
}
-int Field_string::pack_cmp(const char *a, const char *b, uint length)
+/*
+ Compare two packed keys
+
+ SYNOPSIS
+ pack_cmp()
+ a New key
+ b Original key
+ length Key length
+ insert_or_update 1 if this is an insert or update
+
+ RETURN
+ < 0 a < b
+ 0 a = b
+ > 0 a > b
+*/
+
+int Field_string::pack_cmp(const char *a, const char *b, uint length,
+ my_bool insert_or_update)
{
uint a_length, b_length;
- if (field_length > 255)
+ if (length > 255)
{
a_length= uint2korr(a);
b_length= uint2korr(b);
@@ -5149,29 +6054,51 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length)
a_length= (uint) (uchar) *a++;
b_length= (uint) (uchar) *b++;
}
- return my_strnncoll(field_charset,
- (const uchar*)a,a_length,
- (const uchar*)b,b_length);
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) a, a_length,
+ (const uchar*) b, b_length,
+ insert_or_update);
}
-int Field_string::pack_cmp(const char *b, uint length)
+/*
+ Compare a packed key against row
+
+ SYNOPSIS
+ pack_cmp()
+ key Original key
+ length Key length. (May be less than field length)
+ insert_or_update 1 if this is an insert or update
+
+ RETURN
+ < 0 row < key
+ 0 row = key
+ > 0 row > key
+*/
+
+int Field_string::pack_cmp(const char *key, uint length,
+ my_bool insert_or_update)
{
- uint b_length;
- if (field_length > 255)
+ uint row_length, key_length;
+ char *end;
+ if (length > 255)
{
- b_length= uint2korr(b);
- b+= 2;
+ key_length= uint2korr(key);
+ key+= 2;
}
else
- b_length= (uint) (uchar) *b++;
- char *end= ptr + field_length;
+ key_length= (uint) (uchar) *key++;
+
+ /* Only use 'length' of key, not field_length */
+ end= ptr + length;
while (end > ptr && end[-1] == ' ')
end--;
- uint a_length = (uint) (end - ptr);
- return my_strnncoll(field_charset,
- (const uchar*)ptr,a_length,
- (const uchar*)b, b_length);
+ row_length= (uint) (end - ptr);
+
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) ptr, row_length,
+ (const uchar*) key, key_length,
+ insert_or_update);
}
@@ -5179,29 +6106,57 @@ uint Field_string::packed_col_length(const char *data_ptr, uint length)
{
if (length > 255)
return uint2korr(data_ptr)+2;
- else
- return (uint) ((uchar) *data_ptr)+1;
+ return (uint) ((uchar) *data_ptr)+1;
}
+
uint Field_string::max_packed_col_length(uint max_length)
{
return (max_length > 255 ? 2 : 1)+max_length;
}
+Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table)
+{
+ if (type() != MYSQL_TYPE_VAR_STRING || table == new_table)
+ return Field::new_field(root, new_table);
+
+ /*
+ Old VARCHAR field which should be modified to a VARCHAR on copy
+ This is done to ensure that ALTER TABLE will convert old VARCHAR fields
+ to now VARCHAR fields.
+ */
+ return new Field_varstring(field_length, maybe_null(),
+ field_name, new_table,
+ charset());
+}
+
/****************************************************************************
-** VARCHAR type (Not available for the end user yet)
+ VARCHAR type
+ Data in field->ptr is stored as:
+ 1 or 2 bytes length-prefix-header (from Field_varstring::length_bytes)
+ data
+
+ NOTE:
+ When VARCHAR is stored in a key (for handler::index_read() etc) it's always
+ stored with a 2 byte prefix. (Just like blob keys).
+
+ Normally length_bytes is calculated as (field_length < 256 : 1 ? 2)
+ The exception is if there is a prefix key field that is part of a long
+ VARCHAR, in which case field_length for this may be 1 but the length_bytes
+ is 2.
****************************************************************************/
int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
- int error= 0;
- uint32 not_used;
- char buff[80];
+ uint32 not_used, copy_length;
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ int error_code= 0, well_formed_error;
+ enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN;
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if (String::needs_conversion(length, cs, field_charset, &not_used))
{
uint conv_errors;
@@ -5209,38 +6164,65 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
from= tmpstr.ptr();
length= tmpstr.length();
if (conv_errors)
- error= 1;
+ error_code= WARN_DATA_TRUNCATED;
}
- if (length > field_length)
+ /*
+ Make sure we don't break a multibyte sequence
+ as well as don't copy a malformed data.
+ */
+ copy_length= field_charset->cset->well_formed_len(field_charset,
+ from,from+length,
+ field_length/
+ field_charset->mbmaxlen,
+ &well_formed_error);
+ memcpy(ptr + length_bytes, from, copy_length);
+ if (length_bytes == 1)
+ *ptr= (uchar) copy_length;
+ else
+ int2store(ptr, copy_length);
+
+ // Check if we lost something other than just trailing spaces
+ if ((copy_length < length) && table->in_use->count_cuted_fields &&
+ !error_code)
{
- length=field_length;
- error= 1;
+ const char *end= from + length;
+ from+= copy_length;
+ from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES);
+ /* If we lost only spaces then produce a NOTE, not a WARNING */
+ if (from == end)
+ level= MYSQL_ERROR::WARN_LEVEL_NOTE;
+ error_code= WARN_DATA_TRUNCATED;
+ }
+ if (error_code)
+ {
+ if (level == MYSQL_ERROR::WARN_LEVEL_WARN &&
+ table->in_use->abort_on_warning)
+ error_code= ER_DATA_TOO_LONG;
+ set_warning(level, error_code, 1);
+ return 1;
}
- if (error)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
- memcpy(ptr+HA_KEY_BLOB_LENGTH,from,length);
- int2store(ptr, length);
- return error;
+ return 0;
}
int Field_varstring::store(longlong nr)
{
char buff[64];
- int l;
- CHARSET_INFO *cs=charset();
- l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr);
- return Field_varstring::store(buff,(uint)l,cs);
+ uint length;
+ length= (uint) (field_charset->cset->longlong10_to_str)(field_charset,
+ buff,
+ sizeof(buff),
+ -10,nr);
+ return Field_varstring::store(buff, length, field_charset);
}
double Field_varstring::val_real(void)
{
int not_used;
- uint length=uint2korr(ptr)+HA_KEY_BLOB_LENGTH;
- CHARSET_INFO *cs=charset();
char *end_not_used;
- return my_strntod(cs, ptr+HA_KEY_BLOB_LENGTH, length, &end_not_used,
+ uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ return my_strntod(field_charset, ptr+length_bytes, length, &end_not_used,
&not_used);
}
@@ -5248,110 +6230,258 @@ double Field_varstring::val_real(void)
longlong Field_varstring::val_int(void)
{
int not_used;
- uint length=uint2korr(ptr)+HA_KEY_BLOB_LENGTH;
- CHARSET_INFO *cs=charset();
- return my_strntoll(cs,ptr+HA_KEY_BLOB_LENGTH,length,10,NULL, &not_used);
+ char *end_not_used;
+ uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ return my_strntoll(field_charset, ptr+length_bytes, length, 10,
+ &end_not_used, &not_used);
}
-
String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
- uint length=uint2korr(ptr);
- val_ptr->set((const char*) ptr+HA_KEY_BLOB_LENGTH,length,field_charset);
+ uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ val_ptr->set((const char*) ptr+length_bytes, length, field_charset);
return val_ptr;
}
int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
{
- uint a_length=uint2korr(a_ptr);
- uint b_length=uint2korr(b_ptr);
+ uint a_length, b_length;
int diff;
- diff= my_strnncoll(field_charset,
- (const uchar*) a_ptr+HA_KEY_BLOB_LENGTH,
- min(a_length,b_length),
- (const uchar*) b_ptr+HA_KEY_BLOB_LENGTH,
- min(a_length,b_length));
- return diff ? diff : (int) (a_length - b_length);
+
+ if (length_bytes == 1)
+ {
+ a_length= (uint) (uchar) *a_ptr;
+ b_length= (uint) (uchar) *b_ptr;
+ }
+ else
+ {
+ a_length= uint2korr(a_ptr);
+ b_length= uint2korr(b_ptr);
+ }
+ diff= field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) a_ptr+
+ length_bytes,
+ a_length,
+ (const uchar*) b_ptr+
+ length_bytes,
+ b_length,0);
+ return diff;
+}
+
+
+/*
+ NOTE: varstring and blob keys are ALWAYS stored with a 2 byte length prefix
+*/
+
+int Field_varstring::key_cmp(const byte *key_ptr, uint max_key_length)
+{
+ uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uint char_length= max_key_length / field_charset->mbmaxlen;
+
+ char_length= my_charpos(field_charset, ptr + length_bytes,
+ ptr + length_bytes + length, char_length);
+ set_if_smaller(length, char_length);
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) ptr + length_bytes,
+ length,
+ (const uchar*) key_ptr+
+ HA_KEY_BLOB_LENGTH,
+ uint2korr(key_ptr), 0);
+}
+
+
+/*
+ Compare to key segments (always 2 byte length prefix)
+
+ NOTE
+ This is used only to compare key segments created for index_read().
+ (keys are created and compared in key.cc)
+*/
+
+int Field_varstring::key_cmp(const byte *a,const byte *b)
+{
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) a +
+ HA_KEY_BLOB_LENGTH,
+ uint2korr(a),
+ (const uchar*) b +
+ HA_KEY_BLOB_LENGTH,
+ uint2korr(b),
+ 0);
}
+
void Field_varstring::sort_string(char *to,uint length)
{
- uint tot_length=uint2korr(ptr);
+ uint tot_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
tot_length= my_strnxfrm(field_charset,
(uchar*) to, length,
- (uchar*) ptr+HA_KEY_BLOB_LENGTH,
+ (uchar*) ptr + length_bytes,
tot_length);
DBUG_ASSERT(tot_length == length);
}
+enum ha_base_keytype Field_varstring::key_type() const
+{
+ enum ha_base_keytype res;
+
+ if (binary())
+ res= length_bytes == 1 ? HA_KEYTYPE_VARBINARY1 : HA_KEYTYPE_VARBINARY2;
+ else
+ res= length_bytes == 1 ? HA_KEYTYPE_VARTEXT1 : HA_KEYTYPE_VARTEXT2;
+ return res;
+}
+
+
void Field_varstring::sql_type(String &res) const
{
+ THD *thd= table->in_use;
CHARSET_INFO *cs=res.charset();
- ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
- res.alloced_length(),"varchar(%u)",
- field_length / charset()->mbmaxlen);
+ ulong length;
+
+ length= cs->cset->snprintf(cs,(char*) res.ptr(),
+ res.alloced_length(), "%s(%d)",
+ (has_charset() ? "varchar" : "varbinary"),
+ (int) field_length / charset()->mbmaxlen);
res.length(length);
+ if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
+ has_charset() && (charset()->state & MY_CS_BINSORT))
+ res.append(" binary");
}
+
+/*
+ Functions to create a packed row.
+ Here the number of length bytes are depending on the given max_length
+*/
+
char *Field_varstring::pack(char *to, const char *from, uint max_length)
{
- uint length=uint2korr(from);
+ uint length= length_bytes == 1 ? (uint) (uchar) *from : uint2korr(from);
+ set_if_smaller(max_length, field_length);
if (length > max_length)
length=max_length;
*to++= (char) (length & 255);
if (max_length > 255)
*to++= (char) (length >> 8);
if (length)
- memcpy(to, from+HA_KEY_BLOB_LENGTH, length);
+ memcpy(to, from+length_bytes, length);
return to+length;
}
-char *Field_varstring::pack_key(char *to, const char *from, uint max_length)
+char *Field_varstring::pack_key(char *to, const char *key, uint max_length)
{
- uint length=uint2korr(from);
- uint char_length= (field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length;
- from+=HA_KEY_BLOB_LENGTH;
+ uint length= length_bytes == 1 ? (uint) (uchar) *key : uint2korr(key);
+ uint char_length= ((field_charset->mbmaxlen > 1) ?
+ max_length/field_charset->mbmaxlen : max_length);
+ key+= length_bytes;
if (length > char_length)
- char_length= my_charpos(field_charset, from, from+length, char_length);
- set_if_smaller(length, char_length);
+ {
+ char_length= my_charpos(field_charset, key, key+length, char_length);
+ set_if_smaller(length, char_length);
+ }
+ *to++= (char) (length & 255);
+ if (max_length > 255)
+ *to++= (char) (length >> 8);
+ if (length)
+ memcpy(to, key, length);
+ return to+length;
+}
+
+
+/*
+ Unpack a key into a record buffer.
+
+ SYNOPSIS
+ unpack_key()
+ to Pointer into the record buffer.
+ key Pointer to the packed key.
+ max_length Key length limit from key description.
+
+ DESCRIPTION
+ A VARCHAR key has a maximum size of 64K-1.
+ In its packed form, the length field is one or two bytes long,
+ depending on 'max_length'.
+
+ RETURN
+ Pointer to end of 'key' (To the next key part if multi-segment key)
+*/
+
+const char *Field_varstring::unpack_key(char *to, const char *key,
+ uint max_length)
+{
+ /* get length of the blob key */
+ uint32 length= *((uchar*) key++);
+ if (max_length > 255)
+ length+= (*((uchar*) key++)) << 8;
+
+ /* put the length into the record buffer */
+ if (length_bytes == 1)
+ *ptr= (uchar) length;
+ else
+ int2store(ptr, length);
+ memcpy(ptr + length_bytes, key, length);
+ return key + length;
+}
+
+/*
+ Create a packed key that will be used for storage in the index tree
+
+ SYNOPSIS
+ pack_key_from_key_image()
+ to Store packed key segment here
+ from Key segment (as given to index_read())
+ max_length Max length of key
+
+ RETURN
+ end of key storage
+*/
+
+char *Field_varstring::pack_key_from_key_image(char *to, const char *from,
+ uint max_length)
+{
+ /* Key length is always stored as 2 bytes */
+ uint length= uint2korr(from);
+ if (length > max_length)
+ length= max_length;
*to++= (char) (length & 255);
if (max_length > 255)
*to++= (char) (length >> 8);
if (length)
- memcpy(to, from, length);
+ memcpy(to, from+HA_KEY_BLOB_LENGTH, length);
return to+length;
}
+/*
+ unpack field packed with Field_varstring::pack()
+*/
+
const char *Field_varstring::unpack(char *to, const char *from)
{
uint length;
- if (field_length > 255)
- {
+ if (length_bytes == 1)
length= (uint) (uchar) (*to= *from++);
- to[1]=0;
- }
else
{
- length=uint2korr(from);
- to[0] = *from++;
- to[1] = *from++;
+ length= uint2korr(from);
+ to[0]= *from++;
+ to[1]= *from++;
}
if (length)
- memcpy(to+HA_KEY_BLOB_LENGTH, from, length);
+ memcpy(to+ length_bytes, from, length);
return from+length;
}
-int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
+int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length,
+ my_bool insert_or_update)
{
- uint a_length;
- uint b_length;
+ uint a_length, b_length;
if (key_length > 255)
{
a_length=uint2korr(a); a+= 2;
@@ -5362,63 +6492,136 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
a_length= (uint) (uchar) *a++;
b_length= (uint) (uchar) *b++;
}
- return my_strnncoll(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length);
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) a, a_length,
+ (const uchar*) b, b_length,
+ insert_or_update);
}
-int Field_varstring::pack_cmp(const char *b, uint key_length)
+
+int Field_varstring::pack_cmp(const char *b, uint key_length,
+ my_bool insert_or_update)
{
- char *a= ptr+HA_KEY_BLOB_LENGTH;
- uint a_length= uint2korr(ptr);
+ char *a= ptr+ length_bytes;
+ uint a_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
uint b_length;
+ uint char_length= ((field_charset->mbmaxlen > 1) ?
+ key_length / field_charset->mbmaxlen : key_length);
+
if (key_length > 255)
{
- b_length=uint2korr(b); b+= 2;
+ b_length=uint2korr(b); b+= HA_KEY_BLOB_LENGTH;
}
else
- {
b_length= (uint) (uchar) *b++;
+
+ if (a_length > char_length)
+ {
+ char_length= my_charpos(field_charset, a, a+a_length, char_length);
+ set_if_smaller(a_length, char_length);
}
- return my_strnncoll(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length);
+
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) a,
+ a_length,
+ (const uchar*) b, b_length,
+ insert_or_update);
}
+
uint Field_varstring::packed_col_length(const char *data_ptr, uint length)
{
if (length > 255)
- return uint2korr(data_ptr)+HA_KEY_BLOB_LENGTH;
- else
- return (uint) ((uchar) *data_ptr)+1;
+ return uint2korr(data_ptr)+2;
+ return (uint) ((uchar) *data_ptr)+1;
}
+
uint Field_varstring::max_packed_col_length(uint max_length)
{
return (max_length > 255 ? 2 : 1)+max_length;
}
-void Field_varstring::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
- imagetype type)
+
+void Field_varstring::get_key_image(char *buff, uint length, imagetype type)
{
- uint f_length=uint2korr(ptr);
- if (f_length > length)
- f_length= length;
- int2store(buff,length);
- memcpy(buff+HA_KEY_BLOB_LENGTH, ptr+HA_KEY_BLOB_LENGTH, length);
-#ifdef HAVE_purify
+ uint f_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uint char_length= length / field_charset->mbmaxlen;
+ char *pos= ptr+length_bytes;
+ char_length= my_charpos(field_charset, pos, pos + f_length, char_length);
+ set_if_smaller(f_length, char_length);
+ /* Key is always stored with 2 bytes */
+ int2store(buff,f_length);
+ memcpy(buff+HA_KEY_BLOB_LENGTH, pos, f_length);
if (f_length < length)
+ {
+ /*
+ Must clear this as we do a memcmp in opt_range.cc to detect
+ identical keys
+ */
bzero(buff+HA_KEY_BLOB_LENGTH+f_length, (length-f_length));
-#endif
+ }
}
-void Field_varstring::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
+
+void Field_varstring::set_key_image(char *buff,uint length)
+{
+ length= uint2korr(buff); // Real length is here
+ (void) Field_varstring::store(buff+HA_KEY_BLOB_LENGTH, length,
+ field_charset);
+}
+
+
+int Field_varstring::cmp_binary(const char *a_ptr, const char *b_ptr,
+ uint32 max_length)
+{
+ uint32 a_length,b_length;
+
+ if (length_bytes == 1)
+ {
+ a_length= (uint) (uchar) *a_ptr;
+ b_length= (uint) (uchar) *b_ptr;
+ }
+ else
+ {
+ a_length= uint2korr(a_ptr);
+ b_length= uint2korr(b_ptr);
+ }
+ set_if_smaller(a_length, max_length);
+ set_if_smaller(b_length, max_length);
+ if (a_length != b_length)
+ return 1;
+ return memcmp(a_ptr+length_bytes, b_ptr+length_bytes, a_length);
+}
+
+
+Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table)
{
- length=uint2korr(buff); // Real length is here
- (void) Field_varstring::store(buff+HA_KEY_BLOB_LENGTH, length, cs);
+ Field_varstring *res= (Field_varstring*) Field::new_field(root, new_table);
+ if (res)
+ res->length_bytes= length_bytes;
+ return res;
}
+Field *Field_varstring::new_key_field(MEM_ROOT *root,
+ struct st_table *new_table,
+ char *new_ptr, uchar *new_null_ptr,
+ uint new_null_bit)
+{
+ Field_varstring *res;
+ if ((res= (Field_varstring*) Field::new_key_field(root,
+ new_table,
+ new_ptr,
+ new_null_ptr,
+ new_null_bit)))
+ {
+ /* Keys length prefixes are always packed with 2 bytes */
+ res->length_bytes= 2;
+ }
+ return res;
+}
+
/****************************************************************************
** blob type
@@ -5430,14 +6633,14 @@ 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_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
+ :Field_longstr(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
table_arg, cs),
packlength(blob_pack_length)
{
flags|= BLOB_FLAG;
if (table)
- table->blob_fields++;
+ table->s->blob_fields++;
}
@@ -5449,7 +6652,7 @@ void Field_blob::store_length(uint32 number)
break;
case 2:
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int2store(ptr,(unsigned short) number);
}
@@ -5462,7 +6665,7 @@ void Field_blob::store_length(uint32 number)
break;
case 4:
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,number);
}
@@ -5482,7 +6685,7 @@ uint32 Field_blob::get_length(const char *pos)
{
uint16 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
tmp=sint2korr(pos);
else
#endif
@@ -5495,7 +6698,7 @@ uint32 Field_blob::get_length(const char *pos)
{
uint32 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
tmp=uint4korr(pos);
else
#endif
@@ -5553,12 +6756,12 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
else
{
bool was_conversion;
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
uint copy_length;
uint32 not_used;
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if ((was_conversion= String::needs_conversion(length, cs, field_charset,
&not_used)))
{
@@ -5572,7 +6775,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
copy_length= max_data_length();
/*
- copy_length is ok as last argument to well_formed_len as this is never
+ copy_length is OK as last argument to well_formed_len as this is never
used to limit the length of the data. The cut of long data is done with
the 'min()' call below.
*/
@@ -5595,7 +6798,12 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
bmove(ptr+packlength,(char*) &from,sizeof(char*));
}
if (error)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ {
+ if (table->in_use->abort_on_warning)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ else
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+ }
return 0;
}
@@ -5615,18 +6823,19 @@ int Field_blob::store(longlong nr)
return Field_blob::store(value.ptr(), (uint) value.length(), cs);
}
-
double Field_blob::val_real(void)
{
int not_used;
- char *blob;
- char *end_not_used;
+ char *end_not_used, *blob;
+ uint32 length;
+ CHARSET_INFO *cs;
+
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0.0;
- uint32 length=get_length(ptr);
- CHARSET_INFO *cs=charset();
- return my_strntod(cs,blob,length, &end_not_used, &not_used);
+ length= get_length(ptr);
+ cs= charset();
+ return my_strntod(cs, blob, length, &end_not_used, &not_used);
}
@@ -5641,7 +6850,6 @@ longlong Field_blob::val_int(void)
return my_strntoll(charset(),blob,length,10,NULL,&not_used);
}
-
String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
@@ -5658,10 +6866,10 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
uint32 b_length)
{
- return field_charset->coll->strnncoll(field_charset,
- (const uchar*)a, a_length,
- (const uchar*)b, b_length,
- 0);
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*)a, a_length,
+ (const uchar*)b, b_length,
+ 0);
}
@@ -5675,18 +6883,6 @@ int Field_blob::cmp(const char *a_ptr, const char *b_ptr)
}
-int Field_blob::cmp_offset(uint row_offset)
-{
- return Field_blob::cmp(ptr,ptr+row_offset);
-}
-
-
-int Field_blob::cmp_binary_offset(uint row_offset)
-{
- return cmp_binary(ptr, ptr+row_offset);
-}
-
-
int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
uint32 max_length)
{
@@ -5708,8 +6904,7 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
/* The following is used only when comparing a key */
-void Field_blob::get_key_image(char *buff,uint length,
- CHARSET_INFO *cs, imagetype type)
+void Field_blob::get_key_image(char *buff, uint length, imagetype type)
{
uint32 blob_length= get_length(ptr);
char *blob;
@@ -5744,8 +6939,9 @@ void Field_blob::get_key_image(char *buff,uint length,
#endif /*HAVE_SPATIAL*/
get_ptr(&blob);
- uint char_length= length / cs->mbmaxlen;
- char_length= my_charpos(cs, blob, blob + blob_length, char_length);
+ uint char_length= length / field_charset->mbmaxlen;
+ char_length= my_charpos(field_charset, blob, blob + blob_length,
+ char_length);
set_if_smaller(blob_length, char_length);
if ((uint32) length > blob_length)
@@ -5761,10 +6957,11 @@ void Field_blob::get_key_image(char *buff,uint length,
memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
}
-void Field_blob::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
+
+void Field_blob::set_key_image(char *buff,uint length)
{
length= uint2korr(buff);
- (void) Field_blob::store(buff+HA_KEY_BLOB_LENGTH, length, cs);
+ (void) Field_blob::store(buff+HA_KEY_BLOB_LENGTH, length, field_charset);
}
@@ -5777,7 +6974,7 @@ int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
uint char_length= max_key_length / cs->mbmaxlen;
char_length= my_charpos(cs, blob1, blob1+blob_length, char_length);
set_if_smaller(blob_length, char_length);
- return Field_blob::cmp(blob1,min(blob_length, max_key_length),
+ return Field_blob::cmp(blob1, blob_length,
(char*) key_ptr+HA_KEY_BLOB_LENGTH,
uint2korr(key_ptr));
}
@@ -5866,10 +7063,10 @@ const char *Field_blob::unpack(char *to, const char *from)
/* Keys for blobs are like keys on varchars */
-int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
+int Field_blob::pack_cmp(const char *a, const char *b, uint key_length,
+ my_bool insert_or_update)
{
- uint a_length;
- uint b_length;
+ uint a_length, b_length;
if (key_length > 255)
{
a_length=uint2korr(a); a+=2;
@@ -5880,13 +7077,15 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
a_length= (uint) (uchar) *a++;
b_length= (uint) (uchar) *b++;
}
- return my_strnncoll(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length);
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) a, a_length,
+ (const uchar*) b, b_length,
+ insert_or_update);
}
-int Field_blob::pack_cmp(const char *b, uint key_length)
+int Field_blob::pack_cmp(const char *b, uint key_length,
+ my_bool insert_or_update)
{
char *a;
memcpy_fixed(&a,ptr+packlength,sizeof(char*));
@@ -5900,12 +7099,11 @@ int Field_blob::pack_cmp(const char *b, uint key_length)
b_length=uint2korr(b); b+=2;
}
else
- {
b_length= (uint) (uchar) *b++;
- }
- return my_strnncoll(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length);
+ return field_charset->coll->strnncollsp(field_charset,
+ (const uchar*) a, a_length,
+ (const uchar*) b, b_length,
+ insert_or_update);
}
/* Create a packed key that will be used for storage from a MySQL row */
@@ -5915,8 +7113,8 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length)
char *save=ptr;
ptr=(char*) from;
uint32 length=get_length(); // Length of from string
- uint char_length= (field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length;
+ uint char_length= ((field_charset->mbmaxlen > 1) ?
+ max_length/field_charset->mbmaxlen : max_length);
if (length)
get_ptr((char**) &from);
if (length > char_length)
@@ -5974,6 +7172,7 @@ const char *Field_blob::unpack_key(char *to, const char *from, uint max_length)
return from + length;
}
+
/* Create a packed key that will be used for storage from a MySQL key */
char *Field_blob::pack_key_from_key_image(char *to, const char *from,
@@ -5990,14 +7189,15 @@ char *Field_blob::pack_key_from_key_image(char *to, const char *from,
return to+length;
}
+
uint Field_blob::packed_col_length(const char *data_ptr, uint length)
{
if (length > 255)
return uint2korr(data_ptr)+2;
- else
- return (uint) ((uchar) *data_ptr)+1;
+ return (uint) ((uchar) *data_ptr)+1;
}
+
uint Field_blob::max_packed_col_length(uint max_length)
{
return (max_length > 255 ? 2 : 1)+max_length;
@@ -6006,8 +7206,7 @@ uint Field_blob::max_packed_col_length(uint max_length)
#ifdef HAVE_SPATIAL
-void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
- imagetype type)
+void Field_geom::get_key_image(char *buff, uint length, imagetype type)
{
char *blob;
const char *dummy;
@@ -6036,11 +7235,6 @@ void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
}
-void Field_geom::set_key_image(char *buff, uint length, CHARSET_INFO *cs)
-{
- Field_blob::set_key_image(buff, length, cs);
-}
-
void Field_geom::sql_type(String &res) const
{
CHARSET_INFO *cs= &my_charset_latin1;
@@ -6073,12 +7267,38 @@ void Field_geom::sql_type(String &res) const
}
+int Field_geom::store(double nr)
+{
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+}
+
+
+int Field_geom::store(longlong nr)
+{
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+}
+
+
+int Field_geom::store_decimal(const my_decimal *)
+{
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+}
+
+
int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
{
if (!length)
bzero(ptr, Field_blob::pack_length());
else
{
+ if (from == Geometry::bad_geometry_data.ptr())
+ goto err;
// Check given WKB
uint32 wkb_type;
if (length < SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE*2)
@@ -6086,7 +7306,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
wkb_type= uint4korr(from + WKB_HEADER_SIZE);
if (wkb_type < (uint32) Geometry::wkb_point ||
wkb_type > (uint32) Geometry::wkb_end)
- return -1;
+ goto err;
Field_blob::store_length(length);
if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
{ // Must make a copy
@@ -6099,6 +7319,8 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
err:
bzero(ptr, Field_blob::pack_length());
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
return -1;
}
@@ -6127,7 +7349,7 @@ void Field_enum::store_type(ulonglong value)
case 1: ptr[0]= (uchar) value; break;
case 2:
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int2store(ptr,(unsigned short) value);
}
@@ -6138,7 +7360,7 @@ void Field_enum::store_type(ulonglong value)
case 3: int3store(ptr,(long) value); break;
case 4:
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int4store(ptr,value);
}
@@ -6148,7 +7370,7 @@ void Field_enum::store_type(ulonglong value)
break;
case 8:
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
{
int8store(ptr,value);
}
@@ -6168,10 +7390,10 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
{
int err= 0;
uint32 not_used;
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if (String::needs_conversion(length, cs, field_charset, &not_used))
{
uint dummy_errors;
@@ -6193,11 +7415,11 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
if (err || end != from+length || tmp > typelib->count)
{
tmp=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
}
}
else
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
}
store_type((ulonglong) tmp);
return err;
@@ -6215,7 +7437,7 @@ int Field_enum::store(longlong nr)
int error= 0;
if ((uint) nr > typelib->count || nr == 0)
{
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
nr=0;
error=1;
}
@@ -6239,7 +7461,7 @@ longlong Field_enum::val_int(void)
{
uint16 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
tmp=sint2korr(ptr);
else
#endif
@@ -6252,7 +7474,7 @@ longlong Field_enum::val_int(void)
{
uint32 tmp;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
tmp=uint4korr(ptr);
else
#endif
@@ -6263,7 +7485,7 @@ longlong Field_enum::val_int(void)
{
longlong tmp;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
tmp=sint8korr(ptr);
else
#endif
@@ -6352,10 +7574,10 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
char *not_used;
uint not_used2;
uint32 not_used_offset;
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if (String::needs_conversion(length, cs, field_charset, &not_used_offset))
{
uint dummy_errors;
@@ -6374,11 +7596,11 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
{
tmp=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
}
}
else if (got_warning)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
store_type(tmp);
return err;
}
@@ -6391,7 +7613,7 @@ int Field_set::store(longlong nr)
(longlong) 1))
{
nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
error=1;
}
store_type((ulonglong) nr);
@@ -6490,8 +7712,321 @@ bool Field_num::eq_def(Field *field)
}
+/*
+ Bit field.
+
+ We store the first 0 - 6 uneven bits among the null bits
+ at the start of the record. The rest bytes are stored in
+ the record itself.
+
+ For example:
+
+ CREATE TABLE t1 (a int, b bit(17), c bit(21) not null, d bit(8));
+ We would store data as follows in the record:
+
+ Byte Bit
+ 1 7 - reserve for delete
+ 6 - null bit for 'a'
+ 5 - null bit for 'b'
+ 4 - first (high) bit of 'b'
+ 3 - first (high) bit of 'c'
+ 2 - second bit of 'c'
+ 1 - third bit of 'c'
+ 0 - forth bit of 'c'
+ 2 7 - firth bit of 'c'
+ 6 - null bit for 'd'
+ 3 - 6 four bytes for 'a'
+ 7 - 8 two bytes for 'b'
+ 9 - 10 two bytes for 'c'
+ 11 one byte for 'd'
+*/
+
+Field_bit::Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ : Field(ptr_arg, len_arg >> 3, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg),
+ bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7)
+{
+ /*
+ Ensure that Field::eq() can distinguish between two different bit fields.
+ (two bit fields that are not null, may have same ptr and null_ptr)
+ */
+ if (!null_ptr_arg)
+ null_bit= bit_ofs_arg;
+}
+
+
+Field *Field_bit::new_key_field(MEM_ROOT *root,
+ struct st_table *new_table,
+ char *new_ptr, uchar *new_null_ptr,
+ uint new_null_bit)
+{
+ Field_bit *res;
+ if ((res= (Field_bit*) Field::new_key_field(root, new_table,
+ new_ptr, new_null_ptr,
+ new_null_bit)))
+ {
+ /* Move bits normally stored in null_pointer to new_ptr */
+ res->bit_ptr= (uchar*) new_ptr;
+ res->bit_ofs= 0;
+ if (bit_len)
+ res->ptr++; // Store rest of data here
+ }
+ return res;
+}
+
+
+int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
+{
+ int delta;
+
+ for (; !*from && length; from++, length--); // skip left 0's
+ delta= field_length - length;
+
+ if (delta < -1 ||
+ (delta == -1 && (uchar) *from > ((1 << bit_len) - 1)) ||
+ (!bit_len && delta < 0))
+ {
+ set_rec_bits(0xff, bit_ptr, bit_ofs, bit_len);
+ memset(ptr, 0xff, field_length);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ return 1;
+ }
+ /* delta is >= -1 here */
+ if (delta > 0)
+ {
+ if (bit_len)
+ clr_rec_bits(bit_ptr, bit_ofs, bit_len);
+ bzero(ptr, delta);
+ memcpy(ptr + delta, from, length);
+ }
+ else if (delta == 0)
+ {
+ if (bit_len)
+ clr_rec_bits(bit_ptr, bit_ofs, bit_len);
+ memcpy(ptr, from, length);
+ }
+ else
+ {
+ if (bit_len)
+ {
+ set_rec_bits((uchar) *from, bit_ptr, bit_ofs, bit_len);
+ from++;
+ }
+ memcpy(ptr, from, field_length);
+ }
+ return 0;
+}
+
+
+int Field_bit::store(double nr)
+{
+ return (Field_bit::store((longlong) nr));
+}
+
+
+int Field_bit::store(longlong nr)
+{
+ char buf[8];
+
+ mi_int8store(buf, nr);
+ return store(buf, 8, NULL);
+}
+
+
+int Field_bit::store_decimal(const my_decimal *val)
+{
+ int err= 0;
+ longlong i= convert_decimal2longlong(val, 1, &err);
+ return test(err | store(i));
+}
+
+
+double Field_bit::val_real(void)
+{
+ return (double) Field_bit::val_int();
+}
+
+
+longlong Field_bit::val_int(void)
+{
+ ulonglong bits= 0;
+ if (bit_len)
+ {
+ bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ bits<<= (field_length * 8);
+ }
+
+ switch (field_length) {
+ case 0: return bits;
+ case 1: return bits | (ulonglong) (uchar) ptr[0];
+ case 2: return bits | mi_uint2korr(ptr);
+ case 3: return bits | mi_uint3korr(ptr);
+ case 4: return bits | mi_uint4korr(ptr);
+ case 5: return bits | mi_uint5korr(ptr);
+ case 6: return bits | mi_uint6korr(ptr);
+ case 7: return bits | mi_uint7korr(ptr);
+ default: return mi_uint8korr(ptr + field_length - sizeof(longlong));
+ }
+}
+
+
+String *Field_bit::val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused)))
+{
+ char buff[sizeof(longlong)];
+ uint length= min(pack_length(), sizeof(longlong));
+ ulonglong bits= val_int();
+ mi_int8store(buff,bits);
+
+ val_buffer->alloc(length);
+ memcpy_fixed((char*) val_buffer->ptr(), buff+8-length, length);
+ val_buffer->length(length);
+ val_buffer->set_charset(&my_charset_bin);
+ return val_buffer;
+}
+
+
+my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value)
+{
+ int2my_decimal(E_DEC_FATAL_ERROR, val_int(), 1, deciaml_value);
+ return deciaml_value;
+}
+
+
+int Field_bit::key_cmp(const byte *str, uint length)
+{
+ if (bit_len)
+ {
+ int flag;
+ uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ if ((flag= (int) (bits - *(uchar*) str)))
+ return flag;
+ str++;
+ length--;
+ }
+ return memcmp(ptr, str, length);
+}
+
+
+int Field_bit::cmp_offset(uint row_offset)
+{
+ if (bit_len)
+ {
+ int flag;
+ uchar bits_a= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ uchar bits_b= get_rec_bits(bit_ptr + row_offset, bit_ofs, bit_len);
+ if ((flag= (int) (bits_a - bits_b)))
+ return flag;
+ }
+ return memcmp(ptr, ptr + row_offset, field_length);
+}
+
+
+void Field_bit::get_key_image(char *buff, uint length, imagetype type)
+{
+ if (bit_len)
+ {
+ uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ *buff++= bits;
+ length--;
+ }
+ memcpy(buff, ptr, min(length, field_length));
+}
+
+
+void Field_bit::sql_type(String &res) const
+{
+ CHARSET_INFO *cs= res.charset();
+ ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "bit(%d)",
+ (int) field_length * 8 + bit_len);
+ res.length((uint) length);
+}
+
+
+char *Field_bit::pack(char *to, const char *from, uint max_length)
+{
+ uint length= min(field_length + (bit_len > 0), max_length);
+ if (bit_len)
+ {
+ uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ *to++= bits;
+ length--;
+ }
+ memcpy(to, from, length);
+ return to + length;
+}
+
+
+const char *Field_bit::unpack(char *to, const char *from)
+{
+ if (bit_len)
+ {
+ set_rec_bits(*from, bit_ptr, bit_ofs, bit_len);
+ from++;
+ }
+ memcpy(to, from, field_length);
+ return from + field_length;
+}
+
+
+/*
+ Bit field support for non-MyISAM tables.
+*/
+
+Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg,
+ uchar *null_ptr_arg, uchar null_bit_arg,
+ uchar *bit_ptr_arg, uchar bit_ofs_arg,
+ enum utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg)
+ : Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, bit_ptr_arg,
+ bit_ofs_arg, unireg_check_arg, field_name_arg, table_arg),
+ create_length(len_arg)
+{
+ bit_ptr= 0;
+ bit_ofs= 0;
+ bit_len= 0;
+ field_length= ((len_arg + 7) & ~7) / 8;
+}
+
+
+int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
+{
+ int delta;
+ uchar bits= create_length & 7;
+
+ for (; !*from && length; from++, length--); // skip left 0's
+ delta= field_length - length;
+
+ if (delta < 0 ||
+ (delta == 0 && bits && (uint) (uchar) *from >= (uint) (1 << bits)))
+ {
+ memset(ptr, 0xff, field_length);
+ *ptr&= ((1 << bits) - 1); /* set first byte */
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ return 1;
+ }
+ bzero(ptr, delta);
+ memcpy(ptr + delta, from, length);
+ return 0;
+}
+
+
+void Field_bit_as_char::sql_type(String &res) const
+{
+ CHARSET_INFO *cs= res.charset();
+ ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
+ "bit(%d)", (int) create_length);
+ res.length((uint) length);
+}
+
+
/*****************************************************************************
-** Handling of field and create_field
+ Handling of field and create_field
*****************************************************************************/
void create_field::create_length_to_internal_length(void)
@@ -6503,20 +8038,72 @@ void create_field::create_length_to_internal_length(void)
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VARCHAR:
length*= charset->mbmaxlen;
- pack_length= calc_pack_length(sql_type == FIELD_TYPE_VAR_STRING ?
- FIELD_TYPE_STRING : sql_type, length);
+ key_length= length;
+ pack_length= calc_pack_length(sql_type, length);
break;
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
+ /* Pack_length already calculated in sql_parse.cc */
length*= charset->mbmaxlen;
+ key_length= pack_length;
+ break;
+ case MYSQL_TYPE_BIT:
+ if (f_bit_as_char(pack_flag))
+ {
+ key_length= pack_length= ((length + 7) & ~7) / 8;
+ }
+ else
+ {
+ pack_length= length / 8;
+ /* We need one extra byte to store the bits we save among the null bits */
+ key_length= pack_length + test(length & 7);
+ }
+ break;
+ case MYSQL_TYPE_NEWDECIMAL:
+ key_length= pack_length= my_decimal_get_binary_size(length, decimals);
break;
default:
- /* do nothing */
+ key_length= pack_length= calc_pack_length(sql_type, length);
break;
}
}
+
+void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
+ uint32 length_arg, uint32 decimals,
+ bool maybe_null, bool is_unsigned)
+{
+ field_name= "";
+ sql_type= sql_type_arg;
+ length= length_arg;;
+ unireg_check= Field::NONE;
+ interval= 0;
+ charset= &my_charset_bin;
+ geom_type= Field::GEOM_GEOMETRY;
+ pack_flag= (FIELDFLAG_NUMBER |
+ ((decimals & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
+ (maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
+ (is_unsigned ? 0 : FIELDFLAG_DECIMAL));
+}
+
+
+enum_field_types get_blob_type_from_length(ulong length)
+{
+ enum_field_types type;
+ if (length < 256)
+ type= FIELD_TYPE_TINY_BLOB;
+ else if (length < 65536)
+ type= FIELD_TYPE_BLOB;
+ else if (length < 256L*256L*256L)
+ type= FIELD_TYPE_MEDIUM_BLOB;
+ else
+ type= FIELD_TYPE_LONG_BLOB;
+ return type;
+}
+
+
/*
Make a field from the .frm file info
*/
@@ -6524,9 +8111,10 @@ void create_field::create_length_to_internal_length(void)
uint32 calc_pack_length(enum_field_types type,uint32 length)
{
switch (type) {
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_DECIMAL: return (length);
- case FIELD_TYPE_VAR_STRING: return (length+HA_KEY_BLOB_LENGTH);
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case FIELD_TYPE_DECIMAL: return (length);
+ case MYSQL_TYPE_VARCHAR: return (length + (length < 256 ? 1: 2));
case FIELD_TYPE_YEAR:
case FIELD_TYPE_TINY : return 1;
case FIELD_TYPE_SHORT : return 2;
@@ -6547,10 +8135,13 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
case FIELD_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr;
case FIELD_TYPE_SET:
- case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen
- default: return 0;
+ case FIELD_TYPE_ENUM:
+ case FIELD_TYPE_NEWDECIMAL:
+ abort(); return 0; // This shouldn't happen
+ case FIELD_TYPE_BIT: return length / 8;
+ default:
+ return 0;
}
- return 0; // Keep compiler happy
}
@@ -6578,11 +8169,30 @@ Field *make_field(char *ptr, uint32 field_length,
const char *field_name,
struct st_table *table)
{
+ uchar *bit_ptr;
+ uchar bit_offset;
+ LINT_INIT(bit_ptr);
+ LINT_INIT(bit_offset);
+ if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag))
+ {
+ bit_ptr= null_pos;
+ bit_offset= null_bit;
+ if (f_maybe_null(pack_flag)) // if null field
+ {
+ bit_ptr+= (null_bit == 7); // shift bit_ptr and bit_offset
+ bit_offset= (bit_offset + 1) & 7;
+ }
+ }
+
if (!f_maybe_null(pack_flag))
{
null_pos=0;
null_bit=0;
}
+ else
+ {
+ null_bit= ((uchar) 1) << null_bit;
+ }
switch (field_type)
{
@@ -6599,12 +8209,18 @@ Field *make_field(char *ptr, uint32 field_length,
{
if (!f_is_packed(pack_flag))
{
- if (field_type == FIELD_TYPE_STRING ||
+ if (field_type == MYSQL_TYPE_STRING ||
field_type == FIELD_TYPE_DECIMAL || // 3.23 or 4.0 string
- field_type == FIELD_TYPE_VAR_STRING)
+ field_type == MYSQL_TYPE_VAR_STRING)
return new Field_string(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
field_charset);
+ if (field_type == MYSQL_TYPE_VARCHAR)
+ return new Field_varstring(ptr,field_length,
+ HA_VARCHAR_PACKLENGTH(field_length),
+ null_pos,null_bit,
+ unireg_check, field_name, table,
+ field_charset);
return 0; // Error
}
@@ -6642,6 +8258,12 @@ Field *make_field(char *ptr, uint32 field_length,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
+ case FIELD_TYPE_NEWDECIMAL:
+ return new Field_new_decimal(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_decimals(pack_flag),
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
case FIELD_TYPE_FLOAT:
return new Field_float(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
@@ -6700,6 +8322,12 @@ Field *make_field(char *ptr, uint32 field_length,
unireg_check, field_name, table, field_charset);
case FIELD_TYPE_NULL:
return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset);
+ case FIELD_TYPE_BIT:
+ return f_bit_as_char(pack_flag) ?
+ new Field_bit_as_char(ptr, field_length, null_pos, null_bit, bit_ptr,
+ bit_offset, unireg_check, field_name, table) :
+ new Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr,
+ bit_offset, unireg_check, field_name, table);
default: // Impossible (Wrong version)
break;
}
@@ -6717,44 +8345,55 @@ create_field::create_field(Field *old_field,Field *orig_field)
flags= old_field->flags;
unireg_check=old_field->unireg_check;
pack_length=old_field->pack_length();
+ key_length= old_field->key_length();
sql_type= old_field->real_type();
charset= old_field->charset(); // May be NULL ptr
comment= old_field->comment;
+ decimals= old_field->decimals();
/* Fix if the original table had 4 byte pointer blobs */
if (flags & BLOB_FLAG)
- pack_length= (pack_length- old_field->table->blob_ptr_size +
+ pack_length= (pack_length- old_field->table->s->blob_ptr_size +
portable_sizeof_char_ptr);
- switch (sql_type)
- {
- case FIELD_TYPE_BLOB:
- switch (pack_length - portable_sizeof_char_ptr)
- {
- case 1: sql_type= FIELD_TYPE_TINY_BLOB; break;
- case 2: sql_type= FIELD_TYPE_BLOB; break;
- case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break;
- default: sql_type= FIELD_TYPE_LONG_BLOB; break;
- }
- length=(length+charset->mbmaxlen-1)/charset->mbmaxlen; // QQ: Probably not needed
- break;
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
- length=(length+charset->mbmaxlen-1)/charset->mbmaxlen;
- break;
- default:
- break;
- }
-
- decimals= old_field->decimals();
- if (sql_type == FIELD_TYPE_STRING)
- {
+ switch (sql_type) {
+ case FIELD_TYPE_BLOB:
+ switch (pack_length - portable_sizeof_char_ptr) {
+ case 1: sql_type= FIELD_TYPE_TINY_BLOB; break;
+ case 2: sql_type= FIELD_TYPE_BLOB; break;
+ case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break;
+ default: sql_type= FIELD_TYPE_LONG_BLOB; break;
+ }
+ length=(length+charset->mbmaxlen-1) / charset->mbmaxlen;
+ key_length/= charset->mbmaxlen;
+ break;
+ case MYSQL_TYPE_STRING:
/* Change CHAR -> VARCHAR if dynamic record length */
- sql_type=old_field->type();
- decimals=0;
+ if (old_field->type() == MYSQL_TYPE_VAR_STRING)
+ sql_type= MYSQL_TYPE_VARCHAR;
+ /* fall through */
+
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ /* This is corrected in create_length_to_internal_length */
+ length= (length+charset->mbmaxlen-1) / charset->mbmaxlen;
+ break;
+#ifdef HAVE_SPATIAL
+ case FIELD_TYPE_GEOMETRY:
+ geom_type= ((Field_geom*)old_field)->geom_type;
+ break;
+#endif
+ case FIELD_TYPE_BIT:
+ length= (old_field->key_type() == HA_KEYTYPE_BIT) ?
+ ((Field_bit *) old_field)->bit_len + length * 8 :
+ ((Field_bit_as_char *) old_field)->create_length;
+ break;
+ default:
+ break;
}
+
if (flags & (ENUM_FLAG | SET_FLAG))
interval= ((Field_enum*) old_field)->typelib;
else
@@ -6764,36 +8403,61 @@ create_field::create_field(Field *old_field,Field *orig_field)
old_field->ptr && orig_field)
{
char buff[MAX_FIELD_WIDTH],*pos;
- String tmp(buff,sizeof(buff), charset);
+ String tmp(buff,sizeof(buff), charset), *res;
+ my_ptrdiff_t diff;
/* Get the value from default_values */
- my_ptrdiff_t diff= (my_ptrdiff_t) (orig_field->table->rec_buff_length*2);
+ diff= (my_ptrdiff_t) (orig_field->table->s->default_values-
+ orig_field->table->record[0]);
orig_field->move_field(diff); // Points now at default_values
bool is_null=orig_field->is_real_null();
- orig_field->val_str(&tmp);
+ res= orig_field->val_str(&tmp);
orig_field->move_field(-diff); // Back to record[0]
if (!is_null)
{
- pos= (char*) sql_memdup(tmp.ptr(),tmp.length()+1);
- pos[tmp.length()]=0;
- def= new Item_string(pos, tmp.length(), charset);
+ pos= (char*) sql_strmake(res->ptr(), res->length());
+ def= new Item_string(pos, res->length(), charset);
}
}
-#ifdef HAVE_SPATIAL
- if (sql_type == FIELD_TYPE_GEOMETRY)
+}
+
+
+/*
+ maximum possible display length for blob
+
+ SYNOPSIS
+ Field_blob::max_length()
+
+ RETURN
+ length
+*/
+uint32 Field_blob::max_length()
+{
+ switch (packlength)
{
- geom_type= ((Field_geom*)old_field)->geom_type;
+ case 1:
+ return 255;
+ case 2:
+ return 65535;
+ case 3:
+ return 16777215;
+ case 4:
+ return (uint32) 4294967295U;
+ default:
+ DBUG_ASSERT(0); // we should never go here
+ return 0;
}
-#endif
}
-/* Warning handling */
+/*****************************************************************************
+ Warning handling
+*****************************************************************************/
/*
Produce warning or note about data saved into field
- SYNOPSYS
+ SYNOPSIS
set_warning()
level - level of message (Note/Warning/Error)
code - error code of message to be produced
@@ -6804,18 +8468,20 @@ create_field::create_field(Field *old_field,Field *orig_field)
if count_cuted_fields == FIELD_CHECK_IGNORE for current thread.
RETURN VALUE
- true - if count_cuted_fields == FIELD_CHECK_IGNORE
- false - otherwise
+ 1 if count_cuted_fields == FIELD_CHECK_IGNORE
+ 0 otherwise
*/
+
bool
-Field::set_warning(const uint level, const uint code, int cuted_increment)
+Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
+ int cuted_increment)
{
THD *thd= table->in_use;
if (thd->count_cuted_fields)
{
thd->cuted_fields+= cuted_increment;
- push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level,
- code, ER(code), field_name, thd->row_count);
+ push_warning_printf(thd, level, code, ER(code), field_name,
+ thd->row_count);
return 0;
}
return 1;
@@ -6825,8 +8491,8 @@ Field::set_warning(const uint level, const uint code, int cuted_increment)
/*
Produce warning or note about datetime string data saved into field
- SYNOPSYS
- set_warning()
+ SYNOPSIS
+ set_datime_warning()
level - level of message (Note/Warning/Error)
code - error code of message to be produced
str - string value which we tried to save
@@ -6839,20 +8505,23 @@ Field::set_warning(const uint level, const uint code, int cuted_increment)
fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current
thread.
*/
+
void
-Field::set_datetime_warning(const uint level, const uint code,
+Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
const char *str, uint str_length,
timestamp_type ts_type, int cuted_increment)
{
- if (set_warning(level, code, cuted_increment))
- make_truncated_value_warning(table->in_use, str, str_length, ts_type);
+ if (table->in_use->really_abort_on_warning() ||
+ set_warning(level, code, cuted_increment))
+ make_truncated_value_warning(table->in_use, str, str_length, ts_type,
+ field_name);
}
/*
Produce warning or note about integer datetime value saved into field
- SYNOPSYS
+ SYNOPSIS
set_warning()
level - level of message (Note/Warning/Error)
code - error code of message to be produced
@@ -6865,17 +8534,19 @@ Field::set_datetime_warning(const uint level, const uint code,
fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current
thread.
*/
+
void
-Field::set_datetime_warning(const uint level, const uint code,
+Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
longlong nr, timestamp_type ts_type,
int cuted_increment)
{
- if (set_warning(level, code, cuted_increment))
+ if (table->in_use->really_abort_on_warning() ||
+ set_warning(level, code, cuted_increment))
{
char str_nr[22];
char *str_end= longlong10_to_str(nr, str_nr, -10);
make_truncated_value_warning(table->in_use, str_nr, str_end - str_nr,
- ts_type);
+ ts_type, field_name);
}
}
@@ -6883,7 +8554,7 @@ Field::set_datetime_warning(const uint level, const uint code,
/*
Produce warning or note about double datetime data saved into field
- SYNOPSYS
+ SYNOPSIS
set_warning()
level - level of message (Note/Warning/Error)
code - error code of message to be produced
@@ -6895,42 +8566,18 @@ Field::set_datetime_warning(const uint level, const uint code,
fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current
thread.
*/
+
void
-Field::set_datetime_warning(const uint level, const uint code,
+Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
double nr, timestamp_type ts_type)
{
- if (set_warning(level, code, 1))
+ if (table->in_use->really_abort_on_warning() ||
+ set_warning(level, code, 1))
{
/* DBL_DIG is enough to print '-[digits].E+###' */
char str_nr[DBL_DIG + 8];
uint str_len= my_sprintf(str_nr, (str_nr, "%g", nr));
- make_truncated_value_warning(table->in_use, str_nr, str_len, ts_type);
- }
-}
-
-/*
- maximum possible display length for blob
-
- SYNOPSIS
- Field_blob::max_length()
-
- RETURN
- length
-*/
-uint32 Field_blob::max_length()
-{
- switch (packlength)
- {
- case 1:
- return 255;
- case 2:
- return 65535;
- case 3:
- return 16777215;
- case 4:
- return (uint32) 4294967295U;
- default:
- DBUG_ASSERT(0); // we should never go here
- return 0;
+ make_truncated_value_warning(table->in_use, str_nr, str_len, ts_type,
+ field_name);
}
}
diff --git a/sql/field.h b/sql/field.h
index f19771c3f9c..ac9c2f351b3 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -48,11 +48,7 @@ class Field
void operator=(Field &);
public:
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
- static void operator delete(void *ptr_arg, size_t size) {
-#ifdef SAFEMALLOC
- bfill(ptr_arg, size, 0x8F);
-#endif
- }
+ static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); }
char *ptr; // Position to field in record
uchar *null_ptr; // Byte where null_bit is
@@ -62,9 +58,9 @@ public:
*/
struct st_table *table; // Pointer for table
struct st_table *orig_table; // Pointer to original table
- const char *table_name,*field_name;
+ const char **table_name, *field_name;
LEX_STRING comment;
- ulong query_id; // For quick test of used fields
+ query_id_t query_id; // For quick test of used fields
/* Field is part of the following keys */
key_map key_start,part_of_key,part_of_sortkey;
/*
@@ -100,9 +96,11 @@ public:
virtual int store(const char *to,uint length,CHARSET_INFO *cs)=0;
virtual int store(double nr)=0;
virtual int store(longlong nr)=0;
- virtual void store_time(TIME *ltime,timestamp_type t_type);
+ virtual int store_decimal(const my_decimal *d)=0;
+ virtual int store_time(TIME *ltime, timestamp_type t_type);
virtual double val_real(void)=0;
virtual longlong val_int(void)=0;
+ virtual my_decimal *val_decimal(my_decimal *);
inline String *val_str(String *str) { return val_str(str, str); }
/*
val_str(buf1, buf2) gets two buffers and should use them as follows:
@@ -117,19 +115,25 @@ public:
This trickery is used to decrease a number of malloc calls.
*/
virtual String *val_str(String*,String *)=0;
+ String *val_int_as_str(String *val_buffer, my_bool unsigned_flag);
virtual Item_result result_type () const=0;
virtual Item_result cmp_type () const { return result_type(); }
virtual Item_result cast_to_int_type () const { return result_type(); }
static enum_field_types field_type_merge(enum_field_types, enum_field_types);
static Item_result result_merge_type(enum_field_types);
- bool eq(Field *field) { return ptr == field->ptr && null_ptr == field->null_ptr; }
+ bool eq(Field *field)
+ {
+ return (ptr == field->ptr && null_ptr == field->null_ptr &&
+ null_bit == field->null_bit);
+ }
virtual bool eq_def(Field *field);
virtual uint32 pack_length() const { return (uint32) field_length; }
+ virtual uint32 pack_length_in_rec() const { return pack_length(); }
virtual void reset(void) { bzero(ptr,pack_length()); }
virtual void reset_fields() {}
virtual void set_default()
{
- my_ptrdiff_t offset = (my_ptrdiff_t) (table->default_values -
+ my_ptrdiff_t offset = (my_ptrdiff_t) (table->s->default_values -
table->record[0]);
memcpy(ptr, ptr + offset, pack_length());
if (null_ptr)
@@ -146,10 +150,9 @@ public:
virtual int cmp(const char *,const char *)=0;
virtual int cmp_binary(const char *a,const char *b, uint32 max_length=~0L)
{ return memcmp(a,b,pack_length()); }
- virtual int cmp_offset(uint row_offset)
- { return memcmp(ptr,ptr+row_offset,pack_length()); }
- virtual int cmp_binary_offset(uint row_offset)
- { return memcmp(ptr,ptr+row_offset,pack_length()); }
+ int cmp_offset(uint row_offset) { return cmp(ptr,ptr+row_offset); }
+ int cmp_binary_offset(uint row_offset)
+ { return cmp_binary(ptr, ptr+row_offset); };
virtual int key_cmp(const byte *a,const byte *b)
{ return cmp((char*) a,(char*) b); }
virtual int key_cmp(const byte *str, uint length)
@@ -179,7 +182,7 @@ public:
{ if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; }
inline bool maybe_null(void) { return null_ptr != 0 || table->maybe_null; }
inline bool real_maybe_null(void) { return null_ptr != 0; }
- virtual void make_field(Send_field *)=0;
+ virtual void make_field(Send_field *);
virtual void sort_string(char *buff,uint length)=0;
virtual bool optimize_range(uint idx, uint part);
/*
@@ -191,28 +194,11 @@ public:
*/
virtual bool can_be_compared_as_longlong() const { return FALSE; }
virtual void free() {}
- Field *new_field(MEM_ROOT *root, struct st_table *new_table)
- {
- Field *tmp= (Field*) memdup_root(root,(char*) this,size_of());
- if (tmp)
- {
- if (tmp->table->maybe_null)
- tmp->flags&= ~NOT_NULL_FLAG;
- tmp->table= new_table;
- tmp->key_start.init(0);
- tmp->part_of_key.init(0);
- tmp->part_of_sortkey.init(0);
- tmp->unireg_check=Field::NONE;
- tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
- ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
-#ifdef PROBABLY_WRONG
- tmp->table_name= new_table->table_name;
-#endif
- tmp->reset_fields();
- }
- return tmp;
- }
- inline void move_field(char *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
+ virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table);
+ virtual Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
+ char *new_ptr, uchar *new_null_ptr,
+ uint new_null_bit);
+ virtual void move_field(char *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
{
ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
}
@@ -227,11 +213,10 @@ public:
{ memcpy(buff,ptr,length); }
inline void set_image(char *buff,uint length, CHARSET_INFO *cs)
{ memcpy(ptr,buff,length); }
- virtual void get_key_image(char *buff,uint length, CHARSET_INFO *cs,
- imagetype type)
- { get_image(buff,length,cs); }
- virtual void set_key_image(char *buff,uint length, CHARSET_INFO *cs)
- { set_image(buff,length,cs); }
+ virtual void get_key_image(char *buff, uint length, imagetype type)
+ { get_image(buff,length, &my_charset_bin); }
+ virtual void set_key_image(char *buff,uint length)
+ { set_image(buff,length, &my_charset_bin); }
inline longlong val_int_offset(uint row_offset)
{
ptr+=row_offset;
@@ -239,6 +224,17 @@ public:
ptr-=row_offset;
return tmp;
}
+
+ inline String *val_str(String *str, char *new_ptr)
+ {
+ char *old_ptr= ptr;
+ ptr= new_ptr;
+ val_str(str);
+ ptr= old_ptr;
+ return str;
+ }
+ bool quote_data(String *unquoted_string);
+ bool needs_quotes(void);
virtual bool send_binary(Protocol *protocol);
virtual char *pack(char* to, const char *from, uint max_length=~(uint) 0)
{
@@ -270,9 +266,11 @@ public:
virtual uint max_packed_col_length(uint max_length)
{ return max_length;}
- virtual int pack_cmp(const char *a,const char *b, uint key_length_arg)
+ virtual int pack_cmp(const char *a,const char *b, uint key_length_arg,
+ my_bool insert_or_update)
{ return cmp(a,b); }
- virtual int pack_cmp(const char *b, uint key_length_arg)
+ virtual int pack_cmp(const char *b, uint key_length_arg,
+ my_bool insert_or_update)
{ return cmp(ptr,b); }
uint offset(); // Should be inline ...
void copy_from_tmp(int offset);
@@ -283,18 +281,30 @@ public:
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
virtual void set_charset(CHARSET_INFO *charset) { }
- bool set_warning(const unsigned int level, const unsigned int code,
+ bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
int cuted_increment);
- void set_datetime_warning(const uint level, const uint code,
+ bool check_int(const char *str, int length, const char *int_end,
+ CHARSET_INFO *cs);
+ void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code,
const char *str, uint str_len,
timestamp_type ts_type, int cuted_increment);
- void set_datetime_warning(const uint level, const uint code,
+ void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code,
longlong nr, timestamp_type ts_type,
int cuted_increment);
- void set_datetime_warning(const uint level, const uint code,
+ void set_datetime_warning(MYSQL_ERROR::enum_warning_level, const uint code,
double nr, timestamp_type ts_type);
+ inline bool check_overflow(int op_result)
+ {
+ return (op_result == E_DEC_OVERFLOW);
+ }
+ int warn_if_overflow(int op_result);
/* maximum possible display length */
virtual uint32 max_length()= 0;
+ /* length of field value symbolic representation (in bytes) */
+ virtual uint32 representation_length() { return field_length; }
+ /* convert decimal to longlong with overflow check */
+ longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag,
+ int *err);
friend bool reopen_table(THD *,struct st_table *,bool);
friend int cre_myisam(my_string name, register TABLE *form, uint options,
ulonglong auto_increment_value);
@@ -321,16 +331,7 @@ public:
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
struct st_table *table_arg,
- uint8 dec_arg,bool zero_arg,bool unsigned_arg)
- :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg),
- dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg)
- {
- if (zerofill)
- flags|=ZEROFILL_FLAG;
- if (unsigned_flag)
- flags|=UNSIGNED_FLAG;
- }
+ uint8 dec_arg, bool zero_arg, bool unsigned_arg);
Item_result result_type () const { return REAL_RESULT; }
void prepend_zeros(String *value);
void add_zerofill_and_unsigned(String &res) const;
@@ -339,6 +340,8 @@ public:
uint decimals() const { return (uint) dec; }
uint size_of() const { return sizeof(*this); }
bool eq_def(Field *field);
+ int store_decimal(const my_decimal *);
+ my_decimal *val_decimal(my_decimal *);
};
@@ -349,39 +352,69 @@ public:
Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
- struct st_table *table_arg,CHARSET_INFO *charset)
- :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg)
- {
- field_charset=charset;
- if (charset->state & MY_CS_BINSORT)
- flags|=BINARY_FLAG;
- }
+ struct st_table *table_arg, CHARSET_INFO *charset);
Item_result result_type () const { return STRING_RESULT; }
uint decimals() const { return NOT_FIXED_DEC; }
int store(double nr);
int store(longlong nr)=0;
+ int store_decimal(const my_decimal *);
int store(const char *to,uint length,CHARSET_INFO *cs)=0;
- void make_field(Send_field *);
uint size_of() const { return sizeof(*this); }
CHARSET_INFO *charset(void) const { return field_charset; }
void set_charset(CHARSET_INFO *charset) { field_charset=charset; }
bool binary() const { return field_charset == &my_charset_bin; }
uint32 max_length() { return field_length; }
friend class create_field;
+ my_decimal *val_decimal(my_decimal *);
+};
+
+
+/* base class for Field_string, Field_varstring and Field_blob */
+
+class Field_longstr :public Field_str
+{
+public:
+ Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg,CHARSET_INFO *charset)
+ :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, table_arg, charset)
+ {}
+
+ my_decimal *val_decimal(my_decimal *);
+ int store_decimal(const my_decimal *d);
};
+/* base class for float and double and decimal (old one) */
+class Field_real :public Field_num {
+public:
+
+ Field_real(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg,
+ uint8 dec_arg, bool zero_arg, bool unsigned_arg)
+ :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, table_arg, dec_arg, zero_arg, unsigned_arg)
+ {}
+
-class Field_decimal :public Field_num {
+ int store_decimal(const my_decimal *);
+ my_decimal *val_decimal(my_decimal *);
+};
+
+
+class Field_decimal :public Field_real {
public:
Field_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg,
- dec_arg, zero_arg,unsigned_arg)
+ :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg,
+ dec_arg, zero_arg, unsigned_arg)
{}
enum_field_types type() const { return FIELD_TYPE_DECIMAL;}
enum ha_base_keytype key_type() const
@@ -402,6 +435,45 @@ public:
};
+/* New decimal/numeric field which use fixed point arithmetic */
+class Field_new_decimal :public Field_num {
+public:
+ uint bin_size;
+ Field_new_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg,
+ uint8 dec_arg, bool zero_arg, bool unsigned_arg);
+ Field_new_decimal(uint32 len_arg, bool maybe_null_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg, uint8 dec_arg);
+ enum_field_types type() const { return FIELD_TYPE_NEWDECIMAL;}
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ Item_result result_type () const { return DECIMAL_RESULT; }
+ void reset(void);
+ bool store_value(const my_decimal *decimal_value);
+ void set_value_on_overflow(my_decimal *decimal_value, bool sign);
+ int store(const char *to, uint length, CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
+ int store_decimal(const my_decimal *);
+ double val_real(void);
+ longlong val_int(void);
+ my_decimal *val_decimal(my_decimal *);
+ String *val_str(String*, String *);
+ int cmp(const char *, const char*);
+ void sort_string(char *buff, uint length);
+ bool zero_pack() const { return 0; }
+ void sql_type(String &str) const;
+ uint32 max_length()
+ { return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); }
+ uint32 representation_length()
+ { return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); };
+ uint size_of() const { return sizeof(*this); }
+ uint32 pack_length() const { return (uint32) bin_size; }
+};
+
+
class Field_tiny :public Field_num {
public:
Field_tiny(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
@@ -575,21 +647,22 @@ public:
};
#endif
-class Field_float :public Field_num {
+
+class Field_float :public Field_real {
public:
Field_float(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
- uint8 dec_arg,bool zero_arg,bool unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg,
- dec_arg, zero_arg,unsigned_arg)
+ uint8 dec_arg,bool zero_arg,bool unsigned_arg)
+ :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg,
+ dec_arg, zero_arg, unsigned_arg)
{}
Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
struct st_table *table_arg, uint8 dec_arg)
- :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
- NONE, field_name_arg, table_arg,dec_arg,0,0)
+ :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
+ NONE, field_name_arg, table_arg, dec_arg, 0, 0)
{}
enum_field_types type() const { return FIELD_TYPE_FLOAT;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; }
@@ -609,21 +682,21 @@ public:
};
-class Field_double :public Field_num {
+class Field_double :public Field_real {
public:
Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg,
- dec_arg, zero_arg,unsigned_arg)
+ :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg,
+ dec_arg, zero_arg, unsigned_arg)
{}
Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
struct st_table *table_arg, uint8 dec_arg)
- :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
- NONE, field_name_arg, table_arg,dec_arg,0,0)
+ :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
+ NONE, field_name_arg, table_arg, dec_arg, 0, 0)
{}
enum_field_types type() const { return FIELD_TYPE_DOUBLE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
@@ -643,7 +716,7 @@ public:
};
-/* Everything saved in this will disapper. It will always return NULL */
+/* Everything saved in this will disappear. It will always return NULL */
class Field_null :public Field_str {
static uchar null[1];
@@ -659,9 +732,11 @@ public:
{ null[0]=1; return 0; }
int store(double nr) { null[0]=1; return 0; }
int store(longlong nr) { null[0]=1; return 0; }
+ int store_decimal(const my_decimal *d) { null[0]=1; return 0; }
void reset(void) {}
double val_real(void) { return 0.0;}
longlong val_int(void) { return 0;}
+ my_decimal *val_decimal(my_decimal *) { return 0; }
String *val_str(String *value,String *value2)
{ value2->length(0); return value2;}
int cmp(const char *a, const char *b) { return 0;}
@@ -712,7 +787,7 @@ public:
if ((*null_value= is_null()))
return 0;
#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
+ if (table->s->db_low_byte_first)
return sint4korr(ptr);
#endif
long tmp;
@@ -793,7 +868,7 @@ public:
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr);
- void store_time(TIME *ltime,timestamp_type type);
+ int store_time(TIME *ltime, timestamp_type type);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; }
double val_real(void);
longlong val_int(void);
@@ -825,6 +900,7 @@ public:
enum_field_types type() const { return FIELD_TYPE_TIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
enum Item_result cmp_type () const { return INT_RESULT; }
+ int store_time(TIME *ltime, timestamp_type type);
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr);
@@ -864,7 +940,7 @@ public:
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr);
- void store_time(TIME *ltime,timestamp_type type);
+ int store_time(TIME *ltime, timestamp_type type);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; }
double val_real(void);
longlong val_int(void);
@@ -881,24 +957,26 @@ public:
};
-class Field_string :public Field_str {
+class Field_string :public Field_longstr {
public:
Field_string(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg,cs) {};
+ :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg, cs) {};
Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg, cs) {};
+ struct st_table *table_arg, CHARSET_INFO *cs)
+ :Field_longstr((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ NONE, field_name_arg, table_arg, cs) {};
enum_field_types type() const
{
- return ((table && table->db_create_options & HA_OPTION_PACK_RECORD &&
- field_length >= 4) ?
- FIELD_TYPE_VAR_STRING : FIELD_TYPE_STRING);
+ return ((orig_table &&
+ orig_table->s->db_create_options & HA_OPTION_PACK_RECORD &&
+ field_length >= 4) &&
+ orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR ?
+ MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING);
}
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
@@ -915,39 +993,52 @@ public:
void sql_type(String &str) const;
char *pack(char *to, const char *from, uint max_length=~(uint) 0);
const char *unpack(char* to, const char *from);
- int pack_cmp(const char *a,const char *b,uint key_length);
- int pack_cmp(const char *b,uint key_length);
+ int pack_cmp(const char *a,const char *b,uint key_length,
+ my_bool insert_or_update);
+ int pack_cmp(const char *b,uint key_length,my_bool insert_or_update);
uint packed_col_length(const char *to, uint length);
uint max_packed_col_length(uint max_length);
uint size_of() const { return sizeof(*this); }
enum_field_types real_type() const { return FIELD_TYPE_STRING; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
+ Field *new_field(MEM_ROOT *root, struct st_table *new_table);
};
-class Field_varstring :public Field_str {
+class Field_varstring :public Field_longstr {
public:
- Field_varstring(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
+ /* Store number of bytes used to store length (1 or 2) */
+ uint32 length_bytes;
+ Field_varstring(char *ptr_arg,
+ uint32 len_arg, uint length_bytes_arg,
+ uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg, cs)
- {}
+ :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg, cs),
+ length_bytes(length_bytes_arg)
+ {
+ if (table)
+ table->s->varchar_fields++;
+ }
Field_varstring(uint32 len_arg,bool maybe_null_arg,
- const char *field_name_arg,
- struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg, cs)
- {}
+ const char *field_name_arg,
+ struct st_table *table_arg, CHARSET_INFO *cs)
+ :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ NONE, field_name_arg, table_arg, cs),
+ length_bytes(len_arg < 256 ? 1 :2)
+ {
+ if (table)
+ table->s->varchar_fields++;
+ }
- enum_field_types type() const { return FIELD_TYPE_VAR_STRING; }
- enum ha_base_keytype key_type() const
- { return binary() ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; }
+ enum_field_types type() const { return MYSQL_TYPE_VARCHAR; }
+ enum ha_base_keytype key_type() const;
bool zero_pack() const { return 0; }
- void reset(void) { bzero(ptr,field_length+2); }
- uint32 pack_length() const { return (uint32) field_length+2; }
+ void reset(void) { bzero(ptr,field_length+length_bytes); }
+ uint32 pack_length() const { return (uint32) field_length+length_bytes; }
uint32 key_length() const { return (uint32) field_length; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(longlong nr);
@@ -957,24 +1048,34 @@ public:
String *val_str(String*,String *);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
- void get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type);
- void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
+ void get_key_image(char *buff,uint length, imagetype type);
+ void set_key_image(char *buff,uint length);
void sql_type(String &str) const;
char *pack(char *to, const char *from, uint max_length=~(uint) 0);
char *pack_key(char *to, const char *from, uint max_length);
+ char *pack_key_from_key_image(char* to, const char *from, uint max_length);
const char *unpack(char* to, const char *from);
- int pack_cmp(const char *a, const char *b, uint key_length);
- int pack_cmp(const char *b, uint key_length);
+ const char *unpack_key(char* to, const char *from, uint max_length);
+ int pack_cmp(const char *a, const char *b, uint key_length,
+ my_bool insert_or_update);
+ int pack_cmp(const char *b, uint key_length,my_bool insert_or_update);
+ int cmp_binary(const char *a,const char *b, uint32 max_length=~0L);
+ int key_cmp(const byte *,const byte*);
+ int key_cmp(const byte *str, uint length);
uint packed_col_length(const char *to, uint length);
uint max_packed_col_length(uint max_length);
uint size_of() const { return sizeof(*this); }
- enum_field_types real_type() const { return FIELD_TYPE_VAR_STRING; }
+ enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
+ Field *new_field(MEM_ROOT *root, struct st_table *new_table);
+ Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
+ char *new_ptr, uchar *new_null_ptr,
+ uint new_null_bit);
};
-class Field_blob :public Field_str {
+class Field_blob :public Field_longstr {
protected:
uint packlength;
String value; // For temporaries
@@ -985,15 +1086,15 @@ public:
CHARSET_INFO *cs);
Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg, cs),
+ :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ NONE, field_name_arg, table_arg, cs),
packlength(4)
{
flags|= BLOB_FLAG;
}
enum_field_types type() const { return FIELD_TYPE_BLOB;}
enum ha_base_keytype key_type() const
- { return binary() ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; }
+ { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr);
@@ -1002,15 +1103,13 @@ public:
String *val_str(String*,String *);
int cmp(const char *,const char*);
int cmp(const char *a, uint32 a_length, const char *b, uint32 b_length);
- int cmp_offset(uint offset);
int cmp_binary(const char *a,const char *b, uint32 max_length=~0L);
- int cmp_binary_offset(uint row_offset);
int key_cmp(const byte *,const byte*);
int key_cmp(const byte *str, uint length);
uint32 key_length() const { return 0; }
void sort_string(char *buff,uint length);
uint32 pack_length() const
- { return (uint32) (packlength+table->blob_ptr_size); }
+ { return (uint32) (packlength+table->s->blob_ptr_size); }
inline uint32 max_data_length() const
{
return (uint32) (((ulonglong) 1 << (packlength*8)) -1);
@@ -1036,8 +1135,8 @@ public:
store_length(length);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
- void get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type);
- void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
+ void get_key_image(char *buff,uint length, imagetype type);
+ void set_key_image(char *buff,uint length);
void sql_type(String &str) const;
inline bool copy()
{ char *tmp;
@@ -1051,12 +1150,13 @@ public:
return 0;
}
char *pack(char *to, const char *from, uint max_length= ~(uint) 0);
- const char *unpack(char *to, const char *from);
char *pack_key(char *to, const char *from, uint max_length);
char *pack_key_from_key_image(char* to, const char *from, uint max_length);
+ const char *unpack(char *to, const char *from);
const char *unpack_key(char* to, const char *from, uint max_length);
- int pack_cmp(const char *a, const char *b, uint key_length);
- int pack_cmp(const char *b, uint key_length);
+ int pack_cmp(const char *a, const char *b, uint key_length,
+ my_bool insert_or_update);
+ int pack_cmp(const char *b, uint key_length,my_bool insert_or_update);
uint packed_col_length(const char *col_ptr, uint length);
uint max_packed_col_length(uint max_length);
void free() { value.free(); }
@@ -1068,6 +1168,7 @@ public:
uint32 max_length();
};
+
#ifdef HAVE_SPATIAL
class Field_geom :public Field_blob {
public:
@@ -1085,18 +1186,18 @@ public:
:Field_blob(len_arg, maybe_null_arg, field_name_arg,
table_arg, &my_charset_bin)
{ geom_type= geom_type_arg; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY; }
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; }
enum_field_types type() const { return FIELD_TYPE_GEOMETRY; }
void sql_type(String &str) const;
int store(const char *to, uint length, CHARSET_INFO *charset);
- int store(double nr) { return 1; }
- int store(longlong nr) { return 1; }
-
- void get_key_image(char *buff,uint length, CHARSET_INFO *cs,imagetype type);
- void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
+ int store(double nr);
+ int store(longlong nr);
+ int store_decimal(const my_decimal *);
+ void get_key_image(char *buff,uint length,imagetype type);
};
#endif /*HAVE_SPATIAL*/
+
class Field_enum :public Field_str {
protected:
uint packlength;
@@ -1166,11 +1267,75 @@ public:
};
+class Field_bit :public Field {
+public:
+ uchar *bit_ptr; // position in record where 'uneven' bits store
+ uchar bit_ofs; // offset to 'uneven' high bits
+ uint bit_len; // number of 'uneven' high bits
+ Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg);
+ 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); }
+ uint size_of() const { return sizeof(*this); }
+ Item_result result_type () const { return INT_RESULT; }
+ void reset(void) { bzero(ptr, field_length); }
+ int store(const char *to, uint length, CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
+ int store_decimal(const my_decimal *);
+ double val_real(void);
+ longlong val_int(void);
+ String *val_str(String*, String *);
+ my_decimal *val_decimal(my_decimal *);
+ int cmp(const char *a, const char *b)
+ { return cmp_binary(a, b); }
+ int key_cmp(const byte *a, const byte *b)
+ { return cmp_binary((char *) a, (char *) b); }
+ int key_cmp(const byte *str, uint length);
+ int cmp_offset(uint row_offset);
+ void get_key_image(char *buff, uint length, imagetype type);
+ void set_key_image(char *buff, uint length)
+ { Field_bit::store(buff, length, &my_charset_bin); }
+ void sort_string(char *buff, uint length)
+ { get_key_image(buff, length, itRAW); }
+ uint32 pack_length() const
+ { return (uint32) field_length + (bit_len > 0); }
+ uint32 pack_length_in_rec() const { return field_length; }
+ void sql_type(String &str) const;
+ char *pack(char *to, const char *from, uint max_length=~(uint) 0);
+ const char *unpack(char* to, const char *from);
+ Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
+ char *new_ptr, uchar *new_null_ptr,
+ uint new_null_bit);
+};
+
+
+class Field_bit_as_char: public Field_bit {
+public:
+ uchar create_length;
+ Field_bit_as_char(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
+ 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; }
+ 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); }
+ int store(longlong nr) { return Field_bit::store(nr); }
+ void sql_type(String &str) const;
+};
+
+
/*
Create field class for CREATE TABLE
*/
-class create_field :public Sql_alloc {
+class create_field :public Sql_alloc
+{
public:
const char *field_name;
const char *change; // If done with alter table
@@ -1178,8 +1343,8 @@ public:
LEX_STRING comment; // Comment for field
Item *def; // Default value
enum enum_field_types sql_type;
- uint32 length;
- uint decimals,flags,pack_length;
+ ulong length;
+ uint decimals, flags, pack_length, key_length;
Field::utype unireg_check;
TYPELIB *interval; // Which interval to use
List<String> interval_list;
@@ -1192,6 +1357,11 @@ public:
create_field() :after(0) {}
create_field(Field *field, Field *orig_field);
void create_length_to_internal_length(void);
+
+ /* Init for a tmp table field. To be extended if need be. */
+ void init_for_tmp_table(enum_field_types sql_type_arg,
+ uint32 max_length, uint32 decimals,
+ bool maybe_null, bool is_unsigned);
};
@@ -1244,11 +1414,10 @@ Field *make_field(char *ptr, uint32 field_length,
TYPELIB *interval, const char *field_name,
struct st_table *table);
uint pack_length_to_packflag(uint type);
+enum_field_types get_blob_type_from_length(ulong length);
uint32 calc_pack_length(enum_field_types type,uint32 length);
int set_field_to_null(Field *field);
int set_field_to_null_with_conversions(Field *field, bool no_conversions);
-bool test_if_int(const char *str, int length, const char *int_end,
- CHARSET_INFO *cs);
/*
The following are for the interface with the .frm file
@@ -1264,9 +1433,12 @@ bool test_if_int(const char *str, int length, const char *int_end,
#define FIELDFLAG_BLOB 1024 // mangled with decimals!
#define FIELDFLAG_GEOM 2048 // mangled with decimals!
+#define FIELDFLAG_TREAT_BIT_AS_CHAR 4096 /* use Field_bit_as_char */
+
#define FIELDFLAG_LEFT_FULLSCREEN 8192
#define FIELDFLAG_RIGHT_FULLSCREEN 16384
#define FIELDFLAG_FORMAT_NUMBER 16384 // predit: ###,,## in output
+#define FIELDFLAG_NO_DEFAULT 16384 /* sql */
#define FIELDFLAG_SUM ((uint) 32768)// predit: +#fieldflag
#define FIELDFLAG_MAYBE_NULL ((uint) 32768)// sql
#define FIELDFLAG_PACK_SHIFT 3
@@ -1275,8 +1447,6 @@ bool test_if_int(const char *str, int length, const char *int_end,
#define FIELDFLAG_NUM_SCREEN_TYPE 0x7F01
#define FIELDFLAG_ALFA_SCREEN_TYPE 0x7800
-#define FIELD_SORT_REVERSE 16384
-
#define MTYP_TYPENR(type) (type & 127) /* Remove bits from type */
#define f_is_dec(x) ((x) & FIELDFLAG_DECIMAL)
@@ -1294,3 +1464,5 @@ bool test_if_int(const char *str, int length, const char *int_end,
#define f_is_equ(x) ((x) & (1+2+FIELDFLAG_PACK+31*256))
#define f_settype(x) (((int) x) << FIELDFLAG_PACK_SHIFT)
#define f_maybe_null(x) (x & FIELDFLAG_MAYBE_NULL)
+#define f_no_default(x) (x & FIELDFLAG_NO_DEFAULT)
+#define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 8b362bbf807..ae784ae0293 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -121,13 +121,11 @@ set_field_to_null(Field *field)
field->reset();
if (current_thd->count_cuted_fields == CHECK_FIELD_WARN)
{
- field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, 1);
+ field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
return 0;
}
if (!current_thd->no_errors)
- my_printf_error(ER_BAD_NULL_ERROR,ER(ER_BAD_NULL_ERROR),MYF(0),
- field->field_name);
+ my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name);
return -1;
}
@@ -185,8 +183,7 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions)
return 0;
}
if (!current_thd->no_errors)
- my_printf_error(ER_BAD_NULL_ERROR,ER(ER_BAD_NULL_ERROR),MYF(0),
- field->field_name);
+ my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name);
return -1;
}
@@ -232,7 +229,7 @@ static void do_copy_not_null(Copy_field *copy)
if (*copy->from_null_ptr & copy->from_bit)
{
copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, 1);
+ WARN_DATA_TRUNCATED, 1);
copy->to_field->reset();
}
else
@@ -307,7 +304,8 @@ static void do_field_string(Copy_field *copy)
char buff[MAX_FIELD_WIDTH];
copy->tmp.set_quick(buff,sizeof(buff),copy->tmp.charset());
copy->from_field->val_str(&copy->tmp);
- copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length(),copy->tmp.charset());
+ copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length(),
+ copy->tmp.charset());
}
@@ -337,7 +335,7 @@ static void do_cut_string(Copy_field *copy)
if (!my_isspace(system_charset_info, *ptr)) // QQ: ucs incompatible
{
copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, 1);
+ WARN_DATA_TRUNCATED, 1);
break;
}
}
@@ -352,18 +350,35 @@ static void do_expand_string(Copy_field *copy)
copy->to_length-copy->from_length, ' ');
}
-static void do_varstring(Copy_field *copy)
+
+static void do_varstring1(Copy_field *copy)
+{
+ uint length= (uint) *(uchar*) copy->from_ptr;
+ if (length > copy->to_length- 1)
+ {
+ length=copy->to_length - 1;
+ if (current_thd->count_cuted_fields)
+ copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED, 1);
+ }
+ *(uchar*) copy->to_ptr= (uchar) length;
+ memcpy(copy->to_ptr+1, copy->from_ptr + 1, length);
+}
+
+
+static void do_varstring2(Copy_field *copy)
{
uint length=uint2korr(copy->from_ptr);
- if (length > copy->to_length-2)
+ if (length > copy->to_length- HA_KEY_BLOB_LENGTH)
{
- length=copy->to_length-2;
+ length=copy->to_length-HA_KEY_BLOB_LENGTH;
if (current_thd->count_cuted_fields)
copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, 1);
+ WARN_DATA_TRUNCATED, 1);
}
int2store(copy->to_ptr,length);
- memcpy(copy->to_ptr+2, copy->from_ptr,length);
+ memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, copy->from_ptr + HA_KEY_BLOB_LENGTH,
+ length);
}
/***************************************************************************
@@ -471,26 +486,38 @@ void Copy_field::set(Field *to,Field *from,bool save)
void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
{
+ bool compatible_db_low_byte_first= (to->table->s->db_low_byte_first ==
+ from->table->s->db_low_byte_first);
if (to->flags & BLOB_FLAG)
{
if (!(from->flags & BLOB_FLAG) || from->charset() != to->charset())
return do_conv_blob;
- if (from_length != to_length ||
- to->table->db_low_byte_first != from->table->db_low_byte_first)
+ if (from_length != to_length || !compatible_db_low_byte_first)
{
// Correct pointer to point at char pointer
- to_ptr+=to_length - to->table->blob_ptr_size;
- from_ptr+=from_length- from->table->blob_ptr_size;
+ to_ptr+= to_length - to->table->s->blob_ptr_size;
+ from_ptr+= from_length- from->table->s->blob_ptr_size;
return do_copy_blob;
}
}
else
{
+ if (to->real_type() == FIELD_TYPE_BIT ||
+ from->real_type() == FIELD_TYPE_BIT)
+ return do_field_int;
// Check if identical fields
if (from->result_type() == STRING_RESULT)
{
+ /*
+ If we are copying date or datetime's we have to check the dates
+ if we don't allow 'all' dates.
+ */
if (to->real_type() != from->real_type() ||
- to->table->db_low_byte_first != from->table->db_low_byte_first)
+ !compatible_db_low_byte_first ||
+ ((to->table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) &&
+ to->type() == FIELD_TYPE_DATE ||
+ to->type() == FIELD_TYPE_DATETIME))
{
if (from->real_type() == FIELD_TYPE_ENUM ||
from->real_type() == FIELD_TYPE_SET)
@@ -506,9 +533,15 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
}
else if (to->charset() != from->charset())
return do_field_string;
- else if (to->real_type() == FIELD_TYPE_VAR_STRING && to_length !=
- from_length)
- return do_varstring;
+ else if (to->real_type() == MYSQL_TYPE_VARCHAR)
+ {
+ if (((Field_varstring*) to)->length_bytes !=
+ ((Field_varstring*) from)->length_bytes)
+ return do_field_string;
+ if (to_length != from_length)
+ return (((Field_varstring*) to)->length_bytes == 1 ?
+ do_varstring1 : do_varstring2);
+ }
else if (to_length < from_length)
return do_cut_string;
else if (to_length > from_length)
@@ -516,7 +549,7 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
}
else if (to->real_type() != from->real_type() ||
to_length != from_length ||
- to->table->db_low_byte_first != from->table->db_low_byte_first)
+ !compatible_db_low_byte_first)
{
if (to->real_type() == FIELD_TYPE_DECIMAL ||
to->result_type() == STRING_RESULT)
@@ -527,8 +560,7 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
}
else
{
- if (!to->eq_def(from) ||
- to->table->db_low_byte_first != from->table->db_low_byte_first)
+ if (!to->eq_def(from) || !compatible_db_low_byte_first)
{
if (to->real_type() == FIELD_TYPE_DECIMAL)
return do_field_string;
@@ -562,8 +594,16 @@ void field_conv(Field *to,Field *from)
!(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) &&
to->real_type() != FIELD_TYPE_ENUM &&
to->real_type() != FIELD_TYPE_SET &&
+ to->real_type() != FIELD_TYPE_BIT &&
+ (to->real_type() != FIELD_TYPE_NEWDECIMAL ||
+ (to->field_length == from->field_length &&
+ (((Field_num*)to)->dec == ((Field_num*)from)->dec))) &&
from->charset() == to->charset() &&
- to->table->db_low_byte_first == from->table->db_low_byte_first)
+ to->table->s->db_low_byte_first == from->table->s->db_low_byte_first &&
+ (!(to->table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) ||
+ to->type() != FIELD_TYPE_DATE &&
+ to->type() != FIELD_TYPE_DATETIME))
{ // Identical fields
memcpy(to->ptr,from->ptr,to->pack_length());
return;
@@ -574,7 +614,8 @@ void field_conv(Field *to,Field *from)
Field_blob *blob=(Field_blob*) to;
from->val_str(&blob->value);
if (!blob->value.is_alloced() &&
- from->real_type() != FIELD_TYPE_STRING)
+ from->real_type() != MYSQL_TYPE_STRING &&
+ from->real_type() != MYSQL_TYPE_VARCHAR)
blob->value.copy();
blob->store(blob->value.ptr(),blob->value.length(),from->charset());
return;
@@ -588,10 +629,21 @@ void field_conv(Field *to,Field *from)
char buff[MAX_FIELD_WIDTH];
String result(buff,sizeof(buff),from->charset());
from->val_str(&result);
+ /*
+ We use c_ptr_quick() here to make it easier if to is a float/double
+ as the conversion routines will do a copy of the result doesn't
+ end with \0. Can be replaced with .ptr() when we have our own
+ string->double conversion.
+ */
to->store(result.c_ptr_quick(),result.length(),from->charset());
}
else if (from->result_type() == REAL_RESULT)
to->store(from->val_real());
+ else if (from->result_type() == DECIMAL_RESULT)
+ {
+ my_decimal buff;
+ to->store_decimal(from->val_decimal(&buff));
+ }
else
to->store(from->val_int());
}
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 75b114fc140..30ebd8d59e1 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -48,7 +48,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer,
BUFFPEK *buffpek,
uint maxbuffer,IO_CACHE *tempfile,
IO_CACHE *outfile);
-static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count);
+static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count,
+ FILESORT_INFO *table_sort);
static uint sortlength(SORT_FIELD *sortorder, uint s_length,
bool *multi_byte_charset);
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
@@ -106,8 +107,16 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_PUSH(""); /* No DBUG here */
#endif
-
- outfile= table->sort.io_cache;
+ FILESORT_INFO table_sort;
+ /*
+ Don't use table->sort in filesort as it is also used by
+ QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end
+ when index_merge select has finished with it.
+ */
+ memcpy(&table_sort, &table->sort, sizeof(FILESORT_INFO));
+ table->sort.io_cache= NULL;
+
+ outfile= table_sort.io_cache;
my_b_clear(&tempfile);
my_b_clear(&buffpek_pointers);
buffpek=0;
@@ -118,7 +127,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
param.ref_length= table->file->ref_length;
param.addon_field= 0;
param.addon_length= 0;
- if (!(table->tmp_table || table->fulltext_searched))
+ if (!(table->file->table_flags() & HA_FAST_KEY_READ) &&
+ !table->fulltext_searched)
{
/*
Get the descriptors of all fields whose values are appended
@@ -128,14 +138,15 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
param.sort_length,
&param.addon_length);
}
- table->sort.addon_buf= 0;
- table->sort.addon_length= param.addon_length;
- table->sort.addon_field= param.addon_field;
- table->sort.unpack= unpack_addon_fields;
+
+ table_sort.addon_buf= 0;
+ table_sort.addon_length= param.addon_length;
+ table_sort.addon_field= param.addon_field;
+ table_sort.unpack= unpack_addon_fields;
if (param.addon_field)
{
param.res_length= param.addon_length;
- if (!(table->sort.addon_buf= (byte *) my_malloc(param.addon_length,
+ if (!(table_sort.addon_buf= (byte *) my_malloc(param.addon_length,
MYF(MY_WME))))
goto err;
}
@@ -153,11 +164,11 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (select && select->quick)
{
- statistic_increment(filesort_range_count, &LOCK_status);
+ statistic_increment(thd->status_var.filesort_range_count, &LOCK_status);
}
else
{
- statistic_increment(filesort_scan_count, &LOCK_status);
+ statistic_increment(thd->status_var.filesort_scan_count, &LOCK_status);
}
#ifdef CAN_TRUST_RANGE
if (select && select->quick && select->quick->records > 0L)
@@ -218,7 +229,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (maxbuffer == 0) // The whole set is in memory
{
- if (save_index(&param,sort_keys,(uint) records))
+ if (save_index(&param,sort_keys,(uint) records, &table_sort))
goto err;
}
else
@@ -274,13 +285,16 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
}
}
if (error)
- my_error(ER_FILSORT_ABORT,MYF(ME_ERROR+ME_WAITTANG));
+ my_message(ER_FILSORT_ABORT, ER(ER_FILSORT_ABORT),
+ MYF(ME_ERROR+ME_WAITTANG));
else
- statistic_add(filesort_rows, (ulong) records, &LOCK_status);
+ statistic_add(thd->status_var.filesort_rows,
+ (ulong) records, &LOCK_status);
*examined_rows= param.examined_rows;
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_POP(); /* Ok to DBUG */
#endif
+ memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO));
DBUG_PRINT("exit",("records: %ld",records));
DBUG_RETURN(error ? HA_POS_ERROR : records);
} /* filesort */
@@ -387,7 +401,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
my_off_t record;
TABLE *sort_form;
- volatile my_bool *killed= &current_thd->killed;
+ volatile THD::killed_state *killed= &current_thd->killed;
handler *file;
DBUG_ENTER("find_all_keys");
DBUG_PRINT("info",("using: %s",(select?select->quick?"ranges":"where":"every row")));
@@ -407,21 +421,30 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
next_pos=ref_pos;
if (! indexfile && ! quick_select)
{
- file->reset(); // QQ; Shouldn't be needed
- if (sort_form->key_read) // QQ Can be removed after the reset
- file->extra(HA_EXTRA_KEYREAD); // QQ is removed
next_pos=(byte*) 0; /* Find records in sequence */
file->ha_rnd_init(1);
file->extra_opt(HA_EXTRA_CACHE,
current_thd->variables.read_buff_size);
}
+ READ_RECORD read_record_info;
+ if (quick_select)
+ {
+ if (select->quick->reset())
+ DBUG_RETURN(HA_POS_ERROR);
+ init_read_record(&read_record_info, current_thd, select->quick->head,
+ select, 1, 1);
+ }
+
for (;;)
{
if (quick_select)
{
- if ((error=select->quick->get_next()))
- break;
+ if ((error= read_record_info.read_record(&read_record_info)))
+ {
+ error= HA_ERR_END_OF_FILE;
+ break;
+ }
file->position(sort_form->record[0]);
}
else /* Not quick-select */
@@ -440,8 +463,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
error=file->rnd_next(sort_form->record[0]);
if (!flag)
{
- ha_store_ptr(ref_pos,ref_length,record); // Position to row
- record+=sort_form->db_record_offset;
+ my_store_ptr(ref_pos,ref_length,record); // Position to row
+ record+= sort_form->s->db_record_offset;
}
else
file->position(sort_form->record[0]);
@@ -449,6 +472,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
if (error && error != HA_ERR_RECORD_DELETED)
break;
}
+
if (*killed)
{
DBUG_PRINT("info",("Sort killed by user"));
@@ -475,9 +499,21 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
else
file->unlock_row();
}
- (void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */
- if (!next_pos)
- file->ha_rnd_end();
+ if (quick_select)
+ {
+ /*
+ index_merge quick select uses table->sort when retrieving rows, so free
+ resoures it has allocated.
+ */
+ end_read_record(&read_record_info);
+ }
+ else
+ {
+ (void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */
+ if (!next_pos)
+ file->ha_rnd_end();
+ }
+
DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
if (error != HA_ERR_END_OF_FILE)
{
@@ -532,10 +568,10 @@ write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
MYF(MY_WME)))
- goto err; /* purecov: inspected */
+ goto err; /* purecov: inspected */
buffpek.file_pos= my_b_tell(tempfile);
if ((ha_rows) count > param->max_rows)
- count=(uint) param->max_rows; /* purecov: inspected */
+ count=(uint) param->max_rows; /* purecov: inspected */
buffpek.count=(ha_rows) count;
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
if (my_b_write(tempfile, (byte*) *sort_keys, (uint) rec_length))
@@ -584,20 +620,21 @@ static void make_sortkey(register SORTPARAM *param,
else
{ // Item
Item *item=sort_field->item;
+ maybe_null= item->maybe_null;
switch (sort_field->result_type) {
case STRING_RESULT:
{
CHARSET_INFO *cs=item->collation.collation;
char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
- if ((maybe_null=item->maybe_null))
+ if (maybe_null)
*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);
if (!res)
{
- if (item->maybe_null)
+ if (maybe_null)
bzero((char*) to-1,sort_field->length+1);
else
{
@@ -637,20 +674,22 @@ static void make_sortkey(register SORTPARAM *param,
case INT_RESULT:
{
longlong value=item->val_int();
- if ((maybe_null=item->maybe_null))
+ if (maybe_null)
+ {
*to++=1; /* purecov: inspected */
- if (item->null_value)
- {
- if (item->maybe_null)
- bzero((char*) to-1,sort_field->length+1);
- else
- {
- DBUG_PRINT("warning",
- ("Got null on something that shouldn't be null"));
- bzero((char*) to,sort_field->length);
- }
- break;
- }
+ if (item->null_value)
+ {
+ if (maybe_null)
+ bzero((char*) to-1,sort_field->length+1);
+ else
+ {
+ DBUG_PRINT("warning",
+ ("Got null on something that shouldn't be null"));
+ bzero((char*) to,sort_field->length);
+ }
+ break;
+ }
+ }
#if SIZEOF_LONG_LONG > 4
to[7]= (uchar) value;
to[6]= (uchar) (value >> 8);
@@ -674,17 +713,37 @@ static void make_sortkey(register SORTPARAM *param,
#endif
break;
}
+ case DECIMAL_RESULT:
+ {
+ my_decimal dec_buf, *dec_val= item->val_decimal(&dec_buf);
+ if (maybe_null)
+ {
+ if (item->null_value)
+ {
+ bzero((char*)to, sort_field->length+1);
+ to++;
+ break;
+ }
+ *to++=1;
+ }
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, (char*)to,
+ item->max_length - (item->decimals ? 1:0),
+ item->decimals);
+ break;
+ }
case REAL_RESULT:
{
- double value=item->val();
- if ((maybe_null=item->null_value))
- {
- bzero((char*) to,sort_field->length+1);
- to++;
- break;
- }
- if ((maybe_null=item->maybe_null))
+ double value= item->val_real();
+ if (maybe_null)
+ {
+ if (item->null_value)
+ {
+ bzero((char*) to,sort_field->length+1);
+ to++;
+ break;
+ }
*to++=1;
+ }
change_double_for_sort(value,(byte*) to);
break;
}
@@ -720,7 +779,7 @@ static void make_sortkey(register SORTPARAM *param,
*/
SORT_ADDON_FIELD *addonf= param->addon_field;
uchar *nulls= to;
- DBUG_ASSERT(addonf);
+ DBUG_ASSERT(addonf != 0);
bzero((char *) nulls, addonf->offset);
to+= addonf->offset;
for ( ; (field= addonf->field) ; addonf++)
@@ -753,8 +812,8 @@ static void make_sortkey(register SORTPARAM *param,
return;
}
-
-static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
+static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
+ FILESORT_INFO *table_sort)
{
uint offset,res_length;
byte *to;
@@ -765,7 +824,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
offset= param->rec_length-res_length;
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows;
- if (!(to= param->sort_form->sort.record_pointers=
+ if (!(to= table_sort->record_pointers=
(byte*) my_malloc(res_length*count, MYF(MY_WME))))
DBUG_RETURN(1); /* purecov: inspected */
for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
@@ -850,6 +909,39 @@ uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
} /* read_to_buffer */
+/*
+ Put all room used by freed buffer to use in adjacent buffer. Note, that
+ we can't simply distribute memory evenly between all buffers, because
+ new areas must not overlap with old ones.
+ SYNOPSYS
+ reuse_freed_buff()
+ queue IN list of non-empty buffers, without freed buffer
+ reuse IN empty buffer
+ key_length IN key length
+*/
+
+void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length)
+{
+ uchar *reuse_end= reuse->base + reuse->max_keys * key_length;
+ for (uint i= 0; i < queue->elements; ++i)
+ {
+ BUFFPEK *bp= (BUFFPEK *) queue_element(queue, i);
+ if (bp->base + bp->max_keys * key_length == reuse->base)
+ {
+ bp->max_keys+= reuse->max_keys;
+ return;
+ }
+ else if (bp->base == reuse_end)
+ {
+ bp->base= reuse->base;
+ bp->max_keys+= reuse->max_keys;
+ return;
+ }
+ }
+ DBUG_ASSERT(0);
+}
+
+
/*
Merge buffers to one buffer
SYNOPSIS
@@ -879,18 +971,19 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
ha_rows max_rows,org_max_rows;
my_off_t to_start_filepos;
uchar *strpos;
- BUFFPEK *buffpek,**refpek;
+ BUFFPEK *buffpek;
QUEUE queue;
qsort2_cmp cmp;
- volatile my_bool *killed= &current_thd->killed;
- my_bool not_killable;
+ volatile THD::killed_state *killed= &current_thd->killed;
+ THD::killed_state not_killable;
DBUG_ENTER("merge_buffers");
- statistic_increment(filesort_merge_passes, &LOCK_status);
+ statistic_increment(current_thd->status_var.filesort_merge_passes,
+ &LOCK_status);
if (param->not_killable)
{
killed= &not_killable;
- not_killable= 0;
+ not_killable= THD::NOT_KILLED;
}
error=0;
@@ -993,29 +1086,8 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
if (!(error= (int) read_to_buffer(from_file,buffpek,
rec_length)))
{
- uchar *base= buffpek->base;
- ulong max_keys= buffpek->max_keys;
-
VOID(queue_remove(&queue,0));
-
- /* Put room used by buffer to use in other buffer */
- for (refpek= (BUFFPEK**) &queue_top(&queue);
- refpek <= (BUFFPEK**) &queue_end(&queue);
- refpek++)
- {
- buffpek= *refpek;
- if (buffpek->base+buffpek->max_keys*rec_length == base)
- {
- buffpek->max_keys+= max_keys;
- break;
- }
- else if (base+max_keys*rec_length == buffpek->base)
- {
- buffpek->base= base;
- buffpek->max_keys+= max_keys;
- break;
- }
- }
+ reuse_freed_buff(&queue, buffpek, rec_length);
break; /* One buffer have been removed */
}
else if (error == -1)
@@ -1140,7 +1212,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
{
sortorder->need_strxnfrm= 1;
*multi_byte_charset= 1;
- sortorder->length= sortorder->length*cs->strxfrm_multiply;
+ sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
}
}
if (sortorder->field->maybe_null())
@@ -1153,7 +1225,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
sortorder->length=sortorder->item->max_length;
if (use_strnxfrm((cs=sortorder->item->collation.collation)))
{
- sortorder->length= sortorder->length*cs->strxfrm_multiply;
+ sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
sortorder->need_strxnfrm= 1;
*multi_byte_charset= 1;
}
@@ -1165,6 +1237,12 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
sortorder->length=4;
#endif
break;
+ case DECIMAL_RESULT:
+ sortorder->length=
+ my_decimal_get_binary_size(sortorder->item->max_length -
+ (sortorder->item->decimals ? 1 : 0),
+ sortorder->item->decimals);
+ break;
case REAL_RESULT:
sortorder->length=sizeof(double);
break;
@@ -1224,27 +1302,29 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
uint length= 0;
uint fields= 0;
uint null_fields= 0;
-
- /*
- If there is a reference to a field in the query add it
- to the the set of appended fields.
- Note for future refinement:
- This this a too strong condition.
- Actually we need only the fields referred in the
- result set. And for some of them it makes sense to use
- the values directly from sorted fields.
+ query_id_t query_id= thd->query_id;
+ /*
+ If there is a reference to a field in the query add it
+ to the the set of appended fields.
+ Note for future refinement:
+ This this a too strong condition.
+ Actually we need only the fields referred in the
+ result set. And for some of them it makes sense to use
+ the values directly from sorted fields.
*/
*plength= 0;
+
/*
- The following statement is added to avoid sorting in alter_table.
- The fact is the filter 'field->query_id != thd->query_id'
- doesn't work for alter table
+ The following statement is added to avoid sorting in alter_table.
+ The fact is the filter 'field->query_id != thd->query_id'
+ doesn't work for alter table
*/
- if (thd->lex->sql_command != SQLCOM_SELECT)
+ if (thd->lex->sql_command != SQLCOM_SELECT &&
+ thd->lex->sql_command != SQLCOM_INSERT_SELECT)
return 0;
for (pfield= ptabfield; (field= *pfield) ; pfield++)
{
- if (field->query_id != thd->query_id)
+ if (field->query_id != query_id)
continue;
if (field->flags & BLOB_FLAG)
return 0;
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 0bbdf84c8d6..57b5e006489 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -83,8 +83,17 @@ TODO:
#include "mysql_version.h"
#include "lex.h"
+const char *default_dbug_option="d:t:o,/tmp/gen_lex_hash.trace";
+
struct my_option my_long_options[] =
{
+#ifdef DBUG_OFF
+ {"debug", '#', "This is a non-debug version. Catch this and exit",
+ 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#else
+ {"debug", '#', "Output debug log", (gptr*) &default_dbug_option,
+ (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
{"help", '?', "Display help and exit",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Output version information and exit",
@@ -108,7 +117,7 @@ hash_lex_struct *get_hash_struct_by_len(hash_lex_struct **root_by_len,
{
if (*max_len<len){
*root_by_len= (hash_lex_struct *)realloc((char*)*root_by_len,
- sizeof(hash_lex_struct)*len);
+ sizeof(hash_lex_struct)*len);
hash_lex_struct *cur, *end= *root_by_len + len;
for (cur= *root_by_len + *max_len; cur<end; cur++)
cur->first_char= 0;
@@ -353,6 +362,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case '?':
usage(0);
exit(0);
+ case '#':
+ DBUG_PUSH(argument ? argument : default_dbug_option);
+ break;
}
return 0;
}
@@ -425,11 +437,12 @@ int check_duplicates()
int main(int argc,char **argv)
{
MY_INIT(argv[0]);
+ DBUG_PROCESS(argv[0]);
if (get_options(argc,(char **) argv))
exit(1);
- printf("/* Copyright (C) 2001 MySQL AB\n\
+ printf("/* Copyright (C) 2001-2004 MySQL AB\n\
This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
and you are welcome to modify and redistribute it under the GPL license\n\
\n*/\n\n");
@@ -449,9 +462,8 @@ int main(int argc,char **argv)
printf("\nunsigned int sql_functions_max_len=%d;\n",max_len);
printf("\nunsigned int symbols_max_len=%d;\n\n",max_len2);
- printf
-(
-"inline SYMBOL *get_hash_symbol(const char *s,\n\
+ printf("\
+inline SYMBOL *get_hash_symbol(const char *s,\n \
unsigned int len,bool function)\n\
{\n\
register uchar *hash_map;\n\
@@ -516,5 +528,7 @@ int main(int argc,char **argv)
}\n\
}\n"
);
+ my_end(0);
+ exit(0);
}
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 626201a38a6..04d81b2f95a 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -102,11 +102,35 @@ static int write_status(DB *status_block, char *buff, uint length);
static void update_status(BDB_SHARE *share, TABLE *table);
static void berkeley_noticecall(DB_ENV *db_env, db_notices notice);
-
+static int berkeley_close_connection(THD *thd);
+static int berkeley_commit(THD *thd, bool all);
+static int berkeley_rollback(THD *thd, bool all);
+
+static handlerton berkeley_hton = {
+ "BerkeleyDB",
+ 0, /* slot */
+ 0, /* savepoint size */
+ berkeley_close_connection,
+ NULL, /* savepoint_set */
+ NULL, /* savepoint_rollback */
+ NULL, /* savepoint_release */
+ berkeley_commit,
+ berkeley_rollback,
+ NULL, /* prepare */
+ NULL, /* recover */
+ NULL, /* commit_by_xid */
+ NULL /* rollback_by_xid */
+};
+
+typedef struct st_berkeley_trx_data {
+ DB_TXN *all;
+ DB_TXN *stmt;
+ uint bdb_lock_count;
+} berkeley_trx_data;
/* General functions */
-bool berkeley_init(void)
+handlerton *berkeley_init(void)
{
DBUG_ENTER("berkeley_init");
@@ -135,7 +159,7 @@ bool berkeley_init(void)
berkeley_log_file_size= max(berkeley_log_file_size, 10*1024*1024L);
if (db_env_create(&db_env,0))
- DBUG_RETURN(1); /* purecov: inspected */
+ DBUG_RETURN(0);
db_env->set_errcall(db_env,berkeley_print_error);
db_env->set_errpfx(db_env,"bdb");
db_env->set_noticecall(db_env, berkeley_noticecall);
@@ -163,16 +187,15 @@ bool berkeley_init(void)
DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN |
DB_CREATE | DB_THREAD, 0666))
{
- db_env->close(db_env,0); /* purecov: inspected */
- db_env=0; /* purecov: inspected */
- goto err;
+ db_env->close(db_env,0);
+ db_env=0;
+ DBUG_RETURN(0);
}
(void) hash_init(&bdb_open_tables,system_charset_info,32,0,0,
(hash_get_key) bdb_get_key,0,0);
pthread_mutex_init(&bdb_mutex,MY_MUTEX_INIT_FAST);
-err:
- DBUG_RETURN(db_env == 0);
+ DBUG_RETURN(&berkeley_hton);
}
@@ -190,6 +213,12 @@ bool berkeley_end(void)
DBUG_RETURN(error != 0);
}
+static int berkeley_close_connection(THD *thd)
+{
+ my_free((gptr)thd->ha_data[berkeley_hton.slot], MYF(0));
+ return 0;
+}
+
bool berkeley_flush_logs()
{
int error;
@@ -208,26 +237,29 @@ bool berkeley_flush_logs()
DBUG_RETURN(result);
}
-
-int berkeley_commit(THD *thd, void *trans)
+static int berkeley_commit(THD *thd, bool all)
{
DBUG_ENTER("berkeley_commit");
- DBUG_PRINT("trans",("ending transaction %s",
- trans == thd->transaction.stmt.bdb_tid ? "stmt" : "all"));
- int error=txn_commit((DB_TXN*) trans,0);
+ DBUG_PRINT("trans",("ending transaction %s", all ? "all" : "stmt"));
+ berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
+ DB_TXN **txn= all ? &trx->all : &trx->stmt;
+ int error=txn_commit(*txn,0);
+ *txn=0;
#ifndef DBUG_OFF
if (error)
- DBUG_PRINT("error",("error: %d",error)); /* purecov: inspected */
+ DBUG_PRINT("error",("error: %d",error));
#endif
DBUG_RETURN(error);
}
-int berkeley_rollback(THD *thd, void *trans)
+static int berkeley_rollback(THD *thd, bool all)
{
DBUG_ENTER("berkeley_rollback");
- DBUG_PRINT("trans",("aborting transaction %s",
- trans == thd->transaction.stmt.bdb_tid ? "stmt" : "all"));
- int error=txn_abort((DB_TXN*) trans);
+ DBUG_PRINT("trans",("aborting transaction %s", all ? "all" : "stmt"));
+ berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
+ DB_TXN **txn= all ? &trx->all : &trx->stmt;
+ int error=txn_abort(*txn);
+ *txn=0;
DBUG_RETURN(error);
}
@@ -339,11 +371,15 @@ void berkeley_cleanup_log_files(void)
/*****************************************************************************
** Berkeley DB tables
*****************************************************************************/
+static const char *ha_berkeley_exts[] = {
+ ha_berkeley_ext,
+ NullS
+};
-static const char *ha_bdb_bas_exts[]= { ha_berkeley_ext, NullS };
const char **ha_berkeley::bas_ext() const
-{ return ha_bdb_bas_exts; }
-
+{
+ return ha_berkeley_exts;
+}
ulong ha_berkeley::index_flags(uint idx, uint part, bool all_parts) const
{
@@ -359,7 +395,8 @@ ulong ha_berkeley::index_flags(uint idx, uint part, bool all_parts) const
}
switch (table->key_info[idx].key_part[i].field->key_type()) {
case HA_KEYTYPE_TEXT:
- case HA_KEYTYPE_VARTEXT:
+ case HA_KEYTYPE_VARTEXT1:
+ case HA_KEYTYPE_VARTEXT2:
/*
As BDB stores only one copy of equal strings, we can't use key read
on these. Binary collations do support key read though.
@@ -394,9 +431,11 @@ berkeley_cmp_packed_key(DB *file, const DBT *new_key, const DBT *saved_key)
KEY_PART_INFO *key_part= key->key_part, *end=key_part+key->key_parts;
uint key_length=new_key->size;
+ DBUG_DUMP("key_in_index", saved_key_ptr, saved_key->size);
for (; key_part != end && (int) key_length > 0; key_part++)
{
int cmp;
+ uint length;
if (key_part->null_bit)
{
if (*new_key_ptr != *saved_key_ptr++)
@@ -405,11 +444,12 @@ berkeley_cmp_packed_key(DB *file, const DBT *new_key, const DBT *saved_key)
if (!*new_key_ptr++)
continue;
}
- if ((cmp=key_part->field->pack_cmp(new_key_ptr,saved_key_ptr,
- key_part->length)))
+ if ((cmp= key_part->field->pack_cmp(new_key_ptr,saved_key_ptr,
+ key_part->length,
+ key->table->insert_or_update)))
return cmp;
- uint length=key_part->field->packed_col_length(new_key_ptr,
- key_part->length);
+ length= key_part->field->packed_col_length(new_key_ptr,
+ key_part->length);
new_key_ptr+=length;
key_length-=length;
saved_key_ptr+=key_part->field->packed_col_length(saved_key_ptr,
@@ -435,7 +475,7 @@ berkeley_cmp_fix_length_key(DB *file, const DBT *new_key, const DBT *saved_key)
for (; key_part != end && (int) key_length > 0 ; key_part++)
{
int cmp;
- if ((cmp=key_part->field->pack_cmp(new_key_ptr,saved_key_ptr,0)))
+ if ((cmp=key_part->field->pack_cmp(new_key_ptr,saved_key_ptr,0,0)))
return cmp;
new_key_ptr+=key_part->length;
key_length-= key_part->length;
@@ -445,6 +485,7 @@ berkeley_cmp_fix_length_key(DB *file, const DBT *new_key, const DBT *saved_key)
}
#endif
+
/* Compare key against row */
static bool
@@ -456,6 +497,7 @@ berkeley_key_cmp(TABLE *table, KEY *key_info, const char *key, uint key_length)
for (; key_part != end && (int) key_length > 0; key_part++)
{
int cmp;
+ uint length;
if (key_part->null_bit)
{
key_length--;
@@ -469,27 +511,34 @@ berkeley_key_cmp(TABLE *table, KEY *key_info, const char *key, uint key_length)
if (!*key++) // Null value
continue;
}
- if ((cmp=key_part->field->pack_cmp(key,key_part->length)))
+ /*
+ Last argument has to be 0 as we are also using this to function to see
+ if a key like 'a ' matched a row with 'a'
+ */
+ if ((cmp= key_part->field->pack_cmp(key, key_part->length, 0)))
return cmp;
- uint length=key_part->field->packed_col_length(key,key_part->length);
- key+=length;
- key_length-=length;
+ length= key_part->field->packed_col_length(key,key_part->length);
+ key+= length;
+ key_length-= length;
}
return 0; // Identical keys
}
+
int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
{
char name_buff[FN_REFLEN];
uint open_mode=(mode == O_RDONLY ? DB_RDONLY : 0) | DB_THREAD;
+ uint max_key_length;
int error;
+ TABLE_SHARE *table_share= table->s;
DBUG_ENTER("ha_berkeley::open");
/* Open primary key */
hidden_primary_key=0;
- if ((primary_key=table->primary_key) >= MAX_KEY)
+ if ((primary_key= table_share->primary_key) >= MAX_KEY)
{ // No primary key
- primary_key=table->keys;
+ primary_key= table_share->keys;
key_used_on_scan=MAX_KEY;
ref_length=hidden_primary_key=BDB_HIDDEN_PRIMARY_KEY_LENGTH;
}
@@ -497,18 +546,18 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
key_used_on_scan=primary_key;
/* Need some extra memory in case of packed keys */
- uint max_key_length= table->max_key_length + MAX_REF_PARTS*3;
+ max_key_length= table_share->max_key_length + MAX_REF_PARTS*3;
if (!(alloc_ptr=
my_multi_malloc(MYF(MY_WME),
&key_buff, max_key_length,
&key_buff2, max_key_length,
&primary_key_buff,
(hidden_primary_key ? 0 :
- table->key_info[table->primary_key].key_length),
+ table->key_info[table_share->primary_key].key_length),
NullS)))
DBUG_RETURN(1); /* purecov: inspected */
if (!(rec_buff= (byte*) my_malloc((alloced_rec_buff_length=
- table->rec_buff_length),
+ table_share->rec_buff_length),
MYF(MY_WME))))
{
my_free(alloc_ptr,MYF(0)); /* purecov: inspected */
@@ -516,7 +565,7 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
}
/* Init shared structure */
- if (!(share=get_share(name,table)))
+ if (!(share= get_share(name,table)))
{
my_free((char*) rec_buff,MYF(0)); /* purecov: inspected */
my_free(alloc_ptr,MYF(0)); /* purecov: inspected */
@@ -529,7 +578,7 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
/* Fill in shared structure, if needed */
pthread_mutex_lock(&share->mutex);
- file = share->file;
+ file= share->file;
if (!share->use_count++)
{
if ((error=db_create(&file, db_env, 0)))
@@ -540,13 +589,13 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
my_errno=error; /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
- share->file = file;
+ share->file= file;
file->set_bt_compare(file,
(hidden_primary_key ? berkeley_cmp_hidden_key :
berkeley_cmp_packed_key));
if (!hidden_primary_key)
- file->app_private= (void*) (table->key_info+table->primary_key);
+ file->app_private= (void*) (table->key_info + table_share->primary_key);
if ((error= txn_begin(db_env, 0, (DB_TXN**) &transaction, 0)) ||
(error= (file->open(file, transaction,
fn_format(name_buff, name, "", ha_berkeley_ext,
@@ -554,7 +603,7 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
"main", DB_BTREE, open_mode, 0))) ||
(error= transaction->commit(transaction, 0)))
{
- free_share(share,table, hidden_primary_key,1); /* purecov: inspected */
+ free_share(share, table, hidden_primary_key,1); /* purecov: inspected */
my_free((char*) rec_buff,MYF(0)); /* purecov: inspected */
my_free(alloc_ptr,MYF(0)); /* purecov: inspected */
my_errno=error; /* purecov: inspected */
@@ -566,7 +615,7 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
key_type[primary_key]=DB_NOOVERWRITE;
DB **ptr=key_file;
- for (uint i=0, used_keys=0; i < table->keys ; i++, ptr++)
+ for (uint i=0, used_keys=0; i < table_share->keys ; i++, ptr++)
{
char part[7];
if (i != primary_key)
@@ -598,7 +647,7 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
}
}
/* Calculate pack_length of primary key */
- share->fixed_length_primary_key=1;
+ share->fixed_length_primary_key= 1;
if (!hidden_primary_key)
{
ref_length=0;
@@ -608,18 +657,19 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
ref_length+= key_part->field->max_packed_col_length(key_part->length);
share->fixed_length_primary_key=
(ref_length == table->key_info[primary_key].key_length);
- share->status|=STATUS_PRIMARY_KEY_INIT;
+ share->status|= STATUS_PRIMARY_KEY_INIT;
}
- share->ref_length=ref_length;
+ share->ref_length= ref_length;
}
- ref_length=share->ref_length; // If second open
+ ref_length= share->ref_length; // If second open
pthread_mutex_unlock(&share->mutex);
transaction=0;
cursor=0;
key_read=0;
block_size=8192; // Berkeley DB block size
- share->fixed_length_row=!(table->db_create_options & HA_OPTION_PACK_RECORD);
+ share->fixed_length_row= !(table_share->db_create_options &
+ HA_OPTION_PACK_RECORD);
get_status();
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
@@ -659,9 +709,15 @@ bool ha_berkeley::fix_rec_buff_for_blob(ulong length)
ulong ha_berkeley::max_row_length(const byte *buf)
{
- ulong length=table->reclength + table->fields*2;
- for (Field_blob **ptr=table->blob_field ; *ptr ; ptr++)
- length+= (*ptr)->get_length((char*) buf+(*ptr)->offset())+2;
+ ulong length= table->s->reclength + table->s->fields*2;
+ uint *ptr, *end;
+ for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
+ ptr != end ;
+ ptr++)
+ {
+ Field_blob *blob= ((Field_blob*) table->field[*ptr]);
+ length+= blob->get_length((char*) buf + blob->offset())+2;
+ }
return length;
}
@@ -677,29 +733,30 @@ ulong ha_berkeley::max_row_length(const byte *buf)
int ha_berkeley::pack_row(DBT *row, const byte *record, bool new_row)
{
+ byte *ptr;
bzero((char*) row,sizeof(*row));
if (share->fixed_length_row)
{
row->data=(void*) record;
- row->size=table->reclength+hidden_primary_key;
+ row->size= table->s->reclength+hidden_primary_key;
if (hidden_primary_key)
{
if (new_row)
get_auto_primary_key(current_ident);
- memcpy_fixed((char*) record+table->reclength, (char*) current_ident,
+ memcpy_fixed((char*) record+table->s->reclength, (char*) current_ident,
BDB_HIDDEN_PRIMARY_KEY_LENGTH);
}
return 0;
}
- if (table->blob_fields)
+ if (table->s->blob_fields)
{
if (fix_rec_buff_for_blob(max_row_length(record)))
return HA_ERR_OUT_OF_MEM; /* purecov: inspected */
}
/* Copy null bits */
- memcpy(rec_buff, record, table->null_bytes);
- byte *ptr=rec_buff + table->null_bytes;
+ memcpy(rec_buff, record, table->s->null_bytes);
+ ptr= rec_buff + table->s->null_bytes;
for (Field **field=table->field ; *field ; field++)
ptr=(byte*) (*field)->pack((char*) ptr,
@@ -722,13 +779,13 @@ int ha_berkeley::pack_row(DBT *row, const byte *record, bool new_row)
void ha_berkeley::unpack_row(char *record, DBT *row)
{
if (share->fixed_length_row)
- memcpy(record,(char*) row->data,table->reclength+hidden_primary_key);
+ memcpy(record,(char*) row->data,table->s->reclength+hidden_primary_key);
else
{
/* Copy null bits */
const char *ptr= (const char*) row->data;
- memcpy(record, ptr, table->null_bytes);
- ptr+=table->null_bytes;
+ memcpy(record, ptr, table->s->null_bytes);
+ ptr+= table->s->null_bytes;
for (Field **field=table->field ; *field ; field++)
ptr= (*field)->unpack(record + (*field)->offset(), ptr);
}
@@ -739,11 +796,11 @@ void ha_berkeley::unpack_row(char *record, DBT *row)
void ha_berkeley::unpack_key(char *record, DBT *key, uint index)
{
- KEY *key_info=table->key_info+index;
+ KEY *key_info= table->key_info+index;
KEY_PART_INFO *key_part= key_info->key_part,
- *end=key_part+key_info->key_parts;
+ *end= key_part+key_info->key_parts;
+ char *pos= (char*) key->data;
- char *pos=(char*) key->data;
for (; key_part != end; key_part++)
{
if (key_part->null_bit)
@@ -767,8 +824,10 @@ void ha_berkeley::unpack_key(char *record, DBT *key, uint index)
/*
- Create a packed key from from a row
- This will never fail as the key buffer is pre allocated.
+ Create a packed key from a row. This key will be written as such
+ to the index tree.
+
+ This will never fail as the key buffer is pre-allocated.
*/
DBT *ha_berkeley::create_key(DBT *key, uint keynr, char *buff,
@@ -814,7 +873,10 @@ DBT *ha_berkeley::create_key(DBT *key, uint keynr, char *buff,
/*
- Create a packed key from from a MySQL unpacked key
+ Create a packed key from from a MySQL unpacked key (like the one that is
+ sent from the index_read()
+
+ This key is to be used to read a row
*/
DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff,
@@ -860,7 +922,7 @@ int ha_berkeley::write_row(byte * record)
int error;
DBUG_ENTER("write_row");
- statistic_increment(ha_write_count,&LOCK_status);
+ 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();
if (table->next_number_field && record == table->record[0])
@@ -868,7 +930,8 @@ int ha_berkeley::write_row(byte * record)
if ((error=pack_row(&row, record,1)))
DBUG_RETURN(error); /* purecov: inspected */
- if (table->keys + test(hidden_primary_key) == 1)
+ table->insert_or_update= 1; // For handling of VARCHAR
+ if (table->s->keys + test(hidden_primary_key) == 1)
{
error=file->put(file, transaction, create_key(&prim_key, primary_key,
key_buff, record),
@@ -879,7 +942,8 @@ int ha_berkeley::write_row(byte * record)
{
DB_TXN *sub_trans = transaction;
/* Don't use sub transactions in temporary tables */
- ulong thd_options = table->tmp_table == NO_TMP_TABLE ? table->in_use->options : 0;
+ ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ?
+ table->in_use->options : 0);
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
key_map changed_keys(0);
@@ -894,7 +958,7 @@ int ha_berkeley::write_row(byte * record)
&row, key_type[primary_key])))
{
changed_keys.set_bit(primary_key);
- for (uint keynr=0 ; keynr < table->keys ; keynr++)
+ for (uint keynr=0 ; keynr < table->s->keys ; keynr++)
{
if (keynr == primary_key)
continue;
@@ -926,7 +990,8 @@ int ha_berkeley::write_row(byte * record)
else if (!changed_keys.is_clear_all())
{
new_error = 0;
- for (uint keynr=0 ; keynr < table->keys+test(hidden_primary_key) ;
+ for (uint keynr=0;
+ keynr < table->s->keys+test(hidden_primary_key);
keynr++)
{
if (changed_keys.is_set(keynr))
@@ -953,6 +1018,7 @@ int ha_berkeley::write_row(byte * record)
break;
}
}
+ table->insert_or_update= 0;
if (error == DB_KEYEXIST)
error=HA_ERR_FOUND_DUPP_KEY;
else if (!error)
@@ -977,7 +1043,7 @@ int ha_berkeley::key_cmp(uint keynr, const byte * old_row,
(new_row[key_part->null_offset] & key_part->null_bit))
return 1;
}
- if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
{
if (key_part->field->cmp_binary((char*) (old_row + key_part->offset),
@@ -1075,7 +1141,7 @@ int ha_berkeley::restore_keys(DB_TXN *trans, key_map *changed_keys,
that one just put back the old value. */
if (!changed_keys->is_clear_all())
{
- for (keynr=0 ; keynr < table->keys+test(hidden_primary_key) ; keynr++)
+ for (keynr=0 ; keynr < table->s->keys+test(hidden_primary_key) ; keynr++)
{
if (changed_keys->is_set(keynr))
{
@@ -1102,15 +1168,17 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
DBT prim_key, key, old_prim_key;
int error;
DB_TXN *sub_trans;
- ulong thd_options = table->tmp_table == NO_TMP_TABLE ? table->in_use->options : 0;
+ ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ?
+ table->in_use->options : 0);
bool primary_key_changed;
DBUG_ENTER("update_row");
LINT_INIT(error);
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_update_count,&LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
+ table->insert_or_update= 1; // For handling of VARCHAR
if (hidden_primary_key)
{
primary_key_changed=0;
@@ -1146,7 +1214,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
thd_options, using_ignore)))
{
// Update all other keys
- for (uint keynr=0 ; keynr < table->keys ; keynr++)
+ for (uint keynr=0 ; keynr < table->s->keys ; keynr++)
{
if (keynr == primary_key)
continue;
@@ -1163,6 +1231,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
if (new_error)
error = new_error;
}
+ table->insert_or_update= 0;
DBUG_RETURN(error); // Fatal error /* purecov: inspected */
}
changed_keys.set_bit(keynr);
@@ -1195,8 +1264,9 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
thd_options);
if (new_error)
{
- error=new_error; // This shouldn't happen /* purecov: inspected */
- break; /* purecov: inspected */
+ /* This shouldn't happen */
+ error=new_error; /* purecov: inspected */
+ break; /* purecov: inspected */
}
}
}
@@ -1208,6 +1278,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
if (error != DB_LOCK_DEADLOCK)
break;
}
+ table->insert_or_update= 0;
if (error == DB_KEYEXIST)
error=HA_ERR_FOUND_DUPP_KEY;
DBUG_RETURN(error);
@@ -1274,7 +1345,9 @@ int ha_berkeley::remove_keys(DB_TXN *trans, const byte *record,
DBT *new_record, DBT *prim_key, key_map *keys)
{
int result = 0;
- for (uint keynr=0 ; keynr < table->keys+test(hidden_primary_key) ; keynr++)
+ for (uint keynr=0;
+ keynr < table->s->keys+test(hidden_primary_key);
+ keynr++)
{
if (keys->is_set(keynr))
{
@@ -1294,10 +1367,11 @@ int ha_berkeley::delete_row(const byte * record)
{
int error;
DBT row, prim_key;
- key_map keys=table->keys_in_use;
- ulong thd_options = table->tmp_table == NO_TMP_TABLE ? table->in_use->options : 0;
+ key_map keys= table->s->keys_in_use;
+ ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ?
+ table->in_use->options : 0);
DBUG_ENTER("delete_row");
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
if ((error=pack_row(&row, record, 0)))
DBUG_RETURN((error)); /* purecov: inspected */
@@ -1354,7 +1428,7 @@ int ha_berkeley::index_init(uint keynr)
{
int error;
DBUG_ENTER("ha_berkeley::index_init");
- DBUG_PRINT("enter",("table: '%s' key: %d", table->real_name, keynr));
+ DBUG_PRINT("enter",("table: '%s' key: %d", table->s->table_name, keynr));
/*
Under some very rare conditions (like full joins) we may already have
@@ -1381,7 +1455,7 @@ int ha_berkeley::index_end()
DBUG_ENTER("ha_berkely::index_end");
if (cursor)
{
- DBUG_PRINT("enter",("table: '%s'", table->real_name));
+ DBUG_PRINT("enter",("table: '%s'", table->s->table_name));
error=cursor->c_close(cursor);
cursor=0;
}
@@ -1444,7 +1518,7 @@ int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row,
int ha_berkeley::index_read_idx(byte * buf, uint keynr, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ table->in_use->status_var.ha_read_key_count++;
DBUG_ENTER("index_read_idx");
current_row.flags=DB_DBT_REALLOC;
active_index=MAX_KEY;
@@ -1465,7 +1539,7 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
int do_prev= 0;
DBUG_ENTER("ha_berkeley::index_read");
- statistic_increment(ha_read_key_count,&LOCK_status);
+ table->in_use->status_var.ha_read_key_count++;
bzero((char*) &row,sizeof(row));
if (find_flag == HA_READ_BEFORE_KEY)
{
@@ -1477,7 +1551,8 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
find_flag= HA_READ_AFTER_KEY;
do_prev= 1;
}
- if (key_len == key_info->key_length)
+ if (key_len == key_info->key_length &&
+ !(table->key_info[active_index].flags & HA_END_SPACE_KEY))
{
if (find_flag == HA_READ_AFTER_KEY)
key_info->handler.bdb_return_if_eq= 1;
@@ -1534,7 +1609,8 @@ int ha_berkeley::index_read_last(byte * buf, const byte * key, uint key_len)
KEY *key_info= &table->key_info[active_index];
DBUG_ENTER("ha_berkeley::index_read");
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
/* read of partial key */
@@ -1558,7 +1634,8 @@ int ha_berkeley::index_next(byte * buf)
{
DBT row;
DBUG_ENTER("index_next");
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
(char*) buf, active_index, &row, &last_key, 1));
@@ -1569,9 +1646,11 @@ int ha_berkeley::index_next_same(byte * buf, const byte *key, uint keylen)
DBT row;
int error;
DBUG_ENTER("index_next_same");
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
- if (keylen == table->key_info[active_index].key_length)
+ if (keylen == table->key_info[active_index].key_length &&
+ !(table->key_info[active_index].flags & HA_END_SPACE_KEY))
error=read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT_DUP),
(char*) buf, active_index, &row, &last_key, 1);
else
@@ -1589,7 +1668,8 @@ int ha_berkeley::index_prev(byte * buf)
{
DBT row;
DBUG_ENTER("index_prev");
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_prev_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_PREV),
(char*) buf, active_index, &row, &last_key, 1));
@@ -1600,7 +1680,8 @@ int ha_berkeley::index_first(byte * buf)
{
DBT row;
DBUG_ENTER("index_first");
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_first_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_FIRST),
(char*) buf, active_index, &row, &last_key, 1));
@@ -1610,7 +1691,8 @@ int ha_berkeley::index_last(byte * buf)
{
DBT row;
DBUG_ENTER("index_last");
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_last_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_LAST),
(char*) buf, active_index, &row, &last_key, 0));
@@ -1632,7 +1714,8 @@ int ha_berkeley::rnd_next(byte *buf)
{
DBT row;
DBUG_ENTER("rnd_next");
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
(char*) buf, primary_key, &row, &last_key, 1));
@@ -1656,6 +1739,7 @@ DBT *ha_berkeley::get_pos(DBT *to, byte *pos)
pos+=key_part->field->packed_col_length((char*) pos,key_part->length);
to->size= (uint) (pos- (byte*) to->data);
}
+ DBUG_DUMP("key", (char*) to->data, to->size);
return to;
}
@@ -1663,9 +1747,10 @@ DBT *ha_berkeley::get_pos(DBT *to, byte *pos)
int ha_berkeley::rnd_pos(byte * buf, byte *pos)
{
DBT db_pos;
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+
DBUG_ENTER("ha_berkeley::rnd_pos");
-
+ statistic_increment(table->in_use->status_var.ha_read_rnd_count,
+ &LOCK_status);
active_index= MAX_KEY;
DBUG_RETURN(read_row(file->get(file, transaction,
get_pos(&db_pos, pos),
@@ -1725,14 +1810,14 @@ void ha_berkeley::info(uint flag)
if ((flag & HA_STATUS_CONST) || version != share->version)
{
version=share->version;
- for (uint i=0 ; i < table->keys ; i++)
+ for (uint i=0 ; i < table->s->keys ; i++)
{
table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]=
share->rec_per_key[i];
}
}
/* Don't return key if we got an error for the internal primary key */
- if (flag & HA_STATUS_ERRKEY && last_dup_key < table->keys)
+ if (flag & HA_STATUS_ERRKEY && last_dup_key < table->s->keys)
errkey= last_dup_key;
DBUG_VOID_RETURN;
}
@@ -1794,61 +1879,65 @@ int ha_berkeley::reset(void)
int ha_berkeley::external_lock(THD *thd, int lock_type)
{
int error=0;
+ berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
DBUG_ENTER("ha_berkeley::external_lock");
+ if (!trx)
+ {
+ thd->ha_data[berkeley_hton.slot]= trx= (berkeley_trx_data *)
+ my_malloc(sizeof(*trx), MYF(MY_ZEROFILL));
+ if (!trx)
+ DBUG_RETURN(1);
+ }
if (lock_type != F_UNLCK)
{
- if (!thd->transaction.bdb_lock_count++)
+ if (!trx->bdb_lock_count++)
{
- DBUG_ASSERT(thd->transaction.stmt.bdb_tid == 0);
+ DBUG_ASSERT(trx->stmt == 0);
transaction=0; // Safety
/* First table lock, start transaction */
if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
- OPTION_TABLE_LOCK)) &&
- !thd->transaction.all.bdb_tid)
+ OPTION_TABLE_LOCK)) && !trx->all)
{
/* We have to start a master transaction */
- DBUG_PRINT("trans",("starting transaction all"));
- if ((error=txn_begin(db_env, 0,
- (DB_TXN**) &thd->transaction.all.bdb_tid,
- 0)))
+ DBUG_PRINT("trans",("starting transaction all: options: 0x%lx",
+ (ulong) thd->options));
+ if ((error=txn_begin(db_env, 0, &trx->all, 0)))
{
- thd->transaction.bdb_lock_count--; // We didn't get the lock /* purecov: inspected */
- DBUG_RETURN(error); /* purecov: inspected */
+ trx->bdb_lock_count--; // We didn't get the lock
+ DBUG_RETURN(error);
}
+ trans_register_ha(thd, TRUE, &berkeley_hton);
if (thd->in_lock_tables)
DBUG_RETURN(0); // Don't create stmt trans
}
DBUG_PRINT("trans",("starting transaction stmt"));
- if ((error=txn_begin(db_env,
- (DB_TXN*) thd->transaction.all.bdb_tid,
- (DB_TXN**) &thd->transaction.stmt.bdb_tid,
- 0)))
+ if ((error=txn_begin(db_env, trx->all, &trx->stmt, 0)))
{
/* We leave the possible master transaction open */
- thd->transaction.bdb_lock_count--; // We didn't get the lock /* purecov: inspected */
- DBUG_RETURN(error); /* purecov: inspected */
+ trx->bdb_lock_count--; // We didn't get the lock
+ DBUG_RETURN(error);
}
+ trans_register_ha(thd, FALSE, &berkeley_hton);
}
- transaction= (DB_TXN*) thd->transaction.stmt.bdb_tid;
+ transaction= trx->stmt;
}
else
{
lock.type=TL_UNLOCK; // Unlocked
thread_safe_add(share->rows, changed_rows, &share->mutex);
changed_rows=0;
- if (!--thd->transaction.bdb_lock_count)
+ if (!--trx->bdb_lock_count)
{
- if (thd->transaction.stmt.bdb_tid)
+ if (trx->stmt)
{
/*
- F_UNLOCK is done without a transaction commit / rollback.
+ F_UNLCK is done without a transaction commit / rollback.
This happens if the thread didn't update any rows
We must in this case commit the work to keep the row locks
*/
DBUG_PRINT("trans",("commiting non-updating transaction"));
- error=txn_commit((DB_TXN*) thd->transaction.stmt.bdb_tid,0);
- thd->transaction.stmt.bdb_tid=0;
- transaction=0;
+ error= txn_commit(trx->stmt,0);
+ trx->stmt= transaction= 0;
}
}
}
@@ -1866,14 +1955,20 @@ int ha_berkeley::start_stmt(THD *thd)
{
int error=0;
DBUG_ENTER("ha_berkeley::start_stmt");
- if (!thd->transaction.stmt.bdb_tid)
+ berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
+ DBUG_ASSERT(trx);
+ /*
+ note that trx->stmt may have been already initialized as start_stmt()
+ is called for *each table* not for each storage engine,
+ and there could be many bdb tables referenced in the query
+ */
+ if (!trx->stmt)
{
DBUG_PRINT("trans",("starting transaction stmt"));
- error=txn_begin(db_env, (DB_TXN*) thd->transaction.all.bdb_tid,
- (DB_TXN**) &thd->transaction.stmt.bdb_tid,
- 0);
+ error=txn_begin(db_env, trx->all, &trx->stmt, 0);
+ trans_register_ha(thd, FALSE, &berkeley_hton);
}
- transaction= (DB_TXN*) thd->transaction.stmt.bdb_tid;
+ transaction= trx->stmt;
DBUG_RETURN(error);
}
@@ -1973,9 +2068,9 @@ int ha_berkeley::create(const char *name, register TABLE *form,
if ((error= create_sub_table(name_buff,"main",DB_BTREE,0)))
DBUG_RETURN(error); /* purecov: inspected */
- primary_key=table->primary_key;
+ primary_key= table->s->primary_key;
/* Create the keys */
- for (uint i=0; i < form->keys; i++)
+ for (uint i=0; i < form->s->keys; i++)
{
if (i != primary_key)
{
@@ -1997,7 +2092,7 @@ int ha_berkeley::create(const char *name, register TABLE *form,
"status", DB_BTREE, DB_CREATE, 0))))
{
char rec_buff[4+MAX_KEY*4];
- uint length= 4+ table->keys*4;
+ uint length= 4+ table->s->keys*4;
bzero(rec_buff, length);
error= write_status(status_block, rec_buff, length);
status_block->close(status_block,0);
@@ -2061,19 +2156,35 @@ ha_rows ha_berkeley::records_in_range(uint keynr, key_range *start_key,
DB_KEY_RANGE start_range, end_range;
DB *kfile=key_file[keynr];
double start_pos,end_pos,rows;
- DBUG_ENTER("records_in_range");
-
- if ((start_key && kfile->key_range(kfile,transaction,
- pack_key(&key, keynr, key_buff,
- start_key->key,
- start_key->length),
- &start_range,0)) ||
- (end_key && kfile->key_range(kfile,transaction,
- pack_key(&key, keynr, key_buff,
- end_key->key,
- end_key->length),
- &end_range,0)))
- DBUG_RETURN(HA_BERKELEY_RANGE_COUNT); // Better than returning an error /* purecov: inspected */
+ bool error;
+ KEY *key_info= &table->key_info[keynr];
+ DBUG_ENTER("ha_berkeley::records_in_range");
+
+ /* Ensure we get maximum range, even for varchar keys with different space */
+ key_info->handler.bdb_return_if_eq= -1;
+ error= ((start_key && kfile->key_range(kfile,transaction,
+ pack_key(&key, keynr, key_buff,
+ start_key->key,
+ start_key->length),
+ &start_range,0)));
+ if (error)
+ {
+ key_info->handler.bdb_return_if_eq= 0;
+ // Better than returning an error
+ DBUG_RETURN(HA_BERKELEY_RANGE_COUNT); /* purecov: inspected */
+ }
+ key_info->handler.bdb_return_if_eq= 1;
+ error= (end_key && kfile->key_range(kfile,transaction,
+ pack_key(&key, keynr, key_buff,
+ end_key->key,
+ end_key->length),
+ &end_range,0));
+ key_info->handler.bdb_return_if_eq= 0;
+ if (error)
+ {
+ // Better than returning an error
+ DBUG_RETURN(HA_BERKELEY_RANGE_COUNT); /* purecov: inspected */
+ }
if (!start_key)
start_pos= 0.0;
@@ -2094,16 +2205,16 @@ ha_rows ha_berkeley::records_in_range(uint keynr, key_range *start_key,
}
-longlong ha_berkeley::get_auto_increment()
+ulonglong ha_berkeley::get_auto_increment()
{
- longlong nr=1; // Default if error or new key
+ ulonglong nr=1; // Default if error or new key
int error;
(void) ha_berkeley::extra(HA_EXTRA_KEYREAD);
/* Set 'active_index' */
- ha_berkeley::index_init(table->next_number_index);
+ ha_berkeley::index_init(table->s->next_number_index);
- if (!table->next_number_key_offset)
+ if (!table->s->next_number_key_offset)
{ // Autoincrement at key-start
error=ha_berkeley::index_last(table->record[1]);
}
@@ -2116,7 +2227,7 @@ longlong ha_berkeley::get_auto_increment()
/* Reading next available number for a sub key */
ha_berkeley::create_key(&last_key, active_index,
key_buff, table->record[0],
- table->next_number_key_offset);
+ table->s->next_number_key_offset);
/* Store for compare */
memcpy(old_key.data=key_buff2, key_buff, (old_key.size=last_key.size));
old_key.app_private=(void*) key_info;
@@ -2145,8 +2256,8 @@ longlong ha_berkeley::get_auto_increment()
}
}
if (!error)
- nr=(longlong)
- table->next_number_field->val_int_offset(table->rec_buff_length)+1;
+ nr= (ulonglong)
+ table->next_number_field->val_int_offset(table->s->rec_buff_length)+1;
ha_berkeley::index_end();
(void) ha_berkeley::extra(HA_EXTRA_NO_KEYREAD);
return nr;
@@ -2184,7 +2295,7 @@ static void print_msg(THD *thd, const char *table_name, const char *op_name,
protocol->store(msg_type);
protocol->store(msgbuf);
if (protocol->write())
- thd->killed=1;
+ thd->killed=THD::KILL_CONNECTION;
}
#endif
@@ -2193,6 +2304,8 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
uint i;
DB_BTREE_STAT *stat=0;
DB_TXN_STAT *txn_stat_ptr= 0;
+ berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
+ DBUG_ASSERT(trx);
/*
Original bdb documentation says:
@@ -2207,13 +2320,10 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
txn_stat_ptr && txn_stat_ptr->st_nactive>=2)
{
DB_TXN_ACTIVE *atxn_stmt= 0, *atxn_all= 0;
-
- DB_TXN *txn_all= (DB_TXN*) thd->transaction.all.bdb_tid;
- u_int32_t all_id= txn_all->id(txn_all);
-
- DB_TXN *txn_stmt= (DB_TXN*) thd->transaction.stmt.bdb_tid;
- u_int32_t stmt_id= txn_stmt->id(txn_stmt);
-
+
+ u_int32_t all_id= trx->all->id(trx->all);
+ u_int32_t stmt_id= trx->stmt->id(trx->stmt);
+
DB_TXN_ACTIVE *cur= txn_stat_ptr->st_txnarray;
DB_TXN_ACTIVE *end= cur + txn_stat_ptr->st_nactive;
for (; cur!=end && (!atxn_stmt || !atxn_all); cur++)
@@ -2221,7 +2331,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
if (cur->txnid==all_id) atxn_all= cur;
if (cur->txnid==stmt_id) atxn_stmt= cur;
}
-
+
if (atxn_stmt && atxn_all &&
log_compare(&atxn_stmt->lsn,&atxn_all->lsn))
{
@@ -2231,7 +2341,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
free(txn_stat_ptr);
}
- for (i=0 ; i < table->keys ; i++)
+ for (i=0 ; i < table->s->keys ; i++)
{
if (stat)
{
@@ -2366,14 +2476,15 @@ static BDB_SHARE *get_share(const char *table_name, TABLE *table)
char *tmp_name;
DB **key_file;
u_int32_t *key_type;
+ uint keys= table->s->keys;
if ((share=(BDB_SHARE *)
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
&share, sizeof(*share),
- &rec_per_key, table->keys * sizeof(ha_rows),
+ &rec_per_key, keys * sizeof(ha_rows),
&tmp_name, length+1,
- &key_file, (table->keys+1) * sizeof(*key_file),
- &key_type, (table->keys+1) * sizeof(u_int32_t),
+ &key_file, (keys+1) * sizeof(*key_file),
+ &key_type, (keys+1) * sizeof(u_int32_t),
NullS)))
{
share->rec_per_key = rec_per_key;
@@ -2400,7 +2511,7 @@ static int free_share(BDB_SHARE *share, TABLE *table, uint hidden_primary_key,
bool mutex_is_locked)
{
int error, result = 0;
- uint keys=table->keys + test(hidden_primary_key);
+ uint keys= table->s->keys + test(hidden_primary_key);
pthread_mutex_lock(&bdb_mutex);
if (mutex_is_locked)
pthread_mutex_unlock(&share->mutex); /* purecov: inspected */
@@ -2464,8 +2575,8 @@ void ha_berkeley::get_status()
}
if (!(share->status & STATUS_ROW_COUNT_INIT) && share->status_block)
{
- share->org_rows=share->rows=
- table->max_rows ? table->max_rows : HA_BERKELEY_MAX_ROWS;
+ share->org_rows= share->rows=
+ table->s->max_rows ? table->s->max_rows : HA_BERKELEY_MAX_ROWS;
if (!share->status_block->cursor(share->status_block, 0, &cursor, 0))
{
DBT row;
@@ -2480,9 +2591,10 @@ void ha_berkeley::get_status()
uint i;
uchar *pos=(uchar*) row.data;
share->org_rows=share->rows=uint4korr(pos); pos+=4;
- for (i=0 ; i < table->keys ; i++)
+ for (i=0 ; i < table->s->keys ; i++)
{
- share->rec_per_key[i]=uint4korr(pos); pos+=4;
+ share->rec_per_key[i]=uint4korr(pos);
+ pos+=4;
}
}
cursor->c_close(cursor);
@@ -2540,7 +2652,7 @@ static void update_status(BDB_SHARE *share, TABLE *table)
{
char rec_buff[4+MAX_KEY*4], *pos=rec_buff;
int4store(pos,share->rows); pos+=4;
- for (uint i=0 ; i < table->keys ; i++)
+ for (uint i=0 ; i < table->s->keys ; i++)
{
int4store(pos,share->rec_per_key[i]); pos+=4;
}
@@ -2556,6 +2668,7 @@ end:
DBUG_VOID_RETURN;
}
+
/*
Return an estimated of the number of rows in the table.
Used when sorting to allocate buffers and by the optimizer.
@@ -2566,4 +2679,29 @@ ha_rows ha_berkeley::estimate_rows_upper_bound()
return share->rows + HA_BERKELEY_EXTRA_ROWS;
}
+int ha_berkeley::cmp_ref(const byte *ref1, const byte *ref2)
+{
+ if (hidden_primary_key)
+ return memcmp(ref1, ref2, BDB_HIDDEN_PRIMARY_KEY_LENGTH);
+
+ int result;
+ Field *field;
+ 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;
+
+ for (; key_part != end; key_part++)
+ {
+ field= key_part->field;
+ result= field->pack_cmp((const char*)ref1, (const char*)ref2,
+ key_part->length, 0);
+ if (result)
+ return result;
+ ref1+= field->packed_col_length((const char*)ref1, key_part->length);
+ ref2+= field->packed_col_length((const char*)ref2, key_part->length);
+ }
+
+ return 0;
+}
+
#endif /* HAVE_BERKELEY_DB */
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index 25d3e128502..10e61455867 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -153,9 +153,11 @@ class ha_berkeley: public handler
int5store(to,share->auto_ident);
pthread_mutex_unlock(&share->mutex);
}
- longlong get_auto_increment();
+ ulonglong get_auto_increment();
void print_error(int error, myf errflag);
uint8 table_cache_type() { return HA_CACHE_TBL_TRANSACT; }
+ bool primary_key_is_clustered() { return true; }
+ int cmp_ref(const byte *ref1, const byte *ref2);
};
extern bool berkeley_shared_data;
@@ -166,9 +168,7 @@ extern char *berkeley_home, *berkeley_tmpdir, *berkeley_logdir;
extern long berkeley_lock_scan_time;
extern TYPELIB berkeley_lock_typelib;
-bool berkeley_init(void);
+handlerton *berkeley_init(void);
bool berkeley_end(void);
bool berkeley_flush_logs(void);
-int berkeley_commit(THD *thd, void *trans);
-int berkeley_rollback(THD *thd, void *trans);
int berkeley_show_logs(Protocol *protocol);
diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc
index e34d5d723a4..d9aedbe751d 100644
--- a/sql/ha_blackhole.cc
+++ b/sql/ha_blackhole.cc
@@ -25,10 +25,13 @@
#include "ha_blackhole.h"
+static const char *ha_black_hole_exts[] = {
+ NullS
+};
+
const char **ha_blackhole::bas_ext() const
-{
- static const char *ext[]= { NullS };
- return ext;
+{
+ return ha_blackhole_exts;
}
int ha_blackhole::open(const char *name, int mode, uint test_if_locked)
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
new file mode 100644
index 00000000000..0ac209d82e0
--- /dev/null
+++ b/sql/ha_federated.cc
@@ -0,0 +1,1927 @@
+/* Copyright (C) 2004 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 */
+
+/*
+
+ MySQL Federated Storage Engine
+
+ ha_federated.cc - MySQL Federated Storage Engine
+ Patrick Galbraith and Brian Aker, 2004
+
+ This is a handler which uses a foreign database as the data file, as
+ opposed to a handler like MyISAM, which uses .MYD files locally.
+
+ How this handler works
+ ----------------------------------
+ Normal database files are local and as such: You create a table called
+ 'users', a file such as 'users.MYD' is created. A handler reads, inserts,
+ deletes, updates data in this file. The data is stored in particular format,
+ so to read, that data has to be parsed into fields, to write, fields have to
+ be stored in this format to write to this data file.
+
+ With MySQL Federated storage engine, there will be no local files for each
+ table's data (such as .MYD). A foreign database will store the data that would
+ normally be in this file. This will necessitate the use of MySQL client API
+ to read, delete, update, insert this data. The data will have to be retrieve
+ via an SQL call "SELECT * FROM users". Then, to read this data, it will have
+ to be retrieved via mysql_fetch_row one row at a time, then converted from
+ the column in this select into the format that the handler expects.
+
+ The create table will simply create the .frm file, and within the
+ "CREATE TABLE" SQL, there SHALL be any of the following :
+
+ comment=scheme://username:password@hostname:port/database/tablename
+ comment=scheme://username@hostname/database/tablename
+ comment=scheme://username:password@hostname/database/tablename
+ comment=scheme://username:password@hostname/database/tablename
+
+ An example would be:
+
+ comment=mysql://username:password@hostname:port/database/tablename
+
+ ***IMPORTANT***
+
+ Only 'mysql://' is supported at this release.
+
+
+ This comment connection string is necessary for the handler to be
+ able to connect to the foreign server.
+
+
+ The basic flow is this:
+
+ SQL calls issues locally ->
+ mysql handler API (data in handler format) ->
+ mysql client API (data converted to SQL calls) ->
+ foreign database -> mysql client API ->
+ convert result sets (if any) to handler format ->
+ handler API -> results or rows affected to local
+
+ What this handler does and doesn't support
+ ------------------------------------------
+ * Tables MUST be created on the foreign server prior to any action on those
+ tables via the handler, first version. IMPORTANT: IF you MUST use the
+ federated storage engine type on the REMOTE end, MAKE SURE [ :) ] That
+ the table you connect to IS NOT a table pointing BACK to your ORIGNAL
+ table! You know and have heard the screaching of audio feedback? You
+ know putting two mirror in front of each other how the reflection
+ continues for eternity? Well, need I say more?!
+ * There will not be support for transactions.
+ * There is no way for the handler to know if the foreign database or table
+ has changed. The reason for this is that this database has to work like a
+ data file that would never be written to by anything other than the
+ database. The integrity of the data in the local table could be breached
+ if there was any change to the foreign database.
+ * Support for SELECT, INSERT, UPDATE , DELETE, indexes.
+ * No ALTER TABLE, DROP TABLE or any other Data Definition Language calls.
+ * Prepared statements will not be used in the first implementation, it
+ remains to to be seen whether the limited subset of the client API for the
+ server supports this.
+ * This uses SELECT, INSERT, UPDATE, DELETE and not HANDLER for its
+ implementation.
+ * This will not work with the query cache.
+
+ Method calls
+
+ A two column table, with one record:
+
+ (SELECT)
+
+ "SELECT * FROM foo"
+ ha_federated::info
+ ha_federated::scan_time:
+ ha_federated::rnd_init: share->select_query SELECT * FROM foo
+ ha_federated::extra
+
+ <for every row of data retrieved>
+ ha_federated::rnd_next
+ ha_federated::convert_row_to_internal_format
+ ha_federated::rnd_next
+ </for every row of data retrieved>
+
+ ha_federated::rnd_end
+ ha_federated::extra
+ ha_federated::reset
+
+ (INSERT)
+
+ "INSERT INTO foo (id, ts) VALUES (2, now());"
+
+ ha_federated::write_row
+
+ <for every field/column>
+ Field::quote_data
+ Field::quote_data
+ </for every field/column>
+
+ ha_federated::reset
+
+ (UPDATE)
+
+ "UPDATE foo SET ts = now() WHERE id = 1;"
+
+ ha_federated::index_init
+ ha_federated::index_read
+ ha_federated::index_read_idx
+ Field::quote_data
+ ha_federated::rnd_next
+ ha_federated::convert_row_to_internal_format
+ ha_federated::update_row
+
+ <quote 3 cols, new and old data>
+ Field::quote_data
+ Field::quote_data
+ Field::quote_data
+ Field::quote_data
+ Field::quote_data
+ Field::quote_data
+ </quote 3 cols, new and old data>
+
+ ha_federated::extra
+ ha_federated::extra
+ ha_federated::extra
+ ha_federated::external_lock
+ ha_federated::reset
+
+
+ How do I use this handler?
+ --------------------------
+ First of all, you need to build this storage engine:
+
+ ./configure --with-federated-storage-engine
+ make
+
+ Next, to use this handler, it's very simple. You must
+ have two databases running, either both on the same host, or
+ on different hosts.
+
+ One the server that will be connecting to the foreign
+ host (client), you create your table as such:
+
+ CREATE TABLE test_table (
+ id int(20) NOT NULL auto_increment,
+ name varchar(32) NOT NULL default '',
+ other int(20) NOT NULL default '0',
+ PRIMARY KEY (id),
+ KEY name (name),
+ KEY other_key (other))
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+ COMMENT='root@127.0.0.1:9306/federated/test_federated';
+
+ Notice the "COMMENT" and "ENGINE" field? This is where you
+ respectively set the engine type, "FEDERATED" and foreign
+ host information, this being the database your 'client' database
+ will connect to and use as the "data file". Obviously, the foreign
+ database is running on port 9306, so you want to start up your other
+ database so that it is indeed on port 9306, and your federated
+ database on a port other than that. In my setup, I use port 5554
+ for federated, and port 5555 for the foreign database.
+
+ Then, on the foreign database:
+
+ CREATE TABLE test_table (
+ id int(20) NOT NULL auto_increment,
+ name varchar(32) NOT NULL default '',
+ other int(20) NOT NULL default '0',
+ PRIMARY KEY (id),
+ KEY name (name),
+ KEY other_key (other))
+ ENGINE="<NAME>" <-- whatever you want, or not specify
+ DEFAULT CHARSET=latin1 ;
+
+ This table is exactly the same (and must be exactly the same),
+ except that it is not using the federated handler and does
+ not need the URL.
+
+
+ How to see the handler in action
+ --------------------------------
+
+ When developing this handler, I compiled the federated database with
+ debugging:
+
+ ./configure --with-federated-storage-engine
+ --prefix=/home/mysql/mysql-build/federated/ --with-debug
+
+ Once compiled, I did a 'make install' (not for the purpose of installing
+ the binary, but to install all the files the binary expects to see in the
+ diretory I specified in the build with --prefix,
+ "/home/mysql/mysql-build/federated".
+
+ Then, I started the foreign server:
+
+ /usr/local/mysql/bin/mysqld_safe
+ --user=mysql --log=/tmp/mysqld.5555.log -P 5555
+
+ Then, I went back to the directory containing the newly compiled mysqld,
+ <builddir>/sql/, started up gdb:
+
+ gdb ./mysqld
+
+ Then, withn the (gdb) prompt:
+ (gdb) run --gdb --port=5554 --socket=/tmp/mysqld.5554 --skip-innodb --debug
+
+ Next, I open several windows for each:
+
+ 1. Tail the debug trace: tail -f /tmp/mysqld.trace|grep ha_fed
+ 2. Tail the SQL calls to the foreign database: tail -f /tmp/mysqld.5555.log
+ 3. A window with a client open to the federated server on port 5554
+ 4. A window with a client open to the federated server on port 5555
+
+ I would create a table on the client to the foreign server on port
+ 5555, and then to the federated server on port 5554. At this point,
+ I would run whatever queries I wanted to on the federated server,
+ just always remembering that whatever changes I wanted to make on
+ the table, or if I created new tables, that I would have to do that
+ on the foreign server.
+
+ Another thing to look for is 'show variables' to show you that you have
+ support for federated handler support:
+
+ show variables like '%federat%'
+
+ and:
+
+ show storage engines;
+
+ Both should display the federated storage handler.
+
+
+ Testing
+ -------
+
+ There is a test for MySQL Federated Storage Handler in ./mysql-test/t,
+ federatedd.test It starts both a slave and master database using
+ the same setup that the replication tests use, with the exception that
+ it turns off replication, and sets replication to ignore the test tables.
+ After ensuring that you actually do have support for the federated storage
+ handler, numerous queries/inserts/updates/deletes are run, many derived
+ from the MyISAM tests, plus som other tests which were meant to reveal
+ any issues that would be most likely to affect this handler. All tests
+ should work! ;)
+
+ To run these tests, go into ./mysql-test (based in the directory you
+ built the server in)
+
+ ./mysql-test-run federatedd
+
+ To run the test, or if you want to run the test and have debug info:
+
+ ./mysql-test-run --debug federated
+
+ This will run the test in debug mode, and you can view the trace and
+ log files in the ./mysql-test/var/log directory
+
+ ls -l mysql-test/var/log/
+ -rw-r--r-- 1 patg patg 17 4 Dec 12:27 current_test
+ -rw-r--r-- 1 patg patg 692 4 Dec 12:52 manager.log
+ -rw-rw---- 1 patg patg 21246 4 Dec 12:51 master-bin.000001
+ -rw-rw---- 1 patg patg 68 4 Dec 12:28 master-bin.index
+ -rw-r--r-- 1 patg patg 1620 4 Dec 12:51 master.err
+ -rw-rw---- 1 patg patg 23179 4 Dec 12:51 master.log
+ -rw-rw---- 1 patg patg 16696550 4 Dec 12:51 master.trace
+ -rw-r--r-- 1 patg patg 0 4 Dec 12:28 mysqltest-time
+ -rw-r--r-- 1 patg patg 2024051 4 Dec 12:51 mysqltest.trace
+ -rw-rw---- 1 patg patg 94992 4 Dec 12:51 slave-bin.000001
+ -rw-rw---- 1 patg patg 67 4 Dec 12:28 slave-bin.index
+ -rw-rw---- 1 patg patg 249 4 Dec 12:52 slave-relay-bin.000003
+ -rw-rw---- 1 patg patg 73 4 Dec 12:28 slave-relay-bin.index
+ -rw-r--r-- 1 patg patg 1349 4 Dec 12:51 slave.err
+ -rw-rw---- 1 patg patg 96206 4 Dec 12:52 slave.log
+ -rw-rw---- 1 patg patg 15706355 4 Dec 12:51 slave.trace
+ -rw-r--r-- 1 patg patg 0 4 Dec 12:51 warnings
+
+ Of course, again, you can tail the trace log:
+
+ tail -f mysql-test/var/log/master.trace |grep ha_fed
+
+ As well as the slave query log:
+
+ tail -f mysql-test/var/log/slave.log
+
+ Files that comprise the test suit
+ ---------------------------------
+ mysql-test/t/federated.test
+ mysql-test/r/federated.result
+ mysql-test/r/have_federated_db.require
+ mysql-test/include/have_federated_db.inc
+
+
+ Other tidbits
+ -------------
+
+ These were the files that were modified or created for this
+ Federated handler to work:
+
+ ./configure.in
+ ./sql/Makefile.am
+ ./config/ac_macros/ha_federated.m4
+ ./sql/handler.cc
+ ./sql/mysqld.cc
+ ./sql/set_var.cc
+ ./sql/field.h
+ ./sql/sql_string.h
+ ./mysql-test/mysql-test-run(.sh)
+ ./mysql-test/t/federated.test
+ ./mysql-test/r/federated.result
+ ./mysql-test/r/have_federated_db.require
+ ./mysql-test/include/have_federated_db.inc
+ ./sql/ha_federated.cc
+ ./sql/ha_federated.h
+
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include <mysql_priv.h>
+
+#ifdef HAVE_FEDERATED_DB
+#include "ha_federated.h"
+#define MAX_REMOTE_SIZE IO_SIZE
+/* Variables for federated share methods */
+static HASH federated_open_tables; // Hash used to track open
+ // tables
+pthread_mutex_t federated_mutex; // This is the mutex we use to
+ // init the hash
+static int federated_init= FALSE; // Variable for checking the
+ // init state of hash
+
+/* Function we use in the creation of our hash to get key. */
+
+static byte *federated_get_key(FEDERATED_SHARE *share, uint *length,
+ my_bool not_used __attribute__ ((unused)))
+{
+ *length= share->table_name_length;
+ return (byte*) share->table_name;
+}
+
+/*
+ Initialize the federated handler.
+
+ SYNOPSIS
+ federated_db_init()
+ void
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool federated_db_init()
+{
+ federated_init= 1;
+ VOID(pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST));
+ return (hash_init(&federated_open_tables, system_charset_info, 32, 0, 0,
+ (hash_get_key) federated_get_key, 0, 0));
+}
+
+
+/*
+ Release the federated handler.
+
+ SYNOPSIS
+ federated_db_end()
+ void
+
+ RETURN
+ FALSE OK
+*/
+
+bool federated_db_end()
+{
+ if (federated_init)
+ {
+ hash_free(&federated_open_tables);
+ VOID(pthread_mutex_destroy(&federated_mutex));
+ }
+ federated_init= 0;
+ return FALSE;
+}
+
+
+/*
+ Check (in create) whether the tables exists, and that it can be connected to
+
+ SYNOPSIS
+ check_foreign_data_source()
+ share pointer to FEDERATED share
+
+ DESCRIPTION
+ This method first checks that the connection information that parse url
+ has populated into the share will be sufficient to connect to the foreign
+ table, and if so, does the foreign table exist.
+*/
+
+static int check_foreign_data_source(FEDERATED_SHARE *share)
+{
+ char escaped_table_base_name[IO_SIZE];
+ MYSQL *mysql;
+ MYSQL_RES *result=0;
+ uint error_code;
+ char query_buffer[IO_SIZE];
+ char error_buffer[IO_SIZE];
+ String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
+ DBUG_ENTER("ha_federated::check_foreign_data_source");
+ query.length(0);
+
+ /* error out if we can't alloc memory for mysql_init(NULL) (per Georg) */
+ if (! (mysql= mysql_init(NULL)))
+ {
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ /* check if we can connect */
+ if (!mysql_real_connect(mysql,
+ share->hostname,
+ share->username,
+ share->password,
+ share->database,
+ share->port,
+ share->socket, 0))
+ {
+ my_sprintf(error_buffer,
+ (error_buffer,
+ "unable to connect to database '%s' on host '%s as user '%s' !",
+ share->database, share->hostname, share->username));
+ error_code= ER_CONNECT_TO_MASTER;
+ goto error;
+ }
+ else
+ {
+ /*
+ 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
+ */
+ query.append("SHOW TABLES LIKE '");
+ escape_string_for_mysql(&my_charset_bin, (char *)escaped_table_base_name,
+ sizeof(escaped_table_base_name),
+ share->table_base_name,
+ share->table_base_name_length);
+ query.append(escaped_table_base_name);
+ query.append("'");
+
+ error_code= ER_QUERY_ON_MASTER;
+ if (mysql_real_query(mysql, query.ptr(), query.length()))
+ goto error;
+
+ result= mysql_store_result(mysql);
+ if (! result)
+ goto error;
+
+ /* if ! mysql_num_rows, the table doesn't exist, send error */
+ if (! mysql_num_rows(result))
+ {
+ my_sprintf(error_buffer,
+ (error_buffer, "foreign table '%s' does not exist!",
+ share->table_base_name));
+ goto error;
+ }
+ mysql_free_result(result);
+ result= 0;
+ mysql_close(mysql);
+
+ }
+ DBUG_RETURN(0);
+
+error:
+ if (result)
+ mysql_free_result(result);
+ mysql_close(mysql);
+ my_error(error_code, MYF(0), error_buffer);
+ DBUG_RETURN(error_code);
+
+}
+
+
+/*
+ Parse connection info from table->s->comment
+
+ SYNOPSIS
+ parse_url()
+ share pointer to FEDERATED share
+ table pointer to current TABLE class
+ table_create_flag determines what error to throw
+
+ DESCRIPTION
+ populates the share with information about the connection
+ to the foreign database that will serve as the data source.
+ This string must be specified (currently) in the "comment" field,
+ listed in the CREATE TABLE statement.
+
+ This string MUST be in the format of any of these:
+
+ scheme://username:password@hostname:port/database/table
+ scheme://username@hostname/database/table
+ scheme://username@hostname:port/database/table
+ scheme://username:password@hostname/database/table
+
+ An Example:
+
+ mysql://joe:joespass@192.168.1.111:9308/federated/testtable
+
+ ***IMPORTANT***
+ Currently, only "mysql://" is supported.
+
+ 'password' and 'port' are both optional.
+
+ RETURN VALUE
+ 0 success
+ 1 failure, wrong string format
+
+*/
+
+static int parse_url(FEDERATED_SHARE *share, TABLE *table,
+ uint table_create_flag)
+{
+ uint error_num= (table_create_flag ? ER_CANT_CREATE_TABLE :
+ ER_CONNECT_TO_MASTER);
+ DBUG_ENTER("ha_federated::parse_url");
+
+ share->port= 0;
+ share->socket= 0;
+ share->scheme= my_strdup(table->s->comment, MYF(0));
+
+ if ((share->username= strstr(share->scheme, "://")))
+ {
+ share->scheme[share->username - share->scheme]= '\0';
+
+ if (strcmp(share->scheme, "mysql") != 0)
+ goto error;
+
+ share->username+= 3;
+
+ if ((share->hostname= strchr(share->username, '@')))
+ {
+ share->username[share->hostname - share->username]= '\0';
+ share->hostname++;
+
+ if ((share->password= strchr(share->username, ':')))
+ {
+ share->username[share->password - share->username]= '\0';
+ share->password++;
+ share->username= share->username;
+ /* make sure there isn't an extra / or @ */
+ if ((strchr(share->password, '/') || strchr(share->hostname, '@')))
+ goto error;
+ /*
+ Found that if the string is:
+ user:@hostname:port/database/table
+ Then password is a null string, so set to NULL
+ */
+ if ((share->password[0] == '\0'))
+ share->password= NULL;
+ }
+ else
+ share->username= share->username;
+
+ /* make sure there isn't an extra / or @ */
+ if ((strchr(share->username, '/')) || (strchr(share->hostname, '@')))
+ goto error;
+
+ if ((share->database= strchr(share->hostname, '/')))
+ {
+ share->hostname[share->database - share->hostname]= '\0';
+ share->database++;
+
+ if ((share->sport= strchr(share->hostname, ':')))
+ {
+ share->hostname[share->sport - share->hostname]= '\0';
+ share->sport++;
+ if (share->sport[0] == '\0')
+ share->sport= NULL;
+ else
+ share->port= atoi(share->sport);
+ }
+
+ if ((share->table_base_name= strchr(share->database, '/')))
+ {
+ share->database[share->table_base_name - share->database]= '\0';
+ share->table_base_name++;
+ }
+ else
+ goto error;
+
+ share->table_base_name_length= strlen(share->table_base_name);
+ }
+ else
+ goto error;
+ /* make sure there's not an extra / */
+ if ((strchr(share->table_base_name, '/')))
+ goto error;
+
+ if (share->hostname[0] == '\0')
+ share->hostname= NULL;
+
+ if (!share->port)
+ {
+ if (strcmp(share->hostname, my_localhost) == 0)
+ share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0));
+ else
+ share->port= MYSQL_PORT;
+ }
+
+ DBUG_PRINT("info",
+ ("scheme %s username %s password %s \
+ hostname %s port %d database %s tablename %s\n",
+ share->scheme, share->username, share->password,
+ share->hostname, share->port, share->database,
+ share->table_base_name));
+ }
+ else
+ goto error;
+ }
+ else
+ goto error;
+
+ DBUG_RETURN(0);
+
+error:
+ my_error(error_num, MYF(0),
+ "connection string is not in the correct format",0);
+ DBUG_RETURN(1);
+
+}
+
+
+/*
+ Convert MySQL result set row to handler internal format
+
+ SYNOPSIS
+ convert_row_to_internal_format()
+ record Byte pointer to record
+ row MySQL result set row from fetchrow()
+
+ DESCRIPTION
+ This method simply iterates through a row returned via fetchrow with
+ values from a successful SELECT , and then stores each column's value
+ in the field object via the field object pointer (pointing to the table's
+ array of field object pointers). This is how the handler needs the data
+ to be stored to then return results back to the user
+
+ RETURN VALUE
+ 0 After fields have had field values stored from record
+ */
+
+uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row)
+{
+ ulong *lengths;
+ uint num_fields;
+ uint x= 0;
+
+ DBUG_ENTER("ha_federated::convert_row_to_internal_format");
+
+ num_fields= mysql_num_fields(result);
+ lengths= mysql_fetch_lengths(result);
+
+ memset(record, 0, table->s->null_bytes);
+
+ for (Field **field= table->field; *field; field++, x++)
+ {
+ if (!row[x])
+ (*field)->set_null();
+ else
+ (*field)->store(row[x], lengths[x], &my_charset_bin);
+ }
+
+ DBUG_RETURN(0);
+}
+
+/*
+ Create a WHERE clause based off of values in keys
+ Note: This code was inspired by key_copy from key.cc
+
+ SYNOPSIS
+ create_where_from_key ()
+ to String object to store WHERE clause
+ key_info KEY struct pointer
+ key byte pointer containing key
+ key_length length of key
+
+ DESCRIPTION
+ Using iteration through all the keys via a KEY_PART_INFO pointer,
+ This method 'extracts' the value of each key in the byte pointer
+ *key, and for each key found, constructs an appropriate WHERE clause
+
+ RETURN VALUE
+ 0 After all keys have been accounted for to create the WHERE clause
+ 1 No keys found
+
+ */
+
+bool ha_federated::create_where_from_key(String *to, KEY *key_info,
+ const byte *key, uint key_length)
+{
+ uint second_loop= 0;
+ KEY_PART_INFO *key_part;
+ bool needs_quotes;
+ String tmp;
+
+ DBUG_ENTER("ha_federated::create_where_from_key");
+ for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
+ {
+ Field *field= key_part->field;
+ needs_quotes= field->needs_quotes();
+ uint length= key_part->length;
+
+ if (second_loop++ && to->append(" AND ", 5))
+ DBUG_RETURN(1);
+ if (to->append('`') || to->append(field->field_name) || to->append("` ", 2))
+ DBUG_RETURN(1); // Out of memory
+
+ if (key_part->null_bit)
+ {
+ if (*key++)
+ {
+ if (to->append("IS NULL", 7))
+ DBUG_RETURN(1);
+
+ DBUG_PRINT("info",
+ ("NULL type %s", to->c_ptr_quick()));
+ key_length-= key_part->store_length;
+ key+= key_part->store_length - 1;
+ continue;
+ }
+ key_length--;
+ }
+ if (to->append("= "))
+ DBUG_RETURN(1);
+ if (needs_quotes && to->append("'"))
+ DBUG_RETURN(1);
+ if (key_part->type == HA_KEYTYPE_BIT)
+ {
+ /* This is can be treated as a hex string */
+ Field_bit *field= (Field_bit *) (key_part->field);
+ char buff[64 + 2], *ptr;
+ byte *end= (byte*)(key)+length;
+
+ buff[0]= '0';
+ buff[1]= 'x';
+ for (ptr= buff + 2; key < end; key++)
+ {
+ uint tmp= (uint)(uchar) *key;
+ *ptr++= _dig_vec_upper[tmp >> 4];
+ *ptr++= _dig_vec_upper[tmp & 15];
+ }
+ if (to->append(buff, (uint)(ptr - buff)))
+ DBUG_RETURN(1);
+
+ key_length-= length;
+ continue;
+ }
+ if (key_part->key_part_flag & HA_BLOB_PART)
+ {
+ uint blob_length= uint2korr(key);
+ key+= HA_KEY_BLOB_LENGTH;
+ key_length-= HA_KEY_BLOB_LENGTH;
+
+ tmp.set_quick((char*) key, blob_length, &my_charset_bin);
+ if (append_escaped(to, &tmp))
+ DBUG_RETURN(1);
+
+ length= key_part->length;
+ }
+ else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
+ {
+ length= uint2korr(key);
+ key+= HA_KEY_BLOB_LENGTH;
+ tmp.set_quick((char*) key, length, &my_charset_bin);
+ if (append_escaped(to, &tmp))
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ char buff[MAX_FIELD_WIDTH];
+ String str(buff, sizeof(buff), field->charset()), *res;
+
+ res= field->val_str(&str, (char*) (key));
+ if (field->result_type() == STRING_RESULT)
+ {
+ if (append_escaped(to, res))
+ DBUG_RETURN(1);
+ res= field->val_str(&str, (char*) (key));
+ }
+ else if (to->append(res->ptr(), res->length()))
+ DBUG_RETURN(1);
+ }
+ if (needs_quotes && to->append("'"))
+ DBUG_RETURN(1);
+ DBUG_PRINT("info",
+ ("final value for 'to' %s", to->c_ptr_quick()));
+ key+= length;
+ key_length-= length;
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(1);
+}
+
+/*
+ Example of simple lock controls. The "share" it creates is structure we will
+ pass to each federated handler. Do you have to have one of these? Well, you
+ have pieces that are used for locking, and they are needed to function.
+*/
+
+static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
+{
+ FEDERATED_SHARE *share;
+ char query_buffer[IO_SIZE];
+ String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
+ query.length(0);
+
+ uint table_name_length, table_base_name_length;
+ char *tmp_table_name, *tmp_table_base_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;
+ DBUG_PRINT("info", ("table_name %s", table_base_name));
+ /*
+ So why does this exist? There is no way currently to init a storage engine.
+ Innodb and BDB both have modifications to the server to allow them to
+ do this. Since you will not want to do this, this is probably the next
+ best method.
+ */
+ pthread_mutex_lock(&federated_mutex);
+ table_name_length= (uint) strlen(table_name);
+ table_base_name_length= (uint) strlen(table_base_name);
+
+ if (!(share= (FEDERATED_SHARE *) hash_search(&federated_open_tables,
+ (byte*) table_name,
+ table_name_length)))
+ {
+ query.set_charset(system_charset_info);
+ query.append("SELECT * FROM `");
+
+ if (!(share= (FEDERATED_SHARE *)
+ my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &share, sizeof(*share),
+ &tmp_table_name, table_name_length + 1,
+ &select_query, query.length() +
+ strlen(table->s->comment) + 1, NullS)))
+ {
+ pthread_mutex_unlock(&federated_mutex);
+ return NULL;
+ }
+
+ if (parse_url(share, table, 0))
+ goto error;
+
+ query.append(share->table_base_name);
+ query.append("`");
+ share->use_count= 0;
+ share->table_name_length= table_name_length;
+ share->table_name= tmp_table_name;
+ share->select_query= select_query;
+ strmov(share->table_name, table_name);
+ strmov(share->select_query, query.ptr());
+ DBUG_PRINT("info",
+ ("share->select_query %s", share->select_query));
+ if (my_hash_insert(&federated_open_tables, (byte*) share))
+ goto error;
+ thr_lock_init(&share->lock);
+ pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
+ }
+ share->use_count++;
+ pthread_mutex_unlock(&federated_mutex);
+
+ return share;
+
+error:
+ pthread_mutex_unlock(&federated_mutex);
+ if (share->scheme)
+ my_free((gptr) share->scheme, MYF(0));
+ my_free((gptr) share, MYF(0));
+
+ return NULL;
+}
+
+
+/*
+ Free lock controls. We call this whenever we close a table.
+ If the table had the last reference to the share then we
+ free memory associated with it.
+*/
+
+static int free_share(FEDERATED_SHARE *share)
+{
+ pthread_mutex_lock(&federated_mutex);
+
+ if (!--share->use_count)
+ {
+ if (share->scheme)
+ my_free((gptr) share->scheme, MYF(0));
+
+ hash_delete(&federated_open_tables, (byte*) share);
+ thr_lock_delete(&share->lock);
+ VOID(pthread_mutex_destroy(&share->mutex));
+ my_free((gptr) share, MYF(0));
+ }
+ pthread_mutex_unlock(&federated_mutex);
+
+ return 0;
+}
+
+
+/*
+ If frm_error() is called then we will use this to to find out
+ what file extentions exist for the storage engine. This is
+ also used by the default rename_table and delete_table method
+ in handler.cc.
+*/
+static const char *ha_federated_exts[] = {
+ NullS
+};
+
+const char **ha_federated::bas_ext() const
+{
+ return ha_federated_exts;
+}
+
+
+/*
+ Used for opening tables. The name will be the name of the file.
+ A table is opened when it needs to be opened. For instance
+ when a request comes in for a select on the table (tables are not
+ open and closed for each request, they are cached).
+
+ Called from handler.cc by handler::ha_open(). The server opens
+ all tables by calling ha_open() which then calls the handler
+ specific open().
+*/
+
+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)))
+ DBUG_RETURN(1);
+ thr_lock_data_init(&share->lock, &lock, NULL);
+
+ /* Connect to foreign database mysql_real_connect() */
+ mysql= mysql_init(0);
+ DBUG_PRINT("info", ("hostname %s", share->hostname));
+ DBUG_PRINT("info", ("username %s", share->username));
+ DBUG_PRINT("info", ("password %s", share->password));
+ DBUG_PRINT("info", ("database %s", share->database));
+ DBUG_PRINT("info", ("port %d", share->port));
+ if (!mysql_real_connect(mysql,
+ share->hostname,
+ share->username,
+ share->password,
+ share->database,
+ share->port,
+ share->socket, 0))
+ {
+ my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_CONNECT_TO_MASTER);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Closes a table. We call the free_share() function to free any resources
+ that we have allocated in the "shared" structure.
+
+ Called from sql_base.cc, sql_select.cc, and table.cc.
+ In sql_select.cc it is only used to close up temporary tables or during
+ the process where a temporary table is converted over to being a
+ myisam table.
+ For sql_base.cc look at close_data_tables().
+*/
+
+int ha_federated::close(void)
+{
+ DBUG_ENTER("ha_federated::close");
+
+ /* free the result set */
+ if (result)
+ {
+ DBUG_PRINT("info",
+ ("mysql_free_result result at address %lx", result));
+ mysql_free_result(result);
+ result= 0;
+ }
+ /* Disconnect from mysql */
+ mysql_close(mysql);
+ DBUG_RETURN(free_share(share));
+
+}
+
+/*
+
+ Checks if a field in a record is SQL NULL.
+
+ SYNOPSIS
+ field_in_record_is_null()
+ table TABLE pointer, MySQL table object
+ field Field pointer, MySQL field object
+ record char pointer, contains record
+
+ DESCRIPTION
+ This method uses the record format information in table to track
+ the null bit in record.
+
+ RETURN VALUE
+ 1 if NULL
+ 0 otherwise
+*/
+
+inline uint field_in_record_is_null(TABLE *table,
+ Field *field,
+ char *record)
+{
+ int null_offset;
+ DBUG_ENTER("ha_federated::field_in_record_is_null");
+
+ if (!field->null_ptr)
+ DBUG_RETURN(0);
+
+ null_offset= (uint) ((char*)field->null_ptr - (char*)table->record[0]);
+
+ if (record[null_offset] & field->null_bit)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+/*
+ write_row() inserts a row. No extra() hint is given currently if a bulk load
+ is happeneding. buf() is a byte array of data. You can use the field
+ information to extract the data from the native byte array type.
+ Example of this would be:
+ for (Field **field=table->field ; *field ; field++)
+ {
+ ...
+ }
+
+ Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
+ sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
+*/
+
+int ha_federated::write_row(byte *buf)
+{
+ uint x= 0, num_fields= 0;
+ Field **field;
+ ulong current_query_id= 1;
+ ulong tmp_query_id= 1;
+ uint all_fields_have_same_query_id= 1;
+
+ char insert_buffer[IO_SIZE];
+ char values_buffer[IO_SIZE], insert_field_value_buffer[IO_SIZE];
+
+ /* The main insert query string */
+ String insert_string(insert_buffer, sizeof(insert_buffer), &my_charset_bin);
+ insert_string.length(0);
+ /* The string containing the values to be added to the insert */
+ String values_string(values_buffer, sizeof(values_buffer), &my_charset_bin);
+ values_string.length(0);
+ /* The actual value of the field, to be added to the values_string */
+ String insert_field_value_string(insert_field_value_buffer,
+ sizeof(insert_field_value_buffer),
+ &my_charset_bin);
+ insert_field_value_string.length(0);
+
+ DBUG_ENTER("ha_federated::write_row");
+ DBUG_PRINT("info", ("table charset name %s csname %s",
+ table->s->table_charset->name, table->s->table_charset->csname));
+
+ 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();
+
+ /*
+ get the current query id - the fields that we add to the insert
+ statement to send to the foreign will not be appended unless they match
+ this query id
+ */
+ current_query_id= table->in_use->query_id;
+ DBUG_PRINT("info", ("current query id %d", current_query_id));
+
+ /* start off our string */
+ insert_string.append("INSERT INTO `");
+ insert_string.append(share->table_base_name);
+ insert_string.append("`");
+ /* start both our field and field values strings */
+ insert_string.append(" (");
+ values_string.append(" VALUES (");
+
+ /*
+ Even if one field is different, all_fields_same_query_id can't remain
+ 0 if it remains 0, then that means no fields were specified in the query
+ such as in the case of INSERT INTO table VALUES (val1, val2, valN)
+ */
+ for (field= table->field; *field; field++, x++)
+ {
+ if (x > 0 && tmp_query_id != (*field)->query_id)
+ all_fields_have_same_query_id= 0;
+
+ tmp_query_id= (*field)->query_id;
+ }
+ /*
+ loop through the field pointer array, add any fields to both the values
+ list and the fields list that match the current query id
+ */
+ x=0;
+ for (field= table->field; *field; field++, x++)
+ {
+ /* if there is a query id and if it's equal to the current query id */
+ if (((*field)->query_id && (*field)->query_id == current_query_id)
+ || all_fields_have_same_query_id)
+ {
+ num_fields++;
+
+ if ((*field)->is_null())
+ {
+ DBUG_PRINT("info",
+ ("column %d current query id %d field is_null query id %d",
+ x, current_query_id, (*field)->query_id));
+ insert_field_value_string.append("NULL");
+ }
+ else
+ {
+ DBUG_PRINT("info",
+ ("column %d current query id %d field is not null query ID %d",
+ x, current_query_id, (*field)->query_id));
+ (*field)->val_str(&insert_field_value_string);
+ /* quote these fields if they require it */
+ (*field)->quote_data(&insert_field_value_string); }
+ /* append the field name */
+ insert_string.append((*field)->field_name);
+
+ /* append the value */
+ values_string.append(insert_field_value_string);
+ insert_field_value_string.length(0);
+
+ /* append commas between both fields and fieldnames */
+ insert_string.append(',');
+ values_string.append(',');
+
+ }
+ }
+
+ /*
+ chop of the trailing comma, or if there were no fields, a '('
+ So, "INSERT INTO foo (" becomes "INSERT INTO foo "
+ or, with fields, "INSERT INTO foo (field1, field2," becomes
+ "INSERT INTO foo (field1, field2"
+ */
+ insert_string.chop();
+
+ /*
+ if there were no fields, we don't want to add a closing paren
+ AND, we don't want to chop off the last char '('
+ insert will be "INSERT INTO t1 VALUES ();"
+ */
+ DBUG_PRINT("info", ("x %d num fields %d", x, num_fields));
+ if (num_fields > 0)
+ {
+ /* chops off leading commas */
+ values_string.chop();
+ insert_string.append(')');
+ }
+ /* we always want to append this, even if there aren't any fields */
+ values_string.append(')');
+
+ /* add the values */
+ insert_string.append(values_string);
+
+ DBUG_PRINT("info", ("insert query %s", insert_string.c_ptr_quick()));
+
+ if (mysql_real_query(mysql, insert_string.ptr(), insert_string.length()))
+ {
+ my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
+ }
+
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Yes, update_row() does what you expect, it updates a row. old_data will have
+ the previous row record in it, while new_data will have the newest data in
+ it.
+
+ Keep in mind that the server can do updates based on ordering if an ORDER BY
+ clause was used. Consecutive ordering is not guarenteed.
+ Currently new_data will not have an updated auto_increament record, or
+ and updated timestamp field. You can do these for federated by doing these:
+ if (table->timestamp_on_update_now)
+ update_timestamp(new_row+table->timestamp_on_update_now-1);
+ if (table->next_number_field && record == table->record[0])
+ update_auto_increment();
+
+ Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
+*/
+
+int ha_federated::update_row(const byte *old_data, byte *new_data)
+{
+ uint x= 0;
+ uint has_a_primary_key= 0;
+ uint primary_key_field_num;
+ char old_field_value_buffer[IO_SIZE], new_field_value_buffer[IO_SIZE];
+ char update_buffer[IO_SIZE], where_buffer[IO_SIZE];
+
+ /* stores the value to be replaced of the field were are updating */
+ String old_field_value(old_field_value_buffer, sizeof(old_field_value_buffer),
+ &my_charset_bin);
+ /* stores the new value of the field */
+ String new_field_value(new_field_value_buffer, sizeof(new_field_value_buffer),
+ &my_charset_bin);
+ /* stores the update query */
+ String update_string(update_buffer, sizeof(update_buffer), &my_charset_bin);
+ /* stores the WHERE clause */
+ String where_string(where_buffer, sizeof(where_buffer), &my_charset_bin);
+
+ DBUG_ENTER("ha_federated::update_row");
+ old_field_value.length(0);
+ new_field_value.length(0);
+ update_string.length(0);
+ where_string.length(0);
+
+ has_a_primary_key= (table->s->primary_key == 0 ? 1 : 0);
+ primary_key_field_num= has_a_primary_key ?
+ table->key_info[table->s->primary_key].key_part->fieldnr - 1 : -1;
+ if (has_a_primary_key)
+ DBUG_PRINT("info", ("has a primary key"));
+
+ update_string.append("UPDATE `");
+ update_string.append(share->table_base_name);
+ update_string.append("`");
+ update_string.append(" SET ");
+
+/*
+ In this loop, we want to match column names to values being inserted
+ (while building INSERT statement).
+
+ Iterate through table->field (new data) and share->old_filed (old_data)
+ using the same index to created an SQL UPDATE statement, new data is
+ used to create SET field=value and old data is used to create WHERE
+ field=oldvalue
+ */
+
+ for (Field **field= table->field; *field; field++, x++)
+ {
+ /*
+ In all of these tests for 'has_a_primary_key', what I'm trying to
+ accomplish is to only use the primary key in the WHERE clause if the
+ table has a primary key, as opposed to a table without a primary key
+ in which case we have to use all the fields to create a WHERE clause
+ using the old/current values, as well as adding a LIMIT statement
+ */
+ if (has_a_primary_key)
+ {
+ if (x == primary_key_field_num)
+ where_string.append((*field)->field_name);
+ }
+ else
+ where_string.append((*field)->field_name);
+
+ update_string.append((*field)->field_name);
+ update_string.append('=');
+
+ if ((*field)->is_null())
+ {
+ DBUG_PRINT("info", ("column %d is NULL", x ));
+ new_field_value.append("NULL");
+ }
+ else
+ {
+ /* otherwise = */
+ (*field)->val_str(&new_field_value);
+ (*field)->quote_data(&new_field_value);
+
+ if (has_a_primary_key)
+ {
+ if (x == primary_key_field_num)
+ where_string.append("=");
+ }
+ else if (!field_in_record_is_null(table, *field, (char*) old_data))
+ where_string.append("=");
+ }
+
+ if (has_a_primary_key)
+ {
+ if (x == primary_key_field_num)
+ {
+ (*field)->val_str(&old_field_value,
+ (char*) (old_data + (*field)->offset()));
+ (*field)->quote_data(&old_field_value);
+ where_string.append(old_field_value);
+ }
+ }
+ else
+ {
+ if (field_in_record_is_null(table, *field, (char*) old_data))
+ where_string.append(" IS NULL ");
+ else
+ {
+ uint o_len;
+ (*field)->val_str(&old_field_value,
+ (char*) (old_data + (*field)->offset()));
+ o_len= (*field)->pack_length();
+ DBUG_PRINT("info", ("o_len %lu", o_len));
+ (*field)->quote_data(&old_field_value);
+ where_string.append(old_field_value);
+ }
+ }
+ DBUG_PRINT("info",
+ ("column %d new value %s old value %s",
+ x, new_field_value.c_ptr_quick(), old_field_value.c_ptr_quick() ));
+ update_string.append(new_field_value);
+ new_field_value.length(0);
+
+ if (x + 1 < table->s->fields)
+ {
+ update_string.append(", ");
+ if (!has_a_primary_key)
+ where_string.append(" AND ");
+ }
+ old_field_value.length(0);
+ }
+ update_string.append(" WHERE ");
+ update_string.append(where_string);
+ if (! has_a_primary_key)
+ update_string.append(" LIMIT 1");
+
+ DBUG_PRINT("info", ("Final update query: %s",
+ update_string.c_ptr_quick()));
+ if (mysql_real_query(mysql, update_string.ptr(), update_string.length()))
+ {
+ my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
+ }
+
+
+ DBUG_RETURN(0);
+}
+
+/*
+ This will delete a row. 'buf' will contain a copy of the row to be deleted.
+ The server will call this right after the current row has been called (from
+ either a previous rnd_nexT() or index call).
+ If you keep a pointer to the last row or can access a primary key it will
+ make doing the deletion quite a bit easier.
+ Keep in mind that the server does no guarentee consecutive deletions.
+ ORDER BY clauses can be used.
+
+ Called in sql_acl.cc and sql_udf.cc to manage internal table information.
+ Called in sql_delete.cc, sql_insert.cc, and sql_select.cc. In sql_select
+ it is used for removing duplicates while in insert it is used for REPLACE
+ calls.
+*/
+
+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.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++)
+ {
+ delete_string.append((*field)->field_name);
+
+ if ((*field)->is_null())
+ {
+ delete_string.append(" IS ");
+ data_string.append("NULL");
+ }
+ else
+ {
+ delete_string.append("=");
+ (*field)->val_str(&data_string);
+ (*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(" LIMIT 1");
+ DBUG_PRINT("info",
+ ("Delete sql: %s", delete_string.c_ptr_quick()));
+ if (mysql_real_query(mysql, delete_string.ptr(), delete_string.length()))
+ {
+ my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
+ }
+
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Positions an index cursor to the index specified in the handle. Fetches the
+ row if available. If the key value is null, begin at the first key of the
+ index. This method, which is called in the case of an SQL statement having
+ a WHERE clause on a non-primary key index, simply calls index_read_idx.
+*/
+
+int ha_federated::index_read(byte *buf, const byte *key,
+ uint key_len __attribute__ ((unused)),
+ enum ha_rkey_function find_flag
+ __attribute__ ((unused)))
+{
+ DBUG_ENTER("ha_federated::index_read");
+ DBUG_RETURN(index_read_idx(buf, active_index, key, key_len, find_flag));
+}
+
+
+/*
+ Positions an index cursor to the index specified in key. Fetches the
+ row if any. This is only used to read whole keys.
+
+ This method is called via index_read in the case of a WHERE clause using
+ a regular non-primary key index, OR is called DIRECTLY when the WHERE clause
+ uses a PRIMARY KEY index.
+*/
+
+int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
+ uint key_len __attribute__ ((unused)),
+ enum ha_rkey_function find_flag
+ __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;
+
+ char sql_query_buffer[IO_SIZE];
+ String sql_query(sql_query_buffer, sizeof(sql_query_buffer), &my_charset_bin);
+ sql_query.length(0);
+
+ DBUG_ENTER("ha_federated::index_read_idx");
+
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
+
+ sql_query.append(share->select_query);
+ sql_query.append(" WHERE ");
+
+ keylen= strlen((char*) (key));
+ create_where_from_key(&index_string, &table->key_info[index], key, keylen);
+ sql_query.append(index_string);
+
+ DBUG_PRINT("info",
+ ("current key %d key value %s index_string value %s length %d",
+ index, (char*) key, index_string.c_ptr_quick(),
+ index_string.length()));
+
+ DBUG_PRINT("info",
+ ("current position %d sql_query %s", current_position,
+ sql_query.c_ptr_quick()));
+
+ if (result)
+ {
+ mysql_free_result(result);
+ result= 0;
+ }
+ if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length()))
+ {
+ my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
+ }
+ result= mysql_store_result(mysql);
+
+ if (!result)
+ {
+ table->status= STATUS_NOT_FOUND;
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
+
+ if (mysql_errno(mysql))
+ {
+ table->status= STATUS_NOT_FOUND;
+ DBUG_RETURN(mysql_errno(mysql));
+ }
+
+ DBUG_RETURN(rnd_next(buf));
+}
+
+/* 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));
+ active_index= keynr;
+ DBUG_RETURN(0);
+}
+
+/* Used to read forward through the index. */
+int ha_federated::index_next(byte *buf)
+{
+ DBUG_ENTER("ha_federated::index_next");
+ DBUG_RETURN(rnd_next(buf));
+}
+
+
+/*
+ rnd_init() is called when the system wants the storage engine to do a table
+ scan.
+
+ This is the method that gets data for the SELECT calls.
+
+ See the federated in the introduction at the top of this file to see when
+ rnd_init() is called.
+
+ Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc,
+ sql_table.cc, and sql_update.cc.
+*/
+
+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
+ properly, especially with updates containing WHERE clauses using
+ indexed columns.
+
+ When the initial query contains a WHERE clause of the query using an
+ indexed column, it's index_read_idx that selects the exact record from
+ the foreign database.
+
+ When there is NO index in the query, either due to not having a WHERE
+ clause, or the WHERE clause is using columns that are not indexed, a
+ 'full table scan' done by rnd_init, which in this situation simply means
+ a 'select * from ...' on the foreign table.
+
+ In other words, this 'scan' flag gives us the means to ensure that if
+ there is an index involved in the query, we want index_read_idx to
+ retrieve the exact record (scan flag is 0), and do not want rnd_init
+ to do a 'full table scan' and wipe out that result set.
+
+ Prior to using this flag, the problem was most apparent with updates.
+
+ An initial query like 'UPDATE tablename SET anything = whatever WHERE
+ indexedcol = someval', index_read_idx would get called, using a query
+ constructed with a WHERE clause built from the values of index ('indexcol'
+ in this case, having a value of 'someval'). mysql_store_result would
+ then get called (this would be the result set we want to use).
+
+ After this rnd_init (from sql_update.cc) would be called, it would then
+ unecessarily call "select * from table" on the foreign table, then call
+ mysql_store_result, which would wipe out the correct previous result set
+ from the previous call of index_read_idx's that had the result set
+ containing the correct record, hence update the wrong row!
+
+ */
+ scan_flag= scan;
+ if (scan)
+ {
+ DBUG_PRINT("info", ("share->select_query %s", share->select_query));
+ if (result)
+ {
+ DBUG_PRINT("info",
+ ("mysql_free_result address %lx", result));
+ mysql_free_result(result);
+ result= 0;
+ }
+
+ if (mysql_real_query
+ (mysql, share->select_query, strlen(share->select_query)))
+ {
+ my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
+ }
+ result= mysql_store_result(mysql);
+
+ if (mysql_errno(mysql))
+ DBUG_RETURN(mysql_errno(mysql));
+ }
+ DBUG_RETURN(0);
+}
+
+int ha_federated::rnd_end()
+{
+ DBUG_ENTER("ha_federated::rnd_end");
+ if (result)
+ {
+ DBUG_PRINT("info", ("mysql_free_result address %lx", result));
+ mysql_free_result(result);
+ result= 0;
+ }
+
+ mysql_free_result(result);
+ DBUG_RETURN(index_end());
+}
+
+int ha_federated::index_end(void)
+{
+ DBUG_ENTER("ha_federated::index_end");
+ active_index= MAX_KEY;
+ DBUG_RETURN(0);
+}
+
+/*
+ This is called for each row of the table scan. When you run out of records
+ you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
+ The Field structure for the table is the key to getting data into buf
+ in a manner that will allow the server to understand it.
+
+ Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc,
+ sql_table.cc, and sql_update.cc.
+*/
+
+int ha_federated::rnd_next(byte *buf)
+{
+ MYSQL_ROW row;
+ DBUG_ENTER("ha_federated::rnd_next");
+
+ if (result == 0)
+ {
+ /*
+ Return value of rnd_init is not always checked (see records.cc),
+ so we can get here _even_ if there is _no_ pre-fetched result-set!
+ TODO: fix it.
+ */
+ DBUG_RETURN(1);
+ }
+
+ /* Fetch a row, insert it back in a row format. */
+ current_position= result->data_cursor;
+ DBUG_PRINT("info", ("current position %d", current_position));
+ if (!(row= mysql_fetch_row(result)))
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ DBUG_RETURN(convert_row_to_internal_format(buf, row));
+}
+
+
+/*
+ 'position()' is called after each call to rnd_next() if the data needs to be
+ ordered. You can do something like the following to store the position:
+ my_store_ptr(ref, ref_length, current_position);
+
+ The server uses ref to store data. ref_length in the above case is the size
+ needed to store current_position. ref is just a byte array that the server
+ will maintain. If you are using offsets to mark rows, then current_position
+ should be the offset. If it is a primary key like in BDB, then it needs to
+ be a primary key.
+
+ Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
+*/
+
+void ha_federated::position(const byte *record)
+{
+ DBUG_ENTER("ha_federated::position");
+ /* my_store_ptr Add seek storage */
+ *(MYSQL_ROW_OFFSET *) ref= current_position; // ref is always aligned
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ This is like rnd_next, but you are given a position to use to determine the
+ row. The position will be of the type that you stored in ref. You can use
+ ha_get_ptr(pos,ref_length) to retrieve whatever key or position you saved
+ when position() was called.
+
+ This method is required for an ORDER BY.
+
+ Called from filesort.cc records.cc sql_insert.cc sql_select.cc sql_update.cc.
+*/
+int ha_federated::rnd_pos(byte *buf, byte *pos)
+{
+ DBUG_ENTER("ha_federated::rnd_pos");
+ /*
+ we do not need to do any of this if there has been a scan performed
+ already, or if this is an update and index_read_idx already has a result
+ set in which to build it's update query from
+ */
+ if (scan_flag)
+ {
+ statistic_increment(table->in_use->status_var.ha_read_rnd_count,
+ &LOCK_status);
+ memcpy_fixed(&current_position, pos, sizeof(MYSQL_ROW_OFFSET)); // pos
+ /* is not aligned */
+ result->current_row= 0;
+ result->data_cursor= current_position;
+ DBUG_RETURN(rnd_next(buf));
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ ::info() is used to return information to the optimizer.
+ Currently this table handler doesn't implement most of the fields
+ really needed. SHOW also makes use of this data
+ Another note, you will probably want to have the following in your
+ code:
+ if (records < 2)
+ records = 2;
+ The reason is that the server will optimize for cases of only a single
+ record. If in a table scan you don't know the number of records
+ it will probably be better to set records to two so you can return
+ as many records as you need.
+ Along with records a few more variables you may wish to set are:
+ records
+ deleted
+ data_file_length
+ index_file_length
+ delete_length
+ check_time
+ Take a look at the public variables in handler.h for more information.
+
+ Called in:
+ filesort.cc
+ ha_heap.cc
+ item_sum.cc
+ opt_sum.cc
+ sql_delete.cc
+ sql_delete.cc
+ sql_derived.cc
+ sql_select.cc
+ sql_select.cc
+ sql_select.cc
+ sql_select.cc
+ sql_select.cc
+ sql_show.cc
+ sql_show.cc
+ sql_show.cc
+ sql_show.cc
+ sql_table.cc
+ sql_union.cc
+ sql_update.cc
+
+*/
+/* FIX: later version provide better information to the optimizer */
+
+void ha_federated::info(uint flag)
+{
+ DBUG_ENTER("ha_federated::info");
+ records= 10000; // fix later
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Used to delete all rows in a table. Both for cases of truncate and
+ for cases where the optimizer realizes that all rows will be
+ removed as a result of a SQL statement.
+
+ Called from item_sum.cc by Item_func_group_concat::clear(),
+ Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
+ Called from sql_delete.cc by mysql_delete().
+ Called from sql_select.cc by JOIN::reinit().
+ Called from sql_union.cc by st_select_lex_unit::exec().
+*/
+
+int ha_federated::delete_all_rows()
+{
+ DBUG_ENTER("ha_federated::delete_all_rows");
+
+ char query_buffer[IO_SIZE];
+ String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
+ query.length(0);
+
+ query.set_charset(system_charset_info);
+ query.append("TRUNCATE `");
+ query.append(share->table_base_name);
+ query.append("`");
+
+ if (mysql_real_query(mysql, query.ptr(), query.length()))
+ {
+ my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
+ }
+
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+}
+
+
+/*
+ The idea with handler::store_lock() is the following:
+
+ The statement decided which locks we should need for the table
+ for updates/deletes/inserts we get WRITE locks, for SELECT... we get
+ read locks.
+
+ Before adding the lock into the table lock handler (see thr_lock.c)
+ mysqld calls store lock with the requested locks. Store lock can now
+ modify a write lock to a read lock (or some other lock), ignore the
+ lock (if we don't want to use MySQL table locks at all) or add locks
+ for many tables (like we do when we are using a MERGE handler).
+
+ Berkeley DB for federated changes all WRITE locks to TL_WRITE_ALLOW_WRITE
+ (which signals that we are doing WRITES, but we are still allowing other
+ reader's and writer's.
+
+ When releasing locks, store_lock() are also called. In this case one
+ usually doesn't have to do anything.
+
+ In some exceptional cases MySQL may send a request for a TL_IGNORE;
+ This means that we are requesting the same lock as last time and this
+ should also be ignored. (This may happen when someone does a flush
+ table when we have opened a part of the tables, in which case mysqld
+ closes and reopens the tables and tries to get the same locks at last
+ time). In the future we will probably try to remove this.
+
+ Called from lock.cc by get_lock_data().
+*/
+
+THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
+ {
+ /*
+ Here is where we get into the guts of a row level lock.
+ If TL_UNLOCK is set
+ If we are not doing a LOCK TABLE or DISCARD/IMPORT
+ TABLESPACE, then allow multiple writers
+ */
+
+ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
+ lock_type <= TL_WRITE) && !thd->in_lock_tables && !thd->tablespace_op)
+ lock_type= TL_WRITE_ALLOW_WRITE;
+
+ /*
+ In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
+ MySQL would use the lock TL_READ_NO_INSERT on t2, and that
+ would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
+ to t2. Convert the lock to a normal read lock to allow
+ concurrent inserts to t2.
+ */
+
+ if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables)
+ lock_type= TL_READ;
+
+ lock.type= lock_type;
+ }
+
+ *to++= &lock;
+
+ return to;
+}
+
+/*
+ create() does nothing, since we have no local setup of our own.
+ FUTURE: We should potentially connect to the foreign database and
+*/
+
+int ha_federated::create(const char *name, TABLE *table_arg,
+ HA_CREATE_INFO *create_info)
+{
+ int connection_error=0;
+ FEDERATED_SHARE tmp;
+ DBUG_ENTER("ha_federated::create");
+
+ if (parse_url(&tmp, table_arg, 1))
+ {
+ my_error(ER_CANT_CREATE_TABLE, MYF(0), name, 1);
+ goto error;
+ }
+ if ((connection_error= check_foreign_data_source(&tmp)))
+ {
+ my_error(connection_error, MYF(0), name, 1);
+ goto error;
+ }
+
+ my_free((gptr) tmp.scheme, MYF(0));
+ DBUG_RETURN(0);
+
+error:
+ DBUG_PRINT("info", ("errors, returning %d", ER_CANT_CREATE_TABLE));
+ my_free((gptr) tmp.scheme, MYF(0));
+ DBUG_RETURN(ER_CANT_CREATE_TABLE);
+
+}
+#endif /* HAVE_FEDERATED_DB */
diff --git a/sql/ha_federated.h b/sql/ha_federated.h
new file mode 100644
index 00000000000..22fc03e9eec
--- /dev/null
+++ b/sql/ha_federated.h
@@ -0,0 +1,188 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Please read ha_exmple.cc before reading this file.
+ Please keep in mind that the federated storage engine implements all methods
+ that are required to be implemented. handler.h has a full list of methods
+ that you can implement.
+*/
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#include <mysql.h>
+//#include <client.h>
+
+/*
+ FEDERATED_SHARE is a structure that will be shared amoung all open handlers
+ The example implements the minimum of what you will probably need.
+*/
+typedef struct st_federated_share {
+ char *table_name;
+ char *table_base_name;
+ /*
+ the primary select query to be used in rnd_init
+ */
+ char *select_query;
+ /*
+ remote host info, parse_url supplies
+ */
+ char *scheme;
+ char *hostname;
+ char *username;
+ char *password;
+ char *database;
+ char *table;
+ char *socket;
+ char *sport;
+ int port;
+ uint table_name_length,table_base_name_length,use_count;
+ pthread_mutex_t mutex;
+ THR_LOCK lock;
+} FEDERATED_SHARE;
+
+/*
+ Class definition for the storage engine
+*/
+class ha_federated: public handler
+{
+ THR_LOCK_DATA lock; /* MySQL lock */
+ FEDERATED_SHARE *share; /* Shared lock info */
+ MYSQL *mysql;
+ MYSQL_RES *result;
+ bool scan_flag;
+ uint ref_length;
+ uint fetch_num; // stores the fetch num
+ MYSQL_ROW_OFFSET current_position; // Current position used by ::position()
+
+private:
+ /*
+ return 0 on success
+ return errorcode otherwise
+ */
+ uint convert_row_to_internal_format(byte *buf, MYSQL_ROW row);
+ bool create_where_from_key(String *to, KEY *key_info,
+ const byte *key, uint key_length);
+
+public:
+ ha_federated(TABLE *table): handler(table),
+ mysql(0), result(0), scan_flag(0),
+ ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0)
+ {
+ }
+ ~ha_federated()
+ {
+ }
+ /* The name that will be used for display purposes */
+ const char *table_type() const { return "FEDERATED"; }
+ /*
+ The name of the index type that will be used for display
+ don't implement this method unless you really have indexes
+ */
+ const char *index_type(uint inx) { return "REMOTE"; }
+ const char **bas_ext() const;
+ /*
+ This is a list of flags that says what the storage engine
+ implements. The current table flags are documented in
+ handler.h
+ Serg: Double check these (Brian)
+ // FIX add blob support
+ */
+ ulong table_flags() const
+ {
+ return (HA_TABLE_SCAN_ON_INDEX | HA_NOT_EXACT_COUNT |
+ HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED |
+ HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS);
+ }
+ /*
+ This is a bitmap of flags that says how the storage engine
+ implements indexes. The current index flags are documented in
+ handler.h. If you do not implement indexes, just return zero
+ here.
+
+ part is the key part to check. First key part is 0
+ If all_parts it's set, MySQL want to know the flags for the combined
+ index up to and including 'part'.
+ */
+ ulong index_flags(uint inx, uint part, bool all_parts) const
+ {
+ return (HA_READ_NEXT);
+ // return (HA_READ_NEXT | HA_ONLY_WHOLE_INDEX);
+ }
+ uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
+ uint max_supported_keys() const { return MAX_KEY; }
+ uint max_supported_key_parts() const { return 1024; }
+ uint max_supported_key_length() const { return 1024; }
+ /*
+ Called in test_quick_select to determine if indexes should be used.
+ */
+ virtual double scan_time()
+ {
+ DBUG_PRINT("ha_federated::scan_time",
+ ("rows %d", records)); return (double)(records*2);
+ }
+ /*
+ The next method will never be called if you do not implement indexes.
+ */
+ virtual double read_time(uint index, uint ranges, ha_rows rows)
+ { return (double) rows / 20.0+1; }
+
+ /*
+ Everything below are methods that we implment in ha_federated.cc.
+
+ Most of these methods are not obligatory, skip them and
+ MySQL will treat them as not implemented
+ */
+ int open(const char *name, int mode, uint test_if_locked); // required
+ int close(void); // required
+
+ int write_row(byte * buf);
+ int update_row(const byte * old_data, byte * new_data);
+ int delete_row(const byte * buf);
+ int index_init(uint keynr);
+ int index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_idx(byte * buf, uint idx, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_next(byte * buf);
+ int index_end();
+ /*
+ unlike index_init(), rnd_init() can be called two times
+ without rnd_end() in between (it only makes sense if scan=1).
+ then the second call should prepare for the new table scan
+ (e.g if rnd_init allocates the cursor, second call should
+ position it to the start of the table, no need to deallocate
+ and allocate it again
+ */
+ int rnd_init(bool scan); //required
+ int rnd_end();
+ int rnd_next(byte *buf); //required
+ int rnd_pos(byte * buf, byte *pos); //required
+ void position(const byte *record); //required
+ void info(uint); //required
+
+ int delete_all_rows(void);
+ int create(const char *name, TABLE *form,
+ HA_CREATE_INFO *create_info); //required
+
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type); //required
+};
+
+bool federated_db_init(void);
+bool federated_db_end(void);
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index 4dc48c7422b..52ff776c5d6 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -26,9 +26,14 @@
/*****************************************************************************
** HEAP tables
*****************************************************************************/
+static const char *ha_heap_exts[] = {
+ NullS
+};
const char **ha_heap::bas_ext() const
-{ static const char *ext[1]= { NullS }; return ext; }
+{
+ return ha_heap_exts;
+}
/*
Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to
@@ -90,16 +95,17 @@ int ha_heap::close(void)
void ha_heap::set_keys_for_scanning(void)
{
btree_keys.clear_all();
- for (uint i= 0 ; i < table->keys ; i++)
+ for (uint i= 0 ; i < table->s->keys ; i++)
{
if (table->key_info[i].algorithm == HA_KEY_ALG_BTREE)
btree_keys.set_bit(i);
}
}
+
void ha_heap::update_key_stats()
{
- for (uint i= 0; i < table->keys; i++)
+ for (uint i= 0; i < table->s->keys; i++)
{
KEY *key=table->key_info+i;
if (!key->rec_per_key)
@@ -114,17 +120,18 @@ void ha_heap::update_key_stats()
records_changed= 0;
}
+
int ha_heap::write_row(byte * buf)
{
int res;
- statistic_increment(ha_write_count,&LOCK_status);
+ 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();
if (table->next_number_field && buf == table->record[0])
update_auto_increment();
res= heap_write(file,buf);
- if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
- file->s->records)
+ if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
+ file->s->records))
update_key_stats();
return res;
}
@@ -132,7 +139,7 @@ int ha_heap::write_row(byte * buf)
int ha_heap::update_row(const byte * old_data, byte * new_data)
{
int res;
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_update_count,&LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
res= heap_update(file,old_data,new_data);
@@ -145,9 +152,9 @@ int ha_heap::update_row(const byte * old_data, byte * new_data)
int ha_heap::delete_row(const byte * buf)
{
int res;
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
res= heap_delete(file,buf);
- if (!res && table->tmp_table == NO_TMP_TABLE &&
+ if (!res && table->s->tmp_table == NO_TMP_TABLE &&
++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)
update_key_stats();
return res;
@@ -157,7 +164,8 @@ int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
enum ha_rkey_function find_flag)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
int error = heap_rkey(file,buf,active_index, key, key_len, find_flag);
table->status = error ? STATUS_NOT_FOUND : 0;
return error;
@@ -166,7 +174,8 @@ int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
int error= heap_rkey(file, buf, active_index, key, key_len,
HA_READ_PREFIX_LAST);
table->status= error ? STATUS_NOT_FOUND : 0;
@@ -176,7 +185,8 @@ int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len)
int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
int error = heap_rkey(file, buf, index, key, key_len, find_flag);
table->status = error ? STATUS_NOT_FOUND : 0;
return error;
@@ -185,7 +195,8 @@ int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
int ha_heap::index_next(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
int error=heap_rnext(file,buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -194,7 +205,8 @@ int ha_heap::index_next(byte * buf)
int ha_heap::index_prev(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_prev_count,
+ &LOCK_status);
int error=heap_rprev(file,buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -203,7 +215,8 @@ int ha_heap::index_prev(byte * buf)
int ha_heap::index_first(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_first_count,
+ &LOCK_status);
int error=heap_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -212,7 +225,8 @@ int ha_heap::index_first(byte * buf)
int ha_heap::index_last(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_last_count,
+ &LOCK_status);
int error=heap_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -225,7 +239,8 @@ int ha_heap::rnd_init(bool scan)
int ha_heap::rnd_next(byte *buf)
{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
int error=heap_scan(file, buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -235,7 +250,8 @@ int ha_heap::rnd_pos(byte * buf, byte *pos)
{
int error;
HEAP_PTR position;
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_count,
+ &LOCK_status);
memcpy_fixed((char*) &position,pos,sizeof(HEAP_PTR));
error=heap_rrnd(file, buf, position);
table->status=error ? STATUS_NOT_FOUND: 0;
@@ -272,7 +288,7 @@ int ha_heap::extra(enum ha_extra_function operation)
int ha_heap::delete_all_rows()
{
heap_clear(file);
- if (table->tmp_table == NO_TMP_TABLE)
+ if (table->s->tmp_table == NO_TMP_TABLE)
update_key_stats();
return 0;
}
@@ -431,31 +447,32 @@ 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
- else
- return key->rec_per_key[key->key_parts-1];
+ return key->rec_per_key[key->key_parts-1];
}
int ha_heap::create(const char *name, TABLE *table_arg,
HA_CREATE_INFO *create_info)
{
- uint key, parts, mem_per_row= 0;
+ uint key, parts, mem_per_row= 0, keys= table_arg->s->keys;
uint auto_key= 0, auto_key_type= 0;
ha_rows max_rows;
HP_KEYDEF *keydef;
HA_KEYSEG *seg;
char buff[FN_REFLEN];
int error;
+ TABLE_SHARE *share= table_arg->s;
+ bool found_real_auto_increment= 0;
- for (key= parts= 0; key < table_arg->keys; key++)
+ for (key= parts= 0; key < keys; key++)
parts+= table_arg->key_info[key].key_parts;
- if (!(keydef= (HP_KEYDEF*) my_malloc(table_arg->keys * sizeof(HP_KEYDEF) +
+ if (!(keydef= (HP_KEYDEF*) my_malloc(keys * sizeof(HP_KEYDEF) +
parts * sizeof(HA_KEYSEG),
MYF(MY_WME))))
return my_errno;
- seg= my_reinterpret_cast(HA_KEYSEG*) (keydef + table_arg->keys);
- for (key= 0; key < table_arg->keys; key++)
+ seg= my_reinterpret_cast(HA_KEYSEG*) (keydef + keys);
+ for (key= 0; key < keys; key++)
{
KEY *pos= table_arg->key_info+key;
KEY_PART_INFO *key_part= pos->key_part;
@@ -478,23 +495,26 @@ int ha_heap::create(const char *name, TABLE *table_arg,
default:
DBUG_ASSERT(0); // cannot happen
}
- keydef[key].algorithm= ((pos->algorithm == HA_KEY_ALG_UNDEF) ?
- HA_KEY_ALG_HASH : pos->algorithm);
for (; key_part != key_part_end; key_part++, seg++)
{
- uint flag= key_part->key_type;
Field *field= key_part->field;
+
if (pos->algorithm == HA_KEY_ALG_BTREE)
seg->type= field->key_type();
else
{
- if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT)
+ if ((seg->type = field->key_type()) != (int) HA_KEYTYPE_TEXT &&
+ seg->type != HA_KEYTYPE_VARTEXT1 &&
+ seg->type != HA_KEYTYPE_VARTEXT2 &&
+ seg->type != HA_KEYTYPE_VARBINARY1 &&
+ seg->type != HA_KEYTYPE_VARBINARY2)
seg->type= HA_KEYTYPE_BINARY;
}
seg->start= (uint) key_part->offset;
seg->length= (uint) key_part->length;
- seg->flag = 0;
+ seg->flag= key_part->key_part_flag;
+
seg->charset= field->charset();
if (field->null_ptr)
{
@@ -508,7 +528,7 @@ int ha_heap::create(const char *name, TABLE *table_arg,
}
if (field->flags & AUTO_INCREMENT_FLAG &&
table_arg->found_next_number_field &&
- key == table_arg->next_number_index)
+ key == share->next_number_index)
{
/*
Store key number and type for found auto_increment key
@@ -519,20 +539,28 @@ int ha_heap::create(const char *name, TABLE *table_arg,
}
}
}
- mem_per_row+= MY_ALIGN(table_arg->reclength + 1, sizeof(char*));
+ mem_per_row+= MY_ALIGN(share->reclength + 1, sizeof(char*));
+ max_rows = (ha_rows) (table->in_use->variables.max_heap_table_size /
+ mem_per_row);
+ if (table_arg->found_next_number_field)
+ {
+ keydef[share->next_number_index].flag|= HA_AUTO_KEY;
+ found_real_auto_increment= share->next_number_key_offset == 0;
+ }
HP_CREATE_INFO hp_create_info;
hp_create_info.auto_key= auto_key;
hp_create_info.auto_key_type= auto_key_type;
hp_create_info.auto_increment= (create_info->auto_increment_value ?
create_info->auto_increment_value - 1 : 0);
hp_create_info.max_table_size=current_thd->variables.max_heap_table_size;
+ hp_create_info.with_auto_increment= found_real_auto_increment;
max_rows = (ha_rows) (hp_create_info.max_table_size / mem_per_row);
error= heap_create(fn_format(buff,name,"","",4+2),
- table_arg->keys,keydef, table_arg->reclength,
- (ulong) ((table_arg->max_rows < max_rows &&
- table_arg->max_rows) ?
- table_arg->max_rows : max_rows),
- (ulong) table_arg->min_rows, &hp_create_info);
+ keys, keydef, share->reclength,
+ (ulong) ((share->max_rows < max_rows &&
+ share->max_rows) ?
+ share->max_rows : max_rows),
+ (ulong) share->min_rows, &hp_create_info);
my_free((gptr) keydef, MYF(0));
if (file)
info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
@@ -547,7 +575,7 @@ void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
create_info->auto_increment_value= auto_increment_value;
}
-longlong ha_heap::get_auto_increment()
+ulonglong ha_heap::get_auto_increment()
{
ha_heap::info(HA_STATUS_AUTO);
return auto_increment_value;
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index f36e9f31c55..fb526888b01 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -32,7 +32,11 @@ class ha_heap: public handler
public:
ha_heap(TABLE *table): handler(table), file(0), records_changed(0) {}
~ha_heap() {}
- const char *table_type() const { return "HEAP"; }
+ const char *table_type() const
+ {
+ return (table->in_use->variables.sql_mode & MODE_MYSQL323) ?
+ "HEAP" : "MEMORY";
+ }
const char *index_type(uint inx)
{
return ((table->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ? "BTREE" :
@@ -63,7 +67,7 @@ public:
int write_row(byte * buf);
int update_row(const byte * old_data, byte * new_data);
int delete_row(const byte * buf);
- longlong get_auto_increment();
+ ulonglong get_auto_increment();
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
@@ -92,6 +96,12 @@ public:
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
+ int cmp_ref(const byte *ref1, const byte *ref2)
+ {
+ HEAP_PTR ptr1=*(HEAP_PTR*)ref1;
+ HEAP_PTR ptr2=*(HEAP_PTR*)ref2;
+ return ptr1 < ptr2? -1 : (ptr1 > ptr2? 1 : 0);
+ }
private:
void update_key_stats();
};
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 83c72594dfb..4217b694f06 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & Innobase Oy
+/* Copyright (C) 2000-2005 MySQL AB & Innobase Oy
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,15 +14,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* This file defines the InnoDB handler: the interface between MySQL and
-InnoDB
+/* This file defines the InnoDB handler: the interface between MySQL and InnoDB
NOTE: You can only use noninlined InnoDB functions in this file, because we
have disables the InnoDB inlining in this file. */
-/* TODO list for the InnoDB handler in 4.1:
- - Remove the flag innodb_active_trans from thd and replace it with a
- function call innodb_active_trans(thd), which looks at the InnoDB
+/* TODO list for the InnoDB handler in 5.0:
+ - Remove the flag trx->active_trans and look at the InnoDB
trx struct state field
+ - fix savepoint functions to use savepoint storage area
- Find out what kind of problems the OS X case-insensitivity causes to
table and database names; should we 'normalize' the names like we do
in Windows?
@@ -46,9 +45,58 @@ have disables the InnoDB inlining in this file. */
#include "ha_innodb.h"
-pthread_mutex_t innobase_mutex;
+pthread_mutex_t innobase_share_mutex, /* to protect innobase_open_files */
+ prepare_commit_mutex; /* to force correct commit order in
+ binlog */
bool innodb_inited= 0;
+/*-----------------------------------------------------------------*/
+/* These variables are used to implement (semi-)synchronous MySQL binlog
+replication for InnoDB tables. */
+
+pthread_cond_t innobase_repl_cond; /* Posix cond variable;
+ this variable is signaled
+ when enough binlog has been
+ sent to slave, so that a
+ waiting trx can return the
+ 'ok' message to the client
+ for a commit */
+pthread_mutex_t innobase_repl_cond_mutex; /* Posix cond variable mutex
+ that also protects the next
+ innobase_repl_... variables */
+uint innobase_repl_state; /* 1 if synchronous replication
+ is switched on and is working
+ ok; else 0 */
+uint innobase_repl_file_name_inited = 0; /* This is set to 1 when
+ innobase_repl_file_name
+ contains meaningful data */
+char* innobase_repl_file_name; /* The binlog name up to which
+ we have sent some binlog to
+ the slave */
+my_off_t innobase_repl_pos; /* The position in that file
+ up to which we have sent the
+ binlog to the slave */
+uint innobase_repl_n_wait_threads = 0; /* This tells how many
+ transactions currently are
+ waiting for the binlog to be
+ sent to the client */
+uint innobase_repl_wait_file_name_inited = 0; /* This is set to 1
+ when we know the 'smallest'
+ wait position */
+char* innobase_repl_wait_file_name; /* NULL, or the 'smallest'
+ innobase_repl_file_name that
+ a transaction is waiting for */
+my_off_t innobase_repl_wait_pos; /* The smallest position in
+ that file that a trx is
+ waiting for: the trx can
+ proceed and send an 'ok' to
+ the client when MySQL has sent
+ the binlog up to this position
+ to the slave */
+/*-----------------------------------------------------------------*/
+
+
+
/* Store MySQL definition of 'byte': in Linux it is char while InnoDB
uses unsigned char; the header univ.i which we include next defines
'byte' as a macro which expands to 'unsigned char' */
@@ -80,6 +128,7 @@ extern "C" {
#include "../innobase/include/fsp0fsp.h"
#include "../innobase/include/sync0sync.h"
#include "../innobase/include/fil0fil.h"
+#include "../innobase/include/trx0xa.h"
}
#define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */
@@ -87,6 +136,7 @@ extern "C" {
uint innobase_init_flags = 0;
ulong innobase_cache_size = 0;
+ulong innobase_large_page_size = 0;
/* The default values for the following, type long, start-up parameters
are declared in mysqld.cc: */
@@ -95,7 +145,7 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group,
innobase_log_file_size, innobase_log_buffer_size,
innobase_buffer_pool_awe_mem_mb,
innobase_buffer_pool_size, innobase_additional_mem_pool_size,
- innobase_file_io_threads, innobase_lock_wait_timeout,
+ innobase_file_io_threads, innobase_lock_wait_timeout,
innobase_thread_concurrency, innobase_force_recovery,
innobase_open_files;
@@ -114,12 +164,12 @@ char* innobase_unix_file_flush_method = NULL;
values */
uint innobase_flush_log_at_trx_commit = 1;
+ulong innobase_fast_shutdown = 1;
my_bool innobase_log_archive = FALSE;/* unused */
+my_bool innobase_use_doublewrite = TRUE;
+my_bool innobase_use_checksums = TRUE;
+my_bool innobase_use_large_pages = FALSE;
my_bool innobase_use_native_aio = FALSE;
-my_bool innobase_fast_shutdown = TRUE;
-my_bool innobase_very_fast_shutdown = FALSE; /* this can be set to
- 1 just prior calling
- innobase_end() */
my_bool innobase_file_per_table = FALSE;
my_bool innobase_locks_unsafe_for_binlog = FALSE;
my_bool innobase_create_status_file = FALSE;
@@ -136,8 +186,6 @@ ulong innobase_active_counter = 0;
char* innobase_home = NULL;
-char innodb_dummy_stmt_trx_handle = 'D';
-
static HASH innobase_open_tables;
#ifdef __NETWARE__ /* some special cleanup for NetWare */
@@ -148,6 +196,125 @@ static mysql_byte* innobase_get_key(INNOBASE_SHARE *share,uint *length,
my_bool not_used __attribute__((unused)));
static INNOBASE_SHARE *get_share(const char *table_name);
static void free_share(INNOBASE_SHARE *share);
+static int innobase_close_connection(THD* thd);
+static int innobase_commit(THD* thd, bool all);
+static int innobase_rollback(THD* thd, bool all);
+static int innobase_rollback_to_savepoint(THD* thd, void *savepoint);
+static int innobase_savepoint(THD* thd, void *savepoint);
+static int innobase_release_savepoint(THD* thd, void *savepoint);
+
+static handlerton innobase_hton = {
+ "InnoDB",
+ 0, /* slot */
+ sizeof(trx_named_savept_t), /* savepoint size. TODO: use it */
+ innobase_close_connection,
+ innobase_savepoint,
+ innobase_rollback_to_savepoint,
+ innobase_release_savepoint,
+ innobase_commit, /* commit */
+ innobase_rollback, /* rollback */
+ innobase_xa_prepare, /* prepare */
+ innobase_xa_recover, /* recover */
+ innobase_commit_by_xid, /* commit_by_xid */
+ innobase_rollback_by_xid /* rollback_by_xid */
+};
+
+/*********************************************************************
+Commits a transaction in an InnoDB database. */
+
+void
+innobase_commit_low(
+/*================*/
+ trx_t* trx); /* in: transaction handle */
+
+struct show_var_st innodb_status_variables[]= {
+ {"buffer_pool_pages_data",
+ (char*) &export_vars.innodb_buffer_pool_pages_data, SHOW_LONG},
+ {"buffer_pool_pages_dirty",
+ (char*) &export_vars.innodb_buffer_pool_pages_dirty, SHOW_LONG},
+ {"buffer_pool_pages_flushed",
+ (char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG},
+ {"buffer_pool_pages_free",
+ (char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG},
+ {"buffer_pool_pages_latched",
+ (char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
+ {"buffer_pool_pages_misc",
+ (char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG},
+ {"buffer_pool_pages_total",
+ (char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG},
+ {"buffer_pool_read_ahead_rnd",
+ (char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG},
+ {"buffer_pool_read_ahead_seq",
+ (char*) &export_vars.innodb_buffer_pool_read_ahead_seq, SHOW_LONG},
+ {"buffer_pool_read_requests",
+ (char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG},
+ {"buffer_pool_reads",
+ (char*) &export_vars.innodb_buffer_pool_reads, SHOW_LONG},
+ {"buffer_pool_wait_free",
+ (char*) &export_vars.innodb_buffer_pool_wait_free, SHOW_LONG},
+ {"buffer_pool_write_requests",
+ (char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
+ {"data_fsyncs",
+ (char*) &export_vars.innodb_data_fsyncs, SHOW_LONG},
+ {"data_pending_fsyncs",
+ (char*) &export_vars.innodb_data_pending_fsyncs, SHOW_LONG},
+ {"data_pending_reads",
+ (char*) &export_vars.innodb_data_pending_reads, SHOW_LONG},
+ {"data_pending_writes",
+ (char*) &export_vars.innodb_data_pending_writes, SHOW_LONG},
+ {"data_read",
+ (char*) &export_vars.innodb_data_read, SHOW_LONG},
+ {"data_reads",
+ (char*) &export_vars.innodb_data_reads, SHOW_LONG},
+ {"data_writes",
+ (char*) &export_vars.innodb_data_writes, SHOW_LONG},
+ {"data_written",
+ (char*) &export_vars.innodb_data_written, SHOW_LONG},
+ {"dblwr_pages_written",
+ (char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
+ {"dblwr_writes",
+ (char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
+ {"log_waits",
+ (char*) &export_vars.innodb_log_waits, SHOW_LONG},
+ {"log_write_requests",
+ (char*) &export_vars.innodb_log_write_requests, SHOW_LONG},
+ {"log_writes",
+ (char*) &export_vars.innodb_log_writes, SHOW_LONG},
+ {"os_log_fsyncs",
+ (char*) &export_vars.innodb_os_log_fsyncs, SHOW_LONG},
+ {"os_log_pending_fsyncs",
+ (char*) &export_vars.innodb_os_log_pending_fsyncs, SHOW_LONG},
+ {"os_log_pending_writes",
+ (char*) &export_vars.innodb_os_log_pending_writes, SHOW_LONG},
+ {"os_log_written",
+ (char*) &export_vars.innodb_os_log_written, SHOW_LONG},
+ {"page_size",
+ (char*) &export_vars.innodb_page_size, SHOW_LONG},
+ {"pages_created",
+ (char*) &export_vars.innodb_pages_created, SHOW_LONG},
+ {"pages_read",
+ (char*) &export_vars.innodb_pages_read, SHOW_LONG},
+ {"pages_written",
+ (char*) &export_vars.innodb_pages_written, SHOW_LONG},
+ {"row_lock_waits",
+ (char*) &export_vars.innodb_row_lock_waits, SHOW_LONG},
+ {"row_lock_current_waits",
+ (char*) &export_vars.innodb_row_lock_current_waits, SHOW_LONG},
+ {"row_lock_time",
+ (char*) &export_vars.innodb_row_lock_time, SHOW_LONGLONG},
+ {"row_lock_time_max",
+ (char*) &export_vars.innodb_row_lock_time_max, SHOW_LONG},
+ {"row_lock_time_avg",
+ (char*) &export_vars.innodb_row_lock_time_avg, SHOW_LONG},
+ {"rows_deleted",
+ (char*) &export_vars.innodb_rows_deleted, SHOW_LONG},
+ {"rows_inserted",
+ (char*) &export_vars.innodb_rows_inserted, SHOW_LONG},
+ {"rows_read",
+ (char*) &export_vars.innodb_rows_read, SHOW_LONG},
+ {"rows_updated",
+ (char*) &export_vars.innodb_rows_updated, SHOW_LONG},
+ {NullS, NullS, SHOW_LONG}};
/* General functions */
@@ -215,9 +382,20 @@ documentation, see handler.cc. */
void
innobase_release_temporary_latches(
/*===============================*/
- void* innobase_tid)
+ THD *thd)
{
- innobase_release_stat_resources((trx_t*)innobase_tid);
+ trx_t* trx;
+
+ if (!innodb_inited) {
+
+ return;
+ }
+
+ trx = (trx_t*) thd->ha_data[innobase_hton.slot];
+
+ if (trx) {
+ innobase_release_stat_resources(trx);
+ }
}
/************************************************************************
@@ -433,6 +611,34 @@ innobase_mysql_print_thd(
}
/**********************************************************************
+Get the variable length bounds of the given character set.
+
+NOTE that the exact prototype of this function has to be in
+/innobase/data/data0type.ic! */
+extern "C"
+void
+innobase_get_cset_width(
+/*====================*/
+ ulint cset, /* in: MySQL charset-collation code */
+ ulint* mbminlen, /* out: minimum length of a char (in bytes) */
+ ulint* mbmaxlen) /* out: maximum length of a char (in bytes) */
+{
+ CHARSET_INFO* cs;
+ ut_ad(cset < 256);
+ ut_ad(mbminlen);
+ ut_ad(mbmaxlen);
+
+ cs = all_charsets[cset];
+ if (cs) {
+ *mbminlen = cs->mbminlen;
+ *mbmaxlen = cs->mbmaxlen;
+ } else {
+ ut_a(cset == 0);
+ *mbminlen = *mbmaxlen = 0;
+ }
+}
+
+/**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively.
NOTE that the exact prototype of this function has to be in
@@ -498,9 +704,10 @@ innobase_mysql_tmpfile(void)
if (fd2 < 0) {
DBUG_PRINT("error",("Got error %d on dup",fd2));
my_errno=errno;
- my_error(EE_OUT_OF_FILERESOURCES,
- MYF(ME_BELL+ME_WAITTANG), filename, my_errno);
- }
+ my_error(EE_OUT_OF_FILERESOURCES,
+ MYF(ME_BELL+ME_WAITTANG),
+ filename, my_errno);
+ }
my_close(fd, MYF(MY_WME));
}
return(fd2);
@@ -521,25 +728,21 @@ check_trx_exists(
ut_ad(thd == current_thd);
- trx = (trx_t*) thd->transaction.all.innobase_tid;
+ trx = (trx_t*) thd->ha_data[innobase_hton.slot];
if (trx == NULL) {
DBUG_ASSERT(thd != NULL);
trx = trx_allocate_for_mysql();
trx->mysql_thd = thd;
- trx->mysql_query_str = &((*thd).query);
-
- thd->transaction.all.innobase_tid = trx;
+ trx->mysql_query_str = &(thd->query);
+ trx->active_trans = 0;
- /* The execution of a single SQL statement is denoted by
- a 'transaction' handle which is a dummy pointer: InnoDB
- remembers internally where the latest SQL statement
- started, and if error handling requires rolling back the
- latest statement, InnoDB does a rollback to a savepoint. */
+ /* Update the info whether we should skip XA steps that eat
+ CPU time */
+ trx->support_xa = (ibool)(thd->variables.innodb_support_xa);
- thd->transaction.stmt.innobase_tid =
- (void*)&innodb_dummy_stmt_trx_handle;
+ thd->ha_data[innobase_hton.slot] = trx;
} else {
if (trx->magic_n != TRX_MAGIC_N) {
mem_analyze_corruption((byte*)trx);
@@ -576,7 +779,7 @@ ha_innobase::update_thd(
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
trx_t* trx;
-
+
trx = check_trx_exists(thd);
if (prebuilt->trx != trx) {
@@ -589,6 +792,45 @@ ha_innobase::update_thd(
return(0);
}
+/*************************************************************************
+Registers that InnoDB takes part in an SQL statement, so that MySQL knows to
+roll back the statement if the statement results in an error. This MUST be
+called for every SQL statement that may be rolled back by MySQL. Calling this
+several times to register the same statement is allowed, too. */
+inline
+void
+innobase_register_stmt(
+/*===================*/
+ THD* thd) /* in: MySQL thd (connection) object */
+{
+ /* Register the statement */
+ trans_register_ha(thd, FALSE, &innobase_hton);
+}
+
+/*************************************************************************
+Registers an InnoDB transaction in MySQL, so that the MySQL XA code knows
+to call the InnoDB prepare and commit, or rollback for the transaction. This
+MUST be called for every transaction for which the user may call commit or
+rollback. Calling this several times to register the same transaction is
+allowed, too.
+This function also registers the current SQL statement. */
+inline
+void
+innobase_register_trx_and_stmt(
+/*===========================*/
+ THD* thd) /* in: MySQL thd (connection) object */
+{
+ /* NOTE that actually innobase_register_stmt() registers also
+ the transaction in the AUTOCOMMIT=1 mode. */
+
+ innobase_register_stmt(thd);
+
+ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
+
+ /* No autocommit mode, register for a transaction */
+ trans_register_ha(thd, TRUE, &innobase_hton);
+ }
+}
/* BACKGROUND INFO: HOW THE MYSQL QUERY CACHE WORKS WITH INNODB
------------------------------------------------------------
@@ -643,7 +885,14 @@ returns TRUE for all tables in the query.
If thd is not in the autocommit state, this function also starts a new
transaction for thd if there is no active trx yet, and assigns a consistent
-read view to it if there is no read view yet. */
+read view to it if there is no read view yet.
+
+Why a deadlock of threads is not possible: the query cache calls this function
+at the start of a SELECT processing. Then the calling thread cannot be
+holding any InnoDB semaphores. The calling thread is holding the
+query cache mutex, and this function will reserver the InnoDB kernel mutex.
+Thus, the 'rank' in sync0sync.h of the MySQL query cache mutex is above
+the InnoDB kernel mutex. */
my_bool
innobase_query_caching_of_table_permitted(
@@ -658,8 +907,9 @@ innobase_query_caching_of_table_permitted(
char* full_name, /* in: concatenation of database name,
the null character '\0', and the table
name */
- uint full_name_len) /* in: length of the full name, i.e.
+ uint full_name_len, /* in: length of the full name, i.e.
len(dbname) + len(tablename) + 1 */
+ ulonglong *unused) /* unused for this engine */
{
ibool is_autocommit;
trx_t* trx;
@@ -674,10 +924,12 @@ innobase_query_caching_of_table_permitted(
return((my_bool)FALSE);
}
- trx = (trx_t*) thd->transaction.all.innobase_tid;
-
- if (trx == NULL) {
- trx = check_trx_exists(thd);
+ trx = check_trx_exists(thd);
+ if (trx->has_search_latch) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Error: the calling thread is holding the adaptive search\n"
+"InnoDB: latch though calling innobase_query_caching_of_table_permitted\n");
}
innobase_release_stat_resources(trx);
@@ -725,7 +977,11 @@ innobase_query_caching_of_table_permitted(
/* The call of row_search_.. will start a new transaction if it is
not yet started */
- thd->transaction.all.innodb_active_trans = 1;
+ if (trx->active_trans == 0) {
+
+ innobase_register_trx_and_stmt(thd);
+ trx->active_trans = 1;
+ }
if (row_search_check_if_query_cache_permitted(trx, norm_name)) {
@@ -755,6 +1011,10 @@ innobase_invalidate_query_cache(
ulint full_name_len) /* in: full name length where also the null
chars count */
{
+ /* Note that the sync0sync.h rank of the query cache mutex is just
+ above the InnoDB kernel mutex. The caller of this function must not
+ have latches of a lower rank. */
+
/* Argument TRUE below means we are using transactions */
#ifdef HAVE_QUERY_CACHE
query_cache.invalidate((THD*)(trx->mysql_thd),
@@ -833,7 +1093,12 @@ ha_innobase::init_table_handle_for_HANDLER(void)
/* Set the MySQL flag to mark that there is an active transaction */
- current_thd->transaction.all.innodb_active_trans = 1;
+ if (prebuilt->trx->active_trans == 0) {
+
+ innobase_register_trx_and_stmt(current_thd);
+
+ prebuilt->trx->active_trans = 1;
+ }
/* We did the necessary inits in this function, no need to repeat them
in row_search_for_mysql */
@@ -856,12 +1121,14 @@ ha_innobase::init_table_handle_for_HANDLER(void)
prebuilt->read_just_key = FALSE;
prebuilt->used_in_HANDLER = TRUE;
+
+ prebuilt->keep_other_fields_on_keyread = FALSE;
}
/*************************************************************************
Opens an InnoDB database. */
-bool
+handlerton*
innobase_init(void)
/*===============*/
/* out: TRUE if error */
@@ -873,6 +1140,8 @@ innobase_init(void)
DBUG_ENTER("innobase_init");
+ ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
+
os_innodb_umask = (ulint)my_umask;
/* First calculate the default path for innodb_data_home_dir etc.,
@@ -936,7 +1205,9 @@ innobase_init(void)
if (ret == FALSE) {
sql_print_error(
"InnoDB: syntax error in innodb_data_file_path");
- DBUG_RETURN(TRUE);
+ my_free(internal_innobase_data_file_path,
+ MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_RETURN(0);
}
/* -------------- Log files ---------------------------*/
@@ -966,7 +1237,9 @@ innobase_init(void)
"InnoDB: syntax error in innodb_log_group_home_dir\n"
"InnoDB: or a wrong number of mirrored log groups\n");
- DBUG_RETURN(TRUE);
+ my_free(internal_innobase_data_file_path,
+ MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_RETURN(0);
}
/* --------------------------------------------------*/
@@ -1008,11 +1281,14 @@ innobase_init(void)
srv_n_file_io_threads = (ulint) innobase_file_io_threads;
srv_lock_wait_timeout = (ulint) innobase_lock_wait_timeout;
- srv_thread_concurrency = (ulint) innobase_thread_concurrency;
srv_force_recovery = (ulint) innobase_force_recovery;
- srv_fast_shutdown = (ibool) innobase_fast_shutdown;
+ srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
+ srv_use_checksums = (ibool) innobase_use_checksums;
+ os_use_large_pages = (ibool) innobase_use_large_pages;
+ os_large_page_size = (ulint) innobase_large_page_size;
+
srv_file_per_table = (ibool) innobase_file_per_table;
srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog;
@@ -1021,7 +1297,7 @@ innobase_init(void)
srv_print_verbose_log = mysqld_embedded ? 0 : 1;
- /* Store the default charset-collation number of this MySQL
+ /* Store the default charset-collation number of this MySQL
installation */
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
@@ -1049,13 +1325,15 @@ innobase_init(void)
err = innobase_start_or_create_for_mysql();
if (err != DB_SUCCESS) {
-
- DBUG_RETURN(1);
+ my_free(internal_innobase_data_file_path,
+ MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_RETURN(0);
}
(void) hash_init(&innobase_open_tables,system_charset_info, 32, 0, 0,
(hash_get_key) innobase_get_key, 0, 0);
- pthread_mutex_init(&innobase_mutex, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
innodb_inited= 1;
/* If this is a replication slave and we needed to do a crash recovery,
@@ -1073,7 +1351,7 @@ innobase_init(void)
glob_mi.pos = trx_sys_mysql_master_log_pos;
}
*/
- DBUG_RETURN(0);
+ DBUG_RETURN(&innobase_hton);
}
/***********************************************************************
@@ -1093,23 +1371,18 @@ innobase_end(void)
set_panic_flag_for_netware();
}
#endif
- if (innodb_inited)
- {
- if (innobase_very_fast_shutdown) {
- srv_very_fast_shutdown = TRUE;
- fprintf(stderr,
-"InnoDB: MySQL has requested a very fast shutdown without flushing\n"
-"InnoDB: the InnoDB buffer pool to data files. At the next mysqld startup\n"
-"InnoDB: InnoDB will do a crash recovery!\n");
-
- }
+ if (innodb_inited) {
- innodb_inited= 0;
- if (innobase_shutdown_for_mysql() != DB_SUCCESS)
- err= 1;
- hash_free(&innobase_open_tables);
- my_free(internal_innobase_data_file_path,MYF(MY_ALLOW_ZERO_PTR));
- pthread_mutex_destroy(&innobase_mutex);
+ srv_fast_shutdown = (ulint) innobase_fast_shutdown;
+ innodb_inited = 0;
+ if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
+ err = 1;
+ }
+ hash_free(&innobase_open_tables);
+ my_free(internal_innobase_data_file_path,
+ MYF(MY_ALLOW_ZERO_PTR));
+ pthread_mutex_destroy(&innobase_share_mutex);
+ pthread_mutex_destroy(&prepare_commit_mutex);
}
DBUG_RETURN(err);
@@ -1147,13 +1420,15 @@ innobase_commit_low(
}
#ifdef HAVE_REPLICATION
- if (current_thd->slave_thread) {
+ THD *thd=current_thd;
+
+ if (thd && thd->slave_thread) {
/* Update the replication position info inside InnoDB */
trx->mysql_master_log_file_name
= active_mi->rli.group_master_log_name;
- trx->mysql_master_log_pos= ((ib_longlong)
- active_mi->rli.future_group_master_log_pos);
+ trx->mysql_master_log_pos = ((ib_longlong)
+ active_mi->rli.future_group_master_log_pos);
}
#endif /* HAVE_REPLICATION */
@@ -1197,7 +1472,12 @@ innobase_start_trx_and_assign_read_view(
/* Set the MySQL flag to mark that there is an active transaction */
- current_thd->transaction.all.innodb_active_trans = 1;
+ if (trx->active_trans == 0) {
+
+ innobase_register_trx_and_stmt(current_thd);
+
+ trx->active_trans = 1;
+ }
DBUG_RETURN(0);
}
@@ -1206,60 +1486,74 @@ innobase_start_trx_and_assign_read_view(
Commits a transaction in an InnoDB database or marks an SQL statement
ended. */
-int
+static int
innobase_commit(
/*============*/
/* out: 0 */
THD* thd, /* in: MySQL thread handle of the user for whom
the transaction should be committed */
- void* trx_handle)/* in: InnoDB trx handle or
- &innodb_dummy_stmt_trx_handle: the latter means
- that the current SQL statement ended */
+ bool all) /* in: TRUE - commit transaction
+ FALSE - the current SQL statement ended */
{
- trx_t* trx;
+ trx_t* trx;
DBUG_ENTER("innobase_commit");
DBUG_PRINT("trans", ("ending transaction"));
trx = check_trx_exists(thd);
+ /* Update the info whether we should skip XA steps that eat CPU time */
+ trx->support_xa = (ibool)(thd->variables.innodb_support_xa);
+
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex, we have to release the search system latch
first to obey the latching order. */
innobase_release_stat_resources(trx);
- /* The flag thd->transaction.all.innodb_active_trans is set to 1 in
+ /* The flag trx->active_trans is set to 1 in
1. ::external_lock(),
2. ::start_stmt(),
3. innobase_query_caching_of_table_permitted(),
4. innobase_savepoint(),
5. ::init_table_handle_for_HANDLER(),
- 6. innobase_start_trx_and_assign_read_view()
+ 6. innobase_start_trx_and_assign_read_view(),
+ 7. ::transactional_table_lock()
and it is only set to 0 in a commit or a rollback. If it is 0 we know
there cannot be resources to be freed and we could return immediately.
For the time being, we play safe and do the cleanup though there should
be nothing to clean up. */
- if (thd->transaction.all.innodb_active_trans == 0
+ if (trx->active_trans == 0
&& trx->conc_state != TRX_NOT_STARTED) {
fprintf(stderr,
-"InnoDB: Error: thd->transaction.all.innodb_active_trans == 0\n"
+"InnoDB: Error: trx->active_trans == 0\n"
"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n");
}
- if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle
+ if (all
|| (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
- /* We were instructed to commit the whole transaction, or
+ /* We were instructed to commit the whole transaction, or
this is an SQL statement end and autocommit is on */
+ /* We need current binlog position for ibbackup to work.
+ Note, the position is current because of prepare_commit_mutex */
+ trx->mysql_log_file_name = mysql_bin_log.get_log_fname();
+ trx->mysql_log_offset =
+ (ib_longlong)mysql_bin_log.get_log_file()->pos_in_file;
+
innobase_commit_low(trx);
- thd->transaction.all.innodb_active_trans = 0;
+ if (trx->active_trans == 2) {
+
+ pthread_mutex_unlock(&prepare_commit_mutex);
+ }
+ trx->active_trans = 0;
+
} else {
/* We just mark the SQL statement ended and do not do a
transaction commit */
@@ -1285,6 +1579,10 @@ innobase_commit(
DBUG_RETURN(0);
}
+/* TODO: put the
+MySQL-4.1 functionality back to 5.0. This is needed to get InnoDB Hot Backup
+to work. */
+
/*********************************************************************
This is called when MySQL writes the binlog entry for the current
transaction. Writes to the InnoDB tablespace info which tells where the
@@ -1310,18 +1608,70 @@ innobase_report_binlog_offset_and_commit(
ut_a(trx != NULL);
- trx->mysql_log_file_name = log_file_name;
+ trx->mysql_log_file_name = log_file_name;
trx->mysql_log_offset = (ib_longlong)end_offset;
-
+
+#ifdef HAVE_REPLICATION
+ if (thd->variables.sync_replication) {
+ /* Let us store the binlog file name and the position, so that
+ we know how long to wait for the binlog to the replicated to
+ the slave in synchronous replication. */
+
+ if (trx->repl_wait_binlog_name == NULL) {
+
+ trx->repl_wait_binlog_name =
+ (char*)mem_alloc_noninline(FN_REFLEN + 100);
+ }
+
+ ut_a(strlen(log_file_name) < FN_REFLEN + 100);
+
+ strcpy(trx->repl_wait_binlog_name, log_file_name);
+
+ trx->repl_wait_binlog_pos = (ib_longlong)end_offset;
+ }
+#endif /* HAVE_REPLICATION */
trx->flush_log_later = TRUE;
- innobase_commit(thd, trx_handle);
+ innobase_commit(thd, TRUE);
trx->flush_log_later = FALSE;
return(0);
}
+#if 0
+/***********************************************************************
+This function stores the binlog offset and flushes logs. */
+
+void
+innobase_store_binlog_offset_and_flush_log(
+/*=======================================*/
+ char *binlog_name, /* in: binlog name */
+ longlong offset) /* in: binlog offset */
+{
+ mtr_t mtr;
+
+ assert(binlog_name != NULL);
+
+ /* Start a mini-transaction */
+ mtr_start_noninline(&mtr);
+
+ /* Update the latest MySQL binlog name and offset info
+ in trx sys header */
+
+ trx_sys_update_mysql_binlog_offset(
+ binlog_name,
+ offset,
+ TRX_SYS_MYSQL_LOG_INFO, &mtr);
+
+ /* Commits the mini-transaction */
+ mtr_commit(&mtr);
+
+ /* Syncronous flush of the log buffer to disk */
+ log_buffer_flush_to_disk();
+}
+#endif
+
/*********************************************************************
This is called after MySQL has written the binlog entry for the current
transaction. Flushes the InnoDB log files to disk if required. */
@@ -1330,36 +1680,244 @@ int
innobase_commit_complete(
/*=====================*/
/* out: 0 */
- void* trx_handle) /* in: InnoDB trx handle */
+ THD* thd) /* in: user thread */
{
trx_t* trx;
- if (srv_flush_log_at_trx_commit == 0) {
+ trx = (trx_t*) thd->ha_data[innobase_hton.slot];
- return(0);
- }
+ if (trx && trx->active_trans) {
- trx = (trx_t*)trx_handle;
+ trx->active_trans = 0;
- ut_a(trx != NULL);
+ if (srv_flush_log_at_trx_commit == 0) {
+
+ return(0);
+ }
+
+ trx_commit_complete_for_mysql(trx);
+ }
+
+#ifdef HAVE_REPLICATION
+ if (thd->variables.sync_replication
+ && trx->repl_wait_binlog_name
+ && innobase_repl_state != 0) {
+
+ struct timespec abstime;
+ int cmp;
+ int ret;
+
+ /* In synchronous replication, let us wait until the MySQL
+ replication has sent the relevant binlog segment to the
+ replication slave. */
+
+ pthread_mutex_lock(&innobase_repl_cond_mutex);
+try_again:
+ if (innobase_repl_state == 0) {
+
+ pthread_mutex_unlock(&innobase_repl_cond_mutex);
+
+ return(0);
+ }
+
+ cmp = strcmp(innobase_repl_file_name,
+ trx->repl_wait_binlog_name);
+ if (cmp > 0
+ || (cmp == 0 && innobase_repl_pos
+ >= (my_off_t)trx->repl_wait_binlog_pos)) {
+ /* We have already sent the relevant binlog to the
+ slave: no need to wait here */
+
+ pthread_mutex_unlock(&innobase_repl_cond_mutex);
+
+/* printf("Binlog now sent\n"); */
- trx_commit_complete_for_mysql(trx);
+ return(0);
+ }
+ /* Let us update the info about the minimum binlog position
+ of waiting threads in the innobase_repl_... variables */
+
+ if (innobase_repl_wait_file_name_inited != 0) {
+ cmp = strcmp(trx->repl_wait_binlog_name,
+ innobase_repl_wait_file_name);
+ if (cmp < 0
+ || (cmp == 0 && (my_off_t)trx->repl_wait_binlog_pos
+ <= innobase_repl_wait_pos)) {
+ /* This thd has an even lower position, let
+ us update the minimum info */
+
+ strcpy(innobase_repl_wait_file_name,
+ trx->repl_wait_binlog_name);
+
+ innobase_repl_wait_pos =
+ trx->repl_wait_binlog_pos;
+ }
+ } else {
+ strcpy(innobase_repl_wait_file_name,
+ trx->repl_wait_binlog_name);
+
+ innobase_repl_wait_pos = trx->repl_wait_binlog_pos;
+
+ innobase_repl_wait_file_name_inited = 1;
+ }
+ set_timespec(abstime, thd->variables.sync_replication_timeout);
+
+ /* Let us suspend this thread to wait on the condition;
+ when replication has progressed far enough, we will release
+ these waiting threads. The following call
+ pthread_cond_timedwait also atomically unlocks
+ innobase_repl_cond_mutex. */
+
+ innobase_repl_n_wait_threads++;
+
+/* printf("Waiting for binlog to be sent\n"); */
+
+ ret = pthread_cond_timedwait(&innobase_repl_cond,
+ &innobase_repl_cond_mutex, &abstime);
+ innobase_repl_n_wait_threads--;
+
+ if (ret != 0) {
+ ut_print_timestamp(stderr);
+
+ fprintf(stderr,
+" InnoDB: Error: MySQL synchronous replication\n"
+"InnoDB: was not able to send the binlog to the slave within the\n"
+"InnoDB: timeout %lu. We assume that the slave has become inaccessible,\n"
+"InnoDB: and switch off synchronous replication until the communication.\n"
+"InnoDB: to the slave works again.\n",
+ thd->variables.sync_replication_timeout);
+ fprintf(stderr,
+"InnoDB: MySQL synchronous replication has sent binlog\n"
+"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name,
+ (ulong)innobase_repl_pos);
+ fprintf(stderr,
+"InnoDB: This transaction needs it to be sent up to\n"
+"InnoDB: file %s, position %lu\n", trx->repl_wait_binlog_name,
+ (uint)trx->repl_wait_binlog_pos);
+
+ innobase_repl_state = 0;
+
+ pthread_mutex_unlock(&innobase_repl_cond_mutex);
+
+ return(0);
+ }
+
+ goto try_again;
+ }
+#endif HAVE_REPLICATION
return(0);
}
+#ifdef HAVE_REPLICATION
/*********************************************************************
-Rolls back a transaction or the latest SQL statement. */
+In synchronous replication, reports to InnoDB up to which binlog position
+we have sent the binlog to the slave. Note that replication is synchronous
+for one slave only. For other slaves, we do nothing in this function. This
+function is used in a replication master. */
int
+innobase_repl_report_sent_binlog(
+/*=============================*/
+ /* out: 0 */
+ THD* thd, /* in: thread doing the binlog communication to
+ the slave */
+ char* log_file_name, /* in: binlog file name */
+ my_off_t end_offset) /* in: the offset in the binlog file up to
+ which we sent the contents to the slave */
+{
+ int cmp;
+ ibool can_release_threads = 0;
+
+ /* If synchronous replication is not switched on, or this thd is
+ sending binlog to a slave where we do not need synchronous replication,
+ then return immediately */
+
+ if (thd->server_id != thd->variables.sync_replication_slave_id) {
+
+ /* Do nothing */
+
+ return(0);
+ }
+
+ pthread_mutex_lock(&innobase_repl_cond_mutex);
+
+ if (innobase_repl_state == 0) {
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Switching MySQL synchronous replication on again at\n"
+"InnoDB: binlog file %s, position %lu\n", log_file_name, (ulong)end_offset);
+
+ innobase_repl_state = 1;
+ }
+
+ /* The position should increase monotonically, since just one thread
+ is sending the binlog to the slave for which we want synchronous
+ replication. Let us check this, and print an error to the .err log
+ if that is not the case. */
+
+ if (innobase_repl_file_name_inited) {
+ cmp = strcmp(log_file_name, innobase_repl_file_name);
+
+ if (cmp < 0
+ || (cmp == 0 && end_offset < innobase_repl_pos)) {
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Error: MySQL synchronous replication has sent binlog\n"
+"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name,
+ (ulong)innobase_repl_pos);
+ fprintf(stderr,
+"InnoDB: but now MySQL reports that it sent the binlog only up to\n"
+"InnoDB: file %s, position %lu\n", log_file_name, (ulong)end_offset);
+
+ }
+ }
+
+ strcpy(innobase_repl_file_name, log_file_name);
+ innobase_repl_pos = end_offset;
+ innobase_repl_file_name_inited = 1;
+
+ if (innobase_repl_n_wait_threads > 0) {
+ /* Let us check if some of the waiting threads doing a trx
+ commit can now proceed */
+
+ cmp = strcmp(innobase_repl_file_name,
+ innobase_repl_wait_file_name);
+ if (cmp > 0
+ || (cmp == 0 && innobase_repl_pos
+ >= innobase_repl_wait_pos)) {
+
+ /* Yes, at least one waiting thread can now proceed:
+ let us release all waiting threads with a broadcast */
+
+ can_release_threads = 1;
+
+ innobase_repl_wait_file_name_inited = 0;
+ }
+ }
+
+ pthread_mutex_unlock(&innobase_repl_cond_mutex);
+
+ if (can_release_threads) {
+
+ pthread_cond_broadcast(&innobase_repl_cond);
+ }
+}
+#endif /* HAVE_REPLICATION */
+
+/*********************************************************************
+Rolls back a transaction or the latest SQL statement. */
+
+static int
innobase_rollback(
/*==============*/
/* out: 0 or error number */
THD* thd, /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
- void* trx_handle)/* in: InnoDB trx handle or a dummy stmt handle;
- the latter means we roll back the latest SQL
- statement */
+ bool all) /* in: TRUE - commit transaction
+ FALSE - the current SQL statement ended */
{
int error = 0;
trx_t* trx;
@@ -1369,6 +1927,9 @@ innobase_rollback(
trx = check_trx_exists(thd);
+ /* Update the info whether we should skip XA steps that eat CPU time */
+ trx->support_xa = (ibool)(thd->variables.innodb_support_xa);
+
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex, we have to release the search system latch
first to obey the latching order. */
@@ -1383,11 +1944,11 @@ innobase_rollback(
row_unlock_table_autoinc_for_mysql(trx);
}
- if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle
+ if (all
|| (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
error = trx_rollback_for_mysql(trx);
- thd->transaction.all.innodb_active_trans = 0;
+ trx->active_trans = 0;
} else {
error = trx_rollback_last_sql_stat_for_mysql(trx);
}
@@ -1396,23 +1957,54 @@ innobase_rollback(
}
/*********************************************************************
-Rolls back a transaction to a savepoint. */
+Rolls back a transaction */
int
+innobase_rollback_trx(
+/*==================*/
+ /* out: 0 or error number */
+ trx_t* trx) /* in: transaction */
+{
+ int error = 0;
+
+ DBUG_ENTER("innobase_rollback_trx");
+ DBUG_PRINT("trans", ("aborting transaction"));
+
+ /* Release a possible FIFO ticket and search latch. Since we will
+ reserve the kernel mutex, we have to release the search system latch
+ first to obey the latching order. */
+
+ innobase_release_stat_resources(trx);
+
+ if (trx->auto_inc_lock) {
+ /* If we had reserved the auto-inc lock for some table (if
+ we come here to roll back the latest SQL statement) we
+ release it now before a possibly lengthy rollback */
+
+ row_unlock_table_autoinc_for_mysql(trx);
+ }
+
+ error = trx_rollback_for_mysql(trx);
+
+ DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
+}
+
+/*********************************************************************
+Rolls back a transaction to a savepoint. */
+
+static int
innobase_rollback_to_savepoint(
/*===========================*/
/* out: 0 if success, HA_ERR_NO_SAVEPOINT if
no savepoint with the given name */
THD* thd, /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
- char* savepoint_name, /* in: savepoint name */
- my_off_t* binlog_cache_pos)/* out: position which corresponds to the
- savepoint in the binlog cache of this
- transaction, not defined if error */
+ void *savepoint) /* in: savepoint data */
{
ib_longlong mysql_binlog_cache_pos;
int error = 0;
trx_t* trx;
+ char name[64];
DBUG_ENTER("innobase_rollback_to_savepoint");
@@ -1424,27 +2016,53 @@ innobase_rollback_to_savepoint(
innobase_release_stat_resources(trx);
- error = trx_rollback_to_savepoint_for_mysql(trx, savepoint_name,
+ /* TODO: use provided savepoint data area to store savepoint data */
+
+ longlong2str((ulonglong)savepoint, name, 36);
+
+ error = trx_rollback_to_savepoint_for_mysql(trx, name,
&mysql_binlog_cache_pos);
- *binlog_cache_pos = (my_off_t)mysql_binlog_cache_pos;
+ DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
+}
+
+/*********************************************************************
+Release transaction savepoint name. */
+static
+int
+innobase_release_savepoint(
+/*=======================*/
+ /* out: 0 if success, HA_ERR_NO_SAVEPOINT if
+ no savepoint with the given name */
+ THD* thd, /* in: handle to the MySQL thread of the user
+ whose transaction should be rolled back */
+ void* savepoint) /* in: savepoint data */
+{
+ int error = 0;
+ trx_t* trx;
+ char name[64];
+
+ DBUG_ENTER("innobase_release_savepoint");
+
+ trx = check_trx_exists(thd);
+
+ /* TODO: use provided savepoint data area to store savepoint data */
+
+ longlong2str((ulonglong)savepoint, name, 36);
+
+ error = trx_release_savepoint_for_mysql(trx, name);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
}
/*********************************************************************
Sets a transaction savepoint. */
-
+static
int
innobase_savepoint(
/*===============*/
/* out: always 0, that is, always succeeds */
THD* thd, /* in: handle to the MySQL thread */
- char* savepoint_name, /* in: savepoint name */
- my_off_t binlog_cache_pos)/* in: offset up to which the current
- transaction has cached log entries to its
- binlog cache, not defined if no transaction
- active, or we are in the autocommit state, or
- binlogging is not switched on */
+ void* savepoint) /* in: savepoint data */
{
int error = 0;
trx_t* trx;
@@ -1465,14 +2083,14 @@ innobase_savepoint(
innobase_release_stat_resources(trx);
- /* Setting a savepoint starts a transaction inside InnoDB since
- it allocates resources for it (memory to store the savepoint name,
- for example) */
+ /* cannot happen outside of transaction */
+ DBUG_ASSERT(trx->active_trans);
- thd->transaction.all.innodb_active_trans = 1;
+ /* TODO: use provided savepoint data area to store savepoint data */
+ char name[64];
+ longlong2str((ulonglong)savepoint,name,36);
- error = trx_savepoint_for_mysql(trx, savepoint_name,
- (ib_longlong)binlog_cache_pos);
+ error = trx_savepoint_for_mysql(trx, name, (ib_longlong)0);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
}
@@ -1480,25 +2098,14 @@ innobase_savepoint(
/*********************************************************************
Frees a possible InnoDB trx object associated with the current THD. */
-int
+static int
innobase_close_connection(
/*======================*/
/* out: 0 or error number */
THD* thd) /* in: handle to the MySQL thread of the user
- whose transaction should be rolled back */
+ whose resources should be free'd */
{
- trx_t* trx;
-
- trx = (trx_t*)thd->transaction.all.innobase_tid;
-
- if (NULL != trx) {
- innobase_rollback(thd, (void*)trx);
-
- trx_free_for_mysql(trx);
-
- thd->transaction.all.innobase_tid = NULL;
- }
-
+ trx_free_for_mysql((trx_t*)thd->ha_data[innobase_hton.slot]);
return(0);
}
@@ -1508,18 +2115,41 @@ innobase_close_connection(
*****************************************************************************/
/********************************************************************
+Get the record format from the data dictionary. */
+enum row_type
+ha_innobase::get_row_type() const
+/*=============================*/
+ /* out: ROW_TYPE_REDUNDANT or ROW_TYPE_COMPACT */
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+
+ if (prebuilt && prebuilt->table) {
+ if (prebuilt->table->comp) {
+ return(ROW_TYPE_COMPACT);
+ } else {
+ return(ROW_TYPE_REDUNDANT);
+ }
+ }
+ ut_ad(0);
+ return(ROW_TYPE_NOT_USED);
+}
+
+/********************************************************************
Gives the file extension of an InnoDB single-table tablespace. */
+static const char* ha_innobase_exts[] = {
+ ".ibd",
+ NullS
+};
const char**
ha_innobase::bas_ext() const
/*========================*/
/* out: file extension string */
{
- static const char* ext[] = {".ibd", NullS};
-
- return(ext);
+ return ha_innobase_exts;
}
+
/*********************************************************************
Normalizes a table name string. A normalized name consists of the
database name catenated to '/' and table name. An example:
@@ -1604,7 +2234,8 @@ ha_innobase::open(
fields when packed actually became 1 byte longer, when we also
stored the string length as the first byte. */
- upd_and_key_val_buff_len = table->reclength + table->max_key_length
+ upd_and_key_val_buff_len =
+ table->s->reclength + table->s->max_key_length
+ MAX_REF_PARTS * 3;
if (!(mysql_byte*) my_multi_malloc(MYF(MY_WME),
&upd_buff, upd_and_key_val_buff_len,
@@ -1634,7 +2265,7 @@ ha_innobase::open(
my_free((char*) upd_buff, MYF(0));
my_errno = ENOENT;
- DBUG_RETURN(1);
+ DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
if (ib_table->ibd_file_missing && !thd->tablespace_op) {
@@ -1651,16 +2282,17 @@ ha_innobase::open(
my_free((char*) upd_buff, MYF(0));
my_errno = ENOENT;
- DBUG_RETURN(1);
+ DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
innobase_prebuilt = row_create_prebuilt(ib_table);
- ((row_prebuilt_t*)innobase_prebuilt)->mysql_row_len = table->reclength;
+ ((row_prebuilt_t*)innobase_prebuilt)->mysql_row_len =
+ table->s->reclength;
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
- primary_key = table->primary_key;
+ primary_key = table->s->primary_key;
key_used_on_scan = primary_key;
/* Allocate a buffer for a 'row reference'. A row reference is
@@ -1678,13 +2310,11 @@ ha_innobase::open(
((row_prebuilt_t*)innobase_prebuilt)
->clust_index_was_generated = FALSE;
- /*
- MySQL allocates the buffer for ref. key_info->key_length
- includes space for all key columns + one byte for each column
- that may be NULL. ref_length must be as exact as possible to
- save space, because all row reference buffers are allocated
- based on ref_length.
- */
+ /* MySQL allocates the buffer for ref. key_info->key_length
+ includes space for all key columns + one byte for each column
+ that may be NULL. ref_length must be as exact as possible to
+ save space, because all row reference buffers are allocated
+ based on ref_length. */
ref_length = table->key_info[primary_key].key_length;
} else {
@@ -1706,15 +2336,13 @@ ha_innobase::open(
ref_length = DATA_ROW_ID_LEN;
- /*
- If we automatically created the clustered index, then
- MySQL does not know about it, and MySQL must NOT be aware
- of the index used on scan, to make it avoid checking if we
- update the column of the index. That is why we assert below
- that key_used_on_scan is the undefined value MAX_KEY.
- The column is the row id in the automatical generation case,
- and it will never be updated anyway.
- */
+ /* If we automatically created the clustered index, then
+ MySQL does not know about it, and MySQL must NOT be aware
+ of the index used on scan, to make it avoid checking if we
+ update the column of the index. That is why we assert below
+ that key_used_on_scan is the undefined value MAX_KEY.
+ The column is the row id in the automatical generation case,
+ and it will never be updated anyway. */
if (key_used_on_scan != MAX_KEY) {
fprintf(stderr,
@@ -1724,8 +2352,6 @@ ha_innobase::open(
}
}
- auto_inc_counter_for_this_stat = 0;
-
block_size = 16 * 1024; /* Index block size in InnoDB: used by MySQL
in query optimization */
@@ -1833,7 +2459,7 @@ reset_null_bits(
TABLE* table, /* in: MySQL table object */
char* record) /* in: a row in MySQL format */
{
- bzero(record, table->null_bytes);
+ bzero(record, table->s->null_bytes);
}
extern "C" {
@@ -1868,12 +2494,14 @@ innobase_mysql_cmp(
switch (mysql_tp) {
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
case FIELD_TYPE_TINY_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
case FIELD_TYPE_BLOB:
case FIELD_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_VARCHAR:
/* Use the charset number to pick the right charset struct for
the comparison. Since the MySQL function get_charset may be
slow before Bar removes the mutex operation there, we first
@@ -1901,7 +2529,7 @@ innobase_mysql_cmp(
ret = charset->coll->strnncollsp(charset,
a, a_length,
- b, b_length);
+ b, b_length, 0);
if (ret < 0) {
return(-1);
} else if (ret > 0) {
@@ -1918,7 +2546,9 @@ innobase_mysql_cmp(
}
/******************************************************************
-Converts a MySQL type to an InnoDB type. */
+Converts a MySQL type to an InnoDB type. Note that this function returns
+the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
+VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'. */
inline
ulint
get_innobase_type_from_mysql_type(
@@ -1963,8 +2593,9 @@ get_innobase_type_from_mysql_type(
switch (field->type()) {
/* NOTE that we only allow string types in DATA_MYSQL
and DATA_VARMYSQL */
- case FIELD_TYPE_VAR_STRING: if (field->binary()) {
-
+ case MYSQL_TYPE_VAR_STRING: /* old <= 4.1 VARCHAR */
+ case MYSQL_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */
+ if (field->binary()) {
return(DATA_BINARY);
} else if (strcmp(
field->charset()->name,
@@ -1973,7 +2604,8 @@ get_innobase_type_from_mysql_type(
} else {
return(DATA_VARMYSQL);
}
- case FIELD_TYPE_STRING: if (field->binary()) {
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_STRING: if (field->binary()) {
return(DATA_FIXBINARY);
} else if (strcmp(
@@ -1983,6 +2615,8 @@ get_innobase_type_from_mysql_type(
} else {
return(DATA_MYSQL);
}
+ case FIELD_TYPE_NEWDECIMAL:
+ return(DATA_BINARY);
case FIELD_TYPE_LONG:
case FIELD_TYPE_LONGLONG:
case FIELD_TYPE_TINY:
@@ -2014,6 +2648,35 @@ get_innobase_type_from_mysql_type(
}
/***********************************************************************
+Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
+storage format. */
+inline
+void
+innobase_write_to_2_little_endian(
+/*==============================*/
+ byte* buf, /* in: where to store */
+ ulint val) /* in: value to write, must be < 64k */
+{
+ ut_a(val < 256 * 256);
+
+ buf[0] = (byte)(val & 0xFF);
+ buf[1] = (byte)(val / 256);
+}
+
+/***********************************************************************
+Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
+storage format. */
+inline
+uint
+innobase_read_from_2_little_endian(
+/*===============================*/
+ /* out: value */
+ const mysql_byte* buf) /* in: from where to read */
+{
+ return((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
+}
+
+/***********************************************************************
Stores a key value for a row to a buffer. */
uint
@@ -2052,9 +2715,14 @@ ha_innobase::store_key_val_for_row(
3. In a column prefix field, prefix_len next bytes are reserved for
data. In a normal field the max field length next bytes are reserved
for data. For a VARCHAR(n) the max field length is n. If the stored
- value is the SQL NULL then these data bytes are set to 0. */
+ value is the SQL NULL then these data bytes are set to 0.
- /* We have to zero-fill the buffer so that MySQL is able to use a
+ 4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
+ in the MySQL row format, the length is stored in 1 or 2 bytes,
+ depending on the maximum allowed length. But in the MySQL key value
+ format, the length always takes 2 bytes.
+
+ We have to zero-fill the buffer so that MySQL is able to use a
simple memcmp to compare two key values to determine if they are
equal. MySQL does this to compare contents of two 'ref' values. */
@@ -2077,7 +2745,50 @@ ha_innobase::store_key_val_for_row(
field = key_part->field;
mysql_type = field->type();
- if (mysql_type == FIELD_TYPE_TINY_BLOB
+ if (mysql_type == MYSQL_TYPE_VARCHAR) {
+ /* >= 5.0.3 true VARCHAR */
+ ulint lenlen;
+ ulint len;
+ byte* data;
+
+ if (is_null) {
+ buff += key_part->length + 2;
+
+ continue;
+ }
+
+ lenlen = (ulint)
+ (((Field_varstring*)field)->length_bytes);
+
+ data = row_mysql_read_true_varchar(&len,
+ (byte*) (record
+ + (ulint)get_field_offset(table, field)),
+ lenlen);
+
+ /* In a column prefix index, we may need to truncate
+ the stored value: */
+
+ if (len > key_part->length) {
+ len = key_part->length;
+ }
+
+ /* The length in a key value is always stored in 2
+ bytes */
+
+ row_mysql_store_true_var_len((byte*)buff, len, 2);
+ buff += 2;
+
+ memcpy(buff, data, len);
+
+ /* Note that we always reserve the maximum possible
+ length of the true VARCHAR in the key value, though
+ only len first bytes after the 2 length bytes contain
+ actual data. The rest of the space was reset to zero
+ in the bzero() call above. */
+
+ buff += key_part->length;
+
+ } else if (mysql_type == FIELD_TYPE_TINY_BLOB
|| mysql_type == FIELD_TYPE_MEDIUM_BLOB
|| mysql_type == FIELD_TYPE_BLOB
|| mysql_type == FIELD_TYPE_LONG_BLOB) {
@@ -2085,9 +2796,9 @@ ha_innobase::store_key_val_for_row(
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
if (is_null) {
- buff += key_part->length + 2;
+ buff += key_part->length + 2;
- continue;
+ continue;
}
blob_data = row_mysql_read_blob_ref(&blob_len,
@@ -2097,6 +2808,11 @@ ha_innobase::store_key_val_for_row(
ut_a(get_field_offset(table, field)
== key_part->offset);
+
+ /* All indexes on BLOB and TEXT are column prefix
+ indexes, and we may need to truncate the data to be
+ stored in the kay value: */
+
if (blob_len > key_part->length) {
blob_len = key_part->length;
}
@@ -2104,19 +2820,28 @@ ha_innobase::store_key_val_for_row(
/* MySQL reserves 2 bytes for the length and the
storage of the number is little-endian */
- ut_a(blob_len < 256);
- *((byte*)buff) = (byte)blob_len;
+ innobase_write_to_2_little_endian(
+ (byte*)buff, (ulint)blob_len);
buff += 2;
memcpy(buff, blob_data, blob_len);
+ /* Note that we always reserve the maximum possible
+ length of the BLOB prefix in the key value. */
+
buff += key_part->length;
} else {
+ /* Here we handle all other data types except the
+ true VARCHAR, BLOB and TEXT. Note that the column
+ value we store may be also in a column prefix
+ index. */
+
if (is_null) {
buff += key_part->length;
continue;
}
+
memcpy(buff, record + key_part->offset,
key_part->length);
buff += key_part->length;
@@ -2208,7 +2933,7 @@ build_template(
the clustered index */
}
- n_fields = (ulint)table->fields; /* number of columns */
+ n_fields = (ulint)table->s->fields; /* number of columns */
if (!prebuilt->mysql_template) {
prebuilt->mysql_template = (mysql_row_templ_t*)
@@ -2217,7 +2942,7 @@ build_template(
}
prebuilt->template_type = templ_type;
- prebuilt->null_bitmap_len = table->null_bytes;
+ prebuilt->null_bitmap_len = table->s->null_bytes;
prebuilt->templ_contains_blob = FALSE;
@@ -2227,12 +2952,15 @@ build_template(
templ = prebuilt->mysql_template + n_requested_fields;
field = table->field[i];
- if (templ_type == ROW_MYSQL_REC_FIELDS
- && !(fetch_all_in_key
- && dict_index_contains_col_or_prefix(index, i))
- && !(fetch_primary_key_cols
- && dict_table_col_in_clustered_key(index->table, i))
- && thd->query_id != field->query_id) {
+ ibool index_contains_field=
+ dict_index_contains_col_or_prefix(index, i);
+
+ 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))) {
/* This field is not needed in the query, skip it */
@@ -2270,11 +2998,19 @@ build_template(
templ->mysql_col_len = (ulint) field->pack_length();
templ->type = index->table->cols[i].type.mtype;
- templ->is_unsigned = index->table->cols[i].type.prtype
- & DATA_UNSIGNED;
+ templ->mysql_type = (ulint)field->type();
+
+ if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
+ templ->mysql_length_bytes = (ulint)
+ (((Field_varstring*)field)->length_bytes);
+ }
+
templ->charset = dtype_get_charset_coll_noninline(
index->table->cols[i].type.prtype);
-
+ templ->mbminlen = index->table->cols[i].type.mbminlen;
+ templ->mbmaxlen = index->table->cols[i].type.mbmaxlen;
+ templ->is_unsigned = index->table->cols[i].type.prtype
+ & DATA_UNSIGNED;
if (templ->type == DATA_BLOB) {
prebuilt->templ_contains_blob = TRUE;
}
@@ -2310,31 +3046,31 @@ ha_innobase::write_row(
int error;
longlong auto_inc;
longlong dummy;
- ibool incremented_auto_inc_for_stat = FALSE;
- ibool incremented_auto_inc_counter = FALSE;
- ibool skip_auto_inc_decr;
+ ibool auto_inc_used= FALSE;
DBUG_ENTER("ha_innobase::write_row");
if (prebuilt->trx !=
- (trx_t*) current_thd->transaction.all.innobase_tid) {
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]) {
fprintf(stderr,
"InnoDB: Error: the transaction object for the table handle is at\n"
"InnoDB: %p, but for the current thread it is at %p\n",
prebuilt->trx,
- current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
fputs("\n"
"InnoDB: Dump of 200 bytes around transaction.all: ",
stderr);
ut_print_buf(stderr,
- ((byte*)(&(current_thd->transaction.all))) - 100, 200);
+ ((byte*)(&(current_thd->ha_data[innobase_hton.slot]))) - 100,
+ 200);
putc('\n', stderr);
ut_error;
}
- statistic_increment(ha_write_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_write_count,
+ &LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
@@ -2366,7 +3102,7 @@ ha_innobase::write_row(
src_table = lock_get_src_table(
prebuilt->trx, prebuilt->table, &mode);
if (!src_table) {
- no_commit:
+no_commit:
/* Unknown situation: do not commit */
/*
ut_print_timestamp(stderr);
@@ -2381,14 +3117,15 @@ ha_innobase::write_row(
no need to re-acquire locks on it. */
/* Altering to InnoDB format */
- innobase_commit(user_thd, prebuilt->trx);
+ innobase_commit(user_thd, 1);
/* Note that this transaction is still active. */
- user_thd->transaction.all.innodb_active_trans = 1;
+ prebuilt->trx->active_trans = 1;
/* We will need an IX lock on the destination table. */
prebuilt->sql_stat_start = TRUE;
} else {
/* Ensure that there are no other table locks than
LOCK_IX and LOCK_AUTO_INC on the destination table. */
+
if (!lock_is_table_exclusive(prebuilt->table,
prebuilt->trx)) {
goto no_commit;
@@ -2396,9 +3133,9 @@ ha_innobase::write_row(
/* Commit the transaction. This will release the table
locks, so they have to be acquired again. */
- innobase_commit(user_thd, prebuilt->trx);
+ innobase_commit(user_thd, 1);
/* Note that this transaction is still active. */
- user_thd->transaction.all.innodb_active_trans = 1;
+ prebuilt->trx->active_trans = 1;
/* Re-acquire the table lock on the source table. */
row_lock_table_for_mysql(prebuilt, src_table, mode);
/* We will need an IX lock on the destination table. */
@@ -2443,40 +3180,34 @@ ha_innobase::write_row(
prebuilt->sql_stat_start = TRUE;
}
- /* Fetch the value the user possibly has set in the
- autoincrement field */
+ /*
+ We must use the handler code to update the auto-increment
+ value to be sure that increment it correctly.
+ */
+ update_auto_increment();
+ auto_inc_used= 1;
- auto_inc = table->next_number_field->val_int();
+ }
- /* In replication and also otherwise the auto-inc column
- can be set with SET INSERT_ID. Then we must look at
- user_thd->next_insert_id. If it is nonzero and the user
- has not supplied a value, we must use it, and use values
- incremented by 1 in all subsequent inserts within the
- same SQL statement! */
+ if (prebuilt->mysql_template == NULL
+ || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
+ /* Build the template used in converting quickly between
+ the two database formats */
- if (auto_inc == 0 && user_thd->next_insert_id != 0) {
+ build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
+ }
- auto_inc_counter_for_this_stat
- = user_thd->next_insert_id;
- }
+ innodb_srv_conc_enter_innodb(prebuilt->trx);
- if (auto_inc == 0 && auto_inc_counter_for_this_stat) {
- /* The user set the auto-inc counter for
- this SQL statement with SET INSERT_ID. We must
- assign sequential values from the counter. */
+ error = row_insert_for_mysql((byte*) record, prebuilt);
- auto_inc = auto_inc_counter_for_this_stat;
+ if (error == DB_SUCCESS && auto_inc_used) {
- /* We give MySQL a new value to place in the
- auto-inc column */
- user_thd->next_insert_id = auto_inc;
+ /* Fetch the value that was set in the autoincrement field */
- auto_inc_counter_for_this_stat++;
- incremented_auto_inc_for_stat = TRUE;
- }
+ auto_inc = table->next_number_field->val_int();
- if (auto_inc != 0) {
+ if (auto_inc != 0) {
/* This call will calculate the max of the current
value and the value supplied by the user and
update the counter accordingly */
@@ -2488,107 +3219,19 @@ ha_innobase::write_row(
The lock is released at each SQL statement's
end. */
- innodb_srv_conc_enter_innodb(prebuilt->trx);
- error = row_lock_table_autoinc_for_mysql(prebuilt);
- innodb_srv_conc_exit_innodb(prebuilt->trx);
-
- if (error != DB_SUCCESS) {
-
- error = convert_error_code_to_mysql(error,
- user_thd);
- goto func_exit;
- }
-
- dict_table_autoinc_update(prebuilt->table, auto_inc);
- } else {
- innodb_srv_conc_enter_innodb(prebuilt->trx);
-
- if (!prebuilt->trx->auto_inc_lock) {
-
- error = row_lock_table_autoinc_for_mysql(
- prebuilt);
- if (error != DB_SUCCESS) {
- innodb_srv_conc_exit_innodb(
- prebuilt->trx);
-
- error = convert_error_code_to_mysql(
- error, user_thd);
- goto func_exit;
- }
- }
-
- /* The following call gets the value of the auto-inc
- counter of the table and increments it by 1 */
-
- auto_inc = dict_table_autoinc_get(prebuilt->table);
- incremented_auto_inc_counter = TRUE;
+ error = row_lock_table_autoinc_for_mysql(prebuilt);
- innodb_srv_conc_exit_innodb(prebuilt->trx);
-
- /* We can give the new value for MySQL to place in
- the field */
-
- user_thd->next_insert_id = auto_inc;
- }
-
- /* This call of a handler.cc function places
- user_thd->next_insert_id to the column value, if the column
- value was not set by the user */
-
- update_auto_increment();
- }
-
- if (prebuilt->mysql_template == NULL
- || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
- /* Build the template used in converting quickly between
- the two database formats */
-
- build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
- }
-
- innodb_srv_conc_enter_innodb(prebuilt->trx);
-
- error = row_insert_for_mysql((byte*) record, prebuilt);
+ if (error != DB_SUCCESS) {
+ error = convert_error_code_to_mysql(error,
+ user_thd);
+ goto func_exit;
+ }
+ dict_table_autoinc_update(prebuilt->table, auto_inc);
+ }
+ }
innodb_srv_conc_exit_innodb(prebuilt->trx);
- if (error != DB_SUCCESS) {
- /* If the insert did not succeed we restore the value of
- the auto-inc counter we used; note that this behavior was
- introduced only in version 4.0.4.
- NOTE that a REPLACE command and LOAD DATA INFILE REPLACE
- handles a duplicate key error
- itself, and we must not decrement the autoinc counter
- if we are performing those statements.
- NOTE 2: if there was an error, for example a deadlock,
- which caused InnoDB to roll back the whole transaction
- already in the call of row_insert_for_mysql(), we may no
- longer have the AUTO-INC lock, and cannot decrement
- the counter here. */
-
- skip_auto_inc_decr = FALSE;
-
- if (error == DB_DUPLICATE_KEY
- && (user_thd->lex->sql_command == SQLCOM_REPLACE
- || user_thd->lex->sql_command
- == SQLCOM_REPLACE_SELECT
- || (user_thd->lex->sql_command == SQLCOM_LOAD
- && user_thd->lex->duplicates == DUP_REPLACE))) {
-
- skip_auto_inc_decr= TRUE;
- }
-
- if (!skip_auto_inc_decr && incremented_auto_inc_counter
- && prebuilt->trx->auto_inc_lock) {
- dict_table_autoinc_decrement(prebuilt->table);
- }
-
- if (!skip_auto_inc_decr && incremented_auto_inc_for_stat
- && prebuilt->trx->auto_inc_lock) {
- auto_inc_counter_for_this_stat--;
- }
- }
-
error = convert_error_code_to_mysql(error, user_thd);
/* Tell InnoDB server that there might be work for
@@ -2599,54 +3242,6 @@ func_exit:
DBUG_RETURN(error);
}
-/******************************************************************
-Converts field data for storage in an InnoDB update vector. */
-inline
-mysql_byte*
-innobase_convert_and_store_changed_col(
-/*===================================*/
- /* out: pointer to the end of the converted
- data in the buffer */
- upd_field_t* ufield, /* in/out: field in the update vector */
- mysql_byte* buf, /* in: buffer we can use in conversion */
- mysql_byte* data, /* in: column data to store */
- ulint len, /* in: data len */
- ulint col_type,/* in: data type in InnoDB type numbers */
- ulint is_unsigned)/* in: != 0 if an unsigned integer type */
-{
- uint i;
-
- if (len == UNIV_SQL_NULL) {
- data = NULL;
- } else if (col_type == DATA_VARCHAR || col_type == DATA_BINARY
- || col_type == DATA_VARMYSQL) {
- /* Remove trailing spaces */
- while (len > 0 && data[len - 1] == ' ') {
- len--;
- }
- } else if (col_type == DATA_INT) {
- /* Store integer data in InnoDB in a big-endian
- format, sign bit negated, if signed */
-
- for (i = 0; i < len; i++) {
- buf[len - 1 - i] = data[i];
- }
-
- if (!is_unsigned) {
- buf[0] = buf[0] ^ 128;
- }
-
- data = buf;
-
- buf += len;
- }
-
- ufield->new_val.data = data;
- ufield->new_val.len = len;
-
- return(buf);
-}
-
/**************************************************************************
Checks which fields have changed in a row and stores information
of them to an update vector. */
@@ -2667,19 +3262,22 @@ calc_row_difference(
{
mysql_byte* original_upd_buff = upd_buff;
Field* field;
+ enum_field_types field_mysql_type;
uint n_fields;
ulint o_len;
ulint n_len;
+ ulint col_pack_len;
+ byte* new_mysql_row_col;
byte* o_ptr;
byte* n_ptr;
byte* buf;
upd_field_t* ufield;
ulint col_type;
- ulint is_unsigned;
ulint n_changed = 0;
+ dfield_t dfield;
uint i;
- n_fields = table->fields;
+ n_fields = table->s->fields;
/* We use upd_buff to convert changed fields */
buf = (byte*) upd_buff;
@@ -2696,25 +3294,50 @@ calc_row_difference(
o_ptr = (byte*) old_row + get_field_offset(table, field);
n_ptr = (byte*) new_row + get_field_offset(table, field);
- o_len = field->pack_length();
- n_len = field->pack_length();
+
+ /* Use new_mysql_row_col and col_pack_len save the values */
+
+ new_mysql_row_col = n_ptr;
+ col_pack_len = field->pack_length();
+ o_len = col_pack_len;
+ n_len = col_pack_len;
+
+ /* We use o_ptr and n_ptr to dig up the actual data for
+ comparison. */
+
+ field_mysql_type = field->type();
+
col_type = prebuilt->table->cols[i].type.mtype;
- is_unsigned = prebuilt->table->cols[i].type.prtype &
- DATA_UNSIGNED;
+
switch (col_type) {
case DATA_BLOB:
o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
+
break;
+
case DATA_VARCHAR:
case DATA_BINARY:
case DATA_VARMYSQL:
- o_ptr = row_mysql_read_var_ref_noninline(&o_len,
- o_ptr);
- n_ptr = row_mysql_read_var_ref_noninline(&n_len,
- n_ptr);
+ if (field_mysql_type == MYSQL_TYPE_VARCHAR) {
+ /* This is a >= 5.0.3 type true VARCHAR where
+ the real payload data length is stored in
+ 1 or 2 bytes */
+
+ o_ptr = row_mysql_read_true_varchar(
+ &o_len, o_ptr,
+ (ulint)
+ (((Field_varstring*)field)->length_bytes));
+
+ n_ptr = row_mysql_read_true_varchar(
+ &n_len, n_ptr,
+ (ulint)
+ (((Field_varstring*)field)->length_bytes));
+ }
+
+ break;
default:
;
}
@@ -2736,12 +3359,27 @@ calc_row_difference(
/* The field has changed */
ufield = uvect->fields + n_changed;
+
+ /* Let us use a dummy dfield to make the conversion
+ from the MySQL column format to the InnoDB format */
+
+ dfield.type = (prebuilt->table->cols + i)->type;
+
+ if (n_len != UNIV_SQL_NULL) {
+ buf = row_mysql_store_col_in_innobase_format(
+ &dfield,
+ (byte*)buf,
+ TRUE,
+ new_mysql_row_col,
+ col_pack_len,
+ prebuilt->table->comp);
+ ufield->new_val.data = dfield.data;
+ ufield->new_val.len = dfield.len;
+ } else {
+ ufield->new_val.data = NULL;
+ ufield->new_val.len = UNIV_SQL_NULL;
+ }
- buf = (byte*)
- innobase_convert_and_store_changed_col(ufield,
- (mysql_byte*)buf,
- (mysql_byte*)n_ptr, n_len, col_type,
- is_unsigned);
ufield->exp = NULL;
ufield->field_no = prebuilt->table->cols[i].clust_pos;
n_changed++;
@@ -2778,7 +3416,7 @@ ha_innobase::update_row(
DBUG_ENTER("ha_innobase::update_row");
ut_ad(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
@@ -2839,7 +3477,7 @@ ha_innobase::delete_row(
DBUG_ENTER("ha_innobase::delete_row");
ut_ad(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;
@@ -2872,6 +3510,29 @@ ha_innobase::delete_row(
DBUG_RETURN(error);
}
+/**************************************************************************
+Deletes a lock set to a row */
+
+void
+ha_innobase::unlock_row(void)
+/*=========================*/
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+
+ DBUG_ENTER("ha_innobase::unlock_row");
+
+ if (last_query_id != user_thd->query_id) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Error: last_query_id is %lu != user_thd_query_id is %lu\n",
+ (ulong)last_query_id, (ulong)user_thd->query_id);
+ mem_analyze_corruption((byte *) prebuilt->trx);
+ ut_error;
+ }
+
+ row_unlock_for_mysql(prebuilt);
+}
+
/**********************************************************************
Initializes a handle to use an index. */
@@ -3023,9 +3684,10 @@ ha_innobase::index_read(
DBUG_ENTER("index_read");
ut_ad(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,
+ &LOCK_status);
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;
@@ -3131,16 +3793,17 @@ ha_innobase::change_active_index(
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
KEY* key=0;
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,
+ &LOCK_status);
DBUG_ENTER("change_active_index");
ut_ad(user_thd == current_thd);
ut_ad(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
active_index = keynr;
- if (keynr != MAX_KEY && table->keys > 0) {
+ if (keynr != MAX_KEY && table->s->keys > 0) {
key = table->key_info + active_index;
prebuilt->index = dict_table_get_index_noninline(
@@ -3224,7 +3887,7 @@ ha_innobase::general_fetch(
DBUG_ENTER("general_fetch");
ut_ad(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
innodb_srv_conc_enter_innodb(prebuilt->trx);
@@ -3263,7 +3926,8 @@ ha_innobase::index_next(
mysql_byte* buf) /* in/out: buffer for next row in MySQL
format */
{
- statistic_increment(ha_read_next_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,
+ &LOCK_status);
return(general_fetch(buf, ROW_SEL_NEXT, 0));
}
@@ -3280,7 +3944,8 @@ ha_innobase::index_next_same(
const mysql_byte* key, /* in: key value */
uint keylen) /* in: key value length */
{
- statistic_increment(ha_read_next_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,
+ &LOCK_status);
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
}
@@ -3314,7 +3979,8 @@ ha_innobase::index_first(
int error;
DBUG_ENTER("index_first");
- statistic_increment(ha_read_first_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_first_count,
+ &LOCK_status);
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
@@ -3340,7 +4006,8 @@ ha_innobase::index_last(
int error;
DBUG_ENTER("index_last");
- statistic_increment(ha_read_last_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_last_count,
+ &LOCK_status);
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
@@ -3405,7 +4072,8 @@ ha_innobase::rnd_next(
int error;
DBUG_ENTER("rnd_next");
- statistic_increment(ha_read_rnd_next_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
if (start_of_scan) {
error = index_first(buf);
@@ -3441,10 +4109,11 @@ ha_innobase::rnd_pos(
DBUG_ENTER("rnd_pos");
DBUG_DUMP("key", (char*) pos, ref_length);
- statistic_increment(ha_read_rnd_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_count,
+ &LOCK_status);
ut_ad(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
if (prebuilt->clust_index_was_generated) {
/* No primary key was defined for the table and we
@@ -3458,7 +4127,7 @@ ha_innobase::rnd_pos(
}
if (error) {
- DBUG_PRINT("error",("Got error: %ld",error));
+ DBUG_PRINT("error", ("Got error: %ld", error));
DBUG_RETURN(error);
}
@@ -3466,10 +4135,11 @@ ha_innobase::rnd_pos(
for the table, and it is == ref_length */
error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
- if (error)
- {
- DBUG_PRINT("error",("Got error: %ld",error));
+
+ if (error) {
+ DBUG_PRINT("error", ("Got error: %ld", error));
}
+
change_active_index(keynr);
DBUG_RETURN(error);
@@ -3493,7 +4163,7 @@ ha_innobase::position(
uint len;
ut_ad(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
if (prebuilt->clust_index_was_generated) {
/* No primary key was defined for the table and we
@@ -3509,12 +4179,11 @@ ha_innobase::position(
ref_length, record);
}
- /* Since we do not store len to the buffer 'ref', we must assume
- that len is always fixed for this table. The following assertion
- checks this. */
+ /* We assume that the 'ref' value len is always fixed for the same
+ table. */
if (len != ref_length) {
- fprintf(stderr,
+ fprintf(stderr,
"InnoDB: Error: stored ref len is %lu, but table ref len is %lu\n",
(ulong)len, (ulong)ref_length);
}
@@ -3530,7 +4199,7 @@ create_table_def(
TABLE* form, /* in: information on table
columns and indexes */
const char* table_name, /* in: table name */
- const char* path_of_temp_table)/* in: if this is a table explicitly
+ const char* path_of_temp_table,/* in: if this is a table explicitly
created by the user with the
TEMPORARY keyword, then this
parameter is the dir path where the
@@ -3538,27 +4207,30 @@ create_table_def(
an .ibd file for it (no .ibd extension
in the path, though); otherwise this
is NULL */
+ ibool comp) /* in: TRUE=compact record format */
{
Field* field;
dict_table_t* table;
ulint n_cols;
int error;
ulint col_type;
+ ulint col_len;
ulint nulls_allowed;
ulint unsigned_type;
ulint binary_type;
+ ulint long_true_varchar;
ulint charset_no;
ulint i;
DBUG_ENTER("create_table_def");
DBUG_PRINT("enter", ("table_name: %s", table_name));
- n_cols = form->fields;
+ n_cols = form->s->fields;
/* We pass 0 as the space id, and determine at a lower level the space
id where to store the table */
- table = dict_mem_table_create((char*) table_name, 0, n_cols);
+ table = dict_mem_table_create(table_name, 0, n_cols, comp);
if (path_of_temp_table) {
table->dir_path_of_temp_table =
@@ -3569,7 +4241,7 @@ create_table_def(
field = form->field[i];
col_type = get_innobase_type_from_mysql_type(&unsigned_type,
- field);
+ field);
if (field->null_ptr) {
nulls_allowed = 0;
} else {
@@ -3588,17 +4260,40 @@ create_table_def(
charset_no = (ulint)field->charset()->number;
- ut_a(charset_no < 256); /* in ut0type.h we assume that
- the number fits in one byte */
+ ut_a(charset_no < 256); /* in data0type.h we assume
+ that the number fits in one
+ byte */
+ }
+
+ ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
+ that this fits in one byte */
+ col_len = field->pack_length();
+
+ /* The MySQL pack length contains 1 or 2 bytes length field
+ for a true VARCHAR. Let us subtract that, so that the InnoDB
+ column length in the InnoDB data dictionary is the real
+ maximum byte length of the actual data. */
+
+ long_true_varchar = 0;
+
+ if (field->type() == MYSQL_TYPE_VARCHAR) {
+ col_len -= ((Field_varstring*)field)->length_bytes;
+
+ if (((Field_varstring*)field)->length_bytes == 2) {
+ long_true_varchar = DATA_LONG_TRUE_VARCHAR;
+ }
}
- dict_mem_table_add_col(table, (char*) field->field_name,
- col_type, dtype_form_prtype(
- (ulint)field->type()
- | nulls_allowed | unsigned_type
- | binary_type,
- + charset_no),
- field->pack_length(), 0);
+ dict_mem_table_add_col(table,
+ (char*) field->field_name,
+ col_type,
+ dtype_form_prtype(
+ (ulint)field->type()
+ | nulls_allowed | unsigned_type
+ | binary_type | long_true_varchar,
+ charset_no),
+ col_len,
+ 0);
}
error = row_create_table_for_mysql(table, trx);
@@ -3641,7 +4336,7 @@ create_index(
ind_type = 0;
- if (key_num == form->primary_key) {
+ if (key_num == form->s->primary_key) {
ind_type = ind_type | DICT_CLUSTERED;
}
@@ -3664,7 +4359,7 @@ create_index(
the length of the key part versus the column. */
field = NULL;
- for (j = 0; j < form->fields; j++) {
+ for (j = 0; j < form->s->fields; j++) {
field = form->field[j];
@@ -3677,13 +4372,17 @@ create_index(
}
}
- ut_a(j < form->fields);
+ ut_a(j < form->s->fields);
col_type = get_innobase_type_from_mysql_type(
&is_unsigned, key_part->field);
if (DATA_BLOB == col_type
- || key_part->length < field->pack_length()) {
+ || (key_part->length < field->pack_length()
+ && field->type() != MYSQL_TYPE_VARCHAR)
+ || (field->type() == MYSQL_TYPE_VARCHAR
+ && key_part->length < field->pack_length()
+ - ((Field_varstring*)field)->length_bytes)) {
prefix_len = key_part->length;
@@ -3766,12 +4465,13 @@ ha_innobase::create(
char name2[FN_REFLEN];
char norm_name[FN_REFLEN];
THD *thd= current_thd;
+ ib_longlong auto_inc_value;
DBUG_ENTER("ha_innobase::create");
DBUG_ASSERT(thd != NULL);
- if (form->fields > 1000) {
+ if (form->s->fields > 1000) {
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
but we play safe here */
@@ -3819,12 +4519,9 @@ ha_innobase::create(
/* Create the table definition in InnoDB */
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
-
- error = create_table_def(trx, form, norm_name, name2);
- } else {
- error = create_table_def(trx, form, norm_name, NULL);
- }
+ error = create_table_def(trx, form, norm_name,
+ create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL,
+ form->s->row_type != ROW_TYPE_REDUNDANT);
if (error) {
innobase_commit_low(trx);
@@ -3838,8 +4535,8 @@ ha_innobase::create(
/* Look for a primary key */
- primary_key_no= (table->primary_key != MAX_KEY ?
- (int) table->primary_key :
+ primary_key_no= (table->s->primary_key != MAX_KEY ?
+ (int) table->s->primary_key :
-1);
/* Our function row_get_mysql_key_number_for_index assumes
@@ -3849,7 +4546,7 @@ ha_innobase::create(
/* Create the keys */
- if (form->keys == 0 || primary_key_no == -1) {
+ if (form->s->keys == 0 || primary_key_no == -1) {
/* Create an index which is used as the clustered index;
order the rows by their row id which is internally generated
by InnoDB */
@@ -3882,7 +4579,7 @@ ha_innobase::create(
}
}
- for (i = 0; i < form->keys; i++) {
+ for (i = 0; i < form->s->keys; i++) {
if (i != (uint) primary_key_no) {
@@ -3939,6 +4636,20 @@ ha_innobase::create(
DBUG_ASSERT(innobase_table != 0);
+ if ((create_info->used_fields & HA_CREATE_USED_AUTO) &&
+ (create_info->auto_increment_value != 0)) {
+
+ /* Query was ALTER TABLE...AUTO_INCREMENT = x; or
+ CREATE TABLE ...AUTO_INCREMENT = x; Find out a table
+ definition from the dictionary and get the current value
+ of the auto increment field. Set a new value to the
+ auto increment field if the value is greater than the
+ maximum value in the column. */
+
+ auto_inc_value = create_info->auto_increment_value;
+ dict_table_autoinc_initialize(innobase_table, auto_inc_value);
+ }
+
/* Tell the InnoDB server that there might be work for
utility threads: */
@@ -3967,7 +4678,7 @@ ha_innobase::discard_or_import_tablespace(
ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
dict_table = prebuilt->table;
trx = prebuilt->trx;
@@ -3984,6 +4695,46 @@ ha_innobase::discard_or_import_tablespace(
}
/*********************************************************************
+Deletes all rows of an InnoDB table. */
+
+int
+ha_innobase::delete_all_rows(void)
+/*==============================*/
+ /* out: error number */
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
+ int error;
+ trx_t* trx;
+ THD* thd = current_thd;
+
+ DBUG_ENTER("ha_innobase::delete_all_rows");
+
+ if (thd->lex->sql_command != SQLCOM_TRUNCATE) {
+ fallback:
+ /* We only handle TRUNCATE TABLE t as a special case.
+ DELETE FROM t will have to use ha_innobase::delete_row(). */
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND);
+ }
+
+ /* Get the transaction associated with the current thd, or create one
+ if not yet created */
+
+ trx = check_trx_exists(thd);
+
+ /* Truncate the table in InnoDB */
+
+ error = row_truncate_table_for_mysql(prebuilt->table, trx);
+ if (error == DB_ERROR) {
+ /* Cannot truncate; resort to ha_innobase::delete_row() */
+ goto fallback;
+ }
+
+ error = convert_error_code_to_mysql(error, NULL);
+
+ DBUG_RETURN(error);
+}
+
+/*********************************************************************
Drops a table from an InnoDB database. Before calling this function,
MySQL calls innobase_commit to commit the transaction of the current user.
Then the current user cannot have locks set on the table. Drop table
@@ -4237,11 +4988,11 @@ ha_innobase::records_in_range(
KEY* key;
dict_index_t* index;
mysql_byte* key_val_buff2 = (mysql_byte*) my_malloc(
- table->reclength
- + table->max_key_length + 100,
+ table->s->reclength
+ + table->s->max_key_length + 100,
MYF(MY_WME));
- ulint buff2_len = table->reclength
- + table->max_key_length + 100;
+ ulint buff2_len = table->s->reclength
+ + table->s->max_key_length + 100;
dtuple_t* range_start;
dtuple_t* range_end;
ib_longlong n_rows;
@@ -4398,21 +5149,27 @@ ha_innobase::read_time(
ha_rows total_rows;
double time_for_scan;
- if (index != table->primary_key)
- return handler::read_time(index, ranges, rows); // Not clustered
+ if (index != table->s->primary_key) {
+ /* Not clustered */
+ return(handler::read_time(index, ranges, rows));
+ }
- if (rows <= 2)
- return (double) rows;
+ if (rows <= 2) {
+
+ return((double) rows);
+ }
/* Assume that the read time is proportional to the scan time for all
rows + at most one seek per range. */
time_for_scan = scan_time();
- if ((total_rows = estimate_rows_upper_bound()) < rows)
- return time_for_scan;
+ if ((total_rows = estimate_rows_upper_bound()) < rows) {
+
+ return(time_for_scan);
+ }
- return (ranges + (double) rows / (double) total_rows * time_for_scan);
+ return(ranges + (double) rows / (double) total_rows * time_for_scan);
}
/*************************************************************************
@@ -4517,7 +5274,7 @@ ha_innobase::info(
index = dict_table_get_next_index_noninline(index);
}
- for (i = 0; i < table->keys; i++) {
+ for (i = 0; i < table->s->keys; i++) {
if (index == NULL) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -4635,7 +5392,7 @@ ha_innobase::check(
ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
if (prebuilt->mysql_template == NULL) {
/* Build the template; we will use a dummy template
@@ -4793,6 +5550,103 @@ ha_innobase::get_foreign_key_create_info(void)
return(str);
}
+
+int
+ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
+{
+ dict_foreign_t* foreign;
+
+ DBUG_ENTER("get_foreign_key_list");
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
+ ut_a(prebuilt != NULL);
+ update_thd(current_thd);
+ prebuilt->trx->op_info = (char*)"getting list of foreign keys";
+ trx_search_latch_release_if_reserved(prebuilt->trx);
+ mutex_enter_noninline(&(dict_sys->mutex));
+ foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
+
+ while (foreign != NULL)
+ {
+ uint i;
+ FOREIGN_KEY_INFO f_key_info;
+ LEX_STRING *name= 0;
+ const char *tmp_buff;
+
+ tmp_buff= foreign->id;
+ i= 0;
+ while (tmp_buff[i] != '/')
+ i++;
+ tmp_buff+= i + 1;
+ f_key_info.forein_id= make_lex_string(thd, 0,
+ tmp_buff, strlen(tmp_buff), 1);
+ tmp_buff= foreign->referenced_table_name;
+ i= 0;
+ while (tmp_buff[i] != '/')
+ i++;
+ f_key_info.referenced_db= make_lex_string(thd, 0,
+ tmp_buff, i, 1);
+ tmp_buff+= i + 1;
+ f_key_info.referenced_table= make_lex_string(thd, 0,
+ tmp_buff, strlen(tmp_buff), 1);
+
+ for (i= 0;;)
+ {
+ tmp_buff= foreign->foreign_col_names[i];
+ name= make_lex_string(thd, name, tmp_buff, strlen(tmp_buff), 1);
+ f_key_info.foreign_fields.push_back(name);
+ tmp_buff= foreign->referenced_col_names[i];
+ name= make_lex_string(thd, name, tmp_buff, strlen(tmp_buff), 1);
+ f_key_info.referenced_fields.push_back(name);
+ if (++i >= foreign->n_fields)
+ break;
+ }
+
+ ulong length= 0;
+ if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE)
+ {
+ length=17;
+ tmp_buff= "ON DELETE CASCADE";
+ }
+ else if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL)
+ {
+ length=18;
+ tmp_buff= "ON DELETE SET NULL";
+ }
+ else if (foreign->type == DICT_FOREIGN_ON_DELETE_NO_ACTION)
+ {
+ length=19;
+ tmp_buff= "ON DELETE NO ACTION";
+ }
+ else if (foreign->type == DICT_FOREIGN_ON_UPDATE_CASCADE)
+ {
+ length=17;
+ tmp_buff= "ON UPDATE CASCADE";
+ }
+ else if (foreign->type == DICT_FOREIGN_ON_UPDATE_SET_NULL)
+ {
+ length=18;
+ tmp_buff= "ON UPDATE SET NULL";
+ }
+ else if (foreign->type == DICT_FOREIGN_ON_UPDATE_NO_ACTION)
+ {
+ length=19;
+ tmp_buff= "ON UPDATE NO ACTION";
+ }
+ f_key_info.constraint_method= make_lex_string(thd,
+ f_key_info.constraint_method,
+ tmp_buff, length, 1);
+
+ FOREIGN_KEY_INFO *pf_key_info= ((FOREIGN_KEY_INFO *)
+ thd->memdup((gptr) &f_key_info,
+ sizeof(FOREIGN_KEY_INFO)));
+ f_key_list->push_back(pf_key_info);
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+ mutex_exit_noninline(&(dict_sys->mutex));
+ prebuilt->trx->op_info = (char*)"";
+ DBUG_RETURN(0);
+}
+
/*********************************************************************
Checks if ALTER TABLE may change the storage engine of the table.
Changing storage engines is not allowed for tables for which there
@@ -4881,9 +5735,11 @@ ha_innobase::extra(
if (prebuilt->blob_heap) {
row_mysql_prebuilt_free_blob_heap(prebuilt);
}
+ prebuilt->keep_other_fields_on_keyread = 0;
prebuilt->read_just_key = 0;
break;
case HA_EXTRA_RESET_STATE:
+ prebuilt->keep_other_fields_on_keyread = 0;
prebuilt->read_just_key = 0;
break;
case HA_EXTRA_NO_KEYREAD:
@@ -4902,6 +5758,9 @@ ha_innobase::extra(
case HA_EXTRA_KEYREAD:
prebuilt->read_just_key = 1;
break;
+ case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
+ prebuilt->keep_other_fields_on_keyread = 1;
+ break;
default:/* Do nothing */
;
}
@@ -4950,6 +5809,7 @@ ha_innobase::start_stmt(
prebuilt->sql_stat_start = TRUE;
prebuilt->hint_need_to_fetch_extra_cols = 0;
prebuilt->read_just_key = 0;
+ prebuilt->keep_other_fields_on_keyread = FALSE;
if (!prebuilt->mysql_has_locked) {
/* This handle is for a temporary table created inside
@@ -4972,8 +5832,9 @@ ha_innobase::start_stmt(
select_lock_type value. The value of
stored_select_lock_type was decided in:
1) ::store_lock(),
- 2) ::external_lock(), and
- 3) ::init_table_handle_for_HANDLER(). */
+ 2) ::external_lock(),
+ 3) ::init_table_handle_for_HANDLER(), and
+ 4) :.transactional_table_lock(). */
prebuilt->select_lock_type =
prebuilt->stored_select_lock_type;
@@ -4994,7 +5855,13 @@ ha_innobase::start_stmt(
}
/* Set the MySQL flag to mark that there is an active transaction */
- thd->transaction.all.innodb_active_trans = 1;
+ if (trx->active_trans == 0) {
+
+ innobase_register_trx_and_stmt(thd);
+ trx->active_trans = 1;
+ } else {
+ innobase_register_stmt(thd);
+ }
return(0);
}
@@ -5047,6 +5914,7 @@ ha_innobase::external_lock(
prebuilt->hint_need_to_fetch_extra_cols = 0;
prebuilt->read_just_key = 0;
+ prebuilt->keep_other_fields_on_keyread = FALSE;
if (lock_type == F_WRLCK) {
@@ -5061,7 +5929,13 @@ ha_innobase::external_lock(
/* Set the MySQL flag to mark that there is an active
transaction */
- thd->transaction.all.innodb_active_trans = 1;
+ if (trx->active_trans == 0) {
+
+ innobase_register_trx_and_stmt(thd);
+ trx->active_trans = 1;
+ } else if (trx->n_mysql_tables_in_use == 0) {
+ innobase_register_stmt(thd);
+ }
trx->n_mysql_tables_in_use++;
prebuilt->mysql_has_locked = TRUE;
@@ -5141,8 +6015,8 @@ ha_innobase::external_lock(
innobase_release_stat_resources(trx);
if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
- if (thd->transaction.all.innodb_active_trans != 0) {
- innobase_commit(thd, trx);
+ if (trx->active_trans != 0) {
+ innobase_commit(thd, TRUE);
}
} else {
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
@@ -5159,17 +6033,121 @@ ha_innobase::external_lock(
DBUG_RETURN(0);
}
+/**********************************************************************
+With this function MySQL request a transactional lock to a table when
+user issued query LOCK TABLES..WHERE ENGINE = InnoDB. */
+
+int
+ha_innobase::transactional_table_lock(
+/*==================================*/
+ /* out: 0 */
+ THD* thd, /* in: handle to the user thread */
+ int lock_type) /* in: lock type */
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+ trx_t* trx;
+
+ DBUG_ENTER("ha_innobase::transactional_table_lock");
+ DBUG_PRINT("enter",("lock_type: %d", lock_type));
+
+ /* We do not know if MySQL can call this function before calling
+ external_lock(). To be safe, update the thd of the current table
+ handle. */
+
+ update_thd(thd);
+
+ if (prebuilt->table->ibd_file_missing && !current_thd->tablespace_op) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB error:\n"
+"MySQL is trying to use a table handle but the .ibd file for\n"
+"table %s does not exist.\n"
+"Have you deleted the .ibd file from the database directory under\n"
+"the MySQL datadir?"
+"Look from section 15.1 of http://www.innodb.com/ibman.html\n"
+"how you can resolve the problem.\n",
+ prebuilt->table->name);
+ DBUG_RETURN(HA_ERR_CRASHED);
+ }
+
+ trx = prebuilt->trx;
+
+ prebuilt->sql_stat_start = TRUE;
+ prebuilt->hint_need_to_fetch_extra_cols = 0;
+
+ prebuilt->read_just_key = 0;
+ prebuilt->keep_other_fields_on_keyread = FALSE;
+
+ if (lock_type == F_WRLCK) {
+ prebuilt->select_lock_type = LOCK_X;
+ prebuilt->stored_select_lock_type = LOCK_X;
+ } else if (lock_type == F_RDLCK) {
+ prebuilt->select_lock_type = LOCK_S;
+ prebuilt->stored_select_lock_type = LOCK_S;
+ } else {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB error:\n"
+"MySQL is trying to set transactional table lock with corrupted lock type\n"
+"to table %s, lock type %d does not exist.\n",
+ prebuilt->table->name, lock_type);
+ DBUG_RETURN(HA_ERR_CRASHED);
+ }
+
+ /* MySQL is setting a new transactional table lock */
+
+ /* Set the MySQL flag to mark that there is an active transaction */
+ if (trx->active_trans == 0) {
+
+ innobase_register_trx_and_stmt(thd);
+ trx->active_trans = 1;
+ }
+
+ 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);
+
+ if (error != DB_SUCCESS) {
+ error = convert_error_code_to_mysql(error, user_thd);
+ DBUG_RETURN(error);
+ }
+
+ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
+
+ /* Store the current undo_no of the transaction
+ so that we know where to roll back if we have
+ to roll back the next SQL statement */
+
+ trx_mark_sql_stat_end(trx);
+ }
+ }
+
+ DBUG_RETURN(0);
+}
+
+/****************************************************************************
+Here we export InnoDB status variables to MySQL. */
+
+void
+innodb_export_status(void)
+/*======================*/
+{
+ srv_export_innodb_status();
+}
+
/****************************************************************************
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
Monitor to the client. */
-int
+bool
innodb_show_status(
/*===============*/
THD* thd) /* in: the MySQL query thread of the caller */
{
Protocol *protocol= thd->protocol;
trx_t* trx;
+ long flen;
+ char* str;
DBUG_ENTER("innodb_show_status");
@@ -5177,7 +6155,7 @@ innodb_show_status(
my_message(ER_NOT_SUPPORTED_YET,
"Cannot call SHOW INNODB STATUS because skip-innodb is defined",
MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
trx = check_trx_exists(thd);
@@ -5186,14 +6164,13 @@ innodb_show_status(
/* We let the InnoDB Monitor to output at most 64000 bytes of text. */
- long flen;
- char* str;
-
mutex_enter_noninline(&srv_monitor_file_mutex);
rewind(srv_monitor_file);
+
srv_printf_innodb_monitor(srv_monitor_file);
flen = ftell(srv_monitor_file);
os_file_set_eof(srv_monitor_file);
+
if (flen < 0) {
flen = 0;
} else if (flen > 64000 - 1) {
@@ -5203,10 +6180,10 @@ innodb_show_status(
/* allocate buffer for the string, and
read the contents of the temporary file */
- if (!(str = my_malloc(flen + 1, MYF(0))))
- {
- mutex_exit_noninline(&srv_monitor_file_mutex);
- DBUG_RETURN(-1);
+ if (!(str = my_malloc(flen + 1, MYF(0)))) {
+ mutex_exit_noninline(&srv_monitor_file_mutex);
+
+ DBUG_RETURN(TRUE);
}
rewind(srv_monitor_file);
@@ -5218,22 +6195,122 @@ innodb_show_status(
field_list.push_back(new Item_empty_string("Status", flen));
- if (protocol->send_fields(&field_list, 1)) {
-
+ if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+ Protocol::SEND_EOF)) {
my_free(str, MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
protocol->prepare_for_resend();
protocol->store(str, flen, system_charset_info);
my_free(str, MYF(0));
- if (protocol->write())
- DBUG_RETURN(-1);
+ if (protocol->write()) {
+ DBUG_RETURN(TRUE);
+ }
send_eof(thd);
- DBUG_RETURN(0);
+
+ DBUG_RETURN(FALSE);
+}
+
+/****************************************************************************
+Implements the SHOW MUTEX STATUS command. . */
+
+bool
+innodb_mutex_show_status(
+/*===============*/
+ THD* thd) /* in: the MySQL query thread of the caller */
+{
+ Protocol *protocol= thd->protocol;
+ List<Item> field_list;
+ mutex_t* mutex;
+ ulint rw_lock_count= 0;
+ ulint rw_lock_count_spin_loop= 0;
+ ulint rw_lock_count_spin_rounds= 0;
+ ulint rw_lock_count_os_wait= 0;
+ ulint rw_lock_count_os_yield= 0;
+ ulonglong rw_lock_wait_time= 0;
+ DBUG_ENTER("innodb_mutex_show_status");
+
+ field_list.push_back(new Item_empty_string("Mutex", FN_REFLEN));
+ field_list.push_back(new Item_empty_string("Module", FN_REFLEN));
+ field_list.push_back(new Item_uint("Count", 21));
+ field_list.push_back(new Item_uint("Spin_waits", 21));
+ field_list.push_back(new Item_uint("Spin_rounds", 21));
+ field_list.push_back(new Item_uint("OS_waits", 21));
+ field_list.push_back(new Item_uint("OS_yields", 21));
+ field_list.push_back(new Item_uint("OS_waits_time", 21));
+
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
+
+#ifdef MUTEX_PROTECT_TO_BE_ADDED_LATER
+ mutex_enter(&mutex_list_mutex);
+#endif
+
+ mutex = UT_LIST_GET_FIRST(mutex_list);
+
+ while ( mutex != NULL )
+ {
+ if (mutex->mutex_type != 1)
+ {
+ if (mutex->count_using > 0)
+ {
+ protocol->prepare_for_resend();
+ protocol->store(mutex->cmutex_name, system_charset_info);
+ protocol->store(mutex->cfile_name, system_charset_info);
+ protocol->store((ulonglong)mutex->count_using);
+ protocol->store((ulonglong)mutex->count_spin_loop);
+ protocol->store((ulonglong)mutex->count_spin_rounds);
+ protocol->store((ulonglong)mutex->count_os_wait);
+ protocol->store((ulonglong)mutex->count_os_yield);
+ protocol->store((ulonglong)mutex->lspent_time/1000);
+
+ if (protocol->write())
+ {
+#ifdef MUTEX_PROTECT_TO_BE_ADDED_LATER
+ mutex_exit(&mutex_list_mutex);
+#endif
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ else
+ {
+ rw_lock_count += mutex->count_using;
+ rw_lock_count_spin_loop += mutex->count_spin_loop;
+ rw_lock_count_spin_rounds += mutex->count_spin_rounds;
+ rw_lock_count_os_wait += mutex->count_os_wait;
+ rw_lock_count_os_yield += mutex->count_os_yield;
+ rw_lock_wait_time += mutex->lspent_time;
+ }
+
+ mutex = UT_LIST_GET_NEXT(list, mutex);
+ }
+
+ protocol->prepare_for_resend();
+ protocol->store("rw_lock_mutexes", system_charset_info);
+ protocol->store("", system_charset_info);
+ protocol->store((ulonglong)rw_lock_count);
+ protocol->store((ulonglong)rw_lock_count_spin_loop);
+ protocol->store((ulonglong)rw_lock_count_spin_rounds);
+ protocol->store((ulonglong)rw_lock_count_os_wait);
+ protocol->store((ulonglong)rw_lock_count_os_yield);
+ protocol->store((ulonglong)rw_lock_wait_time/1000);
+
+ if (protocol->write())
+ {
+ DBUG_RETURN(1);
+ }
+
+#ifdef MUTEX_PROTECT_TO_BE_ADDED_LATER
+ mutex_exit(&mutex_list_mutex);
+#endif
+ send_eof(thd);
+ DBUG_RETURN(FALSE);
}
/****************************************************************************
@@ -5251,7 +6328,7 @@ static mysql_byte* innobase_get_key(INNOBASE_SHARE *share,uint *length,
static INNOBASE_SHARE *get_share(const char *table_name)
{
INNOBASE_SHARE *share;
- pthread_mutex_lock(&innobase_mutex);
+ pthread_mutex_lock(&innobase_share_mutex);
uint length=(uint) strlen(table_name);
if (!(share=(INNOBASE_SHARE*) hash_search(&innobase_open_tables,
(mysql_byte*) table_name,
@@ -5265,7 +6342,7 @@ static INNOBASE_SHARE *get_share(const char *table_name)
strmov(share->table_name,table_name);
if (my_hash_insert(&innobase_open_tables, (mysql_byte*) share))
{
- pthread_mutex_unlock(&innobase_mutex);
+ pthread_mutex_unlock(&innobase_share_mutex);
my_free((gptr) share,0);
return 0;
}
@@ -5274,13 +6351,13 @@ static INNOBASE_SHARE *get_share(const char *table_name)
}
}
share->use_count++;
- pthread_mutex_unlock(&innobase_mutex);
+ pthread_mutex_unlock(&innobase_share_mutex);
return share;
}
static void free_share(INNOBASE_SHARE *share)
{
- pthread_mutex_lock(&innobase_mutex);
+ pthread_mutex_lock(&innobase_share_mutex);
if (!--share->use_count)
{
hash_delete(&innobase_open_tables, (mysql_byte*) share);
@@ -5288,7 +6365,7 @@ static void free_share(INNOBASE_SHARE *share)
pthread_mutex_destroy(&share->mutex);
my_free((gptr) share, MYF(0));
}
- pthread_mutex_unlock(&innobase_mutex);
+ pthread_mutex_unlock(&innobase_share_mutex);
}
/*********************************************************************
@@ -5312,11 +6389,16 @@ ha_innobase::store_lock(
of current handle is stored
next to this array */
enum thr_lock_type lock_type) /* in: lock type to store in
- 'lock' */
+ 'lock'; this may also be
+ TL_IGNORE */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
- if ((lock_type == TL_READ && thd->in_lock_tables) ||
+ /* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
+ Be careful to ignore TL_IGNORE if we are going to do something with
+ only 'real' locks! */
+
+ if ((lock_type == TL_READ && thd->in_lock_tables) ||
(lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) ||
lock_type == TL_READ_WITH_SHARED_LOCKS ||
lock_type == TL_READ_NO_INSERT ||
@@ -5333,7 +6415,12 @@ ha_innobase::store_lock(
MySQL is doing LOCK TABLES ... READ.
5) we let InnoDB do locking reads for all SQL statements that
are not simple SELECTs; note that select_lock_type in this
- case may get strengthened in ::external_lock() to LOCK_X. */
+ case may get strengthened in ::external_lock() to LOCK_X.
+ Note that we MUST use a locking read in all data modifying
+ SQL statements, because otherwise the execution would not be
+ serializable, and also the results from the update could be
+ unexpected if an obsolete consistent read view would be
+ used. */
if (srv_locks_unsafe_for_binlog &&
prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE &&
@@ -5359,10 +6446,6 @@ ha_innobase::store_lock(
} else if (lock_type != TL_IGNORE) {
- /* In ha_berkeley.cc there is a comment that MySQL
- may in exceptional cases call this with TL_IGNORE also
- when it is NOT going to release the lock. */
-
/* We set possible LOCK_X value in external_lock, not yet
here even if this would be SELECT ... FOR UPDATE */
@@ -5373,11 +6456,12 @@ ha_innobase::store_lock(
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
/* If we are not doing a LOCK TABLE or DISCARD/IMPORT
- TABLESPACE, then allow multiple writers */
+ TABLESPACE or TRUNCATE TABLE, then allow multiple writers */
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
lock_type <= TL_WRITE) && !thd->in_lock_tables
- && !thd->tablespace_op) {
+ && !thd->tablespace_op
+ && thd->lex->sql_command != SQLCOM_TRUNCATE) {
lock_type = TL_WRITE_ALLOW_WRITE;
}
@@ -5392,7 +6476,7 @@ ha_innobase::store_lock(
lock_type = TL_READ;
}
- lock.type=lock_type;
+ lock.type = lock_type;
}
*to++= &lock;
@@ -5419,7 +6503,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
ut_a(prebuilt);
ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) current_thd->ha_data[innobase_hton.slot]);
ut_a(prebuilt->table);
/* In case MySQL calls this in the middle of a SELECT query, release
@@ -5454,7 +6538,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
}
(void) extra(HA_EXTRA_KEYREAD);
- index_init(table->next_number_index);
+ 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
@@ -5489,7 +6573,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
} else {
/* Initialize to max(col) + 1 */
auto_inc = (longlong) table->next_number_field->
- val_int_offset(table->rec_buff_length) + 1;
+ val_int_offset(table->s->rec_buff_length) + 1;
}
dict_table_autoinc_initialize(prebuilt->table, auto_inc);
@@ -5510,7 +6594,7 @@ initialized yet. This function does not change the value of the auto-inc
counter if it already has been initialized. Returns the value of the
auto-inc counter. */
-longlong
+ulonglong
ha_innobase::get_auto_increment()
/*=============================*/
/* out: auto-increment column value, -1 if error
@@ -5523,41 +6607,85 @@ ha_innobase::get_auto_increment()
if (error) {
- return(-1);
+ return(~(ulonglong) 0);
}
- return(nr);
+ return((ulonglong) nr);
}
/***********************************************************************
-This function stores the binlog offset and flushes logs. */
+Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
+If there is no explicitly declared non-null unique key or a primary key, then
+InnoDB internally uses the row id as the primary key. */
-void
-innobase_store_binlog_offset_and_flush_log(
-/*=======================================*/
- char *binlog_name, /* in: binlog name */
- longlong offset) /* in: binlog offset */
+int
+ha_innobase::cmp_ref(
+/*=================*/
+ /* out: < 0 if ref1 < ref2, 0 if equal, else
+ > 0 */
+ const mysql_byte* ref1, /* in: an (internal) primary key value in the
+ MySQL key value format */
+ const mysql_byte* ref2) /* in: an (internal) primary key value in the
+ MySQL key value format */
{
- mtr_t mtr;
-
- assert(binlog_name != NULL);
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+ enum_field_types mysql_type;
+ Field* field;
+ KEY_PART_INFO* key_part;
+ KEY_PART_INFO* key_part_end;
+ uint len1;
+ uint len2;
+ int result;
- /* Start a mini-transaction */
- mtr_start_noninline(&mtr);
+ if (prebuilt->clust_index_was_generated) {
+ /* The 'ref' is an InnoDB row id */
- /* Update the latest MySQL binlog name and offset info
- in trx sys header */
+ return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
+ }
- trx_sys_update_mysql_binlog_offset(
- binlog_name,
- offset,
- TRX_SYS_MYSQL_LOG_INFO, &mtr);
+ /* Do a type-aware comparison of primary key fields. PK fields
+ are always NOT NULL, so no checks for NULL are performed. */
- /* Commits the mini-transaction */
- mtr_commit(&mtr);
-
- /* Syncronous flush of the log buffer to disk */
- log_buffer_flush_to_disk();
+ key_part = table->key_info[table->s->primary_key].key_part;
+
+ key_part_end = key_part
+ + table->key_info[table->s->primary_key].key_parts;
+
+ for (; key_part != key_part_end; ++key_part) {
+ field = key_part->field;
+ mysql_type = field->type();
+
+ if (mysql_type == FIELD_TYPE_TINY_BLOB
+ || mysql_type == FIELD_TYPE_MEDIUM_BLOB
+ || mysql_type == FIELD_TYPE_BLOB
+ || mysql_type == FIELD_TYPE_LONG_BLOB) {
+
+ /* In the MySQL key value format, a column prefix of
+ a BLOB is preceded by a 2-byte length field */
+
+ len1 = innobase_read_from_2_little_endian(ref1);
+ len2 = innobase_read_from_2_little_endian(ref2);
+
+ ref1 += 2;
+ ref2 += 2;
+ result = ((Field_blob*)field)->cmp(
+ (const char*)ref1, len1,
+ (const char*)ref2, len2);
+ } else {
+ result = field->cmp((const char*)ref1,
+ (const char*)ref2);
+ }
+
+ if (result) {
+
+ return(result);
+ }
+
+ ref1 += key_part->length;
+ ref2 += key_part->length;
+ }
+
+ return(0);
}
char*
@@ -5672,15 +6800,17 @@ innobase_query_is_update(void)
thd = (THD *)innobase_current_thd();
- if ( thd->lex->sql_command == SQLCOM_REPLACE ||
- thd->lex->sql_command == SQLCOM_REPLACE_SELECT ||
- ( thd->lex->sql_command == SQLCOM_LOAD &&
- thd->lex->duplicates == DUP_REPLACE )) {
+ if (thd->lex->sql_command == SQLCOM_REPLACE ||
+ thd->lex->sql_command == SQLCOM_REPLACE_SELECT ||
+ (thd->lex->sql_command == SQLCOM_LOAD &&
+ thd->lex->duplicates == DUP_REPLACE)) {
+
return(1);
}
- if ( thd->lex->sql_command == SQLCOM_INSERT &&
- thd->lex->duplicates == DUP_UPDATE ) {
+ if (thd->lex->sql_command == SQLCOM_INSERT &&
+ thd->lex->duplicates == DUP_UPDATE) {
+
return(1);
}
@@ -5688,4 +6818,161 @@ innobase_query_is_update(void)
}
}
+/***********************************************************************
+This function is used to prepare X/Open XA distributed transaction */
+
+int
+innobase_xa_prepare(
+/*================*/
+ /* out: 0 or error number */
+ THD* thd, /* in: handle to the MySQL thread of the user
+ whose XA transaction should be prepared */
+ bool all) /* in: TRUE - commit transaction
+ FALSE - the current SQL statement ended */
+{
+ int error = 0;
+ trx_t* trx = check_trx_exists(thd);
+
+ if (thd->lex->sql_command != SQLCOM_XA_PREPARE) {
+
+ /* For ibbackup to work the order of transactions in binlog
+ and InnoDB must be the same. Consider the situation
+
+ thread1> prepare; write to binlog; ...
+ <context switch>
+ thread2> prepare; write to binlog; commit
+ thread1> ... commit
+
+ To ensure this will not happen we're taking the mutex on
+ prepare, and releasing it on commit.
+
+ Note: only do it for normal commits, done via ha_commit_trans.
+ If 2pc protocol is executed by external transaction
+ coordinator, it will be just a regular MySQL client
+ executing XA PREPARE and XA COMMIT commands.
+ In this case we cannot know how many minutes or hours
+ will be between XA PREPARE and XA COMMIT, and we don't want
+ to block for undefined period of time.
+ */
+ pthread_mutex_lock(&prepare_commit_mutex);
+ trx->active_trans = 2;
+ }
+
+ if (!thd->variables.innodb_support_xa) {
+
+ return(0);
+ }
+
+ trx->xid=thd->transaction.xid;
+
+ /* Release a possible FIFO ticket and search latch. Since we will
+ reserve the kernel mutex, we have to release the search system latch
+ first to obey the latching order. */
+
+ innobase_release_stat_resources(trx);
+
+ if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) {
+
+ fprintf(stderr,
+"InnoDB: Error: trx->active_trans == 0\n"
+"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n");
+ }
+
+ if (all
+ || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
+
+ /* We were instructed to prepare the whole transaction, or
+ this is an SQL statement end and autocommit is on */
+
+ ut_ad(trx->active_trans);
+
+ error = trx_prepare_for_mysql(trx);
+ } else {
+ /* We just mark the SQL statement ended and do not do a
+ transaction prepare */
+
+ if (trx->auto_inc_lock) {
+ /* If we had reserved the auto-inc lock for some
+ table in this SQL statement we release it now */
+
+ row_unlock_table_autoinc_for_mysql(trx);
+ }
+ /* Store the current undo_no of the transaction so that we
+ know where to roll back if we have to roll back the next
+ SQL statement */
+
+ trx_mark_sql_stat_end(trx);
+ }
+
+ /* Tell the InnoDB server that there might be work for utility
+ threads: */
+
+ srv_active_wake_master_thread();
+
+ return error;
+}
+
+/***********************************************************************
+This function is used to recover X/Open XA distributed transactions */
+
+int
+innobase_xa_recover(
+/*================*/
+ /* out: number of prepared transactions
+ stored in xid_list */
+ XID* xid_list, /* in/out: prepared transactions */
+ uint len) /* in: number of slots in xid_list */
+{
+ if (len == 0 || xid_list == NULL) {
+
+ return(0);
+ }
+
+ return(trx_recover_for_mysql(xid_list, len));
+}
+
+/***********************************************************************
+This function is used to commit one X/Open XA distributed transaction
+which is in the prepared state */
+
+int
+innobase_commit_by_xid(
+/*===================*/
+ /* out: 0 or error number */
+ XID* xid) /* in: X/Open XA transaction identification */
+{
+ trx_t* trx;
+
+ trx = trx_get_trx_by_xid(xid);
+
+ if (trx) {
+ innobase_commit_low(trx);
+
+ return(XA_OK);
+ } else {
+ return(XAER_NOTA);
+ }
+}
+
+/***********************************************************************
+This function is used to rollback one X/Open XA distributed transaction
+which is in the prepared state */
+
+int
+innobase_rollback_by_xid(
+/*=====================*/
+ /* out: 0 or error number */
+ XID *xid) /* in: X/Open XA transaction idenfification */
+{
+ trx_t* trx;
+
+ trx = trx_get_trx_by_xid(xid);
+
+ if (trx) {
+ return(innobase_rollback_trx(trx));
+ } else {
+ return(XAER_NOTA);
+ }
+}
+
#endif /* HAVE_INNOBASE_DB */
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index edf428669d8..6c412a889b2 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB && Innobase Oy
+/* Copyright (C) 2000-2005 MySQL AB && Innobase Oy
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
@@ -33,16 +33,21 @@ typedef struct st_innobase_share {
} INNOBASE_SHARE;
+my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
+ uint full_name_len,
+ ulonglong *unused);
+
/* The class defining a handle to an Innodb table */
class ha_innobase: public handler
{
- void* innobase_prebuilt; /* (row_prebuilt_t*) prebuilt
- struct in Innodb, used to save
- CPU */
+ void* innobase_prebuilt;/* (row_prebuilt_t*) prebuilt
+ struct in InnoDB, used to save
+ CPU time with prebuilt data
+ structures*/
THD* user_thd; /* the thread handle of the user
currently using the handle; this is
set in external_lock function */
- ulong last_query_id; /* the latest query id where the
+ query_id_t last_query_id; /* the latest query id where the
handle was used */
THR_LOCK_DATA lock;
INNOBASE_SHARE *share;
@@ -79,7 +84,7 @@ class ha_innobase: public handler
public:
ha_innobase(TABLE *table): handler(table),
int_table_flags(HA_REC_NOT_IN_SEQ |
- HA_NULL_IN_KEY | HA_FAST_KEY_READ |
+ HA_NULL_IN_KEY |
HA_CAN_INDEX_BLOBS |
HA_CAN_SQL_HANDLER |
HA_NOT_EXACT_COUNT |
@@ -91,6 +96,11 @@ class ha_innobase: public handler
{
}
~ha_innobase() {}
+ /*
+ Get the row type from the storage engine. If this method returns
+ ROW_TYPE_NOT_USED, the information in HA_CREATE_INFO should be used.
+ */
+ enum row_type get_row_type() const;
const char* table_type() const { return("InnoDB");}
const char *index_type(uint key_number) { return "BTREE"; }
@@ -98,7 +108,10 @@ class ha_innobase: public handler
ulong table_flags() const { return int_table_flags; }
ulong index_flags(uint idx, uint part, bool all_parts) const
{
- return (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE |
+ return (HA_READ_NEXT |
+ HA_READ_PREV |
+ HA_READ_ORDER |
+ HA_READ_RANGE |
HA_KEYREAD_ONLY);
}
uint max_supported_keys() const { return MAX_KEY; }
@@ -122,6 +135,7 @@ class ha_innobase: public handler
int write_row(byte * buf);
int update_row(const byte * old_data, byte * new_data);
int delete_row(const byte * buf);
+ void unlock_row();
int index_init(uint index);
int index_end();
@@ -148,35 +162,56 @@ class ha_innobase: public handler
int discard_or_import_tablespace(my_bool discard);
int extra(enum ha_extra_function operation);
int external_lock(THD *thd, int lock_type);
+ int transactional_table_lock(THD *thd, int lock_type);
int start_stmt(THD *thd);
void position(byte *record);
- ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
+ ha_rows records_in_range(uint inx, key_range *min_key, key_range
+ *max_key);
ha_rows estimate_rows_upper_bound();
int create(const char *name, register TABLE *form,
HA_CREATE_INFO *create_info);
+ int delete_all_rows();
int delete_table(const char *name);
int rename_table(const char* from, const char* to);
int check(THD* thd, HA_CHECK_OPT* check_opt);
char* update_table_comment(const char* comment);
char* get_foreign_key_create_info();
+ int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
bool can_switch_engines();
uint referenced_by_foreign_key();
void free_foreign_key_create_info(char* str);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
void init_table_handle_for_HANDLER();
- longlong get_auto_increment();
+ ulonglong get_auto_increment();
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
-
- static char *get_mysql_bin_log_name();
+ /*
+ ask handler about permission to cache table during query registration
+ */
+ my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback *call_back,
+ ulonglong *engine_data)
+ {
+ *call_back= innobase_query_caching_of_table_permitted;
+ *engine_data= 0;
+ return innobase_query_caching_of_table_permitted(thd, table_key,
+ key_length,
+ engine_data);
+ }
+ static char *get_mysql_bin_log_name();
static ulonglong get_mysql_bin_log_pos();
+ bool primary_key_is_clustered() { return true; }
+ int cmp_ref(const byte *ref1, const byte *ref2);
};
+extern struct show_var_st innodb_status_variables[];
extern uint innobase_init_flags, innobase_lock_type;
extern uint innobase_flush_log_at_trx_commit;
-extern ulong innobase_cache_size;
+extern ulong innobase_cache_size, innobase_fast_shutdown;
+extern ulong innobase_large_page_size;
extern char *innobase_home, *innobase_tmpdir, *innobase_logdir;
extern long innobase_lock_scan_time;
extern long innobase_mirrored_log_groups, innobase_log_files_in_group;
@@ -191,7 +226,10 @@ extern char *innobase_log_group_home_dir, *innobase_log_arch_dir;
extern char *innobase_unix_file_flush_method;
/* The following variables have to be my_bool for SHOW VARIABLES to work */
extern my_bool innobase_log_archive,
- innobase_use_native_aio, innobase_fast_shutdown,
+ innobase_use_doublewrite,
+ innobase_use_checksums,
+ innobase_use_large_pages,
+ innobase_use_native_aio,
innobase_file_per_table, innobase_locks_unsafe_for_binlog,
innobase_create_status_file;
extern my_bool innobase_very_fast_shutdown; /* set this to 1 just before
@@ -203,40 +241,85 @@ extern "C" {
extern ulong srv_max_buf_pool_modified_pct;
extern ulong srv_max_purge_lag;
extern ulong srv_auto_extend_increment;
+extern ulong srv_n_spin_wait_rounds;
+extern ulong srv_n_free_tickets_to_enter;
+extern ulong srv_thread_sleep_delay;
+extern ulong srv_thread_concurrency;
}
extern TYPELIB innobase_lock_typelib;
-bool innobase_init(void);
+handlerton *innobase_init(void);
bool innobase_end(void);
bool innobase_flush_logs(void);
uint innobase_get_free_space(void);
-int innobase_commit(THD *thd, void* trx_handle);
+/*
+ don't delete it - it may be re-enabled later
+ as an optimization for the most common case InnoDB+binlog
+*/
+#if 0
int innobase_report_binlog_offset_and_commit(
THD* thd,
void* trx_handle,
char* log_file_name,
my_off_t end_offset);
-int innobase_commit_complete(
- void* trx_handle);
-int innobase_rollback(THD *thd, void* trx_handle);
-int innobase_rollback_to_savepoint(
- THD* thd,
- char* savepoint_name,
- my_off_t* binlog_cache_pos);
-int innobase_savepoint(
- THD* thd,
- char* savepoint_name,
- my_off_t binlog_cache_pos);
-int innobase_close_connection(THD *thd);
+int innobase_commit_complete(void* trx_handle);
+void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset);
+#endif
+
int innobase_drop_database(char *path);
-int innodb_show_status(THD* thd);
+bool innodb_show_status(THD* thd);
+bool innodb_mutex_show_status(THD* thd);
+void innodb_export_status(void);
-my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
- uint full_name_len);
-void innobase_release_temporary_latches(void* innobase_tid);
+void innobase_release_temporary_latches(THD *thd);
void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset);
int innobase_start_trx_and_assign_read_view(THD* thd);
+
+/***********************************************************************
+This function is used to prepare X/Open XA distributed transaction */
+
+int innobase_xa_prepare(
+/*====================*/
+ /* out: 0 or error number */
+ THD* thd, /* in: handle to the MySQL thread of the user
+ whose XA transaction should be prepared */
+ bool all); /* in: TRUE - commit transaction
+ FALSE - the current SQL statement ended */
+
+/***********************************************************************
+This function is used to recover X/Open XA distributed transactions */
+
+int innobase_xa_recover(
+/*====================*/
+ /* out: number of prepared transactions
+ stored in xid_list */
+ XID* xid_list, /* in/out: prepared transactions */
+ uint len); /* in: number of slots in xid_list */
+
+/***********************************************************************
+This function is used to commit one X/Open XA distributed transaction
+which is in the prepared state */
+
+int innobase_commit_by_xid(
+/*=======================*/
+ /* out: 0 or error number */
+ XID* xid); /* in : X/Open XA Transaction Identification */
+
+/***********************************************************************
+This function is used to rollback one X/Open XA distributed transaction
+which is in the prepared state */
+
+int innobase_rollback_by_xid(
+ /* out: 0 or error number */
+ XID *xid); /* in : X/Open XA Transaction Idenfification */
+
+
+int innobase_xa_end(THD *thd);
+
+
+int innobase_repl_report_sent_binlog(THD *thd, char *log_file_name,
+ my_off_t end_offset);
diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc
deleted file mode 100644
index 9de532fa7b0..00000000000
--- a/sql/ha_isam.cc
+++ /dev/null
@@ -1,402 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include "mysql_priv.h"
-#ifdef HAVE_ISAM
-#include <m_ctype.h>
-#include <myisampack.h>
-#include "ha_isam.h"
-#ifndef MASTER
-#include "../srclib/isam/isamdef.h"
-#else
-#include "../isam/isamdef.h"
-#endif
-
-/*****************************************************************************
-** isam tables
-*****************************************************************************/
-
-
-const char **ha_isam::bas_ext() const
-{ static const char *ext[]= { ".ISM",".ISD", NullS }; return ext; }
-
-int ha_isam::open(const char *name, int mode, uint test_if_locked)
-{
- char name_buff[FN_REFLEN];
- if (!(file=nisam_open(fn_format(name_buff,name,"","",2 | 4), mode,
- test_if_locked)))
- return (my_errno ? my_errno : -1);
-
- if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
- test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
- (void) nisam_extra(file,HA_EXTRA_NO_WAIT_LOCK);
- info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
- if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
- (void) nisam_extra(file,HA_EXTRA_WAIT_LOCK);
- if (!table->db_record_offset)
- int_table_flags|=HA_REC_NOT_IN_SEQ;
- return (0);
-}
-
-int ha_isam::close(void)
-{
- return !nisam_close(file) ? 0 : my_errno ? my_errno : -1;
-}
-
-uint ha_isam::min_record_length(uint options) const
-{
- return (options & HA_OPTION_PACK_RECORD) ? 1 : 5;
-}
-
-
-int ha_isam::write_row(byte * buf)
-{
- statistic_increment(ha_write_count,&LOCK_status);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
- if (table->next_number_field && buf == table->record[0])
- update_auto_increment();
- return !nisam_write(file,buf) ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isam::update_row(const byte * old_data, byte * new_data)
-{
- statistic_increment(ha_update_count,&LOCK_status);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
- return !nisam_update(file,old_data,new_data) ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isam::delete_row(const byte * buf)
-{
- statistic_increment(ha_delete_count,&LOCK_status);
- return !nisam_delete(file,buf) ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isam::index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
-{
- statistic_increment(ha_read_key_count,&LOCK_status);
- int error=nisam_rkey(file, buf, active_index, key, key_len, find_flag);
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isam::index_read_idx(byte * buf, uint index, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
-{
- statistic_increment(ha_read_key_count,&LOCK_status);
- int error=nisam_rkey(file, buf, index, key, key_len, find_flag);
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isam::index_read_last(byte * buf, const byte * key, uint key_len)
-{
- statistic_increment(ha_read_key_count,&LOCK_status);
- int error=nisam_rkey(file, buf, active_index, key, key_len,
- HA_READ_PREFIX_LAST);
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isam::index_next(byte * buf)
-{
- statistic_increment(ha_read_next_count,&LOCK_status);
- int error=nisam_rnext(file,buf,active_index);
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
-}
-
-int ha_isam::index_prev(byte * buf)
-{
- statistic_increment(ha_read_prev_count,&LOCK_status);
- int error=nisam_rprev(file,buf, active_index);
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
-}
-
-int ha_isam::index_first(byte * buf)
-{
- statistic_increment(ha_read_first_count,&LOCK_status);
- int error=nisam_rfirst(file, buf, active_index);
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
-}
-
-int ha_isam::index_last(byte * buf)
-{
- statistic_increment(ha_read_last_count,&LOCK_status);
- int error=nisam_rlast(file, buf, active_index);
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
-}
-
-int ha_isam::rnd_init(bool scan)
-{
- return nisam_extra(file,HA_EXTRA_RESET) ? 0 : my_errno ? my_errno : -1;;
-}
-
-int ha_isam::rnd_next(byte *buf)
-{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
- int error=nisam_rrnd(file, buf, NI_POS_ERROR);
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isam::rnd_pos(byte * buf, byte *pos)
-{
- statistic_increment(ha_read_rnd_count,&LOCK_status);
- int error=nisam_rrnd(file, buf, (ulong) ha_get_ptr(pos,ref_length));
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : -1;
-}
-
-void ha_isam::position(const byte *record)
-{
- my_off_t position=nisam_position(file);
- if (position == (my_off_t) ~ (ulong) 0)
- position=HA_OFFSET_ERROR;
- ha_store_ptr(ref, ref_length, position);
-}
-
-void ha_isam::info(uint flag)
-{
- N_ISAMINFO info;
- (void) nisam_info(file,&info,flag);
- if (flag & HA_STATUS_VARIABLE)
- {
- records = info.records;
- deleted = info.deleted;
- data_file_length=info.data_file_length;
- index_file_length=info.index_file_length;
- delete_length = info.delete_length;
- check_time = info.isamchk_time;
- mean_rec_length=info.mean_reclength;
- }
- if (flag & HA_STATUS_CONST)
- {
- max_data_file_length=info.max_data_file_length;
- max_index_file_length=info.max_index_file_length;
- create_time = info.create_time;
- sortkey = info.sortkey;
- block_size=nisam_block_size;
- table->keys = min(table->keys,info.keys);
- table->keys_in_use.set_prefix(table->keys);
- table->db_options_in_use= info.options;
- table->db_record_offset=
- (table->db_options_in_use &
- (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? 0 :
- table->reclength;
- if (!table->tmp_table)
- {
- ulong *rec_per_key=info.rec_per_key;
- for (uint i=0 ; i < table->keys ; i++)
- {
- table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]=
- *(rec_per_key++);
- }
- }
- ref_length=4;
- }
- if (flag & HA_STATUS_ERRKEY)
- {
- errkey = info.errkey;
- ha_store_ptr(dupp_ref, ref_length, info.dupp_key_pos);
- }
- if (flag & HA_STATUS_TIME)
- update_time = info.update_time;
-}
-
-
-int ha_isam::extra(enum ha_extra_function operation)
-{
- if ((specialflag & SPECIAL_SAFE_MODE || test_flags & TEST_NO_EXTRA) &&
- (operation == HA_EXTRA_WRITE_CACHE ||
- operation == HA_EXTRA_KEYREAD))
- return 0;
- return nisam_extra(file,operation);
-}
-
-int ha_isam::external_lock(THD *thd, int lock_type)
-{
- if (!table->tmp_table)
- return nisam_lock_database(file,lock_type);
- return 0;
-}
-
-
-THR_LOCK_DATA **ha_isam::store_lock(THD *thd,
- THR_LOCK_DATA **to,
- enum thr_lock_type lock_type)
-{
- if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
- file->lock.type=lock_type;
- *to++= &file->lock;
- return to;
-}
-
-
-int ha_isam::create(const char *name, register TABLE *form,
- HA_CREATE_INFO *create_info)
-
-{
- uint options=form->db_options_in_use;
- int error;
- uint i,j,recpos,minpos,fieldpos,temp_length,length;
- enum ha_base_keytype type;
- char buff[FN_REFLEN];
- KEY *pos;
- N_KEYDEF keydef[MAX_KEY];
- N_RECINFO *recinfo,*recinfo_pos;
- DBUG_ENTER("ha_isam::create");
-
- type=HA_KEYTYPE_BINARY; // Keep compiler happy
- if (!(recinfo= (N_RECINFO*) my_malloc((form->fields*2+2)*sizeof(N_RECINFO),
- MYF(MY_WME))))
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
-
- pos=form->key_info;
- for (i=0; i < form->keys ; i++, pos++)
- {
- keydef[i].base.flag= (pos->flags & HA_NOSAME);
- for (j=0 ; (int7) j < pos->key_parts ; j++)
- {
- keydef[i].seg[j].base.flag=pos->key_part[j].key_part_flag;
- Field *field=pos->key_part[j].field;
- type=field->key_type();
-
- if ((options & HA_OPTION_PACK_KEYS ||
- (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
- HA_SPACE_PACK_USED))) &&
- pos->key_part[j].length > 8 &&
- (type == HA_KEYTYPE_TEXT ||
- type == HA_KEYTYPE_NUM ||
- (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
- {
- if (j == 0)
- keydef[i].base.flag|=HA_PACK_KEY;
- if (!(field->flags & ZEROFILL_FLAG) &&
- (field->type() == FIELD_TYPE_STRING ||
- field->type() == FIELD_TYPE_VAR_STRING ||
- ((int) (pos->key_part[j].length - field->decimals()))
- >= 4))
- keydef[i].seg[j].base.flag|=HA_SPACE_PACK;
- }
- keydef[i].seg[j].base.type=(int) type;
- keydef[i].seg[j].base.start= pos->key_part[j].offset;
- keydef[i].seg[j].base.length= pos->key_part[j].length;
- }
- keydef[i].seg[j].base.type=(int) HA_KEYTYPE_END; /* End of key-parts */
- }
-
- recpos=0; recinfo_pos=recinfo;
- while (recpos < (uint) form->reclength)
- {
- Field **field,*found=0;
- minpos=form->reclength; length=0;
-
- for (field=form->field ; *field ; field++)
- {
- if ((fieldpos=(*field)->offset()) >= recpos &&
- fieldpos <= minpos)
- {
- /* skip null fields */
- if (!(temp_length= (*field)->pack_length()))
- continue; /* Skip null-fields */
- if (! found || fieldpos < minpos ||
- (fieldpos == minpos && temp_length < length))
- {
- minpos=fieldpos; found= *field; length=temp_length;
- }
- }
- }
- DBUG_PRINT("loop",("found: %lx recpos: %d minpos: %d length: %d",
- found,recpos,minpos,length));
- if (recpos != minpos)
- { // Reserved space (Null bits?)
- recinfo_pos->base.type=(int) FIELD_NORMAL;
- recinfo_pos++->base.length= (uint16) (minpos-recpos);
- }
- if (! found)
- break;
-
- if (found->flags & BLOB_FLAG)
- {
- /* ISAM can only handle blob pointers of sizeof(char(*)) */
- recinfo_pos->base.type= (int) FIELD_BLOB;
- if (options & HA_OPTION_LONG_BLOB_PTR)
- length= length-portable_sizeof_char_ptr+sizeof(char*);
- }
- else if (!(options & HA_OPTION_PACK_RECORD))
- recinfo_pos->base.type= (int) FIELD_NORMAL;
- else if (found->zero_pack())
- recinfo_pos->base.type= (int) FIELD_SKIP_ZERO;
- else
- recinfo_pos->base.type= (int) ((length <= 3 ||
- (found->flags & ZEROFILL_FLAG)) ?
- FIELD_NORMAL :
- found->type() == FIELD_TYPE_STRING ||
- found->type() == FIELD_TYPE_VAR_STRING ?
- FIELD_SKIP_ENDSPACE :
- FIELD_SKIP_PRESPACE);
- recinfo_pos++ ->base.length=(uint16) length;
- recpos=minpos+length;
- DBUG_PRINT("loop",("length: %d type: %d",
- recinfo_pos[-1].base.length,recinfo_pos[-1].base.type));
-
- if ((found->flags & BLOB_FLAG) && (options & HA_OPTION_LONG_BLOB_PTR) &&
- sizeof(char*) != portable_sizeof_char_ptr)
- { // Not used space
- recinfo_pos->base.type=(int) FIELD_ZERO;
- recinfo_pos++->base.length=
- (uint16) (portable_sizeof_char_ptr-sizeof(char*));
- recpos+= (portable_sizeof_char_ptr-sizeof(char*));
- }
- }
- recinfo_pos->base.type= (int) FIELD_LAST; /* End of fieldinfo */
- error=nisam_create(fn_format(buff,name,"","",2+4+16),form->keys,keydef,
- recinfo,(ulong) form->max_rows, (ulong) form->min_rows,
- 0, 0, 0L);
- my_free((gptr) recinfo,MYF(0));
- DBUG_RETURN(error);
-
-}
-
-static key_range no_range= { (byte*) 0, 0, HA_READ_KEY_EXACT };
-
-ha_rows ha_isam::records_in_range(uint inx, key_range *min_key,
- key_range *max_key)
-{
- /* ISAM checks if 'key' pointer <> 0 to know if there is no range */
- if (!min_key)
- min_key= &no_range;
- if (!max_key)
- max_key= &no_range;
- return (ha_rows) nisam_records_in_range(file,
- (int) inx,
- min_key->key, min_key->length,
- min_key->flag,
- max_key->key, max_key->length,
- max_key->flag);
-}
-#endif /* HAVE_ISAM */
diff --git a/sql/ha_isam.h b/sql/ha_isam.h
deleted file mode 100644
index b3e932696cb..00000000000
--- a/sql/ha_isam.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-/* class for the the myisam handler */
-
-#include <nisam.h>
-
-class ha_isam: public handler
-{
- N_INFO *file;
- /* We need this as table_flags() may change after open() */
- ulong int_table_flags;
-
- public:
- ha_isam(TABLE *table)
- :handler(table), file(0),
- int_table_flags(HA_READ_RND_SAME |
- HA_DUPP_POS | HA_NOT_DELETE_WITH_CACHE | HA_FILE_BASED)
- {}
- ~ha_isam() {}
- ulong index_flags(uint idx, uint part, bool all_parts) const
- { return HA_READ_NEXT; } // but no HA_READ_PREV here!!!
- const char *table_type() const { return "ISAM"; }
- const char *index_type(uint key_number) { return "BTREE"; }
- const char **bas_ext() const;
- ulong table_flags() const { return int_table_flags; }
- uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
- uint max_supported_keys() const { return N_MAXKEY; }
- uint max_supported_key_parts() const { return N_MAXKEY_SEG; }
- uint max_supported_key_length() const { return N_MAX_KEY_LENGTH; }
- uint min_record_length(uint options) const;
- bool low_byte_first() const { return 0; }
-
- int open(const char *name, int mode, uint test_if_locked);
- int close(void);
- int write_row(byte * buf);
- int update_row(const byte * old_data, byte * new_data);
- int delete_row(const byte * buf);
- int index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
- int index_read_idx(byte * buf, uint idx, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
- int index_read_last(byte * buf, const byte * key, uint key_len);
- int index_next(byte * buf);
- int index_prev(byte * buf);
- int index_first(byte * buf);
- int index_last(byte * buf);
- int rnd_init(bool scan);
- int rnd_next(byte *buf);
- int rnd_pos(byte * buf, byte *pos);
- void position(const byte *record);
- void info(uint);
- int extra(enum ha_extra_function operation);
- int external_lock(THD *thd, int lock_type);
- ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
-
- int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
- THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
- enum thr_lock_type lock_type);
-};
-
diff --git a/sql/ha_isammrg.cc b/sql/ha_isammrg.cc
deleted file mode 100644
index 367607eef19..00000000000
--- a/sql/ha_isammrg.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include "mysql_priv.h"
-#ifdef HAVE_ISAM
-#include <m_ctype.h>
-#ifndef MASTER
-#include "../srclib/merge/mrg_def.h"
-#else
-#include "../merge/mrg_def.h"
-#endif
-#include "ha_isammrg.h"
-
-/*****************************************************************************
-** ISAM MERGE tables
-*****************************************************************************/
-
-const char **ha_isammrg::bas_ext() const
-{ static const char *ext[]= { ".MRG", NullS }; return ext; }
-
-int ha_isammrg::open(const char *name, int mode, uint test_if_locked)
-{
- char name_buff[FN_REFLEN];
- if (!(file=mrg_open(fn_format(name_buff,name,"","",2 | 4), mode,
- test_if_locked)))
- return (my_errno ? my_errno : -1);
-
- if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
- test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
- mrg_extra(file,HA_EXTRA_NO_WAIT_LOCK);
- info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
- if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
- mrg_extra(file,HA_EXTRA_WAIT_LOCK);
- if (table->reclength != mean_rec_length)
- {
- DBUG_PRINT("error",("reclength: %d mean_rec_length: %d",
- table->reclength, mean_rec_length));
- mrg_close(file);
- file=0;
- return ER_WRONG_MRG_TABLE;
- }
- return (0);
-}
-
-int ha_isammrg::close(void)
-{
- return !mrg_close(file) ? 0 : my_errno ? my_errno : -1;
-}
-
-uint ha_isammrg::min_record_length(uint options) const
-{
- return (options & HA_OPTION_PACK_RECORD) ? 1 : 5;
-}
-
-int ha_isammrg::write_row(byte * buf)
-{
- return (my_errno=HA_ERR_WRONG_COMMAND);
-}
-
-int ha_isammrg::update_row(const byte * old_data, byte * new_data)
-{
- statistic_increment(ha_update_count,&LOCK_status);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
- return !mrg_update(file,old_data,new_data) ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isammrg::delete_row(const byte * buf)
-{
- statistic_increment(ha_delete_count,&LOCK_status);
- return !mrg_delete(file,buf) ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isammrg::index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
-{
- return (my_errno=HA_ERR_WRONG_COMMAND);
-}
-
-int ha_isammrg::index_read_idx(byte * buf, uint index, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
-{
- return (my_errno=HA_ERR_WRONG_COMMAND);
-}
-
-int ha_isammrg::index_next(byte * buf)
-{
- return (my_errno=HA_ERR_WRONG_COMMAND);
-}
-
-int ha_isammrg::index_prev(byte * buf)
-{
- return (my_errno=HA_ERR_WRONG_COMMAND);
-}
-
-int ha_isammrg::index_first(byte * buf)
-{
- return (my_errno=HA_ERR_WRONG_COMMAND);
-}
-
-int ha_isammrg::index_last(byte * buf)
-{
- return (my_errno=HA_ERR_WRONG_COMMAND);
-}
-
-int ha_isammrg::rnd_init(bool scan)
-{
- return !mrg_extra(file,HA_EXTRA_RESET) ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isammrg::rnd_next(byte *buf)
-{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
- int error=mrg_rrnd(file, buf, ~(mrg_off_t) 0);
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isammrg::rnd_pos(byte * buf, byte *pos)
-{
- statistic_increment(ha_read_rnd_count,&LOCK_status);
- int error=mrg_rrnd(file, buf, (ulong) ha_get_ptr(pos,ref_length));
- table->status=error ? STATUS_NOT_FOUND: 0;
- return !error ? 0 : my_errno ? my_errno : -1;
-}
-
-void ha_isammrg::position(const byte *record)
-{
- ulong position= mrg_position(file);
- ha_store_ptr(ref, ref_length, (my_off_t) position);
-}
-
-
-void ha_isammrg::info(uint flag)
-{
- MERGE_INFO info;
- (void) mrg_info(file,&info,flag);
- records = (ha_rows) info.records;
- deleted = (ha_rows) info.deleted;
- data_file_length=info.data_file_length;
- errkey = info.errkey;
- table->keys_in_use.clear_all(); // No keys yet
- table->db_options_in_use = info.options;
- mean_rec_length=info.reclength;
- block_size=0;
- update_time=0;
- ref_length=4; // Should be big enough
-}
-
-
-int ha_isammrg::extra(enum ha_extra_function operation)
-{
- return !mrg_extra(file,operation) ? 0 : my_errno ? my_errno : -1;
-}
-
-int ha_isammrg::external_lock(THD *thd, int lock_type)
-{
- return !mrg_lock_database(file,lock_type) ? 0 : my_errno ? my_errno : -1;
-}
-
-uint ha_isammrg::lock_count(void) const
-{
- return file->tables;
-}
-
-THR_LOCK_DATA **ha_isammrg::store_lock(THD *thd,
- THR_LOCK_DATA **to,
- enum thr_lock_type lock_type)
-{
- MRG_TABLE *open_table;
-
- for (open_table=file->open_tables ;
- open_table != file->end_table ;
- open_table++)
- {
- *(to++)= &open_table->table->lock;
- if (lock_type != TL_IGNORE && open_table->table->lock.type == TL_UNLOCK)
- open_table->table->lock.type=lock_type;
- }
- return to;
-}
-
-
-int ha_isammrg::create(const char *name, register TABLE *form,
- HA_CREATE_INFO *create_info)
-
-{
- char buff[FN_REFLEN];
- return mrg_create(fn_format(buff,name,"","",2+4+16),0);
-}
-#endif /* HAVE_ISAM */
diff --git a/sql/ha_isammrg.h b/sql/ha_isammrg.h
deleted file mode 100644
index 657e5060272..00000000000
--- a/sql/ha_isammrg.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-
-#ifdef __GNUC__
-#pragma interface /* gcc class implementation */
-#endif
-
-/* class for the the myisam merge handler */
-
-#include <merge.h>
-
-class ha_isammrg: public handler
-{
- MRG_INFO *file;
-
- public:
- ha_isammrg(TABLE *table): handler(table), file(0) {}
- ~ha_isammrg() {}
- const char *table_type() const { return "MRG_ISAM"; }
- const char **bas_ext() const;
- ulong table_flags() const { return (HA_READ_RND_SAME |
- HA_REC_NOT_IN_SEQ | HA_FILE_BASED); }
- ulong index_flags(uint idx, uint part, bool all_parts) const
- { DBUG_ASSERT(0); return 0; }
-
- uint max_supported_keys() const { return 0; }
- bool low_byte_first() const { return 0; }
- uint min_record_length(uint options) const;
-
- int open(const char *name, int mode, uint test_if_locked);
- int close(void);
- int write_row(byte * buf);
- int update_row(const byte * old_data, byte * new_data);
- int delete_row(const byte * buf);
- int index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
- int index_read_idx(byte * buf, uint indx, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
- int index_next(byte * buf);
- int index_prev(byte * buf);
- int index_first(byte * buf);
- int index_last(byte * buf);
- int rnd_init(bool scan);
- int rnd_next(byte *buf);
- int rnd_pos(byte * buf, byte *pos);
- void position(const byte *record);
- void info(uint);
- int extra(enum ha_extra_function operation);
- int external_lock(THD *thd, int lock_type);
- uint lock_count(void) const;
- int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
- THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
- enum thr_lock_type lock_type);
- uint8 table_cache_type() { return HA_CACHE_TBL_NOCACHE; }
-};
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 7ddb7ca25ed..2049efb73db 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -87,9 +87,10 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
extern "C" {
-volatile my_bool *killed_ptr(MI_CHECK *param)
+volatile int *killed_ptr(MI_CHECK *param)
{
- return &(((THD *)(param->thd))->killed);
+ /* In theory Unsafe conversion, but should be ok for now */
+ return (int*) &(((THD *)(param->thd))->killed);
}
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
@@ -122,8 +123,16 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
}
+static const char *ha_myisam_exts[] = {
+ ".MYI",
+ ".MYD",
+ NullS
+};
+
const char **ha_myisam::bas_ext() const
-{ static const char *ext[]= { ".MYI",".MYD", NullS }; return ext; }
+{
+ return ha_myisam_exts;
+}
const char *ha_myisam::index_type(uint key_number)
@@ -232,7 +241,7 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked)
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0));
- if (!table->db_record_offset)
+ if (!table->s->db_record_offset)
int_table_flags|=HA_REC_NOT_IN_SEQ;
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
int_table_flags|=HA_HAS_CHECKSUM;
@@ -248,7 +257,7 @@ int ha_myisam::close(void)
int ha_myisam::write_row(byte * buf)
{
- statistic_increment(ha_write_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_write_count,&LOCK_status);
/* If we have a timestamp column, update it to the current time */
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
@@ -274,9 +283,9 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
thd->proc_info="Checking table";
myisamchk_init(&param);
param.thd = thd;
- param.op_name = (char*)"check";
- param.db_name = table->table_cache_key;
- param.table_name = table->table_name;
+ param.op_name = "check";
+ param.db_name= table->s->db;
+ param.table_name= table->alias;
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
if (!(table->db_stat & HA_READ_ONLY))
@@ -361,11 +370,11 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
myisamchk_init(&param);
param.thd = thd;
- param.op_name = (char*) "analyze";
- param.db_name = table->table_cache_key;
- param.table_name = table->table_name;
- param.testflag=(T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
- T_DONT_CHECK_CHECKSUM);
+ param.op_name= "analyze";
+ param.db_name= table->s->db;
+ param.table_name= table->alias;
+ param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
+ T_DONT_CHECK_CHECKSUM);
param.using_global_keycache = 1;
if (!(share->state.changed & STATE_NOT_ANALYZED))
@@ -387,9 +396,9 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
{
HA_CHECK_OPT tmp_check_opt;
- char* backup_dir= thd->lex->backup_dir;
+ char *backup_dir= thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- char* table_name = table->real_name;
+ const char *table_name= table->s->table_name;
int error;
const char* errmsg;
DBUG_ENTER("restore");
@@ -398,11 +407,11 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
MI_NAME_DEXT))
DBUG_RETURN(HA_ADMIN_INVALID);
- if (my_copy(src_path, fn_format(dst_path, table->path, "",
+ if (my_copy(src_path, fn_format(dst_path, table->s->path, "",
MI_NAME_DEXT, 4), MYF(MY_WME)))
{
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in my_copy (Error %d)";
+ error= HA_ADMIN_FAILED;
+ errmsg= "Failed in my_copy (Error %d)";
goto err;
}
@@ -414,11 +423,11 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
{
MI_CHECK param;
myisamchk_init(&param);
- param.thd = thd;
- param.op_name = (char*)"restore";
- param.db_name = table->table_cache_key;
- param.table_name = table->table_name;
- param.testflag = 0;
+ param.thd= thd;
+ param.op_name= "restore";
+ param.db_name= table->s->db;
+ param.table_name= table->s->table_name;
+ param.testflag= 0;
mi_check_print_error(&param, errmsg, my_errno);
DBUG_RETURN(error);
}
@@ -427,9 +436,9 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
{
- char* backup_dir= thd->lex->backup_dir;
+ char *backup_dir= thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- char* table_name = table->real_name;
+ const char *table_name= table->s->table_name;
int error;
const char *errmsg;
DBUG_ENTER("ha_myisam::backup");
@@ -437,12 +446,13 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir,
reg_ext))
{
- errmsg = "Failed in fn_format() for .frm file (errno: %d)";
- error = HA_ADMIN_INVALID;
+ errmsg= "Failed in fn_format() for .frm file (errno: %d)";
+ error= HA_ADMIN_INVALID;
goto err;
}
- if (my_copy(fn_format(src_path, table->path,"", reg_ext, MY_UNPACK_FILENAME),
+ if (my_copy(fn_format(src_path, table->s->path, "", reg_ext,
+ MY_UNPACK_FILENAME),
dst_path,
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_DONT_OVERWRITE_FILE)))
{
@@ -460,7 +470,7 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
goto err;
}
- if (my_copy(fn_format(src_path, table->path,"", MI_NAME_DEXT,
+ if (my_copy(fn_format(src_path, table->s->path, "", MI_NAME_DEXT,
MY_UNPACK_FILENAME),
dst_path,
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_DONT_OVERWRITE_FILE)))
@@ -475,11 +485,11 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
{
MI_CHECK param;
myisamchk_init(&param);
- param.thd = thd;
- param.op_name = (char*)"backup";
- param.db_name = table->table_cache_key;
- param.table_name = table->table_name;
- param.testflag = 0;
+ param.thd= thd;
+ param.op_name= "backup";
+ param.db_name= table->s->db;
+ param.table_name= table->s->table_name;
+ param.testflag = 0;
mi_check_print_error(&param,errmsg, my_errno);
DBUG_RETURN(error);
}
@@ -496,10 +506,10 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
myisamchk_init(&param);
param.thd = thd;
- param.op_name = (char*) "repair";
- param.testflag = ((check_opt->flags & ~(T_EXTEND)) |
- T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
- (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
+ param.op_name= "repair";
+ param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
+ T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
+ (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
param.sort_buffer_length= check_opt->sort_buffer_size;
start_records=file->state->records;
while ((error=repair(thd,param,0)) && param.retry_repair)
@@ -510,7 +520,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
{
param.testflag&= ~T_RETRY_WITHOUT_QUICK;
sql_print_information("Retrying repair of: '%s' without quick",
- table->path);
+ table->s->path);
continue;
}
param.testflag&= ~T_QUICK;
@@ -518,7 +528,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
{
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
sql_print_information("Retrying repair of: '%s' with keycache",
- table->path);
+ table->s->path);
continue;
}
break;
@@ -530,7 +540,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
sql_print_information("Found %s of %s rows when repairing '%s'",
llstr(file->state->records, llbuff),
llstr(start_records, llbuff2),
- table->path);
+ table->s->path);
}
return error;
}
@@ -543,9 +553,9 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
myisamchk_init(&param);
param.thd = thd;
- param.op_name = (char*) "optimize";
- param.testflag = (check_opt->flags | T_SILENT | T_FORCE_CREATE |
- T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
+ param.op_name= "optimize";
+ param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
+ T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
param.sort_buffer_length= check_opt->sort_buffer_size;
if ((error= repair(thd,param,1)) && param.retry_repair)
{
@@ -569,18 +579,18 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
ha_rows rows= file->state->records;
DBUG_ENTER("ha_myisam::repair");
- param.db_name = table->table_cache_key;
- param.table_name = table->table_name;
+ param.db_name= table->s->db;
+ param.table_name= table->alias;
param.tmpfile_createflag = O_RDWR | O_TRUNC;
param.using_global_keycache = 1;
- param.thd=thd;
- param.tmpdir=&mysql_tmpdir_list;
- param.out_flag=0;
+ param.thd= thd;
+ param.tmpdir= &mysql_tmpdir_list;
+ param.out_flag= 0;
strmov(fixed_name,file->filename);
// Don't lock tables if we have used LOCK TABLE
if (!thd->locked_tables &&
- mi_lock_database(file, table->tmp_table ? F_EXTRA_LCK : F_WRLCK))
+ mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
{
mi_check_print_error(&param,ER(ER_CANT_LOCK),my_errno);
DBUG_RETURN(HA_ADMIN_FAILED);
@@ -601,7 +611,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
local_testflag|= T_STATISTICS;
param.testflag|= T_STATISTICS; // We get this for free
statistics_done=1;
- if (current_thd->variables.myisam_repair_threads>1)
+ if (thd->variables.myisam_repair_threads>1)
{
char buf[40];
/* TODO: respect myisam_repair_threads variable */
@@ -725,7 +735,7 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
{
- char buf[80];
+ char buf[STRING_BUFFER_USUAL_SIZE];
my_snprintf(buf, sizeof(buf),
"Failed to flush to index file (errno: %d)", error);
errmsg= buf;
@@ -739,9 +749,9 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
MI_CHECK param;
myisamchk_init(&param);
param.thd= thd;
- param.op_name= (char*)"assign_to_keycache";
- param.db_name= table->table_cache_key;
- param.table_name= table->table_name;
+ param.op_name= "assign_to_keycache";
+ param.db_name= table->s->db;
+ param.table_name= table->s->table_name;
param.testflag= 0;
mi_check_print_error(&param, errmsg);
}
@@ -807,10 +817,10 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
MI_CHECK param;
myisamchk_init(&param);
param.thd= thd;
- param.op_name= (char*)"preload_keys";
- param.db_name= table->table_cache_key;
- param.table_name= table->table_name;
- param.testflag= 0;
+ param.op_name= "preload_keys";
+ param.db_name= table->s->db;
+ param.table_name= table->s->table_name;
+ param.testflag= 0;
mi_check_print_error(&param, errmsg);
DBUG_RETURN(error);
}
@@ -915,9 +925,9 @@ int ha_myisam::enable_indexes(uint mode)
const char *save_proc_info=thd->proc_info;
thd->proc_info="Creating index";
myisamchk_init(&param);
- param.op_name = (char*) "recreating_index";
- param.testflag = (T_SILENT | T_REP_BY_SORT | T_QUICK |
- T_CREATE_MISSING_KEYS);
+ param.op_name= "recreating_index";
+ param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
+ T_CREATE_MISSING_KEYS);
param.myf_rw&= ~MY_WAIT_IF_FULL;
param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
param.tmpdir=&mysql_tmpdir_list;
@@ -925,8 +935,11 @@ int ha_myisam::enable_indexes(uint mode)
{
sql_print_warning("Warning: Enabling keys got errno %d, retrying",
my_errno);
+ thd->clear_error();
param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
error= (repair(thd,param,0) != HA_ADMIN_OK);
+ if (!error && thd->net.report_error)
+ error= HA_ERR_CRASHED;
}
info(HA_STATUS_CONST);
thd->proc_info=save_proc_info;
@@ -979,8 +992,9 @@ int ha_myisam::indexes_are_disabled(void)
void ha_myisam::start_bulk_insert(ha_rows rows)
{
DBUG_ENTER("ha_myisam::start_bulk_insert");
- THD *thd=current_thd;
- ulong size= min(thd->variables.read_buff_size, table->avg_row_length*rows);
+ THD *thd= current_thd;
+ ulong size= min(thd->variables.read_buff_size,
+ table->s->avg_row_length*rows);
DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu",
(ulong) rows, size));
@@ -1048,18 +1062,18 @@ bool ha_myisam::check_and_repair(THD *thd)
// Don't use quick if deleted rows
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
check_opt.flags|=T_QUICK;
- sql_print_warning("Checking table: '%s'",table->path);
+ sql_print_warning("Checking table: '%s'",table->s->path);
old_query= thd->query;
old_query_length= thd->query_length;
pthread_mutex_lock(&LOCK_thread_count);
- thd->query= table->real_name;
- thd->query_length= strlen(table->real_name);
+ thd->query= (char*) table->s->table_name;
+ thd->query_length= strlen(table->s->table_name);
pthread_mutex_unlock(&LOCK_thread_count);
if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
{
- sql_print_warning("Recovering table: '%s'",table->path);
+ sql_print_warning("Recovering table: '%s'",table->s->path);
check_opt.flags=
((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
(marked_crashed ? 0 : T_QUICK) |
@@ -1083,7 +1097,7 @@ bool ha_myisam::is_crashed() const
int ha_myisam::update_row(const byte * old_data, byte * new_data)
{
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_update_count,&LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return mi_update(file,old_data,new_data);
@@ -1091,7 +1105,7 @@ int ha_myisam::update_row(const byte * old_data, byte * new_data)
int ha_myisam::delete_row(const byte * buf)
{
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
return mi_delete(file,buf);
}
@@ -1099,7 +1113,8 @@ int ha_myisam::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
int error=mi_rkey(file,buf,active_index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1108,7 +1123,8 @@ int ha_myisam::index_read(byte * buf, const byte * key,
int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
int error=mi_rkey(file,buf,index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1117,7 +1133,8 @@ int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
int ha_myisam::index_read_last(byte * buf, const byte * key, uint key_len)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
int error=mi_rkey(file,buf,active_index, key, key_len, HA_READ_PREFIX_LAST);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1126,7 +1143,8 @@ int ha_myisam::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_myisam::index_next(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
int error=mi_rnext(file,buf,active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1135,7 +1153,8 @@ int ha_myisam::index_next(byte * buf)
int ha_myisam::index_prev(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_prev_count,
+ &LOCK_status);
int error=mi_rprev(file,buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1144,7 +1163,8 @@ int ha_myisam::index_prev(byte * buf)
int ha_myisam::index_first(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_first_count,
+ &LOCK_status);
int error=mi_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1153,7 +1173,8 @@ int ha_myisam::index_first(byte * buf)
int ha_myisam::index_last(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_last_count,
+ &LOCK_status);
int error=mi_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1164,7 +1185,8 @@ int ha_myisam::index_next_same(byte * buf,
uint length __attribute__((unused)))
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
int error=mi_rnext_same(file,buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1180,7 +1202,8 @@ int ha_myisam::rnd_init(bool scan)
int ha_myisam::rnd_next(byte *buf)
{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
int error=mi_scan(file, buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1193,8 +1216,9 @@ int ha_myisam::restart_rnd_next(byte *buf, byte *pos)
int ha_myisam::rnd_pos(byte * buf, byte *pos)
{
- statistic_increment(ha_read_rnd_count,&LOCK_status);
- int error=mi_rrnd(file, buf, ha_get_ptr(pos,ref_length));
+ statistic_increment(table->in_use->status_var.ha_read_rnd_count,
+ &LOCK_status);
+ int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
@@ -1202,7 +1226,7 @@ int ha_myisam::rnd_pos(byte * buf, byte *pos)
void ha_myisam::position(const byte* record)
{
my_off_t position=mi_position(file);
- ha_store_ptr(ref, ref_length, position);
+ my_store_ptr(ref, ref_length, position);
}
void ha_myisam::info(uint flag)
@@ -1223,25 +1247,25 @@ void ha_myisam::info(uint flag)
}
if (flag & HA_STATUS_CONST)
{
- max_data_file_length=info.max_data_file_length;
- max_index_file_length=info.max_index_file_length;
- create_time = info.create_time;
- sortkey = info.sortkey;
- ref_length=info.reflength;
- table->db_options_in_use = info.options;
- block_size=myisam_block_size;
- table->keys_in_use.set_prefix(table->keys);
- table->keys_in_use.intersect(info.key_map);
- table->keys_for_keyread= table->keys_in_use;
- table->keys_for_keyread.subtract(table->read_only_keys);
- table->db_record_offset=info.record_offset;
- if (table->key_parts)
+ TABLE_SHARE *share= table->s;
+ max_data_file_length= info.max_data_file_length;
+ max_index_file_length= info.max_index_file_length;
+ create_time= info.create_time;
+ sortkey= info.sortkey;
+ ref_length= info.reflength;
+ share->db_options_in_use= info.options;
+ block_size= myisam_block_size;
+ share->keys_in_use.set_prefix(share->keys);
+ share->keys_in_use.intersect(info.key_map);
+ share->keys_for_keyread.intersect(share->keys_in_use);
+ share->db_record_offset= info.record_offset;
+ if (share->key_parts)
memcpy((char*) table->key_info[0].rec_per_key,
(char*) info.rec_per_key,
- sizeof(table->key_info[0].rec_per_key)*table->key_parts);
- raid_type=info.raid_type;
- raid_chunks=info.raid_chunks;
- raid_chunksize=info.raid_chunksize;
+ sizeof(table->key_info[0].rec_per_key)*share->key_parts);
+ raid_type= info.raid_type;
+ raid_chunks= info.raid_chunks;
+ raid_chunksize= info.raid_chunksize;
/*
Set data_file_name and index_file_name to point at the symlink value
@@ -1258,7 +1282,7 @@ void ha_myisam::info(uint flag)
if (flag & HA_STATUS_ERRKEY)
{
errkey = info.errkey;
- ha_store_ptr(dupp_ref, ref_length, info.dupp_key_pos);
+ my_store_ptr(dupp_ref, ref_length, info.dupp_key_pos);
}
if (flag & HA_STATUS_TIME)
update_time = info.update_time;
@@ -1297,7 +1321,7 @@ int ha_myisam::delete_table(const char *name)
int ha_myisam::external_lock(THD *thd, int lock_type)
{
- return mi_lock_database(file, !table->tmp_table ?
+ return mi_lock_database(file, !table->s->tmp_table ?
lock_type : ((lock_type == F_UNLCK) ?
F_UNLCK : F_EXTRA_LCK));
}
@@ -1342,21 +1366,23 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
MI_KEYDEF *keydef;
MI_COLUMNDEF *recinfo,*recinfo_pos;
HA_KEYSEG *keyseg;
- uint options=table_arg->db_options_in_use;
+ TABLE_SHARE *share= table->s;
+ uint options= share->db_options_in_use;
DBUG_ENTER("ha_myisam::create");
type=HA_KEYTYPE_BINARY; // Keep compiler happy
if (!(my_multi_malloc(MYF(MY_WME),
- &recinfo,(table_arg->fields*2+2)*sizeof(MI_COLUMNDEF),
- &keydef, table_arg->keys*sizeof(MI_KEYDEF),
+ &recinfo,(share->fields*2+2)*
+ sizeof(MI_COLUMNDEF),
+ &keydef, share->keys*sizeof(MI_KEYDEF),
&keyseg,
- ((table_arg->key_parts + table_arg->keys) *
+ ((share->key_parts + share->keys) *
sizeof(HA_KEYSEG)),
NullS)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
pos=table_arg->key_info;
- for (i=0; i < table_arg->keys ; i++, pos++)
+ for (i=0; i < share->keys ; i++, pos++)
{
keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL));
keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ?
@@ -1366,9 +1392,9 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
keydef[i].keysegs=pos->key_parts;
for (j=0 ; j < pos->key_parts ; j++)
{
- keydef[i].seg[j].flag=pos->key_part[j].key_part_flag;
Field *field=pos->key_part[j].field;
type=field->key_type();
+ keydef[i].seg[j].flag=pos->key_part[j].key_part_flag;
if (options & HA_OPTION_PACK_KEYS ||
(pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
@@ -1383,8 +1409,8 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
if (j == 0)
keydef[i].flag|=HA_PACK_KEY;
if (!(field->flags & ZEROFILL_FLAG) &&
- (field->type() == FIELD_TYPE_STRING ||
- field->type() == FIELD_TYPE_VAR_STRING ||
+ (field->type() == MYSQL_TYPE_STRING ||
+ field->type() == MYSQL_TYPE_VAR_STRING ||
((int) (pos->key_part[j].length - field->decimals()))
>= 4))
keydef[i].seg[j].flag|=HA_SPACE_PACK;
@@ -1395,8 +1421,10 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
keydef[i].seg[j].type= (int) type;
keydef[i].seg[j].start= pos->key_part[j].offset;
keydef[i].seg[j].length= pos->key_part[j].length;
- keydef[i].seg[j].bit_start=keydef[i].seg[j].bit_end=0;
- keydef[i].seg[j].language = field->charset()->number;
+ keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end=
+ keydef[i].seg[j].bit_length= 0;
+ keydef[i].seg[j].bit_pos= 0;
+ keydef[i].seg[j].language= field->charset()->number;
if (field->null_ptr)
{
@@ -1415,7 +1443,14 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
keydef[i].seg[j].flag|=HA_BLOB_PART;
/* save number of bytes used to pack length */
keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
- table_arg->blob_ptr_size);
+ share->blob_ptr_size);
+ }
+ else if (field->type() == FIELD_TYPE_BIT)
+ {
+ keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len;
+ keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs;
+ keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr -
+ (uchar*) table_arg->record[0]);
}
}
keyseg+=pos->key_parts;
@@ -1423,15 +1458,16 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
if (table_arg->found_next_number_field)
{
- keydef[table_arg->next_number_index].flag|= HA_AUTO_KEY;
- found_real_auto_increment= table_arg->next_number_key_offset == 0;
+ keydef[share->next_number_index].flag|= HA_AUTO_KEY;
+ found_real_auto_increment= share->next_number_key_offset == 0;
}
recpos=0; recinfo_pos=recinfo;
- while (recpos < (uint) table_arg->reclength)
+ while (recpos < (uint) share->reclength)
{
Field **field,*found=0;
- minpos=table_arg->reclength; length=0;
+ minpos= share->reclength;
+ length=0;
for (field=table_arg->field ; *field ; field++)
{
@@ -1439,7 +1475,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
fieldpos <= minpos)
{
/* skip null fields */
- if (!(temp_length= (*field)->pack_length()))
+ if (!(temp_length= (*field)->pack_length_in_rec()))
continue; /* Skip null-fields */
if (! found || fieldpos < minpos ||
(fieldpos == minpos && temp_length < length))
@@ -1448,7 +1484,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
}
}
}
- DBUG_PRINT("loop",("found: %lx recpos: %d minpos: %d length: %d",
+ DBUG_PRINT("loop",("found: 0x%lx recpos: %d minpos: %d length: %d",
found,recpos,minpos,length));
if (recpos != minpos)
{ // Reserved space (Null bits?)
@@ -1460,33 +1496,33 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
break;
if (found->flags & BLOB_FLAG)
- {
recinfo_pos->type= (int) FIELD_BLOB;
- }
+ else if (found->type() == MYSQL_TYPE_VARCHAR)
+ recinfo_pos->type= FIELD_VARCHAR;
else if (!(options & HA_OPTION_PACK_RECORD))
recinfo_pos->type= (int) FIELD_NORMAL;
else if (found->zero_pack())
recinfo_pos->type= (int) FIELD_SKIP_ZERO;
else
recinfo_pos->type= (int) ((length <= 3 ||
- (found->flags & ZEROFILL_FLAG)) ?
- FIELD_NORMAL :
- found->type() == FIELD_TYPE_STRING ||
- found->type() == FIELD_TYPE_VAR_STRING ?
- FIELD_SKIP_ENDSPACE :
- FIELD_SKIP_PRESPACE);
+ (found->flags & ZEROFILL_FLAG)) ?
+ FIELD_NORMAL :
+ found->type() == MYSQL_TYPE_STRING ||
+ found->type() == MYSQL_TYPE_VAR_STRING ?
+ FIELD_SKIP_ENDSPACE :
+ FIELD_SKIP_PRESPACE);
if (found->null_ptr)
{
recinfo_pos->null_bit=found->null_bit;
recinfo_pos->null_pos= (uint) (found->null_ptr-
- (uchar*) table_arg->record[0]);
+ (uchar*) table_arg->record[0]);
}
else
{
recinfo_pos->null_bit=0;
recinfo_pos->null_pos=0;
}
- (recinfo_pos++) ->length=(uint16) length;
+ (recinfo_pos++)->length= (uint16) length;
recpos=minpos+length;
DBUG_PRINT("loop",("length: %d type: %d",
recinfo_pos[-1].length,recinfo_pos[-1].type));
@@ -1494,21 +1530,21 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
}
MI_CREATE_INFO create_info;
bzero((char*) &create_info,sizeof(create_info));
- create_info.max_rows=table_arg->max_rows;
- create_info.reloc_rows=table_arg->min_rows;
+ create_info.max_rows= share->max_rows;
+ create_info.reloc_rows= share->min_rows;
create_info.with_auto_increment=found_real_auto_increment;
create_info.auto_increment=(info->auto_increment_value ?
info->auto_increment_value -1 :
(ulonglong) 0);
- create_info.data_file_length= ((ulonglong) table_arg->max_rows *
- table_arg->avg_row_length);
+ create_info.data_file_length= ((ulonglong) share->max_rows *
+ share->avg_row_length);
create_info.raid_type=info->raid_type;
create_info.raid_chunks= (info->raid_chunks ? info->raid_chunks :
RAID_DEFAULT_CHUNKS);
- create_info.raid_chunksize=(info->raid_chunksize ? info->raid_chunksize :
- RAID_DEFAULT_CHUNKSIZE);
- create_info.data_file_name= info->data_file_name;
- create_info.index_file_name=info->index_file_name;
+ create_info.raid_chunksize= (info->raid_chunksize ? info->raid_chunksize :
+ RAID_DEFAULT_CHUNKSIZE);
+ create_info.data_file_name= info->data_file_name;
+ create_info.index_file_name= info->index_file_name;
if (info->options & HA_LEX_CREATE_TMP_TABLE)
create_flags|= HA_CREATE_TMP_TABLE;
@@ -1521,7 +1557,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
/* TODO: Check that the following fn_format is really needed */
error=mi_create(fn_format(buff,name,"","",2+4),
- table_arg->keys,keydef,
+ share->keys,keydef,
(uint) (recinfo_pos-recinfo), recinfo,
0, (MI_UNIQUEDEF*) 0,
&create_info, create_flags);
@@ -1537,30 +1573,35 @@ int ha_myisam::rename_table(const char * from, const char * to)
}
-longlong ha_myisam::get_auto_increment()
+ulonglong ha_myisam::get_auto_increment()
{
- if (!table->next_number_key_offset)
+ ulonglong nr;
+ int error;
+ byte key[MI_MAX_KEY_LENGTH];
+
+ if (!table->s->next_number_key_offset)
{ // Autoincrement at key-start
ha_myisam::info(HA_STATUS_AUTO);
return auto_increment_value;
}
/* it's safe to call the following if bulk_insert isn't on */
- mi_flush_bulk_insert(file, table->next_number_index);
+ mi_flush_bulk_insert(file, table->s->next_number_index);
- longlong nr;
- int error;
- byte key[MI_MAX_KEY_LENGTH];
(void) extra(HA_EXTRA_KEYREAD);
- key_copy(key,table,table->next_number_index,
- table->next_number_key_offset);
- error=mi_rkey(file,table->record[1],(int) table->next_number_index,
- key,table->next_number_key_offset,HA_READ_PREFIX_LAST);
+ key_copy(key, table->record[0],
+ table->key_info + table->s->next_number_index,
+ table->s->next_number_key_offset);
+ error= mi_rkey(file,table->record[1],(int) table->s->next_number_index,
+ key,table->s->next_number_key_offset,HA_READ_PREFIX_LAST);
if (error)
- nr=1;
+ nr= 1;
else
- nr=(longlong)
- table->next_number_field->val_int_offset(table->rec_buff_length)+1;
+ {
+ /* Get data from record[1] */
+ nr= ((ulonglong) table->next_number_field->
+ val_int_offset(table->s->rec_buff_length)+1);
+ }
extra(HA_EXTRA_NO_KEYREAD);
return nr;
}
@@ -1605,7 +1646,8 @@ int ha_myisam::ft_read(byte * buf)
if (!ft_handler)
return -1;
- thread_safe_increment(ha_read_next_count,&LOCK_status); // why ?
+ thread_safe_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status); // why ?
error=ft_handler->please->read_next(ft_handler,(char*) buf);
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index 1e6cf2f4ada..7e14a3b7941 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -47,7 +47,7 @@ class ha_myisam: public handler
int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME |
- HA_CAN_INSERT_DELAYED),
+ HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD),
can_enable_indexes(1)
{}
~ha_myisam() {}
@@ -115,7 +115,7 @@ class ha_myisam: public handler
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
- longlong get_auto_increment();
+ ulonglong get_auto_increment();
int rename_table(const char * from, const char * to);
int delete_table(const char *name);
int check(THD* thd, HA_CHECK_OPT* check_opt);
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index 7a5d4fcf0a1..f7c0abf9810 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -32,8 +32,16 @@
** MyISAM MERGE tables
*****************************************************************************/
+static const char *ha_myisammrg_exts[] = {
+ ".MRG",
+ NullS
+};
+
const char **ha_myisammrg::bas_ext() const
-{ static const char *ext[]= { ".MRG", NullS }; return ext; }
+{
+ return ha_myisammrg_exts;
+}
+
const char *ha_myisammrg::index_type(uint key_number)
{
@@ -67,15 +75,15 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked)
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
myrg_extra(file,HA_EXTRA_WAIT_LOCK,0);
- if (table->reclength != mean_rec_length && mean_rec_length)
+ if (table->s->reclength != mean_rec_length && mean_rec_length)
{
DBUG_PRINT("error",("reclength: %d mean_rec_length: %d",
- table->reclength, mean_rec_length));
+ table->s->reclength, mean_rec_length));
goto err;
}
#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
/* Merge table has more than 2G rows */
- if (table->crashed)
+ if (table->s->crashed)
goto err;
#endif
return (0);
@@ -92,7 +100,7 @@ int ha_myisammrg::close(void)
int ha_myisammrg::write_row(byte * buf)
{
- statistic_increment(ha_write_count,&LOCK_status);
+ 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();
if (table->next_number_field && buf == table->record[0])
@@ -102,7 +110,7 @@ int ha_myisammrg::write_row(byte * buf)
int ha_myisammrg::update_row(const byte * old_data, byte * new_data)
{
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_update_count,&LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return myrg_update(file,old_data,new_data);
@@ -110,14 +118,15 @@ int ha_myisammrg::update_row(const byte * old_data, byte * new_data)
int ha_myisammrg::delete_row(const byte * buf)
{
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
return myrg_delete(file,buf);
}
int ha_myisammrg::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
int error=myrg_rkey(file,buf,active_index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -126,7 +135,8 @@ int ha_myisammrg::index_read(byte * buf, const byte * key,
int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
int error=myrg_rkey(file,buf,index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -134,7 +144,8 @@ int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key,
int ha_myisammrg::index_read_last(byte * buf, const byte * key, uint key_len)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
int error=myrg_rkey(file,buf,active_index, key, key_len,
HA_READ_PREFIX_LAST);
table->status=error ? STATUS_NOT_FOUND: 0;
@@ -143,7 +154,8 @@ int ha_myisammrg::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_myisammrg::index_next(byte * buf)
{
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
int error=myrg_rnext(file,buf,active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -151,7 +163,8 @@ int ha_myisammrg::index_next(byte * buf)
int ha_myisammrg::index_prev(byte * buf)
{
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_prev_count,
+ &LOCK_status);
int error=myrg_rprev(file,buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -159,7 +172,8 @@ int ha_myisammrg::index_prev(byte * buf)
int ha_myisammrg::index_first(byte * buf)
{
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_first_count,
+ &LOCK_status);
int error=myrg_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -167,7 +181,8 @@ int ha_myisammrg::index_first(byte * buf)
int ha_myisammrg::index_last(byte * buf)
{
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_last_count,
+ &LOCK_status);
int error=myrg_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -177,7 +192,8 @@ int ha_myisammrg::index_next_same(byte * buf,
const byte *key __attribute__((unused)),
uint length __attribute__((unused)))
{
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
int error=myrg_rnext_same(file,buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -190,7 +206,8 @@ int ha_myisammrg::rnd_init(bool scan)
int ha_myisammrg::rnd_next(byte *buf)
{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -198,8 +215,9 @@ int ha_myisammrg::rnd_next(byte *buf)
int ha_myisammrg::rnd_pos(byte * buf, byte *pos)
{
- statistic_increment(ha_read_rnd_count,&LOCK_status);
- int error=myrg_rrnd(file, buf, ha_get_ptr(pos,ref_length));
+ statistic_increment(table->in_use->status_var.ha_read_rnd_count,
+ &LOCK_status);
+ int error=myrg_rrnd(file, buf, my_get_ptr(pos,ref_length));
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
@@ -207,7 +225,7 @@ int ha_myisammrg::rnd_pos(byte * buf, byte *pos)
void ha_myisammrg::position(const byte *record)
{
ulonglong position= myrg_position(file);
- ha_store_ptr(ref, ref_length, (my_off_t) position);
+ my_store_ptr(ref, ref_length, (my_off_t) position);
}
@@ -231,14 +249,14 @@ void ha_myisammrg::info(uint flag)
#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
if ((info.records >= (ulonglong) 1 << 32) ||
(info.deleted >= (ulonglong) 1 << 32))
- table->crashed=1;
+ table->s->crashed= 1;
#endif
data_file_length=info.data_file_length;
errkey = info.errkey;
- table->keys_in_use.set_prefix(table->keys);
- table->db_options_in_use = info.options;
- table->is_view=1;
- mean_rec_length=info.reclength;
+ table->s->keys_in_use.set_prefix(table->s->keys);
+ table->s->db_options_in_use= info.options;
+ table->s->is_view= 1;
+ mean_rec_length= info.reclength;
block_size=0;
update_time=0;
#if SIZEOF_OFF_T > 4
@@ -248,10 +266,10 @@ void ha_myisammrg::info(uint flag)
#endif
if (flag & HA_STATUS_CONST)
{
- if (table->key_parts && info.rec_per_key)
+ if (table->s->key_parts && info.rec_per_key)
memcpy((char*) table->key_info[0].rec_per_key,
(char*) info.rec_per_key,
- sizeof(table->key_info[0].rec_per_key)*table->key_parts);
+ sizeof(table->key_info[0].rec_per_key)*table->s->key_parts);
}
}
@@ -351,14 +369,14 @@ void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
goto err;
split_file_name(open_table->table->filename, &db, &name);
- if (!(ptr->real_name= thd->strmake(name.str, name.length)))
+ if (!(ptr->table_name= thd->strmake(name.str, name.length)))
goto err;
if (db.length && !(ptr->db= thd->strmake(db.str, db.length)))
goto err;
create_info->merge_list.elements++;
(*create_info->merge_list.next) = (byte*) ptr;
- create_info->merge_list.next= (byte**) &ptr->next;
+ create_info->merge_list.next= (byte**) &ptr->next_local;
}
*create_info->merge_list.next=0;
}
@@ -378,21 +396,22 @@ err:
int ha_myisammrg::create(const char *name, register TABLE *form,
HA_CREATE_INFO *create_info)
{
- char buff[FN_REFLEN],**table_names,**pos;
+ char buff[FN_REFLEN];
+ const char **table_names, **pos;
TABLE_LIST *tables= (TABLE_LIST*) create_info->merge_list.first;
THD *thd= current_thd;
uint dirlgt= dirname_length(name);
DBUG_ENTER("ha_myisammrg::create");
- if (!(table_names= (char**) thd->alloc((create_info->merge_list.elements+1)*
- sizeof(char*))))
+ if (!(table_names= (const char**)
+ thd->alloc((create_info->merge_list.elements+1) * sizeof(char*))))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
- for (pos=table_names ; tables ; tables=tables->next)
+ for (pos= table_names; tables; tables= tables->next_local)
{
- char *table_name;
+ const char *table_name;
TABLE **tbl= 0;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
- tbl= find_temporary_table(thd, tables->db, tables->real_name);
+ tbl= find_temporary_table(thd, tables->db, tables->table_name);
if (!tbl)
{
/*
@@ -407,7 +426,7 @@ int ha_myisammrg::create(const char *name, register TABLE *form,
an embedded server without changing the paths in the .MRG file.
*/
uint length= my_snprintf(buff, FN_REFLEN, "%s/%s/%s", mysql_data_home,
- tables->db, tables->real_name);
+ tables->db, tables->table_name);
/*
If a MyISAM table is in the same directory as the MERGE table,
we use the table name without a path. This means that the
@@ -415,18 +434,18 @@ int ha_myisammrg::create(const char *name, register TABLE *form,
as the MyISAM tables are from the same database as the MERGE table.
*/
if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt))
- table_name= tables->real_name;
+ table_name= tables->table_name;
else
if (! (table_name= thd->strmake(buff, length)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}
else
- table_name=(*tbl)->path;
+ table_name= (*tbl)->s->path;
*pos++= table_name;
}
*pos=0;
DBUG_RETURN(myrg_create(fn_format(buff,name,"","",2+4+16),
- (const char **) table_names,
+ table_names,
create_info->merge_insert_method,
(my_bool) 0));
}
@@ -446,7 +465,7 @@ void ha_myisammrg::append_create_info(String *packet)
packet->append(" UNION=(",8);
MYRG_TABLE *open_table,*first;
- current_db= table->table_cache_key;
+ current_db= table->s->db;
db_length= strlen(current_db);
for (first=open_table=file->open_tables ;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index a1166641f7d..b61dbd1792c 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -12,7 +12,7 @@
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
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
@@ -37,7 +37,7 @@ extern my_bool opt_ndb_optimized_node_selection;
extern const char *opt_ndbcluster_connectstring;
// Default value for parallelism
-static const int parallelism= 240;
+static const int parallelism= 0;
// Default value for max number of transactions
// createable against NDB from this handler
@@ -45,6 +45,26 @@ static const int max_transactions= 256;
static const char *ha_ndb_ext=".ndb";
+static int ndbcluster_close_connection(THD *thd);
+static int ndbcluster_commit(THD *thd, bool all);
+static int ndbcluster_rollback(THD *thd, bool all);
+
+static handlerton ndbcluster_hton = {
+ "ndbcluster",
+ 0, /* slot */
+ 0, /* savepoint size */
+ ndbcluster_close_connection,
+ NULL, /* savepoint_set */
+ NULL, /* savepoint_rollback */
+ NULL, /* savepoint_release */
+ ndbcluster_commit,
+ ndbcluster_rollback,
+ NULL, /* prepare */
+ NULL, /* recover */
+ NULL, /* commit_by_xid */
+ NULL /* rollback_by_xid */
+};
+
#define NDB_HIDDEN_PRIMARY_KEY_LENGTH 8
#define NDB_FAILED_AUTO_INCREMENT ~(Uint64)0
@@ -53,10 +73,11 @@ static const char *ha_ndb_ext=".ndb";
#define ERR_PRINT(err) \
DBUG_PRINT("error", ("%d message: %s", err.code, err.message))
-#define ERR_RETURN(err) \
-{ \
- ERR_PRINT(err); \
- DBUG_RETURN(ndb_to_mysql_error(&err)); \
+#define ERR_RETURN(err) \
+{ \
+ const NdbError& tmp= err; \
+ ERR_PRINT(tmp); \
+ DBUG_RETURN(ndb_to_mysql_error(&tmp)); \
}
// Typedefs for long names
@@ -83,17 +104,61 @@ static void free_share(NDB_SHARE *share);
static int packfrm(const void *data, uint len, const void **pack_data, uint *pack_len);
static int unpackfrm(const void **data, uint *len,
- const void* pack_data);
+ const void* pack_data);
static int ndb_get_table_statistics(Ndb*, const char *,
- Uint64* rows, Uint64* commits);
+ struct Ndb_statistics *);
+// Util thread variables
+static pthread_t ndb_util_thread;
+pthread_mutex_t LOCK_ndb_util_thread;
+pthread_cond_t COND_ndb_util_thread;
+extern "C" pthread_handler_decl(ndb_util_thread_func, arg);
+ulong ndb_cache_check_time;
/*
Dummy buffer to read zero pack_length fields
which are mapped to 1 char
*/
-static byte dummy_buf[1];
+static uint32 dummy_buf;
+
+/*
+ Stats that can be retrieved from ndb
+*/
+
+struct Ndb_statistics {
+ Uint64 row_count;
+ Uint64 commit_count;
+ Uint64 row_size;
+ Uint64 fragment_memory;
+};
+
+/* Status variables shown with 'show status like 'Ndb%' */
+
+static long ndb_cluster_node_id= 0;
+static const char * ndb_connected_host= 0;
+static long ndb_connected_port= 0;
+static long ndb_number_of_replicas= 0;
+static long ndb_number_of_storage_nodes= 0;
+
+static int update_status_variables(Ndb_cluster_connection *c)
+{
+ ndb_cluster_node_id= c->node_id();
+ ndb_connected_port= c->get_connected_port();
+ ndb_connected_host= c->get_connected_host();
+ ndb_number_of_replicas= 0;
+ ndb_number_of_storage_nodes= c->no_db_nodes();
+ return 0;
+}
+
+struct show_var_st ndb_status_variables[]= {
+ {"cluster_node_id", (char*) &ndb_cluster_node_id, SHOW_LONG},
+ {"connected_host", (char*) &ndb_connected_host, SHOW_CHAR_PTR},
+ {"connected_port", (char*) &ndb_connected_port, SHOW_LONG},
+// {"number_of_replicas", (char*) &ndb_number_of_replicas, SHOW_LONG},
+ {"number_of_storage_nodes",(char*) &ndb_number_of_storage_nodes, SHOW_LONG},
+ {NullS, NullS, SHOW_LONG}
+};
/*
Error handling functions
@@ -114,7 +179,7 @@ static const err_code_mapping err_map[]=
{ 721, HA_ERR_TABLE_EXIST, 1 },
{ 4244, HA_ERR_TABLE_EXIST, 1 },
- { 709, HA_ERR_NO_SUCH_TABLE, 1 },
+ { 709, HA_ERR_NO_SUCH_TABLE, 0 },
{ 266, HA_ERR_LOCK_WAIT_TIMEOUT, 1 },
{ 274, HA_ERR_LOCK_WAIT_TIMEOUT, 1 },
@@ -129,6 +194,8 @@ static const err_code_mapping err_map[]=
{ 827, HA_ERR_RECORD_FILE_FULL, 1 },
{ 832, HA_ERR_RECORD_FILE_FULL, 1 },
+ { 284, HA_ERR_TABLE_DEF_CHANGED, 0 },
+
{ 0, 1, 0 },
{ -1, -1, 1 }
@@ -143,8 +210,8 @@ static int ndb_to_mysql_error(const NdbError *err)
{
// Push the NDB error message as warning
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
- ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
- err->code, err->message, "NDB");
+ ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
+ err->code, err->message, "NDB");
}
if (err_map[i].my_err == -1)
return err->code;
@@ -154,58 +221,67 @@ static int ndb_to_mysql_error(const NdbError *err)
inline
-int execute_no_commit(ha_ndbcluster *h, NdbConnection *trans)
+int execute_no_commit(ha_ndbcluster *h, NdbTransaction *trans)
{
- int m_batch_execute= 0;
#ifdef NOT_USED
+ int m_batch_execute= 0;
if (m_batch_execute)
return 0;
#endif
- return trans->execute(NoCommit,AbortOnError,h->m_force_send);
+ return trans->execute(NdbTransaction::NoCommit,
+ NdbTransaction::AbortOnError,
+ h->m_force_send);
}
inline
-int execute_commit(ha_ndbcluster *h, NdbConnection *trans)
+int execute_commit(ha_ndbcluster *h, NdbTransaction *trans)
{
- int m_batch_execute= 0;
#ifdef NOT_USED
+ int m_batch_execute= 0;
if (m_batch_execute)
return 0;
#endif
- return trans->execute(Commit,AbortOnError,h->m_force_send);
+ return trans->execute(NdbTransaction::Commit,
+ NdbTransaction::AbortOnError,
+ h->m_force_send);
}
inline
-int execute_commit(THD *thd, NdbConnection *trans)
+int execute_commit(THD *thd, NdbTransaction *trans)
{
- int m_batch_execute= 0;
#ifdef NOT_USED
+ int m_batch_execute= 0;
if (m_batch_execute)
return 0;
#endif
- return trans->execute(Commit,AbortOnError,thd->variables.ndb_force_send);
+ return trans->execute(NdbTransaction::Commit,
+ NdbTransaction::AbortOnError,
+ thd->variables.ndb_force_send);
}
inline
-int execute_no_commit_ie(ha_ndbcluster *h, NdbConnection *trans)
+int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans)
{
- int m_batch_execute= 0;
#ifdef NOT_USED
+ int m_batch_execute= 0;
if (m_batch_execute)
return 0;
#endif
- return trans->execute(NoCommit, AO_IgnoreError,h->m_force_send);
+ return trans->execute(NdbTransaction::NoCommit,
+ NdbTransaction::AO_IgnoreError,
+ h->m_force_send);
}
/*
Place holder for ha_ndbcluster thread specific data
*/
-
Thd_ndb::Thd_ndb()
{
ndb= new Ndb(g_ndb_cluster_connection, "");
lock_count= 0;
count= 0;
+ all= NULL;
+ stmt= NULL;
error= 0;
}
@@ -213,13 +289,22 @@ Thd_ndb::~Thd_ndb()
{
if (ndb)
delete ndb;
- ndb= 0;
+ ndb= NULL;
+ changed_tables.empty();
}
inline
+Thd_ndb *
+get_thd_ndb(THD *thd) { return (Thd_ndb *) thd->ha_data[ndbcluster_hton.slot]; }
+
+inline
+void
+set_thd_ndb(THD *thd, Thd_ndb *thd_ndb) { thd->ha_data[ndbcluster_hton.slot]= thd_ndb; }
+
+inline
Ndb *ha_ndbcluster::get_ndb()
{
- return ((Thd_ndb*)current_thd->transaction.thd_ndb)->ndb;
+ return get_thd_ndb(current_thd)->ndb;
}
/*
@@ -235,7 +320,7 @@ struct Ndb_local_table_statistics {
void ha_ndbcluster::set_rec_per_key()
{
DBUG_ENTER("ha_ndbcluster::get_status_const");
- for (uint i=0 ; i < table->keys ; i++)
+ for (uint i=0 ; i < table->s->keys ; i++)
{
table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]= 1;
}
@@ -250,19 +335,21 @@ void ha_ndbcluster::records_update()
struct Ndb_local_table_statistics *info=
(struct Ndb_local_table_statistics *)m_table_info;
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
- ((const NDBTAB *)m_table)->getTableId(),
- info->no_uncommitted_rows_count));
+ ((const NDBTAB *)m_table)->getTableId(),
+ info->no_uncommitted_rows_count));
// if (info->records == ~(ha_rows)0)
{
Ndb *ndb= get_ndb();
- Uint64 rows;
- if(ndb_get_table_statistics(ndb, m_tabname, &rows, 0) == 0){
- info->records= rows;
+ struct Ndb_statistics stat;
+ 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;
}
}
{
THD *thd= current_thd;
- if (((Thd_ndb*)(thd->transaction.thd_ndb))->error)
+ if (get_thd_ndb(thd)->error)
info->no_uncommitted_rows_count= 0;
}
records= info->records+ info->no_uncommitted_rows_count;
@@ -274,8 +361,7 @@ void ha_ndbcluster::no_uncommitted_rows_execute_failure()
if (m_ha_not_exact_count)
return;
DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_execute_failure");
- THD *thd= current_thd;
- ((Thd_ndb*)(thd->transaction.thd_ndb))->error= 1;
+ get_thd_ndb(current_thd)->error= 1;
DBUG_VOID_RETURN;
}
@@ -286,15 +372,15 @@ void ha_ndbcluster::no_uncommitted_rows_init(THD *thd)
DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_init");
struct Ndb_local_table_statistics *info=
(struct Ndb_local_table_statistics *)m_table_info;
- Thd_ndb *thd_ndb= (Thd_ndb *)thd->transaction.thd_ndb;
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
if (info->last_count != thd_ndb->count)
{
- info->last_count = thd_ndb->count;
+ info->last_count= thd_ndb->count;
info->no_uncommitted_rows_count= 0;
info->records= ~(ha_rows)0;
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
- ((const NDBTAB *)m_table)->getTableId(),
- info->no_uncommitted_rows_count));
+ ((const NDBTAB *)m_table)->getTableId(),
+ info->no_uncommitted_rows_count));
}
DBUG_VOID_RETURN;
}
@@ -308,8 +394,8 @@ void ha_ndbcluster::no_uncommitted_rows_update(int c)
(struct Ndb_local_table_statistics *)m_table_info;
info->no_uncommitted_rows_count+= c;
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
- ((const NDBTAB *)m_table)->getTableId(),
- info->no_uncommitted_rows_count));
+ ((const NDBTAB *)m_table)->getTableId(),
+ info->no_uncommitted_rows_count));
DBUG_VOID_RETURN;
}
@@ -318,16 +404,17 @@ void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd)
if (m_ha_not_exact_count)
return;
DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_reset");
- ((Thd_ndb*)(thd->transaction.thd_ndb))->count++;
- ((Thd_ndb*)(thd->transaction.thd_ndb))->error= 0;
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
+ thd_ndb->count++;
+ thd_ndb->error= 0;
DBUG_VOID_RETURN;
}
/*
Take care of the error that occured in NDB
-
+
RETURN
- 0 No error
+ 0 No error
# The mapped error code
*/
@@ -353,9 +440,9 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global)
}
else
dict->removeCachedTable(m_tabname);
- table->version=0L; /* Free when thread is ready */
+ table->s->version=0L; /* Free when thread is ready */
/* Invalidate indexes */
- for (uint i= 0; i < table->keys; i++)
+ for (uint i= 0; i < table->s->keys; i++)
{
NDBINDEX *index = (NDBINDEX *) m_index[i].index;
NDBINDEX *unique_index = (NDBINDEX *) m_index[i].unique_index;
@@ -368,7 +455,7 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global)
dict->invalidateIndex(index->getName(), m_tabname);
else
dict->removeCachedIndex(index->getName(), m_tabname);
- break;
+ break;
case(UNIQUE_ORDERED_INDEX):
if (global)
dict->invalidateIndex(index->getName(), m_tabname);
@@ -388,7 +475,7 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global)
DBUG_VOID_RETURN;
}
-int ha_ndbcluster::ndb_err(NdbConnection *trans)
+int ha_ndbcluster::ndb_err(NdbTransaction *trans)
{
int res;
NdbError err= trans->getNdbError();
@@ -397,7 +484,6 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans)
ERR_PRINT(err);
switch (err.classification) {
case NdbError::SchemaError:
- {
invalidate_dictionary_cache(TRUE);
if (err.code==284)
@@ -415,27 +501,17 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans)
if (err.code != 709)
DBUG_RETURN(1);
}
- else
- {
- DBUG_PRINT("info", ("Table exist but must have changed"));
- /* In 5.0, this should be replaced with a mapping to a mysql error */
- my_printf_error(ER_UNKNOWN_ERROR,
- "Table definition has changed, "\
- "please retry transaction",
- MYF(0));
- DBUG_RETURN(1);
- }
+ DBUG_PRINT("info", ("Table exists but must have changed"));
}
break;
- }
default:
break;
}
res= ndb_to_mysql_error(&err);
DBUG_PRINT("info", ("transformed ndbcluster error %d to mysql error %d",
- err.code, res));
+ err.code, res));
if (res == HA_ERR_FOUND_DUPP_KEY)
- m_dupkey= table->primary_key;
+ m_dupkey= table->s->primary_key;
DBUG_RETURN(res);
}
@@ -447,7 +523,7 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans)
*/
bool ha_ndbcluster::get_error_message(int error,
- String *buf)
+ String *buf)
{
DBUG_ENTER("ha_ndbcluster::get_error_message");
DBUG_PRINT("enter", ("error: %d", error));
@@ -473,7 +549,6 @@ bool ha_ndbcluster::get_error_message(int error,
static inline bool ndb_supported_type(enum_field_types type)
{
switch (type) {
- case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
@@ -481,6 +556,8 @@ static inline bool ndb_supported_type(enum_field_types type)
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_DATE:
@@ -489,12 +566,14 @@ static inline bool ndb_supported_type(enum_field_types type)
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_BIT:
return TRUE;
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_GEOMETRY:
@@ -509,11 +588,11 @@ static inline bool ndb_supported_type(enum_field_types type)
*/
bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op,
- uint fieldnr, const byte *field_ptr)
+ uint fieldnr, const byte *field_ptr)
{
DBUG_ENTER("set_hidden_key");
DBUG_RETURN(ndb_op->equal(fieldnr, (char*)field_ptr,
- NDB_HIDDEN_PRIMARY_KEY_LENGTH) != 0);
+ NDB_HIDDEN_PRIMARY_KEY_LENGTH) != 0);
}
@@ -561,21 +640,50 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
if (ndb_supported_type(field->type()))
{
// ndb currently does not support size 0
- const byte *empty_field= "";
+ uint32 empty_field;
if (pack_len == 0)
{
- pack_len= 1;
- field_ptr= empty_field;
+ pack_len= sizeof(empty_field);
+ field_ptr= (byte *)&empty_field;
+ if (field->is_null())
+ empty_field= 0;
+ else
+ empty_field= 1;
}
if (! (field->flags & BLOB_FLAG))
{
- if (field->is_null())
- // Set value to NULL
- DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL, pack_len) != 0));
- // Common implementation for most field types
- DBUG_RETURN(ndb_op->setValue(fieldnr, (char*)field_ptr, pack_len) != 0);
+ if (field->type() != MYSQL_TYPE_BIT)
+ {
+ if (field->is_null())
+ // Set value to NULL
+ DBUG_RETURN((ndb_op->setValue(fieldnr,
+ (char*)NULL, pack_len) != 0));
+ // Common implementation for most field types
+ DBUG_RETURN(ndb_op->setValue(fieldnr,
+ (char*)field_ptr, pack_len) != 0);
+ }
+ else // if (field->type() == MYSQL_TYPE_BIT)
+ {
+ longlong bits= field->val_int();
+
+ // Round up bit field length to nearest word boundry
+ pack_len= ((pack_len + 3) >> 2) << 2;
+ DBUG_ASSERT(pack_len <= 8);
+ if (field->is_null())
+ // Set value to NULL
+ DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL, pack_len) != 0));
+ DBUG_PRINT("info", ("bit field"));
+ DBUG_DUMP("value", (char*)&bits, pack_len);
+#ifdef WORDS_BIGENDIAN
+ if (pack_len < 5)
+ {
+ DBUG_RETURN(ndb_op->setValue(fieldnr,
+ ((char*)&bits)+4, pack_len) != 0);
+ }
+#endif
+ DBUG_RETURN(ndb_op->setValue(fieldnr, (char*)&bits, pack_len) != 0);
+ }
}
-
// Blob type
NdbBlob *ndb_blob= ndb_op->getBlobHandle(fieldnr);
if (ndb_blob != NULL)
@@ -601,7 +709,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26));
if (set_blob_value)
- *set_blob_value= TRUE;
+ *set_blob_value= TRUE;
// No callback needed to write value
DBUG_RETURN(ndb_blob->setValue(blob_ptr, blob_len) != 0);
}
@@ -645,7 +753,7 @@ int ha_ndbcluster::get_ndb_blobs_value(NdbBlob *last_ndb_blob)
for (int loop= 0; loop <= 1; loop++)
{
uint32 offset= 0;
- for (uint i= 0; i < table->fields; i++)
+ for (uint i= 0; i < table->s->fields; i++)
{
Field *field= table->field[i];
NdbValue value= m_value[i];
@@ -709,14 +817,21 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
{
DBUG_ASSERT(field->ptr != NULL);
if (! (field->flags & BLOB_FLAG))
- {
- byte *field_buf;
- if (field->pack_length() != 0)
- field_buf= buf + (field->ptr - table->record[0]);
- else
- field_buf= dummy_buf;
- m_value[fieldnr].rec= ndb_op->getValue(fieldnr,
- field_buf);
+ {
+ if (field->type() != MYSQL_TYPE_BIT)
+ {
+ byte *field_buf;
+ if (field->pack_length() != 0)
+ field_buf= buf + (field->ptr - table->record[0]);
+ else
+ field_buf= (byte *)&dummy_buf;
+ m_value[fieldnr].rec= ndb_op->getValue(fieldnr,
+ field_buf);
+ }
+ else // if (field->type() == MYSQL_TYPE_BIT)
+ {
+ m_value[fieldnr].rec= ndb_op->getValue(fieldnr);
+ }
DBUG_RETURN(m_value[fieldnr].rec == NULL);
}
@@ -747,14 +862,14 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
*/
bool ha_ndbcluster::uses_blob_value(bool all_fields)
{
- if (table->blob_fields == 0)
+ if (table->s->blob_fields == 0)
return FALSE;
if (all_fields)
return TRUE;
{
- uint no_fields= table->fields;
+ uint no_fields= table->s->fields;
int i;
- THD *thd= table->in_use;
+ THD *thd= current_thd;
// They always put blobs at the end..
for (i= no_fields - 1; i >= 0; i--)
{
@@ -807,7 +922,7 @@ int ha_ndbcluster::get_metadata(const char *path)
*/
error= 0;
if (readfrm(path, &data, &length) ||
- packfrm(data, length, &pack_data, &pack_length))
+ packfrm(data, length, &pack_data, &pack_length))
{
my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR));
@@ -815,24 +930,24 @@ int ha_ndbcluster::get_metadata(const char *path)
}
if ((pack_length != tab->getFrmLength()) ||
- (memcmp(pack_data, tab->getFrmData(), pack_length)))
+ (memcmp(pack_data, tab->getFrmData(), pack_length)))
{
if (!invalidating_ndb_table)
{
- DBUG_PRINT("info", ("Invalidating table"));
+ DBUG_PRINT("info", ("Invalidating table"));
invalidate_dictionary_cache(TRUE);
- invalidating_ndb_table= TRUE;
+ invalidating_ndb_table= TRUE;
}
else
{
- DBUG_PRINT("error",
- ("metadata, pack_length: %d getFrmLength: %d memcmp: %d",
- pack_length, tab->getFrmLength(),
- memcmp(pack_data, tab->getFrmData(), pack_length)));
- DBUG_DUMP("pack_data", (char*)pack_data, pack_length);
- DBUG_DUMP("frm", (char*)tab->getFrmData(), tab->getFrmLength());
- error= 3;
- invalidating_ndb_table= FALSE;
+ DBUG_PRINT("error",
+ ("metadata, pack_length: %d getFrmLength: %d memcmp: %d",
+ pack_length, tab->getFrmLength(),
+ memcmp(pack_data, tab->getFrmData(), pack_length)));
+ DBUG_DUMP("pack_data", (char*)pack_data, pack_length);
+ DBUG_DUMP("frm", (char*)tab->getFrmData(), tab->getFrmLength());
+ error= 3;
+ invalidating_ndb_table= FALSE;
}
}
else
@@ -854,8 +969,8 @@ int ha_ndbcluster::get_metadata(const char *path)
}
static int fix_unique_index_attr_order(NDB_INDEX_DATA &data,
- const NDBINDEX *index,
- KEY *key_info)
+ const NDBINDEX *index,
+ KEY *key_info)
{
DBUG_ENTER("fix_unique_index_attr_order");
unsigned sz= index->getNoOfIndexColumns();
@@ -881,8 +996,8 @@ static int fix_unique_index_attr_order(NDB_INDEX_DATA &data,
const NDBCOL *c= index->getColumn(j);
if (strncmp(field_name, c->getName(), name_sz) == 0)
{
- data.unique_index_attrid_map[i]= j;
- break;
+ data.unique_index_attrid_map[i]= j;
+ break;
}
}
DBUG_ASSERT(data.unique_index_attrid_map[i] != 255);
@@ -894,16 +1009,16 @@ int ha_ndbcluster::build_index_list(Ndb *ndb, TABLE *tab, enum ILBP phase)
{
uint i;
int error= 0;
- const char *name, *index_name;
+ const char *index_name;
char unique_index_name[FN_LEN];
static const char* unique_suffix= "$unique";
KEY* key_info= tab->key_info;
- const char **key_name= tab->keynames.type_names;
+ const char **key_name= tab->s->keynames.type_names;
NDBDICT *dict= ndb->getDictionary();
- DBUG_ENTER("build_index_list");
+ DBUG_ENTER("ha_ndbcluster::build_index_list");
// Save information about all known indexes
- for (i= 0; i < tab->keys; i++, key_info++, key_name++)
+ for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
{
index_name= *key_name;
NDB_INDEX_TYPE idx_type= get_index_type_from_table(i);
@@ -912,40 +1027,40 @@ int ha_ndbcluster::build_index_list(Ndb *ndb, TABLE *tab, enum ILBP phase)
{
strxnmov(unique_index_name, FN_LEN, index_name, unique_suffix, NullS);
DBUG_PRINT("info", ("Created unique index name \'%s\' for index %d",
- unique_index_name, i));
+ unique_index_name, i));
}
// Create secondary indexes if in create phase
if (phase == ILBP_CREATE)
{
DBUG_PRINT("info", ("Creating index %u: %s", i, index_name));
switch (idx_type){
-
+
case PRIMARY_KEY_INDEX:
- // Do nothing, already created
- break;
+ // Do nothing, already created
+ break;
case PRIMARY_KEY_ORDERED_INDEX:
- error= create_ordered_index(index_name, key_info);
- break;
+ error= create_ordered_index(index_name, key_info);
+ break;
case UNIQUE_ORDERED_INDEX:
- if (!(error= create_ordered_index(index_name, key_info)))
- error= create_unique_index(unique_index_name, key_info);
- break;
+ if (!(error= create_ordered_index(index_name, key_info)))
+ error= create_unique_index(unique_index_name, key_info);
+ break;
case UNIQUE_INDEX:
- if (!(error= check_index_fields_not_null(i)))
- error= create_unique_index(unique_index_name, key_info);
- break;
+ if (!(error= check_index_fields_not_null(i)))
+ error= create_unique_index(unique_index_name, key_info);
+ break;
case ORDERED_INDEX:
- error= create_ordered_index(index_name, key_info);
- break;
+ error= create_ordered_index(index_name, key_info);
+ break;
default:
- DBUG_ASSERT(FALSE);
- break;
+ DBUG_ASSERT(FALSE);
+ break;
}
if (error)
{
- DBUG_PRINT("error", ("Failed to create index %u", i));
- drop_table();
- break;
+ DBUG_PRINT("error", ("Failed to create index %u", i));
+ drop_table();
+ break;
}
}
// Add handles to index objects
@@ -977,12 +1092,12 @@ int ha_ndbcluster::build_index_list(Ndb *ndb, TABLE *tab, enum ILBP phase)
NDB_INDEX_TYPE ha_ndbcluster::get_index_type_from_table(uint inx) const
{
bool is_hash_index= (table->key_info[inx].algorithm == HA_KEY_ALG_HASH);
- if (inx == table->primary_key)
+ if (inx == table->s->primary_key)
return is_hash_index ? PRIMARY_KEY_INDEX : PRIMARY_KEY_ORDERED_INDEX;
- else
- return ((table->key_info[inx].flags & HA_NOSAME) ?
- (is_hash_index ? UNIQUE_INDEX : UNIQUE_ORDERED_INDEX) :
- ORDERED_INDEX);
+
+ return ((table->key_info[inx].flags & HA_NOSAME) ?
+ (is_hash_index ? UNIQUE_INDEX : UNIQUE_ORDERED_INDEX) :
+ ORDERED_INDEX);
}
int ha_ndbcluster::check_index_fields_not_null(uint inx)
@@ -990,16 +1105,16 @@ int ha_ndbcluster::check_index_fields_not_null(uint inx)
KEY* key_info= table->key_info + inx;
KEY_PART_INFO* key_part= key_info->key_part;
KEY_PART_INFO* end= key_part+key_info->key_parts;
- DBUG_ENTER("check_index_fields_not_null");
+ DBUG_ENTER("ha_ndbcluster::check_index_fields_not_null");
for (; key_part != end; key_part++)
{
Field* field= key_part->field;
if (field->maybe_null())
{
- my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX),
- MYF(0),field->field_name);
- DBUG_RETURN(ER_NULL_COLUMN_IN_INDEX);
+ my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX),
+ MYF(0),field->field_name);
+ DBUG_RETURN(ER_NULL_COLUMN_IN_INDEX);
}
}
@@ -1057,6 +1172,7 @@ static const ulong index_type_flags[]=
*/
// HA_KEYREAD_ONLY |
HA_READ_NEXT |
+ HA_READ_PREV |
HA_READ_RANGE |
HA_READ_ORDER,
@@ -1065,11 +1181,13 @@ static const ulong index_type_flags[]=
/* UNIQUE_ORDERED_INDEX */
HA_READ_NEXT |
+ HA_READ_PREV |
HA_READ_RANGE |
HA_READ_ORDER,
/* ORDERED_INDEX */
HA_READ_NEXT |
+ HA_READ_PREV |
HA_READ_RANGE |
HA_READ_ORDER
};
@@ -1093,16 +1211,34 @@ inline NDB_INDEX_TYPE ha_ndbcluster::get_index_type(uint idx_no) const
inline ulong ha_ndbcluster::index_flags(uint idx_no, uint part,
bool all_parts) const
{
- DBUG_ENTER("index_flags");
+ DBUG_ENTER("ha_ndbcluster::index_flags");
DBUG_PRINT("info", ("idx_no: %d", idx_no));
DBUG_ASSERT(get_index_type_from_table(idx_no) < index_flags_size);
DBUG_RETURN(index_type_flags[get_index_type_from_table(idx_no)]);
}
+static void shrink_varchar(Field* field, const byte* & ptr, char* buf)
+{
+ if (field->type() == MYSQL_TYPE_VARCHAR) {
+ Field_varstring* f= (Field_varstring*)field;
+ if (f->length_bytes == 1) {
+ uint pack_len= field->pack_length();
+ DBUG_ASSERT(1 <= pack_len && pack_len <= 256);
+ if (ptr[1] == 0) {
+ buf[0]= ptr[0];
+ } else {
+ DBUG_ASSERT(false);
+ buf[0]= 255;
+ }
+ memmove(buf + 1, ptr + 2, pack_len - 1);
+ ptr= buf;
+ }
+ }
+}
int ha_ndbcluster::set_primary_key(NdbOperation *op, const byte *key)
{
- KEY* key_info= table->key_info + table->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");
@@ -1110,10 +1246,13 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const byte *key)
for (; key_part != end; key_part++)
{
Field* field= key_part->field;
+ const byte* ptr= key;
+ char buf[256];
+ shrink_varchar(field, ptr, buf);
if (set_ndb_key(op, field,
- key_part->fieldnr-1, key))
+ key_part->fieldnr-1, ptr))
ERR_RETURN(op->getNdbError());
- key += key_part->length;
+ key += key_part->store_length;
}
DBUG_RETURN(0);
}
@@ -1121,7 +1260,7 @@ 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->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_old_data");
@@ -1130,7 +1269,7 @@ int ha_ndbcluster::set_primary_key_from_old_data(NdbOperation *op, const byte *o
{
Field* field= key_part->field;
if (set_ndb_key(op, field,
- key_part->fieldnr-1, old_data+key_part->offset))
+ key_part->fieldnr-1, old_data+key_part->offset))
ERR_RETURN(op->getNdbError());
}
DBUG_RETURN(0);
@@ -1140,7 +1279,7 @@ int ha_ndbcluster::set_primary_key_from_old_data(NdbOperation *op, const byte *o
int ha_ndbcluster::set_primary_key(NdbOperation *op)
{
DBUG_ENTER("set_primary_key");
- KEY* key_info= table->key_info + table->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;
@@ -1154,6 +1293,69 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op)
DBUG_RETURN(0);
}
+int
+ha_ndbcluster::set_index_key(NdbOperation *op,
+ const KEY *key_info,
+ const byte * key_ptr)
+{
+ DBUG_ENTER("ha_ndbcluster::set_index_key");
+ uint i;
+ KEY_PART_INFO* key_part= key_info->key_part;
+ KEY_PART_INFO* end= key_part+key_info->key_parts;
+
+ for (i= 0; key_part != end; key_part++, i++)
+ {
+ Field* field= key_part->field;
+ const byte* ptr= key_part->null_bit ? key_ptr + 1 : key_ptr;
+ char buf[256];
+ shrink_varchar(field, ptr, buf);
+ if (set_ndb_key(op, field, m_index[active_index].unique_index_attrid_map[i], ptr))
+ ERR_RETURN(m_active_trans->getNdbError());
+ key_ptr+= key_part->store_length;
+ }
+ DBUG_RETURN(0);
+}
+
+inline
+int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
+{
+ uint i;
+ THD *thd= current_thd;
+
+ DBUG_ENTER("define_read_attrs");
+
+ // Define attributes to read
+ for (i= 0; i < table->s->fields; i++)
+ {
+ Field *field= table->field[i];
+ if ((thd->query_id == field->query_id) ||
+ ((field->flags & PRI_KEY_FLAG)) ||
+ m_retrieve_all_fields)
+ {
+ if (get_ndb_value(op, field, i, buf))
+ ERR_RETURN(op->getNdbError());
+ }
+ else
+ {
+ m_value[i].ptr= NULL;
+ }
+ }
+
+ if (table->s->primary_key == MAX_KEY)
+ {
+ DBUG_PRINT("info", ("Getting hidden key"));
+ // Scanning table with no primary key
+ int hidden_no= table->s->fields;
+#ifndef DBUG_OFF
+ const NDBTAB *tab= (const NDBTAB *) m_table;
+ if (!tab->getColumn(hidden_no))
+ DBUG_RETURN(1);
+#endif
+ if (get_ndb_value(op, NULL, hidden_no, NULL))
+ ERR_RETURN(op->getNdbError());
+ }
+ DBUG_RETURN(0);
+}
/*
Read one record from NDB using primary key
@@ -1161,10 +1363,11 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op)
int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
{
- uint no_fields= table->fields, i;
+ uint no_fields= table->s->fields;
NdbConnection *trans= m_active_trans;
NdbOperation *op;
- THD *thd= current_thd;
+
+ int res;
DBUG_ENTER("pk_read");
DBUG_PRINT("enter", ("key_len: %u", key_len));
DBUG_DUMP("key", (char*)key, key_len);
@@ -1174,43 +1377,27 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) ||
op->readTuple(lm) != 0)
ERR_RETURN(trans->getNdbError());
-
- if (table->primary_key == MAX_KEY)
+
+ if (table->s->primary_key == MAX_KEY)
{
// This table has no primary key, use "hidden" primary key
DBUG_PRINT("info", ("Using hidden key"));
DBUG_DUMP("key", (char*)key, 8);
if (set_hidden_key(op, no_fields, key))
ERR_RETURN(trans->getNdbError());
-
+
// Read key at the same time, for future reference
if (get_ndb_value(op, NULL, no_fields, NULL))
ERR_RETURN(trans->getNdbError());
}
else
{
- int res;
if ((res= set_primary_key(op, key)))
return res;
}
- // Read all wanted non-key field(s) unless HA_EXTRA_RETRIEVE_ALL_COLS
- for (i= 0; i < no_fields; i++)
- {
- Field *field= table->field[i];
- if ((thd->query_id == field->query_id) ||
- m_retrieve_all_fields ||
- (field->flags & PRI_KEY_FLAG) && m_retrieve_primary_key)
- {
- if (get_ndb_value(op, field, i, buf))
- ERR_RETURN(trans->getNdbError());
- }
- else
- {
- // Attribute was not to be read
- m_value[i].ptr= NULL;
- }
- }
+ if((res= define_read_attrs(buf, op)))
+ DBUG_RETURN(res);
if (execute_no_commit_ie(this,trans) != 0)
{
@@ -1224,15 +1411,14 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
DBUG_RETURN(0);
}
-
/*
Read one complementing record from NDB using primary key from old_data
*/
int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data)
{
- uint no_fields= table->fields, i;
- NdbConnection *trans= m_active_trans;
+ uint no_fields= table->s->fields, i;
+ NdbTransaction *trans= m_active_trans;
NdbOperation *op;
THD *thd= current_thd;
DBUG_ENTER("complemented_pk_read");
@@ -1246,20 +1432,20 @@ 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)))
- ERR_RETURN(trans->getNdbError());
-
+
+ int res;
+ if ((res= set_primary_key_from_old_data(op, old_data)))
+ ERR_RETURN(trans->getNdbError());
+
// Read all unreferenced non-key field(s)
for (i= 0; i < no_fields; i++)
{
Field *field= table->field[i];
- if (!(field->flags & PRI_KEY_FLAG) &&
- (thd->query_id != field->query_id))
+ if (!((field->flags & PRI_KEY_FLAG) ||
+ (thd->query_id == field->query_id)))
{
if (get_ndb_value(op, field, i, new_data))
- ERR_RETURN(trans->getNdbError());
+ ERR_RETURN(trans->getNdbError());
}
}
@@ -1272,6 +1458,20 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data)
// The value have now been fetched from NDB
unpack_record(new_data);
table->status= 0;
+
+ /**
+ * restore m_value
+ */
+ for (i= 0; i < no_fields; i++)
+ {
+ Field *field= table->field[i];
+ if (!((field->flags & PRI_KEY_FLAG) ||
+ (thd->query_id == field->query_id)))
+ {
+ m_value[i].ptr= NULL;
+ }
+ }
+
DBUG_RETURN(0);
}
@@ -1281,26 +1481,25 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data)
int ha_ndbcluster::peek_row()
{
- NdbConnection *trans= m_active_trans;
+ NdbTransaction *trans= m_active_trans;
NdbOperation *op;
- THD *thd= current_thd;
DBUG_ENTER("peek_row");
-
+
NdbOperation::LockMode lm=
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) ||
op->readTuple(lm) != 0)
ERR_RETURN(trans->getNdbError());
-
+
int res;
if ((res= set_primary_key(op)))
ERR_RETURN(trans->getNdbError());
-
+
if (execute_no_commit_ie(this,trans) != 0)
- {
- table->status= STATUS_NOT_FOUND;
- DBUG_RETURN(ndb_err(trans));
- }
+ {
+ table->status= STATUS_NOT_FOUND;
+ DBUG_RETURN(ndb_err(trans));
+ }
DBUG_RETURN(0);
}
@@ -1309,58 +1508,29 @@ int ha_ndbcluster::peek_row()
*/
int ha_ndbcluster::unique_index_read(const byte *key,
- uint key_len, byte *buf)
+ uint key_len, byte *buf)
{
- NdbConnection *trans= m_active_trans;
+ int res;
+ NdbTransaction *trans= m_active_trans;
NdbIndexOperation *op;
- THD *thd= current_thd;
- byte *key_ptr;
- KEY* key_info;
- KEY_PART_INFO *key_part, *end;
- uint i;
- DBUG_ENTER("unique_index_read");
+ DBUG_ENTER("ha_ndbcluster::unique_index_read");
DBUG_PRINT("enter", ("key_len: %u, index: %u", key_len, active_index));
DBUG_DUMP("key", (char*)key, key_len);
NdbOperation::LockMode lm=
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
if (!(op= trans->getNdbIndexOperation((NDBINDEX *)
- m_index[active_index].unique_index,
+ m_index[active_index].unique_index,
(const NDBTAB *) m_table)) ||
op->readTuple(lm) != 0)
ERR_RETURN(trans->getNdbError());
// Set secondary index key(s)
- key_ptr= (byte *) key;
- key_info= table->key_info + active_index;
- DBUG_ASSERT(key_info->key_length == key_len);
- end= (key_part= key_info->key_part) + key_info->key_parts;
-
- for (i= 0; key_part != end; key_part++, i++)
- {
- if (set_ndb_key(op, key_part->field,
- m_index[active_index].unique_index_attrid_map[i],
- key_part->null_bit ? key_ptr + 1 : key_ptr))
- ERR_RETURN(trans->getNdbError());
- key_ptr+= key_part->store_length;
- }
-
- // Get non-index attribute(s)
- for (i= 0; i < table->fields; i++)
- {
- Field *field= table->field[i];
- if ((thd->query_id == field->query_id) ||
- (field->flags & PRI_KEY_FLAG)) // && m_retrieve_primary_key ??
- {
- if (get_ndb_value(op, field, i, buf))
- ERR_RETURN(op->getNdbError());
- }
- else
- {
- // Attribute was not to be read
- m_value[i].ptr= NULL;
- }
- }
+ if((res= set_index_key(op, table->key_info + active_index, key)))
+ DBUG_RETURN(res);
+
+ if((res= define_read_attrs(buf, op)))
+ DBUG_RETURN(res);
if (execute_no_commit_ie(this,trans) != 0)
{
@@ -1373,31 +1543,12 @@ int ha_ndbcluster::unique_index_read(const byte *key,
DBUG_RETURN(0);
}
-/*
- Get the next record of a started scan. Try to fetch
- it locally from NdbApi cached records if possible,
- otherwise ask NDB for more.
-
- NOTE
- If this is a update/delete make sure to not contact
- NDB before any pending ops have been sent to NDB.
-
-*/
-
-inline int ha_ndbcluster::next_result(byte *buf)
-{
+inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
+{
+ DBUG_ENTER("fetch_next");
int check;
- NdbConnection *trans= m_active_trans;
- NdbResultSet *cursor= m_active_cursor;
- DBUG_ENTER("next_result");
-
- if (!cursor)
- DBUG_RETURN(HA_ERR_END_OF_FILE);
-
- /*
- If this an update or delete, call nextResult with false
- to process any records already cached in NdbApi
- */
+ NdbTransaction *trans= m_active_trans;
+
bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE;
do {
DBUG_PRINT("info", ("Call nextResult, contact_ndb: %d", contact_ndb));
@@ -1407,60 +1558,95 @@ inline int ha_ndbcluster::next_result(byte *buf)
if (m_ops_pending && m_blobs_pending)
{
if (execute_no_commit(this,trans) != 0)
- DBUG_RETURN(ndb_err(trans));
+ DBUG_RETURN(ndb_err(trans));
m_ops_pending= 0;
m_blobs_pending= FALSE;
}
- check= cursor->nextResult(contact_ndb, m_force_send);
- if (check == 0)
+
+ if ((check= cursor->nextResult(contact_ndb, m_force_send)) == 0)
{
- // One more record found
- DBUG_PRINT("info", ("One more record found"));
-
- unpack_record(buf);
- table->status= 0;
DBUG_RETURN(0);
}
else if (check == 1 || check == 2)
{
// 1: No more records
// 2: No more cached records
-
+
/*
- Before fetching more rows and releasing lock(s),
- all pending update or delete operations should
- be sent to NDB
+ Before fetching more rows and releasing lock(s),
+ all pending update or delete operations should
+ be sent to NDB
*/
DBUG_PRINT("info", ("ops_pending: %d", m_ops_pending));
if (m_ops_pending)
{
- // if (current_thd->transaction.on)
- if (m_transaction_on)
- {
- if (execute_no_commit(this,trans) != 0)
- DBUG_RETURN(ndb_err(trans));
- }
- else
- {
- if (execute_commit(this,trans) != 0)
- DBUG_RETURN(ndb_err(trans));
- int res= trans->restart();
- DBUG_ASSERT(res == 0);
- }
- m_ops_pending= 0;
+ if (m_transaction_on)
+ {
+ if (execute_no_commit(this,trans) != 0)
+ DBUG_RETURN(-1);
+ }
+ else
+ {
+ if (execute_commit(this,trans) != 0)
+ DBUG_RETURN(-1);
+ if(trans->restart() != 0)
+ {
+ DBUG_ASSERT(0);
+ DBUG_RETURN(-1);
+ }
+ }
+ m_ops_pending= 0;
}
-
contact_ndb= (check == 2);
}
+ else
+ {
+ DBUG_RETURN(-1);
+ }
} while (check == 2);
-
- table->status= STATUS_NOT_FOUND;
- if (check == -1)
- DBUG_RETURN(ndb_err(trans));
- // No more records
- DBUG_PRINT("info", ("No more records"));
- DBUG_RETURN(HA_ERR_END_OF_FILE);
+ DBUG_RETURN(1);
+}
+
+/*
+ Get the next record of a started scan. Try to fetch
+ it locally from NdbApi cached records if possible,
+ otherwise ask NDB for more.
+
+ NOTE
+ If this is a update/delete make sure to not contact
+ NDB before any pending ops have been sent to NDB.
+
+*/
+
+inline int ha_ndbcluster::next_result(byte *buf)
+{
+ int res;
+ DBUG_ENTER("next_result");
+
+ if (!m_active_cursor)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ if((res= fetch_next(m_active_cursor)) == 0)
+ {
+ DBUG_PRINT("info", ("One more record found"));
+
+ unpack_record(buf);
+ table->status= 0;
+ DBUG_RETURN(0);
+ }
+ else if(res == 1)
+ {
+ // No more records
+ table->status= STATUS_NOT_FOUND;
+
+ DBUG_PRINT("info", ("No more records"));
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
+ else
+ {
+ DBUG_RETURN(ndb_err(m_active_trans));
+ }
}
/*
@@ -1468,7 +1654,8 @@ inline int ha_ndbcluster::next_result(byte *buf)
*/
int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
- const key_range *keys[2])
+ const key_range *keys[2],
+ uint range_no)
{
const KEY *const key_info= table->key_info + active_index;
const uint key_parts= key_info->key_parts;
@@ -1501,7 +1688,9 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
{
KEY_PART_INFO *key_part= &key_info->key_part[i];
Field *field= key_part->field;
+#ifndef DBUG_OFF
uint part_len= key_part->length;
+#endif
uint part_store_len= key_part->store_length;
// Info about each key part
struct part_st {
@@ -1516,7 +1705,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
for (j= 0; j <= 1; j++)
{
- struct part_st &p = part[j];
+ struct part_st &p= part[j];
p.key= NULL;
p.bound_type= -1;
if (tot_len < key_tot_len[j])
@@ -1535,6 +1724,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
case HA_READ_KEY_EXACT:
p.bound_type= NdbIndexScanOperation::BoundEQ;
break;
+ // ascending
case HA_READ_KEY_OR_NEXT:
p.bound_type= NdbIndexScanOperation::BoundLE;
break;
@@ -1544,6 +1734,19 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
else
p.bound_type= NdbIndexScanOperation::BoundLT;
break;
+ // descending
+ case HA_READ_PREFIX_LAST: // weird
+ p.bound_type= NdbIndexScanOperation::BoundEQ;
+ break;
+ case HA_READ_PREFIX_LAST_OR_PREV: // weird
+ p.bound_type= NdbIndexScanOperation::BoundGE;
+ break;
+ case HA_READ_BEFORE_KEY:
+ if (! p.part_last)
+ p.bound_type= NdbIndexScanOperation::BoundGE;
+ else
+ p.bound_type= NdbIndexScanOperation::BoundGT;
+ break;
default:
break;
}
@@ -1551,6 +1754,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
if (j == 1) {
switch (p.key->flag)
{
+ // ascending
case HA_READ_BEFORE_KEY:
if (! p.part_last)
p.bound_type= NdbIndexScanOperation::BoundGE;
@@ -1562,6 +1766,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
break;
default:
break;
+ // descending strangely sets no end key
}
}
@@ -1570,6 +1775,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
DBUG_PRINT("error", ("key %d unknown flag %d", j, p.key->flag));
DBUG_ASSERT(false);
// Stop setting bounds but continue with what we have
+ op->end_of_bound(range_no);
DBUG_RETURN(0);
}
}
@@ -1595,7 +1801,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
for (j= 0; j <= 1; j++)
{
- struct part_st &p = part[j];
+ struct part_st &p= part[j];
// Set bound if not done with this key
if (p.key != NULL)
{
@@ -1605,79 +1811,38 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
// Set bound if not cancelled via type -1
if (p.bound_type != -1)
- {
- if (op->setBound(i, p.bound_type, p.bound_ptr))
+ {
+ const char* ptr= p.bound_ptr;
+ char buf[256];
+ shrink_varchar(field, ptr, buf);
+ if (op->setBound(i, p.bound_type, ptr))
ERR_RETURN(op->getNdbError());
- }
+ }
}
}
tot_len+= part_store_len;
}
+ op->end_of_bound(range_no);
DBUG_RETURN(0);
}
-inline
-int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
-{
- uint i;
- THD *thd= current_thd;
- NdbConnection *trans= m_active_trans;
-
- DBUG_ENTER("define_read_attrs");
-
- // Define attributes to read
- for (i= 0; i < table->fields; i++)
- {
- Field *field= table->field[i];
- if ((thd->query_id == field->query_id) ||
- (field->flags & PRI_KEY_FLAG) ||
- m_retrieve_all_fields)
- {
- if (get_ndb_value(op, field, i, buf))
- ERR_RETURN(op->getNdbError());
- }
- else
- {
- m_value[i].ptr= NULL;
- }
- }
-
- if (table->primary_key == MAX_KEY)
- {
- DBUG_PRINT("info", ("Getting hidden key"));
- // Scanning table with no primary key
- int hidden_no= table->fields;
-#ifndef DBUG_OFF
- const NDBTAB *tab= (const NDBTAB *) m_table;
- if (!tab->getColumn(hidden_no))
- DBUG_RETURN(1);
-#endif
- if (get_ndb_value(op, NULL, hidden_no, NULL))
- ERR_RETURN(op->getNdbError());
- }
-
- if (execute_no_commit(this,trans) != 0)
- DBUG_RETURN(ndb_err(trans));
- DBUG_PRINT("exit", ("Scan started successfully"));
- DBUG_RETURN(next_result(buf));
-}
-
/*
Start ordered index scan in NDB
*/
int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
- const key_range *end_key,
- bool sorted, byte* buf)
+ const key_range *end_key,
+ bool sorted, bool descending, byte* buf)
{
+ int res;
bool restart;
- NdbConnection *trans= m_active_trans;
- NdbResultSet *cursor;
+ NdbTransaction *trans= m_active_trans;
NdbIndexScanOperation *op;
- DBUG_ENTER("ordered_index_scan");
- DBUG_PRINT("enter", ("index: %u, sorted: %d", active_index, sorted));
+ DBUG_ENTER("ha_ndbcluster::ordered_index_scan");
+ DBUG_PRINT("enter", ("index: %u, sorted: %d, descending: %d",
+ active_index, sorted, descending));
DBUG_PRINT("enter", ("Starting new ordered scan on %s", m_tabname));
// Check that sorted seems to be initialised
@@ -1689,126 +1854,42 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
NdbOperation::LockMode lm=
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
if (!(op= trans->getNdbIndexScanOperation((NDBINDEX *)
- m_index[active_index].index,
- (const NDBTAB *) m_table)) ||
- !(cursor= op->readTuples(lm, 0, parallelism, sorted)))
+ m_index[active_index].index,
+ (const NDBTAB *) m_table)) ||
+ op->readTuples(lm, 0, parallelism, sorted, descending))
ERR_RETURN(trans->getNdbError());
- m_active_cursor= cursor;
+ m_active_cursor= op;
} else {
restart= true;
- op= (NdbIndexScanOperation*)m_active_cursor->getOperation();
+ op= (NdbIndexScanOperation*)m_active_cursor;
DBUG_ASSERT(op->getSorted() == sorted);
DBUG_ASSERT(op->getLockMode() ==
- (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type));
+ (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type));
if(op->reset_bounds(m_force_send))
DBUG_RETURN(ndb_err(m_active_trans));
}
-
+
{
const key_range *keys[2]= { start_key, end_key };
- int ret= set_bounds(op, keys);
- if (ret)
- DBUG_RETURN(ret);
+ res= set_bounds(op, keys);
+ if (res)
+ DBUG_RETURN(res);
}
- if (!restart)
- {
- DBUG_RETURN(define_read_attrs(buf, op));
- }
- else
- {
- if (execute_no_commit(this,trans) != 0)
- DBUG_RETURN(ndb_err(trans));
-
- DBUG_RETURN(next_result(buf));
- }
-}
-
-/*
- Start a filtered scan in NDB.
-
- NOTE
- This function is here as an example of how to start a
- filtered scan. It should be possible to replace full_table_scan
- with this function and make a best effort attempt
- at filtering out the irrelevant data by converting the "items"
- into interpreted instructions.
- This would speed up table scans where there is a limiting WHERE clause
- that doesn't match any index in the table.
-
- */
-
-int ha_ndbcluster::filtered_scan(const byte *key, uint key_len,
- byte *buf,
- enum ha_rkey_function find_flag)
-{
- NdbConnection *trans= m_active_trans;
- NdbResultSet *cursor;
- NdbScanOperation *op;
-
- DBUG_ENTER("filtered_scan");
- DBUG_PRINT("enter", ("key_len: %u, index: %u",
- key_len, active_index));
- DBUG_DUMP("key", (char*)key, key_len);
- DBUG_PRINT("info", ("Starting a new filtered scan on %s",
- m_tabname));
-
- NdbOperation::LockMode lm=
- (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
- if (!(op= trans->getNdbScanOperation((const NDBTAB *) m_table)) ||
- !(cursor= op->readTuples(lm, 0, parallelism)))
- ERR_RETURN(trans->getNdbError());
- m_active_cursor= cursor;
+ if (!restart && generate_scan_filter(m_cond_stack, op))
+ DBUG_RETURN(ndb_err(trans));
+ if (!restart && (res= define_read_attrs(buf, op)))
{
- // Start scan filter
- NdbScanFilter sf(op);
- sf.begin();
-
- // Set filter using the supplied key data
- byte *key_ptr= (byte *) key;
- uint tot_len= 0;
- KEY* key_info= table->key_info + active_index;
- for (uint k= 0; k < key_info->key_parts; k++)
- {
- KEY_PART_INFO* key_part= key_info->key_part+k;
- Field* field= key_part->field;
- uint ndb_fieldnr= key_part->fieldnr-1;
- DBUG_PRINT("key_part", ("fieldnr: %d", ndb_fieldnr));
- //const NDBCOL *col= ((const NDBTAB *) m_table)->getColumn(ndb_fieldnr);
- uint32 field_len= field->pack_length();
- DBUG_DUMP("key", (char*)key, field_len);
-
- DBUG_PRINT("info", ("Column %s, type: %d, len: %d",
- field->field_name, field->real_type(), field_len));
-
- // Define scan filter
- if (field->real_type() == MYSQL_TYPE_STRING)
- sf.eq(ndb_fieldnr, key_ptr, field_len);
- else
- {
- if (field_len == 8)
- sf.eq(ndb_fieldnr, (Uint64)*key_ptr);
- else if (field_len <= 4)
- sf.eq(ndb_fieldnr, (Uint32)*key_ptr);
- else
- DBUG_RETURN(1);
- }
-
- key_ptr += field_len;
- tot_len += field_len;
-
- if (tot_len >= key_len)
- break;
- }
- // End scan filter
- sf.end();
+ DBUG_RETURN(res);
}
- DBUG_RETURN(define_read_attrs(buf, op));
-}
-
+ if (execute_no_commit(this,trans) != 0)
+ DBUG_RETURN(ndb_err(trans));
+
+ DBUG_RETURN(next_result(buf));
+}
/*
Start full table scan in NDB
@@ -1816,10 +1897,9 @@ int ha_ndbcluster::filtered_scan(const byte *key, uint key_len,
int ha_ndbcluster::full_table_scan(byte *buf)
{
- uint i;
- NdbResultSet *cursor;
+ int res;
NdbScanOperation *op;
- NdbConnection *trans= m_active_trans;
+ NdbTransaction *trans= m_active_trans;
DBUG_ENTER("full_table_scan");
DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname));
@@ -1827,10 +1907,18 @@ int ha_ndbcluster::full_table_scan(byte *buf)
NdbOperation::LockMode lm=
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
if (!(op=trans->getNdbScanOperation((const NDBTAB *) m_table)) ||
- !(cursor= op->readTuples(lm, 0, parallelism)))
+ op->readTuples(lm, 0, parallelism))
ERR_RETURN(trans->getNdbError());
- m_active_cursor= cursor;
- DBUG_RETURN(define_read_attrs(buf, op));
+ m_active_cursor= op;
+ if (generate_scan_filter(m_cond_stack, op))
+ DBUG_RETURN(ndb_err(trans));
+ if((res= define_read_attrs(buf, op)))
+ DBUG_RETURN(res);
+
+ if (execute_no_commit(this,trans) != 0)
+ DBUG_RETURN(ndb_err(trans));
+ DBUG_PRINT("exit", ("Scan started successfully"));
+ DBUG_RETURN(next_result(buf));
}
/*
@@ -1840,25 +1928,27 @@ int ha_ndbcluster::write_row(byte *record)
{
bool has_auto_increment;
uint i;
- NdbConnection *trans= m_active_trans;
+ NdbTransaction *trans= m_active_trans;
NdbOperation *op;
int res;
+ THD *thd= current_thd;
+
DBUG_ENTER("write_row");
- if(m_ignore_dup_key && table->primary_key != MAX_KEY)
+ if (m_ignore_dup_key && table->s->primary_key != MAX_KEY)
{
int peek_res= peek_row();
if (!peek_res)
{
- m_dupkey= table->primary_key;
+ m_dupkey= table->s->primary_key;
DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY);
}
if (peek_res != HA_ERR_KEY_NOT_FOUND)
DBUG_RETURN(peek_res);
}
-
- statistic_increment(ha_write_count,&LOCK_status);
+
+ statistic_increment(thd->status_var.ha_write_count, &LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
has_auto_increment= (table->next_number_field && record == table->record[0]);
@@ -1870,7 +1960,7 @@ int ha_ndbcluster::write_row(byte *record)
if (res != 0)
ERR_RETURN(trans->getNdbError());
- if (table->primary_key == MAX_KEY)
+ if (table->s->primary_key == MAX_KEY)
{
// Table has hidden primary key
Ndb *ndb= get_ndb();
@@ -1883,7 +1973,7 @@ int ha_ndbcluster::write_row(byte *record)
ndb->getNdbError().status == NdbError::TemporaryError);
if (auto_value == NDB_FAILED_AUTO_INCREMENT)
ERR_RETURN(ndb->getNdbError());
- if (set_hidden_key(op, table->fields, (const byte*)&auto_value))
+ if (set_hidden_key(op, table->s->fields, (const byte*)&auto_value))
ERR_RETURN(op->getNdbError());
}
else
@@ -1892,8 +1982,12 @@ int ha_ndbcluster::write_row(byte *record)
if (has_auto_increment)
{
+ THD *thd= table->in_use;
+
m_skip_auto_increment= FALSE;
update_auto_increment();
+ /* Ensure that handler is always called for auto_increment values */
+ thd->next_insert_id= 0;
m_skip_auto_increment= !auto_increment_column_changed;
}
@@ -1905,17 +1999,19 @@ int ha_ndbcluster::write_row(byte *record)
// Set non-key attribute(s)
bool set_blob_value= FALSE;
- for (i= 0; i < table->fields; i++)
+ for (i= 0; i < table->s->fields; i++)
{
Field *field= table->field[i];
if (!(field->flags & PRI_KEY_FLAG) &&
- set_ndb_value(op, field, i, &set_blob_value))
+ set_ndb_value(op, field, i, &set_blob_value))
{
m_skip_auto_increment= TRUE;
ERR_RETURN(op->getNdbError());
}
}
+ m_rows_changed++;
+
/*
Execute write operation
NOTE When doing inserts with many values in
@@ -1931,33 +2027,34 @@ int ha_ndbcluster::write_row(byte *record)
m_primary_key_update ||
set_blob_value)
{
- THD *thd= current_thd;
// Send rows to NDB
DBUG_PRINT("info", ("Sending inserts to NDB, "\
- "rows_inserted:%d, bulk_insert_rows: %d",
- (int)m_rows_inserted, (int)m_bulk_insert_rows));
+ "rows_inserted:%d, bulk_insert_rows: %d",
+ (int)m_rows_inserted, (int)m_bulk_insert_rows));
m_bulk_insert_not_flushed= FALSE;
- // if (thd->transaction.on)
if (m_transaction_on)
{
if (execute_no_commit(this,trans) != 0)
{
- m_skip_auto_increment= TRUE;
- no_uncommitted_rows_execute_failure();
- DBUG_RETURN(ndb_err(trans));
+ m_skip_auto_increment= TRUE;
+ no_uncommitted_rows_execute_failure();
+ DBUG_RETURN(ndb_err(trans));
}
}
else
{
if (execute_commit(this,trans) != 0)
{
- m_skip_auto_increment= TRUE;
- no_uncommitted_rows_execute_failure();
- DBUG_RETURN(ndb_err(trans));
+ m_skip_auto_increment= TRUE;
+ no_uncommitted_rows_execute_failure();
+ DBUG_RETURN(ndb_err(trans));
+ }
+ if(trans->restart() != 0)
+ {
+ DBUG_ASSERT(0);
+ DBUG_RETURN(-1);
}
- int res= trans->restart();
- DBUG_ASSERT(res == 0);
}
}
if ((has_auto_increment) && (m_skip_auto_increment))
@@ -1965,11 +2062,11 @@ int ha_ndbcluster::write_row(byte *record)
Ndb *ndb= get_ndb();
Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1;
DBUG_PRINT("info",
- ("Trying to set next auto increment value to %lu",
+ ("Trying to set next auto increment value to %lu",
(ulong) next_val));
if (ndb->setAutoIncrementValue((const NDBTAB *) m_table, next_val, TRUE))
DBUG_PRINT("info",
- ("Setting next auto increment value to %u", next_val));
+ ("Setting next auto increment value to %u", next_val));
}
m_skip_auto_increment= TRUE;
@@ -1980,7 +2077,7 @@ int ha_ndbcluster::write_row(byte *record)
/* Compare if a key in a row has changed */
int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row,
- const byte * new_row)
+ const byte * new_row)
{
KEY_PART_INFO *key_part=table->key_info[keynr].key_part;
KEY_PART_INFO *end=key_part+table->key_info[keynr].key_parts;
@@ -1990,22 +2087,22 @@ int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row,
if (key_part->null_bit)
{
if ((old_row[key_part->null_offset] & key_part->null_bit) !=
- (new_row[key_part->null_offset] & key_part->null_bit))
- return 1;
+ (new_row[key_part->null_offset] & key_part->null_bit))
+ return 1;
}
- if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
{
if (key_part->field->cmp_binary((char*) (old_row + key_part->offset),
- (char*) (new_row + key_part->offset),
- (ulong) key_part->length))
- return 1;
+ (char*) (new_row + key_part->offset),
+ (ulong) key_part->length))
+ return 1;
}
else
{
if (memcmp(old_row+key_part->offset, new_row+key_part->offset,
- key_part->length))
- return 1;
+ key_part->length))
+ return 1;
}
}
return 0;
@@ -2018,13 +2115,13 @@ int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row,
int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
{
THD *thd= current_thd;
- NdbConnection *trans= m_active_trans;
- NdbResultSet* cursor= m_active_cursor;
+ NdbTransaction *trans= m_active_trans;
+ NdbScanOperation* cursor= m_active_cursor;
NdbOperation *op;
uint i;
DBUG_ENTER("update_row");
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_update_count, &LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
{
table->timestamp_field->set_time();
@@ -2033,8 +2130,8 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
}
/* Check for update of primary key for special handling */
- if ((table->primary_key != MAX_KEY) &&
- (key_cmp(table->primary_key, old_data, 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;
@@ -2086,7 +2183,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
the active record in cursor
*/
DBUG_PRINT("info", ("Calling updateTuple on cursor"));
- if (!(op= cursor->updateTuple()))
+ if (!(op= cursor->updateCurrentTuple()))
ERR_RETURN(trans->getNdbError());
m_ops_pending++;
if (uses_blob_value(FALSE))
@@ -2095,39 +2192,41 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
else
{
if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) ||
- op->updateTuple() != 0)
+ op->updateTuple() != 0)
ERR_RETURN(trans->getNdbError());
- if (table->primary_key == MAX_KEY)
+ if (table->s->primary_key == MAX_KEY)
{
// This table has no primary key, use "hidden" primary key
DBUG_PRINT("info", ("Using hidden key"));
// Require that the PK for this record has previously been
// read into m_value
- uint no_fields= table->fields;
- NdbRecAttr* rec= m_value[no_fields].rec;
+ uint no_fields= table->s->fields;
+ const NdbRecAttr* rec= m_value[no_fields].rec;
DBUG_ASSERT(rec);
DBUG_DUMP("key", (char*)rec->aRef(), NDB_HIDDEN_PRIMARY_KEY_LENGTH);
if (set_hidden_key(op, no_fields, rec->aRef()))
- ERR_RETURN(op->getNdbError());
+ ERR_RETURN(op->getNdbError());
}
else
{
int res;
if ((res= set_primary_key_from_old_data(op, old_data)))
- DBUG_RETURN(res);
+ DBUG_RETURN(res);
}
}
+ m_rows_changed++;
+
// Set non-key attribute(s)
- for (i= 0; i < table->fields; i++)
+ for (i= 0; i < table->s->fields; i++)
{
Field *field= table->field[i];
if (((thd->query_id == field->query_id) || m_retrieve_all_fields) &&
(!(field->flags & PRI_KEY_FLAG)) &&
- set_ndb_value(op, field, i))
+ set_ndb_value(op, field, i))
ERR_RETURN(op->getNdbError());
}
@@ -2147,12 +2246,14 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
int ha_ndbcluster::delete_row(const byte *record)
{
- NdbConnection *trans= m_active_trans;
- NdbResultSet* cursor= m_active_cursor;
+ THD *thd= current_thd;
+ NdbTransaction *trans= m_active_trans;
+ NdbScanOperation* cursor= m_active_cursor;
NdbOperation *op;
DBUG_ENTER("delete_row");
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_delete_count,&LOCK_status);
+ m_rows_changed++;
if (cursor)
{
@@ -2164,7 +2265,7 @@ int ha_ndbcluster::delete_row(const byte *record)
the active record in cursor
*/
DBUG_PRINT("info", ("Calling deleteTuple on cursor"));
- if (cursor->deleteTuple() != 0)
+ if (cursor->deleteCurrentTuple() != 0)
ERR_RETURN(trans->getNdbError());
m_ops_pending++;
@@ -2178,32 +2279,32 @@ int ha_ndbcluster::delete_row(const byte *record)
{
if (!(op=trans->getNdbOperation((const NDBTAB *) m_table)) ||
- op->deleteTuple() != 0)
+ op->deleteTuple() != 0)
ERR_RETURN(trans->getNdbError());
no_uncommitted_rows_update(-1);
- if (table->primary_key == MAX_KEY)
+ if (table->s->primary_key == MAX_KEY)
{
// This table has no primary key, use "hidden" primary key
DBUG_PRINT("info", ("Using hidden key"));
- uint no_fields= table->fields;
- NdbRecAttr* rec= m_value[no_fields].rec;
+ uint no_fields= table->s->fields;
+ const NdbRecAttr* rec= m_value[no_fields].rec;
DBUG_ASSERT(rec != NULL);
if (set_hidden_key(op, no_fields, rec->aRef()))
- ERR_RETURN(op->getNdbError());
+ ERR_RETURN(op->getNdbError());
}
else
{
int res;
if ((res= (m_primary_key_update ?
- set_primary_key_from_old_data(op, record)
- : set_primary_key(op))))
- return res;
+ set_primary_key_from_old_data(op, record)
+ : set_primary_key(op))))
+ return res;
}
}
-
+
// Execute delete operation
if (execute_no_commit(this,trans) != 0) {
no_uncommitted_rows_execute_failure();
@@ -2217,7 +2318,7 @@ int ha_ndbcluster::delete_row(const byte *record)
SYNOPSIS
unpack_record()
- buf Buffer to store read row
+ buf Buffer to store read row
NOTE
The data for each row is read directly into the
@@ -2232,10 +2333,12 @@ void ha_ndbcluster::unpack_record(byte* buf)
Field **field, **end;
NdbValue *value= m_value;
DBUG_ENTER("unpack_record");
+
+ end= table->field + table->s->fields;
// Set null flag(s)
- bzero(buf, table->null_bytes);
- for (field= table->field, end= field+table->fields;
+ bzero(buf, table->s->null_bytes);
+ for (field= table->field;
field < end;
field++, value++)
{
@@ -2245,33 +2348,54 @@ void ha_ndbcluster::unpack_record(byte* buf)
{
if ((*value).rec->isNULL())
(*field)->set_null(row_offset);
+ else if ((*field)->type() == MYSQL_TYPE_BIT)
+ {
+ uint pack_len= (*field)->pack_length();
+ if (pack_len < 5)
+ {
+ DBUG_PRINT("info", ("bit field H'%.8X",
+ (*value).rec->u_32_value()));
+ ((Field_bit *) *field)->store((longlong)
+ (*value).rec->u_32_value());
+ }
+ else
+ {
+ DBUG_PRINT("info", ("bit field H'%.8X%.8X",
+ *(Uint32 *)(*value).rec->aRef(),
+ *((Uint32 *)(*value).rec->aRef()+1)));
+ ((Field_bit *) *field)->store((longlong)
+ (*value).rec->u_64_value()); }
+ }
}
else
{
NdbBlob* ndb_blob= (*value).blob;
bool isNull= TRUE;
- int ret= ndb_blob->getNull(isNull);
+#ifndef DBUG_OFF
+ int ret=
+#endif
+ ndb_blob->getNull(isNull);
DBUG_ASSERT(ret == 0);
if (isNull)
- (*field)->set_null(row_offset);
+ (*field)->set_null(row_offset);
}
}
}
-
+
#ifndef DBUG_OFF
// Read and print all values that was fetched
- if (table->primary_key == MAX_KEY)
+ if (table->s->primary_key == MAX_KEY)
{
// Table with hidden primary key
- int hidden_no= table->fields;
+ int hidden_no= table->s->fields;
const NDBTAB *tab= (const NDBTAB *) m_table;
const NDBCOL *hidden_col= tab->getColumn(hidden_no);
- NdbRecAttr* rec= m_value[hidden_no].rec;
+ const NdbRecAttr* rec= m_value[hidden_no].rec;
DBUG_ASSERT(rec);
DBUG_PRINT("hidden", ("%d: %s \"%llu\"", hidden_no,
hidden_col->getName(), rec->u_64_value()));
}
- print_results();
+ //print_results();
#endif
DBUG_VOID_RETURN;
}
@@ -2282,166 +2406,61 @@ void ha_ndbcluster::unpack_record(byte* buf)
void ha_ndbcluster::print_results()
{
- const NDBTAB *tab= (const NDBTAB*) m_table;
DBUG_ENTER("print_results");
#ifndef DBUG_OFF
+ const NDBTAB *tab= (const NDBTAB*) m_table;
+
if (!_db_on_)
DBUG_VOID_RETURN;
-
- for (uint f=0; f<table->fields;f++)
+
+ char buf_type[MAX_FIELD_WIDTH], buf_val[MAX_FIELD_WIDTH];
+ String type(buf_type, sizeof(buf_type), &my_charset_bin);
+ String val(buf_val, sizeof(buf_val), &my_charset_bin);
+ for (uint f= 0; f < table->s->fields; f++)
{
+ /* Use DBUG_PRINT since DBUG_FILE cannot be filtered out */
+ char buf[2000];
Field *field;
- const NDBCOL *col;
+ void* ptr;
NdbValue value;
+ buf[0]= 0;
+ field= table->field[f];
if (!(value= m_value[f]).ptr)
{
- fprintf(DBUG_FILE, "Field %d was not read\n", f);
- continue;
+ my_snprintf(buf, sizeof(buf), "not read");
+ goto print_value;
}
- field= table->field[f];
- DBUG_DUMP("field->ptr", (char*)field->ptr, field->pack_length());
- col= tab->getColumn(f);
- fprintf(DBUG_FILE, "%d: %s\t", f, col->getName());
- NdbBlob *ndb_blob= NULL;
+ ptr= field->ptr;
+
if (! (field->flags & BLOB_FLAG))
{
if (value.rec->isNULL())
{
- fprintf(DBUG_FILE, "NULL\n");
- continue;
+ my_snprintf(buf, sizeof(buf), "NULL");
+ goto print_value;
}
+ type.length(0);
+ val.length(0);
+ field->sql_type(type);
+ field->val_str(&val);
+ my_snprintf(buf, sizeof(buf), "%s %s", type.c_ptr(), val.c_ptr());
}
else
{
- ndb_blob= value.blob;
+ NdbBlob *ndb_blob= value.blob;
bool isNull= TRUE;
ndb_blob->getNull(isNull);
if (isNull) {
- fprintf(DBUG_FILE, "NULL\n");
- continue;
+ my_snprintf(buf, sizeof(buf), "NULL");
+ goto print_value;
}
}
- switch (col->getType()) {
- case NdbDictionary::Column::Tinyint: {
- char value= *field->ptr;
- fprintf(DBUG_FILE, "Tinyint\t%d", value);
- break;
- }
- case NdbDictionary::Column::Tinyunsigned: {
- unsigned char value= *field->ptr;
- fprintf(DBUG_FILE, "Tinyunsigned\t%u", value);
- break;
- }
- case NdbDictionary::Column::Smallint: {
- short value= *field->ptr;
- fprintf(DBUG_FILE, "Smallint\t%d", value);
- break;
- }
- case NdbDictionary::Column::Smallunsigned: {
- unsigned short value= *field->ptr;
- fprintf(DBUG_FILE, "Smallunsigned\t%u", value);
- break;
- }
- case NdbDictionary::Column::Mediumint: {
- byte value[3];
- memcpy(value, field->ptr, 3);
- fprintf(DBUG_FILE, "Mediumint\t%d,%d,%d", value[0], value[1], value[2]);
- break;
- }
- case NdbDictionary::Column::Mediumunsigned: {
- byte value[3];
- memcpy(value, field->ptr, 3);
- fprintf(DBUG_FILE, "Mediumunsigned\t%u,%u,%u", value[0], value[1], value[2]);
- break;
- }
- case NdbDictionary::Column::Int: {
- fprintf(DBUG_FILE, "Int\t%lld", field->val_int());
- break;
- }
- case NdbDictionary::Column::Unsigned: {
- Uint32 value= (Uint32) *field->ptr;
- fprintf(DBUG_FILE, "Unsigned\t%u", value);
- break;
- }
- case NdbDictionary::Column::Bigint: {
- Int64 value= (Int64) *field->ptr;
- fprintf(DBUG_FILE, "Bigint\t%lld", value);
- break;
- }
- case NdbDictionary::Column::Bigunsigned: {
- Uint64 value= (Uint64) *field->ptr;
- fprintf(DBUG_FILE, "Bigunsigned\t%llu", value);
- break;
- }
- case NdbDictionary::Column::Float: {
- float value= (float) *field->ptr;
- fprintf(DBUG_FILE, "Float\t%f", value);
- break;
- }
- case NdbDictionary::Column::Double: {
- double value= (double) *field->ptr;
- fprintf(DBUG_FILE, "Double\t%f", value);
- break;
- }
- case NdbDictionary::Column::Olddecimal: {
- char *value= field->ptr;
- fprintf(DBUG_FILE, "Olddecimal\t'%-*s'", field->pack_length(), value);
- break;
- }
- case NdbDictionary::Column::Olddecimalunsigned: {
- char *value= field->ptr;
- fprintf(DBUG_FILE, "Olddecimalunsigned\t'%-*s'", field->pack_length(), value);
- break;
- }
- case NdbDictionary::Column::Char:{
- const char *value= (char *) field->ptr;
- fprintf(DBUG_FILE, "Char\t'%.*s'", field->pack_length(), value);
- break;
- }
- case NdbDictionary::Column::Varchar:
- case NdbDictionary::Column::Binary:
- case NdbDictionary::Column::Varbinary: {
- const char *value= (char *) field->ptr;
- fprintf(DBUG_FILE, "Var\t'%.*s'", field->pack_length(), value);
- break;
- }
- case NdbDictionary::Column::Datetime: {
- Uint64 value= (Uint64) *field->ptr;
- fprintf(DBUG_FILE, "Datetime\t%llu", value);
- break;
- }
- case NdbDictionary::Column::Date: {
- Uint64 value= (Uint64) *field->ptr;
- fprintf(DBUG_FILE, "Date\t%llu", value);
- break;
- }
- case NdbDictionary::Column::Time: {
- Uint64 value= (Uint64) *field->ptr;
- fprintf(DBUG_FILE, "Time\t%llu", value);
- break;
- }
- case NdbDictionary::Column::Blob: {
- Uint64 len= 0;
- ndb_blob->getLength(len);
- fprintf(DBUG_FILE, "Blob\t[len=%u]", (unsigned)len);
- break;
- }
- case NdbDictionary::Column::Text: {
- Uint64 len= 0;
- ndb_blob->getLength(len);
- fprintf(DBUG_FILE, "Text\t[len=%u]", (unsigned)len);
- break;
- }
- case NdbDictionary::Column::Undefined:
- fprintf(DBUG_FILE, "Unknown type: %d", col->getType());
- break;
- }
- fprintf(DBUG_FILE, "\n");
-
+print_value:
+ DBUG_PRINT("value", ("%u,%s: %s", f, field->field_name, buf));
}
#endif
DBUG_VOID_RETURN;
@@ -2450,7 +2469,7 @@ void ha_ndbcluster::print_results()
int ha_ndbcluster::index_init(uint index)
{
- DBUG_ENTER("index_init");
+ DBUG_ENTER("ha_ndbcluster::index_init");
DBUG_PRINT("enter", ("index: %u", index));
DBUG_RETURN(handler::index_init(index));
}
@@ -2458,7 +2477,7 @@ int ha_ndbcluster::index_init(uint index)
int ha_ndbcluster::index_end()
{
- DBUG_ENTER("index_end");
+ DBUG_ENTER("ha_ndbcluster::index_end");
DBUG_RETURN(close_scan());
}
@@ -2470,7 +2489,7 @@ int
check_null_in_key(const KEY* key_info, const byte *key, uint key_len)
{
KEY_PART_INFO *curr_part, *end_part;
- const byte* end_ptr = key + key_len;
+ const byte* end_ptr= key + key_len;
curr_part= key_info->key_part;
end_part= curr_part + key_info->key_parts;
@@ -2486,23 +2505,23 @@ check_null_in_key(const KEY* key_info, const byte *key, uint key_len)
}
int ha_ndbcluster::index_read(byte *buf,
- const byte *key, uint key_len,
- enum ha_rkey_function find_flag)
+ const byte *key, uint key_len,
+ enum ha_rkey_function find_flag)
{
- DBUG_ENTER("index_read");
+ DBUG_ENTER("ha_ndbcluster::index_read");
DBUG_PRINT("enter", ("active_index: %u, key_len: %u, find_flag: %d",
active_index, key_len, find_flag));
int error;
- ndb_index_type type = get_index_type(active_index);
- const KEY* key_info = table->key_info+active_index;
+ ndb_index_type type= get_index_type(active_index);
+ const KEY* key_info= table->key_info+active_index;
switch (type){
case PRIMARY_KEY_ORDERED_INDEX:
case PRIMARY_KEY_INDEX:
if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len)
{
if(m_active_cursor && (error= close_scan()))
- DBUG_RETURN(error);
+ DBUG_RETURN(error);
DBUG_RETURN(pk_read(key, key_len, buf));
}
else if (type == PRIMARY_KEY_INDEX)
@@ -2513,10 +2532,10 @@ int ha_ndbcluster::index_read(byte *buf,
case UNIQUE_ORDERED_INDEX:
case UNIQUE_INDEX:
if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len &&
- !check_null_in_key(key_info, key, key_len))
+ !check_null_in_key(key_info, key, key_len))
{
if(m_active_cursor && (error= close_scan()))
- DBUG_RETURN(error);
+ DBUG_RETURN(error);
DBUG_RETURN(unique_index_read(key, key_len, buf));
}
else if (type == UNIQUE_INDEX)
@@ -2534,20 +2553,31 @@ int ha_ndbcluster::index_read(byte *buf,
}
key_range start_key;
- start_key.key = key;
- start_key.length = key_len;
- start_key.flag = find_flag;
- error= ordered_index_scan(&start_key, 0, TRUE, buf);
+ start_key.key= key;
+ start_key.length= key_len;
+ start_key.flag= find_flag;
+ bool descending= FALSE;
+ switch (find_flag) {
+ case HA_READ_KEY_OR_PREV:
+ case HA_READ_BEFORE_KEY:
+ case HA_READ_PREFIX_LAST:
+ case HA_READ_PREFIX_LAST_OR_PREV:
+ descending= TRUE;
+ break;
+ default:
+ break;
+ }
+ error= ordered_index_scan(&start_key, 0, TRUE, descending, buf);
DBUG_RETURN(error == HA_ERR_END_OF_FILE ? HA_ERR_KEY_NOT_FOUND : error);
}
int ha_ndbcluster::index_read_idx(byte *buf, uint index_no,
- const byte *key, uint key_len,
- enum ha_rkey_function find_flag)
+ const byte *key, uint key_len,
+ enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
- DBUG_ENTER("index_read_idx");
+ statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
+ DBUG_ENTER("ha_ndbcluster::index_read_idx");
DBUG_PRINT("enter", ("index_no: %u, key_len: %u", index_no, key_len));
index_init(index_no);
DBUG_RETURN(index_read(buf, key, key_len, find_flag));
@@ -2556,72 +2586,68 @@ int ha_ndbcluster::index_read_idx(byte *buf, uint index_no,
int ha_ndbcluster::index_next(byte *buf)
{
- DBUG_ENTER("index_next");
-
- int error= 1;
- statistic_increment(ha_read_next_count,&LOCK_status);
+ DBUG_ENTER("ha_ndbcluster::index_next");
+ statistic_increment(current_thd->status_var.ha_read_next_count,
+ &LOCK_status);
DBUG_RETURN(next_result(buf));
}
int ha_ndbcluster::index_prev(byte *buf)
{
- DBUG_ENTER("index_prev");
- statistic_increment(ha_read_prev_count,&LOCK_status);
- DBUG_RETURN(1);
+ DBUG_ENTER("ha_ndbcluster::index_prev");
+ statistic_increment(current_thd->status_var.ha_read_prev_count,
+ &LOCK_status);
+ DBUG_RETURN(next_result(buf));
}
int ha_ndbcluster::index_first(byte *buf)
{
- DBUG_ENTER("index_first");
- statistic_increment(ha_read_first_count,&LOCK_status);
+ DBUG_ENTER("ha_ndbcluster::index_first");
+ statistic_increment(current_thd->status_var.ha_read_first_count,
+ &LOCK_status);
// Start the ordered index scan and fetch the first row
// Only HA_READ_ORDER indexes get called by index_first
- DBUG_RETURN(ordered_index_scan(0, 0, TRUE, buf));
+ DBUG_RETURN(ordered_index_scan(0, 0, TRUE, FALSE, buf));
}
int ha_ndbcluster::index_last(byte *buf)
{
- DBUG_ENTER("index_last");
- statistic_increment(ha_read_last_count,&LOCK_status);
- int res;
- if((res= ordered_index_scan(0, 0, TRUE, buf)) == 0){
- NdbResultSet *cursor= m_active_cursor;
- while((res= cursor->nextResult(TRUE, m_force_send)) == 0);
- if(res == 1){
- unpack_record(buf);
- table->status= 0;
- DBUG_RETURN(0);
- }
- }
- DBUG_RETURN(res);
+ DBUG_ENTER("ha_ndbcluster::index_last");
+ statistic_increment(current_thd->status_var.ha_read_last_count,&LOCK_status);
+ DBUG_RETURN(ordered_index_scan(0, 0, TRUE, TRUE, buf));
}
+int ha_ndbcluster::index_read_last(byte * buf, const byte * key, uint key_len)
+{
+ DBUG_ENTER("ha_ndbcluster::index_read_last");
+ DBUG_RETURN(index_read(buf, key, key_len, HA_READ_PREFIX_LAST));
+}
inline
int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
- const key_range *end_key,
- bool eq_range, bool sorted,
- byte* buf)
+ const key_range *end_key,
+ bool eq_r, bool sorted,
+ byte* buf)
{
KEY* key_info;
int error= 1;
DBUG_ENTER("ha_ndbcluster::read_range_first_to_buf");
- DBUG_PRINT("info", ("eq_range: %d, sorted: %d", eq_range, sorted));
+ DBUG_PRINT("info", ("eq_r: %d, sorted: %d", eq_r, sorted));
switch (get_index_type(active_index)){
case PRIMARY_KEY_ORDERED_INDEX:
case PRIMARY_KEY_INDEX:
key_info= table->key_info + active_index;
if (start_key &&
- start_key->length == key_info->key_length &&
- start_key->flag == HA_READ_KEY_EXACT)
+ start_key->length == key_info->key_length &&
+ start_key->flag == HA_READ_KEY_EXACT)
{
if(m_active_cursor && (error= close_scan()))
- DBUG_RETURN(error);
+ 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);
}
@@ -2630,11 +2656,11 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
case UNIQUE_INDEX:
key_info= table->key_info + active_index;
if (start_key && start_key->length == key_info->key_length &&
- start_key->flag == HA_READ_KEY_EXACT &&
- !check_null_in_key(key_info, start_key->key, start_key->length))
+ 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()))
- DBUG_RETURN(error);
+ 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);
}
@@ -2644,23 +2670,23 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
}
// Start the ordered index scan and fetch the first row
- error= ordered_index_scan(start_key, end_key, sorted, buf);
+ error= ordered_index_scan(start_key, end_key, sorted, FALSE, buf);
DBUG_RETURN(error);
}
int ha_ndbcluster::read_range_first(const key_range *start_key,
- const key_range *end_key,
- bool eq_range, bool sorted)
+ const key_range *end_key,
+ bool eq_r, bool sorted)
{
byte* buf= table->record[0];
DBUG_ENTER("ha_ndbcluster::read_range_first");
DBUG_RETURN(read_range_first_to_buf(start_key,
- end_key,
- eq_range,
- sorted,
- buf));
+ end_key,
+ eq_r,
+ sorted,
+ buf));
}
int ha_ndbcluster::read_range_next()
@@ -2672,7 +2698,7 @@ int ha_ndbcluster::read_range_next()
int ha_ndbcluster::rnd_init(bool scan)
{
- NdbResultSet *cursor= m_active_cursor;
+ NdbScanOperation *cursor= m_active_cursor;
DBUG_ENTER("rnd_init");
DBUG_PRINT("enter", ("scan: %d", scan));
// Check if scan is to be restarted
@@ -2680,22 +2706,26 @@ int ha_ndbcluster::rnd_init(bool scan)
{
if (!scan)
DBUG_RETURN(1);
- int res= cursor->restart(m_force_send);
- DBUG_ASSERT(res == 0);
+ if(cursor->restart(m_force_send) != 0)
+ {
+ DBUG_ASSERT(0);
+ DBUG_RETURN(-1);
+ }
}
- index_init(table->primary_key);
+ index_init(table->s->primary_key);
DBUG_RETURN(0);
}
int ha_ndbcluster::close_scan()
{
- NdbResultSet *cursor= m_active_cursor;
- NdbConnection *trans= m_active_trans;
+ NdbTransaction *trans= m_active_trans;
DBUG_ENTER("close_scan");
- if (!cursor)
+ m_multi_cursor= 0;
+ if (!m_active_cursor && !m_multi_cursor)
DBUG_RETURN(1);
+ NdbScanOperation *cursor= m_active_cursor ? m_active_cursor : m_multi_cursor;
if (m_ops_pending)
{
@@ -2711,8 +2741,8 @@ int ha_ndbcluster::close_scan()
m_ops_pending= 0;
}
- cursor->close(m_force_send);
- m_active_cursor= NULL;
+ cursor->close(m_force_send, true);
+ m_active_cursor= m_multi_cursor= NULL;
DBUG_RETURN(0);
}
@@ -2726,7 +2756,8 @@ int ha_ndbcluster::rnd_end()
int ha_ndbcluster::rnd_next(byte *buf)
{
DBUG_ENTER("rnd_next");
- statistic_increment(ha_read_rnd_next_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
if (!m_active_cursor)
DBUG_RETURN(full_table_scan(buf));
@@ -2744,7 +2775,8 @@ int ha_ndbcluster::rnd_next(byte *buf)
int ha_ndbcluster::rnd_pos(byte *buf, byte *pos)
{
DBUG_ENTER("rnd_pos");
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_count,
+ &LOCK_status);
// The primary key for the record is stored in pos
// Perform a pk_read using primary key "index"
DBUG_RETURN(pk_read(pos, ref_length, buf));
@@ -2765,9 +2797,9 @@ void ha_ndbcluster::position(const byte *record)
byte *buff;
DBUG_ENTER("position");
- if (table->primary_key != MAX_KEY)
+ if (table->s->primary_key != MAX_KEY)
{
- key_info= table->key_info + table->primary_key;
+ key_info= table->key_info + table->s->primary_key;
key_part= key_info->key_part;
end= key_part + key_info->key_parts;
buff= ref;
@@ -2791,15 +2823,17 @@ void ha_ndbcluster::position(const byte *record)
{
// No primary key, get hidden key
DBUG_PRINT("info", ("Getting hidden key"));
- int hidden_no= table->fields;
- NdbRecAttr* rec= m_value[hidden_no].rec;
+ int hidden_no= table->s->fields;
+ const NdbRecAttr* rec= m_value[hidden_no].rec;
+ memcpy(ref, (const void*)rec->aRef(), ref_length);
+#ifndef DBUG_OFF
const NDBTAB *tab= (const NDBTAB *) m_table;
const NDBCOL *hidden_col= tab->getColumn(hidden_no);
DBUG_ASSERT(hidden_col->getPrimaryKey() &&
hidden_col->getAutoIncrement() &&
rec != NULL &&
ref_length == NDB_HIDDEN_PRIMARY_KEY_LENGTH);
- memcpy(ref, (const void*)rec->aRef(), ref_length);
+#endif
}
DBUG_DUMP("ref", (char*)ref, ref_length);
@@ -2824,19 +2858,28 @@ void ha_ndbcluster::info(uint flag)
if (m_table_info)
{
if (m_ha_not_exact_count)
- records= 100;
+ records= 100;
else
- records_update();
+ records_update();
}
else
{
if ((my_errno= check_ndb_connection()))
DBUG_VOID_RETURN;
Ndb *ndb= get_ndb();
- Uint64 rows= 100;
- if (current_thd->variables.ndb_use_exact_count)
- ndb_get_table_statistics(ndb, m_tabname, &rows, 0);
- records= rows;
+ struct Ndb_statistics stat;
+ if (current_thd->variables.ndb_use_exact_count &&
+ ndb_get_table_statistics(ndb, m_tabname, &stat) == 0)
+ {
+ mean_rec_length= stat.row_size;
+ data_file_length= stat.fragment_memory;
+ records= stat.row_count;
+ }
+ else
+ {
+ mean_rec_length= 0;
+ records= 100;
+ }
}
}
if (flag & HA_STATUS_CONST)
@@ -2867,6 +2910,8 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
break;
case HA_EXTRA_RESET: /* Reset database to after open */
DBUG_PRINT("info", ("HA_EXTRA_RESET"));
+ DBUG_PRINT("info", ("Clearing condition stack"));
+ cond_clear();
break;
case HA_EXTRA_CACHE: /* Cash record in HA_rrnd() */
DBUG_PRINT("info", ("HA_EXTRA_CACHE"));
@@ -2953,8 +2998,8 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
m_ignore_dup_key= FALSE;
break;
case HA_EXTRA_RETRIEVE_ALL_COLS: /* Retrieve all columns, not just those
- where field->query_id is the same as
- the current query id */
+ where field->query_id is the same as
+ the current query id */
DBUG_PRINT("info", ("HA_EXTRA_RETRIEVE_ALL_COLS"));
m_retrieve_all_fields= TRUE;
break;
@@ -2976,6 +3021,8 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
break;
case HA_EXTRA_CHANGE_KEY_TO_DUP:
DBUG_PRINT("info", ("HA_EXTRA_CHANGE_KEY_TO_DUP"));
+ case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
+ DBUG_PRINT("info", ("HA_EXTRA_KEYREAD_PRESERVE_FIELDS"));
break;
}
@@ -3036,7 +3083,7 @@ int ha_ndbcluster::end_bulk_insert()
// Check if last inserts need to be flushed
if (m_bulk_insert_not_flushed)
{
- NdbConnection *trans= m_active_trans;
+ NdbTransaction *trans= m_active_trans;
// Send rows to NDB
DBUG_PRINT("info", ("Sending inserts to NDB, "\
"rows_inserted:%d, bulk_insert_rows: %d",
@@ -3061,19 +3108,16 @@ int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size)
DBUG_RETURN(extra(operation));
}
+static const char *ha_ndbcluster_exts[] = {
+ ha_ndb_ext,
+ NullS
+};
-int ha_ndbcluster::reset()
+const char** ha_ndbcluster::bas_ext() const
{
- DBUG_ENTER("reset");
- // Reset what?
- DBUG_RETURN(1);
+ return ha_ndbcluster_exts;
}
-static const char *ha_ndb_bas_exts[]= { ha_ndb_ext, NullS };
-const char **ha_ndbcluster::bas_ext() const
-{ return ha_ndb_bas_exts; }
-
-
/*
How many seeks it will take to read through the table
This is to be comparable to the number returned by records_in_range so
@@ -3085,7 +3129,7 @@ double ha_ndbcluster::scan_time()
DBUG_ENTER("ha_ndbcluster::scan_time()");
double res= rows2double(records*1000);
DBUG_PRINT("exit", ("table: %s value: %f",
- m_tabname, res));
+ m_tabname, res));
DBUG_RETURN(res);
}
@@ -3144,9 +3188,9 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
As MySQL will execute an external lock for every new table it uses
we can use this to start the transactions.
If we are in auto_commit mode we just need to start a transaction
- for the statement, this will be stored in transaction.stmt.
+ for the statement, this will be stored in thd_ndb.stmt.
If not, we have to start a master transaction if there doesn't exist
- one from before, this will be stored in transaction.all
+ one from before, this will be stored in thd_ndb.all
When a table lock is held one transaction will be started which holds
the table lock and for each statement a hupp transaction will be started
@@ -3159,21 +3203,21 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
int ha_ndbcluster::external_lock(THD *thd, int lock_type)
{
int error=0;
- NdbConnection* trans= NULL;
+ NdbTransaction* trans= NULL;
DBUG_ENTER("external_lock");
/*
Check that this handler instance has a connection
set up to the Ndb object of thd
*/
- if (check_ndb_connection())
+ if (check_ndb_connection(thd))
DBUG_RETURN(1);
-
- Thd_ndb *thd_ndb= (Thd_ndb*)thd->transaction.thd_ndb;
+
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
Ndb *ndb= thd_ndb->ndb;
- DBUG_PRINT("enter", ("transaction.thd_ndb->lock_count: %d",
- thd_ndb->lock_count));
+ DBUG_PRINT("enter", ("thd: %x, thd_ndb: %x, thd_ndb->lock_count: %d",
+ thd, thd_ndb, thd_ndb->lock_count));
if (lock_type != F_UNLCK)
{
@@ -3181,23 +3225,23 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
if (!thd_ndb->lock_count++)
{
PRINT_OPTION_FLAGS(thd);
-
if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN | OPTION_TABLE_LOCK)))
{
// Autocommit transaction
- DBUG_ASSERT(!thd->transaction.stmt.ndb_tid);
+ DBUG_ASSERT(!thd_ndb->stmt);
DBUG_PRINT("trans",("Starting transaction stmt"));
trans= ndb->startTransaction();
if (trans == NULL)
ERR_RETURN(ndb->getNdbError());
- no_uncommitted_rows_reset(thd);
- thd->transaction.stmt.ndb_tid= trans;
+ no_uncommitted_rows_reset(thd);
+ thd_ndb->stmt= trans;
+ trans_register_ha(thd, FALSE, &ndbcluster_hton);
}
else
{
- if (!thd->transaction.all.ndb_tid)
- {
+ if (!thd_ndb->all)
+ {
// Not autocommit transaction
// A "master" transaction ha not been started yet
DBUG_PRINT("trans",("starting transaction, all"));
@@ -3205,7 +3249,9 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
trans= ndb->startTransaction();
if (trans == NULL)
ERR_RETURN(ndb->getNdbError());
- no_uncommitted_rows_reset(thd);
+ no_uncommitted_rows_reset(thd);
+ thd_ndb->all= trans;
+ trans_register_ha(thd, TRUE, &ndbcluster_hton);
/*
If this is the start of a LOCK TABLE, a table look
@@ -3214,12 +3260,11 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
Check if it should be read or write lock
*/
if (thd->options & (OPTION_TABLE_LOCK))
- {
+ {
//lockThisTable();
DBUG_PRINT("info", ("Locking the table..." ));
}
- thd->transaction.all.ndb_tid= trans;
}
}
}
@@ -3244,22 +3289,20 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
m_transaction_on= FALSE;
else
m_transaction_on= thd->variables.ndb_use_transactions;
- // m_use_local_query_cache= thd->variables.ndb_use_local_query_cache;
- m_active_trans= thd->transaction.all.ndb_tid ?
- (NdbConnection*)thd->transaction.all.ndb_tid:
- (NdbConnection*)thd->transaction.stmt.ndb_tid;
+ m_active_trans= thd_ndb->all ? thd_ndb->all : thd_ndb->stmt;
DBUG_ASSERT(m_active_trans);
// Start of transaction
+ m_rows_changed= 0;
m_retrieve_all_fields= FALSE;
m_retrieve_primary_key= FALSE;
- m_ops_pending= 0;
+ m_ops_pending= 0;
{
NDBDICT *dict= ndb->getDictionary();
const NDBTAB *tab;
void *tab_info;
if (!(tab= dict->getTable(m_tabname, &tab_info)))
- ERR_RETURN(dict->getNdbError());
+ ERR_RETURN(dict->getNdbError());
DBUG_PRINT("info", ("Table schema version: %d",
tab->getObjectVersion()));
// Check if thread has stale local cache
@@ -3283,16 +3326,34 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
m_table_info= tab_info;
}
no_uncommitted_rows_init(thd);
- }
- else
+ }
+ else
{
DBUG_PRINT("info", ("lock_type == F_UNLCK"));
+
+ if (ndb_cache_check_time && m_rows_changed)
+ {
+ DBUG_PRINT("info", ("Rows has changed and util thread is running"));
+ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ {
+ DBUG_PRINT("info", ("Add share to list of tables to be invalidated"));
+ /* NOTE push_back allocates memory using transactions mem_root! */
+ thd_ndb->changed_tables.push_back(m_share, &thd->transaction.mem_root);
+ }
+
+ pthread_mutex_lock(&m_share->mutex);
+ DBUG_PRINT("info", ("Invalidating commit_count"));
+ m_share->commit_count= 0;
+ m_share->commit_count_lock++;
+ pthread_mutex_unlock(&m_share->mutex);
+ }
+
if (!--thd_ndb->lock_count)
{
DBUG_PRINT("trans", ("Last external_lock"));
PRINT_OPTION_FLAGS(thd);
- if (thd->transaction.stmt.ndb_tid)
+ if (thd_ndb->stmt)
{
/*
Unlock is done without a transaction commit / rollback.
@@ -3301,10 +3362,11 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
*/
DBUG_PRINT("trans",("ending non-updating transaction"));
ndb->closeTransaction(m_active_trans);
- thd->transaction.stmt.ndb_tid= 0;
+ thd_ndb->stmt= NULL;
}
}
m_table_info= NULL;
+
/*
This is the place to make sure this handler instance
no longer are connected to the active transaction.
@@ -3318,6 +3380,10 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
DBUG_PRINT("warning", ("m_active_cursor != NULL"));
m_active_cursor= NULL;
+ if (m_multi_cursor)
+ DBUG_PRINT("warning", ("m_multi_cursor != NULL"));
+ m_multi_cursor= NULL;
+
if (m_blobs_pending)
DBUG_PRINT("warning", ("blobs_pending != 0"));
m_blobs_pending= 0;
@@ -3343,21 +3409,24 @@ int ha_ndbcluster::start_stmt(THD *thd)
DBUG_ENTER("start_stmt");
PRINT_OPTION_FLAGS(thd);
- NdbConnection *trans= (NdbConnection*)thd->transaction.stmt.ndb_tid;
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
+ NdbTransaction *trans= thd_ndb->stmt;
if (!trans){
- Ndb *ndb= ((Thd_ndb*)thd->transaction.thd_ndb)->ndb;
+ Ndb *ndb= thd_ndb->ndb;
DBUG_PRINT("trans",("Starting transaction stmt"));
-
- NdbConnection *tablock_trans=
- (NdbConnection*)thd->transaction.all.ndb_tid;
+
+#if 0
+ NdbTransaction *tablock_trans= thd_ndb->all;
DBUG_PRINT("info", ("tablock_trans: %x", (UintPtr)tablock_trans));
DBUG_ASSERT(tablock_trans);
// trans= ndb->hupp(tablock_trans);
+#endif
trans= ndb->startTransaction();
if (trans == NULL)
ERR_RETURN(ndb->getNdbError());
no_uncommitted_rows_reset(thd);
- thd->transaction.stmt.ndb_tid= trans;
+ thd_ndb->stmt= trans;
+ trans_register_ha(thd, FALSE, &ndbcluster_hton);
}
m_active_trans= trans;
@@ -3371,18 +3440,19 @@ int ha_ndbcluster::start_stmt(THD *thd)
/*
- Commit a transaction started in NDB
+ Commit a transaction started in NDB
*/
-int ndbcluster_commit(THD *thd, void *ndb_transaction)
+int ndbcluster_commit(THD *thd, bool all)
{
int res= 0;
- Ndb *ndb= ((Thd_ndb*)thd->transaction.thd_ndb)->ndb;
- NdbConnection *trans= (NdbConnection*)ndb_transaction;
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
+ Ndb *ndb= thd_ndb->ndb;
+ NdbTransaction *trans= all ? thd_ndb->all : thd_ndb->stmt;
DBUG_ENTER("ndbcluster_commit");
DBUG_PRINT("transaction",("%s",
- trans == thd->transaction.stmt.ndb_tid ?
+ trans == thd_ndb->stmt ?
"stmt" : "all"));
DBUG_ASSERT(ndb && trans);
@@ -3390,12 +3460,31 @@ int ndbcluster_commit(THD *thd, void *ndb_transaction)
{
const NdbError err= trans->getNdbError();
const NdbOperation *error_op= trans->getNdbErrorOperation();
- ERR_PRINT(err);
+ ERR_PRINT(err);
res= ndb_to_mysql_error(&err);
- if (res != -1)
+ if (res != -1)
ndbcluster_print_error(res, error_op);
}
ndb->closeTransaction(trans);
+
+ if(all)
+ thd_ndb->all= NULL;
+ else
+ thd_ndb->stmt= NULL;
+
+ /* Clear commit_count for tables changed by transaction */
+ NDB_SHARE* share;
+ List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
+ while ((share= it++))
+ {
+ pthread_mutex_lock(&share->mutex);
+ DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %d ", share->table_name, share->commit_count));
+ share->commit_count= 0;
+ share->commit_count_lock++;
+ pthread_mutex_unlock(&share->mutex);
+ }
+ thd_ndb->changed_tables.empty();
+
DBUG_RETURN(res);
}
@@ -3404,19 +3493,20 @@ int ndbcluster_commit(THD *thd, void *ndb_transaction)
Rollback a transaction started in NDB
*/
-int ndbcluster_rollback(THD *thd, void *ndb_transaction)
+int ndbcluster_rollback(THD *thd, bool all)
{
int res= 0;
- Ndb *ndb= ((Thd_ndb*)thd->transaction.thd_ndb)->ndb;
- NdbConnection *trans= (NdbConnection*)ndb_transaction;
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
+ Ndb *ndb= thd_ndb->ndb;
+ NdbTransaction *trans= all ? thd_ndb->all : thd_ndb->stmt;
DBUG_ENTER("ndbcluster_rollback");
DBUG_PRINT("transaction",("%s",
- trans == thd->transaction.stmt.ndb_tid ?
+ trans == thd_ndb->stmt ?
"stmt" : "all"));
DBUG_ASSERT(ndb && trans);
- if (trans->execute(Rollback) != 0)
+ if (trans->execute(NdbTransaction::Rollback) != 0)
{
const NdbError err= trans->getNdbError();
const NdbOperation *error_op= trans->getNdbErrorOperation();
@@ -3426,7 +3516,16 @@ int ndbcluster_rollback(THD *thd, void *ndb_transaction)
ndbcluster_print_error(res, error_op);
}
ndb->closeTransaction(trans);
- DBUG_RETURN(0);
+
+ if(all)
+ thd_ndb->all= NULL;
+ else
+ thd_ndb->stmt= NULL;
+
+ /* Clear list of tables changed by transaction */
+ thd_ndb->changed_tables.empty();
+
+ DBUG_RETURN(res);
}
@@ -3434,6 +3533,9 @@ int ndbcluster_rollback(THD *thd, void *ndb_transaction)
Define NDB column based on Field.
Returns 0 or mysql error code.
Not member of ha_ndbcluster because NDBCOL cannot be declared.
+
+ MySQL text types with character set "binary" are mapped to true
+ NDB binary types without a character set. This may change.
*/
static int create_ndb_column(NDBCOL &col,
@@ -3516,6 +3618,24 @@ static int create_ndb_column(NDBCOL &col,
col.setLength(1);
}
break;
+ case MYSQL_TYPE_NEWDECIMAL:
+ {
+ Field_new_decimal *f= (Field_new_decimal*)field;
+ uint precision= f->field_length;
+ uint scale= f->decimals();
+ if (field->flags & UNSIGNED_FLAG)
+ {
+ col.setType(NDBCOL::Decimalunsigned);
+ }
+ else
+ {
+ col.setType(NDBCOL::Decimal);
+ }
+ col.setPrecision(precision);
+ col.setScale(scale);
+ col.setLength(1);
+ }
+ break;
// Date types
case MYSQL_TYPE_DATETIME:
col.setType(NDBCOL::Datetime);
@@ -3543,30 +3663,56 @@ static int create_ndb_column(NDBCOL &col,
break;
// Char types
case MYSQL_TYPE_STRING:
- if (field->flags & BINARY_FLAG)
+ if (field->pack_length() == 0)
+ {
+ col.setType(NDBCOL::Bit);
+ col.setLength(1);
+ }
+ else if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
+ {
col.setType(NDBCOL::Binary);
- else {
- col.setType(NDBCOL::Char);
- col.setCharset(cs);
+ col.setLength(field->pack_length());
}
- if (field->pack_length() == 0)
- col.setLength(1); // currently ndb does not support size 0
else
+ {
+ col.setType(NDBCOL::Char);
+ col.setCharset(cs);
col.setLength(field->pack_length());
+ }
break;
- case MYSQL_TYPE_VAR_STRING:
- if (field->flags & BINARY_FLAG)
- col.setType(NDBCOL::Varbinary);
- else {
- col.setType(NDBCOL::Varchar);
- col.setCharset(cs);
+ case MYSQL_TYPE_VAR_STRING: // ?
+ case MYSQL_TYPE_VARCHAR:
+ {
+ Field_varstring* f= (Field_varstring*)field;
+ if (f->length_bytes == 1)
+ {
+ if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
+ col.setType(NDBCOL::Varbinary);
+ else {
+ col.setType(NDBCOL::Varchar);
+ col.setCharset(cs);
+ }
+ }
+ else if (f->length_bytes == 2)
+ {
+ if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
+ col.setType(NDBCOL::Longvarbinary);
+ else {
+ col.setType(NDBCOL::Longvarchar);
+ col.setCharset(cs);
+ }
+ }
+ else
+ {
+ return HA_ERR_UNSUPPORTED;
+ }
+ col.setLength(field->field_length);
}
- col.setLength(field->pack_length());
break;
// Blob types (all come in as MYSQL_TYPE_BLOB)
mysql_type_tiny_blob:
case MYSQL_TYPE_TINY_BLOB:
- if (field->flags & BINARY_FLAG)
+ if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
col.setType(NDBCOL::Blob);
else {
col.setType(NDBCOL::Text);
@@ -3577,9 +3723,9 @@ static int create_ndb_column(NDBCOL &col,
col.setPartSize(0);
col.setStripeSize(0);
break;
- mysql_type_blob:
+ //mysql_type_blob:
case MYSQL_TYPE_BLOB:
- if (field->flags & BINARY_FLAG)
+ if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
col.setType(NDBCOL::Blob);
else {
col.setType(NDBCOL::Text);
@@ -3601,7 +3747,7 @@ static int create_ndb_column(NDBCOL &col,
break;
mysql_type_medium_blob:
case MYSQL_TYPE_MEDIUM_BLOB:
- if (field->flags & BINARY_FLAG)
+ if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
col.setType(NDBCOL::Blob);
else {
col.setType(NDBCOL::Text);
@@ -3613,7 +3759,7 @@ static int create_ndb_column(NDBCOL &col,
break;
mysql_type_long_blob:
case MYSQL_TYPE_LONG_BLOB:
- if (field->flags & BINARY_FLAG)
+ if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
col.setType(NDBCOL::Blob);
else {
col.setType(NDBCOL::Text);
@@ -3632,6 +3778,15 @@ static int create_ndb_column(NDBCOL &col,
col.setType(NDBCOL::Char);
col.setLength(field->pack_length());
break;
+ 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)
+ col.setLength(1);
+ else
+ col.setLength(no_of_bits);
+ break;
+ }
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_GEOMETRY:
goto mysql_type_unsupported;
@@ -3662,7 +3817,7 @@ static int create_ndb_column(NDBCOL &col,
static void ndb_set_fragmentation(NDBTAB &tab, TABLE *form, uint pk_length)
{
- if (form->max_rows == (ha_rows) 0) /* default setting, don't set fragmentation */
+ if (form->s->max_rows == (ha_rows) 0) /* default setting, don't set fragmentation */
return;
/**
* get the number of fragments right
@@ -3680,12 +3835,12 @@ static void ndb_set_fragmentation(NDBTAB &tab, TABLE *form, uint pk_length)
acc_row_size+= 4 + /*safety margin*/ 4;
#endif
ulonglong acc_fragment_size= 512*1024*1024;
- ulonglong max_rows= form->max_rows;
+ ulonglong max_rows= form->s->max_rows;
#if MYSQL_VERSION_ID >= 50100
no_fragments= (max_rows*acc_row_size)/acc_fragment_size+1;
#else
no_fragments= ((max_rows*acc_row_size)/acc_fragment_size+1
- +1/*correct rounding*/)/2;
+ +1/*correct rounding*/)/2;
#endif
}
{
@@ -3695,8 +3850,8 @@ static void ndb_set_fragmentation(NDBTAB &tab, TABLE *form, uint pk_length)
{
ftype= NDBTAB::FragAllLarge;
if (no_fragments > 4*no_nodes)
- push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
- "Ndb might have problems storing the max amount of rows specified");
+ push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
+ "Ndb might have problems storing the max amount of rows specified");
}
else if (no_fragments > no_nodes)
ftype= NDBTAB::FragAllMedium;
@@ -3707,18 +3862,17 @@ static void ndb_set_fragmentation(NDBTAB &tab, TABLE *form, uint pk_length)
}
int ha_ndbcluster::create(const char *name,
- TABLE *form,
- HA_CREATE_INFO *info)
+ TABLE *form,
+ HA_CREATE_INFO *info)
{
NDBTAB tab;
NDBCOL col;
uint pack_length, length, i, pk_length= 0;
const void *data, *pack_data;
- const char **key_names= form->keynames.type_names;
char name2[FN_HEADLEN];
bool create_from_engine= (info->table_options & HA_CREATE_FROM_ENGINE);
- DBUG_ENTER("create");
+ DBUG_ENTER("ha_ndbcluster::create");
DBUG_PRINT("enter", ("name: %s", name));
fn_format(name2, name, "", "",2); // Remove the .frm extension
set_dbname(name2);
@@ -3750,12 +3904,12 @@ int ha_ndbcluster::create(const char *name,
my_free((char*)data, MYF(0));
my_free((char*)pack_data, MYF(0));
- for (i= 0; i < form->fields; i++)
+ for (i= 0; i < form->s->fields; i++)
{
Field *field= form->field[i];
DBUG_PRINT("info", ("name: %s, type: %u, pack_length: %d",
field->field_name, field->real_type(),
- field->pack_length()));
+ field->pack_length()));
if ((my_errno= create_ndb_column(col, field, info)))
DBUG_RETURN(my_errno);
tab.addColumn(col);
@@ -3764,7 +3918,7 @@ int ha_ndbcluster::create(const char *name,
}
// No primary key, create shadow key as 64 bit, auto increment
- if (form->primary_key == MAX_KEY)
+ if (form->s->primary_key == MAX_KEY)
{
DBUG_PRINT("info", ("Generating shadow key"));
col.setName("$PK");
@@ -3778,7 +3932,7 @@ int ha_ndbcluster::create(const char *name,
}
// Make sure that blob tables don't have to big part size
- for (i= 0; i < form->fields; i++)
+ for (i= 0; i < form->s->fields; i++)
{
/**
* The extra +7 concists
@@ -3790,13 +3944,13 @@ int ha_ndbcluster::create(const char *name,
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
{
- NdbDictionary::Column * col = tab.getColumn(i);
- int size = pk_length + (col->getPartSize()+3)/4 + 7;
+ NdbDictionary::Column * col= tab.getColumn(i);
+ int size= pk_length + (col->getPartSize()+3)/4 + 7;
if(size > NDB_MAX_TUPLE_SIZE_IN_WORDS &&
- (pk_length+7) < 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;
- col->setPartSize(4*size);
+ size= NDB_MAX_TUPLE_SIZE_IN_WORDS - pk_length - 7;
+ col->setPartSize(4*size);
}
/**
* If size > NDB_MAX and pk_length+7 >= NDB_MAX
@@ -3838,17 +3992,17 @@ int ha_ndbcluster::create(const char *name,
int ha_ndbcluster::create_ordered_index(const char *name,
- KEY *key_info)
+ KEY *key_info)
{
- DBUG_ENTER("create_ordered_index");
+ DBUG_ENTER("ha_ndbcluster::create_ordered_index");
DBUG_RETURN(create_index(name, key_info, FALSE));
}
int ha_ndbcluster::create_unique_index(const char *name,
- KEY *key_info)
+ KEY *key_info)
{
- DBUG_ENTER("create_unique_index");
+ DBUG_ENTER("ha_ndbcluster::create_unique_index");
DBUG_RETURN(create_index(name, key_info, TRUE));
}
@@ -3858,15 +4012,15 @@ int ha_ndbcluster::create_unique_index(const char *name,
*/
int ha_ndbcluster::create_index(const char *name,
- KEY *key_info,
- bool unique)
+ KEY *key_info,
+ bool unique)
{
Ndb *ndb= get_ndb();
NdbDictionary::Dictionary *dict= ndb->getDictionary();
KEY_PART_INFO *key_part= key_info->key_part;
KEY_PART_INFO *end= key_part + key_info->key_parts;
- DBUG_ENTER("create_index");
+ DBUG_ENTER("ha_ndbcluster::create_index");
DBUG_PRINT("enter", ("name: %s ", name));
NdbDictionary::Index ndb_index(name);
@@ -3920,7 +4074,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
if (check_ndb_connection())
DBUG_RETURN(my_errno= HA_ERR_NO_CONNECTION);
-
+
Ndb *ndb= get_ndb();
dict= ndb->getDictionary();
if (!(orig_tab= dict->getTable(m_tabname)))
@@ -3955,7 +4109,6 @@ int ha_ndbcluster::alter_table_name(const char *to)
Ndb *ndb= get_ndb();
NDBDICT *dict= ndb->getDictionary();
const NDBTAB *orig_tab= (const NDBTAB *) m_table;
- int ret;
DBUG_ENTER("alter_table_name_table");
NdbDictionary::Table new_tab= *orig_tab;
@@ -3971,66 +4124,66 @@ int ha_ndbcluster::alter_table_name(const char *to)
/*
- Delete a table from NDB Cluster
+ Delete table from NDB Cluster
+
*/
int ha_ndbcluster::delete_table(const char *name)
{
- DBUG_ENTER("delete_table");
+ DBUG_ENTER("ha_ndbcluster::delete_table");
DBUG_PRINT("enter", ("name: %s", name));
set_dbname(name);
set_tabname(name);
-
+
if (check_ndb_connection())
DBUG_RETURN(HA_ERR_NO_CONNECTION);
- // Remove .ndb file
+
+ /* Call ancestor function to delete .ndb file */
handler::delete_table(name);
+
+ /* Drop the table from NDB */
DBUG_RETURN(drop_table());
}
/*
- Drop a table in NDB Cluster
+ Drop table in NDB Cluster
*/
int ha_ndbcluster::drop_table()
{
Ndb *ndb= get_ndb();
NdbDictionary::Dictionary *dict= ndb->getDictionary();
-
+
DBUG_ENTER("drop_table");
DBUG_PRINT("enter", ("Deleting %s", m_tabname));
-
- if (dict->dropTable(m_tabname))
- {
- const NdbError err= dict->getNdbError();
- if (err.code == 709)
- ; // 709: No such table existed
- else
- ERR_RETURN(dict->getNdbError());
- }
+
release_metadata();
+ if (dict->dropTable(m_tabname))
+ ERR_RETURN(dict->getNdbError());
DBUG_RETURN(0);
}
-longlong ha_ndbcluster::get_auto_increment()
+ulonglong ha_ndbcluster::get_auto_increment()
{
+ int cache_size;
+ Uint64 auto_value;
DBUG_ENTER("get_auto_increment");
DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
Ndb *ndb= get_ndb();
-
+
if (m_rows_inserted > m_rows_to_insert)
/* We guessed too low */
m_rows_to_insert+= m_autoincrement_prefetch;
- int cache_size=
+ 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;
- Uint64 auto_value= NDB_FAILED_AUTO_INCREMENT;
+ auto_value= NDB_FAILED_AUTO_INCREMENT;
uint retries= NDB_AUTO_INCREMENT_RETRIES;
do {
auto_value=
@@ -4058,9 +4211,11 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
m_table_version(-1),
m_table_info(NULL),
m_table_flags(HA_REC_NOT_IN_SEQ |
- HA_NULL_IN_KEY |
- HA_AUTO_PART_KEY |
- HA_NO_PREFIX_CHAR_KEYS),
+ HA_NULL_IN_KEY |
+ HA_AUTO_PART_KEY |
+ HA_NO_PREFIX_CHAR_KEYS |
+ HA_NEED_READ_RANGE_BUFFER |
+ HA_CAN_BIT_FIELD),
m_share(0),
m_use_write(FALSE),
m_ignore_dup_key(FALSE),
@@ -4070,6 +4225,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
m_rows_to_insert((ha_rows) 1),
m_rows_inserted((ha_rows) 0),
m_bulk_insert_rows((ha_rows) 1024),
+ m_rows_changed((ha_rows) 0),
m_bulk_insert_not_flushed(FALSE),
m_ops_pending(0),
m_skip_auto_increment(TRUE),
@@ -4081,10 +4237,11 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
m_force_send(TRUE),
m_autoincrement_prefetch((ha_rows) 32),
m_transaction_on(TRUE),
- m_use_local_query_cache(FALSE)
-{
+ m_cond_stack(NULL),
+ m_multi_cursor(NULL)
+{
int i;
-
+
DBUG_ENTER("ha_ndbcluster");
m_tabname[0]= '\0';
@@ -4127,10 +4284,15 @@ ha_ndbcluster::~ha_ndbcluster()
}
DBUG_ASSERT(m_active_trans == NULL);
+ // Discard the condition stack
+ DBUG_PRINT("info", ("Clearing condition stack"));
+ cond_clear();
+
DBUG_VOID_RETURN;
}
+
/*
Open a table for further use
- fetch metadata for this table from NDB
@@ -4148,9 +4310,9 @@ int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked)
// Setup ref_length to make room for the whole
// primary key to be written in the ref variable
- if (table->primary_key != MAX_KEY)
+ if (table->s->primary_key != MAX_KEY)
{
- key= table->key_info+table->primary_key;
+ key= table->key_info+table->s->primary_key;
ref_length= key->key_length;
DBUG_PRINT("info", (" ref_length: %d", ref_length));
}
@@ -4231,23 +4393,20 @@ void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb)
Ndb* check_ndb_in_thd(THD* thd)
{
- DBUG_ENTER("check_ndb_in_thd");
- Thd_ndb *thd_ndb= (Thd_ndb*)thd->transaction.thd_ndb;
-
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
if (!thd_ndb)
{
if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
- DBUG_RETURN(NULL);
- thd->transaction.thd_ndb= thd_ndb;
+ return NULL;
+ set_thd_ndb(thd, thd_ndb);
}
- DBUG_RETURN(thd_ndb->ndb);
+ return thd_ndb->ndb;
}
-int ha_ndbcluster::check_ndb_connection()
+int ha_ndbcluster::check_ndb_connection(THD* thd)
{
- THD* thd= current_thd;
Ndb *ndb;
DBUG_ENTER("check_ndb_connection");
@@ -4258,16 +4417,16 @@ int ha_ndbcluster::check_ndb_connection()
}
-void ndbcluster_close_connection(THD *thd)
+int ndbcluster_close_connection(THD *thd)
{
- Thd_ndb *thd_ndb= (Thd_ndb*)thd->transaction.thd_ndb;
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
DBUG_ENTER("ndbcluster_close_connection");
if (thd_ndb)
{
ha_ndbcluster::release_thd_ndb(thd_ndb);
- thd->transaction.thd_ndb= NULL;
+ set_thd_ndb(thd, NULL); // not strictly required but does not hurt either
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(0);
}
@@ -4276,7 +4435,7 @@ void ndbcluster_close_connection(THD *thd)
*/
int ndbcluster_discover(THD* thd, const char *db, const char *name,
- const void** frmblob, uint* frmlen)
+ const void** frmblob, uint* frmlen)
{
uint len;
const void* data;
@@ -4320,33 +4479,31 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name,
/*
Check if a table exists in NDB
-
+
*/
int ndbcluster_table_exists(THD* thd, const char *db, const char *name)
{
- uint len;
- const void* data;
const NDBTAB* tab;
Ndb* ndb;
DBUG_ENTER("ndbcluster_table_exists");
- DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
+ DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
if (!(ndb= check_ndb_in_thd(thd)))
- DBUG_RETURN(HA_ERR_NO_CONNECTION);
+ DBUG_RETURN(HA_ERR_NO_CONNECTION);
ndb->setDatabaseName(db);
NDBDICT* dict= ndb->getDictionary();
dict->set_local_table_data_size(sizeof(Ndb_local_table_statistics));
dict->invalidateTable(name);
if (!(tab= dict->getTable(name)))
- {
+ {
const NdbError err= dict->getNdbError();
if (err.code == 709)
DBUG_RETURN(0);
ERR_RETURN(err);
}
-
+
DBUG_PRINT("info", ("Found table %s", tab->getName()));
DBUG_RETURN(1);
}
@@ -4354,7 +4511,7 @@ int ndbcluster_table_exists(THD* thd, const char *db, const char *name)
extern "C" byte* tables_get_key(const char *entry, uint *length,
- my_bool not_used __attribute__((unused)))
+ my_bool not_used __attribute__((unused)))
{
*length= strlen(entry);
return (byte*) entry;
@@ -4418,7 +4575,7 @@ int ndbcluster_drop_database(const char *path)
int ndbcluster_find_files(THD *thd,const char *db,const char *path,
- const char *wild, bool dir, List<char> *files)
+ const char *wild, bool dir, List<char> *files)
{
DBUG_ENTER("ndbcluster_find_files");
DBUG_PRINT("enter", ("db: %s", db));
@@ -4438,18 +4595,18 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
// List tables in NDB
NDBDICT *dict= ndb->getDictionary();
if (dict->listObjects(list,
- NdbDictionary::Object::UserTable) != 0)
+ NdbDictionary::Object::UserTable) != 0)
ERR_RETURN(dict->getNdbError());
if (hash_init(&ndb_tables, system_charset_info,list.count,0,0,
- (hash_get_key)tables_get_key,0,0))
+ (hash_get_key)tables_get_key,0,0))
{
DBUG_PRINT("error", ("Failed to init HASH ndb_tables"));
DBUG_RETURN(-1);
}
if (hash_init(&ok_tables, system_charset_info,32,0,0,
- (hash_get_key)tables_get_key,0,0))
+ (hash_get_key)tables_get_key,0,0))
{
DBUG_PRINT("error", ("Failed to init HASH ok_tables"));
hash_free(&ndb_tables);
@@ -4470,11 +4627,11 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
{
if (lower_case_table_names)
{
- if (wild_case_compare(files_charset_info, t.name, wild))
- continue;
+ if (wild_case_compare(files_charset_info, t.name, wild))
+ continue;
}
else if (wild_compare(t.name,wild,0))
- continue;
+ continue;
}
DBUG_PRINT("info", ("Inserting %s into ndb_tables hash", t.name));
my_hash_insert(&ndb_tables, (byte*)thd->strdup(t.name));
@@ -4496,7 +4653,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
// File is not in NDB, check for .ndb file with this name
(void)strxnmov(name, FN_REFLEN,
- mysql_data_home,"/",db,"/",file_name,ha_ndb_ext,NullS);
+ mysql_data_home,"/",db,"/",file_name,ha_ndb_ext,NullS);
DBUG_PRINT("info", ("Check access for %s", name));
if (access(name, F_OK))
{
@@ -4540,17 +4697,20 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
// Delete old files
List_iterator_fast<char> it3(delete_list);
while ((file_name=it3++))
- {
- DBUG_PRINT("info", ("Remove table %s/%s",db, file_name ));
+ {
+ DBUG_PRINT("info", ("Remove table %s/%s", db, file_name));
// Delete the table and all related files
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
table_list.db= (char*) db;
- table_list.alias=table_list.real_name=(char*)file_name;
- (void)mysql_rm_table_part2(thd, &table_list,
- /* if_exists */ TRUE,
- /* drop_temporary */ FALSE,
- /* dont_log_query*/ TRUE);
+ table_list.alias= table_list.table_name= (char*)file_name;
+ (void)mysql_rm_table_part2(thd, &table_list,
+ /* if_exists */ FALSE,
+ /* drop_temporary */ FALSE,
+ /* drop_view */ FALSE,
+ /* dont_log_query*/ TRUE);
+ /* Clear error message that is returned when table is deleted */
+ thd->clear_error();
}
}
@@ -4577,7 +4737,15 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
a NDB Cluster table handler
*/
-bool ndbcluster_init()
+/* Call back after cluster connect */
+static int connect_callback()
+{
+ update_status_variables(g_ndb_cluster_connection);
+ return 0;
+}
+
+handlerton *
+ndbcluster_init()
{
int res;
DBUG_ENTER("ndbcluster_init");
@@ -4588,7 +4756,7 @@ bool ndbcluster_init()
new Ndb_cluster_connection(opt_ndbcluster_connectstring)) == 0)
{
DBUG_PRINT("error",("Ndb_cluster_connection(%s)",
- opt_ndbcluster_connectstring));
+ opt_ndbcluster_connectstring));
goto ndbcluster_init_error;
}
@@ -4596,7 +4764,11 @@ bool ndbcluster_init()
(opt_ndb_optimized_node_selection);
// Create a Ndb object to open the connection to NDB
- g_ndb= new Ndb(g_ndb_cluster_connection, "sys");
+ if ( (g_ndb= new Ndb(g_ndb_cluster_connection, "sys")) == 0 )
+ {
+ DBUG_PRINT("error", ("failed to create global ndb object"));
+ goto ndbcluster_init_error;
+ }
g_ndb->getDictionary()->set_local_table_data_size(sizeof(Ndb_local_table_statistics));
if (g_ndb->init() != 0)
{
@@ -4606,22 +4778,29 @@ bool ndbcluster_init()
if ((res= g_ndb_cluster_connection->connect(0,0,0)) == 0)
{
+ connect_callback();
DBUG_PRINT("info",("NDBCLUSTER storage engine at %s on port %d",
- g_ndb_cluster_connection->get_connected_host(),
- g_ndb_cluster_connection->get_connected_port()));
+ g_ndb_cluster_connection->get_connected_host(),
+ g_ndb_cluster_connection->get_connected_port()));
g_ndb_cluster_connection->wait_until_ready(10,3);
}
else if(res == 1)
{
- if (g_ndb_cluster_connection->start_connect_thread()) {
+ if (g_ndb_cluster_connection->start_connect_thread(connect_callback))
+ {
DBUG_PRINT("error", ("g_ndb_cluster_connection->start_connect_thread()"));
goto ndbcluster_init_error;
}
+#ifndef DBUG_OFF
{
char buf[1024];
- DBUG_PRINT("info",("NDBCLUSTER storage engine not started, will connect using %s",
- g_ndb_cluster_connection->get_connectstring(buf,sizeof(buf))));
+ DBUG_PRINT("info",
+ ("NDBCLUSTER storage engine not started, "
+ "will connect using %s",
+ g_ndb_cluster_connection->
+ get_connectstring(buf,sizeof(buf))));
}
+#endif
}
else
{
@@ -4633,38 +4812,66 @@ bool ndbcluster_init()
(void) hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0,
(hash_get_key) ndbcluster_get_key,0,0);
pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&COND_ndb_util_thread, NULL);
+
+ // Create utility thread
+ pthread_t tmp;
+ if (pthread_create(&tmp, &connection_attrib, ndb_util_thread_func, 0))
+ {
+ DBUG_PRINT("error", ("Could not create ndb utility thread"));
+ hash_free(&ndbcluster_open_tables);
+ pthread_mutex_destroy(&ndbcluster_mutex);
+ pthread_mutex_destroy(&LOCK_ndb_util_thread);
+ pthread_cond_destroy(&COND_ndb_util_thread);
+ goto ndbcluster_init_error;
+ }
+
ndbcluster_inited= 1;
-#ifdef USE_DISCOVER_ON_STARTUP
- if (ndb_discover_tables() != 0)
- goto ndbcluster_init_error;
-#endif
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(&ndbcluster_hton);
+
ndbcluster_init_error:
- ndbcluster_end();
- DBUG_RETURN(TRUE);
+ if(g_ndb)
+ delete g_ndb;
+ g_ndb= NULL;
+ if (g_ndb_cluster_connection)
+ delete g_ndb_cluster_connection;
+ g_ndb_cluster_connection= NULL;
+ DBUG_RETURN(NULL);
}
/*
End use of the NDB Cluster table handler
- free all global variables allocated by
- ndcluster_init()
+ ndbcluster_init()
*/
bool ndbcluster_end()
{
DBUG_ENTER("ndbcluster_end");
+
+ if (!ndbcluster_inited)
+ DBUG_RETURN(0);
+
+ // Kill ndb utility thread
+ (void) pthread_mutex_lock(&LOCK_ndb_util_thread);
+ DBUG_PRINT("exit",("killing ndb util thread: %lx", ndb_util_thread));
+ (void) pthread_cond_signal(&COND_ndb_util_thread);
+ (void) pthread_mutex_unlock(&LOCK_ndb_util_thread);
+
if(g_ndb)
delete g_ndb;
g_ndb= NULL;
if (g_ndb_cluster_connection)
delete g_ndb_cluster_connection;
g_ndb_cluster_connection= NULL;
- if (!ndbcluster_inited)
- DBUG_RETURN(0);
+
hash_free(&ndbcluster_open_tables);
pthread_mutex_destroy(&ndbcluster_mutex);
+ pthread_mutex_destroy(&LOCK_ndb_util_thread);
+ pthread_cond_destroy(&COND_ndb_util_thread);
ndbcluster_inited= 0;
DBUG_RETURN(0);
}
@@ -4680,7 +4887,7 @@ void ndbcluster_print_error(int error, const NdbOperation *error_op)
DBUG_ENTER("ndbcluster_print_error");
TABLE tab;
const char *tab_name= (error_op) ? error_op->getTableName() : "";
- tab.table_name= (char *) tab_name;
+ tab.alias= (char *) tab_name;
ha_ndbcluster error_handler(&tab);
tab.file= &error_handler;
error_handler.print_error(error, MYF(0));
@@ -4845,16 +5052,216 @@ const char* ha_ndbcluster::index_type(uint key_number)
return "HASH";
}
}
+
uint8 ha_ndbcluster::table_cache_type()
{
- if (m_use_local_query_cache)
- return HA_CACHE_TBL_TRANSACT;
+ DBUG_ENTER("ha_ndbcluster::table_cache_type=HA_CACHE_TBL_ASKTRANSACT");
+ DBUG_RETURN(HA_CACHE_TBL_ASKTRANSACT);
+}
+
+
+uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
+ Uint64 *commit_count)
+{
+ DBUG_ENTER("ndb_get_commitcount");
+
+ char name[FN_REFLEN];
+ NDB_SHARE *share;
+ (void)strxnmov(name, FN_REFLEN, "./",dbname,"/",tabname,NullS);
+ DBUG_PRINT("enter", ("name: %s", name));
+ pthread_mutex_lock(&ndbcluster_mutex);
+ if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables,
+ (byte*) name,
+ strlen(name))))
+ {
+ pthread_mutex_unlock(&ndbcluster_mutex);
+ DBUG_PRINT("info", ("Table %s not found in ndbcluster_open_tables",
+ name));
+ DBUG_RETURN(1);
+ }
+ share->use_count++;
+ pthread_mutex_unlock(&ndbcluster_mutex);
+
+ pthread_mutex_lock(&share->mutex);
+ if (ndb_cache_check_time > 0)
+ {
+ if (share->commit_count != 0)
+ {
+ *commit_count= share->commit_count;
+ DBUG_PRINT("info", ("Getting commit_count: %llu from share",
+ share->commit_count));
+ pthread_mutex_unlock(&share->mutex);
+ free_share(share);
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_PRINT("info", ("Get commit_count from NDB"));
+ Ndb *ndb;
+ if (!(ndb= check_ndb_in_thd(thd)))
+ DBUG_RETURN(1);
+ ndb->setDatabaseName(dbname);
+ uint lock= share->commit_count_lock;
+ pthread_mutex_unlock(&share->mutex);
+
+ struct Ndb_statistics stat;
+ if (ndb_get_table_statistics(ndb, tabname, &stat))
+ {
+ free_share(share);
+ DBUG_RETURN(1);
+ }
+
+ pthread_mutex_lock(&share->mutex);
+ if(share->commit_count_lock == lock)
+ {
+ DBUG_PRINT("info", ("Setting commit_count to %llu", stat.commit_count));
+ share->commit_count= stat.commit_count;
+ *commit_count= stat.commit_count;
+ }
else
- return HA_CACHE_TBL_NOCACHE;
+ {
+ DBUG_PRINT("info", ("Discarding commit_count, comit_count_lock changed"));
+ *commit_count= 0;
+ }
+ pthread_mutex_unlock(&share->mutex);
+ free_share(share);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Check if a cached query can be used.
+ This is done by comparing the supplied engine_data to commit_count of
+ the table.
+ The commit_count is either retrieved from the share for the table, where
+ it has been cached by the util thread. If the util thread is not started,
+ NDB has to be contacetd to retrieve the commit_count, this will introduce
+ a small delay while waiting for NDB to answer.
+
+
+ SYNOPSIS
+ ndbcluster_cache_retrieval_allowed
+ thd thread handle
+ full_name concatenation of database name,
+ the null character '\0', and the table
+ name
+ full_name_len length of the full name,
+ i.e. len(dbname) + len(tablename) + 1
+
+ engine_data parameter retrieved when query was first inserted into
+ the cache. If the value of engine_data is changed,
+ all queries for this table should be invalidated.
+
+ RETURN VALUE
+ TRUE Yes, use the query from cache
+ FALSE No, don't use the cached query, and if engine_data
+ has changed, all queries for this table should be invalidated
+
+*/
+
+static my_bool
+ndbcluster_cache_retrieval_allowed(THD *thd,
+ char *full_name, uint full_name_len,
+ ulonglong *engine_data)
+{
+ DBUG_ENTER("ndbcluster_cache_retrieval_allowed");
+
+ Uint64 commit_count;
+ bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
+ char *dbname= full_name;
+ char *tabname= dbname+strlen(dbname)+1;
+
+ DBUG_PRINT("enter", ("dbname: %s, tabname: %s, is_autocommit: %d",
+ dbname, tabname, is_autocommit));
+
+ if (!is_autocommit)
+ {
+ DBUG_PRINT("exit", ("No, don't use cache in transaction"));
+ DBUG_RETURN(FALSE);
+ }
+
+ if (ndb_get_commitcount(thd, dbname, tabname, &commit_count))
+ {
+ *engine_data= 0; /* invalidate */
+ DBUG_PRINT("exit", ("No, could not retrieve commit_count"));
+ DBUG_RETURN(FALSE);
+ }
+ DBUG_PRINT("info", ("*engine_data: %llu, commit_count: %llu",
+ *engine_data, commit_count));
+ if (commit_count == 0)
+ {
+ *engine_data= 0; /* invalidate */
+ DBUG_PRINT("exit", ("No, local commit has been performed"));
+ DBUG_RETURN(FALSE);
+ }
+ else if (*engine_data != commit_count)
+ {
+ *engine_data= commit_count; /* invalidate */
+ DBUG_PRINT("exit", ("No, commit_count has changed"));
+ DBUG_RETURN(FALSE);
+ }
+
+ DBUG_PRINT("exit", ("OK to use cache, engine_data: %llu", *engine_data));
+ DBUG_RETURN(TRUE);
+}
+
+
+/**
+ Register a table for use in the query cache. Fetch the commit_count
+ for the table and return it in engine_data, this will later be used
+ to check if the table has changed, before the cached query is reused.
+
+ SYNOPSIS
+ ha_ndbcluster::can_query_cache_table
+ thd thread handle
+ full_name concatenation of database name,
+ the null character '\0', and the table
+ name
+ full_name_len length of the full name,
+ i.e. len(dbname) + len(tablename) + 1
+ qc_engine_callback function to be called before using cache on this table
+ engine_data out, commit_count for this table
+
+ RETURN VALUE
+ TRUE Yes, it's ok to cahce this query
+ FALSE No, don't cach the query
+
+*/
+
+my_bool
+ha_ndbcluster::register_query_cache_table(THD *thd,
+ char *full_name, uint full_name_len,
+ qc_engine_callback *engine_callback,
+ ulonglong *engine_data)
+{
+ DBUG_ENTER("ha_ndbcluster::register_query_cache_table");
+
+ bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
+
+ DBUG_PRINT("enter",("dbname: %s, tabname: %s, is_autocommit: %d",
+ m_dbname, m_tabname, is_autocommit));
+
+ if (!is_autocommit)
+ {
+ DBUG_PRINT("exit", ("Can't register table during transaction"))
+ DBUG_RETURN(FALSE);
+ }
+
+ Uint64 commit_count;
+ if (ndb_get_commitcount(thd, m_dbname, m_tabname, &commit_count))
+ {
+ *engine_data= 0;
+ DBUG_PRINT("exit", ("Error, could not get commitcount"))
+ DBUG_RETURN(FALSE);
+ }
+ *engine_data= commit_count;
+ *engine_callback= ndbcluster_cache_retrieval_allowed;
+ DBUG_PRINT("exit", ("commit_count: %llu", commit_count));
+ DBUG_RETURN(commit_count > 0);
}
+
/*
- Handling the shared NDB_SHARE structure that is needed to
+ Handling the shared NDB_SHARE structure that is needed to
provide table locking.
It's also used for sharing data with other NDB handlers
in the same MySQL Server. There is currently not much
@@ -4862,7 +5269,7 @@ uint8 ha_ndbcluster::table_cache_type()
*/
static byte* ndbcluster_get_key(NDB_SHARE *share,uint *length,
- my_bool not_used __attribute__((unused)))
+ my_bool not_used __attribute__((unused)))
{
*length=share->table_name_length;
return (byte*) share->table_name;
@@ -4891,9 +5298,22 @@ static NDB_SHARE* get_share(const char *table_name)
}
thr_lock_init(&share->lock);
pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
+ share->commit_count= 0;
+ share->commit_count_lock= 0;
+ }
+ else
+ {
+ DBUG_PRINT("error", ("Failed to alloc share"));
+ pthread_mutex_unlock(&ndbcluster_mutex);
+ return 0;
}
}
share->use_count++;
+
+ DBUG_PRINT("share",
+ ("table_name: %s, length: %d, use_count: %d, commit_count: %d",
+ share->table_name, share->table_name_length, share->use_count,
+ share->commit_count));
pthread_mutex_unlock(&ndbcluster_mutex);
return share;
}
@@ -4904,7 +5324,7 @@ static void free_share(NDB_SHARE *share)
pthread_mutex_lock(&ndbcluster_mutex);
if (!--share->use_count)
{
- hash_delete(&ndbcluster_open_tables, (byte*) share);
+ hash_delete(&ndbcluster_open_tables, (byte*) share);
thr_lock_delete(&share->lock);
pthread_mutex_destroy(&share->mutex);
my_free((gptr) share, MYF(0));
@@ -4933,7 +5353,7 @@ struct frm_blob_struct
static int packfrm(const void *data, uint len,
- const void **pack_data, uint *pack_len)
+ const void **pack_data, uint *pack_len)
{
int error;
ulong org_len, comp_len;
@@ -4975,7 +5395,7 @@ err:
static int unpackfrm(const void **unpack_data, uint *unpack_len,
- const void *pack_data)
+ const void *pack_data)
{
const frm_blob_struct *blob= (frm_blob_struct*)pack_data;
byte *data;
@@ -4983,12 +5403,12 @@ static int unpackfrm(const void **unpack_data, uint *unpack_len,
DBUG_ENTER("unpackfrm");
DBUG_PRINT("enter", ("pack_data: %x", pack_data));
- complen= uint4korr((char*)&blob->head.complen);
- orglen= uint4korr((char*)&blob->head.orglen);
- ver= uint4korr((char*)&blob->head.ver);
+ complen= uint4korr((char*)&blob->head.complen);
+ orglen= uint4korr((char*)&blob->head.orglen);
+ ver= uint4korr((char*)&blob->head.ver);
DBUG_PRINT("blob",("ver: %d complen: %d orglen: %d",
- ver,complen,orglen));
+ ver,complen,orglen));
DBUG_DUMP("blob->data", (char*) blob->data, complen);
if (ver != 1)
@@ -5013,12 +5433,12 @@ static int unpackfrm(const void **unpack_data, uint *unpack_len,
static
int
-ndb_get_table_statistics(Ndb* ndb, const char * table,
- Uint64* row_count, Uint64* commit_count)
+ndb_get_table_statistics(Ndb* ndb, const char * table,
+ struct Ndb_statistics * ndbstat)
{
DBUG_ENTER("ndb_get_table_statistics");
DBUG_PRINT("enter", ("table: %s", table));
- NdbConnection* pTrans= ndb->startTransaction();
+ NdbTransaction* pTrans= ndb->startTransaction();
do
{
if (pTrans == NULL)
@@ -5028,41 +5448,58 @@ ndb_get_table_statistics(Ndb* ndb, const char * table,
if (pOp == NULL)
break;
- NdbResultSet* rs= pOp->readTuples(NdbOperation::LM_CommittedRead);
- if (rs == 0)
+ if (pOp->readTuples(NdbOperation::LM_CommittedRead))
break;
int check= pOp->interpret_exit_last_row();
if (check == -1)
break;
- Uint64 rows, commits;
+ Uint64 rows, commits, mem;
+ Uint32 size;
pOp->getValue(NdbDictionary::Column::ROW_COUNT, (char*)&rows);
pOp->getValue(NdbDictionary::Column::COMMIT_COUNT, (char*)&commits);
+ pOp->getValue(NdbDictionary::Column::ROW_SIZE, (char*)&size);
+ pOp->getValue(NdbDictionary::Column::FRAGMENT_MEMORY, (char*)&mem);
- check= pTrans->execute(NoCommit, AbortOnError, TRUE);
+ check= pTrans->execute(NdbTransaction::NoCommit,
+ NdbTransaction::AbortOnError,
+ TRUE);
if (check == -1)
break;
+ Uint32 count= 0;
Uint64 sum_rows= 0;
Uint64 sum_commits= 0;
- while((check= rs->nextResult(TRUE, TRUE)) == 0)
+ Uint64 sum_row_size= 0;
+ Uint64 sum_mem= 0;
+ while((check= pOp->nextResult(TRUE, TRUE)) == 0)
{
sum_rows+= rows;
sum_commits+= commits;
+ if (sum_row_size < size)
+ sum_row_size= size;
+ sum_mem+= mem;
+ count++;
}
if (check == -1)
break;
- rs->close(TRUE);
+ pOp->close(TRUE);
ndb->closeTransaction(pTrans);
- if(row_count)
- * row_count= sum_rows;
- if(commit_count)
- * commit_count= sum_commits;
- DBUG_PRINT("exit", ("records: %u commits: %u", sum_rows, sum_commits));
+
+ ndbstat->row_count= sum_rows;
+ ndbstat->commit_count= sum_commits;
+ ndbstat->row_size= sum_row_size;
+ ndbstat->fragment_memory= sum_mem;
+
+ DBUG_PRINT("exit", ("records: %llu commits: %llu "
+ "row_size: %llu mem: %llu count: %u",
+ sum_rows, sum_commits, sum_row_size,
+ sum_mem, count));
+
DBUG_RETURN(0);
} while(0);
@@ -5086,7 +5523,7 @@ int ha_ndbcluster::write_ndb_file()
DBUG_PRINT("enter", ("db: %s, name: %s", m_dbname, m_tabname));
(void)strxnmov(path, FN_REFLEN,
- mysql_data_home,"/",m_dbname,"/",m_tabname,ha_ndb_ext,NullS);
+ mysql_data_home,"/",m_dbname,"/",m_tabname,ha_ndb_ext,NullS);
if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
{
@@ -5097,4 +5534,1588 @@ int ha_ndbcluster::write_ndb_file()
DBUG_RETURN(error);
}
+int
+ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE *ranges,
+ uint range_count,
+ bool sorted,
+ HANDLER_BUFFER *buffer)
+{
+ DBUG_ENTER("ha_ndbcluster::read_multi_range_first");
+
+ int res;
+ KEY* key_info= table->key_info + active_index;
+ NDB_INDEX_TYPE index_type= get_index_type(active_index);
+ ulong reclength= table->s->reclength;
+ NdbOperation* op;
+
+ if (uses_blob_value(m_retrieve_all_fields))
+ {
+ /**
+ * blobs can't be batched currently
+ */
+ m_disable_multi_read= true;
+ DBUG_RETURN(handler::read_multi_range_first(found_range_p,
+ ranges,
+ range_count,
+ sorted,
+ buffer));
+ }
+
+ m_disable_multi_read= false;
+
+ /**
+ * Copy arguments into member variables
+ */
+ m_multi_ranges= ranges;
+ multi_range_curr= ranges;
+ multi_range_end= ranges+range_count;
+ multi_range_sorted= sorted;
+ multi_range_buffer= buffer;
+
+ /**
+ * read multi range will read ranges as follows (if not ordered)
+ *
+ * input read order
+ * ====== ==========
+ * pk-op 1 pk-op 1
+ * pk-op 2 pk-op 2
+ * range 3 range (3,5) NOTE result rows will be intermixed
+ * pk-op 4 pk-op 4
+ * range 5
+ * pk-op 6 pk-ok 6
+ */
+
+ /**
+ * Variables for loop
+ */
+ byte *curr= (byte*)buffer->buffer;
+ byte *end_of_buffer= (byte*)buffer->buffer_end;
+ NdbOperation::LockMode lm=
+ (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
+ const NDBTAB *tab= (const NDBTAB *) m_table;
+ const NDBINDEX *unique_idx= (NDBINDEX *) m_index[active_index].unique_index;
+ const NDBINDEX *idx= (NDBINDEX *) m_index[active_index].index;
+ const NdbOperation* lastOp= m_active_trans->getLastDefinedOperation();
+ NdbIndexScanOperation* scanOp= 0;
+ for(; multi_range_curr<multi_range_end && curr+reclength <= end_of_buffer;
+ multi_range_curr++)
+ {
+ switch(index_type){
+ case PRIMARY_KEY_INDEX:
+ pk:
+ {
+ multi_range_curr->range_flag |= UNIQUE_RANGE;
+ if ((op= m_active_trans->getNdbOperation(tab)) &&
+ !op->readTuple(lm) &&
+ !set_primary_key(op, multi_range_curr->start_key.key) &&
+ !define_read_attrs(curr, op) &&
+ (op->setAbortOption(AO_IgnoreError), true))
+ curr += reclength;
+ else
+ ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
+ break;
+ }
+ break;
+ case UNIQUE_INDEX:
+ sk:
+ {
+ multi_range_curr->range_flag |= UNIQUE_RANGE;
+ if ((op= m_active_trans->getNdbIndexOperation(unique_idx, tab)) &&
+ !op->readTuple(lm) &&
+ !set_index_key(op, key_info, multi_range_curr->start_key.key) &&
+ !define_read_attrs(curr, op) &&
+ (op->setAbortOption(AO_IgnoreError), true))
+ curr += reclength;
+ else
+ 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: {
+ range:
+ multi_range_curr->range_flag &= ~(uint)UNIQUE_RANGE;
+ if (scanOp == 0)
+ {
+ if (m_multi_cursor)
+ {
+ scanOp= m_multi_cursor;
+ 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))
+ DBUG_RETURN(ndb_err(m_active_trans));
+
+ end_of_buffer -= reclength;
+ }
+ else if ((scanOp= m_active_trans->getNdbIndexScanOperation(idx, tab))
+ &&!scanOp->readTuples(lm, 0, parallelism, sorted, false, true)
+ &&!generate_scan_filter(m_cond_stack, scanOp)
+ &&!define_read_attrs(end_of_buffer-reclength, scanOp))
+ {
+ m_multi_cursor= scanOp;
+ m_multi_range_cursor_result_ptr= end_of_buffer-reclength;
+ }
+ else
+ {
+ ERR_RETURN(scanOp ? scanOp->getNdbError() :
+ m_active_trans->getNdbError());
+ }
+ }
+
+ const key_range *keys[2]= { &multi_range_curr->start_key,
+ &multi_range_curr->end_key };
+ if ((res= set_bounds(scanOp, keys, multi_range_curr-ranges)))
+ DBUG_RETURN(res);
+ break;
+ }
+ case(UNDEFINED_INDEX):
+ DBUG_ASSERT(FALSE);
+ DBUG_RETURN(1);
+ break;
+ }
+ }
+
+ if (multi_range_curr != multi_range_end)
+ {
+ /**
+ * Mark that we're using entire buffer (even if might not) as
+ * we haven't read all ranges for some reason
+ * This as we don't want mysqld to reuse the buffer when we read
+ * the remaining ranges
+ */
+ buffer->end_of_used_area= (byte*)buffer->buffer_end;
+ }
+ else
+ {
+ buffer->end_of_used_area= curr;
+ }
+
+ /**
+ * Set first operation in multi range
+ */
+ m_current_multi_operation=
+ lastOp ? lastOp->next() : m_active_trans->getFirstDefinedOperation();
+ if (!(res= execute_no_commit_ie(this, m_active_trans)))
+ {
+ m_multi_range_defined= multi_range_curr;
+ multi_range_curr= ranges;
+ m_multi_range_result_ptr= (byte*)buffer->buffer;
+ DBUG_RETURN(read_multi_range_next(found_range_p));
+ }
+ ERR_RETURN(m_active_trans->getNdbError());
+}
+
+#if 0
+#define DBUG_MULTI_RANGE(x) printf("read_multi_range_next: case %d\n", x);
+#else
+#define DBUG_MULTI_RANGE(x)
+#endif
+
+int
+ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p)
+{
+ DBUG_ENTER("ha_ndbcluster::read_multi_range_next");
+ if (m_disable_multi_read)
+ {
+ DBUG_RETURN(handler::read_multi_range_next(multi_range_found_p));
+ }
+
+ int res;
+ int range_no;
+ ulong reclength= table->s->reclength;
+ const NdbOperation* op= m_current_multi_operation;
+ for(;multi_range_curr < m_multi_range_defined; multi_range_curr++)
+ {
+ if (multi_range_curr->range_flag & UNIQUE_RANGE)
+ {
+ if (op->getNdbError().code == 0)
+ goto found_next;
+
+ op= m_active_trans->getNextCompletedOperation(op);
+ m_multi_range_result_ptr += reclength;
+ continue;
+ }
+ else if (m_multi_cursor && !multi_range_sorted)
+ {
+ DBUG_MULTI_RANGE(1);
+ if ((res= fetch_next(m_multi_cursor)) == 0)
+ {
+ DBUG_MULTI_RANGE(2);
+ range_no= m_multi_cursor->get_range_no();
+ goto found;
+ }
+ else
+ {
+ goto close_scan;
+ }
+ }
+ else if (m_multi_cursor && multi_range_sorted)
+ {
+ if (m_active_cursor && (res= fetch_next(m_multi_cursor)))
+ {
+ DBUG_MULTI_RANGE(3);
+ goto close_scan;
+ }
+
+ range_no= m_multi_cursor->get_range_no();
+ uint current_range_no= multi_range_curr - m_multi_ranges;
+ if ((uint) range_no == current_range_no)
+ {
+ DBUG_MULTI_RANGE(4);
+ // return current row
+ goto found;
+ }
+ else if (range_no > (int)current_range_no)
+ {
+ DBUG_MULTI_RANGE(5);
+ // wait with current row
+ m_active_cursor= 0;
+ continue;
+ }
+ else
+ {
+ DBUG_MULTI_RANGE(6);
+ // First fetch from cursor
+ DBUG_ASSERT(range_no == -1);
+ if((res= m_multi_cursor->nextResult(true)))
+ {
+ goto close_scan;
+ }
+ multi_range_curr--; // Will be increased in for-loop
+ continue;
+ }
+ }
+ else /** m_multi_cursor == 0 */
+ {
+ DBUG_MULTI_RANGE(7);
+ /**
+ * Corresponds to range 5 in example in read_multi_range_first
+ */
+ (void)1;
+ continue;
+ }
+
+ DBUG_ASSERT(false); // Should only get here via goto's
+close_scan:
+ if (res == 1)
+ {
+ m_multi_cursor->close(false, true);
+ m_active_cursor= m_multi_cursor= 0;
+ DBUG_MULTI_RANGE(8);
+ continue;
+ }
+ else
+ {
+ DBUG_RETURN(ndb_err(m_active_trans));
+ }
+ }
+
+ if (multi_range_curr == multi_range_end)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ /**
+ * Read remaining ranges
+ */
+ DBUG_RETURN(read_multi_range_first(multi_range_found_p,
+ multi_range_curr,
+ multi_range_end - multi_range_curr,
+ multi_range_sorted,
+ multi_range_buffer));
+
+found:
+ /**
+ * Found a record belonging to a scan
+ */
+ m_active_cursor= m_multi_cursor;
+ * multi_range_found_p= m_multi_ranges + range_no;
+ memcpy(table->record[0], m_multi_range_cursor_result_ptr, reclength);
+ setup_recattr(m_active_cursor->getFirstRecAttr());
+ unpack_record(table->record[0]);
+ table->status= 0;
+ DBUG_RETURN(0);
+
+found_next:
+ /**
+ * Found a record belonging to a pk/index op,
+ * copy result and move to next to prepare for next call
+ */
+ * multi_range_found_p= multi_range_curr;
+ memcpy(table->record[0], m_multi_range_result_ptr, reclength);
+ setup_recattr(op->getFirstRecAttr());
+ unpack_record(table->record[0]);
+ table->status= 0;
+
+ multi_range_curr++;
+ m_current_multi_operation= m_active_trans->getNextCompletedOperation(op);
+ m_multi_range_result_ptr += reclength;
+ DBUG_RETURN(0);
+}
+
+int
+ha_ndbcluster::setup_recattr(const NdbRecAttr* curr)
+{
+ DBUG_ENTER("setup_recattr");
+
+ Field **field, **end;
+ NdbValue *value= m_value;
+
+ end= table->field + table->s->fields;
+
+ for (field= table->field; field < end; field++, value++)
+ {
+ if ((* value).ptr)
+ {
+ DBUG_ASSERT(curr != 0);
+ (* value).rec= curr;
+ curr= curr->next();
+ }
+ }
+
+ DBUG_RETURN(0);
+}
+
+char*
+ha_ndbcluster::update_table_comment(
+ /* out: table comment + additional */
+ const char* comment)/* in: table comment defined by user */
+{
+ uint length= strlen(comment);
+ if(length > 64000 - 3)
+ {
+ return((char*)comment); /* string too long */
+ }
+
+ Ndb* ndb;
+ if (!(ndb= get_ndb()))
+ {
+ return((char*)comment);
+ }
+
+ ndb->setDatabaseName(m_dbname);
+ NDBDICT* dict= ndb->getDictionary();
+ const NDBTAB* tab;
+ if (!(tab= dict->getTable(m_tabname)))
+ {
+ return((char*)comment);
+ }
+
+ char *str;
+ const char *fmt="%s%snumber_of_replicas: %d";
+ const unsigned fmt_len_plus_extra= length + strlen(fmt);
+ if ((str= my_malloc(fmt_len_plus_extra, MYF(0))) == NULL)
+ {
+ return (char*)comment;
+ }
+
+ snprintf(str,fmt_len_plus_extra,fmt,comment,
+ length > 0 ? " ":"",
+ tab->getReplicaCount());
+ return str;
+}
+
+
+// Utility thread main loop
+extern "C" pthread_handler_decl(ndb_util_thread_func,
+ arg __attribute__((unused)))
+{
+ THD *thd; /* needs to be first for thread_stack */
+ Ndb* ndb;
+ int error= 0;
+ struct timespec abstime;
+
+ my_thread_init();
+ DBUG_ENTER("ndb_util_thread");
+ DBUG_PRINT("enter", ("ndb_cache_check_time: %d", ndb_cache_check_time));
+
+ thd= new THD; /* note that contructor of THD uses DBUG_ */
+ THD_CHECK_SENTRY(thd);
+ ndb= new Ndb(g_ndb_cluster_connection, "");
+
+ pthread_detach_this_thread();
+ ndb_util_thread= pthread_self();
+
+ thd->thread_stack= (char*)&thd; /* remember where our stack is */
+ if (thd->store_globals() && (ndb->init() != -1))
+ {
+ thd->cleanup();
+ delete thd;
+ delete ndb;
+ DBUG_RETURN(NULL);
+ }
+
+ List<NDB_SHARE> util_open_tables;
+ set_timespec(abstime, 0);
+ for (;;)
+ {
+
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
+ error= pthread_cond_timedwait(&COND_ndb_util_thread,
+ &LOCK_ndb_util_thread,
+ &abstime);
+ pthread_mutex_unlock(&LOCK_ndb_util_thread);
+
+ DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %d",
+ ndb_cache_check_time));
+
+ if (abort_loop)
+ break; /* Shutting down server */
+
+ if (ndb_cache_check_time == 0)
+ {
+ /* Wake up in 1 second to check if value has changed */
+ set_timespec(abstime, 1);
+ continue;
+ }
+
+ /* Lock mutex and fill list with pointers to all open tables */
+ NDB_SHARE *share;
+ pthread_mutex_lock(&ndbcluster_mutex);
+ for (uint i= 0; i < ndbcluster_open_tables.records; i++)
+ {
+ share= (NDB_SHARE *)hash_element(&ndbcluster_open_tables, i);
+ share->use_count++; /* Make sure the table can't be closed */
+ DBUG_PRINT("ndb_util_thread",
+ ("Found open table[%d]: %s, use_count: %d",
+ i, share->table_name, share->use_count));
+
+ /* Store pointer to table */
+ util_open_tables.push_back(share);
+ }
+ pthread_mutex_unlock(&ndbcluster_mutex);
+
+ /* Iterate through the open files list */
+ List_iterator_fast<NDB_SHARE> it(util_open_tables);
+ while ((share= it++))
+ {
+ /* Split tab- and dbname */
+ char buf[FN_REFLEN];
+ char *tabname, *db;
+ uint length= dirname_length(share->table_name);
+ tabname= share->table_name+length;
+ memcpy(buf, share->table_name, length-1);
+ buf[length-1]= 0;
+ db= buf+dirname_length(buf);
+ DBUG_PRINT("ndb_util_thread",
+ ("Fetching commit count for: %s",
+ share->table_name));
+
+ /* Contact NDB to get commit count for table */
+ ndb->setDatabaseName(db);
+ struct Ndb_statistics stat;
+
+ uint lock;
+ pthread_mutex_lock(&share->mutex);
+ lock= share->commit_count_lock;
+ pthread_mutex_unlock(&share->mutex);
+
+ if(ndb_get_table_statistics(ndb, tabname, &stat) == 0)
+ {
+ DBUG_PRINT("ndb_util_thread",
+ ("Table: %s, commit_count: %llu, rows: %llu",
+ share->table_name, stat.commit_count, stat.row_count));
+ }
+ else
+ {
+ DBUG_PRINT("ndb_util_thread",
+ ("Error: Could not get commit count for table %s",
+ share->table_name));
+ stat.commit_count= 0;
+ }
+
+ pthread_mutex_lock(&share->mutex);
+ if (share->commit_count_lock == lock)
+ share->commit_count= stat.commit_count;
+ pthread_mutex_unlock(&share->mutex);
+
+ /* Decrease the use count and possibly free share */
+ free_share(share);
+ }
+
+ /* Clear the list of open tables */
+ util_open_tables.empty();
+
+ /* Calculate new time to wake up */
+ int secs= 0;
+ int msecs= ndb_cache_check_time;
+
+ struct timeval tick_time;
+ gettimeofday(&tick_time, 0);
+ abstime.tv_sec= tick_time.tv_sec;
+ abstime.tv_nsec= tick_time.tv_usec * 1000;
+
+ if(msecs >= 1000){
+ secs= msecs / 1000;
+ msecs= msecs % 1000;
+ }
+
+ abstime.tv_sec+= secs;
+ abstime.tv_nsec+= msecs * 1000000;
+ if (abstime.tv_nsec >= 1000000000) {
+ abstime.tv_sec+= 1;
+ abstime.tv_nsec-= 1000000000;
+ }
+ }
+
+ thd->cleanup();
+ delete thd;
+ delete ndb;
+ DBUG_PRINT("exit", ("ndb_util_thread"));
+ my_thread_end();
+ pthread_exit(0);
+ DBUG_RETURN(NULL);
+}
+
+/*
+ Condition pushdown
+*/
+/*
+ Push a condition to ndbcluster storage engine for evaluation
+ during table and index scans. The conditions will be stored on a stack
+ for possibly storing several conditions. The stack can be popped
+ by calling cond_pop, handler::extra(HA_EXTRA_RESET) (handler::reset())
+ will clear the stack.
+ The current implementation supports arbitrary AND/OR nested conditions
+ with comparisons between columns and constants (including constant
+ expressions and function calls) and the following comparison operators:
+ =, !=, >, >=, <, <=, "is null", and "is not null".
+
+ RETURN
+ NULL The condition was supported and will be evaluated for each
+ row found during the scan
+ cond The condition was not supported and all rows will be returned from
+ the scan for evaluation (and thus not saved on stack)
+*/
+const
+COND*
+ha_ndbcluster::cond_push(const COND *cond)
+{
+ Ndb_cond_stack *ndb_cond = new Ndb_cond_stack();
+ DBUG_ENTER("cond_push");
+ DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname););
+ if (m_cond_stack)
+ ndb_cond->next= m_cond_stack;
+ else
+ ndb_cond->next= NULL;
+ m_cond_stack= ndb_cond;
+
+ if (serialize_cond(cond, ndb_cond))
+ {
+ DBUG_RETURN(NULL);
+ }
+ else
+ {
+ cond_pop();
+ }
+
+ DBUG_RETURN(cond);
+}
+
+/*
+ Pop the top condition from the condition stack of the handler instance.
+*/
+void
+ha_ndbcluster::cond_pop()
+{
+ Ndb_cond_stack *ndb_cond_stack= m_cond_stack;
+ if (ndb_cond_stack)
+ {
+ m_cond_stack= ndb_cond_stack->next;
+ delete ndb_cond_stack;
+ }
+}
+
+/*
+ Clear the condition stack
+*/
+void
+ha_ndbcluster::cond_clear()
+{
+ DBUG_ENTER("cond_clear");
+ while (m_cond_stack)
+ cond_pop();
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Serialize the item tree into a linked list represented by Ndb_cond
+ for fast generation of NbdScanFilter. Adds information such as
+ position of fields that is not directly available in the Item tree.
+ Also checks if condition is supported.
+*/
+void ndb_serialize_cond(const Item *item, void *arg)
+{
+ Ndb_cond_traverse_context *context= (Ndb_cond_traverse_context *) arg;
+ DBUG_ENTER("ndb_serialize_cond");
+
+ // Check if we are skipping arguments to a function to be evaluated
+ if (context->skip)
+ {
+ DBUG_PRINT("info", ("Skiping argument %d", context->skip));
+ context->skip--;
+ 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):
+ break;
+ default:
+ context->supported= FALSE;
+ break;
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ if (context->supported)
+ {
+ Ndb_cond_stack *ndb_stack= context->stack_ptr;
+ Ndb_cond *prev_cond= context->cond_ptr;
+ Ndb_cond *curr_cond= context->cond_ptr= new Ndb_cond();
+ if (!ndb_stack->ndb_cond)
+ ndb_stack->ndb_cond= curr_cond;
+ curr_cond->prev= prev_cond;
+ if (prev_cond) prev_cond->next= curr_cond;
+
+ // Check for end of AND/OR expression
+ if (!item)
+ {
+ // End marker for condition group
+ DBUG_PRINT("info", ("End of condition group"));
+ curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
+ }
+ else
+ 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();
+ /*
+ Check that the field is part of the table of the handler
+ instance and that we expect a field with of this result type.
+ */
+ if (context->table == field->table)
+ {
+ const NDBTAB *tab= (const NDBTAB *) context->ndb_table;
+ DBUG_PRINT("info", ("FIELD_ITEM"));
+ DBUG_PRINT("info", ("table %s", tab->getName()));
+ DBUG_PRINT("info", ("column %s", field->field_name));
+ DBUG_PRINT("info", ("result type %d", field->result_type()));
+
+ // Check that we are expecting a field and with the correct
+ // result type
+ if(context->expecting(Item::FIELD_ITEM) &&
+ (context->expecting_field_result(field->result_type()) ||
+ // Date and year can be written as strings
+ (type == MYSQL_TYPE_TIME ||
+ type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_YEAR ||
+ type == MYSQL_TYPE_DATETIME)
+ ? context->expecting_field_result(STRING_RESULT) : true)
+ // Bit fields no yet supported in scan filter
+ && type != MYSQL_TYPE_BIT)
+ {
+ const NDBCOL *col= tab->getColumn(field->field_name);
+ DBUG_ASSERT(col);
+ curr_cond->ndb_item= new Ndb_item(field, col->getColumnNo());
+ context->dont_expect(Item::FIELD_ITEM);
+ context->expect_no_field_result();
+ if (context->expect_mask)
+ {
+ // We have not seen second argument yet
+ if (type == MYSQL_TYPE_TIME ||
+ type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_YEAR ||
+ type == MYSQL_TYPE_DATETIME)
+ {
+ context->expect_only(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ }
+ else
+ 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):
+ context->expect_only(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ break;
+ case(INT_RESULT):
+ context->expect_only(Item::INT_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ break;
+ case(DECIMAL_RESULT):
+ context->expect_only(Item::DECIMAL_ITEM);
+ context->expect(Item::REAL_ITEM);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ // Check that field and string constant collations are the same
+ if ((field->result_type() == STRING_RESULT) &&
+ !context->expecting_collation(item->collation.collation))
+ {
+ DBUG_PRINT("info", ("Found non-matching collation %s",
+ item->collation.collation->name));
+ context->supported= FALSE;
+ }
+ }
+ break;
+ }
+ }
+ DBUG_PRINT("info", ("Was not expecting field of type %u",
+ field->result_type()));
+ context->supported= FALSE;
+ break;
+ }
+ 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) ||
+ func_item->functype() == Item_func::UNKNOWN_FUNC)
+ context->expect_nothing();
+ else
+ {
+ // Did not expect function here
+ context->supported= FALSE;
+ break;
+ }
+
+ 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);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::NE_FUNC): {
+ DBUG_PRINT("info", ("NE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::LT_FUNC): {
+ DBUG_PRINT("info", ("LT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::LE_FUNC): {
+ DBUG_PRINT("info", ("LE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::GE_FUNC): {
+ DBUG_PRINT("info", ("GE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::GT_FUNC): {
+ DBUG_PRINT("info", ("GT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::LIKE_FUNC): {
+ DBUG_PRINT("info", ("LIKE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ break;
+ }
+ case(Item_func::NOTLIKE_FUNC): {
+ DBUG_PRINT("info", ("NOTLIKE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ break;
+ }
+ case(Item_func::ISNULL_FUNC): {
+ DBUG_PRINT("info", ("ISNULL_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::ISNOTNULL_FUNC): {
+ DBUG_PRINT("info", ("ISNOTNULL_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::NOT_FUNC): {
+ DBUG_PRINT("info", ("NOT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ break;
+ }
+ 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): {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::STRING_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ context->expect_collation(func_item->collation.collation);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ // Check that string result have correct collation
+ if (!context->expecting_collation(item->collation.collation))
+ {
+ DBUG_PRINT("info", ("Found non-matching collation %s",
+ item->collation.collation->name));
+ context->supported= FALSE;
+ }
+ }
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ case(REAL_RESULT): {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::REAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ case(INT_RESULT): {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::INT_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(INT_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ case(DECIMAL_RESULT): {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::DECIMAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(DECIMAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ default:
+ break;
+ }
+ else
+ // Function does not return constant expression
+ context->supported= FALSE;
+ break;
+ }
+ default: {
+ DBUG_PRINT("info", ("Found func_item of type %d",
+ func_item->functype()));
+ context->supported= FALSE;
+ }
+ }
+ break;
+ }
+ case(Item::STRING_ITEM):
+ DBUG_PRINT("info", ("STRING_ITEM"));
+ if (context->expecting(Item::STRING_ITEM))
+ {
+#ifndef DBUG_OFF
+ char buff[256];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ str.length(0);
+ Item_string *string_item= (Item_string *) item;
+ DBUG_PRINT("info", ("value \"%s\"",
+ string_item->val_str(&str)->ptr()));
+#endif
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::STRING_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ context->expect_collation(item->collation.collation);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ // Check that we are comparing with a field with same collation
+ if (!context->expecting_collation(item->collation.collation))
+ {
+ DBUG_PRINT("info", ("Found non-matching collation %s",
+ item->collation.collation->name));
+ context->supported= FALSE;
+ }
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case(Item::INT_ITEM):
+ DBUG_PRINT("info", ("INT_ITEM"));
+ if (context->expecting(Item::INT_ITEM))
+ {
+ Item_int *int_item= (Item_int *) item;
+ DBUG_PRINT("info", ("value %d", int_item->value));
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::INT_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(INT_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case(Item::REAL_ITEM):
+ DBUG_PRINT("info", ("REAL_ITEM %s"));
+ if (context->expecting(Item::REAL_ITEM))
+ {
+ Item_float *float_item= (Item_float *) item;
+ DBUG_PRINT("info", ("value %f", float_item->value));
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::REAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case(Item::VARBIN_ITEM):
+ DBUG_PRINT("info", ("VARBIN_ITEM"));
+ if (context->expecting(Item::VARBIN_ITEM))
+ {
+#ifndef DBUG_OFF
+ char buff[256];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ str.length(0);
+ Item_hex_string *varbin_item= (Item_hex_string *) item;
+ DBUG_PRINT("info", ("value \"%s\"",
+ varbin_item->val_str(&str)->ptr()));
+#endif
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::VARBIN_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case(Item::DECIMAL_ITEM):
+ DBUG_PRINT("info", ("DECIMAL_ITEM %s"));
+ if (context->expecting(Item::DECIMAL_ITEM))
+ {
+ Item_decimal *decimal_item= (Item_decimal *) item;
+ DBUG_PRINT("info", ("value %f", decimal_item->val_real()));
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::DECIMAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ 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):
+ 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):
+ DBUG_PRINT("info", ("COND_OR_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
+ cond_item);
+ break;
+ default:
+ DBUG_PRINT("info", ("COND_ITEM %d", cond_item->functype()));
+ context->supported= FALSE;
+ break;
+ }
+ else
+ // Did not expect condition
+ context->supported= FALSE;
+ break;
+ }
+ default: {
+ DBUG_PRINT("info", ("Found item of type %d", item->type()));
+ context->supported= FALSE;
+ }
+ }
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+bool
+ha_ndbcluster::serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond)
+{
+ DBUG_ENTER("serialize_cond");
+ Item *item= (Item *) cond;
+ Ndb_cond_traverse_context context(table, (void *)m_table, ndb_cond);
+ // Expect a logical expression
+ context.expect(Item::FUNC_ITEM);
+ context.expect(Item::COND_ITEM);
+ item->traverse_cond(&ndb_serialize_cond, (void *) &context, Item::PREFIX);
+ DBUG_PRINT("info", ("The pushed condition is %ssupported", (context.supported)?"":"not "));
+
+ DBUG_RETURN(context.supported);
+}
+
+int
+ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
+ NdbScanFilter *filter,
+ bool negated)
+{
+ DBUG_ENTER("build_scan_filter_predicate");
+ 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):
+ field=
+ (a->type == NDB_FIELD)? a : NULL;
+ break;
+ case(2):
+ if (!cond->next->next)
+ break;
+ b= cond->next->next->ndb_item;
+ value=
+ (a->type == NDB_VALUE)? a
+ : (b->type == NDB_VALUE)? b
+ : NULL;
+ field=
+ (a->type == NDB_FIELD)? a
+ : (b->type == NDB_FIELD)? b
+ : NULL;
+ break;
+ default:
+ break;
+ }
+ switch((negated) ?
+ Ndb_item::negate(cond->ndb_item->qualification.function_type)
+ : cond->ndb_item->qualification.function_type)
+ {
+ case(Item_func::EQ_FUNC): {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating EQ filter"));
+ if (filter->cmp(NdbScanFilter::COND_EQ,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case(Item_func::NE_FUNC): {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating NE filter"));
+ if (filter->cmp(NdbScanFilter::COND_NE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case(Item_func::LT_FUNC): {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating LT filter"));
+ if (filter->cmp(NdbScanFilter::COND_LT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating GT filter"));
+ if (filter->cmp(NdbScanFilter::COND_GT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case(Item_func::LE_FUNC): {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating LE filter"));
+ if (filter->cmp(NdbScanFilter::COND_LE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating GE filter"));
+ if (filter->cmp(NdbScanFilter::COND_GE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case(Item_func::GE_FUNC): {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating GE filter"));
+ if (filter->cmp(NdbScanFilter::COND_GE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating LE filter"));
+ if (filter->cmp(NdbScanFilter::COND_LE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case(Item_func::GT_FUNC): {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating GT filter"));
+ if (filter->cmp(NdbScanFilter::COND_GT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating LT filter"));
+ if (filter->cmp(NdbScanFilter::COND_LT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case(Item_func::LIKE_FUNC): {
+ if (!value || !field) break;
+ if ((value->qualification.value_type != Item::STRING_ITEM) &&
+ (value->qualification.value_type != Item::VARBIN_ITEM))
+ break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating LIKE filter: like(%d,%s,%d)",
+ field->get_field_no(), value->get_val(),
+ value->pack_length()));
+ if (filter->cmp(NdbScanFilter::COND_LIKE,
+ field->get_field_no(),
+ value->get_val(),
+ value->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case(Item_func::NOTLIKE_FUNC): {
+ if (!value || !field) break;
+ if ((value->qualification.value_type != Item::STRING_ITEM) &&
+ (value->qualification.value_type != Item::VARBIN_ITEM))
+ break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating NOTLIKE filter: notlike(%d,%s,%d)",
+ field->get_field_no(), value->get_val(),
+ value->pack_length()));
+ if (filter->cmp(NdbScanFilter::COND_NOT_LIKE,
+ field->get_field_no(),
+ value->get_val(),
+ value->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case(Item_func::ISNULL_FUNC):
+ if (!field)
+ break;
+ DBUG_PRINT("info", ("Generating ISNULL filter"));
+ if (filter->isnull(field->get_field_no()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next;
+ DBUG_RETURN(0);
+ case(Item_func::ISNOTNULL_FUNC): {
+ if (!field)
+ break;
+ DBUG_PRINT("info", ("Generating ISNOTNULL filter"));
+ if (filter->isnotnull(field->get_field_no()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next;
+ DBUG_RETURN(0);
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ DBUG_PRINT("info", ("Found illegal condition"));
+ DBUG_RETURN(1);
+}
+
+int
+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): {
+ level++;
+ DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NAND":"AND",
+ level));
+ if ((negated) ? filter->begin(NdbScanFilter::NAND)
+ : filter->begin(NdbScanFilter::AND) == -1)
+ DBUG_RETURN(1);
+ negated= false;
+ cond= cond->next;
+ break;
+ }
+ case(Item_func::COND_OR_FUNC): {
+ level++;
+ DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NOR":"OR",
+ level));
+ if ((negated) ? filter->begin(NdbScanFilter::NOR)
+ : filter->begin(NdbScanFilter::OR) == -1)
+ DBUG_RETURN(1);
+ negated= false;
+ cond= cond->next;
+ break;
+ }
+ case(Item_func::NOT_FUNC): {
+ cond= cond->next;
+ negated= true;
+ break;
+ }
+ default:
+ if (build_scan_filter_predicate(cond, filter, negated))
+ DBUG_RETURN(1);
+ negated= false;
+ break;
+ }
+ break;
+ case(NDB_END_COND):
+ DBUG_PRINT("info", ("End of group %u", level));
+ level--;
+ if (cond) cond= cond->next;
+ if (filter->end() == -1)
+ DBUG_RETURN(1);
+ break;
+ default: {
+ DBUG_PRINT("info", ("Illegal scan filter"));
+ }
+ }
+ } while (level > 0);
+
+ DBUG_RETURN(0);
+}
+
+int
+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(Item_func::COND_AND_FUNC):
+ case(Item_func::COND_OR_FUNC):
+ simple_cond= FALSE;
+ break;
+ default:
+ break;
+ }
+ if (simple_cond && filter->begin() == -1)
+ DBUG_RETURN(1);
+ if (build_scan_filter_group(cond, filter))
+ DBUG_RETURN(1);
+ if (simple_cond && filter->end() == -1)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+int
+ha_ndbcluster::generate_scan_filter(Ndb_cond_stack *ndb_cond_stack,
+ NdbScanOperation *op)
+{
+ DBUG_ENTER("generate_scan_filter");
+ if (ndb_cond_stack)
+ {
+ NdbScanFilter filter(op);
+ bool multiple_cond= FALSE;
+ // Wrap an AND group around multiple conditions
+ if (ndb_cond_stack->next) {
+ multiple_cond= TRUE;
+ if (filter.begin() == -1)
+ DBUG_RETURN(1);
+ }
+ for (Ndb_cond_stack *stack= ndb_cond_stack;
+ (stack);
+ stack= stack->next)
+ {
+ Ndb_cond *cond= stack->ndb_cond;
+
+ if (build_scan_filter(cond, &filter))
+ {
+ DBUG_PRINT("info", ("build_scan_filter failed"));
+ DBUG_RETURN(1);
+ }
+ }
+ if (multiple_cond && filter.end() == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Empty stack"));
+ }
+
+ DBUG_RETURN(0);
+}
+
#endif /* HAVE_NDBCLUSTER_DB */
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index 7de5dd503e7..81b2873d9dd 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -29,15 +29,16 @@
class Ndb; // Forward declaration
class NdbOperation; // Forward declaration
-class NdbConnection; // Forward declaration
+class NdbTransaction; // Forward declaration
class NdbRecAttr; // Forward declaration
-class NdbResultSet; // Forward declaration
class NdbScanOperation;
+class NdbScanFilter;
class NdbIndexScanOperation;
class NdbBlob;
// connectstring to cluster if given by mysqld
extern const char *ndbcluster_connectstring;
+extern ulong ndb_cache_check_time;
typedef enum ndb_index_type {
UNDEFINED_INDEX = 0,
@@ -60,20 +61,321 @@ typedef struct st_ndbcluster_share {
pthread_mutex_t mutex;
char *table_name;
uint table_name_length,use_count;
+ uint commit_count_lock;
+ ulonglong commit_count;
} NDB_SHARE;
+typedef enum ndb_item_type {
+ NDB_VALUE = 0, // Qualified more with Item::Type
+ NDB_FIELD = 1, // Qualified from table definition
+ NDB_FUNCTION = 2,// Qualified from Item_func::Functype
+ NDB_END_COND = 3 // End marker for condition group
+} NDB_ITEM_TYPE;
+
+typedef union ndb_item_qualification {
+ Item::Type value_type;
+ enum_field_types field_type; // Instead of Item::FIELD_ITEM
+ Item_func::Functype function_type; // Instead of Item::FUNC_ITEM
+} NDB_ITEM_QUALIFICATION;
+
+typedef struct ndb_item_field_value {
+ Field* field;
+ int column_no;
+} NDB_ITEM_FIELD_VALUE;
+
+typedef union ndb_item_value {
+ const Item *item;
+ NDB_ITEM_FIELD_VALUE *field_value;
+} NDB_ITEM_VALUE;
+
+struct negated_function_mapping
+{
+ Item_func::Functype pos_fun;
+ Item_func::Functype neg_fun;
+};
+
+static const negated_function_mapping neg_map[]=
+{
+ {Item_func::EQ_FUNC, Item_func::NE_FUNC},
+ {Item_func::NE_FUNC, Item_func::EQ_FUNC},
+ {Item_func::LT_FUNC, Item_func::GE_FUNC},
+ {Item_func::LE_FUNC, Item_func::GT_FUNC},
+ {Item_func::GT_FUNC, Item_func::LE_FUNC},
+ {Item_func::GE_FUNC, Item_func::LT_FUNC},
+ {Item_func::LIKE_FUNC, Item_func::NOTLIKE_FUNC},
+ {Item_func::NOTLIKE_FUNC, Item_func::LIKE_FUNC},
+ {Item_func::ISNULL_FUNC, Item_func::ISNOTNULL_FUNC},
+ {Item_func::ISNOTNULL_FUNC, Item_func::ISNULL_FUNC},
+ {Item_func::UNKNOWN_FUNC, Item_func::NOT_FUNC}
+};
+
+/*
+ This class is the construction element for serialization of Item tree
+ in condition pushdown.
+ An instance of Ndb_Item represents a constant, table field reference,
+ unary or binary comparison predicate, and start/end of AND/OR.
+ Instances of Ndb_Item are stored in a linked list implemented by Ndb_cond
+ class.
+ The order of elements produced by Ndb_cond::next corresponds to
+ breadth-first traversal of the Item (i.e. expression) tree in prefix order.
+ AND and OR have arbitrary arity, so the end of AND/OR group is marked with
+ Ndb_item with type == NDB_END_COND.
+ NOT items represent negated conditions and generate NAND/NOR groups.
+*/
+class Ndb_item {
+ public:
+ Ndb_item(NDB_ITEM_TYPE item_type) : type(item_type) {};
+ Ndb_item(NDB_ITEM_TYPE item_type,
+ NDB_ITEM_QUALIFICATION item_qualification,
+ const Item *item_value)
+ : type(item_type), qualification(item_qualification)
+ {
+ switch(item_type) {
+ case(NDB_VALUE):
+ value.item= item_value;
+ break;
+ case(NDB_FIELD): {
+ NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
+ Item_field *field_item= (Item_field *) item_value;
+ field_value->field= field_item->field;
+ field_value->column_no= -1; // Will be fetched at scan filter generation
+ value.field_value= field_value;
+ break;
+ }
+ case(NDB_FUNCTION):
+ value.item= item_value;
+ break;
+ case(NDB_END_COND):
+ break;
+ }
+ };
+ Ndb_item(Field *field, int column_no) : type(NDB_FIELD)
+ {
+ NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
+ qualification.field_type= field->type();
+ field_value->field= field;
+ field_value->column_no= column_no;
+ value.field_value= field_value;
+ };
+ Ndb_item(Item_func::Functype func_type, const Item *item_value)
+ : type(NDB_FUNCTION)
+ {
+ qualification.function_type= func_type;
+ value.item= item_value;
+ };
+ ~Ndb_item()
+ {
+ if (type == NDB_FIELD)
+ {
+ delete value.field_value;
+ value.field_value= NULL;
+ }
+ };
+
+ uint32 pack_length()
+ {
+ switch(type) {
+ case(NDB_VALUE):
+ if(qualification.value_type == Item::STRING_ITEM)
+ return value.item->str_value.length();
+ break;
+ case(NDB_FIELD):
+ return value.field_value->field->pack_length();
+ default:
+ break;
+ }
+
+ return 0;
+ };
+
+ Field * get_field() { return value.field_value->field; };
+
+ int get_field_no() { return value.field_value->column_no; };
+
+ int argument_count()
+ {
+ return ((Item_func *) value.item)->argument_count();
+ };
+
+ const char* get_val()
+ {
+ switch(type) {
+ case(NDB_VALUE):
+ if(qualification.value_type == Item::STRING_ITEM)
+ return value.item->str_value.ptr();
+ break;
+ case(NDB_FIELD):
+ return value.field_value->field->ptr;
+ default:
+ break;
+ }
+
+ return NULL;
+ };
+
+ void save_in_field(Ndb_item *field_item)
+ {
+ Field *field = field_item->value.field_value->field;
+ const Item *item= value.item;
+
+ if (item && field)
+ ((Item *)item)->save_in_field(field, false);
+ };
+
+ static Item_func::Functype negate(Item_func::Functype fun)
+ {
+ uint i;
+ for (i=0;
+ fun != neg_map[i].pos_fun &&
+ neg_map[i].pos_fun != Item_func::UNKNOWN_FUNC;
+ i++);
+ return neg_map[i].neg_fun;
+ };
+
+ NDB_ITEM_TYPE type;
+ NDB_ITEM_QUALIFICATION qualification;
+ private:
+ NDB_ITEM_VALUE value;
+};
+
+/*
+ This class implements a linked list used for storing a
+ serialization of the Item tree for condition pushdown.
+ */
+class Ndb_cond
+{
+ public:
+ Ndb_cond() : ndb_item(NULL), next(NULL), prev(NULL) {};
+ ~Ndb_cond()
+ {
+ if (ndb_item) delete ndb_item;
+ ndb_item= NULL;
+ if (next) delete next;
+ next= prev= NULL;
+ };
+ Ndb_item *ndb_item;
+ Ndb_cond *next;
+ Ndb_cond *prev;
+};
+
+/*
+ This class implements a stack for storing several conditions
+ for pushdown (represented as serialized Item trees using Ndb_cond).
+ The current implementation only pushes one condition, but is
+ prepared for handling several (C1 AND C2 ...) if the logic for
+ pushing conditions is extended in sql_select.
+*/
+class Ndb_cond_stack
+{
+ public:
+ Ndb_cond_stack() : ndb_cond(NULL), next(NULL) {};
+ ~Ndb_cond_stack()
+ {
+ if (ndb_cond) delete ndb_cond;
+ ndb_cond= NULL;
+ next= NULL;
+ };
+ Ndb_cond *ndb_cond;
+ Ndb_cond_stack *next;
+};
+
+/*
+ This class is used for storing the context when traversing
+ the Item tree. It stores a reference to the table the condition
+ is defined on, the serialized representation being generated,
+ if the condition found is supported, and information what is
+ expected next in the tree inorder for the condition to be supported.
+*/
+class Ndb_cond_traverse_context
+{
+ public:
+ Ndb_cond_traverse_context(TABLE *tab, void* ndb_tab, Ndb_cond_stack* stack)
+ : table(tab), ndb_table(ndb_tab),
+ supported(TRUE), stack_ptr(stack), cond_ptr(NULL),
+ expect_mask(0), expect_field_result_mask(0), skip(0), collation(NULL)
+ {
+ if (stack)
+ cond_ptr= stack->ndb_cond;
+ };
+ void expect(Item::Type type)
+ {
+ expect_mask|= (1 << type);
+ };
+ void dont_expect(Item::Type type)
+ {
+ expect_mask&= ~(1 << type);
+ };
+ bool expecting(Item::Type type)
+ {
+ return (expect_mask & (1 << type));
+ };
+ void expect_nothing()
+ {
+ expect_mask= 0;
+ };
+ void expect_only(Item::Type type)
+ {
+ expect_mask= 0;
+ expect(type);
+ };
+
+ void expect_field_result(Item_result result)
+ {
+ expect_field_result_mask|= (1 << result);
+ };
+ bool expecting_field_result(Item_result result)
+ {
+ return (expect_field_result_mask & (1 << result));
+ };
+ void expect_no_field_result()
+ {
+ expect_field_result_mask= 0;
+ };
+ void expect_only_field_result(Item_result result)
+ {
+ expect_field_result_mask= 0;
+ expect_field_result(result);
+ };
+ void expect_collation(CHARSET_INFO* col)
+ {
+ collation= col;
+ };
+ bool expecting_collation(CHARSET_INFO* col)
+ {
+ bool matching= (!collation) ? true : (collation == col);
+ collation= NULL;
+
+ return matching;
+ };
+
+ TABLE* table;
+ void* ndb_table;
+ bool supported;
+ Ndb_cond_stack* stack_ptr;
+ Ndb_cond* cond_ptr;
+ uint expect_mask;
+ uint expect_field_result_mask;
+ uint skip;
+ CHARSET_INFO* collation;
+
+};
+
/*
Place holder for ha_ndbcluster thread specific data
*/
-class Thd_ndb {
+class Thd_ndb
+{
public:
Thd_ndb();
~Thd_ndb();
Ndb *ndb;
ulong count;
uint lock_count;
+ NdbTransaction *all;
+ NdbTransaction *stmt;
int error;
+ List<NDB_SHARE> changed_tables;
};
class ha_ndbcluster: public handler
@@ -91,32 +393,40 @@ class ha_ndbcluster: public handler
int index_init(uint index);
int index_end();
int index_read(byte *buf, const byte *key, uint key_len,
- enum ha_rkey_function find_flag);
+ enum ha_rkey_function find_flag);
int index_read_idx(byte *buf, uint index, const byte *key, uint key_len,
- enum ha_rkey_function find_flag);
+ enum ha_rkey_function find_flag);
int index_next(byte *buf);
int index_prev(byte *buf);
int index_first(byte *buf);
int index_last(byte *buf);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
int rnd_init(bool scan);
int rnd_end();
int rnd_next(byte *buf);
int rnd_pos(byte *buf, byte *pos);
void position(const byte *record);
int read_range_first(const key_range *start_key,
- const key_range *end_key,
- bool eq_range, bool sorted);
+ const key_range *end_key,
+ bool eq_range, bool sorted);
int read_range_first_to_buf(const key_range *start_key,
- const key_range *end_key,
- bool eq_range, bool sorted,
- byte* buf);
+ const key_range *end_key,
+ bool eq_range, bool sorted,
+ byte* buf);
int read_range_next();
+ /**
+ * Multi range stuff
+ */
+ int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE*ranges, uint range_count,
+ bool sorted, HANDLER_BUFFER *buffer);
+ int read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
+
bool get_error_message(int error, String *buf);
void info(uint);
int extra(enum ha_extra_function operation);
int extra_opt(enum ha_extra_function operation, ulong cache_size);
- int reset();
int external_lock(THD *thd, int lock_type);
int start_stmt(THD *thd);
const char * table_type() const;
@@ -132,8 +442,8 @@ class ha_ndbcluster: public handler
int delete_table(const char *name);
int create(const char *name, TABLE *form, HA_CREATE_INFO *info);
THR_LOCK_DATA **store_lock(THD *thd,
- THR_LOCK_DATA **to,
- enum thr_lock_type lock_type);
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
bool low_byte_first() const;
bool has_transactions();
@@ -146,12 +456,55 @@ class ha_ndbcluster: public handler
static Thd_ndb* seize_thd_ndb();
static void release_thd_ndb(Thd_ndb* thd_ndb);
- uint8 table_cache_type();
- static void set_dbname(const char *pathname, char *dbname);
- static void set_tabname(const char *pathname, char *tabname);
+static void set_dbname(const char *pathname, char *dbname);
+static void set_tabname(const char *pathname, char *tabname);
+
+ /*
+ Condition pushdown
+ */
+
+ /*
+ Push condition down to the table handler.
+ SYNOPSIS
+ cond_push()
+ cond Condition to be pushed. The condition tree must not be
+ modified by the by the caller.
+ RETURN
+ The 'remainder' condition that caller must use to filter out records.
+ NULL means the handler will not return rows that do not match the
+ passed condition.
+ NOTES
+ The pushed conditions form a stack (from which one can remove the
+ last pushed condition using cond_pop).
+ The table handler filters out rows using (pushed_cond1 AND pushed_cond2
+ AND ... AND pushed_condN)
+ or less restrictive condition, depending on handler's capabilities.
- private:
+ handler->extra(HA_EXTRA_RESET) call empties the condition stack.
+ Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
+ condition stack.
+ The current implementation supports arbitrary AND/OR nested conditions
+ with comparisons between columns and constants (including constant
+ expressions and function calls) and the following comparison operators:
+ =, !=, >, >=, <, <=, like, "not like", "is null", and "is not null".
+ Negated conditions are supported by NOT which generate NAND/NOR groups.
+ */
+ const COND *cond_push(const COND *cond);
+ /*
+ Pop the top condition from the condition stack of the handler instance.
+ SYNOPSIS
+ cond_pop()
+ Pops the top if condition stack, if stack is not empty
+ */
+ void cond_pop();
+
+ uint8 table_cache_type();
+ my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback *engine_callback,
+ ulonglong *engine_data);
+private:
int alter_table_name(const char *to);
int drop_table();
int create_index(const char *name, KEY *key_info, bool unique);
@@ -170,16 +523,17 @@ class ha_ndbcluster: public handler
int complemented_pk_read(const byte *old_data, byte *new_data);
int peek_row();
int unique_index_read(const byte *key, uint key_len,
- byte *buf);
+ byte *buf);
int ordered_index_scan(const key_range *start_key,
- const key_range *end_key,
- bool sorted, byte* buf);
+ const key_range *end_key,
+ bool sorted, bool descending, byte* buf);
int full_table_scan(byte * buf);
+ int fetch_next(NdbScanOperation* op);
int next_result(byte *buf);
int define_read_attrs(byte* buf, NdbOperation* op);
int filtered_scan(const byte *key, uint key_len,
- byte *buf,
- enum ha_rkey_function find_flag);
+ byte *buf,
+ enum ha_rkey_function find_flag);
int close_scan();
void unpack_record(byte *buf);
int get_ndb_lock_type(enum thr_lock_type type);
@@ -188,9 +542,9 @@ class ha_ndbcluster: public handler
void set_tabname(const char *pathname);
bool set_hidden_key(NdbOperation*,
- uint fieldnr, const byte* field_ptr);
+ uint fieldnr, const byte* field_ptr);
int set_ndb_key(NdbOperation*, Field *field,
- uint fieldnr, const byte* field_ptr);
+ uint fieldnr, const byte* field_ptr);
int set_ndb_value(NdbOperation*, Field *field, uint fieldnr, bool *set_blob_value= 0);
int get_ndb_value(NdbOperation*, Field *field, uint fieldnr, byte*);
friend int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg);
@@ -198,22 +552,49 @@ class ha_ndbcluster: public handler
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_bounds(NdbIndexScanOperation *ndb_op, const key_range *keys[2]);
+ 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);
void print_results();
- longlong get_auto_increment();
+ ulonglong get_auto_increment();
void invalidate_dictionary_cache(bool global);
- int ndb_err(NdbConnection*);
+ int ndb_err(NdbTransaction*);
bool uses_blob_value(bool all_fields);
+ char *update_table_comment(const char * comment);
+
int write_ndb_file();
- private:
- int check_ndb_connection();
+ int check_ndb_connection(THD* thd= current_thd);
- NdbConnection *m_active_trans;
- NdbResultSet *m_active_cursor;
+ void set_rec_per_key();
+ void records_update();
+ void no_uncommitted_rows_execute_failure();
+ void no_uncommitted_rows_update(int);
+ void no_uncommitted_rows_init(THD *);
+ void no_uncommitted_rows_reset(THD *);
+
+ /*
+ Condition pushdown
+ */
+ void cond_clear();
+ bool serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond);
+ int build_scan_filter_predicate(Ndb_cond* &cond,
+ NdbScanFilter* filter,
+ bool negated= false);
+ int build_scan_filter_group(Ndb_cond* &cond,
+ NdbScanFilter* filter);
+ int build_scan_filter(Ndb_cond* &cond, NdbScanFilter* filter);
+ int generate_scan_filter(Ndb_cond_stack* cond_stack,
+ NdbScanOperation* op);
+
+ friend int execute_commit(ha_ndbcluster*, NdbTransaction*);
+ friend int execute_no_commit(ha_ndbcluster*, NdbTransaction*);
+ friend int execute_no_commit_ie(ha_ndbcluster*, NdbTransaction*);
+
+ NdbTransaction *m_active_trans;
+ NdbScanOperation *m_active_cursor;
void *m_table;
int m_table_version;
void *m_table_info;
@@ -225,7 +606,7 @@ class ha_ndbcluster: public handler
NDB_SHARE *m_share;
NDB_INDEX_DATA m_index[MAX_KEY];
// NdbRecAttr has no reference to blob
- typedef union { NdbRecAttr *rec; NdbBlob *blob; void *ptr; } NdbValue;
+ typedef union { const NdbRecAttr *rec; NdbBlob *blob; void *ptr; } NdbValue;
NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE];
bool m_use_write;
bool m_ignore_dup_key;
@@ -235,6 +616,7 @@ class ha_ndbcluster: public handler
ha_rows m_rows_to_insert;
ha_rows m_rows_inserted;
ha_rows m_bulk_insert_rows;
+ ha_rows m_rows_changed;
bool m_bulk_insert_not_flushed;
ha_rows m_ops_pending;
bool m_skip_auto_increment;
@@ -248,33 +630,27 @@ class ha_ndbcluster: public handler
bool m_force_send;
ha_rows m_autoincrement_prefetch;
bool m_transaction_on;
- bool m_use_local_query_cache;
-
+ Ndb_cond_stack *m_cond_stack;
+ bool m_disable_multi_read;
+ byte *m_multi_range_result_ptr;
+ KEY_MULTI_RANGE *m_multi_ranges;
+ KEY_MULTI_RANGE *m_multi_range_defined;
+ const NdbOperation *m_current_multi_operation;
+ NdbIndexScanOperation *m_multi_cursor;
+ byte *m_multi_range_cursor_result_ptr;
+ int setup_recattr(const NdbRecAttr*);
Ndb *get_ndb();
- void set_rec_per_key();
- void records_update();
- void no_uncommitted_rows_execute_failure();
- void no_uncommitted_rows_update(int);
- void no_uncommitted_rows_init(THD *);
- void no_uncommitted_rows_reset(THD *);
-
- friend int execute_no_commit(ha_ndbcluster*, NdbConnection*);
- friend int execute_commit(ha_ndbcluster*, NdbConnection*);
- friend int execute_no_commit_ie(ha_ndbcluster*, NdbConnection*);
};
-bool ndbcluster_init(void);
-bool ndbcluster_end(void);
-
-int ndbcluster_commit(THD *thd, void* ndb_transaction);
-int ndbcluster_rollback(THD *thd, void* ndb_transaction);
+extern struct show_var_st ndb_status_variables[];
-void ndbcluster_close_connection(THD *thd);
+handlerton *ndbcluster_init(void);
+bool ndbcluster_end(void);
int ndbcluster_discover(THD* thd, const char* dbname, const char* name,
- const void** frmblob, uint* frmlen);
+ 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);
+ const char *wild, bool dir, List<char> *files);
int ndbcluster_table_exists(THD* thd, const char *db, const char *name);
int ndbcluster_drop_database(const char* path);
diff --git a/sql/handler.cc b/sql/handler.cc
index f174f51514e..7318de1c503 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -25,10 +25,6 @@
#include "ha_heap.h"
#include "ha_myisam.h"
#include "ha_myisammrg.h"
-#ifdef HAVE_ISAM
-#include "ha_isam.h"
-#include "ha_isammrg.h"
-#endif
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"
#endif
@@ -50,29 +46,34 @@
#ifdef HAVE_NDBCLUSTER_DB
#include "ha_ndbcluster.h"
#endif
+#ifdef HAVE_FEDERATED_DB
+#include "ha_federated.h"
+#endif
#include <myisampack.h>
#include <errno.h>
/* static functions defined in this file */
-static int NEAR_F delete_file(const char *name,const char *ext,int extflag);
+static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
-ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count,
- ha_read_key_count, ha_read_next_count, ha_read_prev_count,
- ha_read_first_count, ha_read_last_count,
- ha_commit_count, ha_rollback_count,
- ha_read_rnd_count, ha_read_rnd_next_count, ha_discover_count;
+/* list of all available storage engines (of their handlertons) */
+handlerton *handlertons[MAX_HA]={0};
-static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
+/* number of entries in handlertons[] */
+ulong total_ha;
+/* number of storage engines (from handlertons[]) that support 2pc */
+ulong total_ha_2pc;
+/* size of savepoint storage area (see ha_init) */
+ulong savepoint_alloc_size;
struct show_table_type_st sys_table_types[]=
{
{"MyISAM", &have_yes,
"Default engine as of MySQL 3.23 with great performance", DB_TYPE_MYISAM},
- {"HEAP", &have_yes,
- "Alias for MEMORY", DB_TYPE_HEAP},
{"MEMORY", &have_yes,
"Hash based, stored in memory, useful for temporary tables", DB_TYPE_HEAP},
+ {"HEAP", &have_yes,
+ "Alias for MEMORY", DB_TYPE_HEAP},
{"MERGE", &have_yes,
"Collection of identical MyISAM tables", DB_TYPE_MRG_MYISAM},
{"MRG_MYISAM",&have_yes,
@@ -99,13 +100,16 @@ struct show_table_type_st sys_table_types[]=
"Archive storage engine", DB_TYPE_ARCHIVE_DB},
{"CSV",&have_csv_db,
"CSV storage engine", DB_TYPE_CSV_DB},
+ {"FEDERATED",&have_federated_db,
+ "Federated MySQL storage engine", DB_TYPE_FEDERATED_DB},
{"BLACKHOLE",&have_blackhole_db,
- "Storage engine designed to act as null storage", DB_TYPE_BLACKHOLE_DB},
+ "/dev/null storage engine (anything you write to it disappears)",
+ DB_TYPE_BLACKHOLE_DB},
{NullS, NULL, NullS, DB_TYPE_UNKNOWN}
};
const char *ha_row_type[] = {
- "", "FIXED", "DYNAMIC", "COMPRESSED","?","?","?"
+ "", "FIXED", "DYNAMIC", "COMPRESSED", "REDUNDANT", "COMPACT", "?","?","?"
};
const char *tx_isolation_names[] =
@@ -119,11 +123,11 @@ uint known_extensions_id= 0;
enum db_type ha_resolve_by_name(const char *name, uint namelen)
{
- THD *thd=current_thd;
+ THD *thd= current_thd;
if (thd && !my_strcasecmp(&my_charset_latin1, name, "DEFAULT")) {
return (enum db_type) thd->variables.table_type;
}
-
+
show_table_type_st *types;
for (types= sys_table_types; types->type; types++)
{
@@ -141,7 +145,7 @@ const char *ha_get_storage_engine(enum db_type db_type)
if (db_type == types->db_type)
return types->type;
}
-
+
return "none";
}
@@ -163,6 +167,7 @@ my_bool ha_storage_engine_is_enabled(enum db_type database_type)
enum db_type ha_checktype(enum db_type database_type)
{
+ THD *thd;
if (ha_storage_engine_is_enabled(database_type))
return database_type;
@@ -177,12 +182,13 @@ enum db_type ha_checktype(enum db_type database_type)
break;
}
- return
- DB_TYPE_UNKNOWN != (enum db_type) current_thd->variables.table_type ?
- (enum db_type) current_thd->variables.table_type :
- DB_TYPE_UNKNOWN != (enum db_type) global_system_variables.table_type ?
- (enum db_type) global_system_variables.table_type :
- DB_TYPE_MYISAM;
+ 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 !=
+ DB_TYPE_UNKNOWN ?
+ (enum db_type) global_system_variables.table_type : DB_TYPE_MYISAM)
+ );
} /* ha_checktype */
@@ -222,6 +228,10 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
case DB_TYPE_BLACKHOLE_DB:
return new ha_blackhole(table);
#endif
+#ifdef HAVE_FEDERATED_DB
+ case DB_TYPE_FEDERATED_DB:
+ return new ha_federated(table);
+#endif
#ifdef HAVE_CSV_DB
case DB_TYPE_CSV_DB:
return new ha_tina(table);
@@ -247,65 +257,190 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
}
}
-bool ha_caching_allowed(THD* thd, char* table_key,
- uint key_length, uint8 cache_type)
+/*
+ Register handler error messages for use with my_error().
+
+ SYNOPSIS
+ ha_init_errors()
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
+
+static int ha_init_errors(void)
{
-#ifdef HAVE_INNOBASE_DB
- if (cache_type == HA_CACHE_TBL_ASKTRANSACT)
- return innobase_query_caching_of_table_permitted(thd, table_key, key_length);
-#endif
- return 1;
+#define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg)
+ const char **errmsgs;
+
+ /* Allocate a pointer array for the error message strings. */
+ /* Zerofill it to avoid uninitialized gaps. */
+ if (! (errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*),
+ MYF(MY_WME | MY_ZEROFILL))))
+ return 1;
+
+ /* Set the dedicated error messages. */
+ SETMSG(HA_ERR_KEY_NOT_FOUND, ER(ER_KEY_NOT_FOUND));
+ SETMSG(HA_ERR_FOUND_DUPP_KEY, ER(ER_DUP_KEY));
+ SETMSG(HA_ERR_RECORD_CHANGED, "Update wich is recoverable");
+ SETMSG(HA_ERR_WRONG_INDEX, "Wrong index given to function");
+ SETMSG(HA_ERR_CRASHED, ER(ER_NOT_KEYFILE));
+ SETMSG(HA_ERR_WRONG_IN_RECORD, ER(ER_CRASHED_ON_USAGE));
+ SETMSG(HA_ERR_OUT_OF_MEM, "Table handler out of memory");
+ SETMSG(HA_ERR_NOT_A_TABLE, "Incorrect file format '%.64s'");
+ SETMSG(HA_ERR_WRONG_COMMAND, "Command not supported");
+ SETMSG(HA_ERR_OLD_FILE, ER(ER_OLD_KEYFILE));
+ SETMSG(HA_ERR_NO_ACTIVE_RECORD, "No record read in update");
+ SETMSG(HA_ERR_RECORD_DELETED, "Intern record deleted");
+ SETMSG(HA_ERR_RECORD_FILE_FULL, ER(ER_RECORD_FILE_FULL));
+ SETMSG(HA_ERR_INDEX_FILE_FULL, "No more room in index file '%.64s'");
+ SETMSG(HA_ERR_END_OF_FILE, "End in next/prev/first/last");
+ SETMSG(HA_ERR_UNSUPPORTED, ER(ER_ILLEGAL_HA));
+ SETMSG(HA_ERR_TO_BIG_ROW, "Too big row");
+ SETMSG(HA_WRONG_CREATE_OPTION, "Wrong create option");
+ SETMSG(HA_ERR_FOUND_DUPP_UNIQUE, ER(ER_DUP_UNIQUE));
+ SETMSG(HA_ERR_UNKNOWN_CHARSET, "Can't open charset");
+ SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF, ER(ER_WRONG_MRG_TABLE));
+ SETMSG(HA_ERR_CRASHED_ON_REPAIR, ER(ER_CRASHED_ON_REPAIR));
+ SETMSG(HA_ERR_CRASHED_ON_USAGE, ER(ER_CRASHED_ON_USAGE));
+ SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT, ER(ER_LOCK_WAIT_TIMEOUT));
+ SETMSG(HA_ERR_LOCK_TABLE_FULL, ER(ER_LOCK_TABLE_FULL));
+ SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER(ER_READ_ONLY_TRANSACTION));
+ SETMSG(HA_ERR_LOCK_DEADLOCK, ER(ER_LOCK_DEADLOCK));
+ SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER(ER_CANNOT_ADD_FOREIGN));
+ SETMSG(HA_ERR_NO_REFERENCED_ROW, ER(ER_NO_REFERENCED_ROW));
+ SETMSG(HA_ERR_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED));
+ SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name");
+ SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size");
+ SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'");
+ SETMSG(HA_ERR_TABLE_EXIST, ER(ER_TABLE_EXISTS_ERROR));
+ SETMSG(HA_ERR_NO_CONNECTION, "Could not connect to storage engine");
+ SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER(ER_TABLE_DEF_CHANGED));
+
+ /* Register the error messages for use with my_error(). */
+ return my_error_register(errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
+}
+
+
+/*
+ Unregister handler error messages.
+
+ SYNOPSIS
+ ha_finish_errors()
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
+
+static int ha_finish_errors(void)
+{
+ const char **errmsgs;
+
+ /* Allocate a pointer array for the error message strings. */
+ if (! (errmsgs= my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST)))
+ return 1;
+ my_free((gptr) errmsgs, MYF(0));
+ return 0;
+}
+
+
+static inline void ha_was_inited_ok(handlerton **ht)
+{
+ uint tmp= (*ht)->savepoint_offset;
+ (*ht)->savepoint_offset= savepoint_alloc_size;
+ savepoint_alloc_size+= tmp;
+ (*ht)->slot= total_ha++;
+ if ((*ht)->prepare)
+ total_ha_2pc++;
}
int ha_init()
{
int error= 0;
+ handlerton **ht= handlertons;
+ total_ha= savepoint_alloc_size= 0;
+
+ if (ha_init_errors())
+ return 1;
+
+ if (opt_bin_log)
+ {
+ if (!(*ht= binlog_init()))
+ {
+ mysql_bin_log.close(LOG_CLOSE_INDEX);
+ opt_bin_log= 0;
+ error= 1;
+ }
+ else
+ ha_was_inited_ok(ht++);
+ }
#ifdef HAVE_BERKELEY_DB
if (have_berkeley_db == SHOW_OPTION_YES)
{
- if (berkeley_init())
+ if (!(*ht= berkeley_init()))
{
have_berkeley_db= SHOW_OPTION_DISABLED; // If we couldn't use handler
error= 1;
}
else
- opt_using_transactions=1;
+ ha_was_inited_ok(ht++);
}
#endif
#ifdef HAVE_INNOBASE_DB
if (have_innodb == SHOW_OPTION_YES)
{
- if (innobase_init())
+ if (!(*ht= innobase_init()))
{
have_innodb= SHOW_OPTION_DISABLED; // If we couldn't use handler
error= 1;
}
else
- opt_using_transactions=1;
+ ha_was_inited_ok(ht++);
}
#endif
#ifdef HAVE_NDBCLUSTER_DB
if (have_ndbcluster == SHOW_OPTION_YES)
{
- if (ndbcluster_init())
+ if (!(*ht= ndbcluster_init()))
{
have_ndbcluster= SHOW_OPTION_DISABLED;
error= 1;
}
else
- opt_using_transactions=1;
+ ha_was_inited_ok(ht++);
+ }
+#endif
+#ifdef HAVE_FEDERATED_DB
+ if (have_federated_db == SHOW_OPTION_YES)
+ {
+ if (federated_db_init())
+ {
+ have_federated_db= SHOW_OPTION_DISABLED;
+ error= 1;
+ }
}
#endif
#ifdef HAVE_ARCHIVE_DB
if (have_archive_db == SHOW_OPTION_YES)
{
- if (archive_db_init())
+ if (!(*ht= archive_db_init()))
{
have_archive_db= SHOW_OPTION_DISABLED;
error= 1;
}
+ else
+ ha_was_inited_ok(ht++);
}
#endif
+ DBUG_ASSERT(total_ha < MAX_HA);
+ /*
+ Check if there is a transaction-capable storage engine besides the
+ binary log (which is considered a transaction-capable storage engine in
+ counting total_ha)
+ */
+ opt_using_transactions= total_ha>(ulong)opt_bin_log;
+ savepoint_alloc_size+= sizeof(SAVEPOINT);
return error;
}
@@ -337,10 +472,16 @@ int ha_panic(enum ha_panic_function flag)
if (have_ndbcluster == SHOW_OPTION_YES)
error|=ndbcluster_end();
#endif
+#ifdef HAVE_FEDERATED_DB
+ if (have_federated_db == SHOW_OPTION_YES)
+ error|= federated_db_end();
+#endif
#ifdef HAVE_ARCHIVE_DB
if (have_archive_db == SHOW_OPTION_YES)
error|= archive_db_end();
#endif
+ if (ha_finish_errors())
+ error= 1;
return error;
} /* ha_panic */
@@ -356,16 +497,238 @@ void ha_drop_database(char* path)
#endif
}
+/* don't bother to rollback here, it's done already */
void ha_close_connection(THD* thd)
{
-#ifdef HAVE_INNOBASE_DB
- if (have_innodb == SHOW_OPTION_YES)
- innobase_close_connection(thd);
-#endif
-#ifdef HAVE_NDBCLUSTER_DB
- if (have_ndbcluster == SHOW_OPTION_YES)
- ndbcluster_close_connection(thd);
+ for (uint i=0; i < total_ha; i++)
+ if (thd->ha_data[i])
+ (*handlertons[i]->close_connection)(thd);
+}
+
+/* ========================================================================
+ ======================= TRANSACTIONS ===================================*/
+
+/*
+ Register a storage engine for a transaction
+
+ DESCRIPTION
+ Every storage engine MUST call this function when it starts
+ a transaction or a statement (that is it must be called both for the
+ "beginning of transaction" and "beginning of statement").
+ Only storage engines registered for the transaction/statement
+ will know when to commit/rollback it.
+
+ NOTE
+ trans_register_ha is idempotent - storage engine may register many
+ times per transaction.
+
+*/
+void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
+{
+ THD_TRANS *trans;
+ handlerton **ht;
+ DBUG_ENTER("trans_register_ha");
+ DBUG_PRINT("enter",("%s", all ? "all" : "stmt"));
+
+ if (all)
+ {
+ trans= &thd->transaction.all;
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+ }
+ else
+ trans= &thd->transaction.stmt;
+
+ for (ht=trans->ht; *ht; ht++)
+ if (*ht == ht_arg)
+ DBUG_VOID_RETURN; /* already registered, return */
+
+ trans->ht[trans->nht++]=ht_arg;
+ DBUG_ASSERT(*ht == ht_arg);
+ trans->no_2pc|=(ht_arg->prepare==0);
+ if (thd->transaction.xid.is_null())
+ thd->transaction.xid.set(thd->query_id);
+ DBUG_VOID_RETURN;
+}
+
+/*
+ RETURN
+ 0 - ok
+ 1 - error, transaction was rolled back
+*/
+int ha_prepare(THD *thd)
+{
+ int error=0, all=1;
+ THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
+ handlerton **ht=trans->ht;
+ DBUG_ENTER("ha_prepare");
+#ifdef USING_TRANSACTIONS
+ if (trans->nht)
+ {
+ for (; *ht; ht++)
+ {
+ int err;
+ statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status);
+ if ((err= (*(*ht)->prepare)(thd, all)))
+ {
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
+ ha_rollback_trans(thd, all);
+ error=1;
+ break;
+ }
+ }
+ }
+#endif /* USING_TRANSACTIONS */
+ DBUG_RETURN(error);
+}
+
+/*
+ RETURN
+ 0 - ok
+ 1 - transaction was rolled back
+ 2 - error during commit, data may be inconsistent
+*/
+int ha_commit_trans(THD *thd, bool all)
+{
+ int error= 0, cookie= 0;
+ THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt;
+ bool is_real_trans= all || thd->transaction.all.nht == 0;
+ handlerton **ht= trans->ht;
+ my_xid xid= thd->transaction.xid.get_my_xid();
+ DBUG_ENTER("ha_commit_trans");
+#ifdef USING_TRANSACTIONS
+ if (trans->nht)
+ {
+ if (is_real_trans && wait_if_global_read_lock(thd, 0, 0))
+ {
+ ha_rollback_trans(thd, all);
+ DBUG_RETURN(1);
+ }
+ DBUG_EXECUTE_IF("crash_commit_before", abort(););
+ if (!trans->no_2pc && trans->nht > 1)
+ {
+ for (; *ht && !error; ht++)
+ {
+ int err;
+ if ((err= (*(*ht)->prepare)(thd, all)))
+ {
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
+ error= 1;
+ }
+ statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status);
+ }
+ DBUG_EXECUTE_IF("crash_commit_after_prepare", abort(););
+ if (error || (is_real_trans && xid &&
+ (error= !(cookie= tc_log->log(thd, xid)))))
+ {
+ ha_rollback_trans(thd, all);
+ error= 1;
+ goto end;
+ }
+ DBUG_EXECUTE_IF("crash_commit_after_log", abort(););
+ }
+ error=ha_commit_one_phase(thd, all) ? cookie ? 2 : 1 : 0;
+ DBUG_EXECUTE_IF("crash_commit_before_unlog", abort(););
+ if (cookie)
+ tc_log->unlog(cookie, xid);
+ DBUG_EXECUTE_IF("crash_commit_after", abort(););
+end:
+ if (is_real_trans)
+ start_waiting_global_read_lock(thd);
+ }
+#endif /* USING_TRANSACTIONS */
+ DBUG_RETURN(error);
+}
+
+/*
+ NOTE - this function does not care about global read lock.
+ A caller should.
+*/
+int ha_commit_one_phase(THD *thd, bool all)
+{
+ int error=0;
+ THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
+ bool is_real_trans=all || thd->transaction.all.nht == 0;
+ handlerton **ht=trans->ht;
+ DBUG_ENTER("ha_commit_one_phase");
+#ifdef USING_TRANSACTIONS
+ if (trans->nht)
+ {
+ for (ht=trans->ht; *ht; ht++)
+ {
+ int err;
+ if ((err= (*(*ht)->commit)(thd, all)))
+ {
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
+ error=1;
+ }
+ statistic_increment(thd->status_var.ha_commit_count,&LOCK_status);
+ *ht= 0;
+ }
+ trans->nht=0;
+ trans->no_2pc=0;
+ if (is_real_trans)
+ thd->transaction.xid.null();
+ if (all)
+ {
+#ifdef HAVE_QUERY_CACHE
+ if (thd->transaction.changed_tables)
+ query_cache.invalidate(thd->transaction.changed_tables);
#endif
+ thd->variables.tx_isolation=thd->session_tx_isolation;
+ thd->transaction.cleanup();
+ }
+ }
+#endif /* USING_TRANSACTIONS */
+ DBUG_RETURN(error);
+}
+
+
+int ha_rollback_trans(THD *thd, bool all)
+{
+ int error=0;
+ THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
+ bool is_real_trans=all || thd->transaction.all.nht == 0;
+ DBUG_ENTER("ha_rollback_trans");
+#ifdef USING_TRANSACTIONS
+ if (trans->nht)
+ {
+ for (handlerton **ht=trans->ht; *ht; ht++)
+ {
+ int err;
+ if ((err= (*(*ht)->rollback)(thd, all)))
+ { // cannot happen
+ my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
+ error=1;
+ }
+ statistic_increment(thd->status_var.ha_rollback_count,&LOCK_status);
+ *ht= 0;
+ }
+ trans->nht=0;
+ trans->no_2pc=0;
+ if (is_real_trans)
+ thd->transaction.xid.null();
+ if (all)
+ {
+ thd->variables.tx_isolation=thd->session_tx_isolation;
+ thd->transaction.cleanup();
+ }
+ }
+#endif /* USING_TRANSACTIONS */
+ /*
+ If a non-transactional table was updated, warn; don't warn if this is a
+ slave thread (because when a slave thread executes a ROLLBACK, it has
+ been read from the binary log, so it's 100% sure and normal to produce
+ error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
+ slave SQL thread, it would not stop the thread but just be printed in
+ the error log; but we don't want users to wonder why they have this
+ message in the error log, so we don't send it.
+ */
+ if (is_real_trans && (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ !thd->slave_thread)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARNING_NOT_COMPLETE_ROLLBACK,
+ ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
+ DBUG_RETURN(error);
}
/*
@@ -381,7 +744,7 @@ int ha_autocommit_or_rollback(THD *thd, int error)
{
DBUG_ENTER("ha_autocommit_or_rollback");
#ifdef USING_TRANSACTIONS
- if (opt_using_transactions)
+ if (thd->transaction.stmt.nht)
{
if (!error)
{
@@ -397,83 +760,264 @@ int ha_autocommit_or_rollback(THD *thd, int error)
DBUG_RETURN(error);
}
+int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
+{
+ handlerton **ht= handlertons, **end_ht=ht+total_ha;
+ int res= 1;
+
+ for ( ; ht < end_ht ; ht++)
+ if ((*ht)->recover)
+ res= res &&
+ (*(commit ? (*ht)->commit_by_xid : (*ht)->rollback_by_xid))(xid);
+ return res;
+}
+
+#ifndef DBUG_OFF
+/* this does not need to be multi-byte safe or anything */
+static char* xid_to_str(char *buf, XID *xid)
+{
+ int i;
+ char *s=buf;
+ *s++='\'';
+ for (i=0; i < xid->gtrid_length+xid->bqual_length; i++)
+ {
+ uchar c=(uchar)xid->data[i];
+ /* is_next_dig is set if next character is a number */
+ bool is_next_dig= FALSE;
+ if (i < XIDDATASIZE)
+ {
+ char ch= xid->data[i+1];
+ is_next_dig= (ch >= '0' && ch <='9');
+ }
+ if (i == xid->gtrid_length)
+ {
+ *s++='\'';
+ if (xid->bqual_length)
+ {
+ *s++='.';
+ *s++='\'';
+ }
+ }
+ if (c < 32 || c > 126)
+ {
+ *s++='\\';
+ /*
+ If next character is a number, write current character with
+ 3 octal numbers to ensure that the next number is not seen
+ as part of the octal number
+ */
+ if (c > 077 || is_next_dig)
+ *s++=_dig_vec_lower[c >> 6];
+ if (c > 007 || is_next_dig)
+ *s++=_dig_vec_lower[(c >> 3) & 7];
+ *s++=_dig_vec_lower[c & 7];
+ }
+ else
+ {
+ if (c == '\'' || c == '\\')
+ *s++='\\';
+ *s++=c;
+ }
+ }
+ *s++='\'';
+ *s=0;
+ return buf;
+}
+#endif
+
/*
- This function is called when MySQL writes the log segment of a
- transaction to the binlog. It is called when the LOCK_log mutex is
- reserved. Here we communicate to transactional table handlers what
- binlog position corresponds to the current transaction. The handler
- can store it and in recovery print to the user, so that the user
- knows from what position in the binlog to start possible
- roll-forward, for example, if the crashed server was a slave in
- replication. This function also calls the commit of the table
- handler, because the order of transactions in the log of the table
- handler must be the same as in the binlog.
- NOTE that to eliminate the bottleneck of the group commit, we do not
- flush the handler log files here, but only later in a call of
- ha_commit_complete().
+ recover() step of xa
- arguments:
- thd: the thread handle of the current connection
- log_file_name: latest binlog file name
- end_offset: the offset in the binlog file up to which we wrote
- return value: 0 if success, 1 if error
-*/
+ NOTE
+ there are three modes of operation:
-int ha_report_binlog_offset_and_commit(THD *thd,
- char *log_file_name,
- my_off_t end_offset)
+ - automatic recover after a crash
+ in this case commit_list != 0, tc_heuristic_recover==0
+ all xids from commit_list are committed, others are rolled back
+
+ - manual (heuristic) recover
+ in this case commit_list==0, tc_heuristic_recover != 0
+ DBA has explicitly specified that all prepared transactions should
+ be committed (or rolled back).
+
+ - no recovery (MySQL did not detect a crash)
+ in this case commit_list==0, tc_heuristic_recover == 0
+ there should be no prepared transactions in this case.
+*/
+int ha_recover(HASH *commit_list)
{
- int error= 0;
-#ifdef HAVE_INNOBASE_DB
- THD_TRANS *trans;
- trans = &thd->transaction.all;
- if (trans->innodb_active_trans)
+ int len, got, found_foreign_xids=0, found_my_xids=0;
+ handlerton **ht= handlertons, **end_ht=ht+total_ha;
+ XID *list=0;
+ bool dry_run=(commit_list==0 && tc_heuristic_recover==0);
+ DBUG_ENTER("ha_recover");
+
+ /* commit_list and tc_heuristic_recover cannot be set both */
+ DBUG_ASSERT(commit_list==0 || tc_heuristic_recover==0);
+ /* if either is set, total_ha_2pc must be set too */
+ DBUG_ASSERT(dry_run || total_ha_2pc>(ulong)opt_bin_log);
+
+ if (total_ha_2pc <= (ulong)opt_bin_log)
+ DBUG_RETURN(0);
+
+ if (commit_list)
+ sql_print_information("Starting crash recovery...");
+
+#ifndef WILL_BE_DELETED_LATER
+ /*
+ for now, only InnoDB supports 2pc. It means we can always safely
+ rollback all pending transactions, without risking inconsistent data
+ */
+ DBUG_ASSERT(total_ha_2pc == (ulong) opt_bin_log+1); // only InnoDB and binlog
+ tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
+ dry_run=FALSE;
+#endif
+
+ for (len= MAX_XID_LIST_SIZE ; list==0 && len > MIN_XID_LIST_SIZE; len/=2)
{
- /*
- If we updated some InnoDB tables (innodb_active_trans is true), the
- binlog coords will be reported into InnoDB during the InnoDB commit
- (innobase_report_binlog_offset_and_commit). But if we updated only
- non-InnoDB tables, we need an explicit call to report it.
- */
- if ((error=innobase_report_binlog_offset_and_commit(thd,
- trans->innobase_tid,
- log_file_name,
- end_offset)))
+ list=(XID *)my_malloc(len*sizeof(XID), MYF(0));
+ }
+ if (!list)
+ {
+ sql_print_error(ER(ER_OUTOFMEMORY), len*sizeof(XID));
+ DBUG_RETURN(1);
+ }
+
+ for ( ; ht < end_ht ; ht++)
+ {
+ if (!(*ht)->recover)
+ continue;
+ while ((got=(*(*ht)->recover)(list, len)) > 0 )
{
- my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
- error=1;
+ sql_print_information("Found %d prepared transaction(s) in %s",
+ got, (*ht)->name);
+ for (int i=0; i < got; i ++)
+ {
+ my_xid x=list[i].get_my_xid();
+ if (!x) // not "mine" - that is generated by external TM
+ {
+#ifndef DBUG_OFF
+ char buf[XIDDATASIZE*4+6]; // see xid_to_str
+ sql_print_information("ignore xid %s", xid_to_str(buf, list+i));
+#endif
+ found_foreign_xids++;
+ continue;
+ }
+ if (dry_run)
+ {
+ found_my_xids++;
+ continue;
+ }
+ // recovery mode
+ if (commit_list ?
+ hash_search(commit_list, (byte *)&x, sizeof(x)) != 0 :
+ tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
+ {
+#ifndef DBUG_OFF
+ char buf[XIDDATASIZE*4+6]; // see xid_to_str
+ sql_print_information("commit xid %s", xid_to_str(buf, list+i));
+#endif
+ (*(*ht)->commit_by_xid)(list+i);
+ }
+ else
+ {
+#ifndef DBUG_OFF
+ char buf[XIDDATASIZE*4+6]; // see xid_to_str
+ sql_print_information("rollback xid %s", xid_to_str(buf, list+i));
+#endif
+ (*(*ht)->rollback_by_xid)(list+i);
+ }
+ }
+ if (got < len)
+ break;
}
}
- else if (opt_innodb_safe_binlog) // Don't report if not useful
- innobase_store_binlog_offset_and_flush_log(log_file_name, end_offset);
-#endif
- return error;
+ my_free((gptr)list, MYF(0));
+ if (found_foreign_xids)
+ sql_print_warning("Found %d prepared XA transactions", found_foreign_xids);
+ if (dry_run && found_my_xids)
+ {
+ sql_print_error("Found %d prepared transactions! It means that mysqld was "
+ "not shut down properly last time and critical recovery "
+ "information (last binlog or %s file) was manually deleted "
+ "after a crash. You have to start mysqld with "
+ "--tc-heuristic-recover switch to commit or rollback "
+ "pending transactions.",
+ found_my_xids, opt_tc_log_file);
+ DBUG_RETURN(1);
+ }
+ if (commit_list)
+ sql_print_information("Crash recovery finished.");
+ DBUG_RETURN(0);
}
/*
- Flushes the handler log files (if my.cnf settings do not free us from it)
- after we have called ha_report_binlog_offset_and_commit(). To eliminate
- the bottleneck from the group commit, this should be called when
- LOCK_log has been released in log.cc.
+ return the list of XID's to a client, the same way SHOW commands do
- arguments:
- thd: the thread handle of the current connection
- return value: always 0
+ NOTE
+ I didn't find in XA specs that an RM cannot return the same XID twice,
+ so mysql_xa_recover does not filter XID's to ensure uniqueness.
+ It can be easily fixed later, if necessary.
*/
-
-int ha_commit_complete(THD *thd)
+bool mysql_xa_recover(THD *thd)
{
-#ifdef HAVE_INNOBASE_DB
- THD_TRANS *trans;
- trans = &thd->transaction.all;
- if (trans->innobase_tid)
+ List<Item> field_list;
+ Protocol *protocol= thd->protocol;
+ handlerton **ht= handlertons, **end_ht=ht+total_ha;
+ bool error=TRUE;
+ int len, got;
+ XID *list=0;
+ DBUG_ENTER("mysql_xa_recover");
+
+ field_list.push_back(new Item_int("formatID",0,11));
+ field_list.push_back(new Item_int("gtrid_length",0,11));
+ field_list.push_back(new Item_int("bqual_length",0,11));
+ field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
+
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
+
+ for (len= MAX_XID_LIST_SIZE ; list==0 && len > MIN_XID_LIST_SIZE; len/=2)
+ {
+ list=(XID *)my_malloc(len*sizeof(XID), MYF(0));
+ }
+ if (!list)
{
- innobase_commit_complete(trans->innobase_tid);
+ my_error(ER_OUTOFMEMORY, MYF(0), len);
+ DBUG_RETURN(1);
+ }
- trans->innodb_active_trans=0;
+ for ( ; ht < end_ht ; ht++)
+ {
+ if (!(*ht)->recover)
+ continue;
+ while ((got=(*(*ht)->recover)(list, len)) > 0 )
+ {
+ XID *xid, *end;
+ for (xid=list, end=list+got; xid < end; xid++)
+ {
+ if (xid->get_my_xid())
+ continue; // skip "our" xids
+ protocol->prepare_for_resend();
+ protocol->store_longlong((longlong)xid->formatID, FALSE);
+ protocol->store_longlong((longlong)xid->gtrid_length, FALSE);
+ protocol->store_longlong((longlong)xid->bqual_length, FALSE);
+ protocol->store(xid->data, xid->gtrid_length+xid->bqual_length,
+ &my_charset_bin);
+ if (protocol->write())
+ goto err;
+ }
+ if (got < len)
+ break;
+ }
}
-#endif
- return 0;
+
+ error=FALSE;
+ send_eof(thd);
+err:
+ my_free((gptr)list, MYF(0));
+ DBUG_RETURN(error);
}
/*
@@ -496,313 +1040,126 @@ int ha_commit_complete(THD *thd)
int ha_release_temporary_latches(THD *thd)
{
#ifdef HAVE_INNOBASE_DB
- THD_TRANS *trans;
- trans = &thd->transaction.all;
- if (trans->innobase_tid)
- innobase_release_temporary_latches(trans->innobase_tid);
+ if (opt_innodb)
+ innobase_release_temporary_latches(thd);
#endif
return 0;
}
-int ha_commit_trans(THD *thd, THD_TRANS* trans)
-{
- int error=0;
- DBUG_ENTER("ha_commit_trans");
-#ifdef USING_TRANSACTIONS
- if (opt_using_transactions)
- {
- bool transaction_commited= 0;
- bool operation_done= 0, need_start_waiters= 0;
- /* If transaction has done some updates to tables */
- if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
- my_b_tell(&thd->transaction.trans_log))
- {
- if ((error= wait_if_global_read_lock(thd, 0, 0)))
- {
- /*
- Note that ROLLBACK [TO SAVEPOINT] does not have this test; it's
- because ROLLBACK never updates data, so needn't wait on the lock.
- */
- my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
- error= 1;
- }
- else
- need_start_waiters= 1;
- if (mysql_bin_log.is_open())
- {
- mysql_bin_log.write(thd, &thd->transaction.trans_log, 1);
- statistic_increment(binlog_cache_use, &LOCK_status);
- if (thd->transaction.trans_log.disk_writes != 0)
- {
- /*
- We have to do this after addition of trans_log to main binlog since
- this operation can cause flushing of end of trans_log to disk.
- */
- statistic_increment(binlog_cache_disk_use, &LOCK_status);
- thd->transaction.trans_log.disk_writes= 0;
- }
- reinit_io_cache(&thd->transaction.trans_log,
- WRITE_CACHE, (my_off_t) 0, 0, 1);
- thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
- }
- }
-#ifdef HAVE_NDBCLUSTER_DB
- if (trans->ndb_tid)
- {
- if ((error=ndbcluster_commit(thd,trans->ndb_tid)))
- {
- if (error == -1)
- my_error(ER_ERROR_DURING_COMMIT, MYF(0));
- error=1;
- }
- if (trans == &thd->transaction.all)
- operation_done= transaction_commited= 1;
- trans->ndb_tid=0;
- }
-#endif
-#ifdef HAVE_BERKELEY_DB
- if (trans->bdb_tid)
- {
- if ((error=berkeley_commit(thd,trans->bdb_tid)))
- {
- my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
- error=1;
- }
- else
- if (!(thd->options & OPTION_BEGIN))
- transaction_commited= 1;
- trans->bdb_tid=0;
- }
-#endif
+/*
+ Export statistics for different engines. Currently we use it only for
+ InnoDB.
+*/
+
+int ha_update_statistics()
+{
#ifdef HAVE_INNOBASE_DB
- if (trans->innobase_tid)
- {
- if ((error=innobase_commit(thd,trans->innobase_tid)))
- {
- my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
- error=1;
- }
- trans->innodb_active_trans=0;
- if (trans == &thd->transaction.all)
- operation_done= transaction_commited= 1;
- }
+ if (opt_innodb)
+ innodb_export_status();
#endif
-#ifdef HAVE_QUERY_CACHE
- if (transaction_commited && thd->transaction.changed_tables)
- query_cache.invalidate(thd->transaction.changed_tables);
-#endif /*HAVE_QUERY_CACHE*/
- if (error && trans == &thd->transaction.all && mysql_bin_log.is_open())
- sql_print_error("Got error during commit; Binlog is not up to date!");
- thd->variables.tx_isolation=thd->session_tx_isolation;
- if (operation_done)
- {
- statistic_increment(ha_commit_count,&LOCK_status);
- thd->transaction.cleanup();
- }
- if (need_start_waiters)
- start_waiting_global_read_lock(thd);
- }
-#endif // using transactions
- DBUG_RETURN(error);
+ return 0;
}
-
-int ha_rollback_trans(THD *thd, THD_TRANS *trans)
+int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
{
int error=0;
- DBUG_ENTER("ha_rollback_trans");
-#ifdef USING_TRANSACTIONS
- if (opt_using_transactions)
+ THD_TRANS *trans=&thd->transaction.all;
+ handlerton **ht=trans->ht, **end_ht;
+ DBUG_ENTER("ha_rollback_to_savepoint");
+ DBUG_ASSERT(thd->transaction.stmt.ht[0] == 0);
+
+ trans->nht=sv->nht;
+ trans->no_2pc=0;
+ end_ht=ht+sv->nht;
+ /*
+ rolling back to savepoint in all storage engines that were part of the
+ transaction when the savepoint was set
+ */
+ for (; ht < end_ht; ht++)
{
- bool operation_done=0;
- /*
- As rollback can be 30 times slower than insert in InnoDB, and user may
- not know there's rollback (if it's because of a dupl row), better warn.
- */
- const char *save_proc_info= thd->proc_info;
- thd->proc_info= "Rolling back";
-#ifdef HAVE_NDBCLUSTER_DB
- if (trans->ndb_tid)
- {
- if ((error=ndbcluster_rollback(thd, trans->ndb_tid)))
- {
- if (error == -1)
- my_error(ER_ERROR_DURING_ROLLBACK, MYF(0));
- error=1;
- }
- trans->ndb_tid = 0;
- operation_done=1;
- }
-#endif
-#ifdef HAVE_BERKELEY_DB
- if (trans->bdb_tid)
- {
- if ((error=berkeley_rollback(thd, trans->bdb_tid)))
- {
- my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
- error=1;
- }
- trans->bdb_tid=0;
- operation_done=1;
- }
-#endif
-#ifdef HAVE_INNOBASE_DB
- if (trans->innobase_tid)
- {
- if ((error=innobase_rollback(thd, trans->innobase_tid)))
- {
- my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
- error=1;
- }
- trans->innodb_active_trans=0;
- operation_done=1;
+ int err;
+ DBUG_ASSERT((*ht)->savepoint_set != 0);
+ if ((err= (*(*ht)->savepoint_rollback)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
+ { // cannot happen
+ my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
+ error=1;
}
-#endif
- if ((trans == &thd->transaction.all) && mysql_bin_log.is_open())
- {
- /*
- Update the binary log with a BEGIN/ROLLBACK block if we have
- cached some queries and we updated some non-transactional
- table. Such cases should be rare (updating a
- non-transactional table inside a transaction...). Count disk
- writes to trans_log in any case.
- */
- if (my_b_tell(&thd->transaction.trans_log))
- {
- if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE))
- mysql_bin_log.write(thd, &thd->transaction.trans_log, 0);
- statistic_increment(binlog_cache_use, &LOCK_status);
- if (thd->transaction.trans_log.disk_writes != 0)
- {
- /*
- We have to do this after addition of trans_log to main binlog since
- this operation can cause flushing of end of trans_log to disk.
- */
- statistic_increment(binlog_cache_disk_use, &LOCK_status);
- thd->transaction.trans_log.disk_writes= 0;
- }
- }
- /* Flushed or not, empty the binlog cache */
- reinit_io_cache(&thd->transaction.trans_log,
- WRITE_CACHE, (my_off_t) 0, 0, 1);
- thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
- if (operation_done)
- thd->transaction.cleanup();
+ statistic_increment(thd->status_var.ha_savepoint_rollback_count,&LOCK_status);
+ trans->no_2pc|=(*ht)->prepare == 0;
+ }
+ /*
+ rolling back the transaction in all storage engines that were not part of
+ the transaction when the savepoint was set
+ */
+ for (; *ht ; ht++)
+ {
+ int err;
+ if ((err= (*(*ht)->rollback)(thd, 1)))
+ { // cannot happen
+ my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
+ error=1;
}
- thd->variables.tx_isolation=thd->session_tx_isolation;
- if (operation_done)
- statistic_increment(ha_rollback_count,&LOCK_status);
- thd->proc_info= save_proc_info;
+ statistic_increment(thd->status_var.ha_rollback_count,&LOCK_status);
+ *ht=0; // keep it conveniently zero-filled
}
-#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
-
/*
- Rolls the current transaction back to a savepoint.
- Return value: 0 if success, 1 if there was not a savepoint of the given
- name.
- NOTE: how do we handle this (unlikely but legal) case:
- [transaction] + [update to non-trans table] + [rollback to savepoint] ?
- The problem occurs when a savepoint is before the update to the
- non-transactional table. Then when there's a rollback to the savepoint, if we
- simply truncate the binlog cache, we lose the part of the binlog cache where
- the update is. If we want to not lose it, we need to write the SAVEPOINT
- command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
- is easy: it's just write at the end of the binlog cache, but the former
- should be *inserted* to the place where the user called SAVEPOINT. The
- solution is that when the user calls SAVEPOINT, we write it to the binlog
- cache (so no need to later insert it). As transactions are never intermixed
- in the binary log (i.e. they are serialized), we won't have conflicts with
- savepoint names when using mysqlbinlog or in the slave SQL thread.
- Then when ROLLBACK TO SAVEPOINT is called, if we updated some
- non-transactional table, we don't truncate the binlog cache but instead write
- ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
- will chop the SAVEPOINT command from the binlog cache, which is good as in
- that case there is no need to have it in the binlog).
+ note, that according to the sql standard (ISO/IEC 9075-2:2003)
+ section "4.33.4 SQL-statements and transaction states",
+ SAVEPOINT is *not* transaction-initiating SQL-statement
*/
-int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
+int ha_savepoint(THD *thd, SAVEPOINT *sv)
{
- my_off_t binlog_cache_pos=0;
- bool operation_done=0;
int error=0;
- DBUG_ENTER("ha_rollback_to_savepoint");
+ THD_TRANS *trans=&thd->transaction.all;
+ handlerton **ht=trans->ht;
+ DBUG_ENTER("ha_savepoint");
+ DBUG_ASSERT(thd->transaction.stmt.ht[0] == 0);
#ifdef USING_TRANSACTIONS
- if (opt_using_transactions)
+ for (; *ht; ht++)
{
-#ifdef HAVE_INNOBASE_DB
- /*
- Retrieve the trans_log binlog cache position corresponding to the
- savepoint, and if the rollback is successful inside InnoDB reset the write
- position in the binlog cache to what it was at the savepoint.
- */
- if ((error=innobase_rollback_to_savepoint(thd, savepoint_name,
- &binlog_cache_pos)))
+ int err;
+ if (! (*ht)->savepoint_set)
{
- my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
+ my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT");
error=1;
+ break;
}
- else if (mysql_bin_log.is_open())
- {
- /*
- Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
- non-transactional table. Otherwise, truncate the binlog cache starting
- from the SAVEPOINT command.
- */
- if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
- my_b_tell(&thd->transaction.trans_log)))
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
- if (mysql_bin_log.write(&qinfo))
- error= 1;
- }
- else
- reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE,
- binlog_cache_pos, 0, 0);
+ if ((err= (*(*ht)->savepoint_set)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
+ { // cannot happen
+ my_error(ER_GET_ERRNO, MYF(0), err);
+ error=1;
}
- operation_done=1;
-#endif
- if (operation_done)
- statistic_increment(ha_rollback_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_savepoint_count,&LOCK_status);
}
+ sv->nht=trans->nht;
#endif /* USING_TRANSACTIONS */
-
DBUG_RETURN(error);
}
-
-/*
-Sets a transaction savepoint.
-Return value: always 0, that is, succeeds always
-*/
-
-int ha_savepoint(THD *thd, char *savepoint_name)
+int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
{
int error=0;
- DBUG_ENTER("ha_savepoint");
-#ifdef USING_TRANSACTIONS
- if (opt_using_transactions)
+ handlerton **ht=thd->transaction.all.ht, **end_ht;
+ DBUG_ENTER("ha_release_savepoint");
+ DBUG_ASSERT(thd->transaction.stmt.ht[0] == 0);
+
+ end_ht=ht+sv->nht;
+ for (; ht < end_ht; ht++)
{
- /* Write it to the binary log (see comments of ha_rollback_to_savepoint) */
- if (mysql_bin_log.is_open())
- {
-#ifdef HAVE_INNOBASE_DB
- innobase_savepoint(thd,savepoint_name,
- my_b_tell(&thd->transaction.trans_log));
-#endif
- Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
- if (mysql_bin_log.write(&qinfo))
- error= 1;
+ int err;
+ if (!(*ht)->savepoint_release)
+ continue;
+ if ((err= (*(*ht)->savepoint_release)(thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
+ { // cannot happen
+ my_error(ER_GET_ERRNO, MYF(0), err);
+ error=1;
}
-#ifdef HAVE_INNOBASE_DB
- else
- innobase_savepoint(thd,savepoint_name,0);
-#endif
}
-#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
@@ -846,12 +1203,25 @@ bool ha_flush_logs()
The .frm file will be deleted only if we return 0 or ENOENT
*/
-int ha_delete_table(enum db_type table_type, const char *path)
+int ha_delete_table(THD *thd, enum db_type table_type, const char *path,
+ const char *alias, bool generate_warning)
{
+ handler *file;
char tmp_path[FN_REFLEN];
- handler *file=get_new_handler((TABLE*) 0, table_type);
- if (!file)
- return ENOENT;
+ int error;
+ TABLE dummy_table;
+ TABLE_SHARE dummy_share;
+ DBUG_ENTER("ha_delete_table");
+
+ bzero((char*) &dummy_table, sizeof(dummy_table));
+ bzero((char*) &dummy_share, sizeof(dummy_share));
+ dummy_table.s= &dummy_share;
+
+ /* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */
+ if (table_type == DB_TYPE_UNKNOWN ||
+ ! (file=get_new_handler(&dummy_table, table_type)))
+ DBUG_RETURN(ENOENT);
+
if (lower_case_table_names == 2 && !(file->table_flags() & HA_FILE_BASED))
{
/* Ensure that table handler get path in lower case */
@@ -859,64 +1229,45 @@ int ha_delete_table(enum db_type table_type, const char *path)
my_casedn_str(files_charset_info, tmp_path);
path= tmp_path;
}
- int error=file->delete_table(path);
- delete file;
- return error;
-}
-
-
-void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos)
-{
- switch (pack_length) {
-#if SIZEOF_OFF_T > 4
- case 8: mi_int8store(buff,pos); break;
- case 7: mi_int7store(buff,pos); break;
- case 6: mi_int6store(buff,pos); break;
- case 5: mi_int5store(buff,pos); break;
-#endif
- case 4: mi_int4store(buff,pos); break;
- case 3: mi_int3store(buff,pos); break;
- case 2: mi_int2store(buff,(uint) pos); break;
- case 1: buff[0]= (uchar) pos; break;
- }
- return;
-}
-
-my_off_t ha_get_ptr(byte *ptr, uint pack_length)
-{
- my_off_t pos;
- switch (pack_length) {
-#if SIZEOF_OFF_T > 4
- case 8:
- pos= (my_off_t) mi_uint8korr(ptr);
- break;
- case 7:
- pos= (my_off_t) mi_uint7korr(ptr);
- break;
- case 6:
- pos= (my_off_t) mi_uint6korr(ptr);
- break;
- case 5:
- pos= (my_off_t) mi_uint5korr(ptr);
- break;
-#endif
- case 4:
- pos= (my_off_t) mi_uint4korr(ptr);
- break;
- case 3:
- pos= (my_off_t) mi_uint3korr(ptr);
- break;
- case 2:
- pos= (my_off_t) mi_uint2korr(ptr);
- break;
- case 1:
- pos= (my_off_t) mi_uint2korr(ptr);
- break;
- default:
- pos=0; // Impossible
- break;
+ if ((error= file->delete_table(path)) && generate_warning)
+ {
+ /*
+ Because file->print_error() use my_error() to generate the error message
+ we must store the error state in thd, reset it and restore it to
+ be able to get hold of the error message.
+ (We should in the future either rewrite handler::print_error() or make
+ a nice method of this.
+ */
+ bool query_error= thd->query_error;
+ sp_rcontext *spcont= thd->spcont;
+ SELECT_LEX *current_select= thd->lex->current_select;
+ char buff[sizeof(thd->net.last_error)];
+ char new_error[sizeof(thd->net.last_error)];
+ int last_errno= thd->net.last_errno;
+
+ strmake(buff, thd->net.last_error, sizeof(buff)-1);
+ thd->query_error= 0;
+ thd->spcont= 0;
+ thd->lex->current_select= 0;
+ thd->net.last_error[0]= 0;
+
+ /* Fill up strucutures that print_error may need */
+ dummy_table.s->path= path;
+ dummy_table.alias= alias;
+
+ file->print_error(error, 0);
+ strmake(new_error, thd->net.last_error, sizeof(buff)-1);
+
+ /* restore thd */
+ thd->query_error= query_error;
+ thd->spcont= spcont;
+ thd->lex->current_select= current_select;
+ thd->net.last_errno= last_errno;
+ strmake(thd->net.last_error, buff, sizeof(buff)-1);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, new_error);
}
- return pos;
+ delete file;
+ DBUG_RETURN(error);
}
/****************************************************************************
@@ -931,8 +1282,8 @@ int handler::ha_open(const char *name, int mode, int test_if_locked)
int error;
DBUG_ENTER("handler::ha_open");
DBUG_PRINT("enter",("name: %s db_type: %d db_stat: %d mode: %d lock_test: %d",
- name, table->db_type, table->db_stat, mode,
- test_if_locked));
+ name, table->s->db_type, table->db_stat, mode,
+ test_if_locked));
if ((error=open(name,mode,test_if_locked)))
{
@@ -950,7 +1301,7 @@ int handler::ha_open(const char *name, int mode, int test_if_locked)
}
else
{
- if (table->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
+ if (table->s->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
table->db_stat|=HA_READ_ONLY;
(void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
@@ -980,7 +1331,7 @@ int handler::read_first_row(byte * buf, uint primary_key)
register int error;
DBUG_ENTER("handler::read_first_row");
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_first_count,&LOCK_status);
/*
If there is very few deleted rows in the table, find the first row by
@@ -1004,71 +1355,202 @@ int handler::read_first_row(byte * buf, uint primary_key)
DBUG_RETURN(error);
}
+/*
+ Generate the next auto-increment number based on increment and offset
+
+ In most cases increment= offset= 1, in which case we get:
+ 1,2,3,4,5,...
+ If increment=10 and offset=5 and previous number is 1, we get:
+ 1,5,15,25,35,...
+*/
+
+inline ulonglong
+next_insert_id(ulonglong nr,struct system_variables *variables)
+{
+ nr= (((nr+ variables->auto_increment_increment -
+ variables->auto_increment_offset)) /
+ (ulonglong) variables->auto_increment_increment);
+ return (nr* (ulonglong) variables->auto_increment_increment +
+ variables->auto_increment_offset);
+}
+
/*
- Updates field with field_type NEXT_NUMBER according to following:
- if field = 0 change field to the next free key in database.
+ Updates columns with type NEXT_NUMBER if:
+
+ - If column value is set to NULL (in which case
+ auto_increment_field_not_null is 0)
+ - If column is set to 0 and (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) is not
+ set. In the future we will only set NEXT_NUMBER fields if one sets them
+ to NULL (or they are not included in the insert list).
+
+
+ There are two different cases when the above is true:
+
+ - thd->next_insert_id == 0 (This is the normal case)
+ In this case we set the set the column for the first row to the value
+ next_insert_id(get_auto_increment(column))) which is normally
+ max-used-column-value +1.
+
+ We call get_auto_increment() only for the first row in a multi-row
+ statement. For the following rows we generate new numbers based on the
+ last used number.
+
+ - thd->next_insert_id != 0. This happens when we have read a statement
+ from the binary log or when one has used SET LAST_INSERT_ID=#.
+
+ In this case we will set the column to the value of next_insert_id.
+ The next row will be given the id
+ next_insert_id(next_insert_id)
+
+ The idea is that generated auto_increment values are predictable and
+ independent of the column values in the table. This is needed to be
+ able to replicate into a table that already has rows with a higher
+ auto-increment value than the one that is inserted.
+
+ After we have already generated an auto-increment number and the user
+ inserts a column with a higher value than the last used one, we will
+ start counting from the inserted value.
+
+ thd->next_insert_id is cleared after it's been used for a statement.
*/
void handler::update_auto_increment()
{
- longlong nr;
- THD *thd;
+ ulonglong nr;
+ THD *thd= table->in_use;
+ struct system_variables *variables= &thd->variables;
DBUG_ENTER("handler::update_auto_increment");
- if (table->next_number_field->val_int() != 0 ||
+
+ /*
+ We must save the previous value to be able to restore it if the
+ row was not inserted
+ */
+ thd->prev_insert_id= thd->next_insert_id;
+
+ if ((nr= table->next_number_field->val_int()) != 0 ||
table->auto_increment_field_not_null &&
- current_thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
+ thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
{
+ /* Clear flag for next row */
table->auto_increment_field_not_null= FALSE;
+ /* Mark that we didn't generate a new value **/
auto_increment_column_changed=0;
+
+ /* Update next_insert_id if we have already generated a value */
+ if (thd->clear_next_insert_id && nr >= thd->next_insert_id)
+ {
+ if (variables->auto_increment_increment != 1)
+ nr= next_insert_id(nr, variables);
+ else
+ nr++;
+ thd->next_insert_id= nr;
+ DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr));
+ }
DBUG_VOID_RETURN;
}
table->auto_increment_field_not_null= FALSE;
- thd=current_thd;
- if ((nr=thd->next_insert_id))
- thd->next_insert_id=0; // Clear after use
- else
- nr=get_auto_increment();
- if (!table->next_number_field->store(nr))
+ if (!(nr= thd->next_insert_id))
+ {
+ nr= get_auto_increment();
+ if (variables->auto_increment_increment != 1)
+ nr= next_insert_id(nr-1, variables);
+ /*
+ Update next row based on the found value. This way we don't have to
+ call the handler for every generated auto-increment value on a
+ multi-row statement
+ */
+ thd->next_insert_id= nr;
+ }
+
+ DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr));
+
+ /* Mark that we should clear next_insert_id before next stmt */
+ thd->clear_next_insert_id= 1;
+
+ if (!table->next_number_field->store((longlong) nr))
thd->insert_id((ulonglong) nr);
else
thd->insert_id(table->next_number_field->val_int());
+
+ /*
+ We can't set next_insert_id if the auto-increment key is not the
+ first key part, as there is no guarantee that the first parts will be in
+ sequence
+ */
+ if (!table->s->next_number_key_offset)
+ {
+ /*
+ Set next insert id to point to next auto-increment value to be able to
+ handle multi-row statements
+ This works even if auto_increment_increment > 1
+ */
+ thd->next_insert_id= next_insert_id(nr, variables);
+ }
+ else
+ thd->next_insert_id= 0;
+
+ /* Mark that we generated a new value */
auto_increment_column_changed=1;
DBUG_VOID_RETURN;
}
+/*
+ restore_auto_increment
-longlong handler::get_auto_increment()
+ In case of error on write, we restore the last used next_insert_id value
+ because the previous value was not used.
+*/
+
+void handler::restore_auto_increment()
{
- longlong nr;
+ THD *thd= table->in_use;
+ if (thd->next_insert_id)
+ thd->next_insert_id= thd->prev_insert_id;
+}
+
+
+ulonglong handler::get_auto_increment()
+{
+ ulonglong nr;
int error;
(void) extra(HA_EXTRA_KEYREAD);
- index_init(table->next_number_index);
- if (!table->next_number_key_offset)
+ index_init(table->s->next_number_index);
+ if (!table->s->next_number_key_offset)
{ // Autoincrement at key-start
error=index_last(table->record[1]);
}
else
{
byte key[MAX_KEY_LENGTH];
- key_copy(key,table,table->next_number_index,
- table->next_number_key_offset);
- error=index_read(table->record[1], key, table->next_number_key_offset,
- HA_READ_PREFIX_LAST);
+ key_copy(key, table->record[0],
+ table->key_info + table->s->next_number_index,
+ table->s->next_number_key_offset);
+ error= index_read(table->record[1], key, table->s->next_number_key_offset,
+ HA_READ_PREFIX_LAST);
}
if (error)
nr=1;
else
- nr=(longlong) table->next_number_field->
- val_int_offset(table->rec_buff_length)+1;
+ nr= ((ulonglong) table->next_number_field->
+ val_int_offset(table->s->rec_buff_length)+1);
index_end();
(void) extra(HA_EXTRA_NO_KEYREAD);
return nr;
}
- /* Print error that we got from handler function */
+
+/*
+ Print error that we got from handler function
+
+ NOTE
+ In case of delete table it's only safe to use the following parts of
+ the 'table' structure:
+ table->s->path
+ table->alias
+*/
void handler::print_error(int error, myf errflag)
{
@@ -1109,7 +1591,7 @@ void handler::print_error(int error, myf errflag)
str.length(max_length-4);
str.append("...");
}
- my_error(ER_DUP_ENTRY,MYF(0),str.c_ptr(),key_nr+1);
+ my_error(ER_DUP_ENTRY, MYF(0), str.c_ptr(), key_nr+1);
DBUG_VOID_RETURN;
}
textno=ER_DUP_KEY;
@@ -1127,14 +1609,20 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_CRASHED:
textno=ER_NOT_KEYFILE;
break;
+ case HA_ERR_WRONG_IN_RECORD:
+ textno= ER_CRASHED_ON_USAGE;
+ break;
case HA_ERR_CRASHED_ON_USAGE:
textno=ER_CRASHED_ON_USAGE;
break;
+ case HA_ERR_NOT_A_TABLE:
+ textno= error;
+ break;
case HA_ERR_CRASHED_ON_REPAIR:
textno=ER_CRASHED_ON_REPAIR;
break;
case HA_ERR_OUT_OF_MEM:
- my_error(ER_OUT_OF_RESOURCES,errflag);
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), errflag);
DBUG_VOID_RETURN;
case HA_ERR_WRONG_COMMAND:
textno=ER_ILLEGAL_HA;
@@ -1148,6 +1636,9 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_RECORD_FILE_FULL:
textno=ER_RECORD_FILE_FULL;
break;
+ case HA_ERR_INDEX_FILE_FULL:
+ textno= errno;
+ break;
case HA_ERR_LOCK_WAIT_TIMEOUT:
textno=ER_LOCK_WAIT_TIMEOUT;
break;
@@ -1169,6 +1660,9 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_NO_REFERENCED_ROW:
textno=ER_NO_REFERENCED_ROW;
break;
+ case HA_ERR_TABLE_DEF_CHANGED:
+ textno=ER_TABLE_DEF_CHANGED;
+ break;
case HA_ERR_NO_SUCH_TABLE:
{
/*
@@ -1178,10 +1672,10 @@ void handler::print_error(int error, myf errflag)
*/
char *db;
char buff[FN_REFLEN];
- uint length=dirname_part(buff,table->path);
+ uint length= dirname_part(buff,table->s->path);
buff[length-1]=0;
db=buff+dirname_length(buff);
- my_error(ER_NO_SUCH_TABLE,MYF(0),db,table->table_name);
+ my_error(ER_NO_SUCH_TABLE, MYF(0), db, table->alias);
break;
}
default:
@@ -1195,27 +1689,27 @@ void handler::print_error(int error, myf errflag)
{
const char* engine= table_type();
if (temporary)
- my_error(ER_GET_TEMPORARY_ERRMSG,MYF(0),error,str.ptr(),engine);
+ my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(), engine);
else
- my_error(ER_GET_ERRMSG,MYF(0),error,str.ptr(),engine);
+ my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine);
}
- else
+ else
my_error(ER_GET_ERRNO,errflag,error);
DBUG_VOID_RETURN;
}
}
- my_error(textno,errflag,table->table_name,error);
+ my_error(textno, errflag, table->alias, error);
DBUG_VOID_RETURN;
}
-/*
+/*
Return an error message specific to this handler
-
+
SYNOPSIS
error error code previously returned by handler
buf Pointer to String where to add error message
-
+
Returns true if this is a temporary error
*/
@@ -1238,16 +1732,40 @@ uint handler::get_dup_key(int error)
}
+/*
+ Delete all files with extension from bas_ext()
+
+ SYNOPSIS
+ delete_table()
+ name Base name of table
+
+ NOTES
+ We assume that the handler may return more extensions than
+ was actually used for the file.
+
+ RETURN
+ 0 If we successfully deleted at least one file from base_ext and
+ didn't get any other errors than ENOENT
+ # Error
+*/
+
int handler::delete_table(const char *name)
{
- int error=0;
+ int error= 0;
+ int enoent_or_zero= ENOENT; // Error if no file was deleted
+ char buff[FN_REFLEN];
+
for (const char **ext=bas_ext(); *ext ; ext++)
{
- if (delete_file(name,*ext,2))
+ fn_format(buff, name, "", *ext, 2 | 4);
+ if (my_delete_with_symlink(buff, MYF(0)))
{
- if ((error=errno) != ENOENT)
+ if ((error= my_errno) != ENOENT)
break;
}
+ else
+ enoent_or_zero= 0; // No error for ENOENT
+ error= enoent_or_zero;
}
return error;
}
@@ -1269,7 +1787,12 @@ int handler::rename_table(const char * from, const char * to)
}
/*
- Tell the handler to turn on or off transaction in the handler
+ Tell the storage engine that it is allowed to "disable transaction" in the
+ handler. It is a hint that ACID is not required - it is used in NDB for
+ ALTER TABLE, for example, when data are copied to temporary table.
+ A storage engine may treat this hint any way it likes. NDB for example
+ starts to commit every now and then automatically.
+ This hint can be safely ignored.
*/
int ha_enable_transaction(THD *thd, bool on)
@@ -1278,6 +1801,16 @@ int ha_enable_transaction(THD *thd, bool on)
DBUG_ENTER("ha_enable_transaction");
thd->transaction.on= on;
+ if (on)
+ {
+ /*
+ Now all storage engines should have transaction handling enabled.
+ But some may have it enabled all the time - "disabling" transactions
+ is an optimization hint that storage engine is free to ignore.
+ So, let's commit an open transaction (if any) now.
+ */
+ error= end_trans(thd, COMMIT);
+ }
DBUG_RETURN(error);
}
@@ -1313,7 +1846,7 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
char name_buff[FN_REFLEN];
DBUG_ENTER("ha_create_table");
- if (openfrm(name,"",0,(uint) READ_ALL, 0, &table))
+ if (openfrm(current_thd, name,"",0,(uint) READ_ALL, 0, &table))
DBUG_RETURN(1);
if (update_create_info)
{
@@ -1331,7 +1864,7 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
error=table.file->create(name,&table,create_info);
VOID(closefrm(&table));
if (error)
- my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,error);
+ my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name,error);
DBUG_RETURN(error != 0);
}
@@ -1378,7 +1911,7 @@ int ha_create_table_from_engine(THD* thd,
if ((error = writefrm(path, frmblob, frmlen)))
goto err_end;
- if (openfrm(path,"",0,(uint) READ_ALL, 0, &table))
+ if (openfrm(thd, path,"",0,(uint) READ_ALL, 0, &table))
DBUG_RETURN(1);
update_create_info_from_table(&create_info, &table);
@@ -1400,13 +1933,6 @@ err_end:
DBUG_RETURN(error);
}
-static int NEAR_F delete_file(const char *name,const char *ext,int extflag)
-{
- char buff[FN_REFLEN];
- VOID(fn_format(buff,name,"",ext,extflag | 4));
- return(my_delete_with_symlink(buff,MYF(MY_WME)));
-}
-
void st_ha_check_opt::init()
{
flags= sql_flags= 0;
@@ -1522,7 +2048,7 @@ int ha_discover(THD *thd, const char *db, const char *name,
error= ndbcluster_discover(thd, db, name, frmblob, frmlen);
#endif
if (!error)
- statistic_increment(ha_discover_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_discover_count,&LOCK_status);
DBUG_RETURN(error);
}
@@ -1577,6 +2103,131 @@ int ha_table_exists(THD* thd, const char* db, const char* name)
/*
+ Read the first row of a multi-range set.
+
+ SYNOPSIS
+ read_multi_range_first()
+ found_range_p Returns a pointer to the element in 'ranges' that
+ corresponds to the returned row.
+ ranges An array of KEY_MULTI_RANGE range descriptions.
+ range_count Number of ranges in 'ranges'.
+ sorted If result should be sorted per key.
+ buffer A HANDLER_BUFFER for internal handler usage.
+
+ NOTES
+ Record is read into table->record[0].
+ *found_range_p returns a valid value only if read_multi_range_first()
+ returns 0.
+ Sorting is done within each range. If you want an overall sort, enter
+ 'ranges' with sorted ranges.
+
+ RETURN
+ 0 OK, found a row
+ HA_ERR_END_OF_FILE No rows in range
+ # Error code
+*/
+
+int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE *ranges, uint range_count,
+ bool sorted, HANDLER_BUFFER *buffer)
+{
+ int result= HA_ERR_END_OF_FILE;
+ DBUG_ENTER("handler::read_multi_range_first");
+ multi_range_sorted= sorted;
+ multi_range_buffer= buffer;
+
+ for (multi_range_curr= ranges, multi_range_end= ranges + range_count;
+ multi_range_curr < multi_range_end;
+ multi_range_curr++)
+ {
+ result= read_range_first(multi_range_curr->start_key.length ?
+ &multi_range_curr->start_key : 0,
+ multi_range_curr->end_key.length ?
+ &multi_range_curr->end_key : 0,
+ test(multi_range_curr->range_flag & EQ_RANGE),
+ multi_range_sorted);
+ if (result != HA_ERR_END_OF_FILE)
+ break;
+ }
+
+ *found_range_p= multi_range_curr;
+ DBUG_PRINT("exit",("result %d", result));
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Read the next row of a multi-range set.
+
+ SYNOPSIS
+ read_multi_range_next()
+ found_range_p Returns a pointer to the element in 'ranges' that
+ corresponds to the returned row.
+
+ NOTES
+ Record is read into table->record[0].
+ *found_range_p returns a valid value only if read_multi_range_next()
+ returns 0.
+
+ RETURN
+ 0 OK, found a row
+ HA_ERR_END_OF_FILE No (more) rows in range
+ # Error code
+*/
+
+int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
+{
+ int result;
+ DBUG_ENTER("handler::read_multi_range_next");
+
+ /* We should not be called after the last call returned EOF. */
+ DBUG_ASSERT(multi_range_curr < multi_range_end);
+
+ do
+ {
+ /* Save a call if there can be only one row in range. */
+ if (multi_range_curr->range_flag != (UNIQUE_RANGE | EQ_RANGE))
+ {
+ result= read_range_next();
+
+ /* On success or non-EOF errors jump to the end. */
+ if (result != HA_ERR_END_OF_FILE)
+ break;
+ }
+ else
+ {
+ /*
+ We need to set this for the last range only, but checking this
+ condition is more expensive than just setting the result code.
+ */
+ result= HA_ERR_END_OF_FILE;
+ }
+
+ /* Try the next range(s) until one matches a record. */
+ for (multi_range_curr++;
+ multi_range_curr < multi_range_end;
+ multi_range_curr++)
+ {
+ result= read_range_first(multi_range_curr->start_key.length ?
+ &multi_range_curr->start_key : 0,
+ multi_range_curr->end_key.length ?
+ &multi_range_curr->end_key : 0,
+ test(multi_range_curr->range_flag & EQ_RANGE),
+ multi_range_sorted);
+ if (result != HA_ERR_END_OF_FILE)
+ break;
+ }
+ }
+ while ((result == HA_ERR_END_OF_FILE) &&
+ (multi_range_curr < multi_range_end));
+
+ *found_range_p= multi_range_curr;
+ DBUG_PRINT("exit",("handler::read_multi_range_next: result %d", result));
+ DBUG_RETURN(result);
+}
+
+
+/*
Read first row between two ranges.
Store ranges for future calls to read_range_next
@@ -1730,9 +2381,9 @@ TYPELIB *ha_known_exts(void)
const char **ext, *old_ext;
known_extensions_id= mysys_usage_id;
- found_exts.push_back((char*) ".db");
+ found_exts.push_back((char*) triggers_file_ext);
for (types= sys_table_types; types->type; types++)
- {
+ {
if (*types->value == SHOW_OPTION_YES)
{
handler *file= get_new_handler(0,(enum db_type) types->db_type);
@@ -1755,7 +2406,7 @@ TYPELIB *ha_known_exts(void)
(found_exts.elements+1),
MYF(MY_WME | MY_FAE));
- DBUG_ASSERT(ext);
+ DBUG_ASSERT(ext != 0);
known_extensions.count= found_exts.elements;
known_extensions.type_names= ext;
@@ -1765,3 +2416,62 @@ TYPELIB *ha_known_exts(void)
}
return &known_extensions;
}
+
+#ifdef HAVE_REPLICATION
+/*
+ Reports to table handlers up to which position we have sent the binlog
+ to a slave in replication
+
+ SYNOPSIS
+ ha_repl_report_sent_binlog()
+
+ NOTES
+ Only works for InnoDB at the moment
+
+ RETURN VALUE
+ Always 0 (= success)
+
+ PARAMETERS
+ THD *thd in: thread doing the binlog communication to
+ the slave
+ char *log_file_name in: binlog file name
+ my_off_t end_offset in: the offset in the binlog file up to
+ which we sent the contents to the slave
+*/
+
+int ha_repl_report_sent_binlog(THD *thd, char *log_file_name,
+ my_off_t end_offset)
+{
+#ifdef HAVE_INNOBASE_DB
+ return innobase_repl_report_sent_binlog(thd,log_file_name,end_offset);
+#else
+ /* remove warnings about unused parameters */
+ thd=thd; log_file_name=log_file_name; end_offset=end_offset;
+ return 0;
+#endif
+}
+
+/*
+ Reports to table handlers that we stop replication to a specific slave
+
+ SYNOPSIS
+ ha_repl_report_replication_stop()
+
+ NOTES
+ Does nothing at the moment
+
+ RETURN VALUE
+ Always 0 (= success)
+
+ PARAMETERS
+ THD *thd in: thread doing the binlog communication to
+ the slave
+*/
+
+int ha_repl_report_replication_stop(THD *thd)
+{
+ thd = thd;
+
+ return 0;
+}
+#endif /* HAVE_REPLICATION */
diff --git a/sql/handler.h b/sql/handler.h
index d2f77c4149a..5e25f038c36 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -44,16 +44,25 @@
#define HA_ADMIN_INVALID -5
#define HA_ADMIN_REJECT -6
#define HA_ADMIN_TRY_ALTER -7
+#define HA_ADMIN_WRONG_CHECKSUM -8
/* Bits in table_flags() to show what database can do */
-#define HA_READ_RND_SAME (1 << 0) /* can switch index during the scan
- with ::rnd_same() - not used yet.
- see mi_rsame/heap_rsame/myrg_rsame */
+
+/*
+ Can switch index during the scan with ::rnd_same() - not used yet.
+ see mi_rsame/heap_rsame/myrg_rsame
+*/
+#define HA_READ_RND_SAME (1 << 0)
#define HA_TABLE_SCAN_ON_INDEX (1 << 2) /* No separate data/index file */
#define HA_REC_NOT_IN_SEQ (1 << 3) /* ha_info don't return recnumber;
It returns a position to ha_r_rnd */
#define HA_CAN_GEOMETRY (1 << 4)
-#define HA_FAST_KEY_READ (1 << 5) /* no need for a record cache in filesort */
+/*
+ Reading keys in random order is as fast as reading keys in sort order
+ (Used in records.cc to decide if we should use a record cache and by
+ filesort to decide if we should sort key + data or key + pointer-to-row
+*/
+#define HA_FAST_KEY_READ (1 << 5)
#define HA_NULL_IN_KEY (1 << 7) /* One can have keys with NULL */
#define HA_DUPP_POS (1 << 8) /* ha_position() gives dup row */
#define HA_NO_BLOBS (1 << 9) /* Doesn't support blobs */
@@ -61,9 +70,11 @@
#define HA_AUTO_PART_KEY (1 << 11) /* auto-increment in multi-part key */
#define HA_REQUIRE_PRIMARY_KEY (1 << 12) /* .. and can't create a hidden one */
#define HA_NOT_EXACT_COUNT (1 << 13)
-#define HA_CAN_INSERT_DELAYED (1 << 14) /* only handlers with table-level locks
- need no special code to support
- INSERT DELAYED */
+/*
+ INSERT_DELAYED only works with handlers that uses MySQL internal table
+ level locks
+*/
+#define HA_CAN_INSERT_DELAYED (1 << 14)
#define HA_PRIMARY_KEY_IN_READ_INDEX (1 << 15)
#define HA_NOT_DELETE_WITH_CACHE (1 << 18)
#define HA_NO_PREFIX_CHAR_KEYS (1 << 20)
@@ -73,6 +84,9 @@
#define HA_HAS_CHECKSUM (1 << 24)
/* Table data are stored in separate files (for lower_case_table_names) */
#define HA_FILE_BASED (1 << 26)
+#define HA_NO_VARCHAR (1 << 27)
+#define HA_CAN_BIT_FIELD (1 << 28) /* supports bit fields */
+#define HA_NEED_READ_RANGE_BUFFER (1 << 29) /* for read_multi_range */
/* bits in index_flags(index_number) for what you can do with index */
@@ -89,6 +103,11 @@
#define HA_KEY_SWITCH_NONUNIQ_SAVE 2
#define HA_KEY_SWITCH_ALL_SAVE 3
+/*
+ Note: the following includes binlog and closing 0.
+ so: innodb+bdb+ndb+binlog+0
+*/
+#define MAX_HA 6
/*
Bits in index_ddl_flags(KEY *wanted_index)
@@ -141,13 +160,13 @@
/* Options of START TRANSACTION statement (and later of SET TRANSACTION stmt) */
#define MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT 1
-enum db_type
-{
+enum db_type
+{
DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1,
DB_TYPE_HASH,DB_TYPE_MISAM,DB_TYPE_PISAM,
DB_TYPE_RMS_ISAM, DB_TYPE_HEAP, DB_TYPE_ISAM,
DB_TYPE_MRG_ISAM, DB_TYPE_MYISAM, DB_TYPE_MRG_MYISAM,
- DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB,
+ DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB,
DB_TYPE_GEMINI, DB_TYPE_NDBCLUSTER,
DB_TYPE_EXAMPLE_DB, DB_TYPE_ARCHIVE_DB, DB_TYPE_CSV_DB,
DB_TYPE_FEDERATED_DB,
@@ -163,27 +182,182 @@ struct show_table_type_st {
};
enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED,
- ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED};
+ ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED,
+ ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT };
/* struct to hold information about the table that should be created */
/* Bits in used_fields */
-#define HA_CREATE_USED_AUTO 1
-#define HA_CREATE_USED_RAID 2
-#define HA_CREATE_USED_UNION 4
-#define HA_CREATE_USED_INSERT_METHOD 8
-#define HA_CREATE_USED_MIN_ROWS 16
-#define HA_CREATE_USED_MAX_ROWS 32
-#define HA_CREATE_USED_AVG_ROW_LENGTH 64
-#define HA_CREATE_USED_PACK_KEYS 128
-#define HA_CREATE_USED_CHARSET 256
-#define HA_CREATE_USED_DEFAULT_CHARSET 512
-
-typedef struct st_thd_trans {
- void *bdb_tid;
- void *innobase_tid;
- bool innodb_active_trans;
- void *ndb_tid;
+#define HA_CREATE_USED_AUTO (1L << 0)
+#define HA_CREATE_USED_RAID (1L << 1)
+#define HA_CREATE_USED_UNION (1L << 2)
+#define HA_CREATE_USED_INSERT_METHOD (1L << 3)
+#define HA_CREATE_USED_MIN_ROWS (1L << 4)
+#define HA_CREATE_USED_MAX_ROWS (1L << 5)
+#define HA_CREATE_USED_AVG_ROW_LENGTH (1L << 6)
+#define HA_CREATE_USED_PACK_KEYS (1L << 7)
+#define HA_CREATE_USED_CHARSET (1L << 8)
+#define HA_CREATE_USED_DEFAULT_CHARSET (1L << 9)
+#define HA_CREATE_USED_DATADIR (1L << 10)
+#define HA_CREATE_USED_INDEXDIR (1L << 11)
+#define HA_CREATE_USED_ENGINE (1L << 12)
+#define HA_CREATE_USED_CHECKSUM (1L << 13)
+#define HA_CREATE_USED_DELAY_KEY_WRITE (1L << 14)
+#define HA_CREATE_USED_ROW_FORMAT (1L << 15)
+#define HA_CREATE_USED_COMMENT (1L << 16)
+#define HA_CREATE_USED_PASSWORD (1L << 17)
+
+typedef ulonglong my_xid; // this line is the same as in log_event.h
+#define MYSQL_XID_PREFIX "MySQLXid"
+#define MYSQL_XID_PREFIX_LEN 8 // must be a multiple of 8
+#define MYSQL_XID_OFFSET (MYSQL_XID_PREFIX_LEN+sizeof(server_id))
+#define MYSQL_XID_GTRID_LEN (MYSQL_XID_OFFSET+sizeof(my_xid))
+
+#define XIDDATASIZE 128
+#define MAXGTRIDSIZE 64
+#define MAXBQUALSIZE 64
+
+struct xid_t {
+ long formatID;
+ long gtrid_length;
+ long bqual_length;
+ char data[XIDDATASIZE]; // not \0-terminated !
+
+ bool eq(struct xid_t *xid)
+ { return !memcmp(this, xid, sizeof(long)*3+gtrid_length+bqual_length); }
+ bool eq(long g, long b, const char *d)
+ { return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
+ void set(struct xid_t *xid)
+ { memcpy(this, xid, sizeof(long)*3+xid->gtrid_length+xid->bqual_length); }
+ void set(long f, const char *g, long gl, const char *b, long bl)
+ {
+ formatID= f;
+ memcpy(data, g, gtrid_length= gl);
+ memcpy(data+gl, b, bqual_length= bl);
+ }
+ void set(ulonglong xid)
+ {
+ my_xid tmp;
+ formatID= 1;
+ set(MYSQL_XID_PREFIX_LEN, 0, MYSQL_XID_PREFIX);
+ memcpy(data+MYSQL_XID_PREFIX_LEN, &server_id, sizeof(server_id));
+ tmp= xid;
+ memcpy(data+MYSQL_XID_OFFSET, &tmp, sizeof(tmp));
+ gtrid_length=MYSQL_XID_GTRID_LEN;
+ }
+ void set(long g, long b, const char *d)
+ {
+ formatID= 1;
+ gtrid_length= g;
+ bqual_length= b;
+ memcpy(data, d, g+b);
+ }
+ bool is_null() { return formatID == -1; }
+ void null() { formatID= -1; }
+ my_xid quick_get_my_xid()
+ {
+ my_xid tmp;
+ memcpy(&tmp, data+MYSQL_XID_OFFSET, sizeof(tmp));
+ return tmp;
+ }
+ my_xid get_my_xid()
+ {
+ return gtrid_length == MYSQL_XID_GTRID_LEN && bqual_length == 0 &&
+ !memcmp(data+MYSQL_XID_PREFIX_LEN, &server_id, sizeof(server_id)) &&
+ !memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ?
+ quick_get_my_xid() : 0;
+ }
+};
+typedef struct xid_t XID;
+
+/* for recover() handlerton call */
+#define MIN_XID_LIST_SIZE 128
+#ifdef SAFEMALLOC
+#define MAX_XID_LIST_SIZE 256
+#else
+#define MAX_XID_LIST_SIZE (1024*128)
+#endif
+
+/*
+ handlerton is a singleton structure - one instance per storage engine -
+ to provide access to storage engine functionality that works on the
+ "global" level (unlike handler class that works on a per-table basis)
+
+ usually handlerton instance is defined statically in ha_xxx.cc as
+
+ static handlerton { ... } xxx_hton;
+
+ savepoint_*, prepare, recover, and *_by_xid pointers can be 0.
+*/
+typedef struct
+{
+ /*
+ storage engine name as it should be printed to a user
+ */
+ const char *name;
+ /*
+ each storage engine has it's own memory area (actually a pointer)
+ in the thd, for storing per-connection information.
+ It is accessed as
+
+ thd->ha_data[xxx_hton.slot]
+
+ slot number is initialized by MySQL after xxx_init() is called.
+ */
+ uint slot;
+ /*
+ to store per-savepoint data storage engine is provided with an area
+ of a requested size (0 is ok here).
+ savepoint_offset must be initialized statically to the size of
+ the needed memory to store per-savepoint information.
+ After xxx_init it is changed to be an offset to savepoint storage
+ area and need not be used by storage engine.
+ see binlog_hton and binlog_savepoint_set/rollback for an example.
+ */
+ uint savepoint_offset;
+ /*
+ handlerton methods:
+
+ close_connection is only called if
+ thd->ha_data[xxx_hton.slot] is non-zero, so even if you don't need
+ this storage area - set it to something, so that MySQL would know
+ this storage engine was accessed in this connection
+ */
+ int (*close_connection)(THD *thd);
+ /*
+ sv points to an uninitialized storage area of requested size
+ (see savepoint_offset description)
+ */
+ int (*savepoint_set)(THD *thd, void *sv);
+ /*
+ sv points to a storage area, that was earlier passed
+ to the savepoint_set call
+ */
+ int (*savepoint_rollback)(THD *thd, void *sv);
+ int (*savepoint_release)(THD *thd, void *sv);
+ /*
+ 'all' is true if it's a real commit, that makes persistent changes
+ 'all' is false if it's not in fact a commit but an end of the
+ statement that is part of the transaction.
+ NOTE 'all' is also false in auto-commit mode where 'end of statement'
+ and 'real commit' mean the same event.
+ */
+ int (*commit)(THD *thd, bool all);
+ int (*rollback)(THD *thd, bool all);
+ int (*prepare)(THD *thd, bool all);
+ int (*recover)(XID *xid_list, uint len);
+ int (*commit_by_xid)(XID *xid);
+ int (*rollback_by_xid)(XID *xid);
+} handlerton;
+
+typedef struct st_thd_trans
+{
+ /* number of entries in the ht[] */
+ uint nht;
+ /* true is not all entries in the ht[] support 2pc */
+ bool no_2pc;
+ /* storage engines that registered themselves for this transaction */
+ handlerton *ht[MAX_HA];
} THD_TRANS;
enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
@@ -208,6 +382,8 @@ typedef struct st_ha_create_information
uint raid_type,raid_chunks;
uint merge_insert_method;
bool table_existed; /* 1 in create if table existed */
+ bool frm_only; /* 1 if no ha_create_table() */
+ bool varchar; /* 1 if table has a VARCHAR */
} HA_CREATE_INFO;
@@ -215,6 +391,14 @@ typedef struct st_ha_create_information
struct st_table;
typedef struct st_table TABLE;
+struct st_foreign_key_info;
+typedef struct st_foreign_key_info FOREIGN_KEY_INFO;
+
+typedef struct st_savepoint SAVEPOINT;
+extern ulong savepoint_alloc_size;
+
+/* Forward declaration for condition pushdown to storage engine */
+typedef class Item COND;
typedef struct st_ha_check_opt
{
@@ -226,6 +410,21 @@ typedef struct st_ha_check_opt
} HA_CHECK_OPT;
+/*
+ This is a buffer area that the handler can use to store rows.
+ 'end_of_used_area' should be kept updated after calls to
+ read-functions so that other parts of the code can use the
+ remaining area (until next read calls is issued).
+*/
+
+typedef struct st_handler_buffer
+{
+ const byte *buffer; /* Buffer one can start using */
+ const byte *buffer_end; /* End of buffer */
+ byte *end_of_used_area; /* End of area that was used by handler */
+} HANDLER_BUFFER;
+
+
class handler :public Sql_alloc
{
protected:
@@ -260,6 +459,12 @@ public:
time_t check_time;
time_t update_time;
+ /* The following are for read_multi_range */
+ bool multi_range_sorted;
+ KEY_MULTI_RANGE *multi_range_curr;
+ KEY_MULTI_RANGE *multi_range_end;
+ HANDLER_BUFFER *multi_range_buffer;
+
/* The following are for read_range() */
key_range save_end_range, *end_range;
KEY_PART_INFO *range_key_part;
@@ -277,7 +482,7 @@ public:
enum {NONE=0, INDEX, RND} inited;
bool auto_increment_column_changed;
bool implicit_emptied; /* Can be !=0 only if HEAP */
-
+ const COND *pushed_cond;
handler(TABLE *table_arg) :table(table_arg),
ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0),
@@ -286,7 +491,8 @@ public:
create_time(0), check_time(0), update_time(0),
key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
ref_length(sizeof(my_off_t)), block_size(0),
- raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0)
+ raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0),
+ pushed_cond(NULL)
{}
virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ }
int ha_open(const char *name, int mode, int test_if_locked);
@@ -312,33 +518,43 @@ public:
virtual ha_rows estimate_rows_upper_bound()
{ return records+EXTRA_RECORDS; }
+ /*
+ Get the row type from the storage engine. If this method returns
+ ROW_TYPE_NOT_USED, the information in HA_CREATE_INFO should be used.
+ */
+ virtual enum row_type get_row_type() const { return ROW_TYPE_NOT_USED; }
+
virtual const char *index_type(uint key_number) { DBUG_ASSERT(0); return "";}
int ha_index_init(uint idx)
{
+ DBUG_ENTER("ha_index_init");
DBUG_ASSERT(inited==NONE);
inited=INDEX;
- return index_init(idx);
+ DBUG_RETURN(index_init(idx));
}
int ha_index_end()
{
+ DBUG_ENTER("ha_index_end");
DBUG_ASSERT(inited==INDEX);
inited=NONE;
- return index_end();
+ DBUG_RETURN(index_end());
}
int ha_rnd_init(bool scan)
{
+ DBUG_ENTER("ha_rnd_init");
DBUG_ASSERT(inited==NONE || (inited==RND && scan));
inited=RND;
- return rnd_init(scan);
+ DBUG_RETURN(rnd_init(scan));
}
int ha_rnd_end()
{
+ DBUG_ENTER("ha_rnd_end");
DBUG_ASSERT(inited==RND);
inited=NONE;
- return rnd_end();
+ DBUG_RETURN(rnd_end());
}
- /* this is neseccary in many places, e.g. in HANDLER command */
+ /* this is necessary in many places, e.g. in HANDLER command */
int ha_index_or_rnd_end()
{
return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0;
@@ -367,6 +583,10 @@ public:
virtual int index_next_same(byte *buf, const byte *key, uint keylen);
virtual int index_read_last(byte * buf, const byte * key, uint key_len)
{ return (my_errno=HA_ERR_WRONG_COMMAND); }
+ virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE *ranges, uint range_count,
+ bool sorted, HANDLER_BUFFER *buffer);
+ virtual int read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
virtual int read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_range, bool sorted);
@@ -398,7 +618,7 @@ public:
virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)
{ return extra(operation); }
virtual int reset() { return extra(HA_EXTRA_RESET); }
- virtual int external_lock(THD *thd, int lock_type)=0;
+ virtual int external_lock(THD *thd, int lock_type) { return 0; }
virtual void unlock_row() {}
virtual int start_stmt(THD *thd) {return 0;}
/*
@@ -409,7 +629,8 @@ public:
*/
virtual int delete_all_rows()
{ return (my_errno=HA_ERR_WRONG_COMMAND); }
- virtual longlong get_auto_increment();
+ virtual ulonglong get_auto_increment();
+ virtual void restore_auto_increment();
virtual void update_create_info(HA_CREATE_INFO *create_info) {}
/* admin commands - called from mysql_admin_table */
@@ -453,6 +674,8 @@ public:
/* used in ALTER TABLE; 1 if changing storage engine is allowed */
virtual bool can_switch_engines() { return 1; }
/* used in REPLACE; is > 0 if table is referred by a FOREIGN KEY */
+ virtual int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
+ { return 0; }
virtual uint referenced_by_foreign_key() { return 0;}
virtual void init_table_handle_for_HANDLER()
{ return; } /* prepare InnoDB for HANDLER */
@@ -509,10 +732,61 @@ public:
/* Type of table for caching query */
virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; }
- /*
- Is query with this table cachable (have sense only for ASKTRANSACT
- tables)
- */
+ /* ask handler about permission to cache table when query is to be cached */
+ virtual my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data)
+ {
+ *engine_callback= 0;
+ return 1;
+ }
+ /*
+ RETURN
+ true Primary key (if there is one) is clustered key covering all fields
+ false otherwise
+ */
+ virtual bool primary_key_is_clustered() { return FALSE; }
+
+ virtual int cmp_ref(const byte *ref1, const byte *ref2)
+ {
+ return memcmp(ref1, ref2, ref_length);
+ }
+
+ /*
+ Condition pushdown to storage engines
+ */
+
+ /*
+ Push condition down to the table handler.
+ SYNOPSIS
+ cond_push()
+ cond Condition to be pushed. The condition tree must not be
+ modified by the by the caller.
+ RETURN
+ The 'remainder' condition that caller must use to filter out records.
+ NULL means the handler will not return rows that do not match the
+ passed condition.
+ NOTES
+ The pushed conditions form a stack (from which one can remove the
+ last pushed condition using cond_pop).
+ The table handler filters out rows using (pushed_cond1 AND pushed_cond2
+ AND ... AND pushed_condN)
+ or less restrictive condition, depending on handler's capabilities.
+
+ handler->extra(HA_EXTRA_RESET) call empties the condition stack.
+ Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
+ condition stack.
+ */
+ virtual const COND *cond_push(const COND *cond) { return cond; };
+ /*
+ Pop the top condition from the condition stack of the handler instance.
+ SYNOPSIS
+ cond_pop()
+ Pops the top if condition stack, if stack is not empty
+ */
+ virtual void cond_pop() { return; };
};
/* Some extern variables used with handlers */
@@ -520,58 +794,88 @@ public:
extern struct show_table_type_st sys_table_types[];
extern const char *ha_row_type[];
extern TYPELIB tx_isolation_typelib;
+extern handlerton *handlertons[MAX_HA];
+extern ulong total_ha, total_ha_2pc;
/* Wrapper functions */
-#define ha_commit_stmt(thd) (ha_commit_trans((thd), &((thd)->transaction.stmt)))
-#define ha_rollback_stmt(thd) (ha_rollback_trans((thd), &((thd)->transaction.stmt)))
-#define ha_commit(thd) (ha_commit_trans((thd), &((thd)->transaction.all)))
-#define ha_rollback(thd) (ha_rollback_trans((thd), &((thd)->transaction.all)))
+#define ha_commit_stmt(thd) (ha_commit_trans((thd), FALSE))
+#define ha_rollback_stmt(thd) (ha_rollback_trans((thd), FALSE))
+#define ha_commit(thd) (ha_commit_trans((thd), TRUE))
+#define ha_rollback(thd) (ha_rollback_trans((thd), TRUE))
#define ha_supports_generate(T) (T != DB_TYPE_INNODB && \
T != DB_TYPE_BERKELEY_DB && \
T != DB_TYPE_NDBCLUSTER)
-bool ha_caching_allowed(THD* thd, char* table_key,
- uint key_length, uint8 cache_type);
+/* lookups */
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);
-my_off_t ha_get_ptr(byte *ptr, uint pack_length);
-void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos);
+enum db_type ha_checktype(enum db_type database_type);
+
+/* basic stuff */
int ha_init(void);
+TYPELIB *ha_known_exts(void);
int ha_panic(enum ha_panic_function flag);
+int ha_update_statistics();
void ha_close_connection(THD* thd);
-enum db_type ha_checktype(enum db_type database_type);
my_bool ha_storage_engine_is_enabled(enum db_type database_type);
+bool ha_flush_logs(void);
+void ha_drop_database(char* path);
int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
bool update_create_info);
+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_delete_table(enum db_type db_type, const char *path);
-void ha_drop_database(char* path);
+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);
+
+/* key cache */
int ha_init_key_cache(const char *name, KEY_CACHE *key_cache);
int ha_resize_key_cache(KEY_CACHE *key_cache);
int ha_change_key_cache_param(KEY_CACHE *key_cache);
+int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache);
int ha_end_key_cache(KEY_CACHE *key_cache);
-int ha_start_stmt(THD *thd);
-int ha_report_binlog_offset_and_commit(THD *thd, char *log_file_name,
- my_off_t end_offset);
-int ha_commit_complete(THD *thd);
+
+/* report to InnoDB that control passes to the client */
int ha_release_temporary_latches(THD *thd);
-int ha_commit_trans(THD *thd, THD_TRANS *trans);
-int ha_rollback_trans(THD *thd, THD_TRANS *trans);
-int ha_rollback_to_savepoint(THD *thd, char *savepoint_name);
-int ha_savepoint(THD *thd, char *savepoint_name);
+
+/* transactions: interface to handlerton functions */
+int ha_start_consistent_snapshot(THD *thd);
+int ha_commit_or_rollback_by_xid(XID *xid, bool commit);
+int ha_commit_one_phase(THD *thd, bool all);
+int ha_rollback_trans(THD *thd, bool all);
+int ha_prepare(THD *thd);
+int ha_recover(HASH *commit_list);
+
+/* transactions: these functions never call handlerton functions directly */
+int ha_commit_trans(THD *thd, bool all);
int ha_autocommit_or_rollback(THD *thd, int error);
-void ha_set_spin_retries(uint retries);
-bool ha_flush_logs(void);
int ha_enable_transaction(THD *thd, bool on);
-int ha_change_key_cache(KEY_CACHE *old_key_cache,
- KEY_CACHE *new_key_cache);
-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);
-TYPELIB *ha_known_exts(void);
-int ha_start_consistent_snapshot(THD *thd);
+
+/* savepoints */
+int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv);
+int ha_savepoint(THD *thd, SAVEPOINT *sv);
+int ha_release_savepoint(THD *thd, SAVEPOINT *sv);
+
+/* these are called by storage engines */
+void trans_register_ha(THD *thd, bool all, handlerton *ht);
+
+/*
+ Storage engine has to assume the transaction will end up with 2pc if
+ - there is more than one 2pc-capable storage engine available
+ - in the current transaction 2pc was not disabled yet
+*/
+#define trans_need_2pc(thd, all) ((total_ha_2pc > 1) && \
+ !((all ? &thd->transaction.all : &thd->transaction.stmt)->no_2pc))
+
+/* semi-synchronous replication */
+int ha_repl_report_sent_binlog(THD *thd, char *log_file_name,
+ my_off_t end_offset);
+int ha_repl_report_replication_stop(THD *thd);
diff --git a/sql/item.cc b/sql/item.cc
index ffde92c4214..7264f8b2d68 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -22,6 +22,10 @@
#include "mysql_priv.h"
#include <m_ctype.h>
#include "my_dir.h"
+#include "sp_rcontext.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
+#include "sql_select.h"
static void mark_as_dependent(THD *thd,
SELECT_LEX *last, SELECT_LEX *current,
@@ -29,6 +33,131 @@ static void mark_as_dependent(THD *thd,
const String my_null_string("NULL", 4, default_charset_info);
+/****************************************************************************/
+
+/* Hybrid_type_traits {_real} */
+
+void Hybrid_type_traits::fix_length_and_dec(Item *item, Item *arg) const
+{
+ item->decimals= NOT_FIXED_DEC;
+ item->max_length= item->float_length(arg->decimals);
+}
+
+static const Hybrid_type_traits real_traits_instance;
+
+const Hybrid_type_traits *Hybrid_type_traits::instance()
+{
+ return &real_traits_instance;
+}
+
+
+my_decimal *
+Hybrid_type_traits::val_decimal(Hybrid_type *val, my_decimal *to) const
+{
+ double2my_decimal(E_DEC_FATAL_ERROR, val->real, val->dec_buf);
+ return val->dec_buf;
+}
+
+
+String *
+Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const
+{
+ to->set(val->real, decimals, &my_charset_bin);
+ return to;
+}
+
+/* Hybrid_type_traits_decimal */
+static const Hybrid_type_traits_decimal decimal_traits_instance;
+
+const Hybrid_type_traits_decimal *Hybrid_type_traits_decimal::instance()
+{
+ return &decimal_traits_instance;
+}
+
+
+void
+Hybrid_type_traits_decimal::fix_length_and_dec(Item *item, Item *arg) const
+{
+ item->decimals= arg->decimals;
+ item->max_length= min(arg->max_length + DECIMAL_LONGLONG_DIGITS,
+ DECIMAL_MAX_LENGTH);
+}
+
+
+void Hybrid_type_traits_decimal::set_zero(Hybrid_type *val) const
+{
+ my_decimal_set_zero(&val->dec_buf[0]);
+ val->used_dec_buf_no= 0;
+}
+
+
+void Hybrid_type_traits_decimal::add(Hybrid_type *val, Field *f) const
+{
+ my_decimal_add(E_DEC_FATAL_ERROR,
+ &val->dec_buf[val->used_dec_buf_no ^ 1],
+ &val->dec_buf[val->used_dec_buf_no],
+ f->val_decimal(&val->dec_buf[2]));
+ val->used_dec_buf_no^= 1;
+}
+
+
+void Hybrid_type_traits_decimal::div(Hybrid_type *val, ulonglong u) const
+{
+ int2my_decimal(E_DEC_FATAL_ERROR, u, TRUE, &val->dec_buf[2]);
+ /* XXX: what is '4' for scale? */
+ my_decimal_div(E_DEC_FATAL_ERROR,
+ &val->dec_buf[val->used_dec_buf_no ^ 1],
+ &val->dec_buf[val->used_dec_buf_no],
+ &val->dec_buf[2], 4);
+ val->used_dec_buf_no^= 1;
+}
+
+
+longlong
+Hybrid_type_traits_decimal::val_int(Hybrid_type *val, bool unsigned_flag) const
+{
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
+ unsigned_flag, &result);
+ return result;
+}
+
+
+double
+Hybrid_type_traits_decimal::val_real(Hybrid_type *val) const
+{
+ my_decimal2double(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
+ &val->real);
+ return val->real;
+}
+
+
+String *
+Hybrid_type_traits_decimal::val_str(Hybrid_type *val, String *to,
+ uint8 decimals) const
+{
+ my_decimal_round(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
+ decimals, FALSE, &val->dec_buf[2]);
+ my_decimal2string(E_DEC_FATAL_ERROR, &val->dec_buf[2], 0, 0, 0, to);
+ return to;
+}
+
+/* Hybrid_type_traits_integer */
+static const Hybrid_type_traits_integer integer_traits_instance;
+
+const Hybrid_type_traits_integer *Hybrid_type_traits_integer::instance()
+{
+ return &integer_traits_instance;
+}
+
+void
+Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
+{
+ item->decimals= 0;
+ item->max_length= 21;
+ item->unsigned_flag= 0;
+}
+
/*****************************************************************************
** Item functions
*****************************************************************************/
@@ -40,13 +169,140 @@ void item_init(void)
item_user_lock_init();
}
+
+/*
+TODO: make this functions class dependent
+*/
+
+bool Item::val_bool()
+{
+ switch(result_type()) {
+ case INT_RESULT:
+ return val_int() != 0;
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *val= val_decimal(&decimal_value);
+ if (val)
+ return !my_decimal_is_zero(val);
+ return 0;
+ }
+ case REAL_RESULT:
+ case STRING_RESULT:
+ return val_real() != 0.0;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return 0; // Wrong (but safe)
+ }
+}
+
+
+String *Item::val_string_from_real(String *str)
+{
+ double nr= val_real();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ str->set(nr,decimals, &my_charset_bin);
+ return str;
+}
+
+
+String *Item::val_string_from_int(String *str)
+{
+ longlong nr= val_int();
+ if (null_value)
+ return 0;
+ if (unsigned_flag)
+ str->set((ulonglong) nr, &my_charset_bin);
+ else
+ str->set(nr, &my_charset_bin);
+ return str;
+}
+
+
+String *Item::val_string_from_decimal(String *str)
+{
+ my_decimal dec_buf, *dec= val_decimal(&dec_buf);
+ if (null_value)
+ return 0;
+ my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
+ my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, 0, str);
+ return str;
+}
+
+
+my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value)
+{
+ double nr= val_real();
+ if (null_value)
+ return 0;
+ double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value);
+ return (decimal_value);
+}
+
+
+my_decimal *Item::val_decimal_from_int(my_decimal *decimal_value)
+{
+ longlong nr= val_int();
+ if (null_value)
+ return 0;
+ int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
+
+my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
+{
+ String *res;
+ char *end_ptr;
+ if (!(res= val_str(&str_value)))
+ return 0; // NULL or EOM
+
+ end_ptr= (char*) res->ptr()+ res->length();
+ if (str2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_BAD_NUM,
+ res->ptr(), res->length(), res->charset(),
+ decimal_value) & E_DEC_BAD_NUM)
+ {
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), "DECIMAL",
+ str_value.c_ptr());
+ }
+ return decimal_value;
+}
+
+
+double Item::val_real_from_decimal()
+{
+ /* Note that fix_fields may not be called for Item_avg_field items */
+ double result;
+ my_decimal value_buff, *dec_val= val_decimal(&value_buff);
+ if (null_value)
+ return 0.0;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &result);
+ return result;
+}
+
+
+longlong Item::val_int_from_decimal()
+{
+ /* Note that fix_fields may not be called for Item_avg_field items */
+ longlong result;
+ my_decimal value, *dec_val= val_decimal(&value);
+ if (null_value)
+ return 0;
+ my_decimal2int(E_DEC_FATAL_ERROR, dec_val, unsigned_flag, &result);
+ return result;
+}
+
+
Item::Item():
- fixed(0)
+ name(0), orig_name(0), name_length(0), fixed(0),
+ collation(&my_charset_bin, DERIVATION_COERCIBLE)
{
marker= 0;
maybe_null=null_value=with_sum_func=unsigned_flag=0;
- collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
- name= 0;
decimals= 0; max_length= 0;
/* Put item in free list so that we can free all items at end */
@@ -69,13 +325,14 @@ Item::Item():
}
/*
- Constructor used by Item_field, Item_*_ref & agregate (sum) functions.
+ Constructor used by Item_field, Item_*_ref & aggregate (sum) functions.
Used for duplicating lists in processing queries with temporary
tables
*/
Item::Item(THD *thd, Item *item):
str_value(item->str_value),
name(item->name),
+ orig_name(item->orig_name),
max_length(item->max_length),
marker(item->marker),
decimals(item->decimals),
@@ -96,25 +353,78 @@ void Item::print_item_w_name(String *str)
print(str);
if (name)
{
- str->append(" AS `", 5);
- str->append(name);
- str->append('`');
+ THD *thd= current_thd;
+ str->append(" AS ", 4);
+ append_identifier(thd, str, name, strlen(name));
}
}
+void Item::cleanup()
+{
+ DBUG_ENTER("Item::cleanup");
+ DBUG_PRINT("info", ("Item: 0x%lx, Type: %d, name %s, original name %s",
+ this, (int)type(), name ? name : "(null)",
+ orig_name ? orig_name : "null"));
+ fixed=0;
+ marker= 0;
+ if (orig_name)
+ name= orig_name;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ cleanup() item if it is 'fixed'
+
+ SYNOPSIS
+ cleanup_processor()
+ arg - a dummy parameter, is not used here
+*/
+
+bool Item::cleanup_processor(byte *arg)
+{
+ if (fixed)
+ cleanup();
+ return FALSE;
+}
+
+
+/*
+ rename item (used for views, cleanup() return original name)
+
+ SYNOPSIS
+ Item::rename()
+ new_name new name of item;
+*/
+
+void Item::rename(char *new_name)
+{
+ /*
+ we can compare pointers to names here, because if name was not changed,
+ pointer will be same
+ */
+ if (!orig_name && new_name != name)
+ orig_name= name;
+ name= 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), cached_field_index(NO_CACHED_FIELD_INDEX),
+ db_name(db_name_par), table_name(table_name_par),
+ field_name(field_name_par),
+ alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
cached_table(0), depended_from(0)
{
name = (char*) field_name_par;
}
-// Constructor used by Item_field & Item_*_ref (see Item comment)
+
+/* Constructor used by Item_field & Item_*_ref (see Item comment) */
+
Item_ident::Item_ident(THD *thd, Item_ident *item)
:Item(thd, item),
orig_db_name(item->orig_db_name),
@@ -123,6 +433,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item)
db_name(item->db_name),
table_name(item->table_name),
field_name(item->field_name),
+ alias_name_used(item->alias_name_used),
cached_field_index(item->cached_field_index),
cached_table(item->cached_table),
depended_from(item->depended_from)
@@ -131,10 +442,14 @@ Item_ident::Item_ident(THD *thd, Item_ident *item)
void Item_ident::cleanup()
{
DBUG_ENTER("Item_ident::cleanup");
- DBUG_PRINT("enter", ("b:%s(%s), t:%s(%s), f:%s(%s)",
- db_name, orig_db_name,
- table_name, orig_table_name,
- field_name, orig_field_name));
+#ifdef CANT_BE_USED_AS_MEMORY_IS_FREED
+ db_name ? db_name : "(null)",
+ orig_db_name ? orig_db_name : "(null)",
+ table_name ? table_name : "(null)",
+ orig_table_name ? orig_table_name : "(null)",
+ field_name ? field_name : "(null)",
+ orig_field_name ? orig_field_name : "(null)"));
+#endif
Item::cleanup();
db_name= orig_db_name;
table_name= orig_table_name;
@@ -151,6 +466,45 @@ bool Item_ident::remove_dependence_processor(byte * arg)
}
+/*
+ Store the pointer to this item field into a list if not already there.
+
+ SYNOPSIS
+ Item_field::collect_item_field_processor()
+ arg pointer to a List<Item_field>
+
+ DESCRIPTION
+ The method is used by Item::walk to collect all unique Item_field objects
+ from a tree of Items into a set of items represented as a list.
+
+ IMPLEMENTATION
+ Item_cond::walk() and Item_func::walk() stop the evaluation of the
+ processor function for its arguments once the processor returns
+ true.Therefore in order to force this method being called for all item
+ arguments in a condition the method must return false.
+
+ RETURN
+ false to force the evaluation of collect_item_field_processor
+ for the subsequent items.
+*/
+
+bool Item_field::collect_item_field_processor(byte *arg)
+{
+ DBUG_ENTER("Item_field::collect_item_field_processor");
+ DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname"));
+ List<Item_field> *item_list= (List<Item_field>*) arg;
+ List_iterator<Item_field> item_list_it(*item_list);
+ Item_field *curr_item;
+ while ((curr_item= item_list_it++))
+ {
+ if (curr_item->eq(this, 1))
+ DBUG_RETURN(false); /* Already in the set. */
+ }
+ item_list->push_back(this);
+ DBUG_RETURN(false);
+}
+
+
bool Item::check_cols(uint c)
{
if (c != 1)
@@ -168,12 +522,15 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
{
/* Empty string, used by AS or internal function like last_insert_id() */
name= (char*) str;
+ name_length= 0;
return;
}
if (cs->ctype)
{
- // This will probably need a better implementation in the future:
- // a function in CHARSET_INFO structure.
+ /*
+ This will probably need a better implementation in the future:
+ a function in CHARSET_INFO structure.
+ */
while (length && !my_isgraph(cs,*str))
{ // Fix problem with yacc
length--;
@@ -183,12 +540,12 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
if (!my_charset_same(cs, system_charset_info))
{
uint32 res_length;
- name= sql_strmake_with_convert(str, length, cs,
+ name= sql_strmake_with_convert(str, name_length= length, cs,
MAX_ALIAS_NAME, system_charset_info,
&res_length);
}
else
- name=sql_strmake(str, min(length,MAX_ALIAS_NAME));
+ name= sql_strmake(str, (name_length= min(length,MAX_ALIAS_NAME)));
}
@@ -236,18 +593,8 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
return NULL;
}
conv->str_value.copy();
- /*
- The above line executes str_value.realloc() internally,
- which alligns Alloced_length using ALLIGN_SIZE.
- In the case of Item_string::str_value we don't want
- Alloced_length to be longer than str_length.
- Otherwise, some functions like Item_func_concat::val_str()
- try to reuse str_value as a buffer for concatenation result
- for optimization purposes, so our string constant become
- corrupted. See bug#8785 for more details.
- Let's shrink Alloced_length to str_length to avoid this problem.
- */
- conv->str_value.shrink_to_length();
+ /* Ensure that no one is going to change the result string */
+ conv->str_value.mark_as_const();
return conv;
}
@@ -307,6 +654,121 @@ CHARSET_INFO *Item::default_charset()
}
+int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
+{
+ int res;
+ THD *thd= field->table->in_use;
+ enum_check_fields tmp= thd->count_cuted_fields;
+ thd->count_cuted_fields= CHECK_FIELD_IGNORE;
+ res= save_in_field(field, no_conversions);
+ thd->count_cuted_fields= tmp;
+ return res;
+}
+
+
+double Item_splocal::val_real()
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ double ret= it->val_real();
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+longlong Item_splocal::val_int()
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ longlong ret= it->val_int();
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+String *Item_splocal::val_str(String *sp)
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ String *ret= it->val_str(sp);
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ my_decimal *val= it->val_decimal(decimal_value);
+ Item::null_value= it->null_value;
+ return val;
+}
+
+
+bool Item_splocal::is_null()
+{
+ Item *it= this_item();
+ bool ret= it->is_null();
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+Item *
+Item_splocal::this_item()
+{
+ THD *thd= current_thd;
+
+ return thd->spcont->get_item(m_offset);
+}
+
+Item *
+Item_splocal::this_const_item() const
+{
+ THD *thd= current_thd;
+
+ return thd->spcont->get_item(m_offset);
+}
+
+Item::Type
+Item_splocal::type() const
+{
+ THD *thd= current_thd;
+
+ if (thd->spcont)
+ return thd->spcont->get_item(m_offset)->type();
+ return NULL_ITEM; // Anything but SUBSELECT_ITEM
+}
+
+
+bool Item_splocal::fix_fields(THD *, struct st_table_list *, Item **)
+{
+ Item *it= this_item();
+ DBUG_ASSERT(it->fixed);
+ max_length= it->max_length;
+ decimals= it->decimals;
+ fixed= 1;
+ return FALSE;
+}
+
+
+void Item_splocal::cleanup()
+{
+ fixed= 0;
+}
+
+
+void Item_splocal::print(String *str)
+{
+ str->reserve(m_name.length+8);
+ str->append(m_name.str, m_name.length);
+ str->append('@');
+ str->qs_append(m_offset);
+}
+
+
+
/*
Move SUM items out from item tree and replace with reference
@@ -363,7 +825,7 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
Aggregate two collations together taking
into account their coercibility (aka derivation):
- 0 == DERIVATION_EXPLICIT - an explicitely written COLLATE clause
+ 0 == DERIVATION_EXPLICIT - an explicitly written COLLATE clause
1 == DERIVATION_NONE - a mix of two different collations
2 == DERIVATION_IMPLICIT - a column
3 == DERIVATION_COERCIBLE - a string constant
@@ -401,7 +863,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
/*
We do allow to use binary strings (like BLOBS)
together with character strings.
- Binaries have more precedance than a character
+ Binaries have more precedence than a character
string of the same derivation.
*/
if (collation == &my_charset_bin)
@@ -492,7 +954,9 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
}
Item_field::Item_field(Field *f)
- :Item_ident(NullS, f->table_name, f->field_name)
+ :Item_ident(NullS, *f->table_name, f->field_name),
+ item_equal(0), no_const_subst(0),
+ have_privileges(0), any_privileges(0)
{
set_field(f);
/*
@@ -503,7 +967,9 @@ Item_field::Item_field(Field *f)
}
Item_field::Item_field(THD *thd, Field *f)
- :Item_ident(f->table->table_cache_key, f->table_name, f->field_name)
+ :Item_ident(f->table->s->db, *f->table_name, f->field_name),
+ item_equal(0), no_const_subst(0),
+ have_privileges(0), any_privileges(0)
{
/*
We always need to provide Item_field with a fully qualified field
@@ -540,7 +1006,11 @@ Item_field::Item_field(THD *thd, Field *f)
Item_field::Item_field(THD *thd, Item_field *item)
:Item_ident(thd, item),
field(item->field),
- result_field(item->result_field)
+ result_field(item->result_field),
+ item_equal(item->item_equal),
+ no_const_subst(item->no_const_subst),
+ have_privileges(item->have_privileges),
+ any_privileges(item->any_privileges)
{
collation.set(DERIVATION_IMPLICIT);
}
@@ -549,11 +1019,12 @@ void Item_field::set_field(Field *field_par)
{
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
- max_length=field_par->field_length;
decimals= field->decimals();
- table_name=field_par->table_name;
- field_name=field_par->field_name;
- db_name=field_par->table->table_cache_key;
+ max_length= field_par->representation_length();
+ table_name= *field_par->table_name;
+ field_name= field_par->field_name;
+ db_name= field_par->table->s->db;
+ alias_name_used= field_par->table->alias_name_used;
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
collation.set(field_par->charset(), DERIVATION_IMPLICIT);
fixed= 1;
@@ -598,6 +1069,55 @@ const char *Item_ident::full_name() const
return tmp;
}
+void Item_ident::print(String *str)
+{
+ THD *thd= current_thd;
+ char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
+ const char *d_name= db_name, *t_name= table_name;
+ if (lower_case_table_names== 1 ||
+ (lower_case_table_names == 2 && !alias_name_used))
+ {
+ if (table_name && table_name[0])
+ {
+ strmov(t_name_buff, table_name);
+ my_casedn_str(files_charset_info, t_name_buff);
+ t_name= t_name_buff;
+ }
+ if (db_name && db_name[0])
+ {
+ strmov(d_name_buff, db_name);
+ my_casedn_str(files_charset_info, d_name_buff);
+ d_name= d_name_buff;
+ }
+ }
+
+ if (!table_name || !field_name)
+ {
+ const char *nm= field_name ? field_name : name ? name : "tmp_field";
+ append_identifier(thd, str, nm, strlen(nm));
+ return;
+ }
+ if (db_name && db_name[0] && !alias_name_used)
+ {
+ append_identifier(thd, str, d_name, strlen(d_name));
+ str->append('.');
+ append_identifier(thd, str, t_name, strlen(t_name));
+ str->append('.');
+ append_identifier(thd, str, field_name, strlen(field_name));
+ }
+ else
+ {
+ if (table_name[0])
+ {
+ append_identifier(thd, str, t_name, strlen(t_name));
+ str->append('.');
+ append_identifier(thd, str, field_name, strlen(field_name));
+ }
+ else
+ append_identifier(thd, str, field_name, strlen(field_name));
+ }
+}
+
/* ARGSUSED */
String *Item_field::val_str(String *str)
{
@@ -608,7 +1128,8 @@ String *Item_field::val_str(String *str)
return field->val_str(str,&str_value);
}
-double Item_field::val()
+
+double Item_field::val_real()
{
DBUG_ASSERT(fixed == 1);
if ((null_value=field->is_null()))
@@ -616,6 +1137,7 @@ double Item_field::val()
return field->val_real();
}
+
longlong Item_field::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -625,6 +1147,14 @@ longlong Item_field::val_int()
}
+my_decimal *Item_field::val_decimal(my_decimal *decimal_value)
+{
+ if ((null_value= field->is_null()))
+ return 0;
+ return field->val_decimal(decimal_value);
+}
+
+
String *Item_field::str_result(String *str)
{
if ((null_value=result_field->is_null()))
@@ -679,6 +1209,40 @@ longlong Item_field::val_int_result()
}
+my_decimal *Item_field::val_decimal_result(my_decimal *decimal_value)
+{
+ if ((null_value= result_field->is_null()))
+ return 0;
+ return result_field->val_decimal(decimal_value);
+}
+
+
+bool Item_field::val_bool_result()
+{
+ if ((null_value= result_field->is_null()))
+ return FALSE;
+ switch (result_field->result_type()) {
+ case INT_RESULT:
+ return result_field->val_int() != 0;
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *val= result_field->val_decimal(&decimal_value);
+ if (val)
+ return !my_decimal_is_zero(val);
+ return 0;
+ }
+ case REAL_RESULT:
+ case STRING_RESULT:
+ return result_field->val_real() != 0.0;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return 0; // Shut up compiler
+ }
+}
+
+
bool Item_field::eq(const Item *item, bool binary_cmp) const
{
if (item->type() != FIELD_ITEM)
@@ -726,8 +1290,9 @@ Item *Item_field::get_tmp_table_item(THD *thd)
/*
- Create an item from a string we KNOW points to a valid longlong/ulonglong
- end \0 terminated number string
+ Create an item from a string we KNOW points to a valid longlong
+ end \0 terminated number string.
+ This is always 'signed'. Unsigned values are created with Item_uint()
*/
Item_int::Item_int(const char *str_arg, uint length)
@@ -741,6 +1306,12 @@ Item_int::Item_int(const char *str_arg, uint length)
}
+my_decimal *Item_int::val_decimal(my_decimal *decimal_value)
+{
+ int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
String *Item_int::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
@@ -781,7 +1352,98 @@ void Item_uint::print(String *str)
}
-String *Item_real::val_str(String *str)
+Item_decimal::Item_decimal(const char *str_arg, uint length,
+ CHARSET_INFO *charset)
+{
+ str2my_decimal(E_DEC_FATAL_ERROR, str_arg, length, charset, &decimal_value);
+ name= (char*) str_arg;
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(&decimal_value);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+Item_decimal::Item_decimal(longlong val, bool unsig)
+{
+ int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(&decimal_value);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+Item_decimal::Item_decimal(double val, int precision, int scale)
+{
+ double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value);
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(&decimal_value);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg,
+ uint decimal_par, uint length)
+{
+ my_decimal2decimal(val_arg, &decimal_value);
+ name= (char*) str;
+ decimals= (uint8) decimal_par;
+ max_length= length;
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+Item_decimal::Item_decimal(my_decimal *value_par)
+{
+ my_decimal2decimal(value_par, &decimal_value);
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(value_par);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+Item_decimal::Item_decimal(const char *bin, int precision, int scale)
+{
+ binary2my_decimal(E_DEC_FATAL_ERROR, bin, &decimal_value, precision, scale);
+ decimals= (uint8) decimal_value.frac;
+ max_length= my_decimal_max_length(&decimal_value);
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+longlong Item_decimal::val_int()
+{
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &result);
+ return result;
+}
+
+double Item_decimal::val_real()
+{
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
+ return result;
+}
+
+String *Item_decimal::val_str(String *result)
+{
+ result->set_charset(&my_charset_bin);
+ my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, result);
+ return result;
+}
+
+void Item_decimal::print(String *str)
+{
+ my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value);
+ str->append(str_value);
+}
+
+
+String *Item_float::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
@@ -790,6 +1452,15 @@ String *Item_real::val_str(String *str)
}
+my_decimal *Item_float::val_decimal(my_decimal *decimal_value)
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value);
+ return (decimal_value);
+}
+
+
void Item_string::print(String *str)
{
str->append('_');
@@ -799,9 +1470,76 @@ void Item_string::print(String *str)
str->append('\'');
}
+
+inline bool check_if_only_end_space(CHARSET_INFO *cs, char *str, char *end)
+{
+ return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end;
+}
+
+
+double Item_string::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ int error;
+ char *end, *org_end;
+ double tmp;
+ CHARSET_INFO *cs= str_value.charset();
+
+ org_end= (char*) str_value.ptr() + str_value.length();
+ tmp= my_strntod(cs, (char*) str_value.ptr(), str_value.length(), &end,
+ &error);
+ if (error || (end != org_end && !check_if_only_end_space(cs, end, org_end)))
+ {
+ /*
+ We can use str_value.ptr() here as Item_string is gurantee to put an
+ end \0 here.
+ */
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), "DOUBLE",
+ str_value.ptr());
+ }
+ return tmp;
+}
+
+
+longlong Item_string::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ int err;
+ longlong tmp;
+ char *end= (char*) str_value.ptr()+ str_value.length();
+ char *org_end= end;
+ CHARSET_INFO *cs= str_value.charset();
+
+ tmp= (*(cs->cset->strtoll10))(cs, str_value.ptr(), &end, &err);
+ /*
+ TODO: Give error if we wanted a signed integer and we got an unsigned
+ one
+ */
+ if (err > 0 ||
+ (end != org_end && !check_if_only_end_space(cs, end, org_end)))
+ {
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER",
+ str_value.ptr());
+ }
+ return tmp;
+}
+
+
+my_decimal *Item_string::val_decimal(my_decimal *decimal_value)
+{
+ return val_decimal_from_string(decimal_value);
+}
+
+
bool Item_null::eq(const Item *item, bool binary_cmp) const
{ return item->type() == type(); }
-double Item_null::val()
+
+
+double Item_null::val_real()
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
@@ -824,6 +1562,11 @@ String *Item_null::val_str(String *str)
return 0;
}
+my_decimal *Item_null::val_decimal(my_decimal *decimal_value)
+{
+ return 0;
+}
+
Item *Item_null::safe_charset_converter(CHARSET_INFO *tocs)
{
@@ -846,12 +1589,13 @@ default_set_param_func(Item_param *param,
param->set_null();
}
+
Item_param::Item_param(unsigned pos_in_query_arg) :
state(NO_VALUE),
item_result_type(STRING_RESULT),
/* Don't pretend to be a literal unless value for this item is set. */
item_type(PARAM_ITEM),
- param_type(MYSQL_TYPE_STRING),
+ param_type(MYSQL_TYPE_VARCHAR),
pos_in_query(pos_in_query_arg),
set_param_func(default_set_param_func)
{
@@ -864,11 +1608,11 @@ Item_param::Item_param(unsigned pos_in_query_arg) :
maybe_null= 1;
}
+
void Item_param::set_null()
{
DBUG_ENTER("Item_param::set_null");
/* These are cleared after each execution by reset() method */
- max_length= 0;
null_value= 1;
/*
Because of NULL and string values we need to set max_length for each new
@@ -905,6 +1649,35 @@ void Item_param::set_double(double d)
/*
+ Set decimal parameter value from string.
+
+ SYNOPSIS
+ set_decimal()
+ str - character string
+ length - string length
+
+ NOTE
+ as we use character strings to send decimal values in
+ binary protocol, we use str2my_decimal to convert it to
+ internal decimal value.
+*/
+
+void Item_param::set_decimal(const char *str, ulong length)
+{
+ char *end;
+ DBUG_ENTER("Item_param::set_decimal");
+
+ end= (char*) str+length;
+ str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end);
+ state= DECIMAL_VALUE;
+ decimals= decimal_value.frac;
+ max_length= decimal_value.intg + decimals + 2;
+ maybe_null= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
Set parameter value from TIME value.
SYNOPSIS
@@ -933,7 +1706,7 @@ void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg)
{
char buff[MAX_DATE_STRING_REP_LENGTH];
uint length= my_TIME_to_str(&value.time, buff);
- make_truncated_value_warning(current_thd, buff, length, type);
+ make_truncated_value_warning(current_thd, buff, length, type, 0);
set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
}
@@ -957,6 +1730,7 @@ bool Item_param::set_str(const char *str, ulong length)
&dummy_errors))
DBUG_RETURN(TRUE);
state= STRING_VALUE;
+ max_length= length;
maybe_null= 0;
/* max_length and decimals are set after charset conversion */
/* sic: str may be not null-terminated, don't add DBUG_PRINT here */
@@ -996,7 +1770,7 @@ bool Item_param::set_longdata(const char *str, ulong length)
RETURN
0 OK
- 1 Out of memort
+ 1 Out of memory
*/
bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
@@ -1042,6 +1816,15 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
DBUG_RETURN(1);
break;
}
+ case DECIMAL_RESULT:
+ {
+ const my_decimal *ent_value= (const my_decimal *)entry->value;
+ my_decimal2decimal(ent_value, &decimal_value);
+ state= DECIMAL_VALUE;
+ decimals= ent_value->frac;
+ max_length= ent_value->intg + decimals + 2;
+ break;
+ }
default:
DBUG_ASSERT(0);
set_null();
@@ -1073,7 +1856,7 @@ void Item_param::reset()
str_value.length(0);
str_value_ptr.length(0);
/*
- We must prevent all charset conversions untill data has been written
+ We must prevent all charset conversions until data has been written
to the binary log.
*/
str_value.set_charset(&my_charset_bin);
@@ -1101,6 +1884,8 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
return field->store(value.integer);
case REAL_VALUE:
return field->store(value.real);
+ case DECIMAL_VALUE:
+ return field->store_decimal(&decimal_value);
case TIME_VALUE:
field->store_time(&value.time, value.time.time_type);
return 0;
@@ -1144,21 +1929,27 @@ bool Item_param::get_date(TIME *res, uint fuzzydate)
}
-double Item_param::val()
+double Item_param::val_real()
{
switch (state) {
case REAL_VALUE:
return value.real;
case INT_VALUE:
return (double) value.integer;
+ case DECIMAL_VALUE:
+ {
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
+ return result;
+ }
case STRING_VALUE:
case LONG_DATA_VALUE:
- {
- int dummy_err;
- char *end_not_used;
- return my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(), &end_not_used, &dummy_err);
- }
+ {
+ int dummy_err;
+ char *end_not_used;
+ return my_strntod(str_value.charset(), (char*) str_value.ptr(),
+ str_value.length(), &end_not_used, &dummy_err);
+ }
case TIME_VALUE:
/*
This works for example when user says SELECT ?+0.0 and supplies
@@ -1181,6 +1972,12 @@ longlong Item_param::val_int()
return (longlong) (value.real + (value.real > 0 ? 0.5 : -0.5));
case INT_VALUE:
return value.integer;
+ case DECIMAL_VALUE:
+ {
+ longlong i;
+ my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &i);
+ return i;
+ }
case STRING_VALUE:
case LONG_DATA_VALUE:
{
@@ -1199,6 +1996,36 @@ longlong Item_param::val_int()
}
+my_decimal *Item_param::val_decimal(my_decimal *dec)
+{
+ switch (state) {
+ case DECIMAL_VALUE:
+ return &decimal_value;
+ case REAL_VALUE:
+ double2my_decimal(E_DEC_FATAL_ERROR, value.real, dec);
+ return dec;
+ case INT_VALUE:
+ int2my_decimal(E_DEC_FATAL_ERROR, value.integer, unsigned_flag, dec);
+ return dec;
+ case STRING_VALUE:
+ case LONG_DATA_VALUE:
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, dec);
+ return dec;
+ case TIME_VALUE:
+ {
+ longlong i= (longlong) TIME_to_ulonglong(&value.time);
+ int2my_decimal(E_DEC_FATAL_ERROR, i, 0, dec);
+ return dec;
+ }
+ case NULL_VALUE:
+ return 0;
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0;
+}
+
+
String *Item_param::val_str(String* str)
{
switch (state) {
@@ -1211,6 +2038,11 @@ String *Item_param::val_str(String* str)
case INT_VALUE:
str->set(value.integer, &my_charset_bin);
return str;
+ case DECIMAL_VALUE:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
+ 0, 0, 0, str) <= 1)
+ return str;
+ return NULL;
case TIME_VALUE:
{
if (str->reserve(MAX_DATE_STRING_REP_LENGTH))
@@ -1243,6 +2075,11 @@ const String *Item_param::query_val_str(String* str) const
case REAL_VALUE:
str->set(value.real, NOT_FIXED_DEC, &my_charset_bin);
break;
+ case DECIMAL_VALUE:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
+ 0, 0, 0, str) > 1)
+ return &my_null_string;
+ break;
case TIME_VALUE:
{
char *buf, *ptr;
@@ -1274,7 +2111,7 @@ const String *Item_param::query_val_str(String* str) const
buf= str->c_ptr_quick();
ptr= buf;
*ptr++= '\'';
- ptr+= escape_string_for_mysql(str_value.charset(), ptr,
+ ptr+= escape_string_for_mysql(str_value.charset(), ptr, 0,
str_value.ptr(), str_value.length());
*ptr++= '\'';
str->length(ptr - buf);
@@ -1356,9 +2193,28 @@ bool Item_param::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 0;
}
-/* End of Item_param related */
+
+void Item_param::print(String *str)
+{
+ if (state == NO_VALUE)
+ {
+ str->append('?');
+ }
+ else
+ {
+ char buffer[STRING_BUFFER_USUAL_SIZE];
+ String tmp(buffer, sizeof(buffer), &my_charset_bin);
+ const String *res;
+ res= query_val_str(&tmp);
+ str->append(*res);
+ }
+}
+/****************************************************************************
+ Item_copy_string
+****************************************************************************/
+
void Item_copy_string::copy()
{
String *res=item->val_str(&str_value);
@@ -1377,6 +2233,17 @@ String *Item_copy_string::val_str(String *str)
}
+my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value)
+{
+ // Item_copy_string is used without fix_fields call
+ if (null_value)
+ return 0;
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value);
+ return (decimal_value);
+}
+
+
+
int Item_copy_string::save_in_field(Field *field, bool no_conversions)
{
if (null_value)
@@ -1399,10 +2266,10 @@ bool Item::fix_fields(THD *thd,
// We do not check fields which are fixed during construction
DBUG_ASSERT(fixed == 0 || basic_const_item());
fixed= 1;
- return 0;
+ return FALSE;
}
-double Item_ref_null_helper::val()
+double Item_ref_null_helper::val_real()
{
DBUG_ASSERT(fixed == 1);
double tmp= (*ref)->val_result();
@@ -1420,6 +2287,24 @@ longlong Item_ref_null_helper::val_int()
}
+my_decimal *Item_ref_null_helper::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ my_decimal *val= (*ref)->val_decimal_result(decimal_value);
+ owner->was_null|= null_value= (*ref)->null_value;
+ return val;
+}
+
+
+bool Item_ref_null_helper::val_bool()
+{
+ DBUG_ASSERT(fixed == 1);
+ bool val= (*ref)->val_bool_result();
+ owner->was_null|= null_value= (*ref)->null_value;
+ return val;
+}
+
+
String* Item_ref_null_helper::val_str(String* s)
{
DBUG_ASSERT(fixed == 1);
@@ -1436,29 +2321,37 @@ bool Item_ref_null_helper::get_date(TIME *ltime, uint fuzzydate)
/*
- Mark item and SELECT_LEXs as dependent if it is not outer resolving
+ Mark item and SELECT_LEXs as dependent if item was resolved in outer SELECT
SYNOPSIS
mark_as_dependent()
thd - thread handler
last - select from which current item depend
current - current select
- item - item which should be marked
+ resolved_item - item which was resolved in outer SELECT(for warning)
+ mark_item - item which should be marked (can be differ in case of
+ substitution)
*/
static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
- Item_ident *item)
-{
- // store pointer on SELECT_LEX from which item is dependent
- item->depended_from= last;
+ Item_ident *resolved_item,
+ Item_ident *mark_item)
+{
+ const char *db_name= (resolved_item->db_name ?
+ resolved_item->db_name : "");
+ const char *table_name= (resolved_item->table_name ?
+ resolved_item->table_name : "");
+ /* store pointer on SELECT_LEX from which item is dependent */
+ if (mark_item)
+ mark_item->depended_from= last;
current->mark_as_dependent(last);
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_WARN_FIELD_RESOLVED),
- (item->db_name?item->db_name:""), (item->db_name?".":""),
- (item->table_name?item->table_name:""), (item->table_name?".":""),
- item->field_name,
+ db_name, (db_name[0] ? "." : ""),
+ table_name, (table_name [0] ? "." : ""),
+ resolved_item->field_name,
current->select_number, last->select_number);
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_WARN_FIELD_RESOLVED, warn_buff);
@@ -1466,177 +2359,471 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
}
-bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+
+
+/*
+ Search a GROUP BY clause for a field with a certain name.
+
+ SYNOPSIS
+ find_field_in_group_list()
+ find_item the item being searched for
+ group_list GROUP BY clause
+
+ DESCRIPTION
+ Search the GROUP BY list for a column named as find_item. When searching
+ preference is given to columns that are qualified with the same table (and
+ database) name as the one being searched for.
+
+ RETURN
+ - the found item on success
+ - NULL if find_item is not in group_list
+*/
+
+static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
+{
+ const char *db_name;
+ const char *table_name;
+ const char *field_name;
+ ORDER *found_group= NULL;
+ int found_match_degree= 0;
+ Item_field *cur_field;
+ int cur_match_degree= 0;
+
+ if (find_item->type() == Item::FIELD_ITEM ||
+ find_item->type() == Item::REF_ITEM)
+ {
+ db_name= ((Item_ident*) find_item)->db_name;
+ table_name= ((Item_ident*) find_item)->table_name;
+ field_name= ((Item_ident*) find_item)->field_name;
+ }
+ else
+ return NULL;
+
+ DBUG_ASSERT(field_name != 0);
+
+ for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next)
+ {
+ if ((*(cur_group->item))->type() == Item::FIELD_ITEM)
+ {
+ cur_field= (Item_field*) *cur_group->item;
+ cur_match_degree= 0;
+
+ DBUG_ASSERT(cur_field->field_name != 0);
+
+ if (!my_strcasecmp(system_charset_info,
+ cur_field->field_name, field_name))
+ ++cur_match_degree;
+ else
+ continue;
+
+ if (cur_field->table_name && table_name)
+ {
+ /* If field_name is qualified by a table name. */
+ if (strcmp(cur_field->table_name, table_name))
+ /* Same field names, different tables. */
+ return NULL;
+
+ ++cur_match_degree;
+ if (cur_field->db_name && db_name)
+ {
+ /* If field_name is also qualified by a database name. */
+ if (strcmp(cur_field->db_name, db_name))
+ /* Same field names, different databases. */
+ return NULL;
+ ++cur_match_degree;
+ }
+ }
+
+ if (cur_match_degree > found_match_degree)
+ {
+ found_match_degree= cur_match_degree;
+ found_group= cur_group;
+ }
+ else if (found_group && (cur_match_degree == found_match_degree) &&
+ ! (*(found_group->item))->eq(cur_field, 0))
+ {
+ /*
+ If the current resolve candidate matches equally well as the current
+ best match, they must reference the same column, otherwise the field
+ is ambiguous.
+ */
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find_item->full_name(), current_thd->where);
+ return NULL;
+ }
+ }
+ }
+
+ if (found_group)
+ return found_group->item;
+ else
+ return NULL;
+}
+
+
+/*
+ Resolve a column reference in a sub-select.
+
+ SYNOPSIS
+ resolve_ref_in_select_and_group()
+ thd current thread
+ ref column reference being resolved
+ select the sub-select that ref is resolved against
+
+ DESCRIPTION
+ Resolve a column reference (usually inside a HAVING clause) against the
+ SELECT and GROUP BY clauses of the query described by 'select'. The name
+ resolution algorithm searches both the SELECT and GROUP BY clauses, and in
+ case of a name conflict prefers GROUP BY column names over SELECT names. If
+ both clauses contain different fields with the same names, a warning is
+ issued that name of 'ref' is ambiguous. We extend ANSI SQL in that when no
+ GROUP BY column is found, then a HAVING name is resolved as a possibly
+ derived SELECT column.
+
+ NOTES
+ The resolution procedure is:
+ - Search for a column or derived column named col_ref_i [in table T_j]
+ in the SELECT clause of Q.
+ - Search for a column named col_ref_i [in table T_j]
+ in the GROUP BY clause of Q.
+ - If found different columns with the same name in GROUP BY and SELECT
+ - issue a warning and return the GROUP BY column,
+ - otherwise return the found SELECT column.
+
+
+ RETURN
+ NULL - there was an error, and the error was already reported
+ not_found_item - the item was not resolved, no error was reported
+ resolved item - if the item was resolved
+*/
+
+static Item**
+resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
+{
+ Item **group_by_ref= NULL;
+ Item **select_ref= NULL;
+ ORDER *group_list= (ORDER*) select->group_list.first;
+ bool ambiguous_fields= FALSE;
+ uint counter;
+ bool not_used;
+
+ /*
+ Search for a column or derived column named as 'ref' in the SELECT
+ clause of the current select.
+ */
+ if (!(select_ref= find_item_in_list(ref, *(select->get_item_list()),
+ &counter, REPORT_EXCEPT_NOT_FOUND,
+ &not_used)))
+ return NULL; /* Some error occurred. */
+
+ /* If this is a non-aggregated field inside HAVING, search in GROUP BY. */
+ if (select->having_fix_field && !ref->with_sum_func && group_list)
+ {
+ group_by_ref= find_field_in_group_list(ref, group_list);
+
+ /* Check if the fields found in SELECT and GROUP BY are the same field. */
+ if (group_by_ref && (select_ref != not_found_item) &&
+ !((*group_by_ref)->eq(*select_ref, 0)))
+ {
+ ambiguous_fields= TRUE;
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NON_UNIQ_ERROR,
+ ER(ER_NON_UNIQ_ERROR), ref->full_name(),
+ current_thd->where);
+
+ }
+ }
+
+ if (select_ref != not_found_item || group_by_ref)
+ {
+ if (select_ref != not_found_item && !ambiguous_fields)
+ {
+ DBUG_ASSERT(*select_ref != 0);
+ if (!select->ref_pointer_array[counter])
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0),
+ ref->name, "forward reference in item list");
+ return NULL;
+ }
+ DBUG_ASSERT((*select_ref)->fixed);
+ return (select->ref_pointer_array + counter);
+ }
+ if (group_by_ref)
+ return group_by_ref;
+ DBUG_ASSERT(FALSE);
+ return NULL; /* So there is no compiler warning. */
+ }
+
+ return (Item**) not_found_item;
+}
+
+
+/*
+ Resolve the name of a column reference.
+
+ 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
+ The method resolves the column reference represented by 'this' as a column
+ present in one of: FROM clause, SELECT clause, GROUP BY clause of a query
+ Q, or in outer queries that contain Q.
+
+ NOTES
+ The name resolution algorithm used is (where [T_j] is an optional table
+ name that qualifies the column name):
+
+ resolve_column_reference([T_j].col_ref_i)
+ {
+ search for a column or derived column named col_ref_i
+ [in table T_j] in the FROM clause of Q;
+
+ if such a column is NOT found AND // Lookup in outer queries.
+ there are outer queries
+ {
+ for each outer query Q_k beginning from the inner-most one
+ {
+ if - Q_k is not a group query AND
+ - Q_k is not inside an aggregate function
+ OR
+ - Q_(k-1) is not in a HAVING or SELECT clause of Q_k
+ {
+ search for a column or derived column named col_ref_i
+ [in table T_j] in the FROM clause of Q_k;
+ }
+
+ if such a column is not found
+ Search for a column or derived column named col_ref_i
+ [in table T_j] in the SELECT and GROUP clauses of Q_k.
+ }
+ }
+ }
+
+ Notice that compared to Item_ref::fix_fields, here we first search the FROM
+ clause, and then we search the SELECT and GROUP BY clauses.
+
+ RETURN
+ TRUE if error
+ FALSE on success
+*/
+
+bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
{
enum_parsing_place place= NO_MATTER;
DBUG_ASSERT(fixed == 0);
if (!field) // If field is not checked
{
- TABLE_LIST *where= 0;
- bool upward_lookup= 0;
- Field *tmp= (Field *)not_found_field;
- if ((tmp= find_field_in_tables(thd, this, tables, &where, 0)) ==
+ bool upward_lookup= FALSE;
+ Field *from_field= (Field *)not_found_field;
+ /*
+ 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 ((from_field= find_field_in_tables(thd, this, tables, reference,
+ IGNORE_EXCEPT_NON_UNIQUE,
+ !any_privileges)) ==
not_found_field)
{
- /*
- We can't find table field in table list of current select,
- consequently we have to find it in outer subselect(s).
- We can't join lists of outer & current select, because of scope
- of view rules. For example if both tables (outer & current) have
- field 'field' it is not mistake to refer to this field without
- mention of table name, but if we join tables in one list it will
- cause error ER_NON_UNIQ_ERROR in find_field_in_tables.
- */
SELECT_LEX *last= 0;
-#ifdef EMBEDDED_LIBRARY
- thd->net.last_errno= 0;
-#endif
TABLE_LIST *table_list;
- Item **refer= (Item **)not_found_item;
- uint counter;
- bool not_used;
- // Prevent using outer fields in subselects, that is not supported now
- SELECT_LEX *cursel= (SELECT_LEX *) thd->lex->current_select;
- if (cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
+ 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).
+
+ 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.
+ */
+ if (current_sel->master_unit()->first_select()->linkage !=
+ DERIVED_TABLE_TYPE)
{
- SELECT_LEX_UNIT *prev_unit= cursel->master_unit();
- for (SELECT_LEX *sl= prev_unit->outer_select();
- sl;
- sl= (prev_unit= sl->master_unit())->outer_select())
+ 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())
{
- upward_lookup= 1;
- table_list= (last= sl)->get_table_list();
- if (sl->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
+ 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 primary INSERT st_select_lex => skip first table
- resolving
+ It is a primary INSERT st_select_lex => do not resolve against the
+ first table.
*/
- table_list= table_list->next;
- }
-
- Item_subselect *prev_subselect_item= prev_unit->item;
+ table_list= table_list->next_local;
+ }
place= prev_subselect_item->parsing_place;
/*
- check table fields only if subquery used somewhere out of HAVING
- or outer SELECT do not use groupping (i.e. tables are
- accessable)
+ 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).
+
+ 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 ||
- (sl->with_sum_func == 0 && sl->group_list.elements == 0)) &&
- (tmp= find_field_in_tables(thd, this,
- table_list, &where,
- 0)) != not_found_field)
- {
- if (!tmp)
- return -1;
- prev_subselect_item->used_tables_cache|= tmp->table->map;
- prev_subselect_item->const_item_cache= 0;
- break;
- }
- if (sl->resolve_mode == SELECT_LEX::SELECT_MODE &&
- (refer= find_item_in_list(this, sl->item_list, &counter,
- REPORT_EXCEPT_NOT_FOUND,
- &not_used)) !=
- (Item **) not_found_item)
+ (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 (refer && (*refer)->fixed) // Avoid crash in case of error
- {
- prev_subselect_item->used_tables_cache|= (*refer)->used_tables();
- prev_subselect_item->const_item_cache&= (*refer)->const_item();
- }
+ 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;
}
+ /* Search in the SELECT and GROUP lists of the outer select. */
+ if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
+ {
+ 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)
+ {
+ DBUG_ASSERT(*ref && (*ref)->fixed);
+ prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
+ prev_subselect_item->const_item_cache&= (*ref)->const_item();
+ 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;
- if (sl->master_unit()->first_select()->linkage ==
+ if (outer_sel->master_unit()->first_select()->linkage ==
DERIVED_TABLE_TYPE)
break; // do not look over derived table
}
}
- if (!tmp)
- return -1;
- else if (!refer)
- return 1;
- else if (tmp == not_found_field && refer == (Item **)not_found_item)
+
+ DBUG_ASSERT(ref != 0);
+ if (!from_field)
+ return TRUE;
+ if (ref == not_found_item && from_field == not_found_field)
{
if (upward_lookup)
{
- // We can't say exactly what absend table or field
- my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0),
- full_name(), thd->where);
+ // 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, &where, 1);
+ find_field_in_tables(thd, this, tables, reference, REPORT_ALL_ERRORS,
+ TRUE);
}
- return -1;
+ return TRUE;
}
- else if (refer != (Item **)not_found_item)
+ else if (ref != not_found_item)
{
- if (!last->ref_pointer_array[counter])
- {
- my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
- "forward reference in item list");
- return -1;
- }
- DBUG_ASSERT((*refer)->fixed);
+ Item *save;
+ Item_ref *rf;
+
+ /* Should have been checked in resolve_ref_in_select_and_group(). */
+ DBUG_ASSERT(*ref && (*ref)->fixed);
/*
Here, a subset of actions performed by Item_ref::set_properties
is not enough. So we pass ptr to NULL into Item_[direct]_ref
constructor, so no initialization is performed, and call
fix_fields() below.
*/
- Item *save= last->ref_pointer_array[counter];
- last->ref_pointer_array[counter]= NULL;
- Item_ref *rf= (place == IN_HAVING ?
- new Item_ref(last->ref_pointer_array + counter,
- (char *)table_name,
- (char *)field_name) :
- new Item_direct_ref(last->ref_pointer_array + counter,
- (char *)table_name,
- (char *)field_name));
+ 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));
+ *ref= save;
if (!rf)
- return 1;
- thd->change_item_tree(ref, rf);
- last->ref_pointer_array[counter]= save;
+ return TRUE;
+ 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()
*/
- if (rf->fix_fields(thd, tables, ref) || rf->check_cols(1))
- return 1;
+ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref()
+ if (rf->fix_fields(thd, tables, reference) || rf->check_cols(1))
+ return TRUE;
- mark_as_dependent(thd, last, cursel, rf);
- return 0;
+ mark_as_dependent(thd, last, current_sel, this, rf);
+ return FALSE;
}
else
{
- mark_as_dependent(thd, last, cursel, this);
+ mark_as_dependent(thd, last, current_sel, this, this);
if (last->having_fix_field)
{
Item_ref *rf;
- rf= new Item_ref((where->db[0] ? where->db : 0),
- (char*) where->alias, (char*) field_name);
+ rf= new Item_ref((cached_table->db[0] ? cached_table->db : 0),
+ (char*) cached_table->alias, (char*) field_name);
if (!rf)
- return 1;
- thd->change_item_tree(ref, rf);
+ return TRUE;
+ 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()
*/
- return rf->fix_fields(thd, tables, ref) || rf->check_cols(1);
+ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref()
+ return (rf->fix_fields(thd, tables, reference) || rf->check_cols(1));
}
}
}
- else if (!tmp)
- return -1;
+ else if (!from_field)
+ return TRUE;
+
+ /*
+ if it is not expression from merged VIEW we will set this field.
- set_field(tmp);
+ We can leave expression substituted from view for next PS/SP rexecution
+ (i.e. do not register this substitution for reverting on cleupup()
+ (register_item_tree_changing())), because this subtree will be
+ fix_field'ed during setup_tables()->setup_ancestor() (i.e. before
+ all other expressions of query, and references on tables which do
+ not present in query will not make problems.
+
+ Also we suppose that view can't be changed during PS/SP life.
+ */
+ if (from_field == view_ref_found)
+ return FALSE;
+
+ set_field(from_field);
}
else if (thd->set_query_id && field->query_id != thd->query_id)
{
@@ -1645,24 +2832,187 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
field->query_id=thd->query_id;
table->used_fields++;
table->used_keys.intersect(field->part_of_key);
- fixed= 1;
}
- return 0;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (any_privileges)
+ {
+ char *db, *tab;
+ if (cached_table->view)
+ {
+ db= cached_table->view_db.str;
+ tab= cached_table->view_name.str;
+ }
+ else
+ {
+ db= cached_table->db;
+ tab= cached_table->table_name;
+ }
+ if (!(have_privileges= (get_column_grant(thd, &field->table->grant,
+ db, tab, field_name) &
+ VIEW_ANY_ACL)))
+ {
+ my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
+ "ANY", thd->priv_user, thd->host_or_ip,
+ field_name, tab);
+ return TRUE;
+ }
+ }
+#endif
+ fixed= 1;
+ return FALSE;
}
+
+Item *Item_field::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ no_const_subst= 1;
+ return Item::safe_charset_converter(tocs);
+}
+
+
void Item_field::cleanup()
{
DBUG_ENTER("Item_field::cleanup");
Item_ident::cleanup();
/*
Even if this object was created by direct link to field in setup_wild()
- it will be linked correctly next tyme by name of field and table alias.
+ it will be linked correctly next time by name of field and table alias.
I.e. we can drop 'field'.
*/
field= result_field= 0;
DBUG_VOID_RETURN;
}
+/*
+ Find a field among specified multiple equalities
+
+ SYNOPSIS
+ find_item_equal()
+ cond_equal reference to list of multiple equalities where
+ the field (this object) is to be looked for
+
+ DESCRIPTION
+ The function first searches the field among multiple equalities
+ of the current level (in the cond_equal->current_level list).
+ If it fails, it continues searching in upper levels accessed
+ through a pointer cond_equal->upper_levels.
+ The search terminates as soon as a multiple equality containing
+ the field is found.
+
+ RETURN VALUES
+ First Item_equal containing the field, if success
+ 0, otherwise
+*/
+Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
+{
+ Item_equal *item= 0;
+ while (cond_equal)
+ {
+ List_iterator_fast<Item_equal> li(cond_equal->current_level);
+ while ((item= li++))
+ {
+ if (item->contains(field))
+ return item;
+ }
+ /*
+ The field is not found in any of the multiple equalities
+ of the current level. Look for it in upper levels
+ */
+ cond_equal= cond_equal->upper_levels;
+ }
+ return 0;
+}
+
+
+/*
+ Set a pointer to the multiple equality the field reference belongs to
+ (if any)
+
+ SYNOPSIS
+ equal_fields_propagator()
+ arg - reference to list of multiple equalities where
+ the field (this object) is to be looked for
+
+ DESCRIPTION
+ The function looks for a multiple equality containing the field item
+ among those referenced by arg.
+ In the case such equality exists the function does the following.
+ If the found multiple equality contains a constant, then the field
+ reference is substituted for this constant, otherwise it sets a pointer
+ to the multiple equality in the field item.
+
+ NOTES
+ This function is supposed to be called as a callback parameter in calls
+ of the transform method.
+
+ RETURN VALUES
+ pointer to the replacing constant item, if the field item was substituted
+ pointer to the field item, otherwise.
+*/
+
+Item *Item_field::equal_fields_propagator(byte *arg)
+{
+ if (no_const_subst)
+ return this;
+ item_equal= find_item_equal((COND_EQUAL *) arg);
+ Item *item= 0;
+ if (item_equal)
+ item= item_equal->get_const();
+ if (!item)
+ item= this;
+ return item;
+}
+
+
+/*
+ Mark the item to not be part of substitution if it's not a binary item
+ See comments in Arg_comparator::set_compare_func() for details
+*/
+
+Item *Item_field::set_no_const_sub(byte *arg)
+{
+ if (field->charset() != &my_charset_bin)
+ no_const_subst=1;
+ return this;
+}
+
+
+/*
+ Replace an Item_field for an equal Item_field that evaluated earlier
+ (if any)
+
+ SYNOPSIS
+ replace_equal_field_()
+ arg - a dummy parameter, is not used here
+
+ DESCRIPTION
+ The function returns a pointer to an item that is taken from
+ the very beginning of the item_equal list which the Item_field
+ object refers to (belongs to).
+ If the Item_field object does not refer any Item_equal object
+ 'this' is returned
+
+ NOTES
+ This function is supposed to be called as a callback parameter in calls
+ of the thransformer method.
+
+ RETURN VALUES
+ pointer to a replacement Item_field if there is a better equal item;
+ this - otherwise.
+*/
+
+Item *Item_field::replace_equal_field(byte *arg)
+{
+ if (item_equal)
+ {
+ Item_field *subst= item_equal->get_first();
+ if (!field->eq(subst->field))
+ return subst;
+ }
+ return this;
+}
+
+
void Item::init_make_field(Send_field *tmp_field,
enum enum_field_types field_type)
{
@@ -1691,18 +3041,63 @@ void Item::make_field(Send_field *tmp_field)
void Item_empty_string::make_field(Send_field *tmp_field)
{
- init_make_field(tmp_field,FIELD_TYPE_VAR_STRING);
+ init_make_field(tmp_field, MYSQL_TYPE_VARCHAR);
}
enum_field_types Item::field_type() const
{
- return ((result_type() == STRING_RESULT) ? FIELD_TYPE_VAR_STRING :
- (result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG :
- FIELD_TYPE_DOUBLE);
+ switch (result_type()) {
+ case STRING_RESULT: return MYSQL_TYPE_VARCHAR;
+ case INT_RESULT: return FIELD_TYPE_LONGLONG;
+ case DECIMAL_RESULT: return FIELD_TYPE_NEWDECIMAL;
+ case REAL_RESULT: return FIELD_TYPE_DOUBLE;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return MYSQL_TYPE_VARCHAR;
+ }
+}
+
+
+/*
+ Create a field to hold a string value from an item
+
+ SYNOPSIS
+ make_string_field()
+ table Table for which the field is created
+
+ IMPLEMENTATION
+ If max_length > CONVERT_IF_BIGGER_TO_BLOB create a blob
+ If max_length > 0 create a varchar
+ If max_length == 0 create a CHAR(0)
+*/
+
+
+Field *Item::make_string_field(TABLE *table)
+{
+ if (max_length > CONVERT_IF_BIGGER_TO_BLOB)
+ return new Field_blob(max_length, maybe_null, name, table,
+ collation.collation);
+ if (max_length > 0)
+ return new Field_varstring(max_length, maybe_null, name, table,
+ collation.collation);
+ return new Field_string(max_length, maybe_null, name, table,
+ collation.collation);
}
+/*
+ Create a field based on field_type of argument
+
+ For now, this is only used to create a field for
+ IFNULL(x,something)
+
+ RETURN
+ 0 error
+ # Created field
+*/
+
Field *Item::tmp_table_field_from_field_type(TABLE *table)
{
/*
@@ -1714,6 +3109,11 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
case MYSQL_TYPE_DECIMAL:
return new Field_decimal((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table, decimals, 0, unsigned_flag);
+ case MYSQL_TYPE_NEWDECIMAL:
+ return new Field_new_decimal((char*) 0, max_length - (decimals?1:0),
+ null_ptr, 0,
+ Field::NONE, name, table, decimals, 0,
+ unsigned_flag);
case MYSQL_TYPE_TINY:
return new Field_tiny((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table, 0, unsigned_flag);
@@ -1752,32 +3152,24 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
return new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table);
default:
- /* This case should never be choosen */
+ /* This case should never be chosen */
DBUG_ASSERT(0);
/* If something goes awfully wrong, it's better to get a string than die */
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
- case MYSQL_TYPE_VAR_STRING:
- if (max_length > 255)
- break; // If blob
- return new Field_varstring(max_length, maybe_null, name, table,
- collation.collation);
case MYSQL_TYPE_STRING:
- if (max_length > 255) // If blob
- break;
- return new Field_string(max_length, maybe_null, name, table,
- collation.collation);
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_VARCHAR:
+ return make_string_field(table);
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_GEOMETRY:
+ return new Field_blob(max_length, maybe_null, name, table,
+ collation.collation);
break; // Blob handled outside of case
}
-
- /* blob is special as it's generated for both blobs and long strings */
- return new Field_blob(max_length, maybe_null, name, table,
- collation.collation);
}
@@ -1785,7 +3177,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
void Item_field::make_field(Send_field *tmp_field)
{
field->make_field(tmp_field);
- DBUG_ASSERT(tmp_field->table_name);
+ DBUG_ASSERT(tmp_field->table_name != 0);
if (name)
tmp_field->col_name=name; // Use user supplied name
}
@@ -1857,7 +3249,7 @@ int Item_null::save_in_field(Field *field, bool no_conversions)
field Field where we want to store NULL
RETURN VALUES
- 0 ok
+ 0 OK
1 Field doesn't support NULL values
*/
@@ -1890,12 +3282,21 @@ int Item::save_in_field(Field *field, bool no_conversions)
}
else if (result_type() == REAL_RESULT)
{
- double nr=val();
+ double nr= val_real();
if (null_value)
return set_field_to_null(field);
field->set_notnull();
error=field->store(nr);
}
+ else if (result_type() == DECIMAL_RESULT)
+ {
+ my_decimal decimal_value;
+ my_decimal *value= val_decimal(&decimal_value);
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ error=field->store_decimal(value);
+ }
else
{
longlong nr=val_int();
@@ -1937,25 +3338,100 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
return field->store(nr);
}
+
+int Item_decimal::save_in_field(Field *field, bool no_conversions)
+{
+ field->set_notnull();
+ return field->store_decimal(&decimal_value);
+}
+
+
Item_num *Item_uint::neg()
{
- return new Item_real(name, - ((double) value), 0, max_length);
+ Item_decimal *item= new Item_decimal(value, 0);
+ return item->neg();
}
-int Item_real::save_in_field(Field *field, bool no_conversions)
+
+static uint nr_of_decimals(const char *str, const char *end)
{
- double nr=val();
+ const char *decimal_point;
+
+ /* Find position for '.' */
+ for (;;)
+ {
+ if (str == end)
+ return 0;
+ if (*str == 'e' || *str == 'E')
+ return NOT_FIXED_DEC;
+ if (*str++ == '.')
+ break;
+ }
+ decimal_point= str;
+ for (; my_isdigit(system_charset_info, *str) ; str++)
+ ;
+ if (*str == 'e' || *str == 'E')
+ return NOT_FIXED_DEC;
+ return (uint) (str - decimal_point);
+}
+
+
+/*
+ This function is only called during parsing. We will signal an error if
+ value is not a true double value (overflow)
+*/
+
+Item_float::Item_float(const char *str_arg, uint length)
+{
+ int error;
+ char *end_not_used;
+ value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end_not_used,
+ &error);
+ if (error)
+ {
+ /*
+ Note that we depend on that str_arg is null terminated, which is true
+ when we are in the parser
+ */
+ DBUG_ASSERT(str_arg[length] == 0);
+ my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", (char*) str_arg);
+ }
+ presentation= name=(char*) str_arg;
+ decimals=(uint8) nr_of_decimals(str_arg, str_arg+length);
+ max_length=length;
+ fixed= 1;
+}
+
+
+int Item_float::save_in_field(Field *field, bool no_conversions)
+{
+ double nr= val_real();
if (null_value)
return set_field_to_null(field);
field->set_notnull();
return field->store(nr);
}
-/****************************************************************************
-** varbinary item
-** In string context this is a binary string
-** In number context this is a longlong value.
-****************************************************************************/
+
+void Item_float::print(String *str)
+{
+ if (presentation)
+ {
+ str->append(presentation);
+ return;
+ }
+ char buffer[20];
+ String num(buffer, sizeof(buffer), &my_charset_bin);
+ num.set(value, decimals, &my_charset_bin);
+ str->append(num);
+}
+
+
+/*
+ hex item
+ In string context this is a binary string.
+ In number context this is a longlong value.
+*/
inline uint char_val(char X)
{
@@ -1965,7 +3441,7 @@ inline uint char_val(char X)
}
-Item_varbinary::Item_varbinary(const char *str, uint str_length)
+Item_hex_string::Item_hex_string(const char *str, uint str_length)
{
name=(char*) str-2; // Lex makes this start with 0x
max_length=(str_length+1)/2;
@@ -1986,7 +3462,7 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length)
fixed= 1;
}
-longlong Item_varbinary::val_int()
+longlong Item_hex_string::val_int()
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
@@ -2000,7 +3476,17 @@ longlong Item_varbinary::val_int()
}
-int Item_varbinary::save_in_field(Field *field, bool no_conversions)
+my_decimal *Item_hex_string::val_decimal(my_decimal *decimal_value)
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ ulonglong value= (ulonglong)val_int();
+ int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value);
+ return (decimal_value);
+}
+
+
+int Item_hex_string::save_in_field(Field *field, bool no_conversions)
{
int error;
field->set_notnull();
@@ -2018,6 +3504,44 @@ int Item_varbinary::save_in_field(Field *field, bool no_conversions)
/*
+ bin item.
+ In string context this is a binary string.
+ In number context this is a longlong value.
+*/
+
+Item_bin_string::Item_bin_string(const char *str, uint str_length)
+{
+ const char *end= str + str_length - 1;
+ uchar bits= 0;
+ uint power= 1;
+
+ name= (char*) str - 2;
+ max_length= (str_length + 7) >> 3;
+ char *ptr= (char*) sql_alloc(max_length + 1);
+ if (!ptr)
+ return;
+ str_value.set(ptr, max_length, &my_charset_bin);
+ ptr+= max_length - 1;
+ ptr[1]= 0; // Set end null for string
+ for (; end >= str; end--)
+ {
+ if (power == 256)
+ {
+ power= 1;
+ *ptr--= bits;
+ bits= 0;
+ }
+ if (*end == '1')
+ bits|= power;
+ power<<= 1;
+ }
+ *ptr= (char) bits;
+ collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
+ fixed= 1;
+}
+
+
+/*
Pack data in buffer for sending
*/
@@ -2034,7 +3558,7 @@ bool Item::send(Protocol *protocol, String *buffer)
{
bool result;
enum_field_types type;
- LINT_INIT(result);
+ LINT_INIT(result); // Will be set if null_value == 0
switch ((type=field_type())) {
default:
@@ -2049,6 +3573,9 @@ bool Item::send(Protocol *protocol, String *buffer)
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_NEWDECIMAL:
{
String *res;
if ((res=val_str(buffer)))
@@ -2064,6 +3591,7 @@ bool Item::send(Protocol *protocol, String *buffer)
break;
}
case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_YEAR:
{
longlong nr;
nr= val_int();
@@ -2091,15 +3619,14 @@ bool Item::send(Protocol *protocol, String *buffer)
case MYSQL_TYPE_FLOAT:
{
float nr;
- nr= (float) val();
+ nr= (float) val_real();
if (!null_value)
result= protocol->store(nr, decimals, buffer);
break;
}
case MYSQL_TYPE_DOUBLE:
{
- double nr;
- nr= val();
+ double nr= val_real();
if (!null_value)
result= protocol->store(nr, decimals, buffer);
break;
@@ -2140,200 +3667,298 @@ 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)
+{
+ /*
+ This constructor used to create some internals references over fixed items
+ */
+ DBUG_ASSERT(ref != 0);
+ if (*ref)
+ set_properties();
+}
+
+
/*
- This is used for HAVING clause
- Find field in select list having the same name
+ Resolve the name of a reference to a column reference.
+
+ 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
+ The method resolves the column reference represented by 'this' as a column
+ present in one of: GROUP BY clause, SELECT clause, outer queries. It is
+ used typically for columns in the HAVING clause which are not under
+ aggregate functions.
+
+ NOTES
+ The name resolution algorithm used is (where [T_j] is an optional table
+ name that qualifies the column name):
+
+ resolve_extended([T_j].col_ref_i)
+ {
+ Search for a column or derived column named col_ref_i [in table T_j]
+ in the SELECT and GROUP clauses of Q.
+
+ if such a column is NOT found AND // Lookup in outer queries.
+ there are outer queries
+ {
+ for each outer query Q_k beginning from the inner-most one
+ {
+ Search for a column or derived column named col_ref_i
+ [in table T_j] in the SELECT and GROUP clauses of Q_k.
+
+ if such a column is not found AND
+ - Q_k is not a group query AND
+ - Q_k is not inside an aggregate function
+ OR
+ - Q_(k-1) is not in a HAVING or SELECT clause of Q_k
+ {
+ search for a column or derived column named col_ref_i
+ [in table T_j] in the FROM clause of Q_k;
+ }
+ }
+ }
+ }
+
+ This procedure treats GROUP BY and SELECT clauses as one namespace for
+ column references in HAVING. Notice that compared to
+ Item_field::fix_fields, here we first search the SELECT and GROUP BY
+ clauses, and then we search the FROM clause.
+
+ POSTCONDITION
+ Item_ref::ref is 0 or points to a valid item
+
+ RETURN
+ TRUE if error
+ FALSE on success
*/
-bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
+bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
{
DBUG_ASSERT(fixed == 0);
- uint counter;
enum_parsing_place place= NO_MATTER;
- bool not_used;
- if (!ref)
+ SELECT_LEX *current_sel= thd->lex->current_select;
+
+ if (!ref || ref == not_found_item)
{
- TABLE_LIST *where= 0, *table_list;
- SELECT_LEX_UNIT *prev_unit= thd->lex->current_select->master_unit();
- SELECT_LEX *sl= prev_unit->outer_select();
- /*
- Finding only in current select will be performed for selects that have
- not outer one and for derived tables (which not support using outer
- fields for now)
- */
- if ((ref= find_item_in_list(this,
- *(thd->lex->current_select->get_item_list()),
- &counter,
- ((sl &&
- thd->lex->current_select->master_unit()->
- first_select()->linkage !=
- DERIVED_TABLE_TYPE) ?
- REPORT_EXCEPT_NOT_FOUND :
- REPORT_ALL_ERRORS ), &not_used)) ==
- (Item **)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 == not_found_item) /* This reference was not resolved. */
{
- Field *tmp= (Field*) not_found_field;
- SELECT_LEX *last= 0;
+ TABLE_LIST *table_list;
+ Field *from_field;
+ SELECT_LEX *last;
+ ref= 0;
+
+ if (!outer_sel || (current_sel->master_unit()->first_select()->linkage ==
+ DERIVED_TABLE_TYPE))
+ {
+ /* 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;
+ }
/*
- We can't find table field in select list of current select,
- consequently we have to find it in outer subselect(s).
- We can't join lists of outer & current select, because of scope
- of view rules. For example if both tables (outer & current) have
- field 'field' it is not mistake to refer to this field without
- mention of table name, but if we join tables in one list it will
- cause error ER_NON_UNIQ_ERROR in find_item_in_list.
+ 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).
+
+ 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.
*/
- for ( ; sl ; sl= (prev_unit= sl->master_unit())->outer_select())
+ 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())
{
- last= sl;
- Item_subselect *prev_subselect_item= prev_unit->item;
- if (sl->resolve_mode == SELECT_LEX::SELECT_MODE &&
- (ref= find_item_in_list(this, sl->item_list,
- &counter, REPORT_EXCEPT_NOT_FOUND,
- &not_used)) !=
- (Item **)not_found_item)
- {
- if (ref && (*ref)->fixed) // Avoid crash in case of error
- {
- prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
- prev_subselect_item->const_item_cache&= (*ref)->const_item();
- }
- break;
- }
- table_list= sl->get_table_list();
- if (sl->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
- {
- // it is primary INSERT st_select_lex => skip first table resolving
- table_list= table_list->next;
- }
+ last= outer_sel;
+ Item_subselect *prev_subselect_item= prev_unit->item;
+
+ /* Search in the SELECT and GROUP lists of the outer select. */
+ if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
+ {
+ 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)
+ {
+ DBUG_ASSERT(*ref && (*ref)->fixed);
+ prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
+ prev_subselect_item->const_item_cache&= (*ref)->const_item();
+ break;
+ }
+ /*
+ Set ref to 0 to ensure that we get an error in case we replaced
+ this item with another item and still use this item in some
+ other place of the parse tree.
+ */
+ 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 subquery used somewhere out of HAVING
- or SELECT list or outer SELECT do not use groupping (i.e. tables
- are accessable)
+ 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:
+ 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 ||
- (sl->with_sum_func == 0 && sl->group_list.elements == 0)) &&
- (tmp= find_field_in_tables(thd, this,
- table_list, &where,
- 0)) != not_found_field)
+ (!outer_sel->with_sum_func &&
+ outer_sel->group_list.elements == 0)))
{
- prev_subselect_item->used_tables_cache|= tmp->table->map;
- prev_subselect_item->const_item_cache= 0;
- break;
+ /*
+ 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,
+ reference,
+ IGNORE_EXCEPT_NON_UNIQUE,
+ TRUE);
+ if (! from_field)
+ return TRUE;
+ if (from_field == view_ref_found)
+ {
+ Item::Type type= (*reference)->type();
+ prev_subselect_item->used_tables_cache|=
+ (*reference)->used_tables();
+ prev_subselect_item->const_item_cache&=
+ (*reference)->const_item();
+ DBUG_ASSERT((*reference)->type() == REF_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, so can quit
+ */
+ return FALSE;
+ }
+ if (from_field != not_found_field)
+ {
+ prev_subselect_item->used_tables_cache|= from_field->table->map;
+ prev_subselect_item->const_item_cache= 0;
+ 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;
+ DBUG_ASSERT(from_field == not_found_field);
- if (sl->master_unit()->first_select()->linkage ==
- DERIVED_TABLE_TYPE)
- break; // do not look over derived table
- }
+ /* Reference is not found => depend on outer (or just error). */
+ prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
+ prev_subselect_item->const_item_cache= 0;
- if (!ref)
- return 1;
- if (!tmp)
- return -1;
- if (ref == (Item **)not_found_item && tmp == not_found_field)
- {
- // We can't say exactly what absend (table or field)
- my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0),
- full_name(), thd->where);
- ref= 0; // Safety
- return 1;
+ if (outer_sel->master_unit()->first_select()->linkage ==
+ DERIVED_TABLE_TYPE)
+ break; /* Do not consider derived tables. */
}
- if (tmp != not_found_field)
+
+ DBUG_ASSERT(from_field != 0 && from_field != view_ref_found);
+ if (from_field != not_found_field)
{
Item_field* fld;
- /*
- Set ref to 0 as we are replacing this item with the found item
- and this will ensure we get an error if this item would be
- used elsewhere
- */
- ref= 0; // Safety
- if (!(fld= new Item_field(tmp)))
- return 1;
- thd->change_item_tree(reference, fld);
- mark_as_dependent(thd, last, thd->lex->current_select, fld);
- return 0;
+ if (!(fld= new Item_field(from_field)))
+ return TRUE;
+ thd->change_item_tree(reference, fld);
+ mark_as_dependent(thd, last, thd->lex->current_select, this, fld);
+ return FALSE;
}
- if (!last->ref_pointer_array[counter])
+ if (ref == 0)
{
- my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
- "forward reference in item list");
- return -1;
+ /* 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;
}
- DBUG_ASSERT((*ref)->fixed);
- mark_as_dependent(thd, last, thd->lex->current_select,
- this);
- if (place == IN_HAVING)
- {
- Item_ref *rf;
- if (!(rf= new Item_direct_ref(last->ref_pointer_array + counter,
- (char *)table_name,
- (char *)field_name)))
- return 1;
- ref= 0; // Safety
- if (rf->fix_fields(thd, tables, ref) || rf->check_cols(1))
- return 1;
- thd->change_item_tree(reference, rf);
- return 0;
- }
- ref= last->ref_pointer_array + counter;
- }
- else if (!ref)
- return 1;
- else
- {
- if (!(*ref)->fixed)
- {
- my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
- "forward reference in item list");
- return -1;
- }
- ref= thd->lex->current_select->ref_pointer_array + counter;
+ /* Should be checked in resolve_ref_in_select_and_group(). */
+ DBUG_ASSERT(*ref && (*ref)->fixed);
+ mark_as_dependent(thd, last, current_sel, this, this);
}
}
+ DBUG_ASSERT(*ref);
/*
- The following conditional is changed as to correctly identify
- incorrect references in group functions or forward references
- with sub-select's / derived tables, while it prevents this
- check when Item_ref is created in an expression involving
- summing function, which is to be placed in the user variable.
+ Check if this is an incorrect reference in a group function or forward
+ reference. Do not issue an error if this is an unnamed reference inside an
+ aggregate function.
*/
if (((*ref)->with_sum_func && name &&
(depended_from ||
- !(thd->lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
- thd->lex->current_select->having_fix_field))) ||
+ !(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
+ current_sel->having_fix_field))) ||
!(*ref)->fixed)
{
- my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
- ((*ref)->with_sum_func?
- "reference on group function":
- "forward reference in item list"));
- return 1;
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0),
+ name, ((*ref)->with_sum_func?
+ "reference to group function":
+ "forward reference in item list"));
+ return TRUE;
}
set_properties();
- if (ref && (*ref)->check_cols(1))
- return 1;
- return 0;
+ if ((*ref)->check_cols(1))
+ return TRUE;
+ return FALSE;
}
+
void Item_ref::set_properties()
{
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
collation.set((*ref)->collation);
+ /*
+ We have to remember if we refer to a sum function, to ensure that
+ split_sum_func() doesn't try to change the reference.
+ */
with_sum_func= (*ref)->with_sum_func;
unsigned_flag= (*ref)->unsigned_flag;
+ if ((*ref)->type() == FIELD_ITEM)
+ alias_name_used= ((Item_ident *) (*ref))->alias_name_used;
+ else
+ alias_name_used= TRUE; // it is not field, so it is was resolved by alias
fixed= 1;
}
+
+void Item_ref::cleanup()
+{
+ DBUG_ENTER("Item_ref::cleanup");
+ Item_ident::cleanup();
+ result_field= 0;
+ DBUG_VOID_RETURN;
+}
+
+
void Item_ref::print(String *str)
{
if (ref && *ref)
@@ -2343,6 +3968,150 @@ void Item_ref::print(String *str)
}
+bool Item_ref::send(Protocol *prot, String *tmp)
+{
+ if (result_field)
+ return prot->store(result_field);
+ return (*ref)->send(prot, tmp);
+}
+
+
+double Item_ref::val_result()
+{
+ if (result_field)
+ {
+ if ((null_value= result_field->is_null()))
+ return 0.0;
+ return result_field->val_real();
+ }
+ return val_real();
+}
+
+
+longlong Item_ref::val_int_result()
+{
+ if (result_field)
+ {
+ if ((null_value= result_field->is_null()))
+ return 0;
+ return result_field->val_int();
+ }
+ return val_int();
+}
+
+
+String *Item_ref::str_result(String* str)
+{
+ if (result_field)
+ {
+ if ((null_value= result_field->is_null()))
+ return 0;
+ str->set_charset(str_value.charset());
+ return result_field->val_str(str, &str_value);
+ }
+ return val_str(str);
+}
+
+
+my_decimal *Item_ref::val_decimal_result(my_decimal *decimal_value)
+{
+ if (result_field)
+ {
+ if ((null_value= result_field->is_null()))
+ return 0;
+ return result_field->val_decimal(decimal_value);
+ }
+ return val_decimal(decimal_value);
+}
+
+
+bool Item_ref::val_bool_result()
+{
+ if (result_field)
+ {
+ if ((null_value= result_field->is_null()))
+ return 0;
+ switch (result_field->result_type()) {
+ case INT_RESULT:
+ return result_field->val_int() != 0;
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *val= result_field->val_decimal(&decimal_value);
+ if (val)
+ return !my_decimal_is_zero(val);
+ return 0;
+ }
+ case REAL_RESULT:
+ case STRING_RESULT:
+ return result_field->val_real() != 0.0;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ return val_bool();
+}
+
+
+double Item_ref::val_real()
+{
+ DBUG_ASSERT(fixed);
+ double tmp=(*ref)->val_result();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+longlong Item_ref::val_int()
+{
+ DBUG_ASSERT(fixed);
+ longlong tmp=(*ref)->val_int_result();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_ref::val_bool()
+{
+ DBUG_ASSERT(fixed);
+ bool tmp= (*ref)->val_bool_result();
+ null_value= (*ref)->null_value;
+ return tmp;
+}
+
+
+String *Item_ref::val_str(String* tmp)
+{
+ DBUG_ASSERT(fixed);
+ tmp=(*ref)->str_result(tmp);
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_ref::is_null()
+{
+ DBUG_ASSERT(fixed);
+ (void) (*ref)->val_int_result();
+ return (*ref)->null_value;
+}
+
+
+bool Item_ref::get_date(TIME *ltime,uint fuzzydate)
+{
+ return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
+}
+
+
+my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
+{
+ my_decimal *val= (*ref)->val_decimal(decimal_value);
+ null_value= (*ref)->null_value;
+ return val;
+}
+
+
void Item_ref_null_helper::print(String *str)
{
str->append("<ref_null_helper>(", 18);
@@ -2354,6 +4123,59 @@ void Item_ref_null_helper::print(String *str)
}
+double Item_direct_ref::val_real()
+{
+ double tmp=(*ref)->val_real();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+longlong Item_direct_ref::val_int()
+{
+ longlong tmp=(*ref)->val_int();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+String *Item_direct_ref::val_str(String* tmp)
+{
+ tmp=(*ref)->val_str(tmp);
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+my_decimal *Item_direct_ref::val_decimal(my_decimal *decimal_value)
+{
+ my_decimal *tmp= (*ref)->val_decimal(decimal_value);
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_direct_ref::val_bool()
+{
+ bool tmp= (*ref)->val_bool();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_direct_ref::is_null()
+{
+ (void) (*ref)->val_int();
+ return (*ref)->null_value;
+}
+
+
+bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate)
+{
+ return (null_value=(*ref)->get_date(ltime,fuzzydate));
+}
+
+
void Item_null_helper::print(String *str)
{
str->append("<null_helper>(", 14);
@@ -2373,35 +4195,43 @@ bool Item_default_value::fix_fields(THD *thd,
struct st_table_list *table_list,
Item **items)
{
+ Item_field *field_arg;
+ Field *def_field;
DBUG_ASSERT(fixed == 0);
+
if (!arg)
{
fixed= 1;
- return 0;
+ return FALSE;
}
if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
- return 1;
+ return TRUE;
if (arg->type() == REF_ITEM)
{
Item_ref *ref= (Item_ref *)arg;
if (ref->ref[0]->type() != FIELD_ITEM)
{
- return 1;
+ return TRUE;
}
arg= ref->ref[0];
}
- Item_field *field_arg= (Item_field *)arg;
- Field *def_field= (Field*) sql_alloc(field_arg->field->size_of());
- if (!def_field)
- return 1;
+ field_arg= (Item_field *)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;
+ }
+ if (!(def_field= (Field*) sql_alloc(field_arg->field->size_of())))
+ return TRUE;
memcpy(def_field, field_arg->field, field_arg->field->size_of());
- def_field->move_field(def_field->table->default_values -
+ def_field->move_field(def_field->table->s->default_values -
def_field->table->record[0]);
set_field(def_field);
- return 0;
+ return FALSE;
}
+
void Item_default_value::print(String *str)
{
if (!arg)
@@ -2414,6 +4244,27 @@ void Item_default_value::print(String *str)
str->append(')');
}
+
+int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
+{
+ if (!arg)
+ {
+ 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);
+ return 1;
+ }
+ field_arg->set_default();
+ return 0;
+ }
+ return Item_field::save_in_field(field_arg, no_conversions);
+}
+
+
bool Item_insert_value::eq(const Item *item, bool binary_cmp) const
{
return item->type() == INSERT_VALUE_ITEM &&
@@ -2427,14 +4278,14 @@ bool Item_insert_value::fix_fields(THD *thd,
{
DBUG_ASSERT(fixed == 0);
if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
- return 1;
+ return TRUE;
if (arg->type() == REF_ITEM)
{
Item_ref *ref= (Item_ref *)arg;
if (ref->ref[0]->type() != FIELD_ITEM)
{
- return 1;
+ return TRUE;
}
arg= ref->ref[0];
}
@@ -2443,7 +4294,7 @@ bool Item_insert_value::fix_fields(THD *thd,
{
Field *def_field= (Field*) sql_alloc(field_arg->field->size_of());
if (!def_field)
- return 1;
+ return TRUE;
memcpy(def_field, field_arg->field, field_arg->field->size_of());
def_field->move_field(def_field->table->insert_values -
def_field->table->record[0]);
@@ -2456,7 +4307,7 @@ bool Item_insert_value::fix_fields(THD *thd,
set_field(new Field_null(0, 0, Field::NONE, tmp_field->field_name,
tmp_field->table, &my_charset_bin));
}
- return 0;
+ return FALSE;
}
void Item_insert_value::print(String *str)
@@ -2466,6 +4317,98 @@ void Item_insert_value::print(String *str)
str->append(')');
}
+
+/*
+ Bind item representing field of row being changed in trigger
+ to appropriate Field object.
+
+ SYNOPSIS
+ setup_field()
+ thd - current thread context
+ table - table of trigger (and where we looking for fields)
+ event - type of trigger event
+
+ NOTE
+ This function does almost the same as fix_fields() for Item_field
+ but is invoked during trigger definition parsing and takes TABLE
+ object as its argument. If proper field was not found in table
+ error will be reported at fix_fields() time.
+*/
+void Item_trigger_field::setup_field(THD *thd, TABLE *table,
+ enum trg_event_type event)
+{
+ uint field_idx= (uint)-1;
+ bool save_set_query_id= thd->set_query_id;
+
+ /* TODO: Think more about consequences of this step. */
+ thd->set_query_id= 0;
+
+ if (find_field_in_real_table(thd, table, field_name,
+ strlen(field_name), 0, 0,
+ &field_idx))
+ {
+ field= (row_version == OLD_ROW && event == TRG_EVENT_UPDATE) ?
+ table->triggers->old_field[field_idx] :
+ table->field[field_idx];
+ }
+
+ thd->set_query_id= save_set_query_id;
+}
+
+
+bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const
+{
+ return item->type() == TRIGGER_FIELD_ITEM &&
+ row_version == ((Item_trigger_field *)item)->row_version &&
+ !my_strcasecmp(system_charset_info, field_name,
+ ((Item_trigger_field *)item)->field_name);
+}
+
+
+bool Item_trigger_field::fix_fields(THD *thd,
+ TABLE_LIST *table_list,
+ Item **items)
+{
+ /*
+ Since trigger is object tightly associated with TABLE object most
+ of its set up can be performed during trigger loading i.e. trigger
+ parsing! So we have little to do in fix_fields. :)
+ FIXME may be we still should bother about permissions here.
+ */
+ DBUG_ASSERT(fixed == 0);
+
+ if (field)
+ {
+ // QQ: May be this should be moved to setup_field?
+ set_field(field);
+ fixed= 1;
+ return 0;
+ }
+
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name,
+ (row_version == NEW_ROW) ? "NEW" : "OLD");
+ return 1;
+}
+
+
+void Item_trigger_field::print(String *str)
+{
+ str->append((row_version == NEW_ROW) ? "NEW" : "OLD", 3);
+ str->append('.');
+ str->append(field_name);
+}
+
+
+void Item_trigger_field::cleanup()
+{
+ /*
+ Since special nature of Item_trigger_field we should not do most of
+ things from Item_field::cleanup() or Item_ident::cleanup() here.
+ */
+ Item::cleanup();
+}
+
+
/*
If item is a const function, calculate it and return a const item
The original item is freed if not returned
@@ -2479,6 +4422,9 @@ Item_result item_cmp_type(Item_result a,Item_result b)
return INT_RESULT;
else if (a == ROW_RESULT || b == ROW_RESULT)
return ROW_RESULT;
+ if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
+ (b == INT_RESULT || b == DECIMAL_RESULT))
+ return DECIMAL_RESULT;
return REAL_RESULT;
}
@@ -2493,7 +4439,8 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
item->result_type());
char *name=item->name; // Alloced by sql_alloc
- if (res_type == STRING_RESULT)
+ switch (res_type) {
+ case STRING_RESULT:
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff),&my_charset_bin),*result;
@@ -2506,22 +4453,40 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
char *tmp_str= sql_strmake(result->ptr(), length);
new_item= new Item_string(name, tmp_str, length, result->charset());
}
+ break;
}
- else if (res_type == INT_RESULT)
+ case INT_RESULT:
{
longlong result=item->val_int();
uint length=item->max_length;
bool null_value=item->null_value;
new_item= (null_value ? (Item*) new Item_null(name) :
(Item*) new Item_int(name, result, length));
+ break;
}
- else
+ case REAL_RESULT:
{ // It must REAL_RESULT
- double result=item->val();
+ double result= item->val_real();
uint length=item->max_length,decimals=item->decimals;
bool null_value=item->null_value;
new_item= (null_value ? (Item*) new Item_null(name) : (Item*)
- new Item_real(name, result, decimals, length));
+ new Item_float(name, result, decimals, length));
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *result= item->val_decimal(&decimal_value);
+ uint length= item->max_length, decimals= item->decimals;
+ bool null_value= item->null_value;
+ new_item= (null_value ?
+ (Item*) new Item_null(name) :
+ (Item*) new Item_decimal(name, result, length, decimals));
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
if (new_item)
thd->change_item_tree(ref, new_item);
@@ -2552,7 +4517,17 @@ bool field_is_equal_to_item(Field *field,Item *item)
}
if (res_type == INT_RESULT)
return 1; // Both where of type int
- double result=item->val();
+ if (res_type == DECIMAL_RESULT)
+ {
+ my_decimal item_buf, *item_val,
+ field_buf, *field_val;
+ item_val= item->val_decimal(&item_buf);
+ if (item->null_value)
+ return 1; // This must be true
+ field_val= field->val_decimal(&field_buf);
+ return !my_decimal_cmp(item_val, field_val);
+ }
+ double result= item->val_real();
if (item->null_value)
return 1;
return result == field->val_real();
@@ -2560,12 +4535,13 @@ bool field_is_equal_to_item(Field *field,Item *item)
Item_cache* Item_cache::get_cache(Item_result type)
{
- switch (type)
- {
+ switch (type) {
case INT_RESULT:
return new Item_cache_int();
case REAL_RESULT:
return new Item_cache_real();
+ case DECIMAL_RESULT:
+ return new Item_cache_decimal();
case STRING_RESULT:
return new Item_cache_str();
case ROW_RESULT:
@@ -2593,6 +4569,23 @@ void Item_cache_int::store(Item *item)
{
value= item->val_int_result();
null_value= item->null_value;
+ unsigned_flag= item->unsigned_flag;
+}
+
+
+String *Item_cache_int::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ str->set(value, default_charset());
+ return str;
+}
+
+
+my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
+ return decimal_val;
}
@@ -2603,6 +4596,68 @@ void Item_cache_real::store(Item *item)
}
+longlong Item_cache_real::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ return (longlong) (value+(value > 0 ? 0.5 : -0.5));
+}
+
+
+String* Item_cache_real::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ str->set(value, decimals, default_charset());
+ return str;
+}
+
+
+my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
+ return decimal_val;
+}
+
+
+void Item_cache_decimal::store(Item *item)
+{
+ my_decimal *val= item->val_decimal_result(&decimal_value);
+ if (!(null_value= item->null_value) && val != &decimal_value)
+ my_decimal2decimal(val, &decimal_value);
+}
+
+double Item_cache_decimal::val_real()
+{
+ DBUG_ASSERT(fixed);
+ double res;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
+ return res;
+}
+
+longlong Item_cache_decimal::val_int()
+{
+ DBUG_ASSERT(fixed);
+ longlong res;
+ my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
+ return res;
+}
+
+String* Item_cache_decimal::val_str(String *str)
+{
+ DBUG_ASSERT(fixed);
+ my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
+ &decimal_value);
+ my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str);
+ return str;
+}
+
+my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed);
+ return &decimal_value;
+}
+
+
void Item_cache_str::store(Item *item)
{
value_buff.set(buffer, sizeof(buffer), item->collation.collation);
@@ -2624,18 +4679,15 @@ void Item_cache_str::store(Item *item)
}
}
-
-double Item_cache_str::val()
+double Item_cache_str::val_real()
{
DBUG_ASSERT(fixed == 1);
- int err;
+ int err_not_used;
+ char *end_not_used;
if (value)
- {
- char *end_not_used;
return my_strntod(value->charset(), (char*) value->ptr(),
- value->length(), &end_not_used, &err);
- }
- return (double)0;
+ value->length(), &end_not_used, &err_not_used);
+ return (double) 0;
}
@@ -2650,6 +4702,16 @@ longlong Item_cache_str::val_int()
return (longlong)0;
}
+my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (value)
+ string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
+ else
+ decimal_val= 0;
+ return decimal_val;
+}
+
bool Item_cache_row::allocate(uint num)
{
@@ -2747,6 +4809,9 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item)
maybe_null= item->maybe_null;
collation.set(item->collation);
get_full_info(item);
+ /* fix variable decimals which always is NOT_FIXED_DEC */
+ if (Field::result_merge_type(fld_type) == INT_RESULT)
+ decimals= 0;
}
@@ -2805,7 +4870,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
break;
}
case FUNC_ITEM:
- if (((Item_func *) item)->functype() == Item_func::VAR_VALUE_FUNC)
+ if (((Item_func *) item)->functype() == Item_func::GUSERVAR_FUNC)
{
/*
There are work around of problem with changing variable type on the
@@ -2821,6 +4886,8 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
return MYSQL_TYPE_LONGLONG;
case REAL_RESULT:
return MYSQL_TYPE_DOUBLE;
+ case DECIMAL_RESULT:
+ return MYSQL_TYPE_NEWDECIMAL;
case ROW_RESULT:
default:
DBUG_ASSERT(0);
@@ -2850,8 +4917,38 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
bool Item_type_holder::join_types(THD *thd, Item *item)
{
- max_length= max(max_length, display_length(item));
+ DBUG_ENTER("Item_type_holder::join_types");
+ DBUG_PRINT("info:", ("was type %d len %d, dec %d name %s",
+ fld_type, max_length, decimals,
+ (name ? name : "<NULL>")));
+ DBUG_PRINT("info:", ("in type %d len %d, dec %d",
+ get_real_type(item),
+ item->max_length, item->decimals));
fld_type= Field::field_type_merge(fld_type, get_real_type(item));
+ {
+ int item_decimals= item->decimals;
+ /* fix variable decimals which always is NOT_FIXED_DEC */
+ if (Field::result_merge_type(fld_type) == INT_RESULT)
+ item_decimals= 0;
+ decimals= max(decimals, item_decimals);
+ }
+ if (Field::result_merge_type(fld_type) == DECIMAL_RESULT)
+ {
+ int item_length= display_length(item);
+ int intp1= item_length - min(item->decimals, NOT_FIXED_DEC - 1);
+ int intp2= max_length - min(decimals, NOT_FIXED_DEC - 1);
+ /* can't be overflow because it work only for decimals (no strings) */
+ int dec_length= max(intp1, intp2) + decimals;
+ max_length= max(max_length, (uint) max(item_length, dec_length));
+ /*
+ we can't allow decimals to be NOT_FIXED_DEC, to prevent creation
+ decimal with max precision (see Field_new_decimal constcuctor)
+ */
+ if (decimals >= NOT_FIXED_DEC)
+ decimals= NOT_FIXED_DEC - 1;
+ }
+ else
+ max_length= max(max_length, display_length(item));
if (Field::result_merge_type(fld_type) == STRING_RESULT)
{
const char *old_cs, *old_derivation;
@@ -2864,13 +4961,14 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
item->collation.collation->name,
item->collation.derivation_name(),
"UNION");
- return TRUE;
+ DBUG_RETURN(TRUE);
}
}
- decimals= max(decimals, item->decimals);
maybe_null|= item->maybe_null;
get_full_info(item);
- return FALSE;
+ DBUG_PRINT("info", ("become type: %d len: %u dec: %u",
+ (int) fld_type, max_length, (uint) decimals));
+ DBUG_RETURN(FALSE);
}
/*
@@ -2898,6 +4996,9 @@ uint32 Item_type_holder::display_length(Item *item)
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
case MYSQL_TYPE_TINY_BLOB:
@@ -2963,10 +5064,6 @@ Field *Item_type_holder::make_field_by_type(TABLE *table)
Field::NONE, name,
table, get_set_pack_length(enum_set_typelib->count),
enum_set_typelib, collation.collation);
- case MYSQL_TYPE_VAR_STRING:
- table->db_create_options|= HA_OPTION_PACK_RECORD;
- return new Field_string(max_length, maybe_null, name, table,
- collation.collation);
default:
break;
}
@@ -3006,7 +5103,7 @@ void Item_type_holder::get_full_info(Item *item)
}
-double Item_type_holder::val()
+double Item_type_holder::val_real()
{
DBUG_ASSERT(0); // should never be called
return 0.0;
@@ -3019,6 +5116,11 @@ longlong Item_type_holder::val_int()
return 0;
}
+my_decimal *Item_type_holder::val_decimal(my_decimal *)
+{
+ DBUG_ASSERT(0); // should never be called
+ return 0;
+}
String *Item_type_holder::val_str(String*)
{
@@ -3042,5 +5144,6 @@ void Item_result_field::cleanup()
template class List<Item>;
template class List_iterator<Item>;
template class List_iterator_fast<Item>;
+template class List_iterator_fast<Item_field>;
template class List<List_item>;
#endif
diff --git a/sql/item.h b/sql/item.h
index d576fbbc60a..850a2d6636d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -22,11 +22,12 @@
class Protocol;
struct st_table_list;
void item_init(void); /* Init item functions */
+class Item_field;
/*
"Declared Type Collation"
- A combination of collation and its deriviation.
+ A combination of collation and its derivation.
*/
enum Derivation
@@ -45,7 +46,7 @@ enum Derivation
MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
(i.e. constant).
MY_COLL_ALLOW_CONV - allow any kind of conversion
- (combintion of the above two)
+ (combination of the above two)
MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE
(e.g. when aggregating for comparison)
MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV
@@ -105,7 +106,124 @@ public:
}
};
+
+/*************************************************************************/
+/*
+ A framework to easily handle different return types for hybrid items
+ (hybrid item is an item whose operand can be of any type, e.g. integer,
+ real, decimal).
+*/
+
+struct Hybrid_type_traits;
+
+struct Hybrid_type
+{
+ longlong integer;
+
+ double real;
+ /*
+ Use two decimal buffers interchangeably to speed up += operation
+ which has no native support in decimal library.
+ Hybrid_type+= arg is implemented as dec_buf[1]= dec_buf[0] + arg.
+ The third decimal is used as a handy temporary storage.
+ */
+ my_decimal dec_buf[3];
+ int used_dec_buf_no;
+
+ /*
+ Traits moved to a separate class to
+ a) be able to easily change object traits in runtime
+ b) they work as a differentiator for the union above
+ */
+ const Hybrid_type_traits *traits;
+
+ Hybrid_type() {}
+ /* XXX: add traits->copy() when needed */
+ Hybrid_type(const Hybrid_type &rhs) :traits(rhs.traits) {}
+};
+
+
+/* Hybryd_type_traits interface + default implementation for REAL_RESULT */
+
+struct Hybrid_type_traits
+{
+ virtual Item_result type() const { return REAL_RESULT; }
+
+ virtual void
+ fix_length_and_dec(Item *item, Item *arg) const;
+
+ /* Hybrid_type operations. */
+ virtual void set_zero(Hybrid_type *val) const { val->real= 0.0; }
+ virtual void add(Hybrid_type *val, Field *f) const
+ { val->real+= f->val_real(); }
+ virtual void div(Hybrid_type *val, ulonglong u) const
+ { val->real/= ulonglong2double(u); }
+
+ virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const
+ { return (longlong) val->real; }
+ virtual double val_real(Hybrid_type *val) const { return val->real; }
+ virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const;
+ virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
+ static const Hybrid_type_traits *instance();
+};
+
+
+struct Hybrid_type_traits_decimal: public Hybrid_type_traits
+{
+ virtual Item_result type() const { return DECIMAL_RESULT; }
+
+ virtual void
+ fix_length_and_dec(Item *arg, Item *item) const;
+
+ /* Hybrid_type operations. */
+ virtual void set_zero(Hybrid_type *val) const;
+ virtual void add(Hybrid_type *val, Field *f) const;
+ virtual void div(Hybrid_type *val, ulonglong u) const;
+
+ virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const;
+ virtual double val_real(Hybrid_type *val) const;
+ virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
+ { return &val->dec_buf[val->used_dec_buf_no]; }
+ virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
+ static const Hybrid_type_traits_decimal *instance();
+};
+
+
+struct Hybrid_type_traits_integer: public Hybrid_type_traits
+{
+ virtual Item_result type() const { return INT_RESULT; }
+
+ virtual void
+ fix_length_and_dec(Item *arg, Item *item) const;
+
+ /* Hybrid_type operations. */
+ virtual void set_zero(Hybrid_type *val) const
+ { val->integer= 0; }
+ virtual void add(Hybrid_type *val, Field *f) const
+ { val->integer+= f->val_int(); }
+ virtual void div(Hybrid_type *val, ulonglong u) const
+ { val->integer/= (longlong) u; }
+
+ virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const
+ { return val->integer; }
+ virtual double val_real(Hybrid_type *val) const
+ { return (double) val->integer; }
+ virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
+ {
+ int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, &val->dec_buf[2]);
+ return &val->dec_buf[2];
+ }
+ virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const
+ { buf->set(val->integer, &my_charset_bin); return buf;}
+ static const Hybrid_type_traits_integer *instance();
+};
+
+/*************************************************************************/
+
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 */
@@ -114,18 +232,20 @@ public:
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); }
- static void operator delete(void *ptr,size_t size) {}
+ static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
- enum Type {FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM,
+ enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM,
INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM,
COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM,
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};
+ PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
+
+ enum traverse_order { POSTFIX, PREFIX };
/*
str_values's main purpose is to be used to cache the value in
@@ -133,8 +253,11 @@ public:
*/
String str_value;
my_string name; /* Name from select */
+ /* Original item name (if it was renamed)*/
+ my_string orig_name;
Item *next;
uint32 max_length;
+ uint name_length; /* Length of name */
uint8 marker,decimals;
my_bool maybe_null; /* If item may be null */
my_bool null_value; /* if item is null */
@@ -146,26 +269,24 @@ public:
// alloc & destruct is done as start of select using sql_alloc
Item();
/*
- Constructor used by Item_field, Item_ref & agregate (sum) functions.
+ Constructor used by Item_field, Item_ref & aggregate (sum) functions.
Used for duplicating lists in processing queries with temporary
tables
Also it used for Item_cond_and/Item_cond_or for creating
- top AND/OR ctructure of WHERE clause to protect it of
+ top AND/OR structure of WHERE clause to protect it of
optimisation changes in prepared statements
*/
Item(THD *thd, Item *item);
- virtual ~Item() { name=0; } /*lint -e1509 */
+ virtual ~Item()
+ {
+ name=0;
+ } /*lint -e1509 */
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()
- {
- DBUG_ENTER("Item::cleanup");
- DBUG_PRINT("info", ("Type: %d", (int)type()));
- fixed=0;
- marker= 0;
- DBUG_VOID_RETURN;
- }
+ 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 **);
/*
should be used in case where we are sure that we do not need
@@ -173,6 +294,7 @@ public:
*/
inline void quick_fix_field() { fixed= 1; }
/* Function returns 1 on overflow and -1 on fatal errors */
+ int save_in_field_no_warnings(Field *field, bool no_conversions);
virtual int save_in_field(Field *field, bool no_conversions);
virtual void save_org_in_field(Field *field)
{ (void) save_in_field(field, 1); }
@@ -185,40 +307,117 @@ public:
virtual enum_field_types field_type() const;
virtual enum Type type() const =0;
/* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */
- virtual double val()=0;
+ /*
+ Return double precision floating point representation of item.
+
+ SYNOPSIS
+ val_real()
+
+ RETURN
+ In case of NULL value return 0.0 and set null_value flag to TRUE.
+ If value is not null null_value flag will be reset to FALSE.
+ */
+ virtual double val_real()=0;
+ /*
+ Return integer representation of item.
+
+ SYNOPSIS
+ val_int()
+
+ RETURN
+ In case of NULL value return 0 and set null_value flag to TRUE.
+ If value is not null null_value flag will be reset to FALSE.
+ */
virtual longlong val_int()=0;
/*
Return string representation of this item object.
- The argument to val_str() is an allocated buffer this or any
- nested Item object can use to store return value of this method.
- This buffer should only be used if the item itself doesn't have an
- own String buffer. In case when the item maintains it's own string
- buffer, it's preferrable to return it instead to minimize number of
- mallocs/memcpys.
- The caller of this method can modify returned string, but only in
- case when it was allocated on heap, (is_alloced() is true). This
- allows the caller to efficiently use a buffer allocated by a child
- without having to allocate a buffer of it's own. The buffer, given
- to val_str() as agrument, belongs to the caller and is later used
- by the caller at it's own choosing.
- A few implications from the above:
- - unless you return a string object which only points to your buffer
- but doesn't manages it you should be ready that it will be
- modified.
- - even for not allocated strings (is_alloced() == false) the caller
- can change charset (see Item_func_{typecast/binary}. XXX: is this
- a bug?
- - still you should try to minimize data copying and return internal
- object whenever possible.
+ SYNOPSIS
+ val_str()
+ str an allocated buffer this or any nested Item object can use to
+ store return value of this method.
+
+ NOTE
+ Buffer passed via argument should only be used if the item itself
+ doesn't have an own String buffer. In case when the item maintains
+ it's own string buffer, it's preferable to return it instead to
+ minimize number of mallocs/memcpys.
+ The caller of this method can modify returned string, but only in case
+ when it was allocated on heap, (is_alloced() is true). This allows
+ the caller to efficiently use a buffer allocated by a child without
+ having to allocate a buffer of it's own. The buffer, given to
+ val_str() as argument, belongs to the caller and is later used by the
+ caller at it's own choosing.
+ A few implications from the above:
+ - unless you return a string object which only points to your buffer
+ but doesn't manages it you should be ready that it will be
+ modified.
+ - even for not allocated strings (is_alloced() == false) the caller
+ can change charset (see Item_func_{typecast/binary}. XXX: is this
+ a bug?
+ - still you should try to minimize data copying and return internal
+ object whenever possible.
+
+ RETURN
+ In case of NULL value return 0 (NULL pointer) and set null_value flag
+ to TRUE.
+ If value is not null null_value flag will be reset to FALSE.
+ */
+ virtual String *val_str(String *str)=0;
+ /*
+ Return decimal representation of item with fixed point.
+
+ SYNOPSIS
+ val_decimal()
+ decimal_buffer buffer which can be used by Item for returning value
+ (but can be not)
+
+ NOTE
+ Returned value should not be changed if it is not the same which was
+ passed via argument.
+
+ RETURN
+ Return pointer on my_decimal (it can be other then passed via argument)
+ if value is not NULL (null_value flag will be reset to FALSE).
+ In case of NULL value it return 0 pointer and set null_value flag
+ to TRUE.
+ */
+ virtual my_decimal *val_decimal(my_decimal *decimal_buffer)= 0;
+ /*
+ Return boolean value of item.
+
+ RETURN
+ FALSE value is false or NULL
+ TRUE value is true (not equal to 0)
*/
- virtual String *val_str(String*)=0;
+ virtual bool val_bool();
+ /* Helper functions, see item_sum.cc */
+ String *val_string_from_real(String *str);
+ String *val_string_from_int(String *str);
+ String *val_string_from_decimal(String *str);
+ my_decimal *val_decimal_from_real(my_decimal *decimal_value);
+ my_decimal *val_decimal_from_int(my_decimal *decimal_value);
+ my_decimal *val_decimal_from_string(my_decimal *decimal_value);
+ longlong val_int_from_decimal();
+ double val_real_from_decimal();
+
virtual Field *get_tmp_table_field() { return 0; }
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; }
- virtual double val_result() { return val(); }
+
+ /*
+ *result* family of methods is analog of *val* family (see above) but
+ return value of result_field of item if it is present. If Item have not
+ result field, it return val(). This methods set null_value flag in same
+ way as *val* methods do it.
+ */
+ virtual double val_result() { return val_real(); }
virtual longlong val_int_result() { return val_int(); }
virtual String *str_result(String* tmp) { return val_str(tmp); }
+ virtual my_decimal *val_decimal_result(my_decimal *val)
+ { return val_decimal(val); }
+ virtual bool val_bool_result() { return val_bool(); }
+
/* bit map of tables used by item */
virtual table_map used_tables() const { return (table_map) 0L; }
/*
@@ -282,14 +481,14 @@ public:
virtual void top_level_item() {}
/*
set field of temporary table for Item which can be switched on temporary
- table during query processing (groupping and so on)
+ table during query processing (grouping and so on)
*/
virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; }
virtual bool is_bool_func() { return 0; }
virtual void save_in_result_field(bool no_conversions) {}
/*
- set value of aggegate function in case of no rows for groupping were found
+ set value of aggregate function in case of no rows for grouping were found
*/
virtual void no_rows_in_result() {}
virtual Item *copy_or_same(THD *thd) { return this; }
@@ -305,9 +504,28 @@ public:
return (this->*processor)(arg);
}
+ virtual Item* transform(Item_transformer transformer, byte *arg)
+ {
+ return (this->*transformer)(arg);
+ }
+
+ virtual void traverse_cond(Cond_traverser traverser,
+ void *arg, traverse_order order)
+ {
+ (*traverser)(this, arg);
+ }
+
virtual bool remove_dependence_processor(byte * arg) { return 0; }
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 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; }
+ virtual Item *this_item() { return this; } /* For SPs mostly. */
+ virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
+
// Row emulation
virtual uint cols() { return 1; }
virtual Item* el(uint i) { return this; }
@@ -319,6 +537,7 @@ public:
virtual void bring_value() {}
Field *tmp_table_field_from_field_type(TABLE *table);
+ virtual Item_field *filed_for_view_update() { return 0; }
virtual Item *neg_transformer(THD *thd) { return NULL; }
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
@@ -327,6 +546,81 @@ public:
cleanup();
delete this;
}
+
+ virtual bool is_splocal() { return 0; } /* Needed for error checking */
+};
+
+
+// A local SP variable (incl. parameters), used in runtime
+class Item_splocal : public Item
+{
+private:
+
+ uint m_offset;
+ LEX_STRING m_name;
+
+public:
+
+ Item_splocal(LEX_STRING name, uint offset)
+ : m_offset(offset), m_name(name)
+ {
+ Item::maybe_null= TRUE;
+ }
+
+ bool is_splocal() { return 1; } /* Needed for error checking */
+
+ Item *this_item();
+ Item *this_const_item() const;
+
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ void cleanup();
+
+ inline uint get_offset()
+ {
+ return m_offset;
+ }
+
+ // Abstract methods inherited from Item. Just defer the call to
+ // the item in the frame
+ enum Type type() const;
+
+ double val_real();
+ longlong val_int();
+ String *val_str(String *sp);
+ my_decimal *val_decimal(my_decimal *);
+ bool is_null();
+ void print(String *str);
+
+ inline void make_field(Send_field *field)
+ {
+ Item *it= this_item();
+
+ if (name)
+ it->set_name(name, strlen(name), system_charset_info);
+ else
+ it->set_name(m_name.str, m_name.length, system_charset_info);
+ it->make_field(field);
+ }
+
+ inline Item_result result_type() const
+ {
+ return this_const_item()->result_type();
+ }
+
+ inline bool const_item() const
+ {
+ return TRUE;
+ }
+
+ inline int save_in_field(Field *field, bool no_conversions)
+ {
+ return this_item()->save_in_field(field, no_conversions);
+ }
+
+ inline bool send(Protocol *protocol, String *str)
+ {
+ return this_item()->send(protocol, str);
+ }
};
@@ -355,6 +649,7 @@ public:
const char *db_name;
const char *table_name;
const char *field_name;
+ bool alias_name_used; /* true if item was resolved against alias */
/*
Cached value of index for this field in table->field array, used by prep.
stmts for speeding up their re-execution. Holds NO_CACHED_FIELD_INDEX
@@ -374,19 +669,37 @@ public:
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);
};
+class Item_equal;
+class COND_EQUAL;
class Item_field :public Item_ident
{
+protected:
void set_field(Field *field);
public:
Field *field,*result_field;
+ Item_equal *item_equal;
+ bool no_const_subst;
+ /*
+ if any_privileges set to TRUE then here real effective privileges will
+ be stored
+ */
+ uint have_privileges;
+ /* 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)
+ field(0), result_field(0), item_equal(0), no_const_subst(0),
+ have_privileges(0), any_privileges(0)
{ collation.set(DERIVATION_IMPLICIT); }
/*
Constructor needed to process subselect with temporary tables (see Item)
@@ -406,12 +719,15 @@ public:
Item_field(Field *field);
enum Type type() const { return FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
- double val();
+ double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
+ my_decimal *val_decimal_result(my_decimal *);
+ 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 **);
@@ -438,8 +754,15 @@ public:
bool get_time(TIME *ltime);
bool is_null() { return field->is_null(); }
Item *get_tmp_table_item(THD *thd);
+ bool collect_item_field_processor(byte * arg);
void cleanup();
+ Item_equal *find_item_equal(COND_EQUAL *cond_equal);
+ Item *equal_fields_propagator(byte *arg);
+ Item *set_no_const_sub(byte *arg);
+ Item *replace_equal_field(byte *arg);
inline uint32 max_disp_length() { return field->max_length(); }
+ Item_field *filed_for_view_update() { return this; }
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
friend class Item_default_value;
friend class Item_insert_value;
friend class st_select_lex_unit;
@@ -458,15 +781,16 @@ public:
}
enum Type type() const { return NULL_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
- double val();
+ double val_real();
longlong val_int();
String *val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
int save_in_field(Field *field, bool no_conversions);
int save_safe_in_field(Field *field);
bool send(Protocol *protocol, String *str);
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
- // to prevent drop fixed flag (no need parent cleanup call)
+ /* to prevent drop fixed flag (no need parent cleanup call) */
void cleanup() {}
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_null(name); }
@@ -495,7 +819,8 @@ public:
enum enum_item_param_state
{
NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE,
- STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE
+ STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE,
+ DECIMAL_VALUE
} state;
/*
@@ -509,6 +834,7 @@ public:
Can not be declared inside the union as it's not a POD type.
*/
String str_value_ptr;
+ my_decimal decimal_value;
union
{
longlong integer;
@@ -558,8 +884,9 @@ public:
enum Type type() const { return item_type; }
enum_field_types field_type() const { return param_type; }
- double val();
+ double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal*);
String *val_str(String*);
bool get_time(TIME *tm);
bool get_date(TIME *tm, uint fuzzydate);
@@ -569,6 +896,7 @@ public:
void set_null();
void set_int(longlong i, uint32 max_length_arg);
void set_double(double i);
+ void set_decimal(const char *str, ulong length);
bool set_str(const char *str, ulong length);
bool set_longdata(const char *str, ulong length);
void set_time(TIME *tm, timestamp_type type, uint32 max_length_arg);
@@ -594,7 +922,7 @@ public:
*/
virtual table_map used_tables() const
{ return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; }
- void print(String *str) { str->append('?'); }
+ void print(String *str);
/* parameter never equal to other parameter of other item */
bool eq(const Item *item, bool binary_cmp) const { return 0; }
bool is_null()
@@ -618,7 +946,8 @@ public:
enum Item_result result_type () const { return INT_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
- double val() { DBUG_ASSERT(fixed == 1); return (double) value; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
+ my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
@@ -630,13 +959,24 @@ public:
};
+class Item_static_int_func :public Item_int
+{
+ const char *func_name;
+public:
+ Item_static_int_func(const char *str_arg, longlong i, uint length)
+ :Item_int(NullS, i, length), func_name(str_arg)
+ {}
+ void print(String *str) { str->append(func_name); }
+};
+
+
class Item_uint :public Item_int
{
public:
Item_uint(const char *str_arg, uint length);
Item_uint(uint32 i) :Item_int((longlong) i, 10)
{ unsigned_flag= 1; }
- double val()
+ double val_real()
{ DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); }
String *val_str(String*);
Item *new_item() { return new Item_uint(name,max_length); }
@@ -646,55 +986,94 @@ public:
};
-class Item_real :public Item_num
+/* decimal (fixed point) constant */
+class Item_decimal :public Item_num
{
+protected:
+ my_decimal decimal_value;
public:
- double value;
- // Item_real() :value(0) {}
- Item_real(const char *str_arg, uint length) :value(my_atof(str_arg))
+ Item_decimal(const char *str_arg, uint length, CHARSET_INFO *charset);
+ Item_decimal(const char *str, const my_decimal *val_arg,
+ uint decimal_par, uint length);
+ Item_decimal(my_decimal *value_par);
+ Item_decimal(longlong val, bool unsig);
+ Item_decimal(double val, int precision, int scale);
+ Item_decimal(const char *bin, int precision, int scale);
+
+ enum Type type() const { return DECIMAL_ITEM; }
+ enum Item_result result_type () const { return DECIMAL_RESULT; }
+ enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
+ longlong val_int();
+ double val_real();
+ String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *val) { return &decimal_value; }
+ int save_in_field(Field *field, bool no_conversions);
+ bool basic_const_item() const { return 1; }
+ Item *new_item()
{
- name=(char*) str_arg;
- decimals=(uint8) nr_of_decimals(str_arg);
- max_length=length;
- fixed= 1;
+ return new Item_decimal(name, &decimal_value, decimals, max_length);
}
- Item_real(const char *str,double val_arg,uint decimal_par,uint length)
+ // to prevent drop fixed flag (no need parent cleanup call)
+ void cleanup() {}
+ void print(String *str);
+ Item_num *neg()
+ {
+ my_decimal_neg(&decimal_value);
+ unsigned_flag= !decimal_value.sign();
+ return this;
+ }
+};
+
+class Item_float :public Item_num
+{
+ char *presentation;
+public:
+ double value;
+ // Item_real() :value(0) {}
+ Item_float(const char *str_arg, uint length);
+ Item_float(const char *str,double val_arg,uint decimal_par,uint length)
:value(val_arg)
{
- name=(char*) str;
+ presentation= name=(char*) str;
decimals=(uint8) decimal_par;
max_length=length;
fixed= 1;
}
- Item_real(double value_par) :value(value_par) { fixed= 1; }
+ Item_float(double value_par) :presentation(0), value(value_par) { fixed= 1; }
+
int save_in_field(Field *field, bool no_conversions);
enum Type type() const { return REAL_ITEM; }
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
- double val() { DBUG_ASSERT(fixed == 1); return value; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return value; }
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
return (longlong) (value+(value > 0 ? 0.5 : -0.5));
}
String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
bool basic_const_item() const { return 1; }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
- Item *new_item() { return new Item_real(name,value,decimals,max_length); }
+ Item *new_item()
+ { return new Item_float(name, value, decimals, max_length); }
Item_num *neg() { value= -value; return this; }
+ void print(String *str);
};
-class Item_float :public Item_real
+class Item_static_float_func :public Item_float
{
+ const char *func_name;
public:
- Item_float(const char *str,uint length) :Item_real(str,length)
- {
- decimals=NOT_FIXED_DEC;
- max_length=DBL_DIG+8;
- }
+ Item_static_float_func(const char *str, double val_arg, uint decimal_par,
+ uint length)
+ :Item_float(NullS, val_arg, decimal_par, length), func_name(str)
+ {}
+ void print(String *str) { str->append(func_name); }
};
+
class Item_string :public Item
{
public:
@@ -728,29 +1107,17 @@ public:
fixed= 1;
}
enum Type type() const { return STRING_ITEM; }
- double val()
- {
- DBUG_ASSERT(fixed == 1);
- int err;
- char *end_not_used;
- return my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(), &end_not_used, &err);
- }
- longlong val_int()
- {
- DBUG_ASSERT(fixed == 1);
- int err;
- return my_strntoll(str_value.charset(), str_value.ptr(),
- str_value.length(), 10, (char**) 0, &err);
- }
+ double val_real();
+ longlong val_int();
String *val_str(String*)
{
DBUG_ASSERT(fixed == 1);
return (String*) &str_value;
}
+ my_decimal *val_decimal(my_decimal *);
int save_in_field(Field *field, bool no_conversions);
enum Item_result result_type () const { return STRING_RESULT; }
- enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
+ enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
bool basic_const_item() const { return 1; }
bool eq(const Item *item, bool binary_cmp) const;
Item *new_item()
@@ -766,13 +1133,27 @@ public:
void cleanup() {}
};
+
+class Item_static_string_func :public Item_string
+{
+ const char *func_name;
+public:
+ Item_static_string_func(const char *name_par, const char *str, uint length,
+ CHARSET_INFO *cs,
+ Derivation dv= DERIVATION_COERCIBLE)
+ :Item_string(NullS, str, length, cs, dv), func_name(name_par)
+ {}
+ void print(String *str) { str->append(func_name); }
+};
+
+
/* for show tables */
class Item_datetime :public Item_string
{
public:
Item_datetime(const char *item_name): Item_string(item_name,"",0,
- &my_charset_bin)
+ &my_charset_bin)
{ max_length=19;}
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
};
@@ -800,24 +1181,32 @@ public:
};
-class Item_varbinary :public Item
+class Item_hex_string: public Item
{
public:
- Item_varbinary(const char *str,uint str_length);
+ Item_hex_string(): Item() {}
+ Item_hex_string(const char *str,uint str_length);
enum Type type() const { return VARBIN_ITEM; }
- double val()
- { DBUG_ASSERT(fixed == 1); return (double) Item_varbinary::val_int(); }
+ double val_real()
+ { DBUG_ASSERT(fixed == 1); return (double) Item_hex_string::val_int(); }
longlong val_int();
bool basic_const_item() const { return 1; }
String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
+ my_decimal *val_decimal(my_decimal *);
int save_in_field(Field *field, bool no_conversions);
enum Item_result result_type () const { return STRING_RESULT; }
- enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
+ enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
};
+class Item_bin_string: public Item_hex_string
+{
+public:
+ Item_bin_string(const char *str,uint str_length);
+};
+
class Item_result_field :public Item /* Item with result field */
{
public:
@@ -851,7 +1240,7 @@ public:
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), ref(0) {}
+ :Item_ident(db_par, table_name_par, field_name_par), result_field(0), ref(0) {}
/*
This constructor is used in two scenarios:
A) *item = NULL
@@ -866,52 +1255,26 @@ 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_ident(NullS, table_name_par, field_name_par), ref(item)
- {
- DBUG_ASSERT(item);
- if (*item)
- set_properties();
- }
+ Item_ref(Item **item, const char *table_name_par, const char *field_name_par);
/* Constructor need to process subselect with temporary tables (see Item) */
- Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), 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); }
- double val()
- {
- DBUG_ASSERT(fixed);
- double tmp=(*ref)->val_result();
- null_value=(*ref)->null_value;
- return tmp;
- }
- longlong val_int()
- {
- DBUG_ASSERT(fixed);
- longlong tmp=(*ref)->val_int_result();
- null_value=(*ref)->null_value;
- return tmp;
- }
- String *val_str(String* tmp)
- {
- DBUG_ASSERT(fixed);
- tmp=(*ref)->str_result(tmp);
- null_value=(*ref)->null_value;
- return tmp;
- }
- bool is_null()
- {
- DBUG_ASSERT(fixed);
- (void) (*ref)->val_int_result();
- return (*ref)->null_value;
- }
- bool get_date(TIME *ltime,uint fuzzydate)
- {
- DBUG_ASSERT(fixed);
- return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
- }
- bool send(Protocol *prot, String *tmp){ return (*ref)->send(prot, tmp); }
+ double val_real();
+ longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
+ String *val_str(String* tmp);
+ bool is_null();
+ bool get_date(TIME *ltime,uint fuzzydate);
+ double val_result();
+ longlong val_int_result();
+ String *str_result(String* tmp);
+ 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)
@@ -931,7 +1294,10 @@ public:
(*ref)->save_in_field(result_field, no_conversions);
}
Item *real_item() { return *ref; }
+ bool walk(Item_processor processor, byte *arg)
+ { return (*ref)->walk(processor, arg); }
void print(String *str);
+ void cleanup();
};
@@ -948,33 +1314,13 @@ public:
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
- double val()
- {
- double tmp=(*ref)->val();
- null_value=(*ref)->null_value;
- return tmp;
- }
- longlong val_int()
- {
- longlong tmp=(*ref)->val_int();
- null_value=(*ref)->null_value;
- return tmp;
- }
- String *val_str(String* tmp)
- {
- tmp=(*ref)->val_str(tmp);
- null_value=(*ref)->null_value;
- return tmp;
- }
- bool is_null()
- {
- (void) (*ref)->val_int();
- return (*ref)->null_value;
- }
- bool get_date(TIME *ltime,uint fuzzydate)
- {
- return (null_value=(*ref)->get_date(ltime,fuzzydate));
- }
+ double val_real();
+ longlong val_int();
+ String *val_str(String* tmp);
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
+ bool is_null();
+ bool get_date(TIME *ltime,uint fuzzydate);
};
@@ -988,9 +1334,11 @@ 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) {}
- double val();
+ double val_real();
longlong val_int();
String* val_str(String* s);
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
bool get_date(TIME *ltime, uint fuzzydate);
void print(String *str);
};
@@ -1001,7 +1349,8 @@ class Item_null_helper :public Item_ref_null_helper
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, &item, table_name_par, field_name_par),
+ :Item_ref_null_helper(master, (store= 0, &store), table_name_par,
+ field_name_par),
store(item)
{ ref= &store; }
void print(String *str);
@@ -1063,13 +1412,13 @@ public:
enum Type type() const { return COPY_STR_ITEM; }
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return cached_field_type; }
- double val()
+ double val_real()
{
- int err;
+ int err_not_used;
char *end_not_used;
return (null_value ? 0.0 :
my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(), &end_not_used, &err));
+ str_value.length(), &end_not_used, &err_not_used));
}
longlong val_int()
{
@@ -1077,6 +1426,7 @@ public:
return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err);
}
String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
void make_field(Send_field *field) { item->make_field(field); }
void copy();
int save_in_field(Field *field, bool no_conversions);
@@ -1125,6 +1475,15 @@ public:
};
+class Item_decimal_buff :public Item_buff
+{
+ Item *item;
+ my_decimal value;
+public:
+ Item_decimal_buff(Item *item_par);
+ bool cmp(void);
+};
+
class Item_field_buff :public Item_buff
{
char *buff;
@@ -1152,15 +1511,7 @@ public:
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, struct st_table_list *, Item **);
void print(String *str);
- int save_in_field(Field *field_arg, bool no_conversions)
- {
- if (!arg)
- {
- field_arg->set_default();
- return 0;
- }
- return Item_field::save_in_field(field_arg, no_conversions);
- }
+ int save_in_field(Field *field_arg, bool no_conversions);
table_map used_tables() const { return (table_map)0L; }
bool walk(Item_processor processor, byte *args)
@@ -1168,6 +1519,19 @@ public:
return arg->walk(processor, args) ||
(this->*processor)(args);
}
+
+ /*
+ This method like the walk method traverses the item tree, but
+ at the same time it can replace some nodes in the tree
+ */
+ Item *transform(Item_transformer transformer, byte *args)
+ {
+ Item *new_item= arg->transform(transformer, args);
+ if (!new_item)
+ return 0;
+ arg= new_item;
+ return (this->*transformer)(args);
+ }
};
class Item_insert_value : public Item_field
@@ -1192,6 +1556,59 @@ public:
}
};
+
+/*
+ We need this two enums here instead of sql_lex.h because
+ at least one of them is used by Item_trigger_field interface.
+
+ Time when trigger is invoked (i.e. before or after row actually
+ inserted/updated/deleted).
+*/
+enum trg_action_time_type
+{
+ TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1
+};
+
+/*
+ Event on which trigger is invoked.
+*/
+enum trg_event_type
+{
+ TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2
+};
+
+/*
+ Represents NEW/OLD version of field of row which is
+ changed/read in trigger.
+
+ Note: For this item actual binding to Field object happens not during
+ fix_fields() (like for Item_field) but during parsing of trigger
+ definition, when table is opened, with special setup_field() call.
+*/
+class Item_trigger_field : public Item_field
+{
+public:
+ /* Is this item represents row from NEW or OLD row ? */
+ enum row_version_type {OLD_ROW, NEW_ROW};
+ row_version_type row_version;
+ /* Next in list of all Item_trigger_field's in trigger */
+ Item_trigger_field *next_trg_field;
+
+ 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)
+ {}
+ void setup_field(THD *thd, TABLE *table, enum trg_event_type event);
+ 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 **);
+ void print(String *str);
+ table_map used_tables() const { return (table_map)0L; }
+ void cleanup();
+};
+
+
class Item_cache: public Item
{
protected:
@@ -1221,24 +1638,23 @@ public:
void print(String *str);
};
+
class Item_cache_int: public Item_cache
{
+protected:
longlong value;
public:
Item_cache_int(): Item_cache(), value(0) {}
-
+
void store(Item *item);
- double val() { DBUG_ASSERT(fixed == 1); return (double) value; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
- String* val_str(String *str)
- {
- DBUG_ASSERT(fixed == 1);
- str->set(value, default_charset());
- return str;
- }
+ String* val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return INT_RESULT; }
};
+
class Item_cache_real: public Item_cache
{
double value;
@@ -1246,31 +1662,42 @@ public:
Item_cache_real(): Item_cache(), value(0) {}
void store(Item *item);
- double val() { DBUG_ASSERT(fixed == 1); return value; }
- longlong val_int()
- {
- DBUG_ASSERT(fixed == 1);
- return (longlong) (value+(value > 0 ? 0.5 : -0.5));
- }
- String* val_str(String *str)
- {
- str->set(value, decimals, default_charset());
- return str;
- }
+ double val_real() { DBUG_ASSERT(fixed == 1); return value; }
+ longlong val_int();
+ String* val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return REAL_RESULT; }
};
+
+class Item_cache_decimal: public Item_cache
+{
+protected:
+ my_decimal decimal_value;
+public:
+ Item_cache_decimal(): Item_cache() {}
+
+ void store(Item *item);
+ double val_real();
+ longlong val_int();
+ String* val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
+ enum Item_result result_type() const { return DECIMAL_RESULT; }
+};
+
+
class Item_cache_str: public Item_cache
{
- char buffer[80];
+ char buffer[STRING_BUFFER_USUAL_SIZE];
String *value, value_buff;
public:
Item_cache_str(): Item_cache(), value(0) { }
-
+
void store(Item *item);
- double val();
+ double val_real();
longlong val_int();
String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; }
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return STRING_RESULT; }
CHARSET_INFO *charset() const { return value->charset(); };
};
@@ -1300,7 +1727,7 @@ public:
{
illegal_method_call((const char*)"make_field");
};
- double val()
+ double val_real()
{
illegal_method_call((const char*)"val");
return 0;
@@ -1315,6 +1742,12 @@ public:
illegal_method_call((const char*)"val_str");
return 0;
};
+ my_decimal *val_decimal(my_decimal *val)
+ {
+ illegal_method_call((const char*)"val_decimal");
+ return 0;
+ };
+
enum Item_result result_type() const { return ROW_RESULT; }
uint cols() { return item_count; }
@@ -1357,8 +1790,9 @@ public:
Item_result result_type() const;
virtual enum_field_types field_type() const { return fld_type; };
enum Type type() const { return TYPE_HOLDER; }
- double val();
+ double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
bool join_types(THD *thd, Item *);
Field *make_field_by_type(TABLE *table);
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index 1559cfe958e..af17d377e31 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -28,11 +28,20 @@ Item_buff *new_Item_buff(Item *item)
if (item->type() == Item::FIELD_ITEM &&
!(((Item_field *) item)->field->flags & BLOB_FLAG))
return new Item_field_buff((Item_field *) item);
- if (item->result_type() == STRING_RESULT)
+ switch (item->result_type()) {
+ case STRING_RESULT:
return new Item_str_buff((Item_field *) item);
- if (item->result_type() == INT_RESULT)
+ case INT_RESULT:
return new Item_int_buff((Item_field *) item);
- return new Item_real_buff(item);
+ case REAL_RESULT:
+ return new Item_real_buff(item);
+ case DECIMAL_RESULT:
+ return new Item_decimal_buff(item);
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return 0;
+ }
}
Item_buff::~Item_buff() {}
@@ -70,7 +79,7 @@ Item_str_buff::~Item_str_buff()
bool Item_real_buff::cmp(void)
{
- double nr=item->val();
+ double nr= item->val_real();
if (null_value != item->null_value || nr != value)
{
null_value= item->null_value;
@@ -107,6 +116,27 @@ bool Item_field_buff::cmp(void)
}
+Item_decimal_buff::Item_decimal_buff(Item *it)
+ :item(it)
+{
+ my_decimal_set_zero(&value);
+}
+
+
+bool Item_decimal_buff::cmp()
+{
+ my_decimal tmp;
+ my_decimal *ptmp= item->val_decimal(&tmp);
+ if (null_value != item->null_value || my_decimal_cmp(&value, ptmp) == 0)
+ {
+ null_value= item->null_value;
+ my_decimal2decimal(ptmp, &value);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
/*****************************************************************************
** Instansiate templates
*****************************************************************************/
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 8498ab4800e..66354560756 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -31,6 +31,8 @@ static Item_result item_store_type(Item_result a,Item_result b)
return STRING_RESULT;
else if (a == REAL_RESULT || b == REAL_RESULT)
return REAL_RESULT;
+ else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT)
+ return DECIMAL_RESULT;
else
return INT_RESULT;
}
@@ -51,12 +53,13 @@ static void agg_cmp_type(Item_result *type, Item **items, uint nitems)
type[0]= item_cmp_type(type[0], items[i]->result_type());
}
-static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname)
+static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
+ const char *fname)
{
- my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
- c1.collation->name,c1.derivation_name(),
- c2.collation->name,c2.derivation_name(),
- fname);
+ my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
+ c1.collation->name,c1.derivation_name(),
+ c2.collation->name,c2.derivation_name(),
+ fname);
}
@@ -104,7 +107,7 @@ Item_bool_func2* Le_creator::create(Item *a, Item *b) const
longlong Item_func_not::val_int()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ bool value= args[0]->val_bool();
null_value=args[0]->null_value;
return ((!null_value && value == 0) ? 1 : 0);
}
@@ -116,11 +119,11 @@ longlong Item_func_not::val_int()
longlong Item_func_not_all::val_int()
{
DBUG_ASSERT(fixed == 1);
- double value= args[0]->val();
+ bool value= args[0]->val_bool();
/*
- return TRUE if there was records in underlaying select in max/min
- optimisation (ALL subquery)
+ return TRUE if there was records in underlying select in max/min
+ optimization (ALL subquery)
*/
if (empty_underlying_subquery())
return 1;
@@ -147,18 +150,18 @@ void Item_func_not_all::print(String *str)
/*
Special NOP (No OPeration) for ALL subquery it is like Item_func_not_all
- (return TRUE if underlaying sudquery do not return rows) but if subquery
+ (return TRUE if underlying subquery do not return rows) but if subquery
returns some rows it return same value as argument (TRUE/FALSE).
*/
longlong Item_func_nop_all::val_int()
{
DBUG_ASSERT(fixed == 1);
- double value= args[0]->val();
+ longlong value= args[0]->val_int();
/*
- return FALSE if there was records in underlaying select in max/min
- optimisation (SAME/ANY subquery)
+ return FALSE if there was records in underlying select in max/min
+ optimization (SAME/ANY subquery)
*/
if (empty_underlying_subquery())
return 0;
@@ -207,12 +210,26 @@ void Item_bool_func2::fix_length_and_dec()
if (!args[0] || !args[1])
return;
+ /*
+ We allow to convert to Unicode character sets in some cases.
+ The conditions when conversion is possible are:
+ - arguments A and B have different charsets
+ - A wins according to coercibility rules
+ - character set of A is superset for character set of B
+
+ If all of the above is true, then it's possible to convert
+ B into the character set of A, and then compare according
+ to the collation of A.
+ */
+
+
DTCollation coll;
if (args[0]->result_type() == STRING_RESULT &&
args[1]->result_type() == STRING_RESULT &&
agg_arg_charsets(coll, args, 2, MY_COLL_CMP_CONV))
return;
-
+
+
// Make a special case of compare with fields to get nicer DATE comparisons
if (functype() == LIKE_FUNC) // Disable conversion in case of LIKE function.
@@ -234,7 +251,7 @@ void Item_bool_func2::fix_length_and_dec()
}
}
}
- if (args[1]->type() == FIELD_ITEM)
+ if (args[1]->type() == FIELD_ITEM /* && !args[1]->const_item() */)
{
Field *field=((Item_field*) args[1])->field;
if (field->can_be_compared_as_longlong())
@@ -256,7 +273,8 @@ 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)];
- if (type == ROW_RESULT)
+ switch(type) {
+ case ROW_RESULT:
{
uint n= (*a)->cols();
if (n != (*b)->cols())
@@ -276,8 +294,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
}
comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
}
+ break;
}
- else if (type == STRING_RESULT)
+ case STRING_RESULT:
{
/*
We must set cmp_charset here as we may be called from for an automatic
@@ -299,15 +318,28 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
func= &Arg_comparator::compare_binary_string;
else if (func == &Arg_comparator::compare_e_string)
func= &Arg_comparator::compare_e_binary_string;
+
+ /*
+ As this is binary compassion, mark all fields that they can't be
+ transformed. Otherwise we would get into trouble with comparisons
+ like:
+ WHERE col= 'j' AND col LIKE BINARY 'j'
+ which would be transformed to:
+ WHERE col= 'j'
+ */
+ (*a)->transform(&Item::set_no_const_sub, (byte*) 0);
+ (*b)->transform(&Item::set_no_const_sub, (byte*) 0);
}
+ break;
}
- else if (type == INT_RESULT)
+ case INT_RESULT:
{
if (func == &Arg_comparator::compare_int_signed)
{
if ((*a)->unsigned_flag)
- func= ((*b)->unsigned_flag)? &Arg_comparator::compare_int_unsigned :
- &Arg_comparator::compare_int_unsigned_signed;
+ func= (((*b)->unsigned_flag)?
+ &Arg_comparator::compare_int_unsigned :
+ &Arg_comparator::compare_int_unsigned_signed);
else if ((*b)->unsigned_flag)
func= &Arg_comparator::compare_int_signed_unsigned;
}
@@ -316,6 +348,13 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
if ((*a)->unsigned_flag ^ (*b)->unsigned_flag)
func= &Arg_comparator::compare_e_int_diff_signedness;
}
+ break;
+ }
+ case DECIMAL_RESULT:
+ case REAL_RESULT:
+ break;
+ default:
+ DBUG_ASSERT(0);
}
return 0;
}
@@ -399,10 +438,10 @@ int Arg_comparator::compare_real()
performing the comparison.
*/
volatile double val1, val2;
- val1= (*a)->val();
+ val1= (*a)->val_real();
if (!(*a)->null_value)
{
- val2= (*b)->val();
+ val2= (*b)->val_real();
if (!(*b)->null_value)
{
owner->null_value= 0;
@@ -415,15 +454,43 @@ int Arg_comparator::compare_real()
return -1;
}
+int Arg_comparator::compare_decimal()
+{
+ my_decimal value1;
+ my_decimal *val1= (*a)->val_decimal(&value1);
+ if (!(*a)->null_value)
+ {
+ my_decimal value2;
+ my_decimal *val2= (*b)->val_decimal(&value2);
+ if (!(*b)->null_value)
+ {
+ owner->null_value= 0;
+ return my_decimal_cmp(val1, val2);
+ }
+ }
+ owner->null_value= 1;
+ return -1;
+}
+
int Arg_comparator::compare_e_real()
{
- double val1= (*a)->val();
- double val2= (*b)->val();
+ double val1= (*a)->val_real();
+ double val2= (*b)->val_real();
if ((*a)->null_value || (*b)->null_value)
return test((*a)->null_value && (*b)->null_value);
return test(val1 == val2);
}
+int Arg_comparator::compare_e_decimal()
+{
+ my_decimal value1, value2;
+ my_decimal *val1= (*a)->val_decimal(&value1);
+ my_decimal *val2= (*b)->val_decimal(&value2);
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return test(my_decimal_cmp(val1, val2) == 0);
+}
+
int Arg_comparator::compare_int_signed()
{
longlong val1= (*a)->val_int();
@@ -582,7 +649,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->current_arena->is_stmt_prepare())
+ if (!thd->only_prepare())
cache->store(args[0]);
if (cache->cols() == 1)
{
@@ -615,17 +682,17 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
{
DBUG_ASSERT(fixed == 0);
if (fix_left(thd, tables, ref))
- return 1;
+ return TRUE;
if (args[0]->maybe_null)
maybe_null=1;
if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args+1))
- return 1;
+ return TRUE;
Item_in_subselect * sub= (Item_in_subselect *)args[1];
if (args[0]->cols() != sub->engine->cols())
{
my_error(ER_OPERAND_COLUMNS, MYF(0), args[0]->cols());
- return 1;
+ return TRUE;
}
if (args[1]->maybe_null)
maybe_null=1;
@@ -634,7 +701,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
not_null_tables_cache|= args[1]->not_null_tables();
const_item_cache&= args[1]->const_item();
fixed= 1;
- return 0;
+ return FALSE;
}
@@ -647,7 +714,7 @@ longlong Item_in_optimizer::val_int()
null_value= 1;
return 0;
}
- longlong tmp= args[1]->val_int_result();
+ bool tmp= args[1]->val_bool_result();
null_value= args[1]->null_value;
return tmp;
}
@@ -756,6 +823,8 @@ longlong Item_func_strcmp::val_int()
void Item_func_interval::fix_length_and_dec()
{
+ use_decimal_comparison= (row->el(0)->result_type() == DECIMAL_RESULT) ||
+ (row->el(0)->result_type() == INT_RESULT);
if (row->cols() > 8)
{
bool consts=1;
@@ -766,10 +835,41 @@ void Item_func_interval::fix_length_and_dec()
}
if (consts &&
- (intervals=(double*) sql_alloc(sizeof(double)*(row->cols()-1))))
+ (intervals=
+ (interval_range*) sql_alloc(sizeof(interval_range)*(row->cols()-1))))
{
- for (uint i=1 ; i < row->cols(); i++)
- intervals[i-1]=row->el(i)->val();
+ if (use_decimal_comparison)
+ {
+ for (uint i=1 ; i < row->cols(); i++)
+ {
+ Item *el= row->el(i);
+ interval_range *range= intervals + (i-1);
+ if ((el->result_type() == DECIMAL_RESULT) ||
+ (el->result_type() == INT_RESULT))
+ {
+ range->type= DECIMAL_RESULT;
+ range->dec.init();
+ my_decimal *dec= el->val_decimal(&range->dec);
+ if (dec != &range->dec)
+ {
+ range->dec= *dec;
+ range->dec.fix_buffer_pointer();
+ }
+ }
+ else
+ {
+ range->type= REAL_RESULT;
+ range->dbl= el->val_real();
+ }
+ }
+ }
+ else
+ {
+ for (uint i=1 ; i < row->cols(); i++)
+ {
+ intervals[i-1].dbl= row->el(i)->val_real();
+ }
+ }
}
}
maybe_null= 0;
@@ -782,20 +882,43 @@ void Item_func_interval::fix_length_and_dec()
/*
- return -1 if null value,
- 0 if lower than lowest
- 1 - arg_count-1 if between args[n] and args[n+1]
- arg_count if higher than biggest argument
+ Execute Item_func_interval()
+
+ SYNOPSIS
+ Item_func_interval::val_int()
+
+ NOTES
+ If we are doing a decimal comparison, we are
+ evaluating the first item twice.
+
+ RETURN
+ -1 if null value,
+ 0 if lower than lowest
+ 1 - arg_count-1 if between args[n] and args[n+1]
+ arg_count if higher than biggest argument
*/
longlong Item_func_interval::val_int()
{
DBUG_ASSERT(fixed == 1);
- double value= row->el(0)->val();
+ double value;
+ my_decimal dec_buf, *dec= NULL;
uint i;
- if (row->el(0)->null_value)
- return -1; // -1 if null
+ if (use_decimal_comparison)
+ {
+ dec= row->el(0)->val_decimal(&dec_buf);
+ if (row->el(0)->null_value)
+ return -1;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &value);
+ }
+ else
+ {
+ value= row->el(0)->val_real();
+ if (row->el(0)->null_value)
+ return -1;
+ }
+
if (intervals)
{ // Use binary search to find interval
uint start,end;
@@ -804,22 +927,46 @@ longlong Item_func_interval::val_int()
while (start != end)
{
uint mid= (start + end + 1) / 2;
- if (intervals[mid] <= value)
+ interval_range *range= intervals + mid;
+ my_bool cmp_result;
+ /*
+ The values in the range intervall may have different types,
+ Only do a decimal comparision of the first argument is a decimal
+ and we are comparing against a decimal
+ */
+ if (dec && range->type == DECIMAL_RESULT)
+ cmp_result= my_decimal_cmp(&range->dec, dec) <= 0;
+ else
+ cmp_result= (range->dbl <= value);
+ if (cmp_result)
start= mid;
else
end= mid - 1;
}
- return (value < intervals[start]) ? 0 : start + 1;
+ interval_range *range= intervals+start;
+ return ((dec && range->type == DECIMAL_RESULT) ?
+ my_decimal_cmp(dec, &range->dec) < 0 :
+ value < range->dbl) ? 0 : start + 1;
}
for (i=1 ; i < row->cols() ; i++)
{
- if (row->el(i)->val() > value)
+ Item *el= row->el(i);
+ if (use_decimal_comparison &&
+ ((el->result_type() == DECIMAL_RESULT) ||
+ (el->result_type() == INT_RESULT)))
+ {
+ my_decimal e_dec_buf, *e_dec= row->el(i)->val_decimal(&e_dec_buf);
+ if (my_decimal_cmp(e_dec, dec) > 0)
+ return i-1;
+ }
+ else if (row->el(i)->val_real() > value)
return i-1;
}
return i-1;
}
+
void Item_func_between::fix_length_and_dec()
{
max_length= 1;
@@ -827,7 +974,7 @@ void Item_func_between::fix_length_and_dec()
/*
As some compare functions are generated after sql_yacc,
- we have to check for out of memory conditons here
+ we have to check for out of memory conditions here
*/
if (!args[0] || !args[1] || !args[2])
return;
@@ -837,7 +984,7 @@ void Item_func_between::fix_length_and_dec()
return;
/*
- Make a special case of compare with date/time and longlong fields.
+ Make a special ease of compare with date/time and longlong fields.
They are compared as integers, so for const item this time-consuming
conversion can be done only once, not for every single comparison
*/
@@ -888,7 +1035,7 @@ longlong Item_func_between::val_int()
}
else if (cmp_type == INT_RESULT)
{
- longlong value=args[0]->val_int(),a,b;
+ longlong value=args[0]->val_int(), a, b;
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
a=args[1]->val_int();
@@ -906,13 +1053,31 @@ longlong Item_func_between::val_int()
null_value= value >= a;
}
}
+ else if (cmp_type == DECIMAL_RESULT)
+ {
+ my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf),
+ a_buf, *a_dec, b_buf, *b_dec;
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ a_dec= args[1]->val_decimal(&a_buf);
+ b_dec= args[2]->val_decimal(&b_buf);
+ if (!args[1]->null_value && !args[2]->null_value)
+ return (my_decimal_cmp(dec, a_dec)>=0) && (my_decimal_cmp(dec, b_dec)<=0);
+
+ if (args[1]->null_value && args[2]->null_value)
+ null_value=1;
+ else if (args[1]->null_value)
+ null_value= (my_decimal_cmp(dec, b_dec) <= 0);
+ else
+ null_value= (my_decimal_cmp(dec, a_dec) >= 0);
+ }
else
{
- double value=args[0]->val(),a,b;
+ double value= args[0]->val_real(),a,b;
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
- a=args[1]->val();
- b=args[2]->val();
+ a= args[1]->val_real();
+ b= args[2]->val_real();
if (!args[1]->null_value && !args[2]->null_value)
return (value >= a && value <= b) ? 1 : 0;
if (args[1]->null_value && args[2]->null_value)
@@ -945,14 +1110,25 @@ void
Item_func_ifnull::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null;
- max_length=max(args[0]->max_length,args[1]->max_length);
- decimals=max(args[0]->decimals,args[1]->decimals);
+ decimals= max(args[0]->decimals, args[1]->decimals);
+ max_length= (max(args[0]->max_length - args[0]->decimals,
+ args[1]->max_length - args[1]->decimals) +
+ decimals);
agg_result_type(&cached_result_type, args, 2);
- if (cached_result_type == STRING_RESULT)
+ switch (cached_result_type) {
+ case STRING_RESULT:
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV);
- else if (cached_result_type != REAL_RESULT)
+ break;
+ case DECIMAL_RESULT:
+ case REAL_RESULT:
+ break;
+ case INT_RESULT:
decimals= 0;
-
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
cached_field_type= args[0]->field_type();
if (cached_field_type != args[1]->field_type())
cached_field_type= Item_func::field_type();
@@ -969,16 +1145,16 @@ Field *Item_func_ifnull::tmp_table_field(TABLE *table)
}
double
-Item_func_ifnull::val()
+Item_func_ifnull::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if (!args[0]->null_value)
{
null_value=0;
return value;
}
- value=args[1]->val();
+ value= args[1]->val_real();
if ((null_value=args[1]->null_value))
return 0.0;
return value;
@@ -1000,6 +1176,23 @@ Item_func_ifnull::val_int()
return value;
}
+
+my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ my_decimal *value= args[0]->val_decimal(decimal_value);
+ if (!args[0]->null_value)
+ {
+ null_value= 0;
+ return value;
+ }
+ value= args[1]->val_decimal(decimal_value);
+ if ((null_value= args[1]->null_value))
+ return 0;
+ return value;
+}
+
+
String *
Item_func_ifnull::val_str(String *str)
{
@@ -1023,8 +1216,10 @@ void
Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
- max_length=max(args[1]->max_length,args[2]->max_length);
- decimals=max(args[1]->decimals,args[2]->decimals);
+ decimals= max(args[1]->decimals, args[2]->decimals);
+ max_length= (max(args[1]->max_length - args[1]->decimals,
+ args[2]->max_length - args[2]->decimals) +
+ decimals);
enum Item_result arg1_type=args[1]->result_type();
enum Item_result arg2_type=args[2]->result_type();
bool null1=args[1]->const_item() && args[1]->null_value;
@@ -1046,7 +1241,7 @@ Item_func_if::fix_length_and_dec()
if (cached_result_type == STRING_RESULT)
{
if (agg_arg_charsets(collation, args+1, 2, MY_COLL_ALLOW_CONV))
- return;
+ return;
}
else
{
@@ -1057,11 +1252,11 @@ Item_func_if::fix_length_and_dec()
double
-Item_func_if::val()
+Item_func_if::val_real()
{
DBUG_ASSERT(fixed == 1);
- Item *arg= args[0]->val_int() ? args[1] : args[2];
- double value=arg->val();
+ Item *arg= args[0]->val_bool() ? args[1] : args[2];
+ double value= arg->val_real();
null_value=arg->null_value;
return value;
}
@@ -1070,7 +1265,7 @@ longlong
Item_func_if::val_int()
{
DBUG_ASSERT(fixed == 1);
- Item *arg= args[0]->val_int() ? args[1] : args[2];
+ Item *arg= args[0]->val_bool() ? args[1] : args[2];
longlong value=arg->val_int();
null_value=arg->null_value;
return value;
@@ -1080,7 +1275,7 @@ String *
Item_func_if::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- Item *arg= args[0]->val_int() ? args[1] : args[2];
+ Item *arg= args[0]->val_bool() ? args[1] : args[2];
String *res=arg->val_str(str);
if (res)
res->set_charset(collation.collation);
@@ -1089,6 +1284,17 @@ Item_func_if::val_str(String *str)
}
+my_decimal *
+Item_func_if::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ Item *arg= args[0]->val_bool() ? args[1] : args[2];
+ my_decimal *value= arg->val_decimal(decimal_value);
+ null_value= arg->null_value;
+ return value;
+}
+
+
void
Item_func_nullif::fix_length_and_dec()
{
@@ -1105,6 +1311,7 @@ Item_func_nullif::fix_length_and_dec()
}
}
+
/*
nullif () returns NULL if arguments are equal, else it returns the
first argument.
@@ -1113,7 +1320,7 @@ Item_func_nullif::fix_length_and_dec()
*/
double
-Item_func_nullif::val()
+Item_func_nullif::val_real()
{
DBUG_ASSERT(fixed == 1);
double value;
@@ -1122,7 +1329,7 @@ Item_func_nullif::val()
null_value=1;
return 0.0;
}
- value=args[0]->val();
+ value= args[0]->val_real();
null_value=args[0]->null_value;
return value;
}
@@ -1158,6 +1365,22 @@ Item_func_nullif::val_str(String *str)
}
+my_decimal *
+Item_func_nullif::val_decimal(my_decimal * decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ my_decimal *res;
+ if (!cmp.compare())
+ {
+ null_value=1;
+ return 0;
+ }
+ res= args[0]->val_decimal(decimal_value);
+ null_value= args[0]->null_value;
+ return res;
+}
+
+
bool
Item_func_nullif::is_null()
{
@@ -1173,14 +1396,16 @@ Item_func_nullif::is_null()
Item *Item_func_case::find_item(String *str)
{
- String *first_expr_str,*tmp;
+ String *first_expr_str, *tmp;
+ my_decimal *first_expr_dec, first_expr_dec_val;
longlong first_expr_int;
double first_expr_real;
-
+
/* These will be initialized later */
LINT_INIT(first_expr_str);
LINT_INIT(first_expr_int);
LINT_INIT(first_expr_real);
+ LINT_INIT(first_expr_dec);
if (first_expr_num != -1)
{
@@ -1197,13 +1422,18 @@ Item *Item_func_case::find_item(String *str)
return else_expr_num != -1 ? args[else_expr_num] : 0;
break;
case REAL_RESULT:
- first_expr_real= args[first_expr_num]->val();
+ first_expr_real= args[first_expr_num]->val_real();
if (args[first_expr_num]->null_value)
return else_expr_num != -1 ? args[else_expr_num] : 0;
break;
+ case DECIMAL_RESULT:
+ first_expr_dec= args[first_expr_num]->val_decimal(&first_expr_dec_val);
+ if (args[first_expr_num]->null_value)
+ return else_expr_num != -1 ? args[else_expr_num] : 0;
+ break;
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
@@ -1215,7 +1445,7 @@ Item *Item_func_case::find_item(String *str)
if (first_expr_num == -1)
{
// No expression between CASE and the first WHEN
- if (args[i]->val_int())
+ if (args[i]->val_bool())
return args[i+1];
continue;
}
@@ -1230,12 +1460,19 @@ Item *Item_func_case::find_item(String *str)
return args[i+1];
break;
case REAL_RESULT:
- if (args[i]->val()==first_expr_real && !args[i]->null_value)
+ if (args[i]->val_real() == first_expr_real && !args[i]->null_value)
+ return args[i+1];
+ break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal value;
+ if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0)
return args[i+1];
break;
+ }
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
@@ -1245,7 +1482,6 @@ Item *Item_func_case::find_item(String *str)
}
-
String *Item_func_case::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -1282,7 +1518,7 @@ longlong Item_func_case::val_int()
return res;
}
-double Item_func_case::val()
+double Item_func_case::val_real()
{
DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
@@ -1295,11 +1531,32 @@ double Item_func_case::val()
null_value=1;
return 0;
}
- res=item->val();
+ res= item->val_real();
null_value=item->null_value;
return res;
}
+
+my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ char buff[MAX_FIELD_WIDTH];
+ String dummy_str(buff, sizeof(buff), default_charset());
+ Item *item= find_item(&dummy_str);
+ my_decimal *res;
+
+ if (!item)
+ {
+ null_value=1;
+ return 0;
+ }
+
+ res= item->val_decimal(decimal_value);
+ null_value= item->null_value;
+ return res;
+}
+
+
void Item_func_case::fix_length_and_dec()
{
Item **agg;
@@ -1308,8 +1565,10 @@ void Item_func_case::fix_length_and_dec()
if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1))))
return;
- // Aggregate all THEN and ELSE expression types
- // and collations when string result
+ /*
+ Aggregate all THEN and ELSE expression types
+ and collations when string result
+ */
for (nagg= 0 ; nagg < ncases/2 ; nagg++)
agg[nagg]= args[nagg*2+1];
@@ -1336,7 +1595,7 @@ void Item_func_case::fix_length_and_dec()
agg_cmp_type(&cmp_type, agg, nagg);
if ((cmp_type == STRING_RESULT) &&
agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV))
- return;
+ return;
}
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
@@ -1416,13 +1675,28 @@ longlong Item_func_coalesce::val_int()
return 0;
}
-double Item_func_coalesce::val()
+double Item_func_coalesce::val_real()
{
DBUG_ASSERT(fixed == 1);
null_value=0;
for (uint i=0 ; i < arg_count ; i++)
{
- double res=args[i]->val();
+ double res= args[i]->val_real();
+ if (!args[i]->null_value)
+ return res;
+ }
+ null_value=1;
+ return 0;
+}
+
+
+my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ null_value= 0;
+ for (uint i= 0; i < arg_count; i++)
+ {
+ my_decimal *res= args[i]->val_decimal(decimal_value);
if (!args[i]->null_value)
return res;
}
@@ -1433,18 +1707,28 @@ double Item_func_coalesce::val()
void Item_func_coalesce::fix_length_and_dec()
{
- max_length= 0;
- decimals= 0;
agg_result_type(&cached_result_type, args, arg_count);
- for (uint i=0 ; i < arg_count ; i++)
+ switch (cached_result_type)
{
- set_if_bigger(max_length,args[i]->max_length);
- set_if_bigger(decimals,args[i]->decimals);
- }
- if (cached_result_type == STRING_RESULT)
+ case STRING_RESULT:
+ count_only_length();
+ decimals= NOT_FIXED_DEC;
agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV);
- else if (cached_result_type != REAL_RESULT)
+ break;
+ case DECIMAL_RESULT:
+ count_decimal_length();
+ break;
+ case REAL_RESULT:
+ count_real_length();
+ break;
+ case INT_RESULT:
+ count_only_length();
decimals= 0;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
}
/****************************************************************************
@@ -1461,11 +1745,24 @@ static int cmp_double(void *cmp_arg, double *a,double *b)
return *a < *b ? -1 : *a == *b ? 0 : 1;
}
-static int cmp_row(void *cmp_arg, cmp_item_row* a, cmp_item_row* b)
+static int cmp_row(void *cmp_arg, cmp_item_row *a, cmp_item_row *b)
{
return a->compare(b);
}
+
+static int cmp_decimal(void *cmp_arg, my_decimal *a, my_decimal *b)
+{
+ /*
+ We need call of fixing buffer pointer, because fast sort just copy
+ decimal buffers in memory and pointers left pointing on old buffer place
+ */
+ a->fix_buffer_pointer();
+ b->fix_buffer_pointer();
+ return my_decimal_cmp(a, b);
+}
+
+
int in_vector::find(Item *item)
{
byte *result=get_value(item);
@@ -1585,28 +1882,58 @@ in_double::in_double(uint elements)
void in_double::set(uint pos,Item *item)
{
- ((double*) base)[pos]=item->val();
+ ((double*) base)[pos]= item->val_real();
}
byte *in_double::get_value(Item *item)
{
- tmp= item->val();
+ tmp= item->val_real();
if (item->null_value)
return 0; /* purecov: inspected */
return (byte*) &tmp;
}
-cmp_item* cmp_item::get_comparator(Item *item)
+
+in_decimal::in_decimal(uint elements)
+ :in_vector(elements, sizeof(my_decimal),(qsort2_cmp) cmp_decimal, 0)
+{}
+
+
+void in_decimal::set(uint pos, Item *item)
{
- switch (item->result_type()) {
+ /* as far as 'item' is constant, we can store reference on my_decimal */
+ my_decimal *dec= ((my_decimal *)base) + pos;
+ dec->len= DECIMAL_BUFF_LENGTH;
+ dec->fix_buffer_pointer();
+ my_decimal *res= item->val_decimal(dec);
+ if (res != dec)
+ my_decimal2decimal(res, dec);
+}
+
+
+byte *in_decimal::get_value(Item *item)
+{
+ my_decimal *result= item->val_decimal(&val);
+ if (item->null_value)
+ return 0;
+ return (byte *)result;
+}
+
+
+cmp_item* cmp_item::get_comparator(Item_result type,
+ CHARSET_INFO *cs)
+{
+ switch (type) {
case STRING_RESULT:
- return new cmp_item_sort_string(item->collation.collation);
+ return new cmp_item_sort_string(cs);
case INT_RESULT:
return new cmp_item_int;
case REAL_RESULT:
return new cmp_item_real;
case ROW_RESULT:
return new cmp_item_row;
+ case DECIMAL_RESULT:
+ return new cmp_item_decimal;
default:
DBUG_ASSERT(0);
break;
@@ -1639,7 +1966,7 @@ cmp_item* cmp_item_row::make_same()
cmp_item_row::~cmp_item_row()
{
DBUG_ENTER("~cmp_item_row");
- DBUG_PRINT("enter",("this: %lx", this));
+ DBUG_PRINT("enter",("this: 0x%lx", this));
if (comparators)
{
for (uint i= 0; i < n; i++)
@@ -1665,7 +1992,9 @@ void cmp_item_row::store_value(Item *item)
for (uint i=0; i < n; i++)
{
if (!comparators[i])
- if (!(comparators[i]= cmp_item::get_comparator(item->el(i))))
+ if (!(comparators[i]=
+ cmp_item::get_comparator(item->el(i)->result_type(),
+ item->el(i)->collation.collation)))
break; // new failed
comparators[i]->store_value(item->el(i));
item->null_value|= item->el(i)->null_value;
@@ -1736,6 +2065,37 @@ int cmp_item_row::compare(cmp_item *c)
}
+void cmp_item_decimal::store_value(Item *item)
+{
+ my_decimal *val= item->val_decimal(&value);
+ /* val may be zero if item is nnull */
+ if (val && val != &value)
+ my_decimal2decimal(val, &value);
+}
+
+
+int cmp_item_decimal::cmp(Item *arg)
+{
+ my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf);
+ if (arg->null_value)
+ return 1;
+ return my_decimal_cmp(&value, tmp);
+}
+
+
+int cmp_item_decimal::compare(cmp_item *arg)
+{
+ cmp_item_decimal *cmp= (cmp_item_decimal*) arg;
+ return my_decimal_cmp(&value, &cmp->value);
+}
+
+
+cmp_item* cmp_item_decimal::make_same()
+{
+ return new cmp_item_decimal();
+}
+
+
bool Item_func_in::nulls_in_row()
{
Item **arg,**arg_end;
@@ -1752,7 +2112,7 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
{
return cs->coll->strnncollsp(cs,
(uchar *) x->ptr(),x->length(),
- (uchar *) y->ptr(),y->length());
+ (uchar *) y->ptr(),y->length(), 0);
}
@@ -1791,6 +2151,9 @@ void Item_func_in::fix_length_and_dec()
case ROW_RESULT:
array= new in_row(arg_count-1, args[0]);
break;
+ case DECIMAL_RESULT:
+ array= new in_decimal(arg_count - 1);
+ break;
default:
DBUG_ASSERT(0);
return;
@@ -1812,7 +2175,7 @@ void Item_func_in::fix_length_and_dec()
}
else
{
- in_item= cmp_item::get_comparator(args[0]);
+ in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation);
if (cmp_type == STRING_RESULT)
in_item->cmp_charset= cmp_collation.collation;
}
@@ -1923,7 +2286,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
char buff[sizeof(char*)]; // Max local vars in function
#endif
not_null_tables_cache= used_tables_cache= 0;
- const_item_cache= 0;
+ const_item_cache= 1;
/*
and_table_cache is the value that Item_cond_or() returns for
not_null_tables()
@@ -1931,7 +2294,22 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
and_tables_cache= ~(table_map) 0;
if (check_stack_overrun(thd, buff))
- return 1; // Fatal error flag is set!
+ return TRUE; // Fatal error flag is set!
+ /*
+ The following optimization reduces the depth of an AND-OR tree.
+ E.g. a WHERE clause like
+ F1 AND (F2 AND (F2 AND F4))
+ is parsed into a tree with the same nested structure as defined
+ by braces. This optimization will transform such tree into
+ AND (F1, F2, F3, F4).
+ Trees of OR items are flattened as well:
+ ((F1 OR F2) OR (F3 OR F4)) => OR (F1, F2, F3, F4)
+ Items for removed AND/OR levels will dangle until the death of the
+ entire statement.
+ The optimization is currently prepared statements and stored procedures
+ friendly as it doesn't allocate any memory and its effects are durable
+ (i.e. do not depend on PS/SP arguments).
+ */
while ((item=li++))
{
table_map tmp_table_map;
@@ -1949,12 +2327,12 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if ((!item->fixed &&
item->fix_fields(thd, tables, li.ref())) ||
(item= *li.ref())->check_cols(1))
- return 1; /* purecov: inspected */
+ return TRUE; /* purecov: inspected */
used_tables_cache|= item->used_tables();
tmp_table_map= item->not_null_tables();
not_null_tables_cache|= tmp_table_map;
and_tables_cache&= tmp_table_map;
- const_item_cache&= item->const_item();
+ const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func;
if (item->maybe_null)
maybe_null=1;
@@ -1962,7 +2340,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
thd->lex->current_select->cond_count+= list.elements;
fix_length_and_dec();
fixed= 1;
- return 0;
+ return FALSE;
}
bool Item_cond::walk(Item_processor processor, byte *arg)
@@ -1977,6 +2355,66 @@ bool Item_cond::walk(Item_processor processor, byte *arg)
/*
+ Transform an Item_cond object with a transformer callback function
+
+ SYNOPSIS
+ transform()
+ transformer the transformer callback function to be applied to the nodes
+ of the tree of the object
+ arg parameter to be passed to the transformer
+
+ DESCRIPTION
+ The function recursively applies the transform method with the
+ same transformer to each member item of the condition list.
+ If the call of the method for a member item returns a new item
+ the old item is substituted for a new one.
+ After this the transform method is applied to the root node
+ of the Item_cond object.
+
+ RETURN VALUES
+ Item returned as the result of transformation of the root node
+*/
+
+Item *Item_cond::transform(Item_transformer transformer, byte *arg)
+{
+ List_iterator<Item> li(list);
+ Item *item;
+ while ((item= li++))
+ {
+ Item *new_item= item->transform(transformer, arg);
+ if (!new_item)
+ return 0;
+ if (new_item != item)
+ li.replace(new_item);
+ }
+ return Item_func::transform(transformer, arg);
+}
+
+void Item_cond::traverse_cond(Cond_traverser traverser,
+ void *arg, traverse_order order)
+{
+ List_iterator<Item> li(list);
+ Item *item;
+
+ switch(order) {
+ case(PREFIX):
+ (*traverser)(this, arg);
+ while ((item= li++))
+ {
+ item->traverse_cond(traverser, arg, order);
+ }
+ (*traverser)(NULL, arg);
+ break;
+ case(POSTFIX):
+ while ((item= li++))
+ {
+ item->traverse_cond(traverser, arg, order);
+ }
+ (*traverser)(this, arg);
+ }
+}
+
+/*
Move SUM items out from item tree and replace with reference
SYNOPSIS
@@ -2023,7 +2461,7 @@ void Item_cond::update_used_tables()
{
item->update_used_tables();
used_tables_cache|= item->used_tables();
- const_item_cache&= item->const_item();
+ const_item_cache&= item->const_item();
}
}
@@ -2064,7 +2502,7 @@ void Item_cond::neg_arguments(THD *thd)
/*
- Evalution of AND(expr, expr, expr ...)
+ Evaluation of AND(expr, expr, expr ...)
NOTES:
abort_if_null is set for AND expressions for which we don't care if the
@@ -2089,7 +2527,7 @@ longlong Item_cond_and::val_int()
null_value= 0;
while ((item=li++))
{
- if (item->val_int() == 0)
+ if (!item->val_bool())
{
if (abort_on_null || !(null_value= item->null_value))
return 0; // return FALSE
@@ -2107,7 +2545,7 @@ longlong Item_cond_or::val_int()
null_value=0;
while ((item=li++))
{
- if (item->val_int() != 0)
+ if (item->val_bool())
{
null_value=0;
return 1;
@@ -2279,12 +2717,12 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
DBUG_ASSERT(fixed == 0);
if (Item_bool_func2::fix_fields(thd, tlist, ref) ||
escape_item->fix_fields(thd, tlist, &escape_item))
- return 1;
+ return TRUE;
if (!escape_item->const_during_execution())
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE");
- return 1;
+ return TRUE;
}
if (escape_item->const_item())
@@ -2302,7 +2740,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
{
String* res2 = args[1]->val_str(&tmp_value2);
if (!res2)
- return 0; // Null argument
+ return FALSE; // Null argument
const size_t len = res2->length();
const char* first = res2->ptr();
@@ -2335,7 +2773,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
}
}
}
- return 0;
+ return FALSE;
}
#ifdef USE_REGEX
@@ -2346,15 +2784,15 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
DBUG_ASSERT(fixed == 0);
if ((!args[0]->fixed &&
args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) ||
- (!args[1]->fixed &&
+ (!args[1]->fixed &&
args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1))
- return 1; /* purecov: inspected */
+ return TRUE; /* purecov: inspected */
with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;
max_length= 1;
decimals= 0;
if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV))
- return 1;
+ return TRUE;
used_tables_cache=args[0]->used_tables() | args[1]->used_tables();
not_null_tables_cache= (args[0]->not_null_tables() |
@@ -2368,7 +2806,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (args[1]->null_value)
{ // Will always return NULL
maybe_null=1;
- return 0;
+ return FALSE;
}
int error;
if ((error= regcomp(&preg,res->c_ptr(),
@@ -2379,8 +2817,8 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
cmp_collation.collation)))
{
(void) regerror(error,&preg,buff,sizeof(buff));
- my_printf_error(ER_REGEXP_ERROR,ER(ER_REGEXP_ERROR),MYF(0),buff);
- return 1;
+ my_error(ER_REGEXP_ERROR, MYF(0), buff);
+ return TRUE;
}
regex_compiled=regex_is_const=1;
maybe_null=args[0]->maybe_null;
@@ -2388,7 +2826,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
else
maybe_null=1;
fixed= 1;
- return 0;
+ return FALSE;
}
@@ -2423,7 +2861,7 @@ longlong Item_func_regex::val_int()
regfree(&preg);
regex_compiled=0;
}
- if (regcomp(&preg,res2->c_ptr(),
+ if (regcomp(&preg,res2->c_ptr_safe(),
((cmp_collation.collation->state &
(MY_CS_BINSORT | MY_CS_CSSORT)) ?
REG_EXTENDED | REG_NOSUB :
@@ -2720,7 +3158,7 @@ longlong Item_cond_xor::val_int()
/*
Apply NOT transformation to the item and return a new one.
- SYNPOSIS
+ SYNOPSIS
neg_transformer()
thd thread handler
@@ -2831,3 +3269,287 @@ Item *Item_bool_rowready_func2::negated_item()
DBUG_ASSERT(0);
return 0;
}
+
+Item_equal::Item_equal(Item_field *f1, Item_field *f2)
+ : Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
+{
+ const_item_cache= 0;
+ fields.push_back(f1);
+ fields.push_back(f2);
+}
+
+Item_equal::Item_equal(Item *c, Item_field *f)
+ : Item_bool_func(), eval_item(0), cond_false(0)
+{
+ const_item_cache= 0;
+ fields.push_back(f);
+ const_item= c;
+}
+
+
+Item_equal::Item_equal(Item_equal *item_equal)
+ : Item_bool_func(), eval_item(0), cond_false(0)
+{
+ const_item_cache= 0;
+ List_iterator_fast<Item_field> li(item_equal->fields);
+ Item_field *item;
+ while ((item= li++))
+ {
+ fields.push_back(item);
+ }
+ const_item= item_equal->const_item;
+ cond_false= item_equal->cond_false;
+}
+
+void Item_equal::add(Item *c)
+{
+ if (cond_false)
+ return;
+ if (!const_item)
+ {
+ const_item= c;
+ return;
+ }
+ Item_func_eq *func= new Item_func_eq(c, const_item);
+ func->set_cmp_func();
+ func->quick_fix_field();
+ cond_false = !(func->val_int());
+}
+
+void Item_equal::add(Item_field *f)
+{
+ fields.push_back(f);
+}
+
+uint Item_equal::members()
+{
+ return fields.elements;
+}
+
+
+/*
+ Check whether a field is referred in the multiple equality
+
+ SYNOPSIS
+ contains()
+ field field whose occurrence is to be checked
+
+ DESCRIPTION
+ The function checks whether field is occurred in the Item_equal object
+
+ RETURN VALUES
+ 1 if nultiple equality contains a reference to field
+ 0 otherwise
+*/
+
+bool Item_equal::contains(Field *field)
+{
+ List_iterator_fast<Item_field> it(fields);
+ Item_field *item;
+ while ((item= it++))
+ {
+ if (field->eq(item->field))
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ Join members of another Item_equal object
+
+ SYNOPSIS
+ merge()
+ item multiple equality whose members are to be joined
+
+ DESCRIPTION
+ The function actually merges two multiple equalities.
+ After this operation the Item_equal object additionally contains
+ the field items of another item of the type Item_equal.
+ If the optional constant items are not equal the cond_false flag is
+ set to 1.
+
+ RETURN VALUES
+ none
+*/
+
+void Item_equal::merge(Item_equal *item)
+{
+ fields.concat(&item->fields);
+ Item *c= item->const_item;
+ if (c)
+ {
+ /*
+ The flag cond_false will be set to 1 after this, if
+ the multiple equality already contains a constant and its
+ value is not equal to the value of c.
+ */
+ add(const_item);
+ }
+ cond_false|= item->cond_false;
+}
+
+
+/*
+ Order field items in multiple equality according to a sorting criteria
+
+ SYNOPSIS
+ sort()
+ cmp function to compare field item
+ arg context extra parameter for the cmp function
+
+ DESCRIPTION
+ The function perform ordering of the field items in the Item_equal
+ object according to the criteria determined by the cmp callback parameter.
+ If cmp(item_field1,item_field2,arg)<0 than item_field1 must be
+ placed after item_fiel2.
+
+ IMPLEMENTATION
+ The function sorts field items by the exchange sort algorithm.
+ The list of field items is looked through and whenever two neighboring
+ members follow in a wrong order they are swapped. This is performed
+ again and again until we get all members in a right order.
+
+ RETURN VALUES
+ None
+*/
+
+void Item_equal::sort(Item_field_cmpfunc cmp, void *arg)
+{
+ bool swap;
+ List_iterator<Item_field> it(fields);
+ do
+ {
+ Item_field *item1= it++;
+ Item_field **ref1= it.ref();
+ Item_field *item2;
+
+ swap= FALSE;
+ while ((item2= it++))
+ {
+ Item_field **ref2= it.ref();
+ if (cmp(item1, item2, arg) < 0)
+ {
+ Item_field *item= *ref1;
+ *ref1= *ref2;
+ *ref2= item;
+ swap= TRUE;
+ }
+ else
+ {
+ item1= item2;
+ ref1= ref2;
+ }
+ }
+ it.rewind();
+ } while (swap);
+}
+
+bool Item_equal::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+{
+ List_iterator_fast<Item_field> li(fields);
+ Item *item;
+ not_null_tables_cache= used_tables_cache= 0;
+ const_item_cache= 0;
+ while ((item=li++))
+ {
+ table_map tmp_table_map;
+ used_tables_cache|= item->used_tables();
+ tmp_table_map= item->not_null_tables();
+ not_null_tables_cache|= tmp_table_map;
+ if (item->maybe_null)
+ maybe_null=1;
+ }
+ fix_length_and_dec();
+ fixed= 1;
+ return 0;
+}
+
+void Item_equal::update_used_tables()
+{
+ List_iterator_fast<Item_field> li(fields);
+ Item *item;
+ not_null_tables_cache= used_tables_cache= 0;
+ if ((const_item_cache= cond_false))
+ return;
+ while ((item=li++))
+ {
+ item->update_used_tables();
+ used_tables_cache|= item->used_tables();
+ const_item_cache&= item->const_item();
+ }
+}
+
+longlong Item_equal::val_int()
+{
+ if (cond_false)
+ return 0;
+ List_iterator_fast<Item_field> it(fields);
+ Item *item= const_item ? const_item : it++;
+ if ((null_value= item->null_value))
+ return 0;
+ eval_item->store_value(item);
+ while ((item= it++))
+ {
+ if ((null_value= item->null_value) || eval_item->cmp(item))
+ return 0;
+ }
+ return 1;
+}
+
+void Item_equal::fix_length_and_dec()
+{
+ Item *item= const_item ? const_item : get_first();
+ eval_item= cmp_item::get_comparator(item->result_type(),
+ item->collation.collation);
+ if (item->result_type() == STRING_RESULT)
+ eval_item->cmp_charset= cmp_collation.collation;
+}
+
+bool Item_equal::walk(Item_processor processor, byte *arg)
+{
+ List_iterator_fast<Item_field> it(fields);
+ Item *item;
+ while ((item= it++))
+ if (item->walk(processor, arg))
+ return 1;
+ return Item_func::walk(processor, arg);
+}
+
+Item *Item_equal::transform(Item_transformer transformer, byte *arg)
+{
+ List_iterator<Item_field> it(fields);
+ Item *item;
+ while ((item= it++))
+ {
+ Item *new_item= item->transform(transformer, arg);
+ if (!new_item)
+ return 0;
+ if (new_item != item)
+ it.replace((Item_field *) new_item);
+ }
+ return Item_func::transform(transformer, arg);
+}
+
+void Item_equal::print(String *str)
+{
+ str->append(func_name());
+ str->append('(');
+ List_iterator_fast<Item_field> it(fields);
+ Item *item;
+ if (const_item)
+ const_item->print(str);
+ else
+ {
+ item= it++;
+ item->print(str);
+ }
+ while ((item= it++))
+ {
+ str->append(',');
+ str->append(' ');
+ item->print(str);
+ }
+ str->append(')');
+}
+
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 37b0674a094..e917e13c5aa 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -27,6 +27,8 @@ class Arg_comparator;
typedef int (Arg_comparator::*arg_cmp_func)();
+typedef int (*Item_field_cmpfunc)(Item_field *f1, Item_field *f2, void *arg);
+
class Arg_comparator: public Sql_alloc
{
Item **a, **b;
@@ -65,6 +67,7 @@ public:
int compare_string(); // compare args[0] & args[1]
int compare_binary_string(); // compare args[0] & args[1]
int compare_real(); // compare args[0] & args[1]
+ int compare_decimal(); // compare args[0] & args[1]
int compare_int_signed(); // compare args[0] & args[1]
int compare_int_signed_unsigned();
int compare_int_unsigned_signed();
@@ -73,11 +76,12 @@ public:
int compare_e_string(); // compare args[0] & args[1]
int compare_e_binary_string(); // compare args[0] & args[1]
int compare_e_real(); // compare args[0] & args[1]
+ int compare_e_decimal(); // compare args[0] & args[1]
int compare_e_int(); // compare args[0] & args[1]
int compare_e_int_diff_signedness();
int compare_e_row(); // compare args[0] & args[1]
- static arg_cmp_func comparator_matrix [4][2];
+ static arg_cmp_func comparator_matrix [5][2];
friend class Item_func;
};
@@ -230,9 +234,44 @@ public:
};
class Item_maxmin_subselect;
+
+/*
+ The class Item_func_trig_cond is used for guarded predicates
+ which are employed only for internal purposes.
+ A guarded predicates is an object consisting of an a regular or
+ a guarded predicate P and a pointer to a boolean guard variable g.
+ A guarded predicate P/g is evaluated to true if the value of the
+ guard g is false, otherwise it is evaluated to the same value that
+ the predicate P: val(P/g)= g ? val(P):true.
+ Guarded predicates allow us to include predicates into a conjunction
+ conditionally. Currently they are utilized for pushed down predicates
+ in queries with outer join operations.
+
+ In the future, probably, it makes sense to extend this class to
+ the objects consisting of three elements: a predicate P, a pointer
+ to a variable g and a firing value s with following evaluation
+ rule: val(P/g,s)= g==s? val(P) : true. It will allow us to build only
+ one item for the objects of the form P/g1/g2...
+
+ Objects of this class are built only for query execution after
+ the execution plan has been already selected. That's why this
+ class needs only val_int out of generic methods.
+*/
+
+class Item_func_trig_cond: public Item_bool_func
+{
+ bool *trig_var;
+public:
+ Item_func_trig_cond(Item *a, bool *f) : Item_bool_func(a) { trig_var= f; }
+ longlong val_int() { return *trig_var ? args[0]->val_int() : 1; }
+ enum Functype functype() const { return TRIG_COND_FUNC; };
+ const char *func_name() const { return "trigcond"; };
+ bool const_item() const { return FALSE; }
+};
+
class Item_func_not_all :public Item_func_not
{
- /* allow to check presence od values in max/min optimisation */
+ /* allow to check presence of values in max/min optimization */
Item_sum_hybrid *test_sum_item;
Item_maxmin_subselect *test_sub_item;
@@ -385,10 +424,18 @@ public:
};
+struct interval_range
+{
+ Item_result type;
+ double dbl;
+ my_decimal dec;
+};
+
class Item_func_interval :public Item_int_func
{
Item_row *row;
- double *intervals;
+ my_bool use_decimal_comparison;
+ interval_range *intervals;
public:
Item_func_interval(Item_row *a)
:Item_int_func(a),row(a),intervals(0)
@@ -401,24 +448,43 @@ public:
};
-class Item_func_ifnull :public Item_func
+class Item_func_coalesce :public Item_func
{
+protected:
enum Item_result cached_result_type;
+ Item_func_coalesce(Item *a, Item *b)
+ :Item_func(a, b), cached_result_type(INT_RESULT)
+ {}
+public:
+ Item_func_coalesce(List<Item> &list)
+ :Item_func(list),cached_result_type(INT_RESULT)
+ {}
+ double val_real();
+ longlong val_int();
+ String *val_str(String *);
+ my_decimal *val_decimal(my_decimal *);
+ void fix_length_and_dec();
+ enum Item_result result_type () const { return cached_result_type; }
+ const char *func_name() const { return "coalesce"; }
+ table_map not_null_tables() const { return 0; }
+};
+
+
+class Item_func_ifnull :public Item_func_coalesce
+{
+protected:
enum_field_types cached_field_type;
bool field_type_defined;
public:
- Item_func_ifnull(Item *a,Item *b)
- :Item_func(a,b), cached_result_type(INT_RESULT)
- {}
- double val();
+ Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {}
+ double val_real();
longlong val_int();
String *val_str(String *str);
- enum Item_result result_type () const { return cached_result_type; }
+ my_decimal *val_decimal(my_decimal *);
enum_field_types field_type() const;
void fix_length_and_dec();
const char *func_name() const { return "ifnull"; }
Field *tmp_table_field(TABLE *table);
- table_map not_null_tables() const { return 0; }
};
@@ -429,9 +495,10 @@ public:
Item_func_if(Item *a,Item *b,Item *c)
:Item_func(a,b,c), cached_result_type(INT_RESULT)
{}
- double val();
+ double val_real();
longlong val_int();
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)
{
@@ -452,9 +519,10 @@ public:
Item_func_nullif(Item *a,Item *b)
:Item_bool_func2(a,b), cached_result_type(INT_RESULT)
{}
- double val();
+ double val_real();
longlong val_int();
String *val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec();
const char *func_name() const { return "nullif"; }
@@ -464,23 +532,6 @@ public:
};
-class Item_func_coalesce :public Item_func
-{
- enum Item_result cached_result_type;
-public:
- Item_func_coalesce(List<Item> &list)
- :Item_func(list),cached_result_type(INT_RESULT)
- {}
- double val();
- longlong val_int();
- String *val_str(String *);
- void fix_length_and_dec();
- enum Item_result result_type () const { return cached_result_type; }
- const char *func_name() const { return "coalesce"; }
- table_map not_null_tables() const { return 0; }
-};
-
-
class Item_func_case :public Item_func
{
int first_expr_num, else_expr_num;
@@ -493,7 +544,7 @@ public:
Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
:Item_func(), first_expr_num(-1), else_expr_num(-1),
cached_result_type(INT_RESULT)
- {
+ {
ncases= list.elements;
if (first_expr_arg)
{
@@ -507,9 +558,10 @@ public:
}
set_arguments(list);
}
- double val();
+ double val_real();
longlong val_int();
String *val_str(String *);
+ my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec();
table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; }
@@ -550,7 +602,7 @@ public:
class in_string :public in_vector
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmp;
public:
in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs);
@@ -577,6 +629,16 @@ public:
byte *get_value(Item *item);
};
+class in_decimal :public in_vector
+{
+ my_decimal val;
+public:
+ in_decimal(uint elements);
+ void set(uint pos, Item *item);
+ byte *get_value(Item *item);
+};
+
+
/*
** Classes for easy comparing of non const items
*/
@@ -591,7 +653,7 @@ public:
virtual int cmp(Item *item)= 0;
// for optimized IN with row
virtual int compare(cmp_item *item)= 0;
- static cmp_item* get_comparator(Item *);
+ static cmp_item* get_comparator(Item_result type, CHARSET_INFO *cs);
virtual cmp_item *make_same()= 0;
virtual void store_value_by_template(cmp_item *tmpl, Item *item)
{
@@ -612,7 +674,7 @@ public:
class cmp_item_sort_string :public cmp_item_string
{
protected:
- char value_buff[80];
+ char value_buff[STRING_BUFFER_USUAL_SIZE];
String value;
public:
cmp_item_sort_string(CHARSET_INFO *cs):
@@ -624,7 +686,7 @@ public:
}
int cmp(Item *arg)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff, sizeof(buff), cmp_charset), *res;
if (!(res= arg->val_str(&tmp)))
return 1; /* Can't be right */
@@ -664,11 +726,11 @@ class cmp_item_real :public cmp_item
public:
void store_value(Item *item)
{
- value= item->val();
+ value= item->val_real();
}
int cmp(Item *arg)
{
- return value != arg->val();
+ return value != arg->val_real();
}
int compare(cmp_item *c)
{
@@ -678,6 +740,18 @@ public:
cmp_item *make_same();
};
+
+class cmp_item_decimal :public cmp_item
+{
+ my_decimal value;
+public:
+ void store_value(Item *item);
+ int cmp(Item *arg);
+ int compare(cmp_item *c);
+ cmp_item *make_same();
+};
+
+
class cmp_item_row :public cmp_item
{
cmp_item **comparators;
@@ -831,8 +905,9 @@ public:
class Item_func_isnotnull :public Item_bool_func
{
+ bool abort_on_null;
public:
- Item_func_isnotnull(Item *a) :Item_bool_func(a) {}
+ Item_func_isnotnull(Item *a) :Item_bool_func(a), abort_on_null(0) {}
longlong val_int();
enum Functype functype() const { return ISNOTNULL_FUNC; }
void fix_length_and_dec()
@@ -841,10 +916,12 @@ public:
}
const char *func_name() const { return "isnotnull"; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
- table_map not_null_tables() const { return 0; }
+ table_map not_null_tables() const
+ { return abort_on_null ? not_null_tables_cache : 0; }
Item *neg_transformer(THD *thd);
void print(String *str);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
+ void top_level_item() { abort_on_null=1; }
};
@@ -930,7 +1007,7 @@ public:
/* Item_cond() is only used to create top level items */
Item_cond(): Item_bool_func(), abort_on_null(1)
{ const_item_cache=0; }
- Item_cond(Item *i1,Item *i2)
+ Item_cond(Item *i1,Item *i2)
:Item_bool_func(), abort_on_null(0)
{
list.push_back(i1);
@@ -940,6 +1017,7 @@ public:
Item_cond(List<Item> &nlist)
: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);
enum Type type() const { return COND_ITEM; }
@@ -948,17 +1026,163 @@ public:
void update_used_tables();
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,COND **conds);
+ friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
+ 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);
+ Item *transform(Item_transformer transformer, byte *arg);
+ void traverse_cond(Cond_traverser, void *arg, traverse_order order);
void neg_arguments(THD *thd);
};
+/*
+ The class Item_equal is used to represent conjunctions of equality
+ predicates of the form field1 = field2, and field=const in where
+ conditions and on expressions.
+
+ All equality predicates of the form field1=field2 contained in a
+ conjunction are substituted for a sequence of items of this class.
+ An item of this class Item_equal(f1,f2,...fk) represents a
+ multiple equality f1=f2=...=fk.
+
+ If a conjunction contains predicates f1=f2 and f2=f3, a new item of
+ this class is created Item_equal(f1,f2,f3) representing the multiple
+ equality f1=f2=f3 that substitutes the above equality predicates in
+ the conjunction.
+ A conjunction of the predicates f2=f1 and f3=f1 and f3=f2 will be
+ substituted for the item representing the same multiple equality
+ f1=f2=f3.
+ An item Item_equal(f1,f2) can appear instead of a conjunction of
+ f2=f1 and f1=f2, or instead of just the predicate f1=f2.
+
+ An item of the class Item_equal inherits equalities from outer
+ conjunctive levels.
+
+ Suppose we have a where condition of the following form:
+ WHERE f1=f2 AND f3=f4 AND f3=f5 AND ... AND (...OR (f1=f3 AND ...)).
+ In this case:
+ f1=f2 will be substituted for Item_equal(f1,f2);
+ f3=f4 and f3=f5 will be substituted for Item_equal(f3,f4,f5);
+ f1=f3 will be substituted for Item_equal(f1,f2,f3,f4,f5);
+
+ An object of the class Item_equal can contain an optional constant
+ item c. Then it represents a multiple equality of the form
+ c=f1=...=fk.
+
+ Objects of the class Item_equal are used for the following:
+
+ 1. An object Item_equal(t1.f1,...,tk.fk) allows us to consider any
+ pair of tables ti and tj as joined by an equi-condition.
+ Thus it provide us with additional access paths from table to table.
+
+ 2. An object Item_equal(t1.f1,...,tk.fk) is applied to deduce new
+ SARGable predicates:
+ f1=...=fk AND P(fi) => f1=...=fk AND P(fi) AND P(fj).
+ It also can give us additional index scans and can allow us to
+ improve selectivity estimates.
+
+ 3. An object Item_equal(t1.f1,...,tk.fk) is used to optimize the
+ selected execution plan for the query: if table ti is accessed
+ before the table tj then in any predicate P in the where condition
+ the occurrence of tj.fj is substituted for ti.fi. This can allow
+ an evaluation of the predicate at an earlier step.
+
+ When feature 1 is supported they say that join transitive closure
+ is employed.
+ When feature 2 is supported they say that search argument transitive
+ closure is employed.
+ Both features are usually supported by preprocessing original query and
+ adding additional predicates.
+ We do not just add predicates, we rather dynamically replace some
+ predicates that can not be used to access tables in the investigated
+ plan for those, obtained by substitution of some fields for equal fields,
+ that can be used.
+
+ Prepared Statements/Stored Procedures note: instances of class
+ Item_equal are created only at the time a PS/SP is executed and
+ are deleted in the end of execution. All changes made to these
+ objects need not be registered in the list of changes of the parse
+ tree and do not harm PS/SP re-execution.
+*/
+
+class Item_equal: public Item_bool_func
+{
+ List<Item_field> fields; /* list of equal field items */
+ Item *const_item; /* optional constant item equal to fields items */
+ cmp_item *eval_item;
+ bool cond_false;
+ DTCollation cmp_collation;
+public:
+ inline Item_equal()
+ : Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
+ { const_item_cache=0 ;}
+ Item_equal(Item_field *f1, Item_field *f2);
+ Item_equal(Item *c, Item_field *f);
+ Item_equal(Item_equal *item_equal);
+ inline Item* get_const() { return const_item; }
+ void add(Item *c);
+ void add(Item_field *f);
+ uint members();
+ bool contains(Field *field);
+ Item_field* get_first() { return fields.head(); }
+ void merge(Item_equal *item);
+ enum Functype functype() const { return MULT_EQUAL_FUNC; }
+ longlong val_int();
+ const char *func_name() const { return "multiple equal"; }
+ optimize_type select_optimize() const { return OPTIMIZE_EQUAL; }
+ 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);
+ void update_used_tables();
+ bool walk(Item_processor processor, byte *arg);
+ Item *transform(Item_transformer transformer, byte *arg);
+ void print(String *str);
+ CHARSET_INFO *compare_collation()
+ { return fields.head()->collation.collation; }
+};
+
+class COND_EQUAL: public Sql_alloc
+{
+public:
+ uint max_members; /* max number of members the current level
+ list and all lower level lists */
+ COND_EQUAL *upper_levels; /* multiple equalities of upper and levels */
+ List<Item_equal> current_level; /* list of multiple equalities of
+ the current and level */
+ COND_EQUAL()
+ {
+ max_members= 0;
+ upper_levels= 0;
+ }
+};
+
+
+class Item_equal_iterator : public List_iterator_fast<Item_field>
+{
+public:
+ inline Item_equal_iterator(Item_equal &item_equal)
+ :List_iterator_fast<Item_field> (item_equal.fields)
+ {}
+ inline Item_field* operator++(int)
+ {
+ Item_field *item= (*(List_iterator_fast<Item_field> *) this)++;
+ return item;
+ }
+ inline void rewind(void)
+ {
+ List_iterator_fast<Item_field>::rewind();
+ }
+};
+
class Item_cond_and :public Item_cond
{
public:
+ COND_EQUAL cond_equal; /* contains list of Item_equal objects for
+ the current and level and reference
+ to multiple equalities of upper and levels */
Item_cond_and() :Item_cond() {}
Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {}
Item_cond_and(THD *thd, Item_cond_and *item) :Item_cond(thd, item) {}
@@ -1001,7 +1225,7 @@ public:
/*
- XOR is Item_cond, not an Item_int_func bevause we could like to
+ XOR is Item_cond, not an Item_int_func because we could like to
optimize (a XOR b) later on. It's low prio, though
*/
@@ -1019,7 +1243,7 @@ public:
};
-/* Some usefull inline functions */
+/* Some useful inline functions */
inline Item *and_conds(Item *a, Item *b)
{
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 2b12a1310b9..b9073a6c0b3 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -18,10 +18,6 @@
#include "mysql_priv.h"
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
Item *create_func_abs(Item* a)
{
return new Item_func_abs(a);
@@ -77,12 +73,13 @@ Item *create_func_connection_id(void)
{
THD *thd=current_thd;
thd->lex->safe_to_cache_query= 0;
- return new Item_int(NullS,(longlong)
- ((thd->slave_thread) ?
- thd->variables.pseudo_thread_id :
- thd->thread_id),
- 10);
-}
+ return new Item_static_int_func("connection_id()",
+ (longlong)
+ ((thd->slave_thread) ?
+ thd->variables.pseudo_thread_id :
+ thd->thread_id),
+ 10);
+}
Item *create_func_conv(Item* a, Item *b, Item *c)
{
@@ -292,7 +289,7 @@ Item *create_func_period_diff(Item* a, Item *b)
Item *create_func_pi(void)
{
- return new Item_real("pi()",M_PI,6,8);
+ return new Item_static_float_func("pi()", M_PI, 6, 8);
}
Item *create_func_pow(Item* a, Item *b)
@@ -309,13 +306,9 @@ Item *create_func_current_user()
thd->lex->safe_to_cache_query= 0;
length= (uint) (strxmov(buff, thd->priv_user, "@", thd->priv_host, NullS) -
buff);
- return new Item_string(NullS, thd->memdup(buff, length), length,
- system_charset_info);
-}
-
-Item *create_func_quarter(Item* a)
-{
- return new Item_func_quarter(a);
+ return new Item_static_string_func("current_user()",
+ thd->memdup(buff, length), length,
+ system_charset_info);
}
Item *create_func_radians(Item *a)
@@ -440,7 +433,7 @@ Item *create_func_uuid(void)
Item *create_func_version(void)
{
- return new Item_string(NullS,server_version,
+ return new Item_static_string_func("version()", server_version,
(uint) strlen(server_version),
system_charset_info, DERIVATION_SYSCONST);
}
@@ -462,7 +455,7 @@ Item *create_load_file(Item* a)
}
-Item *create_func_cast(Item *a, Cast_target cast_type, int len,
+Item *create_func_cast(Item *a, Cast_target cast_type, int len, int dec,
CHARSET_INFO *cs)
{
Item *res;
@@ -475,6 +468,9 @@ Item *create_func_cast(Item *a, Cast_target cast_type, int len,
case ITEM_CAST_DATE: res= new Item_date_typecast(a); break;
case ITEM_CAST_TIME: res= new Item_time_typecast(a); break;
case ITEM_CAST_DATETIME: res= new Item_datetime_typecast(a); break;
+ case ITEM_CAST_DECIMAL:
+ res= new Item_decimal_typecast(a, (len>0) ? len : 10, dec ? dec : 2);
+ break;
case ITEM_CAST_CHAR:
res= new Item_char_typecast(a, len, cs ? cs :
current_thd->variables.collation_connection);
diff --git a/sql/item_create.h b/sql/item_create.h
index faff6f45220..0a9af144ec0 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -28,7 +28,8 @@ Item *create_func_bit_length(Item* a);
Item *create_func_coercibility(Item* a);
Item *create_func_ceiling(Item* a);
Item *create_func_char_length(Item* a);
-Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs);
+Item *create_func_cast(Item *a, Cast_target cast_type, int len, int dec,
+ CHARSET_INFO *cs);
Item *create_func_connection_id(void);
Item *create_func_conv(Item* a, Item *b, Item *c);
Item *create_func_cos(Item* a);
@@ -72,7 +73,6 @@ Item *create_func_period_diff(Item* a, Item *b);
Item *create_func_pi(void);
Item *create_func_pow(Item* a, Item *b);
Item *create_func_current_user(void);
-Item *create_func_quarter(Item* a);
Item *create_func_radians(Item *a);
Item *create_func_release_lock(Item* a);
Item *create_func_repeat(Item* a, Item *b);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 1b80ef06251..c2afc2fd685 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -28,6 +28,9 @@
#include <time.h>
#include <ft_global.h>
+#include "sp_head.h"
+#include "sp_rcontext.h"
+#include "sp.h"
bool check_reserved_words(LEX_STRING *name)
{
@@ -42,10 +45,10 @@ bool check_reserved_words(LEX_STRING *name)
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
const char *fname)
{
- my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
- c1.collation->name,c1.derivation_name(),
- c2.collation->name,c2.derivation_name(),
- fname);
+ my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
+ c1.collation->name, c1.derivation_name(),
+ c2.collation->name, c2.derivation_name(),
+ fname);
}
static void my_coll_agg_error(DTCollation &c1,
@@ -53,11 +56,11 @@ static void my_coll_agg_error(DTCollation &c1,
DTCollation &c3,
const char *fname)
{
- my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0),
- c1.collation->name,c1.derivation_name(),
- c2.collation->name,c2.derivation_name(),
- c3.collation->name,c3.derivation_name(),
- fname);
+ my_error(ER_CANT_AGGREGATE_3COLLATIONS, MYF(0),
+ c1.collation->name, c1.derivation_name(),
+ c2.collation->name, c2.derivation_name(),
+ c3.collation->name, c3.derivation_name(),
+ fname);
}
@@ -71,7 +74,7 @@ static void my_coll_agg_error(Item** args, uint count, const char *fname)
args[2]->collation,
fname);
else
- my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname);
+ my_error(ER_CANT_AGGREGATE_NCOLLATIONS, MYF(0), fname);
}
@@ -187,8 +190,15 @@ bool Item_func::agg_arg_charsets(DTCollation &coll,
res= TRUE;
break; // we cannot return here, we need to restore "arena".
}
- conv->fix_fields(thd, 0, &conv);
+ if ((*arg)->type() == FIELD_ITEM)
+ ((Item_field *)(*arg))->no_const_subst= 1;
+ /*
+ 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
+ */
*arg= conv;
+ conv->fix_fields(thd, 0, arg);
}
if (arena)
thd->restore_backup_item_arena(arena, &backup);
@@ -274,8 +284,8 @@ Item_func::Item_func(THD *thd, Item_func *item)
item.
RETURN VALUES
- 0 ok
- 1 Got error. Stored with my_error().
+ FALSE ok
+ TRUE Got error. Stored with my_error().
*/
bool
@@ -291,7 +301,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
const_item_cache=1;
if (check_stack_overrun(thd, buff))
- return 1; // Fatal error if flag is set!
+ return TRUE; // Fatal error if flag is set!
if (arg_count)
{ // Print purify happy
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
@@ -302,8 +312,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
We shouldn't call fix_fields() twice, so check 'fixed' field first
*/
if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)))
- return 1; /* purecov: inspected */
-
+ return TRUE; /* purecov: inspected */
item= *arg;
if (allowed_arg_cols)
@@ -329,10 +338,10 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
}
fix_length_and_dec();
- if (thd->net.last_errno) // An error inside fix_length_and_dec occured
- return 1;
+ if (thd->net.report_error) // An error inside fix_length_and_dec occured
+ return TRUE;
fixed= 1;
- return 0;
+ return FALSE;
}
bool Item_func::walk (Item_processor processor, byte *argument)
@@ -349,6 +358,71 @@ bool Item_func::walk (Item_processor processor, byte *argument)
return (this->*processor)(argument);
}
+void Item_func::traverse_cond(Cond_traverser traverser,
+ void *argument, traverse_order order)
+{
+ if (arg_count)
+ {
+ Item **arg,**arg_end;
+
+ switch (order) {
+ case(PREFIX):
+ (*traverser)(this, argument);
+ for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
+ {
+ (*arg)->traverse_cond(traverser, argument, order);
+ }
+ break;
+ case (POSTFIX):
+ for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
+ {
+ (*arg)->traverse_cond(traverser, argument, order);
+ }
+ (*traverser)(this, argument);
+ }
+ }
+}
+
+
+
+/*
+ Transform an Item_func object with a transformer callback function
+
+ SYNOPSIS
+ transform()
+ transformer the transformer callback function to be applied to the nodes
+ of the tree of the object
+ argument parameter to be passed to the transformer
+
+ DESCRIPTION
+ The function recursively applies the transform method with the
+ same transformer to each argument the function.
+ If the call of the method for a member item returns a new item
+ the old item is substituted for a new one.
+ After this the transform method is applied to the root node
+ of the Item_func object.
+
+ RETURN VALUES
+ Item returned as the result of transformation of the root node
+*/
+
+Item *Item_func::transform(Item_transformer transformer, byte *argument)
+{
+ if (arg_count)
+ {
+ Item **arg,**arg_end;
+ for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
+ {
+ Item *new_item= (*arg)->transform(transformer, argument);
+ if (!new_item)
+ return 0;
+ if (*arg != new_item)
+ current_thd->change_item_tree(arg, new_item);
+ }
+ }
+ return (this->*transformer)(argument);
+}
+
/* See comments in Item_cmp_func::split_sum_func() */
@@ -438,6 +512,7 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
return 1;
}
+
Field *Item_func::tmp_table_field(TABLE *t_arg)
{
Field *res;
@@ -456,25 +531,33 @@ Field *Item_func::tmp_table_field(TABLE *t_arg)
res= new Field_double(max_length, maybe_null, name, t_arg, decimals);
break;
case STRING_RESULT:
- if (max_length > 255)
- res= new Field_blob(max_length, maybe_null, name, t_arg, collation.collation);
- else
- res= new Field_string(max_length, maybe_null, name, t_arg, collation.collation);
+ res= make_string_field(t_arg);
+ break;
+ case DECIMAL_RESULT:
+ res= new Field_new_decimal(max_length + (decimals?1:0), maybe_null,
+ name, t_arg, decimals);
break;
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
return res;
}
+my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed);
+ int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
String *Item_real_func::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- double nr=val();
+ double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
str->set(nr,decimals, &my_charset_bin);
@@ -482,38 +565,107 @@ String *Item_real_func::val_str(String *str)
}
-String *Item_num_func::val_str(String *str)
+void Item_func::fix_num_length_and_dec()
{
- DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
+ decimals= 0;
+ for (uint i=0 ; i < arg_count ; i++)
{
- longlong nr=val_int();
- if (null_value)
- return 0; /* purecov: inspected */
- if (!unsigned_flag)
- str->set(nr,&my_charset_bin);
- else
- str->set((ulonglong) nr,&my_charset_bin);
+ set_if_bigger(decimals, args[i]->decimals);
}
- else
+ max_length= float_length(decimals);
+}
+
+
+void Item_func_numhybrid::fix_num_length_and_dec()
+{}
+
+
+/*
+ Set max_length/decimals of function if function is fixed point and
+ result length/precision depends on argument ones
+
+ SYNOPSIS
+ Item_func::count_decimal_length()
+*/
+
+void Item_func::count_decimal_length()
+{
+ uint32 length= 0;
+ decimals= 0;
+ for (uint i=0 ; i < arg_count ; i++)
{
- double nr=val();
- if (null_value)
- return 0; /* purecov: inspected */
- str->set(nr,decimals,&my_charset_bin);
+ set_if_bigger(decimals, args[i]->decimals);
+ set_if_bigger(length, (args[i]->max_length - args[i]->decimals));
}
- return str;
+ max_length= length;
+ length+= decimals;
+ if (length < max_length) // If previous operation gave overflow
+ max_length= UINT_MAX32;
+ else
+ max_length= length;
}
-void Item_func::fix_num_length_and_dec()
+/*
+ Set max_length of if it is maximum length of its arguments
+
+ SYNOPSIS
+ Item_func::count_only_length()
+*/
+
+void Item_func::count_only_length()
{
- decimals=0;
+ max_length= 0;
for (uint i=0 ; i < arg_count ; i++)
- set_if_bigger(decimals,args[i]->decimals);
- max_length=float_length(decimals);
+ set_if_bigger(max_length, args[i]->max_length);
}
+
+/*
+ Set max_length/decimals of function if function is floating point and
+ result length/precision depends on argument ones
+
+ SYNOPSIS
+ Item_func::count_real_length()
+*/
+
+void Item_func::count_real_length()
+{
+ uint32 length= 0;
+ decimals= 0;
+ max_length= 0;
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ if (decimals != NOT_FIXED_DEC)
+ {
+ set_if_bigger(decimals, args[i]->decimals);
+ set_if_bigger(length, (args[i]->max_length - args[i]->decimals));
+ }
+ set_if_bigger(max_length, args[i]->max_length);
+ }
+ if (decimals != NOT_FIXED_DEC)
+ {
+ max_length= length;
+ length+= decimals;
+ if (length < max_length) // If previous operation gave overflow
+ max_length= UINT_MAX32;
+ else
+ max_length= length;
+ }
+}
+
+
+
+void Item_func::signal_divide_by_null()
+{
+ THD *thd= current_thd;
+ if (thd->variables.sql_mode & MODE_ERROR_FOR_DIVISION_BY_ZERO)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DIVISION_BY_ZERO,
+ ER(ER_DIVISION_BY_ZERO));
+ null_value= 1;
+}
+
+
Item *Item_func::get_tmp_table_item(THD *thd)
{
if (!with_sum_func && !const_item())
@@ -534,45 +686,215 @@ String *Item_int_func::val_str(String *str)
return str;
}
+
/*
- Change from REAL_RESULT (default) to INT_RESULT if both arguments are
- integers
+ Check arguments here to determine result's type for function with two
+ arguments.
+
+ SYNOPSIS
+ Item_num_op::find_num_type()
*/
void Item_num_op::find_num_type(void)
{
- if (args[0]->result_type() == INT_RESULT &&
- args[1]->result_type() == INT_RESULT)
+ DBUG_ENTER("Item_num_op::find_num_type");
+ DBUG_PRINT("info", ("name %s", func_name()));
+ DBUG_ASSERT(arg_count == 2);
+ Item_result r0= args[0]->result_type();
+ Item_result r1= args[1]->result_type();
+
+ if (r0 == REAL_RESULT || r1 == REAL_RESULT ||
+ r0 == STRING_RESULT || r1 ==STRING_RESULT)
{
+ count_real_length();
+ max_length= float_length(decimals);
+ hybrid_type= REAL_RESULT;
+ }
+ else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT)
+ {
+ hybrid_type= DECIMAL_RESULT;
+ result_precision();
+ }
+ else if (r0 == INT_RESULT && r1 == INT_RESULT)
+ {
+ decimals= 0;
hybrid_type=INT_RESULT;
unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag;
+ result_precision();
+ }
+ DBUG_PRINT("info", ("Type: %s",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--")));
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Set result type of function if it (type) is depends only on first argument
+
+ SYNOPSIS
+ Item_func_num1::find_num_type()
+*/
+
+void Item_func_num1::find_num_type()
+{
+ DBUG_ENTER("Item_func_num1::find_num_type");
+ DBUG_PRINT("info", ("name %s", func_name()));
+ switch (hybrid_type= args[0]->result_type()) {
+ case INT_RESULT:
+ unsigned_flag= args[0]->unsigned_flag;
+ break;
+ case STRING_RESULT:
+ case REAL_RESULT:
+ hybrid_type= REAL_RESULT;
+ max_length= float_length(decimals);
+ break;
+ case DECIMAL_RESULT:
+ break;
+ default:
+ DBUG_ASSERT(0);
}
+ DBUG_PRINT("info", ("Type: %s",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--")));
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_func_num1::fix_num_length_and_dec()
+{
+ decimals= args[0]->decimals;
+ max_length= args[0]->max_length;
}
-String *Item_num_op::val_str(String *str)
+
+void Item_func_numhybrid::fix_length_and_dec()
+{
+ fix_num_length_and_dec();
+ find_num_type();
+}
+
+
+String *Item_func_numhybrid::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
+ switch (hybrid_type) {
+ case DECIMAL_RESULT:
{
- longlong nr=val_int();
+ my_decimal decimal_value, *val;
+ if (!(val= decimal_op(&decimal_value)))
+ return 0; // null is set
+ my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
+ my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
+ break;
+ }
+ case INT_RESULT:
+ {
+ longlong nr= int_op();
if (null_value)
return 0; /* purecov: inspected */
if (!unsigned_flag)
str->set(nr,&my_charset_bin);
else
str->set((ulonglong) nr,&my_charset_bin);
+ break;
}
- else
+ case REAL_RESULT:
{
- double nr=val();
+ double nr= real_op();
if (null_value)
return 0; /* purecov: inspected */
str->set(nr,decimals,&my_charset_bin);
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
}
return str;
}
+double Item_func_numhybrid::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ switch (hybrid_type) {
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value, *val;
+ double result;
+ if (!(val= decimal_op(&decimal_value)))
+ return 0.0; // null is set
+ my_decimal2double(E_DEC_FATAL_ERROR, val, &result);
+ return result;
+ }
+ case INT_RESULT:
+ return (double)int_op();
+ case REAL_RESULT:
+ return real_op();
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0.0;
+}
+
+
+longlong Item_func_numhybrid::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ switch (hybrid_type) {
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value, *val;
+ if (!(val= decimal_op(&decimal_value)))
+ return 0; // null is set
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
+ return result;
+ }
+ case INT_RESULT:
+ return int_op();
+ case REAL_RESULT:
+ return (longlong)real_op();
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0;
+}
+
+
+my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value)
+{
+ my_decimal *val= decimal_value;
+ DBUG_ASSERT(fixed == 1);
+ switch (hybrid_type) {
+ case DECIMAL_RESULT:
+ val= decimal_op(decimal_value);
+ break;
+ case INT_RESULT:
+ {
+ longlong result= int_op();
+ int2my_decimal(E_DEC_FATAL_ERROR, result, unsigned_flag, decimal_value);
+ break;
+ }
+ case REAL_RESULT:
+ {
+ double result= (double)int_op();
+ double2my_decimal(E_DEC_FATAL_ERROR, result, decimal_value);
+ break;
+ }
+ case STRING_RESULT:
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ return val;
+}
+
+
void Item_func_signed::print(String *str)
{
str->append("cast(", 5);
@@ -664,26 +986,98 @@ longlong Item_func_unsigned::val_int()
}
-double Item_func_plus::val()
+String *Item_decimal_typecast::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- double value=args[0]->val()+args[1]->val();
+ my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
+ my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, &tmp_buf);
+ my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str);
+ return str;
+}
+
+
+double Item_decimal_typecast::val_real()
+{
+ my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
+ double res;
+ my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res);
+ return res;
+}
+
+
+longlong Item_decimal_typecast::val_int()
+{
+ my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
+ longlong res;
+ my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res);
+ return res;
+}
+
+
+my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec)
+{
+ my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf);
+ my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec);
+ return dec;
+}
+
+
+double Item_func_plus::real_op()
+{
+ double value= args[0]->val_real() + args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
return value;
}
-longlong Item_func_plus::val_int()
+
+longlong Item_func_plus::int_op()
{
- DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
- {
- longlong value=args[0]->val_int()+args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
- return 0;
- return value;
- }
- return (longlong) Item_func_plus::val();
+ longlong value=args[0]->val_int()+args[1]->val_int();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value;
+}
+
+
+/*
+ Calculate plus of two decimail's
+
+ SYNOPSIS
+ decimal_op()
+ decimal_value Buffer that can be used to store result
+
+ RETURN
+ 0 Value was NULL; In this case null_value is set
+ # Value of operation as a decimal
+*/
+
+my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal value1, *val1;
+ my_decimal value2, *val2;
+ val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ val2= args[1]->val_decimal(&value2);
+ if ((null_value= (args[1]->null_value ||
+ my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1,
+ val2) > 1)))
+ return 0;
+ return decimal_value;
+}
+
+/*
+ Set precision of results for additive operations (+ and -)
+
+ SYNOPSIS
+ Item_func_additive_op::result_precision()
+*/
+void Item_func_additive_op::result_precision()
+{
+ decimals= max(args[0]->decimals, args[1]->decimals);
+ max_length= (max(args[0]->max_length - args[0]->decimals,
+ args[1]->max_length - args[1]->decimals) +
+ decimals + 1);
}
@@ -701,84 +1095,168 @@ void Item_func_minus::fix_length_and_dec()
}
-double Item_func_minus::val()
+double Item_func_minus::real_op()
{
- DBUG_ASSERT(fixed == 1);
- double value=args[0]->val() - args[1]->val();
+ double value= args[0]->val_real() - args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
return value;
}
-longlong Item_func_minus::val_int()
+
+longlong Item_func_minus::int_op()
{
- DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
- {
- longlong value=args[0]->val_int() - args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
- return 0;
- return value;
- }
- return (longlong) Item_func_minus::val();
+ longlong value=args[0]->val_int() - args[1]->val_int();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value;
+}
+
+
+/* See Item_func_plus::decimal_op for comments */
+
+my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal value1, *val1;
+ my_decimal value2, *val2=
+
+ val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ val2= args[1]->val_decimal(&value2);
+ if ((null_value= (args[1]->null_value ||
+ my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1,
+ val2) > 1)))
+ return 0;
+ return decimal_value;
}
-double Item_func_mul::val()
+double Item_func_mul::real_op()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val()*args[1]->val();
+ double value= args[0]->val_real() * args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
- return 0.0; /* purecov: inspected */
+ return 0.0;
return value;
}
-longlong Item_func_mul::val_int()
+
+longlong Item_func_mul::int_op()
{
DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
- {
- longlong value=args[0]->val_int()*args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
- return 0; /* purecov: inspected */
- return value;
- }
- return (longlong) Item_func_mul::val();
+ longlong value=args[0]->val_int()*args[1]->val_int();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value;
+}
+
+
+/* See Item_func_plus::decimal_op for comments */
+
+my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal value1, *val1;
+ my_decimal value2, *val2;
+ val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ val2= args[1]->val_decimal(&value2);
+ if ((null_value= (args[1]->null_value ||
+ my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1,
+ val2) > 1)))
+ return 0;
+ return decimal_value;
+}
+
+
+void Item_func_mul::result_precision()
+{
+ decimals= args[0]->decimals + args[1]->decimals;
+ max_length= ((args[0]->max_length - args[0]->decimals) +
+ (args[1]->max_length - args[1]->decimals) +
+ decimals);
}
-double Item_func_div::val()
+double Item_func_div::real_op()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
- double val2=args[1]->val();
- if ((null_value= val2 == 0.0 || args[0]->null_value || args[1]->null_value))
+ double value= args[0]->val_real();
+ double val2= args[1]->val_real();
+ if ((null_value= args[0]->null_value || args[1]->null_value))
+ return 0.0;
+ if (val2 == 0.0)
+ {
+ signal_divide_by_null();
return 0.0;
+ }
return value/val2;
}
-longlong Item_func_div::val_int()
+
+my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
{
- DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
- {
- longlong value=args[0]->val_int();
- longlong val2=args[1]->val_int();
- if ((null_value= val2 == 0 || args[0]->null_value || args[1]->null_value))
- return 0;
- return value/val2;
+ my_decimal value1, *val1;
+ my_decimal value2, *val2;
+
+ val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ val2= args[1]->val_decimal(&value2);
+ if ((null_value= args[1]->null_value))
+ return 0;
+ switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
+ val1, val2, DECIMAL_DIV_SCALE_INCREASE)) {
+ case E_DEC_TRUNCATED:
+ case E_DEC_OK:
+ return decimal_value;
+ case E_DEC_DIV_ZERO:
+ signal_divide_by_null();
+ default:
+ null_value= 1; // Safety
+ return 0;
}
- return (longlong) Item_func_div::val();
}
+
+void Item_func_div::result_precision()
+{
+ decimals= (args[0]->decimals + args[0]->decimals +
+ DECIMAL_DIV_SCALE_INCREASE);
+ max_length= ((args[0]->max_length - args[0]->decimals) +
+ (args[1]->max_length - args[1]->decimals) +
+ decimals);
+}
+
+
void Item_func_div::fix_length_and_dec()
{
- decimals=max(args[0]->decimals,args[1]->decimals)+2;
- set_if_smaller(decimals, NOT_FIXED_DEC);
- max_length=args[0]->max_length - args[0]->decimals + decimals;
- uint tmp=float_length(decimals);
- set_if_smaller(max_length,tmp);
- maybe_null=1;
+ DBUG_ENTER("Item_func_div::fix_length_and_dec");
+ Item_num_op::fix_length_and_dec();
+ switch(hybrid_type) {
+ case REAL_RESULT:
+ {
+ decimals=max(args[0]->decimals,args[1]->decimals)+2;
+ set_if_smaller(decimals, NOT_FIXED_DEC);
+ max_length=args[0]->max_length - args[0]->decimals + decimals;
+ uint tmp=float_length(decimals);
+ set_if_smaller(max_length,tmp);
+ break;
+ }
+ case INT_RESULT:
+ hybrid_type= DECIMAL_RESULT;
+ DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
+ result_precision();
+ break;
+ case DECIMAL_RESULT:
+ result_precision();
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ maybe_null= 1; // devision by zero
+ DBUG_VOID_RETURN;
}
@@ -788,8 +1266,13 @@ longlong Item_func_int_div::val_int()
DBUG_ASSERT(fixed == 1);
longlong value=args[0]->val_int();
longlong val2=args[1]->val_int();
- if ((null_value= val2 == 0 || args[0]->null_value || args[1]->null_value))
+ if ((null_value= (args[0]->null_value || args[1]->null_value)))
return 0;
+ if (val2 == 0)
+ {
+ signal_divide_by_null();
+ return 0;
+ }
return (unsigned_flag ?
(ulonglong) value / (ulonglong) val2 :
value / val2);
@@ -798,133 +1281,179 @@ longlong Item_func_int_div::val_int()
void Item_func_int_div::fix_length_and_dec()
{
- find_num_type();
max_length=args[0]->max_length - args[0]->decimals;
maybe_null=1;
+ unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag;
}
-double Item_func_mod::val()
-{
- DBUG_ASSERT(fixed == 1);
- double x= args[0]->val();
- double y= args[1]->val();
- if ((null_value= (y == 0.0) || args[0]->null_value || args[1]->null_value))
- return 0.0; /* purecov: inspected */
- return fmod(x, y);
-}
-
-longlong Item_func_mod::val_int()
+longlong Item_func_mod::int_op()
{
DBUG_ASSERT(fixed == 1);
longlong value= args[0]->val_int();
longlong val2= args[1]->val_int();
- if ((null_value=val2 == 0 || args[0]->null_value || args[1]->null_value))
+ if ((null_value= args[0]->null_value || args[1]->null_value))
return 0; /* purecov: inspected */
+ if (val2 == 0)
+ {
+ signal_divide_by_null();
+ return 0;
+ }
return value % val2;
}
-void Item_func_mod::fix_length_and_dec()
+double Item_func_mod::real_op()
{
- Item_num_op::fix_length_and_dec();
+ DBUG_ASSERT(fixed == 1);
+ double value= args[0]->val_real();
+ double val2= args[1]->val_real();
+ if ((null_value= args[0]->null_value || args[1]->null_value))
+ return 0.0; /* purecov: inspected */
+ if (val2 == 0.0)
+ {
+ signal_divide_by_null();
+ return 0.0;
+ }
+ return fmod(value,val2);
}
-double Item_func_neg::val()
+my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value)
{
- DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
- null_value=args[0]->null_value;
+ my_decimal value1, *val1;
+ my_decimal value2, *val2;
+
+ val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ val2= args[1]->val_decimal(&value2);
+ if ((null_value= args[1]->null_value))
+ return 0;
+ switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
+ val1, val2)) {
+ case E_DEC_TRUNCATED:
+ case E_DEC_OK:
+ return decimal_value;
+ case E_DEC_DIV_ZERO:
+ signal_divide_by_null();
+ default:
+ null_value= 1;
+ return 0;
+ }
+}
+
+
+void Item_func_mod::result_precision()
+{
+ decimals= max(args[0]->decimals, args[1]->decimals);
+ max_length= max(args[0]->max_length, args[1]->max_length);
+}
+
+
+double Item_func_neg::real_op()
+{
+ double value= args[0]->val_real();
+ null_value= args[0]->null_value;
return -value;
}
-longlong Item_func_neg::val_int()
+longlong Item_func_neg::int_op()
{
- DBUG_ASSERT(fixed == 1);
- longlong value=args[0]->val_int();
- null_value=args[0]->null_value;
+ longlong value= args[0]->val_int();
+ null_value= args[0]->null_value;
return -value;
}
+my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal val, *value= args[0]->val_decimal(&val);
+ if (!(null_value= args[0]->null_value))
+ {
+ my_decimal2decimal(value, decimal_value);
+ my_decimal_neg(decimal_value);
+ }
+ return decimal_value;
+}
+
+
+void Item_func_neg::fix_num_length_and_dec()
+{
+ decimals= args[0]->decimals;
+ /* 1 add because sign can appear */
+ max_length= args[0]->max_length + 1;
+ unsigned_flag= 0;
+}
+
+
void Item_func_neg::fix_length_and_dec()
{
- enum Item_result arg_result= args[0]->result_type();
- enum Item::Type arg_type= args[0]->type();
- decimals=args[0]->decimals;
- max_length=args[0]->max_length;
- hybrid_type= REAL_RESULT;
-
+ DBUG_ENTER("Item_func_neg::fix_length_and_dec");
+ Item_func_num1::fix_length_and_dec();
+
/*
- We need to account for added '-' in the following cases:
- A) argument is a real or integer positive constant - in this case
- argument's max_length is set to actual number of bytes occupied, and not
- maximum number of bytes real or integer may require. Note that all
- constants are non negative so we don't need to account for removed '-'.
- B) argument returns a string.
+ If this is in integer context keep the context as integer if possible
+ (This is how multiplication and other integer functions works)
*/
- if (arg_result == STRING_RESULT ||
- (arg_type == REAL_ITEM && ((Item_real*)args[0])->value >= 0) ||
- (arg_type == INT_ITEM && ((Item_int*)args[0])->value > 0))
- max_length++;
-
- if (args[0]->result_type() == INT_RESULT)
+ if (hybrid_type == INT_RESULT &&
+ args[0]->type() == INT_ITEM &&
+ ((ulonglong) ((Item_uint*) args[0])->value >=
+ (ulonglong) LONGLONG_MIN))
{
/*
- If this is in integer context keep the context as integer
- (This is how multiplication and other integer functions works)
-
- We must however do a special case in the case where the argument
- is a unsigned bigint constant as in this case the only safe
- number to convert in integer context is 9223372036854775808.
- (This is needed because the lex parser doesn't anymore handle
- signed integers)
+ Ensure that result is converted to DECIMAL, as longlong can't hold
+ the negated number
*/
- if (args[0]->type() != INT_ITEM ||
- ((ulonglong) ((Item_uint*) args[0])->value <=
- (ulonglong) LONGLONG_MIN))
- hybrid_type= INT_RESULT;
+ hybrid_type= DECIMAL_RESULT;
+ DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
}
+ DBUG_VOID_RETURN;
}
-double Item_func_abs::val()
+double Item_func_abs::real_op()
{
- DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
- null_value=args[0]->null_value;
+ double value= args[0]->val_real();
+ null_value= args[0]->null_value;
return fabs(value);
}
-longlong Item_func_abs::val_int()
+longlong Item_func_abs::int_op()
{
- DBUG_ASSERT(fixed == 1);
- longlong value=args[0]->val_int();
- null_value=args[0]->null_value;
+ longlong value= args[0]->val_int();
+ null_value= args[0]->null_value;
return value >= 0 ? value : -value;
}
-void Item_func_abs::fix_length_and_dec()
+my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value)
{
- decimals=args[0]->decimals;
- max_length=args[0]->max_length;
- hybrid_type= REAL_RESULT;
- if (args[0]->result_type() == INT_RESULT)
+ my_decimal val, *value= args[0]->val_decimal(&val);
+ if (!(null_value= args[0]->null_value))
{
- hybrid_type= INT_RESULT;
- unsigned_flag= 1;
+ my_decimal2decimal(value, decimal_value);
+ if (decimal_value->sign())
+ my_decimal_neg(decimal_value);
}
+ return decimal_value;
+}
+
+
+void Item_func_abs::fix_length_and_dec()
+{
+ Item_func_num1::fix_length_and_dec();
+ if (hybrid_type == INT_RESULT)
+ unsigned_flag= 1;
}
/* Gateway to natural LOG function */
-double Item_func_ln::val()
+double Item_func_ln::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=(args[0]->null_value || value <= 0.0)))
return 0.0;
return log(value);
@@ -935,15 +1464,15 @@ double Item_func_ln::val()
We have to check if all values are > zero and first one is not one
as these are the cases then result is not a number.
*/
-double Item_func_log::val()
+double Item_func_log::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=(args[0]->null_value || value <= 0.0)))
return 0.0;
if (arg_count == 2)
{
- double value2= args[1]->val();
+ double value2= args[1]->val_real();
if ((null_value=(args[1]->null_value || value2 <= 0.0 || value == 1.0)))
return 0.0;
return log(value2) / log(value);
@@ -951,47 +1480,47 @@ double Item_func_log::val()
return log(value);
}
-double Item_func_log2::val()
+double Item_func_log2::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=(args[0]->null_value || value <= 0.0)))
return 0.0;
- return log(value) / log(2.0);
+ return log(value) / M_LN2;
}
-double Item_func_log10::val()
+double Item_func_log10::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=(args[0]->null_value || value <= 0.0)))
return 0.0; /* purecov: inspected */
return log10(value);
}
-double Item_func_exp::val()
+double Item_func_exp::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0.0; /* purecov: inspected */
return exp(value);
}
-double Item_func_sqrt::val()
+double Item_func_sqrt::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=(args[0]->null_value || value < 0)))
return 0.0; /* purecov: inspected */
return sqrt(value);
}
-double Item_func_pow::val()
+double Item_func_pow::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
- double val2=args[1]->val();
+ double value= args[0]->val_real();
+ double val2= args[1]->val_real();
if ((null_value=(args[0]->null_value || args[1]->null_value)))
return 0.0; /* purecov: inspected */
return pow(value,val2);
@@ -999,35 +1528,35 @@ double Item_func_pow::val()
// Trigonometric functions
-double Item_func_acos::val()
+double Item_func_acos::val_real()
{
DBUG_ASSERT(fixed == 1);
// the volatile's for BUG #2338 to calm optimizer down (because of gcc's bug)
- volatile double value=args[0]->val();
+ volatile double value= args[0]->val_real();
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
return 0.0;
return fix_result(acos(value));
}
-double Item_func_asin::val()
+double Item_func_asin::val_real()
{
DBUG_ASSERT(fixed == 1);
// the volatile's for BUG #2338 to calm optimizer down (because of gcc's bug)
- volatile double value=args[0]->val();
+ volatile double value= args[0]->val_real();
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
return 0.0;
return fix_result(asin(value));
}
-double Item_func_atan::val()
+double Item_func_atan::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0.0;
if (arg_count == 2)
{
- double val2= args[1]->val();
+ double val2= args[1]->val_real();
if ((null_value=args[1]->null_value))
return 0.0;
return fix_result(atan2(value,val2));
@@ -1035,28 +1564,28 @@ double Item_func_atan::val()
return fix_result(atan(value));
}
-double Item_func_cos::val()
+double Item_func_cos::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(cos(value));
}
-double Item_func_sin::val()
+double Item_func_sin::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(sin(value));
}
-double Item_func_tan::val()
+double Item_func_tan::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0.0;
return fix_result(tan(value));
@@ -1117,44 +1646,172 @@ void Item_func_integer::fix_length_and_dec()
decimals=0;
}
-longlong Item_func_ceiling::val_int()
+void Item_func_int_val::fix_num_length_and_dec()
{
- DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
- null_value=args[0]->null_value;
- return (longlong) ceil(value);
+ max_length= args[0]->max_length - (args[0]->decimals ?
+ args[0]->decimals + 1 :
+ 0) + 2;
+ uint tmp= float_length(decimals);
+ set_if_smaller(max_length,tmp);
+ decimals= 0;
}
-longlong Item_func_floor::val_int()
+
+void Item_func_int_val::find_num_type()
{
- DBUG_ASSERT(fixed == 1);
- // the volatile's for BUG #3051 to calm optimizer down (because of gcc's bug)
- volatile double value=args[0]->val();
- null_value=args[0]->null_value;
- return (longlong) floor(value);
+ DBUG_ENTER("Item_func_int_val::find_num_type");
+ DBUG_PRINT("info", ("name %s", func_name()));
+ switch(hybrid_type= args[0]->result_type())
+ {
+ case STRING_RESULT:
+ case REAL_RESULT:
+ hybrid_type= REAL_RESULT;
+ max_length= float_length(decimals);
+ break;
+ case INT_RESULT:
+ case DECIMAL_RESULT:
+ /*
+ -2 because in most high position can't be used any digit for longlong
+ and one position for increasing value during operation
+ */
+ if ((args[0]->max_length - args[0]->decimals) >=
+ (DECIMAL_LONGLONG_DIGITS - 2))
+ {
+ hybrid_type= DECIMAL_RESULT;
+ }
+ else
+ {
+ unsigned_flag= args[0]->unsigned_flag;
+ hybrid_type= INT_RESULT;
+ }
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_PRINT("info", ("Type: %s",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--")));
+
+ DBUG_VOID_RETURN;
}
-void Item_func_round::fix_length_and_dec()
+
+longlong Item_func_ceiling::int_op()
{
- max_length=args[0]->max_length;
- decimals=args[0]->decimals;
+ longlong result;
+ switch (args[0]->result_type()) {
+ case INT_RESULT:
+ result= args[0]->val_int();
+ null_value= args[0]->null_value;
+ break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal dec_buf, *dec;
+ if ((dec= Item_func_ceiling::decimal_op(&dec_buf)))
+ my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
+ else
+ result= 0;
+ break;
+ }
+ default:
+ result= (longlong)Item_func_ceiling::real_op();
+ };
+ return result;
+}
+
+
+double Item_func_ceiling::real_op()
+{
+ /*
+ the volatile's for BUG #3051 to calm optimizer down (because of gcc's
+ bug)
+ */
+ volatile double value= args[0]->val_real();
+ null_value= args[0]->null_value;
+ return ceil(value);
+}
+
+
+my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal val, *value= args[0]->val_decimal(&val);
+ if ((null_value= (args[0]->null_value ||
+ my_decimal_ceiling(E_DEC_FATAL_ERROR, value,
+ decimal_value) > 1)))
+ return 0;
+ return decimal_value;
+}
+
+
+longlong Item_func_floor::int_op()
+{
+ longlong result;
+ switch (args[0]->result_type()) {
+ case INT_RESULT:
+ result= args[0]->val_int();
+ null_value= args[0]->null_value;
+ break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal dec_buf, *dec;
+ if ((dec= Item_func_floor::decimal_op(&dec_buf)))
+ my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
+ else
+ result= 0;
+ break;
+ }
+ default:
+ result= (longlong)Item_func_floor::real_op();
+ };
+ return result;
+}
+
+
+double Item_func_floor::real_op()
+{
+ /*
+ the volatile's for BUG #3051 to calm optimizer down (because of gcc's
+ bug)
+ */
+ volatile double value= args[0]->val_real();
+ null_value= args[0]->null_value;
+ return floor(value);
+}
+
+
+my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal val, *value= args[0]->val_decimal(&val);
+ if ((null_value= (args[0]->null_value ||
+ my_decimal_floor(E_DEC_FATAL_ERROR, value,
+ decimal_value) > 1)))
+ return 0;
+ return decimal_value;
+}
+
+
+void Item_func_round::fix_num_length_and_dec()
+{
+ max_length= args[0]->max_length;
+ decimals= NOT_FIXED_DEC;
if (args[1]->const_item())
{
int tmp=(int) args[1]->val_int();
if (tmp < 0)
decimals=0;
else
- decimals=min(tmp,NOT_FIXED_DEC);
- if ((tmp= decimals - args[0]->decimals) > 0)
- max_length+= tmp;
+ decimals=min(tmp, NOT_FIXED_DEC);
}
}
-double Item_func_round::val()
+double Item_func_round::real_op()
{
- DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
int dec=(int) args[1]->val_int();
+ if (dec > 0)
+ decimals= dec; // to get correct output
uint abs_dec=abs(dec);
double tmp;
/*
@@ -1181,6 +1838,57 @@ double Item_func_round::val()
}
+longlong Item_func_round::int_op()
+{
+ longlong value= args[0]->val_int();
+ int dec=(int) args[1]->val_int();
+ decimals= 0;
+ uint abs_dec;
+ if ((null_value= args[0]->null_value || args[1]->null_value))
+ return 0;
+ if (dec >= 0)
+ return value; // integer have not digits after point
+
+ abs_dec= -dec;
+ double tmp;
+ /*
+ tmp2 is here to avoid return the value with 80 bit precision
+ This will fix that the test round(0.1,1) = round(0.1,1) is true
+ */
+ volatile double tmp2;
+
+ tmp= (abs_dec < array_elements(log_10) ?
+ log_10[abs_dec] : pow(10.0, (double) abs_dec));
+
+ if (truncate)
+ {
+ if (unsigned_flag)
+ tmp2= floor(ulonglong2double(value)/tmp)*tmp;
+ else if (value >= 0)
+ tmp2= floor(((double)value)/tmp)*tmp;
+ else
+ tmp2= ceil(((double)value)/tmp)*tmp;
+ }
+ else
+ tmp2= rint(((double)value)/tmp)*tmp;
+ return (longlong)tmp2;
+}
+
+
+my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal val, *value= args[0]->val_decimal(&val);
+ int dec=(int) args[1]->val_int();
+ if (dec > 0)
+ decimals= dec; // to get correct output
+ if ((null_value= (args[0]->null_value || args[1]->null_value ||
+ my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate,
+ decimal_value) > 1)))
+ return 0;
+ return decimal_value;
+}
+
+
bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables,
Item **ref)
{
@@ -1237,7 +1945,7 @@ void Item_func_rand::update_used_tables()
}
-double Item_func_rand::val()
+double Item_func_rand::val_real()
{
DBUG_ASSERT(fixed == 1);
return my_rnd(rand);
@@ -1246,16 +1954,16 @@ double Item_func_rand::val()
longlong Item_func_sign::val_int()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
null_value=args[0]->null_value;
return value < 0.0 ? -1 : (value > 0 ? 1 : 0);
}
-double Item_func_units::val()
+double Item_func_units::val_real()
{
DBUG_ASSERT(fixed == 1);
- double value=args[0]->val();
+ double value= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0;
return value*mul+add;
@@ -1271,10 +1979,8 @@ void Item_func_min_max::fix_length_and_dec()
for (uint i=0 ; i < arg_count ; i++)
{
- if (max_length < args[i]->max_length)
- max_length=args[i]->max_length;
- if (decimals < args[i]->decimals)
- decimals=args[i]->decimals;
+ set_if_bigger(max_length, args[i]->max_length);
+ set_if_bigger(decimals, args[i]->decimals);
if (!args[i]->maybe_null)
maybe_null=0;
cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
@@ -1299,9 +2005,17 @@ String *Item_func_min_max::val_str(String *str)
str->set((ulonglong) nr,&my_charset_bin);
return str;
}
+ case DECIMAL_RESULT:
+ {
+ my_decimal dec_buf, *dec_val= val_decimal(&dec_buf);
+ if (null_value)
+ return 0;
+ my_decimal2string(E_DEC_FATAL_ERROR, dec_val, 0, 0, 0, str);
+ return str;
+ }
case REAL_RESULT:
{
- double nr=val();
+ double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
str->set(nr,decimals,&my_charset_bin);
@@ -1337,7 +2051,7 @@ String *Item_func_min_max::val_str(String *str)
}
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
return 0;
}
@@ -1345,7 +2059,7 @@ String *Item_func_min_max::val_str(String *str)
}
-double Item_func_min_max::val()
+double Item_func_min_max::val_real()
{
DBUG_ASSERT(fixed == 1);
double value=0.0;
@@ -1354,12 +2068,12 @@ double Item_func_min_max::val()
{
if (null_value)
{
- value=args[i]->val();
+ value= args[i]->val_real();
null_value=args[i]->null_value;
}
else
{
- double tmp=args[i]->val();
+ double tmp= args[i]->val_real();
if (!args[i]->null_value && (tmp < value ? cmp_sign : -cmp_sign) > 0)
value=tmp;
}
@@ -1390,6 +2104,40 @@ longlong Item_func_min_max::val_int()
return value;
}
+
+my_decimal *Item_func_min_max::val_decimal(my_decimal *dec)
+{
+ DBUG_ASSERT(fixed == 1);
+ my_decimal tmp_buf, *tmp, *res= NULL;
+ null_value=1;
+ for (uint i=0; i < arg_count ; i++)
+ {
+ if (null_value)
+ {
+ res= args[i]->val_decimal(dec);
+ null_value= args[i]->null_value;
+ }
+ else
+ {
+ tmp= args[i]->val_decimal(&tmp_buf);
+ if (args[i]->null_value)
+ continue;
+ if ((my_decimal_cmp(tmp, res) * cmp_sign) < 0)
+ {
+ if (tmp == &tmp_buf)
+ {
+ my_decimal2decimal(tmp, dec);
+ res= dec;
+ }
+ else
+ res= tmp;
+ }
+ }
+ }
+ return res;
+}
+
+
longlong Item_func_length::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -1502,18 +2250,35 @@ longlong Item_func_field::val_int()
else if (cmp_type == INT_RESULT)
{
longlong val= args[0]->val_int();
+ if (args[0]->is_null())
+ return 0;
for (uint i=1; i < arg_count ; i++)
{
- if (val == args[i]->val_int())
+ if (val == args[i]->val_int() && ! args[i]->is_null())
return (longlong) (i);
}
}
+ else if (cmp_type == DECIMAL_RESULT)
+ {
+ my_decimal dec_arg_buf, *dec_arg,
+ dec_buf, *dec= args[0]->val_decimal(&dec_buf);
+ if (args[0]->is_null())
+ return 0;
+ for (uint i=1; i < arg_count; i++)
+ {
+ dec_arg= args[i]->val_decimal(&dec_arg_buf);
+ if (!args[i]->is_null() && !my_decimal_cmp(dec_arg, dec))
+ return (longlong) (i);
+ }
+ }
else
{
- double val= args[0]->val();
+ double val= args[0]->val_real();
+ if (args[0]->is_null())
+ return 0;
for (uint i=1; i < arg_count ; i++)
{
- if (val == args[i]->val())
+ if (val == args[i]->val_real() && ! args[i]->is_null())
return (longlong) (i);
}
}
@@ -1689,26 +2454,6 @@ longlong Item_func_bit_count::val_int()
#ifdef HAVE_DLOPEN
-udf_handler::~udf_handler()
-{
- if (!not_original)
- {
- if (initialized)
- {
- if (u_d->func_deinit != NULL)
- {
- void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*))
- u_d->func_deinit;
- (*deinit)(&initid);
- }
- free_udf(u_d);
- }
- if (buffers) // Because of bug in ecc
- delete [] buffers;
- }
-}
-
-
bool
udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
uint arg_count, Item **arguments)
@@ -1719,15 +2464,14 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
DBUG_ENTER("Item_udf_func::fix_fields");
if (check_stack_overrun(thd, buff))
- DBUG_RETURN(1); // Fatal error flag is set!
+ DBUG_RETURN(TRUE); // Fatal error flag is set!
udf_func *tmp_udf=find_udf(u_d->name.str,(uint) u_d->name.length,1);
if (!tmp_udf)
{
- my_printf_error(ER_CANT_FIND_UDF,ER(ER_CANT_FIND_UDF),MYF(0),u_d->name.str,
- errno);
- DBUG_RETURN(1);
+ my_error(ER_CANT_FIND_UDF, MYF(0), u_d->name.str, errno);
+ DBUG_RETURN(TRUE);
}
u_d=tmp_udf;
args=arguments;
@@ -1744,7 +2488,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
{
free_udf(u_d);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
uint i;
Item **arg,**arg_end;
@@ -1752,13 +2496,13 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
arg != arg_end ;
arg++,i++)
{
- if (!(*arg)->fixed &&
+ if (!(*arg)->fixed &&
(*arg)->fix_fields(thd, tables, arg))
DBUG_RETURN(1);
// we can't assign 'item' before, because fix_fields() can change arg
Item *item= *arg;
if (item->check_cols(1))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
/*
TODO: We should think about this. It is not always
right way just to set an UDF result to return my_charset_bin
@@ -1768,7 +2512,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
Moreover, some arguments can represent a numeric input
which doesn't effect the result character set and collation.
There is no a general rule for UDF. Everything depends on
- the particular user definted function.
+ the particular user defined function.
*/
if (item->collation.collation->state & MY_CS_BINSORT)
func->collation.set(&my_charset_bin);
@@ -1779,14 +2523,19 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
const_item_cache&=item->const_item();
f_args.arg_type[i]=item->result_type();
}
+ //TODO: why all following memory is not allocated with 1 call of sql_alloc?
if (!(buffers=new String[arg_count]) ||
!(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) ||
- !(f_args.lengths=(ulong*) sql_alloc(arg_count * sizeof(long))) ||
- !(f_args.maybe_null=(char*) sql_alloc(arg_count * sizeof(char))) ||
- !(num_buffer= (char*) sql_alloc(ALIGN_SIZE(sizeof(double))*arg_count)))
+ !(f_args.lengths= (ulong*) sql_alloc(arg_count * sizeof(long))) ||
+ !(f_args.maybe_null= (char*) sql_alloc(arg_count * sizeof(char))) ||
+ !(num_buffer= (char*) sql_alloc(arg_count *
+ ALIGN_SIZE(sizeof(double)))) ||
+ !(f_args.attributes= (char**) sql_alloc(arg_count * sizeof(char *))) ||
+ !(f_args.attribute_lengths= (ulong*) sql_alloc(arg_count *
+ sizeof(long))))
{
free_udf(u_d);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
}
func->fix_length_and_dec();
@@ -1802,8 +2551,10 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
for (uint i=0; i < arg_count; i++)
{
f_args.args[i]=0;
- f_args.lengths[i]=arguments[i]->max_length;
- f_args.maybe_null[i]=(char) arguments[i]->maybe_null;
+ f_args.lengths[i]= arguments[i]->max_length;
+ f_args.maybe_null[i]= (char) arguments[i]->maybe_null;
+ f_args.attributes[i]= arguments[i]->name;
+ f_args.attribute_lengths[i]= arguments[i]->name_length;
switch(arguments[i]->type()) {
case Item::STRING_ITEM: // Constant string !
@@ -1823,7 +2574,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
}
break;
case Item::REAL_ITEM:
- *((double*) to) = arguments[i]->val();
+ *((double*) to)= arguments[i]->val_real();
if (!arguments[i]->null_value)
{
f_args.args[i]=to;
@@ -1840,10 +2591,10 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
u_d->func_init;
if ((error=(uchar) init(&initid, &f_args, thd->net.last_error)))
{
- my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0),
- u_d->name.str, thd->net.last_error);
+ my_error(ER_CANT_INITIALIZE_UDF, MYF(0),
+ u_d->name.str, thd->net.last_error);
free_udf(u_d);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
func->max_length=min(initid.max_length,MAX_BLOB_WIDTH);
func->maybe_null=initid.maybe_null;
@@ -1853,11 +2604,11 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
initialized=1;
if (error)
{
- my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0),
- u_d->name.str, ER(ER_UNKNOWN_ERROR));
- DBUG_RETURN(1);
+ my_error(ER_CANT_INITIALIZE_UDF, MYF(0),
+ u_d->name.str, ER(ER_UNKNOWN_ERROR));
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -1872,6 +2623,7 @@ bool udf_handler::get_arguments()
f_args.args[i]=0;
switch (f_args.arg_type[i]) {
case STRING_RESULT:
+ case DECIMAL_RESULT:
{
String *res=args[i]->val_str(&buffers[str_count++]);
if (!(args[i]->null_value))
@@ -1890,7 +2642,7 @@ bool udf_handler::get_arguments()
}
break;
case REAL_RESULT:
- *((double*) to) = args[i]->val();
+ *((double*) to)= args[i]->val_real();
if (!args[i]->null_value)
{
f_args.args[i]=to;
@@ -1899,7 +2651,7 @@ bool udf_handler::get_arguments()
break;
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
@@ -1944,8 +2696,37 @@ String *udf_handler::val_str(String *str,String *save_str)
}
+/*
+ For the moment, UDF functions are returning DECIMAL values as strings
+*/
+
+my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf)
+{
+ char buf[DECIMAL_MAX_STR_LENGTH+1], *end;
+ ulong res_length= DECIMAL_MAX_STR_LENGTH;
+
+ if (get_arguments())
+ {
+ *null_value=1;
+ return 0;
+ }
+ char *(*func)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)=
+ (char* (*)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *))
+ u_d->func;
+
+ char *res= func(&initid, &f_args, buf, &res_length, &is_null, &error);
+ if (is_null || error)
+ {
+ *null_value= 1;
+ return 0;
+ }
+ end= res+ res_length;
+ str2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf, &end);
+ return dec_buf;
+}
+
-double Item_func_udf_float::val()
+double Item_func_udf_float::val_real()
{
DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_func_udf_float::val");
@@ -1958,7 +2739,7 @@ double Item_func_udf_float::val()
String *Item_func_udf_float::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- double nr=val();
+ double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
str->set(nr,decimals,&my_charset_bin);
@@ -1990,6 +2771,59 @@ String *Item_func_udf_int::val_str(String *str)
return str;
}
+
+longlong Item_func_udf_decimal::val_int()
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ longlong result;
+ if (null_value)
+ return 0;
+ my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
+ return result;
+}
+
+
+double Item_func_udf_decimal::val_real()
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ double result;
+ if (null_value)
+ return 0.0;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
+ return result;
+}
+
+
+my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf)
+{
+ DBUG_ASSERT(fixed == 1);
+ DBUG_ENTER("Item_func_udf_decimal::val_decimal");
+ DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ args[0]->result_type(), arg_count));
+
+ DBUG_RETURN(udf.val_decimal(&null_value, dec_buf));
+}
+
+
+String *Item_func_udf_decimal::val_str(String *str)
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0;
+ if (str->length() < DECIMAL_MAX_STR_LENGTH)
+ str->length(DECIMAL_MAX_STR_LENGTH);
+ my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
+ my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str);
+ return str;
+}
+
+
+void Item_func_udf_decimal::fix_length_and_dec()
+{
+ fix_num_length_and_dec();
+}
+
+
/* Default max_length is max argument length */
void Item_func_udf_str::fix_length_and_dec()
@@ -2009,6 +2843,31 @@ String *Item_func_udf_str::val_str(String *str)
return res;
}
+
+/*
+ This has to come last in the udf_handler methods, or C for AIX
+ version 6.0.0.0 fails to compile with debugging enabled. (Yes, really.)
+ */
+
+udf_handler::~udf_handler()
+{
+ if (!not_original)
+ {
+ if (initialized)
+ {
+ if (u_d->func_deinit != NULL)
+ {
+ void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*))
+ u_d->func_deinit;
+ (*deinit)(&initid);
+ }
+ free_udf(u_d);
+ }
+ if (buffers) // Because of bug in ecc
+ delete [] buffers;
+ }
+}
+
#else
bool udf_handler::get_arguments() { return 0; }
#endif /* HAVE_DLOPEN */
@@ -2092,18 +2951,6 @@ void item_user_lock_free(void)
void item_user_lock_release(User_level_lock *ull)
{
ull->locked=0;
- if (mysql_bin_log.is_open())
- {
- char buf[256];
- const char *command="DO RELEASE_LOCK(\"";
- String tmp(buf,sizeof(buf), system_charset_info);
- tmp.copy(command, strlen(command), tmp.charset());
- tmp.append(ull->key,ull->key_length);
- tmp.append("\")", 2);
- Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1, FALSE);
- qev.error_code=0; // this query is always safe to run on slave
- mysql_bin_log.write(&qev);
- }
if (--ull->count)
pthread_cond_signal(&ull->cond);
else
@@ -2227,6 +3074,16 @@ longlong Item_func_get_lock::val_int()
User_level_lock *ull;
int error=0;
+ /*
+ In slave thread no need to get locks, everything is serialized. Anyway
+ there is no way to make GET_LOCK() work on slave like it did on master
+ (i.e. make it return exactly the same value) because we don't have the
+ same other concurrent threads environment. No matter what we return here,
+ it's not guaranteed to be same as on master.
+ */
+ if (thd->slave_thread)
+ return 1;
+
pthread_mutex_lock(&LOCK_user_locks);
if (!res || !res->length())
@@ -2350,16 +3207,17 @@ longlong Item_func_release_lock::val_int()
longlong Item_func_last_insert_id::val_int()
{
+ THD *thd= current_thd;
DBUG_ASSERT(fixed == 1);
if (arg_count)
{
- longlong value=args[0]->val_int();
- current_thd->insert_id(value);
- null_value=args[0]->null_value;
+ longlong value= args[0]->val_int();
+ thd->insert_id(value);
+ null_value= args[0]->null_value;
+ return value; // Avoid side effect of insert_id()
}
- else
- current_thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- return current_thd->insert_id();
+ thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+ return thd->insert_id();
}
/* This function is just used to test speed of different functions */
@@ -2375,7 +3233,7 @@ longlong Item_func_benchmark::val_int()
{
switch (args[0]->result_type()) {
case REAL_RESULT:
- (void) args[0]->val();
+ (void) args[0]->val_real();
break;
case INT_RESULT:
(void) args[0]->val_int();
@@ -2385,7 +3243,7 @@ longlong Item_func_benchmark::val_int()
break;
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
return 0;
}
@@ -2464,7 +3322,7 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
/* fix_fields will call Item_func_set_user_var::fix_length_and_dec */
if (Item_func::fix_fields(thd, tables, ref) ||
!(entry= get_variable(&thd->user_vars, name, 1)))
- return 1;
+ return TRUE;
/*
Remember the last query which updated it, this way a query can later know
if this variable is a constant item in the query (it is if update_query_id
@@ -2486,11 +3344,12 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
from the argument if the argument is NULL
and the variable has previously been initialized.
*/
- if (!entry->collation.collation || !args[0]->null_value)
+ null_item= (args[0]->type() == NULL_ITEM);
+ if (!entry->collation.collation || !null_item)
entry->collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT);
collation.set(entry->collation.collation, DERIVATION_IMPLICIT);
cached_result_type= args[0]->result_type();
- return 0;
+ return FALSE;
}
@@ -2504,18 +3363,34 @@ Item_func_set_user_var::fix_length_and_dec()
}
-bool Item_func_set_user_var::update_hash(void *ptr, uint length,
- Item_result type,
- CHARSET_INFO *cs,
- Derivation dv)
+/*
+ Set value to user variable.
+
+ SYNOPSYS
+ update_hash()
+ entry - pointer to structure representing variable
+ set_null - should we set NULL value ?
+ ptr - pointer to buffer with new value
+ length - length of new value
+ type - type of new value
+ cs - charset info for new value
+ dv - derivation for new value
+
+ RETURN VALUE
+ False - success, True - failure
+*/
+
+static bool
+update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
+ Item_result type, CHARSET_INFO *cs, Derivation dv)
{
- if ((null_value=args[0]->null_value))
+ if (set_null)
{
char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
if (entry->value && entry->value != pos)
my_free(entry->value,MYF(0));
- entry->value=0;
- entry->length=0;
+ entry->value= 0;
+ entry->length= 0;
}
else
{
@@ -2542,7 +3417,7 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length,
entry->value=0;
if (!(entry->value=(char*) my_realloc(entry->value, length,
MYF(MY_ALLOW_ZERO_PTR))))
- goto err;
+ return 1;
}
}
if (type == STRING_RESULT)
@@ -2551,22 +3426,40 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length,
entry->value[length]= 0; // Store end \0
}
memcpy(entry->value,ptr,length);
+ if (type == DECIMAL_RESULT)
+ ((my_decimal*)entry->value)->fix_buffer_pointer();
entry->length= length;
- entry->type=type;
entry->collation.set(cs, dv);
}
+ entry->type=type;
return 0;
+}
- err:
- current_thd->fatal_error(); // Probably end of memory
- null_value= 1;
- return 1;
+
+bool
+Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type,
+ CHARSET_INFO *cs, Derivation dv)
+{
+ /*
+ If we set a variable explicitely to NULL then keep the old
+ result type of the variable
+ */
+ if ((null_value= args[0]->null_value) && null_item)
+ type= entry->type; // Don't change type of item
+ if (::update_hash(entry, (null_value= args[0]->null_value),
+ ptr, length, type, cs, dv))
+ {
+ current_thd->fatal_error(); // Probably end of memory
+ null_value= 1;
+ return 1;
+ }
+ return 0;
}
/* Get the value of a variable as a double */
-double user_var_entry::val(my_bool *null_value)
+double user_var_entry::val_real(my_bool *null_value)
{
if ((*null_value= (value == 0)))
return 0.0;
@@ -2576,6 +3469,12 @@ double user_var_entry::val(my_bool *null_value)
return *(double*) value;
case INT_RESULT:
return (double) *(longlong*) value;
+ case DECIMAL_RESULT:
+ {
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *)value, &result);
+ return result;
+ }
case STRING_RESULT:
return my_atof(value); // This is null terminated
case ROW_RESULT:
@@ -2598,6 +3497,12 @@ longlong user_var_entry::val_int(my_bool *null_value)
return (longlong) *(double*) value;
case INT_RESULT:
return *(longlong*) value;
+ case DECIMAL_RESULT:
+ {
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 1, &result);
+ return result;
+ }
case STRING_RESULT:
{
int error;
@@ -2626,6 +3531,9 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
case INT_RESULT:
str->set(*(longlong*) value, &my_charset_bin);
break;
+ case DECIMAL_RESULT:
+ my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str);
+ break;
case STRING_RESULT:
if (str->copy(value, length, collation.collation))
str= 0; // EOM error
@@ -2636,19 +3544,46 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
return(str);
}
+/* Get the value of a variable as a decimal */
+
+my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val)
+{
+ if ((*null_value= (value == 0)))
+ return 0;
+
+ switch (type) {
+ case REAL_RESULT:
+ double2my_decimal(E_DEC_FATAL_ERROR, *(double*) value, val);
+ break;
+ case INT_RESULT:
+ int2my_decimal(E_DEC_FATAL_ERROR, *(longlong*) value, 0, val);
+ break;
+ case DECIMAL_RESULT:
+ val= (my_decimal *)value;
+ break;
+ case STRING_RESULT:
+ str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val);
+ break;
+ case ROW_RESULT:
+ DBUG_ASSERT(1); // Impossible
+ break;
+ }
+ return(val);
+}
+
/*
This functions is invoked on SET @variable or @variable:= expression.
- Evaluete (and check expression), store results.
+ Evaluate (and check expression), store results.
SYNOPSYS
Item_func_set_user_var::check()
NOTES
- For now it always return OK. All problem with value evalueting
- will be catched by thd->net.report_error check in sql_set_variables().
+ For now it always return OK. All problem with value evaluating
+ will be caught by thd->net.report_error check in sql_set_variables().
RETURN
- 0 - OK.
+ FALSE OK.
*/
bool
@@ -2659,7 +3594,7 @@ Item_func_set_user_var::check()
switch (cached_result_type) {
case REAL_RESULT:
{
- save_result.vreal= args[0]->val();
+ save_result.vreal= args[0]->val_real();
break;
}
case INT_RESULT:
@@ -2672,13 +3607,18 @@ Item_func_set_user_var::check()
save_result.vstr= args[0]->val_str(&value);
break;
}
+ case DECIMAL_RESULT:
+ {
+ save_result.vdec= args[0]->val_decimal(&decimal_buff);
+ break;
+ }
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -2693,7 +3633,7 @@ Item_func_set_user_var::check()
the value method used by the user
RETURN
- 0 Ok
+ 0 OK
1 EOM Error
*/
@@ -2730,9 +3670,20 @@ Item_func_set_user_var::update()
DERIVATION_IMPLICIT);
break;
}
+ case DECIMAL_RESULT:
+ {
+ if (!save_result.vdec) // Null value
+ res= update_hash((void*) 0, 0, DECIMAL_RESULT, &my_charset_bin,
+ DERIVATION_IMPLICIT);
+ else
+ res= update_hash((void*) save_result.vdec,
+ sizeof(my_decimal), DECIMAL_RESULT,
+ &my_charset_bin, DERIVATION_IMPLICIT);
+ break;
+ }
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
@@ -2740,12 +3691,12 @@ Item_func_set_user_var::update()
}
-double Item_func_set_user_var::val()
+double Item_func_set_user_var::val_real()
{
DBUG_ASSERT(fixed == 1);
check();
update(); // Store expression
- return entry->val(&null_value);
+ return entry->val_real(&null_value);
}
longlong Item_func_set_user_var::val_int()
@@ -2765,6 +3716,15 @@ String *Item_func_set_user_var::val_str(String *str)
}
+my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed == 1);
+ check();
+ update(); // Store expression
+ return entry->val_decimal(&null_value, val);
+}
+
+
void Item_func_set_user_var::print(String *str)
{
str->append("(@", 2);
@@ -2775,6 +3735,16 @@ void Item_func_set_user_var::print(String *str)
}
+void Item_func_set_user_var::print_as_stmt(String *str)
+{
+ str->append("set @", 5);
+ str->append(name.str, name.length);
+ str->append(":=", 2);
+ args[0]->print(str);
+ str->append(')');
+}
+
+
String *
Item_func_get_user_var::val_str(String *str)
{
@@ -2786,12 +3756,21 @@ Item_func_get_user_var::val_str(String *str)
}
-double Item_func_get_user_var::val()
+double Item_func_get_user_var::val_real()
{
DBUG_ASSERT(fixed == 1);
if (!var_entry)
return 0.0; // No such variable
- return (var_entry->val(&null_value));
+ return (var_entry->val_real(&null_value));
+}
+
+
+my_decimal *Item_func_get_user_var::val_decimal(my_decimal *dec)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (!var_entry)
+ return 0;
+ return var_entry->val_decimal(&null_value, dec);
}
@@ -2822,7 +3801,7 @@ longlong Item_func_get_user_var::val_int()
RETURN
0 OK
- 1 Failed to put appropiate record into binary log
+ 1 Failed to put appropriate record into binary log
*/
@@ -2846,8 +3825,8 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name,
that it gets into the binlog (if it didn't, the slave could be
influenced by a variable of the same name previously set by another
thread).
- We create it like if it had been explicitely set with SET before.
- The 'new' mimicks what sql_yacc.yy does when 'SET @a=10;'.
+ We create it like if it had been explicitly set with SET before.
+ The 'new' mimics what sql_yacc.yy does when 'SET @a=10;'.
sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION'
in dispatch_command()). Instead of building a one-element list to pass to
sql_set_variables(), we could instead manually call check() and update();
@@ -2878,7 +3857,7 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name,
uint size;
/*
First we need to store value of var_entry, when the next situation
- appers:
+ appears:
> set @a:=1;
> insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
We have to write to binlog value @a= 1;
@@ -2940,7 +3919,13 @@ void Item_func_get_user_var::fix_length_and_dec()
case STRING_RESULT:
max_length= MAX_BLOB_WIDTH;
break;
+ case DECIMAL_RESULT:
+ max_length= DECIMAL_MAX_LENGTH;
+ decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1);
+ break;
case ROW_RESULT: // Keep compiler happy
+ default:
+ DBUG_ASSERT(0);
break;
}
}
@@ -2997,6 +3982,77 @@ 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)
+{
+ DBUG_ASSERT(fixed == 0);
+ if (Item::fix_fields(thd, tables, ref) ||
+ !(entry= get_variable(&thd->user_vars, name, 1)))
+ return TRUE;
+ entry->type= STRING_RESULT;
+ /*
+ Let us set the same collation which is used for loading
+ of fields in LOAD DATA INFILE.
+ (Since Item_user_var_as_out_param is used only there).
+ */
+ entry->collation.set(thd->variables.collation_database);
+ entry->update_query_id= thd->query_id;
+ return FALSE;
+}
+
+
+void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs)
+{
+ if (::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs,
+ DERIVATION_IMPLICIT))
+ current_thd->fatal_error(); // Probably end of memory
+}
+
+
+void Item_user_var_as_out_param::set_value(const char *str, uint length,
+ CHARSET_INFO* cs)
+{
+ if (::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs,
+ DERIVATION_IMPLICIT))
+ current_thd->fatal_error(); // Probably end of memory
+}
+
+
+double Item_user_var_as_out_param::val_real()
+{
+ DBUG_ASSERT(0);
+ return 0.0;
+}
+
+
+longlong Item_user_var_as_out_param::val_int()
+{
+ DBUG_ASSERT(0);
+ return 0;
+}
+
+
+String* Item_user_var_as_out_param::val_str(String *str)
+{
+ DBUG_ASSERT(0);
+ return 0;
+}
+
+
+my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer)
+{
+ DBUG_ASSERT(0);
+ return 0;
+}
+
+
+void Item_user_var_as_out_param::print(String *str)
+{
+ str->append('@');
+ str->append(name.str,name.length);
+}
+
+
longlong Item_func_inet_aton::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -3132,7 +4188,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
!args[0]->const_during_execution())
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST");
- return 1;
+ return TRUE;
}
const_item_cache=0;
@@ -3155,7 +4211,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
if (key == NO_SUCH_KEY && !(flags & FT_BOOL))
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
- return 1;
+ return TRUE;
}
table=((Item_field *)item)->field->table;
table->fulltext_searched=1;
@@ -3171,7 +4227,7 @@ bool Item_func_match::fix_index()
if (key == NO_SUCH_KEY)
return 0;
- for (keynr=0 ; keynr < table->keys ; keynr++)
+ for (keynr=0 ; keynr < table->s->keys ; keynr++)
{
if ((table->key_info[keynr].flags & HA_FULLTEXT) &&
(table->keys_in_use_for_query.is_set(keynr)))
@@ -3237,7 +4293,8 @@ err:
key=NO_SUCH_KEY;
return 0;
}
- my_error(ER_FT_MATCHING_KEY_NOT_FOUND,MYF(0));
+ my_message(ER_FT_MATCHING_KEY_NOT_FOUND,
+ ER(ER_FT_MATCHING_KEY_NOT_FOUND), MYF(0));
return 1;
}
@@ -3258,7 +4315,7 @@ bool Item_func_match::eq(const Item *item, bool binary_cmp) const
}
-double Item_func_match::val()
+double Item_func_match::val_real()
{
DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_func_match::val");
@@ -3366,7 +4423,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
{
if (!var->is_struct())
{
- net_printf(thd, ER_VARIABLE_IS_NOT_STRUCT, base_name->str);
+ my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), base_name->str);
return 0;
}
}
@@ -3474,6 +4531,271 @@ longlong Item_func_is_used_lock::val_int()
}
+longlong Item_func_row_count::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ THD *thd= current_thd;
+
+ return thd->row_count_func;
+}
+
+
+Item_func_sp::Item_func_sp(sp_name *name)
+ :Item_func(), m_name(name), m_sp(NULL), result_field(NULL)
+{
+ maybe_null= 1;
+ m_name->init_qname(current_thd);
+ dummy_table= (TABLE*) sql_calloc(sizeof(TABLE));
+}
+
+
+Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list)
+ :Item_func(list), m_name(name), m_sp(NULL), result_field(NULL)
+{
+ maybe_null= 1;
+ m_name->init_qname(current_thd);
+ dummy_table= (TABLE*) sql_calloc(sizeof(TABLE));
+}
+
+
+const char *
+Item_func_sp::func_name() const
+{
+ THD *thd= current_thd;
+ /* Calculate length to avoid reallocation of string for sure */
+ uint len= ((m_name->m_db.length +
+ m_name->m_name.length)*2 + //characters*quoting
+ 2 + // ` and `
+ 1 + // .
+ 1 + // end of string
+ ALIGN_SIZE(1)); // to avoid String reallocation
+ String qname((char *)alloc_root(thd->mem_root, len), len,
+ system_charset_info);
+
+ qname.length(0);
+ append_identifier(thd, &qname, m_name->m_db.str, m_name->m_db.length);
+ qname.append('.');
+ append_identifier(thd, &qname, m_name->m_name.str, m_name->m_name.length);
+ return qname.ptr();
+}
+
+
+Field *
+Item_func_sp::sp_result_field(void) const
+{
+ Field *field= 0;
+ THD *thd= current_thd;
+ DBUG_ENTER("Item_func_sp::sp_result_field");
+ if (m_sp)
+ {
+ if (dummy_table->s == NULL)
+ {
+ char *empty_name= (char *) "";
+ TABLE_SHARE *share;
+ dummy_table->s= share= &dummy_table->share_not_to_be_used;
+ dummy_table->alias = empty_name;
+ dummy_table->maybe_null = maybe_null;
+ dummy_table->in_use= current_thd;
+ share->table_cache_key = empty_name;
+ share->table_name = empty_name;
+ share->table_name = empty_name;
+ }
+ field= m_sp->make_field(max_length, name, dummy_table);
+ }
+ DBUG_RETURN(field);
+}
+
+
+int
+Item_func_sp::execute(Field **flp)
+{
+ Item *it;
+ Field *f;
+ if (execute(&it))
+ {
+ null_value= 1;
+ return 1;
+ }
+ if (!(f= *flp))
+ {
+ *flp= f= sp_result_field();
+ f->move_field((f->pack_length() > sizeof(result_buf)) ?
+ sql_alloc(f->pack_length()) : result_buf);
+ f->null_ptr= (uchar *)&null_value;
+ f->null_bit= 1;
+ }
+ it->save_in_field(f, 1);
+ return f->is_null();
+}
+
+
+int
+Item_func_sp::execute(Item **itp)
+{
+ DBUG_ENTER("Item_func_sp::execute");
+ THD *thd= current_thd;
+ ulong old_client_capabilites;
+ int res;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ st_sp_security_context save_ctx;
+#endif
+
+ if (! m_sp)
+ m_sp= sp_find_function(thd, m_name, TRUE); // cache only
+ if (! m_sp)
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ DBUG_RETURN(-1);
+ }
+
+ old_client_capabilites= thd->client_capabilities;
+ thd->client_capabilities &= ~CLIENT_MULTI_RESULTS;
+
+#ifndef EMBEDDED_LIBRARY
+ my_bool nsok= thd->net.no_send_ok;
+ thd->net.no_send_ok= TRUE;
+#endif
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_procedure_access(thd, EXECUTE_ACL,
+ m_sp->m_db.str, m_sp->m_name.str, 0))
+ DBUG_RETURN(-1);
+ sp_change_security_context(thd, m_sp, &save_ctx);
+ if (save_ctx.changed &&
+ check_procedure_access(thd, EXECUTE_ACL,
+ m_sp->m_db.str, m_sp->m_name.str, 0))
+ {
+ sp_restore_security_context(thd, m_sp, &save_ctx);
+ thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS;
+ DBUG_RETURN(-1);
+ }
+#endif
+
+ res= m_sp->execute_function(thd, args, arg_count, itp);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ sp_restore_security_context(thd, m_sp, &save_ctx);
+#endif
+
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+
+ thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS;
+
+ DBUG_RETURN(res);
+}
+
+
+void
+Item_func_sp::make_field(Send_field *tmp_field)
+{
+ Field *field;
+ DBUG_ENTER("Item_func_sp::make_field");
+ if (! m_sp)
+ m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
+ if ((field= sp_result_field()))
+ {
+ field->make_field(tmp_field);
+ delete field;
+ DBUG_VOID_RETURN;
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ init_make_field(tmp_field, MYSQL_TYPE_VARCHAR);
+ DBUG_VOID_RETURN;
+}
+
+
+enum enum_field_types
+Item_func_sp::field_type() const
+{
+ Field *field= 0;
+ DBUG_ENTER("Item_func_sp::field_type");
+
+ if (result_field)
+ DBUG_RETURN(result_field->type());
+ if (! m_sp)
+ m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
+ if ((field= sp_result_field()))
+ {
+ enum_field_types result= field->type();
+ delete field;
+ DBUG_RETURN(result);
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ DBUG_RETURN(MYSQL_TYPE_VARCHAR);
+}
+
+
+Item_result
+Item_func_sp::result_type() const
+{
+ Field *field= 0;
+ DBUG_ENTER("Item_func_sp::result_type");
+ DBUG_PRINT("info", ("m_sp = %p", m_sp));
+
+ if (result_field)
+ DBUG_RETURN(result_field->result_type());
+ if (! m_sp)
+ m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
+ if ((field= sp_result_field()))
+ {
+ Item_result result= field->result_type();
+ delete field;
+ DBUG_RETURN(result);
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ DBUG_RETURN(STRING_RESULT);
+}
+
+void
+Item_func_sp::fix_length_and_dec()
+{
+ Field *field= result_field;
+ DBUG_ENTER("Item_func_sp::fix_length_and_dec");
+
+ if (result_field)
+ {
+ decimals= result_field->decimals();
+ max_length= result_field->representation_length();
+ DBUG_VOID_RETURN;
+ }
+
+ if (! m_sp)
+ m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
+ if (! m_sp)
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ }
+ else
+ {
+ if (!field)
+ field= sp_result_field();
+
+ decimals= field->decimals();
+ max_length= field->representation_length();
+
+ switch (field->result_type()) {
+ case STRING_RESULT:
+ maybe_null= 1;
+ case REAL_RESULT:
+ case INT_RESULT:
+ case DECIMAL_RESULT:
+ break;
+ case ROW_RESULT:
+ default:
+ // This case should never be chosen
+ DBUG_ASSERT(0);
+ break;
+ }
+
+ if (field != result_field)
+ delete field;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
longlong Item_func_found_rows::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -3481,3 +4803,18 @@ longlong Item_func_found_rows::val_int()
return thd->found_rows();
}
+
+Field *
+Item_func_sp::tmp_table_field(TABLE *t_arg)
+{
+ Field *res= 0;
+ DBUG_ENTER("Item_func_sp::tmp_table_field");
+
+ if (m_sp)
+ res= m_sp->make_field(max_length, (const char *)name, t_arg);
+
+ if (!res)
+ res= Item_func::tmp_table_field(t_arg);
+
+ DBUG_RETURN(res);
+}
diff --git a/sql/item_func.h b/sql/item_func.h
index 288db3a148c..76d1151f3bf 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -44,15 +44,19 @@ public:
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
GE_FUNC,GT_FUNC,FT_FUNC,
LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
- COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, BETWEEN, IN_FUNC,
+ COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC,
+ BETWEEN, IN_FUNC, MULT_EQUAL_FUNC,
INTERVAL_FUNC, ISNOTNULLTEST_FUNC,
SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC,
SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC,
SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC,
SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING,
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
- NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, VAR_VALUE_FUNC};
- enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL };
+ NOT_FUNC, NOT_ALL_FUNC,
+ NOW_FUNC, TRIG_COND_FUNC,
+ GUSERVAR_FUNC};
+ enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL,
+ OPTIMIZE_EQUAL };
enum Type type() const { return FUNC_ITEM; }
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
Item_func(void):
@@ -129,7 +133,10 @@ public:
void print(String *str);
void print_op(String *str);
void print_args(String *str, uint from);
- void fix_num_length_and_dec();
+ virtual void fix_num_length_and_dec();
+ void count_only_length();
+ void count_real_length();
+ void count_decimal_length();
inline bool get_arg0_date(TIME *ltime, uint fuzzy_date)
{
return (null_value=args[0]->get_date(ltime, fuzzy_date));
@@ -139,11 +146,14 @@ public:
return (null_value=args[0]->get_time(ltime));
}
bool is_null() { (void) val_int(); return null_value; }
+ void signal_divide_by_null();
friend class udf_handler;
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg);
Item *get_tmp_table_item(THD *thd);
-
+
+ my_decimal *val_decimal(my_decimal *);
+
bool agg_arg_collations(DTCollation &c, Item **items, uint nitems,
uint flags= 0);
bool agg_arg_collations_for_comparison(DTCollation &c,
@@ -152,6 +162,9 @@ public:
bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems,
uint flags= 0);
bool walk(Item_processor processor, byte *arg);
+ Item *transform(Item_transformer transformer, byte *arg);
+ void traverse_cond(Cond_traverser traverser,
+ void * arg, traverse_order order);
};
@@ -163,52 +176,75 @@ 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);
- longlong val_int() { DBUG_ASSERT(fixed == 1); return (longlong) val(); }
+ longlong val_int()
+ { DBUG_ASSERT(fixed == 1); return (longlong) val_real(); }
enum Item_result result_type () const { return REAL_RESULT; }
- void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
+ void fix_length_and_dec()
+ { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); }
};
-class Item_num_func :public Item_func
+class Item_func_numhybrid: public Item_func
{
- protected:
+protected:
Item_result hybrid_type;
public:
- Item_num_func(Item *a) :Item_func(a),hybrid_type(REAL_RESULT) {}
- Item_num_func(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {}
- String *val_str(String*str);
- longlong val_int() { DBUG_ASSERT(fixed == 1); return (longlong) val(); }
+ Item_func_numhybrid(Item *a) :Item_func(a),hybrid_type(REAL_RESULT)
+ {}
+ Item_func_numhybrid(Item *a,Item *b)
+ :Item_func(a,b),hybrid_type(REAL_RESULT)
+ {}
+
enum Item_result result_type () const { return hybrid_type; }
- void fix_length_and_dec() { fix_num_length_and_dec(); }
- bool is_null() { (void) val(); return null_value; }
+ void fix_length_and_dec();
+ void fix_num_length_and_dec();
+ virtual void find_num_type()= 0; /* To be called from fix_length_and_dec */
+
+ double val_real();
+ longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
+ String *val_str(String*str);
+
+ virtual longlong int_op()= 0;
+ virtual double real_op()= 0;
+ virtual my_decimal *decimal_op(my_decimal *)= 0;
+ bool is_null() { (void) val_real(); return null_value; }
+};
+
+/* function where type of result detected by first argument */
+class Item_func_num1: public Item_func_numhybrid
+{
+public:
+ Item_func_num1(Item *a) :Item_func_numhybrid(a) {}
+ Item_func_num1(Item *a, Item *b) :Item_func_numhybrid(a, b) {}
+
+ void fix_num_length_and_dec();
+ void find_num_type();
};
-class Item_num_op :public Item_func
+/* Base class for operations like '+', '-', '*' */
+class Item_num_op :public Item_func_numhybrid
{
- protected:
- Item_result hybrid_type;
public:
- Item_num_op(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {}
- String *val_str(String*str);
+ Item_num_op(Item *a,Item *b) :Item_func_numhybrid(a, b) {}
+ virtual void result_precision()= 0;
void print(String *str) { print_op(str); }
- enum Item_result result_type () const { return hybrid_type; }
- void fix_length_and_dec() { fix_num_length_and_dec(); find_num_type(); }
- void find_num_type(void);
- bool is_null() { (void) val(); return null_value; }
+ void find_num_type();
};
class Item_int_func :public Item_func
{
public:
- Item_int_func() :Item_func() { max_length=21; }
- Item_int_func(Item *a) :Item_func(a) { max_length=21; }
- Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length=21; }
- Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { max_length=21; }
- Item_int_func(List<Item> &list) :Item_func(list) { max_length=21; }
+ Item_int_func() :Item_func() { max_length= 21; }
+ Item_int_func(Item *a) :Item_func(a) { max_length= 21; }
+ Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length= 21; }
+ Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c)
+ { max_length= 21; }
+ Item_int_func(List<Item> &list) :Item_func(list) { max_length= 21; }
Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) {}
- double val() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() {}
@@ -220,9 +256,9 @@ class Item_func_signed :public Item_int_func
public:
Item_func_signed(Item *a) :Item_int_func(a) {}
const char *func_name() const { return "cast_as_signed"; }
- double val()
+ double val_real()
{
- double tmp= args[0]->val();
+ double tmp= args[0]->val_real();
null_value= args[0]->null_value;
return tmp;
}
@@ -246,22 +282,51 @@ public:
};
-class Item_func_plus :public Item_num_op
+class Item_decimal_typecast :public Item_func
{
+ my_decimal decimal_value;
public:
- Item_func_plus(Item *a,Item *b) :Item_num_op(a,b) {}
- const char *func_name() const { return "+"; }
- double val();
+ Item_decimal_typecast(Item *a, int len, int dec) :Item_func(a)
+ {
+ max_length= len + 2;
+ decimals= dec;
+ }
+ String *val_str(String *str);
+ double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal*);
+ enum Item_result result_type () const { return DECIMAL_RESULT; }
+ enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; }
+ void fix_length_and_dec() {};
};
-class Item_func_minus :public Item_num_op
+
+class Item_func_additive_op :public Item_num_op
+{
+public:
+ Item_func_additive_op(Item *a,Item *b) :Item_num_op(a,b) {}
+ void result_precision();
+};
+
+
+class Item_func_plus :public Item_func_additive_op
{
public:
- Item_func_minus(Item *a,Item *b) :Item_num_op(a,b) {}
+ Item_func_plus(Item *a,Item *b) :Item_func_additive_op(a,b) {}
+ const char *func_name() const { return "+"; }
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
+};
+
+class Item_func_minus :public Item_func_additive_op
+{
+public:
+ Item_func_minus(Item *a,Item *b) :Item_func_additive_op(a,b) {}
const char *func_name() const { return "-"; }
- double val();
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
void fix_length_and_dec();
};
@@ -271,8 +336,10 @@ class Item_func_mul :public Item_num_op
public:
Item_func_mul(Item *a,Item *b) :Item_num_op(a,b) {}
const char *func_name() const { return "*"; }
- double val();
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
+ void result_precision();
};
@@ -280,22 +347,24 @@ class Item_func_div :public Item_num_op
{
public:
Item_func_div(Item *a,Item *b) :Item_num_op(a,b) {}
- double val();
- longlong val_int();
+ longlong int_op() { DBUG_ASSERT(0); return 0; }
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "/"; }
void fix_length_and_dec();
+ void result_precision();
};
-class Item_func_int_div :public Item_num_op
+class Item_func_int_div :public Item_int_func
{
public:
- Item_func_int_div(Item *a,Item *b) :Item_num_op(a,b)
- { hybrid_type=INT_RESULT; }
- double val() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+ Item_func_int_div(Item *a,Item *b) :Item_int_func(a,b)
+ {}
longlong val_int();
const char *func_name() const { return "DIV"; }
void fix_length_and_dec();
+ void print(String *str) { print_op(str); }
};
@@ -303,37 +372,39 @@ class Item_func_mod :public Item_num_op
{
public:
Item_func_mod(Item *a,Item *b) :Item_num_op(a,b) {}
- double val();
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "%"; }
- void fix_length_and_dec();
+ void result_precision();
};
-class Item_func_neg :public Item_num_func
+class Item_func_neg :public Item_func_num1
{
public:
- Item_func_neg(Item *a) :Item_num_func(a) {}
- double val();
- longlong val_int();
+ Item_func_neg(Item *a) :Item_func_num1(a) {}
+ double real_op();
+ longlong int_op();
+ my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "-"; }
void fix_length_and_dec();
+ void fix_num_length_and_dec();
};
-class Item_func_abs :public Item_num_func
+class Item_func_abs :public Item_func_num1
{
public:
- Item_func_abs(Item *a) :Item_num_func(a) {}
+ Item_func_abs(Item *a) :Item_func_num1(a) {}
+ double real_op();
+ longlong int_op();
+ my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "abs"; }
- double val();
- longlong val_int();
- enum Item_result result_type () const
- { return args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT; }
void fix_length_and_dec();
};
-// A class to handle logaritmic and trigometric functions
+// A class to handle logarithmic and trigonometric functions
class Item_dec_func :public Item_real_func
{
@@ -363,7 +434,7 @@ class Item_func_exp :public Item_dec_func
{
public:
Item_func_exp(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "exp"; }
};
@@ -372,7 +443,7 @@ class Item_func_ln :public Item_dec_func
{
public:
Item_func_ln(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "ln"; }
};
@@ -382,7 +453,7 @@ class Item_func_log :public Item_dec_func
public:
Item_func_log(Item *a) :Item_dec_func(a) {}
Item_func_log(Item *a,Item *b) :Item_dec_func(a,b) {}
- double val();
+ double val_real();
const char *func_name() const { return "log"; }
};
@@ -391,7 +462,7 @@ class Item_func_log2 :public Item_dec_func
{
public:
Item_func_log2(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "log2"; }
};
@@ -400,7 +471,7 @@ class Item_func_log10 :public Item_dec_func
{
public:
Item_func_log10(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "log10"; }
};
@@ -409,7 +480,7 @@ class Item_func_sqrt :public Item_dec_func
{
public:
Item_func_sqrt(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "sqrt"; }
};
@@ -418,7 +489,7 @@ class Item_func_pow :public Item_dec_func
{
public:
Item_func_pow(Item *a,Item *b) :Item_dec_func(a,b) {}
- double val();
+ double val_real();
const char *func_name() const { return "pow"; }
};
@@ -427,7 +498,7 @@ class Item_func_acos :public Item_dec_func
{
public:
Item_func_acos(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "acos"; }
};
@@ -435,7 +506,7 @@ class Item_func_asin :public Item_dec_func
{
public:
Item_func_asin(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "asin"; }
};
@@ -444,7 +515,7 @@ class Item_func_atan :public Item_dec_func
public:
Item_func_atan(Item *a) :Item_dec_func(a) {}
Item_func_atan(Item *a,Item *b) :Item_dec_func(a,b) {}
- double val();
+ double val_real();
const char *func_name() const { return "atan"; }
};
@@ -452,7 +523,7 @@ class Item_func_cos :public Item_dec_func
{
public:
Item_func_cos(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "cos"; }
};
@@ -460,7 +531,7 @@ class Item_func_sin :public Item_dec_func
{
public:
Item_func_sin(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "sin"; }
};
@@ -468,7 +539,7 @@ class Item_func_tan :public Item_dec_func
{
public:
Item_func_tan(Item *a) :Item_dec_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "tan"; }
};
@@ -480,34 +551,49 @@ public:
};
-class Item_func_ceiling :public Item_func_integer
+class Item_func_int_val :public Item_func_num1
+{
+public:
+ Item_func_int_val(Item *a) :Item_func_num1(a) {}
+ void fix_num_length_and_dec();
+ void find_num_type();
+};
+
+
+class Item_func_ceiling :public Item_func_int_val
{
- Item_func_ceiling(); /* Never called */
public:
- Item_func_ceiling(Item *a) :Item_func_integer(a) {}
+ Item_func_ceiling(Item *a) :Item_func_int_val(a) {}
const char *func_name() const { return "ceiling"; }
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
};
-class Item_func_floor :public Item_func_integer
+
+class Item_func_floor :public Item_func_int_val
{
public:
- Item_func_floor(Item *a) :Item_func_integer(a) {}
+ Item_func_floor(Item *a) :Item_func_int_val(a) {}
const char *func_name() const { return "floor"; }
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
};
/* This handles round and truncate */
-class Item_func_round :public Item_real_func
+class Item_func_round :public Item_func_num1
{
bool truncate;
public:
- Item_func_round(Item *a,Item *b,bool trunc_arg)
- :Item_real_func(a,b),truncate(trunc_arg) {}
+ Item_func_round(Item *a, Item *b, bool trunc_arg)
+ :Item_func_num1(a,b), truncate(trunc_arg) {}
const char *func_name() const { return truncate ? "truncate" : "round"; }
- double val();
- void fix_length_and_dec();
+ double real_op();
+ longlong int_op();
+ my_decimal *decimal_op(my_decimal *);
+ void fix_num_length_and_dec();
};
@@ -517,7 +603,7 @@ class Item_func_rand :public Item_real_func
public:
Item_func_rand(Item *a) :Item_real_func(a), rand(0) {}
Item_func_rand() :Item_real_func() {}
- double val();
+ double val_real();
const char *func_name() const { return "rand"; }
bool const_item() const { return 0; }
void update_used_tables();
@@ -541,9 +627,10 @@ class Item_func_units :public Item_real_func
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();
+ double val_real();
const char *func_name() const { return name; }
- void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
+ void fix_length_and_dec()
+ { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); }
};
@@ -555,9 +642,10 @@ class Item_func_min_max :public Item_func
public:
Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list),
cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg) {}
- double val();
+ double val_real();
longlong val_int();
String *val_str(String *);
+ my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec();
enum Item_result result_type () const { return cmp_type; }
table_map not_null_tables() const { return 0; }
@@ -745,7 +833,11 @@ public:
Item_func_last_insert_id(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "last_insert_id"; }
- void fix_length_and_dec() { if (arg_count) max_length= args[0]->max_length; }
+ void fix_length_and_dec()
+ {
+ if (arg_count)
+ max_length= args[0]->max_length;
+ }
};
class Item_func_benchmark :public Item_int_func
@@ -795,8 +887,19 @@ class Item_func_udf_float :public Item_udf_func
Item_func_udf_float(udf_func *udf_arg, List<Item> &list)
:Item_udf_func(udf_arg,list) {}
longlong val_int()
- { DBUG_ASSERT(fixed == 1); return (longlong) Item_func_udf_float::val(); }
- double val();
+ {
+ DBUG_ASSERT(fixed == 1);
+ return (longlong) Item_func_udf_float::val_real();
+ }
+ my_decimal *val_decimal(my_decimal *dec_buf)
+ {
+ double res=val_real();
+ if (null_value)
+ return NULL;
+ double2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf);
+ return dec_buf;
+ }
+ double val_real();
String *val_str(String *str);
void fix_length_and_dec() { fix_num_length_and_dec(); }
};
@@ -809,10 +912,25 @@ public:
Item_func_udf_int(udf_func *udf_arg, List<Item> &list)
:Item_udf_func(udf_arg,list) {}
longlong val_int();
- double val() { return (double) Item_func_udf_int::val_int(); }
+ double val_real() { return (double) Item_func_udf_int::val_int(); }
String *val_str(String *str);
enum Item_result result_type () const { return INT_RESULT; }
- void fix_length_and_dec() { decimals=0; max_length=21; }
+ void fix_length_and_dec() { decimals= 0; max_length= 21; }
+};
+
+
+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, List<Item> &list)
+ :Item_udf_func(udf_arg,list) {}
+ longlong val_int();
+ double val_real();
+ my_decimal *val_decimal(my_decimal *);
+ String *val_str(String *str);
+ enum Item_result result_type () const { return DECIMAL_RESULT; }
+ void fix_length_and_dec();
};
@@ -823,20 +941,29 @@ public:
Item_func_udf_str(udf_func *udf_arg, List<Item> &list)
:Item_udf_func(udf_arg,list) {}
String *val_str(String *);
- double val()
+ double val_real()
{
- int err;
- String *res;
+ int err_not_used;
char *end_not_used;
- res=val_str(&str_value);
- return res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
- &end_not_used, &err) : 0.0;
+ String *res;
+ res= val_str(&str_value);
+ return res ? my_strntod(res->charset(),(char*) res->ptr(),
+ res->length(), &end_not_used, &err_not_used) : 0.0;
}
longlong val_int()
{
- int err;
+ int err_not_used;
String *res; res=val_str(&str_value);
- return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,(char**) 0,&err) : (longlong) 0;
+ return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,
+ (char**) 0, &err_not_used) : (longlong) 0;
+ }
+ my_decimal *val_decimal(my_decimal *dec_buf)
+ {
+ String *res=val_str(&str_value);
+ if (!res)
+ return NULL;
+ string2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf);
+ return dec_buf;
}
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
@@ -849,7 +976,7 @@ 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) {}
- double val() { DBUG_ASSERT(fixed == 1); return 0.0; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
};
@@ -862,6 +989,15 @@ 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) {}
+ my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; }
+};
+
+
class Item_func_udf_str :public Item_func
{
public:
@@ -869,7 +1005,7 @@ public:
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() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; }
+ double val_real() { DBUG_ASSERT(fixed == 1); null_value= 1; return 0.0; }
longlong val_int() { DBUG_ASSERT(fixed == 1); null_value=1; return 0; }
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec() { maybe_null=1; max_length=0; }
@@ -920,7 +1056,7 @@ class Item_master_pos_wait :public Item_int_func
};
-/* Handling of user definiable variables */
+/* Handling of user definable variables */
class user_var_entry;
@@ -931,11 +1067,14 @@ class Item_func_set_user_var :public Item_func
user_var_entry *entry;
char buffer[MAX_FIELD_WIDTH];
String value;
+ my_decimal decimal_buff;
+ bool null_item;
union
{
longlong vint;
double vreal;
String *vstr;
+ my_decimal *vdec;
} save_result;
String save_buff;
@@ -944,9 +1083,10 @@ public:
Item_func_set_user_var(LEX_STRING a,Item *b)
:Item_func(b), cached_result_type(INT_RESULT), name(a)
{}
- double val();
+ double val_real();
longlong val_int();
String *val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
bool update_hash(void *ptr, uint length, enum Item_result type,
CHARSET_INFO *cs, Derivation dv);
bool check();
@@ -955,6 +1095,7 @@ public:
bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref);
void fix_length_and_dec();
void print(String *str);
+ void print_as_stmt(String *str);
const char *func_name() const { return "set_user_var"; }
};
@@ -967,8 +1108,11 @@ class Item_func_get_user_var :public Item_func
public:
Item_func_get_user_var(LEX_STRING a):
Item_func(), name(a) {}
- double val();
+ enum Functype functype() const { return GUSERVAR_FUNC; }
+ LEX_STRING get_name() { return name; }
+ double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal*);
String *val_str(String* str);
void fix_length_and_dec();
void print(String *str);
@@ -977,8 +1121,7 @@ public:
We must always return variables as strings to guard against selects of type
select @t1:=1,@t1,@t:="hello",@t from foo where (@t1:= t2.b)
*/
- enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
- enum Functype functype() const { return VAR_VALUE_FUNC; }
+ enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
const char *func_name() const { return "get_user_var"; }
bool const_item() const;
table_map used_tables() const
@@ -987,6 +1130,35 @@ public:
};
+/*
+ This item represents user variable used as out parameter (e.g in LOAD DATA),
+ and it is supposed to be used only for this purprose. So it is simplified
+ a lot. Actually you should never obtain its value.
+
+ The only two reasons for this thing being an Item is possibility to store it
+ in List<Item> and desire to place this code somewhere near other functions
+ working with user variables.
+*/
+class Item_user_var_as_out_param :public Item
+{
+ LEX_STRING name;
+ user_var_entry *entry;
+public:
+ Item_user_var_as_out_param(LEX_STRING a) : name(a) {}
+ /* We should return something different from FIELD_ITEM here */
+ enum Type type() const { return STRING_ITEM;}
+ double val_real();
+ longlong val_int();
+ 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);
+ void print(String *str);
+ void set_null_value(CHARSET_INFO* cs);
+ void set_value(const char *str, uint length, CHARSET_INFO* cs);
+};
+
+
class Item_func_inet_aton : public Item_int_func
{
public:
@@ -1027,11 +1199,7 @@ public:
table->file->ft_handler=0;
table->fulltext_searched=0;
}
- if (concat)
- {
- delete concat;
- concat= 0;
- }
+ concat= 0;
DBUG_VOID_RETURN;
}
enum Functype functype() const { return FT_FUNC; }
@@ -1041,8 +1209,8 @@ public:
bool fix_fields(THD *thd, struct st_table_list *tlist, 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()!=0.0; }
- double val();
+ longlong val_int() { DBUG_ASSERT(fixed == 1); return val_real() != 0.0; }
+ double val_real();
void print(String *str);
bool fix_index();
@@ -1083,7 +1251,100 @@ public:
enum Cast_target
{
ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
- ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR
+ ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR,
+ ITEM_CAST_DECIMAL
+};
+
+
+class Item_func_row_count :public Item_int_func
+{
+public:
+ Item_func_row_count() :Item_int_func() {}
+ longlong val_int();
+ const char *func_name() const { return "row_count"; }
+ void fix_length_and_dec() { decimals= 0; maybe_null=0; }
+};
+
+
+/*
+ *
+ * Stored FUNCTIONs
+ *
+ */
+
+class sp_head;
+class sp_name;
+
+class Item_func_sp :public Item_func
+{
+private:
+ sp_name *m_name;
+ mutable sp_head *m_sp;
+ TABLE *dummy_table;
+ Field *result_field;
+ char result_buf[64];
+
+ int execute(Item **itp);
+ int execute(Field **flp);
+ Field *sp_result_field(void) const;
+
+public:
+
+ Item_func_sp(sp_name *name);
+
+ Item_func_sp(sp_name *name, List<Item> &list);
+
+ virtual ~Item_func_sp()
+ {}
+
+ void cleanup()
+ {
+ if (result_field)
+ delete result_field;
+ Item_func::cleanup();
+ result_field= NULL;
+ }
+
+ const char *func_name() const;
+
+ enum enum_field_types field_type() const;
+
+ Field *tmp_table_field(TABLE *t_arg);
+
+ void make_field(Send_field *tmp_field);
+
+ Item_result result_type() const;
+
+ longlong val_int()
+ {
+ if (execute(&result_field))
+ return (longlong) 0;
+ return result_field->val_int();
+ }
+
+ double val_real()
+ {
+ if (execute(&result_field))
+ return 0.0;
+ return result_field->val_real();
+ }
+
+ my_decimal *val_decimal(my_decimal *dec_buf)
+ {
+ if (execute(&result_field))
+ return NULL;
+ return result_field->val_decimal(dec_buf);
+ }
+
+ String *val_str(String *str)
+ {
+ if (execute(&result_field))
+ return NULL;
+ return result_field->val_str(str);
+ }
+
+ void fix_length_and_dec();
+
};
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 2f00416bddf..b9f2ec8a6ca 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -55,8 +55,11 @@ String *Item_func_geometry_from_text::val_str(String *str)
return 0;
str->length(0);
str->q_append(srid);
- if ((null_value= !Geometry::create_from_wkt(&buffer, &trs, str, 0)))
- return 0;
+ if (!Geometry::create_from_wkt(&buffer, &trs, str, 0))
+ /* We shouldn't return NULL here as NULL is a legal spatial object */
+ /* Geometry::bad_spatial_data will produce error message beeing stored*/
+ /* in GEOMETRY field */
+ return &Geometry::bad_geometry_data;
return str;
}
@@ -319,8 +322,8 @@ err:
String *Item_func_point::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- double x= args[0]->val();
- double y= args[1]->val();
+ double x= args[0]->val_real();
+ double y= args[1]->val_real();
if ((null_value= (args[0]->null_value ||
args[1]->null_value ||
@@ -627,7 +630,7 @@ longlong Item_func_numpoints::val_int()
}
-double Item_func_x::val()
+double Item_func_x::val_real()
{
DBUG_ASSERT(fixed == 1);
double res= 0.0; // In case of errors
@@ -644,7 +647,7 @@ double Item_func_x::val()
}
-double Item_func_y::val()
+double Item_func_y::val_real()
{
DBUG_ASSERT(fixed == 1);
double res= 0; // In case of errors
@@ -661,7 +664,7 @@ double Item_func_y::val()
}
-double Item_func_area::val()
+double Item_func_area::val_real()
{
DBUG_ASSERT(fixed == 1);
double res= 0; // In case of errors
@@ -678,7 +681,7 @@ double Item_func_area::val()
return res;
}
-double Item_func_glength::val()
+double Item_func_glength::val_real()
{
DBUG_ASSERT(fixed == 1);
double res= 0; // In case of errors
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 79e4f804a04..e19036cc982 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -263,7 +263,7 @@ class Item_func_x: public Item_real_func
String value;
public:
Item_func_x(Item *a): Item_real_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "x"; }
};
@@ -273,7 +273,7 @@ class Item_func_y: public Item_real_func
String value;
public:
Item_func_y(Item *a): Item_real_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "y"; }
};
@@ -316,7 +316,7 @@ class Item_func_area: public Item_real_func
String value;
public:
Item_func_area(Item *a): Item_real_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "area"; }
};
@@ -326,7 +326,7 @@ class Item_func_glength: public Item_real_func
String value;
public:
Item_func_glength(Item *a): Item_real_func(a) {}
- double val();
+ double val_real();
const char *func_name() const { return "glength"; }
};
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 12d202a1699..0c8baa332ca 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -62,7 +62,7 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++)
{
if ((*arg)->fix_fields(thd, tabl, arg))
- return 1;
+ return TRUE;
// we can't assign 'item' before, because fix_fields() can change arg
Item *item= *arg;
used_tables_cache |= item->used_tables();
@@ -73,15 +73,15 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
with_null|= item->null_inside();
else
{
- item->val_int();
- with_null|= item->null_value;
+ if (item->is_null())
+ with_null|= 1;
}
}
maybe_null|= item->maybe_null;
with_sum_func= with_sum_func || item->with_sum_func;
}
fixed= 1;
- return 0;
+ return FALSE;
}
@@ -138,6 +138,18 @@ bool Item_row::walk(Item_processor processor, byte *arg)
return (this->*processor)(arg);
}
+Item *Item_row::transform(Item_transformer transformer, byte *arg)
+{
+ for (uint i= 0; i < arg_count; i++)
+ {
+ Item *new_item= items[i]->transform(transformer, arg);
+ if (!new_item)
+ return 0;
+ items[i]= new_item;
+ }
+ return (this->*transformer)(arg);
+}
+
void Item_row::bring_value()
{
for (uint i= 0; i < arg_count; i++)
diff --git a/sql/item_row.h b/sql/item_row.h
index 39bc4513e1e..e6b23eebb49 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -41,7 +41,7 @@ public:
{
illegal_method_call((const char*)"make_field");
};
- double val()
+ double val_real()
{
illegal_method_call((const char*)"val");
return 0;
@@ -56,6 +56,11 @@ public:
illegal_method_call((const char*)"val_str");
return 0;
};
+ my_decimal *val_decimal(my_decimal *)
+ {
+ illegal_method_call((const char*)"val_decimal");
+ return 0;
+ };
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
table_map used_tables() const { return used_tables_cache; };
@@ -65,6 +70,7 @@ public:
void print(String *str);
bool walk(Item_processor processor, byte *arg);
+ Item *transform(Item_transformer transformer, byte *arg);
uint cols() { return arg_count; }
Item* el(uint i) { return items[i]; }
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 8b9351d95a5..3fe1b819f36 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -41,35 +41,25 @@ String my_empty_string("",default_charset_info);
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
const char *fname)
{
- my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
- c1.collation->name,c1.derivation_name(),
- c2.collation->name,c2.derivation_name(),
- fname);
+ my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
+ c1.collation->name, c1.derivation_name(),
+ c2.collation->name, c2.derivation_name(),
+ fname);
}
-uint nr_of_decimals(const char *str)
-{
- if ((str=strchr(str,'.')))
- {
- const char *start= ++str;
- for (; my_isdigit(system_charset_info,*str) ; str++) ;
- return (uint) (str-start);
- }
- return 0;
-}
-double Item_str_func::val()
+double Item_str_func::val_real()
{
DBUG_ASSERT(fixed == 1);
- int err;
- char buff[64];
- char *end_not_used;
+ int err_not_used;
+ char *end_not_used, buff[64];
String *res, tmp(buff,sizeof(buff), &my_charset_bin);
res= val_str(&tmp);
- return res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
- &end_not_used, &err) : 0.0;
+ return res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
+ &end_not_used, &err_not_used) : 0.0;
}
+
longlong Item_str_func::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -1187,21 +1177,29 @@ String *Item_func_substr_index::val_str(String *str)
String *Item_func_ltrim::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res =args[0]->val_str(str);
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff),res->charset());
- String *remove_str= (arg_count==2) ? args[1]->val_str(&tmp) : &remove;
+ char buff[MAX_FIELD_WIDTH], *ptr, *end;
+ String tmp(buff,sizeof(buff),system_charset_info);
+ String *res, *remove_str;
uint remove_length;
LINT_INIT(remove_length);
- if (!remove_str || (remove_length=remove_str->length()) == 0 ||
+ res= args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ remove_str= &remove; /* Default value. */
+ if (arg_count == 2)
+ {
+ remove_str= args[1]->val_str(&tmp);
+ if ((null_value= args[1]->null_value))
+ return 0;
+ }
+
+ if ((remove_length= remove_str->length()) == 0 ||
remove_length > res->length())
return res;
- char *ptr=(char*) res->ptr();
- char *end=ptr+res->length();
+ ptr= (char*) res->ptr();
+ end= ptr+res->length();
if (remove_length == 1)
{
char chr=(*remove_str)[0];
@@ -1226,21 +1224,29 @@ String *Item_func_ltrim::val_str(String *str)
String *Item_func_rtrim::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res =args[0]->val_str(str);
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff),res->charset());
- String *remove_str= (arg_count==2) ? args[1]->val_str(&tmp) : &remove;
+ char buff[MAX_FIELD_WIDTH], *ptr, *end;
+ String tmp(buff, sizeof(buff), system_charset_info);
+ String *res, *remove_str;
uint remove_length;
LINT_INIT(remove_length);
- if (!remove_str || (remove_length=remove_str->length()) == 0 ||
+ res= args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ remove_str= &remove; /* Default value. */
+ if (arg_count == 2)
+ {
+ remove_str= args[1]->val_str(&tmp);
+ if ((null_value= args[1]->null_value))
+ return 0;
+ }
+
+ if ((remove_length= remove_str->length()) == 0 ||
remove_length > res->length())
return res;
- char *ptr=(char*) res->ptr();
- char *end=ptr+res->length();
+ ptr= (char*) res->ptr();
+ end= ptr+res->length();
#ifdef USE_MB
char *p=ptr;
register uint32 l;
@@ -1299,31 +1305,31 @@ String *Item_func_rtrim::val_str(String *str)
String *Item_func_trim::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res =args[0]->val_str(str);
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff),res->charset());
+ char buff[MAX_FIELD_WIDTH], *ptr, *end;
+ const char *r_ptr;
+ String tmp(buff, sizeof(buff), system_charset_info);
+ String *res, *remove_str;
uint remove_length;
LINT_INIT(remove_length);
- String *remove_str; /* The string to remove from res. */
+ res= args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ remove_str= &remove; /* Default value. */
if (arg_count == 2)
{
remove_str= args[1]->val_str(&tmp);
if ((null_value= args[1]->null_value))
return 0;
}
- else
- remove_str= &remove; /* Default value. */
- if (!remove_str || (remove_length=remove_str->length()) == 0 ||
+ if ((remove_length= remove_str->length()) == 0 ||
remove_length > res->length())
return res;
- char *ptr=(char*) res->ptr();
- char *end=ptr+res->length();
- const char *r_ptr=remove_str->ptr();
+ ptr= (char*) res->ptr();
+ end= ptr+res->length();
+ r_ptr= remove_str->ptr();
while (ptr+remove_length <= end && !memcmp(ptr,r_ptr,remove_length))
ptr+=remove_length;
#ifdef USE_MB
@@ -1662,10 +1668,9 @@ Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org)
String *Item_func_format::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- double nr =args[0]->val();
+ double nr= args[0]->val_real();
+ uint32 length,str_length,dec;
int diff;
- uint32 length, str_length;
- uint dec;
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
dec= decimals ? decimals+1 : 0;
@@ -1681,7 +1686,7 @@ String *Item_func_format::val_str(String *str)
if (str_length >= dec+4)
{
char *tmp,*pos;
- length= str->length()+(diff= (int)(str_length- dec-1)/3);
+ length= str->length()+(diff=((int)(str_length- dec-1))/3);
str= copy_if_not_alloced(&tmp_str,str,length);
str->length(length);
tmp= (char*) str->ptr()+length - dec-1;
@@ -1734,14 +1739,14 @@ void Item_func_elt::fix_length_and_dec()
}
-double Item_func_elt::val()
+double Item_func_elt::val_real()
{
DBUG_ASSERT(fixed == 1);
uint tmp;
null_value=1;
if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count)
return 0.0;
- double result= args[tmp]->val();
+ double result= args[tmp]->val_real();
null_value= args[tmp]->null_value;
return result;
}
@@ -1794,7 +1799,7 @@ void Item_func_make_set::fix_length_and_dec()
for (uint i=0 ; i < arg_count ; i++)
max_length+=args[i]->max_length;
-
+
used_tables_cache|= item->used_tables();
not_null_tables_cache&= item->not_null_tables();
const_item_cache&= item->const_item();
@@ -2258,8 +2263,8 @@ void Item_func_set_collation::fix_length_and_dec()
if (!set_collation ||
!my_charset_same(args[0]->collation.collation,set_collation))
{
- my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- colname,args[0]->collation.collation->csname);
+ my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
+ colname, args[0]->collation.collation->csname);
return;
}
collation.set(set_collation, DERIVATION_EXPLICIT);
@@ -2287,6 +2292,18 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const
return 1;
}
+
+void Item_func_set_collation::print(String *str)
+{
+ str->append('(');
+ args[0]->print(str);
+ str->append(" collate ", 9);
+ DBUG_ASSERT(args[1]->basic_const_item() &&
+ args[1]->type() == Item::STRING_ITEM);
+ args[1]->str_value.print(str);
+ str->append(')');
+}
+
String *Item_func_charset::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -2855,6 +2872,8 @@ String *Item_func_uuid::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
char *s;
+ THD *thd= current_thd;
+
pthread_mutex_lock(&LOCK_uuid_generator);
if (! uuid_time) /* first UUID() call. initializing data */
{
@@ -2869,7 +2888,7 @@ String *Item_func_uuid::val_str(String *str)
with a clock_seq value (initialized random below), we use a separate
randominit() here
*/
- randominit(&uuid_rand, tmp + (ulong)current_thd, tmp + query_id);
+ randominit(&uuid_rand, tmp + (ulong) thd, tmp + (ulong)query_id);
for (i=0; i < (int)sizeof(mac); i++)
mac[i]=(uchar)(my_rnd(&uuid_rand)*255);
}
@@ -2879,7 +2898,8 @@ String *Item_func_uuid::val_str(String *str)
*--s=_dig_vec_lower[mac[i] & 15];
*--s=_dig_vec_lower[mac[i] >> 4];
}
- randominit(&uuid_rand, tmp + (ulong)start_time, tmp + bytes_sent);
+ randominit(&uuid_rand, tmp + (ulong)start_time,
+ tmp + thd->status_var.bytes_sent);
set_clock_seq_str();
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 323b52b826c..eec81f953fb 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -32,7 +32,7 @@ public:
Item_str_func(Item *a,Item *b,Item *c,Item *d, Item* e) :Item_func(a,b,c,d,e) {decimals=NOT_FIXED_DEC; }
Item_str_func(List<Item> &list) :Item_func(list) {decimals=NOT_FIXED_DEC; }
longlong val_int();
- double val();
+ double val_real();
enum Item_result result_type () const { return STRING_RESULT; }
void left_right_max_length();
};
@@ -201,7 +201,7 @@ public:
Item_func_substr_index(Item *a,Item *b,Item *c) :Item_str_func(a,b,c) {}
String *val_str(String *);
void fix_length_and_dec();
- const char *func_name() const { return "substr_index"; }
+ const char *func_name() const { return "substring_index"; }
};
@@ -244,7 +244,7 @@ public:
Returns strcat('*', octet2hex(sha1(sha1(password)))). '*' stands for new
password format, sha1(sha1(password) is so-called hash_stage2 value.
Length of returned string is always 41 byte. To find out how entire
- authentification procedure works, see comments in password.c.
+ authentication procedure works, see comments in password.c.
*/
class Item_func_password :public Item_str_func
@@ -386,7 +386,7 @@ class Item_func_elt :public Item_str_func
{
public:
Item_func_elt(List<Item> &list) :Item_str_func(list) {}
- double val();
+ double val_real();
longlong val_int();
String *val_str(String *str);
void fix_length_and_dec();
@@ -405,8 +405,7 @@ public:
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- return (!item->fixed &&
- item->fix_fields(thd, tlist, &item) ||
+ return ((!item->fixed && item->fix_fields(thd, tlist, &item)) ||
item->check_cols(1) ||
Item_func::fix_fields(thd, tlist, ref));
}
@@ -420,6 +419,14 @@ public:
return item->walk(processor, arg) ||
Item_str_func::walk(processor, arg);
}
+ Item *transform(Item_transformer transformer, byte *arg)
+ {
+ Item *new_item= item->transform(transformer, arg);
+ if (!new_item)
+ return 0;
+ item= new_item;
+ return Item_str_func::transform(transformer, arg);
+ }
void print(String *str);
};
@@ -628,7 +635,12 @@ public:
void fix_length_and_dec();
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "collate"; }
- void print(String *str) { print_op(str); }
+ void print(String *str);
+ Item_field *filed_for_view_update()
+ {
+ /* this function is transparent for view updating */
+ return args[0]->filed_for_view_update();
+ }
};
class Item_func_charset :public Item_str_func
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 301740c50ef..0fbcf32a83c 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -53,7 +53,7 @@ void Item_subselect::init(st_select_lex *select_lex,
{
DBUG_ENTER("Item_subselect::init");
- DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex));
+ DBUG_PRINT("enter", ("select_lex: 0x%x", (ulong) select_lex));
unit= select_lex->master_unit();
if (unit->item)
@@ -66,7 +66,7 @@ void Item_subselect::init(st_select_lex *select_lex,
parsing_place= unit->item->parsing_place;
unit->item->engine= 0;
unit->item= this;
- engine->change_item(this, result);
+ engine->change_result(this, result);
}
else
{
@@ -132,18 +132,18 @@ Item_subselect::select_transformer(JOIN *join)
bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{
+ char const *save_where= thd_param->where;
+ bool res;
+
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param));
- char const *save_where= thd->where;
- int res;
-
if (check_stack_overrun(thd, (gptr)&res))
- return 1;
+ return TRUE;
res= engine->prepare();
- // all transformetion is done (used by prepared statements)
+ // all transformation is done (used by prepared statements)
changed= 1;
if (!res)
@@ -173,7 +173,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
if (engine->cols() > max_columns)
{
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
- return 1;
+ return TRUE;
}
fix_length_and_dec();
}
@@ -246,7 +246,7 @@ void Item_subselect::update_used_tables()
{
if (!engine->uncacheable())
{
- // did all used tables become ststic?
+ // did all used tables become static?
if (!(used_tables_cache & ~engine->upper_select_const_tables()))
const_item_cache= 1;
}
@@ -271,7 +271,8 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex)
DBUG_VOID_RETURN;
}
-Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent,
+Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
+ Item_subselect *parent,
st_select_lex *select_lex,
bool max_arg)
:Item_singlerow_subselect(), was_values(TRUE)
@@ -290,6 +291,12 @@ Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent,
used_tables_cache= parent->get_used_tables_cache();
const_item_cache= parent->get_const_item_cache();
+ /*
+ this subquery always creates during preparation, so we can assign
+ thd here
+ */
+ thd= thd_param;
+
DBUG_VOID_RETURN;
}
@@ -333,10 +340,8 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
return RES_OK;
SELECT_LEX *select_lex= join->select_lex;
-
- /* Juggle with current arena only if we're in prepared statement prepare */
- Item_arena *arena= join->thd->current_arena;
-
+ Item_arena *arena= thd->current_arena;
+
if (!select_lex->master_unit()->first_select()->next_select() &&
!select_lex->table_list.elements &&
select_lex->item_list.elements == 1 &&
@@ -351,7 +356,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
!(select_lex->item_list.head()->type() == FIELD_ITEM ||
select_lex->item_list.head()->type() == REF_ITEM) &&
/*
- switch off this optimisation for prepare statement,
+ switch off this optimization for prepare statement,
because we do not rollback this changes
TODO: make rollback for it, or special name resolving mode in 5.0.
*/
@@ -360,11 +365,11 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
{
have_to_be_excluded= 1;
- if (join->thd->lex->describe)
+ if (thd->lex->describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
- push_warning(join->thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
substitution= select_lex->item_list.head();
@@ -384,6 +389,7 @@ err:
return RES_ERROR;
}
+
void Item_singlerow_subselect::store(uint i, Item *item)
{
row[i]->store(item);
@@ -446,13 +452,13 @@ void Item_singlerow_subselect::bring_value()
exec();
}
-double Item_singlerow_subselect::val()
+double Item_singlerow_subselect::val_real()
{
DBUG_ASSERT(fixed == 1);
if (!exec() && !value->null_value)
{
null_value= 0;
- return value->val();
+ return value->val_real();
}
else
{
@@ -476,7 +482,7 @@ longlong Item_singlerow_subselect::val_int()
}
}
-String *Item_singlerow_subselect::val_str (String *str)
+String *Item_singlerow_subselect::val_str(String *str)
{
if (!exec() && !value->null_value)
{
@@ -491,10 +497,41 @@ String *Item_singlerow_subselect::val_str (String *str)
}
+my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
+{
+ if (!exec() && !value->null_value)
+ {
+ null_value= 0;
+ return value->val_decimal(decimal_value);
+ }
+ else
+ {
+ reset();
+ return 0;
+ }
+}
+
+
+bool Item_singlerow_subselect::val_bool()
+{
+ if (!exec() && !value->null_value)
+ {
+ null_value= 0;
+ return value->val_bool();
+ }
+ else
+ {
+ reset();
+ return 0;
+ }
+}
+
+
Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex):
Item_subselect()
{
DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
+ bool val_bool();
init(select_lex, new select_exists_subselect(this));
max_columns= UINT_MAX;
null_value= 0; //can't be NULL
@@ -570,7 +607,7 @@ void Item_exists_subselect::fix_length_and_dec()
max_columns= engine->cols();
}
-double Item_exists_subselect::val()
+double Item_exists_subselect::val_real()
{
DBUG_ASSERT(fixed == 1);
if (exec())
@@ -600,12 +637,37 @@ String *Item_exists_subselect::val_str(String *str)
reset();
return 0;
}
- str->set(value,&my_charset_bin);
+ str->set((ulonglong)value,&my_charset_bin);
return str;
}
-double Item_in_subselect::val()
+my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (exec())
+ {
+ reset();
+ return 0;
+ }
+ int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value);
+ return decimal_value;
+}
+
+
+bool Item_exists_subselect::val_bool()
+{
+ DBUG_ASSERT(fixed == 1);
+ if (exec())
+ {
+ reset();
+ return 0;
+ }
+ return value != 0;
+}
+
+
+double Item_in_subselect::val_real()
{
/*
As far as Item_in_subselect called only from Item_in_optimizer this
@@ -627,6 +689,11 @@ double Item_in_subselect::val()
longlong Item_in_subselect::val_int()
{
+ /*
+ As far as Item_in_subselect called only from Item_in_optimizer this
+ method should not be used
+ */
+ DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
if (exec())
{
@@ -659,17 +726,53 @@ String *Item_in_subselect::val_str(String *str)
null_value= 1;
return 0;
}
- str->set(value, &my_charset_bin);
+ str->set((ulonglong)value, &my_charset_bin);
return str;
}
+bool Item_in_subselect::val_bool()
+{
+ DBUG_ASSERT(fixed == 1);
+ if (exec())
+ {
+ reset();
+ null_value= 1;
+ return 0;
+ }
+ if (was_null && !value)
+ null_value= 1;
+ return value;
+}
+
+my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value)
+{
+ /*
+ As far as Item_in_subselect called only from Item_in_optimizer this
+ method should not be used
+ */
+ DBUG_ASSERT(0);
+ DBUG_ASSERT(fixed == 1);
+ if (exec())
+ {
+ reset();
+ null_value= 1;
+ return 0;
+ }
+ if (was_null && !value)
+ null_value= 1;
+ int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value);
+ return decimal_value;
+}
+
+
/* Rewrite a single-column IN/ALL/ANY subselect. */
Item_subselect::trans_res
Item_in_subselect::single_value_transformer(JOIN *join,
Comp_creator *func)
{
+ Item_subselect::trans_res result= RES_ERROR;
DBUG_ENTER("Item_in_subselect::single_value_transformer");
SELECT_LEX *select_lex= join->select_lex;
@@ -738,7 +841,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
/*
Item_sum_(max|min) can't substitute other item => we can use 0 as
- reference
+ 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))
DBUG_RETURN(RES_ERROR);
@@ -753,7 +857,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
// remove LIMIT placed by ALL/ANY subquery
select_lex->master_unit()->global_parameters->select_limit=
HA_POS_ERROR;
- subs= item= new Item_maxmin_subselect(this, select_lex, func->l_op());
+ subs= item= new Item_maxmin_subselect(thd, this, select_lex, func->l_op());
if (upper_item)
upper_item->set_sub_test(item);
}
@@ -780,7 +884,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
thd->lex->current_select= current;
/*
- As far as Item_ref_in_optimizer do not substitude itself on fix_fields
+ 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(),
@@ -791,9 +895,6 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
- Item *item;
-
- item= (Item*) select_lex->item_list.head();
/*
Add the left part of a subselect to a WHERE or HAVING clause of
the right part, e.g. SELECT 1 IN (SELECT a FROM t1) =>
@@ -804,11 +905,17 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (join->having || select_lex->with_sum_func ||
select_lex->group_list.elements)
{
- item= func->create(expr,
- new Item_ref_null_helper(this,
- select_lex->ref_pointer_array,
- (char *)"<ref>",
- this->full_name()));
+ bool tmp;
+ Item *item= func->create(expr,
+ new Item_ref_null_helper(this,
+ select_lex->
+ ref_pointer_array,
+ (char *)"<ref>",
+ this->full_name()));
+#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
/*
AND and comparison functions can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last
@@ -816,21 +923,26 @@ Item_in_subselect::single_value_transformer(JOIN *join,
*/
select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
- if (join->having->fix_fields(thd, join->tables_list, 0))
- {
- select_lex->having_fix_field= 0;
- DBUG_RETURN(RES_ERROR);
- }
+ /*
+ 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);
select_lex->having_fix_field= 0;
+ if (tmp)
+ DBUG_RETURN(RES_ERROR);
}
else
{
+ Item *item= (Item*) select_lex->item_list.head();
+
select_lex->item_list.empty();
select_lex->item_list.push_back(new Item_int("Not_used",
(longlong) 1, 21));
select_lex->ref_pointer_array[0]= select_lex->item_list.head();
if (select_lex->table_list.elements)
{
+ bool tmp;
Item *having= item, *orig_item= item;
item= func->create(expr, item);
if (!abort_on_null && orig_item->maybe_null)
@@ -846,14 +958,21 @@ Item_in_subselect::single_value_transformer(JOIN *join,
new Item_cond_and(having, join->having) :
having);
select_lex->having_fix_field= 1;
- if (join->having->fix_fields(thd, join->tables_list, 0))
- {
- select_lex->having_fix_field= 0;
+ /*
+ 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);
+ select_lex->having_fix_field= 0;
+ if (tmp)
DBUG_RETURN(RES_ERROR);
- }
- select_lex->having_fix_field= 0;
item= new Item_cond_or(item,
new Item_func_isnull(orig_item));
+#ifdef CORRECT_BUT_TOO_SLOW_TO_BE_USABLE
+ if (left_expr->maybe_null)
+ item= new Item_cond_or(new Item_func_isnull(left_expr), item);
+#endif
}
item->name= (char *)in_additional_cond;
/*
@@ -862,11 +981,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
argument (reference) to fix_fields()
*/
select_lex->where= join->conds= and_items(join->conds, item);
+ /*
+ 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))
DBUG_RETURN(RES_ERROR);
}
else
{
+ bool tmp;
if (select_lex->master_unit()->first_select()->next_select())
{
/*
@@ -874,26 +998,30 @@ Item_in_subselect::single_value_transformer(JOIN *join,
we can assign select_lex->having here, and pass 0 as last
argument (reference) to fix_fields()
*/
- select_lex->having=
- join->having=
- func->create(expr,
+ item= func->create(expr,
new Item_null_helper(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_fix_field= 1;
- if (join->having->fix_fields(thd, join->tables_list,
- 0))
- {
- select_lex->having_fix_field= 0;
+ /*
+ 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);
+ select_lex->having_fix_field= 0;
+ if (tmp)
DBUG_RETURN(RES_ERROR);
- }
- select_lex->having_fix_field= 0;
}
else
{
// it is single select without tables => possible optimization
item= func->create(left_expr, item);
- // fix_field of item will be done in time of substituting
+ // fix_field of item will be done in time of substituting
substitution= item;
have_to_be_excluded= 1;
if (thd->lex->describe)
@@ -915,10 +1043,9 @@ Item_in_subselect::single_value_transformer(JOIN *join,
Item_subselect::trans_res
Item_in_subselect::row_value_transformer(JOIN *join)
{
- DBUG_ENTER("Item_in_subselect::row_value_transformer");
-
Item *item= 0;
SELECT_LEX *select_lex= join->select_lex;
+ DBUG_ENTER("Item_in_subselect::row_value_transformer");
if (select_lex->item_list.elements != left_expr->cols())
{
@@ -941,7 +1068,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
DBUG_RETURN(RES_ERROR);
}
- // we will refer to apper level cache array => we have to save it in PS
+ // we will refer to upper level cache array => we have to save it in PS
optimizer->keep_top_level_cache();
thd->lex->current_select= current;
@@ -959,9 +1086,9 @@ Item_in_subselect::row_value_transformer(JOIN *join)
check_cols(left_expr->el(i)->cols()))
DBUG_RETURN(RES_ERROR);
Item *func= new Item_ref_null_helper(this,
- select_lex->ref_pointer_array+i,
- (char *) "<no matter>",
- (char *) "<list ref>");
+ select_lex->ref_pointer_array+i,
+ (char *) "<no matter>",
+ (char *) "<list ref>");
func=
eq_creator.create(new Item_direct_ref((*optimizer->get_cache())->
addr(i),
@@ -982,6 +1109,10 @@ Item_in_subselect::row_value_transformer(JOIN *join)
*/
select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
+ /*
+ 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))
{
select_lex->having_fix_field= 0;
@@ -997,9 +1128,14 @@ Item_in_subselect::row_value_transformer(JOIN *join)
argument (reference) to fix_fields()
*/
select_lex->where= join->conds= and_items(join->conds, item);
+ /*
+ join->conds can't be fixed after creation, so we do not check
+ join->conds->fixed
+ */
if (join->conds->fix_fields(thd, join->tables_list, 0))
DBUG_RETURN(RES_ERROR);
}
+
DBUG_RETURN(RES_OK);
}
@@ -1154,13 +1290,7 @@ subselect_single_select_engine(st_select_lex *select,
{
select_lex= select;
SELECT_LEX_UNIT *unit= select_lex->master_unit();
- unit->offset_limit_cnt= unit->global_parameters->offset_limit;
- unit->select_limit_cnt= unit->global_parameters->select_limit+
- unit->global_parameters ->offset_limit;
- if (unit->select_limit_cnt < unit->global_parameters->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR; // no limit
- if (unit->select_limit_cnt == HA_POS_ERROR)
- select_lex->options&= ~OPTION_FOUND_ROWS;
+ unit->set_limit(unit->global_parameters, select_lex);
unit->item= item;
this->select_lex= select_lex;
}
@@ -1305,17 +1435,17 @@ void subselect_uniquesubquery_engine::fix_length_and_dec(Item_cache **row)
int subselect_single_select_engine::exec()
{
DBUG_ENTER("subselect_single_select_engine::exec");
- char const *save_where= join->thd->where;
- SELECT_LEX *save_select= join->thd->lex->current_select;
- join->thd->lex->current_select= select_lex;
+ char const *save_where= thd->where;
+ SELECT_LEX *save_select= thd->lex->current_select;
+ thd->lex->current_select= select_lex;
if (!optimized)
{
optimized=1;
if (join->optimize())
{
- join->thd->where= save_where;
+ thd->where= save_where;
executed= 1;
- join->thd->lex->current_select= save_select;
+ thd->lex->current_select= save_select;
DBUG_RETURN(join->error ? join->error : 1);
}
if (item->engine_changed)
@@ -1327,8 +1457,8 @@ int subselect_single_select_engine::exec()
{
if (join->reinit())
{
- join->thd->where= save_where;
- join->thd->lex->current_select= save_select;
+ thd->where= save_where;
+ thd->lex->current_select= save_select;
DBUG_RETURN(1);
}
item->reset();
@@ -1339,20 +1469,20 @@ int subselect_single_select_engine::exec()
item->reset_value_registration();
join->exec();
executed= 1;
- join->thd->where= save_where;
- join->thd->lex->current_select= save_select;
+ thd->where= save_where;
+ thd->lex->current_select= save_select;
DBUG_RETURN(join->error||thd->is_fatal_error);
}
- join->thd->where= save_where;
- join->thd->lex->current_select= save_select;
+ thd->where= save_where;
+ thd->lex->current_select= save_select;
DBUG_RETURN(0);
}
int subselect_union_engine::exec()
{
- char const *save_where= unit->thd->where;
+ char const *save_where= thd->where;
int res= unit->exec();
- unit->thd->where= save_where;
+ thd->where= save_where;
return res;
}
@@ -1475,7 +1605,7 @@ int subselect_indexsubquery_engine::exec()
uint subselect_single_select_engine::cols()
{
- DBUG_ASSERT(select_lex->join); // should be called after fix_fields()
+ DBUG_ASSERT(select_lex->join != 0); // should be called after fix_fields()
return select_lex->join->fields_list.elements;
}
@@ -1520,7 +1650,7 @@ void subselect_uniquesubquery_engine::exclude()
table_map subselect_engine::calc_const_tables(TABLE_LIST *table)
{
table_map map= 0;
- for (; table; table= table->next)
+ for(; table; table= table->next_leaf)
{
TABLE *tbl= table->table;
if (tbl && tbl->const_table)
@@ -1533,14 +1663,13 @@ table_map subselect_engine::calc_const_tables(TABLE_LIST *table)
table_map subselect_single_select_engine::upper_select_const_tables()
{
return calc_const_tables((TABLE_LIST *) select_lex->outer_select()->
- table_list.first);
+ leaf_tables);
}
table_map subselect_union_engine::upper_select_const_tables()
{
- return calc_const_tables((TABLE_LIST *) unit->outer_select()->
- table_list.first);
+ return calc_const_tables((TABLE_LIST *) unit->outer_select()->leaf_tables);
}
@@ -1561,7 +1690,7 @@ void subselect_uniquesubquery_engine::print(String *str)
str->append("<primary_index_lookup>(", 23);
tab->ref.items[0]->print(str);
str->append(" in ", 4);
- str->append(tab->table->real_name);
+ str->append(tab->table->s->table_name);
KEY *key_info= tab->table->key_info+ tab->ref.key;
str->append(" on ", 4);
str->append(key_info->name);
@@ -1579,12 +1708,12 @@ void subselect_indexsubquery_engine::print(String *str)
str->append("<index_lookup>(", 15);
tab->ref.items[0]->print(str);
str->append(" in ", 4);
- str->append(tab->table->real_name);
+ str->append(tab->table->s->table_name);
KEY *key_info= tab->table->key_info+ tab->ref.key;
str->append(" on ", 4);
str->append(key_info->name);
if (check_null)
- str->append(" chicking NULL", 14);
+ str->append(" checking NULL", 14);
if (cond)
{
str->append(" where ", 7);
@@ -1596,18 +1725,18 @@ void subselect_indexsubquery_engine::print(String *str)
/*
change select_result object of engine
- SINOPSYS
+ SYNOPSIS
subselect_single_select_engine::change_result()
si new subselect Item
res new select_result object
RETURN
- 0 OK
- -1 error
+ FALSE OK
+ TRUE error
*/
-int subselect_single_select_engine::change_item(Item_subselect *si,
- select_subselect *res)
+bool subselect_single_select_engine::change_result(Item_subselect *si,
+ select_subselect *res)
{
item= si;
result= res;
@@ -1618,18 +1747,18 @@ int subselect_single_select_engine::change_item(Item_subselect *si,
/*
change select_result object of engine
- SINOPSYS
+ SYNOPSIS
subselect_single_select_engine::change_result()
si new subselect Item
res new select_result object
RETURN
- 0 OK
- -1 error
+ FALSE OK
+ TRUE error
*/
-int subselect_union_engine::change_item(Item_subselect *si,
- select_subselect *res)
+bool subselect_union_engine::change_result(Item_subselect *si,
+ select_subselect *res)
{
item= si;
int rc= unit->change_result(res, result);
@@ -1641,27 +1770,28 @@ int subselect_union_engine::change_item(Item_subselect *si,
/*
change select_result emulation, never should be called
- SINOPSYS
+ SYNOPSIS
subselect_single_select_engine::change_result()
si new subselect Item
res new select_result object
RETURN
- -1 error
+ FALSE OK
+ TRUE error
*/
-int subselect_uniquesubquery_engine::change_item(Item_subselect *si,
- select_subselect *res)
+bool subselect_uniquesubquery_engine::change_result(Item_subselect *si,
+ select_subselect *res)
{
DBUG_ASSERT(0);
- return -1;
+ return TRUE;
}
/*
Report about presence of tables in subquery
- SINOPSYS
+ SYNOPSIS
subselect_single_select_engine::no_tables()
RETURN
@@ -1677,7 +1807,7 @@ bool subselect_single_select_engine::no_tables()
/*
Report about presence of tables in subquery
- SINOPSYS
+ SYNOPSIS
subselect_union_engine::no_tables()
RETURN
@@ -1698,7 +1828,7 @@ bool subselect_union_engine::no_tables()
/*
Report about presence of tables in subquery
- SINOPSYS
+ SYNOPSIS
subselect_uniquesubquery_engine::no_tables()
RETURN
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index a6e005d5d26..1a407c695b2 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -26,7 +26,7 @@ class JOIN;
class select_subselect;
class subselect_engine;
class Item_bool_func2;
-class Statement;
+class Item_arena;
/* base class for subselects */
@@ -96,6 +96,7 @@ public:
virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
+ table_map not_null_tables() const { return 0; }
bool const_item() const;
inline table_map get_used_tables_cache() { return used_tables_cache; }
inline bool get_const_item_cache() { return const_item_cache; }
@@ -114,6 +115,7 @@ public:
mechanism. Engine call this method before rexecution query.
*/
virtual void reset_value_registration() {}
+ enum_parsing_place place() { return parsing_place; }
friend class select_subselect;
friend class Item_in_optimizer;
@@ -139,9 +141,11 @@ public:
void reset();
trans_res select_transformer(JOIN *join);
void store(uint i, Item* item);
- double val();
+ double val_real();
longlong val_int ();
String *val_str (String *);
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
enum Item_result result_type() const;
void fix_length_and_dec();
@@ -155,7 +159,7 @@ public:
friend class select_singlerow_subselect;
};
-/* used in static ALL/ANY optimisation */
+/* used in static ALL/ANY optimization */
class select_max_min_finder_subselect;
class Item_maxmin_subselect :public Item_singlerow_subselect
{
@@ -163,7 +167,7 @@ protected:
bool max;
bool was_values; // Set if we have found at least one row
public:
- Item_maxmin_subselect(Item_subselect *parent,
+ Item_maxmin_subselect(THD *thd, Item_subselect *parent,
st_select_lex *select_lex, bool max);
void print(String *str);
void cleanup();
@@ -177,7 +181,7 @@ public:
class Item_exists_subselect :public Item_subselect
{
protected:
- longlong value; /* value of this item (boolean: exists/not-exists) */
+ bool value; /* value of this item (boolean: exists/not-exists) */
public:
Item_exists_subselect(st_select_lex *select_lex);
@@ -191,8 +195,10 @@ public:
enum Item_result result_type() const { return INT_RESULT;}
longlong val_int();
- double val();
+ double val_real();
String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
void fix_length_and_dec();
void print(String *str);
@@ -237,8 +243,10 @@ public:
trans_res single_value_transformer(JOIN *join, Comp_creator *func);
trans_res row_value_transformer(JOIN * join);
longlong val_int();
- double val();
+ double val_real();
String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
void top_level_item() { abort_on_null=1; }
bool test_limit(st_select_lex_unit *unit);
void print(String *str);
@@ -295,7 +303,7 @@ public:
virtual int prepare()= 0;
virtual void fix_length_and_dec(Item_cache** row)= 0;
virtual int exec()= 0;
- virtual uint cols()= 0; /* return number of columnss in select */
+ virtual uint cols()= 0; /* return number of columns in select */
virtual uint8 uncacheable()= 0; /* query is uncacheable */
enum Item_result type() { return res_type; }
virtual void exclude()= 0;
@@ -303,7 +311,7 @@ public:
virtual table_map upper_select_const_tables()= 0;
static table_map calc_const_tables(TABLE_LIST *);
virtual void print(String *str)= 0;
- virtual int change_item(Item_subselect *si, select_subselect *result)= 0;
+ virtual bool change_result(Item_subselect *si, select_subselect *result)= 0;
virtual bool no_tables()= 0;
};
@@ -328,7 +336,7 @@ public:
void exclude();
table_map upper_select_const_tables();
void print (String *str);
- int change_item(Item_subselect *si, select_subselect *result);
+ bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
};
@@ -349,7 +357,7 @@ public:
void exclude();
table_map upper_select_const_tables();
void print (String *str);
- int change_item(Item_subselect *si, select_subselect *result);
+ bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
};
@@ -379,7 +387,7 @@ public:
void exclude();
table_map upper_select_const_tables() { return 0; }
void print (String *str);
- int change_item(Item_subselect *si, select_subselect *result);
+ bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 7e9c5d09136..3dd4b6618a2 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -22,6 +22,7 @@
#endif
#include "mysql_priv.h"
+#include "sql_select.h"
Item_sum::Item_sum(List<Item> &list)
:arg_count(list.elements)
@@ -124,6 +125,7 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
return sum_item;
}
+
bool Item_sum::walk (Item_processor processor, byte *argument)
{
if (arg_count)
@@ -138,30 +140,56 @@ bool Item_sum::walk (Item_processor processor, byte *argument)
return (this->*processor)(argument);
}
+
+Field *Item_sum::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length)
+{
+ switch (result_type()) {
+ case REAL_RESULT:
+ return new Field_double(max_length,maybe_null,name,table,decimals);
+ case INT_RESULT:
+ return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag);
+ case STRING_RESULT:
+ if (max_length > 255 && convert_blob_length)
+ return new Field_varstring(convert_blob_length, maybe_null,
+ name, table,
+ collation.collation);
+ return make_string_field(table);
+ case DECIMAL_RESULT:
+ return new Field_new_decimal(max_length - (decimals?1:0),
+ maybe_null, name, table, decimals);
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
+ }
+}
+
+
String *
Item_sum_num::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- double nr=val();
- if (null_value)
- return 0;
- str->set(nr,decimals, &my_charset_bin);
- return str;
+ return val_string_from_real(str);
+}
+
+
+my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value)
+{
+ return val_decimal_from_real(decimal_value);
}
String *
Item_sum_int::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- longlong nr= val_int();
- if (null_value)
- return 0;
- if (unsigned_flag)
- str->set((ulonglong) nr, &my_charset_bin);
- else
- str->set(nr, &my_charset_bin);
- return str;
+ return val_string_from_int(str);
+}
+
+
+my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value)
+{
+ return val_decimal_from_int(decimal_value);
}
@@ -172,8 +200,9 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (!thd->allow_sum_func)
{
- my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
- return 1;
+ my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
+ MYF(0));
+ return TRUE;
}
thd->allow_sum_func=0; // No included group funcs
decimals=0;
@@ -181,9 +210,8 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
for (uint i=0 ; i < arg_count ; i++)
{
if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
- return 1;
- if (decimals < args[i]->decimals)
- decimals=args[i]->decimals;
+ return TRUE;
+ set_if_bigger(decimals, args[i]->decimals);
maybe_null |= args[i]->maybe_null;
}
result_field=0;
@@ -192,10 +220,33 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
fix_length_and_dec();
thd->allow_sum_func=1; // Allow group functions
fixed= 1;
- return 0;
+ return FALSE;
}
+Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
+ :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type),
+ hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign),
+ used_table_cache(item->used_table_cache), was_values(item->was_values)
+{
+ /* copy results from old value */
+ switch (hybrid_type) {
+ case INT_RESULT:
+ sum_int= item->sum_int;
+ break;
+ case DECIMAL_RESULT:
+ my_decimal2decimal(&item->sum_dec, &sum_dec);
+ break;
+ case REAL_RESULT:
+ sum= item->sum;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ collation.set(item->collation);
+}
+
bool
Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
@@ -204,8 +255,9 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
Item *item= args[0];
if (!thd->allow_sum_func)
{
- my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
- return 1;
+ my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
+ MYF(0));
+ return TRUE;
}
thd->allow_sum_func=0; // No included group funcs
@@ -213,21 +265,29 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (!item->fixed &&
item->fix_fields(thd, tables, args) ||
(item= args[0])->check_cols(1))
- return 1;
-
- hybrid_type= item->result_type();
- if (hybrid_type == INT_RESULT)
- {
- max_length=20;
- }
- else if (hybrid_type == REAL_RESULT)
- {
- max_length=float_length(decimals);
- }else
- {
- max_length=item->max_length;
- }
+ return TRUE;
decimals=item->decimals;
+
+ switch (hybrid_type= item->result_type()) {
+ case INT_RESULT:
+ max_length= 20;
+ sum_int= 0;
+ break;
+ case DECIMAL_RESULT:
+ max_length= item->max_length;
+ my_decimal_set_zero(&sum_dec);
+ break;
+ case REAL_RESULT:
+ max_length= float_length(decimals);
+ sum= 0.0;
+ break;
+ case STRING_RESULT:
+ max_length= item->max_length;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ };
/* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= 1;
unsigned_flag=item->unsigned_flag;
@@ -241,7 +301,22 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
else
hybrid_field_type= Item::field_type();
fixed= 1;
- return 0;
+ return FALSE;
+}
+
+Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length)
+{
+ if (args[0]->type() == Item::FIELD_ITEM)
+ {
+ Field *field= ((Item_field*) args[0])->field;
+
+ if ((field= create_tmp_field_from_field(current_thd, field, name, table,
+ NULL, convert_blob_length)))
+ field->flags&= ~NOT_NULL_FLAG;
+ return field;
+ }
+ return Item_sum::create_tmp_field(group, table, convert_blob_length);
}
@@ -249,6 +324,20 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
** reset and add of sum_func
***********************************************************************/
+Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item)
+ :Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
+ curr_dec_buff(item->curr_dec_buff)
+{
+ /* TODO: check if the following assignments are really needed */
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal2decimal(item->dec_buffs, dec_buffs);
+ my_decimal2decimal(item->dec_buffs + 1, dec_buffs + 1);
+ }
+ else
+ sum= item->sum;
+}
+
Item *Item_sum_sum::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_sum(thd, this);
@@ -257,26 +346,402 @@ Item *Item_sum_sum::copy_or_same(THD* thd)
void Item_sum_sum::clear()
{
- null_value=1; sum=0.0;
+ DBUG_ENTER("Item_sum_sum::clear");
+ null_value=1;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ curr_dec_buff= 0;
+ my_decimal_set_zero(dec_buffs);
+ }
+ else
+ sum= 0.0;
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_sum_sum::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
+ maybe_null=null_value=1;
+ decimals= args[0]->decimals;
+ switch (args[0]->result_type()) {
+ case REAL_RESULT:
+ case STRING_RESULT:
+ hybrid_type= REAL_RESULT;
+ sum= 0.0;
+ break;
+ case INT_RESULT:
+ case DECIMAL_RESULT:
+ /* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
+ max_length= min(args[0]->max_length + DECIMAL_LONGLONG_DIGITS,
+ DECIMAL_MAX_LENGTH);
+ curr_dec_buff= 0;
+ hybrid_type= DECIMAL_RESULT;
+ my_decimal_set_zero(dec_buffs);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_PRINT("info", ("Type: %s (%d, %d)",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--"),
+ max_length,
+ (int)decimals));
+ DBUG_VOID_RETURN;
}
bool Item_sum_sum::add()
{
- sum+=args[0]->val();
- if (!args[0]->null_value)
- null_value= 0;
- return 0;
+ DBUG_ENTER("Item_sum_sum::add");
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
+ val, dec_buffs + curr_dec_buff);
+ curr_dec_buff^= 1;
+ null_value= 0;
+ }
+ }
+ else
+ {
+ sum+= args[0]->val_real();
+ if (!args[0]->null_value)
+ null_value= 0;
+ }
+ DBUG_RETURN(0);
+}
+
+
+longlong Item_sum_sum::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag,
+ &result);
+ return result;
+ }
+ return (longlong) val_real();
}
-double Item_sum_sum::val()
+double Item_sum_sum::val_real()
{
DBUG_ASSERT(fixed == 1);
+ if (hybrid_type == DECIMAL_RESULT)
+ my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum);
return sum;
}
+String *Item_sum_sum::val_str(String *str)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ return val_string_from_decimal(str);
+ return val_string_from_real(str);
+}
+
+
+my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ return (dec_buffs + curr_dec_buff);
+ return val_decimal_from_real(val);
+}
+
+/***************************************************************************/
+
+C_MODE_START
+
+/* Declarations for auxilary C-callbacks */
+
+static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
+{
+ return memcmp(key1, key2, *(uint *) arg);
+}
+
+
+static int item_sum_distinct_walk(void *element, element_count num_of_dups,
+ void *item)
+{
+ return ((Item_sum_distinct*) (item))->unique_walk_function(element);
+}
+
+C_MODE_END
+
+/* Item_sum_distinct */
+
+Item_sum_distinct::Item_sum_distinct(Item *item_arg)
+ :Item_sum_num(item_arg), tree(0)
+{
+ /*
+ quick_group is an optimizer hint, which means that GROUP BY can be
+ handled with help of index on grouped columns.
+ By setting quick_group to zero we force creation of temporary table
+ to perform GROUP BY.
+ */
+ quick_group= 0;
+}
+
+
+Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original)
+ :Item_sum_num(thd, original), val(original->val), tree(0),
+ table_field_type(original->table_field_type)
+{
+ quick_group= 0;
+}
+
+
+/*
+ Behaves like an Integer except to fix_length_and_dec().
+ Additionally div() converts val with this traits to a val with true
+ decimal traits along with conversion of integer value to decimal value.
+ This is to speedup SUM/AVG(DISTINCT) evaluation for 8-32 bit integer
+ values.
+*/
+struct Hybrid_type_traits_fast_decimal: public
+ Hybrid_type_traits_integer
+{
+ virtual Item_result type() const { return DECIMAL_RESULT; }
+ virtual void fix_length_and_dec(Item *item, Item *arg) const
+ { Hybrid_type_traits_decimal::instance()->fix_length_and_dec(item, arg); }
+
+ virtual void div(Hybrid_type *val, ulonglong u) const
+ {
+ int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, val->dec_buf);
+ val->used_dec_buf_no= 0;
+ val->traits= Hybrid_type_traits_decimal::instance();
+ val->traits->div(val, u);
+ }
+ static const Hybrid_type_traits_fast_decimal *instance();
+};
+
+static const Hybrid_type_traits_fast_decimal fast_decimal_traits_instance;
+
+const Hybrid_type_traits_fast_decimal
+ *Hybrid_type_traits_fast_decimal::instance()
+{
+ return &fast_decimal_traits_instance;
+}
+
+void Item_sum_distinct::fix_length_and_dec()
+{
+ DBUG_ASSERT(args[0]->fixed);
+
+ table_field_type= args[0]->field_type();
+
+ /* Adjust tmp table type according to the chosen aggregation type */
+ switch (args[0]->result_type()) {
+ case STRING_RESULT:
+ case REAL_RESULT:
+ val.traits= Hybrid_type_traits::instance();
+ if (table_field_type != MYSQL_TYPE_FLOAT)
+ table_field_type= MYSQL_TYPE_DOUBLE;
+ break;
+ case INT_RESULT:
+ /*
+ Preserving int8, int16, int32 field types gives ~10% performance boost
+ as the size of result tree becomes significantly smaller.
+ Another speed up we gain by using longlong for intermediate
+ calculations. The range of int64 is enough to hold sum 2^32 distinct
+ integers each <= 2^32.
+ */
+ if (table_field_type == MYSQL_TYPE_INT24 ||
+ table_field_type >= MYSQL_TYPE_TINY &&
+ table_field_type <= MYSQL_TYPE_LONG)
+ {
+ val.traits= Hybrid_type_traits_fast_decimal::instance();
+ break;
+ }
+ table_field_type= MYSQL_TYPE_LONGLONG;
+ /* fallthrough */
+ case DECIMAL_RESULT:
+ val.traits= Hybrid_type_traits_decimal::instance();
+ if (table_field_type != MYSQL_TYPE_LONGLONG)
+ table_field_type= MYSQL_TYPE_NEWDECIMAL;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ val.traits->fix_length_and_dec(this, args[0]);
+}
+
+
+bool Item_sum_distinct::setup(THD *thd)
+{
+ List<create_field> field_list;
+ create_field field_def; /* field definition */
+
+ DBUG_ENTER("Item_sum_distinct::setup");
+
+ DBUG_ASSERT(tree == 0); /* setup can not be called twice */
+
+ /*
+ Virtual table and the tree are created anew on each re-execution of
+ PS/SP. Hence all further allocations are performed in the runtime
+ mem_root.
+ */
+ if (field_list.push_back(&field_def))
+ return TRUE;
+
+ null_value= maybe_null= 1;
+ quick_group= 0;
+
+ DBUG_ASSERT(args[0]->fixed);
+
+ field_def.init_for_tmp_table(table_field_type, args[0]->max_length,
+ args[0]->decimals, args[0]->maybe_null,
+ args[0]->unsigned_flag);
+
+ if (! (table= create_virtual_tmp_table(thd, field_list)))
+ return TRUE;
+
+ /* XXX: check that the case of CHAR(0) works OK */
+ tree_key_length= table->s->reclength - table->s->null_bytes;
+
+ /*
+ Unique handles all unique elements in a tree until they can't fit
+ in. Then the tree is dumped to the temporary file. We can use
+ simple_raw_key_cmp because the table contains numbers only; decimals
+ are converted to binary representation as well.
+ */
+ tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length,
+ thd->variables.max_heap_table_size);
+
+ DBUG_RETURN(tree == 0);
+}
+
+
+bool Item_sum_distinct::add()
+{
+ args[0]->save_in_field(table->field[0], FALSE);
+ if (!table->field[0]->is_null())
+ {
+ DBUG_ASSERT(tree);
+ null_value= 0;
+ /*
+ '0' values are also stored in the tree. This doesn't matter
+ for SUM(DISTINCT), but is important for AVG(DISTINCT)
+ */
+ return tree->unique_add(table->field[0]->ptr);
+ }
+ return 0;
+}
+
+
+bool Item_sum_distinct::unique_walk_function(void *element)
+{
+ memcpy(table->field[0]->ptr, element, tree_key_length);
+ ++count;
+ val.traits->add(&val, table->field[0]);
+ return 0;
+}
+
+
+void Item_sum_distinct::clear()
+{
+ DBUG_ENTER("Item_sum_distinct::clear");
+ DBUG_ASSERT(tree != 0); /* we always have a tree */
+ null_value= 1;
+ tree->reset();
+ DBUG_VOID_RETURN;
+}
+
+void Item_sum_distinct::cleanup()
+{
+ Item_sum_num::cleanup();
+ delete tree;
+ tree= 0;
+ table= 0;
+}
+
+Item_sum_distinct::~Item_sum_distinct()
+{
+ delete tree;
+ /* no need to free the table */
+}
+
+
+void Item_sum_distinct::calculate_val_and_count()
+{
+ count= 0;
+ val.traits->set_zero(&val);
+ /*
+ We don't have a tree only if 'setup()' hasn't been called;
+ this is the case of sql_select.cc:return_zero_rows.
+ */
+ if (tree)
+ {
+ table->field[0]->set_notnull();
+ tree->walk(item_sum_distinct_walk, (void*) this);
+ }
+}
+
+
+double Item_sum_distinct::val_real()
+{
+ calculate_val_and_count();
+ return val.traits->val_real(&val);
+}
+
+
+my_decimal *Item_sum_distinct::val_decimal(my_decimal *to)
+{
+ calculate_val_and_count();
+ if (null_value)
+ return 0;
+ return val.traits->val_decimal(&val, to);
+}
+
+
+longlong Item_sum_distinct::val_int()
+{
+ calculate_val_and_count();
+ return val.traits->val_int(&val, unsigned_flag);
+}
+
+
+String *Item_sum_distinct::val_str(String *str)
+{
+ calculate_val_and_count();
+ if (null_value)
+ return 0;
+ return val.traits->val_str(&val, str, decimals);
+}
+
+/* end of Item_sum_distinct */
+
+/* Item_sum_avg_distinct */
+
+void
+Item_sum_avg_distinct::fix_length_and_dec()
+{
+ Item_sum_distinct::fix_length_and_dec();
+ /*
+ AVG() will divide val by count. We need to reserve digits
+ after decimal point as the result can be fractional.
+ */
+ decimals= min(decimals + 4, NOT_FIXED_DEC);
+}
+
+
+void
+Item_sum_avg_distinct::calculate_val_and_count()
+{
+ Item_sum_distinct::calculate_val_and_count();
+ if (count)
+ val.traits->div(&val, count);
+}
+
+
Item *Item_sum_count::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_count(thd, this);
@@ -321,6 +786,20 @@ void Item_sum_count::cleanup()
/*
Avgerage
*/
+void Item_sum_avg::fix_length_and_dec()
+{
+ Item_sum_sum::fix_length_and_dec();
+ maybe_null=null_value=1;
+ decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ f_scale= args[0]->decimals;
+ max_length= DECIMAL_MAX_LENGTH + (f_scale ? 1 : 0);
+ f_precision= DECIMAL_MAX_LENGTH;
+ dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
+ }
+}
+
Item *Item_sum_avg::copy_or_same(THD* thd)
{
@@ -328,24 +807,44 @@ Item *Item_sum_avg::copy_or_same(THD* thd)
}
+Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_len)
+{
+ if (group)
+ {
+ /*
+ We must store both value and counter in the temporary table in one field.
+ The easyest way is to do this is to store both value in a string
+ and unpack on access.
+ */
+ return new Field_string(((hybrid_type == DECIMAL_RESULT) ?
+ dec_bin_size : sizeof(double)) + sizeof(longlong),
+ 0, name, table, &my_charset_bin);
+ }
+ if (hybrid_type == DECIMAL_RESULT)
+ return new Field_new_decimal(f_precision,
+ maybe_null, name, table, f_scale);
+ return new Field_double(max_length, maybe_null, name, table, decimals);
+}
+
+
void Item_sum_avg::clear()
{
- sum=0.0; count=0;
+ Item_sum_sum::clear();
+ count=0;
}
bool Item_sum_avg::add()
{
- double nr=args[0]->val();
+ if (Item_sum_sum::add())
+ return TRUE;
if (!args[0]->null_value)
- {
- sum+=nr;
count++;
- }
- return 0;
+ return FALSE;
}
-double Item_sum_avg::val()
+double Item_sum_avg::val_real()
{
DBUG_ASSERT(fixed == 1);
if (!count)
@@ -353,8 +852,32 @@ double Item_sum_avg::val()
null_value=1;
return 0.0;
}
- null_value=0;
- return sum/ulonglong2double(count);
+ return Item_sum_sum::val_real() / ulonglong2double(count);
+}
+
+
+my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
+{
+ my_decimal sum, cnt;
+ const my_decimal *sum_dec;
+ DBUG_ASSERT(fixed == 1);
+ if (!count)
+ {
+ null_value=1;
+ return NULL;
+ }
+ sum_dec= Item_sum_sum::val_decimal(&sum);
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt);
+ my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, 4);
+ return val;
+}
+
+
+String *Item_sum_avg::val_str(String *str)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ return val_string_from_decimal(str);
+ return val_string_from_real(str);
}
@@ -362,10 +885,10 @@ double Item_sum_avg::val()
Standard deviation
*/
-double Item_sum_std::val()
+double Item_sum_std::val_real()
{
DBUG_ASSERT(fixed == 1);
- double tmp= Item_sum_variance::val();
+ double tmp= Item_sum_variance::val_real();
return tmp <= 0.0 ? 0.0 : sqrt(tmp);
}
@@ -379,34 +902,158 @@ Item *Item_sum_std::copy_or_same(THD* thd)
Variance
*/
+
+Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item):
+ Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
+ cur_dec(item->cur_dec), count(item->count), sample(item->sample)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ memcpy(dec_sum, item->dec_sum, sizeof(item->dec_sum));
+ memcpy(dec_sqr, item->dec_sqr, sizeof(item->dec_sqr));
+ for (int i=0; i<2; i++)
+ {
+ dec_sum[i].fix_buffer_pointer();
+ dec_sqr[i].fix_buffer_pointer();
+ }
+ }
+ else
+ {
+ sum= item->sum;
+ sum_sqr= item->sum_sqr;
+ }
+}
+
+
+void Item_sum_variance::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_sum_variance::fix_length_and_dec");
+ maybe_null= null_value= 1;
+ decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC);
+ switch (args[0]->result_type()) {
+ case REAL_RESULT:
+ case STRING_RESULT:
+ hybrid_type= REAL_RESULT;
+ sum= 0.0;
+ break;
+ case INT_RESULT:
+ case DECIMAL_RESULT:
+ /*
+ SUM result can't be longer than length(arg)*2 +
+ digits_after_the_point_to_add
+ */
+ max_length= args[0]->max_length*2 + 4;
+ cur_dec= 0;
+ hybrid_type= DECIMAL_RESULT;
+ my_decimal_set_zero(dec_sum);
+ my_decimal_set_zero(dec_sqr);
+
+ /*
+ The maxium value to usable for variance is DECIMAL_MAX_LENGTH/2
+ becasue we need to be able to calculate in dec_bin_size1
+ column_value * column_value
+ */
+ f_scale0= args[0]->decimals;
+ f_precision0= DECIMAL_MAX_LENGTH / 2;
+ f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1);
+ f_precision1= DECIMAL_MAX_LENGTH;
+ dec_bin_size0= my_decimal_get_binary_size(f_precision0, f_scale0);
+ dec_bin_size1= my_decimal_get_binary_size(f_precision1, f_scale1);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_PRINT("info", ("Type: %s (%d, %d)",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--"),
+ max_length,
+ (int)decimals));
+ DBUG_VOID_RETURN;
+}
+
+
Item *Item_sum_variance::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_variance(thd, this);
}
+Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_len)
+{
+ if (group)
+ {
+ /*
+ We must store both value and counter in the temporary table in one field.
+ The easyest way is to do this is to store both value in a string
+ and unpack on access.
+ */
+ return new Field_string(((hybrid_type == DECIMAL_RESULT) ?
+ dec_bin_size0 + dec_bin_size1 :
+ sizeof(double)*2) + sizeof(longlong),
+ 0, name, table, &my_charset_bin);
+ }
+ if (hybrid_type == DECIMAL_RESULT)
+ return new Field_new_decimal(DECIMAL_MAX_LENGTH,
+ maybe_null, name, table, f_scale1 + 4);
+ return new Field_double(max_length, maybe_null,name,table,decimals);
+}
+
+
void Item_sum_variance::clear()
{
- sum=sum_sqr=0.0;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal_set_zero(dec_sum);
+ my_decimal_set_zero(dec_sqr);
+ cur_dec= 0;
+ }
+ else
+ sum=sum_sqr=0.0;
count=0;
}
bool Item_sum_variance::add()
{
- double nr=args[0]->val();
- if (!args[0]->null_value)
+ if (hybrid_type == DECIMAL_RESULT)
{
- sum+=nr;
- sum_sqr+=nr*nr;
- count++;
+ my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf);
+ my_decimal sqr_buf;
+ if (!args[0]->null_value)
+ {
+ count++;
+ int next_dec= cur_dec ^ 1;
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr+next_dec,
+ dec_sqr+cur_dec, &sqr_buf);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sum+next_dec,
+ dec_sum+cur_dec, dec);
+ cur_dec= next_dec;
+ }
+ }
+ else
+ {
+ double nr= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ sum+=nr;
+ sum_sqr+=nr*nr;
+ count++;
+ }
}
return 0;
}
-double Item_sum_variance::val()
+double Item_sum_variance::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (!count)
+ if (hybrid_type == DECIMAL_RESULT)
+ return val_real_from_decimal();
+
+ if (count <= sample)
{
null_value=1;
return 0.0;
@@ -414,38 +1061,115 @@ double Item_sum_variance::val()
null_value=0;
/* Avoid problems when the precision isn't good enough */
double tmp=ulonglong2double(count);
- double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
+ double tmp2= (sum_sqr - sum*sum/tmp)/(tmp - (double)sample);
return tmp2 <= 0.0 ? 0.0 : tmp2;
}
+
+my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf)
+{
+ my_decimal count_buf, count1_buf, sum_sqr_buf;
+ DBUG_ASSERT(fixed ==1 );
+ if (hybrid_type == REAL_RESULT)
+ return val_decimal_from_real(dec_buf);
+
+ if (count <= sample)
+ {
+ null_value= 1;
+ return 0;
+ }
+ null_value= 0;
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_buf);
+ int2my_decimal(E_DEC_FATAL_ERROR, count-sample, 0, &count1_buf);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf,
+ dec_sum+cur_dec, dec_sum+cur_dec);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count_buf, 2);
+ my_decimal_sub(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sqr+cur_dec, dec_buf);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count1_buf, 2);
+ return dec_buf;
+}
+
+
void Item_sum_variance::reset_field()
{
- double nr=args[0]->val();
- char *res=result_field->ptr;
+ double nr;
+ char *res= result_field->ptr;
+
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_dec, *arg2_dec;
+ longlong tmp;
+
+ arg_dec= args[0]->val_decimal(&value);
+ if (args[0]->null_value)
+ {
+ arg_dec= arg2_dec= &decimal_zero;
+ tmp= 0;
+ }
+ else
+ {
+ my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum, arg_dec, arg_dec);
+ arg2_dec= dec_sum;
+ tmp= 1;
+ }
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec,
+ res, f_precision0, f_scale0);
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg2_dec,
+ res+dec_bin_size0, f_precision1, f_scale1);
+ res+= dec_bin_size0 + dec_bin_size1;
+ int8store(res,tmp);
+ return;
+ }
+ nr= args[0]->val_real();
if (args[0]->null_value)
bzero(res,sizeof(double)*2+sizeof(longlong));
else
{
+ longlong tmp;
float8store(res,nr);
nr*=nr;
float8store(res+sizeof(double),nr);
- longlong tmp=1;
+ tmp= 1;
int8store(res+sizeof(double)*2,tmp);
}
}
+
void Item_sum_variance::update_field()
{
- double nr,old_nr,old_sqr;
longlong field_count;
char *res=result_field->ptr;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ binary2my_decimal(E_DEC_FATAL_ERROR, res,
+ dec_sum+1, f_precision0, f_scale0);
+ binary2my_decimal(E_DEC_FATAL_ERROR, res+dec_bin_size0,
+ dec_sqr+1, f_precision1, f_scale1);
+ field_count= sint8korr(res + (dec_bin_size0 + dec_bin_size1));
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sum, arg_val, dec_sum+1);
+ my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum+1, arg_val, arg_val);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr, dec_sqr+1, dec_sum+1);
+ field_count++;
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum,
+ res, f_precision0, f_scale0);
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_sqr,
+ res+dec_bin_size0, f_precision1, f_scale1);
+ res+= dec_bin_size0 + dec_bin_size1;
+ int8store(res, field_count);
+ }
+ return;
+ }
+ double nr,old_nr,old_sqr;
float8get(old_nr, res);
float8get(old_sqr, res+sizeof(double));
field_count=sint8korr(res+sizeof(double)*2);
- nr=args[0]->val();
+ nr= args[0]->val_real();
if (!args[0]->null_value)
{
old_nr+=nr;
@@ -454,35 +1178,52 @@ void Item_sum_variance::update_field()
}
float8store(res,old_nr);
float8store(res+sizeof(double),old_sqr);
- int8store(res+sizeof(double)*2,field_count);
+ res+= sizeof(double)*2;
+ int8store(res,field_count);
}
+
/* min & max */
void Item_sum_hybrid::clear()
{
- sum= 0.0;
- sum_int= 0;
- value.length(0);
+ switch (hybrid_type) {
+ case INT_RESULT:
+ sum_int= 0;
+ break;
+ case DECIMAL_RESULT:
+ my_decimal_set_zero(&sum_dec);
+ break;
+ case REAL_RESULT:
+ sum= 0.0;
+ break;
+ default:
+ value.length(0);
+ }
null_value= 1;
}
-double Item_sum_hybrid::val()
+double Item_sum_hybrid::val_real()
{
DBUG_ASSERT(fixed == 1);
- int err;
- char *end_not_used;
if (null_value)
return 0.0;
switch (hybrid_type) {
case STRING_RESULT:
+ {
+ char *end_not_used;
+ int err_not_used;
String *res; res=val_str(&str_value);
- return (res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
- &end_not_used, &err) : 0.0);
+ return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
+ &end_not_used, &err_not_used) : 0.0);
+ }
case INT_RESULT:
if (unsigned_flag)
return ulonglong2double(sum_int);
return (double) sum_int;
+ case DECIMAL_RESULT:
+ my_decimal2double(E_DEC_FATAL_ERROR, &sum_dec, &sum);
+ return sum;
case REAL_RESULT:
return sum;
case ROW_RESULT:
@@ -491,7 +1232,6 @@ double Item_sum_hybrid::val()
DBUG_ASSERT(0);
return 0;
}
- return 0; // Keep compiler happy
}
longlong Item_sum_hybrid::val_int()
@@ -499,9 +1239,46 @@ longlong Item_sum_hybrid::val_int()
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
- if (hybrid_type == INT_RESULT)
+ switch (hybrid_type) {
+ case INT_RESULT:
return sum_int;
- return (longlong) Item_sum_hybrid::val();
+ case DECIMAL_RESULT:
+ {
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, &sum_dec, unsigned_flag, &result);
+ return sum_int;
+ }
+ default:
+ return (longlong) Item_sum_hybrid::val_real();
+ }
+}
+
+
+my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (null_value)
+ return 0;
+ switch (hybrid_type) {
+ case STRING_RESULT:
+ string2my_decimal(E_DEC_FATAL_ERROR, &value, val);
+ break;
+ case REAL_RESULT:
+ double2my_decimal(E_DEC_FATAL_ERROR, sum, val);
+ break;
+ case DECIMAL_RESULT:
+ val= &sum_dec;
+ break;
+ case INT_RESULT:
+ int2my_decimal(E_DEC_FATAL_ERROR, sum_int, unsigned_flag, val);
+ break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
+ }
+ return val; // Keep compiler happy
}
@@ -517,6 +1294,9 @@ Item_sum_hybrid::val_str(String *str)
case REAL_RESULT:
str->set(sum,decimals, &my_charset_bin);
break;
+ case DECIMAL_RESULT:
+ my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str);
+ return str;
case INT_RESULT:
if (unsigned_flag)
str->set((ulonglong) sum_int, &my_charset_bin);
@@ -590,9 +1370,20 @@ bool Item_sum_min::add()
}
}
break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value &&
+ (null_value || (my_decimal_cmp(&sum_dec, val) > 0)))
+ {
+ my_decimal2decimal(val, &sum_dec);
+ null_value= 0;
+ }
+ }
+ break;
case REAL_RESULT:
{
- double nr=args[0]->val();
+ double nr= args[0]->val_real();
if (!args[0]->null_value && (null_value || nr < sum))
{
sum=nr;
@@ -643,9 +1434,20 @@ bool Item_sum_max::add()
}
}
break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value &&
+ (null_value || (my_decimal_cmp(val, &sum_dec) > 0)))
+ {
+ my_decimal2decimal(val, &sum_dec);
+ null_value= 0;
+ }
+ }
+ break;
case REAL_RESULT:
{
- double nr=args[0]->val();
+ double nr= args[0]->val_real();
if (!args[0]->null_value && (null_value || nr > sum))
{
sum=nr;
@@ -725,7 +1527,7 @@ bool Item_sum_and::add()
void Item_sum_num::reset_field()
{
- double nr=args[0]->val();
+ double nr= args[0]->val_real();
char *res=result_field->ptr;
if (maybe_null)
@@ -744,7 +1546,8 @@ void Item_sum_num::reset_field()
void Item_sum_hybrid::reset_field()
{
- if (hybrid_type == STRING_RESULT)
+ switch(hybrid_type) {
+ case STRING_RESULT:
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff),result_field->charset()),*res;
@@ -760,8 +1563,9 @@ void Item_sum_hybrid::reset_field()
result_field->set_notnull();
result_field->store(res->ptr(),res->length(),tmp.charset());
}
+ break;
}
- else if (hybrid_type == INT_RESULT)
+ case INT_RESULT:
{
longlong nr=args[0]->val_int();
@@ -776,10 +1580,11 @@ void Item_sum_hybrid::reset_field()
result_field->set_notnull();
}
result_field->store(nr);
+ break;
}
- else // REAL_RESULT
+ case REAL_RESULT:
{
- double nr=args[0]->val();
+ double nr= args[0]->val_real();
if (maybe_null)
{
@@ -792,14 +1597,50 @@ void Item_sum_hybrid::reset_field()
result_field->set_notnull();
}
result_field->store(nr);
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+
+ if (maybe_null)
+ {
+ if (args[0]->null_value)
+ result_field->set_null();
+ else
+ result_field->set_notnull();
+ }
+ /*
+ We must store zero in the field as we will use the field value in
+ add()
+ */
+ if (!arg_dec) // Null
+ arg_dec= &decimal_zero;
+ result_field->store_decimal(arg_dec);
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
}
void Item_sum_sum::reset_field()
{
- double nr=args[0]->val(); // Nulls also return 0
- float8store(result_field->ptr,nr);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!arg_val) // Null
+ arg_val= &decimal_zero;
+ result_field->store_decimal(arg_val);
+ }
+ else
+ {
+ DBUG_ASSERT(hybrid_type == REAL_RESULT);
+ double nr= args[0]->val_real(); // Nulls also return 0
+ float8store(result_field->ptr, nr);
+ }
if (args[0]->null_value)
result_field->set_null();
else
@@ -826,20 +1667,39 @@ void Item_sum_count::reset_field()
void Item_sum_avg::reset_field()
{
- double nr=args[0]->val();
char *res=result_field->ptr;
-
- if (args[0]->null_value)
- bzero(res,sizeof(double)+sizeof(longlong));
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ longlong tmp;
+ my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+ if (args[0]->null_value)
+ {
+ arg_dec= &decimal_zero;
+ tmp= 0;
+ }
+ else
+ tmp= 1;
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale);
+ res+= dec_bin_size;
+ int8store(res, tmp);
+ }
else
{
- float8store(res,nr);
- res+=sizeof(double);
- longlong tmp=1;
- int8store(res,tmp);
+ double nr= args[0]->val_real();
+
+ if (args[0]->null_value)
+ bzero(res,sizeof(double)+sizeof(longlong));
+ else
+ {
+ longlong tmp= 1;
+ float8store(res,nr);
+ res+=sizeof(double);
+ int8store(res,tmp);
+ }
}
}
+
void Item_sum_bit::reset_field()
{
reset();
@@ -854,23 +1714,46 @@ void Item_sum_bit::update_field()
int8store(res, bits);
}
+
/*
** calc next value and merge it with field_value
*/
void Item_sum_sum::update_field()
{
- double old_nr,nr;
- char *res=result_field->ptr;
-
- float8get(old_nr,res);
- nr=args[0]->val();
- if (!args[0]->null_value)
+ if (hybrid_type == DECIMAL_RESULT)
{
- old_nr+=nr;
- result_field->set_notnull();
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ if (!result_field->is_null())
+ {
+ my_decimal field_value,
+ *field_val= result_field->val_decimal(&field_value);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, field_val);
+ result_field->store_decimal(dec_buffs);
+ }
+ else
+ {
+ result_field->store_decimal(arg_val);
+ result_field->set_notnull();
+ }
+ }
+ }
+ else
+ {
+ double old_nr,nr;
+ char *res=result_field->ptr;
+
+ float8get(old_nr,res);
+ nr= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ old_nr+=nr;
+ result_field->set_notnull();
+ }
+ float8store(res,old_nr);
}
- float8store(res,old_nr);
}
@@ -894,32 +1777,59 @@ void Item_sum_count::update_field()
void Item_sum_avg::update_field()
{
- double nr,old_nr;
longlong field_count;
char *res=result_field->ptr;
-
- float8get(old_nr,res);
- field_count=sint8korr(res+sizeof(double));
-
- nr=args[0]->val();
- if (!args[0]->null_value)
+ if (hybrid_type == DECIMAL_RESULT)
{
- old_nr+=nr;
- field_count++;
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ binary2my_decimal(E_DEC_FATAL_ERROR, res,
+ dec_buffs + 1, f_precision, f_scale);
+ field_count= sint8korr(res + dec_bin_size);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1);
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs,
+ res, f_precision, f_scale);
+ res+= dec_bin_size;
+ field_count++;
+ int8store(res, field_count);
+ }
+ }
+ else
+ {
+ double nr;
+
+ nr= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ double old_nr;
+ float8get(old_nr, res);
+ field_count= sint8korr(res + sizeof(double));
+ old_nr+= nr;
+ float8store(res,old_nr);
+ res+= sizeof(double);
+ field_count++;
+ int8store(res, field_count);
+ }
}
- float8store(res,old_nr);
- res+=sizeof(double);
- int8store(res,field_count);
}
+
void Item_sum_hybrid::update_field()
{
- if (hybrid_type == STRING_RESULT)
+ switch (hybrid_type) {
+ case STRING_RESULT:
min_max_update_str_field();
- else if (hybrid_type == INT_RESULT)
+ break;
+ case INT_RESULT:
min_max_update_int_field();
- else
+ break;
+ case DECIMAL_RESULT:
+ min_max_update_decimal_field();
+ break;
+ default:
min_max_update_real_field();
+ }
}
@@ -947,7 +1857,7 @@ Item_sum_hybrid::min_max_update_real_field()
double nr,old_nr;
old_nr=result_field->val_real();
- nr=args[0]->val();
+ nr= args[0]->val_real();
if (!args[0]->null_value)
{
if (result_field->is_null(0) ||
@@ -989,56 +1899,156 @@ Item_sum_hybrid::min_max_update_int_field()
}
-Item_avg_field::Item_avg_field(Item_sum_avg *item)
+void
+Item_sum_hybrid::min_max_update_decimal_field()
+{
+ /* TODO: optimize: do not get result_field in case of args[0] is NULL */
+ my_decimal old_val, nr_val;
+ const my_decimal *old_nr= result_field->val_decimal(&old_val);
+ const my_decimal *nr= args[0]->val_decimal(&nr_val);
+ if (!args[0]->null_value)
+ {
+ if (result_field->is_null(0))
+ old_nr=nr;
+ else
+ {
+ bool res= my_decimal_cmp(old_nr, nr) > 0;
+ /* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */
+ if ((cmp_sign > 0) ^ (!res))
+ old_nr=nr;
+ }
+ result_field->set_notnull();
+ }
+ else if (result_field->is_null(0))
+ result_field->set_null();
+ result_field->store_decimal(old_nr);
+}
+
+
+Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item)
{
name=item->name;
decimals=item->decimals;
max_length=item->max_length;
field=item->result_field;
maybe_null=1;
+ hybrid_type= res_type;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ f_scale= item->f_scale;
+ f_precision= item->f_precision;
+ dec_bin_size= item->dec_bin_size;
+ }
}
-double Item_avg_field::val()
+double Item_avg_field::val_real()
{
// fix_fields() never calls for this Item
double nr;
longlong count;
+ char *res;
+
+ if (hybrid_type == DECIMAL_RESULT)
+ return val_real_from_decimal();
+
float8get(nr,field->ptr);
- char *res=(field->ptr+sizeof(double));
- count=sint8korr(res);
+ res= (field->ptr+sizeof(double));
+ count= sint8korr(res);
- if (!count)
- {
- null_value=1;
+ if ((null_value= !count))
return 0.0;
- }
- null_value=0;
return nr/(double) count;
}
-String *Item_avg_field::val_str(String *str)
+
+longlong Item_avg_field::val_int()
+{
+ return (longlong) val_real();
+}
+
+
+my_decimal *Item_avg_field::val_decimal(my_decimal *dec_buf)
{
// fix_fields() never calls for this Item
- double nr=Item_avg_field::val();
- if (null_value)
+ if (hybrid_type == REAL_RESULT)
+ return val_decimal_from_real(dec_buf);
+
+ longlong count= sint8korr(field->ptr + dec_bin_size);
+ if ((null_value= !count))
return 0;
- str->set(nr,decimals, &my_charset_bin);
- return str;
+
+ my_decimal dec_count, dec_field;
+ binary2my_decimal(E_DEC_FATAL_ERROR,
+ field->ptr, &dec_field, f_precision, f_scale);
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_field, &dec_count, 4);
+ return dec_buf;
+}
+
+
+String *Item_avg_field::val_str(String *str)
+{
+ // fix_fields() never calls for this Item
+ if (hybrid_type == DECIMAL_RESULT)
+ return val_string_from_decimal(str);
+ return val_string_from_real(str);
}
+
Item_std_field::Item_std_field(Item_sum_std *item)
: Item_variance_field(item)
{
}
-double Item_std_field::val()
+
+double Item_std_field::val_real()
{
+ double nr;
// fix_fields() never calls for this Item
- double tmp= Item_variance_field::val();
- return tmp <= 0.0 ? 0.0 : sqrt(tmp);
+ if (hybrid_type == REAL_RESULT)
+ {
+ /*
+ We can't call Item_variance_field::val_real() on a DECIMAL_RESULT
+ as this would call Item_std_field::val_decimal() and we would
+ calculate sqrt() twice
+ */
+ nr= Item_variance_field::val_real();
+ }
+ else
+ {
+ my_decimal dec_buf,*dec;
+ dec= Item_variance_field::val_decimal(&dec_buf);
+ if (!dec)
+ nr= 0.0; // NULL; Return 0.0
+ else
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr);
+ }
+ return nr <= 0.0 ? 0.0 : sqrt(nr);
}
+
+my_decimal *Item_std_field::val_decimal(my_decimal *dec_buf)
+{
+ /*
+ We can't call val_decimal_from_real() for DECIMAL_RESULT as
+ Item_variance_field::val_real() would cause an infinite loop
+ */
+ my_decimal tmp_dec, *dec;
+ double nr;
+ if (hybrid_type == REAL_RESULT)
+ return val_decimal_from_real(dec_buf);
+ dec= Item_variance_field::val_decimal(dec_buf);
+ if (!dec)
+ return 0;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr);
+ nr= nr <= 0.0 ? 0.0 : sqrt(nr);
+ double2my_decimal(E_DEC_FATAL_ERROR, nr, &tmp_dec);
+ my_decimal_round(E_DEC_FATAL_ERROR, &tmp_dec, decimals, FALSE, dec_buf);
+ return dec_buf;
+}
+
+
Item_variance_field::Item_variance_field(Item_sum_variance *item)
{
name=item->name;
@@ -1046,57 +2056,81 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item)
max_length=item->max_length;
field=item->result_field;
maybe_null=1;
+ sample= item->sample;
+ if ((hybrid_type= item->hybrid_type) == DECIMAL_RESULT)
+ {
+ f_scale0= item->f_scale0;
+ f_precision0= item->f_precision0;
+ dec_bin_size0= item->dec_bin_size0;
+ f_scale1= item->f_scale1;
+ f_precision1= item->f_precision1;
+ dec_bin_size1= item->dec_bin_size1;
+ }
}
-double Item_variance_field::val()
+
+double Item_variance_field::val_real()
{
// fix_fields() never calls for this Item
+ if (hybrid_type == DECIMAL_RESULT)
+ return val_real_from_decimal();
+
double sum,sum_sqr;
longlong count;
float8get(sum,field->ptr);
float8get(sum_sqr,(field->ptr+sizeof(double)));
count=sint8korr(field->ptr+sizeof(double)*2);
- if (!count)
- {
- null_value=1;
+ if ((null_value= (count <= sample)))
return 0.0;
- }
- null_value=0;
+
double tmp= (double) count;
- double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
+ double tmp2= (sum_sqr - sum*sum/tmp)/(tmp - (double)sample);
return tmp2 <= 0.0 ? 0.0 : tmp2;
}
+
String *Item_variance_field::val_str(String *str)
{
+ if (hybrid_type == DECIMAL_RESULT)
+ return val_string_from_decimal(str);
+ return val_string_from_real(str);
+}
+
+
+my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf)
+{
// fix_fields() never calls for this Item
- double nr=val();
- if (null_value)
+ if (hybrid_type == REAL_RESULT)
+ return val_decimal_from_real(dec_buf);
+
+ longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1);
+ if ((null_value= (count <= sample)))
return 0;
- str->set(nr,decimals, &my_charset_bin);
- return str;
+
+ my_decimal dec_count, dec1_count, dec_sum, dec_sqr, tmp;
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
+ int2my_decimal(E_DEC_FATAL_ERROR, count-sample, 0, &dec1_count);
+ binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr,
+ &dec_sum, f_precision0, f_scale0);
+ binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr+dec_bin_size0,
+ &dec_sqr, f_precision1, f_scale1);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &tmp, &dec_sum, &dec_sum);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &tmp, &dec_count, 2);
+ my_decimal_sub(E_DEC_FATAL_ERROR, &dec_sum, &dec_sqr, dec_buf);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_sum, &dec1_count, 2);
+ return dec_buf;
}
+
/****************************************************************************
** COUNT(DISTINCT ...)
****************************************************************************/
-#include "sql_select.h"
-
-int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
-{
- return memcmp(key1, key2, *(uint*) arg);
-}
-
int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
{
- Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
- CHARSET_INFO *cs=item->key_charset;
- uint len=item->key_length;
- return cs->coll->strnncollsp(cs,
- (const uchar*) key1, len,
- (const uchar*) key2, len);
+ Field *f= (Field*) arg;
+ return f->cmp((const char*)key1, (const char*)key2);
}
/*
@@ -1110,13 +2144,13 @@ int composite_key_cmp(void* arg, byte* key1, byte* key2)
{
Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
Field **field = item->table->field;
- Field **field_end= field + item->table->fields;
+ Field **field_end= field + item->table->s->fields;
uint32 *lengths=item->field_lengths;
for (; field < field_end; ++field)
{
Field* f = *field;
int len = *lengths++;
- int res = f->key_cmp(key1, key2);
+ int res = f->cmp((char *) key1, (char *) key2);
if (res)
return res;
key1 += len;
@@ -1125,54 +2159,42 @@ int composite_key_cmp(void* arg, byte* key1, byte* key2)
return 0;
}
-/*
- helper function for walking the tree when we dump it to MyISAM -
- tree_walk will call it for each leaf
-*/
-int dump_leaf(byte* key, uint32 count __attribute__((unused)),
- Item_sum_count_distinct* item)
+C_MODE_START
+
+static int count_distinct_walk(void *elem, element_count count, void *arg)
{
- byte* buf = item->table->record[0];
- int error;
- /*
- The first item->rec_offset bytes are taken care of with
- restore_record(table,default_values) in setup()
- */
- memcpy(buf + item->rec_offset, key, item->tree->size_of_element);
- if ((error = item->table->file->write_row(buf)))
- {
- if (error != HA_ERR_FOUND_DUPP_KEY &&
- error != HA_ERR_FOUND_DUPP_UNIQUE)
- return 1;
- }
+ (*((ulonglong*)arg))++;
return 0;
}
+C_MODE_END
+
void Item_sum_count_distinct::cleanup()
{
DBUG_ENTER("Item_sum_count_distinct::cleanup");
Item_sum_int::cleanup();
- /*
- Free table and tree if they belong to this item (if item have not pointer
- to original item from which was made copy => it own its objects )
- */
+
+ /* Free objects only if we own them. */
if (!original)
{
+ /*
+ We need to delete the table and the tree in cleanup() as
+ they were allocated in the runtime memroot. Using the runtime
+ memroot reduces memory footprint for PS/SP and simplifies setup().
+ */
+ delete tree;
+ tree= 0;
if (table)
{
- free_tmp_table(current_thd, table);
+ free_tmp_table(table->in_use, table);
table= 0;
}
delete tmp_table_param;
tmp_table_param= 0;
- if (use_tree)
- {
- delete_tree(tree);
- use_tree= 0;
- }
}
+ always_null= FALSE;
DBUG_VOID_RETURN;
}
@@ -1183,8 +2205,15 @@ void Item_sum_count_distinct::make_unique()
{
table=0;
original= 0;
- use_tree= 0; // to prevent delete_tree call on uninitialized tree
- tree= &tree_base;
+ tree= 0;
+ tmp_table_param= 0;
+ always_null= FALSE;
+}
+
+
+Item_sum_count_distinct::~Item_sum_count_distinct()
+{
+ cleanup();
}
@@ -1192,18 +2221,23 @@ bool Item_sum_count_distinct::setup(THD *thd)
{
List<Item> list;
SELECT_LEX *select_lex= thd->lex->current_select;
- if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
- return 1;
-
+
+ /*
+ Setup can be called twice for ROLLUP items. This is a bug.
+ Please add DBUG_ASSERT(tree == 0) here when it's fixed.
+ */
+ if (tree || table || tmp_table_param)
+ return FALSE;
+
if (!(tmp_table_param= new TMP_TABLE_PARAM))
- return 1;
+ return TRUE;
/* Create a table with an unique key over all parameters */
for (uint i=0; i < arg_count ; i++)
{
Item *item=args[i];
if (list.push_back(item))
- return 1; // End of memory
+ return TRUE; // End of memory
if (item->const_item())
{
(void) item->val_int();
@@ -1212,139 +2246,88 @@ bool Item_sum_count_distinct::setup(THD *thd)
}
}
if (always_null)
- return 0;
+ return FALSE;
count_field_types(tmp_table_param,list,0);
- if (table)
- {
- free_tmp_table(thd, table);
- tmp_table_param->cleanup();
- }
+ DBUG_ASSERT(table == 0);
if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
0,
select_lex->options | thd->options,
HA_POS_ERROR, (char*)"")))
- return 1;
+ return TRUE;
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1;
-
- // no blobs, otherwise it would be MyISAM
- if (table->db_type == DB_TYPE_HEAP)
+ if (table->s->db_type == DB_TYPE_HEAP)
{
+ /*
+ No blobs, otherwise it would have been MyISAM: set up a compare
+ function and its arguments to use with Unique.
+ */
qsort_cmp2 compare_key;
void* cmp_arg;
+ Field **field= table->field;
+ Field **field_end= field + table->s->fields;
+ bool all_binary= TRUE;
- // to make things easier for dump_leaf if we ever have to dump to MyISAM
- restore_record(table,default_values);
-
- if (table->fields == 1)
+ for (tree_key_length= 0; field < field_end; ++field)
{
- /*
- If we have only one field, which is the most common use of
- count(distinct), it is much faster to use a simpler key
- compare method that can take advantage of not having to worry
- about other fields
- */
- Field* field = table->field[0];
- switch(field->type())
+ Field *f= *field;
+ enum enum_field_types type= f->type();
+ tree_key_length+= f->pack_length();
+ if (!f->binary() && (type == MYSQL_TYPE_STRING ||
+ type == MYSQL_TYPE_VAR_STRING ||
+ type == MYSQL_TYPE_VARCHAR))
{
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
- if (field->binary())
- {
- compare_key = (qsort_cmp2)simple_raw_key_cmp;
- cmp_arg = (void*) &key_length;
- }
- else
- {
- /*
- If we have a string, we must take care of charsets and case
- sensitivity
- */
- compare_key = (qsort_cmp2)simple_str_key_cmp;
- cmp_arg = (void*) this;
- }
- break;
- default:
- /*
- Since at this point we cannot have blobs anything else can
- be compared with memcmp
- */
- compare_key = (qsort_cmp2)simple_raw_key_cmp;
- cmp_arg = (void*) &key_length;
- break;
+ all_binary= FALSE;
+ break;
}
- key_charset = field->charset();
- key_length = field->pack_length();
- rec_offset = 1;
}
- else // too bad, cannot cheat - there is more than one field
+ if (all_binary)
{
- bool all_binary = 1;
- Field** field, **field_end;
- field_end = (field = table->field) + table->fields;
- uint32 *lengths;
- if (!(field_lengths=
- (uint32*) thd->alloc(sizeof(uint32) * table->fields)))
- return 1;
-
- for (key_length = 0, lengths=field_lengths; field < field_end; ++field)
- {
- uint32 length= (*field)->pack_length();
- key_length += length;
- *lengths++ = length;
- if (!(*field)->binary())
- all_binary = 0; // Can't break loop here
- }
- rec_offset = table->reclength - key_length;
- if (all_binary)
+ cmp_arg= (void*) &tree_key_length;
+ compare_key= (qsort_cmp2) simple_raw_key_cmp;
+ }
+ else
+ {
+ if (table->s->fields == 1)
{
- compare_key = (qsort_cmp2)simple_raw_key_cmp;
- cmp_arg = (void*) &key_length;
+ /*
+ If we have only one field, which is the most common use of
+ count(distinct), it is much faster to use a simpler key
+ compare method that can take advantage of not having to worry
+ about other fields.
+ */
+ compare_key= (qsort_cmp2) simple_str_key_cmp;
+ cmp_arg= (void*) table->field[0];
+ /* tree_key_length has been set already */
}
else
{
- compare_key = (qsort_cmp2) composite_key_cmp ;
- cmp_arg = (void*) this;
+ uint32 *length;
+ compare_key= (qsort_cmp2) composite_key_cmp;
+ cmp_arg= (void*) this;
+ field_lengths= (uint32*) thd->alloc(table->s->fields * sizeof(uint32));
+ for (tree_key_length= 0, length= field_lengths, field= table->field;
+ field < field_end; ++field, ++length)
+ {
+ *length= (*field)->pack_length();
+ tree_key_length+= *length;
+ }
}
}
-
- if (use_tree)
- delete_tree(tree);
- init_tree(tree, min(thd->variables.max_heap_table_size,
- thd->variables.sortbuff_size/16), 0,
- key_length, compare_key, 0, NULL, cmp_arg);
- use_tree = 1;
-
+ DBUG_ASSERT(tree == 0);
+ tree= new Unique(compare_key, cmp_arg, tree_key_length,
+ thd->variables.max_heap_table_size);
/*
- The only time key_length could be 0 is if someone does
+ The only time tree_key_length could be 0 is if someone does
count(distinct) on a char(0) field - stupid thing to do,
but this has to be handled - otherwise someone can crash
the server with a DoS attack
*/
- max_elements_in_tree = ((key_length) ?
- thd->variables.max_heap_table_size/key_length : 1);
-
- }
- if (original)
- {
- original->table= table;
- original->use_tree= use_tree;
+ if (! tree)
+ return TRUE;
}
- return 0;
-}
-
-
-int Item_sum_count_distinct::tree_to_myisam()
-{
- if (create_myisam_from_heap(current_thd, table, tmp_table_param,
- HA_ERR_RECORD_FILE_FULL, 1) ||
- tree_walk(tree, (tree_walk_action)&dump_leaf, (void*)this,
- left_root_right))
- return 1;
- delete_tree(tree);
- use_tree = 0;
- return 0;
+ return FALSE;
}
@@ -1356,8 +2339,9 @@ Item *Item_sum_count_distinct::copy_or_same(THD* thd)
void Item_sum_count_distinct::clear()
{
- if (use_tree)
- reset_tree(tree);
+ /* tree and table can be both null only if always_null */
+ if (tree)
+ tree->reset();
else if (table)
{
table->file->extra(HA_EXTRA_NO_CACHE);
@@ -1378,32 +2362,21 @@ bool Item_sum_count_distinct::add()
if ((*field)->is_real_null(0))
return 0; // Don't count NULL
- if (use_tree)
+ if (tree)
{
/*
- If the tree got too big, convert to MyISAM, otherwise insert into the
- tree.
+ The first few bytes of record (at least one) are just markers
+ for deleted and NULLs. We want to skip them since they will
+ bloat the tree without providing any valuable info. Besides,
+ key_length used to initialize the tree didn't include space for them.
*/
- if (tree->elements_in_tree > max_elements_in_tree)
- {
- if (tree_to_myisam())
- return 1;
- }
- else if (!tree_insert(tree, table->record[0] + rec_offset, 0,
- tree->custom_arg))
- return 1;
- }
- else if ((error=table->file->write_row(table->record[0])))
- {
- if (error != HA_ERR_FOUND_DUPP_KEY &&
- error != HA_ERR_FOUND_DUPP_UNIQUE)
- {
- if (create_myisam_from_heap(current_thd, table, tmp_table_param, error,
- 1))
- return 1; // Not a table_is_full error
- }
+ return tree->unique_add(table->record[0] + table->s->null_bytes);
}
- return 0;
+ if ((error= table->file->write_row(table->record[0])) &&
+ error != HA_ERR_FOUND_DUPP_KEY &&
+ error != HA_ERR_FOUND_DUPP_UNIQUE)
+ return TRUE;
+ return FALSE;
}
@@ -1412,8 +2385,16 @@ longlong Item_sum_count_distinct::val_int()
DBUG_ASSERT(fixed == 1);
if (!table) // Empty query
return LL(0);
- if (use_tree)
- return tree->elements_in_tree;
+ if (tree)
+ {
+ ulonglong count;
+
+ if (tree->elements == 0)
+ return (longlong) tree->elements_in_tree(); // everything fits in memory
+ count= 0;
+ tree->walk(count_distinct_walk, (void*) &count);
+ return (longlong) count;
+ }
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
return table->file->records;
}
@@ -1454,7 +2435,7 @@ Item *Item_sum_udf_float::copy_or_same(THD* thd)
return new (thd->mem_root) Item_sum_udf_float(thd, this);
}
-double Item_sum_udf_float::val()
+double Item_sum_udf_float::val_real()
{
DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_sum_udf_float::val");
@@ -1463,14 +2444,51 @@ double Item_sum_udf_float::val()
DBUG_RETURN(udf.val(&null_value));
}
+
String *Item_sum_udf_float::val_str(String *str)
{
+ return val_string_from_real(str);
+}
+
+
+my_decimal *Item_sum_udf_float::val_decimal(my_decimal *dec)
+{
+ return val_decimal_from_real(dec);
+}
+
+
+String *Item_sum_udf_decimal::val_str(String *str)
+{
+ return val_string_from_decimal(str);
+}
+
+
+double Item_sum_udf_decimal::val_real()
+{
+ return val_real_from_decimal();
+}
+
+
+longlong Item_sum_udf_decimal::val_int()
+{
+ return val_int_from_decimal();
+}
+
+
+my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf)
+{
DBUG_ASSERT(fixed == 1);
- double nr=val();
- if (null_value)
- return 0; /* purecov: inspected */
- str->set(nr,decimals, &my_charset_bin);
- return str;
+ DBUG_ENTER("Item_func_udf_decimal::val_decimal");
+ DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ args[0]->result_type(), arg_count));
+
+ DBUG_RETURN(udf.val_decimal(&null_value, dec_buf));
+}
+
+
+Item *Item_sum_udf_decimal::copy_or_same(THD* thd)
+{
+ return new (thd->mem_root) Item_sum_udf_decimal(thd, this);
}
@@ -1479,7 +2497,6 @@ Item *Item_sum_udf_int::copy_or_same(THD* thd)
return new (thd->mem_root) Item_sum_udf_int(thd, this);
}
-
longlong Item_sum_udf_int::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -1492,14 +2509,15 @@ longlong Item_sum_udf_int::val_int()
String *Item_sum_udf_int::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
- longlong nr=val_int();
- if (null_value)
- return 0;
- str->set(nr, &my_charset_bin);
- return str;
+ return val_string_from_int(str);
+}
+
+my_decimal *Item_sum_udf_int::val_decimal(my_decimal *dec)
+{
+ return val_decimal_from_int(dec);
}
+
/* Default max_length is max argument length */
void Item_sum_udf_str::fix_length_and_dec()
@@ -1518,6 +2536,11 @@ Item *Item_sum_udf_str::copy_or_same(THD* thd)
}
+my_decimal *Item_sum_udf_str::val_decimal(my_decimal *dec)
+{
+ return val_decimal_from_string(dec);
+}
+
String *Item_sum_udf_str::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -1534,7 +2557,7 @@ String *Item_sum_udf_str::val_str(String *str)
GROUP_CONCAT function
SQL SYNTAX:
- GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...]
+ GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...]
[SEPARATOR str_const])
concat of values from "group by" operation
@@ -1554,8 +2577,9 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
byte* key2)
{
Item_func_group_concat* grp_item= (Item_func_group_concat*)arg;
+ TABLE *table= grp_item->table;
Item **field_item, **end;
- char *record= (char*) grp_item->table->record[0];
+ char *record= (char*) table->record[0] + table->s->null_bytes;
for (field_item= grp_item->args, end= field_item + grp_item->arg_count_field;
field_item < end;
@@ -1571,7 +2595,7 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
{
int res;
uint offset= (uint) (field->ptr - record);
- if ((res= field->key_cmp(key1 + offset, key2 + offset)))
+ if ((res= field->cmp((char *) key1 + offset, (char *) key2 + offset)))
return res;
}
}
@@ -1588,7 +2612,8 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
{
Item_func_group_concat* grp_item= (Item_func_group_concat*) arg;
ORDER **order_item, **end;
- char *record= (char*) grp_item->table->record[0];
+ TABLE *table= grp_item->table;
+ char *record= (char*) table->record[0] + table->s->null_bytes;
for (order_item= grp_item->order, end=order_item+ grp_item->arg_count_order;
order_item < end;
@@ -1601,18 +2626,19 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
the temporary table, not the original field
*/
Field *field= item->get_tmp_table_field();
+ /* If the item is a constant, there is no tmp table field */
if (field)
{
int res;
uint offset= (uint) (field->ptr - record);
- if ((res= field->key_cmp(key1 + offset, key2 + offset)))
+ if ((res= field->cmp((char *) key1 + offset, (char *) key2 + offset)))
return (*order_item)->asc ? res : -res;
}
}
/*
We can't return 0 because in that case the tree class would remove this
item as double value. This would cause problems for case-changes and
- if the the returned values are not the same we do the sort on.
+ if the returned values are not the same we do the sort on.
*/
return 1;
}
@@ -1641,51 +2667,51 @@ int group_concat_key_cmp_with_distinct_and_order(void* arg,byte* key1,
Append data from current leaf to item->result
*/
-int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
+int dump_leaf_key(byte* key, element_count count __attribute__((unused)),
Item_func_group_concat *item)
{
- char buff[MAX_FIELD_WIDTH];
- String tmp((char *)&buff,sizeof(buff),default_charset_info), tmp2;
- char *record= (char*) item->table->record[0];
+ TABLE *table= item->table;
+ char *record= (char*) table->record[0] + table->s->null_bytes;
+ String tmp((char *)table->record[1], table->s->reclength, default_charset_info), tmp2;
+ String *result= &item->result;
+ Item **arg= item->args, **arg_end= item->args + item->arg_count_field;
- if (item->result.length())
- item->result.append(*item->separator);
+ if (result->length())
+ result->append(*item->separator);
tmp.length(0);
-
- for (uint i= 0; i < item->arg_count_field; i++)
+
+ for (; arg < arg_end; arg++)
{
- Item *show_item= item->args[i];
- if (!show_item->const_item())
+ String *res;
+ if (! (*arg)->const_item())
{
/*
We have to use get_tmp_table_field() instead of
real_item()->get_tmp_table_field() because we want the field in
the temporary table, not the original field
+ We also can't use table->field array to access the fields
+ because it contains both order and arg list fields.
*/
- Field *field= show_item->get_tmp_table_field();
- String *res;
+ Field *field= (*arg)->get_tmp_table_field();
char *save_ptr= field->ptr;
uint offset= (uint) (save_ptr - record);
- DBUG_ASSERT(offset < item->table->reclength);
+ DBUG_ASSERT(offset < table->s->reclength);
field->ptr= (char *) key + offset;
res= field->val_str(&tmp,&tmp2);
- item->result.append(*res);
field->ptr= save_ptr;
}
- else
- {
- String *res= show_item->val_str(&tmp);
- if (res)
- item->result.append(*res);
- }
+ else
+ res= (*arg)->val_str(&tmp);
+ if (res)
+ result->append(*res);
}
- /* stop if length of result more than group_concat_max_len */
- if (item->result.length() > item->group_concat_max_len)
+ /* stop if length of result more than max_length */
+ if (result->length() > item->max_length)
{
item->count_cut_values++;
- item->result.length(item->group_concat_max_len);
+ result->length(item->max_length);
item->warning_for_row= TRUE;
return 1;
}
@@ -1695,36 +2721,31 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
/*
Constructor of Item_func_group_concat
- is_distinct - distinct
- is_select - list of expression for show values
- is_order - list of sort columns
- is_separator - string value of separator
+ distinct_arg - distinct
+ select_list - list of expression for show values
+ order_list - list of sort columns
+ separator_arg - string value of separator
*/
-Item_func_group_concat::Item_func_group_concat(bool is_distinct,
- List<Item> *is_select,
- SQL_LIST *is_order,
- String *is_separator)
- :Item_sum(), tmp_table_param(0), max_elements_in_tree(0), warning(0),
- key_length(0), tree_mode(0), distinct(is_distinct), warning_for_row(0),
- separator(is_separator), tree(&tree_base), table(0),
+Item_func_group_concat::
+Item_func_group_concat(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),
- arg_count_order(0), arg_count_field(0),
- count_cut_values(0)
+ arg_count_order(order_list ? order_list->elements : 0),
+ arg_count_field(select_list->elements),
+ count_cut_values(0),
+ distinct(distinct_arg),
+ warning_for_row(FALSE),
+ original(0)
{
Item *item_select;
Item **arg_ptr;
- original= 0;
- quick_group= 0;
- mark_as_sum_func();
- order= 0;
- group_concat_max_len= current_thd->variables.group_concat_max_len;
-
- arg_count_field= is_select->elements;
- arg_count_order= is_order ? is_order->elements : 0;
+ quick_group= FALSE;
arg_count= arg_count_field + arg_count_order;
-
+
/*
We need to allocate:
args - arg_count_field+arg_count_order
@@ -1732,23 +2753,23 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
order - arg_count_order
*/
if (!(args= (Item**) sql_alloc(sizeof(Item*) * arg_count +
- sizeof(ORDER*)*arg_count_order)))
+ sizeof(ORDER*)*arg_count_order)))
return;
order= (ORDER**)(args + arg_count);
/* fill args items of show and sort */
- List_iterator_fast<Item> li(*is_select);
+ List_iterator_fast<Item> li(*select_list);
for (arg_ptr=args ; (item_select= li++) ; arg_ptr++)
*arg_ptr= item_select;
- if (arg_count_order)
+ if (arg_count_order)
{
ORDER **order_ptr= order;
- for (ORDER *order_item= (ORDER*) is_order->first;
- order_item != NULL;
- order_item= order_item->next)
+ for (ORDER *order_item= (ORDER*) order_list->first;
+ order_item != NULL;
+ order_item= order_item->next)
{
(*order_ptr++)= order_item;
*arg_ptr= *order_item->item;
@@ -1756,28 +2777,24 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
}
}
}
-
+
Item_func_group_concat::Item_func_group_concat(THD *thd,
- Item_func_group_concat *item)
- :Item_sum(thd, item),item_thd(thd),
+ Item_func_group_concat *item)
+ :Item_sum(thd, item),
tmp_table_param(item->tmp_table_param),
- max_elements_in_tree(item->max_elements_in_tree),
warning(item->warning),
- key_length(item->key_length),
- tree_mode(item->tree_mode),
- distinct(item->distinct),
- warning_for_row(item->warning_for_row),
separator(item->separator),
tree(item->tree),
table(item->table),
order(item->order),
tables_list(item->tables_list),
- group_concat_max_len(item->group_concat_max_len),
arg_count_order(item->arg_count_order),
arg_count_field(item->arg_count_field),
- field_list_offset(item->field_list_offset),
count_cut_values(item->count_cut_values),
+ distinct(item->distinct),
+ warning_for_row(item->warning_for_row),
+ always_null(item->always_null),
original(item)
{
quick_group= item->quick_group;
@@ -1807,28 +2824,33 @@ void Item_func_group_concat::cleanup()
*/
if (!original)
{
+ delete tmp_table_param;
+ tmp_table_param= 0;
if (table)
{
+ THD *thd= table->in_use;
free_tmp_table(thd, table);
table= 0;
+ if (tree)
+ {
+ delete_tree(tree);
+ tree= 0;
+ }
+ if (warning)
+ {
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
+ warning->set_msg(thd, warn_buff);
+ warning= 0;
+ }
}
- delete tmp_table_param;
- tmp_table_param= 0;
- if (tree_mode)
- {
- tree_mode= 0;
- delete_tree(tree);
- }
+ DBUG_ASSERT(tree == 0);
+ DBUG_ASSERT(warning == 0);
}
DBUG_VOID_RETURN;
}
-Item_func_group_concat::~Item_func_group_concat()
-{
-}
-
-
Item *Item_func_group_concat::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_func_group_concat(thd, this);
@@ -1841,14 +2863,9 @@ void Item_func_group_concat::clear()
result.copy();
null_value= TRUE;
warning_for_row= FALSE;
- if (table)
- {
- table->file->extra(HA_EXTRA_NO_CACHE);
- table->file->delete_all_rows();
- table->file->extra(HA_EXTRA_WRITE_CACHE);
- }
- if (tree_mode)
+ if (tree)
reset_tree(tree);
+ /* No need to reset the table as we never call write_row */
}
@@ -1865,82 +2882,72 @@ bool Item_func_group_concat::add()
if (!show_item->const_item())
{
/*
- Here we use real_item as we want the original field data that should
- be written to table->record[0]
+ Here we use real_item as we want the original field data that should
+ be written to table->record[0]
*/
Field *f= show_item->real_item()->get_tmp_table_field();
if (f->is_null())
- return 0; // Skip row if it contains null
+ return 0; // Skip row if it contains null
}
}
null_value= FALSE;
TREE_ELEMENT *el= 0; // Only for safety
- if (tree_mode)
- el= tree_insert(tree, table->record[0], 0, tree->custom_arg);
+ if (tree)
+ el= tree_insert(tree, table->record[0] + table->s->null_bytes, 0,
+ tree->custom_arg);
/*
If the row is not a duplicate (el->count == 1)
we can dump the row here in case of GROUP_CONCAT(DISTINCT...)
instead of doing tree traverse later.
*/
- if (result.length() <= group_concat_max_len &&
+ if (result.length() <= max_length &&
!warning_for_row &&
- (!tree_mode || (el->count == 1 && distinct && !arg_count_order)))
- dump_leaf_key(table->record[0], 1, this);
+ (!tree || (el->count == 1 && distinct && !arg_count_order)))
+ dump_leaf_key(table->record[0] + table->s->null_bytes, 1, this);
return 0;
}
-void Item_func_group_concat::reset_field()
-{
- if (tree_mode)
- reset_tree(tree);
-}
-
-
bool
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
- uint i; /* for loop variable */
+ uint i; /* for loop variable */
DBUG_ASSERT(fixed == 0);
if (!thd->allow_sum_func)
{
- my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
- return 1;
+ my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
+ MYF(0));
+ return TRUE;
}
-
+
thd->allow_sum_func= 0;
maybe_null= 0;
- item_thd= thd;
/*
Fix fields for select list and ORDER clause
*/
- for (i=0 ; i < arg_count ; i++)
+ for (i=0 ; i < arg_count ; i++)
{
- if ((!args[i]->fixed &&
+ if ((!args[i]->fixed &&
args[i]->fix_fields(thd, tables, args + i)) ||
args[i]->check_cols(1))
- return 1;
+ return TRUE;
if (i < arg_count_field)
maybe_null|= args[i]->maybe_null;
}
result_field= 0;
null_value= 1;
- max_length= group_concat_max_len;
- thd->allow_sum_func= 1;
- if (!(tmp_table_param= new TMP_TABLE_PARAM))
- return 1;
- /* We'll convert all blobs to varchar fields in the temporary table */
- tmp_table_param->convert_blob_length= group_concat_max_len;
+ thd->allow_sum_func= 1;
+ max_length= thd->variables.group_concat_max_len;
tables_list= tables;
fixed= 1;
- return 0;
+ return FALSE;
}
@@ -1948,84 +2955,80 @@ bool Item_func_group_concat::setup(THD *thd)
{
List<Item> list;
SELECT_LEX *select_lex= thd->lex->current_select;
- uint const_fields;
- byte *record;
qsort_cmp2 compare_key;
DBUG_ENTER("Item_func_group_concat::setup");
- if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
- DBUG_RETURN(1);
-
/*
- push all not constant fields to list and create temp table
- */
- const_fields= 0;
+ Currently setup() can be called twice. Please add
+ assertion here when this is fixed.
+ */
+ if (table || tree)
+ DBUG_RETURN(FALSE);
+
+ if (!(tmp_table_param= new TMP_TABLE_PARAM))
+ DBUG_RETURN(TRUE);
+
+ /* We'll convert all blobs to varchar fields in the temporary table */
+ tmp_table_param->convert_blob_length= max_length;
+ /* Push all not constant fields to the list and create a temp table */
always_null= 0;
for (uint i= 0; i < arg_count_field; i++)
{
Item *item= args[i];
if (list.push_back(item))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
if (item->const_item())
{
- const_fields++;
- (void) item->val_int();
- if (item->null_value)
- always_null= 1;
+ if (item->is_null())
+ {
+ always_null= 1;
+ DBUG_RETURN(FALSE);
+ }
}
}
- if (always_null)
- DBUG_RETURN(0);
-
+
List<Item> all_fields(list);
- if (arg_count_order)
- {
- bool hidden_group_fields;
- setup_group(thd, args, tables_list, list, all_fields, *order,
- &hidden_group_fields);
- }
-
+ /*
+ Try to find every ORDER expression in the list of GROUP_CONCAT
+ arguments. If an expression is not found, prepend it to
+ "all_fields". The resulting field list is used as input to create
+ tmp table columns.
+ */
+ if (arg_count_order &&
+ setup_order(thd, args, tables_list, list, all_fields, *order))
+ DBUG_RETURN(TRUE);
+
count_field_types(tmp_table_param,all_fields,0);
- if (table)
- {
- /*
- We come here when we are getting the result from a temporary table,
- not the original tables used in the query
- */
- free_tmp_table(thd, table);
- tmp_table_param->cleanup();
- }
+ DBUG_ASSERT(table == 0);
/*
- We have to create a temporary table to get descriptions of fields
+ We have to create a temporary table to get descriptions of fields
(types, sizes and so on).
Note that in the table, we first have the ORDER BY fields, then the
field list.
- We need to set set_sum_field in true for storing value of blob in buffer
- of a record instead of a pointer of one.
+ We need to set set_sum_field in true for storing value of blob in buffer
+ of a record instead of a pointer of one.
*/
- if (!(table=create_tmp_table(thd, tmp_table_param, all_fields,
- (ORDER*) 0, 0, TRUE,
- select_lex->options | thd->options,
- HA_POS_ERROR,(char *) "")))
- DBUG_RETURN(1);
+ if (!(table= create_tmp_table(thd, tmp_table_param, all_fields,
+ (ORDER*) 0, 0, TRUE,
+ select_lex->options | thd->options,
+ HA_POS_ERROR, (char*) "")))
+ DBUG_RETURN(TRUE);
table->file->extra(HA_EXTRA_NO_ROWS);
table->no_rows= 1;
- key_length= table->reclength;
- record= table->record[0];
-
- /* Offset to first result field in table */
- field_list_offset= table->fields - (list.elements - const_fields);
- if (tree_mode)
- delete_tree(tree);
-
- /* choose function of sort */
- tree_mode= distinct || arg_count_order;
- if (tree_mode)
+ if (distinct || arg_count_order)
{
+ /*
+ Need sorting: init tree and choose a function to sort.
+ Don't reserve space for NULLs: if any of gconcat arguments is NULL,
+ the row is not added to the result.
+ */
+ uint tree_key_length= table->s->reclength - table->s->null_bytes;
+
+ tree= &tree_base;
if (arg_count_order)
{
if (distinct)
@@ -2038,27 +3041,16 @@ bool Item_func_group_concat::setup(THD *thd)
compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct;
}
/*
- Create a tree of sort. Tree is used for a sort and a remove double
- values (according with syntax of the function). If function doesn't
- contain DISTINCT and ORDER BY clauses, we don't create this tree.
+ Create a tree for sorting. The tree is used to sort and to remove
+ duplicate values (according to the syntax of this function). If there
+ is no DISTINCT or ORDER BY clauses, we don't create this tree.
*/
init_tree(tree, min(thd->variables.max_heap_table_size,
- thd->variables.sortbuff_size/16), 0,
- key_length, compare_key, 0, NULL, (void*) this);
- max_elements_in_tree= (key_length ?
- thd->variables.max_heap_table_size/key_length : 1);
- };
-
- /*
- Copy table and tree_mode if they belong to this item (if item have not
- pointer to original item from which was made copy => it own its objects)
- */
- if (original)
- {
- original->table= table;
- original->tree_mode= tree_mode;
+ thd->variables.sortbuff_size/16), 0,
+ tree_key_length, compare_key, 0, NULL, (void*) this);
}
- DBUG_RETURN(0);
+
+ DBUG_RETURN(FALSE);
}
@@ -2066,10 +3058,10 @@ bool Item_func_group_concat::setup(THD *thd)
void Item_func_group_concat::make_unique()
{
+ tmp_table_param= 0;
table=0;
original= 0;
- tree_mode= 0; // to prevent delete_tree call on uninitialized tree
- tree= &tree_base;
+ tree= 0;
}
@@ -2079,20 +3071,21 @@ String* Item_func_group_concat::val_str(String* str)
if (null_value)
return 0;
if (count_cut_values && !warning)
+ {
/*
ER_CUT_VALUE_GROUP_CONCAT needs an argument, but this gets set in
Item_func_group_concat::cleanup().
*/
- warning= push_warning(item_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ DBUG_ASSERT(table);
+ warning= push_warning(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_CUT_VALUE_GROUP_CONCAT,
ER(ER_CUT_VALUE_GROUP_CONCAT));
+ }
if (result.length())
return &result;
- if (tree_mode)
- {
+ if (tree)
tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
left_root_right);
- }
return &result;
}
@@ -2114,7 +3107,7 @@ void Item_func_group_concat::print(String *str)
for (uint i= 0 ; i < arg_count_order ; i++)
{
if (i)
- str->append(',');
+ str->append(',');
(*order[i]->item)->print(str);
}
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index dab136e4716..8c8360b0726 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -23,13 +23,15 @@
#include <my_tree.h>
+class Item_arena;
+
class Item_sum :public Item_result_field
{
public:
enum Sumfunctype
- { COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
- MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
- UDF_SUM_FUNC, GROUP_CONCAT_FUNC
+ { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
+ AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC,
+ VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC
};
Item **args, *tmp_args[2];
@@ -66,6 +68,9 @@ public:
a temporary table. Similar to reset(), but must also store value in
result_field. Like reset() it is supposed to reset start value to
default.
+ This set of methods (reult_field(), reset_field, update_field()) of
+ Item_sum is used only if quick_group is not null. Otherwise
+ copy_or_same() is used to obtain a copy of this item.
*/
virtual void reset_field()=0;
/*
@@ -90,7 +95,8 @@ public:
virtual bool setup(THD *thd) {return 0;}
virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd);
-
+ virtual Field *create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length);
bool walk (Item_processor processor, byte *argument);
};
@@ -105,8 +111,12 @@ public:
Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {}
bool fix_fields(THD *, TABLE_LIST *, Item **);
longlong val_int()
- { DBUG_ASSERT(fixed == 1); return (longlong) val(); } /* Real as default */
+ {
+ DBUG_ASSERT(fixed == 1);
+ return (longlong) val_real(); /* Real as default */
+ }
String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *);
void reset_field();
};
@@ -117,8 +127,9 @@ public:
Item_sum_int(Item *item_par) :Item_sum_num(item_par) {}
Item_sum_int(List<Item> &list) :Item_sum_num(list) {}
Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {}
- double val() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec()
{ decimals=0; max_length=21; maybe_null=null_value=0; }
@@ -127,17 +138,24 @@ public:
class Item_sum_sum :public Item_sum_num
{
+protected:
+ Item_result hybrid_type;
double sum;
- void fix_length_and_dec() { maybe_null=null_value=1; }
+ my_decimal dec_buffs[2];
+ uint curr_dec_buff;
+ void fix_length_and_dec();
- public:
- Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {}
- Item_sum_sum(THD *thd, Item_sum_sum *item)
- :Item_sum_num(thd, item), sum(item->sum) {}
+public:
+ Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {}
+ Item_sum_sum(THD *thd, Item_sum_sum *item);
enum Sumfunctype sum_func () const {return SUM_FUNC;}
void clear();
bool add();
- double val();
+ double val_real();
+ longlong val_int();
+ String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *);
+ enum Item_result result_type () const { return hybrid_type; }
void reset_field();
void update_field();
void no_rows_in_result() {}
@@ -146,6 +164,89 @@ class Item_sum_sum :public Item_sum_num
};
+
+/* Common class for SUM(DISTINCT), AVG(DISTINCT) */
+
+class Unique;
+
+class Item_sum_distinct :public Item_sum_num
+{
+protected:
+ /* storage for the summation result */
+ ulonglong count;
+ Hybrid_type val;
+ /* storage for unique elements */
+ Unique *tree;
+ TABLE *table;
+ enum enum_field_types table_field_type;
+ uint tree_key_length;
+protected:
+ Item_sum_distinct(THD *thd, Item_sum_distinct *item);
+public:
+ Item_sum_distinct(Item *item_par);
+ ~Item_sum_distinct();
+
+ bool setup(THD *thd);
+ void clear();
+ void cleanup();
+ bool add();
+ double val_real();
+ my_decimal *val_decimal(my_decimal *);
+ longlong val_int();
+ String *val_str(String *str);
+
+ /* XXX: does it need make_unique? */
+
+ 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(); }
+ virtual void calculate_val_and_count();
+ virtual bool unique_walk_function(void *elem);
+};
+
+
+/*
+ Item_sum_sum_distinct - implementation of SUM(DISTINCT expr).
+ See also: MySQL manual, chapter 'Adding New Functions To MySQL'
+ and comments in item_sum.cc.
+*/
+
+class Item_sum_sum_distinct :public Item_sum_distinct
+{
+private:
+ Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item)
+ :Item_sum_distinct(thd, item) {}
+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"; }
+ Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); }
+};
+
+
+/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */
+
+class Item_sum_avg_distinct: public Item_sum_distinct
+{
+private:
+ Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original)
+ :Item_sum_distinct(thd, original) {}
+public:
+ Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {}
+
+ 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"; }
+ Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); }
+};
+
+
class Item_sum_count :public Item_sum_int
{
longlong count;
@@ -180,68 +281,44 @@ class TMP_TABLE_PARAM;
class Item_sum_count_distinct :public Item_sum_int
{
TABLE *table;
- table_map used_table_cache;
uint32 *field_lengths;
TMP_TABLE_PARAM *tmp_table_param;
- TREE tree_base;
- TREE *tree;
+ /*
+ If there are no blobs, we can use a tree, which
+ is faster than heap table. In that case, we still use the table
+ to help get things set up, but we insert nothing in it
+ */
+ Unique *tree;
/*
Following is 0 normal object and pointer to original one for copy
(to correctly free resources)
*/
Item_sum_count_distinct *original;
+ uint tree_key_length;
- uint key_length;
- CHARSET_INFO *key_charset;
-
- /*
- Calculated based on max_heap_table_size. If reached,
- walk the tree and dump it into MyISAM table
- */
- uint max_elements_in_tree;
-
- /*
- The first few bytes of record ( at least one)
- are just markers for deleted and NULLs. We want to skip them since
- they will just bloat the tree without providing any valuable info
- */
- int rec_offset;
- /*
- If there are no blobs, we can use a tree, which
- is faster than heap table. In that case, we still use the table
- to help get things set up, but we insert nothing in it
- */
- bool use_tree;
bool always_null; // Set to 1 if the result is always NULL
- int tree_to_myisam();
friend int composite_key_cmp(void* arg, byte* key1, byte* key2);
friend int simple_str_key_cmp(void* arg, byte* key1, byte* key2);
- friend int simple_raw_key_cmp(void* arg, byte* key1, byte* key2);
- friend int dump_leaf(byte* key, uint32 count __attribute__((unused)),
- Item_sum_count_distinct* item);
- public:
+public:
Item_sum_count_distinct(List<Item> &list)
- :Item_sum_int(list), table(0), used_table_cache(~(table_map) 0),
- tmp_table_param(0), tree(&tree_base), original(0), use_tree(0),
- always_null(0)
+ :Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0),
+ tree(0), original(0), always_null(FALSE)
{ quick_group= 0; }
Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item)
:Item_sum_int(thd, item), table(item->table),
- used_table_cache(item->used_table_cache),
field_lengths(item->field_lengths),
tmp_table_param(item->tmp_table_param),
- tree(item->tree), original(item), key_length(item->key_length),
- max_elements_in_tree(item->max_elements_in_tree),
- rec_offset(item->rec_offset), use_tree(item->use_tree),
+ tree(item->tree), original(item), tree_key_length(item->tree_key_length),
always_null(item->always_null)
{}
+ ~Item_sum_count_distinct();
+
void cleanup();
- table_map used_tables() const { return used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; }
void clear();
bool add();
@@ -265,43 +342,53 @@ class Item_avg_field :public Item_result_field
{
public:
Field *field;
- Item_avg_field(Item_sum_avg *item);
+ Item_result hybrid_type;
+ uint f_precision, f_scale;
+ uint dec_bin_size;
+ Item_avg_field(Item_result res_type, Item_sum_avg *item);
enum Type type() const { return FIELD_AVG_ITEM; }
- double val();
- longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val(); }
+ double val_real();
+ longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
bool is_null() { (void) val_int(); return null_value; }
String *val_str(String*);
- enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
+ enum_field_types field_type() const
+ {
+ return hybrid_type == DECIMAL_RESULT ?
+ MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
+ }
void fix_length_and_dec() {}
+ enum Item_result result_type () const { return hybrid_type; }
};
-class Item_sum_avg :public Item_sum_num
+class Item_sum_avg :public Item_sum_sum
{
- void fix_length_and_dec()
- {
- decimals=min(decimals+4, NOT_FIXED_DEC);
- maybe_null=1;
- }
-
- double sum;
+public:
ulonglong count;
+ uint f_precision, f_scale;
+ uint dec_bin_size;
- public:
- Item_sum_avg(Item *item_par) :Item_sum_num(item_par), sum(0.0), count(0) {}
+ Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {}
Item_sum_avg(THD *thd, Item_sum_avg *item)
- :Item_sum_num(thd, item), sum(item->sum), count(item->count) {}
+ :Item_sum_sum(thd, item), count(item->count) {}
+ void fix_length_and_dec();
enum Sumfunctype sum_func () const {return AVG_FUNC;}
void clear();
bool add();
- double val();
+ double val_real();
+ // In SPs we might force the "wrong" type with select into a declare variable
+ longlong val_int() { return (longlong)val_real(); }
+ my_decimal *val_decimal(my_decimal *);
+ String *val_str(String *str);
void reset_field();
void update_field();
Item *result_item(Field *field)
- { return new Item_avg_field(this); }
+ { return new Item_avg_field(hybrid_type, this); }
void no_rows_in_result() {}
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);
};
class Item_sum_variance;
@@ -310,14 +397,26 @@ class Item_variance_field :public Item_result_field
{
public:
Field *field;
+ Item_result hybrid_type;
+ uint f_precision0, f_scale0;
+ uint f_precision1, f_scale1;
+ uint dec_bin_size0, dec_bin_size1;
+ uint sample;
Item_variance_field(Item_sum_variance *item);
enum Type type() const {return FIELD_VARIANCE_ITEM; }
- double val();
- longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val(); }
+ double val_real();
+ longlong val_int()
+ { /* can't be fix_fields()ed */ return (longlong) val_real(); }
String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
bool is_null() { (void) val_int(); return null_value; }
- enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
+ enum_field_types field_type() const
+ {
+ return hybrid_type == DECIMAL_RESULT ?
+ MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
+ }
void fix_length_and_dec() {}
+ enum Item_result result_type () const { return hybrid_type; }
};
@@ -335,23 +434,28 @@ public:
class Item_sum_variance : public Item_sum_num
{
+ void fix_length_and_dec();
+
+public:
+ Item_result hybrid_type;
double sum, sum_sqr;
+ my_decimal dec_sum[2], dec_sqr[2];
+ int cur_dec;
ulonglong count;
- void fix_length_and_dec()
- {
- decimals=min(decimals+4, NOT_FIXED_DEC);
- maybe_null=1;
- }
+ uint f_precision0, f_scale0;
+ uint f_precision1, f_scale1;
+ uint dec_bin_size0, dec_bin_size1;
+ uint sample;
- public:
- Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {}
- Item_sum_variance(THD *thd, Item_sum_variance *item):
- Item_sum_num(thd, item), sum(item->sum), sum_sqr(item->sum_sqr),
- count(item->count) {}
+ Item_sum_variance(Item *item_par, uint sample_arg) :Item_sum_num(item_par),
+ hybrid_type(REAL_RESULT), cur_dec(0), count(0), sample(sample_arg)
+ {}
+ Item_sum_variance(THD *thd, Item_sum_variance *item);
enum Sumfunctype sum_func () const { return VARIANCE_FUNC; }
void clear();
bool add();
- double val();
+ double val_real();
+ my_decimal *val_decimal(my_decimal *);
void reset_field();
void update_field();
Item *result_item(Field *field)
@@ -359,6 +463,8 @@ class Item_sum_variance : public Item_sum_num
void no_rows_in_result() {}
const char *func_name() const { return "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; }
};
class Item_sum_std;
@@ -368,7 +474,10 @@ class Item_std_field :public Item_variance_field
public:
Item_std_field(Item_sum_std *item);
enum Type type() const { return FIELD_STD_ITEM; }
- double val();
+ double val_real();
+ my_decimal *val_decimal(my_decimal *);
+ enum Item_result result_type () const { return REAL_RESULT; }
+ enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;}
};
/*
@@ -378,26 +487,30 @@ public:
class Item_sum_std :public Item_sum_variance
{
public:
- Item_sum_std(Item *item_par) :Item_sum_variance(item_par) {}
+ Item_sum_std(Item *item_par, uint sample_arg)
+ :Item_sum_variance(item_par, sample_arg) {}
Item_sum_std(THD *thd, Item_sum_std *item)
:Item_sum_variance(thd, item)
{}
enum Sumfunctype sum_func () const { return STD_FUNC; }
- double val();
+ double val_real();
Item *result_item(Field *field)
{ return new Item_std_field(this); }
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;}
};
// This class is a string or number function depending on num_func
class Item_sum_hybrid :public Item_sum
{
- protected:
+protected:
String value,tmp_value;
double sum;
longlong sum_int;
+ my_decimal sum_dec;
Item_result hybrid_type;
enum_field_types hybrid_field_type;
int cmp_sign;
@@ -408,22 +521,18 @@ class Item_sum_hybrid :public Item_sum
Item_sum_hybrid(Item *item_par,int sign)
:Item_sum(item_par), sum(0.0), sum_int(0),
hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG),
- cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE)
- { collation.set(&my_charset_bin); }
- Item_sum_hybrid(THD *thd, Item_sum_hybrid *item):
- Item_sum(thd, item), value(item->value),
- sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type),
- hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign),
- used_table_cache(item->used_table_cache),
+ cmp_sign(sign), used_table_cache(~(table_map) 0),
was_values(TRUE)
- { collation.set(item->collation); }
+ { collation.set(&my_charset_bin); }
+ Item_sum_hybrid(THD *thd, Item_sum_hybrid *item);
bool fix_fields(THD *, TABLE_LIST *, Item **);
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
void clear();
- double val();
+ double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
void reset_field();
String *val_str(String *);
void make_const() { used_table_cache=0; }
@@ -434,9 +543,12 @@ class Item_sum_hybrid :public Item_sum
void min_max_update_str_field();
void min_max_update_real_field();
void min_max_update_int_field();
+ void min_max_update_decimal_field();
void cleanup();
bool any_value() { return was_values; }
void no_rows_in_result();
+ Field *create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length);
};
@@ -482,7 +594,7 @@ public:
void reset_field();
void update_field();
void fix_length_and_dec()
- { decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; }
+ { decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; }
};
@@ -562,9 +674,13 @@ class Item_sum_udf_float :public Item_udf_sum
Item_sum_udf_float(THD *thd, Item_sum_udf_float *item)
:Item_udf_sum(thd, item) {}
longlong val_int()
- { DBUG_ASSERT(fixed == 1); return (longlong) Item_sum_udf_float::val(); }
- double val();
+ {
+ DBUG_ASSERT(fixed == 1);
+ return (longlong) Item_sum_udf_float::val_real();
+ }
+ double val_real();
String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec() { fix_num_length_and_dec(); }
Item *copy_or_same(THD* thd);
};
@@ -579,9 +695,10 @@ public:
Item_sum_udf_int(THD *thd, Item_sum_udf_int *item)
:Item_udf_sum(thd, item) {}
longlong val_int();
- double val()
+ double val_real()
{ DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); }
String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() { decimals=0; max_length=21; }
Item *copy_or_same(THD* thd);
@@ -597,26 +714,52 @@ public:
Item_sum_udf_str(THD *thd, Item_sum_udf_str *item)
:Item_udf_sum(thd, item) {}
String *val_str(String *);
- double val()
+ double val_real()
{
- int err;
+ int err_not_used;
char *end_not_used;
String *res;
res=val_str(&str_value);
return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(),
- &end_not_used, &err) : 0.0;
+ &end_not_used, &err_not_used) : 0.0;
}
longlong val_int()
{
- int err;
- String *res; res=val_str(&str_value);
- return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err) : (longlong) 0;
+ int err_not_used;
+ char *end;
+ String *res;
+ CHARSET_INFO *cs;
+
+ if (!(res= val_str(&str_value)))
+ return 0; /* Null value */
+ cs= res->charset();
+ end= (char*) res->ptr()+res->length();
+ return cs->cset->strtoll10(cs, res->ptr(), &end, &err_not_used);
}
+ my_decimal *val_decimal(my_decimal *dec);
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
Item *copy_or_same(THD* thd);
};
+
+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, List<Item> &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 *);
+ double val_real();
+ longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
+ enum Item_result result_type () const { return DECIMAL_RESULT; }
+ void fix_length_and_dec() { fix_num_length_and_dec(); }
+ Item *copy_or_same(THD* thd);
+};
+
#else /* Dummy functions to get sql_yacc.cc compiled */
class Item_sum_udf_float :public Item_sum_num
@@ -627,7 +770,7 @@ class Item_sum_udf_float :public Item_sum_num
Item_sum_udf_float(THD *thd, Item_sum_udf_float *item)
:Item_sum_num(thd, item) {}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
- double val() { DBUG_ASSERT(fixed == 1); return 0.0; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
void clear() {}
bool add() { return 0; }
void update_field() {}
@@ -643,7 +786,23 @@ public:
:Item_sum_num(thd, item) {}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; }
- double val() { DBUG_ASSERT(fixed == 1); return 0; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return 0; }
+ void clear() {}
+ bool add() { return 0; }
+ void update_field() {}
+};
+
+
+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(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; }
void update_field() {}
@@ -659,7 +818,7 @@ public:
:Item_sum_num(thd, item) {}
String *val_str(String *)
{ DBUG_ASSERT(fixed == 1); null_value=1; return 0; }
- double val() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; }
+ double val_real() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; }
longlong val_int() { DBUG_ASSERT(fixed == 1); null_value=1; return 0; }
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec() { maybe_null=1; max_length=0; }
@@ -675,15 +834,26 @@ class MYSQL_ERROR;
class Item_func_group_concat : public Item_sum
{
- THD *item_thd;
TMP_TABLE_PARAM *tmp_table_param;
- uint max_elements_in_tree;
MYSQL_ERROR *warning;
- uint key_length;
- bool tree_mode;
+ String result;
+ String *separator;
+ TREE tree_base;
+ TREE *tree;
+ TABLE *table;
+ ORDER **order;
+ TABLE_LIST *tables_list;
+ uint arg_count_order; // total count of ORDER BY items
+ uint arg_count_field; // count of arguments
+ uint count_cut_values;
bool distinct;
bool warning_for_row;
bool always_null;
+ /*
+ Following is 0 normal object and pointer to original one for copy
+ (to correctly free resources)
+ */
+ Item_func_group_concat *original;
friend int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
byte* key2);
@@ -692,33 +862,16 @@ class Item_func_group_concat : public Item_sum
friend int group_concat_key_cmp_with_distinct_and_order(void* arg,
byte* key1,
byte* key2);
- friend int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
+ friend int dump_leaf_key(byte* key,
+ element_count count __attribute__((unused)),
Item_func_group_concat *group_concat_item);
- public:
- String result;
- String *separator;
- TREE tree_base;
- TREE *tree;
- TABLE *table;
- ORDER **order;
- TABLE_LIST *tables_list;
- ulong group_concat_max_len;
- uint arg_count_order;
- uint arg_count_field;
- uint field_list_offset;
- uint count_cut_values;
- /*
- Following is 0 normal object and pointer to original one for copy
- (to correctly free resources)
- */
- Item_func_group_concat *original;
-
+public:
Item_func_group_concat(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();
+ ~Item_func_group_concat() {}
void cleanup();
enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;}
@@ -726,12 +879,12 @@ class Item_func_group_concat : public Item_sum
virtual Item_result result_type () const { return STRING_RESULT; }
void clear();
bool add();
- void reset_field();
+ void reset_field() {} // not used
+ void update_field() {} // not used
bool fix_fields(THD *, TABLE_LIST *, Item **);
bool setup(THD *thd);
void make_unique();
- virtual void update_field() {}
- double val()
+ double val_real()
{
String *res; res=val_str(&str_value);
return res ? my_atof(res->c_ptr()) : 0.0;
@@ -746,6 +899,10 @@ class Item_func_group_concat : public Item_sum
end_ptr= (char*) res->ptr()+ res->length();
return my_strtoll10(res->ptr(), &end_ptr, &error);
}
+ my_decimal *val_decimal(my_decimal *decimal_value)
+ {
+ return val_decimal_from_string(decimal_value);
+ }
String* val_str(String* str);
Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 23cd9c7ced2..7a9c7898856 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -160,7 +160,8 @@ static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
static bool extract_date_time(DATE_TIME_FORMAT *format,
const char *val, uint length, TIME *l_time,
timestamp_type cached_timestamp_type,
- const char **sub_pattern_end)
+ const char **sub_pattern_end,
+ const char *date_time_type)
{
int weekday= 0, yearday= 0, daypart= 0;
int week_number= -1;
@@ -188,12 +189,12 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
for (; ptr != end && val != val_end; ptr++)
{
-
if (*ptr == '%' && ptr+1 != end)
{
int val_len;
char *tmp;
+ error= 0;
/* Skip pre-space between each argument */
while (val != val_end && my_isspace(cs, *val))
val++;
@@ -343,16 +344,22 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
/* Time in AM/PM notation */
case 'r':
- error= extract_date_time(&time_ampm_format, val,
- (uint)(val_end - val), l_time,
- cached_timestamp_type, &val);
+ /*
+ We can't just set error here, as we don't want to generate two
+ warnings in case of errors
+ */
+ if (extract_date_time(&time_ampm_format, val,
+ (uint)(val_end - val), l_time,
+ cached_timestamp_type, &val, "time"))
+ DBUG_RETURN(1);
break;
/* Time in 24-hour notation */
case 'T':
- error= extract_date_time(&time_24hrs_format, val,
- (uint)(val_end - val), l_time,
- cached_timestamp_type, &val);
+ if (extract_date_time(&time_24hrs_format, val,
+ (uint)(val_end - val), l_time,
+ cached_timestamp_type, &val, "time"))
+ DBUG_RETURN(1);
break;
/* Conversion specifiers that match classes of characters */
@@ -463,7 +470,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
if (!my_isspace(&my_charset_latin1,*val))
{
make_truncated_value_warning(current_thd, val_begin, length,
- cached_timestamp_type);
+ cached_timestamp_type, NullS);
break;
}
} while (++val != val_end);
@@ -471,6 +478,13 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
DBUG_RETURN(0);
err:
+ {
+ char buff[128];
+ strmake(buff, val_begin, min(length, sizeof(buff)-1));
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
+ date_time_type, buff, "str_to_time");
+ }
DBUG_RETURN(1);
}
@@ -869,7 +883,7 @@ longlong Item_func_to_days::val_int()
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
- if (get_arg0_date(&ltime,0))
+ if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
return 0;
return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
}
@@ -878,7 +892,7 @@ longlong Item_func_dayofyear::val_int()
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
- if (get_arg0_date(&ltime,0))
+ if (get_arg0_date(&ltime,TIME_NO_ZERO_DATE))
return 0;
return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) -
calc_daynr(ltime.year,1,1) + 1;
@@ -888,7 +902,7 @@ longlong Item_func_dayofmonth::val_int()
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
- (void) get_arg0_date(&ltime,1);
+ (void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
return (longlong) ltime.day;
}
@@ -896,7 +910,7 @@ longlong Item_func_month::val_int()
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
- (void) get_arg0_date(&ltime,1);
+ (void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
return (longlong) ltime.month;
}
@@ -925,7 +939,7 @@ longlong Item_func_quarter::val_int()
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
- (void) get_arg0_date(&ltime,1);
+ (void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
return (longlong) ((ltime.month+2)/3);
}
@@ -997,7 +1011,7 @@ longlong Item_func_week::val_int()
DBUG_ASSERT(fixed == 1);
uint year;
TIME ltime;
- if (get_arg0_date(&ltime,0))
+ if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
return 0;
return (longlong) calc_week(&ltime,
week_mode((uint) args[1]->val_int()),
@@ -1010,7 +1024,7 @@ longlong Item_func_yearweek::val_int()
DBUG_ASSERT(fixed == 1);
uint year,week;
TIME ltime;
- if (get_arg0_date(&ltime,0))
+ if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
return 0;
week= calc_week(&ltime,
(week_mode((uint) args[1]->val_int()) | WEEK_YEAR),
@@ -1051,7 +1065,7 @@ longlong Item_func_year::val_int()
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
- (void) get_arg0_date(&ltime,1);
+ (void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
return (longlong) ltime.year;
}
@@ -1150,9 +1164,15 @@ static bool get_interval_value(Item *args,interval_type int_type,
case INTERVAL_YEAR:
interval->year= (ulong) value;
break;
+ case INTERVAL_QUARTER:
+ interval->month= (ulong)(value*3);
+ break;
case INTERVAL_MONTH:
interval->month= (ulong) value;
break;
+ case INTERVAL_WEEK:
+ interval->day= (ulong)(value*7);
+ break;
case INTERVAL_DAY:
interval->day= (ulong) value;
break;
@@ -1623,7 +1643,7 @@ String *Item_func_date_format::val_str(String *str)
if (!is_time_format)
{
- if (get_arg0_date(&l_time,1))
+ if (get_arg0_date(&l_time, TIME_FUZZY_DATE))
return 0;
}
else
@@ -1740,11 +1760,11 @@ Item_func_convert_tz::fix_fields(THD *thd_arg, TABLE_LIST *tables_arg, Item **re
{
String str;
if (Item_date_func::fix_fields(thd_arg, tables_arg, ref))
- return 1;
+ return TRUE;
tz_tables= thd_arg->lex->time_zone_tables_used;
- return 0;
+ return FALSE;
}
@@ -1778,7 +1798,7 @@ longlong Item_func_convert_tz::val_int()
bool Item_func_convert_tz::get_date(TIME *ltime,
- uint fuzzy_date __attribute__((unused)))
+ uint fuzzy_date __attribute__((unused)))
{
my_time_t my_time_tmp;
bool not_used;
@@ -1796,7 +1816,7 @@ bool Item_func_convert_tz::get_date(TIME *ltime,
to_tz_cached= args[2]->const_item();
}
- if (from_tz==0 || to_tz==0 || get_arg0_date(ltime, 0))
+ if (from_tz==0 || to_tz==0 || get_arg0_date(ltime, TIME_NO_ZERO_DATE))
{
null_value= 1;
return 1;
@@ -1867,7 +1887,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
INTERVAL interval;
ltime->neg= 0;
- if (args[0]->get_date(ltime,0) ||
+ if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) ||
get_interval_value(args[1],int_type,&value,&interval))
goto null_date;
sign= (interval.neg ? -1 : 1);
@@ -1927,6 +1947,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
break;
}
case INTERVAL_DAY:
+ case INTERVAL_WEEK:
period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
sign * (long) interval.day);
/* Daynumber from year 0 to 9999-12-31 */
@@ -1943,6 +1964,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
ltime->day=28; // Was leap-year
break;
case INTERVAL_YEAR_MONTH:
+ case INTERVAL_QUARTER:
case INTERVAL_MONTH:
period= (ltime->year*12 + sign * (long) interval.year*12 +
ltime->month-1 + sign * (long) interval.month);
@@ -1974,7 +1996,7 @@ String *Item_date_add_interval::val_str(String *str)
TIME ltime;
enum date_time_format_types format;
- if (Item_date_add_interval::get_date(&ltime,0))
+ if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
return 0;
if (ltime.time_type == MYSQL_TIMESTAMP_DATE)
@@ -1997,7 +2019,7 @@ longlong Item_date_add_interval::val_int()
DBUG_ASSERT(fixed == 1);
TIME ltime;
longlong date;
- if (Item_date_add_interval::get_date(&ltime,0))
+ if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
return (longlong) 0;
date = (ltime.year*100L + ltime.month)*100L + ltime.day;
return ltime.time_type == MYSQL_TIMESTAMP_DATE ? date :
@@ -2006,12 +2028,13 @@ longlong Item_date_add_interval::val_int()
static const char *interval_names[]=
{
- "year", "month", "day", "hour", "minute",
- "second", "microsecond", "year_month",
- "day_hour", "day_minute", "day_second",
- "hour_minute", "hour_second", "minute_second",
- "day_microsecond", "hour_microsecond",
- "minute_microsecond", "second_microsecond"
+ "year", "quarter", "month", "day", "hour",
+ "minute", "week", "second", "microsecond",
+ "year_month", "day_hour", "day_minute",
+ "day_second", "hour_minute", "hour_second",
+ "minute_second", "day_microsecond",
+ "hour_microsecond", "minute_microsecond",
+ "second_microsecond"
};
void Item_date_add_interval::print(String *str)
@@ -2042,7 +2065,9 @@ void Item_extract::fix_length_and_dec()
switch (int_type) {
case INTERVAL_YEAR: max_length=4; date_value=1; break;
case INTERVAL_YEAR_MONTH: max_length=6; date_value=1; break;
+ case INTERVAL_QUARTER: max_length=2; date_value=1; break;
case INTERVAL_MONTH: max_length=2; date_value=1; break;
+ case INTERVAL_WEEK: max_length=2; date_value=1; break;
case INTERVAL_DAY: max_length=2; date_value=1; break;
case INTERVAL_DAY_HOUR: max_length=9; date_value=0; break;
case INTERVAL_DAY_MINUTE: max_length=11; date_value=0; break;
@@ -2066,10 +2091,12 @@ longlong Item_extract::val_int()
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
+ uint year;
+ ulong week_format;
long neg;
if (date_value)
{
- if (get_arg0_date(&ltime,1))
+ if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
return 0;
neg=1;
}
@@ -2087,7 +2114,13 @@ longlong Item_extract::val_int()
switch (int_type) {
case INTERVAL_YEAR: return ltime.year;
case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
+ case INTERVAL_QUARTER: return ltime.month/3 + 1;
case INTERVAL_MONTH: return ltime.month;
+ case INTERVAL_WEEK:
+ {
+ week_format= current_thd->variables.default_week_format;
+ return calc_week(&ltime, week_mode(week_format), &year);
+ }
case INTERVAL_DAY: return ltime.day;
case INTERVAL_DAY_HOUR: return (long) (ltime.day*100L+ltime.hour)*neg;
case INTERVAL_DAY_MINUTE: return (long) (ltime.day*10000L+
@@ -2187,7 +2220,7 @@ void Item_char_typecast::print(String *str)
if (cast_cs)
{
str->append(" charset ", 9);
- str->append(cast_cs->name);
+ str->append(cast_cs->csname);
}
str->append(')');
}
@@ -2223,39 +2256,47 @@ String *Item_char_typecast::val_str(String *str)
res->set_charset(cast_cs);
/*
- Cut the tail if cast with length
- and the result is longer than cast length, e.g.
- CAST('string' AS CHAR(1))
+ Cut the tail if cast with length
+ and the result is longer than cast length, e.g.
+ CAST('string' AS CHAR(1))
*/
if (cast_length >= 0 &&
(res->length() > (length= (uint32) res->charpos(cast_length))))
{ // Safe even if const arg
+ char char_type[40];
+ my_snprintf(char_type, sizeof(char_type), "CHAR(%lu)", length);
+
if (!res->alloced_length())
{ // Don't change const str
str_value= *res; // Not malloced string
res= &str_value;
}
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), char_type,
+ res->c_ptr_safe());
res->length((uint) length);
}
null_value= 0;
return res;
}
+
void Item_char_typecast::fix_length_and_dec()
{
uint32 char_length;
- /*
- We always force character set conversion if cast_cs
- is a multi-byte character set. It garantees that the
- result of CAST is a well-formed string.
- For single-byte character sets we allow just to copy
- from the argument. A single-byte character sets string
- is always well-formed.
+ /*
+ We always force character set conversion if cast_cs is a
+ multi-byte character set. It garantees that the result of CAST is
+ a well-formed string. For single-byte character sets we allow
+ just to copy from the argument. A single-byte character sets
+ string is always well-formed.
*/
- charset_conversion= (cast_cs->mbmaxlen > 1) ||
- !my_charset_same(args[0]->collation.collation, cast_cs) &&
- args[0]->collation.collation != &my_charset_bin &&
- cast_cs != &my_charset_bin;
+ charset_conversion= ((cast_cs->mbmaxlen > 1) ||
+ !my_charset_same(args[0]->collation.collation,
+ cast_cs) &&
+ args[0]->collation.collation != &my_charset_bin &&
+ cast_cs != &my_charset_bin);
collation.set(cast_cs, DERIVATION_IMPLICIT);
char_length= (cast_length >= 0) ? cast_length :
args[0]->max_length/args[0]->collation.collation->mbmaxlen;
@@ -2267,7 +2308,7 @@ String *Item_datetime_typecast::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
- if (!get_arg0_date(&ltime,1) &&
+ if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
!make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
&ltime, str))
return str;
@@ -2308,7 +2349,7 @@ String *Item_time_typecast::val_str(String *str)
bool Item_date_typecast::get_date(TIME *ltime, uint fuzzy_date)
{
- bool res= get_arg0_date(ltime,1);
+ bool res= get_arg0_date(ltime, TIME_FUZZY_DATE);
ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
ltime->time_type= MYSQL_TIMESTAMP_DATE;
return res;
@@ -2320,7 +2361,7 @@ String *Item_date_typecast::val_str(String *str)
DBUG_ASSERT(fixed == 1);
TIME ltime;
- if (!get_arg0_date(&ltime,1) && !str->alloc(11))
+ if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) && !str->alloc(11))
{
make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
return str;
@@ -2414,7 +2455,7 @@ String *Item_func_add_time::val_str(String *str)
null_value=0;
if (is_date) // TIMESTAMP function
{
- if (get_arg0_date(&l_time1,1) ||
+ if (get_arg0_date(&l_time1, TIME_FUZZY_DATE) ||
args[1]->get_time(&l_time2) ||
l_time1.time_type == MYSQL_TIMESTAMP_TIME ||
l_time2.time_type != MYSQL_TIMESTAMP_TIME)
@@ -2594,6 +2635,163 @@ longlong Item_func_microsecond::val_int()
}
+longlong Item_func_timestamp_diff::val_int()
+{
+ TIME ltime1, ltime2;
+ longlong seconds;
+ long microseconds;
+ long months= 0;
+ int neg= 1;
+
+ null_value= 0;
+ if (args[0]->get_date(&ltime1, TIME_NO_ZERO_DATE) ||
+ args[1]->get_date(&ltime2, TIME_NO_ZERO_DATE))
+ goto null_date;
+
+ if (calc_time_diff(&ltime2,&ltime1, 1,
+ &seconds, &microseconds))
+ neg= -1;
+
+ if (int_type == INTERVAL_YEAR ||
+ int_type == INTERVAL_QUARTER ||
+ int_type == INTERVAL_MONTH)
+ {
+ uint year;
+ uint year_beg, year_end, month_beg, month_end;
+ uint diff_days= (uint) (seconds/86400L);
+ uint diff_years= 0;
+ if (neg == -1)
+ {
+ year_beg= ltime2.year;
+ year_end= ltime1.year;
+ month_beg= ltime2.month;
+ month_end= ltime1.month;
+ }
+ else
+ {
+ year_beg= ltime1.year;
+ year_end= ltime2.year;
+ month_beg= ltime1.month;
+ month_end= ltime2.month;
+ }
+ /* calc years*/
+ for (year= year_beg;year < year_end; year++)
+ {
+ uint days=calc_days_in_year(year);
+ if (days > diff_days)
+ break;
+ diff_days-= days;
+ diff_years++;
+ }
+
+ /* calc months; Current year is in the 'year' variable */
+ month_beg--; /* Change months to be 0-11 for easier calculation */
+ month_end--;
+
+ months= 12*diff_years;
+ while (month_beg != month_end)
+ {
+ uint m_days= (uint) days_in_month[month_beg];
+ if (month_beg == 1)
+ {
+ /* This is only calculated once so there is no reason to cache it*/
+ uint leap= (uint) ((year & 3) == 0 && (year%100 ||
+ (year%400 == 0 && year)));
+ m_days+= leap;
+ }
+ if (m_days > diff_days)
+ break;
+ diff_days-= m_days;
+ months++;
+ if (month_beg++ == 11) /* if we wrap to next year */
+ {
+ month_beg= 0;
+ year++;
+ }
+ }
+ if (neg == -1)
+ months= -months;
+ }
+
+ switch (int_type) {
+ case INTERVAL_YEAR:
+ return months/12;
+ case INTERVAL_QUARTER:
+ return months/3;
+ case INTERVAL_MONTH:
+ return months;
+ case INTERVAL_WEEK:
+ return seconds/86400L/7L*neg;
+ case INTERVAL_DAY:
+ return seconds/86400L*neg;
+ case INTERVAL_HOUR:
+ return seconds/3600L*neg;
+ case INTERVAL_MINUTE:
+ return seconds/60L*neg;
+ case INTERVAL_SECOND:
+ return seconds*neg;
+ case INTERVAL_MICROSECOND:
+ /*
+ In MySQL difference between any two valid datetime values
+ in microseconds fits into longlong.
+ */
+ return (seconds*1000000L+microseconds)*neg;
+ default:
+ break;
+ }
+
+null_date:
+ null_value=1;
+ return 0;
+}
+
+
+void Item_func_timestamp_diff::print(String *str)
+{
+ str->append(func_name());
+ str->append('(');
+
+ switch (int_type) {
+ case INTERVAL_YEAR:
+ str->append("YEAR");
+ break;
+ case INTERVAL_QUARTER:
+ str->append("QUARTER");
+ break;
+ case INTERVAL_MONTH:
+ str->append("MONTH");
+ break;
+ case INTERVAL_WEEK:
+ str->append("WEEK");
+ break;
+ case INTERVAL_DAY:
+ str->append("DAY");
+ break;
+ case INTERVAL_HOUR:
+ str->append("HOUR");
+ break;
+ case INTERVAL_MINUTE:
+ str->append("MINUTE");
+ break;
+ case INTERVAL_SECOND:
+ str->append("SECOND");
+ break;
+ case INTERVAL_MICROSECOND:
+ str->append("SECOND_FRAC");
+ break;
+ default:
+ break;
+ }
+
+ for (uint i=0 ; i < 2 ; i++)
+ {
+ str->append(',');
+ args[i]->print(str);
+ }
+ str->append(')');
+}
+
+
String *Item_func_get_format::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -2700,9 +2898,9 @@ get_date_time_result_type(const char *format, uint length)
have all types of date-time components and can end our search.
*/
return DATE_TIME_MICROSECOND;
- }
}
}
+ }
/* We don't have all three types of date-time components */
if (frac_second_used)
@@ -2780,7 +2978,7 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date)
date_time_format.format.str= (char*) format->ptr();
date_time_format.format.length= format->length();
if (extract_date_time(&date_time_format, val->ptr(), val->length(),
- ltime, cached_timestamp_type, 0))
+ ltime, cached_timestamp_type, 0, "datetime"))
goto null_date;
if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day)
{
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index cc2709bf555..ab511ae2883 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -88,7 +88,7 @@ class Item_func_month :public Item_func
public:
Item_func_month(Item *a) :Item_func(a) {}
longlong val_int();
- double val()
+ double val_real()
{ DBUG_ASSERT(fixed == 1); return (double) Item_func_month::val_int(); }
String *val_str(String *str)
{
@@ -250,7 +250,7 @@ public:
Item_func_weekday(Item *a,bool type_arg)
:Item_func(a), odbc_type(type_arg) {}
longlong val_int();
- double val() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
String *val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -315,7 +315,9 @@ public:
};
-/* This can't be a Item_str_func, because the val() functions are special */
+/*
+ This can't be a Item_str_func, because the val_real() functions are special
+*/
class Item_date :public Item_func
{
@@ -326,7 +328,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
String *val_str(String *str);
longlong val_int();
- double val() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
const char *func_name() const { return "date"; }
void fix_length_and_dec()
{
@@ -369,7 +371,7 @@ public:
Item_func_curtime(Item *a) :Item_func(a) {}
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
- double val() { DBUG_ASSERT(fixed == 1); return (double) value; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
String *val_str(String *str);
void fix_length_and_dec();
@@ -452,7 +454,7 @@ public:
Item_func_now() :Item_date_func() {}
Item_func_now(Item *a) :Item_date_func(a) {}
enum Item_result result_type () const { return STRING_RESULT; }
- double val() { DBUG_ASSERT(fixed == 1); return (double) value; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
int save_in_field(Field *to, bool no_conversions);
String *val_str(String *str);
@@ -512,7 +514,7 @@ class Item_func_from_unixtime :public Item_date_func
THD *thd;
public:
Item_func_from_unixtime(Item *a) :Item_date_func(a) {}
- double val()
+ double val_real()
{
DBUG_ASSERT(fixed == 1);
return (double) Item_func_from_unixtime::val_int();
@@ -555,7 +557,7 @@ class Item_func_convert_tz :public Item_date_func
Item_func_convert_tz(Item *a, Item *b, Item *c):
Item_date_func(a, b, c), from_tz_cached(0), to_tz_cached(0) {}
longlong val_int();
- double val() { return (double) val_int(); }
+ 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 **);
@@ -569,7 +571,7 @@ class Item_func_sec_to_time :public Item_str_func
{
public:
Item_func_sec_to_time(Item *item) :Item_str_func(item) {}
- double val()
+ double val_real()
{
DBUG_ASSERT(fixed == 1);
return (double) Item_func_sec_to_time::val_int();
@@ -597,11 +599,11 @@ public:
enum interval_type
{
- INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR, INTERVAL_MINUTE,
- INTERVAL_SECOND, INTERVAL_MICROSECOND ,INTERVAL_YEAR_MONTH,
- INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND,
- INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, INTERVAL_MINUTE_SECOND,
- INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND,
+ INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR,
+ INTERVAL_MINUTE, INTERVAL_WEEK, INTERVAL_SECOND, INTERVAL_MICROSECOND ,
+ INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
+ INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
+ INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND,
INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND
};
@@ -619,7 +621,7 @@ public:
const char *func_name() const { return "date_add_interval"; }
void fix_length_and_dec();
enum_field_types field_type() const { return cached_field_type; }
- double val() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
longlong val_int();
bool get_date(TIME *res, uint fuzzy_date);
void print(String *str);
@@ -842,6 +844,23 @@ public:
};
+class Item_func_timestamp_diff :public Item_int_func
+{
+ const interval_type int_type;
+public:
+ Item_func_timestamp_diff(Item *a,Item *b,interval_type type_arg)
+ :Item_int_func(a,b), int_type(type_arg) {}
+ const char *func_name() const { return "timestamp_diff"; }
+ longlong val_int();
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ maybe_null=1;
+ }
+ void print(String *str);
+};
+
+
enum date_time_format
{
USA_FORMAT, JIS_FORMAT, ISO_FORMAT, EUR_FORMAT, INTERNAL_FORMAT
diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc
index 88e0cbbc0e6..c1a19d71d04 100644
--- a/sql/item_uniq.cc
+++ b/sql/item_uniq.cc
@@ -20,3 +20,9 @@
#endif
#include "mysql_priv.h"
+
+Field *Item_sum_unique_users::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length)
+{
+ return new Field_long(9,maybe_null,name,table,1);
+}
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index 5582537bdbb..602474f7581 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -27,7 +27,7 @@ class Item_func_unique_users :public Item_real_func
public:
Item_func_unique_users(Item *name_arg,int start,int end,List<Item> &list)
:Item_real_func(list) {}
- double val() { DBUG_ASSERT(fixed == 1); return 0.0; }
+ 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); }
};
@@ -40,7 +40,7 @@ public:
:Item_sum_num(item_arg) {}
Item_sum_unique_users(THD *thd, Item_sum_unique_users *item)
:Item_sum_num(thd, item) {}
- double val() { DBUG_ASSERT(fixed == 1); return 0.0; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;}
void clear() {}
bool add() { return 0; }
@@ -50,11 +50,12 @@ public:
{
DBUG_ASSERT(fixed == 0);
fixed= 1;
- return 0;
+ return FALSE;
}
Item *copy_or_same(THD* thd)
{
return new Item_sum_unique_users(thd, this);
}
void print(String *str) { str->append("0.0", 3); }
+ Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
};
diff --git a/sql/key.cc b/sql/key.cc
index 7ddd40de2c9..3299c3db8f8 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -38,7 +38,9 @@ int find_ref_key(TABLE *table,Field *field, uint *key_length)
/* Test if some key starts as fieldpos */
- for (i=0, key_info=table->key_info ; i < (int) table->keys ; i++, key_info++)
+ for (i= 0, key_info= table->key_info ;
+ i < (int) table->s->keys ;
+ i++, key_info++)
{
if (key_info->key_part[0].offset == fieldpos)
{ /* Found key. Calc keylength */
@@ -48,7 +50,9 @@ int find_ref_key(TABLE *table,Field *field, uint *key_length)
}
/* Test if some key contains fieldpos */
- for (i=0, key_info=table->key_info ; i < (int) table->keys ; i++, key_info++)
+ for (i= 0, key_info= table->key_info ;
+ i < (int) table->s->keys ;
+ i++, key_info++)
{
uint j;
KEY_PART_INFO *key_part;
@@ -66,94 +70,165 @@ int find_ref_key(TABLE *table,Field *field, uint *key_length)
}
- /* Copy a key from record to some buffer */
- /* if length == 0 then copy whole key */
+/*
+ Copy part of a record that forms a key or key prefix to a buffer.
+
+ SYNOPSIS
+ key_copy()
+ to_key buffer that will be used as a key
+ from_record full record to be copied from
+ key_info descriptor of the index
+ key_length specifies length of all keyparts that will be copied
+
+ DESCRIPTION
+ The function takes a complete table record (as e.g. retrieved by
+ handler::index_read()), and a description of an index on the same table,
+ and extracts the first key_length bytes of the record which are part of a
+ key into to_key. If length == 0 then copy all bytes from the record that
+ form a key.
+
+ RETURN
+ None
+*/
-void key_copy(byte *key,TABLE *table,uint idx,uint key_length)
+void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length)
{
uint length;
- KEY *key_info=table->key_info+idx;
KEY_PART_INFO *key_part;
if (key_length == 0)
- key_length=key_info->key_length;
- for (key_part=key_info->key_part;
- (int) key_length > 0 ;
- key_part++)
+ key_length= key_info->key_length;
+ for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
{
if (key_part->null_bit)
{
- *key++= test(table->record[0][key_part->null_offset] &
+ *to_key++= test(from_record[key_part->null_offset] &
key_part->null_bit);
key_length--;
}
+ if (key_part->type == HA_KEYTYPE_BIT)
+ {
+ Field_bit *field= (Field_bit *) (key_part->field);
+ if (field->bit_len)
+ {
+ uchar bits= get_rec_bits((uchar*) from_record +
+ key_part->null_offset +
+ (key_part->null_bit == 128),
+ field->bit_ofs, field->bit_len);
+ *to_key++= bits;
+ key_length--;
+ }
+ }
if (key_part->key_part_flag & HA_BLOB_PART)
{
char *pos;
- ulong blob_length=((Field_blob*) key_part->field)->get_length();
- key_length-=2;
+ ulong blob_length= ((Field_blob*) key_part->field)->get_length();
+ key_length-= HA_KEY_BLOB_LENGTH;
((Field_blob*) key_part->field)->get_ptr(&pos);
- length=min(key_length,key_part->length);
- set_if_smaller(blob_length,length);
- int2store(key,(uint) blob_length);
- key+=2; // Skip length info
- memcpy(key,pos,blob_length);
+ length=min(key_length, key_part->length);
+ set_if_smaller(blob_length, length);
+ int2store(to_key, (uint) blob_length);
+ to_key+= HA_KEY_BLOB_LENGTH; // Skip length info
+ memcpy(to_key, pos, blob_length);
+ }
+ else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
+ {
+ key_length-= HA_KEY_BLOB_LENGTH;
+ length= min(key_length, key_part->length);
+ key_part->field->get_key_image((char *) to_key, length, Field::itRAW);
+ to_key+= HA_KEY_BLOB_LENGTH;
}
else
{
- length=min(key_length,key_part->length);
- memcpy(key,table->record[0]+key_part->offset,(size_t) length);
+ length= min(key_length, key_part->length);
+ memcpy(to_key, from_record + key_part->offset, (size_t) length);
}
- key+=length;
- key_length-=length;
+ to_key+= length;
+ key_length-= length;
}
-} /* key_copy */
+}
- /* restore a key from some buffer to record */
+/*
+ Restore a key from some buffer to record.
+
+ SYNOPSIS
+ key_restore()
+ to_record record buffer where the key will be restored to
+ from_key buffer that contains a key
+ key_info descriptor of the index
+ key_length specifies length of all keyparts that will be restored
-void key_restore(TABLE *table,byte *key,uint idx,uint key_length)
+ DESCRIPTION
+ This function converts a key into record format. It can be used in cases
+ when we want to return a key as a result row.
+
+ RETURN
+ None
+*/
+
+void key_restore(byte *to_record, byte *from_key, KEY *key_info,
+ uint key_length)
{
uint length;
- KEY *key_info=table->key_info+idx;
KEY_PART_INFO *key_part;
if (key_length == 0)
{
- if (idx == (uint) -1)
- return;
- key_length=key_info->key_length;
+ key_length= key_info->key_length;
}
- for (key_part=key_info->key_part;
- (int) key_length > 0 ;
- key_part++)
+ for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
{
if (key_part->null_bit)
{
- if (*key++)
- table->record[0][key_part->null_offset]|= key_part->null_bit;
+ if (*from_key++)
+ to_record[key_part->null_offset]|= key_part->null_bit;
else
- table->record[0][key_part->null_offset]&= ~key_part->null_bit;
+ to_record[key_part->null_offset]&= ~key_part->null_bit;
key_length--;
}
+ if (key_part->type == HA_KEYTYPE_BIT)
+ {
+ Field_bit *field= (Field_bit *) (key_part->field);
+ if (field->bit_len)
+ {
+ uchar bits= *(from_key + key_part->length - field->field_length -1);
+ set_rec_bits(bits, to_record + key_part->null_offset +
+ (key_part->null_bit == 128),
+ field->bit_ofs, field->bit_len);
+ }
+ else
+ {
+ clr_rec_bits(to_record + key_part->null_offset +
+ (key_part->null_bit == 128),
+ field->bit_ofs, field->bit_len);
+ }
+ }
if (key_part->key_part_flag & HA_BLOB_PART)
{
- uint blob_length=uint2korr(key);
- key+=2;
- key_length-=2;
+ uint blob_length= uint2korr(from_key);
+ from_key+= HA_KEY_BLOB_LENGTH;
+ key_length-= HA_KEY_BLOB_LENGTH;
((Field_blob*) key_part->field)->set_ptr((ulong) blob_length,
- (char*) key);
- length=key_part->length;
+ (char*) from_key);
+ length= key_part->length;
+ }
+ else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
+ {
+ key_length-= HA_KEY_BLOB_LENGTH;
+ length= min(key_length, key_part->length);
+ key_part->field->set_key_image((char *) from_key, length);
+ from_key+= HA_KEY_BLOB_LENGTH;
}
else
{
- length=min(key_length,key_part->length);
- memcpy(table->record[0]+key_part->offset,key,(size_t) length);
+ length= min(key_length, key_part->length);
+ memcpy(to_record + key_part->offset, from_key, (size_t) length);
}
- key+=length;
- key_length-=length;
+ from_key+= length;
+ key_length-= length;
}
-} /* key_restore */
+}
/*
@@ -179,54 +254,54 @@ void key_restore(TABLE *table,byte *key,uint idx,uint key_length)
bool key_cmp_if_same(TABLE *table,const byte *key,uint idx,uint key_length)
{
- uint length;
+ uint store_length;
KEY_PART_INFO *key_part;
+ const byte *key_end= key + key_length;;
for (key_part=table->key_info[idx].key_part;
- (int) key_length > 0;
- key_part++, key+=length, key_length-=length)
+ key < key_end ;
+ key_part++, key+= store_length)
{
+ uint length;
+ store_length= key_part->store_length;
+
if (key_part->null_bit)
{
- key_length--;
if (*key != test(table->record[0][key_part->null_offset] &
key_part->null_bit))
return 1;
if (*key)
- {
- length=key_part->store_length;
continue;
- }
key++;
+ store_length--;
}
- if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH))
+ if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
+ HA_BIT_PART))
{
- if (key_part->field->key_cmp(key, key_part->length+ HA_KEY_BLOB_LENGTH))
+ if (key_part->field->key_cmp(key, key_part->length))
return 1;
- length=key_part->length+HA_KEY_BLOB_LENGTH;
+ continue;
}
- else
+ length= min((uint) (key_end-key), store_length);
+ if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
+ FIELDFLAG_PACK)))
{
- length=min(key_length,key_part->length);
- if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
- FIELDFLAG_PACK)))
+ CHARSET_INFO *cs= key_part->field->charset();
+ uint char_length= key_part->length / cs->mbmaxlen;
+ const byte *pos= table->record[0] + key_part->offset;
+ if (length > char_length)
{
- CHARSET_INFO *cs= key_part->field->charset();
- uint char_length= key_part->length / cs->mbmaxlen;
- const byte *pos= table->record[0] + key_part->offset;
- if (length > char_length)
- {
- char_length= my_charpos(cs, pos, pos + length, char_length);
- set_if_smaller(char_length, length);
- }
- if (cs->coll->strnncollsp(cs,
- (const uchar*) key, length,
- (const uchar*) pos, char_length))
- return 1;
+ char_length= my_charpos(cs, pos, pos + length, char_length);
+ set_if_smaller(char_length, length);
}
- else if (memcmp(key,table->record[0]+key_part->offset,length))
- return 1;
+ if (cs->coll->strnncollsp(cs,
+ (const uchar*) key, length,
+ (const uchar*) pos, char_length, 0))
+ return 1;
+ continue;
}
+ if (memcmp(key,table->record[0]+key_part->offset,length))
+ return 1;
}
return 0;
}
@@ -302,9 +377,9 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
If table handler has primary key as part of the index, check that primary
key is not updated
*/
- if (idx != table->primary_key && table->primary_key < MAX_KEY &&
+ if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
(table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
- return check_if_key_used(table, table->primary_key, fields);
+ return check_if_key_used(table, table->s->primary_key, fields);
return 0;
}
diff --git a/sql/lex.h b/sql/lex.h
index 325d052de90..d0dc287775e 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -19,11 +19,11 @@
#include "lex_symbol.h"
-/* We don't want to include sql_yacc.h into gen_lex_hash */
SYM_GROUP sym_group_common= {"", ""};
SYM_GROUP sym_group_geom= {"Spatial extentions", "HAVE_SPATIAL"};
SYM_GROUP sym_group_rtree= {"RTree keys", "HAVE_RTREE_KEYS"};
+/* We don't want to include sql_yacc.h into gen_lex_hash */
#ifdef NO_YACC_SYMBOLS
#define SYM_OR_NULL(A) 0
#else
@@ -48,7 +48,7 @@ SYM_GROUP sym_group_rtree= {"RTree keys", "HAVE_RTREE_KEYS"};
*/
static SYMBOL symbols[] = {
- { "&&", SYM(AND_SYM)},
+ { "&&", SYM(AND_AND_SYM)},
{ "<", SYM(LT)},
{ "<=", SYM(LE)},
{ "<>", SYM(NE)},
@@ -65,6 +65,7 @@ static SYMBOL symbols[] = {
{ "AGAINST", SYM(AGAINST)},
{ "AGGREGATE", SYM(AGGREGATE_SYM)},
{ "ALL", SYM(ALL)},
+ { "ALGORITHM", SYM(ALGORITHM_SYM)},
{ "ALTER", SYM(ALTER)},
{ "ANALYZE", SYM(ANALYZE_SYM)},
{ "AND", SYM(AND_SYM)},
@@ -72,6 +73,7 @@ static SYMBOL symbols[] = {
{ "AS", SYM(AS)},
{ "ASC", SYM(ASC)},
{ "ASCII", SYM(ASCII_SYM)},
+ { "ASENSITIVE", SYM(ASENSITIVE_SYM)},
{ "AUTO_INCREMENT", SYM(AUTO_INC)},
{ "AVG", SYM(AVG_SYM)},
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH)},
@@ -93,8 +95,11 @@ static SYMBOL symbols[] = {
{ "BY", SYM(BY)},
{ "BYTE", SYM(BYTE_SYM)},
{ "CACHE", SYM(CACHE_SYM)},
+ { "CALL", SYM(CALL_SYM)},
{ "CASCADE", SYM(CASCADE)},
+ { "CASCADED", SYM(CASCADED)},
{ "CASE", SYM(CASE_SYM)},
+ { "CHAIN", SYM(CHAIN_SYM)},
{ "CHANGE", SYM(CHANGE)},
{ "CHANGED", SYM(CHANGED)},
{ "CHAR", SYM(CHAR_SYM)},
@@ -112,10 +117,15 @@ static SYMBOL symbols[] = {
{ "COMMENT", SYM(COMMENT_SYM)},
{ "COMMIT", SYM(COMMIT_SYM)},
{ "COMMITTED", SYM(COMMITTED_SYM)},
+ { "COMPACT", SYM(COMPACT_SYM)},
{ "COMPRESSED", SYM(COMPRESSED_SYM)},
{ "CONCURRENT", SYM(CONCURRENT)},
+ { "CONDITION", SYM(CONDITION_SYM)},
+ { "CONNECTION", SYM(CONNECTION_SYM)},
{ "CONSISTENT", SYM(CONSISTENT_SYM)},
{ "CONSTRAINT", SYM(CONSTRAINT)},
+ { "CONTAINS", SYM(CONTAINS_SYM)},
+ { "CONTINUE", SYM(CONTINUE_SYM)},
{ "CONVERT", SYM(CONVERT_SYM)},
{ "CREATE", SYM(CREATE)},
{ "CROSS", SYM(CROSS)},
@@ -124,6 +134,7 @@ static SYMBOL symbols[] = {
{ "CURRENT_TIME", SYM(CURTIME)},
{ "CURRENT_TIMESTAMP", SYM(NOW_SYM)},
{ "CURRENT_USER", SYM(CURRENT_USER)},
+ { "CURSOR", SYM(CURSOR_SYM)},
{ "DATA", SYM(DATA_SYM)},
{ "DATABASE", SYM(DATABASE)},
{ "DATABASES", SYM(DATABASES)},
@@ -137,13 +148,16 @@ static SYMBOL symbols[] = {
{ "DEALLOCATE", SYM(DEALLOCATE_SYM)},
{ "DEC", SYM(DECIMAL_SYM)},
{ "DECIMAL", SYM(DECIMAL_SYM)},
+ { "DECLARE", SYM(DECLARE_SYM)},
{ "DEFAULT", SYM(DEFAULT)},
+ { "DEFINER", SYM(DEFINER_SYM)},
{ "DELAYED", SYM(DELAYED_SYM)},
{ "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM)},
{ "DELETE", SYM(DELETE_SYM)},
{ "DESC", SYM(DESC)},
{ "DESCRIBE", SYM(DESCRIBE)},
{ "DES_KEY_FILE", SYM(DES_KEY_FILE)},
+ { "DETERMINISTIC", SYM(DETERMINISTIC_SYM)},
{ "DIRECTORY", SYM(DIRECTORY_SYM)},
{ "DISABLE", SYM(DISABLE_SYM)},
{ "DISCARD", SYM(DISCARD)},
@@ -157,7 +171,9 @@ static SYMBOL symbols[] = {
{ "DUMPFILE", SYM(DUMPFILE)},
{ "DUPLICATE", SYM(DUPLICATE_SYM)},
{ "DYNAMIC", SYM(DYNAMIC_SYM)},
+ { "EACH", SYM(EACH_SYM)},
{ "ELSE", SYM(ELSE)},
+ { "ELSEIF", SYM(ELSEIF_SYM)},
{ "ENABLE", SYM(ENABLE_SYM)},
{ "ENCLOSED", SYM(ENCLOSED)},
{ "END", SYM(END)},
@@ -170,11 +186,13 @@ static SYMBOL symbols[] = {
{ "EVENTS", SYM(EVENTS_SYM)},
{ "EXECUTE", SYM(EXECUTE_SYM)},
{ "EXISTS", SYM(EXISTS)},
+ { "EXIT", SYM(EXIT_SYM)},
{ "EXPANSION", SYM(EXPANSION_SYM)},
{ "EXPLAIN", SYM(DESCRIBE)},
{ "EXTENDED", SYM(EXTENDED_SYM)},
{ "FALSE", SYM(FALSE_SYM)},
{ "FAST", SYM(FAST_SYM)},
+ { "FETCH", SYM(FETCH_SYM)},
{ "FIELDS", SYM(COLUMNS)},
{ "FILE", SYM(FILE_SYM)},
{ "FIRST", SYM(FIRST_SYM)},
@@ -186,14 +204,17 @@ static SYMBOL symbols[] = {
{ "FOR", SYM(FOR_SYM)},
{ "FORCE", SYM(FORCE_SYM)},
{ "FOREIGN", SYM(FOREIGN)},
+ { "FOUND", SYM(FOUND_SYM)},
+ { "FRAC_SECOND", SYM(FRAC_SECOND_SYM)},
{ "FROM", SYM(FROM)},
{ "FULL", SYM(FULL)},
{ "FULLTEXT", SYM(FULLTEXT_SYM)},
- { "FUNCTION", SYM(UDF_SYM)},
+ { "FUNCTION", SYM(FUNCTION_SYM)},
{ "GEOMETRY", SYM(GEOMETRY_SYM)},
{ "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)},
{ "GET_FORMAT", SYM(GET_FORMAT)},
{ "GLOBAL", SYM(GLOBAL_SYM)},
+ { "GOTO", SYM(GOTO_SYM)},
{ "GRANT", SYM(GRANT)},
{ "GRANTS", SYM(GRANTS)},
{ "GROUP", SYM(GROUP)},
@@ -218,6 +239,8 @@ static SYMBOL symbols[] = {
{ "INNER", SYM(INNER_SYM)},
{ "INNOBASE", SYM(INNOBASE_SYM)},
{ "INNODB", SYM(INNOBASE_SYM)},
+ { "INOUT", SYM(INOUT_SYM)},
+ { "INSENSITIVE", SYM(INSENSITIVE_SYM)},
{ "INSERT", SYM(INSERT)},
{ "INSERT_METHOD", SYM(INSERT_METHOD)},
{ "INT", SYM(INT_SYM)},
@@ -233,12 +256,17 @@ static SYMBOL symbols[] = {
{ "IS", SYM(IS)},
{ "ISOLATION", SYM(ISOLATION)},
{ "ISSUER", SYM(ISSUER_SYM)},
+ { "ITERATE", SYM(ITERATE_SYM)},
+ { "INVOKER", SYM(INVOKER_SYM)},
{ "JOIN", SYM(JOIN_SYM)},
{ "KEY", SYM(KEY_SYM)},
{ "KEYS", SYM(KEYS)},
{ "KILL", SYM(KILL_SYM)},
+ { "LABEL", SYM(LABEL_SYM)},
+ { "LANGUAGE", SYM(LANGUAGE_SYM)},
{ "LAST", SYM(LAST_SYM)},
{ "LEADING", SYM(LEADING)},
+ { "LEAVE", SYM(LEAVE_SYM)},
{ "LEAVES", SYM(LEAVES)},
{ "LEFT", SYM(LEFT)},
{ "LEVEL", SYM(LEVEL_SYM)},
@@ -256,6 +284,7 @@ static SYMBOL symbols[] = {
{ "LONG", SYM(LONG_SYM)},
{ "LONGBLOB", SYM(LONGBLOB)},
{ "LONGTEXT", SYM(LONGTEXT)},
+ { "LOOP", SYM(LOOP_SYM)},
{ "LOW_PRIORITY", SYM(LOW_PRIORITY)},
{ "MASTER", SYM(MASTER_SYM)},
{ "MASTER_CONNECT_RETRY", SYM(MASTER_CONNECT_RETRY_SYM)},
@@ -277,23 +306,29 @@ static SYMBOL symbols[] = {
{ "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR)},
{ "MAX_ROWS", SYM(MAX_ROWS)},
{ "MAX_UPDATES_PER_HOUR", SYM(MAX_UPDATES_PER_HOUR)},
+ { "MAX_USER_CONNECTIONS", SYM(MAX_USER_CONNECTIONS_SYM)},
{ "MEDIUM", SYM(MEDIUM_SYM)},
{ "MEDIUMBLOB", SYM(MEDIUMBLOB)},
{ "MEDIUMINT", SYM(MEDIUMINT)},
{ "MEDIUMTEXT", SYM(MEDIUMTEXT)},
+ { "MERGE", SYM(MERGE_SYM)},
{ "MICROSECOND", SYM(MICROSECOND_SYM)},
{ "MIDDLEINT", SYM(MEDIUMINT)}, /* For powerbuilder */
+ { "MIGRATE", SYM(MIGRATE_SYM)},
{ "MINUTE", SYM(MINUTE_SYM)},
{ "MINUTE_MICROSECOND", SYM(MINUTE_MICROSECOND_SYM)},
{ "MINUTE_SECOND", SYM(MINUTE_SECOND_SYM)},
{ "MIN_ROWS", SYM(MIN_ROWS)},
{ "MOD", SYM(MOD_SYM)},
{ "MODE", SYM(MODE_SYM)},
+ { "MODIFIES", SYM(MODIFIES_SYM)},
{ "MODIFY", SYM(MODIFY_SYM)},
{ "MONTH", SYM(MONTH_SYM)},
{ "MULTILINESTRING", SYM(MULTILINESTRING)},
{ "MULTIPOINT", SYM(MULTIPOINT)},
{ "MULTIPOLYGON", SYM(MULTIPOLYGON)},
+ { "MUTEX", SYM(MUTEX_SYM)},
+ { "NAME", SYM(NAME_SYM)},
{ "NAMES", SYM(NAMES_SYM)},
{ "NATIONAL", SYM(NATIONAL_SYM)},
{ "NATURAL", SYM(NATURAL)},
@@ -304,7 +339,7 @@ static SYMBOL symbols[] = {
{ "NEXT", SYM(NEXT_SYM)},
{ "NO", SYM(NO_SYM)},
{ "NONE", SYM(NONE_SYM)},
- { "NOT", SYM(NOT)},
+ { "NOT", SYM(NOT_SYM)},
{ "NO_WRITE_TO_BINLOG", SYM(NO_WRITE_TO_BINLOG)},
{ "NULL", SYM(NULL_SYM)},
{ "NUMERIC", SYM(NUMERIC_SYM)},
@@ -312,6 +347,7 @@ static SYMBOL symbols[] = {
{ "OFFSET", SYM(OFFSET_SYM)},
{ "OLD_PASSWORD", SYM(OLD_PASSWORD)},
{ "ON", SYM(ON)},
+ { "ONE", SYM(ONE_SYM)},
{ "ONE_SHOT", SYM(ONE_SHOT_SYM)},
{ "OPEN", SYM(OPEN_SYM)},
{ "OPTIMIZE", SYM(OPTIMIZE)},
@@ -319,11 +355,13 @@ static SYMBOL symbols[] = {
{ "OPTIONALLY", SYM(OPTIONALLY)},
{ "OR", SYM(OR_SYM)},
{ "ORDER", SYM(ORDER_SYM)},
+ { "OUT", SYM(OUT_SYM)},
{ "OUTER", SYM(OUTER)},
{ "OUTFILE", SYM(OUTFILE)},
{ "PACK_KEYS", SYM(PACK_KEYS_SYM)},
{ "PARTIAL", SYM(PARTIAL)},
{ "PASSWORD", SYM(PASSWORD)},
+ { "PHASE", SYM(PHASE_SYM)},
{ "POINT", SYM(POINT_SYM)},
{ "POLYGON", SYM(POLYGON)},
{ "PRECISION", SYM(PRECISION)},
@@ -335,6 +373,7 @@ static SYMBOL symbols[] = {
{ "PROCESS" , SYM(PROCESS)},
{ "PROCESSLIST", SYM(PROCESSLIST_SYM)},
{ "PURGE", SYM(PURGE)},
+ { "QUARTER", SYM(QUARTER_SYM)},
{ "QUERY", SYM(QUERY_SYM)},
{ "QUICK", SYM(QUICK)},
{ "RAID0", SYM(RAID_0_SYM)},
@@ -342,36 +381,48 @@ static SYMBOL symbols[] = {
{ "RAID_CHUNKSIZE", SYM(RAID_CHUNKSIZE)},
{ "RAID_TYPE", SYM(RAID_TYPE)},
{ "READ", SYM(READ_SYM)},
+ { "READS", SYM(READS_SYM)},
{ "REAL", SYM(REAL)},
+ { "RECOVER", SYM(RECOVER_SYM)},
+ { "REDUNDANT", SYM(REDUNDANT_SYM)},
{ "REFERENCES", SYM(REFERENCES)},
{ "REGEXP", SYM(REGEXP)},
{ "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM)},
{ "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM)},
{ "RELAY_THREAD", SYM(RELAY_THREAD)},
+ { "RELEASE", SYM(RELEASE_SYM)},
{ "RELOAD", SYM(RELOAD)},
{ "RENAME", SYM(RENAME)},
{ "REPAIR", SYM(REPAIR)},
{ "REPEATABLE", SYM(REPEATABLE_SYM)},
{ "REPLACE", SYM(REPLACE)},
{ "REPLICATION", SYM(REPLICATION)},
+ { "REPEAT", SYM(REPEAT_SYM)},
{ "REQUIRE", SYM(REQUIRE_SYM)},
{ "RESET", SYM(RESET_SYM)},
{ "RESTORE", SYM(RESTORE_SYM)},
{ "RESTRICT", SYM(RESTRICT)},
- { "RETURNS", SYM(UDF_RETURNS_SYM)},
+ { "RESUME", SYM(RESUME_SYM)},
+ { "RETURN", SYM(RETURN_SYM)},
+ { "RETURNS", SYM(RETURNS_SYM)},
{ "REVOKE", SYM(REVOKE)},
{ "RIGHT", SYM(RIGHT)},
{ "RLIKE", SYM(REGEXP)}, /* Like in mSQL2 */
{ "ROLLBACK", SYM(ROLLBACK_SYM)},
{ "ROLLUP", SYM(ROLLUP_SYM)},
+ { "ROUTINE", SYM(ROUTINE_SYM)},
{ "ROW", SYM(ROW_SYM)},
{ "ROWS", SYM(ROWS_SYM)},
{ "ROW_FORMAT", SYM(ROW_FORMAT_SYM)},
{ "RTREE", SYM(RTREE_SYM)},
{ "SAVEPOINT", SYM(SAVEPOINT_SYM)},
+ { "SCHEMA", SYM(DATABASE)},
+ { "SCHEMAS", SYM(DATABASES)},
{ "SECOND", SYM(SECOND_SYM)},
{ "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM)},
+ { "SECURITY", SYM(SECURITY_SYM)},
{ "SELECT", SYM(SELECT_SYM)},
+ { "SENSITIVE", SYM(SENSITIVE_SYM)},
{ "SEPARATOR", SYM(SEPARATOR_SYM)},
{ "SERIAL", SYM(SERIAL_SYM)},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM)},
@@ -389,6 +440,11 @@ static SYMBOL symbols[] = {
{ "SONAME", SYM(UDF_SONAME_SYM)},
{ "SOUNDS", SYM(SOUNDS_SYM)},
{ "SPATIAL", SYM(SPATIAL_SYM)},
+ { "SPECIFIC", SYM(SPECIFIC_SYM)},
+ { "SQL", SYM(SQL_SYM)},
+ { "SQLEXCEPTION", SYM(SQLEXCEPTION_SYM)},
+ { "SQLSTATE", SYM(SQLSTATE_SYM)},
+ { "SQLWARNING", SYM(SQLWARNING_SYM)},
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT)},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT)},
{ "SQL_CACHE", SYM(SQL_CACHE_SYM)},
@@ -396,6 +452,15 @@ static SYMBOL symbols[] = {
{ "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM)},
{ "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT)},
{ "SQL_THREAD", SYM(SQL_THREAD)},
+ { "SQL_TSI_FRAC_SECOND", SYM(FRAC_SECOND_SYM)},
+ { "SQL_TSI_SECOND", SYM(SECOND_SYM)},
+ { "SQL_TSI_MINUTE", SYM(MINUTE_SYM)},
+ { "SQL_TSI_HOUR", SYM(HOUR_SYM)},
+ { "SQL_TSI_DAY", SYM(DAY_SYM)},
+ { "SQL_TSI_WEEK", SYM(WEEK_SYM)},
+ { "SQL_TSI_MONTH", SYM(MONTH_SYM)},
+ { "SQL_TSI_QUARTER", SYM(QUARTER_SYM)},
+ { "SQL_TSI_YEAR", SYM(YEAR_SYM)},
{ "SSL", SYM(SSL_SYM)},
{ "START", SYM(START_SYM)},
{ "STARTING", SYM(STARTING)},
@@ -407,29 +472,37 @@ static SYMBOL symbols[] = {
{ "STRIPED", SYM(RAID_STRIPED_SYM)},
{ "SUBJECT", SYM(SUBJECT_SYM)},
{ "SUPER", SYM(SUPER_SYM)},
+ { "SUSPEND", SYM(SUSPEND_SYM)},
{ "TABLE", SYM(TABLE_SYM)},
{ "TABLES", SYM(TABLES)},
{ "TABLESPACE", SYM(TABLESPACE)},
{ "TEMPORARY", SYM(TEMPORARY)},
+ { "TEMPTABLE", SYM(TEMPTABLE_SYM)},
{ "TERMINATED", SYM(TERMINATED)},
{ "TEXT", SYM(TEXT_SYM)},
{ "THEN", SYM(THEN_SYM)},
{ "TIME", SYM(TIME_SYM)},
{ "TIMESTAMP", SYM(TIMESTAMP)},
+ { "TIMESTAMPADD", SYM(TIMESTAMP_ADD)},
+ { "TIMESTAMPDIFF", SYM(TIMESTAMP_DIFF)},
{ "TINYBLOB", SYM(TINYBLOB)},
{ "TINYINT", SYM(TINYINT)},
{ "TINYTEXT", SYM(TINYTEXT)},
{ "TO", SYM(TO_SYM)},
{ "TRAILING", SYM(TRAILING)},
{ "TRANSACTION", SYM(TRANSACTION_SYM)},
+ { "TRIGGER", SYM(TRIGGER_SYM)},
{ "TRUE", SYM(TRUE_SYM)},
{ "TRUNCATE", SYM(TRUNCATE_SYM)},
{ "TYPE", SYM(TYPE_SYM)},
{ "TYPES", SYM(TYPES_SYM)},
{ "UNCOMMITTED", SYM(UNCOMMITTED_SYM)},
+ { "UNDEFINED", SYM(UNDEFINED_SYM)},
+ { "UNDO", SYM(UNDO_SYM)},
{ "UNICODE", SYM(UNICODE_SYM)},
{ "UNION", SYM(UNION_SYM)},
{ "UNIQUE", SYM(UNIQUE_SYM)},
+ { "UNKNOWN", SYM(UNKNOWN_SYM)},
{ "UNLOCK", SYM(UNLOCK_SYM)},
{ "UNSIGNED", SYM(UNSIGNED)},
{ "UNTIL", SYM(UNTIL_SYM)},
@@ -451,17 +524,21 @@ static SYMBOL symbols[] = {
{ "VARIABLES", SYM(VARIABLES)},
{ "VARYING", SYM(VARYING)},
{ "WARNINGS", SYM(WARNINGS)},
+ { "WEEK", SYM(WEEK_SYM)},
{ "WHEN", SYM(WHEN_SYM)},
{ "WHERE", SYM(WHERE)},
+ { "WHILE", SYM(WHILE_SYM)},
+ { "VIEW", SYM(VIEW_SYM)},
{ "WITH", SYM(WITH)},
{ "WORK", SYM(WORK_SYM)},
{ "WRITE", SYM(WRITE_SYM)},
{ "X509", SYM(X509_SYM)},
{ "XOR", SYM(XOR)},
+ { "XA", SYM(XA_SYM)},
{ "YEAR", SYM(YEAR_SYM)},
{ "YEAR_MONTH", SYM(YEAR_MONTH_SYM)},
{ "ZEROFILL", SYM(ZEROFILL)},
- { "||", SYM(OR_OR_CONCAT)}
+ { "||", SYM(OR_OR_SYM)}
};
@@ -499,7 +576,6 @@ static SYMBOL sql_functions[] = {
{ "CONCAT", SYM(CONCAT)},
{ "CONCAT_WS", SYM(CONCAT_WS)},
{ "CONNECTION_ID", F_SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
- { "CONTAINS", F_SYM(FUNC_ARG2),0,CREATE_FUNC_GEOM(create_func_contains)},
{ "CONV", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
{ "CONVERT_TZ", SYM(CONVERT_TZ_SYM)},
{ "COUNT", SYM(COUNT_SYM)},
@@ -636,14 +712,13 @@ static SYMBOL sql_functions[] = {
{ "POSITION", SYM(POSITION_SYM)},
{ "POW", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
{ "POWER", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
- { "QUARTER", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_quarter)},
{ "QUOTE", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_quote)},
{ "RADIANS", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_radians)},
{ "RAND", SYM(RAND)},
{ "RELEASE_LOCK", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_release_lock)},
- { "REPEAT", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_repeat)},
{ "REVERSE", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_reverse)},
{ "ROUND", SYM(ROUND)},
+ { "ROW_COUNT", SYM(ROW_COUNT_SYM)},
{ "RPAD", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_rpad)},
{ "RTRIM", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_rtrim)},
{ "SEC_TO_TIME", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sec_to_time)},
@@ -660,6 +735,8 @@ static SYMBOL sql_functions[] = {
{ "STARTPOINT", F_SYM(FUNC_ARG1),0,CREATE_FUNC_GEOM(create_func_startpoint)},
{ "STD", SYM(STD_SYM)},
{ "STDDEV", SYM(STD_SYM)},
+ { "STDDEV_POP", SYM(STD_SYM)},
+ { "STDDEV_SAMP", SYM(STDDEV_SAMP_SYM)},
{ "STR_TO_DATE", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_str_to_date)},
{ "STRCMP", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_strcmp)},
{ "SUBSTR", SYM(SUBSTRING)},
@@ -685,8 +762,9 @@ static SYMBOL sql_functions[] = {
{ "UPPER", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
{ "UUID", F_SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_uuid)},
{ "VARIANCE", SYM(VARIANCE_SYM)},
+ { "VAR_POP", SYM(VARIANCE_SYM)},
+ { "VAR_SAMP", SYM(VAR_SAMP_SYM)},
{ "VERSION", F_SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)},
- { "WEEK", SYM(WEEK_SYM)},
{ "WEEKDAY", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekday)},
{ "WEEKOFYEAR", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekofyear)},
{ "WITHIN", F_SYM(FUNC_ARG2),0,CREATE_FUNC_GEOM(create_func_within)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 03541bb0810..83a39005cd8 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -79,7 +79,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
bool unlock, TABLE **write_locked);
static int lock_external(THD *thd, TABLE **table,uint count);
static int unlock_external(THD *thd, TABLE **table,uint count);
-static void print_lock_error(int error);
+static void print_lock_error(int error, const char *);
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
@@ -153,7 +153,7 @@ retry:
thd->proc_info=0;
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
if (sql_lock)
{
mysql_unlock_tables(thd,sql_lock);
@@ -183,12 +183,12 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
if ((error=(*tables)->file->external_lock(thd,lock_type)))
{
+ print_lock_error(error, (*tables)->file->table_type());
for (; i-- ; tables--)
{
(*tables)->file->external_lock(thd, F_UNLCK);
(*tables)->current_lock=F_UNLCK;
}
- print_lock_error(error);
DBUG_RETURN(error);
}
else
@@ -376,12 +376,13 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
{
(*table)->current_lock = F_UNLCK;
if ((error=(*table)->file->external_lock(thd, F_UNLCK)))
+ {
error_code=error;
+ print_lock_error(error_code, (*table)->file->table_type());
+ }
}
table++;
} while (--count);
- if (error_code)
- print_lock_error(error_code);
DBUG_RETURN(error_code);
}
@@ -402,7 +403,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
*write_lock_used=0;
for (i=tables=lock_count=0 ; i < count ; i++)
{
- if (table_ptr[i]->tmp_table != TMP_TABLE)
+ if (table_ptr[i]->s->tmp_table != TMP_TABLE)
{
tables+=table_ptr[i]->file->lock_count();
lock_count++;
@@ -422,7 +423,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
for (i=0 ; i < count ; i++)
{
TABLE *table;
- if ((table=table_ptr[i])->tmp_table == TMP_TABLE)
+ if ((table=table_ptr[i])->s->tmp_table == TMP_TABLE)
continue;
*to++=table;
enum thr_lock_type lock_type= table->reginfo.lock_type;
@@ -431,7 +432,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
*write_lock_used=table;
if (table->db_stat & HA_READ_ONLY)
{
- my_error(ER_OPEN_AS_READONLY,MYF(0),table->table_name);
+ my_error(ER_OPEN_AS_READONLY, MYF(0), table->alias);
my_free((gptr) sql_lock,MYF(0));
return 0;
}
@@ -527,11 +528,11 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
char *db= table_list->db;
uint key_length;
DBUG_ENTER("lock_table_name");
- DBUG_PRINT("enter",("db: %s name: %s", db, table_list->real_name));
+ DBUG_PRINT("enter",("db: %s name: %s", db, table_list->table_name));
safe_mutex_assert_owner(&LOCK_open);
- key_length=(uint) (strmov(strmov(key,db)+1,table_list->real_name)
+ key_length=(uint) (strmov(strmov(key,db)+1,table_list->table_name)
-key)+ 1;
@@ -550,8 +551,9 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
if (!(table= (TABLE*) my_malloc(sizeof(*table)+key_length,
MYF(MY_WME | MY_ZEROFILL))))
DBUG_RETURN(-1);
- memcpy((table->table_cache_key= (char*) (table+1)), key, key_length);
- table->key_length=key_length;
+ table->s= &table->share_not_to_be_used;
+ memcpy((table->s->table_cache_key= (char*) (table+1)), key, key_length);
+ table->s->key_length=key_length;
table->in_use=thd;
table->locked_by_name=1;
table_list->table=table;
@@ -561,7 +563,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
my_free((gptr) table,MYF(0));
DBUG_RETURN(-1);
}
- if (remove_table_from_cache(thd, db, table_list->real_name))
+ if (remove_table_from_cache(thd, db, table_list->table_name, 0))
DBUG_RETURN(1); // Table is in use
DBUG_RETURN(0);
}
@@ -579,7 +581,7 @@ void unlock_table_name(THD *thd, TABLE_LIST *table_list)
static bool locked_named_table(THD *thd, TABLE_LIST *table_list)
{
- for (; table_list ; table_list=table_list->next)
+ for (; table_list ; table_list=table_list->next_local)
{
if (table_list->table && table_is_used(table_list->table,0))
return 1;
@@ -633,7 +635,7 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list)
bool got_all_locks=1;
TABLE_LIST *lock_table;
- for (lock_table=table_list ; lock_table ; lock_table=lock_table->next)
+ for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
{
int got_lock;
if ((got_lock=lock_table_name(thd,lock_table)) < 0)
@@ -676,13 +678,15 @@ end:
void unlock_table_names(THD *thd, TABLE_LIST *table_list,
TABLE_LIST *last_table)
{
- for (TABLE_LIST *table=table_list ; table != last_table ; table=table->next)
+ for (TABLE_LIST *table= table_list;
+ table != last_table;
+ table= table->next_local)
unlock_table_name(thd,table);
pthread_cond_broadcast(&COND_refresh);
}
-static void print_lock_error(int error)
+static void print_lock_error(int error, const char *table)
{
int textno;
DBUG_ENTER("print_lock_error");
@@ -694,11 +698,22 @@ static void print_lock_error(int error)
case HA_ERR_READ_ONLY_TRANSACTION:
textno=ER_READ_ONLY_TRANSACTION;
break;
+ case HA_ERR_LOCK_DEADLOCK:
+ textno=ER_LOCK_DEADLOCK;
+ break;
+ case HA_ERR_WRONG_COMMAND:
+ textno=ER_ILLEGAL_HA;
+ break;
default:
textno=ER_CANT_LOCK;
break;
}
- my_error(textno,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error);
+
+ if ( textno == ER_ILLEGAL_HA )
+ my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
+ else
+ my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
+
DBUG_VOID_RETURN;
}
@@ -722,6 +737,13 @@ static void print_lock_error(int error)
protect_against_global_read_lock
count of threads which have set protection against global read lock.
+ access to them is protected with a mutex LOCK_global_read_lock
+
+ (XXX: one should never take LOCK_open if LOCK_global_read_lock is taken,
+ otherwise a deadlock may occur - see mysql_rm_table. Other mutexes could
+ be a problem too - grep the code for global_read_lock if you want to use
+ any other mutex here)
+
How blocking of threads by global read lock is achieved: that's
advisory. Any piece of code which should be blocked by global read lock must
be designed like this:
@@ -759,7 +781,7 @@ static void print_lock_error(int error)
table instance of thd2
thd1: COMMIT; # blocked by thd3.
thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
-
+
Note that we need to support that one thread does
FLUSH TABLES WITH READ LOCK; and then COMMIT;
(that's what innobackup does, for some good reason).
@@ -786,8 +808,8 @@ bool lock_global_read_lock(THD *thd)
if (!thd->global_read_lock)
{
- (void) pthread_mutex_lock(&LOCK_open);
- const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
+ (void) pthread_mutex_lock(&LOCK_global_read_lock);
+ const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock,
"Waiting to get readlock");
DBUG_PRINT("info",
("waiting_for: %d protect_against: %d",
@@ -795,7 +817,7 @@ bool lock_global_read_lock(THD *thd)
waiting_for_read_lock++;
while (protect_against_global_read_lock && !thd->killed)
- pthread_cond_wait(&COND_refresh, &LOCK_open);
+ pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock);
waiting_for_read_lock--;
if (thd->killed)
{
@@ -804,7 +826,7 @@ bool lock_global_read_lock(THD *thd)
}
thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
global_read_lock++;
- thd->exit_cond(old_message);
+ thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
}
/*
We DON'T set global_read_lock_blocks_commit now, it will be set after
@@ -820,11 +842,11 @@ bool lock_global_read_lock(THD *thd)
void unlock_global_read_lock(THD *thd)
{
uint tmp;
- pthread_mutex_lock(&LOCK_open);
+ pthread_mutex_lock(&LOCK_global_read_lock);
tmp= --global_read_lock;
if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
--global_read_lock_blocks_commit;
- pthread_mutex_unlock(&LOCK_open);
+ pthread_mutex_unlock(&LOCK_global_read_lock);
/* Send the signal outside the mutex to avoid a context switch */
if (!tmp)
pthread_cond_broadcast(&COND_refresh);
@@ -843,14 +865,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
DBUG_ENTER("wait_if_global_read_lock");
LINT_INIT(old_message);
- (void) pthread_mutex_lock(&LOCK_open);
+ (void) pthread_mutex_lock(&LOCK_global_read_lock);
if ((need_exit_cond= must_wait))
{
if (thd->global_read_lock) // This thread had the read locks
{
if (is_not_commit)
- my_error(ER_CANT_UPDATE_WITH_READLOCK,MYF(0));
- (void) pthread_mutex_unlock(&LOCK_open);
+ my_message(ER_CANT_UPDATE_WITH_READLOCK,
+ ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0));
+ (void) pthread_mutex_unlock(&LOCK_global_read_lock);
/*
We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
This allowance is needed to not break existing versions of innobackup
@@ -858,11 +881,11 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
*/
DBUG_RETURN(is_not_commit);
}
- old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
+ old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock,
"Waiting for release of readlock");
while (must_wait && ! thd->killed &&
(!abort_on_refresh || thd->version == refresh_version))
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_global_read_lock);
if (thd->killed)
result=1;
}
@@ -872,10 +895,10 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
The following is only true in case of a global read locks (which is rare)
and if old_message is set
*/
- if (unlikely(need_exit_cond))
- thd->exit_cond(old_message);
+ if (unlikely(need_exit_cond))
+ thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
else
- pthread_mutex_unlock(&LOCK_open);
+ pthread_mutex_unlock(&LOCK_global_read_lock);
DBUG_RETURN(result);
}
@@ -886,34 +909,49 @@ void start_waiting_global_read_lock(THD *thd)
DBUG_ENTER("start_waiting_global_read_lock");
if (unlikely(thd->global_read_lock))
DBUG_VOID_RETURN;
- (void) pthread_mutex_lock(&LOCK_open);
+ (void) pthread_mutex_lock(&LOCK_global_read_lock);
tmp= (!--protect_against_global_read_lock &&
(waiting_for_read_lock || global_read_lock_blocks_commit));
- (void) pthread_mutex_unlock(&LOCK_open);
+ (void) pthread_mutex_unlock(&LOCK_global_read_lock);
if (tmp)
pthread_cond_broadcast(&COND_refresh);
DBUG_VOID_RETURN;
}
-void make_global_read_lock_block_commit(THD *thd)
+bool make_global_read_lock_block_commit(THD *thd)
{
+ bool error;
+ const char *old_message;
+ DBUG_ENTER("make_global_read_lock_block_commit");
/*
If we didn't succeed lock_global_read_lock(), or if we already suceeded
make_global_read_lock_block_commit(), do nothing.
*/
if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
- return;
- pthread_mutex_lock(&LOCK_open);
+ DBUG_RETURN(1);
+ pthread_mutex_lock(&LOCK_global_read_lock);
/* increment this BEFORE waiting on cond (otherwise race cond) */
global_read_lock_blocks_commit++;
- while (protect_against_global_read_lock)
- pthread_cond_wait(&COND_refresh, &LOCK_open);
- pthread_mutex_unlock(&LOCK_open);
- thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
+ /* For testing we set up some blocking, to see if we can be killed */
+ DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
+ protect_against_global_read_lock++;);
+ old_message= thd->enter_cond(&COND_refresh, &LOCK_global_read_lock,
+ "Waiting for all running commits to finish");
+ while (protect_against_global_read_lock && !thd->killed)
+ pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock);
+ DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
+ protect_against_global_read_lock--;);
+ if (error= thd->killed)
+ global_read_lock_blocks_commit--; // undo what we did
+ else
+ thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
+ thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
+ DBUG_RETURN(error);
}
+
/*
Set protection against global read lock.
@@ -926,9 +964,9 @@ void make_global_read_lock_block_commit(THD *thd)
TRUE Error, global read lock exists already.
*/
-my_bool set_protect_against_global_read_lock(void)
+bool set_protect_against_global_read_lock(void)
{
- my_bool global_read_lock_exists;
+ bool global_read_lock_exists;
pthread_mutex_lock(&LOCK_open);
if (! (global_read_lock_exists= test(global_read_lock)))
diff --git a/sql/log.cc b/sql/log.cc
index c8a3b512b6d..fc74223d7b6 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -24,7 +24,6 @@
#include "mysql_priv.h"
#include "sql_repl.h"
-#include "ha_innodb.h" // necessary to cut the binlog when crash recovery
#include <my_dir.h>
#include <stdarg.h>
@@ -34,28 +33,249 @@
#include "message.h"
#endif
-MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
+MYSQL_LOG mysql_log, mysql_slow_log, mysql_bin_log;
ulong sync_binlog_counter= 0;
static bool test_if_number(const char *str,
long *res, bool allow_wildcards);
+static int binlog_close_connection(THD *thd);
+static int binlog_savepoint_set(THD *thd, void *sv);
+static int binlog_savepoint_rollback(THD *thd, void *sv);
+static int binlog_commit(THD *thd, bool all);
+static int binlog_rollback(THD *thd, bool all);
+static int binlog_prepare(THD *thd, bool all);
+
+static handlerton binlog_hton = {
+ "binlog",
+ 0,
+ sizeof(my_off_t), /* savepoint size = binlog offset */
+ binlog_close_connection,
+ binlog_savepoint_set,
+ binlog_savepoint_rollback,
+ NULL, /* savepoint_release */
+ binlog_commit,
+ binlog_rollback,
+ binlog_prepare,
+ NULL, /* recover */
+ NULL, /* commit_by_xid */
+ NULL /* rollback_by_xid */
+};
+
+/*
+ this function is mostly a placeholder.
+ conceptually, binlog initialization (now mostly done in MYSQL_LOG::open)
+ should be moved here.
+*/
+
+handlerton *binlog_init()
+{
+ return &binlog_hton;
+}
+
+static int binlog_close_connection(THD *thd)
+{
+ IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
+ DBUG_ASSERT(mysql_bin_log.is_open() && !my_b_tell(trans_log));
+ close_cached_file(trans_log);
+ my_free((gptr)trans_log, MYF(0));
+ return 0;
+}
+
+static int binlog_end_trans(THD *thd, IO_CACHE *trans_log, Log_event *end_ev)
+{
+ int error=0;
+ DBUG_ENTER("binlog_end_trans");
+ if (end_ev)
+ error= mysql_bin_log.write(thd, trans_log, end_ev);
+
+ statistic_increment(binlog_cache_use, &LOCK_status);
+ if (trans_log->disk_writes != 0)
+ {
+ statistic_increment(binlog_cache_disk_use, &LOCK_status);
+ trans_log->disk_writes= 0;
+ }
+ reinit_io_cache(trans_log, WRITE_CACHE, (my_off_t) 0, 0, 1); // cannot fail
+ trans_log->end_of_file= max_binlog_cache_size;
+ DBUG_RETURN(error);
+}
+
+static int binlog_prepare(THD *thd, bool all)
+{
+ /*
+ do nothing.
+ just pretend we can do 2pc, so that MySQL won't
+ switch to 1pc.
+ real work will be done in MYSQL_LOG::log()
+ */
+ return 0;
+}
+
+static int binlog_commit(THD *thd, bool all)
+{
+ IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
+ DBUG_ENTER("binlog_commit");
+ DBUG_ASSERT(mysql_bin_log.is_open() &&
+ (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))));
+
+ if (!my_b_tell(trans_log))
+ {
+ // we're here because trans_log was flushed in MYSQL_LOG::log()
+ DBUG_RETURN(0);
+ }
+ Query_log_event qev(thd, "COMMIT", 6, TRUE, FALSE);
+ DBUG_RETURN(binlog_end_trans(thd, trans_log, &qev));
+}
+
+static int binlog_rollback(THD *thd, bool all)
+{
+ int error=0;
+ IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
+ DBUG_ENTER("binlog_rollback");
+ /*
+ First assert is guaranteed - see trans_register_ha() call below.
+ The second must be true. If it is not, we're registering
+ unnecessary, doing extra work. The cause should be found and eliminated
+ */
+ DBUG_ASSERT(all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)));
+ DBUG_ASSERT(mysql_bin_log.is_open() && my_b_tell(trans_log));
+ /*
+ Update the binary log with a BEGIN/ROLLBACK block if we have
+ cached some queries and we updated some non-transactional
+ table. Such cases should be rare (updating a
+ non-transactional table inside a transaction...)
+ */
+ if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE))
+ {
+ Query_log_event qev(thd, "ROLLBACK", 8, TRUE, FALSE);
+ error= binlog_end_trans(thd, trans_log, &qev);
+ }
+ else
+ error= binlog_end_trans(thd, trans_log, 0);
+ DBUG_RETURN(error);
+}
+
+/*
+ NOTE: how do we handle this (unlikely but legal) case:
+ [transaction] + [update to non-trans table] + [rollback to savepoint] ?
+ The problem occurs when a savepoint is before the update to the
+ non-transactional table. Then when there's a rollback to the savepoint, if we
+ simply truncate the binlog cache, we lose the part of the binlog cache where
+ the update is. If we want to not lose it, we need to write the SAVEPOINT
+ command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
+ is easy: it's just write at the end of the binlog cache, but the former
+ should be *inserted* to the place where the user called SAVEPOINT. The
+ solution is that when the user calls SAVEPOINT, we write it to the binlog
+ cache (so no need to later insert it). As transactions are never intermixed
+ in the binary log (i.e. they are serialized), we won't have conflicts with
+ savepoint names when using mysqlbinlog or in the slave SQL thread.
+ Then when ROLLBACK TO SAVEPOINT is called, if we updated some
+ non-transactional table, we don't truncate the binlog cache but instead write
+ ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
+ will chop the SAVEPOINT command from the binlog cache, which is good as in
+ that case there is no need to have it in the binlog).
+*/
+
+static int binlog_savepoint_set(THD *thd, void *sv)
+{
+ IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
+ DBUG_ENTER("binlog_savepoint_set");
+ DBUG_ASSERT(mysql_bin_log.is_open() && my_b_tell(trans_log));
+
+ *(my_off_t *)sv= my_b_tell(trans_log);
+ /* Write it to the binary log */
+ Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
+ DBUG_RETURN(mysql_bin_log.write(&qinfo));
+}
+
+static int binlog_savepoint_rollback(THD *thd, void *sv)
+{
+ IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
+ DBUG_ENTER("binlog_savepoint_rollback");
+ DBUG_ASSERT(mysql_bin_log.is_open() && my_b_tell(trans_log));
+
+ /*
+ Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
+ non-transactional table. Otherwise, truncate the binlog cache starting
+ from the SAVEPOINT command.
+ */
+ if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE))
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
+ DBUG_RETURN(mysql_bin_log.write(&qinfo));
+ }
+ reinit_io_cache(trans_log, WRITE_CACHE, *(my_off_t *)sv, 0, 0);
+ DBUG_RETURN(0);
+}
+
+int check_binlog_magic(IO_CACHE* log, const char** errmsg)
+{
+ char magic[4];
+ DBUG_ASSERT(my_b_tell(log) == 0);
+
+ if (my_b_read(log, (byte*) magic, sizeof(magic)))
+ {
+ *errmsg = "I/O error reading the header from the binary log";
+ sql_print_error("%s, errno=%d, io cache code=%d", *errmsg, my_errno,
+ log->error);
+ return 1;
+ }
+ if (memcmp(magic, BINLOG_MAGIC, sizeof(magic)))
+ {
+ *errmsg = "Binlog has bad magic number; It's not a binary log file that can be used by this version of MySQL";
+ return 1;
+ }
+ return 0;
+}
+
+File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
+{
+ File file;
+ DBUG_ENTER("open_binlog");
+
+ if ((file = my_open(log_file_name, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
+ {
+ sql_print_error("Failed to open log (file '%s', errno %d)",
+ log_file_name, my_errno);
+ *errmsg = "Could not open log file";
+ goto err;
+ }
+ if (init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
+ MYF(MY_WME|MY_DONT_CHECK_FILESIZE)))
+ {
+ sql_print_error("Failed to create a cache on log (file '%s')",
+ log_file_name);
+ *errmsg = "Could not open log file";
+ goto err;
+ }
+ if (check_binlog_magic(log,errmsg))
+ goto err;
+ DBUG_RETURN(file);
+
+err:
+ if (file >= 0)
+ {
+ my_close(file,MYF(0));
+ end_io_cache(log);
+ }
+ DBUG_RETURN(-1);
+}
#ifdef __NT__
static int eventSource = 0;
-void setup_windows_event_source()
+void setup_windows_event_source()
{
- HKEY hRegKey= NULL;
+ HKEY hRegKey= NULL;
DWORD dwError= 0;
TCHAR szPath[MAX_PATH];
DWORD dwTypes;
-
+
if (eventSource) // Ensure that we are only called once
return;
eventSource= 1;
// Create the event source registry key
- dwError= RegCreateKey(HKEY_LOCAL_MACHINE,
+ dwError= RegCreateKey(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\MySQL",
&hRegKey);
@@ -63,9 +283,8 @@ void setup_windows_event_source()
GetModuleFileName(NULL, szPath, MAX_PATH);
/* Register EventMessageFile */
- dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
+ dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
(PBYTE) szPath, strlen(szPath)+1);
-
/* Register supported event types */
dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
@@ -128,25 +347,20 @@ static int find_uniq_filename(char *name)
MYSQL_LOG::MYSQL_LOG()
:bytes_written(0), last_time(0), query_start(0), name(0),
file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0),
- need_start_event(1)
+ need_start_event(1), prepared_xids(0), description_event_for_exec(0),
+ description_event_for_queue(0)
{
/*
We don't want to initialize LOCK_Log here as such initialization depends on
safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
called only in main(). Doing initialization here would make it happen
- before main().
+ before main().
*/
index_file_name[0] = 0;
bzero((char*) &log_file,sizeof(log_file));
bzero((char*) &index_file, sizeof(index_file));
}
-
-MYSQL_LOG::~MYSQL_LOG()
-{
- cleanup();
-}
-
/* this is called only once */
void MYSQL_LOG::cleanup()
@@ -155,7 +369,9 @@ void MYSQL_LOG::cleanup()
if (inited)
{
inited= 0;
- close(LOG_CLOSE_INDEX);
+ close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
+ delete description_event_for_queue;
+ delete description_event_for_exec;
(void) pthread_mutex_destroy(&LOCK_log);
(void) pthread_mutex_destroy(&LOCK_index);
(void) pthread_cond_destroy(&update_cond);
@@ -165,7 +381,7 @@ void MYSQL_LOG::cleanup()
int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
-{
+{
fn_format(new_name,log_name,mysql_data_home,"",4);
if (log_type != LOG_NORMAL)
{
@@ -206,6 +422,66 @@ void MYSQL_LOG::init_pthread_objects()
(void) pthread_cond_init(&update_cond, 0);
}
+const char *MYSQL_LOG::generate_name(const char *log_name,
+ const char *suffix,
+ bool strip_ext, char *buff)
+{
+ if (!log_name || !log_name[0])
+ {
+ /*
+ TODO: The following should be using fn_format(); We just need to
+ first change fn_format() to cut the file name if it's too long.
+ */
+ strmake(buff,glob_hostname,FN_REFLEN-5);
+ strmov(fn_ext(buff),suffix);
+ return (const char *)buff;
+ }
+ // get rid of extension if the log is binary to avoid problems
+ if (strip_ext)
+ {
+ char *p = fn_ext(log_name);
+ uint length=(uint) (p-log_name);
+ strmake(buff,log_name,min(length,FN_REFLEN));
+ return (const char*)buff;
+ }
+ return log_name;
+}
+
+bool MYSQL_LOG::open_index_file(const char *index_file_name_arg,
+ const char *log_name)
+{
+ File index_file_nr= -1;
+ DBUG_ASSERT(!my_b_inited(&index_file));
+
+ /*
+ First open of this class instance
+ Create an index file that will hold all file names uses for logging.
+ Add new entries to the end of it.
+ */
+ myf opt= MY_UNPACK_FILENAME;
+ if (!index_file_name_arg)
+ {
+ index_file_name_arg= log_name; // Use same basename for index file
+ opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
+ }
+ fn_format(index_file_name, index_file_name_arg, mysql_data_home,
+ ".index", opt);
+ if ((index_file_nr= my_open(index_file_name,
+ O_RDWR | O_CREAT | O_BINARY ,
+ MYF(MY_WME))) < 0 ||
+ my_sync(index_file_nr, MYF(MY_WME)) ||
+ init_io_cache(&index_file, index_file_nr,
+ IO_SIZE, WRITE_CACHE,
+ my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
+ 0, MYF(MY_WME | MY_WAIT_IF_FULL)))
+ {
+ if (index_file_nr >= 0)
+ my_close(index_file_nr,MYF(0));
+ return TRUE;
+ }
+ return FALSE;
+}
+
/*
Open a (new) log file.
@@ -221,34 +497,39 @@ void MYSQL_LOG::init_pthread_objects()
1 error
*/
-bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
- const char *new_name, const char *index_file_name_arg,
- enum cache_type io_cache_type_arg,
- bool no_auto_events_arg,
- ulong max_size_arg)
+bool MYSQL_LOG::open(const char *log_name,
+ enum_log_type log_type_arg,
+ const char *new_name,
+ enum cache_type io_cache_type_arg,
+ bool no_auto_events_arg,
+ ulong max_size_arg,
+ bool null_created_arg)
{
- char buff[512];
- File file= -1, index_file_nr= -1;
- int open_flags = O_CREAT | O_APPEND | O_BINARY;
+ char buff[FN_REFLEN];
+ File file= -1;
+ int open_flags = O_CREAT | O_BINARY;
DBUG_ENTER("MYSQL_LOG::open");
- DBUG_PRINT("enter",("log_type: %d",(int) log_type));
+ DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
last_time=query_start=0;
write_error=0;
init(log_type_arg,io_cache_type_arg,no_auto_events_arg,max_size_arg);
-
+
if (!(name=my_strdup(log_name,MYF(MY_WME))))
+ {
+ name= (char *)log_name; // for the error message
goto err;
+ }
if (new_name)
strmov(log_file_name,new_name);
else if (generate_new_name(log_file_name, name))
goto err;
-
+
if (io_cache_type == SEQ_READ_APPEND)
- open_flags |= O_RDWR;
+ open_flags |= O_RDWR | O_APPEND;
else
- open_flags |= O_WRONLY;
+ open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND);
db[0]=0;
open_count++;
@@ -307,13 +588,6 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
{
bool write_file_name_to_index_file=0;
- myf opt= MY_UNPACK_FILENAME;
- if (!index_file_name_arg)
- {
- index_file_name_arg= name; // Use same basename for index file
- opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
- }
-
if (!my_b_filelength(&log_file))
{
/*
@@ -325,43 +599,64 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
if (my_b_safe_write(&log_file, (byte*) BINLOG_MAGIC,
BIN_LOG_HEADER_SIZE))
goto err;
- bytes_written += BIN_LOG_HEADER_SIZE;
- write_file_name_to_index_file=1;
+ bytes_written+= BIN_LOG_HEADER_SIZE;
+ write_file_name_to_index_file= 1;
}
- if (!my_b_inited(&index_file))
+ DBUG_ASSERT(my_b_inited(&index_file) != 0);
+ reinit_io_cache(&index_file, WRITE_CACHE,
+ my_b_filelength(&index_file), 0, 0);
+ if (need_start_event && !no_auto_events)
{
/*
- First open of this class instance
- Create an index file that will hold all file names uses for logging.
- Add new entries to the end of it.
- Index file (and binlog) are so critical for recovery/replication
- that we create them with MY_WAIT_IF_FULL.
+ In 4.x we set need_start_event=0 here, but in 5.0 we want a Start event
+ even if this is not the very first binlog.
*/
- fn_format(index_file_name, index_file_name_arg, mysql_data_home,
- ".index", opt);
- if ((index_file_nr= my_open(index_file_name,
- O_RDWR | O_CREAT | O_BINARY ,
- MYF(MY_WME))) < 0 ||
- my_sync(index_file_nr, MYF(MY_WME)) ||
- init_io_cache(&index_file, index_file_nr,
- IO_SIZE, WRITE_CACHE,
- my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
- 0, MYF(MY_WME | MY_WAIT_IF_FULL)))
- goto err;
- }
- else
- {
- safe_mutex_assert_owner(&LOCK_index);
- reinit_io_cache(&index_file, WRITE_CACHE, my_b_filelength(&index_file),
- 0, 0);
+ Format_description_log_event s(BINLOG_VERSION);
+ /*
+ don't set LOG_EVENT_BINLOG_IN_USE_F for SEQ_READ_APPEND io_cache
+ as we won't be able to reset it later
+ */
+ if (io_cache_type == WRITE_CACHE)
+ s.flags|= LOG_EVENT_BINLOG_IN_USE_F;
+ if (!s.is_valid())
+ goto err;
+ if (null_created_arg)
+ s.created= 0;
+ if (s.write(&log_file))
+ goto err;
+ bytes_written+= s.data_written;
}
- if (need_start_event && !no_auto_events)
+ if (description_event_for_queue &&
+ description_event_for_queue->binlog_version>=4)
{
- need_start_event=0;
- Start_log_event s;
- s.set_log_pos(this);
- s.write(&log_file);
+ /*
+ This is a relay log written to by the I/O slave thread.
+ Write the event so that others can later know the format of this relay
+ log.
+ Note that this event is very close to the original event from the
+ master (it has binlog version of the master, event types of the
+ master), so this is suitable to parse the next relay log's event. It
+ has been produced by
+ Format_description_log_event::Format_description_log_event(char* buf,).
+ Why don't we want to write the description_event_for_queue if this
+ event is for format<4 (3.23 or 4.x): this is because in that case, the
+ description_event_for_queue describes the data received from the
+ master, but not the data written to the relay log (*conversion*),
+ which is in format 4 (slave's).
+ */
+ /*
+ Set 'created' to 0, so that in next relay logs this event does not
+ trigger cleaning actions on the slave in
+ Format_description_log_event::exec_event().
+ */
+ description_event_for_queue->created= 0;
+ /* Don't set log_pos in event header */
+ description_event_for_queue->artificial_event=1;
+
+ if (description_event_for_queue->write(&log_file))
+ goto err;
+ bytes_written+= description_event_for_queue->data_written;
}
if (flush_io_cache(&log_file) ||
my_sync(log_file.file, MYF(MY_WME)))
@@ -393,11 +688,9 @@ err:
sql_print_error("Could not use %s for logging (error %d). \
Turning logging off for the whole duration of the MySQL server process. \
To turn it on again: fix the cause, \
-shutdown the MySQL server and restart it.", log_name, errno);
+shutdown the MySQL server and restart it.", name, errno);
if (file >= 0)
my_close(file,MYF(0));
- if (index_file_nr >= 0)
- my_close(index_file_nr,MYF(0));
end_io_cache(&log_file);
end_io_cache(&index_file);
safeFree(name);
@@ -503,8 +796,8 @@ int MYSQL_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
DBUG_PRINT("enter",("log_name: %s", log_name ? log_name : "NULL"));
/*
- Mutex needed because we need to make sure the file pointer does not move
- from under our feet
+ Mutex needed because we need to make sure the file pointer does not
+ move from under our feet
*/
if (need_lock)
pthread_mutex_lock(&LOCK_index);
@@ -587,7 +880,7 @@ int MYSQL_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
goto err;
}
- fname[length-1]=0; // kill /n
+ fname[length-1]=0; // kill \n
linfo->index_file_offset = my_b_tell(&index_file);
err:
@@ -629,6 +922,13 @@ bool MYSQL_LOG::reset_logs(THD* thd)
*/
pthread_mutex_lock(&LOCK_log);
pthread_mutex_lock(&LOCK_index);
+ /*
+ The following mutex is needed to ensure that no threads call
+ 'delete thd' as we would then risk missing a 'rollback' from this
+ thread. If the transaction involved MyISAM tables, it should go
+ into binlog even on rollback.
+ */
+ (void) pthread_mutex_lock(&LOCK_thread_count);
/* Save variables so that we can reopen the log */
save_name=name;
@@ -643,7 +943,7 @@ bool MYSQL_LOG::reset_logs(THD* thd)
error=1;
goto err;
}
-
+
for (;;)
{
my_delete(linfo.log_file_name, MYF(MY_WME));
@@ -656,11 +956,13 @@ bool MYSQL_LOG::reset_logs(THD* thd)
my_delete(index_file_name, MYF(MY_WME)); // Reset (open will update)
if (!thd->slave_thread)
need_start_event=1;
- open(save_name, save_log_type, 0, index_file_name,
- io_cache_type, no_auto_events, max_size);
+ open_index_file(index_file_name, 0);
+ open(save_name, save_log_type, 0,
+ io_cache_type, no_auto_events, max_size, 0);
my_free((gptr) save_name, MYF(0));
-err:
+err:
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
pthread_mutex_unlock(&LOCK_index);
pthread_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
@@ -679,7 +981,7 @@ err:
rli->group_relay_log_name are deleted ; if true, the latter is
deleted too (i.e. all relay logs
read by the SQL slave thread are deleted).
-
+
NOTE
- This is only called from the slave-execute thread when it has read
all commands from a relay log and want to switch to a new relay log.
@@ -839,22 +1141,18 @@ int MYSQL_LOG::purge_logs(const char *to_log,
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
!log_in_use(log_info.log_file_name))
{
- ulong tmp;
- LINT_INIT(tmp);
+ ulong file_size= 0;
if (decrease_log_space) //stat the file we want to delete
{
MY_STAT s;
+
+ /*
+ If we could not stat, we can't know the amount
+ of space that deletion will free. In most cases,
+ deletion won't work either, so it's not a problem.
+ */
if (my_stat(log_info.log_file_name,&s,MYF(0)))
- tmp= s.st_size;
- else
- {
- /*
- If we could not stat, we can't know the amount
- of space that deletion will free. In most cases,
- deletion won't work either, so it's not a problem.
- */
- tmp= 0;
- }
+ file_size= s.st_size;
}
/*
It's not fatal if we can't delete a log file ;
@@ -862,7 +1160,7 @@ int MYSQL_LOG::purge_logs(const char *to_log,
*/
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space)
- *decrease_log_space-= tmp;
+ *decrease_log_space-= file_size;
if (find_next_log(&log_info, 0) || exit_loop)
break;
}
@@ -978,8 +1276,7 @@ bool MYSQL_LOG::is_active(const char *log_file_name_arg)
SYNOPSIS
new_file()
- need_lock Set to 1 (default) if caller has not locked
- LOCK_log and LOCK_index
+ need_lock Set to 1 if caller has not locked LOCK_log
NOTE
The new file name is stored last in the index file
@@ -998,13 +1295,30 @@ void MYSQL_LOG::new_file(bool need_lock)
}
if (need_lock)
- {
pthread_mutex_lock(&LOCK_log);
- pthread_mutex_lock(&LOCK_index);
- }
+ pthread_mutex_lock(&LOCK_index);
+
safe_mutex_assert_owner(&LOCK_log);
safe_mutex_assert_owner(&LOCK_index);
+ /*
+ if binlog is used as tc log, be sure all xids are "unlogged",
+ so that on recover we only need to scan one - latest - binlog file
+ for prepared xids. As this is expected to be a rare event,
+ simple wait strategy is enough. We're locking LOCK_log to be sure no
+ new Xid_log_event's are added to the log (and prepared_xids is not
+ increased), and waiting on COND_prep_xids for late threads to
+ catch up.
+ */
+ if (prepared_xids)
+ {
+ tc_log_page_waits++;
+ pthread_mutex_lock(&LOCK_prep_xids);
+ while (prepared_xids)
+ pthread_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
+ pthread_mutex_unlock(&LOCK_prep_xids);
+ }
+
/* Reuse old name if not binlog and not update log */
new_name_ptr= name;
@@ -1016,7 +1330,7 @@ void MYSQL_LOG::new_file(bool need_lock)
if (generate_new_name(new_name, name))
goto end;
new_name_ptr=new_name;
-
+
if (log_type == LOG_BIN)
{
if (!no_auto_events)
@@ -1027,38 +1341,43 @@ void MYSQL_LOG::new_file(bool need_lock)
*/
THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */
Rotate_log_event r(thd,new_name+dirname_length(new_name));
- r.set_log_pos(this);
r.write(&log_file);
- bytes_written += r.get_event_len();
+ bytes_written += r.data_written;
}
/*
Update needs to be signalled even if there is no rotate event
log rotation should give the waiting thread a signal to
discover EOF and move on to the next log.
*/
- signal_update();
+ signal_update();
}
old_name=name;
save_log_type=log_type;
name=0; // Don't free name
close(LOG_CLOSE_TO_BE_OPENED);
- /*
+ /*
Note that at this point, log_type != LOG_CLOSED (important for is_open()).
*/
- open(old_name, save_log_type, new_name_ptr, index_file_name, io_cache_type,
- no_auto_events, max_size);
- if (this == &mysql_bin_log)
- report_pos_in_innodb();
+ /*
+ new_file() is only used for rotation (in FLUSH LOGS or because size >
+ max_binlog_size or max_relay_log_size).
+ If this is a binary log, the Format_description_log_event at the beginning of
+ the new file should have created=0 (to distinguish with the
+ Format_description_log_event written at server startup, which should
+ trigger temp tables deletion on slaves.
+ */
+
+ open(old_name, save_log_type, new_name_ptr,
+ io_cache_type, no_auto_events, max_size, 1);
my_free(old_name,MYF(0));
end:
if (need_lock)
- {
- pthread_mutex_unlock(&LOCK_index);
pthread_mutex_unlock(&LOCK_log);
- }
+ pthread_mutex_unlock(&LOCK_index);
+
DBUG_VOID_RETURN;
}
@@ -1079,16 +1398,12 @@ bool MYSQL_LOG::append(Log_event* ev)
error=1;
goto err;
}
- bytes_written += ev->get_event_len();
+ bytes_written+= ev->data_written;
DBUG_PRINT("info",("max_size: %lu",max_size));
if ((uint) my_b_append_tell(&log_file) > max_size)
- {
- pthread_mutex_lock(&LOCK_index);
new_file(0);
- pthread_mutex_unlock(&LOCK_index);
- }
-err:
+err:
pthread_mutex_unlock(&LOCK_log);
signal_update(); // Safe as we don't call close
DBUG_RETURN(error);
@@ -1101,9 +1416,9 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
DBUG_ENTER("MYSQL_LOG::appendv");
va_list(args);
va_start(args,len);
-
+
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
-
+
pthread_mutex_lock(&LOCK_log);
do
{
@@ -1116,11 +1431,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
DBUG_PRINT("info",("max_size: %lu",max_size));
if ((uint) my_b_append_tell(&log_file) > max_size)
- {
- pthread_mutex_lock(&LOCK_index);
new_file(0);
- pthread_mutex_unlock(&LOCK_index);
- }
err:
pthread_mutex_unlock(&LOCK_log);
@@ -1132,7 +1443,7 @@ err:
/*
Write to normal (not rotable) log
- This is the format for the 'normal', 'slow' and 'update' logs.
+ This is the format for the 'normal' log.
*/
bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
@@ -1220,55 +1531,43 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
return 0;
}
-
-inline bool sync_binlog(IO_CACHE *cache)
+bool MYSQL_LOG::flush_and_sync()
{
- return (sync_binlog_period &&
- (sync_binlog_period == ++sync_binlog_counter) &&
- (sync_binlog_counter= 0, my_sync(cache->file, MYF(MY_WME))));
+ int err=0, fd=log_file.file;
+ safe_mutex_assert_owner(&LOCK_log);
+ if (flush_io_cache(&log_file))
+ return 1;
+ if (++sync_binlog_counter >= sync_binlog_period && sync_binlog_period)
+ {
+ sync_binlog_counter= 0;
+ err=my_sync(fd, MYF(MY_WME));
+ }
+ return err;
}
/*
Write an event to the binary log
*/
-bool MYSQL_LOG::write(Log_event* event_info)
+bool MYSQL_LOG::write(Log_event *event_info)
{
- THD *thd=event_info->thd;
- bool called_handler_commit=0;
- bool error=0;
- bool should_rotate = 0;
- DBUG_ENTER("MYSQL_LOG::write(event)");
-
+ THD *thd= event_info->thd;
+ bool error= 1;
+ DBUG_ENTER("MYSQL_LOG::write(Log_event *)");
+
pthread_mutex_lock(&LOCK_log);
- /*
+ /*
In most cases this is only called if 'is_open()' is true; in fact this is
mostly called if is_open() *was* true a few instructions before, but it
could have changed since.
*/
- if (is_open())
+ if (likely(is_open()))
{
const char *local_db= event_info->get_db();
IO_CACHE *file= &log_file;
-#ifdef USING_TRANSACTIONS
- /*
- Should we write to the binlog cache or to the binlog on disk?
- Write to the binlog cache if:
- - it is already not empty (meaning we're in a transaction; note that the
- present event could be about a non-transactional table, but still we need
- to write to the binlog cache in that case to handle updates to mixed
- trans/non-trans table types the best possible in binlogging)
- - or if the event asks for it (cache_stmt == true).
- */
- if (opt_using_transactions &&
- (event_info->get_cache_stmt() ||
- (thd && my_b_tell(&thd->transaction.trans_log))))
- file= &thd->transaction.trans_log;
-#endif
- DBUG_PRINT("info",("event type=%d",event_info->get_type_code()));
#ifdef HAVE_REPLICATION
- /*
+ /*
In the future we need to add to the following if tests like
"do the involved tables match (to be implemented)
binlog_[wild_]{do|ignore}_table?" (WL#1049)"
@@ -1282,88 +1581,81 @@ bool MYSQL_LOG::write(Log_event* event_info)
}
#endif /* HAVE_REPLICATION */
- error=1;
+#ifdef USING_TRANSACTIONS
+ /*
+ Should we write to the binlog cache or to the binlog on disk?
+ Write to the binlog cache if:
+ - it is already not empty (meaning we're in a transaction; note that the
+ present event could be about a non-transactional table, but still we need
+ to write to the binlog cache in that case to handle updates to mixed
+ trans/non-trans table types the best possible in binlogging)
+ - or if the event asks for it (cache_stmt == true).
+ */
+ if (opt_using_transactions && thd)
+ {
+ IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
+
+ if (event_info->get_cache_stmt())
+ {
+ if (!trans_log)
+ {
+ thd->ha_data[binlog_hton.slot]= trans_log= (IO_CACHE *)
+ my_malloc(sizeof(IO_CACHE), MYF(MY_ZEROFILL));
+ if (!trans_log || open_cached_file(trans_log, mysql_tmpdir,
+ LOG_PREFIX,
+ binlog_cache_size, MYF(MY_WME)))
+ {
+ my_free((gptr)trans_log, MYF(MY_ALLOW_ZERO_PTR));
+ thd->ha_data[binlog_hton.slot]= trans_log= 0;
+ goto err;
+ }
+ trans_log->end_of_file= max_binlog_cache_size;
+ trans_register_ha(thd,
+ thd->options & (OPTION_NOT_AUTOCOMMIT |
+ OPTION_BEGIN),
+ &binlog_hton);
+ }
+ else if (!my_b_tell(trans_log))
+ trans_register_ha(thd,
+ thd->options & (OPTION_NOT_AUTOCOMMIT |
+ OPTION_BEGIN),
+ &binlog_hton);
+ file= trans_log;
+ }
+ else if (trans_log && my_b_tell(trans_log))
+ file= trans_log;
+ }
+#endif
+ DBUG_PRINT("info",("event type=%d",event_info->get_type_code()));
+
/*
No check for auto events flag here - this write method should
never be called if auto-events are enabled
*/
/*
- 1. Write first log events which describe the 'run environment'
- of the SQL command
+ 1. Write first log events which describe the 'run environment'
+ of the SQL command
*/
if (thd)
{
-#if MYSQL_VERSION_ID < 50000
- /*
- To make replication of charsets working in 4.1 we are writing values
- of charset related variables before every statement in the binlog,
- if values of those variables differ from global server-wide defaults.
- We are using SET ONE_SHOT command so that the charset vars get reset
- to default after the first non-SET statement.
- In the next 5.0 this won't be needed as we will use the new binlog
- format to store charset info.
- */
- if ((thd->variables.character_set_client->number !=
- global_system_variables.collation_server->number) ||
- (thd->variables.character_set_client->number !=
- thd->variables.collation_connection->number) ||
- (thd->variables.collation_server->number !=
- thd->variables.collation_connection->number))
- {
- char buf[200];
- int written= my_snprintf(buf, sizeof(buf)-1,
- "SET ONE_SHOT CHARACTER_SET_CLIENT=%u,\
-COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
- (uint) thd->variables.character_set_client->number,
- (uint) thd->variables.collation_connection->number,
- (uint) thd->variables.collation_database->number,
- (uint) thd->variables.collation_server->number);
- Query_log_event e(thd, buf, written, 0, FALSE);
- e.set_log_pos(this);
- e.error_code = 0; // This statement cannot fail (see [1]).
- if (e.write(file))
- goto err;
- }
- /*
- We use the same ONE_SHOT trick for making replication of time zones
- working in 4.1. Again in 5.0 we have better means for doing this.
- */
- if (thd->time_zone_used &&
- thd->variables.time_zone != global_system_variables.time_zone)
- {
- char buf[MAX_TIME_ZONE_NAME_LENGTH + 26];
- char *buf_end= strxmov(buf, "SET ONE_SHOT TIME_ZONE='",
- thd->variables.time_zone->get_name()->ptr(),
- "'", NullS);
- Query_log_event e(thd, buf, buf_end - buf, 0, FALSE);
- e.set_log_pos(this);
- e.error_code = 0; // This statement cannot fail (see [1]).
- if (e.write(file))
- goto err;
- }
-#endif
-
if (thd->last_insert_id_used)
{
Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
thd->current_insert_id);
- e.set_log_pos(this);
if (e.write(file))
goto err;
}
if (thd->insert_id_used)
{
Intvar_log_event e(thd,(uchar) INSERT_ID_EVENT,thd->last_insert_id);
- e.set_log_pos(this);
if (e.write(file))
goto err;
}
if (thd->rand_used)
{
Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
- e.set_log_pos(this);
if (e.write(file))
goto err;
}
@@ -1379,139 +1671,25 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
user_var_event->length,
user_var_event->type,
user_var_event->charset_number);
- e.set_log_pos(this);
if (e.write(file))
goto err;
}
}
-#ifdef TO_BE_REMOVED
- if (thd->variables.convert_set)
- {
- char buf[256], *p;
- p= strmov(strmov(buf, "SET CHARACTER SET "),
- thd->variables.convert_set->name);
- Query_log_event e(thd, buf, (ulong) (p - buf), 0);
- e.set_log_pos(this);
- e.error_code = 0; // This statement cannot fail (see [1]).
- if (e.write(file))
- goto err;
- }
-#endif
-
- /*
- If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL
- command in the binlog inside:
- SET FOREIGN_KEY_CHECKS=0;
- <command>;
- SET FOREIGN_KEY_CHECKS=1;
- */
-
- if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
- {
- Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=0", 24, 0, FALSE);
- e.set_log_pos(this);
- e.error_code = 0; // This statement cannot fail (see [1]).
- if (e.write(file))
- goto err;
- }
}
- /*
- Write the SQL command
-
- [1] If this statement has an error code, the slave is required to fail
- with the same error code or stop. The preamble and epilogue should
- *not* have this error code since the execution of those is
- guaranteed *not* to produce any error code. This would therefore
- stop the slave even if the execution of the real statement can be
- handled gracefully by the slave.
+ /*
+ Write the SQL command
*/
- event_info->set_log_pos(this);
if (event_info->write(file))
goto err;
- /* Write log events to reset the 'run environment' of the SQL command */
-
- if (thd)
- {
- if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
- {
- Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=1", 24, 0, FALSE);
- e.set_log_pos(this);
- e.error_code = 0; // This statement cannot fail (see [1]).
- if (e.write(file))
- goto err;
- }
- }
-
- /*
- Tell for transactional table handlers up to which position in the
- binlog file we wrote. The table handler can store this info, and
- after crash recovery print for the user the offset of the last
- transactions which were recovered. Actually, we must also call
- the table handler commit here, protected by the LOCK_log mutex,
- because otherwise the transactions may end up in a different order
- in the table handler log!
-
- Note that we will NOT call ha_report_binlog_offset_and_commit() if
- there are binlog events cached in the transaction cache. That is
- because then the log event which we write to the binlog here is
- not a transactional event. In versions < 4.0.13 before this fix this
- caused an InnoDB transaction to be committed if in the middle there
- was a MyISAM event!
- */
-
if (file == &log_file) // we are writing to the real log (disk)
{
- if (flush_io_cache(file) || sync_binlog(file))
+ if (flush_and_sync())
goto err;
-
- if (opt_using_transactions &&
- !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
- {
- /*
- LOAD DATA INFILE in AUTOCOMMIT=1 mode writes to the binlog
- chunks also before it is successfully completed. We only report
- the binlog write and do the commit inside the transactional table
- handler if the log event type is appropriate.
- */
-
- if (event_info->get_type_code() == QUERY_EVENT ||
- event_info->get_type_code() == EXEC_LOAD_EVENT)
- {
-#ifndef DBUG_OFF
- if (unlikely(opt_crash_binlog_innodb))
- {
- /*
- This option is for use in rpl_crash_binlog_innodb.test.
- 1st we want to verify that Binlog_dump thread cannot send the
- event now (because of LOCK_log): we here tell the Binlog_dump
- thread to wake up, sleep for the slave to have time to possibly
- receive data from the master (it should not), and then crash.
- 2nd we want to verify that at crash recovery the rolled back
- event is cut from the binlog.
- */
- if (!(--opt_crash_binlog_innodb))
- {
- signal_update();
- sleep(2);
- fprintf(stderr,"This is a normal crash because of"
- " --crash-binlog-innodb\n");
- assert(0);
- }
- DBUG_PRINT("info",("opt_crash_binlog_innodb: %d",
- opt_crash_binlog_innodb));
- }
-#endif
- error = ha_report_binlog_offset_and_commit(thd, log_file_name,
- file->pos_in_file);
- called_handler_commit=1;
- }
- }
- /* We wrote to the real log, check automatic rotation; */
- DBUG_PRINT("info",("max_size: %lu",max_size));
- should_rotate= (my_b_tell(file) >= (my_off_t) max_size);
+ signal_update();
+ rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
}
error=0;
@@ -1519,44 +1697,38 @@ err:
if (error)
{
if (my_errno == EFBIG)
- my_error(ER_TRANS_CACHE_FULL, MYF(0));
+ my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(0));
else
my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno);
write_error=1;
}
- if (file == &log_file)
- signal_update();
- if (should_rotate)
- {
- pthread_mutex_lock(&LOCK_index);
- new_file(0); // inside mutex
- pthread_mutex_unlock(&LOCK_index);
- }
}
pthread_mutex_unlock(&LOCK_log);
+ DBUG_RETURN(error);
+}
- /*
- Flush the transactional handler log file now that we have released
- LOCK_log; the flush is placed here to eliminate the bottleneck on the
- group commit
- */
-
- if (called_handler_commit)
- ha_commit_complete(thd);
-
-#ifdef HAVE_REPLICATION
- if (should_rotate && expire_logs_days)
+void MYSQL_LOG::rotate_and_purge(uint flags)
+{
+ if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
+ pthread_mutex_lock(&LOCK_log);
+ if ((flags & RP_FORCE_ROTATE) ||
+ (my_b_tell(&log_file) >= (my_off_t) max_size))
{
- long purge_time= time(0) - expire_logs_days*24*60*60;
- if (purge_time >= 0)
- error= purge_logs_before_date(purge_time);
- }
+ new_file(0);
+#ifdef HAVE_REPLICATION
+ if (expire_logs_days)
+ {
+ long purge_time= time(0) - expire_logs_days*24*60*60;
+ if (purge_time >= 0)
+ purge_logs_before_date(purge_time);
+ }
#endif
- DBUG_RETURN(error);
+ }
+ if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
+ pthread_mutex_unlock(&LOCK_log);
}
-
uint MYSQL_LOG::next_file_id()
{
uint res;
@@ -1572,10 +1744,8 @@ uint MYSQL_LOG::next_file_id()
SYNOPSIS
write()
- thd
+ thd
cache The cache to copy to the binlog
- commit_or_rollback If true, will write "COMMIT" in the end, if false will
- write "ROLLBACK".
NOTE
- We only come here if there is something in the cache.
@@ -1585,35 +1755,25 @@ uint MYSQL_LOG::next_file_id()
IMPLEMENTATION
- To support transaction over replication, we wrap the transaction
with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
- We want to write a BEGIN/ROLLBACK block when a non-transactional table was
- updated in a transaction which was rolled back. This is to ensure that the
- same updates are run on the slave.
+ We want to write a BEGIN/ROLLBACK block when a non-transactional table
+ was updated in a transaction which was rolled back. This is to ensure
+ that the same updates are run on the slave.
*/
-bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
+bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
{
- bool should_rotate= 0, error= 0;
+ DBUG_ENTER("MYSQL_LOG::write(THD *, IO_CACHE *, Log_event *)");
VOID(pthread_mutex_lock(&LOCK_log));
- DBUG_ENTER("MYSQL_LOG::write(cache");
-
- if (is_open()) // Should always be true
+
+ if (likely(is_open())) // Should always be true
{
uint length;
/*
- Add the "BEGIN" and "COMMIT" in the binlog around transactions
- which may contain more than 1 SQL statement. If we run with
- AUTOCOMMIT=1, then MySQL immediately writes each SQL statement to
- the binlog when the statement has been completed. No need to add
- "BEGIN" ... "COMMIT" around such statements. Otherwise, MySQL uses
- thd->transaction.trans_log to cache the SQL statements until the
- explicit commit, and at the commit writes the contents in .trans_log
- to the binlog.
-
- We write the "BEGIN" mark first in the buffer (.trans_log) where we
- store the SQL statements for a transaction. At the transaction commit
- we will add the "COMMIT mark and write the buffer to the binlog.
+ Log "BEGIN" at the beginning of the transaction.
+ which may contain more than 1 SQL statement.
*/
+ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
{
Query_log_event qinfo(thd, "BEGIN", 5, TRUE, FALSE);
/*
@@ -1631,7 +1791,6 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
master's binlog, which would result in wrong positions being shown to
the user, MASTER_POS_WAIT undue waiting etc.
*/
- qinfo.set_log_pos(this);
if (qinfo.write(&log_file))
goto err;
}
@@ -1639,83 +1798,45 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
goto err;
length=my_b_bytes_in_cache(cache);
+ DBUG_EXECUTE_IF("half_binlogged_transaction", length-=100;);
do
{
/* Write data to the binary log file */
if (my_b_write(&log_file, cache->read_pos, length))
goto err;
cache->read_pos=cache->read_end; // Mark buffer used up
+ DBUG_EXECUTE_IF("half_binlogged_transaction", goto DBUG_skip_commit;);
} while ((length=my_b_fill(cache)));
- /*
- We write the command "COMMIT" as the last SQL command in the
- binlog segment cached for this transaction
- */
-
- {
- Query_log_event qinfo(thd,
- commit_or_rollback ? "COMMIT" : "ROLLBACK",
- commit_or_rollback ? 6 : 8,
- TRUE, FALSE);
- qinfo.error_code= 0;
- qinfo.set_log_pos(this);
- if (qinfo.write(&log_file) || flush_io_cache(&log_file) ||
- sync_binlog(&log_file))
- goto err;
- }
+ if (commit_event->write(&log_file))
+ goto err;
+DBUG_skip_commit:
+ if (flush_and_sync())
+ goto err;
+ DBUG_EXECUTE_IF("half_binlogged_transaction", abort(););
if (cache->error) // Error on read
{
sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
write_error=1; // Don't give more errors
goto err;
}
-#ifndef DBUG_OFF
- if (unlikely(opt_crash_binlog_innodb))
- {
- /* see the previous MYSQL_LOG::write() method for a comment */
- if (!(--opt_crash_binlog_innodb))
- {
- signal_update();
- sleep(2);
- fprintf(stderr, "This is a normal crash because of"
- " --crash-binlog-innodb\n");
- assert(0);
- }
- DBUG_PRINT("info",("opt_crash_binlog_innodb: %d",
- opt_crash_binlog_innodb));
- }
-#endif
- if ((ha_report_binlog_offset_and_commit(thd, log_file_name,
- log_file.pos_in_file)))
- goto err;
signal_update();
- DBUG_PRINT("info",("max_size: %lu",max_size));
- if (should_rotate= (my_b_tell(&log_file) >= (my_off_t) max_size))
- {
- pthread_mutex_lock(&LOCK_index);
- new_file(0); // inside mutex
- pthread_mutex_unlock(&LOCK_index);
- }
-
+ /*
+ if commit_event is Xid_log_event, increase the number of
+ prepared_xids (it's decreasd in ::unlog()). Binlog cannot be rotated
+ if there're prepared xids in it - see the comment in new_file() for
+ an explanation.
+ If the commit_event is not Xid_log_event (then it's a Query_log_event)
+ rotate binlog, if necessary.
+ */
+ if (commit_event->get_type_code() == XID_EVENT)
+ thread_safe_increment(prepared_xids, &LOCK_prep_xids);
+ else
+ rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
}
VOID(pthread_mutex_unlock(&LOCK_log));
- /* Flush the transactional handler log file now that we have released
- LOCK_log; the flush is placed here to eliminate the bottleneck on the
- group commit */
-
- ha_commit_complete(thd);
-
-#ifdef HAVE_REPLICATION
- if (should_rotate && expire_logs_days)
- {
- long purge_time= time(0) - expire_logs_days*24*60*60;
- if (purge_time >= 0)
- error= purge_logs_before_date(purge_time);
- }
-#endif
-
- DBUG_RETURN(error);
+ DBUG_RETURN(0);
err:
if (!write_error)
@@ -1729,8 +1850,7 @@ err:
/*
- Write update log in a format suitable for incremental backup
- This is also used by the slow query log.
+ Write to the slow query log.
*/
bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
@@ -1861,26 +1981,26 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
SYNOPSIS
wait_for_update()
thd Thread variable
- master_or_slave If 0, the caller is the Binlog_dump thread from master;
+ is_slave If 0, the caller is the Binlog_dump thread from master;
if 1, the caller is the SQL thread from the slave. This
influences only thd->proc_info.
NOTES
One must have a lock on LOCK_log before calling this function.
- This lock will be freed before return! That's required by
+ This lock will be released before return! That's required by
THD::enter_cond() (see NOTES in sql_class.h).
*/
-void MYSQL_LOG::wait_for_update(THD* thd, bool master_or_slave)
+void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave)
{
const char *old_msg;
DBUG_ENTER("wait_for_update");
old_msg= thd->enter_cond(&update_cond, &LOCK_log,
- master_or_slave ?
+ is_slave ?
"Has read all relay log; waiting for the slave I/O "
- "thread to update it" :
+ "thread to update it" :
"Has sent all binlog to slave; waiting for binlog "
- "to be updated");
+ "to be updated");
pthread_cond_wait(&update_cond, &LOCK_log);
thd->exit_cond(old_msg);
DBUG_VOID_RETURN;
@@ -1892,11 +2012,11 @@ void MYSQL_LOG::wait_for_update(THD* thd, bool master_or_slave)
SYNOPSIS
close()
- exiting Bitmask for one or more of the following bits:
- LOG_CLOSE_INDEX if we should close the index file
- LOG_CLOSE_TO_BE_OPENED if we intend to call open
- at once after close.
- LOG_CLOSE_STOP_EVENT write a 'stop' event to the log
+ exiting Bitmask for one or more of the following bits:
+ LOG_CLOSE_INDEX if we should close the index file
+ LOG_CLOSE_TO_BE_OPENED if we intend to call open
+ at once after close.
+ LOG_CLOSE_STOP_EVENT write a 'stop' event to the log
NOTES
One can do an open on the object at once after doing a close.
@@ -1914,13 +2034,27 @@ void MYSQL_LOG::close(uint exiting)
(exiting & LOG_CLOSE_STOP_EVENT))
{
Stop_log_event s;
- s.set_log_pos(this);
s.write(&log_file);
+ bytes_written+= s.data_written;
signal_update();
}
#endif /* HAVE_REPLICATION */
end_io_cache(&log_file);
- if (my_close(log_file.file,MYF(0)) < 0 && ! write_error)
+
+ /* don't pwrite in a file opened with O_APPEND - it doesn't work */
+ if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
+ {
+ my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
+ byte flags=0; // clearing LOG_EVENT_BINLOG_IN_USE_F
+ my_pwrite(log_file.file, &flags, 1, offset, MYF(0));
+ }
+
+ if (my_sync(log_file.file,MYF(MY_WME)) && ! write_error)
+ {
+ write_error=1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+ }
+ if (my_close(log_file.file,MYF(MY_WME)) && ! write_error)
{
write_error=1;
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
@@ -2104,145 +2238,6 @@ bool flush_error_log()
return result;
}
-
-/*
- If the server has InnoDB on, and InnoDB has published the position of the
- last committed transaction (which happens only if a crash recovery occured at
- this startup) then truncate the previous binary log at the position given by
- InnoDB. If binlog is shorter than the position, print a message to the error
- log.
-
- SYNOPSIS
- cut_spurious_tail()
-
- RETURN VALUES
- 1 Error
- 0 Ok
-*/
-
-bool MYSQL_LOG::cut_spurious_tail()
-{
- int error= 0;
- DBUG_ENTER("cut_spurious_tail");
-
-#ifdef HAVE_INNOBASE_DB
- if (have_innodb != SHOW_OPTION_YES)
- DBUG_RETURN(0);
- /*
- This is the place where we use information from InnoDB to cut the
- binlog.
- */
- char *name= ha_innobase::get_mysql_bin_log_name();
- ulonglong pos= ha_innobase::get_mysql_bin_log_pos();
- ulonglong actual_size;
- char llbuf1[22], llbuf2[22];
-
- if (name[0] == 0 || pos == ULONGLONG_MAX)
- {
- DBUG_PRINT("info", ("InnoDB has not set binlog info"));
- DBUG_RETURN(0);
- }
- /* The binlog given by InnoDB normally is never an active binlog */
- if (is_open() && is_active(name))
- {
- sql_print_error("Warning: after InnoDB crash recovery, InnoDB says that "
- "the binary log of the previous run has the same name "
- "'%s' as the current one; this is likely to be abnormal.",
- name);
- DBUG_RETURN(1);
- }
- sql_print_error("After InnoDB crash recovery, checking if the binary log "
- "'%s' contains rolled back transactions which must be "
- "removed from it...", name);
- /* If we have a too long binlog, cut. If too short, print error */
- int fd= my_open(name, O_EXCL | O_APPEND | O_BINARY | O_WRONLY, MYF(MY_WME));
- if (fd < 0)
- {
- int save_errno= my_errno;
- sql_print_error("Could not open the binary log '%s' for truncation.",
- name);
- if (save_errno != ENOENT)
- sql_print_error("The binary log '%s' should not be used for "
- "replication.", name);
- DBUG_RETURN(1);
- }
-
- if (pos > (actual_size= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME))))
- {
- /*
- Note that when we have MyISAM rollback this error message should be
- reconsidered.
- */
- sql_print_error("The binary log '%s' is shorter than its expected size "
- "(actual: %s, expected: %s) so it misses at least one "
- "committed transaction; so it should not be used for "
- "replication or point-in-time recovery. You would need "
- "to restart slaves from a fresh master's data "
- "snapshot ",
- name, llstr(actual_size, llbuf1),
- llstr(pos, llbuf2));
- error= 1;
- goto err;
- }
- if (pos < actual_size)
- {
- sql_print_error("The binary log '%s' is bigger than its expected size "
- "(actual: %s, expected: %s) so it contains a rolled back "
- "transaction; now truncating that.", name,
- llstr(actual_size, llbuf1), llstr(pos, llbuf2));
- /*
- As on some OS, my_chsize() can only pad with 0s instead of really
- truncating. Then mysqlbinlog (and Binlog_dump thread) will error on
- these zeroes. This is annoying, but not more (you just need to manually
- switch replication to the next binlog). Fortunately, in my_chsize.c, it
- says that all modern machines support real ftruncate().
-
- */
- if ((error= my_chsize(fd, pos, 0, MYF(MY_WME))))
- goto err;
- }
-err:
- if (my_close(fd, MYF(MY_WME)))
- error= 1;
-#endif
- DBUG_RETURN(error);
-}
-
-
-/*
- If the server has InnoDB on, store the binlog name and position into
- InnoDB. This function is used every time we create a new binlog.
-
- SYNOPSIS
- report_pos_in_innodb()
-
- NOTES
- This cannot simply be done in MYSQL_LOG::open(), because when we create
- the first binlog at startup, we have not called ha_init() yet so we cannot
- write into InnoDB yet.
-
- RETURN VALUES
- 1 Error
- 0 Ok
-*/
-
-void MYSQL_LOG::report_pos_in_innodb()
-{
- DBUG_ENTER("report_pos_in_innodb");
-#ifdef HAVE_INNOBASE_DB
- if (is_open() && have_innodb == SHOW_OPTION_YES)
- {
- DBUG_PRINT("info", ("Reporting binlog info into InnoDB - "
- "name: '%s' position: %d",
- log_file_name, my_b_tell(&log_file)));
- innobase_store_binlog_offset_and_flush_log(log_file_name,
- my_b_tell(&log_file));
- }
-#endif
- DBUG_VOID_RETURN;
-}
-
-
void MYSQL_LOG::signal_update()
{
DBUG_ENTER("MYSQL_LOG::signal_update");
@@ -2307,7 +2302,7 @@ void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
vprint_msg_to_log()
event_type Type of event to write (Error, Warning, or Info)
format Printf style format of message
- args va_list list of arguments for the message
+ args va_list list of arguments for the message
NOTE
@@ -2373,3 +2368,644 @@ void sql_print_information(const char *format, ...)
DBUG_VOID_RETURN;
}
+
+#ifdef HAVE_MMAP
+/********* transaction coordinator log for 2pc - mmap() based solution *******/
+
+/*
+ the log consists of a file, mmapped to a memory.
+ file is divided on pages of tc_log_page_size size.
+ (usable size of the first page is smaller because of log header)
+ there's PAGE control structure for each page
+ each page (or rather PAGE control structure) can be in one of three
+ states - active, syncing, pool.
+ there could be only one page in active or syncing states,
+ but many in pool - pool is fifo queue.
+ usual lifecycle of a page is pool->active->syncing->pool
+ "active" page - is a page where new xid's are logged.
+ the page stays active as long as syncing slot is taken.
+ "syncing" page is being synced to disk. no new xid can be added to it.
+ when the sync is done the page is moved to a pool and an active page
+ becomes "syncing".
+
+ the result of such an architecture is a natural "commit grouping" -
+ If commits are coming faster than the system can sync, they do not
+ stall. Instead, all commit that came since the last sync are
+ logged to the same page, and they all are synced with the next -
+ one - sync. Thus, thought individual commits are delayed, throughput
+ is not decreasing.
+
+ when a xid is added to an active page, the thread of this xid waits
+ for a page's condition until the page is synced. when syncing slot
+ becomes vacant one of these waiters is awaken to take care of syncing.
+ it syncs the page and signals all waiters that the page is synced.
+ PAGE::waiters is used to count these waiters, and a page may never
+ become active again until waiters==0 (that is all waiters from the
+ previous sync have noticed the sync was completed)
+
+ note, that the page becomes "dirty" and has to be synced only when a
+ new xid is added into it. Removing a xid from a page does not make it
+ dirty - we don't sync removals to disk.
+*/
+#define TC_LOG_HEADER_SIZE (sizeof(tc_log_magic)+1)
+
+static const char tc_log_magic[]={(char) 254, 0x23, 0x05, 0x74};
+
+ulong opt_tc_log_size= TC_LOG_MIN_SIZE;
+ulong tc_log_max_pages_used=0, tc_log_page_size=0,
+ tc_log_page_waits=0, tc_log_cur_pages_used=0;
+
+int TC_LOG_MMAP::open(const char *opt_name)
+{
+ uint i;
+ bool crashed=FALSE;
+ PAGE *pg;
+
+ DBUG_ASSERT(total_ha_2pc > 1);
+ DBUG_ASSERT(opt_name && opt_name[0]);
+
+ tc_log_page_size= my_getpagesize();
+ DBUG_ASSERT(TC_LOG_PAGE_SIZE % tc_log_page_size == 0);
+
+ fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME);
+ if ((fd= my_open(logname, O_RDWR, MYF(0))) < 0)
+ {
+ if (my_errno != ENOENT)
+ goto err;
+ if (using_heuristic_recover())
+ return 1;
+ if ((fd= my_create(logname, O_RDWR, 0, MYF(MY_WME))) < 0)
+ goto err;
+ inited=1;
+ file_length= opt_tc_log_size;
+ if (my_chsize(fd, file_length, 0, MYF(MY_WME)))
+ goto err;
+ }
+ else
+ {
+ inited= 1;
+ crashed= TRUE;
+ sql_print_information("Recovering after a crash using %s", opt_name);
+ if (tc_heuristic_recover)
+ {
+ sql_print_error("Cannot perform automatic crash recovery when "
+ "--tc-heuristic-recover is used");
+ goto err;
+ }
+ file_length= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
+ if (file_length == MY_FILEPOS_ERROR || file_length % tc_log_page_size)
+ goto err;
+ }
+
+ data= (uchar *)my_mmap(0, (size_t)file_length, PROT_READ|PROT_WRITE,
+ MAP_NOSYNC|MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED)
+ {
+ my_errno=errno;
+ goto err;
+ }
+ inited=2;
+
+ npages=(uint)file_length/tc_log_page_size;
+ DBUG_ASSERT(npages >= 3); // to guarantee non-empty pool
+ if (!(pages=(PAGE *)my_malloc(npages*sizeof(PAGE), MYF(MY_WME|MY_ZEROFILL))))
+ goto err;
+ inited=3;
+ for (pg=pages, i=0; i < npages; i++, pg++)
+ {
+ pg->next=pg+1;
+ pg->waiters=0;
+ pg->state=POOL;
+ pthread_mutex_init(&pg->lock, MY_MUTEX_INIT_FAST);
+ pthread_cond_init (&pg->cond, 0);
+ pg->start=(my_xid *)(data + i*tc_log_page_size);
+ pg->end=(my_xid *)(pg->start + tc_log_page_size);
+ pg->size=pg->free=tc_log_page_size/sizeof(my_xid);
+ }
+ pages[0].size=pages[0].free=
+ (tc_log_page_size-TC_LOG_HEADER_SIZE)/sizeof(my_xid);
+ pages[0].start=pages[0].end-pages[0].size;
+ pages[npages-1].next=0;
+ inited=4;
+
+ if (crashed && recover())
+ goto err;
+
+ memcpy(data, tc_log_magic, sizeof(tc_log_magic));
+ data[sizeof(tc_log_magic)]= (uchar)total_ha_2pc;
+ my_msync(fd, data, tc_log_page_size, MS_SYNC);
+ inited=5;
+
+ pthread_mutex_init(&LOCK_sync, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_active, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_pool, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&COND_active, 0);
+ pthread_cond_init(&COND_pool, 0);
+
+ inited=6;
+
+ syncing= 0;
+ active=pages;
+ pool=pages+1;
+ pool_last=pages+npages-1;
+
+ return 0;
+
+err:
+ close();
+ return 1;
+}
+
+/*
+ there is no active page, let's got one from the pool
+
+ two strategies here:
+ 1. take the first from the pool
+ 2. if there're waiters - take the one with the most free space
+
+ TODO page merging. try to allocate adjacent page first,
+ so that they can be flushed both in one sync
+*/
+void TC_LOG_MMAP::get_active_from_pool()
+{
+ PAGE **p, **best_p=0;
+ int best_free;
+
+ if (syncing)
+ pthread_mutex_lock(&LOCK_pool);
+
+ do
+ {
+ best_p= p= &pool;
+ if ((*p)->waiters == 0) // can the first page be used ?
+ break; // yes - take it.
+
+ best_free=0; // no - trying second strategy
+ for (p=&(*p)->next; *p; p=&(*p)->next)
+ {
+ if ((*p)->waiters == 0 && (*p)->free > best_free)
+ {
+ best_free=(*p)->free;
+ best_p=p;
+ }
+ }
+ }
+ while ((*best_p == 0 || best_free == 0) && overflow());
+
+ active=*best_p;
+ if (active->free == active->size) // we've chosen an empty page
+ {
+ tc_log_cur_pages_used++;
+ set_if_bigger(tc_log_max_pages_used, tc_log_cur_pages_used);
+ }
+
+ if ((*best_p)->next) // unlink the page from the pool
+ *best_p=(*best_p)->next;
+ else
+ pool_last=*best_p;
+
+ if (syncing)
+ pthread_mutex_unlock(&LOCK_pool);
+}
+
+int TC_LOG_MMAP::overflow()
+{
+ /*
+ simple overflow handling - just wait
+ TODO perhaps, increase log size ?
+ let's check the behaviour of tc_log_page_waits first
+ */
+ tc_log_page_waits++;
+ pthread_cond_wait(&COND_pool, &LOCK_pool);
+ return 1; // always return 1
+}
+
+/*
+ all access to active page is serialized but it's not a problem, as
+ we're assuming that fsync() will be a main bottleneck.
+ That is, parallelizing writes to log pages we'll decrease number of
+ threads waiting for a page, but then all these threads will be waiting
+ for a fsync() anyway
+
+ RETURN
+ 0 - error
+ otherwise - "cookie", a number that will be passed as an argument
+ to unlog() call. tc_log can define it any way it wants,
+ and use for whatever purposes. TC_LOG_MMAP sets it
+ to the position in memory where xid was logged to.
+*/
+
+int TC_LOG_MMAP::log(THD *thd, my_xid xid)
+{
+ int err;
+ PAGE *p;
+ ulong cookie;
+
+ pthread_mutex_lock(&LOCK_active);
+
+ /*
+ if active page is full - just wait...
+ frankly speaking, active->free here accessed outside of mutex
+ protection, but it's safe, because it only means we may miss an
+ unlog() for the active page, and we're not waiting for it here -
+ unlog() does not signal COND_active.
+ */
+ while (unlikely(active && active->free == 0))
+ pthread_cond_wait(&COND_active, &LOCK_active);
+
+ /* no active page ? take one from the pool */
+ if (active == 0)
+ get_active_from_pool();
+
+ p=active;
+ pthread_mutex_lock(&p->lock);
+
+ /* searching for an empty slot */
+ while (*p->ptr)
+ {
+ p->ptr++;
+ DBUG_ASSERT(p->ptr < p->end); // because p->free > 0
+ }
+
+ /* found! store xid there and mark the page dirty */
+ cookie= (ulong)((uchar *)p->ptr - data); // can never be zero
+ *p->ptr++= xid;
+ p->free--;
+ p->state= DIRTY;
+
+ /* to sync or not to sync - this is the question */
+ pthread_mutex_unlock(&LOCK_active);
+ pthread_mutex_lock(&LOCK_sync);
+ pthread_mutex_unlock(&p->lock);
+
+ if (syncing)
+ { // somebody's syncing. let's wait
+ p->waiters++;
+ /*
+ note - it must be while(), not do ... while() here
+ as p->state may be not DIRTY when we come here
+ */
+ while (p->state == DIRTY && syncing)
+ pthread_cond_wait(&p->cond, &LOCK_sync);
+ p->waiters--;
+ err= p->state == ERROR;
+ if (p->state != DIRTY) // page was synced
+ {
+ if (p->waiters == 0)
+ pthread_cond_signal(&COND_pool); // in case somebody's waiting
+ pthread_mutex_unlock(&LOCK_sync);
+ goto done; // we're done
+ }
+ } // page was not synced! do it now
+ DBUG_ASSERT(active == p && syncing == 0);
+ pthread_mutex_lock(&LOCK_active);
+ syncing=p; // place is vacant - take it
+ active=0; // page is not active anymore
+ pthread_cond_broadcast(&COND_active); // in case somebody's waiting
+ pthread_mutex_unlock(&LOCK_active);
+ pthread_mutex_unlock(&LOCK_sync);
+ err= sync();
+
+done:
+ return err ? 0 : cookie;
+}
+
+int TC_LOG_MMAP::sync()
+{
+ int err;
+
+ DBUG_ASSERT(syncing != active);
+
+ /*
+ sit down and relax - this can take a while...
+ note - no locks are held at this point
+ */
+ err= my_msync(fd, syncing->start, 1, MS_SYNC);
+
+ /* page is synced. let's move it to the pool */
+ pthread_mutex_lock(&LOCK_pool);
+ pool_last->next=syncing;
+ pool_last=syncing;
+ syncing->next=0;
+ syncing->state= err ? ERROR : POOL;
+ pthread_cond_broadcast(&syncing->cond); // signal "sync done"
+ pthread_cond_signal(&COND_pool); // in case somebody's waiting
+ pthread_mutex_unlock(&LOCK_pool);
+
+ /* marking 'syncing' slot free */
+ pthread_mutex_lock(&LOCK_sync);
+ syncing=0;
+ pthread_cond_signal(&active->cond); // wake up a new syncer
+ pthread_mutex_unlock(&LOCK_sync);
+ return err;
+}
+
+/*
+ erase xid from the page, update page free space counters/pointers.
+ cookie points directly to the memory where xid was logged
+*/
+void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
+{
+ PAGE *p=pages+(cookie/tc_log_page_size);
+ my_xid *x=(my_xid *)(data+cookie);
+
+ DBUG_ASSERT(*x == xid);
+ DBUG_ASSERT(x >= p->start && x < p->end);
+ *x=0;
+
+ pthread_mutex_lock(&p->lock);
+ p->free++;
+ DBUG_ASSERT(p->free <= p->size);
+ set_if_smaller(p->ptr, x);
+ if (p->free == p->size) // the page is completely empty
+ statistic_decrement(tc_log_cur_pages_used, &LOCK_status);
+ if (p->waiters == 0) // the page is in pool and ready to rock
+ pthread_cond_signal(&COND_pool); // ping ... for overflow()
+ pthread_mutex_unlock(&p->lock);
+}
+
+void TC_LOG_MMAP::close()
+{
+ uint i;
+ switch (inited) {
+ case 6:
+ pthread_mutex_destroy(&LOCK_sync);
+ pthread_mutex_destroy(&LOCK_active);
+ pthread_mutex_destroy(&LOCK_pool);
+ pthread_cond_destroy(&COND_pool);
+ case 5:
+ data[0]='A'; // garble the first (signature) byte, in case my_delete fails
+ case 4:
+ for (i=0; i < npages; i++)
+ {
+ if (pages[i].ptr == 0)
+ break;
+ pthread_mutex_destroy(&pages[i].lock);
+ pthread_cond_destroy(&pages[i].cond);
+ }
+ case 3:
+ my_free((gptr)pages, MYF(0));
+ case 2:
+ my_munmap(data, (size_t)file_length);
+ case 1:
+ my_close(fd, MYF(0));
+ }
+ if (inited>=5) // cannot do in the switch because of Windows
+ my_delete(logname, MYF(MY_WME));
+ inited=0;
+}
+
+int TC_LOG_MMAP::recover()
+{
+ HASH xids;
+ PAGE *p=pages, *end_p=pages+npages;
+
+ if (memcmp(data, tc_log_magic, sizeof(tc_log_magic)))
+ {
+ sql_print_error("Bad magic header in tc log");
+ goto err1;
+ }
+
+ /*
+ the first byte after magic signature is set to current
+ number of storage engines on startup
+ */
+ if (data[sizeof(tc_log_magic)] != total_ha_2pc)
+ {
+ sql_print_error("Recovery failed! You must enable "
+ "exactly %d storage engines that support "
+ "two-phase commit protocol",
+ data[sizeof(tc_log_magic)]);
+ goto err1;
+ }
+
+ if (hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
+ sizeof(my_xid), 0, 0, MYF(0)))
+ goto err1;
+
+ for ( ; p < end_p ; p++)
+ {
+ for (my_xid *x=p->start; x < p->end; x++)
+ if (*x && my_hash_insert(&xids, (byte *)x))
+ goto err2; // OOM
+ }
+
+ if (ha_recover(&xids))
+ goto err2;
+
+ hash_free(&xids);
+ bzero(data, (size_t)file_length);
+ return 0;
+
+err2:
+ hash_free(&xids);
+err1:
+ sql_print_error("Crash recovery failed. Either correct the problem "
+ "(if it's, for example, out of memory error) and restart, "
+ "or delete tc log and start mysqld with "
+ "--tc-heuristic-recover={commit|rollback}");
+ return 1;
+}
+#endif
+
+TC_LOG *tc_log;
+TC_LOG_DUMMY tc_log_dummy;
+TC_LOG_MMAP tc_log_mmap;
+
+/*
+ Perform heuristic recovery, if --tc-heuristic-recover was used
+
+ RETURN VALUE
+ 0 no heuristic recovery was requested
+ 1 heuristic recovery was performed
+
+ NOTE
+ no matter whether heuristic recovery was successful or not
+ mysqld must exit. So, return value is the same in both cases.
+*/
+
+int TC_LOG::using_heuristic_recover()
+{
+ if (!tc_heuristic_recover)
+ return 0;
+
+ sql_print_information("Heuristic crash recovery mode");
+ if (ha_recover(0))
+ sql_print_error("Heuristic crash recovery failed");
+ sql_print_information("Please restart mysqld without --tc-heuristic-recover");
+ return 1;
+}
+
+/****** transaction coordinator log for 2pc - binlog() based solution ******/
+#define TC_LOG_BINLOG MYSQL_LOG
+
+/*
+ TODO keep in-memory list of prepared transactions
+ (add to list in log(), remove on unlog())
+ and copy it to the new binlog if rotated
+ but let's check the behaviour of tc_log_page_waits first!
+*/
+
+int TC_LOG_BINLOG::open(const char *opt_name)
+{
+ LOG_INFO log_info;
+ int error= 1;
+
+ DBUG_ASSERT(total_ha_2pc > 1);
+ DBUG_ASSERT(opt_name && opt_name[0]);
+
+ pthread_mutex_init(&LOCK_prep_xids, MY_MUTEX_INIT_FAST);
+ pthread_cond_init (&COND_prep_xids, 0);
+
+ if (!my_b_inited(&index_file))
+ {
+ /* There was a failure to open the index file, can't open the binlog */
+ cleanup();
+ return 1;
+ }
+
+ if (using_heuristic_recover())
+ {
+ /* generate a new binlog to mask a corrupted one */
+ open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0);
+ cleanup();
+ return 1;
+ }
+
+ if ((error= find_log_pos(&log_info, NullS, 1)))
+ {
+ if (error != LOG_INFO_EOF)
+ sql_print_error("find_log_pos() failed (error: %d)", error);
+ else
+ error= 0;
+ goto err;
+ }
+
+ {
+ const char *errmsg;
+ IO_CACHE log;
+ File file;
+ Log_event *ev=0;
+ Format_description_log_event fdle(BINLOG_VERSION);
+ char log_name[FN_REFLEN];
+
+ if (! fdle.is_valid())
+ goto err;
+
+ do
+ {
+ strmake(log_name, log_info.log_file_name, sizeof(log_name)-1);
+ } while (!(error= find_next_log(&log_info, 1)));
+
+ if (error != LOG_INFO_EOF)
+ {
+ sql_print_error("find_log_pos() failed (error: %d)", error);
+ goto err;
+ }
+
+ if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
+ {
+ sql_print_error("%s", errmsg);
+ goto err;
+ }
+
+ if ((ev= Log_event::read_log_event(&log, 0, &fdle)) &&
+ ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
+ ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
+ {
+ sql_print_information("Recovering after a crash using %s", opt_name);
+ error= recover(&log, (Format_description_log_event *)ev);
+ }
+ else
+ error=0;
+
+ delete ev;
+ end_io_cache(&log);
+ my_close(file, MYF(MY_WME));
+
+ if (error)
+ goto err;
+ }
+
+err:
+ return error;
+}
+
+/* this is called on shutdown, after ha_panic */
+void TC_LOG_BINLOG::close()
+{
+ DBUG_ASSERT(prepared_xids==0);
+ pthread_mutex_destroy(&LOCK_prep_xids);
+ pthread_cond_destroy (&COND_prep_xids);
+}
+
+/*
+ TODO group commit
+
+ RETURN
+ 0 - error
+ 1 - success
+*/
+int TC_LOG_BINLOG::log(THD *thd, my_xid xid)
+{
+ Xid_log_event xle(thd, xid);
+ IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
+ return !binlog_end_trans(thd, trans_log, &xle); // invert return value
+}
+
+void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
+{
+ pthread_mutex_lock(&LOCK_prep_xids);
+ if (--prepared_xids == 0)
+ pthread_cond_signal(&COND_prep_xids);
+ pthread_mutex_unlock(&LOCK_prep_xids);
+ rotate_and_purge(0); // as ::write() did not rotate
+}
+
+int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
+{
+ Log_event *ev;
+ HASH xids;
+ MEM_ROOT mem_root;
+
+ if (! fdle->is_valid() ||
+ hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
+ sizeof(my_xid), 0, 0, MYF(0)))
+ goto err1;
+
+ init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
+
+ fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
+
+ while ((ev= Log_event::read_log_event(log,0,fdle)) && ev->is_valid())
+ {
+ if (ev->get_type_code() == XID_EVENT)
+ {
+ Xid_log_event *xev=(Xid_log_event *)ev;
+ byte *x=(byte *)memdup_root(&mem_root, (char *)& xev->xid,
+ sizeof(xev->xid));
+ if (! x)
+ goto err2;
+ my_hash_insert(&xids, x);
+ }
+ delete ev;
+ }
+
+ if (ha_recover(&xids))
+ goto err2;
+
+ free_root(&mem_root, MYF(0));
+ hash_free(&xids);
+ return 0;
+
+err2:
+ free_root(&mem_root, MYF(0));
+ hash_free(&xids);
+err1:
+ sql_print_error("Crash recovery failed. Either correct the problem "
+ "(if it's, for example, out of memory error) and restart, "
+ "or delete (or rename) binary log and start mysqld with "
+ "--tc-heuristic-recover={commit|rollback}");
+ return 1;
+}
+
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 8a949b81fc1..86d31a9c2e8 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -180,10 +180,12 @@ static void cleanup_load_tmpdir()
write_str()
*/
-static bool write_str(IO_CACHE *file, char *str, byte length)
+static bool write_str(IO_CACHE *file, char *str, uint length)
{
- return (my_b_safe_write(file, &length, 1) ||
- my_b_safe_write(file, (byte*) str, (int) length));
+ byte tmp[1];
+ tmp[0]= (byte) length;
+ return (my_b_safe_write(file, tmp, sizeof(tmp)) ||
+ my_b_safe_write(file, (byte*) str, length));
}
@@ -191,17 +193,18 @@ static bool write_str(IO_CACHE *file, char *str, byte length)
read_str()
*/
-static inline int read_str(char * &buf, char *buf_end, char * &str,
- uint8 &len)
+static inline int read_str(char **buf, char *buf_end, char **str,
+ uint8 *len)
{
- if (buf + (uint) (uchar) *buf >= buf_end)
+ if (*buf + ((uint) (uchar) **buf) >= buf_end)
return 1;
- len = (uint8) *buf;
- str= buf+1;
- buf+= (uint) len+1;
+ *len= (uint8) **buf;
+ *str= (*buf)+1;
+ (*buf)+= (uint) *len+1;
return 0;
}
+
/*
Transforms a string into "" or its expression in 0x... form.
*/
@@ -225,9 +228,25 @@ static char *str_to_hex(char *to, char *from, uint len)
return p; // pointer to end 0 of 'to'
}
+/*
+ Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
+ commands just before it prints a query.
+*/
+
+static void print_set_option(FILE* file, uint32 bits_changed, uint32 option,
+ uint32 flags, const char* name, bool* need_comma)
+{
+ if (bits_changed & option)
+ {
+ if (*need_comma)
+ fprintf(file,", ");
+ fprintf(file,"%s=%d", name, (bool)(flags & option));
+ *need_comma= 1;
+ }
+}
/**************************************************************************
- Log_event methods
+ Log_event methods (= the parent class of all events)
**************************************************************************/
/*
@@ -237,7 +256,7 @@ static char *str_to_hex(char *to, char *from, uint len)
const char* Log_event::get_type_str()
{
switch(get_type_code()) {
- case START_EVENT: return "Start";
+ case START_EVENT_V3: return "Start_v3";
case STOP_EVENT: return "Stop";
case QUERY_EVENT: return "Query";
case ROTATE_EVENT: return "Rotate";
@@ -250,8 +269,12 @@ const char* Log_event::get_type_str()
case DELETE_FILE_EVENT: return "Delete_file";
case EXEC_LOAD_EVENT: return "Exec_load";
case RAND_EVENT: return "RAND";
+ case XID_EVENT: return "Xid";
case USER_VAR_EVENT: return "User var";
- default: return "Unknown"; /* impossible */
+ case FORMAT_DESCRIPTION_EVENT: return "Format_desc";
+ case BEGIN_LOAD_QUERY_EVENT: return "Begin_load_query";
+ case EXECUTE_LOAD_QUERY_EVENT: return "Execute_load_query";
+ default: return "Unknown"; /* impossible */
}
}
@@ -262,25 +285,23 @@ const char* Log_event::get_type_str()
#ifndef MYSQL_CLIENT
Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
- :log_pos(0), temp_buf(0), exec_time(0), cached_event_len(0),
- flags(flags_arg), thd(thd_arg)
+ :log_pos(0), temp_buf(0), exec_time(0), flags(flags_arg), thd(thd_arg)
{
server_id= thd->server_id;
when= thd->start_time;
- cache_stmt= (using_trans &&
- (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)));
+ cache_stmt= using_trans;
}
/*
- This minimal constructor is for when you are not even sure that there is a
- valid THD. For example in the server when we are shutting down or flushing
- logs after receiving a SIGHUP (then we must write a Rotate to the binlog but
- we have no THD, so we need this minimal constructor).
+ This minimal constructor is for when you are not even sure that there
+ is a valid THD. For example in the server when we are shutting down or
+ flushing logs after receiving a SIGHUP (then we must write a Rotate to
+ the binlog but we have no THD, so we need this minimal constructor).
*/
Log_event::Log_event()
- :temp_buf(0), exec_time(0), cached_event_len(0), flags(0), cache_stmt(0),
+ :temp_buf(0), exec_time(0), flags(0), cache_stmt(0),
thd(0)
{
server_id= ::server_id;
@@ -294,24 +315,71 @@ Log_event::Log_event()
Log_event::Log_event()
*/
-Log_event::Log_event(const char* buf, bool old_format)
- :temp_buf(0), cached_event_len(0), cache_stmt(0)
+Log_event::Log_event(const char* buf,
+ const Format_description_log_event* description_event)
+ :temp_buf(0), cache_stmt(0)
{
+#ifndef MYSQL_CLIENT
+ thd = 0;
+#endif
when = uint4korr(buf);
server_id = uint4korr(buf + SERVER_ID_OFFSET);
- if (old_format)
+ if (description_event->binlog_version==1)
{
- log_pos=0;
- flags=0;
+ log_pos= 0;
+ flags= 0;
+ return;
}
- else
+ /* 4.0 or newer */
+ log_pos= uint4korr(buf + LOG_POS_OFFSET);
+ /*
+ If the log is 4.0 (so here it can only be a 4.0 relay log read by
+ the SQL thread or a 4.0 master binlog read by the I/O thread),
+ log_pos is the beginning of the event: we transform it into the end
+ of the event, which is more useful.
+ But how do you know that the log is 4.0: you know it if
+ description_event is version 3 *and* you are not reading a
+ Format_desc (remember that mysqlbinlog starts by assuming that 5.0
+ logs are in 4.0 format, until it finds a Format_desc).
+ */
+ if (description_event->binlog_version==3 &&
+ buf[EVENT_TYPE_OFFSET]<FORMAT_DESCRIPTION_EVENT && log_pos)
{
- log_pos = uint4korr(buf + LOG_POS_OFFSET);
- flags = uint2korr(buf + FLAGS_OFFSET);
+ /*
+ If log_pos=0, don't change it. log_pos==0 is a marker to mean
+ "don't change rli->group_master_log_pos" (see
+ inc_group_relay_log_pos()). As it is unreal log_pos, adding the
+ event len's is nonsense. For example, a fake Rotate event should
+ not have its log_pos (which is 0) changed or it will modify
+ Exec_master_log_pos in SHOW SLAVE STATUS, displaying a nonsense
+ value of (a non-zero offset which does not exist in the master's
+ binlog, so which will cause problems if the user uses this value
+ in CHANGE MASTER).
+ */
+ log_pos+= uint4korr(buf + EVENT_LEN_OFFSET);
}
-#ifndef MYSQL_CLIENT
- thd = 0;
-#endif
+ DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
+
+ flags= uint2korr(buf + FLAGS_OFFSET);
+ if ((buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT) ||
+ (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT))
+ {
+ /*
+ These events always have a header which stops here (i.e. their
+ header is FROZEN).
+ */
+ /*
+ Initialization to zero of all other Log_event members as they're
+ not specified. Currently there are no such members; in the future
+ there will be an event UID (but Format_description and Rotate
+ don't need this UID, as they are not propagated through
+ --log-slave-updates (remember the UID is used to not play a query
+ twice when you have two masters which are slaves of a 3rd master).
+ Then we are done.
+ */
+ return;
+ }
+ /* otherwise, go on with reading the header from buf (nothing now) */
}
#ifndef MYSQL_CLIENT
@@ -337,41 +405,42 @@ int Log_event::exec_event(struct st_relay_log_info* rli)
only in the case discussed above, 'if (rli)' is useless here.
But as we are not 100% sure, keep it for now.
*/
- if (rli)
+ if (rli)
{
/*
- If in a transaction, and if the slave supports transactions,
- just inc_event_relay_log_pos(). We only have to check for OPTION_BEGIN
- (not OPTION_NOT_AUTOCOMMIT) as transactions are logged
- with BEGIN/COMMIT, not with SET AUTOCOMMIT= .
-
+ If in a transaction, and if the slave supports transactions, just
+ inc_event_relay_log_pos(). We only have to check for OPTION_BEGIN
+ (not OPTION_NOT_AUTOCOMMIT) as transactions are logged with
+ BEGIN/COMMIT, not with SET AUTOCOMMIT= .
+
CAUTION: opt_using_transactions means
- innodb || bdb ; suppose the master supports InnoDB and BDB,
+ innodb || bdb ; suppose the master supports InnoDB and BDB,
but the slave supports only BDB, problems
- will arise:
+ will arise:
- suppose an InnoDB table is created on the master,
- then it will be MyISAM on the slave
- - but as opt_using_transactions is true, the slave will believe he is
- transactional with the MyISAM table. And problems will come when one
- does START SLAVE; STOP SLAVE; START SLAVE; (the slave will resume at
- BEGIN whereas there has not been any rollback). This is the problem of
- using opt_using_transactions instead of a finer
- "does the slave support _the_transactional_handler_used_on_the_master_".
-
- More generally, we'll have problems when a query mixes a transactional
- handler and MyISAM and STOP SLAVE is issued in the middle of the
- "transaction". START SLAVE will resume at BEGIN while the MyISAM table
- has already been updated.
+ - but as opt_using_transactions is true, the slave will believe he
+ is transactional with the MyISAM table. And problems will come
+ when one does START SLAVE; STOP SLAVE; START SLAVE; (the slave
+ will resume at BEGIN whereas there has not been any rollback).
+ This is the problem of using opt_using_transactions instead of a
+ finer "does the slave support
+ _the_transactional_handler_used_on_the_master_".
+
+ More generally, we'll have problems when a query mixes a
+ transactional handler and MyISAM and STOP SLAVE is issued in the
+ middle of the "transaction". START SLAVE will resume at BEGIN
+ while the MyISAM table has already been updated.
*/
if ((thd->options & OPTION_BEGIN) && opt_using_transactions)
- rli->inc_event_relay_log_pos(get_event_len());
+ rli->inc_event_relay_log_pos();
else
{
- rli->inc_group_relay_log_pos(get_event_len(),log_pos);
+ rli->inc_group_relay_log_pos(log_pos);
flush_relay_log_info(rli);
/*
- Note that Rotate_log_event::exec_event() does not call this function,
- so there is no chance that a fake rotate event resets
+ Note that Rotate_log_event::exec_event() does not call this
+ function, so there is no chance that a fake rotate event resets
last_master_timestamp.
Note that we update without mutex (probably ok - except in some very
rare cases, only consequence is that value may take some time to
@@ -432,58 +501,101 @@ void Log_event::init_show_field_list(List<Item>* field_list)
field_list->push_back(new Item_empty_string("Event_type", 20));
field_list->push_back(new Item_return_int("Server_id", 10,
MYSQL_TYPE_LONG));
- field_list->push_back(new Item_return_int("Orig_log_pos", 11,
+ field_list->push_back(new Item_return_int("End_log_pos", 11,
MYSQL_TYPE_LONGLONG));
field_list->push_back(new Item_empty_string("Info", 20));
}
-#endif /* !MYSQL_CLIENT */
/*
Log_event::write()
*/
-int Log_event::write(IO_CACHE* file)
+bool Log_event::write_header(IO_CACHE* file, ulong event_data_length)
{
- return (write_header(file) || write_data(file)) ? -1 : 0;
-}
+ byte header[LOG_EVENT_HEADER_LEN];
+ DBUG_ENTER("Log_event::write_header");
+ /* Store number of bytes that will be written by this event */
+ data_written= event_data_length + sizeof(header);
-/*
- Log_event::write_header()
-*/
+ /*
+ log_pos != 0 if this is relay-log event. In this case we should not
+ change the position
+ */
-int Log_event::write_header(IO_CACHE* file)
-{
- char buf[LOG_EVENT_HEADER_LEN];
- char* pos = buf;
- int4store(pos, (ulong) when); // timestamp
- pos += 4;
- *pos++ = get_type_code(); // event type code
- int4store(pos, server_id);
- pos += 4;
- long tmp=get_data_size() + LOG_EVENT_HEADER_LEN;
- int4store(pos, tmp);
- pos += 4;
- int4store(pos, log_pos);
- pos += 4;
- int2store(pos, flags);
- pos += 2;
- return (my_b_safe_write(file, (byte*) buf, (uint) (pos - buf)));
+ if (is_artificial_event())
+ {
+ /*
+ We should not do any cleanup on slave when reading this. We
+ mark this by setting log_pos to 0. Start_log_event_v3() will
+ detect this on reading and set artificial_event=1 for the event.
+ */
+ log_pos= 0;
+ }
+ else if (!log_pos)
+ {
+ /*
+ Calculate position of end of event
+
+ Note that with a SEQ_READ_APPEND cache, my_b_tell() does not
+ work well. So this will give slightly wrong positions for the
+ Format_desc/Rotate/Stop events which the slave writes to its
+ relay log. For example, the initial Format_desc will have
+ end_log_pos=91 instead of 95. Because after writing the first 4
+ bytes of the relay log, my_b_tell() still reports 0. Because
+ my_b_append() does not update the counter which my_b_tell()
+ later uses (one should probably use my_b_append_tell() to work
+ around this). To get right positions even when writing to the
+ relay log, we use the (new) my_b_safe_tell().
+
+ Note that this raises a question on the correctness of all these
+ DBUG_ASSERT(my_b_tell()=rli->event_relay_log_pos).
+
+ If in a transaction, the log_pos which we calculate below is not
+ very good (because then my_b_safe_tell() returns start position
+ of the BEGIN, so it's like the statement was at the BEGIN's
+ place), but it's not a very serious problem (as the slave, when
+ it is in a transaction, does not take those end_log_pos into
+ account (as it calls inc_event_relay_log_pos()). To be fixed
+ later, so that it looks less strange. But not bug.
+ */
+
+ log_pos= my_b_safe_tell(file)+data_written;
+ }
+
+ /*
+ Header will be of size LOG_EVENT_HEADER_LEN for all events, except for
+ FORMAT_DESCRIPTION_EVENT and ROTATE_EVENT, where it will be
+ LOG_EVENT_MINIMAL_HEADER_LEN (remember these 2 have a frozen header,
+ because we read them before knowing the format).
+ */
+
+ int4store(header, (ulong) when); // timestamp
+ header[EVENT_TYPE_OFFSET]= get_type_code();
+ int4store(header+ SERVER_ID_OFFSET, server_id);
+ int4store(header+ EVENT_LEN_OFFSET, data_written);
+ int4store(header+ LOG_POS_OFFSET, log_pos);
+ int2store(header+ FLAGS_OFFSET, flags);
+
+ DBUG_RETURN(my_b_safe_write(file, header, sizeof(header)) != 0);
}
/*
Log_event::read_log_event()
+
+ This needn't be format-tolerant, because we only read
+ LOG_EVENT_MINIMAL_HEADER_LEN (we just want to read the event's length).
+
*/
-#ifndef MYSQL_CLIENT
int Log_event::read_log_event(IO_CACHE* file, String* packet,
pthread_mutex_t* log_lock)
{
ulong data_len;
int result=0;
- char buf[LOG_EVENT_HEADER_LEN];
+ char buf[LOG_EVENT_MINIMAL_HEADER_LEN];
DBUG_ENTER("read_log_event");
if (log_lock)
@@ -503,24 +615,25 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
goto end;
}
data_len= uint4korr(buf + EVENT_LEN_OFFSET);
- if (data_len < LOG_EVENT_HEADER_LEN ||
+ if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN ||
data_len > current_thd->variables.max_allowed_packet)
{
DBUG_PRINT("error",("data_len: %ld", data_len));
- result= ((data_len < LOG_EVENT_HEADER_LEN) ? LOG_READ_BOGUS :
+ result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS :
LOG_READ_TOO_LARGE);
goto end;
}
packet->append(buf, sizeof(buf));
- data_len-= LOG_EVENT_HEADER_LEN;
+ data_len-= LOG_EVENT_MINIMAL_HEADER_LEN;
if (data_len)
{
if (packet->append(file, data_len))
{
/*
- Here we should never hit EOF in a non-error condition.
+ Here if we hit EOF it's really an error: as data_len is >=0
+ there's supposed to be more bytes available.
EOF means we are reading the event partially, which should
- never happen.
+ never happen: either we read badly or the binlog is truncated.
*/
result= file->error >= 0 ? LOG_READ_TRUNC: LOG_READ_IO;
/* Implicit goto end; */
@@ -537,42 +650,63 @@ end:
#ifndef MYSQL_CLIENT
#define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock);
#define LOCK_MUTEX if (log_lock) pthread_mutex_lock(log_lock);
-#define max_allowed_packet current_thd->variables.max_allowed_packet
#else
#define UNLOCK_MUTEX
#define LOCK_MUTEX
-#define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet)
#endif
/*
Log_event::read_log_event()
NOTE:
- Allocates memory; The caller is responsible for clean-up
+ Allocates memory; The caller is responsible for clean-up.
*/
#ifndef MYSQL_CLIENT
Log_event* Log_event::read_log_event(IO_CACHE* file,
pthread_mutex_t* log_lock,
- bool old_format)
+ const Format_description_log_event *description_event)
#else
-Log_event* Log_event::read_log_event(IO_CACHE* file, bool old_format)
-#endif
+Log_event* Log_event::read_log_event(IO_CACHE* file,
+ const Format_description_log_event *description_event)
+#endif
{
- char head[LOG_EVENT_HEADER_LEN];
- uint header_size= old_format ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
+ DBUG_ENTER("Log_event::read_log_event(IO_CACHE *, Format_description_log_event *");
+ DBUG_ASSERT(description_event != 0);
+ char head[LOG_EVENT_MINIMAL_HEADER_LEN];
+ /*
+ First we only want to read at most LOG_EVENT_MINIMAL_HEADER_LEN, just to
+ check the event for sanity and to know its length; no need to really parse
+ it. We say "at most" because this could be a 3.23 master, which has header
+ of 13 bytes, whereas LOG_EVENT_MINIMAL_HEADER_LEN is 19 bytes (it's
+ "minimal" over the set {MySQL >=4.0}).
+ */
+ uint header_size= min(description_event->common_header_len,
+ LOG_EVENT_MINIMAL_HEADER_LEN);
LOCK_MUTEX;
+ DBUG_PRINT("info", ("my_b_tell=%lu", my_b_tell(file)));
if (my_b_read(file, (byte *) head, header_size))
{
+ DBUG_PRINT("info", ("Log_event::read_log_event(IO_CACHE*,Format_desc*) \
+failed my_b_read"));
UNLOCK_MUTEX;
- return 0;
+ /*
+ No error here; it could be that we are at the file's end. However
+ if the next my_b_read() fails (below), it will be an error as we
+ were able to read the first bytes.
+ */
+ DBUG_RETURN(0);
}
uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
char *buf= 0;
const char *error= 0;
Log_event *res= 0;
+#ifndef max_allowed_packet
+ THD *thd=current_thd;
+ uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~0;
+#endif
if (data_len > max_allowed_packet)
{
@@ -599,15 +733,16 @@ Log_event* Log_event::read_log_event(IO_CACHE* file, bool old_format)
error = "read error";
goto err;
}
- if ((res = read_log_event(buf, data_len, &error, old_format)))
+ if ((res= read_log_event(buf, data_len, &error, description_event)))
res->register_temp_buf(buf);
err:
UNLOCK_MUTEX;
- if (error)
+ if (!res)
{
- sql_print_error("\
-Error in Log_event::read_log_event(): '%s', data_len: %d, event_type: %d",
+ DBUG_ASSERT(error != 0);
+ sql_print_error("Error in Log_event::read_log_event(): "
+ "'%s', data_len: %d, event_type: %d",
error,data_len,head[EVENT_TYPE_OFFSET]);
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
/*
@@ -620,94 +755,120 @@ Error in Log_event::read_log_event(): '%s', data_len: %d, event_type: %d",
*/
file->error= -1;
}
- return res;
+ DBUG_RETURN(res);
}
/*
Log_event::read_log_event()
+ Binlog format tolerance is in (buf, event_len, description_event)
+ constructors.
*/
-Log_event* Log_event::read_log_event(const char* buf, int event_len,
- const char **error, bool old_format)
+Log_event* Log_event::read_log_event(const char* buf, uint event_len,
+ const char **error,
+ const Format_description_log_event *description_event)
{
- DBUG_ENTER("Log_event::read_log_event");
-
+ Log_event* ev;
+ DBUG_ENTER("Log_event::read_log_event(char*,...)");
+ DBUG_ASSERT(description_event != 0);
+ DBUG_PRINT("info", ("binlog_version: %d", description_event->binlog_version));
if (event_len < EVENT_LEN_OFFSET ||
(uint) event_len != uint4korr(buf+EVENT_LEN_OFFSET))
{
*error="Sanity check failed"; // Needed to free buffer
DBUG_RETURN(NULL); // general sanity check - will fail on a partial read
}
-
- Log_event* ev = NULL;
-
+
switch(buf[EVENT_TYPE_OFFSET]) {
case QUERY_EVENT:
- ev = new Query_log_event(buf, event_len, old_format);
+ ev = new Query_log_event(buf, event_len, description_event, QUERY_EVENT);
break;
case LOAD_EVENT:
- ev = new Create_file_log_event(buf, event_len, old_format);
+ ev = new Load_log_event(buf, event_len, description_event);
break;
case NEW_LOAD_EVENT:
- ev = new Load_log_event(buf, event_len, old_format);
+ ev = new Load_log_event(buf, event_len, description_event);
break;
case ROTATE_EVENT:
- ev = new Rotate_log_event(buf, event_len, old_format);
+ ev = new Rotate_log_event(buf, event_len, description_event);
break;
#ifdef HAVE_REPLICATION
- case SLAVE_EVENT:
+ case SLAVE_EVENT: /* can never happen (unused event) */
ev = new Slave_log_event(buf, event_len);
break;
#endif /* HAVE_REPLICATION */
case CREATE_FILE_EVENT:
- ev = new Create_file_log_event(buf, event_len, old_format);
+ ev = new Create_file_log_event(buf, event_len, description_event);
break;
case APPEND_BLOCK_EVENT:
- ev = new Append_block_log_event(buf, event_len);
+ ev = new Append_block_log_event(buf, event_len, description_event);
break;
case DELETE_FILE_EVENT:
- ev = new Delete_file_log_event(buf, event_len);
+ ev = new Delete_file_log_event(buf, event_len, description_event);
break;
case EXEC_LOAD_EVENT:
- ev = new Execute_load_log_event(buf, event_len);
+ ev = new Execute_load_log_event(buf, event_len, description_event);
break;
- case START_EVENT:
- ev = new Start_log_event(buf, old_format);
+ case START_EVENT_V3: /* this is sent only by MySQL <=4.x */
+ ev = new Start_log_event_v3(buf, description_event);
break;
-#ifdef HAVE_REPLICATION
case STOP_EVENT:
- ev = new Stop_log_event(buf, old_format);
+ ev = new Stop_log_event(buf, description_event);
break;
-#endif /* HAVE_REPLICATION */
case INTVAR_EVENT:
- ev = new Intvar_log_event(buf, old_format);
+ ev = new Intvar_log_event(buf, description_event);
+ break;
+ case XID_EVENT:
+ ev = new Xid_log_event(buf, description_event);
break;
case RAND_EVENT:
- ev = new Rand_log_event(buf, old_format);
+ ev = new Rand_log_event(buf, description_event);
break;
case USER_VAR_EVENT:
- ev = new User_var_log_event(buf, old_format);
+ ev = new User_var_log_event(buf, description_event);
+ break;
+ case FORMAT_DESCRIPTION_EVENT:
+ ev = new Format_description_log_event(buf, event_len, description_event);
+ break;
+ case BEGIN_LOAD_QUERY_EVENT:
+ ev = new Begin_load_query_log_event(buf, event_len, description_event);
+ break;
+ case EXECUTE_LOAD_QUERY_EVENT:
+ ev = new Execute_load_query_log_event(buf, event_len, description_event);
break;
default:
+ DBUG_PRINT("error",("Unknown evernt code: %d",(int) buf[EVENT_TYPE_OFFSET]));
+ ev= NULL;
break;
}
+
+ /*
+ is_valid() are small event-specific sanity tests which are
+ important; for example there are some my_malloc() in constructors
+ (e.g. Query_log_event::Query_log_event(char*...)); when these
+ my_malloc() fail we can't return an error out of the constructor
+ (because constructor is "void") ; so instead we leave the pointer we
+ wanted to allocate (e.g. 'query') to 0 and we test it in is_valid().
+ Same for Format_description_log_event, member 'post_header_len'.
+ */
if (!ev || !ev->is_valid())
{
+ DBUG_PRINT("error",("Found invalid event in binary log"));
+
delete ev;
#ifdef MYSQL_CLIENT
- if (!force_opt)
+ if (!force_opt) /* then mysqlbinlog dies */
{
*error= "Found invalid event in binary log";
DBUG_RETURN(0);
}
- ev= new Unknown_log_event(buf, old_format);
+ ev= new Unknown_log_event(buf, description_event);
#else
*error= "Found invalid event in binary log";
DBUG_RETURN(0);
#endif
}
- ev->cached_event_len = event_len;
DBUG_RETURN(ev);
}
@@ -722,7 +883,7 @@ void Log_event::print_header(FILE* file)
char llbuff[22];
fputc('#', file);
print_timestamp(file);
- fprintf(file, " server id %d log_pos %s ", server_id,
+ fprintf(file, " server id %d end_log_pos %s ", server_id,
llstr(log_pos,llbuff));
}
@@ -754,19 +915,6 @@ void Log_event::print_timestamp(FILE* file, time_t* ts)
#endif /* MYSQL_CLIENT */
-/*
- Log_event::set_log_pos()
-*/
-
-#ifndef MYSQL_CLIENT
-void Log_event::set_log_pos(MYSQL_LOG* log)
-{
- if (!log_pos)
- log_pos = my_b_tell(&log->log_file);
-}
-#endif /* !MYSQL_CLIENT */
-
-
/**************************************************************************
Query_log_event methods
**************************************************************************/
@@ -775,15 +923,20 @@ void Log_event::set_log_pos(MYSQL_LOG* log)
/*
Query_log_event::pack_info()
+ This (which is used only for SHOW BINLOG EVENTS) could be updated to
+ print SET @@session_var=. But this is not urgent, as SHOW BINLOG EVENTS is
+ only an information, it does not produce suitable queries to replay (for
+ example it does not print LOAD DATA INFILE).
*/
void Query_log_event::pack_info(Protocol *protocol)
{
+ // TODO: show the catalog ??
char *buf, *pos;
if (!(buf= my_malloc(9 + db_len + q_len, MYF(MY_WME))))
return;
- pos= buf;
- if (!(flags & LOG_EVENT_SUPPRESS_USE_F)
+ pos= buf;
+ if (!(flags & LOG_EVENT_SUPPRESS_USE_F)
&& db && db_len)
{
pos= strmov(buf, "use `");
@@ -800,34 +953,38 @@ void Query_log_event::pack_info(Protocol *protocol)
}
#endif
+#ifndef MYSQL_CLIENT
/*
Query_log_event::write()
-*/
-int Query_log_event::write(IO_CACHE* file)
-{
- return query ? Log_event::write(file) : -1;
-}
-
-
-/*
- Query_log_event::write_data()
+ NOTES:
+ In this event we have to modify the header to have the correct
+ EVENT_LEN_OFFSET as we don't yet know how many status variables we
+ will print!
*/
-int Query_log_event::write_data(IO_CACHE* file)
+bool Query_log_event::write(IO_CACHE* file)
{
- char buf[QUERY_HEADER_LEN];
+ uchar buf[QUERY_HEADER_LEN+
+ 1+4+ // code of flags2 and flags2
+ 1+8+ // code of sql_mode and sql_mode
+ 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog
+ 1+4+ // code of autoinc and the 2 autoinc variables
+ 1+6+ // code of charset and charset
+ 1+1+MAX_TIME_ZONE_NAME_LENGTH // code of tz and tz length and tz name
+ ], *start, *start_of_status;
+ ulong event_length;
if (!query)
- return -1;
-
+ return 1; // Something wrong with event
+
/*
We want to store the thread id:
(- as an information for the user when he reads the binlog)
- if the query uses temporary table: for the slave SQL thread to know to
which master connection the temp table belongs.
- Now imagine we (write_data()) are called by the slave SQL thread (we are
+ Now imagine we (write()) are called by the slave SQL thread (we are
logging a query executed by this thread; the slave runs with
--log-slave-updates). Then this query will be logged with
thread_id=the_thread_id_of_the_SQL_thread. Imagine that 2 temp tables of
@@ -864,78 +1021,320 @@ int Query_log_event::write_data(IO_CACHE* file)
buf[Q_DB_LEN_OFFSET] = (char) db_len;
int2store(buf + Q_ERR_CODE_OFFSET, error_code);
- return (my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) ||
- my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
- my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0;
+ /*
+ You MUST always write status vars in increasing order of code. This
+ guarantees that a slightly older slave will be able to parse those he
+ knows.
+ */
+ start_of_status= start= buf+QUERY_HEADER_LEN;
+ if (flags2_inited)
+ {
+ *start++= Q_FLAGS2_CODE;
+ int4store(start, flags2);
+ start+= 4;
+ }
+ if (sql_mode_inited)
+ {
+ *start++= Q_SQL_MODE_CODE;
+ int8store(start, (ulonglong)sql_mode);
+ start+= 8;
+ }
+ if (catalog_len) // i.e. "catalog inited" (false for 4.0 events)
+ {
+ *start++= Q_CATALOG_NZ_CODE;
+ *start++= (uchar) catalog_len;
+ bmove(start, catalog, catalog_len);
+ start+= catalog_len;
+ /*
+ In 5.0.x where x<4 masters we used to store the end zero here. This was
+ a waste of one byte so we don't do it in x>=4 masters. We change code to
+ Q_CATALOG_NZ_CODE, because re-using the old code would make x<4 slaves
+ of this x>=4 master segfault (expecting a zero when there is
+ none). Remaining compatibility problems are: the older slave will not
+ find the catalog; but it is will not crash, and it's not an issue
+ that it does not find the catalog as catalogs were not used in these
+ older MySQL versions (we store it in binlog and read it from relay log
+ but do nothing useful with it). What is an issue is that the older slave
+ will stop processing the Q_* blocks (and jumps to the db/query) as soon
+ as it sees unknown Q_CATALOG_NZ_CODE; so it will not be able to read
+ Q_AUTO_INCREMENT*, Q_CHARSET and so replication will fail silently in
+ various ways. Documented that you should not mix alpha/beta versions if
+ they are not exactly the same version, with example of 5.0.3->5.0.2 and
+ 5.0.4->5.0.3. If replication is from older to new, the new will
+ recognize Q_CATALOG_CODE and have no problem.
+ */
+ }
+ if (auto_increment_increment != 1)
+ {
+ *start++= Q_AUTO_INCREMENT;
+ int2store(start, auto_increment_increment);
+ int2store(start+2, auto_increment_offset);
+ start+= 4;
+ }
+ if (charset_inited)
+ {
+ *start++= Q_CHARSET_CODE;
+ memcpy(start, charset, 6);
+ start+= 6;
+ }
+ if (time_zone_len)
+ {
+ /* In the TZ sys table, column Name is of length 64 so this should be ok */
+ DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
+ *start++= Q_TIME_ZONE_CODE;
+ *start++= time_zone_len;
+ memcpy(start, time_zone_str, time_zone_len);
+ start+= time_zone_len;
+ }
+ /*
+ Here there could be code like
+ if (command-line-option-which-says-"log_this_variable" && inited)
+ {
+ *start++= Q_THIS_VARIABLE_CODE;
+ int4store(start, this_variable);
+ start+= 4;
+ }
+ */
+
+ /* Store length of status variables */
+ status_vars_len= (uint) (start-start_of_status);
+ int2store(buf + Q_STATUS_VARS_LEN_OFFSET, status_vars_len);
+
+ /*
+ Calculate length of whole event
+ The "1" below is the \0 in the db's length
+ */
+ event_length= (uint) (start-buf) + get_post_header_size_for_derived() + db_len + 1 + q_len;
+
+ return (write_header(file, event_length) ||
+ my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) ||
+ write_post_header_for_derived(file) ||
+ my_b_safe_write(file, (byte*) start_of_status,
+ (uint) (start-start_of_status)) ||
+ my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
+ my_b_safe_write(file, (byte*) query, q_len)) ? 1 : 0;
}
/*
Query_log_event::Query_log_event()
*/
-
-#ifndef MYSQL_CLIENT
Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
ulong query_length, bool using_trans,
bool suppress_use)
- :Log_event(thd_arg,
+ :Log_event(thd_arg,
((thd_arg->tmp_table_used ? LOG_EVENT_THREAD_SPECIFIC_F : 0)
| (suppress_use ? LOG_EVENT_SUPPRESS_USE_F : 0)),
using_trans),
- data_buf(0), query(query_arg),
+ data_buf(0), query(query_arg), catalog(thd_arg->catalog),
db(thd_arg->db), q_len((uint32) query_length),
- error_code(thd_arg->killed ?
+ error_code((thd_arg->killed != THD::NOT_KILLED) ?
((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ?
- 0 : ER_SERVER_SHUTDOWN) : thd_arg->net.last_errno),
+ 0 : thd->killed_errno()) : thd_arg->net.last_errno),
thread_id(thd_arg->thread_id),
/* save the original thread id; we already know the server id */
- slave_proxy_id(thd_arg->variables.pseudo_thread_id)
+ slave_proxy_id(thd_arg->variables.pseudo_thread_id),
+ flags2_inited(1), sql_mode_inited(1), charset_inited(1),
+ sql_mode(thd_arg->variables.sql_mode),
+ auto_increment_increment(thd_arg->variables.auto_increment_increment),
+ auto_increment_offset(thd_arg->variables.auto_increment_offset)
{
time_t end_time;
time(&end_time);
exec_time = (ulong) (end_time - thd->start_time);
+ catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
+ /* status_vars_len is set just before writing the event */
db_len = (db) ? (uint32) strlen(db) : 0;
+ /*
+ If we don't use flags2 for anything else than options contained in
+ thd->options, it would be more efficient to flags2=thd_arg->options
+ (OPTIONS_WRITTEN_TO_BINLOG would be used only at reading time).
+ But it's likely that we don't want to use 32 bits for 3 bits; in the future
+ we will probably want to reclaim the 29 bits. So we need the &.
+ */
+ flags2= thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG;
+ DBUG_ASSERT(thd->variables.character_set_client->number < 256*256);
+ DBUG_ASSERT(thd->variables.collation_connection->number < 256*256);
+ DBUG_ASSERT(thd->variables.collation_server->number < 256*256);
+ int2store(charset, thd_arg->variables.character_set_client->number);
+ int2store(charset+2, thd_arg->variables.collation_connection->number);
+ int2store(charset+4, thd_arg->variables.collation_server->number);
+ if (thd_arg->time_zone_used)
+ {
+ /*
+ Note that our event becomes dependent on the Time_zone object
+ representing the time zone. Fortunately such objects are never deleted
+ or changed during mysqld's lifetime.
+ */
+ time_zone_len= thd_arg->variables.time_zone->get_name()->length();
+ time_zone_str= thd_arg->variables.time_zone->get_name()->ptr();
+ }
+ else
+ time_zone_len= 0;
+ DBUG_PRINT("info",("Query_log_event has flags2=%lu sql_mode=%lu",flags2,sql_mode));
}
#endif /* MYSQL_CLIENT */
/*
Query_log_event::Query_log_event()
+ This is used by the SQL slave thread to prepare the event before execution.
*/
-Query_log_event::Query_log_event(const char* buf, int event_len,
- bool old_format)
- :Log_event(buf, old_format),data_buf(0), query(NULL), db(NULL)
+Query_log_event::Query_log_event(const char* buf, uint event_len,
+ const Format_description_log_event *description_event,
+ Log_event_type event_type)
+ :Log_event(buf, description_event), data_buf(0), query(NullS),
+ db(NullS), catalog_len(0), status_vars_len(0),
+ flags2_inited(0), sql_mode_inited(0), charset_inited(0),
+ auto_increment_increment(1), auto_increment_offset(1),
+ time_zone_len(0)
{
ulong data_len;
- if (old_format)
- {
- if ((uint)event_len < OLD_HEADER_LEN + QUERY_HEADER_LEN)
- return;
- data_len = event_len - (QUERY_HEADER_LEN + OLD_HEADER_LEN);
- buf += OLD_HEADER_LEN;
- }
- else
- {
- if ((uint)event_len < QUERY_EVENT_OVERHEAD)
- return;
- data_len = event_len - QUERY_EVENT_OVERHEAD;
- buf += LOG_EVENT_HEADER_LEN;
- }
-
+ uint32 tmp;
+ uint8 common_header_len, post_header_len;
+ char *start;
+ const char *end;
+ bool catalog_nz= 1;
+ DBUG_ENTER("Query_log_event::Query_log_event(char*,...)");
+
+ common_header_len= description_event->common_header_len;
+ post_header_len= description_event->post_header_len[event_type-1];
+ DBUG_PRINT("info",("event_len=%ld, common_header_len=%d, post_header_len=%d",
+ event_len, common_header_len, post_header_len));
+
+ /*
+ We test if the event's length is sensible, and if so we compute data_len.
+ We cannot rely on QUERY_HEADER_LEN here as it would not be format-tolerant.
+ We use QUERY_HEADER_MINIMAL_LEN which is the same for 3.23, 4.0 & 5.0.
+ */
+ if (event_len < (uint)(common_header_len + post_header_len))
+ DBUG_VOID_RETURN;
+ data_len = event_len - (common_header_len + post_header_len);
+ buf+= common_header_len;
+
+ slave_proxy_id= thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET);
exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
+ db_len = (uint)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars
error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
- if (!(data_buf = (char*) my_malloc(data_len + 1, MYF(MY_WME))))
- return;
+ /*
+ 5.0 format starts here.
+ Depending on the format, we may or not have affected/warnings etc
+ The remnent post-header to be parsed has length:
+ */
+ tmp= post_header_len - QUERY_HEADER_MINIMAL_LEN;
+ if (tmp)
+ {
+ status_vars_len= uint2korr(buf + Q_STATUS_VARS_LEN_OFFSET);
+ data_len-= status_vars_len;
+ DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u",
+ (uint) status_vars_len));
+ tmp-= 2;
+ }
+ /*
+ We have parsed everything we know in the post header for QUERY_EVENT,
+ the rest of post header is either comes from older version MySQL or
+ dedicated to derived events (e.g. Execute_load_query...)
+ */
- memcpy(data_buf, buf + Q_DATA_OFFSET, data_len);
- slave_proxy_id= thread_id= uint4korr(buf + Q_THREAD_ID_OFFSET);
- db = data_buf;
- db_len = (uint)buf[Q_DB_LEN_OFFSET];
- query=data_buf + db_len + 1;
- q_len = data_len - 1 - db_len;
- *((char*)query+q_len) = 0;
+ /* variable-part: the status vars; only in MySQL 5.0 */
+
+ start= (char*) (buf+post_header_len);
+ end= (const char*) (start+status_vars_len);
+ for (const uchar* pos= (const uchar*) start; pos < (const uchar*) end;)
+ {
+ switch (*pos++) {
+ case Q_FLAGS2_CODE:
+ flags2_inited= 1;
+ flags2= uint4korr(pos);
+ DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", flags2));
+ pos+= 4;
+ break;
+ case Q_SQL_MODE_CODE:
+ {
+#ifndef DBUG_OFF
+ char buff[22];
+#endif
+ sql_mode_inited= 1;
+ sql_mode= (ulong) uint8korr(pos); // QQ: Fix when sql_mode is ulonglong
+ DBUG_PRINT("info",("In Query_log_event, read sql_mode: %s",
+ llstr(sql_mode, buff)));
+ pos+= 8;
+ break;
+ }
+ case Q_CATALOG_NZ_CODE:
+ if ((catalog_len= *pos))
+ catalog= (char*) pos+1; // Will be copied later
+ pos+= catalog_len+1;
+ break;
+ case Q_AUTO_INCREMENT:
+ auto_increment_increment= uint2korr(pos);
+ auto_increment_offset= uint2korr(pos+2);
+ pos+= 4;
+ break;
+ case Q_CHARSET_CODE:
+ {
+ charset_inited= 1;
+ memcpy(charset, pos, 6);
+ pos+= 6;
+ break;
+ }
+ case Q_TIME_ZONE_CODE:
+ {
+ if ((time_zone_len= *pos))
+ time_zone_str= (char *)(pos+1);
+ pos+= time_zone_len+1;
+ break;
+ }
+ case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */
+ if ((catalog_len= *pos))
+ catalog= (char*) pos+1; // Will be copied later
+ pos+= catalog_len+2; // leap over end 0
+ catalog_nz= 0; // catalog has end 0 in event
+ break;
+ default:
+ /* That's why you must write status vars in growing order of code */
+ DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
+ code: %u), skipping the rest of them", (uint) *(pos-1)));
+ pos= (const uchar*) end; // Break loop
+ }
+ }
+
+ if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 +
+ time_zone_len + 1 +
+ data_len + 1, MYF(MY_WME))))
+ DBUG_VOID_RETURN;
+ if (catalog_len) // If catalog is given
+ {
+ if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3.
+ {
+ memcpy(start, catalog, catalog_len);
+ catalog= start;
+ start+= catalog_len;
+ *start++= 0;
+ }
+ else
+ {
+ memcpy(start, catalog, catalog_len+1); // copy end 0
+ catalog= start;
+ start+= catalog_len+1;
+ }
+ }
+ if (time_zone_len)
+ {
+ memcpy(start, time_zone_str, time_zone_len);
+ time_zone_str= start;
+ start+= time_zone_len;
+ *start++= 0;
+ }
+ /* A 2nd variable part; this is common to all versions */
+ memcpy((char*) start, end, data_len); // Copy db and query
+ start[data_len]= '\0'; // End query with \0 (For safetly)
+ db= start;
+ query= start + db_len + 1;
+ q_len= data_len - db_len -1;
+ DBUG_VOID_RETURN;
}
@@ -944,30 +1343,27 @@ Query_log_event::Query_log_event(const char* buf, int event_len,
*/
#ifdef MYSQL_CLIENT
-void Query_log_event::print(FILE* file, bool short_form, char* last_db)
+void Query_log_event::print_query_header(FILE* file, bool short_form,
+ LAST_EVENT_INFO* last_event_info)
{
+ // TODO: print the catalog ??
char buff[40],*end; // Enough for SET TIMESTAMP
+ bool different_db= 1;
+ uint32 tmp;
+
if (!short_form)
{
print_header(file);
- fprintf(file, "\tQuery\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
- (ulong) thread_id, (ulong) exec_time, error_code);
+ fprintf(file, "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
+ get_type_str(), (ulong) thread_id, (ulong) exec_time, error_code);
}
- bool different_db= 1;
-
- if (!(flags & LOG_EVENT_SUPPRESS_USE_F))
+ if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db)
{
- if (db && last_db)
- {
- if (different_db= memcmp(last_db, db, db_len + 1))
- memcpy(last_db, db, db_len + 1);
- }
-
- if (db && db[0] && different_db)
- {
+ if (different_db= memcmp(last_event_info->db, db, db_len + 1))
+ memcpy(last_event_info->db, db, db_len + 1);
+ if (db[0] && different_db)
fprintf(file, "use %s;\n", db);
- }
}
end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
@@ -976,8 +1372,114 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db)
my_fwrite(file, (byte*) buff, (uint) (end-buff),MYF(MY_NABP | MY_WME));
if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
fprintf(file,"SET @@session.pseudo_thread_id=%lu;\n",(ulong)thread_id);
+
+ /*
+ If flags2_inited==0, this is an event from 3.23 or 4.0; nothing to
+ print (remember we don't produce mixed relay logs so there cannot be
+ 5.0 events before that one so there is nothing to reset).
+ */
+ if (likely(flags2_inited)) /* likely as this will mainly read 5.0 logs */
+ {
+ /* tmp is a bitmask of bits which have changed. */
+ if (likely(last_event_info->flags2_inited))
+ /* All bits which have changed */
+ tmp= (last_event_info->flags2) ^ flags2;
+ else /* that's the first Query event we read */
+ {
+ last_event_info->flags2_inited= 1;
+ tmp= ~((uint32)0); /* all bits have changed */
+ }
+
+ if (unlikely(tmp)) /* some bits have changed */
+ {
+ bool need_comma= 0;
+ fprintf(file, "SET ");
+ print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2,
+ "@@session.foreign_key_checks", &need_comma);
+ print_set_option(file, tmp, OPTION_AUTO_IS_NULL, flags2,
+ "@@session.sql_auto_is_null", &need_comma);
+ print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2,
+ "@@session.unique_checks", &need_comma);
+ fprintf(file,";\n");
+ last_event_info->flags2= flags2;
+ }
+ }
+
+ /*
+ Now the session variables;
+ it's more efficient to pass SQL_MODE as a number instead of a
+ comma-separated list.
+ FOREIGN_KEY_CHECKS, SQL_AUTO_IS_NULL, UNIQUE_CHECKS are session-only
+ variables (they have no global version; they're not listed in
+ sql_class.h), The tests below work for pure binlogs or pure relay
+ logs. Won't work for mixed relay logs but we don't create mixed
+ relay logs (that is, there is no relay log with a format change
+ except within the 3 first events, which mysqlbinlog handles
+ gracefully). So this code should always be good.
+ */
+
+ if (likely(sql_mode_inited))
+ {
+ if (unlikely(!last_event_info->sql_mode_inited)) /* first Query event */
+ {
+ last_event_info->sql_mode_inited= 1;
+ /* force a difference to force write */
+ last_event_info->sql_mode= ~sql_mode;
+ }
+ if (unlikely(last_event_info->sql_mode != sql_mode))
+ {
+ fprintf(file,"SET @@session.sql_mode=%lu;\n",(ulong)sql_mode);
+ last_event_info->sql_mode= sql_mode;
+ }
+ }
+ if (last_event_info->auto_increment_increment != auto_increment_increment ||
+ last_event_info->auto_increment_offset != auto_increment_offset)
+ {
+ fprintf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu;\n",
+ auto_increment_increment,auto_increment_offset);
+ last_event_info->auto_increment_increment= auto_increment_increment;
+ last_event_info->auto_increment_offset= auto_increment_offset;
+ }
+
+ /* TODO: print the catalog when we feature SET CATALOG */
+
+ if (likely(charset_inited))
+ {
+ if (unlikely(!last_event_info->charset_inited)) /* first Query event */
+ {
+ last_event_info->charset_inited= 1;
+ last_event_info->charset[0]= ~charset[0]; // force a difference to force write
+ }
+ if (unlikely(bcmp(last_event_info->charset, charset, 6)))
+ {
+ fprintf(file,"SET "
+ "@@session.character_set_client=%d,"
+ "@@session.collation_connection=%d,"
+ "@@session.collation_server=%d"
+ ";\n",
+ uint2korr(charset),
+ uint2korr(charset+2),
+ uint2korr(charset+4));
+ memcpy(last_event_info->charset, charset, 6);
+ }
+ }
+ if (time_zone_len)
+ {
+ if (bcmp(last_event_info->time_zone_str, time_zone_str, time_zone_len+1))
+ {
+ fprintf(file,"SET @@session.time_zone='%s';\n", time_zone_str);
+ memcpy(last_event_info->time_zone_str, time_zone_str, time_zone_len+1);
+ }
+ }
+}
+
+
+void Query_log_event::print(FILE* file, bool short_form,
+ LAST_EVENT_INFO* last_event_info)
+{
+ print_query_header(file, short_form, last_event_info);
my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
- fprintf(file, ";\n");
+ fputs(";\n", file);
}
#endif /* MYSQL_CLIENT */
@@ -989,37 +1491,116 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Query_log_event::exec_event(struct st_relay_log_info* rli)
{
+ return exec_event(rli, query, q_len);
+}
+
+
+int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query_arg, uint32 q_len_arg)
+{
int expected_error,actual_error= 0;
+ /*
+ Colleagues: please never free(thd->catalog) in MySQL. This would lead to
+ bugs as here thd->catalog is a part of an alloced block, not an entire
+ alloced block (see Query_log_event::exec_event()). Same for thd->db.
+ Thank you.
+ */
+ thd->catalog= catalog_len ? (char *) catalog : (char *)"";
thd->db_length= db_len;
thd->db= (char*) rewrite_db(db, &thd->db_length);
+ thd->variables.auto_increment_increment= auto_increment_increment;
+ thd->variables.auto_increment_offset= auto_increment_offset;
/*
- InnoDB internally stores the master log position it has processed so far;
- position to store is of the END of the current log event.
+ InnoDB internally stores the master log position it has executed so far,
+ i.e. the position just after the COMMIT event.
+ When InnoDB will want to store, the positions in rli won't have
+ been updated yet, so group_master_log_* will point to old BEGIN
+ and event_master_log* will point to the beginning of current COMMIT.
+ But log_pos of the COMMIT Query event is what we want, i.e. the pos of the
+ END of the current log event (COMMIT). We save it in rli so that InnoDB can
+ access it.
*/
-#if MYSQL_VERSION_ID < 50000
- rli->future_group_master_log_pos= log_pos + get_event_len() -
- (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0);
-#else
- /* In 5.0 we store the end_log_pos in the relay log so no problem */
rli->future_group_master_log_pos= log_pos;
-#endif
+ DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
+
clear_all_errors(thd, rli);
if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
{
thd->set_time((time_t)when);
- thd->query_length= q_len;
- thd->query = (char*)query;
+ thd->query_length= q_len_arg;
+ thd->query= (char*)query_arg;
VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id = query_id++;
+ thd->query_id = next_query_id();
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->variables.pseudo_thread_id= thread_id; // for temp tables
-
DBUG_PRINT("query",("%s",thd->query));
+
if (ignored_error_code((expected_error= error_code)) ||
!check_expected_error(thd,rli,expected_error))
- mysql_parse(thd, thd->query, q_len);
+ {
+ if (flags2_inited)
+ /*
+ all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must
+ take their value from flags2.
+ */
+ thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG);
+ /*
+ else, we are in a 3.23/4.0 binlog; we previously received a
+ Rotate_log_event which reset thd->options and sql_mode etc, so nothing to do.
+ */
+ /*
+ We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a
+ slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not
+ force us to ignore the dir too. Imagine you are a ring of machines, and
+ one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE
+ on this machine; you don't want it to propagate elsewhere (you don't want
+ all slaves to start ignoring the dirs).
+ */
+ if (sql_mode_inited)
+ thd->variables.sql_mode=
+ (ulong) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
+ (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE));
+ if (charset_inited)
+ {
+ if (rli->cached_charset_compare(charset))
+ {
+ /* Verify that we support the charsets found in the event. */
+ if (!(thd->variables.character_set_client=
+ get_charset(uint2korr(charset), MYF(MY_WME))) ||
+ !(thd->variables.collation_connection=
+ get_charset(uint2korr(charset+2), MYF(MY_WME))) ||
+ !(thd->variables.collation_server=
+ get_charset(uint2korr(charset+4), MYF(MY_WME))))
+ {
+ /*
+ We updated the thd->variables with nonsensical values (0). Let's
+ set them to something safe (i.e. which avoids crash), and we'll
+ stop with EE_UNKNOWN_CHARSET in compare_errors (unless set to
+ ignore this error).
+ */
+ set_slave_thread_default_charset(thd, rli);
+ goto compare_errors;
+ }
+ thd->update_charset(); // for the charset change to take effect
+ }
+ }
+ if (time_zone_len)
+ {
+ String tmp(time_zone_str, time_zone_len, &my_charset_bin);
+ if (!(thd->variables.time_zone=
+ my_tz_find_with_opening_tz_tables(thd, &tmp)))
+ {
+ my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
+ thd->variables.time_zone= global_system_variables.time_zone;
+ goto compare_errors;
+ }
+ }
+
+ /* Execute the query (note that we bypass dispatch_command()) */
+ mysql_parse(thd, thd->query, thd->query_length);
+
+ }
else
{
/*
@@ -1029,7 +1610,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
we exit gracefully; otherwise we warn about the bad error and tell DBA
to check/fix it.
*/
- if (mysql_test_parse_for_slave(thd, thd->query, q_len))
+ if (mysql_test_parse_for_slave(thd, thd->query, thd->query_length))
clear_all_errors(thd, rli); /* Can ignore query */
else
{
@@ -1049,19 +1630,21 @@ START SLAVE; . Query: '%s'", expected_error, thd->query);
if (thd->net.last_errno != ER_SLAVE_IGNORED_TABLE)
mysql_log.write(thd,COM_QUERY,"%s",thd->query);
- /*
+compare_errors:
+
+ /*
If we expected a non-zero error code, and we don't get the same error
code, and none of them should be ignored.
*/
DBUG_PRINT("info",("expected_error: %d last_errno: %d",
- expected_error, thd->net.last_errno));
+ expected_error, thd->net.last_errno));
if ((expected_error != (actual_error= thd->net.last_errno)) &&
- expected_error &&
- !ignored_error_code(actual_error) &&
- !ignored_error_code(expected_error))
+ expected_error &&
+ !ignored_error_code(actual_error) &&
+ !ignored_error_code(expected_error))
{
slave_print_error(rli, 0,
- "\
+ "\
Query caused different errors on master and slave. \
Error on master: '%s' (%d), Error on slave: '%s' (%d). \
Default database: '%s'. Query: '%s'",
@@ -1069,14 +1652,14 @@ Default database: '%s'. Query: '%s'",
expected_error,
actual_error ? thd->net.last_error: "no error",
actual_error,
- print_slave_db_safe(thd->db), query);
+ print_slave_db_safe(db), query_arg);
thd->query_error= 1;
}
/*
If we get the same error code as expected, or they should be ignored.
*/
else if (expected_error == actual_error ||
- ignored_error_code(actual_error))
+ ignored_error_code(actual_error))
{
DBUG_PRINT("info",("error ignored"));
clear_all_errors(thd, rli);
@@ -1090,14 +1673,46 @@ Default database: '%s'. Query: '%s'",
"Error '%s' on query. Default database: '%s'. Query: '%s'",
(actual_error ? thd->net.last_error :
"unexpected success or fatal error"),
- print_slave_db_safe(thd->db), query);
+ print_slave_db_safe(thd->db), query_arg);
thd->query_error= 1;
}
+
+ /*
+ TODO: compare the values of "affected rows" around here. Something
+ like:
+ if ((uint32) affected_in_event != (uint32) affected_on_slave)
+ {
+ sql_print_error("Slave: did not get the expected number of affected \
+ rows running query from master - expected %d, got %d (this numbers \
+ should have matched modulo 4294967296).", 0, ...);
+ thd->query_error = 1;
+ }
+ We may also want an option to tell the slave to ignore "affected"
+ mismatch. This mismatch could be implemented with a new ER_ code, and
+ to ignore it you would use --slave-skip-errors...
+
+ To do the comparison we need to know the value of "affected" which the
+ above mysql_parse() computed. And we need to know the value of
+ "affected" in the master's binlog. Both will be implemented later. The
+ important thing is that we now have the format ready to log the values
+ of "affected" in the binlog. So we can release 5.0.0 before effectively
+ logging "affected" and effectively comparing it.
+ */
} /* End of if (db_ok(... */
end:
VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->db= 0; // prevent db from being freed
+ /*
+ Probably we have set thd->query, thd->db, thd->catalog to point to places
+ in the data_buf of this event. Now the event is going to be deleted
+ probably, so data_buf will be freed, so the thd->... listed above will be
+ pointers to freed memory.
+ So we must set them to 0, so that those bad pointers values are not later
+ used. Note that "cleanup" queries like automatic DROP TEMPORARY TABLE
+ don't suffer from these assignments to 0 as DROP TEMPORARY
+ TABLE uses the db.table syntax.
+ */
+ thd->db= thd->catalog= 0; // prevent db from being freed
thd->query= 0; // just to be sure
thd->query_length= thd->db_length =0;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -1110,22 +1725,30 @@ end:
updating query.
*/
return (thd->query_error ? thd->query_error :
- (thd->one_shot_set ? (rli->inc_event_relay_log_pos(get_event_len()),0) :
+ (thd->one_shot_set ? (rli->inc_event_relay_log_pos(),0) :
Log_event::exec_event(rli)));
}
#endif
/**************************************************************************
- Start_log_event methods
+ Start_log_event_v3 methods
**************************************************************************/
+#ifndef MYSQL_CLIENT
+Start_log_event_v3::Start_log_event_v3() :Log_event(), binlog_version(BINLOG_VERSION), artificial_event(0)
+{
+ created= when;
+ memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
+}
+#endif
+
/*
- Start_log_event::pack_info()
+ Start_log_event_v3::pack_info()
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Start_log_event::pack_info(Protocol *protocol)
+void Start_log_event_v3::pack_info(Protocol *protocol)
{
char buf[12 + ST_SERVER_VER_LEN + 14 + 22], *pos;
pos= strmov(buf, "Server ver: ");
@@ -1138,57 +1761,80 @@ void Start_log_event::pack_info(Protocol *protocol)
/*
- Start_log_event::print()
+ Start_log_event_v3::print()
*/
#ifdef MYSQL_CLIENT
-void Start_log_event::print(FILE* file, bool short_form, char* last_db)
+void Start_log_event_v3::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
{
- if (short_form)
- return;
-
- print_header(file);
- fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version,
- server_version);
- print_timestamp(file);
- if (created)
- fprintf(file," at startup");
- fputc('\n', file);
+ if (!short_form)
+ {
+ print_header(file);
+ fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version,
+ server_version);
+ print_timestamp(file);
+ if (created)
+ fprintf(file," at startup");
+ fputc('\n', file);
+ if (flags & LOG_EVENT_BINLOG_IN_USE_F)
+ fprintf(file, "# Warning: this binlog was not closed properly. "
+ "Most probably mysqld crashed writing it.\n");
+ }
+ if (!artificial_event && created)
+ {
+#ifdef WHEN_WE_HAVE_THE_RESET_CONNECTION_SQL_COMMAND
+ /*
+ This is for mysqlbinlog: like in replication, we want to delete the stale
+ tmp files left by an unclean shutdown of mysqld (temporary tables)
+ and rollback unfinished transaction.
+ Probably this can be done with RESET CONNECTION (syntax to be defined).
+ */
+ fprintf(file,"RESET CONNECTION;\n");
+#else
+ fprintf(file,"ROLLBACK;\n");
+#endif
+ }
fflush(file);
}
#endif /* MYSQL_CLIENT */
/*
- Start_log_event::Start_log_event()
+ Start_log_event_v3::Start_log_event_v3()
*/
-Start_log_event::Start_log_event(const char* buf,
- bool old_format)
- :Log_event(buf, old_format)
+Start_log_event_v3::Start_log_event_v3(const char* buf,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event)
{
- buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
- binlog_version = uint2korr(buf+ST_BINLOG_VER_OFFSET);
+ buf+= description_event->common_header_len;
+ binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
ST_SERVER_VER_LEN);
- created = uint4korr(buf+ST_CREATED_OFFSET);
+ created= uint4korr(buf+ST_CREATED_OFFSET);
+ /* We use log_pos to mark if this was an artificial event or not */
+ artificial_event= (log_pos == 0);
}
/*
- Start_log_event::write_data()
+ Start_log_event_v3::write()
*/
-int Start_log_event::write_data(IO_CACHE* file)
+#ifndef MYSQL_CLIENT
+bool Start_log_event_v3::write(IO_CACHE* file)
{
- char buff[START_HEADER_LEN];
+ char buff[START_V3_HEADER_LEN];
int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
int4store(buff + ST_CREATED_OFFSET,created);
- return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
+ return (write_header(file, sizeof(buff)) ||
+ my_b_safe_write(file, (byte*) buff, sizeof(buff)));
}
+#endif
+
/*
- Start_log_event::exec_event()
+ Start_log_event_v3::exec_event()
The master started
@@ -1207,84 +1853,321 @@ int Start_log_event::write_data(IO_CACHE* file)
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Start_log_event::exec_event(struct st_relay_log_info* rli)
+int Start_log_event_v3::exec_event(struct st_relay_log_info* rli)
{
- DBUG_ENTER("Start_log_event::exec_event");
-
- /*
- If the I/O thread has not started, mi->old_format is BINLOG_FORMAT_CURRENT
- (that's what the MASTER_INFO constructor does), so the test below is not
- perfect at all.
- */
- switch (rli->mi->old_format) {
- case BINLOG_FORMAT_CURRENT:
- /*
- This is 4.x, so a Start_log_event is only at master startup,
- so we are sure the master has restarted and cleared his temp tables.
- */
- close_temporary_tables(thd);
- cleanup_load_tmpdir();
+ DBUG_ENTER("Start_log_event_v3::exec_event");
+ switch (binlog_version)
+ {
+ case 3:
+ case 4:
/*
- As a transaction NEVER spans on 2 or more binlogs:
- if we have an active transaction at this point, the master died while
- writing the transaction to the binary log, i.e. while flushing the binlog
- cache to the binlog. As the write was started, the transaction had been
- committed on the master, so we lack of information to replay this
- transaction on the slave; all we can do is stop with error.
+ This can either be 4.x (then a Start_log_event_v3 is only at master
+ startup so we are sure the master has restarted and cleared his temp
+ tables; the event always has 'created'>0) or 5.0 (then we have to test
+ 'created').
*/
- if (thd->options & OPTION_BEGIN)
+ if (created)
{
- slave_print_error(rli, 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.");
- return(1);
+ close_temporary_tables(thd);
+ cleanup_load_tmpdir();
}
break;
- /*
+ /*
Now the older formats; in that case load_tmpdir is cleaned up by the I/O
thread.
*/
- case BINLOG_FORMAT_323_LESS_57:
+ case 1:
+ if (strncmp(rli->relay_log.description_event_for_exec->server_version,
+ "3.23.57",7) >= 0 && created)
+ {
+ /*
+ Can distinguish, based on the value of 'created': this event was
+ generated at master startup.
+ */
+ close_temporary_tables(thd);
+ }
/*
- Cannot distinguish a Start_log_event generated at master startup and
- one generated by master FLUSH LOGS, so cannot be sure temp tables
- have to be dropped. So do nothing.
+ Otherwise, can't distinguish a Start_log_event generated at
+ master startup and one generated by master FLUSH LOGS, so cannot
+ be sure temp tables have to be dropped. So do nothing.
*/
break;
- case BINLOG_FORMAT_323_GEQ_57:
- /*
- Can distinguish, based on the value of 'created',
- which was generated at master startup.
- */
- if (created)
- close_temporary_tables(thd);
- break;
default:
/* this case is impossible */
- return 1;
+ DBUG_RETURN(1);
}
-
DBUG_RETURN(Log_event::exec_event(rli));
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-/**************************************************************************
- Load_log_event methods
-**************************************************************************/
+/***************************************************************************
+ Format_description_log_event methods
+****************************************************************************/
/*
- Load_log_event::pack_info()
+ Format_description_log_event 1st ctor.
+
+ SYNOPSIS
+ Format_description_log_event::Format_description_log_event
+ binlog_version the binlog version for which we want to build
+ an event. Can be 1 (=MySQL 3.23), 3 (=4.0.x
+ x>=2 and 4.1) or 4 (MySQL 5.0). Note that the
+ old 4.0 (binlog version 2) is not supported;
+ it should not be used for replication with
+ 5.0.
+
+ DESCRIPTION
+ Ctor. Can be used to create the event to write to the binary log (when the
+ server starts or when FLUSH LOGS), or to create artificial events to parse
+ binlogs from MySQL 3.23 or 4.x.
+ When in a client, only the 2nd use is possible.
+*/
+
+Format_description_log_event::
+Format_description_log_event(uint8 binlog_ver, const char* server_ver)
+ :Start_log_event_v3()
+{
+ created= when;
+ binlog_version= binlog_ver;
+ switch (binlog_ver) {
+ case 4: /* MySQL 5.0 */
+ memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
+ common_header_len= LOG_EVENT_HEADER_LEN;
+ number_of_event_types= LOG_EVENT_TYPES;
+ /* we'll catch my_malloc() error in is_valid() */
+ post_header_len=(uint8*) my_malloc(number_of_event_types*sizeof(uint8),
+ MYF(MY_ZEROFILL));
+ /*
+ This long list of assignments is not beautiful, but I see no way to
+ make it nicer, as the right members are #defines, not array members, so
+ it's impossible to write a loop.
+ */
+ if (post_header_len)
+ {
+ post_header_len[START_EVENT_V3-1]= START_V3_HEADER_LEN;
+ post_header_len[QUERY_EVENT-1]= QUERY_HEADER_LEN;
+ post_header_len[ROTATE_EVENT-1]= ROTATE_HEADER_LEN;
+ post_header_len[LOAD_EVENT-1]= LOAD_HEADER_LEN;
+ post_header_len[CREATE_FILE_EVENT-1]= CREATE_FILE_HEADER_LEN;
+ post_header_len[APPEND_BLOCK_EVENT-1]= APPEND_BLOCK_HEADER_LEN;
+ post_header_len[EXEC_LOAD_EVENT-1]= EXEC_LOAD_HEADER_LEN;
+ post_header_len[DELETE_FILE_EVENT-1]= DELETE_FILE_HEADER_LEN;
+ post_header_len[NEW_LOAD_EVENT-1]= post_header_len[LOAD_EVENT-1];
+ post_header_len[FORMAT_DESCRIPTION_EVENT-1]= FORMAT_DESCRIPTION_HEADER_LEN;
+ post_header_len[BEGIN_LOAD_QUERY_EVENT-1]= post_header_len[APPEND_BLOCK_EVENT-1];
+ post_header_len[EXECUTE_LOAD_QUERY_EVENT-1]= EXECUTE_LOAD_QUERY_HEADER_LEN;
+ }
+ break;
+
+ case 1: /* 3.23 */
+ case 3: /* 4.0.x x>=2 */
+ /*
+ We build an artificial (i.e. not sent by the master) event, which
+ describes what those old master versions send.
+ */
+ if (binlog_ver==1)
+ strmov(server_version, server_ver ? server_ver : "3.23");
+ else
+ strmov(server_version, server_ver ? server_ver : "4.0");
+ common_header_len= binlog_ver==1 ? OLD_HEADER_LEN :
+ LOG_EVENT_MINIMAL_HEADER_LEN;
+ /*
+ The first new event in binlog version 4 is Format_desc. So any event type
+ after that does not exist in older versions. We use the events known by
+ version 3, even if version 1 had only a subset of them (this is not a
+ problem: it uses a few bytes for nothing but unifies code; it does not
+ make the slave detect less corruptions).
+ */
+ number_of_event_types= FORMAT_DESCRIPTION_EVENT - 1;
+ post_header_len=(uint8*) my_malloc(number_of_event_types*sizeof(uint8),
+ MYF(0));
+ if (post_header_len)
+ {
+ post_header_len[START_EVENT_V3-1]= START_V3_HEADER_LEN;
+ post_header_len[QUERY_EVENT-1]= QUERY_HEADER_MINIMAL_LEN;
+ post_header_len[STOP_EVENT-1]= 0;
+ post_header_len[ROTATE_EVENT-1]= (binlog_ver==1) ? 0 : ROTATE_HEADER_LEN;
+ post_header_len[INTVAR_EVENT-1]= 0;
+ post_header_len[LOAD_EVENT-1]= LOAD_HEADER_LEN;
+ post_header_len[SLAVE_EVENT-1]= 0;
+ post_header_len[CREATE_FILE_EVENT-1]= CREATE_FILE_HEADER_LEN;
+ post_header_len[APPEND_BLOCK_EVENT-1]= APPEND_BLOCK_HEADER_LEN;
+ post_header_len[EXEC_LOAD_EVENT-1]= EXEC_LOAD_HEADER_LEN;
+ post_header_len[DELETE_FILE_EVENT-1]= DELETE_FILE_HEADER_LEN;
+ post_header_len[NEW_LOAD_EVENT-1]= post_header_len[LOAD_EVENT-1];
+ post_header_len[RAND_EVENT-1]= 0;
+ post_header_len[USER_VAR_EVENT-1]= 0;
+ }
+ break;
+ default: /* Includes binlog version 2 i.e. 4.0.x x<=1 */
+ post_header_len= 0; /* will make is_valid() fail */
+ break;
+ }
+}
+
+
+/*
+ The problem with this constructor is that the fixed header may have a
+ length different from this version, but we don't know this length as we
+ have not read the Format_description_log_event which says it, yet. This
+ length is in the post-header of the event, but we don't know where the
+ post-header starts.
+ So this type of event HAS to:
+ - either have the header's length at the beginning (in the header, at a
+ fixed position which will never be changed), not in the post-header. That
+ would make the header be "shifted" compared to other events.
+ - or have a header of size LOG_EVENT_MINIMAL_HEADER_LEN (19), in all future
+ versions, so that we know for sure.
+ I (Guilhem) chose the 2nd solution. Rotate has the same constraint (because
+ it is sent before Format_description_log_event).
+*/
+
+Format_description_log_event::
+Format_description_log_event(const char* buf,
+ uint event_len,
+ const
+ Format_description_log_event*
+ description_event)
+ :Start_log_event_v3(buf, description_event)
+{
+ DBUG_ENTER("Format_description_log_event::Format_description_log_event(char*,...)");
+ buf+= LOG_EVENT_MINIMAL_HEADER_LEN;
+ if ((common_header_len=buf[ST_COMMON_HEADER_LEN_OFFSET]) < OLD_HEADER_LEN)
+ DBUG_VOID_RETURN; /* sanity check */
+ number_of_event_types=
+ event_len-(LOG_EVENT_MINIMAL_HEADER_LEN+ST_COMMON_HEADER_LEN_OFFSET+1);
+ DBUG_PRINT("info", ("common_header_len=%d number_of_event_types=%d",
+ common_header_len, number_of_event_types));
+ /* If alloc fails, we'll detect it in is_valid() */
+ post_header_len= (uint8*) my_memdup((byte*)buf+ST_COMMON_HEADER_LEN_OFFSET+1,
+ number_of_event_types*
+ sizeof(*post_header_len), MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+#ifndef MYSQL_CLIENT
+bool Format_description_log_event::write(IO_CACHE* file)
+{
+ /*
+ We don't call Start_log_event_v3::write() because this would make 2
+ my_b_safe_write().
+ */
+ byte buff[FORMAT_DESCRIPTION_HEADER_LEN];
+ int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
+ memcpy((char*) buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
+ int4store(buff + ST_CREATED_OFFSET,created);
+ buff[ST_COMMON_HEADER_LEN_OFFSET]= LOG_EVENT_HEADER_LEN;
+ memcpy((char*) buff+ST_COMMON_HEADER_LEN_OFFSET+1, (byte*) post_header_len,
+ LOG_EVENT_TYPES);
+ return (write_header(file, sizeof(buff)) ||
+ my_b_safe_write(file, buff, sizeof(buff)));
+}
+#endif
+
+/*
+ SYNOPSIS
+ Format_description_log_event::exec_event()
+
+ IMPLEMENTATION
+ Save the information which describes the binlog's format, to be able to
+ read all coming events.
+ Call Start_log_event_v3::exec_event().
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Load_log_event::pack_info(Protocol *protocol)
+int Format_description_log_event::exec_event(struct st_relay_log_info* rli)
{
- char *buf, *pos;
- uint buf_len;
+ DBUG_ENTER("Format_description_log_event::exec_event");
+
+ /* save the information describing this binlog */
+ delete rli->relay_log.description_event_for_exec;
+ rli->relay_log.description_event_for_exec= this;
+
+#ifdef USING_TRANSACTIONS
+ /*
+ As a transaction NEVER spans on 2 or more binlogs:
+ if we have an active transaction at this point, the master died
+ while writing the transaction to the binary log, i.e. while
+ flushing the binlog cache to the binlog. As the write was started,
+ the transaction had been committed on the master, so we lack of
+ information to replay this transaction on the slave; all we can do
+ is stop with error.
+ Note: this event could be sent by the master to inform us of the
+ format of its binlog; in other words maybe it is not at its
+ original place when it comes to us; we'll know this by checking
+ log_pos ("artificial" events have log_pos == 0).
+ */
+ if (!artificial_event && created && thd->transaction.all.nht)
+ {
+ slave_print_error(rli, 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.");
+ end_trans(thd, ROLLBACK);
+ }
+#endif
+ /*
+ If this event comes from ourselves, there is no cleaning task to perform,
+ we don't call Start_log_event_v3::exec_event() (this was just to update the
+ log's description event).
+ */
+ if (server_id == (uint32) ::server_id)
+ {
+ /*
+ Do not modify rli->group_master_log_pos, as this event did not exist on
+ the master. That is, just update the *relay log* coordinates; this is
+ done by passing log_pos=0 to inc_group_relay_log_pos, like we do in
+ Stop_log_event::exec_event().
+ If in a transaction, don't touch group_* coordinates.
+ */
+ if (thd->options & OPTION_BEGIN)
+ rli->inc_event_relay_log_pos();
+ else
+ {
+ rli->inc_group_relay_log_pos(0);
+ flush_relay_log_info(rli);
+ }
+ DBUG_RETURN(0);
+ }
+
+ /*
+ If the event was not requested by the slave i.e. the master sent it while
+ the slave asked for a position >4, the event will make
+ rli->group_master_log_pos advance. Say that the slave asked for position
+ 1000, and the Format_desc event's end is 96. Then in the beginning of
+ replication rli->group_master_log_pos will be 0, then 96, then jump to
+ first really asked event (which is >96). So this is ok.
+ */
+ DBUG_RETURN(Start_log_event_v3::exec_event(rli));
+}
+#endif
+
+ /**************************************************************************
+ Load_log_event methods
+ General note about Load_log_event: the binlogging of LOAD DATA INFILE is
+ going to be changed in 5.0 (or maybe in 5.1; not decided yet).
+ However, the 5.0 slave could still have to read such events (from a 4.x
+ master), convert them (which just means maybe expand the header, when 5.0
+ servers have a UID in events) (remember that whatever is after the header
+ will be like in 4.x, as this event's format is not modified in 5.0 as we
+ will use new types of events to log the new LOAD DATA INFILE features).
+ To be able to read/convert, we just need to not assume that the common
+ header is of length LOG_EVENT_HEADER_LEN (we must use the description
+ event).
+ Note that I (Guilhem) manually tested replication of a big LOAD DATA INFILE
+ between 3.23 and 5.0, and between 4.0 and 5.0, and it works fine (and the
+ positions displayed in SHOW SLAVE STATUS then are fine too).
+ **************************************************************************/
+
+/*
+ Load_log_event::pack_info()
+*/
- buf_len=
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+uint Load_log_event::get_query_buffer_length()
+{
+ return
5 + db_len + 3 + // "use DB; "
18 + fname_len + 2 + // "LOAD DATA INFILE 'file''"
7 + // LOCAL
@@ -1294,14 +2177,18 @@ void Load_log_event::pack_info(Protocol *protocol)
23 + sql_ex.enclosed_len*4 + 2 + // " OPTIONALLY ENCLOSED BY 'str'"
12 + sql_ex.escaped_len*4 + 2 + // " ESCAPED BY 'str'"
21 + sql_ex.line_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'"
- 19 + sql_ex.line_start_len*4 + 2 + // " LINES STARTING BY 'str'"
- 15 + 22 + // " IGNORE xxx LINES"
+ 19 + sql_ex.line_start_len*4 + 2 + // " LINES STARTING BY 'str'"
+ 15 + 22 + // " IGNORE xxx LINES"
3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)"
+}
- if (!(buf= my_malloc(buf_len, MYF(MY_WME))))
- return;
- pos= buf;
- if (db && db_len)
+
+void Load_log_event::print_query(bool need_db, char *buf,
+ char **end, char **fn_start, char **fn_end)
+{
+ char *pos= buf;
+
+ if (need_db && db && db_len)
{
pos= strmov(pos, "use `");
memcpy(pos, db, db_len);
@@ -1309,6 +2196,10 @@ void Load_log_event::pack_info(Protocol *protocol)
}
pos= strmov(pos, "LOAD DATA ");
+
+ if (fn_start)
+ *fn_start= pos;
+
if (check_fname_outside_temp_buf())
pos= strmov(pos, "LOCAL ");
pos= strmov(pos, "INFILE '");
@@ -1320,7 +2211,12 @@ void Load_log_event::pack_info(Protocol *protocol)
else if (sql_ex.opt_flags & IGNORE_FLAG)
pos= strmov(pos, " IGNORE ");
- pos= strmov(pos ,"INTO TABLE `");
+ pos= strmov(pos ,"INTO");
+
+ if (fn_end)
+ *fn_end= pos;
+
+ pos= strmov(pos ," TABLE `");
memcpy(pos, table_name, table_name_len);
pos+= table_name_len;
@@ -1369,17 +2265,30 @@ void Load_log_event::pack_info(Protocol *protocol)
*pos++= ')';
}
- protocol->store(buf, pos-buf, &my_charset_bin);
+ *end= pos;
+}
+
+
+void Load_log_event::pack_info(Protocol *protocol)
+{
+ char *buf, *end;
+
+ if (!(buf= my_malloc(get_query_buffer_length(), MYF(MY_WME))))
+ return;
+ print_query(TRUE, buf, &end, 0, 0);
+ protocol->store(buf, end-buf, &my_charset_bin);
my_free(buf, MYF(0));
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
+#ifndef MYSQL_CLIENT
+
/*
Load_log_event::write_data_header()
*/
-int Load_log_event::write_data_header(IO_CACHE* file)
+bool Load_log_event::write_data_header(IO_CACHE* file)
{
char buf[LOAD_HEADER_LEN];
int4store(buf + L_THREAD_ID_OFFSET, slave_proxy_id);
@@ -1388,7 +2297,7 @@ int Load_log_event::write_data_header(IO_CACHE* file)
buf[L_TBL_LEN_OFFSET] = (char)table_name_len;
buf[L_DB_LEN_OFFSET] = (char)db_len;
int4store(buf + L_NUM_FIELDS_OFFSET, num_fields);
- return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN);
+ return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN) != 0;
}
@@ -1396,7 +2305,7 @@ int Load_log_event::write_data_header(IO_CACHE* file)
Load_log_event::write_data_body()
*/
-int Load_log_event::write_data_body(IO_CACHE* file)
+bool Load_log_event::write_data_body(IO_CACHE* file)
{
if (sql_ex.write_data(file))
return 1;
@@ -1416,7 +2325,6 @@ int Load_log_event::write_data_body(IO_CACHE* file)
Load_log_event::Load_log_event()
*/
-#ifndef MYSQL_CLIENT
Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
const char *db_arg, const char *table_name_arg,
List<Item> &fields_arg,
@@ -1500,6 +2408,7 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
}
#endif /* !MYSQL_CLIENT */
+
/*
Load_log_event::Load_log_event()
@@ -1508,15 +2417,25 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
constructed event.
*/
-Load_log_event::Load_log_event(const char *buf, int event_len,
- bool old_format)
- :Log_event(buf, old_format), num_fields(0), fields(0),
- field_lens(0), field_block_len(0),
+Load_log_event::Load_log_event(const char *buf, uint event_len,
+ const Format_description_log_event *description_event)
+ :Log_event(buf, description_event), num_fields(0), fields(0),
+ field_lens(0),field_block_len(0),
table_name(0), db(0), fname(0), local_fname(FALSE)
{
DBUG_ENTER("Load_log_event");
- if (event_len) // derived class, will call copy_log_event() itself
- copy_log_event(buf, event_len, old_format);
+ /*
+ I (Guilhem) manually tested replication of LOAD DATA INFILE for 3.23->5.0,
+ 4.0->5.0 and 5.0->5.0 and it works.
+ */
+ if (event_len)
+ copy_log_event(buf, event_len,
+ ((buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
+ LOAD_HEADER_LEN +
+ description_event->common_header_len :
+ LOAD_HEADER_LEN + LOG_EVENT_HEADER_LEN),
+ description_event);
+ /* otherwise it's a derived class, will call copy_log_event() itself */
DBUG_VOID_RETURN;
}
@@ -1526,14 +2445,14 @@ Load_log_event::Load_log_event(const char *buf, int event_len,
*/
int Load_log_event::copy_log_event(const char *buf, ulong event_len,
- bool old_format)
+ int body_offset,
+ const Format_description_log_event *description_event)
{
+ DBUG_ENTER("Load_log_event::copy_log_event");
uint data_len;
char* buf_end = (char*)buf + event_len;
- uint header_len= old_format ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
- const char* data_head = buf + header_len;
- DBUG_ENTER("Load_log_event::copy_log_event");
-
+ /* this is the beginning of the post-header */
+ const char* data_head = buf + description_event->common_header_len;
slave_proxy_id= thread_id= uint4korr(data_head + L_THREAD_ID_OFFSET);
exec_time = uint4korr(data_head + L_EXEC_TIME_OFFSET);
skip_lines = uint4korr(data_head + L_SKIP_LINES_OFFSET);
@@ -1541,21 +2460,17 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
db_len = (uint)data_head[L_DB_LEN_OFFSET];
num_fields = uint4korr(data_head + L_NUM_FIELDS_OFFSET);
- int body_offset = ((buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
- LOAD_HEADER_LEN + header_len :
- get_data_body_offset());
-
if ((int) event_len < body_offset)
DBUG_RETURN(1);
/*
Sql_ex.init() on success returns the pointer to the first byte after
the sql_ex structure, which is the start of field lengths array.
*/
- if (!(field_lens=(uchar*)sql_ex.init((char*)buf + body_offset,
- buf_end,
- buf[EVENT_TYPE_OFFSET] != LOAD_EVENT)))
+ if (!(field_lens= (uchar*)sql_ex.init((char*)buf + body_offset,
+ buf_end,
+ buf[EVENT_TYPE_OFFSET] != LOAD_EVENT)))
DBUG_RETURN(1);
-
+
data_len = event_len - body_offset;
if (num_fields > data_len) // simple sanity check against corruption
DBUG_RETURN(1);
@@ -1568,6 +2483,7 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
fname = db + db_len + 1;
fname_len = strlen(fname);
// null termination is accomplished by the caller doing buf[event_len]=0
+
DBUG_RETURN(0);
}
@@ -1577,13 +2493,13 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
*/
#ifdef MYSQL_CLIENT
-void Load_log_event::print(FILE* file, bool short_form, char* last_db)
+void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
{
- print(file, short_form, last_db, 0);
+ print(file, short_form, last_event_info, 0);
}
-void Load_log_event::print(FILE* file, bool short_form, char* last_db,
+void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info,
bool commented)
{
DBUG_ENTER("Load_log_event::print");
@@ -1595,7 +2511,7 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db,
}
bool different_db= 1;
- if (db && last_db)
+ if (db)
{
/*
If the database is different from the one of the previous statement, we
@@ -1603,9 +2519,9 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db,
But if commented, the "use" is going to be commented so we should not
update the last_db.
*/
- if ((different_db= memcmp(last_db, db, db_len + 1)) &&
+ if ((different_db= memcmp(last_event_info->db, db, db_len + 1)) &&
!commented)
- memcpy(last_db, db, db_len + 1);
+ memcpy(last_event_info->db, db, db_len + 1);
}
if (db && db[0] && different_db)
@@ -1727,7 +2643,6 @@ void Load_log_event::set_fields(const char* affected_db,
int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
bool use_rli_only_for_errors)
{
- char *load_data_query= 0;
thd->db_length= db_len;
thd->db= (char*) rewrite_db(db, &thd->db_length);
DBUG_ASSERT(thd->query == 0);
@@ -1741,15 +2656,12 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
mysql_init_query(thd, 0, 0);
if (!use_rli_only_for_errors)
{
-#if MYSQL_VERSION_ID < 50000
- rli->future_group_master_log_pos= log_pos + get_event_len() -
- (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0);
-#else
+ /* Saved for InnoDB, see comment in Query_log_event::exec_event() */
rli->future_group_master_log_pos= log_pos;
-#endif
+ DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
}
-
- /*
+
+ /*
We test replicate_*_db rules. Note that we have already prepared the file
to load, even if we are going to ignore and delete it now. So it is
possible that we did a lot of disk writes for nothing. In other words, a
@@ -1765,7 +2677,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
{
thd->set_time((time_t)when);
VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id = query_id++;
+ thd->query_id = next_query_id();
VOID(pthread_mutex_unlock(&LOCK_thread_count));
/*
Initing thd->row_count is not necessary in theory as this variable has no
@@ -1773,12 +2685,12 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
"data truncated" warning but which is absorbed and never gets to the
error log); still we init it to avoid a Valgrind message.
*/
- mysql_reset_errors(thd);
+ mysql_reset_errors(thd, 0);
TABLE_LIST tables;
bzero((char*) &tables,sizeof(tables));
tables.db = thd->db;
- tables.alias = tables.real_name = (char*)table_name;
+ tables.alias = tables.table_name = (char*) table_name;
tables.lock_type = TL_WRITE;
tables.updating= 1;
@@ -1792,21 +2704,30 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
else
{
char llbuff[22];
+ char *end;
enum enum_duplicates handle_dup;
bool ignore= 0;
+ char *load_data_query;
+
/*
- Make a simplified LOAD DATA INFILE query, for the information of the
- user in SHOW PROCESSLIST. Note that db is known in the 'db' column.
+ Forge LOAD DATA INFILE query which will be used in SHOW PROCESS LIST
+ and written to slave's binlog if binlogging is on.
*/
- if ((load_data_query= (char *) my_alloca(18 + strlen(fname) + 14 +
- strlen(tables.real_name) + 8)))
+ if (!(load_data_query= (char *)thd->alloc(get_query_buffer_length() + 1)))
{
- thd->query_length= (uint)(strxmov(load_data_query,
- "LOAD DATA INFILE '", fname,
- "' INTO TABLE `", tables.real_name,
- "` <...>", NullS) - load_data_query);
- thd->query= load_data_query;
+ /*
+ This will set thd->fatal_error in case of OOM. So we surely will notice
+ that something is wrong.
+ */
+ goto error;
}
+
+ print_query(FALSE, load_data_query, &end, (char **)&thd->lex->fname_start,
+ (char **)&thd->lex->fname_end);
+ *end= 0;
+ thd->query_length= end - load_data_query;
+ thd->query= load_data_query;
+
if (sql_ex.opt_flags & REPLACE_FLAG)
handle_dup= DUP_REPLACE;
else if (sql_ex.opt_flags & IGNORE_FLAG)
@@ -1852,6 +2773,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
List<Item> field_list;
set_fields(thd->db,field_list);
thd->variables.pseudo_thread_id= thread_id;
+ List<Item> set_fields;
if (net)
{
// mysql_load will use thd->net to read the file
@@ -1861,9 +2783,13 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
*/
thd->net.pkt_nr = net->pkt_nr;
}
- if (mysql_load(thd, &ex, &tables, field_list, handle_dup, ignore, net != 0,
- TL_WRITE))
- thd->query_error = 1;
+ /*
+ It is safe to use set_fields twice because we are not going to
+ update it inside mysql_load().
+ */
+ if (mysql_load(thd, &ex, &tables, field_list, set_fields, set_fields,
+ handle_dup, ignore, net != 0))
+ thd->query_error= 1;
if (thd->cuted_fields)
{
/* log_pos is the position of the LOAD event in the master log */
@@ -1889,20 +2815,19 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
if (net)
skip_load_data_infile(net);
}
-
+
+error:
thd->net.vio = 0;
char *save_db= thd->db;
VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->db= 0;
+ thd->db= thd->catalog= 0;
thd->query= 0;
thd->query_length= thd->db_length= 0;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
close_thread_tables(thd);
- if (load_data_query)
- my_afree(load_data_query);
if (thd->query_error)
{
- /* this err/sql_errno code is copy-paste from send_error() */
+ /* this err/sql_errno code is copy-paste from net_send_error() */
const char *err;
int sql_errno;
if ((err=thd->net.last_error)[0])
@@ -1960,17 +2885,17 @@ void Rotate_log_event::pack_info(Protocol *protocol)
*/
#ifdef MYSQL_CLIENT
-void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
+void Rotate_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
{
char buf[22];
+
if (short_form)
return;
-
print_header(file);
fprintf(file, "\tRotate to ");
if (new_log_ident)
my_fwrite(file, (byte*) new_log_ident, (uint)ident_len,
- MYF(MY_NABP | MY_WME));
+ MYF(MY_NABP | MY_WME));
fprintf(file, " pos: %s", llstr(pos, buf));
fputc('\n', file);
fflush(file);
@@ -1982,31 +2907,22 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
Rotate_log_event::Rotate_log_event()
*/
-Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
- bool old_format)
- :Log_event(buf, old_format),new_log_ident(NULL),alloced(0)
+Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event) ,new_log_ident(NULL),alloced(0)
{
+ DBUG_ENTER("Rotate_log_event::Rotate_log_event(char*,...)");
// The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
- int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
+ uint8 header_size= description_event->common_header_len;
+ uint8 post_header_len= description_event->post_header_len[ROTATE_EVENT-1];
uint ident_offset;
- DBUG_ENTER("Rotate_log_event");
-
if (event_len < header_size)
DBUG_VOID_RETURN;
-
buf += header_size;
- if (old_format)
- {
- ident_len = (uint)(event_len - OLD_HEADER_LEN);
- pos = 4;
- ident_offset = 0;
- }
- else
- {
- ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD);
- pos = uint8korr(buf + R_POS_OFFSET);
- ident_offset = ROTATE_HEADER_LEN;
- }
+ pos = post_header_len ? uint8korr(buf + R_POS_OFFSET) : 4;
+ ident_len = (uint)(event_len -
+ (header_size+post_header_len));
+ ident_offset = post_header_len;
set_if_smaller(ident_len,FN_REFLEN-1);
if (!(new_log_ident= my_strdup_with_length((byte*) buf +
ident_offset,
@@ -2019,29 +2935,32 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
/*
- Rotate_log_event::write_data()
+ Rotate_log_event::write()
*/
-int Rotate_log_event::write_data(IO_CACHE* file)
+#ifndef MYSQL_CLIENT
+bool Rotate_log_event::write(IO_CACHE* file)
{
char buf[ROTATE_HEADER_LEN];
int8store(buf + R_POS_OFFSET, pos);
- return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
- my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
+ return (write_header(file, ROTATE_HEADER_LEN + ident_len) ||
+ my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
+ my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
}
-
+#endif
/*
Rotate_log_event::exec_event()
- Got a rotate log even from the master
+ Got a rotate log event from the master
IMPLEMENTATION
This is mainly used so that we can later figure out the logname and
position for the master.
- We can't rotate the slave as this will cause infinitive rotations
+ We can't rotate the slave's BINlog as this will cause infinitive rotations
in a A -> B -> A setup.
+ The NOTES below is a wrong comment which will disappear when 4.1 is merged.
RETURN VALUES
0 ok
@@ -2053,7 +2972,7 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
DBUG_ENTER("Rotate_log_event::exec_event");
pthread_mutex_lock(&rli->data_lock);
- rli->event_relay_log_pos += get_event_len();
+ rli->event_relay_log_pos= my_b_tell(rli->cur_log);
/*
If we are in a transaction: the only normal case is when the I/O thread was
copying a big transaction, then it was stopped and restarted: we have this
@@ -2065,15 +2984,31 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
COMMIT or ROLLBACK
In that case, we don't want to touch the coordinates which correspond to
the beginning of the transaction.
+ Starting from 5.0.0, there also are some rotates from the slave itself, in
+ the relay log.
*/
if (!(thd->options & OPTION_BEGIN))
{
memcpy(rli->group_master_log_name, new_log_ident, ident_len+1);
rli->notify_group_master_log_name_update();
- rli->group_master_log_pos = pos;
- rli->group_relay_log_pos = rli->event_relay_log_pos;
- DBUG_PRINT("info", ("group_master_log_pos: %lu",
+ rli->group_master_log_pos= pos;
+ rli->group_relay_log_pos= rli->event_relay_log_pos;
+ DBUG_PRINT("info", ("group_master_log_name: '%s' group_master_log_pos:\
+%lu",
+ rli->group_master_log_name,
(ulong) rli->group_master_log_pos));
+ /*
+ Reset thd->options and sql_mode etc, because this could be the signal of
+ a master's downgrade from 5.0 to 4.0.
+ However, no need to reset description_event_for_exec: indeed, if the next
+ master is 5.0 (even 5.0.1) we will soon get a Format_desc; if the next
+ master is 4.0 then the events are in the slave's format (conversion).
+ */
+ set_slave_thread_options(thd);
+ set_slave_thread_default_charset(thd, rli);
+ thd->variables.sql_mode= global_system_variables.sql_mode;
+ thd->variables.auto_increment_increment=
+ thd->variables.auto_increment_offset= 1;
}
pthread_mutex_unlock(&rli->data_lock);
pthread_cond_broadcast(&rli->data_cond);
@@ -2107,12 +3042,13 @@ void Intvar_log_event::pack_info(Protocol *protocol)
Intvar_log_event::Intvar_log_event()
*/
-Intvar_log_event::Intvar_log_event(const char* buf, bool old_format)
- :Log_event(buf, old_format)
+Intvar_log_event::Intvar_log_event(const char* buf,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event)
{
- buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
- type = buf[I_TYPE_OFFSET];
- val = uint8korr(buf+I_VAL_OFFSET);
+ buf+= description_event->common_header_len;
+ type= buf[I_TYPE_OFFSET];
+ val= uint8korr(buf+I_VAL_OFFSET);
}
@@ -2131,16 +3067,19 @@ const char* Intvar_log_event::get_var_type_name()
/*
- Intvar_log_event::write_data()
+ Intvar_log_event::write()
*/
-int Intvar_log_event::write_data(IO_CACHE* file)
+#ifndef MYSQL_CLIENT
+bool Intvar_log_event::write(IO_CACHE* file)
{
- char buf[9];
- buf[I_TYPE_OFFSET] = type;
+ byte buf[9];
+ buf[I_TYPE_OFFSET]= (byte) type;
int8store(buf + I_VAL_OFFSET, val);
- return my_b_safe_write(file, (byte*) buf, sizeof(buf));
+ return (write_header(file, sizeof(buf)) ||
+ my_b_safe_write(file, buf, sizeof(buf)));
}
+#endif
/*
@@ -2148,7 +3087,8 @@ int Intvar_log_event::write_data(IO_CACHE* file)
*/
#ifdef MYSQL_CLIENT
-void Intvar_log_event::print(FILE* file, bool short_form, char* last_db)
+void Intvar_log_event::print(FILE* file, bool short_form,
+ LAST_EVENT_INFO* last_event_info)
{
char llbuff[22];
const char *msg;
@@ -2191,7 +3131,7 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
thd->next_insert_id = val;
break;
}
- rli->inc_event_relay_log_pos(get_event_len());
+ rli->inc_event_relay_log_pos();
return 0;
}
#endif
@@ -2214,26 +3154,30 @@ void Rand_log_event::pack_info(Protocol *protocol)
#endif
-Rand_log_event::Rand_log_event(const char* buf, bool old_format)
- :Log_event(buf, old_format)
+Rand_log_event::Rand_log_event(const char* buf,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event)
{
- buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
- seed1 = uint8korr(buf+RAND_SEED1_OFFSET);
- seed2 = uint8korr(buf+RAND_SEED2_OFFSET);
+ buf+= description_event->common_header_len;
+ seed1= uint8korr(buf+RAND_SEED1_OFFSET);
+ seed2= uint8korr(buf+RAND_SEED2_OFFSET);
}
-int Rand_log_event::write_data(IO_CACHE* file)
+#ifndef MYSQL_CLIENT
+bool Rand_log_event::write(IO_CACHE* file)
{
- char buf[16];
+ byte buf[16];
int8store(buf + RAND_SEED1_OFFSET, seed1);
int8store(buf + RAND_SEED2_OFFSET, seed2);
- return my_b_safe_write(file, (byte*) buf, sizeof(buf));
+ return (write_header(file, sizeof(buf)) ||
+ my_b_safe_write(file, buf, sizeof(buf)));
}
+#endif
#ifdef MYSQL_CLIENT
-void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
+void Rand_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
{
char llbuff[22],llbuff2[22];
if (!short_form)
@@ -2253,13 +3197,83 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli)
{
thd->rand.seed1= (ulong) seed1;
thd->rand.seed2= (ulong) seed2;
- rli->inc_event_relay_log_pos(get_event_len());
+ rli->inc_event_relay_log_pos();
return 0;
}
#endif /* !MYSQL_CLIENT */
/**************************************************************************
+ Xid_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Xid_log_event::pack_info(Protocol *protocol)
+{
+ char buf[128], *pos;
+ pos= strmov(buf, "COMMIT /* xid=");
+ pos= longlong10_to_str(xid, pos, 10);
+ pos= strmov(pos, " */");
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+#endif
+
+/*
+ NOTE it's ok not to use int8store here,
+ as long as xid_t::set(ulonglong) and
+ xid_t::get_my_xid doesn't do it either
+
+ we don't care about actual values of xids as long as
+ identical numbers compare identically
+*/
+
+Xid_log_event::
+Xid_log_event(const char* buf,
+ const Format_description_log_event *description_event)
+ :Log_event(buf, description_event)
+{
+ buf+= description_event->common_header_len;
+ memcpy((char*) &xid, buf, sizeof(xid));
+}
+
+
+#ifndef MYSQL_CLIENT
+bool Xid_log_event::write(IO_CACHE* file)
+{
+ return write_header(file, sizeof(xid)) ||
+ my_b_safe_write(file, (byte*) &xid, sizeof(xid));
+}
+#endif
+
+
+#ifdef MYSQL_CLIENT
+void Xid_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
+{
+ if (!short_form)
+ {
+ char buf[64];
+ longlong10_to_str(xid, buf, 10);
+
+ print_header(file);
+ fprintf(file, "\tXid = %s\n", buf);
+ fflush(file);
+ }
+ fprintf(file, "COMMIT;\n");
+}
+#endif /* MYSQL_CLIENT */
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int Xid_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ /* For a slave Xid_log_event is COMMIT */
+ mysql_log.write(thd,COM_QUERY,"COMMIT /* implicit, from Xid_log_event */");
+ return end_trans(thd, COMMIT) || Log_event::exec_event(rli);
+}
+#endif /* !MYSQL_CLIENT */
+
+
+/**************************************************************************
User_var_log_event methods
**************************************************************************/
@@ -2290,6 +3304,16 @@ void User_var_log_event::pack_info(Protocol* protocol)
buf= my_malloc(val_offset + 22, MYF(MY_WME));
event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf;
break;
+ case DECIMAL_RESULT:
+ {
+ buf= my_malloc(val_offset + DECIMAL_MAX_STR_LENGTH, MYF(MY_WME));
+ String str(buf+val_offset, DECIMAL_MAX_STR_LENGTH, &my_charset_bin);
+ my_decimal dec;
+ binary2my_decimal(E_DEC_FATAL_ERROR, val+2, &dec, val[0], val[1]);
+ my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str);
+ event_len= str.length() + val_offset;
+ break;
+ }
case STRING_RESULT:
/* 15 is for 'COLLATE' and other chars */
buf= my_malloc(event_len+val_len*2+1+2*MY_CS_NAME_SIZE+15, MYF(MY_WME));
@@ -2324,10 +3348,12 @@ void User_var_log_event::pack_info(Protocol* protocol)
#endif /* !MYSQL_CLIENT */
-User_var_log_event::User_var_log_event(const char* buf, bool old_format)
- :Log_event(buf, old_format)
+User_var_log_event::
+User_var_log_event(const char* buf,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event)
{
- buf+= (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
+ buf+= description_event->common_header_len;
name_len= uint4korr(buf);
name= (char *) buf + UV_NAME_LEN_SIZE;
buf+= UV_NAME_LEN_SIZE + name_len;
@@ -2351,13 +3377,15 @@ User_var_log_event::User_var_log_event(const char* buf, bool old_format)
}
-int User_var_log_event::write_data(IO_CACHE* file)
+#ifndef MYSQL_CLIENT
+bool User_var_log_event::write(IO_CACHE* file)
{
char buf[UV_NAME_LEN_SIZE];
char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
- char buf2[8], *pos= buf2;
+ char buf2[max(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
uint buf1_length;
+ ulong event_length;
int4store(buf, name_len);
@@ -2370,8 +3398,6 @@ int User_var_log_event::write_data(IO_CACHE* file)
{
buf1[1]= type;
int4store(buf1 + 2, charset_number);
- int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
- buf1_length= 10;
switch (type) {
case REAL_RESULT:
@@ -2380,6 +3406,16 @@ int User_var_log_event::write_data(IO_CACHE* file)
case INT_RESULT:
int8store(buf2, *(longlong*) val);
break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal *dec= (my_decimal *)val;
+ dec->fix_buffer_pointer();
+ buf2[0]= (char)(dec->intg + dec->frac);
+ buf2[1]= (char)dec->frac;
+ decimal2bin((decimal_t*)val, buf2+2, buf2[0], buf2[1]);
+ val_len= decimal_bin_size(buf2[0], buf2[1]) + 2;
+ break;
+ }
case STRING_RESULT:
pos= val;
break;
@@ -2388,12 +3424,20 @@ int User_var_log_event::write_data(IO_CACHE* file)
DBUG_ASSERT(1);
return 0;
}
+ int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
+ buf1_length= 10;
}
- return (my_b_safe_write(file, (byte*) buf, sizeof(buf)) ||
+
+ /* Length of the whole event */
+ event_length= sizeof(buf)+ name_len + buf1_length + val_len;
+
+ return (write_header(file, event_length) ||
+ my_b_safe_write(file, (byte*) buf, sizeof(buf)) ||
my_b_safe_write(file, (byte*) name, name_len) ||
my_b_safe_write(file, (byte*) buf1, buf1_length) ||
my_b_safe_write(file, (byte*) pos, val_len));
}
+#endif
/*
@@ -2401,7 +3445,7 @@ int User_var_log_event::write_data(IO_CACHE* file)
*/
#ifdef MYSQL_CLIENT
-void User_var_log_event::print(FILE* file, bool short_form, char* last_db)
+void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
{
if (!short_form)
{
@@ -2430,6 +3474,23 @@ void User_var_log_event::print(FILE* file, bool short_form, char* last_db)
longlong10_to_str(uint8korr(val), int_buf, -10);
fprintf(file, ":=%s;\n", int_buf);
break;
+ case DECIMAL_RESULT:
+ {
+ char str_buf[200];
+ int str_len= sizeof(str_buf) - 1;
+ int precision= (int)val[0];
+ int scale= (int)val[1];
+ decimal_digit_t dec_buf[10];
+ decimal_t dec;
+ dec.len= 10;
+ dec.buf= dec_buf;
+
+ bin2decimal(val+2, &dec, precision, scale);
+ decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
+ str_buf[str_len]= 0;
+ fprintf(file, ":=%s;\n",str_buf);
+ break;
+ }
case STRING_RESULT:
{
/*
@@ -2506,7 +3567,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
switch (type) {
case REAL_RESULT:
float8get(real_val, val);
- it= new Item_real(real_val);
+ it= new Item_float(real_val);
val= (char*) &real_val; // Pointer to value in native format
val_len= 8;
break;
@@ -2516,6 +3577,14 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
val= (char*) &int_val; // Pointer to value in native format
val_len= 8;
break;
+ case DECIMAL_RESULT:
+ {
+ Item_decimal *dec= new Item_decimal(val+2, val[0], val[1]);
+ it= dec;
+ val= (char *)dec->val_decimal(NULL);
+ val_len= sizeof(my_decimal);
+ break;
+ }
case STRING_RESULT:
it= new Item_string(val, val_len, charset);
break;
@@ -2539,7 +3608,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT);
free_root(thd->mem_root,0);
- rli->inc_event_relay_log_pos(get_event_len());
+ rli->inc_event_relay_log_pos();
return 0;
}
#endif /* !MYSQL_CLIENT */
@@ -2551,7 +3620,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
#ifdef HAVE_REPLICATION
#ifdef MYSQL_CLIENT
-void Unknown_log_event::print(FILE* file, bool short_form, char* last_db)
+void Unknown_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
{
if (short_form)
return;
@@ -2581,12 +3650,12 @@ void Slave_log_event::pack_info(Protocol *protocol)
#ifndef MYSQL_CLIENT
Slave_log_event::Slave_log_event(THD* thd_arg,
struct st_relay_log_info* rli)
- :Log_event(thd_arg, 0, 0), mem_pool(0), master_host(0)
+ :Log_event(thd_arg, 0, 0) , mem_pool(0), master_host(0)
{
DBUG_ENTER("Slave_log_event");
if (!rli->inited) // QQ When can this happen ?
DBUG_VOID_RETURN;
-
+
MASTER_INFO* mi = rli->mi;
// TODO: re-write this better without holding both locks at the same time
pthread_mutex_lock(&mi->data_lock);
@@ -2622,7 +3691,7 @@ Slave_log_event::~Slave_log_event()
#ifdef MYSQL_CLIENT
-void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
+void Slave_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
{
char llbuff[22];
if (short_form)
@@ -2642,13 +3711,18 @@ int Slave_log_event::get_data_size()
}
-int Slave_log_event::write_data(IO_CACHE* file)
+#ifndef MYSQL_CLIENT
+bool Slave_log_event::write(IO_CACHE* file)
{
+ ulong event_length= get_data_size();
int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos);
int2store(mem_pool + SL_MASTER_PORT_OFFSET, master_port);
// log and host are already there
- return my_b_safe_write(file, (byte*)mem_pool, get_data_size());
+
+ return (write_header(file, event_length) ||
+ my_b_safe_write(file, (byte*) mem_pool, event_length));
}
+#endif
void Slave_log_event::init_from_mem_pool(int data_size)
@@ -2668,12 +3742,13 @@ void Slave_log_event::init_from_mem_pool(int data_size)
}
-Slave_log_event::Slave_log_event(const char* buf, int event_len)
- :Log_event(buf,0),mem_pool(0),master_host(0)
+/* This code is not used, so has not been updated to be format-tolerant */
+Slave_log_event::Slave_log_event(const char* buf, uint event_len)
+ :Log_event(buf,0) /*unused event*/ ,mem_pool(0),master_host(0)
{
- event_len -= LOG_EVENT_HEADER_LEN;
- if (event_len < 0)
+ if (event_len < LOG_EVENT_HEADER_LEN)
return;
+ event_len -= LOG_EVENT_HEADER_LEN;
if (!(mem_pool = (char*) my_malloc(event_len + 1, MYF(MY_WME))))
return;
memcpy(mem_pool, buf + LOG_EVENT_HEADER_LEN, event_len);
@@ -2701,7 +3776,7 @@ int Slave_log_event::exec_event(struct st_relay_log_info* rli)
*/
#ifdef MYSQL_CLIENT
-void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
+void Stop_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info)
{
if (short_form)
return;
@@ -2716,14 +3791,14 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
/*
Stop_log_event::exec_event()
- The master stopped.
+ The master stopped.
We used to clean up all temporary tables but this is useless as, as the
- master has shut down properly, it has written all DROP TEMPORARY TABLE and DO
- RELEASE_LOCK (prepared statements' deletion is TODO).
+ master has shut down properly, it has written all DROP TEMPORARY TABLE
+ (prepared statements' deletion is TODO only when we binlog prep stmts).
We used to clean up slave_load_tmpdir, but this is useless as it has been
cleared at the end of LOAD DATA INFILE.
So we have nothing to do here.
- The place were we must do this cleaning is in Start_log_event::exec_event(),
+ The place were we must do this cleaning is in Start_log_event_v3::exec_event(),
not here. Because if we come here, the master was sane.
*/
@@ -2737,8 +3812,13 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli)
could give false triggers in MASTER_POS_WAIT() that we have reached
the target position when in fact we have not.
*/
- rli->inc_group_relay_log_pos(get_event_len(), 0);
- flush_relay_log_info(rli);
+ if (thd->options & OPTION_BEGIN)
+ rli->inc_event_relay_log_pos();
+ else
+ {
+ rli->inc_group_relay_log_pos(0);
+ flush_relay_log_info(rli);
+ }
return 0;
}
#endif /* !MYSQL_CLIENT */
@@ -2769,20 +3849,19 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex,
sql_ex.force_new_format();
DBUG_VOID_RETURN;
}
-#endif /* !MYSQL_CLIENT */
/*
Create_file_log_event::write_data_body()
*/
-int Create_file_log_event::write_data_body(IO_CACHE* file)
+bool Create_file_log_event::write_data_body(IO_CACHE* file)
{
- int res;
- if ((res = Load_log_event::write_data_body(file)) || fake_base)
+ bool res;
+ if ((res= Load_log_event::write_data_body(file)) || fake_base)
return res;
return (my_b_safe_write(file, (byte*) "", 1) ||
- my_b_safe_write(file, (byte*) block, block_len));
+ my_b_safe_write(file, (byte*) block, block_len));
}
@@ -2790,14 +3869,14 @@ int Create_file_log_event::write_data_body(IO_CACHE* file)
Create_file_log_event::write_data_header()
*/
-int Create_file_log_event::write_data_header(IO_CACHE* file)
+bool Create_file_log_event::write_data_header(IO_CACHE* file)
{
- int res;
- if ((res = Load_log_event::write_data_header(file)) || fake_base)
- return res;
+ bool res;
byte buf[CREATE_FILE_HEADER_LEN];
+ if ((res= Load_log_event::write_data_header(file)) || fake_base)
+ return res;
int4store(buf + CF_FILE_ID_OFFSET, file_id);
- return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN);
+ return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN) != 0;
}
@@ -2805,42 +3884,58 @@ int Create_file_log_event::write_data_header(IO_CACHE* file)
Create_file_log_event::write_base()
*/
-int Create_file_log_event::write_base(IO_CACHE* file)
+bool Create_file_log_event::write_base(IO_CACHE* file)
{
- int res;
- fake_base = 1; // pretend we are Load event
- res = write(file);
- fake_base = 0;
+ bool res;
+ fake_base= 1; // pretend we are Load event
+ res= write(file);
+ fake_base= 0;
return res;
}
+#endif /* !MYSQL_CLIENT */
/*
Create_file_log_event ctor
*/
-Create_file_log_event::Create_file_log_event(const char* buf, int len,
- bool old_format)
- :Load_log_event(buf,0,old_format),fake_base(0),block(0),inited_from_old(0)
+Create_file_log_event::Create_file_log_event(const char* buf, uint len,
+ const Format_description_log_event* description_event)
+ :Load_log_event(buf,0,description_event),fake_base(0),block(0),inited_from_old(0)
{
- int block_offset;
- DBUG_ENTER("Create_file_log_event");
-
- /*
- We must make copy of 'buf' as this event may have to live over a
- rotate log entry when used in mysqlbinlog
- */
+ DBUG_ENTER("Create_file_log_event::Create_file_log_event(char*,...)");
+ uint block_offset;
+ uint header_len= description_event->common_header_len;
+ uint8 load_header_len= description_event->post_header_len[LOAD_EVENT-1];
+ uint8 create_file_header_len= description_event->post_header_len[CREATE_FILE_EVENT-1];
if (!(event_buf= my_memdup((byte*) buf, len, MYF(MY_WME))) ||
- (copy_log_event(event_buf, len, old_format)))
+ copy_log_event(event_buf,len,
+ ((buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
+ load_header_len + header_len :
+ (fake_base ? (header_len+load_header_len) :
+ (header_len+load_header_len) +
+ create_file_header_len)),
+ description_event))
DBUG_VOID_RETURN;
-
- if (!old_format)
+ if (description_event->binlog_version!=1)
{
- file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN +
- + LOAD_HEADER_LEN + CF_FILE_ID_OFFSET);
- // + 1 for \0 terminating fname
- block_offset = (LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() +
- CREATE_FILE_HEADER_LEN + 1);
+ file_id= uint4korr(buf +
+ header_len +
+ load_header_len + CF_FILE_ID_OFFSET);
+ /*
+ Note that it's ok to use get_data_size() below, because it is computed
+ with values we have already read from this event (because we called
+ copy_log_event()); we are not using slave's format info to decode
+ master's format, we are really using master's format info.
+ Anyway, both formats should be identical (except the common_header_len)
+ as these Load events are not changed between 4.0 and 5.0 (as logging of
+ LOAD DATA INFILE does not use Load_log_event in 5.0).
+
+ The + 1 is for \0 terminating fname
+ */
+ block_offset= (description_event->common_header_len +
+ Load_log_event::get_data_size() +
+ create_file_header_len + 1);
if (len < block_offset)
return;
block = (char*)buf + block_offset;
@@ -2861,18 +3956,18 @@ Create_file_log_event::Create_file_log_event(const char* buf, int len,
#ifdef MYSQL_CLIENT
void Create_file_log_event::print(FILE* file, bool short_form,
- char* last_db, bool enable_local)
+ LAST_EVENT_INFO* last_event_info, bool enable_local)
{
if (short_form)
{
if (enable_local && check_fname_outside_temp_buf())
- Load_log_event::print(file, 1, last_db);
+ Load_log_event::print(file, 1, last_event_info);
return;
}
if (enable_local)
{
- Load_log_event::print(file, short_form, last_db, !check_fname_outside_temp_buf());
+ Load_log_event::print(file, short_form, last_event_info, !check_fname_outside_temp_buf());
/*
That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
SHOW BINLOG EVENTS we don't.
@@ -2885,9 +3980,9 @@ void Create_file_log_event::print(FILE* file, bool short_form,
void Create_file_log_event::print(FILE* file, bool short_form,
- char* last_db)
+ LAST_EVENT_INFO* last_event_info)
{
- print(file,short_form,last_db,0);
+ print(file,short_form,last_event_info,0);
}
#endif /* MYSQL_CLIENT */
@@ -3008,30 +4103,38 @@ Append_block_log_event::Append_block_log_event(THD* thd_arg, const char* db_arg,
Append_block_log_event ctor
*/
-Append_block_log_event::Append_block_log_event(const char* buf, int len)
- :Log_event(buf, 0),block(0)
+Append_block_log_event::Append_block_log_event(const char* buf, uint len,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event),block(0)
{
- DBUG_ENTER("Append_block_log_event");
- if ((uint)len < APPEND_BLOCK_EVENT_OVERHEAD)
+ DBUG_ENTER("Append_block_log_event::Append_block_log_event(char*,...)");
+ uint8 common_header_len= description_event->common_header_len;
+ uint8 append_block_header_len=
+ description_event->post_header_len[APPEND_BLOCK_EVENT-1];
+ uint total_header_len= common_header_len+append_block_header_len;
+ if (len < total_header_len)
DBUG_VOID_RETURN;
- file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
- block = (char*)buf + APPEND_BLOCK_EVENT_OVERHEAD;
- block_len = len - APPEND_BLOCK_EVENT_OVERHEAD;
+ file_id= uint4korr(buf + common_header_len + AB_FILE_ID_OFFSET);
+ block= (char*)buf + total_header_len;
+ block_len= len - total_header_len;
DBUG_VOID_RETURN;
}
/*
- Append_block_log_event::write_data()
+ Append_block_log_event::write()
*/
-int Append_block_log_event::write_data(IO_CACHE* file)
+#ifndef MYSQL_CLIENT
+bool Append_block_log_event::write(IO_CACHE* file)
{
byte buf[APPEND_BLOCK_HEADER_LEN];
int4store(buf + AB_FILE_ID_OFFSET, file_id);
- return (my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
+ return (write_header(file, APPEND_BLOCK_HEADER_LEN + block_len) ||
+ my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
my_b_safe_write(file, (byte*) block, block_len));
}
+#endif
/*
@@ -3040,14 +4143,14 @@ int Append_block_log_event::write_data(IO_CACHE* file)
#ifdef MYSQL_CLIENT
void Append_block_log_event::print(FILE* file, bool short_form,
- char* last_db)
+ LAST_EVENT_INFO* last_event_info)
{
if (short_form)
return;
print_header(file);
fputc('\n', file);
- fprintf(file, "#Append_block: file_id: %d block_len: %d\n",
- file_id, block_len);
+ fprintf(file, "#%s: file_id: %d block_len: %d\n",
+ get_type_str(), file_id, block_len);
}
#endif /* MYSQL_CLIENT */
@@ -3066,14 +4169,21 @@ void Append_block_log_event::pack_info(Protocol *protocol)
block_len));
protocol->store(buf, length, &my_charset_bin);
}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
/*
+ Append_block_log_event::get_create_or_append()
+*/
+
+int Append_block_log_event::get_create_or_append() const
+{
+ return 0; /* append to the file, fail if not exists */
+}
+
+/*
Append_block_log_event::exec_event()
*/
-#if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
{
char proc_info[17+FN_REFLEN+10], *fname= proc_info+17;
@@ -3085,14 +4195,32 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
memcpy(p, ".data", 6);
strnmov(proc_info, "Making temp file ", 17); // no end 0
thd->proc_info= proc_info;
- if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY|O_NOFOLLOW, MYF(MY_WME))) < 0)
+ if (get_create_or_append())
{
- slave_print_error(rli,my_errno, "Error in Append_block event: could not open file '%s'", fname);
+ my_delete(fname, MYF(0)); // old copy may exist already
+ if ((fd= my_create(fname, CREATE_MODE,
+ O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+ MYF(MY_WME))) < 0)
+ {
+ slave_print_error(rli, my_errno,
+ "Error in %s event: could not create file '%s'",
+ get_type_str(), fname);
+ goto err;
+ }
+ }
+ else if ((fd = my_open(fname, O_WRONLY | O_APPEND | O_BINARY | O_NOFOLLOW,
+ MYF(MY_WME))) < 0)
+ {
+ slave_print_error(rli, my_errno,
+ "Error in %s event: could not open file '%s'",
+ get_type_str(), fname);
goto err;
}
if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
{
- slave_print_error(rli,my_errno, "Error in Append_block event: write to '%s' failed", fname);
+ slave_print_error(rli, my_errno,
+ "Error in %s event: write to '%s' failed",
+ get_type_str(), fname);
goto err;
}
error=0;
@@ -3126,25 +4254,31 @@ Delete_file_log_event::Delete_file_log_event(THD *thd_arg, const char* db_arg,
Delete_file_log_event ctor
*/
-Delete_file_log_event::Delete_file_log_event(const char* buf, int len)
- :Log_event(buf, 0),file_id(0)
+Delete_file_log_event::Delete_file_log_event(const char* buf, uint len,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event),file_id(0)
{
- if ((uint)len < DELETE_FILE_EVENT_OVERHEAD)
+ uint8 common_header_len= description_event->common_header_len;
+ uint8 delete_file_header_len= description_event->post_header_len[DELETE_FILE_EVENT-1];
+ if (len < (uint)(common_header_len + delete_file_header_len))
return;
- file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
+ file_id= uint4korr(buf + common_header_len + DF_FILE_ID_OFFSET);
}
/*
- Delete_file_log_event::write_data()
+ Delete_file_log_event::write()
*/
-int Delete_file_log_event::write_data(IO_CACHE* file)
+#ifndef MYSQL_CLIENT
+bool Delete_file_log_event::write(IO_CACHE* file)
{
byte buf[DELETE_FILE_HEADER_LEN];
int4store(buf + DF_FILE_ID_OFFSET, file_id);
- return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN);
+ return (write_header(file, sizeof(buf)) ||
+ my_b_safe_write(file, buf, sizeof(buf)));
}
+#endif
/*
@@ -3153,7 +4287,7 @@ int Delete_file_log_event::write_data(IO_CACHE* file)
#ifdef MYSQL_CLIENT
void Delete_file_log_event::print(FILE* file, bool short_form,
- char* last_db)
+ LAST_EVENT_INFO* last_event_info)
{
if (short_form)
return;
@@ -3216,25 +4350,31 @@ Execute_load_log_event::Execute_load_log_event(THD *thd_arg, const char* db_arg,
Execute_load_log_event ctor
*/
-Execute_load_log_event::Execute_load_log_event(const char* buf, int len)
- :Log_event(buf, 0), file_id(0)
+Execute_load_log_event::Execute_load_log_event(const char* buf, uint len,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event), file_id(0)
{
- if ((uint)len < EXEC_LOAD_EVENT_OVERHEAD)
+ uint8 common_header_len= description_event->common_header_len;
+ uint8 exec_load_header_len= description_event->post_header_len[EXEC_LOAD_EVENT-1];
+ if (len < (uint)(common_header_len+exec_load_header_len))
return;
- file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET);
+ file_id= uint4korr(buf + common_header_len + EL_FILE_ID_OFFSET);
}
/*
- Execute_load_log_event::write_data()
+ Execute_load_log_event::write()
*/
-int Execute_load_log_event::write_data(IO_CACHE* file)
+#ifndef MYSQL_CLIENT
+bool Execute_load_log_event::write(IO_CACHE* file)
{
byte buf[EXEC_LOAD_HEADER_LEN];
int4store(buf + EL_FILE_ID_OFFSET, file_id);
- return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN);
+ return (write_header(file, sizeof(buf)) ||
+ my_b_safe_write(file, buf, sizeof(buf)));
}
+#endif
/*
@@ -3243,7 +4383,7 @@ int Execute_load_log_event::write_data(IO_CACHE* file)
#ifdef MYSQL_CLIENT
void Execute_load_log_event::print(FILE* file, bool short_form,
- char* last_db)
+ LAST_EVENT_INFO* last_event_info)
{
if (short_form)
return;
@@ -3282,7 +4422,8 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
Load_log_event* lev = 0;
memcpy(p, ".info", 6);
- if ((fd = my_open(fname, O_RDONLY|O_BINARY|O_NOFOLLOW, MYF(MY_WME))) < 0 ||
+ if ((fd = my_open(fname, O_RDONLY | O_BINARY | O_NOFOLLOW,
+ MYF(MY_WME))) < 0 ||
init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
MYF(MY_WME|MY_NABP)))
{
@@ -3290,8 +4431,8 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
goto err;
}
if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
- (pthread_mutex_t*)0,
- (bool)0)) ||
+ (pthread_mutex_t*)0,
+ rli->relay_log.description_event_for_exec)) ||
lev->get_type_code() != NEW_LOAD_EVENT)
{
slave_print_error(rli,0, "Error in Exec_load event: file '%s' appears corrupted", fname);
@@ -3306,15 +4447,7 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
mysql_load()).
*/
-#if MYSQL_VERSION_ID < 40100
- rli->future_master_log_pos= log_pos + get_event_len() -
- (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0);
-#elif MYSQL_VERSION_ID < 50000
- rli->future_group_master_log_pos= log_pos + get_event_len() -
- (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0);
-#else
- rli->future_group_master_log_pos= log_pos;
-#endif
+ rli->future_group_master_log_pos= log_pos;
if (lev->exec_event(0,rli,1))
{
/*
@@ -3365,6 +4498,223 @@ err:
/**************************************************************************
+ Begin_load_query_log_event methods
+**************************************************************************/
+
+#ifndef MYSQL_CLIENT
+Begin_load_query_log_event::
+Begin_load_query_log_event(THD* thd_arg, const char* db_arg, char* block_arg,
+ uint block_len_arg, bool using_trans)
+ :Append_block_log_event(thd_arg, db_arg, block_arg, block_len_arg,
+ using_trans)
+{
+ file_id= thd_arg->file_id= mysql_bin_log.next_file_id();
+}
+#endif
+
+
+Begin_load_query_log_event::
+Begin_load_query_log_event(const char* buf, uint len,
+ const Format_description_log_event* desc_event)
+ :Append_block_log_event(buf, len, desc_event)
+{
+}
+
+
+#if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int Begin_load_query_log_event::get_create_or_append() const
+{
+ return 1; /* create the file */
+}
+#endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
+
+
+/**************************************************************************
+ Execute_load_query_log_event methods
+**************************************************************************/
+
+
+#ifndef MYSQL_CLIENT
+Execute_load_query_log_event::
+Execute_load_query_log_event(THD* thd_arg, const char* query_arg,
+ ulong query_length_arg, uint fn_pos_start_arg,
+ uint fn_pos_end_arg,
+ enum_load_dup_handling dup_handling_arg,
+ bool using_trans, bool suppress_use):
+ Query_log_event(thd_arg, query_arg, query_length_arg, using_trans,
+ suppress_use),
+ file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg),
+ fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg)
+{
+}
+#endif /* !MYSQL_CLIENT */
+
+
+Execute_load_query_log_event::
+Execute_load_query_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* desc_event):
+ Query_log_event(buf, event_len, desc_event, EXECUTE_LOAD_QUERY_EVENT),
+ file_id(0), fn_pos_start(0), fn_pos_end(0)
+{
+ if (!Query_log_event::is_valid())
+ return;
+
+ buf+= desc_event->common_header_len;
+
+ fn_pos_start= uint4korr(buf + ELQ_FN_POS_START_OFFSET);
+ fn_pos_end= uint4korr(buf + ELQ_FN_POS_END_OFFSET);
+ dup_handling= (enum_load_dup_handling)(*(buf + ELQ_DUP_HANDLING_OFFSET));
+
+ if (fn_pos_start > q_len || fn_pos_end > q_len ||
+ dup_handling > LOAD_DUP_REPLACE)
+ return;
+
+ file_id= uint4korr(buf + ELQ_FILE_ID_OFFSET);
+}
+
+
+ulong Execute_load_query_log_event::get_post_header_size_for_derived()
+{
+ return EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN;
+}
+
+
+#ifndef MYSQL_CLIENT
+bool
+Execute_load_query_log_event::write_post_header_for_derived(IO_CACHE* file)
+{
+ char buf[EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN];
+ int4store(buf, file_id);
+ int4store(buf + 4, fn_pos_start);
+ int4store(buf + 4 + 4, fn_pos_end);
+ *(buf + 4 + 4 + 4)= (char)dup_handling;
+ return my_b_safe_write(file, (byte*) buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
+}
+#endif
+
+
+#ifdef MYSQL_CLIENT
+void Execute_load_query_log_event::print(FILE* file, bool short_form,
+ LAST_EVENT_INFO* last_event_info)
+{
+ print(file, short_form, last_event_info, 0);
+}
+
+
+void Execute_load_query_log_event::print(FILE* file, bool short_form,
+ LAST_EVENT_INFO* last_event_info,
+ const char *local_fname)
+{
+ print_query_header(file, short_form, last_event_info);
+
+ if (local_fname)
+ {
+ my_fwrite(file, (byte*) query, fn_pos_start, MYF(MY_NABP | MY_WME));
+ fprintf(file, " LOCAL INFILE \'");
+ fprintf(file, local_fname);
+ fprintf(file, "\'");
+ if (dup_handling == LOAD_DUP_REPLACE)
+ fprintf(file, " REPLACE");
+ fprintf(file, " INTO");
+ my_fwrite(file, (byte*) query + fn_pos_end, q_len-fn_pos_end,
+ MYF(MY_NABP | MY_WME));
+ fprintf(file, ";\n");
+ }
+ else
+ {
+ my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
+ fprintf(file, ";\n");
+ }
+
+ if (!short_form)
+ fprintf(file, "# file_id: %d \n", file_id);
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Execute_load_query_log_event::pack_info(Protocol *protocol)
+{
+ char *buf, *pos;
+ if (!(buf= my_malloc(9 + db_len + q_len + 10 + 21, MYF(MY_WME))))
+ return;
+ pos= buf;
+ if (db && db_len)
+ {
+ pos= strmov(buf, "use `");
+ memcpy(pos, db, db_len);
+ pos= strmov(pos+db_len, "`; ");
+ }
+ if (query && q_len)
+ {
+ memcpy(pos, query, q_len);
+ pos+= q_len;
+ }
+ pos= strmov(pos, " ;file_id=");
+ pos= int10_to_str((long) file_id, pos, 10);
+ protocol->store(buf, pos-buf, &my_charset_bin);
+ my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+}
+
+
+int
+Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ char *p;
+ char *buf;
+ char *fname;
+ char *fname_end;
+ int error;
+
+ /* Replace filename and LOCAL keyword in query before executing it */
+ if (!(buf = my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) +
+ (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME))))
+ {
+ slave_print_error(rli, my_errno, "Not enough memory");
+ return 1;
+ }
+
+ p= buf;
+ memcpy(p, query, fn_pos_start);
+ p+= fn_pos_start;
+ fname= (p= strmake(p, " INFILE \'", 9));
+ p= slave_load_file_stem(p, file_id, server_id);
+ fname_end= (p= strmake(p, ".data", 5));
+ *(p++)='\'';
+ switch (dup_handling)
+ {
+ case LOAD_DUP_IGNORE:
+ p= strmake(p, " IGNORE", 7);
+ break;
+ case LOAD_DUP_REPLACE:
+ p= strmake(p, " REPLACE", 8);
+ break;
+ default:
+ /* Ordinary load data */
+ break;
+ }
+ p= strmake(p, " INTO", 5);
+ p= strmake(p, query+fn_pos_end, q_len-fn_pos_end);
+
+ error= Query_log_event::exec_event(rli, buf, p-buf);
+
+ /* Forging file name for deletion in same buffer */
+ *fname_end= 0;
+
+ /*
+ If there was an error the slave is going to stop, leave the
+ file so that we can re-execute this event at START SLAVE.
+ */
+ if (!error)
+ (void) my_delete(fname, MYF(MY_WME));
+
+ my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ return error;
+}
+#endif
+
+
+/**************************************************************************
sql_ex_info methods
**************************************************************************/
@@ -3372,15 +4722,15 @@ err:
sql_ex_info::write_data()
*/
-int sql_ex_info::write_data(IO_CACHE* file)
+bool sql_ex_info::write_data(IO_CACHE* file)
{
if (new_format())
{
- return (write_str(file, field_term, field_term_len) ||
- write_str(file, enclosed, enclosed_len) ||
- write_str(file, line_term, line_term_len) ||
- write_str(file, line_start, line_start_len) ||
- write_str(file, escaped, escaped_len) ||
+ return (write_str(file, field_term, (uint) field_term_len) ||
+ write_str(file, enclosed, (uint) enclosed_len) ||
+ write_str(file, line_term, (uint) line_term_len) ||
+ write_str(file, line_start, (uint) line_start_len) ||
+ write_str(file, escaped, (uint) escaped_len) ||
my_b_safe_write(file,(byte*) &opt_flags,1));
}
else
@@ -3393,7 +4743,7 @@ int sql_ex_info::write_data(IO_CACHE* file)
old_ex.escaped= *escaped;
old_ex.opt_flags= opt_flags;
old_ex.empty_flags=empty_flags;
- return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex));
+ return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex)) != 0;
}
}
@@ -3415,11 +4765,11 @@ char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format)
the case when we have old format because we will be reusing net buffer
to read the actual file before we write out the Create_file event.
*/
- if (read_str(buf, buf_end, field_term, field_term_len) ||
- read_str(buf, buf_end, enclosed, enclosed_len) ||
- read_str(buf, buf_end, line_term, line_term_len) ||
- read_str(buf, buf_end, line_start, line_start_len) ||
- read_str(buf, buf_end, escaped, escaped_len))
+ if (read_str(&buf, buf_end, &field_term, &field_term_len) ||
+ read_str(&buf, buf_end, &enclosed, &enclosed_len) ||
+ read_str(&buf, buf_end, &line_term, &line_term_len) ||
+ read_str(&buf, buf_end, &line_start, &line_start_len) ||
+ read_str(&buf, buf_end, &escaped, &escaped_len))
return 0;
opt_flags = *buf++;
}
diff --git a/sql/log_event.h b/sql/log_event.h
index f848f2ae1b9..2985fcabb50 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@@ -35,12 +35,42 @@
#define LOG_EVENT_OFFSET 4
-#define BINLOG_VERSION 3
+/*
+ 3 is MySQL 4.x; 4 is MySQL 5.0.0.
+ Compared to version 3, version 4 has:
+ - a different Start_log_event, which includes info about the binary log
+ (sizes of headers); this info is included for better compatibility if the
+ master's MySQL version is different from the slave's.
+ - all events have a unique ID (the triplet (server_id, timestamp at server
+ start, other) to be sure an event is not executed more than once in a
+ multimaster setup, example:
+ M1
+ / \
+ v v
+ M2 M3
+ \ /
+ v v
+ S
+ if a query is run on M1, it will arrive twice on S, so we need that S
+ remembers the last unique ID it has processed, to compare and know if the
+ event should be skipped or not. Example of ID: we already have the server id
+ (4 bytes), plus:
+ timestamp_when_the_master_started (4 bytes), a counter (a sequence number
+ which increments every time we write an event to the binlog) (3 bytes).
+ Q: how do we handle when the counter is overflowed and restarts from 0 ?
+
+ - Query and Load (Create or Execute) events may have a more precise timestamp
+ (with microseconds), number of matched/affected/warnings rows
+ and fields of session variables: SQL_MODE,
+ FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, SQL_AUTO_IS_NULL, the collations and
+ charsets, the PASSWORD() version (old/new/...).
+*/
+#define BINLOG_VERSION 4
/*
We could have used SERVER_VERSION_LENGTH, but this introduces an
obscure dependency - if somebody decided to change SERVER_VERSION_LENGTH
- this would have broken the replication protocol
+ this would break the replication protocol
*/
#define ST_SERVER_VER_LEN 50
@@ -49,6 +79,12 @@
TERMINATED etc).
*/
+/*
+ These are flags and structs to handle all the LOAD DATA INFILE options (LINES
+ TERMINATED etc).
+ DUMPFILE_FLAG is probably useless (DUMPFILE is a clause of SELECT, not of LOAD
+ DATA).
+*/
#define DUMPFILE_FLAG 0x1
#define OPT_ENCLOSED_FLAG 0x2
#define REPLACE_FLAG 0x4
@@ -92,18 +128,18 @@ struct sql_ex_info
char* escaped;
int cached_new_format;
uint8 field_term_len,enclosed_len,line_term_len,line_start_len, escaped_len;
- char opt_flags;
+ char opt_flags;
char empty_flags;
-
+
// store in new format even if old is possible
- void force_new_format() { cached_new_format = 1;}
+ void force_new_format() { cached_new_format = 1;}
int data_size()
{
return (new_format() ?
field_term_len + enclosed_len + line_term_len +
line_start_len + escaped_len + 6 : 7);
}
- int write_data(IO_CACHE* file);
+ bool write_data(IO_CACHE* file);
char* init(char* buf,char* buf_end,bool use_new_format);
bool new_format()
{
@@ -127,28 +163,44 @@ struct sql_ex_info
See the #defines below for the format specifics.
- The events which really update data are Query_log_event and
- Load_log_event/Create_file_log_event/Execute_load_log_event (these 3 act
- together to replicate LOAD DATA INFILE, with the help of
- Append_block_log_event which prepares temporary files to load into the table).
+ The events which really update data are Query_log_event,
+ Execute_load_query_log_event and old Load_log_event and
+ Execute_load_log_event events (Execute_load_query is used together with
+ Begin_load_query and Append_block events to replicate LOAD DATA INFILE.
+ Create_file/Append_block/Execute_load (which includes Load_log_event)
+ were used to replicate LOAD DATA before the 5.0.3).
****************************************************************************/
#define LOG_EVENT_HEADER_LEN 19 /* the fixed header length */
#define OLD_HEADER_LEN 13 /* the fixed header length in 3.23 */
+/*
+ Fixed header length, where 4.x and 5.0 agree. That is, 5.0 may have a longer
+ header (it will for sure when we have the unique event's ID), but at least
+ the first 19 bytes are the same in 4.x and 5.0. So when we have the unique
+ event's ID, LOG_EVENT_HEADER_LEN will be something like 26, but
+ LOG_EVENT_MINIMAL_HEADER_LEN will remain 19.
+*/
+#define LOG_EVENT_MINIMAL_HEADER_LEN 19
/* event-specific post-header sizes */
-#define QUERY_HEADER_LEN (4 + 4 + 1 + 2)
+// where 3.23, 4.x and 5.0 agree
+#define QUERY_HEADER_MINIMAL_LEN (4 + 4 + 1 + 2)
+// where 5.0 differs: 2 for len of N-bytes vars.
+#define QUERY_HEADER_LEN (QUERY_HEADER_MINIMAL_LEN + 2)
#define LOAD_HEADER_LEN (4 + 4 + 4 + 1 +1 + 4)
-#define START_HEADER_LEN (2 + ST_SERVER_VER_LEN + 4)
-#define ROTATE_HEADER_LEN 8
+#define START_V3_HEADER_LEN (2 + ST_SERVER_VER_LEN + 4)
+#define ROTATE_HEADER_LEN 8 // this is FROZEN (the Rotate post-header is frozen)
#define CREATE_FILE_HEADER_LEN 4
#define APPEND_BLOCK_HEADER_LEN 4
#define EXEC_LOAD_HEADER_LEN 4
#define DELETE_FILE_HEADER_LEN 4
+#define FORMAT_DESCRIPTION_HEADER_LEN (START_V3_HEADER_LEN+1+LOG_EVENT_TYPES)
+#define EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN (4 + 4 + 4 + 1)
+#define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN)
-/*
- Event header offsets;
+/*
+ Event header offsets;
these point to places inside the fixed header.
*/
@@ -158,11 +210,12 @@ struct sql_ex_info
#define LOG_POS_OFFSET 13
#define FLAGS_OFFSET 17
-/* start event post-header */
+/* start event post-header (for v3 and v4) */
#define ST_BINLOG_VER_OFFSET 0
#define ST_SERVER_VER_OFFSET 2
#define ST_CREATED_OFFSET (ST_SERVER_VER_OFFSET + ST_SERVER_VER_LEN)
+#define ST_COMMON_HEADER_LEN_OFFSET (ST_CREATED_OFFSET + 4)
/* slave event post-header (this event is never written) */
@@ -176,7 +229,29 @@ struct sql_ex_info
#define Q_EXEC_TIME_OFFSET 4
#define Q_DB_LEN_OFFSET 8
#define Q_ERR_CODE_OFFSET 9
+#define Q_STATUS_VARS_LEN_OFFSET 11
#define Q_DATA_OFFSET QUERY_HEADER_LEN
+/* these are codes, not offsets; not more than 256 values (1 byte). */
+#define Q_FLAGS2_CODE 0
+#define Q_SQL_MODE_CODE 1
+#ifndef TO_BE_DELETED
+/*
+ Q_CATALOG_CODE is catalog with end zero stored; it is used only by MySQL
+ 5.0.x where 0<=x<=3.
+*/
+#define Q_CATALOG_CODE 2
+#endif
+#define Q_AUTO_INCREMENT 3
+#define Q_CHARSET_CODE 4
+#define Q_TIME_ZONE_CODE 5
+/*
+ Q_CATALOG_NZ_CODE is catalog withOUT end zero stored; it is used by MySQL
+ 5.0.x where x>=4. Saves one byte in every Query_log_event in binlog,
+ compared to Q_CATALOG_CODE. The reason we didn't simply re-use
+ Q_CATALOG_CODE is that then a 5.0.3 slave of this 5.0.x (x>=4) master would
+ crash (segfault etc) because it would expect a 0 when there is none.
+*/
+#define Q_CATALOG_NZ_CODE 6
/* Intvar event post-header */
@@ -228,15 +303,11 @@ struct sql_ex_info
/* DF = "Delete File" */
#define DF_FILE_ID_OFFSET 0
-#define QUERY_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+QUERY_HEADER_LEN)
-#define QUERY_DATA_OFFSET (LOG_EVENT_HEADER_LEN+QUERY_HEADER_LEN)
-#define ROTATE_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+ROTATE_HEADER_LEN)
-#define LOAD_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+LOAD_HEADER_LEN)
-#define CREATE_FILE_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+\
- +LOAD_HEADER_LEN+CREATE_FILE_HEADER_LEN)
-#define DELETE_FILE_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+DELETE_FILE_HEADER_LEN)
-#define EXEC_LOAD_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+EXEC_LOAD_HEADER_LEN)
-#define APPEND_BLOCK_EVENT_OVERHEAD (LOG_EVENT_HEADER_LEN+APPEND_BLOCK_HEADER_LEN)
+/* ELQ = "Execute Load Query" */
+#define ELQ_FILE_ID_OFFSET QUERY_HEADER_LEN
+#define ELQ_FN_POS_START_OFFSET ELQ_FILE_ID_OFFSET + 4
+#define ELQ_FN_POS_END_OFFSET ELQ_FILE_ID_OFFSET + 8
+#define ELQ_DUP_HANDLING_OFFSET ELQ_FILE_ID_OFFSET + 12
/* 4 bytes which all binlogs should begin with */
#define BINLOG_MAGIC "\xfe\x62\x69\x6e"
@@ -249,20 +320,45 @@ struct sql_ex_info
So they are now removed and their place may later be reused for other
flags. Then one must remember that Rotate events in 4.x have
LOG_EVENT_FORCED_ROTATE_F set, so one should not rely on the value of the
- replacing flag when reading a Rotate event.
+ replacing flag when reading a Rotate event.
I keep the defines here just to remember what they were.
*/
#ifdef TO_BE_REMOVED
#define LOG_EVENT_TIME_F 0x1
-#define LOG_EVENT_FORCED_ROTATE_F 0x2
+#define LOG_EVENT_FORCED_ROTATE_F 0x2
#endif
-/*
+
+/*
+ This flag only makes sense for Format_description_log_event. It is set
+ when the event is written, and *reset* when a binlog file is
+ closed (yes, it's the only case when MySQL modifies already written
+ part of binlog). Thus it is a reliable indicator that binlog was
+ closed correctly. (Stop_log_event is not enough, there's always a
+ small chance that mysqld crashes in the middle of insert and end of
+ the binlog would look like a Stop_log_event).
+
+ This flag is used to detect a restart after a crash, and to provide
+ "unbreakable" binlog. The problem is that on a crash storage engines
+ rollback automatically, while binlog does not. To solve this we use this
+ flag and automatically append ROLLBACK to every non-closed binlog (append
+ virtually, on reading, file itself is not changed). If this flag is found,
+ mysqlbinlog simply prints "ROLLBACK" Replication master does not abort on
+ binlog corruption, but takes it as EOF, and replication slave forces a
+ rollback in this case.
+
+ Note, that old binlogs does not have this flag set, so we get a
+ a backward-compatible behaviour.
+*/
+
+#define LOG_EVENT_BINLOG_IN_USE_F 0x1
+
+/*
If the query depends on the thread (for example: TEMPORARY TABLE).
Currently this is used by mysqlbinlog to know it must print
SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it
for every query but this would be slow).
*/
-#define LOG_EVENT_THREAD_SPECIFIC_F 0x4
+#define LOG_EVENT_THREAD_SPECIFIC_F 0x4
/*
Suppress the generation of 'USE' statements before the actual
@@ -277,15 +373,63 @@ struct sql_ex_info
*/
#define LOG_EVENT_SUPPRESS_USE_F 0x8
+/*
+ OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must be
+ written to the binlog. OPTIONS_WRITTEN_TO_BINLOG could be written
+ into the Format_description_log_event, so that if later we don't want
+ to replicate a variable we did replicate, or the contrary, it's
+ doable. But it should not be too hard to decide once for all of what
+ we replicate and what we don't, among the fixed 32 bits of
+ thd->options.
+ I (Guilhem) have read through every option's usage, and it looks like
+ OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only ones
+ which alter how the query modifies the table. It's good to replicate
+ OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the slave may
+ insert data slower than the master, in InnoDB.
+ OPTION_BIG_SELECTS is not needed (the slave thread runs with
+ max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed
+ either, as the manual says (because a too big in-memory temp table is
+ automatically written to disk).
+*/
+#define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_AUTO_IS_NULL | \
+OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS)
+
enum Log_event_type
{
- UNKNOWN_EVENT= 0, START_EVENT= 1, QUERY_EVENT= 2, STOP_EVENT= 3,
- ROTATE_EVENT= 4, INTVAR_EVENT= 5, LOAD_EVENT=6, SLAVE_EVENT= 7,
- CREATE_FILE_EVENT= 8, APPEND_BLOCK_EVENT= 9, EXEC_LOAD_EVENT= 10,
- DELETE_FILE_EVENT= 11, NEW_LOAD_EVENT= 12, RAND_EVENT= 13,
- USER_VAR_EVENT= 14
+ /*
+ Every time you update this enum (when you add a type), you have to
+ fix Format_description_log_event::Format_description_log_event().
+ */
+ UNKNOWN_EVENT= 0, START_EVENT_V3, QUERY_EVENT, STOP_EVENT, ROTATE_EVENT,
+ INTVAR_EVENT, LOAD_EVENT, SLAVE_EVENT, CREATE_FILE_EVENT,
+ APPEND_BLOCK_EVENT, EXEC_LOAD_EVENT, DELETE_FILE_EVENT,
+ /*
+ NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer
+ sql_ex, allowing multibyte TERMINATED BY etc; both types share the
+ same class (Load_log_event)
+ */
+ NEW_LOAD_EVENT,
+ RAND_EVENT, USER_VAR_EVENT,
+ FORMAT_DESCRIPTION_EVENT,
+ XID_EVENT,
+ BEGIN_LOAD_QUERY_EVENT,
+ EXECUTE_LOAD_QUERY_EVENT,
+
+ /*
+ add new events here - right above this comment!
+ existing events should never change their numbers
+ */
+
+ ENUM_END_EVENT /* end marker */
};
+/*
+ The number of types we handle in Format_description_log_event (UNKNOWN_EVENT
+ is not to be handled, it does not exist in binlogs, it does not have a
+ format).
+*/
+#define LOG_EVENT_TYPES (ENUM_END_EVENT-1)
+
enum Int_event_type
{
INVALID_INT_EVENT = 0, LAST_INSERT_ID_EVENT = 1, INSERT_ID_EVENT = 2
@@ -298,8 +442,45 @@ class MYSQL_LOG;
class THD;
#endif
+class Format_description_log_event;
+
struct st_relay_log_info;
+#ifdef MYSQL_CLIENT
+/*
+ A structure for mysqlbinlog to remember the last db, flags2, sql_mode etc; it
+ is passed to events' print() methods, so that they print only the necessary
+ USE and SET commands.
+*/
+typedef struct st_last_event_info
+{
+ // TODO: have the last catalog here ??
+ char db[FN_REFLEN+1]; // TODO: make this a LEX_STRING when thd->db is
+ bool flags2_inited;
+ uint32 flags2;
+ bool sql_mode_inited;
+ ulong sql_mode; /* must be same as THD.variables.sql_mode */
+ ulong auto_increment_increment, auto_increment_offset;
+ bool charset_inited;
+ char charset[6]; // 3 variables, each of them storable in 2 bytes
+ char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
+ st_last_event_info()
+ :flags2_inited(0), sql_mode_inited(0),
+ auto_increment_increment(1),auto_increment_offset(1), charset_inited(0)
+ {
+ /*
+ Currently we only use static LAST_EVENT_INFO objects, so zeroed at
+ program's startup, but these explicit bzero() is for the day someone
+ creates dynamic instances.
+ */
+ bzero(db, sizeof(db));
+ bzero(charset, sizeof(charset));
+ bzero(time_zone_str, sizeof(time_zone_str));
+ }
+} LAST_EVENT_INFO;
+#endif
+
+
/*****************************************************************************
Log_event class
@@ -310,69 +491,76 @@ struct st_relay_log_info;
class Log_event
{
public:
- /*
- The offset in the log where this event originally appeared (it is preserved
- in relay logs, making SHOW SLAVE STATUS able to print coordinates of the
- event in the master's binlog). Note: when a transaction is written by the
- master to its binlog (wrapped in BEGIN/COMMIT) the log_pos of all the
- queries it contains is the one of the BEGIN (this way, when one does SHOW
- SLAVE STATUS it sees the offset of the BEGIN, which is logical as rollback
- may occur), except the COMMIT query which has its real offset.
+ /*
+ The offset in the log where this event originally appeared (it is
+ preserved in relay logs, making SHOW SLAVE STATUS able to print
+ coordinates of the event in the master's binlog). Note: when a
+ transaction is written by the master to its binlog (wrapped in
+ BEGIN/COMMIT) the log_pos of all the queries it contains is the
+ one of the BEGIN (this way, when one does SHOW SLAVE STATUS it
+ sees the offset of the BEGIN, which is logical as rollback may
+ occur), except the COMMIT query which has its real offset.
*/
my_off_t log_pos;
- /*
+ /*
A temp buffer for read_log_event; it is later analysed according to the
event's type, and its content is distributed in the event-specific fields.
*/
- char *temp_buf;
+ char *temp_buf;
/*
- Timestamp on the master(for debugging and replication of NOW()/TIMESTAMP).
- It is important for queries and LOAD DATA INFILE. This is set at the event's
- creation time, except for Query and Load (et al.) events where this is set
- at the query's execution time, which guarantees good replication (otherwise,
- we could have a query and its event with different timestamps).
+ Timestamp on the master(for debugging and replication of
+ NOW()/TIMESTAMP). It is important for queries and LOAD DATA
+ INFILE. This is set at the event's creation time, except for Query
+ and Load (et al.) events where this is set at the query's
+ execution time, which guarantees good replication (otherwise, we
+ could have a query and its event with different timestamps).
*/
time_t when;
/* The number of seconds the query took to run on the master. */
ulong exec_time;
- /*
- The master's server id (is preserved in the relay log; used to prevent from
- infinite loops in circular replication).
+ /* Number of bytes written by write() function */
+ ulong data_written;
+
+ /*
+ The master's server id (is preserved in the relay log; used to
+ prevent from infinite loops in circular replication).
*/
uint32 server_id;
- uint cached_event_len;
/*
- Some 16 flags. Only one is really used now; look above for
- LOG_EVENT_TIME_F, LOG_EVENT_FORCED_ROTATE_F,
- LOG_EVENT_THREAD_SPECIFIC_F, and LOG_EVENT_SUPPRESS_USE_F for
- notes.
+ Some 16 flags. Look above for LOG_EVENT_TIME_F,
+ LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and
+ LOG_EVENT_SUPPRESS_USE_F for notes.
*/
uint16 flags;
bool cache_stmt;
+
#ifndef MYSQL_CLIENT
THD* thd;
- Log_event(THD* thd_arg, uint16 flags_arg, bool cache_stmt);
Log_event();
+ Log_event(THD* thd_arg, uint16 flags_arg, bool cache_stmt);
/*
- read_log_event() functions read an event from a binlog or relay log; used by
- SHOW BINLOG EVENTS, the binlog_dump thread on the master (reads master's
- binlog), the slave IO thread (reads the event sent by binlog_dump), the
- slave SQL thread (reads the event from the relay log).
+ read_log_event() functions read an event from a binlog or relay
+ log; used by SHOW BINLOG EVENTS, the binlog_dump thread on the
+ master (reads master's binlog), the slave IO thread (reads the
+ event sent by binlog_dump), the slave SQL thread (reads the event
+ from the relay log). If mutex is 0, the read will proceed without
+ mutex. We need the description_event to be able to parse the
+ event (to know the post-header's size); in fact in read_log_event
+ we detect the event's type, then call the specific event's
+ constructor and pass description_event as an argument.
*/
- // if mutex is 0, the read will proceed without mutex
static Log_event* read_log_event(IO_CACHE* file,
pthread_mutex_t* log_lock,
- bool old_format);
+ const Format_description_log_event *description_event);
static int read_log_event(IO_CACHE* file, String* packet,
pthread_mutex_t* log_lock);
- /* set_log_pos() is used to fill log_pos with tell(log). */
- void set_log_pos(MYSQL_LOG* log);
/*
- init_show_field_list() prepares the column names and types for the output of
- SHOW BINLOG EVENTS; it is used only by SHOW BINLOG EVENTS.
+ init_show_field_list() prepares the column names and types for the
+ output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
+ EVENTS.
*/
static void init_show_field_list(List<Item>* field_list);
#ifdef HAVE_REPLICATION
@@ -393,13 +581,15 @@ public:
return thd ? thd->db : 0;
}
#else
- // avoid having to link mysqlbinlog against libpthread
- static Log_event* read_log_event(IO_CACHE* file, bool old_format);
+ Log_event() : temp_buf(0) {}
+ /* avoid having to link mysqlbinlog against libpthread */
+ static Log_event* read_log_event(IO_CACHE* file,
+ const Format_description_log_event *description_event);
/* print*() functions are used by mysqlbinlog */
- virtual void print(FILE* file, bool short_form = 0, char* last_db = 0) = 0;
+ virtual void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0) = 0;
void print_timestamp(FILE* file, time_t *ts = 0);
void print_header(FILE* file);
-#endif
+#endif
static void *operator new(size_t size)
{
@@ -409,19 +599,25 @@ public:
{
my_free((gptr) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
}
-
- int write(IO_CACHE* file);
- int write_header(IO_CACHE* file);
- virtual int write_data(IO_CACHE* file)
- { return write_data_header(file) || write_data_body(file); }
- virtual int write_data_header(IO_CACHE* file __attribute__((unused)))
+
+#ifndef MYSQL_CLIENT
+ bool write_header(IO_CACHE* file, ulong data_length);
+ virtual bool write(IO_CACHE* file)
+ {
+ return (write_header(file, get_data_size()) ||
+ write_data_header(file) ||
+ write_data_body(file));
+ }
+ virtual bool write_data_header(IO_CACHE* file)
{ return 0; }
- virtual int write_data_body(IO_CACHE* file __attribute__((unused)))
+ virtual bool write_data_body(IO_CACHE* file __attribute__((unused)))
{ return 0; }
+#endif
virtual Log_event_type get_type_code() = 0;
- virtual bool is_valid() = 0;
+ virtual bool is_valid() const = 0;
+ virtual bool is_artificial_event() { return 0; }
inline bool get_cache_stmt() { return cache_stmt; }
- Log_event(const char* buf, bool old_format);
+ Log_event(const char* buf, const Format_description_log_event* description_event);
virtual ~Log_event() { free_temp_buf();}
void register_temp_buf(char* buf) { temp_buf = buf; }
void free_temp_buf()
@@ -432,19 +628,31 @@ public:
temp_buf = 0;
}
}
+ /*
+ Get event length for simple events. For complicated events the length
+ is calculated during write()
+ */
virtual int get_data_size() { return 0;}
- virtual int get_data_body_offset() { return 0; }
- int get_event_len()
- {
- return (cached_event_len ? cached_event_len :
- (cached_event_len = LOG_EVENT_HEADER_LEN + get_data_size()));
- }
- static Log_event* read_log_event(const char* buf, int event_len,
- const char **error, bool old_format);
+ static Log_event* read_log_event(const char* buf, uint event_len,
+ const char **error,
+ const Format_description_log_event
+ *description_event);
/* returns the human readable name of the event's type */
const char* get_type_str();
};
+/*
+ One class for each type of event.
+ Two constructors for each class:
+ - one to create the event for logging (when the server acts as a master),
+ called after an update to the database is done,
+ which accepts parameters like the query, the database, the options for LOAD
+ DATA INFILE...
+ - one to create the event from a packet (when the server acts as a slave),
+ called before reproducing the update, which accepts parameters (like a
+ buffer). Used to read from the master, from the relay log, and in
+ mysqlbinlog. This constructor must be format-tolerant.
+*/
/*****************************************************************************
@@ -459,6 +667,7 @@ protected:
char* data_buf;
public:
const char* query;
+ const char* catalog;
const char* db;
/*
If we already know the length of the query string
@@ -469,13 +678,64 @@ public:
uint32 db_len;
uint16 error_code;
ulong thread_id;
- /*
- For events created by Query_log_event::exec_event (and
- Load_log_event::exec_event()) we need the *original* thread id, to be able
- to log the event with the original (=master's) thread id (fix for
- BUG#1686).
+ /*
+ For events created by Query_log_event::exec_event (and
+ Load_log_event::exec_event()) we need the *original* thread id, to be able
+ to log the event with the original (=master's) thread id (fix for
+ BUG#1686).
*/
ulong slave_proxy_id;
+
+ /*
+ Binlog format 3 and 4 start to differ (as far as class members are
+ concerned) from here.
+ */
+
+ uint catalog_len; // <= 255 char; 0 means uninited
+
+ /*
+ We want to be able to store a variable number of N-bit status vars:
+ (generally N=32; but N=64 for SQL_MODE) a user may want to log the number
+ of affected rows (for debugging) while another does not want to lose 4
+ bytes in this.
+ The storage on disk is the following:
+ status_vars_len is part of the post-header,
+ status_vars are in the variable-length part, after the post-header, before
+ the db & query.
+ status_vars on disk is a sequence of pairs (code, value) where 'code' means
+ 'sql_mode', 'affected' etc. Sometimes 'value' must be a short string, so
+ its first byte is its length. For now the order of status vars is:
+ flags2 - sql_mode - catalog - autoinc - charset
+ We should add the same thing to Load_log_event, but in fact
+ LOAD DATA INFILE is going to be logged with a new type of event (logging of
+ the plain text query), so Load_log_event would be frozen, so no need. The
+ new way of logging LOAD DATA INFILE would use a derived class of
+ Query_log_event, so automatically benefit from the work already done for
+ status variables in Query_log_event.
+ */
+ uint16 status_vars_len;
+
+ /*
+ 'flags2' is a second set of flags (on top of those in Log_event), for
+ session variables. These are thd->options which is & against a mask
+ (OPTIONS_WRITTEN_TO_BINLOG).
+ flags2_inited helps make a difference between flags2==0 (3.23 or 4.x
+ master, we don't know flags2, so use the slave server's global options) and
+ flags2==0 (5.0 master, we know this has a meaning of flags all down which
+ must influence the query).
+ */
+ bool flags2_inited;
+ bool sql_mode_inited;
+ bool charset_inited;
+
+ uint32 flags2;
+ /* In connections sql_mode is 32 bits now but will be 64 bits soon */
+ ulong sql_mode;
+ ulong auto_increment_increment, auto_increment_offset;
+ char charset[6];
+ uint time_zone_len; /* 0 means uninited */
+ const char *time_zone_str;
+
#ifndef MYSQL_CLIENT
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
@@ -484,31 +744,35 @@ public:
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+ int exec_event(struct st_relay_log_info* rli, const char *query_arg,
+ uint32 q_len_arg);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print_query_header(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
- Query_log_event(const char* buf, int event_len, bool old_format);
+ Query_log_event(const char* buf, uint event_len,
+ const Format_description_log_event *description_event,
+ Log_event_type event_type);
~Query_log_event()
{
if (data_buf)
- {
my_free((gptr) data_buf, MYF(0));
- }
}
Log_event_type get_type_code() { return QUERY_EVENT; }
- int write(IO_CACHE* file);
- int write_data(IO_CACHE* file); // returns 0 on success, -1 on error
- bool is_valid() { return query != 0; }
- int get_data_size()
- {
- return (q_len + db_len + 2
- + 4 // thread_id
- + 4 // exec_time
- + 2 // error_code
- );
- }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+ virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
+#endif
+ bool is_valid() const { return query != 0; }
+
+ /*
+ Returns number of bytes additionaly written to post header by derived
+ events (so far it is only Execute_load_query event).
+ */
+ virtual ulong get_post_header_size_for_derived() { return 0; }
+ /* Writes derived event-specific part of post header. */
};
#ifdef HAVE_REPLICATION
@@ -518,6 +782,7 @@ public:
Slave Log Event class
Note that this class is currently not used at all; no code writes a
Slave_log_event (though some code in repl_failsafe.cc reads Slave_log_event).
+ So it's not a problem if this code is not maintained.
****************************************************************************/
class Slave_log_event: public Log_event
@@ -533,20 +798,22 @@ public:
int master_log_len;
uint16 master_port;
-#ifndef MYSQL_CLIENT
+#ifndef MYSQL_CLIENT
Slave_log_event(THD* thd_arg, struct st_relay_log_info* rli);
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
- Slave_log_event(const char* buf, int event_len);
+ Slave_log_event(const char* buf, uint event_len);
~Slave_log_event();
int get_data_size();
- bool is_valid() { return master_host != 0; }
+ bool is_valid() const { return master_host != 0; }
Log_event_type get_type_code() { return SLAVE_EVENT; }
- int write_data(IO_CACHE* file );
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
};
#endif /* HAVE_REPLICATION */
@@ -559,13 +826,23 @@ public:
****************************************************************************/
class Load_log_event: public Log_event
{
+private:
+ uint get_query_buffer_length();
+ void print_query(bool need_db, char *buf, char **end,
+ char **fn_start, char **fn_end);
protected:
- int copy_log_event(const char *buf, ulong event_len, bool old_format);
+ int copy_log_event(const char *buf, ulong event_len,
+ int body_offset, const Format_description_log_event* description_event);
public:
ulong thread_id;
ulong slave_proxy_id;
uint32 table_name_len;
+ /*
+ No need to have a catalog, as these events can only come from 4.x.
+ TODO: this may become false if Dmitri pushes his new LOAD DATA INFILE in
+ 5.0 only (not in 4.x).
+ */
uint32 db_len;
uint32 fname_len;
uint32 num_fields;
@@ -596,7 +873,7 @@ public:
#ifndef MYSQL_CLIENT
String field_lens_buf;
String fields_buf;
-
+
Load_log_event(THD* thd, sql_exchange* ex, const char* db_arg,
const char* table_name_arg,
List<Item>& fields_arg, enum enum_duplicates handle_dup, bool ignore,
@@ -609,60 +886,76 @@ public:
{
return exec_event(thd->slave_net,rli,0);
}
- int exec_event(NET* net, struct st_relay_log_info* rli,
+ int exec_event(NET* net, struct st_relay_log_info* rli,
bool use_rli_only_for_errors);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
- void print(FILE* file, bool short_form, char* last_db, bool commented);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info = 0);
+ void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info, bool commented);
#endif
- Load_log_event(const char* buf, int event_len, bool old_format);
+ /*
+ Note that for all the events related to LOAD DATA (Load_log_event,
+ Create_file/Append/Exec/Delete, we pass description_event; however as
+ logging of LOAD DATA is going to be changed in 4.1 or 5.0, this is only used
+ for the common_header_len (post_header_len will not be changed).
+ */
+ Load_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Load_log_event()
{}
Log_event_type get_type_code()
{
return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT;
}
- int write_data_header(IO_CACHE* file);
- int write_data_body(IO_CACHE* file);
- bool is_valid() { return table_name != 0; }
+#ifndef MYSQL_CLIENT
+ bool write_data_header(IO_CACHE* file);
+ bool write_data_body(IO_CACHE* file);
+#endif
+ bool is_valid() const { return table_name != 0; }
int get_data_size()
{
- return (table_name_len + 2 + db_len + 2 + fname_len
- + 4 // thread_id
- + 4 // exec_time
- + 4 // skip_lines
- + 4 // field block len
+ return (table_name_len + db_len + 2 + fname_len
+ + LOAD_HEADER_LEN
+ sql_ex.data_size() + field_block_len + num_fields);
}
- int get_data_body_offset() { return LOAD_EVENT_OVERHEAD; }
};
extern char server_version[SERVER_VERSION_LENGTH];
/*****************************************************************************
- Start Log Event class
+ Start Log Event_v3 class
+
+ Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and
+ 4.x).
+ Format_description_log_event derives from Start_log_event_v3; it is the
+ Start_log_event of binlog format 4 (MySQL 5.0), that is, the event that
+ describes the other events' header/postheader lengths. This event is sent by
+ MySQL 5.0 whenever it starts sending a new binlog if the requested position
+ is >4 (otherwise if ==4 the event will be sent naturally).
****************************************************************************/
-class Start_log_event: public Log_event
+
+class Start_log_event_v3: public Log_event
{
public:
- /*
- If this event is at the start of the first binary log since server startup
- 'created' should be the timestamp when the event (and the binary log) was
- created.
- In the other case (i.e. this event is at the start of a binary log created
- by FLUSH LOGS or automatic rotation), 'created' should be 0.
- This "trick" is used by MySQL >=4.0.14 slaves to know if they must drop the
- stale temporary tables or not.
- Note that when 'created'!=0, it is always equal to the event's timestamp;
- indeed Start_log_event is written only in log.cc where the first
- constructor below is called, in which 'created' is set to 'when'.
- So in fact 'created' is a useless variable. When it is 0
- we can read the actual value from timestamp ('when') and when it is
- non-zero we can read the same value from timestamp ('when'). Conclusion:
+ /*
+ If this event is at the start of the first binary log since server
+ startup 'created' should be the timestamp when the event (and the
+ binary log) was created. In the other case (i.e. this event is at
+ the start of a binary log created by FLUSH LOGS or automatic
+ rotation), 'created' should be 0. This "trick" is used by MySQL
+ >=4.0.14 slaves to know whether they must drop stale temporary
+ tables and whether they should abort unfinished transaction.
+
+ Note that when 'created'!=0, it is always equal to the event's
+ timestamp; indeed Start_log_event is written only in log.cc where
+ the first constructor below is called, in which 'created' is set
+ to 'when'. So in fact 'created' is a useless variable. When it is
+ 0 we can read the actual value from timestamp ('when') and when it
+ is non-zero we can read the same value from timestamp
+ ('when'). Conclusion:
- we use timestamp to print when the binlog was created.
- we use 'created' only to know if this is a first binlog or not.
In 3.23.57 we did not pay attention to this identity, so mysqlbinlog in
@@ -672,29 +965,89 @@ public:
time_t created;
uint16 binlog_version;
char server_version[ST_SERVER_VER_LEN];
+ /*
+ artifical_event is 1 in the case where this is a generated event that
+ should not case any cleanup actions. We handle this in the log by
+ setting log_event == 0 (for now).
+ */
+ bool artificial_event;
#ifndef MYSQL_CLIENT
- Start_log_event() :Log_event(), binlog_version(BINLOG_VERSION)
- {
- created = (time_t) when;
- memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
- }
+ Start_log_event_v3();
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
-
- Start_log_event(const char* buf, bool old_format);
- ~Start_log_event() {}
- Log_event_type get_type_code() { return START_EVENT;}
- int write_data(IO_CACHE* file);
- bool is_valid() { return 1; }
+ Start_log_event_v3() {}
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
+
+ Start_log_event_v3(const char* buf,
+ const Format_description_log_event* description_event);
+ ~Start_log_event_v3() {}
+ Log_event_type get_type_code() { return START_EVENT_V3;}
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
+ int get_data_size()
+ {
+ return START_V3_HEADER_LEN; //no variable-sized part
+ }
+ virtual bool is_artificial_event() { return artificial_event; }
+};
+
+
+/*
+ For binlog version 4.
+ This event is saved by threads which read it, as they need it for future
+ use (to decode the ordinary events).
+*/
+
+class Format_description_log_event: public Start_log_event_v3
+{
+public:
+ /*
+ The size of the fixed header which _all_ events have
+ (for binlogs written by this version, this is equal to
+ LOG_EVENT_HEADER_LEN), except FORMAT_DESCRIPTION_EVENT and ROTATE_EVENT
+ (those have a header of size LOG_EVENT_MINIMAL_HEADER_LEN).
+ */
+ uint8 common_header_len;
+ uint8 number_of_event_types;
+ /* The list of post-headers' lengthes */
+ uint8 *post_header_len;
+
+ Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
+
+#ifndef MYSQL_CLIENT
+#ifdef HAVE_REPLICATION
+ int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
+#endif
+
+ Format_description_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
+ ~Format_description_log_event() { my_free((gptr)post_header_len, MYF(0)); }
+ Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;}
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const
+ {
+ return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN :
+ LOG_EVENT_MINIMAL_HEADER_LEN)) &&
+ (post_header_len != NULL));
+ }
int get_data_size()
{
- return START_HEADER_LEN;
+ /*
+ The vector of post-header lengths is considered as part of the
+ post-header, because in a given version it never changes (contrary to the
+ query in a Query_log_event).
+ */
+ return FORMAT_DESCRIPTION_HEADER_LEN;
}
};
@@ -706,13 +1059,14 @@ public:
Logs special variables such as auto_increment values
****************************************************************************/
+
class Intvar_log_event: public Log_event
{
public:
ulonglong val;
uchar type;
-#ifndef MYSQL_CLIENT
+#ifndef MYSQL_CLIENT
Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg)
:Log_event(thd_arg,0,0),val(val_arg),type(type_arg)
{}
@@ -721,25 +1075,32 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
- Intvar_log_event(const char* buf, bool old_format);
+ Intvar_log_event(const char* buf, const Format_description_log_event* description_event);
~Intvar_log_event() {}
Log_event_type get_type_code() { return INTVAR_EVENT;}
const char* get_var_type_name();
int get_data_size() { return 9; /* sizeof(type) + sizeof(val) */;}
- int write_data(IO_CACHE* file);
- bool is_valid() { return 1; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
};
+
/*****************************************************************************
Rand Log Event class
- Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.
+ Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.0.
+ 4.1.1 does not need it (it's repeatable again) so this event needn't be
+ written in 4.1.1 for PASSWORD() (but the fact that it is written is just a
+ waste, it does not cause bugs).
****************************************************************************/
+
class Rand_log_event: public Log_event
{
public:
@@ -755,15 +1116,54 @@ class Rand_log_event: public Log_event
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
- Rand_log_event(const char* buf, bool old_format);
+ Rand_log_event(const char* buf, const Format_description_log_event* description_event);
~Rand_log_event() {}
Log_event_type get_type_code() { return RAND_EVENT;}
int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ }
- int write_data(IO_CACHE* file);
- bool is_valid() { return 1; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
+};
+
+/*****************************************************************************
+
+ Xid Log Event class
+
+ Logs xid of the transaction-to-be-committed in the 2pc protocol.
+ Has no meaning in replication, slaves ignore it.
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
+typedef ulonglong my_xid; // this line is the same as in handler.h
+#endif
+
+class Xid_log_event: public Log_event
+{
+ public:
+ my_xid xid;
+
+#ifndef MYSQL_CLIENT
+ Xid_log_event(THD* thd_arg, my_xid x): Log_event(thd_arg,0,0), xid(x) {}
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
+ int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
+#else
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
+
+ Xid_log_event(const char* buf, const Format_description_log_event* description_event);
+ ~Xid_log_event() {}
+ Log_event_type get_type_code() { return XID_EVENT;}
+ int get_data_size() { return sizeof(xid); }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
};
/*****************************************************************************
@@ -773,7 +1173,11 @@ class Rand_log_event: public Log_event
Every time a query uses the value of a user variable, a User_var_log_event is
written before the Query_log_event, to set the user variable.
+ Every time a query uses the value of a user variable, a User_var_log_event is
+ written before the Query_log_event, to set the user variable.
+
****************************************************************************/
+
class User_var_log_event: public Log_event
{
public:
@@ -794,29 +1198,24 @@ public:
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
- User_var_log_event(const char* buf, bool old_format);
+ User_var_log_event(const char* buf, const Format_description_log_event* description_event);
~User_var_log_event() {}
Log_event_type get_type_code() { return USER_VAR_EVENT;}
- int get_data_size()
- {
- return (is_null ? UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL :
- UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
- UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE + val_len);
- }
- int write_data(IO_CACHE* file);
- bool is_valid() { return 1; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
+ bool is_valid() const { return 1; }
};
+
/*****************************************************************************
Stop Log Event class
****************************************************************************/
-#ifdef HAVE_REPLICATION
-
class Stop_log_event: public Log_event
{
public:
@@ -825,27 +1224,25 @@ public:
{}
int exec_event(struct st_relay_log_info* rli);
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
- Stop_log_event(const char* buf, bool old_format):
- Log_event(buf, old_format)
+ Stop_log_event(const char* buf, const Format_description_log_event* description_event):
+ Log_event(buf, description_event)
{}
~Stop_log_event() {}
Log_event_type get_type_code() { return STOP_EVENT;}
- bool is_valid() { return 1; }
+ bool is_valid() const { return 1; }
};
-#endif /* HAVE_REPLICATION */
-
-
/*****************************************************************************
Rotate Log Event class
- This will be depricated when we move to using sequence ids.
+ This will be deprecated when we move to using sequence ids.
****************************************************************************/
+
class Rotate_log_event: public Log_event
{
public:
@@ -853,7 +1250,7 @@ public:
ulonglong pos;
uint ident_len;
bool alloced;
-#ifndef MYSQL_CLIENT
+#ifndef MYSQL_CLIENT
Rotate_log_event(THD* thd_arg, const char* new_log_ident_arg,
uint ident_len_arg = 0,
ulonglong pos_arg = LOG_EVENT_OFFSET)
@@ -866,10 +1263,11 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
- Rotate_log_event(const char* buf, int event_len, bool old_format);
+ Rotate_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Rotate_log_event()
{
if (alloced)
@@ -877,17 +1275,19 @@ public:
}
Log_event_type get_type_code() { return ROTATE_EVENT;}
int get_data_size() { return ident_len + ROTATE_HEADER_LEN;}
- bool is_valid() { return new_log_ident != 0; }
- int write_data(IO_CACHE* file);
+ bool is_valid() const { return new_log_ident != 0; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
};
+
/* the classes below are for the new LOAD DATA INFILE logging */
/*****************************************************************************
-
Create File Log Event class
-
****************************************************************************/
+
class Create_file_log_event: public Load_log_event
{
protected:
@@ -896,7 +1296,7 @@ protected:
our Load part - used on the slave when writing event out to
SQL_LOAD-*.info file
*/
- bool fake_base;
+ bool fake_base;
public:
char* block;
const char *event_buf;
@@ -916,11 +1316,12 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
- void print(FILE* file, bool short_form, char* last_db, bool enable_local);
-#endif
-
- Create_file_log_event(const char* buf, int event_len, bool old_format);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info, bool enable_local);
+#endif
+
+ Create_file_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Create_file_log_event()
{
my_free((char*) event_buf, MYF(MY_ALLOW_ZERO_PTR));
@@ -936,19 +1337,16 @@ public:
Load_log_event::get_data_size() +
4 + 1 + block_len);
}
- int get_data_body_offset()
- {
- return (fake_base ? LOAD_EVENT_OVERHEAD:
- LOAD_EVENT_OVERHEAD + CREATE_FILE_HEADER_LEN);
- }
- bool is_valid() { return inited_from_old || block != 0; }
- int write_data_header(IO_CACHE* file);
- int write_data_body(IO_CACHE* file);
+ bool is_valid() const { return inited_from_old || block != 0; }
+#ifndef MYSQL_CLIENT
+ bool write_data_header(IO_CACHE* file);
+ bool write_data_body(IO_CACHE* file);
/*
Cut out Create_file extentions and
write it as Load event - used on the slave
*/
- int write_base(IO_CACHE* file);
+ bool write_base(IO_CACHE* file);
+#endif
};
@@ -957,6 +1355,7 @@ public:
Append Block Log Event class
****************************************************************************/
+
class Append_block_log_event: public Log_event
{
public:
@@ -964,14 +1363,15 @@ public:
uint block_len;
uint file_id;
/*
- 'db' is filled when the event is created in mysql_load() (the event needs to
- have a 'db' member to be well filtered by binlog-*-db rules). 'db' is not
- written to the binlog (it's not used by Append_block_log_event::write()), so
- it can't be read in the Append_block_log_event(const char* buf, int
- event_len) constructor.
- In other words, 'db' is used only for filtering by binlog-*-db rules.
- Create_file_log_event is different: its 'db' (which is inherited from
- Load_log_event) is written to the binlog and can be re-read.
+ 'db' is filled when the event is created in mysql_load() (the
+ event needs to have a 'db' member to be well filtered by
+ binlog-*-db rules). 'db' is not written to the binlog (it's not
+ used by Append_block_log_event::write()), so it can't be read in
+ the Append_block_log_event(const char* buf, int event_len)
+ constructor. In other words, 'db' is used only for filtering by
+ binlog-*-db rules. Create_file_log_event is different: it's 'db'
+ (which is inherited from Load_log_event) is written to the binlog
+ and can be re-read.
*/
const char* db;
@@ -981,31 +1381,37 @@ public:
#ifdef HAVE_REPLICATION
int exec_event(struct st_relay_log_info* rli);
void pack_info(Protocol* protocol);
+ virtual int get_create_or_append() const;
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
#endif
-
- Append_block_log_event(const char* buf, int event_len);
+
+ Append_block_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Append_block_log_event() {}
Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;}
int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;}
- bool is_valid() { return block != 0; }
- int write_data(IO_CACHE* file);
+ bool is_valid() const { return block != 0; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
const char* get_db() { return db; }
};
+
/*****************************************************************************
Delete File Log Event class
****************************************************************************/
+
class Delete_file_log_event: public Log_event
{
public:
uint file_id;
const char* db; /* see comment in Append_block_log_event */
-
+
#ifndef MYSQL_CLIENT
Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
@@ -1013,29 +1419,34 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
- void print(FILE* file, bool short_form, char* last_db, bool enable_local);
-#endif
-
- Delete_file_log_event(const char* buf, int event_len);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+ void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info, bool enable_local);
+#endif
+
+ Delete_file_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Delete_file_log_event() {}
Log_event_type get_type_code() { return DELETE_FILE_EVENT;}
int get_data_size() { return DELETE_FILE_HEADER_LEN ;}
- bool is_valid() { return file_id != 0; }
- int write_data(IO_CACHE* file);
+ bool is_valid() const { return file_id != 0; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
const char* get_db() { return db; }
};
+
/*****************************************************************************
Execute Load Log Event class
****************************************************************************/
+
class Execute_load_log_event: public Log_event
{
public:
uint file_id;
- const char* db; /* see comment in Append_block_log_event */
+ const char* db; /* see comment in Append_block_log_event */
#ifndef MYSQL_CLIENT
Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans);
@@ -1044,30 +1455,128 @@ public:
int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, bool short_form = 0, char* last_db = 0);
-#endif
-
- Execute_load_log_event(const char* buf, int event_len);
+ void print(FILE* file, bool short_form = 0, LAST_EVENT_INFO* last_event_info= 0);
+#endif
+
+ Execute_load_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
~Execute_load_log_event() {}
Log_event_type get_type_code() { return EXEC_LOAD_EVENT;}
int get_data_size() { return EXEC_LOAD_HEADER_LEN ;}
- bool is_valid() { return file_id != 0; }
- int write_data(IO_CACHE* file);
+ bool is_valid() const { return file_id != 0; }
+#ifndef MYSQL_CLIENT
+ bool write(IO_CACHE* file);
+#endif
const char* get_db() { return db; }
};
+
+/***************************************************************************
+
+ Begin load query Log Event class
+
+ Event for the first block of file to be loaded, its only difference from
+ Append_block event is that this event creates or truncates existing file
+ before writing data.
+
+****************************************************************************/
+class Begin_load_query_log_event: public Append_block_log_event
+{
+public:
+#ifndef MYSQL_CLIENT
+ Begin_load_query_log_event(THD* thd_arg, const char *db_arg,
+ char* block_arg, uint block_len_arg,
+ bool using_trans);
+#ifdef HAVE_REPLICATION
+ Begin_load_query_log_event(THD* thd);
+ int get_create_or_append() const;
+#endif /* HAVE_REPLICATION */
+#endif
+ Begin_load_query_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event);
+ ~Begin_load_query_log_event() {}
+ Log_event_type get_type_code() { return BEGIN_LOAD_QUERY_EVENT; }
+};
+
+
+/*
+ Elements of this enum describe how LOAD DATA handles duplicates.
+*/
+enum enum_load_dup_handling { LOAD_DUP_ERROR= 0, LOAD_DUP_IGNORE,
+ LOAD_DUP_REPLACE };
+
+/****************************************************************************
+
+ Execute load query Log Event class
+
+ Event responsible for LOAD DATA execution, it similar to Query_log_event
+ but before executing the query it substitutes original filename in LOAD DATA
+ query with name of temporary file.
+
+****************************************************************************/
+class Execute_load_query_log_event: public Query_log_event
+{
+public:
+ uint file_id; // file_id of temporary file
+ uint fn_pos_start; // pointer to the part of the query that should
+ // be substituted
+ uint fn_pos_end; // pointer to the end of this part of query
+ /*
+ We have to store type of duplicate handling explicitly, because
+ for LOAD DATA it also depends on LOCAL option. And this part
+ of query will be rewritten during replication so this information
+ may be lost...
+ */
+ enum_load_dup_handling dup_handling;
+
+#ifndef MYSQL_CLIENT
+ Execute_load_query_log_event(THD* thd, const char* query_arg,
+ ulong query_length, uint fn_pos_start_arg,
+ uint fn_pos_end_arg,
+ enum_load_dup_handling dup_handling_arg,
+ bool using_trans, bool suppress_use);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
+ int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
+#else
+ void print(FILE* file, bool short_form = 0,
+ LAST_EVENT_INFO* last_event_info= 0);
+ /* Prints the query as LOAD DATA LOCAL and with rewritten filename */
+ void print(FILE* file, bool short_form, LAST_EVENT_INFO* last_event_info,
+ const char *local_fname);
+#endif
+ Execute_load_query_log_event(const char* buf, uint event_len,
+ const Format_description_log_event *description_event);
+ ~Execute_load_query_log_event() {}
+
+ Log_event_type get_type_code() { return EXECUTE_LOAD_QUERY_EVENT; }
+ bool is_valid() const { return Query_log_event::is_valid() && file_id != 0; }
+
+ ulong get_post_header_size_for_derived();
+#ifndef MYSQL_CLIENT
+ bool write_post_header_for_derived(IO_CACHE* file);
+#endif
+ };
+
+
#ifdef MYSQL_CLIENT
class Unknown_log_event: public Log_event
{
public:
- Unknown_log_event(const char* buf, bool old_format):
- Log_event(buf, old_format)
+ /*
+ Even if this is an unknown event, we still pass description_event to
+ Log_event's ctor, this way we can extract maximum information from the
+ event's header (the unique ID for example).
+ */
+ Unknown_log_event(const char* buf, const Format_description_log_event* description_event):
+ Log_event(buf, description_event)
{}
~Unknown_log_event() {}
- void print(FILE* file, bool short_form= 0, char* last_db= 0);
+ void print(FILE* file, bool short_form= 0, LAST_EVENT_INFO* last_event_info= 0);
Log_event_type get_type_code() { return UNKNOWN_EVENT;}
- bool is_valid() { return 1; }
+ bool is_valid() const { return 1; }
};
-#endif
+#endif
#endif /* _log_event_h */
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
new file mode 100644
index 00000000000..b4bbef4a637
--- /dev/null
+++ b/sql/my_decimal.cc
@@ -0,0 +1,237 @@
+/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; 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"
+
+#ifndef MYSQL_CLIENT
+/*
+ report result of decimal operation
+
+ SYNOPSIS
+ decimal_operation_results()
+ result decimal library return code (E_DEC_* see include/decimal.h)
+
+ TODO
+ Fix error messages
+
+ RETURN
+ result
+*/
+
+int decimal_operation_results(int result)
+{
+ switch (result) {
+ case E_DEC_OK:
+ break;
+ case E_DEC_TRUNCATED:
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED),
+ "", (long)-1);
+ break;
+ case E_DEC_OVERFLOW:
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_WARN_DATA_OUT_OF_RANGE,
+ ER(ER_WARN_DATA_OUT_OF_RANGE),
+ "", (long)-1);
+ break;
+ case E_DEC_DIV_ZERO:
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO));
+ break;
+ case E_DEC_BAD_NUM:
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "decimal", "", "", (long)-1);
+ break;
+ case E_DEC_OOM:
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ return result;
+}
+
+
+/*
+ Converting decimal to string
+
+ SYNOPSIS
+ my_decimal2string()
+
+ return
+ E_DEC_OK
+ E_DEC_TRUNCATED
+ E_DEC_OVERFLOW
+ E_DEC_OOM
+*/
+
+int my_decimal2string(uint mask, const my_decimal *d,
+ int fixed_prec, int fixed_dec,
+ char filler, String *str)
+{
+ int length= (fixed_prec ? (fixed_prec + 1) : my_decimal_string_length(d));
+ int result;
+ if (str->alloc(length))
+ return check_result(mask, E_DEC_OOM);
+ result= decimal2string((decimal_t*) d, (char*) str->ptr(),
+ &length, fixed_prec, fixed_dec,
+ filler);
+ str->length(length);
+ return check_result(mask, result);
+}
+
+
+/*
+ Convert from decimal to binary representation
+
+ SYNOPSIS
+ my_decimal2binary()
+ mask error processing mask
+ d number for conversion
+ bin pointer to buffer where to write result
+ prec overall number of decimal digits
+ scale number of decimal digits after decimal point
+
+ NOTE
+ Before conversion we round number if it need but produce truncation
+ error in this case
+
+ RETURN
+ E_DEC_OK
+ E_DEC_TRUNCATED
+ E_DEC_OVERFLOW
+*/
+
+int my_decimal2binary(uint mask, const my_decimal *d, char *bin, int prec,
+ int scale)
+{
+ int err1= E_DEC_OK, err2;
+ my_decimal rounded;
+ my_decimal2decimal(d, &rounded);
+ decimal_optimize_fraction(&rounded);
+ if (scale < rounded.frac)
+ {
+ err1= E_DEC_TRUNCATED;
+ /* decimal_round can return only E_DEC_TRUNCATED */
+ decimal_round(&rounded, &rounded, scale, HALF_UP);
+ }
+ err2= decimal2bin(&rounded, bin, prec, scale);
+ if (!err2)
+ err2= err1;
+ return check_result(mask, err2);
+}
+
+
+/*
+ Convert string for decimal when string can be in some multibyte charset
+
+ SYNOPSIS
+ str2my_decimal()
+ mask error processing mask
+ from string to process
+ length length of given string
+ charset charset of given string
+ decimal_value buffer for result storing
+
+ RESULT
+ E_DEC_OK
+ E_DEC_TRUNCATED
+ E_DEC_OVERFLOW
+ E_DEC_BAD_NUM
+ E_DEC_OOM
+*/
+
+int str2my_decimal(uint mask, const char *from, uint length,
+ CHARSET_INFO *charset, my_decimal *decimal_value)
+{
+ char *end, *from_end;
+ int err;
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String tmp(buff, sizeof(buff), &my_charset_bin);
+ if (charset->mbminlen > 1)
+ {
+ uint dummy_errors;
+ tmp.copy(from, length, charset, &my_charset_latin1, &dummy_errors);
+ from= tmp.ptr();
+ length= tmp.length();
+ charset= &my_charset_bin;
+ }
+ from_end= end= (char*) from+length;
+ err= string2decimal((char *)from, (decimal_t*) decimal_value, &end);
+ if (end != from_end && !err)
+ {
+ /* Give warning if there is something other than end space */
+ for ( ; end < from_end; end++)
+ {
+ if (!my_isspace(&my_charset_latin1, *end))
+ {
+ err= E_DEC_TRUNCATED;
+ break;
+ }
+ }
+ }
+ check_result(mask, err);
+ return err;
+}
+
+
+#ifndef DBUG_OFF
+/* routines for debugging print */
+
+/* print decimal */
+void
+print_decimal(const my_decimal *dec)
+{
+ fprintf(DBUG_FILE,
+ "\nDecimal: sign: %d intg: %d frac: %d \n\
+%09d,%09d,%09d,%09d,%09d,%09d,%09d,%09d\n",
+ dec->sign(), dec->intg, dec->frac,
+ dec->buf[0], dec->buf[1], dec->buf[2], dec->buf[3],
+ dec->buf[4], dec->buf[5], dec->buf[6], dec->buf[7]);
+}
+
+
+/* print decimal with its binary representation */
+void
+print_decimal_buff(const my_decimal *dec, const byte* ptr, int length)
+{
+ print_decimal(dec);
+ fprintf(DBUG_FILE, "Record: ");
+ for (int i= 0; i < length; i++)
+ {
+ fprintf(DBUG_FILE, "%02X ", (uint)((uchar *)ptr)[i]);
+ }
+ fprintf(DBUG_FILE, "\n");
+}
+
+
+void dbug_print_decimal(const char *tag, const char *format, my_decimal *val)
+{
+ char buff[DECIMAL_MAX_STR_LENGTH];
+ String str(buff, sizeof(buff), &my_charset_bin);
+ if (!val)
+ str.set("NULL", 4, &my_charset_bin);
+ else
+ my_decimal2string(0, val, 0, 0, 0, &str);
+ DBUG_PRINT(tag, (format, (char*) str.ptr()));
+}
+
+#endif
+
+
+#endif /*MYSQL_CLIENT*/
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
new file mode 100644
index 00000000000..03801390d82
--- /dev/null
+++ b/sql/my_decimal.h
@@ -0,0 +1,334 @@
+/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; 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 */
+
+/*
+ It is interface module to fixed precision decimals library.
+
+ Most functions use 'uint mask' as parameter, if during operation error
+ which fit in this mask is detected then it will be processed automatically
+ here. (errors are E_DEC_* constants, see include/decimal.h)
+
+ Most function are just inline wrappers around library calls
+*/
+
+#ifndef my_decimal_h
+#define my_decimal_h
+
+C_MODE_START
+#include <decimal.h>
+C_MODE_END
+
+#define DECIMAL_LONGLONG_DIGITS 22
+#define DECIMAL_LONG_DIGITS 10
+#define DECIMAL_LONG3_DIGITS 8
+
+/* number of digits on which we increase scale of devision result */
+#define DECIMAL_DIV_SCALE_INCREASE 5
+
+/* maximum length of buffer in our big digits (uint32) */
+#define DECIMAL_BUFF_LENGTH 8
+/*
+ maximum guaranteed length of number in decimal digits (number of our
+ digits * number of decimal digits in one our big digit - number of decimal
+ digits in one our big digit decreased on 1 (because we always put decimal
+ point on the border of our big digits))
+*/
+#define DECIMAL_MAX_LENGTH ((8 * 9) - 8)
+/*
+ maximum length of string representation (number of maximum decimal
+ digits + 1 position for sign + 1 position for decimal point)
+*/
+#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_LENGTH + 2)
+/*
+ maximum size of packet length
+*/
+#define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_LENGTH
+
+
+inline uint my_decimal_size(uint precision, uint scale)
+{
+ /*
+ Always allocate more space to allow library to put decimal point
+ where it want
+ */
+ return decimal_size(precision, scale) + 1;
+}
+
+
+/*
+ my_decimal class limits 'decimal_t' type to what we need in MySQL
+ It contains internally all necessary space needed by the instance so
+ no extra memory is needed. One should call fix_buffer_pointer() function
+ when he moves my_decimal objects in memory
+*/
+
+class my_decimal :public decimal_t
+{
+ decimal_digit_t buffer[DECIMAL_BUFF_LENGTH];
+
+public:
+
+ void init()
+ {
+ len= DECIMAL_BUFF_LENGTH;
+ buf= buffer;
+#if !defined (HAVE_purify) && !defined(DBUG_OFF)
+ /* Set buffer to 'random' value to find wrong buffer usage */
+ for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++)
+ buffer[i]= i;
+#endif
+ }
+ my_decimal()
+ {
+ init();
+ }
+ void fix_buffer_pointer() { buf= buffer; }
+
+ bool sign() const { return decimal_t::sign; }
+ void sign(bool s) { decimal_t::sign= s; }
+};
+
+
+#ifndef DBUG_OFF
+void print_decimal(const my_decimal *dec);
+void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length);
+void dbug_print_decimal(const char *tag, const char *format, my_decimal *val);
+#else
+#define dbug_print_decimal(A,B,C)
+#endif
+
+#ifndef MYSQL_CLIENT
+int decimal_operation_results(int result);
+#else
+inline int decimal_operation_results(int result)
+{
+ return result;
+}
+#endif /*MYSQL_CLIENT*/
+
+inline int check_result(uint mask, int result)
+{
+ if (result & mask)
+ decimal_operation_results(result);
+ return result;
+}
+
+
+inline
+int my_decimal_string_length(const my_decimal *d)
+{
+ return decimal_string_size(d);
+}
+
+
+inline
+int my_decimal_max_length(const my_decimal *d)
+{
+ /* -1 because we do not count \0 */
+ return decimal_string_size(d) - 1;
+}
+
+
+inline
+int my_decimal_get_binary_size(uint precision, uint scale)
+{
+ return decimal_bin_size((int)precision, (int)scale);
+}
+
+
+inline
+void my_decimal2decimal(const my_decimal *from, my_decimal *to)
+{
+ *to= *from;
+ to->fix_buffer_pointer();
+}
+
+
+int my_decimal2binary(uint mask, const my_decimal *d, char *bin, int prec,
+ int scale);
+
+
+inline
+int binary2my_decimal(uint mask, const char *bin, my_decimal *d, int prec,
+ int scale)
+{
+ return check_result(mask, bin2decimal((char *)bin, (decimal_t*) d, prec,
+ scale));
+}
+
+
+inline
+int my_decimal_set_zero(my_decimal *d)
+{
+ decimal_make_zero(((decimal_t*) d));
+ return 0;
+}
+
+
+inline
+bool my_decimal_is_zero(const my_decimal *decimal_value)
+{
+ return decimal_is_zero((decimal_t*) decimal_value);
+}
+
+
+inline
+int my_decimal_round(uint mask, const my_decimal *from, int scale,
+ bool truncate, my_decimal *to)
+{
+ return check_result(mask, decimal_round((decimal_t*) from, to, scale,
+ (truncate ? TRUNCATE : HALF_UP)));
+}
+
+
+inline
+int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to)
+{
+ return check_result(mask, decimal_round((decimal_t*) from, to, 0, FLOOR));
+}
+
+
+inline
+int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
+{
+ return check_result(mask, decimal_round((decimal_t*) from, to, 0, CEILING));
+}
+
+
+#ifndef MYSQL_CLIENT
+int my_decimal2string(uint mask, const my_decimal *d, int fixed_prec,
+ int fixed_dec, char filler, String *str);
+#endif
+
+inline
+int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag,
+ longlong *l)
+{
+ my_decimal rounded;
+ /* decimal_round can return only E_DEC_TRUNCATED */
+ decimal_round((decimal_t*)d, &rounded, 0, HALF_UP);
+ return check_result(mask, (unsigned_flag ?
+ decimal2ulonglong(&rounded, (ulonglong *)l) :
+ decimal2longlong(&rounded, l)));
+}
+
+
+inline
+int my_decimal2double(uint mask, const my_decimal *d, double *result)
+{
+ /* No need to call check_result as this will always succeed */
+ return decimal2double((decimal_t*) d, result);
+}
+
+
+inline
+int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end)
+{
+ return check_result(mask, string2decimal(str, (decimal_t*) d, end));
+}
+
+
+int str2my_decimal(uint mask, const char *from, uint length,
+ CHARSET_INFO *charset, my_decimal *decimal_value);
+
+#if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
+inline
+int string2my_decimal(uint mask, const String *str, my_decimal *d)
+{
+ return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d);
+}
+#endif
+
+inline
+int double2my_decimal(uint mask, double val, my_decimal *d)
+{
+ return check_result(mask, double2decimal(val, (decimal_t*) d));
+}
+
+
+inline
+int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d)
+{
+ return check_result(mask, (unsigned_flag ?
+ ulonglong2decimal((ulonglong)i, d) :
+ longlong2decimal(i, d)));
+}
+
+
+inline
+void my_decimal_neg(decimal_t *arg)
+{
+ decimal_neg(arg);
+}
+
+
+inline
+int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b)
+{
+ return check_result(mask, decimal_add((decimal_t*) a, (decimal_t*) b, res));
+}
+
+
+inline
+int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b)
+{
+ return check_result(mask, decimal_sub((decimal_t*) a, (decimal_t*) b, res));
+}
+
+
+inline
+int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b)
+{
+ return check_result(mask, decimal_mul((decimal_t*) a, (decimal_t*) b, res));
+}
+
+
+inline
+int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b, int div_scale_inc)
+{
+ return check_result(mask, decimal_div((decimal_t*) a, (decimal_t*) b, res,
+ div_scale_inc));
+}
+
+
+inline
+int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b)
+{
+ return check_result(mask, decimal_mod((decimal_t*) a, (decimal_t*) b, res));
+}
+
+
+/* Returns -1 if a<b, 1 if a>b and 0 if a==b */
+inline
+int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
+{
+ return decimal_cmp((decimal_t*) a, (decimal_t*) b);
+}
+
+inline
+void max_my_decimal(my_decimal *to, int precision, int frac)
+{
+ DBUG_ASSERT(precision <= DECIMAL_MAX_LENGTH);
+ max_decimal(precision, frac, (decimal_t*) to);
+}
+
+#endif /*my_decimal_h*/
+
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index f5d4464ce68..06c946114eb 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -14,6 +14,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/*
+ Mostly this file is used in the server. But a little part of it is used in
+ mysqlbinlog too (definition of SELECT_DISTINCT and others).
+ The consequence is that 90% of the file is wrapped in #ifndef MYSQL_CLIENT,
+ except the part which must be in the server and in the client.
+*/
+
+#ifndef MYSQL_CLIENT
+
#include <my_global.h>
#include <mysql_version.h>
#include <mysql_embed.h>
@@ -35,6 +44,13 @@ typedef ulonglong table_map; /* Used for table bits in join */
typedef Bitmap<64> key_map; /* Used for finding keys */
typedef ulong key_part_map; /* Used for finding key parts */
+/* query_id */
+typedef ulonglong query_id_t;
+extern query_id_t query_id;
+
+/* increment query_id and return it. */
+inline query_id_t next_query_id() { return query_id++; }
+
/* useful constants */
extern const key_map key_map_empty;
extern const key_map key_map_full;
@@ -55,7 +71,7 @@ char *sql_strmake_with_convert(const char *str, uint32 arg_length,
CHARSET_INFO *from_cs,
uint32 max_res_length,
CHARSET_INFO *to_cs, uint32 *result_length);
-void kill_one_thread(THD *thd, ulong id);
+void kill_one_thread(THD *thd, ulong id, bool only_kill_query);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
@@ -100,7 +116,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
The following parameters is to decide when to use an extra cache to
optimise seeks when reading a big table in sorted order
*/
-#define MIN_FILE_LENGTH_TO_USE_ROW_CACHE (16L*1024*1024)
+#define MIN_FILE_LENGTH_TO_USE_ROW_CACHE (10L*1024*1024)
#define MIN_ROWS_TO_USE_TABLE_CACHE 100
#define MIN_ROWS_TO_USE_BULK_INSERT 100
@@ -112,6 +128,26 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define TIME_FOR_COMPARE 5 // 5 compares == one read
/*
+ Number of comparisons of table rowids equivalent to reading one row from a
+ table.
+*/
+#define TIME_FOR_COMPARE_ROWID (TIME_FOR_COMPARE*2)
+
+/*
+ For sequential disk seeks the cost formula is:
+ DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST * #blocks_to_skip
+
+ The cost of average seek
+ DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*BLOCKS_IN_AVG_SEEK =1.0.
+*/
+#define DISK_SEEK_BASE_COST ((double)0.5)
+
+#define BLOCKS_IN_AVG_SEEK 128
+
+#define DISK_SEEK_PROP_COST ((double)0.5/BLOCKS_IN_AVG_SEEK)
+
+
+/*
Number of rows in a reference table when refereed through a not unique key.
This value is only used when we don't know anything about the key
distribution.
@@ -142,6 +178,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define FLUSH_TIME 0 /* Don't flush tables */
#define MAX_CONNECT_ERRORS 10 // errors before disabling host
+#ifdef HAVE_INNOBASE_DB
+#define IF_INNOBASE_DB(A, B) (A)
+#else
+#define IF_INNOBASE_DB(A, B) (B)
+#endif
+
#if defined(__WIN__) || defined(OS2)
#define IF_WIN(A,B) (A)
#undef FLUSH_TIME
@@ -173,8 +215,15 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define TEST_SIGINT 1024 /* Allow sigint on threads */
#define TEST_SYNCHRONIZATION 2048 /* get server to do sleep in some
places */
+#endif
+
+/*
+ This is included in the server and in the client.
+ Options for select set by the yacc parser (stored in lex->options).
+ None of the 32 defines below should have its value changed, or this will
+ break replication.
+*/
-/* options for select set by the yacc parser (stored in lex->options) */
#define SELECT_DISTINCT (1L << 0)
#define SELECT_STRAIGHT_JOIN (1L << 1)
#define SELECT_DESCRIBE (1L << 2)
@@ -211,9 +260,20 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
key checks in some cases */
#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27)
#define SELECT_NO_UNLOCK (1L << 28)
+#define OPTION_SCHEMA_TABLE (1L << 29)
+/* Flag set if setup_tables already done */
+#define OPTION_SETUP_TABLES_DONE (1L << 30)
+
+/*
+ Maximum length of time zone name that we support
+ (Time zone name is char(64) in db). mysqlbinlog needs it.
+*/
+#define MAX_TIME_ZONE_NAME_LENGTH 72
+
+/* The rest of the file is included in the server only */
+#ifndef MYSQL_CLIENT
-/* If set to 0, then the thread will ignore all warnings with level notes.
- Set by executing SET SQL_NOTES=1 */
+/* If not set then the thread will ignore all warnings with level notes. */
#define OPTION_SQL_NOTES (1L << 31)
/* Bits for different SQL modes modes (including ANSI mode) */
@@ -231,12 +291,32 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define MODE_DB2 2048
#define MODE_MAXDB 4096
#define MODE_NO_KEY_OPTIONS 8192
-#define MODE_NO_TABLE_OPTIONS 16384
-#define MODE_NO_FIELD_OPTIONS 32768
-#define MODE_MYSQL323 65536
-#define MODE_MYSQL40 (MODE_MYSQL323*2)
-#define MODE_ANSI (MODE_MYSQL40*2)
-#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
+#define MODE_NO_TABLE_OPTIONS 16384
+#define MODE_NO_FIELD_OPTIONS 32768
+#define MODE_MYSQL323 65536
+#define MODE_MYSQL40 (MODE_MYSQL323*2)
+#define MODE_ANSI (MODE_MYSQL40*2)
+#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
+#define MODE_NO_BACKSLASH_ESCAPES (MODE_NO_AUTO_VALUE_ON_ZERO*2)
+#define MODE_STRICT_TRANS_TABLES (MODE_NO_BACKSLASH_ESCAPES*2)
+#define MODE_STRICT_ALL_TABLES (MODE_STRICT_TRANS_TABLES*2)
+#define MODE_NO_ZERO_IN_DATE (MODE_STRICT_ALL_TABLES*2)
+#define MODE_NO_ZERO_DATE (MODE_NO_ZERO_IN_DATE*2)
+#define MODE_INVALID_DATES (MODE_NO_ZERO_DATE*2)
+#define MODE_ERROR_FOR_DIVISION_BY_ZERO (MODE_INVALID_DATES*2)
+#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)
+/*
+ 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
+ contact the replication team because the replication code should then be
+ updated (to store more bytes on disk).
+
+ NOTE: When adding new SQL_MODE types, make sure to also add them to
+ ../scripts/mysql_create_system_tables.sh and
+ ../scripts/mysql_fix_privilege_tables.sql
+*/
#define RAID_BLOCK_SIZE 1024
@@ -289,6 +369,8 @@ void debug_sync_point(const char* lock_name, uint lock_timeout);
#define WEEK_YEAR 2
#define WEEK_FIRST_WEEKDAY 4
+#define STRING_BUFFER_USUAL_SIZE 80
+
enum enum_parsing_place
{
NO_MATTER,
@@ -332,11 +414,18 @@ typedef struct st_sql_list {
first= save->first;
elements+= save->elements;
}
+ inline void push_back(struct st_sql_list *save)
+ {
+ if (save->first)
+ {
+ *next= save->first;
+ next= save->next;
+ elements+= save->elements;
+ }
+ }
} SQL_LIST;
-uint nr_of_decimals(const char *str); /* Neaded by sql_string.h */
-
extern pthread_key(THD*, THR_THD);
inline THD *_current_thd(void)
{
@@ -344,33 +433,62 @@ inline THD *_current_thd(void)
}
#define current_thd _current_thd()
+/*
+ External variables
+*/
+extern ulong server_id, concurrency;
+
+
+typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
+ uint key_length,
+ ulonglong *engine_data);
#include "sql_string.h"
#include "sql_list.h"
#include "sql_map.h"
+#include "my_decimal.h"
#include "handler.h"
+#include "parse_file.h"
#include "table.h"
+#include "sql_error.h"
#include "field.h" /* Field definitions */
#include "protocol.h"
#include "sql_udf.h"
class user_var_entry;
#include "item.h"
+extern my_decimal decimal_zero;
typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
/* sql_parse.cc */
void free_items(Item *item);
void cleanup_items(Item *item);
class THD;
-void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
-int check_one_table_access(THD *thd, ulong privilege,
+void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0,
+ TABLE *stopper= 0);
+bool check_one_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables);
+bool check_procedure_access(THD *thd,ulong want_access,char *db,char *name,
+ bool no_errors);
+bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
-int multi_update_precheck(THD *thd, TABLE_LIST *tables);
-int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
-int update_precheck(THD *thd, TABLE_LIST *tables);
-int delete_precheck(THD *thd, TABLE_LIST *tables);
-int insert_precheck(THD *thd, TABLE_LIST *tables);
-int create_table_precheck(THD *thd, TABLE_LIST *tables,
- TABLE_LIST *create_table);
+bool check_some_routine_access(THD *thd, const char *db, const char *name);
+bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
+bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
+bool mysql_multi_update_prepare(THD *thd);
+bool mysql_multi_delete_prepare(THD *thd);
+bool mysql_insert_select_prepare(THD *thd);
+bool update_precheck(THD *thd, TABLE_LIST *tables);
+bool delete_precheck(THD *thd, TABLE_LIST *tables);
+bool insert_precheck(THD *thd, TABLE_LIST *tables);
+bool create_table_precheck(THD *thd, TABLE_LIST *tables,
+ TABLE_LIST *create_table);
+
+enum enum_mysql_completiontype {
+ ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
+ COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
+};
+
+int end_trans(THD *thd, enum enum_mysql_completiontype completion);
+
Item *negate_expression(THD *thd, Item *expr);
#include "sql_class.h"
#include "sql_acl.h"
@@ -423,19 +541,20 @@ struct Query_cache_query_flags
#define prepare_execute(A) ((A)->command == COM_EXECUTE)
-int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
-int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
-int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
+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);
void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
-int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
- my_bool drop_temporary);
+bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
+ my_bool drop_temporary);
int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
- bool drop_temporary, bool log_query);
+ bool drop_temporary, bool drop_view, bool log_query);
int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
bool if_exists, bool drop_temporary,
bool log_query);
int quick_rm_table(enum db_type base,const char *db,
const char *table_name);
+void close_cached_table(THD *thd, TABLE *table);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool mysql_change_db(THD *thd,const char *name);
void mysql_parse(THD *thd,char *inBuf,uint length);
@@ -443,8 +562,8 @@ bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
bool alloc_query(THD *thd, char *packet, ulong packet_length);
void mysql_init_select(LEX *lex);
-void mysql_init_query(THD *thd, uchar *buf, uint length);
void mysql_reset_thd_for_next_command(THD *thd);
+void mysql_init_query(THD *thd, uchar *buf, uint length);
bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name);
void mysql_init_multi_delete(LEX *lex);
@@ -455,7 +574,7 @@ extern "C" pthread_handler_decl(handle_one_connection,arg);
extern "C" pthread_handler_decl(handle_bootstrap,arg);
void end_thread(THD *thd,bool put_in_cache);
void flush_thread_cache();
-void mysql_execute_command(THD *thd);
+bool mysql_execute_command(THD *thd);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
@@ -474,25 +593,27 @@ bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables,
bool no_errors);
bool check_global_access(THD *thd, ulong want_access);
-int mysql_backup_table(THD* thd, TABLE_LIST* table_list);
-int mysql_restore_table(THD* thd, TABLE_LIST* table_list);
-
-int mysql_checksum_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-int mysql_check_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-int mysql_repair_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-int mysql_analyze_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-int mysql_optimize_table(THD* thd, TABLE_LIST* table_list,
- HA_CHECK_OPT* check_opt);
-int mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
- LEX_STRING *key_cache_name);
-int mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
+bool mysql_backup_table(THD* thd, TABLE_LIST* table_list);
+bool mysql_restore_table(THD* thd, TABLE_LIST* table_list);
+
+bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list,
+ HA_CHECK_OPT* check_opt);
+bool mysql_check_table(THD* thd, TABLE_LIST* table_list,
+ HA_CHECK_OPT* check_opt);
+bool mysql_repair_table(THD* thd, TABLE_LIST* table_list,
+ HA_CHECK_OPT* check_opt);
+bool mysql_analyze_table(THD* thd, TABLE_LIST* table_list,
+ HA_CHECK_OPT* check_opt);
+bool mysql_optimize_table(THD* thd, TABLE_LIST* table_list,
+ HA_CHECK_OPT* check_opt);
+bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
+ LEX_STRING *key_cache_name);
+bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
KEY_CACHE *dst_cache);
+bool mysql_xa_recover(THD *thd);
+
bool check_simple_select();
SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
@@ -502,95 +623,99 @@ int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields);
-int handle_select(THD *thd, LEX *lex, select_result *result);
-int mysql_select(THD *thd, Item ***rref_pointer_array,
- TABLE_LIST *tables, uint wild_num, List<Item> &list,
- COND *conds, uint og_num, ORDER *order, ORDER *group,
- Item *having, ORDER *proc_param, ulong select_type,
- select_result *result, SELECT_LEX_UNIT *unit,
- SELECT_LEX *select_lex);
+bool handle_select(THD *thd, LEX *lex, select_result *result,
+ ulong setup_tables_done_option);
+bool mysql_select(THD *thd, Item ***rref_pointer_array,
+ TABLE_LIST *tables, uint wild_num, List<Item> &list,
+ COND *conds, uint og_num, ORDER *order, ORDER *group,
+ Item *having, ORDER *proc_param, ulong select_type,
+ select_result *result, SELECT_LEX_UNIT *unit,
+ SELECT_LEX *select_lex);
void free_underlaid_joins(THD *thd, SELECT_LEX *select);
-int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
- select_result *result);
+bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
+ select_result *result);
int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
select_result *result);
-int mysql_union(THD *thd, LEX *lex, select_result *result,
- SELECT_LEX_UNIT *unit);
-int mysql_handle_derived(LEX *lex);
+bool mysql_union(THD *thd, LEX *lex, select_result *result,
+ SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
+int mysql_handle_derived(LEX *lex, int (*processor)(THD *thd,
+ LEX *lex,
+ TABLE_LIST *table));
+int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
+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, uint convert_blob_length);
-int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
- List<create_field> &fields,
- List<Key> &keys, uint &db_options,
- handler *file, KEY *&key_info_buffer,
- uint &key_count, int select_field_count);
-int mysql_create_table(THD *thd,const char *db, const char *table_name,
- HA_CREATE_INFO *create_info,
- List<create_field> &fields, List<Key> &keys,
- bool tmp_table, uint select_field_count);
+ bool group, bool modify_item,
+ uint convert_blob_length);
+void sp_prepare_create_field(THD *thd, create_field *sql_field);
+int prepare_create_field(create_field *sql_field,
+ uint *blob_columns,
+ int *timestamps, int *timestamps_with_niladic,
+ uint table_flags);
+bool mysql_create_table(THD *thd,const char *db, const char *table_name,
+ HA_CREATE_INFO *create_info,
+ List<create_field> &fields, List<Key> &keys,
+ bool tmp_table, uint select_field_count);
TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
- const char *db, const char *name,
+ TABLE_LIST *create_table,
List<create_field> *extra_fields,
List<Key> *keys,
List<Item> *items,
- MYSQL_LOCK **lock);
-int mysql_alter_table(THD *thd, char *new_db, char *new_name,
- HA_CREATE_INFO *create_info,
- TABLE_LIST *table_list,
- List<create_field> &fields,
- List<Key> &keys,
- uint order_num, ORDER *order,
- enum enum_duplicates handle_duplicates,
- bool ignore,
- ALTER_INFO *alter_info, bool do_send_ok=1);
-int mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
-int mysql_create_like_table(THD *thd, TABLE_LIST *table,
- HA_CREATE_INFO *create_info,
- Table_ident *src_table);
+ MYSQL_LOCK **lock);
+bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
+ HA_CREATE_INFO *create_info,
+ TABLE_LIST *table_list,
+ List<create_field> &fields,
+ List<Key> &keys,
+ uint order_num, ORDER *order,
+ enum enum_duplicates handle_duplicates,
+ bool ignore,
+ ALTER_INFO *alter_info, bool do_send_ok);
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
+bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
+ HA_CREATE_INFO *create_info,
+ Table_ident *src_table);
bool mysql_rename_table(enum db_type base,
const char *old_db,
const char * old_name,
const char *new_db,
const char * new_name);
-int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
-int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
- ALTER_INFO *alter_info);
-int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
- TABLE_LIST *update_table_list,
- Item **conds, uint order_num, ORDER *order);
+bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
+bool mysql_drop_index(THD *thd, TABLE_LIST *table_list,
+ ALTER_INFO *alter_info);
+bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
+ Item **conds, uint order_num, ORDER *order);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &values,COND *conds,
- uint order_num, ORDER *order, ha_rows limit,
+ uint order_num, ORDER *order, ha_rows limit,
enum enum_duplicates handle_duplicates, bool ignore);
-int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
- List<Item> *fields, List<Item> *values,
- COND *conds, ulong options,
- enum enum_duplicates handle_duplicates, bool ignore,
- SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
-int mysql_multi_update_lock(THD *thd,
- TABLE_LIST *table_list,
- List<Item> *fields,
- SELECT_LEX *select_lex);
-int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
- TABLE_LIST *insert_table_list, TABLE *table,
- List<Item> &fields, List_item *values,
- List<Item> &update_fields,
- List<Item> &update_values, enum_duplicates duplic);
-int 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 mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
-int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order,
- ha_rows rows, ulong options);
-int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
+bool mysql_multi_update(THD *thd, TABLE_LIST *table_list,
+ List<Item> *fields, List<Item> *values,
+ COND *conds, ulong options,
+ enum enum_duplicates handle_duplicates, bool ignore,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
+bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
+ List<Item> &fields, List_item *values,
+ List<Item> &update_fields,
+ List<Item> &update_values, enum_duplicates duplic,
+ COND **where, bool select_insert);
+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);
+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);
+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,const char *db,const char *table,const char *alias,
+TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
bool *refresh);
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=0);
+bool reopen_table(TABLE *table,bool locked);
bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
bool send_refresh);
@@ -601,12 +726,28 @@ bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
void abort_locked_tables(THD *thd,const char *db, const char *table_name);
void execute_init_command(THD *thd, sys_var_str *init_command_var,
rw_lock_t *var_mutex);
-extern const Field *not_found_field;
+extern Field *not_found_field;
+extern Field *view_ref_found;
+
+enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
+ IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
+ IGNORE_EXCEPT_NON_UNIQUE};
Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
- TABLE_LIST **where, bool report_error);
-Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
- bool check_grant,bool allow_rowid,
- uint *cached_field_index_ptr);
+ Item **ref,
+ find_item_error_report_type report_error,
+ bool check_privileges);
+Field *
+find_field_in_table(THD *thd, TABLE_LIST *table_list,
+ const char *name, const char *item_name,
+ uint length, Item **ref,
+ bool check_grants_table, bool check_grants_view,
+ bool allow_rowid,
+ uint *cached_field_index_ptr,
+ bool register_tree_change);
+Field *
+find_field_in_real_table(THD *thd, TABLE *table, const char *name,
+ uint length, bool check_grants, bool allow_rowid,
+ uint *cached_field_index_ptr);
#ifdef HAVE_OPENSSL
#include <openssl/des.h>
struct st_des_keyblock
@@ -626,62 +767,70 @@ void free_des_key_file();
#endif /* HAVE_OPENSSL */
/* sql_do.cc */
-int mysql_do(THD *thd, List<Item> &values);
+bool mysql_do(THD *thd, List<Item> &values);
+
+/* sql_analyse.h */
+bool append_escaped(String *to_str, String *from_str);
/* sql_show.cc */
-int mysqld_show_dbs(THD *thd,const char *wild);
-int mysqld_show_open_tables(THD *thd,const char *wild);
-int mysqld_show_tables(THD *thd,const char *db,const char *wild);
-int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild);
-int mysqld_show_fields(THD *thd,TABLE_LIST *table, const char *wild,
- bool verbose);
-int mysqld_show_keys(THD *thd, TABLE_LIST *table);
-int mysqld_show_logs(THD *thd);
+bool mysqld_show_open_tables(THD *thd,const char *wild);
+bool mysqld_show_logs(THD *thd);
void append_identifier(THD *thd, String *packet, const char *name,
uint length);
int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
-int mysqld_dump_create_info(THD *thd, TABLE *table, int fd = -1);
-int mysqld_show_create(THD *thd, TABLE_LIST *table_list);
-int mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
+int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
+bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
+bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
void mysqld_list_processes(THD *thd,const char *user,bool verbose);
int mysqld_show_status(THD *thd);
int mysqld_show_variables(THD *thd,const char *wild);
-int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
- enum enum_var_type value_type,
- pthread_mutex_t *mutex);
int mysql_find_files(THD *thd,List<char> *files, const char *db,
const char *path, const char *wild, bool dir);
-int mysqld_show_charsets(THD *thd,const char *wild);
-int mysqld_show_collations(THD *thd,const char *wild);
-int mysqld_show_storage_engines(THD *thd);
-int mysqld_show_privileges(THD *thd);
-int mysqld_show_column_types(THD *thd);
-int mysqld_help (THD *thd, const char *text);
+bool mysqld_show_storage_engines(THD *thd);
+bool mysqld_show_privileges(THD *thd);
+bool mysqld_show_column_types(THD *thd);
+bool mysqld_help (THD *thd, const char *text);
+void calc_sum_of_all_status(STATUS_VAR *to);
+
+
+
+/* information schema */
+extern LEX_STRING information_schema_name;
+LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
+ const char* str, uint length,
+ bool allocate_lex_string);
+ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name);
+ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx);
+int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
+ enum enum_schema_tables schema_table_idx);
+int make_schema_select(THD *thd, SELECT_LEX *sel,
+ enum enum_schema_tables schema_table_idx);
+int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list);
+int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
+int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
+int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
+int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
+bool get_schema_tables_result(JOIN *join);
/* sql_prepare.cc */
-int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
- LEX_STRING *name=NULL);
+bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
+ LEX_STRING *name);
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_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
-
-/* sql_error.cc */
-MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
- const char *msg);
-void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
- uint code, const char *format, ...);
-void mysql_reset_errors(THD *thd);
-my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
+void reset_stmt_for_execute(THD *thd, LEX *lex);
+void init_stmt_after_parse(THD*, LEX*);
/* sql_handler.cc */
-int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen= 0);
-int mysql_ha_close(THD *thd, TABLE_LIST *tables);
-int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
- List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
+bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen);
+bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
+bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
+ List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags);
/* mysql_ha_flush mode_flags bits */
#define MYSQL_HA_CLOSE_FINAL 0x00
@@ -699,18 +848,24 @@ bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type,
char *change, List<String> *interval_list,
CHARSET_INFO *cs,
uint uint_geom_type);
+create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
+ char *length, char *decimals,
+ uint type_modifier,
+ Item *default_value, Item *on_update_value,
+ LEX_STRING *comment, char *change,
+ List<String> *interval_list, CHARSET_INFO *cs,
+ uint uint_geom_type);
void store_position_for_column(const char *name);
-bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc=0);
+bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc);
void add_join_on(TABLE_LIST *b,Item *expr);
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b);
bool add_proc_to_list(THD *thd, Item *item);
TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
SQL_SELECT *make_select(TABLE *head, table_map const_tables,
- table_map read_tables, COND *conds, int *error);
-enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
- IGNORE_ERRORS};
-extern const Item **not_found_item;
+ table_map read_tables, COND *conds,
+ bool allow_null_cond, int *error);
+extern Item **not_found_item;
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
find_item_error_report_type report_error,
bool *unaliased);
@@ -718,22 +873,25 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
- List_iterator<Item> *it);
-bool setup_tables(TABLE_LIST *tables);
+ List_iterator<Item> *it, bool any_privileges,
+ bool allocate_view_names);
+bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
+ TABLE_LIST **leaves, bool refresh_only,
+ bool select_insert);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
-int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
- List<Item> &item, bool set_query_id,
- List<Item> *sum_func_list, bool allow_sum_func);
-int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
+bool setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
+ List<Item> &item, bool set_query_id,
+ List<Item> *sum_func_list, bool allow_sum_func);
+int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
+ COND **conds);
int setup_ftfuncs(SELECT_LEX* select);
int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
void wait_for_refresh(THD *thd);
-int open_tables(THD *thd, TABLE_LIST *tables, uint *counter);
+int open_tables(THD *thd, TABLE_LIST **tables, uint *counter);
int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
-int open_and_lock_tables(THD *thd,TABLE_LIST *tables);
-int open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables);
-void relink_tables_for_derived(THD *thd);
+bool open_and_lock_tables(THD *thd,TABLE_LIST *tables);
+bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables);
int lock_tables(THD *thd, TABLE_LIST *tables, uint counter);
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list);
@@ -742,35 +900,55 @@ void free_io_cache(TABLE *entry);
void intern_close_table(TABLE *entry);
bool close_thread_table(THD *thd, TABLE **table_ptr);
void close_temporary_tables(THD *thd);
-TABLE_LIST * find_table_in_list(TABLE_LIST *table,
- const char *db_name, const char *table_name);
-TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
- const char *db_name,
- const char *table_name);
+TABLE_LIST *find_table_in_list(TABLE_LIST *table,
+ uint offset_to_list,
+ const char *db_name,
+ const char *table_name);
+TABLE_LIST *unique_table(TABLE_LIST *table, TABLE_LIST *table_list);
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
-void close_temporary(TABLE *table, bool delete_table=1);
+void close_temporary(TABLE *table, bool delete_table);
bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
const char *table_name);
void remove_db_from_cache(const char *db);
void flush_tables();
bool remove_table_from_cache(THD *thd, const char *db, const char *table,
- bool return_if_owned_by_thd=0);
+ bool return_if_owned_by_thd);
bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables);
void copy_field_from_tmp_record(Field *field,int offset);
-int fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors);
-int fill_record(Field **field,List<Item> &values, bool ignore_errors);
+bool fill_record(THD *thd, List<Item> &fields, List<Item> &values,
+ bool ignore_errors);
+bool fill_record(THD *thd, Field **field, List<Item> &values,
+ bool ignore_errors);
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild);
+inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table,
+ const char *db_name,
+ const char *table_name)
+{
+ return find_table_in_list(table, offsetof(TABLE_LIST, next_global),
+ db_name, table_name);
+}
+
+inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table,
+ const char *db_name,
+ const char *table_name)
+{
+ return find_table_in_list(table, offsetof(TABLE_LIST, next_local),
+ db_name, table_name);
+}
+
+
/* sql_calc.cc */
bool eval_const_cond(COND *cond);
/* sql_load.cc */
-int mysql_load(THD *thd,sql_exchange *ex, TABLE_LIST *table_list,
- List<Item> &fields, enum enum_duplicates handle_duplicates,
- bool ignore,
- bool local_file,thr_lock_type lock_type);
-int write_record(TABLE *table,COPY_INFO *info);
+bool mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list,
+ List<Item> &fields_vars, List<Item> &set_fields,
+ List<Item> &set_values_list,
+ enum enum_duplicates handle_duplicates, bool ignore,
+ bool local_file);
+int write_record(THD *thd, TABLE *table, COPY_INFO *info);
/* sql_manager.cc */
/* bits set in manager_status */
@@ -785,12 +963,15 @@ extern "C" pthread_handler_decl(handle_manager, arg);
void print_where(COND *cond,const char *info);
void print_cached_tables(void);
void TEST_filesort(SORT_FIELD *sortorder,uint s_length);
+void print_plan(JOIN* join, double read_time, double record_count,
+ uint idx, const char *info);
#endif
-void mysql_print_status(THD *thd);
+void mysql_print_status();
/* key.cc */
int find_ref_key(TABLE *form,Field *field, uint *offset);
-void key_copy(byte *key,TABLE *form,uint index,uint key_length);
-void key_restore(TABLE *form,byte *key,uint index,uint key_length);
+void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length);
+void key_restore(byte *to_record, byte *from_key, KEY *key_info,
+ uint key_length);
bool key_cmp_if_same(TABLE *form,const byte *key,uint index,uint key_length);
void key_unpack(String *to,TABLE *form,uint index);
bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields);
@@ -808,11 +989,9 @@ void sql_print_information(const char *format, ...);
bool fn_format_relative_to_data_home(my_string to, const char *name,
const char *dir, const char *extension);
-bool open_log(MYSQL_LOG *log, const char *hostname,
- const char *opt_name, const char *extension,
- const char *index_file_name,
- enum_log_type type, bool read_append,
- bool no_auto_events, ulong max_size);
+File open_binlog(IO_CACHE *log, const char *log_file_name,
+ const char **errmsg);
+handlerton *binlog_init();
/* mysqld.cc */
extern void yyerror(const char*);
@@ -853,6 +1032,7 @@ extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str;
extern const char *in_left_expr_name, *in_additional_cond;
+extern const char * const triggers_file_ext;
extern Eq_creator eq_creator;
extern Ne_creator ne_creator;
extern Gt_creator gt_creator;
@@ -862,43 +1042,34 @@ extern Le_creator le_creator;
extern char language[FN_REFLEN], reg_ext[FN_EXTLEN];
extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
-extern char log_error_file[FN_REFLEN];
+extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
+extern double last_query_cost;
extern double log_10[32];
extern ulonglong log_10_int[20];
extern ulonglong keybuff_size;
-extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables;
-extern ulong created_tmp_tables, created_tmp_disk_tables, bytes_sent;
+extern ulong refresh_version,flush_version, thread_id;
extern ulong binlog_cache_use, binlog_cache_disk_use;
extern ulong aborted_threads,aborted_connects;
extern ulong delayed_insert_timeout;
extern ulong delayed_insert_limit, delayed_queue_size;
extern ulong delayed_insert_threads, delayed_insert_writes;
extern ulong delayed_rows_in_use,delayed_insert_errors;
-extern ulong filesort_rows, filesort_range_count, filesort_scan_count;
-extern ulong filesort_merge_passes;
-extern ulong select_range_check_count, select_range_count, select_scan_count;
-extern ulong select_full_range_join_count,select_full_join_count;
extern ulong slave_open_temp_tables;
extern ulong query_cache_size, query_cache_min_res_unit;
extern ulong thd_startup_options, slow_launch_threads, slow_launch_time;
-extern ulong server_id, concurrency;
-extern ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count;
-extern ulong ha_read_key_count, ha_read_next_count, ha_read_prev_count;
-extern ulong ha_read_first_count, ha_read_last_count;
-extern ulong ha_read_rnd_count, ha_read_rnd_next_count, ha_discover_count;
-extern ulong ha_commit_count, ha_rollback_count,table_cache_size;
+extern ulong table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
extern ulong slave_net_timeout, slave_trans_retries;
-extern ulong max_user_connections;
-extern ulong long_query_count, what_to_log,flush_time;
+extern uint max_user_connections;
+extern ulong what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
extern ulong max_binlog_size, max_relay_log_size;
extern ulong rpl_recovery_rank, thread_cache_size;
-extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log;
+extern ulong back_log;
extern ulong specialflag, current_pid;
extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter;
-extern my_bool relay_log_purge, opt_innodb_safe_binlog;
+extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb;
extern uint test_flags,select_errors,ha_open_options;
extern uint protocol_version, mysqld_port, dropping_tables;
extern uint delay_key_write_options, lower_case_table_names;
@@ -908,6 +1079,7 @@ extern bool using_update_log, opt_large_files, server_id_supplied;
extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log;
extern bool opt_disable_networking, opt_skip_show_db;
extern bool volatile abort_loop, shutdown_in_progress, grant_option;
+extern bool mysql_proc_table_exists;
extern uint volatile thread_count, thread_running, global_read_lock;
extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types;
extern my_bool opt_safe_show_db, opt_local_infile;
@@ -915,19 +1087,24 @@ extern my_bool opt_slave_compressed_protocol, use_temp_pool;
extern my_bool opt_readonly, lower_case_file_system;
extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
extern my_bool opt_secure_auth;
+extern my_bool sp_automatic_privileges;
+extern my_bool opt_old_style_user_limits;
extern uint opt_crash_binlog_innodb;
extern char *shared_memory_base_name, *mysqld_unix_port;
extern bool opt_enable_shared_memory;
extern char *default_tz_name;
+extern my_bool opt_large_pages;
+extern uint opt_large_page_size;
-extern MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
+extern MYSQL_LOG mysql_log,mysql_slow_log,mysql_bin_log;
extern FILE *bootstrap_file;
+extern int bootstrap_error;
extern pthread_key(MEM_ROOT**,THR_MALLOC);
extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status,
LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
- LOCK_slave_list, LOCK_active_mi, LOCK_manager,
+ LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock,
LOCK_global_system_variables, LOCK_user_conn;
extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
@@ -938,12 +1115,9 @@ extern MY_BITMAP temp_pool;
extern String my_empty_string;
extern const String my_null_string;
extern SHOW_VAR init_vars[],status_vars[], internal_vars[];
-extern SHOW_COMP_OPTION have_isam;
-extern SHOW_COMP_OPTION have_innodb;
-extern SHOW_COMP_OPTION have_berkeley_db;
-extern SHOW_COMP_OPTION have_ndbcluster;
extern struct system_variables global_system_variables;
extern struct system_variables max_system_variables;
+extern struct system_status_var global_status_var;
extern struct rand_struct sql_rand;
extern const char *opt_date_time_formats[];
@@ -960,12 +1134,14 @@ extern struct my_option my_long_options[];
extern SHOW_COMP_OPTION have_isam, have_innodb, have_berkeley_db;
extern SHOW_COMP_OPTION have_example_db, have_archive_db, have_csv_db;
+extern SHOW_COMP_OPTION have_federated_db;
+extern SHOW_COMP_OPTION have_blackhole_db;
+extern SHOW_COMP_OPTION have_ndbcluster;
extern SHOW_COMP_OPTION have_raid, have_openssl, have_symlink;
-extern SHOW_COMP_OPTION have_query_cache, have_berkeley_db, have_innodb;
+extern SHOW_COMP_OPTION have_query_cache;
extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
extern SHOW_COMP_OPTION have_crypt;
extern SHOW_COMP_OPTION have_compress;
-extern SHOW_COMP_OPTION have_blackhole_db;
#ifndef __WIN__
extern pthread_t signal_thread;
@@ -986,10 +1162,11 @@ void mysql_lock_abort_for_thread(THD *thd, TABLE *table);
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
bool lock_global_read_lock(THD *thd);
void unlock_global_read_lock(THD *thd);
-bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit);
+bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
+ bool is_not_commit);
void start_waiting_global_read_lock(THD *thd);
-void make_global_read_lock_block_commit(THD *thd);
-my_bool set_protect_against_global_read_lock(void);
+bool make_global_read_lock_block_commit(THD *thd);
+bool set_protect_against_global_read_lock(void);
void unset_protect_against_global_read_lock(void);
/* Lock based on name */
@@ -999,7 +1176,7 @@ void unlock_table_name(THD *thd, TABLE_LIST *table_list);
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
bool lock_table_names(THD *thd, TABLE_LIST *table_list);
void unlock_table_names(THD *thd, TABLE_LIST *table_list,
- TABLE_LIST *last_table= 0);
+ TABLE_LIST *last_table);
/* old unireg functions */
@@ -1015,8 +1192,8 @@ int rea_create_table(THD *thd, my_string file_name,HA_CREATE_INFO *create_info,
uint key_count,KEY *key_info);
int format_number(uint inputflag,uint max_length,my_string pos,uint length,
my_string *errpos);
-int openfrm(const char *name,const char *alias,uint filestat,uint prgflag,
- uint ha_open_flags, TABLE *outparam);
+int openfrm(THD *thd, const char *name,const char *alias,uint filestat,
+ uint prgflag, uint ha_open_flags, TABLE *outparam);
int readfrm(const char *name, const void** data, uint* length);
int writefrm(const char* name, const void* data, uint len);
int closefrm(TABLE *table);
@@ -1026,20 +1203,18 @@ void free_blobs(TABLE *table);
int set_zone(int nr,int min_zone,int max_zone);
ulong convert_period_to_month(ulong period);
ulong convert_month_to_period(ulong month);
-uint calc_days_in_year(uint year);
void get_date_from_daynr(long daynr,uint *year, uint *month,
uint *day);
my_time_t TIME_to_timestamp(THD *thd, const TIME *t, bool *not_exist);
bool str_to_time_with_warn(const char *str,uint length,TIME *l_time);
timestamp_type str_to_datetime_with_warn(const char *str, uint length,
TIME *l_time, uint flags);
-longlong number_to_TIME(longlong nr, TIME *time_res, bool fuzzy_date,
- int *was_cut);
void localtime_to_TIME(TIME *to, struct tm *from);
void calc_time_from_sec(TIME *to, long seconds, long microseconds);
void make_truncated_value_warning(THD *thd, const char *str_val,
- uint str_length, timestamp_type time_type);
+ uint str_length, timestamp_type time_type,
+ const char *field_name);
extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
const char *format_str,
uint format_length);
@@ -1055,10 +1230,6 @@ void make_date(const DATE_TIME_FORMAT *format, const TIME *l_time,
String *str);
void make_time(const DATE_TIME_FORMAT *format, const TIME *l_time,
String *str);
-ulonglong TIME_to_ulonglong_datetime(const TIME *time);
-ulonglong TIME_to_ulonglong_date(const TIME *time);
-ulonglong TIME_to_ulonglong_time(const TIME *time);
-ulonglong TIME_to_ulonglong(const TIME *time);
int test_if_number(char *str,int *res,bool allow_wildcards);
void change_byte(byte *,uint,char,char);
@@ -1130,6 +1301,8 @@ extern int yyparse(void *thd);
SQL_CRYPT *get_crypt_for_frm(void);
#endif
+#include "sql_view.h"
+
/* Some inline functions for more speed */
inline bool add_item_to_list(THD *thd, Item *item)
@@ -1156,7 +1329,7 @@ inline void mark_as_null_row(TABLE *table)
{
table->null_row=1;
table->status|=STATUS_NULL_ROW;
- bfill(table->null_flags,table->null_bytes,255);
+ bfill(table->null_flags,table->s->null_bytes,255);
}
inline void table_case_convert(char * name, uint length)
@@ -1206,8 +1379,8 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
table->const_table= 0;
table->null_row= 0;
table->status= STATUS_NO_RECORD;
- table->keys_in_use_for_query= table->keys_in_use;
- table->maybe_null= test(table->outer_join= table_list->outer_join);
+ table->keys_in_use_for_query= table->s->keys_in_use;
+ table->maybe_null= table_list->outer_join;
table->tablenr= tablenr;
table->map= (table_map) 1 << tablenr;
table->force_index= table_list->force_index;
@@ -1245,3 +1418,5 @@ bool check_stack_overrun(THD *thd,char *dummy);
inline void kill_delayed_threads(void) {}
#define check_stack_overrun(A, B) 0
#endif
+
+#endif /* MYSQL_CLIENT */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 682733abd89..169c9e057b5 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -22,6 +22,7 @@
#include "repl_failsafe.h"
#include "stacktrace.h"
#include "mysqld_suffix.h"
+#include "mysys_err.h"
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"
#endif
@@ -29,9 +30,6 @@
#include "ha_innodb.h"
#endif
#include "ha_myisam.h"
-#ifdef HAVE_ISAM
-#include "ha_isam.h"
-#endif
#ifdef HAVE_NDBCLUSTER_DB
#include "ha_ndbcluster.h"
#endif
@@ -46,14 +44,10 @@
#else
#define OPT_BDB_DEFAULT 0
#endif
-#ifdef HAVE_ISAM_DB
-#define OPT_ISAM_DEFAULT 1
-#else
-#define OPT_ISAM_DEFAULT 0
-#endif
#ifdef HAVE_NDBCLUSTER_DB
#define OPT_NDBCLUSTER_DEFAULT 0
-#if defined(NDB_SHM_TRANSPORTER) && MYSQL_VERSION_ID >= 50000
+#if defined(NOT_ENOUGH_TESTED) \
+ && defined(NDB_SHM_TRANSPORTER) && MYSQL_VERSION_ID >= 50000
#define OPT_NDB_SHM_DEFAULT 1
#else
#define OPT_NDB_SHM_DEFAULT 0
@@ -62,10 +56,11 @@
#define OPT_NDBCLUSTER_DEFAULT 0
#endif
-#include <nisam.h>
#include <thr_alarm.h>
#include <ft_global.h>
#include <errmsg.h>
+#include "sp_rcontext.h"
+#include "sp_cache.h"
#define mysqld_charset &my_charset_latin1
@@ -79,10 +74,6 @@
#define IF_PURIFY(A,B) (B)
#endif
-#ifndef INADDR_NONE
-#define INADDR_NONE -1 // Error value from inet_addr
-#endif
-
/* stack traces are only supported on linux intel */
#if defined(__linux__) && defined(__i386__) && defined(USE_PSTACK)
#define HAVE_STACK_TRACE_ON_SEGV
@@ -112,10 +103,11 @@ extern "C" { // Because of SCO 3.2V4.2
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
+#include <my_net.h>
#if defined(OS2)
# include <sys/un.h>
-#elif !defined( __WIN__)
+#elif !defined(__WIN__)
# ifndef __NETWARE__
#include <sys/resource.h>
# endif /* __NETWARE__ */
@@ -147,11 +139,11 @@ int deny_severity = LOG_WARNING;
#include <sys/mman.h>
#endif
+#ifdef __NETWARE__
#define zVOLSTATE_ACTIVE 6
#define zVOLSTATE_DEACTIVE 2
#define zVOLSTATE_MAINTENANCE 3
-#ifdef __NETWARE__
#include <nks/vm.h>
#include <library.h>
#include <monitor.h>
@@ -238,10 +230,17 @@ const char *sql_mode_names[] =
"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", NullS
+ "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",
+ NullS
};
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
sql_mode_names, NULL };
+const char *tc_heuristic_recover_names[]= { "COMMIT", "ROLLBACK", NullS };
+TYPELIB tc_heuristic_recover_typelib=
+ { array_elements(tc_heuristic_recover_names)-1,"",
+ tc_heuristic_recover_names, NULL };
const char *first_keyword= "first", *binary_keyword= "BINARY";
const char *my_localhost= "localhost", *delayed_user= "DELAYED";
#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
@@ -258,11 +257,12 @@ bool opt_large_files= sizeof(my_off_t) > 4;
bool opt_help= 0;
bool opt_verbose= 0;
-arg_cmp_func Arg_comparator::comparator_matrix[4][2] =
+arg_cmp_func Arg_comparator::comparator_matrix[5][2] =
{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string},
{&Arg_comparator::compare_real, &Arg_comparator::compare_e_real},
{&Arg_comparator::compare_int_signed, &Arg_comparator::compare_e_int},
- {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}};
+ {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row},
+ {&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal}};
/* Global variables */
@@ -287,7 +287,13 @@ my_bool opt_log_slave_updates= 0;
my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam, opt_ndbcluster;
#ifdef HAVE_NDBCLUSTER_DB
const char *opt_ndbcluster_connectstring= 0;
+const char *opt_ndb_connectstring= 0;
+char opt_ndb_constrbuf[1024];
+unsigned opt_ndb_constrbuf_len= 0;
my_bool opt_ndb_shm, opt_ndb_optimized_node_selection;
+ulong opt_ndb_cache_check_time;
+const char *opt_ndb_mgmd;
+ulong opt_ndb_nodeid;
#endif
my_bool opt_readonly, use_temp_pool, relay_log_purge;
my_bool opt_sync_bdb_logs, opt_sync_frm, opt_allow_suspicious_udfs;
@@ -295,8 +301,16 @@ my_bool opt_secure_auth= 0;
my_bool opt_short_log_format= 0;
my_bool opt_log_queries_not_using_indexes= 0;
my_bool lower_case_file_system= 0;
-my_bool opt_innodb_safe_binlog= 0;
+my_bool opt_large_pages= 0;
+uint opt_large_page_size= 0;
+my_bool opt_old_style_user_limits= 0;
+/*
+ True if there is at least one per-hour limit for some user, so we should
+ check them before each query (and possibly reset counters when hour is
+ changed). False otherwise.
+*/
volatile bool mqh_used = 0;
+my_bool sp_automatic_privileges= 1;
#ifdef HAVE_INITGROUPS
static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */
@@ -304,7 +318,7 @@ static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
uint delay_key_write_options, protocol_version;
uint lower_case_table_names;
-uint opt_crash_binlog_innodb;
+uint tc_heuristic_recover= 0;
uint volatile thread_count, thread_running, kill_cached_threads, wake_thread;
ulong back_log, connect_timeout, concurrency;
ulong server_id, thd_startup_options;
@@ -314,29 +328,24 @@ ulong open_files_limit, max_binlog_size, max_relay_log_size;
ulong slave_net_timeout, slave_trans_retries;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
-ulong com_stat[(uint) SQLCOM_END], com_other;
-ulong bytes_sent, bytes_received, net_big_packet_count;
ulong refresh_version, flush_version; /* Increments on each reload */
-ulong query_id, long_query_count;
+query_id_t query_id;
ulong aborted_threads, killed_threads, aborted_connects;
ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size;
ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use;
ulong delayed_insert_errors,flush_time, thread_created;
-ulong filesort_rows, filesort_range_count, filesort_scan_count;
-ulong filesort_merge_passes;
-ulong select_range_check_count, select_range_count, select_scan_count;
-ulong select_full_range_join_count,select_full_join_count;
-ulong specialflag=0,opened_tables=0,created_tmp_tables=0,
- created_tmp_disk_tables=0;
+ulong specialflag=0;
ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
ulong max_connections,max_used_connections,
- max_connect_errors, max_user_connections = 0;
+ max_connect_errors;
+uint max_user_connections= 0;
ulong thread_id=1L,current_pid;
ulong slow_launch_threads = 0, sync_binlog_period;
ulong expire_logs_days = 0;
ulong rpl_recovery_rank=0;
ulong my_bind_addr; /* the address we bind to */
volatile ulong cached_thread_count= 0;
+double last_query_cost= -1; /* -1 denotes that no query was compiled yet */
double log_10[32]; /* 10 potences */
time_t start_time;
@@ -348,7 +357,7 @@ char* log_error_file_ptr= log_error_file;
char mysql_real_data_home[FN_REFLEN],
language[FN_REFLEN], reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN],
*mysqld_user,*mysqld_chroot, *opt_init_file,
- *opt_init_connect, *opt_init_slave,
+ *opt_init_connect, *opt_init_slave, *opt_tc_log_file,
def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
const char *opt_date_time_formats[3];
@@ -366,6 +375,7 @@ const char *sql_mode_str="OFF";
const char *in_left_expr_name= "<left expr>";
/* name of additional condition */
const char *in_additional_cond= "<IN COND>";
+my_decimal decimal_zero;
/* classes for comparation parsing/processing */
Eq_creator eq_creator;
Ne_creator ne_creator;
@@ -376,6 +386,7 @@ Le_creator le_creator;
FILE *bootstrap_file;
+int bootstrap_error;
I_List<i_string_pair> replicate_rewrite_db;
I_List<i_string> replicate_do_db, replicate_ignore_db;
@@ -386,6 +397,7 @@ I_List<NAMED_LIST> key_caches;
struct system_variables global_system_variables;
struct system_variables max_system_variables;
+struct system_status_var global_status_var;
MY_TMPDIR mysql_tmpdir_list;
MY_BITMAP temp_pool;
@@ -395,6 +407,7 @@ CHARSET_INFO *national_charset_info, *table_alias_charset;
SHOW_COMP_OPTION have_berkeley_db, have_innodb, have_isam, have_ndbcluster,
have_example_db, have_archive_db, have_csv_db;
+SHOW_COMP_OPTION have_federated_db;
SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache;
SHOW_COMP_OPTION have_geometry, have_rtree_keys;
SHOW_COMP_OPTION have_crypt, have_compress;
@@ -405,7 +418,7 @@ SHOW_COMP_OPTION have_blackhole_db;
pthread_key(MEM_ROOT**,THR_MALLOC);
pthread_key(THD*, THR_THD);
pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
- LOCK_mapped_file, LOCK_status,
+ LOCK_mapped_file, LOCK_status, LOCK_global_read_lock,
LOCK_error_log, LOCK_uuid_generator,
LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
@@ -436,7 +449,7 @@ static my_bool opt_do_pstack, opt_noacl, opt_bootstrap, opt_myisam_log;
static int cleanup_done;
static ulong opt_specialflag, opt_myisam_block_size;
static char *opt_logname, *opt_update_logname, *opt_binlog_index_name;
-static char *opt_slow_logname;
+static char *opt_slow_logname, *opt_tc_heuristic_recover;
static char *mysql_home_ptr, *pidfile_name_ptr;
static char **defaults_argv;
static char *opt_bin_logname;
@@ -518,7 +531,7 @@ static char *get_relative_path(const char *path);
static void fix_paths(void);
extern "C" pthread_handler_decl(handle_connections_sockets,arg);
extern "C" pthread_handler_decl(kill_server_thread,arg);
-static int bootstrap(FILE *file);
+static void bootstrap(FILE *file);
static void close_server_sock();
static bool read_init_file(char *file_name);
#ifdef __NT__
@@ -545,6 +558,8 @@ static void close_connections(void)
#ifdef EXTRA_DEBUG
int count=0;
#endif
+ THD *thd= current_thd;
+
DBUG_ENTER("close_connections");
/* Clear thread cache */
@@ -555,14 +570,14 @@ static void close_connections(void)
(void) pthread_mutex_lock(&LOCK_manager);
if (manager_thread_in_use)
{
- DBUG_PRINT("quit",("killing manager thread: %lx",manager_thread));
+ DBUG_PRINT("quit",("killing manager thread: 0x%lx",manager_thread));
(void) pthread_cond_signal(&COND_manager);
}
(void) pthread_mutex_unlock(&LOCK_manager);
/* kill connection thread */
#if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2) && !defined(__NETWARE__)
- DBUG_PRINT("quit",("waiting for select thread: %lx",select_thread));
+ DBUG_PRINT("quit",("waiting for select thread: 0x%lx",select_thread));
(void) pthread_mutex_lock(&LOCK_thread_count);
while (select_thread_in_use)
@@ -596,7 +611,7 @@ static void close_connections(void)
/* Abort listening to new connections */
DBUG_PRINT("quit",("Closing sockets"));
- if ( !opt_disable_networking )
+ if (!opt_disable_networking )
{
if (ip_sock != INVALID_SOCKET)
{
@@ -609,7 +624,7 @@ static void close_connections(void)
if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
{
HANDLE temp;
- DBUG_PRINT( "quit", ("Closing named pipes") );
+ DBUG_PRINT("quit", ("Closing named pipes") );
/* Create connection to the handle named pipe handler to break the loop */
if ((temp = CreateFile(pipe_name,
@@ -651,7 +666,7 @@ static void close_connections(void)
{
DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
tmp->thread_id));
- tmp->killed=1;
+ tmp->killed= THD::KILL_CONNECTION;
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
@@ -775,7 +790,7 @@ void kill_mysql(void)
}
#endif
#elif defined(OS2)
- pthread_cond_signal( &eventShutdown); // post semaphore
+ pthread_cond_signal(&eventShutdown); // post semaphore
#elif defined(HAVE_PTHREAD_KILL)
if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL))
{
@@ -812,9 +827,9 @@ static void __cdecl kill_server(int sig_ptr)
#define RETURN_FROM_KILL_SERVER DBUG_VOID_RETURN
#endif
{
- int sig=(int) (long) sig_ptr; // This is passed a int
DBUG_ENTER("kill_server");
#ifndef EMBEDDED_LIBRARY
+ int sig=(int) (long) sig_ptr; // This is passed a int
// if there is a signal during the kill in progress, ignore the other
if (kill_in_progress) // Safety
RETURN_FROM_KILL_SERVER;
@@ -846,9 +861,10 @@ static void __cdecl kill_server(int sig_ptr)
unireg_abort(1); /* purecov: inspected */
else
unireg_end();
+
#ifdef __NETWARE__
- if (!event_flag)
- pthread_join(select_thread, NULL); // wait for main thread
+ if(!event_flag)
+ pthread_join(select_thread, NULL); // wait for main thread
#endif /* __NETWARE__ */
pthread_exit(0); /* purecov: deadcode */
@@ -939,7 +955,6 @@ void clean_up(bool print_message)
mysql_log.cleanup();
mysql_slow_log.cleanup();
- mysql_update_log.cleanup();
mysql_bin_log.cleanup();
#ifdef HAVE_REPLICATION
@@ -964,6 +979,8 @@ void clean_up(bool print_message)
udf_free();
#endif
(void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */
+ if (tc_log)
+ tc_log->close();
delete_elements(&key_caches, (void (*)(const char*, gptr)) free_key_cache);
multi_keycache_free();
end_thr_alarm(1); /* Free allocated memory */
@@ -1012,7 +1029,9 @@ void clean_up(bool print_message)
if (!opt_bootstrap)
(void) my_delete(pidfile_name,MYF(0)); // This may not always exist
#endif
- x_free((gptr) my_errmsg[ERRMAPP]); /* Free messages */
+ finish_client_errs();
+ my_free((gptr) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST),
+ MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
DBUG_PRINT("quit", ("Error messages freed"));
/* Tell main we are ready */
(void) pthread_mutex_lock(&LOCK_thread_count);
@@ -1078,6 +1097,7 @@ static void clean_up_mutexes()
(void) rwlock_destroy(&LOCK_sys_init_connect);
(void) rwlock_destroy(&LOCK_sys_init_slave);
(void) pthread_mutex_destroy(&LOCK_global_system_variables);
+ (void) pthread_mutex_destroy(&LOCK_global_read_lock);
(void) pthread_cond_destroy(&COND_thread_count);
(void) pthread_cond_destroy(&COND_refresh);
(void) pthread_cond_destroy(&COND_thread_cache);
@@ -1173,7 +1193,7 @@ err:
static void set_user(const char *user, struct passwd *user_info)
{
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
- DBUG_ASSERT(user_info);
+ DBUG_ASSERT(user_info != 0);
#ifdef HAVE_INITGROUPS
/*
We can get a SIGSEGV when calling initgroups() on some systems when NSS
@@ -1202,7 +1222,7 @@ static void set_user(const char *user, struct passwd *user_info)
static void set_effective_user(struct passwd *user_info)
{
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
- DBUG_ASSERT(user_info);
+ DBUG_ASSERT(user_info != 0);
if (setregid((gid_t)-1, user_info->pw_gid) == -1)
{
sql_perror("setregid");
@@ -1241,12 +1261,13 @@ static void server_init(void)
DBUG_ENTER("server_init");
#ifdef __WIN__
- if ( !opt_disable_networking )
+ if (!opt_disable_networking)
{
WSADATA WsaData;
if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
{
- my_message(0,"WSAStartup Failed\n",MYF(0));
+ /* errors are not read yet, so we use test here */
+ my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0));
unireg_abort(1);
}
}
@@ -1325,7 +1346,7 @@ static void server_init(void)
sql_perror("Can't start server : Set security descriptor");
unireg_abort(1);
}
- saPipeSecurity.nLength = sizeof( SECURITY_ATTRIBUTES );
+ saPipeSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor;
saPipeSecurity.bInheritHandle = FALSE;
if ((hPipe= CreateNamedPipe(pipe_name,
@@ -1345,9 +1366,9 @@ static void server_init(void)
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL );
- MessageBox( NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
- MB_OK|MB_ICONINFORMATION );
- LocalFree( lpMsgBuf );
+ MessageBox(NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
+ MB_OK|MB_ICONINFORMATION);
+ LocalFree(lpMsgBuf);
unireg_abort(1);
}
}
@@ -1408,8 +1429,9 @@ void yyerror(const char *s)
/* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
s=ER(ER_SYNTAX_ERROR);
- net_printf(thd,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "",
- thd->lex->yylineno);
+ my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0), s,
+ (yytext ? (char*) yytext : ""),
+ thd->lex->yylineno);
}
@@ -1437,11 +1459,11 @@ void close_connection(THD *thd, uint errcode, bool lock)
errcode ? ER(errcode) : ""));
if (lock)
(void) pthread_mutex_lock(&LOCK_thread_count);
- thd->killed=1;
- if ((vio=thd->net.vio) != 0)
+ thd->killed= THD::KILL_CONNECTION;
+ if ((vio= thd->net.vio) != 0)
{
if (errcode)
- send_error(thd, errcode, ER(errcode)); /* purecov: inspected */
+ net_send_error(thd, errcode, ER(errcode)); /* purecov: inspected */
vio_close(vio); /* vio is freed in delete thd */
}
if (lock)
@@ -1554,7 +1576,7 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
THD *thd=current_thd;
DBUG_ENTER("abort_thread");
if (thd)
- thd->killed=1;
+ thd->killed= THD::KILL_CONNECTION;
DBUG_VOID_RETURN;
}
#endif
@@ -1570,7 +1592,7 @@ static void init_signals(void)
{
int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ;
for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++)
- signal( signals[i], kill_server) ;
+ signal(signals[i], kill_server) ;
#if defined(__WIN__)
signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT
#else
@@ -1594,18 +1616,18 @@ static void check_data_home(const char *path)
// down server event callback
void mysql_down_server_cb(void *, void *)
{
- event_flag = TRUE;
+ event_flag= TRUE;
kill_server(0);
}
// destroy callback resources
void mysql_cb_destroy(void *)
-{
- UnRegisterEventNotification(eh); // cleanup down event notification
+{
+ UnRegisterEventNotification(eh); // cleanup down event notification
NX_UNWRAP_INTERFACE(ref);
- /* Deregister NSS volume deactivation event */
- NX_UNWRAP_INTERFACE(refneb);
+ /* Deregister NSS volume deactivation event */
+ NX_UNWRAP_INTERFACE(refneb);
if (neb_consumer_id)
UnRegisterConsumer(neb_consumer_id, NULL);
}
@@ -1728,7 +1750,6 @@ ulong neb_event_callback(struct EventBlock *eblock)
nw_panic = TRUE;
event_flag= TRUE;
kill_server(0);
-
}
}
return 0;
@@ -1786,7 +1807,7 @@ static void getvolumeID(BYTE *volumeName)
datavolid.clockSeqLow= info.vol.volumeID.clockSeqLow;
/* This is guranteed to be 6-byte length (but sizeof() would be better) */
memcpy(datavolid.node, info.vol.volumeID.node, (unsigned int) 6);
-
+
exit:
if (rootKey)
zClose(rootKey);
@@ -2170,7 +2191,7 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
if (!(opt_specialflag & SPECIAL_NO_PRIOR))
my_pthread_attr_setprio(&connection_attrib,INTERRUPT_PRIOR);
if (pthread_create(&tmp,&connection_attrib, kill_server_thread,
- (void*) sig))
+ (void*) &sig))
sql_print_error("Can't create thread to kill server");
#else
kill_server((void*) sig); // MIT THREAD has a alarm thread
@@ -2180,10 +2201,10 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
case SIGHUP:
if (!abort_loop)
{
- mysql_print_status((THD*) 0); // Print some debug info
+ mysql_print_status(); // Print some debug info
reload_acl_and_cache((THD*) 0,
(REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
- REFRESH_STATUS | REFRESH_GRANT |
+ REFRESH_GRANT |
REFRESH_THREADS | REFRESH_HOSTS),
(TABLE_LIST*) 0, NULL); // Flush logs
}
@@ -2211,8 +2232,8 @@ static void check_data_home(const char *path)
/*
- All global error messages are sent here where the first one is stored for
- the client
+ All global error messages are sent here where the first one is stored
+ for the client
*/
@@ -2221,9 +2242,24 @@ extern "C" int my_message_sql(uint error, const char *str, myf MyFlags)
{
THD *thd;
DBUG_ENTER("my_message_sql");
- DBUG_PRINT("error", ("Message: '%s'", str));
+ DBUG_PRINT("error", ("error: %u message: '%s'", error, str));
+ /*
+ Put here following assertion when situation with EE_* error codes
+ will be fixed
+ DBUG_ASSERT(error != 0);
+ */
if ((thd= current_thd))
{
+ if (thd->spcont &&
+ thd->spcont->find_handler(error, MYSQL_ERROR::WARN_LEVEL_ERROR))
+ {
+ DBUG_RETURN(0);
+ }
+
+ thd->query_error= 1; // needed to catch query errors during replication
+
+ if (!thd->no_warnings_for_error)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
/*
thd->lex->current_select == 0 if lex structure is not inited
(not query command (COM_QUERY))
@@ -2235,13 +2271,14 @@ extern "C" int my_message_sql(uint error, const char *str, myf MyFlags)
(thd->lex->current_select ?
thd->lex->current_select->no_error : 0),
(int) thd->is_fatal_error));
-
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
}
else
{
NET *net= &thd->net;
net->report_error= 1;
+#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
+ query_cache_abort(net);
+#endif
if (!net->last_error[0]) // Return only first message
{
strmake(net->last_error, str, sizeof(net->last_error)-1);
@@ -2302,10 +2339,10 @@ extern "C" pthread_handler_decl(handle_shutdown,arg)
my_thread_init();
// wait semaphore
- pthread_cond_wait( &eventShutdown, NULL);
+ pthread_cond_wait(&eventShutdown, NULL);
// close semaphore and kill server
- pthread_cond_destroy( &eventShutdown);
+ pthread_cond_destroy(&eventShutdown);
/*
Exit main loop on main thread, so kill will be done from
@@ -2322,44 +2359,16 @@ extern "C" pthread_handler_decl(handle_shutdown,arg)
#endif
-const char *load_default_groups[]= {
+const char *load_default_groups[]= {
#ifdef HAVE_NDBCLUSTER_DB
"mysql_cluster",
#endif
-"mysqld","server",MYSQL_BASE_VERSION,0,0};
+"mysqld","server", MYSQL_BASE_VERSION, 0, 0};
+
+#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
static const int load_default_groups_sz=
sizeof(load_default_groups)/sizeof(load_default_groups[0]);
-
-bool open_log(MYSQL_LOG *log, const char *hostname,
- const char *opt_name, const char *extension,
- const char *index_file_name,
- enum_log_type type, bool read_append,
- bool no_auto_events, ulong max_size)
-{
- char tmp[FN_REFLEN];
- if (!opt_name || !opt_name[0])
- {
- /*
- TODO: The following should be using fn_format(); We just need to
- first change fn_format() to cut the file name if it's too long.
- */
- strmake(tmp,hostname,FN_REFLEN-5);
- strmov(fn_ext(tmp),extension);
- opt_name=tmp;
- }
- // get rid of extension if the log is binary to avoid problems
- if (type == LOG_BIN)
- {
- char *p = fn_ext(opt_name);
- uint length=(uint) (p-opt_name);
- strmake(tmp,opt_name,min(length,FN_REFLEN));
- opt_name=tmp;
- }
- return log->open(opt_name, type, 0, index_file_name,
- (read_append) ? SEQ_READ_APPEND : WRITE_CACHE,
- no_auto_events, max_size);
-}
-
+#endif
/*
Initialize one of the global date/time format variables
@@ -2368,7 +2377,7 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
init_global_datetime_format()
format_type What kind of format should be supported
var_ptr Pointer to variable that should be updated
-
+
NOTES
The default value is taken from either opt_date_time_formats[] or
the ISO format (ANSI SQL)
@@ -2407,6 +2416,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
char **argv, const char **groups)
{
umask(((~my_umask) & 0666));
+ my_decimal_set_zero(&decimal_zero); // set decimal_zero constant;
tzset(); // Set tzname
max_system_variables.pseudo_thread_id= (ulong)~0;
@@ -2447,7 +2457,6 @@ static int init_common_variables(const char *conf_file_name, int argc,
before MY_INIT(). So we do it here.
*/
mysql_log.init_pthread_objects();
- mysql_update_log.init_pthread_objects();
mysql_slow_log.init_pthread_objects();
mysql_bin_log.init_pthread_objects();
@@ -2464,6 +2473,19 @@ static int init_common_variables(const char *conf_file_name, int argc,
DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname,
server_version, SYSTEM_TYPE,MACHINE_TYPE));
+#ifdef HAVE_LARGE_PAGES
+ /* Initialize large page size */
+ if (opt_large_pages && (opt_large_page_size= my_get_large_page_size()))
+ {
+ my_use_large_pages= 1;
+ my_large_page_size= opt_large_page_size;
+#ifdef HAVE_INNOBASE_DB
+ innobase_use_large_pages= 1;
+ innobase_large_page_size= opt_large_page_size;
+#endif
+ }
+#endif /* HAVE_LARGE_PAGES */
+
/* connections and databases needs lots of files */
{
uint files, wanted_files;
@@ -2572,6 +2594,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
(void) my_rwlock_init(&LOCK_sys_init_connect, NULL);
(void) my_rwlock_init(&LOCK_sys_init_slave, NULL);
@@ -2585,6 +2608,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_rpl_status, NULL);
#endif
+ sp_cache_init();
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
@@ -2612,7 +2636,7 @@ static void init_ssl()
ssl_acceptor_fd= new_VioSSLAcceptorFd(opt_ssl_key, opt_ssl_cert,
opt_ssl_ca, opt_ssl_capath,
opt_ssl_cipher);
- DBUG_PRINT("info",("ssl_acceptor_fd: %lx", (long) ssl_acceptor_fd));
+ DBUG_PRINT("info",("ssl_acceptor_fd: 0x%lx", (long) ssl_acceptor_fd));
if (!ssl_acceptor_fd)
opt_use_ssl = 0;
}
@@ -2639,41 +2663,69 @@ static int init_server_components()
#endif
/* Setup log files */
if (opt_log)
- open_log(&mysql_log, glob_hostname, opt_logname, ".log", NullS,
- LOG_NORMAL, 0, 0, 0);
+ mysql_log.open_query_log(opt_logname);
if (opt_update_log)
{
- open_log(&mysql_update_log, glob_hostname, opt_update_logname, "",
- NullS, LOG_NEW, 0, 0, 0);
- using_update_log=1;
- }
- if (opt_slow_log)
- open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
- NullS, LOG_NORMAL, 0, 0, 0);
-
- if (opt_bin_log)
- {
- /* If we fail to open binlog, it's going to hinder our recovery, so die */
- if (open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin",
- opt_binlog_index_name, LOG_BIN, 0, 0, max_binlog_size))
- unireg_abort(1);
- using_update_log=1;
-#ifdef HAVE_REPLICATION
- if (expire_logs_days)
+ /*
+ Update log is removed since 5.0. But we still accept the option.
+ The idea is if the user already uses the binlog and the update log,
+ we completely ignore any option/variable related to the update log, like
+ if the update log did not exist. But if the user uses only the update log,
+ then we translate everything into binlog for him (with warnings).
+ Implementation of the above :
+ - If mysqld is started with --log-update and --log-bin,
+ ignore --log-update (print a warning), push a warning when SQL_LOG_UPDATE
+ is used, and turn off --sql-bin-update-same.
+ This will completely ignore SQL_LOG_UPDATE
+ - If mysqld is started with --log-update only,
+ change it to --log-bin (with the filename passed to log-update,
+ plus '-bin') (print a warning), push a warning when SQL_LOG_UPDATE is
+ used, and turn on --sql-bin-update-same.
+ This will translate SQL_LOG_UPDATE to SQL_LOG_BIN.
+
+ Note that we tell the user that --sql-bin-update-same is deprecated and
+ does nothing, and we don't take into account if he used this option or
+ not; but internally we give this variable a value to have the behaviour we
+ want (i.e. have SQL_LOG_UPDATE influence SQL_LOG_BIN or not).
+ As sql-bin-update-same, log-update and log-bin cannot be changed by the
+ user after starting the server (they are not variables), the user will not
+ later interfere with the settings we do here.
+ */
+ if (opt_bin_log)
{
- long purge_time= time(0) - expire_logs_days*24*60*60;
- if (purge_time >= 0)
- mysql_bin_log.purge_logs_before_date(purge_time);
+ opt_sql_bin_update= 0;
+ sql_print_error("The update log is no longer supported by MySQL in \
+version 5.0 and above. It is replaced by the binary log.");
+ }
+ else
+ {
+ opt_sql_bin_update= 1;
+ opt_bin_log= 1;
+ if (opt_update_logname)
+ {
+ // as opt_bin_log==0, no need to free opt_bin_logname
+ if (!(opt_bin_logname= my_strdup(opt_update_logname, MYF(MY_WME))))
+ exit(EXIT_OUT_OF_MEMORY);
+ sql_print_error("The update log is no longer supported by MySQL in \
+version 5.0 and above. It is replaced by the binary log. Now starting MySQL \
+with --log-bin='%s' instead.",opt_bin_logname);
+ }
+ else
+ sql_print_error("The update log is no longer supported by MySQL in \
+version 5.0 and above. It is replaced by the binary log. Now starting MySQL \
+with --log-bin instead.");
}
-#endif
}
- else if (opt_log_slave_updates)
+ if (opt_log_slave_updates && !opt_bin_log)
{
- sql_print_warning("\
-you need to use --log-bin to make --log-slave-updates work. \
-Now disabling --log-slave-updates.");
+ sql_print_warning("You need to use --log-bin to make "
+ "--log-slave-updates work.");
+ unireg_abort(1);
}
+ if (opt_slow_log)
+ mysql_slow_log.open_slow_log(opt_slow_logname);
+
#ifdef HAVE_REPLICATION
if (opt_log_slave_updates && replicate_same_server_id)
{
@@ -2704,39 +2756,33 @@ server.");
}
}
- if (opt_innodb_safe_binlog)
+ if (opt_bin_log)
{
- if (have_innodb != SHOW_OPTION_YES)
- sql_print_warning("--innodb-safe-binlog is meaningful only if "
- "the InnoDB storage engine is enabled in the server.");
-#ifdef HAVE_INNOBASE_DB
- if (innobase_flush_log_at_trx_commit != 1)
- {
- sql_print_warning("--innodb-safe-binlog is meaningful only if "
- "innodb_flush_log_at_trx_commit is 1; now setting it "
- "to 1.");
- innobase_flush_log_at_trx_commit= 1;
- }
- if (innobase_unix_file_flush_method)
+ char buf[FN_REFLEN];
+ const char *ln;
+ ln= mysql_bin_log.generate_name(opt_bin_logname, "-bin", 1, buf);
+ if (!opt_bin_logname && !opt_binlog_index_name)
{
/*
- This option has so many values that it's hard to know which value is
- good (especially "littlesync", and on Windows... see
- srv/srv0start.c).
+ User didn't give us info to name the binlog index file.
+ Picking `hostname`-bin.index like did in 4.x, causes replication to
+ fail if the hostname is changed later. So, we would like to instead
+ require a name. But as we don't want to break many existing setups, we
+ only give warning, not error.
*/
- sql_print_warning("--innodb-safe-binlog requires that "
- "the innodb_flush_method actually synchronizes the "
- "InnoDB log to disk; it is your responsibility "
- "to verify that the method you chose does it.");
+ sql_print_warning("No argument was provided to --log-bin, and "
+ "--log-bin-index was not used; so replication "
+ "may break when this MySQL server acts as a "
+ "master and has his hostname changed!! Please "
+ "use '--log-bin=%s' to avoid this problem.", ln);
}
- if (sync_binlog_period != 1)
+ if (ln == buf)
{
- sql_print_warning("--innodb-safe-binlog is meaningful only if "
- "the global sync_binlog variable is 1; now setting it "
- "to 1.");
- sync_binlog_period= 1;
+ my_free(opt_bin_logname, MYF(MY_ALLOW_ZERO_PTR));
+ opt_bin_logname=my_strdup(buf, MYF(0));
}
-#endif
+ mysql_bin_log.open_index_file(opt_binlog_index_name, ln);
+ using_update_log=1;
}
if (ha_init())
@@ -2744,20 +2790,37 @@ server.");
sql_print_error("Can't init databases");
unireg_abort(1);
}
- if (opt_myisam_log)
- (void) mi_log(1);
+ tc_log= total_ha_2pc > 1 ? opt_bin_log ?
+ (TC_LOG *)&mysql_bin_log :
+ (TC_LOG *)&tc_log_mmap :
+ (TC_LOG *)&tc_log_dummy;
- /*
- Now that InnoDB is initialized, we can know the last good binlog position
- and cut the binlog if needed. This function does nothing if there was no
- crash recovery by InnoDB.
- */
- if (opt_innodb_safe_binlog)
+ if (tc_log->open(opt_bin_logname))
+ {
+ sql_print_error("Can't init tc log");
+ unireg_abort(1);
+ }
+
+ if (ha_recover(0))
+ {
+ unireg_abort(1);
+ }
+
+ if (opt_bin_log && mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0,
+ WRITE_CACHE, 0, max_binlog_size, 0))
+ unireg_abort(1);
+
+#ifdef HAVE_REPLICATION
+ if (opt_bin_log && expire_logs_days)
{
- /* not fatal if fails (but print errors) */
- mysql_bin_log.cut_spurious_tail();
+ long purge_time= time(0) - expire_logs_days*24*60*60;
+ if (purge_time >= 0)
+ mysql_bin_log.purge_logs_before_date(purge_time);
}
- mysql_bin_log.report_pos_in_innodb();
+#endif
+
+ if (opt_myisam_log)
+ (void) mi_log(1);
/* call ha_init_key_cache() on all key caches to init them */
process_key_caches(&ha_init_key_cache);
@@ -2915,7 +2978,7 @@ int main(int argc, char **argv)
if (_cust_check_startup())
{
/ * _cust_check_startup will report startup failure error * /
- exit( 1 );
+ exit(1);
}
#endif
@@ -3085,9 +3148,9 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (opt_bootstrap)
{
select_thread_in_use= 0; // Allow 'kill' to work
- int error= bootstrap(stdin);
+ bootstrap(stdin);
end_thr_alarm(1); // Don't allow alarms
- unireg_abort(error ? 1 : 0);
+ unireg_abort(bootstrap_error ? 1 : 0);
}
if (opt_init_file)
{
@@ -3101,20 +3164,17 @@ we force server id to 2, but this MySQL server will not act as a slave.");
create_shutdown_thread();
create_maintenance_thread();
- printf(ER(ER_READY),my_progname,server_version,
- ((unix_sock == INVALID_SOCKET) ? (char*) "" : mysqld_unix_port),
- mysqld_port, "");
- if (MYSQL_COMPILATION_COMMENT[0] != '\0')
- fputs(" " MYSQL_COMPILATION_COMMENT, stdout);
-
- putchar('\n');
- fflush(stdout);
+ sql_print_information(ER(ER_STARTUP),my_progname,server_version,
+ ((unix_sock == INVALID_SOCKET) ? (char*) ""
+ : mysqld_unix_port),
+ mysqld_port,
+ MYSQL_COMPILATION_COMMENT);
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();
#else
#ifdef __WIN__
- if ( !have_tcpip || opt_disable_networking)
+ if (!have_tcpip || opt_disable_networking)
{
sql_print_error("TCP/IP unavailable or disabled with --skip-networking; no available interfaces");
unireg_abort(1);
@@ -3217,7 +3277,8 @@ default_service_handling(char **argv,
const char *servicename,
const char *displayname,
const char *file_path,
- const char *extra_opt)
+ const char *extra_opt,
+ const char *account_name)
{
char path_and_service[FN_REFLEN+FN_REFLEN+32], *pos, *end;
end= path_and_service + sizeof(path_and_service)-3;
@@ -3236,12 +3297,14 @@ default_service_handling(char **argv,
if (Service.got_service_option(argv, "install"))
{
- Service.Install(1, servicename, displayname, path_and_service);
+ Service.Install(1, servicename, displayname, path_and_service,
+ account_name);
return 0;
}
if (Service.got_service_option(argv, "install-manual"))
{
- Service.Install(0, servicename, displayname, path_and_service);
+ Service.Install(0, servicename, displayname, path_and_service,
+ account_name);
return 0;
}
if (Service.got_service_option(argv, "remove"))
@@ -3256,13 +3319,14 @@ default_service_handling(char **argv,
int main(int argc, char **argv)
{
- /* When several instances are running on the same machine, we
- need to have an unique named hEventShudown through the
- application PID e.g.: MySQLShutdown1890; MySQLShutdown2342
- */
+ /*
+ When several instances are running on the same machine, we
+ need to have an unique named hEventShudown through the
+ application PID e.g.: MySQLShutdown1890; MySQLShutdown2342
+ */
int10_to_str((int) GetCurrentProcessId(),strmov(shutdown_event_name,
- "MySQLShutdown"), 10);
-
+ "MySQLShutdown"), 10);
+
/* Must be initialized early for comparison of service name */
system_charset_info= &my_charset_utf8_general_ci;
@@ -3276,7 +3340,7 @@ int main(int argc, char **argv)
if (argc == 2)
{
if (!default_service_handling(argv, MYSQL_SERVICENAME, MYSQL_SERVICENAME,
- file_path, ""))
+ file_path, "", NULL))
return 0;
if (Service.IsService(argv[1])) /* Start an optional service */
{
@@ -3295,7 +3359,8 @@ int main(int argc, char **argv)
}
else if (argc == 3) /* install or remove any optional service */
{
- if (!default_service_handling(argv, argv[2], argv[2], file_path, ""))
+ if (!default_service_handling(argv, argv[2], argv[2], file_path, "",
+ NULL))
return 0;
if (Service.IsService(argv[2]))
{
@@ -3313,15 +3378,30 @@ int main(int argc, char **argv)
return 0;
}
}
- else if (argc == 4)
+ else if (argc == 4 || argc == 5)
{
/*
- Install an optional service with optional config file
- mysqld --install-manual mysqldopt --defaults-file=c:\miguel\my.ini
+ This may seem strange, because we handle --local-service while
+ preserving 4.1's behavior of allowing any one other argument that is
+ passed to the service on startup. (The assumption is that this is
+ --defaults-file=file, but that was not enforced in 4.1, so we don't
+ enforce it here.)
*/
- if (!default_service_handling(argv, argv[2], argv[2], file_path,
- argv[3]))
- return 0;
+ const char *extra_opt= NullS;
+ const char *account_name = NullS;
+ int index;
+ for (index = 3; index < argc; index++)
+ {
+ if (!strcmp(argv[index], "--local-service"))
+ account_name= "NT AUTHORITY\\LocalService";
+ else
+ extra_opt= argv[index];
+ }
+
+ if (argc == 4 || account_name)
+ if (!default_service_handling(argv, argv[2], argv[2], file_path,
+ extra_opt, account_name))
+ return 0;
}
else if (argc == 1 && Service.IsService(MYSQL_SERVICENAME))
{
@@ -3345,9 +3425,8 @@ int main(int argc, char **argv)
create MySQL privilege tables without having to start a full MySQL server.
*/
-static int bootstrap(FILE *file)
+static void bootstrap(FILE *file)
{
- int error= 0;
DBUG_ENTER("bootstrap");
THD *thd= new THD;
@@ -3365,7 +3444,8 @@ static int bootstrap(FILE *file)
(void*) thd))
{
sql_print_warning("Can't create thread to handle bootstrap");
- DBUG_RETURN(-1);
+ bootstrap_error=-1;
+ DBUG_VOID_RETURN;
}
/* Wait for thread to die */
(void) pthread_mutex_lock(&LOCK_thread_count);
@@ -3380,13 +3460,7 @@ static int bootstrap(FILE *file)
handle_bootstrap((void *)thd);
#endif
- error= thd->is_fatal_error;
-#ifndef EMBEDDED_LIBRARY
- net_end(&thd->net);
-#endif
- thd->cleanup();
- delete thd;
- DBUG_RETURN(error);
+ DBUG_VOID_RETURN;
}
@@ -3397,7 +3471,7 @@ static bool read_init_file(char *file_name)
DBUG_PRINT("enter",("name: %s",file_name));
if (!(file=my_fopen(file_name,O_RDONLY,MYF(MY_WME))))
return(1);
- bootstrap(file); /* Ignore errors from this */
+ bootstrap(file);
(void) my_fclose(file,MYF(MY_WME));
return 0;
}
@@ -3462,10 +3536,10 @@ static void create_new_thread(THD *thd)
("Can't create thread to handle request (error %d)",
error));
thread_count--;
- thd->killed=1; // Safety
+ thd->killed= THD::KILL_CONNECTION; // Safety
(void) pthread_mutex_unlock(&LOCK_thread_count);
statistic_increment(aborted_connects,&LOCK_status);
- net_printf(thd,ER_CANT_CREATE_THREAD,error);
+ net_printf_error(thd, ER_CANT_CREATE_THREAD, error);
(void) pthread_mutex_lock(&LOCK_thread_count);
close_connection(thd,0,0);
delete thd;
@@ -3689,7 +3763,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
if (!(vio_tmp=vio_new(new_sock,
sock == unix_sock ? VIO_TYPE_SOCKET :
VIO_TYPE_TCPIP,
- sock == unix_sock)) ||
+ sock == unix_sock ? VIO_LOCALHOST: 0)) ||
my_net_init(&thd->net,vio_tmp))
{
if (vio_tmp)
@@ -3736,25 +3810,27 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
while (!abort_loop)
{
/* wait for named pipe connection */
- fConnected = ConnectNamedPipe( hPipe, NULL );
+ fConnected = ConnectNamedPipe(hPipe, NULL);
if (abort_loop)
break;
if (!fConnected)
fConnected = GetLastError() == ERROR_PIPE_CONNECTED;
if (!fConnected)
{
- CloseHandle( hPipe );
- if ((hPipe = CreateNamedPipe(pipe_name,
- PIPE_ACCESS_DUPLEX,
- PIPE_TYPE_BYTE |
- PIPE_READMODE_BYTE |
- PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- (int) global_system_variables.net_buffer_length,
- (int) global_system_variables.net_buffer_length,
- NMPWAIT_USE_DEFAULT_WAIT,
- &saPipeSecurity )) ==
- INVALID_HANDLE_VALUE )
+ CloseHandle(hPipe);
+ if ((hPipe= CreateNamedPipe(pipe_name,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_BYTE |
+ PIPE_READMODE_BYTE |
+ PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ (int) global_system_variables.
+ net_buffer_length,
+ (int) global_system_variables.
+ net_buffer_length,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &saPipeSecurity)) ==
+ INVALID_HANDLE_VALUE)
{
sql_perror("Can't create new named pipe!");
break; // Abort
@@ -3781,8 +3857,8 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
if (!(thd = new THD))
{
- DisconnectNamedPipe( hConnectedPipe );
- CloseHandle( hConnectedPipe );
+ DisconnectNamedPipe(hConnectedPipe);
+ CloseHandle(hConnectedPipe);
continue;
}
if (!(thd->net.vio = vio_new_win32pipe(hConnectedPipe)) ||
@@ -3883,7 +3959,7 @@ pthread_handler_decl(handle_connections_shared_memory,arg)
/*
it can be after shutdown command
*/
- if (abort_loop)
+ if (abort_loop)
goto error;
HANDLE handle_client_file_map= 0;
@@ -4066,7 +4142,7 @@ enum options_mysqld
OPT_MASTER_HOST, OPT_MASTER_USER,
OPT_MASTER_PASSWORD, OPT_MASTER_PORT,
OPT_MASTER_INFO_FILE, OPT_MASTER_CONNECT_RETRY,
- OPT_MASTER_RETRY_COUNT,
+ OPT_MASTER_RETRY_COUNT, OPT_LOG_TC, OPT_LOG_TC_SIZE,
OPT_MASTER_SSL, OPT_MASTER_SSL_KEY,
OPT_MASTER_SSL_CERT, OPT_MASTER_SSL_CAPATH,
OPT_MASTER_SSL_CIPHER, OPT_MASTER_SSL_CA,
@@ -4080,7 +4156,7 @@ enum options_mysqld
OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE,
OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
OPT_REPLICATE_WILD_IGNORE_TABLE, OPT_REPLICATE_SAME_SERVER_ID,
- OPT_DISCONNECT_SLAVE_EVENT_COUNT,
+ OPT_DISCONNECT_SLAVE_EVENT_COUNT, OPT_TC_HEURISTIC_RECOVER,
OPT_ABORT_SLAVE_EVENT_COUNT,
OPT_INNODB_DATA_HOME_DIR,
OPT_INNODB_DATA_FILE_PATH,
@@ -4089,16 +4165,20 @@ enum options_mysqld
OPT_INNODB_LOG_ARCHIVE,
OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
OPT_INNODB_FLUSH_METHOD,
+ OPT_INNODB_DOUBLEWRITE,
+ OPT_INNODB_CHECKSUMS,
OPT_INNODB_FAST_SHUTDOWN,
OPT_INNODB_FILE_PER_TABLE, OPT_CRASH_BINLOG_INNODB,
OPT_INNODB_LOCKS_UNSAFE_FOR_BINLOG,
OPT_SAFE_SHOW_DB, OPT_INNODB_SAFE_BINLOG,
OPT_INNODB, OPT_ISAM,
+ OPT_ENGINE_CONDITION_PUSHDOWN,
OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDB_USE_EXACT_COUNT,
OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
- OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION,
+ OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_CACHE_CHECK_TIME,
+ OPT_NDB_MGMD, OPT_NDB_NODEID,
OPT_SKIP_SAFEMALLOC,
- OPT_TEMP_POOL, OPT_TX_ISOLATION,
+ OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
@@ -4129,7 +4209,7 @@ enum options_mysqld
OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
OPT_MAX_LENGTH_FOR_SORT_DATA,
OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
- OPT_MAX_ERROR_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
+ OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
@@ -4160,8 +4240,12 @@ enum options_mysqld
OPT_INNODB_STATUS_FILE,
OPT_INNODB_MAX_DIRTY_PAGES_PCT,
OPT_INNODB_TABLE_LOCKS,
+ OPT_INNODB_SUPPORT_XA,
OPT_INNODB_OPEN_FILES,
OPT_INNODB_AUTOEXTEND_INCREMENT,
+ OPT_INNODB_SYNC_SPIN_LOOPS,
+ OPT_INNODB_CONCURRENCY_TICKETS,
+ OPT_INNODB_THREAD_SLEEP_DELAY,
OPT_BDB_CACHE_SIZE,
OPT_BDB_LOG_BUFFER_SIZE,
OPT_BDB_MAX_LOCK,
@@ -4188,7 +4272,15 @@ enum options_mysqld
OPT_TIME_FORMAT,
OPT_DATETIME_FORMAT,
OPT_LOG_QUERIES_NOT_USING_INDEXES,
- OPT_DEFAULT_TIME_ZONE
+ OPT_DEFAULT_TIME_ZONE,
+ OPT_OPTIMIZER_SEARCH_DEPTH,
+ OPT_OPTIMIZER_PRUNE_LEVEL,
+ OPT_UPDATABLE_VIEWS_WITH_LIMIT,
+ OPT_SP_AUTOMATIC_PRIVILEGES,
+ OPT_AUTO_INCREMENT, OPT_AUTO_INCREMENT_OFFSET,
+ OPT_ENABLE_LARGE_PAGES,
+ OPT_TIMED_MUTEXES,
+ OPT_OLD_STYLE_USER_LIMITS
};
@@ -4214,6 +4306,20 @@ struct my_option my_long_options[] =
"from libc.so",
(gptr*) &opt_allow_suspicious_udfs, (gptr*) &opt_allow_suspicious_udfs,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"auto-increment-increment", OPT_AUTO_INCREMENT,
+ "Auto-increment columns are incremented by this",
+ (gptr*) &global_system_variables.auto_increment_increment,
+ (gptr*) &max_system_variables.auto_increment_increment, 0, GET_ULONG,
+ OPT_ARG, 1, 1, 65535, 0, 1, 0 },
+ {"auto-increment-offset", OPT_AUTO_INCREMENT_OFFSET,
+ "Offset added to Auto-increment columns. Used when auto-increment-increment != 1",
+ (gptr*) &global_system_variables.auto_increment_offset,
+ (gptr*) &max_system_variables.auto_increment_offset, 0, GET_ULONG, OPT_ARG,
+ 1, 1, 65535, 0, 1, 0 },
+ {"automatic-sp-privileges", OPT_SP_AUTOMATIC_PRIVILEGES,
+ "Creating and dropping stored procedures alters ACLs. Disable with --skip-automatic-sp-privileges.",
+ (gptr*) &sp_automatic_privileges, (gptr*) &sp_automatic_privileges,
+ 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"basedir", 'b',
"Path to installation directory. All paths are usually resolved relative to this.",
(gptr*) &mysql_home_ptr, (gptr*) &mysql_home_ptr, 0, GET_STR, REQUIRED_ARG,
@@ -4235,7 +4341,7 @@ Disable with --skip-bdb (will save memory).",
"Don't try to recover Berkeley DB tables on start.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"bdb-no-sync", OPT_BDB_NOSYNC,
- "Disable synchronously flushing logs. This option is deprecated, use --skip-sync-bdb-logs or sync-bdb-logs=0 instead",
+ "This option is deprecated, use --skip-sync-bdb-logs instead",
// (gptr*) &opt_sync_bdb_logs, (gptr*) &opt_sync_bdb_logs, 0, GET_BOOL,
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"bdb-shared-data", OPT_BDB_SHARED,
@@ -4271,6 +4377,10 @@ Disable with --skip-bdb (will save memory).",
{"collation-server", OPT_DEFAULT_COLLATION, "Set the default collation.",
(gptr*) &default_collation_name, (gptr*) &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+ {"completion-type", OPT_COMPLETION_TYPE, "Default completion type.",
+ (gptr*) &global_system_variables.completion_type,
+ (gptr*) &max_system_variables.completion_type, 0, GET_ULONG,
+ REQUIRED_ARG, 0, 0, 2, 0, 1, 0},
{"concurrent-insert", OPT_CONCURRENT_INSERT,
"Use concurrent insert with MyISAM. Disable with --skip-concurrent-insert.",
(gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert,
@@ -4331,6 +4441,12 @@ Disable with --skip-bdb (will save memory).",
{"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure.",
(gptr*) &opt_do_pstack, (gptr*) &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0,
0, 0, 0, 0},
+ {"engine-condition-pushdown",
+ OPT_ENGINE_CONDITION_PUSHDOWN,
+ "Push supported query conditions to the storage engine.",
+ (gptr*) &global_system_variables.engine_condition_pushdown,
+ (gptr*) &global_system_variables.engine_condition_pushdown,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running.",
@@ -4344,6 +4460,12 @@ Disable with --skip-bdb (will save memory).",
"Set up signals usable for debugging",
(gptr*) &opt_debugging, (gptr*) &opt_debugging,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef HAVE_LARGE_PAGES
+ {"large-pages", OPT_ENABLE_LARGE_PAGES, "Enable support for large pages. \
+Disable with --skip-large-pages.",
+ (gptr*) &opt_large_pages, (gptr*) &opt_large_pages, 0, GET_BOOL, NO_ARG, 0, 0, 0,
+ 0, 0, 0},
+#endif
{"init-connect", OPT_INIT_CONNECT, "Command(s) that are executed for each new connection",
(gptr*) &opt_init_connect, (gptr*) &opt_init_connect, 0, GET_STR_ALLOC,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -4359,6 +4481,11 @@ Disable with --skip-bdb (will save memory).",
Disable with --skip-innodb (will save memory).",
(gptr*) &opt_innodb, (gptr*) &opt_innodb, 0, GET_BOOL, NO_ARG, OPT_INNODB_DEFAULT, 0, 0,
0, 0, 0},
+#ifdef HAVE_INNOBASE_DB
+ {"innodb_checksums", OPT_INNODB_CHECKSUMS, "Enable InnoDB checksums validation (enabled by default). \
+Disable with --skip-innodb-checksums.", (gptr*) &innobase_use_checksums,
+ (gptr*) &innobase_use_checksums, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+#endif
{"innodb_data_file_path", OPT_INNODB_DATA_FILE_PATH,
"Path to individual files and their sizes.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -4367,9 +4494,28 @@ Disable with --skip-innodb (will save memory).",
"The common part for InnoDB table spaces.", (gptr*) &innobase_data_home_dir,
(gptr*) &innobase_data_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
+ {"innodb_doublewrite", OPT_INNODB_DOUBLEWRITE, "Enable InnoDB doublewrite buffer (enabled by default). \
+Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
+ (gptr*) &innobase_use_doublewrite, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"innodb_fast_shutdown", OPT_INNODB_FAST_SHUTDOWN,
- "Speeds up server shutdown process.", (gptr*) &innobase_fast_shutdown,
- (gptr*) &innobase_fast_shutdown, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ "Speeds up the shutdown process of the InnoDB storage engine. Possible "
+ "values are 0, 1 (faster)"
+ /*
+ NetWare can't close unclosed files, can't automatically kill remaining
+ threads, etc, so on this OS we disable the crash-like InnoDB shutdown.
+ */
+#ifndef __NETWARE__
+ " or 2 (fastest - crash-like)"
+#endif
+ ".",
+ (gptr*) &innobase_fast_shutdown,
+ (gptr*) &innobase_fast_shutdown, 0, GET_ULONG, OPT_ARG, 1, 0,
+#ifndef __NETWARE__
+ 2,
+#else
+ 1,
+#endif
+ 0, 0, 0},
{"innodb_file_per_table", OPT_INNODB_FILE_PER_TABLE,
"Stores each InnoDB table to an .ibd file in the database dir.",
(gptr*) &innobase_file_per_table,
@@ -4414,10 +4560,14 @@ Disable with --skip-innodb (will save memory).",
(gptr*) &global_system_variables.innodb_table_locks,
(gptr*) &global_system_variables.innodb_table_locks,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ {"innodb_support_xa", OPT_INNODB_SUPPORT_XA,
+ "Enable InnoDB support for the XA two-phase commit",
+ (gptr*) &global_system_variables.innodb_support_xa,
+ (gptr*) &global_system_variables.innodb_support_xa,
+ 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
#endif /* End HAVE_INNOBASE_DB */
- {"isam", OPT_ISAM, "Enable ISAM (if this version of MySQL supports it). \
-Disable with --skip-isam.",
- (gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, OPT_ISAM_DEFAULT, 0, 0,
+ {"isam", OPT_ISAM, "Obsolete. ISAM storage engine is no longer supported.",
+ (gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
{"language", 'L',
"Client error messages in given language. May be given as a full path.",
@@ -4431,14 +4581,16 @@ Disable with --skip-isam.",
{"log", 'l', "Log connections and queries to file.", (gptr*) &opt_logname,
(gptr*) &opt_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-bin", OPT_BIN_LOG,
- "Log update queries in binary format.",
+ "Log update queries in binary format. Optional (but strongly recommended "
+ "to avoid replication problems if server's hostname changes) argument "
+ "should be the chosen location for the binary log files.",
(gptr*) &opt_bin_logname, (gptr*) &opt_bin_logname, 0, GET_STR_ALLOC,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-bin-index", OPT_BIN_LOG_INDEX,
"File that holds the names for last binary log files.",
(gptr*) &opt_binlog_index_name, (gptr*) &opt_binlog_index_name, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"log-error", OPT_ERROR_LOG_FILE, "Log error file.",
+ {"log-error", OPT_ERROR_LOG_FILE, "Error log file.",
(gptr*) &log_error_file_ptr, (gptr*) &log_error_file_ptr, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-isam", OPT_ISAM_LOG, "Log all MyISAM changes to file.",
@@ -4463,13 +4615,22 @@ Disable with --skip-isam.",
"Log slow queries to this log file. Defaults logging to hostname-slow.log file.",
(gptr*) &opt_slow_logname, (gptr*) &opt_slow_logname, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
+ {"log-tc", OPT_LOG_TC,
+ "Path to transaction coordinator log (used for transactions that affect "
+ "more than one storage engine, when binary log is disabled)",
+ (gptr*) &opt_tc_log_file, (gptr*) &opt_tc_log_file, 0, GET_STR,
+ REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"log-tc-size", OPT_LOG_TC_SIZE, "Size of transaction coordinator log.",
+ (gptr*) &opt_tc_log_size, (gptr*) &opt_tc_log_size, 0, GET_ULONG,
+ REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ~0L, 0, TC_LOG_PAGE_SIZE, 0},
{"log-update", OPT_UPDATE_LOG,
- "Log updates to file.# where # is a unique number if not given.",
+ "The update log is deprecated since version 5.0, is replaced by the binary \
+log and this option justs turns on --log-bin instead.",
(gptr*) &opt_update_logname, (gptr*) &opt_update_logname, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"log-warnings", 'W', "Log some non-critical warnings to the error log file. Use this option twice or --log-warnings=2 if you also want 'Aborted connections' warnings.",
+ {"log-warnings", 'W', "Log some not critical warnings to the log file.",
(gptr*) &global_system_variables.log_warnings,
- (gptr*) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, ~0L,
+ (gptr*) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, 0,
0, 0, 0},
{"low-priority-updates", OPT_LOW_PRIORITY_UPDATES,
"INSERT/DELETE/UPDATE has lower priority than selects.",
@@ -4549,9 +4710,19 @@ Disable with --skip-ndbcluster (will save memory).",
#ifdef HAVE_NDBCLUSTER_DB
{"ndb-connectstring", OPT_NDB_CONNECTSTRING,
"Connect string for ndbcluster.",
- (gptr*) &opt_ndbcluster_connectstring,
- (gptr*) &opt_ndbcluster_connectstring,
+ (gptr*) &opt_ndb_connectstring,
+ (gptr*) &opt_ndb_connectstring,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"ndb-mgmd-host", OPT_NDB_MGMD,
+ "Set host and port for ndb_mgmd. Syntax: hostname[:port]",
+ (gptr*) &opt_ndb_mgmd,
+ (gptr*) &opt_ndb_mgmd,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"ndb-nodeid", OPT_NDB_NODEID,
+ "Nodeid for this mysqlserver in the cluster.",
+ (gptr*) &opt_ndb_nodeid,
+ (gptr*) &opt_ndb_nodeid,
+ 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ndb-autoincrement-prefetch-sz", OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
"Specify number of autoincrement values that are prefetched.",
(gptr*) &global_system_variables.ndb_autoincrement_prefetch_sz,
@@ -4589,6 +4760,10 @@ Disable with --skip-ndbcluster (will save memory).",
(gptr*) &opt_ndb_optimized_node_selection,
(gptr*) &opt_ndb_optimized_node_selection,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ { "ndb-cache-check-time", OPT_NDB_CACHE_CHECK_TIME,
+ "A dedicated thread is created to, at the given millisecons interval, invalidate the query cache if another MySQL server in the cluster has changed the data in the database.",
+ (gptr*) &opt_ndb_cache_check_time, (gptr*) &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG,
+ 0, 0, LONG_TIMEOUT, 0, 1, 0},
#endif
{"new", 'n', "Use very new possible 'unsafe' functions.",
(gptr*) &global_system_variables.new_mode,
@@ -4608,6 +4783,10 @@ Disable with --skip-ndbcluster (will save memory).",
"Only use one thread (for debugging under Linux).", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
+ {"old-style-user-limits", OPT_OLD_STYLE_USER_LIMITS,
+ "Enable old-style user limits (before 5.0.3 user resources were counted per each user+host vs. per account)",
+ (gptr*) &opt_old_style_user_limits, (gptr*) &opt_old_style_user_limits,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"pid-file", OPT_PID_FILE, "Pid file used by safe_mysqld.",
(gptr*) &pidfile_name_ptr, (gptr*) &pidfile_name_ptr, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -4771,9 +4950,9 @@ replicating a LOAD DATA INFILE command.",
0},
#endif /* HAVE_REPLICATION */
{"sql-bin-update-same", OPT_SQL_BIN_UPDATE_SAME,
- "If set, setting SQL_LOG_BIN to a value will automatically set SQL_LOG_UPDATE to the same value and vice versa.",
- (gptr*) &opt_sql_bin_update, (gptr*) &opt_sql_bin_update, 0, GET_BOOL,
- NO_ARG, 0, 0, 0, 0, 0, 0},
+ "The update log is deprecated since version 5.0, is replaced by the binary \
+log and this option does nothing anymore.",
+ 0, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"sql-mode", OPT_SQL_MODE,
"Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
(gptr*) &sql_mode_str, (gptr*) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0,
@@ -4789,13 +4968,21 @@ replicating a LOAD DATA INFILE command.",
{"symbolic-links", 's', "Enable symbolic link support.",
(gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG,
IF_PURIFY(0,1), 0, 0, 0, 0, 0},
+ {"tc-heuristic-recover", OPT_TC_HEURISTIC_RECOVER,
+ "Decision to use in heuristic recover process. Possible values are COMMIT or ROLLBACK",
+ (gptr*) &opt_tc_heuristic_recover, (gptr*) &opt_tc_heuristic_recover,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"temp-pool", OPT_TEMP_POOL,
"Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.",
(gptr*) &use_temp_pool, (gptr*) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1,
0, 0, 0, 0, 0},
+ {"timed_mutexes", OPT_TIMED_MUTEXES,
+ "Specify whether to time mutexes (only InnoDB mutexes are currently supported)",
+ (gptr*) &timed_mutexes, (gptr*) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0,
+ 0, 0, 0, 0, 0},
{"tmpdir", 't',
"Path for temporary files. Several paths may be specified, separated by a "
-#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
+#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__)
"semicolon (;)"
#else
"colon (:)"
@@ -4855,12 +5042,6 @@ replicating a LOAD DATA INFILE command.",
"The number of seconds the mysqld server is waiting for a connect packet before responding with 'Bad handshake'.",
(gptr*) &connect_timeout, (gptr*) &connect_timeout,
0, GET_ULONG, REQUIRED_ARG, CONNECT_TIMEOUT, 2, LONG_TIMEOUT, 0, 1, 0 },
-#ifdef HAVE_REPLICATION
- {"crash_binlog_innodb", OPT_CRASH_BINLOG_INNODB,
- "Used only for testing, to crash when writing Nth event to binlog.",
- (gptr*) &opt_crash_binlog_innodb, (gptr*) &opt_crash_binlog_innodb,
- 0, GET_UINT, REQUIRED_ARG, 0, 0, ~(uint)0, 0, 1, 0},
-#endif
{ "date_format", OPT_DATE_FORMAT,
"The DATE format (For future).",
(gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE],
@@ -4942,6 +5123,12 @@ replicating a LOAD DATA INFILE command.",
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
(gptr*) &innobase_buffer_pool_size, (gptr*) &innobase_buffer_pool_size, 0,
GET_LONG, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, ~0L, 0, 1024*1024L, 0},
+ {"innodb_concurrency_tickets", OPT_INNODB_CONCURRENCY_TICKETS,
+ "Number of times a thread is allowed to enter InnoDB within the same \
+ SQL query after it has once got the ticket",
+ (gptr*) &srv_n_free_tickets_to_enter,
+ (gptr*) &srv_n_free_tickets_to_enter,
+ 0, GET_LONG, REQUIRED_ARG, 500L, 1L, ~0L, 0, 1L, 0},
{"innodb_file_io_threads", OPT_INNODB_FILE_IO_THREADS,
"Number of file I/O threads in InnoDB.", (gptr*) &innobase_file_io_threads,
(gptr*) &innobase_file_io_threads, 0, GET_LONG, REQUIRED_ARG, 4, 4, 64, 0,
@@ -4975,30 +5162,21 @@ replicating a LOAD DATA INFILE command.",
"How many files at the maximum InnoDB keeps open at the same time.",
(gptr*) &innobase_open_files, (gptr*) &innobase_open_files, 0,
GET_LONG, REQUIRED_ARG, 300L, 10L, ~0L, 0, 1L, 0},
-#ifdef HAVE_REPLICATION
- /*
- Disabled for the 4.1.3 release. Disabling just this paragraph of code is
- enough, as then user can't set it to 1 so it will always be ignored in the
- rest of code.
- */
-#if MYSQL_VERSION_ID >= 40103
- /*
- innodb_safe_binlog is not a variable, just an option. Does not make
- sense to make it a variable, as it is only used at startup (and so the
- value would be lost at next startup, so setting it on the fly would have no
- effect).
- */
- {"innodb_safe_binlog", OPT_INNODB_SAFE_BINLOG,
- "After a crash recovery by InnoDB, truncate the binary log after the last "
- "not-rolled-back statement/transaction.",
- (gptr*) &opt_innodb_safe_binlog, (gptr*) &opt_innodb_safe_binlog,
- 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
-#endif
-#endif
+ {"innodb_sync_spin_loops", OPT_INNODB_SYNC_SPIN_LOOPS,
+ "Count of spin-loop rounds in InnoDB mutexes",
+ (gptr*) &srv_n_spin_wait_rounds,
+ (gptr*) &srv_n_spin_wait_rounds,
+ 0, GET_LONG, REQUIRED_ARG, 20L, 0L, ~0L, 0, 1L, 0},
{"innodb_thread_concurrency", OPT_INNODB_THREAD_CONCURRENCY,
"Helps in performance tuning in heavily concurrent environments.",
- (gptr*) &innobase_thread_concurrency, (gptr*) &innobase_thread_concurrency,
+ (gptr*) &srv_thread_concurrency, (gptr*) &srv_thread_concurrency,
0, GET_LONG, REQUIRED_ARG, 8, 1, 1000, 0, 1, 0},
+ {"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY,
+ "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0"
+ " disable a sleep",
+ (gptr*) &srv_thread_sleep_delay,
+ (gptr*) &srv_thread_sleep_delay,
+ 0, GET_LONG, REQUIRED_ARG, 10000L, 0L, ~0L, 0, 1L, 0},
#endif /* HAVE_INNOBASE_DB */
{"interactive_timeout", OPT_INTERACTIVE_TIMEOUT,
"The number of seconds the server waits for activity on an interactive connection before closing it.",
@@ -5016,7 +5194,7 @@ replicating a LOAD DATA INFILE command.",
(gptr*) &dflt_key_cache_var.param_buff_size,
(gptr*) 0,
0, (GET_ULL | GET_ASK_ADDR),
- REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, UINT_MAX32, MALLOC_OVERHEAD,
+ REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, ~(ulong) 0, MALLOC_OVERHEAD,
IO_SIZE, 0},
{"key_cache_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD,
"This characterizes the number of hits a hot block has to be untouched until it is considered aged enough to be downgraded to a warm block. This specifies the percentage ratio of that number of hits to the total number of blocks in key cache",
@@ -5120,12 +5298,17 @@ The minimum value for this variable is 4096.",
REQUIRED_ARG, 32, 1, ~0L, 0, 1, 0},
{"max_user_connections", OPT_MAX_USER_CONNECTIONS,
"The maximum number of active connections for a single user (0 = no limit).",
- (gptr*) &max_user_connections, (gptr*) &max_user_connections, 0, GET_ULONG,
- REQUIRED_ARG, 0, 1, ~0L, 0, 1, 0},
+ (gptr*) &max_user_connections, (gptr*) &max_user_connections, 0, GET_UINT,
+ REQUIRED_ARG, 0, 1, ~0, 0, 1, 0},
{"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT,
"After this many write locks, allow some read locks to run in between.",
(gptr*) &max_write_lock_count, (gptr*) &max_write_lock_count, 0, GET_ULONG,
REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0},
+ {"multi_range_count", OPT_MULTI_RANGE_COUNT,
+ "Number of key ranges to request at once.",
+ (gptr*) &global_system_variables.multi_range_count,
+ (gptr*) &max_system_variables.multi_range_count, 0,
+ GET_ULONG, REQUIRED_ARG, 256, 1, ~0L, 0, 1, 0},
{"myisam_block_size", OPT_MYISAM_BLOCK_SIZE,
"Block size to be used for MyISAM index pages.",
(gptr*) &opt_myisam_block_size,
@@ -5183,6 +5366,16 @@ The minimum value for this variable is 4096.",
"If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.",
(gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, OS_FILE_LIMIT, 0, 1, 0},
+ {"optimizer_prune_level", OPT_OPTIMIZER_PRUNE_LEVEL,
+ "Controls the heuristic(s) applied during query optimization to prune less-promising partial plans from the optimizer search space. Meaning: 0 - do not apply any heuristic, thus perform exhaustive search; 1 - prune plans based on number of retrieved rows.",
+ (gptr*) &global_system_variables.optimizer_prune_level,
+ (gptr*) &max_system_variables.optimizer_prune_level,
+ 0, GET_ULONG, OPT_ARG, 1, 0, 1, 0, 1, 0},
+ {"optimizer_search_depth", OPT_OPTIMIZER_SEARCH_DEPTH,
+ "Maximum depth of search performed by the query optimizer. Values larger than the number of relations in a query result in better query plans, but take longer to compile a query. Smaller values than the number of tables in a relation result in faster optimization, but may produce very bad query plans. If set to 0, the system will automatically pick a reasonable value; if set to MAX_TABLES+2, the optimizer will switch to the original find_best (used for testing/comparison).",
+ (gptr*) &global_system_variables.optimizer_search_depth,
+ (gptr*) &max_system_variables.optimizer_search_depth,
+ 0, GET_ULONG, OPT_ARG, MAX_TABLES+1, 0, MAX_TABLES+2, 0, 1, 0},
{"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE,
"The size of the buffer that is allocated when preloading indexes",
(gptr*) &global_system_variables.preload_buff_size,
@@ -5276,7 +5469,7 @@ The minimum value for this variable is 4096.",
"it failed with a deadlock or elapsed lock wait timeout, "
"before giving up and stopping.",
(gptr*) &slave_trans_retries, (gptr*) &slave_trans_retries, 0,
- GET_ULONG, REQUIRED_ARG, 0L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
+ GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
#endif /* HAVE_REPLICATION */
{"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
"If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented.",
@@ -5290,36 +5483,35 @@ The minimum value for this variable is 4096.",
1, 0},
#ifdef HAVE_BERKELEY_DB
{"sync-bdb-logs", OPT_BDB_SYNC,
- "Synchronously flush logs. Enabled by default",
+ "Synchronously flush Berkeley DB logs. Enabled by default",
(gptr*) &opt_sync_bdb_logs, (gptr*) &opt_sync_bdb_logs, 0, GET_BOOL,
NO_ARG, 1, 0, 0, 0, 0, 0},
#endif /* HAVE_BERKELEY_DB */
{"sync-binlog", OPT_SYNC_BINLOG,
- "Sync the binlog to disk after every #th event. \
-#=0 (the default) does no sync. Syncing slows MySQL down",
- (gptr*) &sync_binlog_period,
- (gptr*) &sync_binlog_period, 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1,
- 0},
-#ifdef DOES_NOTHING_YET
+ "Synchronously flush binary log to disk after every #th event. "
+ "Use 0 (default) to disable synchronous flushing.",
+ (gptr*) &sync_binlog_period, (gptr*) &sync_binlog_period, 0, GET_ULONG,
+ REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0},
+ {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.",
+ (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0,
+ 0, 0, 0, 0},
+#ifdef HAVE_REPLICATION
{"sync-replication", OPT_SYNC_REPLICATION,
- "Enable synchronous replication",
+ "Enable synchronous replication.",
(gptr*) &global_system_variables.sync_replication,
(gptr*) &global_system_variables.sync_replication,
0, GET_ULONG, REQUIRED_ARG, 0, 0, 1, 0, 1, 0},
{"sync-replication-slave-id", OPT_SYNC_REPLICATION_SLAVE_ID,
- "Synchronous replication is wished for this slave",
+ "Synchronous replication is wished for this slave.",
(gptr*) &global_system_variables.sync_replication_slave_id,
(gptr*) &global_system_variables.sync_replication_slave_id,
0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0},
{"sync-replication-timeout", OPT_SYNC_REPLICATION_TIMEOUT,
- "Synchronous replication timeout",
+ "Synchronous replication timeout.",
(gptr*) &global_system_variables.sync_replication_timeout,
(gptr*) &global_system_variables.sync_replication_timeout,
0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0},
-#endif
- {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default",
- (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0,
- 0, 0, 0, 0},
+#endif /* HAVE_REPLICATION */
{"table_cache", OPT_TABLE_CACHE,
"The number of open tables for all threads.", (gptr*) &table_cache_size,
(gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L,
@@ -5356,6 +5548,11 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.trans_prealloc_size,
(gptr*) &max_system_variables.trans_prealloc_size, 0, GET_ULONG,
REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0},
+ {"updatable_views_with_limit", OPT_UPDATABLE_VIEWS_WITH_LIMIT,
+ "1 = YES = Don't issue an error message (warning only) if a VIEW without presence of a key of the underlying table is used in queries with a LIMIT clause for updating. 0 = NO = Prohibit update of a VIEW, which does not contain a key of the underlying table and the query uses a LIMIT clause (usually get from GUI tools).",
+ (gptr*) &global_system_variables.updatable_views_with_limit,
+ (gptr*) &max_system_variables.updatable_views_with_limit,
+ 0, GET_ULONG, REQUIRED_ARG, 1, 0, 1, 0, 1, 0},
{"wait_timeout", OPT_WAIT_TIMEOUT,
"The number of seconds the server waits for activity on a connection before closing it.",
(gptr*) &global_system_variables.net_wait_timeout,
@@ -5371,167 +5568,170 @@ struct show_var_st status_vars[]= {
{"Aborted_connects", (char*) &aborted_connects, SHOW_LONG},
{"Binlog_cache_disk_use", (char*) &binlog_cache_disk_use, SHOW_LONG},
{"Binlog_cache_use", (char*) &binlog_cache_use, SHOW_LONG},
- {"Bytes_received", (char*) &bytes_received, SHOW_LONG},
- {"Bytes_sent", (char*) &bytes_sent, SHOW_LONG},
- {"Com_admin_commands", (char*) &com_other, SHOW_LONG},
- {"Com_alter_db", (char*) (com_stat+(uint) SQLCOM_ALTER_DB),SHOW_LONG},
- {"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG},
- {"Com_analyze", (char*) (com_stat+(uint) SQLCOM_ANALYZE),SHOW_LONG},
- {"Com_backup_table", (char*) (com_stat+(uint) SQLCOM_BACKUP_TABLE),SHOW_LONG},
- {"Com_begin", (char*) (com_stat+(uint) SQLCOM_BEGIN),SHOW_LONG},
- {"Com_change_db", (char*) (com_stat+(uint) SQLCOM_CHANGE_DB),SHOW_LONG},
- {"Com_change_master", (char*) (com_stat+(uint) SQLCOM_CHANGE_MASTER),SHOW_LONG},
- {"Com_check", (char*) (com_stat+(uint) SQLCOM_CHECK),SHOW_LONG},
- {"Com_checksum", (char*) (com_stat+(uint) SQLCOM_CHECKSUM),SHOW_LONG},
- {"Com_commit", (char*) (com_stat+(uint) SQLCOM_COMMIT),SHOW_LONG},
- {"Com_create_db", (char*) (com_stat+(uint) SQLCOM_CREATE_DB),SHOW_LONG},
- {"Com_create_function", (char*) (com_stat+(uint) SQLCOM_CREATE_FUNCTION),SHOW_LONG},
- {"Com_create_index", (char*) (com_stat+(uint) SQLCOM_CREATE_INDEX),SHOW_LONG},
- {"Com_create_table", (char*) (com_stat+(uint) SQLCOM_CREATE_TABLE),SHOW_LONG},
- {"Com_dealloc_sql", (char*) (com_stat+(uint)
- SQLCOM_DEALLOCATE_PREPARE), SHOW_LONG},
- {"Com_delete", (char*) (com_stat+(uint) SQLCOM_DELETE),SHOW_LONG},
- {"Com_delete_multi", (char*) (com_stat+(uint) SQLCOM_DELETE_MULTI),SHOW_LONG},
- {"Com_do", (char*) (com_stat+(uint) SQLCOM_DO),SHOW_LONG},
- {"Com_drop_db", (char*) (com_stat+(uint) SQLCOM_DROP_DB),SHOW_LONG},
- {"Com_drop_function", (char*) (com_stat+(uint) SQLCOM_DROP_FUNCTION),SHOW_LONG},
- {"Com_drop_index", (char*) (com_stat+(uint) SQLCOM_DROP_INDEX),SHOW_LONG},
- {"Com_drop_table", (char*) (com_stat+(uint) SQLCOM_DROP_TABLE),SHOW_LONG},
- {"Com_drop_user", (char*) (com_stat+(uint) SQLCOM_DROP_USER),SHOW_LONG},
- {"Com_execute_sql", (char*) (com_stat+(uint) SQLCOM_EXECUTE),
- SHOW_LONG},
- {"Com_flush", (char*) (com_stat+(uint) SQLCOM_FLUSH),SHOW_LONG},
- {"Com_grant", (char*) (com_stat+(uint) SQLCOM_GRANT),SHOW_LONG},
- {"Com_ha_close", (char*) (com_stat+(uint) SQLCOM_HA_CLOSE),SHOW_LONG},
- {"Com_ha_open", (char*) (com_stat+(uint) SQLCOM_HA_OPEN),SHOW_LONG},
- {"Com_ha_read", (char*) (com_stat+(uint) SQLCOM_HA_READ),SHOW_LONG},
- {"Com_help", (char*) (com_stat+(uint) SQLCOM_HELP),SHOW_LONG},
- {"Com_insert", (char*) (com_stat+(uint) SQLCOM_INSERT),SHOW_LONG},
- {"Com_insert_select", (char*) (com_stat+(uint) SQLCOM_INSERT_SELECT),SHOW_LONG},
- {"Com_kill", (char*) (com_stat+(uint) SQLCOM_KILL),SHOW_LONG},
- {"Com_load", (char*) (com_stat+(uint) SQLCOM_LOAD),SHOW_LONG},
- {"Com_load_master_data", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_DATA),SHOW_LONG},
- {"Com_load_master_table", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_TABLE),SHOW_LONG},
- {"Com_lock_tables", (char*) (com_stat+(uint) SQLCOM_LOCK_TABLES),SHOW_LONG},
- {"Com_optimize", (char*) (com_stat+(uint) SQLCOM_OPTIMIZE),SHOW_LONG},
- {"Com_preload_keys", (char*) (com_stat+(uint) SQLCOM_PRELOAD_KEYS),SHOW_LONG},
- {"Com_prepare_sql", (char*) (com_stat+(uint) SQLCOM_PREPARE),
- SHOW_LONG},
- {"Com_purge", (char*) (com_stat+(uint) SQLCOM_PURGE),SHOW_LONG},
- {"Com_purge_before_date", (char*) (com_stat+(uint) SQLCOM_PURGE_BEFORE),SHOW_LONG},
- {"Com_rename_table", (char*) (com_stat+(uint) SQLCOM_RENAME_TABLE),SHOW_LONG},
- {"Com_repair", (char*) (com_stat+(uint) SQLCOM_REPAIR),SHOW_LONG},
- {"Com_replace", (char*) (com_stat+(uint) SQLCOM_REPLACE),SHOW_LONG},
- {"Com_replace_select", (char*) (com_stat+(uint) SQLCOM_REPLACE_SELECT),SHOW_LONG},
- {"Com_reset", (char*) (com_stat+(uint) SQLCOM_RESET),SHOW_LONG},
- {"Com_restore_table", (char*) (com_stat+(uint) SQLCOM_RESTORE_TABLE),SHOW_LONG},
- {"Com_revoke", (char*) (com_stat+(uint) SQLCOM_REVOKE),SHOW_LONG},
- {"Com_revoke_all", (char*) (com_stat+(uint) SQLCOM_REVOKE_ALL),SHOW_LONG},
- {"Com_rollback", (char*) (com_stat+(uint) SQLCOM_ROLLBACK),SHOW_LONG},
- {"Com_savepoint", (char*) (com_stat+(uint) SQLCOM_SAVEPOINT),SHOW_LONG},
- {"Com_select", (char*) (com_stat+(uint) SQLCOM_SELECT),SHOW_LONG},
- {"Com_set_option", (char*) (com_stat+(uint) SQLCOM_SET_OPTION),SHOW_LONG},
- {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG},
- {"Com_show_binlogs", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOGS),SHOW_LONG},
- {"Com_show_charsets", (char*) (com_stat+(uint) SQLCOM_SHOW_CHARSETS),SHOW_LONG},
- {"Com_show_collations", (char*) (com_stat+(uint) SQLCOM_SHOW_COLLATIONS),SHOW_LONG},
- {"Com_show_column_types", (char*) (com_stat+(uint) SQLCOM_SHOW_COLUMN_TYPES),SHOW_LONG},
- {"Com_show_create_db", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE_DB),SHOW_LONG},
- {"Com_show_create_table", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG},
- {"Com_show_databases", (char*) (com_stat+(uint) SQLCOM_SHOW_DATABASES),SHOW_LONG},
- {"Com_show_errors", (char*) (com_stat+(uint) SQLCOM_SHOW_ERRORS),SHOW_LONG},
- {"Com_show_fields", (char*) (com_stat+(uint) SQLCOM_SHOW_FIELDS),SHOW_LONG},
- {"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG},
- {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG},
- {"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG},
- {"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG},
- {"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG},
- {"Com_show_new_master", (char*) (com_stat+(uint) SQLCOM_SHOW_NEW_MASTER),SHOW_LONG},
- {"Com_show_open_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_OPEN_TABLES),SHOW_LONG},
- {"Com_show_privileges", (char*) (com_stat+(uint) SQLCOM_SHOW_PRIVILEGES),SHOW_LONG},
- {"Com_show_processlist", (char*) (com_stat+(uint) SQLCOM_SHOW_PROCESSLIST),SHOW_LONG},
- {"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG},
- {"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG},
- {"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG},
- {"Com_show_storage_engines", (char*) (com_stat+(uint) SQLCOM_SHOW_STORAGE_ENGINES),SHOW_LONG},
- {"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG},
- {"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG},
- {"Com_show_warnings", (char*) (com_stat+(uint) SQLCOM_SHOW_WARNS),SHOW_LONG},
- {"Com_slave_start", (char*) (com_stat+(uint) SQLCOM_SLAVE_START),SHOW_LONG},
- {"Com_slave_stop", (char*) (com_stat+(uint) SQLCOM_SLAVE_STOP),SHOW_LONG},
- {"Com_truncate", (char*) (com_stat+(uint) SQLCOM_TRUNCATE),SHOW_LONG},
- {"Com_unlock_tables", (char*) (com_stat+(uint) SQLCOM_UNLOCK_TABLES),SHOW_LONG},
- {"Com_update", (char*) (com_stat+(uint) SQLCOM_UPDATE),SHOW_LONG},
- {"Com_update_multi", (char*) (com_stat+(uint) SQLCOM_UPDATE_MULTI),SHOW_LONG},
+ {"Bytes_received", (char*) offsetof(STATUS_VAR, bytes_received), SHOW_LONG_STATUS},
+ {"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent), SHOW_LONG_STATUS},
+ {"Com_admin_commands", (char*) offsetof(STATUS_VAR, com_other), SHOW_LONG_STATUS},
+ {"Com_alter_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_DB]), SHOW_LONG_STATUS},
+ {"Com_alter_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_TABLE]), SHOW_LONG_STATUS},
+ {"Com_analyze", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ANALYZE]), SHOW_LONG_STATUS},
+ {"Com_backup_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BACKUP_TABLE]), SHOW_LONG_STATUS},
+ {"Com_begin", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BEGIN]), SHOW_LONG_STATUS},
+ {"Com_change_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHANGE_DB]), SHOW_LONG_STATUS},
+ {"Com_change_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHANGE_MASTER]), SHOW_LONG_STATUS},
+ {"Com_check", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHECK]), SHOW_LONG_STATUS},
+ {"Com_checksum", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHECKSUM]), SHOW_LONG_STATUS},
+ {"Com_commit", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_COMMIT]), SHOW_LONG_STATUS},
+ {"Com_create_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_DB]), SHOW_LONG_STATUS},
+ {"Com_create_function", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_FUNCTION]), SHOW_LONG_STATUS},
+ {"Com_create_index", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_INDEX]), SHOW_LONG_STATUS},
+ {"Com_create_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_TABLE]), SHOW_LONG_STATUS},
+ {"Com_dealloc_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DEALLOCATE_PREPARE]), SHOW_LONG_STATUS},
+ {"Com_delete", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DELETE]), SHOW_LONG_STATUS},
+ {"Com_delete_multi", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DELETE_MULTI]), SHOW_LONG_STATUS},
+ {"Com_do", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DO]), SHOW_LONG_STATUS},
+ {"Com_drop_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_DB]), SHOW_LONG_STATUS},
+ {"Com_drop_function", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_FUNCTION]), SHOW_LONG_STATUS},
+ {"Com_drop_index", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_INDEX]), SHOW_LONG_STATUS},
+ {"Com_drop_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_TABLE]), SHOW_LONG_STATUS},
+ {"Com_drop_user", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_USER]), SHOW_LONG_STATUS},
+ {"Com_execute_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_EXECUTE]), SHOW_LONG_STATUS},
+ {"Com_flush", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_FLUSH]), SHOW_LONG_STATUS},
+ {"Com_grant", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_GRANT]), SHOW_LONG_STATUS},
+ {"Com_ha_close", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HA_CLOSE]), SHOW_LONG_STATUS},
+ {"Com_ha_open", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HA_OPEN]), SHOW_LONG_STATUS},
+ {"Com_ha_read", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HA_READ]), SHOW_LONG_STATUS},
+ {"Com_help", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HELP]), SHOW_LONG_STATUS},
+ {"Com_insert", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_INSERT]), SHOW_LONG_STATUS},
+ {"Com_insert_select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_INSERT_SELECT]), SHOW_LONG_STATUS},
+ {"Com_kill", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_KILL]), SHOW_LONG_STATUS},
+ {"Com_load", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD]), SHOW_LONG_STATUS},
+ {"Com_load_master_data", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD_MASTER_DATA]), SHOW_LONG_STATUS},
+ {"Com_load_master_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD_MASTER_TABLE]), SHOW_LONG_STATUS},
+ {"Com_lock_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOCK_TABLES]), SHOW_LONG_STATUS},
+ {"Com_optimize", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_OPTIMIZE]), SHOW_LONG_STATUS},
+ {"Com_preload_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PRELOAD_KEYS]), SHOW_LONG_STATUS},
+ {"Com_prepare_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PREPARE]), SHOW_LONG_STATUS},
+ {"Com_purge", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PURGE]), SHOW_LONG_STATUS},
+ {"Com_purge_before_date", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PURGE_BEFORE]), SHOW_LONG_STATUS},
+ {"Com_rename_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RENAME_TABLE]), SHOW_LONG_STATUS},
+ {"Com_repair", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPAIR]), SHOW_LONG_STATUS},
+ {"Com_replace", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE]), SHOW_LONG_STATUS},
+ {"Com_replace_select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE_SELECT]), SHOW_LONG_STATUS},
+ {"Com_reset", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESET]), SHOW_LONG_STATUS},
+ {"Com_restore_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESTORE_TABLE]), SHOW_LONG_STATUS},
+ {"Com_revoke", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE]), SHOW_LONG_STATUS},
+ {"Com_revoke_all", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE_ALL]), SHOW_LONG_STATUS},
+ {"Com_rollback", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ROLLBACK]), SHOW_LONG_STATUS},
+ {"Com_savepoint", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SAVEPOINT]), SHOW_LONG_STATUS},
+ {"Com_select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SELECT]), SHOW_LONG_STATUS},
+ {"Com_set_option", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SET_OPTION]), SHOW_LONG_STATUS},
+ {"Com_show_binlogs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOGS]), SHOW_LONG_STATUS},
+ {"Com_show_binlog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOG_EVENTS]), SHOW_LONG_STATUS},
+ {"Com_show_charsets", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CHARSETS]), SHOW_LONG_STATUS},
+ {"Com_show_collations", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLLATIONS]), SHOW_LONG_STATUS},
+ {"Com_show_column_types", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLUMN_TYPES]), SHOW_LONG_STATUS},
+ {"Com_show_create_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE]), SHOW_LONG_STATUS},
+ {"Com_show_create_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE_DB]), SHOW_LONG_STATUS},
+ {"Com_show_databases", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_DATABASES]), SHOW_LONG_STATUS},
+ {"Com_show_errors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_ERRORS]), SHOW_LONG_STATUS},
+ {"Com_show_fields", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_FIELDS]), SHOW_LONG_STATUS},
+ {"Com_show_grants", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_GRANTS]), SHOW_LONG_STATUS},
+ {"Com_show_innodb_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_INNODB_STATUS]), SHOW_LONG_STATUS},
+ {"Com_show_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_KEYS]), SHOW_LONG_STATUS},
+ {"Com_show_logs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_LOGS]), SHOW_LONG_STATUS},
+ {"Com_show_master_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_MASTER_STAT]), SHOW_LONG_STATUS},
+ {"Com_show_new_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NEW_MASTER]), SHOW_LONG_STATUS},
+ {"Com_show_open_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_OPEN_TABLES]), SHOW_LONG_STATUS},
+ {"Com_show_privileges", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PRIVILEGES]), SHOW_LONG_STATUS},
+ {"Com_show_processlist", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PROCESSLIST]), SHOW_LONG_STATUS},
+ {"Com_show_slave_hosts", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_HOSTS]), SHOW_LONG_STATUS},
+ {"Com_show_slave_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_STAT]), SHOW_LONG_STATUS},
+ {"Com_show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS},
+ {"Com_show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS},
+ {"Com_show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS},
+ {"Com_show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS},
+ {"Com_show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS},
+ {"Com_slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS},
+ {"Com_slave_stop", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_STOP]), SHOW_LONG_STATUS},
+ {"Com_truncate", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TRUNCATE]), SHOW_LONG_STATUS},
+ {"Com_unlock_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UNLOCK_TABLES]), SHOW_LONG_STATUS},
+ {"Com_update", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UPDATE]), SHOW_LONG_STATUS},
+ {"Com_update_multi", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UPDATE_MULTI]), SHOW_LONG_STATUS},
+ {"Com_xa_commit", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_COMMIT]),SHOW_LONG_STATUS},
+ {"Com_xa_end", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_END]),SHOW_LONG_STATUS},
+ {"Com_xa_prepare", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_PREPARE]),SHOW_LONG_STATUS},
+ {"Com_xa_recover", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_RECOVER]),SHOW_LONG_STATUS},
+ {"Com_xa_rollback", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_ROLLBACK]),SHOW_LONG_STATUS},
+ {"Com_xa_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_XA_START]),SHOW_LONG_STATUS},
{"Connections", (char*) &thread_id, SHOW_LONG_CONST},
- {"Created_tmp_disk_tables", (char*) &created_tmp_disk_tables,SHOW_LONG},
+ {"Created_tmp_disk_tables", (char*) offsetof(STATUS_VAR, created_tmp_disk_tables), SHOW_LONG_STATUS},
{"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG},
- {"Created_tmp_tables", (char*) &created_tmp_tables, SHOW_LONG},
+ {"Created_tmp_tables", (char*) offsetof(STATUS_VAR, created_tmp_tables), SHOW_LONG_STATUS},
{"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG},
{"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_CONST},
{"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG},
{"Flush_commands", (char*) &refresh_version, SHOW_LONG_CONST},
- {"Handler_commit", (char*) &ha_commit_count, SHOW_LONG},
- {"Handler_delete", (char*) &ha_delete_count, SHOW_LONG},
- {"Handler_discover", (char*) &ha_discover_count, SHOW_LONG},
- {"Handler_read_first", (char*) &ha_read_first_count, SHOW_LONG},
- {"Handler_read_key", (char*) &ha_read_key_count, SHOW_LONG},
- {"Handler_read_next", (char*) &ha_read_next_count, SHOW_LONG},
- {"Handler_read_prev", (char*) &ha_read_prev_count, SHOW_LONG},
- {"Handler_read_rnd", (char*) &ha_read_rnd_count, SHOW_LONG},
- {"Handler_read_rnd_next", (char*) &ha_read_rnd_next_count, SHOW_LONG},
- {"Handler_rollback", (char*) &ha_rollback_count, SHOW_LONG},
- {"Handler_update", (char*) &ha_update_count, SHOW_LONG},
- {"Handler_write", (char*) &ha_write_count, SHOW_LONG},
- {"Key_blocks_not_flushed", (char*) &dflt_key_cache_var.global_blocks_changed,
- SHOW_KEY_CACHE_LONG},
- {"Key_blocks_unused", (char*) &dflt_key_cache_var.blocks_unused,
- SHOW_KEY_CACHE_CONST_LONG},
- {"Key_blocks_used", (char*) &dflt_key_cache_var.blocks_used,
- SHOW_KEY_CACHE_CONST_LONG},
- {"Key_read_requests", (char*) &dflt_key_cache_var.global_cache_r_requests,
- SHOW_KEY_CACHE_LONG},
- {"Key_reads", (char*) &dflt_key_cache_var.global_cache_read,
- SHOW_KEY_CACHE_LONG},
- {"Key_write_requests", (char*) &dflt_key_cache_var.global_cache_w_requests,
- SHOW_KEY_CACHE_LONG},
- {"Key_writes", (char*) &dflt_key_cache_var.global_cache_write,
- SHOW_KEY_CACHE_LONG},
+ {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS},
+ {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS},
+ {"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS},
+ {"Handler_prepare", (char*) offsetof(STATUS_VAR, ha_prepare_count), SHOW_LONG_STATUS},
+ {"Handler_read_first", (char*) offsetof(STATUS_VAR, ha_read_first_count), SHOW_LONG_STATUS},
+ {"Handler_read_key", (char*) offsetof(STATUS_VAR, ha_read_key_count), SHOW_LONG_STATUS},
+ {"Handler_read_next", (char*) offsetof(STATUS_VAR, ha_read_next_count), SHOW_LONG_STATUS},
+ {"Handler_read_prev", (char*) offsetof(STATUS_VAR, ha_read_prev_count), SHOW_LONG_STATUS},
+ {"Handler_read_rnd", (char*) offsetof(STATUS_VAR, ha_read_rnd_count), SHOW_LONG_STATUS},
+ {"Handler_read_rnd_next", (char*) offsetof(STATUS_VAR, ha_read_rnd_next_count), SHOW_LONG_STATUS},
+ {"Handler_rollback", (char*) offsetof(STATUS_VAR, ha_rollback_count), SHOW_LONG_STATUS},
+ {"Handler_savepoint", (char*) offsetof(STATUS_VAR, ha_savepoint_count), SHOW_LONG_STATUS},
+ {"Handler_savepoint_rollback",(char*) offsetof(STATUS_VAR, ha_savepoint_rollback_count), SHOW_LONG_STATUS},
+ {"Handler_update", (char*) offsetof(STATUS_VAR, ha_update_count), SHOW_LONG_STATUS},
+ {"Handler_write", (char*) offsetof(STATUS_VAR, ha_write_count), SHOW_LONG_STATUS},
+#ifdef HAVE_INNOBASE_DB
+ {"Innodb_", (char*) &innodb_status_variables, SHOW_VARS},
+#endif /*HAVE_INNOBASE_DB*/
+ {"Key_blocks_not_flushed", (char*) &dflt_key_cache_var.global_blocks_changed, SHOW_KEY_CACHE_LONG},
+ {"Key_blocks_unused", (char*) &dflt_key_cache_var.blocks_unused, SHOW_KEY_CACHE_CONST_LONG},
+ {"Key_blocks_used", (char*) &dflt_key_cache_var.blocks_used, SHOW_KEY_CACHE_CONST_LONG},
+ {"Key_read_requests", (char*) &dflt_key_cache_var.global_cache_r_requests, SHOW_KEY_CACHE_LONG},
+ {"Key_reads", (char*) &dflt_key_cache_var.global_cache_read, SHOW_KEY_CACHE_LONG},
+ {"Key_write_requests", (char*) &dflt_key_cache_var.global_cache_w_requests, SHOW_KEY_CACHE_LONG},
+ {"Key_writes", (char*) &dflt_key_cache_var.global_cache_write, SHOW_KEY_CACHE_LONG},
+ {"Last_query_cost", (char*) &last_query_cost, SHOW_DOUBLE},
{"Max_used_connections", (char*) &max_used_connections, SHOW_LONG},
+#ifdef HAVE_NDBCLUSTER_DB
+ {"Ndb_", (char*) &ndb_status_variables, SHOW_VARS},
+#endif /*HAVE_NDBCLUSTER_DB*/
{"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_CONST},
{"Open_files", (char*) &my_file_opened, SHOW_LONG_CONST},
{"Open_streams", (char*) &my_stream_opened, SHOW_LONG_CONST},
{"Open_tables", (char*) 0, SHOW_OPENTABLES},
- {"Opened_tables", (char*) &opened_tables, SHOW_LONG},
+ {"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables), SHOW_LONG_STATUS},
#ifdef HAVE_QUERY_CACHE
- {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks,
- SHOW_LONG_CONST},
- {"Qcache_free_memory", (char*) &query_cache.free_memory,
- SHOW_LONG_CONST},
+ {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, SHOW_LONG_CONST},
+ {"Qcache_free_memory", (char*) &query_cache.free_memory, SHOW_LONG_CONST},
{"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG},
{"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG},
{"Qcache_lowmem_prunes", (char*) &query_cache.lowmem_prunes, SHOW_LONG},
{"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG},
{"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_CONST},
- {"Qcache_total_blocks", (char*) &query_cache.total_blocks,
- SHOW_LONG_CONST},
+ {"Qcache_total_blocks", (char*) &query_cache.total_blocks, SHOW_LONG_CONST},
#endif /*HAVE_QUERY_CACHE*/
{"Questions", (char*) 0, SHOW_QUESTION},
{"Rpl_status", (char*) 0, SHOW_RPL_STATUS},
- {"Select_full_join", (char*) &select_full_join_count, SHOW_LONG},
- {"Select_full_range_join", (char*) &select_full_range_join_count, SHOW_LONG},
- {"Select_range", (char*) &select_range_count, SHOW_LONG},
- {"Select_range_check", (char*) &select_range_check_count, SHOW_LONG},
- {"Select_scan", (char*) &select_scan_count, SHOW_LONG},
+ {"Select_full_join", (char*) offsetof(STATUS_VAR, select_full_join_count), SHOW_LONG_STATUS},
+ {"Select_full_range_join", (char*) offsetof(STATUS_VAR, select_full_range_join_count), SHOW_LONG_STATUS},
+ {"Select_range", (char*) offsetof(STATUS_VAR, select_range_count), SHOW_LONG_STATUS},
+ {"Select_range_check", (char*) offsetof(STATUS_VAR, select_range_check_count), SHOW_LONG_STATUS},
+ {"Select_scan", (char*) offsetof(STATUS_VAR, select_scan_count), SHOW_LONG_STATUS},
{"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_LONG},
{"Slave_running", (char*) 0, SHOW_SLAVE_RUNNING},
{"Slave_retried_transactions",(char*) 0, SHOW_SLAVE_RETRIED_TRANS},
{"Slow_launch_threads", (char*) &slow_launch_threads, SHOW_LONG},
- {"Slow_queries", (char*) &long_query_count, SHOW_LONG},
- {"Sort_merge_passes", (char*) &filesort_merge_passes, SHOW_LONG},
- {"Sort_range", (char*) &filesort_range_count, SHOW_LONG},
- {"Sort_rows", (char*) &filesort_rows, SHOW_LONG},
- {"Sort_scan", (char*) &filesort_scan_count, SHOW_LONG},
+ {"Slow_queries", (char*) offsetof(STATUS_VAR, long_query_count), SHOW_LONG_STATUS},
+ {"Sort_merge_passes", (char*) offsetof(STATUS_VAR, filesort_merge_passes), SHOW_LONG_STATUS},
+ {"Sort_range", (char*) offsetof(STATUS_VAR, filesort_range_count), SHOW_LONG_STATUS},
+ {"Sort_rows", (char*) offsetof(STATUS_VAR, filesort_rows), SHOW_LONG_STATUS},
+ {"Sort_scan", (char*) offsetof(STATUS_VAR, filesort_scan_count), SHOW_LONG_STATUS},
#ifdef HAVE_OPENSSL
{"Ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE},
{"Ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT},
@@ -5559,6 +5759,9 @@ struct show_var_st status_vars[]= {
#endif /* HAVE_OPENSSL */
{"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG},
{"Table_locks_waited", (char*) &locks_waited, SHOW_LONG},
+ {"Tc_log_max_pages_used", (char*) &tc_log_max_pages_used, SHOW_LONG},
+ {"Tc_log_page_size", (char*) &tc_log_page_size, SHOW_LONG},
+ {"Tc_log_page_waits", (char*) &tc_log_page_waits, SHOW_LONG},
{"Threads_cached", (char*) &cached_thread_count, SHOW_LONG_CONST},
{"Threads_connected", (char*) &thread_count, SHOW_INT_CONST},
{"Threads_created", (char*) &thread_created, SHOW_LONG_CONST},
@@ -5651,7 +5854,8 @@ static void mysql_init_variables(void)
mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0;
opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0;
opt_disable_networking= opt_skip_show_db=0;
- opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname=0;
+ opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0;
+ opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name !
opt_secure_auth= 0;
opt_bootstrap= opt_myisam_log= 0;
mqh_used= 0;
@@ -5662,28 +5866,24 @@ static void mysql_init_variables(void)
test_flags= select_errors= dropping_tables= ha_open_options=0;
thread_count= thread_running= kill_cached_threads= wake_thread=0;
slave_open_temp_tables= 0;
- com_other= 0;
cached_thread_count= 0;
- bytes_sent= bytes_received= 0;
opt_endinfo= using_udf_functions= 0;
opt_using_transactions= using_update_log= 0;
abort_loop= select_thread_in_use= signal_thread_in_use= 0;
ready_to_exit= shutdown_in_progress= grant_option= 0;
- long_query_count= aborted_threads= aborted_connects= 0;
+ aborted_threads= aborted_connects= 0;
delayed_insert_threads= delayed_insert_writes= delayed_rows_in_use= 0;
delayed_insert_errors= thread_created= 0;
- filesort_rows= filesort_range_count= filesort_scan_count= 0;
- filesort_merge_passes= select_range_check_count= select_range_count= 0;
- select_scan_count= select_full_range_join_count= select_full_join_count= 0;
- specialflag= opened_tables= created_tmp_tables= created_tmp_disk_tables= 0;
+ specialflag= 0;
binlog_cache_use= binlog_cache_disk_use= 0;
max_used_connections= slow_launch_threads = 0;
mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0;
errmesg= 0;
mysqld_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS;
bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list));
- bzero((gptr) &com_stat, sizeof(com_stat));
-
+ bzero((char *) &global_status_var, sizeof(global_status_var));
+ opt_large_pages= 0;
+
/* Character sets */
system_charset_info= &my_charset_utf8_general_ci;
files_charset_info= &my_charset_utf8_general_ci;
@@ -5775,11 +5975,7 @@ static void mysql_init_variables(void)
#else
have_innodb=SHOW_OPTION_NO;
#endif
-#ifdef HAVE_ISAM
- have_isam=SHOW_OPTION_YES;
-#else
have_isam=SHOW_OPTION_NO;
-#endif
#ifdef HAVE_EXAMPLE_DB
have_example_db= SHOW_OPTION_YES;
#else
@@ -5795,6 +5991,11 @@ static void mysql_init_variables(void)
#else
have_blackhole_db= SHOW_OPTION_NO;
#endif
+#ifdef HAVE_FEDERATED_DB
+ have_federated_db= SHOW_OPTION_YES;
+#else
+ have_federated_db= SHOW_OPTION_NO;
+#endif
#ifdef HAVE_CSV_DB
have_csv_db= SHOW_OPTION_YES;
#else
@@ -6086,6 +6287,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;
myisam_concurrent_insert=0;
myisam_recover_options= HA_RECOVER_NONE;
+ sp_automatic_privileges=0;
my_use_symdir=0;
ha_open_options&= ~(HA_OPEN_ABORT_IF_CRASHED | HA_OPEN_DELAY_KEY_WRITE);
#ifdef HAVE_QUERY_CACHE
@@ -6172,9 +6374,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_error_log= 0; // Force logs to stdout
break;
case (int) OPT_FLUSH:
-#ifdef HAVE_ISAM
- nisam_flush=1;
-#endif
myisam_flush=1;
flush_time=0; // No auto flush
break;
@@ -6259,7 +6458,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *end;
uint length= strlen(argument);
long value= my_strntol(&my_charset_latin1, argument, length, 10, &end, &err);
- if (test_if_int(argument,(uint) length, end, &my_charset_latin1))
+ if (end == argument+length)
berkeley_lock_scan_time= value;
else
{
@@ -6282,14 +6481,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
have_berkeley_db= SHOW_OPTION_DISABLED;
#endif
break;
- case OPT_ISAM:
-#ifdef HAVE_ISAM
- if (opt_isam)
- have_isam= SHOW_OPTION_YES;
- else
- have_isam= SHOW_OPTION_DISABLED;
-#endif
- break;
case OPT_NDBCLUSTER:
#ifdef HAVE_NDBCLUSTER_DB
if (opt_ndbcluster)
@@ -6298,6 +6489,31 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
have_ndbcluster= SHOW_OPTION_DISABLED;
#endif
break;
+#ifdef HAVE_NDBCLUSTER_DB
+ case OPT_NDB_MGMD:
+ case OPT_NDB_NODEID:
+ {
+ int len= my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
+ sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
+ "%s%s%s",opt_ndb_constrbuf_len > 0 ? ",":"",
+ optid == OPT_NDB_NODEID ? "nodeid=" : "",
+ argument);
+ opt_ndb_constrbuf_len+= len;
+ }
+ /* fall through to add the connectstring to the end
+ * and set opt_ndbcluster_connectstring
+ */
+ case OPT_NDB_CONNECTSTRING:
+ if (opt_ndb_connectstring && opt_ndb_connectstring[0])
+ my_snprintf(opt_ndb_constrbuf+opt_ndb_constrbuf_len,
+ sizeof(opt_ndb_constrbuf)-opt_ndb_constrbuf_len,
+ "%s%s", opt_ndb_constrbuf_len > 0 ? ",":"",
+ opt_ndb_connectstring);
+ else
+ opt_ndb_constrbuf[opt_ndb_constrbuf_len]= 0;
+ opt_ndbcluster_connectstring= opt_ndb_constrbuf;
+ break;
+#endif
case OPT_INNODB:
#ifdef HAVE_INNOBASE_DB
if (opt_innodb)
@@ -6315,9 +6531,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case OPT_INNODB_LOG_ARCHIVE:
innobase_log_archive= argument ? test(atoi(argument)) : 1;
break;
- case OPT_INNODB_FAST_SHUTDOWN:
- innobase_fast_shutdown= argument ? test(atoi(argument)) : 1;
- break;
#endif /* HAVE_INNOBASE_DB */
case OPT_MYISAM_RECOVER:
{
@@ -6339,6 +6552,16 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
ha_open_options|=HA_OPEN_ABORT_IF_CRASHED;
break;
}
+ case OPT_TC_HEURISTIC_RECOVER:
+ {
+ if ((tc_heuristic_recover=find_type(argument,
+ &tc_heuristic_recover_typelib, 2)) <=0)
+ {
+ fprintf(stderr, "Unknown option to tc-heuristic-recover: %s\n",argument);
+ exit(1);
+ }
+ break;
+ }
case OPT_SQL_MODE:
{
sql_mode_str= argument;
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index c8b2e28ec52..4fbbeedb812 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -72,7 +72,7 @@
/* The following is because alarms doesn't work on windows. */
#define NO_ALARM
#endif
-
+
#ifndef NO_ALARM
#include "my_pthread.h"
void sql_print_error(const char *format,...);
@@ -83,7 +83,6 @@ void sql_print_error(const char *format,...);
#include "thr_alarm.h"
#ifdef MYSQL_SERVER
-#define USE_QUERY_CACHE
/*
The following variables/functions should really not be declared
extern, but as it's hard to include mysql_priv.h here, we have to
@@ -92,12 +91,16 @@ void sql_print_error(const char *format,...);
extern uint test_flags;
extern ulong bytes_sent, bytes_received, net_big_packet_count;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+#ifndef MYSQL_INSTANCE_MANAGER
extern void query_cache_insert(NET *net, const char *packet, ulong length);
-#else
-#undef statistic_add
-#undef statistic_increment
-#define statistic_add(A,B,C)
-#define statistic_increment(A,B)
+#define USE_QUERY_CACHE
+#define update_statistics(A) A
+#endif /* MYSQL_INSTANCE_MANGER */
+#endif /* defined(MYSQL_SERVER) && !defined(MYSQL_INSTANCE_MANAGER) */
+
+#if !defined(MYSQL_SERVER) || defined(MYSQL_INSTANCE_MANAGER)
+#define update_statistics(A)
+#define thd_increment_bytes_sent(N)
#endif
#define TEST_BLOCKING 8
@@ -118,7 +121,7 @@ my_bool my_net_init(NET *net, Vio* vio)
DBUG_RETURN(1);
net->buff_end=net->buff+net->max_packet;
net->vio = vio;
- net->no_send_ok = 0;
+ net->no_send_ok= net->no_send_eof= net->no_send_error= 0;
net->error=0; net->return_errno=0; net->return_status=0;
net->pkt_nr=net->compress_pkt_nr=0;
net->write_pos=net->read_pos = net->buff;
@@ -445,7 +448,8 @@ net_real_write(NET *net,const char *packet,ulong len)
my_bool net_blocking = vio_is_blocking(net->vio);
DBUG_ENTER("net_real_write");
-#if defined(MYSQL_SERVER) && defined(HAVE_QUERY_CACHE)
+#if defined(MYSQL_SERVER) && defined(HAVE_QUERY_CACHE) \
+ && !defined(MYSQL_INSTANCE_MANAGER)
if (net->query_cache_query != 0)
query_cache_insert(net, packet, len);
#endif
@@ -554,7 +558,7 @@ net_real_write(NET *net,const char *packet,ulong len)
break;
}
pos+=length;
- statistic_add(bytes_sent,length,&LOCK_bytes_sent);
+ update_statistics(thd_increment_bytes_sent(length));
}
#ifndef __WIN__
end:
@@ -625,7 +629,7 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
/* The following is good for debugging */
- statistic_increment(net_big_packet_count,&LOCK_bytes_received);
+ update_statistics(thd_increment_net_big_packet_count(1));
if (!thr_alarm_in_use(alarmed))
{
@@ -641,7 +645,7 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
uint length= min(remain, net->max_packet);
if (net_safe_read(net, (char*) net->buff, length, alarmed))
DBUG_RETURN(1);
- statistic_add(bytes_received, length, &LOCK_bytes_received);
+ update_statistics(thd_increment_bytes_received(length));
remain -= (uint32) length;
}
if (old != MAX_PACKET_LENGTH)
@@ -766,7 +770,7 @@ my_real_read(NET *net, ulong *complen)
}
remain -= (uint32) length;
pos+= (ulong) length;
- statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ update_statistics(thd_increment_bytes_received(length));
}
if (i == 0)
{ /* First parts is packet length */
diff --git a/sql/nt_servc.h b/sql/nt_servc.h
index 6d74eaccea2..a3c12569114 100644
--- a/sql/nt_servc.h
+++ b/sql/nt_servc.h
@@ -48,8 +48,9 @@ class NTService
//service install / un-install
- BOOL Install(int startType,LPCSTR szInternName,LPCSTR szDisplayName,LPCSTR szFullPath,
- LPCSTR szAccountName=NULL,LPCSTR szPassword=NULL);
+ BOOL Install(int startType,LPCSTR szInternName,LPCSTR szDisplayName,
+ LPCSTR szFullPath, LPCSTR szAccountName=NULL,
+ LPCSTR szPassword=NULL);
BOOL SeekStatus(LPCSTR szInternName, int OperationType);
BOOL Remove(LPCSTR szInternName);
BOOL IsService(LPCSTR ServiceName);
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 33223b83894..95fe003770b 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -23,13 +23,25 @@
*/
+/*
+ Classes in this file are used in the following way:
+ 1. For a selection condition a tree of SEL_IMERGE/SEL_TREE/SEL_ARG objects
+ is created. #of rows in table and index statistics are ignored at this
+ step.
+ 2. Created SEL_TREE and index stats data are used to construct a
+ TABLE_READ_PLAN-derived object (TRP_*). Several 'candidate' table read
+ plans may be created.
+ 3. The least expensive table read plan is used to create a tree of
+ QUICK_SELECT_I-derived objects which are later used for row retrieval.
+ QUICK_RANGEs are also created in this step.
+*/
+
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
#endif
#include "mysql_priv.h"
#include <m_ctype.h>
-#include <nisam.h>
#include "sql_select.h"
#ifndef EXTRA_DEBUG
@@ -37,6 +49,11 @@
#define test_use_count(A) {}
#endif
+/*
+ Convert double value to #rows. Currently this does floor(), and we
+ might consider using round() instead.
+*/
+#define double2rows(x) ((ha_rows)(x))
static int sel_cmp(Field *f,char *a,char *b,uint8 a_flag,uint8 b_flag);
@@ -167,8 +184,7 @@ public:
min_value=arg->max_value;
min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN;
}
- void store(uint length,char **min_key,uint min_key_flag,
- char **max_key, uint max_key_flag)
+ void store_min(uint length,char **min_key,uint min_key_flag)
{
if ((min_flag & GEOM_FLAG) ||
(!(min_flag & NO_MIN_RANGE) &&
@@ -183,6 +199,11 @@ public:
memcpy(*min_key,min_value,length);
(*min_key)+= length;
}
+ }
+ void store(uint length,char **min_key,uint min_key_flag,
+ char **max_key, uint max_key_flag)
+ {
+ store_min(length, min_key, min_key_flag);
if (!(max_flag & NO_MAX_RANGE) &&
!(max_key_flag & (NO_MAX_RANGE | NEAR_MAX)))
{
@@ -267,31 +288,78 @@ public:
SEL_ARG *clone_tree();
};
+class SEL_IMERGE;
+
class SEL_TREE :public Sql_alloc
{
public:
enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type;
SEL_TREE(enum Type type_arg) :type(type_arg) {}
- SEL_TREE() :type(KEY) { bzero((char*) keys,sizeof(keys));}
+ SEL_TREE() :type(KEY)
+ {
+ keys_map.clear_all();
+ bzero((char*) keys,sizeof(keys));
+ }
SEL_ARG *keys[MAX_KEY];
+ key_map keys_map; /* bitmask of non-NULL elements in keys */
+
+ /*
+ Possible ways to read rows using index_merge. The list is non-empty only
+ if type==KEY. Currently can be non empty only if keys_map.is_clear_all().
+ */
+ List<SEL_IMERGE> merges;
+
+ /* The members below are filled/used only after get_mm_tree is done */
+ key_map ror_scans_map; /* bitmask of ROR scan-able elements in keys */
+ uint n_ror_scans; /* number of set bits in ror_scans_map */
+
+ struct st_ror_scan_info **ror_scans; /* list of ROR key scans */
+ struct st_ror_scan_info **ror_scans_end; /* last ROR scan */
+ /* Note that #records for each key scan is stored in table->quick_rows */
};
typedef struct st_qsel_param {
THD *thd;
TABLE *table;
- KEY_PART *key_parts,*key_parts_end,*key[MAX_KEY];
+ 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;
table_map prev_tables,read_tables,current_table;
- uint baseflag, keys, max_key_part, range_count;
+ uint baseflag, max_key_part, range_count;
+
+ uint keys; /* number of keys used in the query */
+
+ /* used_key_no -> table_key_no translation table */
uint real_keynr[MAX_KEY];
+
char min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
bool quick; // Don't calulate possible keys
COND *cond;
+
+ uint fields_bitmap_size;
+ MY_BITMAP needed_fields; /* bitmask of fields needed by the query */
+
+ key_map *needed_reg; /* ptr to SQL_SELECT::needed_reg */
+
+ uint *imerge_cost_buff; /* buffer for index_merge cost estimates */
+ uint imerge_cost_buff_size; /* size of the buffer */
+
+ /* TRUE if last checked tree->key can be used for ROR-scan */
+ bool is_ror_scan;
} PARAM;
+class TABLE_READ_PLAN;
+ class TRP_RANGE;
+ class TRP_ROR_INTERSECT;
+ class TRP_ROR_UNION;
+ class TRP_ROR_INDEX_MERGE;
+ class TRP_GROUP_MIN_MAX;
+
+struct st_ror_scan_info;
+
static SEL_TREE * get_mm_parts(PARAM *param,COND *cond_func,Field *field,
Item_func::Functype type,Item *value,
Item_result cmp_type);
@@ -299,32 +367,279 @@ static SEL_ARG *get_mm_leaf(PARAM *param,COND *cond_func,Field *field,
KEY_PART *key_part,
Item_func::Functype type,Item *value);
static SEL_TREE *get_mm_tree(PARAM *param,COND *cond);
+
+static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree);
static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
char *min_key,uint min_key_flag,
char *max_key, uint max_key_flag);
-static QUICK_SELECT *get_quick_select(PARAM *param,uint index,
- SEL_ARG *key_tree);
+QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
+ SEL_ARG *key_tree,
+ MEM_ROOT *alloc = NULL);
+static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
+ bool index_read_must_be_used,
+ double read_time);
+static
+TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
+ double read_time,
+ bool *are_all_covering);
+static
+TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
+ SEL_TREE *tree,
+ double read_time);
+static
+TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
+ double read_time);
+static
+TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree);
+static int get_index_merge_params(PARAM *param, key_map& needed_reg,
+ SEL_IMERGE *imerge, double *read_time,
+ ha_rows* imerge_rows);
+inline double get_index_only_read_time(const PARAM* param, ha_rows records,
+ int keynr);
+
#ifndef DBUG_OFF
-static void print_quick(QUICK_SELECT *quick,const key_map* needed_reg);
+static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map,
+ const char *msg);
+static void print_ror_scans_arr(TABLE *table, const char *msg,
+ struct st_ror_scan_info **start,
+ struct st_ror_scan_info **end);
+static void print_rowid(byte* val, int len);
+static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg);
#endif
+
static SEL_TREE *tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_TREE *tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2);
static SEL_ARG *key_or(SEL_ARG *key1,SEL_ARG *key2);
static SEL_ARG *key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag);
static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1);
-static bool get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
+bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
SEL_ARG *key_tree,char *min_key,uint min_key_flag,
char *max_key,uint max_key_flag);
static bool eq_tree(SEL_ARG* a,SEL_ARG *b);
static SEL_ARG null_element(SEL_ARG::IMPOSSIBLE);
-static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length);
+static bool null_part_in_key(KEY_PART *key_part, const char *key,
+ uint length);
+bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, PARAM* param);
+
+
+/*
+ SEL_IMERGE is a list of possible ways to do index merge, i.e. it is
+ a condition in the following form:
+ (t_1||t_2||...||t_N) && (next)
+
+ where all t_i are SEL_TREEs, next is another SEL_IMERGE and no pair
+ (t_i,t_j) contains SEL_ARGS for the same index.
+
+ SEL_TREE contained in SEL_IMERGE always has merges=NULL.
+
+ This class relies on memory manager to do the cleanup.
+*/
+
+class SEL_IMERGE : public Sql_alloc
+{
+ enum { PREALLOCED_TREES= 10};
+public:
+ SEL_TREE *trees_prealloced[PREALLOCED_TREES];
+ SEL_TREE **trees; /* trees used to do index_merge */
+ SEL_TREE **trees_next; /* last of these trees */
+ SEL_TREE **trees_end; /* end of allocated space */
+
+ SEL_ARG ***best_keys; /* best keys to read in SEL_TREEs */
+
+ SEL_IMERGE() :
+ trees(&trees_prealloced[0]),
+ trees_next(trees),
+ trees_end(trees + PREALLOCED_TREES)
+ {}
+ int or_sel_tree(PARAM *param, SEL_TREE *tree);
+ int or_sel_tree_with_checks(PARAM *param, SEL_TREE *new_tree);
+ int or_sel_imerge_with_checks(PARAM *param, SEL_IMERGE* imerge);
+};
+
+
+/*
+ Add SEL_TREE to this index_merge without any checks,
+
+ NOTES
+ This function implements the following:
+ (x_1||...||x_N) || t = (x_1||...||x_N||t), where x_i, t are SEL_TREEs
+
+ RETURN
+ 0 - OK
+ -1 - Out of memory.
+*/
+
+int SEL_IMERGE::or_sel_tree(PARAM *param, SEL_TREE *tree)
+{
+ if (trees_next == trees_end)
+ {
+ const int realloc_ratio= 2; /* Double size for next round */
+ uint old_elements= (trees_end - trees);
+ uint old_size= sizeof(SEL_TREE**) * old_elements;
+ uint new_size= old_size * realloc_ratio;
+ SEL_TREE **new_trees;
+ if (!(new_trees= (SEL_TREE**)alloc_root(param->mem_root, new_size)))
+ return -1;
+ memcpy(new_trees, trees, old_size);
+ trees= new_trees;
+ trees_next= trees + old_elements;
+ trees_end= trees + old_elements * realloc_ratio;
+ }
+ *(trees_next++)= tree;
+ return 0;
+}
+
+
+/*
+ Perform OR operation on this SEL_IMERGE and supplied SEL_TREE new_tree,
+ combining new_tree with one of the trees in this SEL_IMERGE if they both
+ have SEL_ARGs for the same key.
+
+ SYNOPSIS
+ or_sel_tree_with_checks()
+ param PARAM from SQL_SELECT::test_quick_select
+ new_tree SEL_TREE with type KEY or KEY_SMALLER.
+
+ NOTES
+ This does the following:
+ (t_1||...||t_k)||new_tree =
+ either
+ = (t_1||...||t_k||new_tree)
+ or
+ = (t_1||....||(t_j|| new_tree)||...||t_k),
+
+ where t_i, y are SEL_TREEs.
+ new_tree is combined with the first t_j it has a SEL_ARG on common
+ key with. As a consequence of this, choice of keys to do index_merge
+ read may depend on the order of conditions in WHERE part of the query.
+
+ RETURN
+ 0 OK
+ 1 One of the trees was combined with new_tree to SEL_TREE::ALWAYS,
+ and (*this) should be discarded.
+ -1 An error occurred.
+*/
+
+int SEL_IMERGE::or_sel_tree_with_checks(PARAM *param, SEL_TREE *new_tree)
+{
+ for (SEL_TREE** tree = trees;
+ tree != trees_next;
+ tree++)
+ {
+ if (sel_trees_can_be_ored(*tree, new_tree, param))
+ {
+ *tree = tree_or(param, *tree, new_tree);
+ if (!*tree)
+ return 1;
+ if (((*tree)->type == SEL_TREE::MAYBE) ||
+ ((*tree)->type == SEL_TREE::ALWAYS))
+ return 1;
+ /* SEL_TREE::IMPOSSIBLE is impossible here */
+ return 0;
+ }
+ }
+
+ /* New tree cannot be combined with any of existing trees. */
+ return or_sel_tree(param, new_tree);
+}
+
+
+/*
+ Perform OR operation on this index_merge and supplied index_merge list.
+
+ RETURN
+ 0 - OK
+ 1 - One of conditions in result is always TRUE and this SEL_IMERGE
+ should be discarded.
+ -1 - An error occurred
+*/
+
+int SEL_IMERGE::or_sel_imerge_with_checks(PARAM *param, SEL_IMERGE* imerge)
+{
+ for (SEL_TREE** tree= imerge->trees;
+ tree != imerge->trees_next;
+ tree++)
+ {
+ if (or_sel_tree_with_checks(param, *tree))
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ Perform AND operation on two index_merge lists and store result in *im1.
+*/
+
+inline void imerge_list_and_list(List<SEL_IMERGE> *im1, List<SEL_IMERGE> *im2)
+{
+ im1->concat(im2);
+}
+
+
+/*
+ Perform OR operation on 2 index_merge lists, storing result in first list.
+
+ NOTES
+ The following conversion is implemented:
+ (a_1 &&...&& a_N)||(b_1 &&...&& b_K) = AND_i,j(a_i || b_j) =>
+ => (a_1||b_1).
+
+ i.e. all conjuncts except the first one are currently dropped.
+ This is done to avoid producing N*K ways to do index_merge.
+
+ If (a_1||b_1) produce a condition that is always TRUE, NULL is returned
+ and index_merge is discarded (while it is actually possible to try
+ harder).
+
+ As a consequence of this, choice of keys to do index_merge read may depend
+ on the order of conditions in WHERE part of the query.
+
+ RETURN
+ 0 OK, result is stored in *im1
+ other Error, both passed lists are unusable
+*/
+
+int imerge_list_or_list(PARAM *param,
+ List<SEL_IMERGE> *im1,
+ List<SEL_IMERGE> *im2)
+{
+ SEL_IMERGE *imerge= im1->head();
+ im1->empty();
+ im1->push_back(imerge);
+
+ return imerge->or_sel_imerge_with_checks(param, im2->head());
+}
+
+
+/*
+ Perform OR operation on index_merge list and key tree.
+
+ RETURN
+ 0 OK, result is stored in *im1.
+ other Error
+*/
+
+int imerge_list_or_tree(PARAM *param,
+ List<SEL_IMERGE> *im1,
+ SEL_TREE *tree)
+{
+ SEL_IMERGE *imerge;
+ List_iterator<SEL_IMERGE> it(*im1);
+ while((imerge= it++))
+ {
+ if (imerge->or_sel_tree_with_checks(param, tree))
+ it.remove();
+ }
+ return im1->is_empty();
+}
/***************************************************************************
-** Basic functions for SQL_SELECT and QUICK_SELECT
+** Basic functions for SQL_SELECT and QUICK_RANGE_SELECT
***************************************************************************/
/* make a select from mysql info
@@ -334,13 +649,17 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length);
*/
SQL_SELECT *make_select(TABLE *head, table_map const_tables,
- table_map read_tables, COND *conds, int *error)
+ table_map read_tables, COND *conds,
+ bool allow_null_cond,
+ int *error)
+
{
SQL_SELECT *select;
DBUG_ENTER("make_select");
*error=0;
- if (!conds)
+
+ if (!conds && !allow_null_cond)
DBUG_RETURN(0);
if (!(select= new SQL_SELECT))
{
@@ -380,7 +699,7 @@ void SQL_SELECT::cleanup()
free_cond=0;
delete cond;
cond= 0;
- }
+ }
close_cached_file(&file);
}
@@ -392,11 +711,29 @@ SQL_SELECT::~SQL_SELECT()
#undef index // Fix for Unixware 7
-QUICK_SELECT::QUICK_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc)
- :dont_free(0),sorted(0),error(0),index(key_nr),max_used_key_length(0),
- used_key_parts(0), head(table), it(ranges),range(0)
+QUICK_SELECT_I::QUICK_SELECT_I()
+ :max_used_key_length(0),
+ used_key_parts(0)
+{}
+
+QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
+ bool no_alloc, MEM_ROOT *parent_alloc)
+ :dont_free(0),error(0),free_file(0),in_range(0),cur_range(NULL),range(0)
{
- if (!no_alloc)
+ sorted= 0;
+ index= key_nr;
+ head= table;
+ key_part_info= head->key_info[index].key_part;
+ my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16);
+
+ /* 'thd' is not accessible in QUICK_RANGE_SELECT::reset(). */
+ multi_range_bufsiz= thd->variables.read_rnd_buff_size;
+ multi_range_count= thd->variables.multi_range_count;
+ multi_range_length= 0;
+ multi_range= NULL;
+ multi_range_buff= NULL;
+
+ if (!no_alloc && !parent_alloc)
{
// Allocates everything through the internal memroot
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
@@ -404,21 +741,463 @@ QUICK_SELECT::QUICK_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc)
}
else
bzero((char*) &alloc,sizeof(alloc));
- file=head->file;
- record=head->record[0];
- init();
+ file= head->file;
+ record= head->record[0];
+}
+
+
+int QUICK_RANGE_SELECT::init()
+{
+ DBUG_ENTER("QUICK_RANGE_SELECT::init");
+
+ if (file->inited == handler::NONE)
+ DBUG_RETURN(error= file->ha_index_init(index));
+ error= 0;
+ DBUG_RETURN(0);
+}
+
+
+void QUICK_RANGE_SELECT::range_end()
+{
+ if (file->inited != handler::NONE)
+ file->ha_index_or_rnd_end();
}
-QUICK_SELECT::~QUICK_SELECT()
+
+QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
{
+ DBUG_ENTER("QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT");
if (!dont_free)
{
- if (file->inited)
- file->ha_index_end();
+ /* file is NULL for CPK scan on covering ROR-intersection */
+ if (file)
+ {
+ range_end();
+ file->extra(HA_EXTRA_NO_KEYREAD);
+ if (free_file)
+ {
+ DBUG_PRINT("info", ("Freeing separate handler %p (free=%d)", file,
+ free_file));
+ file->reset();
+ file->external_lock(current_thd, F_UNLCK);
+ file->close();
+ }
+ }
+ delete_dynamic(&ranges); /* ranges are allocated in alloc */
free_root(&alloc,MYF(0));
}
+ if (multi_range)
+ my_free((char*) multi_range, MYF(0));
+ if (multi_range_buff)
+ my_free((char*) multi_range_buff, MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+
+QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param,
+ TABLE *table)
+ :pk_quick_select(NULL), thd(thd_param)
+{
+ DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT");
+ index= MAX_KEY;
+ head= table;
+ bzero(&read_record, sizeof(read_record));
+ init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
+ DBUG_VOID_RETURN;
+}
+
+int QUICK_INDEX_MERGE_SELECT::init()
+{
+ DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::init");
+ DBUG_RETURN(0);
+}
+
+int QUICK_INDEX_MERGE_SELECT::reset()
+{
+ DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::reset");
+ DBUG_RETURN(read_keys_and_merge());
+}
+
+bool
+QUICK_INDEX_MERGE_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick_sel_range)
+{
+ /*
+ Save quick_select that does scan on clustered primary key as it will be
+ processed separately.
+ */
+ if (head->file->primary_key_is_clustered() &&
+ quick_sel_range->index == head->s->primary_key)
+ pk_quick_select= quick_sel_range;
+ else
+ return quick_selects.push_back(quick_sel_range);
+ return 0;
+}
+
+QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT()
+{
+ List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects);
+ QUICK_RANGE_SELECT* quick;
+ DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT");
+ quick_it.rewind();
+ while ((quick= quick_it++))
+ quick->file= NULL;
+ quick_selects.delete_elements();
+ delete pk_quick_select;
+ free_root(&alloc,MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+
+QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param,
+ TABLE *table,
+ bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc)
+ : cpk_quick(NULL), thd(thd_param), need_to_fetch_row(retrieve_full_rows),
+ scans_inited(false)
+{
+ index= MAX_KEY;
+ head= table;
+ record= head->record[0];
+ if (!parent_alloc)
+ init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
+ else
+ bzero(&alloc, sizeof(MEM_ROOT));
+ last_rowid= (byte*)alloc_root(parent_alloc? parent_alloc : &alloc,
+ head->file->ref_length);
+}
+
+
+/*
+ Do post-constructor initialization.
+ SYNOPSIS
+ QUICK_ROR_INTERSECT_SELECT::init()
+
+ RETURN
+ 0 OK
+ other Error code
+*/
+
+int QUICK_ROR_INTERSECT_SELECT::init()
+{
+ DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init");
+ /* Check if last_rowid was successfully allocated in ctor */
+ DBUG_RETURN(!last_rowid);
+}
+
+
+/*
+ Initialize this quick select to be a ROR-merged scan.
+
+ SYNOPSIS
+ QUICK_RANGE_SELECT::init_ror_merged_scan()
+ reuse_handler If TRUE, use head->file, otherwise create a separate
+ handler object
+
+ NOTES
+ This function creates and prepares for subsequent use a separate handler
+ object if it can't reuse head->file. The reason for this is that during
+ ROR-merge several key scans are performed simultaneously, and a single
+ handler is only capable of preserving context of a single key scan.
+
+ In ROR-merge the quick select doing merge does full records retrieval,
+ merged quick selects read only keys.
+
+ RETURN
+ 0 ROR child scan initialized, ok to use.
+ 1 error
+*/
+
+int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
+{
+ handler *save_file= file;
+ DBUG_ENTER("QUICK_RANGE_SELECT::init_ror_merged_scan");
+
+ if (reuse_handler)
+ {
+ DBUG_PRINT("info", ("Reusing handler %p", file));
+ if (file->extra(HA_EXTRA_KEYREAD) ||
+ file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) ||
+ init() || reset())
+ {
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+
+ /* Create a separate handler object for this quick select */
+ if (free_file)
+ {
+ /* already have own 'handler' object. */
+ DBUG_RETURN(0);
+ }
+
+ THD *thd= current_thd;
+ if (!(file= get_new_handler(head, head->s->db_type)))
+ goto failure;
+ DBUG_PRINT("info", ("Allocated new handler %p", file));
+ if (file->ha_open(head->s->path, head->db_stat, HA_OPEN_IGNORE_IF_LOCKED))
+ {
+ /* Caller will free the memory */
+ goto failure;
+ }
+ if (file->external_lock(thd, F_RDLCK))
+ goto failure;
+
+ if (file->extra(HA_EXTRA_KEYREAD) ||
+ file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) ||
+ init() || reset())
+ {
+ file->external_lock(thd, F_UNLCK);
+ file->close();
+ goto failure;
+ }
+ free_file= TRUE;
+ last_rowid= file->ref;
+ DBUG_RETURN(0);
+
+failure:
+ file= save_file;
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Initialize this quick select to be a part of a ROR-merged scan.
+ SYNOPSIS
+ QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan()
+ reuse_handler If TRUE, use head->file, otherwise create separate
+ handler object.
+ RETURN
+ 0 OK
+ other error code
+*/
+int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler)
+{
+ List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects);
+ QUICK_RANGE_SELECT* quick;
+ DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan");
+
+ /* Initialize all merged "children" quick selects */
+ DBUG_ASSERT(!need_to_fetch_row || reuse_handler);
+ if (!need_to_fetch_row && reuse_handler)
+ {
+ quick= quick_it++;
+ /*
+ There is no use of this->file. Use it for the first of merged range
+ selects.
+ */
+ if (quick->init_ror_merged_scan(TRUE))
+ DBUG_RETURN(1);
+ quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
+ }
+ while((quick= quick_it++))
+ {
+ if (quick->init_ror_merged_scan(FALSE))
+ DBUG_RETURN(1);
+ quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
+ /* All merged scans share the same record buffer in intersection. */
+ quick->record= head->record[0];
+ }
+
+ if (need_to_fetch_row && head->file->ha_rnd_init(1))
+ {
+ DBUG_PRINT("error", ("ROR index_merge rnd_init call failed"));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Initialize quick select for row retrieval.
+ SYNOPSIS
+ reset()
+ RETURN
+ 0 OK
+ other Error code
+*/
+
+int QUICK_ROR_INTERSECT_SELECT::reset()
+{
+ DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::reset");
+ if (!scans_inited && init_ror_merged_scan(TRUE))
+ DBUG_RETURN(1);
+ scans_inited= true;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ QUICK_RANGE_SELECT *quick;
+ while ((quick= it++))
+ quick->reset();
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Add a merged quick select to this ROR-intersection quick select.
+
+ SYNOPSIS
+ QUICK_ROR_INTERSECT_SELECT::push_quick_back()
+ quick Quick select to be added. The quick select must return
+ rows in rowid order.
+ NOTES
+ This call can only be made before init() is called.
+
+ RETURN
+ FALSE OK
+ TRUE Out of memory.
+*/
+
+bool
+QUICK_ROR_INTERSECT_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick)
+{
+ return quick_selects.push_back(quick);
+}
+
+QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT()
+{
+ DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT");
+ quick_selects.delete_elements();
+ delete cpk_quick;
+ free_root(&alloc,MYF(0));
+ if (need_to_fetch_row && head->file->inited != handler::NONE)
+ head->file->ha_rnd_end();
+ DBUG_VOID_RETURN;
+}
+
+
+QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
+ TABLE *table)
+ : thd(thd_param), scans_inited(false)
+{
+ index= MAX_KEY;
+ head= table;
+ rowid_length= table->file->ref_length;
+ record= head->record[0];
+ init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
+ thd_param->mem_root= &alloc;
+}
+
+
+/*
+ Do post-constructor initialization.
+ SYNOPSIS
+ QUICK_ROR_UNION_SELECT::init()
+
+ RETURN
+ 0 OK
+ other Error code
+*/
+
+int QUICK_ROR_UNION_SELECT::init()
+{
+ DBUG_ENTER("QUICK_ROR_UNION_SELECT::init");
+ if (init_queue(&queue, quick_selects.elements, 0,
+ FALSE , QUICK_ROR_UNION_SELECT::queue_cmp,
+ (void*) this))
+ {
+ bzero(&queue, sizeof(QUEUE));
+ DBUG_RETURN(1);
+ }
+
+ if (!(cur_rowid= (byte*)alloc_root(&alloc, 2*head->file->ref_length)))
+ DBUG_RETURN(1);
+ prev_rowid= cur_rowid + head->file->ref_length;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Comparison function to be used QUICK_ROR_UNION_SELECT::queue priority
+ queue.
+
+ SYNPOSIS
+ QUICK_ROR_UNION_SELECT::queue_cmp()
+ arg Pointer to QUICK_ROR_UNION_SELECT
+ val1 First merged select
+ val2 Second merged select
+*/
+int QUICK_ROR_UNION_SELECT::queue_cmp(void *arg, byte *val1, byte *val2)
+{
+ QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg;
+ return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid,
+ ((QUICK_SELECT_I*)val2)->last_rowid);
}
+
+/*
+ Initialize quick select for row retrieval.
+ SYNOPSIS
+ reset()
+
+ RETURN
+ 0 OK
+ other Error code
+*/
+
+int QUICK_ROR_UNION_SELECT::reset()
+{
+ QUICK_SELECT_I* quick;
+ int error;
+ DBUG_ENTER("QUICK_ROR_UNION_SELECT::reset");
+ have_prev_rowid= FALSE;
+ if (!scans_inited)
+ {
+ QUICK_SELECT_I *quick;
+ List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
+ while ((quick= it++))
+ {
+ if (quick->init_ror_merged_scan(FALSE))
+ DBUG_RETURN(1);
+ }
+ scans_inited= true;
+ }
+ queue_remove_all(&queue);
+ /*
+ Initialize scans for merged quick selects and put all merged quick
+ selects into the queue.
+ */
+ List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
+ while ((quick= it++))
+ {
+ if (quick->reset())
+ DBUG_RETURN(1);
+ if ((error= quick->get_next()))
+ {
+ if (error == HA_ERR_END_OF_FILE)
+ continue;
+ DBUG_RETURN(error);
+ }
+ quick->save_last_pos();
+ queue_insert(&queue, (byte*)quick);
+ }
+
+ if (head->file->ha_rnd_init(1))
+ {
+ DBUG_PRINT("error", ("ROR index_merge rnd_init call failed"));
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(0);
+}
+
+
+bool
+QUICK_ROR_UNION_SELECT::push_quick_back(QUICK_SELECT_I *quick_sel_range)
+{
+ return quick_selects.push_back(quick_sel_range);
+}
+
+QUICK_ROR_UNION_SELECT::~QUICK_ROR_UNION_SELECT()
+{
+ DBUG_ENTER("QUICK_ROR_UNION_SELECT::~QUICK_ROR_UNION_SELECT");
+ delete_queue(&queue);
+ quick_selects.delete_elements();
+ if (head->file->inited != handler::NONE)
+ head->file->ha_rnd_end();
+ free_root(&alloc,MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+
QUICK_RANGE::QUICK_RANGE()
:min_key(0),max_key(0),min_length(0),max_length(0),
flag(NO_MIN_RANGE | NO_MAX_RANGE)
@@ -582,28 +1361,270 @@ SEL_ARG *SEL_ARG::clone_tree()
return root;
}
+
/*
- Test if a key can be used in different ranges
+ Table rows retrieval plan. Range optimizer creates QUICK_SELECT_I-derived
+ objects from table read plans.
+*/
+class TABLE_READ_PLAN
+{
+public:
+ /*
+ Plan read cost, with or without cost of full row retrieval, depending
+ on plan creation parameters.
+ */
+ double read_cost;
+ ha_rows records; /* estimate of #rows to be examined */
+
+ /*
+ If TRUE, the scan returns rows in rowid order. This is used only for
+ scans that can be both ROR and non-ROR.
+ */
+ bool is_ror;
+ /*
+ Create quick select for this plan.
+ SYNOPSIS
+ make_quick()
+ param Parameter from test_quick_select
+ retrieve_full_rows If TRUE, created quick select will do full record
+ retrieval.
+ parent_alloc Memory pool to use, if any.
+
+ NOTES
+ retrieve_full_rows is ignored by some implementations.
+
+ RETURN
+ created quick select
+ NULL on any error.
+ */
+ virtual QUICK_SELECT_I *make_quick(PARAM *param,
+ bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc=NULL) = 0;
+
+ /* Table read plans are allocated on MEM_ROOT and are never deleted */
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
+ static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
+ static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* Never called */ }
+};
+
+class TRP_ROR_INTERSECT;
+class TRP_ROR_UNION;
+class TRP_INDEX_MERGE;
+
+
+/*
+ Plan for a QUICK_RANGE_SELECT scan.
+ TRP_RANGE::make_quick ignores retrieve_full_rows parameter because
+ QUICK_RANGE_SELECT doesn't distinguish between 'index only' scans and full
+ record retrieval scans.
+*/
+
+class TRP_RANGE : public TABLE_READ_PLAN
+{
+public:
+ SEL_ARG *key; /* set of intervals to be used in "range" method retrieval */
+ uint key_idx; /* key number in PARAM::key */
+
+ TRP_RANGE(SEL_ARG *key_arg, uint idx_arg)
+ : key(key_arg), key_idx(idx_arg)
+ {}
+
+ QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc)
+ {
+ DBUG_ENTER("TRP_RANGE::make_quick");
+ QUICK_RANGE_SELECT *quick;
+ if ((quick= get_quick_select(param, key_idx, key, parent_alloc)))
+ {
+ quick->records= records;
+ quick->read_time= read_cost;
+ }
+ DBUG_RETURN(quick);
+ }
+};
+
+
+/* Plan for QUICK_ROR_INTERSECT_SELECT scan. */
+
+class TRP_ROR_INTERSECT : public TABLE_READ_PLAN
+{
+public:
+ QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc);
+
+ /* Array of pointers to ROR range scans used in this intersection */
+ struct st_ror_scan_info **first_scan;
+ struct st_ror_scan_info **last_scan; /* End of the above array */
+ struct st_ror_scan_info *cpk_scan; /* Clustered PK scan, if there is one */
+ bool is_covering; /* TRUE if no row retrieval phase is necessary */
+ double index_scan_costs; /* SUM(cost(index_scan)) */
+};
+
+
+/*
+ Plan for QUICK_ROR_UNION_SELECT scan.
+ QUICK_ROR_UNION_SELECT always retrieves full rows, so retrieve_full_rows
+ is ignored by make_quick.
+*/
+
+class TRP_ROR_UNION : public TABLE_READ_PLAN
+{
+public:
+ QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc);
+ TABLE_READ_PLAN **first_ror; /* array of ptrs to plans for merged scans */
+ TABLE_READ_PLAN **last_ror; /* end of the above array */
+};
+
+
+/*
+ Plan for QUICK_INDEX_MERGE_SELECT scan.
+ QUICK_ROR_INTERSECT_SELECT always retrieves full rows, so retrieve_full_rows
+ is ignored by make_quick.
+*/
+
+class TRP_INDEX_MERGE : public TABLE_READ_PLAN
+{
+public:
+ QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc);
+ TRP_RANGE **range_scans; /* array of ptrs to plans of merged scans */
+ TRP_RANGE **range_scans_end; /* end of the array */
+};
+
+
+/*
+ Plan for a QUICK_GROUP_MIN_MAX_SELECT scan.
+*/
+
+class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN
+{
+private:
+ bool have_min, have_max;
+ KEY_PART_INFO *min_max_arg_part;
+ uint group_prefix_len;
+ uint used_key_parts;
+ uint group_key_parts;
+ KEY *index_info;
+ uint index;
+ uint key_infix_len;
+ byte key_infix[MAX_KEY_LENGTH];
+ SEL_TREE *range_tree; /* Represents all range predicates in the query. */
+ SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */
+ uint param_idx; /* Index of used key in param->key. */
+ /* Number of records selected by the ranges in index_tree. */
+public:
+ ha_rows quick_prefix_records;
+public:
+ TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg,
+ KEY_PART_INFO *min_max_arg_part_arg,
+ uint group_prefix_len_arg, uint used_key_parts_arg,
+ uint group_key_parts_arg, KEY *index_info_arg,
+ uint index_arg, uint key_infix_len_arg,
+ byte *key_infix_arg,
+ SEL_TREE *tree_arg, SEL_ARG *index_tree_arg,
+ uint param_idx_arg, ha_rows quick_prefix_records_arg)
+ : have_min(have_min_arg), have_max(have_max_arg),
+ min_max_arg_part(min_max_arg_part_arg),
+ group_prefix_len(group_prefix_len_arg), used_key_parts(used_key_parts_arg),
+ group_key_parts(group_key_parts_arg), index_info(index_info_arg),
+ index(index_arg), key_infix_len(key_infix_len_arg), range_tree(tree_arg),
+ index_tree(index_tree_arg), param_idx(param_idx_arg),
+ quick_prefix_records(quick_prefix_records_arg)
+ {
+ if (key_infix_len)
+ memcpy(this->key_infix, key_infix_arg, key_infix_len);
+ }
+
+ QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc);
+};
+
+
+/*
+ Fill param->needed_fields with bitmap of fields used in the query.
SYNOPSIS
- SQL_SELECT::test_quick_select(thd,keys_to_use, prev_tables,
- limit, force_quick_range)
+ fill_used_fields_bitmap()
+ param Parameter from test_quick_select function.
+
+ NOTES
+ Clustered PK members are not put into the bitmap as they are implicitly
+ present in all keys (and it is impossible to avoid reading them).
+ RETURN
+ 0 Ok
+ 1 Out of memory.
+*/
+
+static int fill_used_fields_bitmap(PARAM *param)
+{
+ TABLE *table= param->table;
+ param->fields_bitmap_size= (table->s->fields/8 + 1);
+ uchar *tmp;
+ uint pk;
+ if (!(tmp= (uchar*)alloc_root(param->mem_root,param->fields_bitmap_size)) ||
+ bitmap_init(&param->needed_fields, tmp, param->fields_bitmap_size*8,
+ FALSE))
+ return 1;
+
+ bitmap_clear_all(&param->needed_fields);
+ for (uint i= 0; i < table->s->fields; i++)
+ {
+ if (param->thd->query_id == table->field[i]->query_id)
+ bitmap_set_bit(&param->needed_fields, i+1);
+ }
+
+ pk= param->table->s->primary_key;
+ if (param->table->file->primary_key_is_clustered() && pk != MAX_KEY)
+ {
+ /* The table uses clustered PK and it is not internally generated */
+ KEY_PART_INFO *key_part= param->table->key_info[pk].key_part;
+ KEY_PART_INFO *key_part_end= key_part +
+ param->table->key_info[pk].key_parts;
+ for(;key_part != key_part_end; ++key_part)
+ {
+ bitmap_clear_bit(&param->needed_fields, key_part->fieldnr);
+ }
+ }
+ return 0;
+}
+
- Updates the following in the select parameter:
- needed_reg - Bits for keys with may be used if all prev regs are read
- quick - Parameter to use when reading records.
- In the table struct the following information is updated:
- quick_keys - Which keys can be used
- quick_rows - How many rows the key matches
+/*
+ Test if a key can be used in different ranges
- RETURN VALUES
- -1 if impossible select
- 0 if can't use quick_select
- 1 if found usable range
+ SYNOPSIS
+ SQL_SELECT::test_quick_select()
+ thd Current thread
+ keys_to_use Keys to use for range retrieval
+ prev_tables Tables assumed to be already read when the scan is
+ performed (but not read at the moment of this call)
+ limit Query limit
+ force_quick_range Prefer to use range (instead of full table scan) even
+ if it is more expensive.
+
+ NOTES
+ Updates the following in the select parameter:
+ needed_reg - Bits for keys with may be used if all prev regs are read
+ quick - Parameter to use when reading records.
+
+ In the table struct the following information is updated:
+ quick_keys - Which keys can be used
+ quick_rows - How many rows the key matches
+
+ TODO
+ Check if this function really needs to modify keys_to_use, and change the
+ code to pass it by reference if it doesn't.
+
+ In addition to force_quick_range other means can be (an usually are) used
+ to make this function prefer range over full table scan. Figure out if
+ force_quick_range is really needed.
- TODO
- check if the function really needs to modify keys_to_use, and change the
- code to pass it by reference if not
+ RETURN
+ -1 if impossible select (i.e. certainly no rows will be selected)
+ 0 if can't use quick_select
+ 1 if found usable ranges and quick select has been successfully created.
*/
int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
@@ -612,28 +1633,29 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
{
uint idx;
double scan_time;
- DBUG_ENTER("test_quick_select");
+ DBUG_ENTER("SQL_SELECT::test_quick_select");
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
keys_to_use.to_ulonglong(), (ulong) prev_tables,
(ulong) const_tables));
-
+ DBUG_PRINT("info", ("records=%lu", (ulong)head->file->records));
delete quick;
quick=0;
- needed_reg.clear_all(); quick_keys.clear_all();
- if (!cond || (specialflag & SPECIAL_SAFE_MODE) && ! force_quick_range ||
+ needed_reg.clear_all();
+ quick_keys.clear_all();
+ if ((specialflag & SPECIAL_SAFE_MODE) && ! force_quick_range ||
!limit)
DBUG_RETURN(0); /* purecov: inspected */
if (keys_to_use.is_clear_all())
DBUG_RETURN(0);
- records=head->file->records;
+ records= head->file->records;
if (!records)
records++; /* purecov: inspected */
- scan_time=(double) records / TIME_FOR_COMPARE+1;
- read_time=(double) head->file->scan_time()+ scan_time + 1.1;
+ scan_time= (double) records / TIME_FOR_COMPARE + 1;
+ read_time= (double) head->file->scan_time() + scan_time + 1.1;
if (head->force_index)
scan_time= read_time= DBL_MAX;
if (limit < records)
- read_time=(double) records+scan_time+1; // Force to use index
+ read_time= (double) records + scan_time + 1; // Force to use index
else if (read_time <= 2.0 && !force_quick_range)
DBUG_RETURN(0); /* No need for quick select */
@@ -643,7 +1665,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (!keys_to_use.is_clear_all())
{
MEM_ROOT *old_root,alloc;
- SEL_TREE *tree;
+ SEL_TREE *tree= NULL;
KEY_PART *key_parts;
KEY *key_info;
PARAM param;
@@ -657,11 +1679,15 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.table=head;
param.keys=0;
param.mem_root= &alloc;
+ param.needed_reg= &needed_reg;
+ param.imerge_cost_buff_size= 0;
+
thd->no_errors=1; // Don't warn about NULL
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
- if (!(param.key_parts = (KEY_PART*) alloc_root(&alloc,
- sizeof(KEY_PART)*
- head->key_parts)))
+ if (!(param.key_parts= (KEY_PART*) alloc_root(&alloc,
+ sizeof(KEY_PART)*
+ head->s->key_parts)) ||
+ fill_used_fields_bitmap(&param))
{
thd->no_errors=0;
free_root(&alloc,MYF(0)); // Return memory & allocator
@@ -671,8 +1697,12 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
old_root= thd->mem_root;
thd->mem_root= &alloc;
+ /*
+ Make an array with description of all key parts of all table keys.
+ This is used in get_mm_parts function.
+ */
key_info= head->key_info;
- for (idx=0 ; idx < head->keys ; idx++, key_info++)
+ for (idx=0 ; idx < head->s->keys ; idx++, key_info++)
{
KEY_PART_INFO *key_part_info;
if (!keys_to_use.is_set(idx))
@@ -698,81 +1728,141 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
}
param.key_parts_end=key_parts;
- if ((tree=get_mm_tree(&param,cond)))
+ /* Calculate cost of full index read for the shortest covering index */
+ if (!head->used_keys.is_clear_all())
+ {
+ int key_for_use= find_shortest_key(head, &head->used_keys);
+ double key_read_time= (get_index_only_read_time(&param, records,
+ key_for_use) +
+ (double) records / TIME_FOR_COMPARE);
+ DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, "
+ "read time %g", key_for_use, key_read_time));
+ if (key_read_time < read_time)
+ read_time= key_read_time;
+ }
+
+ TABLE_READ_PLAN *best_trp= NULL;
+ TRP_GROUP_MIN_MAX *group_trp;
+ double best_read_time= read_time;
+
+ if (cond)
+ tree= get_mm_tree(&param,cond);
+
+ if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
+ {
+ records=0L; /* Return -1 from this function. */
+ read_time= (double) HA_POS_ERROR;
+ goto free_mem;
+ }
+ else if (tree && tree->type != SEL_TREE::KEY &&
+ tree->type != SEL_TREE::KEY_SMALLER)
+ goto free_mem;
+
+
+ /*
+ Try to construct a QUICK_GROUP_MIN_MAX_SELECT.
+ Notice that it can be constructed no matter if there is a range tree.
+ */
+ group_trp= get_best_group_min_max(&param, tree);
+ if (group_trp && group_trp->read_cost < best_read_time)
+ {
+ best_trp= group_trp;
+ best_read_time= best_trp->read_cost;
+ }
+
+ if (tree)
{
- if (tree->type == SEL_TREE::IMPOSSIBLE)
+ /*
+ It is possible to use a range-based quick select (but it might be
+ slower than 'all' table scan).
+ */
+ if (tree->merges.is_empty())
{
- records=0L; // Return -1 from this function
- read_time= (double) HA_POS_ERROR;
+ TRP_RANGE *range_trp;
+ TRP_ROR_INTERSECT *rori_trp;
+ bool can_build_covering= FALSE;
+
+ /* Get best 'range' plan and prepare data for making other plans */
+ if ((range_trp= get_key_scans_params(&param, tree, FALSE,
+ best_read_time)))
+ {
+ best_trp= range_trp;
+ best_read_time= best_trp->read_cost;
+ }
+
+ /*
+ Simultaneous key scans and row deletes on several handler
+ objects are not allowed so don't use ROR-intersection for
+ table deletes.
+ */
+ if ((thd->lex->sql_command != SQLCOM_DELETE))
+#ifdef NOT_USED
+ if ((thd->lex->sql_command != SQLCOM_UPDATE))
+#endif
+ {
+ /*
+ Get best non-covering ROR-intersection plan and prepare data for
+ building covering ROR-intersection.
+ */
+ if ((rori_trp= get_best_ror_intersect(&param, tree, best_read_time,
+ &can_build_covering)))
+ {
+ best_trp= rori_trp;
+ best_read_time= best_trp->read_cost;
+ /*
+ Try constructing covering ROR-intersect only if it looks possible
+ and worth doing.
+ */
+ if (!rori_trp->is_covering && can_build_covering &&
+ (rori_trp= get_best_covering_ror_intersect(&param, tree,
+ best_read_time)))
+ best_trp= rori_trp;
+ }
+ }
}
- else if (tree->type == SEL_TREE::KEY ||
- tree->type == SEL_TREE::KEY_SMALLER)
+ else
{
- SEL_ARG **key,**end,**best_key=0;
+ /* Try creating index_merge/ROR-union scan. */
+ SEL_IMERGE *imerge;
+ TABLE_READ_PLAN *best_conj_trp= NULL, *new_conj_trp;
+ LINT_INIT(new_conj_trp); /* no empty index_merge lists possible */
+
+ DBUG_PRINT("info",("No range reads possible,"
+ " trying to construct index_merge"));
+ List_iterator_fast<SEL_IMERGE> it(tree->merges);
+ while ((imerge= it++))
+ {
+ new_conj_trp= get_best_disjunct_quick(&param, imerge, best_read_time);
+ if (!best_conj_trp || (new_conj_trp && new_conj_trp->read_cost <
+ best_conj_trp->read_cost))
+ best_conj_trp= new_conj_trp;
+ }
+ if (best_conj_trp)
+ best_trp= best_conj_trp;
+ }
+ }
+ thd->mem_root= old_root;
- for (idx=0,key=tree->keys, end=key+param.keys ;
- key != end ;
- key++,idx++)
- {
- ha_rows found_records;
- double found_read_time;
- if (*key)
- {
- uint keynr= param.real_keynr[idx];
- if ((*key)->type == SEL_ARG::MAYBE_KEY ||
- (*key)->maybe_flag)
- needed_reg.set_bit(keynr);
-
- found_records=check_quick_select(&param, idx, *key);
- if (found_records != HA_POS_ERROR && found_records > 2 &&
- head->used_keys.is_set(keynr) &&
- (head->file->index_flags(keynr, param.max_key_part, 1) &
- HA_KEYREAD_ONLY))
- {
- /*
- We can resolve this by only reading through this key.
- Assume that we will read trough the whole key range
- and that all key blocks are half full (normally things are
- much better).
- */
- uint keys_per_block= (head->file->block_size/2/
- (head->key_info[keynr].key_length+
- head->file->ref_length) + 1);
- found_read_time=((double) (found_records+keys_per_block-1)/
- (double) keys_per_block);
- }
- else
- found_read_time= (head->file->read_time(keynr,
- param.range_count,
- found_records)+
- (double) found_records / TIME_FOR_COMPARE);
- DBUG_PRINT("info",("read_time: %g found_read_time: %g",
- read_time, found_read_time));
- if (read_time > found_read_time && found_records != HA_POS_ERROR)
- {
- read_time=found_read_time;
- records=found_records;
- best_key=key;
- }
- }
- }
- if (best_key && records)
- {
- if ((quick=get_quick_select(&param,(uint) (best_key-tree->keys),
- *best_key)))
- {
- quick->records=records;
- quick->read_time=read_time;
- }
- }
+ /* If we got a read plan, create a quick select from it. */
+ if (best_trp)
+ {
+ records= best_trp->records;
+ if (!(quick= best_trp->make_quick(&param, TRUE)) || quick->init())
+ {
+ delete quick;
+ quick= NULL;
}
}
+
+ free_mem:
free_root(&alloc,MYF(0)); // Return memory & allocator
thd->mem_root= old_root;
thd->no_errors=0;
}
- DBUG_EXECUTE("info",print_quick(quick,&needed_reg););
+
+ DBUG_EXECUTE("info", print_quick(quick, &needed_reg););
+
/*
Assume that if the user is using 'limit' we will only need to scan
limit rows if we are using a key
@@ -780,11 +1870,1533 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
DBUG_RETURN(records ? test(quick) : -1);
}
+
+/*
+ Get cost of 'sweep' full records retrieval.
+ SYNOPSIS
+ get_sweep_read_cost()
+ param Parameter from test_quick_select
+ records # of records to be retrieved
+ RETURN
+ cost of sweep
+*/
+
+double get_sweep_read_cost(const PARAM *param, ha_rows records)
+{
+ double result;
+ DBUG_ENTER("get_sweep_read_cost");
+ if (param->table->file->primary_key_is_clustered())
+ {
+ result= param->table->file->read_time(param->table->s->primary_key,
+ records, records);
+ }
+ else
+ {
+ double n_blocks=
+ ceil(ulonglong2double(param->table->file->data_file_length) / IO_SIZE);
+ double busy_blocks=
+ n_blocks * (1.0 - pow(1.0 - 1.0/n_blocks, rows2double(records)));
+ if (busy_blocks < 1.0)
+ busy_blocks= 1.0;
+ DBUG_PRINT("info",("sweep: nblocks=%g, busy_blocks=%g", n_blocks,
+ busy_blocks));
+ /*
+ Disabled: Bail out if # of blocks to read is bigger than # of blocks in
+ table data file.
+ if (max_cost != DBL_MAX && (busy_blocks+index_reads_cost) >= n_blocks)
+ return 1;
+ */
+ JOIN *join= param->thd->lex->select_lex.join;
+ if (!join || join->tables == 1)
+ {
+ /* No join, assume reading is done in one 'sweep' */
+ result= busy_blocks*(DISK_SEEK_BASE_COST +
+ DISK_SEEK_PROP_COST*n_blocks/busy_blocks);
+ }
+ else
+ {
+ /*
+ Possibly this is a join with source table being non-last table, so
+ assume that disk seeks are random here.
+ */
+ result= busy_blocks;
+ }
+ }
+ DBUG_PRINT("info",("returning cost=%g", result));
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Get best plan for a SEL_IMERGE disjunctive expression.
+ SYNOPSIS
+ get_best_disjunct_quick()
+ param Parameter from check_quick_select function
+ imerge Expression to use
+ read_time Don't create scans with cost > read_time
+
+ NOTES
+ index_merge cost is calculated as follows:
+ index_merge_cost =
+ cost(index_reads) + (see #1)
+ cost(rowid_to_row_scan) + (see #2)
+ cost(unique_use) (see #3)
+
+ 1. cost(index_reads) =SUM_i(cost(index_read_i))
+ For non-CPK scans,
+ cost(index_read_i) = {cost of ordinary 'index only' scan}
+ For CPK scan,
+ cost(index_read_i) = {cost of non-'index only' scan}
+
+ 2. cost(rowid_to_row_scan)
+ If table PK is clustered then
+ cost(rowid_to_row_scan) =
+ {cost of ordinary clustered PK scan with n_ranges=n_rows}
+
+ Otherwise, we use the following model to calculate costs:
+ We need to retrieve n_rows rows from file that occupies n_blocks blocks.
+ We assume that offsets of rows we need are independent variates with
+ uniform distribution in [0..max_file_offset] range.
+
+ We'll denote block as "busy" if it contains row(s) we need to retrieve
+ and "empty" if doesn't contain rows we need.
+
+ Probability that a block is empty is (1 - 1/n_blocks)^n_rows (this
+ applies to any block in file). Let x_i be a variate taking value 1 if
+ block #i is empty and 0 otherwise.
+
+ Then E(x_i) = (1 - 1/n_blocks)^n_rows;
+
+ E(n_empty_blocks) = E(sum(x_i)) = sum(E(x_i)) =
+ = n_blocks * ((1 - 1/n_blocks)^n_rows) =
+ ~= n_blocks * exp(-n_rows/n_blocks).
+
+ E(n_busy_blocks) = n_blocks*(1 - (1 - 1/n_blocks)^n_rows) =
+ ~= n_blocks * (1 - exp(-n_rows/n_blocks)).
+
+ Average size of "hole" between neighbor non-empty blocks is
+ E(hole_size) = n_blocks/E(n_busy_blocks).
+
+ The total cost of reading all needed blocks in one "sweep" is:
+
+ E(n_busy_blocks)*
+ (DISK_SEEK_BASE_COST + DISK_SEEK_PROP_COST*n_blocks/E(n_busy_blocks)).
+
+ 3. Cost of Unique use is calculated in Unique::get_use_cost function.
+
+ ROR-union cost is calculated in the same way index_merge, but instead of
+ Unique a priority queue is used.
+
+ RETURN
+ Created read plan
+ NULL - Out of memory or no read scan could be built.
+*/
+
+static
+TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
+ double read_time)
+{
+ SEL_TREE **ptree;
+ TRP_INDEX_MERGE *imerge_trp= NULL;
+ uint n_child_scans= imerge->trees_next - imerge->trees;
+ TRP_RANGE **range_scans;
+ TRP_RANGE **cur_child;
+ TRP_RANGE **cpk_scan= NULL;
+ bool imerge_too_expensive= FALSE;
+ double imerge_cost= 0.0;
+ ha_rows cpk_scan_records= 0;
+ ha_rows non_cpk_scan_records= 0;
+ bool pk_is_clustered= param->table->file->primary_key_is_clustered();
+ bool all_scans_ror_able= TRUE;
+ bool all_scans_rors= TRUE;
+ uint unique_calc_buff_size;
+ TABLE_READ_PLAN **roru_read_plans;
+ TABLE_READ_PLAN **cur_roru_plan;
+ double roru_index_costs;
+ ha_rows roru_total_records;
+ double roru_intersect_part= 1.0;
+ DBUG_ENTER("get_best_disjunct_quick");
+ DBUG_PRINT("info", ("Full table scan cost =%g", read_time));
+
+ if (!(range_scans= (TRP_RANGE**)alloc_root(param->mem_root,
+ sizeof(TRP_RANGE*)*
+ n_child_scans)))
+ DBUG_RETURN(NULL);
+ /*
+ Collect best 'range' scan for each of disjuncts, and, while doing so,
+ analyze possibility of ROR scans. Also calculate some values needed by
+ other parts of the code.
+ */
+ for (ptree= imerge->trees, cur_child= range_scans;
+ ptree != imerge->trees_next;
+ ptree++, cur_child++)
+ {
+ DBUG_EXECUTE("info", print_sel_tree(param, *ptree, &(*ptree)->keys_map,
+ "tree in SEL_IMERGE"););
+ if (!(*cur_child= get_key_scans_params(param, *ptree, TRUE, read_time)))
+ {
+ /*
+ One of index scans in this index_merge is more expensive than entire
+ table read for another available option. The entire index_merge (and
+ any possible ROR-union) will be more expensive then, too. We continue
+ here only to update SQL_SELECT members.
+ */
+ imerge_too_expensive= TRUE;
+ }
+ if (imerge_too_expensive)
+ continue;
+
+ imerge_cost += (*cur_child)->read_cost;
+ all_scans_ror_able &= ((*ptree)->n_ror_scans > 0);
+ all_scans_rors &= (*cur_child)->is_ror;
+ if (pk_is_clustered &&
+ param->real_keynr[(*cur_child)->key_idx] ==
+ param->table->s->primary_key)
+ {
+ cpk_scan= cur_child;
+ cpk_scan_records= (*cur_child)->records;
+ }
+ else
+ non_cpk_scan_records += (*cur_child)->records;
+ }
+
+ DBUG_PRINT("info", ("index_merge scans cost=%g", imerge_cost));
+ if (imerge_too_expensive || (imerge_cost > read_time) ||
+ (non_cpk_scan_records+cpk_scan_records >= param->table->file->records) &&
+ read_time != DBL_MAX)
+ {
+ /*
+ Bail out if it is obvious that both index_merge and ROR-union will be
+ more expensive
+ */
+ DBUG_PRINT("info", ("Sum of index_merge scans is more expensive than "
+ "full table scan, bailing out"));
+ DBUG_RETURN(NULL);
+ }
+ if (all_scans_rors)
+ {
+ roru_read_plans= (TABLE_READ_PLAN**)range_scans;
+ goto skip_to_ror_scan;
+ }
+ if (cpk_scan)
+ {
+ /*
+ Add one ROWID comparison for each row retrieved on non-CPK scan. (it
+ is done in QUICK_RANGE_SELECT::row_in_ranges)
+ */
+ imerge_cost += non_cpk_scan_records / TIME_FOR_COMPARE_ROWID;
+ }
+
+ /* Calculate cost(rowid_to_row_scan) */
+ imerge_cost += get_sweep_read_cost(param, non_cpk_scan_records);
+ DBUG_PRINT("info",("index_merge cost with rowid-to-row scan: %g",
+ imerge_cost));
+ if (imerge_cost > read_time)
+ goto build_ror_index_merge;
+
+ /* Add Unique operations cost */
+ unique_calc_buff_size=
+ Unique::get_cost_calc_buff_size(non_cpk_scan_records,
+ param->table->file->ref_length,
+ param->thd->variables.sortbuff_size);
+ if (param->imerge_cost_buff_size < unique_calc_buff_size)
+ {
+ if (!(param->imerge_cost_buff= (uint*)alloc_root(param->mem_root,
+ unique_calc_buff_size)))
+ DBUG_RETURN(NULL);
+ param->imerge_cost_buff_size= unique_calc_buff_size;
+ }
+
+ imerge_cost +=
+ Unique::get_use_cost(param->imerge_cost_buff, non_cpk_scan_records,
+ param->table->file->ref_length,
+ param->thd->variables.sortbuff_size);
+ DBUG_PRINT("info",("index_merge total cost: %g (wanted: less then %g)",
+ imerge_cost, read_time));
+ if (imerge_cost < read_time)
+ {
+ if ((imerge_trp= new (param->mem_root)TRP_INDEX_MERGE))
+ {
+ imerge_trp->read_cost= imerge_cost;
+ imerge_trp->records= non_cpk_scan_records + cpk_scan_records;
+ imerge_trp->records= min(imerge_trp->records,
+ param->table->file->records);
+ imerge_trp->range_scans= range_scans;
+ imerge_trp->range_scans_end= range_scans + n_child_scans;
+ read_time= imerge_cost;
+ }
+ }
+
+build_ror_index_merge:
+ if (!all_scans_ror_able || param->thd->lex->sql_command == SQLCOM_DELETE)
+ DBUG_RETURN(imerge_trp);
+
+ /* Ok, it is possible to build a ROR-union, try it. */
+ bool dummy;
+ if (!(roru_read_plans=
+ (TABLE_READ_PLAN**)alloc_root(param->mem_root,
+ sizeof(TABLE_READ_PLAN*)*
+ n_child_scans)))
+ DBUG_RETURN(imerge_trp);
+skip_to_ror_scan:
+ roru_index_costs= 0.0;
+ roru_total_records= 0;
+ cur_roru_plan= roru_read_plans;
+
+ /* Find 'best' ROR scan for each of trees in disjunction */
+ for (ptree= imerge->trees, cur_child= range_scans;
+ ptree != imerge->trees_next;
+ ptree++, cur_child++, cur_roru_plan++)
+ {
+ /*
+ Assume the best ROR scan is the one that has cheapest full-row-retrieval
+ scan cost.
+ Also accumulate index_only scan costs as we'll need them to calculate
+ overall index_intersection cost.
+ */
+ double cost;
+ if ((*cur_child)->is_ror)
+ {
+ /* Ok, we have index_only cost, now get full rows scan cost */
+ cost= param->table->file->
+ read_time(param->real_keynr[(*cur_child)->key_idx], 1,
+ (*cur_child)->records) +
+ rows2double((*cur_child)->records) / TIME_FOR_COMPARE;
+ }
+ else
+ cost= read_time;
+
+ TABLE_READ_PLAN *prev_plan= *cur_child;
+ if (!(*cur_roru_plan= get_best_ror_intersect(param, *ptree, cost,
+ &dummy)))
+ {
+ if (prev_plan->is_ror)
+ *cur_roru_plan= prev_plan;
+ else
+ DBUG_RETURN(imerge_trp);
+ roru_index_costs += (*cur_roru_plan)->read_cost;
+ }
+ else
+ roru_index_costs +=
+ ((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs;
+ roru_total_records += (*cur_roru_plan)->records;
+ roru_intersect_part *= (*cur_roru_plan)->records /
+ param->table->file->records;
+ }
+
+ /*
+ rows to retrieve=
+ SUM(rows_in_scan_i) - table_rows * PROD(rows_in_scan_i / table_rows).
+ This is valid because index_merge construction guarantees that conditions
+ in disjunction do not share key parts.
+ */
+ roru_total_records -= (ha_rows)(roru_intersect_part*
+ param->table->file->records);
+ /* ok, got a ROR read plan for each of the disjuncts
+ Calculate cost:
+ cost(index_union_scan(scan_1, ... scan_n)) =
+ SUM_i(cost_of_index_only_scan(scan_i)) +
+ queue_use_cost(rowid_len, n) +
+ cost_of_row_retrieval
+ See get_merge_buffers_cost function for queue_use_cost formula derivation.
+ */
+
+ double roru_total_cost;
+ roru_total_cost= roru_index_costs +
+ rows2double(roru_total_records)*log((double)n_child_scans) /
+ (TIME_FOR_COMPARE_ROWID * M_LN2) +
+ get_sweep_read_cost(param, roru_total_records);
+
+ DBUG_PRINT("info", ("ROR-union: cost %g, %d members", roru_total_cost,
+ n_child_scans));
+ TRP_ROR_UNION* roru;
+ if (roru_total_cost < read_time)
+ {
+ if ((roru= new (param->mem_root) TRP_ROR_UNION))
+ {
+ roru->first_ror= roru_read_plans;
+ roru->last_ror= roru_read_plans + n_child_scans;
+ roru->read_cost= roru_total_cost;
+ roru->records= roru_total_records;
+ DBUG_RETURN(roru);
+ }
+ }
+ DBUG_RETURN(imerge_trp);
+}
+
+
+/*
+ Calculate cost of 'index only' scan for given index and number of records.
+
+ SYNOPSIS
+ get_index_only_read_time()
+ param parameters structure
+ records #of records to read
+ keynr key to read
+
+ NOTES
+ It is assumed that we will read trough the whole key range and that all
+ key blocks are half full (normally things are much better). It is also
+ assumed that each time we read the next key from the index, the handler
+ performs a random seek, thus the cost is proportional to the number of
+ blocks read.
+
+ TODO:
+ Move this to handler->read_time() by adding a flag 'index-only-read' to
+ this call. The reason for doing this is that the current function doesn't
+ handle the case when the row is stored in the b-tree (like in innodb
+ clustered index)
+*/
+
+inline double get_index_only_read_time(const PARAM* param, ha_rows records,
+ int keynr)
+{
+ double read_time;
+ uint keys_per_block= (param->table->file->block_size/2/
+ (param->table->key_info[keynr].key_length+
+ param->table->file->ref_length) + 1);
+ read_time=((double) (records+keys_per_block-1)/
+ (double) keys_per_block);
+ return read_time;
+}
+
+
+typedef struct st_ror_scan_info
+{
+ uint idx; /* # of used key in param->keys */
+ uint keynr; /* # of used key in table */
+ ha_rows records; /* estimate of # records this scan will return */
+
+ /* Set of intervals over key fields that will be used for row retrieval. */
+ SEL_ARG *sel_arg;
+
+ /* Fields used in the query and covered by this ROR scan. */
+ MY_BITMAP covered_fields;
+ uint used_fields_covered; /* # of set bits in covered_fields */
+ int key_rec_length; /* length of key record (including rowid) */
+
+ /*
+ Cost of reading all index records with values in sel_arg intervals set
+ (assuming there is no need to access full table records)
+ */
+ double index_read_cost;
+ uint first_uncovered_field; /* first unused bit in covered_fields */
+ uint key_components; /* # of parts in the key */
+} ROR_SCAN_INFO;
+
+
+/*
+ Create ROR_SCAN_INFO* structure with a single ROR scan on index idx using
+ sel_arg set of intervals.
+
+ SYNOPSIS
+ make_ror_scan()
+ param Parameter from test_quick_select function
+ idx Index of key in param->keys
+ sel_arg Set of intervals for a given key
+ RETURN
+ NULL - out of memory
+ ROR scan structure containing a scan for {idx, sel_arg}
+*/
+
+static
+ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg)
+{
+ ROR_SCAN_INFO *ror_scan;
+ uchar *bitmap_buf;
+ uint keynr;
+ DBUG_ENTER("make_ror_scan");
+ if (!(ror_scan= (ROR_SCAN_INFO*)alloc_root(param->mem_root,
+ sizeof(ROR_SCAN_INFO))))
+ DBUG_RETURN(NULL);
+
+ ror_scan->idx= idx;
+ ror_scan->keynr= keynr= param->real_keynr[idx];
+ ror_scan->key_rec_length= param->table->key_info[keynr].key_length +
+ param->table->file->ref_length;
+ ror_scan->sel_arg= sel_arg;
+ ror_scan->records= param->table->quick_rows[keynr];
+
+ if (!(bitmap_buf= (uchar*)alloc_root(param->mem_root,
+ param->fields_bitmap_size)))
+ DBUG_RETURN(NULL);
+
+ if (bitmap_init(&ror_scan->covered_fields, bitmap_buf,
+ param->fields_bitmap_size*8, FALSE))
+ DBUG_RETURN(NULL);
+ bitmap_clear_all(&ror_scan->covered_fields);
+
+ KEY_PART_INFO *key_part= param->table->key_info[keynr].key_part;
+ KEY_PART_INFO *key_part_end= key_part +
+ param->table->key_info[keynr].key_parts;
+ uint n_used_covered= 0;
+ for (;key_part != key_part_end; ++key_part)
+ {
+ if (bitmap_is_set(&param->needed_fields, key_part->fieldnr))
+ {
+ n_used_covered++;
+ bitmap_set_bit(&ror_scan->covered_fields, key_part->fieldnr);
+ }
+ }
+ ror_scan->index_read_cost=
+ get_index_only_read_time(param, param->table->quick_rows[ror_scan->keynr],
+ ror_scan->keynr);
+ DBUG_RETURN(ror_scan);
+}
+
+
+/*
+ Compare two ROR_SCAN_INFO** by E(#records_matched) * key_record_length.
+ SYNOPSIS
+ cmp_ror_scan_info()
+ a ptr to first compared value
+ b ptr to second compared value
+
+ RETURN
+ -1 a < b
+ 0 a = b
+ 1 a > b
+*/
+static int cmp_ror_scan_info(ROR_SCAN_INFO** a, ROR_SCAN_INFO** b)
+{
+ double val1= rows2double((*a)->records) * (*a)->key_rec_length;
+ double val2= rows2double((*b)->records) * (*b)->key_rec_length;
+ return (val1 < val2)? -1: (val1 == val2)? 0 : 1;
+}
+
+/*
+ Compare two ROR_SCAN_INFO** by
+ (#covered fields in F desc,
+ #components asc,
+ number of first not covered component asc)
+
+ SYNOPSIS
+ cmp_ror_scan_info_covering()
+ a ptr to first compared value
+ b ptr to second compared value
+
+ RETURN
+ -1 a < b
+ 0 a = b
+ 1 a > b
+*/
+static int cmp_ror_scan_info_covering(ROR_SCAN_INFO** a, ROR_SCAN_INFO** b)
+{
+ if ((*a)->used_fields_covered > (*b)->used_fields_covered)
+ return -1;
+ if ((*a)->used_fields_covered < (*b)->used_fields_covered)
+ return 1;
+ if ((*a)->key_components < (*b)->key_components)
+ return -1;
+ if ((*a)->key_components > (*b)->key_components)
+ return 1;
+ if ((*a)->first_uncovered_field < (*b)->first_uncovered_field)
+ return -1;
+ if ((*a)->first_uncovered_field > (*b)->first_uncovered_field)
+ return 1;
+ return 0;
+}
+
+/* Auxiliary structure for incremental ROR-intersection creation */
+typedef struct
+{
+ const PARAM *param;
+ MY_BITMAP covered_fields; /* union of fields covered by all scans */
+ /*
+ Fraction of table records that satisfies conditions of all scans.
+ This is the number of full records that will be retrieved if a
+ non-index_only index intersection will be employed.
+ */
+ double out_rows;
+ /* TRUE if covered_fields is a superset of needed_fields */
+ bool is_covering;
+
+ ha_rows index_records; /* sum(#records to look in indexes) */
+ double index_scan_costs; /* SUM(cost of 'index-only' scans) */
+ double total_cost;
+} ROR_INTERSECT_INFO;
+
+
+/*
+ Allocate a ROR_INTERSECT_INFO and initialize it to contain zero scans.
+
+ SYNOPSIS
+ ror_intersect_init()
+ param Parameter from test_quick_select
+
+ RETURN
+ allocated structure
+ NULL on error
+*/
+
+static
+ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param)
+{
+ ROR_INTERSECT_INFO *info;
+ uchar* buf;
+ if (!(info= (ROR_INTERSECT_INFO*)alloc_root(param->mem_root,
+ sizeof(ROR_INTERSECT_INFO))))
+ return NULL;
+ info->param= param;
+ if (!(buf= (uchar*)alloc_root(param->mem_root, param->fields_bitmap_size)))
+ return NULL;
+ if (bitmap_init(&info->covered_fields, buf, param->fields_bitmap_size*8,
+ FALSE))
+ return NULL;
+ info->is_covering= FALSE;
+ info->index_scan_costs= 0.0;
+ info->index_records= 0;
+ info->out_rows= param->table->file->records;
+ bitmap_clear_all(&info->covered_fields);
+ return info;
+}
+
+void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
+{
+ dst->param= src->param;
+ memcpy(dst->covered_fields.bitmap, src->covered_fields.bitmap,
+ src->covered_fields.bitmap_size);
+ dst->out_rows= src->out_rows;
+ dst->is_covering= src->is_covering;
+ dst->index_records= src->index_records;
+ dst->index_scan_costs= src->index_scan_costs;
+ dst->total_cost= src->total_cost;
+}
+/*
+ Get selectivity of a ROR scan wrt ROR-intersection.
+
+ SYNOPSIS
+ ror_scan_selectivity()
+ info ROR-interection
+ scan ROR scan
+
+ NOTES
+ Suppose we have a condition on several keys
+ cond=k_11=c_11 AND k_12=c_12 AND ... // parts of first key
+ k_21=c_21 AND k_22=c_22 AND ... // parts of second key
+ ...
+ k_n1=c_n1 AND k_n3=c_n3 AND ... (1) //parts of the key used by *scan
+
+ where k_ij may be the same as any k_pq (i.e. keys may have common parts).
+
+ A full row is retrieved iff entire cond holds.
+
+ The recursive procedure for finding P(cond) is as follows:
+
+ First step:
+ Pick 1st part of 1st key and break conjunction (1) into two parts:
+ cond= (k_11=c_11 AND R)
+
+ Here R may still contain condition(s) equivalent to k_11=c_11.
+ Nevertheless, the following holds:
+
+ P(k_11=c_11 AND R) = P(k_11=c_11) * P(R|k_11=c_11).
+
+ Mark k_11 as fixed field (and satisfied condition) F, save P(F),
+ save R to be cond and proceed to recursion step.
+
+ Recursion step:
+ We have a set of fixed fields/satisfied conditions) F, probability P(F),
+ and remaining conjunction R
+ Pick next key part on current key and its condition "k_ij=c_ij".
+ We will add "k_ij=c_ij" into F and update P(F).
+ Lets denote k_ij as t, R = t AND R1, where R1 may still contain t. Then
+
+ P((t AND R1)|F) = P(t|F) * P(R1|t|F) = P(t|F) * P(R1|(t AND F)) (2)
+
+ (where '|' mean conditional probability, not "or")
+
+ Consider the first multiplier in (2). One of the following holds:
+ a) F contains condition on field used in t (i.e. t AND F = F).
+ Then P(t|F) = 1
+
+ b) F doesn't contain condition on field used in t. Then F and t are
+ considered independent.
+
+ P(t|F) = P(t|(fields_before_t_in_key AND other_fields)) =
+ = P(t|fields_before_t_in_key).
+
+ P(t|fields_before_t_in_key) = #records(fields_before_t_in_key) /
+ #records(fields_before_t_in_key, t)
+
+ The second multiplier is calculated by applying this step recursively.
+
+ IMPLEMENTATION
+ This function calculates the result of application of the "recursion step"
+ described above for all fixed key members of a single key, accumulating set
+ of covered fields, selectivity, etc.
+
+ The calculation is conducted as follows:
+ Lets denote #records(keypart1, ... keypartK) as n_k. We need to calculate
+
+ n_{k1} n_{k_2}
+ --------- * --------- * .... (3)
+ n_{k1-1} n_{k2_1}
+
+ where k1,k2,... are key parts which fields were not yet marked as fixed
+ ( this is result of application of option b) of the recursion step for
+ parts of a single key).
+ Since it is reasonable to expect that most of the fields are not marked
+ as fixed, we calcualate (3) as
+
+ n_{i1} n_{i_2}
+ (3) = n_{max_key_part} / ( --------- * --------- * .... )
+ n_{i1-1} n_{i2_1}
+
+ where i1,i2, .. are key parts that were already marked as fixed.
+
+ In order to minimize number of expensive records_in_range calls we group
+ and reduce adjacent fractions.
+
+ RETURN
+ Selectivity of given ROR scan.
+
+*/
+
+static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
+ const ROR_SCAN_INFO *scan)
+{
+ double selectivity_mult= 1.0;
+ KEY_PART_INFO *key_part= info->param->table->key_info[scan->keynr].key_part;
+ byte key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */
+ char *key_ptr= (char*) key_val;
+ SEL_ARG *sel_arg, *tuple_arg= NULL;
+ bool cur_covered;
+ bool prev_covered= test(bitmap_is_set(&info->covered_fields,
+ key_part->fieldnr));
+ key_range min_range;
+ key_range max_range;
+ min_range.key= (byte*) key_val;
+ min_range.flag= HA_READ_KEY_EXACT;
+ max_range.key= (byte*) key_val;
+ max_range.flag= HA_READ_AFTER_KEY;
+ ha_rows prev_records= info->param->table->file->records;
+ int i;
+ DBUG_ENTER("ror_intersect_selectivity");
+ for(i= 0, sel_arg= scan->sel_arg; sel_arg;
+ i++, sel_arg= sel_arg->next_key_part)
+ {
+ DBUG_PRINT("info",("sel_arg step"));
+ cur_covered= test(bitmap_is_set(&info->covered_fields,
+ (key_part + i)->fieldnr));
+ if (cur_covered != prev_covered)
+ {
+ /* create (part1val, ..., part{n-1}val) tuple. */
+ {
+ if (!tuple_arg)
+ {
+ tuple_arg= scan->sel_arg;
+ tuple_arg->store_min(key_part->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->length, &key_ptr, 0);
+ }
+ }
+ ha_rows records;
+ min_range.length= max_range.length= ((char*) key_ptr - (char*) key_val);
+ records= info->param->table->file->
+ records_in_range(scan->keynr, &min_range, &max_range);
+ if (cur_covered)
+ {
+ /* uncovered -> covered */
+ double tmp= rows2double(records)/rows2double(prev_records);
+ DBUG_PRINT("info", ("Selectivity multiplier: %g", tmp));
+ selectivity_mult *= tmp;
+ prev_records= HA_POS_ERROR;
+ }
+ else
+ {
+ /* covered -> uncovered */
+ prev_records= records;
+ }
+ }
+ prev_covered= cur_covered;
+ }
+ if (!prev_covered)
+ {
+ double tmp= rows2double(info->param->table->quick_rows[scan->keynr]) /
+ rows2double(prev_records);
+ DBUG_PRINT("info", ("Selectivity multiplier: %g", tmp));
+ selectivity_mult *= tmp;
+ }
+ DBUG_PRINT("info", ("Returning multiplier: %g", selectivity_mult));
+ DBUG_RETURN(selectivity_mult);
+}
+
+/*
+ Check if adding a ROR scan to a ROR-intersection reduces its cost of
+ ROR-intersection and if yes, update parameters of ROR-intersection,
+ including its cost.
+
+ SYNOPSIS
+ ror_intersect_add()
+ param Parameter from test_quick_select
+ info ROR-intersection structure to add the scan to.
+ ror_scan ROR scan info to add.
+ is_cpk_scan If TRUE, add the scan as CPK scan (this can be inferred
+ from other parameters and is passed separately only to
+ avoid duplicating the inference code)
+
+ NOTES
+ Adding a ROR scan to ROR-intersect "makes sense" iff the cost of ROR-
+ intersection decreases. The cost of ROR-intersection is calculated as
+ follows:
+
+ cost= SUM_i(key_scan_cost_i) + cost_of_full_rows_retrieval
+
+ When we add a scan the first increases and the second decreases.
+
+ cost_of_full_rows_retrieval=
+ (union of indexes used covers all needed fields) ?
+ cost_of_sweep_read(E(rows_to_retrieve), rows_in_table) :
+ 0
+
+ E(rows_to_retrieve) = #rows_in_table * ror_scan_selectivity(null, scan1) *
+ ror_scan_selectivity({scan1}, scan2) * ... *
+ ror_scan_selectivity({scan1,...}, scanN).
+ RETURN
+ TRUE ROR scan added to ROR-intersection, cost updated.
+ FALSE It doesn't make sense to add this ROR scan to this ROR-intersection.
+*/
+
+static bool ror_intersect_add(ROR_INTERSECT_INFO *info,
+ ROR_SCAN_INFO* ror_scan, bool is_cpk_scan)
+{
+ double selectivity_mult= 1.0;
+
+ DBUG_ENTER("ror_intersect_add");
+ DBUG_PRINT("info", ("Current out_rows= %g", info->out_rows));
+ DBUG_PRINT("info", ("Adding scan on %s",
+ info->param->table->key_info[ror_scan->keynr].name));
+ DBUG_PRINT("info", ("is_cpk_scan=%d",is_cpk_scan));
+
+ selectivity_mult = ror_scan_selectivity(info, ror_scan);
+ if (selectivity_mult == 1.0)
+ {
+ /* Don't add this scan if it doesn't improve selectivity. */
+ DBUG_PRINT("info", ("The scan doesn't improve selectivity."));
+ DBUG_RETURN(false);
+ }
+
+ info->out_rows *= selectivity_mult;
+ DBUG_PRINT("info", ("info->total_cost= %g", info->total_cost));
+
+ if (is_cpk_scan)
+ {
+ /*
+ CPK scan is used to filter out rows. We apply filtering for
+ each record of every scan. Assuming 1/TIME_FOR_COMPARE_ROWID
+ per check this gives us:
+ */
+ info->index_scan_costs += rows2double(info->index_records) /
+ TIME_FOR_COMPARE_ROWID;
+ }
+ else
+ {
+ info->index_records += info->param->table->quick_rows[ror_scan->keynr];
+ info->index_scan_costs += ror_scan->index_read_cost;
+ bitmap_union(&info->covered_fields, &ror_scan->covered_fields);
+ if (!info->is_covering && bitmap_is_subset(&info->param->needed_fields,
+ &info->covered_fields))
+ {
+ DBUG_PRINT("info", ("ROR-intersect is covering now"));
+ info->is_covering= TRUE;
+ }
+ }
+
+ info->total_cost= info->index_scan_costs;
+ DBUG_PRINT("info", ("info->total_cost= %g", info->total_cost));
+ if (!info->is_covering)
+ {
+ info->total_cost +=
+ get_sweep_read_cost(info->param, double2rows(info->out_rows));
+ DBUG_PRINT("info", ("info->total_cost= %g", info->total_cost));
+ }
+ DBUG_PRINT("info", ("New out_rows= %g", info->out_rows));
+ DBUG_PRINT("info", ("New cost= %g, %scovering", info->total_cost,
+ info->is_covering?"" : "non-"));
+ DBUG_RETURN(TRUE);
+}
+
+
+/*
+ Get best ROR-intersection plan using non-covering ROR-intersection search
+ algorithm. The returned plan may be covering.
+
+ SYNOPSIS
+ get_best_ror_intersect()
+ param Parameter from test_quick_select function.
+ tree Transformed restriction condition to be used to look
+ for ROR scans.
+ read_time Do not return read plans with cost > read_time.
+ are_all_covering [out] set to TRUE if union of all scans covers all
+ fields needed by the query (and it is possible to build
+ a covering ROR-intersection)
+
+ NOTES
+ get_key_scans_params must be called before this function can be called.
+
+ When this function is called by ROR-union construction algorithm it
+ assumes it is building an uncovered ROR-intersection (and thus # of full
+ records to be retrieved is wrong here). This is a hack.
+
+ IMPLEMENTATION
+ The approximate best non-covering plan search algorithm is as follows:
+
+ find_min_ror_intersection_scan()
+ {
+ R= select all ROR scans;
+ order R by (E(#records_matched) * key_record_length).
+
+ S= first(R); -- set of scans that will be used for ROR-intersection
+ R= R-first(S);
+ min_cost= cost(S);
+ min_scan= make_scan(S);
+ while (R is not empty)
+ {
+ firstR= R - first(R);
+ if (!selectivity(S + firstR < selectivity(S)))
+ continue;
+
+ S= S + first(R);
+ if (cost(S) < min_cost)
+ {
+ min_cost= cost(S);
+ min_scan= make_scan(S);
+ }
+ }
+ return min_scan;
+ }
+
+ See ror_intersect_add function for ROR intersection costs.
+
+ Special handling for Clustered PK scans
+ Clustered PK contains all table fields, so using it as a regular scan in
+ index intersection doesn't make sense: a range scan on CPK will be less
+ expensive in this case.
+ Clustered PK scan has special handling in ROR-intersection: it is not used
+ to retrieve rows, instead its condition is used to filter row references
+ we get from scans on other keys.
+
+ RETURN
+ ROR-intersection table read plan
+ NULL if out of memory or no suitable plan found.
+*/
+
+static
+TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
+ double read_time,
+ bool *are_all_covering)
+{
+ uint idx;
+ double min_cost= DBL_MAX;
+ DBUG_ENTER("get_best_ror_intersect");
+
+ if ((tree->n_ror_scans < 2) || !param->table->file->records)
+ DBUG_RETURN(NULL);
+
+ /*
+ Step1: Collect ROR-able SEL_ARGs and create ROR_SCAN_INFO for each of
+ them. Also find and save clustered PK scan if there is one.
+ */
+ ROR_SCAN_INFO **cur_ror_scan;
+ ROR_SCAN_INFO *cpk_scan= NULL;
+ uint cpk_no;
+ bool cpk_scan_used= FALSE;
+
+ if (!(tree->ror_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root,
+ sizeof(ROR_SCAN_INFO*)*
+ param->keys)))
+ return NULL;
+ cpk_no= ((param->table->file->primary_key_is_clustered()) ?
+ param->table->s->primary_key : MAX_KEY);
+
+ for (idx= 0, cur_ror_scan= tree->ror_scans; idx < param->keys; idx++)
+ {
+ ROR_SCAN_INFO *scan;
+ if (!tree->ror_scans_map.is_set(idx))
+ continue;
+ if (!(scan= make_ror_scan(param, idx, tree->keys[idx])))
+ return NULL;
+ if (param->real_keynr[idx] == cpk_no)
+ {
+ cpk_scan= scan;
+ tree->n_ror_scans--;
+ }
+ else
+ *(cur_ror_scan++)= scan;
+ }
+
+ tree->ror_scans_end= cur_ror_scan;
+ DBUG_EXECUTE("info",print_ror_scans_arr(param->table, "original",
+ tree->ror_scans,
+ tree->ror_scans_end););
+ /*
+ Ok, [ror_scans, ror_scans_end) is array of ptrs to initialized
+ ROR_SCAN_INFO's.
+ Step 2: Get best ROR-intersection using an approximate algorithm.
+ */
+ qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*),
+ (qsort_cmp)cmp_ror_scan_info);
+ DBUG_EXECUTE("info",print_ror_scans_arr(param->table, "ordered",
+ tree->ror_scans,
+ tree->ror_scans_end););
+
+ ROR_SCAN_INFO **intersect_scans; /* ROR scans used in index intersection */
+ ROR_SCAN_INFO **intersect_scans_end;
+ if (!(intersect_scans= (ROR_SCAN_INFO**)alloc_root(param->mem_root,
+ sizeof(ROR_SCAN_INFO*)*
+ tree->n_ror_scans)))
+ return NULL;
+ intersect_scans_end= intersect_scans;
+
+ /* Create and incrementally update ROR intersection. */
+ ROR_INTERSECT_INFO *intersect, *intersect_best;
+ if (!(intersect= ror_intersect_init(param)) ||
+ !(intersect_best= ror_intersect_init(param)))
+ return NULL;
+
+ /* [intersect_scans,intersect_scans_best) will hold the best intersection */
+ ROR_SCAN_INFO **intersect_scans_best;
+ cur_ror_scan= tree->ror_scans;
+ intersect_scans_best= intersect_scans;
+ while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering)
+ {
+ /* S= S + first(R); R= R - first(R); */
+ if (!ror_intersect_add(intersect, *cur_ror_scan, false))
+ {
+ cur_ror_scan++;
+ continue;
+ }
+
+ *(intersect_scans_end++)= *(cur_ror_scan++);
+
+ if (intersect->total_cost < min_cost)
+ {
+ /* Local minimum found, save it */
+ ror_intersect_cpy(intersect_best, intersect);
+ intersect_scans_best= intersect_scans_end;
+ min_cost = intersect->total_cost;
+ }
+ }
+
+ if (intersect_scans_best == intersect_scans)
+ {
+ DBUG_PRINT("info", ("None of scans increase selectivity"));
+ DBUG_RETURN(NULL);
+ }
+
+ DBUG_EXECUTE("info",print_ror_scans_arr(param->table,
+ "best ROR-intersection",
+ intersect_scans,
+ intersect_scans_best););
+
+ *are_all_covering= intersect->is_covering;
+ uint best_num= intersect_scans_best - intersect_scans;
+ ror_intersect_cpy(intersect, intersect_best);
+
+ /*
+ Ok, found the best ROR-intersection of non-CPK key scans.
+ Check if we should add a CPK scan. If the obtained ROR-intersection is
+ covering, it doesn't make sense to add CPK scan.
+ */
+ if (cpk_scan && !intersect->is_covering)
+ {
+ if (ror_intersect_add(intersect, cpk_scan, TRUE) &&
+ (intersect->total_cost < min_cost))
+ {
+ cpk_scan_used= TRUE;
+ intersect_best= intersect; //just set pointer here
+ }
+ }
+
+ /* Ok, return ROR-intersect plan if we have found one */
+ TRP_ROR_INTERSECT *trp= NULL;
+ if (min_cost < read_time && (cpk_scan_used || best_num > 1))
+ {
+ if (!(trp= new (param->mem_root) TRP_ROR_INTERSECT))
+ DBUG_RETURN(trp);
+ if (!(trp->first_scan=
+ (ROR_SCAN_INFO**)alloc_root(param->mem_root,
+ sizeof(ROR_SCAN_INFO*)*best_num)))
+ DBUG_RETURN(NULL);
+ memcpy(trp->first_scan, intersect_scans, best_num*sizeof(ROR_SCAN_INFO*));
+ trp->last_scan= trp->first_scan + best_num;
+ trp->is_covering= intersect_best->is_covering;
+ trp->read_cost= intersect_best->total_cost;
+ /* Prevent divisons by zero */
+ ha_rows best_rows = double2rows(intersect_best->out_rows);
+ if (!best_rows)
+ best_rows= 1;
+ trp->records= best_rows;
+ trp->index_scan_costs= intersect_best->index_scan_costs;
+ trp->cpk_scan= cpk_scan_used? cpk_scan: NULL;
+ DBUG_PRINT("info", ("Returning non-covering ROR-intersect plan:"
+ "cost %g, records %lu",
+ trp->read_cost, (ulong) trp->records));
+ }
+ DBUG_RETURN(trp);
+}
+
+
+/*
+ Get best covering ROR-intersection.
+ SYNOPSIS
+ get_best_covering_ror_intersect()
+ param Parameter from test_quick_select function.
+ tree SEL_TREE with sets of intervals for different keys.
+ read_time Don't return table read plans with cost > read_time.
+
+ RETURN
+ Best covering ROR-intersection plan
+ NULL if no plan found.
+
+ NOTES
+ get_best_ror_intersect must be called for a tree before calling this
+ function for it.
+ This function invalidates tree->ror_scans member values.
+
+ The following approximate algorithm is used:
+ I=set of all covering indexes
+ F=set of all fields to cover
+ S={}
+
+ do {
+ Order I by (#covered fields in F desc,
+ #components asc,
+ number of first not covered component asc);
+ F=F-covered by first(I);
+ S=S+first(I);
+ I=I-first(I);
+ } while F is not empty.
+*/
+
+static
+TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
+ SEL_TREE *tree,
+ double read_time)
+{
+ ROR_SCAN_INFO **ror_scan_mark;
+ ROR_SCAN_INFO **ror_scans_end= tree->ror_scans_end;
+ DBUG_ENTER("get_best_covering_ror_intersect");
+ uint nbits= param->fields_bitmap_size*8;
+
+ for (ROR_SCAN_INFO **scan= tree->ror_scans; scan != ror_scans_end; ++scan)
+ (*scan)->key_components=
+ param->table->key_info[(*scan)->keynr].key_parts;
+
+ /*
+ Run covering-ROR-search algorithm.
+ Assume set I is [ror_scan .. ror_scans_end)
+ */
+
+ /*I=set of all covering indexes */
+ ror_scan_mark= tree->ror_scans;
+
+ uchar buf[MAX_KEY/8+1];
+ MY_BITMAP covered_fields;
+ if (bitmap_init(&covered_fields, buf, nbits, FALSE))
+ DBUG_RETURN(0);
+ bitmap_clear_all(&covered_fields);
+
+ double total_cost= 0.0f;
+ ha_rows records=0;
+ bool all_covered;
+
+ DBUG_PRINT("info", ("Building covering ROR-intersection"));
+ DBUG_EXECUTE("info", print_ror_scans_arr(param->table,
+ "building covering ROR-I",
+ ror_scan_mark, ror_scans_end););
+ do {
+ /*
+ Update changed sorting info:
+ #covered fields,
+ number of first not covered component
+ Calculate and save these values for each of remaining scans.
+ */
+ for (ROR_SCAN_INFO **scan= ror_scan_mark; scan != ror_scans_end; ++scan)
+ {
+ bitmap_subtract(&(*scan)->covered_fields, &covered_fields);
+ (*scan)->used_fields_covered=
+ bitmap_bits_set(&(*scan)->covered_fields);
+ (*scan)->first_uncovered_field=
+ bitmap_get_first(&(*scan)->covered_fields);
+ }
+
+ qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*),
+ (qsort_cmp)cmp_ror_scan_info_covering);
+
+ DBUG_EXECUTE("info", print_ror_scans_arr(param->table,
+ "remaining scans",
+ ror_scan_mark, ror_scans_end););
+
+ /* I=I-first(I) */
+ total_cost += (*ror_scan_mark)->index_read_cost;
+ records += (*ror_scan_mark)->records;
+ DBUG_PRINT("info", ("Adding scan on %s",
+ param->table->key_info[(*ror_scan_mark)->keynr].name));
+ if (total_cost > read_time)
+ DBUG_RETURN(NULL);
+ /* F=F-covered by first(I) */
+ bitmap_union(&covered_fields, &(*ror_scan_mark)->covered_fields);
+ all_covered= bitmap_is_subset(&param->needed_fields, &covered_fields);
+ } while (!all_covered && (++ror_scan_mark < ror_scans_end));
+
+ if (!all_covered)
+ DBUG_RETURN(NULL); /* should not happen actually */
+
+ /*
+ Ok, [tree->ror_scans .. ror_scan) holds covering index_intersection with
+ cost total_cost.
+ */
+ DBUG_PRINT("info", ("Covering ROR-intersect scans cost: %g", total_cost));
+ DBUG_EXECUTE("info", print_ror_scans_arr(param->table,
+ "creating covering ROR-intersect",
+ tree->ror_scans, ror_scan_mark););
+
+ /* Add priority queue use cost. */
+ total_cost += rows2double(records)*
+ log((double)(ror_scan_mark - tree->ror_scans)) /
+ (TIME_FOR_COMPARE_ROWID * M_LN2);
+ DBUG_PRINT("info", ("Covering ROR-intersect full cost: %g", total_cost));
+
+ if (total_cost > read_time)
+ DBUG_RETURN(NULL);
+
+ TRP_ROR_INTERSECT *trp;
+ if (!(trp= new (param->mem_root) TRP_ROR_INTERSECT))
+ DBUG_RETURN(trp);
+ uint best_num= (ror_scan_mark - tree->ror_scans);
+ if (!(trp->first_scan= (ROR_SCAN_INFO**)alloc_root(param->mem_root,
+ sizeof(ROR_SCAN_INFO*)*
+ best_num)))
+ DBUG_RETURN(NULL);
+ memcpy(trp->first_scan, ror_scan_mark, best_num*sizeof(ROR_SCAN_INFO*));
+ trp->last_scan= trp->first_scan + best_num;
+ trp->is_covering= TRUE;
+ trp->read_cost= total_cost;
+ trp->records= records;
+
+ DBUG_PRINT("info",
+ ("Returning covering ROR-intersect plan: cost %g, records %lu",
+ trp->read_cost, (ulong) trp->records));
+ DBUG_RETURN(trp);
+}
+
+
+/*
+ Get best "range" table read plan for given SEL_TREE.
+ Also update PARAM members and store ROR scans info in the SEL_TREE.
+ SYNOPSIS
+ get_key_scans_params
+ param parameters from test_quick_select
+ tree make range select for this SEL_TREE
+ index_read_must_be_used if TRUE, assume 'index only' option will be set
+ (except for clustered PK indexes)
+ read_time don't create read plans with cost > read_time.
+ RETURN
+ Best range read plan
+ NULL if no plan found or error occurred
+*/
+
+static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
+ bool index_read_must_be_used,
+ double read_time)
+{
+ int idx;
+ SEL_ARG **key,**end, **key_to_read= NULL;
+ ha_rows best_records;
+ TRP_RANGE* read_plan= NULL;
+ bool pk_is_clustered= param->table->file->primary_key_is_clustered();
+ DBUG_ENTER("get_key_scans_params");
+ LINT_INIT(best_records); /* protected by key_to_read */
+ /*
+ Note that there may be trees that have type SEL_TREE::KEY but contain no
+ key reads at all, e.g. tree for expression "key1 is not null" where key1
+ is defined as "not null".
+ */
+ DBUG_EXECUTE("info", print_sel_tree(param, tree, &tree->keys_map,
+ "tree scans"););
+ tree->ror_scans_map.clear_all();
+ tree->n_ror_scans= 0;
+ for (idx= 0,key=tree->keys, end=key+param->keys;
+ key != end ;
+ key++,idx++)
+ {
+ ha_rows found_records;
+ double found_read_time;
+ if (*key)
+ {
+ uint keynr= param->real_keynr[idx];
+ if ((*key)->type == SEL_ARG::MAYBE_KEY ||
+ (*key)->maybe_flag)
+ param->needed_reg->set_bit(keynr);
+
+ bool read_index_only= index_read_must_be_used ? TRUE :
+ (bool) param->table->used_keys.is_set(keynr);
+
+ found_records= check_quick_select(param, idx, *key);
+ if (param->is_ror_scan)
+ {
+ tree->n_ror_scans++;
+ tree->ror_scans_map.set_bit(idx);
+ }
+ double cpu_cost= (double) found_records / TIME_FOR_COMPARE;
+ if (found_records != HA_POS_ERROR && found_records > 2 &&
+ read_index_only &&
+ (param->table->file->index_flags(keynr, param->max_key_part,1) &
+ HA_KEYREAD_ONLY) &&
+ !(pk_is_clustered && keynr == param->table->s->primary_key))
+ {
+ /*
+ We can resolve this by only reading through this key.
+ 0.01 is added to avoid races between range and 'index' scan.
+ */
+ found_read_time= get_index_only_read_time(param,found_records,keynr) +
+ cpu_cost + 0.01;
+ }
+ else
+ {
+ /*
+ cost(read_through_index) = cost(disk_io) + cost(row_in_range_checks)
+ The row_in_range check is in QUICK_RANGE_SELECT::cmp_next function.
+ */
+ found_read_time= param->table->file->read_time(keynr,
+ param->range_count,
+ found_records) +
+ cpu_cost + 0.01;
+ }
+ DBUG_PRINT("info",("key %s: found_read_time: %g (cur. read_time: %g)",
+ param->table->key_info[keynr].name, found_read_time,
+ read_time));
+
+ if (read_time > found_read_time && found_records != HA_POS_ERROR
+ /*|| read_time == DBL_MAX*/ )
+ {
+ read_time= found_read_time;
+ best_records= found_records;
+ key_to_read= key;
+ }
+
+ }
+ }
+
+ DBUG_EXECUTE("info", print_sel_tree(param, tree, &tree->ror_scans_map,
+ "ROR scans"););
+ if (key_to_read)
+ {
+ idx= key_to_read - tree->keys;
+ if ((read_plan= new (param->mem_root) TRP_RANGE(*key_to_read, idx)))
+ {
+ read_plan->records= best_records;
+ read_plan->is_ror= tree->ror_scans_map.is_set(idx);
+ read_plan->read_cost= read_time;
+ DBUG_PRINT("info",
+ ("Returning range plan for key %s, cost %g, records %lu",
+ param->table->key_info[param->real_keynr[idx]].name,
+ read_plan->read_cost, (ulong) read_plan->records));
+ }
+ }
+ else
+ DBUG_PRINT("info", ("No 'range' table read plan found"));
+
+ DBUG_RETURN(read_plan);
+}
+
+
+QUICK_SELECT_I *TRP_INDEX_MERGE::make_quick(PARAM *param,
+ bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc)
+{
+ QUICK_INDEX_MERGE_SELECT *quick_imerge;
+ QUICK_RANGE_SELECT *quick;
+ /* index_merge always retrieves full rows, ignore retrieve_full_rows */
+ if (!(quick_imerge= new QUICK_INDEX_MERGE_SELECT(param->thd, param->table)))
+ return NULL;
+
+ quick_imerge->records= records;
+ quick_imerge->read_time= read_cost;
+ for(TRP_RANGE **range_scan= range_scans; range_scan != range_scans_end;
+ range_scan++)
+ {
+ if (!(quick= (QUICK_RANGE_SELECT*)
+ ((*range_scan)->make_quick(param, FALSE, &quick_imerge->alloc)))||
+ quick_imerge->push_quick_back(quick))
+ {
+ delete quick;
+ delete quick_imerge;
+ return NULL;
+ }
+ }
+ return quick_imerge;
+}
+
+QUICK_SELECT_I *TRP_ROR_INTERSECT::make_quick(PARAM *param,
+ bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc)
+{
+ QUICK_ROR_INTERSECT_SELECT *quick_intrsect;
+ QUICK_RANGE_SELECT *quick;
+ DBUG_ENTER("TRP_ROR_INTERSECT::make_quick");
+ MEM_ROOT *alloc;
+
+ if ((quick_intrsect=
+ new QUICK_ROR_INTERSECT_SELECT(param->thd, param->table,
+ retrieve_full_rows? (!is_covering):FALSE,
+ parent_alloc)))
+ {
+ DBUG_EXECUTE("info", print_ror_scans_arr(param->table,
+ "creating ROR-intersect",
+ first_scan, last_scan););
+ alloc= parent_alloc? parent_alloc: &quick_intrsect->alloc;
+ for(; first_scan != last_scan;++first_scan)
+ {
+ if (!(quick= get_quick_select(param, (*first_scan)->idx,
+ (*first_scan)->sel_arg, alloc)) ||
+ quick_intrsect->push_quick_back(quick))
+ {
+ delete quick_intrsect;
+ DBUG_RETURN(NULL);
+ }
+ }
+ if (cpk_scan)
+ {
+ if (!(quick= get_quick_select(param, cpk_scan->idx,
+ cpk_scan->sel_arg, alloc)))
+ {
+ delete quick_intrsect;
+ DBUG_RETURN(NULL);
+ }
+ quick->file= NULL;
+ quick_intrsect->cpk_quick= quick;
+ }
+ quick_intrsect->records= records;
+ quick_intrsect->read_time= read_cost;
+ }
+ DBUG_RETURN(quick_intrsect);
+}
+
+
+QUICK_SELECT_I *TRP_ROR_UNION::make_quick(PARAM *param,
+ bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc)
+{
+ QUICK_ROR_UNION_SELECT *quick_roru;
+ TABLE_READ_PLAN **scan;
+ QUICK_SELECT_I *quick;
+ DBUG_ENTER("TRP_ROR_UNION::make_quick");
+ /*
+ It is impossible to construct a ROR-union that will not retrieve full
+ rows, ignore retrieve_full_rows parameter.
+ */
+ if ((quick_roru= new QUICK_ROR_UNION_SELECT(param->thd, param->table)))
+ {
+ for(scan= first_ror; scan != last_ror; scan++)
+ {
+ if (!(quick= (*scan)->make_quick(param, FALSE, &quick_roru->alloc)) ||
+ quick_roru->push_quick_back(quick))
+ DBUG_RETURN(NULL);
+ }
+ quick_roru->records= records;
+ quick_roru->read_time= read_cost;
+ }
+ DBUG_RETURN(quick_roru);
+}
+
+
+/*
+ Build a SEL_TREE for a simple predicate
+
+ SYNOPSIS
+ get_func_mm_tree()
+ param PARAM from SQL_SELECT::test_quick_select
+ cond_func item for the predicate
+ field field in the predicate
+ value constant in the predicate
+ cmp_type compare type for the field
+
+ RETURN
+ Pointer to thre built tree
+*/
+
+static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
+ Field *field, Item *value,
+ Item_result cmp_type)
+{
+ SEL_TREE *tree= 0;
+ DBUG_ENTER("get_func_mm_tree");
+
+ switch (cond_func->functype()) {
+ case Item_func::NE_FUNC:
+ tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
+ value, cmp_type);
+ if (tree)
+ {
+ tree= tree_or(param, tree, get_mm_parts(param, cond_func, field,
+ Item_func::GT_FUNC,
+ value, cmp_type));
+ }
+ break;
+ case Item_func::BETWEEN:
+ tree= get_mm_parts(param, cond_func, field, Item_func::GE_FUNC,
+ cond_func->arguments()[1],cmp_type);
+ if (tree)
+ {
+ tree= tree_and(param, tree, get_mm_parts(param, cond_func, field,
+ Item_func::LE_FUNC,
+ cond_func->arguments()[2],
+ cmp_type));
+ }
+ break;
+ case Item_func::IN_FUNC:
+ {
+ Item_func_in *func=(Item_func_in*) cond_func;
+ tree= get_mm_parts(param, cond_func, field, Item_func::EQ_FUNC,
+ func->arguments()[1], cmp_type);
+ if (tree)
+ {
+ Item **arg, **end;
+ for (arg= func->arguments()+2, end= arg+func->argument_count()-2;
+ arg < end ; arg++)
+ {
+ tree= tree_or(param, tree, get_mm_parts(param, cond_func, field,
+ Item_func::EQ_FUNC,
+ *arg,
+ cmp_type));
+ }
+ }
+ break;
+ }
+ default:
+ {
+ /*
+ Here the function for the following predicates are processed:
+ <, <=, =, >=, >, LIKE, IS NULL, IS NOT NULL.
+ If the predicate is of the form (value op field) it is handled
+ as the equivalent predicate (field rev_op value), e.g.
+ 2 <= a is handled as a >= 2.
+ */
+ Item_func::Functype func_type=
+ (value != cond_func->arguments()[0]) ? cond_func->functype() :
+ ((Item_bool_func2*) cond_func)->rev_functype();
+ tree= get_mm_parts(param, cond_func, field, func_type, value, cmp_type);
+ }
+ }
+
+ DBUG_RETURN(tree);
+
+}
+
/* make a select tree of all keys in condition */
static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
{
SEL_TREE *tree=0;
+ SEL_TREE *ftree= 0;
+ Item_field *field_item= 0;
+ Item *value;
DBUG_ENTER("get_mm_tree");
if (cond->type() == Item::COND_ITEM)
@@ -832,9 +3444,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
DBUG_RETURN(new SEL_TREE(SEL_TREE::IMPOSSIBLE));
}
- table_map ref_tables=cond->used_tables();
+ table_map ref_tables= 0;
+ table_map param_comp= ~(param->prev_tables | param->read_tables |
+ param->current_table);
if (cond->type() != Item::FUNC_ITEM)
{ // Should be a field
+ ref_tables= cond->used_tables();
if ((ref_tables & param->current_table) ||
(ref_tables & ~(param->prev_tables | param->read_tables)))
DBUG_RETURN(0);
@@ -847,97 +3462,111 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
param->cond= cond;
- if (cond_func->functype() == Item_func::BETWEEN)
+ switch (cond_func->functype()) {
+ case Item_func::BETWEEN:
+ if (cond_func->arguments()[0]->type() != Item::FIELD_ITEM)
+ DBUG_RETURN(0);
+ field_item= (Item_field*) (cond_func->arguments()[0]);
+ value= NULL;
+ break;
+ case Item_func::IN_FUNC:
+ {
+ Item_func_in *func=(Item_func_in*) cond_func;
+ if (func->key_item()->type() != Item::FIELD_ITEM)
+ DBUG_RETURN(0);
+ field_item= (Item_field*) (func->key_item());
+ value= NULL;
+ break;
+ }
+ case Item_func::MULT_EQUAL_FUNC:
{
+ Item_equal *item_equal= (Item_equal *) cond;
+ if (!(value= item_equal->get_const()))
+ DBUG_RETURN(0);
+ Item_equal_iterator it(*item_equal);
+ ref_tables= value->used_tables();
+ while ((field_item= it++))
+ {
+ Field *field= field_item->field;
+ Item_result cmp_type= field->cmp_type();
+ if (!((ref_tables | field->table->map) & param_comp))
+ {
+ tree= get_mm_parts(param, cond, field, Item_func::EQ_FUNC,
+ value,cmp_type);
+ ftree= !ftree ? tree : tree_and(param, ftree, tree);
+ }
+ }
+
+ DBUG_RETURN(ftree);
+ }
+ default:
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
{
- Field *field=((Item_field*) (cond_func->arguments()[0]))->field;
- Item_result cmp_type=field->cmp_type();
- DBUG_RETURN(tree_and(param,
- get_mm_parts(param, cond_func, field,
- Item_func::GE_FUNC,
- cond_func->arguments()[1], cmp_type),
- get_mm_parts(param, cond_func, field,
- Item_func::LE_FUNC,
- cond_func->arguments()[2], cmp_type)));
+ field_item= (Item_field*) (cond_func->arguments()[0]);
+ value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : 0;
}
- DBUG_RETURN(0);
+ else if (cond_func->have_rev_func() &&
+ cond_func->arguments()[1]->type() == Item::FIELD_ITEM)
+ {
+ field_item= (Item_field*) (cond_func->arguments()[1]);
+ value= cond_func->arguments()[0];
+ }
+ else
+ DBUG_RETURN(0);
}
- if (cond_func->functype() == Item_func::IN_FUNC)
- { // COND OR
- Item_func_in *func=(Item_func_in*) cond_func;
- if (func->key_item()->type() == Item::FIELD_ITEM)
- {
- Field *field=((Item_field*) (func->key_item()))->field;
- Item_result cmp_type=field->cmp_type();
- tree= get_mm_parts(param,cond_func,field,Item_func::EQ_FUNC,
- func->arguments()[1],cmp_type);
- if (!tree)
- DBUG_RETURN(tree); // Not key field
- for (uint i=2 ; i < func->argument_count(); i++)
- {
- SEL_TREE *new_tree=get_mm_parts(param,cond_func,field,
- Item_func::EQ_FUNC,
- func->arguments()[i],cmp_type);
- tree=tree_or(param,tree,new_tree);
- }
- DBUG_RETURN(tree);
- }
- DBUG_RETURN(0); // Can't optimize this IN
- }
-
- if (ref_tables & ~(param->prev_tables | param->read_tables |
- param->current_table))
- DBUG_RETURN(0); // Can't be calculated yet
- if (!(ref_tables & param->current_table))
- DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); // This may be false or true
-
- /* check field op const */
- /* btw, ft_func's arguments()[0] isn't FIELD_ITEM. SerG*/
- if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
- {
- tree= get_mm_parts(param, cond_func,
- ((Item_field*) (cond_func->arguments()[0]))->field,
- cond_func->functype(),
- cond_func->arg_count > 1 ? cond_func->arguments()[1] :
- 0,
- ((Item_field*) (cond_func->arguments()[0]))->field->
- cmp_type());
- }
- /* check const op field */
- if (!tree &&
- cond_func->have_rev_func() &&
- cond_func->arguments()[1]->type() == Item::FIELD_ITEM)
- {
- DBUG_RETURN(get_mm_parts(param, cond_func,
- ((Item_field*)
- (cond_func->arguments()[1]))->field,
- ((Item_bool_func2*) cond_func)->rev_functype(),
- cond_func->arguments()[0],
- ((Item_field*)
- (cond_func->arguments()[1]))->field->cmp_type()
- ));
+
+ /*
+ If the where condition contains a predicate (ti.field op const),
+ then not only SELL_TREE for this predicate is built, but
+ the trees for the results of substitution of ti.field for
+ each tj.field belonging to the same multiple equality as ti.field
+ are built as well.
+ E.g. for WHERE t1.a=t2.a AND t2.a > 10
+ a SEL_TREE for t2.a > 10 will be built for quick select from t2
+ and
+ a SEL_TREE for t1.a > 10 will be built for quick select from t1.
+ */
+
+ for (uint i= 0; i < cond_func->arg_count; i++)
+ {
+ Item *arg= cond_func->arguments()[i];
+ if (arg != field_item)
+ ref_tables|= arg->used_tables();
}
- DBUG_RETURN(tree);
+ Field *field= field_item->field;
+ Item_result cmp_type= field->cmp_type();
+ if (!((ref_tables | field->table->map) & param_comp))
+ ftree= get_func_mm_tree(param, cond_func, field, value, cmp_type);
+ Item_equal *item_equal= field_item->item_equal;
+ if (item_equal)
+ {
+ Item_equal_iterator it(*item_equal);
+ Item_field *item;
+ while ((item= it++))
+ {
+ Field *f= item->field;
+ if (field->eq(f))
+ continue;
+ if (!((ref_tables | f->table->map) & param_comp))
+ {
+ tree= get_func_mm_tree(param, cond_func, f, value, cmp_type);
+ ftree= !ftree ? tree : tree_and(param, ftree, tree);
+ }
+ }
+ }
+ DBUG_RETURN(ftree);
}
static SEL_TREE *
get_mm_parts(PARAM *param, COND *cond_func, Field *field,
- Item_func::Functype type,
+ Item_func::Functype type,
Item *value, Item_result cmp_type)
{
- bool ne_func= FALSE;
DBUG_ENTER("get_mm_parts");
if (field->table != param->table)
DBUG_RETURN(0);
- if (type == Item_func::NE_FUNC)
- {
- ne_func= TRUE;
- type= Item_func::LT_FUNC;
- }
-
KEY_PART *key_part = param->key_parts;
KEY_PART *end = param->key_parts_end;
SEL_TREE *tree=0;
@@ -966,22 +3595,15 @@ get_mm_parts(PARAM *param, COND *cond_func, Field *field,
else
{
// This key may be used later
- if (!(sel_arg= new SEL_ARG(SEL_ARG::MAYBE_KEY)))
+ if (!(sel_arg= new SEL_ARG(SEL_ARG::MAYBE_KEY)))
DBUG_RETURN(0); // OOM
}
sel_arg->part=(uchar) key_part->part;
tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg);
+ tree->keys_map.set_bit(key_part->key);
}
}
- if (ne_func)
- {
- SEL_TREE *tree2= get_mm_parts(param, cond_func,
- field, Item_func::GT_FUNC,
- value, cmp_type);
- if (tree2)
- tree= tree_or(param,tree,tree2);
- }
DBUG_RETURN(tree);
}
@@ -990,15 +3612,15 @@ static SEL_ARG *
get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
Item_func::Functype type,Item *value)
{
- uint maybe_null=(uint) field->real_maybe_null(), copies;
- uint field_length=field->pack_length()+maybe_null;
+ uint maybe_null=(uint) field->real_maybe_null();
+ bool optimize_range;
SEL_ARG *tree;
- char *str, *str2;
+ char *str;
DBUG_ENTER("get_mm_leaf");
if (!value) // IS NULL or IS NOT NULL
{
- if (field->table->outer_join) // Can't use a key on this
+ if (field->table->maybe_null) // Can't use a key on this
DBUG_RETURN(0);
if (!maybe_null) // Not null field
DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0);
@@ -1031,15 +3653,18 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
!(conf_func->compare_collation()->state & MY_CS_BINSORT))
DBUG_RETURN(0);
+ optimize_range= field->optimize_range(param->real_keynr[key_part->key],
+ key_part->part);
+
if (type == Item_func::LIKE_FUNC)
{
bool like_error;
char buff1[MAX_FIELD_WIDTH],*min_str,*max_str;
String tmp(buff1,sizeof(buff1),value->collation.collation),*res;
uint length,offset,min_length,max_length;
+ uint field_length= field->pack_length()+maybe_null;
- if (!field->optimize_range(param->real_keynr[key_part->key],
- key_part->part))
+ if (!optimize_range)
DBUG_RETURN(0); // Can't optimize this
if (!(res= value->val_str(&tmp)))
DBUG_RETURN(&null_element);
@@ -1082,21 +3707,23 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
length+=offset;
if (!(min_str= (char*) alloc_root(param->mem_root, length*2)))
DBUG_RETURN(0);
+
max_str=min_str+length;
if (maybe_null)
max_str[0]= min_str[0]=0;
+ field_length-= maybe_null;
like_error= my_like_range(field->charset(),
res->ptr(), res->length(),
((Item_func_like*)(param->cond))->escape,
wild_one, wild_many,
- field_length-maybe_null,
+ field_length,
min_str+offset, max_str+offset,
&min_length, &max_length);
if (like_error) // Can't optimize with LIKE
DBUG_RETURN(0);
- if (offset != maybe_null) // Blob
+ if (offset != maybe_null) // BLOB or VARCHAR
{
int2store(min_str+maybe_null,min_length);
int2store(max_str+maybe_null,max_length);
@@ -1104,8 +3731,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
DBUG_RETURN(new SEL_ARG(field,min_str,max_str));
}
- if (!field->optimize_range(param->real_keynr[key_part->key],
- key_part->part) &&
+ if (!optimize_range &&
type != Item_func::EQ_FUNC &&
type != Item_func::EQUAL_FUNC)
DBUG_RETURN(0); // Can't optimize this
@@ -1118,45 +3744,19 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
value->result_type() != STRING_RESULT &&
field->cmp_type() != value->result_type())
DBUG_RETURN(0);
-
- if (value->save_in_field(field, 1) < 0)
+
+ 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
- }
- /* Get local copy of key */
- copies= 1;
- if (field->key_type() == HA_KEYTYPE_VARTEXT)
- copies= 2;
- str= str2= (char*) alloc_root(param->mem_root,
- (key_part->store_length)*copies+1);
+ DBUG_RETURN(&null_element); // cmp with NULL is never TRUE
+ }
+ str= (char*) alloc_root(param->mem_root, key_part->store_length+1);
if (!str)
DBUG_RETURN(0);
if (maybe_null)
*str= (char) field->is_real_null(); // Set to 1 if null
- field->get_key_image(str+maybe_null, key_part->length,
- field->charset(), key_part->image_type);
- if (copies == 2)
- {
- /*
- The key is stored as 2 byte length + key
- key doesn't match end space. In other words, a key 'X ' should match
- all rows between 'X' and 'X ...'
- */
- uint length= uint2korr(str+maybe_null);
- str2= str+ key_part->store_length;
- /* remove end space */
- while (length > 0 && str[length+HA_KEY_BLOB_LENGTH+maybe_null-1] == ' ')
- length--;
- int2store(str+maybe_null, length);
- /* Create key that is space filled */
- memcpy(str2, str, length + HA_KEY_BLOB_LENGTH + maybe_null);
- my_fill_8bit(field->charset(),
- str2+ length+ HA_KEY_BLOB_LENGTH +maybe_null,
- key_part->length-length, ' ');
- int2store(str2+maybe_null, key_part->length);
- }
- if (!(tree=new SEL_ARG(field,str,str2)))
+ 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
switch (type) {
@@ -1227,8 +3827,8 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
** If tree is 0 it means that the condition can't be tested. It refers
** to a non existent table or to a field in current table with isn't a key.
** The different tree flags:
-** IMPOSSIBLE: Condition is never true
-** ALWAYS: Condition is always true
+** IMPOSSIBLE: Condition is never TRUE
+** ALWAYS: Condition is always TRUE
** MAYBE: Condition may exists when tables are read
** MAYBE_KEY: Condition refers to a key that may be used in join loop
** KEY_RANGE: Condition uses a key
@@ -1298,6 +3898,8 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
DBUG_RETURN(tree1);
}
+ key_map result_keys;
+ result_keys.clear_all();
/* Join the trees key per key */
SEL_ARG **key1,**key2,**end;
for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ;
@@ -1314,17 +3916,60 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE)
{
tree1->type= SEL_TREE::IMPOSSIBLE;
+ DBUG_RETURN(tree1);
+ }
+ result_keys.set_bit(key1 - tree1->keys);
#ifdef EXTRA_DEBUG
+ if (*key1)
(*key1)->test_use_count(*key1);
#endif
- break;
- }
}
}
+ tree1->keys_map= result_keys;
+ /* dispose index_merge if there is a "range" option */
+ if (!result_keys.is_clear_all())
+ {
+ tree1->merges.empty();
+ DBUG_RETURN(tree1);
+ }
+
+ /* ok, both trees are index_merge trees */
+ imerge_list_and_list(&tree1->merges, &tree2->merges);
DBUG_RETURN(tree1);
}
+/*
+ Check if two SEL_TREES can be combined into one (i.e. a single key range
+ read can be constructed for "cond_of_tree1 OR cond_of_tree2" ) without
+ using index_merge.
+*/
+
+bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, PARAM* param)
+{
+ key_map common_keys= tree1->keys_map;
+ DBUG_ENTER("sel_trees_can_be_ored");
+ common_keys.intersect(tree2->keys_map);
+
+ if (common_keys.is_clear_all())
+ DBUG_RETURN(FALSE);
+
+ /* trees have a common key, check if they refer to same key part */
+ SEL_ARG **key1,**key2;
+ for (uint key_no=0; key_no < param->keys; key_no++)
+ {
+ if (common_keys.is_set(key_no))
+ {
+ key1= tree1->keys + key_no;
+ key2= tree2->keys + key_no;
+ if ((*key1)->part == (*key2)->part)
+ {
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+ DBUG_RETURN(FALSE);
+}
static SEL_TREE *
tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
@@ -1341,19 +3986,62 @@ tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
if (tree2->type == SEL_TREE::MAYBE)
DBUG_RETURN(tree2);
- /* Join the trees key per key */
- SEL_ARG **key1,**key2,**end;
- SEL_TREE *result=0;
- for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ;
- key1 != end ; key1++,key2++)
+ SEL_TREE *result= 0;
+ key_map result_keys;
+ result_keys.clear_all();
+ if (sel_trees_can_be_ored(tree1, tree2, param))
{
- *key1=key_or(*key1,*key2);
- if (*key1)
+ /* Join the trees key per key */
+ SEL_ARG **key1,**key2,**end;
+ for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ;
+ key1 != end ; key1++,key2++)
{
- result=tree1; // Added to tree1
+ *key1=key_or(*key1,*key2);
+ if (*key1)
+ {
+ result=tree1; // Added to tree1
+ result_keys.set_bit(key1 - tree1->keys);
#ifdef EXTRA_DEBUG
- (*key1)->test_use_count(*key1);
+ (*key1)->test_use_count(*key1);
#endif
+ }
+ }
+ if (result)
+ result->keys_map= result_keys;
+ }
+ else
+ {
+ /* ok, two trees have KEY type but cannot be used without index merge */
+ if (tree1->merges.is_empty() && tree2->merges.is_empty())
+ {
+ SEL_IMERGE *merge;
+ /* both trees are "range" trees, produce new index merge structure */
+ if (!(result= new SEL_TREE()) || !(merge= new SEL_IMERGE()) ||
+ (result->merges.push_back(merge)) ||
+ (merge->or_sel_tree(param, tree1)) ||
+ (merge->or_sel_tree(param, tree2)))
+ result= NULL;
+ else
+ result->type= tree1->type;
+ }
+ else if (!tree1->merges.is_empty() && !tree2->merges.is_empty())
+ {
+ if (imerge_list_or_list(param, &tree1->merges, &tree2->merges))
+ result= new SEL_TREE(SEL_TREE::ALWAYS);
+ else
+ result= tree1;
+ }
+ else
+ {
+ /* one tree is index merge tree and another is range tree */
+ if (tree1->merges.is_empty())
+ swap_variables(SEL_TREE*, tree1, tree2);
+
+ /* add tree2 to tree1->merges, checking if it collapses to ALWAYS */
+ if (imerge_list_or_tree(param, &tree1->merges, tree2))
+ result= new SEL_TREE(SEL_TREE::ALWAYS);
+ else
+ result= tree1;
}
}
DBUG_RETURN(result);
@@ -1402,7 +4090,6 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
}
-
static SEL_ARG *
key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
{
@@ -1472,6 +4159,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
return 0; // Can't optimize this
}
+ if ((key1->min_flag | key2->min_flag) & GEOM_FLAG)
+ {
+ key1->free_tree();
+ key2->free_tree();
+ return 0; // Can't optimize this
+ }
+
key1->use_count--;
key2->use_count--;
SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0;
@@ -1896,7 +4590,7 @@ SEL_ARG::find_range(SEL_ARG *key)
SYNOPSIS
tree_delete()
key Key that is to be deleted from tree (this)
-
+
NOTE
This also frees all sub trees that is used by the element
@@ -2143,7 +4837,7 @@ SEL_ARG *rb_delete_fixup(SEL_ARG *root,SEL_ARG *key,SEL_ARG *par)
}
- /* Test that the proporties for a red-black tree holds */
+ /* Test that the properties for a red-black tree hold */
#ifdef EXTRA_DEBUG
int test_rb_tree(SEL_ARG *element,SEL_ARG *parent)
@@ -2216,7 +4910,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
ulong count=count_key_part_usage(root,pos->next_key_part);
if (count > pos->next_key_part->use_count)
{
- sql_print_information("Use_count: Wrong count for key at %lx, %lu should be %lu",
+ sql_print_information("Use_count: Wrong count for key at 0x%lx, %lu should be %lu",
pos,pos->next_key_part->use_count,count);
return;
}
@@ -2224,68 +4918,167 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
}
}
if (e_count != elements)
- sql_print_warning("Wrong use count: %u (should be %u) for tree at %lx",
+ sql_print_warning("Wrong use count: %u (should be %u) for tree at 0x%lx",
e_count, elements, (gptr) this);
}
#endif
+/*
+ Calculate estimate of number records that will be retrieved by a range
+ scan on given index using given SEL_ARG intervals tree.
+ SYNOPSIS
+ check_quick_select
+ param Parameter from test_quick_select
+ idx Number of index to use in PARAM::key SEL_TREE::key
+ tree Transformed selection condition, tree->key[idx] holds intervals
+ tree to be used for scanning.
+ NOTES
+ param->is_ror_scan is set to reflect if the key scan is a ROR (see
+ is_key_scan_ror function for more info)
+ param->table->quick_*, param->range_count (and maybe others) are
+ updated with data of given key scan, see check_quick_keys for details.
-/*****************************************************************************
-** Check how many records we will find by using the found tree
-*****************************************************************************/
+ RETURN
+ Estimate # of records to be retrieved.
+ HA_POS_ERROR if estimate calculation failed due to table handler problems.
+
+*/
static ha_rows
check_quick_select(PARAM *param,uint idx,SEL_ARG *tree)
{
ha_rows records;
+ bool cpk_scan;
+ uint key;
DBUG_ENTER("check_quick_select");
+ param->is_ror_scan= FALSE;
+
if (!tree)
DBUG_RETURN(HA_POS_ERROR); // Can't use it
param->max_key_part=0;
param->range_count=0;
+ key= param->real_keynr[idx];
+
if (tree->type == SEL_ARG::IMPOSSIBLE)
DBUG_RETURN(0L); // Impossible select. return
if (tree->type != SEL_ARG::KEY_RANGE || tree->part != 0)
DBUG_RETURN(HA_POS_ERROR); // Don't use tree
+
+ enum ha_key_alg key_alg= param->table->key_info[key].algorithm;
+ if ((key_alg != HA_KEY_ALG_BTREE) && (key_alg!= HA_KEY_ALG_UNDEF))
+ {
+ /* Records are not ordered by rowid for other types of indexes. */
+ cpk_scan= FALSE;
+ }
+ else
+ {
+ /*
+ Clustered PK scan is a special case, check_quick_keys doesn't recognize
+ CPK scans as ROR scans (while actually any CPK scan is a ROR scan).
+ */
+ cpk_scan= ((param->table->s->primary_key == param->real_keynr[idx]) &&
+ param->table->file->primary_key_is_clustered());
+ param->is_ror_scan= !cpk_scan;
+ }
+
records=check_quick_keys(param,idx,tree,param->min_key,0,param->max_key,0);
if (records != HA_POS_ERROR)
{
- uint key=param->real_keynr[idx];
param->table->quick_keys.set_bit(key);
param->table->quick_rows[key]=records;
param->table->quick_key_parts[key]=param->max_key_part+1;
+
+ if (cpk_scan)
+ param->is_ror_scan= TRUE;
}
DBUG_PRINT("exit", ("Records: %lu", (ulong) records));
DBUG_RETURN(records);
}
+/*
+ Recursively calculate estimate of # rows that will be retrieved by
+ key scan on key idx.
+ SYNOPSIS
+ check_quick_keys()
+ param Parameter from test_quick select function.
+ idx Number of key to use in PARAM::keys in list of used keys
+ (param->real_keynr[idx] holds the key number in table)
+ key_tree SEL_ARG tree being examined.
+ min_key Buffer with partial min key value tuple
+ min_key_flag
+ max_key Buffer with partial max key value tuple
+ max_key_flag
+
+ NOTES
+ The function does the recursive descent on the tree via SEL_ARG::left,
+ SEL_ARG::right, and SEL_ARG::next_key_part edges. The #rows estimates
+ are calculated using records_in_range calls at the leaf nodes and then
+ summed.
+
+ param->min_key and param->max_key are used to hold prefixes of key value
+ tuples.
+
+ The side effects are:
+
+ param->max_key_part is updated to hold the maximum number of key parts used
+ in scan minus 1.
+
+ param->range_count is incremented if the function finds a range that
+ wasn't counted by the caller.
+
+ param->is_ror_scan is cleared if the function detects that the key scan is
+ not a Rowid-Ordered Retrieval scan ( see comments for is_key_scan_ror
+ function for description of which key scans are ROR scans)
+*/
+
static ha_rows
check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
char *min_key,uint min_key_flag, char *max_key,
uint max_key_flag)
{
- ha_rows records=0,tmp;
+ ha_rows records=0, tmp;
+ uint tmp_min_flag, tmp_max_flag, keynr, min_key_length, max_key_length;
+ char *tmp_min_key, *tmp_max_key;
param->max_key_part=max(param->max_key_part,key_tree->part);
if (key_tree->left != &null_element)
{
+ /*
+ There are at least two intervals for current key part, i.e. condition
+ was converted to something like
+ (keyXpartY less/equals c1) OR (keyXpartY more/equals c2).
+ This is not a ROR scan if the key is not Clustered Primary Key.
+ */
+ param->is_ror_scan= FALSE;
records=check_quick_keys(param,idx,key_tree->left,min_key,min_key_flag,
max_key,max_key_flag);
if (records == HA_POS_ERROR) // Impossible
return records;
}
- uint tmp_min_flag,tmp_max_flag,keynr;
- char *tmp_min_key=min_key,*tmp_max_key=max_key;
-
+ tmp_min_key= min_key;
+ tmp_max_key= max_key;
key_tree->store(param->key[idx][key_tree->part].store_length,
&tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
- uint min_key_length= (uint) (tmp_min_key- param->min_key);
- uint max_key_length= (uint) (tmp_max_key- param->max_key);
+ min_key_length= (uint) (tmp_min_key- param->min_key);
+ max_key_length= (uint) (tmp_max_key- param->max_key);
+
+ if (param->is_ror_scan)
+ {
+ /*
+ If the index doesn't cover entire key, mark the scan as non-ROR scan.
+ Actually we're cutting off some ROR scans here.
+ */
+ uint16 fieldnr= param->table->key_info[param->real_keynr[idx]].
+ key_part[key_tree->part].fieldnr - 1;
+ if (param->table->field[fieldnr]->key_length() !=
+ param->key[idx][key_tree->part].length)
+ param->is_ror_scan= FALSE;
+ }
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
@@ -2300,6 +5093,12 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
tmp_max_key, max_key_flag | key_tree->max_flag);
goto end; // Ugly, but efficient
}
+ else
+ {
+ /* The interval for current key part is not c1 <= keyXpartY <= c1 */
+ param->is_ror_scan= FALSE;
+ }
+
tmp_min_flag=key_tree->min_flag;
tmp_max_flag=key_tree->max_flag;
if (!tmp_min_flag)
@@ -2328,6 +5127,24 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
tmp=1; // Max one record
else
{
+ if (param->is_ror_scan)
+ {
+ /*
+ If we get here, the condition on the key was converted to form
+ "(keyXpart1 = c1) AND ... AND (keyXpart{key_tree->part - 1} = cN) AND
+ somecond(keyXpart{key_tree->part})"
+ Check if
+ somecond is "keyXpart{key_tree->part} = const" and
+ uncovered "tail" of KeyX parts is either empty or is identical to
+ first members of clustered primary key.
+ */
+ if (!(min_key_length == max_key_length &&
+ !memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) &&
+ !key_tree->min_flag && !key_tree->max_flag &&
+ is_key_scan_ror(param, keynr, key_tree->part + 1)))
+ param->is_ror_scan= FALSE;
+ }
+
if (tmp_min_flag & GEOM_FLAG)
{
key_range min_range;
@@ -2364,6 +5181,13 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
records+=tmp;
if (key_tree->right != &null_element)
{
+ /*
+ There are at least two intervals for current key part, i.e. condition
+ was converted to something like
+ (keyXpartY less/equals c1) OR (keyXpartY more/equals c2).
+ This is not a ROR scan if the key is not Clustered Primary Key.
+ */
+ param->is_ror_scan= FALSE;
tmp=check_quick_keys(param,idx,key_tree->right,min_key,min_key_flag,
max_key,max_key_flag);
if (tmp == HA_POS_ERROR)
@@ -2374,22 +5198,110 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
}
-/****************************************************************************
-** change a tree to a structure to be used by quick_select
-** This uses it's own malloc tree
-****************************************************************************/
+/*
+ Check if key scan on given index with equality conditions on first n key
+ parts is a ROR scan.
+
+ SYNOPSIS
+ is_key_scan_ror()
+ param Parameter from test_quick_select
+ keynr Number of key in the table. The key must not be a clustered
+ primary key.
+ nparts Number of first key parts for which equality conditions
+ are present.
+
+ NOTES
+ ROR (Rowid Ordered Retrieval) key scan is a key scan that produces
+ ordered sequence of rowids (ha_xxx::cmp_ref is the comparison function)
+
+ An index scan is a ROR scan if it is done using a condition in form
+
+ "key1_1=c_1 AND ... AND key1_n=c_n" (1)
+
+ where the index is defined on (key1_1, ..., key1_N [,a_1, ..., a_n])
+
+ and the table has a clustered Primary Key
-static QUICK_SELECT *
-get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
+ PRIMARY KEY(a_1, ..., a_n, b1, ..., b_k) with first key parts being
+ identical to uncovered parts ot the key being scanned (2)
+
+ Scans on HASH indexes are not ROR scans,
+ any range scan on clustered primary key is ROR scan (3)
+
+ Check (1) is made in check_quick_keys()
+ Check (3) is made check_quick_select()
+ Check (2) is made by this function.
+
+ RETURN
+ TRUE If the scan is ROR-scan
+ FALSE otherwise
+*/
+
+static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts)
+{
+ KEY *table_key= param->table->key_info + keynr;
+ KEY_PART_INFO *key_part= table_key->key_part + nparts;
+ KEY_PART_INFO *key_part_end= (table_key->key_part +
+ table_key->key_parts);
+ uint pk_number;
+
+ if (key_part == key_part_end)
+ return TRUE;
+ pk_number= param->table->s->primary_key;
+ if (!param->table->file->primary_key_is_clustered() || pk_number == MAX_KEY)
+ return FALSE;
+
+ KEY_PART_INFO *pk_part= param->table->key_info[pk_number].key_part;
+ KEY_PART_INFO *pk_part_end= pk_part +
+ param->table->key_info[pk_number].key_parts;
+ for(;(key_part!=key_part_end) && (pk_part != pk_part_end);
+ ++key_part, ++pk_part)
+ {
+ if ((key_part->field != pk_part->field) ||
+ (key_part->length != pk_part->length))
+ return FALSE;
+ }
+ return (key_part == key_part_end);
+}
+
+
+/*
+ Create a QUICK_RANGE_SELECT from given key and SEL_ARG tree for that key.
+
+ SYNOPSIS
+ get_quick_select()
+ param
+ idx Index of used key in param->key.
+ key_tree SEL_ARG tree for the used key
+ parent_alloc If not NULL, use it to allocate memory for
+ quick select data. Otherwise use quick->alloc.
+ NOTES
+ The caller must call QUICK_SELECT::init for returned quick select
+
+ CAUTION! This function may change thd->mem_root to a MEM_ROOT which will be
+ deallocated when the returned quick select is deleted.
+
+ RETURN
+ NULL on error
+ otherwise created quick select
+*/
+
+QUICK_RANGE_SELECT *
+get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree,
+ MEM_ROOT *parent_alloc)
{
- QUICK_SELECT *quick;
+ QUICK_RANGE_SELECT *quick;
DBUG_ENTER("get_quick_select");
if (param->table->key_info[param->real_keynr[idx]].flags & HA_SPATIAL)
- quick=new QUICK_SELECT_GEOM(param->thd, param->table, param->real_keynr[idx],
- 0);
+ quick=new QUICK_RANGE_SELECT_GEOM(param->thd, param->table,
+ param->real_keynr[idx],
+ test(parent_alloc),
+ parent_alloc);
else
- quick=new QUICK_SELECT(param->thd, param->table, param->real_keynr[idx]);
+ quick=new QUICK_RANGE_SELECT(param->thd, param->table,
+ param->real_keynr[idx],
+ test(parent_alloc));
if (quick)
{
@@ -2403,9 +5315,10 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
else
{
quick->key_parts=(KEY_PART*)
- memdup_root(&quick->alloc,(char*) param->key[idx],
- sizeof(KEY_PART)*
- param->table->key_info[param->real_keynr[idx]].key_parts);
+ memdup_root(parent_alloc? parent_alloc : &quick->alloc,
+ (char*) param->key[idx],
+ sizeof(KEY_PART)*
+ param->table->key_info[param->real_keynr[idx]].key_parts);
}
}
DBUG_RETURN(quick);
@@ -2415,9 +5328,8 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
/*
** Fix this to get all possible sub_ranges
*/
-
-static bool
-get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
+bool
+get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
SEL_ARG *key_tree,char *min_key,uint min_key_flag,
char *max_key, uint max_key_flag)
{
@@ -2513,7 +5425,8 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
set_if_bigger(quick->max_used_key_length,range->min_length);
set_if_bigger(quick->max_used_key_length,range->max_length);
set_if_bigger(quick->used_key_parts, (uint) key_tree->part+1);
- quick->ranges.push_back(range);
+ if (insert_dynamic(&quick->ranges, (gptr)&range))
+ return 1;
end:
if (key_tree->right != &null_element)
@@ -2527,12 +5440,12 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
Return 1 if there is only one range and this uses the whole primary key
*/
-bool QUICK_SELECT::unique_key_range()
+bool QUICK_RANGE_SELECT::unique_key_range()
{
if (ranges.elements == 1)
{
- QUICK_RANGE *tmp;
- if (((tmp=ranges.head())->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE)
+ QUICK_RANGE *tmp= *((QUICK_RANGE**)ranges.buffer);
+ if ((tmp->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE)
{
KEY *key=head->key_info+index;
return ((key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME &&
@@ -2543,11 +5456,11 @@ bool QUICK_SELECT::unique_key_range()
}
-/* Returns true if any part of the key is NULL */
+/* Returns TRUE if any part of the key is NULL */
static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
{
- for (const char *end=key+length ;
+ for (const char *end=key+length ;
key < end;
key+= key_part++->store_length)
{
@@ -2558,15 +5471,60 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
}
+bool QUICK_SELECT_I::check_if_keys_used(List<Item> *fields)
+{
+ return check_if_key_used(head, index, *fields);
+}
+
+bool QUICK_INDEX_MERGE_SELECT::check_if_keys_used(List<Item> *fields)
+{
+ QUICK_RANGE_SELECT *quick;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ while ((quick= it++))
+ {
+ if (check_if_key_used(head, quick->index, *fields))
+ return 1;
+ }
+ return 0;
+}
+
+bool QUICK_ROR_INTERSECT_SELECT::check_if_keys_used(List<Item> *fields)
+{
+ QUICK_RANGE_SELECT *quick;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ while ((quick= it++))
+ {
+ if (check_if_key_used(head, quick->index, *fields))
+ return 1;
+ }
+ return 0;
+}
+
+bool QUICK_ROR_UNION_SELECT::check_if_keys_used(List<Item> *fields)
+{
+ QUICK_SELECT_I *quick;
+ List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
+ while ((quick= it++))
+ {
+ if (quick->check_if_keys_used(fields))
+ return 1;
+ }
+ return 0;
+}
+
+
/****************************************************************************
Create a QUICK RANGE based on a key
+ This allocates things in a new memory root, as this may be called many times
+ during a query.
****************************************************************************/
-QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
+QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
+ TABLE_REF *ref)
{
MEM_ROOT *old_root= thd->mem_root;
/* The following call may change thd->mem_root */
- QUICK_SELECT *quick= new QUICK_SELECT(thd, table, ref->key);
+ QUICK_RANGE_SELECT *quick= new QUICK_RANGE_SELECT(thd, table, ref->key, 0);
KEY *key_info = &table->key_info[ref->key];
KEY_PART *key_part;
QUICK_RANGE *range;
@@ -2574,15 +5532,15 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
if (!quick)
return 0; /* no ranges found */
- if (cp_buffer_from_ref(thd, ref))
+ if (quick->init())
{
- if (thd->is_fatal_error)
- goto err; // out of memory
- goto ok; // empty range
+ delete quick;
+ goto err;
}
- if (!(range= new QUICK_RANGE()))
- goto err; // out of memory
+ if (cp_buffer_from_ref(thd,ref) && thd->is_fatal_error ||
+ !(range= new QUICK_RANGE()))
+ goto err; // out of memory
range->min_key=range->max_key=(char*) ref->key_buff;
range->min_length=range->max_length=ref->key_length;
@@ -2602,10 +5560,10 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
key_part->store_length= key_info->key_part[part].store_length;
key_part->null_bit= key_info->key_part[part].null_bit;
}
- if (quick->ranges.push_back(range))
+ if (insert_dynamic(&quick->ranges,(gptr)&range))
goto err;
- /*
+ /*
Add a NULL range if REF_OR_NULL optimization is used.
For example:
if we have "WHERE A=2 OR A IS NULL" we created the (A=2) range above
@@ -2621,11 +5579,10 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
EQ_RANGE)))
goto err;
*ref->null_ref_key= 0; // Clear null byte
- if (quick->ranges.push_back(null_range))
+ if (insert_dynamic(&quick->ranges,(gptr)&null_range))
goto err;
}
-ok:
thd->mem_root= old_root;
return quick;
@@ -2635,11 +5592,486 @@ err:
return 0;
}
- /* get next possible record using quick-struct */
-int QUICK_SELECT::get_next()
+/*
+ Perform key scans for all used indexes (except CPK), get rowids and merge
+ them into an ordered non-recurrent sequence of rowids.
+
+ The merge/duplicate removal is performed using Unique class. We put all
+ rowids into Unique, get the sorted sequence and destroy the Unique.
+
+ If table has a clustered primary key that covers all rows (TRUE for bdb
+ and innodb currently) and one of the index_merge scans is a scan on PK,
+ then
+ rows that will be retrieved by PK scan are not put into Unique and
+ primary key scan is not performed here, it is performed later separately.
+
+ RETURN
+ 0 OK
+ other error
+*/
+
+int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
+{
+ List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it(quick_selects);
+ QUICK_RANGE_SELECT* cur_quick;
+ int result;
+ Unique *unique;
+ DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::prepare_unique");
+
+ /* We're going to just read rowids. */
+ if (head->file->extra(HA_EXTRA_KEYREAD))
+ DBUG_RETURN(1);
+
+ /*
+ Make innodb retrieve all PK member fields, so
+ * ha_innobase::position (which uses them) call works.
+ * We can filter out rows that will be retrieved by clustered PK.
+ (This also creates a deficiency - it is possible that we will retrieve
+ parts of key that are not used by current query at all.)
+ */
+ if (head->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY))
+ DBUG_RETURN(1);
+
+ cur_quick_it.rewind();
+ cur_quick= cur_quick_it++;
+ DBUG_ASSERT(cur_quick != 0);
+
+ /*
+ We reuse the same instance of handler so we need to call both init and
+ reset here.
+ */
+ if (cur_quick->init() || cur_quick->reset())
+ DBUG_RETURN(1);
+
+ unique= new Unique(refpos_order_cmp, (void *)head->file,
+ head->file->ref_length,
+ thd->variables.sortbuff_size);
+ if (!unique)
+ DBUG_RETURN(1);
+ for (;;)
+ {
+ while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE)
+ {
+ cur_quick->range_end();
+ cur_quick= cur_quick_it++;
+ if (!cur_quick)
+ break;
+
+ if (cur_quick->file->inited != handler::NONE)
+ cur_quick->file->ha_index_end();
+ if (cur_quick->init() || cur_quick->reset())
+ DBUG_RETURN(1);
+ }
+
+ if (result)
+ {
+ if (result != HA_ERR_END_OF_FILE)
+ {
+ cur_quick->range_end();
+ DBUG_RETURN(result);
+ }
+ break;
+ }
+
+ if (thd->killed)
+ DBUG_RETURN(1);
+
+ /* skip row if it will be retrieved by clustered PK scan */
+ if (pk_quick_select && pk_quick_select->row_in_ranges())
+ continue;
+
+ cur_quick->file->position(cur_quick->record);
+ result= unique->unique_add((char*)cur_quick->file->ref);
+ if (result)
+ DBUG_RETURN(1);
+
+ }
+
+ /* ok, all row ids are in Unique */
+ result= unique->get(head);
+ delete unique;
+ doing_pk_scan= FALSE;
+ /* start table scan */
+ init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1);
+ /* index_merge currently doesn't support "using index" at all */
+ head->file->extra(HA_EXTRA_NO_KEYREAD);
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Get next row for index_merge.
+ NOTES
+ The rows are read from
+ 1. rowids stored in Unique.
+ 2. QUICK_RANGE_SELECT with clustered primary key (if any).
+ The sets of rows retrieved in 1) and 2) are guaranteed to be disjoint.
+*/
+
+int QUICK_INDEX_MERGE_SELECT::get_next()
+{
+ int result;
+ DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::get_next");
+
+ if (doing_pk_scan)
+ DBUG_RETURN(pk_quick_select->get_next());
+
+ result= read_record.read_record(&read_record);
+
+ if (result == -1)
+ {
+ result= HA_ERR_END_OF_FILE;
+ end_read_record(&read_record);
+ /* All rows from Unique have been retrieved, do a clustered PK scan */
+ if (pk_quick_select)
+ {
+ doing_pk_scan= TRUE;
+ if ((result= pk_quick_select->init()) || (result= pk_quick_select->reset()))
+ DBUG_RETURN(result);
+ DBUG_RETURN(pk_quick_select->get_next());
+ }
+ }
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Retrieve next record.
+ SYNOPSIS
+ QUICK_ROR_INTERSECT_SELECT::get_next()
+
+ NOTES
+ Invariant on enter/exit: all intersected selects have retrieved all index
+ records with rowid <= some_rowid_val and no intersected select has
+ retrieved any index records with rowid > some_rowid_val.
+ We start fresh and loop until we have retrieved the same rowid in each of
+ the key scans or we got an error.
+
+ If a Clustered PK scan is present, it is used only to check if row
+ satisfies its condition (and never used for row retrieval).
+
+ RETURN
+ 0 - Ok
+ other - Error code if any error occurred.
+*/
+
+int QUICK_ROR_INTERSECT_SELECT::get_next()
+{
+ List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects);
+ QUICK_RANGE_SELECT* quick;
+ int error, cmp;
+ uint last_rowid_count=0;
+ DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::get_next");
+
+ /* Get a rowid for first quick and save it as a 'candidate' */
+ quick= quick_it++;
+ if (cpk_quick)
+ {
+ do {
+ error= quick->get_next();
+ }while (!error && !cpk_quick->row_in_ranges());
+ }
+ else
+ error= quick->get_next();
+
+ if (error)
+ DBUG_RETURN(error);
+
+ quick->file->position(quick->record);
+ memcpy(last_rowid, quick->file->ref, head->file->ref_length);
+ last_rowid_count= 1;
+
+ while (last_rowid_count < quick_selects.elements)
+ {
+ if (!(quick= quick_it++))
+ {
+ quick_it.rewind();
+ quick= quick_it++;
+ }
+
+ do {
+ if ((error= quick->get_next()))
+ DBUG_RETURN(error);
+ quick->file->position(quick->record);
+ cmp= head->file->cmp_ref(quick->file->ref, last_rowid);
+ } while (cmp < 0);
+
+ /* Ok, current select 'caught up' and returned ref >= cur_ref */
+ if (cmp > 0)
+ {
+ /* Found a row with ref > cur_ref. Make it a new 'candidate' */
+ if (cpk_quick)
+ {
+ while (!cpk_quick->row_in_ranges())
+ {
+ if ((error= quick->get_next()))
+ DBUG_RETURN(error);
+ }
+ }
+ memcpy(last_rowid, quick->file->ref, head->file->ref_length);
+ last_rowid_count= 1;
+ }
+ else
+ {
+ /* current 'candidate' row confirmed by this select */
+ last_rowid_count++;
+ }
+ }
+
+ /* We get here iff we got the same row ref in all scans. */
+ if (need_to_fetch_row)
+ error= head->file->rnd_pos(head->record[0], last_rowid);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Retrieve next record.
+ SYNOPSIS
+ QUICK_ROR_UNION_SELECT::get_next()
+
+ NOTES
+ Enter/exit invariant:
+ For each quick select in the queue a {key,rowid} tuple has been
+ retrieved but the corresponding row hasn't been passed to output.
+
+ RETURN
+ 0 - Ok
+ other - Error code if any error occurred.
+*/
+
+int QUICK_ROR_UNION_SELECT::get_next()
+{
+ int error, dup_row;
+ QUICK_SELECT_I *quick;
+ byte *tmp;
+ DBUG_ENTER("QUICK_ROR_UNION_SELECT::get_next");
+
+ do
+ {
+ if (!queue.elements)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ /* Ok, we have a queue with >= 1 scans */
+
+ quick= (QUICK_SELECT_I*)queue_top(&queue);
+ memcpy(cur_rowid, quick->last_rowid, rowid_length);
+
+ /* put into queue rowid from the same stream as top element */
+ if ((error= quick->get_next()))
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ DBUG_RETURN(error);
+ queue_remove(&queue, 0);
+ }
+ else
+ {
+ quick->save_last_pos();
+ queue_replaced(&queue);
+ }
+
+ if (!have_prev_rowid)
+ {
+ /* No rows have been returned yet */
+ dup_row= FALSE;
+ have_prev_rowid= TRUE;
+ }
+ else
+ dup_row= !head->file->cmp_ref(cur_rowid, prev_rowid);
+ }while (dup_row);
+
+ tmp= cur_rowid;
+ cur_rowid= prev_rowid;
+ prev_rowid= tmp;
+
+ error= head->file->rnd_pos(quick->record, prev_rowid);
+ DBUG_RETURN(error);
+}
+
+int QUICK_RANGE_SELECT::reset()
+{
+ uint mrange_bufsiz;
+ byte *mrange_buff;
+ DBUG_ENTER("QUICK_RANGE_SELECT::reset");
+ next=0;
+ range= NULL;
+ cur_range= (QUICK_RANGE**) ranges.buffer;
+
+ /* Do not allocate the buffers twice. */
+ if (multi_range_length)
+ {
+ DBUG_ASSERT(multi_range_length == min(multi_range_count, ranges.elements));
+ DBUG_RETURN(0);
+ }
+
+ /* Allocate the ranges array. */
+ DBUG_ASSERT(ranges.elements);
+ multi_range_length= min(multi_range_count, ranges.elements);
+ DBUG_ASSERT(multi_range_length > 0);
+ while (multi_range_length && ! (multi_range= (KEY_MULTI_RANGE*)
+ my_malloc(multi_range_length *
+ sizeof(KEY_MULTI_RANGE),
+ MYF(MY_WME))))
+ {
+ /* Try to shrink the buffers until it is 0. */
+ multi_range_length/= 2;
+ }
+ if (! multi_range)
+ {
+ multi_range_length= 0;
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+
+ /* Allocate the handler buffer if necessary. */
+ if (file->table_flags() & HA_NEED_READ_RANGE_BUFFER)
+ {
+ mrange_bufsiz= min(multi_range_bufsiz,
+ (QUICK_SELECT_I::records + 1)* head->s->reclength);
+
+ while (mrange_bufsiz &&
+ ! my_multi_malloc(MYF(MY_WME),
+ &multi_range_buff, sizeof(*multi_range_buff),
+ &mrange_buff, mrange_bufsiz,
+ NullS))
+ {
+ /* Try to shrink the buffers until both are 0. */
+ mrange_bufsiz/= 2;
+ }
+ if (! multi_range_buff)
+ {
+ my_free((char*) multi_range, MYF(0));
+ multi_range= NULL;
+ multi_range_length= 0;
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+
+ /* Initialize the handler buffer. */
+ multi_range_buff->buffer= mrange_buff;
+ multi_range_buff->buffer_end= mrange_buff + mrange_bufsiz;
+ multi_range_buff->end_of_used_area= mrange_buff;
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Get next possible record using quick-struct.
+
+ SYNOPSIS
+ QUICK_RANGE_SELECT::get_next()
+
+ NOTES
+ Record is read into table->record[0]
+
+ RETURN
+ 0 Found row
+ HA_ERR_END_OF_FILE No (more) rows in range
+ # Error code
+*/
+
+int QUICK_RANGE_SELECT::get_next()
+{
+ int result;
+ KEY_MULTI_RANGE *mrange;
+ key_range *start_key;
+ key_range *end_key;
+ DBUG_ENTER("QUICK_RANGE_SELECT::get_next");
+ DBUG_ASSERT(multi_range_length && multi_range &&
+ (cur_range >= (QUICK_RANGE**) ranges.buffer) &&
+ (cur_range <= (QUICK_RANGE**) ranges.buffer + ranges.elements));
+
+ for (;;)
+ {
+ if (in_range)
+ {
+ /* We did already start to read this key. */
+ result= file->read_multi_range_next(&mrange);
+ if (result != HA_ERR_END_OF_FILE)
+ {
+ in_range= ! result;
+ DBUG_RETURN(result);
+ }
+ }
+
+ uint count= min(multi_range_length, ranges.elements -
+ (cur_range - (QUICK_RANGE**) ranges.buffer));
+ if (count == 0)
+ {
+ /* Ranges have already been used up before. None is left for read. */
+ in_range= FALSE;
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
+ KEY_MULTI_RANGE *mrange_slot, *mrange_end;
+ for (mrange_slot= multi_range, mrange_end= mrange_slot+count;
+ mrange_slot < mrange_end;
+ mrange_slot++)
+ {
+ start_key= &mrange_slot->start_key;
+ end_key= &mrange_slot->end_key;
+ range= *(cur_range++);
+
+ start_key->key= (const byte*) range->min_key;
+ start_key->length= range->min_length;
+ start_key->flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
+ (range->flag & EQ_RANGE) ?
+ HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
+ end_key->key= (const byte*) range->max_key;
+ end_key->length= range->max_length;
+ /*
+ We use HA_READ_AFTER_KEY here because if we are reading on a key
+ prefix. We want to find all keys with this prefix.
+ */
+ end_key->flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
+ HA_READ_AFTER_KEY);
+
+ mrange_slot->range_flag= range->flag;
+ }
+
+ result= file->read_multi_range_first(&mrange, multi_range, count,
+ sorted, multi_range_buff);
+ if (result != HA_ERR_END_OF_FILE)
+ {
+ in_range= ! result;
+ DBUG_RETURN(result);
+ }
+ in_range= FALSE; /* No matching rows; go to next set of ranges. */
+ }
+}
+
+
+/*
+ Get the next record with a different prefix.
+
+ SYNOPSIS
+ QUICK_RANGE_SELECT::get_next_prefix()
+ prefix_length length of cur_prefix
+ cur_prefix prefix of a key to be searched for
+
+ DESCRIPTION
+ Each subsequent call to the method retrieves the first record that has a
+ prefix with length prefix_length different from cur_prefix, such that the
+ record with the new prefix is within the ranges described by
+ this->ranges. The record found is stored into the buffer pointed by
+ this->record.
+ The method is useful for GROUP-BY queries with range conditions to
+ discover the prefix of the next group that satisfies the range conditions.
+
+ TODO
+ This method is a modified copy of QUICK_RANGE_SELECT::get_next(), so both
+ methods should be unified into a more general one to reduce code
+ duplication.
+
+ RETURN
+ 0 on success
+ HA_ERR_END_OF_FILE if returned all keys
+ other if some error occurred
+*/
+
+int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
{
- DBUG_ENTER("get_next");
+ DBUG_ENTER("QUICK_RANGE_SELECT::get_next_prefix");
for (;;)
{
@@ -2647,22 +6079,30 @@ int QUICK_SELECT::get_next()
key_range start_key, end_key;
if (range)
{
- // Already read through key
- result= file->read_range_next();
- if (result != HA_ERR_END_OF_FILE)
- DBUG_RETURN(result);
+ /* Read the next record in the same range with prefix after cur_prefix. */
+ DBUG_ASSERT(cur_prefix != 0);
+ result= file->index_read(record, cur_prefix, prefix_length,
+ HA_READ_AFTER_KEY);
+ if (result || (file->compare_key(file->end_range) <= 0))
+ DBUG_RETURN(result);
}
- if (!(range= it++))
- DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
+ uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer);
+ if (count == 0)
+ {
+ /* Ranges have already been used up before. None is left for read. */
+ range= 0;
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
+ range= *(cur_range++);
start_key.key= (const byte*) range->min_key;
- start_key.length= range->min_length;
+ start_key.length= min(range->min_length, prefix_length);
start_key.flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
(range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
end_key.key= (const byte*) range->max_key;
- end_key.length= range->max_length;
+ end_key.length= min(range->max_length, prefix_length);
/*
We use READ_AFTER_KEY here because if we are reading on a key
prefix we want to find all keys with this prefix
@@ -2686,9 +6126,9 @@ int QUICK_SELECT::get_next()
/* Get next for geometrical indexes */
-int QUICK_SELECT_GEOM::get_next()
+int QUICK_RANGE_SELECT_GEOM::get_next()
{
- DBUG_ENTER(" QUICK_SELECT_GEOM::get_next");
+ DBUG_ENTER("QUICK_RANGE_SELECT_GEOM::get_next");
for (;;)
{
@@ -2702,8 +6142,14 @@ int QUICK_SELECT_GEOM::get_next()
DBUG_RETURN(result);
}
- if (!(range= it++))
- DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
+ uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer);
+ if (count == 0)
+ {
+ /* Ranges have already been used up before. None is left for read. */
+ range= 0;
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
+ range= *(cur_range++);
result= file->index_read(record,
(byte*) range->min_key,
@@ -2717,6 +6163,46 @@ int QUICK_SELECT_GEOM::get_next()
/*
+ Check if current row will be retrieved by this QUICK_RANGE_SELECT
+
+ NOTES
+ It is assumed that currently a scan is being done on another index
+ which reads all necessary parts of the index that is scanned by this
+ quick select.
+ The implementation does a binary search on sorted array of disjoint
+ ranges, without taking size of range into account.
+
+ This function is used to filter out clustered PK scan rows in
+ index_merge quick select.
+
+ RETURN
+ TRUE if current row will be retrieved by this quick select
+ FALSE if not
+*/
+
+bool QUICK_RANGE_SELECT::row_in_ranges()
+{
+ QUICK_RANGE *range;
+ uint min= 0;
+ uint max= ranges.elements - 1;
+ uint mid= (max + min)/2;
+
+ while (min != max)
+ {
+ if (cmp_next(*(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid)))
+ {
+ /* current row value > mid->max */
+ min= mid + 1;
+ }
+ else
+ max= mid;
+ mid= (min + max) / 2;
+ }
+ range= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid);
+ return (!cmp_next(range) && !cmp_prev(range));
+}
+
+/*
This is a hack: we inherit from QUICK_SELECT so that we can use the
get_next() interface, but we have to hold a pointer to the original
QUICK_SELECT because its data are used all over the place. What
@@ -2726,16 +6212,17 @@ int QUICK_SELECT_GEOM::get_next()
for now, this seems to work right at least.
*/
-QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts)
- : QUICK_SELECT(*q), rev_it(rev_ranges)
+QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q,
+ uint used_key_parts)
+ : QUICK_RANGE_SELECT(*q), rev_it(rev_ranges)
{
QUICK_RANGE *r;
- it.rewind();
- for (r = it++; r; r = it++)
- {
- rev_ranges.push_front(r);
- }
+ QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer;
+ QUICK_RANGE **last_range= pr + ranges.elements;
+ for (; pr!=last_range; pr++)
+ rev_ranges.push_front(*pr);
+
/* Remove EQ_RANGE flag for keys that are not using the full key */
for (r = rev_it++; r; r = rev_it++)
{
@@ -2828,10 +6315,51 @@ int QUICK_SELECT_DESC::get_next()
/*
+ Compare if found key is over max-value
+ Returns 0 if key <= range->max_key
+*/
+
+int QUICK_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg)
+{
+ if (range_arg->flag & NO_MAX_RANGE)
+ return 0; /* key can't be to large */
+
+ KEY_PART *key_part=key_parts;
+ uint store_length;
+
+ for (char *key=range_arg->max_key, *end=key+range_arg->max_length;
+ key < end;
+ key+= store_length, key_part++)
+ {
+ int cmp;
+ store_length= key_part->store_length;
+ if (key_part->null_bit)
+ {
+ if (*key)
+ {
+ if (!key_part->field->is_null())
+ return 1;
+ continue;
+ }
+ else if (key_part->field->is_null())
+ return 0;
+ key++; // Skip null byte
+ store_length--;
+ }
+ if ((cmp=key_part->field->key_cmp((byte*) key, key_part->length)) < 0)
+ return 0;
+ if (cmp > 0)
+ return 1;
+ }
+ return (range_arg->flag & NEAR_MAX) ? 1 : 0; // Exact match
+}
+
+
+/*
Returns 0 if found key is inside range (found key >= range->min_key).
*/
-int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range_arg)
+int QUICK_RANGE_SELECT::cmp_prev(QUICK_RANGE *range_arg)
{
int cmp;
if (range_arg->flag & NO_MIN_RANGE)
@@ -2846,7 +6374,7 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range_arg)
/*
- * True if this range will require using HA_READ_AFTER_KEY
+ * TRUE if this range will require using HA_READ_AFTER_KEY
See comment in get_next() about this
*/
@@ -2858,7 +6386,7 @@ bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg)
}
-/* True if we are reading over a key that may have a NULL value */
+/* TRUE if we are reading over a key that may have a NULL value */
#ifdef NOT_USED
bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range_arg,
@@ -2906,6 +6434,2171 @@ bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range_arg,
#endif
+void QUICK_RANGE_SELECT::add_info_string(String *str)
+{
+ KEY *key_info= head->key_info + index;
+ str->append(key_info->name);
+}
+
+void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str)
+{
+ QUICK_RANGE_SELECT *quick;
+ bool first= TRUE;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ str->append("sort_union(");
+ while ((quick= it++))
+ {
+ if (!first)
+ str->append(',');
+ else
+ first= FALSE;
+ quick->add_info_string(str);
+ }
+ if (pk_quick_select)
+ {
+ str->append(',');
+ pk_quick_select->add_info_string(str);
+ }
+ str->append(')');
+}
+
+void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str)
+{
+ bool first= TRUE;
+ QUICK_RANGE_SELECT *quick;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ str->append("intersect(");
+ while ((quick= it++))
+ {
+ KEY *key_info= head->key_info + quick->index;
+ if (!first)
+ str->append(',');
+ else
+ first= FALSE;
+ str->append(key_info->name);
+ }
+ if (cpk_quick)
+ {
+ KEY *key_info= head->key_info + cpk_quick->index;
+ str->append(',');
+ str->append(key_info->name);
+ }
+ str->append(')');
+}
+
+void QUICK_ROR_UNION_SELECT::add_info_string(String *str)
+{
+ bool first= TRUE;
+ QUICK_SELECT_I *quick;
+ List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
+ str->append("union(");
+ while ((quick= it++))
+ {
+ if (!first)
+ str->append(',');
+ else
+ first= FALSE;
+ quick->add_info_string(str);
+ }
+ str->append(')');
+}
+
+
+void QUICK_RANGE_SELECT::add_keys_and_lengths(String *key_names,
+ String *used_lengths)
+{
+ char buf[64];
+ uint length;
+ KEY *key_info= head->key_info + index;
+ key_names->append(key_info->name);
+ length= longlong2str(max_used_key_length, buf, 10) - buf;
+ used_lengths->append(buf, length);
+}
+
+void QUICK_INDEX_MERGE_SELECT::add_keys_and_lengths(String *key_names,
+ String *used_lengths)
+{
+ char buf[64];
+ uint length;
+ bool first= TRUE;
+ QUICK_RANGE_SELECT *quick;
+
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ while ((quick= it++))
+ {
+ if (first)
+ first= FALSE;
+ else
+ {
+ key_names->append(',');
+ used_lengths->append(',');
+ }
+
+ KEY *key_info= head->key_info + quick->index;
+ key_names->append(key_info->name);
+ length= longlong2str(quick->max_used_key_length, buf, 10) - buf;
+ used_lengths->append(buf, length);
+ }
+ if (pk_quick_select)
+ {
+ KEY *key_info= head->key_info + pk_quick_select->index;
+ key_names->append(',');
+ key_names->append(key_info->name);
+ length= longlong2str(pk_quick_select->max_used_key_length, buf, 10) - buf;
+ used_lengths->append(',');
+ used_lengths->append(buf, length);
+ }
+}
+
+void QUICK_ROR_INTERSECT_SELECT::add_keys_and_lengths(String *key_names,
+ String *used_lengths)
+{
+ char buf[64];
+ uint length;
+ bool first= TRUE;
+ QUICK_RANGE_SELECT *quick;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ while ((quick= it++))
+ {
+ KEY *key_info= head->key_info + quick->index;
+ if (first)
+ first= FALSE;
+ else
+ {
+ key_names->append(',');
+ used_lengths->append(',');
+ }
+ key_names->append(key_info->name);
+ length= longlong2str(quick->max_used_key_length, buf, 10) - buf;
+ used_lengths->append(buf, length);
+ }
+
+ if (cpk_quick)
+ {
+ KEY *key_info= head->key_info + cpk_quick->index;
+ key_names->append(',');
+ key_names->append(key_info->name);
+ length= longlong2str(cpk_quick->max_used_key_length, buf, 10) - buf;
+ used_lengths->append(',');
+ used_lengths->append(buf, length);
+ }
+}
+
+void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names,
+ String *used_lengths)
+{
+ bool first= TRUE;
+ QUICK_SELECT_I *quick;
+ List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
+ while ((quick= it++))
+ {
+ if (first)
+ first= FALSE;
+ else
+ {
+ used_lengths->append(',');
+ key_names->append(',');
+ }
+ quick->add_keys_and_lengths(key_names, used_lengths);
+ }
+}
+
+
+/*******************************************************************************
+* Implementation of QUICK_GROUP_MIN_MAX_SELECT
+*******************************************************************************/
+
+static inline uint get_field_keypart(KEY *index, Field *field);
+static inline SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree,
+ PARAM *param, uint *param_idx);
+static bool
+get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
+ KEY_PART_INFO *first_non_group_part,
+ KEY_PART_INFO *min_max_arg_part,
+ KEY_PART_INFO *last_part, THD *thd,
+ byte *key_infix, uint *key_infix_len,
+ KEY_PART_INFO **first_non_infix_part);
+static bool
+check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item,
+ Field::imagetype image_type);
+
+static void
+cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
+ uint group_key_parts, SEL_TREE *range_tree,
+ SEL_ARG *index_tree, ha_rows quick_prefix_records,
+ bool have_min, bool have_max,
+ double *read_cost, ha_rows *records);
+
+/*
+ Test if this access method is applicable to a GROUP query with MIN/MAX
+ functions, and if so, construct a new TRP object.
+
+ SYNOPSIS
+ get_best_group_min_max()
+ param Parameter from test_quick_select
+ sel_tree Range tree generated by get_mm_tree
+
+ DESCRIPTION
+ Test whether a query can be computed via a QUICK_GROUP_MIN_MAX_SELECT.
+ Queries computable via a QUICK_GROUP_MIN_MAX_SELECT must satisfy the
+ following conditions:
+ A) Table T has at least one compound index I of the form:
+ I = <A_1, ...,A_k, [B_1,..., B_m], C, [D_1,...,D_n]>
+ B) Query conditions:
+ B0. Q is over a single table T.
+ B1. The attributes referenced by Q are a subset of the attributes of I.
+ B2. All attributes QA in Q can be divided into 3 overlapping groups:
+ - SA = {S_1, ..., S_l, [C]} - from the SELECT clause, where C is
+ referenced by any number of MIN and/or MAX functions if present.
+ - WA = {W_1, ..., W_p} - from the WHERE clause
+ - GA = <G_1, ..., G_k> - from the GROUP BY clause (if any)
+ = SA - if Q is a DISTINCT query (based on the
+ equivalence of DISTINCT and GROUP queries.
+ - NGA = QA - (GA union C) = {NG_1, ..., NG_m} - the ones not in
+ GROUP BY and not referenced by MIN/MAX functions.
+ with the following properties specified below.
+
+ SA1. There is at most one attribute in SA referenced by any number of
+ MIN and/or MAX functions which, which if present, is denoted as C.
+ SA2. The position of the C attribute in the index is after the last A_k.
+ SA3. The attribute C can be referenced in the WHERE clause only in
+ predicates of the forms:
+ - (C {< | <= | > | >= | =} const)
+ - (const {< | <= | > | >= | =} C)
+ - (C between const_i and const_j)
+ - C IS NULL
+ - C IS NOT NULL
+ - C != const
+ SA4. If Q has a GROUP BY clause, there are no other aggregate functions
+ except MIN and MAX. For queries with DISTINCT, aggregate functions
+ are allowed.
+ SA5. The select list in DISTINCT queries should not contain expressions.
+ GA1. If Q has a GROUP BY clause, then GA is a prefix of I. That is, if
+ G_i = A_j => i = j.
+ GA2. If Q has a DISTINCT clause, then there is a permutation of SA that
+ forms a prefix of I. This permutation is used as the GROUP clause
+ when the DISTINCT query is converted to a GROUP query.
+ GA3. The attributes in GA may participate in arbitrary predicates, divided
+ into two groups:
+ - RNG(G_1,...,G_q ; where q <= k) is a range condition over the
+ attributes of a prefix of GA
+ - PA(G_i1,...G_iq) is an arbitrary predicate over an arbitrary subset
+ of GA. Since P is applied to only GROUP attributes it filters some
+ groups, and thus can be applied after the grouping.
+ GA4. There are no expressions among G_i, just direct column references.
+ NGA1.If in the index I there is a gap between the last GROUP attribute G_k,
+ and the MIN/MAX attribute C, then NGA must consist of exactly the index
+ attributes that constitute the gap. As a result there is a permutation
+ of NGA that coincides with the gap in the index <B_1, ..., B_m>.
+ NGA2.If BA <> {}, then the WHERE clause must contain a conjunction EQ of
+ equality conditions for all NG_i of the form (NG_i = const) or
+ (const = NG_i), such that each NG_i is referenced in exactly one
+ conjunct. Informally, the predicates provide constants to fill the
+ gap in the index.
+ WA1. There are no other attributes in the WHERE clause except the ones
+ referenced in predicates RNG, PA, PC, EQ defined above. Therefore
+ WA is subset of (GA union NGA union C) for GA,NGA,C that pass the above
+ tests. By transitivity then it also follows that each WA_i participates
+ in the index I (if this was already tested for GA, NGA and C).
+
+ C) Overall query form:
+ SELECT EXPR([A_1,...,A_k], [B_1,...,B_m], [MIN(C)], [MAX(C)])
+ FROM T
+ WHERE [RNG(A_1,...,A_p ; where p <= k)]
+ [AND EQ(B_1,...,B_m)]
+ [AND PC(C)]
+ [AND PA(A_i1,...,A_iq)]
+ GROUP BY A_1,...,A_k
+ [HAVING PH(A_1, ..., B_1,..., C)]
+ where EXPR(...) is an arbitrary expression over some or all SELECT fields,
+ or:
+ SELECT DISTINCT A_i1,...,A_ik
+ FROM T
+ WHERE [RNG(A_1,...,A_p ; where p <= k)]
+ [AND PA(A_i1,...,A_iq)];
+
+ NOTES
+ If the current query satisfies the conditions above, and if
+ (mem_root! = NULL), then the function constructs and returns a new TRP
+ object, that is later used to construct a new QUICK_GROUP_MIN_MAX_SELECT.
+ If (mem_root == NULL), then the function only tests whether the current
+ query satisfies the conditions above, and, if so, sets
+ is_applicable = TRUE.
+
+ Queries with DISTINCT for which index access can be used are transformed
+ into equivalent group-by queries of the form:
+
+ SELECT A_1,...,A_k FROM T
+ WHERE [RNG(A_1,...,A_p ; where p <= k)]
+ [AND PA(A_i1,...,A_iq)]
+ GROUP BY A_1,...,A_k;
+
+ The group-by list is a permutation of the select attributes, according
+ to their order in the index.
+
+ TODO
+ - What happens if the query groups by the MIN/MAX field, and there is no
+ other field as in: "select min(a) from t1 group by a" ?
+ - We assume that the general correctness of the GROUP-BY query was checked
+ before this point. Is this correct, or do we have to check it completely?
+
+ RETURN
+ If mem_root != NULL
+ - valid TRP_GROUP_MIN_MAX object if this QUICK class can be used for
+ the query
+ - NULL o/w.
+ If mem_root == NULL
+ - NULL
+*/
+
+static TRP_GROUP_MIN_MAX *
+get_best_group_min_max(PARAM *param, SEL_TREE *tree)
+{
+ THD *thd= param->thd;
+ JOIN *join= thd->lex->select_lex.join;
+ TABLE *table= param->table;
+ bool have_min= FALSE; /* TRUE if there is a MIN function. */
+ bool have_max= FALSE; /* TRUE if there is a MAX function. */
+ Item_field *min_max_arg_item= NULL;/* The argument of all MIN/MAX functions.*/
+ KEY_PART_INFO *min_max_arg_part= NULL; /* The corresponding keypart. */
+ uint group_prefix_len= 0; /* Length (in bytes) of the key prefix. */
+ KEY *index_info= NULL; /* The index chosen for data access. */
+ uint index= 0; /* The id of the chosen index. */
+ uint group_key_parts= 0; /* Number of index key parts in the group prefix. */
+ uint used_key_parts= 0; /* Number of index key parts used for access. */
+ byte key_infix[MAX_KEY_LENGTH]; /* Constants from equality predicates.*/
+ uint key_infix_len= 0; /* Length of key_infix. */
+ TRP_GROUP_MIN_MAX *read_plan= NULL; /* The eventually constructed TRP. */
+ uint key_part_nr;
+ ORDER *tmp_group;
+ Item *item;
+ Item_field *item_field;
+ DBUG_ENTER("get_best_group_min_max");
+
+ /* Perform few 'cheap' tests whether this access method is applicable. */
+ if (!join || (thd->lex->sql_command != SQLCOM_SELECT))
+ DBUG_RETURN(NULL); /* This is not a select statement. */
+ if ((join->tables != 1) || /* The query must reference one table. */
+ ((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
+ (!join->select_distinct)))
+ DBUG_RETURN(NULL);
+ if (table->s->keys == 0) /* There are no indexes to use. */
+ DBUG_RETURN(NULL);
+
+ /* Analyze the query in more detail. */
+ List_iterator<Item> select_items_it(join->fields_list);
+
+ /* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
+ if(join->make_sum_func_list(join->all_fields, join->fields_list, 1))
+ DBUG_RETURN(NULL);
+ if (join->sum_funcs[0])
+ {
+ Item_sum *min_max_item;
+ Item_sum **func_ptr= join->sum_funcs;
+ while ((min_max_item= *(func_ptr++)))
+ {
+ if (min_max_item->sum_func() == Item_sum::MIN_FUNC)
+ have_min= TRUE;
+ else if (min_max_item->sum_func() == Item_sum::MAX_FUNC)
+ have_max= TRUE;
+ else
+ DBUG_RETURN(NULL);
+
+ Item *expr= min_max_item->args[0]; /* The argument of MIN/MAX. */
+ if (expr->type() == Item::FIELD_ITEM) /* Is it an attribute? */
+ {
+ if (! min_max_arg_item)
+ min_max_arg_item= (Item_field*) expr;
+ else if (! min_max_arg_item->eq(expr, 1))
+ DBUG_RETURN(NULL);
+ }
+ else
+ DBUG_RETURN(NULL);
+ }
+ }
+
+ /* Check (SA5). */
+ if (join->select_distinct)
+ {
+ while ((item= select_items_it++))
+ {
+ if (item->type() != Item::FIELD_ITEM)
+ DBUG_RETURN(NULL);
+ }
+ }
+
+ /* Check (GA4) - that there are no expressions among the group attributes. */
+ for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next)
+ {
+ if ((*tmp_group->item)->type() != Item::FIELD_ITEM)
+ DBUG_RETURN(NULL);
+ }
+
+ /*
+ Check that table has at least one compound index such that the conditions
+ (GA1,GA2) are all TRUE. If there is more than one such index, select the
+ first one. Here we set the variables: group_prefix_len and index_info.
+ */
+ KEY *cur_index_info= table->key_info;
+ KEY *cur_index_info_end= cur_index_info + table->s->keys;
+ KEY_PART_INFO *cur_part= NULL;
+ KEY_PART_INFO *end_part; /* Last part for loops. */
+ /* Last index part. */
+ KEY_PART_INFO *last_part= NULL;
+ KEY_PART_INFO *first_non_group_part= NULL;
+ KEY_PART_INFO *first_non_infix_part= NULL;
+ uint key_infix_parts= 0;
+ uint cur_group_key_parts= 0;
+ uint cur_group_prefix_len= 0;
+ /* Cost-related variables for the best index so far. */
+ double best_read_cost= DBL_MAX;
+ ha_rows best_records= 0;
+ SEL_ARG *best_index_tree= NULL;
+ ha_rows best_quick_prefix_records= 0;
+ uint best_param_idx= 0;
+ double cur_read_cost= DBL_MAX;
+ ha_rows cur_records;
+ SEL_ARG *cur_index_tree= NULL;
+ ha_rows cur_quick_prefix_records= 0;
+ uint cur_param_idx;
+ key_map cur_used_key_parts;
+
+ for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ;
+ cur_index_info++, cur_index++)
+ {
+ /* Check (B1) - if current index is covering. */
+ if (!table->used_keys.is_set(cur_index))
+ goto next_index;
+
+ /*
+ Check (GA1) for GROUP BY queries.
+ */
+ if (join->group_list)
+ {
+ cur_part= cur_index_info->key_part;
+ end_part= cur_part + cur_index_info->key_parts;
+ /* Iterate in parallel over the GROUP list and the index parts. */
+ for (tmp_group= join->group_list; tmp_group && (cur_part != end_part);
+ tmp_group= tmp_group->next, cur_part++)
+ {
+ /*
+ TODO:
+ tmp_group::item is an array of Item, is it OK to consider only the
+ first Item? If so, then why? What is the array for?
+ */
+ /* Above we already checked that all group items are fields. */
+ DBUG_ASSERT((*tmp_group->item)->type() == Item::FIELD_ITEM);
+ Item_field *group_field= (Item_field *) (*tmp_group->item);
+ if (group_field->field->eq(cur_part->field))
+ {
+ cur_group_prefix_len+= cur_part->store_length;
+ ++cur_group_key_parts;
+ }
+ else
+ goto next_index;
+ }
+ }
+ /*
+ Check (GA2) if this is a DISTINCT query.
+ If GA2, then Store a new ORDER object in group_fields_array at the
+ position of the key part of item_field->field. Thus we get the ORDER
+ objects for each field ordered as the corresponding key parts.
+ Later group_fields_array of ORDER objects is used to convert the query
+ to a GROUP query.
+ */
+ else if (join->select_distinct)
+ {
+ select_items_it.rewind();
+ cur_used_key_parts.clear_all();
+ while ((item= select_items_it++))
+ {
+ item_field= (Item_field*) item; /* (SA5) already checked above. */
+ /* Find the order of the key part in the index. */
+ key_part_nr= get_field_keypart(cur_index_info, item_field->field);
+ /*
+ Check if this attribute was already present in the select list.
+ If it was present, then its corresponding key part was alredy used.
+ */
+ if (cur_used_key_parts.is_set(key_part_nr))
+ continue;
+ if (key_part_nr < 1 || key_part_nr > join->fields_list.elements)
+ goto next_index;
+ cur_part= cur_index_info->key_part + key_part_nr - 1;
+ cur_group_prefix_len+= cur_part->store_length;
+ cur_used_key_parts.set_bit(key_part_nr);
+ ++cur_group_key_parts;
+ }
+ }
+ else
+ DBUG_ASSERT(FALSE);
+
+ /* Check (SA2). */
+ if (min_max_arg_item)
+ {
+ key_part_nr= get_field_keypart(cur_index_info, min_max_arg_item->field);
+ if (key_part_nr <= cur_group_key_parts)
+ goto next_index;
+ min_max_arg_part= cur_index_info->key_part + key_part_nr - 1;
+ }
+
+ /*
+ Check (NGA1, NGA2) and extract a sequence of constants to be used as part
+ of all search keys.
+ */
+
+ /*
+ If there is MIN/MAX, each keypart between the last group part and the
+ MIN/MAX part must participate in one equality with constants, and all
+ keyparts after the MIN/MAX part must not be referenced in the query.
+
+ If there is no MIN/MAX, the keyparts after the last group part can be
+ referenced only in equalities with constants, and the referenced keyparts
+ must form a sequence without any gaps that starts immediately after the
+ last group keypart.
+ */
+ last_part= cur_index_info->key_part + cur_index_info->key_parts;
+ first_non_group_part= (cur_group_key_parts < cur_index_info->key_parts) ?
+ cur_index_info->key_part + cur_group_key_parts :
+ NULL;
+ first_non_infix_part= min_max_arg_part ?
+ (min_max_arg_part < last_part) ?
+ min_max_arg_part + 1 :
+ NULL :
+ NULL;
+ if (first_non_group_part &&
+ (!min_max_arg_part || (min_max_arg_part - first_non_group_part > 0)))
+ {
+ if (tree)
+ {
+ uint dummy;
+ SEL_ARG *index_range_tree= get_index_range_tree(cur_index, tree, param,
+ &dummy);
+ if (!get_constant_key_infix(cur_index_info, index_range_tree,
+ first_non_group_part, min_max_arg_part,
+ last_part, thd, key_infix, &key_infix_len,
+ &first_non_infix_part))
+ goto next_index;
+ }
+ else if (min_max_arg_part &&
+ (min_max_arg_part - first_non_group_part > 0))
+ /*
+ There is a gap but no range tree, thus no predicates at all for the
+ non-group keyparts.
+ */
+ goto next_index;
+ }
+
+ /*
+ Test (WA1) partially - that no other keypart after the last infix part is
+ referenced in the query.
+ */
+ if (first_non_infix_part)
+ {
+ for (cur_part= first_non_infix_part; cur_part != last_part; cur_part++)
+ {
+ if (cur_part->field->query_id == thd->query_id)
+ goto next_index;
+ }
+ }
+
+ /* If we got to this point, cur_index_info passes the test. */
+ key_infix_parts= key_infix_len ?
+ (first_non_infix_part - first_non_group_part) : 0;
+ used_key_parts= cur_group_key_parts + key_infix_parts;
+
+ /* Compute the cost of using this index. */
+ if (tree)
+ {
+ /* Find the SEL_ARG sub-tree that corresponds to the chosen index. */
+ cur_index_tree= get_index_range_tree(cur_index, tree, param,
+ &cur_param_idx);
+ /* Check if this range tree can be used for prefix retrieval. */
+ cur_quick_prefix_records= check_quick_select(param, cur_param_idx,
+ cur_index_tree);
+ }
+ cost_group_min_max(table, cur_index_info, used_key_parts,
+ cur_group_key_parts, tree, cur_index_tree,
+ cur_quick_prefix_records, have_min, have_max,
+ &cur_read_cost, &cur_records);
+ /*
+ If cur_read_cost is lower than best_read_cost use cur_index.
+ Do not compare doubles directly because they may have different
+ representations (64 vs. 80 bits).
+ */
+ if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost))
+ {
+ index_info= cur_index_info;
+ index= cur_index;
+ best_read_cost= cur_read_cost;
+ best_records= cur_records;
+ best_index_tree= cur_index_tree;
+ best_quick_prefix_records= cur_quick_prefix_records;
+ best_param_idx= cur_param_idx;
+ group_key_parts= cur_group_key_parts;
+ group_prefix_len= cur_group_prefix_len;
+ }
+
+ next_index:
+ cur_group_key_parts= 0;
+ cur_group_prefix_len= 0;
+ }
+ if (!index_info) /* No usable index found. */
+ DBUG_RETURN(NULL);
+
+ /* Check (SA3) for the where clause. */
+ if (join->conds && min_max_arg_item &&
+ !check_group_min_max_predicates(join->conds, min_max_arg_item,
+ (index_info->flags & HA_SPATIAL) ?
+ Field::itMBR : Field::itRAW))
+ DBUG_RETURN(NULL);
+
+ /* The query passes all tests, so construct a new TRP object. */
+ read_plan= new (param->mem_root)
+ TRP_GROUP_MIN_MAX(have_min, have_max, min_max_arg_part,
+ group_prefix_len, used_key_parts,
+ group_key_parts, index_info, index,
+ key_infix_len,
+ (key_infix_len > 0) ? key_infix : NULL,
+ tree, best_index_tree, best_param_idx,
+ best_quick_prefix_records);
+ if (read_plan)
+ {
+ if (tree && read_plan->quick_prefix_records == 0)
+ DBUG_RETURN(NULL);
+
+ read_plan->read_cost= best_read_cost;
+ read_plan->records= best_records;
+
+ DBUG_PRINT("info",
+ ("Returning group min/max plan: cost: %g, records: %lu",
+ read_plan->read_cost, (ulong) read_plan->records));
+ }
+
+ DBUG_RETURN(read_plan);
+}
+
+
+/*
+ Check that the MIN/MAX attribute participates only in range predicates
+ with constants.
+
+ SYNOPSIS
+ check_group_min_max_predicates()
+ cond tree (or subtree) describing all or part of the WHERE
+ clause being analyzed
+ min_max_arg_item the field referenced by the MIN/MAX function(s)
+ min_max_arg_part the keypart of the MIN/MAX argument if any
+
+ DESCRIPTION
+ The function walks recursively over the cond tree representing a WHERE
+ clause, and checks condition (SA3) - if a field is referenced by a MIN/MAX
+ aggregate function, it is referenced only by one of the following
+ predicates: {=, !=, <, <=, >, >=, between, is null, is not null}.
+
+ RETURN
+ TRUE if cond passes the test
+ FALSE o/w
+*/
+
+static bool
+check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item,
+ Field::imagetype image_type)
+{
+ DBUG_ENTER("check_group_min_max_predicates");
+ DBUG_ASSERT(cond && min_max_arg_item);
+
+ Item::Type cond_type= cond->type();
+ if (cond_type == Item::COND_ITEM) /* 'AND' or 'OR' */
+ {
+ DBUG_PRINT("info", ("Analyzing: %s", ((Item_func*) cond)->func_name()));
+ List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *and_or_arg;
+ while ((and_or_arg= li++))
+ {
+ if(!check_group_min_max_predicates(and_or_arg, min_max_arg_item,
+ image_type))
+ DBUG_RETURN(FALSE);
+ }
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ TODO:
+ This is a very crude fix to handle sub-selects in the WHERE clause
+ (Item_subselect objects). With the test below we rule out from the
+ optimization all queries with subselects in the WHERE clause. What has to
+ be done, is that here we should analyze whether the subselect references
+ the MIN/MAX argument field, and disallow the optimization only if this is
+ so.
+ */
+ if (cond_type == Item::SUBSELECT_ITEM)
+ DBUG_RETURN(FALSE);
+
+ /* We presume that at this point there are no other Items than functions. */
+ DBUG_ASSERT(cond_type == Item::FUNC_ITEM);
+
+ /* Test if cond references only group-by or non-group fields. */
+ Item_func *pred= (Item_func*) cond;
+ Item **arguments= pred->arguments();
+ Item *cur_arg;
+ DBUG_PRINT("info", ("Analyzing: %s", pred->func_name()));
+ for (uint arg_idx= 0; arg_idx < pred->argument_count (); arg_idx++)
+ {
+ cur_arg= arguments[arg_idx];
+ DBUG_PRINT("info", ("cur_arg: %s", cur_arg->full_name()));
+ if (cur_arg->type() == Item::FIELD_ITEM)
+ {
+ if (min_max_arg_item->eq(cur_arg, 1))
+ {
+ /*
+ If pred references the MIN/MAX argument, check whether pred is a range
+ condition that compares the MIN/MAX argument with a constant.
+ */
+ Item_func::Functype pred_type= pred->functype();
+ if (pred_type != Item_func::EQUAL_FUNC &&
+ pred_type != Item_func::LT_FUNC &&
+ pred_type != Item_func::LE_FUNC &&
+ pred_type != Item_func::GT_FUNC &&
+ pred_type != Item_func::GE_FUNC &&
+ pred_type != Item_func::BETWEEN &&
+ pred_type != Item_func::ISNULL_FUNC &&
+ pred_type != Item_func::ISNOTNULL_FUNC &&
+ pred_type != Item_func::EQ_FUNC &&
+ pred_type != Item_func::NE_FUNC)
+ DBUG_RETURN(FALSE);
+
+ /* Check that pred compares min_max_arg_item with a constant. */
+ Item *args[3];
+ bzero(args, 3 * sizeof(Item*));
+ bool inv;
+ /* Test if this is a comparison of a field and a constant. */
+ if (!simple_pred(pred, args, &inv))
+ DBUG_RETURN(FALSE);
+
+ /* Check for compatible string comparisons - similar to get_mm_leaf. */
+ if (args[0] && args[1] && !args[2] && // this is a binary function
+ min_max_arg_item->result_type() == STRING_RESULT &&
+ /*
+ Don't use an index when comparing strings of different collations.
+ */
+ ((args[1]->result_type() == STRING_RESULT &&
+ image_type == Field::itRAW &&
+ ((Field_str*) min_max_arg_item->field)->charset() !=
+ pred->compare_collation())
+ ||
+ /*
+ We can't always use indexes when comparing a string index to a
+ number.
+ */
+ (args[1]->result_type() != STRING_RESULT &&
+ min_max_arg_item->field->cmp_type() != args[1]->result_type())))
+ DBUG_RETURN(FALSE);
+ }
+ }
+ else if (cur_arg->type() == Item::FUNC_ITEM)
+ {
+ if(!check_group_min_max_predicates(cur_arg, min_max_arg_item,
+ image_type))
+ DBUG_RETURN(FALSE);
+ }
+ else if (cur_arg->const_item())
+ {
+ DBUG_RETURN(TRUE);
+ }
+ else
+ DBUG_RETURN(FALSE);
+ }
+
+ DBUG_RETURN(TRUE);
+}
+
+
+/*
+ Extract a sequence of constants from a conjunction of equality predicates.
+
+ SYNOPSIS
+ get_constant_key_infix()
+ index_info [in] Descriptor of the chosen index.
+ index_range_tree [in] Range tree for the chosen index
+ first_non_group_part [in] First index part after group attribute parts
+ min_max_arg_part [in] The keypart of the MIN/MAX argument if any
+ last_part [in] Last keypart of the index
+ thd [in] Current thread
+ key_infix [out] Infix of constants to be used for index lookup
+ key_infix_len [out] Lenghth of the infix
+ first_non_infix_part [out] The first keypart after the infix (if any)
+
+ DESCRIPTION
+ Test conditions (NGA1, NGA2) from get_best_group_min_max(). Namely,
+ for each keypart field NGF_i not in GROUP-BY, check that there is a constant
+ equality predicate among conds with the form (NGF_i = const_ci) or
+ (const_ci = NGF_i).
+ Thus all the NGF_i attributes must fill the 'gap' between the last group-by
+ attribute and the MIN/MAX attribute in the index (if present). If these
+ conditions hold, copy each constant from its corresponding predicate into
+ key_infix, in the order its NG_i attribute appears in the index, and update
+ key_infix_len with the total length of the key parts in key_infix.
+
+ RETURN
+ TRUE if the index passes the test
+ FALSE o/w
+*/
+
+static bool
+get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
+ KEY_PART_INFO *first_non_group_part,
+ KEY_PART_INFO *min_max_arg_part,
+ KEY_PART_INFO *last_part, THD *thd,
+ byte *key_infix, uint *key_infix_len,
+ KEY_PART_INFO **first_non_infix_part)
+{
+ SEL_ARG *cur_range;
+ KEY_PART_INFO *cur_part;
+ /* End part for the first loop below. */
+ KEY_PART_INFO *end_part= min_max_arg_part ? min_max_arg_part : last_part;
+
+ *key_infix_len= 0;
+ byte *key_ptr= key_infix;
+ for (cur_part= first_non_group_part; cur_part != end_part; cur_part++)
+ {
+ /*
+ Find the range tree for the current keypart. We assume that
+ index_range_tree points to the leftmost keypart in the index.
+ */
+ for (cur_range= index_range_tree; cur_range;
+ cur_range= cur_range->next_key_part)
+ {
+ if (cur_range->field->eq(cur_part->field))
+ break;
+ }
+ if (!cur_range)
+ {
+ if (min_max_arg_part)
+ return FALSE; /* The current keypart has no range predicates at all. */
+ else
+ {
+ *first_non_infix_part= cur_part;
+ return TRUE;
+ }
+ }
+
+ /* Check that the current range tree is a single point interval. */
+ if (cur_range->prev || cur_range->next)
+ return FALSE; /* This is not the only range predicate for the field. */
+ if ((cur_range->min_flag & NO_MIN_RANGE) ||
+ (cur_range->max_flag & NO_MAX_RANGE) ||
+ (cur_range->min_flag & NEAR_MIN) || (cur_range->max_flag & NEAR_MAX))
+ return FALSE;
+
+ uint field_length= cur_part->store_length;
+ if ((cur_range->maybe_null &&
+ cur_range->min_value[0] && cur_range->max_value[0])
+ ||
+ (memcmp(cur_range->min_value, cur_range->max_value, field_length) == 0))
+ { /* cur_range specifies 'IS NULL' or an equality condition. */
+ memcpy(key_ptr, cur_range->min_value, field_length);
+ key_ptr+= field_length;
+ *key_infix_len+= field_length;
+ }
+ else
+ return FALSE;
+ }
+
+ if (!min_max_arg_part && (cur_part == last_part))
+ *first_non_infix_part= last_part;
+
+ return TRUE;
+}
+
+
+/*
+ Find the key part referenced by a field.
+
+ SYNOPSIS
+ get_field_keypart()
+ index descriptor of an index
+ field field that possibly references some key part in index
+
+ NOTES
+ The return value can be used to get a KEY_PART_INFO pointer by
+ part= index->key_part + get_field_keypart(...) - 1;
+
+ RETURN
+ Positive number which is the consecutive number of the key part, or
+ 0 if field does not reference any index field.
+*/
+
+static inline uint
+get_field_keypart(KEY *index, Field *field)
+{
+ KEY_PART_INFO *part, *end;
+
+ for (part= index->key_part, end= part + index->key_parts; part < end; part++)
+ {
+ if (field->eq(part->field))
+ return part - index->key_part + 1;
+ }
+ return 0;
+}
+
+
+/*
+ Find the SEL_ARG sub-tree that corresponds to the chosen index.
+
+ SYNOPSIS
+ get_index_range_tree()
+ index [in] The ID of the index being looked for
+ range_tree[in] Tree of ranges being searched
+ param [in] PARAM from SQL_SELECT::test_quick_select
+ param_idx [out] Index in the array PARAM::key that corresponds to 'index'
+
+ DESCRIPTION
+
+ A SEL_TREE contains range trees for all usable indexes. This procedure
+ finds the SEL_ARG sub-tree for 'index'. The members of a SEL_TREE are
+ ordered in the same way as the members of PARAM::key, thus we first find
+ the corresponding index in the array PARAM::key. This index is returned
+ through the variable param_idx, to be used later as argument of
+ check_quick_select().
+
+ RETURN
+ Pointer to the SEL_ARG subtree that corresponds to index.
+*/
+
+SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree, PARAM *param,
+ uint *param_idx)
+{
+ uint idx= 0; /* Index nr in param->key_parts */
+ while (idx < param->keys)
+ {
+ if (index == param->real_keynr[idx])
+ break;
+ idx++;
+ }
+ *param_idx= idx;
+ return(range_tree->keys[idx]);
+}
+
+
+/*
+ Compute the cost of a quick_group_min_max_select for a particular index.
+
+ SYNOPSIS
+ cost_group_min_max()
+ table [in] The table being accessed
+ index_info [in] The index used to access the table
+ used_key_parts [in] Number of key parts used to access the index
+ group_key_parts [in] Number of index key parts in the group prefix
+ range_tree [in] Tree of ranges for all indexes
+ index_tree [in] The range tree for the current index
+ quick_prefix_records [in] Number of records retrieved by the internally
+ used quick range select if any
+ have_min [in] True if there is a MIN function
+ have_max [in] True if there is a MAX function
+ read_cost [out] The cost to retrieve rows via this quick select
+ records [out] The number of rows retrieved
+
+ DESCRIPTION
+ This method computes the access cost of a TRP_GROUP_MIN_MAX instance and
+ the number of rows returned. It updates this->read_cost and this->records.
+
+ NOTES
+ The cost computation distinguishes several cases:
+ 1) No equality predicates over non-group attributes (thus no key_infix).
+ If groups are bigger than blocks on the average, then we assume that it
+ is very unlikely that block ends are aligned with group ends, thus even
+ if we look for both MIN and MAX keys, all pairs of neighbor MIN/MAX
+ keys, except for the first MIN and the last MAX keys, will be in the
+ same block. If groups are smaller than blocks, then we are going to
+ read all blocks.
+ 2) There are equality predicates over non-group attributes.
+ In this case the group prefix is extended by additional constants, and
+ as a result the min/max values are inside sub-groups of the original
+ groups. The number of blocks that will be read depends on whether the
+ ends of these sub-groups will be contained in the same or in different
+ blocks. We compute the probability for the two ends of a subgroup to be
+ in two different blocks as the ratio of:
+ - the number of positions of the left-end of a subgroup inside a group,
+ such that the right end of the subgroup is past the end of the buffer
+ containing the left-end, and
+ - the total number of possible positions for the left-end of the
+ subgroup, which is the number of keys in the containing group.
+ We assume it is very unlikely that two ends of subsequent subgroups are
+ in the same block.
+ 3) The are range predicates over the group attributes.
+ Then some groups may be filtered by the range predicates. We use the
+ selectivity of the range predicates to decide how many groups will be
+ filtered.
+
+ TODO
+ - Take into account the optional range predicates over the MIN/MAX
+ argument.
+ - Check if we have a PK index and we use all cols - then each key is a
+ group, and it will be better to use an index scan.
+
+ RETURN
+ None
+*/
+
+void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
+ uint group_key_parts, SEL_TREE *range_tree,
+ SEL_ARG *index_tree, ha_rows quick_prefix_records,
+ bool have_min, bool have_max,
+ double *read_cost, ha_rows *records)
+{
+ uint table_records;
+ uint num_groups;
+ uint num_blocks;
+ uint keys_per_block;
+ uint keys_per_group;
+ uint keys_per_subgroup; /* Average number of keys in sub-groups */
+ /* formed by a key infix. */
+ double p_overlap; /* Probability that a sub-group overlaps two blocks. */
+ double quick_prefix_selectivity;
+ double io_cost;
+ double cpu_cost= 0; /* TODO: CPU cost of index_read calls? */
+ DBUG_ENTER("cost_group_min_max");
+
+ table_records= table->file->records;
+ keys_per_block= (table->file->block_size / 2 /
+ (index_info->key_length + table->file->ref_length)
+ + 1);
+ num_blocks= (table_records / keys_per_block) + 1;
+
+ /* Compute the number of keys in a group. */
+ keys_per_group= index_info->rec_per_key[group_key_parts - 1];
+ if (keys_per_group == 0) /* If there is no statistics try to guess */
+ /* each group contains 10% of all records */
+ keys_per_group= (table_records / 10) + 1;
+ num_groups= (table_records / keys_per_group) + 1;
+
+ /* Apply the selectivity of the quick select for group prefixes. */
+ if (range_tree && (quick_prefix_records != HA_POS_ERROR))
+ {
+ quick_prefix_selectivity= (double) quick_prefix_records /
+ (double) table_records;
+ num_groups= (uint) rint(num_groups * quick_prefix_selectivity);
+ }
+
+ if (used_key_parts > group_key_parts)
+ { /*
+ Compute the probability that two ends of a subgroup are inside
+ different blocks.
+ */
+ keys_per_subgroup= index_info->rec_per_key[used_key_parts - 1];
+ if (keys_per_subgroup >= keys_per_block) /* If a subgroup is bigger than */
+ p_overlap= 1.0; /* a block, it will overlap at least two blocks. */
+ else
+ {
+ double blocks_per_group= (double) num_blocks / (double) num_groups;
+ p_overlap= (blocks_per_group * (keys_per_subgroup - 1)) / keys_per_group;
+ p_overlap= min(p_overlap, 1.0);
+ }
+ io_cost= (double) min(num_groups * (1 + p_overlap), num_blocks);
+ }
+ else
+ io_cost= (keys_per_group > keys_per_block) ?
+ (have_min && have_max) ? (double) (num_groups + 1) :
+ (double) num_groups :
+ (double) num_blocks;
+
+ /*
+ TODO: If there is no WHERE clause and no other expressions, there should be
+ no CPU cost. We leave it here to make this cost comparable to that of index
+ scan as computed in SQL_SELECT::test_quick_select().
+ */
+ cpu_cost= (double) num_groups / TIME_FOR_COMPARE;
+
+ *read_cost= io_cost + cpu_cost;
+ *records= num_groups;
+
+ DBUG_PRINT("info",
+ ("records=%u, keys/block=%u, keys/group=%u, records=%u, blocks=%u",
+ table_records, keys_per_block, keys_per_group, records,
+ num_blocks));
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Construct a new quick select object for queries with group by with min/max.
+
+ SYNOPSIS
+ TRP_GROUP_MIN_MAX::make_quick()
+ param Parameter from test_quick_select
+ retrieve_full_rows ignored
+ parent_alloc Memory pool to use, if any.
+
+ NOTES
+ Make_quick ignores the retrieve_full_rows parameter because
+ QUICK_GROUP_MIN_MAX_SELECT always performs 'index only' scans.
+ The other parameter are ignored as well because all necessary
+ data to create the QUICK object is computed at this TRP creation
+ time.
+
+ RETURN
+ New QUICK_GROUP_MIN_MAX_SELECT object if successfully created,
+ NULL o/w.
+*/
+
+QUICK_SELECT_I *
+TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc)
+{
+ QUICK_GROUP_MIN_MAX_SELECT *quick;
+ DBUG_ENTER("TRP_GROUP_MIN_MAX::make_quick");
+
+ quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table,
+ param->thd->lex->select_lex.join,
+ have_min, have_max, min_max_arg_part,
+ group_prefix_len, used_key_parts,
+ index_info, index, read_cost, records,
+ key_infix_len, key_infix,
+ parent_alloc);
+ if (!quick)
+ DBUG_RETURN(NULL);
+
+ if (quick->init())
+ {
+ delete quick;
+ DBUG_RETURN(NULL);
+ }
+
+ if (range_tree)
+ {
+ DBUG_ASSERT(quick_prefix_records > 0);
+ if (quick_prefix_records == HA_POS_ERROR)
+ quick->quick_prefix_select= NULL; /* Can't construct a quick select. */
+ else
+ /* Make a QUICK_RANGE_SELECT to be used for group prefix retrieval. */
+ quick->quick_prefix_select= get_quick_select(param, param_idx,
+ index_tree,
+ &quick->alloc);
+
+ /*
+ Extract the SEL_ARG subtree that contains only ranges for the MIN/MAX
+ attribute, and create an array of QUICK_RANGES to be used by the
+ new quick select.
+ */
+ if (min_max_arg_part)
+ {
+ SEL_ARG *min_max_range= index_tree;
+ while (min_max_range) /* Find the tree for the MIN/MAX key part. */
+ {
+ if (min_max_range->field->eq(min_max_arg_part->field))
+ break;
+ min_max_range= min_max_range->next_key_part;
+ }
+ /* Scroll to the leftmost interval for the MIN/MAX argument. */
+ while (min_max_range && min_max_range->prev)
+ min_max_range= min_max_range->prev;
+ /* Create an array of QUICK_RANGEs for the MIN/MAX argument. */
+ while (min_max_range)
+ {
+ if (quick->add_range(min_max_range))
+ {
+ delete quick;
+ quick= NULL;
+ DBUG_RETURN(NULL);
+ }
+ min_max_range= min_max_range->next;
+ }
+ }
+ }
+ else
+ quick->quick_prefix_select= NULL;
+
+ quick->update_key_stat();
+
+ DBUG_RETURN(quick);
+}
+
+
+/*
+ Construct new quick select for group queries with min/max.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::QUICK_GROUP_MIN_MAX_SELECT()
+ table The table being accessed
+ join Descriptor of the current query
+ have_min TRUE if the query selects a MIN function
+ have_max TRUE if the query selects a MAX function
+ min_max_arg_part The only argument field of all MIN/MAX functions
+ group_prefix_len Length of all key parts in the group prefix
+ prefix_key_parts All key parts in the group prefix
+ index_info The index chosen for data access
+ use_index The id of index_info
+ read_cost Cost of this access method
+ records Number of records returned
+ key_infix_len Length of the key infix appended to the group prefix
+ key_infix Infix of constants from equality predicates
+ parent_alloc Memory pool for this and quick_prefix_select data
+
+ RETURN
+ None
+*/
+
+QUICK_GROUP_MIN_MAX_SELECT::
+QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
+ bool have_max_arg,
+ KEY_PART_INFO *min_max_arg_part_arg,
+ uint group_prefix_len_arg,
+ uint used_key_parts_arg, KEY *index_info_arg,
+ uint use_index, double read_cost_arg,
+ ha_rows records_arg, uint key_infix_len_arg,
+ byte *key_infix_arg, MEM_ROOT *parent_alloc)
+ :join(join_arg), index_info(index_info_arg),
+ group_prefix_len(group_prefix_len_arg), have_min(have_min_arg),
+ have_max(have_max_arg), seen_first_key(FALSE),
+ min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg),
+ key_infix_len(key_infix_len_arg), min_functions_it(NULL),
+ max_functions_it(NULL)
+{
+ head= table;
+ file= head->file;
+ index= use_index;
+ record= head->record[0];
+ tmp_record= head->record[1];
+ read_time= read_cost_arg;
+ records= records_arg;
+ used_key_parts= used_key_parts_arg;
+ real_prefix_len= group_prefix_len + key_infix_len;
+ group_prefix= NULL;
+ min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0;
+
+ /*
+ We can't have parent_alloc set as the init function can't handle this case
+ yet.
+ */
+ DBUG_ASSERT(!parent_alloc);
+ if (!parent_alloc)
+ {
+ init_sql_alloc(&alloc, join->thd->variables.range_alloc_block_size, 0);
+ join->thd->mem_root= &alloc;
+ }
+ else
+ bzero(&alloc, sizeof(MEM_ROOT)); // ensure that it's not used
+}
+
+
+/*
+ Do post-constructor initialization.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::init()
+
+ DESCRIPTION
+ The method performs initialization that cannot be done in the constructor
+ such as memory allocations that may fail. It allocates memory for the
+ group prefix and inifix buffers, and for the lists of MIN/MAX item to be
+ updated during execution.
+
+ RETURN
+ 0 OK
+ other Error code
+*/
+
+int QUICK_GROUP_MIN_MAX_SELECT::init()
+{
+ if (group_prefix) /* Already initialized. */
+ return 0;
+
+ if (!(last_prefix= (byte*) alloc_root(&alloc, group_prefix_len)))
+ return 1;
+ /*
+ We may use group_prefix to store keys with all select fields, so allocate
+ enough space for it.
+ */
+ if (!(group_prefix= (byte*) alloc_root(&alloc,
+ real_prefix_len + min_max_arg_len)))
+ return 1;
+
+ if (key_infix_len > 0)
+ {
+ /*
+ The memory location pointed to by key_infix will be deleted soon, so
+ allocate a new buffer and copy the key_infix into it.
+ */
+ byte *tmp_key_infix= (byte*) alloc_root(&alloc, key_infix_len);
+ if (!tmp_key_infix)
+ return 1;
+ memcpy(tmp_key_infix, this->key_infix, key_infix_len);
+ this->key_infix= tmp_key_infix;
+ }
+
+ if (min_max_arg_part)
+ {
+ if(my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16))
+ return 1;
+
+ if (have_min)
+ {
+ if(!(min_functions= new List<Item_sum>))
+ return 1;
+ }
+ else
+ min_functions= NULL;
+ if (have_max)
+ {
+ if(!(max_functions= new List<Item_sum>))
+ return 1;
+ }
+ else
+ max_functions= NULL;
+
+ Item_sum *min_max_item;
+ Item_sum **func_ptr= join->sum_funcs;
+ while ((min_max_item= *(func_ptr++)))
+ {
+ if (have_min && (min_max_item->sum_func() == Item_sum::MIN_FUNC))
+ min_functions->push_back(min_max_item);
+ else if (have_max && (min_max_item->sum_func() == Item_sum::MAX_FUNC))
+ max_functions->push_back(min_max_item);
+ }
+
+ if (have_min)
+ {
+ if (!(min_functions_it= new List_iterator<Item_sum>(*min_functions)))
+ return 1;
+ }
+
+ if (have_max)
+ {
+ if (!(max_functions_it= new List_iterator<Item_sum>(*max_functions)))
+ return 1;
+ }
+ }
+ else
+ min_max_ranges.elements= 0;
+
+ return 0;
+}
+
+
+QUICK_GROUP_MIN_MAX_SELECT::~QUICK_GROUP_MIN_MAX_SELECT()
+{
+ DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::~QUICK_GROUP_MIN_MAX_SELECT");
+ if (file->inited != handler::NONE)
+ file->ha_index_end();
+ if (min_max_arg_part)
+ delete_dynamic(&min_max_ranges);
+ free_root(&alloc,MYF(0));
+ delete min_functions_it;
+ delete max_functions_it;
+ delete quick_prefix_select;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Eventually create and add a new quick range object.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::add_range()
+ sel_range Range object from which a
+
+ NOTES
+ Construct a new QUICK_RANGE object from a SEL_ARG object, and
+ add it to the array min_max_ranges. If sel_arg is an infinite
+ range, e.g. (x < 5 or x > 4), then skip it and do not construct
+ a quick range.
+
+ RETURN
+ FALSE on success
+ TRUE otherwise
+*/
+
+bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range)
+{
+ QUICK_RANGE *range;
+ uint range_flag= sel_range->min_flag | sel_range->max_flag;
+
+ /* Skip (-inf,+inf) ranges, e.g. (x < 5 or x > 4). */
+ if((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE))
+ return FALSE;
+
+ if (!(sel_range->min_flag & NO_MIN_RANGE) &&
+ !(sel_range->max_flag & NO_MAX_RANGE))
+ {
+ if (sel_range->maybe_null &&
+ sel_range->min_value[0] && sel_range->max_value[0])
+ range_flag|= NULL_RANGE; /* IS NULL condition */
+ else if (memcmp(sel_range->min_value, sel_range->max_value,
+ min_max_arg_len) == 0)
+ range_flag|= EQ_RANGE; /* equality condition */
+ }
+ range= new QUICK_RANGE(sel_range->min_value, min_max_arg_len,
+ sel_range->max_value, min_max_arg_len,
+ range_flag);
+ if (!range)
+ return TRUE;
+ if (insert_dynamic(&min_max_ranges, (gptr)&range))
+ return TRUE;
+ return FALSE;
+}
+
+
+/*
+ Determine the total number and length of the keys that will be used for
+ index lookup.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
+
+ DESCRIPTION
+ The total length of the keys used for index lookup depends on whether
+ there are any predicates referencing the min/max argument, and/or if
+ the min/max argument field can be NULL.
+ This function does an optimistic analysis whether the search key might
+ be extended by a constant for the min/max keypart. It is 'optimistic'
+ because during actual execution it may happen that a particular range
+ is skipped, and then a shorter key will be used. However this is data
+ dependent and can't be easily estimated here.
+
+ RETURN
+ None
+*/
+
+void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
+{
+ max_used_key_length= real_prefix_len;
+ if (min_max_ranges.elements > 0)
+ {
+ QUICK_RANGE *cur_range= 0;
+ if (have_min)
+ { /* Check if the right-most range has a lower boundary. */
+ get_dynamic(&min_max_ranges, (gptr)&cur_range,
+ min_max_ranges.elements - 1);
+ if (!(cur_range->flag & NO_MIN_RANGE))
+ {
+ max_used_key_length+= min_max_arg_len;
+ ++used_key_parts;
+ return;
+ }
+ }
+ if (have_max)
+ { /* Check if the left-most range has an upper boundary. */
+ get_dynamic(&min_max_ranges, (gptr)&cur_range, 0);
+ if (!(cur_range->flag & NO_MAX_RANGE))
+ {
+ max_used_key_length+= min_max_arg_len;
+ ++used_key_parts;
+ return;
+ }
+ }
+ }
+ else if (have_min && min_max_arg_part && min_max_arg_part->field->is_null())
+ {
+ max_used_key_length+= min_max_arg_len;
+ ++used_key_parts;
+ }
+}
+
+
+/*
+ Initialize a quick group min/max select for key retrieval.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::reset()
+
+ DESCRIPTION
+ Initialize the index chosen for access and find and store the prefix
+ of the last group. The method is expensive since it performs disk access.
+
+ RETURN
+ 0 OK
+ other Error code
+*/
+
+int QUICK_GROUP_MIN_MAX_SELECT::reset(void)
+{
+ int result;
+ DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset");
+
+ file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */
+ result= file->ha_index_init(index);
+ result= file->index_last(record);
+ if (result == HA_ERR_END_OF_FILE)
+ DBUG_RETURN(0);
+ if (result)
+ DBUG_RETURN(result);
+ if (quick_prefix_select && quick_prefix_select->reset())
+ DBUG_RETURN(1);
+ /* Save the prefix of the last group. */
+ key_copy(last_prefix, record, index_info, group_prefix_len);
+
+ DBUG_RETURN(0);
+}
+
+
+
+/*
+ Get the next key containing the MIN and/or MAX key for the next group.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::get_next()
+
+ DESCRIPTION
+ The method finds the next subsequent group of records that satisfies the
+ query conditions and finds the keys that contain the MIN/MAX values for
+ the key part referenced by the MIN/MAX function(s). Once a group and its
+ MIN/MAX values are found, store these values in the Item_sum objects for
+ the MIN/MAX functions. The rest of the values in the result row are stored
+ in the Item_field::result_field of each select field. If the query does
+ not contain MIN and/or MAX functions, then the function only finds the
+ group prefix, which is a query answer itself.
+
+ NOTES
+ If both MIN and MAX are computed, then we use the fact that if there is
+ no MIN key, there can't be a MAX key as well, so we can skip looking
+ for a MAX key in this case.
+
+ RETURN
+ 0 on success
+ HA_ERR_END_OF_FILE if returned all keys
+ other if some error occurred
+*/
+
+int QUICK_GROUP_MIN_MAX_SELECT::get_next()
+{
+ int min_res= 0;
+ int max_res= 0;
+#ifdef HPUX11
+ /*
+ volatile is required by a bug in the HP compiler due to which the
+ last test of result fails.
+ */
+ volatile int result;
+#else
+ int result;
+#endif
+ int is_last_prefix;
+
+ DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::get_next");
+
+ /*
+ Loop until a group is found that satisfies all query conditions or the last
+ group is reached.
+ */
+ do
+ {
+ result= next_prefix();
+ /*
+ Check if this is the last group prefix. Notice that at this point
+ this->record contains the current prefix in record format.
+ */
+ is_last_prefix= key_cmp(index_info->key_part, last_prefix,
+ group_prefix_len);
+ DBUG_ASSERT(is_last_prefix <= 0);
+ if (result == HA_ERR_KEY_NOT_FOUND)
+ continue;
+ else if (result)
+ break;
+
+ if (have_min)
+ {
+ min_res= next_min();
+ if (min_res == 0)
+ update_min_result();
+ }
+ /* If there is no MIN in the group, there is no MAX either. */
+ if ((have_max && !have_min) ||
+ (have_max && have_min && (min_res == 0)))
+ {
+ max_res= next_max();
+ if (max_res == 0)
+ update_max_result();
+ /* If a MIN was found, a MAX must have been found as well. */
+ DBUG_ASSERT((have_max && !have_min) ||
+ (have_max && have_min && (max_res == 0)));
+ }
+ result= have_min ? min_res : have_max ? max_res : result;
+ }
+ while (result == HA_ERR_KEY_NOT_FOUND && is_last_prefix != 0);
+
+ if (result == 0)
+ /*
+ Partially mimic the behavior of end_select_send. Copy the
+ field data from Item_field::field into Item_field::result_field
+ of each non-aggregated field (the group fields, and optionally
+ other fields in non-ANSI SQL mode).
+ */
+ copy_fields(&join->tmp_table_param);
+ else if (result == HA_ERR_KEY_NOT_FOUND)
+ result= HA_ERR_END_OF_FILE;
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Retrieve the minimal key in the next group.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::next_min()
+
+ DESCRIPTION
+ Load the prefix of the next group into group_prefix and find the minimal
+ key within this group such that the key satisfies the query conditions and
+ NULL semantics. The found key is loaded into this->record.
+
+ IMPLEMENTATION
+ Depending on the values of min_max_ranges.elements, key_infix_len, and
+ whether there is a NULL in the MIN field, this function may directly
+ return without any data access. In this case we use the key loaded into
+ this->record by the call to this->next_prefix() just before this call.
+
+ RETURN
+ 0 on success
+ HA_ERR_KEY_NOT_FOUND if no MIN key was found that fulfills all conditions.
+ other if some error occurred
+*/
+
+int QUICK_GROUP_MIN_MAX_SELECT::next_min()
+{
+ int result= 0;
+ DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::next_min");
+
+ /* Find the MIN key using the eventually extended group prefix. */
+ if (min_max_ranges.elements > 0)
+ {
+ if ((result= next_min_in_range()))
+ DBUG_RETURN(result);
+ }
+ else
+ {
+ /* Apply the constant equality conditions to the non-group select fields. */
+ if (key_infix_len > 0)
+ {
+ if ((result= file->index_read(record, group_prefix, real_prefix_len,
+ HA_READ_KEY_EXACT)))
+ DBUG_RETURN(result);
+ }
+
+ /*
+ If the min/max argument field is NULL, skip subsequent rows in the same
+ group with NULL in it. Notice that:
+ - if the first row in a group doesn't have a NULL in the field, no row
+ in the same group has (because NULL < any other value),
+ - min_max_arg_part->field->ptr points to some place in 'record'.
+ */
+ if (min_max_arg_part && min_max_arg_part->field->is_null())
+ {
+ /* Find the first subsequent record without NULL in the MIN/MAX field. */
+ key_copy(tmp_record, record, index_info, 0);
+ result= file->index_read(record, tmp_record,
+ real_prefix_len + min_max_arg_len,
+ HA_READ_AFTER_KEY);
+ /*
+ Check if the new record belongs to the current group by comparing its
+ prefix with the group's prefix. If it is from the next group, then the
+ whole group has NULLs in the MIN/MAX field, so use the first record in
+ the group as a result.
+ TODO:
+ It is possible to reuse this new record as the result candidate for the
+ next call to next_min(), and to save one lookup in the next call. For
+ this add a new member 'this->next_group_prefix'.
+ */
+ if (!result)
+ {
+ if(key_cmp(index_info->key_part, group_prefix, real_prefix_len))
+ key_restore(record, tmp_record, index_info, 0);
+ } else if (result == HA_ERR_KEY_NOT_FOUND)
+ result= 0; /* There is a result in any case. */
+ }
+ }
+
+ /*
+ If the MIN attribute is non-nullable, this->record already contains the
+ MIN key in the group, so just return.
+ */
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Retrieve the maximal key in the next group.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::next_max()
+
+ DESCRIPTION
+ If there was no previous next_min call to determine the next group prefix,
+ then load the next prefix into group_prefix, then lookup the maximal key of
+ the group, and store it into this->record.
+
+ RETURN
+ 0 on success
+ HA_ERR_KEY_NOT_FOUND if no MAX key was found that fulfills all conditions.
+ other if some error occurred
+*/
+
+int QUICK_GROUP_MIN_MAX_SELECT::next_max()
+{
+ int result;
+
+ DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::next_max");
+
+ /* Get the last key in the (possibly extended) group. */
+ if (min_max_ranges.elements > 0)
+ result= next_max_in_range();
+ else
+ result= file->index_read(record, group_prefix, real_prefix_len,
+ HA_READ_PREFIX_LAST);
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Determine the prefix of the next group.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
+
+ DESCRIPTION
+ Determine the prefix of the next group that satisfies the query conditions.
+ If there is a range condition referencing the group attributes, use a
+ QUICK_RANGE_SELECT object to retrieve the *first* key that satisfies the
+ condition. If there is a key infix of constants, append this infix
+ immediately after the group attributes. The possibly extended prefix is
+ stored in this->group_prefix. The first key of the found group is stored in
+ this->record, on which relies this->next_min().
+
+ RETURN
+ 0 on success
+ HA_ERR_KEY_NOT_FOUND if there is no key with the formed prefix
+ HA_ERR_END_OF_FILE if there are no more keys
+ other if some error occurred
+*/
+int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
+{
+ int result;
+ DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::next_prefix");
+
+ if (quick_prefix_select)
+ {
+ byte *cur_prefix= seen_first_key ? group_prefix : NULL;
+ if ((result= quick_prefix_select->get_next_prefix(group_prefix_len,
+ cur_prefix)))
+ DBUG_RETURN(result);
+ seen_first_key= TRUE;
+ }
+ else
+ {
+ if (!seen_first_key)
+ {
+ result= file->index_first(record);
+ if (result)
+ DBUG_RETURN(result);
+ seen_first_key= TRUE;
+ }
+ else
+ {
+ /* Load the first key in this group into record. */
+ result= file->index_read(record, group_prefix, group_prefix_len,
+ HA_READ_AFTER_KEY);
+ if (result)
+ DBUG_RETURN(result);
+ }
+ }
+
+ /* Save the prefix of this group for subsequent calls. */
+ key_copy(group_prefix, record, index_info, group_prefix_len);
+ /* Append key_infix to group_prefix. */
+ if (key_infix_len > 0)
+ memcpy(group_prefix + group_prefix_len,
+ key_infix, key_infix_len);
+
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Find the minimal key in a group that satisfies some range conditions for the
+ min/max argument field.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
+
+ DESCRIPTION
+ Given the sequence of ranges min_max_ranges, find the minimal key that is
+ in the left-most possible range. If there is no such key, then the current
+ group does not have a MIN key that satisfies the WHERE clause. If a key is
+ found, its value is stored in this->record.
+
+ RETURN
+ 0 on success
+ HA_ERR_KEY_NOT_FOUND if there is no key with the given prefix in any of
+ the ranges
+ other if some error
+*/
+
+int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
+{
+ ha_rkey_function find_flag;
+ uint search_prefix_len;
+ QUICK_RANGE *cur_range;
+ bool found_null= FALSE;
+ int result= HA_ERR_KEY_NOT_FOUND;
+
+ DBUG_ASSERT(min_max_ranges.elements > 0);
+
+ for (uint range_idx= 0; range_idx < min_max_ranges.elements; range_idx++)
+ { /* Search from the left-most range to the right. */
+ get_dynamic(&min_max_ranges, (gptr)&cur_range, range_idx);
+
+ /*
+ If the current value for the min/max argument is bigger than the right
+ boundary of cur_range, there is no need to check this range.
+ */
+ if (range_idx != 0 && !(cur_range->flag & NO_MAX_RANGE) &&
+ (key_cmp(min_max_arg_part, (const byte*) cur_range->max_key,
+ min_max_arg_len) == 1))
+ continue;
+
+ if (cur_range->flag & NO_MIN_RANGE)
+ {
+ find_flag= HA_READ_KEY_EXACT;
+ search_prefix_len= real_prefix_len;
+ }
+ else
+ {
+ /* Extend the search key with the lower boundary for this range. */
+ memcpy(group_prefix + real_prefix_len, cur_range->min_key,
+ cur_range->min_length);
+ search_prefix_len= real_prefix_len + min_max_arg_len;
+ find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ?
+ HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ?
+ HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT;
+ }
+
+ result= file->index_read(record, group_prefix, search_prefix_len,
+ find_flag);
+ if ((result == HA_ERR_KEY_NOT_FOUND) &&
+ (cur_range->flag & (EQ_RANGE | NULL_RANGE)))
+ continue; /* Check the next range. */
+ else if (result)
+ {
+ /*
+ In all other cases (HA_ERR_*, HA_READ_KEY_EXACT with NO_MIN_RANGE,
+ HA_READ_AFTER_KEY, HA_READ_KEY_OR_NEXT) if the lookup failed for this
+ range, it can't succeed for any other subsequent range.
+ */
+ break;
+ }
+
+ /* A key was found. */
+ if (cur_range->flag & EQ_RANGE)
+ break; /* No need to perform the checks below for equal keys. */
+
+ if (cur_range->flag & NULL_RANGE)
+ {
+ /*
+ Remember this key, and continue looking for a non-NULL key that
+ satisfies some other condition.
+ */
+ memcpy(tmp_record, record, head->s->rec_buff_length);
+ found_null= TRUE;
+ continue;
+ }
+
+ /* 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;
+ }
+
+ /* If there is an upper limit, check if the found key is in the range. */
+ if ( !(cur_range->flag & NO_MAX_RANGE) )
+ {
+ /* Compose the MAX key for the range. */
+ byte *max_key= (byte*) my_alloca(real_prefix_len + min_max_arg_len);
+ memcpy(max_key, group_prefix, real_prefix_len);
+ memcpy(max_key + real_prefix_len, cur_range->max_key,
+ cur_range->max_length);
+ /* Compare the found key with max_key. */
+ int cmp_res= key_cmp(index_info->key_part, max_key,
+ real_prefix_len + min_max_arg_len);
+ if (!((cur_range->flag & NEAR_MAX) && (cmp_res == -1) ||
+ (cmp_res <= 0)))
+ {
+ result = HA_ERR_KEY_NOT_FOUND;
+ continue;
+ }
+ }
+ /* If we got to this point, the current key qualifies as MIN. */
+ DBUG_ASSERT(result == 0);
+ break;
+ }
+ /*
+ If there was a key with NULL in the MIN/MAX field, and there was no other
+ key without NULL from the same group that satisfies some other condition,
+ then use the key with the NULL.
+ */
+ if (found_null && result)
+ {
+ memcpy(record, tmp_record, head->s->rec_buff_length);
+ result= 0;
+ }
+ return result;
+}
+
+
+/*
+ Find the maximal key in a group that satisfies some range conditions for the
+ min/max argument field.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
+
+ DESCRIPTION
+ Given the sequence of ranges min_max_ranges, find the maximal key that is
+ in the right-most possible range. If there is no such key, then the current
+ group does not have a MAX key that satisfies the WHERE clause. If a key is
+ found, its value is stored in this->record.
+
+ RETURN
+ 0 on success
+ HA_ERR_KEY_NOT_FOUND if there is no key with the given prefix in any of
+ the ranges
+ other if some error
+*/
+
+int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
+{
+ ha_rkey_function find_flag;
+ uint search_prefix_len;
+ QUICK_RANGE *cur_range;
+ int result;
+
+ DBUG_ASSERT(min_max_ranges.elements > 0);
+
+ for (uint range_idx= min_max_ranges.elements; range_idx > 0; range_idx--)
+ { /* Search from the right-most range to the left. */
+ get_dynamic(&min_max_ranges, (gptr)&cur_range, range_idx - 1);
+
+ /*
+ If the current value for the min/max argument is smaller than the left
+ boundary of cur_range, there is no need to check this range.
+ */
+ if (range_idx != min_max_ranges.elements &&
+ !(cur_range->flag & NO_MIN_RANGE) &&
+ (key_cmp(min_max_arg_part, (const byte*) cur_range->min_key,
+ min_max_arg_len) == -1))
+ continue;
+
+ if (cur_range->flag & NO_MAX_RANGE)
+ {
+ find_flag= HA_READ_PREFIX_LAST;
+ search_prefix_len= real_prefix_len;
+ }
+ else
+ {
+ /* Extend the search key with the upper boundary for this range. */
+ memcpy(group_prefix + real_prefix_len, cur_range->max_key,
+ cur_range->max_length);
+ search_prefix_len= real_prefix_len + min_max_arg_len;
+ find_flag= (cur_range->flag & EQ_RANGE) ?
+ HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ?
+ HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV;
+ }
+
+ result= file->index_read(record, group_prefix, search_prefix_len,
+ find_flag);
+
+ if ((result == HA_ERR_KEY_NOT_FOUND) && (cur_range->flag & EQ_RANGE))
+ continue; /* Check the next range. */
+ else 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. */
+
+ /* 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;
+ }
+
+ /* If there is a lower limit, check if the found key is in the range. */
+ if ( !(cur_range->flag & NO_MIN_RANGE) )
+ {
+ /* Compose the MIN key for the range. */
+ byte *min_key= (byte*) my_alloca(real_prefix_len + min_max_arg_len);
+ memcpy(min_key, group_prefix, real_prefix_len);
+ memcpy(min_key + real_prefix_len, cur_range->min_key,
+ cur_range->min_length);
+ /* Compare the found key with min_key. */
+ int cmp_res= key_cmp(index_info->key_part, min_key,
+ real_prefix_len + min_max_arg_len);
+ if (!((cur_range->flag & NEAR_MIN) && (cmp_res == 1) ||
+ (cmp_res >= 0)))
+ continue;
+ }
+ /* If we got to this point, the current key qualifies as MAX. */
+ return result;
+ }
+ return HA_ERR_KEY_NOT_FOUND;
+}
+
+
+/*
+ Update all MIN function results with the newly found value.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::update_min_result()
+
+ DESCRIPTION
+ The method iterates through all MIN functions and updates the result value
+ of each function by calling Item_sum::reset(), which in turn picks the new
+ result value from this->head->record[0], previously updated by
+ next_min(). The updated value is stored in a member variable of each of the
+ Item_sum objects, depending on the value type.
+
+ IMPLEMENTATION
+ The update must be done separately for MIN and MAX, immediately after
+ next_min() was called and before next_max() is called, because both MIN and
+ MAX take their result value from the same buffer this->head->record[0]
+ (i.e. this->record).
+
+ RETURN
+ None
+*/
+
+void QUICK_GROUP_MIN_MAX_SELECT::update_min_result()
+{
+ Item_sum *min_func;
+
+ min_functions_it->rewind();
+ while ((min_func= (*min_functions_it)++))
+ min_func->reset();
+}
+
+
+/*
+ Update all MAX function results with the newly found value.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::update_max_result()
+
+ DESCRIPTION
+ The method iterates through all MAX functions and updates the result value
+ of each function by calling Item_sum::reset(), which in turn picks the new
+ result value from this->head->record[0], previously updated by
+ next_max(). The updated value is stored in a member variable of each of the
+ Item_sum objects, depending on the value type.
+
+ IMPLEMENTATION
+ The update must be done separately for MIN and MAX, immediately after
+ next_max() was called, because both MIN and MAX take their result value
+ from the same buffer this->head->record[0] (i.e. this->record).
+
+ RETURN
+ None
+*/
+
+void QUICK_GROUP_MIN_MAX_SELECT::update_max_result()
+{
+ Item_sum *max_func;
+
+ max_functions_it->rewind();
+ while ((max_func= (*max_functions_it)++))
+ max_func->reset();
+}
+
+
+/*
+ Append comma-separated list of keys this quick select uses to key_names;
+ append comma-separated list of corresponding used lengths to used_lengths.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths()
+ key_names [out] Names of used indexes
+ used_lengths [out] Corresponding lengths of the index names
+
+ DESCRIPTION
+ This method is used by select_describe to extract the names of the
+ indexes used by a quick select.
+
+*/
+
+void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names,
+ String *used_lengths)
+{
+ char buf[64];
+ uint length;
+ key_names->append(index_info->name);
+ length= longlong2str(max_used_key_length, buf, 10) - buf;
+ used_lengths->append(buf, length);
+}
+
+
+#ifndef DBUG_OFF
+
+static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map,
+ const char *msg)
+{
+ SEL_ARG **key,**end;
+ int idx;
+ char buff[1024];
+ DBUG_ENTER("print_sel_tree");
+ if (! _db_on_)
+ DBUG_VOID_RETURN;
+
+ String tmp(buff,sizeof(buff),&my_charset_bin);
+ tmp.length(0);
+ for (idx= 0,key=tree->keys, end=key+param->keys ;
+ key != end ;
+ key++,idx++)
+ {
+ if (tree_map->is_set(idx))
+ {
+ uint keynr= param->real_keynr[idx];
+ if (tmp.length())
+ tmp.append(',');
+ tmp.append(param->table->key_info[keynr].name);
+ }
+ }
+ if (!tmp.length())
+ tmp.append("(empty)");
+
+ DBUG_PRINT("info", ("SEL_TREE %p (%s) scans:%s", tree, msg, tmp.ptr()));
+
+ DBUG_VOID_RETURN;
+}
+
+
+static void print_ror_scans_arr(TABLE *table, const char *msg,
+ struct st_ror_scan_info **start,
+ struct st_ror_scan_info **end)
+{
+ DBUG_ENTER("print_ror_scans");
+ if (! _db_on_)
+ DBUG_VOID_RETURN;
+
+ char buff[1024];
+ String tmp(buff,sizeof(buff),&my_charset_bin);
+ tmp.length(0);
+ for(;start != end; start++)
+ {
+ if (tmp.length())
+ tmp.append(',');
+ tmp.append(table->key_info[(*start)->keynr].name);
+ }
+ if (!tmp.length())
+ tmp.append("(empty)");
+ DBUG_PRINT("info", ("ROR key scans (%s): %s", msg, tmp.ptr()));
+ DBUG_VOID_RETURN;
+}
+
+
/*****************************************************************************
** Print a quick range for debugging
** TODO:
@@ -2913,8 +8606,6 @@ bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range_arg,
** of locking the DEBUG stream !
*****************************************************************************/
-#ifndef DBUG_OFF
-
static void
print_key(KEY_PART *key_part,const char *key,uint used_length)
{
@@ -2938,8 +8629,11 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
key++; // Skip null byte
store_length--;
}
- field->set_key_image((char*) key, key_part->length, field->charset());
- field->val_str(&tmp);
+ field->set_key_image((char*) key, key_part->length);
+ if (field->type() == MYSQL_TYPE_BIT)
+ (void) field->val_int_as_str(&tmp, 1);
+ else
+ field->val_str(&tmp);
fwrite(tmp.ptr(),sizeof(char),tmp.length(),DBUG_FILE);
if (key+store_length < key_end)
fputc('/',DBUG_FILE);
@@ -2947,48 +8641,166 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
}
-static void print_quick(QUICK_SELECT *quick,const key_map* needed_reg)
+static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg)
{
- QUICK_RANGE *range;
char buf[MAX_KEY/8+1];
- DBUG_ENTER("print_param");
+ DBUG_ENTER("print_quick");
if (! _db_on_ || !quick)
DBUG_VOID_RETURN;
+ DBUG_LOCK_FILE;
+
+ quick->dbug_dump(0, TRUE);
+ fprintf(DBUG_FILE,"other_keys: 0x%s:\n", needed_reg->print(buf));
+
+ DBUG_UNLOCK_FILE;
+ DBUG_VOID_RETURN;
+}
+
- List_iterator<QUICK_RANGE> li(quick->ranges);
+static void print_rowid(byte* val, int len)
+{
+ byte *pb;
DBUG_LOCK_FILE;
- fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: 0x%s):\n",
- quick->index, needed_reg->print(buf));
- while ((range=li++))
+ fputc('\"', DBUG_FILE);
+ for (pb= val; pb!= val + len; ++pb)
+ fprintf(DBUG_FILE, "%c", *pb);
+ fprintf(DBUG_FILE, "\", hex: ");
+
+ for (pb= val; pb!= val + len; ++pb)
+ fprintf(DBUG_FILE, "%x ", *pb);
+ fputc('\n', DBUG_FILE);
+ DBUG_UNLOCK_FILE;
+}
+
+void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
+{
+ fprintf(DBUG_FILE, "%*squick range select, key %s, length: %d\n",
+ indent, "", head->key_info[index].name, max_used_key_length);
+
+ if (verbose)
{
- if (!(range->flag & NO_MIN_RANGE))
+ QUICK_RANGE *range;
+ QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer;
+ QUICK_RANGE **last_range= pr + ranges.elements;
+ for (; pr!=last_range; ++pr)
{
- print_key(quick->key_parts,range->min_key,range->min_length);
- if (range->flag & NEAR_MIN)
- fputs(" < ",DBUG_FILE);
- else
- fputs(" <= ",DBUG_FILE);
- }
- fputs("X",DBUG_FILE);
+ fprintf(DBUG_FILE, "%*s", indent + 2, "");
+ range= *pr;
+ if (!(range->flag & NO_MIN_RANGE))
+ {
+ print_key(key_parts,range->min_key,range->min_length);
+ if (range->flag & NEAR_MIN)
+ fputs(" < ",DBUG_FILE);
+ else
+ fputs(" <= ",DBUG_FILE);
+ }
+ fputs("X",DBUG_FILE);
- if (!(range->flag & NO_MAX_RANGE))
- {
- if (range->flag & NEAR_MAX)
- fputs(" < ",DBUG_FILE);
- else
- fputs(" <= ",DBUG_FILE);
- print_key(quick->key_parts,range->max_key,range->max_length);
+ if (!(range->flag & NO_MAX_RANGE))
+ {
+ if (range->flag & NEAR_MAX)
+ fputs(" < ",DBUG_FILE);
+ else
+ fputs(" <= ",DBUG_FILE);
+ print_key(key_parts,range->max_key,range->max_length);
+ }
+ fputs("\n",DBUG_FILE);
}
- fputs("\n",DBUG_FILE);
}
- DBUG_UNLOCK_FILE;
- DBUG_VOID_RETURN;
}
-#endif
+void QUICK_INDEX_MERGE_SELECT::dbug_dump(int indent, bool verbose)
+{
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ QUICK_RANGE_SELECT *quick;
+ fprintf(DBUG_FILE, "%*squick index_merge select\n", indent, "");
+ fprintf(DBUG_FILE, "%*smerged scans {\n", indent, "");
+ while ((quick= it++))
+ quick->dbug_dump(indent+2, verbose);
+ if (pk_quick_select)
+ {
+ fprintf(DBUG_FILE, "%*sclustered PK quick:\n", indent, "");
+ pk_quick_select->dbug_dump(indent+2, verbose);
+ }
+ fprintf(DBUG_FILE, "%*s}\n", indent, "");
+}
+
+void QUICK_ROR_INTERSECT_SELECT::dbug_dump(int indent, bool verbose)
+{
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ QUICK_RANGE_SELECT *quick;
+ fprintf(DBUG_FILE, "%*squick ROR-intersect select, %scovering\n",
+ indent, "", need_to_fetch_row? "":"non-");
+ fprintf(DBUG_FILE, "%*smerged scans {\n", indent, "");
+ while ((quick= it++))
+ quick->dbug_dump(indent+2, verbose);
+ if (cpk_quick)
+ {
+ fprintf(DBUG_FILE, "%*sclustered PK quick:\n", indent, "");
+ cpk_quick->dbug_dump(indent+2, verbose);
+ }
+ fprintf(DBUG_FILE, "%*s}\n", indent, "");
+}
+
+void QUICK_ROR_UNION_SELECT::dbug_dump(int indent, bool verbose)
+{
+ List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
+ QUICK_SELECT_I *quick;
+ fprintf(DBUG_FILE, "%*squick ROR-union select\n", indent, "");
+ fprintf(DBUG_FILE, "%*smerged scans {\n", indent, "");
+ while ((quick= it++))
+ quick->dbug_dump(indent+2, verbose);
+ fprintf(DBUG_FILE, "%*s}\n", indent, "");
+}
+
+
+/*
+ Print quick select information to DBUG_FILE.
+
+ SYNOPSIS
+ QUICK_GROUP_MIN_MAX_SELECT::dbug_dump()
+ indent Indentation offset
+ verbose If TRUE show more detailed output.
+
+ DESCRIPTION
+ Print the contents of this quick select to DBUG_FILE. The method also
+ calls dbug_dump() for the used quick select if any.
+
+ IMPLEMENTATION
+ Caller is responsible for locking DBUG_FILE before this call and unlocking
+ it afterwards.
+
+ RETURN
+ None
+*/
+
+void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose)
+{
+ fprintf(DBUG_FILE,
+ "%*squick_group_min_max_select: index %s (%d), length: %d\n",
+ indent, "", index_info->name, index, max_used_key_length);
+ if (key_infix_len > 0)
+ {
+ fprintf(DBUG_FILE, "%*susing key_infix with length %d:\n",
+ indent, "", key_infix_len);
+ }
+ if (quick_prefix_select)
+ {
+ fprintf(DBUG_FILE, "%*susing quick_range_select:\n", indent, "");
+ quick_prefix_select->dbug_dump(indent + 2, verbose);
+ }
+ if (min_max_ranges.elements > 0)
+ {
+ fprintf(DBUG_FILE, "%*susing %d quick_ranges for MIN/MAX:\n",
+ indent, "", min_max_ranges.elements);
+ }
+}
+
+
+#endif /* NOT_USED */
/*****************************************************************************
-** Instansiate templates
+** Instantiate templates
*****************************************************************************/
#ifdef __GNUC__
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 5a2044a59f4..97d646cedbe 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -24,16 +24,6 @@
#pragma interface /* gcc class implementation */
#endif
-#define NO_MIN_RANGE 1
-#define NO_MAX_RANGE 2
-#define NEAR_MIN 4
-#define NEAR_MAX 8
-#define UNIQUE_RANGE 16
-#define EQ_RANGE 32
-#define NULL_RANGE 64
-#define GEOM_FLAG 128
-
-
typedef struct st_key_part {
uint16 key,part, store_length, length;
uint8 null_bit;
@@ -66,61 +56,618 @@ class QUICK_RANGE :public Sql_alloc {
};
-class QUICK_SELECT {
+/*
+ Quick select interface.
+ This class is a parent for all QUICK_*_SELECT and FT_SELECT classes.
+
+ The usage scenario is as follows:
+ 1. Create quick select
+ quick= new QUICK_XXX_SELECT(...);
+
+ 2. Perform lightweight initialization. This can be done in 2 ways:
+ 2.a: Regular initialization
+ if (quick->init())
+ {
+ //the only valid action after failed init() call is delete
+ delete quick;
+ }
+ 2.b: Special initialization for quick selects merged by QUICK_ROR_*_SELECT
+ if (quick->init_ror_merged_scan())
+ delete quick;
+
+ 3. Perform zero, one, or more scans.
+ while (...)
+ {
+ // initialize quick select for scan. This may allocate
+ // buffers and/or prefetch rows.
+ if (quick->reset())
+ {
+ //the only valid action after failed reset() call is delete
+ delete quick;
+ //abort query
+ }
+
+ // perform the scan
+ do
+ {
+ res= quick->get_next();
+ } while (res && ...)
+ }
+
+ 4. Delete the select:
+ delete quick;
+
+*/
+
+class QUICK_SELECT_I
+{
+public:
+ bool sorted;
+ ha_rows records; /* estimate of # of records to be retrieved */
+ double read_time; /* time to perform this retrieval */
+ TABLE *head;
+ /*
+ Index this quick select uses, or MAX_KEY for quick selects
+ that use several indexes
+ */
+ uint index;
+
+ /*
+ Total length of first used_key_parts parts of the key.
+ Applicable if index!= MAX_KEY.
+ */
+ uint max_used_key_length;
+
+ /*
+ Max. number of (first) key parts this quick select uses for retrieval.
+ eg. for "(key1p1=c1 AND key1p2=c2) OR key1p1=c2" used_key_parts == 2.
+ Applicable if index!= MAX_KEY.
+ */
+ uint used_key_parts;
+
+ QUICK_SELECT_I();
+ virtual ~QUICK_SELECT_I(){};
+
+ /*
+ Do post-constructor initialization.
+ SYNOPSIS
+ init()
+
+ init() performs initializations that should have been in constructor if
+ it was possible to return errors from constructors. The join optimizer may
+ create and then delete quick selects without retrieving any rows so init()
+ must not contain any IO or CPU intensive code.
+
+ If init() call fails the only valid action is to delete this quick select,
+ reset() and get_next() must not be called.
+
+ RETURN
+ 0 OK
+ other Error code
+ */
+ virtual int init() = 0;
+
+ /*
+ Initialize quick select for row retrieval.
+ SYNOPSIS
+ reset()
+
+ reset() should be called when it is certain that row retrieval will be
+ necessary. This call may do heavyweight initialization like buffering first
+ N records etc. If reset() call fails get_next() must not be called.
+ Note that reset() may be called several times if
+ * the quick select is executed in a subselect
+ * a JOIN buffer is used
+
+ RETURN
+ 0 OK
+ other Error code
+ */
+ virtual int reset(void) = 0;
+
+ virtual int get_next() = 0; /* get next record to retrieve */
+
+ /* Range end should be called when we have looped over the whole index */
+ virtual void range_end() {}
+
+ virtual bool reverse_sorted() = 0;
+ virtual bool unique_key_range() { return false; }
+
+ enum {
+ QS_TYPE_RANGE = 0,
+ QS_TYPE_INDEX_MERGE = 1,
+ QS_TYPE_RANGE_DESC = 2,
+ QS_TYPE_FULLTEXT = 3,
+ QS_TYPE_ROR_INTERSECT = 4,
+ QS_TYPE_ROR_UNION = 5,
+ QS_TYPE_GROUP_MIN_MAX = 6
+ };
+
+ /* Get type of this quick select - one of the QS_TYPE_* values */
+ virtual int get_type() = 0;
+
+ /*
+ Initialize this quick select as a merged scan inside a ROR-union or a ROR-
+ intersection scan. The caller must not additionally call init() if this
+ function is called.
+ SYNOPSIS
+ init_ror_merged_scan()
+ reuse_handler If true, the quick select may use table->handler, otherwise
+ it must create and use a separate handler object.
+ RETURN
+ 0 Ok
+ other Error
+ */
+ virtual int init_ror_merged_scan(bool reuse_handler)
+ { DBUG_ASSERT(0); return 1; }
+
+ /*
+ Save ROWID of last retrieved row in file->ref. This used in ROR-merging.
+ */
+ virtual void save_last_pos(){};
+
+ /*
+ Append comma-separated list of keys this quick select uses to key_names;
+ append comma-separated list of corresponding used lengths to used_lengths.
+ This is used by select_describe.
+ */
+ virtual void add_keys_and_lengths(String *key_names,
+ String *used_lengths)=0;
+
+ /*
+ Append text representation of quick select structure (what and how is
+ merged) to str. The result is added to "Extra" field in EXPLAIN output.
+ This function is implemented only by quick selects that merge other quick
+ selects output and/or can produce output suitable for merging.
+ */
+ virtual void add_info_string(String *str) {};
+ /*
+ Return 1 if any index used by this quick select
+ a) uses field that is listed in passed field list or
+ b) is automatically updated (like a timestamp)
+ */
+ virtual bool check_if_keys_used(List<Item> *fields);
+
+ /*
+ rowid of last row retrieved by this quick select. This is used only when
+ doing ROR-index_merge selects
+ */
+ byte *last_rowid;
+
+ /*
+ Table record buffer used by this quick select.
+ */
+ byte *record;
+#ifndef DBUG_OFF
+ /*
+ Print quick select information to DBUG_FILE. Caller is responsible
+ for locking DBUG_FILE before this call and unlocking it afterwards.
+ */
+ virtual void dbug_dump(int indent, bool verbose)= 0;
+#endif
+};
+
+
+struct st_qsel_param;
+class SEL_ARG;
+
+/*
+ Quick select that does a range scan on a single key. The records are
+ returned in key order.
+*/
+class QUICK_RANGE_SELECT : public QUICK_SELECT_I
+{
+protected:
+ bool next,dont_free;
public:
- bool next,dont_free,sorted;
int error;
- uint index, max_used_key_length, used_key_parts;
- TABLE *head;
+protected:
handler *file;
- byte *record;
- List<QUICK_RANGE> ranges;
- List_iterator<QUICK_RANGE> it;
- QUICK_RANGE *range;
- MEM_ROOT alloc;
+ /*
+ If true, this quick select has its "own" handler object which should be
+ closed no later then this quick select is deleted.
+ */
+ bool free_file;
+ bool in_range;
+ uint multi_range_count; /* copy from thd->variables.multi_range_count */
+ uint multi_range_length; /* the allocated length for the array */
+ uint multi_range_bufsiz; /* copy from thd->variables.read_rnd_buff_size */
+ KEY_MULTI_RANGE *multi_range; /* the multi-range array (allocated and
+ freed by QUICK_RANGE_SELECT) */
+ HANDLER_BUFFER *multi_range_buff; /* the handler buffer (allocated and
+ freed by QUICK_RANGE_SELECT) */
+protected:
+ friend class TRP_ROR_INTERSECT;
+ friend
+ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
+ struct st_table_ref *ref);
+ friend bool get_quick_keys(struct st_qsel_param *param,
+ QUICK_RANGE_SELECT *quick,KEY_PART *key,
+ SEL_ARG *key_tree,
+ char *min_key, uint min_key_flag,
+ char *max_key, uint max_key_flag);
+ friend QUICK_RANGE_SELECT *get_quick_select(struct st_qsel_param*,uint idx,
+ SEL_ARG *key_tree,
+ MEM_ROOT *alloc);
+ friend class QUICK_SELECT_DESC;
+ friend class QUICK_INDEX_MERGE_SELECT;
+ friend class QUICK_ROR_INTERSECT_SELECT;
+
+ DYNAMIC_ARRAY ranges; /* ordered array of range ptrs */
+ QUICK_RANGE **cur_range; /* current element in ranges */
+
+ QUICK_RANGE *range;
KEY_PART *key_parts;
KEY_PART_INFO *key_part_info;
- ha_rows records;
- double read_time;
+ int cmp_next(QUICK_RANGE *range);
+ int cmp_prev(QUICK_RANGE *range);
+ bool row_in_ranges();
+public:
+ MEM_ROOT alloc;
- QUICK_SELECT(THD *thd, TABLE *table,uint index_arg,bool no_alloc=0);
- virtual ~QUICK_SELECT();
- void reset(void) { next=0; it.rewind(); }
- int init()
+ QUICK_RANGE_SELECT(THD *thd, TABLE *table,uint index_arg,bool no_alloc=0,
+ MEM_ROOT *parent_alloc=NULL);
+ ~QUICK_RANGE_SELECT();
+
+ int init();
+ int reset(void);
+ int get_next();
+ void range_end();
+ int get_next_prefix(uint prefix_length, byte *cur_prefix);
+ bool reverse_sorted() { return 0; }
+ bool unique_key_range();
+ int init_ror_merged_scan(bool reuse_handler);
+ void save_last_pos()
+ { file->position(record); }
+ int get_type() { return QS_TYPE_RANGE; }
+ void add_keys_and_lengths(String *key_names, String *used_lengths);
+ void add_info_string(String *str);
+#ifndef DBUG_OFF
+ void dbug_dump(int indent, bool verbose);
+#endif
+private:
+ /* Used only by QUICK_SELECT_DESC */
+ QUICK_RANGE_SELECT(const QUICK_RANGE_SELECT& org) : QUICK_SELECT_I()
{
- key_part_info= head->key_info[index].key_part;
- return error=file->ha_index_init(index);
+ bcopy(&org, this, sizeof(*this));
+ multi_range_length= 0;
+ multi_range= NULL;
+ multi_range_buff= NULL;
}
- virtual int get_next();
- virtual bool reverse_sorted() { return 0; }
- bool unique_key_range();
};
-class QUICK_SELECT_GEOM: public QUICK_SELECT
+class QUICK_RANGE_SELECT_GEOM: public QUICK_RANGE_SELECT
{
public:
- QUICK_SELECT_GEOM(THD *thd, TABLE *table, uint index_arg, bool no_alloc)
- :QUICK_SELECT(thd, table, index_arg, no_alloc)
+ QUICK_RANGE_SELECT_GEOM(THD *thd, TABLE *table, uint index_arg,
+ bool no_alloc, MEM_ROOT *parent_alloc)
+ :QUICK_RANGE_SELECT(thd, table, index_arg, no_alloc, parent_alloc)
{};
virtual int get_next();
};
-class QUICK_SELECT_DESC: public QUICK_SELECT
+/*
+ QUICK_INDEX_MERGE_SELECT - index_merge access method quick select.
+
+ QUICK_INDEX_MERGE_SELECT uses
+ * QUICK_RANGE_SELECTs to get rows
+ * Unique class to remove duplicate rows
+
+ INDEX MERGE OPTIMIZER
+ Current implementation doesn't detect all cases where index_merge could
+ be used, in particular:
+ * index_merge will never be used if range scan is possible (even if
+ range scan is more expensive)
+
+ * index_merge+'using index' is not supported (this the consequence of
+ the above restriction)
+
+ * If WHERE part contains complex nested AND and OR conditions, some ways
+ to retrieve rows using index_merge will not be considered. The choice
+ of read plan may depend on the order of conjuncts/disjuncts in WHERE
+ part of the query, see comments near imerge_list_or_list and
+ SEL_IMERGE::or_sel_tree_with_checks functions for details.
+
+ * There is no "index_merge_ref" method (but index_merge on non-first
+ table in join is possible with 'range checked for each record').
+
+ See comments around SEL_IMERGE class and test_quick_select for more
+ details.
+
+ ROW RETRIEVAL ALGORITHM
+
+ index_merge uses Unique class for duplicates removal. index_merge takes
+ advantage of Clustered Primary Key (CPK) if the table has one.
+ The index_merge algorithm consists of two phases:
+
+ Phase 1 (implemented in QUICK_INDEX_MERGE_SELECT::prepare_unique):
+ prepare()
+ {
+ activate 'index only';
+ while(retrieve next row for non-CPK scan)
+ {
+ if (there is a CPK scan and row will be retrieved by it)
+ skip this row;
+ else
+ put its rowid into Unique;
+ }
+ deactivate 'index only';
+ }
+
+ Phase 2 (implemented as sequence of QUICK_INDEX_MERGE_SELECT::get_next
+ calls):
+
+ fetch()
+ {
+ retrieve all rows from row pointers stored in Unique;
+ free Unique;
+ retrieve all rows for CPK scan;
+ }
+*/
+
+class QUICK_INDEX_MERGE_SELECT : public QUICK_SELECT_I
+{
+public:
+ QUICK_INDEX_MERGE_SELECT(THD *thd, TABLE *table);
+ ~QUICK_INDEX_MERGE_SELECT();
+
+ int init();
+ int reset(void);
+ int get_next();
+ bool reverse_sorted() { return false; }
+ bool unique_key_range() { return false; }
+ int get_type() { return QS_TYPE_INDEX_MERGE; }
+ void add_keys_and_lengths(String *key_names, String *used_lengths);
+ void add_info_string(String *str);
+ bool check_if_keys_used(List<Item> *fields);
+#ifndef DBUG_OFF
+ void dbug_dump(int indent, bool verbose);
+#endif
+
+ bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
+
+ /* range quick selects this index_merge read consists of */
+ List<QUICK_RANGE_SELECT> quick_selects;
+
+ /* quick select that uses clustered primary key (NULL if none) */
+ QUICK_RANGE_SELECT* pk_quick_select;
+
+ /* true if this select is currently doing a clustered PK scan */
+ bool doing_pk_scan;
+
+ MEM_ROOT alloc;
+ THD *thd;
+ int read_keys_and_merge();
+
+ /* used to get rows collected in Unique */
+ READ_RECORD read_record;
+};
+
+
+/*
+ Rowid-Ordered Retrieval (ROR) index intersection quick select.
+ This quick select produces intersection of row sequences returned
+ by several QUICK_RANGE_SELECTs it "merges".
+
+ All merged QUICK_RANGE_SELECTs must return rowids in rowid order.
+ QUICK_ROR_INTERSECT_SELECT will return rows in rowid order, too.
+
+ All merged quick selects retrieve {rowid, covered_fields} tuples (not full
+ table records).
+ QUICK_ROR_INTERSECT_SELECT retrieves full records if it is not being used
+ by QUICK_ROR_INTERSECT_SELECT and all merged quick selects together don't
+ cover needed all fields.
+
+ If one of the merged quick selects is a Clustered PK range scan, it is
+ used only to filter rowid sequence produced by other merged quick selects.
+*/
+
+class QUICK_ROR_INTERSECT_SELECT : public QUICK_SELECT_I
+{
+public:
+ QUICK_ROR_INTERSECT_SELECT(THD *thd, TABLE *table,
+ bool retrieve_full_rows,
+ MEM_ROOT *parent_alloc);
+ ~QUICK_ROR_INTERSECT_SELECT();
+
+ int init();
+ int reset(void);
+ int get_next();
+ bool reverse_sorted() { return false; }
+ bool unique_key_range() { return false; }
+ int get_type() { return QS_TYPE_ROR_INTERSECT; }
+ void add_keys_and_lengths(String *key_names, String *used_lengths);
+ void add_info_string(String *str);
+ bool check_if_keys_used(List<Item> *fields);
+#ifndef DBUG_OFF
+ void dbug_dump(int indent, bool verbose);
+#endif
+ int init_ror_merged_scan(bool reuse_handler);
+ bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
+
+ /*
+ Range quick selects this intersection consists of, not including
+ cpk_quick.
+ */
+ List<QUICK_RANGE_SELECT> quick_selects;
+
+ /*
+ Merged quick select that uses Clustered PK, if there is one. This quick
+ select is not used for row retrieval, it is used for row retrieval.
+ */
+ QUICK_RANGE_SELECT *cpk_quick;
+
+ MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */
+ THD *thd; /* current thread */
+ bool need_to_fetch_row; /* if true, do retrieve full table records. */
+ /* in top-level quick select, true if merged scans where initialized */
+ bool scans_inited;
+};
+
+
+/*
+ Rowid-Ordered Retrieval index union select.
+ This quick select produces union of row sequences returned by several
+ quick select it "merges".
+
+ All merged quick selects must return rowids in rowid order.
+ QUICK_ROR_UNION_SELECT will return rows in rowid order, too.
+
+ All merged quick selects are set not to retrieve full table records.
+ ROR-union quick select always retrieves full records.
+
+*/
+
+class QUICK_ROR_UNION_SELECT : public QUICK_SELECT_I
{
public:
- QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts);
+ QUICK_ROR_UNION_SELECT(THD *thd, TABLE *table);
+ ~QUICK_ROR_UNION_SELECT();
+
+ int init();
+ int reset(void);
+ int get_next();
+ bool reverse_sorted() { return false; }
+ bool unique_key_range() { return false; }
+ int get_type() { return QS_TYPE_ROR_UNION; }
+ void add_keys_and_lengths(String *key_names, String *used_lengths);
+ void add_info_string(String *str);
+ bool check_if_keys_used(List<Item> *fields);
+#ifndef DBUG_OFF
+ void dbug_dump(int indent, bool verbose);
+#endif
+
+ bool push_quick_back(QUICK_SELECT_I *quick_sel_range);
+
+ List<QUICK_SELECT_I> quick_selects; /* Merged quick selects */
+
+ QUEUE queue; /* Priority queue for merge operation */
+ MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */
+
+ THD *thd; /* current thread */
+ byte *cur_rowid; /* buffer used in get_next() */
+ byte *prev_rowid; /* rowid of last row returned by get_next() */
+ bool have_prev_rowid; /* true if prev_rowid has valid data */
+ uint rowid_length; /* table rowid length */
+private:
+ static int queue_cmp(void *arg, byte *val1, byte *val2);
+ bool scans_inited;
+};
+
+
+/*
+ Index scan for GROUP-BY queries with MIN/MAX aggregate functions.
+
+ This class provides a specialized index access method for GROUP-BY queries
+ of the forms:
+
+ SELECT A_1,...,A_k, [B_1,...,B_m], [MIN(C)], [MAX(C)]
+ FROM T
+ WHERE [RNG(A_1,...,A_p ; where p <= k)]
+ [AND EQ(B_1,...,B_m)]
+ [AND PC(C)]
+ [AND PA(A_i1,...,A_iq)]
+ GROUP BY A_1,...,A_k;
+
+ or
+
+ SELECT DISTINCT A_i1,...,A_ik
+ FROM T
+ WHERE [RNG(A_1,...,A_p ; where p <= k)]
+ [AND PA(A_i1,...,A_iq)];
+
+ where all selected fields are parts of the same index.
+ The class of queries that can be processed by this quick select is fully
+ specified in the description of get_best_trp_group_min_max() in opt_range.cc.
+
+ The get_next() method directly produces result tuples, thus obviating the
+ need to call end_send_group() because all grouping is already done inside
+ get_next().
+
+ Since one of the requirements is that all select fields are part of the same
+ index, this class produces only index keys, and not complete records.
+*/
+
+class QUICK_GROUP_MIN_MAX_SELECT : public QUICK_SELECT_I
+{
+private:
+ handler *file; /* The handler used to get data. */
+ JOIN *join; /* Descriptor of the current query */
+ KEY *index_info; /* The index chosen for data access */
+ byte *record; /* Buffer where the next record is returned. */
+ byte *tmp_record; /* Temporary storage for next_min(), next_max(). */
+ byte *group_prefix; /* Key prefix consisting of the GROUP fields. */
+ uint group_prefix_len; /* Length of the group prefix. */
+ byte *last_prefix; /* Prefix of the last group for detecting EOF. */
+ bool have_min; /* Specify whether we are computing */
+ bool have_max; /* a MIN, a MAX, or both. */
+ bool seen_first_key; /* Denotes whether the first key was retrieved.*/
+ KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */
+ /* of all MIN/MAX functions. */
+ uint min_max_arg_len; /* The length of the MIN/MAX argument field */
+ byte *key_infix; /* Infix of constants from equality predicates. */
+ uint key_infix_len;
+ DYNAMIC_ARRAY min_max_ranges; /* Array of range ptrs for the MIN/MAX field. */
+ uint real_prefix_len; /* Length of key prefix extended with key_infix. */
+ List<Item_sum> *min_functions;
+ List<Item_sum> *max_functions;
+ List_iterator<Item_sum> *min_functions_it;
+ List_iterator<Item_sum> *max_functions_it;
+public:
+ /*
+ The following two members are public to allow easy access from
+ TRP_GROUP_MIN_MAX::make_quick()
+ */
+ MEM_ROOT alloc; /* Memory pool for this and quick_prefix_select data. */
+ QUICK_RANGE_SELECT *quick_prefix_select;/* For retrieval of group prefixes. */
+private:
+ int next_prefix();
+ int next_min_in_range();
+ int next_max_in_range();
+ int next_min();
+ int next_max();
+ void update_min_result();
+ void update_max_result();
+public:
+ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
+ bool have_max, KEY_PART_INFO *min_max_arg_part,
+ uint group_prefix_len, uint used_key_parts,
+ KEY *index_info, uint use_index, double read_cost,
+ ha_rows records, uint key_infix_len,
+ byte *key_infix, MEM_ROOT *parent_alloc);
+ ~QUICK_GROUP_MIN_MAX_SELECT();
+ bool add_range(SEL_ARG *sel_range);
+ void update_key_stat();
+ bool alloc_buffers();
+ int init();
+ int reset();
+ int get_next();
+ bool reverse_sorted() { return false; }
+ bool unique_key_range() { return false; }
+ int get_type() { return QS_TYPE_GROUP_MIN_MAX; }
+ void add_keys_and_lengths(String *key_names, String *used_lengths);
+#ifndef DBUG_OFF
+ void dbug_dump(int indent, bool verbose);
+#endif
+};
+
+
+class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT
+{
+public:
+ QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, uint used_key_parts);
int get_next();
bool reverse_sorted() { return 1; }
+ int get_type() { return QS_TYPE_RANGE_DESC; }
private:
- int cmp_prev(QUICK_RANGE *range);
bool range_reads_after_key(QUICK_RANGE *range);
#ifdef NOT_USED
bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts);
#endif
- void reset(void) { next=0; rev_it.rewind(); }
+ int reset(void) { next=0; rev_it.rewind(); return 0; }
List<QUICK_RANGE> rev_ranges;
List_iterator<QUICK_RANGE> rev_it;
};
@@ -128,7 +675,7 @@ private:
class SQL_SELECT :public Sql_alloc {
public:
- QUICK_SELECT *quick; // If quick-select used
+ QUICK_SELECT_I *quick; // If quick-select used
COND *cond; // where condition
TABLE *head;
IO_CACHE file; // Positions to used records
@@ -150,17 +697,17 @@ class SQL_SELECT :public Sql_alloc {
};
-class FT_SELECT: public QUICK_SELECT {
+class FT_SELECT: public QUICK_RANGE_SELECT {
public:
- FT_SELECT(THD *thd, TABLE *table, uint key):
- QUICK_SELECT (thd, table, key, 1) { init(); }
+ FT_SELECT(THD *thd, TABLE *table, uint key) :
+ QUICK_RANGE_SELECT (thd, table, key, 1) { init(); }
~FT_SELECT() { file->ft_end(); }
- int init() { return error= file->ft_init(); }
- int get_next() { return error= file->ft_read(record); }
+ int init() { return error=file->ft_init(); }
+ int reset() { return 0; }
+ int get_next() { return error=file->ft_read(record); }
+ int get_type() { return QS_TYPE_FULLTEXT; }
};
-
-QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
- struct st_table_ref *ref);
-
+QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
+ struct st_table_ref *ref);
#endif
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 4ab506cc4e1..134d3564ef8 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -59,9 +59,9 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond);
SYNOPSIS
opt_sum_query()
- tables Tables in query
- all_fields All fields to be returned
- conds WHERE clause
+ tables list of leaves of join table tree
+ all_fields All fields to be returned
+ conds WHERE clause
NOTE:
This function is only called for queries with sum functions and no
@@ -89,7 +89,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
where_tables= conds->used_tables();
/* Don't replace expression on a table that is part of an outer join */
- for (TABLE_LIST *tl=tables; tl ; tl= tl->next)
+ for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf)
{
if (tl->on_expr)
{
@@ -128,10 +128,10 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
{
longlong count= 1;
TABLE_LIST *table;
- for (table=tables ; table ; table=table->next)
+ for (table= tables; table; table= table->next_leaf)
{
if (outer_tables || (table->table->file->table_flags() &
- HA_NOT_EXACT_COUNT))
+ HA_NOT_EXACT_COUNT) || table->schema_table)
{
const_result= 0; // Can't optimize left join
break;
@@ -332,11 +332,23 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
1 Otherwise
*/
-static bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
+bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
{
Item *item;
*inv_order= 0;
switch (func_item->argument_count()) {
+ case 0:
+ /* MULT_EQUAL_FUNC */
+ {
+ Item_equal *item_equal= (Item_equal *) func_item;
+ Item_equal_iterator it(*item_equal);
+ args[0]= it++;
+ if (it++)
+ return 0;
+ if (!(args[1]= item_equal->get_const()))
+ return 0;
+ }
+ break;
case 1:
/* field IS NULL */
item= func_item->arguments()[0];
@@ -477,6 +489,9 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
case Item_func::BETWEEN:
between= 1;
break;
+ case Item_func::MULT_EQUAL_FUNC:
+ eq_type= 1;
+ break;
default:
return 0; // Can't optimize function
}
@@ -547,8 +562,7 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
store_val_in_field(part->field, args[between && max_fl ? 2 : 1]);
if (part->null_bit)
*key_ptr++= (byte) test(part->field->is_null());
- part->field->get_key_image((char*) key_ptr, part->length,
- part->field->charset(), Field::itRAW);
+ part->field->get_key_image((char*) key_ptr, part->length, Field::itRAW);
}
if (is_field_part)
{
@@ -629,7 +643,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
uint idx= 0;
KEY *keyinfo,*keyinfo_end;
- for (keyinfo= table->key_info, keyinfo_end= keyinfo+table->keys ;
+ for (keyinfo= table->key_info, keyinfo_end= keyinfo+table->s->keys ;
keyinfo != keyinfo_end;
keyinfo++,idx++)
{
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
new file mode 100644
index 00000000000..6c3a81384a6
--- /dev/null
+++ b/sql/parse_file.cc
@@ -0,0 +1,772 @@
+/* Copyright (C) 2004 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 */
+
+// Text .frm files management routines
+
+#include "mysql_priv.h"
+#include <errno.h>
+#include <m_ctype.h>
+#include <my_sys.h>
+#include <my_dir.h>
+
+
+/*
+ write string with escaping
+
+ SYNOPSIS
+ write_escaped_string()
+ file - IO_CACHE for record
+ val_s - string for writing
+
+ RETURN
+ FALSE - OK
+ TRUE - error
+*/
+
+static my_bool
+write_escaped_string(IO_CACHE *file, LEX_STRING *val_s)
+{
+ char *eos= val_s->str + val_s->length;
+ char *ptr= val_s->str;
+
+ for (; ptr < eos; ptr++)
+ {
+ /*
+ Should be in sync with read_escaped_string() and
+ parse_quoted_escaped_string()
+ */
+ switch(*ptr) {
+ case '\\': // escape character
+ if (my_b_append(file, (const byte *)"\\\\", 2))
+ return TRUE;
+ break;
+ case '\n': // parameter value delimiter
+ if (my_b_append(file, (const byte *)"\\n", 2))
+ return TRUE;
+ break;
+ case '\0': // problem for some string processing utilities
+ if (my_b_append(file, (const byte *)"\\0", 2))
+ return TRUE;
+ break;
+ case 26: // problem for windows utilities (Ctrl-Z)
+ if (my_b_append(file, (const byte *)"\\z", 2))
+ return TRUE;
+ break;
+ case '\'': // list of string delimiter
+ if (my_b_append(file, (const byte *)"\\\'", 2))
+ return TRUE;
+ break;
+ default:
+ if (my_b_append(file, (const byte *)ptr, 1))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*
+ write parameter value to IO_CACHE
+
+ SYNOPSIS
+ write_parameter()
+ file pointer to IO_CACHE structure for writing
+ base pointer to data structure
+ parameter pointer to parameter descriptor
+ old_version for returning back old version number value
+
+ RETURN
+ FALSE - OK
+ TRUE - error
+*/
+
+static my_bool
+write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
+ ulonglong *old_version)
+{
+ char num_buf[20]; // buffer for numeric operations
+ // string for numeric operations
+ String num(num_buf, sizeof(num_buf), &my_charset_bin);
+ DBUG_ENTER("write_parameter");
+
+ switch (parameter->type) {
+ case FILE_OPTIONS_STRING:
+ {
+ LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
+ if (my_b_append(file, (const byte *)val_s->str, val_s->length))
+ DBUG_RETURN(TRUE);
+ break;
+ }
+ case FILE_OPTIONS_ESTRING:
+ {
+ if (write_escaped_string(file, (LEX_STRING *)(base + parameter->offset)))
+ DBUG_RETURN(TRUE);
+ break;
+ }
+ case FILE_OPTIONS_ULONGLONG:
+ {
+ num.set(*((ulonglong *)(base + parameter->offset)), &my_charset_bin);
+ if (my_b_append(file, (const byte *)num.ptr(), num.length()))
+ DBUG_RETURN(TRUE);
+ break;
+ }
+ case FILE_OPTIONS_REV:
+ {
+ ulonglong *val_i= (ulonglong *)(base + parameter->offset);
+ *old_version= (*val_i)++;
+ num.set(*val_i, &my_charset_bin);
+ if (my_b_append(file, (const byte *)num.ptr(), num.length()))
+ DBUG_RETURN(TRUE);
+ break;
+ }
+ case FILE_OPTIONS_TIMESTAMP:
+ {
+ /* string have to be allocated already */
+ LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
+ time_t tm= time(NULL);
+
+ get_date(val_s->str, GETDATE_DATE_TIME|GETDATE_GMT|GETDATE_FIXEDLENGTH,
+ tm);
+ val_s->length= PARSE_FILE_TIMESTAMPLENGTH;
+ if (my_b_append(file, (const byte *)val_s->str,
+ PARSE_FILE_TIMESTAMPLENGTH))
+ DBUG_RETURN(TRUE);
+ break;
+ }
+ case FILE_OPTIONS_STRLIST:
+ {
+ List_iterator_fast<LEX_STRING> it(*((List<LEX_STRING>*)
+ (base + parameter->offset)));
+ bool first= 1;
+ LEX_STRING *str;
+ while ((str= it++))
+ {
+ // We need ' ' after string to detect list continuation
+ if ((!first && my_b_append(file, (const byte *)" ", 1)) ||
+ my_b_append(file, (const byte *)"\'", 1) ||
+ write_escaped_string(file, str) ||
+ my_b_append(file, (const byte *)"\'", 1))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ first= 0;
+ }
+ break;
+ }
+ default:
+ DBUG_ASSERT(0); // never should happened
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ write new .frm
+
+ SYNOPSIS
+ sql_create_definition_file()
+ dir directory where put .frm
+ file .frm file name
+ type .frm type string (VIEW, TABLE)
+ base base address for parameter reading (structure like
+ TABLE)
+ parameters parameters description
+ max_versions number of versions to save
+
+ RETURN
+ FALSE - OK
+ TRUE - error
+*/
+
+my_bool
+sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
+ const LEX_STRING *type,
+ gptr base, File_option *parameters,
+ uint max_versions)
+{
+ File handler;
+ IO_CACHE file;
+ char path[FN_REFLEN+1]; // +1 to put temporary file name for sure
+ ulonglong old_version= ULONGLONG_MAX;
+ int path_end;
+ File_option *param;
+ DBUG_ENTER("sql_create_definition_file");
+ DBUG_PRINT("enter", ("Dir: %s, file: %s, base 0x%lx",
+ dir->str, file_name->str, (ulong) base));
+
+ fn_format(path, file_name->str, dir->str, 0, MY_UNPACK_FILENAME);
+ path_end= strlen(path);
+
+ // temporary file name
+ path[path_end]='~';
+ path[path_end+1]= '\0';
+ if ((handler= my_create(path, CREATE_MODE, O_RDWR | O_TRUNC,
+ MYF(MY_WME))) <= 0)
+ {
+ DBUG_RETURN(TRUE);
+ }
+
+ if (init_io_cache(&file, handler, 0, SEQ_READ_APPEND, 0L, 0, MYF(MY_WME)))
+ goto err_w_file;
+
+ // write header (file signature)
+ if (my_b_append(&file, (const byte *)"TYPE=", 5) ||
+ my_b_append(&file, (const byte *)type->str, type->length) ||
+ my_b_append(&file, (const byte *)"\n", 1))
+ goto err_w_file;
+
+ // write parameters to temporary file
+ for (param= parameters; param->name.str; param++)
+ {
+ if (my_b_append(&file, (const byte *)param->name.str,
+ param->name.length) ||
+ my_b_append(&file, (const byte *)"=", 1) ||
+ write_parameter(&file, base, param, &old_version) ||
+ my_b_append(&file, (const byte *)"\n", 1))
+ goto err_w_cache;
+ }
+
+ if (end_io_cache(&file))
+ goto err_w_file;
+
+ if (my_close(handler, MYF(MY_WME)))
+ {
+ DBUG_RETURN(TRUE);
+ }
+
+ // archive copies management
+ path[path_end]='\0';
+ if (!access(path, F_OK))
+ {
+ if (old_version != ULONGLONG_MAX && max_versions != 0)
+ {
+ // save backup
+ char path_arc[FN_REFLEN];
+ // backup old version
+ char path_to[FN_REFLEN];
+
+ // check archive directory existence
+ fn_format(path_arc, "arc", dir->str, "", MY_UNPACK_FILENAME);
+ if (access(path_arc, F_OK))
+ {
+ if (my_mkdir(path_arc, 0777, MYF(MY_WME)))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ }
+
+ my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lu",
+ path_arc, file_name->str, (ulong) old_version);
+ if (my_rename(path, path_to, MYF(MY_WME)))
+ {
+ DBUG_RETURN(TRUE);
+ }
+
+ // remove very old version
+ if (old_version > max_versions)
+ {
+ my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lu",
+ path_arc, file_name->str,
+ (ulong)(old_version - max_versions));
+ if (!access(path_arc, F_OK) && my_delete(path_to, MYF(MY_WME)))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+ else
+ {
+ if (my_delete(path, MYF(MY_WME))) // no backups
+ {
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+
+ {
+ // rename temporary file
+ char path_to[FN_REFLEN];
+ memcpy(path_to, path, path_end+1);
+ path[path_end]='~';
+ if (my_rename(path, path_to, MYF(MY_WME)))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ }
+ DBUG_RETURN(FALSE);
+err_w_cache:
+ end_io_cache(&file);
+err_w_file:
+ my_close(handler, MYF(MY_WME));
+ DBUG_RETURN(TRUE);
+}
+
+
+/*
+ Prepare frm to parse (read to memory)
+
+ SYNOPSIS
+ sql_parse_prepare()
+ file_name - path & filename to .frm file
+ mem_root - MEM_ROOT for buffer allocation
+ bad_format_errors - send errors on bad content
+
+ RETURN
+ 0 - error
+ parser object
+
+ NOTE
+ returned pointer + 1 will be type of .frm
+*/
+
+File_parser *
+sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
+ bool bad_format_errors)
+{
+ MY_STAT stat_info;
+ uint len;
+ char *end, *sign;
+ File_parser *parser;
+ File file;
+ DBUG_ENTER("sql__parse_prepare");
+
+ if (!my_stat(file_name->str, &stat_info, MYF(MY_WME)))
+ {
+ DBUG_RETURN(0);
+ }
+
+ if (stat_info.st_size > INT_MAX-1)
+ {
+ my_error(ER_FPARSER_TOO_BIG_FILE, MYF(0), file_name->str);
+ DBUG_RETURN(0);
+ }
+
+ if (!(parser= new(mem_root) File_parser))
+ {
+ DBUG_RETURN(0);
+ }
+
+ if (!(parser->buff= alloc_root(mem_root, stat_info.st_size+1)))
+ {
+ DBUG_RETURN(0);
+ }
+
+ if ((file= my_open(file_name->str, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
+ {
+ DBUG_RETURN(0);
+ }
+
+ if ((len= my_read(file, (byte *)parser->buff,
+ stat_info.st_size, MYF(MY_WME))) ==
+ MY_FILE_ERROR)
+ {
+ my_close(file, MYF(MY_WME));
+ DBUG_RETURN(0);
+ }
+
+ if (my_close(file, MYF(MY_WME)))
+ {
+ DBUG_RETURN(0);
+ }
+
+ end= parser->end= parser->buff + len;
+ *end= '\0'; // barrier for more simple parsing
+
+ // 7 = 5 (TYPE=) + 1 (letter at least of type name) + 1 ('\n')
+ if (len < 7 ||
+ parser->buff[0] != 'T' ||
+ parser->buff[1] != 'Y' ||
+ parser->buff[2] != 'P' ||
+ parser->buff[3] != 'E' ||
+ parser->buff[4] != '=')
+ goto frm_error;
+
+ // skip signature;
+ parser->file_type.str= sign= parser->buff + 5;
+ while (*sign >= 'A' && *sign <= 'Z' && sign < end)
+ sign++;
+ if (*sign != '\n')
+ goto frm_error;
+ parser->file_type.length= sign - parser->file_type.str;
+ // EOS for file signature just for safety
+ *sign= '\0';
+
+ parser->start= sign + 1;
+ parser->content_ok= 1;
+
+ DBUG_RETURN(parser);
+
+frm_error:
+ if (bad_format_errors)
+ {
+ my_error(ER_FPARSER_BAD_HEADER, MYF(0), file_name->str);
+ DBUG_RETURN(0);
+ }
+ else
+ DBUG_RETURN(parser); // upper level have to check parser->ok()
+}
+
+
+/*
+ parse LEX_STRING
+
+ SYNOPSIS
+ parse_string()
+ ptr - pointer on string beginning
+ end - pointer on symbol after parsed string end (still owned
+ by buffer and can be accessed
+ mem_root - MEM_ROOT for parameter allocation
+ str - pointer on string, where results should be stored
+
+ RETURN
+ 0 - error
+ # - pointer on symbol after string
+*/
+
+static char *
+parse_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
+{
+ // get string length
+ char *eol= strchr(ptr, '\n');
+
+ if (eol >= end)
+ return 0;
+
+ str->length= eol - ptr;
+
+ if (!(str->str= alloc_root(mem_root, str->length+1)))
+ return 0;
+
+ memcpy(str->str, ptr, str->length);
+ str->str[str->length]= '\0'; // just for safety
+ return eol+1;
+}
+
+
+/*
+ read escaped string from ptr to eol in already allocated str
+
+ SYNOPSIS
+ parse_escaped_string()
+ ptr - pointer on string beginning
+ eol - pointer on character after end of string
+ str - target string
+
+ RETURN
+ FALSE - OK
+ TRUE - error
+*/
+
+my_bool
+read_escaped_string(char *ptr, char *eol, LEX_STRING *str)
+{
+ char *write_pos= str->str;
+
+ for(; ptr < eol; ptr++, write_pos++)
+ {
+ char c= *ptr;
+ if (c == '\\')
+ {
+ ptr++;
+ if (ptr >= eol)
+ return TRUE;
+ /*
+ Should be in sync with write_escaped_string() and
+ parse_quoted_escaped_string()
+ */
+ switch(*ptr) {
+ case '\\':
+ *write_pos= '\\';
+ break;
+ case 'n':
+ *write_pos= '\n';
+ break;
+ case '0':
+ *write_pos= '\0';
+ break;
+ case 'z':
+ *write_pos= 26;
+ break;
+ case '\'':
+ *write_pos= '\'';
+ break;
+ default:
+ return TRUE;
+ }
+ }
+ else
+ *write_pos= c;
+ }
+ str->str[str->length= write_pos-str->str]= '\0'; // just for safety
+ return FALSE;
+}
+
+
+/*
+ parse \n delimited escaped string
+
+ SYNOPSIS
+ parse_escaped_string()
+ ptr - pointer on string beginning
+ end - pointer on symbol after parsed string end (still owned
+ by buffer and can be accessed
+ mem_root - MEM_ROOT for parameter allocation
+ str - pointer on string, where results should be stored
+
+ RETURN
+ 0 - error
+ # - pointer on symbol after string
+*/
+
+static char *
+parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
+{
+ char *eol= strchr(ptr, '\n');
+
+ if (eol == 0 || eol >= end ||
+ !(str->str= alloc_root(mem_root, (eol - ptr) + 1)) ||
+ read_escaped_string(ptr, eol, str))
+ return 0;
+
+ return eol+1;
+}
+
+
+/*
+ parse '' delimited escaped string
+
+ SYNOPSIS
+ parse_escaped_string()
+ ptr - pointer on string beginning
+ end - pointer on symbol after parsed string end (still owned
+ by buffer and can be accessed
+ mem_root - MEM_ROOT for parameter allocation
+ str - pointer on string, where results should be stored
+
+ RETURN
+ 0 - error
+ # - pointer on symbol after string
+*/
+
+static char *
+parse_quoted_escaped_string(char *ptr, char *end,
+ MEM_ROOT *mem_root, LEX_STRING *str)
+{
+ char *eol;
+ uint result_len= 0;
+ bool escaped= 0;
+
+ // starting '
+ if (*(ptr++) != '\'')
+ return 0;
+
+ // find ending '
+ for (eol= ptr; (*eol != '\'' || escaped) && eol < end; eol++)
+ {
+ if (!(escaped= (*eol == '\\' && !escaped)))
+ result_len++;
+ }
+
+ // process string
+ if (eol >= end ||
+ !(str->str= alloc_root(mem_root, result_len + 1)) ||
+ read_escaped_string(ptr, eol, str))
+ return 0;
+
+ return eol+1;
+}
+
+
+/*
+ parse parameters
+
+ SYNOPSIS
+ File_parser::parse()
+ base base address for parameter writing (structure like
+ TABLE)
+ mem_root MEM_ROOT for parameters allocation
+ parameters parameters description
+ required number of required parameters in above list
+
+ RETURN
+ FALSE - OK
+ TRUE - error
+*/
+
+my_bool
+File_parser::parse(gptr base, MEM_ROOT *mem_root,
+ struct File_option *parameters, uint required)
+{
+ uint first_param= 0, found= 0;
+ register char *ptr= start;
+ char *eol;
+ LEX_STRING *str;
+ List<LEX_STRING> *list;
+ DBUG_ENTER("File_parser::parse");
+
+ while (ptr < end && found < required)
+ {
+ char *line= ptr;
+ if (*ptr == '#')
+ {
+ // it is comment
+ if (!(ptr= strchr(ptr, '\n')))
+ {
+ my_error(ER_FPARSER_EOF_IN_COMMENT, MYF(0), line);
+ DBUG_RETURN(TRUE);
+ }
+ ptr++;
+ }
+ else
+ {
+ File_option *parameter= parameters+first_param,
+ *parameters_end= parameters+required;
+ int len= 0;
+ for(; parameter < parameters_end; parameter++)
+ {
+ len= parameter->name.length;
+ // check length
+ if (len < (end-ptr) && ptr[len] != '=')
+ continue;
+ // check keyword
+ if (memcmp(parameter->name.str, ptr, len) == 0)
+ break;
+ }
+
+ if (parameter < parameters_end)
+ {
+ found++;
+ /*
+ if we found first parameter, start search from next parameter
+ next time.
+ (this small optimisation should work, because they should be
+ written in same order)
+ */
+ if (parameter == parameters+first_param)
+ first_param++;
+
+ // get value
+ ptr+= (len+1);
+ switch (parameter->type) {
+ case FILE_OPTIONS_STRING:
+ {
+ if (!(ptr= parse_string(ptr, end, mem_root,
+ (LEX_STRING *)(base +
+ parameter->offset))))
+ {
+ my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
+ parameter->name.str, line);
+ DBUG_RETURN(TRUE);
+ }
+ break;
+ }
+ case FILE_OPTIONS_ESTRING:
+ {
+ if (!(ptr= parse_escaped_string(ptr, end, mem_root,
+ (LEX_STRING *)
+ (base + parameter->offset))))
+ {
+ my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
+ parameter->name.str, line);
+ DBUG_RETURN(TRUE);
+ }
+ break;
+ }
+ case FILE_OPTIONS_ULONGLONG:
+ case FILE_OPTIONS_REV:
+ if (!(eol= strchr(ptr, '\n')))
+ {
+ my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
+ parameter->name.str, line);
+ DBUG_RETURN(TRUE);
+ }
+ {
+ int not_used;
+ *((ulonglong*)(base + parameter->offset))=
+ my_strtoll10(ptr, 0, &not_used);
+ }
+ ptr= eol+1;
+ break;
+ case FILE_OPTIONS_TIMESTAMP:
+ {
+ /* string have to be allocated already */
+ LEX_STRING *val= (LEX_STRING *)(base + parameter->offset);
+ /* yyyy-mm-dd HH:MM:SS = 19(PARSE_FILE_TIMESTAMPLENGTH) characters */
+ if (ptr[PARSE_FILE_TIMESTAMPLENGTH] != '\n')
+ {
+ my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
+ parameter->name.str, line);
+ DBUG_RETURN(TRUE);
+ }
+ memcpy(val->str, ptr, PARSE_FILE_TIMESTAMPLENGTH);
+ val->str[val->length= PARSE_FILE_TIMESTAMPLENGTH]= '\0';
+ ptr+= (PARSE_FILE_TIMESTAMPLENGTH+1);
+ break;
+ }
+ case FILE_OPTIONS_STRLIST:
+ {
+ list= (List<LEX_STRING>*)(base + parameter->offset);
+
+ list->empty();
+ // list parsing
+ while (ptr < end)
+ {
+ if (!(str= (LEX_STRING*)alloc_root(mem_root,
+ sizeof(LEX_STRING))) ||
+ list->push_back(str, mem_root))
+ goto list_err;
+ if(!(ptr= parse_quoted_escaped_string(ptr, end, mem_root, str)))
+ goto list_err_w_message;
+ switch (*ptr) {
+ case '\n':
+ goto end_of_list;
+ case ' ':
+ // we cant go over buffer bounds, because we have \0 at the end
+ ptr++;
+ break;
+ default:
+ goto list_err_w_message;
+ }
+ }
+ end_of_list:
+ if (*(ptr++) != '\n')
+ goto list_err;
+ break;
+
+ list_err_w_message:
+ my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
+ parameter->name.str, line);
+ list_err:
+ DBUG_RETURN(TRUE);
+ }
+ default:
+ DBUG_ASSERT(0); // never should happened
+ }
+ }
+ else
+ {
+ // skip unknown parameter
+ if (!(ptr= strchr(ptr, '\n')))
+ {
+ my_error(ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER, MYF(0), line);
+ DBUG_RETURN(TRUE);
+ }
+ ptr++;
+ }
+ }
+ }
+ DBUG_RETURN(FALSE);
+}
diff --git a/sql/parse_file.h b/sql/parse_file.h
new file mode 100644
index 00000000000..82a89dffd18
--- /dev/null
+++ b/sql/parse_file.h
@@ -0,0 +1,69 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2004 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _PARSE_FILE_H_
+#define _PARSE_FILE_H_
+
+#define PARSE_FILE_TIMESTAMPLENGTH 19
+
+enum file_opt_type {
+ FILE_OPTIONS_STRING, /* String (LEX_STRING) */
+ FILE_OPTIONS_ESTRING, /* Escaped string (LEX_STRING) */
+ FILE_OPTIONS_ULONGLONG, /* ulonglong parameter (ulonglong) */
+ FILE_OPTIONS_REV, /* Revision version number (ulonglong) */
+ FILE_OPTIONS_TIMESTAMP, /* timestamp (LEX_STRING have to be
+ allocated with length 20 (19+1) */
+ FILE_OPTIONS_STRLIST /* list of escaped strings
+ (List<LEX_STRING>) */
+};
+
+struct File_option
+{
+ LEX_STRING name; /* Name of the option */
+ int offset; /* offset to base address of value */
+ file_opt_type type; /* Option type */
+};
+
+class File_parser;
+File_parser *sql_parse_prepare(const LEX_STRING *file_name,
+ MEM_ROOT *mem_root, bool bad_format_errors);
+
+my_bool
+sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
+ const LEX_STRING *type,
+ gptr base, File_option *parameters, uint versions);
+
+class File_parser: public Sql_alloc
+{
+ char *buff, *start, *end;
+ LEX_STRING file_type;
+ my_bool content_ok;
+public:
+ File_parser() :buff(0), start(0), end(0), content_ok(0)
+ { file_type.str= 0; file_type.length= 0; }
+
+ my_bool ok() { return content_ok; }
+ LEX_STRING *type() { return &file_type; }
+ my_bool parse(gptr base, MEM_ROOT *mem_root,
+ struct File_option *parameters, uint required);
+
+ friend File_parser *sql_parse_prepare(const LEX_STRING *file_name,
+ MEM_ROOT *mem_root,
+ bool bad_format_errors);
+};
+
+#endif /* _PARSE_FILE_H_ */
diff --git a/sql/password.c b/sql/password.c
index 04b3a46bd48..79675ade30b 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -65,7 +65,7 @@
#include <sha1.h>
#include "mysql.h"
-/************ MySQL 3.23-4.0 authentification routines: untouched ***********/
+/************ MySQL 3.23-4.0 authentication routines: untouched ***********/
/*
New (MySQL 3.21+) random generation structure initialization
@@ -281,7 +281,7 @@ void make_password_from_salt_323(char *to, const ulong *salt)
/*
- **************** MySQL 4.1.1 authentification routines *************
+ **************** MySQL 4.1.1 authentication routines *************
*/
/*
diff --git a/sql/procedure.cc b/sql/procedure.cc
index 7779f5ce085..a31b93da358 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -41,6 +41,34 @@ static struct st_procedure_def {
{ "analyse",proc_analyse_init } // Analyse a result
};
+
+my_decimal *Item_proc_string::val_decimal(my_decimal *decimal_value)
+{
+ if (null_value)
+ return 0;
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value);
+ return (decimal_value);
+}
+
+
+my_decimal *Item_proc_int::val_decimal(my_decimal *decimal_value)
+{
+ if (null_value)
+ return 0;
+ int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_value);
+ return (decimal_value);
+}
+
+
+my_decimal *Item_proc_real::val_decimal(my_decimal *decimal_value)
+{
+ if (null_value)
+ return 0;
+ double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value);
+ return (decimal_value);
+}
+
+
/*****************************************************************************
** Setup handling of procedure
** Return 0 if everything is ok
@@ -65,8 +93,7 @@ setup_procedure(THD *thd,ORDER *param,select_result *result,
DBUG_RETURN(proc);
}
}
- my_printf_error(ER_UNKNOWN_PROCEDURE,ER(ER_UNKNOWN_PROCEDURE),MYF(0),
- (*param->item)->name);
+ my_error(ER_UNKNOWN_PROCEDURE, MYF(0), (*param->item)->name);
*error=1;
DBUG_RETURN(0);
}
diff --git a/sql/procedure.h b/sql/procedure.h
index abe50bdc0a0..5d0dccbcd5e 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -60,13 +60,18 @@ public:
void set(longlong nr) { value=(double) nr; }
void set(const char *str,uint length,CHARSET_INFO *cs)
{
- int err;
+ int err_not_used;
char *end_not_used;
- value= my_strntod(cs, (char*) str, length, &end_not_used, &err);
+ value= my_strntod(cs,(char*) str,length, &end_not_used, &err_not_used);
}
- double val() { return value; }
+ double val_real() { return value; }
longlong val_int() { return (longlong) value; }
- String *val_str(String *s) { s->set(value,decimals,default_charset()); return s; }
+ String *val_str(String *s)
+ {
+ s->set(value,decimals,default_charset());
+ return s;
+ }
+ my_decimal *val_decimal(my_decimal *);
unsigned int size_of() { return sizeof(*this);}
};
@@ -82,9 +87,10 @@ public:
void set(longlong nr) { value=nr; }
void set(const char *str,uint length, CHARSET_INFO *cs)
{ int err; value=my_strntoll(cs,str,length,10,NULL,&err); }
- double val() { return (double) value; }
+ double val_real() { return (double) value; }
longlong val_int() { return value; }
String *val_str(String *s) { s->set(value, default_charset()); return s; }
+ my_decimal *val_decimal(my_decimal *);
unsigned int size_of() { return sizeof(*this);}
};
@@ -95,18 +101,18 @@ public:
Item_proc_string(const char *name_par,uint length) :Item_proc(name_par)
{ this->max_length=length; }
enum Item_result result_type () const { return STRING_RESULT; }
- enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
+ enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
void set(double nr) { str_value.set(nr, 2, default_charset()); }
void set(longlong nr) { str_value.set(nr, default_charset()); }
void set(const char *str, uint length, CHARSET_INFO *cs)
{ str_value.copy(str,length,cs); }
- double val()
+ double val_real()
{
- int err;
- CHARSET_INFO *cs= str_value.charset();
+ int err_not_used;
char *end_not_used;
+ CHARSET_INFO *cs= str_value.charset();
return my_strntod(cs, (char*) str_value.ptr(), str_value.length(),
- &end_not_used, &err);
+ &end_not_used, &err_not_used);
}
longlong val_int()
{
@@ -118,6 +124,7 @@ public:
{
return null_value ? (String*) 0 : (String*) &str_value;
}
+ my_decimal *val_decimal(my_decimal *);
unsigned int size_of() { return sizeof(*this);}
};
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 485605ce8cd..2ea435d84ef 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -24,6 +24,7 @@
#endif
#include "mysql_priv.h"
+#include "sp_rcontext.h"
#include <stdarg.h>
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
@@ -52,22 +53,30 @@ bool Protocol_prep::net_store_data(const char *from, uint length)
/* Send a error string to client */
-void send_error(THD *thd, uint sql_errno, const char *err)
+void net_send_error(THD *thd, uint sql_errno, const char *err)
{
#ifndef EMBEDDED_LIBRARY
uint length;
char buff[MYSQL_ERRMSG_SIZE+2], *pos;
#endif
- const char *orig_err= err;
NET *net= &thd->net;
- DBUG_ENTER("send_error");
+ bool generate_warning= thd->killed != THD::KILL_CONNECTION;
+ DBUG_ENTER("net_send_error");
DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno,
err ? err : net->last_error[0] ?
net->last_error : "NULL"));
-#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
- query_cache_abort(net);
-#endif
+ if (net && net->no_send_error)
+ {
+ thd->clear_error();
+ DBUG_PRINT("info", ("sending error messages prohibited"));
+ DBUG_VOID_RETURN;
+ }
+ if (thd->spcont && thd->spcont->find_handler(sql_errno,
+ MYSQL_ERROR::WARN_LEVEL_ERROR))
+ {
+ DBUG_VOID_RETURN;
+ }
thd->query_error= 1; // needed to catch query errors during replication
if (!err)
{
@@ -76,14 +85,22 @@ void send_error(THD *thd, uint sql_errno, const char *err)
else
{
if ((err=net->last_error)[0])
+ {
sql_errno=net->last_errno;
+ generate_warning= 0; // This warning has already been given
+ }
else
{
sql_errno=ER_UNKNOWN_ERROR;
err=ER(sql_errno); /* purecov: inspected */
}
}
- orig_err= err;
+ }
+
+ if (generate_warning)
+ {
+ /* Error that we have not got with my_error() */
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, sql_errno, err);
}
#ifdef EMBEDDED_LIBRARY
@@ -122,43 +139,14 @@ void send_error(THD *thd, uint sql_errno, const char *err)
}
VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length));
#endif /* EMBEDDED_LIBRARY*/
- if (!thd->killed)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, sql_errno,
- orig_err ? orig_err : ER(sql_errno));
thd->is_fatal_error=0; // Error message is given
thd->net.report_error= 0;
/* Abort multi-result sets */
- thd->lex->found_colon= 0;
thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
DBUG_VOID_RETURN;
}
-
-/*
- Send a warning to the end user
-
- SYNOPSIS
- send_warning()
- thd Thread handler
- sql_errno Warning number (error message)
- err Error string. If not set, use ER(sql_errno)
-
- DESCRIPTION
- Register the warning so that the user can get it with mysql_warnings()
- Send an ok (+ warning count) to the end user.
-*/
-
-void send_warning(THD *thd, uint sql_errno, const char *err)
-{
- DBUG_ENTER("send_warning");
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno,
- err ? err : ER(sql_errno));
- send_ok(thd);
- DBUG_VOID_RETURN;
-}
-
-
/*
Write error package and flush to client
It's a little too low level, but I don't want to use another buffer for
@@ -166,7 +154,7 @@ void send_warning(THD *thd, uint sql_errno, const char *err)
*/
void
-net_printf(THD *thd, uint errcode, ...)
+net_printf_error(THD *thd, uint errcode, ...)
{
va_list args;
uint length,offset;
@@ -179,17 +167,29 @@ net_printf(THD *thd, uint errcode, ...)
#endif
NET *net= &thd->net;
- DBUG_ENTER("net_printf");
+ DBUG_ENTER("net_printf_error");
DBUG_PRINT("enter",("message: %u",errcode));
+ if (net && net->no_send_error)
+ {
+ thd->clear_error();
+ DBUG_PRINT("info", ("sending error messages prohibited"));
+ DBUG_VOID_RETURN;
+ }
+
+ if (thd->spcont && thd->spcont->find_handler(errcode,
+ MYSQL_ERROR::WARN_LEVEL_ERROR))
+ {
+ DBUG_VOID_RETURN;
+ }
thd->query_error= 1; // needed to catch query errors during replication
#ifndef EMBEDDED_LIBRARY
query_cache_abort(net); // Safety
#endif
va_start(args,errcode);
/*
- The following is needed to make net_printf() work with 0 argument for
- errorcode and use the argument after that as the format string. This
+ The following is needed to make net_printf_error() work with 0 argument
+ for errorcode and use the argument after that as the format string. This
is useful for rare errors that are not worth the hassle to put in
errmsg.sys, but at the same time, the message is not fixed text
*/
@@ -252,7 +252,7 @@ net_printf(THD *thd, uint errcode, ...)
strmake(net->last_error, text_pos, length);
strmake(net->sqlstate, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
#endif
- if (!thd->killed)
+ if (thd->killed != THD::KILL_CONNECTION)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, errcode,
text_pos ? text_pos : ER(errcode));
thd->is_fatal_error=0; // Error message is given
@@ -326,6 +326,9 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
VOID(net_flush(net));
/* We can't anymore send an error to the client */
thd->net.report_error= 0;
+ thd->net.no_send_error= 1;
+ DBUG_PRINT("info", ("OK sent, so no more error sending allowed"));
+
DBUG_VOID_RETURN;
}
@@ -358,12 +361,14 @@ send_eof(THD *thd, bool no_flush)
{
NET *net= &thd->net;
DBUG_ENTER("send_eof");
- if (net->vio != 0)
+ if (net->vio != 0 && !net->no_send_eof)
{
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
uchar buff[5];
- uint tmp= min(thd->total_warn_count, 65535);
+ /* 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);
/*
@@ -383,6 +388,8 @@ send_eof(THD *thd, bool no_flush)
if (!no_flush)
VOID(net_flush(net));
}
+ thd->net.no_send_error= 1;
+ DBUG_PRINT("info", ("EOF sent, so no more error sending allowed"));
}
DBUG_VOID_RETURN;
}
@@ -497,6 +504,7 @@ bool Protocol::flush()
flag Bit mask with the following functions:
1 send number of rows
2 send default values
+ 4 don't write eof packet
DESCRIPTION
Sum fields has table name empty and field_name.
@@ -507,7 +515,7 @@ bool Protocol::flush()
*/
#ifndef EMBEDDED_LIBRARY
-bool Protocol::send_fields(List<Item> *list, uint flag)
+bool Protocol::send_fields(List<Item> *list, uint flags)
{
List_iterator_fast<Item> it(*list);
Item *item;
@@ -518,7 +526,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
CHARSET_INFO *thd_charset= thd->variables.character_set_results;
DBUG_ENTER("send_fields");
- if (flag & 1)
+ if (flags & SEND_NUM_ROWS)
{ // Packet with number of elements
char *pos=net_store_length(buff, (uint) list->elements);
(void) my_net_write(&thd->net, buff,(uint) (pos-buff));
@@ -536,6 +544,11 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
CHARSET_INFO *cs= system_charset_info;
Send_field field;
item->make_field(&field);
+
+ /* Keep things compatible for old clients */
+ if (field.type == MYSQL_TYPE_VARCHAR)
+ field.type= MYSQL_TYPE_VAR_STRING;
+
prot.prepare_for_resend();
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
@@ -612,7 +625,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
}
}
local_packet->length((uint) (pos - local_packet->ptr()));
- if (flag & 2)
+ if (flags & SEND_DEFAULTS)
item->send(&prot, &tmp); // Send default value
if (prot.write())
break; /* purecov: inspected */
@@ -621,25 +634,17 @@ bool Protocol::send_fields(List<Item> *list, uint flag)
#endif
}
- my_net_write(&thd->net, eof_buff, 1);
+ if (flags & SEND_EOF)
+ my_net_write(&thd->net, eof_buff, 1);
DBUG_RETURN(prepare_for_send(list));
err:
- send_error(thd,ER_OUT_OF_RESOURCES); /* purecov: inspected */
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
+ MYF(0)); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
-bool Protocol::send_records_num(List<Item> *list, ulonglong records)
-{
- char *pos;
- char buff[20];
- pos=net_store_length(buff, (uint) list->elements);
- pos=net_store_length(pos, records);
- return my_net_write(&thd->net, buff,(uint) (pos-buff));
-}
-
-
bool Protocol::write()
{
DBUG_ENTER("Protocol::write");
@@ -752,6 +757,8 @@ bool Protocol_simple::store(const char *from, uint length,
#ifndef DEBUG_OFF
DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
+ field_types[field_pos] == MYSQL_TYPE_BIT ||
+ field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
(field_types[field_pos] >= MYSQL_TYPE_ENUM &&
field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
field_pos++;
@@ -767,6 +774,8 @@ bool Protocol_simple::store(const char *from, uint length,
#ifndef DEBUG_OFF
DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
+ field_types[field_pos] == MYSQL_TYPE_BIT ||
+ field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
(field_types[field_pos] >= MYSQL_TYPE_ENUM &&
field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
field_pos++;
@@ -791,6 +800,7 @@ bool Protocol_simple::store_short(longlong from)
{
#ifndef DEBUG_OFF
DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_YEAR ||
field_types[field_pos] == MYSQL_TYPE_SHORT);
field_pos++;
#endif
@@ -829,6 +839,20 @@ bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag)
}
+bool Protocol_simple::store_decimal(const my_decimal *d)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
+ field_pos++;
+#endif
+ char buff[DECIMAL_MAX_STR_LENGTH];
+ String str(buff, sizeof(buff), &my_charset_bin);
+ (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
+ return net_store_data(str.ptr(), str.length());
+}
+
+
bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
{
#ifndef DEBUG_OFF
@@ -980,12 +1004,6 @@ void Protocol_prep::prepare_for_resend()
bool Protocol_prep::store(const char *from, uint length, CHARSET_INFO *fromcs)
{
CHARSET_INFO *tocs= thd->variables.character_set_results;
-#ifndef DEBUG_OFF
- DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
- (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
- field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
-#endif
field_pos++;
return store_string_aux(from, length, fromcs, tocs);
}
@@ -993,12 +1011,6 @@ bool Protocol_prep::store(const char *from, uint length, CHARSET_INFO *fromcs)
bool Protocol_prep::store(const char *from,uint length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
-#ifndef DEBUG_OFF
- DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
- (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
- field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
-#endif
field_pos++;
return store_string_aux(from, length, fromcs, tocs);
}
@@ -1016,10 +1028,6 @@ bool Protocol_prep::store_null()
bool Protocol_prep::store_tiny(longlong from)
{
-#ifndef DEBUG_OFF
- DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_TINY);
-#endif
char buff[1];
field_pos++;
buff[0]= (uchar) from;
@@ -1029,11 +1037,6 @@ bool Protocol_prep::store_tiny(longlong from)
bool Protocol_prep::store_short(longlong from)
{
-#ifndef DEBUG_OFF
- DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_SHORT ||
- field_types[field_pos] == MYSQL_TYPE_YEAR);
-#endif
field_pos++;
char *to= packet->prep_append(2, PACKET_BUFFER_EXTRA_ALLOC);
if (!to)
@@ -1045,11 +1048,6 @@ bool Protocol_prep::store_short(longlong from)
bool Protocol_prep::store_long(longlong from)
{
-#ifndef DEBUG_OFF
- DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_INT24 ||
- field_types[field_pos] == MYSQL_TYPE_LONG);
-#endif
field_pos++;
char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
if (!to)
@@ -1061,10 +1059,6 @@ bool Protocol_prep::store_long(longlong from)
bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
{
-#ifndef DEBUG_OFF
- DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_LONGLONG);
-#endif
field_pos++;
char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
if (!to)
@@ -1073,13 +1067,21 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
return 0;
}
-
-bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
+bool Protocol_prep::store_decimal(const my_decimal *d)
{
#ifndef DEBUG_OFF
DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_FLOAT);
+ field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
+ field_pos++;
#endif
+ char buff[DECIMAL_MAX_STR_LENGTH];
+ String str(buff, sizeof(buff), &my_charset_bin);
+ (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
+ return store(str.ptr(), str.length(), str.charset());
+}
+
+bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
+{
field_pos++;
char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
if (!to)
@@ -1091,10 +1093,6 @@ bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
{
-#ifndef DEBUG_OFF
- DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_DOUBLE);
-#endif
field_pos++;
char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
if (!to)
@@ -1118,12 +1116,6 @@ bool Protocol_prep::store(Field *field)
bool Protocol_prep::store(TIME *tm)
{
-#ifndef DEBUG_OFF
- DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_DATETIME ||
- field_types[field_pos] == MYSQL_TYPE_DATE ||
- field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
-#endif
char buff[12],*pos;
uint length;
field_pos++;
@@ -1158,10 +1150,6 @@ bool Protocol_prep::store_date(TIME *tm)
bool Protocol_prep::store_time(TIME *tm)
{
-#ifndef DEBUG_OFF
- DBUG_ASSERT(field_types == 0 ||
- field_types[field_pos] == MYSQL_TYPE_TIME);
-#endif
char buff[13], *pos;
uint length;
field_pos++;
@@ -1188,12 +1176,3 @@ bool Protocol_prep::store_time(TIME *tm)
buff[0]=(char) length; // Length is stored first
return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
}
-
-#ifdef EMBEDDED_LIBRARY
-/* Should be removed when we define the Protocol_cursor's future */
-bool Protocol_cursor::write()
-{
- return Protocol_simple::write();
-}
-#endif
-
diff --git a/sql/protocol.h b/sql/protocol.h
index a3b6da55da3..de379db541b 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -50,17 +50,15 @@ public:
Protocol(THD *thd_arg) { init(thd_arg); }
virtual ~Protocol() {}
void init(THD* thd_arg);
- bool send_fields(List<Item> *list, uint flag);
- bool send_records_num(List<Item> *list, ulonglong records);
+
+ enum { SEND_NUM_ROWS= 1, SEND_DEFAULTS= 2, SEND_EOF= 4 };
+ virtual bool send_fields(List<Item> *list, uint flags);
+
bool store(I_List<i_string> *str_list);
bool store(const char *from, CHARSET_INFO *cs);
String *storage_packet() { return packet; }
inline void free() { packet->free(); }
-#ifndef EMBEDDED_LIBRARY
- bool write();
-#else
virtual bool write();
-#endif
inline bool store(uint32 from)
{ return store_long((longlong) from); }
inline bool store(longlong from)
@@ -83,6 +81,7 @@ public:
virtual bool store_short(longlong from)=0;
virtual bool store_long(longlong from)=0;
virtual bool store_longlong(longlong from, bool unsigned_flag)=0;
+ virtual bool store_decimal(const my_decimal *)=0;
virtual bool store(const char *from, uint length, CHARSET_INFO *cs)=0;
virtual bool store(const char *from, uint length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0;
@@ -108,6 +107,7 @@ public:
virtual bool store_short(longlong from);
virtual bool store_long(longlong from);
virtual bool store_longlong(longlong from, bool unsigned_flag);
+ virtual bool store_decimal(const my_decimal *);
virtual bool store(const char *from, uint length, CHARSET_INFO *cs);
virtual bool store(const char *from, uint length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
@@ -138,6 +138,7 @@ public:
virtual bool store_short(longlong from);
virtual bool store_long(longlong from);
virtual bool store_longlong(longlong from, bool unsigned_flag);
+ virtual bool store_decimal(const my_decimal *);
virtual bool store(const char *from,uint length, CHARSET_INFO *cs);
virtual bool store(const char *from, uint length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
@@ -162,17 +163,20 @@ public:
Protocol_cursor(THD *thd_arg, MEM_ROOT *ini_alloc) :Protocol_simple(thd_arg), alloc(ini_alloc) {}
bool prepare_for_send(List<Item> *item_list)
{
+ row_count= 0;
fields= NULL;
data= NULL;
prev_record= &data;
return Protocol_simple::prepare_for_send(item_list);
}
- bool send_fields(List<Item> *list, uint flag);
+ bool send_fields(List<Item> *list, uint flags);
bool write();
+ uint get_field_count() { return field_count; }
};
void send_warning(THD *thd, uint sql_errno, const char *err=0);
-void net_printf(THD *thd,uint sql_errno, ...);
+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);
diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc
index 5f35552c562..5ac03c4d427 100644
--- a/sql/protocol_cursor.cc
+++ b/sql/protocol_cursor.cc
@@ -26,22 +26,21 @@
#include "mysql_priv.h"
#include <mysql.h>
-bool Protocol_cursor::send_fields(List<Item> *list, uint flag)
+bool Protocol_cursor::send_fields(List<Item> *list, uint flags)
{
List_iterator_fast<Item> it(*list);
Item *item;
MYSQL_FIELD *client_field;
-
- DBUG_ENTER("send_fields");
+ DBUG_ENTER("Protocol_cursor::send_fields");
+
if (prepare_for_send(list))
- return FALSE;
+ return FALSE;
fields= (MYSQL_FIELD *)alloc_root(alloc, sizeof(MYSQL_FIELD) * field_count);
if (!fields)
goto err;
- client_field= fields;
- while ((item= it++))
+ for (client_field= fields; (item= it++) ; client_field++)
{
Send_field server_field;
item->make_field(&server_field);
@@ -51,6 +50,7 @@ bool Protocol_cursor::send_fields(List<Item> *list, uint flag)
client_field->name= strdup_root(alloc, server_field.col_name);
client_field->org_table= strdup_root(alloc, server_field.org_table_name);
client_field->org_name= strdup_root(alloc, server_field.org_col_name);
+ client_field->catalog= strdup_root(alloc, "");
client_field->length= server_field.length;
client_field->type= server_field.type;
client_field->flags= server_field.flags;
@@ -60,12 +60,13 @@ bool Protocol_cursor::send_fields(List<Item> *list, uint flag)
client_field->name_length= strlen(client_field->name);
client_field->org_name_length= strlen(client_field->org_name);
client_field->org_table_length= strlen(client_field->org_table);
+ client_field->catalog_length= 0;
client_field->charsetnr= server_field.charsetnr;
if (INTERNAL_NUM_FIELD(client_field))
client_field->flags|= NUM_FLAG;
- if (flag & 2)
+ if (flags & (uint) Protocol::SEND_DEFAULTS)
{
char buff[80];
String tmp(buff, sizeof(buff), default_charset_info), *res;
@@ -78,16 +79,19 @@ bool Protocol_cursor::send_fields(List<Item> *list, uint flag)
else
client_field->def=0;
client_field->max_length= 0;
- ++client_field;
}
DBUG_RETURN(FALSE);
- err:
- send_error(thd, ER_OUT_OF_RESOURCES); /* purecov: inspected */
+
+err:
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES),
+ MYF(0)); /* purecov: inspected */
DBUG_RETURN(TRUE); /* purecov: inspected */
}
+
/* Get the length of next field. Change parameter to point at fieldstart */
+
bool Protocol_cursor::write()
{
byte *cp= (byte *)packet->ptr();
@@ -100,17 +104,18 @@ bool Protocol_cursor::write()
byte *to;
new_record= (MYSQL_ROWS *)alloc_root(alloc,
- sizeof(MYSQL_ROWS) + (field_count + 1)*sizeof(char *) + packet->length());
+ sizeof(MYSQL_ROWS) + (field_count + 2)*sizeof(char *) + packet->length());
if (!new_record)
goto err;
data_tmp= (byte **)(new_record + 1);
new_record->data= (char **)data_tmp;
- to= (byte *)(fields + field_count + 1);
+ to= (byte *)data_tmp + (field_count + 2)*sizeof(char *);
- for (; cur_field < fields_end; ++cur_field, ++data_tmp)
+ for (; cur_field < fields_end; cur_field++, data_tmp++)
{
- if ((len=net_field_length((uchar **)&cp)))
+ if ((len= net_field_length((uchar **)&cp)) == 0 ||
+ len == NULL_LENGTH)
{
*data_tmp= 0;
}
@@ -118,9 +123,10 @@ bool Protocol_cursor::write()
{
if ((long)len > (end_pos - cp))
{
-// TODO error signal send_error(thd, CR_MALFORMED_PACKET);
+ // TODO error signal send_error(thd, CR_MALFORMED_PACKET);
return TRUE;
}
+ *data_tmp= to;
memcpy(to,(char*) cp,len);
to[len]=0;
to+=len+1;
@@ -129,6 +135,8 @@ bool Protocol_cursor::write()
cur_field->max_length=len;
}
}
+ data_tmp[0]= to; // Pointer to last used byte
+ data_tmp[1]= 0;
*prev_record= new_record;
prev_record= &new_record->next;
@@ -136,8 +144,6 @@ bool Protocol_cursor::write()
row_count++;
return FALSE;
err:
-// TODO error signal send_error(thd, ER_OUT_OF_RESOURCES);
+ // TODO error signal send_error(thd, ER_OUT_OF_RESOURCES);
return TRUE;
}
-
-
diff --git a/sql/records.cc b/sql/records.cc
index e5a0d102b10..9b05dc3e291 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -26,7 +26,7 @@ static int rr_unpack_from_tempfile(READ_RECORD *info);
static int rr_unpack_from_buffer(READ_RECORD *info);
static int rr_from_pointers(READ_RECORD *info);
static int rr_from_cache(READ_RECORD *info);
-static int init_rr_cache(READ_RECORD *info);
+static int init_rr_cache(THD *thd, READ_RECORD *info);
static int rr_cmp(uchar *a,uchar *b);
/* init struct for read with info->read_record */
@@ -84,14 +84,15 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
!(table->file->table_flags() & HA_FAST_KEY_READ) &&
(table->db_stat & HA_READ_ONLY ||
table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
- (ulonglong) table->reclength*(table->file->records+
- table->file->deleted) >
+ (ulonglong) table->s->reclength* (table->file->records+
+ table->file->deleted) >
(ulonglong) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
- info->io_cache->end_of_file/info->ref_length*table->reclength >
+ info->io_cache->end_of_file/info->ref_length * table->s->reclength >
(my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
- !table->blob_fields)
+ !table->s->blob_fields &&
+ info->ref_length <= MAX_REFLENGTH)
{
- if (! init_rr_cache(info))
+ if (! init_rr_cache(thd, info))
{
DBUG_PRINT("info",("using rr_from_cache"));
info->read_record=rr_from_cache;
@@ -101,9 +102,6 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
else if (select && select->quick)
{
DBUG_PRINT("info",("using rr_quick"));
-
- if (!table->file->inited)
- table->file->ha_index_init(select->quick->index);
info->read_record=rr_quick;
}
else if (table->sort.record_pointers)
@@ -125,12 +123,19 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
if (!table->no_cache &&
(use_record_cache > 0 ||
(int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY ||
- !(table->db_options_in_use & HA_OPTION_PACK_RECORD) ||
+ !(table->s->db_options_in_use & HA_OPTION_PACK_RECORD) ||
(use_record_cache < 0 &&
!(table->file->table_flags() & HA_NOT_DELETE_WITH_CACHE))))
VOID(table->file->extra_opt(HA_EXTRA_CACHE,
thd->variables.read_buff_size));
}
+ /* Condition pushdown to storage engine */
+ if (thd->variables.engine_condition_pushdown &&
+ select && select->cond &&
+ (select->cond->used_tables() & table->map) &&
+ !table->file->pushed_cond)
+ table->file->cond_push(select->cond);
+
DBUG_VOID_RETURN;
} /* init_read_record */
@@ -189,7 +194,7 @@ static int rr_sequential(READ_RECORD *info)
{
if (info->thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ info->thd->send_kill_message();
return 1;
}
if (tmp != HA_ERR_RECORD_DELETED)
@@ -321,23 +326,21 @@ static int rr_unpack_from_buffer(READ_RECORD *info)
}
/* cacheing of records from a database */
-static int init_rr_cache(READ_RECORD *info)
+static int init_rr_cache(THD *thd, READ_RECORD *info)
{
uint rec_cache_size;
- THD *thd= current_thd;
-
DBUG_ENTER("init_rr_cache");
- info->struct_length=3+MAX_REFLENGTH;
- info->reclength=ALIGN_SIZE(info->table->reclength+1);
+ info->struct_length= 3+MAX_REFLENGTH;
+ info->reclength= ALIGN_SIZE(info->table->s->reclength+1);
if (info->reclength < info->struct_length)
- info->reclength=ALIGN_SIZE(info->struct_length);
+ info->reclength= ALIGN_SIZE(info->struct_length);
- info->error_offset=info->table->reclength;
- info->cache_records= thd->variables.read_rnd_buff_size /
- (info->reclength+info->struct_length);
- rec_cache_size=info->cache_records*info->reclength;
- info->rec_cache_size=info->cache_records*info->ref_length;
+ info->error_offset= info->table->s->reclength;
+ info->cache_records= (thd->variables.read_rnd_buff_size /
+ (info->reclength+info->struct_length));
+ rec_cache_size= info->cache_records*info->reclength;
+ info->rec_cache_size= info->cache_records*info->ref_length;
// We have to allocate one more byte to use uint3korr (see comments for it)
if (info->cache_records <= 2 ||
@@ -346,7 +349,8 @@ static int init_rr_cache(READ_RECORD *info)
MYF(0))))
DBUG_RETURN(1);
#ifdef HAVE_purify
- bzero(info->cache,rec_cache_size); // Avoid warnings in qsort
+ // Avoid warnings in qsort
+ bzero(info->cache,rec_cache_size+info->cache_records* info->struct_length+1);
#endif
DBUG_PRINT("info",("Allocated buffert for %d records",info->cache_records));
info->read_positions=info->cache+rec_cache_size;
@@ -377,7 +381,8 @@ static int rr_from_cache(READ_RECORD *info)
else
{
error=0;
- memcpy(info->record,info->cache_pos,(size_t) info->table->reclength);
+ memcpy(info->record,info->cache_pos,
+ (size_t) info->table->s->reclength);
}
info->cache_pos+=info->reclength;
return ((int) error);
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 85a51ba9b51..de4ad83fdbb 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -193,7 +193,6 @@ err:
my_message(ER_UNKNOWN_ERROR, "Wrong parameters to function register_slave",
MYF(0));
err2:
- send_error(thd);
return 1;
}
@@ -437,7 +436,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
This function is broken now. See comment for translate_master().
*/
-int show_new_master(THD* thd)
+bool show_new_master(THD* thd)
{
Protocol *protocol= thd->protocol;
DBUG_ENTER("show_new_master");
@@ -450,23 +449,24 @@ int show_new_master(THD* thd)
{
if (errmsg[0])
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
- "SHOW NEW MASTER", errmsg);
- DBUG_RETURN(-1);
+ "SHOW NEW MASTER", errmsg);
+ DBUG_RETURN(TRUE);
}
else
{
field_list.push_back(new Item_empty_string("Log_name", 20));
field_list.push_back(new Item_return_int("Log_pos", 10,
MYSQL_TYPE_LONGLONG));
- if (protocol->send_fields(&field_list, 1))
- DBUG_RETURN(-1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
protocol->prepare_for_resend();
protocol->store(lex_mi->log_file_name, &my_charset_bin);
protocol->store((ulonglong) lex_mi->pos);
if (protocol->write())
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
}
@@ -629,7 +629,7 @@ err:
}
-int show_slave_hosts(THD* thd)
+bool show_slave_hosts(THD* thd)
{
List<Item> field_list;
Protocol *protocol= thd->protocol;
@@ -649,8 +649,9 @@ int show_slave_hosts(THD* thd)
field_list.push_back(new Item_return_int("Master_id", 10,
MYSQL_TYPE_LONG));
- if (protocol->send_fields(&field_list, 1))
- DBUG_RETURN(-1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
pthread_mutex_lock(&LOCK_slave_list);
@@ -671,12 +672,12 @@ int show_slave_hosts(THD* thd)
if (protocol->write())
{
pthread_mutex_unlock(&LOCK_slave_list);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
pthread_mutex_unlock(&LOCK_slave_list);
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -707,6 +708,7 @@ int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi)
if (!mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
mi->port, 0, 0))
DBUG_RETURN(1);
+ mysql->reconnect= 1;
DBUG_RETURN(0);
}
@@ -737,7 +739,7 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db,
{
bzero((char*) &table, sizeof(table)); //just for safe
table.db= (char*) db;
- table.real_name= (char*) table_name;
+ table.table_name= (char*) table_name;
table.updating= 1;
if (!tables_ok(thd, &table))
@@ -757,7 +759,7 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db,
- No active transaction (flush_relay_log_info would not work in this case)
*/
-int load_master_data(THD* thd)
+bool load_master_data(THD* thd)
{
MYSQL mysql;
MYSQL_RES* master_status_res = 0;
@@ -779,16 +781,15 @@ int load_master_data(THD* thd)
(error=terminate_slave_threads(active_mi,restart_thread_mask,
1 /*skip lock*/)))
{
- send_error(thd,error);
+ my_message(error, ER(error), MYF(0));
unlock_slave_threads(active_mi);
pthread_mutex_unlock(&LOCK_active_mi);
- return 1;
+ return TRUE;
}
if (connect_to_master(thd, &mysql, active_mi))
{
- net_printf(thd, error= ER_CONNECT_TO_MASTER,
- mysql_error(&mysql));
+ my_error(error= ER_CONNECT_TO_MASTER, MYF(0), mysql_error(&mysql));
goto err;
}
@@ -800,8 +801,7 @@ int load_master_data(THD* thd)
if (mysql_real_query(&mysql, "SHOW DATABASES", 14) ||
!(db_res = mysql_store_result(&mysql)))
{
- net_printf(thd, error = ER_QUERY_ON_MASTER,
- mysql_error(&mysql));
+ my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
goto err;
}
@@ -814,7 +814,7 @@ int load_master_data(THD* thd)
if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*))))
{
- net_printf(thd, error = ER_OUTOFMEMORY);
+ my_message(error = ER_OUTOFMEMORY, ER(ER_OUTOFMEMORY), MYF(0));
goto err;
}
@@ -828,8 +828,7 @@ int load_master_data(THD* thd)
mysql_real_query(&mysql, "SHOW MASTER STATUS",18) ||
!(master_status_res = mysql_store_result(&mysql)))
{
- net_printf(thd, error = ER_QUERY_ON_MASTER,
- mysql_error(&mysql));
+ my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
goto err;
}
@@ -874,7 +873,6 @@ int load_master_data(THD* thd)
if (mysql_create_db(thd, db, &create_info, 1))
{
- send_error(thd, 0, 0);
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err;
}
@@ -883,8 +881,7 @@ int load_master_data(THD* thd)
mysql_real_query(&mysql, "SHOW TABLES", 11) ||
!(*cur_table_res = mysql_store_result(&mysql)))
{
- net_printf(thd, error = ER_QUERY_ON_MASTER,
- mysql_error(&mysql));
+ my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err;
}
@@ -922,7 +919,7 @@ int load_master_data(THD* thd)
if (init_master_info(active_mi, master_info_file, relay_log_info_file,
0, (SLAVE_IO | SLAVE_SQL)))
- send_error(thd, ER_MASTER_INFO);
+ my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
strmake(active_mi->master_log_name, row[0],
sizeof(active_mi->master_log_name));
active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error);
@@ -941,8 +938,7 @@ int load_master_data(THD* thd)
if (mysql_real_query(&mysql, "UNLOCK TABLES", 13))
{
- net_printf(thd, error = ER_QUERY_ON_MASTER,
- mysql_error(&mysql));
+ my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
goto err;
}
}
@@ -951,10 +947,10 @@ int load_master_data(THD* thd)
0 /* not only reset, but also reinit */,
&errmsg))
{
- send_error(thd, 0, "Failed purging old relay logs");
+ my_error(ER_RELAY_LOG_FAIL, MYF(0), errmsg);
unlock_slave_threads(active_mi);
pthread_mutex_unlock(&LOCK_active_mi);
- return 1;
+ return TRUE;
}
pthread_mutex_lock(&active_mi->rli.data_lock);
active_mi->rli.group_master_log_pos = active_mi->master_log_pos;
diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h
index ad0219bb735..dfaacf557e8 100644
--- a/sql/repl_failsafe.h
+++ b/sql/repl_failsafe.h
@@ -38,11 +38,11 @@ int update_slave_list(MYSQL* mysql, MASTER_INFO* mi);
extern HASH slave_list;
-int load_master_data(THD* thd);
+bool load_master_data(THD* thd);
int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi);
-int show_new_master(THD* thd);
-int show_slave_hosts(THD* thd);
+bool show_new_master(THD* thd);
+bool show_slave_hosts(THD* thd);
int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg);
void init_slave_list();
void end_slave_list();
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 9f63188c28a..0e6e36f63a2 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -28,7 +28,7 @@
- If the variable is thread specific, add it to 'system_variables' struct.
If not, add it to mysqld.cc and an declaration in 'mysql_priv.h'
- If the variable should be changed from the command line, add a definition
- of it in the my_option structure list in mysqld.dcc
+ of it in the my_option structure list in mysqld.cc
- Don't forget to initialize new fields in global_system_variables and
max_system_variables!
- If the variable should show up in 'show variables' add it to the
@@ -82,7 +82,7 @@ TYPELIB delay_key_write_typelib=
delay_key_write_type_names, NULL
};
-static int sys_check_charset(THD *thd, set_var *var);
+static int sys_check_charset(THD *thd, set_var *var);
static bool sys_update_charset(THD *thd, set_var *var);
static void sys_set_default_charset(THD *thd, enum_var_type type);
static int sys_check_ftb_syntax(THD *thd, set_var *var);
@@ -97,8 +97,11 @@ static bool set_option_autocommit(THD *thd, set_var *var);
static int check_log_update(THD *thd, set_var *var);
static bool set_log_update(THD *thd, set_var *var);
static int check_pseudo_thread_id(THD *thd, set_var *var);
+static bool set_log_bin(THD *thd, set_var *var);
static void fix_low_priority_updates(THD *thd, enum_var_type type);
static void fix_tx_isolation(THD *thd, enum_var_type type);
+static int check_completion_type(THD *thd, set_var *var);
+static void fix_completion_type(THD *thd, enum_var_type type);
static void fix_net_read_timeout(THD *thd, enum_var_type type);
static void fix_net_write_timeout(THD *thd, enum_var_type type);
static void fix_net_retry_count(THD *thd, enum_var_type type);
@@ -126,6 +129,14 @@ static byte *get_warning_count(THD *thd);
alphabetic order
*/
+sys_var_thd_ulong sys_auto_increment_increment("auto_increment_increment",
+ &SV::auto_increment_increment);
+sys_var_thd_ulong sys_auto_increment_offset("auto_increment_offset",
+ &SV::auto_increment_offset);
+
+sys_var_bool_ptr sys_automatic_sp_privileges("automatic_sp_privileges",
+ &sp_automatic_privileges);
+
sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size",
&binlog_cache_size);
sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size",
@@ -140,6 +151,10 @@ sys_var_character_set_database sys_character_set_database("character_set_databas
sys_var_character_set_client sys_character_set_client("character_set_client");
sys_var_character_set_connection sys_character_set_connection("character_set_connection");
sys_var_character_set_results sys_character_set_results("character_set_results");
+sys_var_thd_ulong sys_completion_type("completion_type",
+ &SV::completion_type,
+ check_completion_type,
+ fix_completion_type);
sys_var_collation_connection sys_collation_connection("collation_connection");
sys_var_collation_database sys_collation_database("collation_database");
sys_var_collation_server sys_collation_server("collation_server");
@@ -243,12 +258,13 @@ sys_var_long_ptr sys_max_relay_log_size("max_relay_log_size",
fix_max_relay_log_size);
sys_var_thd_ulong sys_max_sort_length("max_sort_length",
&SV::max_sort_length);
-sys_var_long_ptr sys_max_user_connections("max_user_connections",
- &max_user_connections);
+sys_var_max_user_conn sys_max_user_connections("max_user_connections");
sys_var_thd_ulong sys_max_tmp_tables("max_tmp_tables",
&SV::max_tmp_tables);
sys_var_long_ptr sys_max_write_lock_count("max_write_lock_count",
&max_write_lock_count);
+sys_var_thd_ulong sys_multi_range_count("multi_range_count",
+ &SV::multi_range_count);
sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size",
&myisam_data_pointer_size);
sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort_file_size", &SV::myisam_max_extra_sort_file_size, fix_myisam_max_extra_sort_file_size, 1);
@@ -268,6 +284,10 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count",
0, fix_net_retry_count);
sys_var_thd_bool sys_new_mode("new", &SV::new_mode);
sys_var_thd_bool sys_old_passwords("old_passwords", &SV::old_passwords);
+sys_var_thd_ulong sys_optimizer_prune_level("optimizer_prune_level",
+ &SV::optimizer_prune_level);
+sys_var_thd_ulong sys_optimizer_search_depth("optimizer_search_depth",
+ &SV::optimizer_search_depth);
sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size",
&SV::preload_buff_size);
sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
@@ -329,6 +349,11 @@ sys_var_thd_ulong sys_sort_buffer("sort_buffer_size",
&SV::sortbuff_size);
sys_var_thd_sql_mode sys_sql_mode("sql_mode",
&SV::sql_mode);
+sys_var_thd_enum
+sys_updatable_views_with_limit("updatable_views_with_limit",
+ &SV::updatable_views_with_limit,
+ &updatable_views_with_limit_typelib);
+
sys_var_thd_table_type sys_table_type("table_type",
&SV::table_type);
sys_var_thd_storage_engine sys_storage_engine("storage_engine",
@@ -355,23 +380,42 @@ sys_var_thd_enum sys_tx_isolation("tx_isolation",
fix_tx_isolation);
sys_var_thd_ulong sys_tmp_table_size("tmp_table_size",
&SV::tmp_table_size);
+sys_var_bool_ptr sys_timed_mutexes("timed_mutexes",
+ &timed_mutexes);
sys_var_thd_ulong sys_net_wait_timeout("wait_timeout",
&SV::net_wait_timeout);
#ifdef HAVE_INNOBASE_DB
+sys_var_long_ptr sys_innodb_fast_shutdown("innodb_fast_shutdown",
+ &innobase_fast_shutdown);
sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct",
&srv_max_buf_pool_modified_pct);
sys_var_long_ptr sys_innodb_max_purge_lag("innodb_max_purge_lag",
&srv_max_purge_lag);
sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks",
&SV::innodb_table_locks);
+sys_var_thd_bool sys_innodb_support_xa("innodb_support_xa",
+ &SV::innodb_support_xa);
sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment",
&srv_auto_extend_increment);
+sys_var_long_ptr sys_innodb_sync_spin_loops("innodb_sync_spin_loops",
+ &srv_n_spin_wait_rounds);
+sys_var_long_ptr sys_innodb_concurrency_tickets("innodb_concurrency_tickets",
+ &srv_n_free_tickets_to_enter);
+sys_var_long_ptr sys_innodb_thread_sleep_delay("innodb_thread_sleep_delay",
+ &srv_thread_sleep_delay);
+sys_var_long_ptr sys_innodb_thread_concurrency("innodb_thread_concurrency",
+ &srv_thread_concurrency);
#endif
+/* Condition pushdown to storage engine */
+sys_var_thd_bool
+sys_engine_condition_pushdown("engine_condition_pushdown",
+ &SV::engine_condition_pushdown);
+
#ifdef HAVE_NDBCLUSTER_DB
/* ndb thread specific variable settings */
-sys_var_thd_ulong
+sys_var_thd_ulong
sys_ndb_autoincrement_prefetch_sz("ndb_autoincrement_prefetch_sz",
&SV::ndb_autoincrement_prefetch_sz);
sys_var_thd_bool
@@ -380,6 +424,8 @@ sys_var_thd_bool
sys_ndb_use_exact_count("ndb_use_exact_count", &SV::ndb_use_exact_count);
sys_var_thd_bool
sys_ndb_use_transactions("ndb_use_transactions", &SV::ndb_use_transactions);
+sys_var_long_ptr
+sys_ndb_cache_check_time("ndb_cache_check_time", &ndb_cache_check_time);
#endif
/* Time/date/datetime formats */
@@ -420,8 +466,8 @@ static sys_var_thd_bit sys_log_update("sql_log_update",
OPTION_UPDATE_LOG);
static sys_var_thd_bit sys_log_binlog("sql_log_bin",
check_log_update,
- set_log_update,
- OPTION_BIN_LOG);
+ set_log_bin,
+ OPTION_BIN_LOG);
static sys_var_thd_bit sys_sql_warnings("sql_warnings", 0,
set_option_bit,
OPTION_WARNINGS);
@@ -499,7 +545,10 @@ sys_var_const_str sys_license("license", STRINGIFY_ARG(LICENSE));
sys_var *sys_variables[]=
{
&sys_auto_is_null,
+ &sys_auto_increment_increment,
+ &sys_auto_increment_offset,
&sys_autocommit,
+ &sys_automatic_sp_privileges,
&sys_big_tables,
&sys_big_selects,
&sys_binlog_cache_size,
@@ -513,6 +562,7 @@ sys_var *sys_variables[]=
&sys_collation_connection,
&sys_collation_database,
&sys_collation_server,
+ &sys_completion_type,
&sys_concurrent_insert,
&sys_connect_timeout,
&sys_date_format,
@@ -565,6 +615,7 @@ sys_var *sys_variables[]=
&sys_max_tmp_tables,
&sys_max_user_connections,
&sys_max_write_lock_count,
+ &sys_multi_range_count,
&sys_myisam_data_pointer_size,
&sys_myisam_max_extra_sort_file_size,
&sys_myisam_max_sort_file_size,
@@ -577,6 +628,8 @@ sys_var *sys_variables[]=
&sys_net_write_timeout,
&sys_new_mode,
&sys_old_passwords,
+ &sys_optimizer_prune_level,
+ &sys_optimizer_search_depth,
&sys_preload_buff_size,
&sys_pseudo_thread_id,
&sys_query_alloc_block_size,
@@ -629,6 +682,7 @@ sys_var *sys_variables[]=
&sys_table_type,
&sys_thread_cache_size,
&sys_time_format,
+ &sys_timed_mutexes,
&sys_timestamp,
&sys_time_zone,
&sys_tmp_table_size,
@@ -637,19 +691,28 @@ sys_var *sys_variables[]=
&sys_tx_isolation,
&sys_os,
#ifdef HAVE_INNOBASE_DB
+ &sys_innodb_fast_shutdown,
&sys_innodb_max_dirty_pages_pct,
&sys_innodb_max_purge_lag,
&sys_innodb_table_locks,
+ &sys_innodb_support_xa,
&sys_innodb_max_purge_lag,
&sys_innodb_autoextend_increment,
+ &sys_innodb_sync_spin_loops,
+ &sys_innodb_concurrency_tickets,
+ &sys_innodb_thread_sleep_delay,
+ &sys_innodb_thread_concurrency,
#endif
+ &sys_engine_condition_pushdown,
#ifdef HAVE_NDBCLUSTER_DB
&sys_ndb_autoincrement_prefetch_sz,
+ &sys_ndb_cache_check_time,
&sys_ndb_force_send,
&sys_ndb_use_exact_count,
&sys_ndb_use_transactions,
#endif
&sys_unique_checks,
+ &sys_updatable_views_with_limit,
&sys_warning_count
};
@@ -659,6 +722,9 @@ sys_var *sys_variables[]=
*/
struct show_var_st init_vars[]= {
+ {"auto_increment_increment", (char*) &sys_auto_increment_increment, SHOW_SYS},
+ {"auto_increment_offset", (char*) &sys_auto_increment_offset, SHOW_SYS},
+ {sys_automatic_sp_privileges.name,(char*) &sys_automatic_sp_privileges, SHOW_SYS},
{"back_log", (char*) &back_log, SHOW_LONG},
{"basedir", mysql_home, SHOW_CHAR},
#ifdef HAVE_BERKELEY_DB
@@ -682,6 +748,7 @@ struct show_var_st init_vars[]= {
{sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS},
{sys_collation_database.name,(char*) &sys_collation_database, SHOW_SYS},
{sys_collation_server.name,(char*) &sys_collation_server, SHOW_SYS},
+ {sys_completion_type.name, (char*) &sys_completion_type, SHOW_SYS},
{sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS},
{sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS},
{"datadir", mysql_real_data_home, SHOW_CHAR},
@@ -707,7 +774,8 @@ struct show_var_st init_vars[]= {
{"have_compress", (char*) &have_compress, SHOW_HAVE},
{"have_crypt", (char*) &have_crypt, SHOW_HAVE},
{"have_csv", (char*) &have_csv_db, SHOW_HAVE},
- {"have_example_engine", (char*) &have_example_db, SHOW_HAVE},
+ {"have_example_engine", (char*) &have_example_db, SHOW_HAVE},
+ {"have_federated_engine", (char*) &have_federated_db, SHOW_HAVE},
{"have_geometry", (char*) &have_geometry, SHOW_HAVE},
{"have_innodb", (char*) &have_innodb, SHOW_HAVE},
{"have_isam", (char*) &have_isam, SHOW_HAVE},
@@ -725,9 +793,12 @@ struct show_var_st init_vars[]= {
{sys_innodb_autoextend_increment.name, (char*) &sys_innodb_autoextend_increment, SHOW_SYS},
{"innodb_buffer_pool_awe_mem_mb", (char*) &innobase_buffer_pool_awe_mem_mb, SHOW_LONG },
{"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONG },
+ {"innodb_checksums", (char*) &innobase_use_checksums, SHOW_MY_BOOL},
+ {sys_innodb_concurrency_tickets.name, (char*) &sys_innodb_concurrency_tickets, SHOW_SYS},
{"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR},
{"innodb_data_home_dir", (char*) &innobase_data_home_dir, SHOW_CHAR_PTR},
- {"innodb_fast_shutdown", (char*) &innobase_fast_shutdown, SHOW_MY_BOOL},
+ {"innodb_doublewrite", (char*) &innobase_use_doublewrite, SHOW_MY_BOOL},
+ {sys_innodb_fast_shutdown.name,(char*) &sys_innodb_fast_shutdown, SHOW_SYS},
{"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG },
{"innodb_file_per_table", (char*) &innobase_file_per_table, SHOW_MY_BOOL},
{"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_INT},
@@ -745,8 +816,11 @@ struct show_var_st init_vars[]= {
{sys_innodb_max_purge_lag.name, (char*) &sys_innodb_max_purge_lag, SHOW_SYS},
{"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG},
{"innodb_open_files", (char*) &innobase_open_files, SHOW_LONG },
+ {sys_innodb_sync_spin_loops.name, (char*) &sys_innodb_sync_spin_loops, SHOW_SYS},
{sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS},
- {"innodb_thread_concurrency", (char*) &innobase_thread_concurrency, SHOW_LONG },
+ {sys_innodb_support_xa.name, (char*) &sys_innodb_support_xa, SHOW_SYS},
+ {sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency, SHOW_SYS},
+ {sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay, SHOW_SYS},
#endif
{sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS},
{sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS},
@@ -759,6 +833,8 @@ struct show_var_st init_vars[]= {
SHOW_SYS},
{"language", language, SHOW_CHAR},
{"large_files_support", (char*) &opt_large_files, SHOW_BOOL},
+ {"large_pages", (char*) &opt_large_pages, SHOW_MY_BOOL},
+ {"large_page_size", (char*) &opt_large_page_size, SHOW_INT},
{sys_license.name, (char*) &sys_license, SHOW_SYS},
{sys_local_infile.name, (char*) &sys_local_infile, SHOW_SYS},
#ifdef HAVE_MLOCKALL
@@ -771,7 +847,6 @@ struct show_var_st init_vars[]= {
{"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL},
#endif
{"log_slow_queries", (char*) &opt_slow_log, SHOW_BOOL},
- {"log_update", (char*) &opt_update_log, SHOW_BOOL},
{sys_log_warnings.name, (char*) &sys_log_warnings, SHOW_SYS},
{sys_long_query_time.name, (char*) &sys_long_query_time, SHOW_SYS},
{sys_low_priority_updates.name, (char*) &sys_low_priority_updates, SHOW_SYS},
@@ -796,6 +871,7 @@ struct show_var_st init_vars[]= {
{sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS},
{sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS},
{sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS},
+ {sys_multi_range_count.name, (char*) &sys_multi_range_count, SHOW_SYS},
{sys_myisam_data_pointer_size.name, (char*) &sys_myisam_data_pointer_size, SHOW_SYS},
{sys_myisam_max_extra_sort_file_size.name,
(char*) &sys_myisam_max_extra_sort_file_size,
@@ -809,12 +885,15 @@ struct show_var_st init_vars[]= {
#ifdef __NT__
{"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL},
#endif
+ {sys_engine_condition_pushdown.name,
+ (char*) &sys_engine_condition_pushdown, SHOW_SYS},
#ifdef HAVE_NDBCLUSTER_DB
{sys_ndb_autoincrement_prefetch_sz.name,
(char*) &sys_ndb_autoincrement_prefetch_sz, SHOW_SYS},
{sys_ndb_force_send.name, (char*) &sys_ndb_force_send, SHOW_SYS},
{sys_ndb_use_exact_count.name,(char*) &sys_ndb_use_exact_count, SHOW_SYS},
{sys_ndb_use_transactions.name,(char*) &sys_ndb_use_transactions, SHOW_SYS},
+ {sys_ndb_cache_check_time.name,(char*) &sys_ndb_cache_check_time, SHOW_SYS},
#endif
{sys_net_buffer_length.name,(char*) &sys_net_buffer_length, SHOW_SYS},
{sys_net_read_timeout.name, (char*) &sys_net_read_timeout, SHOW_SYS},
@@ -823,6 +902,10 @@ struct show_var_st init_vars[]= {
{sys_new_mode.name, (char*) &sys_new_mode, SHOW_SYS},
{sys_old_passwords.name, (char*) &sys_old_passwords, SHOW_SYS},
{"open_files_limit", (char*) &open_files_limit, SHOW_LONG},
+ {sys_optimizer_prune_level.name, (char*) &sys_optimizer_prune_level,
+ SHOW_SYS},
+ {sys_optimizer_search_depth.name,(char*) &sys_optimizer_search_depth,
+ SHOW_SYS},
{"pid_file", (char*) pidfile_name, SHOW_CHAR},
{"port", (char*) &mysqld_port, SHOW_INT},
{sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS},
@@ -890,12 +973,15 @@ struct show_var_st init_vars[]= {
{"thread_stack", (char*) &thread_stack, SHOW_LONG},
{sys_time_format.name, (char*) &sys_time_format, SHOW_SYS},
{"time_zone", (char*) &sys_time_zone, SHOW_SYS},
+ {sys_timed_mutexes.name, (char*) &sys_timed_mutexes, SHOW_SYS},
{sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS},
{"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR},
{sys_trans_alloc_block_size.name, (char*) &sys_trans_alloc_block_size,
SHOW_SYS},
{sys_trans_prealloc_size.name, (char*) &sys_trans_prealloc_size, SHOW_SYS},
{sys_tx_isolation.name, (char*) &sys_tx_isolation, SHOW_SYS},
+ {sys_updatable_views_with_limit.name,
+ (char*) &sys_updatable_views_with_limit,SHOW_SYS},
{"version", server_version, SHOW_CHAR},
#ifdef HAVE_BERKELEY_DB
{"version_bdb", (char*) DB_VERSION_STRING, SHOW_CHAR},
@@ -921,8 +1007,8 @@ bool sys_var_str::check(THD *thd, set_var *var)
return 0;
if ((res=(*check_func)(thd, var)) < 0)
- my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name,
- var->value->str_value.ptr());
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0),
+ name, var->value->str_value.ptr());
return res;
}
@@ -1088,6 +1174,21 @@ static void fix_tx_isolation(THD *thd, enum_var_type type)
thd->variables.tx_isolation);
}
+static void fix_completion_type(THD *thd __attribute__(unused),
+ enum_var_type type __attribute__(unused)) {}
+
+static int check_completion_type(THD *thd, set_var *var)
+{
+ longlong val= var->value->val_int();
+ if (val < 0 || val > 2)
+ {
+ char buf[64];
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name, llstr(val, buf));
+ return 1;
+ }
+ return 0;
+}
+
/*
If we are changing the thread variable, we have to copy it to NET too
@@ -1202,7 +1303,6 @@ static int check_max_delayed_threads(THD *thd, set_var *var)
return 0;
}
-
static void fix_max_connections(THD *thd, enum_var_type type)
{
#ifndef EMBEDDED_LIBRARY
@@ -1223,10 +1323,12 @@ static void fix_thd_mem_root(THD *thd, enum_var_type type)
static void fix_trans_mem_root(THD *thd, enum_var_type type)
{
+#ifdef USING_TRANSACTIONS
if (type != OPT_GLOBAL)
reset_root_defaults(&thd->transaction.mem_root,
thd->variables.trans_alloc_block_size,
thd->variables.trans_prealloc_size);
+#endif
}
@@ -1471,7 +1573,7 @@ byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type,
bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
const char *value;
String str(buff, sizeof(buff), system_charset_info), *res;
@@ -1508,7 +1610,7 @@ err:
bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
{
bool not_used;
- char buff[80], *error= 0;
+ char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
uint error_len= 0;
String str(buff, sizeof(buff), system_charset_info), *res;
@@ -1565,14 +1667,22 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
{
if (var_type != OPT_DEFAULT)
{
- net_printf(thd, ER_INCORRECT_GLOBAL_LOCAL_VAR,
- name, var_type == OPT_GLOBAL ? "SESSION" : "GLOBAL");
+ my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0),
+ name, var_type == OPT_GLOBAL ? "SESSION" : "GLOBAL");
return 0;
}
/* As there was no local variable, return the global value */
var_type= OPT_GLOBAL;
}
switch (type()) {
+ case SHOW_INT:
+ {
+ uint value;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ value= *(uint*) value_ptr(thd, var_type, base);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ return new Item_uint((int32) value);
+ }
case SHOW_LONG:
{
ulong value;
@@ -1609,7 +1719,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
return tmp;
}
default:
- net_printf(thd, ER_VAR_CANT_BE_READ, name);
+ my_error(ER_VAR_CANT_BE_READ, MYF(0), name);
}
return 0;
}
@@ -1711,7 +1821,7 @@ bool sys_var_thd_date_time_format::update(THD *thd, set_var *var)
bool sys_var_thd_date_time_format::check(THD *thd, set_var *var)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String str(buff,sizeof(buff), system_charset_info), *res;
DATE_TIME_FORMAT *format;
@@ -1815,7 +1925,7 @@ bool sys_var_collation::check(THD *thd, set_var *var)
if (var->value->result_type() == STRING_RESULT)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String str(buff,sizeof(buff), system_charset_info), *res;
if (!(res=var->value->val_str(&str)))
{
@@ -1849,7 +1959,7 @@ bool sys_var_character_set::check(THD *thd, set_var *var)
if (var->value->result_type() == STRING_RESULT)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String str(buff,sizeof(buff), system_charset_info), *res;
if (!(res=var->value->val_str(&str)))
{
@@ -1988,21 +2098,6 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type)
}
}
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50000)
-bool sys_var_character_set_server::check(THD *thd, set_var *var)
-{
- if ((var->type == OPT_GLOBAL) &&
- (mysql_bin_log.is_open() ||
- active_mi->slave_running || active_mi->rli.slave_running))
- {
- my_printf_error(0, "Binary logging and replication forbid changing \
-the global server character set or collation", MYF(0));
- return 1;
- }
- return sys_var_character_set::check(thd,var);
-}
-#endif
-
CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd,
enum_var_type type)
{
@@ -2095,20 +2190,6 @@ void sys_var_collation_database::set_default(THD *thd, enum_var_type type)
}
}
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50000)
-bool sys_var_collation_server::check(THD *thd, set_var *var)
-{
- if ((var->type == OPT_GLOBAL) &&
- (mysql_bin_log.is_open() ||
- active_mi->slave_running || active_mi->rli.slave_running))
- {
- my_printf_error(0, "Binary logging and replication forbid changing \
-the global server character set or collation", MYF(0));
- return 1;
- }
- return sys_var_collation::check(thd,var);
-}
-#endif
bool sys_var_collation_server::update(THD *thd, set_var *var)
{
@@ -2381,7 +2462,7 @@ bool sys_var_slave_skip_counter::check(THD *thd, set_var *var)
pthread_mutex_lock(&active_mi->rli.run_lock);
if (active_mi->rli.slave_running)
{
- my_error(ER_SLAVE_MUST_STOP, MYF(0));
+ my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
result=1;
}
pthread_mutex_unlock(&active_mi->rli.run_lock);
@@ -2416,14 +2497,6 @@ bool sys_var_sync_binlog_period::update(THD *thd, set_var *var)
{
pthread_mutex_t *lock_log= mysql_bin_log.get_log_lock();
sync_binlog_period= (ulong) var->save_result.ulonglong_value;
- /*
- Must reset the counter otherwise it may already be beyond the new period
- and so the new period will not be taken into account. Need mutex otherwise
- might be cancelled by a simultanate ++ in MYSQL_LOG::write().
- */
- pthread_mutex_lock(lock_log);
- sync_binlog_counter= 0;
- pthread_mutex_unlock(lock_log);
return 0;
}
#endif /* HAVE_REPLICATION */
@@ -2443,23 +2516,12 @@ bool sys_var_rand_seed2::update(THD *thd, set_var *var)
bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
{
- char buff[MAX_TIME_ZONE_NAME_LENGTH];
+ char buff[MAX_TIME_ZONE_NAME_LENGTH];
String str(buff, sizeof(buff), &my_charset_latin1);
String *res= var->value->val_str(&str);
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50000)
- if ((var->type == OPT_GLOBAL) &&
- (mysql_bin_log.is_open() ||
- active_mi->slave_running || active_mi->rli.slave_running))
- {
- my_printf_error(0, "Binary logging and replication forbid changing "
- "of the global server time zone", MYF(0));
- return 1;
- }
-#endif
-
if (!(var->save_result.time_zone=
- my_tz_find(res, thd->lex->time_zone_tables_used)))
+ my_tz_find(res, thd->lex->time_zone_tables_used)))
{
my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), res ? res->c_ptr() : "NULL");
return 1;
@@ -2493,7 +2555,18 @@ byte *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type,
if (type == OPT_GLOBAL)
return (byte *)(global_system_variables.time_zone->get_name()->ptr());
else
+ {
+ /*
+ This is an ugly fix for replication: we don't replicate properly queries
+ invoking system variables' values to update tables; but
+ CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
+ replicable (i.e. we tell the binlog code to store the session
+ timezone). If it's the global value which was used we can't replicate
+ (binlog code stores session value only).
+ */
+ thd->time_zone_used= 1;
return (byte *)(thd->variables.time_zone->get_name()->ptr());
+ }
}
@@ -2520,6 +2593,51 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type)
pthread_mutex_unlock(&LOCK_global_system_variables);
}
+
+bool sys_var_max_user_conn::check(THD *thd, set_var *var)
+{
+ if (var->type == OPT_GLOBAL)
+ return sys_var_thd::check(thd, var);
+ else
+ {
+ /*
+ Per-session values of max_user_connections can't be set directly.
+ QQ: May be we should have a separate error message for this?
+ */
+ my_error(ER_GLOBAL_VARIABLE, MYF(0), name);
+ return TRUE;
+ }
+}
+
+bool sys_var_max_user_conn::update(THD *thd, set_var *var)
+{
+ DBUG_ASSERT(var->type == OPT_GLOBAL);
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ max_user_connections= (uint)var->save_result.ulonglong_value;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ return 0;
+}
+
+
+void sys_var_max_user_conn::set_default(THD *thd, enum_var_type type)
+{
+ DBUG_ASSERT(type == OPT_GLOBAL);
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ max_user_connections= (ulong) option_limits->def_value;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+}
+
+
+byte *sys_var_max_user_conn::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
+{
+ if (type != OPT_GLOBAL &&
+ thd->user_connect && thd->user_connect->user_resources.user_conn)
+ return (byte*) &(thd->user_connect->user_resources.user_conn);
+ return (byte*) &(max_user_connections);
+}
+
+
/*
Functions to update thd->options bits
*/
@@ -2579,6 +2697,30 @@ static int check_log_update(THD *thd, set_var *var)
static bool set_log_update(THD *thd, set_var *var)
{
+ /*
+ The update log is not supported anymore since 5.0.
+ See sql/mysqld.cc/, comments in function init_server_components() for an
+ explaination of the different warnings we send below
+ */
+
+ if (opt_sql_bin_update)
+ {
+ ((sys_var_thd_bit*) var->var)->bit_flag|= (OPTION_BIN_LOG |
+ OPTION_UPDATE_LOG);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_UPDATE_LOG_DEPRECATED_TRANSLATED,
+ ER(ER_UPDATE_LOG_DEPRECATED_TRANSLATED));
+ }
+ else
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_UPDATE_LOG_DEPRECATED_IGNORED,
+ ER(ER_UPDATE_LOG_DEPRECATED_IGNORED));
+ set_option_bit(thd, var);
+ return 0;
+}
+
+static bool set_log_bin(THD *thd, set_var *var)
+{
if (opt_sql_bin_update)
((sys_var_thd_bit*) var->var)->bit_flag|= (OPTION_BIN_LOG |
OPTION_UPDATE_LOG);
@@ -2713,9 +2855,6 @@ void set_var_free()
length Length of variable. zero means that we should use strlen()
on the variable
- NOTE
- We have to use net_printf() as this is called during the parsing stage
-
RETURN VALUES
pointer pointer to variable definitions
0 Unknown variable (error message is given)
@@ -2728,7 +2867,7 @@ sys_var *find_sys_var(const char *str, uint length)
length ? length :
strlen(str));
if (!var)
- net_printf(current_thd, ER_UNKNOWN_SYSTEM_VARIABLE, (char*) str);
+ my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
return var;
}
@@ -2818,9 +2957,8 @@ int set_var::check(THD *thd)
{
if (var->check_type(type))
{
- my_error(type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE,
- MYF(0),
- var->name);
+ int err= type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
+ my_error(err, MYF(0), var->name);
return -1;
}
if ((type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)))
@@ -2836,7 +2974,7 @@ int set_var::check(THD *thd)
return 0;
}
- if ((!value->fixed &&
+ if ((!value->fixed &&
value->fix_fields(thd, 0, &value)) || value->check_cols(1))
return -1;
if (var->check_update_type(value->result_type()))
@@ -2864,9 +3002,8 @@ int set_var::light_check(THD *thd)
{
if (var->check_type(type))
{
- my_error(type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE,
- MYF(0),
- var->name);
+ int err= type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
+ my_error(err, MYF(0), var->name);
return -1;
}
if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))
@@ -2933,7 +3070,7 @@ int set_var_user::update(THD *thd)
if (user_var_item->update())
{
/* Give an error if it's not given already */
- my_error(ER_SET_CONSTANTS_ONLY, MYF(0));
+ my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), MYF(0));
return -1;
}
return 0;
@@ -2976,7 +3113,7 @@ int set_var_password::update(THD *thd)
bool sys_var_thd_storage_engine::check(THD *thd, set_var *var)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
const char *value;
String str(buff, sizeof(buff), &my_charset_latin1), *res;
@@ -2997,7 +3134,7 @@ bool sys_var_thd_storage_engine::check(THD *thd, set_var *var)
err:
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), value);
- return 1;
+ return 1;
}
@@ -3119,7 +3256,7 @@ ulong fix_sql_mode(ulong sql_mode)
sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
MODE_IGNORE_SPACE |
MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
- MODE_NO_FIELD_OPTIONS);
+ MODE_NO_FIELD_OPTIONS | MODE_NO_AUTO_CREATE_USER);
if (sql_mode & MODE_MSSQL)
sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
MODE_IGNORE_SPACE |
@@ -3139,11 +3276,15 @@ ulong fix_sql_mode(ulong sql_mode)
sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
MODE_IGNORE_SPACE |
MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
- MODE_NO_FIELD_OPTIONS);
+ MODE_NO_FIELD_OPTIONS | MODE_NO_AUTO_CREATE_USER);
if (sql_mode & MODE_MYSQL40)
- sql_mode|= MODE_NO_FIELD_OPTIONS;
+ sql_mode|= MODE_NO_FIELD_OPTIONS | MODE_HIGH_NOT_PRECEDENCE;
if (sql_mode & MODE_MYSQL323)
- sql_mode|= MODE_NO_FIELD_OPTIONS;
+ sql_mode|= MODE_NO_FIELD_OPTIONS | MODE_HIGH_NOT_PRECEDENCE;
+ if (sql_mode & MODE_TRADITIONAL)
+ sql_mode|= (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES |
+ MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_ERROR_FOR_DIVISION_BY_ZERO | MODE_NO_AUTO_CREATE_USER);
return sql_mode;
}
diff --git a/sql/set_var.h b/sql/set_var.h
index 080a2a95ae0..585f6df3547 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -49,20 +49,14 @@ public:
const char *name;
sys_after_update_func after_update;
-#if MYSQL_VERSION_ID < 50000
bool no_support_one_shot;
-#endif
sys_var(const char *name_arg)
:name(name_arg), after_update(0)
-#if MYSQL_VERSION_ID < 50000
, no_support_one_shot(1)
-#endif
{}
sys_var(const char *name_arg,sys_after_update_func func)
:name(name_arg), after_update(func)
-#if MYSQL_VERSION_ID < 50000
, no_support_one_shot(1)
-#endif
{}
virtual ~sys_var() {}
virtual bool check(THD *thd, set_var *var);
@@ -508,9 +502,7 @@ class sys_var_collation :public sys_var_thd
public:
sys_var_collation(const char *name_arg) :sys_var_thd(name_arg)
{
-#if MYSQL_VERSION_ID < 50000
no_support_one_shot= 0;
-#endif
}
bool check(THD *thd, set_var *var);
SHOW_TYPE type() { return SHOW_CHAR; }
@@ -530,13 +522,11 @@ public:
sys_var_thd(name_arg)
{
nullable= 0;
-#if MYSQL_VERSION_ID < 50000
/*
In fact only almost all variables derived from sys_var_character_set
support ONE_SHOT; character_set_results doesn't. But that's good enough.
*/
no_support_one_shot= 0;
-#endif
}
bool check(THD *thd, set_var *var);
SHOW_TYPE type() { return SHOW_CHAR; }
@@ -575,9 +565,6 @@ class sys_var_character_set_server :public sys_var_character_set
public:
sys_var_character_set_server(const char *name_arg) :
sys_var_character_set(name_arg) {}
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50000)
- bool check(THD *thd, set_var *var);
-#endif
void set_default(THD *thd, enum_var_type type);
CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type);
};
@@ -613,9 +600,6 @@ class sys_var_collation_server :public sys_var_collation
{
public:
sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {}
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50000)
- bool check(THD *thd, set_var *var);
-#endif
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
@@ -723,9 +707,7 @@ public:
sys_var_thd_time_zone(const char *name_arg):
sys_var_thd(name_arg)
{
-#if MYSQL_VERSION_ID < 50000
no_support_one_shot= 0;
-#endif
}
bool check(THD *thd, set_var *var);
SHOW_TYPE type() { return SHOW_CHAR; }
@@ -739,6 +721,23 @@ public:
virtual void set_default(THD *thd, enum_var_type type);
};
+
+class sys_var_max_user_conn : public sys_var_thd
+{
+public:
+ sys_var_max_user_conn(const char *name_arg):
+ sys_var_thd(name_arg) {}
+ bool check(THD *thd, set_var *var);
+ bool update(THD *thd, set_var *var);
+ bool check_default(enum_var_type type)
+ {
+ return type != OPT_GLOBAL || !option_limits;
+ }
+ void set_default(THD *thd, enum_var_type type);
+ SHOW_TYPE type() { return SHOW_INT; }
+ byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+};
+
/****************************************************************************
Classes for parsing of the SET command
****************************************************************************/
@@ -752,9 +751,7 @@ public:
virtual int update(THD *thd)=0; /* To set the value */
/* light check for PS */
virtual int light_check(THD *thd) { return check(thd); }
-#if MYSQL_VERSION_ID < 50000
virtual bool no_support_one_shot() { return 1; }
-#endif
};
@@ -776,7 +773,7 @@ public:
} save_result;
LEX_STRING base; /* for structs */
- set_var(enum_var_type type_arg, sys_var *var_arg, LEX_STRING *base_name_arg,
+ set_var(enum_var_type type_arg, sys_var *var_arg, const LEX_STRING *base_name_arg,
Item *value_arg)
:var(var_arg), type(type_arg), base(*base_name_arg)
{
@@ -797,9 +794,7 @@ public:
int check(THD *thd);
int update(THD *thd);
int light_check(THD *thd);
-#if MYSQL_VERSION_ID < 50000
bool no_support_one_shot() { return var->no_support_one_shot; }
-#endif
};
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
index f0207fdef03..b7ab8fead22 100644
--- a/sql/share/Makefile.am
+++ b/sql/share/Makefile.am
@@ -16,6 +16,8 @@
## Process this file with automake to create Makefile.in
+EXTRA_DIST= errmsg.txt
+
dist-hook:
for dir in charsets @AVAILABLE_LANGUAGES@; do \
test -d $(distdir)/$$dir || mkdir $(distdir)/$$dir; \
@@ -25,10 +27,14 @@ dist-hook:
$(INSTALL_DATA) $(srcdir)/charsets/README $(distdir)/charsets
$(INSTALL_DATA) $(srcdir)/charsets/Index.xml $(distdir)/charsets
-all-local: @AVAILABLE_LANGUAGES_ERRORS@
+all-local: english/errmsg.sys
+
+# Use the english errmsg.sys as a flag that all errmsg.sys needs to be
+# created. Normally these are created by extra/Makefile
-# this is ugly, but portable
-@AVAILABLE_LANGUAGES_ERRORS_RULES@
+english/errmsg.sys: errmsg.txt
+ rm $(top_builddir)/include/mysqld_error.h
+ (cd $(top_builddir)/extra && $(MAKE))
install-data-local:
for lang in @AVAILABLE_LANGUAGES@; \
@@ -36,18 +42,12 @@ install-data-local:
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/$$lang; \
$(INSTALL_DATA) $(srcdir)/$$lang/errmsg.sys \
$(DESTDIR)$(pkgdatadir)/$$lang/errmsg.sys; \
- $(INSTALL_DATA) $(srcdir)/$$lang/errmsg.txt \
- $(DESTDIR)$(pkgdatadir)/$$lang/errmsg.txt; \
done
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/charsets
+ $(INSTALL_DATA) $(srcdir)/errmsg.txt \
+ $(DESTDIR)$(pkgdatadir)/errmsg.txt; \
$(INSTALL_DATA) $(srcdir)/charsets/README $(DESTDIR)$(pkgdatadir)/charsets/README
$(INSTALL_DATA) $(srcdir)/charsets/*.xml $(DESTDIR)$(pkgdatadir)/charsets
-fix_errors:
- for lang in @AVAILABLE_LANGUAGES@; \
- do \
- ../../extra/comp_err -C$(srcdir)/charsets/ $(srcdir)/$$lang/errmsg.txt $(srcdir)/$$lang/errmsg.sys; \
- done
-
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml
index 9595d4a7ddb..3c35ec98a92 100644
--- a/sql/share/charsets/Index.xml
+++ b/sql/share/charsets/Index.xml
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding="utf-8"?>
-<charsets max-id="94">
+<charsets max-id="98">
<copyright>
Copyright (C) 2003 MySQL AB
@@ -553,5 +553,38 @@ To make maintaining easier please:
</collation>
</charset>
+<charset name="cp932">
+ <family>Japanese</family>
+ <description>SJIS for Windows Japanese</description>
+ <alias>ms_cp932</alias>
+ <alias>sjis_cp932</alias>
+ <alias>sjis_ms</alias>
+ <collation name="cp932_japanese_ci" id="95" order="Japanese">
+ <flag>primary</flag>
+ <flag>compiled</flag>
+ </collation>
+ <collation name="cp932_bin" id="96" order="Binary">
+ <flag>binary</flag>
+ <flag>compiled</flag>
+ </collation>
+</charset>
+
+<charset name="eucjpms">
+ <family>Japanese</family>
+ <description>UJIS for Windows Japanese</description>
+ <alias>eucjpms</alias>
+ <alias>eucJP_ms</alias>
+ <alias>ujis_ms</alias>
+ <alias>ujis_cp932</alias>
+ <collation name="eucjpms_japanese_ci" id="97" order="Japanese">
+ <flag>primary</flag>
+ <flag>compiled</flag>
+ </collation>
+ <collation name="eucjpms_bin" id="98" order="Japanese">
+ <flag>binary</flag>
+ <flag>compiled</flag>
+ </collation>
+</charset>
+
</charsets>
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
deleted file mode 100644
index 022a624c921..00000000000
--- a/sql/share/czech/errmsg.txt
+++ /dev/null
@@ -1,333 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Modifikoval Petr -B©najdr, snajdr@pvt.net, snajdr@cpress.cz v.0.01
- ISO LATIN-8852-2
- Dal-B¹í verze Jan Pazdziora, adelton@fi.muni.cz
- Tue Nov 18 17:53:55 MET 1997
- Tue Dec 2 19:08:54 MET 1997 podle 3.21.15c
- Thu May 7 17:40:49 MET DST 1998 podle 3.21.29
- Thu Apr 1 20:49:57 CEST 1999 podle 3.22.20
- Mon Aug 9 13:30:09 MET DST 1999 podle 3.23.2
- Thu Nov 30 14:02:52 MET 2000 podle 3.23.28
-*/
-
-character-set=latin2
-
-"hashchk",
-"isamchk",
-"NE",
-"ANO",
-"Nemohu vytvo-Bøit soubor '%-.64s' (chybový kód: %d)",
-"Nemohu vytvo-Bøit tabulku '%-.64s' (chybový kód: %d)",
-"Nemohu vytvo-Bøit databázi '%-.64s' (chybový kód: %d)",
-"Nemohu vytvo-Bøit databázi '%-.64s'; databáze ji¾ existuje",
-"Nemohu zru-B¹it databázi '%-.64s', databáze neexistuje",
-"Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.64s', chyba %d)",
-"Chyba p-Bøi ru¹ení databáze (nemohu vymazat adresáø '%-.64s', chyba %d)",
-"Chyba p-Bøi výmazu '%-.64s' (chybový kód: %d)",
-"Nemohu -Bèíst záznam v systémové tabulce",
-"Nemohu z-Bískat stav '%-.64s' (chybový kód: %d)",
-"Chyba p-Bøi zji¹»ování pracovní adresáø (chybový kód: %d)",
-"Nemohu uzamknout soubor (chybov-Bý kód: %d)",
-"Nemohu otev-Bøít soubor '%-.64s' (chybový kód: %d)",
-"Nemohu naj-Bít soubor '%-.64s' (chybový kód: %d)",
-"Nemohu -Bèíst adresáø '%-.64s' (chybový kód: %d)",
-"Nemohu zm-Bìnit adresáø na '%-.64s' (chybový kód: %d)",
-"Z-Báznam byl zmìnìn od posledního ètení v tabulce '%-.64s'",
-"Disk je pln-Bý (%s), èekám na uvolnìní nìjakého místa ...",
-"Nemohu zapsat, zdvojen-Bý klíè v tabulce '%-.64s'",
-"Chyba p-Bøi zavírání '%-.64s' (chybový kód: %d)",
-"Chyba p-Bøi ètení souboru '%-.64s' (chybový kód: %d)",
-"Chyba p-Bøi pøejmenování '%-.64s' na '%-.64s' (chybový kód: %d)",
-"Chyba p-Bøi zápisu do souboru '%-.64s' (chybový kód: %d)",
-"'%-.64s' je zam-Bèen proti zmìnám",
-"T-Bøídìní pøeru¹eno",
-"Pohled '%-.64s' pro '%-.64s' neexistuje",
-"Obsluha tabulky vr-Bátila chybu %d",
-"Obsluha tabulky '%-.64s' nem-Bá tento parametr",
-"Nemohu naj-Bít záznam v '%-.64s'",
-"Nespr-Bávná informace v souboru '%-.64s'",
-"Nespr-Bávný klíè pro tabulku '%-.64s'; pokuste se ho opravit",
-"Star-Bý klíèový soubor pro '%-.64s'; opravte ho.",
-"'%-.64s' je jen pro -Bètení",
-"M-Bálo pamìti. Pøestartujte daemona a zkuste znovu (je potøeba %d bytù)",
-"M-Bálo pamìti pro tøídìní. Zvy¹te velikost tøídícího bufferu",
-"Neo-Bèekávaný konec souboru pøi ètení '%-.64s' (chybový kód: %d)",
-"P-Bøíli¹ mnoho spojení",
-"M-Bálo prostoru/pamìti pro thread",
-"Nemohu zjistit jm-Béno stroje pro Va¹i adresu",
-"Chyba p-Bøi ustavování spojení",
-"P-Bøístup pro u¾ivatele '%-.32s'@'%-.64s' k databázi '%-.64s' není povolen",
-"P-Bøístup pro u¾ivatele '%-.32s'@'%-.64s' (s heslem %s)",
-"Nebyla vybr-Bána ¾ádná databáze",
-"Nezn-Bámý pøíkaz",
-"Sloupec '%-.64s' nem-Bù¾e být null",
-"Nezn-Bámá databáze '%-.64s'",
-"Tabulka '%-.64s' ji-B¾ existuje",
-"Nezn-Bámá tabulka '%-.64s'",
-"Sloupec '%-.64s' v %s nen-Bí zcela jasný",
-"Prob-Bíhá ukonèování práce serveru",
-"Nezn-Bámý sloupec '%-.64s' v %s",
-"Pou-B¾ité '%-.64s' nebylo v group by",
-"Nemohu pou-B¾ít group na '%-.64s'",
-"P-Bøíkaz obsahuje zároveò funkci sum a sloupce",
-"Po-Bèet sloupcù neodpovídá zadané hodnotì",
-"Jm-Béno identifikátoru '%-.64s' je pøíli¹ dlouhé",
-"Zdvojen-Bé jméno sloupce '%-.64s'",
-"Zdvojen-Bé jméno klíèe '%-.64s'",
-"Zvojen-Bý klíè '%-.64s' (èíslo klíèe %d)",
-"Chybn-Bá specifikace sloupce '%-.64s'",
-"%s bl-Bízko '%-.64s' na øádku %d",
-"V-Býsledek dotazu je prázdný",
-"Nejednozna-Bèná tabulka/alias: '%-.64s'",
-"Chybn-Bá defaultní hodnota pro '%-.64s'",
-"Definov-Báno více primárních klíèù",
-"Zad-Báno pøíli¹ mnoho klíèù, je povoleno nejvíce %d klíèù",
-"Zad-Báno pøíli¹ mnoho èást klíèù, je povoleno nejvíce %d èástí",
-"Zadan-Bý klíè byl pøíli¹ dlouhý, nejvìt¹í délka klíèe je %d",
-"Kl-Bíèový sloupec '%-.64s' v tabulce neexistuje",
-"Blob sloupec '%-.64s' nem-Bù¾e být pou¾it jako klíè",
-"P-Bøíli¹ velká délka sloupce '%-.64s' (nejvíce %d). Pou¾ijte BLOB",
-"M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè",
-"%s: p-Bøipraven na spojení",
-"%s: norm-Bální ukonèení\n",
-"%s: p-Bøijat signal %d, konèím\n",
-"%s: ukon-Bèení práce hotovo\n",
-"%s: n-Básilné uzavøení threadu %ld u¾ivatele '%-.64s'\n",
-"Nemohu vytvo-Bøit IP socket",
-"Tabulka '%-.64s' nem-Bá index odpovídající CREATE INDEX. Vytvoøte tabulku znovu",
-"Argument separ-Bátoru polo¾ek nebyl oèekáván. Pøeètìte si manuál",
-"Nen-Bí mo¾né pou¾ít pevný rowlength s BLOBem. Pou¾ijte 'fields terminated by'.",
-"Soubor '%-.64s' mus-Bí být v adresáøi databáze nebo èitelný pro v¹echny",
-"Soubor '%-.64s' ji-B¾ existuje",
-"Z-Báznamù: %ld Vymazáno: %ld Pøeskoèeno: %ld Varování: %ld",
-"Z-Báznamù: %ld Zdvojených: %ld",
-"Chybn-Bá podèást klíèe -- není to øetìzec nebo je del¹í ne¾ délka èásti klíèe",
-"Nen-Bí mo¾né vymazat v¹echny polo¾ky s ALTER TABLE. Pou¾ijte DROP TABLE",
-"Nemohu zru-B¹it '%-.64s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe",
-"Z-Báznamù: %ld Zdvojených: %ld Varování: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Nezn-Bámá identifikace threadu: %lu",
-"Nejste vlastn-Bíkem threadu %lu",
-"Nejsou pou-B¾ity ¾ádné tabulky",
-"P-Bøíli¹ mnoho øetìzcù pro sloupec %s a SET",
-"Nemohu vytvo-Bøit jednoznaèné jméno logovacího souboru %s.(1-999)\n",
-"Tabulka '%-.64s' byla zam-Bèena s READ a nemù¾e být zmìnìna",
-"Tabulka '%-.64s' nebyla zam-Bèena s LOCK TABLES",
-"Blob polo-B¾ka '%-.64s' nemù¾e mít defaultní hodnotu",
-"Nep-Bøípustné jméno databáze '%-.64s'",
-"Nep-Bøípustné jméno tabulky '%-.64s'",
-"Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET SQL_BIG_SELECTS=1",
-"Nezn-Bámá chyba",
-"Nezn-Bámá procedura %s",
-"Chybn-Bý poèet parametrù procedury %s",
-"Chybn-Bé parametry procedury %s",
-"Nezn-Bámá tabulka '%-.64s' v %s",
-"Polo-B¾ka '%-.64s' je zadána dvakrát",
-"Nespr-Bávné pou¾ití funkce group",
-"Tabulka '%-.64s' pou-B¾ívá roz¹íøení, které v této verzi MySQL není",
-"Tabulka mus-Bí mít alespoò jeden sloupec",
-"Tabulka '%-.64s' je pln-Bá",
-"Nezn-Bámá znaková sada: '%-.64s'",
-"P-Bøíli¹ mnoho tabulek, MySQL jich mù¾e mít v joinu jen %d",
-"P-Bøíli¹ mnoho polo¾ek",
-"-BØádek je pøíli¹ velký. Maximální velikost øádku, nepoèítaje polo¾ky blob, je %d. Musíte zmìnit nìkteré polo¾ky na blob",
-"P-Bøeteèení zásobníku threadu: pou¾ito %ld z %ld. Pou¾ijte 'mysqld -O thread_stack=#' k zadání vìt¹ího zásobníku",
-"V OUTER JOIN byl nalezen k-Bøí¾ový odkaz. Provìøte ON podmínky",
-"Sloupec '%-.32s' je pou-B¾it s UNIQUE nebo INDEX, ale není definován jako NOT NULL",
-"Nemohu na-Bèíst funkci '%-.64s'",
-"Nemohu inicializovat funkci '%-.64s'; %-.80s",
-"Pro sd-Bílenou knihovnu nejsou povoleny cesty",
-"Funkce '%-.64s' ji-B¾ existuje",
-"Nemohu otev-Bøít sdílenou knihovnu '%-.64s' (errno: %d %s)",
-"Nemohu naj-Bít funkci '%-.64s' v knihovnì'",
-"Funkce '%-.64s' nen-Bí definována",
-"Stroj '%-.64s' je zablokov-Bán kvùli mnoha chybám pøi pøipojování. Odblokujete pou¾itím 'mysqladmin flush-hosts'",
-"Stroj '%-.64s' nem-Bá povoleno se k tomuto MySQL serveru pøipojit",
-"Pou-B¾íváte MySQL jako anonymní u¾ivatel a anonymní u¾ivatelé nemají povoleno mìnit hesla",
-"Na zm-Bìnu hesel ostatním musíte mít právo provést update tabulek v databázi mysql",
-"V tabulce user nen-Bí ¾ádný odpovídající øádek",
-"Nalezen-Bých øádkù: %ld Zmìnìno: %ld Varování: %ld",
-"Nemohu vytvo-Bøit nový thread (errno %d). Pokud je je¹tì nìjaká volná pamì», podívejte se do manuálu na èást o chybách specifických pro jednotlivé operaèní systémy",
-"Po-Bèet sloupcù neodpovídá poètu hodnot na øádku %ld",
-"Nemohu znovuotev-Bøít tabulku: '%-.64s",
-"Neplatn-Bé u¾ití hodnoty NULL",
-"Regul-Bární výraz vrátil chybu '%-.64s'",
-"Pokud nen-Bí ¾ádná GROUP BY klauzule, není dovoleno souèasné pou¾ití GROUP polo¾ek (MIN(),MAX(),COUNT()...) s ne GROUP polo¾kami",
-"Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s'",
-"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s'@'%-.64s' pro tabulku '%-.64s'",
-"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s'@'%-.64s' pro sloupec '%-.64s' v tabulce '%-.64s'",
-"Neplatn-Bý pøíkaz GRANT/REVOKE. Prosím, pøeètìte si v manuálu, jaká privilegia je mo¾né pou¾ít.",
-"Argument p-Bøíkazu GRANT u¾ivatel nebo stroj je pøíli¹ dlouhý",
-"Tabulka '%-.64s.%s' neexistuje",
-"Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s' pro tabulku '%-.64s'",
-"Pou-B¾itý pøíkaz není v této verzi MySQL povolen",
-"Va-B¹e syntaxe je nìjaká divná",
-"Zpo-B¾dìný insert threadu nebyl schopen získat po¾adovaný zámek pro tabulku %-.64s",
-"P-Bøíli¹ mnoho zpo¾dìných threadù",
-"Zru-B¹eno spojení %ld do databáze: '%-.64s' u¾ivatel: '%-.64s' (%s)",
-"Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'",
-"Zji-B¹tìna chyba pøi ètení z roury spojení",
-"Zji-B¹tìna chyba fcntl()",
-"P-Bøíchozí packety v chybném poøadí",
-"Nemohu rozkomprimovat komunika-Bèní packet",
-"Zji-B¹tìna chyba pøi ètení komunikaèního packetu",
-"Zji-B¹tìn timeout pøi ètení komunikaèního packetu",
-"Zji-B¹tìna chyba pøi zápisu komunikaèního packetu",
-"Zji-B¹tìn timeout pøi zápisu komunikaèního packetu",
-"V-Býsledný øetìzec je del¹í ne¾ 'max_allowed_packet'",
-"Typ pou-B¾ité tabulky nepodporuje BLOB/TEXT sloupce",
-"Typ pou-B¾ité tabulky nepodporuje AUTO_INCREMENT sloupce",
-"INSERT DELAYED nen-Bí mo¾no s tabulkou '%-.64s' pou¾ít, proto¾e je zamèená pomocí LOCK TABLES",
-"Nespr-Bávné jméno sloupce '%-.100s'",
-"Handler pou-B¾ité tabulky neumí indexovat sloupce '%-.64s'",
-"V-B¹echny tabulky v MERGE tabulce nejsou definovány stejnì",
-"Kv-Bùli unique constraintu nemozu zapsat do tabulky '%-.64s'",
-"BLOB sloupec '%-.64s' je pou-B¾it ve specifikaci klíèe bez délky",
-"V-B¹echny èásti primárního klíèe musejí být NOT NULL; pokud potøebujete NULL, pou¾ijte UNIQUE",
-"V-Býsledek obsahuje více ne¾ jeden øádek",
-"Tento typ tabulky vy-B¾aduje primární klíè",
-"Tato verze MySQL nen-Bí zkompilována s podporou RAID",
-"Update tabulky bez WHERE s kl-Bíèem není v módu bezpeèných update dovoleno",
-"Kl-Bíè '%-.64s' v tabulce '%-.64s' neexistuje",
-"Nemohu otev-Bøít tabulku",
-"Handler tabulky nepodporuje %s",
-"Proveden-Bí tohoto pøíkazu není v transakci dovoleno",
-"Chyba %d p-Bøi COMMIT",
-"Chyba %d p-Bøi ROLLBACK",
-"Chyba %d p-Bøi FLUSH_LOGS",
-"Chyba %d p-Bøi CHECKPOINT",
-"Spojen-Bí %ld do databáze: '%-.64s' u¾ivatel: '%-.32s' stroj: `%-.64s' (%-.64s) bylo pøeru¹eno",
-"Handler tabulky nepodporuje bin-Bární dump",
-"Binlog uzav-Bøen pøi pokusu o FLUSH MASTER",
-"P-Bøebudování indexu dumpnuté tabulky '%-.64s' nebylo úspì¹né",
-"Chyba masteru: '%-.64s'",
-"S-Bí»ová chyba pøi ètení z masteru",
-"S-Bí»ová chyba pøi zápisu na master",
-"-B®ádný sloupec nemá vytvoøen fulltextový index",
-"Nemohu prov-Bést zadaný pøíkaz, proto¾e existují aktivní zamèené tabulky nebo aktivní transakce",
-"Nezn-Bámá systémová promìnná '%-.64s'",
-"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a mìla by být opravena",
-"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updatable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
deleted file mode 100644
index 18ebe5712f8..00000000000
--- a/sql/share/danish/errmsg.txt
+++ /dev/null
@@ -1,324 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Knud Riishøjgård knudriis@post.tele.dk 99 &&
- Carsten H. Pedersen, carsten.pedersen@bitbybit.dk oct. 1999 / aug. 2001. */
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NEJ",
-"JA",
-"Kan ikke oprette filen '%-.64s' (Fejlkode: %d)",
-"Kan ikke oprette tabellen '%-.64s' (Fejlkode: %d)",
-"Kan ikke oprette databasen '%-.64s' (Fejlkode: %d)",
-"Kan ikke oprette databasen '%-.64s'; databasen eksisterer",
-"Kan ikke slette (droppe) '%-.64s'; databasen eksisterer ikke",
-"Fejl ved sletning (drop) af databasen (kan ikke slette '%-.64s', Fejlkode %d)",
-"Fejl ved sletting af database (kan ikke slette folderen '%-.64s', Fejlkode %d)",
-"Fejl ved sletning af '%-.64s' (Fejlkode: %d)",
-"Kan ikke læse posten i systemfolderen",
-"Kan ikke læse status af '%-.64s' (Fejlkode: %d)",
-"Kan ikke læse aktive folder (Fejlkode: %d)",
-"Kan ikke låse fil (Fejlkode: %d)",
-"Kan ikke åbne fil: '%-.64s' (Fejlkode: %d)",
-"Kan ikke finde fila: '%-.64s' (Fejlkode: %d)",
-"Kan ikke læse folder '%-.64s' (Fejlkode: %d)",
-"Kan ikke skifte folder til '%-.64s' (Fejlkode: %d)",
-"Posten er ændret siden sidste læsning '%-.64s'",
-"Ikke mere diskplads (%s). Venter på at få frigjort plads...",
-"Kan ikke skrive, flere ens nøgler i tabellen '%-.64s'",
-"Fejl ved lukning af '%-.64s' (Fejlkode: %d)",
-"Fejl ved læsning af '%-.64s' (Fejlkode: %d)",
-"Fejl ved omdøbning af '%-.64s' til '%-.64s' (Fejlkode: %d)",
-"Fejl ved skriving av filen '%-.64s' (Fejlkode: %d)",
-"'%-.64s' er låst mod opdateringer",
-"Sortering afbrudt",
-"View '%-.64s' eksisterer ikke for '%-.64s'",
-"Modtog fejl %d fra tabel håndteringen",
-"Denne mulighed eksisterer ikke for tabeltypen '%-.64s'",
-"Kan ikke finde posten i '%-.64s'",
-"Forkert indhold i: '%-.64s'",
-"Fejl i indeksfilen til tabellen '%-.64s'; prøv at reparere den",
-"Gammel indeksfil for tabellen '%-.64s'; reparer den",
-"'%-.64s' er skrivebeskyttet",
-"Ikke mere hukommelse. Genstart serveren og prøv igen (mangler %d bytes)",
-"Ikke mere sorteringshukommelse. Øg sorteringshukommelse (sort buffer size) for serveren",
-"Uventet afslutning på fil (eof) ved læsning af filen '%-.64s' (Fejlkode: %d)",
-"For mange forbindelser (connections)",
-"Udgået for tråde/hukommelse",
-"Kan ikke få værtsnavn for din adresse",
-"Forkert håndtryk (handshake)",
-"Adgang nægtet bruger: '%-.32s'@'%-.64s' til databasen '%-.64s'",
-"Adgang nægtet bruger: '%-.32s'@'%-.64s' (Bruger adgangskode: %s)",
-"Ingen database valgt",
-"Ukendt kommando",
-"Kolonne '%-.64s' kan ikke være NULL",
-"Ukendt database '%-.64s'",
-"Tabellen '%-.64s' findes allerede",
-"Ukendt tabel '%-.64s'",
-"Felt: '%-.64s' i tabel %s er ikke entydigt",
-"Database nedlukning er i gang",
-"Ukendt kolonne '%-.64s' i tabel %s",
-"Brugte '%-.64s' som ikke var i group by",
-"Kan ikke gruppere på '%-.64s'",
-"Udtrykket har summer (sum) funktioner og kolonner i samme udtryk",
-"Kolonne tæller stemmer ikke med antallet af værdier",
-"Navnet '%-.64s' er for langt",
-"Feltnavnet '%-.64s' findes allerede",
-"Indeksnavnet '%-.64s' findes allerede",
-"Ens værdier '%-.64s' for indeks %d",
-"Forkert kolonnespecifikaton for felt '%-.64s'",
-"%s nær '%-.64s' på linje %d",
-"Forespørgsel var tom",
-"Tabellen/aliaset: '%-.64s' er ikke unikt",
-"Ugyldig standardværdi for '%-.64s'",
-"Flere primærnøgler specificeret",
-"For mange nøgler specificeret. Kun %d nøgler må bruges",
-"For mange nøgledele specificeret. Kun %d dele må bruges",
-"Specificeret nøgle var for lang. Maksimal nøglelængde er %d",
-"Nøglefeltet '%-.64s' eksisterer ikke i tabellen",
-"BLOB feltet '%-.64s' kan ikke bruges ved specifikation af indeks",
-"For stor feltlængde for kolonne '%-.64s' (maks = %d). Brug BLOB i stedet",
-"Der kan kun specificeres eet AUTO_INCREMENT-felt, og det skal være indekseret",
-"%s: klar til tilslutninger",
-"%s: Normal nedlukning\n",
-"%s: Fangede signal %d. Afslutter!!\n",
-"%s: Server lukket\n",
-"%s: Forceret nedlukning af tråd: %ld bruger: '%-.64s'\n",
-"Kan ikke oprette IP socket",
-"Tabellen '%-.64s' har ikke den nøgle, som blev brugt i CREATE INDEX. Genopret tabellen",
-"Felt adskiller er ikke som forventet, se dokumentationen",
-"Man kan ikke bruge faste feltlængder med BLOB. Brug i stedet 'fields terminated by'.",
-"Filen '%-.64s' skal være i database-folderen og kunne læses af alle",
-"Filen '%-.64s' eksisterer allerede",
-"Poster: %ld Fjernet: %ld Sprunget over: %ld Advarsler: %ld",
-"Poster: %ld Ens: %ld",
-"Forkert indeksdel. Den anvendte nøgledel er ikke en streng eller længden er større end nøglelængden",
-"Man kan ikke slette alle felter med ALTER TABLE. Brug DROP TABLE i stedet.",
-"Kan ikke udføre DROP '%-.64s'. Undersøg om feltet/nøglen eksisterer.",
-"Poster: %ld Ens: %ld Advarsler: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Ukendt tråd id: %lu",
-"Du er ikke ejer af tråden %lu",
-"Ingen tabeller i brug",
-"For mange tekststrenge til specifikationen af SET i kolonne %-.64s",
-"Kan ikke lave unikt log-filnavn %s.(1-999)\n",
-"Tabellen '%-.64s' var låst med READ lås og kan ikke opdateres",
-"Tabellen '%-.64s' var ikke låst med LOCK TABLES",
-"BLOB feltet '%-.64s' kan ikke have en standard værdi",
-"Ugyldigt database navn '%-.64s'",
-"Ugyldigt tabel navn '%-.64s'",
-"SELECT ville undersøge for mange poster og ville sandsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET SQL_BIG_SELECTS=1 hvis udtrykket er korrekt",
-"Ukendt fejl",
-"Ukendt procedure %s",
-"Forkert antal parametre til proceduren %s",
-"Forkert(e) parametre til proceduren %s",
-"Ukendt tabel '%-.64s' i %s",
-"Feltet '%-.64s' er anvendt to gange",
-"Forkert brug af grupperings-funktion",
-"Tabellen '%-.64s' bruger et filtypenavn som ikke findes i denne MySQL version",
-"En tabel skal have mindst een kolonne",
-"Tabellen '%-.64s' er fuld",
-"Ukendt tegnsæt: '%-.64s'",
-"For mange tabeller. MySQL kan kun bruge %d tabeller i et join",
-"For mange felter",
-"For store poster. Max post størrelse, uden BLOB's, er %d. Du må lave nogle felter til BLOB's",
-"Thread stack brugt: Brugt: %ld af en %ld stak. Brug 'mysqld -O thread_stack=#' for at allokere en større stak om nødvendigt",
-"Krydsreferencer fundet i OUTER JOIN; check dine ON conditions",
-"Kolonne '%-.32s' bruges som UNIQUE eller INDEX men er ikke defineret som NOT NULL",
-"Kan ikke læse funktionen '%-.64s'",
-"Kan ikke starte funktionen '%-.64s'; %-.80s",
-"Angivelse af sti ikke tilladt for delt bibliotek",
-"Funktionen '%-.64s' findes allerede",
-"Kan ikke åbne delt bibliotek '%-.64s' (errno: %d %s)",
-"Kan ikke finde funktionen '%-.64s' i bibliotek'",
-"Funktionen '%-.64s' er ikke defineret",
-"Værten er blokeret på grund af mange fejlforespørgsler. Lås op med 'mysqladmin flush-hosts'",
-"Værten '%-.64s' kan ikke tilkoble denne MySQL-server",
-"Du bruger MySQL som anonym bruger. Anonyme brugere må ikke ændre adgangskoder",
-"Du skal have tilladelse til at opdatere tabeller i MySQL databasen for at ændre andres adgangskoder",
-"Kan ikke finde nogen tilsvarende poster i bruger tabellen",
-"Poster fundet: %ld Ændret: %ld Advarsler: %ld",
-"Kan ikke danne en ny tråd (fejl nr. %d). Hvis computeren ikke er løbet tør for hukommelse, kan du se i brugervejledningen for en mulig operativ-system - afhængig fejl",
-"Kolonne antallet stemmer ikke overens med antallet af værdier i post %ld",
-"Kan ikke genåbne tabel '%-.64s",
-"Forkert brug af nulværdi (NULL)",
-"Fik fejl '%-.64s' fra regexp",
-"Sammenblanding af GROUP kolonner (MIN(),MAX(),COUNT()...) uden GROUP kolonner er ikke tilladt, hvis der ikke er noget GROUP BY prædikat",
-"Denne tilladelse findes ikke for brugeren '%-.32s' på vært '%-.64s'",
-"%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s'@'%-.64s' for tabellen '%-.64s'",
-"%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s'@'%-.64s' for kolonne '%-.64s' in tabellen '%-.64s'",
-"Forkert GRANT/REVOKE kommando. Se i brugervejledningen hvilke privilegier der kan specificeres.",
-"Værts- eller brugernavn for langt til GRANT",
-"Tabellen '%-.64s.%-.64s' eksisterer ikke",
-"Denne tilladelse eksisterer ikke for brugeren '%-.32s' på vært '%-.64s' for tabellen '%-.64s'",
-"Den brugte kommando er ikke tilladt med denne udgave af MySQL",
-"Der er en fejl i SQL syntaksen",
-"Forsinket indsættelse tråden (delayed insert thread) kunne ikke opnå lås på tabellen %-.64s",
-"For mange slettede tråde (threads) i brug",
-"Afbrudt forbindelse %ld til database: '%-.64s' bruger: '%-.64s' (%-.64s)",
-"Modtog en datapakke som var større end 'max_allowed_packet'",
-"Fik læsefejl fra forbindelse (connection pipe)",
-"Fik fejlmeddelelse fra fcntl()",
-"Modtog ikke datapakker i korrekt rækkefølge",
-"Kunne ikke dekomprimere kommunikations-pakke (communication packet)",
-"Fik fejlmeddelelse ved læsning af kommunikations-pakker (communication packets)",
-"Timeout-fejl ved læsning af kommunukations-pakker (communication packets)",
-"Fik fejlmeddelelse ved skrivning af kommunukations-pakker (communication packets)",
-"Timeout-fejl ved skrivning af kommunukations-pakker (communication packets)",
-"Strengen med resultater er større end 'max_allowed_packet'",
-"Denne tabeltype understøtter ikke brug af BLOB og TEXT kolonner",
-"Denne tabeltype understøtter ikke brug af AUTO_INCREMENT kolonner",
-"INSERT DELAYED kan ikke bruges med tabellen '%-.64s', fordi tabellen er låst med LOCK TABLES",
-"Forkert kolonnenavn '%-.100s'",
-"Den brugte tabeltype kan ikke indeksere kolonnen '%-.64s'",
-"Tabellerne i MERGE er ikke defineret ens",
-"Kan ikke skrive til tabellen '%-.64s' fordi det vil bryde CONSTRAINT regler",
-"BLOB kolonnen '%-.64s' brugt i nøglespecifikation uden nøglelængde",
-"Alle dele af en PRIMARY KEY skal være NOT NULL; Hvis du skal bruge NULL i nøglen, brug UNIQUE istedet",
-"Resultatet bestod af mere end een række",
-"Denne tabeltype kræver en primærnøgle",
-"Denne udgave af MySQL er ikke oversat med understøttelse af RAID",
-"Du bruger sikker opdaterings modus ('safe update mode') og du forsøgte at opdatere en tabel uden en WHERE klausul, der gør brug af et KEY felt",
-"Nøglen '%-.64s' eksisterer ikke i tabellen '%-.64s'",
-"Kan ikke åbne tabellen",
-"Denne tabeltype understøtter ikke %s",
-"Du må ikke bruge denne kommando i en transaktion",
-"Modtog fejl %d mens kommandoen COMMIT blev udført",
-"Modtog fejl %d mens kommandoen ROLLBACK blev udført",
-"Modtog fejl %d mens kommandoen FLUSH_LOGS blev udført",
-"Modtog fejl %d mens kommandoen CHECKPOINT blev udført",
-"Afbrød forbindelsen %ld til databasen '%-.64s' bruger: '%-.32s' vært: `%-.64s' (%-.64s)",
-"Denne tabeltype unserstøtter ikke binært tabeldump",
-"Binlog blev lukket mens kommandoen FLUSH MASTER blev udført",
-"Kunne ikke genopbygge indekset for den dumpede tabel '%-.64s'",
-"Fejl fra master: '%-.64s'",
-"Netværksfejl ved læsning fra master",
-"Netværksfejl ved skrivning til master",
-"Kan ikke finde en FULLTEXT nøgle som svarer til kolonne listen",
-"Kan ikke udføre den givne kommando fordi der findes aktive, låste tabeller eller fordi der udføres en transaktion",
-"Ukendt systemvariabel '%-.64s'",
-"Tabellen '%-.64s' er markeret med fejl og bør repareres",
-"Tabellen '%-.64s' er markeret med fejl og sidste (automatiske?) REPAIR fejlede",
-"Advarsel: Visse data i tabeller der ikke understøtter transaktioner kunne ikke tilbagestilles",
-"Fler-udtryks transaktion krævede mere plads en 'max_binlog_cache_size' bytes. Forhøj værdien af denne variabel og prøv igen",
-"Denne handling kunne ikke udføres med kørende slave, brug først kommandoen STOP SLAVE",
-"Denne handling kræver en kørende slave. Konfigurer en slave og brug kommandoen START SLAVE",
-"Denne server er ikke konfigureret som slave. Ret in config-filen eller brug kommandoen CHANGE MASTER TO",
-"Could not initialize master info structure, more error messages can be found in the MySQL error log",
-"Kunne ikke danne en slave-tråd; check systemressourcerne",
-"Brugeren %-.64s har allerede mere end 'max_user_connections' aktive forbindelser",
-"Du må kun bruge konstantudtryk med SET",
-"Lock wait timeout overskredet",
-"Det totale antal låse overstiger størrelsen på låse-tabellen",
-"Update lås kan ikke opnås under en READ UNCOMMITTED transaktion",
-"DROP DATABASE er ikke tilladt mens en tråd holder på globalt read lock",
-"CREATE DATABASE er ikke tilladt mens en tråd holder på globalt read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Modtog fejl %d '%-.100s' fra %s",
-"Modtog temporary fejl %d '%-.100s' fra %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
deleted file mode 100644
index 54377b5949a..00000000000
--- a/sql/share/dutch/errmsg.txt
+++ /dev/null
@@ -1,333 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Dutch error messages (share/dutch/errmsg.txt)
- 2001-08-02 - Arjen Lentz (agl@bitbike.com)
- Completed earlier partial translation; worked on consistency and spelling.
- 2002-01-29 - Arjen Lentz (arjen@mysql.com)
- 2002-04-11 - Arjen Lentz (arjen@mysql.com)
- 2002-06-13 - Arjen Lentz (arjen@mysql.com)
- 2002-08-08 - Arjen Lentz (arjen@mysql.com)
- 2002-08-22 - Arjen Lentz (arjen@mysql.com)
- Translated new error messages.
-*/
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NEE",
-"JA",
-"Kan file '%-.64s' niet aanmaken (Errcode: %d)",
-"Kan tabel '%-.64s' niet aanmaken (Errcode: %d)",
-"Kan database '%-.64s' niet aanmaken (Errcode: %d)",
-"Kan database '%-.64s' niet aanmaken; database bestaat reeds",
-"Kan database '%-.64s' niet verwijderen; database bestaat niet",
-"Fout bij verwijderen database (kan '%-.64s' niet verwijderen, Errcode: %d)",
-"Fout bij verwijderen database (kan rmdir '%-.64s' niet uitvoeren, Errcode: %d)",
-"Fout bij het verwijderen van '%-.64s' (Errcode: %d)",
-"Kan record niet lezen in de systeem tabel",
-"Kan de status niet krijgen van '%-.64s' (Errcode: %d)",
-"Kan de werkdirectory niet krijgen (Errcode: %d)",
-"Kan de file niet blokeren (Errcode: %d)",
-"Kan de file '%-.64s' niet openen (Errcode: %d)",
-"Kan de file: '%-.64s' niet vinden (Errcode: %d)",
-"Kan de directory niet lezen van '%-.64s' (Errcode: %d)",
-"Kan de directory niet veranderen naar '%-.64s' (Errcode: %d)",
-"Record is veranderd sinds de laatste lees activiteit in de tabel '%-.64s'",
-"Schijf vol (%s). Aan het wachten totdat er ruimte vrij wordt gemaakt...",
-"Kan niet schrijven, dubbele zoeksleutel in tabel '%-.64s'",
-"Fout bij het sluiten van '%-.64s' (Errcode: %d)",
-"Fout bij het lezen van file '%-.64s' (Errcode: %d)",
-"Fout bij het hernoemen van '%-.64s' naar '%-.64s' (Errcode: %d)",
-"Fout bij het wegschrijven van file '%-.64s' (Errcode: %d)",
-"'%-.64s' is geblokeerd tegen veranderingen",
-"Sorteren afgebroken",
-"View '%-.64s' bestaat niet voor '%-.64s'",
-"Fout %d van tabel handler",
-"Tabel handler voor '%-.64s' heeft deze optie niet",
-"Kan record niet vinden in '%-.64s'",
-"Verkeerde info in file: '%-.64s'",
-"Verkeerde zoeksleutel file voor tabel: '%-.64s'; probeer het te repareren",
-"Oude zoeksleutel file voor tabel '%-.64s'; repareer het!",
-"'%-.64s' is alleen leesbaar",
-"Geen geheugen meer. Herstart server en probeer opnieuw (%d bytes nodig)",
-"Geen geheugen om te sorteren. Verhoog de server sort buffer size",
-"Onverwachte eof gevonden tijdens het lezen van file '%-.64s' (Errcode: %d)",
-"Te veel verbindingen",
-"Geen thread geheugen meer; controleer of mysqld of andere processen al het beschikbare geheugen gebruikt. Zo niet, dan moet u wellicht 'ulimit' gebruiken om mysqld toe te laten meer geheugen te benutten, of u kunt extra swap ruimte toevoegen",
-"Kan de hostname niet krijgen van uw adres",
-"Verkeerde handshake",
-"Toegang geweigerd voor gebruiker: '%-.32s'@'%-.64s' naar database '%-.64s'",
-"Toegang geweigerd voor gebruiker: '%-.32s'@'%-.64s' (Wachtwoord gebruikt: %s)",
-"Geen database geselecteerd",
-"Onbekend commando",
-"Kolom '%-.64s' kan niet null zijn",
-"Onbekende database '%-.64s'",
-"Tabel '%-.64s' bestaat al",
-"Onbekende tabel '%-.64s'",
-"Kolom: '%-.64s' in %s is niet eenduidig",
-"Bezig met het stoppen van de server",
-"Onbekende kolom '%-.64s' in %s",
-"Opdracht gebruikt '%-.64s' dat niet in de GROUP BY voorkomt",
-"Kan '%-.64s' niet groeperen",
-"Opdracht heeft totaliseer functies en kolommen in dezelfde opdracht",
-"Het aantal kolommen komt niet overeen met het aantal opgegeven waardes",
-"Naam voor herkenning '%-.64s' is te lang",
-"Dubbele kolom naam '%-.64s'",
-"Dubbele zoeksleutel naam '%-.64s'",
-"Dubbele ingang '%-.64s' voor zoeksleutel %d",
-"Verkeerde kolom specificatie voor kolom '%-.64s'",
-"%s bij '%-.64s' in regel %d",
-"Query was leeg",
-"Niet unieke waarde tabel/alias: '%-.64s'",
-"Foutieve standaard waarde voor '%-.64s'",
-"Meerdere primaire zoeksleutels gedefinieerd",
-"Teveel zoeksleutels gedefinieerd. Maximaal zijn %d zoeksleutels toegestaan",
-"Teveel zoeksleutel onderdelen gespecificeerd. Maximaal %d onderdelen toegestaan",
-"Gespecificeerde zoeksleutel was te lang. De maximale lengte is %d",
-"Zoeksleutel kolom '%-.64s' bestaat niet in tabel",
-"BLOB kolom '%-.64s' kan niet gebruikt worden bij zoeksleutel specificatie",
-"Te grote kolomlengte voor '%-.64s' (max = %d). Maak hiervoor gebruik van het type BLOB",
-"Er kan slechts 1 autofield zijn en deze moet als zoeksleutel worden gedefinieerd.",
-"%s: klaar voor verbindingen",
-"%s: Normaal afgesloten \n",
-"%s: Signaal %d. Systeem breekt af!\n",
-"%s: Afsluiten afgerond\n",
-"%s: Afsluiten afgedwongen van thread %ld gebruiker: '%-.64s'\n",
-"Kan IP-socket niet openen",
-"Tabel '%-.64s' heeft geen INDEX zoals deze gemaakt worden met CREATE INDEX. Maak de tabel opnieuw",
-"De argumenten om velden te scheiden zijn anders dan verwacht. Raadpleeg de handleiding",
-"Bij het gebruik van BLOBs is het niet mogelijk om vaste rijlengte te gebruiken. Maak s.v.p. gebruik van 'fields terminated by'.",
-"Het bestand '%-.64s' dient in de database directory voor the komen of leesbaar voor iedereen te zijn.",
-"Het bestand '%-.64s' bestaat reeds",
-"Records: %ld Verwijderd: %ld Overgeslagen: %ld Waarschuwingen: %ld",
-"Records: %ld Dubbel: %ld",
-"Foutief sub-gedeelte van de zoeksleutel. De gebruikte zoeksleutel is geen onderdeel van een string of of de gebruikte lengte is langer dan de zoeksleutel",
-"Het is niet mogelijk alle velden te verwijderen met ALTER TABLE. Gebruik a.u.b. DROP TABLE hiervoor!",
-"Kan '%-.64s' niet weggooien. Controleer of het veld of de zoeksleutel daadwerkelijk bestaat.",
-"Records: %ld Dubbel: %ld Waarschuwing: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Onbekend thread id: %lu",
-"U bent geen bezitter van thread %lu",
-"Geen tabellen gebruikt.",
-"Teveel strings voor kolom %s en SET",
-"Het is niet mogelijk een unieke naam te maken voor de logfile %s.(1-999)\n",
-"Tabel '%-.64s' was gelocked met een lock om te lezen. Derhalve kunnen geen wijzigingen worden opgeslagen.",
-"Tabel '%-.64s' was niet gelocked met LOCK TABLES",
-"Blob veld '%-.64s' can geen standaardwaarde bevatten",
-"Databasenaam '%-.64s' is niet getoegestaan",
-"Niet toegestane tabelnaam '%-.64s'",
-"Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET SQL_BIG_SELECTS=1 als het stament in orde is.",
-"Onbekende Fout",
-"Onbekende procedure %s",
-"Foutief aantal parameters doorgegeven aan procedure %s",
-"Foutieve parameters voor procedure %s",
-"Onbekende tabel '%-.64s' in %s",
-"Veld '%-.64s' is dubbel gespecificeerd",
-"Ongeldig gebruik van GROUP-functie",
-"Tabel '%-.64s' gebruikt een extensie, die niet in deze MySQL-versie voorkomt.",
-"Een tabel moet minstens 1 kolom bevatten",
-"De tabel '%-.64s' is vol",
-"Onbekende character set: '%-.64s'",
-"Teveel tabellen. MySQL kan slechts %d tabellen in een join bevatten",
-"Te veel velden",
-"Rij-grootte is groter dan toegestaan. Maximale rij grootte, blobs niet meegeteld, is %d. U dient sommige velden in blobs te veranderen.",
-"Thread stapel overrun: Gebruikte: %ld van een %ld stack. Gebruik 'mysqld -O thread_stack=#' om een grotere stapel te definieren (indien noodzakelijk).",
-"Gekruiste afhankelijkheid gevonden in OUTER JOIN. Controleer uw ON-conditions",
-"Kolom '%-.64s' wordt gebruikt met UNIQUE of INDEX maar is niet gedefinieerd als NOT NULL",
-"Kan functie '%-.64s' niet laden",
-"Kan functie '%-.64s' niet initialiseren; %-.80s",
-"Geen pad toegestaan voor shared library",
-"Functie '%-.64s' bestaat reeds",
-"Kan shared library '%-.64s' niet openen (Errcode: %d %s)",
-"Kan functie '%-.64s' niet in library vinden",
-"Functie '%-.64s' is niet gedefinieerd",
-"Host '%-.64s' is geblokkeeerd vanwege te veel verbindings fouten. Deblokkeer met 'mysqladmin flush-hosts'",
-"Het is host '%-.64s' is niet toegestaan verbinding te maken met deze MySQL server",
-"U gebruikt MySQL als anonieme gebruiker en deze mogen geen wachtwoorden wijzigen",
-"U moet tabel update priveleges hebben in de mysql database om wachtwoorden voor anderen te mogen wijzigen",
-"Kan geen enkele passende rij vinden in de gebruikers tabel",
-"Passende rijen: %ld Gewijzigd: %ld Waarschuwingen: %ld",
-"Kan geen nieuwe thread aanmaken (Errcode: %d). Indien er geen tekort aan geheugen is kunt u de handleiding consulteren over een mogelijke OS afhankelijke fout",
-"Kolom aantal komt niet overeen met waarde aantal in rij %ld",
-"Kan tabel niet opnieuw openen: '%-.64s",
-"Foutief gebruik van de NULL waarde",
-"Fout '%-.64s' ontvangen van regexp",
-"Het mixen van GROUP kolommen (MIN(),MAX(),COUNT()...) met no-GROUP kolommen is foutief indien er geen GROUP BY clausule is",
-"Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.32s' op host '%-.64s'",
-"%-.16s commando geweigerd voor gebruiker: '%-.32s'@'%-.64s' voor tabel '%-.64s'",
-"%-.16s commando geweigerd voor gebruiker: '%-.32s'@'%-.64s' voor kolom '%-.64s' in tabel '%-.64s'",
-"Foutief GRANT/REVOKE commando. Raadpleeg de handleiding welke priveleges gebruikt kunnen worden.",
-"De host of gebruiker parameter voor GRANT is te lang",
-"Tabel '%-.64s.%s' bestaat niet",
-"Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.32s' op host '%-.64s' op tabel '%-.64s'",
-"Het used commando is niet toegestaan in deze MySQL versie",
-"Er is iets fout in de gebruikte syntax",
-"'Delayed insert' thread kon de aangevraagde 'lock' niet krijgen voor tabel %-.64s",
-"Te veel 'delayed' threads in gebruik",
-"Afgebroken verbinding %ld naar db: '%-.64s' gebruiker: '%-.64s' (%s)",
-"Groter pakket ontvangen dan 'max_allowed_packet'",
-"Kreeg leesfout van de verbindings pipe",
-"Kreeg fout van fcntl()",
-"Pakketten in verkeerde volgorde ontvangen",
-"Communicatiepakket kon niet worden gedecomprimeerd",
-"Fout bij het lezen van communicatiepakketten",
-"Timeout bij het lezen van communicatiepakketten",
-"Fout bij het schrijven van communicatiepakketten",
-"Timeout bij het schrijven van communicatiepakketten",
-"Resultaat string is langer dan 'max_allowed_packet'",
-"Het gebruikte tabel type ondersteunt geen BLOB/TEXT kolommen",
-"Het gebruikte tabel type ondersteunt geen AUTO_INCREMENT kolommen",
-"INSERT DELAYED kan niet worden gebruikt bij table '%-.64s', vanwege een 'lock met LOCK TABLES",
-"Incorrecte kolom naam '%-.100s'",
-"De gebruikte tabel 'handler' kan kolom '%-.64s' niet indexeren",
-"Niet alle tabellen in de MERGE tabel hebben identieke gedefinities",
-"Kan niet opslaan naar table '%-.64s' vanwege 'unique' beperking",
-"BLOB kolom '%-.64s' gebruikt in zoeksleutel specificatie zonder zoeksleutel lengte",
-"Alle delen van een PRIMARY KEY moeten NOT NULL zijn; Indien u NULL in een zoeksleutel nodig heeft kunt u UNIQUE gebruiken",
-"Resultaat bevatte meer dan een rij",
-"Dit tabel type heeft een primaire zoeksleutel nodig",
-"Deze versie van MySQL is niet gecompileerd met RAID ondersteuning",
-"U gebruikt 'safe update mode' en u probeerde een tabel te updaten zonder een WHERE met een KEY kolom",
-"Zoeksleutel '%-.64s' bestaat niet in tabel '%-.64s'",
-"Kan tabel niet openen",
-"De 'handler' voor de tabel ondersteund geen %s",
-"Het is u niet toegestaan dit commando uit te voeren binnen een transactie",
-"Kreeg fout %d tijdens COMMIT",
-"Kreeg fout %d tijdens ROLLBACK",
-"Kreeg fout %d tijdens FLUSH_LOGS",
-"Kreeg fout %d tijdens CHECKPOINT",
-"Afgebroken verbinding %ld naar db: '%-.64s' gebruiker: '%-.32s' host: `%-.64s' (%-.64s)",
-"De 'handler' voor de tabel ondersteund geen binaire tabel dump",
-"Binlog gesloten tijdens FLUSH MASTER poging",
-"Gefaald tijdens heropbouw index van gedumpte tabel '%-.64s'",
-"Fout van master: '%-.64s'",
-"Net fout tijdens lezen van master",
-"Net fout tijdens schrijven naar master",
-"Kan geen FULLTEXT index vinden passend bij de kolom lijst",
-"Kan het gegeven commando niet uitvoeren, want u heeft actieve gelockte tabellen of een actieve transactie",
-"Onbekende systeem variabele '%-.64s'",
-"Tabel '%-.64s' staat als gecrashed gemarkeerd en dient te worden gerepareerd",
-"Tabel '%-.64s' staat als gecrashed gemarkeerd en de laatste (automatische?) reparatie poging mislukte",
-"Waarschuwing: Roll back mislukt voor sommige buiten transacties gewijzigde tabellen",
-"Multi-statement transactie vereist meer dan 'max_binlog_cache_size' bytes opslag. Verhoog deze mysqld variabele en probeer opnieuw",
-"Deze operatie kan niet worden uitgevoerd met een actieve slave, doe eerst STOP SLAVE",
-"Deze operatie vereist een actieve slave, configureer slave en doe dan START SLAVE",
-"De server is niet geconfigureerd als slave, fix in configuratie bestand of met CHANGE MASTER TO",
-"Could not initialize master info structure, more error messages can be found in the MySQL error log",
-"Kon slave thread niet aanmaken, controleer systeem resources",
-"Gebruiker %-.64s heeft reeds meer dan 'max_user_connections' actieve verbindingen",
-"U mag alleen constante expressies gebruiken bij SET",
-"Lock wacht tijd overschreden",
-"Het totale aantal locks overschrijdt de lock tabel grootte",
-"Update locks kunnen niet worden verkregen tijdens een READ UNCOMMITTED transactie",
-"DROP DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit",
-"CREATE DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit",
-"Foutieve parameters voor %s",
-"'%-.32s'@'%-.64s' mag geen nieuwe gebruikers creeren",
-"Incorrecte tabel definitie; alle MERGE tabellen moeten tot dezelfde database behoren",
-"Deadlock gevonden tijdens lock-aanvraag poging; Probeer herstart van de transactie",
-"Het gebruikte tabel type ondersteund geen FULLTEXT indexen",
-"Kan foreign key beperking niet toevoegen",
-"Kan onderliggende rij niet toevoegen: foreign key beperking gefaald",
-"Kan bovenliggende rij nite verwijderen: foreign key beperking gefaald",
-"Fout bij opbouwen verbinding naar master: %-.128s",
-"Fout bij uitvoeren query op master: %-.128s",
-"Fout tijdens uitvoeren van commando %s: %-.128s",
-"Foutief gebruik van %s en %s",
-"De gebruikte SELECT commando's hebben een verschillend aantal kolommen",
-"Kan de query niet uitvoeren vanwege een conflicterende read lock",
-"Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld.",
-"Optie '%s' tweemaal gebruikt in opdracht",
-"Gebruiker '%-.64s' heeft het maximale gebruik van de '%s' faciliteit overschreden (huidige waarde: %ld)",
-"Toegang geweigerd. U moet het %-.128s privilege hebben voor deze operatie",
-"Variabele '%-.64s' is SESSION en kan niet worden gebruikt met SET GLOBAL",
-"Variabele '%-.64s' is GLOBAL en dient te worden gewijzigd met SET GLOBAL",
-"Variabele '%-.64s' heeft geen standaard waarde",
-"Variabele '%-.64s' kan niet worden gewijzigd naar de waarde '%-.64s'",
-"Foutief argumenttype voor variabele '%-.64s'",
-"Variabele '%-.64s' kan alleen worden gewijzigd, niet gelezen",
-"Foutieve toepassing/plaatsing van '%s'",
-"Deze versie van MySQL ondersteunt nog geen '%s'",
-"Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
deleted file mode 100644
index 1ae4e79bf01..00000000000
--- a/sql/share/english/errmsg.txt
+++ /dev/null
@@ -1,321 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NO",
-"YES",
-"Can't create file '%-.64s' (errno: %d)",
-"Can't create table '%-.64s' (errno: %d)",
-"Can't create database '%-.64s' (errno: %d)",
-"Can't create database '%-.64s'; database exists",
-"Can't drop database '%-.64s'; database doesn't exist",
-"Error dropping database (can't delete '%-.64s', errno: %d)",
-"Error dropping database (can't rmdir '%-.64s', errno: %d)",
-"Error on delete of '%-.64s' (errno: %d)",
-"Can't read record in system table",
-"Can't get status of '%-.64s' (errno: %d)",
-"Can't get working directory (errno: %d)",
-"Can't lock file (errno: %d)",
-"Can't open file: '%-.64s' (errno: %d)",
-"Can't find file: '%-.64s' (errno: %d)",
-"Can't read dir of '%-.64s' (errno: %d)",
-"Can't change dir to '%-.64s' (errno: %d)",
-"Record has changed since last read in table '%-.64s'",
-"Disk full (%s); waiting for someone to free some space...",
-"Can't write; duplicate key in table '%-.64s'",
-"Error on close of '%-.64s' (errno: %d)",
-"Error reading file '%-.64s' (errno: %d)",
-"Error on rename of '%-.64s' to '%-.64s' (errno: %d)",
-"Error writing file '%-.64s' (errno: %d)",
-"'%-.64s' is locked against change",
-"Sort aborted",
-"View '%-.64s' doesn't exist for '%-.64s'",
-"Got error %d from storage engine",
-"Table storage engine for '%-.64s' doesn't have this option",
-"Can't find record in '%-.64s'",
-"Incorrect information in file: '%-.64s'",
-"Incorrect key file for table '%-.64s'; try to repair it",
-"Old key file for table '%-.64s'; repair it!",
-"Table '%-.64s' is read only",
-"Out of memory; restart server and try again (needed %d bytes)",
-"Out of sort memory; increase server sort buffer size",
-"Unexpected EOF found when reading file '%-.64s' (errno: %d)",
-"Too many connections",
-"Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to use 'ulimit' to allow mysqld to use more memory or you can add more swap space",
-"Can't get hostname for your address",
-"Bad handshake",
-"Access denied for user '%-.32s'@'%-.64s' to database '%-.64s'",
-"Access denied for user '%-.32s'@'%-.64s' (using password: %s)",
-"No database selected",
-"Unknown command",
-"Column '%-.64s' cannot be null",
-"Unknown database '%-.64s'",
-"Table '%-.64s' already exists",
-"Unknown table '%-.100s'",
-"Column '%-.64s' in %-.64s is ambiguous",
-"Server shutdown in progress",
-"Unknown column '%-.64s' in '%-.64s'",
-"'%-.64s' isn't in GROUP BY",
-"Can't group on '%-.64s'",
-"Statement has sum functions and columns in same statement",
-"Column count doesn't match value count",
-"Identifier name '%-.100s' is too long",
-"Duplicate column name '%-.64s'",
-"Duplicate key name '%-.64s'",
-"Duplicate entry '%-.64s' for key %d",
-"Incorrect column specifier for column '%-.64s'",
-"%s near '%-.80s' at line %d",
-"Query was empty",
-"Not unique table/alias: '%-.64s'",
-"Invalid default value for '%-.64s'",
-"Multiple primary key defined",
-"Too many keys specified; max %d keys allowed",
-"Too many key parts specified; max %d parts allowed",
-"Specified key was too long; max key length is %d bytes",
-"Key column '%-.64s' doesn't exist in table",
-"BLOB column '%-.64s' can't be used in key specification with the used table type",
-"Column length too big for column '%-.64s' (max = %d); use BLOB or TEXT instead",
-"Incorrect table definition; there can be only one auto column and it must be defined as a key",
-"%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d",
-"%s: Normal shutdown\n",
-"%s: Got signal %d. Aborting!\n",
-"%s: Shutdown complete\n",
-"%s: Forcing close of thread %ld user: '%-.32s'\n",
-"Can't create IP socket",
-"Table '%-.64s' has no index like the one used in CREATE INDEX; recreate the table",
-"Field separator argument is not what is expected; check the manual",
-"You can't use fixed rowlength with BLOBs; please use 'fields terminated by'",
-"The file '%-.64s' must be in the database directory or be readable by all",
-"File '%-.80s' already exists",
-"Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld",
-"Records: %ld Duplicates: %ld",
-"Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys",
-"You can't delete all columns with ALTER TABLE; use DROP TABLE instead",
-"Can't DROP '%-.64s'; check that column/key exists",
-"Records: %ld Duplicates: %ld Warnings: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Unknown thread id: %lu",
-"You are not owner of thread %lu",
-"No tables used",
-"Too many strings for column %-.64s and SET",
-"Can't generate a unique log-filename %-.64s.(1-999)\n",
-"Table '%-.64s' was locked with a READ lock and can't be updated",
-"Table '%-.64s' was not locked with LOCK TABLES",
-"BLOB/TEXT column '%-.64s' can't have a default value",
-"Incorrect database name '%-.100s'",
-"Incorrect table name '%-.100s'",
-"The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay",
-"Unknown error",
-"Unknown procedure '%-.64s'",
-"Incorrect parameter count to procedure '%-.64s'",
-"Incorrect parameters to procedure '%-.64s'",
-"Unknown table '%-.64s' in %-.32s",
-"Column '%-.64s' specified twice",
-"Invalid use of group function",
-"Table '%-.64s' uses an extension that doesn't exist in this MySQL version",
-"A table must have at least 1 column",
-"The table '%-.64s' is full",
-"Unknown character set: '%-.64s'",
-"Too many tables; MySQL can only use %d tables in a join",
-"Too many columns",
-"Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs",
-"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
-"Cross dependency found in OUTER JOIN; examine your ON conditions",
-"Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
-"Can't load function '%-.64s'",
-"Can't initialize function '%-.64s'; %-.80s",
-"No paths allowed for shared library",
-"Function '%-.64s' already exists",
-"Can't open shared library '%-.64s' (errno: %d %-.64s)",
-"Can't find function '%-.64s' in library",
-"Function '%-.64s' is not defined",
-"Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'",
-"Host '%-.64s' is not allowed to connect to this MySQL server",
-"You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords",
-"You must have privileges to update tables in the mysql database to be able to change passwords for others",
-"Can't find any matching row in the user table",
-"Rows matched: %ld Changed: %ld Warnings: %ld",
-"Can't create a new thread (errno %d); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug",
-"Column count doesn't match value count at row %ld",
-"Can't reopen table: '%-.64s'",
-"Invalid use of NULL value",
-"Got error '%-.64s' from regexp",
-"Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause",
-"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for table '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
-"Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used",
-"The host or user argument to GRANT is too long",
-"Table '%-.64s.%-.64s' doesn't exist",
-"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
-"The used command is not allowed with this MySQL version",
-"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use",
-"Delayed insert thread couldn't get requested lock for table %-.64s",
-"Too many delayed threads in use",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' (%-.64s)",
-"Got a packet bigger than 'max_allowed_packet' bytes",
-"Got a read error from the connection pipe",
-"Got an error from fcntl()",
-"Got packets out of order",
-"Couldn't uncompress communication packet",
-"Got an error reading communication packets",
-"Got timeout reading communication packets",
-"Got an error writing communication packets",
-"Got timeout writing communication packets",
-"Result string is longer than 'max_allowed_packet' bytes",
-"The used table type doesn't support BLOB/TEXT columns",
-"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s' because it is locked with LOCK TABLES",
-"Incorrect column name '%-.100s'",
-"The used storage engine can't index column '%-.64s'",
-"All tables in the MERGE table are not identically defined",
-"Can't write, because of unique constraint, to table '%-.64s'",
-"BLOB/TEXT column '%-.64s' used in key specification without a key length",
-"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
-"This table type requires a primary key",
-"This version of MySQL is not compiled with RAID support",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The storage engine for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The storage engine for the table does not support binary table dump",
-"Binlog closed, cannot RESET MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add or update a child row: a foreign key constraint fails",
-"Cannot delete or update a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you will get problems if you get an unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu; new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode; you must restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated; use '%s' instead",
-"The target table %-.100s of the %s is not updatable",
-"The '%s' feature is disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated incorrect %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
new file mode 100644
index 00000000000..050bbe86948
--- /dev/null
+++ b/sql/share/errmsg.txt
@@ -0,0 +1,5348 @@
+languages czech=cze latin2, danish=dan latin1, dutch=nla latin1, english=eng latin1, estonian=est latin7, french=fre latin1, german=ger latin1, greek=greek greek, hungarian=hun latin2, italian=ita latin1, japanese=jpn ujis, japanese-sjis=jps sjis, korean=kor euckr, norwegian-ny=norwegian-ny latin1, norwegian=nor latin1, polish=pol latin2, portuguese=por latin1, romanian=rum latin2, russian=rus koi8r, serbian=serbian cp1250, slovak=slo latin2, spanish=spa latin1, swedish=swe latin1, ukrainian=ukr koi8u;
+
+default-language eng
+
+start-error-number 1000
+
+ER_HASHCHK
+ eng "hashchk"
+ER_NISAMCHK
+ eng "isamchk"
+ER_NO
+ cze "NE"
+ dan "NEJ"
+ nla "NEE"
+ eng "NO"
+ est "EI"
+ fre "NON"
+ ger "Nein"
+ greek "Ï×É"
+ hun "NEM"
+ kor "¾Æ´Ï¿À"
+ nor "NEI"
+ norwegian-ny "NEI"
+ pol "NIE"
+ por "NÃO"
+ rum "NU"
+ rus "îåô"
+ serbian "NE"
+ slo "NIE"
+ ukr "î¶"
+ER_YES
+ cze "ANO"
+ dan "JA"
+ nla "JA"
+ eng "YES"
+ est "JAH"
+ fre "OUI"
+ ger "Ja"
+ greek "ÍÁÉ"
+ hun "IGEN"
+ ita "SI"
+ kor "¿¹"
+ nor "JA"
+ norwegian-ny "JA"
+ pol "TAK"
+ por "SIM"
+ rum "DA"
+ rus "äá"
+ serbian "DA"
+ slo "Áno"
+ spa "SI"
+ ukr "ôáë"
+ER_CANT_CREATE_FILE
+ cze "Nemohu vytvo-Bøit soubor '%-.64s' (chybový kód: %d)"
+ dan "Kan ikke oprette filen '%-.64s' (Fejlkode: %d)"
+ nla "Kan file '%-.64s' niet aanmaken (Errcode: %d)"
+ eng "Can't create file '%-.64s' (errno: %d)"
+ est "Ei suuda luua faili '%-.64s' (veakood: %d)"
+ fre "Ne peut créer le fichier '%-.64s' (Errcode: %d)"
+ ger "Kann Datei '%-.64s' nicht erzeugen (Fehler: %d)"
+ greek "Áäýíáôç ç äçìéïõñãßá ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A '%-.64s' file nem hozhato letre (hibakod: %d)"
+ ita "Impossibile creare il file '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)"
+ kor "È­ÀÏ '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke opprette fila '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje opprette fila '%-.64s' (Feilkode: %d)"
+ pol "Nie mo¿na stworzyæ pliku '%-.64s' (Kod b³êdu: %d)"
+ por "Não pode criar o arquivo '%-.64s' (erro no. %d)"
+ rum "Nu pot sa creez fisierul '%-.64s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÆÁÊÌ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da kreiram file '%-.64s' (errno: %d)"
+ slo "Nemô¾em vytvori» súbor '%-.64s' (chybový kód: %d)"
+ spa "No puedo crear archivo '%-.64s' (Error: %d)"
+ swe "Kan inte skapa filen '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_CANT_CREATE_TABLE
+ cze "Nemohu vytvo-Bøit tabulku '%-.64s' (chybový kód: %d)"
+ dan "Kan ikke oprette tabellen '%-.64s' (Fejlkode: %d)"
+ nla "Kan tabel '%-.64s' niet aanmaken (Errcode: %d)"
+ eng "Can't create table '%-.64s' (errno: %d)"
+ jps "'%-.64s' ƒe[ƒuƒ‹‚ªì‚ê‚Ü‚¹‚ñ.(errno: %d)",
+ est "Ei suuda luua tabelit '%-.64s' (veakood: %d)"
+ fre "Ne peut créer la table '%-.64s' (Errcode: %d)"
+ ger "Kann Tabelle '%-.64s' nicht erzeugen (Fehler: %d)"
+ greek "Áäýíáôç ç äçìéïõñãßá ôïõ ðßíáêá '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A '%-.64s' tabla nem hozhato letre (hibakod: %d)"
+ ita "Impossibile creare la tabella '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Æ¡¼¥Ö¥ë¤¬ºî¤ì¤Þ¤»¤ó.(errno: %d)"
+ kor "Å×À̺í '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke opprette tabellen '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje opprette tabellen '%-.64s' (Feilkode: %d)"
+ pol "Nie mo¿na stworzyæ tabeli '%-.64s' (Kod b³êdu: %d)"
+ por "Não pode criar a tabela '%-.64s' (erro no. %d)"
+ rum "Nu pot sa creez tabla '%-.64s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÔÁÂÌÉÃÕ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da kreiram tabelu '%-.64s' (errno: %d)"
+ slo "Nemô¾em vytvori» tabuµku '%-.64s' (chybový kód: %d)"
+ spa "No puedo crear tabla '%-.64s' (Error: %d)"
+ swe "Kan inte skapa tabellen '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÔÁÂÌÉÃÀ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_CANT_CREATE_DB
+ cze "Nemohu vytvo-Bøit databázi '%-.64s' (chybový kód: %d)"
+ dan "Kan ikke oprette databasen '%-.64s' (Fejlkode: %d)"
+ nla "Kan database '%-.64s' niet aanmaken (Errcode: %d)"
+ eng "Can't create database '%-.64s' (errno: %d)"
+ jps "'%-.64s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ (errno: %d)",
+ est "Ei suuda luua andmebaasi '%-.64s' (veakood: %d)"
+ fre "Ne peut créer la base '%-.64s' (Erreur %d)"
+ ger "Kann Datenbank '%-.64s' nicht erzeugen (Fehler: %d)"
+ greek "Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Az '%-.64s' adatbazis nem hozhato letre (hibakod: %d)"
+ ita "Impossibile creare il database '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)"
+ kor "µ¥ÀÌŸº£À̽º '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke opprette databasen '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje opprette databasen '%-.64s' (Feilkode: %d)"
+ pol "Nie mo¿na stworzyæ bazy danych '%-.64s' (Kod b³êdu: %d)"
+ por "Não pode criar o banco de dados '%-.64s' (erro no. %d)"
+ rum "Nu pot sa creez baza de date '%-.64s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da kreiram bazu '%-.64s' (errno: %d)"
+ slo "Nemô¾em vytvori» databázu '%-.64s' (chybový kód: %d)"
+ spa "No puedo crear base de datos '%-.64s' (Error: %d)"
+ swe "Kan inte skapa databasen '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_DB_CREATE_EXISTS
+ cze "Nemohu vytvo-Bøit databázi '%-.64s'; databáze ji¾ existuje"
+ dan "Kan ikke oprette databasen '%-.64s'; databasen eksisterer"
+ nla "Kan database '%-.64s' niet aanmaken; database bestaat reeds"
+ eng "Can't create database '%-.64s'; database exists"
+ jps "'%-.64s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ.Šù‚É‚»‚̃f[ƒ^ƒx[ƒX‚ª‘¶Ý‚µ‚Ü‚·",
+ est "Ei suuda luua andmebaasi '%-.64s': andmebaas juba eksisteerib"
+ fre "Ne peut créer la base '%-.64s'; elle existe déjà"
+ ger "Kann Datenbank '%-.64s' nicht erzeugen. Datenbank '%-.64s' existiert bereits"
+ greek "Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s'; Ç âÜóç äåäïìÝíùí õðÜñ÷åé Þäç"
+ hun "Az '%-.64s' adatbazis nem hozhato letre Az adatbazis mar letezik"
+ ita "Impossibile creare il database '%-.64s'; il database esiste"
+ jpn "'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó.´û¤Ë¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬Â¸ºß¤·¤Þ¤¹"
+ kor "µ¥ÀÌŸº£À̽º '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÔ"
+ nor "Kan ikke opprette databasen '%-.64s'; databasen eksisterer"
+ norwegian-ny "Kan ikkje opprette databasen '%-.64s'; databasen eksisterer"
+ pol "Nie mo¿na stworzyæ bazy danych '%-.64s'; baza danych ju¿ istnieje"
+ por "Não pode criar o banco de dados '%-.64s'; este banco de dados já existe"
+ rum "Nu pot sa creez baza de date '%-.64s'; baza de date exista deja"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s'. âÁÚÁ ÄÁÎÎÙÈ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Ne mogu da kreiram bazu '%-.64s'; baza veæ postoji."
+ slo "Nemô¾em vytvori» databázu '%-.64s'; databáza existuje"
+ spa "No puedo crear base de datos '%-.64s'; la base de datos ya existe"
+ swe "Databasen '%-.64s' existerar redan"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s'. âÁÚÁ ÄÁÎÎÉÈ ¦ÓÎÕ¤"
+ER_DB_DROP_EXISTS
+ cze "Nemohu zru-B¹it databázi '%-.64s', databáze neexistuje"
+ dan "Kan ikke slette (droppe) '%-.64s'; databasen eksisterer ikke"
+ nla "Kan database '%-.64s' niet verwijderen; database bestaat niet"
+ eng "Can't drop database '%-.64s'; database doesn't exist"
+ jps "'%-.64s' ƒf[ƒ^ƒx[ƒX‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ. ‚»‚̃f[ƒ^ƒx[ƒX‚ª‚È‚¢‚Ì‚Å‚·.",
+ est "Ei suuda kustutada andmebaasi '%-.64s': andmebaasi ei eksisteeri"
+ fre "Ne peut effacer la base '%-.64s'; elle n'existe pas"
+ ger "Kann Datenbank '%-.64s' nicht löschen. Keine Datenbank '%-.64s' vorhanden"
+ greek "Áäýíáôç ç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí '%-.64s'. Ç âÜóç äåäïìÝíùí äåí õðÜñ÷åé"
+ hun "A(z) '%-.64s' adatbazis nem szuntetheto meg. Az adatbazis nem letezik"
+ ita "Impossibile cancellare '%-.64s'; il database non esiste"
+ jpn "'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤òÇË´þ¤Ç¤­¤Þ¤»¤ó. ¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬¤Ê¤¤¤Î¤Ç¤¹."
+ kor "µ¥ÀÌŸº£À̽º '%-.64s'¸¦ Á¦°ÅÇÏÁö ¸øÇß½À´Ï´Ù. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÏÁö ¾ÊÀ½ "
+ nor "Kan ikke fjerne (drop) '%-.64s'; databasen eksisterer ikke"
+ norwegian-ny "Kan ikkje fjerne (drop) '%-.64s'; databasen eksisterer ikkje"
+ pol "Nie mo¿na usun?æ bazy danych '%-.64s'; baza danych nie istnieje"
+ por "Não pode eliminar o banco de dados '%-.64s'; este banco de dados não existe"
+ rum "Nu pot sa drop baza de date '%-.64s'; baza da date este inexistenta"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s'. ôÁËÏÊ ÂÁÚÙ ÄÁÎÎÙÈ ÎÅÔ"
+ serbian "Ne mogu da izbrišem bazu '%-.64s'; baza ne postoji."
+ slo "Nemô¾em zmaza» databázu '%-.64s'; databáza neexistuje"
+ spa "No puedo eliminar base de datos '%-.64s'; la base de datos no existe"
+ swe "Kan inte radera databasen '%-.64s'; databasen finns inte"
+ ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s'. âÁÚÁ ÄÁÎÎÉÈ ÎÅ ¦ÓÎÕ¤"
+ER_DB_DROP_DELETE
+ cze "Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.64s', chyba %d)"
+ dan "Fejl ved sletning (drop) af databasen (kan ikke slette '%-.64s', Fejlkode %d)"
+ nla "Fout bij verwijderen database (kan '%-.64s' niet verwijderen, Errcode: %d)"
+ eng "Error dropping database (can't delete '%-.64s', errno: %d)"
+ jps "ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.64s' ‚ð휂ł«‚Ü‚¹‚ñ, errno: %d)",
+ est "Viga andmebaasi kustutamisel (ei suuda kustutada faili '%-.64s', veakood: %d)"
+ fre "Ne peut effacer la base '%-.64s' (erreur %d)"
+ ger "Fehler beim Löschen der Datenbank ('%-.64s' kann nicht gelöscht werden, Fehlernuumer: %d)"
+ greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ '%-.64s', êùäéêüò ëÜèïõò: %d)"
+ hun "Adatbazis megszuntetesi hiba ('%-.64s' nem torolheto, hibakod: %d)"
+ ita "Errore durante la cancellazione del database (impossibile cancellare '%-.64s', errno: %d)"
+ jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.64s' ¤òºï½ü¤Ç¤­¤Þ¤»¤ó, errno: %d)"
+ kor "µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯('%-.64s'¸¦ »èÁ¦ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved fjerning (drop) av databasen (kan ikke slette '%-.64s', feil %d)"
+ norwegian-ny "Feil ved fjerning (drop) av databasen (kan ikkje slette '%-.64s', feil %d)"
+ pol "B³?d podczas usuwania bazy danych (nie mo¿na usun?æ '%-.64s', b³?d %d)"
+ por "Erro ao eliminar banco de dados (não pode eliminar '%-.64s' - erro no. %d)"
+ rum "Eroare dropuind baza de date (nu pot sa sterg '%-.64s', Eroare: %d)"
+ rus "ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ ÂÁÚÙ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ '%-.64s', ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.64s', errno: %d)"
+ slo "Chyba pri mazaní databázy (nemô¾em zmaza» '%-.64s', chybový kód: %d)"
+ spa "Error eliminando la base de datos(no puedo borrar '%-.64s', error %d)"
+ swe "Fel vid radering av databasen (Kan inte radera '%-.64s'. Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.64s', ÐÏÍÉÌËÁ: %d)"
+ER_DB_DROP_RMDIR
+ cze "Chyba p-Bøi ru¹ení databáze (nemohu vymazat adresáø '%-.64s', chyba %d)"
+ dan "Fejl ved sletting af database (kan ikke slette folderen '%-.64s', Fejlkode %d)"
+ nla "Fout bij verwijderen database (kan rmdir '%-.64s' niet uitvoeren, Errcode: %d)"
+ eng "Error dropping database (can't rmdir '%-.64s', errno: %d)"
+ jps "ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.64s' ‚ð rmdir ‚Å‚«‚Ü‚¹‚ñ, errno: %d)",
+ est "Viga andmebaasi kustutamisel (ei suuda kustutada kataloogi '%-.64s', veakood: %d)"
+ fre "Erreur en effaçant la base (rmdir '%-.64s', erreur %d)"
+ ger "Fehler beim Löschen der Datenbank (Verzeichnis '%-.64s' kann nicht gelöscht werden, Fehlernummer: %d)"
+ greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ ôïõ öáêÝëëïõ '%-.64s', êùäéêüò ëÜèïõò: %d)"
+ hun "Adatbazis megszuntetesi hiba ('%-.64s' nem szuntetheto meg, hibakod: %d)"
+ ita "Errore durante la cancellazione del database (impossibile rmdir '%-.64s', errno: %d)"
+ jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.64s' ¤ò rmdir ¤Ç¤­¤Þ¤»¤ó, errno: %d)"
+ kor "µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯(rmdir '%-.64s'¸¦ ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved sletting av database (kan ikke slette katalogen '%-.64s', feil %d)"
+ norwegian-ny "Feil ved sletting av database (kan ikkje slette katalogen '%-.64s', feil %d)"
+ pol "B³?d podczas usuwania bazy danych (nie mo¿na wykonaæ rmdir '%-.64s', b³?d %d)"
+ por "Erro ao eliminar banco de dados (não pode remover diretório '%-.64s' - erro no. %d)"
+ rum "Eroare dropuind baza de date (nu pot sa rmdir '%-.64s', Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ËÁÔÁÌÏÇ '%-.64s', ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem direktorijum '%-.64s', errno: %d)"
+ slo "Chyba pri mazaní databázy (nemô¾em vymaza» adresár '%-.64s', chybový kód: %d)"
+ spa "Error eliminando la base de datos (No puedo borrar directorio '%-.64s', error %d)"
+ swe "Fel vid radering av databasen (Kan inte radera biblioteket '%-.64s'. Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÔÅËÕ '%-.64s', ÐÏÍÉÌËÁ: %d)"
+ER_CANT_DELETE_FILE
+ cze "Chyba p-Bøi výmazu '%-.64s' (chybový kód: %d)"
+ dan "Fejl ved sletning af '%-.64s' (Fejlkode: %d)"
+ nla "Fout bij het verwijderen van '%-.64s' (Errcode: %d)"
+ eng "Error on delete of '%-.64s' (errno: %d)"
+ jps "'%-.64s' ‚Ì휂ªƒGƒ‰[ (errno: %d)",
+ est "Viga '%-.64s' kustutamisel (veakood: %d)"
+ fre "Erreur en effaçant '%-.64s' (Errcode: %d)"
+ ger "Fehler beim Löschen von '%-.64s' (Fehler: %d)"
+ greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Torlesi hiba: '%-.64s' (hibakod: %d)"
+ ita "Errore durante la cancellazione di '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¤Îºï½ü¤¬¥¨¥é¡¼ (errno: %d)"
+ kor "'%-.64s' »èÁ¦ Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved sletting av '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Feil ved sletting av '%-.64s' (Feilkode: %d)"
+ pol "B³?d podczas usuwania '%-.64s' (Kod b³êdu: %d)"
+ por "Erro na remoção de '%-.64s' (erro no. %d)"
+ rum "Eroare incercind sa delete '%-.64s' (Eroare: %d)"
+ rus "ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri brisanju '%-.64s' (errno: %d)"
+ slo "Chyba pri mazaní '%-.64s' (chybový kód: %d)"
+ spa "Error en el borrado de '%-.64s' (Error: %d)"
+ swe "Kan inte radera filen '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_CANT_FIND_SYSTEM_REC
+ cze "Nemohu -Bèíst záznam v systémové tabulce"
+ dan "Kan ikke læse posten i systemfolderen"
+ nla "Kan record niet lezen in de systeem tabel"
+ eng "Can't read record in system table"
+ jps "system table ‚̃ŒƒR[ƒh‚ð“Ç‚ÞŽ–‚ª‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½",
+ est "Ei suuda lugeda kirjet süsteemsest tabelist"
+ fre "Ne peut lire un enregistrement de la table 'system'"
+ ger "Datensatz in der Systemtabelle nicht lesbar"
+ greek "Áäýíáôç ç áíÜãíùóç åããñáöÞò áðü ðßíáêá ôïõ óõóôÞìáôïò"
+ hun "Nem olvashato rekord a rendszertablaban"
+ ita "Impossibile leggere il record dalla tabella di sistema"
+ jpn "system table ¤Î¥ì¥³¡¼¥É¤òÆɤà»ö¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿"
+ kor "system Å×ÀÌºí¿¡¼­ ·¹Äڵ带 ÀÐÀ» ¼ö ¾ø½À´Ï´Ù."
+ nor "Kan ikke lese posten i systemkatalogen"
+ norwegian-ny "Kan ikkje lese posten i systemkatalogen"
+ pol "Nie mo¿na odczytaæ rekordu z tabeli systemowej"
+ por "Não pode ler um registro numa tabela do sistema"
+ rum "Nu pot sa citesc cimpurile in tabla de system (system table)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÞÉÔÁÔØ ÚÁÐÉÓØ × ÓÉÓÔÅÍÎÏÊ ÔÁÂÌÉÃÅ"
+ serbian "Ne mogu da proèitam slog iz sistemske tabele"
+ slo "Nemô¾em èíta» záznam v systémovej tabuµke"
+ spa "No puedo leer el registro en la tabla del sistema"
+ swe "Hittar inte posten i systemregistret"
+ ukr "îÅ ÍÏÖÕ ÚÞÉÔÁÔÉ ÚÁÐÉÓ Ú ÓÉÓÔÅÍÎϧ ÔÁÂÌÉæ"
+ER_CANT_GET_STAT
+ cze "Nemohu z-Bískat stav '%-.64s' (chybový kód: %d)"
+ dan "Kan ikke læse status af '%-.64s' (Fejlkode: %d)"
+ nla "Kan de status niet krijgen van '%-.64s' (Errcode: %d)"
+ eng "Can't get status of '%-.64s' (errno: %d)"
+ jps "'%-.64s' ‚̃XƒeƒCƒ^ƒX‚ª“¾‚ç‚ê‚Ü‚¹‚ñ. (errno: %d)",
+ est "Ei suuda lugeda '%-.64s' olekut (veakood: %d)"
+ fre "Ne peut obtenir le status de '%-.64s' (Errcode: %d)"
+ ger "Kann Status von '%-.64s' nicht ermitteln (Fehler: %d)"
+ greek "Áäýíáôç ç ëÞøç ðëçñïöïñéþí ãéá ôçí êáôÜóôáóç ôïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A(z) '%-.64s' statusza nem allapithato meg (hibakod: %d)"
+ ita "Impossibile leggere lo stato di '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¤Î¥¹¥Æ¥¤¥¿¥¹¤¬ÆÀ¤é¤ì¤Þ¤»¤ó. (errno: %d)"
+ kor "'%-.64s'ÀÇ »óŸ¦ ¾òÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke lese statusen til '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje lese statusen til '%-.64s' (Feilkode: %d)"
+ pol "Nie mo¿na otrzymaæ statusu '%-.64s' (Kod b³êdu: %d)"
+ por "Não pode obter o status de '%-.64s' (erro no. %d)"
+ rum "Nu pot sa obtin statusul lui '%-.64s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÏÌÕÞÉÔØ ÓÔÁÔÕÓÎÕÀ ÉÎÆÏÒÍÁÃÉÀ Ï '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da dobijem stanje file-a '%-.64s' (errno: %d)"
+ slo "Nemô¾em zisti» stav '%-.64s' (chybový kód: %d)"
+ spa "No puedo obtener el estado de '%-.64s' (Error: %d)"
+ swe "Kan inte läsa filinformationen (stat) från '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÏÔÒÉÍÁÔÉ ÓÔÁÔÕÓ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_CANT_GET_WD
+ cze "Chyba p-Bøi zji¹»ování pracovní adresáø (chybový kód: %d)"
+ dan "Kan ikke læse aktive folder (Fejlkode: %d)"
+ nla "Kan de werkdirectory niet krijgen (Errcode: %d)"
+ eng "Can't get working directory (errno: %d)"
+ jps "working directory ‚𓾂鎖‚ª‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½ (errno: %d)",
+ est "Ei suuda identifitseerida jooksvat kataloogi (veakood: %d)"
+ fre "Ne peut obtenir le répertoire de travail (Errcode: %d)"
+ ger "Kann Arbeitsverzeichnis nicht ermitteln (Fehler: %d)"
+ greek "Ï öÜêåëëïò åñãáóßáò äåí âñÝèçêå (êùäéêüò ëÜèïõò: %d)"
+ hun "A munkakonyvtar nem allapithato meg (hibakod: %d)"
+ ita "Impossibile leggere la directory di lavoro (errno: %d)"
+ jpn "working directory ¤òÆÀ¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿ (errno: %d)"
+ kor "¼öÇà µð·ºÅ丮¸¦ ãÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke lese aktiv katalog(Feilkode: %d)"
+ norwegian-ny "Kan ikkje lese aktiv katalog(Feilkode: %d)"
+ pol "Nie mo¿na rozpoznaæ aktualnego katalogu (Kod b³êdu: %d)"
+ por "Não pode obter o diretório corrente (erro no. %d)"
+ rum "Nu pot sa obtin directorul current (working directory) (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÏÐÒÅÄÅÌÉÔØ ÒÁÂÏÞÉÊ ËÁÔÁÌÏÇ (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da dobijem trenutni direktorijum (errno: %d)"
+ slo "Nemô¾em zisti» pracovný adresár (chybový kód: %d)"
+ spa "No puedo acceder al directorio (Error: %d)"
+ swe "Kan inte inte läsa aktivt bibliotek. (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ×ÉÚÎÁÞÉÔÉ ÒÏÂÏÞÕ ÔÅËÕ (ÐÏÍÉÌËÁ: %d)"
+ER_CANT_LOCK
+ cze "Nemohu uzamknout soubor (chybov-Bý kód: %d)"
+ dan "Kan ikke låse fil (Fejlkode: %d)"
+ nla "Kan de file niet blokeren (Errcode: %d)"
+ eng "Can't lock file (errno: %d)"
+ jps "ƒtƒ@ƒCƒ‹‚ðƒƒbƒN‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
+ est "Ei suuda lukustada faili (veakood: %d)"
+ fre "Ne peut verrouiller le fichier (Errcode: %d)"
+ ger "Datei kann nicht gesperrt werden (Fehler: %d)"
+ greek "Ôï áñ÷åßï äåí ìðïñåß íá êëåéäùèåß (êùäéêüò ëÜèïõò: %d)"
+ hun "A file nem zarolhato. (hibakod: %d)"
+ ita "Impossibile il locking il file (errno: %d)"
+ jpn "¥Õ¥¡¥¤¥ë¤ò¥í¥Ã¥¯¤Ç¤­¤Þ¤»¤ó (errno: %d)"
+ kor "È­ÀÏÀ» Àá±×Áö(lock) ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke låse fila (Feilkode: %d)"
+ norwegian-ny "Kan ikkje låse fila (Feilkode: %d)"
+ pol "Nie mo¿na zablokowaæ pliku (Kod b³êdu: %d)"
+ por "Não pode travar o arquivo (erro no. %d)"
+ rum "Nu pot sa lock fisierul (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÏÓÔÁ×ÉÔØ ÂÌÏËÉÒÏ×ËÕ ÎÁ ÆÁÊÌÅ (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da zakljuèam file (errno: %d)"
+ slo "Nemô¾em zamknú» súbor (chybový kód: %d)"
+ spa "No puedo bloquear archivo: (Error: %d)"
+ swe "Kan inte låsa filen. (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÚÁÂÌÏËÕ×ÁÔÉ ÆÁÊÌ (ÐÏÍÉÌËÁ: %d)"
+ER_CANT_OPEN_FILE
+ cze "Nemohu otev-Bøít soubor '%-.64s' (chybový kód: %d)"
+ dan "Kan ikke åbne fil: '%-.64s' (Fejlkode: %d)"
+ nla "Kan de file '%-.64s' niet openen (Errcode: %d)"
+ eng "Can't open file: '%-.64s' (errno: %d)"
+ jps "'%-.64s' ƒtƒ@ƒCƒ‹‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
+ est "Ei suuda avada faili '%-.64s' (veakood: %d)"
+ fre "Ne peut ouvrir le fichier: '%-.64s' (Errcode: %d)"
+ ger "Datei '%-.64s' nicht öffnen (Fehler: %d)"
+ greek "Äåí åßíáé äõíáôü íá áíïé÷ôåß ôï áñ÷åßï: '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A '%-.64s' file nem nyithato meg (hibakod: %d)"
+ ita "Impossibile aprire il file: '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)"
+ kor "È­ÀÏÀ» ¿­Áö ¸øÇß½À´Ï´Ù.: '%-.64s' (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke åpne fila: '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje åpne fila: '%-.64s' (Feilkode: %d)"
+ pol "Nie mo¿na otworzyæ pliku: '%-.64s' (Kod b³êdu: %d)"
+ por "Não pode abrir o arquivo '%-.64s' (erro no. %d)"
+ rum "Nu pot sa deschid fisierul: '%-.64s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÆÁÊÌ: '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da otvorim file: '%-.64s' (errno: %d)"
+ slo "Nemô¾em otvori» súbor: '%-.64s' (chybový kód: %d)"
+ spa "No puedo abrir archivo: '%-.64s' (Error: %d)"
+ swe "Kan inte använda '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÆÁÊÌ: '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_FILE_NOT_FOUND
+ cze "Nemohu naj-Bít soubor '%-.64s' (chybový kód: %d)"
+ dan "Kan ikke finde fila: '%-.64s' (Fejlkode: %d)"
+ nla "Kan de file: '%-.64s' niet vinden (Errcode: %d)"
+ eng "Can't find file: '%-.64s' (errno: %d)"
+ jps "'%-.64s' ƒtƒ@ƒCƒ‹‚ðŒ©•t‚¯‚鎖‚ª‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
+ est "Ei suuda leida faili '%-.64s' (veakood: %d)"
+ fre "Ne peut trouver le fichier: '%-.64s' (Errcode: %d)"
+ ger "Kann Datei '%-.64s' nicht finden (Fehler: %d)"
+ greek "Äåí âñÝèçêå ôï áñ÷åßï: '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A(z) '%-.64s' file nem talalhato (hibakod: %d)"
+ ita "Impossibile trovare il file: '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤ò¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó.(errno: %d)"
+ kor "È­ÀÏÀ» ãÁö ¸øÇß½À´Ï´Ù.: '%-.64s' (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke finne fila: '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje finne fila: '%-.64s' (Feilkode: %d)"
+ pol "Nie mo¿na znale¥æ pliku: '%-.64s' (Kod b³êdu: %d)"
+ por "Não pode encontrar o arquivo '%-.64s' (erro no. %d)"
+ rum "Nu pot sa gasesc fisierul: '%-.64s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÆÁÊÌ: '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da pronaðem file: '%-.64s' (errno: %d)"
+ slo "Nemô¾em nájs» súbor: '%-.64s' (chybový kód: %d)"
+ spa "No puedo encontrar archivo: '%-.64s' (Error: %d)"
+ swe "Hittar inte filen '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ ÆÁÊÌ: '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_CANT_READ_DIR
+ cze "Nemohu -Bèíst adresáø '%-.64s' (chybový kód: %d)"
+ dan "Kan ikke læse folder '%-.64s' (Fejlkode: %d)"
+ nla "Kan de directory niet lezen van '%-.64s' (Errcode: %d)"
+ eng "Can't read dir of '%-.64s' (errno: %d)"
+ jps "'%-.64s' ƒfƒBƒŒƒNƒgƒŠ‚ª“Ç‚ß‚Ü‚¹‚ñ.(errno: %d)",
+ est "Ei suuda lugeda kataloogi '%-.64s' (veakood: %d)"
+ fre "Ne peut lire le répertoire de '%-.64s' (Errcode: %d)"
+ ger "Verzeichnis von '%-.64s' nicht lesbar (Fehler: %d)"
+ greek "Äåí åßíáé äõíáôü íá äéáâáóôåß ï öÜêåëëïò ôïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A(z) '%-.64s' konyvtar nem olvashato. (hibakod: %d)"
+ ita "Impossibile leggere la directory di '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Ç¥£¥ì¥¯¥È¥ê¤¬Æɤá¤Þ¤»¤ó.(errno: %d)"
+ kor "'%-.64s'µð·ºÅ丮¸¦ ÀÐÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke lese katalogen '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje lese katalogen '%-.64s' (Feilkode: %d)"
+ pol "Nie mo¿na odczytaæ katalogu '%-.64s' (Kod b³êdu: %d)"
+ por "Não pode ler o diretório de '%-.64s' (erro no. %d)"
+ rum "Nu pot sa citesc directorul '%-.64s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÞÉÔÁÔØ ËÁÔÁÌÏÇ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da proèitam direktorijum '%-.64s' (errno: %d)"
+ slo "Nemô¾em èíta» adresár '%-.64s' (chybový kód: %d)"
+ spa "No puedo leer el directorio de '%-.64s' (Error: %d)"
+ swe "Kan inte läsa från bibliotek '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÔÅËÕ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_CANT_SET_WD
+ cze "Nemohu zm-Bìnit adresáø na '%-.64s' (chybový kód: %d)"
+ dan "Kan ikke skifte folder til '%-.64s' (Fejlkode: %d)"
+ nla "Kan de directory niet veranderen naar '%-.64s' (Errcode: %d)"
+ eng "Can't change dir to '%-.64s' (errno: %d)"
+ jps "'%-.64s' ƒfƒBƒŒƒNƒgƒŠ‚É chdir ‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
+ est "Ei suuda siseneda kataloogi '%-.64s' (veakood: %d)"
+ fre "Ne peut changer le répertoire pour '%-.64s' (Errcode: %d)"
+ ger "Kann nicht in das Verzeichnis '%-.64s' wechseln (Fehler: %d)"
+ greek "Áäýíáôç ç áëëáãÞ ôïõ ôñÝ÷ïíôïò êáôáëüãïõ óå '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Konyvtarvaltas nem lehetseges a(z) '%-.64s'-ba. (hibakod: %d)"
+ ita "Impossibile cambiare la directory in '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Ç¥£¥ì¥¯¥È¥ê¤Ë chdir ¤Ç¤­¤Þ¤»¤ó.(errno: %d)"
+ kor "'%-.64s'µð·ºÅ丮·Î À̵¿ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke skifte katalog til '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje skifte katalog til '%-.64s' (Feilkode: %d)"
+ pol "Nie mo¿na zmieniæ katalogu na '%-.64s' (Kod b³êdu: %d)"
+ por "Não pode mudar para o diretório '%-.64s' (erro no. %d)"
+ rum "Nu pot sa schimb directorul '%-.64s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÅÒÅÊÔÉ × ËÁÔÁÌÏÇ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da promenim direktorijum na '%-.64s' (errno: %d)"
+ slo "Nemô¾em vojs» do adresára '%-.64s' (chybový kód: %d)"
+ spa "No puedo cambiar al directorio de '%-.64s' (Error: %d)"
+ swe "Kan inte byta till '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÐÅÒÅÊÔÉ Õ ÔÅËÕ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_CHECKREAD
+ cze "Z-Báznam byl zmìnìn od posledního ètení v tabulce '%-.64s'"
+ dan "Posten er ændret siden sidste læsning '%-.64s'"
+ nla "Record is veranderd sinds de laatste lees activiteit in de tabel '%-.64s'"
+ eng "Record has changed since last read in table '%-.64s'"
+ est "Kirje tabelis '%-.64s' on muutunud viimasest lugemisest saadik"
+ fre "Enregistrement modifié depuis sa dernière lecture dans la table '%-.64s'"
+ ger "Datensatz hat sich seit dem letzten Zugriff auf Tabelle '%-.64s' geändert"
+ greek "Ç åããñáöÞ Ý÷åé áëëÜîåé áðü ôçí ôåëåõôáßá öïñÜ ðïõ áíáóýñèçêå áðü ôïí ðßíáêá '%-.64s'"
+ hun "A(z) '%-.64s' tablaban talalhato rekord megvaltozott az utolso olvasas ota"
+ ita "Il record e` cambiato dall'ultima lettura della tabella '%-.64s'"
+ kor "Å×À̺í '%-.64s'¿¡¼­ ¸¶Áö¸·À¸·Î ÀÐÀº ÈÄ Record°¡ º¯°æµÇ¾ú½À´Ï´Ù."
+ nor "Posten har blitt endret siden den ble lest '%-.64s'"
+ norwegian-ny "Posten har vorte endra sidan den sist vart lesen '%-.64s'"
+ pol "Rekord zosta³ zmieniony od ostaniego odczytania z tabeli '%-.64s'"
+ por "Registro alterado desde a última leitura da tabela '%-.64s'"
+ rum "Cimpul a fost schimbat de la ultima citire a tabelei '%-.64s'"
+ rus "úÁÐÉÓØ ÉÚÍÅÎÉÌÁÓØ Ó ÍÏÍÅÎÔÁ ÐÏÓÌÅÄÎÅÊ ×ÙÂÏÒËÉ × ÔÁÂÌÉÃÅ '%-.64s'"
+ serbian "Slog je promenjen od zadnjeg èitanja tabele '%-.64s'"
+ slo "Záznam bol zmenený od posledného èítania v tabuµke '%-.64s'"
+ spa "El registro ha cambiado desde la ultima lectura de la tabla '%-.64s'"
+ swe "Posten har förändrats sedan den lästes i register '%-.64s'"
+ ukr "úÁÐÉÓ ÂÕÌÏ ÚͦÎÅÎÏ Ú ÞÁÓÕ ÏÓÔÁÎÎØÏÇÏ ÞÉÔÁÎÎÑ Ú ÔÁÂÌÉæ '%-.64s'"
+ER_DISK_FULL
+ cze "Disk je pln-Bý (%s), èekám na uvolnìní nìjakého místa ..."
+ dan "Ikke mere diskplads (%s). Venter på at få frigjort plads..."
+ nla "Schijf vol (%s). Aan het wachten totdat er ruimte vrij wordt gemaakt..."
+ eng "Disk full (%s); waiting for someone to free some space..."
+ jps "Disk full (%s). ’N‚©‚ª‰½‚©‚ðŒ¸‚ç‚·‚Ü‚Å‚Ü‚Á‚Ä‚­‚¾‚³‚¢...",
+ est "Ketas täis (%s). Ootame kuni tekib vaba ruumi..."
+ fre "Disque plein (%s). J'attend que quelqu'un libère de l'espace..."
+ ger "Festplatte voll (%-.64s). Warte, bis jemand Platz schafft ..."
+ greek "Äåí õðÜñ÷åé ÷þñïò óôï äßóêï (%s). Ðáñáêáëþ, ðåñéìÝíåôå íá åëåõèåñùèåß ÷þñïò..."
+ hun "A lemez megtelt (%s)."
+ ita "Disco pieno (%s). In attesa che qualcuno liberi un po' di spazio..."
+ jpn "Disk full (%s). 狼¤¬²¿¤«¤ò¸º¤é¤¹¤Þ¤Ç¤Þ¤Ã¤Æ¤¯¤À¤µ¤¤..."
+ kor "Disk full (%s). ´Ù¸¥ »ç¶÷ÀÌ Áö¿ï¶§±îÁö ±â´Ù¸³´Ï´Ù..."
+ nor "Ikke mer diskplass (%s). Venter på å få frigjort plass..."
+ norwegian-ny "Ikkje meir diskplass (%s). Ventar på å få frigjort plass..."
+ pol "Dysk pe³ny (%s). Oczekiwanie na zwolnienie miejsca..."
+ por "Disco cheio (%s). Aguardando alguém liberar algum espaço..."
+ rum "Hard-disk-ul este plin (%s). Astept sa se elibereze ceva spatiu..."
+ rus "äÉÓË ÚÁÐÏÌÎÅÎ. (%s). ïÖÉÄÁÅÍ, ÐÏËÁ ËÔÏ-ÔÏ ÎÅ ÕÂÅÒÅÔ ÐÏÓÌÅ ÓÅÂÑ ÍÕÓÏÒ..."
+ serbian "Disk je pun (%s). Èekam nekoga da doðe i oslobodi nešto mesta..."
+ slo "Disk je plný (%s), èakám na uvoµnenie miesta..."
+ spa "Disco lleno (%s). Esperando para que se libere algo de espacio..."
+ swe "Disken är full (%s). Väntar tills det finns ledigt utrymme..."
+ ukr "äÉÓË ÚÁÐÏ×ÎÅÎÉÊ (%s). ÷ÉÞÉËÕÀ, ÄÏËÉ ÚצÌØÎÉÔØÓÑ ÔÒÏÈÉ Í¦ÓÃÑ..."
+ER_DUP_KEY 23000
+ cze "Nemohu zapsat, zdvojen-Bý klíè v tabulce '%-.64s'"
+ dan "Kan ikke skrive, flere ens nøgler i tabellen '%-.64s'"
+ nla "Kan niet schrijven, dubbele zoeksleutel in tabel '%-.64s'"
+ eng "Can't write; duplicate key in table '%-.64s'"
+ jps "table '%-.64s' ‚É key ‚ªd•¡‚µ‚Ä‚¢‚Ä‘‚«‚±‚ß‚Ü‚¹‚ñ",
+ est "Ei saa kirjutada, korduv võti tabelis '%-.64s'"
+ fre "Ecriture impossible, doublon dans une clé de la table '%-.64s'"
+ ger "Kann nicht speichern, Grund: doppelter Schlüssel in Tabelle '%-.64s'"
+ greek "Äåí åßíáé äõíáôÞ ç êáôá÷þñçóç, ç ôéìÞ õðÜñ÷åé Þäç óôïí ðßíáêá '%-.64s'"
+ hun "Irasi hiba, duplikalt kulcs a '%-.64s' tablaban."
+ ita "Scrittura impossibile: chiave duplicata nella tabella '%-.64s'"
+ jpn "table '%-.64s' ¤Ë key ¤¬½ÅÊ£¤·¤Æ¤¤¤Æ½ñ¤­¤³¤á¤Þ¤»¤ó"
+ kor "±â·ÏÇÒ ¼ö ¾øÀ¾´Ï´Ù., Å×À̺í '%-.64s'¿¡¼­ Áߺ¹ Å°"
+ nor "Kan ikke skrive, flere like nøkler i tabellen '%-.64s'"
+ norwegian-ny "Kan ikkje skrive, flere like nyklar i tabellen '%-.64s'"
+ pol "Nie mo¿na zapisaæ, powtórzone klucze w tabeli '%-.64s'"
+ por "Não pode gravar. Chave duplicada na tabela '%-.64s'"
+ rum "Nu pot sa scriu (can't write), cheie duplicata in tabela '%-.64s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÚÁÐÉÓØ, ÄÕÂÌÉÒÕÀÝÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉÃÅ '%-.64s'"
+ serbian "Ne mogu da pišem pošto postoji duplirani kljuè u tabeli '%-.64s'"
+ slo "Nemô¾em zapísa», duplikát kµúèa v tabuµke '%-.64s'"
+ spa "No puedo escribir, clave duplicada en la tabla '%-.64s'"
+ swe "Kan inte skriva, dubbel söknyckel i register '%-.64s'"
+ ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ, ÄÕÂÌÀÀÞÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉæ '%-.64s'"
+ER_ERROR_ON_CLOSE
+ cze "Chyba p-Bøi zavírání '%-.64s' (chybový kód: %d)"
+ dan "Fejl ved lukning af '%-.64s' (Fejlkode: %d)"
+ nla "Fout bij het sluiten van '%-.64s' (Errcode: %d)"
+ eng "Error on close of '%-.64s' (errno: %d)"
+ est "Viga faili '%-.64s' sulgemisel (veakood: %d)"
+ fre "Erreur a la fermeture de '%-.64s' (Errcode: %d)"
+ ger "Fehler beim Schließen von '%-.64s' (Fehler: %d)"
+ greek "ÐáñïõóéÜóôçêå ðñüâëçìá êëåßíïíôáò ôï '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Hiba a(z) '%-.64s' zarasakor. (hibakod: %d)"
+ ita "Errore durante la chiusura di '%-.64s' (errno: %d)"
+ kor "'%-.64s'´Ý´Â Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved lukking av '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Feil ved lukking av '%-.64s' (Feilkode: %d)"
+ pol "B³?d podczas zamykania '%-.64s' (Kod b³êdu: %d)"
+ por "Erro ao fechar '%-.64s' (erro no. %d)"
+ rum "Eroare inchizind '%-.64s' (errno: %d)"
+ rus "ïÛÉÂËÁ ÐÒÉ ÚÁËÒÙÔÉÉ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri zatvaranju '%-.64s' (errno: %d)"
+ slo "Chyba pri zatváraní '%-.64s' (chybový kód: %d)"
+ spa "Error en el cierre de '%-.64s' (Error: %d)"
+ swe "Fick fel vid stängning av '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÚÁËÒÉÔÉ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_ERROR_ON_READ
+ cze "Chyba p-Bøi ètení souboru '%-.64s' (chybový kód: %d)"
+ dan "Fejl ved læsning af '%-.64s' (Fejlkode: %d)"
+ nla "Fout bij het lezen van file '%-.64s' (Errcode: %d)"
+ eng "Error reading file '%-.64s' (errno: %d)"
+ jps "'%-.64s' ƒtƒ@ƒCƒ‹‚Ì“Ç‚Ýž‚݃Gƒ‰[ (errno: %d)",
+ est "Viga faili '%-.64s' lugemisel (veakood: %d)"
+ fre "Erreur en lecture du fichier '%-.64s' (Errcode: %d)"
+ ger "Fehler beim Lesen der Datei '%-.64s' (Fehler: %d)"
+ greek "Ðñüâëçìá êáôÜ ôçí áíÜãíùóç ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Hiba a '%-.64s'file olvasasakor. (hibakod: %d)"
+ ita "Errore durante la lettura del file '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤ÎÆɤ߹þ¤ß¥¨¥é¡¼ (errno: %d)"
+ kor "'%-.64s'È­ÀÏ Àб⠿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved lesing av '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Feil ved lesing av '%-.64s' (Feilkode: %d)"
+ pol "B³?d podczas odczytu pliku '%-.64s' (Kod b³êdu: %d)"
+ por "Erro ao ler arquivo '%-.64s' (erro no. %d)"
+ rum "Eroare citind fisierul '%-.64s' (errno: %d)"
+ rus "ïÛÉÂËÁ ÞÔÅÎÉÑ ÆÁÊÌÁ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri èitanju file-a '%-.64s' (errno: %d)"
+ slo "Chyba pri èítaní súboru '%-.64s' (chybový kód: %d)"
+ spa "Error leyendo el fichero '%-.64s' (Error: %d)"
+ swe "Fick fel vid läsning av '%-.64s' (Felkod %d)"
+ ukr "îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_ERROR_ON_RENAME
+ cze "Chyba p-Bøi pøejmenování '%-.64s' na '%-.64s' (chybový kód: %d)"
+ dan "Fejl ved omdøbning af '%-.64s' til '%-.64s' (Fejlkode: %d)"
+ nla "Fout bij het hernoemen van '%-.64s' naar '%-.64s' (Errcode: %d)"
+ eng "Error on rename of '%-.64s' to '%-.64s' (errno: %d)"
+ jps "'%-.64s' ‚ð '%-.64s' ‚É rename ‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
+ est "Viga faili '%-.64s' ümbernimetamisel '%-.64s'-ks (veakood: %d)"
+ fre "Erreur en renommant '%-.64s' en '%-.64s' (Errcode: %d)"
+ ger "Fehler beim Umbenennen von '%-.64s' in '%-.64s' (Fehler: %d)"
+ greek "Ðñüâëçìá êáôÜ ôçí ìåôïíïìáóßá ôïõ áñ÷åßïõ '%-.64s' to '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Hiba a '%-.64s' file atnevezesekor. (hibakod: %d)"
+ ita "Errore durante la rinominazione da '%-.64s' a '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¤ò '%-.64s' ¤Ë rename ¤Ç¤­¤Þ¤»¤ó (errno: %d)"
+ kor "'%-.64s'¸¦ '%-.64s'·Î À̸§ º¯°æÁß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved omdøping av '%-.64s' til '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Feil ved omdøyping av '%-.64s' til '%-.64s' (Feilkode: %d)"
+ pol "B³?d podczas zmieniania nazwy '%-.64s' na '%-.64s' (Kod b³êdu: %d)"
+ por "Erro ao renomear '%-.64s' para '%-.64s' (erro no. %d)"
+ rum "Eroare incercind sa renumesc '%-.64s' in '%-.64s' (errno: %d)"
+ rus "ïÛÉÂËÁ ÐÒÉ ÐÅÒÅÉÍÅÎÏ×ÁÎÉÉ '%-.64s' × '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri promeni imena '%-.64s' na '%-.64s' (errno: %d)"
+ slo "Chyba pri premenovávaní '%-.64s' na '%-.64s' (chybový kód: %d)"
+ spa "Error en el renombrado de '%-.64s' a '%-.64s' (Error: %d)"
+ swe "Kan inte byta namn från '%-.64s' till '%-.64s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÐÅÒÅÊÍÅÎÕ×ÁÔÉ '%-.64s' Õ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_ERROR_ON_WRITE
+ cze "Chyba p-Bøi zápisu do souboru '%-.64s' (chybový kód: %d)"
+ dan "Fejl ved skriving av filen '%-.64s' (Fejlkode: %d)"
+ nla "Fout bij het wegschrijven van file '%-.64s' (Errcode: %d)"
+ eng "Error writing file '%-.64s' (errno: %d)"
+ jps "'%-.64s' ƒtƒ@ƒCƒ‹‚ð‘‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
+ est "Viga faili '%-.64s' kirjutamisel (veakood: %d)"
+ fre "Erreur d'écriture du fichier '%-.64s' (Errcode: %d)"
+ ger "Fehler beim Speichern der Datei '%-.64s' (Fehler: %d)"
+ greek "Ðñüâëçìá êáôÜ ôçí áðïèÞêåõóç ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Hiba a '%-.64s' file irasakor. (hibakod: %d)"
+ ita "Errore durante la scrittura del file '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤ò½ñ¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)"
+ kor "'%-.64s'È­ÀÏ ±â·Ï Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved skriving av fila '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Feil ved skriving av fila '%-.64s' (Feilkode: %d)"
+ pol "B³?d podczas zapisywania pliku '%-.64s' (Kod b³êdu: %d)"
+ por "Erro ao gravar arquivo '%-.64s' (erro no. %d)"
+ rum "Eroare scriind fisierul '%-.64s' (errno: %d)"
+ rus "ïÛÉÂËÁ ÚÁÐÉÓÉ × ÆÁÊÌ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri upisu '%-.64s' (errno: %d)"
+ slo "Chyba pri zápise do súboru '%-.64s' (chybový kód: %d)"
+ spa "Error escribiendo el archivo '%-.64s' (Error: %d)"
+ swe "Fick fel vid skrivning till '%-.64s' (Felkod %d)"
+ ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_FILE_USED
+ cze "'%-.64s' je zam-Bèen proti zmìnám"
+ dan "'%-.64s' er låst mod opdateringer"
+ nla "'%-.64s' is geblokeerd tegen veranderingen"
+ eng "'%-.64s' is locked against change"
+ jps "'%-.64s' ‚̓ƒbƒN‚³‚ê‚Ä‚¢‚Ü‚·",
+ est "'%-.64s' on lukustatud muudatuste vastu"
+ fre "'%-.64s' est verrouillé contre les modifications"
+ ger "'%-.64s' ist für Änderungen gesperrt"
+ greek "'%-.64s' äåí åðéôñÝðïíôáé áëëáãÝò"
+ hun "'%-.64s' a valtoztatas ellen zarolva"
+ ita "'%-.64s' e` soggetto a lock contro i cambiamenti"
+ jpn "'%-.64s' ¤Ï¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤¹"
+ kor "'%-.64s'°¡ º¯°æÇÒ ¼ö ¾øµµ·Ï Àá°ÜÀÖÀ¾´Ï´Ù."
+ nor "'%-.64s' er låst mot oppdateringer"
+ norwegian-ny "'%-.64s' er låst mot oppdateringar"
+ pol "'%-.64s' jest zablokowany na wypadek zmian"
+ por "'%-.64s' está com travamento contra alterações"
+ rum "'%-.64s' este blocat pentry schimbari (loccked against change)"
+ rus "'%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÄÌÑ ÉÚÍÅÎÅÎÉÊ"
+ serbian "'%-.64s' je zakljuèan za upis"
+ slo "'%-.64s' je zamknutý proti zmenám"
+ spa "'%-.64s' esta bloqueado contra cambios"
+ swe "'%-.64s' är låst mot användning"
+ ukr "'%-.64s' ÚÁÂÌÏËÏ×ÁÎÉÊ ÎÁ ×ÎÅÓÅÎÎÑ ÚͦÎ"
+ER_FILSORT_ABORT
+ cze "T-Bøídìní pøeru¹eno"
+ dan "Sortering afbrudt"
+ nla "Sorteren afgebroken"
+ eng "Sort aborted"
+ jps "Sort ’†’f",
+ est "Sorteerimine katkestatud"
+ fre "Tri alphabétique abandonné"
+ ger "Sortiervorgang abgebrochen"
+ greek "Ç äéáäéêáóßá ôáîéíüìéóçò áêõñþèçêå"
+ hun "Sikertelen rendezes"
+ ita "Operazione di ordinamento abbandonata"
+ jpn "Sort ̾̂"
+ kor "¼ÒÆ®°¡ ÁߴܵǾú½À´Ï´Ù."
+ nor "Sortering avbrutt"
+ norwegian-ny "Sortering avbrote"
+ pol "Sortowanie przerwane"
+ por "Ordenação abortada"
+ rum "Sortare intrerupta"
+ rus "óÏÒÔÉÒÏ×ËÁ ÐÒÅÒ×ÁÎÁ"
+ serbian "Sortiranje je prekinuto"
+ slo "Triedenie preru¹ené"
+ spa "Ordeancion cancelada"
+ swe "Sorteringen avbruten"
+ ukr "óÏÒÔÕ×ÁÎÎÑ ÐÅÒÅÒ×ÁÎÏ"
+ER_FORM_NOT_FOUND
+ cze "Pohled '%-.64s' pro '%-.64s' neexistuje"
+ dan "View '%-.64s' eksisterer ikke for '%-.64s'"
+ nla "View '%-.64s' bestaat niet voor '%-.64s'"
+ eng "View '%-.64s' doesn't exist for '%-.64s'"
+ jps "View '%-.64s' ‚ª '%-.64s' ‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Vaade '%-.64s' ei eksisteeri '%-.64s' jaoks"
+ fre "La vue (View) '%-.64s' n'existe pas pour '%-.64s'"
+ ger "View '%-.64s' existiert für '%-.64s' nicht"
+ greek "Ôï View '%-.64s' äåí õðÜñ÷åé ãéá '%-.64s'"
+ hun "A(z) '%-.64s' nezet nem letezik a(z) '%-.64s'-hoz"
+ ita "La view '%-.64s' non esiste per '%-.64s'"
+ jpn "View '%-.64s' ¤¬ '%-.64s' ¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "ºä '%-.64s'°¡ '%-.64s'¿¡¼­´Â Á¸ÀçÇÏÁö ¾ÊÀ¾´Ï´Ù."
+ nor "View '%-.64s' eksisterer ikke for '%-.64s'"
+ norwegian-ny "View '%-.64s' eksisterar ikkje for '%-.64s'"
+ pol "Widok '%-.64s' nie istnieje dla '%-.64s'"
+ por "Visão '%-.64s' não existe para '%-.64s'"
+ rum "View '%-.64s' nu exista pentru '%-.64s'"
+ rus "ðÒÅÄÓÔÁ×ÌÅÎÉÅ '%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ ÄÌÑ '%-.64s'"
+ serbian "View '%-.64s' ne postoji za '%-.64s'"
+ slo "Pohµad '%-.64s' neexistuje pre '%-.64s'"
+ spa "La vista '%-.64s' no existe para '%-.64s'"
+ swe "Formulär '%-.64s' finns inte i '%-.64s'"
+ ukr "÷ÉÇÌÑÄ '%-.64s' ÎÅ ¦ÓÎÕ¤ ÄÌÑ '%-.64s'"
+ER_GET_ERRNO
+ cze "Obsluha tabulky vr-Bátila chybu %d"
+ dan "Modtog fejl %d fra tabel håndteringen"
+ nla "Fout %d van tabel handler"
+ eng "Got error %d from storage engine"
+ est "Tabeli handler tagastas vea %d"
+ fre "Reçu l'erreur %d du handler de la table"
+ ger "Fehler %d (Tabellenhandler)"
+ greek "ÅëÞöèç ìÞíõìá ëÜèïõò %d áðü ôïí ÷åéñéóôÞ ðßíáêá (table handler)"
+ hun "%d hibajelzes a tablakezelotol"
+ ita "Rilevato l'errore %d dal gestore delle tabelle"
+ jpn "Got error %d from table handler"
+ kor "Å×À̺í handler¿¡¼­ %d ¿¡·¯°¡ ¹ß»ý ÇÏ¿´½À´Ï´Ù."
+ nor "Mottok feil %d fra tabell håndterer"
+ norwegian-ny "Mottok feil %d fra tabell handterar"
+ pol "Otrzymano b³?d %d z obs³ugi tabeli"
+ por "Obteve erro %d no manipulador de tabelas"
+ rum "Eroarea %d obtinuta din handlerul tabelei"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d ÏÔ ÏÂÒÁÂÏÔÞÉËÁ ÔÁÂÌÉÃ"
+ serbian "Handler tabela je vratio grešku %d"
+ slo "Obsluha tabuµky vrátila chybu %d"
+ spa "Error %d desde el manejador de la tabla"
+ swe "Fick felkod %d från databashanteraren"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d ×¦Ä ÄÅÓËÒÉÐÔÏÒÁ ÔÁÂÌÉæ"
+ER_ILLEGAL_HA
+ cze "Obsluha tabulky '%-.64s' nem-Bá tento parametr"
+ dan "Denne mulighed eksisterer ikke for tabeltypen '%-.64s'"
+ nla "Tabel handler voor '%-.64s' heeft deze optie niet"
+ eng "Table storage engine for '%-.64s' doesn't have this option"
+ est "Tabeli '%-.64s' handler ei toeta antud operatsiooni"
+ fre "Le handler de la table '%-.64s' n'a pas cette option"
+ ger "Diese Option gibt es nicht (Tabellenhandler)"
+ greek "Ï ÷åéñéóôÞò ðßíáêá (table handler) ãéá '%-.64s' äåí äéáèÝôåé áõôÞ ôçí åðéëïãÞ"
+ hun "A(z) '%-.64s' tablakezelonek nincs ilyen opcioja"
+ ita "Il gestore delle tabelle per '%-.64s' non ha questa opzione"
+ jpn "Table handler for '%-.64s' doesn't have this option"
+ kor "'%-.64s'ÀÇ Å×À̺í handler´Â ÀÌ·¯ÇÑ ¿É¼ÇÀ» Á¦°øÇÏÁö ¾ÊÀ¾´Ï´Ù."
+ nor "Tabell håndtereren for '%-.64s' har ikke denne muligheten"
+ norwegian-ny "Tabell håndteraren for '%-.64s' har ikkje denne moglegheita"
+ pol "Obs³uga tabeli '%-.64s' nie posiada tej opcji"
+ por "Manipulador de tabela para '%-.64s' não tem esta opção"
+ rum "Handlerul tabelei pentru '%-.64s' nu are aceasta optiune"
+ rus "ïÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ '%-.64s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÜÔÕ ×ÏÚÍÏÖÎÏÓÔØ"
+ serbian "Handler tabela za '%-.64s' nema ovu opciju"
+ slo "Obsluha tabuµky '%-.64s' nemá tento parameter"
+ spa "El manejador de la tabla de '%-.64s' no tiene esta opcion"
+ swe "Registrets databas har inte denna facilitet"
+ ukr "äÅÓËÒÉÐÔÏÒ ÔÁÂÌÉæ '%-.64s' ÎÅ ÍÁ¤ 椧 ×ÌÁÓÔÉ×ÏÓÔ¦"
+ER_KEY_NOT_FOUND
+ cze "Nemohu naj-Bít záznam v '%-.64s'"
+ dan "Kan ikke finde posten i '%-.64s'"
+ nla "Kan record niet vinden in '%-.64s'"
+ eng "Can't find record in '%-.64s'"
+ jps "'%-.64s'‚Ì‚È‚©‚ɃŒƒR[ƒh‚ªŒ©•t‚©‚è‚Ü‚¹‚ñ",
+ est "Ei suuda leida kirjet '%-.64s'-s"
+ fre "Ne peut trouver l'enregistrement dans '%-.64s'"
+ ger "Kann Datensatz nicht finden"
+ greek "Áäýíáôç ç áíåýñåóç åããñáöÞò óôï '%-.64s'"
+ hun "Nem talalhato a rekord '%-.64s'-ben"
+ ita "Impossibile trovare il record in '%-.64s'"
+ jpn "'%-.64s'¤Î¤Ê¤«¤Ë¥ì¥³¡¼¥É¤¬¸«ÉÕ¤«¤ê¤Þ¤»¤ó"
+ kor "'%-.64s'¿¡¼­ ·¹Äڵ带 ãÀ» ¼ö ¾øÀ¾´Ï´Ù."
+ nor "Kan ikke finne posten i '%-.64s'"
+ norwegian-ny "Kan ikkje finne posten i '%-.64s'"
+ pol "Nie mo¿na znale¥æ rekordu w '%-.64s'"
+ por "Não pode encontrar registro em '%-.64s'"
+ rum "Nu pot sa gasesc recordul in '%-.64s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÚÁÐÉÓØ × '%-.64s'"
+ serbian "Ne mogu da pronaðem slog u '%-.64s'"
+ slo "Nemô¾em nájs» záznam v '%-.64s'"
+ spa "No puedo encontrar el registro en '%-.64s'"
+ swe "Hittar inte posten"
+ ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ Õ '%-.64s'"
+ER_NOT_FORM_FILE
+ cze "Nespr-Bávná informace v souboru '%-.64s'"
+ dan "Forkert indhold i: '%-.64s'"
+ nla "Verkeerde info in file: '%-.64s'"
+ eng "Incorrect information in file: '%-.64s'"
+ jps "ƒtƒ@ƒCƒ‹ '%-.64s' ‚Ì info ‚ªŠÔˆá‚Á‚Ä‚¢‚é‚悤‚Å‚·",
+ est "Vigane informatsioon failis '%-.64s'"
+ fre "Information erronnée dans le fichier: '%-.64s'"
+ ger "Falsche Information in Datei '%-.64s'"
+ greek "ËÜèïò ðëçñïöïñßåò óôï áñ÷åßï: '%-.64s'"
+ hun "Ervenytelen info a file-ban: '%-.64s'"
+ ita "Informazione errata nel file: '%-.64s'"
+ jpn "¥Õ¥¡¥¤¥ë '%-.64s' ¤Î info ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹"
+ kor "È­ÀÏÀÇ ºÎÁ¤È®ÇÑ Á¤º¸: '%-.64s'"
+ nor "Feil informasjon i filen: '%-.64s'"
+ norwegian-ny "Feil informasjon i fila: '%-.64s'"
+ pol "Niew³a?ciwa informacja w pliku: '%-.64s'"
+ por "Informação incorreta no arquivo '%-.64s'"
+ rum "Informatie incorecta in fisierul: '%-.64s'"
+ rus "îÅËÏÒÒÅËÔÎÁÑ ÉÎÆÏÒÍÁÃÉÑ × ÆÁÊÌÅ '%-.64s'"
+ serbian "Pogrešna informacija u file-u: '%-.64s'"
+ slo "Nesprávna informácia v súbore: '%-.64s'"
+ spa "Informacion erronea en el archivo: '%-.64s'"
+ swe "Felaktig fil: '%-.64s'"
+ ukr "èÉÂÎÁ ¦ÎÆÏÒÍÁÃ¦Ñ Õ ÆÁÊ̦: '%-.64s'"
+ER_NOT_KEYFILE
+ cze "Nespr-Bávný klíè pro tabulku '%-.64s'; pokuste se ho opravit"
+ dan "Fejl i indeksfilen til tabellen '%-.64s'; prøv at reparere den"
+ nla "Verkeerde zoeksleutel file voor tabel: '%-.64s'; probeer het te repareren"
+ eng "Incorrect key file for table '%-.64s'; try to repair it"
+ jps "'%-.64s' ƒe[ƒuƒ‹‚Ì key file ‚ªŠÔˆá‚Á‚Ä‚¢‚é‚悤‚Å‚·. C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
+ est "Tabeli '%-.64s' võtmefail on vigane; proovi seda parandada"
+ fre "Index corrompu dans la table: '%-.64s'; essayez de le réparer"
+ ger "Falsche Schlüssel-Datei für Tabelle '%-.64s'. versuche zu reparieren"
+ greek "ËÜèïò áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá: '%-.64s'; Ðáñáêáëþ, äéïñèþóôå ôï!"
+ hun "Ervenytelen kulcsfile a tablahoz: '%-.64s'; probalja kijavitani!"
+ ita "File chiave errato per la tabella : '%-.64s'; prova a riparalo"
+ jpn "'%-.64s' ¥Æ¡¼¥Ö¥ë¤Î key file ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹. ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤"
+ kor "'%-.64s' Å×À̺íÀÇ ºÎÁ¤È®ÇÑ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!"
+ nor "Tabellen '%-.64s' har feil i nøkkelfilen; forsøk å reparer den"
+ norwegian-ny "Tabellen '%-.64s' har feil i nykkelfila; prøv å reparere den"
+ pol "Niew³a?ciwy plik kluczy dla tabeli: '%-.64s'; spróbuj go naprawiæ"
+ por "Arquivo de índice incorreto para tabela '%-.64s'; tente repará-lo"
+ rum "Cheia fisierului incorecta pentru tabela: '%-.64s'; incearca s-o repari"
+ rus "îÅËÏÒÒÅËÔÎÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ: '%-.64s'. ðÏÐÒÏÂÕÊÔÅ ×ÏÓÓÔÁÎÏ×ÉÔØ ÅÇÏ"
+ serbian "Pogrešan key file za tabelu: '%-.64s'; probajte da ga ispravite"
+ slo "Nesprávny kµúè pre tabuµku '%-.64s'; pokúste sa ho opravi»"
+ spa "Clave de archivo erronea para la tabla: '%-.64s'; intente repararlo"
+ swe "Fatalt fel vid hantering av register '%-.64s'; kör en reparation"
+ ukr "èÉÂÎÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ: '%-.64s'; óÐÒÏÂÕÊÔÅ ÊÏÇÏ ×¦ÄÎÏ×ÉÔÉ"
+ER_OLD_KEYFILE
+ cze "Star-Bý klíèový soubor pro '%-.64s'; opravte ho."
+ dan "Gammel indeksfil for tabellen '%-.64s'; reparer den"
+ nla "Oude zoeksleutel file voor tabel '%-.64s'; repareer het!"
+ eng "Old key file for table '%-.64s'; repair it!"
+ jps "'%-.64s' ƒe[ƒuƒ‹‚͌¢Œ`Ž®‚Ì key file ‚̂悤‚Å‚·; C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
+ est "Tabeli '%-.64s' võtmefail on aegunud; paranda see!"
+ fre "Vieux fichier d'index pour la table '%-.64s'; réparez le!"
+ ger "Alte Schlüssel-Datei für Tabelle '%-.64s'. Bitte reparieren"
+ greek "Ðáëáéü áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá '%-.64s'; Ðáñáêáëþ, äéïñèþóôå ôï!"
+ hun "Regi kulcsfile a '%-.64s'tablahoz; probalja kijavitani!"
+ ita "File chiave vecchio per la tabella '%-.64s'; riparalo!"
+ jpn "'%-.64s' ¥Æ¡¼¥Ö¥ë¤Ï¸Å¤¤·Á¼°¤Î key file ¤Î¤è¤¦¤Ç¤¹; ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤"
+ kor "'%-.64s' Å×À̺íÀÇ ÀÌÀü¹öÁ¯ÀÇ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!"
+ nor "Gammel nøkkelfil for tabellen '%-.64s'; reparer den!"
+ norwegian-ny "Gammel nykkelfil for tabellen '%-.64s'; reparer den!"
+ pol "Plik kluczy dla tabeli '%-.64s' jest starego typu; napraw go!"
+ por "Arquivo de índice desatualizado para tabela '%-.64s'; repare-o!"
+ rum "Cheia fisierului e veche pentru tabela '%-.64s'; repar-o!"
+ rus "óÔÁÒÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'; ÏÔÒÅÍÏÎÔÉÒÕÊÔÅ ÅÇÏ!"
+ serbian "Zastareo key file za tabelu '%-.64s'; ispravite ga"
+ slo "Starý kµúèový súbor pre '%-.64s'; opravte ho!"
+ spa "Clave de archivo antigua para la tabla '%-.64s'; reparelo!"
+ swe "Gammal nyckelfil '%-.64s'; reparera registret"
+ ukr "óÔÁÒÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ '%-.64s'; ÷¦ÄÎÏצÔØ ÊÏÇÏ!"
+ER_OPEN_AS_READONLY
+ cze "'%-.64s' je jen pro -Bètení"
+ dan "'%-.64s' er skrivebeskyttet"
+ nla "'%-.64s' is alleen leesbaar"
+ eng "Table '%-.64s' is read only"
+ jps "'%-.64s' ‚Í“Ç‚Ýž‚Ýê—p‚Å‚·",
+ est "Tabel '%-.64s' on ainult lugemiseks"
+ fre "'%-.64s' est en lecture seulement"
+ ger "'%-.64s' ist nur lesbar"
+ greek "'%-.64s' åðéôñÝðåôáé ìüíï ç áíÜãíùóç"
+ hun "'%-.64s' irasvedett"
+ ita "'%-.64s' e` di sola lettura"
+ jpn "'%-.64s' ¤ÏÆɤ߹þ¤ßÀìÍѤǤ¹"
+ kor "Å×À̺í '%-.64s'´Â ÀбâÀü¿ë ÀÔ´Ï´Ù."
+ nor "'%-.64s' er skrivebeskyttet"
+ norwegian-ny "'%-.64s' er skrivetryggja"
+ pol "'%-.64s' jest tylko do odczytu"
+ por "Tabela '%-.64s' é somente para leitura"
+ rum "Tabela '%-.64s' e read-only"
+ rus "ôÁÂÌÉÃÁ '%-.64s' ÐÒÅÄÎÁÚÎÁÞÅÎÁ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ"
+ serbian "Tabelu '%-.64s' je dozvoljeno samo èitati"
+ slo "'%-.64s' is èíta» only"
+ spa "'%-.64s' es de solo lectura"
+ swe "'%-.64s' är skyddad mot förändring"
+ ukr "ôÁÂÌÉÃÑ '%-.64s' Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ"
+ER_OUTOFMEMORY HY001 S1001
+ cze "M-Bálo pamìti. Pøestartujte daemona a zkuste znovu (je potøeba %d bytù)"
+ dan "Ikke mere hukommelse. Genstart serveren og prøv igen (mangler %d bytes)"
+ nla "Geen geheugen meer. Herstart server en probeer opnieuw (%d bytes nodig)"
+ eng "Out of memory; restart server and try again (needed %d bytes)"
+ jps "Out of memory. ƒf[ƒ‚ƒ“‚ðƒŠƒXƒ^[ƒg‚µ‚Ä‚Ý‚Ä‚­‚¾‚³‚¢ (%d bytes •K—v)",
+ est "Mälu sai otsa. Proovi MySQL uuesti käivitada (puudu jäi %d baiti)"
+ fre "Manque de mémoire. Redémarrez le démon et ré-essayez (%d octets nécessaires)"
+ ger "Kein Speicher vorhanden (%d Bytes benötigt). Bitte Server neu starten"
+ greek "Äåí õðÜñ÷åé äéáèÝóéìç ìíÞìç. ÐñïóðáèÞóôå ðÜëé, åðáíåêéíþíôáò ôç äéáäéêáóßá (demon) (÷ñåéÜæïíôáé %d bytes)"
+ hun "Nincs eleg memoria. Inditsa ujra a demont, es probalja ismet. (%d byte szukseges.)"
+ ita "Memoria esaurita. Fai ripartire il demone e riprova (richiesti %d bytes)"
+ jpn "Out of memory. ¥Ç¡¼¥â¥ó¤ò¥ê¥¹¥¿¡¼¥È¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤ (%d bytes ɬÍ×)"
+ kor "Out of memory. µ¥¸óÀ» Àç ½ÇÇà ÈÄ ´Ù½Ã ½ÃÀÛÇϽÿÀ (needed %d bytes)"
+ nor "Ikke mer minne. Star på nytt tjenesten og prøv igjen (trengte %d byter)"
+ norwegian-ny "Ikkje meir minne. Start på nytt tenesten og prøv igjen (trengte %d bytar)"
+ pol "Zbyt ma³o pamiêci. Uruchom ponownie demona i spróbuj ponownie (potrzeba %d bajtów)"
+ por "Sem memória. Reinicie o programa e tente novamente (necessita de %d bytes)"
+ rum "Out of memory. Porneste daemon-ul din nou si incearca inca o data (e nevoie de %d bytes)"
+ rus "îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ. ðÅÒÅÚÁÐÕÓÔÉÔÅ ÓÅÒ×ÅÒ É ÐÏÐÒÏÂÕÊÔÅ ÅÝÅ ÒÁÚ (ÎÕÖÎÏ %d ÂÁÊÔ)"
+ serbian "Nema memorije. Restartujte MySQL server i probajte ponovo (potrebno je %d byte-ova)"
+ slo "Málo pamäti. Re¹tartujte daemona a skúste znova (je potrebných %d bytov)"
+ spa "Memoria insuficiente. Reinicie el demonio e intentelo otra vez (necesita %d bytes)"
+ swe "Oväntat slut på minnet, starta om programmet och försök på nytt (Behövde %d bytes)"
+ ukr "âÒÁË ÐÁÍ'ÑÔ¦. òÅÓÔÁÒÔÕÊÔÅ ÓÅÒ×ÅÒ ÔÁ ÓÐÒÏÂÕÊÔÅ ÚÎÏ×Õ (ÐÏÔÒ¦ÂÎÏ %d ÂÁÊÔ¦×)"
+ER_OUT_OF_SORTMEMORY HY001 S1001
+ cze "M-Bálo pamìti pro tøídìní. Zvy¹te velikost tøídícího bufferu"
+ dan "Ikke mere sorteringshukommelse. Øg sorteringshukommelse (sort buffer size) for serveren"
+ nla "Geen geheugen om te sorteren. Verhoog de server sort buffer size"
+ eng "Out of sort memory; increase server sort buffer size"
+ jps "Out of sort memory. sort buffer size ‚ª‘«‚è‚È‚¢‚悤‚Å‚·.",
+ est "Mälu sai sorteerimisel otsa. Suurenda MySQL-i sorteerimispuhvrit"
+ fre "Manque de mémoire pour le tri. Augmentez-la."
+ ger "Kein Speicher zum Sortieren vorhanden. sort_buffer_size sollte erhöht werden"
+ greek "Äåí õðÜñ÷åé äéáèÝóéìç ìíÞìç ãéá ôáîéíüìéóç. ÁõîÞóôå ôï sort buffer size ãéá ôç äéáäéêáóßá (demon)"
+ hun "Nincs eleg memoria a rendezeshez. Novelje a rendezo demon puffermeretet"
+ ita "Memoria per gli ordinamenti esaurita. Incrementare il 'sort_buffer' al demone"
+ jpn "Out of sort memory. sort buffer size ¤¬Â­¤ê¤Ê¤¤¤è¤¦¤Ç¤¹."
+ kor "Out of sort memory. daemon sort bufferÀÇ Å©±â¸¦ Áõ°¡½ÃÅ°¼¼¿ä"
+ nor "Ikke mer sorteringsminne. Øk sorteringsminnet (sort buffer size) for tjenesten"
+ norwegian-ny "Ikkje meir sorteringsminne. Auk sorteringsminnet (sorteringsbffer storleik) for tenesten"
+ pol "Zbyt ma³o pamiêci dla sortowania. Zwiêksz wielko?æ bufora demona dla sortowania"
+ por "Sem memória para ordenação. Aumente tamanho do 'buffer' de ordenação"
+ rum "Out of memory pentru sortare. Largeste marimea buffer-ului pentru sortare in daemon (sort buffer size)"
+ rus "îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ ÄÌÑ ÓÏÒÔÉÒÏ×ËÉ. õ×ÅÌÉÞØÔÅ ÒÁÚÍÅÒ ÂÕÆÅÒÁ ÓÏÒÔÉÒÏ×ËÉ ÎÁ ÓÅÒ×ÅÒÅ"
+ serbian "Nema memorije za sortiranje. Poveæajte velièinu sort buffer-a MySQL server-u"
+ slo "Málo pamäti pre triedenie, zvý¹te veµkos» triediaceho bufferu"
+ spa "Memoria de ordenacion insuficiente. Incremente el tamano del buffer de ordenacion"
+ swe "Sorteringsbufferten räcker inte till. Kontrollera startparametrarna"
+ ukr "âÒÁË ÐÁÍ'ÑÔ¦ ÄÌÑ ÓÏÒÔÕ×ÁÎÎÑ. ôÒÅÂÁ Ú¦ÌØÛÉÔÉ ÒÏÚÍ¦Ò ÂÕÆÅÒÁ ÓÏÒÔÕ×ÁÎÎÑ Õ ÓÅÒ×ÅÒÁ"
+ER_UNEXPECTED_EOF
+ cze "Neo-Bèekávaný konec souboru pøi ètení '%-.64s' (chybový kód: %d)"
+ dan "Uventet afslutning på fil (eof) ved læsning af filen '%-.64s' (Fejlkode: %d)"
+ nla "Onverwachte eof gevonden tijdens het lezen van file '%-.64s' (Errcode: %d)"
+ eng "Unexpected EOF found when reading file '%-.64s' (errno: %d)"
+ jps "'%-.64s' ƒtƒ@ƒCƒ‹‚ð“Ç‚Ýž‚Ý’†‚É EOF ‚ª—\Šú‚¹‚ÊŠ‚ÅŒ»‚ê‚Ü‚µ‚½. (errno: %d)",
+ est "Ootamatu faililõpumärgend faili '%-.64s' lugemisel (veakood: %d)"
+ fre "Fin de fichier inattendue en lisant '%-.64s' (Errcode: %d)"
+ ger "Unerwartetes Ende beim Lesen der Datei '%-.64s' (Fehler: %d)"
+ greek "ÊáôÜ ôç äéÜñêåéá ôçò áíÜãíùóçò, âñÝèçêå áðñïóäüêçôá ôï ôÝëïò ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Varatlan filevege-jel a '%-.64s'olvasasakor. (hibakod: %d)"
+ ita "Fine del file inaspettata durante la lettura del file '%-.64s' (errno: %d)"
+ jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤òÆɤ߹þ¤ßÃæ¤Ë EOF ¤¬Í½´ü¤»¤Ì½ê¤Ç¸½¤ì¤Þ¤·¤¿. (errno: %d)"
+ kor "'%-.64s' È­ÀÏÀ» Àд µµÁß À߸øµÈ eofÀ» ¹ß°ß (¿¡·¯¹øÈ£: %d)"
+ nor "Uventet slutt på fil (eof) ved lesing av filen '%-.64s' (Feilkode: %d)"
+ norwegian-ny "Uventa slutt på fil (eof) ved lesing av fila '%-.64s' (Feilkode: %d)"
+ pol "Nieoczekiwany 'eof' napotkany podczas czytania z pliku '%-.64s' (Kod b³êdu: %d)"
+ por "Encontrado fim de arquivo inesperado ao ler arquivo '%-.64s' (erro no. %d)"
+ rum "Sfirsit de fisier neasteptat in citirea fisierului '%-.64s' (errno: %d)"
+ rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ '%-.64s' (ÏÛÉÂËÁ: %d)"
+ serbian "Neoèekivani kraj pri èitanju file-a '%-.64s' (errno: %d)"
+ slo "Neoèakávaný koniec súboru pri èítaní '%-.64s' (chybový kód: %d)"
+ spa "Inesperado fin de ficheroU mientras leiamos el archivo '%-.64s' (Error: %d)"
+ swe "Oväntat filslut vid läsning från '%-.64s' (Felkod: %d)"
+ ukr "èÉÂÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ER_CON_COUNT_ERROR 08004
+ cze "P-Bøíli¹ mnoho spojení"
+ dan "For mange forbindelser (connections)"
+ nla "Te veel verbindingen"
+ eng "Too many connections"
+ jps "Ú‘±‚ª‘½‚·‚¬‚Ü‚·",
+ est "Liiga palju samaaegseid ühendusi"
+ fre "Trop de connections"
+ ger "Zu viele Verbindungen"
+ greek "ÕðÜñ÷ïõí ðïëëÝò óõíäÝóåéò..."
+ hun "Tul sok kapcsolat"
+ ita "Troppe connessioni"
+ jpn "Àܳ¤¬Â¿¤¹¤®¤Þ¤¹"
+ kor "³Ê¹« ¸¹Àº ¿¬°á... max_connectionÀ» Áõ°¡ ½ÃÅ°½Ã¿À..."
+ nor "For mange tilkoblinger (connections)"
+ norwegian-ny "For mange tilkoplingar (connections)"
+ pol "Zbyt wiele po³?czeñ"
+ por "Excesso de conexões"
+ rum "Prea multe conectiuni"
+ rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÓÏÅÄÉÎÅÎÉÊ"
+ serbian "Previše konekcija"
+ slo "Príli¹ mnoho spojení"
+ spa "Demasiadas conexiones"
+ swe "För många anslutningar"
+ ukr "úÁÂÁÇÁÔÏ Ú'¤ÄÎÁÎØ"
+ER_OUT_OF_RESOURCES
+ cze "M-Bálo prostoru/pamìti pro thread"
+ dan "Udgået for tråde/hukommelse"
+ nla "Geen thread geheugen meer; controleer of mysqld of andere processen al het beschikbare geheugen gebruikt. Zo niet, dan moet u wellicht 'ulimit' gebruiken om mysqld toe te laten meer geheugen te benutten, of u kunt extra swap ruimte toevoegen"
+ eng "Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to use 'ulimit' to allow mysqld to use more memory or you can add more swap space"
+ jps "Out of memory; mysqld ‚©‚»‚Ì‘¼‚̃vƒƒZƒX‚ªƒƒ‚ƒŠ[‚ð‘S‚ÄŽg‚Á‚Ä‚¢‚é‚©Šm”F‚µ‚Ä‚­‚¾‚³‚¢. ƒƒ‚ƒŠ[‚ðŽg‚¢Ø‚Á‚Ä‚¢‚È‚¢ê‡A'ulimit' ‚ðݒ肵‚Ä mysqld ‚̃ƒ‚ƒŠ[Žg—pŒÀŠE—ʂ𑽂­‚·‚é‚©Aswap space ‚ð‘‚₵‚Ä‚Ý‚Ä‚­‚¾‚³‚¢",
+ est "Mälu sai otsa. Võimalik, et aitab swap-i lisamine või käsu 'ulimit' abil MySQL-le rohkema mälu kasutamise lubamine"
+ fre "Manque de 'threads'/mémoire"
+ ger "Kein Speicher mehr vorhanden. Prüfen Sie, ob mysqld oder ein anderer Prozess allen Speicher verbraucht. Wenn nicht, sollten Sie mit 'ulimit' dafür sorgen, dass mysqld mehr Speicher benutzen darf, oder mehr Swap-Speicher einrichten"
+ greek "Ðñüâëçìá ìå ôç äéáèÝóéìç ìíÞìç (Out of thread space/memory)"
+ hun "Elfogyott a thread-memoria"
+ ita "Fine dello spazio/memoria per i thread"
+ jpn "Out of memory; mysqld ¤«¤½¤Î¾¤Î¥×¥í¥»¥¹¤¬¥á¥â¥ê¡¼¤òÁ´¤Æ»È¤Ã¤Æ¤¤¤ë¤«³Îǧ¤·¤Æ¤¯¤À¤µ¤¤. ¥á¥â¥ê¡¼¤ò»È¤¤ÀڤäƤ¤¤Ê¤¤¾ì¹ç¡¢'ulimit' ¤òÀßÄꤷ¤Æ mysqld ¤Î¥á¥â¥ê¡¼»ÈÍѸ³¦Î̤ò¿¤¯¤¹¤ë¤«¡¢swap space ¤òÁý¤ä¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤"
+ kor "Out of memory; mysqld³ª ¶Ç´Ù¸¥ ÇÁ·Î¼¼¼­¿¡¼­ »ç¿ë°¡´ÉÇÑ ¸Þ¸ð¸®¸¦ »ç¿ëÇÑÁö äũÇϽÿÀ. ¸¸¾à ±×·¸Áö ¾Ê´Ù¸é ulimit ¸í·ÉÀ» ÀÌ¿¿ëÇÏ¿© ´õ¸¹Àº ¸Þ¸ð¸®¸¦ »ç¿ëÇÒ ¼ö ÀÖµµ·Ï Çϰųª ½º¿Ò ½ºÆÐÀ̽º¸¦ Áõ°¡½ÃÅ°½Ã¿À"
+ nor "Tomt for tråd plass/minne"
+ norwegian-ny "Tomt for tråd plass/minne"
+ pol "Zbyt ma³o miejsca/pamiêci dla w?tku"
+ por "Sem memória. Verifique se o mysqld ou algum outro processo está usando toda memória disponível. Se não, você pode ter que usar 'ulimit' para permitir ao mysqld usar mais memória ou você pode adicionar mais área de 'swap'"
+ rum "Out of memory; Verifica daca mysqld sau vreun alt proces foloseste toate memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui mysqld sa foloseasca mai multa memorie ori adauga mai mult spatiu pentru swap (swap space)"
+ rus "îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ; ÕÄÏÓÔÏ×ÅÒØÔÅÓØ, ÞÔÏ mysqld ÉÌÉ ËÁËÏÊ-ÌÉÂÏ ÄÒÕÇÏÊ ÐÒÏÃÅÓÓ ÎÅ ÚÁÎÉÍÁÅÔ ×ÓÀ ÄÏÓÔÕÐÎÕÀ ÐÁÍÑÔØ. åÓÌÉ ÎÅÔ, ÔÏ ×Ù ÍÏÖÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ulimit, ÞÔÏÂÙ ×ÙÄÅÌÉÔØ ÄÌÑ mysqld ÂÏÌØÛÅ ÐÁÍÑÔÉ, ÉÌÉ Õ×ÅÌÉÞÉÔØ ÏÂßÅÍ ÆÁÊÌÁ ÐÏÄËÁÞËÉ"
+ serbian "Nema memorije; Proverite da li MySQL server ili neki drugi proces koristi svu slobodnu memoriju. (UNIX: Ako ne, probajte da upotrebite 'ulimit' komandu da biste dozvolili daemon-u da koristi više memorije ili probajte da dodate više swap memorije)"
+ slo "Málo miesta-pamäti pre vlákno"
+ spa "Memoria/espacio de tranpaso insuficiente"
+ swe "Fick slut på minnet. Kontrollera om mysqld eller någon annan process använder allt tillgängligt minne. Om inte, försök använda 'ulimit' eller allokera mera swap"
+ ukr "âÒÁË ÐÁÍ'ÑÔ¦; ðÅÒÅצÒÔÅ ÞÉ mysqld ÁÂÏ Ñ˦ÓØ ¦ÎÛ¦ ÐÒÏÃÅÓÉ ×ÉËÏÒÉÓÔÏ×ÕÀÔØ ÕÓÀ ÄÏÓÔÕÐÎÕ ÐÁÍ'ÑÔØ. ñË Î¦, ÔÏ ×É ÍÏÖÅÔÅ ÓËÏÒÉÓÔÁÔÉÓÑ 'ulimit', ÁÂÉ ÄÏÚ×ÏÌÉÔÉ mysqld ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ Â¦ÌØÛÅ ÐÁÍ'ÑÔ¦ ÁÂÏ ×É ÍÏÖÅÔÅ ÄÏÄÁÔÉ Â¦ÌØÛŠͦÓÃÑ Ð¦Ä Ó×ÁÐ"
+ER_BAD_HOST_ERROR 08S01
+ cze "Nemohu zjistit jm-Béno stroje pro Va¹i adresu"
+ dan "Kan ikke få værtsnavn for din adresse"
+ nla "Kan de hostname niet krijgen van uw adres"
+ eng "Can't get hostname for your address"
+ jps "‚»‚Ì address ‚Ì hostname ‚ªˆø‚¯‚Ü‚¹‚ñ.",
+ est "Ei suuda lahendada IP aadressi masina nimeks"
+ fre "Ne peut obtenir de hostname pour votre adresse"
+ ger "Kann Hostnamen für diese Adresse nicht erhalten"
+ greek "Äåí Ýãéíå ãíùóôü ôï hostname ãéá ôçí address óáò"
+ hun "A gepnev nem allapithato meg a cimbol"
+ ita "Impossibile risalire al nome dell'host dall'indirizzo (risoluzione inversa)"
+ jpn "¤½¤Î address ¤Î hostname ¤¬°ú¤±¤Þ¤»¤ó."
+ kor "´ç½ÅÀÇ ÄÄÇ»ÅÍÀÇ È£½ºÆ®À̸§À» ¾òÀ» ¼ö ¾øÀ¾´Ï´Ù."
+ nor "Kan ikke få tak i vertsnavn for din adresse"
+ norwegian-ny "Kan ikkje få tak i vertsnavn for di adresse"
+ pol "Nie mo¿na otrzymaæ nazwy hosta dla twojego adresu"
+ por "Não pode obter nome do 'host' para seu endereço"
+ rum "Nu pot sa obtin hostname-ul adresei tale"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÏÌÕÞÉÔØ ÉÍÑ ÈÏÓÔÁ ÄÌÑ ×ÁÛÅÇÏ ÁÄÒÅÓÁ"
+ serbian "Ne mogu da dobijem ime host-a za vašu IP adresu"
+ slo "Nemô¾em zisti» meno hostiteµa pre va¹u adresu"
+ spa "No puedo obtener el nombre de maquina de tu direccion"
+ swe "Kan inte hitta 'hostname' för din adress"
+ ukr "îÅ ÍÏÖÕ ×ÉÚÎÁÞÉÔÉ ¦Í'Ñ ÈÏÓÔÕ ÄÌÑ ×ÁÛϧ ÁÄÒÅÓÉ"
+ER_HANDSHAKE_ERROR 08S01
+ cze "Chyba p-Bøi ustavování spojení"
+ dan "Forkert håndtryk (handshake)"
+ nla "Verkeerde handshake"
+ eng "Bad handshake"
+ est "Väär handshake"
+ fre "Mauvais 'handshake'"
+ ger "Schlechter Handshake"
+ greek "Ç áíáãíþñéóç (handshake) äåí Ýãéíå óùóôÜ"
+ hun "A kapcsolatfelvetel nem sikerult (Bad handshake)"
+ ita "Negoziazione impossibile"
+ nor "Feil håndtrykk (handshake)"
+ norwegian-ny "Feil handtrykk (handshake)"
+ pol "Z³y uchwyt(handshake)"
+ por "Negociação de acesso falhou"
+ rum "Prost inceput de conectie (bad handshake)"
+ rus "îÅËÏÒÒÅËÔÎÏÅ ÐÒÉ×ÅÔÓÔ×ÉÅ"
+ serbian "Loš poèetak komunikacije (handshake)"
+ slo "Chyba pri nadväzovaní spojenia"
+ spa "Protocolo erroneo"
+ swe "Fel vid initiering av kommunikationen med klienten"
+ ukr "îÅצÒÎÁ ÕÓÔÁÎÏ×ËÁ Ú×'ÑÚËÕ"
+ER_DBACCESS_DENIED_ERROR 42000
+ cze "P-Bøístup pro u¾ivatele '%-.32s'@'%-.64s' k databázi '%-.64s' není povolen"
+ dan "Adgang nægtet bruger: '%-.32s'@'%-.64s' til databasen '%-.64s'"
+ nla "Toegang geweigerd voor gebruiker: '%-.32s'@'%-.64s' naar database '%-.64s'"
+ eng "Access denied for user '%-.32s'@'%-.64s' to database '%-.64s'"
+ jps "ƒ†[ƒU[ '%-.32s'@'%-.64s' ‚Ì '%-.64s' ƒf[ƒ^ƒx[ƒX‚ւ̃AƒNƒZƒX‚ð‹‘”Û‚µ‚Ü‚·",
+ est "Ligipääs keelatud kasutajale '%-.32s'@'%-.64s' andmebaasile '%-.64s'"
+ fre "Accès refusé pour l'utilisateur: '%-.32s'@'@%-.64s'. Base '%-.64s'"
+ ger "Benutzer '%-.32s'@'%-.64s' hat keine Zugriffsberechtigung für Datenbank '%-.64s'"
+ greek "Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s'@'%-.64s' óôç âÜóç äåäïìÝíùí '%-.64s'"
+ hun "A(z) '%-.32s'@'%-.64s' felhasznalo szamara tiltott eleres az '%-.64s' adabazishoz."
+ ita "Accesso non consentito per l'utente: '%-.32s'@'%-.64s' al database '%-.64s'"
+ jpn "¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ¤Î '%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥¢¥¯¥»¥¹¤òµñÈݤ·¤Þ¤¹"
+ kor "'%-.32s'@'%-.64s' »ç¿ëÀÚ´Â '%-.64s' µ¥ÀÌŸº£À̽º¿¡ Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù."
+ nor "Tilgang nektet for bruker: '%-.32s'@'%-.64s' til databasen '%-.64s' nektet"
+ norwegian-ny "Tilgang ikkje tillate for brukar: '%-.32s'@'%-.64s' til databasen '%-.64s' nekta"
+ por "Acesso negado para o usuário '%-.32s'@'%-.64s' ao banco de dados '%-.64s'"
+ rum "Acces interzis pentru utilizatorul: '%-.32s'@'%-.64s' la baza de date '%-.64s'"
+ rus "äÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s'@'%-.64s' ÄÏÓÔÕÐ Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÚÁËÒÙÔ"
+ serbian "Pristup je zabranjen korisniku '%-.32s'@'%-.64s' za bazu '%-.64s'"
+ slo "Zakázaný prístup pre u¾ívateµa: '%-.32s'@'%-.64s' k databázi '%-.64s'"
+ spa "Acceso negado para usuario: '%-.32s'@'%-.64s' para la base de datos '%-.64s'"
+ swe "Användare '%-.32s'@'%-.64s' är ej berättigad att använda databasen %-.64s"
+ ukr "äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'@'%-.64s' ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ '%-.64s'"
+ER_ACCESS_DENIED_ERROR 28000
+ cze "P-Bøístup pro u¾ivatele '%-.32s'@'%-.64s' (s heslem %s)"
+ dan "Adgang nægtet bruger: '%-.32s'@'%-.64s' (Bruger adgangskode: %s)"
+ nla "Toegang geweigerd voor gebruiker: '%-.32s'@'%-.64s' (Wachtwoord gebruikt: %s)"
+ eng "Access denied for user '%-.32s'@'%-.64s' (using password: %s)"
+ jps "ƒ†[ƒU[ '%-.32s'@'%-.64s' ‚ð‹‘”Û‚µ‚Ü‚·.uUsing password: %s)",
+ est "Ligipääs keelatud kasutajale '%-.32s'@'%-.64s' (kasutab parooli: %s)"
+ fre "Accès refusé pour l'utilisateur: '%-.32s'@'@%-.64s' (mot de passe: %s)"
+ ger "Benutzer '%-.32s'@'%-.64s' hat keine Zugriffsberechtigung (verwendetes Passwort: %-.64s)"
+ greek "Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s'@'%-.64s' (÷ñÞóç password: %s)"
+ hun "A(z) '%-.32s'@'%-.64s' felhasznalo szamara tiltott eleres. (Hasznalja a jelszot: %s)"
+ ita "Accesso non consentito per l'utente: '%-.32s'@'%-.64s' (Password: %s)"
+ jpn "¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ¤òµñÈݤ·¤Þ¤¹.uUsing password: %s)"
+ kor "'%-.32s'@'%-.64s' »ç¿ëÀÚ´Â Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù. (using password: %s)"
+ nor "Tilgang nektet for bruker: '%-.32s'@'%-.64s' (Bruker passord: %s)"
+ norwegian-ny "Tilgang ikke tillate for brukar: '%-.32s'@'%-.64s' (Brukar passord: %s)"
+ por "Acesso negado para o usuário '%-.32s'@'%-.64s' (senha usada: %s)"
+ rum "Acces interzis pentru utilizatorul: '%-.32s'@'%-.64s' (Folosind parola: %s)"
+ rus "äÏÓÔÕÐ ÚÁËÒÙÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s'@'%-.64s' (ÂÙÌ ÉÓÐÏÌØÚÏ×ÁÎ ÐÁÒÏÌØ: %s)"
+ serbian "Pristup je zabranjen korisniku '%-.32s'@'%-.64s' (koristi lozinku: '%s')"
+ slo "Zakázaný prístup pre u¾ívateµa: '%-.32s'@'%-.64s' (pou¾itie hesla: %s)"
+ spa "Acceso negado para usuario: '%-.32s'@'%-.64s' (Usando clave: %s)"
+ swe "Användare '%-.32s'@'%-.64s' är ej berättigad att logga in (Använder lösen: %s)"
+ ukr "äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'@'%-.64s' (÷ÉËÏÒÉÓÔÁÎÏ ÐÁÒÏÌØ: %s)"
+ER_NO_DB_ERROR 3D000
+ cze "Nebyla vybr-Bána ¾ádná databáze"
+ dan "Ingen database valgt"
+ nla "Geen database geselecteerd"
+ eng "No database selected"
+ jps "ƒf[ƒ^ƒx[ƒX‚ª‘I‘ð‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ.",
+ est "Andmebaasi ei ole valitud"
+ fre "Aucune base n'a été sélectionnée"
+ ger "Keine Datenbank ausgewählt"
+ greek "Äåí åðéëÝ÷èçêå âÜóç äåäïìÝíùí"
+ hun "Nincs kivalasztott adatbazis"
+ ita "Nessun database selezionato"
+ jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ÁªÂò¤µ¤ì¤Æ¤¤¤Þ¤»¤ó."
+ kor "¼±ÅÃµÈ µ¥ÀÌŸº£À̽º°¡ ¾ø½À´Ï´Ù."
+ nor "Ingen database valgt"
+ norwegian-ny "Ingen database vald"
+ pol "Nie wybrano ¿adnej bazy danych"
+ por "Nenhum banco de dados foi selecionado"
+ rum "Nici o baza de data nu a fost selectata inca"
+ rus "âÁÚÁ ÄÁÎÎÙÈ ÎÅ ×ÙÂÒÁÎÁ"
+ serbian "Ni jedna baza nije selektovana"
+ slo "Nebola vybraná databáza"
+ spa "Base de datos no seleccionada"
+ swe "Ingen databas i användning"
+ ukr "âÁÚÕ ÄÁÎÎÉÈ ÎÅ ×ÉÂÒÁÎÏ"
+ER_UNKNOWN_COM_ERROR 08S01
+ cze "Nezn-Bámý pøíkaz"
+ dan "Ukendt kommando"
+ nla "Onbekend commando"
+ eng "Unknown command"
+ jps "‚»‚̃Rƒ}ƒ“ƒh‚͉½H",
+ est "Tundmatu käsk"
+ fre "Commande inconnue"
+ ger "Unbekannter Befehl"
+ greek "Áãíùóôç åíôïëÞ"
+ hun "Ervenytelen parancs"
+ ita "Comando sconosciuto"
+ jpn "¤½¤Î¥³¥Þ¥ó¥É¤Ï²¿¡©"
+ kor "¸í·É¾î°¡ ¹ºÁö ¸ð¸£°Ú¾î¿ä..."
+ nor "Ukjent kommando"
+ norwegian-ny "Ukjent kommando"
+ pol "Nieznana komenda"
+ por "Comando desconhecido"
+ rum "Comanda invalida"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ËÏÍÁÎÄÁ ËÏÍÍÕÎÉËÁÃÉÏÎÎÏÇÏ ÐÒÏÔÏËÏÌÁ"
+ serbian "Nepoznata komanda"
+ slo "Neznámy príkaz"
+ spa "Comando desconocido"
+ swe "Okänt commando"
+ ukr "îÅצÄÏÍÁ ËÏÍÁÎÄÁ"
+ER_BAD_NULL_ERROR 23000
+ cze "Sloupec '%-.64s' nem-Bù¾e být null"
+ dan "Kolonne '%-.64s' kan ikke være NULL"
+ nla "Kolom '%-.64s' kan niet null zijn"
+ eng "Column '%-.64s' cannot be null"
+ jps "Column '%-.64s' ‚Í null ‚É‚Í‚Å‚«‚È‚¢‚Ì‚Å‚·",
+ est "Tulp '%-.64s' ei saa omada nullväärtust"
+ fre "Le champ '%-.64s' ne peut être vide (null)"
+ ger "Feld '%-.64s' darf nicht NULL sein"
+ greek "Ôï ðåäßï '%-.64s' äåí ìðïñåß íá åßíáé êåíü (null)"
+ hun "A(z) '%-.64s' oszlop erteke nem lehet nulla"
+ ita "La colonna '%-.64s' non puo` essere nulla"
+ jpn "Column '%-.64s' ¤Ï null ¤Ë¤Ï¤Ç¤­¤Ê¤¤¤Î¤Ç¤¹"
+ kor "Ä®·³ '%-.64s'´Â ³Î(Null)ÀÌ µÇ¸é ¾ÈµË´Ï´Ù. "
+ nor "Kolonne '%-.64s' kan ikke vere null"
+ norwegian-ny "Kolonne '%-.64s' kan ikkje vere null"
+ pol "Kolumna '%-.64s' nie mo¿e byæ null"
+ por "Coluna '%-.64s' não pode ser vazia"
+ rum "Coloana '%-.64s' nu poate sa fie null"
+ rus "óÔÏÌÂÅà '%-.64s' ÎÅ ÍÏÖÅÔ ÐÒÉÎÉÍÁÔØ ×ÅÌÉÞÉÎÕ NULL"
+ serbian "Kolona '%-.64s' ne može biti NULL"
+ slo "Pole '%-.64s' nemô¾e by» null"
+ spa "La columna '%-.64s' no puede ser nula"
+ swe "Kolumn '%-.64s' får inte vara NULL"
+ ukr "óÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÎÕÌØÏ×ÉÍ"
+ER_BAD_DB_ERROR 42000
+ cze "Nezn-Bámá databáze '%-.64s'"
+ dan "Ukendt database '%-.64s'"
+ nla "Onbekende database '%-.64s'"
+ eng "Unknown database '%-.64s'"
+ jps "'%-.64s' ‚È‚ñ‚ăf[ƒ^ƒx[ƒX‚Í’m‚è‚Ü‚¹‚ñ.",
+ est "Tundmatu andmebaas '%-.64s'"
+ fre "Base '%-.64s' inconnue"
+ ger "Unbekannte Datenbank '%-.64s'"
+ greek "Áãíùóôç âÜóç äåäïìÝíùí '%-.64s'"
+ hun "Ervenytelen adatbazis: '%-.64s'"
+ ita "Database '%-.64s' sconosciuto"
+ jpn "'%-.64s' ¤Ê¤ó¤Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ÏÃΤê¤Þ¤»¤ó."
+ kor "µ¥ÀÌŸº£À̽º '%-.64s'´Â ¾Ë¼ö ¾øÀ½"
+ nor "Ukjent database '%-.64s'"
+ norwegian-ny "Ukjent database '%-.64s'"
+ pol "Nieznana baza danych '%-.64s'"
+ por "Banco de dados '%-.64s' desconhecido"
+ rum "Baza de data invalida '%-.64s'"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ÂÁÚÁ ÄÁÎÎÙÈ '%-.64s'"
+ serbian "Nepoznata baza '%-.64s'"
+ slo "Neznáma databáza '%-.64s'"
+ spa "Base de datos desconocida '%-.64s'"
+ swe "Okänd databas: '%-.64s'"
+ ukr "îÅצÄÏÍÁ ÂÁÚÁ ÄÁÎÎÉÈ '%-.64s'"
+ER_TABLE_EXISTS_ERROR 42S01
+ cze "Tabulka '%-.64s' ji-B¾ existuje"
+ dan "Tabellen '%-.64s' findes allerede"
+ nla "Tabel '%-.64s' bestaat al"
+ eng "Table '%-.64s' already exists"
+ jps "Table '%-.64s' ‚ÍŠù‚É‚ ‚è‚Ü‚·",
+ est "Tabel '%-.64s' juba eksisteerib"
+ fre "La table '%-.64s' existe déjà"
+ ger "Tabelle '%-.64s' bereits vorhanden"
+ greek "Ï ðßíáêáò '%-.64s' õðÜñ÷åé Þäç"
+ hun "A(z) '%-.64s' tabla mar letezik"
+ ita "La tabella '%-.64s' esiste gia`"
+ jpn "Table '%-.64s' ¤Ï´û¤Ë¤¢¤ê¤Þ¤¹"
+ kor "Å×À̺í '%-.64s'´Â ÀÌ¹Ì Á¸ÀçÇÔ"
+ nor "Tabellen '%-.64s' eksisterer allerede"
+ norwegian-ny "Tabellen '%-.64s' eksisterar allereide"
+ pol "Tabela '%-.64s' ju¿ istnieje"
+ por "Tabela '%-.64s' já existe"
+ rum "Tabela '%-.64s' exista deja"
+ rus "ôÁÂÌÉÃÁ '%-.64s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Tabela '%-.64s' veæ postoji"
+ slo "Tabuµka '%-.64s' u¾ existuje"
+ spa "La tabla '%-.64s' ya existe"
+ swe "Tabellen '%-.64s' finns redan"
+ ukr "ôÁÂÌÉÃÑ '%-.64s' ×ÖÅ ¦ÓÎÕ¤"
+ER_BAD_TABLE_ERROR 42S02
+ cze "Nezn-Bámá tabulka '%-.100s'"
+ dan "Ukendt tabel '%-.100s'"
+ nla "Onbekende tabel '%-.100s'"
+ eng "Unknown table '%-.100s'"
+ jps "table '%-.100s' ‚Í‚ ‚è‚Ü‚¹‚ñ.",
+ est "Tundmatu tabel '%-.100s'"
+ fre "Table '%-.100s' inconnue"
+ ger "Unbekannte Tabelle '%-.100s'"
+ greek "Áãíùóôïò ðßíáêáò '%-.100s'"
+ hun "Ervenytelen tabla: '%-.100s'"
+ ita "Tabella '%-.100s' sconosciuta"
+ jpn "table '%-.100s' ¤Ï¤¢¤ê¤Þ¤»¤ó."
+ kor "Å×À̺í '%-.100s'´Â ¾Ë¼ö ¾øÀ½"
+ nor "Ukjent tabell '%-.100s'"
+ norwegian-ny "Ukjent tabell '%-.100s'"
+ pol "Nieznana tabela '%-.100s'"
+ por "Tabela '%-.100s' desconhecida"
+ rum "Tabela '%-.100s' este invalida"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.100s'"
+ serbian "Nepoznata tabela '%-.100s'"
+ slo "Neznáma tabuµka '%-.100s'"
+ spa "Tabla '%-.100s' desconocida"
+ swe "Okänd tabell '%-.100s'"
+ ukr "îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.100s'"
+ER_NON_UNIQ_ERROR 23000
+ cze "Sloupec '%-.64s' v %s nen-Bí zcela jasný"
+ dan "Felt: '%-.64s' i tabel %s er ikke entydigt"
+ nla "Kolom: '%-.64s' in %s is niet eenduidig"
+ eng "Column '%-.64s' in %-.64s is ambiguous"
+ est "Väli '%-.64s' %-.64s-s ei ole ühene"
+ fre "Champ: '%-.64s' dans %s est ambigu"
+ ger "Spalte '%-.64s' in %-.64s ist nicht eindeutig"
+ greek "Ôï ðåäßï: '%-.64s' óå %-.64s äåí Ý÷åé êáèïñéóôåß"
+ hun "A(z) '%-.64s' oszlop %-.64s-ben ketertelmu"
+ ita "Colonna: '%-.64s' di %-.64s e` ambigua"
+ jpn "Column: '%-.64s' in %-.64s is ambiguous"
+ kor "Ä®·³: '%-.64s' in '%-.64s' ÀÌ ¸ðÈ£ÇÔ"
+ nor "Felt: '%-.64s' i tabell %s er ikke entydig"
+ norwegian-ny "Kolonne: '%-.64s' i tabell %s er ikkje eintydig"
+ pol "Kolumna: '%-.64s' w %s jest dwuznaczna"
+ por "Coluna '%-.64s' em '%-.64s' é ambígua"
+ rum "Coloana: '%-.64s' in %-.64s este ambigua"
+ rus "óÔÏÌÂÅÃ '%-.64s' × %-.64s ÚÁÄÁÎ ÎÅÏÄÎÏÚÎÁÞÎÏ"
+ serbian "Kolona '%-.64s' u %-.64s nije jedinstvena u kontekstu"
+ slo "Pole: '%-.64s' v %-.64s je nejasné"
+ spa "La columna: '%-.64s' en %s es ambigua"
+ swe "Kolumn '%-.64s' i %s är inte unik"
+ ukr "óÔÏ×ÂÅÃØ '%-.64s' Õ %-.64s ×ÉÚÎÁÞÅÎÉÊ ÎÅÏÄÎÏÚÎÁÞÎÏ"
+ER_SERVER_SHUTDOWN 08S01
+ cze "Prob-Bíhá ukonèování práce serveru"
+ dan "Database nedlukning er i gang"
+ nla "Bezig met het stoppen van de server"
+ eng "Server shutdown in progress"
+ jps "Server ‚ð shutdown ’†...",
+ est "Serveri seiskamine käib"
+ fre "Arrêt du serveur en cours"
+ ger "Der Server wird heruntergefahren"
+ greek "Åíáñîç äéáäéêáóßáò áðïóýíäåóçò ôïõ åîõðçñåôçôÞ (server shutdown)"
+ hun "A szerver leallitasa folyamatban"
+ ita "Shutdown del server in corso"
+ jpn "Server ¤ò shutdown Ãæ..."
+ kor "Server°¡ ¼Ë´Ù¿î ÁßÀÔ´Ï´Ù."
+ nor "Database nedkobling er i gang"
+ norwegian-ny "Tenar nedkopling er i gang"
+ pol "Trwa koñczenie dzia³ania serwera"
+ por "'Shutdown' do servidor em andamento"
+ rum "Terminarea serverului este in desfasurare"
+ rus "óÅÒ×ÅÒ ÎÁÈÏÄÉÔÓÑ × ÐÒÏÃÅÓÓÅ ÏÓÔÁÎÏ×ËÉ"
+ serbian "Gašenje servera je u toku"
+ slo "Prebieha ukonèovanie práce servera"
+ spa "Desconexion de servidor en proceso"
+ swe "Servern går nu ned"
+ ukr "úÁ×ÅÒÛÕ¤ÔØÓÑ ÒÁÂÏÔÁ ÓÅÒ×ÅÒÁ"
+ER_BAD_FIELD_ERROR 42S22 S0022
+ cze "Nezn-Bámý sloupec '%-.64s' v %s"
+ dan "Ukendt kolonne '%-.64s' i tabel %s"
+ nla "Onbekende kolom '%-.64s' in %s"
+ eng "Unknown column '%-.64s' in '%-.64s'"
+ jps "'%-.64s' column ‚Í '%-.64s' ‚É‚Í‚ ‚è‚Ü‚¹‚ñ.",
+ est "Tundmatu tulp '%-.64s' '%-.64s'-s"
+ fre "Champ '%-.64s' inconnu dans %s"
+ ger "Unbekanntes Tabellenfeld '%-.64s' in %-.64s"
+ greek "Áãíùóôï ðåäßï '%-.64s' óå '%-.64s'"
+ hun "A(z) '%-.64s' oszlop ervenytelen '%-.64s'-ben"
+ ita "Colonna sconosciuta '%-.64s' in '%-.64s'"
+ jpn "'%-.64s' column ¤Ï '%-.64s' ¤Ë¤Ï¤¢¤ê¤Þ¤»¤ó."
+ kor "Unknown Ä®·³ '%-.64s' in '%-.64s'"
+ nor "Ukjent kolonne '%-.64s' i tabell %s"
+ norwegian-ny "Ukjent felt '%-.64s' i tabell %s"
+ pol "Nieznana kolumna '%-.64s' w %s"
+ por "Coluna '%-.64s' desconhecida em '%-.64s'"
+ rum "Coloana invalida '%-.64s' in '%-.64s'"
+ rus "îÅÉÚ×ÅÓÔÎÙÊ ÓÔÏÌÂÅà '%-.64s' × '%-.64s'"
+ serbian "Nepoznata kolona '%-.64s' u '%-.64s'"
+ slo "Neznáme pole '%-.64s' v '%-.64s'"
+ spa "La columna '%-.64s' en %s es desconocida"
+ swe "Okänd kolumn '%-.64s' i %s"
+ ukr "îÅצÄÏÍÉÊ ÓÔÏ×ÂÅÃØ '%-.64s' Õ '%-.64s'"
+ER_WRONG_FIELD_WITH_GROUP 42000 S1009
+ cze "Pou-B¾ité '%-.64s' nebylo v group by"
+ dan "Brugte '%-.64s' som ikke var i group by"
+ nla "Opdracht gebruikt '%-.64s' dat niet in de GROUP BY voorkomt"
+ eng "'%-.64s' isn't in GROUP BY"
+ jps "'%-.64s' isn't in GROUP BY",
+ est "'%-.64s' puudub GROUP BY klauslis"
+ fre "'%-.64s' n'est pas dans 'group by'"
+ ger "'%-.64s' ist nicht in GROUP BY vorhanden"
+ greek "×ñçóéìïðïéÞèçêå '%-.64s' ðïõ äåí õðÞñ÷å óôï group by"
+ hun "Used '%-.64s' with wasn't in group by"
+ ita "Usato '%-.64s' che non e` nel GROUP BY"
+ kor "'%-.64s'Àº GROUP BY¼Ó¿¡ ¾øÀ½"
+ nor "Brukte '%-.64s' som ikke var i group by"
+ norwegian-ny "Brukte '%-.64s' som ikkje var i group by"
+ pol "U¿yto '%-.64s' bez umieszczenia w group by"
+ por "'%-.64s' não está em 'GROUP BY'"
+ rum "'%-.64s' nu exista in clauza GROUP BY"
+ rus "'%-.64s' ÎÅ ÐÒÉÓÕÔÓÔ×ÕÅÔ × GROUP BY"
+ serbian "Entitet '%-.64s' nije naveden u komandi 'GROUP BY'"
+ slo "Pou¾ité '%-.64s' nebolo v 'group by'"
+ spa "Usado '%-.64s' el cual no esta group by"
+ swe "'%-.64s' finns inte i GROUP BY"
+ ukr "'%-.64s' ÎÅ ¤ Õ GROUP BY"
+ER_WRONG_GROUP_FIELD 42000 S1009
+ cze "Nemohu pou-B¾ít group na '%-.64s'"
+ dan "Kan ikke gruppere på '%-.64s'"
+ nla "Kan '%-.64s' niet groeperen"
+ eng "Can't group on '%-.64s'"
+ est "Ei saa grupeerida '%-.64s' järgi"
+ fre "Ne peut regrouper '%-.64s'"
+ ger "Gruppierung über '%-.64s' nicht möglich"
+ greek "Áäýíáôç ç ïìáäïðïßçóç (group on) '%-.64s'"
+ hun "A group nem hasznalhato: '%-.64s'"
+ ita "Impossibile raggruppare per '%-.64s'"
+ kor "'%-.64s'¸¦ ±×·ìÇÒ ¼ö ¾øÀ½"
+ nor "Kan ikke gruppere på '%-.64s'"
+ norwegian-ny "Kan ikkje gruppere på '%-.64s'"
+ pol "Nie mo¿na grupowaæ po '%-.64s'"
+ por "Não pode agrupar em '%-.64s'"
+ rum "Nu pot sa grupez pe (group on) '%-.64s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÇÒÕÐÐÉÒÏ×ËÕ ÐÏ '%-.64s'"
+ serbian "Ne mogu da grupišem po '%-.64s'"
+ slo "Nemô¾em pou¾i» 'group' na '%-.64s'"
+ spa "No puedo agrupar por '%-.64s'"
+ swe "Kan inte använda GROUP BY med '%-.64s'"
+ ukr "îÅ ÍÏÖÕ ÇÒÕÐÕ×ÁÔÉ ÐÏ '%-.64s'"
+ER_WRONG_SUM_SELECT 42000 S1009
+ cze "P-Bøíkaz obsahuje zároveò funkci sum a sloupce"
+ dan "Udtrykket har summer (sum) funktioner og kolonner i samme udtryk"
+ nla "Opdracht heeft totaliseer functies en kolommen in dezelfde opdracht"
+ eng "Statement has sum functions and columns in same statement"
+ est "Lauses on korraga nii tulbad kui summeerimisfunktsioonid"
+ fre "Vous demandez la fonction sum() et des champs dans la même commande"
+ ger "Die Verwendung von Summierungsfunktionen und Spalten im selben Befehl ist nicht erlaubt"
+ greek "Ç äéáôýðùóç ðåñéÝ÷åé sum functions êáé columns óôçí ßäéá äéáôýðùóç"
+ ita "Il comando ha una funzione SUM e una colonna non specificata nella GROUP BY"
+ kor "Statement °¡ sum±â´ÉÀ» µ¿ÀÛÁßÀÌ°í Ä®·³µµ µ¿ÀÏÇÑ statementÀÔ´Ï´Ù."
+ nor "Uttrykket har summer (sum) funksjoner og kolonner i samme uttrykk"
+ norwegian-ny "Uttrykket har summer (sum) funksjoner og kolonner i same uttrykk"
+ pol "Zapytanie ma funkcje sumuj?ce i kolumny w tym samym zapytaniu"
+ por "Cláusula contém funções de soma e colunas juntas"
+ rum "Comanda are functii suma si coloane in aceeasi comanda"
+ rus "÷ÙÒÁÖÅÎÉÅ ÓÏÄÅÒÖÉÔ ÇÒÕÐÐÏ×ÙÅ ÆÕÎËÃÉÉ É ÓÔÏÌÂÃÙ, ÎÏ ÎÅ ×ËÌÀÞÁÅÔ GROUP BY. á ËÁË ×Ù ÕÍÕÄÒÉÌÉÓØ ÐÏÌÕÞÉÔØ ÜÔÏ ÓÏÏÂÝÅÎÉÅ Ï ÏÛÉÂËÅ?"
+ serbian "Izraz ima 'SUM' agregatnu funkciju i kolone u isto vreme"
+ slo "Príkaz obsahuje zároveò funkciu 'sum' a poµa"
+ spa "El estamento tiene funciones de suma y columnas en el mismo estamento"
+ swe "Kommandot har både sum functions och enkla funktioner"
+ ukr "õ ×ÉÒÁÚ¦ ×ÉËÏÒÉÓÔÁÎÏ Ð¦ÄÓÕÍÏ×ÕÀÞ¦ ÆÕÎËæ§ ÐÏÒÑÄ Ú ¦ÍÅÎÁÍÉ ÓÔÏ×Âæ×"
+ER_WRONG_VALUE_COUNT 21S01
+ cze "Po-Bèet sloupcù neodpovídá zadané hodnotì"
+ dan "Kolonne tæller stemmer ikke med antallet af værdier"
+ nla "Het aantal kolommen komt niet overeen met het aantal opgegeven waardes"
+ eng "Column count doesn't match value count"
+ est "Tulpade arv erineb väärtuste arvust"
+ ger "Die Anzahl der Spalten entspricht nicht der Anzahl der Werte"
+ greek "Ôï Column count äåí ôáéñéÜæåé ìå ôï value count"
+ hun "Az oszlopban levo ertek nem egyezik meg a szamitott ertekkel"
+ ita "Il numero delle colonne non e` uguale al numero dei valori"
+ kor "Ä®·³ÀÇ Ä«¿îÆ®°¡ °ªÀÇ Ä«¿îÆ®¿Í ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù."
+ nor "Felt telling stemmer verdi telling"
+ norwegian-ny "Kolonne telling stemmer verdi telling"
+ pol "Liczba kolumn nie odpowiada liczbie warto?ci"
+ por "Contagem de colunas não confere com a contagem de valores"
+ rum "Numarul de coloane nu este acelasi cu numarul valoarei"
+ rus "ëÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ× ÎÅ ÓÏ×ÐÁÄÁÅÔ Ó ËÏÌÉÞÅÓÔ×ÏÍ ÚÎÁÞÅÎÉÊ"
+ serbian "Broj kolona ne odgovara broju vrednosti"
+ slo "Poèet polí nezodpovedá zadanej hodnote"
+ spa "La columna con count no tiene valores para contar"
+ swe "Antalet kolumner motsvarar inte antalet värden"
+ ukr "ë¦ÌØ˦ÓÔØ ÓÔÏ×ÂÃ¦× ÎÅ ÓЦ×ÐÁÄÁ¤ Ú Ë¦ÌØ˦ÓÔÀ ÚÎÁÞÅÎØ"
+ER_TOO_LONG_IDENT 42000 S1009
+ cze "Jm-Béno identifikátoru '%-.64s' je pøíli¹ dlouhé"
+ dan "Navnet '%-.64s' er for langt"
+ nla "Naam voor herkenning '%-.64s' is te lang"
+ eng "Identifier name '%-.100s' is too long"
+ jps "Identifier name '%-.100s' ‚Í’·‚·‚¬‚Ü‚·",
+ est "Identifikaatori '%-.100s' nimi on liiga pikk"
+ fre "Le nom de l'identificateur '%-.64s' est trop long"
+ ger "Name des Bezeichners '%-.64s' ist zu lang"
+ greek "Ôï identifier name '%-.100s' åßíáé ðïëý ìåãÜëï"
+ hun "A(z) '%-.100s' azonositonev tul hosszu."
+ ita "Il nome dell'identificatore '%-.100s' e` troppo lungo"
+ jpn "Identifier name '%-.100s' ¤ÏŤ¹¤®¤Þ¤¹"
+ kor "Identifier '%-.100s'´Â ³Ê¹« ±æ±º¿ä."
+ nor "Identifikator '%-.64s' er for lang"
+ norwegian-ny "Identifikator '%-.64s' er for lang"
+ pol "Nazwa identyfikatora '%-.64s' jest zbyt d³uga"
+ por "Nome identificador '%-.100s' é longo demais"
+ rum "Numele indentificatorului '%-.100s' este prea lung"
+ rus "óÌÉÛËÏÍ ÄÌÉÎÎÙÊ ÉÄÅÎÔÉÆÉËÁÔÏÒ '%-.100s'"
+ serbian "Ime '%-.100s' je predugaèko"
+ slo "Meno identifikátora '%-.100s' je príli¹ dlhé"
+ spa "El nombre del identificador '%-.64s' es demasiado grande"
+ swe "Kolumnnamn '%-.64s' är för långt"
+ ukr "¶Í'Ñ ¦ÄÅÎÔÉƦËÁÔÏÒÁ '%-.100s' ÚÁÄÏ×ÇÅ"
+ER_DUP_FIELDNAME 42S21 S1009
+ cze "Zdvojen-Bé jméno sloupce '%-.64s'"
+ dan "Feltnavnet '%-.64s' findes allerede"
+ nla "Dubbele kolom naam '%-.64s'"
+ eng "Duplicate column name '%-.64s'"
+ jps "'%-.64s' ‚Æ‚¢‚¤ column –¼‚Íd•¡‚µ‚Ä‚Ü‚·",
+ est "Kattuv tulba nimi '%-.64s'"
+ fre "Nom du champ '%-.64s' déjà utilisé"
+ ger "Doppelter Spaltenname vorhanden: '%-.64s'"
+ greek "ÅðáíÜëçøç column name '%-.64s'"
+ hun "Duplikalt oszlopazonosito: '%-.64s'"
+ ita "Nome colonna duplicato '%-.64s'"
+ jpn "'%-.64s' ¤È¤¤¤¦ column ̾¤Ï½ÅÊ£¤·¤Æ¤Þ¤¹"
+ kor "Áߺ¹µÈ Ä®·³ À̸§: '%-.64s'"
+ nor "Feltnavnet '%-.64s' eksisterte fra før"
+ norwegian-ny "Feltnamnet '%-.64s' eksisterte frå før"
+ pol "Powtórzona nazwa kolumny '%-.64s'"
+ por "Nome da coluna '%-.64s' duplicado"
+ rum "Numele coloanei '%-.64s' e duplicat"
+ rus "äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ÓÔÏÌÂÃÁ '%-.64s'"
+ serbian "Duplirano ime kolone '%-.64s'"
+ slo "Opakované meno poµa '%-.64s'"
+ spa "Nombre de columna duplicado '%-.64s'"
+ swe "Kolumnnamn '%-.64s finns flera gånger"
+ ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ÓÔÏ×ÂÃÑ '%-.64s'"
+ER_DUP_KEYNAME 42000 S1009
+ cze "Zdvojen-Bé jméno klíèe '%-.64s'"
+ dan "Indeksnavnet '%-.64s' findes allerede"
+ nla "Dubbele zoeksleutel naam '%-.64s'"
+ eng "Duplicate key name '%-.64s'"
+ jps "'%-.64s' ‚Æ‚¢‚¤ key ‚Ì–¼‘O‚Íd•¡‚µ‚Ä‚¢‚Ü‚·",
+ est "Kattuv võtme nimi '%-.64s'"
+ fre "Nom de clef '%-.64s' déjà utilisé"
+ ger "Doppelter Name für Schlüssel (Key) vorhanden: '%-.64s'"
+ greek "ÅðáíÜëçøç key name '%-.64s'"
+ hun "Duplikalt kulcsazonosito: '%-.64s'"
+ ita "Nome chiave duplicato '%-.64s'"
+ jpn "'%-.64s' ¤È¤¤¤¦ key ¤Î̾Á°¤Ï½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
+ kor "Áߺ¹µÈ Å° À̸§ : '%-.64s'"
+ nor "Nøkkelnavnet '%-.64s' eksisterte fra før"
+ norwegian-ny "Nøkkelnamnet '%-.64s' eksisterte frå før"
+ pol "Powtórzony nazwa klucza '%-.64s'"
+ por "Nome da chave '%-.64s' duplicado"
+ rum "Numele cheiei '%-.64s' e duplicat"
+ rus "äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ËÌÀÞÁ '%-.64s'"
+ serbian "Duplirano ime kljuèa '%-.64s'"
+ slo "Opakované meno kµúèa '%-.64s'"
+ spa "Nombre de clave duplicado '%-.64s'"
+ swe "Nyckelnamn '%-.64s' finns flera gånger"
+ ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ËÌÀÞÁ '%-.64s'"
+ER_DUP_ENTRY 23000 S1009
+ cze "Zvojen-Bý klíè '%-.64s' (èíslo klíèe %d)"
+ dan "Ens værdier '%-.64s' for indeks %d"
+ nla "Dubbele ingang '%-.64s' voor zoeksleutel %d"
+ eng "Duplicate entry '%-.64s' for key %d"
+ jps "'%-.64s' ‚Í key %d ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·",
+ est "Kattuv väärtus '%-.64s' võtmele %d"
+ fre "Duplicata du champ '%-.64s' pour la clef %d"
+ ger "Doppelter Eintrag '%-.64s' für Schlüssel %d"
+ greek "ÄéðëÞ åããñáöÞ '%-.64s' ãéá ôï êëåéäß %d"
+ hun "Duplikalt bejegyzes '%-.64s' a %d kulcs szerint."
+ ita "Valore duplicato '%-.64s' per la chiave %d"
+ jpn "'%-.64s' ¤Ï key %d ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
+ kor "Áߺ¹µÈ ÀÔ·Â °ª '%-.64s': key %d"
+ nor "Like verdier '%-.64s' for nøkkel %d"
+ norwegian-ny "Like verdiar '%-.64s' for nykkel %d"
+ pol "Powtórzone wyst?pienie '%-.64s' dla klucza %d"
+ por "Entrada '%-.64s' duplicada para a chave %d"
+ rum "Cimpul '%-.64s' e duplicat pentru cheia %d"
+ rus "äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.64s' ÐÏ ËÌÀÞÕ %d"
+ serbian "Dupliran unos '%-.64s' za kljuè '%d'"
+ slo "Opakovaný kµúè '%-.64s' (èíslo kµúèa %d)"
+ spa "Entrada duplicada '%-.64s' para la clave %d"
+ swe "Dubbel nyckel '%-.64s' för nyckel %d"
+ ukr "äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.64s' ÄÌÑ ËÌÀÞÁ %d"
+ER_WRONG_FIELD_SPEC 42000 S1009
+ cze "Chybn-Bá specifikace sloupce '%-.64s'"
+ dan "Forkert kolonnespecifikaton for felt '%-.64s'"
+ nla "Verkeerde kolom specificatie voor kolom '%-.64s'"
+ eng "Incorrect column specifier for column '%-.64s'"
+ est "Vigane tulba kirjeldus tulbale '%-.64s'"
+ fre "Mauvais paramètre de champ pour le champ '%-.64s'"
+ ger "Falsche Spaltenangaben für Spalte '%-.64s'"
+ greek "ÅóöáëìÝíï column specifier ãéá ôï ðåäßï '%-.64s'"
+ hun "Rossz oszlopazonosito: '%-.64s'"
+ ita "Specifica errata per la colonna '%-.64s'"
+ kor "Ä®·³ '%-.64s'ÀÇ ºÎÁ¤È®ÇÑ Ä®·³ Á¤ÀÇÀÚ"
+ nor "Feil kolonne spesifikator for felt '%-.64s'"
+ norwegian-ny "Feil kolonne spesifikator for kolonne '%-.64s'"
+ pol "B³êdna specyfikacja kolumny dla kolumny '%-.64s'"
+ por "Especificador de coluna incorreto para a coluna '%-.64s'"
+ rum "Specificandul coloanei '%-.64s' este incorect"
+ rus "îÅËÏÒÒÅËÔÎÙÊ ÏÐÒÅÄÅÌÉÔÅÌØ ÓÔÏÌÂÃÁ ÄÌÑ ÓÔÏÌÂÃÁ '%-.64s'"
+ serbian "Pogrešan naziv kolone za kolonu '%-.64s'"
+ slo "Chyba v ¹pecifikácii poµa '%-.64s'"
+ spa "Especificador de columna erroneo para la columna '%-.64s'"
+ swe "Felaktigt kolumntyp för kolumn '%-.64s'"
+ ukr "îÅצÒÎÉÊ ÓÐÅÃÉƦËÁÔÏÒ ÓÔÏ×ÂÃÑ '%-.64s'"
+ER_PARSE_ERROR 42000
+ cze "%s bl-Bízko '%-.64s' na øádku %d"
+ dan "%s nær '%-.64s' på linje %d"
+ nla "%s bij '%-.64s' in regel %d"
+ eng "%s near '%-.80s' at line %d"
+ jps "%s : '%-.80s' •t‹ß : %d s–Ú",
+ est "%s '%-.80s' ligidal real %d"
+ fre "%s près de '%-.64s' à la ligne %d"
+ ger "%s bei '%-.80s' in Zeile %d"
+ greek "%s ðëçóßïí '%-.80s' óôç ãñáììÞ %d"
+ hun "A %s a '%-.80s'-hez kozeli a %d sorban"
+ ita "%s vicino a '%-.80s' linea %d"
+ jpn "%s : '%-.80s' ÉÕ¶á : %d ¹ÔÌÜ"
+ kor "'%-.64s' ¿¡·¯ °°À¾´Ï´Ù. ('%-.80s' ¸í·É¾î ¶óÀÎ %d)"
+ nor "%s nær '%-.64s' på linje %d"
+ norwegian-ny "%s attmed '%-.64s' på line %d"
+ pol "%s obok '%-.64s' w linii %d"
+ por "%s próximo a '%-.80s' na linha %d"
+ rum "%s linga '%-.80s' pe linia %d"
+ rus "%s ÏËÏÌÏ '%-.80s' ÎÁ ÓÔÒÏËÅ %d"
+ serbian "'%s' u iskazu '%-.80s' na liniji %d"
+ slo "%s blízko '%-.80s' na riadku %d"
+ spa "%s cerca '%-.64s' en la linea %d"
+ swe "%s nära '%-.64s' på rad %d"
+ ukr "%s ¦ÌÑ '%-.80s' × ÓÔÒÏæ %d"
+ER_EMPTY_QUERY 42000
+ cze "V-Býsledek dotazu je prázdný"
+ dan "Forespørgsel var tom"
+ nla "Query was leeg"
+ eng "Query was empty"
+ jps "Query ‚ª‹ó‚Å‚·.",
+ est "Tühi päring"
+ fre "Query est vide"
+ ger "Leere Abfrage"
+ greek "Ôï åñþôçìá (query) ðïõ èÝóáôå Þôáí êåíü"
+ hun "Ures lekerdezes."
+ ita "La query e` vuota"
+ jpn "Query ¤¬¶õ¤Ç¤¹."
+ kor "Äõ¸®°á°ú°¡ ¾ø½À´Ï´Ù."
+ nor "Forespørsel var tom"
+ norwegian-ny "Førespurnad var tom"
+ pol "Zapytanie by³o puste"
+ por "Consulta (query) estava vazia"
+ rum "Query-ul a fost gol"
+ rus "úÁÐÒÏÓ ÏËÁÚÁÌÓÑ ÐÕÓÔÙÍ"
+ serbian "Upit je bio prazan"
+ slo "Výsledok po¾iadavky bol prázdny"
+ spa "La query estaba vacia"
+ swe "Frågan var tom"
+ ukr "ðÕÓÔÉÊ ÚÁÐÉÔ"
+ER_NONUNIQ_TABLE 42000 S1009
+ cze "Nejednozna-Bèná tabulka/alias: '%-.64s'"
+ dan "Tabellen/aliaset: '%-.64s' er ikke unikt"
+ nla "Niet unieke waarde tabel/alias: '%-.64s'"
+ eng "Not unique table/alias: '%-.64s'"
+ jps "'%-.64s' ‚͈êˆÓ‚Ì table/alias –¼‚Å‚Í‚ ‚è‚Ü‚¹‚ñ",
+ est "Ei ole unikaalne tabel/alias '%-.64s'"
+ fre "Table/alias: '%-.64s' non unique"
+ ger "Tabellenname/Alias '%-.64s' nicht eindeutig"
+ greek "Áäýíáôç ç áíåýñåóç unique table/alias: '%-.64s'"
+ hun "Nem egyedi tabla/alias: '%-.64s'"
+ ita "Tabella/alias non unico: '%-.64s'"
+ jpn "'%-.64s' ¤Ï°ì°Õ¤Î table/alias ̾¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+ kor "Unique ÇÏÁö ¾ÊÀº Å×À̺í/alias: '%-.64s'"
+ nor "Ikke unikt tabell/alias: '%-.64s'"
+ norwegian-ny "Ikkje unikt tabell/alias: '%-.64s'"
+ pol "Tabela/alias nie s? unikalne: '%-.64s'"
+ por "Tabela/alias '%-.64s' não única"
+ rum "Tabela/alias: '%-.64s' nu este unic"
+ rus "ðÏ×ÔÏÒÑÀÝÁÑÓÑ ÔÁÂÌÉÃÁ/ÐÓÅ×ÄÏÎÉÍ '%-.64s'"
+ serbian "Tabela ili alias nisu bili jedinstveni: '%-.64s'"
+ slo "Nie jednoznaèná tabuµka/alias: '%-.64s'"
+ spa "Tabla/alias: '%-.64s' es no unica"
+ swe "Icke unikt tabell/alias: '%-.64s'"
+ ukr "îÅÕΦËÁÌØÎÁ ÔÁÂÌÉÃÑ/ÐÓÅ×ÄÏΦÍ: '%-.64s'"
+ER_INVALID_DEFAULT 42000 S1009
+ cze "Chybn-Bá defaultní hodnota pro '%-.64s'"
+ dan "Ugyldig standardværdi for '%-.64s'"
+ nla "Foutieve standaard waarde voor '%-.64s'"
+ eng "Invalid default value for '%-.64s'"
+ est "Vigane vaikeväärtus '%-.64s' jaoks"
+ fre "Valeur par défaut invalide pour '%-.64s'"
+ ger "Fehlerhafter Vorgabewert (DEFAULT): '%-.64s'"
+ greek "ÅóöáëìÝíç ðñïêáèïñéóìÝíç ôéìÞ (default value) ãéá '%-.64s'"
+ hun "Ervenytelen ertek: '%-.64s'"
+ ita "Valore di default non valido per '%-.64s'"
+ kor "'%-.64s'ÀÇ À¯È¿ÇÏÁö ¸øÇÑ µðÆúÆ® °ªÀ» »ç¿ëÇϼ̽À´Ï´Ù."
+ nor "Ugyldig standardverdi for '%-.64s'"
+ norwegian-ny "Ugyldig standardverdi for '%-.64s'"
+ pol "Niew³a?ciwa warto?æ domy?lna dla '%-.64s'"
+ por "Valor padrão (default) inválido para '%-.64s'"
+ rum "Valoarea de default este invalida pentru '%-.64s'"
+ rus "îÅËÏÒÒÅËÔÎÏÅ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ '%-.64s'"
+ serbian "Loša default vrednost za '%-.64s'"
+ slo "Chybná implicitná hodnota pre '%-.64s'"
+ spa "Valor por defecto invalido para '%-.64s'"
+ swe "Ogiltigt DEFAULT värde för '%-.64s'"
+ ukr "îÅצÒÎÅ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ ÄÌÑ '%-.64s'"
+ER_MULTIPLE_PRI_KEY 42000 S1009
+ cze "Definov-Báno více primárních klíèù"
+ dan "Flere primærnøgler specificeret"
+ nla "Meerdere primaire zoeksleutels gedefinieerd"
+ eng "Multiple primary key defined"
+ jps "•¡”‚Ì primary key ‚ª’è‹`‚³‚ê‚Ü‚µ‚½",
+ est "Mitut primaarset võtit ei saa olla"
+ fre "Plusieurs clefs primaires définies"
+ ger "Mehrfacher Primärschlüssel (PRIMARY KEY) definiert"
+ greek "Ðåñéóóüôåñá áðü Ýíá primary key ïñßóôçêáí"
+ hun "Tobbszoros elsodleges kulcs definialas."
+ ita "Definite piu` chiave primarie"
+ jpn "Ê£¿ô¤Î primary key ¤¬ÄêµÁ¤µ¤ì¤Þ¤·¤¿"
+ kor "Multiple primary key°¡ Á¤ÀǵǾî ÀÖ½¿"
+ nor "Fleire primærnøkle spesifisert"
+ norwegian-ny "Fleire primærnyklar spesifisert"
+ pol "Zdefiniowano wiele kluczy podstawowych"
+ por "Definida mais de uma chave primária"
+ rum "Chei primare definite de mai multe ori"
+ rus "õËÁÚÁÎÏ ÎÅÓËÏÌØËÏ ÐÅÒ×ÉÞÎÙÈ ËÌÀÞÅÊ"
+ serbian "Definisani višestruki primarni kljuèevi"
+ slo "Zadefinovaných viac primárnych kµúèov"
+ spa "Multiples claves primarias definidas"
+ swe "Flera PRIMARY KEY använda"
+ ukr "ðÅÒ×ÉÎÎÏÇÏ ËÌÀÞÁ ×ÉÚÎÁÞÅÎÏ ÎÅÏÄÎÏÒÁÚÏ×Ï"
+ER_TOO_MANY_KEYS 42000 S1009
+ cze "Zad-Báno pøíli¹ mnoho klíèù, je povoleno nejvíce %d klíèù"
+ dan "For mange nøgler specificeret. Kun %d nøgler må bruges"
+ nla "Teveel zoeksleutels gedefinieerd. Maximaal zijn %d zoeksleutels toegestaan"
+ eng "Too many keys specified; max %d keys allowed"
+ jps "key ‚ÌŽw’肪‘½‚·‚¬‚Ü‚·. key ‚ÍÅ‘å %d ‚Ü‚Å‚Å‚·",
+ est "Liiga palju võtmeid. Maksimaalselt võib olla %d võtit"
+ fre "Trop de clefs sont définies. Maximum de %d clefs alloué"
+ ger "Zu viele Schlüssel definiert. Maximal %d Schlüssel erlaubt"
+ greek "ÐÜñá ðïëëÜ key ïñßóèçêáí. Ôï ðïëý %d åðéôñÝðïíôáé"
+ hun "Tul sok kulcs. Maximum %d kulcs engedelyezett."
+ ita "Troppe chiavi. Sono ammesse max %d chiavi"
+ jpn "key ¤Î»ØÄ꤬¿¤¹¤®¤Þ¤¹. key ¤ÏºÇÂç %d ¤Þ¤Ç¤Ç¤¹"
+ kor "³Ê¹« ¸¹Àº Å°°¡ Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.. ÃÖ´ë %dÀÇ Å°°¡ °¡´ÉÇÔ"
+ nor "For mange nøkler spesifisert. Maks %d nøkler tillatt"
+ norwegian-ny "For mange nykler spesifisert. Maks %d nyklar tillatt"
+ pol "Okre?lono zbyt wiele kluczy. Dostêpnych jest maksymalnie %d kluczy"
+ por "Especificadas chaves demais. O máximo permitido são %d chaves"
+ rum "Prea multe chei. Numarul de chei maxim este %d"
+ rus "õËÁÚÁÎÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ËÌÀÞÅÊ. òÁÚÒÅÛÁÅÔÓÑ ÕËÁÚÙ×ÁÔØ ÎÅ ÂÏÌÅÅ %d ËÌÀÞÅÊ"
+ serbian "Navedeno je previše kljuèeva. Maksimum %d kljuèeva je dozvoljeno"
+ slo "Zadaných ríli¹ veµa kµúèov. Najviac %d kµúèov je povolených"
+ spa "Demasiadas claves primarias declaradas. Un maximo de %d claves son permitidas"
+ swe "För många nycklar använda. Man får ha högst %d nycklar"
+ ukr "úÁÂÁÇÁÔÏ ËÌÀÞ¦× ÚÁÚÎÁÞÅÎÏ. äÏÚ×ÏÌÅÎÏ ÎŠ¦ÌØÛÅ %d ËÌÀÞ¦×"
+ER_TOO_MANY_KEY_PARTS 42000 S1009
+ cze "Zad-Báno pøíli¹ mnoho èást klíèù, je povoleno nejvíce %d èástí"
+ dan "For mange nøgledele specificeret. Kun %d dele må bruges"
+ nla "Teveel zoeksleutel onderdelen gespecificeerd. Maximaal %d onderdelen toegestaan"
+ eng "Too many key parts specified; max %d parts allowed"
+ est "Võti koosneb liiga paljudest osadest. Maksimaalselt võib olla %d osa"
+ fre "Trop de parties specifiées dans la clef. Maximum de %d parties"
+ ger "Zu viele Teilschlüssel definiert. Maximal sind %d Teilschlüssel erlaubt"
+ greek "ÐÜñá ðïëëÜ key parts ïñßóèçêáí. Ôï ðïëý %d åðéôñÝðïíôáé"
+ hun "Tul sok kulcsdarabot definialt. Maximum %d resz engedelyezett"
+ ita "Troppe parti di chiave specificate. Sono ammesse max %d parti"
+ kor "³Ê¹« ¸¹Àº Å° ºÎºÐ(parts)µéÀÌ Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.. ÃÖ´ë %d ºÎºÐÀÌ °¡´ÉÇÔ"
+ nor "For mange nøkkeldeler spesifisert. Maks %d deler tillatt"
+ norwegian-ny "For mange nykkeldelar spesifisert. Maks %d delar tillatt"
+ pol "Okre?lono zbyt wiele czê?ci klucza. Dostêpnych jest maksymalnie %d czê?ci"
+ por "Especificadas partes de chave demais. O máximo permitido são %d partes"
+ rum "Prea multe chei. Numarul de chei maxim este %d"
+ rus "õËÁÚÁÎÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÞÁÓÔÅÊ ÓÏÓÔÁ×ÎÏÇÏ ËÌÀÞÁ. òÁÚÒÅÛÁÅÔÓÑ ÕËÁÚÙ×ÁÔØ ÎÅ ÂÏÌÅÅ %d ÞÁÓÔÅÊ"
+ serbian "Navedeno je previše delova kljuèa. Maksimum %d delova je dozvoljeno"
+ slo "Zadaných ríli¹ veµa èastí kµúèov. Je povolených najviac %d èastí"
+ spa "Demasiadas partes de clave declaradas. Un maximo de %d partes son permitidas"
+ swe "För många nyckeldelar använda. Man får ha högst %d nyckeldelar"
+ ukr "úÁÂÁÇÁÔÏ ÞÁÓÔÉÎ ËÌÀÞÁ ÚÁÚÎÁÞÅÎÏ. äÏÚ×ÏÌÅÎÏ ÎŠ¦ÌØÛÅ %d ÞÁÓÔÉÎ"
+ER_TOO_LONG_KEY 42000 S1009
+ cze "Zadan-Bý klíè byl pøíli¹ dlouhý, nejvìt¹í délka klíèe je %d"
+ dan "Specificeret nøgle var for lang. Maksimal nøglelængde er %d"
+ nla "Gespecificeerde zoeksleutel was te lang. De maximale lengte is %d"
+ eng "Specified key was too long; max key length is %d bytes"
+ jps "key ‚ª’·‚·‚¬‚Ü‚·. key ‚Ì’·‚³‚ÍÅ‘å %d ‚Å‚·",
+ est "Võti on liiga pikk. Maksimaalne võtmepikkus on %d"
+ fre "La clé est trop longue. Longueur maximale: %d"
+ ger "Schlüssel ist zu lang. Die maximale Schlüssellänge beträgt %d"
+ greek "Ôï êëåéäß ðïõ ïñßóèçêå åßíáé ðïëý ìåãÜëï. Ôï ìÝãéóôï ìÞêïò åßíáé %d"
+ hun "A megadott kulcs tul hosszu. Maximalis kulcshosszusag: %d"
+ ita "La chiave specificata e` troppo lunga. La max lunghezza della chiave e` %d"
+ jpn "key ¤¬Ä¹¤¹¤®¤Þ¤¹. key ¤ÎŤµ¤ÏºÇÂç %d ¤Ç¤¹"
+ kor "Á¤ÀÇµÈ Å°°¡ ³Ê¹« ±é´Ï´Ù. ÃÖ´ë Å°ÀÇ ±æÀÌ´Â %dÀÔ´Ï´Ù."
+ nor "Spesifisert nøkkel var for lang. Maks nøkkellengde er is %d"
+ norwegian-ny "Spesifisert nykkel var for lang. Maks nykkellengde er %d"
+ pol "Zdefinowany klucz jest zbyt d³ugi. Maksymaln? d³ugo?ci? klucza jest %d"
+ por "Chave especificada longa demais. O comprimento de chave máximo permitido é %d"
+ rum "Cheia specificata este prea lunga. Marimea maxima a unei chei este de %d"
+ rus "õËÁÚÁÎ ÓÌÉÛËÏÍ ÄÌÉÎÎÙÊ ËÌÀÞ. íÁËÓÉÍÁÌØÎÁÑ ÄÌÉÎÁ ËÌÀÞÁ ÓÏÓÔÁ×ÌÑÅÔ %d ÂÁÊÔ"
+ serbian "Navedeni kljuè je predug. Maksimalna dužina kljuèa je %d"
+ slo "Zadaný kµúè je príli¹ dlhý, najväè¹ia då¾ka kµúèa je %d"
+ spa "Declaracion de clave demasiado larga. La maxima longitud de clave es %d"
+ swe "För lång nyckel. Högsta tillåtna nyckellängd är %d"
+ ukr "úÁÚÎÁÞÅÎÉÊ ËÌÀÞ ÚÁÄÏ×ÇÉÊ. îÁʦÌØÛÁ ÄÏ×ÖÉÎÁ ËÌÀÞÁ %d ÂÁÊÔ¦×"
+ER_KEY_COLUMN_DOES_NOT_EXITS 42000 S1009
+ cze "Kl-Bíèový sloupec '%-.64s' v tabulce neexistuje"
+ dan "Nøglefeltet '%-.64s' eksisterer ikke i tabellen"
+ nla "Zoeksleutel kolom '%-.64s' bestaat niet in tabel"
+ eng "Key column '%-.64s' doesn't exist in table"
+ jps "Key column '%-.64s' ‚ªƒe[ƒuƒ‹‚É‚ ‚è‚Ü‚¹‚ñ.",
+ est "Võtme tulp '%-.64s' puudub tabelis"
+ fre "La clé '%-.64s' n'existe pas dans la table"
+ ger "In der Tabelle gibt es keine Schlüsselspalte '%-.64s'"
+ greek "Ôï ðåäßï êëåéäß '%-.64s' äåí õðÜñ÷åé óôïí ðßíáêá"
+ hun "A(z) '%-.64s'kulcsoszlop nem letezik a tablaban"
+ ita "La colonna chiave '%-.64s' non esiste nella tabella"
+ jpn "Key column '%-.64s' ¤¬¥Æ¡¼¥Ö¥ë¤Ë¤¢¤ê¤Þ¤»¤ó."
+ kor "Key Ä®·³ '%-.64s'´Â Å×ÀÌºí¿¡ Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
+ nor "Nøkkel felt '%-.64s' eksiterer ikke i tabellen"
+ norwegian-ny "Nykkel kolonne '%-.64s' eksiterar ikkje i tabellen"
+ pol "Kolumna '%-.64s' zdefiniowana w kluczu nie istnieje w tabeli"
+ por "Coluna chave '%-.64s' não existe na tabela"
+ rum "Coloana cheie '%-.64s' nu exista in tabela"
+ rus "ëÌÀÞÅ×ÏÊ ÓÔÏÌÂÅà '%-.64s' × ÔÁÂÌÉÃÅ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Kljuèna kolona '%-.64s' ne postoji u tabeli"
+ slo "Kµúèový ståpec '%-.64s' v tabuµke neexistuje"
+ spa "La columna clave '%-.64s' no existe en la tabla"
+ swe "Nyckelkolumn '%-.64s' finns inte"
+ ukr "ëÌÀÞÏ×ÉÊ ÓÔÏ×ÂÅÃØ '%-.64s' ÎÅ ¦ÓÎÕ¤ Õ ÔÁÂÌÉæ"
+ER_BLOB_USED_AS_KEY 42000 S1009
+ cze "Blob sloupec '%-.64s' nem-Bù¾e být pou¾it jako klíè"
+ dan "BLOB feltet '%-.64s' kan ikke bruges ved specifikation af indeks"
+ nla "BLOB kolom '%-.64s' kan niet gebruikt worden bij zoeksleutel specificatie"
+ eng "BLOB column '%-.64s' can't be used in key specification with the used table type"
+ est "BLOB-tüüpi tulpa '%-.64s' ei saa kasutada võtmena"
+ fre "Champ BLOB '%-.64s' ne peut être utilisé dans une clé"
+ ger "BLOB-Feld '%-.64s' kann beim verwendeten Tabellentyp nicht als Schlüssel verwendet werden"
+ greek "Ðåäßï ôýðïõ Blob '%-.64s' äåí ìðïñåß íá ÷ñçóéìïðïéçèåß óôïí ïñéóìü åíüò êëåéäéïý (key specification)"
+ hun "Blob objektum '%-.64s' nem hasznalhato kulcskent"
+ ita "La colonna BLOB '%-.64s' non puo` essere usata nella specifica della chiave"
+ kor "BLOB Ä®·³ '%-.64s'´Â Å° Á¤ÀÇ¿¡¼­ »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù."
+ nor "Blob felt '%-.64s' kan ikke brukes ved spesifikasjon av nøkler"
+ norwegian-ny "Blob kolonne '%-.64s' kan ikkje brukast ved spesifikasjon av nyklar"
+ pol "Kolumna typu Blob '%-.64s' nie mo¿e byæ u¿yta w specyfikacji klucza"
+ por "Coluna BLOB '%-.64s' não pode ser utilizada na especificação de chave para o tipo de tabela usado"
+ rum "Coloana de tip BLOB '%-.64s' nu poate fi folosita in specificarea cheii cu tipul de tabla folosit"
+ rus "óÔÏÌÂÅà ÔÉÐÁ BLOB '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ËÁË ÚÎÁÞÅÎÉÅ ËÌÀÞÁ × ÔÁÂÌÉÃÅ ÔÁËÏÇÏ ÔÉÐÁ"
+ serbian "BLOB kolona '%-.64s' ne može biti upotrebljena za navoðenje kljuèa sa tipom tabele koji se trenutno koristi"
+ slo "Blob pole '%-.64s' nemô¾e by» pou¾ité ako kµúè"
+ spa "La columna Blob '%-.64s' no puede ser usada en una declaracion de clave"
+ swe "En BLOB '%-.64s' kan inte vara nyckel med den använda tabelltypen"
+ ukr "BLOB ÓÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ × ÃØÏÍÕ ÔÉЦ ÔÁÂÌÉæ"
+ER_TOO_BIG_FIELDLENGTH 42000 S1009
+ cze "P-Bøíli¹ velká délka sloupce '%-.64s' (nejvíce %d). Pou¾ijte BLOB"
+ dan "For stor feltlængde for kolonne '%-.64s' (maks = %d). Brug BLOB i stedet"
+ nla "Te grote kolomlengte voor '%-.64s' (max = %d). Maak hiervoor gebruik van het type BLOB"
+ eng "Column length too big for column '%-.64s' (max = %d); use BLOB or TEXT instead"
+ jps "column '%-.64s' ‚Í,Šm•Û‚·‚é column ‚Ì‘å‚«‚³‚ª‘½‚·‚¬‚Ü‚·. (Å‘å %d ‚Ü‚Å). BLOB ‚ð‚©‚í‚è‚ÉŽg—p‚µ‚Ä‚­‚¾‚³‚¢.",
+ est "Tulba '%-.64s' pikkus on liiga pikk (maksimaalne pikkus: %d). Kasuta BLOB väljatüüpi"
+ fre "Champ '%-.64s' trop long (max = %d). Utilisez un BLOB"
+ ger "Feldlänge für Feld '%-.64s' zu groß (maximal %d). BLOB-Feld verwenden!"
+ greek "Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.64s' (max = %d). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB"
+ hun "A(z) '%-.64s' oszlop tul hosszu. (maximum = %d). Hasznaljon BLOB tipust inkabb."
+ ita "La colonna '%-.64s' e` troppo grande (max=%d). Utilizza un BLOB."
+ jpn "column '%-.64s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礭¤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %d ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤."
+ kor "Ä®·³ '%-.64s'ÀÇ Ä®·³ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %d). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä."
+ nor "For stor nøkkellengde for kolonne '%-.64s' (maks = %d). Bruk BLOB istedenfor"
+ norwegian-ny "For stor nykkellengde for felt '%-.64s' (maks = %d). Bruk BLOB istadenfor"
+ pol "Zbyt du¿a d³ugo?æ kolumny '%-.64s' (maks. = %d). W zamian u¿yj typu BLOB"
+ por "Comprimento da coluna '%-.64s' grande demais (max = %d); use BLOB em seu lugar"
+ rum "Lungimea coloanei '%-.64s' este prea lunga (maximum = %d). Foloseste BLOB mai bine"
+ rus "óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.64s' (ÍÁËÓÉÍÕÍ = %d). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ÉÌÉ TEXT ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ"
+ serbian "Previše podataka za kolonu '%-.64s' (maksimum je %d). Upotrebite BLOB polje"
+ slo "Príli¹ veµká då¾ka pre pole '%-.64s' (maximum = %d). Pou¾ite BLOB"
+ spa "Longitud de columna demasiado grande para la columna '%-.64s' (maximo = %d).Usar BLOB en su lugar"
+ swe "För stor kolumnlängd angiven för '%-.64s' (max= %d). Använd en BLOB instället"
+ ukr "úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.64s' (max = %d). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB"
+ER_WRONG_AUTO_KEY 42000 S1009
+ cze "M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè"
+ dan "Der kan kun specificeres eet AUTO_INCREMENT-felt, og det skal være indekseret"
+ nla "Er kan slechts 1 autofield zijn en deze moet als zoeksleutel worden gedefinieerd."
+ eng "Incorrect table definition; there can be only one auto column and it must be defined as a key"
+ jps "ƒe[ƒuƒ‹‚Ì’è‹`‚ªˆá‚¢‚Ü‚·; there can be only one auto column and it must be defined as a key",
+ est "Vigane tabelikirjeldus; Tabelis tohib olla üks auto_increment tüüpi tulp ning see peab olema defineeritud võtmena"
+ fre "Un seul champ automatique est permis et il doit être indexé"
+ ger "Falsche Tabellendefinition. Es darf nur ein Auto-Feld geben und dieses muss als Schlüssel definiert werden"
+ greek "Ìðïñåß íá õðÜñ÷åé ìüíï Ýíá auto field êáé ðñÝðåé íá Ý÷åé ïñéóèåß óáí key"
+ hun "Csak egy auto mezo lehetseges, es azt kulcskent kell definialni."
+ ita "Puo` esserci solo un campo AUTO e deve essere definito come chiave"
+ jpn "¥Æ¡¼¥Ö¥ë¤ÎÄêµÁ¤¬°ã¤¤¤Þ¤¹; there can be only one auto column and it must be defined as a key"
+ kor "ºÎÁ¤È®ÇÑ Å×À̺í Á¤ÀÇ; Å×À̺íÀº ÇϳªÀÇ auto Ä®·³ÀÌ Á¸ÀçÇÏ°í Å°·Î Á¤ÀǵǾîÁ®¾ß ÇÕ´Ï´Ù."
+ nor "Bare ett auto felt kan være definert som nøkkel."
+ norwegian-ny "Bare eitt auto felt kan være definert som nøkkel."
+ pol "W tabeli mo¿e byæ tylko jedno pole auto i musi ono byæ zdefiniowane jako klucz"
+ por "Definição incorreta de tabela. Somente é permitido um único campo auto-incrementado e ele tem que ser definido como chave"
+ rum "Definitia tabelei este incorecta; Nu pot fi mai mult de o singura coloana de tip auto si aceasta trebuie definita ca cheie"
+ rus "îÅËÏÒÒÅËÔÎÏÅ ÏÐÒÅÄÅÌÅÎÉÅ ÔÁÂÌÉÃÙ: ÍÏÖÅÔ ÓÕÝÅÓÔ×Ï×ÁÔØ ÔÏÌØËÏ ÏÄÉÎ Á×ÔÏÉÎËÒÅÍÅÎÔÎÙÊ ÓÔÏÌÂÅÃ, É ÏÎ ÄÏÌÖÅÎ ÂÙÔØ ÏÐÒÅÄÅÌÅÎ ËÁË ËÌÀÞ"
+ serbian "Pogrešna definicija tabele; U tabeli može postojati samo jedna 'AUTO' kolona i ona mora biti istovremeno definisana kao kolona kljuèa"
+ slo "Mô¾ete ma» iba jedno AUTO pole a to musí by» definované ako kµúè"
+ spa "Puede ser solamente un campo automatico y este debe ser definido como una clave"
+ swe "Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel"
+ ukr "îÅצÒÎÅ ×ÉÚÎÁÞÅÎÎÑ ÔÁÂÌÉæ; íÏÖÅ ÂÕÔÉ ÌÉÛÅ ÏÄÉÎ Á×ÔÏÍÁÔÉÞÎÉÊ ÓÔÏ×ÂÅÃØ, ÝÏ ÐÏ×ÉÎÅÎ ÂÕÔÉ ×ÉÚÎÁÞÅÎÉÊ ÑË ËÌÀÞ"
+ER_READY
+ cze "%s: p-Bøipraven na spojení"
+ dan "%s: klar til tilslutninger"
+ nla "%s: klaar voor verbindingen"
+ eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d"
+ jps "%s: €”õŠ®—¹",
+ est "%s: ootab ühendusi"
+ fre "%s: Prêt pour des connections"
+ ger "%-.64s: Bereit für Verbindungen"
+ greek "%s: óå áíáìïíÞ óõíäÝóåùí"
+ hun "%s: kapcsolatra kesz"
+ ita "%s: Pronto per le connessioni\n"
+ jpn "%s: ½àÈ÷´°Î»"
+ kor "%s: ¿¬°á ÁغñÁßÀÔ´Ï´Ù"
+ nor "%s: klar for tilkoblinger"
+ norwegian-ny "%s: klar for tilkoblingar"
+ pol "%s: gotowe do po³?czenia"
+ por "%s: Pronto para conexões"
+ rum "%s: sint gata pentru conectii"
+ rus "%s: çÏÔÏ× ÐÒÉÎÉÍÁÔØ ÓÏÅÄÉÎÅÎÉÑ.\n÷ÅÒÓÉÑ: '%s' ÓÏËÅÔ: '%s' ÐÏÒÔ: %d %s"
+ serbian "%s: Spreman za konekcije\n"
+ slo "%s: pripravený na spojenie"
+ spa "%s: preparado para conexiones"
+ swe "%s: klar att ta emot klienter"
+ ukr "%s: çÏÔÏ×ÉÊ ÄÌÑ Ú'¤ÄÎÁÎØ!"
+ER_NORMAL_SHUTDOWN
+ cze "%s: norm-Bální ukonèení\n"
+ dan "%s: Normal nedlukning\n"
+ nla "%s: Normaal afgesloten \n"
+ eng "%s: Normal shutdown\n"
+ est "%s: MySQL lõpetas\n"
+ fre "%s: Arrêt normal du serveur\n"
+ ger "%-.64s: Normal heruntergefahren\n"
+ greek "%s: ÖõóéïëïãéêÞ äéáäéêáóßá shutdown\n"
+ hun "%s: Normal leallitas\n"
+ ita "%s: Shutdown normale\n"
+ kor "%s: Á¤»óÀûÀÎ shutdown\n"
+ nor "%s: Normal avslutning\n"
+ norwegian-ny "%s: Normal nedkopling\n"
+ pol "%s: Standardowe zakoñczenie dzia³ania\n"
+ por "%s: 'Shutdown' normal\n"
+ rum "%s: Terminare normala\n"
+ rus "%s: ëÏÒÒÅËÔÎÁÑ ÏÓÔÁÎÏ×ËÁ\n"
+ serbian "%s: Normalno gašenje\n"
+ slo "%s: normálne ukonèenie\n"
+ spa "%s: Apagado normal\n"
+ swe "%s: Normal avslutning\n"
+ ukr "%s: îÏÒÍÁÌØÎÅ ÚÁ×ÅÒÛÅÎÎÑ\n"
+ER_GOT_SIGNAL
+ cze "%s: p-Bøijat signal %d, konèím\n"
+ dan "%s: Fangede signal %d. Afslutter!!\n"
+ nla "%s: Signaal %d. Systeem breekt af!\n"
+ eng "%s: Got signal %d. Aborting!\n"
+ jps "%s: Got signal %d. ’†’f!\n",
+ est "%s: sain signaali %d. Lõpetan!\n"
+ fre "%s: Reçu le signal %d. Abandonne!\n"
+ ger "%-.64s: Signal %d erhalten. Abbruch!\n"
+ greek "%s: ÅëÞöèç ôï ìÞíõìá %d. Ç äéáäéêáóßá åãêáôáëåßðåôáé!\n"
+ hun "%s: %d jelzes. Megszakitva!\n"
+ ita "%s: Ricevuto segnale %d. Interruzione!\n"
+ jpn "%s: Got signal %d. ̾̂!\n"
+ kor "%s: %d ½ÅÈ£°¡ µé¾î¿ÔÀ½. ÁßÁö!\n"
+ nor "%s: Oppdaget signal %d. Avslutter!\n"
+ norwegian-ny "%s: Oppdaga signal %d. Avsluttar!\n"
+ pol "%s: Otrzymano sygna³ %d. Koñczenie dzia³ania!\n"
+ por "%s: Obteve sinal %d. Abortando!\n"
+ rum "%s: Semnal %d obtinut. Aborting!\n"
+ rus "%s: ðÏÌÕÞÅÎ ÓÉÇÎÁÌ %d. ðÒÅËÒÁÝÁÅÍ!\n"
+ serbian "%s: Dobio signal %d. Prekidam!\n"
+ slo "%s: prijatý signál %d, ukonèenie (Abort)!\n"
+ spa "%s: Recibiendo signal %d. Abortando!\n"
+ swe "%s: Fick signal %d. Avslutar!\n"
+ ukr "%s: ïÔÒÉÍÁÎÏ ÓÉÇÎÁÌ %d. ðÅÒÅÒÉ×ÁÀÓØ!\n"
+ER_SHUTDOWN_COMPLETE
+ cze "%s: ukon-Bèení práce hotovo\n"
+ dan "%s: Server lukket\n"
+ nla "%s: Afsluiten afgerond\n"
+ eng "%s: Shutdown complete\n"
+ jps "%s: Shutdown Š®—¹\n",
+ est "%s: Lõpp\n"
+ fre "%s: Arrêt du serveur terminé\n"
+ ger "%-.64s: Heruntergefahren (shutdown)\n"
+ greek "%s: Ç äéáäéêáóßá Shutdown ïëïêëçñþèçêå\n"
+ hun "%s: A leallitas kesz\n"
+ ita "%s: Shutdown completato\n"
+ jpn "%s: Shutdown ´°Î»\n"
+ kor "%s: Shutdown ÀÌ ¿Ï·áµÊ!\n"
+ nor "%s: Avslutning komplett\n"
+ norwegian-ny "%s: Nedkopling komplett\n"
+ pol "%s: Zakoñczenie dzia³ania wykonane\n"
+ por "%s: 'Shutdown' completo\n"
+ rum "%s: Terminare completa\n"
+ rus "%s: ïÓÔÁÎÏ×ËÁ ÚÁ×ÅÒÛÅÎÁ\n"
+ serbian "%s: Gašenje završeno\n"
+ slo "%s: práca ukonèená\n"
+ spa "%s: Apagado completado\n"
+ swe "%s: Avslutning klar\n"
+ ukr "%s: òÏÂÏÔÕ ÚÁ×ÅÒÛÅÎÏ\n"
+ER_FORCING_CLOSE 08S01
+ cze "%s: n-Básilné uzavøení threadu %ld u¾ivatele '%-.64s'\n"
+ dan "%s: Forceret nedlukning af tråd: %ld bruger: '%-.64s'\n"
+ nla "%s: Afsluiten afgedwongen van thread %ld gebruiker: '%-.64s'\n"
+ eng "%s: Forcing close of thread %ld user: '%-.32s'\n"
+ jps "%s: ƒXƒŒƒbƒh %ld ‹­§I—¹ user: '%-.64s'\n",
+ est "%s: Sulgen jõuga lõime %ld kasutaja: '%-.32s'\n"
+ fre "%s: Arrêt forcé de la tâche (thread) %ld utilisateur: '%-.64s'\n"
+ ger "%s: Thread %ld zwangsweise beendet. Benutzer: '%-.32s'\n"
+ greek "%s: Ôï thread èá êëåßóåé %ld user: '%-.64s'\n"
+ hun "%s: A(z) %ld thread kenyszeritett zarasa. Felhasznalo: '%-.64s'\n"
+ ita "%s: Forzata la chiusura del thread %ld utente: '%-.64s'\n"
+ jpn "%s: ¥¹¥ì¥Ã¥É %ld ¶¯À©½ªÎ» user: '%-.64s'\n"
+ kor "%s: thread %ldÀÇ °­Á¦ Á¾·á user: '%-.64s'\n"
+ nor "%s: Påtvinget avslutning av tråd %ld bruker: '%-.64s'\n"
+ norwegian-ny "%s: Påtvinga avslutning av tråd %ld brukar: '%-.64s'\n"
+ pol "%s: Wymuszenie zamkniêcia w?tku %ld u¿ytkownik: '%-.64s'\n"
+ por "%s: Forçando finalização da 'thread' %ld - usuário '%-.32s'\n"
+ rum "%s: Terminare fortata a thread-ului %ld utilizatorului: '%-.32s'\n"
+ rus "%s: ðÒÉÎÕÄÉÔÅÌØÎÏ ÚÁËÒÙ×ÁÅÍ ÐÏÔÏË %ld ÐÏÌØÚÏ×ÁÔÅÌÑ: '%-.32s'\n"
+ serbian "%s: Usiljeno gašenje thread-a %ld koji pripada korisniku: '%-.32s'\n"
+ slo "%s: násilné ukonèenie vlákna %ld u¾ívateµa '%-.64s'\n"
+ spa "%s: Forzando a cerrar el thread %ld usuario: '%-.64s'\n"
+ swe "%s: Stänger av tråd %ld; användare: '%-.64s'\n"
+ ukr "%s: ðÒÉÓËÏÒÀÀ ÚÁËÒÉÔÔÑ Ç¦ÌËÉ %ld ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'\n"
+ER_IPSOCK_ERROR 08S01
+ cze "Nemohu vytvo-Bøit IP socket"
+ dan "Kan ikke oprette IP socket"
+ nla "Kan IP-socket niet openen"
+ eng "Can't create IP socket"
+ jps "IP socket ‚ªì‚ê‚Ü‚¹‚ñ",
+ est "Ei suuda luua IP socketit"
+ fre "Ne peut créer la connection IP (socket)"
+ ger "Kann IP-Socket nicht erzeugen"
+ greek "Äåí åßíáé äõíáôÞ ç äçìéïõñãßá IP socket"
+ hun "Az IP socket nem hozhato letre"
+ ita "Impossibile creare il socket IP"
+ jpn "IP socket ¤¬ºî¤ì¤Þ¤»¤ó"
+ kor "IP ¼ÒÄÏÀ» ¸¸µéÁö ¸øÇß½À´Ï´Ù."
+ nor "Kan ikke opprette IP socket"
+ norwegian-ny "Kan ikkje opprette IP socket"
+ pol "Nie mo¿na stworzyæ socket'u IP"
+ por "Não pode criar o soquete IP"
+ rum "Nu pot crea IP socket"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ IP-ÓÏËÅÔ"
+ serbian "Ne mogu da kreiram IP socket"
+ slo "Nemô¾em vytvori» IP socket"
+ spa "No puedo crear IP socket"
+ swe "Kan inte skapa IP-socket"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ IP ÒÏÚ'¤Í"
+ER_NO_SUCH_INDEX 42S12 S1009
+ cze "Tabulka '%-.64s' nem-Bá index odpovídající CREATE INDEX. Vytvoøte tabulku znovu"
+ dan "Tabellen '%-.64s' har ikke den nøgle, som blev brugt i CREATE INDEX. Genopret tabellen"
+ nla "Tabel '%-.64s' heeft geen INDEX zoals deze gemaakt worden met CREATE INDEX. Maak de tabel opnieuw"
+ eng "Table '%-.64s' has no index like the one used in CREATE INDEX; recreate the table"
+ jps "Table '%-.64s' ‚Í‚»‚̂悤‚È index ‚ðŽ‚Á‚Ä‚¢‚Ü‚¹‚ñ(CREATE INDEX ŽÀsŽž‚ÉŽw’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ). ƒe[ƒuƒ‹‚ðì‚è’¼‚µ‚Ä‚­‚¾‚³‚¢",
+ est "Tabelil '%-.64s' puuduvad võtmed. Loo tabel uuesti"
+ fre "La table '%-.64s' n'a pas d'index comme celle utilisée dans CREATE INDEX. Recréez la table"
+ ger "Tabelle '%-.64s' besitzt keinen wie den in CREATE INDEX verwendeten Index. Index neu anlegen"
+ greek "Ï ðßíáêáò '%-.64s' äåí Ý÷åé åõñåôÞñéï (index) óáí áõôü ðïõ ÷ñçóéìïðïéåßôå óôçí CREATE INDEX. Ðáñáêáëþ, îáíáäçìéïõñãÞóôå ôïí ðßíáêá"
+ hun "A(z) '%-.64s' tablahoz nincs meg a CREATE INDEX altal hasznalt index. Alakitsa at a tablat"
+ ita "La tabella '%-.64s' non ha nessun indice come quello specificatato dalla CREATE INDEX. Ricrea la tabella"
+ jpn "Table '%-.64s' ¤Ï¤½¤Î¤è¤¦¤Ê index ¤ò»ý¤Ã¤Æ¤¤¤Þ¤»¤ó(CREATE INDEX ¼Â¹Ô»þ¤Ë»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó). ¥Æ¡¼¥Ö¥ë¤òºî¤êľ¤·¤Æ¤¯¤À¤µ¤¤"
+ kor "Å×À̺í '%-.64s'´Â À妽º¸¦ ¸¸µéÁö ¾Ê¾Ò½À´Ï´Ù. alter Å×À̺í¸í·ÉÀ» ÀÌ¿ëÇÏ¿© Å×À̺íÀ» ¼öÁ¤Çϼ¼¿ä..."
+ nor "Tabellen '%-.64s' har ingen index som den som er brukt i CREATE INDEX. Gjenopprett tabellen"
+ norwegian-ny "Tabellen '%-.64s' har ingen index som den som er brukt i CREATE INDEX. Oprett tabellen på nytt"
+ pol "Tabela '%-.64s' nie ma indeksu takiego jak w CREATE INDEX. Stwórz tabelê"
+ por "Tabela '%-.64s' não possui um índice como o usado em CREATE INDEX. Recrie a tabela"
+ rum "Tabela '%-.64s' nu are un index ca acela folosit in CREATE INDEX. Re-creeaza tabela"
+ rus "÷ ÔÁÂÌÉÃÅ '%-.64s' ÎÅÔ ÔÁËÏÇÏ ÉÎÄÅËÓÁ, ËÁË × CREATE INDEX. óÏÚÄÁÊÔÅ ÔÁÂÌÉÃÕ ÚÁÎÏ×Ï"
+ serbian "Tabela '%-.64s' nema isti indeks kao onaj upotrebljen pri komandi 'CREATE INDEX'. Napravite tabelu ponovo"
+ slo "Tabuµka '%-.64s' nemá index zodpovedajúci CREATE INDEX. Vytvorte tabulku znova"
+ spa "La tabla '%-.64s' no tiene indice como el usado en CREATE INDEX. Crea de nuevo la tabla"
+ swe "Tabellen '%-.64s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen"
+ ukr "ôÁÂÌÉÃÑ '%-.64s' ÍÁ¤ ¦ÎÄÅËÓ, ÝÏ ÎÅ ÓЦ×ÐÁÄÁ¤ Ú ×ËÁÚÁÎÎÉÍ Õ CREATE INDEX. óÔ×ÏÒ¦ÔØ ÔÁÂÌÉÃÀ ÚÎÏ×Õ"
+ER_WRONG_FIELD_TERMINATORS 42000 S1009
+ cze "Argument separ-Bátoru polo¾ek nebyl oèekáván. Pøeètìte si manuál"
+ dan "Felt adskiller er ikke som forventet, se dokumentationen"
+ nla "De argumenten om velden te scheiden zijn anders dan verwacht. Raadpleeg de handleiding"
+ eng "Field separator argument is not what is expected; check the manual"
+ est "Väljade eraldaja erineb oodatust. Tutvu kasutajajuhendiga"
+ fre "Séparateur de champs inconnu. Vérifiez dans le manuel"
+ ger "Feldbegrenzer-Argument ist nicht in der erwarteten Form. Bitte im Handbuch nachlesen"
+ greek "Ï äéá÷ùñéóôÞò ðåäßùí äåí åßíáé áõôüò ðïõ áíáìåíüôáí. Ðáñáêáëþ áíáôñÝîôå óôï manual"
+ hun "A mezoelvalaszto argumentumok nem egyeznek meg a varttal. Nezze meg a kezikonyvben!"
+ ita "L'argomento 'Field separator' non e` quello atteso. Controlla il manuale"
+ kor "ÇÊµå ±¸ºÐÀÚ ÀμöµéÀÌ ¿ÏÀüÇÏÁö ¾Ê½À´Ï´Ù. ¸Þ´º¾óÀ» ã¾Æ º¸¼¼¿ä."
+ nor "Felt skiller argumentene er ikke som forventet, se dokumentasjonen"
+ norwegian-ny "Felt skiljer argumenta er ikkje som venta, sjå dokumentasjonen"
+ pol "Nie oczekiwano separatora. Sprawd¥ podrêcznik"
+ por "Argumento separador de campos não é o esperado. Cheque o manual"
+ rum "Argumentul pentru separatorul de cimpuri este diferit de ce ma asteptam. Verifica manualul"
+ rus "áÒÇÕÍÅÎÔ ÒÁÚÄÅÌÉÔÅÌÑ ÐÏÌÅÊ - ÎÅ ÔÏÔ, ËÏÔÏÒÙÊ ÏÖÉÄÁÌÓÑ. ïÂÒÁÝÁÊÔÅÓØ Ë ÄÏËÕÍÅÎÔÁÃÉÉ"
+ serbian "Argument separatora polja nije ono što se oèekivalo. Proverite uputstvo MySQL server-a"
+ slo "Argument oddeµovaè polí nezodpovedá po¾iadavkám. Skontrolujte v manuáli"
+ spa "Los separadores de argumentos del campo no son los especificados. Comprueba el manual"
+ swe "Fältseparatorerna är vad som förväntades. Kontrollera mot manualen"
+ ukr "èÉÂÎÉÊ ÒÏÚĦÌÀ×ÁÞ ÐÏ̦×. ðÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ"
+ER_BLOBS_AND_NO_TERMINATED 42000 S1009
+ cze "Nen-Bí mo¾né pou¾ít pevný rowlength s BLOBem. Pou¾ijte 'fields terminated by'."
+ dan "Man kan ikke bruge faste feltlængder med BLOB. Brug i stedet 'fields terminated by'."
+ nla "Bij het gebruik van BLOBs is het niet mogelijk om vaste rijlengte te gebruiken. Maak s.v.p. gebruik van 'fields terminated by'."
+ eng "You can't use fixed rowlength with BLOBs; please use 'fields terminated by'"
+ est "BLOB-tüüpi väljade olemasolul ei saa kasutada fikseeritud väljapikkust. Vajalik 'fields terminated by' määrang."
+ fre "Vous ne pouvez utiliser des lignes de longueur fixe avec des BLOBs. Utiliser 'fields terminated by'."
+ ger "Eine feste Zeilenlänge kann für BLOB-Felder nicht verwendet werden. Bitte 'fields terminated by' verwenden"
+ greek "Äåí ìðïñåßôå íá ÷ñçóéìïðïéÞóåôå fixed rowlength óå BLOBs. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå 'fields terminated by'."
+ hun "Fix hosszusagu BLOB-ok nem hasznalhatok. Hasznalja a 'mezoelvalaszto jelet' ."
+ ita "Non possono essere usate righe a lunghezza fissa con i BLOB. Usa 'FIELDS TERMINATED BY'."
+ jpn "You can't use fixed rowlength with BLOBs; please use 'fields terminated by'."
+ kor "BLOB·Î´Â °íÁ¤±æÀÌÀÇ lowlength¸¦ »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù. 'fields terminated by'¸¦ »ç¿ëÇϼ¼¿ä."
+ nor "En kan ikke bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'."
+ norwegian-ny "Ein kan ikkje bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'."
+ pol "Nie mo¿na u¿yæ sta³ej d³ugo?ci wiersza z polami typu BLOB. U¿yj 'fields terminated by'."
+ por "Você não pode usar comprimento de linha fixo com BLOBs. Por favor, use campos com comprimento limitado."
+ rum "Nu poti folosi lungime de cimp fix pentru BLOB-uri. Foloseste 'fields terminated by'."
+ rus "æÉËÓÉÒÏ×ÁÎÎÙÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ Ó ÐÏÌÑÍÉ ÔÉÐÁ BLOB ÉÓÐÏÌØÚÏ×ÁÔØ ÎÅÌØÚÑ, ÐÒÉÍÅÎÑÊÔÅ 'fields terminated by'"
+ serbian "Ne možete koristiti fiksnu velièinu sloga kada imate BLOB polja. Molim koristite 'fields terminated by' opciju."
+ slo "Nie je mo¾né pou¾i» fixnú då¾ku s BLOBom. Pou¾ite 'fields terminated by'."
+ spa "No puedes usar longitudes de filas fijos con BLOBs. Por favor usa 'campos terminados por '."
+ swe "Man kan inte använda fast radlängd med blobs. Använd 'fields terminated by'"
+ ukr "îÅ ÍÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÓÔÁÌÕ ÄÏ×ÖÉÎÕ ÓÔÒÏËÉ Ú BLOB. úËÏÒÉÓÔÁÊÔÅÓÑ 'fields terminated by'"
+ER_TEXTFILE_NOT_READABLE
+ cze "Soubor '%-.64s' mus-Bí být v adresáøi databáze nebo èitelný pro v¹echny"
+ dan "Filen '%-.64s' skal være i database-folderen og kunne læses af alle"
+ nla "Het bestand '%-.64s' dient in de database directory voor the komen of leesbaar voor iedereen te zijn."
+ eng "The file '%-.64s' must be in the database directory or be readable by all"
+ jps "ƒtƒ@ƒCƒ‹ '%-.64s' ‚Í databse ‚Ì directory ‚É‚ ‚é‚©‘S‚Ẵ†[ƒU[‚ª“Ç‚ß‚é‚悤‚É‹–‰Â‚³‚ê‚Ä‚¢‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ.",
+ est "Fail '%-.64s' peab asuma andmebaasi kataloogis või olema kõigile loetav"
+ fre "Le fichier '%-.64s' doit être dans le répertoire de la base et lisible par tous"
+ ger "Datei '%-.64s' muss im Datenbank-Verzeichnis vorhanden und lesbar für alle sein"
+ greek "Ôï áñ÷åßï '%-.64s' ðñÝðåé íá õðÜñ÷åé óôï database directory Þ íá ìðïñåß íá äéáâáóôåß áðü üëïõò"
+ hun "A(z) '%-.64s'-nak az adatbazis konyvtarban kell lennie, vagy mindenki szamara olvashatonak"
+ ita "Il file '%-.64s' deve essere nella directory del database e deve essere leggibile da tutti"
+ jpn "¥Õ¥¡¥¤¥ë '%-.64s' ¤Ï databse ¤Î directory ¤Ë¤¢¤ë¤«Á´¤Æ¤Î¥æ¡¼¥¶¡¼¤¬Æɤá¤ë¤è¤¦¤Ëµö²Ä¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó."
+ kor "'%-.64s' È­ÀÏ´Â µ¥ÀÌŸº£À̽º µð·ºÅ丮¿¡ Á¸ÀçÇϰųª ¸ðµÎ¿¡°Ô Àб⠰¡´ÉÇÏ¿©¾ß ÇÕ´Ï´Ù."
+ nor "Filen '%-.64s' må være i database-katalogen for å være lesbar for alle"
+ norwegian-ny "Filen '%-.64s' må være i database-katalogen for å være lesbar for alle"
+ pol "Plik '%-.64s' musi znajdowaæ sie w katalogu bazy danych lub mieæ prawa czytania przez wszystkich"
+ por "Arquivo '%-.64s' tem que estar no diretório do banco de dados ou ter leitura possível para todos"
+ rum "Fisierul '%-.64s' trebuie sa fie in directorul bazei de data sau trebuie sa poata sa fie citit de catre toata lumea (verifica permisiile)"
+ rus "æÁÊÌ '%-.64s' ÄÏÌÖÅÎ ÎÁÈÏÄÉÔØÓÑ × ÔÏÍ ÖÅ ËÁÔÁÌÏÇÅ, ÞÔÏ É ÂÁÚÁ ÄÁÎÎÙÈ, ÉÌÉ ÂÙÔØ ÏÂÝÅÄÏÓÔÕÐÎÙÍ ÄÌÑ ÞÔÅÎÉÑ"
+ serbian "File '%-.64s' mora biti u direktorijumu gde su file-ovi baze i mora imati odgovarajuæa prava pristupa"
+ slo "Súbor '%-.64s' musí by» v adresári databázy, alebo èitateµný pre v¹etkých"
+ spa "El archivo '%-.64s' debe estar en el directorio de la base de datos o ser de lectura por todos"
+ swe "Textfilen '%.64s' måste finnas i databasbiblioteket eller vara läsbar för alla"
+ ukr "æÁÊÌ '%-.64s' ÐÏ×ÉÎÅÎ ÂÕÔÉ Õ ÔÅæ ÂÁÚÉ ÄÁÎÎÉÈ ÁÂÏ ÍÁÔÉ ×ÓÔÁÎÏ×ÌÅÎÅ ÐÒÁ×Ï ÎÁ ÞÉÔÁÎÎÑ ÄÌÑ ÕÓ¦È"
+ER_FILE_EXISTS_ERROR
+ cze "Soubor '%-.64s' ji-B¾ existuje"
+ dan "Filen '%-.64s' eksisterer allerede"
+ nla "Het bestand '%-.64s' bestaat reeds"
+ eng "File '%-.80s' already exists"
+ jps "File '%-.64s' ‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·",
+ est "Fail '%-.80s' juba eksisteerib"
+ fre "Le fichier '%-.64s' existe déjà"
+ ger "Datei '%-.64s' bereits vorhanden"
+ greek "Ôï áñ÷åßï '%-.64s' õðÜñ÷åé Þäç"
+ hun "A '%-.64s' file mar letezik."
+ ita "Il file '%-.64s' esiste gia`"
+ jpn "File '%-.64s' ¤Ï´û¤Ë¸ºß¤·¤Þ¤¹"
+ kor "'%-.64s' È­ÀÏÀº ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù."
+ nor "Filen '%-.64s' eksisterte allerede"
+ norwegian-ny "Filen '%-.64s' eksisterte allereide"
+ pol "Plik '%-.64s' ju¿ istnieje"
+ por "Arquivo '%-.80s' já existe"
+ rum "Fisierul '%-.80s' exista deja"
+ rus "æÁÊÌ '%-.80s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "File '%-.80s' veæ postoji"
+ slo "Súbor '%-.64s' u¾ existuje"
+ spa "El archivo '%-.64s' ya existe"
+ swe "Filen '%-.64s' existerar redan"
+ ukr "æÁÊÌ '%-.80s' ×ÖÅ ¦ÓÎÕ¤"
+ER_LOAD_INFO
+ cze "Z-Báznamù: %ld Vymazáno: %ld Pøeskoèeno: %ld Varování: %ld"
+ dan "Poster: %ld Fjernet: %ld Sprunget over: %ld Advarsler: %ld"
+ nla "Records: %ld Verwijderd: %ld Overgeslagen: %ld Waarschuwingen: %ld"
+ eng "Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld"
+ jps "ƒŒƒR[ƒh”: %ld íœ: %ld Skipped: %ld Warnings: %ld",
+ est "Kirjeid: %ld Kustutatud: %ld Vahele jäetud: %ld Hoiatusi: %ld"
+ fre "Enregistrements: %ld Effacés: %ld Non traités: %ld Avertissements: %ld"
+ ger "Datensätze: %ld Gelöscht: %ld Ausgelassen: %ld Warnungen: %ld"
+ greek "ÅããñáöÝò: %ld ÄéáãñáöÝò: %ld ÐáñåêÜìöèçóáí: %ld ÐñïåéäïðïéÞóåéò: %ld"
+ hun "Rekordok: %ld Torolve: %ld Skipped: %ld Warnings: %ld"
+ ita "Records: %ld Cancellati: %ld Saltati: %ld Avvertimenti: %ld"
+ jpn "¥ì¥³¡¼¥É¿ô: %ld ºï½ü: %ld Skipped: %ld Warnings: %ld"
+ kor "·¹ÄÚµå: %ld°³ »èÁ¦: %ld°³ ½ºÅµ: %ld°³ °æ°í: %ld°³"
+ nor "Poster: %ld Fjernet: %ld Hoppet over: %ld Advarsler: %ld"
+ norwegian-ny "Poster: %ld Fjerna: %ld Hoppa over: %ld Åtvaringar: %ld"
+ pol "Recordów: %ld Usuniêtych: %ld Pominiêtych: %ld Ostrze¿eñ: %ld"
+ por "Registros: %ld - Deletados: %ld - Ignorados: %ld - Avisos: %ld"
+ rum "Recorduri: %ld Sterse: %ld Sarite (skipped): %ld Atentionari (warnings): %ld"
+ rus "úÁÐÉÓÅÊ: %ld õÄÁÌÅÎÏ: %ld ðÒÏÐÕÝÅÎÏ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld"
+ serbian "Slogova: %ld Izbrisano: %ld Preskoèeno: %ld Upozorenja: %ld"
+ slo "Záznamov: %ld Zmazaných: %ld Preskoèených: %ld Varovania: %ld"
+ spa "Registros: %ld Borrados: %ld Saltados: %ld Peligros: %ld"
+ swe "Rader: %ld Bortagna: %ld Dubletter: %ld Varningar: %ld"
+ ukr "úÁÐÉÓ¦×: %ld ÷ÉÄÁÌÅÎÏ: %ld ðÒÏÐÕÝÅÎÏ: %ld úÁÓÔÅÒÅÖÅÎØ: %ld"
+ER_ALTER_INFO
+ cze "Z-Báznamù: %ld Zdvojených: %ld"
+ dan "Poster: %ld Ens: %ld"
+ nla "Records: %ld Dubbel: %ld"
+ eng "Records: %ld Duplicates: %ld"
+ jps "ƒŒƒR[ƒh”: %ld d•¡: %ld",
+ est "Kirjeid: %ld Kattuvaid: %ld"
+ fre "Enregistrements: %ld Doublons: %ld"
+ ger "Datensätze: %ld Duplikate: %ld"
+ greek "ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld"
+ hun "Rekordok: %ld Duplikalva: %ld"
+ ita "Records: %ld Duplicati: %ld"
+ jpn "¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£: %ld"
+ kor "·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³"
+ nor "Poster: %ld Like: %ld"
+ norwegian-ny "Poster: %ld Like: %ld"
+ pol "Rekordów: %ld Duplikatów: %ld"
+ por "Registros: %ld - Duplicados: %ld"
+ rum "Recorduri: %ld Duplicate: %ld"
+ rus "úÁÐÉÓÅÊ: %ld äÕÂÌÉËÁÔÏ×: %ld"
+ serbian "Slogova: %ld Duplikata: %ld"
+ slo "Záznamov: %ld Opakovaných: %ld"
+ spa "Registros: %ld Duplicados: %ld"
+ swe "Rader: %ld Dubletter: %ld"
+ ukr "úÁÐÉÓ¦×: %ld äÕÂ̦ËÁÔ¦×: %ld"
+ER_WRONG_SUB_KEY
+ cze "Chybn-Bá podèást klíèe -- není to øetìzec nebo je del¹í ne¾ délka èásti klíèe"
+ dan "Forkert indeksdel. Den anvendte nøgledel er ikke en streng eller længden er større end nøglelængden"
+ nla "Foutief sub-gedeelte van de zoeksleutel. De gebruikte zoeksleutel is geen onderdeel van een string of of de gebruikte lengte is langer dan de zoeksleutel"
+ eng "Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys"
+ est "Vigane võtme osa. Kasutatud võtmeosa ei ole string tüüpi, määratud pikkus on pikem kui võtmeosa või tabelihandler ei toeta seda tüüpi võtmeid"
+ fre "Mauvaise sous-clef. Ce n'est pas un 'string' ou la longueur dépasse celle définie dans la clef"
+ ger "Falscher Unterteilschlüssel. Der verwendete Schlüsselteil ist entweder kein String, die verwendete Länge ist länger als der Teilschlüssel oder der Tabellenhandler unterstützt keine Unterteilschlüssel"
+ greek "ÅóöáëìÝíï sub part key. Ôï ÷ñçóéìïðïéïýìåíï key part äåí åßíáé string Þ ôï ìÞêïò ôïõ åßíáé ìåãáëýôåñï"
+ hun "Rossz alkulcs. A hasznalt kulcsresz nem karaktersorozat vagy hosszabb, mint a kulcsresz"
+ ita "Sotto-parte della chiave errata. La parte di chiave utilizzata non e` una stringa o la lunghezza e` maggiore della parte di chiave."
+ jpn "Incorrect sub part key; the used key part isn't a string or the used length is longer than the key part"
+ kor "ºÎÁ¤È®ÇÑ ¼­¹ö ÆÄÆ® Å°. »ç¿ëµÈ Å° ÆÄÆ®°¡ ½ºÆ®¸µÀÌ ¾Æ´Ï°Å³ª Å° ÆÄÆ®ÀÇ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù."
+ nor "Feil delnøkkel. Den brukte delnøkkelen er ikke en streng eller den oppgitte lengde er lengre enn nøkkel lengden"
+ norwegian-ny "Feil delnykkel. Den brukte delnykkelen er ikkje ein streng eller den oppgitte lengda er lengre enn nykkellengden"
+ pol "B³êdna podczê?æ klucza. U¿yta czê?æ klucza nie jest ³añcuchem lub u¿yta d³ugo?æ jest wiêksza ni¿ czê?æ klucza"
+ por "Sub parte da chave incorreta. A parte da chave usada não é uma 'string' ou o comprimento usado é maior que parte da chave ou o manipulador de tabelas não suporta sub chaves únicas"
+ rum "Componentul cheii este incorrect. Componentul folosit al cheii nu este un sir sau lungimea folosita este mai lunga decit lungimea cheii"
+ rus "îÅËÏÒÒÅËÔÎÁÑ ÞÁÓÔØ ËÌÀÞÁ. éÓÐÏÌØÚÕÅÍÁÑ ÞÁÓÔØ ËÌÀÞÁ ÎÅ Ñ×ÌÑÅÔÓÑ ÓÔÒÏËÏÊ, ÕËÁÚÁÎÎÁÑ ÄÌÉÎÁ ÂÏÌØÛÅ, ÞÅÍ ÄÌÉÎÁ ÞÁÓÔÉ ËÌÀÞÁ, ÉÌÉ ÏÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÕÎÉËÁÌØÎÙÅ ÞÁÓÔÉ ËÌÀÞÁ"
+ serbian "Pogrešan pod-kljuè dela kljuèa. Upotrebljeni deo kljuèa nije string, upotrebljena dužina je veæa od dela kljuèa ili handler tabela ne podržava jedinstvene pod-kljuèeve"
+ slo "Incorrect sub part key; the used key part isn't a string or the used length is longer than the key part"
+ spa "Parte de la clave es erronea. Una parte de la clave no es una cadena o la longitud usada es tan grande como la parte de la clave"
+ swe "Felaktig delnyckel. Nyckeldelen är inte en sträng eller den angivna längden är längre än kolumnlängden"
+ ukr "îÅצÒÎÁ ÞÁÓÔÉÎÁ ËÌÀÞÁ. ÷ÉËÏÒÉÓÔÁÎÁ ÞÁÓÔÉÎÁ ËÌÀÞÁ ÎÅ ¤ ÓÔÒÏËÏÀ, ÚÁÄÏ×ÇÁ ÁÂÏ ×ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ ÕΦËÁÌØÎÉÈ ÞÁÓÔÉÎ ËÌÀÞÅÊ"
+ER_CANT_REMOVE_ALL_FIELDS 42000
+ cze "Nen-Bí mo¾né vymazat v¹echny polo¾ky s ALTER TABLE. Pou¾ijte DROP TABLE"
+ dan "Man kan ikke slette alle felter med ALTER TABLE. Brug DROP TABLE i stedet."
+ nla "Het is niet mogelijk alle velden te verwijderen met ALTER TABLE. Gebruik a.u.b. DROP TABLE hiervoor!"
+ eng "You can't delete all columns with ALTER TABLE; use DROP TABLE instead"
+ jps "ALTER TABLE ‚Å‘S‚Ä‚Ì column ‚Í휂ł«‚Ü‚¹‚ñ. DROP TABLE ‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢",
+ est "ALTER TABLE kasutades ei saa kustutada kõiki tulpasid. Kustuta tabel DROP TABLE abil"
+ fre "Vous ne pouvez effacer tous les champs avec ALTER TABLE. Utilisez DROP TABLE"
+ ger "Mit ALTER TABLE können nicht alle Felder auf einmal gelöscht werden. Dafür DROP TABLE verwenden"
+ greek "Äåí åßíáé äõíáôÞ ç äéáãñáöÞ üëùí ôùí ðåäßùí ìå ALTER TABLE. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå DROP TABLE"
+ hun "Az osszes mezo nem torolheto az ALTER TABLE-lel. Hasznalja a DROP TABLE-t helyette"
+ ita "Non si possono cancellare tutti i campi con una ALTER TABLE. Utilizzare DROP TABLE"
+ jpn "ALTER TABLE ¤ÇÁ´¤Æ¤Î column ¤Ïºï½ü¤Ç¤­¤Þ¤»¤ó. DROP TABLE ¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤"
+ kor "ALTER TABLE ¸í·ÉÀ¸·Î´Â ¸ðµç Ä®·³À» Áö¿ï ¼ö ¾ø½À´Ï´Ù. DROP TABLE ¸í·ÉÀ» ÀÌ¿ëÇϼ¼¿ä."
+ nor "En kan ikke slette alle felt med ALTER TABLE. Bruk DROP TABLE isteden."
+ norwegian-ny "Ein kan ikkje slette alle felt med ALTER TABLE. Bruk DROP TABLE istadenfor."
+ pol "Nie mo¿na usun?æ wszystkich pól wykorzystuj?c ALTER TABLE. W zamian u¿yj DROP TABLE"
+ por "Você não pode deletar todas as colunas com ALTER TABLE; use DROP TABLE em seu lugar"
+ rum "Nu poti sterge toate coloanele cu ALTER TABLE. Foloseste DROP TABLE in schimb"
+ rus "îÅÌØÚÑ ÕÄÁÌÉÔØ ×ÓÅ ÓÔÏÌÂÃÙ Ó ÐÏÍÏÝØÀ ALTER TABLE. éÓÐÏÌØÚÕÊÔÅ DROP TABLE"
+ serbian "Ne možete da izbrišete sve kolone pomoæu komande 'ALTER TABLE'. Upotrebite komandu 'DROP TABLE' ako želite to da uradite"
+ slo "One nemô¾em zmaza» all fields with ALTER TABLE; use DROP TABLE instead"
+ spa "No puede borrar todos los campos con ALTER TABLE. Usa DROP TABLE para hacerlo"
+ swe "Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället"
+ ukr "îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ×Ó¦ ÓÔÏ×Âæ ÚÁ ÄÏÐÏÍÏÇÏÀ ALTER TABLE. äÌÑ ÃØÏÇÏ ÓËÏÒÉÓÔÁÊÔÅÓÑ DROP TABLE"
+ER_CANT_DROP_FIELD_OR_KEY 42000
+ cze "Nemohu zru-B¹it '%-.64s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe"
+ dan "Kan ikke udføre DROP '%-.64s'. Undersøg om feltet/nøglen eksisterer."
+ nla "Kan '%-.64s' niet weggooien. Controleer of het veld of de zoeksleutel daadwerkelijk bestaat."
+ eng "Can't DROP '%-.64s'; check that column/key exists"
+ jps "'%-.64s' ‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½; check that column/key exists",
+ est "Ei suuda kustutada '%-.64s'. Kontrolli kas tulp/võti eksisteerib"
+ fre "Ne peut effacer (DROP) '%-.64s'. Vérifiez s'il existe"
+ ger "Kann '%-.64s' nicht löschen. Existiert das Feld / der Schlüssel?"
+ greek "Áäýíáôç ç äéáãñáöÞ (DROP) '%-.64s'. Ðáñáêáëþ åëÝãîôå áí ôï ðåäßï/êëåéäß õðÜñ÷åé"
+ hun "A DROP '%-.64s' nem lehetseges. Ellenorizze, hogy a mezo/kulcs letezik-e"
+ ita "Impossibile cancellare '%-.64s'. Controllare che il campo chiave esista"
+ jpn "'%-.64s' ¤òÇË´þ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿; check that column/key exists"
+ kor "'%-.64s'¸¦ DROPÇÒ ¼ö ¾ø½À´Ï´Ù. Ä®·³À̳ª Å°°¡ Á¸ÀçÇÏ´ÂÁö äũÇϼ¼¿ä."
+ nor "Kan ikke DROP '%-.64s'. Undersøk om felt/nøkkel eksisterer."
+ norwegian-ny "Kan ikkje DROP '%-.64s'. Undersøk om felt/nøkkel eksisterar."
+ pol "Nie mo¿na wykonaæ operacji DROP '%-.64s'. Sprawd¥, czy to pole/klucz istnieje"
+ por "Não se pode fazer DROP '%-.64s'. Confira se esta coluna/chave existe"
+ rum "Nu pot sa DROP '%-.64s'. Verifica daca coloana/cheia exista"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ (DROP) '%-.64s'. õÂÅÄÉÔÅÓØ ÞÔÏ ÓÔÏÌÂÅÃ/ËÌÀÞ ÄÅÊÓÔ×ÉÔÅÌØÎÏ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Ne mogu da izvršim komandu drop 'DROP' na '%-.64s'. Proverite da li ta kolona (odnosno kljuè) postoji"
+ slo "Nemô¾em zru¹i» (DROP) '%-.64s'. Skontrolujte, èi neexistujú záznamy/kµúèe"
+ spa "No puedo ELIMINAR '%-.64s'. compuebe que el campo/clave existe"
+ swe "Kan inte ta bort '%-.64s'. Kontrollera att fältet/nyckel finns"
+ ukr "îÅ ÍÏÖÕ DROP '%-.64s'. ðÅÒÅצÒÔÅ, ÞÉ ÃÅÊ ÓÔÏ×ÂÅÃØ/ËÌÀÞ ¦ÓÎÕ¤"
+ER_INSERT_INFO
+ cze "Z-Báznamù: %ld Zdvojených: %ld Varování: %ld"
+ dan "Poster: %ld Ens: %ld Advarsler: %ld"
+ nla "Records: %ld Dubbel: %ld Waarschuwing: %ld"
+ eng "Records: %ld Duplicates: %ld Warnings: %ld"
+ jps "ƒŒƒR[ƒh”: %ld d•¡”: %ld Warnings: %ld",
+ est "Kirjeid: %ld Kattuvaid: %ld Hoiatusi: %ld"
+ fre "Enregistrements: %ld Doublons: %ld Avertissements: %ld"
+ ger "Datensätze: %ld Duplikate: %ld Warnungen: %ld"
+ greek "ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld ÐñïåéäïðïéÞóåéò: %ld"
+ hun "Rekordok: %ld Duplikalva: %ld Warnings: %ld"
+ ita "Records: %ld Duplicati: %ld Avvertimenti: %ld"
+ jpn "¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£¿ô: %ld Warnings: %ld"
+ kor "·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³ °æ°í: %ld°³"
+ nor "Poster: %ld Like: %ld Advarsler: %ld"
+ norwegian-ny "Postar: %ld Like: %ld Åtvaringar: %ld"
+ pol "Rekordów: %ld Duplikatów: %ld Ostrze¿eñ: %ld"
+ por "Registros: %ld - Duplicados: %ld - Avisos: %ld"
+ rum "Recorduri: %ld Duplicate: %ld Atentionari (warnings): %ld"
+ rus "úÁÐÉÓÅÊ: %ld äÕÂÌÉËÁÔÏ×: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld"
+ serbian "Slogova: %ld Duplikata: %ld Upozorenja: %ld"
+ slo "Záznamov: %ld Opakovaných: %ld Varovania: %ld"
+ spa "Registros: %ld Duplicados: %ld Peligros: %ld"
+ swe "Rader: %ld Dubletter: %ld Varningar: %ld"
+ ukr "úÁÐÉÓ¦×: %ld äÕÂ̦ËÁÔ¦×: %ld úÁÓÔÅÒÅÖÅÎØ: %ld"
+ER_UPDATE_TABLE_USED
+ eng "You can't specify target table '%-.64s' for update in FROM clause"
+ ger "Die Verwendung der zu aktualisierenden Zieltabelle '%-.64s' ist in der FROM-Klausel nicht zulässig."
+ rus "îÅ ÄÏÐÕÓËÁÅÔÓÑ ÕËÁÚÁÎÉÅ ÔÁÂÌÉÃÙ '%-.64s' × ÓÐÉÓËÅ ÔÁÂÌÉà FROM ÄÌÑ ×ÎÅÓÅÎÉÑ × ÎÅÅ ÉÚÍÅÎÅÎÉÊ"
+ swe "INSERT-table '%-.64s' får inte finnas i FROM tabell-listan"
+ ukr "ôÁÂÌÉÃÑ '%-.64s' ÝÏ ÚͦÎÀ¤ÔØÓÑ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ ÐÅÒÅ̦ËÕ ÔÁÂÌÉÃØ FROM"
+ER_NO_SUCH_THREAD
+ cze "Nezn-Bámá identifikace threadu: %lu"
+ dan "Ukendt tråd id: %lu"
+ nla "Onbekend thread id: %lu"
+ eng "Unknown thread id: %lu"
+ jps "thread id: %lu ‚Í‚ ‚è‚Ü‚¹‚ñ",
+ est "Tundmatu lõim: %lu"
+ fre "Numéro de tâche inconnu: %lu"
+ ger "Unbekannte Thread-ID: %lu"
+ greek "Áãíùóôï thread id: %lu"
+ hun "Ervenytelen szal (thread) id: %lu"
+ ita "Thread id: %lu sconosciuto"
+ jpn "thread id: %lu ¤Ï¤¢¤ê¤Þ¤»¤ó"
+ kor "¾Ë¼ö ¾ø´Â ¾²·¹µå id: %lu"
+ nor "Ukjent tråd id: %lu"
+ norwegian-ny "Ukjent tråd id: %lu"
+ pol "Nieznany identyfikator w?tku: %lu"
+ por "'Id' de 'thread' %lu desconhecido"
+ rum "Id-ul: %lu thread-ului este necunoscut"
+ rus "îÅÉÚ×ÅÓÔÎÙÊ ÎÏÍÅÒ ÐÏÔÏËÁ: %lu"
+ serbian "Nepoznat thread identifikator: %lu"
+ slo "Neznáma identifikácia vlákna: %lu"
+ spa "Identificador del thread: %lu desconocido"
+ swe "Finns ingen tråd med id %lu"
+ ukr "îÅצÄÏÍÉÊ ¦ÄÅÎÔÉƦËÁÔÏÒ Ç¦ÌËÉ: %lu"
+ER_KILL_DENIED_ERROR
+ cze "Nejste vlastn-Bíkem threadu %lu"
+ dan "Du er ikke ejer af tråden %lu"
+ nla "U bent geen bezitter van thread %lu"
+ eng "You are not owner of thread %lu"
+ jps "thread %lu ‚̃I[ƒi[‚Å‚Í‚ ‚è‚Ü‚¹‚ñ",
+ est "Ei ole lõime %lu omanik"
+ fre "Vous n'êtes pas propriétaire de la tâche no: %lu"
+ ger "Sie sind nicht Eigentümer von Thread %lu"
+ greek "Äåí åßóèå owner ôïõ thread %lu"
+ hun "A %lu thread-nek mas a tulajdonosa"
+ ita "Utente non proprietario del thread %lu"
+ jpn "thread %lu ¤Î¥ª¡¼¥Ê¡¼¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+ kor "¾²·¹µå(Thread) %luÀÇ ¼ÒÀ¯ÀÚ°¡ ¾Æ´Õ´Ï´Ù."
+ nor "Du er ikke eier av tråden %lu"
+ norwegian-ny "Du er ikkje eigar av tråd %lu"
+ pol "Nie jeste? w³a?cicielem w?tku %lu"
+ por "Você não é proprietário da 'thread' %lu"
+ rum "Nu sinteti proprietarul threadului %lu"
+ rus "÷Ù ÎÅ Ñ×ÌÑÅÔÅÓØ ×ÌÁÄÅÌØÃÅÍ ÐÏÔÏËÁ %lu"
+ serbian "Vi niste vlasnik thread-a %lu"
+ slo "Nie ste vlastníkom vlákna %lu"
+ spa "Tu no eres el propietario del thread%lu"
+ swe "Du är inte ägare till tråd %lu"
+ ukr "÷É ÎÅ ×ÏÌÏÄÁÒ Ç¦ÌËÉ %lu"
+ER_NO_TABLES_USED
+ cze "Nejsou pou-B¾ity ¾ádné tabulky"
+ dan "Ingen tabeller i brug"
+ nla "Geen tabellen gebruikt."
+ eng "No tables used"
+ est "Ühtegi tabelit pole kasutusel"
+ fre "Aucune table utilisée"
+ ger "Keine Tabellen verwendet"
+ greek "Äåí ÷ñçóéìïðïéÞèçêáí ðßíáêåò"
+ hun "Nincs hasznalt tabla"
+ ita "Nessuna tabella usata"
+ kor "¾î¶² Å×ÀÌºíµµ »ç¿ëµÇÁö ¾Ê¾Ò½À´Ï´Ù."
+ nor "Ingen tabeller i bruk"
+ norwegian-ny "Ingen tabellar i bruk"
+ pol "Nie ma ¿adej u¿ytej tabeli"
+ por "Nenhuma tabela usada"
+ rum "Nici o tabela folosita"
+ rus "îÉËÁËÉÅ ÔÁÂÌÉÃÙ ÎÅ ÉÓÐÏÌØÚÏ×ÁÎÙ"
+ serbian "Nema upotrebljenih tabela"
+ slo "Nie je pou¾itá ¾iadna tabuµka"
+ spa "No ha tablas usadas"
+ swe "Inga tabeller angivna"
+ ukr "îÅ ×ÉËÏÒÉÓÔÁÎÏ ÔÁÂÌÉÃØ"
+ER_TOO_BIG_SET
+ cze "P-Bøíli¹ mnoho øetìzcù pro sloupec %s a SET"
+ dan "For mange tekststrenge til specifikationen af SET i kolonne %-.64s"
+ nla "Teveel strings voor kolom %s en SET"
+ eng "Too many strings for column %-.64s and SET"
+ est "Liiga palju string tulbale %-.64s tüübile SET"
+ fre "Trop de chaînes dans la colonne %s avec SET"
+ ger "Zu viele Strings für SET-Spalte %-.64s angegeben"
+ greek "ÐÜñá ðïëëÜ strings ãéá ôï ðåäßï %-.64s êáé SET"
+ hun "Tul sok karakter: %-.64s es SET"
+ ita "Troppe stringhe per la colonna %-.64s e la SET"
+ kor "Ä®·³ %-.64s¿Í SET¿¡¼­ ½ºÆ®¸µÀÌ ³Ê¹« ¸¹½À´Ï´Ù."
+ nor "For mange tekststrenger kolonne %s og SET"
+ norwegian-ny "For mange tekststrengar felt %s og SET"
+ pol "Zbyt wiele ³añcuchów dla kolumny %s i polecenia SET"
+ por "'Strings' demais para coluna '%-.64s' e SET"
+ rum "Prea multe siruri pentru coloana %-.64s si SET"
+ rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÚÎÁÞÅÎÉÊ ÄÌÑ ÓÔÏÌÂÃÁ %-.64s × SET"
+ serbian "Previše string-ova za kolonu '%-.64s' i komandu 'SET'"
+ slo "Príli¹ mnoho re»azcov pre pole %-.64s a SET"
+ spa "Muchas strings para columna %s y SET"
+ swe "För många alternativ till kolumn %s för SET"
+ ukr "úÁÂÁÇÁÔÏ ÓÔÒÏË ÄÌÑ ÓÔÏ×ÂÃÑ %-.64s ÔÁ SET"
+ER_NO_UNIQUE_LOGFILE
+ cze "Nemohu vytvo-Bøit jednoznaèné jméno logovacího souboru %s.(1-999)\n"
+ dan "Kan ikke lave unikt log-filnavn %s.(1-999)\n"
+ nla "Het is niet mogelijk een unieke naam te maken voor de logfile %s.(1-999)\n"
+ eng "Can't generate a unique log-filename %-.64s.(1-999)\n"
+ est "Ei suuda luua unikaalset logifaili nime %-.64s.(1-999)\n"
+ fre "Ne peut générer un unique nom de journal %s.(1-999)\n"
+ ger "Kann keinen eindeutigen Dateinamen für die Logdatei %-.64s erzeugen (1-999)\n"
+ greek "Áäýíáôç ç äçìéïõñãßá unique log-filename %-.64s.(1-999)\n"
+ hun "Egyedi log-filenev nem generalhato: %-.64s.(1-999)\n"
+ ita "Impossibile generare un nome del file log unico %-.64s.(1-999)\n"
+ kor "Unique ·Î±×È­ÀÏ '%-.64s'¸¦ ¸¸µé¼ö ¾ø½À´Ï´Ù.(1-999)\n"
+ nor "Kan ikke lage unikt loggfilnavn %s.(1-999)\n"
+ norwegian-ny "Kan ikkje lage unikt loggfilnavn %s.(1-999)\n"
+ pol "Nie mo¿na stworzyæ unikalnej nazwy pliku z logiem %s.(1-999)\n"
+ por "Não pode gerar um nome de arquivo de 'log' único '%-.64s'.(1-999)\n"
+ rum "Nu pot sa generez un nume de log unic %-.64s.(1-999)\n"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÕÎÉËÁÌØÎÏÅ ÉÍÑ ÆÁÊÌÁ ÖÕÒÎÁÌÁ %-.64s.(1-999)\n"
+ serbian "Ne mogu da generišem jedinstveno ime log-file-a: '%-.64s.(1-999)'\n"
+ slo "Nemô¾em vytvori» unikátne meno log-súboru %-.64s.(1-999)\n"
+ spa "No puede crear un unico archivo log %s.(1-999)\n"
+ swe "Kan inte generera ett unikt filnamn %s.(1-999)\n"
+ ukr "îÅ ÍÏÖÕ ÚÇÅÎÅÒÕ×ÁÔÉ ÕΦËÁÌØÎÅ ¦Í'Ñ log-ÆÁÊÌÕ %-.64s.(1-999)\n"
+ER_TABLE_NOT_LOCKED_FOR_WRITE
+ cze "Tabulka '%-.64s' byla zam-Bèena s READ a nemù¾e být zmìnìna"
+ dan "Tabellen '%-.64s' var låst med READ lås og kan ikke opdateres"
+ nla "Tabel '%-.64s' was gelocked met een lock om te lezen. Derhalve kunnen geen wijzigingen worden opgeslagen."
+ eng "Table '%-.64s' was locked with a READ lock and can't be updated"
+ jps "Table '%-.64s' ‚Í READ lock ‚É‚È‚Á‚Ä‚¢‚ÄAXV‚Í‚Å‚«‚Ü‚¹‚ñ",
+ est "Tabel '%-.64s' on lukustatud READ lukuga ning ei ole muudetav"
+ fre "Table '%-.64s' verrouillée lecture (READ): modification impossible"
+ ger "Tabelle '%-.64s' ist mit Lesesperre versehen und kann nicht aktualisiert werden"
+ greek "Ï ðßíáêáò '%-.64s' Ý÷åé êëåéäùèåß ìå READ lock êáé äåí åðéôñÝðïíôáé áëëáãÝò"
+ hun "A(z) '%-.64s' tabla zarolva lett (READ lock) es nem lehet frissiteni"
+ ita "La tabella '%-.64s' e` soggetta a lock in lettura e non puo` essere aggiornata"
+ jpn "Table '%-.64s' ¤Ï READ lock ¤Ë¤Ê¤Ã¤Æ¤¤¤Æ¡¢¹¹¿·¤Ï¤Ç¤­¤Þ¤»¤ó"
+ kor "Å×À̺í '%-.64s'´Â READ ¶ôÀÌ Àá°ÜÀ־ °»½ÅÇÒ ¼ö ¾ø½À´Ï´Ù."
+ nor "Tabellen '%-.64s' var låst med READ lås og kan ikke oppdateres"
+ norwegian-ny "Tabellen '%-.64s' var låst med READ lås og kan ikkje oppdaterast"
+ pol "Tabela '%-.64s' zosta³a zablokowana przez READ i nie mo¿e zostaæ zaktualizowana"
+ por "Tabela '%-.64s' foi travada com trava de leitura e não pode ser atualizada"
+ rum "Tabela '%-.64s' a fost locked cu un READ lock si nu poate fi actualizata"
+ rus "ôÁÂÌÉÃÁ '%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎÁ ÕÒÏ×ÎÅÍ READ lock É ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÚÍÅÎÅÎÁ"
+ serbian "Tabela '%-.64s' je zakljuèana READ lock-om; iz nje se može samo èitati ali u nju se ne može pisati"
+ slo "Tabuµka '%-.64s' bola zamknutá s READ a nemô¾e by» zmenená"
+ spa "Tabla '%-.64s' fue trabada con un READ lock y no puede ser actualizada"
+ swe "Tabell '%-.64s' kan inte uppdateras emedan den är låst för läsning"
+ ukr "ôÁÂÌÉÃÀ '%-.64s' ÚÁÂÌÏËÏ×ÁÎÏ Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ, ÔÏÍÕ §§ ÎÅ ÍÏÖÎÁ ÏÎÏ×ÉÔÉ"
+ER_TABLE_NOT_LOCKED
+ cze "Tabulka '%-.64s' nebyla zam-Bèena s LOCK TABLES"
+ dan "Tabellen '%-.64s' var ikke låst med LOCK TABLES"
+ nla "Tabel '%-.64s' was niet gelocked met LOCK TABLES"
+ eng "Table '%-.64s' was not locked with LOCK TABLES"
+ jps "Table '%-.64s' ‚Í LOCK TABLES ‚É‚æ‚Á‚ăƒbƒN‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Tabel '%-.64s' ei ole lukustatud käsuga LOCK TABLES"
+ fre "Table '%-.64s' non verrouillée: utilisez LOCK TABLES"
+ ger "Tabelle '%-.64s' wurde nicht mit LOCK TABLES gesperrt"
+ greek "Ï ðßíáêáò '%-.64s' äåí Ý÷åé êëåéäùèåß ìå LOCK TABLES"
+ hun "A(z) '%-.64s' tabla nincs zarolva a LOCK TABLES-szel"
+ ita "Non e` stato impostato il lock per la tabella '%-.64s' con LOCK TABLES"
+ jpn "Table '%-.64s' ¤Ï LOCK TABLES ¤Ë¤è¤Ã¤Æ¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "Å×À̺í '%-.64s'´Â LOCK TABLES ¸í·ÉÀ¸·Î Àá±âÁö ¾Ê¾Ò½À´Ï´Ù."
+ nor "Tabellen '%-.64s' var ikke låst med LOCK TABLES"
+ norwegian-ny "Tabellen '%-.64s' var ikkje låst med LOCK TABLES"
+ pol "Tabela '%-.64s' nie zosta³a zablokowana poleceniem LOCK TABLES"
+ por "Tabela '%-.64s' não foi travada com LOCK TABLES"
+ rum "Tabela '%-.64s' nu a fost locked cu LOCK TABLES"
+ rus "ôÁÂÌÉÃÁ '%-.64s' ÎÅ ÂÙÌÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES"
+ serbian "Tabela '%-.64s' nije bila zakljuèana komandom 'LOCK TABLES'"
+ slo "Tabuµka '%-.64s' nebola zamknutá s LOCK TABLES"
+ spa "Tabla '%-.64s' no fue trabada con LOCK TABLES"
+ swe "Tabell '%-.64s' är inte låst med LOCK TABLES"
+ ukr "ôÁÂÌÉÃÀ '%-.64s' ÎÅ ÂÕÌÏ ÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES"
+ER_BLOB_CANT_HAVE_DEFAULT 42000
+ cze "Blob polo-B¾ka '%-.64s' nemù¾e mít defaultní hodnotu"
+ dan "BLOB feltet '%-.64s' kan ikke have en standard værdi"
+ nla "Blob veld '%-.64s' can geen standaardwaarde bevatten"
+ eng "BLOB/TEXT column '%-.64s' can't have a default value"
+ est "BLOB-tüüpi tulp '%-.64s' ei saa omada vaikeväärtust"
+ fre "BLOB '%-.64s' ne peut avoir de valeur par défaut"
+ ger "BLOB-Feld '%-.64s' darf keinen Vorgabewert (DEFAULT) haben"
+ greek "Ôá Blob ðåäßá '%-.64s' äåí ìðïñïýí íá Ý÷ïõí ðñïêáèïñéóìÝíåò ôéìÝò (default value)"
+ hun "A(z) '%-.64s' blob objektumnak nem lehet alapertelmezett erteke"
+ ita "Il campo BLOB '%-.64s' non puo` avere un valore di default"
+ jpn "BLOB column '%-.64s' can't have a default value"
+ kor "BLOB Ä®·³ '%-.64s' ´Â µðÆúÆ® °ªÀ» °¡Áú ¼ö ¾ø½À´Ï´Ù."
+ nor "Blob feltet '%-.64s' kan ikke ha en standard verdi"
+ norwegian-ny "Blob feltet '%-.64s' kan ikkje ha ein standard verdi"
+ pol "Pole typu blob '%-.64s' nie mo¿e mieæ domy?lnej warto?ci"
+ por "Coluna BLOB '%-.64s' não pode ter um valor padrão (default)"
+ rum "Coloana BLOB '%-.64s' nu poate avea o valoare default"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÕËÁÚÙ×ÁÔØ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ ÓÔÏÌÂÃÁ BLOB '%-.64s'"
+ serbian "BLOB kolona '%-.64s' ne može imati default vrednost"
+ slo "Pole BLOB '%-.64s' nemô¾e ma» implicitnú hodnotu"
+ spa "Campo Blob '%-.64s' no puede tener valores patron"
+ swe "BLOB fält '%-.64s' kan inte ha ett DEFAULT-värde"
+ ukr "óÔÏ×ÂÅÃØ BLOB '%-.64s' ÎÅ ÍÏÖÅ ÍÁÔÉ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ"
+ER_WRONG_DB_NAME 42000
+ cze "Nep-Bøípustné jméno databáze '%-.64s'"
+ dan "Ugyldigt database navn '%-.64s'"
+ nla "Databasenaam '%-.64s' is niet getoegestaan"
+ eng "Incorrect database name '%-.100s'"
+ jps "Žw’肵‚½ database –¼ '%-.100s' ‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·",
+ est "Vigane andmebaasi nimi '%-.100s'"
+ fre "Nom de base de donnée illégal: '%-.64s'"
+ ger "Unerlaubter Datenbankname '%-.64s'"
+ greek "ËÜèïò üíïìá âÜóçò äåäïìÝíùí '%-.100s'"
+ hun "Hibas adatbazisnev: '%-.100s'"
+ ita "Nome database errato '%-.100s'"
+ jpn "»ØÄꤷ¤¿ database ̾ '%-.100s' ¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹"
+ kor "'%-.100s' µ¥ÀÌŸº£À̽ºÀÇ À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù."
+ nor "Ugyldig database navn '%-.64s'"
+ norwegian-ny "Ugyldig database namn '%-.64s'"
+ pol "Niedozwolona nazwa bazy danych '%-.64s'"
+ por "Nome de banco de dados '%-.100s' incorreto"
+ rum "Numele bazei de date este incorect '%-.100s'"
+ rus "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÂÁÚÙ ÄÁÎÎÙÈ '%-.100s'"
+ serbian "Pogrešno ime baze '%-.100s'"
+ slo "Neprípustné meno databázy '%-.100s'"
+ spa "Nombre de base de datos ilegal '%-.64s'"
+ swe "Felaktigt databasnamn '%-.64s'"
+ ukr "îÅצÒÎÅ ¦Í'Ñ ÂÁÚÉ ÄÁÎÎÉÈ '%-.100s'"
+ER_WRONG_TABLE_NAME 42000
+ cze "Nep-Bøípustné jméno tabulky '%-.64s'"
+ dan "Ugyldigt tabel navn '%-.64s'"
+ nla "Niet toegestane tabelnaam '%-.64s'"
+ eng "Incorrect table name '%-.100s'"
+ jps "Žw’肵‚½ table –¼ '%-.100s' ‚Í‚Ü‚¿‚ª‚Á‚Ä‚¢‚Ü‚·",
+ est "Vigane tabeli nimi '%-.100s'"
+ fre "Nom de table illégal: '%-.64s'"
+ ger "Unerlaubter Tabellenname '%-.64s'"
+ greek "ËÜèïò üíïìá ðßíáêá '%-.100s'"
+ hun "Hibas tablanev: '%-.100s'"
+ ita "Nome tabella errato '%-.100s'"
+ jpn "»ØÄꤷ¤¿ table ̾ '%-.100s' ¤Ï¤Þ¤Á¤¬¤Ã¤Æ¤¤¤Þ¤¹"
+ kor "'%-.100s' Å×À̺í À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù."
+ nor "Ugyldig tabell navn '%-.64s'"
+ norwegian-ny "Ugyldig tabell namn '%-.64s'"
+ pol "Niedozwolona nazwa tabeli '%-.64s'..."
+ por "Nome de tabela '%-.100s' incorreto"
+ rum "Numele tabelei este incorect '%-.100s'"
+ rus "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÔÁÂÌÉÃÙ '%-.100s'"
+ serbian "Pogrešno ime tabele '%-.100s'"
+ slo "Neprípustné meno tabuµky '%-.100s'"
+ spa "Nombre de tabla ilegal '%-.64s'"
+ swe "Felaktigt tabellnamn '%-.64s'"
+ ukr "îÅצÒÎÅ ¦Í'Ñ ÔÁÂÌÉæ '%-.100s'"
+ER_TOO_BIG_SELECT 42000
+ cze "Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET SQL_BIG_SELECTS=1"
+ dan "SELECT ville undersøge for mange poster og ville sandsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET SQL_BIG_SELECTS=1 hvis udtrykket er korrekt"
+ nla "Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET SQL_BIG_SELECTS=1 als het stament in orde is."
+ eng "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay"
+ est "SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada käsku SET SQL_BIG_SELECTS=1"
+ fre "SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET SQL_BIG_SELECTS=1 si SELECT se passe bien"
+ ger "Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange dauern. Bitte WHERE-Klausel überprüfen oder gegebenenfalls SET SQL_BIG_SELECTS=1 oder SET SQL_MAX_JOIN_SIZE=# verwenden"
+ greek "Ôï SELECT èá åîåôÜóåé ìåãÜëï áñéèìü åããñáöþí êáé ðéèáíþò èá êáèõóôåñÞóåé. Ðáñáêáëþ åîåôÜóôå ôéò ðáñáìÝôñïõò ôïõ WHERE êáé ÷ñçóéìïðïéåßóôå SET SQL_BIG_SELECTS=1 áí ôï SELECT åßíáé óùóôü"
+ hun "A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET SQL_BIG_SELECTS=1 beallitast, ha a SELECT okay"
+ ita "La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET SQL_BIG_SELECTS=1 se e` tutto a posto."
+ kor "SELECT ¸í·É¿¡¼­ ³Ê¹« ¸¹Àº ·¹Äڵ带 ã±â ¶§¹®¿¡ ¸¹Àº ½Ã°£ÀÌ ¼Ò¿äµË´Ï´Ù. µû¶ó¼­ WHERE ¹®À» Á¡°ËÇϰųª, ¸¸¾à SELECT°¡ okµÇ¸é SET SQL_BIG_SELECTS=1 ¿É¼ÇÀ» »ç¿ëÇϼ¼¿ä."
+ nor "SELECT ville undersøke for mange poster og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt"
+ norwegian-ny "SELECT ville undersøkje for mange postar og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt"
+ pol "Operacja SELECT bêdzie dotyczy³a zbyt wielu rekordów i prawdopodobnie zajmie bardzo du¿o czasu. Sprawd¥ warunek WHERE i u¿yj SQL_OPTION BIG_SELECTS=1 je?li operacja SELECT jest poprawna"
+ por "O SELECT examinaria registros demais e provavelmente levaria muito tempo. Cheque sua cláusula WHERE e use SET SQL_BIG_SELECTS=1, se o SELECT estiver correto"
+ rum "SELECT-ul ar examina prea multe cimpuri si probabil ar lua prea mult timp; verifica clauza WHERE si foloseste SET SQL_BIG_SELECTS=1 daca SELECT-ul e okay"
+ rus "äÌÑ ÔÁËÏÊ ×ÙÂÏÒËÉ SELECT ÄÏÌÖÅÎ ÂÕÄÅÔ ÐÒÏÓÍÏÔÒÅÔØ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÚÁÐÉÓÅÊ É, ×ÉÄÉÍÏ, ÜÔÏ ÚÁÊÍÅÔ ÏÞÅÎØ ÍÎÏÇÏ ×ÒÅÍÅÎÉ. ðÒÏ×ÅÒØÔÅ ×ÁÛÅ ÕËÁÚÁÎÉÅ WHERE, É, ÅÓÌÉ × ÎÅÍ ×ÓÅ × ÐÏÒÑÄËÅ, ÕËÁÖÉÔÅ SET SQL_BIG_SELECTS=1"
+ serbian "Komanda 'SELECT' æe ispitati previše slogova i potrošiti previše vremena. Proverite vaš 'WHERE' filter i upotrebite 'SET OPTION SQL_BIG_SELECTS=1' ako želite baš ovakvu komandu"
+ slo "Zadaná po¾iadavka SELECT by prechádzala príli¹ mnoho záznamov a trvala by príli¹ dlho. Skontrolujte tvar WHERE a ak je v poriadku, pou¾ite SET SQL_BIG_SELECTS=1"
+ spa "El SELECT puede examinar muchos registros y probablemente con mucho tiempo. Verifique tu WHERE y usa SET SQL_BIG_SELECTS=1 si el SELECT esta correcto"
+ swe "Den angivna frågan skulle läsa mer än MAX_JOIN_SIZE rader. Kontrollera din WHERE och använd SET SQL_BIG_SELECTS=1 eller SET MAX_JOIN_SIZE=# ifall du vill hantera stora joins"
+ ukr "úÁÐÉÔÕ SELECT ÐÏÔÒ¦ÂÎÏ ÏÂÒÏÂÉÔÉ ÂÁÇÁÔÏ ÚÁÐÉÓ¦×, ÝÏ, ÐÅ×ÎÅ, ÚÁÊÍÅ ÄÕÖÅ ÂÁÇÁÔÏ ÞÁÓÕ. ðÅÒÅצÒÔÅ ×ÁÛÅ WHERE ÔÁ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ SET SQL_BIG_SELECTS=1, ÑËÝÏ ÃÅÊ ÚÁÐÉÔ SELECT ¤ צÒÎÉÍ"
+ER_UNKNOWN_ERROR
+ cze "Nezn-Bámá chyba"
+ dan "Ukendt fejl"
+ nla "Onbekende Fout"
+ eng "Unknown error"
+ est "Tundmatu viga"
+ fre "Erreur inconnue"
+ ger "Unbekannter Fehler"
+ greek "ÐñïÝêõøå Üãíùóôï ëÜèïò"
+ hun "Ismeretlen hiba"
+ ita "Errore sconosciuto"
+ kor "¾Ë¼ö ¾ø´Â ¿¡·¯ÀÔ´Ï´Ù."
+ nor "Ukjent feil"
+ norwegian-ny "Ukjend feil"
+ por "Erro desconhecido"
+ rum "Eroare unknown"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ÏÛÉÂËÁ"
+ serbian "Nepoznata greška"
+ slo "Neznámá chyba"
+ spa "Error desconocido"
+ swe "Oidentifierat fel"
+ ukr "îÅצÄÏÍÁ ÐÏÍÉÌËÁ"
+ER_UNKNOWN_PROCEDURE 42000
+ cze "Nezn-Bámá procedura %s"
+ dan "Ukendt procedure %s"
+ nla "Onbekende procedure %s"
+ eng "Unknown procedure '%-.64s'"
+ est "Tundmatu protseduur '%-.64s'"
+ fre "Procédure %s inconnue"
+ ger "Unbekannte Prozedur '%-.64s'"
+ greek "Áãíùóôç äéáäéêáóßá '%-.64s'"
+ hun "Ismeretlen eljaras: '%-.64s'"
+ ita "Procedura '%-.64s' sconosciuta"
+ kor "¾Ë¼ö ¾ø´Â ¼öÇ๮ : '%-.64s'"
+ nor "Ukjent prosedyre %s"
+ norwegian-ny "Ukjend prosedyre %s"
+ pol "Unkown procedure %s"
+ por "'Procedure' '%-.64s' desconhecida"
+ rum "Procedura unknown '%-.64s'"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ÐÒÏÃÅÄÕÒÁ '%-.64s'"
+ serbian "Nepoznata procedura '%-.64s'"
+ slo "Neznámá procedúra '%-.64s'"
+ spa "Procedimiento desconocido %s"
+ swe "Okänd procedur: %s"
+ ukr "îÅצÄÏÍÁ ÐÒÏÃÅÄÕÒÁ '%-.64s'"
+ER_WRONG_PARAMCOUNT_TO_PROCEDURE 42000
+ cze "Chybn-Bý poèet parametrù procedury %s"
+ dan "Forkert antal parametre til proceduren %s"
+ nla "Foutief aantal parameters doorgegeven aan procedure %s"
+ eng "Incorrect parameter count to procedure '%-.64s'"
+ est "Vale parameetrite hulk protseduurile '%-.64s'"
+ fre "Mauvais nombre de paramètres pour la procedure %s"
+ ger "Falsche Parameterzahl für Prozedur '%-.64s'"
+ greek "ËÜèïò áñéèìüò ðáñáìÝôñùí óôç äéáäéêáóßá '%-.64s'"
+ hun "Rossz parameter a(z) '%-.64s'eljaras szamitasanal"
+ ita "Numero di parametri errato per la procedura '%-.64s'"
+ kor "'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ"
+ nor "Feil parameter antall til prosedyren %s"
+ norwegian-ny "Feil parameter tal til prosedyra %s"
+ pol "Incorrect parameter count to procedure %s"
+ por "Número de parâmetros incorreto para a 'procedure' '%-.64s'"
+ rum "Procedura '%-.64s' are un numar incorect de parametri"
+ rus "îÅËÏÒÒÅËÔÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÐÁÒÁÍÅÔÒÏ× ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.64s'"
+ serbian "Pogrešan broj parametara za proceduru '%-.64s'"
+ slo "Chybný poèet parametrov procedúry '%-.64s'"
+ spa "Equivocado parametro count para procedimiento %s"
+ swe "Felaktigt antal parametrar till procedur %s"
+ ukr "èÉÂÎÁ ˦ÌØ˦ÓÔØ ÐÁÒÁÍÅÔÒ¦× ÐÒÏÃÅÄÕÒÉ '%-.64s'"
+ER_WRONG_PARAMETERS_TO_PROCEDURE
+ cze "Chybn-Bé parametry procedury %s"
+ dan "Forkert(e) parametre til proceduren %s"
+ nla "Foutieve parameters voor procedure %s"
+ eng "Incorrect parameters to procedure '%-.64s'"
+ est "Vigased parameetrid protseduurile '%-.64s'"
+ fre "Paramètre erroné pour la procedure %s"
+ ger "Falsche Parameter für Prozedur '%-.64s'"
+ greek "ËÜèïò ðáñÜìåôñïé óôçí äéáäéêáóßá '%-.64s'"
+ hun "Rossz parameter a(z) '%-.64s' eljarasban"
+ ita "Parametri errati per la procedura '%-.64s'"
+ kor "'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ"
+ nor "Feil parametre til prosedyren %s"
+ norwegian-ny "Feil parameter til prosedyra %s"
+ pol "Incorrect parameters to procedure %s"
+ por "Parâmetros incorretos para a 'procedure' '%-.64s'"
+ rum "Procedura '%-.64s' are parametrii incorecti"
+ rus "îÅËÏÒÒÅËÔÎÙÅ ÐÁÒÁÍÅÔÒÙ ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.64s'"
+ serbian "Pogrešni parametri prosleðeni proceduri '%-.64s'"
+ slo "Chybné parametre procedúry '%-.64s'"
+ spa "Equivocados parametros para procedimiento %s"
+ swe "Felaktiga parametrar till procedur %s"
+ ukr "èÉÂÎÉÊ ÐÁÒÁÍÅÔÅÒ ÐÒÏÃÅÄÕÒÉ '%-.64s'"
+ER_UNKNOWN_TABLE 42S02
+ cze "Nezn-Bámá tabulka '%-.64s' v %s"
+ dan "Ukendt tabel '%-.64s' i %s"
+ nla "Onbekende tabel '%-.64s' in %s"
+ eng "Unknown table '%-.64s' in %-.32s"
+ est "Tundmatu tabel '%-.64s' %-.32s-s"
+ fre "Table inconnue '%-.64s' dans %s"
+ ger "Unbekannte Tabelle '%-.64s' in '%-.64s'"
+ greek "Áãíùóôïò ðßíáêáò '%-.64s' óå %s"
+ hun "Ismeretlen tabla: '%-.64s' %s-ban"
+ ita "Tabella '%-.64s' sconosciuta in %s"
+ jpn "Unknown table '%-.64s' in %s"
+ kor "¾Ë¼ö ¾ø´Â Å×À̺í '%-.64s' (µ¥ÀÌŸº£À̽º %s)"
+ nor "Ukjent tabell '%-.64s' i %s"
+ norwegian-ny "Ukjend tabell '%-.64s' i %s"
+ pol "Unknown table '%-.64s' in %s"
+ por "Tabela '%-.64s' desconhecida em '%-.32s'"
+ rum "Tabla '%-.64s' invalida in %-.32s"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.64s' × %-.32s"
+ serbian "Nepoznata tabela '%-.64s' u '%-.32s'"
+ slo "Neznáma tabuµka '%-.64s' v %s"
+ spa "Tabla desconocida '%-.64s' in %s"
+ swe "Okänd tabell '%-.64s' i '%-.64s'"
+ ukr "îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.64s' Õ %-.32s"
+ER_FIELD_SPECIFIED_TWICE 42000
+ cze "Polo-B¾ka '%-.64s' je zadána dvakrát"
+ dan "Feltet '%-.64s' er anvendt to gange"
+ nla "Veld '%-.64s' is dubbel gespecificeerd"
+ eng "Column '%-.64s' specified twice"
+ est "Tulp '%-.64s' on määratletud topelt"
+ fre "Champ '%-.64s' spécifié deux fois"
+ ger "Feld '%-.64s' wurde zweimal angegeben"
+ greek "Ôï ðåäßï '%-.64s' Ý÷åé ïñéóèåß äýï öïñÝò"
+ hun "A(z) '%-.64s' mezot ketszer definialta"
+ ita "Campo '%-.64s' specificato 2 volte"
+ kor "Ä®·³ '%-.64s'´Â µÎ¹ø Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù."
+ nor "Feltet '%-.64s' er spesifisert to ganger"
+ norwegian-ny "Feltet '%-.64s' er spesifisert to gangar"
+ pol "Field '%-.64s' specified twice"
+ por "Coluna '%-.64s' especificada duas vezes"
+ rum "Coloana '%-.64s' specificata de doua ori"
+ rus "óÔÏÌÂÅà '%-.64s' ÕËÁÚÁÎ Ä×ÁÖÄÙ"
+ serbian "Kolona '%-.64s' je navedena dva puta"
+ slo "Pole '%-.64s' je zadané dvakrát"
+ spa "Campo '%-.64s' especificado dos veces"
+ swe "Fält '%-.64s' är redan använt"
+ ukr "óÔÏ×ÂÅÃØ '%-.64s' ÚÁÚÎÁÞÅÎÏ Äצަ"
+ER_INVALID_GROUP_FUNC_USE
+ cze "Nespr-Bávné pou¾ití funkce group"
+ dan "Forkert brug af grupperings-funktion"
+ nla "Ongeldig gebruik van GROUP-functie"
+ eng "Invalid use of group function"
+ est "Vigane grupeerimisfunktsiooni kasutus"
+ fre "Utilisation invalide de la clause GROUP"
+ ger "Falsche Verwendung einer Gruppierungsfunktion"
+ greek "ÅóöáëìÝíç ÷ñÞóç ôçò group function"
+ hun "A group funkcio ervenytelen hasznalata"
+ ita "Uso non valido di una funzione di raggruppamento"
+ kor "À߸øµÈ ±×·ì ÇÔ¼ö¸¦ »ç¿ëÇÏ¿´½À´Ï´Ù."
+ por "Uso inválido de função de agrupamento (GROUP)"
+ rum "Folosire incorecta a functiei group"
+ rus "îÅÐÒÁ×ÉÌØÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÇÒÕÐÐÏ×ÙÈ ÆÕÎËÃÉÊ"
+ serbian "Pogrešna upotreba 'GROUP' funkcije"
+ slo "Nesprávne pou¾itie funkcie GROUP"
+ spa "Invalido uso de función en grupo"
+ swe "Felaktig användning av SQL grupp function"
+ ukr "èÉÂÎÅ ×ÉËÏÒÉÓÔÁÎÎÑ ÆÕÎËæ§ ÇÒÕÐÕ×ÁÎÎÑ"
+ER_UNSUPPORTED_EXTENSION 42000
+ cze "Tabulka '%-.64s' pou-B¾ívá roz¹íøení, které v této verzi MySQL není"
+ dan "Tabellen '%-.64s' bruger et filtypenavn som ikke findes i denne MySQL version"
+ nla "Tabel '%-.64s' gebruikt een extensie, die niet in deze MySQL-versie voorkomt."
+ eng "Table '%-.64s' uses an extension that doesn't exist in this MySQL version"
+ est "Tabel '%-.64s' kasutab laiendust, mis ei eksisteeri antud MySQL versioonis"
+ fre "Table '%-.64s' : utilise une extension invalide pour cette version de MySQL"
+ ger "Tabelle '%-.64s' verwendet eine Extension, die in dieser MySQL-Version nicht verfügbar ist"
+ greek "Ï ðßíáêò '%-.64s' ÷ñçóéìïðïéåß êÜðïéï extension ðïõ äåí õðÜñ÷åé óôçí Ýêäïóç áõôÞ ôçò MySQL"
+ hun "A(z) '%-.64s' tabla olyan bovitest hasznal, amely nem letezik ebben a MySQL versioban."
+ ita "La tabella '%-.64s' usa un'estensione che non esiste in questa versione di MySQL"
+ kor "Å×À̺í '%-.64s'´Â È®Àå¸í·ÉÀ» ÀÌ¿ëÇÏÁö¸¸ ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
+ nor "Table '%-.64s' uses a extension that doesn't exist in this MySQL version"
+ norwegian-ny "Table '%-.64s' uses a extension that doesn't exist in this MySQL version"
+ pol "Table '%-.64s' uses a extension that doesn't exist in this MySQL version"
+ por "Tabela '%-.64s' usa uma extensão que não existe nesta versão do MySQL"
+ rum "Tabela '%-.64s' foloseste o extensire inexistenta in versiunea curenta de MySQL"
+ rus "÷ ÔÁÂÌÉÃÅ '%-.64s' ÉÓÐÏÌØÚÕÀÔÓÑ ×ÏÚÍÏÖÎÏÓÔÉ, ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÍÙÅ × ÜÔÏÊ ×ÅÒÓÉÉ MySQL"
+ serbian "Tabela '%-.64s' koristi ekstenziju koje ne postoji u ovoj verziji MySQL-a"
+ slo "Tabuµka '%-.64s' pou¾íva roz¹írenie, ktoré v tejto verzii MySQL nie je"
+ spa "Tabla '%-.64s' usa una extensión que no existe en esta MySQL versión"
+ swe "Tabell '%-.64s' har en extension som inte finns i denna version av MySQL"
+ ukr "ôÁÂÌÉÃÑ '%-.64s' ×ÉËÏÒÉÓÔÏ×Õ¤ ÒÏÚÛÉÒÅÎÎÑ, ÝÏ ÎÅ ¦ÓÎÕ¤ Õ Ã¦Ê ×ÅÒÓ¦§ MySQL"
+ER_TABLE_MUST_HAVE_COLUMNS 42000
+ cze "Tabulka mus-Bí mít alespoò jeden sloupec"
+ dan "En tabel skal have mindst een kolonne"
+ nla "Een tabel moet minstens 1 kolom bevatten"
+ eng "A table must have at least 1 column"
+ jps "ƒe[ƒuƒ‹‚ÍÅ’á 1 ŒÂ‚Ì column ‚ª•K—v‚Å‚·",
+ est "Tabelis peab olema vähemalt üks tulp"
+ fre "Une table doit comporter au moins une colonne"
+ ger "Eine Tabelle muß mindestens 1 Spalte besitzen"
+ greek "Åíáò ðßíáêáò ðñÝðåé íá Ý÷åé ôïõëÜ÷éóôïí Ýíá ðåäßï"
+ hun "A tablanak legalabb egy oszlopot tartalmazni kell"
+ ita "Una tabella deve avere almeno 1 colonna"
+ jpn "¥Æ¡¼¥Ö¥ë¤ÏºÇÄã 1 ¸Ä¤Î column ¤¬É¬ÍפǤ¹"
+ kor "ÇϳªÀÇ Å×ÀÌºí¿¡¼­´Â Àû¾îµµ ÇϳªÀÇ Ä®·³ÀÌ Á¸ÀçÇÏ¿©¾ß ÇÕ´Ï´Ù."
+ por "Uma tabela tem que ter pelo menos uma (1) coluna"
+ rum "O tabela trebuie sa aiba cel putin o coloana"
+ rus "÷ ÔÁÂÌÉÃÅ ÄÏÌÖÅÎ ÂÙÔØ ËÁË ÍÉÎÉÍÕÍ ÏÄÉÎ ÓÔÏÌÂÅÃ"
+ serbian "Tabela mora imati najmanje jednu kolonu"
+ slo "Tabuµka musí ma» aspoò 1 pole"
+ spa "Una tabla debe tener al menos 1 columna"
+ swe "Tabeller måste ha minst 1 kolumn"
+ ukr "ôÁÂÌÉÃÑ ÐÏ×ÉÎÎÁ ÍÁÔÉ ÈÏÞÁ ÏÄÉÎ ÓÔÏ×ÂÅÃØ"
+ER_RECORD_FILE_FULL
+ cze "Tabulka '%-.64s' je pln-Bá"
+ dan "Tabellen '%-.64s' er fuld"
+ nla "De tabel '%-.64s' is vol"
+ eng "The table '%-.64s' is full"
+ jps "table '%-.64s' ‚Í‚¢‚Á‚Ï‚¢‚Å‚·",
+ est "Tabel '%-.64s' on täis"
+ fre "La table '%-.64s' est pleine"
+ ger "Tabelle '%-.64s' ist voll"
+ greek "Ï ðßíáêáò '%-.64s' åßíáé ãåìÜôïò"
+ hun "A '%-.64s' tabla megtelt"
+ ita "La tabella '%-.64s' e` piena"
+ jpn "table '%-.64s' ¤Ï¤¤¤Ã¤Ñ¤¤¤Ç¤¹"
+ kor "Å×À̺í '%-.64s'°¡ full³µ½À´Ï´Ù. "
+ por "Tabela '%-.64s' está cheia"
+ rum "Tabela '%-.64s' e plina"
+ rus "ôÁÂÌÉÃÁ '%-.64s' ÐÅÒÅÐÏÌÎÅÎÁ"
+ serbian "Tabela '%-.64s' je popunjena do kraja"
+ slo "Tabuµka '%-.64s' je plná"
+ spa "La tabla '%-.64s' está llena"
+ swe "Tabellen '%-.64s' är full"
+ ukr "ôÁÂÌÉÃÑ '%-.64s' ÚÁÐÏ×ÎÅÎÁ"
+ER_UNKNOWN_CHARACTER_SET 42000
+ cze "Nezn-Bámá znaková sada: '%-.64s'"
+ dan "Ukendt tegnsæt: '%-.64s'"
+ nla "Onbekende character set: '%-.64s'"
+ eng "Unknown character set: '%-.64s'"
+ jps "character set '%-.64s' ‚̓Tƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Vigane kooditabel '%-.64s'"
+ fre "Jeu de caractères inconnu: '%-.64s'"
+ ger "Unbekannter Zeichensatz: '%-.64s'"
+ greek "Áãíùóôï character set: '%-.64s'"
+ hun "Ervenytelen karakterkeszlet: '%-.64s'"
+ ita "Set di caratteri '%-.64s' sconosciuto"
+ jpn "character set '%-.64s' ¤Ï¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Þ¤»¤ó"
+ kor "¾Ë¼ö¾ø´Â ¾ð¾î Set: '%-.64s'"
+ por "Conjunto de caracteres '%-.64s' desconhecido"
+ rum "Set de caractere invalid: '%-.64s'"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ËÏÄÉÒÏ×ËÁ '%-.64s'"
+ serbian "Nepoznati karakter-set: '%-.64s'"
+ slo "Neznáma znaková sada: '%-.64s'"
+ spa "Juego de caracteres desconocido: '%-.64s'"
+ swe "Okänd teckenuppsättning: '%-.64s'"
+ ukr "îÅצÄÏÍÁ ËÏÄÏ×Á ÔÁÂÌÉÃÑ: '%-.64s'"
+ER_TOO_MANY_TABLES
+ cze "P-Bøíli¹ mnoho tabulek, MySQL jich mù¾e mít v joinu jen %d"
+ dan "For mange tabeller. MySQL kan kun bruge %d tabeller i et join"
+ nla "Teveel tabellen. MySQL kan slechts %d tabellen in een join bevatten"
+ eng "Too many tables; MySQL can only use %d tables in a join"
+ jps "ƒe[ƒuƒ‹‚ª‘½‚·‚¬‚Ü‚·; MySQL can only use %d tables in a join",
+ est "Liiga palju tabeleid. MySQL suudab JOINiga ühendada kuni %d tabelit"
+ fre "Trop de tables. MySQL ne peut utiliser que %d tables dans un JOIN"
+ ger "Zu viele Tabellen. MySQL kann in einem Join maximal %d Tabellen verwenden"
+ greek "Ðïëý ìåãÜëïò áñéèìüò ðéíÜêùí. Ç MySQL ìðïñåß íá ÷ñçóéìïðïéÞóåé %d ðßíáêåò óå äéáäéêáóßá join"
+ hun "Tul sok tabla. A MySQL csak %d tablat tud kezelni osszefuzeskor"
+ ita "Troppe tabelle. MySQL puo` usare solo %d tabelle in una join"
+ jpn "¥Æ¡¼¥Ö¥ë¤¬Â¿¤¹¤®¤Þ¤¹; MySQL can only use %d tables in a join"
+ kor "³Ê¹« ¸¹Àº Å×À̺íÀÌ JoinµÇ¾ú½À´Ï´Ù. MySQL¿¡¼­´Â JOIN½Ã %d°³ÀÇ Å×ÀÌºí¸¸ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù."
+ por "Tabelas demais. O MySQL pode usar somente %d tabelas em uma junção (JOIN)"
+ rum "Prea multe tabele. MySQL nu poate folosi mai mult de %d tabele intr-un join"
+ rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÔÁÂÌÉÃ. MySQL ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÔÏÌØËÏ %d ÔÁÂÌÉÃ × ÓÏÅÄÉÎÅÎÉÉ"
+ serbian "Previše tabela. MySQL može upotrebiti maksimum %d tabela pri 'JOIN' operaciji"
+ slo "Príli¹ mnoho tabuliek. MySQL mô¾e pou¾i» len %d v JOIN-e"
+ spa "Muchas tablas. MySQL solamente puede usar %d tablas en un join"
+ swe "För många tabeller. MySQL can ha högst %d tabeller i en och samma join"
+ ukr "úÁÂÁÇÁÔÏ ÔÁÂÌÉÃØ. MySQL ÍÏÖÅ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÌÉÛÅ %d ÔÁÂÌÉÃØ Õ ÏÂ'¤ÄÎÁÎΦ"
+ER_TOO_MANY_FIELDS
+ cze "P-Bøíli¹ mnoho polo¾ek"
+ dan "For mange felter"
+ nla "Te veel velden"
+ eng "Too many columns"
+ jps "column ‚ª‘½‚·‚¬‚Ü‚·",
+ est "Liiga palju tulpasid"
+ fre "Trop de champs"
+ ger "Zu viele Spalten"
+ greek "Ðïëý ìåãÜëïò áñéèìüò ðåäßùí"
+ hun "Tul sok mezo"
+ ita "Troppi campi"
+ jpn "column ¤¬Â¿¤¹¤®¤Þ¤¹"
+ kor "Ä®·³ÀÌ ³Ê¹« ¸¹½À´Ï´Ù."
+ por "Colunas demais"
+ rum "Prea multe coloane"
+ rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÓÔÏÌÂÃÏ×"
+ serbian "Previše kolona"
+ slo "Príli¹ mnoho polí"
+ spa "Muchos campos"
+ swe "För många fält"
+ ukr "úÁÂÁÇÁÔÏ ÓÔÏ×Âæ×"
+ER_TOO_BIG_ROWSIZE 42000
+ cze "-BØádek je pøíli¹ velký. Maximální velikost øádku, nepoèítaje polo¾ky blob, je %d. Musíte zmìnit nìkteré polo¾ky na blob"
+ dan "For store poster. Max post størrelse, uden BLOB's, er %d. Du må lave nogle felter til BLOB's"
+ nla "Rij-grootte is groter dan toegestaan. Maximale rij grootte, blobs niet meegeteld, is %d. U dient sommige velden in blobs te veranderen."
+ eng "Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs"
+ jps "row size ‚ª‘å‚«‚·‚¬‚Ü‚·. BLOB ‚ðŠÜ‚Ü‚È‚¢ê‡‚Ì row size ‚ÌÅ‘å‚Í %d ‚Å‚·. ‚¢‚­‚‚©‚Ì field ‚ð BLOB ‚É•Ï‚¦‚Ä‚­‚¾‚³‚¢.",
+ est "Liiga pikk kirje. Kirje maksimumpikkus arvestamata BLOB-tüüpi välju on %d. Muuda mõned väljad BLOB-tüüpi väljadeks"
+ fre "Ligne trop grande. Le taille maximale d'une ligne, sauf les BLOBs, est %d. Changez le type de quelques colonnes en BLOB"
+ ger "Zeilenlänge zu groß. Die maximale Spaltenlänge für den verwendeten Tabellentyp (ohne BLOB-Felder) beträgt %d. Einige Felder müssen in BLOB oder TEXT umgewandelt werden"
+ greek "Ðïëý ìåãÜëï ìÝãåèïò åããñáöÞò. Ôï ìÝãéóôï ìÝãåèïò åããñáöÞò, ÷ùñßò íá õðïëïãßæïíôáé ôá blobs, åßíáé %d. ÐñÝðåé íá ïñßóåôå êÜðïéá ðåäßá óáí blobs"
+ hun "Tul nagy sormeret. A maximalis sormeret (nem szamolva a blob objektumokat) %d. Nehany mezot meg kell valtoztatnia"
+ ita "Riga troppo grande. La massima grandezza di una riga, non contando i BLOB, e` %d. Devi cambiare alcuni campi in BLOB"
+ jpn "row size ¤¬Â礭¤¹¤®¤Þ¤¹. BLOB ¤ò´Þ¤Þ¤Ê¤¤¾ì¹ç¤Î row size ¤ÎºÇÂç¤Ï %d ¤Ç¤¹. ¤¤¤¯¤Ä¤«¤Î field ¤ò BLOB ¤ËÊѤ¨¤Æ¤¯¤À¤µ¤¤."
+ kor "³Ê¹« Å« row »çÀÌÁîÀÔ´Ï´Ù. BLOB¸¦ °è»êÇÏÁö ¾Ê°í ÃÖ´ë row »çÀÌÁî´Â %dÀÔ´Ï´Ù. ¾ó¸¶°£ÀÇ ÇʵåµéÀ» BLOB·Î ¹Ù²Ù¼Å¾ß °Ú±º¿ä.."
+ por "Tamanho de linha grande demais. O máximo tamanho de linha, não contando BLOBs, é %d. Você tem que mudar alguns campos para BLOBs"
+ rum "Marimea liniei (row) prea mare. Marimea maxima a liniei, excluzind BLOB-urile este de %d. Trebuie sa schimbati unele cimpuri in BLOB-uri"
+ rus "óÌÉÛËÏÍ ÂÏÌØÛÏÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ. íÁËÓÉÍÁÌØÎÙÊ ÒÁÚÍÅÒ ÓÔÒÏËÉ, ÉÓËÌÀÞÁÑ ÐÏÌÑ BLOB, - %d. ÷ÏÚÍÏÖÎÏ, ×ÁÍ ÓÌÅÄÕÅÔ ÉÚÍÅÎÉÔØ ÔÉÐ ÎÅËÏÔÏÒÙÈ ÐÏÌÅÊ ÎÁ BLOB"
+ serbian "Prevelik slog. Maksimalna velièina sloga, ne raèunajuæi BLOB polja, je %d. Trebali bi da promenite tip nekih polja u BLOB"
+ slo "Riadok je príli¹ veµký. Maximálna veµkos» riadku, okrem 'BLOB', je %d. Musíte zmeni» niektoré polo¾ky na BLOB"
+ spa "Tamaño de línea muy grande. Máximo tamaño de línea, no contando blob, es %d. Tu tienes que cambiar algunos campos para blob"
+ swe "För stor total radlängd. Den högst tillåtna radlängden, förutom BLOBs, är %d. Ändra några av dina fält till BLOB"
+ ukr "úÁÄÏ×ÇÁ ÓÔÒÏËÁ. îÁʦÌØÛÏÀ ÄÏ×ÖÉÎÏÀ ÓÔÒÏËÉ, ÎÅ ÒÁÈÕÀÞÉ BLOB, ¤ %d. ÷ÁÍ ÐÏÔÒ¦ÂÎÏ ÐÒÉ×ÅÓÔÉ ÄÅÑ˦ ÓÔÏ×Âæ ÄÏ ÔÉÐÕ BLOB"
+ER_STACK_OVERRUN
+ cze "P-Bøeteèení zásobníku threadu: pou¾ito %ld z %ld. Pou¾ijte 'mysqld -O thread_stack=#' k zadání vìt¹ího zásobníku"
+ dan "Thread stack brugt: Brugt: %ld af en %ld stak. Brug 'mysqld -O thread_stack=#' for at allokere en større stak om nødvendigt"
+ nla "Thread stapel overrun: Gebruikte: %ld van een %ld stack. Gebruik 'mysqld -O thread_stack=#' om een grotere stapel te definieren (indien noodzakelijk)."
+ eng "Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed"
+ jps "Thread stack overrun: Used: %ld of a %ld stack. ƒXƒ^ƒbƒN—̈æ‚𑽂­‚Ƃ肽‚¢ê‡A'mysqld -O thread_stack=#' ‚ÆŽw’肵‚Ä‚­‚¾‚³‚¢",
+ fre "Débordement de la pile des tâches (Thread stack). Utilisées: %ld pour une pile de %ld. Essayez 'mysqld -O thread_stack=#' pour indiquer une plus grande valeur"
+ ger "Thread-Stack-Überlauf. Benutzt: %ld von %ld Stack. 'mysqld -O thread_stack=#' verwenen, um notfalls einen größeren Stack anzulegen"
+ greek "Stack overrun óôï thread: Used: %ld of a %ld stack. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå 'mysqld -O thread_stack=#' ãéá íá ïñßóåôå Ýíá ìåãáëýôåñï stack áí ÷ñåéÜæåôáé"
+ hun "Thread verem tullepes: Used: %ld of a %ld stack. Hasznalja a 'mysqld -O thread_stack=#' nagyobb verem definialasahoz"
+ ita "Thread stack overrun: Usati: %ld di uno stack di %ld. Usa 'mysqld -O thread_stack=#' per specificare uno stack piu` grande."
+ jpn "Thread stack overrun: Used: %ld of a %ld stack. ¥¹¥¿¥Ã¥¯Îΰè¤ò¿¤¯¤È¤ê¤¿¤¤¾ì¹ç¡¢'mysqld -O thread_stack=#' ¤È»ØÄꤷ¤Æ¤¯¤À¤µ¤¤"
+ kor "¾²·¹µå ½ºÅÃÀÌ ³ÑÃƽÀ´Ï´Ù. »ç¿ë: %ld°³ ½ºÅÃ: %ld°³. ¸¸¾à ÇÊ¿ä½Ã ´õÅ« ½ºÅÃÀ» ¿øÇÒ¶§¿¡´Â 'mysqld -O thread_stack=#' ¸¦ Á¤ÀÇÇϼ¼¿ä"
+ por "Estouro da pilha do 'thread'. Usados %ld de uma pilha de %ld. Use 'mysqld -O thread_stack=#' para especificar uma pilha maior, se necessário"
+ rum "Stack-ul thread-ului a fost depasit (prea mic): Folositi: %ld intr-un stack de %ld. Folositi 'mysqld -O thread_stack=#' ca sa specifici un stack mai mare"
+ rus "óÔÅË ÐÏÔÏËÏ× ÐÅÒÅÐÏÌÎÅÎ: ÉÓÐÏÌØÚÏ×ÁÎÏ: %ld ÉÚ %ld ÓÔÅËÁ. ðÒÉÍÅÎÑÊÔÅ 'mysqld -O thread_stack=#' ÄÌÑ ÕËÁÚÁÎÉÑ ÂÏÌØÛÅÇÏ ÒÁÚÍÅÒÁ ÓÔÅËÁ, ÅÓÌÉ ÎÅÏÂÈÏÄÉÍÏ"
+ serbian "Prepisivanje thread stack-a: Upotrebljeno: %ld od %ld stack memorije. Upotrebite 'mysqld -O thread_stack=#' da navedete veæi stack ako je potrebno"
+ slo "Preteèenie zásobníku vlákna: pou¾ité: %ld z %ld. Pou¾ite 'mysqld -O thread_stack=#' k zadaniu väè¹ieho zásobníka"
+ spa "Sobrecarga de la pila de thread: Usada: %ld de una %ld pila. Use 'mysqld -O thread_stack=#' para especificar una mayor pila si necesario"
+ swe "Trådstacken tog slut: Har använt %ld av %ld bytes. Använd 'mysqld -O thread_stack=#' ifall du behöver en större stack"
+ ukr "óÔÅË Ç¦ÌÏË ÐÅÒÅÐÏ×ÎÅÎÏ: ÷ÉËÏÒÉÓÔÁÎÏ: %ld Ú %ld. ÷ÉËÏÒÉÓÔÏ×ÕÊÔÅ 'mysqld -O thread_stack=#' ÁÂÉ ÚÁÚÎÁÞÉÔÉ Â¦ÌØÛÉÊ ÓÔÅË, ÑËÝÏ ÎÅÏÂȦÄÎÏ"
+ER_WRONG_OUTER_JOIN 42000
+ cze "V OUTER JOIN byl nalezen k-Bøí¾ový odkaz. Provìøte ON podmínky"
+ dan "Krydsreferencer fundet i OUTER JOIN; check dine ON conditions"
+ nla "Gekruiste afhankelijkheid gevonden in OUTER JOIN. Controleer uw ON-conditions"
+ eng "Cross dependency found in OUTER JOIN; examine your ON conditions"
+ est "Ristsõltuvus OUTER JOIN klauslis. Kontrolli oma ON tingimusi"
+ fre "Dépendance croisée dans une clause OUTER JOIN. Vérifiez la condition ON"
+ ger "OUTER JOIN enthält fehlerhafte Abhängigkeiten. In ON verwendete Bedingungen überprüfen"
+ greek "Cross dependency âñÝèçêå óå OUTER JOIN. Ðáñáêáëþ åîåôÜóôå ôéò óõíèÞêåò ðïõ èÝóáôå óôï ON"
+ hun "Keresztfuggoseg van az OUTER JOIN-ban. Ellenorizze az ON felteteleket"
+ ita "Trovata una dipendenza incrociata nella OUTER JOIN. Controlla le condizioni ON"
+ por "Dependência cruzada encontrada em junção externa (OUTER JOIN); examine as condições utilizadas nas cláusulas 'ON'"
+ rum "Dependinta incrucisata (cross dependency) gasita in OUTER JOIN. Examinati conditiile ON"
+ rus "÷ OUTER JOIN ÏÂÎÁÒÕÖÅÎÁ ÐÅÒÅËÒÅÓÔÎÁÑ ÚÁ×ÉÓÉÍÏÓÔØ. ÷ÎÉÍÁÔÅÌØÎÏ ÐÒÏÁÎÁÌÉÚÉÒÕÊÔÅ Ó×ÏÉ ÕÓÌÏ×ÉÑ ON"
+ serbian "Unakrsna zavisnost pronaðena u komandi 'OUTER JOIN'. Istražite vaše 'ON' uslove"
+ slo "V OUTER JOIN bol nájdený krí¾ový odkaz. Skontrolujte podmienky ON"
+ spa "Dependencia cruzada encontrada en OUTER JOIN. Examine su condición ON"
+ swe "Felaktigt referens i OUTER JOIN. Kontrollera ON-uttrycket"
+ ukr "ðÅÒÅÈÒÅÓÎÁ ÚÁÌÅÖΦÓÔØ Õ OUTER JOIN. ðÅÒÅצÒÔÅ ÕÍÏ×Õ ON"
+ER_NULL_COLUMN_IN_INDEX 42000
+ cze "Sloupec '%-.32s' je pou-B¾it s UNIQUE nebo INDEX, ale není definován jako NOT NULL"
+ dan "Kolonne '%-.32s' bruges som UNIQUE eller INDEX men er ikke defineret som NOT NULL"
+ nla "Kolom '%-.64s' wordt gebruikt met UNIQUE of INDEX maar is niet gedefinieerd als NOT NULL"
+ eng "Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
+ jps "Column '%-.64s' ‚ª UNIQUE ‚© INDEX ‚ÅŽg—p‚³‚ê‚Ü‚µ‚½. ‚±‚̃Jƒ‰ƒ€‚Í NOT NULL ‚Æ’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ.",
+ est "Tulp '%-.64s' on kasutusel indeksina, kuid ei ole määratletud kui NOT NULL"
+ fre "La colonne '%-.32s' fait partie d'un index UNIQUE ou INDEX mais n'est pas définie comme NOT NULL"
+ ger "Spalte '%-.64s' wurde mit UNIQUE oder INDEX benutzt, ist aber nicht als NOT NULL definiert"
+ greek "Ôï ðåäßï '%-.64s' ÷ñçóéìïðïéåßôáé óáí UNIQUE Þ INDEX áëëÜ äåí Ý÷åé ïñéóèåß óáí NOT NULL"
+ hun "A(z) '%-.64s' oszlop INDEX vagy UNIQUE (egyedi), de a definicioja szerint nem NOT NULL"
+ ita "La colonna '%-.64s' e` usata con UNIQUE o INDEX ma non e` definita come NOT NULL"
+ jpn "Column '%-.64s' ¤¬ UNIQUE ¤« INDEX ¤Ç»ÈÍѤµ¤ì¤Þ¤·¤¿. ¤³¤Î¥«¥é¥à¤Ï NOT NULL ¤ÈÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó."
+ kor "'%-.64s' Ä®·³ÀÌ UNIQUE³ª INDEX¸¦ »ç¿ëÇÏ¿´Áö¸¸ NOT NULLÀÌ Á¤ÀǵÇÁö ¾Ê¾Ò±º¿ä..."
+ nor "Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
+ norwegian-ny "Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
+ pol "Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL"
+ por "Coluna '%-.64s' é usada com única (UNIQUE) ou índice (INDEX), mas não está definida como não-nula (NOT NULL)"
+ rum "Coloana '%-.64s' e folosita cu UNIQUE sau INDEX dar fara sa fie definita ca NOT NULL"
+ rus "óÔÏÌÂÅÃ '%-.64s' ÉÓÐÏÌØÚÕÅÔÓÑ × UNIQUE ÉÌÉ × INDEX, ÎÏ ÎÅ ÏÐÒÅÄÅÌÅÎ ËÁË NOT NULL"
+ serbian "Kolona '%-.64s' je upotrebljena kao 'UNIQUE' ili 'INDEX' ali nije definisana kao 'NOT NULL'"
+ slo "Pole '%-.64s' je pou¾ité s UNIQUE alebo INDEX, ale nie je zadefinované ako NOT NULL"
+ spa "Columna '%-.32s' es usada con UNIQUE o INDEX pero no está definida como NOT NULL"
+ swe "Kolumn '%-.32s' är använd med UNIQUE eller INDEX men är inte definerad med NOT NULL"
+ ukr "óÔÏ×ÂÅÃØ '%-.64s' ×ÉËÏÒÉÓÔÏ×Õ¤ÔØÓÑ Ú UNIQUE ÁÂÏ INDEX, ÁÌÅ ÎÅ ×ÉÚÎÁÞÅÎÉÊ ÑË NOT NULL"
+ER_CANT_FIND_UDF
+ cze "Nemohu na-Bèíst funkci '%-.64s'"
+ dan "Kan ikke læse funktionen '%-.64s'"
+ nla "Kan functie '%-.64s' niet laden"
+ eng "Can't load function '%-.64s'"
+ jps "function '%-.64s' ‚ð ƒ[ƒh‚Å‚«‚Ü‚¹‚ñ",
+ est "Ei suuda avada funktsiooni '%-.64s'"
+ fre "Imposible de charger la fonction '%-.64s'"
+ ger "Kann Funktion '%-.64s' nicht laden"
+ greek "Äåí åßíáé äõíáôÞ ç äéáäéêáóßá load ãéá ôç óõíÜñôçóç '%-.64s'"
+ hun "A(z) '%-.64s' fuggveny nem toltheto be"
+ ita "Impossibile caricare la funzione '%-.64s'"
+ jpn "function '%-.64s' ¤ò ¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó"
+ kor "'%-.64s' ÇÔ¼ö¸¦ ·ÎµåÇÏÁö ¸øÇß½À´Ï´Ù."
+ por "Não pode carregar a função '%-.64s'"
+ rum "Nu pot incarca functia '%-.64s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÇÒÕÚÉÔØ ÆÕÎËÃÉÀ '%-.64s'"
+ serbian "Ne mogu da uèitam funkciju '%-.64s'"
+ slo "Nemô¾em naèíta» funkciu '%-.64s'"
+ spa "No puedo cargar función '%-.64s'"
+ swe "Kan inte ladda funktionen '%-.64s'"
+ ukr "îÅ ÍÏÖÕ ÚÁ×ÁÎÔÁÖÉÔÉ ÆÕÎËæÀ '%-.64s'"
+ER_CANT_INITIALIZE_UDF
+ cze "Nemohu inicializovat funkci '%-.64s'; %-.80s"
+ dan "Kan ikke starte funktionen '%-.64s'; %-.80s"
+ nla "Kan functie '%-.64s' niet initialiseren; %-.80s"
+ eng "Can't initialize function '%-.64s'; %-.80s"
+ jps "function '%-.64s' ‚ð‰Šú‰»‚Å‚«‚Ü‚¹‚ñ; %-.80s",
+ est "Ei suuda algväärtustada funktsiooni '%-.64s'; %-.80s"
+ fre "Impossible d'initialiser la fonction '%-.64s'; %-.80s"
+ ger "Kann Funktion '%-.64s' nicht initialisieren: %-.80s"
+ greek "Äåí åßíáé äõíáôÞ ç Ýíáñîç ôçò óõíÜñôçóçò '%-.64s'; %-.80s"
+ hun "A(z) '%-.64s' fuggveny nem inicializalhato; %-.80s"
+ ita "Impossibile inizializzare la funzione '%-.64s'; %-.80s"
+ jpn "function '%-.64s' ¤ò½é´ü²½¤Ç¤­¤Þ¤»¤ó; %-.80s"
+ kor "'%-.64s' ÇÔ¼ö¸¦ ÃʱâÈ­ ÇÏÁö ¸øÇß½À´Ï´Ù.; %-.80s"
+ por "Não pode inicializar a função '%-.64s' - '%-.80s'"
+ rum "Nu pot initializa functia '%-.64s'; %-.80s"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÔØ ÆÕÎËÃÉÀ '%-.64s'; %-.80s"
+ serbian "Ne mogu da inicijalizujem funkciju '%-.64s'; %-.80s"
+ slo "Nemô¾em inicializova» funkciu '%-.64s'; %-.80s"
+ spa "No puedo inicializar función '%-.64s'; %-.80s"
+ swe "Kan inte initialisera funktionen '%-.64s'; '%-.80s'"
+ ukr "îÅ ÍÏÖÕ ¦Î¦Ã¦Á̦ÚÕ×ÁÔÉ ÆÕÎËæÀ '%-.64s'; %-.80s"
+ER_UDF_NO_PATHS
+ cze "Pro sd-Bílenou knihovnu nejsou povoleny cesty"
+ dan "Angivelse af sti ikke tilladt for delt bibliotek"
+ nla "Geen pad toegestaan voor shared library"
+ eng "No paths allowed for shared library"
+ jps "shared library ‚ւ̃pƒX‚ª’Ê‚Á‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Teegi nimes ei tohi olla kataloogi"
+ fre "Chemin interdit pour les bibliothèques partagées"
+ ger "Keine Pfade gestattet für Shared Library"
+ greek "Äåí âñÝèçêáí paths ãéá ôçí shared library"
+ hun "Nincs ut a megosztott konyvtarakhoz (shared library)"
+ ita "Non sono ammessi path per le librerie condivisa"
+ jpn "shared library ¤Ø¤Î¥Ñ¥¹¤¬Ä̤äƤ¤¤Þ¤»¤ó"
+ kor "°øÀ¯ ¶óÀ̹ö·¯¸®¸¦ À§ÇÑ Æнº°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù."
+ por "Não há caminhos (paths) permitidos para biblioteca compartilhada"
+ rum "Nici un paths nu e permis pentru o librarie shared"
+ rus "îÅÄÏÐÕÓÔÉÍÏ ÕËÁÚÙ×ÁÔØ ÐÕÔÉ ÄÌÑ ÄÉÎÁÍÉÞÅÓËÉÈ ÂÉÂÌÉÏÔÅË"
+ serbian "Ne postoje dozvoljene putanje do share-ovane biblioteke"
+ slo "Neprípustné ¾iadne cesty k zdieµanej kni¾nici"
+ spa "No pasos permitidos para librarias conjugadas"
+ swe "Man får inte ange sökväg för dynamiska bibliotek"
+ ukr "îÅ ÄÏÚ×ÏÌÅÎÏ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÐÕÔ¦ ÄÌÑ ÒÏÚĦÌÀ×ÁÎÉÈ Â¦Â̦ÏÔÅË"
+ER_UDF_EXISTS
+ cze "Funkce '%-.64s' ji-B¾ existuje"
+ dan "Funktionen '%-.64s' findes allerede"
+ nla "Functie '%-.64s' bestaat reeds"
+ eng "Function '%-.64s' already exists"
+ jps "Function '%-.64s' ‚ÍŠù‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚·",
+ est "Funktsioon '%-.64s' juba eksisteerib"
+ fre "La fonction '%-.64s' existe déjà"
+ ger "Funktion '%-.64s' existiert schon"
+ greek "Ç óõíÜñôçóç '%-.64s' õðÜñ÷åé Þäç"
+ hun "A '%-.64s' fuggveny mar letezik"
+ ita "La funzione '%-.64s' esiste gia`"
+ jpn "Function '%-.64s' ¤Ï´û¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤¹"
+ kor "'%-.64s' ÇÔ¼ö´Â ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù."
+ por "Função '%-.64s' já existe"
+ rum "Functia '%-.64s' exista deja"
+ rus "æÕÎËÃÉÑ '%-.64s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Funkcija '%-.64s' veæ postoji"
+ slo "Funkcia '%-.64s' u¾ existuje"
+ spa "Función '%-.64s' ya existe"
+ swe "Funktionen '%-.64s' finns redan"
+ ukr "æÕÎËÃ¦Ñ '%-.64s' ×ÖÅ ¦ÓÎÕ¤"
+ER_CANT_OPEN_LIBRARY
+ cze "Nemohu otev-Bøít sdílenou knihovnu '%-.64s' (errno: %d %s)"
+ dan "Kan ikke åbne delt bibliotek '%-.64s' (errno: %d %s)"
+ nla "Kan shared library '%-.64s' niet openen (Errcode: %d %s)"
+ eng "Can't open shared library '%-.64s' (errno: %d %-.64s)"
+ jps "shared library '%-.64s' ‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d %s)",
+ est "Ei suuda avada jagatud teeki '%-.64s' (veakood: %d %-.64s)"
+ fre "Impossible d'ouvrir la bibliothèque partagée '%-.64s' (errno: %d %s)"
+ ger "Kann Shared Library '%-.64s' nicht öffnen (Fehler: %d %-.64s)"
+ greek "Äåí åßíáé äõíáôÞ ç áíÜãíùóç ôçò shared library '%-.64s' (êùäéêüò ëÜèïõò: %d %s)"
+ hun "A(z) '%-.64s' megosztott konyvtar nem hasznalhato (hibakod: %d %s)"
+ ita "Impossibile aprire la libreria condivisa '%-.64s' (errno: %d %s)"
+ jpn "shared library '%-.64s' ¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d %s)"
+ kor "'%-.64s' °øÀ¯ ¶óÀ̹ö·¯¸®¸¦ ¿­¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£: %d %s)"
+ nor "Can't open shared library '%-.64s' (errno: %d %s)"
+ norwegian-ny "Can't open shared library '%-.64s' (errno: %d %s)"
+ pol "Can't open shared library '%-.64s' (errno: %d %s)"
+ por "Não pode abrir biblioteca compartilhada '%-.64s' (erro no. '%d' - '%-.64s')"
+ rum "Nu pot deschide libraria shared '%-.64s' (Eroare: %d %-.64s)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÄÉÎÁÍÉÞÅÓËÕÀ ÂÉÂÌÉÏÔÅËÕ '%-.64s' (ÏÛÉÂËÁ: %d %-.64s)"
+ serbian "Ne mogu da otvorim share-ovanu biblioteku '%-.64s' (errno: %d %-.64s)"
+ slo "Nemô¾em otvori» zdieµanú kni¾nicu '%-.64s' (chybový kód: %d %s)"
+ spa "No puedo abrir libraria conjugada '%-.64s' (errno: %d %s)"
+ swe "Kan inte öppna det dynamiska biblioteket '%-.64s' (Felkod: %d %s)"
+ ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÒÏÚĦÌÀ×ÁÎÕ Â¦Â̦ÏÔÅËÕ '%-.64s' (ÐÏÍÉÌËÁ: %d %-.64s)"
+ER_CANT_FIND_DL_ENTRY
+ cze "Nemohu naj-Bít funkci '%-.64s' v knihovnì'"
+ dan "Kan ikke finde funktionen '%-.64s' i bibliotek'"
+ nla "Kan functie '%-.64s' niet in library vinden"
+ eng "Can't find function '%-.64s' in library'"
+ jps "function '%-.64s' ‚ðƒ‰ƒCƒuƒ‰ƒŠ[’†‚ÉŒ©•t‚¯‚鎖‚ª‚Å‚«‚Ü‚¹‚ñ",
+ est "Ei leia funktsiooni '%-.64s' antud teegis"
+ fre "Impossible de trouver la fonction '%-.64s' dans la bibliothèque'"
+ ger "Kann Funktion '%-.64s' in der Library nicht finden"
+ greek "Äåí åßíáé äõíáôÞ ç áíåýñåóç ôçò óõíÜñôçóçò '%-.64s' óôçí âéâëéïèÞêç'"
+ hun "A(z) '%-.64s' fuggveny nem talalhato a konyvtarban"
+ ita "Impossibile trovare la funzione '%-.64s' nella libreria"
+ jpn "function '%-.64s' ¤ò¥é¥¤¥Ö¥é¥ê¡¼Ãæ¤Ë¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó"
+ kor "¶óÀ̹ö·¯¸®¿¡¼­ '%-.64s' ÇÔ¼ö¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù."
+ por "Não pode encontrar a função '%-.64s' na biblioteca"
+ rum "Nu pot gasi functia '%-.64s' in libraria"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÏÔÙÓËÁÔØ ÆÕÎËÃÉÀ '%-.64s' × ÂÉÂÌÉÏÔÅËÅ"
+ serbian "Ne mogu da pronadjem funkciju '%-.64s' u biblioteci"
+ slo "Nemô¾em nájs» funkciu '%-.64s' v kni¾nici'"
+ spa "No puedo encontrar función '%-.64s' en libraria'"
+ swe "Hittar inte funktionen '%-.64s' in det dynamiska biblioteket"
+ ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ ÆÕÎËæÀ '%-.64s' Õ Â¦Â̦ÏÔÅæ'"
+ER_FUNCTION_NOT_DEFINED
+ cze "Funkce '%-.64s' nen-Bí definována"
+ dan "Funktionen '%-.64s' er ikke defineret"
+ nla "Functie '%-.64s' is niet gedefinieerd"
+ eng "Function '%-.64s' is not defined"
+ jps "Function '%-.64s' ‚Í’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Funktsioon '%-.64s' ei ole defineeritud"
+ fre "La fonction '%-.64s' n'est pas définie"
+ ger "Funktion '%-.64s' ist nicht definiert"
+ greek "Ç óõíÜñôçóç '%-.64s' äåí Ý÷åé ïñéóèåß"
+ hun "A '%-.64s' fuggveny nem definialt"
+ ita "La funzione '%-.64s' non e` definita"
+ jpn "Function '%-.64s' ¤ÏÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "'%-.64s' ÇÔ¼ö°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù."
+ por "Função '%-.64s' não está definida"
+ rum "Functia '%-.64s' nu e definita"
+ rus "æÕÎËÃÉÑ '%-.64s' ÎÅ ÏÐÒÅÄÅÌÅÎÁ"
+ serbian "Funkcija '%-.64s' nije definisana"
+ slo "Funkcia '%-.64s' nie je definovaná"
+ spa "Función '%-.64s' no está definida"
+ swe "Funktionen '%-.64s' är inte definierad"
+ ukr "æÕÎËæÀ '%-.64s' ÎÅ ×ÉÚÎÁÞÅÎÏ"
+ER_HOST_IS_BLOCKED
+ cze "Stroj '%-.64s' je zablokov-Bán kvùli mnoha chybám pøi pøipojování. Odblokujete pou¾itím 'mysqladmin flush-hosts'"
+ dan "Værten er blokeret på grund af mange fejlforespørgsler. Lås op med 'mysqladmin flush-hosts'"
+ nla "Host '%-.64s' is geblokkeeerd vanwege te veel verbindings fouten. Deblokkeer met 'mysqladmin flush-hosts'"
+ eng "Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'"
+ jps "Host '%-.64s' ‚Í many connection error ‚Ì‚½‚ßA‹‘”Û‚³‚ê‚Ü‚µ‚½. 'mysqladmin flush-hosts' ‚ʼn𜂵‚Ä‚­‚¾‚³‚¢",
+ est "Masin '%-.64s' on blokeeritud hulgaliste ühendusvigade tõttu. Blokeeringu saab tühistada 'mysqladmin flush-hosts' käsuga"
+ fre "L'hôte '%-.64s' est bloqué à cause d'un trop grand nombre d'erreur de connection. Débloquer le par 'mysqladmin flush-hosts'"
+ ger "Host '%-.64s' blockiert wegen zu vieler Verbindungsfehler. Aufheben der Blockierung mit 'mysqladmin flush-hosts'"
+ greek "Ï õðïëïãéóôÞò Ý÷åé áðïêëåéóèåß ëüãù ðïëëáðëþí ëáèþí óýíäåóçò. ÐñïóðáèÞóôå íá äéïñþóåôå ìå 'mysqladmin flush-hosts'"
+ hun "A '%-.64s' host blokkolodott, tul sok kapcsolodasi hiba miatt. Hasznalja a 'mysqladmin flush-hosts' parancsot"
+ ita "Sistema '%-.64s' bloccato a causa di troppi errori di connessione. Per sbloccarlo: 'mysqladmin flush-hosts'"
+ jpn "Host '%-.64s' ¤Ï many connection error ¤Î¤¿¤á¡¢µñÈݤµ¤ì¤Þ¤·¤¿. 'mysqladmin flush-hosts' ¤Ç²ò½ü¤·¤Æ¤¯¤À¤µ¤¤"
+ kor "³Ê¹« ¸¹Àº ¿¬°á¿À·ù·Î ÀÎÇÏ¿© È£½ºÆ® '%-.64s'´Â ºí¶ôµÇ¾ú½À´Ï´Ù. 'mysqladmin flush-hosts'¸¦ ÀÌ¿ëÇÏ¿© ºí¶ôÀ» ÇØÁ¦Çϼ¼¿ä"
+ por "'Host' '%-.64s' está bloqueado devido a muitos erros de conexão. Desbloqueie com 'mysqladmin flush-hosts'"
+ rum "Host-ul '%-.64s' e blocat din cauza multelor erori de conectie. Poti deploca folosind 'mysqladmin flush-hosts'"
+ rus "èÏÓÔ '%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÉÚ-ÚÁ ÓÌÉÛËÏÍ ÂÏÌØÛÏÇÏ ËÏÌÉÞÅÓÔ×Á ÏÛÉÂÏË ÓÏÅÄÉÎÅÎÉÑ. òÁÚÂÌÏËÉÒÏ×ÁÔØ ÅÇÏ ÍÏÖÎÏ Ó ÐÏÍÏÝØÀ 'mysqladmin flush-hosts'"
+ serbian "Host '%-.64s' je blokiran zbog previše grešaka u konekciji. Možete ga odblokirati pomoæu komande 'mysqladmin flush-hosts'"
+ spa "Servidor '%-.64s' está bloqueado por muchos errores de conexión. Desbloquear con 'mysqladmin flush-hosts'"
+ swe "Denna dator, '%-.64s', är blockerad pga många felaktig paket. Gör 'mysqladmin flush-hosts' för att ta bort alla blockeringarna"
+ ukr "èÏÓÔ '%-.64s' ÚÁÂÌÏËÏ×ÁÎÏ Ú ÐÒÉÞÉÎÉ ×ÅÌÉËϧ ˦ÌØËÏÓÔ¦ ÐÏÍÉÌÏË Ú'¤ÄÎÁÎÎÑ. äÌÑ ÒÏÚÂÌÏËÕ×ÁÎÎÑ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ 'mysqladmin flush-hosts'"
+ER_HOST_NOT_PRIVILEGED
+ cze "Stroj '%-.64s' nem-Bá povoleno se k tomuto MySQL serveru pøipojit"
+ dan "Værten '%-.64s' kan ikke tilkoble denne MySQL-server"
+ nla "Het is host '%-.64s' is niet toegestaan verbinding te maken met deze MySQL server"
+ eng "Host '%-.64s' is not allowed to connect to this MySQL server"
+ jps "Host '%-.64s' ‚Í MySQL server ‚ÉÚ‘±‚ð‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Masinal '%-.64s' puudub ligipääs sellele MySQL serverile"
+ fre "Le hôte '%-.64s' n'est pas authorisé à se connecter à ce serveur MySQL"
+ ger "Host '%-.64s' hat keine Berechtigung, sich mit diesem MySQL-Server zu verbinden"
+ greek "Ï õðïëïãéóôÞò äåí Ý÷åé äéêáßùìá óýíäåóçò ìå ôïí MySQL server"
+ hun "A '%-.64s' host szamara nem engedelyezett a kapcsolodas ehhez a MySQL szerverhez"
+ ita "Al sistema '%-.64s' non e` consentita la connessione a questo server MySQL"
+ jpn "Host '%-.64s' ¤Ï MySQL server ¤ËÀܳ¤òµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "'%-.64s' È£½ºÆ®´Â ÀÌ MySQL¼­¹ö¿¡ Á¢¼ÓÇÒ Çã°¡¸¦ ¹ÞÁö ¸øÇß½À´Ï´Ù."
+ por "'Host' '%-.64s' não tem permissão para se conectar com este servidor MySQL"
+ rum "Host-ul '%-.64s' nu este permis a se conecta la aceste server MySQL"
+ rus "èÏÓÔÕ '%-.64s' ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÐÏÄËÌÀÞÁÔØÓÑ Ë ÜÔÏÍÕ ÓÅÒ×ÅÒÕ MySQL"
+ serbian "Host-u '%-.64s' nije dozvoljeno da se konektuje na ovaj MySQL server"
+ spa "Servidor '%-.64s' no está permitido para conectar con este servidor MySQL"
+ swe "Denna dator, '%-.64s', har inte privileger att använda denna MySQL server"
+ ukr "èÏÓÔÕ '%-.64s' ÎÅ ÄÏ×ÏÌÅÎÏ Ú×'ÑÚÕ×ÁÔÉÓØ Ú ÃÉÍ ÓÅÒ×ÅÒÏÍ MySQL"
+ER_PASSWORD_ANONYMOUS_USER 42000
+ cze "Pou-B¾íváte MySQL jako anonymní u¾ivatel a anonymní u¾ivatelé nemají povoleno mìnit hesla"
+ dan "Du bruger MySQL som anonym bruger. Anonyme brugere må ikke ændre adgangskoder"
+ nla "U gebruikt MySQL als anonieme gebruiker en deze mogen geen wachtwoorden wijzigen"
+ eng "You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords"
+ jps "MySQL ‚ð anonymous users ‚ÅŽg—p‚µ‚Ä‚¢‚éó‘Ô‚Å‚ÍAƒpƒXƒ[ƒh‚Ì•ÏX‚Í‚Å‚«‚Ü‚¹‚ñ",
+ est "Te kasutate MySQL-i anonüümse kasutajana, kelledel pole parooli muutmise õigust"
+ fre "Vous utilisez un utilisateur anonyme et les utilisateurs anonymes ne sont pas autorisés à changer les mots de passe"
+ ger "Sie benutzen MySQL als anonymer Benutzer und dürfen daher keine Passwörter ändern"
+ greek "×ñçóéìïðïéåßôå ôçí MySQL óáí anonymous user êáé Ýôóé äåí ìðïñåßôå íá áëëÜîåôå ôá passwords Üëëùí ÷ñçóôþí"
+ hun "Nevtelen (anonymous) felhasznalokent nem negedelyezett a jelszovaltoztatas"
+ ita "Impossibile cambiare la password usando MySQL come utente anonimo"
+ jpn "MySQL ¤ò anonymous users ¤Ç»ÈÍѤ·¤Æ¤¤¤ë¾õÂ֤Ǥϡ¢¥Ñ¥¹¥ï¡¼¥É¤ÎÊѹ¹¤Ï¤Ç¤­¤Þ¤»¤ó"
+ kor "´ç½ÅÀº MySQL¼­¹ö¿¡ À͸íÀÇ »ç¿ëÀÚ·Î Á¢¼ÓÀ» Çϼ̽À´Ï´Ù.À͸íÀÇ »ç¿ëÀÚ´Â ¾ÏÈ£¸¦ º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù."
+ por "Você está usando o MySQL como usuário anônimo e usuários anônimos não têm permissão para mudar senhas"
+ rum "Dumneavoastra folositi MySQL ca un utilizator anonim si utilizatorii anonimi nu au voie sa schime parolele"
+ rus "÷Ù ÉÓÐÏÌØÚÕÅÔÅ MySQL ÏÔ ÉÍÅÎÉ ÁÎÏÎÉÍÎÏÇÏ ÐÏÌØÚÏ×ÁÔÅÌÑ, Á ÁÎÏÎÉÍÎÙÍ ÐÏÌØÚÏ×ÁÔÅÌÑÍ ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÍÅÎÑÔØ ÐÁÒÏÌÉ"
+ serbian "Vi koristite MySQL kao anonimni korisnik a anonimnim korisnicima nije dozvoljeno da menjaju lozinke"
+ spa "Tu estás usando MySQL como un usuario anonimo y usuarios anonimos no tienen permiso para cambiar las claves"
+ swe "Du använder MySQL som en anonym användare och som sådan får du inte ändra ditt lösenord"
+ ukr "÷É ×ÉËÏÒÉÓÔÏ×Õ¤ÔÅ MySQL ÑË ÁÎÏΦÍÎÉÊ ËÏÒÉÓÔÕ×ÁÞ, ÔÏÍÕ ×ÁÍ ÎÅ ÄÏÚ×ÏÌÅÎÏ ÚͦÎÀ×ÁÔÉ ÐÁÒÏ̦"
+ER_PASSWORD_NOT_ALLOWED 42000
+ cze "Na zm-Bìnu hesel ostatním musíte mít právo provést update tabulek v databázi mysql"
+ dan "Du skal have tilladelse til at opdatere tabeller i MySQL databasen for at ændre andres adgangskoder"
+ nla "U moet tabel update priveleges hebben in de mysql database om wachtwoorden voor anderen te mogen wijzigen"
+ eng "You must have privileges to update tables in the mysql database to be able to change passwords for others"
+ jps "‘¼‚̃†[ƒU[‚̃pƒXƒ[ƒh‚ð•ÏX‚·‚邽‚ß‚É‚Í, mysql ƒf[ƒ^ƒx[ƒX‚ɑ΂µ‚Ä update ‚Ì‹–‰Â‚ª‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ.",
+ est "Teiste paroolide muutmiseks on nõutav tabelite muutmisõigus 'mysql' andmebaasis"
+ fre "Vous devez avoir le privilège update sur les tables de la base de donnée mysql pour pouvoir changer les mots de passe des autres"
+ ger "Sie benötigen die Berechtigung zum Aktualisieren von Tabellen in der Datenbank 'mysql', um die Passwörter anderer Benutzer ändern zu können"
+ greek "ÐñÝðåé íá Ý÷åôå äéêáßùìá äéüñèùóçò ðéíÜêùí (update) óôç âÜóç äåäïìÝíùí mysql ãéá íá ìðïñåßôå íá áëëÜîåôå ôá passwords Üëëùí ÷ñçóôþí"
+ hun "Onnek tabla-update joggal kell rendelkeznie a mysql adatbazisban masok jelszavanak megvaltoztatasahoz"
+ ita "E` necessario il privilegio di update sulle tabelle del database mysql per cambiare le password per gli altri utenti"
+ jpn "¾¤Î¥æ¡¼¥¶¡¼¤Î¥Ñ¥¹¥ï¡¼¥É¤òÊѹ¹¤¹¤ë¤¿¤á¤Ë¤Ï, mysql ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ËÂФ·¤Æ update ¤Îµö²Ä¤¬¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó."
+ kor "´ç½ÅÀº ´Ù¸¥»ç¿ëÀÚµéÀÇ ¾ÏÈ£¸¦ º¯°æÇÒ ¼ö ÀÖµµ·Ï µ¥ÀÌŸº£À̽º º¯°æ±ÇÇÑÀ» °¡Á®¾ß ÇÕ´Ï´Ù."
+ por "Você deve ter privilégios para atualizar tabelas no banco de dados mysql para ser capaz de mudar a senha de outros"
+ rum "Trebuie sa aveti privilegii sa actualizati tabelele in bazele de date mysql ca sa puteti sa schimati parolele altora"
+ rus "äÌÑ ÔÏÇÏ ÞÔÏÂÙ ÉÚÍÅÎÑÔØ ÐÁÒÏÌÉ ÄÒÕÇÉÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ, Õ ×ÁÓ ÄÏÌÖÎÙ ÂÙÔØ ÐÒÉ×ÉÌÅÇÉÉ ÎÁ ÉÚÍÅÎÅÎÉÅ ÔÁÂÌÉÃ × ÂÁÚÅ ÄÁÎÎÙÈ mysql"
+ serbian "Morate imati privilegije da možete da update-ujete odreðene tabele ako želite da menjate lozinke za druge korisnike"
+ spa "Tu debes de tener permiso para actualizar tablas en la base de datos mysql para cambiar las claves para otros"
+ swe "För att ändra lösenord för andra måste du ha rättigheter att uppdatera mysql-databasen"
+ ukr "÷É ÐÏ×ÉΦ ÍÁÔÉ ÐÒÁ×Ï ÎÁ ÏÎÏ×ÌÅÎÎÑ ÔÁÂÌÉÃØ Õ ÂÁÚ¦ ÄÁÎÎÉÈ mysql, ÁÂÉ ÍÁÔÉ ÍÏÖÌÉצÓÔØ ÚͦÎÀ×ÁÔÉ ÐÁÒÏÌØ ¦ÎÛÉÍ"
+ER_PASSWORD_NO_MATCH 42000
+ cze "V tabulce user nen-Bí ¾ádný odpovídající øádek"
+ dan "Kan ikke finde nogen tilsvarende poster i bruger tabellen"
+ nla "Kan geen enkele passende rij vinden in de gebruikers tabel"
+ eng "Can't find any matching row in the user table"
+ est "Ei leia vastavat kirjet kasutajate tabelis"
+ fre "Impossible de trouver un enregistrement correspondant dans la table user"
+ ger "Kann keinen passenden Datensatz in Tabelle 'user' finden"
+ greek "Äåí åßíáé äõíáôÞ ç áíåýñåóç ôçò áíôßóôïé÷çò åããñáöÞò óôïí ðßíáêá ôùí ÷ñçóôþí"
+ hun "Nincs megegyezo sor a user tablaban"
+ ita "Impossibile trovare la riga corrispondente nella tabella user"
+ kor "»ç¿ëÀÚ Å×ÀÌºí¿¡¼­ ÀÏÄ¡ÇÏ´Â °ÍÀ» ãÀ» ¼ö ¾øÀ¾´Ï´Ù."
+ por "Não pode encontrar nenhuma linha que combine na tabela usuário (user table)"
+ rum "Nu pot gasi nici o linie corespunzatoare in tabela utilizatorului"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÏÔÙÓËÁÔØ ÐÏÄÈÏÄÑÝÕÀ ÚÁÐÉÓØ × ÔÁÂÌÉÃÅ ÐÏÌØÚÏ×ÁÔÅÌÅÊ"
+ serbian "Ne mogu da pronaðem odgovarajuæi slog u 'user' tabeli"
+ spa "No puedo encontrar una línea correponsdiente en la tabla user"
+ swe "Hittade inte användaren i 'user'-tabellen"
+ ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ ×¦ÄÐÏצÄÎÉÈ ÚÁÐÉÓ¦× Õ ÔÁÂÌÉæ ËÏÒÉÓÔÕ×ÁÞÁ"
+ER_UPDATE_INFO
+ cze "Nalezen-Bých øádkù: %ld Zmìnìno: %ld Varování: %ld"
+ dan "Poster fundet: %ld Ændret: %ld Advarsler: %ld"
+ nla "Passende rijen: %ld Gewijzigd: %ld Waarschuwingen: %ld"
+ eng "Rows matched: %ld Changed: %ld Warnings: %ld"
+ jps "ˆê’v”(Rows matched): %ld •ÏX: %ld Warnings: %ld",
+ est "Sobinud kirjeid: %ld Muudetud: %ld Hoiatusi: %ld"
+ fre "Enregistrements correspondants: %ld Modifiés: %ld Warnings: %ld"
+ ger "Datensätze gefunden: %ld Geändert: %ld Warnungen: %ld"
+ hun "Megegyezo sorok szama: %ld Valtozott: %ld Warnings: %ld"
+ ita "Rows riconosciute: %ld Cambiate: %ld Warnings: %ld"
+ jpn "°ìÃ׿ô(Rows matched): %ld Êѹ¹: %ld Warnings: %ld"
+ kor "ÀÏÄ¡ÇÏ´Â Rows : %ld°³ º¯°æµÊ: %ld°³ °æ°í: %ld°³"
+ por "Linhas que combinaram: %ld - Alteradas: %ld - Avisos: %ld"
+ rum "Linii identificate (matched): %ld Schimbate: %ld Atentionari (warnings): %ld"
+ rus "óÏ×ÐÁÌÏ ÚÁÐÉÓÅÊ: %ld éÚÍÅÎÅÎÏ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld"
+ serbian "Odgovarajuæih slogova: %ld Promenjeno: %ld Upozorenja: %ld"
+ spa "Líneas correspondientes: %ld Cambiadas: %ld Avisos: %ld"
+ swe "Rader: %ld Uppdaterade: %ld Varningar: %ld"
+ ukr "úÁÐÉÓ¦× ×¦ÄÐÏצÄÁ¤: %ld úͦÎÅÎÏ: %ld úÁÓÔÅÒÅÖÅÎØ: %ld"
+ER_CANT_CREATE_THREAD
+ cze "Nemohu vytvo-Bøit nový thread (errno %d). Pokud je je¹tì nìjaká volná pamì», podívejte se do manuálu na èást o chybách specifických pro jednotlivé operaèní systémy"
+ dan "Kan ikke danne en ny tråd (fejl nr. %d). Hvis computeren ikke er løbet tør for hukommelse, kan du se i brugervejledningen for en mulig operativ-system - afhængig fejl"
+ nla "Kan geen nieuwe thread aanmaken (Errcode: %d). Indien er geen tekort aan geheugen is kunt u de handleiding consulteren over een mogelijke OS afhankelijke fout"
+ eng "Can't create a new thread (errno %d); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug"
+ jps "V‹K‚ɃXƒŒƒbƒh‚ªì‚ê‚Ü‚¹‚ñ‚Å‚µ‚½ (errno %d). ‚à‚µÅ‘åŽg—p‹–‰Âƒƒ‚ƒŠ[”‚ð‰z‚¦‚Ä‚¢‚È‚¢‚̂ɃGƒ‰[‚ª”­¶‚µ‚Ä‚¢‚é‚È‚ç, ƒ}ƒjƒ…ƒAƒ‹‚Ì’†‚©‚ç 'possible OS-dependent bug' ‚Æ‚¢‚¤•¶Žš‚ð’T‚µ‚Ä‚­‚Ý‚Ä‚¾‚³‚¢.",
+ est "Ei suuda luua uut lõime (veakood %d). Kui mälu ei ole otsas, on tõenäoliselt tegemist operatsioonisüsteemispetsiifilise veaga"
+ fre "Impossible de créer une nouvelle tâche (errno %d). S'il reste de la mémoire libre, consultez le manual pour trouver un éventuel bug dépendant de l'OS"
+ ger "Kann keinen neuen Thread erzeugen (Fehler: %d). Sollte noch Speicher verfügbar sein, bitte im Handbuch wegen möglicher Fehler im Betriebssystem nachschlagen"
+ hun "Uj thread letrehozasa nem lehetseges (Hibakod: %d). Amenyiben van meg szabad memoria, olvassa el a kezikonyv operacios rendszerfuggo hibalehetosegekrol szolo reszet"
+ ita "Impossibile creare un nuovo thread (errno %d). Se non ci sono problemi di memoria disponibile puoi consultare il manuale per controllare possibili problemi dipendenti dal SO"
+ jpn "¿·µ¬¤Ë¥¹¥ì¥Ã¥É¤¬ºî¤ì¤Þ¤»¤ó¤Ç¤·¤¿ (errno %d). ¤â¤·ºÇÂç»ÈÍѵö²Ä¥á¥â¥ê¡¼¿ô¤ò±Û¤¨¤Æ¤¤¤Ê¤¤¤Î¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Æ¤¤¤ë¤Ê¤é, ¥Þ¥Ë¥å¥¢¥ë¤ÎÃ椫¤é 'possible OS-dependent bug' ¤È¤¤¤¦Ê¸»ú¤òõ¤·¤Æ¤¯¤ß¤Æ¤À¤µ¤¤."
+ kor "»õ·Î¿î ¾²·¹µå¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£ %d). ¸¸¾à ¿©À¯¸Þ¸ð¸®°¡ ÀÖ´Ù¸é OS-dependent¹ö±× ÀÇ ¸Þ´º¾ó ºÎºÐÀ» ã¾Æº¸½Ã¿À."
+ nor "Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug"
+ norwegian-ny "Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug"
+ pol "Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug"
+ por "Não pode criar uma nova 'thread' (erro no. %d). Se você não estiver sem memória disponível, você pode consultar o manual sobre um possível 'bug' dependente do sistema operacional"
+ rum "Nu pot crea un thread nou (Eroare %d). Daca mai aveti memorie disponibila in sistem, puteti consulta manualul - ar putea exista un potential bug in legatura cu sistemul de operare"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÎÏ×ÙÊ ÐÏÔÏË (ÏÛÉÂËÁ %d). åÓÌÉ ÜÔÏ ÎÅ ÓÉÔÕÁÃÉÑ, Ó×ÑÚÁÎÎÁÑ Ó ÎÅÈ×ÁÔËÏÊ ÐÁÍÑÔÉ, ÔÏ ×ÁÍ ÓÌÅÄÕÅÔ ÉÚÕÞÉÔØ ÄÏËÕÍÅÎÔÁÃÉÀ ÎÁ ÐÒÅÄÍÅÔ ÏÐÉÓÁÎÉÑ ×ÏÚÍÏÖÎÏÊ ÏÛÉÂËÉ ÒÁÂÏÔÙ × ËÏÎËÒÅÔÎÏÊ ïó"
+ serbian "Ne mogu da kreiram novi thread (errno %d). Ako imate još slobodne memorije, trebali biste da pogledate u priruèniku da li je ovo specifièna greška vašeg operativnog sistema"
+ spa "No puedo crear un nuevo thread (errno %d). Si tu está con falta de memoria disponible, tu puedes consultar el Manual para posibles problemas con SO"
+ swe "Kan inte skapa en ny tråd (errno %d)"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÎÏ×Õ Ç¦ÌËÕ (ÐÏÍÉÌËÁ %d). ñËÝÏ ×É ÎÅ ×ÉËÏÒÉÓÔÁÌÉ ÕÓÀ ÐÁÍ'ÑÔØ, ÔÏ ÐÒÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ ÄÏ ×ÁÛϧ ïó - ÍÏÖÌÉ×Ï ÃÅ ÐÏÍÉÌËÁ ïó"
+ER_WRONG_VALUE_COUNT_ON_ROW 21S01
+ cze "Po-Bèet sloupcù neodpovídá poètu hodnot na øádku %ld"
+ dan "Kolonne antallet stemmer ikke overens med antallet af værdier i post %ld"
+ nla "Kolom aantal komt niet overeen met waarde aantal in rij %ld"
+ eng "Column count doesn't match value count at row %ld"
+ est "Tulpade hulk erineb väärtuste hulgast real %ld"
+ ger "Anzahl der Spalten stimmt nicht mit der Anzahl der Werte in Zeile %ld überein"
+ hun "Az oszlopban talalhato ertek nem egyezik meg a %ld sorban szamitott ertekkel"
+ ita "Il numero delle colonne non corrisponde al conteggio alla riga %ld"
+ kor "Row %ld¿¡¼­ Ä®·³ Ä«¿îÆ®¿Í value Ä«¿îÅÍ¿Í ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù."
+ por "Contagem de colunas não confere com a contagem de valores na linha %ld"
+ rum "Numarul de coloane nu corespunde cu numarul de valori la linia %ld"
+ rus "ëÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ× ÎÅ ÓÏ×ÐÁÄÁÅÔ Ó ËÏÌÉÞÅÓÔ×ÏÍ ÚÎÁÞÅÎÉÊ × ÚÁÐÉÓÉ %ld"
+ serbian "Broj kolona ne odgovara broju vrednosti u slogu %ld"
+ spa "El número de columnas no corresponde al número en la línea %ld"
+ swe "Antalet kolumner motsvarar inte antalet värden på rad: %ld"
+ ukr "ë¦ÌØ˦ÓÔØ ÓÔÏ×ÂÃ¦× ÎÅ ÓЦ×ÐÁÄÁ¤ Ú Ë¦ÌØ˦ÓÔÀ ÚÎÁÞÅÎØ Õ ÓÔÒÏæ %ld"
+ER_CANT_REOPEN_TABLE
+ cze "Nemohu znovuotev-Bøít tabulku: '%-.64s"
+ dan "Kan ikke genåbne tabel '%-.64s"
+ nla "Kan tabel niet opnieuw openen: '%-.64s"
+ eng "Can't reopen table: '%-.64s'"
+ est "Ei suuda taasavada tabelit '%-.64s'"
+ fre "Impossible de réouvrir la table: '%-.64s"
+ ger "Kann Tabelle'%-.64s' nicht erneut öffnen"
+ hun "Nem lehet ujra-megnyitni a tablat: '%-.64s"
+ ita "Impossibile riaprire la tabella: '%-.64s'"
+ kor "Å×À̺íÀ» ´Ù½Ã ¿­¼ö ¾ø±º¿ä: '%-.64s"
+ nor "Can't reopen table: '%-.64s"
+ norwegian-ny "Can't reopen table: '%-.64s"
+ pol "Can't reopen table: '%-.64s"
+ por "Não pode reabrir a tabela '%-.64s"
+ rum "Nu pot redeschide tabela: '%-.64s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÎÏ×Ï ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ '%-.64s'"
+ serbian "Ne mogu da ponovo otvorim tabelu '%-.64s'"
+ slo "Can't reopen table: '%-.64s"
+ spa "No puedo reabrir tabla: '%-.64s"
+ swe "Kunde inte stänga och öppna tabell '%-.64s"
+ ukr "îÅ ÍÏÖÕ ÐÅÒÅצÄËÒÉÔÉ ÔÁÂÌÉÃÀ: '%-.64s'"
+ER_INVALID_USE_OF_NULL 22004
+ cze "Neplatn-Bé u¾ití hodnoty NULL"
+ dan "Forkert brug af nulværdi (NULL)"
+ nla "Foutief gebruik van de NULL waarde"
+ eng "Invalid use of NULL value"
+ jps "NULL ’l‚ÌŽg—p•û–@‚ª•s“KØ‚Å‚·",
+ est "NULL väärtuse väärkasutus"
+ fre "Utilisation incorrecte de la valeur NULL"
+ ger "Unerlaubte Verwendung eines NULL-Werts"
+ hun "A NULL ervenytelen hasznalata"
+ ita "Uso scorretto del valore NULL"
+ jpn "NULL ÃͤλÈÍÑÊýË¡¤¬ÉÔŬÀڤǤ¹"
+ kor "NULL °ªÀ» À߸ø »ç¿ëÇϼ̱º¿ä..."
+ por "Uso inválido do valor NULL"
+ rum "Folosirea unei value NULL e invalida"
+ rus "îÅÐÒÁ×ÉÌØÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ×ÅÌÉÞÉÎÙ NULL"
+ serbian "Pogrešna upotreba vrednosti NULL"
+ spa "Invalido uso de valor NULL"
+ swe "Felaktig använding av NULL"
+ ukr "èÉÂÎÅ ×ÉËÏÒÉÓÔÁÎÎÑ ÚÎÁÞÅÎÎÑ NULL"
+ER_REGEXP_ERROR 42000
+ cze "Regul-Bární výraz vrátil chybu '%-.64s'"
+ dan "Fik fejl '%-.64s' fra regexp"
+ nla "Fout '%-.64s' ontvangen van regexp"
+ eng "Got error '%-.64s' from regexp"
+ est "regexp tagastas vea '%-.64s'"
+ fre "Erreur '%-.64s' provenant de regexp"
+ ger "regexp lieferte Fehler '%-.64s'"
+ hun "'%-.64s' hiba a regularis kifejezes hasznalata soran (regexp)"
+ ita "Errore '%-.64s' da regexp"
+ kor "regexp¿¡¼­ '%-.64s'°¡ ³µ½À´Ï´Ù."
+ por "Obteve erro '%-.64s' em regexp"
+ rum "Eroarea '%-.64s' obtinuta din expresia regulara (regexp)"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ '%-.64s' ÏÔ ÒÅÇÕÌÑÒÎÏÇÏ ×ÙÒÁÖÅÎÉÑ"
+ serbian "Funkcija regexp je vratila grešku '%-.64s'"
+ spa "Obtenido error '%-.64s' de regexp"
+ swe "Fick fel '%-.64s' från REGEXP"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ '%-.64s' ×¦Ä ÒÅÇÕÌÑÒÎÏÇÏ ×ÉÒÁÚÕ"
+ER_MIX_OF_GROUP_FUNC_AND_FIELDS 42000
+ cze "Pokud nen-Bí ¾ádná GROUP BY klauzule, není dovoleno souèasné pou¾ití GROUP polo¾ek (MIN(),MAX(),COUNT()...) s ne GROUP polo¾kami"
+ dan "Sammenblanding af GROUP kolonner (MIN(),MAX(),COUNT()...) uden GROUP kolonner er ikke tilladt, hvis der ikke er noget GROUP BY prædikat"
+ nla "Het mixen van GROUP kolommen (MIN(),MAX(),COUNT()...) met no-GROUP kolommen is foutief indien er geen GROUP BY clausule is"
+ eng "Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause"
+ est "GROUP tulpade (MIN(),MAX(),COUNT()...) kooskasutamine tavaliste tulpadega ilma GROUP BY klauslita ei ole lubatud"
+ fre "Mélanger les colonnes GROUP (MIN(),MAX(),COUNT()...) avec des colonnes normales est interdit s'il n'y a pas de clause GROUP BY"
+ ger "Das Vermischen von GROUP-Spalten (MIN(),MAX(),COUNT()...) mit Nicht-GROUP-Spalten ist nicht zulässig, wenn keine GROUP BY-Klausel vorhanden ist"
+ hun "A GROUP mezok (MIN(),MAX(),COUNT()...) kevert hasznalata nem lehetseges GROUP BY hivatkozas nelkul"
+ ita "Il mescolare funzioni di aggregazione (MIN(),MAX(),COUNT()...) e non e` illegale se non c'e` una clausula GROUP BY"
+ kor "Mixing of GROUP Ä®·³s (MIN(),MAX(),COUNT(),...) with no GROUP Ä®·³s is illegal if there is no GROUP BY clause"
+ por "Mistura de colunas agrupadas (com MIN(), MAX(), COUNT(), ...) com colunas não agrupadas é ilegal, se não existir uma cláusula de agrupamento (cláusula GROUP BY)"
+ rum "Amestecarea de coloane GROUP (MIN(),MAX(),COUNT()...) fara coloane GROUP este ilegala daca nu exista o clauza GROUP BY"
+ rus "ïÄÎÏ×ÒÅÍÅÎÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÓÇÒÕÐÐÉÒÏ×ÁÎÎÙÈ (GROUP) ÓÔÏÌÂÃÏ× (MIN(),MAX(),COUNT(),...) Ó ÎÅÓÇÒÕÐÐÉÒÏ×ÁÎÎÙÍÉ ÓÔÏÌÂÃÁÍÉ Ñ×ÌÑÅÔÓÑ ÎÅËÏÒÒÅËÔÎÙÍ, ÅÓÌÉ × ×ÙÒÁÖÅÎÉÉ ÅÓÔØ GROUP BY"
+ serbian "Upotreba agregatnih funkcija (MIN(),MAX(),COUNT()...) bez 'GROUP' kolona je pogrešna ako ne postoji 'GROUP BY' iskaz"
+ spa "Mezcla de columnas GROUP (MIN(),MAX(),COUNT()...) con no GROUP columnas es ilegal si no hat la clausula GROUP BY"
+ swe "Man får ha både GROUP-kolumner (MIN(),MAX(),COUNT()...) och fält i en fråga om man inte har en GROUP BY-del"
+ ukr "úͦÛÕ×ÁÎÎÑ GROUP ÓÔÏ×ÂÃ¦× (MIN(),MAX(),COUNT()...) Ú ÎÅ GROUP ÓÔÏ×ÂÃÑÍÉ ¤ ÚÁÂÏÒÏÎÅÎÉÍ, ÑËÝÏ ÎÅ ÍÁ¤ GROUP BY"
+ER_NONEXISTING_GRANT 42000
+ cze "Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s'"
+ dan "Denne tilladelse findes ikke for brugeren '%-.32s' på vært '%-.64s'"
+ nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.32s' op host '%-.64s'"
+ eng "There is no such grant defined for user '%-.32s' on host '%-.64s'"
+ jps "ƒ†[ƒU[ '%-.32s' (ƒzƒXƒg '%-.64s' ‚̃†[ƒU[) ‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Sellist õigust ei ole defineeritud kasutajale '%-.32s' masinast '%-.64s'"
+ fre "Un tel droit n'est pas défini pour l'utilisateur '%-.32s' sur l'hôte '%-.64s'"
+ ger "Für Benutzer '%-.32s' auf Host '%-.64s' gibt es keine solche Berechtigung"
+ hun "A '%-.32s' felhasznalonak nincs ilyen joga a '%-.64s' host-on"
+ ita "GRANT non definita per l'utente '%-.32s' dalla macchina '%-.64s'"
+ jpn "¥æ¡¼¥¶¡¼ '%-.32s' (¥Û¥¹¥È '%-.64s' ¤Î¥æ¡¼¥¶¡¼) ¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "»ç¿ëÀÚ '%-.32s' (È£½ºÆ® '%-.64s')¸¦ À§ÇÏ¿© Á¤ÀÇµÈ ±×·± ½ÂÀÎÀº ¾ø½À´Ï´Ù."
+ por "Não existe tal permissão (grant) definida para o usuário '%-.32s' no 'host' '%-.64s'"
+ rum "Nu exista un astfel de grant definit pentru utilzatorul '%-.32s' de pe host-ul '%-.64s'"
+ rus "ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' ÎÁ ÈÏÓÔÅ '%-.64s'"
+ serbian "Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s'"
+ spa "No existe permiso definido para usuario '%-.32s' en el servidor '%-.64s'"
+ swe "Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s'"
+ ukr "ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.32s' Ú ÈÏÓÔÕ '%-.64s'"
+ER_TABLEACCESS_DENIED_ERROR 42000
+ cze "%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s'@'%-.64s' pro tabulku '%-.64s'"
+ dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s'@'%-.64s' for tabellen '%-.64s'"
+ nla "%-.16s commando geweigerd voor gebruiker: '%-.32s'@'%-.64s' voor tabel '%-.64s'"
+ eng "%-.16s command denied to user '%-.32s'@'%-.64s' for table '%-.64s'"
+ jps "ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.32s'@'%-.64s' ,ƒe[ƒuƒ‹ '%-.64s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "%-.16s käsk ei ole lubatud kasutajale '%-.32s'@'%-.64s' tabelis '%-.64s'"
+ fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.32s'@'@%-.64s' sur la table '%-.64s'"
+ ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.32s'@'%-.64s' und für Tabelle '%-.64s'"
+ hun "%-.16s parancs a '%-.32s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' tablaban"
+ ita "Comando %-.16s negato per l'utente: '%-.32s'@'%-.64s' sulla tabella '%-.64s'"
+ jpn "¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ,¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s'@'%-.64s' for Å×À̺í '%-.64s'"
+ por "Comando '%-.16s' negado para o usuário '%-.32s'@'%-.64s' na tabela '%-.64s'"
+ rum "Comanda %-.16s interzisa utilizatorului: '%-.32s'@'%-.64s' pentru tabela '%-.64s'"
+ rus "ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s'@'%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'"
+ serbian "%-.16s komanda zabranjena za korisnika '%-.32s'@'%-.64s' za tabelu '%-.64s'"
+ spa "%-.16s comando negado para usuario: '%-.32s'@'%-.64s' para tabla '%-.64s'"
+ swe "%-.16s ej tillåtet för '%-.32s'@'%-.64s' för tabell '%-.64s'"
+ ukr "%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s'@'%-.64s' Õ ÔÁÂÌÉæ '%-.64s'"
+ER_COLUMNACCESS_DENIED_ERROR 42000
+ cze "%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s'@'%-.64s' pro sloupec '%-.64s' v tabulce '%-.64s'"
+ dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s'@'%-.64s' for kolonne '%-.64s' in tabellen '%-.64s'"
+ nla "%-.16s commando geweigerd voor gebruiker: '%-.32s'@'%-.64s' voor kolom '%-.64s' in tabel '%-.64s'"
+ eng "%-.16s command denied to user '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'"
+ jps "ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.32s'@'%-.64s'\n ƒJƒ‰ƒ€ '%-.64s' ƒe[ƒuƒ‹ '%-.64s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "%-.16s käsk ei ole lubatud kasutajale '%-.32s'@'%-.64s' tulbale '%-.64s' tabelis '%-.64s'"
+ fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.32s'@'@%-.64s' sur la colonne '%-.64s' de la table '%-.64s'"
+ ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.32s'@'%-.64s' und Spalte '%-.64s' in Tabelle '%-.64s'"
+ hun "%-.16s parancs a '%-.32s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' mezo eseten a '%-.64s' tablaban"
+ ita "Comando %-.16s negato per l'utente: '%-.32s'@'%-.64s' sulla colonna '%-.64s' della tabella '%-.64s'"
+ jpn "¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s'\n ¥«¥é¥à '%-.64s' ¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s'@'%-.64s' for Ä®·³ '%-.64s' in Å×À̺í '%-.64s'"
+ por "Comando '%-.16s' negado para o usuário '%-.32s'@'%-.64s' na coluna '%-.64s', na tabela '%-.64s'"
+ rum "Comanda %-.16s interzisa utilizatorului: '%-.32s'@'%-.64s' pentru coloana '%-.64s' in tabela '%-.64s'"
+ rus "ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s'@'%-.64s' ÄÌÑ ÓÔÏÌÂÃÁ '%-.64s' × ÔÁÂÌÉÃÅ '%-.64s'"
+ serbian "%-.16s komanda zabranjena za korisnika '%-.32s'@'%-.64s' za kolonu '%-.64s' iz tabele '%-.64s'"
+ spa "%-.16s comando negado para usuario: '%-.32s'@'%-.64s' para columna '%-.64s' en la tabla '%-.64s'"
+ swe "%-.16s ej tillåtet för '%-.32s'@'%-.64s' för kolumn '%-.64s' i tabell '%-.64s'"
+ ukr "%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s'@'%-.64s' ÄÌÑ ÓÔÏ×ÂÃÑ '%-.64s' Õ ÔÁÂÌÉæ '%-.64s'"
+ER_ILLEGAL_GRANT_FOR_TABLE 42000
+ cze "Neplatn-Bý pøíkaz GRANT/REVOKE. Prosím, pøeètìte si v manuálu, jaká privilegia je mo¾né pou¾ít."
+ dan "Forkert GRANT/REVOKE kommando. Se i brugervejledningen hvilke privilegier der kan specificeres."
+ nla "Foutief GRANT/REVOKE commando. Raadpleeg de handleiding welke priveleges gebruikt kunnen worden."
+ eng "Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used"
+ est "Vigane GRANT/REVOKE käsk. Tutvu kasutajajuhendiga"
+ fre "Commande GRANT/REVOKE incorrecte. Consultez le manuel."
+ ger "Unzulässiger GRANT- oder REVOKE-Befehl. Verfügbare Berechtigungen sind im Handbuch aufgeführt"
+ greek "Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used."
+ hun "Ervenytelen GRANT/REVOKE parancs. Kerem, nezze meg a kezikonyvben, milyen jogok lehetsegesek"
+ ita "Comando GRANT/REVOKE illegale. Prego consultare il manuale per sapere quali privilegi possono essere usati."
+ jpn "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ kor "À߸øµÈ GRANT/REVOKE ¸í·É. ¾î¶² ±Ç¸®¿Í ½ÂÀÎÀÌ »ç¿ëµÇ¾î Áú ¼ö ÀÖ´ÂÁö ¸Þ´º¾óÀ» º¸½Ã¿À."
+ nor "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ norwegian-ny "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ pol "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ por "Comando GRANT/REVOKE ilegal. Por favor consulte no manual quais privilégios podem ser usados."
+ rum "Comanda GRANT/REVOKE ilegala. Consultati manualul in privinta privilegiilor ce pot fi folosite."
+ rus "îÅ×ÅÒÎÁÑ ËÏÍÁÎÄÁ GRANT ÉÌÉ REVOKE. ïÂÒÁÔÉÔÅÓØ Ë ÄÏËÕÍÅÎÔÁÃÉÉ, ÞÔÏÂÙ ×ÙÑÓÎÉÔØ, ËÁËÉÅ ÐÒÉ×ÉÌÅÇÉÉ ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ"
+ serbian "Pogrešna 'GRANT' odnosno 'REVOKE' komanda. Molim Vas pogledajte u priruèniku koje vrednosti mogu biti upotrebljene."
+ slo "Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used."
+ spa "Ilegal comando GRANT/REVOKE. Por favor consulte el manual para cuales permisos pueden ser usados."
+ swe "Felaktigt GRANT-privilegium använt"
+ ukr "èÉÂÎÁ GRANT/REVOKE ËÏÍÁÎÄÁ; ÐÒÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ ÓÔÏÓÏ×ÎÏ ÔÏÇÏ, Ñ˦ ÐÒÁ×Á ÍÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ"
+ER_GRANT_WRONG_HOST_OR_USER 42000
+ cze "Argument p-Bøíkazu GRANT u¾ivatel nebo stroj je pøíli¹ dlouhý"
+ dan "Værts- eller brugernavn for langt til GRANT"
+ nla "De host of gebruiker parameter voor GRANT is te lang"
+ eng "The host or user argument to GRANT is too long"
+ est "Masina või kasutaja nimi GRANT lauses on liiga pikk"
+ fre "L'hôte ou l'utilisateur donné en argument à GRANT est trop long"
+ ger "Das Host- oder User-Argument für GRANT ist zu lang"
+ hun "A host vagy felhasznalo argumentuma tul hosszu a GRANT parancsban"
+ ita "L'argomento host o utente per la GRANT e` troppo lungo"
+ kor "½ÂÀÎ(GRANT)À» À§ÇÏ¿© »ç¿ëÇÑ »ç¿ëÀÚ³ª È£½ºÆ®ÀÇ °ªµéÀÌ ³Ê¹« ±é´Ï´Ù."
+ por "Argumento de 'host' ou de usuário para o GRANT é longo demais"
+ rum "Argumentul host-ului sau utilizatorului pentru GRANT e prea lung"
+ rus "óÌÉÛËÏÍ ÄÌÉÎÎÏÅ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ/ÈÏÓÔÁ ÄÌÑ GRANT"
+ serbian "Argument 'host' ili 'korisnik' prosleðen komandi 'GRANT' je predugaèak"
+ spa "El argumento para servidor o usuario para GRANT es demasiado grande"
+ swe "Felaktigt maskinnamn eller användarnamn använt med GRANT"
+ ukr "áÒÇÕÍÅÎÔ host ÁÂÏ user ÄÌÑ GRANT ÚÁÄÏ×ÇÉÊ"
+ER_NO_SUCH_TABLE 42S02
+ cze "Tabulka '%-.64s.%s' neexistuje"
+ dan "Tabellen '%-.64s.%-.64s' eksisterer ikke"
+ nla "Tabel '%-.64s.%s' bestaat niet"
+ eng "Table '%-.64s.%-.64s' doesn't exist"
+ est "Tabelit '%-.64s.%-.64s' ei eksisteeri"
+ fre "La table '%-.64s.%s' n'existe pas"
+ ger "Tabelle '%-.64s.%-.64s' existiert nicht"
+ hun "A '%-.64s.%s' tabla nem letezik"
+ ita "La tabella '%-.64s.%s' non esiste"
+ jpn "Table '%-.64s.%s' doesn't exist"
+ kor "Å×À̺í '%-.64s.%s' ´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
+ nor "Table '%-.64s.%s' doesn't exist"
+ norwegian-ny "Table '%-.64s.%s' doesn't exist"
+ pol "Table '%-.64s.%s' doesn't exist"
+ por "Tabela '%-.64s.%-.64s' não existe"
+ rum "Tabela '%-.64s.%-.64s' nu exista"
+ rus "ôÁÂÌÉÃÁ '%-.64s.%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Tabela '%-.64s.%-.64s' ne postoji"
+ slo "Table '%-.64s.%s' doesn't exist"
+ spa "Tabla '%-.64s.%s' no existe"
+ swe "Det finns ingen tabell som heter '%-.64s.%s'"
+ ukr "ôÁÂÌÉÃÑ '%-.64s.%-.64s' ÎÅ ¦ÓÎÕ¤"
+ER_NONEXISTING_TABLE_GRANT 42000
+ cze "Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s' pro tabulku '%-.64s'"
+ dan "Denne tilladelse eksisterer ikke for brugeren '%-.32s' på vært '%-.64s' for tabellen '%-.64s'"
+ nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.32s' op host '%-.64s' op tabel '%-.64s'"
+ eng "There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'"
+ est "Sellist õigust ei ole defineeritud kasutajale '%-.32s' masinast '%-.64s' tabelile '%-.64s'"
+ fre "Un tel droit n'est pas défini pour l'utilisateur '%-.32s' sur l'hôte '%-.64s' sur la table '%-.64s'"
+ ger "Keine solche Berechtigung für User '%-.32s' auf Host '%-.64s' an Tabelle '%-.64s'"
+ hun "A '%-.32s' felhasznalo szamara a '%-.64s' host '%-.64s' tablajaban ez a parancs nem engedelyezett"
+ ita "GRANT non definita per l'utente '%-.32s' dalla macchina '%-.64s' sulla tabella '%-.64s'"
+ kor "»ç¿ëÀÚ '%-.32s'(È£½ºÆ® '%-.64s')´Â Å×À̺í '%-.64s'¸¦ »ç¿ëÇϱâ À§ÇÏ¿© Á¤ÀÇµÈ ½ÂÀÎÀº ¾ø½À´Ï´Ù. "
+ por "Não existe tal permissão (grant) definido para o usuário '%-.32s' no 'host' '%-.64s', na tabela '%-.64s'"
+ rum "Nu exista un astfel de privilegiu (grant) definit pentru utilizatorul '%-.32s' de pe host-ul '%-.64s' pentru tabela '%-.64s'"
+ rus "ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' ÎÁ ËÏÍÐØÀÔÅÒÅ '%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'"
+ serbian "Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s' tabeli '%-.64s'"
+ spa "No existe tal permiso definido para usuario '%-.32s' en el servidor '%-.64s' en la tabla '%-.64s'"
+ swe "Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s' för tabell '%-.64s'"
+ ukr "ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.32s' Ú ÈÏÓÔÕ '%-.64s' ÄÌÑ ÔÁÂÌÉæ '%-.64s'"
+ER_NOT_ALLOWED_COMMAND 42000
+ cze "Pou-B¾itý pøíkaz není v této verzi MySQL povolen"
+ dan "Den brugte kommando er ikke tilladt med denne udgave af MySQL"
+ nla "Het used commando is niet toegestaan in deze MySQL versie"
+ eng "The used command is not allowed with this MySQL version"
+ est "Antud käsk ei ole lubatud käesolevas MySQL versioonis"
+ fre "Cette commande n'existe pas dans cette version de MySQL"
+ ger "Der verwendete Befehl ist in dieser MySQL-Version nicht zulässig"
+ hun "A hasznalt parancs nem engedelyezett ebben a MySQL verzioban"
+ ita "Il comando utilizzato non e` supportato in questa versione di MySQL"
+ kor "»ç¿ëµÈ ¸í·ÉÀº ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â ÀÌ¿ëµÇÁö ¾Ê½À´Ï´Ù."
+ por "Comando usado não é permitido para esta versão do MySQL"
+ rum "Comanda folosita nu este permisa pentru aceasta versiune de MySQL"
+ rus "üÔÁ ËÏÍÁÎÄÁ ÎÅ ÄÏÐÕÓËÁÅÔÓÑ × ÄÁÎÎÏÊ ×ÅÒÓÉÉ MySQL"
+ serbian "Upotrebljena komanda nije dozvoljena sa ovom verzijom MySQL servera"
+ spa "El comando usado no es permitido con esta versión de MySQL"
+ swe "Du kan inte använda detta kommando med denna MySQL version"
+ ukr "÷ÉËÏÒÉÓÔÏ×Õ×ÁÎÁ ËÏÍÁÎÄÁ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ Ã¦Ê ×ÅÒÓ¦§ MySQL"
+ER_SYNTAX_ERROR 42000
+ cze "Va-B¹e syntaxe je nìjaká divná"
+ dan "Der er en fejl i SQL syntaksen"
+ nla "Er is iets fout in de gebruikte syntax"
+ eng "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use"
+ est "Viga SQL süntaksis"
+ fre "Erreur de syntaxe"
+ ger "Fehler in der SQL-Syntax. Bitte die korrekte Syntax im Handbuch nachschlagen (diese kann für verschiedene Server-Versionen unterschiedlich sein)"
+ greek "You have an error in your SQL syntax"
+ hun "Szintaktikai hiba"
+ ita "Errore di sintassi nella query SQL"
+ jpn "Something is wrong in your syntax"
+ kor "SQL ±¸¹®¿¡ ¿À·ù°¡ ÀÖ½À´Ï´Ù."
+ nor "Something is wrong in your syntax"
+ norwegian-ny "Something is wrong in your syntax"
+ pol "Something is wrong in your syntax"
+ por "Você tem um erro de sintaxe no seu SQL"
+ rum "Aveti o eroare in sintaxa RSQL"
+ rus "õ ×ÁÓ ÏÛÉÂËÁ × ÚÁÐÒÏÓÅ. éÚÕÞÉÔÅ ÄÏËÕÍÅÎÔÁÃÉÀ ÐÏ ÉÓÐÏÌØÚÕÅÍÏÊ ×ÅÒÓÉÉ MySQL ÎÁ ÐÒÅÄÍÅÔ ËÏÒÒÅËÔÎÏÇÏ ÓÉÎÔÁËÓÉÓÁ"
+ serbian "Imate grešku u vašoj SQL sintaksi"
+ slo "Something is wrong in your syntax"
+ spa "Algo está equivocado en su sintax"
+ swe "Du har något fel i din syntax"
+ ukr "õ ×ÁÓ ÐÏÍÉÌËÁ Õ ÓÉÎÔÁËÓÉÓ¦ SQL"
+ER_DELAYED_CANT_CHANGE_LOCK
+ cze "Zpo-B¾dìný insert threadu nebyl schopen získat po¾adovaný zámek pro tabulku %-.64s"
+ dan "Forsinket indsættelse tråden (delayed insert thread) kunne ikke opnå lås på tabellen %-.64s"
+ nla "'Delayed insert' thread kon de aangevraagde 'lock' niet krijgen voor tabel %-.64s"
+ eng "Delayed insert thread couldn't get requested lock for table %-.64s"
+ est "INSERT DELAYED lõim ei suutnud saada soovitud lukku tabelile %-.64s"
+ fre "La tâche 'delayed insert' n'a pas pu obtenir le verrou démandé sur la table %-.64s"
+ ger "Verzögerter (DELAYED) Einfüge-Thread konnte die angeforderte Sperre für Tabelle '%-.64s' nicht erhalten"
+ hun "A kesleltetett beillesztes (delayed insert) thread nem kapott zatolast a %-.64s tablahoz"
+ ita "Il thread di inserimento ritardato non riesce ad ottenere il lock per la tabella %-.64s"
+ kor "Áö¿¬µÈ insert ¾²·¹µå°¡ Å×À̺í %-.64sÀÇ ¿ä±¸µÈ ¶ôÅ·À» ó¸®ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù."
+ por "'Thread' de inserção retardada (atrasada) pois não conseguiu obter a trava solicitada para tabela '%-.64s'"
+ rum "Thread-ul pentru inserarea aminata nu a putut obtine lacatul (lock) pentru tabela %-.64s"
+ rus "ðÏÔÏË, ÏÂÓÌÕÖÉ×ÁÀÝÉÊ ÏÔÌÏÖÅÎÎÕÀ ×ÓÔÁ×ËÕ (delayed insert), ÎÅ ÓÍÏÇ ÐÏÌÕÞÉÔØ ÚÁÐÒÁÛÉ×ÁÅÍÕÀ ÂÌÏËÉÒÏ×ËÕ ÎÁ ÔÁÂÌÉÃÕ %-.64s"
+ serbian "Prolongirani 'INSERT' thread nije mogao da dobije traženo zakljuèavanje tabele '%-.64s'"
+ spa "Thread de inserción retarda no pudiendo bloquear para la tabla %-.64s"
+ swe "DELAYED INSERT-tråden kunde inte låsa tabell '%-.64s'"
+ ukr "ç¦ÌËÁ ÄÌÑ INSERT DELAYED ÎÅ ÍÏÖÅ ÏÔÒÉÍÁÔÉ ÂÌÏËÕ×ÁÎÎÑ ÄÌÑ ÔÁÂÌÉæ %-.64s"
+ER_TOO_MANY_DELAYED_THREADS
+ cze "P-Bøíli¹ mnoho zpo¾dìných threadù"
+ dan "For mange slettede tråde (threads) i brug"
+ nla "Te veel 'delayed' threads in gebruik"
+ eng "Too many delayed threads in use"
+ est "Liiga palju DELAYED lõimesid kasutusel"
+ fre "Trop de tâche 'delayed' en cours"
+ ger "Zu viele verzögerte (DELAYED) Threads in Verwendung"
+ hun "Tul sok kesletetett thread (delayed)"
+ ita "Troppi threads ritardati in uso"
+ kor "³Ê¹« ¸¹Àº Áö¿¬ ¾²·¹µå¸¦ »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù."
+ por "Excesso de 'threads' retardadas (atrasadas) em uso"
+ rum "Prea multe threaduri aminate care sint in uz"
+ rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÐÏÔÏËÏ×, ÏÂÓÌÕÖÉ×ÁÀÝÉÈ ÏÔÌÏÖÅÎÎÕÀ ×ÓÔÁ×ËÕ (delayed insert)"
+ serbian "Previše prolongiranih thread-ova je u upotrebi"
+ spa "Muchos threads retardados en uso"
+ swe "Det finns redan 'max_delayed_threads' trådar i använding"
+ ukr "úÁÂÁÇÁÔÏ ÚÁÔÒÉÍÁÎÉÈ Ç¦ÌÏË ×ÉËÏÒÉÓÔÏ×Õ¤ÔØÓÑ"
+ER_ABORTING_CONNECTION 08S01
+ cze "Zru-B¹eno spojení %ld do databáze: '%-.64s' u¾ivatel: '%-.64s' (%s)"
+ dan "Afbrudt forbindelse %ld til database: '%-.64s' bruger: '%-.64s' (%-.64s)"
+ nla "Afgebroken verbinding %ld naar db: '%-.64s' gebruiker: '%-.64s' (%s)"
+ eng "Aborted connection %ld to db: '%-.64s' user: '%-.32s' (%-.64s)"
+ est "Ühendus katkestatud %ld andmebaasile: '%-.64s' kasutajale: '%-.32s' (%-.64s)"
+ fre "Connection %ld avortée vers la bd: '%-.64s' utilisateur: '%-.64s' (%s)"
+ ger "Abbruch der Verbindung %ld zur Datenbank '%-.64s'. Benutzer: '%-.64s' (%-.64s)"
+ hun "Megszakitott kapcsolat %ld db: '%-.64s' adatbazishoz, felhasznalo: '%-.64s' (%s)"
+ ita "Interrotta la connessione %ld al db: '%-.64s' utente: '%-.64s' (%s)"
+ jpn "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
+ kor "µ¥ÀÌŸº£À̽º Á¢¼ÓÀ» À§ÇÑ ¿¬°á %ld°¡ Áß´ÜµÊ : '%-.64s' »ç¿ëÀÚ: '%-.64s' (%s)"
+ nor "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
+ norwegian-ny "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
+ pol "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
+ por "Conexão %ld abortou para o banco de dados '%-.64s' - usuário '%-.32s' (%-.64s)"
+ rum "Conectie terminata %ld la baza de date: '%-.64s' utilizator: '%-.32s' (%-.64s)"
+ rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' (%-.64s)"
+ serbian "Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' (%-.64s)"
+ slo "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
+ spa "Conexión abortada %ld para db: '%-.64s' usuario: '%-.64s' (%s)"
+ swe "Avbröt länken för tråd %ld till db '%-.64s', användare '%-.64s' (%s)"
+ ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.64s' ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s' (%-.64s)"
+ER_NET_PACKET_TOO_LARGE 08S01
+ cze "Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'"
+ dan "Modtog en datapakke som var større end 'max_allowed_packet'"
+ nla "Groter pakket ontvangen dan 'max_allowed_packet'"
+ eng "Got a packet bigger than 'max_allowed_packet' bytes"
+ est "Saabus suurem pakett kui lubatud 'max_allowed_packet' muutujaga"
+ fre "Paquet plus grand que 'max_allowed_packet' reçu"
+ ger "Empfangenes Paket ist größer als 'max_allowed_packet'"
+ hun "A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'max_allowed_packet'"
+ ita "Ricevuto un pacchetto piu` grande di 'max_allowed_packet'"
+ kor "'max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù."
+ por "Obteve um pacote maior do que a taxa máxima de pacotes definida (max_allowed_packet)"
+ rum "Un packet mai mare decit 'max_allowed_packet' a fost primit"
+ rus "ðÏÌÕÞÅÎÎÙÊ ÐÁËÅÔ ÂÏÌØÛÅ, ÞÅÍ 'max_allowed_packet'"
+ serbian "Primio sam mrežni paket veæi od definisane vrednosti 'max_allowed_packet'"
+ spa "Obtenido un paquete mayor que 'max_allowed_packet'"
+ swe "Kommunkationspaketet är större än 'max_allowed_packet'"
+ ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔ Â¦ÌØÛÉÊ Î¦Ö max_allowed_packet"
+ER_NET_READ_ERROR_FROM_PIPE 08S01
+ cze "Zji-B¹tìna chyba pøi ètení z roury spojení"
+ dan "Fik læsefejl fra forbindelse (connection pipe)"
+ nla "Kreeg leesfout van de verbindings pipe"
+ eng "Got a read error from the connection pipe"
+ est "Viga ühendustoru lugemisel"
+ fre "Erreur de lecture reçue du pipe de connection"
+ ger "Lese-Fehler bei einer Kommunikations-Pipe"
+ hun "Olvasasi hiba a kapcsolat soran"
+ ita "Rilevato un errore di lettura dalla pipe di connessione"
+ kor "¿¬°á ÆÄÀÌÇÁ·ÎºÎÅÍ ¿¡·¯°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù."
+ por "Obteve um erro de leitura no 'pipe' da conexão"
+ rum "Eroare la citire din cauza lui 'connection pipe'"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ ÞÔÅÎÉÑ ÏÔ ÐÏÔÏËÁ ÓÏÅÄÉÎÅÎÉÑ (connection pipe)"
+ serbian "Greška pri èitanju podataka sa pipe-a"
+ spa "Obtenido un error de lectura de la conexión pipe"
+ swe "Fick läsfel från klienten vid läsning från 'PIPE'"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ ÞÉÔÁÎÎÑ Ú ËÏÍÕΦËÁæÊÎÏÇÏ ËÁÎÁÌÕ"
+ER_NET_FCNTL_ERROR 08S01
+ cze "Zji-B¹tìna chyba fcntl()"
+ dan "Fik fejlmeddelelse fra fcntl()"
+ nla "Kreeg fout van fcntl()"
+ eng "Got an error from fcntl()"
+ est "fcntl() tagastas vea"
+ fre "Erreur reçue de fcntl() "
+ ger "fcntl() lieferte einen Fehler"
+ hun "Hiba a fcntl() fuggvenyben"
+ ita "Rilevato un errore da fcntl()"
+ kor "fcntl() ÇÔ¼ö·ÎºÎÅÍ ¿¡·¯°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù."
+ por "Obteve um erro em fcntl()"
+ rum "Eroare obtinuta de la fcntl()"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ ÏÔ fcntl()"
+ serbian "Greška pri izvršavanju funkcije fcntl()"
+ spa "Obtenido un error de fcntl()"
+ swe "Fick fatalt fel från 'fcntl()'"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËËÕ ×¦Ä fcntl()"
+ER_NET_PACKETS_OUT_OF_ORDER 08S01
+ cze "P-Bøíchozí packety v chybném poøadí"
+ dan "Modtog ikke datapakker i korrekt rækkefølge"
+ nla "Pakketten in verkeerde volgorde ontvangen"
+ eng "Got packets out of order"
+ est "Paketid saabusid vales järjekorras"
+ fre "Paquets reçus dans le désordre"
+ ger "Pakete nicht in der richtigen Reihenfolge empfangen"
+ hun "Helytelen sorrendben erkezett adatcsomagok"
+ ita "Ricevuti pacchetti non in ordine"
+ kor "¼ø¼­°¡ ¸ÂÁö¾Ê´Â ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù."
+ por "Obteve pacotes fora de ordem"
+ rum "Packets care nu sint ordonati au fost gasiti"
+ rus "ðÁËÅÔÙ ÐÏÌÕÞÅÎÙ × ÎÅ×ÅÒÎÏÍ ÐÏÒÑÄËÅ"
+ serbian "Primio sam mrežne pakete van reda"
+ spa "Obtenido paquetes desordenados"
+ swe "Kommunikationspaketen kom i fel ordning"
+ ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔÉ Õ ÎÅÎÁÌÅÖÎÏÍÕ ÐÏÒÑÄËÕ"
+ER_NET_UNCOMPRESS_ERROR 08S01
+ cze "Nemohu rozkomprimovat komunika-Bèní packet"
+ dan "Kunne ikke dekomprimere kommunikations-pakke (communication packet)"
+ nla "Communicatiepakket kon niet worden gedecomprimeerd"
+ eng "Couldn't uncompress communication packet"
+ est "Viga andmepaketi lahtipakkimisel"
+ fre "Impossible de décompresser le paquet reçu"
+ ger "Kommunikationspaket lässt sich nicht entpacken"
+ hun "A kommunikacios adatcsomagok nem tomorithetok ki"
+ ita "Impossibile scompattare i pacchetti di comunicazione"
+ kor "Åë½Å ÆÐŶÀÇ ¾ÐÃàÇØÁ¦¸¦ ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù."
+ por "Não conseguiu descomprimir pacote de comunicação"
+ rum "Nu s-a putut decompresa pachetul de comunicatie (communication packet)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÒÁÓÐÁËÏ×ÁÔØ ÐÁËÅÔ, ÐÏÌÕÞÅÎÎÙÊ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ"
+ serbian "Ne mogu da dekompresujem mrežne pakete"
+ spa "No puedo descomprimir paquetes de comunicación"
+ swe "Kunde inte packa up kommunikationspaketet"
+ ukr "îÅ ÍÏÖÕ ÄÅËÏÍÐÒÅÓÕ×ÁÔÉ ËÏÍÕΦËÁæÊÎÉÊ ÐÁËÅÔ"
+ER_NET_READ_ERROR 08S01
+ cze "Zji-B¹tìna chyba pøi ètení komunikaèního packetu"
+ dan "Fik fejlmeddelelse ved læsning af kommunikations-pakker (communication packets)"
+ nla "Fout bij het lezen van communicatiepakketten"
+ eng "Got an error reading communication packets"
+ est "Viga andmepaketi lugemisel"
+ fre "Erreur de lecture des paquets reçus"
+ ger "Fehler beim Lesen eines Kommunikationspakets"
+ hun "HIba a kommunikacios adatcsomagok olvasasa soran"
+ ita "Rilevato un errore ricevendo i pacchetti di comunicazione"
+ kor "Åë½Å ÆÐŶÀ» Àд Áß ¿À·ù°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù."
+ por "Obteve um erro na leitura de pacotes de comunicação"
+ rum "Eroare obtinuta citind pachetele de comunicatie (communication packets)"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ × ÐÒÏÃÅÓÓÅ ÐÏÌÕÞÅÎÉÑ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ "
+ serbian "Greška pri primanju mrežnih paketa"
+ spa "Obtenido un error leyendo paquetes de comunicación"
+ swe "Fick ett fel vid läsning från klienten"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ ÞÉÔÁÎÎÑ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×"
+ER_NET_READ_INTERRUPTED 08S01
+ cze "Zji-B¹tìn timeout pøi ètení komunikaèního packetu"
+ dan "Timeout-fejl ved læsning af kommunukations-pakker (communication packets)"
+ nla "Timeout bij het lezen van communicatiepakketten"
+ eng "Got timeout reading communication packets"
+ est "Kontrollaja ületamine andmepakettide lugemisel"
+ fre "Timeout en lecture des paquets reçus"
+ ger "Zeitüberschreitung beim Lesen eines Kommunikationspakets"
+ hun "Idotullepes a kommunikacios adatcsomagok olvasasa soran"
+ ita "Rilevato un timeout ricevendo i pacchetti di comunicazione"
+ kor "Åë½Å ÆÐŶÀ» Àд Áß timeoutÀÌ ¹ß»ýÇÏ¿´½À´Ï´Ù."
+ por "Obteve expiração de tempo (timeout) na leitura de pacotes de comunicação"
+ rum "Timeout obtinut citind pachetele de comunicatie (communication packets)"
+ rus "ðÏÌÕÞÅÎ ÔÁÊÍÁÕÔ ÏÖÉÄÁÎÉÑ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ "
+ serbian "Vremenski limit za èitanje mrežnih paketa je istekao"
+ spa "Obtenido timeout leyendo paquetes de comunicación"
+ swe "Fick 'timeout' vid läsning från klienten"
+ ukr "ïÔÒÉÍÁÎÏ ÚÁÔÒÉÍËÕ ÞÉÔÁÎÎÑ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×"
+ER_NET_ERROR_ON_WRITE 08S01
+ cze "Zji-B¹tìna chyba pøi zápisu komunikaèního packetu"
+ dan "Fik fejlmeddelelse ved skrivning af kommunukations-pakker (communication packets)"
+ nla "Fout bij het schrijven van communicatiepakketten"
+ eng "Got an error writing communication packets"
+ est "Viga andmepaketi kirjutamisel"
+ fre "Erreur d'écriture des paquets envoyés"
+ ger "Fehler beim Schreiben eines Kommunikationspakets"
+ hun "Hiba a kommunikacios csomagok irasa soran"
+ ita "Rilevato un errore inviando i pacchetti di comunicazione"
+ kor "Åë½Å ÆÐŶÀ» ±â·ÏÇÏ´Â Áß ¿À·ù°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù."
+ por "Obteve um erro na escrita de pacotes de comunicação"
+ rum "Eroare in scrierea pachetelor de comunicatie (communication packets)"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ ÐÒÉ ÐÅÒÅÄÁÞÅ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ "
+ serbian "Greška pri slanju mrežnih paketa"
+ spa "Obtenido un error de escribiendo paquetes de comunicación"
+ swe "Fick ett fel vid skrivning till klienten"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ ÚÁÐÉÓÕ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×"
+ER_NET_WRITE_INTERRUPTED 08S01
+ cze "Zji-B¹tìn timeout pøi zápisu komunikaèního packetu"
+ dan "Timeout-fejl ved skrivning af kommunukations-pakker (communication packets)"
+ nla "Timeout bij het schrijven van communicatiepakketten"
+ eng "Got timeout writing communication packets"
+ est "Kontrollaja ületamine andmepakettide kirjutamisel"
+ fre "Timeout d'écriture des paquets envoyés"
+ ger "Zeitüberschreitung beim Schreiben eines Kommunikationspakets"
+ hun "Idotullepes a kommunikacios csomagok irasa soran"
+ ita "Rilevato un timeout inviando i pacchetti di comunicazione"
+ kor "Åë½Å ÆÐÆÂÀ» ±â·ÏÇÏ´Â Áß timeoutÀÌ ¹ß»ýÇÏ¿´½À´Ï´Ù."
+ por "Obteve expiração de tempo ('timeout') na escrita de pacotes de comunicação"
+ rum "Timeout obtinut scriind pachetele de comunicatie (communication packets)"
+ rus "ðÏÌÕÞÅÎ ÔÁÊÍÁÕÔ × ÐÒÏÃÅÓÓÅ ÐÅÒÅÄÁÞÉ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ "
+ serbian "Vremenski limit za slanje mrežnih paketa je istekao"
+ spa "Obtenido timeout escribiendo paquetes de comunicación"
+ swe "Fick 'timeout' vid skrivning till klienten"
+ ukr "ïÔÒÉÍÁÎÏ ÚÁÔÒÉÍËÕ ÚÁÐÉÓÕ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×"
+ER_TOO_LONG_STRING 42000
+ cze "V-Býsledný øetìzec je del¹í ne¾ 'max_allowed_packet'"
+ dan "Strengen med resultater er større end 'max_allowed_packet'"
+ nla "Resultaat string is langer dan 'max_allowed_packet'"
+ eng "Result string is longer than 'max_allowed_packet' bytes"
+ est "Tulemus on pikem kui lubatud 'max_allowed_packet' muutujaga"
+ fre "La chaîne résultat est plus grande que 'max_allowed_packet'"
+ ger "Ergebnis ist länger als 'max_allowed_packet'"
+ hun "Ez eredmeny sztring nagyobb, mint a lehetseges maximum: 'max_allowed_packet'"
+ ita "La stringa di risposta e` piu` lunga di 'max_allowed_packet'"
+ por "'String' resultante é mais longa do que 'max_allowed_packet'"
+ rum "Sirul rezultat este mai lung decit 'max_allowed_packet'"
+ rus "òÅÚÕÌØÔÉÒÕÀÝÁÑ ÓÔÒÏËÁ ÂÏÌØÛÅ, ÞÅÍ 'max_allowed_packet'"
+ serbian "Rezultujuèi string je duži nego što to dozvoljava parametar servera 'max_allowed_packet'"
+ spa "La string resultante es mayor que max_allowed_packet"
+ swe "Resultatsträngen är längre än max_allowed_packet"
+ ukr "óÔÒÏËÁ ÒÅÚÕÌØÔÁÔÕ ÄÏ×ÛÁ Î¦Ö max_allowed_packet"
+ER_TABLE_CANT_HANDLE_BLOB 42000
+ cze "Typ pou-B¾ité tabulky nepodporuje BLOB/TEXT sloupce"
+ dan "Denne tabeltype understøtter ikke brug af BLOB og TEXT kolonner"
+ nla "Het gebruikte tabel type ondersteunt geen BLOB/TEXT kolommen"
+ eng "The used table type doesn't support BLOB/TEXT columns"
+ est "Valitud tabelitüüp ei toeta BLOB/TEXT tüüpi välju"
+ fre "Ce type de table ne supporte pas les colonnes BLOB/TEXT"
+ ger "Der verwendete Tabellentyp unterstützt keine BLOB- und TEXT-Spalten"
+ hun "A hasznalt tabla tipus nem tamogatja a BLOB/TEXT mezoket"
+ ita "Il tipo di tabella usata non supporta colonne di tipo BLOB/TEXT"
+ por "Tipo de tabela usado não permite colunas BLOB/TEXT"
+ rum "Tipul de tabela folosit nu suporta coloane de tip BLOB/TEXT"
+ rus "éÓÐÏÌØÚÕÅÍÁÑ ÔÁÂÌÉÃÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÔÉÐÙ BLOB/TEXT"
+ serbian "Iskorišteni tip tabele ne podržava kolone tipa 'BLOB' odnosno 'TEXT'"
+ spa "El tipo de tabla usada no permite soporte para columnas BLOB/TEXT"
+ swe "Den använda tabelltypen kan inte hantera BLOB/TEXT-kolumner"
+ ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ BLOB/TEXT ÓÔÏ×Âæ"
+ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 42000
+ cze "Typ pou-B¾ité tabulky nepodporuje AUTO_INCREMENT sloupce"
+ dan "Denne tabeltype understøtter ikke brug af AUTO_INCREMENT kolonner"
+ nla "Het gebruikte tabel type ondersteunt geen AUTO_INCREMENT kolommen"
+ eng "The used table type doesn't support AUTO_INCREMENT columns"
+ est "Valitud tabelitüüp ei toeta AUTO_INCREMENT tüüpi välju"
+ fre "Ce type de table ne supporte pas les colonnes AUTO_INCREMENT"
+ ger "Der verwendete Tabellentyp unterstützt keine AUTO_INCREMENT-Spalten"
+ hun "A hasznalt tabla tipus nem tamogatja az AUTO_INCREMENT tipusu mezoket"
+ ita "Il tipo di tabella usata non supporta colonne di tipo AUTO_INCREMENT"
+ por "Tipo de tabela usado não permite colunas AUTO_INCREMENT"
+ rum "Tipul de tabela folosit nu suporta coloane de tip AUTO_INCREMENT"
+ rus "éÓÐÏÌØÚÕÅÍÁÑ ÔÁÂÌÉÃÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ Á×ÔÏÉÎËÒÅÍÅÎÔÎÙÅ ÓÔÏÌÂÃÙ"
+ serbian "Iskorišteni tip tabele ne podržava kolone tipa 'AUTO_INCREMENT'"
+ spa "El tipo de tabla usada no permite soporte para columnas AUTO_INCREMENT"
+ swe "Den använda tabelltypen kan inte hantera AUTO_INCREMENT-kolumner"
+ ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ AUTO_INCREMENT ÓÔÏ×Âæ"
+ER_DELAYED_INSERT_TABLE_LOCKED
+ cze "INSERT DELAYED nen-Bí mo¾no s tabulkou '%-.64s' pou¾ít, proto¾e je zamèená pomocí LOCK TABLES"
+ dan "INSERT DELAYED kan ikke bruges med tabellen '%-.64s', fordi tabellen er låst med LOCK TABLES"
+ nla "INSERT DELAYED kan niet worden gebruikt bij table '%-.64s', vanwege een 'lock met LOCK TABLES"
+ eng "INSERT DELAYED can't be used with table '%-.64s' because it is locked with LOCK TABLES"
+ est "INSERT DELAYED ei saa kasutada tabeli '%-.64s' peal, kuna see on lukustatud LOCK TABLES käsuga"
+ fre "INSERT DELAYED ne peut être utilisé avec la table '%-.64s', car elle est verrouée avec LOCK TABLES"
+ ger "INSERT DELAYED kann nicht auf Tabelle '%-.64s' angewendet werden, da diese mit LOCK TABLES gesperrt ist"
+ greek "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
+ hun "Az INSERT DELAYED nem hasznalhato a '%-.64s' tablahoz, mert a tabla zarolt (LOCK TABLES)"
+ ita "L'inserimento ritardato (INSERT DELAYED) non puo` essere usato con la tabella '%-.64s', perche` soggetta a lock da 'LOCK TABLES'"
+ jpn "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
+ kor "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
+ nor "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
+ norwegian-ny "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
+ pol "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
+ por "INSERT DELAYED não pode ser usado com a tabela '%-.64s', porque ela está travada com LOCK TABLES"
+ rum "INSERT DELAYED nu poate fi folosit cu tabela '%-.64s', deoarece este locked folosing LOCK TABLES"
+ rus "îÅÌØÚÑ ÉÓÐÏÌØÚÏ×ÁÔØ INSERT DELAYED ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s', ÐÏÔÏÍÕ ÞÔÏ ÏÎÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES"
+ serbian "Komanda 'INSERT DELAYED' ne može biti iskorištena u tabeli '%-.64s', zbog toga što je zakljuèana komandom 'LOCK TABLES'"
+ slo "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
+ spa "INSERT DELAYED no puede ser usado con tablas '%-.64s', porque esta bloqueada con LOCK TABLES"
+ swe "INSERT DELAYED kan inte användas med tabell '%-.64s', emedan den är låst med LOCK TABLES"
+ ukr "INSERT DELAYED ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÏ Ú ÔÁÂÌÉÃÅÀ '%-.64s', ÔÏÍÕ ÝÏ §§ ÚÁÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES"
+ER_WRONG_COLUMN_NAME 42000
+ cze "Nespr-Bávné jméno sloupce '%-.100s'"
+ dan "Forkert kolonnenavn '%-.100s'"
+ nla "Incorrecte kolom naam '%-.100s'"
+ eng "Incorrect column name '%-.100s'"
+ est "Vigane tulba nimi '%-.100s'"
+ fre "Nom de colonne '%-.100s' incorrect"
+ ger "Falscher Spaltenname '%-.100s'"
+ hun "Ervenytelen mezonev: '%-.100s'"
+ ita "Nome colonna '%-.100s' non corretto"
+ por "Nome de coluna '%-.100s' incorreto"
+ rum "Nume increct de coloana '%-.100s'"
+ rus "îÅ×ÅÒÎÏÅ ÉÍÑ ÓÔÏÌÂÃÁ '%-.100s'"
+ serbian "Pogrešno ime kolone '%-.100s'"
+ spa "Incorrecto nombre de columna '%-.100s'"
+ swe "Felaktigt kolumnnamn '%-.100s'"
+ ukr "îÅצÒÎÅ ¦Í'Ñ ÓÔÏ×ÂÃÑ '%-.100s'"
+ER_WRONG_KEY_COLUMN 42000
+ cze "Handler pou-B¾ité tabulky neumí indexovat sloupce '%-.64s'"
+ dan "Den brugte tabeltype kan ikke indeksere kolonnen '%-.64s'"
+ nla "De gebruikte tabel 'handler' kan kolom '%-.64s' niet indexeren"
+ eng "The used storage engine can't index column '%-.64s'"
+ est "Tabelihandler ei oska indekseerida tulpa '%-.64s'"
+ fre "Le handler de la table ne peut indexé la colonne '%-.64s'"
+ ger "Der verwendete Tabellen-Handler kann die Spalte '%-.64s' nicht indizieren"
+ greek "The used table handler can't index column '%-.64s'"
+ hun "A hasznalt tablakezelo nem tudja a '%-.64s' mezot indexelni"
+ ita "Il gestore delle tabelle non puo` indicizzare la colonna '%-.64s'"
+ jpn "The used table handler can't index column '%-.64s'"
+ kor "The used table handler can't index column '%-.64s'"
+ nor "The used table handler can't index column '%-.64s'"
+ norwegian-ny "The used table handler can't index column '%-.64s'"
+ pol "The used table handler can't index column '%-.64s'"
+ por "O manipulador de tabela usado não pode indexar a coluna '%-.64s'"
+ rum "Handler-ul tabelei folosite nu poate indexa coloana '%-.64s'"
+ rus "éÓÐÏÌØÚÏ×ÁÎÎÙÊ ÏÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÍÏÖÅÔ ÐÒÏÉÎÄÅËÓÉÒÏ×ÁÔØ ÓÔÏÌÂÅà '%-.64s'"
+ serbian "Handler tabele ne može da indeksira kolonu '%-.64s'"
+ slo "The used table handler can't index column '%-.64s'"
+ spa "El manipulador de tabla usado no puede indexar columna '%-.64s'"
+ swe "Den använda tabelltypen kan inte indexera kolumn '%-.64s'"
+ ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ×ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ÎÅ ÍÏÖÅ ¦ÎÄÅËÓÕ×ÁÔÉ ÓÔÏ×ÂÅÃØ '%-.64s'"
+ER_WRONG_MRG_TABLE
+ cze "V-B¹echny tabulky v MERGE tabulce nejsou definovány stejnì"
+ dan "Tabellerne i MERGE er ikke defineret ens"
+ nla "Niet alle tabellen in de MERGE tabel hebben identieke gedefinities"
+ eng "All tables in the MERGE table are not identically defined"
+ est "Kõik tabelid MERGE tabeli määratluses ei ole identsed"
+ fre "Toutes les tables de la table de type MERGE n'ont pas la même définition"
+ ger "Nicht alle Tabellen in der MERGE-Tabelle sind gleich definiert"
+ hun "A MERGE tablaban talalhato tablak definicioja nem azonos"
+ ita "Non tutte le tabelle nella tabella di MERGE sono definite in maniera identica"
+ jpn "All tables in the MERGE table are not defined identically"
+ kor "All tables in the MERGE table are not defined identically"
+ nor "All tables in the MERGE table are not defined identically"
+ norwegian-ny "All tables in the MERGE table are not defined identically"
+ pol "All tables in the MERGE table are not defined identically"
+ por "Todas as tabelas contidas na tabela fundida (MERGE) não estão definidas identicamente"
+ rum "Toate tabelele din tabela MERGE nu sint definite identic"
+ rus "îÅ ×ÓÅ ÔÁÂÌÉÃÙ × MERGE ÏÐÒÅÄÅÌÅÎÙ ÏÄÉÎÁËÏ×Ï"
+ serbian "Tabele iskorištene u 'MERGE' tabeli nisu definisane na isti naèin"
+ slo "All tables in the MERGE table are not defined identically"
+ spa "Todas las tablas en la MERGE tabla no estan definidas identicamente"
+ swe "Tabellerna i MERGE-tabellen är inte identiskt definierade"
+ ukr "ôÁÂÌÉæ Õ MERGE TABLE ÍÁÀÔØ Ò¦ÚÎÕ ÓÔÒÕËÔÕÒÕ"
+ER_DUP_UNIQUE 23000
+ cze "Kv-Bùli unique constraintu nemozu zapsat do tabulky '%-.64s'"
+ dan "Kan ikke skrive til tabellen '%-.64s' fordi det vil bryde CONSTRAINT regler"
+ nla "Kan niet opslaan naar table '%-.64s' vanwege 'unique' beperking"
+ eng "Can't write, because of unique constraint, to table '%-.64s'"
+ est "Ei suuda kirjutada tabelisse '%-.64s', kuna see rikub ühesuse kitsendust"
+ fre "Écriture impossible à cause d'un index UNIQUE sur la table '%-.64s'"
+ ger "Schreiben in Tabelle '%-.64s' nicht möglich wegen einer eindeutigen Beschränkung (unique constraint)"
+ hun "A '%-.64s' nem irhato, az egyedi mezok miatt"
+ ita "Impossibile scrivere nella tabella '%-.64s' per limitazione di unicita`"
+ por "Não pode gravar, devido à restrição UNIQUE, na tabela '%-.64s'"
+ rum "Nu pot scrie pe hard-drive, din cauza constraintului unic (unique constraint) pentru tabela '%-.64s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÐÉÓÁÔØ × ÔÁÂÌÉÃÕ '%-.64s' ÉÚ-ÚÁ ÏÇÒÁÎÉÞÅÎÉÊ ÕÎÉËÁÌØÎÏÇÏ ËÌÀÞÁ"
+ serbian "Zbog provere jedinstvenosti ne mogu da upišem podatke u tabelu '%-.64s'"
+ spa "No puedo escribir, debido al único constraint, para tabla '%-.64s'"
+ swe "Kan inte skriva till tabell '%-.64s'; UNIQUE-test"
+ ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÄÏ ÔÁÂÌÉæ '%-.64s', Ú ÐÒÉÞÉÎÉ ×ÉÍÏÇ ÕΦËÁÌØÎÏÓÔ¦"
+ER_BLOB_KEY_WITHOUT_LENGTH 42000
+ cze "BLOB sloupec '%-.64s' je pou-B¾it ve specifikaci klíèe bez délky"
+ dan "BLOB kolonnen '%-.64s' brugt i nøglespecifikation uden nøglelængde"
+ nla "BLOB kolom '%-.64s' gebruikt in zoeksleutel specificatie zonder zoeksleutel lengte"
+ eng "BLOB/TEXT column '%-.64s' used in key specification without a key length"
+ est "BLOB-tüüpi tulp '%-.64s' on kasutusel võtmes ilma pikkust määratlemata"
+ fre "La colonne '%-.64s' de type BLOB est utilisée dans une définition d'index sans longueur d'index"
+ ger "BLOB- oder TEXT-Spalte '%-.64s' wird in der Schlüsseldefinition ohne Schlüssellängenangabe verwendet"
+ greek "BLOB column '%-.64s' used in key specification without a key length"
+ hun "BLOB mezo '%-.64s' hasznalt a mezo specifikacioban, a mezohossz megadasa nelkul"
+ ita "La colonna '%-.64s' di tipo BLOB e` usata in una chiave senza specificarne la lunghezza"
+ jpn "BLOB column '%-.64s' used in key specification without a key length"
+ kor "BLOB column '%-.64s' used in key specification without a key length"
+ nor "BLOB column '%-.64s' used in key specification without a key length"
+ norwegian-ny "BLOB column '%-.64s' used in key specification without a key length"
+ pol "BLOB column '%-.64s' used in key specification without a key length"
+ por "Coluna BLOB '%-.64s' usada na especificação de chave sem o comprimento da chave"
+ rum "Coloana BLOB '%-.64s' este folosita in specificarea unei chei fara ca o lungime de cheie sa fie folosita"
+ rus "óÔÏÌÂÅÃ ÔÉÐÁ BLOB '%-.64s' ÂÙÌ ÕËÁÚÁÎ × ÏÐÒÅÄÅÌÅÎÉÉ ËÌÀÞÁ ÂÅÚ ÕËÁÚÁÎÉÑ ÄÌÉÎÙ ËÌÀÞÁ"
+ serbian "BLOB kolona '%-.64s' je upotrebljena u specifikaciji kljuèa bez navoðenja dužine kljuèa"
+ slo "BLOB column '%-.64s' used in key specification without a key length"
+ spa "Columna BLOB column '%-.64s' usada en especificación de clave sin tamaño de la clave"
+ swe "Du har inte angett någon nyckellängd för BLOB '%-.64s'"
+ ukr "óÔÏ×ÂÅÃØ BLOB '%-.64s' ×ÉËÏÒÉÓÔÁÎÏ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ ÂÅÚ ×ËÁÚÁÎÎÑ ÄÏ×ÖÉÎÉ ËÌÀÞÁ"
+ER_PRIMARY_CANT_HAVE_NULL 42000
+ cze "V-B¹echny èásti primárního klíèe musejí být NOT NULL; pokud potøebujete NULL, pou¾ijte UNIQUE"
+ dan "Alle dele af en PRIMARY KEY skal være NOT NULL; Hvis du skal bruge NULL i nøglen, brug UNIQUE istedet"
+ nla "Alle delen van een PRIMARY KEY moeten NOT NULL zijn; Indien u NULL in een zoeksleutel nodig heeft kunt u UNIQUE gebruiken"
+ eng "All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead"
+ est "Kõik PRIMARY KEY peavad olema määratletud NOT NULL piiranguga; vajadusel kasuta UNIQUE tüüpi võtit"
+ fre "Toutes les parties d'un index PRIMARY KEY doivent être NOT NULL; Si vous avez besoin d'un NULL dans l'index, utilisez un index UNIQUE"
+ ger "Alle Teile eines PRIMARY KEY müssen als NOT NULL definiert sein. Wenn NULL in einem Schlüssel verwendet wird, muss ein UNIQUE-Schlüssel verwendet werden"
+ hun "Az elsodleges kulcs teljes egeszeben csak NOT NULL tipusu lehet; Ha NULL mezot szeretne a kulcskent, hasznalja inkabb a UNIQUE-ot"
+ ita "Tutte le parti di una chiave primaria devono essere dichiarate NOT NULL; se necessitano valori NULL nelle chiavi utilizzare UNIQUE"
+ por "Todas as partes de uma chave primária devem ser não-nulas. Se você precisou usar um valor nulo (NULL) em uma chave, use a cláusula UNIQUE em seu lugar"
+ rum "Toate partile unei chei primare (PRIMARY KEY) trebuie sa fie NOT NULL; Daca aveti nevoie de NULL in vreo cheie, folositi UNIQUE in schimb"
+ rus "÷ÓÅ ÞÁÓÔÉ ÐÅÒ×ÉÞÎÏÇÏ ËÌÀÞÁ (PRIMARY KEY) ÄÏÌÖÎÙ ÂÙÔØ ÏÐÒÅÄÅÌÅÎÙ ËÁË NOT NULL; åÓÌÉ ×ÁÍ ÎÕÖÎÁ ÐÏÄÄÅÒÖËÁ ×ÅÌÉÞÉÎ NULL × ËÌÀÞÅ, ×ÏÓÐÏÌØÚÕÊÔÅÓØ ÉÎÄÅËÓÏÍ UNIQUE"
+ serbian "Svi delovi primarnog kljuèa moraju biti razlièiti od NULL; Ako Vam ipak treba NULL vrednost u kljuèu, upotrebite 'UNIQUE'"
+ spa "Todas las partes de un PRIMARY KEY deben ser NOT NULL; Si necesitas NULL en una clave, use UNIQUE"
+ swe "Alla delar av en PRIMARY KEY måste vara NOT NULL; Om du vill ha en nyckel med NULL, använd UNIQUE istället"
+ ukr "õÓ¦ ÞÁÓÔÉÎÉ PRIMARY KEY ÐÏ×ÉÎΦ ÂÕÔÉ NOT NULL; ñËÝÏ ×É ÐÏÔÒÅÂÕ¤ÔÅ NULL Õ ËÌÀÞ¦, ÓËÏÒÉÓÔÁÊÔÅÓÑ UNIQUE"
+ER_TOO_MANY_ROWS 42000
+ cze "V-Býsledek obsahuje více ne¾ jeden øádek"
+ dan "Resultatet bestod af mere end een række"
+ nla "Resultaat bevatte meer dan een rij"
+ eng "Result consisted of more than one row"
+ est "Tulemis oli rohkem kui üks kirje"
+ fre "Le résultat contient plus d'un enregistrement"
+ ger "Ergebnis besteht aus mehr als einer Zeile"
+ hun "Az eredmeny tobb, mint egy sort tartalmaz"
+ ita "Il risultato consiste di piu` di una riga"
+ por "O resultado consistiu em mais do que uma linha"
+ rum "Resultatul constista din mai multe linii"
+ rus "÷ ÒÅÚÕÌØÔÁÔÅ ×ÏÚ×ÒÁÝÅÎÁ ÂÏÌÅÅ ÞÅÍ ÏÄÎÁ ÓÔÒÏËÁ"
+ serbian "Rezultat je saèinjen od više slogova"
+ spa "Resultado compuesto de mas que una línea"
+ swe "Resultet bestod av mera än en rad"
+ ukr "òÅÚÕÌØÔÁÔ ÚÎÁÈÏÄÉÔØÓÑ Õ Â¦ÌØÛÅ Î¦Ö ÏÄÎ¦Ê ÓÔÒÏæ"
+ER_REQUIRES_PRIMARY_KEY 42000
+ cze "Tento typ tabulky vy-B¾aduje primární klíè"
+ dan "Denne tabeltype kræver en primærnøgle"
+ nla "Dit tabel type heeft een primaire zoeksleutel nodig"
+ eng "This table type requires a primary key"
+ est "Antud tabelitüüp nõuab primaarset võtit"
+ fre "Ce type de table nécessite une clé primaire (PRIMARY KEY)"
+ ger "Dieser Tabellentyp benötigt einen PRIMARY KEY"
+ hun "Az adott tablatipushoz elsodleges kulcs hasznalata kotelezo"
+ ita "Questo tipo di tabella richiede una chiave primaria"
+ por "Este tipo de tabela requer uma chave primária"
+ rum "Aceast tip de tabela are nevoie de o cheie primara"
+ rus "üÔÏÔ ÔÉÐ ÔÁÂÌÉÃÙ ÔÒÅÂÕÅÔ ÏÐÒÅÄÅÌÅÎÉÑ ÐÅÒ×ÉÞÎÏÇÏ ËÌÀÞÁ"
+ serbian "Ovaj tip tabele zahteva da imate definisan primarni kljuè"
+ spa "Este tipo de tabla necesita de una primary key"
+ swe "Denna tabelltyp kräver en PRIMARY KEY"
+ ukr "ãÅÊ ÔÉÐ ÔÁÂÌÉæ ÐÏÔÒÅÂÕ¤ ÐÅÒ×ÉÎÎÏÇÏ ËÌÀÞÁ"
+ER_NO_RAID_COMPILED
+ cze "Tato verze MySQL nen-Bí zkompilována s podporou RAID"
+ dan "Denne udgave af MySQL er ikke oversat med understøttelse af RAID"
+ nla "Deze versie van MySQL is niet gecompileerd met RAID ondersteuning"
+ eng "This version of MySQL is not compiled with RAID support"
+ est "Antud MySQL versioon on kompileeritud ilma RAID toeta"
+ fre "Cette version de MySQL n'est pas compilée avec le support RAID"
+ ger "Diese MySQL-Version ist nicht mit RAID-Unterstützung kompiliert"
+ hun "Ezen leforditott MySQL verzio nem tartalmaz RAID support-ot"
+ ita "Questa versione di MYSQL non e` compilata con il supporto RAID"
+ por "Esta versão do MySQL não foi compilada com suporte a RAID"
+ rum "Aceasta versiune de MySQL, nu a fost compilata cu suport pentru RAID"
+ rus "üÔÁ ×ÅÒÓÉÑ MySQL ÓËÏÍÐÉÌÉÒÏ×ÁÎÁ ÂÅÚ ÐÏÄÄÅÒÖËÉ RAID"
+ serbian "Ova verzija MySQL servera nije kompajlirana sa podrškom za RAID ureðaje"
+ spa "Esta versión de MySQL no es compilada con soporte RAID"
+ swe "Denna version av MySQL är inte kompilerad med RAID"
+ ukr "ãÑ ×ÅÒÓ¦Ñ MySQL ÎÅ ÚËÏÍЦÌØÏ×ÁÎÁ Ú Ð¦ÄÔÒÉÍËÏÀ RAID"
+ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE
+ cze "Update tabulky bez WHERE s kl-Bíèem není v módu bezpeèných update dovoleno"
+ dan "Du bruger sikker opdaterings modus ('safe update mode') og du forsøgte at opdatere en tabel uden en WHERE klausul, der gør brug af et KEY felt"
+ nla "U gebruikt 'safe update mode' en u probeerde een tabel te updaten zonder een WHERE met een KEY kolom"
+ eng "You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column"
+ est "Katse muuta tabelit turvalises rezhiimis ilma WHERE klauslita"
+ fre "Vous êtes en mode 'safe update' et vous essayez de faire un UPDATE sans clause WHERE utilisant un index"
+ ger "MySQL läuft im sicheren Aktualisierungsmodus (safe update mode). Sie haben versucht, eine Tabelle zu aktualisieren, ohne in der WHERE-Klausel eine KEY-Spalte anzugeben"
+ hun "On a biztonsagos update modot hasznalja, es WHERE that uses a KEY column"
+ ita "In modalita` 'safe update' si e` cercato di aggiornare una tabella senza clausola WHERE su una chiave"
+ por "Você está usando modo de atualização seguro e tentou atualizar uma tabela sem uma cláusula WHERE que use uma coluna chave"
+ rus "÷Ù ÒÁÂÏÔÁÅÔÅ × ÒÅÖÉÍÅ ÂÅÚÏÐÁÓÎÙÈ ÏÂÎÏ×ÌÅÎÉÊ (safe update mode) É ÐÏÐÒÏÂÏ×ÁÌÉ ÉÚÍÅÎÉÔØ ÔÁÂÌÉÃÕ ÂÅÚ ÉÓÐÏÌØÚÏ×ÁÎÉÑ ËÌÀÞÅ×ÏÇÏ ÓÔÏÌÂÃÁ × ÞÁÓÔÉ WHERE"
+ serbian "Vi koristite safe update mod servera, a probali ste da promenite podatke bez 'WHERE' komande koja koristi kolonu kljuèa"
+ spa "Tu estás usando modo de actualización segura y tentado actualizar una tabla sin un WHERE que usa una KEY columna"
+ swe "Du använder 'säker uppdateringsmod' och försökte uppdatera en tabell utan en WHERE-sats som använder sig av en nyckel"
+ ukr "÷É Õ ÒÅÖÉͦ ÂÅÚÐÅÞÎÏÇÏ ÏÎÏ×ÌÅÎÎÑ ÔÁ ÎÁÍÁÇÁ¤ÔÅÓØ ÏÎÏ×ÉÔÉ ÔÁÂÌÉÃÀ ÂÅÚ ÏÐÅÒÁÔÏÒÁ WHERE, ÝÏ ×ÉËÏÒÉÓÔÏ×Õ¤ KEY ÓÔÏ×ÂÅÃØ"
+ER_KEY_DOES_NOT_EXITS
+ cze "Kl-Bíè '%-.64s' v tabulce '%-.64s' neexistuje"
+ dan "Nøglen '%-.64s' eksisterer ikke i tabellen '%-.64s'"
+ nla "Zoeksleutel '%-.64s' bestaat niet in tabel '%-.64s'"
+ eng "Key '%-.64s' doesn't exist in table '%-.64s'"
+ est "Võti '%-.64s' ei eksisteeri tabelis '%-.64s'"
+ fre "L'index '%-.64s' n'existe pas sur la table '%-.64s'"
+ ger "Schlüssel '%-.64s' existiert in der Tabelle '%-.64s' nicht"
+ hun "A '%-.64s' kulcs nem letezik a '%-.64s' tablaban"
+ ita "La chiave '%-.64s' non esiste nella tabella '%-.64s'"
+ por "Chave '%-.64s' não existe na tabela '%-.64s'"
+ rus "ëÌÀÞ '%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ × ÔÁÂÌÉÃÅ '%-.64s'"
+ serbian "Kljuè '%-.64s' ne postoji u tabeli '%-.64s'"
+ spa "Clave '%-.64s' no existe en la tabla '%-.64s'"
+ swe "Nyckel '%-.64s' finns inte in tabell '%-.64s'"
+ ukr "ëÌÀÞ '%-.64s' ÎÅ ¦ÓÎÕ¤ × ÔÁÂÌÉæ '%-.64s'"
+ER_CHECK_NO_SUCH_TABLE 42000
+ cze "Nemohu otev-Bøít tabulku"
+ dan "Kan ikke åbne tabellen"
+ nla "Kan tabel niet openen"
+ eng "Can't open table"
+ est "Ei suuda avada tabelit"
+ fre "Impossible d'ouvrir la table"
+ ger "Kann Tabelle nicht öffnen"
+ hun "Nem tudom megnyitni a tablat"
+ ita "Impossibile aprire la tabella"
+ por "Não pode abrir a tabela"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ"
+ serbian "Ne mogu da otvorim tabelu"
+ spa "No puedo abrir tabla"
+ swe "Kan inte öppna tabellen"
+ ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÔÁÂÌÉÃÀ"
+ER_CHECK_NOT_IMPLEMENTED 42000
+ cze "Handler tabulky nepodporuje %s"
+ dan "Denne tabeltype understøtter ikke %s"
+ nla "De 'handler' voor de tabel ondersteund geen %s"
+ eng "The storage engine for the table doesn't support %s"
+ est "Antud tabelitüüp ei toeta %s käske"
+ fre "Ce type de table ne supporte pas les %s"
+ ger "Die Speicher-Engine für diese Tabelle unterstützt kein %s"
+ greek "The handler for the table doesn't support %s"
+ hun "A tabla kezeloje (handler) nem tamogatja az %s"
+ ita "Il gestore per la tabella non supporta il %s"
+ jpn "The handler for the table doesn't support %s"
+ kor "The handler for the table doesn't support %s"
+ nor "The handler for the table doesn't support %s"
+ norwegian-ny "The handler for the table doesn't support %s"
+ pol "The handler for the table doesn't support %s"
+ por "O manipulador de tabela não suporta %s"
+ rum "The handler for the table doesn't support %s"
+ rus "ïÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÜÔÏÇÏ: %s"
+ serbian "Handler za ovu tabelu ne dozvoljava 'check' odnosno 'repair' komande"
+ slo "The handler for the table doesn't support %s"
+ spa "El manipulador de la tabla no permite soporte para %s"
+ swe "Tabellhanteraren för denna tabell kan inte göra %s"
+ ukr "÷ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕÅ %s"
+ER_CANT_DO_THIS_DURING_AN_TRANSACTION 25000
+ cze "Proveden-Bí tohoto pøíkazu není v transakci dovoleno"
+ dan "Du må ikke bruge denne kommando i en transaktion"
+ nla "Het is u niet toegestaan dit commando uit te voeren binnen een transactie"
+ eng "You are not allowed to execute this command in a transaction"
+ est "Seda käsku ei saa kasutada transaktsiooni sees"
+ fre "Vous n'êtes pas autorisé à exécute cette commande dans une transaction"
+ ger "Sie dürfen diesen Befehl nicht in einer Transaktion ausführen"
+ hun "Az On szamara nem engedelyezett a parancs vegrehajtasa a tranzakcioban"
+ ita "Non puoi eseguire questo comando in una transazione"
+ por "Não lhe é permitido executar este comando em uma transação"
+ rus "÷ÁÍ ÎÅ ÒÁÚÒÅÛÅÎÏ ×ÙÐÏÌÎÑÔØ ÜÔÕ ËÏÍÁÎÄÕ × ÔÒÁÎÚÁËÃÉÉ"
+ serbian "Nije Vam dozvoljeno da izvršite ovu komandu u transakciji"
+ spa "No tienes el permiso para ejecutar este comando en una transición"
+ swe "Du får inte utföra detta kommando i en transaktion"
+ ukr "÷ÁÍ ÎÅ ÄÏÚ×ÏÌÅÎÏ ×ÉËÏÎÕ×ÁÔÉ ÃÀ ËÏÍÁÎÄÕ × ÔÒÁÎÚÁËæ§"
+ER_ERROR_DURING_COMMIT
+ cze "Chyba %d p-Bøi COMMIT"
+ dan "Modtog fejl %d mens kommandoen COMMIT blev udført"
+ nla "Kreeg fout %d tijdens COMMIT"
+ eng "Got error %d during COMMIT"
+ est "Viga %d käsu COMMIT täitmisel"
+ fre "Erreur %d lors du COMMIT"
+ ger "Fehler %d beim COMMIT"
+ hun "%d hiba a COMMIT vegrehajtasa soran"
+ ita "Rilevato l'errore %d durante il COMMIT"
+ por "Obteve erro %d durante COMMIT"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ COMMIT"
+ serbian "Greška %d za vreme izvršavanja komande 'COMMIT'"
+ spa "Obtenido error %d durante COMMIT"
+ swe "Fick fel %d vid COMMIT"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ COMMIT"
+ER_ERROR_DURING_ROLLBACK
+ cze "Chyba %d p-Bøi ROLLBACK"
+ dan "Modtog fejl %d mens kommandoen ROLLBACK blev udført"
+ nla "Kreeg fout %d tijdens ROLLBACK"
+ eng "Got error %d during ROLLBACK"
+ est "Viga %d käsu ROLLBACK täitmisel"
+ fre "Erreur %d lors du ROLLBACK"
+ ger "Fehler %d beim ROLLBACK"
+ hun "%d hiba a ROLLBACK vegrehajtasa soran"
+ ita "Rilevato l'errore %d durante il ROLLBACK"
+ por "Obteve erro %d durante ROLLBACK"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ ROLLBACK"
+ serbian "Greška %d za vreme izvršavanja komande 'ROLLBACK'"
+ spa "Obtenido error %d durante ROLLBACK"
+ swe "Fick fel %d vid ROLLBACK"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ ROLLBACK"
+ER_ERROR_DURING_FLUSH_LOGS
+ cze "Chyba %d p-Bøi FLUSH_LOGS"
+ dan "Modtog fejl %d mens kommandoen FLUSH_LOGS blev udført"
+ nla "Kreeg fout %d tijdens FLUSH_LOGS"
+ eng "Got error %d during FLUSH_LOGS"
+ est "Viga %d käsu FLUSH_LOGS täitmisel"
+ fre "Erreur %d lors du FLUSH_LOGS"
+ ger "Fehler %d bei FLUSH_LOGS"
+ hun "%d hiba a FLUSH_LOGS vegrehajtasa soran"
+ ita "Rilevato l'errore %d durante il FLUSH_LOGS"
+ por "Obteve erro %d durante FLUSH_LOGS"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ FLUSH_LOGS"
+ serbian "Greška %d za vreme izvršavanja komande 'FLUSH_LOGS'"
+ spa "Obtenido error %d durante FLUSH_LOGS"
+ swe "Fick fel %d vid FLUSH_LOGS"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ FLUSH_LOGS"
+ER_ERROR_DURING_CHECKPOINT
+ cze "Chyba %d p-Bøi CHECKPOINT"
+ dan "Modtog fejl %d mens kommandoen CHECKPOINT blev udført"
+ nla "Kreeg fout %d tijdens CHECKPOINT"
+ eng "Got error %d during CHECKPOINT"
+ est "Viga %d käsu CHECKPOINT täitmisel"
+ fre "Erreur %d lors du CHECKPOINT"
+ ger "Fehler %d bei CHECKPOINT"
+ hun "%d hiba a CHECKPOINT vegrehajtasa soran"
+ ita "Rilevato l'errore %d durante il CHECKPOINT"
+ por "Obteve erro %d durante CHECKPOINT"
+ rus "ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ CHECKPOINT"
+ serbian "Greška %d za vreme izvršavanja komande 'CHECKPOINT'"
+ spa "Obtenido error %d durante CHECKPOINT"
+ swe "Fick fel %d vid CHECKPOINT"
+ ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ CHECKPOINT"
+ER_NEW_ABORTING_CONNECTION 08S01
+ cze "Spojen-Bí %ld do databáze: '%-.64s' u¾ivatel: '%-.32s' stroj: `%-.64s' (%-.64s) bylo pøeru¹eno"
+ dan "Afbrød forbindelsen %ld til databasen '%-.64s' bruger: '%-.32s' vært: `%-.64s' (%-.64s)"
+ nla "Afgebroken verbinding %ld naar db: '%-.64s' gebruiker: '%-.32s' host: `%-.64s' (%-.64s)"
+ eng "Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)"
+ est "Ühendus katkestatud %ld andmebaas: '%-.64s' kasutaja: '%-.32s' masin: `%-.64s' (%-.64s)"
+ fre "Connection %ld avortée vers la bd: '%-.64s' utilisateur: '%-.32s' hôte: `%-.64s' (%-.64s)"
+ ger "Verbindungsabbruch %ld zur Datenbank '%-.64s'. Benutzer: '%-.32s', Host: `%-.64s' (%-.64s)"
+ ita "Interrotta la connessione %ld al db: ''%-.64s' utente: '%-.32s' host: '%-.64s' (%-.64s)"
+ por "Conexão %ld abortada para banco de dados '%-.64s' - usuário '%-.32s' - 'host' `%-.64s' ('%-.64s')"
+ rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' Ó ÈÏÓÔÁ `%-.64s' (%-.64s)"
+ serbian "Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' a host: `%-.64s' (%-.64s)"
+ spa "Abortada conexión %ld para db: '%-.64s' usuario: '%-.32s' servidor: `%-.64s' (%-.64s)"
+ swe "Avbröt länken för tråd %ld till db '%-.64s', användare '%-.32s', host '%-.64s' (%-.64s)"
+ ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.64s' ËÏÒÉÓÔÕ×ÁÞ: '%-.32s' ÈÏÓÔ: `%-.64s' (%-.64s)"
+ER_DUMP_NOT_IMPLEMENTED
+ cze "Handler tabulky nepodporuje bin-Bární dump"
+ dan "Denne tabeltype unserstøtter ikke binært tabeldump"
+ nla "De 'handler' voor de tabel ondersteund geen binaire tabel dump"
+ eng "The storage engine for the table does not support binary table dump"
+ fre "Ce type de table ne supporte pas les copies binaires"
+ ger "Die Speicher-Engine für die Tabelle unterstützt keinen binären Tabellen-Dump"
+ ita "Il gestore per la tabella non supporta il dump binario"
+ jpn "The handler for the table does not support binary table dump"
+ por "O manipulador de tabela não suporta 'dump' binário de tabela"
+ rum "The handler for the table does not support binary table dump"
+ rus "ïÂÒÁÂÏÔÞÉË ÜÔÏÊ ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ Ä×ÏÉÞÎÏÇÏ ÓÏÈÒÁÎÅÎÉÑ ÏÂÒÁÚÁ ÔÁÂÌÉÃÙ (dump)"
+ serbian "Handler tabele ne podržava binarni dump tabele"
+ spa "El manipulador de tabla no soporta dump para tabla binaria"
+ swe "Tabellhanteraren klarar inte en binär kopiering av tabellen"
+ ukr "ãÅÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ ¦ÎÁÒÎÕ ÐÅÒÅÄÁÞÕ ÔÁÂÌÉæ"
+ER_FLUSH_MASTER_BINLOG_CLOSED
+ eng "Binlog closed, cannot RESET MASTER"
+ ger "Binlog geschlossen. Kann RESET MASTER nicht ausführen"
+ por "Binlog fechado. Não pode fazer RESET MASTER"
+ rus "ä×ÏÉÞÎÙÊ ÖÕÒÎÁÌ ÏÂÎÏ×ÌÅÎÉÑ ÚÁËÒÙÔ, ÎÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ RESET MASTER"
+ serbian "Binarni log file zatvoren, ne mogu da izvršim komandu 'RESET MASTER'"
+ ukr "òÅÐ̦ËÁæÊÎÉÊ ÌÏÇ ÚÁËÒÉÔÏ, ÎÅ ÍÏÖÕ ×ÉËÏÎÁÔÉ RESET MASTER"
+ER_INDEX_REBUILD
+ cze "P-Bøebudování indexu dumpnuté tabulky '%-.64s' nebylo úspì¹né"
+ dan "Kunne ikke genopbygge indekset for den dumpede tabel '%-.64s'"
+ nla "Gefaald tijdens heropbouw index van gedumpte tabel '%-.64s'"
+ eng "Failed rebuilding the index of dumped table '%-.64s'"
+ fre "La reconstruction de l'index de la table copiée '%-.64s' a échoué"
+ ger "Neuerstellung des Indizes der Dump-Tabelle '%-.64s' fehlgeschlagen"
+ greek "Failed rebuilding the index of dumped table '%-.64s'"
+ hun "Failed rebuilding the index of dumped table '%-.64s'"
+ ita "Fallita la ricostruzione dell'indice della tabella copiata '%-.64s'"
+ por "Falhou na reconstrução do índice da tabela 'dumped' '%-.64s'"
+ rus "ïÛÉÂËÁ ÐÅÒÅÓÔÒÏÊËÉ ÉÎÄÅËÓÁ ÓÏÈÒÁÎÅÎÎÏÊ ÔÁÂÌÉÃÙ '%-.64s'"
+ serbian "Izgradnja indeksa dump-ovane tabele '%-.64s' nije uspela"
+ spa "Falla reconstruyendo el indice de la tabla dumped '%-.64s'"
+ ukr "îÅ×ÄÁÌŠצÄÎÏ×ÌÅÎÎÑ ¦ÎÄÅËÓÁ ÐÅÒÅÄÁÎϧ ÔÁÂÌÉæ '%-.64s'"
+ER_MASTER
+ cze "Chyba masteru: '%-.64s'"
+ dan "Fejl fra master: '%-.64s'"
+ nla "Fout van master: '%-.64s'"
+ eng "Error from master: '%-.64s'"
+ fre "Erreur reçue du maître: '%-.64s'"
+ ger "Fehler vom Master: '%-.64s'"
+ ita "Errore dal master: '%-.64s"
+ por "Erro no 'master' '%-.64s'"
+ rus "ïÛÉÂËÁ ÏÔ ÇÏÌÏ×ÎÏÇÏ ÓÅÒ×ÅÒÁ: '%-.64s'"
+ serbian "Greška iz glavnog servera '%-.64s' u klasteru"
+ spa "Error del master: '%-.64s'"
+ swe "Fick en master: '%-.64s'"
+ ukr "ðÏÍÉÌËÁ ×¦Ä ÇÏÌÏ×ÎÏÇÏ: '%-.64s'"
+ER_MASTER_NET_READ 08S01
+ cze "S-Bí»ová chyba pøi ètení z masteru"
+ dan "Netværksfejl ved læsning fra master"
+ nla "Net fout tijdens lezen van master"
+ eng "Net error reading from master"
+ fre "Erreur de lecture réseau reçue du maître"
+ ger "Netzfehler beim Lesen vom Master"
+ ita "Errore di rete durante la ricezione dal master"
+ por "Erro de rede lendo do 'master'"
+ rus "÷ÏÚÎÉËÌÁ ÏÛÉÂËÁ ÞÔÅÎÉÑ × ÐÒÏÃÅÓÓÅ ËÏÍÍÕÎÉËÁÃÉÉ Ó ÇÏÌÏ×ÎÙÍ ÓÅÒ×ÅÒÏÍ"
+ serbian "Greška u primanju mrežnih paketa sa glavnog servera u klasteru"
+ spa "Error de red leyendo del master"
+ swe "Fick nätverksfel vid läsning från master"
+ ukr "íÅÒÅÖÅ×Á ÐÏÍÉÌËÁ ÞÉÔÁÎÎÑ ×¦Ä ÇÏÌÏ×ÎÏÇÏ"
+ER_MASTER_NET_WRITE 08S01
+ cze "S-Bí»ová chyba pøi zápisu na master"
+ dan "Netværksfejl ved skrivning til master"
+ nla "Net fout tijdens schrijven naar master"
+ eng "Net error writing to master"
+ fre "Erreur d'écriture réseau reçue du maître"
+ ger "Netzfehler beim Schreiben zum Master"
+ ita "Errore di rete durante l'invio al master"
+ por "Erro de rede gravando no 'master'"
+ rus "÷ÏÚÎÉËÌÁ ÏÛÉÂËÁ ÚÁÐÉÓÉ × ÐÒÏÃÅÓÓÅ ËÏÍÍÕÎÉËÁÃÉÉ Ó ÇÏÌÏ×ÎÙÍ ÓÅÒ×ÅÒÏÍ"
+ serbian "Greška u slanju mrežnih paketa na glavni server u klasteru"
+ spa "Error de red escribiendo para el master"
+ swe "Fick nätverksfel vid skrivning till master"
+ ukr "íÅÒÅÖÅ×Á ÐÏÍÉÌËÁ ÚÁÐÉÓÕ ÄÏ ÇÏÌÏ×ÎÏÇÏ"
+ER_FT_MATCHING_KEY_NOT_FOUND
+ cze "-B®ádný sloupec nemá vytvoøen fulltextový index"
+ dan "Kan ikke finde en FULLTEXT nøgle som svarer til kolonne listen"
+ nla "Kan geen FULLTEXT index vinden passend bij de kolom lijst"
+ eng "Can't find FULLTEXT index matching the column list"
+ est "Ei suutnud leida FULLTEXT indeksit, mis kattuks kasutatud tulpadega"
+ fre "Impossible de trouver un index FULLTEXT correspondant à cette liste de colonnes"
+ ger "Kann keinen FULLTEXT-Index finden, der der Spaltenliste entspricht"
+ ita "Impossibile trovare un indice FULLTEXT che corrisponda all'elenco delle colonne"
+ por "Não pode encontrar um índice para o texto todo que combine com a lista de colunas"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÏÔÙÓËÁÔØ ÐÏÌÎÏÔÅËÓÔÏ×ÙÊ (FULLTEXT) ÉÎÄÅËÓ, ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÓÐÉÓËÕ ÓÔÏÌÂÃÏ×"
+ serbian "Ne mogu da pronaðem 'FULLTEXT' indeks koli odgovara listi kolona"
+ spa "No puedo encontrar índice FULLTEXT correspondiendo a la lista de columnas"
+ swe "Hittar inte ett FULLTEXT-index i kolumnlistan"
+ ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ FULLTEXT ¦ÎÄÅËÓ, ÝÏ ×¦ÄÐÏצÄÁ¤ ÐÅÒÅ̦ËÕ ÓÔÏ×Âæ×"
+ER_LOCK_OR_ACTIVE_TRANSACTION
+ cze "Nemohu prov-Bést zadaný pøíkaz, proto¾e existují aktivní zamèené tabulky nebo aktivní transakce"
+ dan "Kan ikke udføre den givne kommando fordi der findes aktive, låste tabeller eller fordi der udføres en transaktion"
+ nla "Kan het gegeven commando niet uitvoeren, want u heeft actieve gelockte tabellen of een actieve transactie"
+ eng "Can't execute the given command because you have active locked tables or an active transaction"
+ est "Ei suuda täita antud käsku kuna on aktiivseid lukke või käimasolev transaktsioon"
+ fre "Impossible d'exécuter la commande car vous avez des tables verrouillées ou une transaction active"
+ ger "Kann den angegebenen Befehl wegen einer aktiven Tabellensperre oder einer aktiven Transaktion nicht ausführen"
+ ita "Impossibile eseguire il comando richiesto: tabelle sotto lock o transazione in atto"
+ por "Não pode executar o comando dado porque você tem tabelas ativas travadas ou uma transação ativa"
+ rus "îÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ ÕËÁÚÁÎÎÕÀ ËÏÍÁÎÄÕ, ÐÏÓËÏÌØËÕ Õ ×ÁÓ ÐÒÉÓÕÔÓÔ×ÕÀÔ ÁËÔÉ×ÎÏ ÚÁÂÌÏËÉÒÏ×ÁÎÎÙÅ ÔÁÂÌÉÃÁ ÉÌÉ ÏÔËÒÙÔÁÑ ÔÒÁÎÚÁËÃÉÑ"
+ serbian "Ne mogu da izvršim datu komandu zbog toga što su tabele zakljuèane ili je transakcija u toku"
+ spa "No puedo ejecutar el comando dado porque tienes tablas bloqueadas o una transición activa"
+ swe "Kan inte utföra kommandot emedan du har en låst tabell eller an aktiv transaktion"
+ ukr "îÅ ÍÏÖÕ ×ÉËÏÎÁÔÉ ÐÏÄÁÎÕ ËÏÍÁÎÄÕ ÔÏÍÕ, ÝÏ ÔÁÂÌÉÃÑ ÚÁÂÌÏËÏ×ÁÎÁ ÁÂÏ ×ÉËÏÎÕ¤ÔØÓÑ ÔÒÁÎÚÁËæÑ"
+ER_UNKNOWN_SYSTEM_VARIABLE
+ cze "Nezn-Bámá systémová promìnná '%-.64s'"
+ dan "Ukendt systemvariabel '%-.64s'"
+ nla "Onbekende systeem variabele '%-.64s'"
+ eng "Unknown system variable '%-.64s'"
+ est "Tundmatu süsteemne muutuja '%-.64s'"
+ fre "Variable système '%-.64s' inconnue"
+ ger "Unbekannte Systemvariable '%-.64s'"
+ ita "Variabile di sistema '%-.64s' sconosciuta"
+ por "Variável de sistema '%-.64s' desconhecida"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ÓÉÓÔÅÍÎÁÑ ÐÅÒÅÍÅÎÎÁÑ '%-.64s'"
+ serbian "Nepoznata sistemska promenljiva '%-.64s'"
+ spa "Desconocida variable de sistema '%-.64s'"
+ swe "Okänd systemvariabel: '%-.64s'"
+ ukr "îÅצÄÏÍÁ ÓÉÓÔÅÍÎÁ ÚͦÎÎÁ '%-.64s'"
+ER_CRASHED_ON_USAGE
+ cze "Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a mìla by být opravena"
+ dan "Tabellen '%-.64s' er markeret med fejl og bør repareres"
+ nla "Tabel '%-.64s' staat als gecrashed gemarkeerd en dient te worden gerepareerd"
+ eng "Table '%-.64s' is marked as crashed and should be repaired"
+ est "Tabel '%-.64s' on märgitud vigaseks ja tuleb parandada"
+ fre "La table '%-.64s' est marquée 'crashed' et devrait être réparée"
+ ger "Tabelle '%-.64s' ist als defekt markiert und sollte repariert werden"
+ ita "La tabella '%-.64s' e` segnalata come corrotta e deve essere riparata"
+ por "Tabela '%-.64s' está marcada como danificada e deve ser reparada"
+ rus "ôÁÂÌÉÃÁ '%-.64s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÄÏÌÖÎÁ ÐÒÏÊÔÉ ÐÒÏ×ÅÒËÕ É ÒÅÍÏÎÔ"
+ serbian "Tabela '%-.64s' je markirana kao ošteæena i trebala bi biti popravljena"
+ spa "Tabla '%-.64s' está marcada como crashed y debe ser reparada"
+ swe "Tabell '%-.64s' är trasig och bör repareras med REPAIR TABLE"
+ ukr "ôÁÂÌÉÃÀ '%-.64s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ §§ ÐÏÔÒ¦ÂÎÏ ×¦ÄÎÏ×ÉÔÉ"
+ER_CRASHED_ON_REPAIR
+ cze "Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila"
+ dan "Tabellen '%-.64s' er markeret med fejl og sidste (automatiske?) REPAIR fejlede"
+ nla "Tabel '%-.64s' staat als gecrashed gemarkeerd en de laatste (automatische?) reparatie poging mislukte"
+ eng "Table '%-.64s' is marked as crashed and last (automatic?) repair failed"
+ est "Tabel '%-.64s' on märgitud vigaseks ja viimane (automaatne?) parandus ebaõnnestus"
+ fre "La table '%-.64s' est marquée 'crashed' et le dernier 'repair' a échoué"
+ ger "Tabelle '%-.64s' ist als defekt markiert und der letzte (automatische?) Reparaturversuch schlug fehl"
+ ita "La tabella '%-.64s' e` segnalata come corrotta e l'ultima ricostruzione (automatica?) e` fallita"
+ por "Tabela '%-.64s' está marcada como danificada e a última reparação (automática?) falhou"
+ rus "ôÁÂÌÉÃÁ '%-.64s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÐÏÓÌÅÄÎÉÊ (Á×ÔÏÍÁÔÉÞÅÓËÉÊ?) ÒÅÍÏÎÔ ÎÅ ÂÙÌ ÕÓÐÅÛÎÙÍ"
+ serbian "Tabela '%-.64s' je markirana kao ošteæena, a zadnja (automatska?) popravka je bila neuspela"
+ spa "Tabla '%-.64s' está marcada como crashed y la última reparación (automactica?) falló"
+ swe "Tabell '%-.64s' är trasig och senast (automatiska?) reparation misslyckades"
+ ukr "ôÁÂÌÉÃÀ '%-.64s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ ÏÓÔÁÎΤ (Á×ÔÏÍÁÔÉÞÎÅ?) צÄÎÏ×ÌÅÎÎÑ ÎÅ ×ÄÁÌÏÓÑ"
+ER_WARNING_NOT_COMPLETE_ROLLBACK
+ dan "Advarsel: Visse data i tabeller der ikke understøtter transaktioner kunne ikke tilbagestilles"
+ nla "Waarschuwing: Roll back mislukt voor sommige buiten transacties gewijzigde tabellen"
+ eng "Some non-transactional changed tables couldn't be rolled back"
+ est "Hoiatus: mõnesid transaktsioone mittetoetavaid tabeleid ei suudetud tagasi kerida"
+ fre "Attention: certaines tables ne supportant pas les transactions ont été changées et elles ne pourront pas être restituées"
+ ger "Änderungen an einigen nicht transaktionalen Tabellen konnten nicht zurückgerollt werden"
+ ita "Attenzione: Alcune delle modifiche alle tabelle non transazionali non possono essere ripristinate (roll back impossibile)"
+ por "Aviso: Algumas tabelas não-transacionais alteradas não puderam ser reconstituídas (rolled back)"
+ rus "÷ÎÉÍÁÎÉÅ: ÐÏ ÎÅËÏÔÏÒÙÍ ÉÚÍÅÎÅÎÎÙÍ ÎÅÔÒÁÎÚÁËÃÉÏÎÎÙÍ ÔÁÂÌÉÃÁÍ ÎÅ×ÏÚÍÏÖÎÏ ÂÕÄÅÔ ÐÒÏÉÚ×ÅÓÔÉ ÏÔËÁÔ ÔÒÁÎÚÁËÃÉÉ"
+ serbian "Upozorenje: Neke izmenjene tabele ne podržavaju komandu 'ROLLBACK'"
+ spa "Aviso: Algunas tablas no transancionales no pueden tener rolled back"
+ swe "Warning: Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK"
+ ukr "úÁÓÔÅÒÅÖÅÎÎÑ: äÅÑ˦ ÎÅÔÒÁÎÚÁËæÊΦ ÚͦÎÉ ÔÁÂÌÉÃØ ÎÅ ÍÏÖÎÁ ÂÕÄÅ ÐÏ×ÅÒÎÕÔÉ"
+ER_TRANS_CACHE_FULL
+ dan "Fler-udtryks transaktion krævede mere plads en 'max_binlog_cache_size' bytes. Forhøj værdien af denne variabel og prøv igen"
+ nla "Multi-statement transactie vereist meer dan 'max_binlog_cache_size' bytes opslag. Verhoog deze mysqld variabele en probeer opnieuw"
+ eng "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again"
+ est "Mitme lausendiga transaktsioon nõudis rohkem ruumi kui lubatud 'max_binlog_cache_size' muutujaga. Suurenda muutuja väärtust ja proovi uuesti"
+ fre "Cette transaction à commandes multiples nécessite plus de 'max_binlog_cache_size' octets de stockage, augmentez cette variable de mysqld et réessayez"
+ ger "Transaktionen, die aus mehreren Befehlen bestehen, benötigen mehr als 'max_binlog_cache_size' Bytes an Speicher. Diese mysqld-Variable bitte vergrössern und erneut versuchen"
+ ita "La transazione a comandi multipli (multi-statement) ha richiesto piu` di 'max_binlog_cache_size' bytes di disco: aumentare questa variabile di mysqld e riprovare"
+ por "Transações multi-declaradas (multi-statement transactions) requeriram mais do que o valor limite (max_binlog_cache_size) de bytes para armazenagem. Aumente o valor desta variável do mysqld e tente novamente"
+ rus "ôÒÁÎÚÁËÃÉÉ, ×ËÌÀÞÁÀÝÅÊ ÂÏÌØÛÏÅ ËÏÌÉÞÅÓÔ×Ï ËÏÍÁÎÄ, ÐÏÔÒÅÂÏ×ÁÌÏÓØ ÂÏÌÅÅ ÞÅÍ 'max_binlog_cache_size' ÂÁÊÔ. õ×ÅÌÉÞØÔÅ ÜÔÕ ÐÅÒÅÍÅÎÎÕÀ ÓÅÒ×ÅÒÁ mysqld É ÐÏÐÒÏÂÕÊÔÅ ÅÝÅ ÒÁÚ"
+ spa "Multipla transición necesita mas que 'max_binlog_cache_size' bytes de almacenamiento. Aumente esta variable mysqld y tente de nuevo"
+ swe "Transaktionen krävde mera än 'max_binlog_cache_size' minne. Öka denna mysqld-variabel och försök på nytt"
+ ukr "ôÒÁÎÚÁËÃ¦Ñ Ú ÂÁÇÁÔØÍÁ ×ÉÒÁÚÁÍÉ ×ÉÍÁÇÁ¤ ¦ÌØÛÅ Î¦Ö 'max_binlog_cache_size' ÂÁÊÔ¦× ÄÌÑ ÚÂÅÒ¦ÇÁÎÎÑ. ú¦ÌØÛÔÅ ÃÀ ÚͦÎÎÕ mysqld ÔÁ ÓÐÒÏÂÕÊÔÅ ÚÎÏ×Õ"
+ER_SLAVE_MUST_STOP
+ dan "Denne handling kunne ikke udføres med kørende slave, brug først kommandoen STOP SLAVE"
+ nla "Deze operatie kan niet worden uitgevoerd met een actieve slave, doe eerst STOP SLAVE"
+ eng "This operation cannot be performed with a running slave; run STOP SLAVE first"
+ fre "Cette opération ne peut être réalisée avec un esclave actif, faites STOP SLAVE d'abord"
+ ger "Diese Operation kann nicht bei einem aktiven Slave durchgeführt werden. Bitte zuerst STOP SLAVE ausführen"
+ ita "Questa operazione non puo' essere eseguita con un database 'slave' che gira, lanciare prima STOP SLAVE"
+ por "Esta operação não pode ser realizada com um 'slave' em execução. Execute STOP SLAVE primeiro"
+ rus "üÔÕ ÏÐÅÒÁÃÉÀ ÎÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ ÐÒÉ ÒÁÂÏÔÁÀÝÅÍ ÐÏÔÏËÅ ÐÏÄÞÉÎÅÎÎÏÇÏ ÓÅÒ×ÅÒÁ. óÎÁÞÁÌÁ ×ÙÐÏÌÎÉÔÅ STOP SLAVE"
+ serbian "Ova operacija ne može biti izvršena dok je aktivan podreðeni server. Zadajte prvo komandu 'STOP SLAVE' da zaustavite podreðeni server."
+ spa "Esta operación no puede ser hecha con el esclavo funcionando, primero use STOP SLAVE"
+ swe "Denna operation kan inte göras under replikering; Gör STOP SLAVE först"
+ ukr "ïÐÅÒÁÃ¦Ñ ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÎÁÎÁ Ú ÚÁÐÕÝÅÎÉÍ Ð¦ÄÌÅÇÌÉÍ, ÓÐÏÞÁÔËÕ ×ÉËÏÎÁÊÔÅ STOP SLAVE"
+ER_SLAVE_NOT_RUNNING
+ dan "Denne handling kræver en kørende slave. Konfigurer en slave og brug kommandoen START SLAVE"
+ nla "Deze operatie vereist een actieve slave, configureer slave en doe dan START SLAVE"
+ eng "This operation requires a running slave; configure slave and do START SLAVE"
+ fre "Cette opération nécessite un esclave actif, configurez les esclaves et faites START SLAVE"
+ ger "Diese Operation benötigt einen aktiven Slave. Bitte Slave konfigurieren und mittels START SLAVE aktivieren"
+ ita "Questa operaione richiede un database 'slave', configurarlo ed eseguire START SLAVE"
+ por "Esta operação requer um 'slave' em execução. Configure o 'slave' e execute START SLAVE"
+ rus "äÌÑ ÜÔÏÊ ÏÐÅÒÁÃÉÉ ÔÒÅÂÕÅÔÓÑ ÒÁÂÏÔÁÀÝÉÊ ÐÏÄÞÉÎÅÎÎÙÊ ÓÅÒ×ÅÒ. óÎÁÞÁÌÁ ×ÙÐÏÌÎÉÔÅ START SLAVE"
+ serbian "Ova operacija zahteva da je aktivan podreðeni server. Konfigurišite prvo podreðeni server i onda izvršite komandu 'START SLAVE'"
+ spa "Esta operación necesita el esclavo funcionando, configure esclavo y haga el START SLAVE"
+ swe "Denna operation kan endast göras under replikering; Konfigurera slaven och gör START SLAVE"
+ ukr "ïÐÅÒÁÃ¦Ñ ×ÉÍÁÇÁ¤ ÚÁÐÕÝÅÎÏÇÏ Ð¦ÄÌÅÇÌÏÇÏ, ÚËÏÎƦÇÕÒÕÊÔŠЦÄÌÅÇÌÏÇÏ ÔÁ ×ÉËÏÎÁÊÔÅ START SLAVE"
+ER_BAD_SLAVE
+ dan "Denne server er ikke konfigureret som slave. Ret in config-filen eller brug kommandoen CHANGE MASTER TO"
+ nla "De server is niet geconfigureerd als slave, fix in configuratie bestand of met CHANGE MASTER TO"
+ eng "The server is not configured as slave; fix in config file or with CHANGE MASTER TO"
+ fre "Le server n'est pas configuré comme un esclave, changez le fichier de configuration ou utilisez CHANGE MASTER TO"
+ ger "Der Server ist nicht als Slave konfiguriert. Bitte in der Konfigurationsdatei oder mittels CHANGE MASTER TO beheben"
+ ita "Il server non e' configurato come 'slave', correggere il file di configurazione cambiando CHANGE MASTER TO"
+ por "O servidor não está configurado como 'slave'. Acerte o arquivo de configuração ou use CHANGE MASTER TO"
+ rus "üÔÏÔ ÓÅÒ×ÅÒ ÎÅ ÎÁÓÔÒÏÅÎ ËÁË ÐÏÄÞÉÎÅÎÎÙÊ. ÷ÎÅÓÉÔÅ ÉÓÐÒÁ×ÌÅÎÉÑ × ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÍ ÆÁÊÌÅ ÉÌÉ Ó ÐÏÍÏÝØÀ CHANGE MASTER TO"
+ serbian "Server nije konfigurisan kao podreðeni server, ispravite konfiguracioni file ili na njemu izvršite komandu 'CHANGE MASTER TO'"
+ spa "El servidor no está configurado como esclavo, edite el archivo config file o con CHANGE MASTER TO"
+ swe "Servern är inte konfigurerade som en replikationsslav. Ändra konfigurationsfilen eller gör CHANGE MASTER TO"
+ ukr "óÅÒ×ÅÒ ÎÅ ÚËÏÎƦÇÕÒÏ×ÁÎÏ ÑË Ð¦ÄÌÅÇÌÉÊ, ×ÉÐÒÁ×ÔÅ ÃÅ Õ ÆÁÊ̦ ËÏÎƦÇÕÒÁæ§ ÁÂÏ Ú CHANGE MASTER TO"
+ER_MASTER_INFO
+ eng "Could not initialize master info structure; more error messages can be found in the MySQL error log"
+ fre "Impossible d'initialiser les structures d'information de maître, vous trouverez des messages d'erreur supplémentaires dans le journal des erreurs de MySQL"
+ serbian "Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info'"
+ swe "Kunde inte initialisera replikationsstrukturerna. See MySQL fel fil för mera information"
+ER_SLAVE_THREAD
+ dan "Kunne ikke danne en slave-tråd; check systemressourcerne"
+ nla "Kon slave thread niet aanmaken, controleer systeem resources"
+ eng "Could not create slave thread; check system resources"
+ fre "Impossible de créer une tâche esclave, vérifiez les ressources système"
+ ger "Konnte keinen Slave-Thread starten. Bitte System-Ressourcen überprüfen"
+ ita "Impossibile creare il thread 'slave', controllare le risorse di sistema"
+ por "Não conseguiu criar 'thread' de 'slave'. Verifique os recursos do sistema"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÐÏÔÏË ÐÏÄÞÉÎÅÎÎÏÇÏ ÓÅÒ×ÅÒÁ. ðÒÏ×ÅÒØÔÅ ÓÉÓÔÅÍÎÙÅ ÒÅÓÕÒÓÙ"
+ serbian "Nisam mogao da startujem thread za podreðeni server, proverite sistemske resurse"
+ spa "No puedo crear el thread esclavo, verifique recursos del sistema"
+ swe "Kunde inte starta en tråd för replikering"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ Ð¦ÄÌÅÇÌÕ Ç¦ÌËÕ, ÐÅÒÅצÒÔÅ ÓÉÓÔÅÍΦ ÒÅÓÕÒÓÉ"
+ER_TOO_MANY_USER_CONNECTIONS 42000
+ dan "Brugeren %-.64s har allerede mere end 'max_user_connections' aktive forbindelser"
+ nla "Gebruiker %-.64s heeft reeds meer dan 'max_user_connections' actieve verbindingen"
+ eng "User %-.64s already has more than 'max_user_connections' active connections"
+ est "Kasutajal %-.64s on juba rohkem ühendusi kui lubatud 'max_user_connections' muutujaga"
+ fre "L'utilisateur %-.64s possède déjà plus de 'max_user_connections' connections actives"
+ ger "Benutzer '%-.64s' hat mehr als max_user_connections aktive Verbindungen"
+ ita "L'utente %-.64s ha gia' piu' di 'max_user_connections' connessioni attive"
+ por "Usuário '%-.64s' já possui mais que o valor máximo de conexões (max_user_connections) ativas"
+ rus "õ ÐÏÌØÚÏ×ÁÔÅÌÑ %-.64s ÕÖÅ ÂÏÌØÛÅ ÞÅÍ 'max_user_connections' ÁËÔÉ×ÎÙÈ ÓÏÅÄÉÎÅÎÉÊ"
+ serbian "Korisnik %-.64s veæ ima više aktivnih konekcija nego što je to odreðeno 'max_user_connections' promenljivom"
+ spa "Usario %-.64s ya tiene mas que 'max_user_connections' conexiones activas"
+ swe "Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar"
+ ukr "ëÏÒÉÓÔÕ×ÁÞ %-.64s ×ÖÅ ÍÁ¤ ¦ÌØÛÅ Î¦Ö 'max_user_connections' ÁËÔÉ×ÎÉÈ Ú'¤ÄÎÁÎØ"
+ER_SET_CONSTANTS_ONLY
+ dan "Du må kun bruge konstantudtryk med SET"
+ nla "U mag alleen constante expressies gebruiken bij SET"
+ eng "You may only use constant expressions with SET"
+ est "Ainult konstantsed suurused on lubatud SET klauslis"
+ fre "Seules les expressions constantes sont autorisées avec SET"
+ ger "Bei SET dürfen nur konstante Ausdrücke verwendet werden"
+ ita "Si possono usare solo espressioni costanti con SET"
+ por "Você pode usar apenas expressões constantes com SET"
+ rus "÷Ù ÍÏÖÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ × SET ÔÏÌØËÏ ËÏÎÓÔÁÎÔÎÙÅ ×ÙÒÁÖÅÎÉÑ"
+ serbian "Možete upotrebiti samo konstantan iskaz sa komandom 'SET'"
+ spa "Tu solo debes usar expresiones constantes con SET"
+ swe "Man kan endast använda konstantuttryck med SET"
+ ukr "íÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÌÉÛÅ ×ÉÒÁÚÉ Ú¦ ÓÔÁÌÉÍÉ Õ SET"
+ER_LOCK_WAIT_TIMEOUT
+ dan "Lock wait timeout overskredet"
+ nla "Lock wacht tijd overschreden"
+ eng "Lock wait timeout exceeded; try restarting transaction"
+ est "Kontrollaeg ületatud luku järel ootamisel; Proovi transaktsiooni otsast alata"
+ fre "Timeout sur l'obtention du verrou"
+ ger "Beim Warten auf eine Sperre wurde die zulässige Wartezeit überschritten. Bitte versuchen Sie, die Transaktion neu zu starten"
+ ita "E' scaduto il timeout per l'attesa del lock"
+ por "Tempo de espera (timeout) de travamento excedido. Tente reiniciar a transação."
+ rus "ôÁÊÍÁÕÔ ÏÖÉÄÁÎÉÑ ÂÌÏËÉÒÏ×ËÉ ÉÓÔÅË; ÐÏÐÒÏÂÕÊÔÅ ÐÅÒÅÚÁÐÕÓÔÉÔØ ÔÒÁÎÚÁËÃÉÀ"
+ serbian "Vremenski limit za zakljuèavanje tabele je istekao; Probajte da ponovo startujete transakciju"
+ spa "Tiempo de bloqueo de espera excedido"
+ swe "Fick inte ett lås i tid ; Försök att starta om transaktionen"
+ ukr "úÁÔÒÉÍËÕ ÏÞ¦ËÕ×ÁÎÎÑ ÂÌÏËÕ×ÁÎÎÑ ×ÉÞÅÒÐÁÎÏ"
+ER_LOCK_TABLE_FULL
+ dan "Det totale antal låse overstiger størrelsen på låse-tabellen"
+ nla "Het totale aantal locks overschrijdt de lock tabel grootte"
+ eng "The total number of locks exceeds the lock table size"
+ est "Lukkude koguarv ületab lukutabeli suuruse"
+ fre "Le nombre total de verrou dépasse la taille de la table des verrous"
+ ger "Die Gesamtzahl der Sperren überschreitet die Größe der Sperrtabelle"
+ ita "Il numero totale di lock e' maggiore della grandezza della tabella di lock"
+ por "O número total de travamentos excede o tamanho da tabela de travamentos"
+ rus "ïÂÝÅÅ ËÏÌÉÞÅÓÔ×Ï ÂÌÏËÉÒÏ×ÏË ÐÒÅ×ÙÓÉÌÏ ÒÁÚÍÅÒÙ ÔÁÂÌÉÃÙ ÂÌÏËÉÒÏ×ÏË"
+ serbian "Broj totalnih zakljuèavanja tabele premašuje velièinu tabele zakljuèavanja"
+ spa "El número total de bloqueos excede el tamaño de bloqueo de la tabla"
+ swe "Antal lås överskrider antalet reserverade lås"
+ ukr "úÁÇÁÌØÎÁ ˦ÌØ˦ÓÔØ ÂÌÏËÕ×ÁÎØ ÐÅÒÅ×ÉÝÉÌÁ ÒÏÚÍ¦Ò ÂÌÏËÕ×ÁÎØ ÄÌÑ ÔÁÂÌÉæ"
+ER_READ_ONLY_TRANSACTION 25000
+ dan "Update lås kan ikke opnås under en READ UNCOMMITTED transaktion"
+ nla "Update locks kunnen niet worden verkregen tijdens een READ UNCOMMITTED transactie"
+ eng "Update locks cannot be acquired during a READ UNCOMMITTED transaction"
+ est "Uuenduslukke ei saa kasutada READ UNCOMMITTED transaktsiooni käigus"
+ fre "Un verrou en update ne peut être acquit pendant une transaction READ UNCOMMITTED"
+ ger "Während einer READ UNCOMMITED-Transaktion können keine UPDATE-Sperren angefordert werden"
+ ita "I lock di aggiornamento non possono essere acquisiti durante una transazione 'READ UNCOMMITTED'"
+ por "Travamentos de atualização não podem ser obtidos durante uma transação de tipo READ UNCOMMITTED"
+ rus "âÌÏËÉÒÏ×ËÉ ÏÂÎÏ×ÌÅÎÉÊ ÎÅÌØÚÑ ÐÏÌÕÞÉÔØ × ÐÒÏÃÅÓÓÅ ÞÔÅÎÉÑ ÎÅ ÐÒÉÎÑÔÏÊ (× ÒÅÖÉÍÅ READ UNCOMMITTED) ÔÒÁÎÚÁËÃÉÉ"
+ serbian "Zakljuèavanja izmena ne mogu biti realizovana sve dok traje 'READ UNCOMMITTED' transakcija"
+ spa "Bloqueos de actualización no pueden ser adqueridos durante una transición READ UNCOMMITTED"
+ swe "Updateringslås kan inte göras när man använder READ UNCOMMITTED"
+ ukr "ïÎÏ×ÉÔÉ ÂÌÏËÕ×ÁÎÎÑ ÎÅ ÍÏÖÌÉ×Ï ÎÁ ÐÒÏÔÑÚ¦ ÔÒÁÎÚÁËæ§ READ UNCOMMITTED"
+ER_DROP_DB_WITH_READ_LOCK
+ dan "DROP DATABASE er ikke tilladt mens en tråd holder på globalt read lock"
+ nla "DROP DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit"
+ eng "DROP DATABASE not allowed while thread is holding global read lock"
+ est "DROP DATABASE ei ole lubatud kui lõim omab globaalset READ lukku"
+ fre "DROP DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture"
+ ger "DROP DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält"
+ ita "DROP DATABASE non e' permesso mentre il thread ha un lock globale di lettura"
+ por "DROP DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura"
+ rus "îÅ ÄÏÐÕÓËÁÅÔÓÑ DROP DATABASE, ÐÏËÁ ÐÏÔÏË ÄÅÒÖÉÔ ÇÌÏÂÁÌØÎÕÀ ÂÌÏËÉÒÏ×ËÕ ÞÔÅÎÉÑ"
+ serbian "Komanda 'DROP DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka"
+ spa "DROP DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global"
+ swe "DROP DATABASE är inte tillåtet när man har ett globalt läslås"
+ ukr "DROP DATABASE ÎÅ ÄÏÚ×ÏÌÅÎÏ ÄÏËÉ Ç¦ÌËÁ ÐÅÒÅÂÕ×Á¤ Ð¦Ä ÚÁÇÁÌØÎÉÍ ÂÌÏËÕ×ÁÎÎÑÍ ÞÉÔÁÎÎÑ"
+ER_CREATE_DB_WITH_READ_LOCK
+ dan "CREATE DATABASE er ikke tilladt mens en tråd holder på globalt read lock"
+ nla "CREATE DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit"
+ eng "CREATE DATABASE not allowed while thread is holding global read lock"
+ est "CREATE DATABASE ei ole lubatud kui lõim omab globaalset READ lukku"
+ fre "CREATE DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture"
+ ger "CREATE DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält"
+ ita "CREATE DATABASE non e' permesso mentre il thread ha un lock globale di lettura"
+ por "CREATE DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura"
+ rus "îÅ ÄÏÐÕÓËÁÅÔÓÑ CREATE DATABASE, ÐÏËÁ ÐÏÔÏË ÄÅÒÖÉÔ ÇÌÏÂÁÌØÎÕÀ ÂÌÏËÉÒÏ×ËÕ ÞÔÅÎÉÑ"
+ serbian "Komanda 'CREATE DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka"
+ spa "CREATE DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global"
+ swe "CREATE DATABASE är inte tillåtet när man har ett globalt läslås"
+ ukr "CREATE DATABASE ÎÅ ÄÏÚ×ÏÌÅÎÏ ÄÏËÉ Ç¦ÌËÁ ÐÅÒÅÂÕ×Á¤ Ð¦Ä ÚÁÇÁÌØÎÉÍ ÂÌÏËÕ×ÁÎÎÑÍ ÞÉÔÁÎÎÑ"
+ER_WRONG_ARGUMENTS
+ nla "Foutieve parameters voor %s"
+ eng "Incorrect arguments to %s"
+ est "Vigased parameetrid %s-le"
+ fre "Mauvais arguments à %s"
+ ger "Falsche Argumente für %s"
+ ita "Argomenti errati a %s"
+ por "Argumentos errados para %s"
+ rus "îÅ×ÅÒÎÙÅ ÐÁÒÁÍÅÔÒÙ ÄÌÑ %s"
+ serbian "Pogrešni argumenti prosleðeni na %s"
+ spa "Argumentos errados para %s"
+ swe "Felaktiga argument till %s"
+ ukr "èÉÂÎÉÊ ÁÒÇÕÍÅÎÔ ÄÌÑ %s"
+ER_NO_PERMISSION_TO_CREATE_USER 42000
+ nla "'%-.32s'@'%-.64s' mag geen nieuwe gebruikers creeren"
+ eng "'%-.32s'@'%-.64s' is not allowed to create new users"
+ est "Kasutajal '%-.32s'@'%-.64s' ei ole lubatud luua uusi kasutajaid"
+ fre "'%-.32s'@'%-.64s' n'est pas autorisé à créer de nouveaux utilisateurs"
+ ger "'%-.32s'@'%-.64s' is nicht berechtigt, neue Benutzer hinzuzufügen"
+ ita "A '%-.32s'@'%-.64s' non e' permesso creare nuovi utenti"
+ por "Não é permitido a '%-.32s'@'%-.64s' criar novos usuários"
+ rus "'%-.32s'@'%-.64s' ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÓÏÚÄÁ×ÁÔØ ÎÏ×ÙÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ"
+ serbian "Korisniku '%-.32s'@'%-.64s' nije dozvoljeno da kreira nove korisnike"
+ spa "'%-.32s`@`%-.64s` no es permitido para crear nuevos usuarios"
+ swe "'%-.32s'@'%-.64s' har inte rättighet att skapa nya användare"
+ ukr "ëÏÒÉÓÔÕ×ÁÞÕ '%-.32s'@'%-.64s' ÎÅ ÄÏÚ×ÏÌÅÎÏ ÓÔ×ÏÒÀ×ÁÔÉ ÎÏ×ÉÈ ËÏÒÉÓÔÕ×ÁÞ¦×"
+ER_UNION_TABLES_IN_DIFFERENT_DIR
+ nla "Incorrecte tabel definitie; alle MERGE tabellen moeten tot dezelfde database behoren"
+ eng "Incorrect table definition; all MERGE tables must be in the same database"
+ est "Vigane tabelimääratlus; kõik MERGE tabeli liikmed peavad asuma samas andmebaasis"
+ fre "Définition de table incorrecte; toutes les tables MERGE doivent être dans la même base de donnée"
+ ger "Falsche Tabellendefinition. Alle MERGE-Tabellen müssen sich in derselben Datenbank befinden"
+ ita "Definizione della tabella errata; tutte le tabelle di tipo MERGE devono essere nello stesso database"
+ por "Definição incorreta da tabela. Todas as tabelas contidas na junção devem estar no mesmo banco de dados."
+ rus "îÅ×ÅÒÎÏÅ ÏÐÒÅÄÅÌÅÎÉÅ ÔÁÂÌÉÃÙ; ÷ÓÅ ÔÁÂÌÉÃÙ × MERGE ÄÏÌÖÎÙ ÐÒÉÎÁÄÌÅÖÁÔØ ÏÄÎÏÊ É ÔÏÊ ÖÅ ÂÁÚÅ ÄÁÎÎÙÈ"
+ serbian "Pogrešna definicija tabele; sve 'MERGE' tabele moraju biti u istoj bazi podataka"
+ spa "Incorrecta definición de la tabla; Todas las tablas MERGE deben estar en el mismo banco de datos"
+ swe "Felaktig tabelldefinition; alla tabeller i en MERGE-tabell måste vara i samma databas"
+ER_LOCK_DEADLOCK 40001
+ nla "Deadlock gevonden tijdens lock-aanvraag poging; Probeer herstart van de transactie"
+ eng "Deadlock found when trying to get lock; try restarting transaction"
+ est "Lukustamisel tekkis tupik (deadlock); alusta transaktsiooni otsast"
+ fre "Deadlock découvert en essayant d'obtenir les verrous : essayez de redémarrer la transaction"
+ ger "Beim Versuch, eine Sperre anzufordern, ist ein Deadlock aufgetreten. Versuchen Sie, die Transaktion erneut zu starten"
+ ita "Trovato deadlock durante il lock; Provare a far ripartire la transazione"
+ por "Encontrado um travamento fatal (deadlock) quando tentava obter uma trava. Tente reiniciar a transação."
+ rus "÷ÏÚÎÉËÌÁ ÔÕÐÉËÏ×ÁÑ ÓÉÔÕÁÃÉÑ × ÐÒÏÃÅÓÓÅ ÐÏÌÕÞÅÎÉÑ ÂÌÏËÉÒÏ×ËÉ; ðÏÐÒÏÂÕÊÔÅ ÐÅÒÅÚÁÐÕÓÔÉÔØ ÔÒÁÎÚÁËÃÉÀ"
+ serbian "Unakrsno zakljuèavanje pronaðeno kada sam pokušao da dobijem pravo na zakljuèavanje; Probajte da restartujete transakciju"
+ spa "Encontrado deadlock cuando tentando obtener el bloqueo; Tente recomenzar la transición"
+ swe "Fick 'DEADLOCK' vid låsförsök av block/rad. Försök att starta om transaktionen"
+ER_TABLE_CANT_HANDLE_FT
+ nla "Het gebruikte tabel type ondersteund geen FULLTEXT indexen"
+ eng "The used table type doesn't support FULLTEXT indexes"
+ est "Antud tabelitüüp ei toeta FULLTEXT indekseid"
+ fre "Le type de table utilisé ne supporte pas les index FULLTEXT"
+ ger "Der verwendete Tabellentyp unterstützt keine FULLTEXT-Indizes"
+ ita "La tabella usata non supporta gli indici FULLTEXT"
+ por "O tipo de tabela utilizado não suporta índices de texto completo (fulltext indexes)"
+ rus "éÓÐÏÌØÚÕÅÍÙÊ ÔÉÐ ÔÁÂÌÉà ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÏÌÎÏÔÅËÓÔÏ×ÙÈ ÉÎÄÅËÓÏ×"
+ serbian "Upotrebljeni tip tabele ne podržava 'FULLTEXT' indekse"
+ spa "El tipo de tabla usada no soporta índices FULLTEXT"
+ swe "Tabelltypen har inte hantering av FULLTEXT-index"
+ ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ FULLTEXT ¦ÎÄÅËÓ¦×"
+ER_CANNOT_ADD_FOREIGN
+ nla "Kan foreign key beperking niet toevoegen"
+ eng "Cannot add foreign key constraint"
+ fre "Impossible d'ajouter des contraintes d'index externe"
+ ger "Fremdschlüssel-Beschränkung konnte nicht hinzugefügt werden"
+ ita "Impossibile aggiungere il vincolo di integrita' referenziale (foreign key constraint)"
+ por "Não pode acrescentar uma restrição de chave estrangeira"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÄÏÂÁ×ÉÔØ ÏÇÒÁÎÉÞÅÎÉÑ ×ÎÅÛÎÅÇÏ ËÌÀÞÁ"
+ serbian "Ne mogu da dodam proveru spoljnog kljuèa"
+ spa "No puede adicionar clave extranjera constraint"
+ swe "Kan inte lägga till 'FOREIGN KEY constraint'"
+ER_NO_REFERENCED_ROW 23000
+ nla "Kan onderliggende rij niet toevoegen: foreign key beperking gefaald"
+ eng "Cannot add or update a child row: a foreign key constraint fails"
+ fre "Impossible d'ajouter un enregistrement fils : une constrainte externe l'empèche"
+ ger "Hinzufügen eines Kind-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl"
+ greek "Cannot add a child row: a foreign key constraint fails"
+ hun "Cannot add a child row: a foreign key constraint fails"
+ ita "Impossibile aggiungere la riga: un vincolo d'integrita' referenziale non e' soddisfatto"
+ norwegian-ny "Cannot add a child row: a foreign key constraint fails"
+ por "Não pode acrescentar uma linha filha: uma restrição de chave estrangeira falhou"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÄÏÂÁ×ÉÔØ ÉÌÉ ÏÂÎÏ×ÉÔØ ÄÏÞÅÒÎÀÀ ÓÔÒÏËÕ: ÐÒÏ×ÅÒËÁ ÏÇÒÁÎÉÞÅÎÉÊ ×ÎÅÛÎÅÇÏ ËÌÀÞÁ ÎÅ ×ÙÐÏÌÎÑÅÔÓÑ"
+ spa "No puede adicionar una línea hijo: falla de clave extranjera constraint"
+ swe "FOREIGN KEY-konflikt: Kan inte skriva barn"
+ER_ROW_IS_REFERENCED 23000
+ eng "Cannot delete or update a parent row: a foreign key constraint fails"
+ fre "Impossible de supprimer un enregistrement père : une constrainte externe l'empèche"
+ ger "Löschen eines Eltern-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl"
+ greek "Cannot delete a parent row: a foreign key constraint fails"
+ hun "Cannot delete a parent row: a foreign key constraint fails"
+ ita "Impossibile cancellare la riga: un vincolo d'integrita' referenziale non e' soddisfatto"
+ por "Não pode apagar uma linha pai: uma restrição de chave estrangeira falhou"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÉÌÉ ÏÂÎÏ×ÉÔØ ÒÏÄÉÔÅÌØÓËÕÀ ÓÔÒÏËÕ: ÐÒÏ×ÅÒËÁ ÏÇÒÁÎÉÞÅÎÉÊ ×ÎÅÛÎÅÇÏ ËÌÀÞÁ ÎÅ ×ÙÐÏÌÎÑÅÔÓÑ"
+ serbian "Ne mogu da izbrišem roditeljski slog: provera spoljnog kljuèa je neuspela"
+ spa "No puede deletar una línea padre: falla de clave extranjera constraint"
+ swe "FOREIGN KEY-konflikt: Kan inte radera fader"
+ER_CONNECT_TO_MASTER 08S01
+ nla "Fout bij opbouwen verbinding naar master: %-.128s"
+ eng "Error connecting to master: %-.128s"
+ ger "Fehler bei der Verbindung zum Master: %-.128s"
+ ita "Errore durante la connessione al master: %-.128s"
+ por "Erro conectando com o master: %-.128s"
+ rus "ïÛÉÂËÁ ÓÏÅÄÉÎÅÎÉÑ Ó ÇÏÌÏ×ÎÙÍ ÓÅÒ×ÅÒÏÍ: %-.128s"
+ spa "Error de coneccion a master: %-.128s"
+ swe "Fick fel vid anslutning till master: %-.128s"
+ER_QUERY_ON_MASTER
+ nla "Fout bij uitvoeren query op master: %-.128s"
+ eng "Error running query on master: %-.128s"
+ ger "Beim Ausführen einer Abfrage auf dem Master trat ein Fehler auf: %-.128s"
+ ita "Errore eseguendo una query sul master: %-.128s"
+ por "Erro rodando consulta no master: %-.128s"
+ rus "ïÛÉÂËÁ ×ÙÐÏÌÎÅÎÉÑ ÚÁÐÒÏÓÁ ÎÁ ÇÏÌÏ×ÎÏÍ ÓÅÒ×ÅÒÅ: %-.128s"
+ spa "Error executando el query en master: %-.128s"
+ swe "Fick fel vid utförande av command på mastern: %-.128s"
+ER_ERROR_WHEN_EXECUTING_COMMAND
+ nla "Fout tijdens uitvoeren van commando %s: %-.128s"
+ eng "Error when executing command %s: %-.128s"
+ est "Viga käsu %s täitmisel: %-.128s"
+ ger "Fehler beim Ausführen des Befehls %s: %-.128s"
+ ita "Errore durante l'esecuzione del comando %s: %-.128s"
+ por "Erro quando executando comando %s: %-.128s"
+ rus "ïÛÉÂËÁ ÐÒÉ ×ÙÐÏÌÎÅÎÉÉ ËÏÍÁÎÄÙ %s: %-.128s"
+ serbian "Greška pri izvršavanju komande %s: %-.128s"
+ spa "Error de %s: %-.128s"
+ swe "Fick fel vid utförande av %s: %-.128s"
+ER_WRONG_USAGE
+ nla "Foutief gebruik van %s en %s"
+ eng "Incorrect usage of %s and %s"
+ est "Vigane %s ja %s kasutus"
+ ger "Falsche Verwendung von %s und %s"
+ ita "Uso errato di %s e %s"
+ por "Uso errado de %s e %s"
+ rus "îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ %s É %s"
+ serbian "Pogrešna upotreba %s i %s"
+ spa "Equivocado uso de %s y %s"
+ swe "Felaktig använding av %s and %s"
+ ukr "Wrong usage of %s and %s"
+ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 21000
+ nla "De gebruikte SELECT commando's hebben een verschillend aantal kolommen"
+ eng "The used SELECT statements have a different number of columns"
+ est "Tulpade arv kasutatud SELECT lausetes ei kattu"
+ ger "Die verwendeten SELECT-Befehle liefern eine unterschiedliche Anzahl von Spalten zurück"
+ ita "La SELECT utilizzata ha un numero di colonne differente"
+ por "Os comandos SELECT usados têm diferente número de colunas"
+ rus "éÓÐÏÌØÚÏ×ÁÎÎÙÅ ÏÐÅÒÁÔÏÒÙ ×ÙÂÏÒËÉ (SELECT) ÄÁÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
+ serbian "Upotrebljene 'SELECT' komande adresiraju razlièit broj kolona"
+ spa "El comando SELECT usado tiene diferente número de columnas"
+ swe "SELECT-kommandona har olika antal kolumner"
+ER_CANT_UPDATE_WITH_READLOCK
+ nla "Kan de query niet uitvoeren vanwege een conflicterende read lock"
+ eng "Can't execute the query because you have a conflicting read lock"
+ est "Ei suuda täita päringut konfliktse luku tõttu"
+ ger "Augrund eines READ LOCK-Konflikts kann die Abfrage nicht ausgeführt werden"
+ ita "Impossibile eseguire la query perche' c'e' un conflitto con in lock di lettura"
+ por "Não posso executar a consulta porque você tem um conflito de travamento de leitura"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÉÓÐÏÌÎÉÔØ ÚÁÐÒÏÓ, ÐÏÓËÏÌØËÕ Õ ×ÁÓ ÕÓÔÁÎÏ×ÌÅÎÙ ËÏÎÆÌÉËÔÕÀÝÉÅ ÂÌÏËÉÒÏ×ËÉ ÞÔÅÎÉÑ"
+ serbian "Ne mogu da izvršim upit zbog toga što imate zakljuèavanja èitanja podataka u konfliktu"
+ spa "No puedo ejecutar el query porque usted tiene conflicto de traba de lectura"
+ swe "Kan inte utföra kommandot emedan du har ett READ-lås"
+ER_MIXING_NOT_ALLOWED
+ nla "Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld."
+ eng "Mixing of transactional and non-transactional tables is disabled"
+ est "Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud"
+ ger "Die gleichzeitige Verwendung von Tabellen mit und ohne Transaktionsunterstützung ist deaktiviert"
+ ita "E' disabilitata la possibilita' di mischiare tabelle transazionali e non-transazionali"
+ por "Mistura de tabelas transacional e não-transacional está desabilitada"
+ rus "éÓÐÏÌØÚÏ×ÁÎÉÅ ÔÒÁÎÚÁËÃÉÏÎÎÙÈ ÔÁÂÌÉà ÎÁÒÑÄÕ Ó ÎÅÔÒÁÎÚÁËÃÉÏÎÎÙÍÉ ÚÁÐÒÅÝÅÎÏ"
+ serbian "Mešanje tabela koje podržavaju transakcije i onih koje ne podržavaju transakcije je iskljuèeno"
+ spa "Mezla de transancional y no-transancional tablas está deshabilitada"
+ swe "Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat"
+ER_DUP_ARGUMENT
+ nla "Optie '%s' tweemaal gebruikt in opdracht"
+ eng "Option '%s' used twice in statement"
+ est "Määrangut '%s' on lauses kasutatud topelt"
+ ger "Option '%s' wird im Befehl zweimal verwendet"
+ ita "L'opzione '%s' e' stata usata due volte nel comando"
+ por "Opção '%s' usada duas vezes no comando"
+ rus "ïÐÃÉÑ '%s' Ä×ÁÖÄÙ ÉÓÐÏÌØÚÏ×ÁÎÁ × ×ÙÒÁÖÅÎÉÉ"
+ spa "Opción '%s' usada dos veces en el comando"
+ swe "Option '%s' användes två gånger"
+ER_USER_LIMIT_REACHED 42000
+ nla "Gebruiker '%-.64s' heeft het maximale gebruik van de '%s' faciliteit overschreden (huidige waarde: %ld)"
+ eng "User '%-.64s' has exceeded the '%s' resource (current value: %ld)"
+ ger "Benutzer '%-.64s' hat die Ressourcenbeschränkung '%s' überschritten (aktueller Wert: %ld)"
+ ita "L'utente '%-.64s' ha ecceduto la risorsa '%s' (valore corrente: %ld)"
+ por "Usuário '%-.64s' tem excedido o '%s' recurso (atual valor: %ld)"
+ rus "ðÏÌØÚÏ×ÁÔÅÌØ '%-.64s' ÐÒÅ×ÙÓÉÌ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÒÅÓÕÒÓÁ '%s' (ÔÅËÕÝÅÅ ÚÎÁÞÅÎÉÅ: %ld)"
+ spa "Usuario '%-.64s' ha excedido el recurso '%s' (actual valor: %ld)"
+ swe "Användare '%-.64s' har överskridit '%s' (nuvarande värde: %ld)"
+ER_SPECIFIC_ACCESS_DENIED_ERROR 42000
+ nla "Toegang geweigerd. U moet het %-.128s privilege hebben voor deze operatie"
+ eng "Access denied; you need the %-.128s privilege for this operation"
+ ger "Befehl nicht zulässig. Hierfür wird die Berechtigung %-.128s benötigt"
+ ita "Accesso non consentito. Serve il privilegio %-.128s per questa operazione"
+ por "Acesso negado. Você precisa o privilégio %-.128s para essa operação"
+ rus "÷ ÄÏÓÔÕÐÅ ÏÔËÁÚÁÎÏ. ÷ÁÍ ÎÕÖÎÙ ÐÒÉ×ÉÌÅÇÉÉ %-.128s ÄÌÑ ÜÔÏÊ ÏÐÅÒÁÃÉÉ"
+ spa "Acceso negado. Usted necesita el privilegio %-.128s para esta operación"
+ swe "Du har inte privlegiet '%-.128s' som behövs för denna operation"
+ ukr "Access denied. You need the %-.128s privilege for this operation"
+ER_LOCAL_VARIABLE
+ nla "Variabele '%-.64s' is SESSION en kan niet worden gebruikt met SET GLOBAL"
+ eng "Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL"
+ ger "Variable '%-.64s' ist eine lokale Variable und kann nicht mit SET GLOBAL verändert werden"
+ ita "La variabile '%-.64s' e' una variabile locale ( SESSION ) e non puo' essere cambiata usando SET GLOBAL"
+ por "Variável '%-.64s' é uma SESSION variável e não pode ser usada com SET GLOBAL"
+ rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' Ñ×ÌÑÅÔÓÑ ÐÏÔÏËÏ×ÏÊ (SESSION) ÐÅÒÅÍÅÎÎÏÊ É ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÚÍÅÎÅÎÁ Ó ÐÏÍÏÝØÀ SET GLOBAL"
+ spa "Variable '%-.64s' es una SESSION variable y no puede ser usada con SET GLOBAL"
+ swe "Variabel '%-.64s' är en SESSION variabel och kan inte ändrad med SET GLOBAL"
+ER_GLOBAL_VARIABLE
+ nla "Variabele '%-.64s' is GLOBAL en dient te worden gewijzigd met SET GLOBAL"
+ eng "Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL"
+ ger "Variable '%-.64s' ist eine globale Variable und muss mit SET GLOBAL verändert werden"
+ ita "La variabile '%-.64s' e' una variabile globale ( GLOBAL ) e deve essere cambiata usando SET GLOBAL"
+ por "Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL"
+ rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' Ñ×ÌÑÅÔÓÑ ÇÌÏÂÁÌØÎÏÊ (GLOBAL) ÐÅÒÅÍÅÎÎÏÊ, É ÅÅ ÓÌÅÄÕÅÔ ÉÚÍÅÎÑÔØ Ó ÐÏÍÏÝØÀ SET GLOBAL"
+ spa "Variable '%-.64s' es una GLOBAL variable y no puede ser configurada con SET GLOBAL"
+ swe "Variabel '%-.64s' är en GLOBAL variabel och bör sättas med SET GLOBAL"
+ER_NO_DEFAULT 42000
+ nla "Variabele '%-.64s' heeft geen standaard waarde"
+ eng "Variable '%-.64s' doesn't have a default value"
+ ger "Variable '%-.64s' hat keinen Vorgabewert"
+ ita "La variabile '%-.64s' non ha un valore di default"
+ por "Variável '%-.64s' não tem um valor padrão"
+ rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÎÅ ÉÍÅÅÔ ÚÎÁÞÅÎÉÑ ÐÏ ÕÍÏÌÞÁÎÉÀ"
+ spa "Variable '%-.64s' no tiene un valor patrón"
+ swe "Variabel '%-.64s' har inte ett DEFAULT-värde"
+ER_WRONG_VALUE_FOR_VAR 42000
+ nla "Variabele '%-.64s' kan niet worden gewijzigd naar de waarde '%-.64s'"
+ eng "Variable '%-.64s' can't be set to the value of '%-.64s'"
+ ger "Variable '%-.64s' kann nicht auf '%-.64s' gesetzt werden"
+ ita "Alla variabile '%-.64s' non puo' essere assegato il valore '%-.64s'"
+ por "Variável '%-.64s' não pode ser configurada para o valor de '%-.64s'"
+ rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÕÓÔÁÎÏ×ÌÅÎÁ × ÚÎÁÞÅÎÉÅ '%-.64s'"
+ spa "Variable '%-.64s' no puede ser configurada para el valor de '%-.64s'"
+ swe "Variabel '%-.64s' kan inte sättas till '%-.64s'"
+ER_WRONG_TYPE_FOR_VAR 42000
+ nla "Foutief argumenttype voor variabele '%-.64s'"
+ eng "Incorrect argument type to variable '%-.64s'"
+ ger "Falscher Argumenttyp für Variable '%-.64s'"
+ ita "Tipo di valore errato per la variabile '%-.64s'"
+ por "Tipo errado de argumento para variável '%-.64s'"
+ rus "îÅ×ÅÒÎÙÊ ÔÉÐ ÁÒÇÕÍÅÎÔÁ ÄÌÑ ÐÅÒÅÍÅÎÎÏÊ '%-.64s'"
+ spa "Tipo de argumento equivocado para variable '%-.64s'"
+ swe "Fel typ av argument till variabel '%-.64s'"
+ER_VAR_CANT_BE_READ
+ nla "Variabele '%-.64s' kan alleen worden gewijzigd, niet gelezen"
+ eng "Variable '%-.64s' can only be set, not read"
+ ger "Variable '%-.64s' kann nur verändert, nicht gelesen werden"
+ ita "Alla variabile '%-.64s' e' di sola scrittura quindi puo' essere solo assegnato un valore, non letto"
+ por "Variável '%-.64s' somente pode ser configurada, não lida"
+ rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÍÏÖÅÔ ÂÙÔØ ÔÏÌØËÏ ÕÓÔÁÎÏ×ÌÅÎÁ, ÎÏ ÎÅ ÓÞÉÔÁÎÁ"
+ spa "Variable '%-.64s' solamente puede ser configurada, no leída"
+ swe "Variabeln '%-.64s' kan endast sättas, inte läsas"
+ER_CANT_USE_OPTION_HERE 42000
+ nla "Foutieve toepassing/plaatsing van '%s'"
+ eng "Incorrect usage/placement of '%s'"
+ ger "Falsche Verwendung oder Platzierung von '%s'"
+ ita "Uso/posizione di '%s' sbagliato"
+ por "Errado uso/colocação de '%s'"
+ rus "îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÉÌÉ × ÎÅ×ÅÒÎÏÍ ÍÅÓÔÅ ÕËÁÚÁÎ '%s'"
+ spa "Equivocado uso/colocación de '%s'"
+ swe "Fel använding/placering av '%s'"
+ER_NOT_SUPPORTED_YET 42000
+ nla "Deze versie van MySQL ondersteunt nog geen '%s'"
+ eng "This version of MySQL doesn't yet support '%s'"
+ ger "Diese MySQL-Version unterstützt '%s' nicht"
+ ita "Questa versione di MySQL non supporta ancora '%s'"
+ por "Esta versão de MySQL não suporta ainda '%s'"
+ rus "üÔÁ ×ÅÒÓÉÑ MySQL ÐÏËÁ ÅÝÅ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ '%s'"
+ spa "Esta versión de MySQL no soporta todavia '%s'"
+ swe "Denna version av MySQL kan ännu inte utföra '%s'"
+ER_MASTER_FATAL_ERROR_READING_BINLOG
+ nla "Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log"
+ eng "Got fatal error %d: '%-.128s' from master when reading data from binary log"
+ ger "Schwerer Fehler %d: '%-.128s vom Master beim Lesen des binären Logs aufgetreten"
+ ita "Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario"
+ por "Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log"
+ rus "ðÏÌÕÞÅÎÁ ÎÅÉÓÐÒÁ×ÉÍÁÑ ÏÛÉÂËÁ %d: '%-.128s' ÏÔ ÇÏÌÏ×ÎÏÇÏ ÓÅÒ×ÅÒÁ × ÐÒÏÃÅÓÓÅ ×ÙÂÏÒËÉ ÄÁÎÎÙÈ ÉÚ Ä×ÏÉÞÎÏÇÏ ÖÕÒÎÁÌÁ"
+ spa "Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log"
+ swe "Fick fatalt fel %d: '%-.128s' från master vid läsning av binärloggen"
+ER_SLAVE_IGNORED_TABLE
+ eng "Slave SQL thread ignored the query because of replicate-*-table rules"
+ ger "Slave-SQL-Thread hat die Abfrage aufgrund von replicate-*-table-Regeln ignoriert"
+ por "Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela"
+ spa "Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla"
+ swe "Slav SQL tråden ignorerade frågan pga en replicate-*-table regel"
+ER_INCORRECT_GLOBAL_LOCAL_VAR
+ eng "Variable '%-.64s' is a %s variable"
+ serbian "Incorrect foreign key definition for '%-.64s': %s"
+ spa "Variable '%-.64s' es una %s variable"
+ swe "Variabel '%-.64s' är av typ %s"
+ER_WRONG_FK_DEF 42000
+ eng "Incorrect foreign key definition for '%-.64s': %s"
+ ger "Falsche Fremdschlüssel-Definition für '%-64s': %s"
+ por "Definição errada da chave estrangeira para '%-.64s': %s"
+ spa "Equivocada definición de llave extranjera para '%-.64s': %s"
+ swe "Felaktig FOREIGN KEY-definition för '%-.64s': %s"
+ER_KEY_REF_DO_NOT_MATCH_TABLE_REF
+ eng "Key reference and table reference don't match"
+ ger "Schlüssel- und Tabellenverweis passen nicht zusammen"
+ por "Referência da chave e referência da tabela não coincidem"
+ spa "Referencia de llave y referencia de tabla no coinciden"
+ swe "Nyckelreferensen och tabellreferensen stämmer inte överens"
+ER_OPERAND_COLUMNS 21000
+ eng "Operand should contain %d column(s)"
+ ger "Operand solle %d Spalte(n) enthalten"
+ rus "ïÐÅÒÁÎÄ ÄÏÌÖÅÎ ÓÏÄÅÒÖÁÔØ %d ËÏÌÏÎÏË"
+ spa "Operando debe tener %d columna(s)"
+ ukr "ïÐÅÒÁÎÄ ÍÁ¤ ÓËÌÁÄÁÔÉÓÑ Ú %d ÓÔÏ×Âæ×"
+ER_SUBQUERY_NO_1_ROW 21000
+ eng "Subquery returns more than 1 row"
+ ger "Unterabfrage lieferte mehr als einen Datensatz zurück"
+ por "Subconsulta retorna mais que 1 registro"
+ rus "ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÊ ÚÁÐÉÓÉ"
+ spa "Subconsulta retorna mas que 1 línea"
+ swe "Subquery returnerade mer än 1 rad"
+ ukr "ð¦ÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ¦ÌØÛ ÎiÖ 1 ÚÁÐÉÓ"
+ER_UNKNOWN_STMT_HANDLER
+ dan "Unknown prepared statement handler (%ld) given to %s"
+ eng "Unknown prepared statement handler (%.*s) given to %s"
+ ger "Unbekannter Prepared-Statement-Handler (%.*s) für %s angegeben"
+ por "Desconhecido manipulador de declaração preparado (%.*s) determinado para %s"
+ spa "Desconocido preparado comando handler (%ld) dado para %s"
+ swe "Okänd PREPARED STATEMENT id (%ld) var given till %s"
+ ukr "Unknown prepared statement handler (%ld) given to %s"
+ER_CORRUPT_HELP_DB
+ eng "Help database is corrupt or does not exist"
+ ger "Die Hilfe-Datenbank ist beschädigt oder existiert nicht"
+ por "Banco de dado de ajuda corrupto ou não existente"
+ spa "Base de datos Help está corrupto o no existe"
+ swe "Hjälpdatabasen finns inte eller är skadad"
+ER_CYCLIC_REFERENCE
+ eng "Cyclic reference on subqueries"
+ ger "Zyklischer Verweis in Unterabfragen"
+ por "Referência cíclica em subconsultas"
+ rus "ãÉËÌÉÞÅÓËÁÑ ÓÓÙÌËÁ ÎÁ ÐÏÄÚÁÐÒÏÓ"
+ spa "Cíclica referencia en subconsultas"
+ swe "Cyklisk referens i subqueries"
+ ukr "ãÉË̦ÞÎÅ ÐÏÓÉÌÁÎÎÑ ÎÁ ЦÄÚÁÐÉÔ"
+ER_AUTO_CONVERT
+ eng "Converting column '%s' from %s to %s"
+ ger "Spalte '%s' wird von %s nach %s umgewandelt"
+ por "Convertendo coluna '%s' de %s para %s"
+ rus "ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÐÏÌÑ '%s' ÉÚ %s × %s"
+ spa "Convirtiendo columna '%s' de %s para %s"
+ swe "Konvertar kolumn '%s' från %s till %s"
+ ukr "ðÅÒÅÔ×ÏÒÅÎÎÑ ÓÔÏ×ÂÃÁ '%s' Ú %s Õ %s"
+ER_ILLEGAL_REFERENCE 42S22
+ eng "Reference '%-.64s' not supported (%s)"
+ ger "Verweis '%-.64s' wird nicht unterstützt (%s)"
+ por "Referência '%-.64s' não suportada (%s)"
+ rus "óÓÙÌËÁ '%-.64s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ (%s)"
+ spa "Referencia '%-.64s' no soportada (%s)"
+ swe "Referens '%-.64s' stöds inte (%s)"
+ ukr "ðÏÓÉÌÁÎÎÑ '%-.64s' ÎÅ ÐiÄÔÒÉÍÕÅÔÓÑ (%s)"
+ER_DERIVED_MUST_HAVE_ALIAS 42000
+ eng "Every derived table must have its own alias"
+ ger "Für jede abgeleitete Tabelle muss ein eigener Alias angegeben werden"
+ por "Cada tabela derivada deve ter seu próprio alias"
+ spa "Cada tabla derivada debe tener su propio alias"
+ swe "Varje 'derived table' måste ha sitt eget alias"
+ER_SELECT_REDUCED 01000
+ eng "Select %u was reduced during optimization"
+ ger "Select %u wurde während der Optimierung reduziert"
+ por "Select %u foi reduzido durante otimização"
+ rus "Select %u ÂÙÌ ÕÐÒÁÚÄÎÅÎ × ÐÒÏÃÅÓÓÅ ÏÐÔÉÍÉÚÁÃÉÉ"
+ spa "Select %u fué reducido durante optimización"
+ swe "Select %u reducerades vid optimiering"
+ ukr "Select %u was ÓËÁÓÏ×ÁÎÏ ÐÒÉ ÏÐÔÉÍiÚÁÃii"
+ER_TABLENAME_NOT_ALLOWED_HERE 42000
+ eng "Table '%-.64s' from one of the SELECTs cannot be used in %-.32s"
+ ger "Tabelle '%-.64s', die in einem der SELECT-Befehle verwendet wurde, kann nicht in %-.32s verwendet werden"
+ por "Tabela '%-.64s' de um dos SELECTs não pode ser usada em %-.32s"
+ spa "Tabla '%-.64s' de uno de los SELECT no puede ser usada en %-.32s"
+ swe "Tabell '%-.64s' från en SELECT kan inte användas i %-.32s"
+ER_NOT_SUPPORTED_AUTH_MODE 08004
+ eng "Client does not support authentication protocol requested by server; consider upgrading MySQL client"
+ ger "Client unterstützt das vom Server erwartete Authentifizierungsprotokoll nicht. Bitte aktualisieren Sie Ihren MySQL-Client"
+ por "Cliente não suporta o protocolo de autenticação exigido pelo servidor; considere a atualização do cliente MySQL"
+ spa "Cliente no soporta protocolo de autenticación solicitado por el servidor; considere actualizar el cliente MySQL"
+ swe "Klienten stöder inte autentiseringsprotokollet som begärts av servern; överväg uppgradering av klientprogrammet."
+ER_SPATIAL_CANT_HAVE_NULL 42000
+ eng "All parts of a SPATIAL index must be NOT NULL"
+ ger "Alle Teile eines SPATIAL index müssen als NOT NULL deklariert sein"
+ por "Todas as partes de uma SPATIAL index devem ser NOT NULL"
+ spa "Todas las partes de una SPATIAL index deben ser NOT NULL"
+ swe "Alla delar av en SPATIAL index måste vara NOT NULL"
+ER_COLLATION_CHARSET_MISMATCH 42000
+ eng "COLLATION '%s' is not valid for CHARACTER SET '%s'"
+ ger "COLLATION '%s' ist für CHARACTER SET '%s' ungültig"
+ por "COLLATION '%s' não é válida para CHARACTER SET '%s'"
+ spa "COLLATION '%s' no es válido para CHARACTER SET '%s'"
+ swe "COLLATION '%s' är inte tillåtet för CHARACTER SET '%s'"
+ER_SLAVE_WAS_RUNNING
+ eng "Slave is already running"
+ ger "Slave läuft bereits"
+ por "O slave já está rodando"
+ spa "Slave ya está funcionando"
+ swe "Slaven har redan startat"
+ER_SLAVE_WAS_NOT_RUNNING
+ eng "Slave already has been stopped"
+ ger "Slave wurde bereits angehalten"
+ por "O slave já está parado"
+ spa "Slave ya fué parado"
+ swe "Slaven har redan stoppat"
+ER_TOO_BIG_FOR_UNCOMPRESS
+ eng "Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)"
+ ger "Unkomprimierte Daten sind zu groß. Die maximale Größe beträgt %d"
+ por "Tamanho muito grande dos dados des comprimidos. O máximo tamanho é %d. (provavelmente, o comprimento dos dados descomprimidos está corrupto)"
+ spa "Tamaño demasiado grande para datos descomprimidos. El máximo tamaño es %d. (probablemente, extensión de datos descomprimidos fué corrompida)"
+ER_ZLIB_Z_MEM_ERROR
+ eng "ZLIB: Not enough memory"
+ ger "ZLIB: Steht nicht genug Speicher zur Verfügung"
+ por "ZLIB: Não suficiente memória disponível"
+ spa "Z_MEM_ERROR: No suficiente memoria para zlib"
+ER_ZLIB_Z_BUF_ERROR
+ eng "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)"
+ ger "ZLIB: Im Ausgabepuffer ist nicht genug Platz vorhanden (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)"
+ por "ZLIB: Não suficiente espaço no buffer emissor (provavelmente, o comprimento dos dados descomprimidos está corrupto)"
+ spa "Z_BUF_ERROR: No suficiente espacio en el búfer de salida para zlib (probablemente, extensión de datos descomprimidos fué corrompida)"
+ER_ZLIB_Z_DATA_ERROR
+ eng "ZLIB: Input data corrupted"
+ ger "ZLIB: Eingabedaten beschädigt"
+ por "ZLIB: Dados de entrada está corrupto"
+ spa "ZLIB: Dato de entrada fué corrompido para zlib"
+ER_CUT_VALUE_GROUP_CONCAT
+ eng "%d line(s) were cut by GROUP_CONCAT()"
+ ger "%d Zeile(n) durch GROUP_CONCAT() abgeschnitten"
+ por "%d linha(s) foram cortada(s) por GROUP_CONCAT()"
+ spa "%d línea(s) fue(fueron) cortadas por group_concat()"
+ swe "%d rad(er) kapades av group_concat()"
+ ukr "%d line(s) was(were) cut by group_concat()"
+ER_WARN_TOO_FEW_RECORDS 01000
+ eng "Row %ld doesn't contain data for all columns"
+ ger "Anzahl der Datensätze in Zeile %ld geringer als Anzahl der Spalten"
+ por "Conta de registro é menor que a conta de coluna na linha %ld"
+ spa "Línea %ld no contiene datos para todas las columnas"
+ER_WARN_TOO_MANY_RECORDS 01000
+ eng "Row %ld was truncated; it contained more data than there were input columns"
+ ger "Anzahl der Datensätze in Zeile %ld größer als Anzahl der Spalten"
+ por "Conta de registro é maior que a conta de coluna na linha %ld"
+ spa "Línea %ld fué truncada; La misma contine mas datos que las que existen en las columnas de entrada"
+ER_WARN_NULL_TO_NOTNULL 22004
+ eng "Column set to default value; NULL supplied to NOT NULL column '%s' at row %ld"
+ ger "Daten abgeschnitten, NULL für NOT NULL-Spalte '%s' in Zeile %ld angegeben"
+ por "Dado truncado, NULL fornecido para NOT NULL coluna '%s' na linha %ld"
+ spa "Datos truncado, NULL suministrado para NOT NULL columna '%s' en la línea %ld"
+ER_WARN_DATA_OUT_OF_RANGE 22003
+ eng "Out of range value adjusted for column '%s' at row %ld"
+ ger "Daten abgeschnitten, außerhalb des Wertebereichs für Spalte '%s' in Zeile %ld"
+ por "Dado truncado, fora de alcance para coluna '%s' na linha %ld"
+ spa "Datos truncados, fuera de gama para columna '%s' en la línea %ld"
+WARN_DATA_TRUNCATED 01000
+ eng "Data truncated for column '%s' at row %ld"
+ ger "Daten abgeschnitten für Spalte '%s' in Zeile %ld"
+ por "Dado truncado para coluna '%s' na linha %ld"
+ spa "Datos truncados para columna '%s' en la línea %ld"
+ER_WARN_USING_OTHER_HANDLER
+ eng "Using storage engine %s for table '%s'"
+ ger "Für Tabelle '%s' wird Speicher-Engine %s benutzt"
+ por "Usando engine de armazenamento %s para tabela '%s'"
+ spa "Usando motor de almacenamiento %s para tabla '%s'"
+ swe "Använder handler %s för tabell '%s'"
+ER_CANT_AGGREGATE_2COLLATIONS
+ eng "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'"
+ ger "Unerlaubte Vermischung der Kollationen (%s,%s) und (%s,%s) für die Operation '%s'"
+ por "Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'"
+ spa "Ilegal mezcla de collations (%s,%s) y (%s,%s) para operación '%s'"
+ER_DROP_USER
+ eng "Cannot drop one or more of the requested users"
+ ger "Kann einen oder mehrere der angegebenen Benutzer nicht löschen"
+ER_REVOKE_GRANTS
+ eng "Can't revoke all privileges, grant for one or more of the requested users"
+ ger "Kann nicht alle Berechtigungen widerrufen, grant for one or more of the requested users"
+ por "Não pode revocar todos os privilégios, grant para um ou mais dos usuários pedidos"
+ spa "No puede revocar todos los privilegios, derecho para uno o mas de los usuarios solicitados"
+ER_CANT_AGGREGATE_3COLLATIONS
+ eng "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'"
+ ger "Unerlaubte Vermischung der Kollationen (%s,%s), (%s,%s), (%s,%s) für die Operation '%s'"
+ por "Ilegal combinação de collations (%s,%s), (%s,%s), (%s,%s) para operação '%s'"
+ spa "Ilegal mezcla de collations (%s,%s), (%s,%s), (%s,%s) para operación '%s'"
+ER_CANT_AGGREGATE_NCOLLATIONS
+ eng "Illegal mix of collations for operation '%s'"
+ ger "Unerlaubte Vermischung der Kollationen für die Operation '%s'"
+ por "Ilegal combinação de collations para operação '%s'"
+ spa "Ilegal mezcla de collations para operación '%s'"
+ER_VARIABLE_IS_NOT_STRUCT
+ eng "Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)"
+ ger "Variable '%-.64s' ist keine Variablen-Komponenten (kann nicht als XXXX.variablen_name verwendet werden)"
+ por "Variável '%-.64s' não é uma variável componente (Não pode ser usada como XXXX.variável_nome)"
+ spa "Variable '%-.64s' no es una variable componente (No puede ser usada como XXXX.variable_name)"
+ER_UNKNOWN_COLLATION
+ eng "Unknown collation: '%-.64s'"
+ ger "Unbekannte Kollation: '%-.64s'"
+ por "Collation desconhecida: '%-.64s'"
+ spa "Collation desconocida: '%-.64s'"
+ER_SLAVE_IGNORED_SSL_PARAMS
+ eng "SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started"
+ ger "SSL-Parameter in CHANGE MASTER werden ignoriert, weil dieser MySQL-Slave ohne SSL-Unterstützung kompiliert wurde. Sie können aber später verwendet werden, wenn der MySQL-Slave mit SSL gestartet wird"
+ por "SSL parâmetros em CHANGE MASTER são ignorados porque este escravo MySQL foi compilado sem o SSL suporte. Os mesmos podem ser usados mais tarde quando o escravo MySQL com SSL seja iniciado."
+ spa "Parametros SSL en CHANGE MASTER son ignorados porque este slave MySQL fue compilado sin soporte SSL; pueden ser usados despues cuando el slave MySQL con SSL sea inicializado"
+ER_SERVER_IS_IN_SECURE_AUTH_MODE
+ eng "Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format"
+ ger "Server läuft im Modus --secure-auth, aber '%s'@'%s' hat ein Passwort im alten Format. Bitte Passwort ins neue Format ändern"
+ por "Servidor está rodando em --secure-auth modo, porêm '%s'@'%s' tem senha no formato antigo; por favor troque a senha para o novo formato"
+ rus "óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s'@'%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ"
+ spa "Servidor está rodando en modo --secure-auth, pero '%s'@'%s' tiene clave en el antiguo formato; por favor cambie la clave para el nuevo formato"
+ER_WARN_FIELD_RESOLVED
+ eng "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d"
+ ger "Feld oder Verweis '%-.64s%s%-.64s%s%-.64s' im SELECT-Befehl Nr. %d wurde im SELECT-Befehl Nr. %d aufgelöst"
+ por "Campo ou referência '%-.64s%s%-.64s%s%-.64s' de SELECT #%d foi resolvido em SELECT #%d"
+ rus "ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.64s%s%-.64s%s%-.64s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d"
+ spa "Campo o referencia '%-.64s%s%-.64s%s%-.64s' de SELECT #%d fue resolvido en SELECT #%d"
+ ukr "óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.64s%s%-.64s%s%-.64s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d"
+ER_BAD_SLAVE_UNTIL_COND
+ eng "Incorrect parameter or combination of parameters for START SLAVE UNTIL"
+ ger "Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL"
+ por "Parâmetro ou combinação de parâmetros errado para START SLAVE UNTIL"
+ spa "Parametro equivocado o combinación de parametros para START SLAVE UNTIL"
+ER_MISSING_SKIP_SLAVE
+ eng "It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you will get problems if you get an unexpected slave's mysqld restart"
+ ger "Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn der Slave-Server unerwartet neu startet"
+ por "É recomendado para rodar com --skip-slave-start quando fazendo replicação passo-por-passo com START SLAVE UNTIL, de outra forma você não está seguro em caso de inesperada reinicialição do mysqld escravo"
+ spa "Es recomendado rodar con --skip-slave-start cuando haciendo replicación step-by-step con START SLAVE UNTIL, a menos que usted no esté seguro en caso de inesperada reinicialización del mysqld slave"
+ER_UNTIL_COND_IGNORED
+ eng "SQL thread is not to be started so UNTIL options are ignored"
+ ger "SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert"
+ por "Thread SQL não pode ser inicializado tal que opções UNTIL são ignoradas"
+ spa "SQL thread no es inicializado tal que opciones UNTIL son ignoradas"
+ER_WRONG_NAME_FOR_INDEX 42000
+ eng "Incorrect index name '%-.100s'"
+ por "Incorreto nome de índice '%-.100s'"
+ spa "Nombre de índice incorrecto '%-.100s'"
+ swe "Felaktigt index namn '%-.100s'"
+ER_WRONG_NAME_FOR_CATALOG 42000
+ eng "Incorrect catalog name '%-.100s'"
+ por "Incorreto nome de catálogo '%-.100s'"
+ spa "Nombre de catalog incorrecto '%-.100s'"
+ swe "Felaktigt katalog namn '%-.100s'"
+ER_WARN_QC_RESIZE
+ eng "Query cache failed to set size %lu; new query cache size is %lu"
+ por "Falha em Query cache para configurar tamanho %lu, novo tamanho de query cache é %lu"
+ rus "ëÅÛ ÚÁÐÒÏÓÏ× ÎÅ ÍÏÖÅÔ ÕÓÔÁÎÏ×ÉÔØ ÒÁÚÍÅÒ %lu, ÎÏ×ÙÊ ÒÁÚÍÅÒ ËÅÛÁ ÚÐÒÏÓÏ× - %lu"
+ spa "Query cache fallada para configurar tamaño %lu, nuevo tamaño de query cache es %lu"
+ swe "Storleken av "Query cache" kunde inte sättas till %lu, ny storlek är %lu"
+ ukr "ëÅÛ ÚÁÐÉÔ¦× ÎÅÓÐÒÏÍÏÖÅÎ ×ÓÔÁÎÏ×ÉÔÉ ÒÏÚÍ¦Ò %lu, ÎÏ×ÉÊ ÒÏÚÍ¦Ò ËÅÛÁ ÚÁÐÉÔ¦× - %lu"
+ER_BAD_FT_COLUMN
+ eng "Column '%-.64s' cannot be part of FULLTEXT index"
+ por "Coluna '%-.64s' não pode ser parte de índice FULLTEXT"
+ spa "Columna '%-.64s' no puede ser parte de FULLTEXT index"
+ swe "Kolumn '%-.64s' kan inte vara del av ett FULLTEXT index"
+ER_UNKNOWN_KEY_CACHE
+ eng "Unknown key cache '%-.100s'"
+ por "Key cache desconhecida '%-.100s'"
+ spa "Desconocida key cache '%-.100s'"
+ swe "Okänd nyckel cache '%-.100s'"
+ER_WARN_HOSTNAME_WONT_WORK
+ eng "MySQL is started in --skip-name-resolve mode; you must restart it without this switch for this grant to work"
+ por "MySQL foi inicializado em modo --skip-name-resolve. Você necesita reincializá-lo sem esta opção para este grant funcionar"
+ spa "MySQL esta inicializado en modo --skip-name-resolve. Usted necesita reinicializarlo sin esta opción para este derecho funcionar"
+ER_UNKNOWN_STORAGE_ENGINE 42000
+ eng "Unknown table engine '%s'"
+ por "Motor de tabela desconhecido '%s'"
+ spa "Desconocido motor de tabla '%s'"
+ER_WARN_DEPRECATED_SYNTAX
+ eng "'%s' is deprecated; use '%s' instead"
+ por "'%s' é desatualizado. Use '%s' em seu lugar"
+ spa "'%s' está desaprobado, use '%s' en su lugar"
+ER_NON_UPDATABLE_TABLE
+ eng "The target table %-.100s of the %s is not updatable"
+ 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"
+ ukr "ôÁÂÌÉÃÑ %-.100s Õ %s ÎÅ ÍÏÖÅ ÏÎÏ×ÌÀ×ÁÔÉÓØ"
+ER_FEATURE_DISABLED
+ eng "The '%s' feature is disabled; you need MySQL built with '%s' to have it working"
+ por "O recurso '%s' foi desativado; você necessita MySQL construído com '%s' para ter isto funcionando"
+ spa "El recurso '%s' fue deshabilitado; usted necesita construir MySQL con '%s' para tener eso funcionando"
+ swe "'%s' är inte aktiverad; För att aktivera detta måste du bygga om MySQL med '%s' definerad"
+ER_OPTION_PREVENTS_STATEMENT
+ eng "The MySQL server is running with the %s option so it cannot execute this statement"
+ por "O servidor MySQL está rodando com a opção %s razão pela qual não pode executar esse commando"
+ spa "El servidor MySQL está rodando con la opción %s tal que no puede ejecutar este comando"
+ swe "MySQL är startad med --skip-grant-tables. Pga av detta kan du inte använda detta kommando"
+ER_DUPLICATED_VALUE_IN_TYPE
+ eng "Column '%-.100s' has duplicated value '%-.64s' in %s"
+ por "Coluna '%-.100s' tem valor duplicado '%-.64s' em %s"
+ spa "Columna '%-.100s' tiene valor doblado '%-.64s' en %s"
+ER_TRUNCATED_WRONG_VALUE 22007
+ eng "Truncated incorrect %-.32s value: '%-.128s'"
+ por "Truncado errado %-.32s valor: '%-.128s'"
+ spa "Equivocado truncado %-.32s valor: '%-.128s'"
+ER_TOO_MUCH_AUTO_TIMESTAMP_COLS
+ eng "Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
+ por "Incorreta definição de tabela; Pode ter somente uma coluna TIMESTAMP com CURRENT_TIMESTAMP em DEFAULT ou ON UPDATE cláusula"
+ spa "Incorrecta definición de tabla; Solamente debe haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o ON UPDATE cláusula"
+ER_INVALID_ON_UPDATE
+ eng "Invalid ON UPDATE clause for '%-.64s' column"
+ por "Inválida cláusula ON UPDATE para campo '%-.64s'"
+ spa "Inválido ON UPDATE cláusula para campo '%-.64s'"
+ER_UNSUPPORTED_PS
+ eng "This command is not supported in the prepared statement protocol yet"
+ER_GET_ERRMSG
+ dan "Modtog fejl %d '%-.100s' fra %s"
+ eng "Got error %d '%-.100s' from %s"
+ nor "Mottok feil %d '%-.100s' fa %s"
+ norwegian-ny "Mottok feil %d '%-.100s' fra %s"
+ER_GET_TEMPORARY_ERRMSG
+ dan "Modtog temporary fejl %d '%-.100s' fra %s"
+ eng "Got temporary error %d '%-.100s' from %s"
+ nor "Mottok temporary feil %d '%-.100s' fra %s"
+ norwegian-ny "Mottok temporary feil %d '%-.100s' fra %s"
+ER_UNKNOWN_TIME_ZONE
+ eng "Unknown or incorrect time zone: '%-.64s'"
+ER_WARN_INVALID_TIMESTAMP
+ eng "Invalid TIMESTAMP value in column '%s' at row %ld"
+ER_INVALID_CHARACTER_STRING
+ eng "Invalid %s character string: '%.64s'"
+ER_WARN_ALLOWED_PACKET_OVERFLOWED
+ eng "Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+ER_CONFLICTING_DECLARATIONS
+ eng "Conflicting declarations: '%s%s' and '%s%s'"
+ER_SP_NO_RECURSIVE_CREATE 2F003
+ eng "Can't create a %s from within another stored routine"
+ER_SP_ALREADY_EXISTS 42000
+ eng "%s %s already exists"
+ER_SP_DOES_NOT_EXIST 42000
+ eng "%s %s does not exist"
+ER_SP_DROP_FAILED
+ eng "Failed to DROP %s %s"
+ER_SP_STORE_FAILED
+ eng "Failed to CREATE %s %s"
+ER_SP_LILABEL_MISMATCH 42000
+ eng "%s with no matching label: %s"
+ER_SP_LABEL_REDEFINE 42000
+ eng "Redefining label %s"
+ER_SP_LABEL_MISMATCH 42000
+ eng "End-label %s without match"
+ER_SP_UNINIT_VAR 01000
+ eng "Referring to uninitialized variable %s"
+ER_SP_BADSELECT 0A000
+ eng "PROCEDURE %s can't return a result set in the given context"
+ER_SP_BADRETURN 42000
+ eng "RETURN is only allowed in a FUNCTION"
+ER_SP_BADSTATEMENT 0A000
+ eng "%s is not allowed in stored procedures"
+ER_UPDATE_LOG_DEPRECATED_IGNORED 42000
+ eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored"
+ER_UPDATE_LOG_DEPRECATED_TRANSLATED 42000
+ eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN"
+ER_QUERY_INTERRUPTED 70100
+ eng "Query execution was interrupted"
+ER_SP_WRONG_NO_OF_ARGS 42000
+ eng "Incorrect number of arguments for %s %s; expected %u, got %u"
+ER_SP_COND_MISMATCH 42000
+ eng "Undefined CONDITION: %s"
+ER_SP_NORETURN 42000
+ eng "No RETURN found in FUNCTION %s"
+ER_SP_NORETURNEND 2F005
+ eng "FUNCTION %s ended without RETURN"
+ER_SP_BAD_CURSOR_QUERY 42000
+ eng "Cursor statement must be a SELECT"
+ER_SP_BAD_CURSOR_SELECT 42000
+ eng "Cursor SELECT must not have INTO"
+ER_SP_CURSOR_MISMATCH 42000
+ eng "Undefined CURSOR: %s"
+ER_SP_CURSOR_ALREADY_OPEN 24000
+ eng "Cursor is already open"
+ER_SP_CURSOR_NOT_OPEN 24000
+ eng "Cursor is not open"
+ER_SP_UNDECLARED_VAR 42000
+ eng "Undeclared variable: %s"
+ER_SP_WRONG_NO_OF_FETCH_ARGS
+ eng "Incorrect number of FETCH variables"
+ER_SP_FETCH_NO_DATA 02000
+ eng "No data to FETCH"
+ER_SP_DUP_PARAM 42000
+ eng "Duplicate parameter: %s"
+ER_SP_DUP_VAR 42000
+ eng "Duplicate variable: %s"
+ER_SP_DUP_COND 42000
+ eng "Duplicate condition: %s"
+ER_SP_DUP_CURS 42000
+ eng "Duplicate cursor: %s"
+ER_SP_CANT_ALTER
+ eng "Failed to ALTER %s %s"
+ER_SP_SUBSELECT_NYI 0A000
+ eng "Subselect value not supported"
+ER_SP_NO_USE 42000
+ eng "USE is not allowed in a stored procedure"
+ER_SP_VARCOND_AFTER_CURSHNDLR 42000
+ eng "Variable or condition declaration after cursor or handler declaration"
+ER_SP_CURSOR_AFTER_HANDLER 42000
+ eng "Cursor declaration after handler declaration"
+ER_SP_CASE_NOT_FOUND 20000
+ eng "Case not found for CASE statement"
+ER_FPARSER_TOO_BIG_FILE
+ eng "Configuration file '%-.64s' is too big"
+ rus "óÌÉÛËÏÍ ÂÏÌØÛÏÊ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÙÊ ÆÁÊÌ '%-.64s'"
+ ukr "úÁÎÁÄÔÏ ×ÅÌÉËÉÊ ËÏÎƦÇÕÒÁæÊÎÉÊ ÆÁÊÌ '%-.64s'"
+ER_FPARSER_BAD_HEADER
+ eng "Malformed file type header in file '%-.64s'"
+ rus "îÅ×ÅÒÎÙÊ ÚÁÇÏÌÏ×ÏË ÔÉÐÁ ÆÁÊÌÁ '%-.64s'"
+ ukr "îÅצÒÎÉÊ ÚÁÇÏÌÏ×ÏË ÔÉÐÕ Õ ÆÁÊ̦ '%-.64s'"
+ER_FPARSER_EOF_IN_COMMENT
+ eng "Unexpected end of file while parsing comment '%-.64s'"
+ rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ × ËÏÍÅÎÔÁÒÉÉ '%-.64s'"
+ ukr "îÅÓÐÏĦ×ÁÎÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ Õ ËÏÍÅÎÔÁÒ¦ '%-.64s'"
+ER_FPARSER_ERROR_IN_PARAMETER
+ eng "Error while parsing parameter '%-.64s' (line: '%-.64s')"
+ rus "ïÛÉÂËÁ ÐÒÉ ÒÁÓÐÏÚÎÁ×ÁÎÉÉ ÐÁÒÁÍÅÔÒÁ '%-.64s' (ÓÔÒÏËÁ: '%-.64s')"
+ ukr "ðÏÍÉÌËÁ × ÒÏÓЦÚÎÁ×ÁÎΦ ÐÁÒÁÍÅÔÒÕ '%-.64s' (ÒÑÄÏË: '%-.64s')"
+ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER
+ eng "Unexpected end of file while skipping unknown parameter '%-.64s'"
+ rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ ÐÒÉ ÐÒÏÐÕÓËÅ ÎÅÉÚ×ÅÓÔÎÏÇÏ ÐÁÒÁÍÅÔÒÁ '%-.64s'"
+ ukr "îÅÓÐÏĦ×ÁÎÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ Õ ÓÐÒϦ ÐÒÏÍÉÎÕÔÉ ÎÅצÄÏÍÉÊ ÐÁÒÁÍÅÔÒ '%-.64s'"
+ER_VIEW_NO_EXPLAIN
+ eng "EXPLAIN/SHOW can not be issued; lacking privileges for underlying table"
+ rus "EXPLAIN/SHOW ÎÅ ÍÏÖÅÔ ÂÙÔØ ×ÙÐÏÌÎÅÎÎÏ; ÎÅÄÏÓÔÁÔÏÞÎÏ ÐÒÁ× ÎÁ ÔÁËÂÌÉÃÙ ÚÁÐÒÏÓÁ"
+ ukr "EXPLAIN/SHOW ÎÅ ÍÏÖÅ ÂÕÔÉ ×¦ËÏÎÁÎÏ; ÎÅÍÁ¤ ÐÒÁ× ÎÁ ÔÉÂÌÉæ ÚÁÐÉÔÕ"
+ER_FRM_UNKNOWN_TYPE
+ eng "File '%-.64s' has unknown type '%-.64s' in its header"
+ rus "æÁÊÌ '%-.64s' ÓÏÄÅÒÖÉÔ ÎÅÉÚ×ÅÓÔÎÙÊ ÔÉÐ '%-.64s' × ÚÁÇÏÌÏ×ËÅ"
+ ukr "æÁÊÌ '%-.64s' ÍÁ¤ ÎÅצÄÏÍÉÊ ÔÉÐ '%-.64s' Õ ÚÁÇÏÌÏ×ËÕ"
+ER_WRONG_OBJECT
+ eng "'%-.64s.%-.64s' is not %s"
+ rus "'%-.64s.%-.64s' - ÎÅ %s"
+ ukr "'%-.64s.%-.64s' ÎÅ ¤ %s"
+ER_NONUPDATEABLE_COLUMN
+ eng "Column '%-.64s' is not updatable"
+ rus "óÔÏÌÂÅà '%-.64s' ÎÅ ÏÂÎÏ×ÌÑÅÍÙÊ"
+ ukr "óÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÚÍÉÎÅÎÉÊ"
+ER_VIEW_SELECT_DERIVED
+ eng "View's SELECT contains a subquery in the FROM clause"
+ rus "View SELECT ÓÏÄÅÒÖÉÔ ÐÏÄÚÁÐÒÏÓ × ËÏÎÓÔÒÕËÃÉÉ FROM"
+ ukr "View SELECT ÍÁ¤ ЦÄÚÁÐÉÔ Õ ËÏÎÓÔÒÕËæ§ FROM"
+ER_VIEW_SELECT_CLAUSE
+ eng "View's SELECT contains a '%s' clause"
+ rus "View SELECT ÓÏÄÅÒÖÉÔ ËÏÎÓÔÒÕËÃÉÀ '%s'"
+ ukr "View SELECT ÍÁ¤ ËÏÎÓÔÒÕËæÀ '%s'"
+ER_VIEW_SELECT_VARIABLE
+ eng "View's SELECT contains a variable or parameter"
+ rus "View SELECT ÓÏÄÅÒÖÉÔ ÐÅÒÅÍÅÎÎÕÀ ÉÌÉ ÐÁÒÁÍÅÔÒ"
+ ukr "View SELECT ÍÁ¤ ÚÍÉÎÎÕ ÁÂÏ ÐÁÒÁÍÅÔÅÒ"
+ER_VIEW_SELECT_TMPTABLE
+ eng "View's SELECT contains a temporary table '%-.64s'"
+ rus "View SELECT ÓÏÄÅÒÖÉÔ ÓÓÙÌËÕ ÎÁ ×ÒÅÍÅÎÎÕÀ ÔÁÂÌÉÃÕ '%-.64s'"
+ ukr "View SELECT ×ÉËÏÒÉÓÔÏ×Õ¤ ÔÉÍÞÁÓÏ×Õ ÔÁÂÌÉÃÀ '%-.64s'"
+ER_VIEW_WRONG_LIST
+ eng "View's SELECT and view's field list have different column counts"
+ rus "View SELECT É ÓÐÉÓÏË ÐÏÌÅÊ view ÉÍÅÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
+ ukr "View SELECT ¦ ÐÅÒÅÌ¦Ë ÓÔÏ×ÂÃ¦× view ÍÁÀÔØ Ò¦ÚÎÕ Ë¦ÌØ˦ÓÔØ ÓËÏ×Âæ×"
+ER_WARN_VIEW_MERGE
+ eng "View merge algorithm can't be used here for now (assumed undefined algorithm)"
+ rus "áÌÇÏÒÉÔÍ ÓÌÉÑÎÉÑ view ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ÓÅÊÞÁÓ (ÁÌÇÏÒÉÔÍ ÂÕÄÅÔ ÎÅÏÐÅÒÅÄÅÌÅÎÎÙÍ)"
+ ukr "áÌÇÏÒÉÔÍ ÚÌÉ×ÁÎÎÑ view ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ ÚÁÒÁÚ (ÁÌÇÏÒÉÔÍ ÂÕÄÅ ÎÅ×ÉÚÎÁÞÅÎÉÊ)"
+ER_WARN_VIEW_WITHOUT_KEY
+ eng "View being updated does not have complete key of underlying table in it"
+ rus "ïÂÎÏ×ÌÑÅÍÙÊ view ÎÅ ÓÏÄÅÒÖÉÔ ËÌÀÞÁ ÉÓÐÏÌØÚÏ×ÁÎÎÙÈ(ÏÊ) × ÎÅÍ ÔÁÂÌÉÃ(Ù)"
+ ukr "View, ÝÏ ÏÎÏ×ÌÀÅÔØÓÑ, ΊͦÓÔÉÔØ ÐÏ×ÎÏÇÏ ËÌÀÞÁ ÔÁÂÌÉæ(Ø), ÝÏ ×ÉËÏÒ¦ÓÔÁÎÁ × ÎØÀÏÍÕ"
+ER_VIEW_INVALID
+ eng "View '%-.64s.%-.64s' references invalid table(s) or column(s) or function(s)"
+ rus "View '%-.64s.%-.64s' ÓÓÙÌÁÅÔÓÑ ÎÁ ÎÅÓÕÝÅÓÔ×ÕÀÝÉÅ ÔÁÂÌÉÃÙ ÉÌÉ ÓÔÏÌÂÃÙ ÉÌÉ ÆÕÎËÃÉÉ"
+ER_SP_NO_DROP_SP
+ eng "Can't drop or alter a %s from within another stored routine"
+ER_SP_GOTO_IN_HNDLR
+ eng "GOTO is not allowed in a stored procedure handler"
+ER_TRG_ALREADY_EXISTS
+ eng "Trigger already exists"
+ER_TRG_DOES_NOT_EXIST
+ eng "Trigger does not exist"
+ER_TRG_ON_VIEW_OR_TEMP_TABLE
+ eng "Trigger's '%-.64s' is view or temporary table"
+ER_TRG_CANT_CHANGE_ROW
+ eng "Updating of %s row is not allowed in %strigger"
+ER_TRG_NO_SUCH_ROW_IN_TRG
+ eng "There is no %s row in %s trigger"
+ER_NO_DEFAULT_FOR_FIELD
+ eng "Field '%-.64s' doesn't have a default value"
+ER_DIVISION_BY_ZERO 22012
+ eng "Division by 0"
+ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+ eng "Incorrect %-.32s value: '%-.128s' for column '%.64s' at row %ld"
+ER_ILLEGAL_VALUE_FOR_TYPE 22007
+ eng "Illegal %s '%-.64s' value found during parsing"
+ER_VIEW_NONUPD_CHECK
+ eng "CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
+ rus "CHECK OPTION ÄÌÑ ÎÅÏÂÎÏ×ÌÑÅÍÏÇÏ VIEW '%-.64s.%-.64s'"
+ ukr "CHECK OPTION ÄÌÑ VIEW '%-.64s.%-.64s' ÝÏ ÎÅ ÍÏÖÅ ÂÕÔÉ ÏÎÏ×ÌÅÎÎÉÍ"
+ER_VIEW_CHECK_FAILED
+ eng "CHECK OPTION failed '%-.64s.%-.64s'"
+ rus "ÐÒÏ×ÅÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.64s.%-.64s' ÐÒÏ×ÁÌÉÌÁÓØ"
+ ukr "ðÅÒÅצÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.64s.%-.64s' ÎÅ ÐÒÏÊÛÌÁ"
+ER_PROCACCESS_DENIED_ERROR 42000
+ eng "%-.16s command denied to user '%-.32s'@'%-.64s' for routine '%-.64s'"
+ER_RELAY_LOG_FAIL
+ eng "Failed purging old relay logs: %s"
+ER_PASSWD_LENGTH
+ eng "Password hash should be a %d-digit hexadecimal number"
+ER_UNKNOWN_TARGET_BINLOG
+ eng "Target log not found in binlog index"
+ER_IO_ERR_LOG_INDEX_READ
+ eng "I/O error reading log index file"
+ER_BINLOG_PURGE_PROHIBITED
+ eng "Server configuration does not permit binlog purge"
+ER_FSEEK_FAIL
+ eng "Failed on fseek()"
+ER_BINLOG_PURGE_FATAL_ERR
+ eng "Fatal error during log purge"
+ER_LOG_IN_USE
+ eng "A purgeable log is in use, will not purge"
+ER_LOG_PURGE_UNKNOWN_ERR
+ eng "Unknown error during log purge"
+ER_RELAY_LOG_INIT
+ eng "Failed initializing relay log position: %s"
+ER_NO_BINARY_LOGGING
+ eng "You are not using binary logging"
+ER_RESERVED_SYNTAX
+ eng "The '%-.64s' syntax is reserved for purposes internal to the MySQL server"
+ER_WSAS_FAILED
+ eng "WSAStartup Failed"
+ER_DIFF_GROUPS_PROC
+ eng "Can't handle procedures with differents groups yet"
+ER_NO_GROUP_FOR_PROC
+ eng "Select must have a group with this procedure"
+ER_ORDER_WITH_PROC
+ eng "Can't use ORDER clause with this procedure"
+ER_LOGGING_PROHIBIT_CHANGING_OF
+ eng "Binary logging and replication forbid changing the global server %s"
+ER_NO_FILE_MAPPING
+ eng "Can't map file: %-.64s, errno: %d"
+ER_WRONG_MAGIC
+ eng "Wrong magic in %-.64s"
+ER_PS_MANY_PARAM
+ eng "Prepared statement contains too many placeholders"
+ER_KEY_PART_0
+ eng "Key part '%-.64s' length cannot be 0"
+ER_VIEW_CHECKSUM
+ eng "View text checksum failed"
+ rus "ðÒÏ×ÅÒËÁ ËÏÎÔÒÏÌØÎÏÊ ÓÕÍÍÙ ÔÅËÓÔÁ VIEW ÐÒÏ×ÁÌÉÌÁÓØ"
+ ukr "ðÅÒÅצÒËÁ ËÏÎÔÒÏÌØÎϧ ÓÕÍÉ ÔÅËÓÔÕ VIEW ÎÅ ÐÒÏÊÛÌÁ"
+ER_VIEW_MULTIUPDATE
+ eng "Can not modify more than one base table through a join view '%-.64s.%-.64s'"
+ rus "îÅÌØÚÑ ÉÚÍÅÎÉÔØ ÂÏÌØÛÅ ÞÅÍ ÏÄÎÕ ÂÁÚÏ×ÕÀ ÔÁÂÌÉÃÕ ÉÓÐÏÌØÚÕÑ ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.64s.%-.64s'"
+ ukr "îÅÍÏÖÌÉ×Ï ÏÎÏ×ÉÔÉ Â¦ÌØÛ ÎÉÖ ÏÄÎÕ ÂÁÚÏ×Õ ÔÁÂÌÉÃÀ ×ÙËÏÒÉÓÔÏ×ÕÀÞÉ VIEW '%-.64s.%-.64s', ÝÏ Í¦ÓÔ¦ÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ"
+ER_VIEW_NO_INSERT_FIELD_LIST
+ eng "Can not insert into join view '%-.64s.%-.64s' without fields list"
+ rus "îÅÌØÚÑ ×ÓÔÁ×ÌÑÔØ ÚÁÐÉÓÉ × ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.64s.%-.64s' ÂÅÚ ÓÐÉÓËÁ ÐÏÌÅÊ"
+ ukr "îÅÍÏÖÌÉ×Ï ÕÓÔÁ×ÉÔÉ ÒÑÄËÉ Õ VIEW '%-.64s.%-.64s', ÝÏ Í¦ÓÔÉÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ, ÂÅÚ ÓÐÉÓËÕ ÓÔÏ×Âæ×"
+ER_VIEW_DELETE_MERGE_VIEW
+ eng "Can not delete from join view '%-.64s.%-.64s'"
+ rus "îÅÌØÚÑ ÕÄÁÌÑÔØ ÉÚ ÍÎÏÇÏÔÁÂÌÉÞÎÏÇÏ VIEW '%-.64s.%-.64s'"
+ ukr "îÅÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÑÄËÉ Õ VIEW '%-.64s.%-.64s', ÝÏ Í¦ÓÔÉÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ"
+ER_CANNOT_USER
+ eng "Operation %s failed for %.256s"
+ ger "Das Kommando %s scheiterte für %.256s"
+ norwegian-ny "Operation %s failed for '%.256s'"
+ER_XAER_NOTA XAE04
+ eng "XAER_NOTA: Unknown XID"
+ER_XAER_INVAL XAE05
+ eng "XAER_INVAL: Invalid arguments (or unsupported command)"
+ER_XAER_RMFAIL XAE07
+ eng "XAER_RMFAIL: The command cannot be executed in the %.64s state"
+ER_XAER_OUTSIDE XAE09
+ eng "XAER_OUTSIDE: Some work is done outside global transaction"
+ER_XAER_RMERR XAE03
+ eng "XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency"
+ER_XA_RBROLLBACK XA100
+ eng "XA_RBROLLBACK: Transaction branch was rolled back"
+ER_NONEXISTING_PROC_GRANT 42000
+ eng "There is no such grant defined for user '%-.32s' on host '%-.64s' on routine '%-.64s'"
+ER_PROC_AUTO_GRANT_FAIL
+ eng "Failed to grant EXECUTE and ALTER ROUTINE privileges"
+ER_PROC_AUTO_REVOKE_FAIL
+ eng "Failed to revoke all privileges to dropped routine"
+ER_DATA_TOO_LONG 22001
+ eng "Data too long for column '%s' at row %ld"
+ER_SP_BAD_SQLSTATE 42000
+ eng "Bad SQLSTATE: '%s'"
+ER_STARTUP
+ eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d %s"
+ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR
+ eng "Can't load value from file with fixed size rows to variable"
+ER_CANT_CREATE_USER_WITH_GRANT 42000
+ eng "You are not allowed to create a user with GRANT"
+ER_WRONG_VALUE_FOR_TYPE
+ eng "Incorrect %-.32s value: '%-.128s' for function %-.32s"
+ER_TABLE_DEF_CHANGED
+ eng "Table definition has changed, please retry transaction"
+ER_SP_DUP_HANDLER 42000
+ eng "Duplicate handler declared in the same block"
+ER_SP_NOT_VAR_ARG 42000
+ eng "OUT or INOUT argument %d for routine %s is not a variable"
+ER_SP_NO_RETSET_IN_FUNC 0A000
+ eng "Not allowed to return a result set from a function"
+ER_CANT_CREATE_GEOMETRY_OBJECT 22003
+ eng "Cannot get geometry object from data you send to the GEOMETRY field"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
deleted file mode 100644
index 5aab524e0d9..00000000000
--- a/sql/share/estonian/errmsg.txt
+++ /dev/null
@@ -1,326 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Esialgne tõlge: Tõnu Samuel (tonu@spam.ee)
- Parandanud ja täiendanud: Indrek Siitan (tfr@mysql.com)
-*/
-
-character-set=latin7
-
-"hashchk",
-"isamchk",
-"EI",
-"JAH",
-"Ei suuda luua faili '%-.64s' (veakood: %d)",
-"Ei suuda luua tabelit '%-.64s' (veakood: %d)",
-"Ei suuda luua andmebaasi '%-.64s' (veakood: %d)",
-"Ei suuda luua andmebaasi '%-.64s': andmebaas juba eksisteerib",
-"Ei suuda kustutada andmebaasi '%-.64s': andmebaasi ei eksisteeri",
-"Viga andmebaasi kustutamisel (ei suuda kustutada faili '%-.64s', veakood: %d)",
-"Viga andmebaasi kustutamisel (ei suuda kustutada kataloogi '%-.64s', veakood: %d)",
-"Viga '%-.64s' kustutamisel (veakood: %d)",
-"Ei suuda lugeda kirjet süsteemsest tabelist",
-"Ei suuda lugeda '%-.64s' olekut (veakood: %d)",
-"Ei suuda identifitseerida jooksvat kataloogi (veakood: %d)",
-"Ei suuda lukustada faili (veakood: %d)",
-"Ei suuda avada faili '%-.64s' (veakood: %d)",
-"Ei suuda leida faili '%-.64s' (veakood: %d)",
-"Ei suuda lugeda kataloogi '%-.64s' (veakood: %d)",
-"Ei suuda siseneda kataloogi '%-.64s' (veakood: %d)",
-"Kirje tabelis '%-.64s' on muutunud viimasest lugemisest saadik",
-"Ketas täis (%s). Ootame kuni tekib vaba ruumi...",
-"Ei saa kirjutada, korduv võti tabelis '%-.64s'",
-"Viga faili '%-.64s' sulgemisel (veakood: %d)",
-"Viga faili '%-.64s' lugemisel (veakood: %d)",
-"Viga faili '%-.64s' ümbernimetamisel '%-.64s'-ks (veakood: %d)",
-"Viga faili '%-.64s' kirjutamisel (veakood: %d)",
-"'%-.64s' on lukustatud muudatuste vastu",
-"Sorteerimine katkestatud",
-"Vaade '%-.64s' ei eksisteeri '%-.64s' jaoks",
-"Tabeli handler tagastas vea %d",
-"Tabeli '%-.64s' handler ei toeta antud operatsiooni",
-"Ei suuda leida kirjet '%-.64s'-s",
-"Vigane informatsioon failis '%-.64s'",
-"Tabeli '%-.64s' võtmefail on vigane; proovi seda parandada",
-"Tabeli '%-.64s' võtmefail on aegunud; paranda see!",
-"Tabel '%-.64s' on ainult lugemiseks",
-"Mälu sai otsa. Proovi MySQL uuesti käivitada (puudu jäi %d baiti)",
-"Mälu sai sorteerimisel otsa. Suurenda MySQL-i sorteerimispuhvrit",
-"Ootamatu faililõpumärgend faili '%-.64s' lugemisel (veakood: %d)",
-"Liiga palju samaaegseid ühendusi",
-"Mälu sai otsa. Võimalik, et aitab swap-i lisamine või käsu 'ulimit' abil MySQL-le rohkema mälu kasutamise lubamine",
-"Ei suuda lahendada IP aadressi masina nimeks",
-"Väär handshake",
-"Ligipääs keelatud kasutajale '%-.32s'@'%-.64s' andmebaasile '%-.64s'",
-"Ligipääs keelatud kasutajale '%-.32s'@'%-.64s' (kasutab parooli: %s)",
-"Andmebaasi ei ole valitud",
-"Tundmatu käsk",
-"Tulp '%-.64s' ei saa omada nullväärtust",
-"Tundmatu andmebaas '%-.64s'",
-"Tabel '%-.64s' juba eksisteerib",
-"Tundmatu tabel '%-.64s'",
-"Väli '%-.64s' %-.64s-s ei ole ühene",
-"Serveri seiskamine käib",
-"Tundmatu tulp '%-.64s' '%-.64s'-s",
-"'%-.64s' puudub GROUP BY klauslis",
-"Ei saa grupeerida '%-.64s' järgi",
-"Lauses on korraga nii tulbad kui summeerimisfunktsioonid",
-"Tulpade arv erineb väärtuste arvust",
-"Identifikaatori '%-.100s' nimi on liiga pikk",
-"Kattuv tulba nimi '%-.64s'",
-"Kattuv võtme nimi '%-.64s'",
-"Kattuv väärtus '%-.64s' võtmele %d",
-"Vigane tulba kirjeldus tulbale '%-.64s'",
-"%s '%-.80s' ligidal real %d",
-"Tühi päring",
-"Ei ole unikaalne tabel/alias '%-.64s'",
-"Vigane vaikeväärtus '%-.64s' jaoks",
-"Mitut primaarset võtit ei saa olla",
-"Liiga palju võtmeid. Maksimaalselt võib olla %d võtit",
-"Võti koosneb liiga paljudest osadest. Maksimaalselt võib olla %d osa",
-"Võti on liiga pikk. Maksimaalne võtmepikkus on %d",
-"Võtme tulp '%-.64s' puudub tabelis",
-"BLOB-tüüpi tulpa '%-.64s' ei saa kasutada võtmena",
-"Tulba '%-.64s' pikkus on liiga pikk (maksimaalne pikkus: %d). Kasuta BLOB väljatüüpi",
-"Vigane tabelikirjeldus; Tabelis tohib olla üks auto_increment tüüpi tulp ning see peab olema defineeritud võtmena",
-"%s: ootab ühendusi",
-"%s: MySQL lõpetas\n",
-"%s: sain signaali %d. Lõpetan!\n",
-"%s: Lõpp\n",
-"%s: Sulgen jõuga lõime %ld kasutaja: '%-.32s'\n",
-"Ei suuda luua IP socketit",
-"Tabelil '%-.64s' puuduvad võtmed. Loo tabel uuesti",
-"Väljade eraldaja erineb oodatust. Tutvu kasutajajuhendiga",
-"BLOB-tüüpi väljade olemasolul ei saa kasutada fikseeritud väljapikkust. Vajalik 'fields terminated by' määrang.",
-"Fail '%-.64s' peab asuma andmebaasi kataloogis või olema kõigile loetav",
-"Fail '%-.80s' juba eksisteerib",
-"Kirjeid: %ld Kustutatud: %ld Vahele jäetud: %ld Hoiatusi: %ld",
-"Kirjeid: %ld Kattuvaid: %ld",
-"Vigane võtme osa. Kasutatud võtmeosa ei ole string tüüpi, määratud pikkus on pikem kui võtmeosa või tabelihandler ei toeta seda tüüpi võtmeid",
-"ALTER TABLE kasutades ei saa kustutada kõiki tulpasid. Kustuta tabel DROP TABLE abil",
-"Ei suuda kustutada '%-.64s'. Kontrolli kas tulp/võti eksisteerib",
-"Kirjeid: %ld Kattuvaid: %ld Hoiatusi: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Tundmatu lõim: %lu",
-"Ei ole lõime %lu omanik",
-"Ühtegi tabelit pole kasutusel",
-"Liiga palju string tulbale %-.64s tüübile SET",
-"Ei suuda luua unikaalset logifaili nime %-.64s.(1-999)\n",
-"Tabel '%-.64s' on lukustatud READ lukuga ning ei ole muudetav",
-"Tabel '%-.64s' ei ole lukustatud käsuga LOCK TABLES",
-"BLOB-tüüpi tulp '%-.64s' ei saa omada vaikeväärtust",
-"Vigane andmebaasi nimi '%-.100s'",
-"Vigane tabeli nimi '%-.100s'",
-"SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada käsku SET SQL_BIG_SELECTS=1",
-"Tundmatu viga",
-"Tundmatu protseduur '%-.64s'",
-"Vale parameetrite hulk protseduurile '%-.64s'",
-"Vigased parameetrid protseduurile '%-.64s'",
-"Tundmatu tabel '%-.64s' %-.32s-s",
-"Tulp '%-.64s' on määratletud topelt",
-"Vigane grupeerimisfunktsiooni kasutus",
-"Tabel '%-.64s' kasutab laiendust, mis ei eksisteeri antud MySQL versioonis",
-"Tabelis peab olema vähemalt üks tulp",
-"Tabel '%-.64s' on täis",
-"Vigane kooditabel '%-.64s'",
-"Liiga palju tabeleid. MySQL suudab JOINiga ühendada kuni %d tabelit",
-"Liiga palju tulpasid",
-"Liiga pikk kirje. Kirje maksimumpikkus arvestamata BLOB-tüüpi välju on %d. Muuda mõned väljad BLOB-tüüpi väljadeks",
-"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
-"Ristsõltuvus OUTER JOIN klauslis. Kontrolli oma ON tingimusi",
-"Tulp '%-.64s' on kasutusel indeksina, kuid ei ole määratletud kui NOT NULL",
-"Ei suuda avada funktsiooni '%-.64s'",
-"Ei suuda algväärtustada funktsiooni '%-.64s'; %-.80s",
-"Teegi nimes ei tohi olla kataloogi",
-"Funktsioon '%-.64s' juba eksisteerib",
-"Ei suuda avada jagatud teeki '%-.64s' (veakood: %d %-.64s)",
-"Ei leia funktsiooni '%-.64s' antud teegis",
-"Funktsioon '%-.64s' ei ole defineeritud",
-"Masin '%-.64s' on blokeeritud hulgaliste ühendusvigade tõttu. Blokeeringu saab tühistada 'mysqladmin flush-hosts' käsuga",
-"Masinal '%-.64s' puudub ligipääs sellele MySQL serverile",
-"Te kasutate MySQL-i anonüümse kasutajana, kelledel pole parooli muutmise õigust",
-"Teiste paroolide muutmiseks on nõutav tabelite muutmisõigus 'mysql' andmebaasis",
-"Ei leia vastavat kirjet kasutajate tabelis",
-"Sobinud kirjeid: %ld Muudetud: %ld Hoiatusi: %ld",
-"Ei suuda luua uut lõime (veakood %d). Kui mälu ei ole otsas, on tõenäoliselt tegemist operatsioonisüsteemispetsiifilise veaga",
-"Tulpade hulk erineb väärtuste hulgast real %ld",
-"Ei suuda taasavada tabelit '%-.64s'",
-"NULL väärtuse väärkasutus",
-"regexp tagastas vea '%-.64s'",
-"GROUP tulpade (MIN(),MAX(),COUNT()...) kooskasutamine tavaliste tulpadega ilma GROUP BY klauslita ei ole lubatud",
-"Sellist õigust ei ole defineeritud kasutajale '%-.32s' masinast '%-.64s'",
-"%-.16s käsk ei ole lubatud kasutajale '%-.32s'@'%-.64s' tabelis '%-.64s'",
-"%-.16s käsk ei ole lubatud kasutajale '%-.32s'@'%-.64s' tulbale '%-.64s' tabelis '%-.64s'",
-"Vigane GRANT/REVOKE käsk. Tutvu kasutajajuhendiga",
-"Masina või kasutaja nimi GRANT lauses on liiga pikk",
-"Tabelit '%-.64s.%-.64s' ei eksisteeri",
-"Sellist õigust ei ole defineeritud kasutajale '%-.32s' masinast '%-.64s' tabelile '%-.64s'",
-"Antud käsk ei ole lubatud käesolevas MySQL versioonis",
-"Viga SQL süntaksis",
-"INSERT DELAYED lõim ei suutnud saada soovitud lukku tabelile %-.64s",
-"Liiga palju DELAYED lõimesid kasutusel",
-"Ühendus katkestatud %ld andmebaasile: '%-.64s' kasutajale: '%-.32s' (%-.64s)",
-"Saabus suurem pakett kui lubatud 'max_allowed_packet' muutujaga",
-"Viga ühendustoru lugemisel",
-"fcntl() tagastas vea",
-"Paketid saabusid vales järjekorras",
-"Viga andmepaketi lahtipakkimisel",
-"Viga andmepaketi lugemisel",
-"Kontrollaja ületamine andmepakettide lugemisel",
-"Viga andmepaketi kirjutamisel",
-"Kontrollaja ületamine andmepakettide kirjutamisel",
-"Tulemus on pikem kui lubatud 'max_allowed_packet' muutujaga",
-"Valitud tabelitüüp ei toeta BLOB/TEXT tüüpi välju",
-"Valitud tabelitüüp ei toeta AUTO_INCREMENT tüüpi välju",
-"INSERT DELAYED ei saa kasutada tabeli '%-.64s' peal, kuna see on lukustatud LOCK TABLES käsuga",
-"Vigane tulba nimi '%-.100s'",
-"Tabelihandler ei oska indekseerida tulpa '%-.64s'",
-"Kõik tabelid MERGE tabeli määratluses ei ole identsed",
-"Ei suuda kirjutada tabelisse '%-.64s', kuna see rikub ühesuse kitsendust",
-"BLOB-tüüpi tulp '%-.64s' on kasutusel võtmes ilma pikkust määratlemata",
-"Kõik PRIMARY KEY peavad olema määratletud NOT NULL piiranguga; vajadusel kasuta UNIQUE tüüpi võtit",
-"Tulemis oli rohkem kui üks kirje",
-"Antud tabelitüüp nõuab primaarset võtit",
-"Antud MySQL versioon on kompileeritud ilma RAID toeta",
-"Katse muuta tabelit turvalises rezhiimis ilma WHERE klauslita",
-"Võti '%-.64s' ei eksisteeri tabelis '%-.64s'",
-"Ei suuda avada tabelit",
-"Antud tabelitüüp ei toeta %s käske",
-"Seda käsku ei saa kasutada transaktsiooni sees",
-"Viga %d käsu COMMIT täitmisel",
-"Viga %d käsu ROLLBACK täitmisel",
-"Viga %d käsu FLUSH_LOGS täitmisel",
-"Viga %d käsu CHECKPOINT täitmisel",
-"Ühendus katkestatud %ld andmebaas: '%-.64s' kasutaja: '%-.32s' masin: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Ei suutnud leida FULLTEXT indeksit, mis kattuks kasutatud tulpadega",
-"Ei suuda täita antud käsku kuna on aktiivseid lukke või käimasolev transaktsioon",
-"Tundmatu süsteemne muutuja '%-.64s'",
-"Tabel '%-.64s' on märgitud vigaseks ja tuleb parandada",
-"Tabel '%-.64s' on märgitud vigaseks ja viimane (automaatne?) parandus ebaõnnestus",
-"Hoiatus: mõnesid transaktsioone mittetoetavaid tabeleid ei suudetud tagasi kerida",
-"Mitme lausendiga transaktsioon nõudis rohkem ruumi kui lubatud 'max_binlog_cache_size' muutujaga. Suurenda muutuja väärtust ja proovi uuesti",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"Kasutajal %-.64s on juba rohkem ühendusi kui lubatud 'max_user_connections' muutujaga",
-"Ainult konstantsed suurused on lubatud SET klauslis",
-"Kontrollaeg ületatud luku järel ootamisel; Proovi transaktsiooni otsast alata",
-"Lukkude koguarv ületab lukutabeli suuruse",
-"Uuenduslukke ei saa kasutada READ UNCOMMITTED transaktsiooni käigus",
-"DROP DATABASE ei ole lubatud kui lõim omab globaalset READ lukku",
-"CREATE DATABASE ei ole lubatud kui lõim omab globaalset READ lukku",
-"Vigased parameetrid %s-le",
-"Kasutajal '%-.32s'@'%-.64s' ei ole lubatud luua uusi kasutajaid",
-"Vigane tabelimääratlus; kõik MERGE tabeli liikmed peavad asuma samas andmebaasis",
-"Lukustamisel tekkis tupik (deadlock); alusta transaktsiooni otsast",
-"Antud tabelitüüp ei toeta FULLTEXT indekseid",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Viga käsu %s täitmisel: %-.128s",
-"Vigane %s ja %s kasutus",
-"Tulpade arv kasutatud SELECT lausetes ei kattu",
-"Ei suuda täita päringut konfliktse luku tõttu",
-"Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud",
-"Määrangut '%s' on lauses kasutatud topelt",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
deleted file mode 100644
index bb2bd29171a..00000000000
--- a/sql/share/french/errmsg.txt
+++ /dev/null
@@ -1,321 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NON",
-"OUI",
-"Ne peut créer le fichier '%-.64s' (Errcode: %d)",
-"Ne peut créer la table '%-.64s' (Errcode: %d)",
-"Ne peut créer la base '%-.64s' (Erreur %d)",
-"Ne peut créer la base '%-.64s'; elle existe déjà",
-"Ne peut effacer la base '%-.64s'; elle n'existe pas",
-"Ne peut effacer la base '%-.64s' (erreur %d)",
-"Erreur en effaçant la base (rmdir '%-.64s', erreur %d)",
-"Erreur en effaçant '%-.64s' (Errcode: %d)",
-"Ne peut lire un enregistrement de la table 'system'",
-"Ne peut obtenir le status de '%-.64s' (Errcode: %d)",
-"Ne peut obtenir le répertoire de travail (Errcode: %d)",
-"Ne peut verrouiller le fichier (Errcode: %d)",
-"Ne peut ouvrir le fichier: '%-.64s' (Errcode: %d)",
-"Ne peut trouver le fichier: '%-.64s' (Errcode: %d)",
-"Ne peut lire le répertoire de '%-.64s' (Errcode: %d)",
-"Ne peut changer le répertoire pour '%-.64s' (Errcode: %d)",
-"Enregistrement modifié depuis sa dernière lecture dans la table '%-.64s'",
-"Disque plein (%s). J'attend que quelqu'un libère de l'espace...",
-"Ecriture impossible, doublon dans une clé de la table '%-.64s'",
-"Erreur a la fermeture de '%-.64s' (Errcode: %d)",
-"Erreur en lecture du fichier '%-.64s' (Errcode: %d)",
-"Erreur en renommant '%-.64s' en '%-.64s' (Errcode: %d)",
-"Erreur d'écriture du fichier '%-.64s' (Errcode: %d)",
-"'%-.64s' est verrouillé contre les modifications",
-"Tri alphabétique abandonné",
-"La vue (View) '%-.64s' n'existe pas pour '%-.64s'",
-"Reçu l'erreur %d du handler de la table",
-"Le handler de la table '%-.64s' n'a pas cette option",
-"Ne peut trouver l'enregistrement dans '%-.64s'",
-"Information erronnée dans le fichier: '%-.64s'",
-"Index corrompu dans la table: '%-.64s'; essayez de le réparer",
-"Vieux fichier d'index pour la table '%-.64s'; réparez le!",
-"'%-.64s' est en lecture seulement",
-"Manque de mémoire. Redémarrez le démon et ré-essayez (%d octets nécessaires)",
-"Manque de mémoire pour le tri. Augmentez-la.",
-"Fin de fichier inattendue en lisant '%-.64s' (Errcode: %d)",
-"Trop de connections",
-"Manque de 'threads'/mémoire",
-"Ne peut obtenir de hostname pour votre adresse",
-"Mauvais 'handshake'",
-"Accès refusé pour l'utilisateur: '%-.32s'@'@%-.64s'. Base '%-.64s'",
-"Accès refusé pour l'utilisateur: '%-.32s'@'@%-.64s' (mot de passe: %s)",
-"Aucune base n'a été sélectionnée",
-"Commande inconnue",
-"Le champ '%-.64s' ne peut être vide (null)",
-"Base '%-.64s' inconnue",
-"La table '%-.64s' existe déjà",
-"Table '%-.64s' inconnue",
-"Champ: '%-.64s' dans %s est ambigu",
-"Arrêt du serveur en cours",
-"Champ '%-.64s' inconnu dans %s",
-"'%-.64s' n'est pas dans 'group by'",
-"Ne peut regrouper '%-.64s'",
-"Vous demandez la fonction sum() et des champs dans la même commande",
-"Column count doesn't match value count",
-"Le nom de l'identificateur '%-.64s' est trop long",
-"Nom du champ '%-.64s' déjà utilisé",
-"Nom de clef '%-.64s' déjà utilisé",
-"Duplicata du champ '%-.64s' pour la clef %d",
-"Mauvais paramètre de champ pour le champ '%-.64s'",
-"%s près de '%-.64s' à la ligne %d",
-"Query est vide",
-"Table/alias: '%-.64s' non unique",
-"Valeur par défaut invalide pour '%-.64s'",
-"Plusieurs clefs primaires définies",
-"Trop de clefs sont définies. Maximum de %d clefs alloué",
-"Trop de parties specifiées dans la clef. Maximum de %d parties",
-"La clé est trop longue. Longueur maximale: %d",
-"La clé '%-.64s' n'existe pas dans la table",
-"Champ BLOB '%-.64s' ne peut être utilisé dans une clé",
-"Champ '%-.64s' trop long (max = %d). Utilisez un BLOB",
-"Un seul champ automatique est permis et il doit être indexé",
-"%s: Prêt pour des connections",
-"%s: Arrêt normal du serveur\n",
-"%s: Reçu le signal %d. Abandonne!\n",
-"%s: Arrêt du serveur terminé\n",
-"%s: Arrêt forcé de la tâche (thread) %ld utilisateur: '%-.64s'\n",
-"Ne peut créer la connection IP (socket)",
-"La table '%-.64s' n'a pas d'index comme celle utilisée dans CREATE INDEX. Recréez la table",
-"Séparateur de champs inconnu. Vérifiez dans le manuel",
-"Vous ne pouvez utiliser des lignes de longueur fixe avec des BLOBs. Utiliser 'fields terminated by'.",
-"Le fichier '%-.64s' doit être dans le répertoire de la base et lisible par tous",
-"Le fichier '%-.64s' existe déjà",
-"Enregistrements: %ld Effacés: %ld Non traités: %ld Avertissements: %ld",
-"Enregistrements: %ld Doublons: %ld",
-"Mauvaise sous-clef. Ce n'est pas un 'string' ou la longueur dépasse celle définie dans la clef",
-"Vous ne pouvez effacer tous les champs avec ALTER TABLE. Utilisez DROP TABLE",
-"Ne peut effacer (DROP) '%-.64s'. Vérifiez s'il existe",
-"Enregistrements: %ld Doublons: %ld Avertissements: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Numéro de tâche inconnu: %lu",
-"Vous n'êtes pas propriétaire de la tâche no: %lu",
-"Aucune table utilisée",
-"Trop de chaînes dans la colonne %s avec SET",
-"Ne peut générer un unique nom de journal %s.(1-999)\n",
-"Table '%-.64s' verrouillée lecture (READ): modification impossible",
-"Table '%-.64s' non verrouillée: utilisez LOCK TABLES",
-"BLOB '%-.64s' ne peut avoir de valeur par défaut",
-"Nom de base de donnée illégal: '%-.64s'",
-"Nom de table illégal: '%-.64s'",
-"SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET SQL_BIG_SELECTS=1 si SELECT se passe bien",
-"Erreur inconnue",
-"Procédure %s inconnue",
-"Mauvais nombre de paramètres pour la procedure %s",
-"Paramètre erroné pour la procedure %s",
-"Table inconnue '%-.64s' dans %s",
-"Champ '%-.64s' spécifié deux fois",
-"Utilisation invalide de la clause GROUP",
-"Table '%-.64s' : utilise une extension invalide pour cette version de MySQL",
-"Une table doit comporter au moins une colonne",
-"La table '%-.64s' est pleine",
-"Jeu de caractères inconnu: '%-.64s'",
-"Trop de tables. MySQL ne peut utiliser que %d tables dans un JOIN",
-"Trop de champs",
-"Ligne trop grande. Le taille maximale d'une ligne, sauf les BLOBs, est %d. Changez le type de quelques colonnes en BLOB",
-"Débordement de la pile des tâches (Thread stack). Utilisées: %ld pour une pile de %ld. Essayez 'mysqld -O thread_stack=#' pour indiquer une plus grande valeur",
-"Dépendance croisée dans une clause OUTER JOIN. Vérifiez la condition ON",
-"La colonne '%-.32s' fait partie d'un index UNIQUE ou INDEX mais n'est pas définie comme NOT NULL",
-"Imposible de charger la fonction '%-.64s'",
-"Impossible d'initialiser la fonction '%-.64s'; %-.80s",
-"Chemin interdit pour les bibliothèques partagées",
-"La fonction '%-.64s' existe déjà",
-"Impossible d'ouvrir la bibliothèque partagée '%-.64s' (errno: %d %s)",
-"Impossible de trouver la fonction '%-.64s' dans la bibliothèque'",
-"La fonction '%-.64s' n'est pas définie",
-"L'hôte '%-.64s' est bloqué à cause d'un trop grand nombre d'erreur de connection. Débloquer le par 'mysqladmin flush-hosts'",
-"Le hôte '%-.64s' n'est pas authorisé à se connecter à ce serveur MySQL",
-"Vous utilisez un utilisateur anonyme et les utilisateurs anonymes ne sont pas autorisés à changer les mots de passe",
-"Vous devez avoir le privilège update sur les tables de la base de donnée mysql pour pouvoir changer les mots de passe des autres",
-"Impossible de trouver un enregistrement correspondant dans la table user",
-"Enregistrements correspondants: %ld Modifiés: %ld Warnings: %ld",
-"Impossible de créer une nouvelle tâche (errno %d). S'il reste de la mémoire libre, consultez le manual pour trouver un éventuel bug dépendant de l'OS",
-"Column count doesn't match value count at row %ld",
-"Impossible de réouvrir la table: '%-.64s",
-"Utilisation incorrecte de la valeur NULL",
-"Erreur '%-.64s' provenant de regexp",
-"Mélanger les colonnes GROUP (MIN(),MAX(),COUNT()...) avec des colonnes normales est interdit s'il n'y a pas de clause GROUP BY",
-"Un tel droit n'est pas défini pour l'utilisateur '%-.32s' sur l'hôte '%-.64s'",
-"La commande '%-.16s' est interdite à l'utilisateur: '%-.32s'@'@%-.64s' sur la table '%-.64s'",
-"La commande '%-.16s' est interdite à l'utilisateur: '%-.32s'@'@%-.64s' sur la colonne '%-.64s' de la table '%-.64s'",
-"Commande GRANT/REVOKE incorrecte. Consultez le manuel.",
-"L'hôte ou l'utilisateur donné en argument à GRANT est trop long",
-"La table '%-.64s.%s' n'existe pas",
-"Un tel droit n'est pas défini pour l'utilisateur '%-.32s' sur l'hôte '%-.64s' sur la table '%-.64s'",
-"Cette commande n'existe pas dans cette version de MySQL",
-"Erreur de syntaxe",
-"La tâche 'delayed insert' n'a pas pu obtenir le verrou démandé sur la table %-.64s",
-"Trop de tâche 'delayed' en cours",
-"Connection %ld avortée vers la bd: '%-.64s' utilisateur: '%-.64s' (%s)",
-"Paquet plus grand que 'max_allowed_packet' reçu",
-"Erreur de lecture reçue du pipe de connection",
-"Erreur reçue de fcntl() ",
-"Paquets reçus dans le désordre",
-"Impossible de décompresser le paquet reçu",
-"Erreur de lecture des paquets reçus",
-"Timeout en lecture des paquets reçus",
-"Erreur d'écriture des paquets envoyés",
-"Timeout d'écriture des paquets envoyés",
-"La chaîne résultat est plus grande que 'max_allowed_packet'",
-"Ce type de table ne supporte pas les colonnes BLOB/TEXT",
-"Ce type de table ne supporte pas les colonnes AUTO_INCREMENT",
-"INSERT DELAYED ne peut être utilisé avec la table '%-.64s', car elle est verrouée avec LOCK TABLES",
-"Nom de colonne '%-.100s' incorrect",
-"Le handler de la table ne peut indexé la colonne '%-.64s'",
-"Toutes les tables de la table de type MERGE n'ont pas la même définition",
-"Écriture impossible à cause d'un index UNIQUE sur la table '%-.64s'",
-"La colonne '%-.64s' de type BLOB est utilisée dans une définition d'index sans longueur d'index",
-"Toutes les parties d'un index PRIMARY KEY doivent être NOT NULL; Si vous avez besoin d'un NULL dans l'index, utilisez un index UNIQUE",
-"Le résultat contient plus d'un enregistrement",
-"Ce type de table nécessite une clé primaire (PRIMARY KEY)",
-"Cette version de MySQL n'est pas compilée avec le support RAID",
-"Vous êtes en mode 'safe update' et vous essayez de faire un UPDATE sans clause WHERE utilisant un index",
-"L'index '%-.64s' n'existe pas sur la table '%-.64s'",
-"Impossible d'ouvrir la table",
-"Ce type de table ne supporte pas les %s",
-"Vous n'êtes pas autorisé à exécute cette commande dans une transaction",
-"Erreur %d lors du COMMIT",
-"Erreur %d lors du ROLLBACK",
-"Erreur %d lors du FLUSH_LOGS",
-"Erreur %d lors du CHECKPOINT",
-"Connection %ld avortée vers la bd: '%-.64s' utilisateur: '%-.32s' hôte: `%-.64s' (%-.64s)",
-"Ce type de table ne supporte pas les copies binaires",
-"Le 'binlog' a été fermé pendant l'exécution du FLUSH MASTER",
-"La reconstruction de l'index de la table copiée '%-.64s' a échoué",
-"Erreur reçue du maître: '%-.64s'",
-"Erreur de lecture réseau reçue du maître",
-"Erreur d'écriture réseau reçue du maître",
-"Impossible de trouver un index FULLTEXT correspondant à cette liste de colonnes",
-"Impossible d'exécuter la commande car vous avez des tables verrouillées ou une transaction active",
-"Variable système '%-.64s' inconnue",
-"La table '%-.64s' est marquée 'crashed' et devrait être réparée",
-"La table '%-.64s' est marquée 'crashed' et le dernier 'repair' a échoué",
-"Attention: certaines tables ne supportant pas les transactions ont été changées et elles ne pourront pas être restituées",
-"Cette transaction à commandes multiples nécessite plus de 'max_binlog_cache_size' octets de stockage, augmentez cette variable de mysqld et réessayez",
-"Cette opération ne peut être réalisée avec un esclave actif, faites STOP SLAVE d'abord",
-"Cette opération nécessite un esclave actif, configurez les esclaves et faites START SLAVE",
-"Le server n'est pas configuré comme un esclave, changez le fichier de configuration ou utilisez CHANGE MASTER TO",
-"Impossible d'initialiser les structures d'information de maître, vous trouverez des messages d'erreur supplémentaires dans le journal des erreurs de MySQL",
-"Impossible de créer une tâche esclave, vérifiez les ressources système",
-"L'utilisateur %-.64s possède déjà plus de 'max_user_connections' connections actives",
-"Seules les expressions constantes sont autorisées avec SET",
-"Timeout sur l'obtention du verrou",
-"Le nombre total de verrou dépasse la taille de la table des verrous",
-"Un verrou en update ne peut être acquit pendant une transaction READ UNCOMMITTED",
-"DROP DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture",
-"CREATE DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture",
-"Mauvais arguments à %s",
-"'%-.32s'@'%-.64s' n'est pas autorisé à créer de nouveaux utilisateurs",
-"Définition de table incorrecte; toutes les tables MERGE doivent être dans la même base de donnée",
-"Deadlock découvert en essayant d'obtenir les verrous : essayez de redémarrer la transaction",
-"Le type de table utilisé ne supporte pas les index FULLTEXT",
-"Impossible d'ajouter des contraintes d'index externe",
-"Impossible d'ajouter un enregistrement fils : une constrainte externe l'empèche",
-"Impossible de supprimer un enregistrement père : une constrainte externe l'empèche",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
deleted file mode 100644
index 03e838dd805..00000000000
--- a/sql/share/german/errmsg.txt
+++ /dev/null
@@ -1,334 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Dirk Munzinger (dmun@4t2.com)
- 2001-06-07
-
- Georg Richter (georg@php.net)
- fixed typos and translation
- translated new error messages
- 2002-12-11
-
- Stefan Hinz (stefan@mysql.com)
- 2003-10-01
-*/
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"Nein",
-"Ja",
-"Kann Datei '%-.64s' nicht erzeugen (Fehler: %d)",
-"Kann Tabelle '%-.64s' nicht erzeugen (Fehler: %d)",
-"Kann Datenbank '%-.64s' nicht erzeugen (Fehler: %d)",
-"Kann Datenbank '%-.64s' nicht erzeugen. Datenbank '%-.64s' existiert bereits",
-"Kann Datenbank '%-.64s' nicht löschen. Keine Datenbank '%-.64s' vorhanden",
-"Fehler beim Löschen der Datenbank ('%-.64s' kann nicht gelöscht werden, Fehlernuumer: %d)",
-"Fehler beim Löschen der Datenbank (Verzeichnis '%-.64s' kann nicht gelöscht werden, Fehlernummer: %d)",
-"Fehler beim Löschen von '%-.64s' (Fehler: %d)",
-"Datensatz in der Systemtabelle nicht lesbar",
-"Kann Status von '%-.64s' nicht ermitteln (Fehler: %d)",
-"Kann Arbeitsverzeichnis nicht ermitteln (Fehler: %d)",
-"Datei kann nicht gesperrt werden (Fehler: %d)",
-"Datei '%-.64s' nicht öffnen (Fehler: %d)",
-"Kann Datei '%-.64s' nicht finden (Fehler: %d)",
-"Verzeichnis von '%-.64s' nicht lesbar (Fehler: %d)",
-"Kann nicht in das Verzeichnis '%-.64s' wechseln (Fehler: %d)",
-"Datensatz hat sich seit dem letzten Zugriff auf Tabelle '%-.64s' geändert",
-"Festplatte voll (%-.64s). Warte, bis jemand Platz schafft ...",
-"Kann nicht speichern, Grund: doppelter Schlüssel in Tabelle '%-.64s'",
-"Fehler beim Schließen von '%-.64s' (Fehler: %d)",
-"Fehler beim Lesen der Datei '%-.64s' (Fehler: %d)",
-"Fehler beim Umbenennen von '%-.64s' in '%-.64s' (Fehler: %d)",
-"Fehler beim Speichern der Datei '%-.64s' (Fehler: %d)",
-"'%-.64s' ist für Änderungen gesperrt",
-"Sortiervorgang abgebrochen",
-"View '%-.64s' existiert für '%-.64s' nicht",
-"Fehler %d (Tabellenhandler)",
-"Diese Option gibt es nicht (Tabellenhandler)",
-"Kann Datensatz nicht finden",
-"Falsche Information in Datei '%-.64s'",
-"Falsche Schlüssel-Datei für Tabelle '%-.64s'. versuche zu reparieren",
-"Alte Schlüssel-Datei für Tabelle '%-.64s'. Bitte reparieren",
-"'%-.64s' ist nur lesbar",
-"Kein Speicher vorhanden (%d Bytes benötigt). Bitte Server neu starten",
-"Kein Speicher zum Sortieren vorhanden. sort_buffer_size sollte erhöht werden",
-"Unerwartetes Ende beim Lesen der Datei '%-.64s' (Fehler: %d)",
-"Zu viele Verbindungen",
-"Kein Speicher mehr vorhanden. Prüfen Sie, ob mysqld oder ein anderer Prozess allen Speicher verbraucht. Wenn nicht, sollten Sie mit 'ulimit' dafür sorgen, dass mysqld mehr Speicher benutzen darf, oder mehr Swap-Speicher einrichten",
-"Kann Hostnamen für diese Adresse nicht erhalten",
-"Schlechter Handshake",
-"Benutzer '%-.32s'@'%-.64s' hat keine Zugriffsberechtigung für Datenbank '%-.64s'",
-"Benutzer '%-.32s'@'%-.64s' hat keine Zugriffsberechtigung (verwendetes Passwort: %-.64s)",
-"Keine Datenbank ausgewählt",
-"Unbekannter Befehl",
-"Feld '%-.64s' darf nicht NULL sein",
-"Unbekannte Datenbank '%-.64s'",
-"Tabelle '%-.64s' bereits vorhanden",
-"Unbekannte Tabelle '%-.64s'",
-"Spalte '%-.64s' in %-.64s ist nicht eindeutig",
-"Der Server wird heruntergefahren",
-"Unbekanntes Tabellenfeld '%-.64s' in %-.64s",
-"'%-.64s' ist nicht in GROUP BY vorhanden",
-"Gruppierung über '%-.64s' nicht möglich",
-"Die Verwendung von Summierungsfunktionen und Spalten im selben Befehl ist nicht erlaubt",
-"Die Anzahl der Spalten entspricht nicht der Anzahl der Werte",
-"Name des Bezeichners '%-.64s' ist zu lang",
-"Doppelter Spaltenname vorhanden: '%-.64s'",
-"Doppelter Name für Schlüssel (Key) vorhanden: '%-.64s'",
-"Doppelter Eintrag '%-.64s' für Schlüssel %d",
-"Falsche Spaltenangaben für Spalte '%-.64s'",
-"%s bei '%-.80s' in Zeile %d",
-"Leere Abfrage",
-"Tabellenname/Alias '%-.64s' nicht eindeutig",
-"Fehlerhafter Vorgabewert (DEFAULT): '%-.64s'",
-"Mehrfacher Primärschlüssel (PRIMARY KEY) definiert",
-"Zu viele Schlüssel definiert. Maximal %d Schlüssel erlaubt",
-"Zu viele Teilschlüssel definiert. Maximal sind %d Teilschlüssel erlaubt",
-"Schlüssel ist zu lang. Die maximale Schlüssellänge beträgt %d",
-"In der Tabelle gibt es keine Schlüsselspalte '%-.64s'",
-"BLOB-Feld '%-.64s' kann beim verwendeten Tabellentyp nicht als Schlüssel verwendet werden",
-"Feldlänge für Feld '%-.64s' zu groß (maximal %d). BLOB-Feld verwenden!",
-"Falsche Tabellendefinition. Es darf nur ein Auto-Feld geben und dieses muss als Schlüssel definiert werden",
-"%-.64s: Bereit für Verbindungen",
-"%-.64s: Normal heruntergefahren\n",
-"%-.64s: Signal %d erhalten. Abbruch!\n",
-"%-.64s: Heruntergefahren (shutdown)\n",
-"%s: Thread %ld zwangsweise beendet. Benutzer: '%-.32s'\n",
-"Kann IP-Socket nicht erzeugen",
-"Tabelle '%-.64s' besitzt keinen wie den in CREATE INDEX verwendeten Index. Index neu anlegen",
-"Feldbegrenzer-Argument ist nicht in der erwarteten Form. Bitte im Handbuch nachlesen",
-"Eine feste Zeilenlänge kann für BLOB-Felder nicht verwendet werden. Bitte 'fields terminated by' verwenden",
-"Datei '%-.64s' muss im Datenbank-Verzeichnis vorhanden und lesbar für alle sein",
-"Datei '%-.64s' bereits vorhanden",
-"Datensätze: %ld Gelöscht: %ld Ausgelassen: %ld Warnungen: %ld",
-"Datensätze: %ld Duplikate: %ld",
-"Falscher Unterteilschlüssel. Der verwendete Schlüsselteil ist entweder kein String, die verwendete Länge ist länger als der Teilschlüssel oder der Tabellenhandler unterstützt keine Unterteilschlüssel",
-"Mit ALTER TABLE können nicht alle Felder auf einmal gelöscht werden. Dafür DROP TABLE verwenden",
-"Kann '%-.64s' nicht löschen. Existiert das Feld / der Schlüssel?",
-"Datensätze: %ld Duplikate: %ld Warnungen: %ld",
-"Die Verwendung der zu aktualisierenden Zieltabelle '%-.64s' ist in der FROM-Klausel nicht zulässig.",
-"Unbekannte Thread-ID: %lu",
-"Sie sind nicht Eigentümer von Thread %lu",
-"Keine Tabellen verwendet",
-"Zu viele Strings für SET-Spalte %-.64s angegeben",
-"Kann keinen eindeutigen Dateinamen für die Logdatei %-.64s erzeugen (1-999)\n",
-"Tabelle '%-.64s' ist mit Lesesperre versehen und kann nicht aktualisiert werden",
-"Tabelle '%-.64s' wurde nicht mit LOCK TABLES gesperrt",
-"BLOB-Feld '%-.64s' darf keinen Vorgabewert (DEFAULT) haben",
-"Unerlaubter Datenbankname '%-.64s'",
-"Unerlaubter Tabellenname '%-.64s'",
-"Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange dauern. Bitte WHERE-Klausel überprüfen oder gegebenenfalls SET SQL_BIG_SELECTS=1 oder SET SQL_MAX_JOIN_SIZE=# verwenden",
-"Unbekannter Fehler",
-"Unbekannte Prozedur '%-.64s'",
-"Falsche Parameterzahl für Prozedur '%-.64s'",
-"Falsche Parameter für Prozedur '%-.64s'",
-"Unbekannte Tabelle '%-.64s' in '%-.64s'",
-"Feld '%-.64s' wurde zweimal angegeben",
-"Falsche Verwendung einer Gruppierungsfunktion",
-"Tabelle '%-.64s' verwendet eine Extension, die in dieser MySQL-Version nicht verfügbar ist",
-"Eine Tabelle muß mindestens 1 Spalte besitzen",
-"Tabelle '%-.64s' ist voll",
-"Unbekannter Zeichensatz: '%-.64s'",
-"Zu viele Tabellen. MySQL kann in einem Join maximal %d Tabellen verwenden",
-"Zu viele Spalten",
-"Zeilenlänge zu groß. Die maximale Spaltenlänge für den verwendeten Tabellentyp (ohne BLOB-Felder) beträgt %d. Einige Felder müssen in BLOB oder TEXT umgewandelt werden",
-"Thread-Stack-Überlauf. Benutzt: %ld von %ld Stack. 'mysqld -O thread_stack=#' verwenen, um notfalls einen größeren Stack anzulegen",
-"OUTER JOIN enthält fehlerhafte Abhängigkeiten. In ON verwendete Bedingungen überprüfen",
-"Spalte '%-.64s' wurde mit UNIQUE oder INDEX benutzt, ist aber nicht als NOT NULL definiert",
-"Kann Funktion '%-.64s' nicht laden",
-"Kann Funktion '%-.64s' nicht initialisieren: %-.80s",
-"Keine Pfade gestattet für Shared Library",
-"Funktion '%-.64s' existiert schon",
-"Kann Shared Library '%-.64s' nicht öffnen (Fehler: %d %-.64s)",
-"Kann Funktion '%-.64s' in der Library nicht finden",
-"Funktion '%-.64s' ist nicht definiert",
-"Host '%-.64s' blockiert wegen zu vieler Verbindungsfehler. Aufheben der Blockierung mit 'mysqladmin flush-hosts'",
-"Host '%-.64s' hat keine Berechtigung, sich mit diesem MySQL-Server zu verbinden",
-"Sie benutzen MySQL als anonymer Benutzer und dürfen daher keine Passwörter ändern",
-"Sie benötigen die Berechtigung zum Aktualisieren von Tabellen in der Datenbank 'mysql', um die Passwörter anderer Benutzer ändern zu können",
-"Kann keinen passenden Datensatz in Tabelle 'user' finden",
-"Datensätze gefunden: %ld Geändert: %ld Warnungen: %ld",
-"Kann keinen neuen Thread erzeugen (Fehler: %d). Sollte noch Speicher verfügbar sein, bitte im Handbuch wegen möglicher Fehler im Betriebssystem nachschlagen",
-"Anzahl der Spalten stimmt nicht mit der Anzahl der Werte in Zeile %ld überein",
-"Kann Tabelle'%-.64s' nicht erneut öffnen",
-"Unerlaubte Verwendung eines NULL-Werts",
-"regexp lieferte Fehler '%-.64s'",
-"Das Vermischen von GROUP-Spalten (MIN(),MAX(),COUNT()...) mit Nicht-GROUP-Spalten ist nicht zulässig, wenn keine GROUP BY-Klausel vorhanden ist",
-"Für Benutzer '%-.32s' auf Host '%-.64s' gibt es keine solche Berechtigung",
-"%-.16s Befehl nicht erlaubt für Benutzer '%-.32s'@'%-.64s' und für Tabelle '%-.64s'",
-"%-.16s Befehl nicht erlaubt für Benutzer '%-.32s'@'%-.64s' und Spalte '%-.64s' in Tabelle '%-.64s'",
-"Unzulässiger GRANT- oder REVOKE-Befehl. Verfügbare Berechtigungen sind im Handbuch aufgeführt",
-"Das Host- oder User-Argument für GRANT ist zu lang",
-"Tabelle '%-.64s.%-.64s' existiert nicht",
-"Keine solche Berechtigung für User '%-.32s' auf Host '%-.64s' an Tabelle '%-.64s'",
-"Der verwendete Befehl ist in dieser MySQL-Version nicht zulässig",
-"Fehler in der SQL-Syntax. Bitte die korrekte Syntax im Handbuch nachschlagen (diese kann für verschiedene Server-Versionen unterschiedlich sein)",
-"Verzögerter (DELAYED) Einfüge-Thread konnte die angeforderte Sperre für Tabelle '%-.64s' nicht erhalten",
-"Zu viele verzögerte (DELAYED) Threads in Verwendung",
-"Abbruch der Verbindung %ld zur Datenbank '%-.64s'. Benutzer: '%-.64s' (%-.64s)",
-"Empfangenes Paket ist größer als 'max_allowed_packet'",
-"Lese-Fehler bei einer Kommunikations-Pipe",
-"fcntl() lieferte einen Fehler",
-"Pakete nicht in der richtigen Reihenfolge empfangen",
-"Kommunikationspaket lässt sich nicht entpacken",
-"Fehler beim Lesen eines Kommunikationspakets",
-"Zeitüberschreitung beim Lesen eines Kommunikationspakets",
-"Fehler beim Schreiben eines Kommunikationspakets",
-"Zeitüberschreitung beim Schreiben eines Kommunikationspakets",
-"Ergebnis ist länger als 'max_allowed_packet'",
-"Der verwendete Tabellentyp unterstützt keine BLOB- und TEXT-Spalten",
-"Der verwendete Tabellentyp unterstützt keine AUTO_INCREMENT-Spalten",
-"INSERT DELAYED kann nicht auf Tabelle '%-.64s' angewendet werden, da diese mit LOCK TABLES gesperrt ist",
-"Falscher Spaltenname '%-.100s'",
-"Der verwendete Tabellen-Handler kann die Spalte '%-.64s' nicht indizieren",
-"Nicht alle Tabellen in der MERGE-Tabelle sind gleich definiert",
-"Schreiben in Tabelle '%-.64s' nicht möglich wegen einer eindeutigen Beschränkung (unique constraint)",
-"BLOB- oder TEXT-Spalte '%-.64s' wird in der Schlüsseldefinition ohne Schlüssellängenangabe verwendet",
-"Alle Teile eines PRIMARY KEY müssen als NOT NULL definiert sein. Wenn NULL in einem Schlüssel verwendet wird, muss ein UNIQUE-Schlüssel verwendet werden",
-"Ergebnis besteht aus mehr als einer Zeile",
-"Dieser Tabellentyp benötigt einen PRIMARY KEY",
-"Diese MySQL-Version ist nicht mit RAID-Unterstützung kompiliert",
-"MySQL läuft im sicheren Aktualisierungsmodus (safe update mode). Sie haben versucht, eine Tabelle zu aktualisieren, ohne in der WHERE-Klausel eine KEY-Spalte anzugeben",
-"Schlüssel '%-.64s' existiert in der Tabelle '%-.64s' nicht",
-"Kann Tabelle nicht öffnen",
-"Die Speicher-Engine für diese Tabelle unterstützt kein %s",
-"Sie dürfen diesen Befehl nicht in einer Transaktion ausführen",
-"Fehler %d beim COMMIT",
-"Fehler %d beim ROLLBACK",
-"Fehler %d bei FLUSH_LOGS",
-"Fehler %d bei CHECKPOINT",
-"Verbindungsabbruch %ld zur Datenbank '%-.64s'. Benutzer: '%-.32s', Host: `%-.64s' (%-.64s)",
-"Die Speicher-Engine für die Tabelle unterstützt keinen binären Tabellen-Dump",
-"Binlog geschlossen. Kann RESET MASTER nicht ausführen",
-"Neuerstellung des Indizes der Dump-Tabelle '%-.64s' fehlgeschlagen",
-"Fehler vom Master: '%-.64s'",
-"Netzfehler beim Lesen vom Master",
-"Netzfehler beim Schreiben zum Master",
-"Kann keinen FULLTEXT-Index finden, der der Spaltenliste entspricht",
-"Kann den angegebenen Befehl wegen einer aktiven Tabellensperre oder einer aktiven Transaktion nicht ausführen",
-"Unbekannte Systemvariable '%-.64s'",
-"Tabelle '%-.64s' ist als defekt markiert und sollte repariert werden",
-"Tabelle '%-.64s' ist als defekt markiert und der letzte (automatische?) Reparaturversuch schlug fehl",
-"Änderungen an einigen nicht transaktionalen Tabellen konnten nicht zurückgerollt werden",
-"Transaktionen, die aus mehreren Befehlen bestehen, benötigen mehr als 'max_binlog_cache_size' Bytes an Speicher. Diese mysqld-Variable bitte vergrössern und erneut versuchen",
-"Diese Operation kann nicht bei einem aktiven Slave durchgeführt werden. Bitte zuerst STOP SLAVE ausführen",
-"Diese Operation benötigt einen aktiven Slave. Bitte Slave konfigurieren und mittels START SLAVE aktivieren",
-"Der Server ist nicht als Slave konfiguriert. Bitte in der Konfigurationsdatei oder mittels CHANGE MASTER TO beheben",
-"Could not initialize master info structure, more error messages can be found in the MySQL error log",
-"Konnte keinen Slave-Thread starten. Bitte System-Ressourcen überprüfen",
-"Benutzer '%-.64s' hat mehr als max_user_connections aktive Verbindungen",
-"Bei SET dürfen nur konstante Ausdrücke verwendet werden",
-"Beim Warten auf eine Sperre wurde die zulässige Wartezeit überschritten. Bitte versuchen Sie, die Transaktion neu zu starten",
-"Die Gesamtzahl der Sperren überschreitet die Größe der Sperrtabelle",
-"Während einer READ UNCOMMITED-Transaktion können keine UPDATE-Sperren angefordert werden",
-"DROP DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält",
-"CREATE DATABASE ist nicht erlaubt, solange der Thread eine globale Lesesperre hält",
-"Falsche Argumente für %s",
-"'%-.32s'@'%-.64s' is nicht berechtigt, neue Benutzer hinzuzufügen",
-"Falsche Tabellendefinition. Alle MERGE-Tabellen müssen sich in derselben Datenbank befinden",
-"Beim Versuch, eine Sperre anzufordern, ist ein Deadlock aufgetreten. Versuchen Sie, die Transaktion erneut zu starten",
-"Der verwendete Tabellentyp unterstützt keine FULLTEXT-Indizes",
-"Fremdschlüssel-Beschränkung konnte nicht hinzugefügt werden",
-"Hinzufügen eines Kind-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl",
-"Löschen eines Eltern-Datensatzes schlug aufgrund einer Fremdschlüssel-Beschränkung fehl",
-"Fehler bei der Verbindung zum Master: %-.128s",
-"Beim Ausführen einer Abfrage auf dem Master trat ein Fehler auf: %-.128s",
-"Fehler beim Ausführen des Befehls %s: %-.128s",
-"Falsche Verwendung von %s und %s",
-"Die verwendeten SELECT-Befehle liefern eine unterschiedliche Anzahl von Spalten zurück",
-"Augrund eines READ LOCK-Konflikts kann die Abfrage nicht ausgeführt werden",
-"Die gleichzeitige Verwendung von Tabellen mit und ohne Transaktionsunterstützung ist deaktiviert",
-"Option '%s' wird im Befehl zweimal verwendet",
-"Benutzer '%-.64s' hat die Ressourcenbeschränkung '%s' überschritten (aktueller Wert: %ld)",
-"Befehl nicht zulässig. Hierfür wird die Berechtigung %-.128s benötigt",
-"Variable '%-.64s' ist eine lokale Variable und kann nicht mit SET GLOBAL verändert werden",
-"Variable '%-.64s' ist eine globale Variable und muss mit SET GLOBAL verändert werden",
-"Variable '%-.64s' hat keinen Vorgabewert",
-"Variable '%-.64s' kann nicht auf '%-.64s' gesetzt werden",
-"Falscher Argumenttyp für Variable '%-.64s'",
-"Variable '%-.64s' kann nur verändert, nicht gelesen werden",
-"Falsche Verwendung oder Platzierung von '%s'",
-"Diese MySQL-Version unterstützt '%s' nicht",
-"Schwerer Fehler %d: '%-.128s vom Master beim Lesen des binären Logs aufgetreten",
-"Slave-SQL-Thread hat die Abfrage aufgrund von replicate-*-table-Regeln ignoriert",
-"Variable '%-.64s' is a %s variable",
-"Falsche Fremdschlüssel-Definition für '%-64s': %s",
-"Schlüssel- und Tabellenverweis passen nicht zusammen",
-"Operand solle %d Spalte(n) enthalten",
-"Unterabfrage lieferte mehr als einen Datensatz zurück",
-"Unbekannter Prepared-Statement-Handler (%.*s) für %s angegeben",
-"Die Hilfe-Datenbank ist beschädigt oder existiert nicht",
-"Zyklischer Verweis in Unterabfragen",
-"Spalte '%s' wird von %s nach %s umgewandelt",
-"Verweis '%-.64s' wird nicht unterstützt (%s)",
-"Für jede abgeleitete Tabelle muss ein eigener Alias angegeben werden",
-"Select %u wurde während der Optimierung reduziert",
-"Tabelle '%-.64s', die in einem der SELECT-Befehle verwendet wurde, kann nicht in %-.32s verwendet werden",
-"Client unterstützt das vom Server erwartete Authentifizierungsprotokoll nicht. Bitte aktualisieren Sie Ihren MySQL-Client",
-"Alle Teile eines SPATIAL KEY müssen als NOT NULL deklariert sein",
-"COLLATION '%s' ist für CHARACTER SET '%s' ungültig",
-"Slave läuft bereits",
-"Slave wurde bereits angehalten",
-"Unkomprimierte Daten sind zu groß. Die maximale Größe beträgt %d",
-"ZLIB: Steht nicht genug Speicher zur Verfügung",
-"ZLIB: Im Ausgabepuffer ist nicht genug Platz vorhanden (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)",
-"ZLIB: Eingabedaten beschädigt",
-"%d Zeile(n) durch GROUP_CONCAT() abgeschnitten",
-"Anzahl der Datensätze in Zeile %ld geringer als Anzahl der Spalten",
-"Anzahl der Datensätze in Zeile %ld größer als Anzahl der Spalten",
-"Daten abgeschnitten, NULL für NOT NULL-Spalte '%s' in Zeile %ld angegeben",
-"Daten abgeschnitten, außerhalb des Wertebereichs für Spalte '%s' in Zeile %ld",
-"Daten abgeschnitten für Spalte '%s' in Zeile %ld",
-"Für Tabelle '%s' wird Speicher-Engine %s benutzt",
-"Unerlaubte Vermischung der Kollationen (%s,%s) und (%s,%s) für die Operation '%s'",
-"Kann einen oder mehrere der angegebenen Benutzer nicht löschen",
-"Kann nicht alle Berechtigungen widerrufen, grant for one or more of the requested users",
-"Unerlaubte Vermischung der Kollationen (%s,%s), (%s,%s), (%s,%s) für die Operation '%s'",
-"Unerlaubte Vermischung der Kollationen für die Operation '%s'",
-"Variable '%-.64s' ist keine Variablen-Komponenten (kann nicht als XXXX.variablen_name verwendet werden)",
-"Unbekannte Kollation: '%-.64s'",
-"SSL-Parameter in CHANGE MASTER werden ignoriert, weil dieser MySQL-Slave ohne SSL-Unterstützung kompiliert wurde. Sie können aber später verwendet werden, wenn der MySQL-Slave mit SSL gestartet wird",
-"Server läuft im Modus --secure-auth, aber '%s'@'%s' hat ein Passwort im alten Format. Bitte Passwort ins neue Format ändern",
-"Feld oder Verweis '%-.64s%s%-.64s%s%-.64s' im SELECT-Befehl Nr. %d wurde im SELECT-Befehl Nr. %d aufgelöst",
-"Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL",
-"Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn der Slave-Server unerwartet neu startet",
-"SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
deleted file mode 100644
index 87168431595..00000000000
--- a/sql/share/greek/errmsg.txt
+++ /dev/null
@@ -1,321 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-character-set=greek
-
-"hashchk",
-"isamchk",
-"Ï×É",
-"ÍÁÉ",
-"Áäýíáôç ç äçìéïõñãßá ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Áäýíáôç ç äçìéïõñãßá ôïõ ðßíáêá '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s'; Ç âÜóç äåäïìÝíùí õðÜñ÷åé Þäç",
-"Áäýíáôç ç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí '%-.64s'. Ç âÜóç äåäïìÝíùí äåí õðÜñ÷åé",
-"ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ '%-.64s', êùäéêüò ëÜèïõò: %d)",
-"ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ ôïõ öáêÝëëïõ '%-.64s', êùäéêüò ëÜèïõò: %d)",
-"ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Áäýíáôç ç áíÜãíùóç åããñáöÞò áðü ðßíáêá ôïõ óõóôÞìáôïò",
-"Áäýíáôç ç ëÞøç ðëçñïöïñéþí ãéá ôçí êáôÜóôáóç ôïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Ï öÜêåëëïò åñãáóßáò äåí âñÝèçêå (êùäéêüò ëÜèïõò: %d)",
-"Ôï áñ÷åßï äåí ìðïñåß íá êëåéäùèåß (êùäéêüò ëÜèïõò: %d)",
-"Äåí åßíáé äõíáôü íá áíïé÷ôåß ôï áñ÷åßï: '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Äåí âñÝèçêå ôï áñ÷åßï: '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Äåí åßíáé äõíáôü íá äéáâáóôåß ï öÜêåëëïò ôïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Áäýíáôç ç áëëáãÞ ôïõ ôñÝ÷ïíôïò êáôáëüãïõ óå '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Ç åããñáöÞ Ý÷åé áëëÜîåé áðü ôçí ôåëåõôáßá öïñÜ ðïõ áíáóýñèçêå áðü ôïí ðßíáêá '%-.64s'",
-"Äåí õðÜñ÷åé ÷þñïò óôï äßóêï (%s). Ðáñáêáëþ, ðåñéìÝíåôå íá åëåõèåñùèåß ÷þñïò...",
-"Äåí åßíáé äõíáôÞ ç êáôá÷þñçóç, ç ôéìÞ õðÜñ÷åé Þäç óôïí ðßíáêá '%-.64s'",
-"ÐáñïõóéÜóôçêå ðñüâëçìá êëåßíïíôáò ôï '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Ðñüâëçìá êáôÜ ôçí áíÜãíùóç ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Ðñüâëçìá êáôÜ ôçí ìåôïíïìáóßá ôïõ áñ÷åßïõ '%-.64s' to '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"Ðñüâëçìá êáôÜ ôçí áðïèÞêåõóç ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"'%-.64s' äåí åðéôñÝðïíôáé áëëáãÝò",
-"Ç äéáäéêáóßá ôáîéíüìéóçò áêõñþèçêå",
-"Ôï View '%-.64s' äåí õðÜñ÷åé ãéá '%-.64s'",
-"ÅëÞöèç ìÞíõìá ëÜèïõò %d áðü ôïí ÷åéñéóôÞ ðßíáêá (table handler)",
-"Ï ÷åéñéóôÞò ðßíáêá (table handler) ãéá '%-.64s' äåí äéáèÝôåé áõôÞ ôçí åðéëïãÞ",
-"Áäýíáôç ç áíåýñåóç åããñáöÞò óôï '%-.64s'",
-"ËÜèïò ðëçñïöïñßåò óôï áñ÷åßï: '%-.64s'",
-"ËÜèïò áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá: '%-.64s'; Ðáñáêáëþ, äéïñèþóôå ôï!",
-"Ðáëáéü áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá '%-.64s'; Ðáñáêáëþ, äéïñèþóôå ôï!",
-"'%-.64s' åðéôñÝðåôáé ìüíï ç áíÜãíùóç",
-"Äåí õðÜñ÷åé äéáèÝóéìç ìíÞìç. ÐñïóðáèÞóôå ðÜëé, åðáíåêéíþíôáò ôç äéáäéêáóßá (demon) (÷ñåéÜæïíôáé %d bytes)",
-"Äåí õðÜñ÷åé äéáèÝóéìç ìíÞìç ãéá ôáîéíüìéóç. ÁõîÞóôå ôï sort buffer size ãéá ôç äéáäéêáóßá (demon)",
-"ÊáôÜ ôç äéÜñêåéá ôçò áíÜãíùóçò, âñÝèçêå áðñïóäüêçôá ôï ôÝëïò ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)",
-"ÕðÜñ÷ïõí ðïëëÝò óõíäÝóåéò...",
-"Ðñüâëçìá ìå ôç äéáèÝóéìç ìíÞìç (Out of thread space/memory)",
-"Äåí Ýãéíå ãíùóôü ôï hostname ãéá ôçí address óáò",
-"Ç áíáãíþñéóç (handshake) äåí Ýãéíå óùóôÜ",
-"Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s'@'%-.64s' óôç âÜóç äåäïìÝíùí '%-.64s'",
-"Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s'@'%-.64s' (÷ñÞóç password: %s)",
-"Äåí åðéëÝ÷èçêå âÜóç äåäïìÝíùí",
-"Áãíùóôç åíôïëÞ",
-"Ôï ðåäßï '%-.64s' äåí ìðïñåß íá åßíáé êåíü (null)",
-"Áãíùóôç âÜóç äåäïìÝíùí '%-.64s'",
-"Ï ðßíáêáò '%-.64s' õðÜñ÷åé Þäç",
-"Áãíùóôïò ðßíáêáò '%-.64s'",
-"Ôï ðåäßï: '%-.64s' óå %-.64s äåí Ý÷åé êáèïñéóôåß",
-"Åíáñîç äéáäéêáóßáò áðïóýíäåóçò ôïõ åîõðçñåôçôÞ (server shutdown)",
-"Áãíùóôï ðåäßï '%-.64s' óå '%-.64s'",
-"×ñçóéìïðïéÞèçêå '%-.64s' ðïõ äåí õðÞñ÷å óôï group by",
-"Áäýíáôç ç ïìáäïðïßçóç (group on) '%-.64s'",
-"Ç äéáôýðùóç ðåñéÝ÷åé sum functions êáé columns óôçí ßäéá äéáôýðùóç",
-"Ôï Column count äåí ôáéñéÜæåé ìå ôï value count",
-"Ôï identifier name '%-.100s' åßíáé ðïëý ìåãÜëï",
-"ÅðáíÜëçøç column name '%-.64s'",
-"ÅðáíÜëçøç key name '%-.64s'",
-"ÄéðëÞ åããñáöÞ '%-.64s' ãéá ôï êëåéäß %d",
-"ÅóöáëìÝíï column specifier ãéá ôï ðåäßï '%-.64s'",
-"%s ðëçóßïí '%-.80s' óôç ãñáììÞ %d",
-"Ôï åñþôçìá (query) ðïõ èÝóáôå Þôáí êåíü",
-"Áäýíáôç ç áíåýñåóç unique table/alias: '%-.64s'",
-"ÅóöáëìÝíç ðñïêáèïñéóìÝíç ôéìÞ (default value) ãéá '%-.64s'",
-"Ðåñéóóüôåñá áðü Ýíá primary key ïñßóôçêáí",
-"ÐÜñá ðïëëÜ key ïñßóèçêáí. Ôï ðïëý %d åðéôñÝðïíôáé",
-"ÐÜñá ðïëëÜ key parts ïñßóèçêáí. Ôï ðïëý %d åðéôñÝðïíôáé",
-"Ôï êëåéäß ðïõ ïñßóèçêå åßíáé ðïëý ìåãÜëï. Ôï ìÝãéóôï ìÞêïò åßíáé %d",
-"Ôï ðåäßï êëåéäß '%-.64s' äåí õðÜñ÷åé óôïí ðßíáêá",
-"Ðåäßï ôýðïõ Blob '%-.64s' äåí ìðïñåß íá ÷ñçóéìïðïéçèåß óôïí ïñéóìü åíüò êëåéäéïý (key specification)",
-"Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.64s' (max = %d). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB",
-"Ìðïñåß íá õðÜñ÷åé ìüíï Ýíá auto field êáé ðñÝðåé íá Ý÷åé ïñéóèåß óáí key",
-"%s: óå áíáìïíÞ óõíäÝóåùí",
-"%s: ÖõóéïëïãéêÞ äéáäéêáóßá shutdown\n",
-"%s: ÅëÞöèç ôï ìÞíõìá %d. Ç äéáäéêáóßá åãêáôáëåßðåôáé!\n",
-"%s: Ç äéáäéêáóßá Shutdown ïëïêëçñþèçêå\n",
-"%s: Ôï thread èá êëåßóåé %ld user: '%-.64s'\n",
-"Äåí åßíáé äõíáôÞ ç äçìéïõñãßá IP socket",
-"Ï ðßíáêáò '%-.64s' äåí Ý÷åé åõñåôÞñéï (index) óáí áõôü ðïõ ÷ñçóéìïðïéåßôå óôçí CREATE INDEX. Ðáñáêáëþ, îáíáäçìéïõñãÞóôå ôïí ðßíáêá",
-"Ï äéá÷ùñéóôÞò ðåäßùí äåí åßíáé áõôüò ðïõ áíáìåíüôáí. Ðáñáêáëþ áíáôñÝîôå óôï manual",
-"Äåí ìðïñåßôå íá ÷ñçóéìïðïéÞóåôå fixed rowlength óå BLOBs. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå 'fields terminated by'.",
-"Ôï áñ÷åßï '%-.64s' ðñÝðåé íá õðÜñ÷åé óôï database directory Þ íá ìðïñåß íá äéáâáóôåß áðü üëïõò",
-"Ôï áñ÷åßï '%-.64s' õðÜñ÷åé Þäç",
-"ÅããñáöÝò: %ld ÄéáãñáöÝò: %ld ÐáñåêÜìöèçóáí: %ld ÐñïåéäïðïéÞóåéò: %ld",
-"ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld",
-"ÅóöáëìÝíï sub part key. Ôï ÷ñçóéìïðïéïýìåíï key part äåí åßíáé string Þ ôï ìÞêïò ôïõ åßíáé ìåãáëýôåñï",
-"Äåí åßíáé äõíáôÞ ç äéáãñáöÞ üëùí ôùí ðåäßùí ìå ALTER TABLE. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå DROP TABLE",
-"Áäýíáôç ç äéáãñáöÞ (DROP) '%-.64s'. Ðáñáêáëþ åëÝãîôå áí ôï ðåäßï/êëåéäß õðÜñ÷åé",
-"ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld ÐñïåéäïðïéÞóåéò: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Áãíùóôï thread id: %lu",
-"Äåí åßóèå owner ôïõ thread %lu",
-"Äåí ÷ñçóéìïðïéÞèçêáí ðßíáêåò",
-"ÐÜñá ðïëëÜ strings ãéá ôï ðåäßï %-.64s êáé SET",
-"Áäýíáôç ç äçìéïõñãßá unique log-filename %-.64s.(1-999)\n",
-"Ï ðßíáêáò '%-.64s' Ý÷åé êëåéäùèåß ìå READ lock êáé äåí åðéôñÝðïíôáé áëëáãÝò",
-"Ï ðßíáêáò '%-.64s' äåí Ý÷åé êëåéäùèåß ìå LOCK TABLES",
-"Ôá Blob ðåäßá '%-.64s' äåí ìðïñïýí íá Ý÷ïõí ðñïêáèïñéóìÝíåò ôéìÝò (default value)",
-"ËÜèïò üíïìá âÜóçò äåäïìÝíùí '%-.100s'",
-"ËÜèïò üíïìá ðßíáêá '%-.100s'",
-"Ôï SELECT èá åîåôÜóåé ìåãÜëï áñéèìü åããñáöþí êáé ðéèáíþò èá êáèõóôåñÞóåé. Ðáñáêáëþ åîåôÜóôå ôéò ðáñáìÝôñïõò ôïõ WHERE êáé ÷ñçóéìïðïéåßóôå SET SQL_BIG_SELECTS=1 áí ôï SELECT åßíáé óùóôü",
-"ÐñïÝêõøå Üãíùóôï ëÜèïò",
-"Áãíùóôç äéáäéêáóßá '%-.64s'",
-"ËÜèïò áñéèìüò ðáñáìÝôñùí óôç äéáäéêáóßá '%-.64s'",
-"ËÜèïò ðáñÜìåôñïé óôçí äéáäéêáóßá '%-.64s'",
-"Áãíùóôïò ðßíáêáò '%-.64s' óå %s",
-"Ôï ðåäßï '%-.64s' Ý÷åé ïñéóèåß äýï öïñÝò",
-"ÅóöáëìÝíç ÷ñÞóç ôçò group function",
-"Ï ðßíáêò '%-.64s' ÷ñçóéìïðïéåß êÜðïéï extension ðïõ äåí õðÜñ÷åé óôçí Ýêäïóç áõôÞ ôçò MySQL",
-"Åíáò ðßíáêáò ðñÝðåé íá Ý÷åé ôïõëÜ÷éóôïí Ýíá ðåäßï",
-"Ï ðßíáêáò '%-.64s' åßíáé ãåìÜôïò",
-"Áãíùóôï character set: '%-.64s'",
-"Ðïëý ìåãÜëïò áñéèìüò ðéíÜêùí. Ç MySQL ìðïñåß íá ÷ñçóéìïðïéÞóåé %d ðßíáêåò óå äéáäéêáóßá join",
-"Ðïëý ìåãÜëïò áñéèìüò ðåäßùí",
-"Ðïëý ìåãÜëï ìÝãåèïò åããñáöÞò. Ôï ìÝãéóôï ìÝãåèïò åããñáöÞò, ÷ùñßò íá õðïëïãßæïíôáé ôá blobs, åßíáé %d. ÐñÝðåé íá ïñßóåôå êÜðïéá ðåäßá óáí blobs",
-"Stack overrun óôï thread: Used: %ld of a %ld stack. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå 'mysqld -O thread_stack=#' ãéá íá ïñßóåôå Ýíá ìåãáëýôåñï stack áí ÷ñåéÜæåôáé",
-"Cross dependency âñÝèçêå óå OUTER JOIN. Ðáñáêáëþ åîåôÜóôå ôéò óõíèÞêåò ðïõ èÝóáôå óôï ON",
-"Ôï ðåäßï '%-.64s' ÷ñçóéìïðïéåßôáé óáí UNIQUE Þ INDEX áëëÜ äåí Ý÷åé ïñéóèåß óáí NOT NULL",
-"Äåí åßíáé äõíáôÞ ç äéáäéêáóßá load ãéá ôç óõíÜñôçóç '%-.64s'",
-"Äåí åßíáé äõíáôÞ ç Ýíáñîç ôçò óõíÜñôçóçò '%-.64s'; %-.80s",
-"Äåí âñÝèçêáí paths ãéá ôçí shared library",
-"Ç óõíÜñôçóç '%-.64s' õðÜñ÷åé Þäç",
-"Äåí åßíáé äõíáôÞ ç áíÜãíùóç ôçò shared library '%-.64s' (êùäéêüò ëÜèïõò: %d %s)",
-"Äåí åßíáé äõíáôÞ ç áíåýñåóç ôçò óõíÜñôçóçò '%-.64s' óôçí âéâëéïèÞêç'",
-"Ç óõíÜñôçóç '%-.64s' äåí Ý÷åé ïñéóèåß",
-"Ï õðïëïãéóôÞò Ý÷åé áðïêëåéóèåß ëüãù ðïëëáðëþí ëáèþí óýíäåóçò. ÐñïóðáèÞóôå íá äéïñþóåôå ìå 'mysqladmin flush-hosts'",
-"Ï õðïëïãéóôÞò äåí Ý÷åé äéêáßùìá óýíäåóçò ìå ôïí MySQL server",
-"×ñçóéìïðïéåßôå ôçí MySQL óáí anonymous user êáé Ýôóé äåí ìðïñåßôå íá áëëÜîåôå ôá passwords Üëëùí ÷ñçóôþí",
-"ÐñÝðåé íá Ý÷åôå äéêáßùìá äéüñèùóçò ðéíÜêùí (update) óôç âÜóç äåäïìÝíùí mysql ãéá íá ìðïñåßôå íá áëëÜîåôå ôá passwords Üëëùí ÷ñçóôþí",
-"Äåí åßíáé äõíáôÞ ç áíåýñåóç ôçò áíôßóôïé÷çò åããñáöÞò óôïí ðßíáêá ôùí ÷ñçóôþí",
-"Rows matched: %ld Changed: %ld Warnings: %ld",
-"Can't create a new thread (errno %d); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug",
-"Column count doesn't match value count at row %ld",
-"Can't reopen table: '%-.64s'",
-"Invalid use of NULL value",
-"Got error '%-.64s' from regexp",
-"Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause",
-"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for table '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
-"Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used.",
-"The host or user argument to GRANT is too long",
-"Table '%-.64s.%-.64s' doesn't exist",
-"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
-"The used command is not allowed with this MySQL version",
-"You have an error in your SQL syntax",
-"Delayed insert thread couldn't get requested lock for table %-.64s",
-"Too many delayed threads in use",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' (%-.64s)",
-"Got a packet bigger than 'max_allowed_packet' bytes",
-"Got a read error from the connection pipe",
-"Got an error from fcntl()",
-"Got packets out of order",
-"Couldn't uncompress communication packet",
-"Got an error reading communication packets",
-"Got timeout reading communication packets",
-"Got an error writing communication packets",
-"Got timeout writing communication packets",
-"Result string is longer than 'max_allowed_packet' bytes",
-"The used table type doesn't support BLOB/TEXT columns",
-"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
-"Incorrect column name '%-.100s'",
-"The used table handler can't index column '%-.64s'",
-"All tables in the MERGE table are not identically defined",
-"Can't write, because of unique constraint, to table '%-.64s'",
-"BLOB column '%-.64s' used in key specification without a key length",
-"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
-"This table type requires a primary key",
-"This version of MySQL is not compiled with RAID support",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
deleted file mode 100644
index af10c33ee2d..00000000000
--- a/sql/share/hungarian/errmsg.txt
+++ /dev/null
@@ -1,326 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Translated by Feher Peter. Forditotta Feher Peter (feherp@mail.matav.hu) 1998
- Updated May, 2000
-*/
-
-character-set=latin2
-
-"hashchk",
-"isamchk",
-"NEM",
-"IGEN",
-"A '%-.64s' file nem hozhato letre (hibakod: %d)",
-"A '%-.64s' tabla nem hozhato letre (hibakod: %d)",
-"Az '%-.64s' adatbazis nem hozhato letre (hibakod: %d)",
-"Az '%-.64s' adatbazis nem hozhato letre Az adatbazis mar letezik",
-"A(z) '%-.64s' adatbazis nem szuntetheto meg. Az adatbazis nem letezik",
-"Adatbazis megszuntetesi hiba ('%-.64s' nem torolheto, hibakod: %d)",
-"Adatbazis megszuntetesi hiba ('%-.64s' nem szuntetheto meg, hibakod: %d)",
-"Torlesi hiba: '%-.64s' (hibakod: %d)",
-"Nem olvashato rekord a rendszertablaban",
-"A(z) '%-.64s' statusza nem allapithato meg (hibakod: %d)",
-"A munkakonyvtar nem allapithato meg (hibakod: %d)",
-"A file nem zarolhato. (hibakod: %d)",
-"A '%-.64s' file nem nyithato meg (hibakod: %d)",
-"A(z) '%-.64s' file nem talalhato (hibakod: %d)",
-"A(z) '%-.64s' konyvtar nem olvashato. (hibakod: %d)",
-"Konyvtarvaltas nem lehetseges a(z) '%-.64s'-ba. (hibakod: %d)",
-"A(z) '%-.64s' tablaban talalhato rekord megvaltozott az utolso olvasas ota",
-"A lemez megtelt (%s).",
-"Irasi hiba, duplikalt kulcs a '%-.64s' tablaban.",
-"Hiba a(z) '%-.64s' zarasakor. (hibakod: %d)",
-"Hiba a '%-.64s'file olvasasakor. (hibakod: %d)",
-"Hiba a '%-.64s' file atnevezesekor. (hibakod: %d)",
-"Hiba a '%-.64s' file irasakor. (hibakod: %d)",
-"'%-.64s' a valtoztatas ellen zarolva",
-"Sikertelen rendezes",
-"A(z) '%-.64s' nezet nem letezik a(z) '%-.64s'-hoz",
-"%d hibajelzes a tablakezelotol",
-"A(z) '%-.64s' tablakezelonek nincs ilyen opcioja",
-"Nem talalhato a rekord '%-.64s'-ben",
-"Ervenytelen info a file-ban: '%-.64s'",
-"Ervenytelen kulcsfile a tablahoz: '%-.64s'; probalja kijavitani!",
-"Regi kulcsfile a '%-.64s'tablahoz; probalja kijavitani!",
-"'%-.64s' irasvedett",
-"Nincs eleg memoria. Inditsa ujra a demont, es probalja ismet. (%d byte szukseges.)",
-"Nincs eleg memoria a rendezeshez. Novelje a rendezo demon puffermeretet",
-"Varatlan filevege-jel a '%-.64s'olvasasakor. (hibakod: %d)",
-"Tul sok kapcsolat",
-"Elfogyott a thread-memoria",
-"A gepnev nem allapithato meg a cimbol",
-"A kapcsolatfelvetel nem sikerult (Bad handshake)",
-"A(z) '%-.32s'@'%-.64s' felhasznalo szamara tiltott eleres az '%-.64s' adabazishoz.",
-"A(z) '%-.32s'@'%-.64s' felhasznalo szamara tiltott eleres. (Hasznalja a jelszot: %s)",
-"Nincs kivalasztott adatbazis",
-"Ervenytelen parancs",
-"A(z) '%-.64s' oszlop erteke nem lehet nulla",
-"Ervenytelen adatbazis: '%-.64s'",
-"A(z) '%-.64s' tabla mar letezik",
-"Ervenytelen tabla: '%-.64s'",
-"A(z) '%-.64s' oszlop %-.64s-ben ketertelmu",
-"A szerver leallitasa folyamatban",
-"A(z) '%-.64s' oszlop ervenytelen '%-.64s'-ben",
-"Used '%-.64s' with wasn't in group by",
-"A group nem hasznalhato: '%-.64s'",
-"Statement has sum functions and columns in same statement",
-"Az oszlopban levo ertek nem egyezik meg a szamitott ertekkel",
-"A(z) '%-.100s' azonositonev tul hosszu.",
-"Duplikalt oszlopazonosito: '%-.64s'",
-"Duplikalt kulcsazonosito: '%-.64s'",
-"Duplikalt bejegyzes '%-.64s' a %d kulcs szerint.",
-"Rossz oszlopazonosito: '%-.64s'",
-"A %s a '%-.80s'-hez kozeli a %d sorban",
-"Ures lekerdezes.",
-"Nem egyedi tabla/alias: '%-.64s'",
-"Ervenytelen ertek: '%-.64s'",
-"Tobbszoros elsodleges kulcs definialas.",
-"Tul sok kulcs. Maximum %d kulcs engedelyezett.",
-"Tul sok kulcsdarabot definialt. Maximum %d resz engedelyezett",
-"A megadott kulcs tul hosszu. Maximalis kulcshosszusag: %d",
-"A(z) '%-.64s'kulcsoszlop nem letezik a tablaban",
-"Blob objektum '%-.64s' nem hasznalhato kulcskent",
-"A(z) '%-.64s' oszlop tul hosszu. (maximum = %d). Hasznaljon BLOB tipust inkabb.",
-"Csak egy auto mezo lehetseges, es azt kulcskent kell definialni.",
-"%s: kapcsolatra kesz",
-"%s: Normal leallitas\n",
-"%s: %d jelzes. Megszakitva!\n",
-"%s: A leallitas kesz\n",
-"%s: A(z) %ld thread kenyszeritett zarasa. Felhasznalo: '%-.64s'\n",
-"Az IP socket nem hozhato letre",
-"A(z) '%-.64s' tablahoz nincs meg a CREATE INDEX altal hasznalt index. Alakitsa at a tablat",
-"A mezoelvalaszto argumentumok nem egyeznek meg a varttal. Nezze meg a kezikonyvben!",
-"Fix hosszusagu BLOB-ok nem hasznalhatok. Hasznalja a 'mezoelvalaszto jelet' .",
-"A(z) '%-.64s'-nak az adatbazis konyvtarban kell lennie, vagy mindenki szamara olvashatonak",
-"A '%-.64s' file mar letezik.",
-"Rekordok: %ld Torolve: %ld Skipped: %ld Warnings: %ld",
-"Rekordok: %ld Duplikalva: %ld",
-"Rossz alkulcs. A hasznalt kulcsresz nem karaktersorozat vagy hosszabb, mint a kulcsresz",
-"Az osszes mezo nem torolheto az ALTER TABLE-lel. Hasznalja a DROP TABLE-t helyette",
-"A DROP '%-.64s' nem lehetseges. Ellenorizze, hogy a mezo/kulcs letezik-e",
-"Rekordok: %ld Duplikalva: %ld Warnings: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Ervenytelen szal (thread) id: %lu",
-"A %lu thread-nek mas a tulajdonosa",
-"Nincs hasznalt tabla",
-"Tul sok karakter: %-.64s es SET",
-"Egyedi log-filenev nem generalhato: %-.64s.(1-999)\n",
-"A(z) '%-.64s' tabla zarolva lett (READ lock) es nem lehet frissiteni",
-"A(z) '%-.64s' tabla nincs zarolva a LOCK TABLES-szel",
-"A(z) '%-.64s' blob objektumnak nem lehet alapertelmezett erteke",
-"Hibas adatbazisnev: '%-.100s'",
-"Hibas tablanev: '%-.100s'",
-"A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET SQL_BIG_SELECTS=1 beallitast, ha a SELECT okay",
-"Ismeretlen hiba",
-"Ismeretlen eljaras: '%-.64s'",
-"Rossz parameter a(z) '%-.64s'eljaras szamitasanal",
-"Rossz parameter a(z) '%-.64s' eljarasban",
-"Ismeretlen tabla: '%-.64s' %s-ban",
-"A(z) '%-.64s' mezot ketszer definialta",
-"A group funkcio ervenytelen hasznalata",
-"A(z) '%-.64s' tabla olyan bovitest hasznal, amely nem letezik ebben a MySQL versioban.",
-"A tablanak legalabb egy oszlopot tartalmazni kell",
-"A '%-.64s' tabla megtelt",
-"Ervenytelen karakterkeszlet: '%-.64s'",
-"Tul sok tabla. A MySQL csak %d tablat tud kezelni osszefuzeskor",
-"Tul sok mezo",
-"Tul nagy sormeret. A maximalis sormeret (nem szamolva a blob objektumokat) %d. Nehany mezot meg kell valtoztatnia",
-"Thread verem tullepes: Used: %ld of a %ld stack. Hasznalja a 'mysqld -O thread_stack=#' nagyobb verem definialasahoz",
-"Keresztfuggoseg van az OUTER JOIN-ban. Ellenorizze az ON felteteleket",
-"A(z) '%-.64s' oszlop INDEX vagy UNIQUE (egyedi), de a definicioja szerint nem NOT NULL",
-"A(z) '%-.64s' fuggveny nem toltheto be",
-"A(z) '%-.64s' fuggveny nem inicializalhato; %-.80s",
-"Nincs ut a megosztott konyvtarakhoz (shared library)",
-"A '%-.64s' fuggveny mar letezik",
-"A(z) '%-.64s' megosztott konyvtar nem hasznalhato (hibakod: %d %s)",
-"A(z) '%-.64s' fuggveny nem talalhato a konyvtarban",
-"A '%-.64s' fuggveny nem definialt",
-"A '%-.64s' host blokkolodott, tul sok kapcsolodasi hiba miatt. Hasznalja a 'mysqladmin flush-hosts' parancsot",
-"A '%-.64s' host szamara nem engedelyezett a kapcsolodas ehhez a MySQL szerverhez",
-"Nevtelen (anonymous) felhasznalokent nem negedelyezett a jelszovaltoztatas",
-"Onnek tabla-update joggal kell rendelkeznie a mysql adatbazisban masok jelszavanak megvaltoztatasahoz",
-"Nincs megegyezo sor a user tablaban",
-"Megegyezo sorok szama: %ld Valtozott: %ld Warnings: %ld",
-"Uj thread letrehozasa nem lehetseges (Hibakod: %d). Amenyiben van meg szabad memoria, olvassa el a kezikonyv operacios rendszerfuggo hibalehetosegekrol szolo reszet",
-"Az oszlopban talalhato ertek nem egyezik meg a %ld sorban szamitott ertekkel",
-"Nem lehet ujra-megnyitni a tablat: '%-.64s",
-"A NULL ervenytelen hasznalata",
-"'%-.64s' hiba a regularis kifejezes hasznalata soran (regexp)",
-"A GROUP mezok (MIN(),MAX(),COUNT()...) kevert hasznalata nem lehetseges GROUP BY hivatkozas nelkul",
-"A '%-.32s' felhasznalonak nincs ilyen joga a '%-.64s' host-on",
-"%-.16s parancs a '%-.32s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' tablaban",
-"%-.16s parancs a '%-.32s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' mezo eseten a '%-.64s' tablaban",
-"Ervenytelen GRANT/REVOKE parancs. Kerem, nezze meg a kezikonyvben, milyen jogok lehetsegesek",
-"A host vagy felhasznalo argumentuma tul hosszu a GRANT parancsban",
-"A '%-.64s.%s' tabla nem letezik",
-"A '%-.32s' felhasznalo szamara a '%-.64s' host '%-.64s' tablajaban ez a parancs nem engedelyezett",
-"A hasznalt parancs nem engedelyezett ebben a MySQL verzioban",
-"Szintaktikai hiba",
-"A kesleltetett beillesztes (delayed insert) thread nem kapott zatolast a %-.64s tablahoz",
-"Tul sok kesletetett thread (delayed)",
-"Megszakitott kapcsolat %ld db: '%-.64s' adatbazishoz, felhasznalo: '%-.64s' (%s)",
-"A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'max_allowed_packet'",
-"Olvasasi hiba a kapcsolat soran",
-"Hiba a fcntl() fuggvenyben",
-"Helytelen sorrendben erkezett adatcsomagok",
-"A kommunikacios adatcsomagok nem tomorithetok ki",
-"HIba a kommunikacios adatcsomagok olvasasa soran",
-"Idotullepes a kommunikacios adatcsomagok olvasasa soran",
-"Hiba a kommunikacios csomagok irasa soran",
-"Idotullepes a kommunikacios csomagok irasa soran",
-"Ez eredmeny sztring nagyobb, mint a lehetseges maximum: 'max_allowed_packet'",
-"A hasznalt tabla tipus nem tamogatja a BLOB/TEXT mezoket",
-"A hasznalt tabla tipus nem tamogatja az AUTO_INCREMENT tipusu mezoket",
-"Az INSERT DELAYED nem hasznalhato a '%-.64s' tablahoz, mert a tabla zarolt (LOCK TABLES)",
-"Ervenytelen mezonev: '%-.100s'",
-"A hasznalt tablakezelo nem tudja a '%-.64s' mezot indexelni",
-"A MERGE tablaban talalhato tablak definicioja nem azonos",
-"A '%-.64s' nem irhato, az egyedi mezok miatt",
-"BLOB mezo '%-.64s' hasznalt a mezo specifikacioban, a mezohossz megadasa nelkul",
-"Az elsodleges kulcs teljes egeszeben csak NOT NULL tipusu lehet; Ha NULL mezot szeretne a kulcskent, hasznalja inkabb a UNIQUE-ot",
-"Az eredmeny tobb, mint egy sort tartalmaz",
-"Az adott tablatipushoz elsodleges kulcs hasznalata kotelezo",
-"Ezen leforditott MySQL verzio nem tartalmaz RAID support-ot",
-"On a biztonsagos update modot hasznalja, es WHERE that uses a KEY column",
-"A '%-.64s' kulcs nem letezik a '%-.64s' tablaban",
-"Nem tudom megnyitni a tablat",
-"A tabla kezeloje (handler) nem tamogatja az %s",
-"Az On szamara nem engedelyezett a parancs vegrehajtasa a tranzakcioban",
-"%d hiba a COMMIT vegrehajtasa soran",
-"%d hiba a ROLLBACK vegrehajtasa soran",
-"%d hiba a FLUSH_LOGS vegrehajtasa soran",
-"%d hiba a CHECKPOINT vegrehajtasa soran",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
deleted file mode 100644
index cd66f15db5f..00000000000
--- a/sql/share/italian/errmsg.txt
+++ /dev/null
@@ -1,321 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NO",
-"SI",
-"Impossibile creare il file '%-.64s' (errno: %d)",
-"Impossibile creare la tabella '%-.64s' (errno: %d)",
-"Impossibile creare il database '%-.64s' (errno: %d)",
-"Impossibile creare il database '%-.64s'; il database esiste",
-"Impossibile cancellare '%-.64s'; il database non esiste",
-"Errore durante la cancellazione del database (impossibile cancellare '%-.64s', errno: %d)",
-"Errore durante la cancellazione del database (impossibile rmdir '%-.64s', errno: %d)",
-"Errore durante la cancellazione di '%-.64s' (errno: %d)",
-"Impossibile leggere il record dalla tabella di sistema",
-"Impossibile leggere lo stato di '%-.64s' (errno: %d)",
-"Impossibile leggere la directory di lavoro (errno: %d)",
-"Impossibile il locking il file (errno: %d)",
-"Impossibile aprire il file: '%-.64s' (errno: %d)",
-"Impossibile trovare il file: '%-.64s' (errno: %d)",
-"Impossibile leggere la directory di '%-.64s' (errno: %d)",
-"Impossibile cambiare la directory in '%-.64s' (errno: %d)",
-"Il record e` cambiato dall'ultima lettura della tabella '%-.64s'",
-"Disco pieno (%s). In attesa che qualcuno liberi un po' di spazio...",
-"Scrittura impossibile: chiave duplicata nella tabella '%-.64s'",
-"Errore durante la chiusura di '%-.64s' (errno: %d)",
-"Errore durante la lettura del file '%-.64s' (errno: %d)",
-"Errore durante la rinominazione da '%-.64s' a '%-.64s' (errno: %d)",
-"Errore durante la scrittura del file '%-.64s' (errno: %d)",
-"'%-.64s' e` soggetto a lock contro i cambiamenti",
-"Operazione di ordinamento abbandonata",
-"La view '%-.64s' non esiste per '%-.64s'",
-"Rilevato l'errore %d dal gestore delle tabelle",
-"Il gestore delle tabelle per '%-.64s' non ha questa opzione",
-"Impossibile trovare il record in '%-.64s'",
-"Informazione errata nel file: '%-.64s'",
-"File chiave errato per la tabella : '%-.64s'; prova a riparalo",
-"File chiave vecchio per la tabella '%-.64s'; riparalo!",
-"'%-.64s' e` di sola lettura",
-"Memoria esaurita. Fai ripartire il demone e riprova (richiesti %d bytes)",
-"Memoria per gli ordinamenti esaurita. Incrementare il 'sort_buffer' al demone",
-"Fine del file inaspettata durante la lettura del file '%-.64s' (errno: %d)",
-"Troppe connessioni",
-"Fine dello spazio/memoria per i thread",
-"Impossibile risalire al nome dell'host dall'indirizzo (risoluzione inversa)",
-"Negoziazione impossibile",
-"Accesso non consentito per l'utente: '%-.32s'@'%-.64s' al database '%-.64s'",
-"Accesso non consentito per l'utente: '%-.32s'@'%-.64s' (Password: %s)",
-"Nessun database selezionato",
-"Comando sconosciuto",
-"La colonna '%-.64s' non puo` essere nulla",
-"Database '%-.64s' sconosciuto",
-"La tabella '%-.64s' esiste gia`",
-"Tabella '%-.64s' sconosciuta",
-"Colonna: '%-.64s' di %-.64s e` ambigua",
-"Shutdown del server in corso",
-"Colonna sconosciuta '%-.64s' in '%-.64s'",
-"Usato '%-.64s' che non e` nel GROUP BY",
-"Impossibile raggruppare per '%-.64s'",
-"Il comando ha una funzione SUM e una colonna non specificata nella GROUP BY",
-"Il numero delle colonne non e` uguale al numero dei valori",
-"Il nome dell'identificatore '%-.100s' e` troppo lungo",
-"Nome colonna duplicato '%-.64s'",
-"Nome chiave duplicato '%-.64s'",
-"Valore duplicato '%-.64s' per la chiave %d",
-"Specifica errata per la colonna '%-.64s'",
-"%s vicino a '%-.80s' linea %d",
-"La query e` vuota",
-"Tabella/alias non unico: '%-.64s'",
-"Valore di default non valido per '%-.64s'",
-"Definite piu` chiave primarie",
-"Troppe chiavi. Sono ammesse max %d chiavi",
-"Troppe parti di chiave specificate. Sono ammesse max %d parti",
-"La chiave specificata e` troppo lunga. La max lunghezza della chiave e` %d",
-"La colonna chiave '%-.64s' non esiste nella tabella",
-"La colonna BLOB '%-.64s' non puo` essere usata nella specifica della chiave",
-"La colonna '%-.64s' e` troppo grande (max=%d). Utilizza un BLOB.",
-"Puo` esserci solo un campo AUTO e deve essere definito come chiave",
-"%s: Pronto per le connessioni\n",
-"%s: Shutdown normale\n",
-"%s: Ricevuto segnale %d. Interruzione!\n",
-"%s: Shutdown completato\n",
-"%s: Forzata la chiusura del thread %ld utente: '%-.64s'\n",
-"Impossibile creare il socket IP",
-"La tabella '%-.64s' non ha nessun indice come quello specificatato dalla CREATE INDEX. Ricrea la tabella",
-"L'argomento 'Field separator' non e` quello atteso. Controlla il manuale",
-"Non possono essere usate righe a lunghezza fissa con i BLOB. Usa 'FIELDS TERMINATED BY'.",
-"Il file '%-.64s' deve essere nella directory del database e deve essere leggibile da tutti",
-"Il file '%-.64s' esiste gia`",
-"Records: %ld Cancellati: %ld Saltati: %ld Avvertimenti: %ld",
-"Records: %ld Duplicati: %ld",
-"Sotto-parte della chiave errata. La parte di chiave utilizzata non e` una stringa o la lunghezza e` maggiore della parte di chiave.",
-"Non si possono cancellare tutti i campi con una ALTER TABLE. Utilizzare DROP TABLE",
-"Impossibile cancellare '%-.64s'. Controllare che il campo chiave esista",
-"Records: %ld Duplicati: %ld Avvertimenti: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Thread id: %lu sconosciuto",
-"Utente non proprietario del thread %lu",
-"Nessuna tabella usata",
-"Troppe stringhe per la colonna %-.64s e la SET",
-"Impossibile generare un nome del file log unico %-.64s.(1-999)\n",
-"La tabella '%-.64s' e` soggetta a lock in lettura e non puo` essere aggiornata",
-"Non e` stato impostato il lock per la tabella '%-.64s' con LOCK TABLES",
-"Il campo BLOB '%-.64s' non puo` avere un valore di default",
-"Nome database errato '%-.100s'",
-"Nome tabella errato '%-.100s'",
-"La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET SQL_BIG_SELECTS=1 se e` tutto a posto.",
-"Errore sconosciuto",
-"Procedura '%-.64s' sconosciuta",
-"Numero di parametri errato per la procedura '%-.64s'",
-"Parametri errati per la procedura '%-.64s'",
-"Tabella '%-.64s' sconosciuta in %s",
-"Campo '%-.64s' specificato 2 volte",
-"Uso non valido di una funzione di raggruppamento",
-"La tabella '%-.64s' usa un'estensione che non esiste in questa versione di MySQL",
-"Una tabella deve avere almeno 1 colonna",
-"La tabella '%-.64s' e` piena",
-"Set di caratteri '%-.64s' sconosciuto",
-"Troppe tabelle. MySQL puo` usare solo %d tabelle in una join",
-"Troppi campi",
-"Riga troppo grande. La massima grandezza di una riga, non contando i BLOB, e` %d. Devi cambiare alcuni campi in BLOB",
-"Thread stack overrun: Usati: %ld di uno stack di %ld. Usa 'mysqld -O thread_stack=#' per specificare uno stack piu` grande.",
-"Trovata una dipendenza incrociata nella OUTER JOIN. Controlla le condizioni ON",
-"La colonna '%-.64s' e` usata con UNIQUE o INDEX ma non e` definita come NOT NULL",
-"Impossibile caricare la funzione '%-.64s'",
-"Impossibile inizializzare la funzione '%-.64s'; %-.80s",
-"Non sono ammessi path per le librerie condivisa",
-"La funzione '%-.64s' esiste gia`",
-"Impossibile aprire la libreria condivisa '%-.64s' (errno: %d %s)",
-"Impossibile trovare la funzione '%-.64s' nella libreria",
-"La funzione '%-.64s' non e` definita",
-"Sistema '%-.64s' bloccato a causa di troppi errori di connessione. Per sbloccarlo: 'mysqladmin flush-hosts'",
-"Al sistema '%-.64s' non e` consentita la connessione a questo server MySQL",
-"Impossibile cambiare la password usando MySQL come utente anonimo",
-"E` necessario il privilegio di update sulle tabelle del database mysql per cambiare le password per gli altri utenti",
-"Impossibile trovare la riga corrispondente nella tabella user",
-"Rows riconosciute: %ld Cambiate: %ld Warnings: %ld",
-"Impossibile creare un nuovo thread (errno %d). Se non ci sono problemi di memoria disponibile puoi consultare il manuale per controllare possibili problemi dipendenti dal SO",
-"Il numero delle colonne non corrisponde al conteggio alla riga %ld",
-"Impossibile riaprire la tabella: '%-.64s'",
-"Uso scorretto del valore NULL",
-"Errore '%-.64s' da regexp",
-"Il mescolare funzioni di aggregazione (MIN(),MAX(),COUNT()...) e non e` illegale se non c'e` una clausula GROUP BY",
-"GRANT non definita per l'utente '%-.32s' dalla macchina '%-.64s'",
-"Comando %-.16s negato per l'utente: '%-.32s'@'%-.64s' sulla tabella '%-.64s'",
-"Comando %-.16s negato per l'utente: '%-.32s'@'%-.64s' sulla colonna '%-.64s' della tabella '%-.64s'",
-"Comando GRANT/REVOKE illegale. Prego consultare il manuale per sapere quali privilegi possono essere usati.",
-"L'argomento host o utente per la GRANT e` troppo lungo",
-"La tabella '%-.64s.%s' non esiste",
-"GRANT non definita per l'utente '%-.32s' dalla macchina '%-.64s' sulla tabella '%-.64s'",
-"Il comando utilizzato non e` supportato in questa versione di MySQL",
-"Errore di sintassi nella query SQL",
-"Il thread di inserimento ritardato non riesce ad ottenere il lock per la tabella %-.64s",
-"Troppi threads ritardati in uso",
-"Interrotta la connessione %ld al db: '%-.64s' utente: '%-.64s' (%s)",
-"Ricevuto un pacchetto piu` grande di 'max_allowed_packet'",
-"Rilevato un errore di lettura dalla pipe di connessione",
-"Rilevato un errore da fcntl()",
-"Ricevuti pacchetti non in ordine",
-"Impossibile scompattare i pacchetti di comunicazione",
-"Rilevato un errore ricevendo i pacchetti di comunicazione",
-"Rilevato un timeout ricevendo i pacchetti di comunicazione",
-"Rilevato un errore inviando i pacchetti di comunicazione",
-"Rilevato un timeout inviando i pacchetti di comunicazione",
-"La stringa di risposta e` piu` lunga di 'max_allowed_packet'",
-"Il tipo di tabella usata non supporta colonne di tipo BLOB/TEXT",
-"Il tipo di tabella usata non supporta colonne di tipo AUTO_INCREMENT",
-"L'inserimento ritardato (INSERT DELAYED) non puo` essere usato con la tabella '%-.64s', perche` soggetta a lock da 'LOCK TABLES'",
-"Nome colonna '%-.100s' non corretto",
-"Il gestore delle tabelle non puo` indicizzare la colonna '%-.64s'",
-"Non tutte le tabelle nella tabella di MERGE sono definite in maniera identica",
-"Impossibile scrivere nella tabella '%-.64s' per limitazione di unicita`",
-"La colonna '%-.64s' di tipo BLOB e` usata in una chiave senza specificarne la lunghezza",
-"Tutte le parti di una chiave primaria devono essere dichiarate NOT NULL; se necessitano valori NULL nelle chiavi utilizzare UNIQUE",
-"Il risultato consiste di piu` di una riga",
-"Questo tipo di tabella richiede una chiave primaria",
-"Questa versione di MYSQL non e` compilata con il supporto RAID",
-"In modalita` 'safe update' si e` cercato di aggiornare una tabella senza clausola WHERE su una chiave",
-"La chiave '%-.64s' non esiste nella tabella '%-.64s'",
-"Impossibile aprire la tabella",
-"Il gestore per la tabella non supporta il %s",
-"Non puoi eseguire questo comando in una transazione",
-"Rilevato l'errore %d durante il COMMIT",
-"Rilevato l'errore %d durante il ROLLBACK",
-"Rilevato l'errore %d durante il FLUSH_LOGS",
-"Rilevato l'errore %d durante il CHECKPOINT",
-"Interrotta la connessione %ld al db: ''%-.64s' utente: '%-.32s' host: '%-.64s' (%-.64s)",
-"Il gestore per la tabella non supporta il dump binario",
-"Binlog e` stato chiuso durante l'esecuzione del FLUSH MASTER",
-"Fallita la ricostruzione dell'indice della tabella copiata '%-.64s'",
-"Errore dal master: '%-.64s",
-"Errore di rete durante la ricezione dal master",
-"Errore di rete durante l'invio al master",
-"Impossibile trovare un indice FULLTEXT che corrisponda all'elenco delle colonne",
-"Impossibile eseguire il comando richiesto: tabelle sotto lock o transazione in atto",
-"Variabile di sistema '%-.64s' sconosciuta",
-"La tabella '%-.64s' e` segnalata come corrotta e deve essere riparata",
-"La tabella '%-.64s' e` segnalata come corrotta e l'ultima ricostruzione (automatica?) e` fallita",
-"Attenzione: Alcune delle modifiche alle tabelle non transazionali non possono essere ripristinate (roll back impossibile)",
-"La transazione a comandi multipli (multi-statement) ha richiesto piu` di 'max_binlog_cache_size' bytes di disco: aumentare questa variabile di mysqld e riprovare",
-"Questa operazione non puo' essere eseguita con un database 'slave' che gira, lanciare prima STOP SLAVE",
-"Questa operaione richiede un database 'slave', configurarlo ed eseguire START SLAVE",
-"Il server non e' configurato come 'slave', correggere il file di configurazione cambiando CHANGE MASTER TO",
-"Could not initialize master info structure, more error messages can be found in the MySQL error log",
-"Impossibile creare il thread 'slave', controllare le risorse di sistema",
-"L'utente %-.64s ha gia' piu' di 'max_user_connections' connessioni attive",
-"Si possono usare solo espressioni costanti con SET",
-"E' scaduto il timeout per l'attesa del lock",
-"Il numero totale di lock e' maggiore della grandezza della tabella di lock",
-"I lock di aggiornamento non possono essere acquisiti durante una transazione 'READ UNCOMMITTED'",
-"DROP DATABASE non e' permesso mentre il thread ha un lock globale di lettura",
-"CREATE DATABASE non e' permesso mentre il thread ha un lock globale di lettura",
-"Argomenti errati a %s",
-"A '%-.32s'@'%-.64s' non e' permesso creare nuovi utenti",
-"Definizione della tabella errata; tutte le tabelle di tipo MERGE devono essere nello stesso database",
-"Trovato deadlock durante il lock; Provare a far ripartire la transazione",
-"La tabella usata non supporta gli indici FULLTEXT",
-"Impossibile aggiungere il vincolo di integrita' referenziale (foreign key constraint)",
-"Impossibile aggiungere la riga: un vincolo d'integrita' referenziale non e' soddisfatto",
-"Impossibile cancellare la riga: un vincolo d'integrita' referenziale non e' soddisfatto",
-"Errore durante la connessione al master: %-.128s",
-"Errore eseguendo una query sul master: %-.128s",
-"Errore durante l'esecuzione del comando %s: %-.128s",
-"Uso errato di %s e %s",
-"La SELECT utilizzata ha un numero di colonne differente",
-"Impossibile eseguire la query perche' c'e' un conflitto con in lock di lettura",
-"E' disabilitata la possibilita' di mischiare tabelle transazionali e non-transazionali",
-"L'opzione '%s' e' stata usata due volte nel comando",
-"L'utente '%-.64s' ha ecceduto la risorsa '%s' (valore corrente: %ld)",
-"Accesso non consentito. Serve il privilegio %-.128s per questa operazione",
-"La variabile '%-.64s' e' una variabile locale ( SESSION ) e non puo' essere cambiata usando SET GLOBAL",
-"La variabile '%-.64s' e' una variabile globale ( GLOBAL ) e deve essere cambiata usando SET GLOBAL",
-"La variabile '%-.64s' non ha un valore di default",
-"Alla variabile '%-.64s' non puo' essere assegato il valore '%-.64s'",
-"Tipo di valore errato per la variabile '%-.64s'",
-"Alla variabile '%-.64s' e' di sola scrittura quindi puo' essere solo assegnato un valore, non letto",
-"Uso/posizione di '%s' sbagliato",
-"Questa versione di MySQL non supporta ancora '%s'",
-"Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/japanese-sjis/errmsg.txt b/sql/share/japanese-sjis/errmsg.txt
deleted file mode 100644
index a06723727b7..00000000000
--- a/sql/share/japanese-sjis/errmsg.txt
+++ /dev/null
@@ -1,325 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Shift-JIS Japanese
-*/
-
-character-set=sjis
-
-"hashchk",
-"isamchk",
-"NO",
-"YES",
-"'%-.64s' ƒtƒ@ƒCƒ‹‚ªì‚ê‚Ü‚¹‚ñ (errno: %d)",
-"'%-.64s' ƒe[ƒuƒ‹‚ªì‚ê‚Ü‚¹‚ñ.(errno: %d)",
-"'%-.64s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ (errno: %d)",
-"'%-.64s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ.Šù‚É‚»‚̃f[ƒ^ƒx[ƒX‚ª‘¶Ý‚µ‚Ü‚·",
-"'%-.64s' ƒf[ƒ^ƒx[ƒX‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ. ‚»‚̃f[ƒ^ƒx[ƒX‚ª‚È‚¢‚Ì‚Å‚·.",
-"ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.64s' ‚ð휂ł«‚Ü‚¹‚ñ, errno: %d)",
-"ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.64s' ‚ð rmdir ‚Å‚«‚Ü‚¹‚ñ, errno: %d)",
-"'%-.64s' ‚Ì휂ªƒGƒ‰[ (errno: %d)",
-"system table ‚̃ŒƒR[ƒh‚ð“Ç‚ÞŽ–‚ª‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½",
-"'%-.64s' ‚̃XƒeƒCƒ^ƒX‚ª“¾‚ç‚ê‚Ü‚¹‚ñ. (errno: %d)",
-"working directory ‚𓾂鎖‚ª‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½ (errno: %d)",
-"ƒtƒ@ƒCƒ‹‚ðƒƒbƒN‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
-"'%-.64s' ƒtƒ@ƒCƒ‹‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
-"'%-.64s' ƒtƒ@ƒCƒ‹‚ðŒ©•t‚¯‚鎖‚ª‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
-"'%-.64s' ƒfƒBƒŒƒNƒgƒŠ‚ª“Ç‚ß‚Ü‚¹‚ñ.(errno: %d)",
-"'%-.64s' ƒfƒBƒŒƒNƒgƒŠ‚É chdir ‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
-"Record has changed since last read in table '%-.64s'",
-"Disk full (%s). ’N‚©‚ª‰½‚©‚ðŒ¸‚ç‚·‚Ü‚Å‚Ü‚Á‚Ä‚­‚¾‚³‚¢...",
-"table '%-.64s' ‚É key ‚ªd•¡‚µ‚Ä‚¢‚Ä‘‚«‚±‚ß‚Ü‚¹‚ñ",
-"Error on close of '%-.64s' (errno: %d)",
-"'%-.64s' ƒtƒ@ƒCƒ‹‚Ì“Ç‚Ýž‚݃Gƒ‰[ (errno: %d)",
-"'%-.64s' ‚ð '%-.64s' ‚É rename ‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
-"'%-.64s' ƒtƒ@ƒCƒ‹‚ð‘‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
-"'%-.64s' ‚̓ƒbƒN‚³‚ê‚Ä‚¢‚Ü‚·",
-"Sort ’†’f",
-"View '%-.64s' ‚ª '%-.64s' ‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
-"Got error %d from table handler",
-"Table handler for '%-.64s' doesn't have this option",
-"'%-.64s'‚Ì‚È‚©‚ɃŒƒR[ƒh‚ªŒ©•t‚©‚è‚Ü‚¹‚ñ",
-"ƒtƒ@ƒCƒ‹ '%-.64s' ‚Ì info ‚ªŠÔˆá‚Á‚Ä‚¢‚é‚悤‚Å‚·",
-"'%-.64s' ƒe[ƒuƒ‹‚Ì key file ‚ªŠÔˆá‚Á‚Ä‚¢‚é‚悤‚Å‚·. C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
-"'%-.64s' ƒe[ƒuƒ‹‚͌¢Œ`Ž®‚Ì key file ‚̂悤‚Å‚·; C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
-"'%-.64s' ‚Í“Ç‚Ýž‚Ýê—p‚Å‚·",
-"Out of memory. ƒf[ƒ‚ƒ“‚ðƒŠƒXƒ^[ƒg‚µ‚Ä‚Ý‚Ä‚­‚¾‚³‚¢ (%d bytes •K—v)",
-"Out of sort memory. sort buffer size ‚ª‘«‚è‚È‚¢‚悤‚Å‚·.",
-"'%-.64s' ƒtƒ@ƒCƒ‹‚ð“Ç‚Ýž‚Ý’†‚É EOF ‚ª—\Šú‚¹‚ÊŠ‚ÅŒ»‚ê‚Ü‚µ‚½. (errno: %d)",
-"Ú‘±‚ª‘½‚·‚¬‚Ü‚·",
-"Out of memory; mysqld ‚©‚»‚Ì‘¼‚̃vƒƒZƒX‚ªƒƒ‚ƒŠ[‚ð‘S‚ÄŽg‚Á‚Ä‚¢‚é‚©Šm”F‚µ‚Ä‚­‚¾‚³‚¢. ƒƒ‚ƒŠ[‚ðŽg‚¢Ø‚Á‚Ä‚¢‚È‚¢ê‡A'ulimit' ‚ðݒ肵‚Ä mysqld ‚̃ƒ‚ƒŠ[Žg—pŒÀŠE—ʂ𑽂­‚·‚é‚©Aswap space ‚ð‘‚₵‚Ä‚Ý‚Ä‚­‚¾‚³‚¢",
-"‚»‚Ì address ‚Ì hostname ‚ªˆø‚¯‚Ü‚¹‚ñ.",
-"Bad handshake",
-"ƒ†[ƒU[ '%-.32s'@'%-.64s' ‚Ì '%-.64s' ƒf[ƒ^ƒx[ƒX‚ւ̃AƒNƒZƒX‚ð‹‘”Û‚µ‚Ü‚·",
-"ƒ†[ƒU[ '%-.32s'@'%-.64s' ‚ð‹‘”Û‚µ‚Ü‚·.uUsing password: %s)",
-"ƒf[ƒ^ƒx[ƒX‚ª‘I‘ð‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ.",
-"‚»‚̃Rƒ}ƒ“ƒh‚͉½H",
-"Column '%-.64s' ‚Í null ‚É‚Í‚Å‚«‚È‚¢‚Ì‚Å‚·",
-"'%-.64s' ‚È‚ñ‚ăf[ƒ^ƒx[ƒX‚Í’m‚è‚Ü‚¹‚ñ.",
-"Table '%-.64s' ‚ÍŠù‚É‚ ‚è‚Ü‚·",
-"table '%-.64s' ‚Í‚ ‚è‚Ü‚¹‚ñ.",
-"Column: '%-.64s' in %-.64s is ambiguous",
-"Server ‚ð shutdown ’†...",
-"'%-.64s' column ‚Í '%-.64s' ‚É‚Í‚ ‚è‚Ü‚¹‚ñ.",
-"'%-.64s' isn't in GROUP BY",
-"Can't group on '%-.64s'",
-"Statement has sum functions and columns in same statement",
-"Column count doesn't match value count",
-"Identifier name '%-.100s' ‚Í’·‚·‚¬‚Ü‚·",
-"'%-.64s' ‚Æ‚¢‚¤ column –¼‚Íd•¡‚µ‚Ä‚Ü‚·",
-"'%-.64s' ‚Æ‚¢‚¤ key ‚Ì–¼‘O‚Íd•¡‚µ‚Ä‚¢‚Ü‚·",
-"'%-.64s' ‚Í key %d ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·",
-"Incorrect column specifier for column '%-.64s'",
-"%s : '%-.80s' •t‹ß : %d s–Ú",
-"Query ‚ª‹ó‚Å‚·.",
-"'%-.64s' ‚͈êˆÓ‚Ì table/alias –¼‚Å‚Í‚ ‚è‚Ü‚¹‚ñ",
-"Invalid default value for '%-.64s'",
-"•¡”‚Ì primary key ‚ª’è‹`‚³‚ê‚Ü‚µ‚½",
-"key ‚ÌŽw’肪‘½‚·‚¬‚Ü‚·. key ‚ÍÅ‘å %d ‚Ü‚Å‚Å‚·",
-"Too many key parts specified; max %d parts allowed",
-"key ‚ª’·‚·‚¬‚Ü‚·. key ‚Ì’·‚³‚ÍÅ‘å %d ‚Å‚·",
-"Key column '%-.64s' ‚ªƒe[ƒuƒ‹‚É‚ ‚è‚Ü‚¹‚ñ.",
-"BLOB column '%-.64s' can't be used in key specification with the used table type",
-"column '%-.64s' ‚Í,Šm•Û‚·‚é column ‚Ì‘å‚«‚³‚ª‘½‚·‚¬‚Ü‚·. (Å‘å %d ‚Ü‚Å). BLOB ‚ð‚©‚í‚è‚ÉŽg—p‚µ‚Ä‚­‚¾‚³‚¢.",
-"ƒe[ƒuƒ‹‚Ì’è‹`‚ªˆá‚¢‚Ü‚·; there can be only one auto column and it must be defined as a key",
-"%s: €”õŠ®—¹",
-"%s: Normal shutdown\n",
-"%s: Got signal %d. ’†’f!\n",
-"%s: Shutdown Š®—¹\n",
-"%s: ƒXƒŒƒbƒh %ld ‹­§I—¹ user: '%-.64s'\n",
-"IP socket ‚ªì‚ê‚Ü‚¹‚ñ",
-"Table '%-.64s' ‚Í‚»‚̂悤‚È index ‚ðŽ‚Á‚Ä‚¢‚Ü‚¹‚ñ(CREATE INDEX ŽÀsŽž‚ÉŽw’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ). ƒe[ƒuƒ‹‚ðì‚è’¼‚µ‚Ä‚­‚¾‚³‚¢",
-"Field separator argument is not what is expected; check the manual",
-"You can't use fixed rowlength with BLOBs; please use 'fields terminated by'.",
-"ƒtƒ@ƒCƒ‹ '%-.64s' ‚Í databse ‚Ì directory ‚É‚ ‚é‚©‘S‚Ẵ†[ƒU[‚ª“Ç‚ß‚é‚悤‚É‹–‰Â‚³‚ê‚Ä‚¢‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ.",
-"File '%-.64s' ‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·",
-"ƒŒƒR[ƒh”: %ld íœ: %ld Skipped: %ld Warnings: %ld",
-"ƒŒƒR[ƒh”: %ld d•¡: %ld",
-"Incorrect sub part key; the used key part isn't a string or the used length is longer than the key part",
-"ALTER TABLE ‚Å‘S‚Ä‚Ì column ‚Í휂ł«‚Ü‚¹‚ñ. DROP TABLE ‚ðŽg—p‚µ‚Ä‚­‚¾‚³‚¢",
-"'%-.64s' ‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½; check that column/key exists",
-"ƒŒƒR[ƒh”: %ld d•¡”: %ld Warnings: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"thread id: %lu ‚Í‚ ‚è‚Ü‚¹‚ñ",
-"thread %lu ‚̃I[ƒi[‚Å‚Í‚ ‚è‚Ü‚¹‚ñ",
-"No tables used",
-"Too many strings for column %-.64s and SET",
-"Can't generate a unique log-filename %-.64s.(1-999)\n",
-"Table '%-.64s' ‚Í READ lock ‚É‚È‚Á‚Ä‚¢‚ÄAXV‚Í‚Å‚«‚Ü‚¹‚ñ",
-"Table '%-.64s' ‚Í LOCK TABLES ‚É‚æ‚Á‚ăƒbƒN‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
-"BLOB column '%-.64s' can't have a default value",
-"Žw’肵‚½ database –¼ '%-.100s' ‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·",
-"Žw’肵‚½ table –¼ '%-.100s' ‚Í‚Ü‚¿‚ª‚Á‚Ä‚¢‚Ü‚·",
-"The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay",
-"Unknown error",
-"Unknown procedure '%-.64s'",
-"Incorrect parameter count to procedure '%-.64s'",
-"Incorrect parameters to procedure '%-.64s'",
-"Unknown table '%-.64s' in %s",
-"Column '%-.64s' specified twice",
-"Invalid use of group function",
-"Table '%-.64s' uses an extension that doesn't exist in this MySQL version",
-"ƒe[ƒuƒ‹‚ÍÅ’á 1 ŒÂ‚Ì column ‚ª•K—v‚Å‚·",
-"table '%-.64s' ‚Í‚¢‚Á‚Ï‚¢‚Å‚·",
-"character set '%-.64s' ‚̓Tƒ|[ƒg‚µ‚Ä‚¢‚Ü‚¹‚ñ",
-"ƒe[ƒuƒ‹‚ª‘½‚·‚¬‚Ü‚·; MySQL can only use %d tables in a join",
-"column ‚ª‘½‚·‚¬‚Ü‚·",
-"row size ‚ª‘å‚«‚·‚¬‚Ü‚·. BLOB ‚ðŠÜ‚Ü‚È‚¢ê‡‚Ì row size ‚ÌÅ‘å‚Í %d ‚Å‚·. ‚¢‚­‚‚©‚Ì field ‚ð BLOB ‚É•Ï‚¦‚Ä‚­‚¾‚³‚¢.",
-"Thread stack overrun: Used: %ld of a %ld stack. ƒXƒ^ƒbƒN—̈æ‚𑽂­‚Ƃ肽‚¢ê‡A'mysqld -O thread_stack=#' ‚ÆŽw’肵‚Ä‚­‚¾‚³‚¢",
-"Cross dependency found in OUTER JOIN; examine your ON conditions",
-"Column '%-.64s' ‚ª UNIQUE ‚© INDEX ‚ÅŽg—p‚³‚ê‚Ü‚µ‚½. ‚±‚̃Jƒ‰ƒ€‚Í NOT NULL ‚Æ’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ.",
-"function '%-.64s' ‚ð ƒ[ƒh‚Å‚«‚Ü‚¹‚ñ",
-"function '%-.64s' ‚ð‰Šú‰»‚Å‚«‚Ü‚¹‚ñ; %-.80s",
-"shared library ‚ւ̃pƒX‚ª’Ê‚Á‚Ä‚¢‚Ü‚¹‚ñ",
-"Function '%-.64s' ‚ÍŠù‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚·",
-"shared library '%-.64s' ‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d %s)",
-"function '%-.64s' ‚ðƒ‰ƒCƒuƒ‰ƒŠ[’†‚ÉŒ©•t‚¯‚鎖‚ª‚Å‚«‚Ü‚¹‚ñ",
-"Function '%-.64s' ‚Í’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
-"Host '%-.64s' ‚Í many connection error ‚Ì‚½‚ßA‹‘”Û‚³‚ê‚Ü‚µ‚½. 'mysqladmin flush-hosts' ‚ʼn𜂵‚Ä‚­‚¾‚³‚¢",
-"Host '%-.64s' ‚Í MySQL server ‚ÉÚ‘±‚ð‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
-"MySQL ‚ð anonymous users ‚ÅŽg—p‚µ‚Ä‚¢‚éó‘Ô‚Å‚ÍAƒpƒXƒ[ƒh‚Ì•ÏX‚Í‚Å‚«‚Ü‚¹‚ñ",
-"‘¼‚̃†[ƒU[‚̃pƒXƒ[ƒh‚ð•ÏX‚·‚邽‚ß‚É‚Í, mysql ƒf[ƒ^ƒx[ƒX‚ɑ΂µ‚Ä update ‚Ì‹–‰Â‚ª‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ.",
-"Can't find any matching row in the user table",
-"ˆê’v”(Rows matched): %ld •ÏX: %ld Warnings: %ld",
-"V‹K‚ɃXƒŒƒbƒh‚ªì‚ê‚Ü‚¹‚ñ‚Å‚µ‚½ (errno %d). ‚à‚µÅ‘åŽg—p‹–‰Âƒƒ‚ƒŠ[”‚ð‰z‚¦‚Ä‚¢‚È‚¢‚̂ɃGƒ‰[‚ª”­¶‚µ‚Ä‚¢‚é‚È‚ç, ƒ}ƒjƒ…ƒAƒ‹‚Ì’†‚©‚ç 'possible OS-dependent bug' ‚Æ‚¢‚¤•¶Žš‚ð’T‚µ‚Ä‚­‚Ý‚Ä‚¾‚³‚¢.",
-"Column count doesn't match value count at row %ld",
-"Can't reopen table: '%-.64s'",
-"NULL ’l‚ÌŽg—p•û–@‚ª•s“KØ‚Å‚·",
-"Got error '%-.64s' from regexp",
-"Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause",
-"ƒ†[ƒU[ '%-.32s' (ƒzƒXƒg '%-.64s' ‚̃†[ƒU[) ‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
-"ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.32s'@'%-.64s' ,ƒe[ƒuƒ‹ '%-.64s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
-"ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.32s'@'%-.64s'\n ƒJƒ‰ƒ€ '%-.64s' ƒe[ƒuƒ‹ '%-.64s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
-"Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used.",
-"The host or user argument to GRANT is too long",
-"Table '%-.64s.%s' doesn't exist",
-"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
-"The used command is not allowed with this MySQL version",
-"Something is wrong in your syntax",
-"Delayed insert thread couldn't get requested lock for table %-.64s",
-"Too many delayed threads in use",
-"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
-"Got a packet bigger than 'max_allowed_packet' bytes",
-"Got a read error from the connection pipe",
-"Got an error from fcntl()",
-"Got packets out of order",
-"Couldn't uncompress communication packet",
-"Got an error reading communication packets",
-"Got timeout reading communication packets",
-"Got an error writing communication packets",
-"Got timeout writing communication packets",
-"Result string is longer than 'max_allowed_packet' bytes",
-"The used table type doesn't support BLOB/TEXT columns",
-"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
-"Incorrect column name '%-.100s'",
-"The used table handler can't index column '%-.64s'",
-"All tables in the MERGE table are not defined identically",
-"Can't write, because of unique constraint, to table '%-.64s'",
-"BLOB column '%-.64s' used in key specification without a key length",
-"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
-"This table type requires a primary key",
-"This version of MySQL is not compiled with RAID support",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got NDB error %d '%-.100s'",
-"Got temporary NDB error %d '%-.100s'",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
deleted file mode 100644
index eaab58d8403..00000000000
--- a/sql/share/japanese/errmsg.txt
+++ /dev/null
@@ -1,325 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- 3.22.10-beta euc-japanese (ujis) text
-*/
-
-character-set=ujis
-
-"hashchk",
-"isamchk",
-"NO",
-"YES",
-"'%-.64s' ¥Õ¥¡¥¤¥ë¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)",
-"'%-.64s' ¥Æ¡¼¥Ö¥ë¤¬ºî¤ì¤Þ¤»¤ó.(errno: %d)",
-"'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)",
-"'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó.´û¤Ë¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬Â¸ºß¤·¤Þ¤¹",
-"'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤òÇË´þ¤Ç¤­¤Þ¤»¤ó. ¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬¤Ê¤¤¤Î¤Ç¤¹.",
-"¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.64s' ¤òºï½ü¤Ç¤­¤Þ¤»¤ó, errno: %d)",
-"¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.64s' ¤ò rmdir ¤Ç¤­¤Þ¤»¤ó, errno: %d)",
-"'%-.64s' ¤Îºï½ü¤¬¥¨¥é¡¼ (errno: %d)",
-"system table ¤Î¥ì¥³¡¼¥É¤òÆɤà»ö¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿",
-"'%-.64s' ¤Î¥¹¥Æ¥¤¥¿¥¹¤¬ÆÀ¤é¤ì¤Þ¤»¤ó. (errno: %d)",
-"working directory ¤òÆÀ¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿ (errno: %d)",
-"¥Õ¥¡¥¤¥ë¤ò¥í¥Ã¥¯¤Ç¤­¤Þ¤»¤ó (errno: %d)",
-"'%-.64s' ¥Õ¥¡¥¤¥ë¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)",
-"'%-.64s' ¥Õ¥¡¥¤¥ë¤ò¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó.(errno: %d)",
-"'%-.64s' ¥Ç¥£¥ì¥¯¥È¥ê¤¬Æɤá¤Þ¤»¤ó.(errno: %d)",
-"'%-.64s' ¥Ç¥£¥ì¥¯¥È¥ê¤Ë chdir ¤Ç¤­¤Þ¤»¤ó.(errno: %d)",
-"Record has changed since last read in table '%-.64s'",
-"Disk full (%s). 狼¤¬²¿¤«¤ò¸º¤é¤¹¤Þ¤Ç¤Þ¤Ã¤Æ¤¯¤À¤µ¤¤...",
-"table '%-.64s' ¤Ë key ¤¬½ÅÊ£¤·¤Æ¤¤¤Æ½ñ¤­¤³¤á¤Þ¤»¤ó",
-"Error on close of '%-.64s' (errno: %d)",
-"'%-.64s' ¥Õ¥¡¥¤¥ë¤ÎÆɤ߹þ¤ß¥¨¥é¡¼ (errno: %d)",
-"'%-.64s' ¤ò '%-.64s' ¤Ë rename ¤Ç¤­¤Þ¤»¤ó (errno: %d)",
-"'%-.64s' ¥Õ¥¡¥¤¥ë¤ò½ñ¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)",
-"'%-.64s' ¤Ï¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤¹",
-"Sort ̾̂",
-"View '%-.64s' ¤¬ '%-.64s' ¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
-"Got error %d from table handler",
-"Table handler for '%-.64s' doesn't have this option",
-"'%-.64s'¤Î¤Ê¤«¤Ë¥ì¥³¡¼¥É¤¬¸«ÉÕ¤«¤ê¤Þ¤»¤ó",
-"¥Õ¥¡¥¤¥ë '%-.64s' ¤Î info ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹",
-"'%-.64s' ¥Æ¡¼¥Ö¥ë¤Î key file ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹. ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤",
-"'%-.64s' ¥Æ¡¼¥Ö¥ë¤Ï¸Å¤¤·Á¼°¤Î key file ¤Î¤è¤¦¤Ç¤¹; ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤",
-"'%-.64s' ¤ÏÆɤ߹þ¤ßÀìÍѤǤ¹",
-"Out of memory. ¥Ç¡¼¥â¥ó¤ò¥ê¥¹¥¿¡¼¥È¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤ (%d bytes ɬÍ×)",
-"Out of sort memory. sort buffer size ¤¬Â­¤ê¤Ê¤¤¤è¤¦¤Ç¤¹.",
-"'%-.64s' ¥Õ¥¡¥¤¥ë¤òÆɤ߹þ¤ßÃæ¤Ë EOF ¤¬Í½´ü¤»¤Ì½ê¤Ç¸½¤ì¤Þ¤·¤¿. (errno: %d)",
-"Àܳ¤¬Â¿¤¹¤®¤Þ¤¹",
-"Out of memory; mysqld ¤«¤½¤Î¾¤Î¥×¥í¥»¥¹¤¬¥á¥â¥ê¡¼¤òÁ´¤Æ»È¤Ã¤Æ¤¤¤ë¤«³Îǧ¤·¤Æ¤¯¤À¤µ¤¤. ¥á¥â¥ê¡¼¤ò»È¤¤ÀڤäƤ¤¤Ê¤¤¾ì¹ç¡¢'ulimit' ¤òÀßÄꤷ¤Æ mysqld ¤Î¥á¥â¥ê¡¼»ÈÍѸ³¦Î̤ò¿¤¯¤¹¤ë¤«¡¢swap space ¤òÁý¤ä¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤",
-"¤½¤Î address ¤Î hostname ¤¬°ú¤±¤Þ¤»¤ó.",
-"Bad handshake",
-"¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ¤Î '%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥¢¥¯¥»¥¹¤òµñÈݤ·¤Þ¤¹",
-"¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ¤òµñÈݤ·¤Þ¤¹.uUsing password: %s)",
-"¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ÁªÂò¤µ¤ì¤Æ¤¤¤Þ¤»¤ó.",
-"¤½¤Î¥³¥Þ¥ó¥É¤Ï²¿¡©",
-"Column '%-.64s' ¤Ï null ¤Ë¤Ï¤Ç¤­¤Ê¤¤¤Î¤Ç¤¹",
-"'%-.64s' ¤Ê¤ó¤Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ÏÃΤê¤Þ¤»¤ó.",
-"Table '%-.64s' ¤Ï´û¤Ë¤¢¤ê¤Þ¤¹",
-"table '%-.64s' ¤Ï¤¢¤ê¤Þ¤»¤ó.",
-"Column: '%-.64s' in %-.64s is ambiguous",
-"Server ¤ò shutdown Ãæ...",
-"'%-.64s' column ¤Ï '%-.64s' ¤Ë¤Ï¤¢¤ê¤Þ¤»¤ó.",
-"'%-.64s' isn't in GROUP BY",
-"Can't group on '%-.64s'",
-"Statement has sum functions and columns in same statement",
-"Column count doesn't match value count",
-"Identifier name '%-.100s' ¤ÏŤ¹¤®¤Þ¤¹",
-"'%-.64s' ¤È¤¤¤¦ column ̾¤Ï½ÅÊ£¤·¤Æ¤Þ¤¹",
-"'%-.64s' ¤È¤¤¤¦ key ¤Î̾Á°¤Ï½ÅÊ£¤·¤Æ¤¤¤Þ¤¹",
-"'%-.64s' ¤Ï key %d ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹",
-"Incorrect column specifier for column '%-.64s'",
-"%s : '%-.80s' ÉÕ¶á : %d ¹ÔÌÜ",
-"Query ¤¬¶õ¤Ç¤¹.",
-"'%-.64s' ¤Ï°ì°Õ¤Î table/alias ̾¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó",
-"Invalid default value for '%-.64s'",
-"Ê£¿ô¤Î primary key ¤¬ÄêµÁ¤µ¤ì¤Þ¤·¤¿",
-"key ¤Î»ØÄ꤬¿¤¹¤®¤Þ¤¹. key ¤ÏºÇÂç %d ¤Þ¤Ç¤Ç¤¹",
-"Too many key parts specified; max %d parts allowed",
-"key ¤¬Ä¹¤¹¤®¤Þ¤¹. key ¤ÎŤµ¤ÏºÇÂç %d ¤Ç¤¹",
-"Key column '%-.64s' ¤¬¥Æ¡¼¥Ö¥ë¤Ë¤¢¤ê¤Þ¤»¤ó.",
-"BLOB column '%-.64s' can't be used in key specification with the used table type",
-"column '%-.64s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礭¤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %d ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤.",
-"¥Æ¡¼¥Ö¥ë¤ÎÄêµÁ¤¬°ã¤¤¤Þ¤¹; there can be only one auto column and it must be defined as a key",
-"%s: ½àÈ÷´°Î»",
-"%s: Normal shutdown\n",
-"%s: Got signal %d. ̾̂!\n",
-"%s: Shutdown ´°Î»\n",
-"%s: ¥¹¥ì¥Ã¥É %ld ¶¯À©½ªÎ» user: '%-.64s'\n",
-"IP socket ¤¬ºî¤ì¤Þ¤»¤ó",
-"Table '%-.64s' ¤Ï¤½¤Î¤è¤¦¤Ê index ¤ò»ý¤Ã¤Æ¤¤¤Þ¤»¤ó(CREATE INDEX ¼Â¹Ô»þ¤Ë»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó). ¥Æ¡¼¥Ö¥ë¤òºî¤êľ¤·¤Æ¤¯¤À¤µ¤¤",
-"Field separator argument is not what is expected; check the manual",
-"You can't use fixed rowlength with BLOBs; please use 'fields terminated by'.",
-"¥Õ¥¡¥¤¥ë '%-.64s' ¤Ï databse ¤Î directory ¤Ë¤¢¤ë¤«Á´¤Æ¤Î¥æ¡¼¥¶¡¼¤¬Æɤá¤ë¤è¤¦¤Ëµö²Ä¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó.",
-"File '%-.64s' ¤Ï´û¤Ë¸ºß¤·¤Þ¤¹",
-"¥ì¥³¡¼¥É¿ô: %ld ºï½ü: %ld Skipped: %ld Warnings: %ld",
-"¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£: %ld",
-"Incorrect sub part key; the used key part isn't a string or the used length is longer than the key part",
-"ALTER TABLE ¤ÇÁ´¤Æ¤Î column ¤Ïºï½ü¤Ç¤­¤Þ¤»¤ó. DROP TABLE ¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤",
-"'%-.64s' ¤òÇË´þ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿; check that column/key exists",
-"¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£¿ô: %ld Warnings: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"thread id: %lu ¤Ï¤¢¤ê¤Þ¤»¤ó",
-"thread %lu ¤Î¥ª¡¼¥Ê¡¼¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó",
-"No tables used",
-"Too many strings for column %-.64s and SET",
-"Can't generate a unique log-filename %-.64s.(1-999)\n",
-"Table '%-.64s' ¤Ï READ lock ¤Ë¤Ê¤Ã¤Æ¤¤¤Æ¡¢¹¹¿·¤Ï¤Ç¤­¤Þ¤»¤ó",
-"Table '%-.64s' ¤Ï LOCK TABLES ¤Ë¤è¤Ã¤Æ¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
-"BLOB column '%-.64s' can't have a default value",
-"»ØÄꤷ¤¿ database ̾ '%-.100s' ¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹",
-"»ØÄꤷ¤¿ table ̾ '%-.100s' ¤Ï¤Þ¤Á¤¬¤Ã¤Æ¤¤¤Þ¤¹",
-"The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay",
-"Unknown error",
-"Unknown procedure '%-.64s'",
-"Incorrect parameter count to procedure '%-.64s'",
-"Incorrect parameters to procedure '%-.64s'",
-"Unknown table '%-.64s' in %s",
-"Column '%-.64s' specified twice",
-"Invalid use of group function",
-"Table '%-.64s' uses an extension that doesn't exist in this MySQL version",
-"¥Æ¡¼¥Ö¥ë¤ÏºÇÄã 1 ¸Ä¤Î column ¤¬É¬ÍפǤ¹",
-"table '%-.64s' ¤Ï¤¤¤Ã¤Ñ¤¤¤Ç¤¹",
-"character set '%-.64s' ¤Ï¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Þ¤»¤ó",
-"¥Æ¡¼¥Ö¥ë¤¬Â¿¤¹¤®¤Þ¤¹; MySQL can only use %d tables in a join",
-"column ¤¬Â¿¤¹¤®¤Þ¤¹",
-"row size ¤¬Â礭¤¹¤®¤Þ¤¹. BLOB ¤ò´Þ¤Þ¤Ê¤¤¾ì¹ç¤Î row size ¤ÎºÇÂç¤Ï %d ¤Ç¤¹. ¤¤¤¯¤Ä¤«¤Î field ¤ò BLOB ¤ËÊѤ¨¤Æ¤¯¤À¤µ¤¤.",
-"Thread stack overrun: Used: %ld of a %ld stack. ¥¹¥¿¥Ã¥¯Îΰè¤ò¿¤¯¤È¤ê¤¿¤¤¾ì¹ç¡¢'mysqld -O thread_stack=#' ¤È»ØÄꤷ¤Æ¤¯¤À¤µ¤¤",
-"Cross dependency found in OUTER JOIN; examine your ON conditions",
-"Column '%-.64s' ¤¬ UNIQUE ¤« INDEX ¤Ç»ÈÍѤµ¤ì¤Þ¤·¤¿. ¤³¤Î¥«¥é¥à¤Ï NOT NULL ¤ÈÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó.",
-"function '%-.64s' ¤ò ¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó",
-"function '%-.64s' ¤ò½é´ü²½¤Ç¤­¤Þ¤»¤ó; %-.80s",
-"shared library ¤Ø¤Î¥Ñ¥¹¤¬Ä̤äƤ¤¤Þ¤»¤ó",
-"Function '%-.64s' ¤Ï´û¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤¹",
-"shared library '%-.64s' ¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d %s)",
-"function '%-.64s' ¤ò¥é¥¤¥Ö¥é¥ê¡¼Ãæ¤Ë¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó",
-"Function '%-.64s' ¤ÏÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
-"Host '%-.64s' ¤Ï many connection error ¤Î¤¿¤á¡¢µñÈݤµ¤ì¤Þ¤·¤¿. 'mysqladmin flush-hosts' ¤Ç²ò½ü¤·¤Æ¤¯¤À¤µ¤¤",
-"Host '%-.64s' ¤Ï MySQL server ¤ËÀܳ¤òµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
-"MySQL ¤ò anonymous users ¤Ç»ÈÍѤ·¤Æ¤¤¤ë¾õÂ֤Ǥϡ¢¥Ñ¥¹¥ï¡¼¥É¤ÎÊѹ¹¤Ï¤Ç¤­¤Þ¤»¤ó",
-"¾¤Î¥æ¡¼¥¶¡¼¤Î¥Ñ¥¹¥ï¡¼¥É¤òÊѹ¹¤¹¤ë¤¿¤á¤Ë¤Ï, mysql ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ËÂФ·¤Æ update ¤Îµö²Ä¤¬¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó.",
-"Can't find any matching row in the user table",
-"°ìÃ׿ô(Rows matched): %ld Êѹ¹: %ld Warnings: %ld",
-"¿·µ¬¤Ë¥¹¥ì¥Ã¥É¤¬ºî¤ì¤Þ¤»¤ó¤Ç¤·¤¿ (errno %d). ¤â¤·ºÇÂç»ÈÍѵö²Ä¥á¥â¥ê¡¼¿ô¤ò±Û¤¨¤Æ¤¤¤Ê¤¤¤Î¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Æ¤¤¤ë¤Ê¤é, ¥Þ¥Ë¥å¥¢¥ë¤ÎÃ椫¤é 'possible OS-dependent bug' ¤È¤¤¤¦Ê¸»ú¤òõ¤·¤Æ¤¯¤ß¤Æ¤À¤µ¤¤.",
-"Column count doesn't match value count at row %ld",
-"Can't reopen table: '%-.64s'",
-"NULL ÃͤλÈÍÑÊýË¡¤¬ÉÔŬÀڤǤ¹",
-"Got error '%-.64s' from regexp",
-"Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause",
-"¥æ¡¼¥¶¡¼ '%-.32s' (¥Û¥¹¥È '%-.64s' ¤Î¥æ¡¼¥¶¡¼) ¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
-"¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ,¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
-"¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s'\n ¥«¥é¥à '%-.64s' ¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
-"Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used.",
-"The host or user argument to GRANT is too long",
-"Table '%-.64s.%s' doesn't exist",
-"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
-"The used command is not allowed with this MySQL version",
-"Something is wrong in your syntax",
-"Delayed insert thread couldn't get requested lock for table %-.64s",
-"Too many delayed threads in use",
-"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
-"Got a packet bigger than 'max_allowed_packet' bytes",
-"Got a read error from the connection pipe",
-"Got an error from fcntl()",
-"Got packets out of order",
-"Couldn't uncompress communication packet",
-"Got an error reading communication packets",
-"Got timeout reading communication packets",
-"Got an error writing communication packets",
-"Got timeout writing communication packets",
-"Result string is longer than 'max_allowed_packet' bytes",
-"The used table type doesn't support BLOB/TEXT columns",
-"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
-"Incorrect column name '%-.100s'",
-"The used table handler can't index column '%-.64s'",
-"All tables in the MERGE table are not defined identically",
-"Can't write, because of unique constraint, to table '%-.64s'",
-"BLOB column '%-.64s' used in key specification without a key length",
-"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
-"This table type requires a primary key",
-"This version of MySQL is not compiled with RAID support",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got NDB error %d '%-.100s'",
-"Got temporary NDB error %d '%-.100s'",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
deleted file mode 100644
index 1cff50432e9..00000000000
--- a/sql/share/korean/errmsg.txt
+++ /dev/null
@@ -1,321 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-character-set=euckr
-
-"hashchk",
-"isamchk",
-"¾Æ´Ï¿À",
-"¿¹",
-"È­ÀÏ '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
-"Å×À̺í '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
-"µ¥ÀÌŸº£À̽º '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. (¿¡·¯¹øÈ£: %d)",
-"µ¥ÀÌŸº£À̽º '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÔ",
-"µ¥ÀÌŸº£À̽º '%-.64s'¸¦ Á¦°ÅÇÏÁö ¸øÇß½À´Ï´Ù. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÏÁö ¾ÊÀ½ ",
-"µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯('%-.64s'¸¦ »èÁ¦ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)",
-"µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯(rmdir '%-.64s'¸¦ ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)",
-"'%-.64s' »èÁ¦ Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)",
-"system Å×ÀÌºí¿¡¼­ ·¹Äڵ带 ÀÐÀ» ¼ö ¾ø½À´Ï´Ù.",
-"'%-.64s'ÀÇ »óŸ¦ ¾òÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
-"¼öÇà µð·ºÅ丮¸¦ ãÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
-"È­ÀÏÀ» Àá±×Áö(lock) ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
-"È­ÀÏÀ» ¿­Áö ¸øÇß½À´Ï´Ù.: '%-.64s' (¿¡·¯¹øÈ£: %d)",
-"È­ÀÏÀ» ãÁö ¸øÇß½À´Ï´Ù.: '%-.64s' (¿¡·¯¹øÈ£: %d)",
-"'%-.64s'µð·ºÅ丮¸¦ ÀÐÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
-"'%-.64s'µð·ºÅ丮·Î À̵¿ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)",
-"Å×À̺í '%-.64s'¿¡¼­ ¸¶Áö¸·À¸·Î ÀÐÀº ÈÄ Record°¡ º¯°æµÇ¾ú½À´Ï´Ù.",
-"Disk full (%s). ´Ù¸¥ »ç¶÷ÀÌ Áö¿ï¶§±îÁö ±â´Ù¸³´Ï´Ù...",
-"±â·ÏÇÒ ¼ö ¾øÀ¾´Ï´Ù., Å×À̺í '%-.64s'¿¡¼­ Áߺ¹ Å°",
-"'%-.64s'´Ý´Â Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)",
-"'%-.64s'È­ÀÏ Àб⠿¡·¯ (¿¡·¯¹øÈ£: %d)",
-"'%-.64s'¸¦ '%-.64s'·Î À̸§ º¯°æÁß ¿¡·¯ (¿¡·¯¹øÈ£: %d)",
-"'%-.64s'È­ÀÏ ±â·Ï Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)",
-"'%-.64s'°¡ º¯°æÇÒ ¼ö ¾øµµ·Ï Àá°ÜÀÖÀ¾´Ï´Ù.",
-"¼ÒÆ®°¡ ÁߴܵǾú½À´Ï´Ù.",
-"ºä '%-.64s'°¡ '%-.64s'¿¡¼­´Â Á¸ÀçÇÏÁö ¾ÊÀ¾´Ï´Ù.",
-"Å×À̺í handler¿¡¼­ %d ¿¡·¯°¡ ¹ß»ý ÇÏ¿´½À´Ï´Ù.",
-"'%-.64s'ÀÇ Å×À̺í handler´Â ÀÌ·¯ÇÑ ¿É¼ÇÀ» Á¦°øÇÏÁö ¾ÊÀ¾´Ï´Ù.",
-"'%-.64s'¿¡¼­ ·¹Äڵ带 ãÀ» ¼ö ¾øÀ¾´Ï´Ù.",
-"È­ÀÏÀÇ ºÎÁ¤È®ÇÑ Á¤º¸: '%-.64s'",
-"'%-.64s' Å×À̺íÀÇ ºÎÁ¤È®ÇÑ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!",
-"'%-.64s' Å×À̺íÀÇ ÀÌÀü¹öÁ¯ÀÇ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!",
-"Å×À̺í '%-.64s'´Â ÀбâÀü¿ë ÀÔ´Ï´Ù.",
-"Out of memory. µ¥¸óÀ» Àç ½ÇÇà ÈÄ ´Ù½Ã ½ÃÀÛÇϽÿÀ (needed %d bytes)",
-"Out of sort memory. daemon sort bufferÀÇ Å©±â¸¦ Áõ°¡½ÃÅ°¼¼¿ä",
-"'%-.64s' È­ÀÏÀ» Àд µµÁß À߸øµÈ eofÀ» ¹ß°ß (¿¡·¯¹øÈ£: %d)",
-"³Ê¹« ¸¹Àº ¿¬°á... max_connectionÀ» Áõ°¡ ½ÃÅ°½Ã¿À...",
-"Out of memory; mysqld³ª ¶Ç´Ù¸¥ ÇÁ·Î¼¼¼­¿¡¼­ »ç¿ë°¡´ÉÇÑ ¸Þ¸ð¸®¸¦ »ç¿ëÇÑÁö äũÇϽÿÀ. ¸¸¾à ±×·¸Áö ¾Ê´Ù¸é ulimit ¸í·ÉÀ» ÀÌ¿¿ëÇÏ¿© ´õ¸¹Àº ¸Þ¸ð¸®¸¦ »ç¿ëÇÒ ¼ö ÀÖµµ·Ï Çϰųª ½º¿Ò ½ºÆÐÀ̽º¸¦ Áõ°¡½ÃÅ°½Ã¿À",
-"´ç½ÅÀÇ ÄÄÇ»ÅÍÀÇ È£½ºÆ®À̸§À» ¾òÀ» ¼ö ¾øÀ¾´Ï´Ù.",
-"Bad handshake",
-"'%-.32s'@'%-.64s' »ç¿ëÀÚ´Â '%-.64s' µ¥ÀÌŸº£À̽º¿¡ Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù.",
-"'%-.32s'@'%-.64s' »ç¿ëÀÚ´Â Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù. (using password: %s)",
-"¼±ÅÃµÈ µ¥ÀÌŸº£À̽º°¡ ¾ø½À´Ï´Ù.",
-"¸í·É¾î°¡ ¹ºÁö ¸ð¸£°Ú¾î¿ä...",
-"Ä®·³ '%-.64s'´Â ³Î(Null)ÀÌ µÇ¸é ¾ÈµË´Ï´Ù. ",
-"µ¥ÀÌŸº£À̽º '%-.64s'´Â ¾Ë¼ö ¾øÀ½",
-"Å×À̺í '%-.64s'´Â ÀÌ¹Ì Á¸ÀçÇÔ",
-"Å×À̺í '%-.64s'´Â ¾Ë¼ö ¾øÀ½",
-"Ä®·³: '%-.64s' in '%-.64s' ÀÌ ¸ðÈ£ÇÔ",
-"Server°¡ ¼Ë´Ù¿î ÁßÀÔ´Ï´Ù.",
-"Unknown Ä®·³ '%-.64s' in '%-.64s'",
-"'%-.64s'Àº GROUP BY¼Ó¿¡ ¾øÀ½",
-"'%-.64s'¸¦ ±×·ìÇÒ ¼ö ¾øÀ½",
-"Statement °¡ sum±â´ÉÀ» µ¿ÀÛÁßÀÌ°í Ä®·³µµ µ¿ÀÏÇÑ statementÀÔ´Ï´Ù.",
-"Ä®·³ÀÇ Ä«¿îÆ®°¡ °ªÀÇ Ä«¿îÆ®¿Í ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù.",
-"Identifier '%-.100s'´Â ³Ê¹« ±æ±º¿ä.",
-"Áߺ¹µÈ Ä®·³ À̸§: '%-.64s'",
-"Áߺ¹µÈ Å° À̸§ : '%-.64s'",
-"Áߺ¹µÈ ÀÔ·Â °ª '%-.64s': key %d",
-"Ä®·³ '%-.64s'ÀÇ ºÎÁ¤È®ÇÑ Ä®·³ Á¤ÀÇÀÚ",
-"'%-.64s' ¿¡·¯ °°À¾´Ï´Ù. ('%-.80s' ¸í·É¾î ¶óÀÎ %d)",
-"Äõ¸®°á°ú°¡ ¾ø½À´Ï´Ù.",
-"Unique ÇÏÁö ¾ÊÀº Å×À̺í/alias: '%-.64s'",
-"'%-.64s'ÀÇ À¯È¿ÇÏÁö ¸øÇÑ µðÆúÆ® °ªÀ» »ç¿ëÇϼ̽À´Ï´Ù.",
-"Multiple primary key°¡ Á¤ÀǵǾî ÀÖ½¿",
-"³Ê¹« ¸¹Àº Å°°¡ Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.. ÃÖ´ë %dÀÇ Å°°¡ °¡´ÉÇÔ",
-"³Ê¹« ¸¹Àº Å° ºÎºÐ(parts)µéÀÌ Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.. ÃÖ´ë %d ºÎºÐÀÌ °¡´ÉÇÔ",
-"Á¤ÀÇµÈ Å°°¡ ³Ê¹« ±é´Ï´Ù. ÃÖ´ë Å°ÀÇ ±æÀÌ´Â %dÀÔ´Ï´Ù.",
-"Key Ä®·³ '%-.64s'´Â Å×ÀÌºí¿¡ Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù.",
-"BLOB Ä®·³ '%-.64s'´Â Å° Á¤ÀÇ¿¡¼­ »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù.",
-"Ä®·³ '%-.64s'ÀÇ Ä®·³ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %d). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä.",
-"ºÎÁ¤È®ÇÑ Å×À̺í Á¤ÀÇ; Å×À̺íÀº ÇϳªÀÇ auto Ä®·³ÀÌ Á¸ÀçÇÏ°í Å°·Î Á¤ÀǵǾîÁ®¾ß ÇÕ´Ï´Ù.",
-"%s: ¿¬°á ÁغñÁßÀÔ´Ï´Ù",
-"%s: Á¤»óÀûÀÎ shutdown\n",
-"%s: %d ½ÅÈ£°¡ µé¾î¿ÔÀ½. ÁßÁö!\n",
-"%s: Shutdown ÀÌ ¿Ï·áµÊ!\n",
-"%s: thread %ldÀÇ °­Á¦ Á¾·á user: '%-.64s'\n",
-"IP ¼ÒÄÏÀ» ¸¸µéÁö ¸øÇß½À´Ï´Ù.",
-"Å×À̺í '%-.64s'´Â À妽º¸¦ ¸¸µéÁö ¾Ê¾Ò½À´Ï´Ù. alter Å×À̺í¸í·ÉÀ» ÀÌ¿ëÇÏ¿© Å×À̺íÀ» ¼öÁ¤Çϼ¼¿ä...",
-"ÇÊµå ±¸ºÐÀÚ ÀμöµéÀÌ ¿ÏÀüÇÏÁö ¾Ê½À´Ï´Ù. ¸Þ´º¾óÀ» ã¾Æ º¸¼¼¿ä.",
-"BLOB·Î´Â °íÁ¤±æÀÌÀÇ lowlength¸¦ »ç¿ëÇÒ ¼ö ¾ø½À´Ï´Ù. 'fields terminated by'¸¦ »ç¿ëÇϼ¼¿ä.",
-"'%-.64s' È­ÀÏ´Â µ¥ÀÌŸº£À̽º µð·ºÅ丮¿¡ Á¸ÀçÇϰųª ¸ðµÎ¿¡°Ô Àб⠰¡´ÉÇÏ¿©¾ß ÇÕ´Ï´Ù.",
-"'%-.64s' È­ÀÏÀº ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù.",
-"·¹ÄÚµå: %ld°³ »èÁ¦: %ld°³ ½ºÅµ: %ld°³ °æ°í: %ld°³",
-"·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³",
-"ºÎÁ¤È®ÇÑ ¼­¹ö ÆÄÆ® Å°. »ç¿ëµÈ Å° ÆÄÆ®°¡ ½ºÆ®¸µÀÌ ¾Æ´Ï°Å³ª Å° ÆÄÆ®ÀÇ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù.",
-"ALTER TABLE ¸í·ÉÀ¸·Î´Â ¸ðµç Ä®·³À» Áö¿ï ¼ö ¾ø½À´Ï´Ù. DROP TABLE ¸í·ÉÀ» ÀÌ¿ëÇϼ¼¿ä.",
-"'%-.64s'¸¦ DROPÇÒ ¼ö ¾ø½À´Ï´Ù. Ä®·³À̳ª Å°°¡ Á¸ÀçÇÏ´ÂÁö äũÇϼ¼¿ä.",
-"·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³ °æ°í: %ld°³",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"¾Ë¼ö ¾ø´Â ¾²·¹µå id: %lu",
-"¾²·¹µå(Thread) %luÀÇ ¼ÒÀ¯ÀÚ°¡ ¾Æ´Õ´Ï´Ù.",
-"¾î¶² Å×ÀÌºíµµ »ç¿ëµÇÁö ¾Ê¾Ò½À´Ï´Ù.",
-"Ä®·³ %-.64s¿Í SET¿¡¼­ ½ºÆ®¸µÀÌ ³Ê¹« ¸¹½À´Ï´Ù.",
-"Unique ·Î±×È­ÀÏ '%-.64s'¸¦ ¸¸µé¼ö ¾ø½À´Ï´Ù.(1-999)\n",
-"Å×À̺í '%-.64s'´Â READ ¶ôÀÌ Àá°ÜÀ־ °»½ÅÇÒ ¼ö ¾ø½À´Ï´Ù.",
-"Å×À̺í '%-.64s'´Â LOCK TABLES ¸í·ÉÀ¸·Î Àá±âÁö ¾Ê¾Ò½À´Ï´Ù.",
-"BLOB Ä®·³ '%-.64s' ´Â µðÆúÆ® °ªÀ» °¡Áú ¼ö ¾ø½À´Ï´Ù.",
-"'%-.100s' µ¥ÀÌŸº£À̽ºÀÇ À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù.",
-"'%-.100s' Å×À̺í À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù.",
-"SELECT ¸í·É¿¡¼­ ³Ê¹« ¸¹Àº ·¹Äڵ带 ã±â ¶§¹®¿¡ ¸¹Àº ½Ã°£ÀÌ ¼Ò¿äµË´Ï´Ù. µû¶ó¼­ WHERE ¹®À» Á¡°ËÇϰųª, ¸¸¾à SELECT°¡ okµÇ¸é SET SQL_BIG_SELECTS=1 ¿É¼ÇÀ» »ç¿ëÇϼ¼¿ä.",
-"¾Ë¼ö ¾ø´Â ¿¡·¯ÀÔ´Ï´Ù.",
-"¾Ë¼ö ¾ø´Â ¼öÇ๮ : '%-.64s'",
-"'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ",
-"'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ",
-"¾Ë¼ö ¾ø´Â Å×À̺í '%-.64s' (µ¥ÀÌŸº£À̽º %s)",
-"Ä®·³ '%-.64s'´Â µÎ¹ø Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù.",
-"À߸øµÈ ±×·ì ÇÔ¼ö¸¦ »ç¿ëÇÏ¿´½À´Ï´Ù.",
-"Å×À̺í '%-.64s'´Â È®Àå¸í·ÉÀ» ÀÌ¿ëÇÏÁö¸¸ ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù.",
-"ÇϳªÀÇ Å×ÀÌºí¿¡¼­´Â Àû¾îµµ ÇϳªÀÇ Ä®·³ÀÌ Á¸ÀçÇÏ¿©¾ß ÇÕ´Ï´Ù.",
-"Å×À̺í '%-.64s'°¡ full³µ½À´Ï´Ù. ",
-"¾Ë¼ö¾ø´Â ¾ð¾î Set: '%-.64s'",
-"³Ê¹« ¸¹Àº Å×À̺íÀÌ JoinµÇ¾ú½À´Ï´Ù. MySQL¿¡¼­´Â JOIN½Ã %d°³ÀÇ Å×ÀÌºí¸¸ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù.",
-"Ä®·³ÀÌ ³Ê¹« ¸¹½À´Ï´Ù.",
-"³Ê¹« Å« row »çÀÌÁîÀÔ´Ï´Ù. BLOB¸¦ °è»êÇÏÁö ¾Ê°í ÃÖ´ë row »çÀÌÁî´Â %dÀÔ´Ï´Ù. ¾ó¸¶°£ÀÇ ÇʵåµéÀ» BLOB·Î ¹Ù²Ù¼Å¾ß °Ú±º¿ä..",
-"¾²·¹µå ½ºÅÃÀÌ ³ÑÃƽÀ´Ï´Ù. »ç¿ë: %ld°³ ½ºÅÃ: %ld°³. ¸¸¾à ÇÊ¿ä½Ã ´õÅ« ½ºÅÃÀ» ¿øÇÒ¶§¿¡´Â 'mysqld -O thread_stack=#' ¸¦ Á¤ÀÇÇϼ¼¿ä",
-"Cross dependency found in OUTER JOIN; examine your ON conditions",
-"'%-.64s' Ä®·³ÀÌ UNIQUE³ª INDEX¸¦ »ç¿ëÇÏ¿´Áö¸¸ NOT NULLÀÌ Á¤ÀǵÇÁö ¾Ê¾Ò±º¿ä...",
-"'%-.64s' ÇÔ¼ö¸¦ ·ÎµåÇÏÁö ¸øÇß½À´Ï´Ù.",
-"'%-.64s' ÇÔ¼ö¸¦ ÃʱâÈ­ ÇÏÁö ¸øÇß½À´Ï´Ù.; %-.80s",
-"°øÀ¯ ¶óÀ̹ö·¯¸®¸¦ À§ÇÑ Æнº°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù.",
-"'%-.64s' ÇÔ¼ö´Â ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù.",
-"'%-.64s' °øÀ¯ ¶óÀ̹ö·¯¸®¸¦ ¿­¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£: %d %s)",
-"¶óÀ̹ö·¯¸®¿¡¼­ '%-.64s' ÇÔ¼ö¸¦ ãÀ» ¼ö ¾ø½À´Ï´Ù.",
-"'%-.64s' ÇÔ¼ö°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù.",
-"³Ê¹« ¸¹Àº ¿¬°á¿À·ù·Î ÀÎÇÏ¿© È£½ºÆ® '%-.64s'´Â ºí¶ôµÇ¾ú½À´Ï´Ù. 'mysqladmin flush-hosts'¸¦ ÀÌ¿ëÇÏ¿© ºí¶ôÀ» ÇØÁ¦Çϼ¼¿ä",
-"'%-.64s' È£½ºÆ®´Â ÀÌ MySQL¼­¹ö¿¡ Á¢¼ÓÇÒ Çã°¡¸¦ ¹ÞÁö ¸øÇß½À´Ï´Ù.",
-"´ç½ÅÀº MySQL¼­¹ö¿¡ À͸íÀÇ »ç¿ëÀÚ·Î Á¢¼ÓÀ» Çϼ̽À´Ï´Ù.À͸íÀÇ »ç¿ëÀÚ´Â ¾ÏÈ£¸¦ º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù.",
-"´ç½ÅÀº ´Ù¸¥»ç¿ëÀÚµéÀÇ ¾ÏÈ£¸¦ º¯°æÇÒ ¼ö ÀÖµµ·Ï µ¥ÀÌŸº£À̽º º¯°æ±ÇÇÑÀ» °¡Á®¾ß ÇÕ´Ï´Ù.",
-"»ç¿ëÀÚ Å×ÀÌºí¿¡¼­ ÀÏÄ¡ÇÏ´Â °ÍÀ» ãÀ» ¼ö ¾øÀ¾´Ï´Ù.",
-"ÀÏÄ¡ÇÏ´Â Rows : %ld°³ º¯°æµÊ: %ld°³ °æ°í: %ld°³",
-"»õ·Î¿î ¾²·¹µå¸¦ ¸¸µé ¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£ %d). ¸¸¾à ¿©À¯¸Þ¸ð¸®°¡ ÀÖ´Ù¸é OS-dependent¹ö±× ÀÇ ¸Þ´º¾ó ºÎºÐÀ» ã¾Æº¸½Ã¿À.",
-"Row %ld¿¡¼­ Ä®·³ Ä«¿îÆ®¿Í value Ä«¿îÅÍ¿Í ÀÏÄ¡ÇÏÁö ¾Ê½À´Ï´Ù.",
-"Å×À̺íÀ» ´Ù½Ã ¿­¼ö ¾ø±º¿ä: '%-.64s",
-"NULL °ªÀ» À߸ø »ç¿ëÇϼ̱º¿ä...",
-"regexp¿¡¼­ '%-.64s'°¡ ³µ½À´Ï´Ù.",
-"Mixing of GROUP Ä®·³s (MIN(),MAX(),COUNT(),...) with no GROUP Ä®·³s is illegal if there is no GROUP BY clause",
-"»ç¿ëÀÚ '%-.32s' (È£½ºÆ® '%-.64s')¸¦ À§ÇÏ¿© Á¤ÀÇµÈ ±×·± ½ÂÀÎÀº ¾ø½À´Ï´Ù.",
-"'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s'@'%-.64s' for Å×À̺í '%-.64s'",
-"'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s'@'%-.64s' for Ä®·³ '%-.64s' in Å×À̺í '%-.64s'",
-"À߸øµÈ GRANT/REVOKE ¸í·É. ¾î¶² ±Ç¸®¿Í ½ÂÀÎÀÌ »ç¿ëµÇ¾î Áú ¼ö ÀÖ´ÂÁö ¸Þ´º¾óÀ» º¸½Ã¿À.",
-"½ÂÀÎ(GRANT)À» À§ÇÏ¿© »ç¿ëÇÑ »ç¿ëÀÚ³ª È£½ºÆ®ÀÇ °ªµéÀÌ ³Ê¹« ±é´Ï´Ù.",
-"Å×À̺í '%-.64s.%s' ´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù.",
-"»ç¿ëÀÚ '%-.32s'(È£½ºÆ® '%-.64s')´Â Å×À̺í '%-.64s'¸¦ »ç¿ëÇϱâ À§ÇÏ¿© Á¤ÀÇµÈ ½ÂÀÎÀº ¾ø½À´Ï´Ù. ",
-"»ç¿ëµÈ ¸í·ÉÀº ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â ÀÌ¿ëµÇÁö ¾Ê½À´Ï´Ù.",
-"SQL ±¸¹®¿¡ ¿À·ù°¡ ÀÖ½À´Ï´Ù.",
-"Áö¿¬µÈ insert ¾²·¹µå°¡ Å×À̺í %-.64sÀÇ ¿ä±¸µÈ ¶ôÅ·À» ó¸®ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù.",
-"³Ê¹« ¸¹Àº Áö¿¬ ¾²·¹µå¸¦ »ç¿ëÇÏ°í ÀÖ½À´Ï´Ù.",
-"µ¥ÀÌŸº£À̽º Á¢¼ÓÀ» À§ÇÑ ¿¬°á %ld°¡ Áß´ÜµÊ : '%-.64s' »ç¿ëÀÚ: '%-.64s' (%s)",
-"'max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù.",
-"¿¬°á ÆÄÀÌÇÁ·ÎºÎÅÍ ¿¡·¯°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
-"fcntl() ÇÔ¼ö·ÎºÎÅÍ ¿¡·¯°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
-"¼ø¼­°¡ ¸ÂÁö¾Ê´Â ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù.",
-"Åë½Å ÆÐŶÀÇ ¾ÐÃàÇØÁ¦¸¦ ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù.",
-"Åë½Å ÆÐŶÀ» Àд Áß ¿À·ù°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
-"Åë½Å ÆÐŶÀ» Àд Áß timeoutÀÌ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
-"Åë½Å ÆÐŶÀ» ±â·ÏÇÏ´Â Áß ¿À·ù°¡ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
-"Åë½Å ÆÐÆÂÀ» ±â·ÏÇÏ´Â Áß timeoutÀÌ ¹ß»ýÇÏ¿´½À´Ï´Ù.",
-"Result string is longer than 'max_allowed_packet' bytes",
-"The used table type doesn't support BLOB/TEXT columns",
-"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
-"Incorrect column name '%-.100s'",
-"The used table handler can't index column '%-.64s'",
-"All tables in the MERGE table are not defined identically",
-"Can't write, because of unique constraint, to table '%-.64s'",
-"BLOB column '%-.64s' used in key specification without a key length",
-"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
-"This table type requires a primary key",
-"This version of MySQL is not compiled with RAID support",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
deleted file mode 100644
index 27f7a18f029..00000000000
--- a/sql/share/norwegian-ny/errmsg.txt
+++ /dev/null
@@ -1,323 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Roy-Magne Mo rmo@www.hivolda.no 97 */
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NEI",
-"JA",
-"Kan ikkje opprette fila '%-.64s' (Feilkode: %d)",
-"Kan ikkje opprette tabellen '%-.64s' (Feilkode: %d)",
-"Kan ikkje opprette databasen '%-.64s' (Feilkode: %d)",
-"Kan ikkje opprette databasen '%-.64s'; databasen eksisterer",
-"Kan ikkje fjerne (drop) '%-.64s'; databasen eksisterer ikkje",
-"Feil ved fjerning (drop) av databasen (kan ikkje slette '%-.64s', feil %d)",
-"Feil ved sletting av database (kan ikkje slette katalogen '%-.64s', feil %d)",
-"Feil ved sletting av '%-.64s' (Feilkode: %d)",
-"Kan ikkje lese posten i systemkatalogen",
-"Kan ikkje lese statusen til '%-.64s' (Feilkode: %d)",
-"Kan ikkje lese aktiv katalog(Feilkode: %d)",
-"Kan ikkje låse fila (Feilkode: %d)",
-"Kan ikkje åpne fila: '%-.64s' (Feilkode: %d)",
-"Kan ikkje finne fila: '%-.64s' (Feilkode: %d)",
-"Kan ikkje lese katalogen '%-.64s' (Feilkode: %d)",
-"Kan ikkje skifte katalog til '%-.64s' (Feilkode: %d)",
-"Posten har vorte endra sidan den sist vart lesen '%-.64s'",
-"Ikkje meir diskplass (%s). Ventar på å få frigjort plass...",
-"Kan ikkje skrive, flere like nyklar i tabellen '%-.64s'",
-"Feil ved lukking av '%-.64s' (Feilkode: %d)",
-"Feil ved lesing av '%-.64s' (Feilkode: %d)",
-"Feil ved omdøyping av '%-.64s' til '%-.64s' (Feilkode: %d)",
-"Feil ved skriving av fila '%-.64s' (Feilkode: %d)",
-"'%-.64s' er låst mot oppdateringar",
-"Sortering avbrote",
-"View '%-.64s' eksisterar ikkje for '%-.64s'",
-"Mottok feil %d fra tabell handterar",
-"Tabell håndteraren for '%-.64s' har ikkje denne moglegheita",
-"Kan ikkje finne posten i '%-.64s'",
-"Feil informasjon i fila: '%-.64s'",
-"Tabellen '%-.64s' har feil i nykkelfila; prøv å reparere den",
-"Gammel nykkelfil for tabellen '%-.64s'; reparer den!",
-"'%-.64s' er skrivetryggja",
-"Ikkje meir minne. Start på nytt tenesten og prøv igjen (trengte %d bytar)",
-"Ikkje meir sorteringsminne. Auk sorteringsminnet (sorteringsbffer storleik) for tenesten",
-"Uventa slutt på fil (eof) ved lesing av fila '%-.64s' (Feilkode: %d)",
-"For mange tilkoplingar (connections)",
-"Tomt for tråd plass/minne",
-"Kan ikkje få tak i vertsnavn for di adresse",
-"Feil handtrykk (handshake)",
-"Tilgang ikkje tillate for brukar: '%-.32s'@'%-.64s' til databasen '%-.64s' nekta",
-"Tilgang ikke tillate for brukar: '%-.32s'@'%-.64s' (Brukar passord: %s)",
-"Ingen database vald",
-"Ukjent kommando",
-"Kolonne '%-.64s' kan ikkje vere null",
-"Ukjent database '%-.64s'",
-"Tabellen '%-.64s' eksisterar allereide",
-"Ukjent tabell '%-.64s'",
-"Kolonne: '%-.64s' i tabell %s er ikkje eintydig",
-"Tenar nedkopling er i gang",
-"Ukjent felt '%-.64s' i tabell %s",
-"Brukte '%-.64s' som ikkje var i group by",
-"Kan ikkje gruppere på '%-.64s'",
-"Uttrykket har summer (sum) funksjoner og kolonner i same uttrykk",
-"Kolonne telling stemmer verdi telling",
-"Identifikator '%-.64s' er for lang",
-"Feltnamnet '%-.64s' eksisterte frå før",
-"Nøkkelnamnet '%-.64s' eksisterte frå før",
-"Like verdiar '%-.64s' for nykkel %d",
-"Feil kolonne spesifikator for kolonne '%-.64s'",
-"%s attmed '%-.64s' på line %d",
-"Førespurnad var tom",
-"Ikkje unikt tabell/alias: '%-.64s'",
-"Ugyldig standardverdi for '%-.64s'",
-"Fleire primærnyklar spesifisert",
-"For mange nykler spesifisert. Maks %d nyklar tillatt",
-"For mange nykkeldelar spesifisert. Maks %d delar tillatt",
-"Spesifisert nykkel var for lang. Maks nykkellengde er %d",
-"Nykkel kolonne '%-.64s' eksiterar ikkje i tabellen",
-"Blob kolonne '%-.64s' kan ikkje brukast ved spesifikasjon av nyklar",
-"For stor nykkellengde for felt '%-.64s' (maks = %d). Bruk BLOB istadenfor",
-"Bare eitt auto felt kan være definert som nøkkel.",
-"%s: klar for tilkoblingar",
-"%s: Normal nedkopling\n",
-"%s: Oppdaga signal %d. Avsluttar!\n",
-"%s: Nedkopling komplett\n",
-"%s: Påtvinga avslutning av tråd %ld brukar: '%-.64s'\n",
-"Kan ikkje opprette IP socket",
-"Tabellen '%-.64s' har ingen index som den som er brukt i CREATE INDEX. Oprett tabellen på nytt",
-"Felt skiljer argumenta er ikkje som venta, sjå dokumentasjonen",
-"Ein kan ikkje bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'.",
-"Filen '%-.64s' må være i database-katalogen for å være lesbar for alle",
-"Filen '%-.64s' eksisterte allereide",
-"Poster: %ld Fjerna: %ld Hoppa over: %ld Åtvaringar: %ld",
-"Poster: %ld Like: %ld",
-"Feil delnykkel. Den brukte delnykkelen er ikkje ein streng eller den oppgitte lengda er lengre enn nykkellengden",
-"Ein kan ikkje slette alle felt med ALTER TABLE. Bruk DROP TABLE istadenfor.",
-"Kan ikkje DROP '%-.64s'. Undersøk om felt/nøkkel eksisterar.",
-"Postar: %ld Like: %ld Åtvaringar: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Ukjent tråd id: %lu",
-"Du er ikkje eigar av tråd %lu",
-"Ingen tabellar i bruk",
-"For mange tekststrengar felt %s og SET",
-"Kan ikkje lage unikt loggfilnavn %s.(1-999)\n",
-"Tabellen '%-.64s' var låst med READ lås og kan ikkje oppdaterast",
-"Tabellen '%-.64s' var ikkje låst med LOCK TABLES",
-"Blob feltet '%-.64s' kan ikkje ha ein standard verdi",
-"Ugyldig database namn '%-.64s'",
-"Ugyldig tabell namn '%-.64s'",
-"SELECT ville undersøkje for mange postar og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt",
-"Ukjend feil",
-"Ukjend prosedyre %s",
-"Feil parameter tal til prosedyra %s",
-"Feil parameter til prosedyra %s",
-"Ukjend tabell '%-.64s' i %s",
-"Feltet '%-.64s' er spesifisert to gangar",
-"Invalid use of group function",
-"Table '%-.64s' uses a extension that doesn't exist in this MySQL version",
-"A table must have at least 1 column",
-"The table '%-.64s' is full",
-"Unknown character set: '%-.64s'",
-"Too many tables; MySQL can only use %d tables in a join",
-"Too many columns",
-"Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs",
-"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
-"Cross dependency found in OUTER JOIN; examine your ON conditions",
-"Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
-"Can't load function '%-.64s'",
-"Can't initialize function '%-.64s'; %-.80s",
-"No paths allowed for shared library",
-"Function '%-.64s' already exists",
-"Can't open shared library '%-.64s' (errno: %d %s)",
-"Can't find function '%-.64s' in library'",
-"Function '%-.64s' is not defined",
-"Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'",
-"Host '%-.64s' is not allowed to connect to this MySQL server",
-"You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords",
-"You must have privileges to update tables in the mysql database to be able to change passwords for others",
-"Can't find any matching row in the user table",
-"Rows matched: %ld Changed: %ld Warnings: %ld",
-"Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug",
-"Column count doesn't match value count at row %ld",
-"Can't reopen table: '%-.64s",
-"Invalid use of NULL value",
-"Got error '%-.64s' from regexp",
-"Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause",
-"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for table '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
-"Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used.",
-"The host or user argument to GRANT is too long",
-"Table '%-.64s.%s' doesn't exist",
-"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
-"The used command is not allowed with this MySQL version",
-"Something is wrong in your syntax",
-"Delayed insert thread couldn't get requested lock for table %-.64s",
-"Too many delayed threads in use",
-"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
-"Got a packet bigger than 'max_allowed_packet' bytes",
-"Got a read error from the connection pipe",
-"Got an error from fcntl()",
-"Got packets out of order",
-"Couldn't uncompress communication packet",
-"Got an error reading communication packets",
-"Got timeout reading communication packets",
-"Got an error writing communication packets",
-"Got timeout writing communication packets",
-"Result string is longer than 'max_allowed_packet' bytes",
-"The used table type doesn't support BLOB/TEXT columns",
-"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
-"Incorrect column name '%-.100s'",
-"The used table handler can't index column '%-.64s'",
-"All tables in the MERGE table are not defined identically",
-"Can't write, because of unique constraint, to table '%-.64s'",
-"BLOB column '%-.64s' used in key specification without a key length",
-"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
-"This table type requires a primary key",
-"This version of MySQL is not compiled with RAID support",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Mottok feil %d '%-.100s' fra %s",
-"Mottok temporary feil %d '%-.100s' fra %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
deleted file mode 100644
index 772f30e5d94..00000000000
--- a/sql/share/norwegian/errmsg.txt
+++ /dev/null
@@ -1,323 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Roy-Magne Mo rmo@www.hivolda.no 97 */
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NEI",
-"JA",
-"Kan ikke opprette fila '%-.64s' (Feilkode: %d)",
-"Kan ikke opprette tabellen '%-.64s' (Feilkode: %d)",
-"Kan ikke opprette databasen '%-.64s' (Feilkode: %d)",
-"Kan ikke opprette databasen '%-.64s'; databasen eksisterer",
-"Kan ikke fjerne (drop) '%-.64s'; databasen eksisterer ikke",
-"Feil ved fjerning (drop) av databasen (kan ikke slette '%-.64s', feil %d)",
-"Feil ved sletting av database (kan ikke slette katalogen '%-.64s', feil %d)",
-"Feil ved sletting av '%-.64s' (Feilkode: %d)",
-"Kan ikke lese posten i systemkatalogen",
-"Kan ikke lese statusen til '%-.64s' (Feilkode: %d)",
-"Kan ikke lese aktiv katalog(Feilkode: %d)",
-"Kan ikke låse fila (Feilkode: %d)",
-"Kan ikke åpne fila: '%-.64s' (Feilkode: %d)",
-"Kan ikke finne fila: '%-.64s' (Feilkode: %d)",
-"Kan ikke lese katalogen '%-.64s' (Feilkode: %d)",
-"Kan ikke skifte katalog til '%-.64s' (Feilkode: %d)",
-"Posten har blitt endret siden den ble lest '%-.64s'",
-"Ikke mer diskplass (%s). Venter på å få frigjort plass...",
-"Kan ikke skrive, flere like nøkler i tabellen '%-.64s'",
-"Feil ved lukking av '%-.64s' (Feilkode: %d)",
-"Feil ved lesing av '%-.64s' (Feilkode: %d)",
-"Feil ved omdøping av '%-.64s' til '%-.64s' (Feilkode: %d)",
-"Feil ved skriving av fila '%-.64s' (Feilkode: %d)",
-"'%-.64s' er låst mot oppdateringer",
-"Sortering avbrutt",
-"View '%-.64s' eksisterer ikke for '%-.64s'",
-"Mottok feil %d fra tabell håndterer",
-"Tabell håndtereren for '%-.64s' har ikke denne muligheten",
-"Kan ikke finne posten i '%-.64s'",
-"Feil informasjon i filen: '%-.64s'",
-"Tabellen '%-.64s' har feil i nøkkelfilen; forsøk å reparer den",
-"Gammel nøkkelfil for tabellen '%-.64s'; reparer den!",
-"'%-.64s' er skrivebeskyttet",
-"Ikke mer minne. Star på nytt tjenesten og prøv igjen (trengte %d byter)",
-"Ikke mer sorteringsminne. Øk sorteringsminnet (sort buffer size) for tjenesten",
-"Uventet slutt på fil (eof) ved lesing av filen '%-.64s' (Feilkode: %d)",
-"For mange tilkoblinger (connections)",
-"Tomt for tråd plass/minne",
-"Kan ikke få tak i vertsnavn for din adresse",
-"Feil håndtrykk (handshake)",
-"Tilgang nektet for bruker: '%-.32s'@'%-.64s' til databasen '%-.64s' nektet",
-"Tilgang nektet for bruker: '%-.32s'@'%-.64s' (Bruker passord: %s)",
-"Ingen database valgt",
-"Ukjent kommando",
-"Kolonne '%-.64s' kan ikke vere null",
-"Ukjent database '%-.64s'",
-"Tabellen '%-.64s' eksisterer allerede",
-"Ukjent tabell '%-.64s'",
-"Felt: '%-.64s' i tabell %s er ikke entydig",
-"Database nedkobling er i gang",
-"Ukjent kolonne '%-.64s' i tabell %s",
-"Brukte '%-.64s' som ikke var i group by",
-"Kan ikke gruppere på '%-.64s'",
-"Uttrykket har summer (sum) funksjoner og kolonner i samme uttrykk",
-"Felt telling stemmer verdi telling",
-"Identifikator '%-.64s' er for lang",
-"Feltnavnet '%-.64s' eksisterte fra før",
-"Nøkkelnavnet '%-.64s' eksisterte fra før",
-"Like verdier '%-.64s' for nøkkel %d",
-"Feil kolonne spesifikator for felt '%-.64s'",
-"%s nær '%-.64s' på linje %d",
-"Forespørsel var tom",
-"Ikke unikt tabell/alias: '%-.64s'",
-"Ugyldig standardverdi for '%-.64s'",
-"Fleire primærnøkle spesifisert",
-"For mange nøkler spesifisert. Maks %d nøkler tillatt",
-"For mange nøkkeldeler spesifisert. Maks %d deler tillatt",
-"Spesifisert nøkkel var for lang. Maks nøkkellengde er is %d",
-"Nøkkel felt '%-.64s' eksiterer ikke i tabellen",
-"Blob felt '%-.64s' kan ikke brukes ved spesifikasjon av nøkler",
-"For stor nøkkellengde for kolonne '%-.64s' (maks = %d). Bruk BLOB istedenfor",
-"Bare ett auto felt kan være definert som nøkkel.",
-"%s: klar for tilkoblinger",
-"%s: Normal avslutning\n",
-"%s: Oppdaget signal %d. Avslutter!\n",
-"%s: Avslutning komplett\n",
-"%s: Påtvinget avslutning av tråd %ld bruker: '%-.64s'\n",
-"Kan ikke opprette IP socket",
-"Tabellen '%-.64s' har ingen index som den som er brukt i CREATE INDEX. Gjenopprett tabellen",
-"Felt skiller argumentene er ikke som forventet, se dokumentasjonen",
-"En kan ikke bruke faste feltlengder med BLOB. Vennlisgt bruk 'fields terminated by'.",
-"Filen '%-.64s' må være i database-katalogen for å være lesbar for alle",
-"Filen '%-.64s' eksisterte allerede",
-"Poster: %ld Fjernet: %ld Hoppet over: %ld Advarsler: %ld",
-"Poster: %ld Like: %ld",
-"Feil delnøkkel. Den brukte delnøkkelen er ikke en streng eller den oppgitte lengde er lengre enn nøkkel lengden",
-"En kan ikke slette alle felt med ALTER TABLE. Bruk DROP TABLE isteden.",
-"Kan ikke DROP '%-.64s'. Undersøk om felt/nøkkel eksisterer.",
-"Poster: %ld Like: %ld Advarsler: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Ukjent tråd id: %lu",
-"Du er ikke eier av tråden %lu",
-"Ingen tabeller i bruk",
-"For mange tekststrenger kolonne %s og SET",
-"Kan ikke lage unikt loggfilnavn %s.(1-999)\n",
-"Tabellen '%-.64s' var låst med READ lås og kan ikke oppdateres",
-"Tabellen '%-.64s' var ikke låst med LOCK TABLES",
-"Blob feltet '%-.64s' kan ikke ha en standard verdi",
-"Ugyldig database navn '%-.64s'",
-"Ugyldig tabell navn '%-.64s'",
-"SELECT ville undersøke for mange poster og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt",
-"Ukjent feil",
-"Ukjent prosedyre %s",
-"Feil parameter antall til prosedyren %s",
-"Feil parametre til prosedyren %s",
-"Ukjent tabell '%-.64s' i %s",
-"Feltet '%-.64s' er spesifisert to ganger",
-"Invalid use of group function",
-"Table '%-.64s' uses a extension that doesn't exist in this MySQL version",
-"A table must have at least 1 column",
-"The table '%-.64s' is full",
-"Unknown character set: '%-.64s'",
-"Too many tables; MySQL can only use %d tables in a join",
-"Too many columns",
-"Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs",
-"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
-"Cross dependency found in OUTER JOIN; examine your ON conditions",
-"Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
-"Can't load function '%-.64s'",
-"Can't initialize function '%-.64s'; %-.80s",
-"No paths allowed for shared library",
-"Function '%-.64s' already exists",
-"Can't open shared library '%-.64s' (errno: %d %s)",
-"Can't find function '%-.64s' in library'",
-"Function '%-.64s' is not defined",
-"Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'",
-"Host '%-.64s' is not allowed to connect to this MySQL server",
-"You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords",
-"You must have privileges to update tables in the mysql database to be able to change passwords for others",
-"Can't find any matching row in the user table",
-"Rows matched: %ld Changed: %ld Warnings: %ld",
-"Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug",
-"Column count doesn't match value count at row %ld",
-"Can't reopen table: '%-.64s",
-"Invalid use of NULL value",
-"Got error '%-.64s' from regexp",
-"Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause",
-"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for table '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
-"Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used.",
-"The host or user argument to GRANT is too long",
-"Table '%-.64s.%s' doesn't exist",
-"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
-"The used command is not allowed with this MySQL version",
-"Something is wrong in your syntax",
-"Delayed insert thread couldn't get requested lock for table %-.64s",
-"Too many delayed threads in use",
-"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
-"Got a packet bigger than 'max_allowed_packet' bytes",
-"Got a read error from the connection pipe",
-"Got an error from fcntl()",
-"Got packets out of order",
-"Couldn't uncompress communication packet",
-"Got an error reading communication packets",
-"Got timeout reading communication packets",
-"Got an error writing communication packets",
-"Got timeout writing communication packets",
-"Result string is longer than 'max_allowed_packet' bytes",
-"The used table type doesn't support BLOB/TEXT columns",
-"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
-"Incorrect column name '%-.100s'",
-"The used table handler can't index column '%-.64s'",
-"All tables in the MERGE table are not defined identically",
-"Can't write, because of unique constraint, to table '%-.64s'",
-"BLOB column '%-.64s' used in key specification without a key length",
-"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
-"This table type requires a primary key",
-"This version of MySQL is not compiled with RAID support",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Mottok feil %d '%-.100s' fa %s",
-"Mottok temporary feil %d '%-.100s' fra %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
deleted file mode 100644
index 634a4d93f42..00000000000
--- a/sql/share/polish/errmsg.txt
+++ /dev/null
@@ -1,326 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Changed by Jaroslaw Lewandowski <jotel@itnet.com.pl>
- Charset ISO-8859-2
-*/
-
-character-set=latin2
-
-"hashchk",
-"isamchk",
-"NIE",
-"TAK",
-"Nie mo¿na stworzyæ pliku '%-.64s' (Kod b³êdu: %d)",
-"Nie mo¿na stworzyæ tabeli '%-.64s' (Kod b³êdu: %d)",
-"Nie mo¿na stworzyæ bazy danych '%-.64s' (Kod b³êdu: %d)",
-"Nie mo¿na stworzyæ bazy danych '%-.64s'; baza danych ju¿ istnieje",
-"Nie mo¿na usun?æ bazy danych '%-.64s'; baza danych nie istnieje",
-"B³?d podczas usuwania bazy danych (nie mo¿na usun?æ '%-.64s', b³?d %d)",
-"B³?d podczas usuwania bazy danych (nie mo¿na wykonaæ rmdir '%-.64s', b³?d %d)",
-"B³?d podczas usuwania '%-.64s' (Kod b³êdu: %d)",
-"Nie mo¿na odczytaæ rekordu z tabeli systemowej",
-"Nie mo¿na otrzymaæ statusu '%-.64s' (Kod b³êdu: %d)",
-"Nie mo¿na rozpoznaæ aktualnego katalogu (Kod b³êdu: %d)",
-"Nie mo¿na zablokowaæ pliku (Kod b³êdu: %d)",
-"Nie mo¿na otworzyæ pliku: '%-.64s' (Kod b³êdu: %d)",
-"Nie mo¿na znale¥æ pliku: '%-.64s' (Kod b³êdu: %d)",
-"Nie mo¿na odczytaæ katalogu '%-.64s' (Kod b³êdu: %d)",
-"Nie mo¿na zmieniæ katalogu na '%-.64s' (Kod b³êdu: %d)",
-"Rekord zosta³ zmieniony od ostaniego odczytania z tabeli '%-.64s'",
-"Dysk pe³ny (%s). Oczekiwanie na zwolnienie miejsca...",
-"Nie mo¿na zapisaæ, powtórzone klucze w tabeli '%-.64s'",
-"B³?d podczas zamykania '%-.64s' (Kod b³êdu: %d)",
-"B³?d podczas odczytu pliku '%-.64s' (Kod b³êdu: %d)",
-"B³?d podczas zmieniania nazwy '%-.64s' na '%-.64s' (Kod b³êdu: %d)",
-"B³?d podczas zapisywania pliku '%-.64s' (Kod b³êdu: %d)",
-"'%-.64s' jest zablokowany na wypadek zmian",
-"Sortowanie przerwane",
-"Widok '%-.64s' nie istnieje dla '%-.64s'",
-"Otrzymano b³?d %d z obs³ugi tabeli",
-"Obs³uga tabeli '%-.64s' nie posiada tej opcji",
-"Nie mo¿na znale¥æ rekordu w '%-.64s'",
-"Niew³a?ciwa informacja w pliku: '%-.64s'",
-"Niew³a?ciwy plik kluczy dla tabeli: '%-.64s'; spróbuj go naprawiæ",
-"Plik kluczy dla tabeli '%-.64s' jest starego typu; napraw go!",
-"'%-.64s' jest tylko do odczytu",
-"Zbyt ma³o pamiêci. Uruchom ponownie demona i spróbuj ponownie (potrzeba %d bajtów)",
-"Zbyt ma³o pamiêci dla sortowania. Zwiêksz wielko?æ bufora demona dla sortowania",
-"Nieoczekiwany 'eof' napotkany podczas czytania z pliku '%-.64s' (Kod b³êdu: %d)",
-"Zbyt wiele po³?czeñ",
-"Zbyt ma³o miejsca/pamiêci dla w?tku",
-"Nie mo¿na otrzymaæ nazwy hosta dla twojego adresu",
-"Z³y uchwyt(handshake)",
-"Access denied for user '%-.32s'@'%-.64s' to database '%-.64s'",
-"Access denied for user '%-.32s'@'%-.64s' (using password: %s)",
-"Nie wybrano ¿adnej bazy danych",
-"Nieznana komenda",
-"Kolumna '%-.64s' nie mo¿e byæ null",
-"Nieznana baza danych '%-.64s'",
-"Tabela '%-.64s' ju¿ istnieje",
-"Nieznana tabela '%-.64s'",
-"Kolumna: '%-.64s' w %s jest dwuznaczna",
-"Trwa koñczenie dzia³ania serwera",
-"Nieznana kolumna '%-.64s' w %s",
-"U¿yto '%-.64s' bez umieszczenia w group by",
-"Nie mo¿na grupowaæ po '%-.64s'",
-"Zapytanie ma funkcje sumuj?ce i kolumny w tym samym zapytaniu",
-"Liczba kolumn nie odpowiada liczbie warto?ci",
-"Nazwa identyfikatora '%-.64s' jest zbyt d³uga",
-"Powtórzona nazwa kolumny '%-.64s'",
-"Powtórzony nazwa klucza '%-.64s'",
-"Powtórzone wyst?pienie '%-.64s' dla klucza %d",
-"B³êdna specyfikacja kolumny dla kolumny '%-.64s'",
-"%s obok '%-.64s' w linii %d",
-"Zapytanie by³o puste",
-"Tabela/alias nie s? unikalne: '%-.64s'",
-"Niew³a?ciwa warto?æ domy?lna dla '%-.64s'",
-"Zdefiniowano wiele kluczy podstawowych",
-"Okre?lono zbyt wiele kluczy. Dostêpnych jest maksymalnie %d kluczy",
-"Okre?lono zbyt wiele czê?ci klucza. Dostêpnych jest maksymalnie %d czê?ci",
-"Zdefinowany klucz jest zbyt d³ugi. Maksymaln? d³ugo?ci? klucza jest %d",
-"Kolumna '%-.64s' zdefiniowana w kluczu nie istnieje w tabeli",
-"Kolumna typu Blob '%-.64s' nie mo¿e byæ u¿yta w specyfikacji klucza",
-"Zbyt du¿a d³ugo?æ kolumny '%-.64s' (maks. = %d). W zamian u¿yj typu BLOB",
-"W tabeli mo¿e byæ tylko jedno pole auto i musi ono byæ zdefiniowane jako klucz",
-"%s: gotowe do po³?czenia",
-"%s: Standardowe zakoñczenie dzia³ania\n",
-"%s: Otrzymano sygna³ %d. Koñczenie dzia³ania!\n",
-"%s: Zakoñczenie dzia³ania wykonane\n",
-"%s: Wymuszenie zamkniêcia w?tku %ld u¿ytkownik: '%-.64s'\n",
-"Nie mo¿na stworzyæ socket'u IP",
-"Tabela '%-.64s' nie ma indeksu takiego jak w CREATE INDEX. Stwórz tabelê",
-"Nie oczekiwano separatora. Sprawd¥ podrêcznik",
-"Nie mo¿na u¿yæ sta³ej d³ugo?ci wiersza z polami typu BLOB. U¿yj 'fields terminated by'.",
-"Plik '%-.64s' musi znajdowaæ sie w katalogu bazy danych lub mieæ prawa czytania przez wszystkich",
-"Plik '%-.64s' ju¿ istnieje",
-"Recordów: %ld Usuniêtych: %ld Pominiêtych: %ld Ostrze¿eñ: %ld",
-"Rekordów: %ld Duplikatów: %ld",
-"B³êdna podczê?æ klucza. U¿yta czê?æ klucza nie jest ³añcuchem lub u¿yta d³ugo?æ jest wiêksza ni¿ czê?æ klucza",
-"Nie mo¿na usun?æ wszystkich pól wykorzystuj?c ALTER TABLE. W zamian u¿yj DROP TABLE",
-"Nie mo¿na wykonaæ operacji DROP '%-.64s'. Sprawd¥, czy to pole/klucz istnieje",
-"Rekordów: %ld Duplikatów: %ld Ostrze¿eñ: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Nieznany identyfikator w?tku: %lu",
-"Nie jeste? w³a?cicielem w?tku %lu",
-"Nie ma ¿adej u¿ytej tabeli",
-"Zbyt wiele ³añcuchów dla kolumny %s i polecenia SET",
-"Nie mo¿na stworzyæ unikalnej nazwy pliku z logiem %s.(1-999)\n",
-"Tabela '%-.64s' zosta³a zablokowana przez READ i nie mo¿e zostaæ zaktualizowana",
-"Tabela '%-.64s' nie zosta³a zablokowana poleceniem LOCK TABLES",
-"Pole typu blob '%-.64s' nie mo¿e mieæ domy?lnej warto?ci",
-"Niedozwolona nazwa bazy danych '%-.64s'",
-"Niedozwolona nazwa tabeli '%-.64s'...",
-"Operacja SELECT bêdzie dotyczy³a zbyt wielu rekordów i prawdopodobnie zajmie bardzo du¿o czasu. Sprawd¥ warunek WHERE i u¿yj SQL_OPTION BIG_SELECTS=1 je?li operacja SELECT jest poprawna",
-"Unknown error",
-"Unkown procedure %s",
-"Incorrect parameter count to procedure %s",
-"Incorrect parameters to procedure %s",
-"Unknown table '%-.64s' in %s",
-"Field '%-.64s' specified twice",
-"Invalid use of group function",
-"Table '%-.64s' uses a extension that doesn't exist in this MySQL version",
-"A table must have at least 1 column",
-"The table '%-.64s' is full",
-"Unknown character set: '%-.64s'",
-"Too many tables; MySQL can only use %d tables in a join",
-"Too many columns",
-"Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs",
-"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
-"Cross dependency found in OUTER JOIN; examine your ON conditions",
-"Column '%-.32s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
-"Can't load function '%-.64s'",
-"Can't initialize function '%-.64s'; %-.80s",
-"No paths allowed for shared library",
-"Function '%-.64s' already exists",
-"Can't open shared library '%-.64s' (errno: %d %s)",
-"Can't find function '%-.64s' in library'",
-"Function '%-.64s' is not defined",
-"Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'",
-"Host '%-.64s' is not allowed to connect to this MySQL server",
-"You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords",
-"You must have privileges to update tables in the mysql database to be able to change passwords for others",
-"Can't find any matching row in the user table",
-"Rows matched: %ld Changed: %ld Warnings: %ld",
-"Can't create a new thread (errno %d); if you are not out of available memory you can consult the manual for any possible OS dependent bug",
-"Column count doesn't match value count at row %ld",
-"Can't reopen table: '%-.64s",
-"Invalid use of NULL value",
-"Got error '%-.64s' from regexp",
-"Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause",
-"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for table '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
-"Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used.",
-"The host or user argument to GRANT is too long",
-"Table '%-.64s.%s' doesn't exist",
-"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
-"The used command is not allowed with this MySQL version",
-"Something is wrong in your syntax",
-"Delayed insert thread couldn't get requested lock for table %-.64s",
-"Too many delayed threads in use",
-"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
-"Got a packet bigger than 'max_allowed_packet' bytes",
-"Got a read error from the connection pipe",
-"Got an error from fcntl()",
-"Got packets out of order",
-"Couldn't uncompress communication packet",
-"Got an error reading communication packets",
-"Got timeout reading communication packets",
-"Got an error writing communication packets",
-"Got timeout writing communication packets",
-"Result string is longer than 'max_allowed_packet' bytes",
-"The used table type doesn't support BLOB/TEXT columns",
-"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
-"Incorrect column name '%-.100s'",
-"The used table handler can't index column '%-.64s'",
-"All tables in the MERGE table are not defined identically",
-"Can't write, because of unique constraint, to table '%-.64s'",
-"BLOB column '%-.64s' used in key specification without a key length",
-"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
-"This table type requires a primary key",
-"This version of MySQL is not compiled with RAID support",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
deleted file mode 100644
index 65d80918072..00000000000
--- a/sql/share/portuguese/errmsg.txt
+++ /dev/null
@@ -1,323 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* Updated by Thiago Delgado Pinto - thiagodp@ieg.com.br - 06.07.2002 */
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NÃO",
-"SIM",
-"Não pode criar o arquivo '%-.64s' (erro no. %d)",
-"Não pode criar a tabela '%-.64s' (erro no. %d)",
-"Não pode criar o banco de dados '%-.64s' (erro no. %d)",
-"Não pode criar o banco de dados '%-.64s'; este banco de dados já existe",
-"Não pode eliminar o banco de dados '%-.64s'; este banco de dados não existe",
-"Erro ao eliminar banco de dados (não pode eliminar '%-.64s' - erro no. %d)",
-"Erro ao eliminar banco de dados (não pode remover diretório '%-.64s' - erro no. %d)",
-"Erro na remoção de '%-.64s' (erro no. %d)",
-"Não pode ler um registro numa tabela do sistema",
-"Não pode obter o status de '%-.64s' (erro no. %d)",
-"Não pode obter o diretório corrente (erro no. %d)",
-"Não pode travar o arquivo (erro no. %d)",
-"Não pode abrir o arquivo '%-.64s' (erro no. %d)",
-"Não pode encontrar o arquivo '%-.64s' (erro no. %d)",
-"Não pode ler o diretório de '%-.64s' (erro no. %d)",
-"Não pode mudar para o diretório '%-.64s' (erro no. %d)",
-"Registro alterado desde a última leitura da tabela '%-.64s'",
-"Disco cheio (%s). Aguardando alguém liberar algum espaço...",
-"Não pode gravar. Chave duplicada na tabela '%-.64s'",
-"Erro ao fechar '%-.64s' (erro no. %d)",
-"Erro ao ler arquivo '%-.64s' (erro no. %d)",
-"Erro ao renomear '%-.64s' para '%-.64s' (erro no. %d)",
-"Erro ao gravar arquivo '%-.64s' (erro no. %d)",
-"'%-.64s' está com travamento contra alterações",
-"Ordenação abortada",
-"Visão '%-.64s' não existe para '%-.64s'",
-"Obteve erro %d no manipulador de tabelas",
-"Manipulador de tabela para '%-.64s' não tem esta opção",
-"Não pode encontrar registro em '%-.64s'",
-"Informação incorreta no arquivo '%-.64s'",
-"Arquivo de índice incorreto para tabela '%-.64s'; tente repará-lo",
-"Arquivo de índice desatualizado para tabela '%-.64s'; repare-o!",
-"Tabela '%-.64s' é somente para leitura",
-"Sem memória. Reinicie o programa e tente novamente (necessita de %d bytes)",
-"Sem memória para ordenação. Aumente tamanho do 'buffer' de ordenação",
-"Encontrado fim de arquivo inesperado ao ler arquivo '%-.64s' (erro no. %d)",
-"Excesso de conexões",
-"Sem memória. Verifique se o mysqld ou algum outro processo está usando toda memória disponível. Se não, você pode ter que usar 'ulimit' para permitir ao mysqld usar mais memória ou você pode adicionar mais área de 'swap'",
-"Não pode obter nome do 'host' para seu endereço",
-"Negociação de acesso falhou",
-"Acesso negado para o usuário '%-.32s'@'%-.64s' ao banco de dados '%-.64s'",
-"Acesso negado para o usuário '%-.32s'@'%-.64s' (senha usada: %s)",
-"Nenhum banco de dados foi selecionado",
-"Comando desconhecido",
-"Coluna '%-.64s' não pode ser vazia",
-"Banco de dados '%-.64s' desconhecido",
-"Tabela '%-.64s' já existe",
-"Tabela '%-.64s' desconhecida",
-"Coluna '%-.64s' em '%-.64s' é ambígua",
-"'Shutdown' do servidor em andamento",
-"Coluna '%-.64s' desconhecida em '%-.64s'",
-"'%-.64s' não está em 'GROUP BY'",
-"Não pode agrupar em '%-.64s'",
-"Cláusula contém funções de soma e colunas juntas",
-"Contagem de colunas não confere com a contagem de valores",
-"Nome identificador '%-.100s' é longo demais",
-"Nome da coluna '%-.64s' duplicado",
-"Nome da chave '%-.64s' duplicado",
-"Entrada '%-.64s' duplicada para a chave %d",
-"Especificador de coluna incorreto para a coluna '%-.64s'",
-"%s próximo a '%-.80s' na linha %d",
-"Consulta (query) estava vazia",
-"Tabela/alias '%-.64s' não única",
-"Valor padrão (default) inválido para '%-.64s'",
-"Definida mais de uma chave primária",
-"Especificadas chaves demais. O máximo permitido são %d chaves",
-"Especificadas partes de chave demais. O máximo permitido são %d partes",
-"Chave especificada longa demais. O comprimento de chave máximo permitido é %d",
-"Coluna chave '%-.64s' não existe na tabela",
-"Coluna BLOB '%-.64s' não pode ser utilizada na especificação de chave para o tipo de tabela usado",
-"Comprimento da coluna '%-.64s' grande demais (max = %d); use BLOB em seu lugar",
-"Definição incorreta de tabela. Somente é permitido um único campo auto-incrementado e ele tem que ser definido como chave",
-"%s: Pronto para conexões",
-"%s: 'Shutdown' normal\n",
-"%s: Obteve sinal %d. Abortando!\n",
-"%s: 'Shutdown' completo\n",
-"%s: Forçando finalização da 'thread' %ld - usuário '%-.32s'\n",
-"Não pode criar o soquete IP",
-"Tabela '%-.64s' não possui um índice como o usado em CREATE INDEX. Recrie a tabela",
-"Argumento separador de campos não é o esperado. Cheque o manual",
-"Você não pode usar comprimento de linha fixo com BLOBs. Por favor, use campos com comprimento limitado.",
-"Arquivo '%-.64s' tem que estar no diretório do banco de dados ou ter leitura possível para todos",
-"Arquivo '%-.80s' já existe",
-"Registros: %ld - Deletados: %ld - Ignorados: %ld - Avisos: %ld",
-"Registros: %ld - Duplicados: %ld",
-"Sub parte da chave incorreta. A parte da chave usada não é uma 'string' ou o comprimento usado é maior que parte da chave ou o manipulador de tabelas não suporta sub chaves únicas",
-"Você não pode deletar todas as colunas com ALTER TABLE; use DROP TABLE em seu lugar",
-"Não se pode fazer DROP '%-.64s'. Confira se esta coluna/chave existe",
-"Registros: %ld - Duplicados: %ld - Avisos: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"'Id' de 'thread' %lu desconhecido",
-"Você não é proprietário da 'thread' %lu",
-"Nenhuma tabela usada",
-"'Strings' demais para coluna '%-.64s' e SET",
-"Não pode gerar um nome de arquivo de 'log' único '%-.64s'.(1-999)\n",
-"Tabela '%-.64s' foi travada com trava de leitura e não pode ser atualizada",
-"Tabela '%-.64s' não foi travada com LOCK TABLES",
-"Coluna BLOB '%-.64s' não pode ter um valor padrão (default)",
-"Nome de banco de dados '%-.100s' incorreto",
-"Nome de tabela '%-.100s' incorreto",
-"O SELECT examinaria registros demais e provavelmente levaria muito tempo. Cheque sua cláusula WHERE e use SET SQL_BIG_SELECTS=1, se o SELECT estiver correto",
-"Erro desconhecido",
-"'Procedure' '%-.64s' desconhecida",
-"Número de parâmetros incorreto para a 'procedure' '%-.64s'",
-"Parâmetros incorretos para a 'procedure' '%-.64s'",
-"Tabela '%-.64s' desconhecida em '%-.32s'",
-"Coluna '%-.64s' especificada duas vezes",
-"Uso inválido de função de agrupamento (GROUP)",
-"Tabela '%-.64s' usa uma extensão que não existe nesta versão do MySQL",
-"Uma tabela tem que ter pelo menos uma (1) coluna",
-"Tabela '%-.64s' está cheia",
-"Conjunto de caracteres '%-.64s' desconhecido",
-"Tabelas demais. O MySQL pode usar somente %d tabelas em uma junção (JOIN)",
-"Colunas demais",
-"Tamanho de linha grande demais. O máximo tamanho de linha, não contando BLOBs, é %d. Você tem que mudar alguns campos para BLOBs",
-"Estouro da pilha do 'thread'. Usados %ld de uma pilha de %ld. Use 'mysqld -O thread_stack=#' para especificar uma pilha maior, se necessário",
-"Dependência cruzada encontrada em junção externa (OUTER JOIN); examine as condições utilizadas nas cláusulas 'ON'",
-"Coluna '%-.64s' é usada com única (UNIQUE) ou índice (INDEX), mas não está definida como não-nula (NOT NULL)",
-"Não pode carregar a função '%-.64s'",
-"Não pode inicializar a função '%-.64s' - '%-.80s'",
-"Não há caminhos (paths) permitidos para biblioteca compartilhada",
-"Função '%-.64s' já existe",
-"Não pode abrir biblioteca compartilhada '%-.64s' (erro no. '%d' - '%-.64s')",
-"Não pode encontrar a função '%-.64s' na biblioteca",
-"Função '%-.64s' não está definida",
-"'Host' '%-.64s' está bloqueado devido a muitos erros de conexão. Desbloqueie com 'mysqladmin flush-hosts'",
-"'Host' '%-.64s' não tem permissão para se conectar com este servidor MySQL",
-"Você está usando o MySQL como usuário anônimo e usuários anônimos não têm permissão para mudar senhas",
-"Você deve ter privilégios para atualizar tabelas no banco de dados mysql para ser capaz de mudar a senha de outros",
-"Não pode encontrar nenhuma linha que combine na tabela usuário (user table)",
-"Linhas que combinaram: %ld - Alteradas: %ld - Avisos: %ld",
-"Não pode criar uma nova 'thread' (erro no. %d). Se você não estiver sem memória disponível, você pode consultar o manual sobre um possível 'bug' dependente do sistema operacional",
-"Contagem de colunas não confere com a contagem de valores na linha %ld",
-"Não pode reabrir a tabela '%-.64s",
-"Uso inválido do valor NULL",
-"Obteve erro '%-.64s' em regexp",
-"Mistura de colunas agrupadas (com MIN(), MAX(), COUNT(), ...) com colunas não agrupadas é ilegal, se não existir uma cláusula de agrupamento (cláusula GROUP BY)",
-"Não existe tal permissão (grant) definida para o usuário '%-.32s' no 'host' '%-.64s'",
-"Comando '%-.16s' negado para o usuário '%-.32s'@'%-.64s' na tabela '%-.64s'",
-"Comando '%-.16s' negado para o usuário '%-.32s'@'%-.64s' na coluna '%-.64s', na tabela '%-.64s'",
-"Comando GRANT/REVOKE ilegal. Por favor consulte no manual quais privilégios podem ser usados.",
-"Argumento de 'host' ou de usuário para o GRANT é longo demais",
-"Tabela '%-.64s.%-.64s' não existe",
-"Não existe tal permissão (grant) definido para o usuário '%-.32s' no 'host' '%-.64s', na tabela '%-.64s'",
-"Comando usado não é permitido para esta versão do MySQL",
-"Você tem um erro de sintaxe no seu SQL",
-"'Thread' de inserção retardada (atrasada) pois não conseguiu obter a trava solicitada para tabela '%-.64s'",
-"Excesso de 'threads' retardadas (atrasadas) em uso",
-"Conexão %ld abortou para o banco de dados '%-.64s' - usuário '%-.32s' (%-.64s)",
-"Obteve um pacote maior do que a taxa máxima de pacotes definida (max_allowed_packet)",
-"Obteve um erro de leitura no 'pipe' da conexão",
-"Obteve um erro em fcntl()",
-"Obteve pacotes fora de ordem",
-"Não conseguiu descomprimir pacote de comunicação",
-"Obteve um erro na leitura de pacotes de comunicação",
-"Obteve expiração de tempo (timeout) na leitura de pacotes de comunicação",
-"Obteve um erro na escrita de pacotes de comunicação",
-"Obteve expiração de tempo ('timeout') na escrita de pacotes de comunicação",
-"'String' resultante é mais longa do que 'max_allowed_packet'",
-"Tipo de tabela usado não permite colunas BLOB/TEXT",
-"Tipo de tabela usado não permite colunas AUTO_INCREMENT",
-"INSERT DELAYED não pode ser usado com a tabela '%-.64s', porque ela está travada com LOCK TABLES",
-"Nome de coluna '%-.100s' incorreto",
-"O manipulador de tabela usado não pode indexar a coluna '%-.64s'",
-"Todas as tabelas contidas na tabela fundida (MERGE) não estão definidas identicamente",
-"Não pode gravar, devido à restrição UNIQUE, na tabela '%-.64s'",
-"Coluna BLOB '%-.64s' usada na especificação de chave sem o comprimento da chave",
-"Todas as partes de uma chave primária devem ser não-nulas. Se você precisou usar um valor nulo (NULL) em uma chave, use a cláusula UNIQUE em seu lugar",
-"O resultado consistiu em mais do que uma linha",
-"Este tipo de tabela requer uma chave primária",
-"Esta versão do MySQL não foi compilada com suporte a RAID",
-"Você está usando modo de atualização seguro e tentou atualizar uma tabela sem uma cláusula WHERE que use uma coluna chave",
-"Chave '%-.64s' não existe na tabela '%-.64s'",
-"Não pode abrir a tabela",
-"O manipulador de tabela não suporta %s",
-"Não lhe é permitido executar este comando em uma transação",
-"Obteve erro %d durante COMMIT",
-"Obteve erro %d durante ROLLBACK",
-"Obteve erro %d durante FLUSH_LOGS",
-"Obteve erro %d durante CHECKPOINT",
-"Conexão %ld abortada para banco de dados '%-.64s' - usuário '%-.32s' - 'host' `%-.64s' ('%-.64s')",
-"O manipulador de tabela não suporta 'dump' binário de tabela",
-"Binlog fechado. Não pode fazer RESET MASTER",
-"Falhou na reconstrução do índice da tabela 'dumped' '%-.64s'",
-"Erro no 'master' '%-.64s'",
-"Erro de rede lendo do 'master'",
-"Erro de rede gravando no 'master'",
-"Não pode encontrar um índice para o texto todo que combine com a lista de colunas",
-"Não pode executar o comando dado porque você tem tabelas ativas travadas ou uma transação ativa",
-"Variável de sistema '%-.64s' desconhecida",
-"Tabela '%-.64s' está marcada como danificada e deve ser reparada",
-"Tabela '%-.64s' está marcada como danificada e a última reparação (automática?) falhou",
-"Aviso: Algumas tabelas não-transacionais alteradas não puderam ser reconstituídas (rolled back)",
-"Transações multi-declaradas (multi-statement transactions) requeriram mais do que o valor limite (max_binlog_cache_size) de bytes para armazenagem. Aumente o valor desta variável do mysqld e tente novamente",
-"Esta operação não pode ser realizada com um 'slave' em execução. Execute STOP SLAVE primeiro",
-"Esta operação requer um 'slave' em execução. Configure o 'slave' e execute START SLAVE",
-"O servidor não está configurado como 'slave'. Acerte o arquivo de configuração ou use CHANGE MASTER TO",
-"Could not initialize master info structure, more error messages can be found in the MySQL error log",
-"Não conseguiu criar 'thread' de 'slave'. Verifique os recursos do sistema",
-"Usuário '%-.64s' já possui mais que o valor máximo de conexões (max_user_connections) ativas",
-"Você pode usar apenas expressões constantes com SET",
-"Tempo de espera (timeout) de travamento excedido. Tente reiniciar a transação.",
-"O número total de travamentos excede o tamanho da tabela de travamentos",
-"Travamentos de atualização não podem ser obtidos durante uma transação de tipo READ UNCOMMITTED",
-"DROP DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura",
-"CREATE DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura",
-"Argumentos errados para %s",
-"Não é permitido a '%-.32s'@'%-.64s' criar novos usuários",
-"Definição incorreta da tabela. Todas as tabelas contidas na junção devem estar no mesmo banco de dados.",
-"Encontrado um travamento fatal (deadlock) quando tentava obter uma trava. Tente reiniciar a transação.",
-"O tipo de tabela utilizado não suporta índices de texto completo (fulltext indexes)",
-"Não pode acrescentar uma restrição de chave estrangeira",
-"Não pode acrescentar uma linha filha: uma restrição de chave estrangeira falhou",
-"Não pode apagar uma linha pai: uma restrição de chave estrangeira falhou",
-"Erro conectando com o master: %-.128s",
-"Erro rodando consulta no master: %-.128s",
-"Erro quando executando comando %s: %-.128s",
-"Uso errado de %s e %s",
-"Os comandos SELECT usados têm diferente número de colunas",
-"Não posso executar a consulta porque você tem um conflito de travamento de leitura",
-"Mistura de tabelas transacional e não-transacional está desabilitada",
-"Opção '%s' usada duas vezes no comando",
-"Usuário '%-.64s' tem excedido o '%s' recurso (atual valor: %ld)",
-"Acesso negado. Você precisa o privilégio %-.128s para essa operação",
-"Variável '%-.64s' é uma SESSION variável e não pode ser usada com SET GLOBAL",
-"Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL",
-"Variável '%-.64s' não tem um valor padrão",
-"Variável '%-.64s' não pode ser configurada para o valor de '%-.64s'",
-"Tipo errado de argumento para variável '%-.64s'",
-"Variável '%-.64s' somente pode ser configurada, não lida",
-"Errado uso/colocação de '%s'",
-"Esta versão de MySQL não suporta ainda '%s'",
-"Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log",
-"Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela",
-"Variable '%-.64s' is a %s variable",
-"Definição errada da chave estrangeira para '%-.64s': %s",
-"Referência da chave e referência da tabela não coincidem",
-"Operand should contain %d column(s)",
-"Subconsulta retorna mais que 1 registro",
-"Desconhecido manipulador de declaração preparado (%.*s) determinado para %s",
-"Banco de dado de ajuda corrupto ou não existente",
-"Referência cíclica em subconsultas",
-"Convertendo coluna '%s' de %s para %s",
-"Referência '%-.64s' não suportada (%s)",
-"Cada tabela derivada deve ter seu próprio alias",
-"Select %u foi reduzido durante otimização",
-"Tabela '%-.64s' de um dos SELECTs não pode ser usada em %-.32s",
-"Cliente não suporta o protocolo de autenticação exigido pelo servidor; considere a atualização do cliente MySQL",
-"Todas as partes de uma SPATIAL KEY devem ser NOT NULL",
-"COLLATION '%s' não é válida para CHARACTER SET '%s'",
-"O slave já está rodando",
-"O slave já está parado",
-"Tamanho muito grande dos dados des comprimidos. O máximo tamanho é %d. (provavelmente, o comprimento dos dados descomprimidos está corrupto)",
-"ZLIB: Não suficiente memória disponível",
-"ZLIB: Não suficiente espaço no buffer emissor (provavelmente, o comprimento dos dados descomprimidos está corrupto)",
-"ZLIB: Dados de entrada está corrupto",
-"%d linha(s) foram cortada(s) por GROUP_CONCAT()",
-"Conta de registro é menor que a conta de coluna na linha %ld",
-"Conta de registro é maior que a conta de coluna na linha %ld",
-"Dado truncado, NULL fornecido para NOT NULL coluna '%s' na linha %ld",
-"Dado truncado, fora de alcance para coluna '%s' na linha %ld",
-"Dado truncado para coluna '%s' na linha %ld",
-"Usando engine de armazenamento %s para tabela '%s'",
-"Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'",
-"Não pode remover um ou mais dos usuários pedidos",
-"Não pode revocar todos os privilégios, grant para um ou mais dos usuários pedidos",
-"Ilegal combinação de collations (%s,%s), (%s,%s), (%s,%s) para operação '%s'",
-"Ilegal combinação de collations para operação '%s'",
-"Variável '%-.64s' não é uma variável componente (Não pode ser usada como XXXX.variável_nome)",
-"Collation desconhecida: '%-.64s'",
-"SSL parâmetros em CHANGE MASTER são ignorados porque este escravo MySQL foi compilado sem o SSL suporte. Os mesmos podem ser usados mais tarde quando o escravo MySQL com SSL seja iniciado.",
-"Servidor está rodando em --secure-auth modo, porêm '%s'@'%s' tem senha no formato antigo; por favor troque a senha para o novo formato",
-"Campo ou referência '%-.64s%s%-.64s%s%-.64s' de SELECT #%d foi resolvido em SELECT #%d",
-"Parâmetro ou combinação de parâmetros errado para START SLAVE UNTIL",
-"É recomendado para rodar com --skip-slave-start quando fazendo replicação passo-por-passo com START SLAVE UNTIL, de outra forma você não está seguro em caso de inesperada reinicialição do mysqld escravo",
-"Thread SQL não pode ser inicializado tal que opções UNTIL são ignoradas",
-"Incorreto nome de índice '%-.100s'",
-"Incorreto nome de catálogo '%-.100s'",
-"Falha em Query cache para configurar tamanho %lu, novo tamanho de query cache é %lu",
-"Coluna '%-.64s' não pode ser parte de índice FULLTEXT",
-"Key cache desconhecida '%-.100s'",
-"MySQL foi inicializado em modo --skip-name-resolve. Você necesita reincializá-lo sem esta opção para este grant funcionar",
-"Motor de tabela desconhecido '%s'",
-"'%s' é desatualizado. Use '%s' em seu lugar",
-"A tabela destino %-.100s do %s não é atualizável",
-"O recurso '%s' foi desativado; você necessita MySQL construído com '%s' para ter isto funcionando",
-"O servidor MySQL está rodando com a opção %s razão pela qual não pode executar esse commando",
-"Coluna '%-.100s' tem valor duplicado '%-.64s' em %s"
-"Truncado errado %-.32s valor: '%-.128s'"
-"Incorreta definição de tabela; Pode ter somente uma coluna TIMESTAMP com CURRENT_TIMESTAMP em DEFAULT ou ON UPDATE cláusula"
-"Inválida cláusula ON UPDATE para campo '%-.64s'",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
deleted file mode 100644
index 01c22f00119..00000000000
--- a/sql/share/romanian/errmsg.txt
+++ /dev/null
@@ -1,326 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Translated into Romanian by Stefan Saroiu
- e-mail: tzoompy@cs.washington.edu
-*/
-
-character-set=latin2
-
-"hashchk",
-"isamchk",
-"NU",
-"DA",
-"Nu pot sa creez fisierul '%-.64s' (Eroare: %d)",
-"Nu pot sa creez tabla '%-.64s' (Eroare: %d)",
-"Nu pot sa creez baza de date '%-.64s' (Eroare: %d)",
-"Nu pot sa creez baza de date '%-.64s'; baza de date exista deja",
-"Nu pot sa drop baza de date '%-.64s'; baza da date este inexistenta",
-"Eroare dropuind baza de date (nu pot sa sterg '%-.64s', Eroare: %d)",
-"Eroare dropuind baza de date (nu pot sa rmdir '%-.64s', Eroare: %d)",
-"Eroare incercind sa delete '%-.64s' (Eroare: %d)",
-"Nu pot sa citesc cimpurile in tabla de system (system table)",
-"Nu pot sa obtin statusul lui '%-.64s' (Eroare: %d)",
-"Nu pot sa obtin directorul current (working directory) (Eroare: %d)",
-"Nu pot sa lock fisierul (Eroare: %d)",
-"Nu pot sa deschid fisierul: '%-.64s' (Eroare: %d)",
-"Nu pot sa gasesc fisierul: '%-.64s' (Eroare: %d)",
-"Nu pot sa citesc directorul '%-.64s' (Eroare: %d)",
-"Nu pot sa schimb directorul '%-.64s' (Eroare: %d)",
-"Cimpul a fost schimbat de la ultima citire a tabelei '%-.64s'",
-"Hard-disk-ul este plin (%s). Astept sa se elibereze ceva spatiu...",
-"Nu pot sa scriu (can't write), cheie duplicata in tabela '%-.64s'",
-"Eroare inchizind '%-.64s' (errno: %d)",
-"Eroare citind fisierul '%-.64s' (errno: %d)",
-"Eroare incercind sa renumesc '%-.64s' in '%-.64s' (errno: %d)",
-"Eroare scriind fisierul '%-.64s' (errno: %d)",
-"'%-.64s' este blocat pentry schimbari (loccked against change)",
-"Sortare intrerupta",
-"View '%-.64s' nu exista pentru '%-.64s'",
-"Eroarea %d obtinuta din handlerul tabelei",
-"Handlerul tabelei pentru '%-.64s' nu are aceasta optiune",
-"Nu pot sa gasesc recordul in '%-.64s'",
-"Informatie incorecta in fisierul: '%-.64s'",
-"Cheia fisierului incorecta pentru tabela: '%-.64s'; incearca s-o repari",
-"Cheia fisierului e veche pentru tabela '%-.64s'; repar-o!",
-"Tabela '%-.64s' e read-only",
-"Out of memory. Porneste daemon-ul din nou si incearca inca o data (e nevoie de %d bytes)",
-"Out of memory pentru sortare. Largeste marimea buffer-ului pentru sortare in daemon (sort buffer size)",
-"Sfirsit de fisier neasteptat in citirea fisierului '%-.64s' (errno: %d)",
-"Prea multe conectiuni",
-"Out of memory; Verifica daca mysqld sau vreun alt proces foloseste toate memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui mysqld sa foloseasca mai multa memorie ori adauga mai mult spatiu pentru swap (swap space)",
-"Nu pot sa obtin hostname-ul adresei tale",
-"Prost inceput de conectie (bad handshake)",
-"Acces interzis pentru utilizatorul: '%-.32s'@'%-.64s' la baza de date '%-.64s'",
-"Acces interzis pentru utilizatorul: '%-.32s'@'%-.64s' (Folosind parola: %s)",
-"Nici o baza de data nu a fost selectata inca",
-"Comanda invalida",
-"Coloana '%-.64s' nu poate sa fie null",
-"Baza de data invalida '%-.64s'",
-"Tabela '%-.64s' exista deja",
-"Tabela '%-.64s' este invalida",
-"Coloana: '%-.64s' in %-.64s este ambigua",
-"Terminarea serverului este in desfasurare",
-"Coloana invalida '%-.64s' in '%-.64s'",
-"'%-.64s' nu exista in clauza GROUP BY",
-"Nu pot sa grupez pe (group on) '%-.64s'",
-"Comanda are functii suma si coloane in aceeasi comanda",
-"Numarul de coloane nu este acelasi cu numarul valoarei",
-"Numele indentificatorului '%-.100s' este prea lung",
-"Numele coloanei '%-.64s' e duplicat",
-"Numele cheiei '%-.64s' e duplicat",
-"Cimpul '%-.64s' e duplicat pentru cheia %d",
-"Specificandul coloanei '%-.64s' este incorect",
-"%s linga '%-.80s' pe linia %d",
-"Query-ul a fost gol",
-"Tabela/alias: '%-.64s' nu este unic",
-"Valoarea de default este invalida pentru '%-.64s'",
-"Chei primare definite de mai multe ori",
-"Prea multe chei. Numarul de chei maxim este %d",
-"Prea multe chei. Numarul de chei maxim este %d",
-"Cheia specificata este prea lunga. Marimea maxima a unei chei este de %d",
-"Coloana cheie '%-.64s' nu exista in tabela",
-"Coloana de tip BLOB '%-.64s' nu poate fi folosita in specificarea cheii cu tipul de tabla folosit",
-"Lungimea coloanei '%-.64s' este prea lunga (maximum = %d). Foloseste BLOB mai bine",
-"Definitia tabelei este incorecta; Nu pot fi mai mult de o singura coloana de tip auto si aceasta trebuie definita ca cheie",
-"%s: sint gata pentru conectii",
-"%s: Terminare normala\n",
-"%s: Semnal %d obtinut. Aborting!\n",
-"%s: Terminare completa\n",
-"%s: Terminare fortata a thread-ului %ld utilizatorului: '%-.32s'\n",
-"Nu pot crea IP socket",
-"Tabela '%-.64s' nu are un index ca acela folosit in CREATE INDEX. Re-creeaza tabela",
-"Argumentul pentru separatorul de cimpuri este diferit de ce ma asteptam. Verifica manualul",
-"Nu poti folosi lungime de cimp fix pentru BLOB-uri. Foloseste 'fields terminated by'.",
-"Fisierul '%-.64s' trebuie sa fie in directorul bazei de data sau trebuie sa poata sa fie citit de catre toata lumea (verifica permisiile)",
-"Fisierul '%-.80s' exista deja",
-"Recorduri: %ld Sterse: %ld Sarite (skipped): %ld Atentionari (warnings): %ld",
-"Recorduri: %ld Duplicate: %ld",
-"Componentul cheii este incorrect. Componentul folosit al cheii nu este un sir sau lungimea folosita este mai lunga decit lungimea cheii",
-"Nu poti sterge toate coloanele cu ALTER TABLE. Foloseste DROP TABLE in schimb",
-"Nu pot sa DROP '%-.64s'. Verifica daca coloana/cheia exista",
-"Recorduri: %ld Duplicate: %ld Atentionari (warnings): %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Id-ul: %lu thread-ului este necunoscut",
-"Nu sinteti proprietarul threadului %lu",
-"Nici o tabela folosita",
-"Prea multe siruri pentru coloana %-.64s si SET",
-"Nu pot sa generez un nume de log unic %-.64s.(1-999)\n",
-"Tabela '%-.64s' a fost locked cu un READ lock si nu poate fi actualizata",
-"Tabela '%-.64s' nu a fost locked cu LOCK TABLES",
-"Coloana BLOB '%-.64s' nu poate avea o valoare default",
-"Numele bazei de date este incorect '%-.100s'",
-"Numele tabelei este incorect '%-.100s'",
-"SELECT-ul ar examina prea multe cimpuri si probabil ar lua prea mult timp; verifica clauza WHERE si foloseste SET SQL_BIG_SELECTS=1 daca SELECT-ul e okay",
-"Eroare unknown",
-"Procedura unknown '%-.64s'",
-"Procedura '%-.64s' are un numar incorect de parametri",
-"Procedura '%-.64s' are parametrii incorecti",
-"Tabla '%-.64s' invalida in %-.32s",
-"Coloana '%-.64s' specificata de doua ori",
-"Folosire incorecta a functiei group",
-"Tabela '%-.64s' foloseste o extensire inexistenta in versiunea curenta de MySQL",
-"O tabela trebuie sa aiba cel putin o coloana",
-"Tabela '%-.64s' e plina",
-"Set de caractere invalid: '%-.64s'",
-"Prea multe tabele. MySQL nu poate folosi mai mult de %d tabele intr-un join",
-"Prea multe coloane",
-"Marimea liniei (row) prea mare. Marimea maxima a liniei, excluzind BLOB-urile este de %d. Trebuie sa schimbati unele cimpuri in BLOB-uri",
-"Stack-ul thread-ului a fost depasit (prea mic): Folositi: %ld intr-un stack de %ld. Folositi 'mysqld -O thread_stack=#' ca sa specifici un stack mai mare",
-"Dependinta incrucisata (cross dependency) gasita in OUTER JOIN. Examinati conditiile ON",
-"Coloana '%-.64s' e folosita cu UNIQUE sau INDEX dar fara sa fie definita ca NOT NULL",
-"Nu pot incarca functia '%-.64s'",
-"Nu pot initializa functia '%-.64s'; %-.80s",
-"Nici un paths nu e permis pentru o librarie shared",
-"Functia '%-.64s' exista deja",
-"Nu pot deschide libraria shared '%-.64s' (Eroare: %d %-.64s)",
-"Nu pot gasi functia '%-.64s' in libraria",
-"Functia '%-.64s' nu e definita",
-"Host-ul '%-.64s' e blocat din cauza multelor erori de conectie. Poti deploca folosind 'mysqladmin flush-hosts'",
-"Host-ul '%-.64s' nu este permis a se conecta la aceste server MySQL",
-"Dumneavoastra folositi MySQL ca un utilizator anonim si utilizatorii anonimi nu au voie sa schime parolele",
-"Trebuie sa aveti privilegii sa actualizati tabelele in bazele de date mysql ca sa puteti sa schimati parolele altora",
-"Nu pot gasi nici o linie corespunzatoare in tabela utilizatorului",
-"Linii identificate (matched): %ld Schimbate: %ld Atentionari (warnings): %ld",
-"Nu pot crea un thread nou (Eroare %d). Daca mai aveti memorie disponibila in sistem, puteti consulta manualul - ar putea exista un potential bug in legatura cu sistemul de operare",
-"Numarul de coloane nu corespunde cu numarul de valori la linia %ld",
-"Nu pot redeschide tabela: '%-.64s'",
-"Folosirea unei value NULL e invalida",
-"Eroarea '%-.64s' obtinuta din expresia regulara (regexp)",
-"Amestecarea de coloane GROUP (MIN(),MAX(),COUNT()...) fara coloane GROUP este ilegala daca nu exista o clauza GROUP BY",
-"Nu exista un astfel de grant definit pentru utilzatorul '%-.32s' de pe host-ul '%-.64s'",
-"Comanda %-.16s interzisa utilizatorului: '%-.32s'@'%-.64s' pentru tabela '%-.64s'",
-"Comanda %-.16s interzisa utilizatorului: '%-.32s'@'%-.64s' pentru coloana '%-.64s' in tabela '%-.64s'",
-"Comanda GRANT/REVOKE ilegala. Consultati manualul in privinta privilegiilor ce pot fi folosite.",
-"Argumentul host-ului sau utilizatorului pentru GRANT e prea lung",
-"Tabela '%-.64s.%-.64s' nu exista",
-"Nu exista un astfel de privilegiu (grant) definit pentru utilizatorul '%-.32s' de pe host-ul '%-.64s' pentru tabela '%-.64s'",
-"Comanda folosita nu este permisa pentru aceasta versiune de MySQL",
-"Aveti o eroare in sintaxa RSQL",
-"Thread-ul pentru inserarea aminata nu a putut obtine lacatul (lock) pentru tabela %-.64s",
-"Prea multe threaduri aminate care sint in uz",
-"Conectie terminata %ld la baza de date: '%-.64s' utilizator: '%-.32s' (%-.64s)",
-"Un packet mai mare decit 'max_allowed_packet' a fost primit",
-"Eroare la citire din cauza lui 'connection pipe'",
-"Eroare obtinuta de la fcntl()",
-"Packets care nu sint ordonati au fost gasiti",
-"Nu s-a putut decompresa pachetul de comunicatie (communication packet)",
-"Eroare obtinuta citind pachetele de comunicatie (communication packets)",
-"Timeout obtinut citind pachetele de comunicatie (communication packets)",
-"Eroare in scrierea pachetelor de comunicatie (communication packets)",
-"Timeout obtinut scriind pachetele de comunicatie (communication packets)",
-"Sirul rezultat este mai lung decit 'max_allowed_packet'",
-"Tipul de tabela folosit nu suporta coloane de tip BLOB/TEXT",
-"Tipul de tabela folosit nu suporta coloane de tip AUTO_INCREMENT",
-"INSERT DELAYED nu poate fi folosit cu tabela '%-.64s', deoarece este locked folosing LOCK TABLES",
-"Nume increct de coloana '%-.100s'",
-"Handler-ul tabelei folosite nu poate indexa coloana '%-.64s'",
-"Toate tabelele din tabela MERGE nu sint definite identic",
-"Nu pot scrie pe hard-drive, din cauza constraintului unic (unique constraint) pentru tabela '%-.64s'",
-"Coloana BLOB '%-.64s' este folosita in specificarea unei chei fara ca o lungime de cheie sa fie folosita",
-"Toate partile unei chei primare (PRIMARY KEY) trebuie sa fie NOT NULL; Daca aveti nevoie de NULL in vreo cheie, folositi UNIQUE in schimb",
-"Resultatul constista din mai multe linii",
-"Aceast tip de tabela are nevoie de o cheie primara",
-"Aceasta versiune de MySQL, nu a fost compilata cu suport pentru RAID",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave; run STOP SLAVE first",
-"This operation requires a running slave; configure slave and do START SLAVE",
-"The server is not configured as slave; fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure; more error messages can be found in the MySQL error log",
-"Could not create slave thread; check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
deleted file mode 100644
index 97d59cec074..00000000000
--- a/sql/share/russian/errmsg.txt
+++ /dev/null
@@ -1,326 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Translation done in 2003 by Egor Egorov; Ensita.NET, http://www.ensita.net/
-*/
-/* charset: KOI8-R */
-
-character-set=koi8r
-
-"hashchk",
-"isamchk",
-"îåô",
-"äá",
-"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÆÁÊÌ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÔÁÂÌÉÃÕ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s'. âÁÚÁ ÄÁÎÎÙÈ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ",
-"îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s'. ôÁËÏÊ ÂÁÚÙ ÄÁÎÎÙÈ ÎÅÔ",
-"ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ ÂÁÚÙ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ '%-.64s', ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ËÁÔÁÌÏÇ '%-.64s', ÏÛÉÂËÁ: %d)",
-"ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÐÒÏÞÉÔÁÔØ ÚÁÐÉÓØ × ÓÉÓÔÅÍÎÏÊ ÔÁÂÌÉÃÅ",
-"îÅ×ÏÚÍÏÖÎÏ ÐÏÌÕÞÉÔØ ÓÔÁÔÕÓÎÕÀ ÉÎÆÏÒÍÁÃÉÀ Ï '%-.64s' (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÏÐÒÅÄÅÌÉÔØ ÒÁÂÏÞÉÊ ËÁÔÁÌÏÇ (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÐÏÓÔÁ×ÉÔØ ÂÌÏËÉÒÏ×ËÕ ÎÁ ÆÁÊÌÅ (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÆÁÊÌ: '%-.64s' (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÆÁÊÌ: '%-.64s' (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÐÒÏÞÉÔÁÔØ ËÁÔÁÌÏÇ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"îÅ×ÏÚÍÏÖÎÏ ÐÅÒÅÊÔÉ × ËÁÔÁÌÏÇ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"úÁÐÉÓØ ÉÚÍÅÎÉÌÁÓØ Ó ÍÏÍÅÎÔÁ ÐÏÓÌÅÄÎÅÊ ×ÙÂÏÒËÉ × ÔÁÂÌÉÃÅ '%-.64s'",
-"äÉÓË ÚÁÐÏÌÎÅÎ. (%s). ïÖÉÄÁÅÍ, ÐÏËÁ ËÔÏ-ÔÏ ÎÅ ÕÂÅÒÅÔ ÐÏÓÌÅ ÓÅÂÑ ÍÕÓÏÒ...",
-"îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÚÁÐÉÓØ, ÄÕÂÌÉÒÕÀÝÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉÃÅ '%-.64s'",
-"ïÛÉÂËÁ ÐÒÉ ÚÁËÒÙÔÉÉ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"ïÛÉÂËÁ ÞÔÅÎÉÑ ÆÁÊÌÁ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"ïÛÉÂËÁ ÐÒÉ ÐÅÒÅÉÍÅÎÏ×ÁÎÉÉ '%-.64s' × '%-.64s' (ÏÛÉÂËÁ: %d)",
-"ïÛÉÂËÁ ÚÁÐÉÓÉ × ÆÁÊÌ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"'%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÄÌÑ ÉÚÍÅÎÅÎÉÊ",
-"óÏÒÔÉÒÏ×ËÁ ÐÒÅÒ×ÁÎÁ",
-"ðÒÅÄÓÔÁ×ÌÅÎÉÅ '%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ ÄÌÑ '%-.64s'",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d ÏÔ ÏÂÒÁÂÏÔÞÉËÁ ÔÁÂÌÉÃ",
-"ïÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ '%-.64s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÜÔÕ ×ÏÚÍÏÖÎÏÓÔØ",
-"îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÚÁÐÉÓØ × '%-.64s'",
-"îÅËÏÒÒÅËÔÎÁÑ ÉÎÆÏÒÍÁÃÉÑ × ÆÁÊÌÅ '%-.64s'",
-"îÅËÏÒÒÅËÔÎÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ: '%-.64s'. ðÏÐÒÏÂÕÊÔÅ ×ÏÓÓÔÁÎÏ×ÉÔØ ÅÇÏ",
-"óÔÁÒÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'; ÏÔÒÅÍÏÎÔÉÒÕÊÔÅ ÅÇÏ!",
-"ôÁÂÌÉÃÁ '%-.64s' ÐÒÅÄÎÁÚÎÁÞÅÎÁ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ",
-"îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ. ðÅÒÅÚÁÐÕÓÔÉÔÅ ÓÅÒ×ÅÒ É ÐÏÐÒÏÂÕÊÔÅ ÅÝÅ ÒÁÚ (ÎÕÖÎÏ %d ÂÁÊÔ)",
-"îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ ÄÌÑ ÓÏÒÔÉÒÏ×ËÉ. õ×ÅÌÉÞØÔÅ ÒÁÚÍÅÒ ÂÕÆÅÒÁ ÓÏÒÔÉÒÏ×ËÉ ÎÁ ÓÅÒ×ÅÒÅ",
-"îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ '%-.64s' (ÏÛÉÂËÁ: %d)",
-"óÌÉÛËÏÍ ÍÎÏÇÏ ÓÏÅÄÉÎÅÎÉÊ",
-"îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ; ÕÄÏÓÔÏ×ÅÒØÔÅÓØ, ÞÔÏ mysqld ÉÌÉ ËÁËÏÊ-ÌÉÂÏ ÄÒÕÇÏÊ ÐÒÏÃÅÓÓ ÎÅ ÚÁÎÉÍÁÅÔ ×ÓÀ ÄÏÓÔÕÐÎÕÀ ÐÁÍÑÔØ. åÓÌÉ ÎÅÔ, ÔÏ ×Ù ÍÏÖÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ulimit, ÞÔÏÂÙ ×ÙÄÅÌÉÔØ ÄÌÑ mysqld ÂÏÌØÛÅ ÐÁÍÑÔÉ, ÉÌÉ Õ×ÅÌÉÞÉÔØ ÏÂßÅÍ ÆÁÊÌÁ ÐÏÄËÁÞËÉ",
-"îÅ×ÏÚÍÏÖÎÏ ÐÏÌÕÞÉÔØ ÉÍÑ ÈÏÓÔÁ ÄÌÑ ×ÁÛÅÇÏ ÁÄÒÅÓÁ",
-"îÅËÏÒÒÅËÔÎÏÅ ÐÒÉ×ÅÔÓÔ×ÉÅ",
-"äÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s'@'%-.64s' ÄÏÓÔÕÐ Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÚÁËÒÙÔ",
-"äÏÓÔÕÐ ÚÁËÒÙÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s'@'%-.64s' (ÂÙÌ ÉÓÐÏÌØÚÏ×ÁÎ ÐÁÒÏÌØ: %s)",
-"âÁÚÁ ÄÁÎÎÙÈ ÎÅ ×ÙÂÒÁÎÁ",
-"îÅÉÚ×ÅÓÔÎÁÑ ËÏÍÁÎÄÁ ËÏÍÍÕÎÉËÁÃÉÏÎÎÏÇÏ ÐÒÏÔÏËÏÌÁ",
-"óÔÏÌÂÅà '%-.64s' ÎÅ ÍÏÖÅÔ ÐÒÉÎÉÍÁÔØ ×ÅÌÉÞÉÎÕ NULL",
-"îÅÉÚ×ÅÓÔÎÁÑ ÂÁÚÁ ÄÁÎÎÙÈ '%-.64s'",
-"ôÁÂÌÉÃÁ '%-.64s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ",
-"îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.175s'",
-"óÔÏÌÂÅÃ '%-.64s' × %-.64s ÚÁÄÁÎ ÎÅÏÄÎÏÚÎÁÞÎÏ",
-"óÅÒ×ÅÒ ÎÁÈÏÄÉÔÓÑ × ÐÒÏÃÅÓÓÅ ÏÓÔÁÎÏ×ËÉ",
-"îÅÉÚ×ÅÓÔÎÙÊ ÓÔÏÌÂÅà '%-.64s' × '%-.64s'",
-"'%-.64s' ÎÅ ÐÒÉÓÕÔÓÔ×ÕÅÔ × GROUP BY",
-"îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÇÒÕÐÐÉÒÏ×ËÕ ÐÏ '%-.64s'",
-"÷ÙÒÁÖÅÎÉÅ ÓÏÄÅÒÖÉÔ ÇÒÕÐÐÏ×ÙÅ ÆÕÎËÃÉÉ É ÓÔÏÌÂÃÙ, ÎÏ ÎÅ ×ËÌÀÞÁÅÔ GROUP BY. á ËÁË ×Ù ÕÍÕÄÒÉÌÉÓØ ÐÏÌÕÞÉÔØ ÜÔÏ ÓÏÏÂÝÅÎÉÅ Ï ÏÛÉÂËÅ?",
-"ëÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ× ÎÅ ÓÏ×ÐÁÄÁÅÔ Ó ËÏÌÉÞÅÓÔ×ÏÍ ÚÎÁÞÅÎÉÊ",
-"óÌÉÛËÏÍ ÄÌÉÎÎÙÊ ÉÄÅÎÔÉÆÉËÁÔÏÒ '%-.100s'",
-"äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ÓÔÏÌÂÃÁ '%-.64s'",
-"äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ËÌÀÞÁ '%-.64s'",
-"äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.64s' ÐÏ ËÌÀÞÕ %d",
-"îÅËÏÒÒÅËÔÎÙÊ ÏÐÒÅÄÅÌÉÔÅÌØ ÓÔÏÌÂÃÁ ÄÌÑ ÓÔÏÌÂÃÁ '%-.64s'",
-"%s ÏËÏÌÏ '%-.80s' ÎÁ ÓÔÒÏËÅ %d",
-"úÁÐÒÏÓ ÏËÁÚÁÌÓÑ ÐÕÓÔÙÍ",
-"ðÏ×ÔÏÒÑÀÝÁÑÓÑ ÔÁÂÌÉÃÁ/ÐÓÅ×ÄÏÎÉÍ '%-.64s'",
-"îÅËÏÒÒÅËÔÎÏÅ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ '%-.64s'",
-"õËÁÚÁÎÏ ÎÅÓËÏÌØËÏ ÐÅÒ×ÉÞÎÙÈ ËÌÀÞÅÊ",
-"õËÁÚÁÎÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ËÌÀÞÅÊ. òÁÚÒÅÛÁÅÔÓÑ ÕËÁÚÙ×ÁÔØ ÎÅ ÂÏÌÅÅ %d ËÌÀÞÅÊ",
-"õËÁÚÁÎÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÞÁÓÔÅÊ ÓÏÓÔÁ×ÎÏÇÏ ËÌÀÞÁ. òÁÚÒÅÛÁÅÔÓÑ ÕËÁÚÙ×ÁÔØ ÎÅ ÂÏÌÅÅ %d ÞÁÓÔÅÊ",
-"õËÁÚÁÎ ÓÌÉÛËÏÍ ÄÌÉÎÎÙÊ ËÌÀÞ. íÁËÓÉÍÁÌØÎÁÑ ÄÌÉÎÁ ËÌÀÞÁ ÓÏÓÔÁ×ÌÑÅÔ %d ÂÁÊÔ",
-"ëÌÀÞÅ×ÏÊ ÓÔÏÌÂÅà '%-.64s' × ÔÁÂÌÉÃÅ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ",
-"óÔÏÌÂÅà ÔÉÐÁ BLOB '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ËÁË ÚÎÁÞÅÎÉÅ ËÌÀÞÁ × ÔÁÂÌÉÃÅ ÔÁËÏÇÏ ÔÉÐÁ",
-"óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.64s' (ÍÁËÓÉÍÕÍ = %d). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ",
-"îÅËÏÒÒÅËÔÎÏÅ ÏÐÒÅÄÅÌÅÎÉÅ ÔÁÂÌÉÃÙ: ÍÏÖÅÔ ÓÕÝÅÓÔ×Ï×ÁÔØ ÔÏÌØËÏ ÏÄÉÎ Á×ÔÏÉÎËÒÅÍÅÎÔÎÙÊ ÓÔÏÌÂÅÃ, É ÏÎ ÄÏÌÖÅÎ ÂÙÔØ ÏÐÒÅÄÅÌÅÎ ËÁË ËÌÀÞ",
-"%s: çÏÔÏ× ÐÒÉÎÉÍÁÔØ ÓÏÅÄÉÎÅÎÉÑ.\n÷ÅÒÓÉÑ: '%s' ÓÏËÅÔ: '%s' ÐÏÒÔ: %d",
-"%s: ëÏÒÒÅËÔÎÁÑ ÏÓÔÁÎÏ×ËÁ\n",
-"%s: ðÏÌÕÞÅÎ ÓÉÇÎÁÌ %d. ðÒÅËÒÁÝÁÅÍ!\n",
-"%s: ïÓÔÁÎÏ×ËÁ ÚÁ×ÅÒÛÅÎÁ\n",
-"%s: ðÒÉÎÕÄÉÔÅÌØÎÏ ÚÁËÒÙ×ÁÅÍ ÐÏÔÏË %ld ÐÏÌØÚÏ×ÁÔÅÌÑ: '%-.32s'\n",
-"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ IP-ÓÏËÅÔ",
-"÷ ÔÁÂÌÉÃÅ '%-.64s' ÎÅÔ ÔÁËÏÇÏ ÉÎÄÅËÓÁ, ËÁË × CREATE INDEX. óÏÚÄÁÊÔÅ ÔÁÂÌÉÃÕ ÚÁÎÏ×Ï",
-"áÒÇÕÍÅÎÔ ÒÁÚÄÅÌÉÔÅÌÑ ÐÏÌÅÊ - ÎÅ ÔÏÔ, ËÏÔÏÒÙÊ ÏÖÉÄÁÌÓÑ. ïÂÒÁÝÁÊÔÅÓØ Ë ÄÏËÕÍÅÎÔÁÃÉÉ",
-"æÉËÓÉÒÏ×ÁÎÎÙÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ Ó ÐÏÌÑÍÉ ÔÉÐÁ BLOB ÉÓÐÏÌØÚÏ×ÁÔØ ÎÅÌØÚÑ, ÐÒÉÍÅÎÑÊÔÅ 'fields terminated by'",
-"æÁÊÌ '%-.64s' ÄÏÌÖÅÎ ÎÁÈÏÄÉÔØÓÑ × ÔÏÍ ÖÅ ËÁÔÁÌÏÇÅ, ÞÔÏ É ÂÁÚÁ ÄÁÎÎÙÈ, ÉÌÉ ÂÙÔØ ÏÂÝÅÄÏÓÔÕÐÎÙÍ ÄÌÑ ÞÔÅÎÉÑ",
-"æÁÊÌ '%-.80s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ",
-"úÁÐÉÓÅÊ: %ld õÄÁÌÅÎÏ: %ld ðÒÏÐÕÝÅÎÏ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld",
-"úÁÐÉÓÅÊ: %ld äÕÂÌÉËÁÔÏ×: %ld",
-"îÅËÏÒÒÅËÔÎÁÑ ÞÁÓÔØ ËÌÀÞÁ. éÓÐÏÌØÚÕÅÍÁÑ ÞÁÓÔØ ËÌÀÞÁ ÎÅ Ñ×ÌÑÅÔÓÑ ÓÔÒÏËÏÊ, ÕËÁÚÁÎÎÁÑ ÄÌÉÎÁ ÂÏÌØÛÅ, ÞÅÍ ÄÌÉÎÁ ÞÁÓÔÉ ËÌÀÞÁ, ÉÌÉ ÏÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÕÎÉËÁÌØÎÙÅ ÞÁÓÔÉ ËÌÀÞÁ",
-"îÅÌØÚÑ ÕÄÁÌÉÔØ ×ÓÅ ÓÔÏÌÂÃÙ Ó ÐÏÍÏÝØÀ ALTER TABLE. éÓÐÏÌØÚÕÊÔÅ DROP TABLE",
-"îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ (DROP) '%-.64s'. õÂÅÄÉÔÅÓØ ÞÔÏ ÓÔÏÌÂÅÃ/ËÌÀÞ ÄÅÊÓÔ×ÉÔÅÌØÎÏ ÓÕÝÅÓÔ×ÕÅÔ",
-"úÁÐÉÓÅÊ: %ld äÕÂÌÉËÁÔÏ×: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld",
-"îÅ ÄÏÐÕÓËÁÅÔÓÑ ÕËÁÚÁÎÉÅ ÔÁÂÌÉÃÙ '%-.64s' × ÓÐÉÓËÅ ÔÁÂÌÉà FROM ÄÌÑ ×ÎÅÓÅÎÉÑ × ÎÅÅ ÉÚÍÅÎÅÎÉÊ",
-"îÅÉÚ×ÅÓÔÎÙÊ ÎÏÍÅÒ ÐÏÔÏËÁ: %lu",
-"÷Ù ÎÅ Ñ×ÌÑÅÔÅÓØ ×ÌÁÄÅÌØÃÅÍ ÐÏÔÏËÁ %lu",
-"îÉËÁËÉÅ ÔÁÂÌÉÃÙ ÎÅ ÉÓÐÏÌØÚÏ×ÁÎÙ",
-"óÌÉÛËÏÍ ÍÎÏÇÏ ÚÎÁÞÅÎÉÊ ÄÌÑ ÓÔÏÌÂÃÁ %-.64s × SET",
-"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÕÎÉËÁÌØÎÏÅ ÉÍÑ ÆÁÊÌÁ ÖÕÒÎÁÌÁ %-.64s.(1-999)\n",
-"ôÁÂÌÉÃÁ '%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎÁ ÕÒÏ×ÎÅÍ READ lock É ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÚÍÅÎÅÎÁ",
-"ôÁÂÌÉÃÁ '%-.64s' ÎÅ ÂÙÌÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES",
-"îÅ×ÏÚÍÏÖÎÏ ÕËÁÚÙ×ÁÔØ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ ÓÔÏÌÂÃÁ BLOB '%-.64s'",
-"îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÂÁÚÙ ÄÁÎÎÙÈ '%-.100s'",
-"îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÔÁÂÌÉÃÙ '%-.100s'",
-"äÌÑ ÔÁËÏÊ ×ÙÂÏÒËÉ SELECT ÄÏÌÖÅÎ ÂÕÄÅÔ ÐÒÏÓÍÏÔÒÅÔØ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÚÁÐÉÓÅÊ É, ×ÉÄÉÍÏ, ÜÔÏ ÚÁÊÍÅÔ ÏÞÅÎØ ÍÎÏÇÏ ×ÒÅÍÅÎÉ. ðÒÏ×ÅÒØÔÅ ×ÁÛÅ ÕËÁÚÁÎÉÅ WHERE, É, ÅÓÌÉ × ÎÅÍ ×ÓÅ × ÐÏÒÑÄËÅ, ÕËÁÖÉÔÅ SET SQL_BIG_SELECTS=1",
-"îÅÉÚ×ÅÓÔÎÁÑ ÏÛÉÂËÁ",
-"îÅÉÚ×ÅÓÔÎÁÑ ÐÒÏÃÅÄÕÒÁ '%-.64s'",
-"îÅËÏÒÒÅËÔÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÐÁÒÁÍÅÔÒÏ× ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.64s'",
-"îÅËÏÒÒÅËÔÎÙÅ ÐÁÒÁÍÅÔÒÙ ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.64s'",
-"îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.64s' × %-.32s",
-"óÔÏÌÂÅà '%-.64s' ÕËÁÚÁÎ Ä×ÁÖÄÙ",
-"îÅÐÒÁ×ÉÌØÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÇÒÕÐÐÏ×ÙÈ ÆÕÎËÃÉÊ",
-"÷ ÔÁÂÌÉÃÅ '%-.64s' ÉÓÐÏÌØÚÕÀÔÓÑ ×ÏÚÍÏÖÎÏÓÔÉ, ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÍÙÅ × ÜÔÏÊ ×ÅÒÓÉÉ MySQL",
-"÷ ÔÁÂÌÉÃÅ ÄÏÌÖÅÎ ÂÙÔØ ËÁË ÍÉÎÉÍÕÍ ÏÄÉÎ ÓÔÏÌÂÅÃ",
-"ôÁÂÌÉÃÁ '%-.64s' ÐÅÒÅÐÏÌÎÅÎÁ",
-"îÅÉÚ×ÅÓÔÎÁÑ ËÏÄÉÒÏ×ËÁ '%-.64s'",
-"óÌÉÛËÏÍ ÍÎÏÇÏ ÔÁÂÌÉÃ. MySQL ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÔÏÌØËÏ %d ÔÁÂÌÉÃ × ÓÏÅÄÉÎÅÎÉÉ",
-"óÌÉÛËÏÍ ÍÎÏÇÏ ÓÔÏÌÂÃÏ×",
-"óÌÉÛËÏÍ ÂÏÌØÛÏÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ. íÁËÓÉÍÁÌØÎÙÊ ÒÁÚÍÅÒ ÓÔÒÏËÉ, ÉÓËÌÀÞÁÑ ÐÏÌÑ BLOB, - %d. ÷ÏÚÍÏÖÎÏ, ×ÁÍ ÓÌÅÄÕÅÔ ÉÚÍÅÎÉÔØ ÔÉÐ ÎÅËÏÔÏÒÙÈ ÐÏÌÅÊ ÎÁ BLOB",
-"óÔÅË ÐÏÔÏËÏ× ÐÅÒÅÐÏÌÎÅÎ: ÉÓÐÏÌØÚÏ×ÁÎÏ: %ld ÉÚ %ld ÓÔÅËÁ. ðÒÉÍÅÎÑÊÔÅ 'mysqld -O thread_stack=#' ÄÌÑ ÕËÁÚÁÎÉÑ ÂÏÌØÛÅÇÏ ÒÁÚÍÅÒÁ ÓÔÅËÁ, ÅÓÌÉ ÎÅÏÂÈÏÄÉÍÏ",
-"÷ OUTER JOIN ÏÂÎÁÒÕÖÅÎÁ ÐÅÒÅËÒÅÓÔÎÁÑ ÚÁ×ÉÓÉÍÏÓÔØ. ÷ÎÉÍÁÔÅÌØÎÏ ÐÒÏÁÎÁÌÉÚÉÒÕÊÔÅ Ó×ÏÉ ÕÓÌÏ×ÉÑ ON",
-"óÔÏÌÂÅÃ '%-.64s' ÉÓÐÏÌØÚÕÅÔÓÑ × UNIQUE ÉÌÉ × INDEX, ÎÏ ÎÅ ÏÐÒÅÄÅÌÅÎ ËÁË NOT NULL",
-"îÅ×ÏÚÍÏÖÎÏ ÚÁÇÒÕÚÉÔØ ÆÕÎËÃÉÀ '%-.64s'",
-"îÅ×ÏÚÍÏÖÎÏ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÔØ ÆÕÎËÃÉÀ '%-.64s'; %-.80s",
-"îÅÄÏÐÕÓÔÉÍÏ ÕËÁÚÙ×ÁÔØ ÐÕÔÉ ÄÌÑ ÄÉÎÁÍÉÞÅÓËÉÈ ÂÉÂÌÉÏÔÅË",
-"æÕÎËÃÉÑ '%-.64s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ",
-"îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÄÉÎÁÍÉÞÅÓËÕÀ ÂÉÂÌÉÏÔÅËÕ '%-.64s' (ÏÛÉÂËÁ: %d %-.64s)",
-"îÅ×ÏÚÍÏÖÎÏ ÏÔÙÓËÁÔØ ÆÕÎËÃÉÀ '%-.64s' × ÂÉÂÌÉÏÔÅËÅ",
-"æÕÎËÃÉÑ '%-.64s' ÎÅ ÏÐÒÅÄÅÌÅÎÁ",
-"èÏÓÔ '%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÉÚ-ÚÁ ÓÌÉÛËÏÍ ÂÏÌØÛÏÇÏ ËÏÌÉÞÅÓÔ×Á ÏÛÉÂÏË ÓÏÅÄÉÎÅÎÉÑ. òÁÚÂÌÏËÉÒÏ×ÁÔØ ÅÇÏ ÍÏÖÎÏ Ó ÐÏÍÏÝØÀ 'mysqladmin flush-hosts'",
-"èÏÓÔÕ '%-.64s' ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÐÏÄËÌÀÞÁÔØÓÑ Ë ÜÔÏÍÕ ÓÅÒ×ÅÒÕ MySQL",
-"÷Ù ÉÓÐÏÌØÚÕÅÔÅ MySQL ÏÔ ÉÍÅÎÉ ÁÎÏÎÉÍÎÏÇÏ ÐÏÌØÚÏ×ÁÔÅÌÑ, Á ÁÎÏÎÉÍÎÙÍ ÐÏÌØÚÏ×ÁÔÅÌÑÍ ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÍÅÎÑÔØ ÐÁÒÏÌÉ",
-"äÌÑ ÔÏÇÏ ÞÔÏÂÙ ÉÚÍÅÎÑÔØ ÐÁÒÏÌÉ ÄÒÕÇÉÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ, Õ ×ÁÓ ÄÏÌÖÎÙ ÂÙÔØ ÐÒÉ×ÉÌÅÇÉÉ ÎÁ ÉÚÍÅÎÅÎÉÅ ÔÁÂÌÉÃ × ÂÁÚÅ ÄÁÎÎÙÈ mysql",
-"îÅ×ÏÚÍÏÖÎÏ ÏÔÙÓËÁÔØ ÐÏÄÈÏÄÑÝÕÀ ÚÁÐÉÓØ × ÔÁÂÌÉÃÅ ÐÏÌØÚÏ×ÁÔÅÌÅÊ",
-"óÏ×ÐÁÌÏ ÚÁÐÉÓÅÊ: %ld éÚÍÅÎÅÎÏ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld",
-"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÎÏ×ÙÊ ÐÏÔÏË (ÏÛÉÂËÁ %d). åÓÌÉ ÜÔÏ ÎÅ ÓÉÔÕÁÃÉÑ, Ó×ÑÚÁÎÎÁÑ Ó ÎÅÈ×ÁÔËÏÊ ÐÁÍÑÔÉ, ÔÏ ×ÁÍ ÓÌÅÄÕÅÔ ÉÚÕÞÉÔØ ÄÏËÕÍÅÎÔÁÃÉÀ ÎÁ ÐÒÅÄÍÅÔ ÏÐÉÓÁÎÉÑ ×ÏÚÍÏÖÎÏÊ ÏÛÉÂËÉ ÒÁÂÏÔÙ × ËÏÎËÒÅÔÎÏÊ ïó",
-"ëÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ× ÎÅ ÓÏ×ÐÁÄÁÅÔ Ó ËÏÌÉÞÅÓÔ×ÏÍ ÚÎÁÞÅÎÉÊ × ÚÁÐÉÓÉ %ld",
-"îÅ×ÏÚÍÏÖÎÏ ÚÁÎÏ×Ï ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ '%-.64s'",
-"îÅÐÒÁ×ÉÌØÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ×ÅÌÉÞÉÎÙ NULL",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ '%-.64s' ÏÔ ÒÅÇÕÌÑÒÎÏÇÏ ×ÙÒÁÖÅÎÉÑ",
-"ïÄÎÏ×ÒÅÍÅÎÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÓÇÒÕÐÐÉÒÏ×ÁÎÎÙÈ (GROUP) ÓÔÏÌÂÃÏ× (MIN(),MAX(),COUNT(),...) Ó ÎÅÓÇÒÕÐÐÉÒÏ×ÁÎÎÙÍÉ ÓÔÏÌÂÃÁÍÉ Ñ×ÌÑÅÔÓÑ ÎÅËÏÒÒÅËÔÎÙÍ, ÅÓÌÉ × ×ÙÒÁÖÅÎÉÉ ÅÓÔØ GROUP BY",
-"ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' ÎÁ ÈÏÓÔÅ '%-.64s'",
-"ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s'@'%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'",
-"ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s'@'%-.64s' ÄÌÑ ÓÔÏÌÂÃÁ '%-.64s' × ÔÁÂÌÉÃÅ '%-.64s'",
-"îÅ×ÅÒÎÁÑ ËÏÍÁÎÄÁ GRANT ÉÌÉ REVOKE. ïÂÒÁÔÉÔÅÓØ Ë ÄÏËÕÍÅÎÔÁÃÉÉ, ÞÔÏÂÙ ×ÙÑÓÎÉÔØ, ËÁËÉÅ ÐÒÉ×ÉÌÅÇÉÉ ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ",
-"óÌÉÛËÏÍ ÄÌÉÎÎÏÅ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ/ÈÏÓÔÁ ÄÌÑ GRANT",
-"ôÁÂÌÉÃÁ '%-.64s.%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ",
-"ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' ÎÁ ËÏÍÐØÀÔÅÒÅ '%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'",
-"üÔÁ ËÏÍÁÎÄÁ ÎÅ ÄÏÐÕÓËÁÅÔÓÑ × ÄÁÎÎÏÊ ×ÅÒÓÉÉ MySQL",
-"õ ×ÁÓ ÏÛÉÂËÁ × ÚÁÐÒÏÓÅ. éÚÕÞÉÔÅ ÄÏËÕÍÅÎÔÁÃÉÀ ÐÏ ÉÓÐÏÌØÚÕÅÍÏÊ ×ÅÒÓÉÉ MySQL ÎÁ ÐÒÅÄÍÅÔ ËÏÒÒÅËÔÎÏÇÏ ÓÉÎÔÁËÓÉÓÁ",
-"ðÏÔÏË, ÏÂÓÌÕÖÉ×ÁÀÝÉÊ ÏÔÌÏÖÅÎÎÕÀ ×ÓÔÁ×ËÕ (delayed insert), ÎÅ ÓÍÏÇ ÐÏÌÕÞÉÔØ ÚÁÐÒÁÛÉ×ÁÅÍÕÀ ÂÌÏËÉÒÏ×ËÕ ÎÁ ÔÁÂÌÉÃÕ %-.64s",
-"óÌÉÛËÏÍ ÍÎÏÇÏ ÐÏÔÏËÏ×, ÏÂÓÌÕÖÉ×ÁÀÝÉÈ ÏÔÌÏÖÅÎÎÕÀ ×ÓÔÁ×ËÕ (delayed insert)",
-"ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' (%-.64s)",
-"ðÏÌÕÞÅÎÎÙÊ ÐÁËÅÔ ÂÏÌØÛÅ, ÞÅÍ 'max_allowed_packet'",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ ÞÔÅÎÉÑ ÏÔ ÐÏÔÏËÁ ÓÏÅÄÉÎÅÎÉÑ (connection pipe)",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ ÏÔ fcntl()",
-"ðÁËÅÔÙ ÐÏÌÕÞÅÎÙ × ÎÅ×ÅÒÎÏÍ ÐÏÒÑÄËÅ",
-"îÅ×ÏÚÍÏÖÎÏ ÒÁÓÐÁËÏ×ÁÔØ ÐÁËÅÔ, ÐÏÌÕÞÅÎÎÙÊ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ × ÐÒÏÃÅÓÓÅ ÐÏÌÕÞÅÎÉÑ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ ",
-"ðÏÌÕÞÅÎ ÔÁÊÍÁÕÔ ÏÖÉÄÁÎÉÑ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ ",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ ÐÒÉ ÐÅÒÅÄÁÞÅ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ ",
-"ðÏÌÕÞÅÎ ÔÁÊÍÁÕÔ × ÐÒÏÃÅÓÓÅ ÐÅÒÅÄÁÞÉ ÐÁËÅÔÁ ÞÅÒÅÚ ËÏÍÍÕÎÉËÁÃÉÏÎÎÙÊ ÐÒÏÔÏËÏÌ ",
-"òÅÚÕÌØÔÉÒÕÀÝÁÑ ÓÔÒÏËÁ ÂÏÌØÛÅ, ÞÅÍ 'max_allowed_packet'",
-"éÓÐÏÌØÚÕÅÍÁÑ ÔÁÂÌÉÃÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÔÉÐÙ BLOB/TEXT",
-"éÓÐÏÌØÚÕÅÍÁÑ ÔÁÂÌÉÃÁ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ Á×ÔÏÉÎËÒÅÍÅÎÔÎÙÅ ÓÔÏÌÂÃÙ",
-"îÅÌØÚÑ ÉÓÐÏÌØÚÏ×ÁÔØ INSERT DELAYED ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s', ÐÏÔÏÍÕ ÞÔÏ ÏÎÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES",
-"îÅ×ÅÒÎÏÅ ÉÍÑ ÓÔÏÌÂÃÁ '%-.100s'",
-"éÓÐÏÌØÚÏ×ÁÎÎÙÊ ÏÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÍÏÖÅÔ ÐÒÏÉÎÄÅËÓÉÒÏ×ÁÔØ ÓÔÏÌÂÅà '%-.64s'",
-"îÅ ×ÓÅ ÔÁÂÌÉÃÙ × MERGE ÏÐÒÅÄÅÌÅÎÙ ÏÄÉÎÁËÏ×Ï",
-"îÅ×ÏÚÍÏÖÎÏ ÚÁÐÉÓÁÔØ × ÔÁÂÌÉÃÕ '%-.64s' ÉÚ-ÚÁ ÏÇÒÁÎÉÞÅÎÉÊ ÕÎÉËÁÌØÎÏÇÏ ËÌÀÞÁ",
-"óÔÏÌÂÅÃ ÔÉÐÁ BLOB '%-.64s' ÂÙÌ ÕËÁÚÁÎ × ÏÐÒÅÄÅÌÅÎÉÉ ËÌÀÞÁ ÂÅÚ ÕËÁÚÁÎÉÑ ÄÌÉÎÙ ËÌÀÞÁ",
-"÷ÓÅ ÞÁÓÔÉ ÐÅÒ×ÉÞÎÏÇÏ ËÌÀÞÁ (PRIMARY KEY) ÄÏÌÖÎÙ ÂÙÔØ ÏÐÒÅÄÅÌÅÎÙ ËÁË NOT NULL; åÓÌÉ ×ÁÍ ÎÕÖÎÁ ÐÏÄÄÅÒÖËÁ ×ÅÌÉÞÉÎ NULL × ËÌÀÞÅ, ×ÏÓÐÏÌØÚÕÊÔÅÓØ ÉÎÄÅËÓÏÍ UNIQUE",
-"÷ ÒÅÚÕÌØÔÁÔÅ ×ÏÚ×ÒÁÝÅÎÁ ÂÏÌÅÅ ÞÅÍ ÏÄÎÁ ÓÔÒÏËÁ",
-"üÔÏÔ ÔÉÐ ÔÁÂÌÉÃÙ ÔÒÅÂÕÅÔ ÏÐÒÅÄÅÌÅÎÉÑ ÐÅÒ×ÉÞÎÏÇÏ ËÌÀÞÁ",
-"üÔÁ ×ÅÒÓÉÑ MySQL ÓËÏÍÐÉÌÉÒÏ×ÁÎÁ ÂÅÚ ÐÏÄÄÅÒÖËÉ RAID",
-"÷Ù ÒÁÂÏÔÁÅÔÅ × ÒÅÖÉÍÅ ÂÅÚÏÐÁÓÎÙÈ ÏÂÎÏ×ÌÅÎÉÊ (safe update mode) É ÐÏÐÒÏÂÏ×ÁÌÉ ÉÚÍÅÎÉÔØ ÔÁÂÌÉÃÕ ÂÅÚ ÉÓÐÏÌØÚÏ×ÁÎÉÑ ËÌÀÞÅ×ÏÇÏ ÓÔÏÌÂÃÁ × ÞÁÓÔÉ WHERE",
-"ëÌÀÞ '%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ × ÔÁÂÌÉÃÅ '%-.64s'",
-"îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ",
-"ïÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÜÔÏÇÏ: %s",
-"÷ÁÍ ÎÅ ÒÁÚÒÅÛÅÎÏ ×ÙÐÏÌÎÑÔØ ÜÔÕ ËÏÍÁÎÄÕ × ÔÒÁÎÚÁËÃÉÉ",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ COMMIT",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ ROLLBACK",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ FLUSH_LOGS",
-"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ %d × ÐÒÏÃÅÓÓÅ CHECKPOINT",
-"ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' Ó ÈÏÓÔÁ `%-.64s' (%-.64s)",
-"ïÂÒÁÂÏÔÞÉË ÜÔÏÊ ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ Ä×ÏÉÞÎÏÇÏ ÓÏÈÒÁÎÅÎÉÑ ÏÂÒÁÚÁ ÔÁÂÌÉÃÙ (dump)",
-"ä×ÏÉÞÎÙÊ ÖÕÒÎÁÌ ÏÂÎÏ×ÌÅÎÉÑ ÚÁËÒÙÔ, ÎÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ RESET MASTER",
-"ïÛÉÂËÁ ÐÅÒÅÓÔÒÏÊËÉ ÉÎÄÅËÓÁ ÓÏÈÒÁÎÅÎÎÏÊ ÔÁÂÌÉÃÙ '%-.64s'",
-"ïÛÉÂËÁ ÏÔ ÇÏÌÏ×ÎÏÇÏ ÓÅÒ×ÅÒÁ: '%-.64s'",
-"÷ÏÚÎÉËÌÁ ÏÛÉÂËÁ ÞÔÅÎÉÑ × ÐÒÏÃÅÓÓÅ ËÏÍÍÕÎÉËÁÃÉÉ Ó ÇÏÌÏ×ÎÙÍ ÓÅÒ×ÅÒÏÍ",
-"÷ÏÚÎÉËÌÁ ÏÛÉÂËÁ ÚÁÐÉÓÉ × ÐÒÏÃÅÓÓÅ ËÏÍÍÕÎÉËÁÃÉÉ Ó ÇÏÌÏ×ÎÙÍ ÓÅÒ×ÅÒÏÍ",
-"îÅ×ÏÚÍÏÖÎÏ ÏÔÙÓËÁÔØ ÐÏÌÎÏÔÅËÓÔÏ×ÙÊ (FULLTEXT) ÉÎÄÅËÓ, ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÓÐÉÓËÕ ÓÔÏÌÂÃÏ×",
-"îÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ ÕËÁÚÁÎÎÕÀ ËÏÍÁÎÄÕ, ÐÏÓËÏÌØËÕ Õ ×ÁÓ ÐÒÉÓÕÔÓÔ×ÕÀÔ ÁËÔÉ×ÎÏ ÚÁÂÌÏËÉÒÏ×ÁÎÎÙÅ ÔÁÂÌÉÃÁ ÉÌÉ ÏÔËÒÙÔÁÑ ÔÒÁÎÚÁËÃÉÑ",
-"îÅÉÚ×ÅÓÔÎÁÑ ÓÉÓÔÅÍÎÁÑ ÐÅÒÅÍÅÎÎÁÑ '%-.64s'",
-"ôÁÂÌÉÃÁ '%-.64s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÄÏÌÖÎÁ ÐÒÏÊÔÉ ÐÒÏ×ÅÒËÕ É ÒÅÍÏÎÔ",
-"ôÁÂÌÉÃÁ '%-.64s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÐÏÓÌÅÄÎÉÊ (Á×ÔÏÍÁÔÉÞÅÓËÉÊ?) ÒÅÍÏÎÔ ÎÅ ÂÙÌ ÕÓÐÅÛÎÙÍ",
-"÷ÎÉÍÁÎÉÅ: ÐÏ ÎÅËÏÔÏÒÙÍ ÉÚÍÅÎÅÎÎÙÍ ÎÅÔÒÁÎÚÁËÃÉÏÎÎÙÍ ÔÁÂÌÉÃÁÍ ÎÅ×ÏÚÍÏÖÎÏ ÂÕÄÅÔ ÐÒÏÉÚ×ÅÓÔÉ ÏÔËÁÔ ÔÒÁÎÚÁËÃÉÉ",
-"ôÒÁÎÚÁËÃÉÉ, ×ËÌÀÞÁÀÝÅÊ ÂÏÌØÛÏÅ ËÏÌÉÞÅÓÔ×Ï ËÏÍÁÎÄ, ÐÏÔÒÅÂÏ×ÁÌÏÓØ ÂÏÌÅÅ ÞÅÍ 'max_binlog_cache_size' ÂÁÊÔ. õ×ÅÌÉÞØÔÅ ÜÔÕ ÐÅÒÅÍÅÎÎÕÀ ÓÅÒ×ÅÒÁ mysqld É ÐÏÐÒÏÂÕÊÔÅ ÅÝÅ ÒÁÚ",
-"üÔÕ ÏÐÅÒÁÃÉÀ ÎÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ ÐÒÉ ÒÁÂÏÔÁÀÝÅÍ ÐÏÔÏËÅ ÐÏÄÞÉÎÅÎÎÏÇÏ ÓÅÒ×ÅÒÁ. óÎÁÞÁÌÁ ×ÙÐÏÌÎÉÔÅ STOP SLAVE",
-"äÌÑ ÜÔÏÊ ÏÐÅÒÁÃÉÉ ÔÒÅÂÕÅÔÓÑ ÒÁÂÏÔÁÀÝÉÊ ÐÏÄÞÉÎÅÎÎÙÊ ÓÅÒ×ÅÒ. óÎÁÞÁÌÁ ×ÙÐÏÌÎÉÔÅ START SLAVE",
-"üÔÏÔ ÓÅÒ×ÅÒ ÎÅ ÎÁÓÔÒÏÅÎ ËÁË ÐÏÄÞÉÎÅÎÎÙÊ. ÷ÎÅÓÉÔÅ ÉÓÐÒÁ×ÌÅÎÉÑ × ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÍ ÆÁÊÌÅ ÉÌÉ Ó ÐÏÍÏÝØÀ CHANGE MASTER TO",
-"Could not initialize master info structure, more error messages can be found in the MySQL error log",
-"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÐÏÔÏË ÐÏÄÞÉÎÅÎÎÏÇÏ ÓÅÒ×ÅÒÁ. ðÒÏ×ÅÒØÔÅ ÓÉÓÔÅÍÎÙÅ ÒÅÓÕÒÓÙ",
-"õ ÐÏÌØÚÏ×ÁÔÅÌÑ %-.64s ÕÖÅ ÂÏÌØÛÅ ÞÅÍ 'max_user_connections' ÁËÔÉ×ÎÙÈ ÓÏÅÄÉÎÅÎÉÊ",
-"÷Ù ÍÏÖÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ × SET ÔÏÌØËÏ ËÏÎÓÔÁÎÔÎÙÅ ×ÙÒÁÖÅÎÉÑ",
-"ôÁÊÍÁÕÔ ÏÖÉÄÁÎÉÑ ÂÌÏËÉÒÏ×ËÉ ÉÓÔÅË; ÐÏÐÒÏÂÕÊÔÅ ÐÅÒÅÚÁÐÕÓÔÉÔØ ÔÒÁÎÚÁËÃÉÀ",
-"ïÂÝÅÅ ËÏÌÉÞÅÓÔ×Ï ÂÌÏËÉÒÏ×ÏË ÐÒÅ×ÙÓÉÌÏ ÒÁÚÍÅÒÙ ÔÁÂÌÉÃÙ ÂÌÏËÉÒÏ×ÏË",
-"âÌÏËÉÒÏ×ËÉ ÏÂÎÏ×ÌÅÎÉÊ ÎÅÌØÚÑ ÐÏÌÕÞÉÔØ × ÐÒÏÃÅÓÓÅ ÞÔÅÎÉÑ ÎÅ ÐÒÉÎÑÔÏÊ (× ÒÅÖÉÍÅ READ UNCOMMITTED) ÔÒÁÎÚÁËÃÉÉ",
-"îÅ ÄÏÐÕÓËÁÅÔÓÑ DROP DATABASE, ÐÏËÁ ÐÏÔÏË ÄÅÒÖÉÔ ÇÌÏÂÁÌØÎÕÀ ÂÌÏËÉÒÏ×ËÕ ÞÔÅÎÉÑ",
-"îÅ ÄÏÐÕÓËÁÅÔÓÑ CREATE DATABASE, ÐÏËÁ ÐÏÔÏË ÄÅÒÖÉÔ ÇÌÏÂÁÌØÎÕÀ ÂÌÏËÉÒÏ×ËÕ ÞÔÅÎÉÑ",
-"îÅ×ÅÒÎÙÅ ÐÁÒÁÍÅÔÒÙ ÄÌÑ %s",
-"'%-.32s'@'%-.64s' ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÓÏÚÄÁ×ÁÔØ ÎÏ×ÙÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ",
-"îÅ×ÅÒÎÏÅ ÏÐÒÅÄÅÌÅÎÉÅ ÔÁÂÌÉÃÙ; ÷ÓÅ ÔÁÂÌÉÃÙ × MERGE ÄÏÌÖÎÙ ÐÒÉÎÁÄÌÅÖÁÔØ ÏÄÎÏÊ É ÔÏÊ ÖÅ ÂÁÚÅ ÄÁÎÎÙÈ",
-"÷ÏÚÎÉËÌÁ ÔÕÐÉËÏ×ÁÑ ÓÉÔÕÁÃÉÑ × ÐÒÏÃÅÓÓÅ ÐÏÌÕÞÅÎÉÑ ÂÌÏËÉÒÏ×ËÉ; ðÏÐÒÏÂÕÊÔÅ ÐÅÒÅÚÁÐÕÓÔÉÔØ ÔÒÁÎÚÁËÃÉÀ",
-"éÓÐÏÌØÚÕÅÍÙÊ ÔÉÐ ÔÁÂÌÉà ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÏÌÎÏÔÅËÓÔÏ×ÙÈ ÉÎÄÅËÓÏ×",
-"îÅ×ÏÚÍÏÖÎÏ ÄÏÂÁ×ÉÔØ ÏÇÒÁÎÉÞÅÎÉÑ ×ÎÅÛÎÅÇÏ ËÌÀÞÁ",
-"îÅ×ÏÚÍÏÖÎÏ ÄÏÂÁ×ÉÔØ ÉÌÉ ÏÂÎÏ×ÉÔØ ÄÏÞÅÒÎÀÀ ÓÔÒÏËÕ: ÐÒÏ×ÅÒËÁ ÏÇÒÁÎÉÞÅÎÉÊ ×ÎÅÛÎÅÇÏ ËÌÀÞÁ ÎÅ ×ÙÐÏÌÎÑÅÔÓÑ",
-"îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÉÌÉ ÏÂÎÏ×ÉÔØ ÒÏÄÉÔÅÌØÓËÕÀ ÓÔÒÏËÕ: ÐÒÏ×ÅÒËÁ ÏÇÒÁÎÉÞÅÎÉÊ ×ÎÅÛÎÅÇÏ ËÌÀÞÁ ÎÅ ×ÙÐÏÌÎÑÅÔÓÑ",
-"ïÛÉÂËÁ ÓÏÅÄÉÎÅÎÉÑ Ó ÇÏÌÏ×ÎÙÍ ÓÅÒ×ÅÒÏÍ: %-.128s",
-"ïÛÉÂËÁ ×ÙÐÏÌÎÅÎÉÑ ÚÁÐÒÏÓÁ ÎÁ ÇÏÌÏ×ÎÏÍ ÓÅÒ×ÅÒÅ: %-.128s",
-"ïÛÉÂËÁ ÐÒÉ ×ÙÐÏÌÎÅÎÉÉ ËÏÍÁÎÄÙ %s: %-.128s",
-"îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ %s É %s",
-"éÓÐÏÌØÚÏ×ÁÎÎÙÅ ÏÐÅÒÁÔÏÒÙ ×ÙÂÏÒËÉ (SELECT) ÄÁÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×",
-"îÅ×ÏÚÍÏÖÎÏ ÉÓÐÏÌÎÉÔØ ÚÁÐÒÏÓ, ÐÏÓËÏÌØËÕ Õ ×ÁÓ ÕÓÔÁÎÏ×ÌÅÎÙ ËÏÎÆÌÉËÔÕÀÝÉÅ ÂÌÏËÉÒÏ×ËÉ ÞÔÅÎÉÑ",
-"éÓÐÏÌØÚÏ×ÁÎÉÅ ÔÒÁÎÚÁËÃÉÏÎÎÙÈ ÔÁÂÌÉà ÎÁÒÑÄÕ Ó ÎÅÔÒÁÎÚÁËÃÉÏÎÎÙÍÉ ÚÁÐÒÅÝÅÎÏ",
-"ïÐÃÉÑ '%s' Ä×ÁÖÄÙ ÉÓÐÏÌØÚÏ×ÁÎÁ × ×ÙÒÁÖÅÎÉÉ",
-"ðÏÌØÚÏ×ÁÔÅÌØ '%-.64s' ÐÒÅ×ÙÓÉÌ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÒÅÓÕÒÓÁ '%s' (ÔÅËÕÝÅÅ ÚÎÁÞÅÎÉÅ: %ld)",
-"÷ ÄÏÓÔÕÐÅ ÏÔËÁÚÁÎÏ. ÷ÁÍ ÎÕÖÎÙ ÐÒÉ×ÉÌÅÇÉÉ %-.128s ÄÌÑ ÜÔÏÊ ÏÐÅÒÁÃÉÉ",
-"ðÅÒÅÍÅÎÎÁÑ '%-.64s' Ñ×ÌÑÅÔÓÑ ÐÏÔÏËÏ×ÏÊ (SESSION) ÐÅÒÅÍÅÎÎÏÊ É ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÚÍÅÎÅÎÁ Ó ÐÏÍÏÝØÀ SET GLOBAL",
-"ðÅÒÅÍÅÎÎÁÑ '%-.64s' Ñ×ÌÑÅÔÓÑ ÇÌÏÂÁÌØÎÏÊ (GLOBAL) ÐÅÒÅÍÅÎÎÏÊ, É ÅÅ ÓÌÅÄÕÅÔ ÉÚÍÅÎÑÔØ Ó ÐÏÍÏÝØÀ SET GLOBAL",
-"ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÎÅ ÉÍÅÅÔ ÚÎÁÞÅÎÉÑ ÐÏ ÕÍÏÌÞÁÎÉÀ",
-"ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÕÓÔÁÎÏ×ÌÅÎÁ × ÚÎÁÞÅÎÉÅ '%-.64s'",
-"îÅ×ÅÒÎÙÊ ÔÉÐ ÁÒÇÕÍÅÎÔÁ ÄÌÑ ÐÅÒÅÍÅÎÎÏÊ '%-.64s'",
-"ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÍÏÖÅÔ ÂÙÔØ ÔÏÌØËÏ ÕÓÔÁÎÏ×ÌÅÎÁ, ÎÏ ÎÅ ÓÞÉÔÁÎÁ",
-"îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÉÌÉ × ÎÅ×ÅÒÎÏÍ ÍÅÓÔÅ ÕËÁÚÁÎ '%s'",
-"üÔÁ ×ÅÒÓÉÑ MySQL ÐÏËÁ ÅÝÅ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ '%s'",
-"ðÏÌÕÞÅÎÁ ÎÅÉÓÐÒÁ×ÉÍÁÑ ÏÛÉÂËÁ %d: '%-.128s' ÏÔ ÇÏÌÏ×ÎÏÇÏ ÓÅÒ×ÅÒÁ × ÐÒÏÃÅÓÓÅ ×ÙÂÏÒËÉ ÄÁÎÎÙÈ ÉÚ Ä×ÏÉÞÎÏÇÏ ÖÕÒÎÁÌÁ",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"ïÐÅÒÁÎÄ ÄÏÌÖÅÎ ÓÏÄÅÒÖÁÔØ %d ËÏÌÏÎÏË",
-"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÊ ÚÁÐÉÓÉ",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"ãÉËÌÉÞÅÓËÁÑ ÓÓÙÌËÁ ÎÁ ÐÏÄÚÁÐÒÏÓ",
-"ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÐÏÌÑ '%s' ÉÚ %s × %s",
-"óÓÙÌËÁ '%-.64s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ (%s)",
-"Every derived table must have its own alias",
-"Select %u ÂÙÌ ÕÐÒÁÚÄÎÅÎ × ÐÒÏÃÅÓÓÅ ÏÐÔÉÍÉÚÁÃÉÉ",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s'@'%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ",
-"ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.64s%s%-.64s%s%-.64s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"ëÅÛ ÚÁÐÒÏÓÏ× ÎÅ ÍÏÖÅÔ ÕÓÔÁÎÏ×ÉÔØ ÒÁÚÍÅÒ %lu, ÎÏ×ÙÊ ÒÁÚÍÅÒ ËÅÛÁ ÚÐÒÏÓÏ× - %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"ôÁÂÌÉÃÁ %-.100s × %s ÎÅ ÍÏÖÅÔ ÉÚÍÅÎÑÔÓÑ",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
deleted file mode 100644
index 06270f621e4..00000000000
--- a/sql/share/serbian/errmsg.txt
+++ /dev/null
@@ -1,314 +0,0 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
-
-/* Serbian Translation, version 1.0:
- Copyright 2002 Vladimir Kraljevic, vladimir_kraljevic@yahoo.com
- This file is public domain and comes with NO WARRANTY of any kind.
- Charset: cp1250
-*/
-
-character-set=cp1250
-
-"hashchk",
-"isamchk",
-"NE",
-"DA",
-"Ne mogu da kreiram file '%-.64s' (errno: %d)",
-"Ne mogu da kreiram tabelu '%-.64s' (errno: %d)",
-"Ne mogu da kreiram bazu '%-.64s' (errno: %d)",
-"Ne mogu da kreiram bazu '%-.64s'; baza veæ postoji.",
-"Ne mogu da izbrišem bazu '%-.64s'; baza ne postoji.",
-"Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.64s', errno: %d)",
-"Ne mogu da izbrišem bazu (ne mogu da izbrišem direktorijum '%-.64s', errno: %d)",
-"Greška pri brisanju '%-.64s' (errno: %d)",
-"Ne mogu da proèitam slog iz sistemske tabele",
-"Ne mogu da dobijem stanje file-a '%-.64s' (errno: %d)",
-"Ne mogu da dobijem trenutni direktorijum (errno: %d)",
-"Ne mogu da zakljuèam file (errno: %d)",
-"Ne mogu da otvorim file: '%-.64s' (errno: %d)",
-"Ne mogu da pronaðem file: '%-.64s' (errno: %d)",
-"Ne mogu da proèitam direktorijum '%-.64s' (errno: %d)",
-"Ne mogu da promenim direktorijum na '%-.64s' (errno: %d)",
-"Slog je promenjen od zadnjeg èitanja tabele '%-.64s'",
-"Disk je pun (%s). Èekam nekoga da doðe i oslobodi nešto mesta...",
-"Ne mogu da pišem pošto postoji duplirani kljuè u tabeli '%-.64s'",
-"Greška pri zatvaranju '%-.64s' (errno: %d)",
-"Greška pri èitanju file-a '%-.64s' (errno: %d)",
-"Greška pri promeni imena '%-.64s' na '%-.64s' (errno: %d)",
-"Greška pri upisu '%-.64s' (errno: %d)",
-"'%-.64s' je zakljuèan za upis",
-"Sortiranje je prekinuto",
-"View '%-.64s' ne postoji za '%-.64s'",
-"Handler tabela je vratio grešku %d",
-"Handler tabela za '%-.64s' nema ovu opciju",
-"Ne mogu da pronaðem slog u '%-.64s'",
-"Pogrešna informacija u file-u: '%-.64s'",
-"Pogrešan key file za tabelu: '%-.64s'; probajte da ga ispravite",
-"Zastareo key file za tabelu '%-.64s'; ispravite ga",
-"Tabelu '%-.64s' je dozvoljeno samo èitati",
-"Nema memorije. Restartujte MySQL server i probajte ponovo (potrebno je %d byte-ova)",
-"Nema memorije za sortiranje. Poveæajte velièinu sort buffer-a MySQL server-u",
-"Neoèekivani kraj pri èitanju file-a '%-.64s' (errno: %d)",
-"Previše konekcija",
-"Nema memorije; Proverite da li MySQL server ili neki drugi proces koristi svu slobodnu memoriju. (UNIX: Ako ne, probajte da upotrebite 'ulimit' komandu da biste dozvolili daemon-u da koristi više memorije ili probajte da dodate više swap memorije)",
-"Ne mogu da dobijem ime host-a za vašu IP adresu",
-"Loš poèetak komunikacije (handshake)",
-"Pristup je zabranjen korisniku '%-.32s'@'%-.64s' za bazu '%-.64s'",
-"Pristup je zabranjen korisniku '%-.32s'@'%-.64s' (koristi lozinku: '%s')",
-"Ni jedna baza nije selektovana",
-"Nepoznata komanda",
-"Kolona '%-.64s' ne može biti NULL",
-"Nepoznata baza '%-.64s'",
-"Tabela '%-.64s' veæ postoji",
-"Nepoznata tabela '%-.64s'",
-"Kolona '%-.64s' u %-.64s nije jedinstvena u kontekstu",
-"Gašenje servera je u toku",
-"Nepoznata kolona '%-.64s' u '%-.64s'",
-"Entitet '%-.64s' nije naveden u komandi 'GROUP BY'",
-"Ne mogu da grupišem po '%-.64s'",
-"Izraz ima 'SUM' agregatnu funkciju i kolone u isto vreme",
-"Broj kolona ne odgovara broju vrednosti",
-"Ime '%-.100s' je predugaèko",
-"Duplirano ime kolone '%-.64s'",
-"Duplirano ime kljuèa '%-.64s'",
-"Dupliran unos '%-.64s' za kljuè '%d'",
-"Pogrešan naziv kolone za kolonu '%-.64s'",
-"'%s' u iskazu '%-.80s' na liniji %d",
-"Upit je bio prazan",
-"Tabela ili alias nisu bili jedinstveni: '%-.64s'",
-"Loša default vrednost za '%-.64s'",
-"Definisani višestruki primarni kljuèevi",
-"Navedeno je previše kljuèeva. Maksimum %d kljuèeva je dozvoljeno",
-"Navedeno je previše delova kljuèa. Maksimum %d delova je dozvoljeno",
-"Navedeni kljuè je predug. Maksimalna dužina kljuèa je %d",
-"Kljuèna kolona '%-.64s' ne postoji u tabeli",
-"BLOB kolona '%-.64s' ne može biti upotrebljena za navoðenje kljuèa sa tipom tabele koji se trenutno koristi",
-"Previše podataka za kolonu '%-.64s' (maksimum je %d). Upotrebite BLOB polje",
-"Pogrešna definicija tabele; U tabeli može postojati samo jedna 'AUTO' kolona i ona mora biti istovremeno definisana kao kolona kljuèa",
-"%s: Spreman za konekcije\n",
-"%s: Normalno gašenje\n",
-"%s: Dobio signal %d. Prekidam!\n",
-"%s: Gašenje završeno\n",
-"%s: Usiljeno gašenje thread-a %ld koji pripada korisniku: '%-.32s'\n",
-"Ne mogu da kreiram IP socket",
-"Tabela '%-.64s' nema isti indeks kao onaj upotrebljen pri komandi 'CREATE INDEX'. Napravite tabelu ponovo",
-"Argument separatora polja nije ono što se oèekivalo. Proverite uputstvo MySQL server-a",
-"Ne možete koristiti fiksnu velièinu sloga kada imate BLOB polja. Molim koristite 'fields terminated by' opciju.",
-"File '%-.64s' mora biti u direktorijumu gde su file-ovi baze i mora imati odgovarajuæa prava pristupa",
-"File '%-.80s' veæ postoji",
-"Slogova: %ld Izbrisano: %ld Preskoèeno: %ld Upozorenja: %ld",
-"Slogova: %ld Duplikata: %ld",
-"Pogrešan pod-kljuè dela kljuèa. Upotrebljeni deo kljuèa nije string, upotrebljena dužina je veæa od dela kljuèa ili handler tabela ne podržava jedinstvene pod-kljuèeve",
-"Ne možete da izbrišete sve kolone pomoæu komande 'ALTER TABLE'. Upotrebite komandu 'DROP TABLE' ako želite to da uradite",
-"Ne mogu da izvršim komandu drop 'DROP' na '%-.64s'. Proverite da li ta kolona (odnosno kljuè) postoji",
-"Slogova: %ld Duplikata: %ld Upozorenja: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Nepoznat thread identifikator: %lu",
-"Vi niste vlasnik thread-a %lu",
-"Nema upotrebljenih tabela",
-"Previše string-ova za kolonu '%-.64s' i komandu 'SET'",
-"Ne mogu da generišem jedinstveno ime log-file-a: '%-.64s.(1-999)'\n",
-"Tabela '%-.64s' je zakljuèana READ lock-om; iz nje se može samo èitati ali u nju se ne može pisati",
-"Tabela '%-.64s' nije bila zakljuèana komandom 'LOCK TABLES'",
-"BLOB kolona '%-.64s' ne može imati default vrednost",
-"Pogrešno ime baze '%-.100s'",
-"Pogrešno ime tabele '%-.100s'",
-"Komanda 'SELECT' æe ispitati previše slogova i potrošiti previše vremena. Proverite vaš 'WHERE' filter i upotrebite 'SET OPTION SQL_BIG_SELECTS=1' ako želite baš ovakvu komandu",
-"Nepoznata greška",
-"Nepoznata procedura '%-.64s'",
-"Pogrešan broj parametara za proceduru '%-.64s'",
-"Pogrešni parametri prosleðeni proceduri '%-.64s'",
-"Nepoznata tabela '%-.64s' u '%-.32s'",
-"Kolona '%-.64s' je navedena dva puta",
-"Pogrešna upotreba 'GROUP' funkcije",
-"Tabela '%-.64s' koristi ekstenziju koje ne postoji u ovoj verziji MySQL-a",
-"Tabela mora imati najmanje jednu kolonu",
-"Tabela '%-.64s' je popunjena do kraja",
-"Nepoznati karakter-set: '%-.64s'",
-"Previše tabela. MySQL može upotrebiti maksimum %d tabela pri 'JOIN' operaciji",
-"Previše kolona",
-"Prevelik slog. Maksimalna velièina sloga, ne raèunajuæi BLOB polja, je %d. Trebali bi da promenite tip nekih polja u BLOB",
-"Prepisivanje thread stack-a: Upotrebljeno: %ld od %ld stack memorije. Upotrebite 'mysqld -O thread_stack=#' da navedete veæi stack ako je potrebno",
-"Unakrsna zavisnost pronaðena u komandi 'OUTER JOIN'. Istražite vaše 'ON' uslove",
-"Kolona '%-.64s' je upotrebljena kao 'UNIQUE' ili 'INDEX' ali nije definisana kao 'NOT NULL'",
-"Ne mogu da uèitam funkciju '%-.64s'",
-"Ne mogu da inicijalizujem funkciju '%-.64s'; %-.80s",
-"Ne postoje dozvoljene putanje do share-ovane biblioteke",
-"Funkcija '%-.64s' veæ postoji",
-"Ne mogu da otvorim share-ovanu biblioteku '%-.64s' (errno: %d %-.64s)",
-"Ne mogu da pronadjem funkciju '%-.64s' u biblioteci",
-"Funkcija '%-.64s' nije definisana",
-"Host '%-.64s' je blokiran zbog previše grešaka u konekciji. Možete ga odblokirati pomoæu komande 'mysqladmin flush-hosts'",
-"Host-u '%-.64s' nije dozvoljeno da se konektuje na ovaj MySQL server",
-"Vi koristite MySQL kao anonimni korisnik a anonimnim korisnicima nije dozvoljeno da menjaju lozinke",
-"Morate imati privilegije da možete da update-ujete odreðene tabele ako želite da menjate lozinke za druge korisnike",
-"Ne mogu da pronaðem odgovarajuæi slog u 'user' tabeli",
-"Odgovarajuæih slogova: %ld Promenjeno: %ld Upozorenja: %ld",
-"Ne mogu da kreiram novi thread (errno %d). Ako imate još slobodne memorije, trebali biste da pogledate u priruèniku da li je ovo specifièna greška vašeg operativnog sistema",
-"Broj kolona ne odgovara broju vrednosti u slogu %ld",
-"Ne mogu da ponovo otvorim tabelu '%-.64s'",
-"Pogrešna upotreba vrednosti NULL",
-"Funkcija regexp je vratila grešku '%-.64s'",
-"Upotreba agregatnih funkcija (MIN(),MAX(),COUNT()...) bez 'GROUP' kolona je pogrešna ako ne postoji 'GROUP BY' iskaz",
-"Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s'",
-"%-.16s komanda zabranjena za korisnika '%-.32s'@'%-.64s' za tabelu '%-.64s'",
-"%-.16s komanda zabranjena za korisnika '%-.32s'@'%-.64s' za kolonu '%-.64s' iz tabele '%-.64s'",
-"Pogrešna 'GRANT' odnosno 'REVOKE' komanda. Molim Vas pogledajte u priruèniku koje vrednosti mogu biti upotrebljene.",
-"Argument 'host' ili 'korisnik' prosleðen komandi 'GRANT' je predugaèak",
-"Tabela '%-.64s.%-.64s' ne postoji",
-"Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s' tabeli '%-.64s'",
-"Upotrebljena komanda nije dozvoljena sa ovom verzijom MySQL servera",
-"Imate grešku u vašoj SQL sintaksi",
-"Prolongirani 'INSERT' thread nije mogao da dobije traženo zakljuèavanje tabele '%-.64s'",
-"Previše prolongiranih thread-ova je u upotrebi",
-"Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' (%-.64s)",
-"Primio sam mrežni paket veæi od definisane vrednosti 'max_allowed_packet'",
-"Greška pri èitanju podataka sa pipe-a",
-"Greška pri izvršavanju funkcije fcntl()",
-"Primio sam mrežne pakete van reda",
-"Ne mogu da dekompresujem mrežne pakete",
-"Greška pri primanju mrežnih paketa",
-"Vremenski limit za èitanje mrežnih paketa je istekao",
-"Greška pri slanju mrežnih paketa",
-"Vremenski limit za slanje mrežnih paketa je istekao",
-"Rezultujuèi string je duži nego što to dozvoljava parametar servera 'max_allowed_packet'",
-"Iskorišteni tip tabele ne podržava kolone tipa 'BLOB' odnosno 'TEXT'",
-"Iskorišteni tip tabele ne podržava kolone tipa 'AUTO_INCREMENT'",
-"Komanda 'INSERT DELAYED' ne može biti iskorištena u tabeli '%-.64s', zbog toga što je zakljuèana komandom 'LOCK TABLES'",
-"Pogrešno ime kolone '%-.100s'",
-"Handler tabele ne može da indeksira kolonu '%-.64s'",
-"Tabele iskorištene u 'MERGE' tabeli nisu definisane na isti naèin",
-"Zbog provere jedinstvenosti ne mogu da upišem podatke u tabelu '%-.64s'",
-"BLOB kolona '%-.64s' je upotrebljena u specifikaciji kljuèa bez navoðenja dužine kljuèa",
-"Svi delovi primarnog kljuèa moraju biti razlièiti od NULL; Ako Vam ipak treba NULL vrednost u kljuèu, upotrebite 'UNIQUE'",
-"Rezultat je saèinjen od više slogova",
-"Ovaj tip tabele zahteva da imate definisan primarni kljuè",
-"Ova verzija MySQL servera nije kompajlirana sa podrškom za RAID ureðaje",
-"Vi koristite safe update mod servera, a probali ste da promenite podatke bez 'WHERE' komande koja koristi kolonu kljuèa",
-"Kljuè '%-.64s' ne postoji u tabeli '%-.64s'",
-"Ne mogu da otvorim tabelu",
-"Handler za ovu tabelu ne dozvoljava 'check' odnosno 'repair' komande",
-"Nije Vam dozvoljeno da izvršite ovu komandu u transakciji",
-"Greška %d za vreme izvršavanja komande 'COMMIT'",
-"Greška %d za vreme izvršavanja komande 'ROLLBACK'",
-"Greška %d za vreme izvršavanja komande 'FLUSH_LOGS'",
-"Greška %d za vreme izvršavanja komande 'CHECKPOINT'",
-"Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' a host: `%-.64s' (%-.64s)",
-"Handler tabele ne podržava binarni dump tabele",
-"Binarni log file zatvoren, ne mogu da izvršim komandu 'RESET MASTER'",
-"Izgradnja indeksa dump-ovane tabele '%-.64s' nije uspela",
-"Greška iz glavnog servera '%-.64s' u klasteru",
-"Greška u primanju mrežnih paketa sa glavnog servera u klasteru",
-"Greška u slanju mrežnih paketa na glavni server u klasteru",
-"Ne mogu da pronaðem 'FULLTEXT' indeks koli odgovara listi kolona",
-"Ne mogu da izvršim datu komandu zbog toga što su tabele zakljuèane ili je transakcija u toku",
-"Nepoznata sistemska promenljiva '%-.64s'",
-"Tabela '%-.64s' je markirana kao ošteæena i trebala bi biti popravljena",
-"Tabela '%-.64s' je markirana kao ošteæena, a zadnja (automatska?) popravka je bila neuspela",
-"Upozorenje: Neke izmenjene tabele ne podržavaju komandu 'ROLLBACK'",
-"Transakcija sa više stavki zahtevala je više od 'max_binlog_cache_size' bajtova skladišnog prostora. Uveæajte ovu promenljivu servera i pokušajte ponovo',
-"Ova operacija ne može biti izvršena dok je aktivan podreðeni server. Zadajte prvo komandu 'STOP SLAVE' da zaustavite podreðeni server.",
-"Ova operacija zahteva da je aktivan podreðeni server. Konfigurišite prvo podreðeni server i onda izvršite komandu 'START SLAVE'",
-"Server nije konfigurisan kao podreðeni server, ispravite konfiguracioni file ili na njemu izvršite komandu 'CHANGE MASTER TO'",
-"Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info'",
-"Nisam mogao da startujem thread za podreðeni server, proverite sistemske resurse",
-"Korisnik %-.64s veæ ima više aktivnih konekcija nego što je to odreðeno 'max_user_connections' promenljivom",
-"Možete upotrebiti samo konstantan iskaz sa komandom 'SET'",
-"Vremenski limit za zakljuèavanje tabele je istekao; Probajte da ponovo startujete transakciju",
-"Broj totalnih zakljuèavanja tabele premašuje velièinu tabele zakljuèavanja",
-"Zakljuèavanja izmena ne mogu biti realizovana sve dok traje 'READ UNCOMMITTED' transakcija",
-"Komanda 'DROP DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka",
-"Komanda 'CREATE DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka",
-"Pogrešni argumenti prosleðeni na %s",
-"Korisniku '%-.32s'@'%-.64s' nije dozvoljeno da kreira nove korisnike",
-"Pogrešna definicija tabele; sve 'MERGE' tabele moraju biti u istoj bazi podataka",
-"Unakrsno zakljuèavanje pronaðeno kada sam pokušao da dobijem pravo na zakljuèavanje; Probajte da restartujete transakciju",
-"Upotrebljeni tip tabele ne podržava 'FULLTEXT' indekse",
-"Ne mogu da dodam proveru spoljnog kljuèa",
-"Ne mogu da dodam slog: provera spoljnog kljuèa je neuspela",
-"Ne mogu da izbrišem roditeljski slog: provera spoljnog kljuèa je neuspela",
-"Greška pri povezivanju sa glavnim serverom u klasteru: %-.128s",
-"Greška pri izvršavanju upita na glavnom serveru u klasteru: %-.128s",
-"Greška pri izvršavanju komande %s: %-.128s",
-"Pogrešna upotreba %s i %s",
-"Upotrebljene 'SELECT' komande adresiraju razlièit broj kolona",
-"Ne mogu da izvršim upit zbog toga što imate zakljuèavanja èitanja podataka u konfliktu",
-"Mešanje tabela koje podržavaju transakcije i onih koje ne podržavaju transakcije je iskljuèeno",
-"Opcija '%s' je upotrebljena dva puta u istom iskazu",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updatable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working"
-"The MySQL server is running with the %s option so it cannot execute this statement"
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
deleted file mode 100644
index 12c3eb2b6af..00000000000
--- a/sql/share/slovak/errmsg.txt
+++ /dev/null
@@ -1,329 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Translated from both E n g l i s h & C z e c h error messages
- by steve: (billik@sun.uniag.sk).
- Encoding: ISO LATIN-8852-2
- Server version: 3.21.25-gamma
- Date: Streda 11. November 1998 20:58:15
-*/
-
-character-set=latin2
-
-"hashchk",
-"isamchk",
-"NIE",
-"Áno",
-"Nemô¾em vytvori» súbor '%-.64s' (chybový kód: %d)",
-"Nemô¾em vytvori» tabuµku '%-.64s' (chybový kód: %d)",
-"Nemô¾em vytvori» databázu '%-.64s' (chybový kód: %d)",
-"Nemô¾em vytvori» databázu '%-.64s'; databáza existuje",
-"Nemô¾em zmaza» databázu '%-.64s'; databáza neexistuje",
-"Chyba pri mazaní databázy (nemô¾em zmaza» '%-.64s', chybový kód: %d)",
-"Chyba pri mazaní databázy (nemô¾em vymaza» adresár '%-.64s', chybový kód: %d)",
-"Chyba pri mazaní '%-.64s' (chybový kód: %d)",
-"Nemô¾em èíta» záznam v systémovej tabuµke",
-"Nemô¾em zisti» stav '%-.64s' (chybový kód: %d)",
-"Nemô¾em zisti» pracovný adresár (chybový kód: %d)",
-"Nemô¾em zamknú» súbor (chybový kód: %d)",
-"Nemô¾em otvori» súbor: '%-.64s' (chybový kód: %d)",
-"Nemô¾em nájs» súbor: '%-.64s' (chybový kód: %d)",
-"Nemô¾em èíta» adresár '%-.64s' (chybový kód: %d)",
-"Nemô¾em vojs» do adresára '%-.64s' (chybový kód: %d)",
-"Záznam bol zmenený od posledného èítania v tabuµke '%-.64s'",
-"Disk je plný (%s), èakám na uvoµnenie miesta...",
-"Nemô¾em zapísa», duplikát kµúèa v tabuµke '%-.64s'",
-"Chyba pri zatváraní '%-.64s' (chybový kód: %d)",
-"Chyba pri èítaní súboru '%-.64s' (chybový kód: %d)",
-"Chyba pri premenovávaní '%-.64s' na '%-.64s' (chybový kód: %d)",
-"Chyba pri zápise do súboru '%-.64s' (chybový kód: %d)",
-"'%-.64s' je zamknutý proti zmenám",
-"Triedenie preru¹ené",
-"Pohµad '%-.64s' neexistuje pre '%-.64s'",
-"Obsluha tabuµky vrátila chybu %d",
-"Obsluha tabuµky '%-.64s' nemá tento parameter",
-"Nemô¾em nájs» záznam v '%-.64s'",
-"Nesprávna informácia v súbore: '%-.64s'",
-"Nesprávny kµúè pre tabuµku '%-.64s'; pokúste sa ho opravi»",
-"Starý kµúèový súbor pre '%-.64s'; opravte ho!",
-"'%-.64s' is èíta» only",
-"Málo pamäti. Re¹tartujte daemona a skúste znova (je potrebných %d bytov)",
-"Málo pamäti pre triedenie, zvý¹te veµkos» triediaceho bufferu",
-"Neoèakávaný koniec súboru pri èítaní '%-.64s' (chybový kód: %d)",
-"Príli¹ mnoho spojení",
-"Málo miesta-pamäti pre vlákno",
-"Nemô¾em zisti» meno hostiteµa pre va¹u adresu",
-"Chyba pri nadväzovaní spojenia",
-"Zakázaný prístup pre u¾ívateµa: '%-.32s'@'%-.64s' k databázi '%-.64s'",
-"Zakázaný prístup pre u¾ívateµa: '%-.32s'@'%-.64s' (pou¾itie hesla: %s)",
-"Nebola vybraná databáza",
-"Neznámy príkaz",
-"Pole '%-.64s' nemô¾e by» null",
-"Neznáma databáza '%-.64s'",
-"Tabuµka '%-.64s' u¾ existuje",
-"Neznáma tabuµka '%-.64s'",
-"Pole: '%-.64s' v %-.64s je nejasné",
-"Prebieha ukonèovanie práce servera",
-"Neznáme pole '%-.64s' v '%-.64s'",
-"Pou¾ité '%-.64s' nebolo v 'group by'",
-"Nemô¾em pou¾i» 'group' na '%-.64s'",
-"Príkaz obsahuje zároveò funkciu 'sum' a poµa",
-"Poèet polí nezodpovedá zadanej hodnote",
-"Meno identifikátora '%-.100s' je príli¹ dlhé",
-"Opakované meno poµa '%-.64s'",
-"Opakované meno kµúèa '%-.64s'",
-"Opakovaný kµúè '%-.64s' (èíslo kµúèa %d)",
-"Chyba v ¹pecifikácii poµa '%-.64s'",
-"%s blízko '%-.80s' na riadku %d",
-"Výsledok po¾iadavky bol prázdny",
-"Nie jednoznaèná tabuµka/alias: '%-.64s'",
-"Chybná implicitná hodnota pre '%-.64s'",
-"Zadefinovaných viac primárnych kµúèov",
-"Zadaných ríli¹ veµa kµúèov. Najviac %d kµúèov je povolených",
-"Zadaných ríli¹ veµa èastí kµúèov. Je povolených najviac %d èastí",
-"Zadaný kµúè je príli¹ dlhý, najväè¹ia då¾ka kµúèa je %d",
-"Kµúèový ståpec '%-.64s' v tabuµke neexistuje",
-"Blob pole '%-.64s' nemô¾e by» pou¾ité ako kµúè",
-"Príli¹ veµká då¾ka pre pole '%-.64s' (maximum = %d). Pou¾ite BLOB",
-"Mô¾ete ma» iba jedno AUTO pole a to musí by» definované ako kµúè",
-"%s: pripravený na spojenie",
-"%s: normálne ukonèenie\n",
-"%s: prijatý signál %d, ukonèenie (Abort)!\n",
-"%s: práca ukonèená\n",
-"%s: násilné ukonèenie vlákna %ld u¾ívateµa '%-.64s'\n",
-"Nemô¾em vytvori» IP socket",
-"Tabuµka '%-.64s' nemá index zodpovedajúci CREATE INDEX. Vytvorte tabulku znova",
-"Argument oddeµovaè polí nezodpovedá po¾iadavkám. Skontrolujte v manuáli",
-"Nie je mo¾né pou¾i» fixnú då¾ku s BLOBom. Pou¾ite 'fields terminated by'.",
-"Súbor '%-.64s' musí by» v adresári databázy, alebo èitateµný pre v¹etkých",
-"Súbor '%-.64s' u¾ existuje",
-"Záznamov: %ld Zmazaných: %ld Preskoèených: %ld Varovania: %ld",
-"Záznamov: %ld Opakovaných: %ld",
-"Incorrect sub part key; the used key part isn't a string or the used length is longer than the key part",
-"One nemô¾em zmaza» all fields with ALTER TABLE; use DROP TABLE instead",
-"Nemô¾em zru¹i» (DROP) '%-.64s'. Skontrolujte, èi neexistujú záznamy/kµúèe",
-"Záznamov: %ld Opakovaných: %ld Varovania: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Neznáma identifikácia vlákna: %lu",
-"Nie ste vlastníkom vlákna %lu",
-"Nie je pou¾itá ¾iadna tabuµka",
-"Príli¹ mnoho re»azcov pre pole %-.64s a SET",
-"Nemô¾em vytvori» unikátne meno log-súboru %-.64s.(1-999)\n",
-"Tabuµka '%-.64s' bola zamknutá s READ a nemô¾e by» zmenená",
-"Tabuµka '%-.64s' nebola zamknutá s LOCK TABLES",
-"Pole BLOB '%-.64s' nemô¾e ma» implicitnú hodnotu",
-"Neprípustné meno databázy '%-.100s'",
-"Neprípustné meno tabuµky '%-.100s'",
-"Zadaná po¾iadavka SELECT by prechádzala príli¹ mnoho záznamov a trvala by príli¹ dlho. Skontrolujte tvar WHERE a ak je v poriadku, pou¾ite SET SQL_BIG_SELECTS=1",
-"Neznámá chyba",
-"Neznámá procedúra '%-.64s'",
-"Chybný poèet parametrov procedúry '%-.64s'",
-"Chybné parametre procedúry '%-.64s'",
-"Neznáma tabuµka '%-.64s' v %s",
-"Pole '%-.64s' je zadané dvakrát",
-"Nesprávne pou¾itie funkcie GROUP",
-"Tabuµka '%-.64s' pou¾íva roz¹írenie, ktoré v tejto verzii MySQL nie je",
-"Tabuµka musí ma» aspoò 1 pole",
-"Tabuµka '%-.64s' je plná",
-"Neznáma znaková sada: '%-.64s'",
-"Príli¹ mnoho tabuliek. MySQL mô¾e pou¾i» len %d v JOIN-e",
-"Príli¹ mnoho polí",
-"Riadok je príli¹ veµký. Maximálna veµkos» riadku, okrem 'BLOB', je %d. Musíte zmeni» niektoré polo¾ky na BLOB",
-"Preteèenie zásobníku vlákna: pou¾ité: %ld z %ld. Pou¾ite 'mysqld -O thread_stack=#' k zadaniu väè¹ieho zásobníka",
-"V OUTER JOIN bol nájdený krí¾ový odkaz. Skontrolujte podmienky ON",
-"Pole '%-.64s' je pou¾ité s UNIQUE alebo INDEX, ale nie je zadefinované ako NOT NULL",
-"Nemô¾em naèíta» funkciu '%-.64s'",
-"Nemô¾em inicializova» funkciu '%-.64s'; %-.80s",
-"Neprípustné ¾iadne cesty k zdieµanej kni¾nici",
-"Funkcia '%-.64s' u¾ existuje",
-"Nemô¾em otvori» zdieµanú kni¾nicu '%-.64s' (chybový kód: %d %s)",
-"Nemô¾em nájs» funkciu '%-.64s' v kni¾nici'",
-"Funkcia '%-.64s' nie je definovaná",
-"Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'",
-"Host '%-.64s' is not allowed to connect to this MySQL server",
-"You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords",
-"You must have privileges to update tables in the mysql database to be able to change passwords for others",
-"Can't find any matching row in the user table",
-"Rows matched: %ld Changed: %ld Warnings: %ld",
-"Can't create a new thread (errno %d); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug",
-"Column count doesn't match value count at row %ld",
-"Can't reopen table: '%-.64s",
-"Invalid use of NULL value",
-"Got error '%-.64s' from regexp",
-"Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause",
-"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for table '%-.64s'",
-"%-.16s command denied to user '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
-"Illegal GRANT/REVOKE command; please consult the manual to see which privleges can be used.",
-"The host or user argument to GRANT is too long",
-"Table '%-.64s.%s' doesn't exist",
-"There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'",
-"The used command is not allowed with this MySQL version",
-"Something is wrong in your syntax",
-"Delayed insert thread couldn't get requested lock for table %-.64s",
-"Too many delayed threads in use",
-"Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)",
-"Got a packet bigger than 'max_allowed_packet' bytes",
-"Got a read error from the connection pipe",
-"Got an error from fcntl()",
-"Got packets out of order",
-"Couldn't uncompress communication packet",
-"Got an error reading communication packets",
-"Got timeout reading communication packets",
-"Got an error writing communication packets",
-"Got timeout writing communication packets",
-"Result string is longer than 'max_allowed_packet' bytes",
-"The used table type doesn't support BLOB/TEXT columns",
-"The used table type doesn't support AUTO_INCREMENT columns",
-"INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES",
-"Incorrect column name '%-.100s'",
-"The used table handler can't index column '%-.64s'",
-"All tables in the MERGE table are not defined identically",
-"Can't write, because of unique constraint, to table '%-.64s'",
-"BLOB column '%-.64s' used in key specification without a key length",
-"All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead",
-"Result consisted of more than one row",
-"This table type requires a primary key",
-"This version of MySQL is not compiled with RAID support",
-"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
-"Key '%-.64s' doesn't exist in table '%-.64s'",
-"Can't open table",
-"The handler for the table doesn't support %s",
-"You are not allowed to execute this command in a transaction",
-"Got error %d during COMMIT",
-"Got error %d during ROLLBACK",
-"Got error %d during FLUSH_LOGS",
-"Got error %d during CHECKPOINT",
-"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
-"The handler for the table does not support binary table dump",
-"Binlog closed while trying to FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Error from master: '%-.64s'",
-"Net error reading from master",
-"Net error writing to master",
-"Can't find FULLTEXT index matching the column list",
-"Can't execute the given command because you have active locked tables or an active transaction",
-"Unknown system variable '%-.64s'",
-"Table '%-.64s' is marked as crashed and should be repaired",
-"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Some non-transactional changed tables couldn't be rolled back",
-"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again",
-"This operation cannot be performed with a running slave, run STOP SLAVE first",
-"This operation requires a running slave, configure slave and do START SLAVE",
-"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, more error messages can be found in the MySQL error log",
-"Could not create slave thread, check system resources",
-"User %-.64s has already more than 'max_user_connections' active connections",
-"You may only use constant expressions with SET",
-"Lock wait timeout exceeded; try restarting transaction",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Incorrect arguments to %s",
-"'%-.32s'@'%-.64s' is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"Operand should contain %d column(s)",
-"Subquery returns more than 1 row",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"Cyclic reference on subqueries",
-"Converting column '%s' from %s to %s",
-"Reference '%-.64s' not supported (%s)",
-"Every derived table must have its own alias",
-"Select %u was reduced during optimization",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"Query cache failed to set size %lu, new query cache size is %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"The target table %-.100s of the %s is not updateable",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
deleted file mode 100644
index c5b4fd34eca..00000000000
--- a/sql/share/spanish/errmsg.txt
+++ /dev/null
@@ -1,325 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- Traduccion por Miguel Angel Fernandez Roiz -- LoboCom Sistemas, s.l.
- From June 28, 2001 translated by Miguel Solorzano miguel@mysql.com */
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NO",
-"SI",
-"No puedo crear archivo '%-.64s' (Error: %d)",
-"No puedo crear tabla '%-.64s' (Error: %d)",
-"No puedo crear base de datos '%-.64s' (Error: %d)",
-"No puedo crear base de datos '%-.64s'; la base de datos ya existe",
-"No puedo eliminar base de datos '%-.64s'; la base de datos no existe",
-"Error eliminando la base de datos(no puedo borrar '%-.64s', error %d)",
-"Error eliminando la base de datos (No puedo borrar directorio '%-.64s', error %d)",
-"Error en el borrado de '%-.64s' (Error: %d)",
-"No puedo leer el registro en la tabla del sistema",
-"No puedo obtener el estado de '%-.64s' (Error: %d)",
-"No puedo acceder al directorio (Error: %d)",
-"No puedo bloquear archivo: (Error: %d)",
-"No puedo abrir archivo: '%-.64s' (Error: %d)",
-"No puedo encontrar archivo: '%-.64s' (Error: %d)",
-"No puedo leer el directorio de '%-.64s' (Error: %d)",
-"No puedo cambiar al directorio de '%-.64s' (Error: %d)",
-"El registro ha cambiado desde la ultima lectura de la tabla '%-.64s'",
-"Disco lleno (%s). Esperando para que se libere algo de espacio...",
-"No puedo escribir, clave duplicada en la tabla '%-.64s'",
-"Error en el cierre de '%-.64s' (Error: %d)",
-"Error leyendo el fichero '%-.64s' (Error: %d)",
-"Error en el renombrado de '%-.64s' a '%-.64s' (Error: %d)",
-"Error escribiendo el archivo '%-.64s' (Error: %d)",
-"'%-.64s' esta bloqueado contra cambios",
-"Ordeancion cancelada",
-"La vista '%-.64s' no existe para '%-.64s'",
-"Error %d desde el manejador de la tabla",
-"El manejador de la tabla de '%-.64s' no tiene esta opcion",
-"No puedo encontrar el registro en '%-.64s'",
-"Informacion erronea en el archivo: '%-.64s'",
-"Clave de archivo erronea para la tabla: '%-.64s'; intente repararlo",
-"Clave de archivo antigua para la tabla '%-.64s'; reparelo!",
-"'%-.64s' es de solo lectura",
-"Memoria insuficiente. Reinicie el demonio e intentelo otra vez (necesita %d bytes)",
-"Memoria de ordenacion insuficiente. Incremente el tamano del buffer de ordenacion",
-"Inesperado fin de ficheroU mientras leiamos el archivo '%-.64s' (Error: %d)",
-"Demasiadas conexiones",
-"Memoria/espacio de tranpaso insuficiente",
-"No puedo obtener el nombre de maquina de tu direccion",
-"Protocolo erroneo",
-"Acceso negado para usuario: '%-.32s'@'%-.64s' para la base de datos '%-.64s'",
-"Acceso negado para usuario: '%-.32s'@'%-.64s' (Usando clave: %s)",
-"Base de datos no seleccionada",
-"Comando desconocido",
-"La columna '%-.64s' no puede ser nula",
-"Base de datos desconocida '%-.64s'",
-"La tabla '%-.64s' ya existe",
-"Tabla '%-.64s' desconocida",
-"La columna: '%-.64s' en %s es ambigua",
-"Desconexion de servidor en proceso",
-"La columna '%-.64s' en %s es desconocida",
-"Usado '%-.64s' el cual no esta group by",
-"No puedo agrupar por '%-.64s'",
-"El estamento tiene funciones de suma y columnas en el mismo estamento",
-"La columna con count no tiene valores para contar",
-"El nombre del identificador '%-.64s' es demasiado grande",
-"Nombre de columna duplicado '%-.64s'",
-"Nombre de clave duplicado '%-.64s'",
-"Entrada duplicada '%-.64s' para la clave %d",
-"Especificador de columna erroneo para la columna '%-.64s'",
-"%s cerca '%-.64s' en la linea %d",
-"La query estaba vacia",
-"Tabla/alias: '%-.64s' es no unica",
-"Valor por defecto invalido para '%-.64s'",
-"Multiples claves primarias definidas",
-"Demasiadas claves primarias declaradas. Un maximo de %d claves son permitidas",
-"Demasiadas partes de clave declaradas. Un maximo de %d partes son permitidas",
-"Declaracion de clave demasiado larga. La maxima longitud de clave es %d",
-"La columna clave '%-.64s' no existe en la tabla",
-"La columna Blob '%-.64s' no puede ser usada en una declaracion de clave",
-"Longitud de columna demasiado grande para la columna '%-.64s' (maximo = %d).Usar BLOB en su lugar",
-"Puede ser solamente un campo automatico y este debe ser definido como una clave",
-"%s: preparado para conexiones",
-"%s: Apagado normal\n",
-"%s: Recibiendo signal %d. Abortando!\n",
-"%s: Apagado completado\n",
-"%s: Forzando a cerrar el thread %ld usuario: '%-.64s'\n",
-"No puedo crear IP socket",
-"La tabla '%-.64s' no tiene indice como el usado en CREATE INDEX. Crea de nuevo la tabla",
-"Los separadores de argumentos del campo no son los especificados. Comprueba el manual",
-"No puedes usar longitudes de filas fijos con BLOBs. Por favor usa 'campos terminados por '.",
-"El archivo '%-.64s' debe estar en el directorio de la base de datos o ser de lectura por todos",
-"El archivo '%-.64s' ya existe",
-"Registros: %ld Borrados: %ld Saltados: %ld Peligros: %ld",
-"Registros: %ld Duplicados: %ld",
-"Parte de la clave es erronea. Una parte de la clave no es una cadena o la longitud usada es tan grande como la parte de la clave",
-"No puede borrar todos los campos con ALTER TABLE. Usa DROP TABLE para hacerlo",
-"No puedo ELIMINAR '%-.64s'. compuebe que el campo/clave existe",
-"Registros: %ld Duplicados: %ld Peligros: %ld",
-"You can't specify target table '%-.64s' for update in FROM clause",
-"Identificador del thread: %lu desconocido",
-"Tu no eres el propietario del thread%lu",
-"No ha tablas usadas",
-"Muchas strings para columna %s y SET",
-"No puede crear un unico archivo log %s.(1-999)\n",
-"Tabla '%-.64s' fue trabada con un READ lock y no puede ser actualizada",
-"Tabla '%-.64s' no fue trabada con LOCK TABLES",
-"Campo Blob '%-.64s' no puede tener valores patron",
-"Nombre de base de datos ilegal '%-.64s'",
-"Nombre de tabla ilegal '%-.64s'",
-"El SELECT puede examinar muchos registros y probablemente con mucho tiempo. Verifique tu WHERE y usa SET SQL_BIG_SELECTS=1 si el SELECT esta correcto",
-"Error desconocido",
-"Procedimiento desconocido %s",
-"Equivocado parametro count para procedimiento %s",
-"Equivocados parametros para procedimiento %s",
-"Tabla desconocida '%-.64s' in %s",
-"Campo '%-.64s' especificado dos veces",
-"Invalido uso de función en grupo",
-"Tabla '%-.64s' usa una extensión que no existe en esta MySQL versión",
-"Una tabla debe tener al menos 1 columna",
-"La tabla '%-.64s' está llena",
-"Juego de caracteres desconocido: '%-.64s'",
-"Muchas tablas. MySQL solamente puede usar %d tablas en un join",
-"Muchos campos",
-"Tamaño de línea muy grande. Máximo tamaño de línea, no contando blob, es %d. Tu tienes que cambiar algunos campos para blob",
-"Sobrecarga de la pila de thread: Usada: %ld de una %ld pila. Use 'mysqld -O thread_stack=#' para especificar una mayor pila si necesario",
-"Dependencia cruzada encontrada en OUTER JOIN; examine su condición ON",
-"Columna '%-.32s' es usada con UNIQUE o INDEX pero no está definida como NOT NULL",
-"No puedo cargar función '%-.64s'",
-"No puedo inicializar función '%-.64s'; %-.80s",
-"No pasos permitidos para librarias conjugadas",
-"Función '%-.64s' ya existe",
-"No puedo abrir libraria conjugada '%-.64s' (errno: %d %s)",
-"No puedo encontrar función '%-.64s' en libraria'",
-"Función '%-.64s' no está definida",
-"Servidor '%-.64s' está bloqueado por muchos errores de conexión. Desbloquear con 'mysqladmin flush-hosts'",
-"Servidor '%-.64s' no está permitido para conectar con este servidor MySQL",
-"Tu estás usando MySQL como un usuario anonimo y usuarios anonimos no tienen permiso para cambiar las claves",
-"Tu debes de tener permiso para actualizar tablas en la base de datos mysql para cambiar las claves para otros",
-"No puedo encontrar una línea correponsdiente en la tabla user",
-"Líneas correspondientes: %ld Cambiadas: %ld Avisos: %ld",
-"No puedo crear un nuevo thread (errno %d). Si tu está con falta de memoria disponible, tu puedes consultar el Manual para posibles problemas con SO",
-"El número de columnas no corresponde al número en la línea %ld",
-"No puedo reabrir tabla: '%-.64s",
-"Invalido uso de valor NULL",
-"Obtenido error '%-.64s' de regexp",
-"Mezcla de columnas GROUP (MIN(),MAX(),COUNT()...) con no GROUP columnas es ilegal si no hat la clausula GROUP BY",
-"No existe permiso definido para usuario '%-.32s' en el servidor '%-.64s'",
-"%-.16s comando negado para usuario: '%-.32s'@'%-.64s' para tabla '%-.64s'",
-"%-.16s comando negado para usuario: '%-.32s'@'%-.64s' para columna '%-.64s' en la tabla '%-.64s'",
-"Ilegal comando GRANT/REVOKE. Por favor consulte el manual para cuales permisos pueden ser usados.",
-"El argumento para servidor o usuario para GRANT es demasiado grande",
-"Tabla '%-.64s.%s' no existe",
-"No existe tal permiso definido para usuario '%-.32s' en el servidor '%-.64s' en la tabla '%-.64s'",
-"El comando usado no es permitido con esta versión de MySQL",
-"Algo está equivocado en su sintax",
-"Thread de inserción retarda no pudiendo bloquear para la tabla %-.64s",
-"Muchos threads retardados en uso",
-"Conexión abortada %ld para db: '%-.64s' usuario: '%-.64s' (%s)",
-"Obtenido un paquete mayor que 'max_allowed_packet'",
-"Obtenido un error de lectura de la conexión pipe",
-"Obtenido un error de fcntl()",
-"Obtenido paquetes desordenados",
-"No puedo descomprimir paquetes de comunicación",
-"Obtenido un error leyendo paquetes de comunicación",
-"Obtenido timeout leyendo paquetes de comunicación",
-"Obtenido un error de escribiendo paquetes de comunicación",
-"Obtenido timeout escribiendo paquetes de comunicación",
-"La string resultante es mayor que 'max_allowed_packet'",
-"El tipo de tabla usada no permite soporte para columnas BLOB/TEXT",
-"El tipo de tabla usada no permite soporte para columnas AUTO_INCREMENT",
-"INSERT DELAYED no puede ser usado con tablas '%-.64s', porque esta bloqueada con LOCK TABLES",
-"Incorrecto nombre de columna '%-.100s'",
-"El manipulador de tabla usado no puede indexar columna '%-.64s'",
-"Todas las tablas en la MERGE tabla no estan definidas identicamente",
-"No puedo escribir, debido al único constraint, para tabla '%-.64s'",
-"Columna BLOB column '%-.64s' usada en especificación de clave sin tamaño de la clave",
-"Todas las partes de un PRIMARY KEY deben ser NOT NULL; Si necesitas NULL en una clave, use UNIQUE",
-"Resultado compuesto de mas que una línea",
-"Este tipo de tabla necesita de una primary key",
-"Esta versión de MySQL no es compilada con soporte RAID",
-"Tu estás usando modo de actualización segura y tentado actualizar una tabla sin un WHERE que usa una KEY columna",
-"Clave '%-.64s' no existe en la tabla '%-.64s'",
-"No puedo abrir tabla",
-"El manipulador de la tabla no permite soporte para %s",
-"No tienes el permiso para ejecutar este comando en una transición",
-"Obtenido error %d durante COMMIT",
-"Obtenido error %d durante ROLLBACK",
-"Obtenido error %d durante FLUSH_LOGS",
-"Obtenido error %d durante CHECKPOINT",
-"Abortada conexión %ld para db: '%-.64s' usuario: '%-.32s' servidor: `%-.64s' (%-.64s)",
-"El manipulador de tabla no soporta dump para tabla binaria",
-"Binlog cerrado mientras tentaba el FLUSH MASTER",
-"Falla reconstruyendo el indice de la tabla dumped '%-.64s'",
-"Error del master: '%-.64s'",
-"Error de red leyendo del master",
-"Error de red escribiendo para el master",
-"No puedo encontrar índice FULLTEXT correspondiendo a la lista de columnas",
-"No puedo ejecutar el comando dado porque tienes tablas bloqueadas o una transición activa",
-"Desconocida variable de sistema '%-.64s'",
-"Tabla '%-.64s' está marcada como crashed y debe ser reparada",
-"Tabla '%-.64s' está marcada como crashed y la última reparación (automactica?) falló",
-"Aviso: Algunas tablas no transancionales no pueden tener rolled back",
-"Multipla transición necesita mas que 'max_binlog_cache_size' bytes de almacenamiento. Aumente esta variable mysqld y tente de nuevo",
-"Esta operación no puede ser hecha con el esclavo funcionando, primero use STOP SLAVE",
-"Esta operación necesita el esclavo funcionando, configure esclavo y haga el START SLAVE",
-"El servidor no está configurado como esclavo, edite el archivo config file o con CHANGE MASTER TO",
-"Could not initialize master info structure, more error messages can be found in the MySQL error log",
-"No puedo crear el thread esclavo, verifique recursos del sistema",
-"Usario %-.64s ya tiene mas que 'max_user_connections' conexiones activas",
-"Tu solo debes usar expresiones constantes con SET",
-"Tiempo de bloqueo de espera excedido",
-"El número total de bloqueos excede el tamaño de bloqueo de la tabla",
-"Bloqueos de actualización no pueden ser adqueridos durante una transición READ UNCOMMITTED",
-"DROP DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global",
-"CREATE DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global",
-"Argumentos errados para %s",
-"'%-.32s`@`%-.64s` no es permitido para crear nuevos usuarios",
-"Incorrecta definición de la tabla; Todas las tablas MERGE deben estar en el mismo banco de datos",
-"Encontrado deadlock cuando tentando obtener el bloqueo; Tente recomenzar la transición",
-"El tipo de tabla usada no soporta índices FULLTEXT",
-"No puede adicionar clave extranjera constraint",
-"No puede adicionar una línea hijo: falla de clave extranjera constraint",
-"No puede deletar una línea padre: falla de clave extranjera constraint",
-"Error de coneccion a master: %-.128s",
-"Error executando el query en master: %-.128s",
-"Error de %s: %-.128s",
-"Equivocado uso de %s y %s",
-"El comando SELECT usado tiene diferente número de columnas",
-"No puedo ejecutar el query porque usted tiene conflicto de traba de lectura",
-"Mezla de transancional y no-transancional tablas está deshabilitada",
-"Opción '%s' usada dos veces en el comando",
-"Usuario '%-.64s' ha excedido el recurso '%s' (actual valor: %ld)",
-"Acceso negado. Usted necesita el privilegio %-.128s para esta operación",
-"Variable '%-.64s' es una SESSION variable y no puede ser usada con SET GLOBAL",
-"Variable '%-.64s' es una GLOBAL variable y no puede ser configurada con SET GLOBAL",
-"Variable '%-.64s' no tiene un valor patrón",
-"Variable '%-.64s' no puede ser configurada para el valor de '%-.64s'",
-"Tipo de argumento equivocado para variable '%-.64s'",
-"Variable '%-.64s' solamente puede ser configurada, no leída",
-"Equivocado uso/colocación de '%s'",
-"Esta versión de MySQL no soporta todavia '%s'",
-"Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log",
-"Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla",
-"Variable '%-.64s' es una %s variable",
-"Equivocada definición de llave extranjera para '%-.64s': %s",
-"Referencia de llave y referencia de tabla no coinciden",
-"Operando debe tener %d columna(s)",
-"Subconsulta retorna mas que 1 línea",
-"Desconocido preparado comando handler (%.*s) dado para %s",
-"Base de datos Help está corrupto o no existe",
-"Cíclica referencia en subconsultas",
-"Convirtiendo columna '%s' de %s para %s",
-"Referencia '%-.64s' no soportada (%s)",
-"Cada tabla derivada debe tener su propio alias",
-"Select %u fué reducido durante optimización",
-"Tabla '%-.64s' de uno de los SELECT no puede ser usada en %-.32s",
-"Cliente no soporta protocolo de autenticación solicitado por el servidor; considere actualizar el cliente MySQL",
-"Todas las partes de una SPATIAL index deben ser NOT NULL",
-"COLLATION '%s' no es válido para CHARACTER SET '%s'",
-"Slave ya está funcionando",
-"Slave ya fué parado",
-"Tamaño demasiado grande para datos descomprimidos. El máximo tamaño es %d. (probablemente, extensión de datos descomprimidos fué corrompida)",
-"ZLIB: No suficiente memoria",
-"ZLIB: No suficiente espacio en el búfer de salida (probablemente, extensión de datos descomprimidos fué corrompida)",
-"ZLIB: Dato de entrada fué corrompido",
-"%d línea(s) fueron cortadas por GROUP_CONCAT()",
-"Línea %ld no contiene datos para todas las columnas",
-"Línea %ld fué truncada; La misma contine mas datos que las que existen en las columnas de entrada",
-"Datos truncado, NULL suministrado para NOT NULL columna '%s' en la línea %ld",
-"Datos truncados, fuera de gama para columna '%s' en la línea %ld",
-"Datos truncados para columna '%s' en la línea %ld",
-"Usando motor de almacenamiento %s para tabla '%s'",
-"Ilegal mezcla de collations (%s,%s) y (%s,%s) para operación '%s'",
-"No puede remover uno o mas de los usuarios solicitados",
-"No puede revocar todos los privilegios, derecho para uno o mas de los usuarios solicitados",
-"Ilegal mezcla de collations (%s,%s), (%s,%s), (%s,%s) para operación '%s'",
-"Ilegal mezcla de collations para operación '%s'",
-"Variable '%-.64s' no es una variable componente (No puede ser usada como XXXX.variable_name)",
-"Collation desconocida: '%-.64s'",
-"Parametros SSL en CHANGE MASTER son ignorados porque este slave MySQL fue compilado sin soporte SSL; pueden ser usados despues cuando el slave MySQL con SSL sea inicializado",
-"Servidor está rodando en modo --secure-auth, pero '%s'@'%s' tiene clave en el antiguo formato; por favor cambie la clave para el nuevo formato",
-"Campo o referencia '%-.64s%s%-.64s%s%-.64s' de SELECT #%d fue resolvido en SELECT #%d",
-"Parametro equivocado o combinación de parametros para START SLAVE UNTIL",
-"Es recomendado rodar con --skip-slave-start cuando haciendo replicación step-by-step con START SLAVE UNTIL, a menos que usted no esté seguro en caso de inesperada reinicialización del mysqld slave",
-"SQL thread no es inicializado tal que opciones UNTIL son ignoradas",
-"Nombre de índice incorrecto '%-.100s'",
-"Nombre de catalog incorrecto '%-.100s'",
-"Query cache fallada para configurar tamaño %lu, nuevo tamaño de query cache es %lu",
-"Columna '%-.64s' no puede ser parte de FULLTEXT index",
-"Desconocida key cache '%-.100s'",
-"MySQL esta inicializado en modo --skip-name-resolve. Usted necesita reinicializarlo sin esta opción para este derecho funcionar",
-"Desconocido motor de tabla '%s'",
-"'%s' está desaprobado, use '%s' en su lugar",
-"La tabla destino %-.100s del %s no es actualizable",
-"El recurso '%s' fue deshabilitado; usted necesita construir MySQL con '%s' para tener eso funcionando",
-"El servidor MySQL está rodando con la opción %s tal que no puede ejecutar este comando",
-"Columna '%-.100s' tiene valor doblado '%-.64s' en %s"
-"Equivocado truncado %-.32s valor: '%-.128s'"
-"Incorrecta definición de tabla; Solamente debe haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o ON UPDATE cláusula"
-"Inválido ON UPDATE cláusula para campo '%-.64s'",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
deleted file mode 100644
index ca863df7939..00000000000
--- a/sql/share/swedish/errmsg.txt
+++ /dev/null
@@ -1,321 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-character-set=latin1
-
-"hashchk",
-"isamchk",
-"NO",
-"YES",
-"Kan inte skapa filen '%-.64s' (Felkod: %d)",
-"Kan inte skapa tabellen '%-.64s' (Felkod: %d)",
-"Kan inte skapa databasen '%-.64s' (Felkod: %d)",
-"Databasen '%-.64s' existerar redan",
-"Kan inte radera databasen '%-.64s'; databasen finns inte",
-"Fel vid radering av databasen (Kan inte radera '%-.64s'. Felkod: %d)",
-"Fel vid radering av databasen (Kan inte radera biblioteket '%-.64s'. Felkod: %d)",
-"Kan inte radera filen '%-.64s' (Felkod: %d)",
-"Hittar inte posten i systemregistret",
-"Kan inte läsa filinformationen (stat) från '%-.64s' (Felkod: %d)",
-"Kan inte inte läsa aktivt bibliotek. (Felkod: %d)",
-"Kan inte låsa filen. (Felkod: %d)",
-"Kan inte använda '%-.64s' (Felkod: %d)",
-"Hittar inte filen '%-.64s' (Felkod: %d)",
-"Kan inte läsa från bibliotek '%-.64s' (Felkod: %d)",
-"Kan inte byta till '%-.64s' (Felkod: %d)",
-"Posten har förändrats sedan den lästes i register '%-.64s'",
-"Disken är full (%s). Väntar tills det finns ledigt utrymme...",
-"Kan inte skriva, dubbel söknyckel i register '%-.64s'",
-"Fick fel vid stängning av '%-.64s' (Felkod: %d)",
-"Fick fel vid läsning av '%-.64s' (Felkod %d)",
-"Kan inte byta namn från '%-.64s' till '%-.64s' (Felkod: %d)",
-"Fick fel vid skrivning till '%-.64s' (Felkod %d)",
-"'%-.64s' är låst mot användning",
-"Sorteringen avbruten",
-"Formulär '%-.64s' finns inte i '%-.64s'",
-"Fick felkod %d från databashanteraren",
-"Registrets databas har inte denna facilitet",
-"Hittar inte posten",
-"Felaktig fil: '%-.64s'",
-"Fatalt fel vid hantering av register '%-.64s'; kör en reparation",
-"Gammal nyckelfil '%-.64s'; reparera registret",
-"'%-.64s' är skyddad mot förändring",
-"Oväntat slut på minnet, starta om programmet och försök på nytt (Behövde %d bytes)",
-"Sorteringsbufferten räcker inte till. Kontrollera startparametrarna",
-"Oväntat filslut vid läsning från '%-.64s' (Felkod: %d)",
-"För många anslutningar",
-"Fick slut på minnet. Kontrollera om mysqld eller någon annan process använder allt tillgängligt minne. Om inte, försök använda 'ulimit' eller allokera mera swap",
-"Kan inte hitta 'hostname' för din adress",
-"Fel vid initiering av kommunikationen med klienten",
-"Användare '%-.32s'@'%-.64s' är ej berättigad att använda databasen %-.64s",
-"Användare '%-.32s'@'%-.64s' är ej berättigad att logga in (Använder lösen: %s)",
-"Ingen databas i användning",
-"Okänt commando",
-"Kolumn '%-.64s' får inte vara NULL",
-"Okänd databas: '%-.64s'",
-"Tabellen '%-.64s' finns redan",
-"Okänd tabell '%-.180s'",
-"Kolumn '%-.64s' i %s är inte unik",
-"Servern går nu ned",
-"Okänd kolumn '%-.64s' i %s",
-"'%-.64s' finns inte i GROUP BY",
-"Kan inte använda GROUP BY med '%-.64s'",
-"Kommandot har både sum functions och enkla funktioner",
-"Antalet kolumner motsvarar inte antalet värden",
-"Kolumnnamn '%-.64s' är för långt",
-"Kolumnnamn '%-.64s finns flera gånger",
-"Nyckelnamn '%-.64s' finns flera gånger",
-"Dubbel nyckel '%-.64s' för nyckel %d",
-"Felaktigt kolumntyp för kolumn '%-.64s'",
-"%s nära '%-.64s' på rad %d",
-"Frågan var tom",
-"Icke unikt tabell/alias: '%-.64s'",
-"Ogiltigt DEFAULT värde för '%-.64s'",
-"Flera PRIMARY KEY använda",
-"För många nycklar använda. Man får ha högst %d nycklar",
-"För många nyckeldelar använda. Man får ha högst %d nyckeldelar",
-"För lång nyckel. Högsta tillåtna nyckellängd är %d",
-"Nyckelkolumn '%-.64s' finns inte",
-"En BLOB '%-.64s' kan inte vara nyckel med den använda tabelltypen",
-"För stor kolumnlängd angiven för '%-.64s' (max= %d). Använd en BLOB instället",
-"Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel",
-"%s: klar att ta emot klienter",
-"%s: Normal avslutning\n",
-"%s: Fick signal %d. Avslutar!\n",
-"%s: Avslutning klar\n",
-"%s: Stänger av tråd %ld; användare: '%-.64s'\n",
-"Kan inte skapa IP-socket",
-"Tabellen '%-.64s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen",
-"Fältseparatorerna är vad som förväntades. Kontrollera mot manualen",
-"Man kan inte använda fast radlängd med blobs. Använd 'fields terminated by'",
-"Textfilen '%.64s' måste finnas i databasbiblioteket eller vara läsbar för alla",
-"Filen '%-.64s' existerar redan",
-"Rader: %ld Bortagna: %ld Dubletter: %ld Varningar: %ld",
-"Rader: %ld Dubletter: %ld",
-"Felaktig delnyckel. Nyckeldelen är inte en sträng eller den angivna längden är längre än kolumnlängden",
-"Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället",
-"Kan inte ta bort '%-.64s'. Kontrollera att fältet/nyckel finns",
-"Rader: %ld Dubletter: %ld Varningar: %ld",
-"INSERT-table '%-.64s' får inte finnas i FROM tabell-listan",
-"Finns ingen tråd med id %lu",
-"Du är inte ägare till tråd %lu",
-"Inga tabeller angivna",
-"För många alternativ till kolumn %s för SET",
-"Kan inte generera ett unikt filnamn %s.(1-999)\n",
-"Tabell '%-.64s' kan inte uppdateras emedan den är låst för läsning",
-"Tabell '%-.64s' är inte låst med LOCK TABLES",
-"BLOB fält '%-.64s' kan inte ha ett DEFAULT-värde",
-"Felaktigt databasnamn '%-.64s'",
-"Felaktigt tabellnamn '%-.64s'",
-"Den angivna frågan skulle läsa mer än MAX_JOIN_SIZE rader. Kontrollera din WHERE och använd SET SQL_BIG_SELECTS=1 eller SET MAX_JOIN_SIZE=# ifall du vill hantera stora joins",
-"Oidentifierat fel",
-"Okänd procedur: %s",
-"Felaktigt antal parametrar till procedur %s",
-"Felaktiga parametrar till procedur %s",
-"Okänd tabell '%-.64s' i '%-.64s'",
-"Fält '%-.64s' är redan använt",
-"Felaktig användning av SQL grupp function",
-"Tabell '%-.64s' har en extension som inte finns i denna version av MySQL",
-"Tabeller måste ha minst 1 kolumn",
-"Tabellen '%-.64s' är full",
-"Okänd teckenuppsättning: '%-.64s'",
-"För många tabeller. MySQL can ha högst %d tabeller i en och samma join",
-"För många fält",
-"För stor total radlängd. Den högst tillåtna radlängden, förutom BLOBs, är %d. Ändra några av dina fält till BLOB",
-"Trådstacken tog slut: Har använt %ld av %ld bytes. Använd 'mysqld -O thread_stack=#' ifall du behöver en större stack",
-"Felaktigt referens i OUTER JOIN. Kontrollera ON-uttrycket",
-"Kolumn '%-.32s' är använd med UNIQUE eller INDEX men är inte definerad med NOT NULL",
-"Kan inte ladda funktionen '%-.64s'",
-"Kan inte initialisera funktionen '%-.64s'; '%-.80s'",
-"Man får inte ange sökväg för dynamiska bibliotek",
-"Funktionen '%-.64s' finns redan",
-"Kan inte öppna det dynamiska biblioteket '%-.64s' (Felkod: %d %s)",
-"Hittar inte funktionen '%-.64s' in det dynamiska biblioteket",
-"Funktionen '%-.64s' är inte definierad",
-"Denna dator, '%-.64s', är blockerad pga många felaktig paket. Gör 'mysqladmin flush-hosts' för att ta bort alla blockeringarna",
-"Denna dator, '%-.64s', har inte privileger att använda denna MySQL server",
-"Du använder MySQL som en anonym användare och som sådan får du inte ändra ditt lösenord",
-"För att ändra lösenord för andra måste du ha rättigheter att uppdatera mysql-databasen",
-"Hittade inte användaren i 'user'-tabellen",
-"Rader: %ld Uppdaterade: %ld Varningar: %ld",
-"Kan inte skapa en ny tråd (errno %d)",
-"Antalet kolumner motsvarar inte antalet värden på rad: %ld",
-"Kunde inte stänga och öppna tabell '%-.64s",
-"Felaktig använding av NULL",
-"Fick fel '%-.64s' från REGEXP",
-"Man får ha både GROUP-kolumner (MIN(),MAX(),COUNT()...) och fält i en fråga om man inte har en GROUP BY-del",
-"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s'",
-"%-.16s ej tillåtet för '%-.32s'@'%-.64s' för tabell '%-.64s'",
-"%-.16s ej tillåtet för '%-.32s'@'%-.64s' för kolumn '%-.64s' i tabell '%-.64s'",
-"Felaktigt GRANT-privilegium använt",
-"Felaktigt maskinnamn eller användarnamn använt med GRANT",
-"Det finns ingen tabell som heter '%-.64s.%s'",
-"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s' för tabell '%-.64s'",
-"Du kan inte använda detta kommando med denna MySQL version",
-"Du har något fel i din syntax",
-"DELAYED INSERT-tråden kunde inte låsa tabell '%-.64s'",
-"Det finns redan 'max_delayed_threads' trådar i använding",
-"Avbröt länken för tråd %ld till db '%-.64s', användare '%-.64s' (%s)",
-"Kommunkationspaketet är större än 'max_allowed_packet'",
-"Fick läsfel från klienten vid läsning från 'PIPE'",
-"Fick fatalt fel från 'fcntl()'",
-"Kommunikationspaketen kom i fel ordning",
-"Kunde inte packa up kommunikationspaketet",
-"Fick ett fel vid läsning från klienten",
-"Fick 'timeout' vid läsning från klienten",
-"Fick ett fel vid skrivning till klienten",
-"Fick 'timeout' vid skrivning till klienten",
-"Resultatsträngen är längre än 'max_allowed_packet'",
-"Den använda tabelltypen kan inte hantera BLOB/TEXT-kolumner",
-"Den använda tabelltypen kan inte hantera AUTO_INCREMENT-kolumner",
-"INSERT DELAYED kan inte användas med tabell '%-.64s', emedan den är låst med LOCK TABLES",
-"Felaktigt kolumnnamn '%-.100s'",
-"Den använda tabelltypen kan inte indexera kolumn '%-.64s'",
-"Tabellerna i MERGE-tabellen är inte identiskt definierade",
-"Kan inte skriva till tabell '%-.64s'; UNIQUE-test",
-"Du har inte angett någon nyckellängd för BLOB '%-.64s'",
-"Alla delar av en PRIMARY KEY måste vara NOT NULL; Om du vill ha en nyckel med NULL, använd UNIQUE istället",
-"Resultet bestod av mera än en rad",
-"Denna tabelltyp kräver en PRIMARY KEY",
-"Denna version av MySQL är inte kompilerad med RAID",
-"Du använder 'säker uppdateringsmod' och försökte uppdatera en tabell utan en WHERE-sats som använder sig av en nyckel",
-"Nyckel '%-.64s' finns inte in tabell '%-.64s'",
-"Kan inte öppna tabellen",
-"Tabellhanteraren för denna tabell kan inte göra %s",
-"Du får inte utföra detta kommando i en transaktion",
-"Fick fel %d vid COMMIT",
-"Fick fel %d vid ROLLBACK",
-"Fick fel %d vid FLUSH_LOGS",
-"Fick fel %d vid CHECKPOINT",
-"Avbröt länken för tråd %ld till db '%-.64s', användare '%-.32s', host '%-.64s' (%-.64s)",
-"Tabellhanteraren klarar inte en binär kopiering av tabellen",
-"Binärloggen stängdes medan FLUSH MASTER utfördes",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Fick en master: '%-.64s'",
-"Fick nätverksfel vid läsning från master",
-"Fick nätverksfel vid skrivning till master",
-"Hittar inte ett FULLTEXT-index i kolumnlistan",
-"Kan inte utföra kommandot emedan du har en låst tabell eller an aktiv transaktion",
-"Okänd systemvariabel: '%-.64s'",
-"Tabell '%-.64s' är trasig och bör repareras med REPAIR TABLE",
-"Tabell '%-.64s' är trasig och senast (automatiska?) reparation misslyckades",
-"Warning: Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK",
-"Transaktionen krävde mera än 'max_binlog_cache_size' minne. Öka denna mysqld-variabel och försök på nytt",
-"Denna operation kan inte göras under replikering; Gör STOP SLAVE först",
-"Denna operation kan endast göras under replikering; Konfigurera slaven och gör START SLAVE",
-"Servern är inte konfigurerade som en replikationsslav. Ändra konfigurationsfilen eller gör CHANGE MASTER TO",
-"Kunde inte initialisera replikationsstrukturerna. See MySQL fel fil för mera information",
-"Kunde inte starta en tråd för replikering",
-"Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar",
-"Man kan endast använda konstantuttryck med SET",
-"Fick inte ett lås i tid ; Försök att starta om transaktionen",
-"Antal lås överskrider antalet reserverade lås",
-"Updateringslås kan inte göras när man använder READ UNCOMMITTED",
-"DROP DATABASE är inte tillåtet när man har ett globalt läslås",
-"CREATE DATABASE är inte tillåtet när man har ett globalt läslås",
-"Felaktiga argument till %s",
-"'%-.32s'@'%-.64s' har inte rättighet att skapa nya användare",
-"Felaktig tabelldefinition; alla tabeller i en MERGE-tabell måste vara i samma databas",
-"Fick 'DEADLOCK' vid låsförsök av block/rad. Försök att starta om transaktionen",
-"Tabelltypen har inte hantering av FULLTEXT-index",
-"Kan inte lägga till 'FOREIGN KEY constraint'",
-"FOREIGN KEY-konflikt: Kan inte skriva barn",
-"FOREIGN KEY-konflikt: Kan inte radera fader",
-"Fick fel vid anslutning till master: %-.128s",
-"Fick fel vid utförande av command på mastern: %-.128s",
-"Fick fel vid utförande av %s: %-.128s",
-"Felaktig använding av %s and %s",
-"SELECT-kommandona har olika antal kolumner",
-"Kan inte utföra kommandot emedan du har ett READ-lås",
-"Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat",
-"Option '%s' användes två gånger",
-"Användare '%-.64s' har överskridit '%s' (nuvarande värde: %ld)",
-"Du har inte privlegiet '%-.128s' som behövs för denna operation",
-"Variabel '%-.64s' är en SESSION variabel och kan inte ändrad med SET GLOBAL",
-"Variabel '%-.64s' är en GLOBAL variabel och bör sättas med SET GLOBAL",
-"Variabel '%-.64s' har inte ett DEFAULT-värde",
-"Variabel '%-.64s' kan inte sättas till '%-.64s'",
-"Fel typ av argument till variabel '%-.64s'",
-"Variabeln '%-.64s' kan endast sättas, inte läsas",
-"Fel använding/placering av '%s'",
-"Denna version av MySQL kan ännu inte utföra '%s'",
-"Fick fatalt fel %d: '%-.128s' från master vid läsning av binärloggen",
-"Slav SQL tråden ignorerade frågan pga en replicate-*-table regel",
-"Variabel '%-.64s' är av typ %s",
-"Felaktig FOREIGN KEY-definition för '%-.64s': %s",
-"Nyckelreferensen och tabellreferensen stämmer inte överens",
-"Operand should contain %d column(s)",
-"Subquery returnerade mer än 1 rad",
-"Okänd PREPARED STATEMENT id (%.*s) var given till %s",
-"Hjälpdatabasen finns inte eller är skadad",
-"Cyklisk referens i subqueries",
-"Konvertar kolumn '%s' från %s till %s",
-"Referens '%-.64s' stöds inte (%s)",
-"Varje 'derived table' måste ha sitt eget alias",
-"Select %u reducerades vid optimiering",
-"Tabell '%-.64s' från en SELECT kan inte användas i %-.32s",
-"Klienten stöder inte autentiseringsprotokollet som begärts av servern; överväg uppgradering av klientprogrammet.",
-"Alla delar av en SPATIAL index måste vara NOT NULL",
-"COLLATION '%s' är inte tillåtet för CHARACTER SET '%s'",
-"Slaven har redan startat",
-"Slaven har redan stoppat",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d rad(er) kapades av GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Använder handler %s för tabell '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Felaktigt index namn '%-.100s'",
-"Felaktigt katalog namn '%-.100s'",
-"Storleken av "Query cache" kunde inte sättas till %lu, ny storlek är %lu",
-"Kolumn '%-.64s' kan inte vara del av ett FULLTEXT index",
-"Okänd nyckel cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"Tabel %-.100s använd med '%s' är inte uppdateringsbar",
-"'%s' är inte aktiverad; För att aktivera detta måste du bygga om MySQL med '%s' definerad",
-"MySQL är startad med --skip-grant-tables. Pga av detta kan du inte använda detta kommando",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Fick felkod %d '%-.100s' från %s",
-"Fick tilfällig felkod %d '%-.100s' från %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
deleted file mode 100644
index b3859fb881c..00000000000
--- a/sql/share/ukrainian/errmsg.txt
+++ /dev/null
@@ -1,327 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- * Ukrainian translation by Roman Festchook <roma@orta.zt.ua>
- * Encoding: KOI8-U
- * Version: 13/09/2001 mysql-3.23.41
- */
-
-character-set=koi8u
-
-"hashchk",
-"isamchk",
-"î¶",
-"ôáë",
-"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÔÁÂÌÉÃÀ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s'. âÁÚÁ ÄÁÎÎÉÈ ¦ÓÎÕ¤",
-"îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s'. âÁÚÁ ÄÁÎÎÉÈ ÎÅ ¦ÓÎÕ¤",
-"îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.64s', ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÔÅËÕ '%-.64s', ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÚÞÉÔÁÔÉ ÚÁÐÉÓ Ú ÓÉÓÔÅÍÎϧ ÔÁÂÌÉæ",
-"îÅ ÍÏÖÕ ÏÔÒÉÍÁÔÉ ÓÔÁÔÕÓ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ×ÉÚÎÁÞÉÔÉ ÒÏÂÏÞÕ ÔÅËÕ (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÚÁÂÌÏËÕ×ÁÔÉ ÆÁÊÌ (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÆÁÊÌ: '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÚÎÁÊÔÉ ÆÁÊÌ: '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÔÅËÕ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÐÅÒÅÊÔÉ Õ ÔÅËÕ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"úÁÐÉÓ ÂÕÌÏ ÚͦÎÅÎÏ Ú ÞÁÓÕ ÏÓÔÁÎÎØÏÇÏ ÞÉÔÁÎÎÑ Ú ÔÁÂÌÉæ '%-.64s'",
-"äÉÓË ÚÁÐÏ×ÎÅÎÉÊ (%s). ÷ÉÞÉËÕÀ, ÄÏËÉ ÚצÌØÎÉÔØÓÑ ÔÒÏÈÉ Í¦ÓÃÑ...",
-"îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ, ÄÕÂÌÀÀÞÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉæ '%-.64s'",
-"îÅ ÍÏÖÕ ÚÁËÒÉÔÉ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÐÅÒÅÊÍÅÎÕ×ÁÔÉ '%-.64s' Õ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"'%-.64s' ÚÁÂÌÏËÏ×ÁÎÉÊ ÎÁ ×ÎÅÓÅÎÎÑ ÚͦÎ",
-"óÏÒÔÕ×ÁÎÎÑ ÐÅÒÅÒ×ÁÎÏ",
-"÷ÉÇÌÑÄ '%-.64s' ÎÅ ¦ÓÎÕ¤ ÄÌÑ '%-.64s'",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d ×¦Ä ÄÅÓËÒÉÐÔÏÒÁ ÔÁÂÌÉæ",
-"äÅÓËÒÉÐÔÏÒ ÔÁÂÌÉæ '%-.64s' ÎÅ ÍÁ¤ 椧 ×ÌÁÓÔÉ×ÏÓÔ¦",
-"îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ Õ '%-.64s'",
-"èÉÂÎÁ ¦ÎÆÏÒÍÁÃ¦Ñ Õ ÆÁÊ̦: '%-.64s'",
-"èÉÂÎÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ: '%-.64s'; óÐÒÏÂÕÊÔÅ ÊÏÇÏ ×¦ÄÎÏ×ÉÔÉ",
-"óÔÁÒÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ '%-.64s'; ÷¦ÄÎÏצÔØ ÊÏÇÏ!",
-"ôÁÂÌÉÃÑ '%-.64s' Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ",
-"âÒÁË ÐÁÍ'ÑÔ¦. òÅÓÔÁÒÔÕÊÔÅ ÓÅÒ×ÅÒ ÔÁ ÓÐÒÏÂÕÊÔÅ ÚÎÏ×Õ (ÐÏÔÒ¦ÂÎÏ %d ÂÁÊÔ¦×)",
-"âÒÁË ÐÁÍ'ÑÔ¦ ÄÌÑ ÓÏÒÔÕ×ÁÎÎÑ. ôÒÅÂÁ Ú¦ÌØÛÉÔÉ ÒÏÚÍ¦Ò ÂÕÆÅÒÁ ÓÏÒÔÕ×ÁÎÎÑ Õ ÓÅÒ×ÅÒÁ",
-"èÉÂÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ '%-.64s' (ÐÏÍÉÌËÁ: %d)",
-"úÁÂÁÇÁÔÏ Ú'¤ÄÎÁÎØ",
-"âÒÁË ÐÁÍ'ÑÔ¦; ðÅÒÅצÒÔÅ ÞÉ mysqld ÁÂÏ Ñ˦ÓØ ¦ÎÛ¦ ÐÒÏÃÅÓÉ ×ÉËÏÒÉÓÔÏ×ÕÀÔØ ÕÓÀ ÄÏÓÔÕÐÎÕ ÐÁÍ'ÑÔØ. ñË Î¦, ÔÏ ×É ÍÏÖÅÔÅ ÓËÏÒÉÓÔÁÔÉÓÑ 'ulimit', ÁÂÉ ÄÏÚ×ÏÌÉÔÉ mysqld ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ Â¦ÌØÛÅ ÐÁÍ'ÑÔ¦ ÁÂÏ ×É ÍÏÖÅÔÅ ÄÏÄÁÔÉ Â¦ÌØÛŠͦÓÃÑ Ð¦Ä Ó×ÁÐ",
-"îÅ ÍÏÖÕ ×ÉÚÎÁÞÉÔÉ ¦Í'Ñ ÈÏÓÔÕ ÄÌÑ ×ÁÛϧ ÁÄÒÅÓÉ",
-"îÅצÒÎÁ ÕÓÔÁÎÏ×ËÁ Ú×'ÑÚËÕ",
-"äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'@'%-.64s' ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ '%-.64s'",
-"äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'@'%-.64s' (÷ÉËÏÒÉÓÔÁÎÏ ÐÁÒÏÌØ: %s)",
-"âÁÚÕ ÄÁÎÎÉÈ ÎÅ ×ÉÂÒÁÎÏ",
-"îÅצÄÏÍÁ ËÏÍÁÎÄÁ",
-"óÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÎÕÌØÏ×ÉÍ",
-"îÅצÄÏÍÁ ÂÁÚÁ ÄÁÎÎÉÈ '%-.64s'",
-"ôÁÂÌÉÃÑ '%-.64s' ×ÖÅ ¦ÓÎÕ¤",
-"îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.180s'",
-"óÔÏ×ÂÅÃØ '%-.64s' Õ %-.64s ×ÉÚÎÁÞÅÎÉÊ ÎÅÏÄÎÏÚÎÁÞÎÏ",
-"úÁ×ÅÒÛÕ¤ÔØÓÑ ÒÁÂÏÔÁ ÓÅÒ×ÅÒÁ",
-"îÅצÄÏÍÉÊ ÓÔÏ×ÂÅÃØ '%-.64s' Õ '%-.64s'",
-"'%-.64s' ÎÅ ¤ Õ GROUP BY",
-"îÅ ÍÏÖÕ ÇÒÕÐÕ×ÁÔÉ ÐÏ '%-.64s'",
-"õ ×ÉÒÁÚ¦ ×ÉËÏÒÉÓÔÁÎÏ Ð¦ÄÓÕÍÏ×ÕÀÞ¦ ÆÕÎËæ§ ÐÏÒÑÄ Ú ¦ÍÅÎÁÍÉ ÓÔÏ×Âæ×",
-"ë¦ÌØ˦ÓÔØ ÓÔÏ×ÂÃ¦× ÎÅ ÓЦ×ÐÁÄÁ¤ Ú Ë¦ÌØ˦ÓÔÀ ÚÎÁÞÅÎØ",
-"¶Í'Ñ ¦ÄÅÎÔÉƦËÁÔÏÒÁ '%-.100s' ÚÁÄÏ×ÇÅ",
-"äÕÂÌÀÀÞÅ ¦Í'Ñ ÓÔÏ×ÂÃÑ '%-.64s'",
-"äÕÂÌÀÀÞÅ ¦Í'Ñ ËÌÀÞÁ '%-.64s'",
-"äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.64s' ÄÌÑ ËÌÀÞÁ %d",
-"îÅצÒÎÉÊ ÓÐÅÃÉƦËÁÔÏÒ ÓÔÏ×ÂÃÑ '%-.64s'",
-"%s ¦ÌÑ '%-.80s' × ÓÔÒÏæ %d",
-"ðÕÓÔÉÊ ÚÁÐÉÔ",
-"îÅÕΦËÁÌØÎÁ ÔÁÂÌÉÃÑ/ÐÓÅ×ÄÏΦÍ: '%-.64s'",
-"îÅצÒÎÅ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ ÄÌÑ '%-.64s'",
-"ðÅÒ×ÉÎÎÏÇÏ ËÌÀÞÁ ×ÉÚÎÁÞÅÎÏ ÎÅÏÄÎÏÒÁÚÏ×Ï",
-"úÁÂÁÇÁÔÏ ËÌÀÞ¦× ÚÁÚÎÁÞÅÎÏ. äÏÚ×ÏÌÅÎÏ ÎŠ¦ÌØÛÅ %d ËÌÀÞ¦×",
-"úÁÂÁÇÁÔÏ ÞÁÓÔÉÎ ËÌÀÞÁ ÚÁÚÎÁÞÅÎÏ. äÏÚ×ÏÌÅÎÏ ÎŠ¦ÌØÛÅ %d ÞÁÓÔÉÎ",
-"úÁÚÎÁÞÅÎÉÊ ËÌÀÞ ÚÁÄÏ×ÇÉÊ. îÁʦÌØÛÁ ÄÏ×ÖÉÎÁ ËÌÀÞÁ %d ÂÁÊÔ¦×",
-"ëÌÀÞÏ×ÉÊ ÓÔÏ×ÂÅÃØ '%-.64s' ÎÅ ¦ÓÎÕ¤ Õ ÔÁÂÌÉæ",
-"BLOB ÓÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ × ÃØÏÍÕ ÔÉЦ ÔÁÂÌÉæ",
-"úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.64s' (max = %d). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB",
-"îÅצÒÎÅ ×ÉÚÎÁÞÅÎÎÑ ÔÁÂÌÉæ; íÏÖÅ ÂÕÔÉ ÌÉÛÅ ÏÄÉÎ Á×ÔÏÍÁÔÉÞÎÉÊ ÓÔÏ×ÂÅÃØ, ÝÏ ÐÏ×ÉÎÅÎ ÂÕÔÉ ×ÉÚÎÁÞÅÎÉÊ ÑË ËÌÀÞ",
-"%s: çÏÔÏ×ÉÊ ÄÌÑ Ú'¤ÄÎÁÎØ!",
-"%s: îÏÒÍÁÌØÎÅ ÚÁ×ÅÒÛÅÎÎÑ\n",
-"%s: ïÔÒÉÍÁÎÏ ÓÉÇÎÁÌ %d. ðÅÒÅÒÉ×ÁÀÓØ!\n",
-"%s: òÏÂÏÔÕ ÚÁ×ÅÒÛÅÎÏ\n",
-"%s: ðÒÉÓËÏÒÀÀ ÚÁËÒÉÔÔÑ Ç¦ÌËÉ %ld ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'\n",
-"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ IP ÒÏÚ'¤Í",
-"ôÁÂÌÉÃÑ '%-.64s' ÍÁ¤ ¦ÎÄÅËÓ, ÝÏ ÎÅ ÓЦ×ÐÁÄÁ¤ Ú ×ËÁÚÁÎÎÉÍ Õ CREATE INDEX. óÔ×ÏÒ¦ÔØ ÔÁÂÌÉÃÀ ÚÎÏ×Õ",
-"èÉÂÎÉÊ ÒÏÚĦÌÀ×ÁÞ ÐÏ̦×. ðÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ",
-"îÅ ÍÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÓÔÁÌÕ ÄÏ×ÖÉÎÕ ÓÔÒÏËÉ Ú BLOB. úËÏÒÉÓÔÁÊÔÅÓÑ 'fields terminated by'",
-"æÁÊÌ '%-.64s' ÐÏ×ÉÎÅÎ ÂÕÔÉ Õ ÔÅæ ÂÁÚÉ ÄÁÎÎÉÈ ÁÂÏ ÍÁÔÉ ×ÓÔÁÎÏ×ÌÅÎÅ ÐÒÁ×Ï ÎÁ ÞÉÔÁÎÎÑ ÄÌÑ ÕÓ¦È",
-"æÁÊÌ '%-.80s' ×ÖÅ ¦ÓÎÕ¤",
-"úÁÐÉÓ¦×: %ld ÷ÉÄÁÌÅÎÏ: %ld ðÒÏÐÕÝÅÎÏ: %ld úÁÓÔÅÒÅÖÅÎØ: %ld",
-"úÁÐÉÓ¦×: %ld äÕÂ̦ËÁÔ¦×: %ld",
-"îÅצÒÎÁ ÞÁÓÔÉÎÁ ËÌÀÞÁ. ÷ÉËÏÒÉÓÔÁÎÁ ÞÁÓÔÉÎÁ ËÌÀÞÁ ÎÅ ¤ ÓÔÒÏËÏÀ, ÚÁÄÏ×ÇÁ ÁÂÏ ×ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ ÕΦËÁÌØÎÉÈ ÞÁÓÔÉÎ ËÌÀÞÅÊ",
-"îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ×Ó¦ ÓÔÏ×Âæ ÚÁ ÄÏÐÏÍÏÇÏÀ ALTER TABLE. äÌÑ ÃØÏÇÏ ÓËÏÒÉÓÔÁÊÔÅÓÑ DROP TABLE",
-"îÅ ÍÏÖÕ DROP '%-.64s'. ðÅÒÅצÒÔÅ, ÞÉ ÃÅÊ ÓÔÏ×ÂÅÃØ/ËÌÀÞ ¦ÓÎÕ¤",
-"úÁÐÉÓ¦×: %ld äÕÂ̦ËÁÔ¦×: %ld úÁÓÔÅÒÅÖÅÎØ: %ld",
-"ôÁÂÌÉÃÑ '%-.64s' ÝÏ ÚͦÎÀ¤ÔØÓÑ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ ÐÅÒÅ̦ËÕ ÔÁÂÌÉÃØ FROM",
-"îÅצÄÏÍÉÊ ¦ÄÅÎÔÉƦËÁÔÏÒ Ç¦ÌËÉ: %lu",
-"÷É ÎÅ ×ÏÌÏÄÁÒ Ç¦ÌËÉ %lu",
-"îÅ ×ÉËÏÒÉÓÔÁÎÏ ÔÁÂÌÉÃØ",
-"úÁÂÁÇÁÔÏ ÓÔÒÏË ÄÌÑ ÓÔÏ×ÂÃÑ %-.64s ÔÁ SET",
-"îÅ ÍÏÖÕ ÚÇÅÎÅÒÕ×ÁÔÉ ÕΦËÁÌØÎÅ ¦Í'Ñ log-ÆÁÊÌÕ %-.64s.(1-999)\n",
-"ôÁÂÌÉÃÀ '%-.64s' ÚÁÂÌÏËÏ×ÁÎÏ Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ, ÔÏÍÕ §§ ÎÅ ÍÏÖÎÁ ÏÎÏ×ÉÔÉ",
-"ôÁÂÌÉÃÀ '%-.64s' ÎÅ ÂÕÌÏ ÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES",
-"óÔÏ×ÂÅÃØ BLOB '%-.64s' ÎÅ ÍÏÖÅ ÍÁÔÉ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ",
-"îÅצÒÎÅ ¦Í'Ñ ÂÁÚÉ ÄÁÎÎÉÈ '%-.100s'",
-"îÅצÒÎÅ ¦Í'Ñ ÔÁÂÌÉæ '%-.100s'",
-"úÁÐÉÔÕ SELECT ÐÏÔÒ¦ÂÎÏ ÏÂÒÏÂÉÔÉ ÂÁÇÁÔÏ ÚÁÐÉÓ¦×, ÝÏ, ÐÅ×ÎÅ, ÚÁÊÍÅ ÄÕÖÅ ÂÁÇÁÔÏ ÞÁÓÕ. ðÅÒÅצÒÔÅ ×ÁÛÅ WHERE ÔÁ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ SET SQL_BIG_SELECTS=1, ÑËÝÏ ÃÅÊ ÚÁÐÉÔ SELECT ¤ צÒÎÉÍ",
-"îÅצÄÏÍÁ ÐÏÍÉÌËÁ",
-"îÅצÄÏÍÁ ÐÒÏÃÅÄÕÒÁ '%-.64s'",
-"èÉÂÎÁ ˦ÌØ˦ÓÔØ ÐÁÒÁÍÅÔÒ¦× ÐÒÏÃÅÄÕÒÉ '%-.64s'",
-"èÉÂÎÉÊ ÐÁÒÁÍÅÔÅÒ ÐÒÏÃÅÄÕÒÉ '%-.64s'",
-"îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.64s' Õ %-.32s",
-"óÔÏ×ÂÅÃØ '%-.64s' ÚÁÚÎÁÞÅÎÏ Äצަ",
-"èÉÂÎÅ ×ÉËÏÒÉÓÔÁÎÎÑ ÆÕÎËæ§ ÇÒÕÐÕ×ÁÎÎÑ",
-"ôÁÂÌÉÃÑ '%-.64s' ×ÉËÏÒÉÓÔÏ×Õ¤ ÒÏÚÛÉÒÅÎÎÑ, ÝÏ ÎÅ ¦ÓÎÕ¤ Õ Ã¦Ê ×ÅÒÓ¦§ MySQL",
-"ôÁÂÌÉÃÑ ÐÏ×ÉÎÎÁ ÍÁÔÉ ÈÏÞÁ ÏÄÉÎ ÓÔÏ×ÂÅÃØ",
-"ôÁÂÌÉÃÑ '%-.64s' ÚÁÐÏ×ÎÅÎÁ",
-"îÅצÄÏÍÁ ËÏÄÏ×Á ÔÁÂÌÉÃÑ: '%-.64s'",
-"úÁÂÁÇÁÔÏ ÔÁÂÌÉÃØ. MySQL ÍÏÖÅ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÌÉÛÅ %d ÔÁÂÌÉÃØ Õ ÏÂ'¤ÄÎÁÎΦ",
-"úÁÂÁÇÁÔÏ ÓÔÏ×Âæ×",
-"úÁÄÏ×ÇÁ ÓÔÒÏËÁ. îÁʦÌØÛÏÀ ÄÏ×ÖÉÎÏÀ ÓÔÒÏËÉ, ÎÅ ÒÁÈÕÀÞÉ BLOB, ¤ %d. ÷ÁÍ ÐÏÔÒ¦ÂÎÏ ÐÒÉ×ÅÓÔÉ ÄÅÑ˦ ÓÔÏ×Âæ ÄÏ ÔÉÐÕ BLOB",
-"óÔÅË Ç¦ÌÏË ÐÅÒÅÐÏ×ÎÅÎÏ: ÷ÉËÏÒÉÓÔÁÎÏ: %ld Ú %ld. ÷ÉËÏÒÉÓÔÏ×ÕÊÔÅ 'mysqld -O thread_stack=#' ÁÂÉ ÚÁÚÎÁÞÉÔÉ Â¦ÌØÛÉÊ ÓÔÅË, ÑËÝÏ ÎÅÏÂȦÄÎÏ",
-"ðÅÒÅÈÒÅÓÎÁ ÚÁÌÅÖΦÓÔØ Õ OUTER JOIN. ðÅÒÅצÒÔÅ ÕÍÏ×Õ ON",
-"óÔÏ×ÂÅÃØ '%-.64s' ×ÉËÏÒÉÓÔÏ×Õ¤ÔØÓÑ Ú UNIQUE ÁÂÏ INDEX, ÁÌÅ ÎÅ ×ÉÚÎÁÞÅÎÉÊ ÑË NOT NULL",
-"îÅ ÍÏÖÕ ÚÁ×ÁÎÔÁÖÉÔÉ ÆÕÎËæÀ '%-.64s'",
-"îÅ ÍÏÖÕ ¦Î¦Ã¦Á̦ÚÕ×ÁÔÉ ÆÕÎËæÀ '%-.64s'; %-.80s",
-"îÅ ÄÏÚ×ÏÌÅÎÏ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÐÕÔ¦ ÄÌÑ ÒÏÚĦÌÀ×ÁÎÉÈ Â¦Â̦ÏÔÅË",
-"æÕÎËÃ¦Ñ '%-.64s' ×ÖÅ ¦ÓÎÕ¤",
-"îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÒÏÚĦÌÀ×ÁÎÕ Â¦Â̦ÏÔÅËÕ '%-.64s' (ÐÏÍÉÌËÁ: %d %-.64s)",
-"îÅ ÍÏÖÕ ÚÎÁÊÔÉ ÆÕÎËæÀ '%-.64s' Õ Â¦Â̦ÏÔÅæ'",
-"æÕÎËæÀ '%-.64s' ÎÅ ×ÉÚÎÁÞÅÎÏ",
-"èÏÓÔ '%-.64s' ÚÁÂÌÏËÏ×ÁÎÏ Ú ÐÒÉÞÉÎÉ ×ÅÌÉËϧ ˦ÌØËÏÓÔ¦ ÐÏÍÉÌÏË Ú'¤ÄÎÁÎÎÑ. äÌÑ ÒÏÚÂÌÏËÕ×ÁÎÎÑ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ 'mysqladmin flush-hosts'",
-"èÏÓÔÕ '%-.64s' ÎÅ ÄÏ×ÏÌÅÎÏ Ú×'ÑÚÕ×ÁÔÉÓØ Ú ÃÉÍ ÓÅÒ×ÅÒÏÍ MySQL",
-"÷É ×ÉËÏÒÉÓÔÏ×Õ¤ÔÅ MySQL ÑË ÁÎÏΦÍÎÉÊ ËÏÒÉÓÔÕ×ÁÞ, ÔÏÍÕ ×ÁÍ ÎÅ ÄÏÚ×ÏÌÅÎÏ ÚͦÎÀ×ÁÔÉ ÐÁÒÏ̦",
-"÷É ÐÏ×ÉΦ ÍÁÔÉ ÐÒÁ×Ï ÎÁ ÏÎÏ×ÌÅÎÎÑ ÔÁÂÌÉÃØ Õ ÂÁÚ¦ ÄÁÎÎÉÈ mysql, ÁÂÉ ÍÁÔÉ ÍÏÖÌÉצÓÔØ ÚͦÎÀ×ÁÔÉ ÐÁÒÏÌØ ¦ÎÛÉÍ",
-"îÅ ÍÏÖÕ ÚÎÁÊÔÉ ×¦ÄÐÏצÄÎÉÈ ÚÁÐÉÓ¦× Õ ÔÁÂÌÉæ ËÏÒÉÓÔÕ×ÁÞÁ",
-"úÁÐÉÓ¦× ×¦ÄÐÏצÄÁ¤: %ld úͦÎÅÎÏ: %ld úÁÓÔÅÒÅÖÅÎØ: %ld",
-"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÎÏ×Õ Ç¦ÌËÕ (ÐÏÍÉÌËÁ %d). ñËÝÏ ×É ÎÅ ×ÉËÏÒÉÓÔÁÌÉ ÕÓÀ ÐÁÍ'ÑÔØ, ÔÏ ÐÒÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ ÄÏ ×ÁÛϧ ïó - ÍÏÖÌÉ×Ï ÃÅ ÐÏÍÉÌËÁ ïó",
-"ë¦ÌØ˦ÓÔØ ÓÔÏ×ÂÃ¦× ÎÅ ÓЦ×ÐÁÄÁ¤ Ú Ë¦ÌØ˦ÓÔÀ ÚÎÁÞÅÎØ Õ ÓÔÒÏæ %ld",
-"îÅ ÍÏÖÕ ÐÅÒÅצÄËÒÉÔÉ ÔÁÂÌÉÃÀ: '%-.64s'",
-"èÉÂÎÅ ×ÉËÏÒÉÓÔÁÎÎÑ ÚÎÁÞÅÎÎÑ NULL",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ '%-.64s' ×¦Ä ÒÅÇÕÌÑÒÎÏÇÏ ×ÉÒÁÚÕ",
-"úͦÛÕ×ÁÎÎÑ GROUP ÓÔÏ×ÂÃ¦× (MIN(),MAX(),COUNT()...) Ú ÎÅ GROUP ÓÔÏ×ÂÃÑÍÉ ¤ ÚÁÂÏÒÏÎÅÎÉÍ, ÑËÝÏ ÎÅ ÍÁ¤ GROUP BY",
-"ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.32s' Ú ÈÏÓÔÕ '%-.64s'",
-"%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s'@'%-.64s' Õ ÔÁÂÌÉæ '%-.64s'",
-"%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s'@'%-.64s' ÄÌÑ ÓÔÏ×ÂÃÑ '%-.64s' Õ ÔÁÂÌÉæ '%-.64s'",
-"èÉÂÎÁ GRANT/REVOKE ËÏÍÁÎÄÁ; ÐÒÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ ÓÔÏÓÏ×ÎÏ ÔÏÇÏ, Ñ˦ ÐÒÁ×Á ÍÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ",
-"áÒÇÕÍÅÎÔ host ÁÂÏ user ÄÌÑ GRANT ÚÁÄÏ×ÇÉÊ",
-"ôÁÂÌÉÃÑ '%-.64s.%-.64s' ÎÅ ¦ÓÎÕ¤",
-"ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.32s' Ú ÈÏÓÔÕ '%-.64s' ÄÌÑ ÔÁÂÌÉæ '%-.64s'",
-"÷ÉËÏÒÉÓÔÏ×Õ×ÁÎÁ ËÏÍÁÎÄÁ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ Ã¦Ê ×ÅÒÓ¦§ MySQL",
-"õ ×ÁÓ ÐÏÍÉÌËÁ Õ ÓÉÎÔÁËÓÉÓ¦ SQL",
-"ç¦ÌËÁ ÄÌÑ INSERT DELAYED ÎÅ ÍÏÖÅ ÏÔÒÉÍÁÔÉ ÂÌÏËÕ×ÁÎÎÑ ÄÌÑ ÔÁÂÌÉæ %-.64s",
-"úÁÂÁÇÁÔÏ ÚÁÔÒÉÍÁÎÉÈ Ç¦ÌÏË ×ÉËÏÒÉÓÔÏ×Õ¤ÔØÓÑ",
-"ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.64s' ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s' (%-.64s)",
-"ïÔÒÉÍÁÎÏ ÐÁËÅÔ Â¦ÌØÛÉÊ Î¦Ö 'max_allowed_packet'",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ ÞÉÔÁÎÎÑ Ú ËÏÍÕΦËÁæÊÎÏÇÏ ËÁÎÁÌÕ",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËËÕ ×¦Ä fcntl()",
-"ïÔÒÉÍÁÎÏ ÐÁËÅÔÉ Õ ÎÅÎÁÌÅÖÎÏÍÕ ÐÏÒÑÄËÕ",
-"îÅ ÍÏÖÕ ÄÅËÏÍÐÒÅÓÕ×ÁÔÉ ËÏÍÕΦËÁæÊÎÉÊ ÐÁËÅÔ",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ ÞÉÔÁÎÎÑ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×",
-"ïÔÒÉÍÁÎÏ ÚÁÔÒÉÍËÕ ÞÉÔÁÎÎÑ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ ÚÁÐÉÓÕ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×",
-"ïÔÒÉÍÁÎÏ ÚÁÔÒÉÍËÕ ÚÁÐÉÓÕ ËÏÍÕΦËÁæÊÎÉÈ ÐÁËÅÔ¦×",
-"óÔÒÏËÁ ÒÅÚÕÌØÔÁÔÕ ÄÏ×ÛÁ Î¦Ö 'max_allowed_packet'",
-"÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ BLOB/TEXT ÓÔÏ×Âæ",
-"÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ AUTO_INCREMENT ÓÔÏ×Âæ",
-"INSERT DELAYED ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÏ Ú ÔÁÂÌÉÃÅÀ '%-.64s', ÔÏÍÕ ÝÏ §§ ÚÁÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES",
-"îÅצÒÎÅ ¦Í'Ñ ÓÔÏ×ÂÃÑ '%-.100s'",
-"÷ÉËÏÒÉÓÔÁÎÉÊ ×ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ÎÅ ÍÏÖÅ ¦ÎÄÅËÓÕ×ÁÔÉ ÓÔÏ×ÂÅÃØ '%-.64s'",
-"ôÁÂÌÉæ Õ MERGE TABLE ÍÁÀÔØ Ò¦ÚÎÕ ÓÔÒÕËÔÕÒÕ",
-"îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÄÏ ÔÁÂÌÉæ '%-.64s', Ú ÐÒÉÞÉÎÉ ×ÉÍÏÇ ÕΦËÁÌØÎÏÓÔ¦",
-"óÔÏ×ÂÅÃØ BLOB '%-.64s' ×ÉËÏÒÉÓÔÁÎÏ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ ÂÅÚ ×ËÁÚÁÎÎÑ ÄÏ×ÖÉÎÉ ËÌÀÞÁ",
-"õÓ¦ ÞÁÓÔÉÎÉ PRIMARY KEY ÐÏ×ÉÎΦ ÂÕÔÉ NOT NULL; ñËÝÏ ×É ÐÏÔÒÅÂÕ¤ÔÅ NULL Õ ËÌÀÞ¦, ÓËÏÒÉÓÔÁÊÔÅÓÑ UNIQUE",
-"òÅÚÕÌØÔÁÔ ÚÎÁÈÏÄÉÔØÓÑ Õ Â¦ÌØÛÅ Î¦Ö ÏÄÎ¦Ê ÓÔÒÏæ",
-"ãÅÊ ÔÉÐ ÔÁÂÌÉæ ÐÏÔÒÅÂÕ¤ ÐÅÒ×ÉÎÎÏÇÏ ËÌÀÞÁ",
-"ãÑ ×ÅÒÓ¦Ñ MySQL ÎÅ ÚËÏÍЦÌØÏ×ÁÎÁ Ú Ð¦ÄÔÒÉÍËÏÀ RAID",
-"÷É Õ ÒÅÖÉͦ ÂÅÚÐÅÞÎÏÇÏ ÏÎÏ×ÌÅÎÎÑ ÔÁ ÎÁÍÁÇÁ¤ÔÅÓØ ÏÎÏ×ÉÔÉ ÔÁÂÌÉÃÀ ÂÅÚ ÏÐÅÒÁÔÏÒÁ WHERE, ÝÏ ×ÉËÏÒÉÓÔÏ×Õ¤ KEY ÓÔÏ×ÂÅÃØ",
-"ëÌÀÞ '%-.64s' ÎÅ ¦ÓÎÕ¤ × ÔÁÂÌÉæ '%-.64s'",
-"îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÔÁÂÌÉÃÀ",
-"÷ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕÅ %s",
-"÷ÁÍ ÎÅ ÄÏÚ×ÏÌÅÎÏ ×ÉËÏÎÕ×ÁÔÉ ÃÀ ËÏÍÁÎÄÕ × ÔÒÁÎÚÁËæ§",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ COMMIT",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ ROLLBACK",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ FLUSH_LOGS",
-"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ CHECKPOINT",
-"ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.64s' ËÏÒÉÓÔÕ×ÁÞ: '%-.32s' ÈÏÓÔ: `%-.64s' (%-.64s)",
-"ãÅÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ ¦ÎÁÒÎÕ ÐÅÒÅÄÁÞÕ ÔÁÂÌÉæ",
-"òÅÐ̦ËÁæÊÎÉÊ ÌÏÇ ÚÁËÒÉÔÏ, ÎÅ ÍÏÖÕ ×ÉËÏÎÁÔÉ RESET MASTER",
-"îÅ×ÄÁÌŠצÄÎÏ×ÌÅÎÎÑ ¦ÎÄÅËÓÁ ÐÅÒÅÄÁÎϧ ÔÁÂÌÉæ '%-.64s'",
-"ðÏÍÉÌËÁ ×¦Ä ÇÏÌÏ×ÎÏÇÏ: '%-.64s'",
-"íÅÒÅÖÅ×Á ÐÏÍÉÌËÁ ÞÉÔÁÎÎÑ ×¦Ä ÇÏÌÏ×ÎÏÇÏ",
-"íÅÒÅÖÅ×Á ÐÏÍÉÌËÁ ÚÁÐÉÓÕ ÄÏ ÇÏÌÏ×ÎÏÇÏ",
-"îÅ ÍÏÖÕ ÚÎÁÊÔÉ FULLTEXT ¦ÎÄÅËÓ, ÝÏ ×¦ÄÐÏצÄÁ¤ ÐÅÒÅ̦ËÕ ÓÔÏ×Âæ×",
-"îÅ ÍÏÖÕ ×ÉËÏÎÁÔÉ ÐÏÄÁÎÕ ËÏÍÁÎÄÕ ÔÏÍÕ, ÝÏ ÔÁÂÌÉÃÑ ÚÁÂÌÏËÏ×ÁÎÁ ÁÂÏ ×ÉËÏÎÕ¤ÔØÓÑ ÔÒÁÎÚÁËæÑ",
-"îÅצÄÏÍÁ ÓÉÓÔÅÍÎÁ ÚͦÎÎÁ '%-.64s'",
-"ôÁÂÌÉÃÀ '%-.64s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ §§ ÐÏÔÒ¦ÂÎÏ ×¦ÄÎÏ×ÉÔÉ",
-"ôÁÂÌÉÃÀ '%-.64s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ ÏÓÔÁÎΤ (Á×ÔÏÍÁÔÉÞÎÅ?) צÄÎÏ×ÌÅÎÎÑ ÎÅ ×ÄÁÌÏÓÑ",
-"úÁÓÔÅÒÅÖÅÎÎÑ: äÅÑ˦ ÎÅÔÒÁÎÚÁËæÊΦ ÚͦÎÉ ÔÁÂÌÉÃØ ÎÅ ÍÏÖÎÁ ÂÕÄÅ ÐÏ×ÅÒÎÕÔÉ",
-"ôÒÁÎÚÁËÃ¦Ñ Ú ÂÁÇÁÔØÍÁ ×ÉÒÁÚÁÍÉ ×ÉÍÁÇÁ¤ ¦ÌØÛÅ Î¦Ö 'max_binlog_cache_size' ÂÁÊÔ¦× ÄÌÑ ÚÂÅÒ¦ÇÁÎÎÑ. ú¦ÌØÛÔÅ ÃÀ ÚͦÎÎÕ mysqld ÔÁ ÓÐÒÏÂÕÊÔÅ ÚÎÏ×Õ",
-"ïÐÅÒÁÃ¦Ñ ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÎÁÎÁ Ú ÚÁÐÕÝÅÎÉÍ Ð¦ÄÌÅÇÌÉÍ, ÓÐÏÞÁÔËÕ ×ÉËÏÎÁÊÔÅ STOP SLAVE",
-"ïÐÅÒÁÃ¦Ñ ×ÉÍÁÇÁ¤ ÚÁÐÕÝÅÎÏÇÏ Ð¦ÄÌÅÇÌÏÇÏ, ÚËÏÎƦÇÕÒÕÊÔŠЦÄÌÅÇÌÏÇÏ ÔÁ ×ÉËÏÎÁÊÔÅ START SLAVE",
-"óÅÒ×ÅÒ ÎÅ ÚËÏÎƦÇÕÒÏ×ÁÎÏ ÑË Ð¦ÄÌÅÇÌÉÊ, ×ÉÐÒÁ×ÔÅ ÃÅ Õ ÆÁÊ̦ ËÏÎƦÇÕÒÁæ§ ÁÂÏ Ú CHANGE MASTER TO",
-"Could not initialize master info structure, more error messages can be found in the MySQL error log",
-"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ Ð¦ÄÌÅÇÌÕ Ç¦ÌËÕ, ÐÅÒÅצÒÔÅ ÓÉÓÔÅÍΦ ÒÅÓÕÒÓÉ",
-"ëÏÒÉÓÔÕ×ÁÞ %-.64s ×ÖÅ ÍÁ¤ ¦ÌØÛÅ Î¦Ö 'max_user_connections' ÁËÔÉ×ÎÉÈ Ú'¤ÄÎÁÎØ",
-"íÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÌÉÛÅ ×ÉÒÁÚÉ Ú¦ ÓÔÁÌÉÍÉ Õ SET",
-"úÁÔÒÉÍËÕ ÏÞ¦ËÕ×ÁÎÎÑ ÂÌÏËÕ×ÁÎÎÑ ×ÉÞÅÒÐÁÎÏ",
-"úÁÇÁÌØÎÁ ˦ÌØ˦ÓÔØ ÂÌÏËÕ×ÁÎØ ÐÅÒÅ×ÉÝÉÌÁ ÒÏÚÍ¦Ò ÂÌÏËÕ×ÁÎØ ÄÌÑ ÔÁÂÌÉæ",
-"ïÎÏ×ÉÔÉ ÂÌÏËÕ×ÁÎÎÑ ÎÅ ÍÏÖÌÉ×Ï ÎÁ ÐÒÏÔÑÚ¦ ÔÒÁÎÚÁËæ§ READ UNCOMMITTED",
-"DROP DATABASE ÎÅ ÄÏÚ×ÏÌÅÎÏ ÄÏËÉ Ç¦ÌËÁ ÐÅÒÅÂÕ×Á¤ Ð¦Ä ÚÁÇÁÌØÎÉÍ ÂÌÏËÕ×ÁÎÎÑÍ ÞÉÔÁÎÎÑ",
-"CREATE DATABASE ÎÅ ÄÏÚ×ÏÌÅÎÏ ÄÏËÉ Ç¦ÌËÁ ÐÅÒÅÂÕ×Á¤ Ð¦Ä ÚÁÇÁÌØÎÉÍ ÂÌÏËÕ×ÁÎÎÑÍ ÞÉÔÁÎÎÑ",
-"èÉÂÎÉÊ ÁÒÇÕÍÅÎÔ ÄÌÑ %s",
-"ëÏÒÉÓÔÕ×ÁÞÕ '%-.32s'@'%-.64s' ÎÅ ÄÏÚ×ÏÌÅÎÏ ÓÔ×ÏÒÀ×ÁÔÉ ÎÏ×ÉÈ ËÏÒÉÓÔÕ×ÁÞ¦×",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; try restarting transaction",
-"÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ FULLTEXT ¦ÎÄÅËÓ¦×",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Incorrect usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied; you need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a SESSION variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Incorrect argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Incorrect usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
-"Variable '%-.64s' is a %s variable",
-"Incorrect foreign key definition for '%-.64s': %s",
-"Key reference and table reference don't match",
-"ïÐÅÒÁÎÄ ÍÁ¤ ÓËÌÁÄÁÔÉÓÑ Ú %d ÓÔÏ×Âæ×",
-"ð¦ÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ¦ÌØÛ ÎiÖ 1 ÚÁÐÉÓ",
-"Unknown prepared statement handler (%.*s) given to %s",
-"Help database is corrupt or does not exist",
-"ãÉË̦ÞÎÅ ÐÏÓÉÌÁÎÎÑ ÎÁ ЦÄÚÁÐÉÔ",
-"ðÅÒÅÔ×ÏÒÅÎÎÑ ÓÔÏ×ÂÃÁ '%s' Ú %s Õ %s",
-"ðÏÓÉÌÁÎÎÑ '%-.64s' ÎÅ ÐiÄÔÒÉÍÕÅÔÓÑ (%s)",
-"Every derived table must have its own alias",
-"Select %u was ÓËÁÓÏ×ÁÎÏ ÐÒÉ ÏÐÔÉÍiÚÁÃii",
-"Table '%-.64s' from one of the SELECTs cannot be used in %-.32s",
-"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
-"All parts of a SPATIAL index must be NOT NULL",
-"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"Slave is already running",
-"Slave has already been stopped",
-"Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)",
-"ZLIB: Not enough memory",
-"ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)",
-"ZLIB: Input data corrupted",
-"%d line(s) were cut by GROUP_CONCAT()",
-"Row %ld doesn't contain data for all columns",
-"Row %ld was truncated; it contained more data than there were input columns",
-"Data truncated; NULL supplied to NOT NULL column '%s' at row %ld",
-"Data truncated; out of range for column '%s' at row %ld",
-"Data truncated for column '%s' at row %ld",
-"Using storage engine %s for table '%s'",
-"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
-"Can't drop one or more of the requested users",
-"Can't revoke all privileges, grant for one or more of the requested users",
-"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
-"Illegal mix of collations for operation '%s'",
-"Variable '%-.64s' is not a variable component (can't be used as XXXX.variable_name)",
-"Unknown collation: '%-.64s'",
-"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started",
-"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
-"óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.64s%s%-.64s%s%-.64s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d",
-"Incorrect parameter or combination of parameters for START SLAVE UNTIL",
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you are not safe in case of unexpected slave's mysqld restart",
-"SQL thread is not to be started so UNTIL options are ignored",
-"Incorrect index name '%-.100s'",
-"Incorrect catalog name '%-.100s'",
-"ëÅÛ ÚÁÐÉÔ¦× ÎÅÓÐÒÏÍÏÖÅÎ ×ÓÔÁÎÏ×ÉÔÉ ÒÏÚÍ¦Ò %lu, ÎÏ×ÉÊ ÒÏÚÍ¦Ò ËÅÛÁ ÚÁÐÉÔ¦× - %lu",
-"Column '%-.64s' cannot be part of FULLTEXT index",
-"Unknown key cache '%-.100s'",
-"MySQL is started in --skip-name-resolve mode. You need to restart it without this switch for this grant to work",
-"Unknown table engine '%s'",
-"'%s' is deprecated, use '%s' instead",
-"ôÁÂÌÉÃÑ %-.100s Õ %s ÎÅ ÍÏÖÅ ÏÎÏ×ÌÀ×ÁÔÉÓØ",
-"The '%s' feature was disabled; you need MySQL built with '%s' to have it working",
-"The MySQL server is running with the %s option so it cannot execute this statement",
-"Column '%-.100s' has duplicated value '%-.64s' in %s"
-"Truncated wrong %-.32s value: '%-.128s'"
-"Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
-"Invalid ON UPDATE clause for '%-.64s' column",
-"This command is not supported in the prepared statement protocol yet",
-"Got error %d '%-.100s' from %s",
-"Got temporary error %d '%-.100s' from %s",
-"Unknown or incorrect time zone: '%-.64s'",
-"Invalid TIMESTAMP value in column '%s' at row %ld",
-"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
-"Conflicting declarations: '%s%s' and '%s%s'"
diff --git a/sql/slave.cc b/sql/slave.cc
index 605f8289946..ebf87660a0e 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000-2003 MySQL AB
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@@ -75,7 +75,6 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
const char* table_name, bool overwrite);
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi);
-
/*
Find out which replications threads are running
@@ -160,7 +159,7 @@ int init_slave()
sql_print_error("Failed to allocate memory for the master info structure");
goto err;
}
-
+
if (init_master_info(active_mi,master_info_file,relay_log_info_file,
!master_host, (SLAVE_IO | SLAVE_SQL)))
{
@@ -219,6 +218,13 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
pos Position in relay log file
need_data_lock Set to 1 if this functions should do mutex locks
errmsg Store pointer to error message here
+ look_for_description_event
+ 1 if we should look for such an event. We only need
+ this when the SQL thread starts and opens an existing
+ relay log and has to execute it (possibly from an
+ offset >4); then we need to read the first event of
+ the relay log to be able to parse the events we have
+ to execute.
DESCRIPTION
- Close old open relay log files.
@@ -236,15 +242,35 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
ulonglong pos, bool need_data_lock,
- const char** errmsg)
+ const char** errmsg,
+ bool look_for_description_event)
{
DBUG_ENTER("init_relay_log_pos");
+ DBUG_PRINT("info", ("pos=%lu", pos));
*errmsg=0;
pthread_mutex_t *log_lock=rli->relay_log.get_log_lock();
if (need_data_lock)
pthread_mutex_lock(&rli->data_lock);
+
+ /*
+ Slave threads are not the only users of init_relay_log_pos(). CHANGE MASTER
+ is, too, and init_slave() too; these 2 functions allocate a description
+ event in init_relay_log_pos, which is not freed by the terminating SQL slave
+ thread as that thread is not started by these functions. So we have to free
+ the description_event here, in case, so that there is no memory leak in
+ running, say, CHANGE MASTER.
+ */
+ delete rli->relay_log.description_event_for_exec;
+ /*
+ By default the relay log is in binlog format 3 (4.0).
+ Even if format is 4, this will work enough to read the first event
+ (Format_desc) (remember that format 4 is just lenghtened compared to format
+ 3; format 3 is a prefix of format 4).
+ */
+ rli->relay_log.description_event_for_exec= new
+ Format_description_log_event(3);
pthread_mutex_lock(log_lock);
@@ -284,9 +310,8 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
In this case, we will use the same IO_CACHE pointer to
read data as the IO thread is using to write data.
*/
- rli->cur_log= rli->relay_log.get_log_file();
- if (my_b_tell(rli->cur_log) == 0 &&
- check_binlog_magic(rli->cur_log, errmsg))
+ my_b_seek((rli->cur_log=rli->relay_log.get_log_file()), (off_t)0);
+ if (check_binlog_magic(rli->cur_log,errmsg))
goto err;
rli->cur_log_old_open_count=rli->relay_log.get_open_count();
}
@@ -300,8 +325,85 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
goto err;
rli->cur_log = &rli->cache_buf;
}
- if (pos >= BIN_LOG_HEADER_SIZE)
+ /*
+ In all cases, check_binlog_magic() has been called so we're at offset 4 for
+ sure.
+ */
+ if (pos > BIN_LOG_HEADER_SIZE) /* If pos<=4, we stay at 4 */
+ {
+ Log_event* ev;
+ while (look_for_description_event)
+ {
+ /*
+ Read the possible Format_description_log_event; if position
+ was 4, no need, it will be read naturally.
+ */
+ DBUG_PRINT("info",("looking for a Format_description_log_event"));
+
+ if (my_b_tell(rli->cur_log) >= pos)
+ break;
+
+ /*
+ Because of we have rli->data_lock and log_lock, we can safely read an
+ event
+ */
+ if (!(ev=Log_event::read_log_event(rli->cur_log,0,
+ rli->relay_log.description_event_for_exec)))
+ {
+ DBUG_PRINT("info",("could not read event, rli->cur_log->error=%d",
+ rli->cur_log->error));
+ if (rli->cur_log->error) /* not EOF */
+ {
+ *errmsg= "I/O error reading event at position 4";
+ goto err;
+ }
+ break;
+ }
+ else if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
+ {
+ DBUG_PRINT("info",("found Format_description_log_event"));
+ delete rli->relay_log.description_event_for_exec;
+ rli->relay_log.description_event_for_exec= (Format_description_log_event*) ev;
+ /*
+ As ev was returned by read_log_event, it has passed is_valid(), so
+ my_malloc() in ctor worked, no need to check again.
+ */
+ /*
+ Ok, we found a Format_description event. But it is not sure that this
+ describes the whole relay log; indeed, one can have this sequence
+ (starting from position 4):
+ Format_desc (of slave)
+ Rotate (of master)
+ Format_desc (of master)
+ So the Format_desc which really describes the rest of the relay log
+ is the 3rd event (it can't be further than that, because we rotate
+ the relay log when we queue a Rotate event from the master).
+ But what describes the Rotate is the first Format_desc.
+ So what we do is:
+ go on searching for Format_description events, until you exceed the
+ position (argument 'pos') or until you find another event than Rotate
+ or Format_desc.
+ */
+ }
+ else
+ {
+ DBUG_PRINT("info",("found event of another type=%d",
+ ev->get_type_code()));
+ look_for_description_event= (ev->get_type_code() == ROTATE_EVENT);
+ delete ev;
+ }
+ }
my_b_seek(rli->cur_log,(off_t)pos);
+#ifndef DBUG_OFF
+ {
+ char llbuf1[22], llbuf2[22];
+ DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
+ llstr(my_b_tell(rli->cur_log),llbuf1),
+ llstr(rli->event_relay_log_pos,llbuf2)));
+ }
+#endif
+
+ }
err:
/*
@@ -316,13 +418,15 @@ err:
if (need_data_lock)
pthread_mutex_unlock(&rli->data_lock);
+ if (!rli->relay_log.description_event_for_exec->is_valid() && !*errmsg)
+ *errmsg= "Invalid Format_description log event; could be out of memory";
DBUG_RETURN ((*errmsg) ? 1 : 0);
}
/*
- Init functio to set up array for errors that should be skipped for slave
+ Init function to set up array for errors that should be skipped for slave
SYNOPSIS
init_slave_skip_errors()
@@ -361,16 +465,15 @@ void init_slave_skip_errors(const char* arg)
}
-void st_relay_log_info::inc_group_relay_log_pos(ulonglong val,
- ulonglong log_pos,
- bool skip_lock)
+void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
+ bool skip_lock)
{
if (!skip_lock)
pthread_mutex_lock(&data_lock);
- inc_event_relay_log_pos(val);
+ inc_event_relay_log_pos();
group_relay_log_pos= event_relay_log_pos;
strmake(group_relay_log_name,event_relay_log_name,
- sizeof(group_relay_log_name)-1);
+ sizeof(group_relay_log_name)-1);
notify_group_relay_log_name_update();
@@ -384,24 +487,31 @@ void st_relay_log_info::inc_group_relay_log_pos(ulonglong val,
not advance as it should on the non-transactional slave (it advances by
big leaps, whereas it should advance by small leaps).
*/
+ /*
+ In 4.x we used the event's len to compute the positions here. This is
+ wrong if the event was 3.23/4.0 and has been converted to 5.0, because
+ then the event's len is not what is was in the master's binlog, so this
+ will make a wrong group_master_log_pos (yes it's a bug in 3.23->4.0
+ replication: Exec_master_log_pos is wrong). Only way to solve this is to
+ have the original offset of the end of the event the relay log. This is
+ what we do in 5.0: log_pos has become "end_log_pos" (because the real use
+ of log_pos in 4.0 was to compute the end_log_pos; so better to store
+ end_log_pos instead of begin_log_pos.
+ If we had not done this fix here, the problem would also have appeared
+ when the slave and master are 5.0 but with different event length (for
+ example the slave is more recent than the master and features the event
+ UID). It would give false MASTER_POS_WAIT, false Exec_master_log_pos in
+ SHOW SLAVE STATUS, and so the user would do some CHANGE MASTER using this
+ value which would lead to badly broken replication.
+ Even the relay_log_pos will be corrupted in this case, because the len is
+ the relay log is not "val".
+ With the end_log_pos solution, we avoid computations involving lengthes.
+ */
+ DBUG_PRINT("info", ("log_pos: %lu group_master_log_pos: %lu",
+ (long) log_pos, (long) group_master_log_pos));
if (log_pos) // 3.23 binlogs don't have log_posx
{
-#if MYSQL_VERSION_ID < 50000
- /*
- If the event was converted from a 3.23 format, get_event_len() has
- grown by 6 bytes (at least for most events, except LOAD DATA INFILE
- which is already a big problem for 3.23->4.0 replication); 6 bytes is
- the difference between the header's size in 4.0 (LOG_EVENT_HEADER_LEN)
- and the header's size in 3.23 (OLD_HEADER_LEN). Note that using
- mi->old_format will not help if the I/O thread has not started yet.
- Yes this is a hack but it's just to make 3.23->4.x replication work;
- 3.23->5.0 replication is working much better.
- */
- group_master_log_pos= log_pos + val -
- (mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0);
-#else
- group_master_log_pos= log_pos+ val;
-#endif /* MYSQL_VERSION_ID < 5000 */
+ group_master_log_pos= log_pos;
}
pthread_cond_broadcast(&data_cond);
if (!skip_lock)
@@ -442,9 +552,9 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
/*
Even if rli->inited==0, we still try to empty rli->master_log_* variables.
Indeed, rli->inited==0 does not imply that they already are empty.
- It could be that slave's info initialization partly succeeded :
+ It could be that slave's info initialization partly succeeded :
for example if relay-log.info existed but *relay-bin*.*
- have been manually removed, init_relay_log_info reads the old
+ have been manually removed, init_relay_log_info reads the old
relay-log.info and fills rli->master_log_*, then init_relay_log_info
checks for the existence of the relay log, this fails and
init_relay_log_info leaves rli->inited to 0.
@@ -453,7 +563,7 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
MASTER, the callers of purge_relay_logs, will delete bogus *.info files
or replace them with correct files), however if the user does SHOW SLAVE
STATUS before START SLAVE, he will see old, confusing rli->master_log_*.
- In other words, we reinit rli->master_log_* for SHOW SLAVE STATUS
+ In other words, we reinit rli->master_log_* for SHOW SLAVE STATUS
to display fine in any case.
*/
@@ -482,13 +592,16 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
sizeof(rli->group_relay_log_name)-1);
strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(),
sizeof(rli->event_relay_log_name)-1);
- // Just first log with magic number and nothing else
- rli->log_space_total= BIN_LOG_HEADER_SIZE;
rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
- rli->relay_log.reset_bytes_written();
+ if (count_relay_log_space(rli))
+ {
+ *errmsg= "Error counting relay log space";
+ goto err;
+ }
if (!just_reset)
- error= init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos,
- 0 /* do not need data lock */, errmsg);
+ error= init_relay_log_pos(rli, rli->group_relay_log_name,
+ rli->group_relay_log_pos,
+ 0 /* do not need data lock */, errmsg, 0);
err:
#ifndef DBUG_OFF
@@ -548,24 +661,26 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
pthread_cond_t* term_cond,
volatile uint *slave_running)
{
+ DBUG_ENTER("terminate_slave_thread");
if (term_lock)
{
pthread_mutex_lock(term_lock);
if (!*slave_running)
{
pthread_mutex_unlock(term_lock);
- return ER_SLAVE_NOT_RUNNING;
+ DBUG_RETURN(ER_SLAVE_NOT_RUNNING);
}
}
DBUG_ASSERT(thd != 0);
+ THD_CHECK_SENTRY(thd);
/*
- Is is criticate to test if the slave is running. Otherwise, we might
+ Is is critical to test if the slave is running. Otherwise, we might
be referening freed memory trying to kick it
*/
- THD_CHECK_SENTRY(thd);
while (*slave_running) // Should always be true
{
+ DBUG_PRINT("loop", ("killing slave thread"));
KICK_SLAVE(thd);
/*
There is a small chance that slave thread might miss the first
@@ -577,7 +692,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
}
if (term_lock)
pthread_mutex_unlock(term_lock);
- return 0;
+ DBUG_RETURN(0);
}
@@ -636,7 +751,7 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
thd->exit_cond(old_msg);
pthread_mutex_lock(cond_lock); // re-acquire it as exit_cond() released
if (thd->killed)
- DBUG_RETURN(ER_SERVER_SHUTDOWN);
+ DBUG_RETURN(thd->killed_errno());
}
}
if (start_lock)
@@ -755,6 +870,11 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
second call will make the decision (because
all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)).
+ Thought which arose from a question of a big customer "I want to include
+ all tables like "abc.%" except the "%.EFG"". This can't be done now. If we
+ supported Perl regexps we could do it with this pattern: /^abc\.(?!EFG)/
+ (I could not find an equivalent in the regex library MySQL uses).
+
RETURN VALUES
0 should not be logged/replicated
1 should be logged/replicated
@@ -765,7 +885,7 @@ bool tables_ok(THD* thd, TABLE_LIST* tables)
bool some_tables_updating= 0;
DBUG_ENTER("tables_ok");
- for (; tables; tables = tables->next)
+ for (; tables; tables= tables->next_global)
{
char hash_key[2*NAME_LEN+2];
char *end;
@@ -776,7 +896,7 @@ bool tables_ok(THD* thd, TABLE_LIST* tables)
some_tables_updating= 1;
end= strmov(hash_key, tables->db ? tables->db : thd->db);
*end++= '.';
- len= (uint) (strmov(end, tables->real_name) - hash_key);
+ len= (uint) (strmov(end, tables->table_name) - hash_key);
if (do_table_inited) // if there are any do's
{
if (hash_search(&replicate_do_table, (byte*) hash_key, len))
@@ -1164,29 +1284,86 @@ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
return 1;
}
+/*
+ Note that we rely on the master's version (3.23, 4.0.14 etc) instead of
+ relying on the binlog's version. This is not perfect: imagine an upgrade
+ of the master without waiting that all slaves are in sync with the master;
+ then a slave could be fooled about the binlog's format. This is what happens
+ when people upgrade a 3.23 master to 4.0 without doing RESET MASTER: 4.0
+ slaves are fooled. So we do this only to distinguish between 3.23 and more
+ recent masters (it's too late to change things for 3.23).
+
+ RETURNS
+ 0 ok
+ 1 error
+*/
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi)
{
const char* errmsg= 0;
-
+
/*
- Note the following switch will bug when we have MySQL branch 30 ;)
+ Free old description_event_for_queue (that is needed if we are in
+ a reconnection).
*/
- switch (*mysql->server_version) {
- case '3':
- mi->old_format =
- (strncmp(mysql->server_version, "3.23.57", 7) < 0) /* < .57 */ ?
- BINLOG_FORMAT_323_LESS_57 :
- BINLOG_FORMAT_323_GEQ_57 ;
- break;
- case '4':
- mi->old_format = BINLOG_FORMAT_CURRENT;
- break;
- default:
- /* 5.0 is not supported */
- errmsg = "Master reported an unrecognized MySQL version. Note that 4.1 \
-slaves can't replicate a 5.0 or newer master.";
- break;
+ delete mi->rli.relay_log.description_event_for_queue;
+ mi->rli.relay_log.description_event_for_queue= 0;
+
+ if (!my_isdigit(&my_charset_bin,*mysql->server_version))
+ errmsg = "Master reported unrecognized MySQL version";
+ else
+ {
+ /*
+ Note the following switch will bug when we have MySQL branch 30 ;)
+ */
+ switch (*mysql->server_version)
+ {
+ case '0':
+ case '1':
+ case '2':
+ errmsg = "Master reported unrecognized MySQL version";
+ break;
+ case '3':
+ mi->rli.relay_log.description_event_for_queue= new
+ Format_description_log_event(1, mysql->server_version);
+ break;
+ case '4':
+ mi->rli.relay_log.description_event_for_queue= new
+ Format_description_log_event(3, mysql->server_version);
+ break;
+ default:
+ /*
+ Master is MySQL >=5.0. Give a default Format_desc event, so that we can
+ take the early steps (like tests for "is this a 3.23 master") which we
+ have to take before we receive the real master's Format_desc which will
+ override this one. Note that the Format_desc we create below is garbage
+ (it has the format of the *slave*); it's only good to help know if the
+ master is 3.23, 4.0, etc.
+ */
+ mi->rli.relay_log.description_event_for_queue= new
+ Format_description_log_event(4, mysql->server_version);
+ break;
+ }
+ }
+
+ /*
+ This does not mean that a 5.0 slave will be able to read a 6.0 master; but
+ as we don't know yet, we don't want to forbid this for now. If a 5.0 slave
+ can't read a 6.0 master, this will show up when the slave can't read some
+ events sent by the master, and there will be error messages.
+ */
+
+ if (errmsg)
+ {
+ sql_print_error(errmsg);
+ return 1;
+ }
+
+ /* as we are here, we tried to allocate the event */
+ if (!mi->rli.relay_log.description_event_for_queue)
+ {
+ sql_print_error("Slave I/O thread failed to create a default Format_description_log_event");
+ return 1;
}
/*
@@ -1244,12 +1421,20 @@ not always make sense; please check the manual before using it).";
values of these 2 are never used (new connections don't use them).
We don't test equality of global collation_database either as it's is
going to be deprecated (made read-only) in 4.1 very soon.
- We don't do it for <3.23.57 because masters <3.23.50 hang on
- SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50).
+ The test is only relevant if master < 5.0.3 (we'll test only if it's older
+ than the 5 branch; < 5.0.3 was alpha...), as >= 5.0.3 master stores
+ charset info in each binlog event.
+ We don't do it for 3.23 because masters <3.23.50 hang on
+ SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). So finally we
+ test only if master is 4.x.
*/
- if (mi->old_format == BINLOG_FORMAT_323_LESS_57)
+
+ /* redundant with rest of code but safer against later additions */
+ if (*mysql->server_version == '3')
goto err;
- if (!mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
+
+ if ((*mysql->server_version == '4') &&
+ !mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
(master_res= mysql_store_result(mysql)))
{
if ((master_row= mysql_fetch_row(master_res)) &&
@@ -1272,8 +1457,11 @@ be equal for replication to work";
such check will broke everything for them. (And now everything will
work for them because by default both their master and slave will have
'SYSTEM' time zone).
+ This check is only necessary for 4.x masters (and < 5.0.4 masters but
+ those were alpha).
*/
- if (!mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
+ if ((*mysql->server_version == '4') &&
+ !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
(master_res= mysql_store_result(mysql)))
{
if ((master_row= mysql_fetch_row(master_res)) &&
@@ -1324,7 +1512,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
packet_len= my_net_read(net); // read create table statement
if (packet_len == packet_error)
{
- send_error(thd, ER_MASTER_NET_READ);
+ my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0));
DBUG_RETURN(1);
}
if (net->read_pos[0] == 255) // error from master
@@ -1333,7 +1521,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
err_msg= (char*) net->read_pos + ((mysql->server_capabilities &
CLIENT_PROTOCOL_41) ?
3+SQLSTATE_LENGTH+1 : 3);
- net_printf(thd, ER_MASTER, err_msg);
+ my_error(ER_MASTER, MYF(0), err_msg);
DBUG_RETURN(1);
}
thd->command = COM_TABLE_DUMP;
@@ -1342,7 +1530,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
if (!(query = thd->strmake((char*) net->read_pos, packet_len)))
{
sql_print_error("create_table_from_dump: out of memory");
- net_printf(thd, ER_GET_ERRNO, "Out of memory");
+ my_message(ER_GET_ERRNO, "Out of memory", MYF(0));
DBUG_RETURN(1);
}
thd->query= query;
@@ -1351,12 +1539,11 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
bzero((char*) &tables,sizeof(tables));
tables.db = (char*)db;
- tables.alias= tables.real_name= (char*)table_name;
+ tables.alias= tables.table_name= (char*)table_name;
/* Drop the table if 'overwrite' is true */
if (overwrite && mysql_rm_table(thd,&tables,1,0)) /* drop if exists */
{
- send_error(thd);
sql_print_error("create_table_from_dump: failed to drop the table");
goto err;
}
@@ -1369,7 +1556,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
save_db = thd->db;
save_db_length= thd->db_length;
thd->db = (char*)db;
- DBUG_ASSERT(thd->db);
+ DBUG_ASSERT(thd->db != 0);
thd->db_length= strlen(thd->db);
mysql_parse(thd, thd->query, packet_len); // run create table
thd->db = save_db; // leave things the way the were before
@@ -1383,7 +1570,6 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
tables.lock_type = TL_WRITE;
if (!open_ltable(thd, &tables, TL_WRITE))
{
- send_error(thd,0,0); // Send error from open_ltable
sql_print_error("create_table_from_dump: could not open created table");
goto err;
}
@@ -1393,7 +1579,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
/* Copy the data file */
if (file->net_read_dump(net))
{
- net_printf(thd, ER_MASTER_NET_READ);
+ my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0));
sql_print_error("create_table_from_dump: failed in\
handler::net_read_dump()");
goto err;
@@ -1413,7 +1599,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
error=file->repair(thd,&check_opt) != 0;
thd->net.vio = save_vio;
if (error)
- net_printf(thd, ER_INDEX_REBUILD,tables.table->real_name);
+ my_error(ER_INDEX_REBUILD, MYF(0), tables.table->s->table_name);
err:
close_thread_tables(thd);
@@ -1436,12 +1622,11 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
{
if (!(mysql = mysql_init(NULL)))
{
- send_error(thd); // EOM
DBUG_RETURN(1);
}
if (connect_to_master(thd, mysql, mi))
{
- net_printf(thd, ER_CONNECT_TO_MASTER, mysql_error(mysql));
+ my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
mysql_close(mysql);
DBUG_RETURN(1);
}
@@ -1465,7 +1650,7 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
if (!called_connected)
mysql_close(mysql);
if (errmsg && thd->vio_ok())
- send_error(thd, error, errmsg);
+ my_message(error, errmsg, MYF(0));
DBUG_RETURN(test(error)); // Return 1 on error
}
@@ -1489,7 +1674,8 @@ void end_master_info(MASTER_INFO* mi)
}
-int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
+static int init_relay_log_info(RELAY_LOG_INFO* rli,
+ const char* info_fname)
{
char fname[FN_REFLEN+128];
int info_fd;
@@ -1497,7 +1683,7 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
int error = 0;
DBUG_ENTER("init_relay_log_info");
- if (rli->inited) // Set if this function called
+ if (rli->inited) // Set if this function called
DBUG_RETURN(0);
fn_format(fname, info_fname, mysql_data_home, "", 4+32);
pthread_mutex_lock(&rli->data_lock);
@@ -1508,23 +1694,10 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
rli->log_space_limit= relay_log_space_limit;
rli->log_space_total= 0;
- // TODO: make this work with multi-master
- if (!opt_relay_logname)
- {
- char tmp[FN_REFLEN];
- /*
- TODO: The following should be using fn_format(); We just need to
- first change fn_format() to cut the file name if it's too long.
- */
- strmake(tmp,glob_hostname,FN_REFLEN-5);
- strmov(strcend(tmp,'.'),"-relay-bin");
- opt_relay_logname=my_strdup(tmp,MYF(MY_WME));
- }
-
/*
The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE.
- Note that the I/O thread flushes it to disk after writing every event, in
- flush_master_info(mi, 1).
+ Note that the I/O thread flushes it to disk after writing every
+ event, in flush_master_info(mi, 1).
*/
/*
@@ -1536,16 +1709,25 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
switch to using max_binlog_size for the relay log) and update
rli->relay_log.max_size (and mysql_bin_log.max_size).
*/
-
- if (open_log(&rli->relay_log, glob_hostname, opt_relay_logname,
- "-relay-bin", opt_relaylog_index_name,
- LOG_BIN, 1 /* read_append cache */,
- 1 /* no auto events */,
- max_relay_log_size ? max_relay_log_size : max_binlog_size))
{
- pthread_mutex_unlock(&rli->data_lock);
- sql_print_error("Failed in open_log() called from init_relay_log_info()");
- DBUG_RETURN(1);
+ char buf[FN_REFLEN];
+ const char *ln;
+ ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin",
+ 1, buf);
+
+ /*
+ note, that if open() fails, we'll still have index file open
+ but a destructor will take care of that
+ */
+ if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln) ||
+ rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0,
+ (max_relay_log_size ? max_relay_log_size :
+ max_binlog_size), 1))
+ {
+ pthread_mutex_unlock(&rli->data_lock);
+ sql_print_error("Failed in open_log() called from init_relay_log_info()");
+ DBUG_RETURN(1);
+ }
}
/* if file does not exist */
@@ -1575,7 +1757,7 @@ file '%s', errno %d)", fname, my_errno);
/* Init relay log with first entry in the relay index file */
if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */,
- &msg))
+ &msg, 0))
{
sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)");
goto err;
@@ -1640,7 +1822,7 @@ Failed to open the existing relay log info file '%s' (errno %d)",
rli->group_relay_log_name,
rli->group_relay_log_pos,
0 /* no data lock*/,
- &msg))
+ &msg, 0))
{
char llbuf[22];
sql_print_error("Failed to open the relay log '%s' (relay_log_pos %s)",
@@ -1649,8 +1831,18 @@ Failed to open the existing relay log info file '%s' (errno %d)",
goto err;
}
}
- DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
- DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
+
+#ifndef DBUG_OFF
+ {
+ char llbuf1[22], llbuf2[22];
+ DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
+ llstr(my_b_tell(rli->cur_log),llbuf1),
+ llstr(rli->event_relay_log_pos,llbuf2)));
+ DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
+ DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
+ }
+#endif
+
/*
Now change the cache from READ to WRITE - must do this
before flush_relay_log_info
@@ -1798,9 +1990,9 @@ void clear_until_condition(RELAY_LOG_INFO* rli)
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
- const char* slave_info_fname,
- bool abort_if_no_master_info_file,
- int thread_mask)
+ const char* slave_info_fname,
+ bool abort_if_no_master_info_file,
+ int thread_mask)
{
int fd,error;
char fname[FN_REFLEN+128];
@@ -1814,7 +2006,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
last time. If this case pos_in_file would be set and we would
get a crash when trying to read the signature for the binary
relay log.
-
+
We only rewind the read position if we are starting the SQL
thread. The handle_slave_sql thread assumes that the read
position is at the beginning of the file, and will read the
@@ -1840,7 +2032,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
fd = mi->fd;
/* does master.info exist ? */
-
+
if (access(fname,F_OK))
{
if (abort_if_no_master_info_file)
@@ -1876,7 +2068,7 @@ file '%s')", fname);
{
if (fd >= 0)
reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0);
- else
+ else
{
if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
{
@@ -1896,52 +2088,52 @@ file '%s')", fname);
mi->fd = fd;
int port, connect_retry, master_log_pos, ssl= 0, lines;
char *first_non_digit;
-
+
/*
Starting from 4.1.x master.info has new format. Now its
- first line contains number of lines in file. By reading this
- number we will be always distinguish to which version our
- master.info corresponds to. We can't simply count lines in
+ first line contains number of lines in file. By reading this
+ number we will be always distinguish to which version our
+ master.info corresponds to. We can't simply count lines in
file since versions before 4.1.x could generate files with more
lines than needed.
- If first line doesn't contain a number or contain number less than
+ If first line doesn't contain a number or contain number less than
14 then such file is treated like file from pre 4.1.1 version.
- There is no ambiguity when reading an old master.info, as before
+ There is no ambiguity when reading an old master.info, as before
4.1.1, the first line contained the binlog's name, which is either
- empty or has an extension (contains a '.'), so can't be confused
+ empty or has an extension (contains a '.'), so can't be confused
with an integer.
- So we're just reading first line and trying to figure which version
+ So we're just reading first line and trying to figure which version
is this.
*/
-
- /*
- The first row is temporarily stored in mi->master_log_name,
- if it is line count and not binlog name (new format) it will be
+
+ /*
+ The first row is temporarily stored in mi->master_log_name,
+ if it is line count and not binlog name (new format) it will be
overwritten by the second row later.
*/
if (init_strvar_from_file(mi->master_log_name,
sizeof(mi->master_log_name), &mi->file,
""))
goto errwithmsg;
-
+
lines= strtoul(mi->master_log_name, &first_non_digit, 10);
- if (mi->master_log_name[0]!='\0' &&
+ if (mi->master_log_name[0]!='\0' &&
*first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
{ // Seems to be new format
- if (init_strvar_from_file(mi->master_log_name,
+ if (init_strvar_from_file(mi->master_log_name,
sizeof(mi->master_log_name), &mi->file, ""))
goto errwithmsg;
}
else
lines= 7;
-
+
if (init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
master_host) ||
init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
- master_user) ||
+ master_user) ||
init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
&mi->file, master_password) ||
init_intvar_from_file(&port, &mi->file, master_port) ||
@@ -1949,17 +2141,17 @@ file '%s')", fname);
master_connect_retry))
goto errwithmsg;
- /*
- If file has ssl part use it even if we have server without
- SSL support. But these option will be ignored later when
- slave will try connect to master, so in this case warning
+ /*
+ If file has ssl part use it even if we have server without
+ SSL support. But these option will be ignored later when
+ slave will try connect to master, so in this case warning
is printed.
*/
- if (lines >= LINES_IN_MASTER_INFO_WITH_SSL &&
+ if (lines >= LINES_IN_MASTER_INFO_WITH_SSL &&
(init_intvar_from_file(&ssl, &mi->file, master_ssl) ||
- init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
+ init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
&mi->file, master_ssl_ca) ||
- init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
+ init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
&mi->file, master_ssl_capath) ||
init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
&mi->file, master_ssl_cert) ||
@@ -1970,11 +2162,11 @@ file '%s')", fname);
goto errwithmsg;
#ifndef HAVE_OPENSSL
if (ssl)
- sql_print_error("SSL information in the master info file "
+ sql_print_warning("SSL information in the master info file "
"('%s') are ignored because this MySQL slave was compiled "
"without SSL support.", fname);
#endif /* HAVE_OPENSSL */
-
+
/*
This has to be handled here as init_intvar_from_file can't handle
my_off_t types
@@ -1994,15 +2186,15 @@ file '%s')", fname);
mi->inited = 1;
// now change cache READ -> WRITE - must do this before flush_master_info
- reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
+ reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1);
if ((error=test(flush_master_info(mi, 1))))
sql_print_error("Failed to flush master info file");
pthread_mutex_unlock(&mi->data_lock);
DBUG_RETURN(error);
-
+
errwithmsg:
sql_print_error("Error reading master configuration");
-
+
err:
if (fd >= 0)
{
@@ -2095,7 +2287,7 @@ void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a)
}
}
-int show_master_info(THD* thd, MASTER_INFO* mi)
+bool show_master_info(THD* thd, MASTER_INFO* mi)
{
// TODO: fix this for multi-master
List<Item> field_list;
@@ -2157,8 +2349,9 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
field_list.push_back(new Item_return_int("Seconds_Behind_Master", 10,
MYSQL_TYPE_LONGLONG));
- if (protocol->send_fields(&field_list, 1))
- DBUG_RETURN(-1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
if (mi->host[0])
{
@@ -2271,10 +2464,10 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
pthread_mutex_unlock(&mi->data_lock);
if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -2344,6 +2537,7 @@ st_relay_log_info::st_relay_log_info()
bzero((char*) &info_file, sizeof(info_file));
bzero((char*) &cache_buf, sizeof(cache_buf));
+ cached_charset_invalidate();
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST);
@@ -2364,6 +2558,7 @@ st_relay_log_info::~st_relay_log_info()
pthread_cond_destroy(&start_cond);
pthread_cond_destroy(&stop_cond);
pthread_cond_destroy(&log_space_cond);
+ relay_log.cleanup();
}
/*
@@ -2401,17 +2596,16 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
ulong init_abort_pos_wait;
int error=0;
struct timespec abstime; // for timeout checking
- set_timespec(abstime,timeout);
-
+ const char *msg;
DBUG_ENTER("wait_for_pos");
- DBUG_PRINT("enter",("group_master_log_name: '%s' pos: %lu timeout: %ld",
- group_master_log_name, (ulong) group_master_log_pos,
- (long) timeout));
+ DBUG_PRINT("enter",("log_name: '%s' log_pos: %lu timeout: %lu",
+ log_name->c_ptr(), (ulong) log_pos, (ulong) timeout));
+ set_timespec(abstime,timeout);
pthread_mutex_lock(&data_lock);
- const char *msg= thd->enter_cond(&data_cond, &data_lock,
- "Waiting for the slave SQL thread to "
- "advance position");
+ msg= thd->enter_cond(&data_cond, &data_lock,
+ "Waiting for the slave SQL thread to "
+ "advance position");
/*
This function will abort when it notices that some CHANGE MASTER or
RESET MASTER has changed the master info.
@@ -2468,6 +2662,12 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
bool pos_reached;
int cmp_result= 0;
+ DBUG_PRINT("info",
+ ("init_abort_pos_wait: %ld abort_pos_wait: %ld",
+ init_abort_pos_wait, abort_pos_wait));
+ DBUG_PRINT("info",("group_master_log_name: '%s' pos: %lu",
+ group_master_log_name, (ulong) group_master_log_pos));
+
/*
group_master_log_name can be "", if we are just after a fresh
replication start or after a CHANGE MASTER TO MASTER_HOST/PORT
@@ -2550,7 +2750,7 @@ err:
thd->exit_cond(msg);
DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \
improper_arguments: %d timed_out: %d",
- (int) thd->killed,
+ thd->killed_errno(),
(int) (init_abort_pos_wait != abort_pos_wait),
(int) slave_running,
(int) (error == -2),
@@ -2563,6 +2763,24 @@ improper_arguments: %d timed_out: %d",
DBUG_RETURN( error ? error : event_count );
}
+void set_slave_thread_options(THD* thd)
+{
+ thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) |
+ OPTION_AUTO_IS_NULL;
+ thd->variables.completion_type= 0;
+}
+
+void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli)
+{
+ thd->variables.character_set_client=
+ global_system_variables.character_set_client;
+ thd->variables.collation_connection=
+ global_system_variables.collation_connection;
+ thd->variables.collation_server=
+ global_system_variables.collation_server;
+ thd->update_charset();
+ rli->cached_charset_invalidate();
+}
/*
init_slave_thread()
@@ -2580,6 +2798,7 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
thd->master_access= ~0;
thd->priv_user = 0;
thd->slave_thread = 1;
+ set_slave_thread_options(thd);
/*
It's nonsense to constrain the slave threads with max_join_size; if a
query succeeded on master, we HAVE to execute it. So set
@@ -2759,8 +2978,7 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
*suppress_warnings= TRUE;
}
else
- sql_print_error("Error reading packet from server: %s (\
-server_errno=%d)",
+ sql_print_error("Error reading packet from server: %s ( server_errno=%d)",
mysql_error(mysql), mysql_errno(mysql));
return packet_error;
}
@@ -2768,8 +2986,8 @@ server_errno=%d)",
/* Check if eof packet */
if (len < 8 && mysql->net.read_pos[0] == 254)
{
- sql_print_error("Slave: received end packet from server, apparent\
- master shutdown: %s",
+ sql_print_information("Slave: received end packet from server, apparent "
+ "master shutdown: %s",
mysql_error(mysql));
return packet_error;
}
@@ -2841,13 +3059,14 @@ bool st_relay_log_info::is_until_satisfied()
if (until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_UNKNOWN)
{
- /*
- We have no cached comaprison results so we should compare log names
- and cache result
+ /*
+ We have no cached comparison results so we should compare log names
+ and cache result.
+ If we are after RESET SLAVE, and the SQL slave thread has not processed
+ any event yet, it could be that group_master_log_name is "". In that case,
+ just wait for more events (as there is no sensible comparison to do).
*/
- DBUG_ASSERT(*log_name || log_pos == 0);
-
if (*log_name)
{
const char *basename= log_name + dirname_length(log_name);
@@ -2883,21 +3102,39 @@ bool st_relay_log_info::is_until_satisfied()
}
+void st_relay_log_info::cached_charset_invalidate()
+{
+ /* Full of zeroes means uninitialized. */
+ bzero(cached_charset, sizeof(cached_charset));
+}
+
+
+bool st_relay_log_info::cached_charset_compare(char *charset)
+{
+ if (bcmp(cached_charset, charset, sizeof(cached_charset)))
+ {
+ memcpy(cached_charset, charset, sizeof(cached_charset));
+ return 1;
+ }
+ return 0;
+}
+
+
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
/*
We acquire this mutex since we need it for all operations except
- event execution. But we will release it in places where we will
+ event execution. But we will release it in places where we will
wait for something for example inside of next_event().
*/
pthread_mutex_lock(&rli->data_lock);
-
- if (rli->until_condition!=RELAY_LOG_INFO::UNTIL_NONE &&
- rli->is_until_satisfied())
+
+ if (rli->until_condition!=RELAY_LOG_INFO::UNTIL_NONE &&
+ rli->is_until_satisfied())
{
sql_print_error("Slave SQL thread stopped because it reached its"
" UNTIL position %ld", (long) rli->until_pos());
- /*
+ /*
Setting abort_slave flag because we do not want additional message about
error in query execution to be printed.
*/
@@ -2905,11 +3142,11 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
pthread_mutex_unlock(&rli->data_lock);
return 1;
}
-
+
Log_event * ev = next_event(rli);
-
+
DBUG_ASSERT(rli->sql_thd==thd);
-
+
if (sql_slave_killed(thd,rli))
{
pthread_mutex_unlock(&rli->data_lock);
@@ -2922,35 +3159,70 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
int exec_res;
/*
- Skip queries originating from this server or number of
- queries specified by the user in slave_skip_counter
- We can't however skip event's that has something to do with the
+ Queries originating from this server must be skipped.
+ Low-level events (Format_desc, Rotate, Stop) from this server
+ must also be skipped. But for those we don't want to modify
+ group_master_log_pos, because these events did not exist on the master.
+ Format_desc is not completely skipped.
+ Skip queries specified by the user in slave_skip_counter.
+ We can't however skip events that has something to do with the
log files themselves.
+ Filtering on own server id is extremely important, to ignore execution of
+ events created by the creation/rotation of the relay log (remember that
+ now the relay log starts with its Format_desc, has a Rotate etc).
*/
- if ((ev->server_id == (uint32) ::server_id && !replicate_same_server_id) ||
- (rli->slave_skip_counter && type_code != ROTATE_EVENT))
+ DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id));
+
+ if ((ev->server_id == (uint32) ::server_id &&
+ !replicate_same_server_id &&
+ type_code != FORMAT_DESCRIPTION_EVENT) ||
+ (rli->slave_skip_counter &&
+ type_code != ROTATE_EVENT && type_code != STOP_EVENT &&
+ type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT))
{
- /* TODO: I/O thread should not even log events with the same server id */
- rli->inc_group_relay_log_pos(ev->get_event_len(),
- type_code != STOP_EVENT ? ev->log_pos : LL(0),
- 1/* skip lock*/);
- flush_relay_log_info(rli);
+ DBUG_PRINT("info", ("event skipped"));
+ if (thd->options & OPTION_BEGIN)
+ rli->inc_event_relay_log_pos();
+ else
+ {
+ rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT ||
+ type_code == STOP_EVENT ||
+ type_code == FORMAT_DESCRIPTION_EVENT) ?
+ LL(0) : ev->log_pos,
+ 1/* skip lock*/);
+ flush_relay_log_info(rli);
+ }
/*
- Protect against common user error of setting the counter to 1
- instead of 2 while recovering from an failed auto-increment insert
+ Protect against common user error of setting the counter to 1
+ instead of 2 while recovering from an insert which used auto_increment,
+ rand or user var.
*/
- if (rli->slave_skip_counter &&
- !((type_code == INTVAR_EVENT || type_code == STOP_EVENT) &&
- rli->slave_skip_counter == 1))
+ if (rli->slave_skip_counter &&
+ !((type_code == INTVAR_EVENT ||
+ type_code == RAND_EVENT ||
+ type_code == USER_VAR_EVENT) &&
+ rli->slave_skip_counter == 1) &&
+ /*
+ The events from ourselves which have something to do with the relay
+ log itself must be skipped, true, but they mustn't decrement
+ rli->slave_skip_counter, because the user is supposed to not see
+ these events (they are not in the master's binlog) and if we
+ decremented, START SLAVE would for example decrement when it sees
+ the Rotate, so the event which the user probably wanted to skip
+ would not be skipped.
+ */
+ !(ev->server_id == (uint32) ::server_id &&
+ (type_code == ROTATE_EVENT || type_code == STOP_EVENT ||
+ type_code == START_EVENT_V3 || type_code == FORMAT_DESCRIPTION_EVENT)))
--rli->slave_skip_counter;
pthread_mutex_unlock(&rli->data_lock);
- delete ev;
- return 0; // avoid infinite update loops
- }
+ delete ev;
+ return 0; // avoid infinite update loops
+ }
pthread_mutex_unlock(&rli->data_lock);
-
+
thd->server_id = ev->server_id; // use the original server id for logging
thd->set_time(); // time the query
thd->lex->current_select= 0;
@@ -2959,7 +3231,16 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
ev->thd = thd;
exec_res = ev->exec_event(rli);
DBUG_ASSERT(rli->sql_thd==thd);
- delete ev;
+ /*
+ Format_description_log_event should not be deleted because it will be
+ used to read info about the relay log's format; it will be deleted when
+ the SQL thread does not need it, i.e. when this thread terminates.
+ */
+ if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
+ {
+ DBUG_PRINT("info", ("Deleting the event after it has been executed"));
+ delete ev;
+ }
if (slave_trans_retries)
{
if (exec_res &&
@@ -2988,7 +3269,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
else if (init_relay_log_pos(rli,
rli->group_relay_log_name,
rli->group_relay_log_pos,
- 1, &errmsg))
+ 1, &errmsg, 1))
sql_print_error("Error initializing relay log position: %s",
errmsg);
else
@@ -3039,17 +3320,17 @@ extern "C" pthread_handler_decl(handle_slave_io,arg)
{
THD *thd; // needs to be first for thread_stack
MYSQL *mysql;
- MASTER_INFO *mi = (MASTER_INFO*)arg;
+ MASTER_INFO *mi = (MASTER_INFO*)arg;
char llbuff[22];
uint retry_count;
-
+
// needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
my_thread_init();
DBUG_ENTER("handle_slave_io");
#ifndef DBUG_OFF
slave_begin:
-#endif
+#endif
DBUG_ASSERT(mi->inited);
mysql= NULL ;
retry_count= 0;
@@ -3058,10 +3339,10 @@ slave_begin:
/* Inform waiting threads that slave has started */
mi->slave_run_id++;
-#ifndef DBUG_OFF
+#ifndef DBUG_OFF
mi->events_till_abort = abort_slave_event_count;
-#endif
-
+#endif
+
thd= new THD; // note that contructor of THD uses DBUG_ !
THD_CHECK_SENTRY(thd);
@@ -3082,17 +3363,16 @@ slave_begin:
mi->abort_slave = 0;
pthread_mutex_unlock(&mi->run_lock);
pthread_cond_broadcast(&mi->start_cond);
-
+
DBUG_PRINT("master_info",("log_file_name: '%s' position: %s",
mi->master_log_name,
llstr(mi->master_log_pos,llbuff)));
-
+
if (!(mi->mysql = mysql = mysql_init(NULL)))
{
sql_print_error("Slave I/O thread: error in mysql_init()");
goto err;
}
-
thd->proc_info = "Connecting to master";
// we can get killed during safe_connect
@@ -3104,7 +3384,7 @@ slave_begin:
llstr(mi->master_log_pos,llbuff));
else
{
- sql_print_error("Slave I/O thread killed while connecting to master");
+ sql_print_information("Slave I/O thread killed while connecting to master");
goto err;
}
@@ -3116,7 +3396,8 @@ connected:
thd->proc_info = "Checking master version";
if (get_master_version_and_clock(mysql, mi))
goto err;
- if (!mi->old_format)
+
+ if (mi->rli.relay_log.description_event_for_queue->binlog_version > 1)
{
/*
Register ourselves with the master.
@@ -3127,22 +3408,22 @@ connected:
if (register_slave_on_master(mysql) || update_slave_list(mysql, mi))
goto err;
}
-
+
DBUG_PRINT("info",("Starting reading binary log from master"));
while (!io_slave_killed(thd,mi))
{
- bool suppress_warnings= 0;
+ bool suppress_warnings= 0;
thd->proc_info = "Requesting binlog dump";
if (request_dump(mysql, mi, &suppress_warnings))
{
sql_print_error("Failed on request_dump()");
if (io_slave_killed(thd,mi))
{
- sql_print_error("Slave I/O thread killed while requesting master \
+ sql_print_information("Slave I/O thread killed while requesting master \
dump");
goto err;
}
-
+
mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
thd->proc_info= "Waiting to reconnect after a failed binlog dump request";
#ifdef SIGNAL_WITH_VIO_CLOSE
@@ -3163,7 +3444,7 @@ dump");
}
if (io_slave_killed(thd,mi))
{
- sql_print_error("Slave I/O thread killed while retrying master \
+ sql_print_information("Slave I/O thread killed while retrying master \
dump");
goto err;
}
@@ -3176,7 +3457,7 @@ reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
if (safe_reconnect(thd, mysql, mi, suppress_warnings) ||
io_slave_killed(thd,mi))
{
- sql_print_error("Slave I/O thread killed during or \
+ sql_print_information("Slave I/O thread killed during or \
after reconnect");
goto err;
}
@@ -3186,22 +3467,22 @@ after reconnect");
while (!io_slave_killed(thd,mi))
{
- bool suppress_warnings= 0;
- /*
+ bool suppress_warnings= 0;
+ /*
We say "waiting" because read_event() will wait if there's nothing to
- read. But if there's something to read, it will not wait. The important
- thing is to not confuse users by saying "reading" whereas we're in fact
- receiving nothing.
+ read. But if there's something to read, it will not wait. The
+ important thing is to not confuse users by saying "reading" whereas
+ we're in fact receiving nothing.
*/
thd->proc_info = "Waiting for master to send event";
ulong event_len = read_event(mysql, mi, &suppress_warnings);
if (io_slave_killed(thd,mi))
{
if (global_system_variables.log_warnings)
- sql_print_error("Slave I/O thread killed while reading event");
+ sql_print_information("Slave I/O thread killed while reading event");
goto err;
}
-
+
if (event_len == packet_error)
{
uint mysql_error_number= mysql_errno(mysql);
@@ -3232,30 +3513,30 @@ max_allowed_packet",
goto err; // Don't retry forever
safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
(void*) mi);
- }
+ }
if (io_slave_killed(thd,mi))
{
if (global_system_variables.log_warnings)
- sql_print_error("Slave I/O thread killed while waiting to \
+ sql_print_information("Slave I/O thread killed while waiting to \
reconnect after a failed read");
goto err;
}
thd->proc_info = "Reconnecting after a failed master event read";
if (!suppress_warnings)
- sql_print_error("Slave I/O thread: Failed reading log event, \
+ sql_print_information("Slave I/O thread: Failed reading log event, \
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
llstr(mi->master_log_pos, llbuff));
if (safe_reconnect(thd, mysql, mi, suppress_warnings) ||
io_slave_killed(thd,mi))
{
if (global_system_variables.log_warnings)
- sql_print_error("Slave I/O thread killed during or after a \
+ sql_print_information("Slave I/O thread killed during or after a \
reconnect done to recover from failed read");
goto err;
}
goto connected;
} // if (event_len == packet_error)
-
+
retry_count=0; // ok event, reset retry counter
thd->proc_info = "Queueing master event to the relay log";
if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
@@ -3311,7 +3592,7 @@ log space");
// error = 0;
err:
// print the current replication position
- sql_print_error("Slave I/O thread exiting, read up to log '%s', position %s",
+ sql_print_information("Slave I/O thread exiting, read up to log '%s', position %s",
IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query = thd->db = 0; // extra safety
@@ -3326,6 +3607,9 @@ err:
pthread_mutex_lock(&mi->run_lock);
mi->slave_running = 0;
mi->io_thd = 0;
+ /* Forget the relay log's format */
+ delete mi->rli.relay_log.description_event_for_queue;
+ mi->rli.relay_log.description_event_for_queue= 0;
// TODO: make rpl_status part of MASTER_INFO
change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE);
mi->abort_slave = 0; // TODO: check if this is needed
@@ -3430,15 +3714,38 @@ slave_begin:
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
rli->group_relay_log_pos,
- 1 /*need data lock*/, &errmsg))
+ 1 /*need data lock*/, &errmsg,
+ 1 /*look for a description_event*/))
{
sql_print_error("Error initializing relay log position: %s",
errmsg);
goto err;
}
THD_CHECK_SENTRY(thd);
- DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
- DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
+#ifndef DBUG_OFF
+ {
+ char llbuf1[22], llbuf2[22];
+ DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
+ llstr(my_b_tell(rli->cur_log),llbuf1),
+ llstr(rli->event_relay_log_pos,llbuf2)));
+ DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
+ /*
+ Wonder if this is correct. I (Guilhem) wonder if my_b_tell() returns the
+ correct position when it's called just after my_b_seek() (the questionable
+ stuff is those "seek is done on next read" comments in the my_b_seek()
+ source code).
+ The crude reality is that this assertion randomly fails whereas
+ replication seems to work fine. And there is no easy explanation why it
+ fails (as we my_b_seek(rli->event_relay_log_pos) at the very end of
+ init_relay_log_pos() called above). Maybe the assertion would be
+ meaningful if we held rli->data_lock between the my_b_seek() and the
+ DBUG_ASSERT().
+ */
+#ifdef SHOULD_BE_CHECKED
+ DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
+#endif
+ }
+#endif
DBUG_ASSERT(rli->sql_thd == thd);
DBUG_PRINT("master_info",("log_file_name: %s position: %s",
@@ -3482,12 +3789,18 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
}
/* Thread stopped. Print the current replication position to the log */
- sql_print_information("Slave SQL thread exiting, replication stopped in log \
- '%s' at position %s", RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff));
+ sql_print_information("Slave SQL thread exiting, replication stopped in log "
+ "'%s' at position %s",
+ RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff));
err:
VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query = thd->db = 0; // extra safety
+ /*
+ Some extra safety, which should not been needed (normally, event deletion
+ should already have done these assignments (each event which sets these
+ variables is supposed to set them to 0 before terminating)).
+ */
+ thd->query= thd->db= thd->catalog= 0;
thd->query_length= thd->db_length= 0;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->proc_info = "Waiting for slave mutex on exit";
@@ -3497,16 +3810,16 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
/* When master_pos_wait() wakes up it will check this and terminate */
rli->slave_running= 0;
- /*
- Going out of the transaction. Necessary to mark it, in case the user
- restarts replication from a non-transactional statement (with CHANGE
- MASTER).
- */
+ /* Forget the relay log's format */
+ delete rli->relay_log.description_event_for_exec;
+ rli->relay_log.description_event_for_exec= 0;
/* Wake up master_pos_wait() */
pthread_mutex_unlock(&rli->data_lock);
DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions"));
pthread_cond_broadcast(&rli->data_cond);
rli->ignore_log_space_limit= 0; /* don't need any lock */
+ /* we die so won't remember charset - re-update them on next thread start */
+ rli->cached_charset_invalidate();
rli->save_temporary_tables = thd->temporary_tables;
/*
@@ -3599,7 +3912,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
if (unlikely(cev_not_written))
break;
Execute_load_log_event xev(thd,0,0);
- xev.log_pos = mi->master_log_pos;
+ xev.log_pos = cev->log_pos;
if (unlikely(mi->rli.relay_log.append(&xev)))
{
sql_print_error("Slave I/O: error writing Exec_load event to \
@@ -3613,7 +3926,6 @@ relay log");
{
cev->block = (char*)net->read_pos;
cev->block_len = num_bytes;
- cev->log_pos = mi->master_log_pos;
if (unlikely(mi->rli.relay_log.append(cev)))
{
sql_print_error("Slave I/O: error writing Create_file event to \
@@ -3627,7 +3939,7 @@ relay log");
{
aev.block = (char*)net->read_pos;
aev.block_len = num_bytes;
- aev.log_pos = mi->master_log_pos;
+ aev.log_pos = cev->log_pos;
if (unlikely(mi->rli.relay_log.append(&aev)))
{
sql_print_error("Slave I/O: error writing Append_block event to \
@@ -3655,6 +3967,7 @@ err:
DESCRIPTION
Updates the master info with the place in the next binary
log where we should start reading.
+ Rotate the relay log to avoid mixed-format relay logs.
NOTES
We assume we already locked mi->data_lock
@@ -3685,21 +3998,34 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
if (disconnect_slave_event_count)
events_till_disconnect++;
#endif
+
+ /*
+ If description_event_for_queue is format <4, there is conversion in the
+ relay log to the slave's format (4). And Rotate can mean upgrade or
+ nothing. If upgrade, it's to 5.0 or newer, so we will get a Format_desc, so
+ no need to reset description_event_for_queue now. And if it's nothing (same
+ master version as before), no need (still using the slave's format).
+ */
+ if (mi->rli.relay_log.description_event_for_queue->binlog_version >= 4)
+ {
+ delete mi->rli.relay_log.description_event_for_queue;
+ /* start from format 3 (MySQL 4.0) again */
+ mi->rli.relay_log.description_event_for_queue= new
+ Format_description_log_event(3);
+ }
+ /*
+ Rotate the relay log makes binlog format detection easier (at next slave
+ start or mysqlbinlog)
+ */
+ rotate_relay_log(mi); /* will take the right mutexes */
DBUG_RETURN(0);
}
-
/*
- queue_old_event()
-
- Writes a 3.23 event to the relay log.
-
- TODO:
- Test this code before release - it has to be tested on a separate
- setup with 3.23 master
+ Reads a 3.23 event and converts it to the slave's format. This code was
+ copied from MySQL 4.0.
*/
-
-static int queue_old_event(MASTER_INFO *mi, const char *buf,
+static int queue_binlog_ver_1_event(MASTER_INFO *mi, const char *buf,
ulong event_len)
{
const char *errmsg = 0;
@@ -3707,7 +4033,7 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
bool ignore_event= 0;
char *tmp_buf = 0;
RELAY_LOG_INFO *rli= &mi->rli;
- DBUG_ENTER("queue_old_event");
+ DBUG_ENTER("queue_binlog_ver_1_event");
/*
If we get Load event, we need to pass a non-reusable buffer
@@ -3739,7 +4065,7 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
connected to the master).
*/
Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
- 1 /*old format*/ );
+ mi->rli.relay_log.description_event_for_queue);
if (unlikely(!ev))
{
sql_print_error("Read invalid event from master: '%s',\
@@ -3749,7 +4075,7 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
DBUG_RETURN(1);
}
pthread_mutex_lock(&mi->data_lock);
- ev->log_pos = mi->master_log_pos;
+ ev->log_pos= mi->master_log_pos; /* 3.23 events don't contain log_pos */
switch (ev->get_type_code()) {
case STOP_EVENT:
ignore_event= 1;
@@ -3773,14 +4099,12 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
*/
{
/* We come here when and only when tmp_buf != 0 */
- DBUG_ASSERT(tmp_buf);
+ DBUG_ASSERT(tmp_buf != 0);
+ inc_pos=event_len;
+ ev->log_pos+= inc_pos;
int error = process_io_create_file(mi,(Create_file_log_event*)ev);
delete ev;
- /*
- We had incremented event_len, but now when it is used to calculate the
- position in the master's log, we must use the original value.
- */
- mi->master_log_pos += --event_len;
+ mi->master_log_pos += inc_pos;
DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
pthread_mutex_unlock(&mi->data_lock);
my_free((char*)tmp_buf, MYF(0));
@@ -3792,6 +4116,12 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
}
if (likely(!ignore_event))
{
+ if (ev->log_pos)
+ /*
+ Don't do it for fake Rotate events (see comment in
+ Log_event::Log_event(const char* buf...) in log_event.cc).
+ */
+ ev->log_pos+= event_len; /* make log_pos be the pos of the end of the event */
if (unlikely(rli->relay_log.append(ev)))
{
delete ev;
@@ -3807,10 +4137,98 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
DBUG_RETURN(0);
}
+/*
+ Reads a 4.0 event and converts it to the slave's format. This code was copied
+ from queue_binlog_ver_1_event(), with some affordable simplifications.
+*/
+static int queue_binlog_ver_3_event(MASTER_INFO *mi, const char *buf,
+ ulong event_len)
+{
+ const char *errmsg = 0;
+ ulong inc_pos;
+ char *tmp_buf = 0;
+ RELAY_LOG_INFO *rli= &mi->rli;
+ DBUG_ENTER("queue_binlog_ver_3_event");
+
+ /* read_log_event() will adjust log_pos to be end_log_pos */
+ Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
+ mi->rli.relay_log.description_event_for_queue);
+ if (unlikely(!ev))
+ {
+ sql_print_error("Read invalid event from master: '%s',\
+ master could be corrupt but a more likely cause of this is a bug",
+ errmsg);
+ my_free((char*) tmp_buf, MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_RETURN(1);
+ }
+ pthread_mutex_lock(&mi->data_lock);
+ switch (ev->get_type_code()) {
+ case STOP_EVENT:
+ goto err;
+ case ROTATE_EVENT:
+ if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
+ {
+ delete ev;
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_RETURN(1);
+ }
+ inc_pos= 0;
+ break;
+ default:
+ inc_pos= event_len;
+ break;
+ }
+ if (unlikely(rli->relay_log.append(ev)))
+ {
+ delete ev;
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_RETURN(1);
+ }
+ rli->relay_log.harvest_bytes_written(&rli->log_space_total);
+ delete ev;
+ mi->master_log_pos+= inc_pos;
+err:
+ DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_RETURN(0);
+}
+
+/*
+ queue_old_event()
+
+ Writes a 3.23 or 4.0 event to the relay log, after converting it to the 5.0
+ (exactly, slave's) format. To do the conversion, we create a 5.0 event from
+ the 3.23/4.0 bytes, then write this event to the relay log.
+
+ TODO:
+ Test this code before release - it has to be tested on a separate
+ setup with 3.23 master or 4.0 master
+*/
+
+static int queue_old_event(MASTER_INFO *mi, const char *buf,
+ ulong event_len)
+{
+ switch (mi->rli.relay_log.description_event_for_queue->binlog_version)
+ {
+ case 1:
+ return queue_binlog_ver_1_event(mi,buf,event_len);
+ case 3:
+ return queue_binlog_ver_3_event(mi,buf,event_len);
+ default: /* unsupported format; eg version 2 */
+ DBUG_PRINT("info",("unsupported binlog format %d in queue_old_event()",
+ mi->rli.relay_log.description_event_for_queue->binlog_version));
+ return 1;
+ }
+}
/*
queue_event()
+ If the event is 3.23/4.0, passes it to queue_old_event() which will convert
+ it. Otherwise, writes a 5.0 (or newer) event to the relay log. Then there is
+ no format conversion, it's pure read/write of bytes.
+ So a 5.0.0 slave's relay log can contain events in the slave's format or in
+ any >=5.0.0 format.
*/
int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
@@ -3820,7 +4238,8 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
RELAY_LOG_INFO *rli= &mi->rli;
DBUG_ENTER("queue_event");
- if (mi->old_format)
+ if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
+ buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
DBUG_RETURN(queue_old_event(mi,buf,event_len));
pthread_mutex_lock(&mi->data_lock);
@@ -3837,7 +4256,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
master server shutdown. The only thing this does is cleaning. But
cleaning is already done on a per-master-thread basis (as the master
server is shutting down cleanly, it has written all DROP TEMPORARY TABLE
- and DO RELEASE_LOCK; prepared statements' deletion are TODO).
+ prepared statements' deletion are TODO only when we binlog prep stmts).
We don't even increment mi->master_log_pos, because we may be just after
a Rotate event. Btw, in a few milliseconds we are going to have a Start
@@ -3847,7 +4266,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
goto err;
case ROTATE_EVENT:
{
- Rotate_log_event rev(buf,event_len,0);
+ Rotate_log_event rev(buf,event_len,mi->rli.relay_log.description_event_for_queue);
if (unlikely(process_io_rotate(mi,&rev)))
{
error= 1;
@@ -3860,6 +4279,42 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
inc_pos= 0;
break;
}
+ case FORMAT_DESCRIPTION_EVENT:
+ {
+ /*
+ Create an event, and save it (when we rotate the relay log, we will have
+ to write this event again).
+ */
+ /*
+ We are the only thread which reads/writes description_event_for_queue.
+ The relay_log struct does not move (though some members of it can
+ change), so we needn't any lock (no rli->data_lock, no log lock).
+ */
+ Format_description_log_event* tmp;
+ const char* errmsg;
+ if (!(tmp= (Format_description_log_event*)
+ Log_event::read_log_event(buf, event_len, &errmsg,
+ mi->rli.relay_log.description_event_for_queue)))
+ {
+ error= 2;
+ goto err;
+ }
+ delete mi->rli.relay_log.description_event_for_queue;
+ mi->rli.relay_log.description_event_for_queue= tmp;
+ /*
+ Though this does some conversion to the slave's format, this will
+ preserve the master's binlog format version, and number of event types.
+ */
+ /*
+ If the event was not requested by the slave (the slave did not ask for
+ it), i.e. has end_log_pos=0, we do not increment mi->master_log_pos
+ */
+ inc_pos= uint4korr(buf+LOG_POS_OFFSET) ? event_len : 0;
+ DBUG_PRINT("info",("binlog format is now %d",
+ mi->rli.relay_log.description_event_for_queue->binlog_version));
+
+ }
+ break;
default:
inc_pos= event_len;
break;
@@ -3886,23 +4341,32 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
We still want to increment, so that we won't re-read this event from the
master if the slave IO thread is now stopped/restarted (more efficient if
the events we are ignoring are big LOAD DATA INFILE).
+ But events which were generated by this slave and which do not exist in
+ the master's binlog (i.e. Format_desc, Rotate & Stop) should not increment
+ mi->master_log_pos.
*/
- mi->master_log_pos+= inc_pos;
+ if (buf[EVENT_TYPE_OFFSET]!=FORMAT_DESCRIPTION_EVENT &&
+ buf[EVENT_TYPE_OFFSET]!=ROTATE_EVENT &&
+ buf[EVENT_TYPE_OFFSET]!=STOP_EVENT)
+ mi->master_log_pos+= inc_pos;
DBUG_PRINT("info", ("master_log_pos: %d, event originating from the same server, ignored", (ulong) mi->master_log_pos));
}
else
{
/* write the event to the relay log */
- if (likely(!(error= rli->relay_log.appendv(buf,event_len,0))))
+ if (likely(!(rli->relay_log.appendv(buf,event_len,0))))
{
mi->master_log_pos+= inc_pos;
DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
}
+ else
+ error=3;
}
err:
pthread_mutex_unlock(&mi->data_lock);
+ DBUG_PRINT("info", ("error=%d", error));
DBUG_RETURN(error);
}
@@ -3927,6 +4391,7 @@ void end_relay_log_info(RELAY_LOG_INFO* rli)
}
rli->inited = 0;
rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
+ rli->relay_log.harvest_bytes_written(&rli->log_space_total);
/*
Delete the slave's temporary tables from memory.
In the future there will be other actions than this, to ensure persistance
@@ -4055,6 +4520,7 @@ replication resumed in log '%s' at position %s", mi->user,
thd->set_active_vio(mysql->net.vio);
#endif
}
+ mysql->reconnect= 1;
DBUG_PRINT("exit",("slave_was_killed: %d", slave_was_killed));
DBUG_RETURN(slave_was_killed);
}
@@ -4148,6 +4614,7 @@ static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
relay_log_pos Current log pos
pending Number of bytes already processed from the event
*/
+ rli->event_relay_log_pos= max(rli->event_relay_log_pos, BIN_LOG_HEADER_SIZE);
my_b_seek(cur_log,rli->event_relay_log_pos);
DBUG_RETURN(cur_log);
}
@@ -4206,28 +4673,40 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
hot_log=0; // Using old binary log
}
}
+
#ifndef DBUG_OFF
{
+ /* This is an assertion which sometimes fails, let's try to track it */
char llbuf1[22], llbuf2[22];
+ DBUG_PRINT("info", ("my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
+ llstr(my_b_tell(cur_log),llbuf1),
+ llstr(rli->event_relay_log_pos,llbuf2)));
DBUG_ASSERT(my_b_tell(cur_log) >= BIN_LOG_HEADER_SIZE);
- /*
- The next assertion sometimes (very rarely) fails, let's try to track
- it
- */
- DBUG_PRINT("info", ("\
-Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
- llstr(my_b_tell(cur_log),llbuf1),
- llstr(rli->group_relay_log_pos,llbuf2)));
- DBUG_ASSERT(my_b_tell(cur_log) == rli->event_relay_log_pos);
+ DBUG_ASSERT(my_b_tell(cur_log) == rli->event_relay_log_pos);
}
#endif
/*
Relay log is always in new format - if the master is 3.23, the
- I/O thread will convert the format for us
+ I/O thread will convert the format for us.
+ A problem: the description event may be in a previous relay log. So if
+ the slave has been shutdown meanwhile, we would have to look in old relay
+ logs, which may even have been deleted. So we need to write this
+ description event at the beginning of the relay log.
+ When the relay log is created when the I/O thread starts, easy: the
+ master will send the description event and we will queue it.
+ But if the relay log is created by new_file(): then the solution is:
+ MYSQL_LOG::open() will write the buffered description event.
*/
- if ((ev=Log_event::read_log_event(cur_log,0,(bool)0 /* new format */)))
+ if ((ev=Log_event::read_log_event(cur_log,0,
+ rli->relay_log.description_event_for_exec)))
+
{
DBUG_ASSERT(thd==rli->sql_thd);
+ /*
+ read it while we have a lock, to avoid a mutex lock in
+ inc_event_relay_log_pos()
+ */
+ rli->future_event_relay_log_pos= my_b_tell(cur_log);
if (hot_log)
pthread_mutex_unlock(log_lock);
DBUG_RETURN(ev);
@@ -4384,8 +4863,8 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
{
#ifdef EXTRA_DEBUG
if (global_system_variables.log_warnings)
- sql_print_error("next log '%s' is currently active",
- rli->linfo.log_file_name);
+ sql_print_information("next log '%s' is currently active",
+ rli->linfo.log_file_name);
#endif
rli->cur_log= cur_log= rli->relay_log.get_log_file();
rli->cur_log_old_open_count= rli->relay_log.get_open_count();
@@ -4414,8 +4893,8 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
*/
#ifdef EXTRA_DEBUG
if (global_system_variables.log_warnings)
- sql_print_error("next log '%s' is not active",
- rli->linfo.log_file_name);
+ sql_print_information("next log '%s' is not active",
+ rli->linfo.log_file_name);
#endif
// open_binlog() will check the magic header
if ((rli->cur_log_fd=open_binlog(cur_log,rli->linfo.log_file_name,
@@ -4441,7 +4920,11 @@ event(errno: %d cur_log->error: %d)",
}
}
if (!errmsg && global_system_variables.log_warnings)
- errmsg = "slave SQL thread was killed";
+ {
+ sql_print_information("Error reading relay log event: %s",
+ "slave SQL thread was killed");
+ DBUG_RETURN(0);
+ }
err:
if (errmsg)
@@ -4461,8 +4944,9 @@ void rotate_relay_log(MASTER_INFO* mi)
DBUG_ENTER("rotate_relay_log");
RELAY_LOG_INFO* rli= &mi->rli;
- lock_slave_threads(mi);
- pthread_mutex_lock(&rli->data_lock);
+ /* We don't lock rli->run_lock. This would lead to deadlocks. */
+ pthread_mutex_lock(&mi->run_lock);
+
/*
We need to test inited because otherwise, new_file() will attempt to lock
LOCK_log, which may not be inited (if we're not a slave).
@@ -4491,8 +4975,7 @@ void rotate_relay_log(MASTER_INFO* mi)
*/
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
end:
- pthread_mutex_unlock(&rli->data_lock);
- unlock_slave_threads(mi);
+ pthread_mutex_unlock(&mi->run_lock);
DBUG_VOID_RETURN;
}
diff --git a/sql/slave.h b/sql/slave.h
index 5a85e26d9ad..c41234ab2ed 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000-2003 MySQL AB
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@@ -93,11 +93,6 @@ extern my_bool opt_log_slave_updates;
extern ulonglong relay_log_space_limit;
struct st_master_info;
-enum enum_binlog_formats {
- BINLOG_FORMAT_CURRENT=0, /* 0 is important for easy 'if (mi->old_format)' */
- BINLOG_FORMAT_323_LESS_57,
- BINLOG_FORMAT_323_GEQ_57 };
-
/*
3 possible values for MASTER_INFO::slave_running and
RELAY_LOG_INFO::slave_running.
@@ -214,6 +209,8 @@ typedef struct st_relay_log_info
ulonglong group_relay_log_pos;
char event_relay_log_name[FN_REFLEN];
ulonglong event_relay_log_pos;
+ ulonglong future_event_relay_log_pos;
+
/*
Original log name and position of the group we're currently executing
(whose coordinates are group_relay_log_name/pos in the relay log)
@@ -295,6 +292,7 @@ typedef struct st_relay_log_info
UNTIL_LOG_NAMES_CMP_EQUAL= 0, UNTIL_LOG_NAMES_CMP_GREATER= 1
} until_log_names_cmp_result;
+ char cached_charset[6];
/*
trans_retries varies between 0 to slave_transaction_retries and counts how
many times the slave has retried the present transaction; gets reset to 0
@@ -327,12 +325,14 @@ typedef struct st_relay_log_info
until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_UNKNOWN;
}
- inline void inc_event_relay_log_pos(ulonglong val)
+ inline void inc_event_relay_log_pos()
{
- event_relay_log_pos+= val;
+ event_relay_log_pos= future_event_relay_log_pos;
}
- void inc_group_relay_log_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0);
+ void inc_group_relay_log_pos(ulonglong log_pos,
+ bool skip_lock=0);
+
int wait_for_pos(THD* thd, String* log_name, longlong log_pos,
longlong timeout);
void close_temporary_tables();
@@ -344,6 +344,14 @@ typedef struct st_relay_log_info
return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos :
group_relay_log_pos);
}
+ /*
+ Last charset (6 bytes) seen by slave SQL thread is cached here; it helps
+ the thread save 3 get_charset() per Query_log_event if the charset is not
+ changing from event to event (common situation).
+ When the 6 bytes are equal to 0 is used to mean "cache is invalidated".
+ */
+ void cached_charset_invalidate();
+ bool cached_charset_compare(char *charset);
} RELAY_LOG_INFO;
@@ -392,11 +400,11 @@ typedef struct st_master_info
my_bool ssl; // enables use of SSL connection if true
char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN];
char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN];
-
+
my_off_t master_log_pos;
File fd; // we keep the file open, so we need to remember the file pointer
IO_CACHE file;
-
+
pthread_mutex_t data_lock,run_lock;
pthread_cond_t data_cond,start_cond,stop_cond;
THD *io_thd;
@@ -409,11 +417,10 @@ typedef struct st_master_info
int events_till_abort;
#endif
bool inited;
- enum enum_binlog_formats old_format;
volatile bool abort_slave;
volatile uint slave_running;
volatile ulong slave_run_id;
- /*
+ /*
The difference in seconds between the clock of the master and the clock of
the slave (second - first). It must be signed as it may be <0 or >0.
clock_diff_with_master is computed when the I/O thread starts; for this the
@@ -422,16 +429,16 @@ typedef struct st_master_info
clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master
*/
- long clock_diff_with_master;
-
+ long clock_diff_with_master;
+
st_master_info()
- :ssl(0), fd(-1), io_thd(0), inited(0), old_format(BINLOG_FORMAT_CURRENT),
+ :ssl(0), fd(-1), io_thd(0), inited(0),
abort_slave(0),slave_running(0), slave_run_id(0)
{
host[0] = 0; user[0] = 0; password[0] = 0;
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
ssl_cipher[0]= 0; ssl_key[0]= 0;
-
+
bzero((char*) &file, sizeof(file));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
@@ -518,8 +525,8 @@ int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
void table_rule_ent_hash_to_str(String* s, HASH* h);
void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a);
-int show_master_info(THD* thd, MASTER_INFO* mi);
-int show_binlog_info(THD* thd);
+bool show_master_info(THD* thd, MASTER_INFO* mi);
+bool show_binlog_info(THD* thd);
/* See if the query uses any tables that should not be replicated */
bool tables_ok(THD* thd, TABLE_LIST* tables);
@@ -551,16 +558,18 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
bool abort_if_no_master_info_file,
int thread_mask);
void end_master_info(MASTER_INFO* mi);
-int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname);
void end_relay_log_info(RELAY_LOG_INFO* rli);
void lock_slave_threads(MASTER_INFO* mi);
void unlock_slave_threads(MASTER_INFO* mi);
void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse);
int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,ulonglong pos,
- bool need_data_lock, const char** errmsg);
+ bool need_data_lock, const char** errmsg,
+ bool look_for_description_event);
int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
const char** errmsg);
+void set_slave_thread_options(THD* thd);
+void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli);
void rotate_relay_log(MASTER_INFO* mi);
extern "C" pthread_handler_decl(handle_slave_io,arg);
diff --git a/sql/sp.cc b/sql/sp.cc
new file mode 100644
index 00000000000..1956f32f2c6
--- /dev/null
+++ b/sql/sp.cc
@@ -0,0 +1,1378 @@
+/* Copyright (C) 2002 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.h"
+#include "sp_head.h"
+#include "sp_cache.h"
+
+static bool
+create_string(THD *thd, String *buf,
+ int sp_type,
+ sp_name *name,
+ const char *params, ulong paramslen,
+ const char *returns, ulong returnslen,
+ const char *body, ulong bodylen,
+ st_sp_chistics *chistics);
+
+/*
+ *
+ * DB storage of Stored PROCEDUREs and FUNCTIONs
+ *
+ */
+
+enum
+{
+ MYSQL_PROC_FIELD_DB = 0,
+ MYSQL_PROC_FIELD_NAME,
+ MYSQL_PROC_FIELD_TYPE,
+ MYSQL_PROC_FIELD_SPECIFIC_NAME,
+ MYSQL_PROC_FIELD_LANGUAGE,
+ MYSQL_PROC_FIELD_ACCESS,
+ MYSQL_PROC_FIELD_DETERMINISTIC,
+ MYSQL_PROC_FIELD_SECURITY_TYPE,
+ MYSQL_PROC_FIELD_PARAM_LIST,
+ MYSQL_PROC_FIELD_RETURNS,
+ MYSQL_PROC_FIELD_BODY,
+ MYSQL_PROC_FIELD_DEFINER,
+ MYSQL_PROC_FIELD_CREATED,
+ MYSQL_PROC_FIELD_MODIFIED,
+ MYSQL_PROC_FIELD_SQL_MODE,
+ MYSQL_PROC_FIELD_COMMENT,
+ MYSQL_PROC_FIELD_COUNT
+};
+
+bool mysql_proc_table_exists= 1;
+
+/* *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)
+{
+ 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));
+
+ /*
+ 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 (thd->lex->proc_table)
+ table= thd->lex->proc_table->table;
+ else
+ {
+ 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)
+ *opened= FALSE;
+ else
+ {
+ 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)))
+ {
+ *tablep= NULL;
+ /*
+ 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;
+ }
+ mysql_proc_table_exists= 1;
+
+ /*
+ Create key to find row. We have to use field->store() to be able to
+ handle VARCHAR and CHAR fields.
+ Assumption here is that the three first fields in the table are
+ 'db', 'name' and 'type' and the first key is the primary key over the
+ same fields.
+ */
+ 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);
+ table->field[2]->store((longlong) type);
+ key_copy(key, table->record[0], table->key_info,
+ table->key_info->key_length);
+
+ if (table->file->index_read_idx(table->record[0], 0,
+ key, table->key_info->key_length,
+ HA_READ_KEY_EXACT))
+ {
+ *tablep= NULL;
+ DBUG_RETURN(SP_KEY_NOT_FOUND);
+ }
+ *tablep= table;
+
+ DBUG_RETURN(SP_OK);
+}
+
+
+static int
+db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
+{
+ extern int yyparse(void *thd);
+ TABLE *table;
+ const char *params, *returns, *body;
+ int ret;
+ bool opened;
+ const char *definer;
+ longlong created;
+ longlong modified;
+ st_sp_chistics chistics;
+ char *ptr;
+ uint length;
+ char buff[65];
+ String str(buff, sizeof(buff), &my_charset_bin);
+ ulong sql_mode;
+ DBUG_ENTER("db_find_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_READ, &table, &opened);
+ if (ret != SP_OK)
+ goto done;
+
+ if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+
+ bzero((char *)&chistics, sizeof(chistics));
+ if ((ptr= get_field(thd->mem_root,
+ table->field[MYSQL_PROC_FIELD_ACCESS])) == NULL)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+ switch (ptr[0]) {
+ case 'N':
+ chistics.daccess= SP_NO_SQL;
+ break;
+ case 'C':
+ chistics.daccess= SP_CONTAINS_SQL;
+ break;
+ case 'R':
+ chistics.daccess= SP_READS_SQL_DATA;
+ break;
+ case 'M':
+ chistics.daccess= SP_MODIFIES_SQL_DATA;
+ break;
+ default:
+ chistics.daccess= SP_CONTAINS_SQL;
+ }
+
+ if ((ptr= get_field(thd->mem_root,
+ table->field[MYSQL_PROC_FIELD_DETERMINISTIC])) == NULL)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+ chistics.detistic= (ptr[0] == 'N' ? FALSE : TRUE);
+
+ if ((ptr= get_field(thd->mem_root,
+ table->field[MYSQL_PROC_FIELD_SECURITY_TYPE])) == NULL)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+ chistics.suid= (ptr[0] == 'I' ? SP_IS_NOT_SUID : SP_IS_SUID);
+
+ if ((params= get_field(thd->mem_root,
+ table->field[MYSQL_PROC_FIELD_PARAM_LIST])) == NULL)
+ {
+ params= "";
+ }
+
+ if (type == TYPE_ENUM_PROCEDURE)
+ returns= "";
+ else if ((returns= get_field(thd->mem_root,
+ table->field[MYSQL_PROC_FIELD_RETURNS])) == NULL)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+
+ if ((body= get_field(thd->mem_root,
+ table->field[MYSQL_PROC_FIELD_BODY])) == NULL)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+
+ // Get additional information
+ if ((definer= get_field(thd->mem_root,
+ table->field[MYSQL_PROC_FIELD_DEFINER])) == NULL)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+
+ modified= table->field[MYSQL_PROC_FIELD_MODIFIED]->val_int();
+ created= table->field[MYSQL_PROC_FIELD_CREATED]->val_int();
+
+ sql_mode= (ulong) table->field[MYSQL_PROC_FIELD_SQL_MODE]->val_int();
+
+ table->field[MYSQL_PROC_FIELD_COMMENT]->val_str(&str, &str);
+
+ ptr= 0;
+ if ((length= str.length()))
+ ptr= thd->strmake(str.ptr(), length);
+ chistics.comment.str= ptr;
+ chistics.comment.length= length;
+
+ if (opened)
+ {
+ opened= FALSE;
+ close_thread_tables(thd, 0, 1);
+ }
+
+ {
+ String defstr;
+ LEX *oldlex= thd->lex;
+ char olddb[128];
+ bool dbchanged;
+ enum enum_sql_command oldcmd= thd->lex->sql_command;
+ ulong old_sql_mode= thd->variables.sql_mode;
+ ha_rows select_limit= thd->variables.select_limit;
+
+ thd->variables.sql_mode= sql_mode;
+ thd->variables.select_limit= HA_POS_ERROR;
+
+ defstr.set_charset(system_charset_info);
+ if (!create_string(thd, &defstr,
+ type,
+ name,
+ params, strlen(params),
+ returns, strlen(returns),
+ body, strlen(body),
+ &chistics))
+ {
+ ret= SP_INTERNAL_ERROR;
+ goto done;
+ }
+
+ dbchanged= FALSE;
+ if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb),
+ 1, &dbchanged)))
+ goto done;
+
+ {
+ /* This is something of a kludge. We need to initialize some fields
+ * in thd->lex (the unit and master stuff), and the easiest way to
+ * do it is, is to call mysql_init_query(), but this unfortunately
+ * resets teh value_list where we keep the CALL parameters. So we
+ * copy the list and then restore it. (... and found_semicolon too).
+ */
+ List<Item> tmpvals= thd->lex->value_list;
+ char *tmpfsc= thd->lex->found_semicolon;
+
+ lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length());
+ thd->lex->value_list= tmpvals;
+ thd->lex->found_semicolon= tmpfsc;
+ }
+
+ if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
+ {
+ LEX *newlex= thd->lex;
+ sp_head *sp= newlex->sphead;
+
+ if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
+ goto done;
+ if (sp)
+ {
+ delete sp;
+ newlex->sphead= NULL;
+ }
+ ret= SP_PARSE_ERROR;
+ }
+ else
+ {
+ if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
+ goto done;
+ *sphp= thd->lex->sphead;
+ (*sphp)->set_info((char *)definer, (uint)strlen(definer),
+ created, modified, &chistics, sql_mode);
+ (*sphp)->optimize();
+ }
+ thd->lex->sql_command= oldcmd;
+ thd->variables.sql_mode= old_sql_mode;
+ thd->variables.select_limit= select_limit;
+ }
+
+ done:
+
+ if (opened)
+ close_thread_tables(thd);
+ DBUG_RETURN(ret);
+}
+
+
+static void
+sp_returns_type(THD *thd, String &result, sp_head *sp)
+{
+ TABLE table;
+ Field *field;
+ bzero(&table, sizeof(table));
+ table.in_use= thd;
+ table.s = &table.share_not_to_be_used;
+ field= sp->make_field(0, 0, &table);
+ field->sql_type(result);
+ delete field;
+}
+
+static int
+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;
+ DBUG_ENTER("db_create_routine");
+ DBUG_PRINT("enter", ("type: %d name: %*s",type,sp->m_name.length,sp->m_name.str));
+
+ dbchanged= FALSE;
+ if ((ret= sp_use_new_db(thd, sp->m_db.str, olddb, sizeof(olddb),
+ 0, &dbchanged)))
+ {
+ ret= SP_NO_DB_ERROR;
+ 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)))
+ ret= SP_OPEN_TABLE_FAILED;
+ else
+ {
+ restore_record(table, s->default_values); // Get default values for fields
+ strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
+
+ if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+ table->field[MYSQL_PROC_FIELD_DB]->
+ store(sp->m_db.str, sp->m_db.length, system_charset_info);
+ table->field[MYSQL_PROC_FIELD_NAME]->
+ store(sp->m_name.str, sp->m_name.length, system_charset_info);
+ table->field[MYSQL_PROC_FIELD_TYPE]->
+ store((longlong)type);
+ table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]->
+ store(sp->m_name.str, sp->m_name.length, system_charset_info);
+ if (sp->m_chistics->daccess != SP_DEFAULT_ACCESS)
+ table->field[MYSQL_PROC_FIELD_ACCESS]->
+ store((longlong)sp->m_chistics->daccess);
+ table->field[MYSQL_PROC_FIELD_DETERMINISTIC]->
+ store((longlong)(sp->m_chistics->detistic ? 1 : 2));
+ if (sp->m_chistics->suid != SP_IS_DEFAULT_SUID)
+ table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
+ store((longlong)sp->m_chistics->suid);
+ table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
+ store(sp->m_params.str, sp->m_params.length, system_charset_info);
+ if (sp->m_type == TYPE_ENUM_FUNCTION)
+ {
+ String retstr(64);
+ sp_returns_type(thd, retstr, sp);
+ table->field[MYSQL_PROC_FIELD_RETURNS]->
+ store(retstr.ptr(), retstr.length(), system_charset_info);
+ }
+ table->field[MYSQL_PROC_FIELD_BODY]->
+ store(sp->m_body.str, sp->m_body.length, system_charset_info);
+ table->field[MYSQL_PROC_FIELD_DEFINER]->
+ store(definer, (uint)strlen(definer), system_charset_info);
+ ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time();
+ ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
+ table->field[MYSQL_PROC_FIELD_SQL_MODE]->
+ store((longlong)thd->variables.sql_mode);
+ if (sp->m_chistics->comment.str)
+ table->field[MYSQL_PROC_FIELD_COMMENT]->
+ store(sp->m_chistics->comment.str, sp->m_chistics->comment.length,
+ system_charset_info);
+
+ ret= SP_OK;
+ if (table->file->write_row(table->record[0]))
+ ret= SP_WRITE_ROW_FAILED;
+ }
+
+done:
+ close_thread_tables(thd);
+ if (dbchanged)
+ (void)sp_change_db(thd, olddb, 1);
+ DBUG_RETURN(ret);
+}
+
+
+static int
+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->file->delete_row(table->record[0]))
+ ret= SP_DELETE_ROW_FAILED;
+ }
+
+ if (opened)
+ close_thread_tables(thd);
+ DBUG_RETURN(ret);
+}
+
+
+static int
+db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
+{
+ TABLE *table;
+ int ret;
+ bool opened;
+ DBUG_ENTER("db_update_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)
+ {
+ store_record(table,record[1]);
+ table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+ ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
+ if (chistics->suid != SP_IS_DEFAULT_SUID)
+ table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
+ store((longlong)chistics->suid);
+ if (chistics->daccess != SP_DEFAULT_ACCESS)
+ table->field[MYSQL_PROC_FIELD_ACCESS]->
+ store((longlong)chistics->daccess);
+ if (chistics->comment.str)
+ table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment.str,
+ chistics->comment.length,
+ system_charset_info);
+ if ((table->file->update_row(table->record[1],table->record[0])))
+ ret= SP_WRITE_ROW_FAILED;
+ }
+ if (opened)
+ close_thread_tables(thd);
+ DBUG_RETURN(ret);
+}
+
+
+struct st_used_field
+{
+ const char *field_name;
+ uint field_length;
+ enum enum_field_types field_type;
+ Field *field;
+};
+
+static struct st_used_field init_fields[]=
+{
+ { "Db", NAME_LEN, MYSQL_TYPE_STRING, 0},
+ { "Name", NAME_LEN, MYSQL_TYPE_STRING, 0},
+ { "Type", 9, MYSQL_TYPE_STRING, 0},
+ { "Definer", 77, MYSQL_TYPE_STRING, 0},
+ { "Modified", 0, MYSQL_TYPE_TIMESTAMP, 0},
+ { "Created", 0, MYSQL_TYPE_TIMESTAMP, 0},
+ { "Security_type", 1, MYSQL_TYPE_STRING, 0},
+ { "Comment", NAME_LEN, MYSQL_TYPE_STRING, 0},
+ { 0, 0, MYSQL_TYPE_STRING, 0}
+};
+
+
+static int
+print_field_values(THD *thd, TABLE *table,
+ struct st_used_field *used_fields,
+ int type, const char *wild)
+{
+ Protocol *protocol= thd->protocol;
+
+ if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type)
+ {
+ String db_string;
+ String name_string;
+ struct st_used_field *used_field= used_fields;
+
+ if (get_field(thd->mem_root, used_field->field, &db_string))
+ db_string.set_ascii("", 0);
+ used_field+= 1;
+ get_field(thd->mem_root, used_field->field, &name_string);
+
+ if (!wild || !wild[0] || !wild_compare(name_string.ptr(), wild, 0))
+ {
+ protocol->prepare_for_resend();
+ protocol->store(&db_string);
+ protocol->store(&name_string);
+ for (used_field++;
+ used_field->field_name;
+ used_field++)
+ {
+ switch (used_field->field_type) {
+ case MYSQL_TYPE_TIMESTAMP:
+ {
+ TIME tmp_time;
+
+ bzero((char *)&tmp_time, sizeof(tmp_time));
+ ((Field_timestamp *) used_field->field)->get_time(&tmp_time);
+ protocol->store(&tmp_time);
+ }
+ break;
+ default:
+ {
+ String tmp_string;
+
+ get_field(thd->mem_root, used_field->field, &tmp_string);
+ protocol->store(&tmp_string);
+ }
+ break;
+ }
+ }
+ if (protocol->write())
+ return SP_INTERNAL_ERROR;
+ }
+ }
+ return SP_OK;
+}
+
+
+static int
+db_show_routine_status(THD *thd, int type, const char *wild)
+{
+ TABLE *table;
+ TABLE_LIST tables;
+ int res;
+ DBUG_ENTER("db_show_routine_status");
+
+ memset(&tables, 0, sizeof(tables));
+ tables.db= (char*)"mysql";
+ tables.table_name= tables.alias= (char*)"proc";
+
+ if (! (table= open_ltable(thd, &tables, TL_READ)))
+ {
+ res= SP_OPEN_TABLE_FAILED;
+ goto done;
+ }
+ else
+ {
+ Item *item;
+ List<Item> field_list;
+ struct st_used_field *used_field;
+ TABLE_LIST *leaves= 0;
+ st_used_field used_fields[array_elements(init_fields)];
+
+ memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields));
+ /* Init header */
+ for (used_field= &used_fields[0];
+ used_field->field_name;
+ used_field++)
+ {
+ switch (used_field->field_type) {
+ case MYSQL_TYPE_TIMESTAMP:
+ field_list.push_back(item=new Item_datetime(used_field->field_name));
+ break;
+ default:
+ field_list.push_back(item=new Item_empty_string(used_field->field_name,
+ used_field->
+ field_length));
+ break;
+ }
+ }
+ /* Print header */
+ if (thd->protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+ Protocol::SEND_EOF))
+ {
+ res= SP_INTERNAL_ERROR;
+ goto err_case;
+ }
+
+ /*
+ Init fields
+
+ tables is not VIEW for sure => we can pass 0 as condition
+ */
+ setup_tables(thd, &tables, 0, &leaves, FALSE, FALSE);
+ for (used_field= &used_fields[0];
+ used_field->field_name;
+ used_field++)
+ {
+ Item_field *field= new Item_field("mysql", "proc",
+ used_field->field_name);
+ if (!(used_field->field= find_field_in_tables(thd, field, &tables,
+ 0, REPORT_ALL_ERRORS, 1)))
+ {
+ res= SP_INTERNAL_ERROR;
+ goto err_case1;
+ }
+ }
+
+ table->file->ha_index_init(0);
+ if ((res= table->file->index_first(table->record[0])))
+ {
+ res= (res == HA_ERR_END_OF_FILE) ? 0 : SP_INTERNAL_ERROR;
+ goto err_case1;
+ }
+ if ((res= print_field_values(thd, table, used_fields, type, wild)))
+ goto err_case1;
+ while (!table->file->index_next(table->record[0]))
+ {
+ if ((res= print_field_values(thd, table, used_fields, type, wild)))
+ goto err_case1;
+ }
+ res= SP_OK;
+ }
+
+err_case1:
+ send_eof(thd);
+err_case:
+ table->file->ha_index_end();
+ close_thread_tables(thd);
+done:
+ DBUG_RETURN(res);
+}
+
+
+/* Drop all routines in database 'db' */
+int
+sp_drop_db_routines(THD *thd, char *db)
+{
+ TABLE *table;
+ byte key[64]; // db
+ uint keylen;
+ int ret;
+ DBUG_ENTER("sp_drop_db_routines");
+ DBUG_PRINT("enter", ("db: %s", db));
+
+ // Put the key used to read the row together
+ keylen= strlen(db);
+ if (keylen > 64)
+ keylen= 64;
+ memcpy(key, db, keylen);
+ 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_OK;
+ table->file->ha_index_init(0);
+ if (! table->file->index_read(table->record[0],
+ key, keylen, HA_READ_KEY_EXACT))
+ {
+ int nxtres;
+ bool deleted= FALSE;
+
+ do {
+ if (! table->file->delete_row(table->record[0]))
+ deleted= TRUE; /* We deleted something */
+ else
+ {
+ ret= SP_DELETE_ROW_FAILED;
+ nxtres= 0;
+ break;
+ }
+ } while (! (nxtres= table->file->index_next_same(table->record[0],
+ key, keylen)));
+ if (nxtres != HA_ERR_END_OF_FILE)
+ ret= SP_KEY_NOT_FOUND;
+ if (deleted)
+ sp_cache_invalidate();
+ }
+ table->file->ha_index_end();
+
+ close_thread_tables(thd);
+
+ DBUG_RETURN(ret);
+}
+
+
+/*****************************************************************************
+ PROCEDURE
+******************************************************************************/
+
+/*
+ Obtain object representing stored procedure by its name from
+ stored procedures cache and looking into mysql.proc if needed.
+
+ SYNOPSIS
+ sp_find_procedure()
+ thd - thread context
+ name - name of procedure
+ cache_only - if true perform cache-only lookup
+ (Don't look in mysql.proc).
+
+ TODO
+ We should consider merging of sp_find_procedure() and
+ sp_find_function() into one sp_find_routine() function
+ (the same applies to other similarly paired functions).
+
+ RETURN VALUE
+ Non-0 pointer to sp_head object for the procedure, or
+ 0 - in case of error.
+*/
+
+sp_head *
+sp_find_procedure(THD *thd, sp_name *name, bool cache_only)
+{
+ sp_head *sp;
+ DBUG_ENTER("sp_find_procedure");
+ DBUG_PRINT("enter", ("name: %*s.%*s",
+ name->m_db.length, name->m_db.str,
+ name->m_name.length, name->m_name.str));
+
+ if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name)) && !cache_only)
+ {
+ if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, name, &sp) == SP_OK)
+ sp_cache_insert(&thd->sp_proc_cache, sp);
+ }
+
+ DBUG_RETURN(sp);
+}
+
+
+int
+sp_exists_routine(THD *thd, TABLE_LIST *tables, bool any, bool no_error)
+{
+ TABLE_LIST *table;
+ bool result= 0;
+ DBUG_ENTER("sp_exists_routine");
+ for (table= tables; table; table= table->next_global)
+ {
+ sp_name *name;
+ LEX_STRING lex_db;
+ LEX_STRING lex_name;
+ lex_db.length= strlen(table->db);
+ lex_name.length= strlen(table->table_name);
+ lex_db.str= thd->strmake(table->db, lex_db.length);
+ lex_name.str= thd->strmake(table->table_name, lex_name.length);
+ name= new sp_name(lex_db, lex_name);
+ name->init_qname(thd);
+ if (sp_find_procedure(thd, name) != NULL ||
+ sp_find_function(thd, name) != NULL)
+ {
+ if (any)
+ DBUG_RETURN(1);
+ result= 1;
+ }
+ else if (!any)
+ {
+ if (!no_error)
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION or PROCEDURE",
+ table->table_name);
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(result);
+}
+
+
+int
+sp_create_procedure(THD *thd, sp_head *sp)
+{
+ int ret;
+ DBUG_ENTER("sp_create_procedure");
+ DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str));
+
+ ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp);
+ DBUG_RETURN(ret);
+}
+
+
+int
+sp_drop_procedure(THD *thd, sp_name *name)
+{
+ int ret;
+ bool found;
+ DBUG_ENTER("sp_drop_procedure");
+ DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+
+ found= sp_cache_remove(&thd->sp_proc_cache, name);
+ ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
+ if (!found && !ret)
+ sp_cache_invalidate();
+ DBUG_RETURN(ret);
+}
+
+
+int
+sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
+{
+ int ret;
+ bool found;
+ DBUG_ENTER("sp_update_procedure");
+ DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+
+ found= sp_cache_remove(&thd->sp_proc_cache, name);
+ ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics);
+ if (!found && !ret)
+ sp_cache_invalidate();
+ DBUG_RETURN(ret);
+}
+
+
+int
+sp_show_create_procedure(THD *thd, sp_name *name)
+{
+ sp_head *sp;
+ DBUG_ENTER("sp_show_create_procedure");
+ DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+
+ if ((sp= sp_find_procedure(thd, name)))
+ {
+ int ret= sp->show_create_procedure(thd);
+
+ DBUG_RETURN(ret);
+ }
+
+ DBUG_RETURN(SP_KEY_NOT_FOUND);
+}
+
+
+int
+sp_show_status_procedure(THD *thd, const char *wild)
+{
+ int ret;
+ DBUG_ENTER("sp_show_status_procedure");
+
+ ret= db_show_routine_status(thd, TYPE_ENUM_PROCEDURE, wild);
+ DBUG_RETURN(ret);
+}
+
+
+/*****************************************************************************
+ FUNCTION
+******************************************************************************/
+
+/*
+ Obtain object representing stored function by its name from
+ stored functions cache and looking into mysql.proc if needed.
+
+ SYNOPSIS
+ sp_find_function()
+ thd - thread context
+ name - name of function
+ cache_only - if true perform cache-only lookup
+ (Don't look in mysql.proc).
+
+ NOTE
+ See TODO section for sp_find_procedure().
+
+ RETURN VALUE
+ Non-0 pointer to sp_head object for the function, or
+ 0 - in case of error.
+*/
+
+sp_head *
+sp_find_function(THD *thd, sp_name *name, bool cache_only)
+{
+ sp_head *sp;
+ DBUG_ENTER("sp_find_function");
+ DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+
+ 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
+ sp_cache_insert(&thd->sp_func_cache, sp);
+ }
+ DBUG_RETURN(sp);
+}
+
+
+int
+sp_create_function(THD *thd, sp_head *sp)
+{
+ int ret;
+ DBUG_ENTER("sp_create_function");
+ DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str));
+
+ ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, sp);
+ DBUG_RETURN(ret);
+}
+
+
+int
+sp_drop_function(THD *thd, sp_name *name)
+{
+ int ret;
+ bool found;
+ DBUG_ENTER("sp_drop_function");
+ DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+
+ found= sp_cache_remove(&thd->sp_func_cache, name);
+ ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
+ if (!found && !ret)
+ sp_cache_invalidate();
+ DBUG_RETURN(ret);
+}
+
+
+int
+sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics)
+{
+ int ret;
+ bool found;
+ DBUG_ENTER("sp_update_procedure");
+ DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+
+ found= sp_cache_remove(&thd->sp_func_cache, name);
+ ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics);
+ if (!found && !ret)
+ sp_cache_invalidate();
+ DBUG_RETURN(ret);
+}
+
+
+int
+sp_show_create_function(THD *thd, sp_name *name)
+{
+ sp_head *sp;
+ DBUG_ENTER("sp_show_create_function");
+ DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
+
+ if ((sp= sp_find_function(thd, name)))
+ {
+ int ret= sp->show_create_function(thd);
+
+ DBUG_RETURN(ret);
+ }
+ DBUG_RETURN(SP_KEY_NOT_FOUND);
+}
+
+
+int
+sp_show_status_function(THD *thd, const char *wild)
+{
+ int ret;
+ DBUG_ENTER("sp_show_status_function");
+ ret= db_show_routine_status(thd, TYPE_ENUM_FUNCTION, wild);
+ DBUG_RETURN(ret);
+}
+
+
+bool
+sp_function_exists(THD *thd, sp_name *name)
+{
+ 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);
+}
+
+
+byte *
+sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first)
+{
+ LEX_STRING *lsp= (LEX_STRING *)ptr;
+ *plen= lsp->length;
+ return (byte *)lsp->str;
+}
+
+
+void
+sp_add_to_hash(HASH *h, sp_name *fun)
+{
+ if (! hash_search(h, (byte *)fun->m_qname.str, fun->m_qname.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);
+ }
+}
+
+
+/*
+ Merge contents of two hashes containing LEX_STRING's
+
+ SYNOPSIS
+ sp_merge_hash()
+ 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.
+*/
+
+bool
+sp_merge_hash(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;
+ }
+ }
+ return res;
+}
+
+
+/*
+ Cache all routines implicitly or explicitly used by query
+ (or whatever object is represented by LEX).
+
+ SYNOPSIS
+ sp_cache_routines()
+ thd - thread context
+ lex - LEX representing query
+
+ 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).
+*/
+
+void
+sp_cache_routines(THD *thd, LEX *lex)
+{
+ bool routines_added= TRUE;
+
+ DBUG_ENTER("sp_cache_routines");
+
+ while (routines_added)
+ {
+ routines_added= FALSE;
+
+ for (int type= TYPE_ENUM_FUNCTION; type < TYPE_ENUM_TRIGGER; type++)
+ {
+ HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs);
+
+ for (uint i=0 ; i < h->records ; i++)
+ {
+ 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 (sp)
+ {
+ routines_added|= sp_merge_hash(&lex->spfuns, &sp->m_spfuns);
+ routines_added|= sp_merge_hash(&lex->spprocs, &sp->m_spprocs);
+ }
+ }
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ * Generates the CREATE... string from the table information.
+ * Returns TRUE on success, FALSE on (alloc) failure.
+ */
+static bool
+create_string(THD *thd, String *buf,
+ int type,
+ sp_name *name,
+ const char *params, ulong paramslen,
+ const char *returns, ulong returnslen,
+ const char *body, ulong bodylen,
+ st_sp_chistics *chistics)
+{
+ /* Make some room to begin with */
+ if (buf->alloc(100 + name->m_qname.length + paramslen + returnslen + bodylen +
+ chistics->comment.length))
+ return FALSE;
+
+ buf->append("CREATE ", 7);
+ if (type == TYPE_ENUM_FUNCTION)
+ buf->append("FUNCTION ", 9);
+ else
+ buf->append("PROCEDURE ", 10);
+ append_identifier(thd, buf, name->m_db.str, name->m_db.length);
+ buf->append('.');
+ append_identifier(thd, buf, name->m_name.str, name->m_name.length);
+ buf->append('(');
+ buf->append(params, paramslen);
+ buf->append(')');
+ if (type == TYPE_ENUM_FUNCTION)
+ {
+ buf->append(" RETURNS ", 9);
+ buf->append(returns, returnslen);
+ }
+ buf->append('\n');
+ switch (chistics->daccess) {
+ case SP_NO_SQL:
+ buf->append(" NO SQL\n");
+ break;
+ case SP_READS_SQL_DATA:
+ buf->append(" READS SQL DATA\n");
+ break;
+ case SP_MODIFIES_SQL_DATA:
+ buf->append(" MODIFIES SQL DATA\n");
+ break;
+ case SP_DEFAULT_ACCESS:
+ case SP_CONTAINS_SQL:
+ /* Do nothing */
+ break;
+ }
+ if (chistics->detistic)
+ buf->append(" DETERMINISTIC\n", 18);
+ if (chistics->suid == SP_IS_NOT_SUID)
+ buf->append(" SQL SECURITY INVOKER\n", 25);
+ if (chistics->comment.length)
+ {
+ buf->append(" COMMENT ");
+ append_unescaped(buf, chistics->comment.str, chistics->comment.length);
+ buf->append('\n');
+ }
+ buf->append(body, bodylen);
+ return TRUE;
+}
+
+
+//
+// Utilities...
+//
+
+int
+sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen,
+ bool no_access_check, bool *dbchangedp)
+{
+ bool changeit;
+ DBUG_ENTER("sp_use_new_db");
+ DBUG_PRINT("enter", ("newdb: %s", newdb));
+
+ if (! newdb)
+ newdb= (char *)"";
+ if (thd->db && thd->db[0])
+ {
+ if (my_strcasecmp(system_charset_info, thd->db, newdb) == 0)
+ changeit= 0;
+ else
+ {
+ changeit= 1;
+ strnmov(olddb, thd->db, olddblen);
+ }
+ }
+ else
+ { // thd->db empty
+ if (newdb[0])
+ changeit= 1;
+ else
+ changeit= 0;
+ olddb[0] = '\0';
+ }
+ if (!changeit)
+ {
+ *dbchangedp= FALSE;
+ DBUG_RETURN(0);
+ }
+ else
+ {
+ int ret= sp_change_db(thd, newdb, no_access_check);
+
+ if (! ret)
+ *dbchangedp= TRUE;
+ DBUG_RETURN(ret);
+ }
+}
+
+/*
+ Change database.
+
+ SYNOPSIS
+ sp_change_db()
+ thd Thread handler
+ name Database name
+ empty_is_ok True= it's ok with "" as name
+ no_access_check True= don't do access check
+
+ DESCRIPTION
+ This is the same as mysql_change_db(), but with some extra
+ arguments for Stored Procedure usage; doing implicit "use"
+ when executing an SP in a different database.
+ We also use different error routines, since this might be
+ invoked from a function when executing a query or statement.
+ Note: We would have prefered to reuse mysql_change_db(), but
+ the error handling in particular made that too awkward, so
+ we (reluctantly) have a "copy" here.
+
+ RETURN VALUES
+ 0 ok
+ 1 error
+*/
+
+int
+sp_change_db(THD *thd, char *name, bool no_access_check)
+{
+ int length, db_length;
+ char *dbname=my_strdup((char*) name,MYF(MY_WME));
+ char path[FN_REFLEN];
+ HA_CREATE_INFO create;
+ DBUG_ENTER("sp_change_db");
+ DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check));
+
+ db_length= (!dbname ? 0 : strip_sp(dbname));
+ if (dbname && db_length)
+ {
+ if ((db_length > NAME_LEN) || check_db_name(dbname))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
+ x_free(dbname);
+ DBUG_RETURN(1);
+ }
+ }
+
+ if (dbname && db_length)
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (! no_access_check)
+ {
+ ulong db_access;
+
+ if (test_all_bits(thd->master_access,DB_ACLS))
+ db_access=DB_ACLS;
+ else
+ db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
+ thd->master_access);
+ if (!(db_access & DB_ACLS) &&
+ (!grant_option || check_grant_db(thd,dbname)))
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user,
+ thd->priv_host,
+ dbname);
+ mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
+ thd->priv_user,
+ thd->priv_host,
+ dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+#endif
+ (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
+ length=unpack_dirname(path,path); // Convert if not unix
+ if (length && path[length-1] == FN_LIBCHAR)
+ path[length-1]=0; // remove ending '\'
+ if (access(path,F_OK))
+ {
+ my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+
+ x_free(thd->db);
+ thd->db=dbname; // THD::~THD will free this
+ thd->db_length=db_length;
+
+ if (dbname && db_length)
+ {
+ strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
+ load_db_opt(thd, path, &create);
+ thd->db_charset= create.default_table_charset ?
+ create.default_table_charset :
+ thd->variables.collation_server;
+ thd->variables.collation_database= thd->db_charset;
+ }
+ DBUG_RETURN(0);
+}
diff --git a/sql/sp.h b/sql/sp.h
new file mode 100644
index 00000000000..00dd8416c1d
--- /dev/null
+++ b/sql/sp.h
@@ -0,0 +1,106 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _SP_H_
+#define _SP_H_
+
+// Return codes from sp_create_*, sp_drop_*, and sp_show_*:
+#define SP_OK 0
+#define SP_KEY_NOT_FOUND -1
+#define SP_OPEN_TABLE_FAILED -2
+#define SP_WRITE_ROW_FAILED -3
+#define SP_DELETE_ROW_FAILED -4
+#define SP_GET_FIELD_FAILED -5
+#define SP_PARSE_ERROR -6
+#define SP_INTERNAL_ERROR -7
+#define SP_NO_DB_ERROR -8
+
+/* Drop all routines in database 'db' */
+int
+sp_drop_db_routines(THD *thd, char *db);
+
+sp_head *
+sp_find_procedure(THD *thd, sp_name *name, bool cache_only = 0);
+
+int
+sp_exists_routine(THD *thd, TABLE_LIST *procs, bool any, bool no_error);
+
+int
+sp_create_procedure(THD *thd, sp_head *sp);
+
+int
+sp_drop_procedure(THD *thd, sp_name *name);
+
+
+int
+sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics);
+
+int
+sp_show_create_procedure(THD *thd, sp_name *name);
+
+int
+sp_show_status_procedure(THD *thd, const char *wild);
+
+sp_head *
+sp_find_function(THD *thd, sp_name *name, bool cache_only = 0);
+
+int
+sp_create_function(THD *thd, sp_head *sp);
+
+int
+sp_drop_function(THD *thd, sp_name *name);
+
+int
+sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics);
+
+int
+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);
+
+
+//
+// Utilities...
+//
+
+// Do a "use newdb". The current db is stored at olddb.
+// If newdb is the same as the current one, nothing is changed.
+// dbchangedp is set to true if the db was actually changed.
+int
+sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddbmax,
+ bool no_access_check, bool *dbchangedp);
+
+// Like mysql_change_db() but handles empty db name and the send_ok() problem.
+int
+sp_change_db(THD *thd, char *db, bool no_access_check);
+
+#endif /* _SP_H_ */
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
new file mode 100644
index 00000000000..056ac6d7e96
--- /dev/null
+++ b/sql/sp_cache.cc
@@ -0,0 +1,166 @@
+/* Copyright (C) 2002 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sp_cache.h"
+#include "sp_head.h"
+
+static pthread_mutex_t Cversion_lock;
+static ulong Cversion = 0;
+
+void
+sp_cache_init()
+{
+ pthread_mutex_init(&Cversion_lock, MY_MUTEX_INIT_FAST);
+}
+
+void
+sp_cache_clear(sp_cache **cp)
+{
+ sp_cache *c= *cp;
+
+ if (c)
+ {
+ delete c;
+ *cp= NULL;
+ }
+}
+
+void
+sp_cache_insert(sp_cache **cp, sp_head *sp)
+{
+ sp_cache *c= *cp;
+
+ if (! c)
+ c= new sp_cache();
+ if (c)
+ {
+ ulong v;
+
+ pthread_mutex_lock(&Cversion_lock); // LOCK
+ v= Cversion;
+ pthread_mutex_unlock(&Cversion_lock); // UNLOCK
+
+ if (c->version < v)
+ {
+ if (*cp)
+ c->remove_all();
+ c->version= v;
+ }
+ c->insert(sp);
+ if (*cp == NULL)
+ *cp= c;
+ }
+}
+
+sp_head *
+sp_cache_lookup(sp_cache **cp, sp_name *name)
+{
+ ulong v;
+ sp_cache *c= *cp;
+
+ if (! c)
+ return NULL;
+
+ pthread_mutex_lock(&Cversion_lock); // LOCK
+ v= Cversion;
+ pthread_mutex_unlock(&Cversion_lock); // UNLOCK
+
+ if (c->version < v)
+ {
+ c->remove_all();
+ c->version= v;
+ return NULL;
+ }
+ return c->lookup(name->m_qname.str, name->m_qname.length);
+}
+
+bool
+sp_cache_remove(sp_cache **cp, sp_name *name)
+{
+ sp_cache *c= *cp;
+ bool found= FALSE;
+
+ if (c)
+ {
+ ulong v;
+
+ pthread_mutex_lock(&Cversion_lock); // LOCK
+ v= Cversion++;
+ pthread_mutex_unlock(&Cversion_lock); // UNLOCK
+
+ if (c->version < v)
+ c->remove_all();
+ else
+ found= c->remove(name->m_qname.str, name->m_qname.length);
+ c->version= v+1;
+ }
+ return found;
+}
+
+void
+sp_cache_invalidate()
+{
+ pthread_mutex_lock(&Cversion_lock); // LOCK
+ Cversion++;
+ pthread_mutex_unlock(&Cversion_lock); // UNLOCK
+}
+
+static byte *
+hash_get_key_for_sp_head(const byte *ptr, uint *plen,
+ my_bool first)
+{
+ sp_head *sp= (sp_head *)ptr;
+
+ *plen= sp->m_qname.length;
+ return (byte*) sp->m_qname.str;
+}
+
+static void
+hash_free_sp_head(void *p)
+{
+ sp_head *sp= (sp_head *)p;
+
+ delete sp;
+}
+
+sp_cache::sp_cache()
+{
+ init();
+}
+
+sp_cache::~sp_cache()
+{
+ hash_free(&m_hashtable);
+}
+
+void
+sp_cache::init()
+{
+ hash_init(&m_hashtable, system_charset_info, 0, 0, 0,
+ hash_get_key_for_sp_head, hash_free_sp_head, 0);
+ version= 0;
+}
+
+void
+sp_cache::cleanup()
+{
+ hash_free(&m_hashtable);
+}
diff --git a/sql/sp_cache.h b/sql/sp_cache.h
new file mode 100644
index 00000000000..754a987090e
--- /dev/null
+++ b/sql/sp_cache.h
@@ -0,0 +1,107 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _SP_CACHE_H_
+#define _SP_CACHE_H_
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class sp_head;
+class sp_cache;
+
+/* Initialize the SP caching once at startup */
+void sp_cache_init();
+
+/* Clear the cache *cp and set *cp to NULL */
+void sp_cache_clear(sp_cache **cp);
+
+/* Insert an SP to cache. If 'cp' points to NULL, it's set to a new cache */
+void sp_cache_insert(sp_cache **cp, sp_head *sp);
+
+/* Lookup an SP in cache */
+sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name);
+
+/* Remove an SP from cache. Returns true if something was removed */
+bool sp_cache_remove(sp_cache **cp, sp_name *name);
+
+/* Invalidate a cache */
+void sp_cache_invalidate();
+
+
+/*
+ *
+ * The cache class. Don't use this directly, use the C API above
+ *
+ */
+
+class sp_cache
+{
+public:
+
+ ulong version;
+
+ sp_cache();
+
+ ~sp_cache();
+
+ void
+ init();
+
+ void
+ cleanup();
+
+ inline void
+ insert(sp_head *sp)
+ {
+ my_hash_insert(&m_hashtable, (const byte *)sp);
+ }
+
+ inline sp_head *
+ lookup(char *name, uint namelen)
+ {
+ return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen);
+ }
+
+ inline bool
+ remove(char *name, uint namelen)
+ {
+ sp_head *sp= lookup(name, namelen);
+
+ if (sp)
+ {
+ hash_delete(&m_hashtable, (byte *)sp);
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ inline void
+ remove_all()
+ {
+ cleanup();
+ init();
+ }
+
+private:
+
+ HASH m_hashtable;
+
+}; // class sp_cache
+
+#endif /* _SP_CACHE_H_ */
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
new file mode 100644
index 00000000000..ad14116a4c7
--- /dev/null
+++ b/sql/sp_head.cc
@@ -0,0 +1,2351 @@
+/* Copyright (C) 2002 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sp_head.h"
+#include "sp.h"
+#include "sp_pcontext.h"
+#include "sp_rcontext.h"
+#include "sp_cache.h"
+
+Item_result
+sp_map_result_type(enum enum_field_types type)
+{
+ switch (type)
+ {
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ return INT_RESULT;
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return DECIMAL_RESULT;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ return REAL_RESULT;
+ default:
+ return STRING_RESULT;
+ }
+}
+
+/*
+ * Returns TRUE if the 'cmd' is a command that might result in
+ * multiple result sets being sent back.
+ * Note: This does not include SQLCOM_SELECT which is treated
+ * separately in sql_yacc.yy.
+ */
+bool
+sp_multi_results_command(enum enum_sql_command cmd)
+{
+ switch (cmd) {
+ case SQLCOM_ANALYZE:
+ case SQLCOM_CHECKSUM:
+ case SQLCOM_HA_READ:
+ case SQLCOM_SHOW_BINLOGS:
+ case SQLCOM_SHOW_BINLOG_EVENTS:
+ case SQLCOM_SHOW_CHARSETS:
+ case SQLCOM_SHOW_COLLATIONS:
+ case SQLCOM_SHOW_COLUMN_TYPES:
+ case SQLCOM_SHOW_CREATE:
+ case SQLCOM_SHOW_CREATE_DB:
+ case SQLCOM_SHOW_CREATE_FUNC:
+ case SQLCOM_SHOW_CREATE_PROC:
+ case SQLCOM_SHOW_DATABASES:
+ case SQLCOM_SHOW_ERRORS:
+ case SQLCOM_SHOW_FIELDS:
+ case SQLCOM_SHOW_GRANTS:
+ case SQLCOM_SHOW_INNODB_STATUS:
+ case SQLCOM_SHOW_KEYS:
+ case SQLCOM_SHOW_LOGS:
+ case SQLCOM_SHOW_MASTER_STAT:
+ case SQLCOM_SHOW_MUTEX_STATUS:
+ case SQLCOM_SHOW_NEW_MASTER:
+ case SQLCOM_SHOW_OPEN_TABLES:
+ case SQLCOM_SHOW_PRIVILEGES:
+ case SQLCOM_SHOW_PROCESSLIST:
+ case SQLCOM_SHOW_SLAVE_HOSTS:
+ case SQLCOM_SHOW_SLAVE_STAT:
+ case SQLCOM_SHOW_STATUS:
+ case SQLCOM_SHOW_STATUS_FUNC:
+ case SQLCOM_SHOW_STATUS_PROC:
+ case SQLCOM_SHOW_STORAGE_ENGINES:
+ case SQLCOM_SHOW_TABLES:
+ case SQLCOM_SHOW_VARIABLES:
+ case SQLCOM_SHOW_WARNS:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* Evaluate a (presumed) func item. Always returns an item, the parameter
+** if nothing else.
+*/
+Item *
+sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
+{
+ DBUG_ENTER("sp_eval_func_item");
+ it= it->this_item();
+ DBUG_PRINT("info", ("type: %d", type));
+
+ if (!it->fixed && it->fix_fields(thd, 0, &it))
+ {
+ DBUG_PRINT("info", ("fix_fields() failed"));
+ DBUG_RETURN(NULL);
+ }
+
+ /* QQ How do we do this? Is there some better way? */
+ if (type == MYSQL_TYPE_NULL)
+ it= new Item_null();
+ else
+ {
+ switch (sp_map_result_type(type)) {
+ case INT_RESULT:
+ {
+ longlong i= it->val_int();
+
+ if (it->null_value)
+ {
+ DBUG_PRINT("info", ("INT_RESULT: null"));
+ it= new Item_null();
+ }
+ else
+ {
+ DBUG_PRINT("info", ("INT_RESULT: %d", i));
+ it= new Item_int(i);
+ }
+ break;
+ }
+ case REAL_RESULT:
+ {
+ double d= it->val_real();
+
+ if (it->null_value)
+ {
+ DBUG_PRINT("info", ("REAL_RESULT: null"));
+ it= new Item_null();
+ }
+ else
+ {
+ /* There's some difference between Item::new_item() and the
+ * constructor; the former crashes, the latter works... weird. */
+ uint8 decimals= it->decimals;
+ uint32 max_length= it->max_length;
+ DBUG_PRINT("info", ("REAL_RESULT: %g", d));
+ it= new Item_float(d);
+ it->decimals= decimals;
+ it->max_length= max_length;
+ }
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= it->val_decimal(&value);
+ if (it->null_value)
+ it= new Item_null();
+ else
+ it= new Item_decimal(val);
+ dbug_print_decimal("info", "DECIMAL_RESULT: %s", val);
+ break;
+ }
+ case STRING_RESULT:
+ {
+ char buffer[MAX_FIELD_WIDTH];
+ String tmp(buffer, sizeof(buffer), it->collation.collation);
+ String *s= it->val_str(&tmp);
+
+ if (it->null_value)
+ {
+ DBUG_PRINT("info", ("default result: null"));
+ it= new Item_null();
+ }
+ else
+ {
+ DBUG_PRINT("info",("default result: %*s",
+ s->length(), s->c_ptr_quick()));
+ it= new Item_string(thd->strmake(s->ptr(), s->length()),
+ s->length(), it->collation.collation);
+ }
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+
+ DBUG_RETURN(it);
+}
+
+
+/*
+ *
+ * sp_name
+ *
+ */
+
+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);
+ sprintf(m_qname.str, "%*s.%*s",
+ m_db.length, (m_db.length ? m_db.str : ""),
+ m_name.length, m_name.str);
+}
+
+sp_name *
+sp_name_current_db_new(THD *thd, LEX_STRING name)
+{
+ sp_name *qname;
+
+ if (! thd->db)
+ qname= new sp_name(name);
+ else
+ {
+ LEX_STRING db;
+
+ db.length= strlen(thd->db);
+ db.str= thd->strmake(thd->db, db.length);
+ qname= new sp_name(db, name);
+ }
+ qname->init_qname(thd);
+ return qname;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+/*
+ *
+ * sp_head
+ *
+ */
+
+void *
+sp_head::operator new(size_t size)
+{
+ DBUG_ENTER("sp_head::operator new");
+ MEM_ROOT own_root;
+ sp_head *sp;
+
+ init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+ sp= (sp_head *) alloc_root(&own_root, size);
+ sp->main_mem_root= own_root;
+ DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root));
+ DBUG_RETURN(sp);
+}
+
+void
+sp_head::operator delete(void *ptr, size_t size)
+{
+ DBUG_ENTER("sp_head::operator delete");
+ MEM_ROOT own_root;
+ sp_head *sp= (sp_head *) ptr;
+
+ /* Make a copy of main_mem_root as free_root will free the sp */
+ own_root= sp->main_mem_root;
+ DBUG_PRINT("info", ("mem_root 0x%lx moved to 0x%lx",
+ (ulong) &sp->mem_root, (ulong) &own_root));
+ free_root(&own_root, MYF(0));
+
+ DBUG_VOID_RETURN;
+}
+
+
+sp_head::sp_head()
+ :Item_arena((bool)FALSE), m_returns_cs(NULL), m_has_return(FALSE),
+ m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(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;
+ 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);
+ DBUG_VOID_RETURN;
+}
+
+
+void
+sp_head::init(LEX *lex)
+{
+ DBUG_ENTER("sp_head::init");
+
+ lex->spcont= m_pcont= new sp_pcontext(NULL);
+ /*
+ Altough trg_table_fields list is used only in triggers we init for all
+ types of stored procedures to simplify reset_lex()/restore_lex() code.
+ */
+ lex->trg_table_fields.empty();
+ my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
+ m_param_begin= m_param_end= m_body_begin= 0;
+ m_qname.str= m_db.str= m_name.str= m_params.str=
+ m_body.str= m_defstr.str= 0;
+ m_qname.length= m_db.length= m_name.length= m_params.length=
+ m_body.length= m_defstr.length= 0;
+ m_returns_cs= NULL;
+ DBUG_VOID_RETURN;
+}
+
+void
+sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
+{
+ DBUG_ENTER("sp_head::init_strings");
+ uint n; /* Counter for nul trimming */
+ /* During parsing, we must use thd->mem_root */
+ MEM_ROOT *root= thd->mem_root;
+
+ /* We have to copy strings to get them into the right memroot */
+ if (name)
+ {
+ m_db.length= name->m_db.length;
+ if (name->m_db.length == 0)
+ m_db.str= NULL;
+ else
+ m_db.str= strmake_root(root, name->m_db.str, name->m_db.length);
+ m_name.length= name->m_name.length;
+ m_name.str= strmake_root(root, name->m_name.str, name->m_name.length);
+
+ if (name->m_qname.length == 0)
+ name->init_qname(thd);
+ m_qname.length= name->m_qname.length;
+ m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length);
+ }
+ else if (thd->db)
+ {
+ m_db.length= thd->db_length;
+ m_db.str= strmake_root(root, thd->db, m_db.length);
+ }
+
+ if (m_param_begin && m_param_end)
+ {
+ m_params.length= m_param_end - m_param_begin;
+ m_params.str= strmake_root(root,
+ (char *)m_param_begin, m_params.length);
+ }
+
+ m_body.length= lex->ptr - m_body_begin;
+ /* Trim nuls at the end */
+ n= 0;
+ while (m_body.length && m_body_begin[m_body.length-1] == '\0')
+ {
+ m_body.length-= 1;
+ n+= 1;
+ }
+ m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length);
+ m_defstr.length= lex->ptr - lex->buf;
+ m_defstr.length-= n;
+ m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length);
+ DBUG_VOID_RETURN;
+}
+
+TYPELIB *
+sp_head::create_typelib(List<String> *src)
+{
+ TYPELIB *result= NULL;
+ CHARSET_INFO *cs= m_returns_cs;
+ DBUG_ENTER("sp_head::clone_typelib");
+ if (src->elements)
+ {
+ result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
+ result->count= src->elements;
+ result->name= "";
+ if (!(result->type_names=(const char **)
+ alloc_root(mem_root,(sizeof(char *)+sizeof(int))*(result->count+1))))
+ return 0;
+ result->type_lengths= (unsigned int *)(result->type_names + result->count+1);
+ List_iterator<String> it(*src);
+ String conv, *tmp;
+ uint32 dummy;
+ for (uint i=0; i<result->count; i++)
+ {
+ tmp = it++;
+ if (String::needs_conversion(tmp->length(), tmp->charset(),
+ cs, &dummy))
+ {
+ uint cnv_errs;
+ conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
+ char *buf= (char*) alloc_root(mem_root,conv.length()+1);
+ memcpy(buf, conv.ptr(), conv.length());
+ buf[conv.length()]= '\0';
+ result->type_names[i]= buf;
+ result->type_lengths[i]= conv.length();
+ }
+ else {
+ result->type_names[i]= strdup_root(mem_root, tmp->c_ptr());
+ result->type_lengths[i]= tmp->length();
+ }
+
+ // Strip trailing spaces.
+ uint lengthsp= cs->cset->lengthsp(cs, result->type_names[i],
+ result->type_lengths[i]);
+ result->type_lengths[i]= lengthsp;
+ ((uchar *)result->type_names[i])[lengthsp]= '\0';
+ }
+ result->type_names[result->count]= 0;
+ result->type_lengths[result->count]= 0;
+ }
+ return result;
+}
+
+int
+sp_head::create(THD *thd)
+{
+ DBUG_ENTER("sp_head::create");
+ int ret;
+
+ DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s",
+ m_type, m_name.str, m_params.str, m_body.str));
+
+#ifndef DBUG_OFF
+ optimize();
+ {
+ String s;
+ sp_instr *i;
+ uint ip= 0;
+ while ((i = get_instr(ip)))
+ {
+ char buf[8];
+
+ sprintf(buf, "%4u: ", ip);
+ s.append(buf);
+ i->print(&s);
+ s.append('\n');
+ ip+= 1;
+ }
+ s.append('\0');
+ DBUG_PRINT("info", ("Code %s\n%s", m_qname.str, s.ptr()));
+ }
+#endif
+
+ if (m_type == TYPE_ENUM_FUNCTION)
+ ret= sp_create_function(thd, this);
+ else
+ ret= sp_create_procedure(thd, this);
+
+ DBUG_RETURN(ret);
+}
+
+sp_head::~sp_head()
+{
+ destroy();
+ if (m_thd)
+ restore_thd_mem_root(m_thd);
+}
+
+void
+sp_head::destroy()
+{
+ sp_instr *i;
+ LEX *lex;
+ DBUG_ENTER("sp_head::destroy");
+ DBUG_PRINT("info", ("name: %s", m_name.str));
+
+ for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
+ delete i;
+ delete_dynamic(&m_instr);
+ m_pcont->destroy();
+ free_items(free_list);
+
+ /*
+ If we have non-empty LEX stack then we just came out of parser with
+ error. Now we should delete all auxilary LEXes and restore original
+ THD::lex (In this case sp_head::restore_thd_mem_root() was not called
+ too, so m_thd points to the current thread context).
+ It is safe to not update LEX::ptr because further query string parsing
+ and execution will be stopped anyway.
+ */
+ DBUG_ASSERT(m_lex.is_empty() || m_thd);
+ while ((lex= (LEX *)m_lex.pop()))
+ {
+ delete m_thd->lex;
+ m_thd->lex= lex;
+ }
+
+ hash_free(&m_sptabs);
+ hash_free(&m_spfuns);
+ hash_free(&m_spprocs);
+ DBUG_VOID_RETURN;
+}
+
+
+Field *
+sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
+{
+ Field *field;
+ DBUG_ENTER("sp_head::make_field");
+ field= ::make_field((char *)0,
+ !m_returns_len ? max_length : m_returns_len,
+ (uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
+ (enum Field::geometry_type)0, Field::NONE,
+ m_returns_typelib,
+ name ? name : (const char *)m_name.str, dummy);
+ DBUG_RETURN(field);
+}
+
+int
+sp_head::execute(THD *thd)
+{
+ DBUG_ENTER("sp_head::execute");
+ char olddb[128];
+ bool dbchanged;
+ sp_rcontext *ctx;
+ int ret= 0;
+ uint ip= 0;
+ Item_arena *old_arena;
+ query_id_t old_query_id;
+ TABLE *old_derived_tables;
+ LEX *old_lex;
+ Item_change_list old_change_list;
+ String old_packet;
+
+
+#ifndef EMBEDDED_LIBRARY
+ if (check_stack_overrun(thd, olddb))
+ {
+ DBUG_RETURN(-1);
+ }
+#endif
+
+ dbchanged= FALSE;
+ if (m_db.length &&
+ (ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0, &dbchanged)))
+ goto done;
+
+ if ((ctx= thd->spcont))
+ 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
+ be able properly do close_thread_tables() in instructions.
+ */
+ old_query_id= thd->query_id;
+ old_derived_tables= thd->derived_tables;
+ thd->derived_tables= 0;
+ /*
+ It is also more efficient to save/restore current thd->lex once when
+ do it in each instruction
+ */
+ old_lex= thd->lex;
+ /*
+ We should also save Item tree change list to avoid rollback something
+ too early in the calling query.
+ */
+ old_change_list= thd->change_list;
+ thd->change_list.empty();
+ /*
+ Cursors will use thd->packet, so they may corrupt data which was prepared
+ for sending by upper level. OTOH cursors in the same routine can share this
+ buffer safely so let use use routine-local packet instead of having own
+ packet buffer for each cursor.
+
+ It is probably safe to use same thd->convert_buff everywhere.
+ */
+ old_packet.swap(thd->packet);
+
+ do
+ {
+ sp_instr *i;
+ uint hip; // Handler ip
+
+ i = get_instr(ip); // Returns NULL when we're done.
+ if (i == NULL)
+ break;
+ DBUG_PRINT("execute", ("Instruction %u", ip));
+ thd->set_time(); // Make current_time() et al work
+ ret= i->execute(thd, &ip);
+ if (i->free_list)
+ cleanup_items(i->free_list);
+ // Check if an exception has occurred and a handler has been found
+ // Note: We havo to check even if ret==0, since warnings (and some
+ // errors don't return a non-zero value.
+ // We also have to check even if thd->killed != 0, since some
+ // errors return with this even when a handler has been found
+ // (e.g. "bad data").
+ if (ctx)
+ {
+ uint hf;
+
+ switch (ctx->found_handler(&hip, &hf))
+ {
+ case SP_HANDLER_NONE:
+ break;
+ case SP_HANDLER_CONTINUE:
+ ctx->save_variables(hf);
+ ctx->push_hstack(ip);
+ // Fall through
+ default:
+ ip= hip;
+ ret= 0;
+ ctx->clear_handler();
+ ctx->in_handler= TRUE;
+ thd->clear_error();
+ thd->killed= THD::NOT_KILLED;
+ continue;
+ }
+ }
+ } while (ret == 0 && !thd->killed);
+
+ /* Restore all saved */
+ old_packet.swap(thd->packet);
+ DBUG_ASSERT(thd->change_list.is_empty());
+ thd->change_list= old_change_list;
+ /* To avoid wiping out thd->change_list on old_change_list destruction */
+ old_change_list.empty();
+ thd->lex= old_lex;
+ thd->query_id= old_query_id;
+ DBUG_ASSERT(!thd->derived_tables);
+ thd->derived_tables= old_derived_tables;
+
+ cleanup_items(thd->current_arena->free_list);
+ thd->current_arena= old_arena;
+
+ done:
+ DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
+ ret, thd->killed, thd->query_error));
+
+ if (thd->killed)
+ ret= -1;
+ /* If the DB has changed, the pointer has changed too, but the
+ original thd->db will then have been freed */
+ if (dbchanged)
+ {
+ if (! thd->killed)
+ ret= sp_change_db(thd, olddb, 0);
+ }
+ DBUG_RETURN(ret);
+}
+
+
+int
+sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
+{
+ DBUG_ENTER("sp_head::execute_function");
+ DBUG_PRINT("info", ("function %s", m_name.str));
+ uint csize = m_pcont->max_pvars();
+ uint params = m_pcont->current_pvars();
+ uint hmax = m_pcont->max_handlers();
+ uint cmax = m_pcont->max_cursors();
+ sp_rcontext *octx = thd->spcont;
+ sp_rcontext *nctx = NULL;
+ uint i;
+ int ret;
+
+ if (argcount != params)
+ {
+ // Need to use my_printf_error here, or it will not terminate the
+ // invoking query properly.
+ my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0),
+ "FUNCTION", m_qname.str, params, argcount);
+ DBUG_RETURN(-1);
+ }
+
+ // QQ Should have some error checking here? (types, etc...)
+ nctx= new sp_rcontext(csize, hmax, cmax);
+ for (i= 0 ; i < params && i < argcount ; i++)
+ {
+ sp_pvar_t *pvar = m_pcont->find_pvar(i);
+ Item *it= sp_eval_func_item(thd, *argp++, pvar->type);
+
+ if (it)
+ nctx->push_item(it);
+ else
+ {
+ DBUG_RETURN(-1);
+ }
+ }
+ // The rest of the frame are local variables which are all IN.
+ // Default all variables to null (those with default clauses will
+ // be set by an set instruction).
+ {
+ Item_null *nit= NULL; // Re-use this, and only create if needed
+ for (; i < csize ; i++)
+ {
+ if (! nit)
+ nit= new Item_null();
+ nctx->push_item(nit);
+ }
+ }
+ thd->spcont= nctx;
+
+ ret= execute(thd);
+
+ if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
+ {
+ /* We need result only in function but not in trigger */
+ Item *it= nctx->get_result();
+
+ if (it)
+ *resp= it;
+ else
+ {
+ my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
+ ret= -1;
+ }
+ }
+
+ nctx->pop_all_cursors(); // To avoid memory leaks after an error
+ thd->spcont= octx;
+ DBUG_RETURN(ret);
+}
+
+static Item_func_get_user_var *
+item_is_user_var(Item *it)
+{
+ if (it->type() == Item::FUNC_ITEM)
+ {
+ Item_func *fi= static_cast<Item_func*>(it);
+
+ if (fi->functype() == Item_func::GUSERVAR_FUNC)
+ return static_cast<Item_func_get_user_var*>(fi);
+ }
+ return NULL;
+}
+
+int
+sp_head::execute_procedure(THD *thd, List<Item> *args)
+{
+ DBUG_ENTER("sp_head::execute_procedure");
+ DBUG_PRINT("info", ("procedure %s", m_name.str));
+ int ret= 0;
+ uint csize = m_pcont->max_pvars();
+ uint params = m_pcont->current_pvars();
+ uint hmax = m_pcont->max_handlers();
+ uint cmax = m_pcont->max_cursors();
+ sp_rcontext *octx = thd->spcont;
+ sp_rcontext *nctx = NULL;
+ my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
+
+ if (args->elements != params)
+ {
+ my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE",
+ m_qname.str, params, args->elements);
+ DBUG_RETURN(-1);
+ }
+
+ if (csize > 0 || hmax > 0 || cmax > 0)
+ {
+ Item_null *nit= NULL; // Re-use this, and only create if needed
+ uint i;
+ List_iterator_fast<Item> li(*args);
+ Item *it;
+
+ nctx= new sp_rcontext(csize, hmax, cmax);
+ if (! octx)
+ { // Create a temporary old context
+ octx= new sp_rcontext(csize, hmax, cmax);
+ tmp_octx= TRUE;
+ }
+ // QQ: Should do type checking?
+ for (i = 0 ; (it= li++) && i < params ; i++)
+ {
+ sp_pvar_t *pvar= m_pcont->find_pvar(i);
+
+ if (pvar)
+ {
+ if (pvar->mode != sp_param_in)
+ {
+ if (!it->is_splocal() && !item_is_user_var(it))
+ {
+ my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str);
+ ret= -1;
+ break;
+ }
+ }
+ if (pvar->mode == sp_param_out)
+ {
+ if (! nit)
+ nit= new Item_null();
+ nctx->push_item(nit); // OUT
+ }
+ else
+ {
+ Item *it2= sp_eval_func_item(thd, it, pvar->type);
+
+ if (it2)
+ nctx->push_item(it2); // IN or INOUT
+ else
+ {
+ ret= -1; // Eval failed
+ break;
+ }
+ }
+ }
+ }
+
+ // The rest of the frame are local variables which are all IN.
+ // Default all variables to null (those with default clauses will
+ // be set by an set instruction).
+ for (; i < csize ; i++)
+ {
+ if (! nit)
+ nit= new Item_null();
+ nctx->push_item(nit);
+ }
+ thd->spcont= nctx;
+ }
+
+ if (! ret)
+ ret= execute(thd);
+
+ if (!ret && csize > 0)
+ {
+ List_iterator_fast<Item> li(*args);
+ Item *it;
+
+ // Copy back all OUT or INOUT values to the previous frame, or
+ // set global user variables
+ for (uint i = 0 ; (it= li++) && i < params ; i++)
+ {
+ sp_pvar_t *pvar= m_pcont->find_pvar(i);
+
+ if (pvar->mode != sp_param_in)
+ {
+ if (it->is_splocal())
+ octx->set_item(static_cast<Item_splocal *>(it)->get_offset(),
+ nctx->get_item(i));
+ else
+ {
+ Item_func_get_user_var *guv= item_is_user_var(it);
+
+ if (guv)
+ {
+ Item *item= nctx->get_item(i);
+ Item_func_set_user_var *suv;
+
+ suv= new Item_func_set_user_var(guv->get_name(), item);
+ /*
+ we do not check suv->fixed, because it can't be fixed after
+ creation
+ */
+ suv->fix_fields(thd, NULL, &item);
+ suv->fix_length_and_dec();
+ suv->check();
+ suv->update();
+ }
+ }
+ }
+ }
+ }
+
+ if (tmp_octx)
+ octx= NULL;
+ if (nctx)
+ nctx->pop_all_cursors(); // To avoid memory leaks after an error
+ thd->spcont= octx;
+
+ DBUG_RETURN(ret);
+}
+
+
+// Reset lex during parsing, before we parse a sub statement.
+void
+sp_head::reset_lex(THD *thd)
+{
+ DBUG_ENTER("sp_head::reset_lex");
+ LEX *sublex;
+ LEX *oldlex= thd->lex;
+
+ (void)m_lex.push_front(oldlex);
+ thd->lex= sublex= new st_lex;
+
+ /* Reset most stuff. The length arguments doesn't matter here. */
+ lex_start(thd, oldlex->buf, (ulong) (oldlex->end_of_query - oldlex->ptr));
+
+ /* We must reset ptr and end_of_query again */
+ sublex->ptr= oldlex->ptr;
+ sublex->end_of_query= oldlex->end_of_query;
+ sublex->tok_start= oldlex->tok_start;
+ sublex->yylineno= oldlex->yylineno;
+ /* And keep the SP stuff too */
+ sublex->sphead= oldlex->sphead;
+ sublex->spcont= oldlex->spcont;
+ /* And trigger related stuff too */
+ sublex->trg_chistics= oldlex->trg_chistics;
+ sublex->trg_table_fields.empty();
+ sublex->sp_lex_in_use= FALSE;
+ DBUG_VOID_RETURN;
+}
+
+// Restore lex during parsing, after we have parsed a sub statement.
+void
+sp_head::restore_lex(THD *thd)
+{
+ DBUG_ENTER("sp_head::restore_lex");
+ LEX *sublex= thd->lex;
+ LEX *oldlex= (LEX *)m_lex.pop();
+
+ init_stmt_after_parse(thd, sublex);
+ if (! oldlex)
+ return; // Nothing to restore
+
+ // Update some state in the old one first
+ oldlex->ptr= sublex->ptr;
+ oldlex->next_state= sublex->next_state;
+ oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
+
+ /*
+ Add routines which are used by statement to respective sets for
+ this routine
+ */
+ sp_merge_hash(&m_spfuns, &sublex->spfuns);
+ sp_merge_hash(&m_spprocs, &sublex->spprocs);
+ /*
+ Merge tables used by this statement (but not by its functions or
+ procedures) to multiset of tables used by this routine.
+ */
+ merge_table_list(thd, sublex->query_tables, sublex);
+ if (! sublex->sp_lex_in_use)
+ delete sublex;
+ thd->lex= oldlex;
+ DBUG_VOID_RETURN;
+}
+
+void
+sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
+{
+ bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t));
+
+ if (bp)
+ {
+ bp->lab= lab;
+ bp->instr= i;
+ (void)m_backpatch.push_front(bp);
+ }
+}
+
+void
+sp_head::backpatch(sp_label_t *lab)
+{
+ bp_t *bp;
+ uint dest= instructions();
+ List_iterator_fast<bp_t> li(m_backpatch);
+
+ while ((bp= li++))
+ {
+ if (bp->lab == lab ||
+ (bp->lab->type == SP_LAB_REF &&
+ my_strcasecmp(system_charset_info, bp->lab->name, lab->name) == 0))
+ {
+ if (bp->lab->type != SP_LAB_REF)
+ bp->instr->backpatch(dest, lab->ctx);
+ else
+ {
+ sp_label_t *dstlab= bp->lab->ctx->find_label(lab->name);
+
+ if (dstlab)
+ {
+ bp->lab= lab;
+ bp->instr->backpatch(dest, dstlab->ctx);
+ }
+ }
+ }
+ }
+}
+
+int
+sp_head::check_backpatch(THD *thd)
+{
+ bp_t *bp;
+ List_iterator_fast<bp_t> li(m_backpatch);
+
+ while ((bp= li++))
+ {
+ if (bp->lab->type == SP_LAB_REF)
+ {
+ my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "GOTO", bp->lab->name);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void
+sp_head::set_info(char *definer, uint definerlen,
+ longlong created, longlong modified,
+ st_sp_chistics *chistics, ulong sql_mode)
+{
+ char *p= strchr(definer, '@');
+ uint len;
+
+ if (! p)
+ p= definer; // Weird...
+ len= p-definer;
+ m_definer_user.str= strmake_root(mem_root, definer, len);
+ m_definer_user.length= len;
+ len= definerlen-len-1;
+ m_definer_host.str= strmake_root(mem_root, p+1, len);
+ m_definer_host.length= len;
+ m_created= created;
+ m_modified= modified;
+ m_chistics= (st_sp_chistics *) memdup_root(mem_root, (char*) chistics,
+ sizeof(*chistics));
+ if (m_chistics->comment.length == 0)
+ m_chistics->comment.str= 0;
+ else
+ m_chistics->comment.str= strmake_root(mem_root,
+ m_chistics->comment.str,
+ m_chistics->comment.length);
+ m_sql_mode= sql_mode;
+}
+
+void
+sp_head::reset_thd_mem_root(THD *thd)
+{
+ DBUG_ENTER("sp_head::reset_thd_mem_root");
+ m_thd_root= thd->mem_root;
+ thd->mem_root= &main_mem_root;
+ DBUG_PRINT("info", ("mem_root 0x%lx moved to thd mem root 0x%lx",
+ (ulong) &mem_root, (ulong) &thd->mem_root));
+ free_list= thd->free_list; // Keep the old list
+ thd->free_list= NULL; // Start a new one
+ /* Copy the db, since substatements will point to it */
+ m_thd_db= thd->db;
+ thd->db= thd->strmake(thd->db, thd->db_length);
+ m_thd= thd;
+ DBUG_VOID_RETURN;
+}
+
+void
+sp_head::restore_thd_mem_root(THD *thd)
+{
+ DBUG_ENTER("sp_head::restore_thd_mem_root");
+ Item *flist= free_list; // The old list
+ set_item_arena(thd); // Get new free_list and mem_root
+ state= INITIALIZED;
+
+ DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
+ (ulong) &mem_root, (ulong) &thd->mem_root));
+ thd->free_list= flist; // Restore the old one
+ thd->db= m_thd_db; // Restore the original db pointer
+ thd->mem_root= m_thd_root;
+ m_thd= NULL;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Check if a user has access right to a routine
+
+ SYNOPSIS
+ check_show_routine_access()
+ thd Thread handler
+ sp SP
+ full_access Set to 1 if the user has SELECT right to the
+ 'mysql.proc' able or is the owner of the routine
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
+{
+ TABLE_LIST tables;
+ bzero((char*) &tables,sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.table_name= tables.alias= (char*) "proc";
+ *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) ||
+ (!strcmp(sp->m_definer_user.str, thd->priv_user) &&
+ !strcmp(sp->m_definer_host.str, thd->priv_host)));
+ if (!*full_access)
+ return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str);
+ return 0;
+}
+
+
+int
+sp_head::show_create_procedure(THD *thd)
+{
+ Protocol *protocol= thd->protocol;
+ char buff[2048];
+ String buffer(buff, sizeof(buff), system_charset_info);
+ int res;
+ List<Item> field_list;
+ ulong old_sql_mode;
+ sys_var *sql_mode_var;
+ byte *sql_mode_str;
+ ulong sql_mode_len;
+ bool full_access;
+
+ DBUG_ENTER("sp_head::show_create_procedure");
+ DBUG_PRINT("info", ("procedure %s", m_name.str));
+ LINT_INIT(sql_mode_str);
+ LINT_INIT(sql_mode_len);
+
+ if (check_show_routine_access(thd, this, &full_access))
+ return 1;
+
+ old_sql_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode= m_sql_mode;
+ sql_mode_var= find_sys_var("SQL_MODE", 8);
+ if (sql_mode_var)
+ {
+ sql_mode_str= sql_mode_var->value_ptr(thd, OPT_SESSION, 0);
+ sql_mode_len= strlen((char*) sql_mode_str);
+ }
+
+ field_list.push_back(new Item_empty_string("Procedure", NAME_LEN));
+ if (sql_mode_var)
+ field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
+ // 1024 is for not to confuse old clients
+ field_list.push_back(new Item_empty_string("Create Procedure",
+ max(buffer.length(), 1024)));
+ if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+ Protocol::SEND_EOF))
+ {
+ res= 1;
+ goto done;
+ }
+ protocol->prepare_for_resend();
+ protocol->store(m_name.str, m_name.length, system_charset_info);
+ if (sql_mode_var)
+ protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
+ if (full_access)
+ protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
+ res= protocol->write();
+ send_eof(thd);
+
+ done:
+ thd->variables.sql_mode= old_sql_mode;
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Add instruction to SP
+
+ SYNOPSIS
+ sp_head::add_instr()
+ instr Instruction
+*/
+
+void sp_head::add_instr(sp_instr *instr)
+{
+ instr->free_list= m_thd->free_list;
+ m_thd->free_list= 0;
+ insert_dynamic(&m_instr, (gptr)&instr);
+}
+
+
+int
+sp_head::show_create_function(THD *thd)
+{
+ Protocol *protocol= thd->protocol;
+ char buff[2048];
+ String buffer(buff, sizeof(buff), system_charset_info);
+ int res;
+ List<Item> field_list;
+ ulong old_sql_mode;
+ sys_var *sql_mode_var;
+ byte *sql_mode_str;
+ ulong sql_mode_len;
+ bool full_access;
+ DBUG_ENTER("sp_head::show_create_function");
+ DBUG_PRINT("info", ("procedure %s", m_name.str));
+ LINT_INIT(sql_mode_str);
+ LINT_INIT(sql_mode_len);
+
+ if (check_show_routine_access(thd, this, &full_access))
+ return 1;
+
+ old_sql_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode= m_sql_mode;
+ sql_mode_var= find_sys_var("SQL_MODE", 8);
+ if (sql_mode_var)
+ {
+ sql_mode_str= sql_mode_var->value_ptr(thd, OPT_SESSION, 0);
+ sql_mode_len= strlen((char*) sql_mode_str);
+ }
+
+ field_list.push_back(new Item_empty_string("Function",NAME_LEN));
+ if (sql_mode_var)
+ field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
+ field_list.push_back(new Item_empty_string("Create Function",
+ max(buffer.length(),1024)));
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ {
+ res= 1;
+ goto done;
+ }
+ protocol->prepare_for_resend();
+ protocol->store(m_name.str, m_name.length, system_charset_info);
+ if (sql_mode_var)
+ protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
+ if (full_access)
+ protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
+ res= protocol->write();
+ send_eof(thd);
+
+ done:
+ thd->variables.sql_mode= old_sql_mode;
+ DBUG_RETURN(res);
+}
+
+void
+sp_head::optimize()
+{
+ List<sp_instr> bp;
+ sp_instr *i;
+ uint src, dst;
+
+ opt_mark(0);
+
+ bp.empty();
+ src= dst= 0;
+ while ((i= get_instr(src)))
+ {
+ if (! i->marked)
+ {
+ delete i;
+ src+= 1;
+ }
+ else
+ {
+ if (src != dst)
+ {
+ sp_instr *ibp;
+ List_iterator_fast<sp_instr> li(bp);
+
+ set_dynamic(&m_instr, (gptr)&i, dst);
+ while ((ibp= li++))
+ {
+ sp_instr_jump *ji= static_cast<sp_instr_jump *>(ibp);
+ if (ji->m_dest == src)
+ ji->m_dest= dst;
+ }
+ }
+ i->opt_move(dst, &bp);
+ src+= 1;
+ dst+= 1;
+ }
+ }
+ m_instr.elements= dst;
+ bp.empty();
+}
+
+void
+sp_head::opt_mark(uint ip)
+{
+ sp_instr *i;
+
+ while ((i= get_instr(ip)) && !i->marked)
+ ip= i->opt_mark(this);
+}
+
+// ------------------------------------------------------------------
+
+
+/*
+ Prepare LEX and thread for execution of instruction, if requested open
+ and lock LEX's tables, execute instruction's core function, perform
+ cleanup afterwards.
+
+ SYNOPSIS
+ reset_lex_and_exec_core()
+ thd - thread context
+ nextp - out - next instruction
+ open_tables - if TRUE then check read access to tables in LEX's table
+ list and open and lock them (used in instructions which
+ need to calculate some expression and don't execute
+ complete statement).
+ sp_instr - instruction for which we prepare context, and which core
+ function execute by calling its exec_core() method.
+
+ NOTE
+ We are not saving/restoring some parts of THD which may need this because
+ we do this once for whole routine execution in sp_head::execute().
+
+ RETURN VALUE
+ 0/non-0 - Success/Failure
+*/
+
+int
+sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
+ bool open_tables, sp_instr* instr)
+{
+ int res= 0;
+
+ DBUG_ASSERT(!thd->derived_tables);
+ DBUG_ASSERT(thd->change_list.is_empty());
+ /*
+ Use our own lex.
+ We should not save old value since it is saved/restored in
+ sp_head::execute() when we are entering/leaving routine.
+ */
+ thd->lex= m_lex;
+
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query_id= next_query_id();
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+
+ /*
+ FIXME. Resetting statement (and using it) is not reentrant, thus recursive
+ functions which try to use the same LEX twice will crash server.
+ We should prevent such situations by tracking if LEX is already
+ in use and throwing error about unallowed recursion if needed.
+ OTOH it is nice to allow recursion in cases when LEX is not really
+ used (e.g. in mathematical functions), so such tracking should be
+ implemented at the same time as ability not to store LEX for
+ instruction if it is not really used.
+ */
+ reset_stmt_for_execute(thd, m_lex);
+
+ /*
+ If requested check whenever we have access to tables in LEX's table list
+ and open and lock them before executing instructtions core function.
+ */
+ if (open_tables &&
+ (check_table_access(thd, SELECT_ACL, m_lex->query_tables, 0) ||
+ open_and_lock_tables(thd, m_lex->query_tables)))
+ res= -1;
+
+ if (!res)
+ res= instr->exec_core(thd, nextp);
+
+ m_lex->unit.cleanup();
+
+ thd->proc_info="closing tables";
+ close_thread_tables(thd);
+
+ thd->rollback_item_tree_changes();
+
+ /*
+ Unlike for PS we should not call Item's destructors for newly created
+ items after execution of each instruction in stored routine. This is
+ because SP often create Item (like Item_int, Item_string etc...) when
+ 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;
+}
+
+
+//
+// sp_instr
+//
+int sp_instr::exec_core(THD *thd, uint *nextp)
+{
+ DBUG_ASSERT(0);
+ return 0;
+}
+
+
+//
+// sp_instr_stmt
+//
+int
+sp_instr_stmt::execute(THD *thd, uint *nextp)
+{
+ char *query;
+ uint32 query_length;
+ DBUG_ENTER("sp_instr_stmt::execute");
+ DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command()));
+ int res;
+
+ query= thd->query;
+ query_length= thd->query_length;
+ if (!(res= alloc_query(thd, m_query.str, m_query.length+1)))
+ {
+ if (query_cache_send_result_to_client(thd,
+ thd->query, thd->query_length) <= 0)
+ {
+ res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
+ query_cache_end_of_result(thd);
+ }
+ else
+ *nextp= m_ip+1;
+ thd->query= query;
+ thd->query_length= query_length;
+ }
+ DBUG_RETURN(res);
+}
+
+void
+sp_instr_stmt::print(String *str)
+{
+ str->reserve(12);
+ str->append("stmt ");
+ str->qs_append((uint)m_lex_keeper.sql_command());
+}
+
+
+int
+sp_instr_stmt::exec_core(THD *thd, uint *nextp)
+{
+ int res= mysql_execute_command(thd);
+ *nextp= m_ip+1;
+ return res;
+}
+
+//
+// sp_instr_set
+//
+int
+sp_instr_set::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_set::execute");
+ DBUG_PRINT("info", ("offset: %u", m_offset));
+
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+int
+sp_instr_set::exec_core(THD *thd, uint *nextp)
+{
+ Item *it;
+ int res;
+
+ it= sp_eval_func_item(thd, m_value, m_type);
+ if (! it)
+ res= -1;
+ else
+ {
+ res= 0;
+ thd->spcont->set_item(m_offset, it);
+ }
+ *nextp = m_ip+1;
+
+ return res;
+}
+
+void
+sp_instr_set::print(String *str)
+{
+ str->reserve(12);
+ str->append("set ");
+ str->qs_append(m_offset);
+ str->append(' ');
+ m_value->print(str);
+}
+
+
+//
+// sp_instr_set_trigger_field
+//
+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))
+ res= -1;
+ *nextp= m_ip + 1;
+ DBUG_RETURN(res);
+}
+
+void
+sp_instr_set_trigger_field::print(String *str)
+{
+ str->append("set ", 4);
+ trigger_field.print(str);
+ str->append(":=", 2);
+ value->print(str);
+}
+
+//
+// sp_instr_jump
+//
+int
+sp_instr_jump::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_jump::execute");
+ DBUG_PRINT("info", ("destination: %u", m_dest));
+
+ *nextp= m_dest;
+ DBUG_RETURN(0);
+}
+
+void
+sp_instr_jump::print(String *str)
+{
+ str->reserve(12);
+ str->append("jump ");
+ str->qs_append(m_dest);
+}
+
+uint
+sp_instr_jump::opt_mark(sp_head *sp)
+{
+ m_dest= opt_shortcut_jump(sp, this);
+ if (m_dest != m_ip+1) /* Jumping to following instruction? */
+ marked= 1;
+ m_optdest= sp->get_instr(m_dest);
+ return m_dest;
+}
+
+uint
+sp_instr_jump::opt_shortcut_jump(sp_head *sp, sp_instr *start)
+{
+ uint dest= m_dest;
+ sp_instr *i;
+
+ while ((i= sp->get_instr(dest)))
+ {
+ uint ndest;
+
+ if (start == i || this == i)
+ break;
+ ndest= i->opt_shortcut_jump(sp, start);
+ if (ndest == dest)
+ break;
+ dest= ndest;
+ }
+ return dest;
+}
+
+void
+sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp)
+{
+ if (m_dest > m_ip)
+ bp->push_back(this); // Forward
+ else if (m_optdest)
+ m_dest= m_optdest->m_ip; // Backward
+ m_ip= dst;
+}
+
+//
+// sp_instr_jump_if
+//
+
+int
+sp_instr_jump_if::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_jump_if::execute");
+ DBUG_PRINT("info", ("destination: %u", m_dest));
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+int
+sp_instr_jump_if::exec_core(THD *thd, uint *nextp)
+{
+ Item *it;
+ int res;
+
+ it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
+ if (!it)
+ res= -1;
+ else
+ {
+ res= 0;
+ if (it->val_int())
+ *nextp = m_dest;
+ else
+ *nextp = m_ip+1;
+ }
+
+ return res;
+}
+
+void
+sp_instr_jump_if::print(String *str)
+{
+ str->reserve(12);
+ str->append("jump_if ");
+ str->qs_append(m_dest);
+ str->append(' ');
+ m_expr->print(str);
+}
+
+uint
+sp_instr_jump_if::opt_mark(sp_head *sp)
+{
+ sp_instr *i;
+
+ marked= 1;
+ if ((i= sp->get_instr(m_dest)))
+ {
+ m_dest= i->opt_shortcut_jump(sp, this);
+ m_optdest= sp->get_instr(m_dest);
+ }
+ sp->opt_mark(m_dest);
+ return m_ip+1;
+}
+
+//
+// sp_instr_jump_if_not
+//
+int
+sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_jump_if_not::execute");
+ DBUG_PRINT("info", ("destination: %u", m_dest));
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+
+int
+sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
+{
+ Item *it;
+ int res;
+
+ it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
+ if (! it)
+ res= -1;
+ else
+ {
+ res= 0;
+ if (! it->val_int())
+ *nextp = m_dest;
+ else
+ *nextp = m_ip+1;
+ }
+
+ return res;
+}
+
+void
+sp_instr_jump_if_not::print(String *str)
+{
+ str->reserve(16);
+ str->append("jump_if_not ");
+ str->qs_append(m_dest);
+ str->append(' ');
+ m_expr->print(str);
+}
+
+uint
+sp_instr_jump_if_not::opt_mark(sp_head *sp)
+{
+ sp_instr *i;
+
+ marked= 1;
+ if ((i= sp->get_instr(m_dest)))
+ {
+ m_dest= i->opt_shortcut_jump(sp, this);
+ m_optdest= sp->get_instr(m_dest);
+ }
+ sp->opt_mark(m_dest);
+ return m_ip+1;
+}
+
+//
+// sp_instr_freturn
+//
+
+int
+sp_instr_freturn::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_freturn::execute");
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+
+int
+sp_instr_freturn::exec_core(THD *thd, uint *nextp)
+{
+ Item *it;
+ int res;
+
+ it= sp_eval_func_item(thd, m_value, m_type);
+ if (! it)
+ res= -1;
+ else
+ {
+ res= 0;
+ thd->spcont->set_result(it);
+ }
+ *nextp= UINT_MAX;
+
+ return res;
+}
+
+void
+sp_instr_freturn::print(String *str)
+{
+ str->reserve(12);
+ str->append("freturn ");
+ str->qs_append((uint)m_type);
+ str->append(' ');
+ m_value->print(str);
+}
+
+//
+// sp_instr_hpush_jump
+//
+int
+sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_hpush_jump::execute");
+ List_iterator_fast<sp_cond_type_t> li(m_cond);
+ sp_cond_type_t *p;
+
+ while ((p= li++))
+ thd->spcont->push_handler(p, m_handler, m_type, m_frame);
+
+ *nextp= m_dest;
+ DBUG_RETURN(0);
+}
+
+void
+sp_instr_hpush_jump::print(String *str)
+{
+ str->reserve(32);
+ str->append("hpush_jump ");
+ str->qs_append(m_dest);
+ str->append(" t=");
+ str->qs_append(m_type);
+ str->append(" f=");
+ str->qs_append(m_frame);
+ str->append(" h=");
+ str->qs_append(m_handler);
+}
+
+uint
+sp_instr_hpush_jump::opt_mark(sp_head *sp)
+{
+ sp_instr *i;
+
+ marked= 1;
+ if ((i= sp->get_instr(m_dest)))
+ {
+ m_dest= i->opt_shortcut_jump(sp, this);
+ m_optdest= sp->get_instr(m_dest);
+ }
+ sp->opt_mark(m_dest);
+ return m_ip+1;
+}
+
+//
+// sp_instr_hpop
+//
+int
+sp_instr_hpop::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_hpop::execute");
+ thd->spcont->pop_handlers(m_count);
+ *nextp= m_ip+1;
+ DBUG_RETURN(0);
+}
+
+void
+sp_instr_hpop::print(String *str)
+{
+ str->reserve(12);
+ str->append("hpop ");
+ str->qs_append(m_count);
+}
+
+void
+sp_instr_hpop::backpatch(uint dest, sp_pcontext *dst_ctx)
+{
+ m_count= m_ctx->diff_handlers(dst_ctx);
+}
+
+
+//
+// sp_instr_hreturn
+//
+int
+sp_instr_hreturn::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_hreturn::execute");
+ if (m_dest)
+ *nextp= m_dest;
+ else
+ {
+ thd->spcont->restore_variables(m_frame);
+ *nextp= thd->spcont->pop_hstack();
+ }
+ thd->spcont->in_handler= FALSE;
+ DBUG_RETURN(0);
+}
+
+void
+sp_instr_hreturn::print(String *str)
+{
+ str->reserve(16);
+ str->append("hreturn ");
+ str->qs_append(m_frame);
+ if (m_dest)
+ str->qs_append(m_dest);
+}
+
+uint
+sp_instr_hreturn::opt_mark(sp_head *sp)
+{
+ if (m_dest)
+ return sp_instr_jump::opt_mark(sp);
+ else
+ {
+ marked= 1;
+ return UINT_MAX;
+ }
+}
+
+
+//
+// sp_instr_cpush
+//
+int
+sp_instr_cpush::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_cpush::execute");
+ thd->spcont->push_cursor(&m_lex_keeper);
+ *nextp= m_ip+1;
+ DBUG_RETURN(0);
+}
+
+void
+sp_instr_cpush::print(String *str)
+{
+ str->append("cpush");
+}
+
+//
+// sp_instr_cpop
+//
+int
+sp_instr_cpop::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_cpop::execute");
+ thd->spcont->pop_cursors(m_count);
+ *nextp= m_ip+1;
+ DBUG_RETURN(0);
+}
+
+void
+sp_instr_cpop::print(String *str)
+{
+ str->reserve(12);
+ str->append("cpop ");
+ str->qs_append(m_count);
+}
+
+void
+sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx)
+{
+ m_count= m_ctx->diff_cursors(dst_ctx);
+}
+
+//
+// sp_instr_copen
+//
+int
+sp_instr_copen::execute(THD *thd, uint *nextp)
+{
+ sp_cursor *c= thd->spcont->get_cursor(m_cursor);
+ int res;
+ DBUG_ENTER("sp_instr_copen::execute");
+
+ if (! c)
+ res= -1;
+ else
+ {
+ sp_lex_keeper *lex_keeper= c->pre_open(thd);
+
+ if (!lex_keeper)
+ {
+ res= -1;
+ *nextp= m_ip+1;
+ }
+ else
+ res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
+
+ c->post_open(thd, (lex_keeper ? TRUE : FALSE));
+ }
+
+ DBUG_RETURN(res);
+}
+
+int
+sp_instr_copen::exec_core(THD *thd, uint *nextp)
+{
+ int res= mysql_execute_command(thd);
+ *nextp= m_ip+1;
+ return res;
+}
+
+void
+sp_instr_copen::print(String *str)
+{
+ str->reserve(12);
+ str->append("copen ");
+ str->qs_append(m_cursor);
+}
+
+//
+// sp_instr_cclose
+//
+int
+sp_instr_cclose::execute(THD *thd, uint *nextp)
+{
+ sp_cursor *c= thd->spcont->get_cursor(m_cursor);
+ int res;
+ DBUG_ENTER("sp_instr_cclose::execute");
+
+ if (! c)
+ res= -1;
+ else
+ res= c->close(thd);
+ *nextp= m_ip+1;
+ DBUG_RETURN(res);
+}
+
+void
+sp_instr_cclose::print(String *str)
+{
+ str->reserve(12);
+ str->append("cclose ");
+ str->qs_append(m_cursor);
+}
+
+//
+// sp_instr_cfetch
+//
+int
+sp_instr_cfetch::execute(THD *thd, uint *nextp)
+{
+ sp_cursor *c= thd->spcont->get_cursor(m_cursor);
+ int res;
+ DBUG_ENTER("sp_instr_cfetch::execute");
+
+ if (! c)
+ res= -1;
+ else
+ res= c->fetch(thd, &m_varlist);
+ *nextp= m_ip+1;
+ DBUG_RETURN(res);
+}
+
+void
+sp_instr_cfetch::print(String *str)
+{
+ List_iterator_fast<struct sp_pvar> li(m_varlist);
+ sp_pvar_t *pv;
+
+ str->reserve(12);
+ str->append("cfetch ");
+ str->qs_append(m_cursor);
+ while ((pv= li++))
+ {
+ str->reserve(8);
+ str->append(' ');
+ str->qs_append(pv->offset);
+ }
+}
+
+//
+// sp_instr_error
+//
+int
+sp_instr_error::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_error::execute");
+
+ my_message(m_errcode, ER(m_errcode), MYF(0));
+ *nextp= m_ip+1;
+ DBUG_RETURN(-1);
+}
+
+void
+sp_instr_error::print(String *str)
+{
+ str->reserve(12);
+ str->append("error ");
+ str->qs_append(m_errcode);
+}
+
+/* ------------------------------------------------------------------ */
+
+
+//
+// Security context swapping
+//
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+void
+sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
+{
+ ctxp->changed= (sp->m_chistics->suid != SP_IS_NOT_SUID &&
+ (strcmp(sp->m_definer_user.str, thd->priv_user) ||
+ strcmp(sp->m_definer_host.str, thd->priv_host)));
+
+ if (ctxp->changed)
+ {
+ ctxp->master_access= thd->master_access;
+ ctxp->db_access= thd->db_access;
+ ctxp->priv_user= thd->priv_user;
+ strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host));
+ ctxp->user= thd->user;
+ ctxp->host= thd->host;
+ ctxp->ip= thd->ip;
+
+ /* Change thise just to do the acl_getroot_no_password */
+ thd->user= sp->m_definer_user.str;
+ thd->host= thd->ip = sp->m_definer_host.str;
+
+ if (acl_getroot_no_password(thd))
+ { // Failed, run as invoker for now
+ ctxp->changed= FALSE;
+ thd->master_access= ctxp->master_access;
+ thd->db_access= ctxp->db_access;
+ thd->priv_user= ctxp->priv_user;
+ strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
+ }
+
+ /* Restore these immiediately */
+ thd->user= ctxp->user;
+ thd->host= ctxp->host;
+ thd->ip= ctxp->ip;
+ }
+}
+
+void
+sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
+{
+ if (ctxp->changed)
+ {
+ ctxp->changed= FALSE;
+ thd->master_access= ctxp->master_access;
+ thd->db_access= ctxp->db_access;
+ thd->priv_user= ctxp->priv_user;
+ strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
+ }
+}
+
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+/*
+ Structure that represent all instances of one table
+ in optimized multi-set of tables used by routine.
+*/
+
+typedef struct st_sp_table
+{
+ LEX_STRING qname;
+ bool temp;
+ TABLE_LIST *table;
+ /*
+ We can't use table->lock_type as lock type for table
+ in multi-set since it can be changed by statement during
+ its execution (e.g. as this happens for multi-update).
+ */
+ thr_lock_type lock_type;
+ uint lock_count;
+ uint query_lock_count;
+} SP_TABLE;
+
+byte *
+sp_table_key(const byte *ptr, uint *plen, my_bool first)
+{
+ SP_TABLE *tab= (SP_TABLE *)ptr;
+ *plen= tab->qname.length;
+ return (byte *)tab->qname.str;
+}
+
+
+/*
+ Merge the list of tables used by some query into the multi-set of
+ tables used by routine.
+
+ SYNOPSIS
+ merge_table_list()
+ thd - thread context
+ table - table list
+ lex_for_tmp_check - LEX of the query for which we are merging
+ table list.
+
+ NOTE
+ This method will use LEX provided to check whenever we are creating
+ temporary table and mark it as such in target multi-set.
+
+ RETURN VALUE
+ TRUE - Success
+ FALSE - Error
+*/
+
+bool
+sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
+{
+ SP_TABLE *tab;
+
+ if (lex_for_tmp_check->sql_command == SQLCOM_DROP_TABLE &&
+ lex_for_tmp_check->drop_temporary)
+ return TRUE;
+
+ for (uint i= 0 ; i < m_sptabs.records ; i++)
+ {
+ tab= (SP_TABLE *)hash_element(&m_sptabs, i);
+ tab->query_lock_count= 0;
+ }
+
+ for (; table ; table= table->next_global)
+ if (!table->derived && !table->schema_table)
+ {
+ char tname[64+1+64+1+64+1]; // db.table.alias\0
+ uint tlen, alen;
+
+ tlen= table->db_length;
+ memcpy(tname, table->db, tlen);
+ tname[tlen++]= '.';
+ memcpy(tname+tlen, table->table_name, table->table_name_length);
+ tlen+= table->table_name_length;
+ tname[tlen++]= '.';
+ alen= strlen(table->alias);
+ memcpy(tname+tlen, table->alias, alen);
+ tlen+= alen;
+ tname[tlen]= '\0';
+
+ /*
+ It is safe to store pointer to table list elements in hash,
+ since they are supposed to have the same lifetime.
+ */
+ if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)))
+ {
+ if (tab->lock_type < table->lock_type)
+ tab->lock_type= table->lock_type; // Use the table with the highest lock type
+ tab->query_lock_count++;
+ if (tab->query_lock_count > tab->lock_count)
+ tab->lock_count++;
+ }
+ else
+ {
+ if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
+ return FALSE;
+ tab->qname.length= tlen;
+ tab->qname.str= (char *)thd->strmake(tname, tab->qname.length);
+ if (!tab->qname.str)
+ return FALSE;
+ if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
+ lex_for_tmp_check->query_tables == table &&
+ lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ tab->temp= TRUE;
+ tab->table= table;
+ tab->lock_type= table->lock_type;
+ tab->lock_count= tab->query_lock_count= 1;
+ my_hash_insert(&m_sptabs, (byte *)tab);
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ Add tables used by routine to the table list.
+
+ SYNOPSIS
+ add_used_tables_to_table_list()
+ thd - thread context
+ query_tables_last_ptr - (in/out) pointer the next_global member of last
+ element of the list where tables will be added
+ (or to its root).
+
+ DESCRIPTION
+ Converts multi-set of tables used by this routine to table list and adds
+ this list to the end of table list specified by 'query_tables_last_ptr'.
+
+ Elements of list will be allocated in PS memroot, so this list will be
+ persistent between PS executions.
+
+ RETURN VALUE
+ TRUE - if some elements were added, FALSE - otherwise.
+*/
+
+bool
+sp_head::add_used_tables_to_table_list(THD *thd,
+ TABLE_LIST ***query_tables_last_ptr)
+{
+ uint i;
+ Item_arena *arena, backup;
+ bool result= FALSE;
+ DBUG_ENTER("sp_head::add_used_tables_to_table_list");
+
+ /*
+ Use persistent arena for table list allocation to be PS friendly.
+ */
+ arena= thd->change_arena_if_needed(&backup);
+
+ for (i=0 ; i < m_sptabs.records ; i++)
+ {
+ char *tab_buff;
+ TABLE_LIST *table, *otable;
+ SP_TABLE *stab= (SP_TABLE *)hash_element(&m_sptabs, i);
+ if (stab->temp)
+ continue;
+
+ otable= stab->table;
+
+ if (!(tab_buff= (char *)thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST)) *
+ stab->lock_count)))
+ DBUG_RETURN(FALSE);
+
+ for (uint j= 0; j < stab->lock_count; j++)
+ {
+ table= (TABLE_LIST *)tab_buff;
+
+ /*
+ It's enough to just copy the pointers as the data will not change
+ during the lifetime of the SP. If the SP is used by PS, we assume
+ that the PS will be invalidated if the functions is deleted or
+ changed.
+ */
+ table->db= otable->db;
+ table->db_length= otable->db_length;
+ table->alias= otable->alias;
+ table->table_name= otable->table_name;
+ table->table_name_length= otable->table_name_length;
+ table->lock_type= stab->lock_type;
+ table->cacheable_table= 1;
+ table->prelocking_placeholder= 1;
+
+ /* Everyting else should be zeroed */
+
+ **query_tables_last_ptr= table;
+ table->prev_global= *query_tables_last_ptr;
+ *query_tables_last_ptr= &table->next_global;
+
+ tab_buff+= ALIGN_SIZE(sizeof(TABLE_LIST));
+ result= TRUE;
+ }
+ }
+
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+
+ DBUG_RETURN(result);
+}
+
+/*
+ * Simple function for adding an explicetly named (systems) table to
+ * the global table list, e.g. "mysql", "proc".
+ *
+ */
+TABLE_LIST *
+sp_add_to_query_tables(THD *thd, LEX *lex,
+ const char *db, const char *name,
+ thr_lock_type locktype)
+{
+ TABLE_LIST *table;
+
+ if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
+ {
+ my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST));
+ return NULL;
+ }
+ table->db_length= strlen(db);
+ table->db= thd->strmake(db, table->db_length);
+ table->table_name_length= strlen(name);
+ table->table_name= thd->strmake(name, table->table_name_length);
+ table->alias= thd->strdup(name);
+ table->lock_type= locktype;
+ table->select_lex= lex->current_select; // QQ?
+ table->cacheable_table= 1;
+
+ lex->add_to_query_tables(table);
+ 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
new file mode 100644
index 00000000000..ee41b1efc83
--- /dev/null
+++ b/sql/sp_head.h
@@ -0,0 +1,954 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _SP_HEAD_H_
+#define _SP_HEAD_H_
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#include <stddef.h>
+
+// Values for the type enum. This reflects the order of the enum declaration
+// in the CREATE TABLE command.
+#define TYPE_ENUM_FUNCTION 1
+#define TYPE_ENUM_PROCEDURE 2
+#define TYPE_ENUM_TRIGGER 3
+
+Item_result
+sp_map_result_type(enum enum_field_types type);
+
+bool
+sp_multi_results_command(enum enum_sql_command cmd);
+
+struct sp_label;
+class sp_instr;
+struct sp_cond_type;
+struct sp_pvar;
+
+class sp_name : public Sql_alloc
+{
+public:
+
+ LEX_STRING m_db;
+ LEX_STRING m_name;
+ LEX_STRING m_qname;
+
+ sp_name(LEX_STRING name)
+ : m_name(name)
+ {
+ m_db.str= m_qname.str= 0;
+ m_db.length= m_qname.length= 0;
+ }
+
+ sp_name(LEX_STRING db, LEX_STRING name)
+ : m_db(db), m_name(name)
+ {
+ m_qname.str= 0;
+ m_qname.length= 0;
+ }
+
+ // Init. the qualified name from the db and name.
+ void init_qname(THD *thd); // thd for memroot allocation
+
+ ~sp_name()
+ {}
+};
+
+sp_name *
+sp_name_current_db_new(THD *thd, LEX_STRING name);
+
+
+class sp_head :private Item_arena
+{
+ sp_head(const sp_head &); /* Prevent use of these */
+ void operator=(sp_head &);
+
+public:
+
+ int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
+ enum enum_field_types m_returns; // For FUNCTIONs only
+ CHARSET_INFO *m_returns_cs; // For FUNCTIONs only
+ TYPELIB *m_returns_typelib; // For FUNCTIONs only
+ uint m_returns_len; // For FUNCTIONs only
+ uint m_returns_pack; // For FUNCTIONs only
+ my_bool m_has_return; // For FUNCTIONs only
+ my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
+ my_bool m_multi_results; // TRUE if a procedure with SELECT(s)
+ my_bool m_in_handler; // TRUE if parser in a handler body
+ uchar *m_tmp_query; // Temporary pointer to sub query string
+ uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
+ st_sp_chistics *m_chistics;
+ ulong m_sql_mode; // For SHOW CREATE
+ LEX_STRING m_qname; // db.name
+ LEX_STRING m_db;
+ LEX_STRING m_name;
+ LEX_STRING m_params;
+ LEX_STRING m_body;
+ LEX_STRING m_defstr;
+ LEX_STRING m_definer_user;
+ LEX_STRING m_definer_host;
+ 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.
+ */
+ HASH m_spfuns, m_spprocs;
+ // Pointers set during parsing
+ uchar *m_param_begin, *m_param_end, *m_body_begin;
+
+ static void *
+ operator new(size_t size);
+
+ static void
+ operator delete(void *ptr, size_t size);
+
+ sp_head();
+
+ // Initialize after we have reset mem_root
+ void
+ init(LEX *lex);
+
+ // Initialize strings after parsing header
+ void
+ init_strings(THD *thd, LEX *lex, sp_name *name);
+
+ TYPELIB *
+ create_typelib(List<String> *src);
+
+ int
+ create(THD *thd);
+
+ virtual ~sp_head();
+
+ // Free memory
+ void
+ destroy();
+
+ int
+ execute_function(THD *thd, Item **args, uint argcount, Item **resp);
+
+ int
+ execute_procedure(THD *thd, List<Item> *args);
+
+ int
+ show_create_procedure(THD *thd);
+
+ int
+ show_create_function(THD *thd);
+
+ void
+ add_instr(sp_instr *instr);
+
+ inline uint
+ instructions()
+ {
+ return m_instr.elements;
+ }
+
+ inline sp_instr *
+ last_instruction()
+ {
+ sp_instr *i;
+
+ get_dynamic(&m_instr, (gptr)&i, m_instr.elements-1);
+ return i;
+ }
+
+ // Resets lex in 'thd' and keeps a copy of the old one.
+ void
+ reset_lex(THD *thd);
+
+ // Restores lex in 'thd' from our copy, but keeps some status from the
+ // one in 'thd', like ptr, tables, fields, etc.
+ void
+ restore_lex(THD *thd);
+
+ // Put the instruction on the backpatch list, associated with the label.
+ void
+ push_backpatch(sp_instr *, struct sp_label *);
+
+ // Update all instruction with this label in the backpatch list to
+ // the current position.
+ void
+ backpatch(struct sp_label *);
+
+ // Check that no unresolved references exist.
+ // If none found, 0 is returned, otherwise errors have been issued
+ // and -1 is returned.
+ // This is called by the parser at the end of a create procedure/function.
+ int
+ check_backpatch(THD *thd);
+
+ char *name(uint *lenp = 0) const
+ {
+ if (lenp)
+ *lenp= m_name.length;
+ return m_name.str;
+ }
+
+ char *create_string(THD *thd, ulong *lenp);
+
+ Field *make_field(uint max_length, const char *name, TABLE *dummy);
+
+ void set_info(char *definer, uint definerlen,
+ longlong created, longlong modified,
+ st_sp_chistics *chistics, ulong sql_mode);
+
+ void reset_thd_mem_root(THD *thd);
+
+ void restore_thd_mem_root(THD *thd);
+
+ void optimize();
+ void opt_mark(uint ip);
+
+ inline sp_instr *
+ get_instr(uint i)
+ {
+ sp_instr *ip;
+
+ if (i < m_instr.elements)
+ get_dynamic(&m_instr, (gptr)&ip, i);
+ else
+ ip= NULL;
+ return ip;
+ }
+
+ /* Add tables used by routine to the table list. */
+ bool add_used_tables_to_table_list(THD *thd,
+ TABLE_LIST ***query_tables_last_ptr);
+
+private:
+
+ MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root
+ THD *m_thd; // Set if we have reset mem_root
+ char *m_thd_db; // Original thd->db pointer
+
+ sp_pcontext *m_pcont; // Parse context
+ List<LEX> m_lex; // Temp. store for the other lex
+ DYNAMIC_ARRAY m_instr; // The "instructions"
+ typedef struct
+ {
+ struct sp_label *lab;
+ sp_instr *instr;
+ } bp_t;
+ List<bp_t> m_backpatch; // Instructions needing backpatching
+ /*
+ Multi-set representing optimized list of tables to be locked by this
+ routine. Does not include tables which are used by invoked routines.
+ */
+ HASH m_sptabs;
+
+ int
+ execute(THD *thd);
+
+ /*
+ Merge the list of tables used by query into the multi-set of tables used
+ by routine.
+ */
+ bool merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check);
+}; // class sp_head : public Sql_alloc
+
+
+//
+// "Instructions"...
+//
+
+class sp_instr : public Sql_alloc
+{
+ sp_instr(const sp_instr &); /* Prevent use of these */
+ void operator=(sp_instr &);
+
+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)
+ {}
+
+ virtual ~sp_instr()
+ { free_items(free_list); }
+
+ // Execute this instrution. '*nextp' will be set to the index of the next
+ // instruction to execute. (For most instruction this will be the
+ // instruction following this one.)
+ // Returns 0 on success, non-zero if some error occured.
+ virtual int execute(THD *thd, uint *nextp) = 0;
+
+ /*
+ Execute core function of instruction after all preparations (e.g.
+ setting of proper LEX, saving part of the thread context have been
+ done).
+
+ Should be implemented for instructions using expressions or whole
+ statements (thus having to have own LEX). Used in concert with
+ sp_lex_keeper class and its descendants.
+ */
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str) = 0;
+
+ virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
+ {}
+
+ virtual uint opt_mark(sp_head *sp)
+ {
+ marked= 1;
+ return m_ip+1;
+ }
+
+ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
+ {
+ return m_ip;
+ }
+
+ virtual void opt_move(uint dst, List<sp_instr> *ibp)
+ {
+ m_ip= dst;
+ }
+
+}; // class sp_instr : public Sql_alloc
+
+
+/*
+ Auxilary class to which instructions delegate responsibility
+ for handling LEX and preparations before executing statement
+ or calculating complex expression.
+
+ Exist mainly to avoid having double hierarchy between instruction
+ classes.
+
+ TODO: Add ability to not store LEX and do any preparations if
+ expression used is simple.
+*/
+
+class sp_lex_keeper
+{
+ /* Prevent use of these */
+ sp_lex_keeper(const sp_lex_keeper &);
+ void operator=(sp_lex_keeper &);
+public:
+
+ sp_lex_keeper(LEX *lex, bool lex_resp)
+ : m_lex(lex), m_lex_resp(lex_resp)
+ {
+ lex->sp_lex_in_use= TRUE;
+ }
+ virtual ~sp_lex_keeper()
+ {
+ if (m_lex_resp)
+ delete m_lex;
+ }
+
+ /*
+ Prepare execution of instruction using LEX, if requested check whenever
+ we have read access to tables used and open/lock them, call instruction's
+ exec_core() method, perform cleanup afterwards.
+ */
+ int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables,
+ sp_instr* instr);
+
+ inline uint sql_command() const
+ {
+ return (uint)m_lex->sql_command;
+ }
+
+private:
+
+ LEX *m_lex;
+ /*
+ Indicates whenever this sp_lex_keeper instance responsible
+ for LEX deletion.
+ */
+ bool m_lex_resp;
+};
+
+
+//
+// Call out to some prepared SQL statement.
+//
+class sp_instr_stmt : public sp_instr
+{
+ sp_instr_stmt(const sp_instr_stmt &); /* Prevent use of these */
+ void operator=(sp_instr_stmt &);
+
+public:
+
+ LEX_STRING m_query; // For thd->query
+
+ sp_instr_stmt(uint ip, sp_pcontext *ctx, LEX *lex)
+ : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
+ {
+ m_query.str= 0;
+ m_query.length= 0;
+ }
+
+ virtual ~sp_instr_stmt()
+ {};
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+private:
+
+ sp_lex_keeper m_lex_keeper;
+
+}; // class sp_instr_stmt : public sp_instr
+
+
+class sp_instr_set : public sp_instr
+{
+ sp_instr_set(const sp_instr_set &); /* Prevent use of these */
+ void operator=(sp_instr_set &);
+
+public:
+
+ sp_instr_set(uint ip, sp_pcontext *ctx,
+ uint offset, Item *val, enum enum_field_types type,
+ LEX *lex, bool lex_resp)
+ : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type),
+ m_lex_keeper(lex, lex_resp)
+ {}
+
+ virtual ~sp_instr_set()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+private:
+
+ uint m_offset; // Frame offset
+ Item *m_value;
+ enum enum_field_types m_type; // The declared type
+ sp_lex_keeper m_lex_keeper;
+
+}; // class sp_instr_set : public sp_instr
+
+
+/*
+ Set NEW/OLD row field value instruction. Used in triggers.
+*/
+class sp_instr_set_trigger_field : public sp_instr
+{
+ sp_instr_set_trigger_field(const sp_instr_set_trigger_field &);
+ void operator=(sp_instr_set_trigger_field &);
+
+public:
+
+ sp_instr_set_trigger_field(uint ip, sp_pcontext *ctx,
+ LEX_STRING field_name, Item *val)
+ : sp_instr(ip, ctx),
+ trigger_field(Item_trigger_field::NEW_ROW, field_name.str),
+ value(val)
+ {}
+
+ virtual ~sp_instr_set_trigger_field()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ Item_trigger_field trigger_field;
+
+private:
+ Item *value;
+}; // class sp_instr_trigger_field : public sp_instr
+
+
+class sp_instr_jump : public sp_instr
+{
+ sp_instr_jump(const sp_instr_jump &); /* Prevent use of these */
+ void operator=(sp_instr_jump &);
+
+public:
+
+ uint m_dest; // Where we will go
+
+ sp_instr_jump(uint ip, sp_pcontext *ctx)
+ : sp_instr(ip, ctx), m_dest(0), m_optdest(0)
+ {}
+
+ sp_instr_jump(uint ip, sp_pcontext *ctx, uint dest)
+ : sp_instr(ip, ctx), m_dest(dest), m_optdest(0)
+ {}
+
+ virtual ~sp_instr_jump()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ virtual uint opt_mark(sp_head *sp);
+
+ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start);
+
+ virtual void opt_move(uint dst, List<sp_instr> *ibp);
+
+ virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
+ {
+ if (m_dest == 0) // Don't reset
+ m_dest= dest;
+ }
+
+protected:
+
+ sp_instr *m_optdest; // Used during optimization
+
+}; // class sp_instr_jump : public sp_instr
+
+
+class sp_instr_jump_if : public sp_instr_jump
+{
+ sp_instr_jump_if(const sp_instr_jump_if &); /* Prevent use of these */
+ void operator=(sp_instr_jump_if &);
+
+public:
+
+ sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
+ : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
+ {}
+
+ sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
+ : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
+ {}
+
+ virtual ~sp_instr_jump_if()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ virtual uint opt_mark(sp_head *sp);
+
+ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
+ {
+ return m_ip;
+ }
+
+private:
+
+ Item *m_expr; // The condition
+ sp_lex_keeper m_lex_keeper;
+
+}; // class sp_instr_jump_if : public sp_instr_jump
+
+
+class sp_instr_jump_if_not : public sp_instr_jump
+{
+ sp_instr_jump_if_not(const sp_instr_jump_if_not &); /* Prevent use of these */
+ void operator=(sp_instr_jump_if_not &);
+
+public:
+
+ sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
+ : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
+ {}
+
+ sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
+ : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
+ {}
+
+ virtual ~sp_instr_jump_if_not()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ virtual uint opt_mark(sp_head *sp);
+
+ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
+ {
+ return m_ip;
+ }
+
+private:
+
+ Item *m_expr; // The condition
+ sp_lex_keeper m_lex_keeper;
+
+}; // class sp_instr_jump_if_not : public sp_instr_jump
+
+
+class sp_instr_freturn : public sp_instr
+{
+ sp_instr_freturn(const sp_instr_freturn &); /* Prevent use of these */
+ void operator=(sp_instr_freturn &);
+
+public:
+
+ sp_instr_freturn(uint ip, sp_pcontext *ctx,
+ Item *val, enum enum_field_types type, LEX *lex)
+ : sp_instr(ip, ctx), m_value(val), m_type(type), m_lex_keeper(lex, TRUE)
+ {}
+
+ virtual ~sp_instr_freturn()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ virtual uint opt_mark(sp_head *sp)
+ {
+ marked= 1;
+ return UINT_MAX;
+ }
+
+protected:
+
+ Item *m_value;
+ enum enum_field_types m_type;
+ sp_lex_keeper m_lex_keeper;
+
+}; // class sp_instr_freturn : public sp_instr
+
+
+class sp_instr_hpush_jump : public sp_instr_jump
+{
+ sp_instr_hpush_jump(const sp_instr_hpush_jump &); /* Prevent use of these */
+ void operator=(sp_instr_hpush_jump &);
+
+public:
+
+ sp_instr_hpush_jump(uint ip, sp_pcontext *ctx, int htype, uint fp)
+ : sp_instr_jump(ip, ctx), m_type(htype), m_frame(fp)
+ {
+ m_handler= ip+1;
+ m_cond.empty();
+ }
+
+ virtual ~sp_instr_hpush_jump()
+ {
+ m_cond.empty();
+ }
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ virtual uint opt_mark(sp_head *sp);
+
+ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
+ {
+ return m_ip;
+ }
+
+ inline void add_condition(struct sp_cond_type *cond)
+ {
+ m_cond.push_front(cond);
+ }
+
+private:
+
+ int m_type; // Handler type
+ uint m_frame;
+ uint m_handler; // Location of handler
+ List<struct sp_cond_type> m_cond;
+
+}; // class sp_instr_hpush_jump : public sp_instr_jump
+
+
+class sp_instr_hpop : public sp_instr
+{
+ sp_instr_hpop(const sp_instr_hpop &); /* Prevent use of these */
+ void operator=(sp_instr_hpop &);
+
+public:
+
+ sp_instr_hpop(uint ip, sp_pcontext *ctx, uint count)
+ : sp_instr(ip, ctx), m_count(count)
+ {}
+
+ virtual ~sp_instr_hpop()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ virtual void backpatch(uint dest, sp_pcontext *dst_ctx);
+
+ virtual uint opt_mark(sp_head *sp)
+ {
+ if (m_count)
+ marked= 1;
+ return m_ip+1;
+ }
+
+private:
+
+ uint m_count;
+
+}; // class sp_instr_hpop : public sp_instr
+
+
+class sp_instr_hreturn : public sp_instr_jump
+{
+ sp_instr_hreturn(const sp_instr_hreturn &); /* Prevent use of these */
+ void operator=(sp_instr_hreturn &);
+
+public:
+
+ sp_instr_hreturn(uint ip, sp_pcontext *ctx, uint fp)
+ : sp_instr_jump(ip, ctx), m_frame(fp)
+ {}
+
+ virtual ~sp_instr_hreturn()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ virtual uint opt_mark(sp_head *sp);
+
+private:
+
+ uint m_frame;
+
+}; // class sp_instr_hreturn : public sp_instr
+
+
+class sp_instr_cpush : public sp_instr
+{
+ sp_instr_cpush(const sp_instr_cpush &); /* Prevent use of these */
+ void operator=(sp_instr_cpush &);
+
+public:
+
+ sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex)
+ : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
+ {}
+
+ virtual ~sp_instr_cpush()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+private:
+
+ sp_lex_keeper m_lex_keeper;
+
+}; // class sp_instr_cpush : public sp_instr
+
+
+class sp_instr_cpop : public sp_instr
+{
+ sp_instr_cpop(const sp_instr_cpop &); /* Prevent use of these */
+ void operator=(sp_instr_cpop &);
+
+public:
+
+ sp_instr_cpop(uint ip, sp_pcontext *ctx, uint count)
+ : sp_instr(ip, ctx), m_count(count)
+ {}
+
+ virtual ~sp_instr_cpop()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ virtual void backpatch(uint dest, sp_pcontext *dst_ctx);
+
+ virtual uint opt_mark(sp_head *sp)
+ {
+ if (m_count)
+ marked= 1;
+ return m_ip+1;
+ }
+
+private:
+
+ uint m_count;
+
+}; // class sp_instr_cpop : public sp_instr
+
+
+class sp_instr_copen : public sp_instr
+{
+ sp_instr_copen(const sp_instr_copen &); /* Prevent use of these */
+ void operator=(sp_instr_copen &);
+
+public:
+
+ sp_instr_copen(uint ip, sp_pcontext *ctx, uint c)
+ : sp_instr(ip, ctx), m_cursor(c)
+ {}
+
+ virtual ~sp_instr_copen()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual int exec_core(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+private:
+
+ uint m_cursor; // Stack index
+
+}; // class sp_instr_copen : public sp_instr_stmt
+
+
+class sp_instr_cclose : public sp_instr
+{
+ sp_instr_cclose(const sp_instr_cclose &); /* Prevent use of these */
+ void operator=(sp_instr_cclose &);
+
+public:
+
+ sp_instr_cclose(uint ip, sp_pcontext *ctx, uint c)
+ : sp_instr(ip, ctx), m_cursor(c)
+ {}
+
+ virtual ~sp_instr_cclose()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+private:
+
+ uint m_cursor;
+
+}; // class sp_instr_cclose : public sp_instr
+
+
+class sp_instr_cfetch : public sp_instr
+{
+ sp_instr_cfetch(const sp_instr_cfetch &); /* Prevent use of these */
+ void operator=(sp_instr_cfetch &);
+
+public:
+
+ sp_instr_cfetch(uint ip, sp_pcontext *ctx, uint c)
+ : sp_instr(ip, ctx), m_cursor(c)
+ {
+ m_varlist.empty();
+ }
+
+ virtual ~sp_instr_cfetch()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ void add_to_varlist(struct sp_pvar *var)
+ {
+ m_varlist.push_back(var);
+ }
+
+private:
+
+ uint m_cursor;
+ List<struct sp_pvar> m_varlist;
+
+}; // class sp_instr_cfetch : public sp_instr
+
+
+class sp_instr_error : public sp_instr
+{
+ sp_instr_error(const sp_instr_error &); /* Prevent use of these */
+ void operator=(sp_instr_error &);
+
+public:
+
+ sp_instr_error(uint ip, sp_pcontext *ctx, int errcode)
+ : sp_instr(ip, ctx), m_errcode(errcode)
+ {}
+
+ virtual ~sp_instr_error()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ virtual uint opt_mark(sp_head *sp)
+ {
+ marked= 1;
+ return UINT_MAX;
+ }
+
+private:
+
+ int m_errcode;
+
+}; // class sp_instr_error : public sp_instr
+
+
+struct st_sp_security_context
+{
+ bool changed;
+ uint master_access;
+ uint db_access;
+ char *priv_user;
+ char priv_host[MAX_HOSTNAME];
+ char *user;
+ char *host;
+ char *ip;
+};
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+void
+sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp);
+void
+sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+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_pcontext.cc b/sql/sp_pcontext.cc
new file mode 100644
index 00000000000..26f576233f3
--- /dev/null
+++ b/sql/sp_pcontext.cc
@@ -0,0 +1,334 @@
+/* Copyright (C) 2002 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#if defined(WIN32) || defined(__WIN__)
+#undef SAFEMALLOC /* Problems with threads */
+#endif
+
+#include "mysql_priv.h"
+#include "sp_pcontext.h"
+#include "sp_head.h"
+
+/*
+ * Sanity check for SQLSTATEs. Will not check if it's really an existing
+ * state (there are just too many), but will check length and bad characters.
+ * Returns TRUE if it's ok, FALSE if it's bad.
+ */
+bool
+sp_cond_check(LEX_STRING *sqlstate)
+{
+ int i;
+ const char *p;
+
+ if (sqlstate->length != 5)
+ return FALSE;
+ for (p= sqlstate->str, i= 0 ; i < 5 ; i++)
+ {
+ char c = p[i];
+
+ if ((c < '0' || '9' < c) &&
+ (c < 'A' || 'Z' < c))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+sp_pcontext::sp_pcontext(sp_pcontext *prev)
+ : Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0),
+ m_handlers(0), m_parent(prev)
+{
+ VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
+ VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8));
+ VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8));
+ VOID(my_init_dynamic_array(&m_handler, sizeof(sp_cond_type_t *), 16, 8));
+ m_label.empty();
+ m_children.empty();
+ if (!prev)
+ m_poffset= m_coffset= 0;
+ else
+ {
+ m_poffset= prev->current_pvars();
+ m_coffset= prev->current_cursors();
+ }
+}
+
+void
+sp_pcontext::destroy()
+{
+ List_iterator_fast<sp_pcontext> li(m_children);
+ sp_pcontext *child;
+
+ while ((child= li++))
+ child->destroy();
+
+ m_children.empty();
+ m_label.empty();
+ delete_dynamic(&m_pvar);
+ delete_dynamic(&m_cond);
+ delete_dynamic(&m_cursor);
+ delete_dynamic(&m_handler);
+}
+
+sp_pcontext *
+sp_pcontext::push_context()
+{
+ sp_pcontext *child= new sp_pcontext(this);
+
+ if (child)
+ m_children.push_back(child);
+ return child;
+}
+
+sp_pcontext *
+sp_pcontext::pop_context()
+{
+ uint submax= max_pvars();
+
+ if (submax > m_parent->m_psubsize)
+ m_parent->m_psubsize= submax;
+ submax= max_handlers();
+ if (submax > m_parent->m_hsubsize)
+ m_parent->m_hsubsize= submax;
+ submax= max_cursors();
+ if (submax > m_parent->m_csubsize)
+ m_parent->m_csubsize= submax;
+ return m_parent;
+}
+
+uint
+sp_pcontext::diff_handlers(sp_pcontext *ctx)
+{
+ uint n= 0;
+ sp_pcontext *pctx= this;
+
+ while (pctx && pctx != ctx)
+ {
+ n+= pctx->m_handlers;
+ pctx= pctx->parent_context();
+ }
+ if (pctx)
+ return n;
+ return 0; // Didn't find ctx
+}
+
+uint
+sp_pcontext::diff_cursors(sp_pcontext *ctx)
+{
+ sp_pcontext *pctx= this;
+
+ while (pctx && pctx != ctx)
+ pctx= pctx->parent_context();
+ if (pctx)
+ return ctx->current_cursors() - pctx->current_cursors();
+ return 0; // Didn't find ctx
+}
+
+/* This does a linear search (from newer to older variables, in case
+** we have shadowed names).
+** It's possible to have a more efficient allocation and search method,
+** but it might not be worth it. The typical number of parameters and
+** variables will in most cases be low (a handfull).
+** ...and, this is only called during parsing.
+*/
+sp_pvar_t *
+sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped)
+{
+ uint i= m_pvar.elements;
+
+ while (i--)
+ {
+ sp_pvar_t *p;
+
+ get_dynamic(&m_pvar, (gptr)&p, i);
+ if (my_strnncoll(system_charset_info,
+ (const uchar *)name->str, name->length,
+ (const uchar *)p->name.str, p->name.length) == 0)
+ {
+ return p;
+ }
+ }
+ if (!scoped && m_parent)
+ return m_parent->find_pvar(name, scoped);
+ return NULL;
+}
+
+void
+sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type,
+ sp_param_mode_t mode)
+{
+ sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t));
+
+ if (p)
+ {
+ if (m_pvar.elements == m_psubsize)
+ m_psubsize+= 1;
+ p->name.str= name->str;
+ p->name.length= name->length;
+ p->type= type;
+ p->mode= mode;
+ p->offset= current_pvars();
+ p->isset= (mode == sp_param_out ? FALSE : TRUE);
+ p->dflt= NULL;
+ insert_dynamic(&m_pvar, (gptr)&p);
+ }
+}
+
+sp_label_t *
+sp_pcontext::push_label(char *name, uint ip)
+{
+ sp_label_t *lab = (sp_label_t *)sql_alloc(sizeof(sp_label_t));
+
+ if (lab)
+ {
+ lab->name= name;
+ lab->ip= ip;
+ lab->type= SP_LAB_GOTO;
+ lab->ctx= this;
+ m_label.push_front(lab);
+ }
+ return lab;
+}
+
+sp_label_t *
+sp_pcontext::find_label(char *name)
+{
+ List_iterator_fast<sp_label_t> li(m_label);
+ sp_label_t *lab;
+
+ while ((lab= li++))
+ if (my_strcasecmp(system_charset_info, name, lab->name) == 0)
+ return lab;
+
+ if (m_parent)
+ return m_parent->find_label(name);
+ return NULL;
+}
+
+void
+sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val)
+{
+ sp_cond_t *p= (sp_cond_t *)sql_alloc(sizeof(sp_cond_t));
+
+ if (p)
+ {
+ p->name.str= name->str;
+ p->name.length= name->length;
+ p->val= val;
+ insert_dynamic(&m_cond, (gptr)&p);
+ }
+}
+
+/*
+ * See comment for find_pvar() above
+ */
+sp_cond_type_t *
+sp_pcontext::find_cond(LEX_STRING *name, my_bool scoped)
+{
+ uint i= m_cond.elements;
+
+ while (i--)
+ {
+ sp_cond_t *p;
+
+ get_dynamic(&m_cond, (gptr)&p, i);
+ if (my_strnncoll(system_charset_info,
+ (const uchar *)name->str, name->length,
+ (const uchar *)p->name.str, p->name.length) == 0)
+ {
+ return p->val;
+ }
+ }
+ if (!scoped && m_parent)
+ return m_parent->find_cond(name, scoped);
+ return NULL;
+}
+
+/*
+ * This only searches the current context, for error checking of
+ * duplicates.
+ * Returns TRUE if found.
+ */
+bool
+sp_pcontext::find_handler(sp_cond_type_t *cond)
+{
+ uint i= m_handler.elements;
+
+ while (i--)
+ {
+ sp_cond_type_t *p;
+
+ get_dynamic(&m_handler, (gptr)&p, i);
+ if (cond->type == p->type)
+ {
+ switch (p->type)
+ {
+ case sp_cond_type_t::number:
+ if (cond->mysqlerr == p->mysqlerr)
+ return TRUE;
+ break;
+ case sp_cond_type_t::state:
+ if (strcmp(cond->sqlstate, p->sqlstate) == 0)
+ return TRUE;
+ break;
+ default:
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+void
+sp_pcontext::push_cursor(LEX_STRING *name)
+{
+ LEX_STRING n;
+
+ if (m_cursor.elements == m_csubsize)
+ m_csubsize+= 1;
+ n.str= name->str;
+ n.length= name->length;
+ insert_dynamic(&m_cursor, (gptr)&n);
+}
+
+/*
+ * See comment for find_pvar() above
+ */
+my_bool
+sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped)
+{
+ uint i= m_cursor.elements;
+
+ while (i--)
+ {
+ LEX_STRING n;
+
+ get_dynamic(&m_cursor, (gptr)&n, i);
+ if (my_strnncoll(system_charset_info,
+ (const uchar *)name->str, name->length,
+ (const uchar *)n.str, n.length) == 0)
+ {
+ *poff= m_coffset + i;
+ return TRUE;
+ }
+ }
+ if (!scoped && m_parent)
+ return m_parent->find_cursor(name, poff, scoped);
+ return FALSE;
+}
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
new file mode 100644
index 00000000000..749b99dcf14
--- /dev/null
+++ b/sql/sp_pcontext.h
@@ -0,0 +1,308 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _SP_PCONTEXT_H_
+#define _SP_PCONTEXT_H_
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+typedef enum
+{
+ sp_param_in,
+ sp_param_out,
+ sp_param_inout
+} sp_param_mode_t;
+
+typedef struct sp_pvar
+{
+ LEX_STRING name;
+ enum enum_field_types type;
+ sp_param_mode_t mode;
+ uint offset; // Offset in current frame
+ my_bool isset;
+ Item *dflt;
+} sp_pvar_t;
+
+
+#define SP_LAB_REF 0 // Unresolved reference (for goto)
+#define SP_LAB_GOTO 1 // Free goto label
+#define SP_LAB_BEGIN 2 // Label at BEGIN
+#define SP_LAB_ITER 3 // Label at iteration control
+
+typedef struct sp_label
+{
+ char *name;
+ uint ip; // Instruction index
+ int type; // begin/iter or ref/free
+ sp_pcontext *ctx; // The label's context
+} sp_label_t;
+
+typedef struct sp_cond_type
+{
+ enum { number, state, warning, notfound, exception } type;
+ char sqlstate[6];
+ uint mysqlerr;
+} sp_cond_type_t;
+
+/* Sanity check for SQLSTATEs. Will not check if it's really an existing
+ * state (there are just too many), but will check length bad characters.
+ */
+extern bool
+sp_cond_check(LEX_STRING *sqlstate);
+
+typedef struct sp_cond
+{
+ LEX_STRING name;
+ sp_cond_type_t *val;
+} sp_cond_t;
+
+class sp_pcontext : public Sql_alloc
+{
+ sp_pcontext(const sp_pcontext &); /* Prevent use of these */
+ void operator=(sp_pcontext &);
+
+ public:
+
+ sp_pcontext(sp_pcontext *prev);
+
+ // Free memory
+ void
+ destroy();
+
+ sp_pcontext *
+ push_context();
+
+ // Returns the previous context, not the one we pop
+ sp_pcontext *
+ pop_context();
+
+ sp_pcontext *
+ parent_context()
+ {
+ return m_parent;
+ }
+
+ uint
+ diff_handlers(sp_pcontext *ctx);
+
+ uint
+ diff_cursors(sp_pcontext *ctx);
+
+
+ //
+ // Parameters and variables
+ //
+
+ inline uint
+ max_pvars()
+ {
+ return m_psubsize + m_pvar.elements;
+ }
+
+ inline uint
+ current_pvars()
+ {
+ return m_poffset + m_pvar.elements;
+ }
+
+ inline uint
+ context_pvars()
+ {
+ return m_pvar.elements;
+ }
+
+ inline uint
+ pvar_context2index(uint i)
+ {
+ return m_poffset + i;
+ }
+
+ inline void
+ set_type(uint i, enum enum_field_types type)
+ {
+ sp_pvar_t *p= find_pvar(i);
+
+ if (p)
+ p->type= type;
+ }
+
+ inline void
+ set_isset(uint i, my_bool val)
+ {
+ sp_pvar_t *p= find_pvar(i);
+
+ if (p)
+ p->isset= val;
+ }
+
+ inline void
+ set_default(uint i, Item *it)
+ {
+ sp_pvar_t *p= find_pvar(i);
+
+ if (p)
+ p->dflt= it;
+ }
+
+ void
+ push_pvar(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
+
+ // Pop the last 'num' slots of the frame
+ inline void
+ pop_pvar(uint num = 1)
+ {
+ while (num--)
+ pop_dynamic(&m_pvar);
+ }
+
+ // Find by name
+ sp_pvar_t *
+ find_pvar(LEX_STRING *name, my_bool scoped=0);
+
+ // Find by index
+ sp_pvar_t *
+ find_pvar(uint i)
+ {
+ sp_pvar_t *p;
+
+ if (i < m_pvar.elements)
+ get_dynamic(&m_pvar, (gptr)&p, i);
+ else
+ p= NULL;
+ return p;
+ }
+
+ //
+ // Labels
+ //
+
+ sp_label_t *
+ push_label(char *name, uint ip);
+
+ sp_label_t *
+ find_label(char *name);
+
+ inline sp_label_t *
+ last_label()
+ {
+ sp_label_t *lab= m_label.head();
+
+ if (!lab && m_parent)
+ lab= m_parent->last_label();
+ return lab;
+ }
+
+ inline sp_label_t *
+ pop_label()
+ {
+ return m_label.pop();
+ }
+
+ //
+ // Conditions
+ //
+
+ void
+ push_cond(LEX_STRING *name, sp_cond_type_t *val);
+
+ inline void
+ pop_cond(uint num)
+ {
+ while (num--)
+ pop_dynamic(&m_cond);
+ }
+
+ sp_cond_type_t *
+ find_cond(LEX_STRING *name, my_bool scoped=0);
+
+ //
+ // Handlers
+ //
+
+ inline void
+ push_handler(sp_cond_type_t *cond)
+ {
+ insert_dynamic(&m_handler, (gptr)&cond);
+ }
+
+ bool
+ find_handler(sp_cond_type *cond);
+
+ inline uint
+ max_handlers()
+ {
+ return m_hsubsize + m_handlers;
+ }
+
+ inline void
+ add_handlers(uint n)
+ {
+ m_handlers+= n;
+ }
+
+ //
+ // Cursors
+ //
+
+ void
+ push_cursor(LEX_STRING *name);
+
+ my_bool
+ find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0);
+
+ inline uint
+ max_cursors()
+ {
+ return m_csubsize + m_cursor.elements;
+ }
+
+ inline uint
+ current_cursors()
+ {
+ return m_coffset + m_cursor.elements;
+ }
+
+protected:
+
+ // The maximum sub context's framesizes
+ uint m_psubsize;
+ uint m_csubsize;
+ uint m_hsubsize;
+ uint m_handlers; // No. of handlers in this context
+
+private:
+
+ sp_pcontext *m_parent; // Parent context
+
+ uint m_poffset; // Variable offset for this context
+ uint m_coffset; // Cursor offset for this context
+
+ DYNAMIC_ARRAY m_pvar; // Parameters/variables
+ DYNAMIC_ARRAY m_cond; // Conditions
+ DYNAMIC_ARRAY m_cursor; // Cursors
+ DYNAMIC_ARRAY m_handler; // Handlers, for checking of duplicates
+
+ List<sp_label_t> m_label; // The label list
+
+ List<sp_pcontext> m_children; // Children contexts, used for destruction
+
+}; // class sp_pcontext : public Sql_alloc
+
+
+#endif /* _SP_PCONTEXT_H_ */
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
new file mode 100644
index 00000000000..def38009eee
--- /dev/null
+++ b/sql/sp_rcontext.cc
@@ -0,0 +1,285 @@
+/* Copyright (C) 2002 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#if defined(WIN32) || defined(__WIN__)
+#undef SAFEMALLOC /* Problems with threads */
+#endif
+
+#include "mysql_priv.h"
+#include "mysql.h"
+#include "sp_head.h"
+#include "sp_rcontext.h"
+#include "sp_pcontext.h"
+
+sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
+ : m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
+ m_hfound(-1), m_ccount(0)
+{
+ in_handler= FALSE;
+ m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
+ m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
+ m_hstack= (uint *)sql_alloc(hmax * sizeof(uint));
+ m_cstack= (sp_cursor **)sql_alloc(cmax * sizeof(sp_cursor *));
+ m_saved.empty();
+}
+
+int
+sp_rcontext::set_item_eval(uint idx, Item *i, enum_field_types type)
+{
+ extern Item *sp_eval_func_item(THD *thd, Item *it, enum_field_types type);
+ Item *it= sp_eval_func_item(current_thd, i, type);
+
+ if (! it)
+ return -1;
+ else
+ {
+ set_item(idx, it);
+ return 0;
+ }
+}
+
+bool
+sp_rcontext::find_handler(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level)
+{
+ if (in_handler)
+ return 0; // Already executing a handler
+ if (m_hfound >= 0)
+ return 1; // Already got one
+
+ const char *sqlstate= mysql_errno_to_sqlstate(sql_errno);
+ int i= m_hcount, found= -1;
+
+ while (i--)
+ {
+ sp_cond_type_t *cond= m_handler[i].cond;
+
+ switch (cond->type)
+ {
+ case sp_cond_type_t::number:
+ if (sql_errno == cond->mysqlerr)
+ found= i; // Always the most specific
+ break;
+ case sp_cond_type_t::state:
+ if (strcmp(sqlstate, cond->sqlstate) == 0 &&
+ (found < 0 || m_handler[found].cond->type > sp_cond_type_t::state))
+ found= i;
+ break;
+ case sp_cond_type_t::warning:
+ if ((sqlstate[0] == '0' && sqlstate[1] == '1' ||
+ level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
+ found < 0)
+ found= i;
+ break;
+ case sp_cond_type_t::notfound:
+ if (sqlstate[0] == '0' && sqlstate[1] == '2' &&
+ found < 0)
+ found= i;
+ break;
+ case sp_cond_type_t::exception:
+ if ((sqlstate[0] != '0' || sqlstate[1] > '2') &&
+ level == MYSQL_ERROR::WARN_LEVEL_ERROR &&
+ found < 0)
+ found= i;
+ break;
+ }
+ }
+ if (found < 0)
+ return FALSE;
+ m_hfound= found;
+ return TRUE;
+}
+
+void
+sp_rcontext::save_variables(uint fp)
+{
+ while (fp < m_count)
+ m_saved.push_front(m_frame[fp++]);
+}
+
+void
+sp_rcontext::restore_variables(uint fp)
+{
+ uint i= m_count;
+
+ while (i-- > fp)
+ m_frame[i]= m_saved.pop();
+}
+
+void
+sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper)
+{
+ m_cstack[m_ccount++]= new sp_cursor(lex_keeper);
+}
+
+void
+sp_rcontext::pop_cursors(uint count)
+{
+ while (count--)
+ {
+ delete m_cstack[--m_ccount];
+ }
+}
+
+
+/*
+ *
+ * sp_cursor
+ *
+ */
+
+// We have split this in two to make it easy for sp_instr_copen
+// to reuse the sp_instr::exec_stmt() code.
+sp_lex_keeper*
+sp_cursor::pre_open(THD *thd)
+{
+ if (m_isopen)
+ {
+ my_message(ER_SP_CURSOR_ALREADY_OPEN, ER(ER_SP_CURSOR_ALREADY_OPEN),
+ MYF(0));
+ return NULL;
+ }
+
+ bzero((char *)&m_mem_root, sizeof(m_mem_root));
+ init_alloc_root(&m_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+ if ((m_prot= new Protocol_cursor(thd, &m_mem_root)) == NULL)
+ return NULL;
+
+ m_oprot= thd->protocol; // Save the original protocol
+ thd->protocol= m_prot;
+
+ m_nseof= thd->net.no_send_eof;
+ thd->net.no_send_eof= TRUE;
+ return m_lex_keeper;
+}
+
+void
+sp_cursor::post_open(THD *thd, my_bool was_opened)
+{
+ thd->net.no_send_eof= m_nseof; // Restore the originals
+ thd->protocol= m_oprot;
+ if (was_opened)
+ {
+ m_isopen= was_opened;
+ m_current_row= m_prot->data;
+ }
+}
+
+int
+sp_cursor::close(THD *thd)
+{
+ if (! m_isopen)
+ {
+ my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
+ return -1;
+ }
+ destroy();
+ return 0;
+}
+
+void
+sp_cursor::destroy()
+{
+ if (m_prot)
+ {
+ delete m_prot;
+ m_prot= NULL;
+ free_root(&m_mem_root, MYF(0));
+ bzero((char *)&m_mem_root, sizeof(m_mem_root));
+ }
+ m_isopen= FALSE;
+}
+
+int
+sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
+{
+ List_iterator_fast<struct sp_pvar> li(*vars);
+ sp_pvar_t *pv;
+ MYSQL_ROW row;
+ uint fldcount;
+
+ if (! m_isopen)
+ {
+ my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0));
+ return -1;
+ }
+ if (m_current_row == NULL)
+ {
+ my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0));
+ return -1;
+ }
+
+ row= m_current_row->data;
+ for (fldcount= 0 ; (pv= li++) ; fldcount++)
+ {
+ Item *it;
+ const char *s;
+
+ if (fldcount >= m_prot->get_field_count())
+ {
+ my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS,
+ ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
+ return -1;
+ }
+ s= row[fldcount];
+ if (!s)
+ it= new Item_null();
+ else
+ {
+ /*
+ Length of data can be calculated as:
+ pointer_to_next_not_null_object - s -1
+ where the last -1 is to remove the end \0
+ */
+ uint len;
+ MYSQL_ROW next= row+fldcount+1;
+ while (!*next) // Skip nulls
+ next++;
+ len= (*next -s)-1;
+ switch (sp_map_result_type(pv->type)) {
+ case INT_RESULT:
+ it= new Item_int(s);
+ break;
+ case REAL_RESULT:
+ it= new Item_float(s, len);
+ break;
+ case DECIMAL_RESULT:
+ it= new Item_decimal(s, len, thd->db_charset);
+ break;
+ case STRING_RESULT:
+ /* TODO: Document why we do an extra copy of the string 's' here */
+ it= new Item_string(thd->strmake(s, len), len, thd->db_charset);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ thd->spcont->set_item(pv->offset, it);
+ }
+ if (fldcount < m_prot->get_field_count())
+ {
+ my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS,
+ ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
+ return -1;
+ }
+ m_current_row= m_current_row->next;
+ return 0;
+}
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
new file mode 100644
index 00000000000..afcd937a369
--- /dev/null
+++ b/sql/sp_rcontext.h
@@ -0,0 +1,243 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _SP_RCONTEXT_H_
+#define _SP_RCONTEXT_H_
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+struct sp_cond_type;
+class sp_cursor;
+struct sp_pvar;
+class sp_lex_keeper;
+
+#define SP_HANDLER_NONE 0
+#define SP_HANDLER_EXIT 1
+#define SP_HANDLER_CONTINUE 2
+#define SP_HANDLER_UNDO 3
+
+typedef struct
+{
+ struct sp_cond_type *cond;
+ uint handler; // Location of handler
+ int type;
+ uint foffset; // Frame offset for the handlers declare level
+} sp_handler_t;
+
+class sp_rcontext : public Sql_alloc
+{
+ sp_rcontext(const sp_rcontext &); /* Prevent use of these */
+ void operator=(sp_rcontext &);
+
+ public:
+
+ bool in_handler;
+
+ sp_rcontext(uint fsize, uint hmax, uint cmax);
+
+ ~sp_rcontext()
+ {
+ // Not needed?
+ //sql_element_free(m_frame);
+ //m_saved.empty();
+ }
+
+ inline void
+ push_item(Item *i)
+ {
+ if (m_count < m_fsize)
+ m_frame[m_count++] = i;
+ }
+
+ inline void
+ set_item(uint idx, Item *i)
+ {
+ if (idx < m_count)
+ m_frame[idx] = i;
+ }
+
+ /* Returns 0 on success, -1 on (eval) failure */
+ int
+ set_item_eval(uint idx, Item *i, enum_field_types type);
+
+ inline Item *
+ get_item(uint idx)
+ {
+ return m_frame[idx];
+ }
+
+ inline void
+ set_result(Item *it)
+ {
+ m_result= it;
+ }
+
+ inline Item *
+ get_result()
+ {
+ return m_result;
+ }
+
+ inline void
+ push_handler(struct sp_cond_type *cond, uint h, int type, uint f)
+ {
+ m_handler[m_hcount].cond= cond;
+ m_handler[m_hcount].handler= h;
+ m_handler[m_hcount].type= type;
+ m_handler[m_hcount].foffset= f;
+ m_hcount+= 1;
+ }
+
+ inline void
+ pop_handlers(uint count)
+ {
+ m_hcount-= count;
+ }
+
+ // Returns 1 if a handler was found, 0 otherwise.
+ bool
+ find_handler(uint sql_errno,MYSQL_ERROR::enum_warning_level level);
+
+ // Returns handler type and sets *ip to location if one was found
+ inline int
+ found_handler(uint *ip, uint *fp)
+ {
+ if (m_hfound < 0)
+ return SP_HANDLER_NONE;
+ *ip= m_handler[m_hfound].handler;
+ *fp= m_handler[m_hfound].foffset;
+ return m_handler[m_hfound].type;
+ }
+
+ // Clears the handler find state
+ inline void
+ clear_handler()
+ {
+ m_hfound= -1;
+ }
+
+ inline void
+ push_hstack(uint h)
+ {
+ m_hstack[m_hsp++]= h;
+ }
+
+ inline uint
+ pop_hstack()
+ {
+ return m_hstack[--m_hsp];
+ }
+
+ // Save variables starting at fp and up
+ void
+ save_variables(uint fp);
+
+ // Restore variables down to fp
+ void
+ restore_variables(uint fp);
+
+ void
+ push_cursor(sp_lex_keeper *lex_keeper);
+
+ void
+ pop_cursors(uint count);
+
+ void
+ pop_all_cursors()
+ {
+ pop_cursors(m_ccount);
+ }
+
+ inline sp_cursor *
+ get_cursor(uint i)
+ {
+ return m_cstack[i];
+ }
+
+private:
+
+ uint m_count;
+ uint m_fsize;
+ Item **m_frame;
+
+ Item *m_result; // For FUNCTIONs
+
+ sp_handler_t *m_handler;
+ uint m_hcount;
+ uint *m_hstack;
+ uint m_hsp;
+ int m_hfound; // Set by find_handler; -1 if not found
+ List<Item> m_saved; // Saved variables
+
+ sp_cursor **m_cstack;
+ uint m_ccount;
+
+}; // class sp_rcontext : public Sql_alloc
+
+
+class sp_cursor : public Sql_alloc
+{
+public:
+
+ sp_cursor(sp_lex_keeper *lex_keeper)
+ : m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL)
+ {
+ /* Empty */
+ }
+
+ virtual ~sp_cursor()
+ {
+ destroy();
+ }
+
+ // We have split this in two to make it easy for sp_instr_copen
+ // to reuse the sp_instr::exec_stmt() code.
+ sp_lex_keeper *
+ pre_open(THD *thd);
+ void
+ post_open(THD *thd, my_bool was_opened);
+
+ int
+ close(THD *thd);
+
+ inline my_bool
+ is_open()
+ {
+ return m_isopen;
+ }
+
+ int
+ fetch(THD *, List<struct sp_pvar> *vars);
+
+private:
+
+ MEM_ROOT m_mem_root; // My own mem_root
+ sp_lex_keeper *m_lex_keeper;
+ Protocol_cursor *m_prot;
+ my_bool m_isopen;
+ my_bool m_nseof; // Original no_send_eof
+ Protocol *m_oprot; // Original protcol
+ MYSQL_ROWS *m_current_row;
+
+ void
+ destroy();
+
+}; // class sp_cursor : public Sql_alloc
+
+#endif /* _SP_RCONTEXT_H_ */
diff --git a/sql/spatial.cc b/sql/spatial.cc
index bcfefd9dde8..427648850e4 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -22,6 +22,8 @@
/***************************** Gis_class_info *******************************/
+String Geometry::bad_geometry_data("Bad object", &my_charset_bin);
+
Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end+1]=
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL
diff --git a/sql/spatial.h b/sql/spatial.h
index b96434831a1..438ec171a72 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -173,6 +173,8 @@ public:
static void operator delete(void *ptr, void *buffer)
{}
+ static String bad_geometry_data;
+
enum wkbType
{
wkb_point= 1,
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 02da05d195f..df19c6e55fd 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -17,8 +17,8 @@
/*
The privileges are saved in the following tables:
- mysql/user ; super user who are allowed to do almoust anything
- mysql/host ; host priviliges. This is used if host is empty in mysql/db.
+ mysql/user ; super user who are allowed to do almost anything
+ mysql/host ; host privileges. This is used if host is empty in mysql/db.
mysql/db ; database privileges / user
data in tables is sorted according to how many not-wild-cards there is
@@ -32,6 +32,8 @@
#endif
#include <m_ctype.h>
#include <stdarg.h>
+#include "sp_head.h"
+#include "sp.h"
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -58,7 +60,7 @@ static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
static MEM_ROOT mem, memex;
static bool initialized=0;
static bool allow_all_hosts=1;
-static HASH acl_check_hosts, column_priv_hash;
+static HASH acl_check_hosts, column_priv_hash, proc_priv_hash;
static DYNAMIC_ARRAY acl_wild_hosts;
static hash_filo *acl_cache;
static uint grant_version=0;
@@ -136,7 +138,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
TABLE_LIST tables[3];
TABLE *table;
READ_RECORD read_record_info;
- MYSQL_LOCK *lock;
my_bool return_val=1;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
char tmp_name[NAME_LEN+1];
@@ -153,6 +154,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
}
priv_version++; /* Privileges updated */
+ mysql_proc_table_exists= 1; // Assume mysql.proc exists
/*
To be able to run this from boot, we allocate a temporary THD
@@ -165,28 +167,17 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
thd->db= my_strdup("mysql",MYF(0));
thd->db_length=5; // Safety
bzero((char*) &tables,sizeof(tables));
- tables[0].alias=tables[0].real_name=(char*) "host";
- tables[1].alias=tables[1].real_name=(char*) "user";
- tables[2].alias=tables[2].real_name=(char*) "db";
- tables[0].next=tables+1;
- tables[1].next=tables+2;
+ tables[0].alias=tables[0].table_name=(char*) "host";
+ tables[1].alias=tables[1].table_name=(char*) "user";
+ tables[2].alias=tables[2].table_name=(char*) "db";
+ tables[0].next_local= tables[0].next_global= tables+1;
+ tables[1].next_local= tables[1].next_global= tables+2;
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
tables[0].db=tables[1].db=tables[2].db=thd->db;
- uint counter;
- if (open_tables(thd, tables, &counter))
- {
- sql_print_error("Fatal error: Can't open privilege tables: %s",
- thd->net.last_error);
- goto end;
- }
- TABLE *ptr[3]; // Lock tables for quick update
- ptr[0]= tables[0].table;
- ptr[1]= tables[1].table;
- ptr[2]= tables[2].table;
- if (!(lock=mysql_lock_tables(thd,ptr,3)))
+ if (simple_open_n_lock_tables(thd, tables))
{
- sql_print_error("Fatal error: Can't lock privilege tables: %s",
+ sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
thd->net.last_error);
goto end;
}
@@ -201,19 +192,17 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (lower_case_table_names)
{
/*
- We make a temporary copy of the database, force it to lower case,
- and then check it against the original name.
+ convert db to lower case and give a warning if the db wasn't
+ already in lower case
*/
- (void)strnmov(tmp_name, host.db, sizeof(tmp_name));
+ (void) strmov(tmp_name, host.db);
my_casedn_str(files_charset_info, host.db);
if (strcmp(host.db, tmp_name) != 0)
- {
sql_print_warning("'host' entry '%s|%s' had database in mixed "
"case that has been forced to lowercase because "
"lower_case_table_names is set. It will not be "
"possible to remove this privilege using REVOKE.",
host.host.hostname, host.db);
- }
}
host.access= get_access(table,2);
host.access= fix_rights_for_db(host.access);
@@ -226,7 +215,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
continue;
}
#ifndef TO_BE_REMOVED
- if (table->fields == 8)
+ if (table->s->fields == 8)
{ // Without grant
if (host.access & CREATE_ACL)
host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL;
@@ -249,8 +238,8 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
}
DBUG_PRINT("info",("user table fields: %d, password length: %d",
- table->fields, table->field[2]->field_length));
-
+ table->s->fields, table->field[2]->field_length));
+
pthread_mutex_lock(&LOCK_global_system_variables);
if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
{
@@ -318,10 +307,34 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
{
uint next_field;
user.access= get_access(table,3,&next_field) & GLOBAL_ACLS;
+ /*
+ if it is pre 5.0.1 privilege table then map CREATE privilege on
+ CREATE VIEW & SHOW VIEW privileges
+ */
+ if (table->s->fields <= 31 && (user.access & CREATE_ACL))
+ user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL);
+
+ /*
+ if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on
+ CREATE PROCEDURE & ALTER PROCEDURE privileges
+ */
+ if (table->s->fields <= 33 && (user.access & CREATE_ACL))
+ user.access|= CREATE_PROC_ACL;
+ if (table->s->fields <= 33 && (user.access & ALTER_ACL))
+ user.access|= ALTER_PROC_ACL;
+
+ /*
+ pre 5.0.3 did not have CREATE_USER_ACL
+ */
+ if (table->s->fields <= 36 && (user.access & GRANT_ACL))
+ user.access|= CREATE_USER_ACL;
+
user.sort= get_sort(2,user.host.hostname,user.user);
user.hostname_length= (user.host.hostname ?
(uint) strlen(user.host.hostname) : 0);
- if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */
+
+ /* Starting from 4.0.2 we have more fields */
+ if (table->s->fields >= 31)
{
char *ssl_type=get_field(&mem, table->field[next_field++]);
if (!ssl_type)
@@ -342,17 +355,26 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
ptr = get_field(&mem, table->field[next_field++]);
user.user_resource.updates=ptr ? atoi(ptr) : 0;
ptr = get_field(&mem, table->field[next_field++]);
- user.user_resource.connections=ptr ? atoi(ptr) : 0;
+ user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
if (user.user_resource.questions || user.user_resource.updates ||
- user.user_resource.connections)
+ user.user_resource.conn_per_hour)
mqh_used=1;
+
+ if (table->s->fields >= 36)
+ {
+ /* Starting from 5.0.3 we have max_user_connections field */
+ ptr= get_field(&mem, table->field[next_field++]);
+ user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
+ }
+ else
+ user.user_resource.user_conn= 0;
}
else
{
user.ssl_type=SSL_TYPE_NONE;
bzero((char *)&(user.user_resource),sizeof(user.user_resource));
#ifndef TO_BE_REMOVED
- if (table->fields <= 13)
+ if (table->s->fields <= 13)
{ // Without grant
if (user.access & CREATE_ACL)
user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
@@ -401,10 +423,10 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (lower_case_table_names)
{
/*
- We make a temporary copy of the database, force it to lower case,
- and then check it against the original name.
+ convert db to lower case and give a warning if the db wasn't
+ already in lower case
*/
- (void)strnmov(tmp_name, db.db, sizeof(tmp_name));
+ (void)strmov(tmp_name, db.db);
my_casedn_str(files_charset_info, db.db);
if (strcmp(db.db, tmp_name) != 0)
{
@@ -417,7 +439,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
}
db.sort=get_sort(3,db.host.hostname,db.db,db.user);
#ifndef TO_BE_REMOVED
- if (table->fields <= 9)
+ if (table->s->fields <= 9)
{ // Without grant
if (db.access & CREATE_ACL)
db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
@@ -431,7 +453,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
freeze_size(&acl_dbs);
init_check_host();
- mysql_unlock_tables(thd, lock);
initialized=1;
thd->version--; // Force close to free memory
return_val=0;
@@ -473,7 +494,8 @@ void acl_free(bool end)
SYNOPSIS
acl_reload()
- thd Thread handle (can be NULL)
+ thd Thread handle. Note that this may be NULL if we refresh
+ because we got a signal
*/
void acl_reload(THD *thd)
@@ -526,8 +548,8 @@ void acl_reload(THD *thd)
Get all access bits from table after fieldnr
IMPLEMENTATION
- We know that the access privileges ends when there is no more fields
- or the field is not an enum with two elements.
+ We know that the access privileges ends when there is no more fields
+ or the field is not an enum with two elements.
SYNOPSIS
get_access()
@@ -630,7 +652,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
thd->host, thd->ip, thd->user are used for checks.
mqh user resources; on success mqh is reset, else
unchanged
- passwd scrambled & crypted password, recieved from client
+ passwd scrambled & crypted password, received from client
(to check): thd->scramble or thd->scramble_323 is
used to decrypt passwd, so they must contain
original random string,
@@ -641,7 +663,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
RETURN VALUE
0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
updated
- 1 user not found or authentification failure
+ 1 user not found or authentication failure
2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
-1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
*/
@@ -781,7 +803,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
break;
}
DBUG_PRINT("info",("checkpoint 2"));
- /* If X509 issuer is speified, we check it... */
+ /* If X509 issuer is specified, we check it... */
if (acl_user->x509_issuer)
{
DBUG_PRINT("info",("checkpoint 3"));
@@ -840,6 +862,85 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
}
+/*
+ * This is like acl_getroot() above, but it doesn't check password,
+ * and we don't care about the user resources.
+ * Used to get access rights for SQL SECURITY DEFINER invocation of
+ * stored procedures.
+ */
+int acl_getroot_no_password(THD *thd)
+{
+ int res= 1;
+ uint i;
+ ACL_USER *acl_user= 0;
+ DBUG_ENTER("acl_getroot_no_password");
+
+ if (!initialized)
+ {
+ /*
+ here if mysqld's been started with --skip-grant-tables option.
+ */
+ thd->priv_user= (char *) ""; // privileges for
+ *thd->priv_host= '\0'; // the user are unknown
+ thd->master_access= ~NO_ACCESS; // everything is allowed
+ DBUG_RETURN(0);
+ }
+
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ thd->master_access= 0;
+ thd->db_access= 0;
+
+ /*
+ Find acl entry in user database.
+ This is specially tailored to suit the check we do for CALL of
+ a stored procedure; thd->user is set to what is actually a
+ priv_user, which can be ''.
+ */
+ for (i=0 ; i < acl_users.elements ; i++)
+ {
+ acl_user= dynamic_element(&acl_users,i,ACL_USER*);
+ if ((!acl_user->user && (!thd->user || !thd->user[0])) ||
+ (acl_user->user && strcmp(thd->user, acl_user->user) == 0))
+ {
+ if (compare_hostname(&acl_user->host, thd->host, thd->ip))
+ {
+ res= 0;
+ break;
+ }
+ }
+ }
+
+ if (acl_user)
+ {
+ for (i=0 ; i < acl_dbs.elements ; i++)
+ {
+ ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
+ if (!acl_db->user ||
+ (thd->user && thd->user[0] && !strcmp(thd->user, acl_db->user)))
+ {
+ if (compare_hostname(&acl_db->host, thd->host, thd->ip))
+ {
+ if (!acl_db->db || (thd->db && !strcmp(acl_db->db, thd->db)))
+ {
+ thd->db_access= acl_db->access;
+ break;
+ }
+ }
+ }
+ }
+ thd->master_access= acl_user->access;
+ thd->priv_user= acl_user->user ? thd->user : (char *) "";
+
+ if (acl_user->host.hostname)
+ strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
+ else
+ *thd->priv_host= 0;
+ }
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ DBUG_RETURN(res);
+}
+
static byte* check_get_key(ACL_USER *buff,uint *length,
my_bool not_used __attribute__((unused)))
{
@@ -866,15 +967,17 @@ static void acl_update_user(const char *user, const char *host,
{
if (!acl_user->host.hostname && !host[0] ||
acl_user->host.hostname &&
- !my_strcasecmp(&my_charset_latin1, host, acl_user->host.hostname))
+ !my_strcasecmp(system_charset_info, host, acl_user->host.hostname))
{
acl_user->access=privileges;
- if (mqh->bits & 1)
+ if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
acl_user->user_resource.questions=mqh->questions;
- if (mqh->bits & 2)
+ if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
acl_user->user_resource.updates=mqh->updates;
- if (mqh->bits & 4)
- acl_user->user_resource.connections=mqh->connections;
+ if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
+ acl_user->user_resource.conn_per_hour= mqh->conn_per_hour;
+ if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS)
+ acl_user->user_resource.user_conn= mqh->user_conn;
if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
{
acl_user->ssl_type= ssl_type;
@@ -945,7 +1048,7 @@ static void acl_update_db(const char *user, const char *host, const char *db,
{
if (!acl_db->host.hostname && !host[0] ||
acl_db->host.hostname &&
- !my_strcasecmp(&my_charset_latin1, host, acl_db->host.hostname))
+ !my_strcasecmp(system_charset_info, host, acl_db->host.hostname))
{
if (!acl_db->db && !db[0] ||
acl_db->db && !strcmp(db,acl_db->db))
@@ -1002,7 +1105,7 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern)
{
- ulong host_access= ~0,db_access= 0;
+ ulong host_access= ~0, db_access= 0;
uint i,key_length;
char key[ACL_KEY_LENGTH],*tmp_db,*end;
acl_entry *entry;
@@ -1091,7 +1194,7 @@ static void init_check_host(void)
DBUG_ENTER("init_check_host");
VOID(my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
acl_users.elements,1));
- VOID(hash_init(&acl_check_hosts,&my_charset_latin1,acl_users.elements,0,0,
+ VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0,
(hash_get_key) check_get_key,0,0));
if (!allow_all_hosts)
{
@@ -1107,7 +1210,7 @@ static void init_check_host(void)
{ // Check if host already exists
acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
acl_host_and_ip *);
- if (!my_strcasecmp(&my_charset_latin1,
+ if (!my_strcasecmp(system_charset_info,
acl_user->host.hostname, acl->hostname))
break; // already stored
}
@@ -1182,29 +1285,27 @@ bool check_change_password(THD *thd, const char *host, const char *user,
{
if (!initialized)
{
- net_printf(thd,ER_OPTION_PREVENTS_STATEMENT,
- "--skip-grant-tables");
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
return(1);
}
if (!thd->slave_thread &&
(strcmp(thd->user,user) ||
- my_strcasecmp(&my_charset_latin1, host, thd->host_or_ip)))
+ my_strcasecmp(system_charset_info, host, thd->host_or_ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1,0))
return(1);
}
if (!thd->slave_thread && !thd->user[0])
{
- send_error(thd, ER_PASSWORD_ANONYMOUS_USER);
+ my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER),
+ MYF(0));
return(1);
}
uint len=strlen(new_password);
if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
- net_printf(thd, 0,
- "Password hash should be a %d-digit hexadecimal number",
- SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
return -1;
}
return(0);
@@ -1243,7 +1344,7 @@ bool change_password(THD *thd, const char *host, const char *user,
if (!(acl_user= find_acl_user(host, user)))
{
VOID(pthread_mutex_unlock(&acl_cache->lock));
- send_error(thd, ER_PASSWORD_NO_MATCH);
+ my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
DBUG_RETURN(1);
}
/* update loaded acl entry: */
@@ -1255,7 +1356,6 @@ bool change_password(THD *thd, const char *host, const char *user,
new_password, new_password_len))
{
VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
- send_error(thd,0); /* purecov: deadcode */
DBUG_RETURN(1); /* purecov: deadcode */
}
@@ -1270,7 +1370,6 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
thd->clear_error();
- mysql_update_log.write(thd, buff, query_length);
Query_log_event qinfo(thd, buff, query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
DBUG_RETURN(0);
@@ -1360,7 +1459,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
return (tmp & host->ip_mask) == host->ip;
}
return (!host->hostname ||
- (hostname && !wild_case_compare(&my_charset_latin1,
+ (hostname && !wild_case_compare(system_charset_info,
hostname,host->hostname)) ||
(ip && !wild_compare(ip,host->hostname,0)));
}
@@ -1373,7 +1472,7 @@ bool hostname_requires_resolving(const char *hostname)
int namelen= strlen(hostname);
int lhlen= strlen(my_localhost);
if ((namelen == lhlen) &&
- !my_strnncoll(&my_charset_latin1, (const uchar *)hostname, namelen,
+ !my_strnncoll(system_charset_info, (const uchar *)hostname, namelen,
(const uchar *)my_localhost, strlen(my_localhost)))
return FALSE;
for (; (cur=*hostname); hostname++)
@@ -1395,11 +1494,12 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
TABLE_LIST tables;
TABLE *table;
bool error=1;
+ char user_key[MAX_KEY_LENGTH];
DBUG_ENTER("update_user_table");
DBUG_PRINT("enter",("user: %s host: %s",user,host));
bzero((char*) &tables,sizeof(tables));
- tables.alias=tables.real_name=(char*) "user";
+ tables.alias=tables.table_name=(char*) "user";
tables.db=(char*) "mysql";
#ifdef HAVE_REPLICATION
@@ -1422,20 +1522,22 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
if (!(table=open_ltable(thd,&tables,TL_WRITE)))
DBUG_RETURN(1); /* purecov: deadcode */
- table->field[0]->store(host,(uint) strlen(host), &my_charset_latin1);
- table->field[1]->store(user,(uint) strlen(user), &my_charset_latin1);
+ table->field[0]->store(host,(uint) strlen(host), system_charset_info);
+ table->field[1]->store(user,(uint) strlen(user), system_charset_info);
+ key_copy((byte *) user_key, table->record[0], table->key_info,
+ table->key_info->key_length);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read_idx(table->record[0],0,
- (byte*) table->field[0]->ptr,
- table->key_info[0].key_length,
+ if (table->file->index_read_idx(table->record[0], 0,
+ (byte *) user_key, table->key_info->key_length,
HA_READ_KEY_EXACT))
{
- my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */
+ my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
+ MYF(0)); /* purecov: deadcode */
DBUG_RETURN(1); /* purecov: deadcode */
}
store_record(table,record[1]);
- table->field[2]->store(new_password, new_password_len, &my_charset_latin1);
+ table->field[2]->store(new_password, new_password_len, system_charset_info);
if ((error=table->file->update_row(table->record[1],table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
@@ -1449,18 +1551,26 @@ end:
}
-/* Return 1 if we are allowed to create new users */
+/*
+ Return 1 if we are allowed to create new users
+ the logic here is: INSERT_ACL is sufficient.
+ It's also a requirement in opt_safe_user_create,
+ otherwise CREATE_USER_ACL is enough.
+*/
static bool test_if_create_new_users(THD *thd)
{
- bool create_new_users=1; // Assume that we are allowed to create new users
- if (opt_safe_user_create && !(thd->master_access & INSERT_ACL))
+ bool create_new_users= test(thd->master_access & INSERT_ACL) ||
+ (!opt_safe_user_create &&
+ test(thd->master_access & CREATE_USER_ACL));
+ if (!create_new_users)
{
TABLE_LIST tl;
ulong db_access;
bzero((char*) &tl,sizeof(tl));
tl.db= (char*) "mysql";
- tl.real_name= (char*) "user";
+ tl.table_name= (char*) "user";
+ create_new_users= 1;
db_access=acl_get(thd->host, thd->ip,
thd->priv_user, tl.db, 0);
@@ -1480,14 +1590,17 @@ static bool test_if_create_new_users(THD *thd)
static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
ulong rights, bool revoke_grant,
- bool create_user)
+ bool can_create_user, bool no_auto_create)
{
int error = -1;
bool old_row_exists=0;
const char *password= "";
uint password_len= 0;
char what= (revoke_grant) ? 'N' : 'Y';
+ byte user_key[MAX_KEY_LENGTH];
+ LEX *lex= thd->lex;
DBUG_ENTER("replace_user_table");
+
safe_mutex_assert_owner(&acl_cache->lock);
if (combo.password.str && combo.password.str[0])
@@ -1495,49 +1608,71 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
- my_printf_error(ER_UNKNOWN_ERROR,
- "Password hash should be a %d-digit hexadecimal number",
- MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
DBUG_RETURN(-1);
}
password_len= combo.password.length;
password=combo.password.str;
}
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(combo.user.str,combo.user.length, system_charset_info);
+ key_copy(user_key, table->record[0], table->key_info,
+ table->key_info->key_length);
+
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (table->file->index_read_idx(table->record[0], 0,
- (byte*) table->field[0]->ptr,
- table->key_info[0].key_length,
- HA_READ_KEY_EXACT))
+ user_key, table->key_info->key_length,
+ HA_READ_KEY_EXACT))
{
- if (!create_user)
+ /* what == 'N' means revoke */
+ if (what == 'N')
{
- if (what == 'N')
- my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
- else
- my_error(ER_NO_PERMISSION_TO_CREATE_USER, MYF(0),
- thd->user, thd->host_or_ip);
+ my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
+ goto end;
+ }
+ /*
+ There are four options which affect the process of creation of
+ a new user (mysqld option --safe-create-user, 'insert' privilege
+ on 'mysql.user' table, using 'GRANT' with 'IDENTIFIED BY' and
+ SQL_MODE flag NO_AUTO_CREATE_USER). Below is the simplified rule
+ how it should work.
+ if (safe-user-create && ! INSERT_priv) => reject
+ else if (identified_by) => create
+ else if (no_auto_create_user) => reject
+ else create
+
+ see also test_if_create_new_users()
+ */
+ else if (!password_len && no_auto_create)
+ {
+ my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo.user.str, combo.host.str);
+ goto end;
+ }
+ else if (!can_create_user)
+ {
+ my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0),
+ thd->user, thd->host_or_ip);
goto end;
}
old_row_exists = 0;
- restore_record(table,default_values); // cp empty row from default_values
+ restore_record(table,s->default_values);
table->field[0]->store(combo.host.str,combo.host.length,
- &my_charset_latin1);
+ system_charset_info);
table->field[1]->store(combo.user.str,combo.user.length,
- &my_charset_latin1);
+ system_charset_info);
table->field[2]->store(password, password_len,
- &my_charset_latin1);
+ system_charset_info);
}
else
{
old_row_exists = 1;
store_record(table,record[1]); // Save copy for update
if (combo.password.str) // If password given
- table->field[2]->store(password, password_len, &my_charset_latin1);
- else if (!rights && !revoke_grant && thd->lex->ssl_type == SSL_TYPE_NOT_SPECIFIED &&
- !thd->lex->mqh.bits)
+ table->field[2]->store(password, password_len, system_charset_info);
+ else if (!rights && !revoke_grant &&
+ lex->ssl_type == SSL_TYPE_NOT_SPECIFIED &&
+ !lex->mqh.specified_limits)
{
DBUG_RETURN(0);
}
@@ -1557,11 +1692,11 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
(*tmp_field)->store(&what, 1, &my_charset_latin1);
}
rights= get_access(table, 3, &next_field);
- DBUG_PRINT("info",("table->fields: %d",table->fields));
- if (table->fields >= 31) /* From 4.0.0 we have more fields */
+ DBUG_PRINT("info",("table fields: %d",table->s->fields));
+ if (table->s->fields >= 31) /* From 4.0.0 we have more fields */
{
/* We write down SSL related ACL stuff */
- switch (thd->lex->ssl_type) {
+ switch (lex->ssl_type) {
case SSL_TYPE_ANY:
table->field[next_field]->store("ANY", 3, &my_charset_latin1);
table->field[next_field+1]->store("", 0, &my_charset_latin1);
@@ -1579,18 +1714,15 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
table->field[next_field+1]->store("", 0, &my_charset_latin1);
table->field[next_field+2]->store("", 0, &my_charset_latin1);
table->field[next_field+3]->store("", 0, &my_charset_latin1);
- if (thd->lex->ssl_cipher)
- table->field[next_field+1]->store(thd->lex->ssl_cipher,
- strlen(thd->lex->ssl_cipher),
- &my_charset_latin1);
- if (thd->lex->x509_issuer)
- table->field[next_field+2]->store(thd->lex->x509_issuer,
- strlen(thd->lex->x509_issuer),
- &my_charset_latin1);
- if (thd->lex->x509_subject)
- table->field[next_field+3]->store(thd->lex->x509_subject,
- strlen(thd->lex->x509_subject),
- &my_charset_latin1);
+ if (lex->ssl_cipher)
+ table->field[next_field+1]->store(lex->ssl_cipher,
+ strlen(lex->ssl_cipher), system_charset_info);
+ if (lex->x509_issuer)
+ table->field[next_field+2]->store(lex->x509_issuer,
+ strlen(lex->x509_issuer), system_charset_info);
+ if (lex->x509_subject)
+ table->field[next_field+3]->store(lex->x509_subject,
+ strlen(lex->x509_subject), system_charset_info);
break;
case SSL_TYPE_NOT_SPECIFIED:
break;
@@ -1601,18 +1733,19 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
table->field[next_field+3]->store("", 0, &my_charset_latin1);
break;
}
+ next_field+=4;
- /* Skip over SSL related fields to first user limits related field */
- next_field+= 4;
-
- USER_RESOURCES mqh= thd->lex->mqh;
- if (mqh.bits & 1)
+ USER_RESOURCES mqh= lex->mqh;
+ if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
table->field[next_field]->store((longlong) mqh.questions);
- if (mqh.bits & 2)
+ if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
table->field[next_field+1]->store((longlong) mqh.updates);
- if (mqh.bits & 4)
- table->field[next_field+2]->store((longlong) mqh.connections);
- mqh_used = mqh_used || mqh.questions || mqh.updates || mqh.connections;
+ if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
+ table->field[next_field+2]->store((longlong) mqh.conn_per_hour);
+ if (table->s->fields >= 36 &&
+ (mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
+ table->field[next_field+3]->store((longlong) mqh.user_conn);
+ mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
}
if (old_row_exists)
{
@@ -1648,19 +1781,19 @@ end:
if (old_row_exists)
acl_update_user(combo.user.str, combo.host.str,
combo.password.str, password_len,
- thd->lex->ssl_type,
- thd->lex->ssl_cipher,
- thd->lex->x509_issuer,
- thd->lex->x509_subject,
- &thd->lex->mqh,
+ lex->ssl_type,
+ lex->ssl_cipher,
+ lex->x509_issuer,
+ lex->x509_subject,
+ &lex->mqh,
rights);
else
acl_insert_user(combo.user.str, combo.host.str, password, password_len,
- thd->lex->ssl_type,
- thd->lex->ssl_cipher,
- thd->lex->x509_issuer,
- thd->lex->x509_subject,
- &thd->lex->mqh,
+ lex->ssl_type,
+ lex->ssl_cipher,
+ lex->x509_issuer,
+ lex->x509_subject,
+ &lex->mqh,
rights);
}
DBUG_RETURN(error);
@@ -1680,6 +1813,7 @@ static int replace_db_table(TABLE *table, const char *db,
bool old_row_exists=0;
int error;
char what= (revoke_grant) ? 'N' : 'Y';
+ byte user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_db_table");
if (!initialized)
@@ -1691,18 +1825,20 @@ static int replace_db_table(TABLE *table, const char *db,
/* Check if there is such a user in user table in memory? */
if (!find_acl_user(combo.host.str,combo.user.str))
{
- my_error(ER_PASSWORD_NO_MATCH,MYF(0));
+ my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
DBUG_RETURN(-1);
}
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(db,(uint) strlen(db), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ key_copy(user_key, table->record[0], table->key_info,
+ table->key_info->key_length);
+
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (table->file->index_read_idx(table->record[0],0,
- (byte*) table->field[0]->ptr,
- table->key_info[0].key_length,
- HA_READ_KEY_EXACT))
+ user_key, table->key_info->key_length,
+ HA_READ_KEY_EXACT))
{
if (what == 'N')
{ // no row, no revoke
@@ -1710,10 +1846,10 @@ static int replace_db_table(TABLE *table, const char *db,
goto abort;
}
old_row_exists = 0;
- restore_record(table,default_values); // cp empty row from default_values
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ restore_record(table, s->default_values);
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(db,(uint) strlen(db), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
}
else
{
@@ -1722,7 +1858,7 @@ static int replace_db_table(TABLE *table, const char *db,
}
store_rights=get_rights_for_db(rights);
- for (i= 3, priv= 1; i < table->fields; i++, priv <<= 1)
+ for (i= 3, priv= 1; i < table->s->fields; i++, priv <<= 1)
{
if (priv & store_rights) // do it if priv is chosen
table->field [i]->store(&what,1, &my_charset_latin1);// set requested privileges
@@ -1789,27 +1925,40 @@ static byte* get_key_column(GRANT_COLUMN *buff,uint *length,
}
-class GRANT_TABLE :public Sql_alloc
+class GRANT_NAME :public Sql_alloc
{
public:
acl_host_and_ip host;
char *db, *user, *tname, *hash_key;
- ulong privs, cols;
+ ulong privs;
ulong sort;
uint key_length;
+ GRANT_NAME(const char *h, const char *d,const char *u,
+ const char *t, ulong p);
+ GRANT_NAME (TABLE *form);
+ virtual ~GRANT_NAME() {};
+ virtual bool ok() { return privs != 0; }
+};
+
+
+class GRANT_TABLE :public GRANT_NAME
+{
+public:
+ ulong cols;
HASH hash_columns;
GRANT_TABLE(const char *h, const char *d,const char *u,
const char *t, ulong p, ulong c);
GRANT_TABLE (TABLE *form, TABLE *col_privs);
+ ~GRANT_TABLE();
bool ok() { return privs != 0 || cols != 0; }
};
-GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
- const char *t, ulong p, ulong c)
- :privs(p), cols(c)
+GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u,
+ const char *t, ulong p)
+ :privs(p)
{
/* Host given by user */
update_hostname(&host, strdup_root(&memex, h));
@@ -1825,15 +1974,20 @@ GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
- (void) hash_init(&hash_columns,&my_charset_latin1,
- 0,0,0, (hash_get_key) get_key_column,0,0);
}
-GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
+GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
+ const char *t, ulong p, ulong c)
+ :GRANT_NAME(h,d,u,t,p), cols(c)
{
- byte key[MAX_KEY_LENGTH];
+ (void) hash_init(&hash_columns,system_charset_info,
+ 0,0,0, (hash_get_key) get_key_column,0,0);
+}
+
+GRANT_NAME::GRANT_NAME(TABLE *form)
+{
update_hostname(&host, get_field(&memex, form->field[0]));
db= get_field(&memex,form->field[1]);
user= get_field(&memex,form->field[2]);
@@ -1844,7 +1998,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
if (!db || !tname)
{
/* Wrong table row; Ignore it */
- privs = cols = 0; /* purecov: inspected */
+ privs= 0;
return; /* purecov: inspected */
}
if (lower_case_table_names)
@@ -1857,30 +2011,48 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
privs = (ulong) form->field[6]->val_int();
- cols = (ulong) form->field[7]->val_int();
privs = fix_rights_for_table(privs);
+}
+
+
+GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
+ :GRANT_NAME(form)
+{
+ byte key[MAX_KEY_LENGTH];
+
+ if (!db || !tname)
+ {
+ /* Wrong table row; Ignore it */
+ hash_clear(&hash_columns); /* allow for destruction */
+ cols= 0;
+ return;
+ }
+ cols= (ulong) form->field[7]->val_int();
cols = fix_rights_for_column(cols);
- (void) hash_init(&hash_columns,&my_charset_latin1,
+ (void) hash_init(&hash_columns,system_charset_info,
0,0,0, (hash_get_key) get_key_column,0,0);
if (cols)
{
- int key_len;
+ 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),
- &my_charset_latin1);
- col_privs->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- col_privs->field[2]->store(user,(uint) strlen(user), &my_charset_latin1);
- col_privs->field[3]->store(tname,(uint) strlen(tname), &my_charset_latin1);
- key_len=(col_privs->field[0]->pack_length()+
- col_privs->field[1]->pack_length()+
- col_privs->field[2]->pack_length()+
- col_privs->field[3]->pack_length());
- key_copy(key,col_privs,0,key_len);
+ 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);
+ col_privs->field[3]->store(tname,(uint) strlen(tname), system_charset_info);
+
+ key_prefix_len= (key_part[0].store_length +
+ key_part[1].store_length +
+ key_part[2].store_length +
+ key_part[3].store_length);
+ key_copy(key, col_privs->record[0], col_privs->key_info, key_prefix_len);
col_privs->field[4]->store("",0, &my_charset_latin1);
+
col_privs->file->ha_index_init(0);
if (col_privs->file->index_read(col_privs->record[0],
- (byte*) col_privs->field[0]->ptr,
- key_len, HA_READ_KEY_EXACT))
+ (byte*) key,
+ key_prefix_len, HA_READ_KEY_EXACT))
{
cols = 0; /* purecov: deadcode */
col_privs->file->ha_index_end();
@@ -1902,13 +2074,19 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
}
my_hash_insert(&hash_columns, (byte *) mem_check);
} while (!col_privs->file->index_next(col_privs->record[0]) &&
- !key_cmp_if_same(col_privs,key,0,key_len));
+ !key_cmp_if_same(col_privs,key,0,key_prefix_len));
col_privs->file->ha_index_end();
}
}
-static byte* get_grant_table(GRANT_TABLE *buff,uint *length,
+GRANT_TABLE::~GRANT_TABLE()
+{
+ hash_free(&hash_columns);
+}
+
+
+static byte* get_grant_table(GRANT_NAME *buff,uint *length,
my_bool not_used __attribute__((unused)))
{
*length=buff->key_length;
@@ -1924,39 +2102,57 @@ void free_grant_table(GRANT_TABLE *grant_table)
/* Search after a matching grant. Prefer exact grants before not exact ones */
-static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
+static GRANT_NAME *name_hash_search(HASH *name_hash,
+ const char *host,const char* ip,
const char *db,
const char *user, const char *tname,
bool exact)
{
char helping [NAME_LEN*2+USERNAME_LENGTH+3];
uint len;
- GRANT_TABLE *grant_table,*found=0;
+ GRANT_NAME *grant_name,*found=0;
len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1;
- for (grant_table=(GRANT_TABLE*) hash_search(&column_priv_hash,
+ for (grant_name=(GRANT_NAME*) hash_search(name_hash,
(byte*) helping,
len) ;
- grant_table ;
- grant_table= (GRANT_TABLE*) hash_next(&column_priv_hash,(byte*) helping,
+ grant_name ;
+ grant_name= (GRANT_NAME*) hash_next(name_hash,(byte*) helping,
len))
{
if (exact)
{
- if (compare_hostname(&grant_table->host, host, ip))
- return grant_table;
+ if (compare_hostname(&grant_name->host, host, ip))
+ return grant_name;
}
else
{
- if (compare_hostname(&grant_table->host, host, ip) &&
- (!found || found->sort < grant_table->sort))
- found=grant_table; // Host ok
+ if (compare_hostname(&grant_name->host, host, ip) &&
+ (!found || found->sort < grant_name->sort))
+ found=grant_name; // Host ok
}
}
return found;
}
+inline GRANT_NAME *
+proc_hash_search(const char *host, const char *ip, const char *db,
+ const char *user, const char *tname, bool exact)
+{
+ return (GRANT_TABLE*) name_hash_search(&proc_priv_hash, host, ip, db,
+ user, tname, exact);
+}
+
+
+inline GRANT_TABLE *
+table_hash_search(const char *host, const char *ip, const char *db,
+ const char *user, const char *tname, bool exact)
+{
+ return (GRANT_TABLE*) name_hash_search(&column_priv_hash, host, ip, db,
+ user, tname, exact);
+}
+
inline GRANT_COLUMN *
column_hash_search(GRANT_TABLE *t, const char *cname, uint length)
@@ -1972,19 +2168,22 @@ static int replace_column_table(GRANT_TABLE *g_t,
ulong rights, bool revoke_grant)
{
int error=0,result=0;
- uint key_length;
byte key[MAX_KEY_LENGTH];
+ uint key_prefix_length;
+ KEY_PART_INFO *key_part= table->key_info->key_part;
DBUG_ENTER("replace_column_table");
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
- table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1);
- key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+
- table->field[2]->pack_length()+ table->field[3]->pack_length());
- key_copy(key,table,0,key_length);
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(db,(uint) strlen(db), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
+
+ /* Get length of 3 first key parts */
+ key_prefix_length= (key_part[0].store_length + key_part[1].store_length +
+ key_part[2].store_length + key_part[3].store_length);
+ key_copy(key, table->record[0], table->key_info, key_prefix_length);
- rights &= COL_ACLS; // Only ACL for columns
+ rights&= COL_ACLS; // Only ACL for columns
/* first fix privileges for all columns in column list */
@@ -1995,27 +2194,35 @@ static int replace_column_table(GRANT_TABLE *g_t,
{
ulong privileges = xx->rights;
bool old_row_exists=0;
- key_restore(table,key,0,key_length);
+ byte user_key[MAX_KEY_LENGTH];
+
+ key_restore(table->record[0],key,table->key_info,
+ key_prefix_length);
table->field[4]->store(xx->column.ptr(),xx->column.length(),
- &my_charset_latin1);
+ system_charset_info);
+ /* Get key for the first 4 columns */
+ key_copy(user_key, table->record[0], table->key_info,
+ table->key_info->key_length);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,
- table->key_info[0].key_length,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read(table->record[0], user_key,
+ table->key_info->key_length,
+ HA_READ_KEY_EXACT))
{
if (revoke_grant)
{
my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
- combo.user.str, combo.host.str, table_name); /* purecov: inspected */
+ combo.user.str, combo.host.str,
+ table_name); /* purecov: inspected */
result= -1; /* purecov: inspected */
continue; /* purecov: inspected */
}
old_row_exists = 0;
- restore_record(table,default_values); // Get empty record
- key_restore(table,key,0,key_length);
+ restore_record(table, s->default_values); // Get empty record
+ key_restore(table->record[0],key,table->key_info,
+ key_prefix_length);
table->field[4]->store(xx->column.ptr(),xx->column.length(),
- &my_charset_latin1);
+ system_charset_info);
}
else
{
@@ -2070,10 +2277,14 @@ static int replace_column_table(GRANT_TABLE *g_t,
if (revoke_grant)
{
+ byte user_key[MAX_KEY_LENGTH];
+ key_copy(user_key, table->record[0], table->key_info,
+ key_prefix_length);
+
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read(table->record[0], (byte*) table->field[0]->ptr,
- key_length,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read(table->record[0], user_key,
+ key_prefix_length,
+ HA_READ_KEY_EXACT))
goto end;
/* Scan through all rows with the same host,db,user and table */
@@ -2087,7 +2298,8 @@ static int replace_column_table(GRANT_TABLE *g_t,
{
GRANT_COLUMN *grant_column = NULL;
char colum_name_buf[HOSTNAME_LENGTH+1];
- String column_name(colum_name_buf,sizeof(colum_name_buf),&my_charset_latin1);
+ String column_name(colum_name_buf,sizeof(colum_name_buf),
+ system_charset_info);
privileges&= ~rights;
table->field[6]->store((longlong)
@@ -2123,7 +2335,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
}
}
} while (!table->file->index_next(table->record[0]) &&
- !key_cmp_if_same(table,key,0,key_length));
+ !key_cmp_if_same(table, key, 0, key_prefix_length));
}
end:
@@ -2142,6 +2354,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
int old_row_exists = 1;
int error=0;
ulong store_table_rights, store_col_rights;
+ byte user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_table_table");
strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS);
@@ -2152,20 +2365,23 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
*/
if (!find_acl_user(combo.host.str,combo.user.str))
{
- my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */
+ my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
+ MYF(0)); /* purecov: deadcode */
DBUG_RETURN(-1); /* purecov: deadcode */
}
- restore_record(table,default_values); // Get empty record
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
- table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
- table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1);
+ restore_record(table, s->default_values); // Get empty record
+ table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[1]->store(db,(uint) strlen(db), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
store_record(table,record[1]); // store at pos 1
+ key_copy(user_key, table->record[0], table->key_info,
+ table->key_info->key_length);
+
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read_idx(table->record[0],0,
- (byte*) table->field[0]->ptr,
- table->key_info[0].key_length,
+ if (table->file->index_read_idx(table->record[0], 0,
+ user_key, table->key_info->key_length,
HA_READ_KEY_EXACT))
{
/*
@@ -2177,7 +2393,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
{ // no row, no revoke
my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
combo.user.str, combo.host.str,
- table_name); /* purecov: deadcode */
+ table_name); /* purecov: deadcode */
DBUG_RETURN(-1); /* purecov: deadcode */
}
old_row_exists = 0;
@@ -2205,7 +2421,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
}
- table->field[4]->store(grantor,(uint) strlen(grantor), &my_charset_latin1);
+ table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info);
table->field[6]->store((longlong) store_table_rights);
table->field[7]->store((longlong) store_col_rights);
rights=fix_rights_for_table(store_table_rights);
@@ -2246,6 +2462,117 @@ table_error:
}
+static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
+ TABLE *table, const LEX_USER &combo,
+ const char *db, const char *proc_name,
+ ulong rights, bool revoke_grant)
+{
+ char grantor[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
+ int old_row_exists= 1;
+ int error=0;
+ ulong store_proc_rights;
+ DBUG_ENTER("replace_proc_table");
+
+ if (!initialized)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
+ DBUG_RETURN(-1);
+ }
+
+ strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS);
+
+ /*
+ The following should always succeed as new users are created before
+ this function is called!
+ */
+ if (!find_acl_user(combo.host.str,combo.user.str))
+ {
+ my_error(ER_PASSWORD_NO_MATCH,MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ restore_record(table, s->default_values); // Get empty record
+ table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
+ table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
+ table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ table->field[3]->store(proc_name,(uint) strlen(proc_name), &my_charset_latin1);
+ store_record(table,record[1]); // store at pos 1
+
+ if (table->file->index_read_idx(table->record[0],0,
+ (byte*) table->field[0]->ptr,0,
+ HA_READ_KEY_EXACT))
+ {
+ /*
+ The following should never happen as we first check the in memory
+ grant tables for the user. There is however always a small change that
+ the user has modified the grant tables directly.
+ */
+ if (revoke_grant)
+ { // no row, no revoke
+ my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
+ combo.user.str, combo.host.str, proc_name);
+ DBUG_RETURN(-1);
+ }
+ old_row_exists= 0;
+ restore_record(table,record[1]); // Get saved record
+ }
+
+ store_proc_rights= get_rights_for_procedure(rights);
+ if (old_row_exists)
+ {
+ ulong j;
+ store_record(table,record[1]);
+ j= (ulong) table->field[6]->val_int();
+
+ if (revoke_grant)
+ {
+ /* column rights are already fixed in mysql_table_grant */
+ store_proc_rights=j & ~store_proc_rights;
+ }
+ else
+ {
+ store_proc_rights|= j;
+ }
+ }
+
+ table->field[4]->store(grantor,(uint) strlen(grantor), &my_charset_latin1);
+ table->field[6]->store((longlong) store_proc_rights);
+ rights=fix_rights_for_procedure(store_proc_rights);
+
+ if (old_row_exists)
+ {
+ if (store_proc_rights)
+ {
+ if ((error=table->file->update_row(table->record[1],table->record[0])))
+ goto table_error;
+ }
+ else if ((error= table->file->delete_row(table->record[1])))
+ goto table_error;
+ }
+ else
+ {
+ error=table->file->write_row(table->record[0]);
+ if (error && error != HA_ERR_FOUND_DUPP_KEY)
+ goto table_error;
+ }
+
+ if (rights)
+ {
+ grant_name->privs= rights;
+ }
+ else
+ {
+ hash_delete(&proc_priv_hash,(byte*) grant_name);
+ }
+ DBUG_RETURN(0);
+
+ /* This should never happen */
+table_error:
+ table->file->print_error(error,MYF(0));
+ DBUG_RETURN(-1);
+}
+
+
/*
Store table level and column level grants in the privilege tables
@@ -2259,11 +2586,11 @@ table_error:
revoke_grant Set to 1 if this is a REVOKE command
RETURN
- 0 ok
- 1 error
+ FALSE ok
+ TRUE error
*/
-int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
+bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
List <LEX_USER> &user_list,
List <LEX_COLUMN> &columns, ulong rights,
bool revoke_grant)
@@ -2273,45 +2600,47 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
LEX_USER *Str;
TABLE_LIST tables[3];
bool create_new_users=0;
+ char *db_name, *table_name;
DBUG_ENTER("mysql_table_grant");
if (!initialized)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
"--skip-grant-tables"); /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
+ DBUG_RETURN(TRUE); /* purecov: inspected */
}
if (rights & ~TABLE_ACLS)
{
- my_error(ER_ILLEGAL_GRANT_FOR_TABLE,MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
+ MYF(0));
+ DBUG_RETURN(TRUE);
}
if (!revoke_grant)
{
- if (columns.elements && !revoke_grant)
+ if (columns.elements)
{
- TABLE *table;
class LEX_COLUMN *column;
List_iterator <LEX_COLUMN> column_iter(columns);
- if (!(table=open_ltable(thd,table_list,TL_READ)))
- DBUG_RETURN(-1);
+ if (open_and_lock_tables(thd, table_list))
+ DBUG_RETURN(TRUE);
+
while ((column = column_iter++))
{
uint unused_field_idx= NO_CACHED_FIELD_INDEX;
- Field *f= find_field_in_table(thd,table,column->column.ptr(),
- column->column.length(),1,0,&unused_field_idx);
- if (!f)
+ Field *f=find_field_in_table(thd, table_list, column->column.ptr(),
+ column->column.ptr(),
+ column->column.length(), 0, 1, 1, 0,
+ &unused_field_idx, FALSE);
+ if (f == (Field*)0)
{
my_error(ER_BAD_FIELD_ERROR, MYF(0),
column->column.c_ptr(), table_list->alias);
- DBUG_RETURN(-1);
- }
- if (f == (Field*)-1)
- {
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
+ if (f == (Field *)-1)
+ DBUG_RETURN(TRUE);
column_priv|= column->rights;
}
close_thread_tables(thd);
@@ -2322,12 +2651,12 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
{
char buf[FN_REFLEN];
sprintf(buf,"%s/%s/%s.frm",mysql_data_home, table_list->db,
- table_list->real_name);
+ table_list->table_name);
fn_format(buf,buf,"","",4+16+32);
if (access(buf,F_OK))
{
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
if (table_list->grant.want_privilege)
@@ -2336,7 +2665,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
get_privilege_desc(command, sizeof(command),
table_list->grant.want_privilege);
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
- command, thd->priv_user, thd->host_or_ip, table_list->alias);
+ command, thd->priv_user, thd->host_or_ip, table_list->alias);
DBUG_RETURN(-1);
}
}
@@ -2345,14 +2674,16 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/* open the mysql.tables_priv and mysql.columns_priv tables */
bzero((char*) &tables,sizeof(tables));
- tables[0].alias=tables[0].real_name= (char*) "user";
- tables[1].alias=tables[1].real_name= (char*) "tables_priv";
- tables[2].alias=tables[2].real_name= (char*) "columns_priv";
- tables[0].next=tables+1;
+ tables[0].alias=tables[0].table_name= (char*) "user";
+ tables[1].alias=tables[1].table_name= (char*) "tables_priv";
+ tables[2].alias=tables[2].table_name= (char*) "columns_priv";
+ tables[0].next_local= tables[0].next_global= tables+1;
/* Don't open column table if we don't need it ! */
- tables[1].next=((column_priv ||
- (revoke_grant && ((rights & COL_ACLS) || columns.elements)))
- ? tables+2 : 0);
+ tables[1].next_local=
+ tables[1].next_global= ((column_priv ||
+ (revoke_grant &&
+ ((rights & COL_ACLS) || columns.elements)))
+ ? tables+2 : 0);
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
@@ -2369,19 +2700,19 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
*/
tables[0].updating= tables[1].updating= tables[2].updating= 1;
if (!tables_ok(0, tables))
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
#endif
if (simple_open_n_lock_tables(thd,tables))
{ // Should never happen
close_thread_tables(thd); /* purecov: deadcode */
- DBUG_RETURN(-1); /* purecov: deadcode */
+ DBUG_RETURN(TRUE); /* purecov: deadcode */
}
if (!revoke_grant)
create_new_users= test_if_create_new_users(thd);
- int result=0;
+ bool result= FALSE;
rw_wrlock(&LOCK_grant);
MEM_ROOT *old_root= thd->mem_root;
thd->mem_root= &memex;
@@ -2393,42 +2724,50 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
- my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
- result= -1;
+ my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
+ MYF(0));
+ result= TRUE;
continue;
}
/* Create user if needed */
pthread_mutex_lock(&acl_cache->lock);
error=replace_user_table(thd, tables[0].table, *Str,
- 0, revoke_grant, create_new_users);
+ 0, revoke_grant, create_new_users,
+ test(thd->variables.sql_mode &
+ MODE_NO_AUTO_CREATE_USER));
pthread_mutex_unlock(&acl_cache->lock);
if (error)
{
- result= -1; // Remember error
+ result= TRUE; // Remember error
continue; // Add next user
}
+ db_name= (table_list->view_db.length ?
+ table_list->view_db.str :
+ table_list->db);
+ table_name= (table_list->view_name.length ?
+ table_list->view_name.str :
+ table_list->table_name);
+
/* Find/create cached table grant */
- grant_table= table_hash_search(Str->host.str,NullS,table_list->db,
- Str->user.str,
- table_list->real_name,1);
+ grant_table= table_hash_search(Str->host.str, NullS, db_name,
+ Str->user.str, table_name, 1);
if (!grant_table)
{
if (revoke_grant)
{
my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
- Str->user.str, Str->host.str, table_list->real_name);
- result= -1;
+ Str->user.str, Str->host.str, table_list->table_name);
+ result= TRUE;
continue;
}
- grant_table = new GRANT_TABLE (Str->host.str,table_list->db,
- Str->user.str,
- table_list->real_name,
+ grant_table = new GRANT_TABLE (Str->host.str, db_name,
+ Str->user.str, table_name,
rights,
column_priv);
if (!grant_table) // end of memory
{
- result= -1; /* purecov: deadcode */
+ result= TRUE; /* purecov: deadcode */
continue; /* purecov: deadcode */
}
my_hash_insert(&column_priv_hash,(byte*) grant_table);
@@ -2468,23 +2807,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/* update table and columns */
- if (replace_table_table(thd,grant_table,tables[1].table,*Str,
- table_list->db,
- table_list->real_name,
+ if (replace_table_table(thd, grant_table, tables[1].table, *Str,
+ db_name, table_name,
rights, column_priv, revoke_grant))
{
/* Should only happen if table is crashed */
- result= -1; /* purecov: deadcode */
+ result= TRUE; /* purecov: deadcode */
}
else if (tables[2].table)
{
- if ((replace_column_table(grant_table,tables[2].table, *Str,
+ if ((replace_column_table(grant_table, tables[2].table, *Str,
columns,
- table_list->db,
- table_list->real_name,
+ db_name, table_name,
rights, revoke_grant)))
{
- result= -1;
+ result= TRUE;
}
}
}
@@ -2498,8 +2835,165 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
-int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
- ulong rights, bool revoke_grant)
+/*
+ Store procedure level grants in the privilege tables
+
+ SYNOPSIS
+ mysql_procedure_grant()
+ thd Thread handle
+ table_list List of procedures to give grant
+ user_list List of users to give grant
+ rights Table level grant
+ revoke_grant Set to 1 if this is a REVOKE command
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
+ List <LEX_USER> &user_list, ulong rights,
+ bool revoke_grant, bool no_error)
+{
+ List_iterator <LEX_USER> str_list (user_list);
+ LEX_USER *Str;
+ TABLE_LIST tables[2];
+ bool create_new_users=0, result=0;
+ char *db_name, *table_name;
+ DBUG_ENTER("mysql_procedure_grant");
+
+ if (!initialized)
+ {
+ if (!no_error)
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
+ "--skip-grant-tables");
+ DBUG_RETURN(TRUE);
+ }
+ if (rights & ~PROC_ACLS)
+ {
+ if (!no_error)
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
+ MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ if (!revoke_grant)
+ {
+ if (sp_exists_routine(thd, table_list, 0, no_error)<0)
+ DBUG_RETURN(TRUE);
+ }
+
+ /* open the mysql.user and mysql.procs_priv tables */
+
+ bzero((char*) &tables,sizeof(tables));
+ tables[0].alias=tables[0].table_name= (char*) "user";
+ tables[1].alias=tables[1].table_name= (char*) "procs_priv";
+ tables[0].next_local= tables[0].next_global= tables+1;
+ tables[0].lock_type=tables[1].lock_type=TL_WRITE;
+ tables[0].db=tables[1].db=(char*) "mysql";
+
+#ifdef HAVE_REPLICATION
+ /*
+ GRANT and REVOKE are applied the slave in/exclusion rules as they are
+ some kind of updates to the mysql.% tables.
+ */
+ if (thd->slave_thread && table_rules_on)
+ {
+ /*
+ The tables must be marked "updating" so that tables_ok() takes them into
+ account in tests.
+ */
+ tables[0].updating= tables[1].updating= 1;
+ if (!tables_ok(0, tables))
+ DBUG_RETURN(FALSE);
+ }
+#endif
+
+ if (simple_open_n_lock_tables(thd,tables))
+ { // Should never happen
+ close_thread_tables(thd);
+ DBUG_RETURN(TRUE);
+ }
+
+ if (!revoke_grant)
+ create_new_users= test_if_create_new_users(thd);
+ rw_wrlock(&LOCK_grant);
+ MEM_ROOT *old_root= thd->mem_root;
+ thd->mem_root= &memex;
+
+ DBUG_PRINT("info",("now time to iterate and add users"));
+
+ while ((Str= str_list++))
+ {
+ int error;
+ GRANT_NAME *grant_name;
+ if (Str->host.length > HOSTNAME_LENGTH ||
+ Str->user.length > USERNAME_LENGTH)
+ {
+ if (!no_error)
+ my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
+ MYF(0));
+ result= TRUE;
+ continue;
+ }
+ /* Create user if needed */
+ pthread_mutex_lock(&acl_cache->lock);
+ error=replace_user_table(thd, tables[0].table, *Str,
+ 0, revoke_grant, create_new_users,
+ test(thd->variables.sql_mode &
+ MODE_NO_AUTO_CREATE_USER));
+ pthread_mutex_unlock(&acl_cache->lock);
+ if (error)
+ {
+ result= TRUE; // Remember error
+ continue; // Add next user
+ }
+
+ db_name= table_list->db;
+ table_name= table_list->table_name;
+
+ grant_name= proc_hash_search(Str->host.str, NullS, db_name,
+ Str->user.str, table_name, 1);
+ if (!grant_name)
+ {
+ if (revoke_grant)
+ {
+ if (!no_error)
+ my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
+ Str->user.str, Str->host.str, table_name);
+ result= TRUE;
+ continue;
+ }
+ grant_name= new GRANT_NAME(Str->host.str, db_name,
+ Str->user.str, table_name,
+ rights);
+ if (!grant_name)
+ {
+ result= TRUE;
+ continue;
+ }
+ my_hash_insert(&proc_priv_hash,(byte*) grant_name);
+ }
+
+ if (replace_proc_table(thd, grant_name, tables[1].table, *Str,
+ db_name, table_name, rights, revoke_grant))
+ {
+ result= TRUE;
+ continue;
+ }
+ }
+ grant_option=TRUE;
+ thd->mem_root= old_root;
+ rw_unlock(&LOCK_grant);
+ if (!result && !no_error)
+ send_ok(thd);
+ /* Tables are automatically closed */
+ DBUG_RETURN(result);
+}
+
+
+bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
+ ulong rights, bool revoke_grant)
{
List_iterator <LEX_USER> str_list (list);
LEX_USER *Str;
@@ -2511,7 +3005,7 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
"--skip-grant-tables"); /* purecov: tested */
- DBUG_RETURN(-1); /* purecov: tested */
+ DBUG_RETURN(TRUE); /* purecov: tested */
}
if (lower_case_table_names && db)
@@ -2523,13 +3017,11 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
/* open the mysql.user and mysql.db tables */
bzero((char*) &tables,sizeof(tables));
- tables[0].alias=tables[0].real_name=(char*) "user";
- tables[1].alias=tables[1].real_name=(char*) "db";
- tables[0].next=tables+1;
- tables[1].next=0;
+ tables[0].alias=tables[0].table_name=(char*) "user";
+ tables[1].alias=tables[1].table_name=(char*) "db";
+ tables[0].next_local= tables[0].next_global= tables+1;
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
tables[0].db=tables[1].db=(char*) "mysql";
- tables[0].table=tables[1].table=0;
#ifdef HAVE_REPLICATION
/*
@@ -2544,14 +3036,14 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
*/
tables[0].updating= tables[1].updating= 1;
if (!tables_ok(0, tables))
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
#endif
if (simple_open_n_lock_tables(thd,tables))
{ // This should never happen
close_thread_tables(thd); /* purecov: deadcode */
- DBUG_RETURN(-1); /* purecov: deadcode */
+ DBUG_RETURN(TRUE); /* purecov: deadcode */
}
if (!revoke_grant)
@@ -2568,15 +3060,15 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
- my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
+ my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
+ MYF(0));
result= -1;
continue;
}
- if ((replace_user_table(thd,
- tables[0].table,
- *Str,
- (!db ? rights : 0), revoke_grant,
- create_new_users)))
+ if (replace_user_table(thd, tables[0].table, *Str,
+ (!db ? rights : 0), revoke_grant, create_new_users,
+ test(thd->variables.sql_mode &
+ MODE_NO_AUTO_CREATE_USER)))
result= -1;
else if (db)
{
@@ -2611,6 +3103,7 @@ void grant_free(void)
DBUG_ENTER("grant_free");
grant_option = FALSE;
hash_free(&column_priv_hash);
+ hash_free(&proc_priv_hash);
free_root(&memex,MYF(0));
DBUG_VOID_RETURN;
}
@@ -2621,18 +3114,20 @@ void grant_free(void)
my_bool grant_init(THD *org_thd)
{
THD *thd;
- TABLE_LIST tables[2];
- MYSQL_LOCK *lock;
+ TABLE_LIST tables[3];
MEM_ROOT *memex_ptr;
my_bool return_val= 1;
- TABLE *t_table, *c_table;
+ TABLE *t_table, *c_table, *p_table;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
DBUG_ENTER("grant_init");
grant_option = FALSE;
- (void) hash_init(&column_priv_hash,&my_charset_latin1,
+ (void) hash_init(&column_priv_hash,system_charset_info,
0,0,0, (hash_get_key) get_grant_table,
(hash_free_key) free_grant_table,0);
+ (void) hash_init(&proc_priv_hash,system_charset_info,
+ 0,0,0, (hash_get_key) get_grant_table,
+ 0,0);
init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
/* Don't do anything if running with --skip-grant */
@@ -2645,69 +3140,104 @@ my_bool grant_init(THD *org_thd)
thd->db= my_strdup("mysql",MYF(0));
thd->db_length=5; // Safety
bzero((char*) &tables, sizeof(tables));
- tables[0].alias=tables[0].real_name= (char*) "tables_priv";
- tables[1].alias=tables[1].real_name= (char*) "columns_priv";
- tables[0].next=tables+1;
- tables[0].lock_type=tables[1].lock_type=TL_READ;
- tables[0].db=tables[1].db=thd->db;
-
- uint counter;
- if (open_tables(thd, tables, &counter))
- goto end;
+ tables[0].alias=tables[0].table_name= (char*) "tables_priv";
+ tables[1].alias=tables[1].table_name= (char*) "columns_priv";
+ tables[2].alias=tables[2].table_name= (char*) "procs_priv";
+ tables[0].next_local= tables[0].next_global= tables+1;
+ tables[1].next_local= tables[1].next_global= tables+2;
+ tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
+ tables[0].db=tables[1].db=tables[2].db=thd->db;
- TABLE *ptr[2]; // Lock tables for quick update
- ptr[0]= tables[0].table;
- ptr[1]= tables[1].table;
- if (!(lock=mysql_lock_tables(thd,ptr,2)))
+ if (simple_open_n_lock_tables(thd, tables))
goto end;
t_table = tables[0].table; c_table = tables[1].table;
+ p_table= tables[2].table;
t_table->file->ha_index_init(0);
- if (t_table->file->index_first(t_table->record[0]))
+ p_table->file->ha_index_init(0);
+ if (!t_table->file->index_first(t_table->record[0]))
{
- return_val= 0;
- goto end_unlock;
- }
- grant_option= TRUE;
+ /* Will be restored by org_thd->store_globals() */
+ memex_ptr= &memex;
+ my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
+ do
+ {
+ GRANT_TABLE *mem_check;
+ if (!(mem_check=new GRANT_TABLE(t_table,c_table)))
+ {
+ /* This could only happen if we are out memory */
+ grant_option= FALSE;
+ goto end_unlock;
+ }
- /* Will be restored by org_thd->store_globals() */
- memex_ptr= &memex;
- my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
- do
+ if (check_no_resolve)
+ {
+ if (hostname_requires_resolving(mem_check->host.hostname))
+ {
+ sql_print_warning("'tables_priv' entry '%s %s@%s' "
+ "ignored in --skip-name-resolve mode.",
+ mem_check->tname, mem_check->user,
+ mem_check->host, mem_check->host);
+ continue;
+ }
+ }
+
+ if (! mem_check->ok())
+ delete mem_check;
+ else if (my_hash_insert(&column_priv_hash,(byte*) mem_check))
+ {
+ delete mem_check;
+ grant_option= FALSE;
+ goto end_unlock;
+ }
+ }
+ while (!t_table->file->index_next(t_table->record[0]));
+ }
+ if (!p_table->file->index_first(p_table->record[0]))
{
- GRANT_TABLE *mem_check;
- if (!(mem_check=new GRANT_TABLE(t_table,c_table)))
+ /* Will be restored by org_thd->store_globals() */
+ memex_ptr= &memex;
+ my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
+ do
{
- /* This could only happen if we are out memory */
- grant_option= FALSE; /* purecov: deadcode */
- goto end_unlock;
- }
+ GRANT_NAME *mem_check;
+ if (!(mem_check=new GRANT_NAME(p_table)))
+ {
+ /* This could only happen if we are out memory */
+ grant_option= FALSE;
+ goto end_unlock;
+ }
- if (check_no_resolve)
- {
- if (hostname_requires_resolving(mem_check->host.hostname))
+ if (check_no_resolve)
{
- sql_print_warning("'tables_priv' entry '%s %s@%s' "
- "ignored in --skip-name-resolve mode.",
- mem_check->tname, mem_check->user,
- mem_check->host, mem_check->host);
- continue;
+ if (hostname_requires_resolving(mem_check->host.hostname))
+ {
+ sql_print_warning("'procs_priv' entry '%s %s@%s' "
+ "ignored in --skip-name-resolve mode.",
+ mem_check->tname, mem_check->user,
+ mem_check->host, mem_check->host);
+ continue;
+ }
}
- }
- if (mem_check->ok() && my_hash_insert(&column_priv_hash,(byte*) mem_check))
- {
- grant_option= FALSE;
- goto end_unlock;
+ mem_check->privs= fix_rights_for_procedure(mem_check->privs);
+ if (! mem_check->ok())
+ delete mem_check;
+ else if (my_hash_insert(&proc_priv_hash,(byte*) mem_check))
+ {
+ delete mem_check;
+ grant_option= FALSE;
+ goto end_unlock;
+ }
}
+ while (!p_table->file->index_next(p_table->record[0]));
}
- while (!t_table->file->index_next(t_table->record[0]));
-
+ grant_option= TRUE;
return_val=0; // Return ok
end_unlock:
t_table->file->ha_index_end();
- mysql_unlock_tables(thd, lock);
+ p_table->file->ha_index_end();
thd->version--; // Force close to free memory
end:
@@ -2737,7 +3267,7 @@ end:
void grant_reload(THD *thd)
{
- HASH old_column_priv_hash;
+ HASH old_column_priv_hash, old_proc_priv_hash;
bool old_grant_option;
MEM_ROOT old_mem;
DBUG_ENTER("grant_reload");
@@ -2745,6 +3275,7 @@ void grant_reload(THD *thd)
rw_wrlock(&LOCK_grant);
grant_version++;
old_column_priv_hash= column_priv_hash;
+ old_proc_priv_hash= proc_priv_hash;
old_grant_option= grant_option;
old_mem= memex;
@@ -2753,12 +3284,14 @@ void grant_reload(THD *thd)
DBUG_PRINT("error",("Reverting to old privileges"));
grant_free(); /* purecov: deadcode */
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
+ proc_priv_hash= old_proc_priv_hash;
grant_option= old_grant_option; /* purecov: deadcode */
memex= old_mem; /* purecov: deadcode */
}
else
{
hash_free(&old_column_priv_hash);
+ hash_free(&old_proc_priv_hash);
free_root(&old_mem,MYF(0));
}
rw_unlock(&LOCK_grant);
@@ -2768,7 +3301,22 @@ void grant_reload(THD *thd)
/****************************************************************************
Check table level grants
- All errors are written directly to the client if no_errors is given !
+
+ SYNOPSIS
+ bool check_grant()
+ thd Thread handler
+ want_access Bits of privileges user needs to have
+ tables List of tables to check. The user should have 'want_access'
+ to all tables in list.
+ show_table <> 0 if we are in show table. In this case it's enough to have
+ any privilege for the table
+ number Check at most this number of tables.
+ no_errors If 0 then we write an error. The error is sent directly to
+ the client
+
+ RETURN
+ 0 ok
+ 1 Error: User did not have the requested privileges
****************************************************************************/
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
@@ -2777,23 +3325,28 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
TABLE_LIST *table;
char *user = thd->priv_user;
DBUG_ENTER("check_grant");
+ DBUG_ASSERT(number > 0);
- want_access &= ~thd->master_access;
+ want_access&= ~thd->master_access;
if (!want_access)
DBUG_RETURN(0); // ok
rw_rdlock(&LOCK_grant);
- for (table= tables; table && number--; table= table->next)
+ for (table= tables; table && number--; table= table->next_global)
{
- if (!(~table->grant.privilege & want_access) || table->derived)
+ GRANT_TABLE *grant_table;
+ if (!(~table->grant.privilege & want_access) ||
+ table->derived || table->schema_table || table->belong_to_view)
{
- table->grant.want_privilege=0;
+ /*
+ It is subquery in the FROM clause. VIEW set table->derived after
+ table opening, but this function always called before table opening.
+ */
+ table->grant.want_privilege= 0;
continue; // Already checked
}
- GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,
- table->db,user,
- table->real_name,0);
- if (!grant_table)
+ if (!(grant_table= table_hash_search(thd->host,thd->ip,
+ table->db,user, table->table_name,0)))
{
want_access &= ~table->grant.privilege;
goto err; // No grants
@@ -2825,137 +3378,133 @@ err:
{
char command[128];
get_privilege_desc(command, sizeof(command), want_access);
- net_printf(thd,ER_TABLEACCESS_DENIED_ERROR,
- command,
- thd->priv_user,
- thd->host_or_ip,
- table ? table->real_name : "unknown");
+ my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
+ command,
+ thd->priv_user,
+ thd->host_or_ip,
+ table ? table->table_name : "unknown");
}
DBUG_RETURN(1);
}
-bool check_grant_column(THD *thd,TABLE *table, const char *name,
- uint length, uint show_tables)
+bool check_grant_column(THD *thd, GRANT_INFO *grant,
+ const char *db_name, const char *table_name,
+ const char *name, uint length, uint show_tables)
{
GRANT_TABLE *grant_table;
GRANT_COLUMN *grant_column;
+ ulong want_access= grant->want_privilege & ~grant->privilege;
+ DBUG_ENTER("check_grant_column");
+ DBUG_PRINT("enter", ("table: %s want_access: %u", table_name, want_access));
- ulong want_access=table->grant.want_privilege;
if (!want_access)
- return 0; // Already checked
+ DBUG_RETURN(0); // Already checked
rw_rdlock(&LOCK_grant);
/* reload table if someone has modified any grants */
- if (table->grant.version != grant_version)
+ if (grant->version != grant_version)
{
- table->grant.grant_table=
- table_hash_search(thd->host, thd->ip, table->table_cache_key,
+ grant->grant_table=
+ table_hash_search(thd->host, thd->ip, db_name,
thd->priv_user,
- table->real_name, 0); /* purecov: inspected */
- table->grant.version=grant_version; /* purecov: inspected */
+ table_name, 0); /* purecov: inspected */
+ grant->version= grant_version; /* purecov: inspected */
}
- if (!(grant_table=table->grant.grant_table))
+ if (!(grant_table= grant->grant_table))
goto err; /* purecov: deadcode */
grant_column=column_hash_search(grant_table, name, length);
if (grant_column && !(~grant_column->rights & want_access))
{
rw_unlock(&LOCK_grant);
- return 0;
+ DBUG_RETURN(0);
}
#ifdef NOT_USED
- if (show_tables && (grant_column || table->grant.privilege & COL_ACLS))
+ if (show_tables && (grant_column || grant->privilege & COL_ACLS))
{
rw_unlock(&LOCK_grant); /* purecov: deadcode */
- return 0; /* purecov: deadcode */
+ DBUG_RETURN(0); /* purecov: deadcode */
}
#endif
- /* We must use my_printf_error() here! */
err:
rw_unlock(&LOCK_grant);
if (!show_tables)
{
char command[128];
get_privilege_desc(command, sizeof(command), want_access);
- my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
- ER(ER_COLUMNACCESS_DENIED_ERROR),
- MYF(0),
- command,
- thd->priv_user,
- thd->host_or_ip,
- name,
- table ? table->real_name : "unknown");
+ my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
+ command,
+ thd->priv_user,
+ thd->host_or_ip,
+ name,
+ table_name);
}
- return 1;
+ DBUG_RETURN(1);
}
-bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
+bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
+ const char* db_name, const char *table_name,
+ Field_iterator *fields)
{
GRANT_TABLE *grant_table;
GRANT_COLUMN *grant_column;
- Field *field=0,**ptr;
- want_access &= ~table->grant.privilege;
+ want_access &= ~grant->privilege;
if (!want_access)
return 0; // Already checked
if (!grant_option)
- {
- field= table->field[0]; // To give a meaningful error message
goto err2;
- }
rw_rdlock(&LOCK_grant);
/* reload table if someone has modified any grants */
- if (table->grant.version != grant_version)
+ if (grant->version != grant_version)
{
- table->grant.grant_table=
- table_hash_search(thd->host, thd->ip, table->table_cache_key,
+ grant->grant_table=
+ table_hash_search(thd->host, thd->ip, db_name,
thd->priv_user,
- table->real_name,0); /* purecov: inspected */
- table->grant.version=grant_version; /* purecov: inspected */
+ table_name, 0); /* purecov: inspected */
+ grant->version= grant_version; /* purecov: inspected */
}
/* The following should always be true */
- if (!(grant_table=table->grant.grant_table))
+ if (!(grant_table= grant->grant_table))
goto err; /* purecov: inspected */
- for (ptr=table->field; (field= *ptr) ; ptr++)
+ for (; !fields->end_of_fields(); fields->next())
{
- grant_column=column_hash_search(grant_table, field->field_name,
- (uint) strlen(field->field_name));
+ const char *field_name= fields->name();
+ grant_column= column_hash_search(grant_table, field_name,
+ (uint) strlen(field_name));
if (!grant_column || (~grant_column->rights & want_access))
goto err;
}
rw_unlock(&LOCK_grant);
return 0;
- /* We must use my_printf_error() here! */
err:
rw_unlock(&LOCK_grant);
err2:
char command[128];
get_privilege_desc(command, sizeof(command), want_access);
- my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
- ER(ER_COLUMNACCESS_DENIED_ERROR),
- MYF(0),
- command,
- thd->priv_user,
- thd->host_or_ip,
- field ? field->field_name : "unknown",
- table->real_name);
+ my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
+ command,
+ thd->priv_user,
+ thd->host_or_ip,
+ fields->name(),
+ table_name);
return 1;
}
/*
Check if a user has the right to access a database
- Access is accepted if he has a grant for any table in the database
+ Access is accepted if he has a grant for any table/routine in the database
Return 1 if access is denied
*/
@@ -2984,6 +3533,103 @@ bool check_grant_db(THD *thd,const char *db)
return error;
}
+
+/****************************************************************************
+ Check procedure level grants
+
+ SYNPOSIS
+ bool check_grant_procedure()
+ thd Thread handler
+ want_access Bits of privileges user needs to have
+ procs List of procedures to check. The user should have 'want_access'
+ no_errors If 0 then we write an error. The error is sent directly to
+ the client
+
+ RETURN
+ 0 ok
+ 1 Error: User did not have the requested privielges
+****************************************************************************/
+
+bool check_grant_procedure(THD *thd, ulong want_access,
+ TABLE_LIST *procs, bool no_errors)
+{
+ TABLE_LIST *table;
+ char *user= thd->priv_user;
+ char *host= thd->priv_host;
+ DBUG_ENTER("check_grant_procedure");
+
+ want_access&= ~thd->master_access;
+ if (!want_access)
+ DBUG_RETURN(0); // ok
+
+ rw_rdlock(&LOCK_grant);
+ for (table= procs; table; table= table->next_global)
+ {
+ GRANT_NAME *grant_proc;
+ if ((grant_proc= proc_hash_search(host,thd->ip,
+ table->db, user, table->table_name, 0)))
+ table->grant.privilege|= grant_proc->privs;
+
+ if (want_access & ~table->grant.privilege)
+ {
+ want_access &= ~table->grant.privilege;
+ goto err;
+ }
+ }
+ rw_unlock(&LOCK_grant);
+ DBUG_RETURN(0);
+err:
+ rw_unlock(&LOCK_grant);
+ if (!no_errors)
+ {
+ char buff[1024];
+ const char *command="";
+ if (table)
+ strxmov(buff, table->db, ".", table->table_name, NullS);
+ if (want_access & EXECUTE_ACL)
+ command= "execute";
+ else if (want_access & ALTER_PROC_ACL)
+ command= "alter procedure";
+ else if (want_access & GRANT_ACL)
+ command= "grant";
+ my_error(ER_PROCACCESS_DENIED_ERROR, MYF(0),
+ command, user, host, table ? buff : "unknown");
+ }
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Check if routine has any of the
+ procedure level grants
+
+ SYNPOSIS
+ bool check_routine_level_acl()
+ thd Thread handler
+ db Database name
+ name Routine name
+
+ RETURN
+ 0 Ok
+ 1 error
+*/
+
+bool check_routine_level_acl(THD *thd, const char *db, const char *name)
+{
+ bool no_routine_acl= 1;
+ if (grant_option)
+ {
+ GRANT_NAME *grant_proc;
+ rw_rdlock(&LOCK_grant);
+ if ((grant_proc= proc_hash_search(thd->priv_host, thd->ip, db,
+ thd->priv_user, name, 0)))
+ no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
+ rw_unlock(&LOCK_grant);
+ }
+ return no_routine_acl;
+}
+
+
/*****************************************************************************
Functions to retrieve the grant for a table/column (for SHOW functions)
*****************************************************************************/
@@ -3000,7 +3646,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
grant_table= NULL;
#else
grant_table= table_hash_search(thd->host, thd->ip, db, user,
- table->real_name, 0);
+ table->table_name, 0);
#endif
table->grant.grant_table=grant_table; // Remember for column test
table->grant.version=grant_version;
@@ -3012,7 +3658,9 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
}
-ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
+ulong get_column_grant(THD *thd, GRANT_INFO *grant,
+ const char *db_name, const char *table_name,
+ const char *field_name)
{
GRANT_TABLE *grant_table;
GRANT_COLUMN *grant_column;
@@ -3020,30 +3668,31 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
rw_rdlock(&LOCK_grant);
/* reload table if someone has modified any grants */
- if (table->grant.version != grant_version)
+ if (grant->version != grant_version)
{
- table->grant.grant_table=
- table_hash_search(thd->host, thd->ip, table->db,
+ grant->grant_table=
+ table_hash_search(thd->host, thd->ip, db_name,
thd->priv_user,
- table->real_name,0); /* purecov: inspected */
- table->grant.version=grant_version; /* purecov: inspected */
+ table_name, 0); /* purecov: inspected */
+ grant->version= grant_version; /* purecov: inspected */
}
- if (!(grant_table=table->grant.grant_table))
- priv=table->grant.privilege;
+ if (!(grant_table= grant->grant_table))
+ priv= grant->privilege;
else
{
- grant_column=column_hash_search(grant_table, field->field_name,
- (uint) strlen(field->field_name));
+ grant_column= column_hash_search(grant_table, field_name,
+ (uint) strlen(field_name));
if (!grant_column)
- priv=table->grant.privilege;
+ priv= grant->privilege;
else
- priv=table->grant.privilege | grant_column->rights;
+ priv= grant->privilege | grant_column->rights;
}
rw_unlock(&LOCK_grant);
return priv;
}
+
/* Help function for mysql_show_grants */
static void add_user_option(String *grant, ulong value, const char *name)
@@ -3061,15 +3710,18 @@ static void add_user_option(String *grant, ulong value, const char *name)
static const char *command_array[]=
{
- "SELECT", "INSERT","UPDATE","DELETE","CREATE", "DROP", "RELOAD","SHUTDOWN",
- "PROCESS","FILE","GRANT","REFERENCES","INDEX", "ALTER", "SHOW DATABASES",
- "SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE",
- "REPLICATION SLAVE", "REPLICATION CLIENT",
+ "SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "RELOAD",
+ "SHUTDOWN", "PROCESS","FILE", "GRANT", "REFERENCES", "INDEX",
+ "ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES",
+ "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT",
+ "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE",
+ "CREATE USER"
};
static uint command_lengths[]=
{
- 6,6,6,6,6,4,6,8,7,4,5,10,5,5,14,5,23,11,7,17,18
+ 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9,
+ 14, 13, 11
};
@@ -3080,7 +3732,7 @@ static uint command_lengths[]=
Send to client grant-like strings depicting user@host privileges
*/
-int mysql_show_grants(THD *thd,LEX_USER *lex_user)
+bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
{
ulong want_access;
uint counter,index;
@@ -3095,7 +3747,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!initialized)
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (!lex_user->host.str)
@@ -3106,8 +3758,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (lex_user->host.length > HOSTNAME_LENGTH ||
lex_user->user.length > USERNAME_LENGTH)
{
- my_error(ER_GRANT_WRONG_HOST_OR_USER,MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
+ MYF(0));
+ DBUG_RETURN(TRUE);
}
for (counter=0 ; counter < acl_users.elements ; counter++)
@@ -3119,14 +3772,14 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!(host=acl_user->host.hostname))
host= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(&my_charset_latin1, lex_user->host.str, host))
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
break;
}
if (counter == acl_users.elements)
{
my_error(ER_NONEXISTING_GRANT, MYF(0),
lex_user->user.str, lex_user->host.str);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
Item_string *field=new Item_string("",0,&my_charset_latin1);
@@ -3136,8 +3789,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
strxmov(buff,"Grants for ",lex_user->user.str,"@",
lex_user->host.str,NullS);
field_list.push_back(field);
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(-1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -3172,7 +3826,8 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(lex_user->user.str, lex_user->user.length,
system_charset_info);
global.append ("'@'",3);
- global.append(lex_user->host.str,lex_user->host.length);
+ global.append(lex_user->host.str,lex_user->host.length,
+ system_charset_info);
global.append ('\'');
if (acl_user->salt_len)
{
@@ -3206,7 +3861,8 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (ssl_options++)
global.append(' ');
global.append("SUBJECT \'",9);
- global.append(acl_user->x509_subject,strlen(acl_user->x509_subject));
+ global.append(acl_user->x509_subject,strlen(acl_user->x509_subject),
+ system_charset_info);
global.append('\'');
}
if (acl_user->ssl_cipher)
@@ -3214,13 +3870,16 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (ssl_options++)
global.append(' ');
global.append("CIPHER '",8);
- global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher));
+ global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher),
+ system_charset_info);
global.append('\'');
}
}
if ((want_access & GRANT_ACL) ||
- (acl_user->user_resource.questions | acl_user->user_resource.updates |
- acl_user->user_resource.connections))
+ (acl_user->user_resource.questions ||
+ acl_user->user_resource.updates ||
+ acl_user->user_resource.conn_per_hour ||
+ acl_user->user_resource.user_conn))
{
global.append(" WITH",5);
if (want_access & GRANT_ACL)
@@ -3229,8 +3888,10 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
"MAX_QUERIES_PER_HOUR");
add_user_option(&global, acl_user->user_resource.updates,
"MAX_UPDATES_PER_HOUR");
- add_user_option(&global, acl_user->user_resource.connections,
+ add_user_option(&global, acl_user->user_resource.conn_per_hour,
"MAX_CONNECTIONS_PER_HOUR");
+ add_user_option(&global, acl_user->user_resource.user_conn,
+ "MAX_USER_CONNECTIONS");
}
protocol->prepare_for_resend();
protocol->store(global.ptr(),global.length(),global.charset());
@@ -3253,7 +3914,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
host= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(&my_charset_latin1, lex_user->host.str, host))
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
want_access=acl_db->access;
if (want_access)
@@ -3287,7 +3948,8 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
db.append(lex_user->user.str, lex_user->user.length,
system_charset_info);
db.append ("'@'",3);
- db.append(lex_user->host.str, lex_user->host.length);
+ db.append(lex_user->host.str, lex_user->host.length,
+ system_charset_info);
db.append ('\'');
if (want_access & GRANT_ACL)
db.append(" WITH GRANT OPTION",18);
@@ -3313,7 +3975,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
user= "";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(&my_charset_latin1, lex_user->host.str,
+ !my_strcasecmp(system_charset_info, lex_user->host.str,
grant_table->host.hostname))
{
ulong table_access= grant_table->privs;
@@ -3393,7 +4055,8 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(lex_user->user.str, lex_user->user.length,
system_charset_info);
global.append("'@'",3);
- global.append(lex_user->host.str,lex_user->host.length);
+ global.append(lex_user->host.str,lex_user->host.length,
+ system_charset_info);
global.append('\'');
if (table_access & GRANT_ACL)
global.append(" WITH GRANT OPTION",18);
@@ -3407,6 +4070,74 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
}
}
+
+ /* Add procedure access */
+ for (index=0 ; index < proc_priv_hash.records ; index++)
+ {
+ const char *user;
+ GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash,
+ index);
+
+ if (!(user=grant_proc->user))
+ user= "";
+
+ if (!strcmp(lex_user->user.str,user) &&
+ !my_strcasecmp(system_charset_info, lex_user->host.str,
+ grant_proc->host.hostname))
+ {
+ ulong proc_access= grant_proc->privs;
+ if (proc_access != 0)
+ {
+ String global(buff, sizeof(buff), system_charset_info);
+ ulong test_access= proc_access & ~GRANT_ACL;
+
+ global.length(0);
+ global.append("GRANT ",6);
+
+ if (!test_access)
+ global.append("USAGE",5);
+ else
+ {
+ /* Add specific procedure access */
+ int found= 0;
+ ulong j;
+
+ for (counter= 0, j= SELECT_ACL; j <= PROC_ACLS; counter++, j<<= 1)
+ {
+ if (test_access & j)
+ {
+ if (found)
+ global.append(", ",2);
+ found= 1;
+ global.append(command_array[counter],command_lengths[counter]);
+ }
+ }
+ }
+ global.append(" ON ",4);
+ append_identifier(thd, &global, grant_proc->db,
+ strlen(grant_proc->db));
+ global.append('.');
+ append_identifier(thd, &global, grant_proc->tname,
+ strlen(grant_proc->tname));
+ global.append(" TO '",5);
+ global.append(lex_user->user.str, lex_user->user.length,
+ system_charset_info);
+ global.append("'@'",3);
+ global.append(lex_user->host.str,lex_user->host.length,
+ system_charset_info);
+ global.append('\'');
+ if (proc_access & GRANT_ACL)
+ global.append(" WITH GRANT OPTION",18);
+ protocol->prepare_for_resend();
+ protocol->store(global.ptr(),global.length(),global.charset());
+ if (protocol->write())
+ {
+ error= -1;
+ break;
+ }
+ }
+ }
+ }
end:
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
@@ -3453,28 +4184,53 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc)
bzero((char*) &uc->user_resources, sizeof(uc->user_resources));
}
+/*
+ Open the grant tables.
+
+ SYNOPSIS
+ open_grant_tables()
+ thd The current thread.
+ tables (out) The 4 elements array for the opened tables.
+
+ DESCRIPTION
+ Tables are numbered as follows:
+ 0 user
+ 1 db
+ 2 tables_priv
+ 3 columns_priv
+
+ RETURN
+ 1 Skip GRANT handling during replication.
+ 0 OK.
+ < 0 Error.
+*/
+
+#define GRANT_TABLES 5
int open_grant_tables(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("open_grant_tables");
if (!initialized)
{
- net_printf(thd,ER_OPTION_PREVENTS_STATEMENT, "--skip-grant-tables");
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
DBUG_RETURN(-1);
}
- bzero((char*) tables, 4*sizeof(*tables));
- tables->alias= tables->real_name= (char*) "user";
- (tables+1)->alias= (tables+1)->real_name= (char*) "db";
- (tables+2)->alias= (tables+2)->real_name= (char*) "tables_priv";
- (tables+3)->alias= (tables+3)->real_name= (char*) "columns_priv";
- tables->next= tables+1;
- (tables+1)->next= tables+2;
- (tables+2)->next= tables+3;
- (tables+3)->next= 0;
+ bzero((char*) tables, GRANT_TABLES*sizeof(*tables));
+ tables->alias= tables->table_name= (char*) "user";
+ (tables+1)->alias= (tables+1)->table_name= (char*) "db";
+ (tables+2)->alias= (tables+2)->table_name= (char*) "tables_priv";
+ (tables+3)->alias= (tables+3)->table_name= (char*) "columns_priv";
+ (tables+4)->alias= (tables+4)->table_name= (char*) "procs_priv";
+ tables->next_local= tables->next_global= tables+1;
+ (tables+1)->next_local= (tables+1)->next_global= tables+2;
+ (tables+2)->next_local= (tables+2)->next_global= tables+3;
+ (tables+3)->next_local= (tables+3)->next_global= tables+4;
tables->lock_type= (tables+1)->lock_type=
- (tables+2)->lock_type= (tables+3)->lock_type= TL_WRITE;
- tables->db= (tables+1)->db= (tables+2)->db= (tables+3)->db=(char*) "mysql";
+ (tables+2)->lock_type= (tables+3)->lock_type=
+ (tables+4)->lock_type= TL_WRITE;
+ tables->db= (tables+1)->db= (tables+2)->db=
+ (tables+3)->db= (tables+4)->db= (char*) "mysql";
#ifdef HAVE_REPLICATION
/*
@@ -3487,10 +4243,12 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
The tables must be marked "updating" so that tables_ok() takes them into
account in tests.
*/
- tables[0].updating=tables[1].updating=tables[2].updating=tables[3].updating=1;
+ tables[0].updating=tables[1].updating=tables[2].updating=
+ tables[3].updating=tables[4].updating=1;
if (!tables_ok(0, tables))
DBUG_RETURN(1);
- tables[0].updating=tables[1].updating=tables[2].updating=tables[3].updating=0;
+ tables[0].updating=tables[1].updating=tables[2].updating=
+ tables[3].updating=tables[4].updating=0;;
}
#endif
@@ -3529,111 +4287,663 @@ ACL_USER *check_acl_user(LEX_USER *user_name,
}
-int mysql_drop_user(THD *thd, List <LEX_USER> &list)
+/*
+ Modify a privilege table.
+
+ SYNOPSIS
+ modify_grant_table()
+ table The table to modify.
+ host_field The host name field.
+ user_field The user name field.
+ user_to The new name for the user if to be renamed,
+ NULL otherwise.
+
+ DESCRIPTION
+ Update user/host in the current record if user_to is not NULL.
+ Delete the current record if user_to is NULL.
+
+ RETURN
+ 0 OK.
+ != 0 Error.
+*/
+
+static int modify_grant_table(TABLE *table, Field *host_field,
+ Field *user_field, LEX_USER *user_to)
{
- uint counter, acl_userd;
- int result;
- ACL_USER *acl_user;
- ACL_DB *acl_db;
- TABLE_LIST tables[4];
+ int error;
+ DBUG_ENTER("modify_grant_table");
- DBUG_ENTER("mysql_drop_user");
+ if (user_to)
+ {
+ /* rename */
+ store_record(table, record[1]);
+ host_field->store(user_to->host.str, user_to->host.length,
+ system_charset_info);
+ user_field->store(user_to->user.str, user_to->user.length,
+ system_charset_info);
+ if ((error= table->file->update_row(table->record[1], table->record[0])))
+ table->file->print_error(error, MYF(0));
+ }
+ else
+ {
+ /* delete */
+ if ((error=table->file->delete_row(table->record[0])))
+ table->file->print_error(error, MYF(0));
+ }
- if ((result= open_grant_tables(thd, tables)))
- DBUG_RETURN(result == 1 ? 0 : 1);
+ DBUG_RETURN(error);
+}
- rw_wrlock(&LOCK_grant);
- VOID(pthread_mutex_lock(&acl_cache->lock));
- LEX_USER *user_name;
- List_iterator <LEX_USER> user_list(list);
- while ((user_name=user_list++))
+/*
+ Handle a privilege table.
+
+ SYNOPSIS
+ handle_grant_table()
+ tables The array with the four open tables.
+ table_no The number of the table to handle (0..4).
+ drop If user_from is to be dropped.
+ user_from The the user to be searched/dropped/renamed.
+ user_to The new name for the user if to be renamed,
+ NULL otherwise.
+
+ DESCRIPTION
+ Scan through all records in a grant table and apply the requested
+ operation. For the "user" table, a single index access is sufficient,
+ since there is an unique index on (host, user).
+ Delete from grant table if drop is true.
+ Update in grant table if drop is false and user_to is not NULL.
+ Search in grant table if drop is false and user_to is NULL.
+ Tables are numbered as follows:
+ 0 user
+ 1 db
+ 2 tables_priv
+ 3 columns_priv
+ 4 procs_priv
+
+ RETURN
+ > 0 At least one record matched.
+ 0 OK, but no record matched.
+ < 0 Error.
+*/
+
+static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
+ LEX_USER *user_from, LEX_USER *user_to)
+{
+ int result= 0;
+ int error;
+ TABLE *table= tables[table_no].table;
+ Field *host_field= table->field[0];
+ Field *user_field= table->field[table_no ? 2 : 1];
+ char *host_str= user_from->host.str;
+ char *user_str= user_from->user.str;
+ const char *host;
+ const char *user;
+ byte user_key[MAX_KEY_LENGTH];
+ uint key_prefix_length;
+ DBUG_ENTER("handle_grant_table");
+
+ if (! table_no) // mysql.user table
{
- if (!(acl_user= check_acl_user(user_name, &counter)))
+ /*
+ The 'user' table has an unique index on (host, user).
+ Thus, we can handle everything with a single index access.
+ The host- and user fields are consecutive in the user table records.
+ So we set host- and user fields of table->record[0] and use the
+ pointer to the host field as key.
+ index_read_idx() will replace table->record[0] (its first argument)
+ by the searched record, if it exists.
+ */
+ DBUG_PRINT("info",("read table: '%s' search: '%s'@'%s'",
+ table->s->table_name, user_str, host_str));
+ host_field->store(host_str, user_from->host.length, system_charset_info);
+ user_field->store(user_str, user_from->user.length, system_charset_info);
+
+ key_prefix_length= (table->key_info->key_part[0].store_length +
+ table->key_info->key_part[1].store_length);
+ key_copy(user_key, table->record[0], table->key_info, key_prefix_length);
+
+ if ((error= table->file->index_read_idx(table->record[0], 0,
+ user_key, key_prefix_length,
+ HA_READ_KEY_EXACT)))
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; No such user",
- user_name->user.str,
- user_name->host.str);
- result= -1;
- continue;
+ if (error != HA_ERR_KEY_NOT_FOUND)
+ {
+ table->file->print_error(error, MYF(0));
+ result= -1;
+ }
}
- if ((acl_user->access & ~0))
+ else
+ {
+ /* If requested, delete or update the record. */
+ result= ((drop || user_to) &&
+ modify_grant_table(table, host_field, user_field, user_to)) ?
+ -1 : 1; /* Error or found. */
+ }
+ DBUG_PRINT("info",("read result: %d", result));
+ }
+ else
+ {
+ /*
+ The non-'user' table do not have indexes on (host, user).
+ And their host- and user fields are not consecutive.
+ Thus, we need to do a table scan to find all matching records.
+ */
+ if ((error= table->file->ha_rnd_init(1)))
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Global privileges exists",
- user_name->user.str,
- user_name->host.str);
+ table->file->print_error(error, MYF(0));
result= -1;
- continue;
}
- acl_userd= counter;
-
- for (counter= 0 ; counter < acl_dbs.elements ; counter++)
+ else
{
- const char *user,*host;
- acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
- if (!(user= acl_db->user))
- user= "";
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("info",("scan table: '%s' search: '%s'@'%s'",
+ table->s->table_name, user_str, host_str));
+#endif
+ while ((error= table->file->rnd_next(table->record[0])) !=
+ HA_ERR_END_OF_FILE)
+ {
+ if (error)
+ {
+ /* Most probable 'deleted record'. */
+ DBUG_PRINT("info",("scan error: %d", error));
+ continue;
+ }
+ if (! (host= get_field(&mem, host_field)))
+ host= "";
+ if (! (user= get_field(&mem, user_field)))
+ user= "";
+
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'",
+ user, host,
+ get_field(&mem, table->field[1]) /*db*/,
+ get_field(&mem, table->field[3]) /*table*/,
+ get_field(&mem, table->field[4]) /*column*/));
+#endif
+ if (strcmp(user_str, user) ||
+ my_strcasecmp(system_charset_info, host_str, host))
+ continue;
+
+ /* If requested, delete or update the record. */
+ result= ((drop || user_to) &&
+ modify_grant_table(table, host_field, user_field, user_to)) ?
+ -1 : result ? result : 1; /* Error or keep result or found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ break ;
+ }
+ (void) table->file->ha_rnd_end();
+ DBUG_PRINT("info",("scan result: %d", result));
+ }
+ }
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Handle an in-memory privilege structure.
+
+ SYNOPSIS
+ handle_grant_struct()
+ struct_no The number of the structure to handle (0..3).
+ drop If user_from is to be dropped.
+ user_from The the user to be searched/dropped/renamed.
+ user_to The new name for the user if to be renamed,
+ NULL otherwise.
+
+ DESCRIPTION
+ Scan through all elements in an in-memory grant structure and apply
+ the requested operation.
+ Delete from grant structure if drop is true.
+ Update in grant structure if drop is false and user_to is not NULL.
+ Search in grant structure if drop is false and user_to is NULL.
+ Structures are numbered as follows:
+ 0 acl_users
+ 1 acl_dbs
+ 2 column_priv_hash
+ 3 procs_priv_hash
+
+ RETURN
+ > 0 At least one element matched.
+ 0 OK, but no element matched.
+ -1 Wrong arguments to function
+*/
+
+static int handle_grant_struct(uint struct_no, bool drop,
+ LEX_USER *user_from, LEX_USER *user_to)
+{
+ int result= 0;
+ uint idx;
+ uint elements;
+ const char *user;
+ const char *host;
+ ACL_USER *acl_user;
+ ACL_DB *acl_db;
+ GRANT_NAME *grant_name;
+ DBUG_ENTER("handle_grant_struct");
+ LINT_INIT(acl_user);
+ LINT_INIT(acl_db);
+ LINT_INIT(grant_name);
+ DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
+ struct_no, user_from->user.str, user_from->host.str));
+
+ /* Get the number of elements in the in-memory structure. */
+ switch (struct_no) {
+ case 0:
+ elements= acl_users.elements;
+ break;
+ case 1:
+ elements= acl_dbs.elements;
+ break;
+ case 2:
+ elements= column_priv_hash.records;
+ break;
+ case 3:
+ elements= proc_priv_hash.records;
+ break;
+ default:
+ return -1;
+ }
+
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("scan struct: %u search user: '%s' host: '%s'",
+ struct_no, user_from->user.str, user_from->host.str));
+#endif
+ /* Loop over all elements. */
+ for (idx= 0; idx < elements; idx++)
+ {
+ /*
+ Get a pointer to the element.
+ Unfortunaltely, the host default differs for the structures.
+ */
+ switch (struct_no) {
+ case 0:
+ acl_user= dynamic_element(&acl_users, idx, ACL_USER*);
+ user= acl_user->user;
+ if (!(host= acl_user->host.hostname))
+ host= "%";
+ break;
+
+ case 1:
+ acl_db= dynamic_element(&acl_dbs, idx, ACL_DB*);
+ user= acl_db->user;
if (!(host= acl_db->host.hostname))
- host= "";
+ host= "%";
+ break;
+
+ case 2:
+ grant_name= (GRANT_NAME*) hash_element(&column_priv_hash, idx);
+ user= grant_name->user;
+ if (!(host= grant_name->host.hostname))
+ host= "%";
+ break;
- if (!strcmp(user_name->user.str,user) &&
- !my_strcasecmp(system_charset_info, user_name->host.str, host))
+ case 3:
+ grant_name= (GRANT_NAME*) hash_element(&proc_priv_hash, idx);
+ user= grant_name->user;
+ if (!(host= grant_name->host.hostname))
+ host= "%";
+ break;
+ }
+ if (! user)
+ user= "";
+ if (! host)
+ host= "";
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
+ struct_no, idx, user, host));
+#endif
+ if (strcmp(user_from->user.str, user) ||
+ my_strcasecmp(system_charset_info, user_from->host.str, host))
+ continue;
+
+ result= 1; /* At least one element found. */
+ if ( drop )
+ {
+ switch ( struct_no )
+ {
+ case 0:
+ delete_dynamic_element(&acl_users, idx);
+ break;
+
+ case 1:
+ delete_dynamic_element(&acl_dbs, idx);
+ break;
+
+ case 2:
+ hash_delete(&column_priv_hash, (byte*) grant_name);
+ break;
+
+ case 3:
+ hash_delete(&proc_priv_hash, (byte*) grant_name);
break;
+ }
+ elements--;
+ idx--;
}
- if (counter != acl_dbs.elements)
+ else if ( user_to )
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Database privileges exists",
- user_name->user.str,
- user_name->host.str);
- result= -1;
- continue;
+ switch ( struct_no ) {
+ case 0:
+ acl_user->user= strdup_root(&mem, user_to->user.str);
+ acl_user->host.hostname= strdup_root(&mem, user_to->host.str);
+ break;
+
+ case 1:
+ acl_db->user= strdup_root(&mem, user_to->user.str);
+ acl_db->host.hostname= strdup_root(&mem, user_to->host.str);
+ break;
+
+ case 2:
+ case 3:
+ grant_name->user= strdup_root(&mem, user_to->user.str);
+ update_hostname(&grant_name->host,
+ strdup_root(&mem, user_to->host.str));
+ break;
+ }
}
+ else
+ {
+ /* If search is requested, we do not need to search further. */
+ break;
+ }
+ }
+#ifdef EXTRA_DEBUG
+ DBUG_PRINT("loop",("scan struct: %u result %d", struct_no, result));
+#endif
- for (counter= 0 ; counter < column_priv_hash.records ; counter++)
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Handle all privilege tables and in-memory privilege structures.
+
+ SYNOPSIS
+ handle_grant_data()
+ tables The array with the four open tables.
+ drop If user_from is to be dropped.
+ user_from The the user to be searched/dropped/renamed.
+ user_to The new name for the user if to be renamed,
+ NULL otherwise.
+
+ DESCRIPTION
+ Go through all grant tables and in-memory grant structures and apply
+ the requested operation.
+ Delete from grant data if drop is true.
+ Update in grant data if drop is false and user_to is not NULL.
+ Search in grant data if drop is false and user_to is NULL.
+
+ RETURN
+ > 0 At least one element matched.
+ 0 OK, but no element matched.
+ < 0 Error.
+*/
+
+static int handle_grant_data(TABLE_LIST *tables, bool drop,
+ LEX_USER *user_from, LEX_USER *user_to)
+{
+ int result= 0;
+ int found;
+ DBUG_ENTER("handle_grant_data");
+
+ /* Handle user table. */
+ if ((found= handle_grant_table(tables, 0, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch the in-memory array. */
+ result= -1;
+ }
+ else
+ {
+ /* Handle user array. */
+ if ((handle_grant_struct(0, drop, user_from, user_to) && ! result) ||
+ found)
{
- const char *user,*host;
- GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
- counter);
- if (!(user=grant_table->user))
- user= "";
- if (!(host=grant_table->host.hostname))
- host= "";
+ result= 1; /* At least one record/element found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ goto end;
+ }
+ }
- if (!strcmp(user_name->user.str,user) &&
- !my_strcasecmp(system_charset_info, user_name->host.str, host))
- break;
+ /* Handle db table. */
+ if ((found= handle_grant_table(tables, 1, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch the in-memory array. */
+ result= -1;
+ }
+ else
+ {
+ /* Handle db array. */
+ if (((handle_grant_struct(1, drop, user_from, user_to) && ! result) ||
+ found) && ! result)
+ {
+ result= 1; /* At least one record/element found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ goto end;
}
- if (counter != column_priv_hash.records)
+ }
+
+ /* Handle procedures table. */
+ if ((found= handle_grant_table(tables, 4, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch in-memory array. */
+ result= -1;
+ }
+ else
+ {
+ /* Handle procs array. */
+ if (((handle_grant_struct(3, drop, user_from, user_to) && ! result) ||
+ found) && ! result)
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Table privileges exists",
- user_name->user.str,
- user_name->host.str);
+ result= 1; /* At least one record/element found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ goto end;
+ }
+ }
+
+ /* Handle tables table. */
+ if ((found= handle_grant_table(tables, 2, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch columns and in-memory array. */
+ result= -1;
+ }
+ else
+ {
+ if (found && ! result)
+ {
+ result= 1; /* At least one record found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ goto end;
+ }
+
+ /* Handle columns table. */
+ if ((found= handle_grant_table(tables, 3, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch the in-memory array. */
result= -1;
+ }
+ else
+ {
+ /* Handle columns hash. */
+ if (((handle_grant_struct(2, drop, user_from, user_to) && ! result) ||
+ found) && ! result)
+ result= 1; /* At least one record/element found. */
+ }
+ }
+ end:
+ DBUG_RETURN(result);
+}
+
+
+static void append_user(String *str, LEX_USER *user)
+{
+ if (str->length())
+ str->append(',');
+ str->append('\'');
+ str->append(user->user.str);
+ str->append("'@'");
+ str->append(user->host.str);
+ str->append('\'');
+}
+
+
+/*
+ Create a list of users.
+
+ SYNOPSIS
+ mysql_create_user()
+ thd The current thread.
+ list The users to create.
+
+ RETURN
+ FALSE OK.
+ TRUE Error.
+*/
+
+bool mysql_create_user(THD *thd, List <LEX_USER> &list)
+{
+ int result;
+ String wrong_users;
+ ulong sql_mode;
+ LEX_USER *user_name;
+ List_iterator <LEX_USER> user_list(list);
+ TABLE_LIST tables[GRANT_TABLES];
+ DBUG_ENTER("mysql_create_user");
+
+ /* CREATE USER may be skipped on replication client. */
+ if ((result= open_grant_tables(thd, tables)))
+ DBUG_RETURN(result != 1);
+
+ rw_wrlock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ while ((user_name= user_list++))
+ {
+ /*
+ Search all in-memory structures and grant tables
+ for a mention of the new user name.
+ */
+ if (handle_grant_data(tables, 0, user_name, NULL))
+ {
+ append_user(&wrong_users, user_name);
+ result= TRUE;
continue;
}
- tables[0].table->field[0]->store(user_name->host.str,(uint)
- user_name->host.length,
- system_charset_info);
- tables[0].table->field[1]->store(user_name->user.str,(uint)
- user_name->user.length,
- system_charset_info);
- tables[0].table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (!tables[0].table->file->index_read_idx(tables[0].table->record[0],0,
- (byte*) tables[0].table->
- field[0]->ptr,
- tables[0].table->
- key_info[0].key_length,
- HA_READ_KEY_EXACT))
- {
- int error;
- if ((error = tables[0].table->file->delete_row(tables[0].table->
- record[0])))
- {
- tables[0].table->file->print_error(error, MYF(0));
- DBUG_RETURN(-1);
- }
- delete_dynamic_element(&acl_users, acl_userd);
+ sql_mode= thd->variables.sql_mode;
+ if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0))
+ {
+ append_user(&wrong_users, user_name);
+ result= TRUE;
+ }
+ }
+
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ rw_unlock(&LOCK_grant);
+ close_thread_tables(thd);
+ if (result)
+ my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Drop a list of users and all their privileges.
+
+ SYNOPSIS
+ mysql_drop_user()
+ thd The current thread.
+ list The users to drop.
+
+ RETURN
+ FALSE OK.
+ TRUE Error.
+*/
+
+bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
+{
+ int result;
+ String wrong_users;
+ LEX_USER *user_name;
+ List_iterator <LEX_USER> user_list(list);
+ TABLE_LIST tables[GRANT_TABLES];
+ DBUG_ENTER("mysql_drop_user");
+
+ /* DROP USER may be skipped on replication client. */
+ if ((result= open_grant_tables(thd, tables)))
+ DBUG_RETURN(result != 1);
+
+ rw_wrlock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ while ((user_name= user_list++))
+ {
+ if (handle_grant_data(tables, 1, user_name, NULL) <= 0)
+ {
+ append_user(&wrong_users, user_name);
+ result= TRUE;
+ }
+ }
+
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ rw_unlock(&LOCK_grant);
+ close_thread_tables(thd);
+ if (result)
+ my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe());
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Rename a user.
+
+ SYNOPSIS
+ mysql_rename_user()
+ thd The current thread.
+ list The user name pairs: (from, to).
+
+ RETURN
+ FALSE OK.
+ TRUE Error.
+*/
+
+bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
+{
+ int result= 0;
+ String wrong_users;
+ LEX_USER *user_from;
+ LEX_USER *user_to;
+ List_iterator <LEX_USER> user_list(list);
+ TABLE_LIST tables[GRANT_TABLES];
+ DBUG_ENTER("mysql_rename_user");
+
+ /* RENAME USER may be skipped on replication client. */
+ if ((result= open_grant_tables(thd, tables)))
+ DBUG_RETURN(result != 1);
+
+ rw_wrlock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ while ((user_from= user_list++))
+ {
+ user_to= user_list++;
+ DBUG_ASSERT(user_to != 0); /* Syntax enforces pairs of users. */
+
+ /*
+ Search all in-memory structures and grant tables
+ for a mention of the new user name.
+ */
+ if (handle_grant_data(tables, 0, user_to, NULL) ||
+ handle_grant_data(tables, 0, user_from, user_to) <= 0)
+ {
+ append_user(&wrong_users, user_from);
+ result= TRUE;
}
}
@@ -3641,20 +4951,35 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list)
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
if (result)
- my_error(ER_DROP_USER, MYF(0));
+ my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe());
DBUG_RETURN(result);
}
-int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
+
+/*
+ Revoke all privileges from a list of users.
+
+ SYNOPSIS
+ mysql_revoke_all()
+ thd The current thread.
+ list The users to revoke all privileges from.
+
+ RETURN
+ > 0 Error. Error message already sent.
+ 0 OK.
+ < 0 Error. Error message not yet sent.
+*/
+
+bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
{
uint counter, revoked;
int result;
ACL_DB *acl_db;
- TABLE_LIST tables[4];
+ TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_revoke_all");
if ((result= open_grant_tables(thd, tables)))
- DBUG_RETURN(result == 1 ? 0 : 1);
+ DBUG_RETURN(result != 1);
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -3665,15 +4990,14 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
{
if (!check_acl_user(lex_user, &counter))
{
- sql_print_error("REVOKE ALL PRIVILEGES, GRANT: User '%s'@'%s' not exists",
- lex_user->user.str,
- lex_user->host.str);
+ sql_print_error("REVOKE ALL PRIVILEGES, GRANT: User '%s'@'%s' does not "
+ "exists", lex_user->user.str, lex_user->host.str);
result= -1;
continue;
}
if (replace_user_table(thd, tables[0].table,
- *lex_user, ~0, 1, 0))
+ *lex_user, ~0, 1, 0, 0))
{
result= -1;
continue;
@@ -3690,13 +5014,13 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
for (counter= 0, revoked= 0 ; counter < acl_dbs.elements ; )
{
const char *user,*host;
-
+
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
if (!(user=acl_db->user))
user= "";
if (!(host=acl_db->host.hostname))
host= "";
-
+
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
@@ -3727,7 +5051,7 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
user= "";
if (!(host=grant_table->host.hostname))
host= "";
-
+
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
@@ -3761,15 +5085,167 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
counter++;
}
} while (revoked);
+
+ /* Remove procedure access */
+ do {
+ for (counter= 0, revoked= 0 ; counter < proc_priv_hash.records ; )
+ {
+ const char *user,*host;
+ GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash,
+ counter);
+ if (!(user=grant_proc->user))
+ user= "";
+ if (!(host=grant_proc->host.hostname))
+ host= "";
+
+ if (!strcmp(lex_user->user.str,user) &&
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+ {
+ if (!replace_proc_table(thd,grant_proc,tables[4].table,*lex_user,
+ grant_proc->db,
+ grant_proc->tname,
+ ~0, 1))
+ {
+ revoked= 1;
+ continue;
+ }
+ result= -1; // Something went wrong
+ }
+ counter++;
+ }
+ } while (revoked);
}
-
+
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
-
+
+ if (result)
+ my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0));
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Revoke privileges for all users on a stored procedure
+
+ SYNOPSIS
+ sp_revoke_privileges()
+ thd The current thread.
+ db DB of the stored procedure
+ name Name of the stored procedure
+
+ RETURN
+ 0 OK.
+ < 0 Error. Error message not yet sent.
+*/
+
+bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name)
+{
+ uint counter, revoked;
+ int result;
+ TABLE_LIST tables[GRANT_TABLES];
+ DBUG_ENTER("sp_revoke_privileges");
+
+ if ((result= open_grant_tables(thd, tables)))
+ DBUG_RETURN(result != 1);
+
+ rw_wrlock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ /* Remove procedure access */
+ do
+ {
+ for (counter= 0, revoked= 0 ; counter < proc_priv_hash.records ; )
+ {
+ GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash,
+ counter);
+ if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) &&
+ !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
+ {
+ LEX_USER lex_user;
+ lex_user.user.str= grant_proc->user;
+ lex_user.user.length= strlen(grant_proc->user);
+ lex_user.host.str= grant_proc->host.hostname;
+ lex_user.host.length= strlen(grant_proc->host.hostname);
+ if (!replace_proc_table(thd,grant_proc,tables[4].table,lex_user,
+ grant_proc->db, grant_proc->tname, ~0, 1))
+ {
+ revoked= 1;
+ continue;
+ }
+ result= -1; // Something went wrong
+ }
+ counter++;
+ }
+ } while (revoked);
+
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ rw_unlock(&LOCK_grant);
+ close_thread_tables(thd);
+
if (result)
- my_error(ER_REVOKE_GRANTS, MYF(0));
+ my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0));
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Grant EXECUTE,ALTER privilege for a stored procedure
+
+ SYNOPSIS
+ sp_grant_privileges()
+ thd The current thread.
+ db DB of the stored procedure
+ name Name of the stored procedure
+
+ RETURN
+ 0 OK.
+ < 0 Error. Error message not yet sent.
+*/
+
+bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name)
+{
+ LEX_USER *combo;
+ TABLE_LIST tables[1];
+ List<LEX_USER> user_list;
+ bool result;
+ DBUG_ENTER("sp_grant_privileges");
+
+ if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
+ DBUG_RETURN(TRUE);
+
+ combo->user.str= thd->user;
+
+ if (!find_acl_user(combo->host.str=(char*)thd->host_or_ip, combo->user.str) &&
+ !find_acl_user(combo->host.str=(char*)thd->host, combo->user.str) &&
+ !find_acl_user(combo->host.str=(char*)thd->ip, combo->user.str) &&
+ !find_acl_user(combo->host.str=(char*)"%", combo->user.str))
+ DBUG_RETURN(TRUE);
+
+ bzero((char*)tables, sizeof(TABLE_LIST));
+ user_list.empty();
+
+ tables->db= (char*)sp_db;
+ tables->table_name= tables->alias= (char*)sp_name;
+ combo->host.length= strlen(combo->host.str);
+ combo->user.length= strlen(combo->user.str);
+ combo->host.str= thd->strmake(combo->host.str,combo->host.length);
+ combo->user.str= thd->strmake(combo->user.str,combo->user.length);
+ combo->password.str= (char*)"";
+ combo->password.length= 0;
+
+ if (user_list.push_back(combo))
+ DBUG_RETURN(TRUE);
+
+ thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
+ bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh));
+
+ result= mysql_procedure_grant(thd, tables, user_list,
+ DEFAULT_CREATE_PROC_ACLS, 0, 1);
DBUG_RETURN(result);
}
@@ -3831,3 +5307,295 @@ int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
DBUG_RETURN (*str != '\0');
}
+
+void update_schema_privilege(TABLE *table, char *buff, const char* db,
+ const char* t_name, const char* column,
+ uint col_length, const char *priv,
+ uint priv_length, const char* is_grantable)
+{
+ int i= 2;
+ CHARSET_INFO *cs= system_charset_info;
+ restore_record(table, s->default_values);
+ table->field[0]->store(buff, strlen(buff), cs);
+ if (db)
+ table->field[i++]->store(db, strlen(db), cs);
+ if (t_name)
+ table->field[i++]->store(t_name, strlen(t_name), cs);
+ if (column)
+ table->field[i++]->store(column, col_length, cs);
+ table->field[i++]->store(priv, priv_length, cs);
+ table->field[i]->store(is_grantable, strlen(is_grantable), cs);
+ table->file->write_row(table->record[0]);
+}
+
+
+int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ uint counter;
+ ACL_USER *acl_user;
+ ulong want_access;
+
+ char buff[100];
+ TABLE *table= tables->table;
+ DBUG_ENTER("fill_schema_user_privileges");
+ for (counter=0 ; counter < acl_users.elements ; counter++)
+ {
+ const char *user,*host, *is_grantable="YES";
+ acl_user=dynamic_element(&acl_users,counter,ACL_USER*);
+ if (!(user=acl_user->user))
+ user= "";
+ if (!(host=acl_user->host.hostname))
+ host= "";
+ want_access= acl_user->access;
+ if (!(want_access & GRANT_ACL))
+ is_grantable= "NO";
+
+ strxmov(buff,"'",user,"'@'",host,"'",NullS);
+ if (!(want_access & ~GRANT_ACL))
+ update_schema_privilege(table, buff, 0, 0, 0, 0, "USAGE", 5, is_grantable);
+ else
+ {
+ uint priv_id;
+ ulong j,test_access= want_access & ~GRANT_ACL;
+ for (priv_id=0, j = SELECT_ACL;j <= GLOBAL_ACLS; priv_id++,j <<= 1)
+ {
+ if (test_access & j)
+ update_schema_privilege(table, buff, 0, 0, 0, 0,
+ command_array[priv_id],
+ command_lengths[priv_id], is_grantable);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+#else
+ return(0);
+#endif
+}
+
+
+int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ uint counter;
+ ACL_DB *acl_db;
+ ulong want_access;
+ char buff[100];
+ TABLE *table= tables->table;
+ DBUG_ENTER("fill_schema_schema_privileges");
+
+ for (counter=0 ; counter < acl_dbs.elements ; counter++)
+ {
+ const char *user, *host, *is_grantable="YES";
+
+ acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
+ if (!(user=acl_db->user))
+ user= "";
+ if (!(host=acl_db->host.hostname))
+ host= "";
+
+ want_access=acl_db->access;
+ if (want_access)
+ {
+ if (!(want_access & GRANT_ACL))
+ {
+ is_grantable= "NO";
+ }
+ strxmov(buff,"'",user,"'@'",host,"'",NullS);
+ if (!(want_access & ~GRANT_ACL))
+ update_schema_privilege(table, buff, acl_db->db, 0, 0,
+ 0, "USAGE", 5, is_grantable);
+ else
+ {
+ int cnt;
+ ulong j,test_access= want_access & ~GRANT_ACL;
+ for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
+ if (test_access & j)
+ update_schema_privilege(table, buff, acl_db->db, 0, 0, 0,
+ command_array[cnt], command_lengths[cnt],
+ is_grantable);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+#else
+ return (0);
+#endif
+}
+
+
+int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ uint index;
+ char buff[100];
+ TABLE *table= tables->table;
+ DBUG_ENTER("fill_schema_table_privileges");
+
+ for (index=0 ; index < column_priv_hash.records ; index++)
+ {
+ const char *user, *is_grantable= "YES";
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
+ index);
+ if (!(user=grant_table->user))
+ user= "";
+ ulong table_access= grant_table->privs;
+ if (table_access)
+ {
+ ulong test_access= table_access & ~GRANT_ACL;
+ /*
+ We should skip 'usage' privilege on table if
+ we have any privileges on column(s) of this table
+ */
+ if (!test_access && grant_table->cols)
+ continue;
+ if (!(table_access & GRANT_ACL))
+ is_grantable= "NO";
+
+ strxmov(buff,"'",user,"'@'",grant_table->host.hostname,"'",NullS);
+ if (!test_access)
+ update_schema_privilege(table, buff, grant_table->db, grant_table->tname,
+ 0, 0, "USAGE", 5, is_grantable);
+ else
+ {
+ ulong j;
+ int cnt;
+ for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1)
+ {
+ if (test_access & j)
+ update_schema_privilege(table, buff, grant_table->db,
+ grant_table->tname, 0, 0, command_array[cnt],
+ command_lengths[cnt], is_grantable);
+ }
+ }
+ }
+ }
+ DBUG_RETURN(0);
+#else
+ return (0);
+#endif
+}
+
+
+int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ uint index;
+ char buff[100];
+ TABLE *table= tables->table;
+ DBUG_ENTER("fill_schema_table_privileges");
+
+ for (index=0 ; index < column_priv_hash.records ; index++)
+ {
+ const char *user, *is_grantable= "YES";
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
+ index);
+ if (!(user=grant_table->user))
+ user= "";
+ ulong table_access= grant_table->cols;
+ if (table_access != 0)
+ {
+ if (!(grant_table->privs & GRANT_ACL))
+ is_grantable= "NO";
+
+ ulong test_access= table_access & ~GRANT_ACL;
+ strxmov(buff,"'",user,"'@'",grant_table->host.hostname,"'",NullS);
+ if (!test_access)
+ continue;
+ else
+ {
+ ulong j;
+ int cnt;
+ for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1)
+ {
+ if (test_access & j)
+ {
+ for (uint col_index=0 ;
+ col_index < grant_table->hash_columns.records ;
+ col_index++)
+ {
+ GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
+ hash_element(&grant_table->hash_columns,col_index);
+ if ((grant_column->rights & j) && (table_access & j))
+ update_schema_privilege(table, buff, grant_table->db,
+ grant_table->tname,
+ grant_column->column,
+ grant_column->key_length,
+ command_array[cnt],
+ command_lengths[cnt], is_grantable);
+ }
+ }
+ }
+ }
+ }
+ }
+ DBUG_RETURN(0);
+#else
+ return (0);
+#endif
+}
+
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+/*
+ fill effective privileges for table
+
+ SYNOPSIS
+ fill_effective_table_privileges()
+ thd thread handler
+ grant grants table descriptor
+ db db name
+ table table name
+*/
+
+void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
+ const char *db, const char *table)
+{
+ /* --skip-grants */
+ if (!initialized)
+ {
+ grant->privilege= ~NO_ACCESS; // everything is allowed
+ return;
+ }
+
+ /* global privileges */
+ grant->privilege= thd->master_access;
+
+ if (!thd->priv_user)
+ return; // it is slave
+
+ /* db privileges */
+ grant->privilege|= acl_get(thd->host, thd->ip, thd->priv_user, db, 0);
+
+ if (!grant_option)
+ return;
+
+ /* table privileges */
+ if (grant->version != grant_version)
+ {
+ rw_rdlock(&LOCK_grant);
+ grant->grant_table=
+ table_hash_search(thd->host, thd->ip, db,
+ thd->priv_user,
+ table, 0); /* purecov: inspected */
+ grant->version= grant_version; /* purecov: inspected */
+ rw_unlock(&LOCK_grant);
+ }
+ if (grant->grant_table != 0)
+ {
+ grant->privilege|= grant->grant_table->privs;
+ }
+}
+
+#else /* NO_EMBEDDED_ACCESS_CHECKS */
+
+/****************************************************************************
+ Dummy wrappers when we don't have any access checks
+****************************************************************************/
+
+bool check_routine_level_acl(THD *thd, const char *db, const char *name)
+{
+ return FALSE;
+}
+
+#endif
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index dc1b04c063a..18eb123d402 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -35,54 +35,87 @@
#define EXECUTE_ACL (1L << 18)
#define REPL_SLAVE_ACL (1L << 19)
#define REPL_CLIENT_ACL (1L << 20)
-
+#define CREATE_VIEW_ACL (1L << 21)
+#define SHOW_VIEW_ACL (1L << 22)
+#define CREATE_PROC_ACL (1L << 23)
+#define ALTER_PROC_ACL (1L << 24)
+#define CREATE_USER_ACL (1L << 25)
/*
don't forget to update
- static struct show_privileges_st sys_privileges[]
- in sql_show.cc when adding new privileges!
+ 1. static struct show_privileges_st sys_privileges[]
+ 2. static const char *command_array[] and static uint command_lengths[]
+ 3. mysql_create_system_tables.sh, mysql_fix_privilege_tables.sql
+ 4. acl_init() or whatever - to define behaviour for old privilege tables
+ 5. sql_yacc.yy - for GRANT/REVOKE to work
*/
-
+#define EXTRA_ACL (1L << 29)
+#define NO_ACCESS (1L << 30)
#define DB_ACLS \
(UPDATE_ACL | SELECT_ACL | INSERT_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
- GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL | LOCK_TABLES_ACL)
+ GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL | \
+ LOCK_TABLES_ACL | EXECUTE_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | \
+ CREATE_PROC_ACL | ALTER_PROC_ACL)
#define TABLE_ACLS \
(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
- GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL)
+ GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_VIEW_ACL | \
+ SHOW_VIEW_ACL)
#define COL_ACLS \
(SELECT_ACL | INSERT_ACL | UPDATE_ACL | REFERENCES_ACL)
+#define PROC_ACLS \
+(ALTER_PROC_ACL | EXECUTE_ACL | GRANT_ACL)
+
+#define SHOW_PROC_ACLS \
+(ALTER_PROC_ACL | EXECUTE_ACL | CREATE_PROC_ACL)
+
#define GLOBAL_ACLS \
(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
RELOAD_ACL | SHUTDOWN_ACL | PROCESS_ACL | FILE_ACL | GRANT_ACL | \
REFERENCES_ACL | INDEX_ACL | ALTER_ACL | SHOW_DB_ACL | SUPER_ACL | \
CREATE_TMP_ACL | LOCK_TABLES_ACL | REPL_SLAVE_ACL | REPL_CLIENT_ACL | \
- EXECUTE_ACL)
+ EXECUTE_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | CREATE_PROC_ACL | \
+ ALTER_PROC_ACL | CREATE_USER_ACL)
-#define EXTRA_ACL (1L << 29)
-#define NO_ACCESS (1L << 30)
+#define DEFAULT_CREATE_PROC_ACLS \
+(ALTER_PROC_ACL | EXECUTE_ACL)
/*
Defines to change the above bits to how things are stored in tables
This is needed as the 'host' and 'db' table is missing a few privileges
*/
-/* Continius bit-segments that needs to be shifted */
-#define DB_REL1 (RELOAD_ACL | SHUTDOWN_ACL | PROCESS_ACL | FILE_ACL)
-#define DB_REL2 (GRANT_ACL | REFERENCES_ACL)
-
/* Privileges that needs to be reallocated (in continous chunks) */
+#define DB_CHUNK0 (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | \
+ CREATE_ACL | DROP_ACL)
#define DB_CHUNK1 (GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL)
#define DB_CHUNK2 (CREATE_TMP_ACL | LOCK_TABLES_ACL)
-
-#define fix_rights_for_db(A) (((A) & 63) | (((A) & DB_REL1) << 4) | (((A) & DB_REL2) << 6))
-#define get_rights_for_db(A) (((A) & 63) | (((A) & DB_CHUNK1) >> 4) | (((A) & DB_CHUNK2) >> 6))
+#define DB_CHUNK3 (CREATE_VIEW_ACL | SHOW_VIEW_ACL | \
+ CREATE_PROC_ACL | ALTER_PROC_ACL )
+#define DB_CHUNK4 (EXECUTE_ACL)
+
+#define fix_rights_for_db(A) (((A) & DB_CHUNK0) | \
+ (((A) << 4) & DB_CHUNK1) | \
+ (((A) << 6) & DB_CHUNK2) | \
+ (((A) << 9) & DB_CHUNK3) | \
+ (((A) << 2) & DB_CHUNK4))
+#define get_rights_for_db(A) (((A) & DB_CHUNK0) | \
+ (((A) & DB_CHUNK1) >> 4) | \
+ (((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 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) | \
+ (((A) << 23) & ALTER_PROC_ACL) | \
+ (((A) << 8) & GRANT_ACL))
+#define get_rights_for_procedure(A) ((((A) & EXECUTE_ACL) >> 18) | \
+ (((A) & ALTER_PROC_ACL) >> 23) | \
+ (((A) & GRANT_ACL) >> 8))
/* Classes */
@@ -141,32 +174,51 @@ ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern);
int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
uint passwd_len);
+int acl_getroot_no_password(THD *thd);
bool acl_check_host(const char *host, const char *ip);
bool check_change_password(THD *thd, const char *host, const char *user,
char *password, uint password_len);
bool change_password(THD *thd, const char *host, const char *user,
char *password);
-int mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
- ulong rights, bool revoke);
-int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
- List <LEX_COLUMN> &column_list, ulong rights,
- bool revoke);
+bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
+ ulong rights, bool revoke);
+bool mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
+ List <LEX_COLUMN> &column_list, ulong rights,
+ bool revoke);
+bool mysql_procedure_grant(THD *thd, TABLE_LIST *table,
+ List <LEX_USER> &user_list, ulong rights,
+ bool revoke, bool no_error);
+ACL_USER *check_acl_user(LEX_USER *user_name, uint *acl_acl_userdx);
my_bool grant_init(THD *thd);
void grant_free(void);
void grant_reload(THD *thd);
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
uint show_command, uint number, bool dont_print_error);
-bool check_grant_column (THD *thd,TABLE *table, const char *name, uint length,
- uint show_command=0);
-bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table);
+bool check_grant_column (THD *thd, GRANT_INFO *grant,
+ const char *db_name, const char *table_name,
+ const char *name, uint length, uint show_command=0);
+bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
+ const char* db_name, const char *table_name,
+ Field_iterator *fields);
+bool check_grant_procedure(THD *thd, ulong want_access,
+ TABLE_LIST *procs, bool no_error);
bool check_grant_db(THD *thd,const char *db);
ulong get_table_grant(THD *thd, TABLE_LIST *table);
-ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field);
-int mysql_show_grants(THD *thd, LEX_USER *user);
+ulong get_column_grant(THD *thd, GRANT_INFO *grant,
+ const char *db_name, const char *table_name,
+ const char *field_name);
+bool mysql_show_grants(THD *thd, LEX_USER *user);
void get_privilege_desc(char *to, uint max_length, ulong access);
void get_mqh(const char *user, const char *host, USER_CONN *uc);
-int mysql_drop_user(THD *thd, List <LEX_USER> &list);
-int mysql_revoke_all(THD *thd, List <LEX_USER> &list);
+bool mysql_create_user(THD *thd, List <LEX_USER> &list);
+bool mysql_drop_user(THD *thd, List <LEX_USER> &list);
+bool mysql_rename_user(THD *thd, List <LEX_USER> &list);
+bool mysql_revoke_all(THD *thd, List <LEX_USER> &list);
+void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
+ const char *db, const char *table);
+bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name);
+bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name);
+bool check_routine_level_acl(THD *thd, const char *db, const char *name);
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define check_grant(A,B,C,D,E,F) 0
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 7ac9a0866df..1056bff4315 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -59,7 +59,11 @@ int compare_ulonglong2(void* cmp_arg __attribute__((unused)),
return compare_ulonglong(s,t);
}
-static bool append_escaped(String *to_str, String *from_str);
+int compare_decimal2(int* len, const char *s, const char *t)
+{
+ return memcmp(s, t, *len);
+}
+
Procedure *
proc_analyse_init(THD *thd, ORDER *param, select_result *result,
@@ -82,7 +86,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
{
// first parameter
if ((*param->item)->type() != Item::INT_ITEM ||
- (*param->item)->val() < 0)
+ (*param->item)->val_real() < 0)
{
my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
goto err;
@@ -96,7 +100,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
}
// second parameter
if ((*param->item)->type() != Item::INT_ITEM ||
- (*param->item)->val() < 0)
+ (*param->item)->val_real() < 0)
{
my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
goto err;
@@ -104,7 +108,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
pc->max_treemem = (uint) (*param->item)->val_int();
}
else if ((*param->item)->type() != Item::INT_ITEM ||
- (*param->item)->val() < 0)
+ (*param->item)->val_real() < 0)
{
my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
goto err;
@@ -129,20 +133,30 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
Item *item;
while ((item = it++))
{
- if (item->result_type() == INT_RESULT)
- {
+ field_info *new_field;
+ switch (item->result_type()) {
+ case INT_RESULT:
// Check if fieldtype is ulonglong
if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field->type() == FIELD_TYPE_LONGLONG &&
((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag)
- *f_info++ = new field_ulonglong(item, pc);
+ new_field= new field_ulonglong(item, pc);
else
- *f_info++ = new field_longlong(item, pc);
+ new_field= new field_longlong(item, pc);
+ break;
+ case REAL_RESULT:
+ new_field= new field_real(item, pc);
+ break;
+ case DECIMAL_RESULT:
+ new_field= new field_decimal(item, pc);
+ break;
+ case STRING_RESULT:
+ new_field= new field_str(item, pc);
+ break;
+ default:
+ goto err;
}
- if (item->result_type() == REAL_RESULT)
- *f_info++ = new field_real(item, pc);
- if (item->result_type() == STRING_RESULT)
- *f_info++ = new field_str(item, pc);
+ *f_info++= new_field;
}
}
DBUG_RETURN(pc);
@@ -262,7 +276,7 @@ bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num)
}
else // ulonglong is as big as bigint in MySQL
{
- if ((check_ulonglong(num, info->integers) == REAL_NUM))
+ if ((check_ulonglong(num, info->integers) == DECIMAL_NUM))
return 0;
ev_info->ullval = (ulonglong) max(ev_info->ullval, info->ullval);
ev_info->max_dval = (double) max(ev_info->max_dval, info->dval);
@@ -370,7 +384,7 @@ void field_str::add()
void field_real::add()
{
char buff[MAX_FIELD_WIDTH], *ptr, *end;
- double num = item->val();
+ double num= item->val_real();
uint length, zero_count, decs;
TREE_ELEMENT *element;
@@ -450,6 +464,83 @@ void field_real::add()
} // field_real::add
+void field_decimal::add()
+{
+ my_decimal dec_buf, *dec= item->val_decimal(&dec_buf);
+ uint length;
+ TREE_ELEMENT *element;
+
+ if (item->null_value)
+ {
+ nulls++;
+ return;
+ }
+
+ length= my_decimal_string_length(dec);
+
+ if (decimal_is_zero(dec))
+ empty++;
+
+ if (room_in_tree)
+ {
+ char buf[DECIMAL_MAX_FIELD_SIZE];
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf,
+ item->max_length, item->decimals);
+ if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg)))
+ {
+ room_in_tree = 0; // Remove tree, out of RAM ?
+ delete_tree(&tree);
+ }
+ /*
+ if element->count == 1, this element can be found only once from tree
+ if element->count == 2, or more, this element is already in tree
+ */
+ else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
+ {
+ room_in_tree = 0; // Remove tree, too many elements
+ delete_tree(&tree);
+ }
+ }
+
+ if (!found)
+ {
+ found = 1;
+ min_arg = max_arg = sum[0] = *dec;
+ min_arg.fix_buffer_pointer();
+ max_arg.fix_buffer_pointer();
+ sum[0].fix_buffer_pointer();
+ my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, dec, dec);
+ cur_sum= 0;
+ min_length = max_length = length;
+ }
+ else if (!decimal_is_zero(dec))
+ {
+ int next_cur_sum= cur_sum ^ 1;
+ my_decimal sqr_buf;
+
+ my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, dec);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
+ my_decimal_add(E_DEC_FATAL_ERROR,
+ sum_sqr+next_cur_sum, sum_sqr+cur_sum, &sqr_buf);
+ cur_sum= next_cur_sum;
+ if (length < min_length)
+ min_length = length;
+ if (length > max_length)
+ max_length = length;
+ if (my_decimal_cmp(dec, &min_arg) < 0)
+ {
+ min_arg= *dec;
+ min_arg.fix_buffer_pointer();
+ }
+ if (my_decimal_cmp(dec, &max_arg) > 0)
+ {
+ max_arg= *dec;
+ max_arg.fix_buffer_pointer();
+ }
+ }
+}
+
+
void field_longlong::add()
{
char buff[MAX_FIELD_WIDTH];
@@ -887,6 +978,72 @@ void field_ulonglong::get_opt_type(String *answer,
} //field_ulonglong::get_opt_type
+void field_decimal::get_opt_type(String *answer,
+ ha_rows total_rows __attribute__((unused)))
+{
+ my_decimal zero;
+ char buff[MAX_FIELD_WIDTH];
+ uint length;
+
+ my_decimal_set_zero(&zero);
+ my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0);
+
+ length= my_sprintf(buff, (buff, "DECIMAL(%d, %d)",
+ (int) (max_length - (item->decimals ? 1 : 0)),
+ item->decimals));
+ if (is_unsigned)
+ length= (uint) (strmov(buff+length, " UNSIGNED")- buff);
+ answer->append(buff, length);
+}
+
+
+String *field_decimal::get_min_arg(String *str)
+{
+ my_decimal2string(E_DEC_FATAL_ERROR, &min_arg, 0, 0, '0', str);
+ return str;
+}
+
+
+String *field_decimal::get_max_arg(String *str)
+{
+ my_decimal2string(E_DEC_FATAL_ERROR, &max_arg, 0, 0, '0', str);
+ return str;
+}
+
+
+String *field_decimal::avg(String *s, ha_rows rows)
+{
+ if (!(rows - nulls))
+ {
+ s->set((double) 0.0, 1,my_thd_charset);
+ return s;
+ }
+ my_decimal num, avg_val;
+ int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
+ my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, 0);
+ my_decimal2string(E_DEC_FATAL_ERROR, &avg_val, 0, 0, '0', s);
+ return s;
+}
+
+
+String *field_decimal::std(String *s, ha_rows rows)
+{
+ if (!(rows - nulls))
+ {
+ s->set((double) 0.0, 1,my_thd_charset);
+ return s;
+ }
+ my_decimal num, std_val, sum2, sum2d;
+ int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sum2, sum+cur_sum, sum+cur_sum);
+ my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0);
+ my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &std_val);
+ my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0);
+ my_decimal2string(E_DEC_FATAL_ERROR, &std_val, 0, 0, '0', s);
+ return s;
+}
+
+
int collect_string(String *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
@@ -921,6 +1078,28 @@ int collect_real(double *element, element_count count __attribute__((unused)),
} // collect_real
+int collect_decimal(char *element, element_count count,
+ TREE_INFO *info)
+{
+ char buff[DECIMAL_MAX_STR_LENGTH];
+ String s(buff, sizeof(buff),&my_charset_bin);
+
+ if (info->found)
+ info->str->append(',');
+ else
+ info->found = 1;
+ my_decimal dec;
+ binary2my_decimal(E_DEC_FATAL_ERROR, element, &dec,
+ info->item->max_length, info->item->decimals);
+
+ info->str->append('\'');
+ my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, '0', &s);
+ info->str->append(s);
+ info->str->append('\'');
+ return 0;
+}
+
+
int collect_longlong(longlong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
@@ -1022,12 +1201,12 @@ uint check_ulonglong(const char *str, uint length)
bigger = LONG_NUM;
}
else if (length > ulonglong_len)
- return REAL_NUM;
+ return DECIMAL_NUM;
else
{
cmp = ulonglong_str;
smaller = LONG_NUM;
- bigger = REAL_NUM;
+ bigger = DECIMAL_NUM;
}
while (*cmp && *cmp++ == *str++) ;
return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
@@ -1052,7 +1231,7 @@ uint check_ulonglong(const char *str, uint length)
1 Out of memory
*/
-static bool append_escaped(String *to_str, String *from_str)
+bool append_escaped(String *to_str, String *from_str)
{
char *from, *end, c;
diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h
index 3d1cffecaef..a0f0df9b43b 100644
--- a/sql/sql_analyse.h
+++ b/sql/sql_analyse.h
@@ -61,6 +61,7 @@ int compare_longlong2(void* cmp_arg __attribute__((unused)),
int compare_ulonglong(const ulonglong *s, const ulonglong *t);
int compare_ulonglong2(void* cmp_arg __attribute__((unused)),
const ulonglong *s, const ulonglong *t);
+int compare_decimal2(int* len, const char *s, const char *t);
Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result,
List<Item> &field_list);
void free_string(String*);
@@ -143,6 +144,36 @@ public:
};
+int collect_decimal(char *element, element_count count,
+ TREE_INFO *info);
+
+class field_decimal :public field_info
+{
+ my_decimal min_arg, max_arg;
+ my_decimal sum[2], sum_sqr[2];
+ int cur_sum;
+ int bin_size;
+public:
+ field_decimal(Item* a, analyse* b) :field_info(a,b)
+ {
+ bin_size= my_decimal_get_binary_size(a->max_length, a->decimals);
+ init_tree(&tree, 0, 0, bin_size, (qsort_cmp2)compare_decimal2,
+ 0, 0, (void *)&bin_size);
+ };
+
+ void add();
+ void get_opt_type(String*, ha_rows);
+ String *get_min_arg(String *);
+ String *get_max_arg(String *);
+ String *avg(String *s, ha_rows rows);
+ friend int collect_decimal(char *element, element_count count,
+ TREE_INFO *info);
+ tree_walk_action collect_enum()
+ { return (tree_walk_action) collect_decimal; }
+ String *std(String *s, ha_rows rows);
+};
+
+
int collect_real(double *element, element_count count, TREE_INFO *info);
class field_real: public field_info
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 8d694c48849..ade1fb96b96 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -19,30 +19,37 @@
#include "mysql_priv.h"
#include "sql_select.h"
+#include "sp_head.h"
+#include "sp.h"
+#include "sql_trigger.h"
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
-#include <nisam.h>
#ifdef __WIN__
#include <io.h>
#endif
TABLE *unused_tables; /* Used by mysql_test */
HASH open_cache; /* Used by mysql_test */
-HASH assign_cache;
-static int open_unireg_entry(THD *thd,TABLE *entry,const char *db,
- const char *name, const char *alias);
+static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
+ const char *name, const char *alias,
+ TABLE_LIST *table_list, MEM_ROOT *mem_root);
static void free_cache_entry(TABLE *entry);
static void mysql_rm_tmp_tables(void);
-
+static my_bool open_new_frm(const char *path, const char *alias,
+ const char *db, const char *table_name,
+ uint db_stat, uint prgflag,
+ uint ha_open_flags, TABLE *outparam,
+ TABLE_LIST *table_desc, MEM_ROOT *mem_root);
+static void relink_tables_for_multidelete(THD *thd);
extern "C" byte *table_cache_key(const byte *record,uint *length,
my_bool not_used __attribute__((unused)))
{
TABLE *entry=(TABLE*) record;
- *length=entry->key_length;
- return (byte*) entry->table_cache_key;
+ *length= entry->s->key_length;
+ return (byte*) entry->s->table_cache_key;
}
bool table_cache_init(void)
@@ -140,20 +147,21 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
{
OPEN_TABLE_LIST *table;
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
+ TABLE_SHARE *share= entry->s;
- DBUG_ASSERT(entry->real_name);
- if ((!entry->real_name)) // To be removed
+ DBUG_ASSERT(share->table_name != 0);
+ if ((!share->table_name)) // To be removed
continue; // Shouldn't happen
if (wild)
{
- strxmov(name,entry->table_cache_key,".",entry->real_name,NullS);
+ strxmov(name,share->table_cache_key,".",share->table_name,NullS);
if (wild_compare(name,wild,0))
continue;
}
/* Check if user has SELECT privilege for any column in the table */
- table_list.db= (char*) entry->table_cache_key;
- table_list.real_name= entry->real_name;
+ table_list.db= (char*) share->db;
+ table_list.table_name= (char*) share->table_name;
table_list.grant.privilege=0;
if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list,1))
@@ -161,8 +169,8 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
/* need to check if we haven't already listed it */
for (table= open_list ; table ; table=table->next)
{
- if (!strcmp(table->table,entry->real_name) &&
- !strcmp(table->db,entry->table_cache_key))
+ if (!strcmp(table->table,share->table_name) &&
+ !strcmp(table->db,entry->s->db))
{
if (entry->in_use)
table->in_use++;
@@ -174,15 +182,15 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
if (table)
continue;
if (!(*start_list = (OPEN_TABLE_LIST *)
- sql_alloc(sizeof(**start_list)+entry->key_length)))
+ sql_alloc(sizeof(**start_list)+share->key_length)))
{
open_list=0; // Out of memory
break;
}
strmov((*start_list)->table=
strmov(((*start_list)->db= (char*) ((*start_list)+1)),
- entry->table_cache_key)+1,
- entry->real_name);
+ entry->s->db)+1,
+ entry->s->table_name);
(*start_list)->in_use= entry->in_use ? 1 : 0;
(*start_list)->locked= entry->locked_by_name ? 1 : 0;
start_list= &(*start_list)->next;
@@ -200,6 +208,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
void intern_close_table(TABLE *table)
{ // Free all structures
free_io_cache(table);
+ delete table->triggers;
if (table->file)
VOID(closefrm(table)); // close file
}
@@ -282,9 +291,9 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
else
{
bool found=0;
- for (TABLE_LIST *table=tables ; table ; table=table->next)
+ for (TABLE_LIST *table= tables; table; table= table->next_local)
{
- if (remove_table_from_cache(thd, table->db, table->real_name, 1))
+ if (remove_table_from_cache(thd, table->db, table->table_name, 1))
found=1;
}
if (!found)
@@ -316,7 +325,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
for (uint idx=0 ; idx < open_cache.records ; idx++)
{
TABLE *table=(TABLE*) hash_element(&open_cache,idx);
- if ((table->version) < refresh_version && table->db_stat)
+ if ((table->s->version) < refresh_version && table->db_stat)
{
found=1;
pthread_cond_wait(&COND_refresh,&LOCK_open);
@@ -333,8 +342,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
result=reopen_tables(thd,1,1);
thd->in_lock_tables=0;
/* Set version for table */
- for (TABLE *table=thd->open_tables; table ; table=table->next)
- table->version=refresh_version;
+ for (TABLE *table=thd->open_tables; table ; table= table->next)
+ table->s->version= refresh_version;
}
VOID(pthread_mutex_unlock(&LOCK_open));
if (if_wait_for_refresh)
@@ -350,7 +359,30 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
/*
- Close all tables used by thread
+ Mark all tables in the list which were used by current substatement
+ as free for reuse.
+
+ SYNOPSIS
+ mark_used_tables_as_free_for_reuse()
+ thd - thread context
+ table - head of the list of tables
+
+ DESCRIPTION
+ Marks all tables in the list which were used by current substatement
+ (they are marked by its query_id) as free for reuse.
+*/
+
+static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
+{
+ for (; table ; table= table->next)
+ if (table->query_id == thd->query_id)
+ table->query_id= 0;
+}
+
+
+/*
+ Close all tables used by the current substatement, or all tables
+ used by this thread if we are on the upper level.
SYNOPSIS
close_thread_tables()
@@ -363,19 +395,37 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
IMPLEMENTATION
Unlocks tables and frees derived tables.
Put all normal tables used by thread in free list.
+
+ When in prelocked mode it will only close/mark as free for reuse
+ tables opened by this substatement, it will also check if we are
+ closing tables after execution of complete query (i.e. we are on
+ upper level) and will leave prelocked mode if needed.
*/
-void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
+void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
+ TABLE *stopper)
{
bool found_old_table;
+ prelocked_mode_type prelocked_mode= thd->prelocked_mode;
DBUG_ENTER("close_thread_tables");
+ /*
+ We are assuming here that thd->derived_tables contains ONLY derived
+ tables for this substatement. i.e. instead of approach which uses
+ query_id matching for determining which of the derived tables belong
+ to this substatement we rely on the ability of substatements to
+ save/restore thd->derived_tables during their execution.
+
+ TODO: Probably even better approach is to simply associate list of
+ derived tables with (sub-)statement instead of thread and destroy
+ them at the end of its execution.
+ */
if (thd->derived_tables && !skip_derived)
{
TABLE *table, *next;
/*
- Close all derived tables generated from questions like
- SELECT * from (select * from t1))
+ Close all derived tables generated in queries like
+ SELECT * FROM (SELECT * FROM t1)
*/
for (table= thd->derived_tables ; table ; table= next)
{
@@ -384,10 +434,50 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
}
thd->derived_tables= 0;
}
- if (thd->locked_tables)
+
+ if (prelocked_mode)
{
- ha_commit_stmt(thd); // If select statement
- DBUG_VOID_RETURN; // LOCK TABLES in use
+ /*
+ Mark all temporary tables used by this substatement as free for reuse.
+ */
+ mark_used_tables_as_free_for_reuse(thd, thd->temporary_tables);
+ }
+
+ if (thd->locked_tables || prelocked_mode)
+ {
+ /*
+ TODO: It is not 100% clear whenever we should do ha_commit_stmt() for
+ sub-statements. This issue needs additional investigation.
+ */
+ ha_commit_stmt(thd);
+
+ /* We are under simple LOCK TABLES so should not do anything else. */
+ if (!prelocked_mode)
+ DBUG_VOID_RETURN;
+
+ if (!thd->lex->requires_prelocking())
+ {
+ /*
+ If we are executing one of substatements we have to mark
+ all tables which it used as free for reuse.
+ */
+ mark_used_tables_as_free_for_reuse(thd, thd->open_tables);
+ DBUG_VOID_RETURN;
+ }
+
+ DBUG_ASSERT(prelocked_mode);
+ /*
+ We are in prelocked mode, so we have to leave it now with doing
+ implicit UNLOCK TABLES if need.
+ */
+ thd->prelocked_mode= NON_PRELOCKED;
+
+ if (prelocked_mode == PRELOCKED_UNDER_LOCK_TABLES)
+ DBUG_VOID_RETURN;
+
+ thd->lock= thd->locked_tables;
+ thd->locked_tables= 0;
+ /* Fallthrough */
}
if (thd->lock)
@@ -395,15 +485,27 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ /*
+ assume handlers auto-commit (if some doesn't - transaction handling
+ in MySQL should be redesigned to support it; it's a big change,
+ and it's not worth it - better to commit explicitly only writing
+ transactions, read-only ones should better take care of themselves.
+ saves some work in 2pc too)
+ see also sql_parse.cc - dispatch_command()
+ */
+ bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
+ if (!thd->active_transaction())
+ thd->transaction.xid.null();
+
/* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */
if (!lock_in_use)
VOID(pthread_mutex_lock(&LOCK_open));
safe_mutex_assert_owner(&LOCK_open);
- DBUG_PRINT("info", ("thd->open_tables=%p", thd->open_tables));
+ DBUG_PRINT("info", ("thd->open_tables: %p", thd->open_tables));
found_old_table= 0;
- while (thd->open_tables)
+ while (thd->open_tables != stopper)
found_old_table|=close_thread_table(thd, &thd->open_tables);
thd->some_tables_deleted=0;
@@ -419,6 +521,17 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
if (!lock_in_use)
VOID(pthread_mutex_unlock(&LOCK_open));
/* VOID(pthread_sigmask(SIG_SETMASK,&thd->signals,NULL)); */
+
+ if (prelocked_mode == PRELOCKED)
+ {
+ /*
+ If we are here then we are leaving normal prelocked mode, so it is
+ good idea to turn off OPTION_TABLE_LOCK flag.
+ */
+ DBUG_ASSERT(thd->lex->requires_prelocking());
+ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+ }
+
DBUG_VOID_RETURN;
}
@@ -431,9 +544,10 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
bool found_old_table= 0;
TABLE *table= *table_ptr;
DBUG_ASSERT(table->key_read == 0);
+ DBUG_ASSERT(table->file->inited == handler::NONE);
*table_ptr=table->next;
- if (table->version != refresh_version ||
+ if (table->s->version != refresh_version ||
thd->version != refresh_version || !table->db_stat)
{
VOID(hash_delete(&open_cache,(byte*) table));
@@ -441,9 +555,9 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
}
else
{
- if (table->flush_version != flush_version)
+ if (table->s->flush_version != flush_version)
{
- table->flush_version=flush_version;
+ table->s->flush_version= flush_version;
table->file->extra(HA_EXTRA_FLUSH);
}
else
@@ -471,8 +585,8 @@ void close_temporary(TABLE *table,bool delete_table)
{
DBUG_ENTER("close_temporary");
char path[FN_REFLEN];
- db_type table_type=table->db_type;
- strmov(path,table->path);
+ db_type table_type=table->s->db_type;
+ strmov(path,table->s->path);
free_io_cache(table);
closefrm(table);
my_free((char*) table,MYF(0));
@@ -501,7 +615,7 @@ void close_temporary_tables(THD *thd)
enough; indeed it is enough, because table->key_length is greater (by 8,
because of server_id and thread_id) than db||table.
*/
- query_buf_size+= table->key_length+1;
+ query_buf_size+= table->s->key_length+1;
if ((query = alloc_root(thd->mem_root, query_buf_size)))
// Better add "if exists", in case a RESET MASTER has been done
@@ -512,17 +626,13 @@ void close_temporary_tables(THD *thd)
if (query) // we might be out of memory, but this is not fatal
{
// skip temporary tables not created directly by the user
- if (table->real_name[0] != '#')
+ if (table->s->table_name[0] != '#')
found_user_tables = 1;
- /*
- Here we assume table_cache_key always starts
- with \0 terminated db name
- */
- end = strxmov(end,"`",table->table_cache_key,"`.`",
- table->real_name,"`,", NullS);
+ end = strxmov(end,"`",table->s->db,"`.`",
+ table->s->table_name,"`,", NullS);
}
next=table->next;
- close_temporary(table);
+ close_temporary(table, 1);
}
if (query && found_user_tables && mysql_bin_log.is_open())
{
@@ -544,56 +654,124 @@ void close_temporary_tables(THD *thd)
thd->temporary_tables=0;
}
+
/*
- Find first suitable table by alias in given list.
+ Find table in list.
SYNOPSIS
find_table_in_list()
- table - pointer to table list
- db_name - data base name or 0 for any
- table_name - table name or 0 for any
+ table Pointer to table list
+ offset Offset to which list in table structure to use
+ db_name Data base name
+ table_name Table name
+
+ NOTES:
+ This is called by find_table_in_local_list() and
+ find_table_in_global_list().
RETURN VALUES
NULL Table not found
# Pointer to found table.
*/
-TABLE_LIST * find_table_in_list(TABLE_LIST *table,
- const char *db_name, const char *table_name)
+TABLE_LIST *find_table_in_list(TABLE_LIST *table,
+ uint offset,
+ const char *db_name,
+ const char *table_name)
{
- for (; table; table= table->next)
- if ((!db_name || !strcmp(table->db, db_name)) &&
- (!table_name || !my_strcasecmp(table_alias_charset,
- table->alias, table_name)))
+ for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
+ {
+ if ((table->table == 0 || table->table->s->tmp_table == NO_TMP_TABLE) &&
+ strcmp(table->db, db_name) == 0 &&
+ strcmp(table->table_name, table_name) == 0)
break;
+ }
return table;
}
+
/*
- Find real table in given list.
+ Test that table is unique (It's only exists once in the table list)
SYNOPSIS
- find_real_table_in_list()
- table - pointer to table list
- db_name - data base name
- table_name - table name
+ unique_table()
+ table table which should be checked
+ table_list list of tables
+
+ NOTE: to exclude derived tables from check we use following mechanism:
+ a) during derived table processing set THD::derived_tables_processing
+ b) JOIN::prepare set SELECT::exclude_from_table_unique_test if
+ THD::derived_tables_processing set. (we can't use JOIN::execute
+ because for PS we perform only JOIN::prepare, but we can't set this
+ flag in JOIN::prepare if we are not sure that we are in derived table
+ processing loop, because multi-update call fix_fields() for some its
+ items (which mean JOIN::prepare for subqueries) before unique_table
+ call to detect which tables should be locked for write).
+ c) unique_table skip all tables which belong to SELECT with
+ SELECT::exclude_from_table_unique_test set.
+ Also SELECT::exclude_from_table_unique_test used to exclude from check
+ tables of main SELECT of multi-delete and multi-update
+
+ TODO: when we will have table/view change detection we can do this check
+ only once for PS/SP
- RETURN VALUES
- NULL Table not found
- # Pointer to found table.
+ RETURN
+ found duplicate
+ 0 if table is unique
*/
-TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
- const char *db_name,
- const char *table_name)
+TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
{
- for (; table; table= table->next)
- if (!strcmp(table->db, db_name) &&
- !strcmp(table->real_name, table_name))
+ TABLE_LIST *res;
+ const char *d_name, *t_name;
+ DBUG_ENTER("unique_table");
+ DBUG_PRINT("enter", ("table alias: %s", table->alias));
+
+ /*
+ If this function called for query which update table (INSERT/UPDATE/...)
+ then we have in table->table pointer to TABLE object which we are
+ updating even if it is VIEW so we need TABLE_LIST of this TABLE object
+ to get right names (even if lower_case_table_names used).
+
+ If this function called for CREATE command that we have not opened table
+ (table->table equal to 0) and right names is in current TABLE_LIST
+ object.
+ */
+ if (table->table)
+ {
+ /* temporary table is always unique */
+ if (table->table && table->table->s->tmp_table != NO_TMP_TABLE)
+ DBUG_RETURN(0);
+ table= table->find_underlying_table(table->table);
+ /*
+ as far as we have table->table we have to find real TABLE_LIST of
+ it in underlying tables
+ */
+ DBUG_ASSERT(table);
+ }
+ d_name= table->db;
+ t_name= table->table_name;
+
+ DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
+ for(;;)
+ {
+ if (!(res= find_table_in_global_list(table_list, d_name, t_name)) ||
+ (!res->table || res->table != table->table) &&
+ (res->select_lex && !res->select_lex->exclude_from_table_unique_test))
break;
- return table;
+ /*
+ If we found entry of this table or or table of SELECT which already
+ processed in derived table or top select of multi-update/multi-delete
+ (exclude_from_table_unique_test).
+ */
+ table_list= res->next_global;
+ DBUG_PRINT("info",
+ ("found same copy of table or table which we should skip"));
+ }
+ DBUG_RETURN(res);
}
+
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
{
char key[MAX_DBKEY_LENGTH];
@@ -608,8 +786,8 @@ TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
prev= &thd->temporary_tables;
for (table=thd->temporary_tables ; table ; table=table->next)
{
- if (table->key_length == key_length &&
- !memcmp(table->table_cache_key,key,key_length))
+ if (table->s->key_length == key_length &&
+ !memcmp(table->s->table_cache_key,key,key_length))
return prev;
prev= &table->next;
}
@@ -624,7 +802,7 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name)
return 1;
table= *prev;
*prev= table->next;
- close_temporary(table);
+ close_temporary(table, 1);
if (thd->slave_thread)
--slave_open_temp_tables;
return 0;
@@ -637,22 +815,26 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name)
Prepares a table cache key, which is the concatenation of db, table_name and
thd->slave_proxy_id, separated by '\0'.
*/
+
bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
const char *table_name)
{
char *key;
+ TABLE_SHARE *share= table->s;
+
if (!(key=(char*) alloc_root(&table->mem_root,
(uint) strlen(db)+
(uint) strlen(table_name)+6+4)))
return 1; /* purecov: inspected */
- table->key_length=(uint)
- (strmov((table->real_name=strmov(table->table_cache_key=key,
- db)+1),
- table_name) - table->table_cache_key)+1;
- int4store(key+table->key_length,thd->server_id);
- table->key_length += 4;
- int4store(key+table->key_length,thd->variables.pseudo_thread_id);
- table->key_length += 4;
+ share->key_length= (uint)
+ (strmov((char*) (share->table_name= strmov(share->table_cache_key= key,
+ db)+1),
+ table_name) - share->table_cache_key)+1;
+ share->db= share->table_cache_key;
+ int4store(key+share->key_length, thd->server_id);
+ share->key_length+= 4;
+ int4store(key+share->key_length, thd->variables.pseudo_thread_id);
+ share->key_length+= 4;
return 0;
}
@@ -683,15 +865,16 @@ static void relink_unused(TABLE *table)
TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find)
{
char key[MAX_DBKEY_LENGTH];
- uint key_length=find->key_length;
+ uint key_length= find->s->key_length;
TABLE *start=list,**prev,*next;
prev= &start;
- memcpy(key,find->table_cache_key,key_length);
+
+ memcpy(key, find->s->table_cache_key, key_length);
for (; list ; list=next)
{
next=list->next;
- if (list->key_length == key_length &&
- !memcmp(list->table_cache_key,key,key_length))
+ if (list->s->key_length == key_length &&
+ !memcmp(list->s->table_cache_key, key, key_length))
{
if (thd->locked_tables)
mysql_lock_remove(thd, thd->locked_tables,list);
@@ -742,29 +925,34 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
DBUG_ENTER("reopen_name_locked_table");
if (thd->killed)
DBUG_RETURN(0);
- TABLE* table;
+ TABLE *table;
+ TABLE_SHARE *share;
if (!(table = table_list->table))
DBUG_RETURN(0);
char* db = thd->db ? thd->db : table_list->db;
- char* table_name = table_list->real_name;
+ char* table_name = table_list->table_name;
char key[MAX_DBKEY_LENGTH];
uint key_length;
key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
pthread_mutex_lock(&LOCK_open);
- if (open_unireg_entry(thd, table, db, table_name, table_name) ||
- !(table->table_cache_key =memdup_root(&table->mem_root,(char*) key,
- key_length)))
+ if (open_unireg_entry(thd, table, db, table_name, table_name, 0,
+ thd->mem_root) ||
+ !(table->s->table_cache_key= memdup_root(&table->mem_root, (char*) key,
+ key_length)))
{
+ delete table->triggers;
closefrm(table);
pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(0);
}
- table->key_length=key_length;
- table->version=0;
- table->flush_version=0;
+ share= table->s;
+ share->db= share->table_cache_key;
+ share->key_length=key_length;
+ share->version=0;
+ share->flush_version=0;
table->in_use = thd;
check_unused();
pthread_mutex_unlock(&LOCK_open);
@@ -773,10 +961,10 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
table->const_table=0;
- table->outer_join= table->null_row= table->maybe_null= table->force_index= 0;
+ table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
- table->keys_in_use_for_query= table->keys_in_use;
- table->used_keys= table->keys_for_keyread;
+ table->keys_in_use_for_query= share->keys_in_use;
+ table->used_keys= share->keys_for_keyread;
DBUG_RETURN(table);
}
@@ -791,12 +979,13 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
******************************************************************************/
-TABLE *open_table(THD *thd,const char *db,const char *table_name,
- const char *alias,bool *refresh)
+TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
+ bool *refresh)
{
reg1 TABLE *table;
char key[MAX_DBKEY_LENGTH];
uint key_length;
+ char *alias= table_list->alias;
DBUG_ENTER("open_table");
/* find a unused table in the open table cache */
@@ -804,45 +993,81 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
*refresh=0;
if (thd->killed)
DBUG_RETURN(0);
- key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
+ key_length= (uint) (strmov(strmov(key, table_list->db)+1,
+ table_list->table_name)-key)+1;
int4store(key + key_length, thd->server_id);
int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
- for (table=thd->temporary_tables; table ; table=table->next)
+ if (!table_list->skip_temporary)
{
- if (table->key_length == key_length + TMP_TABLE_KEY_EXTRA &&
- !memcmp(table->table_cache_key, key,
- key_length + TMP_TABLE_KEY_EXTRA))
+ for (table= thd->temporary_tables; table ; table=table->next)
{
- if (table->query_id == thd->query_id)
+ if (table->s->key_length == key_length + TMP_TABLE_KEY_EXTRA &&
+ !memcmp(table->s->table_cache_key, key,
+ key_length + TMP_TABLE_KEY_EXTRA))
{
- my_printf_error(ER_CANT_REOPEN_TABLE,
- ER(ER_CANT_REOPEN_TABLE),MYF(0),table->table_name);
- DBUG_RETURN(0);
+ if (table->query_id == thd->query_id ||
+ thd->prelocked_mode && table->query_id)
+ {
+ my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
+ DBUG_RETURN(0);
+ }
+ table->query_id= thd->query_id;
+ table->clear_query_id= 1;
+ thd->tmp_table_used= 1;
+ DBUG_PRINT("info",("Using temporary table"));
+ goto reset;
}
- table->query_id=thd->query_id;
- table->clear_query_id=1;
- thd->tmp_table_used= 1;
- DBUG_PRINT("info",("Using temporary table"));
- goto reset;
}
}
- if (thd->locked_tables)
+ if (thd->locked_tables || thd->prelocked_mode)
{ // Using table locks
for (table=thd->open_tables; table ; table=table->next)
{
- if (table->key_length == key_length &&
- !memcmp(table->table_cache_key,key,key_length) &&
- !my_strcasecmp(system_charset_info, table->table_name, alias) &&
- table->query_id != thd->query_id)
+ if (table->s->key_length == key_length &&
+ !memcmp(table->s->table_cache_key, key, key_length) &&
+ !my_strcasecmp(system_charset_info, table->alias, alias) &&
+ table->query_id != thd->query_id && /* skip tables already used by this query */
+ !(thd->prelocked_mode && table->query_id))
{
- table->query_id=thd->query_id;
+ table->query_id= thd->query_id;
DBUG_PRINT("info",("Using locked table"));
goto reset;
}
}
- my_printf_error(ER_TABLE_NOT_LOCKED,ER(ER_TABLE_NOT_LOCKED),MYF(0),alias);
+ /*
+ is it view?
+ (it is work around to allow to open view with locked tables,
+ real fix will be made after definition cache will be made)
+ */
+ {
+ char path[FN_REFLEN];
+ strxnmov(path, FN_REFLEN, mysql_data_home, "/", table_list->db, "/",
+ table_list->table_name, reg_ext, NullS);
+ (void) unpack_filename(path, path);
+ if (mysql_frm_type(path) == FRMTYPE_VIEW)
+ {
+ TABLE tab;// will not be used (because it's VIEW) but have to be passed
+ table= &tab;
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (open_unireg_entry(thd, table, table_list->db,
+ table_list->table_name,
+ alias, table_list, mem_root))
+ {
+ table->next=table->prev=table;
+ free_cache_entry(table);
+ }
+ else
+ {
+ DBUG_ASSERT(table_list->view != 0);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(0); // VIEW
+ }
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
+ }
+ my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
DBUG_RETURN(0);
}
@@ -859,13 +1084,14 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
}
/* close handler tables which are marked for flush */
- mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE);
+ if (thd->handler_tables)
+ mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE);
for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
table && table->in_use ;
table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
{
- if (table->version != refresh_version)
+ if (table->s->version != refresh_version)
{
/*
** There is a refresh in progress for this table
@@ -875,7 +1101,9 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
if (table->in_use != thd)
wait_for_refresh(thd);
else
+ {
VOID(pthread_mutex_unlock(&LOCK_open));
+ }
if (refresh)
*refresh=1;
DBUG_RETURN(0);
@@ -891,10 +1119,11 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
}
table->prev->next=table->next; /* Remove from unused list */
table->next->prev=table->prev;
-
+ table->in_use= thd;
}
else
{
+ TABLE_SHARE *share;
/* Free cache if too big */
while (open_cache.records > table_cache_size && unused_tables)
VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
@@ -905,25 +1134,35 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(NULL);
}
- if (open_unireg_entry(thd, table,db,table_name,alias) ||
- !(table->table_cache_key=memdup_root(&table->mem_root,(char*) key,
- key_length)))
+ if (open_unireg_entry(thd, table, table_list->db, table_list->table_name,
+ alias, table_list, mem_root) ||
+ (!table_list->view &&
+ !(table->s->table_cache_key= memdup_root(&table->mem_root,
+ (char*) key,
+ key_length))))
{
table->next=table->prev=table;
free_cache_entry(table);
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(NULL);
}
- table->key_length=key_length;
- table->version=refresh_version;
- table->flush_version=flush_version;
+ if (table_list->view)
+ {
+ my_free((gptr)table, MYF(0));
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(0); // VIEW
+ }
+ share= table->s;
+ share->db= share->table_cache_key;
+ share->key_length= key_length;
+ share->version= refresh_version;
+ share->flush_version= flush_version;
DBUG_PRINT("info", ("inserting table %p into the cache", table));
VOID(my_hash_insert(&open_cache,(byte*) table));
}
- table->in_use=thd;
check_unused(); // Debugging call
-
+
VOID(pthread_mutex_unlock(&LOCK_open));
if (refresh)
{
@@ -933,51 +1172,29 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
table->reginfo.lock_type=TL_READ; /* Assume read */
reset:
+ if (thd->lex->need_correct_ident())
+ table->alias_name_used= my_strcasecmp(table_alias_charset,
+ table->s->table_name, alias);
/* Fix alias if table name changes */
- if (strcmp(table->table_name,alias))
+ if (strcmp(table->alias, alias))
{
uint length=(uint) strlen(alias)+1;
- table->table_name= (char*) my_realloc(table->table_name,length,
- MYF(MY_WME));
- memcpy(table->table_name,alias,length);
- for (uint i=0 ; i < table->fields ; i++)
- table->field[i]->table_name=table->table_name;
+ table->alias= (char*) my_realloc((char*) table->alias, length,
+ MYF(MY_WME));
+ memcpy((char*) table->alias, alias, length);
}
-#if MYSQL_VERSION_ID < 40100
- /*
- If per-connection "new" variable (represented by variables.new_mode)
- is set then we should pretend that the length of TIMESTAMP field is 19.
- The cheapest (from perfomance viewpoint) way to achieve that is to set
- field_length of all Field_timestamp objects in a table after opening
- it (to 19 if new_mode is true or to original field length otherwise).
- We save value of new_mode variable in TABLE::timestamp_mode to
- not perform this setup if new_mode value is the same between sequential
- table opens.
- */
- my_bool new_mode= thd->variables.new_mode;
- if (table->timestamp_mode != new_mode)
- {
- for (uint i=0 ; i < table->fields ; i++)
- {
- Field *field= table->field[i];
-
- if (field->type() == FIELD_TYPE_TIMESTAMP)
- field->field_length= new_mode ? 19 :
- ((Field_timestamp *)(field))->orig_field_length;
- }
- table->timestamp_mode= new_mode;
- }
-#endif
/* These variables are also set in reopen_table() */
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
table->const_table=0;
- table->outer_join= table->null_row= table->maybe_null= table->force_index= 0;
+ table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
- table->keys_in_use_for_query= table->keys_in_use;
- table->used_keys= table->keys_for_keyread;
+ table->keys_in_use_for_query= table->s->keys_in_use;
+ table->insert_values= 0;
+ table->used_keys= table->s->keys_for_keyread;
if (table->timestamp_field)
table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
+ table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
DBUG_ASSERT(table->key_read == 0);
DBUG_RETURN(table);
}
@@ -990,8 +1207,8 @@ TABLE *find_locked_table(THD *thd, const char *db,const char *table_name)
for (TABLE *table=thd->open_tables; table ; table=table->next)
{
- if (table->key_length == key_length &&
- !memcmp(table->table_cache_key,key,key_length))
+ if (table->s->key_length == key_length &&
+ !memcmp(table->s->table_cache_key,key,key_length))
return table;
}
return(0);
@@ -1008,9 +1225,9 @@ TABLE *find_locked_table(THD *thd, const char *db,const char *table_name)
bool reopen_table(TABLE *table,bool locked)
{
TABLE tmp;
- char *db=table->table_cache_key;
- char *table_name=table->real_name;
- bool error=1;
+ char *db= table->s->table_cache_key;
+ const char *table_name= table->s->table_name;
+ bool error= 1;
Field **field;
uint key,part;
DBUG_ENTER("reopen_table");
@@ -1018,60 +1235,64 @@ bool reopen_table(TABLE *table,bool locked)
#ifdef EXTRA_DEBUG
if (table->db_stat)
sql_print_error("Table %s had a open data handler in reopen_table",
- table->table_name);
+ table->alias);
#endif
if (!locked)
VOID(pthread_mutex_lock(&LOCK_open));
safe_mutex_assert_owner(&LOCK_open);
- if (open_unireg_entry(current_thd,&tmp,db,table_name,table->table_name))
+ if (open_unireg_entry(table->in_use, &tmp, db, table_name,
+ table->alias, 0, table->in_use->mem_root))
goto end;
free_io_cache(table);
- if (!(tmp.table_cache_key= memdup_root(&tmp.mem_root,db,
- table->key_length)))
+ if (!(tmp.s->table_cache_key= memdup_root(&tmp.mem_root,db,
+ table->s->key_length)))
{
+ delete tmp.triggers;
closefrm(&tmp); // End of memory
goto end;
}
+ tmp.s->db= tmp.s->table_cache_key;
/* This list copies variables set by open_table */
tmp.tablenr= table->tablenr;
tmp.used_fields= table->used_fields;
tmp.const_table= table->const_table;
- tmp.outer_join= table->outer_join;
tmp.null_row= table->null_row;
tmp.maybe_null= table->maybe_null;
tmp.status= table->status;
- tmp.keys_in_use_for_query= tmp.keys_in_use;
- tmp.used_keys= tmp.keys_for_keyread;
+ tmp.keys_in_use_for_query= tmp.s->keys_in_use;
+ tmp.used_keys= tmp.s->keys_for_keyread;
tmp.force_index= tmp.force_index;
/* Get state */
- tmp.key_length= table->key_length;
+ tmp.s->key_length= table->s->key_length;
tmp.in_use= table->in_use;
tmp.reginfo.lock_type=table->reginfo.lock_type;
- tmp.version= refresh_version;
- tmp.tmp_table= table->tmp_table;
+ tmp.s->version= refresh_version;
+ tmp.s->tmp_table= table->s->tmp_table;
tmp.grant= table->grant;
/* Replace table in open list */
tmp.next= table->next;
tmp.prev= table->prev;
+ delete table->triggers;
if (table->file)
VOID(closefrm(table)); // close file, free everything
- *table=tmp;
+ *table= tmp;
+ table->s= &table->share_not_to_be_used;
table->file->change_table_ptr(table);
- DBUG_ASSERT(table->table_name);
+ DBUG_ASSERT(table->alias != 0);
for (field=table->field ; *field ; field++)
{
(*field)->table= (*field)->orig_table= table;
- (*field)->table_name=table->table_name;
+ (*field)->table_name= &table->alias;
}
- for (key=0 ; key < table->keys ; key++)
+ for (key=0 ; key < table->s->keys ; key++)
for (part=0 ; part < table->key_info[key].usable_key_parts ; part++)
table->key_info[key].key_part[part].field->table= table;
VOID(pthread_cond_broadcast(&COND_refresh));
@@ -1095,8 +1316,8 @@ bool close_data_tables(THD *thd,const char *db, const char *table_name)
TABLE *table;
for (table=thd->open_tables; table ; table=table->next)
{
- if (!strcmp(table->real_name,table_name) &&
- !strcmp(table->table_cache_key,db))
+ if (!strcmp(table->s->table_name, table_name) &&
+ !strcmp(table->s->db, db))
{
mysql_lock_remove(thd, thd->locked_tables,table);
table->file->close();
@@ -1141,7 +1362,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
next=table->next;
if (!tables || (!db_stat && reopen_table(table,1)))
{
- my_error(ER_CANT_REOPEN_TABLE,MYF(0),table->table_name);
+ my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
VOID(hash_delete(&open_cache,(byte*) table));
error=1;
}
@@ -1153,7 +1374,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
*tables_ptr++= table; // need new lock on this
if (in_refresh)
{
- table->version=0;
+ table->s->version=0;
table->locked_by_flush=0;
}
}
@@ -1192,11 +1413,11 @@ void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
bool found=send_refresh;
for (; table ; table=table->next)
{
- if (table->version != refresh_version)
+ if (table->s->version != refresh_version)
{
found=1;
if (!abort_locks) // If not from flush tables
- table->version = refresh_version; // Let other threads use table
+ table->s->version= refresh_version; // Let other threads use table
if (table->db_stat)
{
if (abort_locks)
@@ -1226,8 +1447,8 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
{
do
{
- char *key= table->table_cache_key;
- uint key_length=table->key_length;
+ char *key= table->s->table_cache_key;
+ uint key_length= table->s->key_length;
for (TABLE *search=(TABLE*) hash_search(&open_cache,
(byte*) key,key_length) ;
search ;
@@ -1235,7 +1456,7 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
{
if (search->locked_by_flush ||
search->locked_by_name && wait_for_name_lock ||
- search->db_stat && search->version < refresh_version)
+ search->db_stat && search->s->version < refresh_version)
return 1; // Table is used
}
} while ((table=table->next));
@@ -1282,11 +1503,11 @@ bool drop_locked_tables(THD *thd,const char *db, const char *table_name)
TABLE *table,*next,**prev;
bool found=0;
prev= &thd->open_tables;
- for (table=thd->open_tables; table ; table=next)
+ for (table= thd->open_tables; table ; table=next)
{
next=table->next;
- if (!strcmp(table->real_name,table_name) &&
- !strcmp(table->table_cache_key,db))
+ if (!strcmp(table->s->table_name, table_name) &&
+ !strcmp(table->s->db, db))
{
mysql_lock_remove(thd, thd->locked_tables,table);
VOID(hash_delete(&open_cache,(byte*) table));
@@ -1321,8 +1542,8 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
TABLE *table;
for (table= thd->open_tables; table ; table= table->next)
{
- if (!strcmp(table->real_name,table_name) &&
- !strcmp(table->table_cache_key,db))
+ if (!strcmp(table->s->table_name,table_name) &&
+ !strcmp(table->s->db, db))
{
mysql_lock_abort(thd,table);
break;
@@ -1341,6 +1562,8 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
db Database name
name Table name
alias Alias name
+ table_desc TABLE_LIST descriptor (used with views)
+ mem_root temporary mem_root for parsing
NOTES
Extra argument for open is taken from thd->open_options
@@ -1349,9 +1572,9 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
0 ok
# Error
*/
-
static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
- const char *name, const char *alias)
+ const char *name, const char *alias,
+ TABLE_LIST *table_desc, MEM_ROOT *mem_root)
{
char path[FN_REFLEN];
int error;
@@ -1359,26 +1582,36 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
DBUG_ENTER("open_unireg_entry");
strxmov(path, mysql_data_home, "/", db, "/", name, NullS);
- while (openfrm(path,alias,
- (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
- HA_TRY_READ_ONLY),
- READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
- thd->open_options, entry))
+ while ((error= openfrm(thd, path, alias,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
+ HA_GET_INDEX | HA_TRY_READ_ONLY |
+ NO_ERR_ON_NEW_FRM),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ thd->open_options, entry)) &&
+ (error != 5 ||
+ (fn_format(path, path, 0, reg_ext, MY_UNPACK_FILENAME),
+ open_new_frm(path, alias, db, name,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
+ HA_GET_INDEX | HA_TRY_READ_ONLY),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ thd->open_options, entry, table_desc, mem_root))))
+
{
- if (!entry->crashed)
+ if (!entry->s || !entry->s->crashed)
{
/*
- Frm file could not be found on disk
- Since it does not exist, no one can be using it
- LOCK_open has been locked to protect from someone else
- trying to discover the table at the same time.
+ Frm file could not be found on disk
+ Since it does not exist, no one can be using it
+ LOCK_open has been locked to protect from someone else
+ trying to discover the table at the same time.
*/
if (discover_retry_count++ != 0)
goto err;
if (ha_create_table_from_engine(thd, db, name, TRUE) != 0)
goto err;
- thd->clear_error(); // Clear error message
+ mysql_reset_errors(thd, 1); // Clear warnings
+ thd->clear_error(); // Clear error message
continue;
}
@@ -1386,7 +1619,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
TABLE_LIST table_list;
bzero((char*) &table_list, sizeof(table_list)); // just for safe
table_list.db=(char*) db;
- table_list.real_name=(char*) name;
+ table_list.table_name=(char*) name;
safe_mutex_assert_owner(&LOCK_open);
@@ -1405,7 +1638,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
pthread_mutex_unlock(&LOCK_open);
thd->clear_error(); // Clear error message
error= 0;
- if (openfrm(path,alias,
+ if (openfrm(thd, path, alias,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
HA_TRY_READ_ONLY),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
@@ -1430,6 +1663,13 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
goto err;
break;
}
+
+ if (error == 5)
+ DBUG_RETURN(0); // we have just opened VIEW
+
+ if (Table_triggers_list::check_n_load(thd, db, name, entry))
+ goto err;
+
/*
If we are here, there was no fatal error (but error may be still
unitialized).
@@ -1458,6 +1698,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
*/
sql_print_error("When opening HEAP table, could not allocate \
memory to write 'DELETE FROM `%s`.`%s`' to the binary log",db,name);
+ delete entry->triggers;
if (entry->file)
closefrm(entry);
goto err;
@@ -1466,6 +1707,14 @@ memory to write 'DELETE FROM `%s`.`%s`' to the binary log",db,name);
}
DBUG_RETURN(0);
err:
+ /* Hide "Table doesn't exist" errors if table belong to view */
+ if (thd->net.last_errno == ER_NO_SUCH_TABLE &&
+ table_desc && table_desc->belong_to_view)
+ {
+ TABLE_LIST * view= table_desc->belong_to_view;
+ thd->clear_error();
+ my_error(ER_VIEW_INVALID, MYF(0), view->view_db.str, view->view_name.str);
+ }
DBUG_RETURN(1);
}
@@ -1475,26 +1724,88 @@ err:
SYNOPSIS
open_tables()
thd - thread handler
- start - list of tables
+ start - list of tables in/out
counter - number of opened tables will be return using this parameter
+ NOTE
+ Unless we are already in prelocked mode, this function will also precache
+ all SP/SFs explicitly or implicitly (via views and triggers) used by the
+ query and add tables needed for their execution to table list. If resulting
+ tables list will be non empty it will mark query as requiring precaching.
+ Prelocked mode will be enabled for such query during lock_tables() call.
+
+ If query for which we are opening tables is already marked as requiring
+ prelocking it won't do such precaching and will simply reuse table list
+ which is already built.
+
RETURN
0 - OK
-1 - error
*/
-int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
+int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
{
TABLE_LIST *tables;
bool refresh;
int result=0;
+ MEM_ROOT new_frm_mem;
+ /* Also used for indicating that prelocking is need */
+ TABLE_LIST **query_tables_last_own;
DBUG_ENTER("open_tables");
+ /*
+ temporary mem_root for new .frm parsing.
+ TODO: variables for size
+ */
+ init_alloc_root(&new_frm_mem, 8024, 8024);
thd->current_tablenr= 0;
restart:
*counter= 0;
+ query_tables_last_own= 0;
thd->proc_info="Opening tables";
- for (tables=start ; tables ; tables=tables->next)
+
+ /*
+ If we are not already executing prelocked statement and don't have
+ statement for which table list for prelocking is already built, let
+ us cache routines and try to build such table list.
+
+ NOTE: If we want queries with functions to work under explicit
+ LOCK TABLES we have to additionaly lock mysql.proc table in it.
+ At least until Monty will fix SP loading :)
+
+ NOTE: We can't delay prelocking until we will met some sub-statement
+ which really uses tables, since this will imply that we have to restore
+ its table list to be able execute it in some other context.
+ And current views implementation assumes that view tables are added to
+ global table list only once during PS preparing/first SP execution.
+ Also locking at earlier stage is probably faster altough may decrease
+ concurrency a bit.
+
+ NOTE: We will mark statement as requiring prelocking only if we will
+ have non empty table list. But this does not guarantee that in prelocked
+ mode we will have some locked tables, because queries which use only
+ derived/information schema tables and views possible. Thus "counter"
+ may be still zero for prelocked statement...
+ */
+ if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
+ (thd->lex->spfuns.records || thd->lex->spprocs.records))
+ {
+ TABLE_LIST **save_query_tables_last;
+
+ sp_cache_routines(thd, thd->lex);
+ 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) ||
+ *start)
+ {
+ query_tables_last_own= save_query_tables_last;
+ *start= thd->lex->query_tables;
+ }
+ }
+
+ for (tables= *start; tables ;tables= tables->next_global)
{
/*
Ignore placeholders for derived tables. After derived tables
@@ -1502,13 +1813,42 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
*/
if (tables->derived)
continue;
+ if (tables->schema_table)
+ {
+ if (!mysql_schema_table(thd, thd->lex, tables))
+ continue;
+ DBUG_RETURN(-1);
+ }
(*counter)++;
if (!tables->table &&
- !(tables->table= open_table(thd,
- tables->db,
- tables->real_name,
- tables->alias, &refresh)))
+ !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh)))
{
+ free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
+ if (tables->view)
+ {
+ /* VIEW placeholder */
+ (*counter)--;
+ /*
+ Again if needed we have to get cache all routines used by this view
+ 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))
+ {
+ // 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);
+ }
+ /* Cleanup hashes because destructo for this LEX is never called */
+ hash_free(&tables->view->spfuns);
+ hash_free(&tables->view->spprocs);
+ continue;
+ }
+
if (refresh) // Refresh in progress
{
/* close all 'old' tables used by this thread */
@@ -1518,12 +1858,17 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
thd->version=refresh_version;
TABLE **prev_table= &thd->open_tables;
bool found=0;
- for (TABLE_LIST *tmp=start ; tmp ; tmp=tmp->next)
+ /*
+ QQ: What we should do if we have started building of table list
+ for prelocking ??? Probably throw it away ? But before we should
+ mark all temporary tables as free? How about locked ?
+ */
+ for (TABLE_LIST *tmp= *start; tmp; tmp= tmp->next_global)
{
/* Close normal (not temporary) changed tables */
- if (tmp->table && ! tmp->table->tmp_table)
+ if (tmp->table && ! tmp->table->s->tmp_table)
{
- if (tmp->table->version != refresh_version ||
+ if (tmp->table->s->version != refresh_version ||
! tmp->table->db_stat)
{
VOID(hash_delete(&open_cache,(byte*) tmp->table));
@@ -1546,11 +1891,39 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
result= -1; // Fatal error
break;
}
+ else
+ {
+ /*
+ If we are not already in prelocked mode and extended table list is not
+ yet built and we have trigger for table being opened then we should
+ cache all routines used by its triggers and add their tables to
+ 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 &&
+ tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ if (!query_tables_last_own)
+ query_tables_last_own= thd->lex->query_tables_last;
+ }
+ free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
+ }
+
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
tables->table->reginfo.lock_type=tables->lock_type;
tables->table->grant= tables->grant;
}
thd->proc_info=0;
+ free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
+
+ if (query_tables_last_own)
+ thd->lex->mark_as_requiring_prelocking(query_tables_last_own);
+
DBUG_RETURN(result);
}
@@ -1578,9 +1951,7 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ &&
(int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ)
{
- my_printf_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,
- ER(ER_TABLE_NOT_LOCKED_FOR_WRITE),
- MYF(0),table->table_name);
+ my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),table->alias);
DBUG_RETURN(1);
}
if ((error=table->file->start_stmt(thd)))
@@ -1601,6 +1972,11 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
table_list Table to open is first table in this list
lock_type Lock to use for open
+ NOTE
+ This function don't do anything like SP/SF/views/triggers analysis done
+ in open_tables(). It is intended for opening of only one concrete table.
+ And used only in special contexts.
+
RETURN VALUES
table Opened table
0 Error
@@ -1618,9 +1994,11 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
thd->proc_info="Opening table";
thd->current_tablenr= 0;
- while (!(table=open_table(thd,table_list->db,
- table_list->real_name,table_list->alias,
- &refresh)) && refresh) ;
+ /* 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)) &&
+ refresh)
+ ;
if (table)
{
@@ -1666,14 +2044,14 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
-1 - error
NOTE
- The lock will automaticly be freed by close_thread_tables()
+ The lock will automaticaly be freed by close_thread_tables()
*/
int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("simple_open_n_lock_tables");
uint counter;
- if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
+ if (open_tables(thd, &tables, &counter) || lock_tables(thd, tables, counter))
DBUG_RETURN(-1); /* purecov: inspected */
DBUG_RETURN(0);
}
@@ -1689,21 +2067,25 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
tables - list of tables for open&locking
RETURN
- 0 - ok
- -1 - error
+ FALSE - ok
+ TRUE - error
NOTE
- The lock will automaticly be freed by close_thread_tables()
+ The lock will automaticaly be freed by close_thread_tables()
*/
-int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
+bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
{
- DBUG_ENTER("open_and_lock_tables");
uint counter;
- if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
- DBUG_RETURN(-1); /* purecov: inspected */
- relink_tables_for_derived(thd);
- DBUG_RETURN(mysql_handle_derived(thd->lex));
+ DBUG_ENTER("open_and_lock_tables");
+ if (open_tables(thd, &tables, &counter) ||
+ lock_tables(thd, tables, counter) ||
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
+ (thd->fill_derived_tables() &&
+ mysql_handle_derived(thd->lex, &mysql_derived_filling)))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ relink_tables_for_multidelete(thd);
+ DBUG_RETURN(0);
}
@@ -1724,40 +2106,66 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
data from the tables.
*/
-int open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
+bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
{
uint counter;
DBUG_ENTER("open_normal_and_derived_tables");
- if (open_tables(thd, tables, &counter))
- DBUG_RETURN(-1); /* purecov: inspected */
- relink_tables_for_derived(thd);
- DBUG_RETURN(mysql_handle_derived(thd->lex));
+ DBUG_ASSERT(!thd->fill_derived_tables());
+ if (open_tables(thd, &tables, &counter) ||
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ relink_tables_for_multidelete(thd); // Not really needed, but
+ DBUG_RETURN(0);
}
/*
Let us propagate pointers to open tables from global table list
- to table lists in particular selects if needed.
+ to table lists for multi-delete
*/
-void relink_tables_for_derived(THD *thd)
+static void relink_tables_for_multidelete(THD *thd)
{
- if (thd->lex->all_selects_list->next_select_in_list() ||
- thd->lex->time_zone_tables_used)
+ if (thd->lex->all_selects_list->next_select_in_list())
{
for (SELECT_LEX *sl= thd->lex->all_selects_list;
sl;
sl= sl->next_select_in_list())
+ {
for (TABLE_LIST *cursor= (TABLE_LIST *) sl->table_list.first;
cursor;
- cursor=cursor->next)
- if (cursor->table_list)
- cursor->table= cursor->table_list->table;
+ cursor=cursor->next_local)
+ {
+ if (cursor->correspondent_table)
+ cursor->table= cursor->correspondent_table->table;
+ }
+ }
}
}
/*
+ Mark all real tables in the list as free for reuse.
+
+ SYNOPSIS
+ mark_real_tables_as_free_for_reuse()
+ thd - thread context
+ table - head of the list of tables
+
+ DESCRIPTION
+ Marks all real tables in the list (i.e. not views, derived
+ or schema tables) as free for reuse.
+*/
+
+static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
+{
+ for (; table; table= table->next_global)
+ if (!table->placeholder() && !table->schema_table)
+ table->table->query_id= 0;
+}
+
+
+/*
Lock all tables in list
SYNOPSIS
@@ -1771,6 +2179,10 @@ void relink_tables_for_derived(THD *thd)
handling thr_lock gives us. You most always get all needed locks at
once.
+ If query for which we are calling this function marked as requring
+ prelocking, this function will do implicit LOCK TABLES and change
+ thd::prelocked_mode accordingly.
+
RETURN VALUES
0 ok
-1 Error
@@ -1779,36 +2191,125 @@ void relink_tables_for_derived(THD *thd)
int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
{
TABLE_LIST *table;
+
+ DBUG_ENTER("lock_tables");
+ /*
+ We can't meet statement requiring prelocking if we already
+ in prelocked mode.
+ */
+ DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking());
+ /*
+ If statement requires prelocking then it has non-empty table list.
+ So it is safe to shortcut.
+ */
+ DBUG_ASSERT(!thd->lex->requires_prelocking() || tables);
+
if (!tables)
- return 0;
+ DBUG_RETURN(0);
- if (!thd->locked_tables)
+ /*
+ We need this extra check for thd->prelocked_mode because we want to avoid
+ attempts to lock tables in substatements. Checking for thd->locked_tables
+ is not enough in some situations. For example for SP containing
+ "drop table t3; create temporary t3 ..; insert into t3 ...;"
+ thd->locked_tables may be 0 after drop tables, and without this extra
+ check insert will try to lock temporary table t3, that will lead
+ to memory leak...
+ */
+ if (!thd->locked_tables && !thd->prelocked_mode)
{
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
TABLE **start,**ptr;
- if (!(ptr=start=(TABLE**) sql_alloc(sizeof(TABLE*)*count)))
- return -1;
- for (table = tables ; table ; table=table->next)
+
+ if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count)))
+ DBUG_RETURN(-1);
+ for (table= tables; table; table= table->next_global)
{
- if (!table->derived)
+ if (!table->placeholder() && !table->schema_table)
*(ptr++)= table->table;
}
+
+ /* We have to emulate LOCK TABLES if we are statement needs prelocking. */
+ if (thd->lex->requires_prelocking())
+ {
+ thd->in_lock_tables=1;
+ thd->options|= OPTION_TABLE_LOCK;
+ }
+
if (!(thd->lock=mysql_lock_tables(thd,start, (uint) (ptr - start))))
- return -1; /* purecov: inspected */
+ {
+ if (thd->lex->requires_prelocking())
+ {
+ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+ thd->in_lock_tables=0;
+ }
+ DBUG_RETURN(-1);
+ }
+ if (thd->lex->requires_prelocking() &&
+ thd->lex->sql_command != SQLCOM_LOCK_TABLES)
+ {
+ TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
+ /*
+ We just have done implicit LOCK TABLES, and now we have
+ to emulate first open_and_lock_tables() after it.
+
+ Note that "LOCK TABLES" can also be marked as requiring prelocking
+ (e.g. if one locks view which uses functions). We should not emulate
+ such open_and_lock_tables() in this case. We also should not set
+ THD::prelocked_mode or first close_thread_tables() call will do
+ "UNLOCK TABLES".
+ */
+ thd->locked_tables= thd->lock;
+ thd->lock= 0;
+ thd->in_lock_tables=0;
+
+ for (table= tables; table != first_not_own; table= table->next_global)
+ {
+ if (!table->placeholder() && !table->schema_table)
+ {
+ table->table->query_id= thd->query_id;
+ if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
+ {
+ ha_rollback_stmt(thd);
+ mysql_unlock_tables(thd, thd->locked_tables);
+ thd->locked_tables= 0;
+ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+ /*
+ Let us mark all tables which don't belong to the statement itself,
+ and was marked as occupied during open_tables() as free for reuse.
+ */
+ mark_real_tables_as_free_for_reuse(first_not_own);
+ thd->prelocked_mode= PRELOCKED;
+ }
}
else
{
- for (table = tables ; table ; table=table->next)
+ TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
+ for (table= tables; table != first_not_own; table= table->next_global)
{
- if (!table->derived &&
+ if (!table->placeholder() && !table->schema_table &&
check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
ha_rollback_stmt(thd);
- return -1;
+ DBUG_RETURN(-1);
}
}
+ /*
+ If we are under explicit LOCK TABLES and our statement requires
+ prelocking, we should mark all "additional" tables as free for use
+ and enter prelocked mode.
+ */
+ if (thd->lex->requires_prelocking())
+ {
+ mark_real_tables_as_free_for_reuse(first_not_own);
+ thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES;
+ }
}
- return 0;
+ DBUG_RETURN(0);
}
@@ -1822,6 +2323,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list)
{
TABLE *tmp_table;
+ TABLE_SHARE *share;
DBUG_ENTER("open_temporary_table");
/*
@@ -1836,7 +2338,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
MYF(MY_WME))))
DBUG_RETURN(0); /* purecov: inspected */
- if (openfrm(path, table_name,
+ if (openfrm(thd, path, table_name,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
ha_open_options,
@@ -1846,21 +2348,22 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
DBUG_RETURN(0);
}
+ share= tmp_table->s;
tmp_table->reginfo.lock_type=TL_WRITE; // Simulate locked
- tmp_table->in_use= thd;
- tmp_table->tmp_table = (tmp_table->file->has_transactions() ?
- TRANSACTIONAL_TMP_TABLE : TMP_TABLE);
- tmp_table->table_cache_key=(char*) (tmp_table+1);
- tmp_table->key_length= (uint) (strmov((tmp_table->real_name=
- strmov(tmp_table->table_cache_key,db)
- +1), table_name)
- - tmp_table->table_cache_key)+1;
- int4store(tmp_table->table_cache_key + tmp_table->key_length,
- thd->server_id);
- tmp_table->key_length += 4;
- int4store(tmp_table->table_cache_key + tmp_table->key_length,
+ share->tmp_table= (tmp_table->file->has_transactions() ?
+ TRANSACTIONAL_TMP_TABLE : TMP_TABLE);
+ share->table_cache_key= (char*) (tmp_table+1);
+ share->db= share->table_cache_key;
+ share->key_length= (uint) (strmov(((char*) (share->table_name=
+ strmov(share->table_cache_key,
+ db)+1)),
+ table_name) -
+ share->table_cache_key) +1;
+ int4store(share->table_cache_key + share->key_length, thd->server_id);
+ share->key_length+= 4;
+ int4store(share->table_cache_key + share->key_length,
thd->variables.pseudo_thread_id);
- tmp_table->key_length += 4;
+ share->key_length+= 4;
if (link_in_list)
{
@@ -1900,23 +2403,167 @@ bool rm_temporary_table(enum db_type base, char *path)
** return unique field
******************************************************************************/
+/* Special Field pointers for find_field_in_tables returning */
+Field *not_found_field= (Field*) 0x1;
+Field *view_ref_found= (Field*) 0x2;
+
#define WRONG_GRANT (Field*) -1
-Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
- bool check_grants, bool allow_rowid,
- uint *cached_field_index_ptr)
+
+/*
+ Find field in table or view
+
+ SYNOPSIS
+ find_field_in_table()
+ thd thread handler
+ table_list table where to find
+ 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
+ passed using this reference (return
+ view_ref_found)
+ check_grants_table do check columns grants for table?
+ check_grants_view do check columns grants for view?
+ allow_rowid do allow finding of "_rowid" field?
+ cached_field_index_ptr cached position in field list (used to
+ speedup prepared tables field finding)
+ register_tree_change TRUE if ref is not stack variable and we
+ need register changes in item tree
+
+ RETURN
+ 0 field is not found
+ view_ref_found found value in VIEW (real result is in *ref)
+ # pointer to field
+*/
+
+Field *
+find_field_in_table(THD *thd, TABLE_LIST *table_list,
+ const char *name, const char *item_name,
+ uint length, Item **ref,
+ bool check_grants_table, bool check_grants_view,
+ bool allow_rowid,
+ uint *cached_field_index_ptr,
+ bool register_tree_change)
+{
+ Field *fld;
+ DBUG_ENTER("find_field_in_table");
+ DBUG_PRINT("enter", ("table: '%s' name: '%s' item name: '%s' ref 0x%lx",
+ table_list->alias, name, item_name, (ulong) ref));
+ if (table_list->field_translation)
+ {
+ 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 ++)
+ {
+ if (!my_strcasecmp(system_charset_info, trans[i].name, name))
+ {
+ if (table_list->schema_table_reformed)
+ {
+ /*
+ Translation table items are always Item_fields
+ and fixed already('mysql_schema_table' function).
+ So we can return ->field. It is used only for
+ 'show & where' commands.
+ */
+ DBUG_RETURN(((Item_field*) (trans[i].item))->field);
+ }
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_grants_view &&
+ check_grant_column(thd, &table_list->grant,
+ table_list->view_db.str,
+ table_list->view_name.str,
+ name, length))
+ DBUG_RETURN(WRONG_GRANT);
+#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_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((Field*) view_ref_found);
+ }
+ }
+ DBUG_RETURN(0);
+ }
+ fld= find_field_in_real_table(thd, table_list->table, name, length,
+ check_grants_table, allow_rowid,
+ cached_field_index_ptr);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* check for views with temporary table algorithm */
+ if (check_grants_view && table_list->view &&
+ fld && fld != WRONG_GRANT &&
+ check_grant_column(thd, &table_list->grant,
+ table_list->view_db.str,
+ table_list->view_name.str,
+ name, length))
+ {
+ DBUG_RETURN(WRONG_GRANT);
+ }
+#endif
+ DBUG_RETURN(fld);
+}
+
+
+/*
+ Find field in table
+
+ SYNOPSIS
+ find_field_in_real_table()
+ thd thread handler
+ table_list table where to find
+ name name of field
+ length length of name
+ check_grants do check columns grants?
+ allow_rowid do allow finding of "_rowid" field?
+ cached_field_index_ptr cached position in field list (used to
+ speedup prepared tables field finding)
+
+ RETURN
+ 0 field is not found
+ # pointer to field
+*/
+
+Field *find_field_in_real_table(THD *thd, TABLE *table,
+ const char *name, uint length,
+ bool check_grants, bool allow_rowid,
+ uint *cached_field_index_ptr)
{
Field **field_ptr, *field;
uint cached_field_index= *cached_field_index_ptr;
/* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
- if (cached_field_index < table->fields &&
+ if (cached_field_index < table->s->fields &&
!my_strcasecmp(system_charset_info,
table->field[cached_field_index]->field_name, name))
field_ptr= table->field + cached_field_index;
- else if (table->name_hash.records)
- field_ptr= (Field**)hash_search(&table->name_hash,(byte*) name,
- length);
+ else if (table->s->name_hash.records)
+ field_ptr= (Field**) hash_search(&table->s->name_hash, (byte*) name,
+ length);
else
{
if (!(field_ptr= table->field))
@@ -1951,7 +2598,9 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
thd->dupp_field=field;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_grants && check_grant_column(thd,table,name,length))
+ if (check_grants && check_grant_column(thd, &table->grant,
+ table->s->db,
+ table->s->table_name, name, length))
return WRONG_GRANT;
#endif
return field;
@@ -1965,26 +2614,33 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
find_field_in_tables()
thd Pointer to current thread structure
item Field item that should be found
- tables Tables for scanning
- where Table where field found will be returned via
- this parameter
- report_error If FALSE then do not report error if item not found
- and return not_found_field
+ 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
RETURN VALUES
- 0 Field is not found or field is not unique- error
- message is reported
- not_found_field Function was called with report_error == FALSE and
- field was not found. no error message reported.
- found field
+ 0 If error: the found field is not unique, or there are
+ no sufficient access priviliges for the found field,
+ or the field is qualified with non-existing table.
+ not_found_field The function was called with report_error ==
+ (IGNORE_ERRORS || IGNORE_EXCEPT_NON_UNIQUE) and a
+ field was not found.
+ view_ref_found View field is found, item passed through ref parameter
+ found field If a item was resolved to some field
*/
-// Special Field pointer for find_field_in_tables returning
-const Field *not_found_field= (Field*) 0x1;
-
Field *
find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
- TABLE_LIST **where, bool report_error)
+ Item **ref, find_item_error_report_type report_error,
+ bool check_privileges)
{
Field *found=0;
const char *db=item->db_name;
@@ -1997,24 +2653,42 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
if (item->cached_table)
{
/*
- This shortcut is used by prepared statements. We assuming that
- TABLE_LIST *tables is not changed during query execution (which
- is true for all queries except RENAME but luckily RENAME doesn't
+ This shortcut is used by prepared statements. We assuming that
+ TABLE_LIST *tables is not changed during query execution (which
+ is true for all queries except RENAME but luckily RENAME doesn't
use fields...) so we can rely on reusing pointer to its member.
- With this optimisation we also miss case when addition of one more
- field makes some prepared query ambiguous and so erronous, but we
+ With this optimization we also miss case when addition of one more
+ field makes some prepared query ambiguous and so erroneous, but we
accept this trade off.
*/
- found= find_field_in_table(thd, item->cached_table->table, name, length,
- test(item->cached_table->
- table->grant.want_privilege),
- 1, &(item->cached_field_index));
+ if (item->cached_table->table && !item->cached_table->view)
+ {
+ found= find_field_in_real_table(thd, item->cached_table->table,
+ name, length,
+ test(item->cached_table->
+ table->grant.want_privilege) &&
+ check_privileges,
+ 1, &(item->cached_field_index));
+ }
+ else
+ {
+ TABLE_LIST *table= item->cached_table;
+ found= find_field_in_table(thd, table, name, item->name, length,
+ ref,
+ (table->table &&
+ test(table->table->grant.
+ want_privilege) &&
+ check_privileges),
+ (test(table->grant.want_privilege) &&
+ check_privileges),
+ 1, &(item->cached_field_index),
+ TRUE);
+ }
if (found)
{
- (*where)= tables;
if (found == WRONG_GRANT)
- return (Field*) 0;
+ return (Field*) 0;
return found;
}
}
@@ -2022,7 +2696,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
if (db && lower_case_table_names)
{
/*
- convert database to lower case for comparision.
+ convert database to lower case for comparison.
We can't do this in Item_field as this would change the
'name' of the item which may be used in the select list
*/
@@ -2034,19 +2708,27 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
if (table_name && table_name[0])
{ /* Qualified field */
bool found_table=0;
- for (; tables ; tables=tables->next)
+ for (; tables; tables= tables->next_local)
{
+ /* TODO; Ensure that db and tables->db always points to something ! */
if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) &&
- (!db || !tables->db || !tables->db[0] || !strcmp(db,tables->db)))
+ (!db || !db[0] || !tables->db || !tables->db[0] ||
+ !strcmp(db,tables->db)))
{
found_table=1;
- Field *find=find_field_in_table(thd,tables->table,name,length,
- test(tables->table->grant.
- want_privilege),
- 1, &(item->cached_field_index));
+ Field *find= find_field_in_table(thd, tables, name, item->name,
+ length, ref,
+ (tables->table &&
+ test(tables->table->grant.
+ want_privilege) &&
+ check_privileges),
+ (test(tables->grant.want_privilege) &&
+ check_privileges),
+ 1, &(item->cached_field_index),
+ TRUE);
if (find)
{
- (*where)= item->cached_table= tables;
+ item->cached_table= tables;
if (!tables->cacheable_table)
item->cached_table= 0;
if (find == WRONG_GRANT)
@@ -2055,8 +2737,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
return find;
if (found)
{
- my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
- item->full_name(),thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == IGNORE_EXCEPT_NON_UNIQUE)
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ item->full_name(),thd->where);
return (Field*) 0;
}
found=find;
@@ -2065,7 +2749,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
}
if (found)
return found;
- if (!found_table && report_error)
+ if (!found_table && (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE))
{
char buff[NAME_LEN*2+1];
if (db && db[0])
@@ -2073,44 +2758,51 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
table_name=buff;
}
- my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
- table_name, thd->where);
+ my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where);
}
else
- if (report_error)
- my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
- item->full_name(),thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE)
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(),thd->where);
else
return (Field*) not_found_field;
return (Field*) 0;
}
- bool allow_rowid= tables && !tables->next; // Only one table
- for (; tables ; tables=tables->next)
+
+ bool allow_rowid= tables && !tables->next_local; // Only one table
+ for (; tables ; tables= tables->next_local)
{
- if (!tables->table)
+ if (!tables->table && !tables->ancestor)
{
- if (report_error)
- my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
- item->full_name(),thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE)
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(),thd->where);
return (Field*) not_found_field;
}
- Field *field=find_field_in_table(thd,tables->table,name,length,
- test(tables->table->grant.want_privilege),
- allow_rowid, &(item->cached_field_index));
+ 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);
if (field)
{
if (field == WRONG_GRANT)
return (Field*) 0;
- (*where)= item->cached_table= tables;
- if (!tables->cacheable_table)
- item->cached_table= 0;
+ item->cached_table= (!tables->cacheable_table || found) ? 0 : tables;
if (found)
{
if (!thd->where) // Returns first found
break;
- my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
- name,thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == IGNORE_EXCEPT_NON_UNIQUE)
+ my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
return (Field*) 0;
}
found=field;
@@ -2118,9 +2810,9 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
}
if (found)
return found;
- if (report_error)
- my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR),
- MYF(0), item->full_name(), thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE)
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where);
else
return (Field*) not_found_field;
return (Field*) 0;
@@ -2157,8 +2849,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
found field
*/
-// Special Item pointer for find_item_in_list returning
-const Item **not_found_item= (const Item**) 0x1;
+/* Special Item pointer to serve as a return value from find_item_in_list(). */
+Item **not_found_item= (Item**) 0x1;
Item **
@@ -2173,6 +2865,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
bool found_unaliased_non_uniq= 0;
uint unaliased_counter;
+ LINT_INIT(unaliased_counter); // Dependent on found_unaliased
+
*unaliased= FALSE;
if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM)
@@ -2232,8 +2926,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
unaliased names only and will have duplicate error anyway.
*/
if (report_error != IGNORE_ERRORS)
- my_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR),
- MYF(0), find->full_name(), current_thd->where);
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
return (Item**) 0;
}
found_unaliased= li.ref();
@@ -2257,8 +2951,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
if ((*found)->eq(item, 0))
continue; // Same field twice
if (report_error != IGNORE_ERRORS)
- my_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR),
- MYF(0), find->full_name(), current_thd->where);
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
return (Item**) 0;
}
found= li.ref();
@@ -2301,8 +2995,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
if (found_unaliased_non_uniq)
{
if (report_error != IGNORE_ERRORS)
- my_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR), MYF(0),
- find->full_name(), current_thd->where);
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
return (Item **) 0;
}
if (found_unaliased)
@@ -2317,8 +3011,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
if (report_error != REPORT_EXCEPT_NOT_FOUND)
{
if (report_error == REPORT_ALL_ERRORS)
- my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0),
- find->full_name(), current_thd->where);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
return (Item **) 0;
}
else
@@ -2333,27 +3027,29 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list,
uint wild_num)
{
- DBUG_ENTER("setup_wild");
if (!wild_num)
- DBUG_RETURN(0);
+ return(0);
- reg2 Item *item;
+ Item *item;
List_iterator<Item> it(fields);
Item_arena *arena, backup;
+ DBUG_ENTER("setup_wild");
+
/*
- If we are in preparing prepared statement phase then we have change
- temporary mem_root to statement mem root to save changes of SELECT list
+ Don't use arena if we are not in prepared statements or stored procedures
+ For PS/SP we have to use arena to remember the changes
*/
arena= thd->change_arena_if_needed(&backup);
while (wild_num && (item= it++))
- {
+ {
if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field_name &&
((Item_field*) item)->field_name[0] == '*' &&
!((Item_field*) item)->field)
{
uint elem= fields.elements;
+ bool any_privileges= ((Item_field *) item)->any_privileges;
Item_subselect *subsel= thd->lex->current_select->master_unit()->item;
if (subsel &&
subsel->substype() == Item_subselect::EXISTS_SUBS)
@@ -2366,9 +3062,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,
- ((Item_field*) item)->table_name, &it))
+ ((Item_field*) item)->table_name, &it,
+ any_privileges, arena != 0))
{
- if (arena)
+ if (arena)
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(-1);
}
@@ -2385,7 +3082,14 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
}
}
if (arena)
+ {
+ /* make * substituting permanent */
+ SELECT_LEX *select_lex= thd->lex->current_select;
+ select_lex->with_wild= 0;
+ select_lex->item_list= fields;
+
thd->restore_backup_item_arena(arena, &backup);
+ }
DBUG_RETURN(0);
}
@@ -2393,9 +3097,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
** Check that all given fields exists and fill struct with current data
****************************************************************************/
-int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
- List<Item> &fields, bool set_query_id,
- List<Item> *sum_func_list, bool allow_sum_func)
+bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+ List<Item> &fields, bool set_query_id,
+ List<Item> *sum_func_list, bool allow_sum_func)
{
reg2 Item *item;
List_iterator<Item> it(fields);
@@ -2424,7 +3128,9 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
{
if (!item->fixed && item->fix_fields(thd, tables, it.ref()) ||
(item= *(it.ref()))->check_cols(1))
- DBUG_RETURN(-1); /* purecov: inspected */
+ {
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ }
if (ref)
*(ref++)= item;
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
@@ -2437,36 +3143,91 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
/*
+ make list of leaves of join table tree
+
+ SYNOPSIS
+ make_leaves_list()
+ list pointer to pointer on list first element
+ tables table list
+
+ RETURN pointer on pointer to next_leaf of last element
+*/
+
+TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
+{
+ for (TABLE_LIST *table= tables; table; table= table->next_local)
+ {
+ if (table->view && !table->table)
+ {
+ /* it is for multi table views only, check it */
+ DBUG_ASSERT(table->ancestor->next_local != 0);
+ list= make_leaves_list(list, table->ancestor);
+ }
+ else
+ {
+ *list= table;
+ list= &table->next_leaf;
+ }
+ }
+ return list;
+}
+
+/*
prepare tables
SYNOPSIS
setup_tables()
- tables table list
-
+ thd Thread handler
+ tables Table list
+ conds Condition of current SELECT (can be changed by VIEW)
+ leaves List of join table leaves list
+ refresh It is onle refresh for subquery
+ select_insert It is SELECT ... INSERT command
- NOTE
- Remap table numbers if INSERT ... SELECT
- Check also that the 'used keys' and 'ignored keys' exists and set up the
- table structure accordingly
+ NOTE
+ Check also that the 'used keys' and 'ignored keys' exists and set up the
+ table structure accordingly
+ Create leaf tables list
- This has to be called for all tables that are used by items, as otherwise
- table->map is not set and all Item_field will be regarded as const items.
+ This has to be called for all tables that are used by items, as otherwise
+ table->map is not set and all Item_field will be regarded as const items.
- RETURN
- 0 ok; In this case *map will includes the choosed index
- 1 error
+ RETURN
+ FALSE ok; In this case *map will includes the choosed index
+ TRUE error
*/
-bool setup_tables(TABLE_LIST *tables)
+bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
+ TABLE_LIST **leaves, bool refresh, bool select_insert)
{
+ uint tablenr= 0;
DBUG_ENTER("setup_tables");
- uint tablenr=0;
- for (TABLE_LIST *table_list=tables ; table_list ;
- table_list=table_list->next,tablenr++)
+ /*
+ this is used for INSERT ... SELECT.
+ For select we setup tables except first (and its underlying tables)
+ */
+ TABLE_LIST *first_select_table= (select_insert ?
+ tables->next_local:
+ 0);
+ if (!(*leaves))
+ make_leaves_list(leaves, tables);
+
+ for (TABLE_LIST *table_list= *leaves;
+ table_list;
+ table_list= table_list->next_leaf, tablenr++)
{
TABLE *table= table_list->table;
+ if (first_select_table &&
+ (table_list->belong_to_view ?
+ table_list->belong_to_view :
+ table_list) == first_select_table)
+ {
+ /* new counting for SELECT of INSERT ... SELECT command */
+ first_select_table= 0;
+ tablenr= 0;
+ }
setup_table_map(table, table_list, tablenr);
- table->used_keys= table->keys_for_keyread;
+ table->used_keys= table->s->keys_for_keyread;
if (table_list->use_index)
{
key_map map;
@@ -2490,6 +3251,18 @@ bool setup_tables(TABLE_LIST *tables)
my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES);
DBUG_RETURN(1);
}
+ if (!refresh)
+ {
+ for (TABLE_LIST *table_list= tables;
+ 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);
+ }
+ }
DBUG_RETURN(0);
}
@@ -2518,11 +3291,13 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
map->clear_all();
while ((name=it++))
{
- if ((pos= find_type(&table->keynames, name->ptr(), name->length(), 1)) <=
- 0)
+ if (table->s->keynames.type_names == 0 ||
+ (pos= find_type(&table->s->keynames, name->ptr(),
+ name->length(), 1)) <=
+ 0)
{
- my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
- table->real_name);
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0),
+ name->c_ptr(), table->s->table_name);
map->set_all();
return 1;
}
@@ -2532,17 +3307,37 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
}
-/****************************************************************************
- This just drops in all fields instead of current '*' field
- Returns pointer to last inserted field if ok
-****************************************************************************/
+/*
+ Drops in all fields instead of current '*' field
+
+ SYNOPSIS
+ insert_fields()
+ thd Thread handler
+ tables List of tables
+ 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 Item_arena
+ memory (made for SP/PS)
+ RETURN
+ 0 ok
+ 'it' is updated to point at last inserted
+ 1 error. Error message is generated but not sent to client
+*/
bool
-insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
- const char *table_name, List_iterator<Item> *it)
+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)
{
- char name_buff[NAME_LEN+1];
+ /* allocate variables on stack to avoid pool alloaction */
+ Field_iterator_table table_iter;
+ Field_iterator_view view_iter;
uint found;
+ char name_buff[NAME_LEN+1];
DBUG_ENTER("insert_fields");
if (db_name && lower_case_table_names)
@@ -2557,216 +3352,432 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
db_name= name_buff;
}
-
- found=0;
- for (; tables ; tables=tables->next)
+ found= 0;
+ for (; tables; tables= tables->next_local)
{
- TABLE *table=tables->table;
+ Field_iterator *iterator;
+ TABLE_LIST *natural_join_table;
+ Field *field;
+ TABLE_LIST *embedded;
+ 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) &&
(!db_name || !strcmp(tables->db,db_name))))
{
+ bool view;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Ensure that we have access right to all columns */
- if (!(table->grant.privilege & SELECT_ACL) &&
- check_grant_all_columns(thd,SELECT_ACL,table))
- DBUG_RETURN(-1);
+ if (!((table && (table->grant.privilege & SELECT_ACL) ||
+ tables->view && (tables->grant.privilege & SELECT_ACL))) &&
+ !any_privileges)
+ {
+ if (tables->view)
+ {
+ view_iter.set(tables);
+ if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant,
+ tables->view_db.str,
+ tables->view_name.str,
+ &view_iter))
+ goto err;
+ }
+ else if (!tables->schema_table)
+ {
+ DBUG_ASSERT(table != 0);
+ table_iter.set(tables);
+ if (check_grant_all_columns(thd, SELECT_ACL, &table->grant,
+ table->s->db,
+ table->s->table_name,
+ &table_iter))
+ goto err;
+ }
+ }
#endif
- Field **ptr=table->field,*field;
- TABLE *natural_join_table= 0;
+ 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;
- thd->used_tables|=table->map;
- if (!table->outer_join &&
- tables->natural_join &&
- !tables->natural_join->table->outer_join)
- natural_join_table= tables->natural_join->table;
+ while ((embedding= embedded->embedding) &&
+ embedding->join_list->elements != 1)
+ {
+ TABLE_LIST *next;
+ List_iterator_fast<TABLE_LIST> it(embedding->nested_join->join_list);
+ last= it++;
+ while ((next= it++))
+ last= next;
+ if (last != tables)
+ break;
+ embedded= embedding;
+ }
- while ((field = *ptr++))
+ if (tables == last &&
+ !embedded->outer_join &&
+ embedded->natural_join &&
+ !embedded->natural_join->outer_join)
+ {
+ embedding= embedded->natural_join;
+ while (embedding->nested_join)
+ embedding= embedding->nested_join->join_list.head();
+ natural_join_table= embedding;
+ }
+ if (tables->field_translation)
{
+ iterator= &view_iter;
+ view= 1;
+ alias_used= my_strcasecmp(table_alias_charset,
+ tables->table_name, tables->alias);
+ }
+ else
+ {
+ iterator= &table_iter;
+ view= 0;
+ }
+ iterator->set(tables);
+
+ for (; !iterator->end_of_fields(); iterator->next())
+ {
+ Item *not_used_item;
uint not_used_field_index= NO_CACHED_FIELD_INDEX;
+ const char *field_name= iterator->name();
/* Skip duplicate field names if NATURAL JOIN is used */
if (!natural_join_table ||
- !find_field_in_table(thd, natural_join_table, field->field_name,
- strlen(field->field_name), 0, 0,
- &not_used_field_index))
+ !find_field_in_table(thd, natural_join_table, field_name,
+ field_name,
+ strlen(field_name), &not_used_item, 0, 0, 0,
+ &not_used_field_index, TRUE))
{
- Item_field *item= new Item_field(thd, field);
+ 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);
+ }
if (!found++)
(void) it->replace(item); // Replace '*'
else
it->after(item);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (any_privileges)
+ {
+ /*
+ In time of view creation MEGRGE algorithm for underlying
+ VIEWs can't be used => it should be Item_field
+ */
+ DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
+ Item_field *fld= (Item_field*)item;
+ char *db, *tab;
+ if (tables->view)
+ {
+ db= tables->view_db.str;
+ tab= tables->view_name.str;
+ }
+ else
+ {
+ db= tables->db;
+ tab= tables->table_name;
+ }
+ if (!tables->schema_table &&
+ !(fld->have_privileges= (get_column_grant(thd,
+ &table->grant,
+ db,
+ tab,
+ fld->field_name) &
+ VIEW_ANY_ACL)))
+ {
+ my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
+ "ANY",
+ thd->priv_user,
+ thd->host_or_ip,
+ fld->field_name,
+ tab);
+ goto err;
+ }
+ }
+#endif
+ }
+ if ((field= iterator->field()))
+ {
+ /*
+ Mark if field used before in this select.
+ Used by 'insert' to verify if a field name is used twice
+ */
+ if (field->query_id == thd->query_id)
+ thd->dupp_field=field;
+ field->query_id=thd->query_id;
+ table->used_keys.intersect(field->part_of_key);
+ }
+ else if (allocate_view_names &&
+ thd->lex->current_select->first_execution)
+ {
+ 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);
}
- /*
- Mark if field used before in this select.
- Used by 'insert' to verify if a field name is used twice
- */
- if (field->query_id == thd->query_id)
- thd->dupp_field=field;
- field->query_id=thd->query_id;
- table->used_keys.intersect(field->part_of_key);
}
- /* All fields are used */
- table->used_fields=table->fields;
+ /*
+ All fields are used in case if usual tables (in case of view used
+ fields marked in setup_tables during fix_fields of view columns
+ */
+ if (table)
+ table->used_fields= table->s->fields;
}
}
- if (!found)
- {
- if (!table_name)
- my_error(ER_NO_TABLES_USED,MYF(0));
- else
- my_error(ER_BAD_TABLE_ERROR,MYF(0),table_name);
- }
- DBUG_RETURN(!found);
+ if (found)
+ DBUG_RETURN(0);
+
+ if (!table_name)
+ my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0));
+ else
+ my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+err:
+#endif
+ DBUG_RETURN(1);
}
/*
-** Fix all conditions and outer join expressions
+ Fix all conditions and outer join expressions
+
+ 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,COND **conds)
+int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
{
- table_map not_null_tables= 0;
- Item_arena *arena= 0, backup;
+ SELECT_LEX *select_lex= thd->lex->current_select;
+ Item_arena *arena= thd->current_arena, backup;
+ bool save_wrapper= thd->lex->current_select->no_wrap_view_item;
+ TABLE_LIST *table= NULL; // For HP compilers
DBUG_ENTER("setup_conds");
+ if (select_lex->conds_processed_with_permanent_arena ||
+ arena->is_conventional())
+ arena= 0; // For easier test
+
thd->set_query_id=1;
- thd->lex->current_select->cond_count= 0;
+
+ thd->lex->current_select->no_wrap_view_item= 0;
+ select_lex->cond_count= 0;
if (*conds)
{
thd->where="where clause";
if (!(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds) ||
(*conds)->check_cols(1))
- DBUG_RETURN(1);
- not_null_tables= (*conds)->not_null_tables();
+ goto err_no_arena;
}
-
/* Check if we are using outer joins */
- for (TABLE_LIST *table=tables ; table ; table=table->next)
+ for (table= leaves; table; table= table->next_leaf)
{
- if (table->on_expr)
+ TABLE_LIST *embedded;
+ TABLE_LIST *embedding= table;
+ do
{
- /* Make a join an a expression */
- thd->where="on clause";
-
- if (!table->on_expr->fixed &&
- table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
- table->on_expr->check_cols(1))
- DBUG_RETURN(1);
- thd->lex->current_select->cond_count++;
-
- /*
- If it's a normal join or a LEFT JOIN which can be optimized away
- add the ON/USING expression to the WHERE
- */
- if (!table->outer_join ||
- ((table->table->map & not_null_tables) &&
- !(specialflag & SPECIAL_NO_NEW_FUNC)))
+ embedded= embedding;
+ if (embedded->on_expr)
{
- table->outer_join= 0;
- arena= thd->change_arena_if_needed(&backup);
- *conds= and_conds(*conds, table->on_expr);
- table->on_expr=0;
- if (arena)
- {
- thd->restore_backup_item_arena(arena, &backup);
- arena= 0; // Safety if goto err
- }
- if ((*conds) && !(*conds)->fixed &&
- (*conds)->fix_fields(thd, tables, conds))
- DBUG_RETURN(1);
+ /* 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->check_cols(1))
+ goto err_no_arena;
+ select_lex->cond_count++;
}
- }
- if (table->natural_join)
- {
- arena= thd->change_arena_if_needed(&backup);
- /* Make a join of all fields with have the same name */
- TABLE *t1= table->table;
- TABLE *t2= table->natural_join->table;
- Item_cond_and *cond_and= new Item_cond_and();
- if (!cond_and) // If not out of memory
- goto err;
- cond_and->top_level_item();
-
- Field **t1_field, *t2_field;
- for (t1_field= t1->field; (*t1_field); t1_field++)
+ if (embedded->natural_join)
{
- const char *t1_field_name= (*t1_field)->field_name;
- uint not_used_field_index= NO_CACHED_FIELD_INDEX;
-
- if ((t2_field= find_field_in_table(thd, t2, t1_field_name,
- strlen(t1_field_name), 0, 0,
- &not_used_field_index)))
+ /* Make a join of all fields wich have the same name */
+ TABLE_LIST *tab1= embedded;
+ TABLE_LIST *tab2= embedded->natural_join;
+ if (!(embedded->outer_join & JOIN_TYPE_RIGHT))
{
- Item_func_eq *tmp=new Item_func_eq(new Item_field(thd, *t1_field),
- new Item_field(thd, t2_field));
- if (!tmp)
- goto err;
- /* Mark field used for table cache */
- (*t1_field)->query_id= t2_field->query_id= thd->query_id;
- cond_and->list.push_back(tmp);
- t1->used_keys.intersect((*t1_field)->part_of_key);
- t2->used_keys.intersect(t2_field->part_of_key);
+ while (tab1->nested_join)
+ {
+ TABLE_LIST *next;
+ List_iterator_fast<TABLE_LIST> it(tab1->nested_join->join_list);
+ tab1= it++;
+ while ((next= it++))
+ tab1= next;
+ }
+ }
+ else
+ {
+ while (tab1->nested_join)
+ tab1= tab1->nested_join->join_list.head();
+ }
+ if (embedded->outer_join & JOIN_TYPE_RIGHT)
+ {
+ while (tab2->nested_join)
+ {
+ TABLE_LIST *next;
+ List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
+ tab2= it++;
+ while ((next= it++))
+ tab2= next;
+ }
+ }
+ else
+ {
+ while (tab2->nested_join)
+ tab2= tab2->nested_join->join_list.head();
}
- }
- thd->lex->current_select->cond_count+= cond_and->list.elements;
- // to prevent natural join processing during PS re-execution
- table->natural_join= 0;
+ if (arena)
+ arena= thd->change_arena_if_needed(&backup);
+
+ TABLE *t1=tab1->table;
+ TABLE *t2=tab2->table;
+ Field_iterator_table table_iter;
+ Field_iterator_view view_iter;
+ Field_iterator *iterator;
+ Field *t1_field, *t2_field;
+ Item *item_t2= 0;
+ Item_cond_and *cond_and= new Item_cond_and();
+
+ if (!cond_and) // If not out of memory
+ goto err_no_arena;
+ cond_and->top_level_item();
+
+ if (table->field_translation)
+ {
+ iterator= &view_iter;
+ view_iter.set(tab1);
+ }
+ else
+ {
+ iterator= &table_iter;
+ table_iter.set(tab1);
+ }
- if (cond_and->list.elements)
- {
- if (!table->outer_join) // Not left join
+ for (; !iterator->end_of_fields(); iterator->next())
{
- *conds= and_conds(*conds, cond_and);
- // fix_fields() should be made with temporary memory pool
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- if (*conds && !(*conds)->fixed)
+ const char *t1_field_name= iterator->name();
+ uint not_used_field_index= NO_CACHED_FIELD_INDEX;
+
+ if ((t2_field= find_field_in_table(thd, tab2, t1_field_name,
+ t1_field_name,
+ strlen(t1_field_name), &item_t2,
+ 0, 0, 0,
+ &not_used_field_index,
+ FALSE)))
{
- if (!(*conds)->fixed &&
- (*conds)->fix_fields(thd, tables, conds))
- DBUG_RETURN(1);
+ if (t2_field != view_ref_found)
+ {
+ if (!(item_t2= new Item_field(thd, t2_field)))
+ goto err;
+ /* Mark field used for table cache */
+ t2_field->query_id= thd->query_id;
+ t2->used_keys.intersect(t2_field->part_of_key);
+ }
+ if ((t1_field= iterator->field()))
+ {
+ /* Mark field used for table cache */
+ t1_field->query_id= thd->query_id;
+ t1->used_keys.intersect(t1_field->part_of_key);
+ }
+ Item_func_eq *tmp= new Item_func_eq(iterator->item(thd),
+ item_t2);
+ if (!tmp)
+ goto err;
+ cond_and->list.push_back(tmp);
}
}
- else
+ select_lex->cond_count+= cond_and->list.elements;
+
+ // to prevent natural join processing during PS re-execution
+ embedding->natural_join= 0;
+
+ if (cond_and->list.elements)
{
- table->on_expr= and_conds(table->on_expr, cond_and);
- // fix_fields() should be made with temporary memory pool
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- if (table->on_expr && !table->on_expr->fixed)
+ COND *on_expr= cond_and;
+ if (!on_expr->fixed)
+ on_expr->fix_fields(thd, 0, &on_expr);
+ if (!embedded->outer_join) // Not left join
{
- if (!table->on_expr->fixed &&
- table->on_expr->fix_fields(thd, tables, &table->on_expr))
- DBUG_RETURN(1);
+ *conds= and_conds(*conds, cond_and);
+ // fix_fields() should be made with temporary memory pool
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ if (*conds && !(*conds)->fixed)
+ {
+ if ((*conds)->fix_fields(thd, tables, conds))
+ goto err_no_arena;
+ }
+ }
+ else
+ {
+ embedded->on_expr= and_conds(embedded->on_expr, cond_and);
+ // fix_fields() should be made with temporary memory pool
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ if (embedded->on_expr && !embedded->on_expr->fixed)
+ {
+ if (embedded->on_expr->fix_fields(thd, tables,
+ &embedded->on_expr))
+ goto err_no_arena;
+ }
}
}
+ else if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
}
- else if (arena)
- {
- thd->restore_backup_item_arena(arena, &backup);
- arena= 0; // Safety if goto err
- }
+ embedding= embedded->embedding;
}
+ while (embedding &&
+ embedding->nested_join->join_list.head() == embedded);
}
- if (thd->current_arena->is_stmt_prepare())
+ if (!thd->current_arena->is_conventional())
{
/*
We are in prepared statement preparation code => we should store
WHERE clause changing for next executions.
- We do this ON -> WHERE transformation only once per PS statement.
+ We do this ON -> WHERE transformation only once per PS/SP statement.
*/
- thd->lex->current_select->where= *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);
}
@@ -2776,8 +3787,25 @@ err:
** Returns : 1 if some field has wrong type
******************************************************************************/
-int
-fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
+
+/*
+ Fill fields with given items.
+
+ SYNOPSIS
+ fill_record()
+ thd thread handler
+ fields Item_fields list to be filled
+ values values to fill with
+ ignore_errors TRUE if we should ignore errors
+
+ RETURN
+ FALSE OK
+ TRUE error occured
+*/
+
+bool
+fill_record(THD * thd, List<Item> &fields, List<Item> &values,
+ bool ignore_errors)
{
List_iterator_fast<Item> f(fields),v(values);
Item *value;
@@ -2792,14 +3820,32 @@ fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
if (rfield == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
- DBUG_RETURN(1);
+ {
+ my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
+ DBUG_RETURN(TRUE);
+ }
}
- DBUG_RETURN(0);
+ DBUG_RETURN(thd->net.report_error);
}
-int
-fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
+/*
+ Fill field buffer with values from Field list
+
+ SYNOPSIS
+ fill_record()
+ thd thread handler
+ ptr pointer on pointer to record
+ values list of fields
+ ignore_errors TRUE if we should ignore errors
+
+ RETURN
+ FALSE OK
+ TRUE error occured
+*/
+
+bool
+fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
{
List_iterator_fast<Item> v(values);
Item *value;
@@ -2812,10 +3858,10 @@ fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
TABLE *table= field->table;
if (field == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
- if ((value->save_in_field(field, 0) < 0) && !ignore_errors)
- DBUG_RETURN(1);
+ if (value->save_in_field(field, 0) == -1)
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(thd->net.report_error);
}
@@ -2863,34 +3909,31 @@ static void mysql_rm_tmp_tables(void)
*****************************************************************************/
/*
-** Invalidate any cache entries that are for some DB
-** We can't use hash_delete when looping hash_elements. We mark them first
-** and afterwards delete those marked unused.
+ Invalidate any cache entries that are for some DB
+
+ SYNOPSIS
+ remove_db_from_cache()
+ db Database name. This will be in lower case if
+ lower_case_table_name is set
+
+ NOTE:
+ We can't use hash_delete when looping hash_elements. We mark them first
+ and afterwards delete those marked unused.
*/
void remove_db_from_cache(const char *db)
{
- char name_buff[NAME_LEN+1];
- if (db && lower_case_table_names)
- {
- /*
- convert database to lower case for comparision.
- */
- strmake(name_buff, db, sizeof(name_buff)-1);
- my_casedn_str(files_charset_info, name_buff);
- db= name_buff;
- }
for (uint idx=0 ; idx < open_cache.records ; idx++)
{
TABLE *table=(TABLE*) hash_element(&open_cache,idx);
- if (!strcmp(table->table_cache_key,db))
+ if (!strcmp(table->s->db, db))
{
- table->version=0L; /* Free when thread is ready */
+ table->s->version= 0L; /* Free when thread is ready */
if (!table->in_use)
relink_unused(table);
}
}
- while (unused_tables && !unused_tables->version)
+ while (unused_tables && !unused_tables->s->version)
VOID(hash_delete(&open_cache,(byte*) unused_tables));
}
@@ -2935,7 +3978,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
{
THD *in_use;
- table->version=0L; /* Free when thread is ready */
+ table->s->version= 0L; /* Free when thread is ready */
if (!(in_use=table->in_use))
{
DBUG_PRINT("info",("Table was not in use"));
@@ -2950,7 +3993,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
! in_use->killed)
{
- in_use->killed=1;
+ in_use->killed= THD::KILL_CONNECTION;
pthread_mutex_lock(&in_use->mysys_var->mutex);
if (in_use->mysys_var->current_cond)
{
@@ -2975,7 +4018,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
else
result= result || return_if_owned_by_thd;
}
- while (unused_tables && !unused_tables->version)
+ while (unused_tables && !unused_tables->s->version)
VOID(hash_delete(&open_cache,(byte*) unused_tables));
DBUG_RETURN(result);
}
@@ -3016,3 +4059,62 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
}
return 0;
}
+
+
+/*
+ open new .frm format table
+
+ SYNOPSIS
+ open_new_frm()
+ path path to .frm
+ alias alias for table
+ db database
+ table_name name of table
+ db_stat open flags (for example HA_OPEN_KEYFILE|HA_OPEN_RNDFILE..)
+ can be 0 (example in ha_example_table)
+ prgflag READ_ALL etc..
+ ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc..
+ outparam result table
+ table_desc TABLE_LIST descriptor
+ mem_root temporary MEM_ROOT for parsing
+*/
+
+static my_bool
+open_new_frm(const char *path, const char *alias,
+ const char *db, const char *table_name,
+ uint db_stat, uint prgflag,
+ uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
+ MEM_ROOT *mem_root)
+{
+ LEX_STRING pathstr;
+ File_parser *parser;
+ DBUG_ENTER("open_new_frm");
+
+ pathstr.str= (char*) path;
+ pathstr.length= strlen(path);
+
+ if ((parser= sql_parse_prepare(&pathstr, mem_root, 1)))
+ {
+ if (!strncmp("VIEW", parser->type()->str, parser->type()->length))
+ {
+ if (table_desc == 0 || table_desc->required_type == FRMTYPE_TABLE)
+ {
+ my_error(ER_WRONG_OBJECT, MYF(0), db, table_name, "BASE TABLE");
+ goto err;
+ }
+ if (mysql_make_view(parser, table_desc))
+ goto err;
+ }
+ else
+ {
+ /* only VIEWs are supported now */
+ my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), path, parser->type()->str);
+ goto err;
+ }
+ DBUG_RETURN(0);
+ }
+
+err:
+ bzero(outparam, sizeof(TABLE)); // do not run repair
+ DBUG_RETURN(1);
+}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 6eff958257b..4a4f61f985c 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -311,7 +311,7 @@ TODO list:
#include "emb_qcache.h"
#endif
-#if defined(EXTRA_DEBUG) && !defined(DBUG_OFF)
+#if !defined(EXTRA_DBUG) && !defined(DBUG_OFF)
#define MUTEX_LOCK(M) { DBUG_PRINT("lock", ("mutex lock 0x%lx", (ulong)(M))); \
pthread_mutex_lock(M);}
#define MUTEX_UNLOCK(M) {DBUG_PRINT("lock", ("mutex unlock 0x%lx",\
@@ -610,6 +610,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
DBUG_VOID_RETURN;
}
header->result(result);
+ header->last_pkt_nr= net->pkt_nr;
BLOCK_UNLOCK_WR(query_block);
}
else
@@ -913,12 +914,12 @@ end:
int
Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
{
+ ulonglong engine_data;
Query_cache_query *query;
Query_cache_block *first_result_block, *result_block;
Query_cache_block_table *block_table, *block_table_end;
ulong tot_length;
Query_cache_query_flags flags;
- bool check_tables;
DBUG_ENTER("Query_cache::send_result_to_client");
if (query_cache_size == 0 || thd->variables.query_cache_type == 0)
@@ -936,11 +937,16 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
/*
Test if the query is a SELECT
- (pre-space is removed in dispatch_command)
+ (pre-space is removed in dispatch_command).
+
+ First '/' looks like comment before command it is not
+ frequently appeared in real lihe, consequently we can
+ check all such queries, too.
*/
- if (my_toupper(system_charset_info, sql[0]) != 'S' ||
- my_toupper(system_charset_info, sql[1]) != 'E' ||
- my_toupper(system_charset_info,sql[2]) !='L')
+ if ((my_toupper(system_charset_info, sql[0]) != 'S' ||
+ my_toupper(system_charset_info, sql[1]) != 'E' ||
+ my_toupper(system_charset_info,sql[2]) !='L') &&
+ sql[0] != '/')
{
DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
goto err;
@@ -1021,7 +1027,6 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
goto err_unlock;
}
- check_tables= query->tables_type() & HA_CACHE_TBL_ASKTRANSACT;
// Check access;
block_table= query_block->table(0);
block_table_end= block_table+query_block->n_tables;
@@ -1029,7 +1034,6 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
{
TABLE_LIST table_list;
TABLE *tmptable;
-
Query_cache_table *table = block_table->parent;
/*
@@ -1040,8 +1044,9 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
*/
for (tmptable= thd->temporary_tables; tmptable ; tmptable= tmptable->next)
{
- if (tmptable->key_length - TMP_TABLE_KEY_EXTRA == table->key_length() &&
- !memcmp(tmptable->table_cache_key, table->data(),
+ if (tmptable->s->key_length - TMP_TABLE_KEY_EXTRA ==
+ table->key_length() &&
+ !memcmp(tmptable->s->table_cache_key, table->data(),
table->key_length()))
{
DBUG_PRINT("qcache",
@@ -1061,7 +1066,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
bzero((char*) &table_list,sizeof(table_list));
table_list.db = table->db();
- table_list.alias= table_list.real_name= table->table();
+ table_list.alias= table_list.table_name= table->table();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_table_access(thd,SELECT_ACL,&table_list,1))
{
@@ -1082,19 +1087,30 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
goto err_unlock; // Parse query
}
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
- if (check_tables && !ha_caching_allowed(thd, table->db(),
- table->key_length(),
- table->type()))
+ engine_data= table->engine_data();
+ if (table->callback() &&
+ !(*table->callback())(thd, table->db(),
+ table->key_length(),
+ &engine_data))
{
DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
- thd->lex->safe_to_cache_query= 0; // Don't try to cache this
+ if (engine_data != table->engine_data())
+ {
+ DBUG_PRINT("qcache",
+ ("Handler require invalidation queries of %s.%s %lld-%lld",
+ table_list.db, table_list.alias,
+ engine_data, table->engine_data()));
+ invalidate_table((byte *) table->db(), table->key_length());
+ }
+ else
+ thd->lex->safe_to_cache_query= 0; // Don't try to cache this
goto err_unlock; // Parse query
}
else
- DBUG_PRINT("qcache", ("handler allow caching (%d) %s,%s",
- check_tables, table_list.db, table_list.alias));
+ DBUG_PRINT("qcache", ("handler allow caching %s,%s",
+ table_list.db, table_list.alias));
}
move_to_query_list_end(query_block);
hits++;
@@ -1118,6 +1134,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
ALIGN_SIZE(sizeof(Query_cache_result))))
break; // Client aborted
result_block = result_block->next;
+ thd->net.pkt_nr= query->last_pkt_nr; // Keep packet number updated
} while (result_block != first_result_block);
#else
{
@@ -1156,7 +1173,7 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
using_transactions = using_transactions &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
- for (; tables_used; tables_used=tables_used->next)
+ for (; tables_used; tables_used= tables_used->next_local)
{
DBUG_ASSERT(!using_transactions || tables_used->table!=0);
if (tables_used->derived)
@@ -1188,7 +1205,7 @@ void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
if (query_cache_size > 0)
{
DUMP(this);
- for (; tables_used; tables_used=tables_used->next)
+ for (; tables_used; tables_used= tables_used->next)
{
invalidate_table((byte*) tables_used->key, tables_used->key_length);
DBUG_PRINT("qcache", (" db %s, table %s", tables_used->key,
@@ -1221,7 +1238,7 @@ void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used)
if (query_cache_size > 0)
{
DUMP(this);
- for (; tables_used; tables_used= tables_used->next)
+ for (; tables_used; tables_used= tables_used->next_local)
{
if (tables_used->lock_type & (TL_WRITE_LOW_PRIORITY | TL_WRITE))
invalidate_table(tables_used->table);
@@ -2053,7 +2070,7 @@ void Query_cache::invalidate_table(TABLE_LIST *table_list)
uint key_length;
Query_cache_block *table_block;
key_length=(uint) (strmov(strmov(key,table_list->db)+1,
- table_list->real_name) -key)+ 1;
+ table_list->table_name) -key)+ 1;
// We don't store temporary tables => no key_length+=4 ...
if ((table_block = (Query_cache_block*)
@@ -2064,7 +2081,7 @@ void Query_cache::invalidate_table(TABLE_LIST *table_list)
void Query_cache::invalidate_table(TABLE *table)
{
- invalidate_table((byte*) table->table_cache_key, table->key_length);
+ invalidate_table((byte*) table->s->table_cache_key, table->s->key_length);
}
void Query_cache::invalidate_table(byte * key, uint32 key_length)
@@ -2086,6 +2103,105 @@ void Query_cache::invalidate_table(Query_cache_block *table_block)
}
}
+
+/*
+ Register given table list begining with given position in tables table of
+ block
+
+ SYNOPSIS
+ Query_cache::register_tables_from_list
+ tables_used given table list
+ counter number current position in table of tables of block
+ block_table pointer to current position in tables table of block
+
+ RETURN
+ 0 error
+ number of next position of table entry in table of tables of block
+*/
+
+TABLE_COUNTER_TYPE
+Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
+ TABLE_COUNTER_TYPE counter,
+ Query_cache_block_table *block_table)
+{
+ TABLE_COUNTER_TYPE n;
+ DBUG_ENTER("Query_cache::register_tables_from_list");
+ for (n= counter;
+ tables_used;
+ tables_used= tables_used->next_global, n++, block_table++)
+ {
+ block_table->n= n;
+ if (tables_used->view)
+ {
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ DBUG_PRINT("qcache", ("view %s, db %s",
+ tables_used->view_name.str,
+ tables_used->view_db.str));
+ key_length= (uint) (strmov(strmov(key, tables_used->view_db.str) + 1,
+ tables_used->view_name.str) - key) + 1;
+ /*
+ There are not callback function for for VIEWs
+ */
+ if (!insert_table(key_length, key, block_table,
+ tables_used->view_db.length + 1,
+ HA_CACHE_TBL_NONTRANSACT, 0, 0))
+ DBUG_RETURN(0);
+ {
+ TABLE_COUNTER_TYPE inc= register_tables_from_list(tables_used->ancestor,
+ n + 1,
+ block_table + 1);
+ if (!inc)
+ DBUG_RETURN(0);
+ n+= inc;
+ block_table+= inc;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("qcache",
+ ("table %s, db %s, openinfo at 0x%lx, keylen %u, key at 0x%lx",
+ tables_used->table->s->table_name,
+ tables_used->table->s->table_cache_key,
+ (ulong) tables_used->table,
+ tables_used->table->s->key_length,
+ (ulong) tables_used->table->s->table_cache_key));
+ if (!insert_table(tables_used->table->s->key_length,
+ tables_used->table->s->table_cache_key, block_table,
+ tables_used->db_length,
+ tables_used->table->file->table_cache_type(),
+ tables_used->callback_func,
+ tables_used->engine_data))
+ DBUG_RETURN(0);
+
+ if (tables_used->table->s->db_type == DB_TYPE_MRG_MYISAM)
+ {
+ ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file;
+ MYRG_INFO *file = handler->myrg_info();
+ for (MYRG_TABLE *table = file->open_tables;
+ table != file->end_table ;
+ table++)
+ {
+ char key[MAX_DBKEY_LENGTH];
+ uint32 db_length;
+ uint key_length= filename_2_table_key(key, table->table->filename,
+ &db_length);
+ (++block_table)->n= ++n;
+ /*
+ There are not callback function for for MyISAM, and engine data
+ */
+ if (!insert_table(key_length, key, block_table,
+ db_length,
+ tables_used->table->file->table_cache_type(),
+ 0, 0))
+ DBUG_RETURN(0);
+ }
+ }
+ }
+ }
+ DBUG_RETURN(n - counter);
+}
+
/*
Store all used tables
@@ -2107,44 +2223,9 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
Query_cache_block_table *block_table = block->table(0);
- for (n=0; tables_used; tables_used=tables_used->next, n++, block_table++)
- {
- DBUG_PRINT("qcache",
- ("table %s, db %s, openinfo at 0x%lx, keylen %u, key at 0x%lx",
- tables_used->real_name, tables_used->db,
- (ulong) tables_used->table,
- tables_used->table->key_length,
- (ulong) tables_used->table->table_cache_key));
- block_table->n=n;
- if (!insert_table(tables_used->table->key_length,
- tables_used->table->table_cache_key, block_table,
- tables_used->db_length,
- tables_used->table->file->table_cache_type()))
- break;
-
- if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM)
- {
- ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file;
- MYRG_INFO *file = handler->myrg_info();
- for (MYRG_TABLE *table = file->open_tables;
- table != file->end_table ;
- table++)
- {
- char key[MAX_DBKEY_LENGTH];
- uint32 db_length;
- uint key_length= filename_2_table_key(key, table->table->filename,
- &db_length);
- (++block_table)->n= ++n;
- if (!insert_table(key_length, key, block_table,
- db_length,
- tables_used->table->file->table_cache_type()))
- goto err;
- }
- }
- }
+ n= register_tables_from_list(tables_used, 0, block_table);
-err:
- if (tables_used)
+ if (n)
{
DBUG_PRINT("qcache", ("failed at table %d", (int) n));
/* Unlink the tables we allocated above */
@@ -2153,7 +2234,7 @@ err:
tmp++)
unlink_table(tmp);
}
- return (tables_used == 0);
+ return (n);
}
/*
@@ -2164,7 +2245,9 @@ err:
my_bool
Query_cache::insert_table(uint key_len, char *key,
Query_cache_block_table *node,
- uint32 db_length, uint8 cache_type)
+ uint32 db_length, uint8 cache_type,
+ qc_engine_callback callback,
+ ulonglong engine_data)
{
DBUG_ENTER("Query_cache::insert_table");
DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d",
@@ -2174,6 +2257,23 @@ Query_cache::insert_table(uint key_len, char *key,
hash_search(&tables, (byte*) key,
key_len));
+ if (table_block &&
+ table_block->table()->engine_data() != engine_data)
+ {
+ DBUG_PRINT("qcache",
+ ("Handler require invalidation queries of %s.%s %lld-%lld",
+ table_block->table()->db(),
+ table_block->table()->table(),
+ engine_data,
+ table_block->table()->engine_data()));
+ /*
+ as far as we delete all queries with this table, table block will be
+ deleted, too
+ */
+ invalidate_table(table_block);
+ table_block= 0;
+ }
+
if (table_block == 0)
{
DBUG_PRINT("qcache", ("new table block from 0x%lx (%u)",
@@ -2204,6 +2304,8 @@ Query_cache::insert_table(uint key_len, char *key,
header->table(db + db_length + 1);
header->key_length(key_len);
header->type(cache_type);
+ header->callback(callback);
+ header->engine_data(engine_data);
}
Query_cache_block_table *list_root = table_block->table(0);
@@ -2630,6 +2732,78 @@ void Query_cache::double_linked_list_join(Query_cache_block *head_tail,
*****************************************************************************/
/*
+ Collect information about table types, check that tables are cachable and
+ count them
+
+ SYNOPSIS
+ process_and_count_tables()
+ tables_used table list for processing
+ tables_type pointer to variable for table types collection
+
+ RETURN
+ 0 error
+ >0 number of tables
+*/
+
+static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
+ uint8 *tables_type)
+{
+ DBUG_ENTER("process_and_count_tables");
+ TABLE_COUNTER_TYPE table_count = 0;
+ for (; tables_used; tables_used= tables_used->next_global)
+ {
+ table_count++;
+ if (tables_used->view)
+ {
+ DBUG_PRINT("qcache", ("view %s, db %s",
+ tables_used->view_name.str,
+ tables_used->view_db.str));
+ *tables_type|= HA_CACHE_TBL_NONTRANSACT;
+ {
+ TABLE_COUNTER_TYPE subcount;
+ if (!(subcount= process_and_count_tables(tables_used->ancestor,
+ tables_type)))
+ DBUG_RETURN(0);
+ table_count+= subcount;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("qcache", ("table %s, db %s, type %u",
+ tables_used->table->s->table_name,
+ tables_used->table->s->table_cache_key,
+ tables_used->table->s->db_type));
+ *tables_type|= tables_used->table->file->table_cache_type();
+
+ /*
+ table_alias_charset used here because it depends of
+ lower_case_table_names variable
+ */
+ if (tables_used->table->s->tmp_table != NO_TMP_TABLE ||
+ (*tables_type & HA_CACHE_TBL_NOCACHE) ||
+ (tables_used->db_length == 5 &&
+ my_strnncoll(table_alias_charset,
+ (uchar*)tables_used->table->s->table_cache_key, 6,
+ (uchar*)"mysql",6) == 0))
+ {
+ DBUG_PRINT("qcache",
+ ("select not cacheable: temporary, system or \
+ other non-cacheable table(s)"));
+ DBUG_RETURN(0);
+ }
+ if (tables_used->table->s->db_type == DB_TYPE_MRG_MYISAM)
+ {
+ ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file;
+ MYRG_INFO *file = handler->myrg_info();
+ table_count+= (file->end_table - file->open_tables);
+ }
+ }
+ }
+ DBUG_RETURN(table_count);
+}
+
+
+/*
If query is cacheable return number tables in query
(query without tables are not cached)
*/
@@ -2640,7 +2814,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
TABLE_LIST *tables_used,
uint8 *tables_type)
{
- TABLE_COUNTER_TYPE table_count = 0;
+ TABLE_COUNTER_TYPE table_count;
DBUG_ENTER("Query_cache::is_cacheable");
if (lex->sql_command == SQLCOM_SELECT &&
@@ -2654,36 +2828,8 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
lex->select_lex.options,
(int) thd->variables.query_cache_type));
- for (; tables_used; tables_used= tables_used->next)
- {
- table_count++;
- DBUG_PRINT("qcache", ("table %s, db %s, type %u",
- tables_used->real_name,
- tables_used->db, tables_used->table->db_type));
- *tables_type|= tables_used->table->file->table_cache_type();
-
- /*
- table_alias_charset used here because it depends of
- lower_case_table_names variable
- */
- if (tables_used->table->tmp_table != NO_TMP_TABLE ||
- (*tables_type & HA_CACHE_TBL_NOCACHE) ||
- (tables_used->db_length == 5 &&
- my_strnncoll(table_alias_charset, (uchar*)tables_used->db, 6,
- (uchar*)"mysql",6) == 0))
- {
- DBUG_PRINT("qcache",
- ("select not cacheable: temporary, system or \
-other non-cacheable table(s)"));
- DBUG_RETURN(0);
- }
- if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM)
- {
- ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file;
- MYRG_INFO *file = handler->myrg_info();
- table_count+= (file->end_table - file->open_tables);
- }
- }
+ if (!(table_count= process_and_count_tables(tables_used, tables_type)))
+ DBUG_RETURN(0);
if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
((*tables_type)&HA_CACHE_TBL_TRANSACT))
@@ -2721,12 +2867,16 @@ my_bool Query_cache::ask_handler_allowance(THD *thd,
{
DBUG_ENTER("Query_cache::ask_handler_allowance");
- for (; tables_used; tables_used= tables_used->next)
+ for (; tables_used; tables_used= tables_used->next_global)
{
- TABLE *table= tables_used->table;
- if (!ha_caching_allowed(thd, table->table_cache_key,
- table->key_length,
- table->file->table_cache_type()))
+ TABLE *table;
+ if (!(table= tables_used->table))
+ continue;
+ handler *handler= table->file;
+ if (!handler->register_query_cache_table(thd, table->s->table_cache_key,
+ table->s->key_length,
+ &tables_used->callback_func,
+ &tables_used->engine_data))
{
DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
tables_used->db, tables_used->alias));
@@ -3170,7 +3320,7 @@ void Query_cache::wreck(uint line, const char *message)
DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
DBUG_PRINT("warning", ("=================================="));
if (thd)
- thd->killed = 1;
+ thd->killed= THD::KILL_CONNECTION;
cache_dump();
/* check_integrity(0); */ /* Can't call it here because of locks */
bins_dump();
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index c933a2349af..c1b08904f51 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -112,6 +112,7 @@ struct Query_cache_query
NET *wri;
ulong len;
uint8 tbls_type;
+ unsigned int last_pkt_nr;
inline void init_n_lock();
void unlock_n_destroy();
@@ -145,6 +146,10 @@ struct Query_cache_table
char *tbl;
uint32 key_len;
uint8 table_type;
+ /* unique for every engine reference */
+ qc_engine_callback callback_func;
+ /* data need by some engines */
+ ulonglong engine_data_buff;
inline char *db() { return (char *) data(); }
inline char *table() { return tbl; }
@@ -153,6 +158,10 @@ struct Query_cache_table
inline void key_length(uint32 len) { key_len= len; }
inline uint8 type() { return table_type; }
inline void type(uint8 t) { table_type= t; }
+ inline qc_engine_callback callback() { return callback_func; }
+ inline void callback(qc_engine_callback fn){ callback_func= fn; }
+ inline ulonglong engine_data() { return engine_data_buff; }
+ inline void engine_data(ulonglong data) { engine_data_buff= data; }
inline gptr data()
{
return (gptr)(((byte*)this)+
@@ -276,12 +285,18 @@ protected:
void invalidate_table(TABLE *table);
void invalidate_table(byte *key, uint32 key_length);
void invalidate_table(Query_cache_block *table_block);
+ TABLE_COUNTER_TYPE
+ register_tables_from_list(TABLE_LIST *tables_used,
+ TABLE_COUNTER_TYPE counter,
+ Query_cache_block_table *block_table);
my_bool register_all_tables(Query_cache_block *block,
TABLE_LIST *tables_used,
TABLE_COUNTER_TYPE tables);
my_bool insert_table(uint key_len, char *key,
Query_cache_block_table *node,
- uint32 db_length, uint8 cache_type);
+ uint32 db_length, uint8 cache_type,
+ qc_engine_callback callback,
+ ulonglong engine_data);
void unlink_table(Query_cache_block_table *node);
Query_cache_block *get_free_block (ulong len, my_bool not_less,
ulong min);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index c20d5f79277..a6a1f4d60ef 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -35,6 +35,9 @@
#endif
#include <mysys_err.h>
+#include "sp_rcontext.h"
+#include "sp_cache.h"
+
/*
The following is used to initialise Table_ident with a internal
table name
@@ -156,18 +159,23 @@ bool foreign_key_prefix(Key *a, Key *b)
THD::THD()
:user_time(0), global_read_lock(0), is_fatal_error(0),
- last_insert_id_used(0),
- insert_id_used(0), rand_used(0), time_zone_used(0),
- in_lock_tables(0), bootstrap(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;
- host= user= priv_user= db= ip=0;
+#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";
locked=some_tables_deleted=no_errors=password= 0;
- killed=0;
query_start_used= 0;
count_cuted_fields= CHECK_FIELD_IGNORE;
- db_length= col_access= 0;
+ killed= NOT_KILLED;
+ 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;
@@ -186,26 +194,28 @@ THD::THD()
variables.pseudo_thread_id= 0;
one_shot_set= 0;
file_id = 0;
+ query_id= 0;
warn_id= 0;
db_charset= global_system_variables.collation_database;
+ bzero(ha_data, sizeof(ha_data));
mysys_var=0;
#ifndef DBUG_OFF
dbug_sentry=THD_SENTRY_MAGIC;
#endif
-#ifndef EMBEDDED_LIBRARY
+#ifndef EMBEDDED_LIBRARY
net.vio=0;
#endif
- net.last_error[0]=0; // If error on boot
+ net.last_error[0]=0; // If error on boot
+ net.query_cache_query=0; // If error on boot
ull=0;
- system_thread=cleanup_done=0;
+ system_thread= cleanup_done= abort_on_warning= no_warnings_for_error= 0;
peer_port= 0; // For SHOW PROCESSLIST
- transaction.changed_tables = 0;
#ifdef __WIN__
real_id = 0;
#endif
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
-#endif
+#endif
pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
/* Variables with default values */
@@ -224,16 +234,17 @@ THD::THD()
/* Initialize sub structures */
init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
user_connect=(USER_CONN *)0;
- hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
+ hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
- (hash_free_key) free_user_var,0);
+ (hash_free_key) free_user_var, 0);
+
+ sp_proc_cache= NULL;
+ sp_func_cache= NULL;
/* For user vars replication*/
if (opt_bin_log)
my_init_dynamic_array(&user_var_events,
- sizeof(BINLOG_USER_VAR_EVENT *),
- 16,
- 16);
+ sizeof(BINLOG_USER_VAR_EVENT *), 16, 16);
else
bzero((char*) &user_var_events, sizeof(user_var_events));
@@ -243,26 +254,9 @@ THD::THD()
protocol_prep.init(this);
tablespace_op=FALSE;
-#ifdef USING_TRANSACTIONS
- bzero((char*) &transaction,sizeof(transaction));
- /*
- Binlog is always open (if needed) before a THD is created (including
- bootstrap).
- */
- if (opt_using_transactions && mysql_bin_log.is_open())
- {
- if (open_cached_file(&transaction.trans_log,
- mysql_tmpdir, LOG_PREFIX, binlog_cache_size,
- MYF(MY_WME)))
- killed=1;
- transaction.trans_log.end_of_file= max_binlog_cache_size;
- }
-#endif
- init_sql_alloc(&transaction.mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
- {
- ulong tmp=sql_rnd_with_mutex();
- randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
- }
+ ulong tmp=sql_rnd_with_mutex();
+ randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
+ prelocked_mode= NON_PRELOCKED;
}
@@ -295,6 +289,7 @@ void THD::init(void)
bzero((char*) warn_count, sizeof(warn_count));
total_warn_count= 0;
update_charset();
+ bzero((char *) &status_var, sizeof(status_var));
}
@@ -310,9 +305,12 @@ void THD::init_for_queries()
reset_root_defaults(mem_root, variables.query_alloc_block_size,
variables.query_prealloc_size);
+#ifdef USING_TRANSACTIONS
reset_root_defaults(&transaction.mem_root,
variables.trans_alloc_block_size,
variables.trans_prealloc_size);
+#endif
+ transaction.xid.null();
}
@@ -333,9 +331,11 @@ void THD::change_user(void)
cleanup_done= 0;
init();
stmt_map.reset();
- hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
+ hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
(hash_free_key) free_user_var, 0);
+ sp_cache_clear(&sp_proc_cache);
+ sp_cache_clear(&sp_func_cache);
}
@@ -344,7 +344,10 @@ void THD::change_user(void)
void THD::cleanup(void)
{
DBUG_ENTER("THD::cleanup");
- ha_rollback(this);
+#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
+ if (transaction.xa_state != XA_PREPARED)
+#endif
+ ha_rollback(this);
if (locked_tables)
{
lock=locked_tables; locked_tables=0;
@@ -359,6 +362,8 @@ void THD::cleanup(void)
my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR));
delete_dynamic(&user_var_events);
hash_free(&user_vars);
+ sp_cache_clear(&sp_proc_cache);
+ sp_cache_clear(&sp_func_cache);
if (global_read_lock)
unlock_global_read_lock(this);
if (ull)
@@ -368,6 +373,7 @@ void THD::cleanup(void)
pthread_mutex_unlock(&LOCK_user_locks);
ull= 0;
}
+
cleanup_done=1;
DBUG_VOID_RETURN;
}
@@ -380,24 +386,23 @@ THD::~THD()
/* Ensure that no one is using THD */
pthread_mutex_lock(&LOCK_delete);
pthread_mutex_unlock(&LOCK_delete);
+ add_to_status(&global_status_var, &status_var);
/* Close connection */
-#ifndef EMBEDDED_LIBRARY
+#ifndef EMBEDDED_LIBRARY
if (net.vio)
{
vio_delete(net.vio);
- net_end(&net);
+ net_end(&net);
}
#endif
if (!cleanup_done)
cleanup();
-#ifdef USING_TRANSACTIONS
- if (opt_using_transactions)
- {
- close_cached_file(&transaction.trans_log);
- ha_close_connection(this);
- }
-#endif
+
+ ha_close_connection(this);
+
+ sp_cache_clear(&sp_proc_cache);
+ sp_cache_clear(&sp_func_cache);
DBUG_PRINT("info", ("freeing host"));
if (host != my_localhost) // If not pointer to constant
@@ -407,11 +412,13 @@ THD::~THD()
safeFree(ip);
safeFree(db);
free_root(&warn_root,MYF(0));
+#ifdef USING_TRANSACTIONS
free_root(&transaction.mem_root,MYF(0));
+#endif
mysys_var=0; // Safety (shouldn't be needed)
pthread_mutex_destroy(&LOCK_delete);
#ifndef DBUG_OFF
- dbug_sentry = THD_SENTRY_GONE;
+ 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);
@@ -419,14 +426,35 @@ THD::~THD()
}
-void THD::awake(bool prepare_to_die)
+/*
+ Add to one status variable another status variable
+
+ NOTES
+ This function assumes that all variables are long/ulong.
+ If this assumption will change, then we have to explictely add
+ the other variables after the while loop
+*/
+
+void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
+{
+ ulong *end= (ulong*) ((byte*) to_var + offsetof(STATUS_VAR,
+ last_system_status_var) +
+ sizeof(ulong));
+ ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
+
+ while (to != end)
+ *(to++)+= *(from++);
+}
+
+
+void THD::awake(THD::killed_state state_to_set)
{
THD_CHECK_SENTRY(this);
safe_mutex_assert_owner(&LOCK_delete);
- if (prepare_to_die)
- killed = 1;
- thr_alarm_kill(real_id);
+ killed= state_to_set;
+ if (state_to_set != THD::KILL_QUERY)
+ thr_alarm_kill(real_id);
#ifdef SIGNAL_WITH_VIO_CLOSE
close_active_vio();
#endif
@@ -485,6 +513,24 @@ bool THD::store_globals()
}
+/* Cleanup after a query */
+
+void THD::cleanup_after_query()
+{
+ if (clear_next_insert_id)
+ {
+ clear_next_insert_id= 0;
+ next_insert_id= 0;
+ }
+ /* Free Items that were created during this execution */
+ free_items(free_list);
+ /*
+ In the rest of code we assume that free_list never points to garbage:
+ Keep this predicate true.
+ */
+ free_list= 0;
+}
+
/*
Convert a string to another character set
@@ -592,7 +638,7 @@ void THD::add_changed_table(TABLE *table)
DBUG_ASSERT((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
table->file->has_transactions());
- add_changed_table(table->table_cache_key, table->key_length);
+ add_changed_table(table->s->table_cache_key, table->s->key_length);
DBUG_VOID_RETURN;
}
@@ -646,8 +692,8 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
if (!new_table)
{
my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
- ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
- killed= 1;
+ ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
+ killed= KILL_CONNECTION;
return 0;
}
@@ -674,15 +720,16 @@ int THD::send_explain_fields(select_result *result)
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("key", NAME_LEN, cs));
item->maybe_null=1;
- field_list.push_back(item=new Item_return_int("key_len",3,
- MYSQL_TYPE_LONGLONG));
+ field_list.push_back(item=new Item_empty_string("key_len",
+ NAME_LEN*MAX_KEY));
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("ref",
NAME_LEN*MAX_REF_PARTS, cs));
item->maybe_null=1;
field_list.push_back(new Item_return_int("rows", 10, MYSQL_TYPE_LONGLONG));
field_list.push_back(new Item_empty_string("Extra", 255, cs));
- return (result->send_fields(field_list,1));
+ return (result->send_fields(field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
}
#ifdef SIGNAL_WITH_VIO_CLOSE
@@ -745,10 +792,13 @@ void THD::rollback_item_tree_changes()
{
I_List_iterator<Item_change_record> it(change_list);
Item_change_record *change;
+ DBUG_ENTER("rollback_item_tree_changes");
+
while ((change= it++))
*change->place= change->old_value;
/* We can forget about changes memory: it's allocated in runtime memroot */
change_list.empty();
+ DBUG_VOID_RETURN;
}
@@ -763,7 +813,7 @@ select_result::select_result()
void select_result::send_error(uint errcode,const char *err)
{
- ::send_error(thd, errcode, err);
+ my_message(errcode, err, MYF(0));
}
@@ -785,9 +835,9 @@ sql_exchange::sql_exchange(char *name,bool flag)
escaped= &default_escaped;
}
-bool select_send::send_fields(List<Item> &list,uint flag)
+bool select_send::send_fields(List<Item> &list, uint flags)
{
- return thd->protocol->send_fields(&list,flag);
+ return thd->protocol->send_fields(&list, flags);
}
/* Send data to client. Returns 0 if ok */
@@ -806,7 +856,6 @@ bool select_send::send_data(List<Item> &items)
InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
by thd
*/
- if (thd->transaction.all.innobase_tid)
ha_release_temporary_latches(thd);
#endif
@@ -841,7 +890,6 @@ bool select_send::send_eof()
/* We may be passing the control from mysqld to the client: release the
InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
by thd */
- if (thd->transaction.all.innobase_tid)
ha_release_temporary_latches(thd);
#endif
@@ -867,7 +915,7 @@ bool select_send::send_eof()
void select_to_file::send_error(uint errcode,const char *err)
{
- ::send_error(thd,errcode,err);
+ my_message(errcode, err, MYF(0));
if (file > 0)
{
(void) end_io_cache(&cache);
@@ -1191,7 +1239,7 @@ bool select_dump::send_data(List<Item> &items)
}
if (row_count++ > 1)
{
- my_error(ER_TOO_MANY_ROWS, MYF(0));
+ my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
goto err;
}
while ((item=li++))
@@ -1204,7 +1252,7 @@ bool select_dump::send_data(List<Item> &items)
}
else if (my_b_write(&cache,(byte*) res->ptr(),res->length()))
{
- my_error(ER_ERROR_ON_WRITE,MYF(0), path, my_errno);
+ my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno);
goto err;
}
}
@@ -1280,6 +1328,9 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items)
case STRING_RESULT:
op= &select_max_min_finder_subselect::cmp_str;
break;
+ case DECIMAL_RESULT:
+ op= &select_max_min_finder_subselect::cmp_decimal;
+ break;
case ROW_RESULT:
// This case should never be choosen
DBUG_ASSERT(0);
@@ -1296,15 +1347,14 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items)
bool select_max_min_finder_subselect::cmp_real()
{
Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
- double val1= cache->val(), val2= maxmin->val();
+ double val1= cache->val_real(), val2= maxmin->val_real();
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 > val2);
- else
- return (maxmin->null_value && !cache->null_value) ||
- (!cache->null_value && !maxmin->null_value &&
- val1 < val2);
+ return (maxmin->null_value && !cache->null_value) ||
+ (!cache->null_value && !maxmin->null_value &&
+ val1 < val2);
}
bool select_max_min_finder_subselect::cmp_int()
@@ -1315,10 +1365,23 @@ bool select_max_min_finder_subselect::cmp_int()
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 > val2);
- else
- return (maxmin->null_value && !cache->null_value) ||
+ return (maxmin->null_value && !cache->null_value) ||
+ (!cache->null_value && !maxmin->null_value &&
+ val1 < val2);
+}
+
+bool select_max_min_finder_subselect::cmp_decimal()
+{
+ Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ my_decimal cval, *cvalue= cache->val_decimal(&cval);
+ my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
+ if (fmax)
+ return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
- val1 < val2);
+ my_decimal_cmp(cvalue, mvalue) > 0) ;
+ return (maxmin->null_value && !cache->null_value) ||
+ (!cache->null_value && !maxmin->null_value &&
+ my_decimal_cmp(cvalue,mvalue) < 0);
}
bool select_max_min_finder_subselect::cmp_str()
@@ -1335,10 +1398,9 @@ bool select_max_min_finder_subselect::cmp_str()
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
sortcmp(val1, val2, cache->collation.collation) > 0) ;
- else
- return (maxmin->null_value && !cache->null_value) ||
- (!cache->null_value && !maxmin->null_value &&
- sortcmp(val1, val2, cache->collation.collation) < 0);
+ return (maxmin->null_value && !cache->null_value) ||
+ (!cache->null_value && !maxmin->null_value &&
+ sortcmp(val1, val2, cache->collation.collation) < 0);
}
bool select_exists_subselect::send_data(List<Item> &items)
@@ -1363,27 +1425,38 @@ bool select_exists_subselect::send_data(List<Item> &items)
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
List_iterator_fast<Item> li(list);
- List_iterator_fast<LEX_STRING> gl(var_list);
+ List_iterator_fast<my_var> gl(var_list);
Item *item;
- LEX_STRING *ls;
+
+ local_vars.empty(); // Clear list if SP
+ unit= u;
+ row_count= 0;
+
if (var_list.elements != list.elements)
{
- my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, MYF(0));
+ my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
+ ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
return 1;
}
- unit=u;
while ((item=li++))
{
- ls= gl++;
- Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item);
- /*
- Item_func_set_user_var can't substitute something else on its place =>
- 0 can be passed as last argument (reference on item)
- */
- xx->fix_fields(thd,(TABLE_LIST*) thd->lex->select_lex.table_list.first,
- 0);
- xx->fix_length_and_dec();
- vars.push_back(xx);
+ my_var *mv= gl++;
+ if (mv->local)
+ (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 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
+ */
+ xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first,
+ 0);
+ xx->fix_length_and_dec();
+ vars.push_back(xx);
+ }
}
return 0;
}
@@ -1444,7 +1517,7 @@ Item_arena::Item_arena(bool init_mem_root)
Item_arena::Type Item_arena::type() const
{
- DBUG_ASSERT("Item_arena::type()" == "abstract");
+ DBUG_ASSERT(0); /* Should never be called */
return STATEMENT;
}
@@ -1460,7 +1533,8 @@ Statement::Statement(THD *thd)
allow_sum_func(0),
lex(&main_lex),
query(0),
- query_length(0)
+ query_length(0),
+ cursor(0)
{
name.str= NULL;
}
@@ -1478,7 +1552,8 @@ Statement::Statement()
allow_sum_func(0), /* initialized later */
lex(&main_lex),
query(0), /* these two are set */
- query_length(0) /* in alloc_query() */
+ query_length(0), /* in alloc_query() */
+ cursor(0)
{
}
@@ -1497,6 +1572,7 @@ void Statement::set_statement(Statement *stmt)
lex= stmt->lex;
query= stmt->query;
query_length= stmt->query_length;
+ cursor= stmt->cursor;
}
@@ -1521,8 +1597,8 @@ void THD::end_statement()
lex_end(lex);
delete lex->result;
lex->result= 0;
- free_items(free_list);
- free_list= 0;
+ /* Note that free_list is freed in cleanup_after_query() */
+
/*
Don't free mem_root, as mem_root is freed in the end of dispatch_command
(once for any command).
@@ -1533,8 +1609,12 @@ void THD::end_statement()
void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup)
{
DBUG_ENTER("Item_arena::set_n_backup_item_arena");
+ DBUG_ASSERT(backup_arena == 0);
backup->set_item_arena(this);
set_item_arena(set);
+#ifndef DBUG_OFF
+ backup_arena= 1;
+#endif
DBUG_VOID_RETURN;
}
@@ -1544,6 +1624,9 @@ void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup)
DBUG_ENTER("Item_arena::restore_backup_item_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.
@@ -1634,8 +1717,19 @@ int Statement_map::insert(Statement *statement)
bool select_dumpvar::send_data(List<Item> &items)
{
List_iterator_fast<Item_func_set_user_var> li(vars);
+ List_iterator_fast<Item_splocal> var_li(local_vars);
+ List_iterator_fast<my_var> my_li(var_list);
+ List_iterator_fast<Item> it(items);
Item_func_set_user_var *xx;
+ Item_splocal *yy;
+ Item *item;
+ my_var *zz;
DBUG_ENTER("send_data");
+ if (unit->offset_limit_cnt)
+ { // using limit offset,count
+ unit->offset_limit_cnt--;
+ DBUG_RETURN(0);
+ }
if (unit->offset_limit_cnt)
{ // Using limit offset,count
@@ -1644,29 +1738,38 @@ bool select_dumpvar::send_data(List<Item> &items)
}
if (row_count++)
{
- my_error(ER_TOO_MANY_ROWS, MYF(0));
+ my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
DBUG_RETURN(1);
}
- while ((xx=li++))
+ while ((zz=my_li++) && (item=it++))
{
- xx->check();
- xx->update();
+ if (zz->local)
+ {
+ if ((yy=var_li++))
+ {
+ if (thd->spcont->set_item_eval(yy->get_offset(), item, zz->type))
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ {
+ if ((xx=li++))
+ {
+ xx->check();
+ xx->update();
+ }
+ }
}
DBUG_RETURN(0);
}
bool select_dumpvar::send_eof()
{
- if (row_count)
- {
- ::send_ok(thd,row_count);
- return 0;
- }
- else
- {
- my_error(ER_EMPTY_QUERY,MYF(0));
- return 1;
- }
+ if (! row_count)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
+ ::send_ok(thd,row_count);
+ return 0;
}
/****************************************************************************
@@ -1678,4 +1781,33 @@ void TMP_TABLE_PARAM::init()
field_count= sum_func_count= func_count= hidden_field_count= 0;
group_parts= group_length= group_null_parts= 0;
quick_group= 1;
+ table_charset= 0;
+}
+
+
+void thd_increment_bytes_sent(ulong length)
+{
+ THD *thd=current_thd;
+ if (likely(thd != 0))
+ { /* current_thd==0 when close_connection() calls net_send_error() */
+ thd->status_var.bytes_sent+= length;
+ }
+}
+
+
+void thd_increment_bytes_received(ulong length)
+{
+ current_thd->status_var.bytes_received+= length;
+}
+
+
+void thd_increment_net_big_packet_count(ulong length)
+{
+ current_thd->status_var.net_big_packet_count+= length;
+}
+
+
+void THD::set_status_var_init()
+{
+ bzero((char*) &status_var, sizeof(status_var));
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 703bb030ab9..62cee00043b 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -26,6 +26,9 @@
class Query_log_event;
class Load_log_event;
class Slave_log_event;
+class Format_description_log_event;
+class sp_rcontext;
+class sp_cache;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
@@ -38,6 +41,102 @@ enum enum_check_fields { CHECK_FIELD_IGNORE, CHECK_FIELD_WARN,
CHECK_FIELD_ERROR_FOR_NULL };
extern char internal_table_name[2];
+extern const char **errmesg;
+
+#define TC_LOG_PAGE_SIZE 8192
+#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE)
+extern ulong opt_tc_log_size;
+extern ulong tc_log_max_pages_used;
+extern ulong tc_log_page_size;
+extern ulong tc_log_page_waits;
+
+#define TC_HEURISTIC_RECOVER_COMMIT 1
+#define TC_HEURISTIC_RECOVER_ROLLBACK 2
+extern uint tc_heuristic_recover;
+
+/*
+ Transaction Coordinator log - a base abstract class
+ for two different implementations
+*/
+class TC_LOG
+{
+ public:
+ int using_heuristic_recover();
+ TC_LOG() {}
+ virtual ~TC_LOG() {}
+
+ virtual int open(const char *opt_name)=0;
+ virtual void close()=0;
+ virtual int log(THD *thd, my_xid xid)=0;
+ virtual void unlog(ulong cookie, my_xid xid)=0;
+};
+
+class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging
+{
+ public:
+ int open(const char *opt_name) { return 0; }
+ void close() { }
+ int log(THD *thd, my_xid xid) { return 1; }
+ void unlog(ulong cookie, my_xid xid) { }
+};
+
+#ifdef HAVE_MMAP
+class TC_LOG_MMAP: public TC_LOG
+{
+ public: // only to keep Sun Forte on sol9x86 happy
+ typedef enum {
+ POOL, // page is in pool
+ ERROR, // last sync failed
+ DIRTY // new xids added since last sync
+ } PAGE_STATE;
+
+ private:
+ typedef struct st_page {
+ struct st_page *next; // page a linked in a fifo queue
+ my_xid *start, *end; // usable area of a page
+ my_xid *ptr; // next xid will be written here
+ int size, free; // max and current number of free xid slots on the page
+ int waiters; // number of waiters on condition
+ PAGE_STATE state; // see above
+ pthread_mutex_t lock; // to access page data or control structure
+ pthread_cond_t cond; // to wait for a sync
+ } PAGE;
+
+ char logname[FN_REFLEN];
+ File fd;
+ my_off_t file_length;
+ uint npages, inited;
+ uchar *data;
+ struct st_page *pages, *syncing, *active, *pool, *pool_last;
+ /*
+ note that, e.g. LOCK_active is only used to protect
+ 'active' pointer, to protect the content of the active page
+ one has to use active->lock.
+ Same for LOCK_pool and LOCK_sync
+ */
+ pthread_mutex_t LOCK_active, LOCK_pool, LOCK_sync;
+ pthread_cond_t COND_pool, COND_active;
+
+ public:
+ TC_LOG_MMAP(): inited(0) {}
+ int open(const char *opt_name);
+ void close();
+ int log(THD *thd, my_xid xid);
+ void unlog(ulong cookie, my_xid xid);
+ int recover();
+
+ private:
+ void get_active_from_pool();
+ int sync();
+ int overflow();
+};
+#else
+#define TC_LOG_MMAP TC_LOG_DUMMY
+#endif
+
+extern TC_LOG *tc_log;
+extern TC_LOG_MMAP tc_log_mmap;
+extern TC_LOG_DUMMY tc_log_dummy;
/* log info errors */
#define LOG_INFO_EOF -1
@@ -75,10 +174,23 @@ typedef struct st_user_var_events
uint charset_number;
} BINLOG_USER_VAR_EVENT;
+#define RP_LOCK_LOG_IS_ALREADY_LOCKED 1
+#define RP_FORCE_ROTATE 2
+
class Log_event;
-class MYSQL_LOG
- {
+/*
+ TODO split MYSQL_LOG into base MYSQL_LOG and
+ MYSQL_QUERY_LOG, MYSQL_SLOW_LOG, MYSQL_BIN_LOG
+ most of the code from MYSQL_LOG should be in the MYSQL_BIN_LOG
+ only (TC_LOG included)
+
+ TODO use mmap instead of IO_CACHE for binlog
+ (mmap+fsync is two times faster than write+fsync)
+*/
+
+class MYSQL_LOG: public TC_LOG
+{
private:
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */
pthread_mutex_t LOCK_log, LOCK_index;
@@ -97,8 +209,15 @@ class MYSQL_LOG
enum cache_type io_cache_type;
bool write_error, inited;
bool need_start_event;
- bool no_auto_events; // For relay binlog
- /*
+ /*
+ no_auto_events means we don't want any of these automatic events :
+ Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't want
+ a Rotate_log event to be written to the relay log. When we start a relay log
+ etc. So in 4.x this is 1 for relay logs, 0 for binlogs.
+ In 5.0 it's 0 for relay logs too!
+ */
+ bool no_auto_events;
+ /*
The max size before rotation (usable only if log_type == LOG_BIN: binary
logs and relay logs).
For a binlog, max_size should be max_binlog_size.
@@ -106,14 +225,40 @@ class MYSQL_LOG
max_binlog_size otherwise.
max_size is set in init(), and dynamically changed (when one does SET
GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) by fix_max_binlog_size and
- fix_max_relay_log_size).
+ fix_max_relay_log_size).
*/
ulong max_size;
+
+ ulong prepared_xids; /* for tc log - number of xids to remember */
+ pthread_mutex_t LOCK_prep_xids;
+ pthread_cond_t COND_prep_xids;
friend class Log_event;
public:
MYSQL_LOG();
- ~MYSQL_LOG();
+ /*
+ note that there's no destructor ~MYSQL_LOG() !
+ The reason is that we don't want it to be automatically called
+ on exit() - but only during the correct shutdown process
+ */
+
+ int open(const char *opt_name);
+ void close();
+ int log(THD *thd, my_xid xid);
+ void unlog(ulong cookie, my_xid xid);
+ int recover(IO_CACHE *log, Format_description_log_event *fdle);
+
+ /*
+ These describe the log's format. This is used only for relay logs.
+ _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
+ necessary to have 2 distinct objects, because the I/O thread may be reading
+ events in a different format from what the SQL thread is reading (consider
+ the case of a master which has been upgraded from 5.0 to 5.1 without doing
+ RESET MASTER, or from 4.x to 5.0).
+ */
+ Format_description_log_event *description_event_for_exec,
+ *description_event_for_queue;
+
void reset_bytes_written()
{
bytes_written = 0;
@@ -122,7 +267,7 @@ public:
{
#ifndef DBUG_OFF
char buf1[22],buf2[22];
-#endif
+#endif
DBUG_ENTER("harvest_bytes_written");
(*counter)+=bytes_written;
DBUG_PRINT("info",("counter: %s bytes_written: %s", llstr(*counter,buf1),
@@ -139,17 +284,36 @@ public:
bool no_auto_events_arg, ulong max_size);
void init_pthread_objects();
void cleanup();
- bool open(const char *log_name,enum_log_type log_type,
- const char *new_name, const char *index_file_name_arg,
+ bool open(const char *log_name,
+ enum_log_type log_type,
+ const char *new_name,
enum cache_type io_cache_type_arg,
- bool no_auto_events_arg, ulong max_size);
- void new_file(bool need_lock= 1);
+ bool no_auto_events_arg, ulong max_size,
+ bool null_created);
+ const char *generate_name(const char *log_name, const char *suffix,
+ bool strip_ext, char *buff);
+ /* simplified open_xxx wrappers for the gigantic open above */
+ bool open_query_log(const char *log_name)
+ {
+ char buf[FN_REFLEN];
+ return open(generate_name(log_name, ".log", 0, buf),
+ LOG_NORMAL, 0, WRITE_CACHE, 0, 0, 0);
+ }
+ bool open_slow_log(const char *log_name)
+ {
+ char buf[FN_REFLEN];
+ return open(generate_name(log_name, "-slow.log", 0, buf),
+ LOG_NORMAL, 0, WRITE_CACHE, 0, 0, 0);
+ }
+ bool open_index_file(const char *index_file_name_arg,
+ const char *log_name);
+ void new_file(bool need_lock);
bool write(THD *thd, enum enum_server_command command,
const char *format,...);
bool write(THD *thd, const char *query, uint query_length,
time_t query_start=0);
bool write(Log_event* event_info); // binary log write
- bool write(THD *thd, IO_CACHE *cache, bool commit_or_rollback);
+ bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event);
/*
v stands for vector
@@ -157,20 +321,20 @@ public:
*/
bool appendv(const char* buf,uint len,...);
bool append(Log_event* ev);
-
+
int generate_new_name(char *new_name,const char *old_name);
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
int update_log_index(LOG_INFO* linfo, bool need_update_threads);
- int purge_logs(const char *to_log, bool included,
+ void rotate_and_purge(uint flags);
+ bool flush_and_sync();
+ int purge_logs(const char *to_log, bool included,
bool need_mutex, bool need_update_threads,
ulonglong *decrease_log_space);
int purge_logs_before_date(time_t purge_time);
- int purge_first_log(struct st_relay_log_info* rli, bool included);
+ int purge_first_log(struct st_relay_log_info* rli, bool included);
bool reset_logs(THD* thd);
void close(uint exiting);
- bool cut_spurious_tail();
- void report_pos_in_innodb();
// iterating through the log index file
int find_log_pos(LOG_INFO* linfo, const char* log_name,
@@ -181,6 +345,7 @@ public:
inline bool is_open() { return log_type != LOG_CLOSED; }
inline char* get_index_fname() { return index_file_name;}
inline char* get_log_fname() { return log_file_name; }
+ inline char* get_name() { return name; }
inline pthread_mutex_t* get_log_lock() { return &LOCK_log; }
inline IO_CACHE* get_log_file() { return &log_file; }
@@ -205,6 +370,8 @@ typedef struct st_copy_info {
/* for INSERT ... UPDATE */
List<Item> *update_fields;
List<Item> *update_values;
+ /* for VIEW ... WITH CHECK OPTION */
+ TABLE_LIST *view;
} COPY_INFO;
@@ -316,27 +483,6 @@ public:
};
-class MYSQL_ERROR: public Sql_alloc
-{
-public:
- enum enum_warning_level
- { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END};
-
- uint code;
- enum_warning_level level;
- char *msg;
-
- MYSQL_ERROR(THD *thd, uint code_arg, enum_warning_level level_arg,
- const char *msg_arg)
- :code(code_arg), level(level_arg)
- {
- if (msg_arg)
- set_msg(thd, msg_arg);
- }
- void set_msg(THD *thd, const char *msg_arg);
-};
-
-
class delayed_insert;
class select_result;
@@ -351,6 +497,7 @@ struct system_variables
ulonglong myisam_max_sort_file_size;
ha_rows select_limit;
ha_rows max_join_size;
+ ulong auto_increment_increment, auto_increment_offset;
ulong bulk_insert_buff_size;
ulong join_buff_size;
ulong long_query_time;
@@ -361,6 +508,7 @@ struct system_variables
ulong max_sort_length;
ulong max_tmp_tables;
ulong max_insert_delayed_threads;
+ ulong multi_range_count;
ulong myisam_repair_threads;
ulong myisam_sort_buff_size;
ulong net_buffer_length;
@@ -369,6 +517,8 @@ struct system_variables
ulong net_retry_count;
ulong net_wait_timeout;
ulong net_write_timeout;
+ ulong optimizer_prune_level;
+ ulong optimizer_search_depth;
ulong preload_buff_size;
ulong query_cache_type;
ulong read_buff_size;
@@ -377,8 +527,11 @@ struct system_variables
ulong table_type;
ulong tmp_table_size;
ulong tx_isolation;
+ ulong completion_type;
/* Determines which non-standard SQL behaviour should be enabled */
ulong sql_mode;
+ /* check of key presence in updatable view */
+ ulong updatable_views_with_limit;
ulong default_week_format;
ulong max_seeks_for_key;
ulong range_alloc_block_size;
@@ -397,6 +550,7 @@ struct system_variables
my_bool low_priority_updates;
my_bool new_mode;
my_bool query_cache_wlock_invalidate;
+ my_bool engine_condition_pushdown;
#ifdef HAVE_REPLICATION
ulong sync_replication;
ulong sync_replication_slave_id;
@@ -404,6 +558,7 @@ struct system_variables
#endif /* HAVE_REPLICATION */
#ifdef HAVE_INNOBASE_DB
my_bool innodb_table_locks;
+ my_bool innodb_support_xa;
#endif /* HAVE_INNOBASE_DB */
#ifdef HAVE_NDBCLUSTER_DB
ulong ndb_autoincrement_prefetch_sz;
@@ -430,6 +585,65 @@ struct system_variables
DATE_TIME_FORMAT *time_format;
};
+
+/* per thread status variables */
+
+typedef struct system_status_var
+{
+ ulong bytes_received;
+ ulong bytes_sent;
+ ulong com_other;
+ ulong com_stat[(uint) SQLCOM_END];
+ ulong created_tmp_disk_tables;
+ ulong created_tmp_tables;
+ ulong ha_commit_count;
+ ulong ha_delete_count;
+ ulong ha_read_first_count;
+ ulong ha_read_last_count;
+ ulong ha_read_key_count;
+ ulong ha_read_next_count;
+ ulong ha_read_prev_count;
+ ulong ha_read_rnd_count;
+ ulong ha_read_rnd_next_count;
+ ulong ha_rollback_count;
+ ulong ha_update_count;
+ ulong ha_write_count;
+ ulong ha_prepare_count;
+ ulong ha_discover_count;
+ ulong ha_savepoint_count;
+ ulong ha_savepoint_rollback_count;
+
+ /* KEY_CACHE parts. These are copies of the original */
+ ulong key_blocks_changed;
+ ulong key_blocks_used;
+ ulong key_cache_r_requests;
+ ulong key_cache_read;
+ ulong key_cache_w_requests;
+ ulong key_cache_write;
+ /* END OF KEY_CACHE parts */
+
+ ulong net_big_packet_count;
+ ulong opened_tables;
+ ulong select_full_join_count;
+ ulong select_full_range_join_count;
+ ulong select_range_count;
+ ulong select_range_check_count;
+ ulong select_scan_count;
+ ulong long_query_count;
+ ulong filesort_merge_passes;
+ ulong filesort_range_count;
+ ulong filesort_rows;
+ ulong filesort_scan_count;
+} STATUS_VAR;
+
+/*
+ This is used for 'show status'. It must be updated to the last ulong
+ variable in system_status_var
+*/
+
+#define last_system_status_var filesort_scan_count
+
+
void free_tmp_table(THD *thd, TABLE *entry);
@@ -443,6 +657,9 @@ public:
Item *free_list;
MEM_ROOT main_mem_root;
MEM_ROOT *mem_root; // Pointer to current memroot
+#ifndef DBUG_OFF
+ bool backup_arena;
+#endif
enum enum_state
{
INITIALIZED= 0, PREPARED= 1, EXECUTED= 3, CONVENTIONAL_EXECUTION= 2,
@@ -479,7 +696,7 @@ public:
inline bool is_first_stmt_execute() const { return state == PREPARED; }
inline bool is_stmt_execute() const
{ return state == PREPARED || state == EXECUTED; }
- inline bool is_conventional_execution() const
+ 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)
@@ -509,6 +726,8 @@ public:
};
+class Cursor;
+
/*
State of a single command executed against this connection.
One connection can contain a lot of simultaneously running statements,
@@ -582,6 +801,7 @@ public:
*/
char *query;
uint32 query_length; // current query length
+ Cursor *cursor;
public:
@@ -670,6 +890,14 @@ private:
Statement *last_found_statement;
};
+struct st_savepoint {
+ struct st_savepoint *prev;
+ char *name;
+ uint length, nht;
+};
+
+enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED};
+extern const char *xa_state_names[];
/*
A registry for item tree transformations performed during
@@ -683,11 +911,20 @@ typedef I_List<Item_change_record> Item_change_list;
/*
+ Type of prelocked mode.
+ See comment for THD::prelocked_mode for complete description.
+*/
+
+enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
+ PRELOCKED_UNDER_LOCK_TABLES= 2};
+
+
+/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
*/
-class THD :public ilink,
+class THD :public ilink,
public Statement
{
public:
@@ -712,6 +949,7 @@ public:
struct sockaddr_in remote; // client socket address
struct rand_struct rand; // used for authentication
struct system_variables variables; // Changeable local variables
+ struct system_status_var status_var; // Per thread statistic vars
pthread_mutex_t LOCK_delete; // Locked before thd is deleted
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
@@ -732,9 +970,17 @@ public:
the connection
priv_user - The user privilege we are using. May be '' for anonymous user.
db - currently selected database
+ catalog - currently selected catalog
ip - client IP
+ WARNING: some members of THD (currently 'db', 'catalog' and 'query') are
+ set and alloced by the slave SQL thread (for the THD of that thread); that
+ thread is (and must remain, for now) the only responsible for freeing these
+ 3 members. If you add members here, and you add code to set them in
+ replication, don't forget to free_them_and_set_them_to_0 in replication
+ properly. For details see the 'err:' label of the pthread_handler_decl of
+ the slave SQL thread, in sql/slave.cc.
*/
- char *host,*user,*priv_user,*db,*ip;
+ char *host,*user,*priv_user,*db,*catalog,*ip;
char priv_host[MAX_HOSTNAME];
/* remote (peer) port */
uint16 peer_port;
@@ -773,7 +1019,13 @@ public:
See also lock_tables() for details.
*/
MYSQL_LOCK *lock; /* Current locks */
- MYSQL_LOCK *locked_tables; /* Tables locked with 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;
HASH handler_tables_hash;
/*
One thread can hold up to one named user-level lock. This variable
@@ -803,15 +1055,15 @@ public:
thr_lock_type update_lock_default;
delayed_insert *di;
my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */
+ /* container for handler's private per-connection data */
+ void *ha_data[MAX_HA];
struct st_transactions {
- IO_CACHE trans_log; // Inited ONLY if binlog is open !
+ SAVEPOINT *savepoints;
THD_TRANS all; // Trans since BEGIN WORK
THD_TRANS stmt; // Trans for current statement
- uint bdb_lock_count;
-#ifdef HAVE_NDBCLUSTER_DB
- void* thd_ndb;
-#endif
- bool on;
+ bool on; // see ha_enable_transaction()
+ XID xid; // transaction identifier
+ enum xa_states xa_state; // used by external XA only
/*
Tables changed in transaction (that must be invalidated in query cache).
List contain only transactional tables, that not invalidated in query
@@ -821,9 +1073,20 @@ public:
MEM_ROOT mem_root; // Transaction-life memory allocation pool
void cleanup()
{
- changed_tables = 0;
+ changed_tables= 0;
+ savepoints= 0;
+#ifdef USING_TRANSACTIONS
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
+#endif
}
+#ifdef USING_TRANSACTIONS
+ st_transactions()
+ {
+ bzero((char*)this, sizeof(*this));
+ xid.null();
+ init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
+ }
+#endif
} transaction;
Field *dupp_field;
#ifndef __WIN__
@@ -849,6 +1112,8 @@ public:
generated auto_increment value in handler.cc
*/
ulonglong next_insert_id;
+ /* Remember last next_insert_id to reset it if something went wrong */
+ ulonglong prev_insert_id;
/*
The insert_id used for the last statement or set by SET LAST_INSERT_ID=#
or SELECT LAST_INSERT_ID(#). Used for binary log and returned by
@@ -866,7 +1131,6 @@ public:
table_map used_tables;
USER_CONN *user_connect;
CHARSET_INFO *db_charset;
- List<TABLE> temporary_tables_should_be_free; // list of temporary tables
/*
FIXME: this, and some other variables like 'count_cuted_fields'
maybe should be statement/cursor local, that is, moved to Statement
@@ -884,8 +1148,8 @@ public:
from table are necessary for this select, to check if it's necessary to
update auto-updatable fields (like auto_increment and timestamp).
*/
- ulong query_id;
- ulong warn_id, version, options, thread_id, col_access;
+ query_id_t query_id, warn_id;
+ ulong version, options, thread_id, col_access;
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
@@ -903,6 +1167,9 @@ public:
/* for user variables replication*/
DYNAMIC_ARRAY user_var_events;
+ enum killed_state { NOT_KILLED=0, KILL_BAD_DATA=1, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED };
+ killed_state volatile killed;
+
/* scramble - random string sent to client on handshake */
char scramble[SCRAMBLE_LENGTH+1];
@@ -910,14 +1177,22 @@ public:
bool locked, some_tables_deleted;
bool last_cuted_field;
bool no_errors, password, is_fatal_error;
- bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
- bool time_zone_used;
+ bool query_start_used, rand_used, time_zone_used;
+ bool last_insert_id_used,insert_id_used, clear_next_insert_id;
bool in_lock_tables;
bool query_error, bootstrap, cleanup_done;
bool tmp_table_used;
bool charset_is_system_charset, charset_is_collation_connection;
bool slow_command;
- my_bool volatile killed;
+ bool no_trans_update, abort_on_warning;
+ bool got_warning; /* Set on call to push_warning() */
+ bool no_warnings_for_error; /* no warnings on call to my_error() */
+ /* set during loop of derived table processing */
+ bool derived_tables_processing;
+ longlong row_count_func; /* For the ROW_COUNT() function */
+ sp_rcontext *spcont; // SP runtime context
+ sp_cache *sp_proc_cache;
+ sp_cache *sp_func_cache;
/*
If we do a purge of binary logs, log index info of the threads
@@ -933,6 +1208,31 @@ 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();
@@ -949,6 +1249,7 @@ public:
void init_for_queries();
void change_user(void);
void cleanup(void);
+ void cleanup_after_query();
bool store_globals();
#ifdef SIGNAL_WITH_VIO_CLOSE
inline void set_active_vio(Vio* vio)
@@ -964,18 +1265,18 @@ public:
pthread_mutex_unlock(&LOCK_delete);
}
void close_active_vio();
-#endif
- void awake(bool prepare_to_die);
+#endif
+ void awake(THD::killed_state state_to_set);
/*
For enter_cond() / exit_cond() to work the mutex must be got before
- enter_cond() (in 4.1 an assertion will soon ensure this); this mutex is
- then released by exit_cond(). Use must be:
- lock mutex; enter_cond(); your code; exit_cond().
+ enter_cond(); this mutex is then released by exit_cond().
+ Usage must be: lock mutex; enter_cond(); your code; exit_cond().
*/
inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex,
const char* msg)
{
const char* old_msg = proc_info;
+ safe_mutex_assert_owner(mutex);
mysys_var->current_mutex = mutex;
mysys_var->current_cond = cond;
proc_info = msg;
@@ -1009,7 +1310,7 @@ public:
inline ulonglong insert_id(void)
{
if (!last_insert_id_used)
- {
+ {
last_insert_id_used=1;
current_insert_id=last_insert_id;
}
@@ -1018,19 +1319,25 @@ public:
inline ulonglong found_rows(void)
{
return limit_found_rows;
- }
+ }
inline bool active_transaction()
{
-#ifdef USING_TRANSACTIONS
- return (transaction.all.bdb_tid != 0 ||
- transaction.all.innodb_active_trans != 0 ||
- transaction.all.ndb_tid != 0);
+#ifdef USING_TRANSACTIONS
+ return server_status & SERVER_STATUS_IN_TRANS;
#else
return 0;
#endif
}
- inline gptr trans_alloc(unsigned int size)
- {
+ inline bool only_prepare()
+ {
+ return command == COM_PREPARE;
+ }
+ inline bool fill_derived_tables()
+ {
+ return !only_prepare() && !lex->only_view_structure();
+ }
+ inline gptr trans_alloc(unsigned int size)
+ {
return alloc_root(&transaction.mem_root,size);
}
@@ -1050,6 +1357,7 @@ public:
net.last_error[0]= 0;
net.last_errno= 0;
net.report_error= 0;
+ query_error= 0;
}
inline bool vio_ok() const { return net.vio != 0; }
#else
@@ -1071,7 +1379,7 @@ public:
use new arena if we are in a prepared statements and we have not
already changed to use this arena.
*/
- if (current_arena->is_stmt_prepare() &&
+ if (!current_arena->is_conventional() &&
mem_root != &current_arena->main_mem_root)
{
set_n_backup_item_arena(current_arena, backup);
@@ -1083,7 +1391,7 @@ public:
void change_item_tree(Item **place, Item *new_value)
{
/* TODO: check for OOM condition here */
- if (!current_arena->is_conventional_execution())
+ if (!current_arena->is_conventional())
nocheck_register_item_tree_change(place, *place, mem_root);
*place= new_value;
}
@@ -1096,6 +1404,24 @@ public:
state after execution of a non-prepared SQL statement.
*/
void end_statement();
+ inline int killed_errno() const
+ {
+ return killed != KILL_BAD_DATA ? killed : 0;
+ }
+ inline void send_kill_message() const
+ {
+ int err= killed_errno();
+ if (err)
+ my_message(err, ER(err), MYF(0));
+ }
+ /* return TRUE if we will abort query if we make a warning now */
+ inline bool really_abort_on_warning()
+ {
+ return (abort_on_warning &&
+ (!no_trans_update ||
+ (variables.sql_mode & MODE_STRICT_ALL_TABLES)));
+ }
+ void set_status_var_init();
};
#define tmp_disable_binlog(A) \
@@ -1134,8 +1460,6 @@ public:
class JOIN;
-void send_error(THD *thd, uint sql_errno=0, const char *err=0);
-
class select_result :public Sql_alloc {
protected:
THD *thd;
@@ -1148,6 +1472,7 @@ public:
unit= u;
return 0;
}
+ virtual int prepare2(void) { return 0; }
/*
Because of peculiarities of prepared statements protocol
we need to know number of columns in the result set (if
@@ -1155,11 +1480,12 @@ public:
*/
virtual uint field_count(List<Item> &fields) const
{ return fields.elements; }
- virtual bool send_fields(List<Item> &list,uint flag)=0;
+ virtual bool send_fields(List<Item> &list, uint flags)=0;
virtual bool send_data(List<Item> &items)=0;
virtual bool initialize_tables (JOIN *join=0) { return 0; }
virtual void send_error(uint errcode,const char *err);
virtual bool send_eof()=0;
+ virtual bool simple_select() { return 0; }
virtual void abort() {}
/*
Cleanup instance of this class for next execution of a prepared
@@ -1186,9 +1512,10 @@ public:
class select_send :public select_result {
public:
select_send() {}
- bool send_fields(List<Item> &list,uint flag);
+ bool send_fields(List<Item> &list, uint flags);
bool send_data(List<Item> &items);
bool send_eof();
+ bool simple_select() { return 1; }
};
@@ -1232,32 +1559,20 @@ public:
class select_insert :public select_result_interceptor {
public:
+ TABLE_LIST *table_list;
TABLE *table;
List<Item> *fields;
ulonglong last_insert_id;
COPY_INFO info;
+ bool insert_into_view;
- select_insert(TABLE *table_par, List<Item> *fields_par,
- enum_duplicates duplic, bool ignore)
- :table(table_par), fields(fields_par), last_insert_id(0)
- {
- bzero((char*) &info,sizeof(info));
- info.ignore= ignore;
- info.handle_duplicates=duplic;
- }
- select_insert(TABLE *table_par, List<Item> *fields_par,
+ select_insert(TABLE_LIST *table_list_par,
+ TABLE *table_par, List<Item> *fields_par,
List<Item> *update_fields, List<Item> *update_values,
- enum_duplicates duplic, bool ignore)
- :table(table_par), fields(fields_par), last_insert_id(0)
- {
- bzero((char*) &info,sizeof(info));
- info.ignore= ignore;
- info.handle_duplicates= duplic;
- info.update_fields= update_fields;
- info.update_values= update_values;
- }
+ enum_duplicates duplic, bool ignore);
~select_insert();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
+ int prepare2(void);
bool send_data(List<Item> &items);
virtual void store_values(List<Item> &values);
void send_error(uint errcode,const char *err);
@@ -1269,22 +1584,21 @@ class select_insert :public select_result_interceptor {
class select_create: public select_insert {
ORDER *group;
- const char *db;
- const char *name;
+ TABLE_LIST *create_table;
List<create_field> *extra_fields;
List<Key> *keys;
HA_CREATE_INFO *create_info;
MYSQL_LOCK *lock;
Field **field;
public:
- select_create(const char *db_name, const char *table_name,
- HA_CREATE_INFO *create_info_par,
- List<create_field> &fields_par,
- List<Key> &keys_par,
- List<Item> &select_fields,enum_duplicates duplic, bool ignore)
- :select_insert (NULL, &select_fields, duplic, ignore), db(db_name),
- name(table_name), extra_fields(&fields_par),keys(&keys_par),
- create_info(create_info_par), lock(0)
+ select_create (TABLE_LIST *table,
+ HA_CREATE_INFO *create_info_par,
+ List<create_field> &fields_par,
+ List<Key> &keys_par,
+ List<Item> &select_fields,enum_duplicates duplic, bool ignore)
+ :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore), create_table(table),
+ extra_fields(&fields_par),keys(&keys_par), create_info(create_info_par),
+ lock(0)
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
void store_values(List<Item> &values);
@@ -1325,10 +1639,13 @@ public:
bool using_indirect_summary_function;
/* If >0 convert all blob fields to varchar(convert_blob_length) */
uint convert_blob_length;
+ CHARSET_INFO *table_charset;
+ bool schema_table;
TMP_TABLE_PARAM()
:copy_field(0), group_parts(0),
- group_length(0), group_null_parts(0), convert_blob_length(0)
+ group_length(0), group_null_parts(0), convert_blob_length(0),
+ schema_table(0)
{}
~TMP_TABLE_PARAM()
{
@@ -1348,7 +1665,6 @@ public:
class select_union :public select_result_interceptor {
public:
TABLE *table;
- COPY_INFO info;
TMP_TABLE_PARAM tmp_table_param;
select_union(TABLE *table_par);
@@ -1393,6 +1709,7 @@ public:
bool send_data(List<Item> &items);
bool cmp_real();
bool cmp_int();
+ bool cmp_decimal();
bool cmp_str();
};
@@ -1463,17 +1780,24 @@ class user_var_entry
public:
LEX_STRING name;
char *value;
- ulong length, update_query_id, used_query_id;
+ ulong length;
+ query_id_t update_query_id, used_query_id;
Item_result type;
- double val(my_bool *null_value);
+ double val_real(my_bool *null_value);
longlong val_int(my_bool *null_value);
String *val_str(my_bool *null_value, String *str, uint decimals);
+ my_decimal *val_decimal(my_bool *null_value, my_decimal *result);
DTCollation collation;
};
-
-/* Class for unique (removing of duplicates) */
+/*
+ Unique -- class for unique (removing of duplicates).
+ Puts all values to the TREE. If the tree becomes too big,
+ it's dumped to the file. User can request sorted values, or
+ just iterate through them. In the last case tree merging is performed in
+ memory simultaneously with iteration, so it should be ~2-3x faster.
+ */
class Unique :public Sql_alloc
{
@@ -1487,17 +1811,32 @@ class Unique :public Sql_alloc
public:
ulong elements;
- Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
+ Unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
uint size_arg, ulong max_in_memory_size_arg);
~Unique();
- inline bool unique_add(gptr ptr)
+ ulong elements_in_tree() { return tree.elements_in_tree; }
+ inline bool unique_add(void *ptr)
{
+ DBUG_ENTER("unique_add");
+ DBUG_PRINT("info", ("tree %u - %u", tree.elements_in_tree, max_elements));
if (tree.elements_in_tree > max_elements && flush())
- return 1;
- return !tree_insert(&tree, ptr, 0, tree.custom_arg);
+ DBUG_RETURN(1);
+ DBUG_RETURN(!tree_insert(&tree, ptr, 0, tree.custom_arg));
}
bool get(TABLE *table);
+ static double get_use_cost(uint *buffer, uint nkeys, uint key_size,
+ ulong max_in_memory_size);
+ inline static int get_cost_calc_buff_size(ulong nkeys, uint key_size,
+ ulong max_in_memory_size)
+ {
+ register ulong max_elems_in_tree=
+ (1 + max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size));
+ return sizeof(uint)*(1 + nkeys/max_elems_in_tree);
+ }
+
+ void reset();
+ bool walk(tree_walk_action action, void *walk_action_arg);
friend int unique_write_to_file(gptr key, element_count count, Unique *unique);
friend int unique_write_to_ptrs(gptr key, element_count count, Unique *unique);
@@ -1512,7 +1851,7 @@ class multi_delete :public select_result_interceptor
ha_rows deleted, found;
uint num_of_tables;
int error;
- bool do_delete, transactional_tables, log_delayed, normal_tables;
+ bool do_delete, transactional_tables, normal_tables;
public:
multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
~multi_delete();
@@ -1527,7 +1866,9 @@ public:
class multi_update :public select_result_interceptor
{
- TABLE_LIST *all_tables, *update_tables, *table_being_updated;
+ TABLE_LIST *all_tables; /* query/update command tables */
+ TABLE_LIST *leaves; /* list of leves of join table tree */
+ TABLE_LIST *update_tables, *table_being_updated;
THD *thd;
TABLE **tmp_tables, *main_table, *table_to_update;
TMP_TABLE_PARAM *tmp_table_param;
@@ -1537,11 +1878,12 @@ class multi_update :public select_result_interceptor
uint table_count;
Copy_field *copy_field;
enum enum_duplicates handle_duplicates;
- bool do_update, trans_safe, transactional_tables, log_delayed, ignore;
+ bool do_update, trans_safe, transactional_tables, ignore;
public:
- multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> *fields,
- List<Item> *values, enum_duplicates handle_duplicates, bool ignore);
+ multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list,
+ List<Item> *fields, List<Item> *values,
+ enum_duplicates handle_duplicates, bool ignore);
~multi_update();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
@@ -1551,16 +1893,32 @@ public:
bool send_eof();
};
+class my_var : public Sql_alloc {
+public:
+ LEX_STRING s;
+ bool local;
+ uint offset;
+ enum_field_types type;
+ my_var (LEX_STRING& j, bool i, uint o, enum_field_types t)
+ :s(j), local(i), offset(o), type(t)
+ {}
+ ~my_var() {}
+};
class select_dumpvar :public select_result_interceptor {
ha_rows row_count;
public:
- List<LEX_STRING> var_list;
+ List<my_var> var_list;
List<Item_func_set_user_var> vars;
- select_dumpvar(void) { var_list.empty(); vars.empty(); row_count=0;}
+ List<Item_splocal> local_vars;
+ select_dumpvar(void) { var_list.empty(); local_vars.empty(); vars.empty(); row_count=0;}
~select_dumpvar() {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
bool send_eof();
void cleanup();
};
+
+/* Functions in sql_class.cc */
+
+void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index c918480812c..3bdd800cd2f 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -19,6 +19,7 @@
#include "mysql_priv.h"
#include <mysys_err.h>
+#include "sp.h"
#include <my_dir.h>
#include <m_ctype.h>
#ifdef __WIN__
@@ -32,7 +33,8 @@ static TYPELIB deletable_extentions=
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
const char *db, const char *path,
uint level);
-
+static long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path);
+static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error);
/* Database options hash */
static HASH dboptions;
static my_bool dboptions_init= 0;
@@ -371,13 +373,13 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
In this case the entry should not be logged.
RETURN VALUES
- 0 ok
- -1 Error
+ FALSE ok
+ TRUE Error
*/
-int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
- bool silent)
+bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
+ bool silent)
{
char path[FN_REFLEN+16];
long result= 1;
@@ -386,6 +388,13 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
uint create_options= create_info ? create_info->options : 0;
uint path_len;
DBUG_ENTER("mysql_create_db");
+
+ /* do not create 'information_schema' db */
+ if (!my_strcasecmp(system_charset_info, db, information_schema_name.str))
+ {
+ my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
+ DBUG_RETURN(-1);
+ }
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
@@ -405,7 +414,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
{
if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
{
- my_error(ER_DB_CREATE_EXISTS,MYF(0),db);
+ my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
error= -1;
goto exit;
}
@@ -415,12 +424,12 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
{
if (my_errno != ENOENT)
{
- my_error(EE_STAT, MYF(0),path,my_errno);
+ my_error(EE_STAT, MYF(0), path, my_errno);
goto exit;
}
if (my_mkdir(path,0777,MYF(0)) < 0)
{
- my_error(ER_CANT_CREATE_DB,MYF(0),db,my_errno);
+ my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
error= -1;
goto exit;
}
@@ -463,7 +472,6 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
query= thd->query;
query_length= thd->query_length;
}
- mysql_update_log.write(thd, query, query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, query, query_length, 0,
@@ -504,7 +512,7 @@ exit2:
/* db-name is already validated when we come here */
-int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
+bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
{
char path[FN_REFLEN+16];
long result=1;
@@ -535,7 +543,6 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
thd->variables.collation_database= thd->db_charset;
}
- mysql_update_log.write(thd,thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0,
@@ -558,7 +565,7 @@ exit:
start_waiting_global_read_lock(thd);
exit2:
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
- DBUG_RETURN(error ? -1 : 0); /* -1 to delegate send_error() */
+ DBUG_RETURN(error);
}
@@ -569,20 +576,21 @@ exit2:
mysql_rm_db()
thd Thread handle
db Database name in the case given by user
- It's already validated when we come here
+ It's already validated and set to lower case
+ (if needed) when we come here
if_exists Don't give error if database doesn't exists
silent Don't generate errors
RETURN
- 0 ok (Database dropped)
- -1 Error generated
+ FALSE ok (Database dropped)
+ ERROR Error
*/
-int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
+bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
{
long deleted=0;
int error= 0;
- char path[FN_REFLEN+16], tmp_db[NAME_LEN+1];
+ char path[FN_REFLEN+16];
MY_DIR *dirp;
uint length;
DBUG_ENTER("mysql_rm_db");
@@ -608,7 +616,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if (!if_exists)
{
error= -1;
- my_error(ER_DB_DROP_EXISTS,MYF(0),db);
+ my_error(ER_DB_DROP_EXISTS, MYF(0), db);
goto exit;
}
else
@@ -629,13 +637,6 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
error = 0;
}
}
- if (lower_case_table_names)
- {
- /* Convert database to lower case */
- strmov(tmp_db, db);
- my_casedn_str(files_charset_info, tmp_db);
- db= tmp_db;
- }
if (!silent && deleted>=0)
{
const char *query;
@@ -652,7 +653,6 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
query =thd->query;
query_length= thd->query_length;
}
- mysql_update_log.write(thd, query, query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, query, query_length, 0,
@@ -674,6 +674,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
exit:
+ (void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
start_waiting_global_read_lock(thd);
/*
If this database was the client's selected database, we silently change the
@@ -742,9 +743,9 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
continue;
/* Check if file is a raid directory */
- if ((my_isdigit(&my_charset_latin1, file->name[0]) ||
+ if ((my_isdigit(system_charset_info, file->name[0]) ||
(file->name[0] >= 'a' && file->name[0] <= 'f')) &&
- (my_isdigit(&my_charset_latin1, file->name[1]) ||
+ (my_isdigit(system_charset_info, file->name[1]) ||
(file->name[1] >= 'a' && file->name[1] <= 'f')) &&
!file->name[2] && !level)
{
@@ -770,6 +771,24 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
found_other_files++;
continue;
}
+ else if (file->name[0] == 'a' && file->name[1] == 'r' &&
+ file->name[2] == 'c' && file->name[3] == '\0')
+ {
+ /* .frm archive */
+ char newpath[FN_REFLEN];
+ MY_DIR *new_dirp;
+ strxmov(newpath, org_path, "/", "arc", NullS);
+ (void) unpack_filename(newpath, newpath);
+ if ((new_dirp = my_dir(newpath, MYF(MY_DONT_SORT))))
+ {
+ DBUG_PRINT("my",("Archive subdir found: %s", newpath));
+ if ((mysql_rm_arc_files(thd, new_dirp, newpath)) < 0)
+ goto err;
+ continue;
+ }
+ found_other_files++;
+ continue;
+ }
extension= fn_ext(file->name);
if (find_type(extension, &deletable_extentions,1+2) <= 0)
{
@@ -788,11 +807,11 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
if (!table_list)
goto err;
table_list->db= (char*) (table_list+1);
- strmov(table_list->real_name= strmov(table_list->db,db)+1, file->name);
- table_list->alias= table_list->real_name; // If lower_case_table_names=2
+ strmov(table_list->table_name= strmov(table_list->db,db)+1, file->name);
+ table_list->alias= table_list->table_name; // If lower_case_table_names=2
/* Link into list */
(*tot_list_next)= table_list;
- tot_list_next= &table_list->next;
+ tot_list_next= &table_list->next_local;
deleted++;
}
else
@@ -829,44 +848,141 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
}
else
{
- char tmp_path[FN_REFLEN], *pos;
- char *path= tmp_path;
- unpack_filename(tmp_path,org_path);
+ /* Don't give errors if we can't delete 'RAID' directory */
+ if (rm_dir_w_symlink(org_path, level == 0))
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_RETURN(deleted);
+
+err:
+ my_dirend(dirp);
+ DBUG_RETURN(-1);
+}
+
+
+/*
+ Remove directory with symlink
+
+ SYNOPSIS
+ rm_dir_w_symlink()
+ org_path path of derictory
+ send_error send errors
+ RETURN
+ 0 OK
+ 1 ERROR
+*/
+
+static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error)
+{
+ char tmp_path[FN_REFLEN], *pos;
+ char *path= tmp_path;
+ DBUG_ENTER("rm_dir_w_symlink");
+ unpack_filename(tmp_path, org_path);
#ifdef HAVE_READLINK
- int error;
-
- /* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */
- pos=strend(path);
- if (pos > path && pos[-1] == FN_LIBCHAR)
- *--pos=0;
+ int error;
+ char tmp2_path[FN_REFLEN];
- if ((error=my_readlink(filePath, path, MYF(MY_WME))) < 0)
- DBUG_RETURN(-1);
- if (!error)
+ /* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */
+ pos= strend(path);
+ if (pos > path && pos[-1] == FN_LIBCHAR)
+ *--pos=0;
+
+ if ((error= my_readlink(tmp2_path, path, MYF(MY_WME))) < 0)
+ DBUG_RETURN(1);
+ if (!error)
+ {
+ if (my_delete(path, MYF(send_error ? MY_WME : 0)))
{
- if (my_delete(path,MYF(!level ? MY_WME : 0)))
- {
- /* Don't give errors if we can't delete 'RAID' directory */
- if (level)
- DBUG_RETURN(deleted);
- DBUG_RETURN(-1);
- }
- /* Delete directory symbolic link pointed at */
- path= filePath;
+ DBUG_RETURN(send_error);
}
+ /* Delete directory symbolic link pointed at */
+ path= tmp2_path;
+ }
#endif
- /* Remove last FN_LIBCHAR to not cause a problem on OS/2 */
- pos=strend(path);
+ /* Remove last FN_LIBCHAR to not cause a problem on OS/2 */
+ pos= strend(path);
- if (pos > path && pos[-1] == FN_LIBCHAR)
- *--pos=0;
- /* Don't give errors if we can't delete 'RAID' directory */
- if (rmdir(path) < 0 && !level)
+ if (pos > path && pos[-1] == FN_LIBCHAR)
+ *--pos=0;
+ if (rmdir(path) < 0 && send_error)
+ {
+ my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Remove .frm archives from directory
+
+ SYNOPSIS
+ thd thread handler
+ dirp list of files in archive directory
+ db data base name
+ org_path path of archive directory
+
+ RETURN
+ > 0 number of removed files
+ -1 error
+*/
+static long mysql_rm_arc_files(THD *thd, MY_DIR *dirp,
+ const char *org_path)
+{
+ long deleted= 0;
+ ulong found_other_files= 0;
+ char filePath[FN_REFLEN];
+ DBUG_ENTER("mysql_rm_arc_files");
+ DBUG_PRINT("enter", ("path: %s", org_path));
+
+ for (uint idx=0 ;
+ idx < (uint) dirp->number_off_files && !thd->killed ;
+ idx++)
+ {
+ FILEINFO *file=dirp->dir_entry+idx;
+ char *extension, *revision;
+ DBUG_PRINT("info",("Examining: %s", file->name));
+
+ /* skiping . and .. */
+ if (file->name[0] == '.' && (!file->name[1] ||
+ (file->name[1] == '.' && !file->name[2])))
+ continue;
+
+ extension= fn_ext(file->name);
+ if (extension[0] != '.' ||
+ extension[1] != 'f' || extension[2] != 'r' ||
+ extension[3] != 'm' || extension[4] != '-')
{
- my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
- DBUG_RETURN(-1);
+ found_other_files++;
+ continue;
+ }
+ revision= extension+5;
+ while (*revision && my_isdigit(system_charset_info, *revision))
+ revision++;
+ if (*revision)
+ {
+ found_other_files++;
+ continue;
+ }
+ strxmov(filePath, org_path, "/", file->name, NullS);
+ if (my_delete_with_symlink(filePath,MYF(MY_WME)))
+ {
+ goto err;
}
}
+ if (thd->killed)
+ goto err;
+
+ my_dirend(dirp);
+
+ /*
+ If the directory is a symbolic link, remove the link first, then
+ remove the directory the symbolic link pointed at
+ */
+ if (!found_other_files &&
+ rm_dir_w_symlink(org_path, 0))
+ DBUG_RETURN(-1);
DBUG_RETURN(deleted);
err:
@@ -893,6 +1009,9 @@ err:
replication slave SQL thread (for that thread, setting of thd->db is done
in ::exec_event() methods of log_event.cc).
+ This function does not send the error message to the client, if that
+ should be sent to the client, call net_send_error after this function
+
RETURN VALUES
0 ok
1 error
@@ -904,6 +1023,7 @@ bool mysql_change_db(THD *thd, const char *name)
char *dbname=my_strdup((char*) name,MYF(MY_WME));
char path[FN_REFLEN];
HA_CREATE_INFO create;
+ bool schema_db= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access;
#endif
@@ -912,16 +1032,26 @@ bool mysql_change_db(THD *thd, const char *name)
if (!dbname || !(db_length= strlen(dbname)))
{
x_free(dbname); /* purecov: inspected */
- send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
+ MYF(0)); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
if (check_db_name(dbname))
{
- net_printf(thd, ER_WRONG_DB_NAME, dbname);
+ my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
x_free(dbname);
DBUG_RETURN(1);
}
DBUG_PRINT("info",("Use database: %s", dbname));
+ if (!my_strcasecmp(system_charset_info, dbname, information_schema_name.str))
+ {
+ schema_db= 1;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ db_access= SELECT_ACL;
+#endif
+ goto end;
+ }
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (test_all_bits(thd->master_access,DB_ACLS))
db_access=DB_ACLS;
@@ -930,10 +1060,10 @@ bool mysql_change_db(THD *thd, const char *name)
thd->master_access);
if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
{
- net_printf(thd,ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->priv_host,
- dbname);
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user,
+ thd->priv_host,
+ dbname);
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
thd->priv_user,
thd->priv_host,
@@ -948,10 +1078,11 @@ bool mysql_change_db(THD *thd, const char *name)
path[length-1]=0; // remove ending '\'
if (access(path,F_OK))
{
- net_printf(thd,ER_BAD_DB_ERROR,dbname);
+ my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
my_free(dbname,MYF(0));
DBUG_RETURN(1);
}
+end:
send_ok(thd);
x_free(thd->db);
thd->db=dbname; // THD::~THD will free this
@@ -959,11 +1090,19 @@ bool mysql_change_db(THD *thd, const char *name)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
thd->db_access=db_access;
#endif
- strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
- load_db_opt(thd, path, &create);
- thd->db_charset= create.default_table_charset ?
- create.default_table_charset :
- thd->variables.collation_server;
- thd->variables.collation_database= thd->db_charset;
+ if (schema_db)
+ {
+ thd->db_charset= system_charset_info;
+ thd->variables.collation_database= system_charset_info;
+ }
+ else
+ {
+ strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
+ load_db_opt(thd, path, &create);
+ thd->db_charset= create.default_table_charset ?
+ create.default_table_charset :
+ thd->variables.collation_server;
+ thd->variables.collation_database= thd->db_charset;
+ }
DBUG_RETURN(0);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 0752105bcae..d524bbcf164 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -26,42 +26,58 @@
#include "mysql_priv.h"
#include "ha_innodb.h"
#include "sql_select.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
-int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
- ha_rows limit, ulong options)
+bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
+ SQL_LIST *order, ha_rows limit, ulong options)
{
int error;
TABLE *table;
SQL_SELECT *select=0;
READ_RECORD info;
- bool using_limit=limit != HA_POS_ERROR;
- bool transactional_table, log_delayed, safe_update, const_cond;
+ bool using_limit=limit != HA_POS_ERROR;
+ bool transactional_table, safe_update, const_cond;
ha_rows deleted;
+ SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_delete");
- if ((open_and_lock_tables(thd, table_list)))
+ if (open_and_lock_tables(thd, table_list))
+ DBUG_RETURN(TRUE);
+ if (!(table= table_list->table))
+ {
+ DBUG_ASSERT(table_list->view &&
+ table_list->ancestor && table_list->ancestor->next_local);
+ my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
+ table_list->view_db.str, table_list->view_name.str);
DBUG_RETURN(-1);
- table= table_list->table;
+ }
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
table->map=1;
- if ((error= mysql_prepare_delete(thd, table_list, &conds)))
- DBUG_RETURN(error);
+ if (mysql_prepare_delete(thd, table_list, &conds))
+ DBUG_RETURN(TRUE);
const_cond= (!conds || conds->const_item());
safe_update=test(thd->options & OPTION_SAFE_UPDATES);
if (safe_update && const_cond)
{
- send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
- DBUG_RETURN(1);
+ my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
+ ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
+ DBUG_RETURN(TRUE);
}
- thd->lex->select_lex.no_error= thd->lex->ignore;
+ select_lex->no_error= thd->lex->ignore;
- /* Test if the user wants to delete all rows */
+ /*
+ Test if the user wants to delete all rows and deletion doesn't have
+ any side-effects (because of triggers), so we can use optimized
+ handler::delete_all_rows() method.
+ */
if (!using_limit && const_cond && (!conds || conds->val_int()) &&
- !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)))
+ !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
+ !(table->triggers && table->triggers->has_delete_triggers()))
{
deleted= table->file->records;
if (!(error=table->file->delete_all_rows()))
@@ -80,13 +96,14 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
table->used_keys.clear_all();
table->quick_keys.clear_all(); // Can't use 'only index'
- select=make_select(table,0,0,conds,&error);
+ select=make_select(table, 0, 0, conds, 0, &error);
if (error)
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
{
delete select;
- free_underlaid_joins(thd, &thd->lex->select_lex);
+ free_underlaid_joins(thd, select_lex);
+ thd->row_count_func= 0;
send_ok(thd,0L);
DBUG_RETURN(0); // Nothing to delete
}
@@ -98,9 +115,10 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
if (safe_update && !using_limit)
{
delete select;
- free_underlaid_joins(thd, &thd->lex->select_lex);
- send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
- DBUG_RETURN(1);
+ free_underlaid_joins(thd, select_lex);
+ my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
+ ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
+ DBUG_RETURN(TRUE);
}
}
if (options & OPTION_QUICK)
@@ -121,8 +139,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
- if (thd->lex->select_lex.setup_ref_array(thd, order->elements) ||
- setup_order(thd, thd->lex->select_lex.ref_pointer_array, &tables,
+ if (select_lex->setup_ref_array(thd, order->elements) ||
+ setup_order(thd, select_lex->ref_pointer_array, &tables,
fields, all_fields, (ORDER*) order->first) ||
!(sortorder=make_unireg_sortorder((ORDER*) order->first, &length)) ||
(table->sort.found_records = filesort(thd, table, sortorder, length,
@@ -131,8 +149,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
== HA_POS_ERROR)
{
delete select;
- free_underlaid_joins(thd, &thd->lex->select_lex);
- DBUG_RETURN(-1); // This will force out message
+ free_underlaid_joins(thd, select_lex);
+ DBUG_RETURN(TRUE);
}
/*
Filesort has already found and selected the rows we want to delete,
@@ -142,9 +160,16 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
select= 0;
}
+ /* If quick select is used, initialize it before retrieving rows. */
+ if (select && select->quick && select->quick->reset())
+ {
+ delete select;
+ free_underlaid_joins(thd, select_lex);
+ DBUG_RETURN(TRUE);
+ }
init_read_record(&info,thd,table,select,1,1);
deleted=0L;
- init_ftfuncs(thd, &thd->lex->select_lex, 1);
+ init_ftfuncs(thd, select_lex, 1);
thd->proc_info="updating";
while (!(error=info.read_record(&info)) && !thd->killed &&
!thd->net.report_error)
@@ -152,6 +177,11 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
// thd->net.report_error is tested to disallow delete row on error
if (!(select && select->skip_record())&& !thd->net.report_error )
{
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
+ TRG_ACTION_BEFORE);
+
if (!(error=table->file->delete_row(table->record[0])))
{
deleted++;
@@ -175,6 +205,10 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
error= 1;
break;
}
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
+ TRG_ACTION_AFTER);
}
else
table->file->unlock_row(); // Row failed selection, release lock on it
@@ -199,7 +233,6 @@ cleanup:
delete select;
transactional_table= table->file->has_transactions();
- log_delayed= (transactional_table || table->tmp_table);
/*
We write to the binary log even if we deleted no row, because maybe the
user is using this command to ensure that a table is clean on master *and
@@ -210,17 +243,16 @@ cleanup:
*/
if ((deleted || (error < 0)) && (error <= 0 || !transactional_table))
{
- mysql_update_log.write(thd,thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed, FALSE);
+ transactional_table, FALSE);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1;
}
- if (!log_delayed)
+ if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (transactional_table)
@@ -234,15 +266,14 @@ cleanup:
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
- free_underlaid_joins(thd, &thd->lex->select_lex);
- if (error >= 0 || thd->net.report_error)
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0);
- else
+ free_underlaid_joins(thd, select_lex);
+ if (error < 0)
{
+ thd->row_count_func= deleted;
send_ok(thd,deleted);
DBUG_PRINT("info",("%d records deleted",deleted));
}
- DBUG_RETURN(0);
+ DBUG_RETURN(error >= 0 || thd->net.report_error);
}
@@ -252,30 +283,35 @@ cleanup:
SYNOPSIS
mysql_prepare_delete()
thd - thread handler
- table_list - global table list
+ table_list - global/local table list
conds - conditions
RETURN VALUE
- 0 - OK
- 1 - error (message is sent to user)
- -1 - error (message is not sent to user)
+ FALSE OK
+ TRUE error
*/
-int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
+bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
{
- TABLE_LIST *delete_table_list= ((TABLE_LIST*) thd->lex->
- select_lex.table_list.first);
+ SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete");
- if (setup_conds(thd, delete_table_list, conds) ||
- setup_ftfuncs(&thd->lex->select_lex))
- DBUG_RETURN(-1);
- if (find_real_table_in_list(table_list->next,
- table_list->db, table_list->real_name))
+ if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables,
+ FALSE, FALSE) ||
+ setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
+ setup_ftfuncs(select_lex))
+ DBUG_RETURN(TRUE);
+ if (!table_list->updatable || check_key_in_view(thd, table_list))
{
- my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
- DBUG_RETURN(-1);
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(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, conds);
+ DBUG_RETURN(FALSE);
}
@@ -285,17 +321,90 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
-extern "C" int refposcmp2(void* arg, const void *a,const void *b)
+extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
+{
+ handler *file= (handler*)arg;
+ return file->cmp_ref((const byte*)a, (const byte*)b);
+}
+
+/*
+ make delete specific preparation and checks after opening tables
+
+ SYNOPSIS
+ mysql_multi_delete_prepare()
+ thd thread handler
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool mysql_multi_delete_prepare(THD *thd)
{
- /* arg is a pointer to file->ref_length */
- return memcmp(a,b, *(int*) arg);
+ LEX *lex= thd->lex;
+ TABLE_LIST *aux_tables= (TABLE_LIST *)lex->auxilliary_table_list.first;
+ TABLE_LIST *target_tbl;
+ DBUG_ENTER("mysql_multi_delete_prepare");
+
+ /*
+ setup_tables() need for VIEWs. JOIN::prepare() will not do it second
+ time.
+
+ lex->query_tables also point on local list of DELETE SELECT_LEX
+ */
+ if (setup_tables(thd, lex->query_tables, &lex->select_lex.where,
+ &lex->select_lex.leaf_tables, FALSE, FALSE))
+ DBUG_RETURN(TRUE);
+
+
+ /*
+ Multi-delete can't be constructed over-union => we always have
+ single SELECT on top and have to check underlying SELECTs of it
+ */
+ lex->select_lex.exclude_from_table_unique_test= TRUE;
+ /* Fix tables-to-be-deleted-from list to point at opened tables */
+ for (target_tbl= (TABLE_LIST*) aux_tables;
+ target_tbl;
+ target_tbl= target_tbl->next_local)
+ {
+ if (!(target_tbl->table= target_tbl->correspondent_table->table))
+ {
+ DBUG_ASSERT(target_tbl->correspondent_table->view &&
+ target_tbl->correspondent_table->ancestor &&
+ target_tbl->correspondent_table->ancestor->next_local);
+ my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
+ target_tbl->correspondent_table->view_db.str,
+ target_tbl->correspondent_table->view_name.str);
+ DBUG_RETURN(TRUE);
+ }
+
+ if (!target_tbl->correspondent_table->updatable ||
+ check_key_in_view(thd, target_tbl->correspondent_table))
+ {
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
+ target_tbl->table_name, "DELETE");
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Check that table from which we delete is not used somewhere
+ inside subqueries/view.
+ */
+ if (unique_table(target_tbl->correspondent_table, lex->query_tables))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0),
+ target_tbl->correspondent_table->table_name);
+ DBUG_RETURN(TRUE);
+ }
+ }
+ DBUG_RETURN(FALSE);
}
+
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
uint num_of_tables_arg)
: delete_tables(dt), thd(thd_arg), deleted(0), found(0),
num_of_tables(num_of_tables_arg), error(0),
- do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0)
+ do_delete(0), transactional_tables(0), normal_tables(0)
{
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
}
@@ -323,7 +432,7 @@ multi_delete::initialize_tables(JOIN *join)
DBUG_RETURN(1);
table_map tables_to_delete_from=0;
- for (walk= delete_tables ; walk ; walk=walk->next)
+ for (walk= delete_tables; walk; walk= walk->next_local)
tables_to_delete_from|= walk->table->map;
walk= delete_tables;
@@ -335,27 +444,25 @@ multi_delete::initialize_tables(JOIN *join)
{
/* We are going to delete from this table */
TABLE *tbl=walk->table=tab->table;
- walk=walk->next;
+ walk= walk->next_local;
/* Don't use KEYREAD optimization on this table */
tbl->no_keyread=1;
/* Don't use record cache */
tbl->no_cache= 1;
tbl->used_keys.clear_all();
if (tbl->file->has_transactions())
- log_delayed= transactional_tables= 1;
- else if (tbl->tmp_table != NO_TMP_TABLE)
- log_delayed= 1;
+ transactional_tables= 1;
else
normal_tables= 1;
}
}
walk= delete_tables;
tempfiles_ptr= tempfiles;
- for (walk=walk->next ; walk ; walk=walk->next)
+ for (walk= walk->next_local ;walk ;walk= walk->next_local)
{
TABLE *table=walk->table;
- *tempfiles_ptr++= new Unique (refposcmp2,
- (void *) &table->file->ref_length,
+ *tempfiles_ptr++= new Unique (refpos_order_cmp,
+ (void *) table->file,
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
}
@@ -366,9 +473,9 @@ multi_delete::initialize_tables(JOIN *join)
multi_delete::~multi_delete()
{
- for (table_being_deleted=delete_tables ;
- table_being_deleted ;
- table_being_deleted=table_being_deleted->next)
+ for (table_being_deleted= delete_tables;
+ table_being_deleted;
+ table_being_deleted= table_being_deleted->next_local)
{
TABLE *t=table_being_deleted->table;
free_io_cache(t); // Alloced by unique
@@ -388,9 +495,9 @@ bool multi_delete::send_data(List<Item> &values)
int secure_counter= -1;
DBUG_ENTER("multi_delete::send_data");
- for (table_being_deleted=delete_tables ;
- table_being_deleted ;
- table_being_deleted=table_being_deleted->next, secure_counter++)
+ for (table_being_deleted= delete_tables;
+ table_being_deleted;
+ table_being_deleted= table_being_deleted->next_local, secure_counter++)
{
TABLE *table=table_being_deleted->table;
@@ -407,7 +514,8 @@ bool multi_delete::send_data(List<Item> &values)
table->status|= STATUS_DELETED;
if (!(error=table->file->delete_row(table->record[0])))
deleted++;
- else if (!table_being_deleted->next || table_being_deleted->table->file->has_transactions())
+ else if (!table_being_deleted->next_local ||
+ table_being_deleted->table->file->has_transactions())
{
table->file->print_error(error,MYF(0));
DBUG_RETURN(1);
@@ -432,7 +540,7 @@ void multi_delete::send_error(uint errcode,const char *err)
DBUG_ENTER("multi_delete::send_error");
/* First send error what ever it is ... */
- ::send_error(thd,errcode,err);
+ my_message(errcode, err, MYF(0));
/* If nothing deleted return */
if (!deleted)
@@ -477,9 +585,9 @@ int multi_delete::do_deletes(bool from_send_error)
if (from_send_error)
{
/* Found out table number for 'table_being_deleted*/
- for (TABLE_LIST *aux=delete_tables;
+ for (TABLE_LIST *aux= delete_tables;
aux != table_being_deleted;
- aux=aux->next)
+ aux= aux->next_local)
counter++;
}
else
@@ -488,9 +596,9 @@ int multi_delete::do_deletes(bool from_send_error)
do_delete= 0;
if (!found)
DBUG_RETURN(0);
- for (table_being_deleted=table_being_deleted->next;
- table_being_deleted ;
- table_being_deleted=table_being_deleted->next, counter++)
+ for (table_being_deleted= table_being_deleted->next_local;
+ table_being_deleted;
+ table_being_deleted= table_being_deleted->next_local, counter++)
{
TABLE *table = table_being_deleted->table;
if (tempfiles[counter]->get(table))
@@ -547,7 +655,9 @@ bool multi_delete::send_eof()
ha_autocommit_...
*/
if (deleted)
+ {
query_cache_invalidate3(thd, delete_tables, 1);
+ }
/*
Write the SQL statement to the binlog if we deleted
@@ -559,28 +669,28 @@ bool multi_delete::send_eof()
*/
if (deleted && (error <= 0 || normal_tables))
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed, FALSE);
+ transactional_tables, FALSE);
if (mysql_bin_log.write(&qinfo) && !normal_tables)
local_error=1; // Log write failed: roll back the SQL statement
}
- if (!log_delayed)
+ if (!transactional_tables)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
- /* Commit or rollback the current SQL statement */
+ /* Commit or rollback the current SQL statement */
if (transactional_tables)
if (ha_autocommit_or_rollback(thd,local_error > 0))
local_error=1;
- if (local_error)
- ::send_error(thd);
- else
+ if (!local_error)
+ {
+ thd->row_count_func= deleted;
::send_ok(thd, deleted);
+ }
return 0;
}
@@ -601,40 +711,40 @@ bool multi_delete::send_eof()
- If we want to have a name lock on the table on exit without errors.
*/
-int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
+bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
{
HA_CREATE_INFO create_info;
char path[FN_REFLEN];
TABLE **table_ptr;
- int error;
+ bool error;
DBUG_ENTER("mysql_truncate");
bzero((char*) &create_info,sizeof(create_info));
/* If it is a temporary table, close and regenerate it */
if (!dont_send_ok && (table_ptr=find_temporary_table(thd,table_list->db,
- table_list->real_name)))
+ table_list->table_name)))
{
TABLE *table= *table_ptr;
table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
- db_type table_type=table->db_type;
- strmov(path,table->path);
+ db_type table_type= table->s->db_type;
+ strmov(path, table->s->path);
*table_ptr= table->next; // Unlink table from list
close_temporary(table,0);
*fn_ext(path)=0; // Remove the .frm extension
ha_create_table(path, &create_info,1);
// We don't need to call invalidate() because this table is not in cache
if ((error= (int) !(open_temporary_table(thd, path, table_list->db,
- table_list->real_name, 1))))
+ table_list->table_name, 1))))
(void) rm_temporary_table(table_type, path);
/*
If we return here we will not have logged the truncation to the bin log
and we will not send_ok() to the client.
*/
- goto end;
+ goto end;
}
(void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db,
- table_list->real_name,reg_ext);
+ table_list->table_name,reg_ext);
fn_format(path,path,"","",4);
if (!dont_send_ok)
@@ -642,17 +752,18 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
db_type table_type;
if ((table_type=get_table_type(path)) == DB_TYPE_UNKNOWN)
{
- my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db,
- table_list->real_name);
- DBUG_RETURN(-1);
+ my_error(ER_NO_SUCH_TABLE, MYF(0),
+ table_list->db, table_list->table_name);
+ DBUG_RETURN(TRUE);
}
- if (!ha_supports_generate(table_type))
+ if (!ha_supports_generate(table_type) || thd->lex->sphead)
{
/* Probably InnoDB table */
ulong save_options= thd->options;
table_list->lock_type= TL_WRITE;
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
ha_enable_transaction(thd, FALSE);
+ mysql_init_select(thd->lex);
error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
HA_POS_ERROR, 0);
ha_enable_transaction(thd, TRUE);
@@ -660,24 +771,23 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
DBUG_RETURN(error);
}
if (lock_and_wait_for_table_name(thd, table_list))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
*fn_ext(path)=0; // Remove the .frm extension
- error= ha_create_table(path,&create_info,1) ? -1 : 0;
- query_cache_invalidate3(thd, table_list, 0);
+ error= ha_create_table(path,&create_info,1);
+ query_cache_invalidate3(thd, table_list, 0);
end:
if (!dont_send_ok)
{
if (!error)
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- thd->tmp_table, FALSE);
+ 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); // This should return record count
@@ -692,5 +802,5 @@ end:
unlock_table_name(thd, table_list);
VOID(pthread_mutex_unlock(&LOCK_open));
}
- DBUG_RETURN(error ? -1 : 0);
+ DBUG_RETURN(error);
}
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index e9f9b432c21..2ae293c1bff 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -24,15 +24,15 @@
#include "mysql_priv.h"
#include "sql_select.h"
-static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s,
- TABLE_LIST *t);
+
/*
- Resolve derived tables in all queries
+ call given derived table processor (preparing or filling tables)
SYNOPSIS
mysql_handle_derived()
lex LEX for this thread
+ processor procedure of derived table processing
RETURN
0 ok
@@ -41,25 +41,22 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s,
*/
int
-mysql_handle_derived(LEX *lex)
+mysql_handle_derived(LEX *lex, int (*processor)(THD*, LEX*, TABLE_LIST*))
{
+ int res= 0;
if (lex->derived_tables)
{
+ lex->thd->derived_tables_processing= TRUE;
for (SELECT_LEX *sl= lex->all_selects_list;
sl;
sl= sl->next_select_in_list())
{
for (TABLE_LIST *cursor= sl->get_table_list();
cursor;
- cursor= cursor->next)
+ cursor= cursor->next_local)
{
- int res;
- if (cursor->derived && (res=mysql_derived(lex->thd, lex,
- cursor->derived,
- cursor)))
- {
- return res;
- }
+ if ((res= (*processor)(lex->thd, lex, cursor)))
+ goto out;
}
if (lex->describe)
{
@@ -72,25 +69,23 @@ mysql_handle_derived(LEX *lex)
}
}
}
- return 0;
+out:
+ lex->thd->derived_tables_processing= FALSE;
+ return res;
}
/*
- Resolve derived tables in all queries
+ Create temporary table structure (but do not fill it)
SYNOPSIS
- mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
+ mysql_derived_prepare()
thd Thread handle
lex LEX for this thread
- unit node that contains all SELECT's for derived tables
- t TABLE_LIST for the upper SELECT
+ orig_table_list TABLE_LIST for the upper SELECT
IMPLEMENTATION
- Derived table is resolved with temporary table. It is created based on the
- queries defined. After temporary table is created, if this is not EXPLAIN,
- then the entire unit / node is deleted. unit is deleted if UNION is used
- for derived table and node is deleted is it is a simple SELECT.
+ Derived table is resolved with temporary table.
After table creation, the above TABLE_LIST is updated with a new table.
@@ -104,65 +99,149 @@ mysql_handle_derived(LEX *lex)
0 ok
1 Error
-1 Error and error message given
-*/
-
+ */
-static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
- TABLE_LIST *org_table_list)
+int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
{
- SELECT_LEX *first_select= unit->first_select();
- TABLE *table;
- int res;
- select_union *derived_result;
- bool is_union= first_select->next_select() &&
- first_select->next_select()->linkage == UNION_TYPE;
- SELECT_LEX *save_current_select= lex->current_select;
- DBUG_ENTER("mysql_derived");
-
- if (!(derived_result= new select_union(0)))
- DBUG_RETURN(1); // out of memory
-
- // st_select_lex_unit::prepare correctly work for single select
- if ((res= unit->prepare(thd, derived_result, 0, org_table_list->alias)))
- goto exit;
-
-
- derived_result->tmp_table_param.init();
- derived_result->tmp_table_param.field_count= unit->types.elements;
- /*
- Temp table is created so that it hounours if UNION without ALL is to be
- processed
-
- As 'distinct' parameter we always pass FALSE (0), because underlying
- query will control distinct condition by itself. Correct test of
- distinct underlying query will be is_union &&
- !unit->union_distinct->next_select() (i.e. it is union and last distinct
- SELECT is last SELECT of UNION).
- */
- if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
- unit->types, (ORDER*) 0,
- FALSE, 1,
- (first_select->options | thd->options |
- TMP_TABLE_ALL_COLUMNS),
- HA_POS_ERROR,
- org_table_list->alias)))
+ SELECT_LEX_UNIT *unit= orig_table_list->derived;
+ int res= 0;
+ DBUG_ENTER("mysql_derived_prepare");
+ if (unit)
{
- res= -1;
- goto exit;
+ SELECT_LEX *first_select= unit->first_select();
+ TABLE *table= 0;
+ select_union *derived_result;
+ bool is_union= first_select->next_select() &&
+ first_select->next_select()->linkage == UNION_TYPE;
+
+ if (!(derived_result= new select_union(0)))
+ DBUG_RETURN(1); // out of memory
+
+ // st_select_lex_unit::prepare correctly work for single select
+ if ((res= unit->prepare(thd, derived_result, 0, orig_table_list->alias)))
+ goto exit;
+
+
+ derived_result->tmp_table_param.init();
+ derived_result->tmp_table_param.field_count= unit->types.elements;
+ /*
+ Temp table is created so that it hounours if UNION without ALL is to be
+ processed
+
+ As 'distinct' parameter we always pass FALSE (0), because underlying
+ query will control distinct condition by itself. Correct test of
+ distinct underlying query will be is_union &&
+ !unit->union_distinct->next_select() (i.e. it is union and last distinct
+ SELECT is last SELECT of UNION).
+ */
+ if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
+ unit->types, (ORDER*) 0,
+ FALSE, 1,
+ (first_select->options | thd->options |
+ TMP_TABLE_ALL_COLUMNS),
+ HA_POS_ERROR,
+ orig_table_list->alias)))
+ {
+ res= -1;
+ goto exit;
+ }
+ derived_result->set_table(table);
+
+exit:
+ /* Hide "Unknown column" or "Unknown function" error */
+ if (orig_table_list->view)
+ {
+ if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
+ thd->net.last_errno == ER_SP_DOES_NOT_EXIST)
+ {
+ thd->clear_error();
+ my_error(ER_VIEW_INVALID, MYF(0), orig_table_list->db,
+ orig_table_list->table_name);
+ }
+ }
+
+ /*
+ if it is preparation PS only or commands that need only VIEW structure
+ then we do not need real data and we can skip execution (and parameters
+ is not defined, too)
+ */
+ if (res)
+ {
+ if (table)
+ free_tmp_table(thd, table);
+ delete derived_result;
+ }
+ else
+ {
+ if (!thd->fill_derived_tables())
+ {
+ delete derived_result;
+ derived_result= NULL;
+ }
+ orig_table_list->derived_result= derived_result;
+ orig_table_list->table= table;
+ orig_table_list->table_name= (char*) table->s->table_name;
+ orig_table_list->table_name_length= strlen((char*)table->s->table_name);
+ table->derived_select_number= first_select->select_number;
+ table->s->tmp_table= TMP_TABLE;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ table->grant.privilege= SELECT_ACL;
+#endif
+ orig_table_list->db= (char *)"";
+ orig_table_list->db_length= 0;
+ // Force read of table stats in the optimizer
+ table->file->info(HA_STATUS_VARIABLE);
+ /* Add new temporary table to list of open derived tables */
+ table->next= thd->derived_tables;
+ thd->derived_tables= table;
+ }
}
- derived_result->set_table(table);
+ else if (orig_table_list->ancestor)
+ orig_table_list->set_ancestor();
+ DBUG_RETURN(res);
+}
- /*
- if it is preparation PS only then we do not need real data and we
- can skip execution (and parameters is not defined, too)
+
+/*
+ fill derived table
+
+ SYNOPSIS
+ mysql_derived_filling()
+ thd Thread handle
+ lex LEX for this thread
+ unit node that contains all SELECT's for derived tables
+ orig_table_list TABLE_LIST for the upper SELECT
+
+ IMPLEMENTATION
+ Derived table is resolved with temporary table. It is created based on the
+ queries defined. After temporary table is filled, if this is not EXPLAIN,
+ then the entire unit / node is deleted. unit is deleted if UNION is used
+ for derived table and node is deleted is it is a simple SELECT.
+
+ RETURN
+ 0 ok
+ 1 Error
+ -1 Error and error message given
*/
- if (! thd->current_arena->is_stmt_prepare())
+
+int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
+{
+ TABLE *table= orig_table_list->table;
+ SELECT_LEX_UNIT *unit= orig_table_list->derived;
+ int res= 0;
+
+ /*check that table creation pass without problem and it is derived table */
+ if (table && unit)
{
+ SELECT_LEX *first_select= unit->first_select();
+ select_union *derived_result= orig_table_list->derived_result;
+ SELECT_LEX *save_current_select= lex->current_select;
+ bool is_union= first_select->next_select() &&
+ first_select->next_select()->linkage == UNION_TYPE;
if (is_union)
{
// execute union without clean up
- if (!(res= unit->prepare(thd, derived_result, SELECT_NO_UNLOCK, "")))
- res= unit->exec();
+ res= unit->exec();
}
else
{
@@ -175,7 +254,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
first_select->options&= ~OPTION_FOUND_ROWS;
lex->current_select= first_select;
- res= mysql_select(thd, &first_select->ref_pointer_array,
+ res= mysql_select(thd, &first_select->ref_pointer_array,
(TABLE_LIST*) first_select->table_list.first,
first_select->with_wild,
first_select->item_list, first_select->where,
@@ -188,54 +267,22 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
SELECT_NO_UNLOCK),
derived_result, unit, first_select);
}
- }
- if (!res)
- {
- /*
- Here we entirely fix both TABLE_LIST and list of SELECT's as
- there were no derived tables
- */
- if (derived_result->flush())
- res= 1;
- else
+ if (!res)
{
- org_table_list->real_name= table->real_name;
- org_table_list->table= table;
- if (org_table_list->table_list)
- {
- org_table_list->table_list->real_name= table->real_name;
- org_table_list->table_list->table= table;
- }
- table->derived_select_number= first_select->select_number;
- table->tmp_table= TMP_TABLE;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- table->grant.privilege= SELECT_ACL;
-#endif
- org_table_list->db= (char *)"";
- // Force read of table stats in the optimizer
- table->file->info(HA_STATUS_VARIABLE);
- }
+ /*
+ Here we entirely fix both TABLE_LIST and list of SELECT's as
+ there were no derived tables
+ */
+ if (derived_result->flush())
+ res= 1;
- if (!lex->describe)
- unit->cleanup();
- if (res)
- free_tmp_table(thd, table);
- else
- {
- /* Add new temporary table to list of open derived tables */
- table->next= thd->derived_tables;
- thd->derived_tables= table;
+ if (!lex->describe)
+ unit->cleanup();
}
+ else
+ unit->cleanup();
+ lex->current_select= save_current_select;
}
- else
- {
- free_tmp_table(thd, table);
- unit->cleanup();
- }
-
-exit:
- delete derived_result;
- lex->current_select= save_current_select;
- DBUG_RETURN(res);
+ return res;
}
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index af72632199f..e37f3e86dda 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -19,17 +19,17 @@
#include "mysql_priv.h"
-int mysql_do(THD *thd, List<Item> &values)
+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))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
while ((value = li++))
value->val_int();
free_underlaid_joins(thd, &thd->lex->select_lex);
thd->clear_error(); // DO always is OK
send_ok(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index d19e9fbdb09..3bda16202b9 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -43,6 +43,7 @@ This file contains the implementation of error and warnings related
***********************************************************************/
#include "mysql_priv.h"
+#include "sp_rcontext.h"
/*
Store a new message in an error object
@@ -63,6 +64,7 @@ void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg)
SYNOPSIS
mysql_reset_errors()
thd Thread handle
+ force Reset warnings even if it has been done before
IMPLEMENTATION
Don't reset warnings if this has already been called for this query.
@@ -70,14 +72,16 @@ void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg)
in which case push_warnings() has already called this function.
*/
-void mysql_reset_errors(THD *thd)
+void mysql_reset_errors(THD *thd, bool force)
{
DBUG_ENTER("mysql_reset_errors");
- if (thd->query_id != thd->warn_id)
+ if (thd->query_id != thd->warn_id || force)
{
thd->warn_id= thd->query_id;
free_root(&thd->warn_root,MYF(0));
bzero((char*) thd->warn_count, sizeof(thd->warn_count));
+ if (force)
+ thd->total_warn_count= 0;
thd->warn_list.empty();
thd->row_count= 1; // by default point to row 1
}
@@ -105,11 +109,43 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
MYSQL_ERROR *err= 0;
DBUG_ENTER("push_warning");
- if (level == MYSQL_ERROR::WARN_LEVEL_NOTE && !(thd->options & OPTION_SQL_NOTES))
- return(0);
+ if (level == MYSQL_ERROR::WARN_LEVEL_NOTE &&
+ !(thd->options & OPTION_SQL_NOTES))
+ DBUG_RETURN(0);
- if (thd->query_id != thd->warn_id)
- mysql_reset_errors(thd);
+ if (thd->query_id != thd->warn_id && !thd->spcont)
+ mysql_reset_errors(thd, 0);
+ thd->got_warning= 1;
+
+ /* Abort if we are using strict mode and we are not using IGNORE */
+ if ((int) level >= (int) MYSQL_ERROR::WARN_LEVEL_WARN &&
+ thd->really_abort_on_warning())
+ {
+ /* Avoid my_message() calling push_warning */
+ bool no_warnings_for_error= thd->no_warnings_for_error;
+ sp_rcontext *spcont= thd->spcont;
+
+ thd->no_warnings_for_error= 1;
+ thd->spcont= 0;
+
+ thd->killed= THD::KILL_BAD_DATA;
+ my_message(code, msg, MYF(0));
+
+ thd->spcont= spcont;
+ thd->no_warnings_for_error= no_warnings_for_error;
+ /* Store error in error list (as my_message() didn't do it) */
+ level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ }
+
+ if (thd->spcont &&
+ thd->spcont->find_handler(code,
+ ((int) level >=
+ (int) MYSQL_ERROR::WARN_LEVEL_WARN &&
+ thd->really_abort_on_warning()) ?
+ MYSQL_ERROR::WARN_LEVEL_ERROR : level))
+ {
+ DBUG_RETURN(NULL);
+ }
if (thd->warn_list.elements < thd->variables.max_error_count)
{
@@ -119,8 +155,7 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
*/
MEM_ROOT *old_root= thd->mem_root;
thd->mem_root= &thd->warn_root;
- err= new MYSQL_ERROR(thd, code, level, msg);
- if (err)
+ if ((err= new MYSQL_ERROR(thd, code, level, msg)))
thd->warn_list.push_back(err);
thd->mem_root= old_root;
}
@@ -168,14 +203,14 @@ void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
Takes into account the current LIMIT
RETURN VALUES
- 0 ok
- 1 Error sending data to client
+ FALSE ok
+ TRUE Error sending data to client
*/
static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"};
static int warning_level_length[]= { 4, 7, 5, 1 };
-my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
+bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
{
List<Item> field_list;
DBUG_ENTER("mysqld_show_warnings");
@@ -184,8 +219,9 @@ my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
- if (thd->protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
+ if (thd->protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
MYSQL_ERROR *err;
SELECT_LEX *sel= &thd->lex->select_lex;
@@ -209,10 +245,10 @@ my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
protocol->store((uint32) err->code);
protocol->store(err->msg, strlen(err->msg), system_charset_info);
if (protocol->write())
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
if (!--limit)
break;
}
- send_eof(thd);
- DBUG_RETURN(0);
+ send_eof(thd);
+ DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_error.h b/sql/sql_error.h
new file mode 100644
index 00000000000..223b50be744
--- /dev/null
+++ b/sql/sql_error.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+class MYSQL_ERROR: public Sql_alloc
+{
+public:
+ enum enum_warning_level
+ { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END};
+
+ uint code;
+ enum_warning_level level;
+ char *msg;
+
+ MYSQL_ERROR(THD *thd, uint code_arg, enum_warning_level level_arg,
+ const char *msg_arg)
+ :code(code_arg), level(level_arg)
+ {
+ if (msg_arg)
+ set_msg(thd, msg_arg);
+ }
+ void set_msg(THD *thd, const char *msg_arg);
+};
+
+MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+ uint code, const char *msg);
+void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
+ uint code, const char *format, ...);
+void mysql_reset_errors(THD *thd, bool force);
+bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index f250a00eca1..bb48b7ada77 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -64,7 +64,7 @@
#define HANDLER_TABLES_HASH_SIZE 120
static enum enum_ha_read_modes rkey_to_rnext[]=
- { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV };
+{ RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV };
#define HANDLER_TABLES_HACK(thd) { \
TABLE *tmp=thd->open_tables; \
@@ -140,19 +140,19 @@ static void mysql_ha_hash_free(TABLE_LIST *tables)
error messages.
RETURN
- 0 ok
- != 0 error
+ FALSE OK
+ TRUE Error
*/
-int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
+bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
{
TABLE_LIST *hash_tables;
char *db, *name, *alias;
uint dblen, namelen, aliaslen, counter;
- int err;
+ int error;
DBUG_ENTER("mysql_ha_open");
DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d",
- tables->db, tables->real_name, tables->alias,
+ tables->db, tables->table_name, tables->alias,
(int) reopen));
if (! hash_inited(&thd->handler_tables_hash))
@@ -173,8 +173,7 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
{
DBUG_PRINT("info",("duplicate '%s'", tables->alias));
if (! reopen)
- my_printf_error(ER_NONUNIQ_TABLE, ER(ER_NONUNIQ_TABLE),
- MYF(0), tables->alias);
+ my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias);
goto err;
}
}
@@ -185,16 +184,20 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
*/
DBUG_ASSERT(! tables->table);
HANDLER_TABLES_HACK(thd);
- err=open_tables(thd, tables, &counter);
+
+ /* for now HANDLER can be used only for real TABLES */
+ tables->required_type= FRMTYPE_TABLE;
+ error= open_tables(thd, &tables, &counter);
+
HANDLER_TABLES_HACK(thd);
- if (err)
+ if (error)
goto err;
/* There can be only one table in '*tables'. */
if (! (tables->table->file->table_flags() & HA_CAN_SQL_HANDLER))
{
if (! reopen)
- my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->alias);
+ my_error(ER_ILLEGAL_HA, MYF(0), tables->alias);
mysql_ha_close(thd, tables);
goto err;
}
@@ -203,7 +206,7 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
{
/* copy the TABLE_LIST struct */
dblen= strlen(tables->db) + 1;
- namelen= strlen(tables->real_name) + 1;
+ namelen= strlen(tables->table_name) + 1;
aliaslen= strlen(tables->alias) + 1;
if (!(my_multi_malloc(MYF(MY_WME),
&hash_tables, sizeof(*hash_tables),
@@ -215,10 +218,10 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
/* structure copy */
*hash_tables= *tables;
hash_tables->db= db;
- hash_tables->real_name= name;
+ hash_tables->table_name= name;
hash_tables->alias= alias;
memcpy(hash_tables->db, tables->db, dblen);
- memcpy(hash_tables->real_name, tables->real_name, namelen);
+ memcpy(hash_tables->table_name, tables->table_name, namelen);
memcpy(hash_tables->alias, tables->alias, aliaslen);
/* add to hash */
@@ -232,11 +235,11 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
if (! reopen)
send_ok(thd);
DBUG_PRINT("exit",("OK"));
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
err:
DBUG_PRINT("exit",("ERROR"));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
@@ -253,17 +256,17 @@ err:
will be closed. Broadcasts a COND_refresh condition.
RETURN
- 0 ok
- != 0 error
+ FALSE ok
+ TRUE error
*/
-int mysql_ha_close(THD *thd, TABLE_LIST *tables)
+bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
{
TABLE_LIST *hash_tables;
TABLE **table_ptr;
DBUG_ENTER("mysql_ha_close");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
- tables->db, tables->real_name, tables->alias));
+ tables->db, tables->table_name, tables->alias));
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
(byte*) tables->alias,
@@ -277,54 +280,32 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables)
*/
for (table_ptr= &(thd->handler_tables);
*table_ptr && (*table_ptr != hash_tables->table);
- table_ptr= &(*table_ptr)->next);
+ table_ptr= &(*table_ptr)->next)
+ ;
-#if MYSQL_VERSION_ID < 40100
- if (*tables->db && strcmp(hash_tables->db, tables->db))
- {
- DBUG_PRINT("info",("wrong db"));
- hash_tables= NULL;
- }
- else
-#endif
+ if (*table_ptr)
{
- if (*table_ptr)
+ (*table_ptr)->file->ha_index_or_rnd_end();
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (close_thread_table(thd, table_ptr))
{
- (*table_ptr)->file->ha_index_or_rnd_end();
- VOID(pthread_mutex_lock(&LOCK_open));
- if (close_thread_table(thd, table_ptr))
- {
- /* Tell threads waiting for refresh that something has happened */
- VOID(pthread_cond_broadcast(&COND_refresh));
- }
- VOID(pthread_mutex_unlock(&LOCK_open));
+ /* Tell threads waiting for refresh that something has happened */
+ VOID(pthread_cond_broadcast(&COND_refresh));
}
-
- hash_delete(&thd->handler_tables_hash, (byte*) hash_tables);
+ VOID(pthread_mutex_unlock(&LOCK_open));
}
+ hash_delete(&thd->handler_tables_hash, (byte*) hash_tables);
}
-
- if (! hash_tables)
+ else
{
-#if MYSQL_VERSION_ID < 40100
- char buff[MAX_DBKEY_LENGTH];
- if (*tables->db)
- strxnmov(buff, sizeof(buff), tables->db, ".", tables->real_name, NullS);
- else
- strncpy(buff, tables->alias, sizeof(buff));
- my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
- buff, "HANDLER");
-#else
- my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
- tables->alias, "HANDLER");
-#endif
+ my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias, "HANDLER");
DBUG_PRINT("exit",("ERROR"));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
send_ok(thd);
DBUG_PRINT("exit", ("OK"));
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -344,14 +325,15 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables)
offset_limit
RETURN
- 0 ok
- != 0 error
+ FALSE ok
+ TRUE error
*/
-int mysql_ha_read(THD *thd, TABLE_LIST *tables,
- enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr,
- enum ha_rkey_function ha_rkey_mode, Item *cond,
- ha_rows select_limit,ha_rows offset_limit)
+bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
+ enum enum_ha_read_modes mode, char *keyname,
+ List<Item> *key_expr,
+ enum ha_rkey_function ha_rkey_mode, Item *cond,
+ ha_rows select_limit,ha_rows offset_limit)
{
TABLE_LIST *hash_tables;
TABLE *table;
@@ -360,13 +342,13 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
Protocol *protocol= thd->protocol;
char buff[MAX_FIELD_WIDTH];
String buffer(buff, sizeof(buff), system_charset_info);
- int err, keyno= -1;
+ int error, keyno= -1;
uint num_rows;
byte *key;
uint key_len;
DBUG_ENTER("mysql_ha_read");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
- tables->db, tables->real_name, tables->alias));
+ tables->db, tables->table_name, tables->alias));
LINT_INIT(key);
LINT_INIT(key_len);
@@ -381,7 +363,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
{
table= hash_tables->table;
DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p",
- hash_tables->db, hash_tables->real_name,
+ hash_tables->db, hash_tables->table_name,
hash_tables->alias, table));
if (!table)
{
@@ -396,7 +378,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
table= hash_tables->table;
DBUG_PRINT("info",("re-opened '%s'.'%s' as '%s' tab %p",
- hash_tables->db, hash_tables->real_name,
+ hash_tables->db, hash_tables->table_name,
hash_tables->alias, table));
}
@@ -416,49 +398,46 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
#if MYSQL_VERSION_ID < 40100
char buff[MAX_DBKEY_LENGTH];
if (*tables->db)
- strxnmov(buff, sizeof(buff), tables->db, ".", tables->real_name, NullS);
+ strxnmov(buff, sizeof(buff), tables->db, ".", tables->table_name, NullS);
else
strncpy(buff, tables->alias, sizeof(buff));
- my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
- buff, "HANDLER");
+ my_error(ER_UNKNOWN_TABLE, MYF(0), buff, "HANDLER");
#else
- my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
- tables->alias, "HANDLER");
+ my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias, "HANDLER");
#endif
goto err0;
}
tables->table=table;
- if (cond && ((!cond->fixed &&
- cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)))
+ if (cond && ((!cond->fixed &&
+ cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)))
goto err0;
table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it
if (keyname)
{
- if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0)
+ if ((keyno=find_type(keyname, &table->s->keynames, 1+2)-1)<0)
{
- my_printf_error(ER_KEY_DOES_NOT_EXITS,ER(ER_KEY_DOES_NOT_EXITS),MYF(0),
- keyname,tables->alias);
+ my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname, tables->alias);
goto err0;
}
table->file->ha_index_or_rnd_end();
table->file->ha_index_init(keyno);
}
- if (insert_fields(thd,tables,tables->db,tables->alias,&it))
+ if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0, 0))
goto err0;
select_limit+=offset_limit;
- protocol->send_fields(&list,1);
+ protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
HANDLER_TABLES_HACK(thd);
lock= mysql_lock_tables(thd, &tables->table, 1);
HANDLER_TABLES_HACK(thd);
if (!lock)
- goto err0; // mysql_lock_tables() printed error message already
+ goto err0; // mysql_lock_tables() printed error message already
/*
In ::external_lock InnoDB resets the fields which tell it that
@@ -473,33 +452,33 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
switch (mode) {
case RFIRST:
if (keyname)
- err=table->file->index_first(table->record[0]);
+ error= table->file->index_first(table->record[0]);
else
{
table->file->ha_index_or_rnd_end();
- if (!(err=table->file->ha_rnd_init(1)))
- err=table->file->rnd_next(table->record[0]);
+ if (!(error= table->file->ha_rnd_init(1)))
+ error= table->file->rnd_next(table->record[0]);
}
mode=RNEXT;
break;
case RLAST:
DBUG_ASSERT(keyname != 0);
- err=table->file->index_last(table->record[0]);
+ error= table->file->index_last(table->record[0]);
mode=RPREV;
break;
case RNEXT:
- err=keyname ?
- table->file->index_next(table->record[0]) :
- table->file->rnd_next(table->record[0]);
+ error= (keyname ?
+ table->file->index_next(table->record[0]) :
+ table->file->rnd_next(table->record[0]));
break;
case RPREV:
DBUG_ASSERT(keyname != 0);
- err=table->file->index_prev(table->record[0]);
+ error= table->file->index_prev(table->record[0]);
break;
case RNEXT_SAME:
/* Continue scan on "(keypart1,keypart2,...)=(c1, c2, ...) */
DBUG_ASSERT(keyname != 0);
- err= table->file->index_next_same(table->record[0], key, key_len);
+ error= table->file->index_next_same(table->record[0], key, key_len);
break;
case RKEY:
{
@@ -508,8 +487,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
KEY_PART_INFO *key_part=keyinfo->key_part;
if (key_expr->elements > keyinfo->key_parts)
{
- my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS),
- MYF(0),keyinfo->key_parts);
+ my_error(ER_TOO_MANY_KEY_PARTS, MYF(0), keyinfo->key_parts);
goto err;
}
List_iterator<Item> it_ke(*key_expr);
@@ -517,7 +495,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
// 'item' can be changed by fix_fields() call
- if ((!item->fixed &&
+ if ((!item->fixed &&
item->fix_fields(thd, tables, it_ke.ref())) ||
(item= *it_ke.ref())->check_cols(1))
goto err;
@@ -530,30 +508,27 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
key_len+=key_part->store_length;
}
if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
- {
- send_error(thd,ER_OUTOFMEMORY);
goto err;
- }
- key_copy(key, table, keyno, key_len);
- err=table->file->index_read(table->record[0],
+ key_copy(key, table->record[0], table->key_info + keyno, key_len);
+ error= table->file->index_read(table->record[0],
key,key_len,ha_rkey_mode);
mode=rkey_to_rnext[(int)ha_rkey_mode];
break;
}
default:
- send_error(thd,ER_ILLEGAL_HA);
+ my_message(ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), MYF(0));
goto err;
}
- if (err == HA_ERR_RECORD_DELETED)
- continue;
- if (err)
+ if (error)
{
- if (err != HA_ERR_KEY_NOT_FOUND && err != HA_ERR_END_OF_FILE)
+ if (error == HA_ERR_RECORD_DELETED)
+ continue;
+ if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
{
sql_print_error("mysql_ha_read: Got error %d when reading table '%s'",
- err, tables->real_name);
- table->file->print_error(err,MYF(0));
+ error, tables->table_name);
+ table->file->print_error(error,MYF(0));
goto err;
}
goto ok;
@@ -570,7 +545,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
if (item->send(thd->protocol, &buffer))
{
protocol->free(); // Free used
- my_error(ER_OUT_OF_RESOURCES,MYF(0));
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
goto err;
}
}
@@ -582,13 +557,13 @@ ok:
mysql_unlock_tables(thd,lock);
send_eof(thd);
DBUG_PRINT("exit",("OK"));
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
err:
mysql_unlock_tables(thd,lock);
err0:
DBUG_PRINT("exit",("ERROR"));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
@@ -631,25 +606,25 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags)
if (tables)
{
/* Close all tables in the list. */
- for (tmp_tables= tables ; tmp_tables; tmp_tables= tmp_tables->next)
+ for (tmp_tables= tables ; tmp_tables; tmp_tables= tmp_tables->next_local)
{
DBUG_PRINT("info-in-tables-list",("'%s'.'%s' as '%s'",
- tmp_tables->db, tmp_tables->real_name,
+ tmp_tables->db, tmp_tables->table_name,
tmp_tables->alias));
/* Close all currently open handler tables with the same base table. */
table_ptr= &(thd->handler_tables);
while (*table_ptr)
{
- if ((! *tmp_tables->db ||
- ! my_strcasecmp(&my_charset_latin1, (*table_ptr)->table_cache_key,
+ if ((!*tmp_tables->db ||
+ !my_strcasecmp(&my_charset_latin1, (*table_ptr)->s->db,
tmp_tables->db)) &&
- ! my_strcasecmp(&my_charset_latin1, (*table_ptr)->real_name,
- tmp_tables->real_name))
+ ! my_strcasecmp(&my_charset_latin1, (*table_ptr)->s->table_name,
+ tmp_tables->table_name))
{
DBUG_PRINT("info",("*table_ptr '%s'.'%s' as '%s'",
- (*table_ptr)->table_cache_key,
- (*table_ptr)->real_name,
- (*table_ptr)->table_name));
+ (*table_ptr)->s->db,
+ (*table_ptr)->s->table_name,
+ (*table_ptr)->alias));
mysql_ha_flush_table(thd, table_ptr, mode_flags);
continue;
}
@@ -666,7 +641,7 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags)
while (*table_ptr)
{
if ((mode_flags & MYSQL_HA_FLUSH_ALL) ||
- ((*table_ptr)->version != refresh_version))
+ ((*table_ptr)->s->version != refresh_version))
{
mysql_ha_flush_table(thd, table_ptr, mode_flags);
continue;
@@ -702,12 +677,12 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags)
TABLE *table= *table_ptr;
DBUG_ENTER("mysql_ha_flush_table");
DBUG_PRINT("enter",("'%s'.'%s' as '%s' flags: 0x%02x",
- table->table_cache_key, table->real_name,
- table->table_name, mode_flags));
+ table->s->db, table->s->table_name,
+ table->alias, mode_flags));
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
- (byte*) (*table_ptr)->table_name,
- strlen((*table_ptr)->table_name) + 1)))
+ (byte*) (*table_ptr)->alias,
+ strlen((*table_ptr)->alias) + 1)))
{
if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE))
{
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 0e0d32a922d..3c8e8e55c1f 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -84,12 +84,11 @@ static bool init_fields(THD *thd, TABLE_LIST *tables,
DBUG_ENTER("init_fields");
for (; count-- ; find_fields++)
{
- TABLE_LIST *not_used;
/* 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,
find_fields->field_name);
if (!(find_fields->field= find_field_in_tables(thd, field, tables,
- &not_used, TRUE)))
+ 0, REPORT_ALL_ERRORS, 1)))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -273,11 +272,11 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
DBUG_ENTER("get_topics_for_keyword");
if ((iindex_topic= find_type((char*) primary_key_name,
- &topics->keynames, 1+2)-1)<0 ||
+ &topics->s->keynames, 1+2)-1)<0 ||
(iindex_relations= find_type((char*) primary_key_name,
- &relations->keynames, 1+2)-1)<0)
+ &relations->s->keynames, 1+2)-1)<0)
{
- send_error(thd,ER_CORRUPT_HELP_DB);
+ my_message(ER_CORRUPT_HELP_DB, ER(ER_CORRUPT_HELP_DB), MYF(0));
DBUG_RETURN(-1);
}
rtopic_id= find_fields[help_relation_help_topic_id].field;
@@ -287,8 +286,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
relations->file->ha_index_init(iindex_relations);
rkey_id->store((longlong) key_id);
- rkey_id->get_key_image(buff, rkey_id->pack_length(), rkey_id->charset(),
- Field::itRAW);
+ rkey_id->get_key_image(buff, rkey_id->pack_length(), Field::itRAW);
int key_res= relations->file->index_read(relations->record[0],
(byte *)buff, rkey_id->pack_length(),
HA_READ_KEY_EXACT);
@@ -301,8 +299,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
longlong topic_id= rtopic_id->val_int();
Field *field= find_fields[help_topic_help_topic_id].field;
field->store((longlong) topic_id);
- field->get_key_image(topic_id_buff, field->pack_length(), field->charset(),
- Field::itRAW);
+ field->get_key_image(topic_id_buff, field->pack_length(), Field::itRAW);
if (!topics->file->index_read(topics->record[0], (byte *)topic_id_buff,
field->pack_length(), HA_READ_KEY_EXACT))
@@ -427,7 +424,8 @@ int send_answer_1(Protocol *protocol, String *s1, String *s2, String *s3)
field_list.push_back(new Item_empty_string("description",1000));
field_list.push_back(new Item_empty_string("example",1000));
- if (protocol->send_fields(&field_list,1))
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(1);
protocol->prepare_for_resend();
@@ -469,7 +467,8 @@ int send_header_2(Protocol *protocol, bool for_category)
field_list.push_back(new Item_empty_string("source_category_name",64));
field_list.push_back(new Item_empty_string("name",64));
field_list.push_back(new Item_empty_string("is_it_category",1));
- DBUG_RETURN(protocol->send_fields(&field_list,1));
+ DBUG_RETURN(protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+ Protocol::SEND_EOF));
}
/*
@@ -559,8 +558,13 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables,
{
if (!cond->fixed)
cond->fix_fields(thd, tables, &cond); // can never fail
- SQL_SELECT *res= make_select(table,0,0,cond,error);
- if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)))
+
+ /* Assume that no indexes cover all required fields */
+ table->used_keys.clear_all();
+
+ SQL_SELECT *res= make_select(table, 0, 0, cond, 0, error);
+ if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)) ||
+ (res->quick && res->quick->reset()))
{
delete res;
res=0;
@@ -607,53 +611,50 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen,
thd Thread handler
RETURN VALUES
- 0 Success
- 1 Error and send_error already commited
- -1 error && send_error should be issued (normal case)
+ FALSE Success
+ TRUE Error and send_error already commited
*/
-int mysqld_help(THD *thd, const char *mask)
+bool mysqld_help(THD *thd, const char *mask)
{
Protocol *protocol= thd->protocol;
SQL_SELECT *select;
st_find_field used_fields[array_elements(init_used_fields)];
DBUG_ENTER("mysqld_help");
+ TABLE_LIST *leaves= 0;
TABLE_LIST tables[4];
bzero((gptr)tables,sizeof(tables));
- tables[0].alias= tables[0].real_name= (char*) "help_topic";
+ tables[0].alias= tables[0].table_name= (char*) "help_topic";
tables[0].lock_type= TL_READ;
- tables[0].next= &tables[1];
- tables[1].alias= tables[1].real_name= (char*) "help_category";
+ tables[0].next_global= tables[0].next_local= &tables[1];
+ tables[1].alias= tables[1].table_name= (char*) "help_category";
tables[1].lock_type= TL_READ;
- tables[1].next= &tables[2];
- tables[2].alias= tables[2].real_name= (char*) "help_relation";
+ tables[1].next_global= tables[1].next_local= &tables[2];
+ tables[2].alias= tables[2].table_name= (char*) "help_relation";
tables[2].lock_type= TL_READ;
- tables[2].next= &tables[3];
- tables[3].alias= tables[3].real_name= (char*) "help_keyword";
+ tables[2].next_global= tables[2].next_local= &tables[3];
+ tables[3].alias= tables[3].table_name= (char*) "help_keyword";
tables[3].lock_type= TL_READ;
- tables[3].next= 0;
tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql";
List<String> topics_list, categories_list, subcategories_list;
String name, description, example;
- int res, count_topics, count_categories, error;
+ int count_topics, count_categories, error;
uint mlen= strlen(mask);
MEM_ROOT *mem_root= thd->mem_root;
if (open_and_lock_tables(thd, tables))
- {
- res= -1;
- goto end;
- }
- /* Init tables and fields to be usable from items */
- setup_tables(tables);
+ goto error;
+ /*
+ Init tables and fields to be usable from items
+
+ tables do not contain VIEWs => we can pass 0 as conds
+ */
+ setup_tables(thd, tables, 0, &leaves, FALSE, FALSE);
memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
- {
- res= -1;
- goto end;
- }
+ goto error;
size_t i;
for (i=0; i<sizeof(tables)/sizeof(TABLE_LIST); i++)
tables[i].table->file->init_table_handle_for_HANDLER();
@@ -661,12 +662,8 @@ int mysqld_help(THD *thd, const char *mask)
if (!(select=
prepare_select_for_name(thd,mask,mlen,tables,tables[0].table,
used_fields[help_topic_name].field,&error)))
- {
- res= -1;
- goto end;
- }
+ goto error;
- res= 1;
count_topics= search_topics(thd,tables[0].table,used_fields,
select,&topics_list,
&name, &description, &example);
@@ -678,10 +675,8 @@ int mysqld_help(THD *thd, const char *mask)
if (!(select=
prepare_select_for_name(thd,mask,mlen,tables,tables[3].table,
used_fields[help_keyword_name].field,&error)))
- {
- res= -1;
- goto end;
- }
+ goto error;
+
count_topics=search_keyword(thd,tables[3].table,used_fields,select,&key_id);
delete select;
count_topics= (count_topics != 1) ? 0 :
@@ -697,10 +692,7 @@ int mysqld_help(THD *thd, const char *mask)
if (!(select=
prepare_select_for_name(thd,mask,mlen,tables,tables[1].table,
used_fields[help_category_name].field,&error)))
- {
- res= -1;
- goto end;
- }
+ goto error;
count_categories= search_categories(thd, tables[1].table, used_fields,
select,
@@ -709,13 +701,13 @@ int mysqld_help(THD *thd, const char *mask)
if (!count_categories)
{
if (send_header_2(protocol,FALSE))
- goto end;
+ goto error;
}
else if (count_categories > 1)
{
if (send_header_2(protocol,FALSE) ||
send_variant_2_list(mem_root,protocol,&categories_list,"Y",0))
- goto end;
+ goto error;
}
else
{
@@ -728,20 +720,14 @@ int mysqld_help(THD *thd, const char *mask)
new Item_int((int32)category_id));
if (!(select= prepare_simple_select(thd,cond_topic_by_cat,
tables,tables[0].table,&error)))
- {
- res= -1;
- goto end;
- }
+ 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)))
- {
- res= -1;
- goto end;
- }
+ goto error;
get_all_items_for_category(thd,tables[1].table,
used_fields[help_category_name].field,
select,&subcategories_list);
@@ -750,39 +736,35 @@ int mysqld_help(THD *thd, const char *mask)
if (send_header_2(protocol, TRUE) ||
send_variant_2_list(mem_root,protocol,&topics_list, "N",cat) ||
send_variant_2_list(mem_root,protocol,&subcategories_list,"Y",cat))
- goto end;
+ goto error;
}
}
else if (count_topics == 1)
{
if (send_answer_1(protocol,&name,&description,&example))
- goto end;
+ goto error;
}
else
{
/* First send header and functions */
if (send_header_2(protocol, FALSE) ||
send_variant_2_list(mem_root,protocol, &topics_list, "N", 0))
- goto end;
+ goto error;
if (!(select=
prepare_select_for_name(thd,mask,mlen,tables,tables[1].table,
used_fields[help_category_name].field,&error)))
- {
- res= -1;
- goto end;
- }
+ goto error;
search_categories(thd, tables[1].table, used_fields,
select,&categories_list, 0);
delete select;
/* Then send categories */
if (send_variant_2_list(mem_root,protocol, &categories_list, "Y", 0))
- goto end;
+ goto error;
}
- res= 0;
-
send_eof(thd);
-end:
- DBUG_RETURN(res);
+ DBUG_RETURN(FALSE);
+error:
+ DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 3ced5921076..729f9751bba 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -18,16 +18,20 @@
/* Insert of records */
#include "mysql_priv.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
+#include "sql_select.h"
static int check_null_fields(THD *thd,TABLE *entry);
#ifndef EMBEDDED_LIBRARY
static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
static int write_delayed(THD *thd,TABLE *table, enum_duplicates dup, bool ignore,
- char *query, uint query_length, int log_on);
+ char *query, uint query_length, bool log_on);
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);
/* Define to force use of my_malloc() if the allocated memory block is big */
@@ -39,9 +43,6 @@ static void unlink_blobs(register TABLE *table);
#define my_safe_afree(ptr, size, min_length) if (size > min_length) my_free(ptr,MYF(0))
#endif
-#define DELAYED_LOG_UPDATE 1
-#define DELAYED_LOG_BIN 2
-
/*
Check if insert fields are correct.
@@ -52,6 +53,7 @@ static void unlink_blobs(register TABLE *table);
table The table for insert.
fields The insert fields.
values The insert values.
+ check_unique If duplicate values should be rejected.
NOTE
Clears TIMESTAMP_AUTO_SET_ON_INSERT from table->timestamp_field_type
@@ -63,50 +65,88 @@ static void unlink_blobs(register TABLE *table);
-1 Error
*/
-static int check_insert_fields(THD *thd, TABLE *table, List<Item> &fields,
- List<Item> &values)
+static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
+ List<Item> &fields, List<Item> &values,
+ bool check_unique)
{
+ TABLE *table= table_list->table;
+
+ if (!table_list->updatable)
+ {
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
+ return -1;
+ }
+
if (fields.elements == 0 && values.elements != 0)
{
- if (values.elements != table->fields)
+ if (!table)
{
- my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
- ER(ER_WRONG_VALUE_COUNT_ON_ROW),
- MYF(0), 1L);
+ DBUG_ASSERT(table_list->view &&
+ table_list->ancestor && table_list->ancestor->next_local);
+ my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
+ table_list->view_db.str, table_list->view_name.str);
return -1;
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (grant_option &&
- check_grant_all_columns(thd,INSERT_ACL,table))
+ if (values.elements != table->s->fields)
+ {
+ my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
return -1;
+ }
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (grant_option)
+ {
+ Field_iterator_table fields;
+ fields.set_table(table);
+ if (check_grant_all_columns(thd, INSERT_ACL, &table->grant,
+ table->s->db, table->s->table_name,
+ &fields))
+ return -1;
+ }
#endif
clear_timestamp_auto_bits(table->timestamp_field_type,
TIMESTAMP_AUTO_SET_ON_INSERT);
}
else
{ // Part field list
+ TABLE_LIST *save_next;
+ int res;
if (fields.elements != values.elements)
{
- my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
- ER(ER_WRONG_VALUE_COUNT_ON_ROW),
- MYF(0), 1L);
+ my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L);
return -1;
}
- TABLE_LIST table_list;
- bzero((char*) &table_list,sizeof(table_list));
- table_list.db= table->table_cache_key;
- table_list.real_name= table_list.alias= table->table_name;
- table_list.table=table;
- table_list.grant=table->grant;
thd->dupp_field=0;
- if (setup_tables(&table_list) ||
- setup_fields(thd, 0, &table_list,fields,1,0,0))
+ thd->lex->select_lex.no_wrap_view_item= 1;
+ save_next= table_list->next_local; // fields only from first table
+ table_list->next_local= 0;
+ res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
+ table_list->next_local= save_next;
+ thd->lex->select_lex.no_wrap_view_item= 0;
+ if (res)
return -1;
+ if (table == 0)
+ {
+ /* it is join view => we need to find table for update */
+ List_iterator_fast<Item> it(fields);
+ Item *item;
+ TABLE_LIST *tbl= 0;
+ table_map map= 0;
+
+ while ((item= it++))
+ map|= item->used_tables();
+ if (table_list->check_single_table(&tbl, map) || tbl == 0)
+ {
+ my_error(ER_VIEW_MULTIUPDATE, MYF(0),
+ table_list->view_db.str, table_list->view_name.str);
+ return -1;
+ }
+ table_list->table= table= tbl->table;
+ }
- if (thd->dupp_field)
+ if (check_unique && thd->dupp_field)
{
- my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name);
+ my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), thd->dupp_field->field_name);
return -1;
}
if (table->timestamp_field && // Don't set timestamp if used
@@ -116,8 +156,17 @@ static int check_insert_fields(THD *thd, TABLE *table, List<Item> &fields,
}
// For the values we need select_priv
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
+ table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
#endif
+
+ if (check_key_in_view(thd, table_list) ||
+ (table_list->view &&
+ check_view_insertability(table_list, thd->query_id)))
+ {
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
+ return -1;
+ }
+
return 0;
}
@@ -141,11 +190,11 @@ static int check_insert_fields(THD *thd, TABLE *table, List<Item> &fields,
-1 Error
*/
-static int check_update_fields(THD *thd, TABLE *table,
- TABLE_LIST *insert_table_list,
+static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
List<Item> &update_fields)
{
- ulong timestamp_query_id;
+ TABLE *table= insert_table_list->table;
+ ulong timestamp_query_id;
LINT_INIT(timestamp_query_id);
/*
@@ -155,7 +204,7 @@ static int check_update_fields(THD *thd, TABLE *table,
if (table->timestamp_field)
{
timestamp_query_id= table->timestamp_field->query_id;
- table->timestamp_field->query_id= thd->query_id-1;
+ table->timestamp_field->query_id= thd->query_id - 1;
}
/*
@@ -179,13 +228,13 @@ static int check_update_fields(THD *thd, TABLE *table,
}
-int mysql_insert(THD *thd,TABLE_LIST *table_list,
- List<Item> &fields,
- List<List_item> &values_list,
- List<Item> &update_fields,
- List<Item> &update_values,
- enum_duplicates duplic,
- bool ignore)
+bool mysql_insert(THD *thd,TABLE_LIST *table_list,
+ List<Item> &fields,
+ List<List_item> &values_list,
+ List<Item> &update_fields,
+ List<Item> &update_values,
+ enum_duplicates duplic,
+ bool ignore)
{
int error, res;
/*
@@ -193,27 +242,22 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
By default, both logs are enabled (this won't cause problems if the server
runs without --log-update or --log-bin).
*/
- int log_on= DELAYED_LOG_UPDATE | DELAYED_LOG_BIN ;
- bool transactional_table, log_delayed;
+ bool log_on= (thd->options & OPTION_BIN_LOG) || (!(thd->master_access & SUPER_ACL));
+ bool transactional_table;
uint value_count;
ulong counter = 1;
ulonglong id;
COPY_INFO info;
- TABLE *table;
+ TABLE *table= 0;
List_iterator_fast<List_item> its(values_list);
List_item *values;
#ifndef EMBEDDED_LIBRARY
char *query= thd->query;
#endif
thr_lock_type lock_type = table_list->lock_type;
- TABLE_LIST *insert_table_list= (TABLE_LIST*)
- thd->lex->select_lex.table_list.first;
+ Item *unused_conds= 0;
DBUG_ENTER("mysql_insert");
- if (!(thd->options & OPTION_UPDATE_LOG))
- log_on&= ~(int) DELAYED_LOG_UPDATE;
- if (!(thd->options & OPTION_BIN_LOG))
- log_on&= ~(int) DELAYED_LOG_BIN;
/*
in safe mode or with skip-new change delayed insert to be regular
if we are told to replace duplicates, the insert cannot be concurrent
@@ -239,19 +283,26 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
{
if (find_locked_table(thd,
table_list->db ? table_list->db : thd->db,
- table_list->real_name))
+ table_list->table_name))
{
- my_printf_error(ER_DELAYED_INSERT_TABLE_LOCKED,
- ER(ER_DELAYED_INSERT_TABLE_LOCKED),
- MYF(0), table_list->real_name);
- DBUG_RETURN(-1);
+ my_error(ER_DELAYED_INSERT_TABLE_LOCKED, MYF(0),
+ table_list->table_name);
+ DBUG_RETURN(TRUE);
}
}
if ((table= delayed_get_table(thd,table_list)) && !thd->is_fatal_error)
{
- res= 0;
- if (table_list->next) /* if sub select */
- res= open_and_lock_tables(thd, table_list->next);
+ /*
+ Open tables used for sub-selects or in stored functions, will also
+ cache these functions.
+ */
+ res= open_and_lock_tables(thd, table_list->next_global);
+ /*
+ First is not processed by open_and_lock_tables() => we need set
+ updateability flags "by hands".
+ */
+ if (!table_list->derived && !table_list->view)
+ table_list->updatable= 1; // usual table
}
else
{
@@ -264,30 +315,31 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
#endif /* EMBEDDED_LIBRARY */
res= open_and_lock_tables(thd, table_list);
if (res || thd->is_fatal_error)
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
- table= table_list->table;
thd->proc_info="init";
thd->used_tables=0;
values= its++;
- if (mysql_prepare_insert(thd, table_list, insert_table_list, table,
- fields, values, update_fields,
- update_values, duplic))
+ if (mysql_prepare_insert(thd, table_list, table, fields, values,
+ update_fields, update_values, duplic, &unused_conds,
+ FALSE))
goto abort;
+ /* 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
value_count= values->elements;
while ((values= its++))
{
counter++;
if (values->elements != value_count)
{
- my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
- ER(ER_WRONG_VALUE_COUNT_ON_ROW),
- MYF(0),counter);
+ my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto abort;
}
- if (setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0))
+ if (setup_fields(thd, 0, table_list, *values, 0, 0, 0))
goto abort;
}
its.rewind ();
@@ -300,12 +352,15 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
info.handle_duplicates=duplic;
info.update_fields= &update_fields;
info.update_values= &update_values;
+ info.view= (table_list->view ? table_list : 0);
+
/*
Count warnings for all inserts.
For single line insert, generate an error if try to set a NOT NULL field
- to NULL
+ to NULL.
*/
- thd->count_cuted_fields= ((values_list.elements == 1) ?
+ thd->count_cuted_fields= ((values_list.elements == 1 &&
+ !ignore) ?
CHECK_FIELD_ERROR_FOR_NULL :
CHECK_FIELD_WARN);
thd->cuted_fields = 0L;
@@ -327,19 +382,36 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
if (lock_type != TL_WRITE_DELAYED)
table->file->start_bulk_insert(values_list.elements);
+ thd->no_trans_update= 0;
+ thd->abort_on_warning= (!ignore &&
+ (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES)));
+
+ if ((fields.elements || !value_count) &&
+ check_that_all_fields_are_given_values(thd, table))
+ {
+ /* thd->net.report_error is now set, which will abort the next loop */
+ error= 1;
+ }
+
while ((values= its++))
{
if (fields.elements || !value_count)
{
- restore_record(table,default_values); // Get empty record
- if (fill_record(fields, *values, 0)|| thd->net.report_error ||
- check_null_fields(thd,table))
+ restore_record(table,s->default_values); // Get empty record
+ if (fill_record(thd, fields, *values, 0))
{
if (values_list.elements != 1 && !thd->net.report_error)
{
info.records++;
continue;
}
+ /*
+ TODO: set thd->abort_on_warning if values_list.elements == 1
+ and check that all items return warning in case of problem with
+ storing field.
+ */
error=1;
break;
}
@@ -347,10 +419,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
else
{
if (thd->used_tables) // Column used in values()
- restore_record(table,default_values); // Get empty record
+ restore_record(table,s->default_values); // Get empty record
else
- table->record[0][0]=table->default_values[0]; // Fix delete marker
- if (fill_record(table->field,*values, 0) || thd->net.report_error)
+ table->record[0][0]= table->s->default_values[0]; // Fix delete marker
+ if (fill_record(thd, table->field, *values, 0))
{
if (values_list.elements != 1 && ! thd->net.report_error)
{
@@ -361,6 +433,26 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
break;
}
}
+
+ /*
+ FIXME: Actually we should do this before
+ check_that_all_fields_are_given_values Or even go into write_record ?
+ */
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_INSERT,
+ TRG_ACTION_BEFORE);
+
+ if ((res= table_list->view_check_option(thd,
+ (values_list.elements == 1 ?
+ 0 :
+ ignore))) ==
+ VIEW_CHECK_SKIP)
+ continue;
+ else if (res == VIEW_CHECK_ERROR)
+ {
+ error= 1;
+ break;
+ }
#ifndef EMBEDDED_LIBRARY
if (lock_type == TL_WRITE_DELAYED)
{
@@ -369,9 +461,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
}
else
#endif
- error=write_record(table,&info);
- if (error)
- break;
+ error=write_record(thd, table ,&info);
/*
If auto_increment values are used, save the first one
for LAST_INSERT_ID() and for the update log.
@@ -382,7 +472,12 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
{ // Get auto increment value
id= thd->last_insert_id;
}
+ if (error)
+ break;
thd->row_count++;
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_INSERT, TRG_ACTION_AFTER);
}
/*
@@ -416,28 +511,28 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
/*
Invalidate the table in the query cache if something changed.
For the transactional algorithm to work the invalidation must be
- before binlog writing and ha_autocommit_...
+ before binlog writing and ha_autocommit_or_rollback
*/
if (info.copied || info.deleted || info.updated)
+ {
query_cache_invalidate3(thd, table_list, 1);
+ }
transactional_table= table->file->has_transactions();
- log_delayed= (transactional_table || table->tmp_table);
if ((info.copied || info.deleted || info.updated) &&
(error <= 0 || !transactional_table))
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed, FALSE);
+ transactional_table, FALSE);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1;
}
- if (!log_delayed)
+ if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (transactional_table)
@@ -466,7 +561,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
goto abort;
if (values_list.elements == 1 && (!(thd->options & OPTION_WARNINGS) ||
!thd->cuted_fields))
- send_ok(thd,info.copied+info.deleted+info.updated,id);
+ {
+ thd->row_count_func= info.copied+info.deleted+info.updated;
+ send_ok(thd, (ulong) thd->row_count_func, id);
+ }
else
{
char buff[160];
@@ -477,11 +575,12 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
else
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
(ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields);
- ::send_ok(thd,info.copied+info.deleted+info.updated,(ulonglong)id,buff);
+ thd->row_count_func= info.copied+info.deleted+info.updated;
+ ::send_ok(thd, (ulong) thd->row_count_func, id, buff);
}
free_underlaid_joins(thd, &thd->lex->select_lex);
- table->insert_values=0;
- DBUG_RETURN(0);
+ thd->abort_on_warning= 0;
+ DBUG_RETURN(FALSE);
abort:
#ifndef EMBEDDED_LIBRARY
@@ -489,8 +588,137 @@ abort:
end_delayed_insert(thd);
#endif
free_underlaid_joins(thd, &thd->lex->select_lex);
- table->insert_values=0;
- DBUG_RETURN(-1);
+ thd->abort_on_warning= 0;
+ DBUG_RETURN(TRUE);
+}
+
+
+/*
+ Additional check for insertability for VIEW
+
+ SYNOPSIS
+ check_view_insertability()
+ view - reference on VIEW
+
+ IMPLEMENTATION
+ A view is insertable if the folloings are true:
+ - All columns in the view are columns from a table
+ - All not used columns in table have a default values
+ - All field in view are unique (not referring to the same column)
+
+ RETURN
+ FALSE - OK
+ view->contain_auto_increment is 1 if and only if the view contains an
+ auto_increment field
+
+ TRUE - can't be used for insert
+*/
+
+static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id)
+{
+ uint num= view->view->select_lex.item_list.elements;
+ TABLE *table= view->table;
+ Field_translator *trans_start= view->field_translation,
+ *trans_end= trans_start + num;
+ Field_translator *trans;
+ Field **field_ptr= table->field;
+ query_id_t other_query_id= query_id - 1;
+ DBUG_ENTER("check_key_in_view");
+
+ DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
+
+ view->contain_auto_increment= 0;
+ /* check simplicity and prepare unique test of view */
+ for (trans= trans_start; trans != trans_end; trans++)
+ {
+ Item_field *field;
+ /* simple SELECT list entry (field without expression) */
+ if (!(field= trans->item->filed_for_view_update()))
+ DBUG_RETURN(TRUE);
+ 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
+ */
+ trans->item= field;
+ }
+ /* unique test */
+ for (trans= trans_start; trans != trans_end; trans++)
+ {
+ /* 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)
+ 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);
+}
+
+
+/*
+ Check if table can be updated
+
+ SYNOPSIS
+ mysql_prepare_insert_check_table()
+ thd Thread handle
+ table_list Table list
+ fields List of fields to be updated
+ where Pointer to where clause
+ select_insert Check is making for SELECT ... INSERT
+
+ RETURN
+ FALSE ok
+ TRUE ERROR
+*/
+
+static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
+ List<Item> &fields, COND **where,
+ bool select_insert)
+{
+ 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,
+ FALSE, select_insert))
+ DBUG_RETURN(TRUE);
+
+ if (insert_into_view && !fields.elements)
+ {
+ thd->lex->empty_field_list_on_rset= 1;
+ if (!table_list->table)
+ {
+ DBUG_ASSERT(table_list->view &&
+ table_list->ancestor && table_list->ancestor->next_local);
+ my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
+ table_list->view_db.str, table_list->view_name.str);
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(insert_view_fields(&fields, table_list));
+ }
+
+ DBUG_RETURN(FALSE);
}
@@ -499,47 +727,70 @@ abort:
SYNOPSIS
mysql_prepare_insert()
- thd - thread handler
- table_list - global table list
- insert_table_list - local table list of INSERT SELECT_LEX
- values - values to insert. NULL for INSERT ... SELECT
+ 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)
+ where Where clause (for insert ... select)
+ select_insert TRUE if INSERT ... SELECT statement
RETURN VALUE
- 0 - OK
- -1 - error (message is not sent to user)
+ FALSE OK
+ TRUE error
*/
-int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
- TABLE_LIST *insert_table_list, TABLE *table,
- List<Item> &fields, List_item *values,
- List<Item> &update_fields, List<Item> &update_values,
- enum_duplicates duplic)
+
+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)
{
+ bool insert_into_view= (table_list->view != 0);
+ /* TODO: use this condition for 'WITH CHECK OPTION' */
+ bool res;
+ TABLE_LIST *next_local;
DBUG_ENTER("mysql_prepare_insert");
- if (duplic == DUP_UPDATE && !table->insert_values)
+ DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
+ (ulong)table_list, (ulong)table,
+ (int)insert_into_view));
+
+ if (duplic == DUP_UPDATE)
{
/* it should be allocated before Item::fix_fields() */
- table->insert_values=
- (byte *)alloc_root(thd->mem_root, table->rec_buff_length);
- if (!table->insert_values)
- DBUG_RETURN(-1);
- }
- if ((values && check_insert_fields(thd, table, fields, *values)) ||
- setup_tables(insert_table_list) ||
- (values && setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0)) ||
+ if (table_list->set_insert_values(thd->mem_root))
+ DBUG_RETURN(TRUE);
+ }
+
+ if (mysql_prepare_insert_check_table(thd, table_list, fields, where,
+ select_insert))
+ DBUG_RETURN(TRUE);
+
+ next_local= table_list->next_local;
+ table_list->next_local= 0;
+ 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 &&
- (check_update_fields(thd, table, insert_table_list, update_fields) ||
- setup_fields(thd, 0, insert_table_list, update_values, 1, 0, 0))))
- DBUG_RETURN(-1);
- if (values && find_real_table_in_list(table_list->next, table_list->db,
- table_list->real_name))
+ ((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;
+
+ if (!table)
+ table= table_list->table;
+
+ if (!select_insert && unique_table(table_list, table_list->next_global))
{
- my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
- DBUG_RETURN(-1);
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
+ DBUG_RETURN(TRUE);
}
if (duplic == DUP_UPDATE || duplic == DUP_REPLACE)
table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY);
-
- DBUG_RETURN(0);
+ thd->lex->select_lex.first_execution= 0;
+ DBUG_RETURN(FALSE);
}
@@ -547,7 +798,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
static int last_uniq_key(TABLE *table,uint keynr)
{
- while (++keynr < table->keys)
+ while (++keynr < table->s->keys)
if (table->key_info[keynr].flags & HA_NOSAME)
return 0;
return 1;
@@ -556,10 +807,12 @@ static int last_uniq_key(TABLE *table,uint keynr)
/*
Write a record to table with optional deleting of conflicting records
+
+ Sets thd->no_trans_update if table which is updated didn't have transactions
*/
-int write_record(TABLE *table,COPY_INFO *info)
+int write_record(THD *thd, TABLE *table,COPY_INFO *info)
{
int error;
char *key=0;
@@ -571,9 +824,10 @@ int write_record(TABLE *table,COPY_INFO *info)
{
while ((error=table->file->write_row(table->record[0])))
{
+ uint key_nr;
if (error != HA_WRITE_SKIP)
goto err;
- uint key_nr;
+ table->file->restore_auto_increment();
if ((int) (key_nr = table->file->get_dup_key(error)) < 0)
{
error=HA_WRITE_SKIP; /* Database can't find key */
@@ -586,7 +840,7 @@ int write_record(TABLE *table,COPY_INFO *info)
*/
if (info->handle_duplicates == DUP_REPLACE &&
table->next_number_field &&
- key_nr == table->next_number_index &&
+ key_nr == table->s->next_number_index &&
table->file->auto_increment_column_changed)
goto err;
if (table->file->table_flags() & HA_DUPP_POS)
@@ -604,14 +858,14 @@ int write_record(TABLE *table,COPY_INFO *info)
if (!key)
{
- if (!(key=(char*) my_safe_alloca(table->max_unique_length,
+ if (!(key=(char*) my_safe_alloca(table->s->max_unique_length,
MAX_KEY_LENGTH)))
{
error=ENOMEM;
goto err;
}
}
- key_copy((byte*) key,table,key_nr,0);
+ key_copy((byte*) key,table->record[0],table->key_info+key_nr,0);
if ((error=(table->file->index_read_idx(table->record[1],key_nr,
(byte*) key,
table->key_info[key_nr].
@@ -621,6 +875,7 @@ int write_record(TABLE *table,COPY_INFO *info)
}
if (info->handle_duplicates == DUP_UPDATE)
{
+ int res= 0;
/* we don't check for other UNIQUE keys - the first row
that matches, is updated. If update causes a conflict again,
an error is returned
@@ -628,9 +883,19 @@ int write_record(TABLE *table,COPY_INFO *info)
DBUG_ASSERT(table->insert_values != NULL);
store_record(table,insert_values);
restore_record(table,record[1]);
- DBUG_ASSERT(info->update_fields->elements==info->update_values->elements);
- if (fill_record(*info->update_fields, *info->update_values, 0))
+ DBUG_ASSERT(info->update_fields->elements ==
+ info->update_values->elements);
+ if (fill_record(thd, *info->update_fields, *info->update_values, 0))
+ goto err;
+
+ /* CHECK OPTION for VIEW ... ON DUPLICATE KEY UPDATE ... */
+ if (info->view &&
+ (res= info->view->view_check_option(current_thd, info->ignore)) ==
+ VIEW_CHECK_SKIP)
+ break;
+ if (res == VIEW_CHECK_ERROR)
goto err;
+
if ((error=table->file->update_row(table->record[1],table->record[0])))
goto err;
info->updated++;
@@ -660,6 +925,8 @@ int write_record(TABLE *table,COPY_INFO *info)
else if ((error=table->file->delete_row(table->record[1])))
goto err;
info->deleted++;
+ if (!table->file->has_transactions())
+ thd->no_trans_update= 1;
}
}
info->copied++;
@@ -669,11 +936,14 @@ int write_record(TABLE *table,COPY_INFO *info)
if (!info->ignore ||
(error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE))
goto err;
+ table->file->restore_auto_increment();
}
else
info->copied++;
if (key)
- my_safe_afree(key,table->max_unique_length,MAX_KEY_LENGTH);
+ my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH);
+ if (!table->file->has_transactions())
+ thd->no_trans_update= 1;
DBUG_RETURN(0);
err:
@@ -687,27 +957,24 @@ err:
/******************************************************************************
Check that all fields with arn't null_fields are used
- If DONT_USE_DEFAULT_FIELDS isn't defined use default value for not set
- fields.
******************************************************************************/
-static int check_null_fields(THD *thd __attribute__((unused)),
- TABLE *entry __attribute__((unused)))
+int check_that_all_fields_are_given_values(THD *thd, TABLE *entry)
{
-#ifdef DONT_USE_DEFAULT_FIELDS
+ int err= 0;
for (Field **field=entry->field ; *field ; field++)
{
- if ((*field)->query_id != thd->query_id && !(*field)->maybe_null() &&
- *field != entry->timestamp_field &&
- *field != entry->next_number_field)
+ if ((*field)->query_id != thd->query_id &&
+ ((*field)->flags & NO_DEFAULT_VALUE_FLAG))
{
- my_printf_error(ER_BAD_NULL_ERROR, ER(ER_BAD_NULL_ERROR),MYF(0),
- (*field)->field_name);
- return 1;
+ 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;
}
}
-#endif
- return 0;
+ return thd->abort_on_warning ? err : 0;
}
/*****************************************************************************
@@ -722,14 +989,13 @@ public:
char *record,*query;
enum_duplicates dup;
time_t start_time;
- bool query_start_used,last_insert_id_used,insert_id_used, ignore;
- int log_query;
+ bool query_start_used,last_insert_id_used,insert_id_used, ignore, log_query;
ulonglong last_insert_id;
timestamp_auto_set_type timestamp_field_type;
uint query_length;
- delayed_row(enum_duplicates dup_arg, bool ignore_arg, int log_query_arg)
- :record(0),query(0),dup(dup_arg),ignore(ignore_arg),log_query(log_query_arg) {}
+ delayed_row(enum_duplicates dup_arg, bool ignore_arg, bool log_query_arg)
+ :record(0), query(0), dup(dup_arg), ignore(ignore_arg), log_query(log_query_arg) {}
~delayed_row()
{
x_free(record);
@@ -836,7 +1102,7 @@ delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
while ((tmp=it++))
{
if (!strcmp(tmp->thd.db,table_list->db) &&
- !strcmp(table_list->real_name,tmp->table->real_name))
+ !strcmp(table_list->table_name,tmp->table->s->table_name))
{
tmp->lock();
break;
@@ -892,15 +1158,15 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
thread_count++;
pthread_mutex_unlock(&LOCK_thread_count);
if (!(tmp->thd.db=my_strdup(table_list->db,MYF(MY_WME))) ||
- !(tmp->thd.query=my_strdup(table_list->real_name,MYF(MY_WME))))
+ !(tmp->thd.query=my_strdup(table_list->table_name,MYF(MY_WME))))
{
delete tmp;
- my_error(ER_OUT_OF_RESOURCES,MYF(0));
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
goto err1;
}
tmp->table_list= *table_list; // Needed to open table
tmp->table_list.db= tmp->thd.db;
- tmp->table_list.alias= tmp->table_list.real_name=tmp->thd.query;
+ tmp->table_list.alias= tmp->table_list.table_name= tmp->thd.query;
tmp->lock();
pthread_mutex_lock(&tmp->mutex);
if ((error=pthread_create(&tmp->thd.real_id,&connection_attrib,
@@ -912,7 +1178,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
pthread_mutex_unlock(&tmp->mutex);
tmp->unlock();
delete tmp;
- net_printf(thd,ER_CANT_CREATE_THREAD,error);
+ my_error(ER_CANT_CREATE_THREAD, MYF(0), error);
goto err1;
}
@@ -947,7 +1213,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
}
pthread_mutex_lock(&tmp->mutex);
- table=tmp->get_local_table(thd);
+ table= tmp->get_local_table(thd);
pthread_mutex_unlock(&tmp->mutex);
if (table)
thd->di=tmp;
@@ -1003,17 +1269,19 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
client_thd->proc_info="allocating local table";
copy= (TABLE*) client_thd->alloc(sizeof(*copy)+
- (table->fields+1)*sizeof(Field**)+
- table->reclength);
+ (table->s->fields+1)*sizeof(Field**)+
+ table->s->reclength);
if (!copy)
goto error;
*copy= *table;
- bzero((char*) &copy->name_hash,sizeof(copy->name_hash)); // No name hashing
+ copy->s= &copy->share_not_to_be_used;
+ // No name hashing
+ bzero((char*) &copy->s->name_hash,sizeof(copy->s->name_hash));
/* We don't need to change the file handler here */
field=copy->field=(Field**) (copy+1);
- copy->record[0]=(byte*) (field+table->fields+1);
- memcpy((char*) copy->record[0],(char*) table->record[0],table->reclength);
+ copy->record[0]=(byte*) (field+table->s->fields+1);
+ memcpy((char*) copy->record[0],(char*) table->record[0],table->s->reclength);
/* Make a copy of all fields */
@@ -1036,7 +1304,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
{
/* Restore offset as this may have been reset in handle_inserts */
copy->timestamp_field=
- (Field_timestamp*) copy->field[table->timestamp_field_offset];
+ (Field_timestamp*) copy->field[table->s->timestamp_field_offset];
copy->timestamp_field->unireg_check= table->timestamp_field->unireg_check;
copy->timestamp_field_type= copy->timestamp_field->get_auto_set_type();
}
@@ -1061,7 +1329,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
/* Put a question in queue */
static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool ignore,
- char *query, uint query_length, int log_on)
+ char *query, uint query_length, bool log_on)
{
delayed_row *row=0;
delayed_insert *di=thd->di;
@@ -1078,13 +1346,13 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool igno
if (!query)
query_length=0;
- if (!(row->record= (char*) my_malloc(table->reclength+query_length+1,
+ if (!(row->record= (char*) my_malloc(table->s->reclength+query_length+1,
MYF(MY_WME))))
goto err;
- memcpy(row->record,table->record[0],table->reclength);
+ memcpy(row->record, table->record[0], table->s->reclength);
if (query_length)
{
- row->query=row->record+table->reclength;
+ row->query= row->record+table->s->reclength;
memcpy(row->query,query,query_length+1);
}
row->query_length= query_length;
@@ -1098,7 +1366,7 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic, bool igno
di->rows.push_back(row);
di->stacked_inserts++;
di->status=1;
- if (table->blob_fields)
+ if (table->s->blob_fields)
unlink_blobs(table);
pthread_cond_signal(&di->cond);
@@ -1141,7 +1409,7 @@ void kill_delayed_threads(void)
{
/* Ensure that the thread doesn't kill itself while we are looking at it */
pthread_mutex_lock(&tmp->mutex);
- tmp->thd.killed=1;
+ tmp->thd.killed= THD::KILL_CONNECTION;
if (tmp->thd.mysys_var)
{
pthread_mutex_lock(&tmp->thd.mysys_var->mutex);
@@ -1180,7 +1448,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
thd->thread_id=thread_id++;
thd->end_time();
threads.append(thd);
- thd->killed=abort_loop;
+ thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED;
pthread_mutex_unlock(&LOCK_thread_count);
/*
@@ -1223,7 +1491,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
if (!(di->table->file->table_flags() & HA_CAN_INSERT_DELAYED))
{
thd->fatal_error();
- my_error(ER_ILLEGAL_HA, MYF(0), di->table_list.real_name);
+ my_error(ER_ILLEGAL_HA, MYF(0), di->table_list.table_name);
goto end;
}
di->table->copy_blobs=1;
@@ -1241,7 +1509,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
for (;;)
{
- if (thd->killed)
+ if (thd->killed == THD::KILL_CONNECTION)
{
uint lock_count;
/*
@@ -1289,7 +1557,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
break;
if (error == ETIME || error == ETIMEDOUT)
{
- thd->killed=1;
+ thd->killed= THD::KILL_CONNECTION;
break;
}
}
@@ -1317,8 +1585,9 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
*/
if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, TRUE)))
{
- di->dead= 1; // Some fatal error
- thd->killed= 1;
+ /* Fatal error */
+ di->dead= 1;
+ thd->killed= THD::KILL_CONNECTION;
}
pthread_cond_broadcast(&di->cond_client);
}
@@ -1326,8 +1595,9 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
{
if (di->handle_inserts())
{
- di->dead= 1; // Some fatal error
- thd->killed= 1;
+ /* Some fatal error */
+ di->dead= 1;
+ thd->killed= THD::KILL_CONNECTION;
}
}
di->status=0;
@@ -1357,7 +1627,7 @@ end:
close_thread_tables(thd); // Free the table
di->table=0;
di->dead= 1; // If error
- thd->killed= 1;
+ thd->killed= THD::KILL_CONNECTION; // If error
pthread_cond_broadcast(&di->cond_client); // Safety
pthread_mutex_unlock(&di->mutex);
@@ -1418,15 +1688,15 @@ bool delayed_insert::handle_inserts(void)
if (thr_upgrade_write_delay_lock(*thd.lock->locks))
{
/* This can only happen if thread is killed by shutdown */
- sql_print_error(ER(ER_DELAYED_CANT_CHANGE_LOCK),table->real_name);
+ sql_print_error(ER(ER_DELAYED_CANT_CHANGE_LOCK),table->s->table_name);
goto err;
}
thd.proc_info="insert";
max_rows=delayed_insert_limit;
- if (thd.killed || table->version != refresh_version)
+ if (thd.killed || table->s->version != refresh_version)
{
- thd.killed=1;
+ thd.killed= THD::KILL_CONNECTION;
max_rows= ~0; // Do as much as possible
}
@@ -1442,7 +1712,7 @@ bool delayed_insert::handle_inserts(void)
{
stacked_inserts--;
pthread_mutex_unlock(&mutex);
- memcpy(table->record[0],row->record,table->reclength);
+ memcpy(table->record[0],row->record,table->s->reclength);
thd.start_time=row->start_time;
thd.query_start_used=row->query_start_used;
@@ -1460,7 +1730,7 @@ bool delayed_insert::handle_inserts(void)
using_ignore=1;
}
thd.clear_error(); // reset error for binlog
- if (write_record(table,&info))
+ if (write_record(&thd, table, &info))
{
info.error_count++; // Ignore errors
thread_safe_increment(delayed_insert_errors,&LOCK_delayed_status);
@@ -1471,17 +1741,12 @@ bool delayed_insert::handle_inserts(void)
using_ignore=0;
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
}
- if (row->query)
+ if (row->query && row->log_query && using_bin_log)
{
- if (row->log_query & DELAYED_LOG_UPDATE)
- mysql_update_log.write(&thd,row->query, row->query_length);
- if (row->log_query & DELAYED_LOG_BIN && using_bin_log)
- {
- Query_log_event qinfo(&thd, row->query, row->query_length,0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ Query_log_event qinfo(&thd, row->query, row->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
}
- if (table->blob_fields)
+ if (table->s->blob_fields)
free_delayed_insert_blobs(table);
thread_safe_sub(delayed_rows_in_use,1,&LOCK_delayed_status);
thread_safe_increment(delayed_insert_writes,&LOCK_delayed_status);
@@ -1495,7 +1760,7 @@ bool delayed_insert::handle_inserts(void)
on this table until all entries has been processed
*/
if (group_count++ >= max_rows && (row= rows.head()) &&
- (!(row->log_query & DELAYED_LOG_BIN && using_bin_log) ||
+ (!(row->log_query & using_bin_log) ||
row->query))
{
group_count=0;
@@ -1516,7 +1781,7 @@ bool delayed_insert::handle_inserts(void)
if (thr_reschedule_write_lock(*thd.lock->locks))
{
/* This should never happen */
- sql_print_error(ER(ER_DELAYED_CANT_CHANGE_LOCK),table->real_name);
+ sql_print_error(ER(ER_DELAYED_CANT_CHANGE_LOCK),table->s->table_name);
}
if (!using_bin_log)
table->file->extra(HA_EXTRA_WRITE_CACHE);
@@ -1559,22 +1824,147 @@ bool delayed_insert::handle_inserts(void)
Store records in INSERT ... SELECT *
***************************************************************************/
+
+/*
+ make insert specific preparation and checks after opening tables
+
+ SYNOPSIS
+ mysql_insert_select_prepare()
+ thd thread handler
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool mysql_insert_select_prepare(THD *thd)
+{
+ LEX *lex= thd->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))
+ 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;
+ /* skip all leaf tables belonged to view where we are insert */
+ for (first_select_leaf_table= lex->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;
+ DBUG_RETURN(FALSE);
+}
+
+
+select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par,
+ List<Item> *fields_par,
+ List<Item> *update_fields,
+ List<Item> *update_values,
+ enum_duplicates duplic,
+ bool ignore_check_option_errors)
+ :table_list(table_list_par), table(table_par), fields(fields_par),
+ last_insert_id(0),
+ insert_into_view(table_list_par && table_list_par->view != 0)
+{
+ bzero((char*) &info,sizeof(info));
+ info.handle_duplicates= duplic;
+ info.ignore= ignore_check_option_errors;
+ info.update_fields= update_fields;
+ info.update_values= update_values;
+ if (table_list_par)
+ info.view= (table_list_par->view ? table_list_par : 0);
+}
+
+
int
select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
DBUG_ENTER("select_insert::prepare");
unit= u;
- if (check_insert_fields(thd, table, *fields, values))
+ if (check_insert_fields(thd, table_list, *fields, values, !insert_into_view))
DBUG_RETURN(1);
+ /*
+ if it is INSERT into join view then check_insert_fields already found
+ real table for insert
+ */
+ table= table_list->table;
- restore_record(table,default_values); // Get empty record
+ /*
+ Is table which we are changing used somewhere in other parts of
+ query
+ */
+ if (!(thd->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;
+ }
+ else
+ {
+ /*
+ We must not yet prepare the result table if it is the same as one of the
+ source tables (INSERT SELECT). The preparation may disable
+ indexes on the result table, which may be used during the select, if it
+ is the same table (Bug #6034). Do the preparation after the select phase
+ in select_insert::prepare2().
+ */
+ table->file->start_bulk_insert((ha_rows) 0);
+ }
+ restore_record(table,s->default_values); // Get empty record
table->next_number_field=table->found_next_number_field;
thd->cuted_fields=0;
- if (info.ignore ||
- info.handle_duplicates != DUP_ERROR)
+ if (info.ignore || info.handle_duplicates != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- table->file->start_bulk_insert((ha_rows) 0);
+ thd->no_trans_update= 0;
+ thd->abort_on_warning= (!info.ignore &&
+ (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));
+}
+
+
+/*
+ Finish the preparation of the result table.
+
+ SYNOPSIS
+ select_insert::prepare2()
+ void
+
+ DESCRIPTION
+ If the result table is the same as one of the source tables (INSERT SELECT),
+ the result table is not finally prepared at the join prepair phase.
+ Do the final preparation now.
+
+ RETURN
+ 0 OK
+*/
+
+int select_insert::prepare2(void)
+{
+ DBUG_ENTER("select_insert::prepare2");
+ if (thd->lex->current_select->options & OPTION_BUFFER_RESULT)
+ table->file->start_bulk_insert((ha_rows) 0);
DBUG_RETURN(0);
}
@@ -1587,12 +1977,15 @@ void select_insert::cleanup()
select_insert::~select_insert()
{
+ DBUG_ENTER("~select_insert");
if (table)
{
table->next_number_field=0;
table->file->reset();
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
+ thd->abort_on_warning= 0;
+ DBUG_VOID_RETURN;
}
@@ -1605,12 +1998,24 @@ bool select_insert::send_data(List<Item> &values)
unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
- thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
+
+ thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields
store_values(values);
- error=thd->net.report_error || write_record(table,&info);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
- if (!error && table->next_number_field) // Clear for next record
+ if (thd->net.report_error)
+ DBUG_RETURN(1);
+ if (table_list) // Not CREATE ... SELECT
+ {
+ switch (table_list->view_check_option(thd, info.ignore)) {
+ case VIEW_CHECK_SKIP:
+ DBUG_RETURN(0);
+ case VIEW_CHECK_ERROR:
+ DBUG_RETURN(1);
+ }
+ }
+ if (!(error= write_record(thd, table,&info)) && table->next_number_field)
{
+ /* Clear for next record */
table->next_number_field->reset();
if (! last_insert_id && thd->insert_id_used)
last_insert_id=thd->insert_id();
@@ -1622,17 +2027,16 @@ bool select_insert::send_data(List<Item> &values)
void select_insert::store_values(List<Item> &values)
{
if (fields->elements)
- fill_record(*fields, values, 1);
+ fill_record(thd, *fields, values, 1);
else
- fill_record(table->field, values, 1);
+ fill_record(thd, table->field, values, 1);
}
void select_insert::send_error(uint errcode,const char *err)
{
DBUG_ENTER("select_insert::send_error");
- /* TODO error should be sent at the query processing end */
- ::send_error(thd,errcode,err);
+ my_message(errcode, err, MYF(0));
if (!table)
{
@@ -1654,18 +2058,19 @@ void select_insert::send_error(uint errcode,const char *err)
{
if (last_insert_id)
thd->insert_id(last_insert_id); // For binary log
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
table->file->has_transactions(), FALSE);
mysql_bin_log.write(&qinfo);
}
- if (!table->tmp_table)
+ if (!table->s->tmp_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (info.copied || info.deleted || info.updated)
+ {
query_cache_invalidate3(thd, table, 1);
+ }
ha_rollback_stmt(thd);
DBUG_VOID_RETURN;
}
@@ -1681,20 +2086,19 @@ bool select_insert::send_eof()
/*
We must invalidate the table in the query cache before binlog writing
- and ha_autocommit_...
+ and ha_autocommit_or_rollback
*/
if (info.copied || info.deleted || info.updated)
{
query_cache_invalidate3(thd, table, 1);
- if (!(table->file->has_transactions() || table->tmp_table))
+ if (!(table->file->has_transactions() || table->s->tmp_table))
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (last_insert_id)
thd->insert_id(last_insert_id); // For binary log
/* Write to binlog before commiting transaction */
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
if (!error)
@@ -1708,8 +2112,6 @@ bool select_insert::send_eof()
if (error)
{
table->file->print_error(error,MYF(0));
- //TODO error should be sent at the query processing end
- ::send_error(thd);
DBUG_RETURN(1);
}
char buff[160];
@@ -1719,7 +2121,8 @@ bool select_insert::send_eof()
else
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
(ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields);
- ::send_ok(thd,info.copied+info.deleted+info.updated,last_insert_id,buff);
+ thd->row_count_func= info.copied+info.deleted+info.updated;
+ ::send_ok(thd, (ulong) thd->row_count_func, last_insert_id, buff);
DBUG_RETURN(0);
}
@@ -1734,40 +2137,42 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DBUG_ENTER("select_create::prepare");
unit= u;
- table= create_table_from_items(thd, create_info, db, name,
+ table= create_table_from_items(thd, create_info, create_table,
extra_fields, keys, &values, &lock);
if (!table)
DBUG_RETURN(-1); // abort() deletes table
- if (table->fields < values.elements)
+ if (table->s->fields < values.elements)
{
- my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
- ER(ER_WRONG_VALUE_COUNT_ON_ROW),
- MYF(0),1);
+ my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1);
DBUG_RETURN(-1);
}
/* First field to copy */
- field=table->field+table->fields - values.elements;
+ field=table->field+table->s->fields - values.elements;
/* Don't set timestamp if used */
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
table->next_number_field=table->found_next_number_field;
- restore_record(table,default_values); // Get empty record
+ restore_record(table,s->default_values); // Get empty record
thd->cuted_fields=0;
- if (info.ignore ||
- info.handle_duplicates != DUP_ERROR)
+ if (info.ignore || info.handle_duplicates != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
table->file->start_bulk_insert((ha_rows) 0);
- DBUG_RETURN(0);
+ thd->no_trans_update= 0;
+ thd->abort_on_warning= (!info.ignore &&
+ (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES)));
+ DBUG_RETURN(check_that_all_fields_are_given_values(thd, table));
}
void select_create::store_values(List<Item> &values)
{
- fill_record(field, values, 1);
+ fill_record(thd, field, values, 1);
}
@@ -1798,9 +2203,9 @@ bool select_create::send_eof()
Check if we can remove the following two rows.
We should be able to just keep the table in the table cache.
*/
- if (!table->tmp_table)
+ if (!table->s->tmp_table)
{
- ulong version= table->version;
+ ulong version= table->s->version;
hash_delete(&open_cache,(byte*) table);
/* Tell threads waiting for refresh that something has happened */
if (version != refresh_version)
@@ -1824,19 +2229,19 @@ void select_create::abort()
if (table)
{
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
- enum db_type table_type=table->db_type;
- if (!table->tmp_table)
+ enum db_type table_type=table->s->db_type;
+ if (!table->s->tmp_table)
{
- ulong version= table->version;
+ ulong version= table->s->version;
hash_delete(&open_cache,(byte*) table);
if (!create_info->table_existed)
- quick_rm_table(table_type, db, name);
+ quick_rm_table(table_type, create_table->db, create_table->table_name);
/* Tell threads waiting for refresh that something has happened */
if (version != refresh_version)
VOID(pthread_cond_broadcast(&COND_refresh));
}
else if (!create_info->table_existed)
- close_temporary_table(thd, db, name);
+ close_temporary_table(thd, create_table->db, create_table->table_name);
table=0;
}
VOID(pthread_mutex_unlock(&LOCK_open));
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d6dcd9ce9ae..61f710a2fe5 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -21,16 +21,14 @@
#include "item_create.h"
#include <m_ctype.h>
#include <hash.h>
-
+#include "sp.h"
+#include "sp_head.h"
/*
- Fake table list object, pointer to which is used as special value for
- st_lex::time_zone_tables_used indicating that we implicitly use time
- zone tables in this statement but real table list was not yet created.
- Pointer to it is also returned by my_tz_get_tables_list() as indication
- of transient error;
+ We are using pointer to this variable for distinguishing between assignment
+ to NEW row field (when parsing trigger definition) and structured variable.
*/
-TABLE_LIST fake_time_zone_tables_list;
+sys_var_long_ptr trg_new_row_fake_var(0, 0);
/* Macros to look like lex */
@@ -42,10 +40,6 @@ TABLE_LIST fake_time_zone_tables_list;
#define yySkip() lex->ptr++
#define yyLength() ((uint) (lex->ptr - lex->tok_start)-1)
-#if MYSQL_VERSION_ID < 32300
-#define FLOAT_NUM REAL_NUM
-#endif
-
pthread_key(LEX*,THR_LEX);
/* Longest standard keyword name */
@@ -117,14 +111,19 @@ void lex_free(void)
void lex_start(THD *thd, uchar *buf,uint length)
{
LEX *lex= thd->lex;
+ DBUG_ENTER("lex_start");
+
+ lex->thd= lex->unit.thd= thd;
+ lex->buf= lex->ptr= buf;
+ lex->end_of_query= buf+length;
+
lex->unit.init_query();
lex->unit.init_select();
- lex->thd= thd;
- lex->unit.thd= thd;
lex->select_lex.init_query();
lex->value_list.empty();
lex->update_list.empty();
lex->param_list.empty();
+ lex->view_list.empty();
lex->unit.next= lex->unit.master=
lex->unit.link_next= lex->unit.return_to= 0;
lex->unit.prev= lex->unit.link_prev= 0;
@@ -135,15 +134,23 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
lex->select_lex.options= 0;
+ lex->select_lex.init_order();
+ lex->select_lex.group_list.empty();
lex->describe= 0;
- lex->subqueries= lex->derived_tables= FALSE;
+ lex->subqueries= FALSE;
+ lex->view_prepare_mode= FALSE;
+ lex->derived_tables= 0;
lex->lock_option= TL_READ;
- lex->found_colon= 0;
+ 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->query_tables_last= &lex->query_tables;
+ lex->variables_used= 0;
+ lex->select_lex.parent_lex= lex;
+ lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
lex->next_state=MY_LEX_START;
- lex->end_of_query=(lex->ptr=buf)+length;
lex->yylineno = 1;
lex->in_comment=0;
lex->length=0;
@@ -159,15 +166,20 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->sql_command=SQLCOM_END;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
+ lex->sphead= NULL;
+ lex->spcont= NULL;
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);
+ DBUG_VOID_RETURN;
}
void lex_end(LEX *lex)
{
- for (SELECT_LEX *sl= lex->all_selects_list;
- sl;
- sl= sl->next_select_in_list())
- sl->expr_list.delete_elements(); // If error when parsing sql-varargs
x_free(lex->yacc_yyss);
x_free(lex->yacc_yyvs);
}
@@ -183,29 +195,16 @@ static int find_keyword(LEX *lex, uint len, bool function)
lex->yylval->symbol.symbol=symbol;
lex->yylval->symbol.str= (char*) tok;
lex->yylval->symbol.length=len;
+
+ if ((symbol->tok == NOT_SYM) &&
+ (lex->thd->variables.sql_mode & MODE_HIGH_NOT_PRECEDENCE))
+ return NOT2_SYM;
+ if ((symbol->tok == OR_OR_SYM) &&
+ !(lex->thd->variables.sql_mode & MODE_PIPES_AS_CONCAT))
+ return OR2_SYM;
+
return symbol->tok;
}
-#ifdef HAVE_DLOPEN
- udf_func *udf;
- if (function && using_udf_functions && (udf=find_udf((char*) tok, len)))
- {
- lex->safe_to_cache_query=0;
- lex->yylval->udf=udf;
- switch (udf->returns) {
- case STRING_RESULT:
- return (udf->type == UDFTYPE_FUNCTION) ? UDF_CHAR_FUNC : UDA_CHAR_SUM;
- case REAL_RESULT:
- return (udf->type == UDFTYPE_FUNCTION) ? UDF_FLOAT_FUNC : UDA_FLOAT_SUM;
- case INT_RESULT:
- return (udf->type == UDFTYPE_FUNCTION) ? UDF_INT_FUNC : UDA_INT_SUM;
- case ROW_RESULT:
- default:
- // This case should never be choosen
- DBUG_ASSERT(0);
- return 0;
- }
- }
-#endif
return 0;
}
@@ -290,7 +289,8 @@ static char *get_text(LEX *lex)
continue;
}
#endif
- if (c == '\\')
+ if (c == '\\' &&
+ !(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES))
{ // Escaped character
found_escape=1;
if (lex->ptr == lex->end_of_query)
@@ -351,7 +351,9 @@ static char *get_text(LEX *lex)
continue;
}
#endif
- if (!found_escape && *str == '\\' && str+1 != end)
+ if (!found_escape &&
+ !(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
+ *str == '\\' && str+1 != end)
{
switch(*++str) {
case 'n':
@@ -455,12 +457,12 @@ inline static uint int_token(const char *str,uint length)
else if (length < signed_longlong_len)
return LONG_NUM;
else if (length > signed_longlong_len)
- return REAL_NUM;
+ return DECIMAL_NUM;
else
{
cmp=signed_longlong_str+1;
smaller=LONG_NUM; // If <= signed_longlong_str
- bigger=REAL_NUM;
+ bigger=DECIMAL_NUM;
}
}
else
@@ -476,10 +478,10 @@ inline static uint int_token(const char *str,uint length)
else if (length > longlong_len)
{
if (length > unsigned_longlong_len)
- return REAL_NUM;
+ return DECIMAL_NUM;
cmp=unsigned_longlong_str;
smaller=ULONGLONG_NUM;
- bigger=REAL_NUM;
+ bigger=DECIMAL_NUM;
}
else
{
@@ -582,8 +584,12 @@ int yylex(void *arg, void *yythd)
state= MY_LEX_HEX_NUMBER;
break;
}
- /* Fall through */
- case MY_LEX_IDENT_OR_BIN: // TODO: Add binary string handling
+ case MY_LEX_IDENT_OR_BIN:
+ if (yyPeek() == '\'')
+ { // Found b'bin-number'
+ state= MY_LEX_BIN_NUMBER;
+ break;
+ }
case MY_LEX_IDENT:
uchar *start;
#if defined(USE_MB) && defined(USE_MB_IDENT)
@@ -704,6 +710,20 @@ int yylex(void *arg, void *yythd)
}
yyUnget();
}
+ else if (c == 'b' && (lex->ptr - lex->tok_start) == 2 &&
+ lex->tok_start[0] == '0' )
+ { // b'bin-number'
+ while (my_isxdigit(cs,(c = yyGet()))) ;
+ if ((lex->ptr - lex->tok_start) >= 4 && !ident_map[c])
+ {
+ yylval->lex_str= get_token(lex, yyLength());
+ yylval->lex_str.str+= 2; // Skip 0x
+ yylval->lex_str.length-= 2;
+ lex->yytoklen-= 2;
+ return (BIN_NUM);
+ }
+ yyUnget();
+ }
// fall through
case MY_LEX_IDENT_START: // We come here after '.'
result_state= IDENT;
@@ -799,7 +819,7 @@ int yylex(void *arg, void *yythd)
return(FLOAT_NUM);
}
yylval->lex_str=get_token(lex,yyLength());
- return(REAL_NUM);
+ return(DECIMAL_NUM);
case MY_LEX_HEX_NUMBER: // Found x'hexstring'
yyGet(); // Skip '
@@ -816,6 +836,19 @@ int yylex(void *arg, void *yythd)
lex->yytoklen-=3;
return (HEX_NUM);
+ case MY_LEX_BIN_NUMBER: // Found b'bin-string'
+ yyGet(); // Skip '
+ while ((c= yyGet()) == '0' || c == '1');
+ length= (lex->ptr - lex->tok_start); // Length of bin-num + 3
+ if (c != '\'')
+ return(ABORT_SYM); // Illegal hex constant
+ yyGet(); // get_token makes an unget
+ yylval->lex_str= get_token(lex, length);
+ yylval->lex_str.str+= 2; // Skip b'
+ yylval->lex_str.length-= 3; // Don't count b' and last '
+ lex->yytoklen-= 3;
+ return (BIN_NUM);
+
case MY_LEX_CMP_OP: // Incomplete comparison operator
if (state_map[yyPeek()] == MY_LEX_CMP_OP ||
state_map[yyPeek()] == MY_LEX_LONG_CMP_OP)
@@ -935,14 +968,13 @@ int yylex(void *arg, void *yythd)
if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) &&
(thd->command != COM_PREPARE))
{
- lex->safe_to_cache_query=0;
- lex->found_colon=(char*)lex->ptr;
- thd->server_status |= SERVER_MORE_RESULTS_EXISTS;
- lex->next_state=MY_LEX_END;
- return(END_OF_INPUT);
+ lex->safe_to_cache_query= 0;
+ lex->found_semicolon=(char*) lex->ptr;
+ thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
+ lex->next_state= MY_LEX_END;
+ return (END_OF_INPUT);
}
- else
- state=MY_LEX_CHAR; // Return ';'
+ state= MY_LEX_CHAR; // Return ';'
break;
}
/* fall true */
@@ -1056,24 +1088,32 @@ void st_select_lex_unit::init_query()
cleaned= 0;
item_list.empty();
describe= 0;
+ found_rows_for_union= 0;
}
void st_select_lex::init_query()
{
st_select_lex_node::init_query();
table_list.empty();
+ top_join_list.empty();
+ join_list= &top_join_list;
+ embedding= leaf_tables= 0;
item_list.empty();
join= 0;
- where= 0;
+ where= prep_where= 0;
olap= UNSPECIFIED_OLAP_TYPE;
having_fix_field= 0;
resolve_mode= NOMATTER_MODE;
cond_count= with_wild= 0;
+ conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
select_n_having_items= 0;
- prep_where= 0;
subquery_in_having= explicit_limit= 0;
+ first_execution= 1;
+ first_cond_optimization= 1;
parsing_place= NO_MATTER;
+ exclude_from_table_unique_test= no_wrap_view_item= FALSE;
+ link_next= 0;
}
void st_select_lex::init_select()
@@ -1325,7 +1365,7 @@ bool st_select_lex::test_limit()
if (select_limit != HA_POS_ERROR)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
- "LIMIT & IN/ALL/ANY/SOME subquery");
+ "LIMIT & IN/ALL/ANY/SOME subquery");
return(1);
}
// We need only 1 row to determinate existence
@@ -1335,147 +1375,6 @@ bool st_select_lex::test_limit()
return(0);
}
-/*
- Interface method of table list creation for query
-
- SYNOPSIS
- st_select_lex_unit::create_total_list()
- thd THD pointer
- result pointer on result list of tables pointer
- check_derived force derived table chacking (used for creating
- table list for derived query)
- DESCRIPTION
- This is used for UNION & subselect to create a new table list of all used
- tables.
- The table_list->table entry in all used tables are set to point
- to the entries in this list.
-
- RETURN
- 0 - OK
- !0 - error
-*/
-bool st_select_lex_unit::create_total_list(THD *thd_arg, st_lex *lex,
- TABLE_LIST **result_arg)
-{
- *result_arg= 0;
- if (!(res= create_total_list_n_last_return(thd_arg, lex, &result_arg)))
- {
- /*
- If time zone tables were used implicitly in statement we should add
- them to global table list.
- */
- if (lex->time_zone_tables_used)
- {
- /*
- Altough we are modifying lex data, it won't raise any problem in
- case when this lex belongs to some prepared statement or stored
- procedure: such modification does not change any invariants imposed
- by requirement to reuse the same lex for multiple executions.
- */
- if ((lex->time_zone_tables_used= my_tz_get_table_list(thd)) !=
- &fake_time_zone_tables_list)
- {
- *result_arg= lex->time_zone_tables_used;
- }
- else
- {
- send_error(thd, 0);
- res= 1;
- }
- }
- }
- return res;
-}
-
-/*
- Table list creation for query
-
- SYNOPSIS
- st_select_lex_unit::create_total_list()
- thd THD pointer
- lex pointer on LEX stricture
- result pointer on pointer on result list of tables pointer
-
- DESCRIPTION
- This is used for UNION & subselect to create a new table list of all used
- tables.
- The table_list->table_list in all tables of global list are set to point
- to the local SELECT_LEX entries.
-
- RETURN
- 0 - OK
- !0 - error
-*/
-bool st_select_lex_unit::
-create_total_list_n_last_return(THD *thd_arg,
- st_lex *lex,
- TABLE_LIST ***result_arg)
-{
- TABLE_LIST *slave_list_first=0, **slave_list_last= &slave_list_first;
- TABLE_LIST **new_table_list= *result_arg, *aux;
- SELECT_LEX *sl= (SELECT_LEX*)slave;
-
- /*
- iterate all inner selects + fake_select (if exists),
- fake_select->next_select() always is 0
- */
- for (;
- sl;
- sl= (sl->next_select() ?
- sl->next_select() :
- (sl == fake_select_lex ?
- 0 :
- fake_select_lex)))
- {
- // check usage of ORDER BY in union
- if (sl->order_list.first && sl->next_select() && !sl->braces &&
- sl->linkage != GLOBAL_OPTIONS_TYPE)
- {
- net_printf(thd_arg,ER_WRONG_USAGE,"UNION","ORDER BY");
- return 1;
- }
-
- for (SELECT_LEX_UNIT *inner= sl->first_inner_unit();
- inner;
- inner= inner->next_unit())
- {
- if (inner->create_total_list_n_last_return(thd, lex,
- &slave_list_last))
- return 1;
- }
-
- if ((aux= (TABLE_LIST*) sl->table_list.first))
- {
- TABLE_LIST *next_table;
- for (; aux; aux= next_table)
- {
- TABLE_LIST *cursor;
- next_table= aux->next;
- /* Add to the total table list */
- if (!(cursor= (TABLE_LIST *) thd->memdup((char*) aux,
- sizeof(*aux))))
- {
- send_error(thd,0);
- return 1;
- }
- *new_table_list= cursor;
- cursor->table_list= aux;
- new_table_list= &cursor->next;
- *new_table_list= 0; // end result list
- aux->table_list= cursor;
- }
- }
- }
-
- if (slave_list_first)
- {
- *new_table_list= slave_list_first;
- new_table_list= slave_list_last;
- }
- *result_arg= new_table_list;
- return 0;
-}
-
st_select_lex_unit* st_select_lex_unit::master_unit()
{
@@ -1497,7 +1396,9 @@ bool st_select_lex::add_order_to_list(THD *thd, Item *item, bool asc)
bool st_select_lex::add_item_to_list(THD *thd, Item *item)
{
- return item_list.push_back(item);
+ DBUG_ENTER("st_select_lex::add_item_to_list");
+ DBUG_PRINT("info", ("Item: %p", item));
+ DBUG_RETURN(item_list.push_back(item));
}
@@ -1585,81 +1486,10 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
*/
Item_arena *arena= thd->current_arena;
return (ref_pointer_array=
- (Item **)arena->alloc(sizeof(Item*) *
- (item_list.elements +
- select_n_having_items +
- order_group_num)* 5)) == 0;
-}
-
-
-/*
- Find db.table which will be updated in this unit
-
- SYNOPSIS
- st_select_lex_unit::check_updateable()
- db - data base name
- table - real table name
-
- RETURN
- 1 - found
- 0 - OK (table did not found)
-*/
-
-bool st_select_lex_unit::check_updateable(char *db, char *table)
-{
- for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
- if (sl->check_updateable(db, table))
- return 1;
- return 0;
-}
-
-
-/*
- Find db.table which will be updated in this select and
- underlying ones (except derived tables)
-
- SYNOPSIS
- st_select_lex::check_updateable()
- db - data base name
- table - real table name
-
- RETURN
- 1 - found
- 0 - OK (table did not found)
-*/
-
-bool st_select_lex::check_updateable(char *db, char *table)
-{
- if (find_real_table_in_list(get_table_list(), db, table))
- return 1;
-
- return check_updateable_in_subqueries(db, table);
-}
-
-/*
- Find db.table which will be updated in underlying subqueries
-
- SYNOPSIS
- st_select_lex::check_updateable_in_subqueries()
- db - data base name
- table - real table name
-
- RETURN
- 1 - found
- 0 - OK (table did not found)
-*/
-
-bool st_select_lex::check_updateable_in_subqueries(char *db, char *table)
-{
- for (SELECT_LEX_UNIT *un= first_inner_unit();
- un;
- un= un->next_unit())
- {
- if (un->first_select()->linkage != DERIVED_TABLE_TYPE &&
- un->check_updateable(db, table))
- return 1;
- }
- return 0;
+ (Item **)arena->alloc(sizeof(Item*) *
+ (item_list.elements +
+ select_n_having_items +
+ order_group_num)* 5)) == 0;
}
@@ -1697,7 +1527,14 @@ void st_select_lex::print_order(String *str, ORDER *order)
{
for (; order; order= order->next)
{
- (*order->item)->print(str);
+ if (order->counter_used)
+ {
+ char buffer[20];
+ my_snprintf(buffer, 20, "%u", order->counter);
+ str->append(buffer);
+ }
+ else
+ (*order->item)->print(str);
if (!order->asc)
str->append(" desc", 5);
if (order->next)
@@ -1708,6 +1545,17 @@ void st_select_lex::print_order(String *str, ORDER *order)
void st_select_lex::print_limit(THD *thd, String *str)
{
+ SELECT_LEX_UNIT *unit= master_unit();
+ Item_subselect *item= unit->item;
+ if (item && unit->global_parameters == this &&
+ (item->substype() == Item_subselect::EXISTS_SUBS ||
+ item->substype() == Item_subselect::IN_SUBS ||
+ item->substype() == Item_subselect::ALL_SUBS))
+ {
+ DBUG_ASSERT(select_limit == 1L && offset_limit == 0L);
+ return;
+ }
+
if (explicit_limit)
{
str->append(" limit ", 7);
@@ -1726,75 +1574,372 @@ void st_select_lex::print_limit(THD *thd, String *str)
}
-st_lex::st_lex()
- :result(0)
-{}
+/*
+ Check whether the merging algorithm can be used on this VIEW
+
+ SYNOPSIS
+ st_lex::can_be_merged()
+
+ DESCRIPTION
+ We can apply merge algorithm if it is single SELECT view with
+ subqueries only in WHERE clause (we do not count SELECTs of underlying
+ views, and second level subqueries) and we have not grpouping, ordering,
+ HAVING clause, aggregate functions, DISTINCT clause, LIMIT clause and
+ several underlying tables.
+
+ RETURN
+ FALSE - only temporary table algorithm can be used
+ TRUE - merge algorithm can be used
+*/
+
+bool st_lex::can_be_merged()
+{
+ // TODO: do not forget implement case when select_lex.table_list.elements==0
+
+ /* find non VIEW subqueries/unions */
+ bool selects_allow_merge= select_lex.next_select() == 0;
+ if (selects_allow_merge)
+ {
+ for (SELECT_LEX_UNIT *unit= select_lex.first_inner_unit();
+ unit;
+ unit= unit->next_unit())
+ {
+ if (unit->first_select()->parent_lex == this &&
+ (unit->item == 0 || unit->item->place() != IN_WHERE))
+ {
+ selects_allow_merge= 0;
+ break;
+ }
+ }
+ }
+
+ return (selects_allow_merge &&
+ select_lex.order_list.elements == 0 &&
+ select_lex.group_list.elements == 0 &&
+ select_lex.having == 0 &&
+ select_lex.with_sum_func == 0 &&
+ select_lex.table_list.elements >= 1 &&
+ !(select_lex.options & SELECT_DISTINCT) &&
+ select_lex.select_limit == HA_POS_ERROR);
+}
/*
- Unlink first table from global table list and first table from outer select
- list (lex->select_lex)
+ check if command can use VIEW with MERGE algorithm (for top VIEWs)
SYNOPSIS
- unlink_first_table()
- tables Global table list
- global_first Save first global table here
- local_first Save first local table here
+ st_lex::can_use_merged()
- NOTES
- This function assumes that outer select list is non-empty.
+ DESCRIPTION
+ Only listed here commands can use merge algorithm in top level
+ SELECT_LEX (for subqueries will be used merge algorithm if
+ st_lex::can_not_use_merged() is not TRUE).
RETURN
- global list without first table
+ FALSE - command can't use merged VIEWs
+ TRUE - VIEWs with MERGE algorithms can be used
+*/
+
+bool st_lex::can_use_merged()
+{
+ switch (sql_command)
+ {
+ case SQLCOM_SELECT:
+ case SQLCOM_CREATE_TABLE:
+ case SQLCOM_UPDATE:
+ case SQLCOM_UPDATE_MULTI:
+ case SQLCOM_DELETE:
+ case SQLCOM_DELETE_MULTI:
+ case SQLCOM_INSERT:
+ case SQLCOM_INSERT_SELECT:
+ case SQLCOM_REPLACE:
+ case SQLCOM_REPLACE_SELECT:
+ case SQLCOM_LOAD:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+/*
+ Check if command can't use merged views in any part of command
+
+ SYNOPSIS
+ st_lex::can_not_use_merged()
+
+ DESCRIPTION
+ Temporary table algorithm will be used on all SELECT levels for queries
+ listed here (see also st_lex::can_use_merged()).
+
+ RETURN
+ FALSE - command can't use merged VIEWs
+ TRUE - VIEWs with MERGE algorithms can be used
*/
-TABLE_LIST *st_lex::unlink_first_table(TABLE_LIST *tables,
- TABLE_LIST **global_first,
- TABLE_LIST **local_first)
+
+bool st_lex::can_not_use_merged()
{
- DBUG_ASSERT(select_lex.table_list.first != 0);
+ switch (sql_command)
+ {
+ case SQLCOM_CREATE_VIEW:
+ case SQLCOM_SHOW_CREATE:
/*
- Save pointers to first elements of global table list and list
- of tables used in outer select. It does not harm if these lists
- are the same.
+ SQLCOM_SHOW_FIELDS is necessary to make
+ information schema tables working correctly with views.
+ see get_schema_tables_result function
*/
- *global_first= tables;
- *local_first= (TABLE_LIST*)select_lex.table_list.first;
-
- /* Exclude first elements from these lists */
- select_lex.table_list.first= (byte*) (*local_first)->next;
- tables= tables->next;
- (*global_first)->next= 0;
- return tables;
+ case SQLCOM_SHOW_FIELDS:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/*
+ Detect that we need only table structure of derived table/view
+
+ SYNOPSIS
+ only_view_structure()
+
+ RETURN
+ TRUE yes, we need only structure
+ FALSE no, we need data
+*/
+
+bool st_lex::only_view_structure()
+{
+ switch(sql_command)
+ {
+ case SQLCOM_SHOW_CREATE:
+ case SQLCOM_SHOW_TABLES:
+ case SQLCOM_SHOW_FIELDS:
+ case SQLCOM_REVOKE_ALL:
+ case SQLCOM_REVOKE:
+ case SQLCOM_GRANT:
+ case SQLCOM_CREATE_VIEW:
+ return TRUE;
+ default:
+ return FALSE;
+ }
}
/*
- Link table which was unlinked with unlink_first_table() back.
+ Should Items_ident be printed correctly
+
+ SYNOPSIS
+ need_correct_ident()
+
+ RETURN
+ TRUE yes, we need only structure
+ FALSE no, we need data
+*/
+
+
+bool st_lex::need_correct_ident()
+{
+ switch(sql_command)
+ {
+ case SQLCOM_SHOW_CREATE:
+ case SQLCOM_SHOW_TABLES:
+ case SQLCOM_CREATE_VIEW:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+
+/*
+ initialize limit counters
+
+ SYNOPSIS
+ st_select_lex_unit::set_limit()
+ values - SELECT_LEX with initial values for counters
+ sl - SELECT_LEX for options set
+*/
+
+void st_select_lex_unit::set_limit(SELECT_LEX *values,
+ SELECT_LEX *sl)
+{
+ offset_limit_cnt= values->offset_limit;
+ select_limit_cnt= values->select_limit+values->offset_limit;
+ if (select_limit_cnt < values->select_limit)
+ select_limit_cnt= HA_POS_ERROR; // no limit
+}
+
+
+/*
+ Unlink the first table from the global table list and the first table from
+ outer select (lex->select_lex) local list
+
+ SYNOPSIS
+ unlink_first_table()
+ link_to_local Set to 1 if caller should link this table to local list
+
+ NOTES
+ We assume that first tables in both lists is the same table or the local
+ list is empty.
+
+ RETURN
+ 0 If 'query_tables' == 0
+ unlinked table
+ In this case link_to_local is set.
+
+*/
+TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
+{
+ TABLE_LIST *first;
+ if ((first= query_tables))
+ {
+ /*
+ Exclude from global table list
+ */
+ if ((query_tables= query_tables->next_global))
+ query_tables->prev_global= &query_tables;
+ else
+ query_tables_last= &query_tables;
+ first->next_global= 0;
+
+ /*
+ and from local list if it is not empty
+ */
+ if ((*link_to_local= test(select_lex.table_list.first)))
+ {
+ select_lex.table_list.first= (byte*) first->next_local;
+ select_lex.table_list.elements--; //safety
+ first->next_local= 0;
+ /*
+ Ensure that the global list has the same first table as the local
+ list.
+ */
+ first_lists_tables_same();
+ }
+ }
+ return first;
+}
+
+
+/*
+ Bring first local table of first most outer select to first place in global
+ table list
+
+ SYNOPSYS
+ st_lex::first_lists_tables_same()
+
+ NOTES
+ In many cases (for example, usual INSERT/DELETE/...) the first table of
+ main SELECT_LEX have special meaning => check that it is the first table
+ in global list and re-link to be first in the global list if it is
+ necessary. We need such re-linking only for queries with sub-queries in
+ the select list, as only in this case tables of sub-queries will go to
+ the global list first.
+*/
+
+void st_lex::first_lists_tables_same()
+{
+ TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first;
+ if (query_tables != first_table && first_table != 0)
+ {
+ TABLE_LIST *next;
+ if (query_tables_last == &first_table->next_global)
+ query_tables_last= first_table->prev_global;
+
+ if ((next= *first_table->prev_global= first_table->next_global))
+ next->prev_global= first_table->prev_global;
+ /* include in new place */
+ first_table->next_global= query_tables;
+ /*
+ We are sure that query_tables is not 0, because first_table was not
+ first table in the global list => we can use
+ query_tables->prev_global without check of query_tables
+ */
+ query_tables->prev_global= &first_table->next_global;
+ first_table->prev_global= &query_tables;
+ query_tables= first_table;
+ }
+}
+
+
+/*
+ Add implicitly used time zone description tables to global table list
+ (if needed).
+
+ SYNOPSYS
+ st_lex::add_time_zone_tables_to_query_tables()
+ thd - pointer to current thread context
+
+ RETURN VALUE
+ TRUE - error
+ FALSE - success
+*/
+
+bool st_lex::add_time_zone_tables_to_query_tables(THD *thd)
+{
+ /* We should not add these tables twice */
+ if (!time_zone_tables_used)
+ {
+ time_zone_tables_used= my_tz_get_table_list(thd, &query_tables_last);
+ if (time_zone_tables_used == &fake_time_zone_tables_list)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ Link table back that was unlinked with unlink_first_table()
SYNOPSIS
link_first_table_back()
- tables Global table list
- global_first Saved first global table
- local_first Saved first local table
+ link_to_local do we need link this table to local
RETURN
global list
*/
-TABLE_LIST *st_lex::link_first_table_back(TABLE_LIST *tables,
- TABLE_LIST *global_first,
- TABLE_LIST *local_first)
+
+void st_lex::link_first_table_back(TABLE_LIST *first,
+ bool link_to_local)
+{
+ if (first)
+ {
+ if ((first->next_global= query_tables))
+ query_tables->prev_global= &first->next_global;
+ else
+ query_tables_last= &first->next_global;
+ query_tables= 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.elements++; //safety
+ }
+ }
+}
+
+
+/*
+ fix some structures at the end of preparation
+
+ SYNOPSIS
+ st_select_lex::fix_prepare_information
+ thd thread handler
+ conds pointer on conditions which will be used for execution statement
+*/
+
+void st_select_lex::fix_prepare_information(THD *thd, Item **conds)
{
- global_first->next= tables;
- select_lex.table_list.first= (byte*) local_first;
- return global_first;
+ if (!thd->current_arena->is_conventional() && first_execution)
+ {
+ first_execution= 0;
+ prep_where= where;
+ }
}
/*
- There are st_select_lex::add_table_to_list &
+ There are st_select_lex::add_table_to_list &
st_select_lex::set_lock_for_tables are in sql_parse.cc
- st_select_lex::print is in sql_select.h
+ st_select_lex::print is in sql_select.cc
st_select_lex_unit::prepare, st_select_lex_unit::exec,
st_select_lex_unit::cleanup, st_select_lex_unit::reinit_exec_mechanism,
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 927982e444f..94f1a8e0df4 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -21,6 +21,10 @@
class Table_ident;
class sql_exchange;
class LEX_COLUMN;
+class sp_head;
+class sp_name;
+class sp_instr;
+class sp_pcontext;
/*
The following hack is needed because mysql_yacc.cc does not define
@@ -49,21 +53,21 @@ enum enum_sql_command {
SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS,
SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS,
- SQLCOM_SHOW_INNODB_STATUS,
+ SQLCOM_SHOW_INNODB_STATUS, SQLCOM_SHOW_MUTEX_STATUS,
SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
- SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB,
+ SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS,
SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES,
SQLCOM_GRANT,
SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB,
SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT,
SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION,
- SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK,
+ SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK,
SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS,
SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE,
SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT,
- SQLCOM_COMMIT, SQLCOM_SAVEPOINT,
+ SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT,
SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER,
SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE,
@@ -74,10 +78,19 @@ enum enum_sql_command {
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES,
- SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM,
-
+ SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER,
+ SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM,
+ SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL,
+ SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION,
+ SQLCOM_SHOW_CREATE_PROC, SQLCOM_SHOW_CREATE_FUNC,
+ SQLCOM_SHOW_STATUS_PROC, SQLCOM_SHOW_STATUS_FUNC,
SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE,
+ SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW,
+ SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
+ SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE,
+ SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER,
/* This should be the last !!! */
+
SQLCOM_END
};
@@ -85,6 +98,39 @@ enum enum_sql_command {
#define DESCRIBE_NORMAL 1
#define DESCRIBE_EXTENDED 2
+enum enum_sp_suid_behaviour
+{
+ SP_IS_DEFAULT_SUID= 0,
+ SP_IS_NOT_SUID,
+ SP_IS_SUID
+};
+
+enum enum_sp_data_access
+{
+ SP_DEFAULT_ACCESS= 0,
+ SP_CONTAINS_SQL,
+ SP_NO_SQL,
+ SP_READS_SQL_DATA,
+ SP_MODIFIES_SQL_DATA
+};
+
+
+#define DERIVED_SUBQUERY 1
+#define DERIVED_VIEW 2
+
+enum enum_view_create_mode
+{
+ VIEW_CREATE_NEW, // check that there are not such VIEW/table
+ VIEW_ALTER, // check that VIEW .frm with such name exists
+ VIEW_CREATE_OR_REPLACE // check only that there are not such table
+};
+
+enum enum_drop_mode
+{
+ DROP_DEFAULT, // mode is not specified
+ DROP_CASCADE, // CASCADE option
+ DROP_RESTRICT // RESTRICT option
+};
typedef List<Item> List_item;
@@ -269,7 +315,7 @@ public:
}
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
- static void operator delete(void *ptr,size_t size) {}
+ static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
st_select_lex_node(): linkage(UNSPECIFIED_TYPE) {}
virtual ~st_select_lex_node() {}
@@ -305,6 +351,8 @@ public:
friend class st_select_lex_unit;
friend bool mysql_new_select(struct st_lex *lex, bool move_down);
+ friend my_bool mysql_make_view (File_parser *parser,
+ TABLE_LIST *table);
private:
void fast_exclude();
};
@@ -327,8 +375,8 @@ protected:
TABLE *table; /* temporary table using for appending UNION results */
select_result *result;
- int res;
ulong found_rows_for_union;
+ bool res;
bool prepared, // prepare phase already performed for UNION (unit)
optimized, // optimize phase already performed for UNION (unit)
executed, // already executed
@@ -369,7 +417,6 @@ public:
Procedure *last_procedure; /* Pointer to procedure, if such exists */
void init_query();
- bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result);
st_select_lex_unit* master_unit();
st_select_lex* outer_select();
st_select_lex* first_select()
@@ -389,25 +436,22 @@ public:
void exclude_tree();
/* UNION methods */
- int prepare(THD *thd, select_result *result, ulong additional_options,
- const char *tmp_table_alias);
- int exec();
- int cleanup();
+ bool prepare(THD *thd, select_result *result, ulong additional_options,
+ const char *tmp_table_alias);
+ bool exec();
+ bool cleanup();
inline void unclean() { cleaned= 0; }
void reinit_exec_mechanism();
- bool check_updateable(char *db, char *table);
void print(String *str);
ulong init_prepare_fake_select_lex(THD *thd);
- int change_result(select_subselect *result, select_subselect *old_result);
inline bool is_prepared() { return prepared; }
+ bool change_result(select_subselect *result, select_subselect *old_result);
+ void set_limit(st_select_lex *values, st_select_lex *sl);
friend void lex_start(THD *thd, uchar *buf, uint length);
friend int subselect_union_engine::exec();
-private:
- bool create_total_list_n_last_return(THD *thd, st_lex *lex,
- TABLE_LIST ***result);
};
typedef class st_select_lex_unit SELECT_LEX_UNIT;
@@ -420,6 +464,8 @@ public:
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 */
+ /* point on lex in which it was created, used in view subquery detection */
+ st_lex *parent_lex;
enum olap_type olap;
SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */
List<Item> item_list; /* list of fields & expressions */
@@ -432,7 +478,11 @@ public:
List<Item_func_match> *ftfunc_list;
List<Item_func_match> ftfunc_list_alloc;
JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */
- const char *type; /* type of select for EXPLAIN */
+ List<TABLE_LIST> top_join_list; /* join list of the top level */
+ List<TABLE_LIST> *join_list; /* list for the currently parsed join */
+ TABLE_LIST *embedding; /* table embedding to the above list */
+ TABLE_LIST *leaf_tables; /* list of leaves in join table tree */
+ const char *type; /* type of select for EXPLAIN */
SQL_LIST order_list; /* ORDER clause */
List<List_item> expr_list;
@@ -451,6 +501,11 @@ public:
uint cond_count; /* number of arguments of and/or/xor in where/having */
enum_parsing_place parsing_place; /* where we are parsing expression */
bool with_sum_func; /* sum function indicator */
+ /*
+ PS or SP cond natural joins was alredy processed with permanent
+ arena and all additional items which we need alredy stored in it
+ */
+ bool conds_processed_with_permanent_arena;
ulong table_join_options;
uint in_sum_expr;
@@ -466,6 +521,12 @@ public:
query processing end even if we use temporary table
*/
bool subquery_in_having;
+ bool first_execution; /* first execution in SP or PS */
+ 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
@@ -528,6 +589,12 @@ public:
List<String> *ignore_index= 0,
LEX_STRING *option= 0);
TABLE_LIST* get_table_list();
+ bool init_nested_join(THD *thd);
+ TABLE_LIST *end_nested_join(THD *thd);
+ TABLE_LIST *nest_last_join(THD *thd);
+ void save_names_for_using_list(TABLE_LIST *tab1, TABLE_LIST *tab2);
+ void add_joined_table(TABLE_LIST *table);
+ TABLE_LIST *convert_right_join();
List<Item>* get_item_list();
List<String>* get_use_index();
List<String>* get_ignore_index();
@@ -550,11 +617,10 @@ public:
init_select();
}
bool setup_ref_array(THD *thd, uint order_group_num);
- bool check_updateable(char *db, char *table);
- bool check_updateable_in_subqueries(char *db, char *table);
void print(THD *thd, String *str);
static void print_order(String *str, ORDER *order);
void print_limit(THD *thd, String *str);
+ void fix_prepare_information(THD *thd, Item **conds);
};
typedef class st_select_lex SELECT_LEX;
@@ -566,6 +632,9 @@ typedef class st_select_lex SELECT_LEX;
#define ALTER_RENAME 32
#define ALTER_ORDER 64
#define ALTER_OPTIONS 128
+#define ALTER_CHANGE_COLUMN_DEFAULT 256
+#define ALTER_KEYS_ONOFF 512
+#define ALTER_CONVERT 1024
typedef struct st_alter_info
{
@@ -574,13 +643,32 @@ typedef struct st_alter_info
uint flags;
enum enum_enable_or_disable keys_onoff;
enum tablespace_op_type tablespace_op;
- bool is_simple;
st_alter_info(){clear();}
void clear(){keys_onoff= LEAVE_AS_IS;tablespace_op= NO_TABLESPACE_OP;}
void reset(){drop_list.empty();alter_list.empty();clear();}
} ALTER_INFO;
+struct st_sp_chistics
+{
+ LEX_STRING comment;
+ enum enum_sp_suid_behaviour suid;
+ bool detistic;
+ enum enum_sp_data_access daccess;
+};
+
+
+struct st_trg_chistics
+{
+ enum trg_action_time_type action_time;
+ enum trg_event_type event;
+};
+
+extern sys_var_long_ptr trg_new_row_fake_var;
+
+enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE,
+ XA_SUSPEND, XA_FOR_MIGRATE};
+
/* The state of the lex parsing. This is saved in the THD struct */
typedef struct st_lex
@@ -593,23 +681,35 @@ typedef struct st_lex
SELECT_LEX *current_select;
/* list of all SELECT_LEX */
SELECT_LEX *all_selects_list;
+ uchar *buf; /* The beginning of string, used by SPs */
uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name;
char *help_arg;
char *backup_dir; /* For RESTORE/BACKUP */
char* to_log; /* For PURGE MASTER LOGS TO */
- time_t purge_time; /* For PURGE MASTER LOGS BEFORE */
char* x509_subject,*x509_issuer,*ssl_cipher;
- char* found_colon; /* For multi queries - next query */
+ char* found_semicolon; /* For multi queries - next query */
String *wild;
sql_exchange *exchange;
select_result *result;
Item *default_value, *on_update_value;
- LEX_STRING *comment, name_and_length;
+ LEX_STRING comment, ident;
LEX_USER *grant_user;
+ XID *xid;
gptr yacc_yyss,yacc_yyvs;
THD *thd;
CHARSET_INFO *charset;
+ TABLE_LIST *query_tables; /* global list of all tables in this query */
+ /*
+ last element next_global of previous list (used only for list building
+ during parsing and VIEW processing. This pointer could be invalid during
+ processing of information schema tables(see get_schema_tables_result
+ function)
+ */
+ TABLE_LIST **query_tables_last;
+ 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;
List<key_part_spec> col_list;
List<key_part_spec> ref_list;
@@ -622,53 +722,115 @@ typedef struct st_lex
List<List_item> many_values;
List<set_var_base> var_list;
List<Item_param> param_list;
+ List<LEX_STRING> view_list; // view list (list of field names in view)
SQL_LIST proc_list, auxilliary_table_list, save_list;
create_field *last_field;
- char *savepoint_name; // Transaction savepoint id
udf_func udf;
HA_CHECK_OPT check_opt; // check/repair options
HA_CREATE_INFO create_info;
LEX_MASTER_INFO mi; // used by CHANGE MASTER
USER_RESOURCES mqh;
- ulong thread_id,type;
- enum_sql_command sql_command;
- thr_lock_type lock_option, multi_lock_option;
+ ulong type;
+ enum_sql_command sql_command, orig_sql_command;
+ thr_lock_type lock_option;
enum SSL_type ssl_type; /* defined in violite.h */
enum my_lex_states next_state;
enum enum_duplicates duplicates;
enum enum_tx_isolation tx_isolation;
enum enum_ha_read_modes ha_read_mode;
- enum ha_rkey_function ha_rkey_mode;
+ union {
+ enum ha_rkey_function ha_rkey_mode;
+ enum xa_option_words xa_opt;
+ };
enum enum_var_type option_type;
+ enum enum_view_create_mode create_view_mode;
+ enum enum_drop_mode drop_mode;
uint uint_geom_type;
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
uint slave_thd_opt, start_transaction_opt;
+ uint table_count; /* used when usual update transformed in multiupdate */
uint8 describe;
+ uint8 derived_tables;
+ uint8 create_view_algorithm;
+ uint8 create_view_check;
bool drop_if_exists, drop_temporary, local_file, one_shot_set;
bool in_comment, ignore_space, verbose, no_write_to_binlog;
- bool derived_tables;
+ bool tx_chain, tx_release;
+ /* special JOIN::prepare mode: changing of query is prohibited */
+ bool view_prepare_mode;
bool safe_to_cache_query;
bool subqueries, ignore;
+ bool variables_used;
ALTER_INFO alter_info;
/* Prepared statements SQL syntax:*/
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
- /*
+ /*
Prepared statement query text or name of variable that holds the
prepared statement (in PREPARE ... queries)
*/
- LEX_STRING prepared_stmt_code;
+ LEX_STRING prepared_stmt_code;
/* If true, prepared_stmt_code is a name of variable that holds the query */
bool prepared_stmt_code_is_varref;
/* Names of user variables holding parameters (in EXECUTE) */
- List<LEX_STRING> prepared_stmt_params;
+ List<LEX_STRING> prepared_stmt_params;
/*
- If points to fake_time_zone_tables_list indicates that time zone
- tables are implicitly used by statement, also is used for holding
- list of those tables after they are opened.
+ Points to part of global table list which contains time zone tables
+ implicitly used by the statement.
*/
TABLE_LIST *time_zone_tables_used;
- st_lex();
+ sp_head *sphead;
+ sp_name *spname;
+ 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 */
+ st_sp_chistics sp_chistics;
+ bool only_view; /* used for SHOW CREATE TABLE/VIEW */
+ /*
+ field_list was created for view and should be removed before PS/SP
+ rexecuton
+ */
+ bool empty_field_list_on_rset;
+ /* Characterstics of trigger being created */
+ st_trg_chistics trg_chistics;
+ /*
+ List of all items (Item_trigger_field objects) representing fields in
+ old/new version of row in trigger. We use this list for checking whenever
+ all such fields are valid at trigger creation time and for binding these
+ fields to TABLE object at table open (altough for latter pointer to table
+ being opened is probably enough).
+ */
+ SQL_LIST trg_table_fields;
+
+ /*
+ If non-0 then indicates that query requires prelocking and points to
+ next_global member of last own element in query table list (i.e. last
+ table which was not added to it as part of preparation to prelocking).
+ 0 - indicates that this query does not need prelocking.
+ */
+ TABLE_LIST **query_tables_own_last;
+
+ /*
+ Pointers to part of LOAD DATA statement that should be rewritten
+ during replication ("LOCAL 'filename' REPLACE INTO" part).
+ */
+ 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);
+ }
+
+ virtual ~st_lex()
+ {
+ hash_free(&spfuns);
+ hash_free(&spprocs);
+ }
+
inline void uncacheable(uint8 cause)
{
safe_to_cache_query= 0;
@@ -688,15 +850,53 @@ typedef struct st_lex
un->uncacheable|= cause;
}
}
- TABLE_LIST *unlink_first_table(TABLE_LIST *tables,
- TABLE_LIST **global_first,
- TABLE_LIST **local_first);
- TABLE_LIST *link_first_table_back(TABLE_LIST *tables,
- TABLE_LIST *global_first,
- TABLE_LIST *local_first);
+ TABLE_LIST *unlink_first_table(bool *link_to_local);
+ void link_first_table_back(TABLE_LIST *first, bool link_to_local);
+ void first_lists_tables_same();
+ inline void add_to_query_tables(TABLE_LIST *table)
+ {
+ *(table->prev_global= query_tables_last)= table;
+ query_tables_last= &table->next_global;
+ }
+ bool add_time_zone_tables_to_query_tables(THD *thd);
+
+ bool can_be_merged();
+ bool can_use_merged();
+ bool can_not_use_merged();
+ bool only_view_structure();
+ bool need_correct_ident();
+
+ inline bool requires_prelocking()
+ {
+ return test(query_tables_own_last);
+ }
+ inline void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last)
+ {
+ query_tables_own_last= tables_own_last;
+ }
+ /* Return pointer to first not-own table in query-tables or 0 */
+ TABLE_LIST* first_not_own_table()
+ {
+ return ( query_tables_own_last ? *query_tables_own_last : 0);
+ }
+
} LEX;
-extern TABLE_LIST fake_time_zone_tables_list;
+struct st_lex_local: public st_lex
+{
+ 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);
+ }
+ static void operator delete(void *ptr,size_t size)
+ { TRASH(ptr, size); }
+ static void operator delete(void *ptr, MEM_ROOT *mem_root)
+ { /* Never called */ }
+};
void lex_init(void);
void lex_free(void);
diff --git a/sql/sql_list.h b/sql/sql_list.h
index be3e29b0c62..55d9d668bdd 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -21,12 +21,6 @@
/* mysql standard class memory allocator */
-#ifdef SAFEMALLOC
-#define TRASH(XX,YY) bfill((XX), (YY), 0x8F)
-#else
-#define TRASH(XX,YY) /* no-op */
-#endif
-
class Sql_alloc
{
public:
@@ -113,6 +107,16 @@ public:
}
return 1;
}
+ inline bool push_back(void *info, MEM_ROOT *mem_root)
+ {
+ if (((*last)=new (mem_root) list_node(info, &end_of_list)))
+ {
+ last= &(*last)->next;
+ elements++;
+ return 0;
+ }
+ return 1;
+ }
inline bool push_front(void *info)
{
list_node *node=new list_node(info,first);
@@ -129,10 +133,12 @@ public:
void remove(list_node **prev)
{
list_node *node=(*prev)->next;
- delete *prev;
- *prev=node;
if (!--elements)
last= &first;
+ else if (last == &(*prev)->next)
+ last= prev;
+ delete *prev;
+ *prev=node;
}
inline void concat(base_list *list)
{
@@ -152,6 +158,30 @@ public:
last= &first;
return tmp->info;
}
+ inline void disjoin(base_list *list)
+ {
+ list_node **prev= &first;
+ list_node *node= first;
+ list_node *list_first= list->first;
+ elements=0;
+ while (node && node != list_first)
+ {
+ prev= &node->next;
+ node= node->next;
+ elements++;
+ }
+ *prev= *last;
+ last= prev;
+ }
+ inline void prepand(base_list *list)
+ {
+ if (!list->is_empty())
+ {
+ *list->last= first;
+ first= list->first;
+ elements+= list->elements;
+ }
+ }
inline list_node* last_node() { return *last; }
inline list_node* first_node() { return first;}
inline void *head() { return first->info; }
@@ -258,10 +288,15 @@ public:
inline List() :base_list() {}
inline List(const List<T> &tmp) :base_list(tmp) {}
inline bool push_back(T *a) { return base_list::push_back(a); }
+ inline bool push_back(T *a, MEM_ROOT *mem_root)
+ { return base_list::push_back(a, mem_root); }
inline bool push_front(T *a) { return base_list::push_front(a); }
inline T* head() {return (T*) base_list::head(); }
inline T** head_ref() {return (T**) base_list::head_ref(); }
inline T* pop() {return (T*) base_list::pop(); }
+ inline void concat(List<T> *list) { base_list::concat(list); }
+ inline void disjoin(List<T> *list) { base_list::disjoin(list); }
+ inline void prepand(List<T> *list) { base_list::prepand(list); }
void delete_elements(void)
{
list_node *element,*next;
@@ -282,6 +317,8 @@ public:
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
+ inline void rewind(void) { base_list_iterator::rewind(); }
+ inline void remove() { base_list_iterator::remove(); }
inline void after(T *a) { base_list_iterator::after(a); }
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
};
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index c4f5b1427af..c827bbace3e 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -71,17 +71,47 @@ public:
void set_io_cache_arg(void* arg) { cache.arg = arg; }
};
-static int read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,
- List<Item> &fields, READ_INFO &read_info,
- ulong skip_lines);
-static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
- List<Item> &fields, READ_INFO &read_info,
- String &enclosed, ulong skip_lines);
-
-int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
- List<Item> &fields, enum enum_duplicates handle_duplicates,
- bool ignore,
- bool read_file_from_client,thr_lock_type lock_type)
+static int read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
+ List<Item> &fields_vars, List<Item> &set_fields,
+ List<Item> &set_values, READ_INFO &read_info,
+ ulong skip_lines,
+ bool ignore_check_option_errors);
+static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
+ List<Item> &fields_vars, List<Item> &set_fields,
+ List<Item> &set_values, READ_INFO &read_info,
+ String &enclosed, ulong skip_lines,
+ bool ignore_check_option_errors);
+static bool write_execute_load_query_log_event(THD *thd,
+ bool duplicates, bool ignore,
+ bool transactional_table);
+
+
+/*
+ Execute LOAD DATA query
+
+ SYNOPSYS
+ mysql_load()
+ thd - current thread
+ ex - sql_exchange object representing source file and its parsing rules
+ table_list - list of tables to which we are loading data
+ fields_vars - list of fields and variables to which we read
+ data from file
+ set_fields - list of fields mentioned in set clause
+ set_values - expressions to assign to fields in previous list
+ handle_duplicates - indicates whenever we should emit error or
+ replace row if we will meet duplicates.
+ ignore - - indicates whenever we should ignore duplicates
+ read_file_from_client - is this LOAD DATA LOCAL ?
+
+ RETURN VALUES
+ TRUE - error / FALSE - success
+*/
+
+bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
+ List<Item> &fields_vars, List<Item> &set_fields,
+ List<Item> &set_values,
+ enum enum_duplicates handle_duplicates, bool ignore,
+ bool read_file_from_client)
{
char name[FN_REFLEN];
File file;
@@ -89,6 +119,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
int error;
String *field_term=ex->field_term,*escaped=ex->escaped;
String *enclosed=ex->enclosed;
+ Item *unused_conds= 0;
bool is_fifo=0;
#ifndef EMBEDDED_LIBRARY
LOAD_FILE_INFO lf_info;
@@ -100,8 +131,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
loaded is located
*/
char *tdb= thd->db ? thd->db : db; // Result is never null
- bool transactional_table, log_delayed;
ulong skip_lines= ex->skip_lines;
+ bool transactional_table;
DBUG_ENTER("mysql_load");
#ifdef EMBEDDED_LIBRARY
@@ -112,56 +143,105 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
{
my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
+ }
+ if (open_and_lock_tables(thd, table_list))
+ DBUG_RETURN(TRUE);
+ if (setup_tables(thd, table_list, &unused_conds,
+ &thd->lex->select_lex.leaf_tables, FALSE, FALSE))
+ DBUG_RETURN(-1);
+ if (!table_list->table || // do not suport join view
+ !table_list->updatable || // and derived tables
+ check_key_in_view(thd, table_list))
+ {
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD");
+ 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.
+
+ The main thing to fix to remove this restriction is to ensure that the
+ table is marked to be 'used for insert' in which case we should never
+ mark this table as as 'const table' (ie, one that has only one row).
+ */
+ if (unique_table(table_list, table_list->next_global))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
+ DBUG_RETURN(TRUE);
}
- if (!(table = open_ltable(thd,table_list,lock_type)))
- DBUG_RETURN(-1);
+
+ table= table_list->table;
transactional_table= table->file->has_transactions();
- log_delayed= (transactional_table || table->tmp_table);
- if (!fields.elements)
+ if (!fields_vars.elements)
{
Field **field;
for (field=table->field; *field ; field++)
- fields.push_back(new Item_field(*field));
+ fields_vars.push_back(new Item_field(*field));
+ table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+ /*
+ Let us also prepare SET clause, altough it is probably empty
+ in this case.
+ */
+ if (setup_fields(thd, 0, table_list, set_fields, 1, 0, 0) ||
+ setup_fields(thd, 0, table_list, set_values, 1, 0, 0))
+ DBUG_RETURN(TRUE);
}
else
{ // Part field list
- thd->dupp_field=0;
- if (setup_tables(table_list) ||
- setup_fields(thd, 0, table_list, fields, 1, 0, 0))
- DBUG_RETURN(-1);
- if (thd->dupp_field)
- {
- my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), thd->dupp_field->field_name);
- DBUG_RETURN(-1);
- }
+ /* 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))
+ DBUG_RETURN(TRUE);
+ /*
+ Check whenever TIMESTAMP field with auto-set feature specified
+ explicitly.
+ */
+ if (table->timestamp_field &&
+ table->timestamp_field->query_id == thd->query_id)
+ table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+ /*
+ Fix the expressions in SET clause. This should be done after
+ check_that_all_fields_are_given_values() and setting use_timestamp
+ since it may update query_id for some fields.
+ */
+ if (setup_fields(thd, 0, table_list, set_values, 1, 0, 0))
+ DBUG_RETURN(TRUE);
}
uint tot_length=0;
- bool use_blobs=0,use_timestamp=0;
- List_iterator_fast<Item> it(fields);
+ bool use_blobs= 0, use_vars= 0;
+ List_iterator_fast<Item> it(fields_vars);
+ Item *item;
- Item_field *field;
- while ((field=(Item_field*) it++))
+ while ((item= it++))
{
- if (field->field->flags & BLOB_FLAG)
+ if (item->type() == Item::FIELD_ITEM)
{
- use_blobs=1;
- tot_length+=256; // Will be extended if needed
+ Field *field= ((Item_field*)item)->field;
+ if (field->flags & BLOB_FLAG)
+ {
+ use_blobs= 1;
+ tot_length+= 256; // Will be extended if needed
+ }
+ else
+ tot_length+= field->field_length;
}
else
- tot_length+=field->field->field_length;
- if (!field_term->length() && !(field->field->flags & NOT_NULL_FLAG))
- field->field->set_notnull();
- if (field->field == table->timestamp_field)
- use_timestamp=1;
+ use_vars= 1;
}
if (use_blobs && !ex->line_term->length() && !field_term->length())
{
my_message(ER_BLOBS_AND_NO_TERMINATED,ER(ER_BLOBS_AND_NO_TERMINATED),
MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
+ }
+ if (use_vars && !field_term->length() && !enclosed->length())
+ {
+ my_error(ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR, MYF(0));
+ DBUG_RETURN(TRUE);
}
/* We can't give an error in the middle when using LOCAL files */
@@ -193,7 +273,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
#if !defined(__WIN__) && !defined(OS2) && ! defined(__NETWARE__)
MY_STAT stat_info;
if (!my_stat(name,&stat_info,MYF(MY_WME)))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
// if we are not in slave thread, the file must be:
if (!thd->slave_thread &&
@@ -204,15 +284,15 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
((stat_info.st_mode & S_IFREG) == S_IFREG ||
(stat_info.st_mode & S_IFIFO) == S_IFIFO)))
{
- my_error(ER_TEXTFILE_NOT_READABLE,MYF(0),name);
- DBUG_RETURN(-1);
+ my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name);
+ DBUG_RETURN(TRUE);
}
if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
is_fifo = 1;
#endif
}
if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
COPY_INFO info;
@@ -228,28 +308,20 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
{
if (file >= 0)
my_close(file,MYF(0)); // no files in net reading
- DBUG_RETURN(-1); // Can't allocate buffers
+ DBUG_RETURN(TRUE); // Can't allocate buffers
}
#ifndef EMBEDDED_LIBRARY
if (mysql_bin_log.is_open())
{
lf_info.thd = thd;
- lf_info.ex = ex;
- lf_info.db = db;
- lf_info.table_name = table_list->real_name;
- lf_info.fields = &fields;
- lf_info.ignore= ignore;
- lf_info.handle_dup = handle_duplicates;
lf_info.wrote_create_file = 0;
lf_info.last_pos_in_file = HA_POS_ERROR;
- lf_info.log_delayed= log_delayed;
+ lf_info.log_delayed= transactional_table;
read_info.set_io_cache_arg((void*) &lf_info);
}
#endif /*!EMBEDDED_LIBRARY*/
- restore_record(table,default_values);
-
thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */
thd->cuted_fields=0L;
/* Skip lines if there is a line terminator */
@@ -266,8 +338,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (!(error=test(read_info.error)))
{
- if (use_timestamp)
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
table->next_number_field=table->found_next_number_field;
if (ignore ||
@@ -276,12 +346,21 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
ha_enable_transaction(thd, FALSE);
table->file->start_bulk_insert((ha_rows) 0);
table->copy_blobs=1;
+
+ thd->no_trans_update= 0;
+ thd->abort_on_warning= (!ignore &&
+ (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES)));
+
if (!field_term->length() && !enclosed->length())
- error=read_fixed_length(thd,info,table,fields,read_info,
- skip_lines);
+ error= read_fixed_length(thd, info, table_list, fields_vars,
+ set_fields, set_values, read_info,
+ skip_lines, ignore);
else
- error=read_sep_field(thd,info,table,fields,read_info,*enclosed,
- skip_lines);
+ error= read_sep_field(thd, info, table_list, fields_vars,
+ set_fields, set_values, read_info,
+ *enclosed, skip_lines, ignore);
if (table->file->end_bulk_insert())
error=1; /* purecov: inspected */
ha_enable_transaction(thd, TRUE);
@@ -337,8 +416,14 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
/* If the file was not empty, wrote_create_file is true */
if (lf_info.wrote_create_file)
{
- Delete_file_log_event d(thd, db, log_delayed);
- mysql_bin_log.write(&d);
+ if ((info.copied || info.deleted) && !transactional_table)
+ write_execute_load_query_log_event(thd, handle_duplicates,
+ ignore, transactional_table);
+ else
+ {
+ Delete_file_log_event d(thd, db, transactional_table);
+ mysql_bin_log.write(&d);
+ }
}
}
#endif /*!EMBEDDED_LIBRARY*/
@@ -348,63 +433,77 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
(ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
send_ok(thd,info.copied+info.deleted,0L,name);
- // on the slave thd->query is never initialized
- if (!thd->slave_thread)
- mysql_update_log.write(thd,thd->query,thd->query_length);
- if (!log_delayed)
+ if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
#ifndef EMBEDDED_LIBRARY
if (mysql_bin_log.is_open())
{
/*
As already explained above, we need to call end_io_cache() or the last
- block will be logged only after Execute_load_log_event (which is wrong),
- when read_info is destroyed.
+ block will be logged only after Execute_load_query_log_event (which is
+ wrong), when read_info is destroyed.
*/
- read_info.end_io_cache();
+ read_info.end_io_cache();
if (lf_info.wrote_create_file)
- {
- Execute_load_log_event e(thd, db, log_delayed);
- mysql_bin_log.write(&e);
- }
+ write_execute_load_query_log_event(thd, handle_duplicates,
+ ignore, transactional_table);
}
#endif /*!EMBEDDED_LIBRARY*/
if (transactional_table)
- error=ha_autocommit_or_rollback(thd,error);
+ error=ha_autocommit_or_rollback(thd,error);
+
err:
if (thd->lock)
{
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ thd->abort_on_warning= 0;
DBUG_RETURN(error);
}
+
+/* Not a very useful function; just to avoid duplication of code */
+static bool write_execute_load_query_log_event(THD *thd,
+ bool duplicates, bool ignore,
+ bool transactional_table)
+{
+ Execute_load_query_log_event
+ e(thd, thd->query, thd->query_length,
+ (char*)thd->lex->fname_start - (char*)thd->query,
+ (char*)thd->lex->fname_end - (char*)thd->query,
+ (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
+ (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
+ transactional_table, FALSE);
+ return mysql_bin_log.write(&e);
+}
+
+
/****************************************************************************
** Read of rows of fixed size + optional garage + optonal newline
****************************************************************************/
static int
-read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
- READ_INFO &read_info, ulong skip_lines)
+read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
+ List<Item> &fields_vars, List<Item> &set_fields,
+ List<Item> &set_values, READ_INFO &read_info,
+ ulong skip_lines, bool ignore_check_option_errors)
{
- List_iterator_fast<Item> it(fields);
+ List_iterator_fast<Item> it(fields_vars);
Item_field *sql_field;
+ TABLE *table= table_list->table;
ulonglong id;
+ bool no_trans_update;
DBUG_ENTER("read_fixed_length");
id= 0;
-
- /* No fields can be null in this format. mark all fields as not null */
- while ((sql_field= (Item_field*) it++))
- sql_field->field->set_notnull();
-
+
while (!read_info.read_fixed_length())
{
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
DBUG_RETURN(1);
}
if (skip_lines)
@@ -423,16 +522,29 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
#ifdef HAVE_purify
read_info.row_end[0]=0;
#endif
+ no_trans_update= !table->file->has_transactions();
+
+ restore_record(table, s->default_values);
+ /*
+ There is no variables in fields_vars list in this format so
+ this conversion is safe.
+ */
while ((sql_field= (Item_field*) it++))
{
Field *field= sql_field->field;
+ /*
+ No fields specified in fields_vars list can be null in this format.
+ Mark field as not null, we should do this for each row because of
+ restore_record...
+ */
+ field->set_notnull();
+
if (pos == read_info.row_end)
{
thd->cuted_fields++; /* Not enough fields */
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_TOO_FEW_RECORDS,
ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
- field->reset();
}
else
{
@@ -442,7 +554,7 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
field->field_length)
length=field->field_length;
save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
- field->store((char*) pos,length,read_info.read_charset);
+ field->store((char*) pos,length,read_info.read_charset);
pos[length]=save_chr;
if ((pos+=length) > read_info.row_end)
pos= read_info.row_end; /* Fills rest with space */
@@ -455,8 +567,23 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
ER_WARN_TOO_MANY_RECORDS,
ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count);
}
- if (write_record(table,&info))
+
+ if (fill_record(thd, set_fields, set_values, ignore_check_option_errors))
+ DBUG_RETURN(1);
+
+ switch (table_list->view_check_option(thd,
+ ignore_check_option_errors)) {
+ case VIEW_CHECK_SKIP:
+ read_info.next_line();
+ goto continue_loop;
+ case VIEW_CHECK_ERROR:
+ DBUG_RETURN(-1);
+ }
+
+ if (thd->killed || write_record(thd,table,&info))
DBUG_RETURN(1);
+ thd->no_trans_update= no_trans_update;
+
/*
If auto_increment values are used, save the first one
for LAST_INSERT_ID() and for the binary/update log.
@@ -477,6 +604,7 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count);
}
thd->row_count++;
+continue_loop:;
}
if (id && !read_info.error)
thd->insert_id(id); // For binary/update log
@@ -486,80 +614,131 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
static int
-read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
- List<Item> &fields, READ_INFO &read_info,
- String &enclosed, ulong skip_lines)
+read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
+ List<Item> &fields_vars, List<Item> &set_fields,
+ List<Item> &set_values, READ_INFO &read_info,
+ String &enclosed, ulong skip_lines,
+ bool ignore_check_option_errors)
{
- List_iterator_fast<Item> it(fields);
- Item_field *sql_field;
+ List_iterator_fast<Item> it(fields_vars);
+ Item *item;
+ TABLE *table= table_list->table;
uint enclosed_length;
ulonglong id;
+ bool no_trans_update;
DBUG_ENTER("read_sep_field");
enclosed_length=enclosed.length();
id= 0;
+ no_trans_update= !table->file->has_transactions();
for (;;it.rewind())
{
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
DBUG_RETURN(1);
}
- while ((sql_field=(Item_field*) it++))
+
+ restore_record(table, s->default_values);
+
+ while ((item= it++))
{
uint length;
byte *pos;
if (read_info.read_field())
break;
+
+ /* If this line is to be skipped we don't want to fill field or var */
+ if (skip_lines)
+ continue;
+
pos=read_info.row_start;
length=(uint) (read_info.row_end-pos);
- Field *field=sql_field->field;
if (!read_info.enclosed &&
(enclosed_length && length == 4 && !memcmp(pos,"NULL",4)) ||
(length == 1 && read_info.found_null))
{
- field->reset();
- field->set_null();
- if (!field->maybe_null())
- {
- if (field->type() == FIELD_TYPE_TIMESTAMP)
- ((Field_timestamp*) field)->set_time();
- else if (field != table->next_number_field)
- field->set_warning((uint) MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_NULL_TO_NOTNULL, 1);
+ if (item->type() == Item::FIELD_ITEM)
+ {
+ Field *field= ((Item_field *)item)->field;
+ field->reset();
+ field->set_null();
+ if (!field->maybe_null())
+ {
+ if (field->type() == FIELD_TYPE_TIMESTAMP)
+ ((Field_timestamp*) field)->set_time();
+ else if (field != table->next_number_field)
+ field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_NULL_TO_NOTNULL, 1);
+ }
}
+ else
+ ((Item_user_var_as_out_param *)item)->set_null_value(
+ read_info.read_charset);
continue;
}
- field->set_notnull();
- read_info.row_end[0]=0; // Safe to change end marker
- field->store((char*) read_info.row_start,length,read_info.read_charset);
+
+ if (item->type() == Item::FIELD_ITEM)
+ {
+ Field *field= ((Item_field *)item)->field;
+ field->set_notnull();
+ read_info.row_end[0]=0; // Safe to change end marker
+ field->store((char*) pos, length, read_info.read_charset);
+ }
+ else
+ ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length,
+ read_info.read_charset);
}
if (read_info.error)
break;
if (skip_lines)
{
- if (!--skip_lines)
- thd->cuted_fields= 0L; // Reset warnings
+ skip_lines--;
continue;
}
- if (sql_field)
- { // Last record
- if (sql_field == (Item_field*) fields.head())
+ if (item)
+ {
+ /* Have not read any field, thus input file is simply ended */
+ if (item == fields_vars.head())
break;
- for (; sql_field ; sql_field=(Item_field*) it++)
+ for (; item ; item= it++)
{
- sql_field->field->set_null();
- sql_field->field->reset();
- thd->cuted_fields++;
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_TOO_FEW_RECORDS,
- ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
+ if (item->type() == Item::FIELD_ITEM)
+ {
+ /*
+ QQ: We probably should not throw warning for each field.
+ But how about intention to always have the same number
+ of warnings in THD::cuted_fields (and get rid of cuted_fields
+ in the end ?)
+ */
+ thd->cuted_fields++;
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_TOO_FEW_RECORDS,
+ ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
+ }
+ else
+ ((Item_user_var_as_out_param *)item)->set_null_value(
+ read_info.read_charset);
}
}
- if (write_record(table,&info))
+
+ if (fill_record(thd, set_fields, set_values, ignore_check_option_errors))
+ DBUG_RETURN(1);
+
+ switch (table_list->view_check_option(thd,
+ ignore_check_option_errors)) {
+ case VIEW_CHECK_SKIP:
+ read_info.next_line();
+ goto continue_loop;
+ case VIEW_CHECK_ERROR:
+ DBUG_RETURN(-1);
+ }
+
+
+ if (thd->killed || write_record(thd, table, &info))
DBUG_RETURN(1);
/*
If auto_increment values are used, save the first one
@@ -571,6 +750,7 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
id= thd->last_insert_id;
if (table->next_number_field)
table->next_number_field->reset(); // Clear for next record
+ thd->no_trans_update= no_trans_update;
if (read_info.next_line()) // Skip to next line
break;
if (read_info.line_cuted)
@@ -579,8 +759,11 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS),
thd->row_count);
+ if (thd->killed)
+ DBUG_RETURN(1);
}
thd->row_count++;
+continue_loop:;
}
if (id && !read_info.error)
thd->insert_id(id); // For binary/update log
@@ -669,12 +852,11 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
my_free((gptr) buffer,MYF(0)); /* purecov: inspected */
error=1;
}
- else
+ else
{
/*
init_io_cache() will not initialize read_function member
- if the cache is READ_NET. The reason is explained in
- mysys/mf_iocache.c. So we work around the problem with a
+ if the cache is READ_NET. So we work around the problem with a
manual assignment
*/
need_end_io_cache = 1;
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
index e7e24f957c6..4bb3482c7e6 100644
--- a/sql/sql_map.cc
+++ b/sql/sql_map.cc
@@ -20,9 +20,9 @@
#endif
#include "mysql_priv.h"
-#ifdef HAVE_MMAP
-#include <sys/mman.h>
#include <sys/stat.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
#endif
#ifndef MAP_NORESERVE
@@ -42,19 +42,18 @@ mapped_files::mapped_files(const my_string filename,byte *magic,uint magic_lengt
struct stat stat_buf;
if (!fstat(file,&stat_buf))
{
- if (!(map=(byte*) mmap(0,(size=(ulong) stat_buf.st_size),PROT_READ,
+ if (!(map=(byte*) my_mmap(0,(size=(ulong) stat_buf.st_size),PROT_READ,
MAP_SHARED | MAP_NORESERVE,file,
0L)))
{
error=errno;
- my_printf_error(0,"Can't map file: %s, errno: %d",MYF(0),
- (my_string) name,error);
+ my_error(ER_NO_FILE_MAPPING, MYF(0), (my_string) name, error);
}
}
if (map && memcmp(map,magic,magic_length))
{
- my_printf_error(0,"Wrong magic in %s",MYF(0),name);
- VOID(munmap(map,size));
+ my_error(ER_WRONG_MAGIC, MYF(0), name);
+ VOID(my_munmap(map,size));
map=0;
}
if (!map)
@@ -72,7 +71,7 @@ mapped_files::~mapped_files()
#ifdef HAVE_MMAP
if (file >= 0)
{
- VOID(munmap((caddr_t) map,size));
+ VOID(my_munmap(map,size));
VOID(my_close(file,MYF(0)));
file= -1; map=0;
}
@@ -112,8 +111,7 @@ mapped_files *map_file(const my_string name,byte *magic,uint magic_length)
{
map->use_count++;
if (!map->map)
- my_printf_error(0,"Can't map file: %s, error: %d",MYF(0),path,
- map->error);
+ my_error(ER_NO_FILE_MAPPING, MYF(0), path, map->error);
}
VOID(pthread_mutex_unlock(&LOCK_mapped_file));
return map;
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index 46f1e6c156e..07271d40492 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -152,7 +152,9 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
List<Item> all_fields(select_lex->item_list);
- if (setup_tables((TABLE_LIST *)select_lex->table_list.first) ||
+ if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first
+ &select_lex->where, &select_lex->leaf_tables,
+ FALSE, 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,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 49110e02113..0cb3a1cbc11 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -25,6 +25,9 @@
#include "ha_innodb.h"
#endif
+#include "sp_head.h"
+#include "sp.h"
+
#ifdef HAVE_OPENSSL
/*
Without SSL the handshake consists of one packet. This packet
@@ -43,6 +46,16 @@
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL */
+/* Used in error handling only */
+#define SP_TYPE_STRING(LP) \
+ ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE")
+#define SP_COM_STRING(LP) \
+ ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION || \
+ (LP)->sql_command == SQLCOM_ALTER_FUNCTION || \
+ (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \
+ (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
+ "FUNCTION" : "PROCEDURE")
+
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
@@ -53,8 +66,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
#endif
static void decrease_user_connections(USER_CONN *uc);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
-static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables,
- List<Item> *fields, SELECT_LEX *select_lex);
+static bool check_multi_update_lock(THD *thd);
static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
@@ -69,10 +81,14 @@ const char *command_name[]={
"Connect","Kill","Debug","Ping","Time","Delayed insert","Change user",
"Binlog Dump","Table Dump", "Connect Out", "Register Slave",
"Prepare", "Execute", "Long Data", "Close stmt",
- "Reset stmt", "Set option",
+ "Reset stmt", "Set option", "Fetch",
"Error" // Last command number
};
+const char *xa_state_names[]={
+ "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
+};
+
static char empty_c_string[1]= {0}; // Used for not defined 'db'
#ifdef __WIN__
@@ -99,7 +115,7 @@ static void unlock_locked_tables(THD *thd)
if (thd->locked_tables)
{
thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automaticly closed
+ thd->locked_tables=0; // Will be automatically closed
close_thread_tables(thd); // Free tables
}
}
@@ -108,17 +124,44 @@ static void unlock_locked_tables(THD *thd)
static bool end_active_trans(THD *thd)
{
int error=0;
+ DBUG_ENTER("end_active_trans");
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
OPTION_TABLE_LOCK))
{
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options));
+ /* Safety if one did "drop table" on locked tables */
+ if (!thd->locked_tables)
+ thd->options&= ~OPTION_TABLE_LOCK;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_commit(thd))
error=1;
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
}
- return error;
+ DBUG_RETURN(error);
}
+static bool begin_trans(THD *thd)
+{
+ int error=0;
+ if (thd->locked_tables)
+ {
+ thd->lock=thd->locked_tables;
+ thd->locked_tables=0; // Will be automatically closed
+ close_thread_tables(thd); // Free tables
+ }
+ if (end_active_trans(thd))
+ error= -1;
+ else
+ {
+ LEX *lex= thd->lex;
+ thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
+ OPTION_BEGIN);
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+ if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
+ error= ha_start_consistent_snapshot(thd);
+ }
+ return error;
+}
#ifdef HAVE_REPLICATION
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
@@ -156,25 +199,21 @@ static int get_or_create_user_conn(THD *thd, const char *user,
my_malloc(sizeof(struct user_conn) + temp_len+1,
MYF(MY_WME)))))
{
- send_error(thd, 0, NullS); // Out of memory
+ net_send_error(thd, 0, NullS); // Out of memory
return_val=1;
goto end;
}
uc->user=(char*) (uc+1);
memcpy(uc->user,temp_user,temp_len+1);
- uc->user_len= user_len;
- uc->host=uc->user + uc->user_len + 1;
+ uc->host= uc->user + user_len + 1;
uc->len = temp_len;
- uc->connections = 1;
- uc->questions=uc->updates=uc->conn_per_hour=0;
+ uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
uc->user_resources=*mqh;
- if (max_user_connections && mqh->connections > max_user_connections)
- uc->user_resources.connections = max_user_connections;
uc->intime=thd->thr_create_time;
if (my_hash_insert(&hash_user_connections, (byte*) uc))
{
my_free((char*) uc,0);
- send_error(thd, 0, NullS); // Out of memory
+ net_send_error(thd, 0, NullS); // Out of memory
return_val=1;
goto end;
}
@@ -196,13 +235,13 @@ end:
command originator of the check: now check_user is called
during connect and change user procedures; used for
logging.
- passwd scrambled password recieved from client
+ passwd scrambled password received from client
passwd_len length of scrambled password
db database name to connect to, may be NULL
check_count dont know exactly
Note, that host, user and passwd may point to communication buffer.
- Current implementation does not depened on that, but future changes
+ Current implementation does not depend on that, but future changes
should be done with this in mind; 'thd' is INOUT, all other params
are 'IN'.
@@ -221,13 +260,15 @@ int check_user(THD *thd, enum enum_server_command command,
#ifdef NO_EMBEDDED_ACCESS_CHECKS
thd->master_access= GLOBAL_ACLS; // Full rights
- /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
+ /* Change database if necessary */
if (db && db[0])
{
thd->db= 0;
thd->db_length= 0;
if (mysql_change_db(thd, db))
{
+ /* Send the error to the client */
+ net_send_error(thd);
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
DBUG_RETURN(-1);
@@ -249,7 +290,7 @@ int check_user(THD *thd, enum enum_server_command command,
*/
if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
{
- net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
DBUG_RETURN(-1);
}
@@ -260,7 +301,7 @@ int check_user(THD *thd, enum enum_server_command command,
/*
Clear thd->db as it points to something, that will be freed when
- connection is closed. We don't want to accidently free a wrong pointer
+ connection is closed. We don't want to accidentally free a wrong pointer
if connect failed. Also in case of 'CHANGE USER' failure, current
database will be switched to 'no database selected'.
*/
@@ -281,15 +322,16 @@ int check_user(THD *thd, enum enum_server_command command,
NET *net= &thd->net;
if (opt_secure_auth_local)
{
- net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
- thd->user, thd->host_or_ip);
+ net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
+ thd->user, thd->host_or_ip);
mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
thd->user, thd->host_or_ip);
DBUG_RETURN(-1);
}
+ /* We have to read very specific packet size */
if (send_old_password_request(thd) ||
- my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very
- { // specific packet size
+ my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
+ {
inc_host_errors(&thd->remote.sin_addr);
DBUG_RETURN(ER_HANDSHAKE_ERROR);
}
@@ -301,7 +343,7 @@ int check_user(THD *thd, enum enum_server_command command,
/* here res is always >= 0 */
if (res == 0)
{
- if (!(thd->master_access & NO_ACCESS)) // authentification is OK
+ if (!(thd->master_access & NO_ACCESS)) // authentication is OK
{
DBUG_PRINT("info",
("Capabilities: %d packet_length: %ld Host: '%s' "
@@ -315,12 +357,12 @@ int check_user(THD *thd, enum enum_server_command command,
if (check_count)
{
VOID(pthread_mutex_lock(&LOCK_thread_count));
- bool count_ok= thread_count < max_connections + delayed_insert_threads
+ bool count_ok= thread_count <= max_connections + delayed_insert_threads
|| (thd->master_access & SUPER_ACL);
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (!count_ok)
- { // too many connections
- send_error(thd, ER_CON_COUNT_ERROR);
+ { // too many connections
+ net_send_error(thd, ER_CON_COUNT_ERROR);
DBUG_RETURN(-1);
}
}
@@ -341,21 +383,27 @@ int check_user(THD *thd, enum enum_server_command command,
thd->db_access=0;
/* Don't allow user to connect if he has done too many queries */
- if ((ur.questions || ur.updates || ur.connections ||
+ if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
max_user_connections) &&
- get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur))
+ get_or_create_user_conn(thd,
+ opt_old_style_user_limits ? thd->user : thd->priv_user,
+ opt_old_style_user_limits ? thd->host_or_ip : thd->priv_host,
+ &ur))
DBUG_RETURN(-1);
if (thd->user_connect &&
- (thd->user_connect->user_resources.connections ||
+ (thd->user_connect->user_resources.conn_per_hour ||
+ thd->user_connect->user_resources.user_conn ||
max_user_connections) &&
check_for_max_user_connections(thd, thd->user_connect))
DBUG_RETURN(-1);
- /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
+ /* Change database if necessary */
if (db && db[0])
{
if (mysql_change_db(thd, db))
{
+ /* Send error to the client */
+ net_send_error(thd);
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
DBUG_RETURN(-1);
@@ -370,14 +418,14 @@ int check_user(THD *thd, enum enum_server_command command,
}
else if (res == 2) // client gave short hash, server has long hash
{
- net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
DBUG_RETURN(-1);
}
- net_printf(thd, ER_ACCESS_DENIED_ERROR,
- thd->user,
- thd->host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
+ net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
+ thd->user,
+ thd->host_or_ip,
+ passwd_len ? ER(ER_YES) : ER(ER_NO));
mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
thd->user,
thd->host_or_ip,
@@ -437,20 +485,29 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
DBUG_ENTER("check_for_max_user_connections");
(void) pthread_mutex_lock(&LOCK_user_conn);
- if (max_user_connections &&
+ if (max_user_connections && !uc->user_resources.user_conn &&
max_user_connections < (uint) uc->connections)
{
- net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
+ net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
error=1;
goto end;
}
time_out_user_resource_limits(thd, uc);
- if (uc->user_resources.connections &&
- uc->user_resources.connections <= uc->conn_per_hour)
+ if (uc->user_resources.user_conn &&
+ uc->user_resources.user_conn < uc->connections)
{
- net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
- "max_connections",
- (long) uc->user_resources.connections);
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
+ "max_user_connections",
+ (long) uc->user_resources.user_conn);
+ error= 1;
+ goto end;
+ }
+ if (uc->user_resources.conn_per_hour &&
+ uc->user_resources.conn_per_hour <= uc->conn_per_hour)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
+ "max_connections",
+ (long) uc->user_resources.conn_per_hour);
error=1;
goto end;
}
@@ -509,6 +566,12 @@ void free_max_user_conn(void)
sql_command is actually set to SQLCOM_END sometimes
so we need the +1 to include it in the array.
+
+ numbers are:
+ 0 - read-only query
+ != 0 - query that may change a table
+ 2 - query that returns meaningful ROW_COUNT() -
+ a number of modified rows
*/
char uc_update_queries[SQLCOM_END+1];
@@ -520,23 +583,25 @@ void init_update_queries(void)
uc_update_queries[SQLCOM_CREATE_TABLE]=1;
uc_update_queries[SQLCOM_CREATE_INDEX]=1;
uc_update_queries[SQLCOM_ALTER_TABLE]=1;
- uc_update_queries[SQLCOM_UPDATE]=1;
- uc_update_queries[SQLCOM_INSERT]=1;
- uc_update_queries[SQLCOM_INSERT_SELECT]=1;
- uc_update_queries[SQLCOM_DELETE]=1;
+ uc_update_queries[SQLCOM_UPDATE]=2;
+ uc_update_queries[SQLCOM_UPDATE_MULTI]=2;
+ uc_update_queries[SQLCOM_INSERT]=2;
+ uc_update_queries[SQLCOM_INSERT_SELECT]=2;
+ uc_update_queries[SQLCOM_DELETE]=2;
+ uc_update_queries[SQLCOM_DELETE_MULTI]=2;
uc_update_queries[SQLCOM_TRUNCATE]=1;
uc_update_queries[SQLCOM_DROP_TABLE]=1;
uc_update_queries[SQLCOM_LOAD]=1;
uc_update_queries[SQLCOM_CREATE_DB]=1;
uc_update_queries[SQLCOM_DROP_DB]=1;
- uc_update_queries[SQLCOM_REPLACE]=1;
- uc_update_queries[SQLCOM_REPLACE_SELECT]=1;
+ uc_update_queries[SQLCOM_REPLACE]=2;
+ uc_update_queries[SQLCOM_REPLACE_SELECT]=2;
uc_update_queries[SQLCOM_RENAME_TABLE]=1;
uc_update_queries[SQLCOM_BACKUP_TABLE]=1;
uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
- uc_update_queries[SQLCOM_DELETE_MULTI]=1;
uc_update_queries[SQLCOM_DROP_INDEX]=1;
- uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
+ uc_update_queries[SQLCOM_CREATE_VIEW]=1;
+ uc_update_queries[SQLCOM_DROP_VIEW]=1;
}
bool is_update_query(enum enum_sql_command command)
@@ -561,7 +626,6 @@ bool is_update_query(enum enum_sql_command command)
static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
{
- bool error= 0;
time_t check_time = thd->start_time ? thd->start_time : time(NULL);
DBUG_ENTER("time_out_user_resource_limits");
@@ -600,8 +664,8 @@ static bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.questions &&
uc->questions++ >= uc->user_resources.questions)
{
- net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
- (long) uc->user_resources.questions);
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
+ (long) uc->user_resources.questions);
error=1;
goto end;
}
@@ -611,8 +675,8 @@ static bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.updates && uc_update_queries[check_command] &&
uc->updates++ >= uc->user_resources.updates)
{
- net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
- (long) uc->user_resources.updates);
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
+ (long) uc->user_resources.updates);
error=1;
goto end;
}
@@ -626,7 +690,7 @@ end:
}
-static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
+static void reset_mqh(LEX_USER *lu, bool get_them= 0)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
(void) pthread_mutex_lock(&LOCK_user_conn);
@@ -648,8 +712,9 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
uc->conn_per_hour=0;
}
}
- else // for FLUSH PRIVILEGES and FLUSH USER_RESOURCES
+ else
{
+ /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
for (uint idx=0;idx < hash_user_connections.records; idx++)
{
USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
@@ -750,7 +815,7 @@ static int check_connection(THD *thd)
#endif /* HAVE_COMPRESS */
#ifdef HAVE_OPENSSL
if (ssl_acceptor_fd)
- client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
+ client_flags |= CLIENT_SSL; /* Wow, SSL is available! */
#endif /* HAVE_OPENSSL */
end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
@@ -798,17 +863,6 @@ static int check_connection(THD *thd)
return(ER_OUT_OF_RESOURCES);
thd->client_capabilities=uint2korr(net->read_pos);
-#ifdef TO_BE_REMOVED_IN_4_1_RELEASE
- /*
- This is just a safety check against any client that would use the old
- CLIENT_CHANGE_USER flag
- */
- if ((thd->client_capabilities & CLIENT_PROTOCOL_41) &&
- !(thd->client_capabilities & (CLIENT_RESERVED |
- CLIENT_SECURE_CONNECTION |
- CLIENT_MULTI_RESULTS)))
- thd->client_capabilities&= ~CLIENT_PROTOCOL_41;
-#endif
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
@@ -956,6 +1010,7 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
*/
save_vio= thd->net.vio;
thd->net.vio= 0;
+ thd->net.no_send_error= 0;
dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
rw_unlock(var_mutex);
thd->client_capabilities= save_client_capabilities;
@@ -974,7 +1029,7 @@ pthread_handler_decl(handle_one_connection,arg)
pthread_detach_this_thread();
#if !defined( __WIN__) && !defined(OS2) // Win32 calls this in pthread_create
- // The following calls needs to be done before we call DBUG_ macros
+ /* The following calls needs to be done before we call DBUG_ macros */
if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
@@ -993,7 +1048,7 @@ pthread_handler_decl(handle_one_connection,arg)
*/
DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
thd->thread_id));
- // now that we've called my_thread_init(), it is safe to call DBUG_*
+ /* now that we've called my_thread_init(), it is safe to call DBUG_* */
#if defined(__WIN__)
init_signals(); // IRENA; testing ?
@@ -1015,11 +1070,12 @@ pthread_handler_decl(handle_one_connection,arg)
int error;
NET *net= &thd->net;
thd->thread_stack= (char*) &thd;
+ net->no_send_error= 0;
if ((error=check_connection(thd)))
{ // Wrong permissions
if (error > 0)
- net_printf(thd,error,thd->host_or_ip);
+ net_printf_error(thd, error, thd->host_or_ip);
#ifdef __NT__
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
my_sleep(1000); /* must wait after eof() */
@@ -1037,32 +1093,39 @@ pthread_handler_decl(handle_one_connection,arg)
thd->version= refresh_version;
thd->proc_info= 0;
+ thd->command= COM_SLEEP;
thd->set_time();
thd->init_for_queries();
+
if (sys_init_connect.value_length && !(thd->master_access & SUPER_ACL))
{
execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
if (thd->query_error)
- thd->killed= 1;
+ thd->killed= THD::KILL_CONNECTION;
}
- while (!net->error && net->vio != 0 && !thd->killed)
+
+ thd->proc_info=0;
+ thd->set_time();
+ thd->init_for_queries();
+ while (!net->error && net->vio != 0 &&
+ !(thd->killed == THD::KILL_CONNECTION))
{
+ net->no_send_error= 0;
if (do_command(thd))
break;
}
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
- free_root(thd->mem_root,MYF(0));
if (net->error && net->vio != 0 && net->report_error)
{
if (!thd->killed && thd->variables.log_warnings > 1)
- sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
+ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
thd->thread_id,(thd->db ? thd->db : "unconnected"),
thd->user ? thd->user : "unauthenticated",
thd->host_or_ip,
(net->last_errno ? ER(net->last_errno) :
ER(ER_UNKNOWN_ERROR)));
- send_error(thd,net->last_errno,NullS);
+ net_send_error(thd, net->last_errno, NullS);
statistic_increment(aborted_threads,&LOCK_status);
}
else if (thd->killed)
@@ -1128,25 +1191,26 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->init_for_queries();
while (fgets(buff, thd->net.max_packet, file))
{
- ulong length= (ulong) strlen(buff);
- while (buff[length-1] != '\n' && !feof(file))
- {
- /*
- We got only a part of the current string. Will try to increase
- net buffer then read the rest of the current string.
- */
- if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
- {
- send_error(thd, thd->net.last_errno, NullS);
- thd->is_fatal_error= 1;
- break;
- }
- buff= (char*) thd->net.buff;
- fgets(buff + length, thd->net.max_packet - length, file);
- length+= (ulong) strlen(buff + length);
- }
- if (thd->is_fatal_error)
- break;
+ ulong length= (ulong) strlen(buff);
+ while (buff[length-1] != '\n' && !feof(file))
+ {
+ /*
+ We got only a part of the current string. Will try to increase
+ net buffer then read the rest of the current string.
+ */
+ if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
+ {
+ net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
+ thd->fatal_error();
+ break;
+ }
+ buff= (char*) thd->net.buff;
+ fgets(buff + length, thd->net.max_packet - length, file);
+ length+= (ulong) strlen(buff + length);
+ }
+ if (thd->is_fatal_error)
+ break;
+
while (length && (my_isspace(thd->charset(), buff[length-1]) ||
buff[length-1] == ';'))
length--;
@@ -1154,24 +1218,29 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->query_length=length;
thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
thd->query[length] = '\0';
- thd->query_id=query_id++;
- if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
- {
- thd->net.error = 0;
- close_thread_tables(thd); // Free tables
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- break;
- }
+ /*
+ We don't need to obtain LOCK_thread_count here because in bootstrap
+ mode we have only one thread.
+ */
+ thd->query_id=next_query_id();
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->is_fatal_error)
break;
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+#ifdef USING_TRANSACTIONS
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
+#endif
}
/* thd->fatal_error should be set in case something went wrong */
end:
+ bootstrap_error= thd->is_fatal_error;
+
+ net_end(&thd->net);
+ thd->cleanup();
+ delete thd;
+
#ifndef EMBEDDED_LIBRARY
(void) pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
@@ -1180,15 +1249,21 @@ end:
my_thread_end();
pthread_exit(0);
#endif
- DBUG_RETURN(0); // Never reached
+ DBUG_RETURN(0);
}
/* This works because items are allocated with sql_alloc() */
void free_items(Item *item)
{
- for (; item ; item=item->next)
+ Item *next;
+ DBUG_ENTER("free_items");
+ for (; item ; item=next)
+ {
+ next=item->next;
item->delete_self();
+ }
+ DBUG_VOID_RETURN;
}
/* This works because items are allocated with sql_alloc() */
@@ -1208,19 +1283,19 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
db = (db && db[0]) ? db : thd->db;
if (!(table_list = (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(1); // out of memory
- table_list->db = db;
- table_list->real_name = table_list->alias = tbl_name;
- table_list->lock_type = TL_READ_NO_INSERT;
- table_list->next = 0;
+ table_list->db= db;
+ table_list->table_name= table_list->alias= tbl_name;
+ table_list->lock_type= TL_READ_NO_INSERT;
+ table_list->prev_global= &table_list; // can be removed after merge with 4.1
if (!db || check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
+ my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL");
goto err;
}
if (lower_case_table_names)
my_casedn_str(files_charset_info, tbl_name);
- remove_escape(table_list->real_name);
+ remove_escape(table_list->table_name);
if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
DBUG_RETURN(1);
@@ -1230,7 +1305,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
thd->free_list = 0;
thd->query_length=(uint) strlen(tbl_name);
thd->query = tbl_name;
- if ((error = mysqld_dump_create_info(thd, table, -1)))
+ if ((error = mysqld_dump_create_info(thd, table_list, -1)))
{
my_error(ER_GET_ERRNO, MYF(0), my_errno);
goto err;
@@ -1240,10 +1315,71 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
my_error(ER_GET_ERRNO, MYF(0), error);
err:
- close_thread_tables(thd);
DBUG_RETURN(error);
}
+/*
+ Ends the current transaction and (maybe) begin the next
+
+ SYNOPSIS
+ end_trans()
+ thd Current thread
+ completion Completion type
+
+ RETURN
+ 0 - OK
+*/
+
+int end_trans(THD *thd, enum enum_mysql_completiontype completion)
+{
+ bool do_release= 0;
+ int res= 0;
+ DBUG_ENTER("end_trans");
+
+ switch (completion) {
+ case COMMIT:
+ /*
+ We don't use end_active_trans() here to ensure that this works
+ even if there is a problem with the OPTION_AUTO_COMMIT flag
+ (Which of course should never happen...)
+ */
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ res= ha_commit(thd);
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ break;
+ case COMMIT_RELEASE:
+ do_release= 1; /* fall through */
+ case COMMIT_AND_CHAIN:
+ res= end_active_trans(thd);
+ if (!res && completion == COMMIT_AND_CHAIN)
+ res= begin_trans(thd);
+ break;
+ case ROLLBACK_RELEASE:
+ do_release= 1; /* fall through */
+ case ROLLBACK:
+ case ROLLBACK_AND_CHAIN:
+ {
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ if (ha_rollback(thd))
+ res= -1;
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ if (!res && (completion == ROLLBACK_AND_CHAIN))
+ res= begin_trans(thd);
+ break;
+ }
+ default:
+ res= -1;
+ my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ if (res < 0)
+ my_error(thd->killed_errno(), MYF(0));
+ else if ((res == 0) && do_release)
+ thd->killed= THD::KILL_CONNECTION;
+
+ DBUG_RETURN(res);
+}
#ifndef EMBEDDED_LIBRARY
@@ -1275,7 +1411,7 @@ bool do_command(THD *thd)
packet=0;
old_timeout=net->read_timeout;
- // Wait max for 8 hours
+ /* Wait max for 8 hours */
net->read_timeout=(uint) thd->variables.net_wait_timeout;
thd->clear_error(); // Clear error message
@@ -1291,12 +1427,15 @@ bool do_command(THD *thd)
statistic_increment(aborted_threads,&LOCK_status);
DBUG_RETURN(TRUE); // We have to close it.
}
- send_error(thd,net->last_errno,NullS);
+ net_send_error(thd, net->last_errno, NullS);
net->error= 0;
DBUG_RETURN(FALSE);
}
else
{
+ if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
+ thd->killed= THD::NOT_KILLED;
+
packet=(char*) net->read_pos;
command = (enum enum_server_command) (uchar) packet[0];
if (command >= COM_END)
@@ -1319,6 +1458,7 @@ bool do_command(THD *thd)
}
#endif /* EMBEDDED_LIBRARY */
+
/*
Perform one connection-level (COM_XXXX) command.
SYNOPSIS
@@ -1348,11 +1488,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
this so that they will not get logged to the slow query log
*/
thd->slow_command=FALSE;
+ thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
thd->set_time();
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id=query_id;
if (command != COM_STATISTICS && command != COM_PING)
- query_id++;
+ next_query_id();
thread_running++;
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -1363,7 +1504,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_INIT_DB:
{
LEX_STRING tmp;
- statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
+ &LOCK_status);
thd->convert_string(&tmp, system_charset_info,
packet, strlen(packet), thd->charset());
if (!mysql_change_db(thd, tmp.str))
@@ -1384,13 +1526,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint db_len= *(uchar*) packet;
uint tbl_len= *(uchar*) (packet + db_len + 1);
- statistic_increment(com_other, &LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
thd->slow_command= TRUE;
db= thd->alloc(db_len + tbl_len + 2);
tbl_name= strmake(db, packet + 1, db_len)+1;
strmake(tbl_name, packet + db_len + 2, tbl_len);
- if (mysql_table_dump(thd, db, tbl_name, -1))
- send_error(thd); // dump to NET
+ mysql_table_dump(thd, db, tbl_name, -1);
break;
}
case COM_CHANGE_USER:
@@ -1398,7 +1539,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->change_user();
thd->clear_error(); // if errors from rollback
- statistic_increment(com_other, &LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
char *user= (char*) packet;
char *passwd= strend(user)+1;
/*
@@ -1412,10 +1553,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*passwd++ : strlen(passwd);
db+= passwd_len + 1;
#ifndef EMBEDDED_LIBRARY
- /* Small check for incomming packet */
+ /* Small check for incoming packet */
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
{
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
#endif
@@ -1438,7 +1579,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (!(thd->user= my_strdup(user, MYF(0))))
{
thd->user= save_user;
- send_error(thd, ER_OUT_OF_RESOURCES);
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
break;
}
@@ -1448,9 +1589,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (res)
{
- /* authentification failure, we shall restore old user */
+ /* authentication failure, we shall restore old user */
if (res > 0)
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
x_free(thd->user);
thd->user= save_user;
thd->priv_user= save_priv_user;
@@ -1475,6 +1616,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
mysql_stmt_execute(thd, packet, packet_length);
break;
}
+ case COM_FETCH:
+ {
+ mysql_stmt_fetch(thd, packet, packet_length);
+ break;
+ }
case COM_LONG_DATA:
{
mysql_stmt_get_longdata(thd, packet, packet_length);
@@ -1482,7 +1628,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_PREPARE:
{
- mysql_stmt_prepare(thd, packet, packet_length);
+ mysql_stmt_prepare(thd, packet, packet_length, 0);
break;
}
case COM_CLOSE_STMT:
@@ -1504,15 +1650,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_PRINT("query",("%-.4096s",thd->query));
mysql_parse(thd,thd->query, thd->query_length);
- while (!thd->killed && !thd->is_fatal_error && thd->lex->found_colon)
+ while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
{
- char *packet= thd->lex->found_colon;
+ char *packet= thd->lex->found_semicolon;
/*
Multiple queries exits, execute them individually
in embedded server - just store them to be executed later
*/
#ifndef EMBEDDED_LIBRARY
- if (thd->lock || thd->open_tables || thd->derived_tables)
+ if (thd->lock || thd->open_tables || thd->derived_tables ||
+ thd->prelocked_mode)
close_thread_tables(thd);
#endif
ulong length= (ulong)(packet_end-packet);
@@ -1528,7 +1675,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_length= length;
thd->query= packet;
- thd->query_id= query_id++;
+ thd->query_id= next_query_id();
thd->set_time(); /* Reset the query start time. */
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -1560,34 +1707,50 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_FIELD_LIST: // This isn't actually needed
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
break;
#else
{
char *fields, *pend;
+ /* Locked closure of all tables */
+ TABLE_LIST *locked_tables= NULL;
TABLE_LIST table_list;
LEX_STRING conv_name;
+ /* Saved variable value */
+ my_bool old_innodb_table_locks=
+ IF_INNOBASE_DB(thd->variables.innodb_table_locks, FALSE);
- statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
+
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
+ &LOCK_status);
bzero((char*) &table_list,sizeof(table_list));
if (!(table_list.db=thd->db))
{
- send_error(thd,ER_NO_DB_ERROR);
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
break;
}
- thd->free_list=0;
pend= strend(packet);
thd->convert_string(&conv_name, system_charset_info,
packet, (uint) (pend-packet), thd->charset());
- table_list.alias= table_list.real_name= conv_name.str;
+ table_list.alias= table_list.table_name= conv_name.str;
packet= pend+1;
+
+ if (!my_strcasecmp(system_charset_info, table_list.db,
+ information_schema_name.str))
+ {
+ ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
+ if (schema_table)
+ table_list.schema_table= schema_table;
+ }
+
thd->query_length= strlen(packet); // for simplicity: don't optimize
if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
break;
- mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
+ mysql_log.write(thd,command,"%s %s",table_list.table_name, fields);
if (lower_case_table_names)
- my_casedn_str(files_charset_info, table_list.real_name);
- remove_escape(table_list.real_name); // This can't have wildcards
+ my_casedn_str(files_charset_info, table_list.table_name);
+ remove_escape(table_list.table_name); // This can't have wildcards
if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
0, 0))
@@ -1595,9 +1758,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (grant_option &&
check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
break;
+ /* init structures for VIEW processing */
+ table_list.select_lex= &(thd->lex->select_lex);
+ mysql_init_query(thd, (uchar*)"", 0);
+ thd->lex->
+ select_lex.table_list.link_in_list((byte*) &table_list,
+ (byte**) &table_list.next_local);
+ thd->lex->query_tables= &table_list;
+
+ /* switch on VIEW optimisation: do not fill temporary tables */
+ thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
mysqld_list_fields(thd,&table_list,fields);
- free_items(thd->free_list);
- thd->free_list= 0;
+ thd->lex->unit.cleanup();
+ thd->cleanup_after_query();
break;
}
#endif
@@ -1613,43 +1786,43 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
char *db=thd->strdup(packet), *alias;
HA_CREATE_INFO create_info;
- statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
+ &LOCK_status);
// null test to handle EOM
if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
+ my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
break;
}
if (check_access(thd,CREATE_ACL,db,0,1,0))
break;
mysql_log.write(thd,command,packet);
bzero(&create_info, sizeof(create_info));
- if (mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
- &create_info, 0) < 0)
- send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db),
+ &create_info, 0);
break;
}
case COM_DROP_DB: // QQ: To be removed
{
- statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
- char *db=thd->strdup(packet), *alias;
- // null test to handle EOM
- if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
+ statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
+ &LOCK_status);
+ char *db=thd->strdup(packet);
+ /* null test to handle EOM */
+ if (!db || check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
+ my_error(ER_WRONG_DB_NAME, MYF(0), db ? db : "NULL");
break;
}
if (check_access(thd,DROP_ACL,db,0,1,0))
break;
if (thd->locked_tables || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
break;
}
mysql_log.write(thd,command,db);
- if (mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : db),
- 0, 0) < 0)
- send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ mysql_rm_db(thd, db, 0, 0);
break;
}
#ifndef EMBEDDED_LIBRARY
@@ -1659,7 +1832,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
ushort flags;
uint32 slave_server_id;
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other,&LOCK_status);
thd->slow_command = TRUE;
if (check_global_access(thd, REPL_SLAVE_ACL))
break;
@@ -1676,7 +1849,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
(long) pos);
mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unregister_slave(thd,1,1);
- // fake COM_QUIT -- if we get here, the thread needs to terminate
+ /* fake COM_QUIT -- if we get here, the thread needs to terminate */
error = TRUE;
net->error = 0;
break;
@@ -1684,21 +1857,20 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
case COM_REFRESH:
{
- statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
+ &LOCK_status);
ulong options= (ulong) (uchar) packet[0];
if (check_global_access(thd,RELOAD_ACL))
break;
mysql_log.write(thd,command,NullS);
- if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL))
- send_error(thd, 0);
- else
+ if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL))
send_ok(thd);
break;
}
#ifndef EMBEDDED_LIBRARY
case COM_SHUTDOWN:
{
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
if (check_global_access(thd,SHUTDOWN_ACL))
break; /* purecov: inspected */
/*
@@ -1715,7 +1887,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level");
- send_error(thd);
break;
}
DBUG_PRINT("quit",("Got shutdown command for level %u", level));
@@ -1729,8 +1900,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
close_connection(thd, 0, 1);
close_thread_tables(thd); // Free before kill
- free_root(thd->mem_root,MYF(0));
- free_root(&thd->transaction.mem_root,MYF(0));
kill_mysql();
error=TRUE;
break;
@@ -1739,7 +1908,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_STATISTICS:
{
mysql_log.write(thd,command,NullS);
- statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
+ &LOCK_status);
#ifndef EMBEDDED_LIBRARY
char buff[200];
#else
@@ -1747,11 +1917,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
ulong uptime = (ulong) (thd->start_time - start_time);
sprintf((char*) buff,
- "Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %u Queries per second avg: %.3f",
+ "Uptime: %lu Threads: %d Questions: %lu Slow queries: %lu Opens: %lu Flush tables: %lu Open tables: %u Queries per second avg: %.3f",
uptime,
- (int) thread_count,thd->query_id,long_query_count,
- opened_tables,refresh_version, cached_tables(),
- uptime ? (float)thd->query_id/(float)uptime : 0);
+ (int) thread_count, (ulong) thd->query_id,
+ (ulong) thd->status_var.long_query_count,
+ thd->status_var.opened_tables, refresh_version, cached_tables(),
+ (uptime ? (ulonglong2double(thd->query_id) / (double) uptime) :
+ (double) 0));
#ifdef SAFEMALLOC
if (sf_malloc_cur_memory) // Using SAFEMALLOC
sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK",
@@ -1765,11 +1937,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_PING:
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
send_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
- statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
+ &LOCK_status);
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
mysql_log.write(thd,command,NullS);
@@ -1779,14 +1952,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
case COM_PROCESS_KILL:
{
- statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
ulong id=(ulong) uint4korr(packet);
- kill_one_thread(thd,id);
+ kill_one_thread(thd,id,false);
break;
}
case COM_SET_OPTION:
{
- statistic_increment(com_stat[SQLCOM_SET_OPTION], &LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
+ &LOCK_status);
enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
switch (command) {
case MYSQL_OPTION_MULTI_STATEMENTS_ON:
@@ -1798,16 +1972,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
send_eof(thd);
break;
default:
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
break;
}
case COM_DEBUG:
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
if (check_global_access(thd, SUPER_ACL))
break; /* purecov: inspected */
- mysql_print_status(thd);
+ mysql_print_status();
mysql_log.write(thd,command,NullS);
send_eof(thd);
break;
@@ -1817,17 +1991,32 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_DELAYED_INSERT:
case COM_END:
default:
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
- if (thd->lock || thd->open_tables || thd->derived_tables)
+ if (thd->lock || thd->open_tables || thd->derived_tables ||
+ thd->prelocked_mode)
{
thd->proc_info="closing tables";
close_thread_tables(thd); /* Free tables */
}
+ /*
+ assume handlers auto-commit (if some doesn't - transaction handling
+ in MySQL should be redesigned to support it; it's a big change,
+ and it's not worth it - better to commit explicitly only writing
+ transactions, read-only ones should better take care of themselves.
+ saves some work in 2pc too)
+ see also sql_base.cc - close_thread_tables()
+ */
+ bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
+ if (!thd->active_transaction())
+ thd->transaction.xid.null();
- if (thd->is_fatal_error)
- send_error(thd,0); // End of memory ?
+ /* report error issued during command execution */
+ if (thd->killed_errno() && !thd->net.report_error)
+ thd->send_kill_message();
+ if (thd->net.report_error)
+ net_send_error(thd);
log_slow_query(thd);
@@ -1861,13 +2050,126 @@ static void log_slow_query(THD *thd)
(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
(specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
{
- long_query_count++;
+ thd->status_var.long_query_count++;
mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
}
}
}
+int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
+ enum enum_schema_tables schema_table_idx)
+{
+ DBUG_ENTER("prepare_schema_table");
+ SELECT_LEX *sel= 0;
+ switch (schema_table_idx) {
+ case SCH_SCHEMATA:
+#if defined(DONT_ALLOW_SHOW_COMMANDS)
+ my_message(ER_NOT_ALLOWED_COMMAND,
+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1);
+#else
+ if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
+ check_global_access(thd, SHOW_DB_ACL))
+ DBUG_RETURN(1);
+ break;
+#endif
+ case SCH_TABLE_NAMES:
+ case SCH_TABLES:
+ case SCH_VIEWS:
+#ifdef DONT_ALLOW_SHOW_COMMANDS
+ my_message(ER_NOT_ALLOWED_COMMAND,
+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1);
+#else
+ {
+ char *db= lex->select_lex.db ? lex->select_lex.db : thd->db;
+ if (!db)
+ {
+ my_message(ER_NO_DB_ERROR,
+ ER(ER_NO_DB_ERROR), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ remove_escape(db); // Fix escaped '_'
+ if (check_db_name(db))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db);
+ DBUG_RETURN(1);
+ }
+ if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
+ DBUG_RETURN(1); /* purecov: inspected */
+ if (!thd->col_access && check_grant_db(thd,db))
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user, thd->priv_host, db);
+ DBUG_RETURN(1);
+ }
+ /*
+ We need to do a copy to make this prepared statement safe if this
+ was thd->db
+ */
+ lex->select_lex.db= thd->strdup(db);
+ break;
+ }
+#endif
+ case SCH_COLUMNS:
+ case SCH_STATISTICS:
+#ifdef DONT_ALLOW_SHOW_COMMANDS
+ my_message(ER_NOT_ALLOWED_COMMAND,
+ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(1);
+#else
+ if (table_ident)
+ {
+ TABLE_LIST **query_tables_last= lex->query_tables_last;
+ sel= new SELECT_LEX();
+ sel->init_query();
+ if(!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
+ (List<String> *) 0, (List<String> *) 0))
+ DBUG_RETURN(1);
+ lex->query_tables_last= query_tables_last;
+ TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
+ char *db= table_list->db;
+ remove_escape(db); // Fix escaped '_'
+ remove_escape(table_list->table_name);
+ if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
+ &table_list->grant.privilege, 0, 0))
+ DBUG_RETURN(1); /* purecov: inspected */
+ if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
+ UINT_MAX, 0))
+ DBUG_RETURN(1);
+ break;
+ }
+#endif
+ case SCH_OPEN_TABLES:
+ case SCH_VARIABLES:
+ case SCH_STATUS:
+ case SCH_PROCEDURES:
+ case SCH_CHARSETS:
+ case SCH_COLLATIONS:
+ case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
+ case SCH_USER_PRIVILEGES:
+ case SCH_SCHEMA_PRIVILEGES:
+ case SCH_TABLE_PRIVILEGES:
+ case SCH_COLUMN_PRIVILEGES:
+ case SCH_TABLE_CONSTRAINTS:
+ case SCH_KEY_COLUMN_USAGE:
+ default:
+ break;
+ }
+
+ SELECT_LEX *select_lex= lex->current_select;
+ if (make_schema_select(thd, select_lex, schema_table_idx))
+ {
+ DBUG_RETURN(1);
+ }
+ TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
+ table_list->schema_select_lex= sel;
+ table_list->schema_table_reformed= 1;
+ DBUG_RETURN(0);
+}
+
+
/*
Read query from packet and store in thd->query
Used in COM_QUERY and COM_PREPARE
@@ -1878,8 +2180,8 @@ static void log_slow_query(THD *thd)
query_length
RETURN VALUES
- 0 ok
- 1 error; In this case thd->fatal_error is set
+ FALSE ok
+ TRUE error; In this case thd->fatal_error is set
*/
bool alloc_query(THD *thd, char *packet, ulong packet_length)
@@ -1904,7 +2206,7 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length)
packet_length,
thd->db_length+ 1 +
QUERY_CACHE_FLAGS_SIZE)))
- return 1;
+ return TRUE;
thd->query[packet_length]=0;
thd->query_length= packet_length;
@@ -1914,7 +2216,7 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length)
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
- return 0;
+ return FALSE;
}
/****************************************************************************
@@ -1922,26 +2224,56 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length)
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/
-void
+bool
mysql_execute_command(THD *thd)
{
- int res= 0;
+ bool res= FALSE;
+ int result= 0;
LEX *lex= thd->lex;
+ /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
+ SELECT_LEX *select_lex= &lex->select_lex;
bool slave_fake_lock= 0;
MYSQL_LOCK *fake_prev_lock= 0;
- SELECT_LEX *select_lex= &lex->select_lex;
- TABLE_LIST *tables= (TABLE_LIST*) select_lex->table_list.first;
+ /* first table of first SELECT_LEX */
+ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
+ /* list of all tables in query */
+ TABLE_LIST *all_tables;
+ /* most outer SELECT_LEX_UNIT of query */
SELECT_LEX_UNIT *unit= &lex->unit;
+ /* Saved variable value */
DBUG_ENTER("mysql_execute_command");
+ thd->net.no_send_error= 0;
+
+ /*
+ In many cases first table of main SELECT_LEX have special meaning =>
+ check that it is first table in global list and relink it first in
+ queries_tables list if it is necessary (we need such relinking only
+ for queries with subqueries in select list, in this case tables of
+ subqueries will go to global list first)
+
+ all_tables will differ from first_table only if most upper SELECT_LEX
+ do not contain tables.
+
+ Because of above in place where should be at least one table in most
+ outer SELECT_LEX we have following check:
+ DBUG_ASSERT(first_table == all_tables);
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ */
+ lex->first_lists_tables_same();
+ /* should be assigned after making first tables same */
+ all_tables= lex->query_tables;
/*
Reset warning count for each query that uses tables
A better approach would be to reset this for any commands
that is not a SHOW command or a select that only access local
variables, but for now this is probably good enough.
+ Don't reset warnings when executing a stored routine.
*/
- if (tables || &lex->select_lex != lex->all_selects_list)
- mysql_reset_errors(thd);
+ if ((all_tables || &lex->select_lex != lex->all_selects_list ||
+ lex->spfuns.records || lex->spprocs.records) &&
+ !thd->spcont)
+ mysql_reset_errors(thd, 0);
#ifdef HAVE_REPLICATION
if (thd->slave_thread)
@@ -1950,8 +2282,7 @@ mysql_execute_command(THD *thd)
{
DBUG_PRINT("info",("need faked locked tables"));
- if (check_multi_update_lock(thd, tables, &select_lex->item_list,
- select_lex))
+ if (check_multi_update_lock(thd))
goto error;
/* Fix for replication, the tables are opened and locked,
@@ -1972,11 +2303,11 @@ mysql_execute_command(THD *thd)
*/
if (!(lex->sql_command == SQLCOM_DROP_TABLE &&
lex->drop_temporary && lex->drop_if_exists) &&
- all_tables_not_ok(thd,tables))
+ all_tables_not_ok(thd, all_tables))
{
/* we warn the slave SQL thread */
- my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
- DBUG_VOID_RETURN;
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+ DBUG_RETURN(0);
}
#ifndef TO_BE_DELETED
/*
@@ -1992,10 +2323,6 @@ mysql_execute_command(THD *thd)
#endif
}
#endif /* !HAVE_REPLICATION */
- if ((&lex->select_lex != lex->all_selects_list ||
- lex->time_zone_tables_used) &&
- lex->unit.create_total_list(thd, lex, &tables))
- DBUG_VOID_RETURN;
/*
When option readonly is set deny operations which change tables.
@@ -2003,13 +2330,14 @@ mysql_execute_command(THD *thd)
*/
if (opt_readonly &&
!(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
- (uc_update_queries[lex->sql_command] > 0))
+ uc_update_queries[lex->sql_command])
{
- net_printf(thd, ER_OPTION_PREVENTS_STATEMENT, "--read-only");
- DBUG_VOID_RETURN;
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
+ DBUG_RETURN(-1);
}
- statistic_increment(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:
{
@@ -2021,43 +2349,26 @@ mysql_execute_command(THD *thd)
}
select_result *result=lex->result;
- if (tables)
+ if (all_tables)
{
- res=check_table_access(thd,
- lex->exchange ? SELECT_ACL | FILE_ACL :
- SELECT_ACL,
- tables,0);
+ res= check_table_access(thd,
+ lex->exchange ? SELECT_ACL | FILE_ACL :
+ SELECT_ACL,
+ all_tables, 0);
}
else
- res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
- any_db,0,0,0);
+ res= check_access(thd,
+ lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
+ any_db, 0, 0, 0);
if (res)
- {
- res=0;
- break; // Error message is given
- }
- /*
- In case of single SELECT unit->global_parameters points on first SELECT
- TODO: move counters to SELECT_LEX
- */
- unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit;
- unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+
- unit->global_parameters->offset_limit);
- if (unit->select_limit_cnt <
- (ha_rows) unit->global_parameters->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR; // no limit
- if (unit->select_limit_cnt == HA_POS_ERROR && !select_lex->next_select())
- select_lex->options&= ~OPTION_FOUND_ROWS;
+ goto error;
- if (!(res=open_and_lock_tables(thd,tables)))
+ if (!(res= open_and_lock_tables(thd, all_tables)))
{
if (lex->describe)
{
if (!(result= new select_send()))
- {
- send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_VOID_RETURN;
- }
+ goto error;
else
thd->send_explain_fields(result);
res= mysql_explain_union(thd, &thd->lex->unit, result);
@@ -2077,12 +2388,9 @@ mysql_execute_command(THD *thd)
else
{
if (!result && !(result= new select_send()))
- {
- res= -1;
- break;
- }
- query_cache_store_query(thd, tables);
- res= handle_select(thd, lex, result);
+ goto error;
+ query_cache_store_query(thd, all_tables);
+ res= handle_select(thd, lex, result, 0);
if (result != lex->result)
delete result;
}
@@ -2121,10 +2429,7 @@ mysql_execute_command(THD *thd)
*/
DBUG_ASSERT(!is_var_null);
if (!pstr)
- {
- res= -1;
- break; // EOM (error should be reported by allocator)
- }
+ goto error;
}
else
{
@@ -2142,11 +2447,8 @@ mysql_execute_command(THD *thd)
query_len= need_conversion? (pstr->length() * to_cs->mbmaxlen) :
pstr->length();
if (!(query_str= alloc_root(thd->mem_root, query_len+1)))
- {
- res= -1;
- break; // EOM (error should be reported by allocator)
- }
-
+ goto error;
+
if (need_conversion)
{
uint dummy_errors;
@@ -2168,8 +2470,8 @@ mysql_execute_command(THD *thd)
query_len, query_str));
}
thd->command= COM_PREPARE;
- if (!mysql_stmt_prepare(thd, query_str, query_len + 1,
- &lex->prepared_stmt_name))
+ if (!(res= mysql_stmt_prepare(thd, query_str, query_len + 1,
+ &lex->prepared_stmt_name)))
send_ok(thd, 0L, 0L, "Statement prepared");
break;
}
@@ -2195,21 +2497,20 @@ mysql_execute_command(THD *thd)
}
else
{
- res= -1;
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
- lex->prepared_stmt_name.length, lex->prepared_stmt_name.str,
+ lex->prepared_stmt_name.length,
+ lex->prepared_stmt_name.str,
"DEALLOCATE PREPARE");
+ goto error;
}
break;
}
case SQLCOM_DO:
- if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
- (res= open_and_lock_tables(thd,tables))))
- break;
+ if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
+ open_and_lock_tables(thd, all_tables))
+ goto error;
res= mysql_do(thd, *lex->insert_list);
- if (thd->net.report_error)
- res= -1;
break;
case SQLCOM_EMPTY_QUERY:
@@ -2225,16 +2526,31 @@ mysql_execute_command(THD *thd)
{
if (check_global_access(thd, SUPER_ACL))
goto error;
- // PURGE MASTER LOGS TO 'file'
+ /* PURGE MASTER LOGS TO 'file' */
res = purge_master_logs(thd, lex->to_log);
break;
}
case SQLCOM_PURGE_BEFORE:
{
+ Item *it;
+
if (check_global_access(thd, SUPER_ACL))
goto error;
- // PURGE MASTER LOGS BEFORE 'data'
- res = purge_master_logs_before_date(thd, lex->purge_time);
+ /* PURGE MASTER LOGS BEFORE 'data' */
+ it= (Item *)lex->value_list.head();
+ if ((!it->fixed &&it->fix_fields(lex->thd, 0, &it)) ||
+ it->check_cols(1))
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
+ goto error;
+ }
+ it= new Item_func_unix_timestamp(it);
+ /*
+ it is OK only emulate fix_fieds, because we need only
+ value of constant
+ */
+ it->quick_fix_field();
+ res = purge_master_logs_before_date(thd, (ulong)it->val_int());
break;
}
#endif
@@ -2259,12 +2575,12 @@ mysql_execute_command(THD *thd)
goto error;
/* This query don't work now. See comment in repl_failsafe.cc */
#ifndef WORKING_NEW_MASTER
- net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
- res= 1;
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
+ goto error;
#else
res = show_new_master(thd);
-#endif
break;
+#endif
}
#ifdef HAVE_REPLICATION
@@ -2279,48 +2595,52 @@ mysql_execute_command(THD *thd)
{
if (check_global_access(thd, REPL_SLAVE_ACL))
goto error;
- res = show_binlog_events(thd);
+ res = mysql_show_binlog_events(thd);
break;
}
#endif
case SQLCOM_BACKUP_TABLE:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL, tables,0) ||
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL, all_tables, 0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_backup_table(thd, tables);
+ res = mysql_backup_table(thd, first_table);
break;
}
case SQLCOM_RESTORE_TABLE:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd, INSERT_ACL, tables,0) ||
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, INSERT_ACL, all_tables, 0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_restore_table(thd, tables);
+ res = mysql_restore_table(thd, first_table);
break;
}
case SQLCOM_ASSIGN_TO_KEYCACHE:
{
- if (check_db_used(thd, tables) ||
- check_access(thd, INDEX_ACL, tables->db,
- &tables->grant.privilege, 0, 0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_access(thd, INDEX_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0))
goto error;
- res= mysql_assign_to_keycache(thd, tables, &lex->name_and_length);
+ res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
break;
}
case SQLCOM_PRELOAD_KEYS:
{
- if (check_db_used(thd, tables) ||
- check_access(thd, INDEX_ACL, tables->db,
- &tables->grant.privilege, 0, 0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_access(thd, INDEX_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0))
goto error;
- res = mysql_preload_keys(thd, tables);
+ res = mysql_preload_keys(thd, first_table);
break;
}
#ifdef HAVE_REPLICATION
@@ -2356,7 +2676,7 @@ mysql_execute_command(THD *thd)
if (check_global_access(thd, SUPER_ACL))
goto error;
if (end_active_trans(thd))
- res= -1;
+ goto error;
else
res = load_master_data(thd);
break;
@@ -2369,23 +2689,32 @@ mysql_execute_command(THD *thd)
res = innodb_show_status(thd);
break;
}
+ case SQLCOM_SHOW_MUTEX_STATUS:
+ {
+ if (check_global_access(thd, SUPER_ACL))
+ goto error;
+ res = innodb_mutex_show_status(thd);
+ break;
+ }
#endif
#ifdef HAVE_REPLICATION
case SQLCOM_LOAD_MASTER_TABLE:
{
- if (!tables->db)
- tables->db=thd->db;
- if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege,0,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (!first_table->db)
+ first_table->db= thd->db;
+ if (check_access(thd, CREATE_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0))
goto error; /* purecov: inspected */
if (grant_option)
{
/* Check that the first table has CREATE privilege */
- if (check_grant(thd, CREATE_ACL, tables, 0, 1, 0))
+ if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
goto error;
}
- if (strlen(tables->real_name) > NAME_LEN)
+ if (strlen(first_table->table_name) > NAME_LEN)
{
- net_printf(thd,ER_WRONG_TABLE_NAME, tables->real_name);
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), first_table->table_name);
break;
}
pthread_mutex_lock(&LOCK_active_mi);
@@ -2393,7 +2722,7 @@ mysql_execute_command(THD *thd)
fetch_master_table will send the error to the client on failure.
Give error if the table already exists.
*/
- if (!fetch_master_table(thd, tables->db, tables->real_name,
+ if (!fetch_master_table(thd, first_table->db, first_table->table_name,
active_mi, 0, 0))
{
send_ok(thd);
@@ -2405,12 +2734,13 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_TABLE:
{
- /* Skip first table, which is the table we are creating */
- TABLE_LIST *create_table, *create_table_local;
- tables= lex->unlink_first_table(tables, &create_table,
- &create_table_local);
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ bool link_to_local;
+ // Skip first table, which is the table we are creating
+ TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
+ TABLE_LIST *select_tables= lex->query_tables;
- if ((res= create_table_precheck(thd, tables, create_table)))
+ if ((res= create_table_precheck(thd, select_tables, create_table)))
goto unsent_create_error;
#ifndef HAVE_READLINK
@@ -2418,16 +2748,13 @@ mysql_execute_command(THD *thd)
#else
/* Fix names if symlinked tables */
if (append_file_to_dir(thd, &lex->create_info.data_file_name,
- create_table->real_name) ||
- append_file_to_dir(thd,&lex->create_info.index_file_name,
- create_table->real_name))
- {
- res=-1;
+ create_table->table_name) ||
+ append_file_to_dir(thd, &lex->create_info.index_file_name,
+ create_table->table_name))
goto unsent_create_error;
- }
#endif
/*
- If we are using SET CHARSET without DEFAULT, add an implicite
+ If we are using SET CHARSET without DEFAULT, add an implicit
DEFAULT to not confuse old users. (This may change).
*/
if ((lex->create_info.used_fields &
@@ -2444,72 +2771,91 @@ mysql_execute_command(THD *thd)
select_result *result;
select_lex->options|= SELECT_NO_UNLOCK;
- unit->offset_limit_cnt= select_lex->offset_limit;
- unit->select_limit_cnt= select_lex->select_limit+
- select_lex->offset_limit;
- if (unit->select_limit_cnt < select_lex->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR; // No limit
+ unit->set_limit(select_lex, select_lex);
- if (!(res=open_and_lock_tables(thd,tables)))
+ if (!(res= open_and_lock_tables(thd, select_tables)))
{
- res= -1; // If error
- if ((result=new select_create(create_table->db,
- create_table->real_name,
- &lex->create_info,
- lex->create_list,
- lex->key_list,
- select_lex->item_list, lex->duplicates,
- lex->ignore)))
+ /*
+ Is table which we are changing used somewhere in other parts
+ of query
+ */
+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
+ unique_table(create_table, select_tables))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table->table_name);
+ goto unsent_create_error;
+ }
+ /* If we create merge table, we have to test tables in merge, too */
+ if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
+ {
+ TABLE_LIST *tab;
+ for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
+ tab;
+ tab= tab->next_local)
+ {
+ if (unique_table(tab, select_tables))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), tab->table_name);
+ goto unsent_create_error;
+ }
+ }
+ }
+
+ if ((result= new select_create(create_table,
+ &lex->create_info,
+ lex->create_list,
+ lex->key_list,
+ select_lex->item_list,
+ lex->duplicates,
+ lex->ignore)))
{
/*
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);
+ res= handle_select(thd, lex, result, 0);
select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
+ delete result;
}
- //reset for PS
+ /* reset for PS */
lex->create_list.empty();
lex->key_list.empty();
}
}
- else // regular create
+ else
{
+ /* regular create */
if (lex->name)
res= mysql_create_like_table(thd, create_table, &lex->create_info,
(Table_ident *)lex->name);
else
{
- res= mysql_create_table(thd,create_table->db,
- create_table->real_name, &lex->create_info,
- lex->create_list,
- lex->key_list,0,0);
+ res= mysql_create_table(thd, create_table->db,
+ create_table->table_name, &lex->create_info,
+ lex->create_list,
+ lex->key_list, 0, 0);
}
if (!res)
send_ok(thd);
}
-
- // put tables back for PS rexecuting
- tables= lex->link_first_table_back(tables, create_table,
- create_table_local);
+ lex->link_first_table_back(create_table, link_to_local);
break;
- res= 1; //error reported
+ /* put tables back for PS rexecuting */
unsent_create_error:
- // put tables back for PS rexecuting
- tables= lex->link_first_table_back(tables, create_table,
- create_table_local);
- break;
+ lex->link_first_table_back(create_table, link_to_local);
+ goto error;
}
case SQLCOM_CREATE_INDEX:
- if (check_one_table_access(thd, INDEX_ACL, tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
if (end_active_trans(thd))
- res= -1;
+ goto error;
else
- res = mysql_create_index(thd, tables, lex->key_list);
+ res = mysql_create_index(thd, first_table, lex->key_list);
break;
#ifdef HAVE_REPLICATION
@@ -2536,8 +2882,9 @@ unsent_create_error:
*/
if (thd->locked_tables || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
- break;
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION),
+ MYF(0));
+ goto error;
}
{
pthread_mutex_lock(&LOCK_active_mi);
@@ -2548,35 +2895,37 @@ unsent_create_error:
#endif /* HAVE_REPLICATION */
case SQLCOM_ALTER_TABLE:
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
#if defined(DONT_ALLOW_SHOW_COMMANDS)
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- break;
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
+ goto error;
#else
{
ulong priv=0;
if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
{
- net_printf(thd, ER_WRONG_TABLE_NAME, lex->name);
- res= 1;
- break;
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
+ goto error;
}
if (!select_lex->db)
- select_lex->db=tables->db;
- if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege,0,0) ||
+ select_lex->db= first_table->db;
+ if (check_access(thd, ALTER_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0) ||
check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0)||
- check_merge_table_access(thd, tables->db,
+ check_merge_table_access(thd, first_table->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto error; /* purecov: inspected */
if (grant_option)
{
- if (check_grant(thd, ALTER_ACL, tables, 0, UINT_MAX, 0))
+ if (check_grant(thd, ALTER_ACL, all_tables, 0, UINT_MAX, 0))
goto error;
if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
{ // Rename of table
TABLE_LIST tmp_table;
bzero((char*) &tmp_table,sizeof(tmp_table));
- tmp_table.real_name=lex->name;
+ tmp_table.table_name=lex->name;
tmp_table.db=select_lex->db;
tmp_table.grant.privilege=priv;
if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
@@ -2588,63 +2937,62 @@ unsent_create_error:
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
/* ALTER TABLE ends previous transaction */
if (end_active_trans(thd))
- res= -1;
+ goto error;
else
{
thd->slow_command=TRUE;
res= mysql_alter_table(thd, select_lex->db, lex->name,
&lex->create_info,
- tables, lex->create_list,
+ first_table, lex->create_list,
lex->key_list,
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
- lex->duplicates, lex->ignore, &lex->alter_info);
+ lex->duplicates, lex->ignore, &lex->alter_info,
+ 1);
}
break;
}
#endif /*DONT_ALLOW_SHOW_COMMANDS*/
case SQLCOM_RENAME_TABLE:
{
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *table;
- if (check_db_used(thd,tables))
+ if (check_db_used(thd, all_tables))
goto error;
- for (table=tables ; table ; table=table->next->next)
+ for (table= first_table; table; table= table->next_local->next_local)
{
if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
&table->grant.privilege,0,0) ||
- check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
- &table->next->grant.privilege,0,0))
+ check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
+ &table->next_local->grant.privilege, 0, 0))
goto error;
if (grant_option)
{
- TABLE_LIST old_list,new_list;
+ TABLE_LIST old_list, new_list;
/*
we do not need initialize old_list and new_list because we will
come table[0] and table->next[0] there
*/
- old_list=table[0];
- new_list=table->next[0];
- old_list.next=new_list.next=0;
- if (check_grant(thd, ALTER_ACL, &old_list, 0, UINT_MAX, 0) ||
- (!test_all_bits(table->next->grant.privilege,
+ old_list= table[0];
+ new_list= table->next_local[0];
+ if (check_grant(thd, ALTER_ACL, &old_list, 0, 1, 0) ||
+ (!test_all_bits(table->next_local->grant.privilege,
INSERT_ACL | CREATE_ACL) &&
- check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0,
- UINT_MAX, 0)))
+ check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
goto error;
}
}
- query_cache_invalidate3(thd, tables, 0);
- if (end_active_trans(thd))
- res= -1;
- else if (mysql_rename_tables(thd,tables))
- res= -1;
+ query_cache_invalidate3(thd, first_table, 0);
+ if (end_active_trans(thd) || mysql_rename_tables(thd, first_table))
+ goto error;
break;
}
#ifndef EMBEDDED_LIBRARY
case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
+ goto error;
#else
{
if (check_global_access(thd, SUPER_ACL))
@@ -2655,40 +3003,47 @@ unsent_create_error:
#endif
#endif /* EMBEDDED_LIBRARY */
case SQLCOM_SHOW_CREATE:
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
+ goto error;
#else
{
- if (check_db_used(thd, tables) ||
- check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
- &tables->grant.privilege,0,0))
+ /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
+ if (lex->only_view)
+ first_table->skip_temporary= 1;
+
+ if (check_db_used(thd, all_tables) ||
+ check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
+ &first_table->grant.privilege, 0, 0))
goto error;
- if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
+ if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
goto error;
- res= mysqld_show_create(thd, tables);
+ res= mysqld_show_create(thd, first_table);
break;
}
#endif
case SQLCOM_CHECKSUM:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0))
goto error; /* purecov: inspected */
- res = mysql_checksum_table(thd, tables, &lex->check_opt);
+ res = mysql_checksum_table(thd, first_table, &lex->check_opt);
break;
}
case SQLCOM_REPAIR:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_repair_table(thd, tables, &lex->check_opt);
+ res= mysql_repair_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -2700,24 +3055,25 @@ unsent_create_error:
}
case SQLCOM_CHECK:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_check_table(thd, tables, &lex->check_opt);
+ res = mysql_check_table(thd, first_table, &lex->check_opt);
break;
}
case SQLCOM_ANALYZE:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
- res = mysql_analyze_table(thd, tables, &lex->check_opt);
+ res = mysql_analyze_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -2730,17 +3086,17 @@ unsent_create_error:
case SQLCOM_OPTIMIZE:
{
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0))
goto error; /* purecov: inspected */
thd->slow_command=TRUE;
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
- mysql_recreate_table(thd, tables, 1) :
- mysql_optimize_table(thd, tables, &lex->check_opt);
+ mysql_recreate_table(thd, first_table, 1) :
+ mysql_optimize_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -2751,173 +3107,149 @@ unsent_create_error:
break;
}
case SQLCOM_UPDATE:
- if (update_precheck(thd, tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (update_precheck(thd, all_tables))
break;
- res= mysql_update(thd,tables,
- select_lex->item_list,
- lex->value_list,
- select_lex->where,
- select_lex->order_list.elements,
- (ORDER *) select_lex->order_list.first,
- select_lex->select_limit,
- lex->duplicates, lex->ignore);
- if (thd->net.report_error)
- res= -1;
- break;
- case SQLCOM_UPDATE_MULTI:
- {
- if ((res= multi_update_precheck(thd, tables)))
+ res= (result= mysql_update(thd, all_tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ select_lex->order_list.elements,
+ (ORDER *) select_lex->order_list.first,
+ select_lex->select_limit,
+ lex->duplicates, lex->ignore));
+ /* mysql_update return 2 if we need to switch to multi-update */
+ if (result != 2)
break;
- res= mysql_multi_update(thd,tables,
- &select_lex->item_list,
- &lex->value_list,
- select_lex->where,
- select_lex->options,
- lex->duplicates, lex->ignore, unit, select_lex);
+ case SQLCOM_UPDATE_MULTI:
+ {
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ /* if we switched from normal update, rights are checked */
+ if (result != 2)
+ {
+ if ((res= multi_update_precheck(thd, all_tables)))
+ break;
+ }
+ else
+ res= 0;
+
+ res= mysql_multi_update(thd, all_tables,
+ &select_lex->item_list,
+ &lex->value_list,
+ select_lex->where,
+ select_lex->options,
+ lex->duplicates, lex->ignore, unit, select_lex);
break;
}
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
{
- if ((res= insert_precheck(thd, tables)))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if ((res= insert_precheck(thd, all_tables)))
break;
- res= mysql_insert(thd,tables,lex->field_list,lex->many_values,
- lex->update_list, lex->value_list,
+ res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
+ lex->update_list, lex->value_list,
lex->duplicates, lex->ignore);
- if (thd->net.report_error)
- res= -1;
+ 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_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
- TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first;
- if ((res= insert_precheck(thd, tables)))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if ((res= insert_precheck(thd, all_tables)))
break;
/* Fix lock for first table */
- if (tables->lock_type == TL_WRITE_DELAYED)
- tables->lock_type= TL_WRITE;
+ if (first_table->lock_type == TL_WRITE_DELAYED)
+ first_table->lock_type= TL_WRITE;
/* Don't unlock tables until command is written to binary log */
select_lex->options|= SELECT_NO_UNLOCK;
select_result *result;
- unit->offset_limit_cnt= select_lex->offset_limit;
- unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
- if (unit->select_limit_cnt < select_lex->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR; // No limit
+ unit->set_limit(select_lex, select_lex);
- if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
+ if (!(res= open_and_lock_tables(thd, all_tables)))
{
- /* Using same table for INSERT and SELECT */
- select_lex->options |= OPTION_BUFFER_RESULT;
- }
+ /* Skip first table, which is the table we are inserting in */
+ lex->select_lex.table_list.first= (byte*)first_table->next_local;
- if ((res= open_and_lock_tables(thd, tables)))
- break;
-
- TABLE *table= tables->table;
- /* Skip first table, which is the table we are inserting in */
- lex->select_lex.table_list.first= (byte*) first_local_table->next;
- tables= (TABLE_LIST *) lex->select_lex.table_list.first;
- first_local_table->next= 0;
-
- if (!(res= mysql_prepare_insert(thd, tables, first_local_table,
- table, lex->field_list, 0,
- lex->update_list, lex->value_list,
- lex->duplicates)) &&
- (result= new select_insert(table, &lex->field_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
- */
- lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
- res= handle_select(thd, lex, result);
+ res= mysql_insert_select_prepare(thd);
+ if (!res && (result= new select_insert(first_table, first_table->table,
+ &lex->field_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
+ */
+ lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
+ res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
+ lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
+ delete result;
+ }
/* revert changes for SP */
- lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
- delete result;
- table->insert_values= 0;
- if (thd->net.report_error)
- res= -1;
+ lex->select_lex.table_list.first= (byte*) first_table;
}
- else
- res= -1;
- first_local_table->next= tables;
- lex->select_lex.table_list.first= (byte*) first_local_table;
+
+ 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:
- if (check_one_table_access(thd, DELETE_ACL, tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_one_table_access(thd, DELETE_ACL, all_tables))
goto error;
/*
Don't allow this within a transaction because we want to use
re-generate table
*/
- if (thd->locked_tables || thd->active_transaction())
+ if ((thd->locked_tables && !lex->sphead) || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res=mysql_truncate(thd, tables, 0);
+
+ res= mysql_truncate(thd, first_table, 0);
break;
case SQLCOM_DELETE:
{
- if ((res= delete_precheck(thd, tables)))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if ((res= delete_precheck(thd, all_tables)))
break;
- res = mysql_delete(thd,tables, select_lex->where,
+ res = mysql_delete(thd, all_tables, select_lex->where,
&select_lex->order_list,
select_lex->select_limit, select_lex->options);
- if (thd->net.report_error)
- res= -1;
break;
}
case SQLCOM_DELETE_MULTI:
{
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
- TABLE_LIST *target_tbl;
uint table_count;
multi_delete *result;
- if ((res= multi_delete_precheck(thd, tables, &table_count)))
+ if ((res= multi_delete_precheck(thd, all_tables, &table_count)))
break;
/* condition will be TRUE on SP re-excuting */
if (select_lex->item_list.elements != 0)
select_lex->item_list.empty();
if (add_item_to_list(thd, new Item_null()))
- {
- res= -1;
- break;
- }
+ goto error;
thd->proc_info="init";
- if ((res=open_and_lock_tables(thd,tables)))
+ if ((res= open_and_lock_tables(thd, all_tables)))
break;
- /* Fix tables-to-be-deleted-from list to point at opened tables */
- for (target_tbl= (TABLE_LIST*) aux_tables;
- target_tbl;
- target_tbl= target_tbl->next)
- {
- TABLE_LIST *orig= target_tbl->table_list;
- target_tbl->table= orig->table;
- /*
- Multi-delete can't be constructed over-union => we always have
- single SELECT on top and have to check underlying SELECTs of it
- */
- if (lex->select_lex.check_updateable_in_subqueries(orig->db,
- orig->real_name))
- {
- my_error(ER_UPDATE_TABLE_USED, MYF(0),
- orig->real_name);
- res= -1;
- break;
- }
- }
+
+ if ((res= mysql_multi_delete_prepare(thd)))
+ goto error;
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
table_count)))
@@ -2930,28 +3262,24 @@ unsent_create_error:
0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
- SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
+ SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
+ OPTION_SETUP_TABLES_DONE,
result, unit, select_lex);
- if (thd->net.report_error)
- res= -1;
delete result;
}
else
- res= -1; // Error is not sent
- close_thread_tables(thd);
+ res= TRUE; // Error
break;
}
case SQLCOM_DROP_TABLE:
{
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (!lex->drop_temporary)
{
- if (check_table_access(thd,DROP_ACL,tables,0))
+ if (check_table_access(thd, DROP_ACL, all_tables, 0))
goto error; /* purecov: inspected */
if (end_active_trans(thd))
- {
- res= -1;
- break;
- }
+ goto error;
}
else
{
@@ -2966,28 +3294,19 @@ unsent_create_error:
if (thd->slave_thread)
lex->drop_if_exists= 1;
}
- res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
+ res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
+ lex->drop_temporary);
}
break;
case SQLCOM_DROP_INDEX:
- if (check_one_table_access(thd, INDEX_ACL, tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
if (end_active_trans(thd))
- res= -1;
- else
- res = mysql_drop_index(thd, tables, &lex->alter_info);
- break;
- case SQLCOM_SHOW_DATABASES:
-#if defined(DONT_ALLOW_SHOW_COMMANDS)
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
-#else
- if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
- check_global_access(thd, SHOW_DB_ACL))
goto error;
- res= mysqld_show_dbs(thd, (lex->wild ? lex->wild->ptr() : NullS));
+ else
+ res = mysql_drop_index(thd, first_table, &lex->alter_info);
break;
-#endif
case SQLCOM_SHOW_PROCESSLIST:
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
@@ -3004,19 +3323,11 @@ unsent_create_error:
case SQLCOM_SHOW_COLUMN_TYPES:
res= mysqld_show_column_types(thd);
break;
- case SQLCOM_SHOW_STATUS:
- res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
- OPT_GLOBAL, &LOCK_status);
- break;
- case SQLCOM_SHOW_VARIABLES:
- res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
- init_vars, lex->option_type,
- &LOCK_global_system_variables);
- break;
case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND),
+ MYF(0)); /* purecov: inspected */
+ goto error;
#else
{
if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0))
@@ -3025,134 +3336,46 @@ unsent_create_error:
break;
}
#endif
- case SQLCOM_SHOW_TABLES:
- /* FALL THROUGH */
-#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
-#else
- {
- char *db=select_lex->db ? select_lex->db : thd->db;
- if (!db)
- {
- send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
- goto error; /* purecov: inspected */
- }
- remove_escape(db); // Fix escaped '_'
- if (check_db_name(db))
- {
- net_printf(thd,ER_WRONG_DB_NAME, db);
- goto error;
- }
- if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
- goto error; /* purecov: inspected */
- if (!thd->col_access && check_grant_db(thd,db))
- {
- net_printf(thd, ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->priv_host,
- db);
- goto error;
- }
- /* grant is checked in mysqld_show_tables */
- if (lex->describe)
- res= mysqld_extend_show_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
- else
- res= mysqld_show_tables(thd,db,
- (lex->wild ? lex->wild->ptr() : NullS));
- break;
- }
-#endif
- case SQLCOM_SHOW_OPEN_TABLES:
- res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
- break;
- case SQLCOM_SHOW_CHARSETS:
- res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
- break;
- case SQLCOM_SHOW_COLLATIONS:
- res= mysqld_show_collations(thd,(lex->wild ? lex->wild->ptr() : NullS));
- break;
- case SQLCOM_SHOW_FIELDS:
-#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
-#else
- {
- char *db=tables->db;
- remove_escape(db); // Fix escaped '_'
- remove_escape(tables->real_name);
- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
- &tables->grant.privilege, 0, 0))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
- goto error;
- res= mysqld_show_fields(thd,tables,
- (lex->wild ? lex->wild->ptr() : NullS),
- lex->verbose);
- break;
- }
-#endif
- case SQLCOM_SHOW_KEYS:
-#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
-#else
- {
- char *db=tables->db;
- remove_escape(db); // Fix escaped '_'
- remove_escape(tables->real_name);
- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
- &tables->grant.privilege, 0, 0))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0))
- goto error;
- res= mysqld_show_keys(thd,tables);
- break;
- }
-#endif
case SQLCOM_CHANGE_DB:
mysql_change_db(thd,select_lex->db);
break;
case SQLCOM_LOAD:
{
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
uint privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL);
+ INSERT_ACL | DELETE_ACL : INSERT_ACL) |
+ (lex->local_file ? 0 : FILE_ACL);
- if (!lex->local_file)
- {
- if (check_access(thd,privilege | FILE_ACL,tables->db,0,0,0))
- goto error;
- }
- else
+ if (lex->local_file)
{
if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
! opt_local_infile)
{
- send_error(thd,ER_NOT_ALLOWED_COMMAND);
+ my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0));
goto error;
}
- if (check_one_table_access(thd, privilege, tables))
- goto error;
}
- res=mysql_load(thd, lex->exchange, tables, lex->field_list,
- lex->duplicates, lex->ignore, (bool) lex->local_file, lex->lock_option);
+
+ if (check_one_table_access(thd, privilege, all_tables))
+ goto error;
+
+ res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
+ lex->update_list, lex->value_list, lex->duplicates,
+ lex->ignore, (bool) lex->local_file);
break;
}
case SQLCOM_SET_OPTION:
{
List<set_var_base> *lex_var_list= &lex->var_list;
- if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
- (res= open_and_lock_tables(thd,tables))))
- break;
+ if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
+ open_and_lock_tables(thd, all_tables)))
+ goto error;
if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
{
- my_printf_error(0, "The SET ONE_SHOT syntax is reserved for \
-purposes internal to the MySQL server", MYF(0));
- res= -1;
- break;
+ my_error(ER_RESERVED_SYNTAX, MYF(0), "SET ONE_SHOT");
+ goto error;
}
if (!(res= sql_set_variables(thd, lex_var_list)))
{
@@ -3163,8 +3386,6 @@ purposes internal to the MySQL server", MYF(0));
thd->one_shot_set|= lex->one_shot_set;
send_ok(thd);
}
- if (thd->net.report_error)
- res= -1;
break;
}
@@ -3187,17 +3408,18 @@ purposes internal to the MySQL server", MYF(0));
break;
case SQLCOM_LOCK_TABLES:
unlock_locked_tables(thd);
- if (check_db_used(thd,tables) || end_active_trans(thd))
+ if (check_db_used(thd, all_tables) || end_active_trans(thd))
goto error;
- if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables,0))
+ if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
goto error;
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
- if (!(res= open_and_lock_tables(thd, tables)))
+
+ if (!(res= simple_open_n_lock_tables(thd, all_tables)))
{
#ifdef HAVE_QUERY_CACHE
if (thd->variables.query_cache_wlock_invalidate)
- query_cache.invalidate_locked_for_write(tables);
+ query_cache.invalidate_locked_for_write(first_table);
#endif /*HAVE_QUERY_CACHE*/
thd->locked_tables=thd->lock;
thd->lock=0;
@@ -3212,22 +3434,22 @@ purposes internal to the MySQL server", MYF(0));
char *alias;
if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
{
- net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
break;
}
/*
If in a slave thread :
CREATE DATABASE DB was certainly not preceded by USE DB.
- For that reason, db_ok() in sql/slave.cc did not check the
+ For that reason, db_ok() in sql/slave.cc did not check the
do_db/ignore_db. And as this query involves no tables, tables_ok()
above was not called. So we have to check rules again here.
*/
#ifdef HAVE_REPLICATION
- if (thd->slave_thread &&
+ if (thd->slave_thread &&
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
{
- my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
@@ -3239,10 +3461,9 @@ purposes internal to the MySQL server", MYF(0));
}
case SQLCOM_DROP_DB:
{
- char *alias;
- if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name))
+ if (check_db_name(lex->name))
{
- net_printf(thd, ER_WRONG_DB_NAME, lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
break;
}
/*
@@ -3257,7 +3478,7 @@ purposes internal to the MySQL server", MYF(0));
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
{
- my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
@@ -3265,11 +3486,11 @@ purposes internal to the MySQL server", MYF(0));
break;
if (thd->locked_tables || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res=mysql_rm_db(thd, (lower_case_table_names == 2 ? alias : lex->name),
- lex->drop_if_exists, 0);
+ res= mysql_rm_db(thd, lex->name, lex->drop_if_exists, 0);
break;
}
case SQLCOM_ALTER_DB:
@@ -3277,12 +3498,12 @@ purposes internal to the MySQL server", MYF(0));
char *db= lex->name ? lex->name : thd->db;
if (!db)
{
- send_error(thd, ER_NO_DB_ERROR);
- goto error;
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ break;
}
if (!strip_sp(db) || check_db_name(db))
{
- net_printf(thd, ER_WRONG_DB_NAME, db);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
break;
}
/*
@@ -3297,7 +3518,7 @@ purposes internal to the MySQL server", MYF(0));
(!db_ok(db, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(db)))
{
- my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
break;
}
#endif
@@ -3305,7 +3526,8 @@ purposes internal to the MySQL server", MYF(0));
break;
if (thd->locked_tables || thd->active_transaction())
{
- send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
res= mysql_alter_db(thd, db, &lex->create_info);
@@ -3315,7 +3537,7 @@ purposes internal to the MySQL server", MYF(0));
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
break;
}
if (check_access(thd,SELECT_ACL,lex->name,0,1,0))
@@ -3323,38 +3545,67 @@ purposes internal to the MySQL server", MYF(0));
res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
break;
}
- case SQLCOM_CREATE_FUNCTION:
+ case SQLCOM_CREATE_FUNCTION: // UDF function
+ {
if (check_access(thd,INSERT_ACL,"mysql",0,1,0))
break;
#ifdef HAVE_DLOPEN
- if (!(res = mysql_create_function(thd,&lex->udf)))
+ if (sp_find_function(thd, lex->spname))
+ {
+ my_error(ER_UDF_EXISTS, MYF(0), lex->spname->m_name.str);
+ goto error;
+ }
+ if (!(res = mysql_create_function(thd, &lex->udf)))
send_ok(thd);
#else
- res= -1;
+ res= TRUE;
#endif
break;
- case SQLCOM_DROP_FUNCTION:
- if (check_access(thd,DELETE_ACL,"mysql",0,1,0))
+ }
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ case SQLCOM_CREATE_USER:
+ {
+ if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1) &&
+ check_global_access(thd,CREATE_USER_ACL))
break;
-#ifdef HAVE_DLOPEN
- if (!(res = mysql_drop_function(thd,&lex->udf.name)))
+ if (!(res= mysql_create_user(thd, lex->users_list)))
+ {
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
send_ok(thd);
-#else
- res= -1;
-#endif
+ }
break;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ }
case SQLCOM_DROP_USER:
{
- if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
+ if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1) &&
+ check_global_access(thd,CREATE_USER_ACL))
break;
if (!(res= mysql_drop_user(thd, lex->users_list)))
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(thd);
+ }
+ break;
+ }
+ case SQLCOM_RENAME_USER:
+ {
+ if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1) &&
+ check_global_access(thd,CREATE_USER_ACL))
+ break;
+ if (!(res= mysql_rename_user(thd, lex->users_list)))
+ {
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
}
send_ok(thd);
}
@@ -3362,11 +3613,11 @@ purposes internal to the MySQL server", MYF(0));
}
case SQLCOM_REVOKE_ALL:
{
- if (check_access(thd, GRANT_ACL ,"mysql",0,1,0))
+ if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1) &&
+ check_global_access(thd,CREATE_USER_ACL))
break;
if (!(res = mysql_revoke_all(thd, lex->users_list)))
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
@@ -3380,95 +3631,99 @@ purposes internal to the MySQL server", MYF(0));
case SQLCOM_GRANT:
{
if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
- tables ? tables->db : select_lex->db,
- tables ? &tables->grant.privilege : 0,
- tables ? 0 : 1, 0))
+ first_table ? first_table->db : select_lex->db,
+ first_table ? &first_table->grant.privilege : 0,
+ first_table ? 0 : 1, 0))
goto error;
- /*
- Check that the user isn't trying to change a password for another
- user if he doesn't have UPDATE privilege to the MySQL database
- */
-
if (thd->user) // If not replication
{
LEX_USER *user;
+ uint counter;
+
List_iterator <LEX_USER> user_list(lex->users_list);
- while ((user=user_list++))
+ while ((user= user_list++))
{
- if (user->password.str &&
- (strcmp(thd->user,user->user.str) ||
- user->host.str &&
- my_strcasecmp(&my_charset_latin1,
- user->host.str, thd->host_or_ip)))
- {
- if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1))
- {
- send_error(thd, ER_PASSWORD_NOT_ALLOWED);
- goto error;
- }
- break; // We are allowed to do global changes
- }
+ if (specialflag & SPECIAL_NO_RESOLVE &&
+ hostname_requires_resolving(user->host.str))
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_HOSTNAME_WONT_WORK,
+ ER(ER_WARN_HOSTNAME_WONT_WORK),
+ user->host.str);
+ // Are we trying to change a password of another user
+ DBUG_ASSERT(user->host.str != 0);
+ if (strcmp(thd->user, user->user.str) ||
+ my_strcasecmp(system_charset_info,
+ user->host.str, thd->host_or_ip))
+ {
+ // TODO: use check_change_password()
+ if (check_acl_user(user, &counter) && user->password.str &&
+ check_access(thd, UPDATE_ACL,"mysql",0,1,1))
+ {
+ my_message(ER_PASSWORD_NOT_ALLOWED,
+ ER(ER_PASSWORD_NOT_ALLOWED), MYF(0));
+ goto error;
+ }
+ }
}
}
- if (specialflag & SPECIAL_NO_RESOLVE)
+ if (first_table)
{
- LEX_USER *user;
- List_iterator <LEX_USER> user_list(lex->users_list);
- while ((user=user_list++))
+ if (!lex->columns.elements &&
+ sp_exists_routine(thd, all_tables, 1, 1))
{
- if (hostname_requires_resolving(user->host.str))
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_HOSTNAME_WONT_WORK,
- ER(ER_WARN_HOSTNAME_WONT_WORK),
- user->host.str);
+ uint grants= lex->all_privileges
+ ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
+ : lex->grant;
+ if (grant_option &&
+ check_grant_procedure(thd, grants | GRANT_ACL, all_tables, 0))
+ goto error;
+ res= mysql_procedure_grant(thd, all_tables, lex->users_list,
+ grants, lex->sql_command == SQLCOM_REVOKE,0);
}
- }
- if (tables)
- {
- if (grant_option && check_grant(thd,
- (lex->grant | lex->grant_tot_col |
- GRANT_ACL),
- tables, 0, UINT_MAX, 0))
- goto error;
- if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
- lex->grant,
- lex->sql_command == SQLCOM_REVOKE)))
+ else
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ if (grant_option && check_grant(thd,
+ (lex->grant | lex->grant_tot_col |
+ GRANT_ACL),
+ all_tables, 0, UINT_MAX, 0))
+ goto error;
+ res= mysql_table_grant(thd, all_tables, lex->users_list,
+ lex->columns, lex->grant,
+ lex->sql_command == SQLCOM_REVOKE);
+ }
+ if (!res && mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
}
}
else
{
if (lex->columns.elements)
{
- send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
- res=1;
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
+ MYF(0));
+ goto error;
}
else
res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
lex->sql_command == SQLCOM_REVOKE);
if (!res)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
- if (mqh_used && lex->sql_command == SQLCOM_GRANT)
+ if (lex->sql_command == SQLCOM_GRANT)
{
List_iterator <LEX_USER> str_list(lex->users_list);
LEX_USER *user;
while ((user=str_list++))
- reset_mqh(thd,user);
+ reset_mqh(user);
}
}
}
@@ -3476,23 +3731,21 @@ purposes internal to the MySQL server", MYF(0));
}
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
case SQLCOM_RESET:
- /*
- RESET commands are never written to the binary log, so we have to
- initialize this variable because RESET shares the same code as FLUSH
+ /*
+ RESET commands are never written to the binary log, so we have to
+ initialize this variable because RESET shares the same code as FLUSH
*/
lex->no_write_to_binlog= 1;
case SQLCOM_FLUSH:
{
- if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
+ if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, all_tables))
goto error;
/*
reload_acl_and_cache() will tell us if we are allowed to write to the
binlog or not.
*/
bool write_to_binlog;
- if (reload_acl_and_cache(thd, lex->type, tables, &write_to_binlog))
- send_error(thd, 0);
- else
+ if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
{
/*
We WANT to write and we CAN write.
@@ -3500,7 +3753,6 @@ purposes internal to the MySQL server", MYF(0));
*/
if (!lex->no_write_to_binlog && write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
@@ -3512,11 +3764,20 @@ purposes internal to the MySQL server", MYF(0));
break;
}
case SQLCOM_KILL:
- kill_one_thread(thd,lex->thread_id);
+ {
+ Item *it= (Item *)lex->value_list.head();
+
+ if ((!it->fixed && it->fix_fields(lex->thd, 0, &it)) || it->check_cols(1))
+ {
+ my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
+ MYF(0));
+ goto error;
+ }
+ kill_one_thread(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
break;
+ }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_SHOW_GRANTS:
- res=0;
if ((thd->priv_user &&
!strcmp(thd->priv_user,lex->grant_user->user.str)) ||
!check_access(thd, SELECT_ACL, "mysql",0,1,0))
@@ -3526,111 +3787,714 @@ purposes internal to the MySQL server", MYF(0));
break;
#endif
case SQLCOM_HA_OPEN:
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL, tables,0))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables) ||
+ check_table_access(thd, SELECT_ACL, all_tables, 0))
goto error;
- res = mysql_ha_open(thd, tables);
+ res= mysql_ha_open(thd, first_table, 0);
break;
case SQLCOM_HA_CLOSE:
- if (check_db_used(thd,tables))
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ if (check_db_used(thd, all_tables))
goto error;
- res = mysql_ha_close(thd, tables);
+ res= mysql_ha_close(thd, first_table);
break;
case SQLCOM_HA_READ:
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
/*
There is no need to check for table permissions here, because
if a user has no permissions to read a table, he won't be
able to open it (with SQLCOM_HA_OPEN) in the first place.
*/
- if (check_db_used(thd,tables))
+ if (check_db_used(thd, all_tables))
goto error;
- res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
- lex->insert_list, lex->ha_rkey_mode, select_lex->where,
- select_lex->select_limit, select_lex->offset_limit);
+ res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
+ lex->insert_list, lex->ha_rkey_mode, select_lex->where,
+ select_lex->select_limit, select_lex->offset_limit);
break;
case SQLCOM_BEGIN:
- if (thd->locked_tables)
+ if (begin_trans(thd))
+ goto error;
+ send_ok(thd);
+ break;
+ case SQLCOM_COMMIT:
+ if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
+ lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
+ goto error;
+ send_ok(thd);
+ break;
+ case SQLCOM_ROLLBACK:
+ if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
+ lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
+ goto error;
+ send_ok(thd);
+ break;
+ case SQLCOM_RELEASE_SAVEPOINT:
+ {
+ SAVEPOINT *sv;
+ for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
{
- thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automaticly closed
- close_thread_tables(thd); // Free tables
+ if (my_strnncoll(system_charset_info,
+ (uchar *)lex->ident.str, lex->ident.length,
+ (uchar *)sv->name, sv->length) == 0)
+ break;
}
- if (end_active_trans(thd))
+ if (sv)
{
- res= -1;
+ if (ha_release_savepoint(thd, sv))
+ res= TRUE; // cannot happen
+ else
+ send_ok(thd);
+ thd->transaction.savepoints=sv->prev;
}
else
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
+ break;
+ }
+ case SQLCOM_ROLLBACK_TO_SAVEPOINT:
+ {
+ SAVEPOINT *sv;
+ for (sv=thd->transaction.savepoints; sv; sv=sv->prev)
{
- thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
- OPTION_BEGIN);
- thd->server_status|= SERVER_STATUS_IN_TRANS;
- if (!(lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) ||
- !(res= ha_start_consistent_snapshot(thd)))
+ if (my_strnncoll(system_charset_info,
+ (uchar *)lex->ident.str, lex->ident.length,
+ (uchar *)sv->name, sv->length) == 0)
+ break;
+ }
+ if (sv)
+ {
+ if (ha_rollback_to_savepoint(thd, sv))
+ res= TRUE; // cannot happen
+ else
+ {
+ if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ !thd->slave_thread)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARNING_NOT_COMPLETE_ROLLBACK,
+ ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
send_ok(thd);
+ }
+ thd->transaction.savepoints=sv;
}
+ else
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
break;
- case SQLCOM_COMMIT:
- /*
- We don't use end_active_trans() here to ensure that this works
- even if there is a problem with the OPTION_AUTO_COMMIT flag
- (Which of course should never happen...)
- */
+ }
+ case SQLCOM_SAVEPOINT:
+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) ||
+ !opt_using_transactions)
+ send_ok(thd);
+ else
+ {
+ SAVEPOINT **sv, *newsv;
+ for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
+ {
+ if (my_strnncoll(system_charset_info,
+ (uchar *)lex->ident.str, lex->ident.length,
+ (uchar *)(*sv)->name, (*sv)->length) == 0)
+ break;
+ }
+ if (*sv) /* old savepoint of the same name exists */
+ {
+ newsv=*sv;
+ ha_release_savepoint(thd, *sv); // it cannot fail
+ *sv=(*sv)->prev;
+ }
+ else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
+ savepoint_alloc_size)) == 0)
+ {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ break;
+ }
+ newsv->name=strmake_root(&thd->transaction.mem_root,
+ lex->ident.str, lex->ident.length);
+ newsv->length=lex->ident.length;
+ /*
+ if we'll get an error here, don't add new savepoint to the list.
+ we'll lose a little bit of memory in transaction mem_root, but it'll
+ be free'd when transaction ends anyway
+ */
+ if (ha_savepoint(thd, newsv))
+ res= TRUE;
+ else
+ {
+ newsv->prev=thd->transaction.savepoints;
+ thd->transaction.savepoints=newsv;
+ send_ok(thd);
+ }
+ }
+ break;
+ case SQLCOM_CREATE_PROCEDURE:
+ case SQLCOM_CREATE_SPFUNCTION:
{
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (!ha_commit(thd))
+ uint namelen;
+ char *name, *db;
+ int result;
+
+ DBUG_ASSERT(lex->sphead != 0);
+
+ if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0))
+ {
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ }
+
+ if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0])
+ {
+ lex->sphead->m_db.length= strlen(thd->db);
+ lex->sphead->m_db.str= strmake_root(thd->mem_root, thd->db,
+ lex->sphead->m_db.length);
+ }
+
+ name= lex->sphead->name(&namelen);
+#ifdef HAVE_DLOPEN
+ if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
{
+ udf_func *udf = find_udf(name, namelen);
+
+ if (udf)
+ {
+ my_error(ER_UDF_EXISTS, MYF(0), name);
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ }
+ }
+#endif
+ if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
+ !lex->sphead->m_has_return)
+ {
+ my_error(ER_SP_NORETURN, MYF(0), name);
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ }
+
+ name= thd->strdup(name);
+ db= thd->strmake(lex->sphead->m_db.str, lex->sphead->m_db.length);
+ res= (result= lex->sphead->create(thd));
+ switch (result) {
+ case SP_OK:
+ lex->unit.cleanup();
+ delete lex->sphead;
+ lex->sphead= 0;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* only add privileges if really neccessary */
+ if (sp_automatic_privileges &&
+ check_procedure_access(thd, DEFAULT_CREATE_PROC_ACLS,
+ db, name, 1))
+ {
+ close_thread_tables(thd);
+ if (sp_grant_privileges(thd, db, name))
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_PROC_AUTO_GRANT_FAIL,
+ ER(ER_PROC_AUTO_GRANT_FAIL));
+ }
+#endif
send_ok(thd);
+ break;
+ case SP_WRITE_ROW_FAILED:
+ my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name);
+ lex->unit.cleanup();
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ case SP_NO_DB_ERROR:
+ my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str);
+ lex->unit.cleanup();
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
+ default:
+ my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name);
+ lex->unit.cleanup();
+ delete lex->sphead;
+ lex->sphead= 0;
+ goto error;
}
- else
- res= -1;
break;
}
- case SQLCOM_ROLLBACK:
- thd->server_status&= ~SERVER_STATUS_IN_TRANS;
- if (!ha_rollback(thd))
+ case SQLCOM_CALL:
{
+ sp_head *sp;
+
/*
- If a non-transactional table was updated, warn; don't warn if this is a
- slave thread (because when a slave thread executes a ROLLBACK, it has
- been read from the binary log, so it's 100% sure and normal to produce
- error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
- slave SQL thread, it would not stop the thread but just be printed in
- the error log; but we don't want users to wonder why they have this
- message in the error log, so we don't send it.
+ This will cache all SP and SF and open and lock all tables
+ required for execution.
*/
- if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
- send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
+ if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
+ open_and_lock_tables(thd, all_tables))
+ goto error;
+
+ /*
+ By this moment all needed SPs should be in cache so no need
+ to look into DB. Moreover we may be unable to do it becuase
+ we may don't have read lock on mysql.proc
+ */
+ if (!(sp= sp_find_procedure(thd, lex->spname, TRUE)))
+ {
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
+ lex->spname->m_qname.str);
+ goto error;
+ }
+ else
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ st_sp_security_context save_ctx;
+#endif
+ ha_rows select_limit;
+ /* bits that should be cleared in thd->server_status */
+ uint bits_to_be_cleared= 0;
+
+#ifndef EMBEDDED_LIBRARY
+ my_bool nsok= thd->net.no_send_ok;
+ thd->net.no_send_ok= TRUE;
+#endif
+ if (sp->m_multi_results)
+ {
+ if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
+ {
+ my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ goto error;
+ }
+ /*
+ If SERVER_MORE_RESULTS_EXISTS is not set,
+ then remember that it should be cleared
+ */
+ bits_to_be_cleared= (~thd->server_status &
+ SERVER_MORE_RESULTS_EXISTS);
+ thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
+ }
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_procedure_access(thd, EXECUTE_ACL,
+ sp->m_db.str, sp->m_name.str, 0))
+ {
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ goto error;
+ }
+ sp_change_security_context(thd, sp, &save_ctx);
+ if (save_ctx.changed &&
+ check_procedure_access(thd, EXECUTE_ACL,
+ sp->m_db.str, sp->m_name.str, 0))
+ {
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ sp_restore_security_context(thd, sp, &save_ctx);
+ goto error;
+ }
+
+#endif
+ select_limit= thd->variables.select_limit;
+ thd->variables.select_limit= HA_POS_ERROR;
+
+ thd->row_count_func= 0;
+ res= sp->execute_procedure(thd, &lex->value_list);
+
+ /*
+ If warnings have been cleared, we have to clear total_warn_count
+ too, otherwise the clients get confused.
+ */
+ if (thd->warn_list.is_empty())
+ thd->total_warn_count= 0;
+
+ thd->variables.select_limit= select_limit;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ sp_restore_security_context(thd, sp, &save_ctx);
+#endif
+
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ thd->server_status&= ~bits_to_be_cleared;
+
+ if (!res)
+ send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
+ thd->row_count_func));
+ else
+ goto error; // Substatement should already have sent error
+ }
+ break;
+ }
+ case SQLCOM_ALTER_PROCEDURE:
+ case SQLCOM_ALTER_FUNCTION:
+ {
+ int result;
+ sp_head *sp;
+ st_sp_chistics chistics;
+
+ memcpy(&chistics, &lex->sp_chistics, sizeof(chistics));
+ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
+ sp= sp_find_procedure(thd, lex->spname);
else
+ sp= sp_find_function(thd, lex->spname);
+ mysql_reset_errors(thd, 0);
+ if (! sp)
+ {
+ if (lex->spname->m_db.str)
+ result= SP_KEY_NOT_FOUND;
+ else
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ goto error;
+ }
+ }
+ else
+ {
+ if (check_procedure_access(thd, ALTER_PROC_ACL, sp->m_db.str,
+ sp->m_name.str, 0))
+ goto error;
+ memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
+ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
+ result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
+ else
+ result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
+ }
+ switch (result)
+ {
+ case SP_OK:
send_ok(thd);
+ break;
+ case SP_KEY_NOT_FOUND:
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_qname.str);
+ goto error;
+ default:
+ my_error(ER_SP_CANT_ALTER, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_qname.str);
+ goto error;
+ }
+ break;
+ }
+ case SQLCOM_DROP_PROCEDURE:
+ case SQLCOM_DROP_FUNCTION:
+ {
+ sp_head *sp;
+ int result;
+ char *db, *name;
+
+ if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
+ sp= sp_find_procedure(thd, lex->spname);
+ else
+ sp= sp_find_function(thd, lex->spname);
+ mysql_reset_errors(thd, 0);
+ if (sp)
+ {
+ db= thd->strdup(sp->m_db.str);
+ name= thd->strdup(sp->m_name.str);
+ if (check_procedure_access(thd, ALTER_PROC_ACL, db, name, 0))
+ goto error;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (sp_automatic_privileges &&
+ sp_revoke_privileges(thd, db, name))
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_PROC_AUTO_REVOKE_FAIL,
+ ER(ER_PROC_AUTO_REVOKE_FAIL));
+ }
+#endif
+ if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
+ result= sp_drop_procedure(thd, lex->spname);
+ else
+ result= sp_drop_function(thd, lex->spname);
+ }
+ else
+ {
+#ifdef HAVE_DLOPEN
+ if (lex->sql_command == SQLCOM_DROP_FUNCTION)
+ {
+ udf_func *udf = find_udf(lex->spname->m_name.str,
+ lex->spname->m_name.length);
+ if (udf)
+ {
+ if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0))
+ goto error;
+ if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
+ {
+ send_ok(thd);
+ break;
+ }
+ }
+ }
+#endif
+ if (lex->spname->m_db.str)
+ result= SP_KEY_NOT_FOUND;
+ else
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ goto error;
+ }
+ }
+ res= result;
+ switch (result)
+ {
+ case SP_OK:
+ send_ok(thd);
+ break;
+ case SP_KEY_NOT_FOUND:
+ if (lex->drop_if_exists)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
+ SP_COM_STRING(lex), lex->spname->m_name.str);
+ res= FALSE;
+ send_ok(thd);
+ break;
+ }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_qname.str);
+ goto error;
+ default:
+ my_error(ER_SP_DROP_FAILED, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_qname.str);
+ goto error;
+ }
+ break;
+ }
+ case SQLCOM_SHOW_CREATE_PROC:
+ {
+ if (lex->spname->m_name.length > NAME_LEN)
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
+ goto error;
+ }
+ if (sp_show_create_procedure(thd, lex->spname) != SP_OK)
+ { /* We don't distinguish between errors for now */
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_name.str);
+ goto error;
+ }
+ break;
+ }
+ case SQLCOM_SHOW_CREATE_FUNC:
+ {
+ if (lex->spname->m_name.length > NAME_LEN)
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
+ goto error;
+ }
+ if (sp_show_create_function(thd, lex->spname) != SP_OK)
+ { /* We don't distinguish between errors for now */
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
+ SP_COM_STRING(lex), lex->spname->m_name.str);
+ goto error;
+ }
+ break;
+ }
+ case SQLCOM_SHOW_STATUS_PROC:
+ {
+ res= sp_show_status_procedure(thd, (lex->wild ?
+ lex->wild->ptr() : NullS));
+ break;
+ }
+ case SQLCOM_SHOW_STATUS_FUNC:
+ {
+ res= sp_show_status_function(thd, (lex->wild ?
+ lex->wild->ptr() : NullS));
+ break;
+ }
+ case SQLCOM_CREATE_VIEW:
+ {
+ if (!(res= mysql_create_view(thd, thd->lex->create_view_mode)) &&
+ mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+ break;
+ }
+ case SQLCOM_DROP_VIEW:
+ {
+ if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
+ end_active_trans(thd))
+ goto error;
+ if (!(res= mysql_drop_view(thd, first_table, thd->lex->drop_mode)) &&
+ mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+ break;
+ }
+ case SQLCOM_CREATE_TRIGGER:
+ {
+ res= mysql_create_or_drop_trigger(thd, all_tables, 1);
+
+ /* We don't care about trigger body after this point */
+ delete lex->sphead;
+ lex->sphead= 0;
+ break;
+ }
+ case SQLCOM_DROP_TRIGGER:
+ {
+ res= mysql_create_or_drop_trigger(thd, all_tables, 0);
+ break;
+ }
+ case SQLCOM_XA_START:
+ if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
+ {
+ if (! thd->transaction.xid.eq(thd->lex->xid))
+ {
+ my_error(ER_XAER_NOTA, MYF(0));
+ break;
+ }
+ thd->transaction.xa_state=XA_ACTIVE;
+ send_ok(thd);
+ break;
+ }
+ if (thd->lex->xa_opt != XA_NONE)
+ { // JOIN is not supported yet. TODO
+ my_error(ER_XAER_INVAL, MYF(0));
+ break;
+ }
+ if (thd->transaction.xa_state != XA_NOTR)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
+ }
+ if (thd->active_transaction() || thd->locked_tables)
+ {
+ my_error(ER_XAER_OUTSIDE, MYF(0));
+ break;
+ }
+ DBUG_ASSERT(thd->transaction.xid.is_null());
+ thd->transaction.xa_state=XA_ACTIVE;
+ thd->transaction.xid.set(thd->lex->xid);
+ thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
+ OPTION_BEGIN);
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+ send_ok(thd);
+ break;
+ case SQLCOM_XA_END:
+ /* fake it */
+ if (thd->lex->xa_opt != XA_NONE)
+ { // SUSPEND and FOR MIGRATE are not supported yet. TODO
+ my_error(ER_XAER_INVAL, MYF(0));
+ break;
+ }
+ if (thd->transaction.xa_state != XA_ACTIVE)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
+ }
+ if (!thd->transaction.xid.eq(thd->lex->xid))
+ {
+ my_error(ER_XAER_NOTA, MYF(0));
+ break;
+ }
+ thd->transaction.xa_state=XA_IDLE;
+ send_ok(thd);
+ break;
+ case SQLCOM_XA_PREPARE:
+ if (thd->transaction.xa_state != XA_IDLE)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
+ }
+ if (!thd->transaction.xid.eq(thd->lex->xid))
+ {
+ my_error(ER_XAER_NOTA, MYF(0));
+ break;
+ }
+ if (ha_prepare(thd))
+ {
+ my_error(ER_XA_RBROLLBACK, MYF(0));
+ thd->transaction.xa_state=XA_NOTR;
+ break;
+ }
+ thd->transaction.xa_state=XA_PREPARED;
+ send_ok(thd);
+ break;
+ case SQLCOM_XA_COMMIT:
+ if (!thd->transaction.xid.eq(thd->lex->xid))
+ {
+ if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 1)))
+ my_error(ER_XAER_NOTA, MYF(0));
+ else
+ send_ok(thd);
+ break;
+ }
+ if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
+ {
+ int r;
+ if ((r= ha_commit(thd)))
+ my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
+ else
+ send_ok(thd);
}
else
- res= -1;
+ if (thd->transaction.xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
+ {
+ if (wait_if_global_read_lock(thd, 0, 0))
+ {
+ ha_rollback(thd);
+ my_error(ER_XAER_RMERR, MYF(0));
+ }
+ else
+ {
+ if (ha_commit_one_phase(thd, 1))
+ my_error(ER_XAER_RMERR, MYF(0));
+ else
+ send_ok(thd);
+ start_waiting_global_read_lock(thd);
+ }
+ }
+ else
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
+ }
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->transaction.xa_state=XA_NOTR;
break;
- case SQLCOM_ROLLBACK_TO_SAVEPOINT:
- if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
+ case SQLCOM_XA_ROLLBACK:
+ if (!thd->transaction.xid.eq(thd->lex->xid))
{
- if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
- send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
+ if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 0)))
+ my_error(ER_XAER_NOTA, MYF(0));
else
- send_ok(thd);
+ send_ok(thd);
+ break;
+ }
+ if (thd->transaction.xa_state != XA_IDLE &&
+ thd->transaction.xa_state != XA_PREPARED)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0),
+ xa_state_names[thd->transaction.xa_state]);
+ break;
}
+ if (ha_rollback(thd))
+ my_error(ER_XAER_RMERR, MYF(0));
else
- res= -1;
- break;
- case SQLCOM_SAVEPOINT:
- if (!ha_savepoint(thd, lex->savepoint_name))
send_ok(thd);
- else
- res= -1;
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ thd->transaction.xa_state=XA_NOTR;
break;
- default: /* Impossible */
+ case SQLCOM_XA_RECOVER:
+ res= mysql_xa_recover(thd);
+ break;
+ default:
+ DBUG_ASSERT(0); /* Impossible */
send_ok(thd);
break;
}
- thd->proc_info="query end"; // QQ
+ thd->proc_info="query end";
if (thd->one_shot_set)
{
/*
@@ -3655,10 +4519,20 @@ purposes internal to the MySQL server", MYF(0));
thd->one_shot_set= 0;
}
}
- if (res < 0)
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+
+ /*
+ The return value for ROW_COUNT() is "implementation dependent" if
+ the statement is not DELETE, INSERT or UPDATE (or a CALL executing
+ such a statement), but -1 is what JDBC and ODBC wants.
+ */
+ if (lex->sql_command != SQLCOM_CALL && uc_update_queries[lex->sql_command]<2)
+ thd->row_count_func= -1;
+ goto cleanup;
error:
+ res= 1;
+
+cleanup:
if (unlikely(slave_fake_lock))
{
DBUG_PRINT("info",("undoing faked lock"));
@@ -3667,7 +4541,7 @@ error:
if (thd->lock == thd->locked_tables)
thd->lock= 0;
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(res || thd->net.report_error);
}
@@ -3678,28 +4552,29 @@ error:
SYNOPSIS
check_one_table_access()
thd Thread handler
- privilege requested privelage
- tables table list of command
+ privilege requested privilege
+ all_tables global table list of query
RETURN
0 - OK
1 - access denied, error is sent to client
*/
-int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
+bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
{
- if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
+ if (check_access(thd, privilege, all_tables->db,
+ &all_tables->grant.privilege, 0, 0))
return 1;
/* Show only 1 table for check_grant */
- if (grant_option && check_grant(thd, privilege, tables, 0, 1, 0))
+ if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
return 1;
/* Check rights on tables of subselects and implictly opened tables */
TABLE_LIST *subselects_tables;
- if ((subselects_tables= tables->next))
+ if ((subselects_tables= all_tables->next_global))
{
- if ((check_table_access(thd, SELECT_ACL, subselects_tables,0)))
+ if ((check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
return 1;
}
return 0;
@@ -3729,14 +4604,14 @@ bool
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool dont_check_global_grants, bool no_errors)
{
- DBUG_ENTER("check_access");
- DBUG_PRINT("enter",("db: '%s' want_access: %lu master_access: %lu",
- db ? db : "", want_access, thd->master_access));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access;
bool db_is_pattern= test(want_access & GRANT_ACL);
#endif
ulong dummy;
+ DBUG_ENTER("check_access");
+ DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
+ db ? db : "", want_access, thd->master_access));
if (save_priv)
*save_priv=0;
else
@@ -3744,8 +4619,10 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
+ DBUG_PRINT("error",("No database"));
if (!no_errors)
- send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
+ MYF(0)); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
}
@@ -3769,11 +4646,14 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
! db && dont_check_global_grants)
{ // We can never grant this
+ DBUG_PRINT("error",("No possible access"));
if (!no_errors)
- net_printf(thd,ER_ACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->priv_host,
- thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
+ my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user,
+ thd->priv_host,
+ (thd->password ?
+ ER(ER_YES) :
+ ER(ER_NO))); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
}
@@ -3787,18 +4667,24 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_PRINT("info",("db_access: %lu", db_access));
/* Remove SHOW attribute and access rights we already have */
want_access &= ~(thd->master_access | EXTRA_ACL);
+ DBUG_PRINT("info",("db_access: %lu want_access: %lu",
+ db_access, want_access));
db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
/* grant_option is set if there exists a single table or column grant */
if (db_access == want_access ||
- ((grant_option && !dont_check_global_grants) &&
- !(want_access & ~(db_access | TABLE_ACLS))))
+ (grant_option && !dont_check_global_grants &&
+ !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
DBUG_RETURN(FALSE); /* Ok */
+
+ DBUG_PRINT("error",("Access denied"));
if (!no_errors)
- net_printf(thd,ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->priv_host,
- db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user,
+ thd->priv_host,
+ (db ? db : (thd->db ?
+ thd->db :
+ "unknown"))); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -3813,7 +4699,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
want_access Use should have any of these global rights
WARNING
- One gets access rigth if one has ANY of the rights in want_access
+ One gets access right if one has ANY of the rights in want_access
This is useful as one in most cases only need one global right,
but in some case we want to check if the user has SUPER or
REPL_CLIENT_ACL rights.
@@ -3832,8 +4718,7 @@ bool check_global_access(THD *thd, ulong want_access)
if ((thd->master_access & want_access))
return 0;
get_privilege_desc(command, sizeof(command), want_access);
- net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
- command);
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
return 1;
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -3851,10 +4736,10 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
uint found=0;
ulong found_access=0;
TABLE_LIST *org_tables=tables;
- for (; tables ; tables=tables->next)
+ for (; tables; tables= tables->next_global)
{
- if (tables->derived ||
- (tables->table && (int)tables->table->tmp_table) ||
+ if (tables->derived || tables->schema_table || tables->belong_to_view ||
+ (tables->table && (int)tables->table->s->tmp_table) ||
my_tz_check_n_skip_implicit_tables(&tables,
thd->lex->time_zone_tables_used))
continue;
@@ -3884,6 +4769,93 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
return FALSE;
}
+
+bool
+check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
+ bool no_errors)
+{
+ TABLE_LIST tables[1];
+
+ bzero((char *)tables, sizeof(TABLE_LIST));
+ tables->db= db;
+ tables->table_name= tables->alias= name;
+
+ if ((thd->master_access & want_access) == want_access && !thd->db)
+ tables->grant.privilege= want_access;
+ else if (check_access(thd,want_access,db,&tables->grant.privilege,
+ 0, no_errors))
+ return TRUE;
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (grant_option)
+ return check_grant_procedure(thd, want_access, tables, no_errors);
+#endif
+
+ return FALSE;
+}
+
+
+/*
+ Check if the routine has any of the routine privileges
+
+ SYNOPSIS
+ check_some_routine_access()
+ thd Thread handler
+ db Database name
+ name Routine name
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool check_some_routine_access(THD *thd, const char *db, const char *name)
+{
+ ulong save_priv;
+ if (thd->master_access & SHOW_PROC_ACLS)
+ return FALSE;
+ if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) ||
+ (save_priv & SHOW_PROC_ACLS))
+ return FALSE;
+ return check_routine_level_acl(thd, db, name);
+}
+
+
+/*
+ Check if the given table has any of the asked privileges
+
+ SYNOPSIS
+ check_some_access()
+ thd Thread handler
+ want_access Bitmap of possible privileges to check for
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+
+bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
+{
+ ulong access;
+ DBUG_ENTER("check_some_access");
+
+ /* This loop will work as long as we have less than 32 privileges */
+ for (access= 1; access < want_access ; access<<= 1)
+ {
+ if (access & want_access)
+ {
+ if (!check_access(thd, access, table->db,
+ &table->grant.privilege, 0, 1) &&
+ !grant_option || !check_grant(thd, access, table, 0, 1, 1))
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_PRINT("exit",("no matching access rights"));
+ DBUG_RETURN(1);
+}
+
+
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list)
{
@@ -3892,7 +4864,7 @@ bool check_merge_table_access(THD *thd, char *db,
{
/* Check that all tables use the current database */
TABLE_LIST *tmp;
- for (tmp=table_list; tmp ; tmp=tmp->next)
+ for (tmp= table_list; tmp; tmp= tmp->next_local)
{
if (!tmp->db || !tmp->db[0])
tmp->db=db;
@@ -3906,13 +4878,14 @@ bool check_merge_table_access(THD *thd, char *db,
static bool check_db_used(THD *thd,TABLE_LIST *tables)
{
- for (; tables ; tables=tables->next)
+ for (; tables; tables= tables->next_global)
{
if (!tables->db)
{
if (!(tables->db=thd->db))
{
- send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
+ MYF(0)); /* purecov: tested */
return TRUE; /* purecov: tested */
}
}
@@ -3920,6 +4893,7 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables)
return FALSE;
}
+
/****************************************************************************
Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/
@@ -3984,6 +4958,7 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
return 0;
}
+
/****************************************************************************
Initialize global thd variables needed for query
****************************************************************************/
@@ -4016,13 +4991,13 @@ void mysql_reset_thd_for_next_command(THD *thd)
DBUG_ENTER("mysql_reset_thd_for_next_command");
thd->free_list= 0;
thd->select_number= 1;
- thd->total_warn_count= 0; // Warnings for this query
+ thd->total_warn_count=0; // Warnings for this query
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
thd->sent_row_count= thd->examined_row_count= 0;
thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0;
thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
- SERVER_QUERY_NO_INDEX_USED |
- SERVER_QUERY_NO_GOOD_INDEX_USED);
+ SERVER_QUERY_NO_INDEX_USED |
+ SERVER_QUERY_NO_GOOD_INDEX_USED);
thd->tmp_table_used= 0;
if (opt_bin_log)
reset_dynamic(&thd->user_var_events);
@@ -4037,6 +5012,8 @@ mysql_init_select(LEX *lex)
SELECT_LEX *select_lex= lex->current_select;
select_lex->init_select();
select_lex->select_limit= HA_POS_ERROR;
+ lex->orig_sql_command= SQLCOM_END;
+ lex->wild= 0;
if (select_lex == &lex->select_lex)
{
DBUG_ASSERT(lex->result == 0);
@@ -4049,18 +5026,21 @@ bool
mysql_new_select(LEX *lex, bool move_down)
{
SELECT_LEX *select_lex;
+ DBUG_ENTER("mysql_new_select");
+
if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
- return 1;
+ DBUG_RETURN(1);
select_lex->select_number= ++lex->thd->select_number;
select_lex->init_query();
select_lex->init_select();
+ select_lex->parent_lex= lex;
if (move_down)
{
+ SELECT_LEX_UNIT *unit;
lex->subqueries= TRUE;
/* first select_lex of subselect or derived table */
- SELECT_LEX_UNIT *unit;
if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
- return 1;
+ DBUG_RETURN(1);
unit->init_query();
unit->init_select();
@@ -4070,10 +5050,15 @@ 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
+ /* TODO: assign resolve_mode for fake subquery after merging with new tree */
}
else
{
+ 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);
SELECT_LEX_UNIT *unit= select_lex->master_unit();
SELECT_LEX *fake= unit->fake_select_lex;
@@ -4084,7 +5069,7 @@ mysql_new_select(LEX *lex, bool move_down)
fake SELECT_LEX for UNION processing
*/
if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
- return 1;
+ DBUG_RETURN(1);
fake->include_standalone(unit,
(SELECT_LEX_NODE**)&unit->fake_select_lex);
fake->select_number= INT_MAX;
@@ -4098,7 +5083,7 @@ mysql_new_select(LEX *lex, bool move_down)
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;
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -4141,6 +5126,8 @@ void mysql_init_multi_delete(LEX *lex)
lex->select_lex.select_limit= lex->unit.select_limit_cnt=
HA_POS_ERROR;
lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
+ lex->query_tables= 0;
+ lex->query_tables_last= &lex->query_tables;
}
@@ -4169,7 +5156,13 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
#endif
{
if (thd->net.report_error)
- send_error(thd, 0, NullS);
+ {
+ if (thd->lex->sphead)
+ {
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
+ }
else
{
/*
@@ -4182,23 +5175,32 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
PROCESSLIST.
Note that we don't need LOCK_thread_count to modify query_length.
*/
- if (lex->found_colon &&
- (thd->query_length= (ulong)(lex->found_colon - thd->query)))
+ if (lex->found_semicolon &&
+ (thd->query_length= (ulong)(lex->found_semicolon - thd->query)))
thd->query_length--;
/* Actually execute the query */
mysql_execute_command(thd);
query_cache_end_of_result(thd);
}
}
+ lex->unit.cleanup();
}
else
{
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error));
query_cache_abort(&thd->net);
+ lex->unit.cleanup();
+ if (thd->lex->sphead)
+ {
+ /* Clean up after failed stored procedure/function */
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
}
thd->proc_info="freeing items";
thd->end_statement();
+ thd->cleanup_after_query();
DBUG_ASSERT(thd->change_list.is_empty());
}
DBUG_VOID_RETURN;
@@ -4219,17 +5221,20 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
{
LEX *lex= thd->lex;
bool error= 0;
+ DBUG_ENTER("mysql_test_parse_for_slave");
mysql_init_query(thd, (uchar*) inBuf, length);
if (!yyparse((void*) thd) && ! thd->is_fatal_error &&
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
- error= 1; /* Ignore question */
+ error= 1; /* Ignore question */
thd->end_statement();
- return error;
+ thd->cleanup_after_query();
+ DBUG_RETURN(error);
}
#endif
+
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
@@ -4246,13 +5251,11 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{
register create_field *new_field;
LEX *lex= thd->lex;
- uint allowed_type_modifier=0;
- char warn_buff[MYSQL_ERRMSG_SIZE];
DBUG_ENTER("add_field_to_list");
if (strlen(field_name) > NAME_LEN)
{
- net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
+ my_error(ER_TOO_LONG_IDENT, MYF(0), field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
if (type_modifier & PRI_KEY_FLAG)
@@ -4283,7 +5286,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
!(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
type == FIELD_TYPE_TIMESTAMP))
{
- net_printf(thd, ER_INVALID_DEFAULT, field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
DBUG_RETURN(1);
}
else if (default_value->type() == Item::NULL_ITEM)
@@ -4292,25 +5295,54 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
NOT_NULL_FLAG)
{
- net_printf(thd,ER_INVALID_DEFAULT,field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
DBUG_RETURN(1);
}
}
else if (type_modifier & AUTO_INCREMENT_FLAG)
{
- net_printf(thd, ER_INVALID_DEFAULT, field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
DBUG_RETURN(1);
}
}
if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
{
- net_printf(thd, ER_INVALID_ON_UPDATE, field_name);
+ my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
DBUG_RETURN(1);
}
-
- if (!(new_field=new create_field()))
+
+ 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)))
DBUG_RETURN(1);
+
+ lex->create_list.push_back(new_field);
+ lex->last_field=new_field;
+ DBUG_RETURN(0);
+}
+
+/*****************************************************************************
+** Create field definition for create
+** Return 0 on failure, otherwise return create_field instance
+******************************************************************************/
+
+create_field *
+new_create_field(THD *thd, char *field_name, enum_field_types type,
+ char *length, char *decimals,
+ uint type_modifier,
+ Item *default_value, Item *on_update_value,
+ LEX_STRING *comment,
+ char *change, List<String> *interval_list, CHARSET_INFO *cs,
+ uint uint_geom_type)
+{
+ register create_field *new_field;
+ uint sign_len, allowed_type_modifier=0;
+ ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
+ DBUG_ENTER("new_create_field");
+
+ if (!(new_field=new create_field()))
+ DBUG_RETURN(NULL);
new_field->field=0;
new_field->field_name=field_name;
new_field->def= default_value;
@@ -4323,24 +5355,24 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
new_field->length=0;
new_field->change=change;
new_field->interval=0;
- new_field->pack_length=0;
+ new_field->pack_length= new_field->key_length= 0;
new_field->charset=cs;
new_field->geom_type= (Field::geometry_type) uint_geom_type;
- if (!comment)
- {
- new_field->comment.str=0;
- new_field->comment.length=0;
- }
- else
- {
- /* In this case comment is always of type Item_string */
- new_field->comment.str= (char*) comment->str;
- new_field->comment.length=comment->length;
- }
+ new_field->comment=*comment;
+ /*
+ Set flag if this field doesn't have a default value
+ Enum values has always the first value as a default (set in
+ make_empty_rec().
+ */
+ if (!default_value && !(type_modifier & AUTO_INCREMENT_FLAG) &&
+ (type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP &&
+ type != FIELD_TYPE_ENUM)
+ new_field->flags|= NO_DEFAULT_VALUE_FLAG;
+
if (length && !(new_field->length= (uint) atoi(length)))
length=0; /* purecov: inspected */
- uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
+ sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1;
if (new_field->length && new_field->decimals &&
new_field->length < new_field->decimals+1 &&
@@ -4370,59 +5402,42 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
break;
case FIELD_TYPE_NULL:
break;
- case FIELD_TYPE_DECIMAL:
+ case FIELD_TYPE_NEWDECIMAL:
if (!length)
{
- if ((new_field->length= new_field->decimals))
- new_field->length++;
- else
+ if (!(new_field->length= new_field->decimals))
new_field->length= 10; // Default length for DECIMAL
}
- if (new_field->length < MAX_FIELD_WIDTH) // Skip wrong argument
- {
- new_field->length+=sign_len;
- if (new_field->decimals)
- new_field->length++;
- }
- break;
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
- if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value)
+ new_field->pack_length=
+ my_decimal_get_binary_size(new_field->length, new_field->decimals);
+ if (new_field->length <= DECIMAL_MAX_LENGTH &&
+ new_field->length >= new_field->decimals)
break;
- /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
- new_field->sql_type= FIELD_TYPE_BLOB;
- sprintf(warn_buff, ER(ER_AUTO_CONVERT), field_name, "CHAR",
- (cs == &my_charset_bin) ? "BLOB" : "TEXT");
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
- warn_buff);
- /* fall through */
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
+ DBUG_RETURN(NULL);
+ case MYSQL_TYPE_VARCHAR:
+ /*
+ Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
+ if they don't have a default value
+ */
+ max_field_charlength= MAX_FIELD_VARCHARLENGTH;
+ break;
+ case MYSQL_TYPE_STRING:
+ break;
case FIELD_TYPE_BLOB:
case FIELD_TYPE_TINY_BLOB:
case FIELD_TYPE_LONG_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
case FIELD_TYPE_GEOMETRY:
- if (new_field->length)
- {
- /* The user has given a length to the blob column */
- if (new_field->length < 256)
- type= FIELD_TYPE_TINY_BLOB;
- else if (new_field->length < 65536)
- type= FIELD_TYPE_BLOB;
- else if (new_field->length < 256L*256L*256L)
- type= FIELD_TYPE_MEDIUM_BLOB;
- else
- type= FIELD_TYPE_LONG_BLOB;
- new_field->length= 0;
- }
- new_field->sql_type= type;
if (default_value) // Allow empty as default value
{
String str,*res;
res=default_value->val_str(&str);
if (res->length())
{
- net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
- DBUG_RETURN(1); /* purecov: inspected */
+ my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
+ field_name); /* purecov: inspected */
+ DBUG_RETURN(NULL);
}
new_field->def=0;
}
@@ -4441,8 +5456,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
uint tmp_length=new_field->length;
if (tmp_length > PRECISION_FOR_DOUBLE)
{
- net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
- DBUG_RETURN(1);
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
+ DBUG_RETURN(NULL);
}
else if (tmp_length > PRECISION_FOR_FLOAT)
{
@@ -4514,11 +5529,11 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
If we have TIMESTAMP NULL column without explicit DEFAULT value
we treat it as having DEFAULT NULL attribute.
*/
- new_field->unireg_check= on_update_value ?
- Field::TIMESTAMP_UN_FIELD :
- (new_field->flags & NOT_NULL_FLAG ?
- Field::TIMESTAMP_OLD_FIELD:
- Field::NONE);
+ new_field->unireg_check= (on_update_value ?
+ Field::TIMESTAMP_UN_FIELD :
+ (new_field->flags & NOT_NULL_FLAG ?
+ Field::TIMESTAMP_OLD_FIELD:
+ Field::NONE));
}
break;
case FIELD_TYPE_DATE: // Old date type
@@ -4538,8 +5553,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{
if (interval_list->elements > sizeof(longlong)*8)
{
- net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
- DBUG_RETURN(1); /* purecov: inspected */
+ my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
+ DBUG_RETURN(NULL);
}
new_field->pack_length= get_set_pack_length(interval_list->elements);
@@ -4553,8 +5568,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
when we know the character set of the column
*/
new_field->length= 1;
+ break;
}
- break;
case FIELD_TYPE_ENUM:
{
// Should be safe
@@ -4565,37 +5580,50 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
while ((tmp= it++))
new_field->interval_list.push_back(tmp);
new_field->length= 1; // See comment for FIELD_TYPE_SET above.
- }
+ break;
+ }
+ case MYSQL_TYPE_VAR_STRING:
+ DBUG_ASSERT(0); // Impossible
break;
+ case MYSQL_TYPE_BIT:
+ {
+ if (!length)
+ new_field->length= 1;
+ if (new_field->length > MAX_BIT_FIELD_LENGTH)
+ {
+ my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name,
+ MAX_BIT_FIELD_LENGTH);
+ DBUG_RETURN(NULL);
+ }
+ new_field->pack_length= (new_field->length + 7) / 8;
+ break;
+ }
+ case FIELD_TYPE_DECIMAL:
+ DBUG_ASSERT(0); /* Was obsolete */
}
- if ((new_field->length > MAX_FIELD_CHARLENGTH && type != FIELD_TYPE_SET &&
- type != FIELD_TYPE_ENUM) ||
- (!new_field->length && !(new_field->flags & BLOB_FLAG) &&
- type != FIELD_TYPE_STRING &&
- type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
+ if (!(new_field->flags & BLOB_FLAG) &&
+ ((new_field->length > max_field_charlength && type != FIELD_TYPE_SET &&
+ type != FIELD_TYPE_ENUM &&
+ (type != MYSQL_TYPE_VARCHAR || default_value)) ||
+ (!new_field->length &&
+ type != MYSQL_TYPE_STRING &&
+ type != MYSQL_TYPE_VARCHAR && type != FIELD_TYPE_GEOMETRY)))
{
- net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
- MAX_FIELD_CHARLENGTH); /* purecov: inspected */
- DBUG_RETURN(1); /* purecov: inspected */
+ my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0),
+ field_name, max_field_charlength); /* purecov: inspected */
+ DBUG_RETURN(NULL);
}
type_modifier&= AUTO_INCREMENT_FLAG;
if ((~allowed_type_modifier) & type_modifier)
{
- net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
- DBUG_RETURN(1);
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
+ DBUG_RETURN(NULL);
}
- if (!new_field->pack_length)
- new_field->pack_length=calc_pack_length(new_field->sql_type ==
- FIELD_TYPE_VAR_STRING ?
- FIELD_TYPE_STRING :
- new_field->sql_type,
- new_field->length);
- lex->create_list.push_back(new_field);
- lex->last_field=new_field;
- DBUG_RETURN(0);
+ DBUG_RETURN(new_field);
}
+
/* Store position for column in ALTER TABLE .. ADD column */
void store_position_for_column(const char *name)
@@ -4634,7 +5662,6 @@ static void remove_escape(char *name)
{
#ifdef USE_MB
int l;
-/* if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
if (use_mb(system_charset_info) &&
(l = my_ismbchar(system_charset_info, name, strend)))
{
@@ -4667,6 +5694,7 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
order->asc = asc;
order->free_me=0;
order->used=0;
+ order->counter_used= 0;
list.link_in_list((byte*) order,(byte**) &order->next);
DBUG_RETURN(0);
}
@@ -4702,6 +5730,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
register TABLE_LIST *ptr;
char *alias_str;
+ LEX *lex= thd->lex;
DBUG_ENTER("add_table_to_list");
if (!table)
@@ -4710,7 +5739,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
if (check_table_name(table->table.str,table->table.length) ||
table->db.str && check_db_name(table->db.str))
{
- net_printf(thd, ER_WRONG_TABLE_NAME, table->table.str);
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
DBUG_RETURN(0);
}
@@ -4718,7 +5747,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
if (table->sel)
{
- net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
+ my_message(ER_DERIVED_MUST_HAVE_ALIAS,
+ ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
DBUG_RETURN(0);
}
if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
@@ -4748,13 +5778,29 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->alias= alias_str;
if (lower_case_table_names && table->table.length)
my_casedn_str(files_charset_info, table->table.str);
- ptr->real_name=table->table.str;
- ptr->real_name_length=table->table.length;
+ ptr->table_name=table->table.str;
+ ptr->table_name_length=table->table.length;
ptr->lock_type= lock_type;
ptr->updating= test(table_options & TL_OPTION_UPDATING);
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel;
+ if (!my_strcasecmp(system_charset_info, ptr->db,
+ information_schema_name.str))
+ {
+ ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
+ if (!schema_table ||
+ (schema_table->hidden &&
+ lex->orig_sql_command == SQLCOM_END)) // not a 'show' command
+ {
+ my_error(ER_UNKNOWN_TABLE, MYF(0),
+ ptr->table_name, information_schema_name.str);
+ DBUG_RETURN(0);
+ }
+ ptr->schema_table_name= ptr->table_name;
+ ptr->schema_table= schema_table;
+ }
+ ptr->select_lex= lex->current_select;
ptr->cacheable_table= 1;
if (use_index_arg)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
@@ -4768,22 +5814,264 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
tables ;
- tables=tables->next)
+ tables=tables->next_local)
{
if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
!strcmp(ptr->db, tables->db))
{
- net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
+ my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
DBUG_RETURN(0); /* purecov: tested */
}
}
}
- table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
+ /* Link table in local list (list for current select) */
+ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
+ /* Link table in global list (all used tables) */
+ lex->add_to_query_tables(ptr);
+ DBUG_RETURN(ptr);
+}
+
+
+/*
+ Initialize a new table list for a nested join
+
+ SYNOPSIS
+ init_nested_join()
+ thd current thread
+
+ DESCRIPTION
+ The function initializes a structure of the TABLE_LIST type
+ for a nested join. It sets up its nested join list as empty.
+ The created structure is added to the front of the current
+ join list in the st_select_lex object. Then the function
+ changes the current nest level for joins to refer to the newly
+ created empty list after having saved the info on the old level
+ in the initialized structure.
+
+ RETURN VALUE
+ 0, if success
+ 1, otherwise
+*/
+
+bool st_select_lex::init_nested_join(THD *thd)
+{
+ TABLE_LIST *ptr;
+ NESTED_JOIN *nested_join;
+ DBUG_ENTER("init_nested_join");
+
+ if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
+ !(nested_join= ptr->nested_join=
+ (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
+ DBUG_RETURN(1);
+ join_list->push_front(ptr);
+ ptr->embedding= embedding;
+ ptr->join_list= join_list;
+ embedding= ptr;
+ join_list= &nested_join->join_list;
+ join_list->empty();
+ DBUG_RETURN(0);
+}
+
+
+/*
+ End a nested join table list
+
+ SYNOPSIS
+ end_nested_join()
+ thd current thread
+
+ DESCRIPTION
+ The function returns to the previous join nest level.
+ If the current level contains only one member, the function
+ moves it one level up, eliminating the nest.
+
+ RETURN VALUE
+ Pointer to TABLE_LIST element added to the total table list, if success
+ 0, otherwise
+*/
+
+TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
+{
+ TABLE_LIST *ptr;
+ NESTED_JOIN *nested_join;
+ DBUG_ENTER("end_nested_join");
+
+ DBUG_ASSERT(embedding);
+ ptr= embedding;
+ join_list= ptr->join_list;
+ embedding= ptr->embedding;
+ nested_join= ptr->nested_join;
+ if (nested_join->join_list.elements == 1)
+ {
+ TABLE_LIST *embedded= nested_join->join_list.head();
+ join_list->pop();
+ embedded->join_list= join_list;
+ embedded->embedding= embedding;
+ join_list->push_front(embedded);
+ ptr= embedded;
+ }
+ else if (nested_join->join_list.elements == 0)
+ {
+ join_list->pop();
+ ptr= 0; // return value
+ }
DBUG_RETURN(ptr);
}
/*
+ Nest last join operation
+
+ SYNOPSIS
+ nest_last_join()
+ thd current thread
+
+ DESCRIPTION
+ The function nest last join operation as if it was enclosed in braces.
+
+ RETURN VALUE
+ Pointer to TABLE_LIST element created for the new nested join, if success
+ 0, otherwise
+*/
+
+TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
+{
+ TABLE_LIST *ptr;
+ NESTED_JOIN *nested_join;
+ DBUG_ENTER("nest_last_join");
+
+ if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
+ !(nested_join= ptr->nested_join=
+ (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
+ DBUG_RETURN(0);
+ ptr->embedding= embedding;
+ ptr->join_list= join_list;
+ List<TABLE_LIST> *embedded_list= &nested_join->join_list;
+ embedded_list->empty();
+ for (int i=0; i < 2; i++)
+ {
+ TABLE_LIST *table= join_list->pop();
+ table->join_list= embedded_list;
+ table->embedding= ptr;
+ embedded_list->push_back(table);
+ }
+ join_list->push_front(ptr);
+ nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
+ DBUG_RETURN(ptr);
+}
+
+
+/*
+ Save names for a join with using clause
+
+ SYNOPSIS
+ save_names_for_using_list
+ tab1 left table in join
+ tab2 right table in join
+
+ DESCRIPTION
+ The function saves the full names of the tables in st_select_lex
+ to be able to build later an on expression to replace the using clause.
+
+ RETURN VALUE
+ None
+*/
+
+void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
+ TABLE_LIST *tab2)
+{
+ while (tab1->nested_join)
+ {
+ tab1= tab1->nested_join->join_list.head();
+ }
+ db1= tab1->db;
+ table1= tab1->alias;
+ while (tab2->nested_join)
+ {
+ TABLE_LIST *next;
+ List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
+ tab2= it++;
+ while ((next= it++))
+ tab2= next;
+ }
+ db2= tab2->db;
+ table2= tab2->alias;
+}
+
+
+/*
+ Add a table to the current join list
+
+ SYNOPSIS
+ add_joined_table()
+ table the table to add
+
+ DESCRIPTION
+ The function puts a table in front of the current join list
+ of st_select_lex object.
+ Thus, joined tables are put into this list in the reverse order
+ (the most outer join operation follows first).
+
+ RETURN VALUE
+ None
+*/
+
+void st_select_lex::add_joined_table(TABLE_LIST *table)
+{
+ DBUG_ENTER("add_joined_table");
+ join_list->push_front(table);
+ table->join_list= join_list;
+ table->embedding= embedding;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Convert a right join into equivalent left join
+
+ SYNOPSIS
+ convert_right_join()
+ thd current thread
+
+ DESCRIPTION
+ The function takes the current join list t[0],t[1] ... and
+ effectively converts it into the list t[1],t[0] ...
+ Although the outer_join flag for the new nested table contains
+ JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
+ operation.
+
+ EXAMPLES
+ SELECT * FROM t1 RIGHT JOIN t2 ON on_expr =>
+ SELECT * FROM t2 LEFT JOIN t1 ON on_expr
+
+ SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr =>
+ SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr
+
+ SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr =>
+ SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr
+
+ SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3 ON on_expr2 =>
+ SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1
+
+ RETURN
+ Pointer to the table representing the inner table, if success
+ 0, otherwise
+*/
+
+TABLE_LIST *st_select_lex::convert_right_join()
+{
+ TABLE_LIST *tab2= join_list->pop();
+ TABLE_LIST *tab1= join_list->pop();
+ DBUG_ENTER("convert_right_join");
+
+ join_list->push_front(tab2);
+ join_list->push_front(tab1);
+ tab1->outer_join|= JOIN_TYPE_RIGHT;
+
+ DBUG_RETURN(tab1);
+}
+
+/*
Set lock for all tables in current select level
SYNOPSIS:
@@ -4803,9 +6091,9 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type,
for_update));
- for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
- tables ;
- tables=tables->next)
+ for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first;
+ tables;
+ tables= tables->next_local)
{
tables->lock_type= lock_type;
tables->updating= for_update;
@@ -4822,7 +6110,7 @@ void add_join_on(TABLE_LIST *b,Item *expr)
b->on_expr=expr;
else
{
- // This only happens if you have both a right and left join
+ /* This only happens if you have both a right and left join */
b->on_expr=new Item_cond_and(b->on_expr,expr);
}
b->on_expr->top_level_item();
@@ -4837,7 +6125,7 @@ void add_join_on(TABLE_LIST *b,Item *expr)
add_join_natural()
a Table to do normal join with
b Do normal join with this table
-
+
IMPLEMENTATION
This function just marks that table b should be joined with a.
The function setup_cond() will create in b->on_expr a list
@@ -4884,8 +6172,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
{
acl_reload(thd);
grant_reload(thd);
- if (mqh_used)
- reset_mqh(thd,(LEX_USER *) NULL,TRUE);
+ reset_mqh((LEX_USER *)NULL, TRUE);
}
#endif
if (options & REFRESH_LOG)
@@ -4895,23 +6182,16 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
the slow query log, and the relay log (if it exists).
*/
- /*
+ /*
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);
- mysql_update_log.new_file(1);
- mysql_bin_log.new_file(1);
mysql_slow_log.new_file(1);
+ mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
#ifdef HAVE_REPLICATION
- if (mysql_bin_log.is_open() && expire_logs_days)
- {
- long purge_time= time(0) - expire_logs_days*24*60*60;
- if (purge_time >= 0)
- mysql_bin_log.purge_logs_before_date(purge_time);
- }
pthread_mutex_lock(&LOCK_active_mi);
rotate_relay_log(active_mi);
pthread_mutex_unlock(&LOCK_active_mi);
@@ -4925,7 +6205,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
if (options & REFRESH_QUERY_CACHE_FREE)
{
query_cache.pack(); // FLUSH QUERY CACHE
- options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
+ options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
}
if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
{
@@ -4949,7 +6229,12 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
return 1;
result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
tables);
- make_global_read_lock_block_commit(thd);
+ if (make_global_read_lock_block_commit(thd))
+ {
+ /* Don't leave things in a half-locked state */
+ unlock_global_read_lock(thd);
+ return 1;
+ }
}
else
result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
@@ -4957,7 +6242,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
}
if (options & REFRESH_HOSTS)
hostname_cache_refresh();
- if (options & REFRESH_STATUS)
+ if (thd && (options & REFRESH_STATUS))
refresh_status();
if (options & REFRESH_THREADS)
flush_thread_cache();
@@ -4987,7 +6272,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
}
#endif
if (options & REFRESH_USER_RESOURCES)
- reset_mqh(thd,(LEX_USER *) NULL);
+ reset_mqh((LEX_USER *) NULL);
if (write_to_binlog)
*write_to_binlog= tmp_write_to_binlog;
return result;
@@ -5005,7 +6290,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
This is written such that we have a short lock on LOCK_thread_count
*/
-void kill_one_thread(THD *thd, ulong id)
+void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
{
THD *tmp;
uint error=ER_NO_SUCH_THREAD;
@@ -5025,7 +6310,7 @@ void kill_one_thread(THD *thd, ulong id)
if ((thd->master_access & SUPER_ACL) ||
!strcmp(thd->user,tmp->user))
{
- tmp->awake(1 /*prepare to die*/);
+ tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
error=0;
}
else
@@ -5036,7 +6321,7 @@ void kill_one_thread(THD *thd, ulong id)
if (!error)
send_ok(thd);
else
- net_printf(thd,error,id);
+ my_error(error, MYF(0), id);
}
@@ -5049,6 +6334,13 @@ static void refresh_status(void)
{
if (ptr->type == SHOW_LONG)
*(ulong*) ptr->value= 0;
+ else if (ptr->type == SHOW_LONG_STATUS)
+ {
+ THD *thd= current_thd;
+ /* We must update the global status before cleaning up the thread */
+ add_to_status(&global_status_var, &thd->status_var);
+ bzero((char*) &thd->status_var, sizeof(thd->status_var));
+ }
}
/* Reset the counters of all key caches (default and named). */
process_key_caches(reset_key_cache_counters);
@@ -5097,12 +6389,13 @@ static bool append_file_to_dir(THD *thd, const char **filename_ptr,
bool check_simple_select()
{
THD *thd= current_thd;
- if (thd->lex->current_select != &thd->lex->select_lex)
+ LEX *lex= thd->lex;
+ if (lex->current_select != &lex->select_lex)
{
char command[80];
- strmake(command, thd->lex->yylval->symbol.str,
- min(thd->lex->yylval->symbol.length, sizeof(command)-1));
- net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
+ strmake(command, lex->yylval->symbol.str,
+ min(lex->yylval->symbol.length, sizeof(command)-1));
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
return 1;
}
return 0;
@@ -5119,18 +6412,16 @@ bool check_simple_select()
SYNOPSIS
check_multi_update_lock()
thd Current thread
- tables List of user-supplied tables
- fields List of fields requiring update
RETURN VALUES
0 ok
1 error
*/
-static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables,
- List<Item> *fields, SELECT_LEX *select_lex)
+static bool check_multi_update_lock(THD *thd)
{
bool res= 1;
- TABLE_LIST *table;
+ LEX *lex= thd->lex;
+ TABLE_LIST *table, *tables= lex->query_tables;
DBUG_ENTER("check_multi_update_lock");
if (check_db_used(thd, tables))
@@ -5140,18 +6431,18 @@ static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables,
Ensure that we have UPDATE or SELECT privilege for each table
The exact privilege is checked in mysql_multi_update()
*/
- for (table= tables ; table ; table= table->next)
+ for (table= tables ; table ; table= table->next_local)
{
- TABLE_LIST *save= table->next;
- table->next= 0;
+ TABLE_LIST *save= table->next_local;
+ table->next_local= 0;
if ((check_access(thd, UPDATE_ACL, table->db, &table->grant.privilege,0,1) ||
(grant_option && check_grant(thd, UPDATE_ACL, table,0,1,1))) &&
check_one_table_access(thd, SELECT_ACL, table))
goto error;
- table->next= save;
+ table->next_local= save;
}
- if (mysql_multi_update_lock(thd, tables, fields, select_lex))
+ if (mysql_multi_update_prepare(thd))
goto error;
res= 0;
@@ -5242,25 +6533,24 @@ Item * all_any_subquery_creator(Item *left_expr,
One should normally create all indexes with CREATE TABLE or ALTER TABLE.
*/
-int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
+bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
{
List<create_field> fields;
ALTER_INFO alter_info;
alter_info.flags= ALTER_ADD_INDEX;
- alter_info.is_simple= 0;
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_create_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.default_table_charset= thd->variables.collation_database;
- DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
+ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
&create_info, table_list,
fields, keys, 0, (ORDER*)0,
- DUP_ERROR, 0, &alter_info));
+ DUP_ERROR, 0, &alter_info, 1));
}
-int mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
+bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
{
List<create_field> fields;
List<Key> keys;
@@ -5271,11 +6561,10 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
create_info.default_table_charset= thd->variables.collation_database;
alter_info->clear();
alter_info->flags= ALTER_DROP_INDEX;
- alter_info->is_simple= 0;
- DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
+ DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
&create_info, table_list,
fields, keys, 0, (ORDER*)0,
- DUP_ERROR, 0, alter_info));
+ DUP_ERROR, 0, alter_info, 1));
}
@@ -5285,33 +6574,31 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
SYNOPSIS
multi_update_precheck()
thd Thread handler
- tables Global table list
+ tables Global/local table list (have to be the same)
RETURN VALUE
- 0 OK
- 1 Error (message is sent to user)
- -1 Error (message is not sent to user)
+ FALSE OK
+ TRUE Error
*/
-int multi_update_precheck(THD *thd, TABLE_LIST *tables)
+bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
{
- DBUG_ENTER("multi_update_precheck");
const char *msg= 0;
TABLE_LIST *table;
LEX *lex= thd->lex;
SELECT_LEX *select_lex= &lex->select_lex;
- TABLE_LIST *update_list= (TABLE_LIST*)select_lex->table_list.first;
+ DBUG_ENTER("multi_update_precheck");
if (select_lex->item_list.elements != lex->value_list.elements)
{
- my_error(ER_WRONG_VALUE_COUNT, MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
+ DBUG_RETURN(TRUE);
}
/*
Ensure that we have UPDATE or SELECT privilege for each table
The exact privilege is checked in mysql_multi_update()
*/
- for (table= update_list; table; table= table->next)
+ for (table= tables; table; table= table->next_local)
{
if (table->derived)
table->grant.privilege= SELECT_ACL;
@@ -5319,17 +6606,12 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables)
&table->grant.privilege, 0, 1) ||
grant_option &&
check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
- (check_access(thd, SELECT_ACL, table->db,
- &table->grant.privilege, 0, 0) ||
- grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
- DBUG_RETURN(1);
+ (check_access(thd, SELECT_ACL, table->db,
+ &table->grant.privilege, 0, 0) ||
+ grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
+ DBUG_RETURN(TRUE);
- /*
- We assign following flag only to copy of table, because it will
- be checked only if query contains subqueries i.e. only if copy exists
- */
- if (table->table_list)
- table->table_list->table_in_update_from_clause= 1;
+ table->table_in_first_from_clause= 1;
}
/*
Is there tables of subqueries?
@@ -5337,27 +6619,16 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables)
if (&lex->select_lex != lex->all_selects_list)
{
DBUG_PRINT("info",("Checking sub query list"));
- for (table= tables; table; table= table->next)
+ for (table= tables; table; table= table->next_global)
{
- if (my_tz_check_n_skip_implicit_tables(&table,
- lex->time_zone_tables_used))
- continue;
- else if (table->table_in_update_from_clause)
- {
- /*
- If we check table by local TABLE_LIST copy then we should copy
- grants to global table list, because it will be used for table
- opening.
- */
- if (table->table_list)
- table->grant= table->table_list->grant;
- }
- else if (!table->derived)
+ if (!my_tz_check_n_skip_implicit_tables(&table,
+ lex->time_zone_tables_used) &&
+ !table->table_in_first_from_clause)
{
if (check_access(thd, SELECT_ACL, table->db,
&table->grant.privilege, 0, 0) ||
grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
}
}
@@ -5370,9 +6641,9 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables)
if (msg)
{
my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
/*
@@ -5381,22 +6652,21 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables)
SYNOPSIS
multi_delete_precheck()
thd Thread handler
- tables Global table list
+ tables Global/local table list
table_count Pointer to table counter
RETURN VALUE
- 0 OK
- 1 error (message is sent to user)
- -1 error (message is not sent to user)
+ FALSE OK
+ TRUE error
*/
-int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
+
+bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
{
- DBUG_ENTER("multi_delete_precheck");
SELECT_LEX *select_lex= &thd->lex->select_lex;
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
- TABLE_LIST *delete_tables= (TABLE_LIST *)select_lex->table_list.first;
TABLE_LIST *target_tbl;
+ DBUG_ENTER("multi_delete_precheck");
*table_count= 0;
@@ -5405,18 +6675,19 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
check_table_access(thd,SELECT_ACL, tables,0) ||
check_table_access(thd,DELETE_ACL, aux_tables,0))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
{
- my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
+ ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
+ DBUG_RETURN(TRUE);
}
- for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next)
+ for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next_local)
{
(*table_count)++;
/* All tables in aux_tables must be found in FROM PART */
TABLE_LIST *walk;
- for (walk= delete_tables; walk; walk= walk->next)
+ for (walk= tables; walk; walk= walk->next_local)
{
if (!my_strcasecmp(table_alias_charset,
target_tbl->alias, walk->alias) &&
@@ -5425,20 +6696,14 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
}
if (!walk)
{
- my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name,
- "MULTI DELETE");
- DBUG_RETURN(-1);
- }
- if (walk->derived)
- {
- my_error(ER_NON_UPDATABLE_TABLE, MYF(0), target_tbl->real_name,
- "DELETE");
- DBUG_RETURN(-1);
+ my_error(ER_UNKNOWN_TABLE, MYF(0),
+ target_tbl->table_name, "MULTI DELETE");
+ DBUG_RETURN(TRUE);
}
walk->lock_type= target_tbl->lock_type;
- target_tbl->table_list= walk; // Remember corresponding table
+ target_tbl->correspondent_table= walk; // Remember corresponding table
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -5451,21 +6716,20 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
tables Global table list
RETURN VALUE
- 0 OK
- 1 Error (message is sent to user)
- -1 Error (message is not sent to user)
+ FALSE OK
+ TRUE Error
*/
-int update_precheck(THD *thd, TABLE_LIST *tables)
+bool update_precheck(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("update_precheck");
if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
{
- my_error(ER_WRONG_VALUE_COUNT, MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN((check_db_used(thd, tables) ||
- check_one_table_access(thd, UPDATE_ACL, tables)) ? 1 : 0);
+ DBUG_RETURN(check_db_used(thd, tables) ||
+ check_one_table_access(thd, UPDATE_ACL, tables));
}
@@ -5478,19 +6742,18 @@ int update_precheck(THD *thd, TABLE_LIST *tables)
tables Global table list
RETURN VALUE
- 0 OK
- 1 error (message is sent to user)
- -1 error (message is not sent to user)
+ FALSE OK
+ TRUE error
*/
-int delete_precheck(THD *thd, TABLE_LIST *tables)
+bool delete_precheck(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("delete_precheck");
if (check_one_table_access(thd, DELETE_ACL, tables))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
/* Set privilege for the WHERE clause */
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -5503,12 +6766,11 @@ int delete_precheck(THD *thd, TABLE_LIST *tables)
tables Global table list
RETURN VALUE
- 0 OK
- 1 error (message is sent to user)
- -1 error (message is not sent to user)
+ FALSE OK
+ TRUE error
*/
-int insert_precheck(THD *thd, TABLE_LIST *tables)
+bool insert_precheck(THD *thd, TABLE_LIST *tables)
{
LEX *lex= thd->lex;
DBUG_ENTER("insert_precheck");
@@ -5517,19 +6779,19 @@ int insert_precheck(THD *thd, TABLE_LIST *tables)
Check that we have modify privileges for the first table and
select privileges for the rest
*/
- ulong privilege= INSERT_ACL |
- (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
- (lex->duplicates == DUP_UPDATE ? UPDATE_ACL : 0);
+ ulong privilege= (INSERT_ACL |
+ (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
+ (lex->value_list.elements ? UPDATE_ACL : 0));
if (check_one_table_access(thd, privilege, tables))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
if (lex->update_list.elements != lex->value_list.elements)
{
- my_error(ER_WRONG_VALUE_COUNT, MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -5543,17 +6805,17 @@ int insert_precheck(THD *thd, TABLE_LIST *tables)
create_table Table which will be created
RETURN VALUE
- 0 OK
- 1 Error (message is sent to user)
+ FALSE OK
+ TRUE Error
*/
-int create_table_precheck(THD *thd, TABLE_LIST *tables,
- TABLE_LIST *create_table)
+bool create_table_precheck(THD *thd, TABLE_LIST *tables,
+ TABLE_LIST *create_table)
{
LEX *lex= thd->lex;
SELECT_LEX *select_lex= &lex->select_lex;
ulong want_priv;
- int error= 1; // Error message is given
+ bool error= TRUE; // Error message is given
DBUG_ENTER("create_table_precheck");
want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
@@ -5574,37 +6836,27 @@ int create_table_precheck(THD *thd, TABLE_LIST *tables,
/* Check permissions for used tables in CREATE TABLE ... SELECT */
/*
- For temporary tables or PREPARED STATEMETNS we don't have to check
- if the created table exists
+ Only do the check for PS, becasue we on execute we have to check that
+ against the opened tables to ensure we don't use a table that is part
+ of the view (which can only be done after the table has been opened).
*/
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- ! thd->current_arena->is_stmt_prepare() &&
- find_real_table_in_list(tables, create_table->db,
- create_table->real_name))
- {
- net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name);
-
- goto err;
- }
- if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
+ if (thd->current_arena->is_stmt_prepare())
{
- TABLE_LIST *tab;
- for (tab= tables; tab; tab= tab->next)
+ /*
+ For temporary tables we don't have to check if the created table exists
+ */
+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
+ find_table_in_global_list(tables, create_table->db,
+ create_table->table_name))
{
- if (find_real_table_in_list((TABLE_LIST*) lex->create_info.
- merge_list.first,
- tables->db, tab->real_name))
- {
- net_printf(thd, ER_UPDATE_TABLE_USED, tab->real_name);
- goto err;
- }
- }
- }
-
+ error= FALSE;
+ goto err;
+ }
+ }
if (tables && check_table_access(thd, SELECT_ACL, tables,0))
goto err;
}
- error= 0;
+ error= FALSE;
err:
DBUG_RETURN(error);
@@ -5616,7 +6868,7 @@ err:
SYNOPSIS
negate_expression()
- thd therad handler
+ thd thread handler
expr expression for negation
RETURN
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index b57f88ac172..17c5f51f1e1 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -70,9 +70,13 @@ Long data handling:
#include "mysql_priv.h"
#include "sql_select.h" // for JOIN
#include <m_ctype.h> // for isspace()
+#include "sp_head.h"
+#include "sp.h"
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
+#else
+#include <mysql_com.h>
#endif
/******************************************************************************
@@ -104,7 +108,7 @@ public:
};
static void execute_stmt(THD *thd, Prepared_statement *stmt,
- String *expanded_query, bool set_context);
+ String *expanded_query);
/******************************************************************************
Implementation
@@ -118,16 +122,13 @@ inline bool is_param_null(const uchar *pos, ulong param_no)
enum { STMT_QUERY_LOG_LENGTH= 8192 };
-enum enum_send_error { DONT_SEND_ERROR= 0, SEND_ERROR };
-
/*
Seek prepared statement in statement map by id: returns zero if statement
was not found, pointer otherwise.
*/
static Prepared_statement *
-find_prepared_statement(THD *thd, ulong id, const char *where,
- enum enum_send_error se)
+find_prepared_statement(THD *thd, ulong id, const char *where)
{
Statement *stmt= thd->stmt_map.find(id);
@@ -135,8 +136,6 @@ find_prepared_statement(THD *thd, ulong id, const char *where,
{
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), 22, llstr(id, llbuf), where);
- if (se == SEND_ERROR)
- send_error(thd);
return 0;
}
return (Prepared_statement *) stmt;
@@ -151,13 +150,18 @@ find_prepared_statement(THD *thd, ulong id, const char *where,
static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
{
NET *net= &stmt->thd->net;
- char buff[9];
+ char buff[12];
+ uint tmp;
DBUG_ENTER("send_prep_stmt");
buff[0]= 0; /* OK packet indicator */
int4store(buff+1, stmt->id);
int2store(buff+5, columns);
int2store(buff+7, stmt->param_count);
+ buff[9]= 0; // Guard against a 4.1 client
+ tmp= min(stmt->thd->total_warn_count, 65535);
+ int2store(buff+10, tmp);
+
/*
Send types and names of placeholders to the client
XXX: fix this nasty upcast from List<Item_param> to List<Item>
@@ -166,7 +170,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
(stmt->param_count &&
stmt->thd->protocol_simple.send_fields((List<Item> *)
&stmt->lex->param_list,
- 0)));
+ Protocol::SEND_EOF)));
}
#else
static bool send_prep_stmt(Prepared_statement *stmt,
@@ -176,7 +180,7 @@ static bool send_prep_stmt(Prepared_statement *stmt,
thd->client_stmt_id= stmt->id;
thd->client_param_count= stmt->param_count;
- thd->net.last_errno= 0;
+ thd->clear_error();
return 0;
}
@@ -328,6 +332,13 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len)
*pos+= 8;
}
+static void set_param_decimal(Item_param *param, uchar **pos, ulong len)
+{
+ ulong length= get_param_length(pos, len);
+ param->set_decimal((char*)*pos, length);
+ *pos+= len;
+}
+
#ifndef EMBEDDED_LIBRARY
/*
@@ -399,6 +410,7 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
*pos+= length;
}
+
static void set_param_date(Item_param *param, uchar **pos, ulong len)
{
MYSQL_TIME tm;
@@ -503,6 +515,12 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
param->item_type= Item::REAL_ITEM;
param->item_result_type= REAL_RESULT;
break;
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ param->set_param_func= set_param_decimal;
+ param->item_type= Item::DECIMAL_ITEM;
+ param->item_result_type= DECIMAL_RESULT;
+ break;
case MYSQL_TYPE_TIME:
param->set_param_func= set_param_time;
param->item_type= Item::STRING_ITEM;
@@ -831,7 +849,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
varname= var_it++;
if (get_var_with_binlog(stmt->thd, *varname, &entry))
DBUG_RETURN(1);
- DBUG_ASSERT(entry);
+ DBUG_ASSERT(entry != 0);
if (param->set_from_user_var(stmt->thd, entry))
DBUG_RETURN(1);
@@ -847,7 +865,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
*ptr++= '\'';
ptr+=
escape_string_for_mysql(&my_charset_utf8_general_ci,
- ptr, entry->name.str, entry->name.length);
+ ptr, 0, entry->name.str, entry->name.length);
*ptr++= '\'';
str.length(ptr - buf);
@@ -867,28 +885,26 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
SYNOPSIS
mysql_test_insert()
stmt prepared statemen handler
- tables list of tables queries
+ tables global/local table list
RETURN VALUE
- 0 ok
- 1 error, sent to the client
- -1 error, not sent to client
+ FALSE OK
+ TRUE error
*/
-static int mysql_test_insert(Prepared_statement *stmt,
- TABLE_LIST *table_list,
- List<Item> &fields,
- List<List_item> &values_list,
- List<Item> &update_fields,
- List<Item> &update_values,
- enum_duplicates duplic)
+
+static bool mysql_test_insert(Prepared_statement *stmt,
+ TABLE_LIST *table_list,
+ List<Item> &fields,
+ List<List_item> &values_list,
+ List<Item> &update_fields,
+ List<Item> &update_values,
+ enum_duplicates duplic)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
List_iterator_fast<List_item> its(values_list);
List_item *values;
- int res= -1;
- TABLE_LIST *insert_table_list=
- (TABLE_LIST*) lex->select_lex.table_list.first;
+ bool res;
DBUG_ENTER("mysql_test_insert");
if ((res= insert_precheck(thd, table_list)))
@@ -904,42 +920,58 @@ static int mysql_test_insert(Prepared_statement *stmt,
*/
if (open_normal_and_derived_tables(thd, table_list))
{
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
+
if ((values= its++))
{
uint value_count;
ulong counter= 0;
+ Item *unused_conds= 0;
+
+ if (table_list->table)
+ {
+ // don't allocate insert_values
+ table_list->table->insert_values=(byte *)1;
+ }
- table_list->table->insert_values=(byte *)1; // don't allocate insert_values
- if ((res= mysql_prepare_insert(thd, table_list, insert_table_list,
- table_list->table, fields, values,
- update_fields, update_values, duplic)))
+ if ((res= 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;
its.rewind();
+ res= TRUE;
+
+ if (table_list->lock_type == TL_WRITE_DELAYED &&
+ !(table_list->table->file->table_flags() & HA_CAN_INSERT_DELAYED))
+ {
+ my_error(ER_ILLEGAL_HA, MYF(0), (table_list->view ?
+ table_list->view_name.str :
+ table_list->table_name));
+ goto error;
+ }
while ((values= its++))
{
counter++;
if (values->elements != value_count)
{
- my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
- ER(ER_WRONG_VALUE_COUNT_ON_ROW),
- MYF(0), counter);
+ my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto error;
}
- if (setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0))
+ if (setup_fields(thd, 0, table_list, *values, 0, 0, 0))
goto error;
}
}
- res= 0;
+ res= FALSE;
error:
lex->unit.cleanup();
- table_list->table->insert_values=0;
+ /* insert_values is cleared in open_table */
DBUG_RETURN(res);
}
@@ -954,39 +986,83 @@ error:
RETURN VALUE
0 success
- 1 error, sent to client
- -1 error, not sent to client
+ 2 convert to multi_update
+ 1 error
*/
static int mysql_test_update(Prepared_statement *stmt,
- TABLE_LIST *table_list)
+ TABLE_LIST *table_list)
{
int res;
THD *thd= stmt->thd;
+ uint table_count= 0;
SELECT_LEX *select= &stmt->lex->select_lex;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ uint want_privilege;
+#endif
DBUG_ENTER("mysql_test_update");
- if ((res= update_precheck(thd, table_list)))
- DBUG_RETURN(res);
+ if (update_precheck(thd, table_list))
+ DBUG_RETURN(1);
- if (open_and_lock_tables(thd, table_list))
- res= -1;
- else
+ if (!open_tables(thd, &table_list, &table_count))
{
- TABLE_LIST *update_table_list= (TABLE_LIST *)select->table_list.first;
+ if (table_list->ancestor && table_list->ancestor->next_local)
+ {
+ DBUG_ASSERT(table_list->view != 0);
+ DBUG_PRINT("info", ("Switch to multi-update"));
+ /* pass counter value */
+ thd->lex->table_count= table_count;
+ /* convert to multiupdate */
+ return 2;
+ }
+
+ /*
+ thd->fill_derived_tables() is false here for sure (because it is
+ preparation of PS, so we even do not check it
+ */
+ if (lock_tables(thd, table_list, table_count) ||
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare))
+ DBUG_RETURN(1);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* TABLE_LIST contain right privilages request */
+ want_privilege= table_list->grant.want_privilege;
+#endif
+
if (!(res= mysql_prepare_update(thd, table_list,
- update_table_list,
&select->where,
select->order_list.elements,
(ORDER *) select->order_list.first)))
{
- if (setup_fields(thd, 0, update_table_list,
- select->item_list, 1, 0, 0) ||
- setup_fields(thd, 0, update_table_list,
- stmt->lex->value_list, 0, 0, 0))
- res= -1;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ table_list->grant.want_privilege=
+ table_list->table->grant.want_privilege=
+ want_privilege;
+#endif
+ thd->lex->select_lex.no_wrap_view_item= 1;
+ if (setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0))
+ {
+ res= 1;
+ thd->lex->select_lex.no_wrap_view_item= 0;
+ }
+ else
+ {
+ thd->lex->select_lex.no_wrap_view_item= 0;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* Check values */
+ table_list->grant.want_privilege=
+ 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))
+ res= 1;
+ }
}
stmt->lex->unit.cleanup();
}
+ else
+ res= 1;
/* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(res);
}
@@ -1001,30 +1077,37 @@ static int mysql_test_update(Prepared_statement *stmt,
tables list of tables queries
RETURN VALUE
- 0 success
- 1 error, sent to client
- -1 error, not sent to client
+ FALSE success
+ TRUE error
*/
static int mysql_test_delete(Prepared_statement *stmt,
TABLE_LIST *table_list)
{
- int res;
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
DBUG_ENTER("mysql_test_delete");
- if ((res= delete_precheck(thd, table_list)))
- DBUG_RETURN(res);
+ if (delete_precheck(thd, table_list))
+ DBUG_RETURN(TRUE);
- if (open_and_lock_tables(thd, table_list))
- res= -1;
- else
+ if (!open_and_lock_tables(thd, table_list))
{
+ bool res;
+ if (!table_list->table)
+ {
+ DBUG_ASSERT(table_list->view &&
+ table_list->ancestor && table_list->ancestor->next_local);
+ my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
+ table_list->view_db.str, table_list->view_name.str);
+ DBUG_RETURN(-1);
+ }
+
res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where);
lex->unit.cleanup();
+ DBUG_RETURN(res);
}
/* TODO: here we should send types of placeholders to the client. */
- DBUG_RETURN(res);
+ DBUG_RETURN(TRUE);
}
@@ -1039,9 +1122,8 @@ static int mysql_test_delete(Prepared_statement *stmt,
tables list of tables queries
RETURN VALUE
- 0 success
- 1 error, sent to client
- -1 error, not sent to client
+ FALSE success
+ TRUE error, sent to client
*/
static int mysql_test_select(Prepared_statement *stmt,
@@ -1050,7 +1132,7 @@ static int mysql_test_select(Prepared_statement *stmt,
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX_UNIT *unit= &lex->unit;
- int result= 1;
+ bool result;
DBUG_ENTER("mysql_test_select");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1058,30 +1140,29 @@ static int mysql_test_select(Prepared_statement *stmt,
if (tables)
{
if (check_table_access(thd, privilege, tables,0))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
else if (check_access(thd, privilege, any_db,0,0,0))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
#endif
+ result= TRUE;
if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
- {
- send_error(thd);
goto err;
- }
if (open_and_lock_tables(thd, tables))
- {
- send_error(thd);
goto err;
- }
+
thd->used_tables= 0; // Updated by setup_fields
- // JOIN::prepare calls
+ /*
+ JOIN::prepare calls
+ It is not SELECT COMMAND for sure, so setup_tables will be called as
+ usual, and we pass 0 as setup_tables_done_option
+ */
if (unit->prepare(thd, 0, 0, ""))
{
- send_error(thd);
goto err_prep;
}
if (!text_protocol)
@@ -1106,12 +1187,12 @@ static int mysql_test_select(Prepared_statement *stmt,
prepared in unit->prepare call above.
*/
if (send_prep_stmt(stmt, lex->result->field_count(fields)) ||
- lex->result->send_fields(fields, 0) ||
+ lex->result->send_fields(fields, Protocol::SEND_EOF) ||
thd->protocol->flush())
goto err_prep;
}
}
- result= 0; // ok
+ result= FALSE; // ok
err_prep:
unit->cleanup();
@@ -1130,30 +1211,27 @@ err:
values list of expressions
RETURN VALUE
- 0 success
- 1 error, sent to client
- -1 error, not sent to client
+ FALSE success
+ TRUE error, sent to client
*/
-static int mysql_test_do_fields(Prepared_statement *stmt,
+static bool mysql_test_do_fields(Prepared_statement *stmt,
TABLE_LIST *tables,
List<Item> *values)
{
DBUG_ENTER("mysql_test_do_fields");
THD *thd= stmt->thd;
- int res= 0;
- if (tables && (res= check_table_access(thd, SELECT_ACL, tables, 0)))
- DBUG_RETURN(res);
+ bool res;
+ if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
+ DBUG_RETURN(TRUE);
- if (tables && (res= open_and_lock_tables(thd, tables)))
+ if (open_and_lock_tables(thd, tables))
{
- DBUG_RETURN(res);
+ DBUG_RETURN(TRUE);
}
res= setup_fields(thd, 0, 0, *values, 0, 0, 0);
stmt->lex->unit.cleanup();
- if (res)
- DBUG_RETURN(-1);
- DBUG_RETURN(0);
+ DBUG_RETURN(res);
}
@@ -1167,31 +1245,30 @@ static int mysql_test_do_fields(Prepared_statement *stmt,
values list of expressions
RETURN VALUE
- 0 success
- 1 error, sent to client
- -1 error, not sent to client
+ FALSE success
+ TRUE error
*/
-static int mysql_test_set_fields(Prepared_statement *stmt,
- TABLE_LIST *tables,
- List<set_var_base> *var_list)
+static bool mysql_test_set_fields(Prepared_statement *stmt,
+ TABLE_LIST *tables,
+ List<set_var_base> *var_list)
{
DBUG_ENTER("mysql_test_set_fields");
List_iterator_fast<set_var_base> it(*var_list);
THD *thd= stmt->thd;
set_var_base *var;
- int res= 0;
+ bool res;
- if (tables && (res= check_table_access(thd, SELECT_ACL, tables, 0)))
- DBUG_RETURN(res);
+ if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
+ DBUG_RETURN(TRUE);
- if (tables && (res= open_and_lock_tables(thd, tables)))
+ if ((res= open_and_lock_tables(thd, tables)))
goto error;
while ((var= it++))
{
if (var->light_check(thd))
{
stmt->lex->unit.cleanup();
- res= -1;
+ res= TRUE;
goto error;
}
}
@@ -1205,32 +1282,40 @@ error:
Check internal SELECT of the prepared command
SYNOPSIS
- select_like_statement_test()
- stmt - prepared table handler
- tables - global list of tables
+ select_like_stmt_test()
+ stmt - prepared statement handler
+ specific_prepare - function of command specific prepare
+ setup_tables_done_option - options to be passed to LEX::unit.prepare()
+
+ NOTE
+ This function won't directly open tables used in select. They should
+ be opened either by calling function (and in this case you probably
+ should use select_like_stmt_test_with_open_n_lock()) or by
+ "specific_prepare" call (like this happens in case of multi-update).
RETURN VALUE
- 0 success
- 1 error, sent to client
- -1 error, not sent to client
+ FALSE success
+ TRUE error
*/
-static int select_like_statement_test(Prepared_statement *stmt,
- TABLE_LIST *tables)
+
+static bool select_like_stmt_test(Prepared_statement *stmt,
+ bool (*specific_prepare)(THD *thd),
+ ulong setup_tables_done_option)
{
- DBUG_ENTER("select_like_statement_test");
+ DBUG_ENTER("select_like_stmt_test");
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
- int res= 0;
+ bool res= FALSE;
- if (tables && (res= open_and_lock_tables(thd, tables)))
+ if (specific_prepare && (res= (*specific_prepare)(thd)))
goto end;
thd->used_tables= 0; // Updated by setup_fields
// JOIN::prepare calls
- if (lex->unit.prepare(thd, 0, 0, ""))
+ if (lex->unit.prepare(thd, 0, setup_tables_done_option, ""))
{
- res= thd->net.report_error ? -1 : 1;
+ res= TRUE;
}
end:
lex->unit.cleanup();
@@ -1239,6 +1324,44 @@ end:
/*
+ Check internal SELECT of the prepared command (with opening and
+ locking tables used).
+
+ SYNOPSIS
+ select_like_stmt_test_with_open_n_lock()
+ stmt - prepared statement handler
+ tables - list of tables to be opened and locked
+ before calling specific_prepare function
+ specific_prepare - function of command specific prepare
+ setup_tables_done_option - options to be passed to LEX::unit.prepare()
+
+ RETURN VALUE
+ FALSE success
+ TRUE error
+*/
+
+static bool
+select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt,
+ TABLE_LIST *tables,
+ bool (*specific_prepare)(THD *thd),
+ ulong setup_tables_done_option)
+{
+ DBUG_ENTER("select_like_stmt_test_with_open_n_lock");
+
+ /*
+ We should not call LEX::unit.cleanup() after this open_and_lock_tables()
+ call because we don't allow prepared EXPLAIN yet so derived tables will
+ clean up after themself.
+ */
+ if (open_and_lock_tables(stmt->thd, tables))
+ DBUG_RETURN(TRUE);
+
+ DBUG_RETURN(select_like_stmt_test(stmt, specific_prepare,
+ setup_tables_done_option));
+}
+
+
+/*
Validate and prepare for execution CREATE TABLE statement
SYNOPSIS
@@ -1251,31 +1374,29 @@ end:
1 error, sent to client
-1 error, not sent to client
*/
-static int mysql_test_create_table(Prepared_statement *stmt,
- TABLE_LIST *tables)
+
+static int mysql_test_create_table(Prepared_statement *stmt)
{
DBUG_ENTER("mysql_test_create_table");
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX *select_lex= &lex->select_lex;
int res= 0;
-
/* Skip first table, which is the table we are creating */
- TABLE_LIST *create_table, *create_table_local;
- tables= lex->unlink_first_table(tables, &create_table,
- &create_table_local);
+ bool link_to_local;
+ TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
+ TABLE_LIST *tables= lex->query_tables;
if (!(res= create_table_precheck(thd, tables, create_table)) &&
select_lex->item_list.elements)
{
select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
- res= select_like_statement_test(stmt, tables);
+ 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 */
- tables= lex->link_first_table_back(tables, create_table,
- create_table_local);
+ lex->link_first_table_back(create_table, link_to_local);
DBUG_RETURN(res);
}
@@ -1287,19 +1408,23 @@ static int mysql_test_create_table(Prepared_statement *stmt,
mysql_test_multiupdate()
stmt prepared statemen handler
tables list of tables queries
+ converted converted to multi-update from usual update
RETURN VALUE
- 0 success
- 1 error, sent to client
- -1 error, not sent to client
+ FALSE success
+ TRUE error
*/
-static int mysql_test_multiupdate(Prepared_statement *stmt,
- TABLE_LIST *tables)
+
+static bool mysql_test_multiupdate(Prepared_statement *stmt,
+ TABLE_LIST *tables,
+ bool converted)
{
- int res;
- if ((res= multi_update_precheck(stmt->thd, tables)))
- return res;
- return select_like_statement_test(stmt, tables);
+ /* if we switched from normal update, rights are checked */
+ if (!converted && multi_update_precheck(stmt->thd, tables))
+ return TRUE;
+
+ return select_like_stmt_test(stmt, &mysql_multi_update_prepare,
+ OPTION_SETUP_TABLES_DONE);
}
@@ -1327,7 +1452,47 @@ static int mysql_test_multidelete(Prepared_statement *stmt,
uint fake_counter;
if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter)))
return res;
- return select_like_statement_test(stmt, tables);
+ if ((res= select_like_stmt_test_with_open_n_lock(stmt, tables,
+ &mysql_multi_delete_prepare,
+ OPTION_SETUP_TABLES_DONE)))
+ return res;
+ if (!tables->table)
+ {
+ DBUG_ASSERT(tables->view &&
+ tables->ancestor && tables->ancestor->next_local);
+ my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
+ tables->view_db.str, tables->view_name.str);
+ return -1;
+ }
+ return 0;
+
+}
+
+
+/*
+ Wrapper for mysql_insert_select_prepare, to make change of local tables
+ after open_and_lock_tables() call.
+
+ SYNOPSIS
+ mysql_insert_select_prepare_tester()
+ thd thread handler
+
+ NOTE: we need remove first local tables after open_and_lock_tables,
+ because mysql_handle_derived use local tables lists
+*/
+
+static bool mysql_insert_select_prepare_tester(THD *thd)
+{
+ 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;
+ /*
+ 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);
}
@@ -1337,31 +1502,38 @@ static int mysql_test_multidelete(Prepared_statement *stmt,
SYNOPSIS
mysql_test_insert_select()
stmt prepared statemen handler
- tables list of tables queries
+ tables list of tables of query
RETURN VALUE
0 success
1 error, sent to client
-1 error, not sent to client
*/
+
static int mysql_test_insert_select(Prepared_statement *stmt,
TABLE_LIST *tables)
{
int res;
LEX *lex= stmt->lex;
+ TABLE_LIST *first_local_table;
+
+ if (tables->table)
+ {
+ // don't allocate insert_values
+ tables->table->insert_values=(byte *)1;
+ }
+
if ((res= insert_precheck(stmt->thd, tables)))
return res;
- TABLE_LIST *first_local_table=
- (TABLE_LIST *)lex->select_lex.table_list.first;
- /* Skip first table, which is the table we are inserting in */
- lex->select_lex.table_list.first= (byte*) first_local_table->next;
- /*
- insert/replace from SELECT give its SELECT_LEX for SELECT,
- and item_list belong to SELECT
- */
- lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
- res= select_like_statement_test(stmt, tables);
- /* revert changes*/
+
+ /* store it, because mysql_insert_select_prepare_tester change it */
+ 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);
+ /* 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;
@@ -1369,30 +1541,39 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
/*
- Send the prepare query results back to client
+ Perform semantic analysis of the parsed tree and send a response packet
+ to the client.
+
SYNOPSIS
- send_prepare_results()
- stmt prepared statement
+ check_prepared_statement()
+ stmt prepared statement
+
+ DESCRIPTION
+ This function
+ - opens all tables and checks access rights
+ - validates semantics of statement columns and SQL functions
+ by calling fix_fields.
+
RETURN VALUE
0 success
1 error, sent to client
*/
-static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
-{
+
+static int check_prepared_statement(Prepared_statement *stmt,
+ bool text_protocol)
+{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX *select_lex= &lex->select_lex;
- TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
+ TABLE_LIST *tables;
enum enum_sql_command sql_command= lex->sql_command;
int res= 0;
- DBUG_ENTER("send_prepare_results");
+ DBUG_ENTER("check_prepared_statement");
DBUG_PRINT("enter",("command: %d, param_count: %ld",
sql_command, stmt->param_count));
- if ((&lex->select_lex != lex->all_selects_list ||
- lex->time_zone_tables_used) &&
- lex->unit.create_total_list(thd, lex, &tables))
- DBUG_RETURN(1);
+ lex->first_lists_tables_same();
+ tables= lex->query_tables;
switch (sql_command) {
case SQLCOM_REPLACE:
@@ -1405,6 +1586,12 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
case SQLCOM_UPDATE:
res= mysql_test_update(stmt, tables);
+ /* mysql_test_update return 2 if we need to switch to multi-update */
+ if (res != 2)
+ break;
+
+ case SQLCOM_UPDATE_MULTI:
+ res= mysql_test_multiupdate(stmt, tables, res == 2);
break;
case SQLCOM_DELETE:
@@ -1418,7 +1605,7 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
DBUG_RETURN(0);
case SQLCOM_CREATE_TABLE:
- res= mysql_test_create_table(stmt, tables);
+ res= mysql_test_create_table(stmt);
break;
case SQLCOM_DO:
@@ -1432,10 +1619,6 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
case SQLCOM_DELETE_MULTI:
res= mysql_test_multidelete(stmt, tables);
break;
-
- case SQLCOM_UPDATE_MULTI:
- res= mysql_test_multiupdate(stmt, tables);
- break;
case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE_SELECT:
@@ -1460,6 +1643,13 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
case SQLCOM_SHOW_GRANTS:
case SQLCOM_DROP_TABLE:
case SQLCOM_RENAME_TABLE:
+ case SQLCOM_ALTER_TABLE:
+ case SQLCOM_COMMIT:
+ case SQLCOM_CREATE_INDEX:
+ case SQLCOM_DROP_INDEX:
+ case SQLCOM_ROLLBACK:
+ case SQLCOM_TRUNCATE:
+ case SQLCOM_CALL:
break;
default:
@@ -1467,15 +1657,13 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
All other is not supported yet
*/
res= -1;
- my_error(ER_UNSUPPORTED_PS, MYF(0));
+ my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
goto error;
}
if (res == 0)
DBUG_RETURN(text_protocol? 0 : (send_prep_stmt(stmt, 0) ||
thd->protocol->flush()));
error:
- if (res < 0)
- send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
DBUG_RETURN(1);
}
@@ -1488,15 +1676,13 @@ error:
static bool init_param_array(Prepared_statement *stmt)
{
LEX *lex= stmt->lex;
- THD *thd= stmt->thd;
if ((stmt->param_count= lex->param_list.elements))
{
if (stmt->param_count > (uint) UINT_MAX16)
{
/* Error code to be defined in 5.0 */
- send_error(thd, ER_UNKNOWN_ERROR,
- "Prepared statement contains too many placeholders.");
- return 1;
+ my_message(ER_PS_MANY_PARAM, ER(ER_PS_MANY_PARAM), MYF(0));
+ return TRUE;
}
Item_param **to;
List_iterator<Item_param> param_iterator(lex->param_list);
@@ -1505,10 +1691,7 @@ static bool init_param_array(Prepared_statement *stmt)
alloc_root(stmt->thd->mem_root,
sizeof(Item_param*) * stmt->param_count);
if (!stmt->param_array)
- {
- send_error(thd, ER_OUT_OF_RESOURCES);
- return 1;
- }
+ return TRUE;
for (to= stmt->param_array;
to < stmt->param_array + stmt->param_count;
++to)
@@ -1516,7 +1699,7 @@ static bool init_param_array(Prepared_statement *stmt)
*to= param_iterator++;
}
}
- return 0;
+ return FALSE;
}
/*
@@ -1531,10 +1714,10 @@ static bool init_param_array(Prepared_statement *stmt)
name NULL or statement name. For unnamed statements binary PS
protocol is used, for named statements text protocol is
used.
- RETURN
- 0 OK, statement prepared successfully
- other Error
-
+ RETURN
+ FALSE OK, statement prepared successfully
+ TRUE Error
+
NOTES
This function parses the query and sends the total number of parameters
and resultset metadata information back to client (if any), without
@@ -1548,21 +1731,18 @@ static bool init_param_array(Prepared_statement *stmt)
*/
-int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
- LEX_STRING *name)
+bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
+ LEX_STRING *name)
{
LEX *lex;
Prepared_statement *stmt= new Prepared_statement(thd);
- int error;
+ bool error;
DBUG_ENTER("mysql_stmt_prepare");
DBUG_PRINT("prep_query", ("%s", packet));
if (stmt == 0)
- {
- send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_RETURN(1);
- }
+ DBUG_RETURN(TRUE);
if (name)
{
@@ -1571,16 +1751,14 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
name->length)))
{
delete stmt;
- send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
}
if (thd->stmt_map.insert(stmt))
{
delete stmt;
- send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
thd->set_n_backup_statement(stmt, &thd->stmt_backup);
@@ -1592,8 +1770,7 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
- send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
mysql_log.write(thd, COM_PREPARE, "[%lu] %s", stmt->id, packet);
@@ -1601,15 +1778,15 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
thd->current_arena= stmt;
mysql_init_query(thd, (uchar *) thd->query, thd->query_length);
/* Reset warnings from previous command */
- mysql_reset_errors(thd);
+ mysql_reset_errors(thd, 0);
lex= thd->lex;
lex->safe_to_cache_query= 0;
error= yyparse((void *)thd) || thd->is_fatal_error ||
thd->net.report_error || init_param_array(stmt);
/*
- While doing context analysis of the query (in send_prepare_results) we
- allocate a lot of additional memory: for open tables, JOINs, derived
+ While doing context analysis of the query (in check_prepared_statement)
+ we allocate a lot of additional memory: for open tables, JOINs, derived
tables, etc. Let's save a snapshot of current parse tree to the
statement and restore original THD. In cases when some tree
transformation can be reused on execute, we set again thd->mem_root from
@@ -1618,18 +1795,22 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
if (!error)
- error= send_prepare_results(stmt, test(name));
+ error= check_prepared_statement(stmt, test(name));
/* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
+ if (error && thd->lex->sphead)
+ {
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
lex_end(lex);
+ close_thread_tables(thd);
thd->restore_backup_statement(stmt, &thd->stmt_backup);
cleanup_items(stmt->free_list);
- close_thread_tables(thd);
- free_items(thd->free_list);
thd->rollback_item_tree_changes();
- thd->free_list= 0;
+ thd->cleanup_after_query();
thd->current_arena= thd;
if (error)
@@ -1637,74 +1818,75 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
stmt= NULL;
- if (thd->net.report_error)
- send_error(thd);
- /* otherwise the error is sent inside yyparse/send_prepare_results */
}
else
{
stmt->setup_set_params();
- SELECT_LEX *sl= stmt->lex->all_selects_list;
- /*
- Save WHERE clause pointers, because they may be changed during query
- optimisation.
- */
- for (; sl; sl= sl->next_select_in_list())
- {
- sl->prep_where= sl->where;
- }
+ init_stmt_after_parse(thd, stmt->lex);
stmt->state= Item_arena::PREPARED;
}
-
DBUG_RETURN(!stmt);
}
-/* Reinit statement before execution */
-static void reset_stmt_for_execute(Prepared_statement *stmt)
+/*
+ Init PS/SP specific parse tree members.
+*/
+
+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.
+ */
+ for (; sl; sl= sl->next_select_in_list())
+ sl->prep_where= sl->where;
+
+ for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global)
+ table->prep_on_expr= table->on_expr;
+}
+
+
+/* Reinit prepared statement/stored procedure before execution */
+
+void reset_stmt_for_execute(THD *thd, LEX *lex)
{
- THD *thd= stmt->thd;
- LEX *lex= stmt->lex;
SELECT_LEX *sl= lex->all_selects_list;
+ DBUG_ENTER("reset_stmt_for_execute");
+ if (lex->empty_field_list_on_rset)
+ {
+ lex->empty_field_list_on_rset= 0;
+ lex->field_list.empty();
+ }
for (; sl; sl= sl->next_select_in_list())
{
- /* remove option which was put by mysql_explain_union() */
- sl->options&= ~SELECT_DESCRIBE;
- /*
- Copy WHERE clause pointers to avoid damaging they by optimisation
- */
- if (sl->prep_where)
+ if (!sl->first_execution)
{
- sl->where= sl->prep_where->copy_andor_structure(thd);
- sl->where->cleanup();
- }
- DBUG_ASSERT(sl->join == 0);
- ORDER *order;
- /* Fix GROUP list */
- for (order= (ORDER *)sl->group_list.first; order; order= order->next)
- order->item= &order->item_ptr;
- /* Fix ORDER list */
- for (order= (ORDER *)sl->order_list.first; order; order= order->next)
- order->item= &order->item_ptr;
+ /* remove option which was put by mysql_explain_union() */
+ sl->options&= ~SELECT_DESCRIBE;
+
+ /* see unique_table() */
+ sl->exclude_from_table_unique_test= FALSE;
- /*
- TODO: When the new table structure is ready, then have a status bit
- to indicate the table is altered, and re-do the setup_*
- and open the tables back.
- */
- for (TABLE_LIST *tables= (TABLE_LIST*) sl->table_list.first;
- tables;
- tables= tables->next)
- {
/*
- Reset old pointers to TABLEs: they are not valid since the tables
- were closed in the end of previous prepare or execute call.
+ Copy WHERE clause pointers to avoid damaging they by optimisation
*/
- tables->table= 0;
- tables->table_list= 0;
+ if (sl->prep_where)
+ {
+ sl->where= sl->prep_where->copy_andor_structure(thd);
+ sl->where->cleanup();
+ }
+ DBUG_ASSERT(sl->join == 0);
+ ORDER *order;
+ /* Fix GROUP list */
+ for (order= (ORDER *)sl->group_list.first; order; order= order->next)
+ order->item= &order->item_ptr;
+ /* Fix ORDER list */
+ for (order= (ORDER *)sl->order_list.first; order; order= order->next)
+ order->item= &order->item_ptr;
}
-
{
SELECT_LEX_UNIT *unit= sl->master_unit();
unit->unclean();
@@ -1713,9 +1895,45 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
unit->reinit_exec_mechanism();
}
}
+
+ /*
+ TODO: When the new table structure is ready, then have a status bit
+ to indicate the table is altered, and re-do the setup_*
+ and open the tables back.
+ */
+ /*
+ NOTE: We should reset whole table list here including all tables added
+ by prelocking algorithm (it is not a problem for substatements since
+ they have their own table list).
+ */
+ for (TABLE_LIST *tables= lex->query_tables;
+ tables;
+ tables= tables->next_global)
+ {
+ /*
+ Reset old pointers to TABLEs: they are not valid since the tables
+ were closed in the end of previous prepare or execute call.
+ */
+ tables->table= 0;
+ if (tables->nested_join)
+ tables->nested_join->counter= 0;
+
+ if (tables->prep_on_expr)
+ {
+ tables->on_expr= tables->prep_on_expr->copy_andor_structure(thd);
+ tables->on_expr->cleanup();
+ }
+ }
lex->current_select= &lex->select_lex;
+
+ /* restore original list used in INSERT ... SELECT */
+ if (lex->leaf_tables_insert)
+ lex->select_lex.leaf_tables= lex->leaf_tables_insert;
+
if (lex->result)
lex->result->cleanup();
+
+ DBUG_VOID_RETURN;
}
@@ -1750,6 +1968,8 @@ static void reset_stmt_params(Prepared_statement *stmt)
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
ulong stmt_id= uint4korr(packet);
+ ulong flags= (ulong) ((uchar) packet[4]);
+ Cursor *cursor= 0;
/*
Query text for binary log, or empty string if the query is not put into
binary log.
@@ -1763,8 +1983,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
packet+= 9; /* stmt_id + 5 bytes of flags */
- if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute",
- SEND_ERROR)))
+ if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute")))
DBUG_VOID_RETURN;
DBUG_PRINT("exec_query:", ("%s", stmt->query));
@@ -1772,12 +1991,35 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
/* Check if we got an error when sending long data */
if (stmt->state == Item_arena::ERROR)
{
- send_error(thd, stmt->last_errno, stmt->last_error);
+ my_message(stmt->last_errno, stmt->last_error, MYF(0));
DBUG_VOID_RETURN;
}
DBUG_ASSERT(thd->free_list == NULL);
mysql_reset_thd_for_next_command(thd);
+ if (flags & (ulong) CURSOR_TYPE_READ_ONLY)
+ {
+ if (!stmt->lex->result || !stmt->lex->result->simple_select())
+ {
+ DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
+ /*
+ If lex->result is set in the parser, this is not a SELECT
+ statement: we can't open a cursor for it.
+ */
+ flags= 0;
+ my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
+ goto err;
+ }
+ else
+ {
+ DBUG_PRINT("info",("Using READ_ONLY cursor"));
+ if (!stmt->cursor &&
+ !(cursor= stmt->cursor= new (&stmt->main_mem_root) Cursor()))
+ DBUG_VOID_RETURN;
+ /* If lex->result is set, mysql_execute_command will use it */
+ stmt->lex->result= &cursor->result;
+ }
+ }
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count)
{
@@ -1796,18 +2038,54 @@ 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->current_arena= stmt;
+ reset_stmt_for_execute(thd, stmt->lex);
+ /* From now cursors assume that thd->mem_root is clean */
+ if (expanded_query.length() &&
+ alloc_query(thd, (char *)expanded_query.ptr(),
+ expanded_query.length()+1))
+ {
+ my_error(ER_OUTOFMEMORY, 0, expanded_query.length());
+ goto err;
+ }
+
mysql_log.write(thd, COM_EXECUTE, "[%lu] %s", stmt->id,
expanded_query.length() ? expanded_query.c_ptr() :
stmt->query);
+
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
- execute_stmt(thd, stmt, &expanded_query, TRUE);
+ if (!(specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(),QUERY_PRIOR);
+ mysql_execute_command(thd);
+ if (!(specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(), WAIT_PRIOR);
thd->protocol= &thd->protocol_simple; // Use normal protocol
+
+ if (cursor && cursor->is_open())
+ {
+ cursor->init_from_thd(thd);
+ cursor->state= stmt->state;
+ }
+ else
+ {
+ thd->lex->unit.cleanup();
+ cleanup_items(stmt->free_list);
+ reset_stmt_params(stmt);
+ close_thread_tables(thd); /* to close derived tables */
+ thd->rollback_item_tree_changes();
+ thd->cleanup_after_query();
+ }
+
+ thd->set_statement(&thd->stmt_backup);
+ thd->current_arena= thd;
DBUG_VOID_RETURN;
set_params_data_err:
reset_stmt_params(stmt);
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
- send_error(thd);
+err:
DBUG_VOID_RETURN;
}
@@ -1827,33 +2105,32 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
String expanded_query;
DBUG_ENTER("mysql_sql_stmt_execute");
+ DBUG_ASSERT(thd->free_list == NULL);
+
if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name)))
{
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_name->length,
stmt_name->str, "EXECUTE");
- send_error(thd);
DBUG_VOID_RETURN;
}
if (stmt->param_count != thd->lex->prepared_stmt_params.elements)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
- send_error(thd);
DBUG_VOID_RETURN;
}
- DBUG_ASSERT(thd->free_list == NULL);
/* 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);
if (stmt->set_params_from_vars(stmt,
thd->stmt_backup.lex->prepared_stmt_params,
&expanded_query))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
- send_error(thd);
}
- execute_stmt(thd, stmt, &expanded_query, FALSE);
+ execute_stmt(thd, stmt, &expanded_query);
DBUG_VOID_RETURN;
}
@@ -1868,23 +2145,21 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
placeholders replaced with actual values. Otherwise empty
string.
NOTES
- Caller must set parameter values and thd::protocol.
- thd->free_list is assumed to be garbage.
+ Caller must set parameter values and thd::protocol.
*/
static void execute_stmt(THD *thd, Prepared_statement *stmt,
- String *expanded_query, bool set_context)
+ String *expanded_query)
{
DBUG_ENTER("execute_stmt");
- if (set_context)
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
- reset_stmt_for_execute(stmt);
+
+ reset_stmt_for_execute(thd, stmt->lex);
if (expanded_query->length() &&
alloc_query(thd, (char *)expanded_query->ptr(),
expanded_query->length()+1))
{
- my_error(ER_OUTOFMEMORY, 0, expanded_query->length());
+ my_error(ER_OUTOFMEMORY, MYF(0), expanded_query->length());
DBUG_VOID_RETURN;
}
/*
@@ -1897,21 +2172,68 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
mysql_execute_command(thd);
- thd->lex->unit.cleanup();
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
- /* Free Items that were created during this execution of the PS. */
- free_items(thd->free_list);
- thd->free_list= 0;
- if (stmt->state == Item_arena::PREPARED)
- stmt->state= Item_arena::EXECUTED;
+ thd->lex->unit.cleanup();
thd->current_arena= thd;
cleanup_items(stmt->free_list);
thd->rollback_item_tree_changes();
reset_stmt_params(stmt);
close_thread_tables(thd); // to close derived tables
thd->set_statement(&thd->stmt_backup);
+ thd->cleanup_after_query();
+
+ if (stmt->state == Item_arena::PREPARED)
+ stmt->state= Item_arena::EXECUTED;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ COM_FETCH handler: fetches requested amount of rows from cursor
+
+ SYNOPSIS
+ mysql_stmt_fetch()
+ thd Thread handler
+ packet Packet from client (with stmt_id & num_rows)
+ packet_length Length of packet
+*/
+
+void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
+{
+ /* assume there is always place for 8-16 bytes */
+ ulong stmt_id= uint4korr(packet);
+ ulong num_rows= uint4korr(packet+=4);
+ Statement *stmt;
+ DBUG_ENTER("mysql_stmt_fetch");
+
+ if (!(stmt= thd->stmt_map.find(stmt_id)) ||
+ !stmt->cursor ||
+ !stmt->cursor->is_open())
+ {
+ my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_id, "fetch");
+ DBUG_VOID_RETURN;
+ }
+ thd->current_arena= stmt;
+ thd->set_n_backup_statement(stmt, &thd->stmt_backup);
+ stmt->cursor->init_thd(thd);
+
+ 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);
+ thd->protocol= &thd->protocol_simple; // Use normal protocol
+
+ if (!(specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(), WAIT_PRIOR);
+
+ /* Restore THD state */
+ stmt->cursor->reset_thd(thd);
+ thd->restore_backup_statement(stmt, &thd->stmt_backup);
+ thd->current_arena= thd;
+
DBUG_VOID_RETURN;
}
@@ -1921,7 +2243,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
SYNOPSIS
mysql_stmt_reset()
thd Thread handle
- packet Packet with stmt id
+ packet Packet with stmt id
DESCRIPTION
This function resets statement to the state it was right after prepare.
@@ -1941,8 +2263,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
DBUG_ENTER("mysql_stmt_reset");
- if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset",
- SEND_ERROR)))
+ if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
DBUG_VOID_RETURN;
stmt->state= Item_arena::PREPARED;
@@ -1973,8 +2294,7 @@ void mysql_stmt_free(THD *thd, char *packet)
DBUG_ENTER("mysql_stmt_free");
- if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close",
- DONT_SEND_ERROR)))
+ if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close")))
DBUG_VOID_RETURN;
/* Statement map deletes statement on erase */
@@ -2024,8 +2344,8 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
stmt_id= uint4korr(packet);
packet+= 4;
- if (!(stmt=find_prepared_statement(thd, stmt_id, "mysql_stmt_send_long_data",
- DONT_SEND_ERROR)))
+ if (!(stmt=find_prepared_statement(thd, stmt_id,
+ "mysql_stmt_send_long_data")))
DBUG_VOID_RETURN;
param_number= uint2korr(packet);
@@ -2091,8 +2411,11 @@ void Prepared_statement::setup_set_params()
}
}
+
Prepared_statement::~Prepared_statement()
{
+ if (cursor)
+ cursor->Cursor::~Cursor();
free_items(free_list);
delete lex->result;
}
@@ -2102,4 +2425,3 @@ Item_arena::Type Prepared_statement::type() const
{
return PREPARED_STATEMENT;
}
-
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 388034e0f1a..8fe17198cf0 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -44,7 +44,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
if (thd->locked_tables || thd->active_transaction())
{
- my_error(ER_LOCK_OR_ACTIVE_TRANSACTION,MYF(0));
+ my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
+ ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
DBUG_RETURN(1);
}
@@ -64,10 +65,10 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
table_list= reverse_table_list(table_list);
/* Find the last renamed table */
- for (table=table_list ;
- table->next != ren_table ;
- table=table->next->next) ;
- table=table->next->next; // Skip error table
+ for (table= table_list;
+ table->next_local != ren_table ;
+ table= table->next_local->next_local) ;
+ table= table->next_local->next_local; // Skip error table
/* Revert to old names */
rename_tables(thd, table, 1);
@@ -80,7 +81,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
/* Lets hope this doesn't fail as the result will be messy */
if (!error)
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error();
@@ -90,7 +90,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
send_ok(thd);
}
- unlock_table_names(thd,table_list);
+ unlock_table_names(thd, table_list, (TABLE_LIST*) 0);
err:
pthread_mutex_unlock(&LOCK_open);
@@ -115,8 +115,8 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list)
while (table_list)
{
- TABLE_LIST *next= table_list->next;
- table_list->next= prev;
+ TABLE_LIST *next= table_list->next_local;
+ table_list->next_local= prev;
prev= table_list;
table_list= next;
}
@@ -135,13 +135,13 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
TABLE_LIST *ren_table,*new_table;
DBUG_ENTER("rename_tables");
- for (ren_table=table_list ; ren_table ; ren_table=new_table->next)
+ for (ren_table= table_list; ren_table; ren_table= new_table->next_local)
{
db_type table_type;
char name[FN_REFLEN];
const char *new_alias, *old_alias;
- new_table=ren_table->next;
+ new_table= ren_table->next_local;
if (lower_case_table_names == 2)
{
old_alias= ren_table->alias;
@@ -149,15 +149,15 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
}
else
{
- old_alias= ren_table->real_name;
- new_alias= new_table->real_name;
+ old_alias= ren_table->table_name;
+ new_alias= new_table->table_name;
}
sprintf(name,"%s/%s/%s%s",mysql_data_home,
new_table->db, new_alias, reg_ext);
unpack_filename(name, name);
if (!access(name,F_OK))
{
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_alias);
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
DBUG_RETURN(ren_table); // This can't be skipped
}
sprintf(name,"%s/%s/%s%s",mysql_data_home,
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index d02bb5ff0a3..0dcfd985f88 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -25,43 +25,46 @@ int max_binlog_dump_events = 0; // unlimited
my_bool opt_sporadic_binlog_dump_fail = 0;
static int binlog_dump_count = 0;
-int check_binlog_magic(IO_CACHE* log, const char** errmsg)
-{
- char magic[4];
- DBUG_ASSERT(my_b_tell(log) == 0);
-
- if (my_b_read(log, (byte*) magic, sizeof(magic)))
- {
- *errmsg = "I/O error reading the header from the binary log";
- sql_print_error("%s, errno=%d, io cache code=%d", *errmsg, my_errno,
- log->error);
- return 1;
- }
- if (memcmp(magic, BINLOG_MAGIC, sizeof(magic)))
- {
- *errmsg = "Binlog has bad magic number; It's not a binary log file that can be used by this version of MySQL";
- return 1;
- }
- return 0;
-}
+/*
+ fake_rotate_event() builds a fake (=which does not exist physically in any
+ binlog) Rotate event, which contains the name of the binlog we are going to
+ send to the slave (because the slave may not know it if it just asked for
+ MASTER_LOG_FILE='', MASTER_LOG_POS=4).
+ < 4.0.14, fake_rotate_event() was called only if the requested pos was 4.
+ After this version we always call it, so that a 3.23.58 slave can rely on
+ it to detect if the master is 4.0 (and stop) (the _fake_ Rotate event has
+ zeros in the good positions which, by chance, make it possible for the 3.23
+ slave to detect that this event is unexpected) (this is luck which happens
+ because the master and slave disagree on the size of the header of
+ Log_event).
+
+ Relying on the event length of the Rotate event instead of these
+ well-placed zeros was not possible as Rotate events have a variable-length
+ part.
+*/
static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
- ulonglong position, const char**errmsg)
+ ulonglong position, const char** errmsg)
{
- char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN];
- memset(header, 0, 4); // when does not matter
+ DBUG_ENTER("fake_rotate_event");
+ char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN+100];
+ /*
+ 'when' (the timestamp) is set to 0 so that slave could distinguish between
+ real and fake Rotate events (if necessary)
+ */
+ memset(header, 0, 4);
header[EVENT_TYPE_OFFSET] = ROTATE_EVENT;
char* p = log_file_name+dirname_length(log_file_name);
uint ident_len = (uint) strlen(p);
- ulong event_len = ident_len + ROTATE_EVENT_OVERHEAD;
+ ulong event_len = ident_len + LOG_EVENT_HEADER_LEN + ROTATE_HEADER_LEN;
int4store(header + SERVER_ID_OFFSET, server_id);
int4store(header + EVENT_LEN_OFFSET, event_len);
int2store(header + FLAGS_OFFSET, 0);
-
+
// TODO: check what problems this may cause and fix them
int4store(header + LOG_POS_OFFSET, 0);
-
+
packet->append(header, sizeof(header));
int8store(buf+R_POS_OFFSET,position);
packet->append(buf, ROTATE_HEADER_LEN);
@@ -69,9 +72,9 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
if (my_net_write(net, (char*)packet->ptr(), packet->length()))
{
*errmsg = "failed on my_net_write()";
- return -1;
+ DBUG_RETURN(-1);
}
- return 0;
+ DBUG_RETURN(0);
}
static int send_file(THD *thd)
@@ -146,41 +149,6 @@ static int send_file(THD *thd)
}
-File open_binlog(IO_CACHE *log, const char *log_file_name,
- const char **errmsg)
-{
- File file;
- DBUG_ENTER("open_binlog");
-
- if ((file = my_open(log_file_name, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
- {
- sql_print_error("Failed to open log (\
-file '%s', errno %d)", log_file_name, my_errno);
- *errmsg = "Could not open log file"; // This will not be sent
- goto err;
- }
- if (init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
- MYF(MY_WME | MY_DONT_CHECK_FILESIZE)))
- {
- sql_print_error("Failed to create a cache on log (\
-file '%s')", log_file_name);
- *errmsg = "Could not open log file"; // This will not be sent
- goto err;
- }
- if (check_binlog_magic(log,errmsg))
- goto err;
- DBUG_RETURN(file);
-
-err:
- if (file >= 0)
- {
- my_close(file,MYF(0));
- end_io_cache(log);
- }
- DBUG_RETURN(-1);
-}
-
-
/*
Adjust the position pointer in the binary log file for all running slaves
@@ -257,41 +225,39 @@ bool log_in_use(const char* log_name)
return result;
}
-int purge_error_message(THD* thd, int res)
+bool purge_error_message(THD* thd, int res)
{
- const char *errmsg= 0;
+ uint errmsg= 0;
switch (res) {
case 0: break;
- case LOG_INFO_EOF: errmsg= "Target log not found in binlog index"; break;
- case LOG_INFO_IO: errmsg= "I/O error reading log index file"; break;
- case LOG_INFO_INVALID:
- errmsg= "Server configuration does not permit binlog purge"; break;
- case LOG_INFO_SEEK: errmsg= "Failed on fseek()"; break;
- case LOG_INFO_MEM: errmsg= "Out of memory"; break;
- case LOG_INFO_FATAL: errmsg= "Fatal error during purge"; break;
- case LOG_INFO_IN_USE: errmsg= "A purgeable log is in use, will not purge";
- break;
- default: errmsg= "Unknown error during purge"; break;
+ case LOG_INFO_EOF: errmsg= ER_UNKNOWN_TARGET_BINLOG; break;
+ case LOG_INFO_IO: errmsg= ER_IO_ERR_LOG_INDEX_READ; break;
+ case LOG_INFO_INVALID:errmsg= ER_BINLOG_PURGE_PROHIBITED; break;
+ case LOG_INFO_SEEK: errmsg= ER_FSEEK_FAIL; break;
+ case LOG_INFO_MEM: errmsg= ER_OUT_OF_RESOURCES; break;
+ case LOG_INFO_FATAL: errmsg= ER_BINLOG_PURGE_FATAL_ERR; break;
+ case LOG_INFO_IN_USE: errmsg= ER_LOG_IN_USE; break;
+ default: errmsg= ER_LOG_PURGE_UNKNOWN_ERR; break;
}
if (errmsg)
{
- send_error(thd, 0, errmsg);
- return 1;
+ my_message(errmsg, ER(errmsg), MYF(0));
+ return TRUE;
}
send_ok(thd);
- return 0;
+ return FALSE;
}
-int purge_master_logs(THD* thd, const char* to_log)
+bool purge_master_logs(THD* thd, const char* to_log)
{
char search_file_name[FN_REFLEN];
if (!mysql_bin_log.is_open())
{
send_ok(thd);
- return 0;
+ return FALSE;
}
mysql_bin_log.make_log_name(search_file_name, to_log);
@@ -301,7 +267,7 @@ int purge_master_logs(THD* thd, const char* to_log)
}
-int purge_master_logs_before_date(THD* thd, time_t purge_time)
+bool purge_master_logs_before_date(THD* thd, time_t purge_time)
{
if (!mysql_bin_log.is_open())
{
@@ -312,6 +278,36 @@ int purge_master_logs_before_date(THD* thd, time_t purge_time)
mysql_bin_log.purge_logs_before_date(purge_time));
}
+int test_for_non_eof_log_read_errors(int error, const char **errmsg)
+{
+ if (error == LOG_READ_EOF)
+ return 0;
+ my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
+ switch (error) {
+ case LOG_READ_BOGUS:
+ *errmsg = "bogus data in log event";
+ break;
+ case LOG_READ_TOO_LARGE:
+ *errmsg = "log event entry exceeded max_allowed_packet; \
+Increase max_allowed_packet on master";
+ break;
+ case LOG_READ_IO:
+ *errmsg = "I/O error reading log event";
+ break;
+ case LOG_READ_MEM:
+ *errmsg = "memory allocation failed reading log event";
+ break;
+ case LOG_READ_TRUNC:
+ *errmsg = "binlog truncated in the middle of event";
+ break;
+ default:
+ *errmsg = "unknown error reading log event on the master";
+ break;
+ }
+ return error;
+}
+
+
/*
TODO: Clean up loop to only have one call to send_file()
*/
@@ -328,6 +324,8 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
int error;
const char *errmsg = "Unknown error";
NET* net = &thd->net;
+ pthread_mutex_t *log_lock;
+ bool binlog_can_be_corrupted= FALSE;
#ifndef DBUG_OFF
int left_events = max_binlog_dump_events;
#endif
@@ -387,43 +385,128 @@ impossible position";
goto err;
}
- my_b_seek(&log, pos); // Seek will done on next read
+ if (thd->variables.sync_replication)
+ ha_repl_report_sent_binlog(thd, log_file_name, pos);
+
/*
We need to start a packet with something other than 255
- to distiquish it from error
+ to distinguish it from error
*/
- packet->set("\0", 1, &my_charset_bin);
+ packet->set("\0", 1, &my_charset_bin); /* This is the start of a new packet */
/*
- Before 4.0.14 we called fake_rotate_event below only if
- (pos == BIN_LOG_HEADER_SIZE), because if this is false then the slave
+ Tell the client about the log name with a fake Rotate event;
+ this is needed even if we also send a Format_description_log_event
+ just after, because that event does not contain the binlog's name.
+ Note that as this Rotate event is sent before
+ Format_description_log_event, the slave cannot have any info to
+ understand this event's format, so the header len of
+ Rotate_log_event is FROZEN (so in 5.0 it will have a header shorter
+ than other events except FORMAT_DESCRIPTION_EVENT).
+ Before 4.0.14 we called fake_rotate_event below only if (pos ==
+ BIN_LOG_HEADER_SIZE), because if this is false then the slave
already knows the binlog's name.
- Now we always call fake_rotate_event; if the slave already knew the log's
- name (ex: CHANGE MASTER TO MASTER_LOG_FILE=...) this is useless but does
- not harm much. It is nice for 3.23 (>=.58) slaves which test Rotate events
- to see if the master is 4.0 (then they choose to stop because they can't
- replicate 4.0); by always calling fake_rotate_event we are sure that
- 3.23.58 and newer will detect the problem as soon as replication starts
- (BUG#198).
+ Since, we always call fake_rotate_event; if the slave already knew
+ the log's name (ex: CHANGE MASTER TO MASTER_LOG_FILE=...) this is
+ useless but does not harm much. It is nice for 3.23 (>=.58) slaves
+ which test Rotate events to see if the master is 4.0 (then they
+ choose to stop because they can't replicate 4.0); by always calling
+ fake_rotate_event we are sure that 3.23.58 and newer will detect the
+ problem as soon as replication starts (BUG#198).
Always calling fake_rotate_event makes sending of normal
- (=from-binlog) Rotate events a priori unneeded, but it is not so simple:
- the 2 Rotate events are not equivalent, the normal one is before the Stop
- event, the fake one is after. If we don't send the normal one, then the
- Stop event will be interpreted (by existing 4.0 slaves) as "the master
- stopped", which is wrong. So for safety, given that we want minimum
- modification of 4.0, we send the normal and fake Rotates.
+ (=from-binlog) Rotate events a priori unneeded, but it is not so
+ simple: the 2 Rotate events are not equivalent, the normal one is
+ before the Stop event, the fake one is after. If we don't send the
+ normal one, then the Stop event will be interpreted (by existing 4.0
+ slaves) as "the master stopped", which is wrong. So for safety,
+ given that we want minimum modification of 4.0, we send the normal
+ and fake Rotates.
*/
if (fake_rotate_event(net, packet, log_file_name, pos, &errmsg))
{
+ /*
+ This error code is not perfect, as fake_rotate_event() does not
+ read anything from the binlog; if it fails it's because of an
+ error in my_net_write(), fortunately it will say so in errmsg.
+ */
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
goto err;
}
packet->set("\0", 1, &my_charset_bin);
- while (!net->error && net->vio != 0 && !thd->killed)
+ /*
+ We can set log_lock now, it does not move (it's a member of
+ mysql_bin_log, and it's already inited, and it will be destroyed
+ only at shutdown).
+ */
+ log_lock = mysql_bin_log.get_log_lock();
+ if (pos > BIN_LOG_HEADER_SIZE)
{
- pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
+ /*
+ Try to find a Format_description_log_event at the beginning of
+ the binlog
+ */
+ if (!(error = Log_event::read_log_event(&log, packet, log_lock)))
+ {
+ /*
+ The packet has offsets equal to the normal offsets in a binlog
+ event +1 (the first character is \0).
+ */
+ DBUG_PRINT("info",
+ ("Looked for a Format_description_log_event, found event type %d",
+ (*packet)[EVENT_TYPE_OFFSET+1]));
+ if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT)
+ {
+ binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] &
+ LOG_EVENT_BINLOG_IN_USE_F);
+ (*packet)[FLAGS_OFFSET+1] &= ~LOG_EVENT_BINLOG_IN_USE_F;
+ /*
+ mark that this event with "log_pos=0", so the slave
+ should not increment master's binlog position
+ (rli->group_master_log_pos)
+ */
+ int4store((char*) packet->ptr()+LOG_POS_OFFSET+1, 0);
+ /* send it */
+ if (my_net_write(net, (char*)packet->ptr(), packet->length()))
+ {
+ errmsg = "Failed on my_net_write()";
+ my_errno= ER_UNKNOWN_ERROR;
+ goto err;
+ }
+
+ if (thd->variables.sync_replication)
+ ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log));
+
+ /*
+ No need to save this event. We are only doing simple reads
+ (no real parsing of the events) so we don't need it. And so
+ we don't need the artificial Format_description_log_event of
+ 3.23&4.x.
+ */
+ }
+ }
+ else
+ {
+ if (test_for_non_eof_log_read_errors(error, &errmsg))
+ goto err;
+ /*
+ It's EOF, nothing to do, go on reading next events, the
+ Format_description_log_event will be found naturally if it is written.
+ */
+ }
+ /* reset the packet as we wrote to it in any case */
+ packet->set("\0", 1, &my_charset_bin);
+ } /* end of if (pos > BIN_LOG_HEADER_SIZE); */
+ else
+ {
+ /* The Format_description_log_event event will be found naturally. */
+ }
+
+ /* seek to the requested position, to start the requested dump */
+ my_b_seek(&log, pos); // Seek will done on next read
+ while (!net->error && net->vio != 0 && !thd->killed)
+ {
while (!(error = Log_event::read_log_event(&log, packet, log_lock)))
{
#ifndef DBUG_OFF
@@ -435,12 +518,26 @@ impossible position";
goto err;
}
#endif
- if (my_net_write(net, (char*)packet->ptr(), packet->length()) )
+
+ if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT)
+ {
+ binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] &
+ LOG_EVENT_BINLOG_IN_USE_F);
+ (*packet)[FLAGS_OFFSET+1] &= ~LOG_EVENT_BINLOG_IN_USE_F;
+ }
+ else if ((*packet)[EVENT_TYPE_OFFSET+1] == STOP_EVENT)
+ binlog_can_be_corrupted= FALSE;
+
+ if (my_net_write(net, (char*)packet->ptr(), packet->length()))
{
errmsg = "Failed on my_net_write()";
my_errno= ER_UNKNOWN_ERROR;
goto err;
}
+
+ if (thd->variables.sync_replication)
+ ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log));
+
DBUG_PRINT("info", ("log event code %d",
(*packet)[LOG_EVENT_OFFSET+1] ));
if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT)
@@ -454,39 +551,25 @@ impossible position";
}
packet->set("\0", 1, &my_charset_bin);
}
+
+ /*
+ here we were reading binlog that was not closed properly (as a result
+ of a crash ?). treat any corruption as EOF
+ */
+ if (binlog_can_be_corrupted && error != LOG_READ_MEM)
+ error=LOG_READ_EOF;
/*
TODO: now that we are logging the offset, check to make sure
- the recorded offset and the actual match
+ the recorded offset and the actual match.
+ Guilhem 2003-06: this is not true if this master is a slave
+ <4.0.15 running with --log-slave-updates, because then log_pos may
+ be the offset in the-master-of-this-master's binlog.
*/
- if (error != LOG_READ_EOF)
- {
- my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
- switch (error) {
- case LOG_READ_BOGUS:
- errmsg = "bogus data in log event";
- break;
- case LOG_READ_TOO_LARGE:
- errmsg = "log event entry exceeded max_allowed_packet; \
-Increase max_allowed_packet on master";
- break;
- case LOG_READ_IO:
- errmsg = "I/O error reading log event";
- break;
- case LOG_READ_MEM:
- errmsg = "memory allocation failed reading log event";
- break;
- case LOG_READ_TRUNC:
- errmsg = "binlog truncated in the middle of event";
- break;
- default:
- errmsg = "unknown error reading log event on the master";
- break;
- }
+ if (test_for_non_eof_log_read_errors(error, &errmsg))
goto err;
- }
if (!(flags & BINLOG_DUMP_NON_BLOCK) &&
- mysql_bin_log.is_active(log_file_name))
+ mysql_bin_log.is_active(log_file_name))
{
/*
Block until there is more data in the log
@@ -522,9 +605,9 @@ Increase max_allowed_packet on master";
now, but we'll be quick and just read one record
TODO:
- Add an counter that is incremented for each time we update
- the binary log. We can avoid the following read if the counter
- has not been updated since last read.
+ Add an counter that is incremented for each time we update the
+ binary log. We can avoid the following read if the counter
+ has not been updated since last read.
*/
pthread_mutex_lock(log_lock);
@@ -568,6 +651,9 @@ Increase max_allowed_packet on master";
goto err;
}
+ if (thd->variables.sync_replication)
+ ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log));
+
if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT)
{
if (send_file(thd))
@@ -617,21 +703,34 @@ Increase max_allowed_packet on master";
(void) my_close(file, MYF(MY_WME));
/*
- Even if the previous log contained a Rotate_log_event, we still fake
- one.
+ Call fake_rotate_event() in case the previous log (the one which
+ we have just finished reading) did not contain a Rotate event
+ (for example (I don't know any other example) the previous log
+ was the last one before the master was shutdown & restarted).
+ This way we tell the slave about the new log's name and
+ position. If the binlog is 5.0, the next event we are going to
+ read and send is Format_description_log_event.
*/
if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0 ||
- fake_rotate_event(net, packet, log_file_name, BIN_LOG_HEADER_SIZE, &errmsg))
+ fake_rotate_event(net, packet, log_file_name, BIN_LOG_HEADER_SIZE,
+ &errmsg))
{
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
goto err;
}
+
+ if (thd->variables.sync_replication)
+ ha_repl_report_sent_binlog(thd, log_file_name, 0);
+
packet->length(0);
packet->append('\0');
}
}
end:
+ if (thd->variables.sync_replication)
+ ha_repl_report_replication_stop(thd);
+
end_io_cache(&log);
(void)my_close(file, MYF(MY_WME));
@@ -643,6 +742,9 @@ end:
DBUG_VOID_RETURN;
err:
+ if (thd->variables.sync_replication)
+ ha_repl_report_replication_stop(thd);
+
thd->proc_info = "Waiting to finalize termination";
end_io_cache(&log);
/*
@@ -657,7 +759,7 @@ err:
pthread_mutex_unlock(&LOCK_thread_count);
if (file >= 0)
(void) my_close(file, MYF(MY_WME));
- send_error(thd, my_errno, errmsg);
+ my_message(my_errno, errmsg, MYF(0));
DBUG_VOID_RETURN;
}
@@ -666,17 +768,17 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
int slave_errno= 0;
int thread_mask;
DBUG_ENTER("start_slave");
-
+
if (check_access(thd, SUPER_ACL, any_db,0,0,0))
DBUG_RETURN(1);
lock_slave_threads(mi); // this allows us to cleanly read slave_running
// Get a mask of _stopped_ threads
init_thread_mask(&thread_mask,mi,1 /* inverse */);
/*
- Below we will start all stopped threads.
- But if the user wants to start only one thread, do as if the other thread
- was running (as we don't wan't to touch the other thread), so set the
- bit to 0 for the other thread
+ Below we will start all stopped threads. But if the user wants to
+ start only one thread, do as if the other thread was running (as we
+ don't wan't to touch the other thread), so set the bit to 0 for the
+ other thread
*/
if (thd->lex->slave_thd_opt)
thread_mask&= thd->lex->slave_thd_opt;
@@ -687,10 +789,10 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
slave_errno=ER_MASTER_INFO;
else if (server_id_supplied && *mi->host)
{
- /*
- If we will start SQL thread we will care about UNTIL options
- If not and they are specified we will ignore them and warn user
- about this fact.
+ /*
+ If we will start SQL thread we will care about UNTIL options If
+ not and they are specified we will ignore them and warn user
+ about this fact.
*/
if (thread_mask & SLAVE_SQL)
{
@@ -700,19 +802,19 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
{
mi->rli.until_condition= RELAY_LOG_INFO::UNTIL_MASTER_POS;
mi->rli.until_log_pos= thd->lex->mi.pos;
- /*
- We don't check thd->lex->mi.log_file_name for NULL here
+ /*
+ We don't check thd->lex->mi.log_file_name for NULL here
since it is checked in sql_yacc.yy
*/
strmake(mi->rli.until_log_name, thd->lex->mi.log_file_name,
- sizeof(mi->rli.until_log_name)-1);
- }
+ sizeof(mi->rli.until_log_name)-1);
+ }
else if (thd->lex->mi.relay_log_pos)
{
mi->rli.until_condition= RELAY_LOG_INFO::UNTIL_RELAY_POS;
mi->rli.until_log_pos= thd->lex->mi.relay_log_pos;
strmake(mi->rli.until_log_name, thd->lex->mi.relay_log_name,
- sizeof(mi->rli.until_log_name)-1);
+ sizeof(mi->rli.until_log_name)-1);
}
else
clear_until_condition(&mi->rli);
@@ -730,30 +832,30 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
p_end points to the first invalid character. If it equals
to p, no digits were found, error. If it contains '\0' it
means conversion went ok.
- */
+ */
if (p_end==p || *p_end)
slave_errno=ER_BAD_SLAVE_UNTIL_COND;
}
else
slave_errno=ER_BAD_SLAVE_UNTIL_COND;
-
+
/* mark the cached result of the UNTIL comparison as "undefined" */
- mi->rli.until_log_names_cmp_result=
+ mi->rli.until_log_names_cmp_result=
RELAY_LOG_INFO::UNTIL_LOG_NAMES_CMP_UNKNOWN;
/* Issuing warning then started without --skip-slave-start */
if (!opt_skip_slave_start)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_MISSING_SKIP_SLAVE,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_MISSING_SKIP_SLAVE,
ER(ER_MISSING_SKIP_SLAVE));
}
-
+
pthread_mutex_unlock(&mi->rli.data_lock);
}
else if (thd->lex->mi.pos || thd->lex->mi.relay_log_pos)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNTIL_COND_IGNORED,
- ER(ER_UNTIL_COND_IGNORED));
-
-
+ ER(ER_UNTIL_COND_IGNORED));
+
if (!slave_errno)
slave_errno = start_slave_threads(0 /*no mutex */,
1 /* wait for start */,
@@ -765,16 +867,18 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
slave_errno = ER_BAD_SLAVE;
}
else
- //no error if all threads are already started, only a warning
+ {
+ /* no error if all threads are already started, only a warning */
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_WAS_RUNNING,
ER(ER_SLAVE_WAS_RUNNING));
+ }
unlock_slave_threads(mi);
-
+
if (slave_errno)
{
if (net_report)
- send_error(thd, slave_errno);
+ my_message(slave_errno, ER(slave_errno), MYF(0));
DBUG_RETURN(1);
}
else if (net_report)
@@ -824,7 +928,7 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
if (slave_errno)
{
if (net_report)
- send_error(thd, slave_errno);
+ my_message(slave_errno, ER(slave_errno), MYF(0));
return 1;
}
else if (net_report)
@@ -870,7 +974,7 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
1 /* just reset */,
&errmsg)))
goto err;
-
+
/*
Clear master's log coordinates and reset host/user/etc to the values
specified in mysqld's options (only for good display of SHOW SLAVE STATUS;
@@ -879,13 +983,13 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
STATUS; before doing START SLAVE;
*/
init_master_info_with_options(mi);
- /*
+ /*
Reset errors (the idea is that we forget about the
old master).
*/
clear_slave_error(&mi->rli);
clear_until_condition(&mi->rli);
-
+
// close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
end_master_info(mi);
// and delete these two files
@@ -905,7 +1009,7 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
err:
unlock_slave_threads(mi);
- if (error)
+ if (error)
my_error(sql_errno, MYF(0), errmsg);
DBUG_RETURN(error);
}
@@ -953,13 +1057,13 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
it will be slow because it will iterate through the list
again. We just to do kill the thread ourselves.
*/
- tmp->awake(1/*prepare to die*/);
+ tmp->awake(THD::KILL_QUERY);
pthread_mutex_unlock(&tmp->LOCK_delete);
}
}
-int change_master(THD* thd, MASTER_INFO* mi)
+bool change_master(THD* thd, MASTER_INFO* mi)
{
int thread_mask;
const char* errmsg= 0;
@@ -970,9 +1074,9 @@ int change_master(THD* thd, MASTER_INFO* mi)
init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
if (thread_mask) // We refuse if any slave thread is running
{
- net_printf(thd,ER_SLAVE_MUST_STOP);
+ my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
unlock_slave_threads(mi);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
thd->proc_info = "Changing master";
@@ -981,9 +1085,9 @@ int change_master(THD* thd, MASTER_INFO* mi)
if (init_master_info(mi, master_info_file, relay_log_info_file, 0,
thread_mask))
{
- send_error(thd, ER_MASTER_INFO);
+ my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
unlock_slave_threads(mi);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
/*
@@ -1100,9 +1204,9 @@ int change_master(THD* thd, MASTER_INFO* mi)
0 /* not only reset, but also reinit */,
&errmsg))
{
- net_printf(thd, 0, "Failed purging old relay logs: %s",errmsg);
+ my_error(ER_RELAY_LOG_FAIL, MYF(0), errmsg);
unlock_slave_threads(mi);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
}
else
@@ -1114,11 +1218,11 @@ int change_master(THD* thd, MASTER_INFO* mi)
mi->rli.group_relay_log_name,
mi->rli.group_relay_log_pos,
0 /*no data lock*/,
- &msg))
+ &msg, 0))
{
- net_printf(thd,0,"Failed initializing relay log position: %s",msg);
+ my_error(ER_RELAY_LOG_INIT, MYF(0), msg);
unlock_slave_threads(mi);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
}
mi->rli.group_master_log_pos = mi->master_log_pos;
@@ -1160,14 +1264,15 @@ int change_master(THD* thd, MASTER_INFO* mi)
unlock_slave_threads(mi);
thd->proc_info = 0;
send_ok(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
int reset_master(THD* thd)
{
if (!mysql_bin_log.is_open())
{
- my_error(ER_FLUSH_MASTER_BINLOG_CLOSED, MYF(ME_BELL+ME_WAITTANG));
+ my_message(ER_FLUSH_MASTER_BINLOG_CLOSED,
+ ER(ER_FLUSH_MASTER_BINLOG_CLOSED), MYF(ME_BELL+ME_WAITTANG));
return 1;
}
return mysql_bin_log.reset_logs(thd);
@@ -1191,18 +1296,22 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
}
-int show_binlog_events(THD* thd)
+bool mysql_show_binlog_events(THD* thd)
{
Protocol *protocol= thd->protocol;
- DBUG_ENTER("show_binlog_events");
+ DBUG_ENTER("mysql_show_binlog_events");
List<Item> field_list;
const char *errmsg = 0;
+ bool ret = TRUE;
IO_CACHE log;
File file = -1;
+ Format_description_log_event *description_event= new
+ Format_description_log_event(3); /* MySQL 4.0 by default */
Log_event::init_show_field_list(&field_list);
- if (protocol-> send_fields(&field_list, 1))
- DBUG_RETURN(-1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
if (mysql_bin_log.is_open())
{
@@ -1214,7 +1323,7 @@ int show_binlog_events(THD* thd)
pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
LOG_INFO linfo;
Log_event* ev;
-
+
limit_start= thd->lex->current_select->offset_limit;
limit_end= thd->lex->current_select->select_limit + limit_start;
@@ -1237,10 +1346,38 @@ int show_binlog_events(THD* thd)
goto err;
pthread_mutex_lock(log_lock);
+
+ /*
+ open_binlog() sought to position 4.
+ Read the first event in case it's a Format_description_log_event, to
+ know the format. If there's no such event, we are 3.23 or 4.x. This
+ code, like before, can't read 3.23 binlogs.
+ This code will fail on a mixed relay log (one which has Format_desc then
+ Rotate then Format_desc).
+ */
+
+ ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,description_event);
+ if (ev)
+ {
+ if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
+ {
+ delete description_event;
+ description_event= (Format_description_log_event*) ev;
+ }
+ else
+ delete ev;
+ }
+
my_b_seek(&log, pos);
+ if (!description_event->is_valid())
+ {
+ errmsg="Invalid Format_description event; could be out of memory";
+ goto err;
+ }
+
for (event_count = 0;
- (ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,0)); )
+ (ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,description_event)); )
{
if (event_count >= limit_start &&
ev->net_send(protocol, linfo.log_file_name, pos))
@@ -1268,7 +1405,10 @@ int show_binlog_events(THD* thd)
pthread_mutex_unlock(log_lock);
}
+ ret= FALSE;
+
err:
+ delete description_event;
if (file >= 0)
{
end_io_cache(&log);
@@ -1278,19 +1418,19 @@ err:
if (errmsg)
{
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
- "SHOW BINLOG EVENTS", errmsg);
- DBUG_RETURN(-1);
+ "SHOW BINLOG EVENTS", errmsg);
+ DBUG_RETURN(TRUE);
}
send_eof(thd);
pthread_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
pthread_mutex_unlock(&LOCK_thread_count);
- DBUG_RETURN(0);
+ DBUG_RETURN(ret);
}
-int show_binlog_info(THD* thd)
+bool show_binlog_info(THD* thd)
{
Protocol *protocol= thd->protocol;
DBUG_ENTER("show_binlog_info");
@@ -1301,8 +1441,9 @@ int show_binlog_info(THD* thd)
field_list.push_back(new Item_empty_string("Binlog_Do_DB",255));
field_list.push_back(new Item_empty_string("Binlog_Ignore_DB",255));
- if (protocol->send_fields(&field_list, 1))
- DBUG_RETURN(-1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
protocol->prepare_for_resend();
if (mysql_bin_log.is_open())
@@ -1315,10 +1456,10 @@ int show_binlog_info(THD* thd)
protocol->store(&binlog_do_db);
protocol->store(&binlog_ignore_db);
if (protocol->write())
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -1330,11 +1471,11 @@ int show_binlog_info(THD* thd)
thd Thread specific variable
RETURN VALUES
- 0 ok
- 1 error (Error message sent to client)
+ FALSE OK
+ TRUE error
*/
-int show_binlogs(THD* thd)
+bool show_binlogs(THD* thd)
{
IO_CACHE *index_file;
char fname[FN_REFLEN];
@@ -1345,14 +1486,14 @@ int show_binlogs(THD* thd)
if (!mysql_bin_log.is_open())
{
- //TODO: Replace with ER() error message
- send_error(thd, 0, "You are not using binary logging");
+ my_message(ER_NO_BINARY_LOGGING, ER(ER_NO_BINARY_LOGGING), MYF(0));
return 1;
}
field_list.push_back(new Item_empty_string("Log_name", 255));
- if (protocol->send_fields(&field_list, 1))
- DBUG_RETURN(1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
mysql_bin_log.lock_index();
index_file=mysql_bin_log.get_index_file();
@@ -1370,11 +1511,11 @@ int show_binlogs(THD* thd)
}
mysql_bin_log.unlock_index();
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
err:
mysql_bin_log.unlock_index();
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
@@ -1394,17 +1535,16 @@ int log_loaded_block(IO_CACHE* file)
lf_info->last_pos_in_file = file->pos_in_file;
if (lf_info->wrote_create_file)
{
- Append_block_log_event a(lf_info->thd, lf_info->db, buffer, block_len,
- lf_info->log_delayed);
+ Append_block_log_event a(lf_info->thd, lf_info->thd->db, buffer,
+ block_len, lf_info->log_delayed);
mysql_bin_log.write(&a);
}
else
{
- Create_file_log_event c(lf_info->thd,lf_info->ex,lf_info->db,
- lf_info->table_name, *lf_info->fields,
- lf_info->handle_dup, lf_info->ignore, buffer,
- block_len, lf_info->log_delayed);
- mysql_bin_log.write(&c);
+ Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db,
+ buffer, block_len,
+ lf_info->log_delayed);
+ mysql_bin_log.write(&b);
lf_info->wrote_create_file = 1;
DBUG_SYNC_POINT("debug_lock.created_file_event",10);
}
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 21b3d2955f7..9eb6456ee20 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -36,24 +36,25 @@ extern I_List<i_string> binlog_do_db, binlog_ignore_db;
extern int max_binlog_dump_events;
extern my_bool opt_sporadic_binlog_dump_fail;
-#define KICK_SLAVE(thd) { pthread_mutex_lock(&(thd)->LOCK_delete); (thd)->awake(0 /* do not prepare to die*/); pthread_mutex_unlock(&(thd)->LOCK_delete); }
-
-File open_binlog(IO_CACHE *log, const char *log_file_name,
- const char **errmsg);
+#define KICK_SLAVE(thd) do { \
+ pthread_mutex_lock(&(thd)->LOCK_delete); \
+ (thd)->awake(THD::NOT_KILLED); \
+ pthread_mutex_unlock(&(thd)->LOCK_delete); \
+ } while(0)
int start_slave(THD* thd, MASTER_INFO* mi, bool net_report);
int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report);
-int change_master(THD* thd, MASTER_INFO* mi);
-int show_binlog_events(THD* thd);
+bool change_master(THD* thd, MASTER_INFO* mi);
+bool mysql_show_binlog_events(THD* thd);
int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
const char* log_file_name2, ulonglong log_pos2);
int reset_slave(THD *thd, MASTER_INFO* mi);
int reset_master(THD* thd);
-int purge_master_logs(THD* thd, const char* to_log);
-int purge_master_logs_before_date(THD* thd, time_t purge_time);
+bool purge_master_logs(THD* thd, const char* to_log);
+bool purge_master_logs_before_date(THD* thd, time_t purge_time);
bool log_in_use(const char* log_name);
void adjust_linfo_offsets(my_off_t purge_offset);
-int show_binlogs(THD* thd);
+bool show_binlogs(THD* thd);
extern int init_master_info(MASTER_INFO* mi);
void kill_zombie_dump_threads(uint32 slave_server_id);
int check_binlog_magic(IO_CACHE* log, const char** errmsg);
@@ -62,12 +63,7 @@ typedef struct st_load_file_info
{
THD* thd;
my_off_t last_pos_in_file;
- sql_exchange* ex;
- List <Item> *fields;
- enum enum_duplicates handle_dup;
- char* db;
- char* table_name;
- bool wrote_create_file, log_delayed, ignore;
+ bool wrote_create_file, log_delayed;
} LOAD_FILE_INFO;
int log_loaded_block(IO_CACHE* file);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index aeb52a39982..fa774c6d89e 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -30,24 +30,45 @@
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext",
- "ref_or_null","unique_subquery","index_subquery"
+ "ref_or_null","unique_subquery","index_subquery",
+ "index_merge"
};
const key_map key_map_empty(0);
const key_map key_map_full(~0);
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
-static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
+static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, COND *conds,
DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
JOIN_TAB *join_tab,
uint tables, COND *conds,
+ COND_EQUAL *cond_equal,
table_map table_map, SELECT_LEX *select_lex);
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
table_map used_tables);
-static void find_best_combination(JOIN *join,table_map rest_tables);
+static void choose_plan(JOIN *join,table_map join_tables);
+
+static void best_access_path(JOIN *join, JOIN_TAB *s, THD *thd,
+ table_map remaining_tables, uint idx,
+ double record_count, double read_time);
+static void optimize_straight_join(JOIN *join, table_map join_tables);
+static void greedy_search(JOIN *join, table_map remaining_tables,
+ uint depth, uint prune_level);
+static void best_extension_by_limited_search(JOIN *join,
+ table_map remaining_tables,
+ uint idx, double record_count,
+ double read_time, uint depth,
+ uint prune_level);
+static uint determine_search_depth(JOIN* join);
+static int join_tab_cmp(const void* ptr1, const void* ptr2);
+static int join_tab_cmp_straight(const void* ptr1, const void* ptr2);
+/*
+ TODO: 'find_best' is here only temporarily until 'greedy_search' is
+ tested and approved.
+*/
static void find_best(JOIN *join,table_map rest_tables,uint index,
double record_count,double read_time);
static uint cache_record_length(JOIN *join,uint index);
@@ -58,6 +79,7 @@ static store_key *get_store_key(THD *thd,
KEY_PART_INFO *key_part, char *key_buff,
uint maybe_null);
static bool make_simple_join(JOIN *join,TABLE *tmp_table);
+static void make_outerjoin_info(JOIN *join);
static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
static void make_join_readinfo(JOIN *join,uint options);
static bool only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables);
@@ -70,27 +92,53 @@ static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables,
uint select_options, const char *info,
Item *having, Procedure *proc,
SELECT_LEX_UNIT *unit);
-static COND *optimize_cond(THD *thd, COND *conds,
+static COND *build_equal_items(THD *thd, COND *cond,
+ COND_EQUAL *inherited,
+ List<TABLE_LIST> *join_list,
+ COND_EQUAL **cond_equal_ref);
+static COND* substitute_for_best_equal_field(COND *cond,
+ COND_EQUAL *cond_equal,
+ void *table_join_idx);
+static COND *simplify_joins(JOIN *join, List<TABLE_LIST> *join_list,
+ COND *conds, bool top);
+static COND *optimize_cond(JOIN *join, COND *conds,
+ List<TABLE_LIST> *join_list,
Item::cond_result *cond_value);
+static bool resolve_nested_join (TABLE_LIST *table);
static COND *remove_eq_conds(THD *thd, COND *cond,
Item::cond_result *cond_value);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table);
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
ulong options);
+static Next_select_func setup_end_select_func(JOIN *join);
static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table,
Procedure *proc);
-static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records);
-static int sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records);
-static int flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last);
-static int end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
-static int end_send_group(JOIN *join, JOIN_TAB *join_tab,bool end_of_records);
-static int end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
-static int end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
-static int end_unique_update(JOIN *join,JOIN_TAB *join_tab,
- bool end_of_records);
-static int end_write_group(JOIN *join, JOIN_TAB *join_tab,
- bool end_of_records);
+
+static enum_nested_loop_state
+sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+static enum_nested_loop_state
+evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
+ int error, my_bool *report_error);
+static enum_nested_loop_state
+evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab);
+static enum_nested_loop_state
+sub_select(JOIN *join,JOIN_TAB *join_tab, bool end_of_records);
+static enum_nested_loop_state
+flush_cached_records(JOIN *join, JOIN_TAB *join_tab, bool skip_last);
+static enum_nested_loop_state
+end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+static enum_nested_loop_state
+end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+static enum_nested_loop_state
+end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+static enum_nested_loop_state
+end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+static enum_nested_loop_state
+end_unique_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+static enum_nested_loop_state
+end_write_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
+
static int test_if_group_changed(List<Item_buff> &list);
static int join_read_const_table(JOIN_TAB *tab, POSITION *pos);
static int join_read_system(JOIN_TAB *tab);
@@ -116,7 +164,7 @@ static int join_read_next_same_or_null(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table,
table_map used_table);
static Item* part_of_refkey(TABLE *form,Field *field);
-static uint find_shortest_key(TABLE *table, const key_map *usable_keys);
+uint find_shortest_key(TABLE *table, const key_map *usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes);
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
@@ -127,6 +175,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field,
ulong offset,Item *having);
static int remove_dup_with_hash_index(THD *thd,TABLE *table,
uint field_count, Field **first_field,
+
ulong key_length,Item *having);
static int join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count);
static ulong used_blob_length(CACHE_FIELD **ptr);
@@ -159,26 +208,37 @@ static void init_tmptable_sum_functions(Item_sum **func);
static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end);
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
+static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr);
static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table,bool need_order,
bool distinct, const char *message=NullS);
static Item *remove_additional_cond(Item* conds);
+static void add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab);
/*
This handles SELECT with and without UNION
*/
-int handle_select(THD *thd, LEX *lex, select_result *result)
+bool handle_select(THD *thd, LEX *lex, select_result *result,
+ ulong setup_tables_done_option)
{
- int res;
+ bool res;
register SELECT_LEX *select_lex = &lex->select_lex;
DBUG_ENTER("handle_select");
if (select_lex->next_select())
- res=mysql_union(thd, lex, result, &lex->unit);
+ res= mysql_union(thd, lex, result, &lex->unit, setup_tables_done_option);
else
+ {
+ SELECT_LEX_UNIT *unit= &lex->unit;
+ unit->set_limit(unit->global_parameters, select_lex);
+ /*
+ 'options' of mysql_select will be set in JOIN, as far as JOIN for
+ every PS/SP execution new, we will not need reset this flag if
+ setup_tables_done_option changed for next rexecution
+ */
res= mysql_select(thd, &select_lex->ref_pointer_array,
(TABLE_LIST*) select_lex->table_list.first,
select_lex->with_wild, select_lex->item_list,
@@ -189,17 +249,18 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
(ORDER*) select_lex->group_list.first,
select_lex->having,
(ORDER*) lex->proc_list.first,
- select_lex->options | thd->options,
- result, &(lex->unit), &(lex->select_lex));
-
- /* Don't set res if it's -1 as we may want this later */
+ select_lex->options | thd->options |
+ setup_tables_done_option,
+ result, unit, select_lex);
+ }
DBUG_PRINT("info",("res: %d report_error: %d", res,
thd->net.report_error));
- if (thd->net.report_error || res<0)
+ res|= thd->net.report_error;
+ if (unlikely(res))
{
- result->send_error(0, NullS);
+ /* If we had a another error reported earlier then this will be ignored */
+ result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
result->abort();
- res= 1; // Error sent to client
}
DBUG_RETURN(res);
}
@@ -210,6 +271,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
*/
inline int setup_without_group(THD *thd, Item **ref_pointer_array,
TABLE_LIST *tables,
+ TABLE_LIST *leaves,
List<Item> &fields,
List<Item> &all_fields,
COND **conds,
@@ -222,11 +284,13 @@ 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, conds) ||
- setup_order(thd, ref_pointer_array, tables, fields, all_fields,
- order) ||
- setup_group(thd, ref_pointer_array, tables, fields, all_fields,
- group, hidden_group_fields));
+ 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);
+ thd->allow_sum_func= 0;
+ res= res || setup_group(thd, ref_pointer_array, tables, fields, all_fields,
+ group, hidden_group_fields);
thd->allow_sum_func= save_allow_sum_func;
DBUG_RETURN(res);
}
@@ -264,17 +328,28 @@ JOIN::prepare(Item ***rref_pointer_array,
tables_list= tables_init;
select_lex= select_lex_arg;
select_lex->join= this;
+ join_list= &select_lex->top_join_list;
union_part= (unit_arg->first_select()->next_select() != 0);
+ /*
+ If we have already executed SELECT, then it have not sense to prevent
+ its table from update (see unique_table())
+ */
+ if (thd->derived_tables_processing)
+ select_lex->exclude_from_table_unique_test= TRUE;
+
/* Check that all tables, fields, conds and order are ok */
- if (setup_tables(tables_list) ||
+ if ((!(select_options & OPTION_SETUP_TABLES_DONE) &&
+ setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables,
+ FALSE, 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,
&all_fields, 1) ||
- setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list,
- all_fields, &conds, order, group_list,
+ setup_without_group(thd, (*rref_pointer_array), tables_list,
+ select_lex->leaf_tables, fields_list,
+ all_fields, &conds, order, group_list,
&hidden_group_fields))
DBUG_RETURN(-1); /* purecov: inspected */
@@ -295,15 +370,19 @@ JOIN::prepare(Item ***rref_pointer_array,
having->split_sum_func(thd, ref_pointer_array, all_fields);
}
- // Is it subselect
+ if (!thd->lex->view_prepare_mode)
{
Item_subselect *subselect;
+ /* Is it subselect? */
if ((subselect= select_lex->master_unit()->item))
{
Item_subselect::trans_res res;
if ((res= subselect->select_transformer(this)) !=
Item_subselect::RES_OK)
+ {
+ select_lex->fix_prepare_information(thd, &conds);
DBUG_RETURN((res == Item_subselect::RES_ERROR));
+ }
}
}
@@ -332,12 +411,15 @@ JOIN::prepare(Item ***rref_pointer_array,
}
if (flag == 3)
{
- my_error(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,MYF(0));
+ my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,
+ ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0));
DBUG_RETURN(-1);
}
}
TABLE_LIST *table_ptr;
- for (table_ptr= tables_list ; table_ptr ; table_ptr= table_ptr->next)
+ for (table_ptr= select_lex->leaf_tables;
+ table_ptr;
+ table_ptr= table_ptr->next_leaf)
tables++;
}
{
@@ -359,21 +441,22 @@ JOIN::prepare(Item ***rref_pointer_array,
{
if (!test_if_subpart(procedure->group,group_list))
{ /* purecov: inspected */
- my_message(0,"Can't handle procedures with differents groups yet",
- MYF(0)); /* purecov: inspected */
+ my_message(ER_DIFF_GROUPS_PROC, ER(ER_DIFF_GROUPS_PROC),
+ MYF(0)); /* purecov: inspected */
goto err; /* purecov: inspected */
}
}
#ifdef NOT_NEEDED
else if (!group_list && procedure->flags & PROC_GROUP)
{
- my_message(0,"Select must have a group with this procedure",MYF(0));
+ my_message(ER_NO_GROUP_FOR_PROC, MYF(0));
goto err;
}
#endif
if (order && (procedure->flags & PROC_NO_SORT))
{ /* purecov: inspected */
- my_message(0,"Can't use order with this procedure",MYF(0)); /* purecov: inspected */
+ my_message(ER_ORDER_WITH_PROC, ER(ER_ORDER_WITH_PROC),
+ MYF(0)); /* purecov: inspected */
goto err; /* purecov: inspected */
}
}
@@ -398,16 +481,7 @@ JOIN::prepare(Item ***rref_pointer_array,
goto err;
}
#endif
- /*
- We must not yet prepare the result table if it is the same as one of the
- source tables (INSERT SELECT). This is checked in mysql_execute_command()
- and OPTION_BUFFER_RESULT is added to the select_options. A temporary
- table is then used to hold the result. The preparation may disable
- indexes on the result table, which may be used during the select, if it
- is the same table (Bug #6034). Do the preparation after the select phase.
- */
- if (! procedure && ! test(select_options & OPTION_BUFFER_RESULT) &&
- result && result->prepare(fields_list, unit_arg))
+ if (!procedure && result && result->prepare(fields_list, unit_arg))
goto err; /* purecov: inspected */
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
@@ -415,6 +489,7 @@ JOIN::prepare(Item ***rref_pointer_array,
if (alloc_func_list())
goto err;
+ select_lex->fix_prepare_information(thd, &conds);
DBUG_RETURN(0); // All OK
err:
@@ -460,7 +535,6 @@ bool JOIN::test_in_subselect(Item **where)
return 0;
}
-
/*
global select optimisation.
return 0 - success
@@ -490,6 +564,10 @@ JOIN::optimize()
}
else if ((conds=new Item_cond_and(conds,having)))
{
+ /*
+ Item_cond_and can't be fixed after creation, so we do not check
+ conds->fixed
+ */
conds->fix_fields(thd, tables_list, &conds);
conds->change_ref_to_fields(thd, tables_list);
conds->top_level_item();
@@ -497,8 +575,32 @@ JOIN::optimize()
}
}
#endif
+ SELECT_LEX *sel= thd->lex->current_select;
+ if (sel->first_cond_optimization)
+ {
+ /*
+ The following code will allocate the new items in a permanent
+ MEMROOT for prepared statements and stored procedures.
+ */
+
+ Item_arena *arena= thd->current_arena, backup;
+ if (arena->is_conventional())
+ arena= 0; // For easier test
+ else
+ thd->set_n_backup_item_arena(arena, &backup);
+
+ sel->first_cond_optimization= 0;
+
+ /* Convert all outer joins to inner joins if possible */
+ conds= simplify_joins(this, join_list, conds, TRUE);
- conds= optimize_cond(thd, conds, &cond_value);
+ sel->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
+
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ }
+
+ conds= optimize_cond(this, conds, join_list, &cond_value);
if (thd->net.report_error)
{
error= 1;
@@ -509,6 +611,7 @@ JOIN::optimize()
if (cond_value == Item::COND_FALSE ||
(!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
{ /* Impossible cond */
+ DBUG_PRINT("info", ("Impossible WHERE"));
zero_result_cause= "Impossible WHERE";
error= 0;
DBUG_RETURN(0);
@@ -522,33 +625,37 @@ JOIN::optimize()
opt_sum_query() returns -1 if no rows match to the WHERE conditions,
or 1 if all items were resolved, or 0, or an error number HA_ERR_...
*/
- if ((res=opt_sum_query(tables_list, all_fields, conds)))
+ if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds)))
{
if (res > 1)
{
+ DBUG_PRINT("error",("Error from opt_sum_query"));
DBUG_RETURN(1);
}
if (res < 0)
{
+ DBUG_PRINT("info",("No matching min/max row"));
zero_result_cause= "No matching min/max row";
error=0;
DBUG_RETURN(0);
}
+ DBUG_PRINT("info",("Select tables optimized away"));
zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
}
}
if (!tables_list)
{
+ DBUG_PRINT("info",("No tables"));
error= 0;
DBUG_RETURN(0);
}
error= -1; // Error is sent to client
- sort_by_table= get_sort_by_table(order, group_list, tables_list);
+ sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables);
/* Calculate how to do the join */
thd->proc_info= "statistics";
- if (make_join_statistics(this, tables_list, conds, &keyuse) ||
+ if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) ||
thd->is_fatal_error)
{
DBUG_PRINT("error",("Error: make_join_statistics() failed"));
@@ -585,20 +692,49 @@ JOIN::optimize()
if (const_tables && !thd->locked_tables &&
!(select_options & SELECT_NO_UNLOCK))
mysql_unlock_some_tables(thd, table, const_tables);
-
if (!conds && outer_join)
{
/* Handle the case where we have an OUTER JOIN without a WHERE */
conds=new Item_int((longlong) 1,1); // Always true
}
- select=make_select(*table, const_table_map,
- const_table_map, conds, &error);
+ select= make_select(*table, const_table_map,
+ const_table_map, conds, 1, &error);
if (error)
{ /* purecov: inspected */
error= -1; /* purecov: inspected */
DBUG_PRINT("error",("Error: make_select() failed"));
DBUG_RETURN(1);
}
+
+ make_outerjoin_info(this);
+
+ /*
+ Among the equal fields belonging to the same multiple equality
+ choose the one that is to be retrieved first and substitute
+ all references to these in where condition for a reference for
+ the selected field.
+ */
+ if (conds)
+ {
+ conds= substitute_for_best_equal_field(conds, cond_equal, map2table);
+ conds->update_used_tables();
+ DBUG_EXECUTE("where", print_where(conds, "after substitute_best_equal"););
+ }
+ /*
+ Permorm the the optimization on fields evaluation mentioned above
+ for all on expressions.
+ */
+ for (JOIN_TAB *tab= join_tab + const_tables; tab < join_tab + tables ; tab++)
+ {
+ if (*tab->on_expr_ref)
+ {
+ *tab->on_expr_ref= substitute_for_best_equal_field(*tab->on_expr_ref,
+ tab->cond_equal,
+ map2table);
+ (*tab->on_expr_ref)->update_used_tables();
+ }
+ }
+
if (make_join_select(this, select, conds))
{
zero_result_cause=
@@ -900,13 +1036,15 @@ JOIN::optimize()
if (create_sort_index(thd, this, group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
alloc_group_fields(this, group_list) ||
- make_sum_func_list(all_fields, fields_list, 1))
+ make_sum_func_list(all_fields, fields_list, 1) ||
+ setup_sum_funcs(thd, sum_funcs))
DBUG_RETURN(1);
group_list=0;
}
else
{
- if (make_sum_func_list(all_fields, fields_list, 0))
+ if (make_sum_func_list(all_fields, fields_list, 0) ||
+ setup_sum_funcs(thd, sum_funcs))
DBUG_RETURN(1);
if (!group_list && ! exec_tmp_table1->distinct && order && simple_order)
{
@@ -973,16 +1111,16 @@ JOIN::reinit()
{
DBUG_ENTER("JOIN::reinit");
/* TODO move to unit reinit */
- unit->offset_limit_cnt =select_lex->offset_limit;
- unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit;
- if (unit->select_limit_cnt < select_lex->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR; // no limit
- if (unit->select_limit_cnt == HA_POS_ERROR)
- select_lex->options&= ~OPTION_FOUND_ROWS;
-
- if (setup_tables(tables_list))
- DBUG_RETURN(1);
-
+ unit->set_limit(select_lex, select_lex);
+
+ /* conds should not be used here, it is added just for safety */
+ if (tables_list)
+ {
+ if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables,
+ TRUE, FALSE))
+ DBUG_RETURN(1);
+ }
+
/* Reset of sum functions */
first_record= 0;
@@ -1041,7 +1179,7 @@ JOIN::exec()
{
int tmp_error;
DBUG_ENTER("JOIN::exec");
-
+
error= 0;
if (procedure)
{
@@ -1052,13 +1190,7 @@ JOIN::exec()
DBUG_VOID_RETURN;
}
}
- else if (test(select_options & OPTION_BUFFER_RESULT) &&
- result && result->prepare(fields_list, unit))
- {
- error= 1;
- thd->limit_found_rows= thd->examined_row_count= 0;
- DBUG_VOID_RETURN;
- }
+ (void) result->prepare2(); // Currently, this cannot fail.
if (!tables_list)
{ // Only test of functions
@@ -1067,7 +1199,8 @@ JOIN::exec()
(zero_result_cause?zero_result_cause:"No tables used"));
else
{
- result->send_fields(fields_list,1);
+ result->send_fields(fields_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
if (!having || having->val_int())
{
if (do_send_rows && (procedure ? (procedure->send_row(fields_list) ||
@@ -1092,7 +1225,7 @@ JOIN::exec()
if (zero_result_cause)
{
- (void) return_zero_rows(this, result, tables_list, fields_list,
+ (void) return_zero_rows(this, result, select_lex->leaf_tables, fields_list,
send_row_on_empty_set(),
select_options,
zero_result_cause,
@@ -1136,6 +1269,12 @@ JOIN::exec()
List<Item> *curr_fields_list= &fields_list;
TABLE *curr_tmp_table= 0;
+ if ((curr_join->select_lex->options & OPTION_SCHEMA_TABLE) &&
+ get_schema_tables_result(curr_join))
+ {
+ DBUG_VOID_RETURN;
+ }
+
/* Create a tmp table if distinct or if the sort is too complicated */
if (need_tmp)
{
@@ -1145,7 +1284,7 @@ JOIN::exec()
/* Copy data to the temporary table */
thd->proc_info= "Copying to tmp table";
-
+ DBUG_PRINT("info", ("%s", thd->proc_info));
if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0)))
{
error= tmp_error;
@@ -1272,6 +1411,7 @@ JOIN::exec()
}
thd->proc_info="Copying to group table";
+ DBUG_PRINT("info", ("%s", thd->proc_info));
tmp_error= -1;
if (curr_join != this)
{
@@ -1288,10 +1428,11 @@ JOIN::exec()
}
}
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
- 1))
+ 1, TRUE))
DBUG_VOID_RETURN;
curr_join->group_list= 0;
- if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table,
+ if (setup_sum_funcs(curr_join->thd, curr_join->sum_funcs) ||
+ (tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table,
0)))
{
error= tmp_error;
@@ -1378,7 +1519,9 @@ JOIN::exec()
set_items_ref_array(items3);
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
- 1) || thd->is_fatal_error)
+ 1, TRUE) ||
+ setup_sum_funcs(curr_join->thd, curr_join->sum_funcs) ||
+ thd->is_fatal_error)
DBUG_VOID_RETURN;
}
if (curr_join->group_list || curr_join->order)
@@ -1443,11 +1586,9 @@ JOIN::exec()
/*
table->keyuse is set in the case there was an original WHERE clause
on the table that was optimized away.
- table->on_expr tells us that it was a LEFT JOIN and there will be
- at least one row generated from the table.
*/
if (curr_table->select_cond ||
- (curr_table->keyuse && !curr_table->on_expr))
+ (curr_table->keyuse && !curr_table->first_inner))
{
/* We have to sort all rows */
curr_join->select_limit= HA_POS_ERROR;
@@ -1477,12 +1618,48 @@ JOIN::exec()
DBUG_VOID_RETURN;
}
}
+ /* XXX: When can we have here thd->net.report_error not zero? */
+ if (thd->net.report_error)
+ {
+ error= thd->net.report_error;
+ DBUG_VOID_RETURN;
+ }
curr_join->having= curr_join->tmp_having;
- thd->proc_info="Sending data";
- error= thd->net.report_error ? -1 :
- do_select(curr_join, curr_fields_list, NULL, procedure);
- thd->limit_found_rows= curr_join->send_records;
- thd->examined_row_count= curr_join->examined_rows;
+ curr_join->fields= curr_fields_list;
+ curr_join->procedure= procedure;
+
+ if (unit == &thd->lex->unit &&
+ (unit->fake_select_lex == 0 || select_lex == unit->fake_select_lex) &&
+ thd->cursor && tables != const_tables)
+ {
+ /*
+ We are here if this is JOIN::exec for the last select of the main unit
+ and the client requested to open a cursor.
+ We check that not all tables are constant because this case is not
+ handled by do_select() separately, and this case is not implemented
+ for cursors yet.
+ */
+ DBUG_ASSERT(error == 0);
+ /*
+ curr_join is used only for reusable joins - that is,
+ to perform SELECT for each outer row (like in subselects).
+ This join is main, so we know for sure that curr_join == join.
+ */
+ DBUG_ASSERT(curr_join == this);
+ /* Open cursor for the last join sweep */
+ error= thd->cursor->open(this);
+ }
+ else
+ {
+ thd->proc_info="Sending data";
+ DBUG_PRINT("info", ("%s", thd->proc_info));
+ result->send_fields(*curr_fields_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+ error= do_select(curr_join, curr_fields_list, NULL, procedure);
+ thd->limit_found_rows= curr_join->send_records;
+ thd->examined_row_count= curr_join->examined_rows;
+ }
+
DBUG_VOID_RETURN;
}
@@ -1511,6 +1688,7 @@ JOIN::cleanup()
tmp_table_param.copy_field=0;
DBUG_RETURN(tmp_join->cleanup());
}
+ cond_equal= 0;
lock=0; // It's faster to unlock later
join_free(1);
@@ -1531,7 +1709,231 @@ JOIN::cleanup()
}
+/************************* Cursor ******************************************/
+
+void
+Cursor::init_from_thd(THD *thd)
+{
+ /*
+ We need to save and reset thd->mem_root, otherwise it'll be freed
+ later in mysql_parse.
+
+ We can't just change the thd->mem_root here as we want to keep the things
+ that is already allocated in thd->mem_root for Cursor::fetch()
+ */
+ main_mem_root= *thd->mem_root;
+ /* Allocate new memory root for thd */
+ init_sql_alloc(thd->mem_root,
+ thd->variables.query_alloc_block_size,
+ thd->variables.query_prealloc_size);
+
+ /*
+ The same is true for open tables and lock: save tables and zero THD
+ pointers to prevent table close in close_thread_tables (This is a part
+ of the temporary solution to make cursors work with minimal changes to
+ the current source base).
+ */
+ derived_tables= thd->derived_tables;
+ open_tables= thd->open_tables;
+ lock= thd->lock;
+ query_id= thd->query_id;
+ free_list= thd->free_list;
+ reset_thd(thd);
+ /*
+ XXX: thd->locked_tables is not changed.
+ What problems can we have with it if cursor is open?
+ */
+ /*
+ TODO: grab thd->free_list here?
+ */
+}
+
+
+void
+Cursor::init_thd(THD *thd)
+{
+ DBUG_ASSERT(thd->derived_tables == 0);
+ thd->derived_tables= derived_tables;
+
+ DBUG_ASSERT(thd->open_tables == 0);
+ thd->open_tables= open_tables;
+
+ DBUG_ASSERT(thd->lock== 0);
+ thd->lock= lock;
+ thd->query_id= query_id;
+}
+
+
+void
+Cursor::reset_thd(THD *thd)
+{
+ thd->derived_tables= 0;
+ thd->open_tables= 0;
+ thd->lock= 0;
+ thd->free_list= 0;
+}
+
+
int
+Cursor::open(JOIN *join_arg)
+{
+ join= join_arg;
+ THD *thd= join->thd;
+ /* First non-constant table */
+ JOIN_TAB *join_tab= join->join_tab + join->const_tables;
+ DBUG_ENTER("Cursor::open");
+
+ /*
+ Send fields description to the client; server_status is sent
+ in 'EOF' packet, which ends send_fields().
+ */
+ thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
+ join->result->send_fields(*join->fields, Protocol::SEND_NUM_ROWS);
+ ::send_eof(thd);
+ thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
+
+ /* Prepare JOIN for reading rows. */
+ join->tmp_table= 0;
+ join->join_tab[join->tables-1].next_select= setup_end_select_func(join);
+ join->send_records= 0;
+ join->fetch_limit= join->unit->offset_limit_cnt;
+
+ /* Disable JOIN CACHE as it is not working with cursors yet */
+ for (JOIN_TAB *tab= join_tab;
+ tab != join->join_tab + join->tables - 1;
+ tab++)
+ {
+ if (tab->next_select == sub_select_cache)
+ tab->next_select= sub_select;
+ }
+
+ DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0);
+ DBUG_ASSERT(join_tab->not_used_in_distinct == 0);
+ /*
+ null_row is set only if row not found and it's outer join: should never
+ happen for the first table in join_tab list
+ */
+ DBUG_ASSERT(join_tab->table->null_row == 0);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ DESCRIPTION
+ Fetch next num_rows rows from the cursor and sent them to the client
+ PRECONDITION:
+ Cursor is open
+ RETURN VALUES:
+ none, this function will send error or OK to network if necessary.
+*/
+
+void
+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;
+
+ /* save references to memory, allocated during fetch */
+ thd->set_n_backup_item_arena(this, &thd->stmt_backup);
+
+ join->fetch_limit+= num_rows;
+
+
+ error= sub_select(join, join_tab, 0);
+ if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
+ error= sub_select(join,join_tab,1);
+ if (error == NESTED_LOOP_QUERY_LIMIT)
+ error= NESTED_LOOP_OK; /* select_limit used */
+ if (error == NESTED_LOOP_CURSOR_LIMIT)
+ join->resume_nested_loop= TRUE;
+
+#ifdef USING_TRANSACTIONS
+ ha_release_temporary_latches(thd);
+#endif
+
+ thd->restore_backup_item_arena(this, &thd->stmt_backup);
+ if (error == NESTED_LOOP_CURSOR_LIMIT)
+ {
+ /* Fetch limit worked, possibly more rows are there */
+ thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
+ ::send_eof(thd);
+ thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
+ }
+ else
+ {
+ close();
+ if (error == NESTED_LOOP_OK)
+ {
+ thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
+ ::send_eof(thd);
+ thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT;
+ }
+ else if (error != NESTED_LOOP_KILLED)
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+ /* free cursor memory */
+ free_items(free_list);
+ free_list= 0;
+ free_root(&main_mem_root, MYF(0));
+ }
+}
+
+
+void
+Cursor::close()
+{
+ THD *thd= join->thd;
+ DBUG_ENTER("Cursor::close");
+
+ join->join_free(0);
+ if (unit)
+ {
+ /* In case of UNIONs JOIN is freed inside unit->cleanup() */
+ unit->cleanup();
+ }
+ else
+ {
+ join->cleanup();
+ delete join;
+ }
+ /* XXX: Another hack: closing tables used in the cursor */
+ {
+ DBUG_ASSERT(lock || open_tables || derived_tables);
+
+ TABLE *tmp_derived_tables= thd->derived_tables;
+ MYSQL_LOCK *tmp_lock= thd->lock;
+
+ thd->open_tables= open_tables;
+ thd->derived_tables= derived_tables;
+ thd->lock= lock;
+ close_thread_tables(thd);
+
+ thd->open_tables= tmp_derived_tables;
+ thd->derived_tables= tmp_derived_tables;
+ thd->lock= tmp_lock;
+ }
+ join= 0;
+ unit= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+Cursor::~Cursor()
+{
+ if (is_open())
+ close();
+ free_items(free_list);
+ /*
+ Must be last, as some memory might be allocated for free purposes,
+ like in free_tmp_table() (TODO: fix this issue)
+ */
+ free_root(&main_mem_root, MYF(0));
+}
+
+/*********************************************************************/
+
+
+bool
mysql_select(THD *thd, Item ***rref_pointer_array,
TABLE_LIST *tables, uint wild_num, List<Item> &fields,
COND *conds, uint og_num, ORDER *order, ORDER *group,
@@ -1539,7 +1941,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
select_result *result, SELECT_LEX_UNIT *unit,
SELECT_LEX *select_lex)
{
- int err;
+ bool err;
bool free_join= 1;
DBUG_ENTER("mysql_select");
@@ -1547,7 +1949,10 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
if (select_lex->join != 0)
{
join= select_lex->join;
- // is it single SELECT in derived table, called in derived table creation
+ /*
+ is it single SELECT in derived table, called in derived table
+ creation
+ */
if (select_lex->linkage != DERIVED_TABLE_TYPE ||
(select_options & SELECT_DESCRIBE))
{
@@ -1556,7 +1961,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
//here is EXPLAIN of subselect or derived table
if (join->change_result(result))
{
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
else
@@ -1575,7 +1980,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
else
{
if (!(join= new JOIN(thd, fields, select_options, result)))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
thd->proc_info="init";
thd->used_tables=0; // Updated by setup_fields
if (join->prepare(rref_pointer_array, tables, wild_num,
@@ -1602,6 +2007,16 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
join->exec();
+ if (thd->cursor && thd->cursor->is_open())
+ {
+ /*
+ A cursor was opened for the last sweep in exec().
+ We are here only if this is mysql_select for top-level SELECT_LEX_UNIT
+ and there were no error.
+ */
+ free_join= 0;
+ }
+
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
select_lex->where= join->conds_history;
@@ -1613,10 +2028,8 @@ err:
{
thd->proc_info="end";
err= join->cleanup();
- if (thd->net.report_error)
- err= -1;
delete join;
- DBUG_RETURN(err);
+ DBUG_RETURN(err || thd->net.report_error);
}
DBUG_RETURN(join->error);
}
@@ -1659,10 +2072,11 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
*/
static bool
-make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
+make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
DYNAMIC_ARRAY *keyuse_array)
{
int error;
+ TABLE *table;
uint i,table_count,const_count,key;
table_map found_const_table_map, all_table_map, found_ref, refs;
key_map const_ref, eq_part;
@@ -1686,47 +2100,60 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
found_const_table_map= all_table_map=0;
const_count=0;
- for (s=stat,i=0 ; tables ; s++,tables=tables->next,i++)
+ for (s= stat, i= 0;
+ tables;
+ s++, tables= tables->next_leaf, i++)
{
- TABLE *table;
+ TABLE_LIST *embedding= tables->embedding;
stat_vector[i]=s;
s->keys.init();
s->const_keys.init();
s->checked_keys.init();
s->needed_reg.init();
table_vector[i]=s->table=table=tables->table;
+ table->pos_in_table_list= tables;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);// record count
table->quick_keys.clear_all();
table->reginfo.join_tab=s;
table->reginfo.not_exists_optimize=0;
- bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
+ bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->s->keys);
all_table_map|= table->map;
s->join=join;
s->info=0; // For describe
- if ((s->on_expr=tables->on_expr))
+
+ s->dependent= tables->dep_tables;
+ s->key_dependent= 0;
+ if (tables->schema_table)
+ table->file->records= 2;
+
+ s->on_expr_ref= &tables->on_expr;
+ if (*s->on_expr_ref)
{
- /* Left join */
+ /* s is the only inner table of an outer join */
if (!table->file->records)
{ // Empty table
- s->key_dependent=s->dependent=0; // Ignore LEFT JOIN depend.
+ s->dependent= 0; // Ignore LEFT JOIN depend.
set_position(join,const_count++,s,(KEYUSE*) 0);
continue;
}
- s->key_dependent=s->dependent=
- s->on_expr->used_tables() & ~(table->map);
- if (table->outer_join & JOIN_TYPE_LEFT)
- s->dependent|=stat_vector[i-1]->dependent | table_vector[i-1]->map;
- if (tables->outer_join & JOIN_TYPE_RIGHT)
- s->dependent|=tables->next->table->map;
- outer_join|=table->map;
+ outer_join|= table->map;
continue;
}
- if (tables->straight) // We don't have to move this
- s->dependent= table_vector[i-1]->map | stat_vector[i-1]->dependent;
- else
- s->dependent=(table_map) 0;
- s->key_dependent=(table_map) 0;
- if ((table->system || table->file->records <= 1) && ! s->dependent &&
+ if (embedding)
+ {
+ /* s belongs to a nested join, maybe to several embedded joins */
+ do
+ {
+ NESTED_JOIN *nested_join= embedding->nested_join;
+ s->dependent|= embedding->dep_tables;
+ embedding= embedding->embedding;
+ outer_join|= nested_join->used_tables;
+ }
+ while (embedding);
+ continue;
+ }
+
+ if ((table->s->system || table->file->records <= 1) && ! s->dependent &&
!(table->file->table_flags() & HA_NOT_EXACT_COUNT) &&
!table->fulltext_searched)
{
@@ -1736,45 +2163,44 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
stat_vector[i]=0;
join->outer_join=outer_join;
- /*
- If outer join: Re-arrange tables in stat_vector so that outer join
- tables are after all tables it is dependent of.
- For example: SELECT * from A LEFT JOIN B ON B.c=C.c, C WHERE A.C=C.C
- Will shift table B after table C.
- */
- if (outer_join)
+ if (join->outer_join)
{
- table_map used_tables=0L;
- for (i=0 ; i < join->tables-1 ; i++)
+ /*
+ Build transitive closure for relation 'to be dependent on'.
+ This will speed up the plan search for many cases with outer joins,
+ as well as allow us to catch illegal cross references/
+ Warshall's algorithm is used to build the transitive closure.
+ As we use bitmaps to represent the relation the complexity
+ of the algorithm is O((number of tables)^2).
+ */
+ for (i= 0, s= stat ; i < table_count ; i++, s++)
{
- if (stat_vector[i]->dependent & ~used_tables)
+ for (uint j= 0 ; j < table_count ; j++)
{
- JOIN_TAB *save= stat_vector[i];
- uint j;
- for (j=i+1;
- j < join->tables && stat_vector[j]->dependent & ~used_tables;
- j++)
- {
- JOIN_TAB *tmp=stat_vector[j]; // Move element up
- stat_vector[j]=save;
- save=tmp;
- }
- if (j == join->tables)
- {
- join->tables=0; // Don't use join->table
- my_error(ER_WRONG_OUTER_JOIN,MYF(0));
- DBUG_RETURN(1);
- }
- stat_vector[i]=stat_vector[j];
- stat_vector[j]=save;
+ table= stat[j].table;
+ if (s->dependent & table->map)
+ s->dependent |= table->reginfo.join_tab->dependent;
+ }
+ if (s->dependent)
+ s->table->maybe_null= 1;
+ }
+ /* Catch illegal cross references for outer joins */
+ for (i= 0, s= stat ; i < table_count ; i++, s++)
+ {
+ if (s->dependent & s->table->map)
+ {
+ join->tables=0; // Don't use join->table
+ my_message(ER_WRONG_OUTER_JOIN, ER(ER_WRONG_OUTER_JOIN), MYF(0));
+ DBUG_RETURN(1);
}
- used_tables|= stat_vector[i]->table->map;
+ s->key_dependent= s->dependent;
}
}
if (conds || outer_join)
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables,
- conds, ~outer_join, join->select_lex))
+ conds, join->cond_equal,
+ ~outer_join, join->select_lex))
DBUG_RETURN(1);
/* Read tables with 0 or 1 rows (system tables) */
@@ -1811,14 +2237,15 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
for (JOIN_TAB **pos=stat_vector+const_count ; (s= *pos) ; pos++)
{
- TABLE *table=s->table;
+ table=s->table;
if (s->dependent) // If dependent on some table
{
// All dep. must be constants
if (s->dependent & ~(found_const_table_map))
continue;
if (table->file->records <= 1L &&
- !(table->file->table_flags() & HA_NOT_EXACT_COUNT))
+ !(table->file->table_flags() & HA_NOT_EXACT_COUNT) &&
+ !table->pos_in_table_list->embedding)
{ // system table
int tmp= 0;
s->type=JT_SYSTEM;
@@ -1917,14 +2344,23 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0;
- if (! s->const_keys.is_clear_all())
+ /*
+ Add to stat->const_keys those indexes for which all group fields or
+ all select distinct fields participate in one index.
+ */
+ add_group_and_distinct_keys(join, s);
+
+ if (!s->const_keys.is_clear_all() &&
+ !s->table->pos_in_table_list->embedding)
{
ha_rows records;
SQL_SELECT *select;
select= make_select(s->table, found_const_table_map,
found_const_table_map,
- s->on_expr ? s->on_expr : conds,
- &error);
+ *s->on_expr_ref ? *s->on_expr_ref : conds,
+ 1, &error);
+ if (!select)
+ DBUG_RETURN(1);
records= get_quick_record_count(join->thd, select, s->table,
&s->const_keys, join->row_limit);
s->quick=select->quick;
@@ -1941,7 +2377,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->const_table_map|= s->table->map;
set_position(join,const_count++,s,(KEYUSE*) 0);
s->type= JT_CONST;
- if (s->on_expr)
+ if (*s->on_expr_ref)
{
/* Generate empty row */
s->info= "Impossible ON condition";
@@ -1959,17 +2395,17 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
}
}
- /* Find best combination and return it */
join->join_tab=stat;
join->map2table=stat_ref;
join->table= join->all_tables=table_vector;
join->const_tables=const_count;
join->found_const_table_map=found_const_table_map;
+ /* Find an optimal join order of the non-constant tables. */
if (join->const_tables != join->tables)
{
optimize_keyuse(join, keyuse_array);
- find_best_combination(join,all_table_map & ~join->const_table_map);
+ choose_plan(join, all_table_map & ~join->const_table_map);
}
else
{
@@ -1977,6 +2413,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
sizeof(POSITION)*join->const_tables);
join->best_read=1.0;
}
+ /* Generate an execution plan from the found optimal join order. */
DBUG_RETURN(join->thd->killed || get_best_combination(join));
}
@@ -2121,6 +2558,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
add_key_field()
key_fields Pointer to add key, if usable
and_level And level, to be stored in KEY_FIELD
+ cond Condition predicate
field Field used in comparision
eq_func True if we used =, <=> or IS NULL
value Value used for comparison with field
@@ -2137,7 +2575,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
static void
add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
- Field *field,bool eq_func,Item **value, uint num_values,
+ Field *field, bool eq_func, Item **value, uint num_values,
table_map usable_tables)
{
uint exists_optimize= 0;
@@ -2213,7 +2651,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
We can't use indexes if the effective collation
of the operation differ from the field collation.
- We can also not used index on a text column, as the column may
+ We also cannot use index on a text column, as the column may
contain 'x' 'x\t' 'x ' and 'read_next_same' will stop after
'x' when searching for WHERE col='x '
*/
@@ -2252,15 +2690,56 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
}
/*
- SYNOPSIS
- add_key_fields()
- key_fields Add KEY_FIELD entries to this array (and move the
- pointer)
- and_level AND-level (a value that is different for every n-way
- AND operation)
- cond Condition to analyze
- usable_tables Value to pass to add_key_field
+ Add possible keys to array of possible keys originated from a simple predicate
+
+ SYNPOSIS
+ add_key_equal_fields()
+ key_fields Pointer to add key, if usable
+ and_level And level, to be stored in KEY_FIELD
+ cond Condition predicate
+ field Field used in comparision
+ eq_func True if we used =, <=> or IS NULL
+ value Value used for comparison with field
+ Is NULL for BETWEEN and IN
+ usable_tables Tables which can be used for key optimization
+
+ NOTES
+ If field items f1 and f2 belong to the same multiple equality and
+ a key is added for f1, the the same key is added for f2.
+
+ RETURN
+ *key_fields is incremented if we stored a key in the array
*/
+
+static void
+add_key_equal_fields(KEY_FIELD **key_fields, uint and_level,
+ Item_func *cond, Item_field *field_item,
+ bool eq_func, Item **val,
+ uint num_values, table_map usable_tables)
+{
+ Field *field= field_item->field;
+ add_key_field(key_fields, and_level, cond, field,
+ eq_func, val, num_values, usable_tables);
+ Item_equal *item_equal= field_item->item_equal;
+ if (item_equal)
+ {
+ /*
+ Add to the set of possible key values every substitution of
+ the field for an equal field included into item_equal
+ */
+ Item_equal_iterator it(*item_equal);
+ Item_field *item;
+ while ((item= it++))
+ {
+ if (!field->eq(item->field))
+ {
+ add_key_field(key_fields, and_level, cond, item->field,
+ eq_func, val, num_values, usable_tables);
+ }
+ }
+ }
+}
+
static void
add_key_fields(KEY_FIELD **key_fields,uint *and_level,
COND *cond, table_map usable_tables)
@@ -2303,16 +2782,26 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
case Item_func::OPTIMIZE_NONE:
break;
case Item_func::OPTIMIZE_KEY:
- // BETWEEN, IN, NOT
+ {
+ // BETWEEN, IN, NE
if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM &&
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
- add_key_field(key_fields,*and_level,cond_func,
- ((Item_field*)(cond_func->key_item()->real_item()))->field,
- cond_func->argument_count() == 2 &&
- cond_func->functype() == Item_func::IN_FUNC,
- cond_func->arguments()+1, cond_func->argument_count()-1,
- usable_tables);
+ {
+ Item **values= cond_func->arguments()+1;
+ if (cond_func->functype() == Item_func::NE_FUNC &&
+ cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
+ !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
+ values--;
+ add_key_equal_fields(key_fields, *and_level, cond_func,
+ (Item_field*) (cond_func->key_item()->real_item()),
+ cond_func->argument_count() == 2 &&
+ cond_func->functype() == Item_func::IN_FUNC,
+ values,
+ cond_func->argument_count()-1,
+ usable_tables);
+ }
break;
+ }
case Item_func::OPTIMIZE_OP:
{
bool equal_func=(cond_func->functype() == Item_func::EQ_FUNC ||
@@ -2321,21 +2810,19 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
!(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
{
- add_key_field(key_fields,*and_level,cond_func,
- ((Item_field*) (cond_func->arguments()[0])->real_item())
- ->field,
- equal_func,
- cond_func->arguments()+1, 1, usable_tables);
+ add_key_equal_fields(key_fields, *and_level, cond_func,
+ (Item_field*) (cond_func->arguments()[0])->real_item(),
+ equal_func,
+ cond_func->arguments()+1, 1, usable_tables);
}
if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
cond_func->functype() != Item_func::LIKE_FUNC &&
!(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT))
{
- add_key_field(key_fields,*and_level,cond_func,
- ((Item_field*) (cond_func->arguments()[1])->real_item())
- ->field,
- equal_func,
- cond_func->arguments(),1,usable_tables);
+ add_key_equal_fields(key_fields, *and_level, cond_func,
+ (Item_field*) (cond_func->arguments()[1])->real_item(),
+ equal_func,
+ cond_func->arguments(),1,usable_tables);
}
break;
}
@@ -2347,15 +2834,55 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
Item *tmp=new Item_null;
if (unlikely(!tmp)) // Should never be true
return;
- add_key_field(key_fields,*and_level,cond_func,
- ((Item_field*) (cond_func->arguments()[0])->real_item())
- ->field,
+ add_key_equal_fields(key_fields, *and_level, cond_func,
+ (Item_field*) (cond_func->arguments()[0])->real_item(),
cond_func->functype() == Item_func::ISNULL_FUNC,
&tmp, 1, usable_tables);
}
break;
+ case Item_func::OPTIMIZE_EQUAL:
+ Item_equal *item_equal= (Item_equal *) cond;
+ Item *const_item= item_equal->get_const();
+ Item_equal_iterator it(*item_equal);
+ Item_field *item;
+ if (const_item)
+ {
+ /*
+ For each field field1 from item_equal consider the equality
+ field1=const_item as a condition allowing an index access of the table
+ with field1 by the keys value of field1.
+ */
+ while ((item= it++))
+ {
+ add_key_field(key_fields, *and_level, cond_func, item->field,
+ TRUE, &const_item, 1, usable_tables);
+ }
+ }
+ else
+ {
+ /*
+ Consider all pairs of different fields included into item_equal.
+ For each of them (field1, field1) consider the equality
+ field1=field2 as a condition allowing an index access of the table
+ with field1 by the keys value of field2.
+ */
+ Item_equal_iterator fi(*item_equal);
+ while ((item= fi++))
+ {
+ Field *field= item->field;
+ while ((item= it++))
+ {
+ if (!field->eq(item->field))
+ {
+ add_key_field(key_fields, *and_level, cond_func, field,
+ TRUE, (Item **) &item, 1, usable_tables);
+ }
+ }
+ it.rewind();
+ }
+ }
+ break;
}
- return;
}
/*
@@ -2380,7 +2907,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
if (key_field->eq_func && !(key_field->optimize & KEY_OPTIMIZE_EXISTS))
{
- for (uint key=0 ; key < form->keys ; key++)
+ for (uint key=0 ; key < form->s->keys ; key++)
{
if (!(form->keys_in_use_for_query.is_set(key)))
continue;
@@ -2430,14 +2957,14 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
Item_func *arg0=(Item_func *)(func->arguments()[0]),
*arg1=(Item_func *)(func->arguments()[1]);
if (arg1->const_item() &&
- ((functype == Item_func::GE_FUNC && arg1->val()> 0) ||
- (functype == Item_func::GT_FUNC && arg1->val()>=0)) &&
+ ((functype == Item_func::GE_FUNC && arg1->val_real() > 0) ||
+ (functype == Item_func::GT_FUNC && arg1->val_real() >=0)) &&
arg0->type() == Item::FUNC_ITEM &&
arg0->functype() == Item_func::FT_FUNC)
cond_func=(Item_func_match *) arg0;
else if (arg0->const_item() &&
- ((functype == Item_func::LE_FUNC && arg0->val()> 0) ||
- (functype == Item_func::LT_FUNC && arg0->val()>=0)) &&
+ ((functype == Item_func::LE_FUNC && arg0->val_real() > 0) ||
+ (functype == Item_func::LT_FUNC && arg0->val_real() >=0)) &&
arg1->type() == Item::FUNC_ITEM &&
arg1->functype() == Item_func::FT_FUNC)
cond_func=(Item_func_match *) arg1;
@@ -2513,15 +3040,19 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
static bool
update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
- uint tables, COND *cond, table_map normal_tables,
- SELECT_LEX *select_lex)
+ uint tables, COND *cond, COND_EQUAL *cond_equal,
+ table_map normal_tables, SELECT_LEX *select_lex)
{
uint and_level,i,found_eq_constant;
KEY_FIELD *key_fields, *end, *field;
+ uint m= 1;
+
+ if (cond_equal && cond_equal->max_members)
+ m= cond_equal->max_members;
if (!(key_fields=(KEY_FIELD*)
thd->alloc(sizeof(key_fields[0])*
- (thd->lex->current_select->cond_count+1)*2)))
+ (thd->lex->current_select->cond_count+1)*2*m)))
return TRUE; /* purecov: inspected */
and_level= 0;
field= end= key_fields;
@@ -2541,11 +3072,32 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
}
for (i=0 ; i < tables ; i++)
{
- if (join_tab[i].on_expr)
- {
- add_key_fields(&end,&and_level,join_tab[i].on_expr,
+ /*
+ Block the creation of keys for inner tables of outer joins.
+ Here only the outer joins that can not be converted to
+ inner joins are left and all nests that can be eliminated
+ are flattened.
+ In the future when we introduce conditional accesses
+ for inner tables in outer joins these keys will be taken
+ into account as well.
+ */
+ if (*join_tab[i].on_expr_ref)
+ {
+ add_key_fields(&end,&and_level,*join_tab[i].on_expr_ref,
join_tab[i].table->map);
}
+ else
+ {
+ TABLE_LIST *tab= join_tab[i].table->pos_in_table_list;
+ TABLE_LIST *embedding= tab->embedding;
+ if (embedding)
+ {
+ NESTED_JOIN *nested_join= embedding->nested_join;
+ if (nested_join->join_list.head() == tab)
+ add_key_fields(&end, &and_level, embedding->on_expr,
+ nested_join->used_tables);
+ }
+ }
}
/* fill keyuse with found key parts */
for ( ; field != end ; field++)
@@ -2557,10 +3109,14 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
}
/*
- Special treatment for ft-keys.
- Remove the following things from KEYUSE:
+ Sort the array of possible keys and remove the following key parts:
- ref if there is a keypart which is a ref and a const.
- - keyparts without previous keyparts.
+ (e.g. if there is a key(a,b) and the clause is a=3 and b=7 and b=t2.d,
+ then we skip the key part corresponding to b=t2.d)
+ - keyparts without previous keyparts
+ (e.g. if there is a key(a,b,c) but only b < 5 (or a=2 and c < 3) is
+ used in the query, we drop the partial key parts from consideration).
+ Special treatment for ft-keys.
*/
if (keyuse->elements)
{
@@ -2608,7 +3164,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
}
/*
- Update some values in keyuse for faster find_best_combination() loop
+ Update some values in keyuse for faster choose_plan() loop
*/
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
@@ -2649,6 +3205,68 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
}
+/*
+ Discover the indexes that can be used for GROUP BY or DISTINCT queries.
+
+ SYNOPSIS
+ add_group_and_distinct_keys()
+ join
+ join_tab
+
+ DESCRIPTION
+ If the query has a GROUP BY clause, find all indexes that contain all
+ GROUP BY fields, and add those indexes to join->const_keys.
+ If the query has a DISTINCT clause, find all indexes that contain all
+ SELECT fields, and add those indexes to join->const_keys.
+ This allows later on such queries to be processed by a
+ QUICK_GROUP_MIN_MAX_SELECT.
+
+ RETURN
+ None
+*/
+
+static void
+add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
+{
+ List<Item_field> indexed_fields;
+ List_iterator<Item_field> indexed_fields_it(indexed_fields);
+ ORDER *cur_group;
+ Item_field *cur_item;
+ key_map possible_keys(0);
+
+ if (join->group_list)
+ { /* Collect all query fields referenced in the GROUP clause. */
+ for (cur_group= join->group_list; cur_group; cur_group= cur_group->next)
+ (*cur_group->item)->walk(&Item::collect_item_field_processor,
+ (byte*) &indexed_fields);
+ }
+ else if (join->select_distinct)
+ { /* Collect all query fields referenced in the SELECT clause. */
+ List<Item> &select_items= join->fields_list;
+ List_iterator<Item> select_items_it(select_items);
+ Item *item;
+ while ((item= select_items_it++))
+ item->walk(&Item::collect_item_field_processor, (byte*) &indexed_fields);
+ }
+ else
+ return;
+
+ if (indexed_fields.elements == 0)
+ return;
+
+ /* Intersect the keys of all group fields. */
+ cur_item= indexed_fields_it++;
+ possible_keys.merge(cur_item->field->part_of_key);
+ while ((cur_item= indexed_fields_it++))
+ {
+ possible_keys.intersect(cur_item->field->part_of_key);
+ }
+
+ if (!possible_keys.is_clear_all())
+ join_tab->const_keys.merge(possible_keys);
+}
+
+
/*****************************************************************************
Go through all combinations of not marked tables and find the one
which uses least records
@@ -2676,16 +3294,984 @@ set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
}
+/*
+ Find the best access path for an extension of a partial execution plan and
+ add this path to the plan.
+
+ SYNOPSIS
+ best_access_path()
+ join pointer to the structure providing all context info
+ for the query
+ s the table to be joined by the function
+ thd thread for the connection that submitted the query
+ remaining_tables set of tables not included into the partial plan yet
+ idx the length of the partial plan
+ record_count estimate for the number of records returned by the partial
+ plan
+ read_time the cost of the partial plan
+
+ DESCRIPTION
+ The function finds the best access path to table 's' from the passed
+ partial plan where an access path is the general term for any means to
+ access the data in 's'. An access path may use either an index or a scan,
+ whichever is cheaper. The input partial plan is passed via the array
+ 'join->positions' of length 'idx'. The chosen access method for 's' and its
+ cost are stored in 'join->positions[idx]'.
+
+ RETURN
+ None
+*/
+
+static void
+best_access_path(JOIN *join,
+ JOIN_TAB *s,
+ THD *thd,
+ table_map remaining_tables,
+ uint idx,
+ double record_count,
+ double read_time)
+{
+ KEYUSE *best_key= 0;
+ uint best_max_key_part= 0;
+ my_bool found_constraint= 0;
+ double best= DBL_MAX;
+ double best_time= DBL_MAX;
+ double records= DBL_MAX;
+ double tmp;
+ ha_rows rec;
+
+ DBUG_ENTER("best_access_path");
+
+ if (s->keyuse)
+ { /* Use key if possible */
+ TABLE *table= s->table;
+ KEYUSE *keyuse,*start_key=0;
+ double best_records= DBL_MAX;
+ uint max_key_part=0;
+
+ /* Test how we can use keys */
+ rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key
+ for (keyuse=s->keyuse ; keyuse->table == table ;)
+ {
+ key_part_map found_part= 0;
+ table_map found_ref= 0;
+ uint found_ref_or_null= 0;
+ uint key= keyuse->key;
+ KEY *keyinfo= table->key_info+key;
+ bool ft_key= (keyuse->keypart == FT_KEYPART);
+
+ /* Calculate how many key segments of the current key we can use */
+ start_key= keyuse;
+ do
+ { /* for each keypart */
+ uint keypart= keyuse->keypart;
+ uint found_part_ref_or_null= KEY_OPTIMIZE_REF_OR_NULL;
+ do
+ {
+ if (!(remaining_tables & keyuse->used_tables) &&
+ !(found_ref_or_null & keyuse->optimize))
+ {
+ found_part|= keyuse->keypart_map;
+ found_ref|= keyuse->used_tables;
+ if (rec > keyuse->ref_table_rows)
+ rec= keyuse->ref_table_rows;
+ found_part_ref_or_null&= keyuse->optimize;
+ }
+ keyuse++;
+ found_ref_or_null|= found_part_ref_or_null;
+ } while (keyuse->table == table && keyuse->key == key &&
+ keyuse->keypart == keypart);
+ } while (keyuse->table == table && keyuse->key == key);
+
+ /*
+ Assume that that each key matches a proportional part of table.
+ */
+ if (!found_part && !ft_key)
+ continue; // Nothing usable found
+
+ if (rec < MATCHING_ROWS_IN_OTHER_TABLE)
+ rec= MATCHING_ROWS_IN_OTHER_TABLE; // Fix for small tables
+
+ /*
+ ft-keys require special treatment
+ */
+ if (ft_key)
+ {
+ /*
+ Really, there should be records=0.0 (yes!)
+ but 1.0 would be probably safer
+ */
+ tmp= prev_record_reads(join, found_ref);
+ records= 1.0;
+ }
+ else
+ {
+ found_constraint= 1;
+ /*
+ Check if we found full key
+ */
+ if (found_part == PREV_BITS(uint,keyinfo->key_parts) &&
+ !found_ref_or_null)
+ { /* use eq key */
+ max_key_part= (uint) ~0;
+ if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
+ {
+ tmp = prev_record_reads(join, found_ref);
+ records=1.0;
+ }
+ else
+ {
+ if (!found_ref)
+ { /* We found a const key */
+ if (table->quick_keys.is_set(key))
+ records= (double) table->quick_rows[key];
+ else
+ {
+ /* quick_range couldn't use key! */
+ records= (double) s->records/rec;
+ }
+ }
+ else
+ {
+ if (!(records=keyinfo->rec_per_key[keyinfo->key_parts-1]))
+ { /* Prefer longer keys */
+ records=
+ ((double) s->records / (double) rec *
+ (1.0 +
+ ((double) (table->s->max_key_length-keyinfo->key_length) /
+ (double) table->s->max_key_length)));
+ if (records < 2.0)
+ records=2.0; /* Can't be as good as a unique */
+ }
+ }
+ /* Limit the number of matched rows */
+ tmp = records;
+ set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
+ if (table->used_keys.is_set(key))
+ {
+ /* we can use only index tree */
+ uint keys_per_block= table->file->block_size/2/
+ (keyinfo->key_length+table->file->ref_length)+1;
+ tmp = record_count*(tmp+keys_per_block-1)/keys_per_block;
+ }
+ else
+ tmp = record_count*min(tmp,s->worst_seeks);
+ }
+ }
+ else
+ {
+ /*
+ Use as much key-parts as possible and a uniq key is better
+ than a not unique key
+ Set tmp to (previous record count) * (records / combination)
+ */
+ if ((found_part & 1) &&
+ (!(table->file->index_flags(key, 0, 0) & HA_ONLY_WHOLE_INDEX) ||
+ found_part == PREV_BITS(uint,keyinfo->key_parts)))
+ {
+ max_key_part=max_part_bit(found_part);
+ /*
+ Check if quick_range could determinate how many rows we
+ will match
+ */
+ if (table->quick_keys.is_set(key) &&
+ table->quick_key_parts[key] == max_key_part)
+ tmp= records= (double) table->quick_rows[key];
+ else
+ {
+ /* Check if we have statistic about the distribution */
+ if ((records = keyinfo->rec_per_key[max_key_part-1]))
+ tmp = records;
+ else
+ {
+ /*
+ Assume that the first key part matches 1% of the file
+ and that the whole key matches 10 (duplicates) or 1
+ (unique) records.
+ Assume also that more key matches proportionally more
+ records
+ This gives the formula:
+ records = (x * (b-a) + a*c-b)/(c-1)
+
+ b = records matched by whole key
+ a = records matched by first key part (1% of all records?)
+ c = number of key parts in key
+ x = used key parts (1 <= x <= c)
+ */
+ double rec_per_key;
+ if (!(rec_per_key=(double)
+ keyinfo->rec_per_key[keyinfo->key_parts-1]))
+ rec_per_key=(double) s->records/rec+1;
+
+ if (!s->records)
+ tmp = 0;
+ else if (rec_per_key/(double) s->records >= 0.01)
+ tmp = rec_per_key;
+ else
+ {
+ double a=s->records*0.01;
+ if (keyinfo->key_parts > 1)
+ tmp= (max_key_part * (rec_per_key - a) +
+ a*keyinfo->key_parts - rec_per_key)/
+ (keyinfo->key_parts-1);
+ else
+ tmp= a;
+ set_if_bigger(tmp,1.0);
+ }
+ records = (ulong) tmp;
+ }
+ /*
+ If quick_select was used on a part of this key, we know
+ the maximum number of rows that the key can match.
+ */
+ if (table->quick_keys.is_set(key) &&
+ table->quick_key_parts[key] <= max_key_part &&
+ records > (double) table->quick_rows[key])
+ tmp= records= (double) table->quick_rows[key];
+ else if (found_ref_or_null)
+ {
+ /* We need to do two key searches to find key */
+ tmp *= 2.0;
+ records *= 2.0;
+ }
+ }
+ /* Limit the number of matched rows */
+ set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
+ if (table->used_keys.is_set(key))
+ {
+ /* we can use only index tree */
+ uint keys_per_block= table->file->block_size/2/
+ (keyinfo->key_length+table->file->ref_length)+1;
+ tmp = record_count*(tmp+keys_per_block-1)/keys_per_block;
+ }
+ else
+ tmp = record_count*min(tmp,s->worst_seeks);
+ }
+ else
+ tmp = best_time; // Do nothing
+ }
+ } /* not ft_key */
+ if (tmp < best_time - records/(double) TIME_FOR_COMPARE)
+ {
+ best_time= tmp + records/(double) TIME_FOR_COMPARE;
+ best= tmp;
+ best_records= records;
+ best_key= start_key;
+ best_max_key_part= max_key_part;
+ }
+ }
+ records= best_records;
+ }
+
+ /*
+ Don't test table scan if it can't be better.
+ Prefer key lookup if we would use the same key for scanning.
+
+ Don't do a table scan on InnoDB tables, if we can read the used
+ parts of the row from any of the used index.
+ This is because table scans uses index and we would not win
+ anything by using a table scan.
+ */
+ if ((records >= s->found_records || best > s->read_time) &&
+ !(s->quick && best_key && s->quick->index == best_key->key &&
+ best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
+ !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
+ ! s->table->used_keys.is_clear_all() && best_key) &&
+ !(s->table->force_index && best_key))
+ { // Check full join
+ ha_rows rnd_records= s->found_records;
+ /*
+ If there is a restriction on the table, assume that 25% of the
+ rows can be skipped on next part.
+ This is to force tables that this table depends on before this
+ table
+ */
+ if (found_constraint)
+ rnd_records-= rnd_records/4;
+
+ /*
+ Range optimizer never proposes a RANGE if it isn't better
+ than FULL: so if RANGE is present, it's always preferred to FULL.
+ Here we estimate its cost.
+ */
+ if (s->quick)
+ {
+ /*
+ For each record we:
+ - read record range through 'quick'
+ - skip rows which does not satisfy WHERE constraints
+ */
+ tmp= record_count *
+ (s->quick->read_time +
+ (s->found_records - rnd_records)/(double) TIME_FOR_COMPARE);
+ }
+ else
+ {
+ /* Estimate cost of reading table. */
+ tmp= s->table->file->scan_time();
+ if (s->table->map & join->outer_join) // Can't use join cache
+ {
+ /*
+ For each record we have to:
+ - read the whole table record
+ - skip rows which does not satisfy join condition
+ */
+ tmp= record_count *
+ (tmp +
+ (s->records - rnd_records)/(double) TIME_FOR_COMPARE);
+ }
+ else
+ {
+ /* We read the table as many times as join buffer becomes full. */
+ tmp*= (1.0 + floor((double) cache_record_length(join,idx) *
+ record_count /
+ (double) thd->variables.join_buff_size));
+ /*
+ We don't make full cartesian product between rows in the scanned
+ table and existing records because we skip all rows from the
+ scanned table, which does not satisfy join condition when
+ we read the table (see flush_cached_records for details). Here we
+ take into account cost to read and skip these records.
+ */
+ tmp+= (s->records - rnd_records)/(double) TIME_FOR_COMPARE;
+ }
+ }
+
+ /*
+ We estimate the cost of evaluating WHERE clause for found records
+ as record_count * rnd_records / TIME_FOR_COMPARE. This cost plus
+ tmp give us total cost of using TABLE SCAN
+ */
+ if (best == DBL_MAX ||
+ (tmp + record_count/(double) TIME_FOR_COMPARE*rnd_records <
+ best + record_count/(double) TIME_FOR_COMPARE*records))
+ {
+ /*
+ If the table has a range (s->quick is set) make_join_select()
+ will ensure that this will be used
+ */
+ best= tmp;
+ records= rows2double(rnd_records);
+ best_key= 0;
+ }
+ }
+
+ /* Update the cost information for the current partial plan */
+ join->positions[idx].records_read= records;
+ join->positions[idx].read_time= best;
+ join->positions[idx].key= best_key;
+ join->positions[idx].table= s;
+
+ if (!best_key &&
+ idx == join->const_tables &&
+ s->table == join->sort_by_table &&
+ join->unit->select_limit_cnt >= records)
+ join->sort_by_table= (TABLE*) 1; // Must use temporary table
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Selects and invokes a search strategy for an optimal query plan.
+
+ SYNOPSIS
+ choose_plan()
+ join pointer to the structure providing all context info for
+ the query
+ join_tables set of the tables in the query
+
+ DESCRIPTION
+ The function checks user-configurable parameters that control the search
+ strategy for an optimal plan, selects the search method and then invokes
+ it. Each specific optimization procedure stores the final optimal plan in
+ the array 'join->best_positions', and the cost of the plan in
+ 'join->best_read'.
+
+ RETURN
+ None
+*/
+
static void
-find_best_combination(JOIN *join, table_map rest_tables)
+choose_plan(JOIN *join, table_map join_tables)
{
- DBUG_ENTER("find_best_combination");
- join->best_read=DBL_MAX;
- find_best(join,rest_tables, join->const_tables,1.0,0.0);
+ uint search_depth= join->thd->variables.optimizer_search_depth;
+ uint prune_level= join->thd->variables.optimizer_prune_level;
+ bool straight_join= join->select_options & SELECT_STRAIGHT_JOIN;
+ DBUG_ENTER("choose_plan");
+
+ /*
+ if (SELECT_STRAIGHT_JOIN option is set)
+ reorder tables so dependent tables come after tables they depend
+ on, otherwise keep tables in the order they were specified in the query
+ else
+ Apply heuristic: pre-sort all access plans with respect to the number of
+ records accessed.
+ */
+ qsort(join->best_ref + join->const_tables, join->tables - join->const_tables,
+ sizeof(JOIN_TAB*), straight_join?join_tab_cmp_straight:join_tab_cmp);
+
+ if (straight_join)
+ {
+ optimize_straight_join(join, join_tables);
+ }
+ else
+ {
+ if (search_depth == MAX_TABLES+2)
+ { /*
+ TODO: 'MAX_TABLES+2' denotes the old implementation of find_best before
+ the greedy version. Will be removed when greedy_search is approved.
+ */
+ join->best_read= DBL_MAX;
+ find_best(join, join_tables, join->const_tables, 1.0, 0.0);
+ }
+ else
+ {
+ if (search_depth == 0)
+ /* Automatically determine a reasonable value for 'search_depth' */
+ search_depth= determine_search_depth(join);
+ greedy_search(join, join_tables, search_depth, prune_level);
+ }
+ }
+
+ /*
+ Store the cost of this query into a user variable
+ Don't update last_query_cost for 'show status' command
+ */
+ if (join->thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS)
+ last_query_cost= join->best_read;
+
DBUG_VOID_RETURN;
}
+/*
+ Compare two JOIN_TAB objects based on the number of accessed records.
+
+ SYNOPSIS
+ join_tab_cmp()
+ ptr1 pointer to first JOIN_TAB object
+ ptr2 pointer to second JOIN_TAB object
+
+ RETURN
+ 1 if first is bigger
+ -1 if second is bigger
+ 0 if equal
+*/
+
+static int
+join_tab_cmp(const void* ptr1, const void* ptr2)
+{
+ JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
+ JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;
+
+ if (jt1->dependent & jt2->table->map)
+ return 1;
+ if (jt2->dependent & jt1->table->map)
+ return -1;
+ if (jt1->found_records > jt2->found_records)
+ return 1;
+ if (jt1->found_records < jt2->found_records)
+ return -1;
+ return jt1 > jt2 ? 1 : (jt1 < jt2 ? -1 : 0);
+}
+
+
+/*
+ Same as join_tab_cmp, but for use with SELECT_STRAIGHT_JOIN.
+*/
+
+static int
+join_tab_cmp_straight(const void* ptr1, const void* ptr2)
+{
+ JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
+ JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;
+
+ if (jt1->dependent & jt2->table->map)
+ return 1;
+ if (jt2->dependent & jt1->table->map)
+ return -1;
+ return jt1 > jt2 ? 1 : (jt1 < jt2 ? -1 : 0);
+}
+
+/*
+ Heuristic procedure to automatically guess a reasonable degree of
+ exhaustiveness for the greedy search procedure.
+
+ SYNOPSIS
+ determine_search_depth()
+ join pointer to the structure providing all context info for the query
+
+ DESCRIPTION
+ The procedure estimates the optimization time and selects a search depth
+ big enough to result in a near-optimal QEP, that doesn't take too long to
+ find. If the number of tables in the query exceeds some constant, then
+ search_depth is set to this constant.
+
+ NOTES
+ This is an extremely simplistic implementation that serves as a stub for a
+ more advanced analysis of the join. Ideally the search depth should be
+ determined by learning from previous query optimizations, because it will
+ depend on the CPU power (and other factors).
+
+ RETURN
+ A positive integer that specifies the search depth (and thus the
+ exhaustiveness) of the depth-first search algorithm used by
+ 'greedy_search'.
+*/
+
+static uint
+determine_search_depth(JOIN *join)
+{
+ uint table_count= join->tables - join->const_tables;
+ uint search_depth;
+ /* TODO: this value should be determined dynamically, based on statistics: */
+ uint max_tables_for_exhaustive_opt= 7;
+
+ if (table_count <= max_tables_for_exhaustive_opt)
+ search_depth= table_count+1; // use exhaustive for small number of tables
+ else
+ /*
+ TODO: this value could be determined by some mapping of the form:
+ depth : table_count -> [max_tables_for_exhaustive_opt..MAX_EXHAUSTIVE]
+ */
+ search_depth= max_tables_for_exhaustive_opt; // use greedy search
+
+ return search_depth;
+}
+
+
+/*
+ Select the best ways to access the tables in a query without reordering them.
+
+ SYNOPSIS
+ optimize_straight_join()
+ join pointer to the structure providing all context info for
+ the query
+ join_tables set of the tables in the query
+
+ DESCRIPTION
+ Find the best access paths for each query table and compute their costs
+ according to their order in the array 'join->best_ref' (thus without
+ reordering the join tables). The function calls sequentially
+ 'best_access_path' for each table in the query to select the best table
+ access method. The final optimal plan is stored in the array
+ 'join->best_positions', and the corresponding cost in 'join->best_read'.
+
+ NOTES
+ This function can be applied to:
+ - queries with STRAIGHT_JOIN
+ - internally to compute the cost of an arbitrary QEP
+ Thus 'optimize_straight_join' can be used at any stage of the query
+ optimization process to finalize a QEP as it is.
+
+ RETURN
+ None
+*/
+
+static void
+optimize_straight_join(JOIN *join, table_map join_tables)
+{
+ JOIN_TAB *s;
+ uint idx= join->const_tables;
+ double record_count= 1.0;
+ double read_time= 0.0;
+
+ for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
+ {
+ /* Find the best access method from 's' to the current partial plan */
+ best_access_path(join, s, join->thd, join_tables, idx, record_count, read_time);
+ /* compute the cost of the new plan extended with 's' */
+ record_count*= join->positions[idx].records_read;
+ read_time+= join->positions[idx].read_time;
+ join_tables&= ~(s->table->map);
+ ++idx;
+ }
+
+ read_time+= record_count / (double) TIME_FOR_COMPARE;
+ if (join->sort_by_table &&
+ join->sort_by_table != join->positions[join->const_tables].table->table)
+ read_time+= record_count; // We have to make a temp table
+ memcpy((gptr) join->best_positions, (gptr) join->positions,
+ sizeof(POSITION)*idx);
+ join->best_read= read_time;
+}
+
+
+/*
+ Find a good, possibly optimal, query execution plan (QEP) by a greedy search.
+
+ SYNOPSIS
+ join pointer to the structure providing all context info
+ for the query
+ remaining_tables set of tables not included into the partial plan yet
+ search_depth controlls the exhaustiveness of the search
+ prune_level the pruning heuristics that should be applied during
+ search
+
+ DESCRIPTION
+ The search procedure uses a hybrid greedy/exhaustive search with controlled
+ exhaustiveness. The search is performed in N = card(remaining_tables)
+ steps. Each step evaluates how promising is each of the unoptimized tables,
+ selects the most promising table, and extends the current partial QEP with
+ that table. Currenly the most 'promising' table is the one with least
+ expensive extension.
+ There are two extreme cases:
+ 1. When (card(remaining_tables) < search_depth), the estimate finds the best
+ complete continuation of the partial QEP. This continuation can be
+ used directly as a result of the search.
+ 2. When (search_depth == 1) the 'best_extension_by_limited_search'
+ consideres the extension of the current QEP with each of the remaining
+ unoptimized tables.
+ All other cases are in-between these two extremes. Thus the parameter
+ 'search_depth' controlls the exhaustiveness of the search. The higher the
+ value, the longer the optimizaton time and possibly the better the
+ resulting plan. The lower the value, the fewer alternative plans are
+ estimated, but the more likely to get a bad QEP.
+
+ All intermediate and final results of the procedure are stored in 'join':
+ join->positions modified for every partial QEP that is explored
+ join->best_positions modified for the current best complete QEP
+ join->best_read modified for the current best complete QEP
+ join->best_ref might be partially reordered
+ The final optimal plan is stored in 'join->best_positions', and its
+ corresponding cost in 'join->best_read'.
+
+ NOTES
+ The following pseudocode describes the algorithm of 'greedy_search':
+
+ procedure greedy_search
+ input: remaining_tables
+ output: pplan;
+ {
+ pplan = <>;
+ do {
+ (t, a) = best_extension(pplan, remaining_tables);
+ pplan = concat(pplan, (t, a));
+ remaining_tables = remaining_tables - t;
+ } while (remaining_tables != {})
+ return pplan;
+ }
+
+ where 'best_extension' is a placeholder for a procedure that selects the
+ most "promising" of all tables in 'remaining_tables'.
+ Currently this estimate is performed by calling
+ 'best_extension_by_limited_search' to evaluate all extensions of the
+ current QEP of size 'search_depth', thus the complexity of 'greedy_search'
+ mainly depends on that of 'best_extension_by_limited_search'.
+
+ If 'best_extension()' == 'best_extension_by_limited_search()', then the
+ worst-case complexity of this algorithm is <=
+ O(N*N^search_depth/search_depth). When serch_depth >= N, then the
+ complexity of greedy_search is O(N!).
+
+ In the future, 'greedy_search' might be extended to support other
+ implementations of 'best_extension', e.g. some simpler quadratic procedure.
+
+ RETURN
+ None
+*/
+
+static void
+greedy_search(JOIN *join,
+ table_map remaining_tables,
+ uint search_depth,
+ uint prune_level)
+{
+ double record_count= 1.0;
+ double read_time= 0.0;
+ uint idx= join->const_tables; // index into 'join->best_ref'
+ uint best_idx;
+ uint rem_size; // cardinality of remaining_tables
+ POSITION best_pos;
+ JOIN_TAB *best_table; // the next plan node to be added to the curr QEP
+
+ DBUG_ENTER("greedy_search");
+
+ /* number of tables that remain to be optimized */
+ rem_size= my_count_bits(remaining_tables);
+
+ do {
+ /* Find the extension of the current QEP with the lowest cost */
+ join->best_read= DBL_MAX;
+ best_extension_by_limited_search(join, remaining_tables, idx, record_count,
+ read_time, search_depth, prune_level);
+
+ if (rem_size <= search_depth)
+ {
+ /*
+ 'join->best_positions' contains a complete optimal extension of the
+ current partial QEP.
+ */
+ DBUG_EXECUTE("opt", print_plan(join, read_time, record_count,
+ join->tables, "optimal"););
+ DBUG_VOID_RETURN;
+ }
+
+ /* select the first table in the optimal extension as most promising */
+ best_pos= join->best_positions[idx];
+ best_table= best_pos.table;
+ /*
+ Each subsequent loop of 'best_extension_by_limited_search' uses
+ 'join->positions' for cost estimates, therefore we have to update its
+ value.
+ */
+ join->positions[idx]= best_pos;
+
+ /* find the position of 'best_table' in 'join->best_ref' */
+ best_idx= idx;
+ JOIN_TAB *pos= join->best_ref[best_idx];
+ while (pos && best_table != pos)
+ pos= join->best_ref[++best_idx];
+ DBUG_ASSERT((pos != NULL)); // should always find 'best_table'
+ /* move 'best_table' at the first free position in the array of joins */
+ swap_variables(JOIN_TAB*, join->best_ref[idx], join->best_ref[best_idx]);
+
+ /* compute the cost of the new plan extended with 'best_table' */
+ record_count*= join->positions[idx].records_read;
+ read_time+= join->positions[idx].read_time;
+
+ remaining_tables&= ~(best_table->table->map);
+ --rem_size;
+ ++idx;
+
+ DBUG_EXECUTE("opt",
+ print_plan(join, read_time, record_count, idx, "extended"););
+ } while (TRUE);
+}
+
+
+/*
+ Find a good, possibly optimal, query execution plan (QEP) by a possibly
+ exhaustive search.
+
+ SYNOPSIS
+ best_extension_by_limited_search()
+ join pointer to the structure providing all context info for
+ the query
+ remaining_tables set of tables not included into the partial plan yet
+ idx length of the partial QEP in 'join->positions';
+ since a depth-first search is used, also corresponds to
+ the current depth of the search tree;
+ also an index in the array 'join->best_ref';
+ record_count estimate for the number of records returned by the best
+ partial plan
+ read_time the cost of the best partial plan
+ search_depth maximum depth of the recursion and thus size of the found
+ optimal plan (0 < search_depth <= join->tables+1).
+ prune_level pruning heuristics that should be applied during optimization
+ (values: 0 = EXHAUSTIVE, 1 = PRUNE_BY_TIME_OR_ROWS)
+
+ DESCRIPTION
+ The procedure searches for the optimal ordering of the query tables in set
+ 'remaining_tables' of size N, and the corresponding optimal access paths to each
+ table. The choice of a table order and an access path for each table
+ constitutes a query execution plan (QEP) that fully specifies how to
+ execute the query.
+
+ The maximal size of the found plan is controlled by the parameter
+ 'search_depth'. When search_depth == N, the resulting plan is complete and
+ can be used directly as a QEP. If search_depth < N, the found plan consists
+ of only some of the query tables. Such "partial" optimal plans are useful
+ only as input to query optimization procedures, and cannot be used directly
+ to execute a query.
+
+ The algorithm begins with an empty partial plan stored in 'join->positions'
+ and a set of N tables - 'remaining_tables'. Each step of the algorithm
+ evaluates the cost of the partial plan extended by all access plans for
+ each of the relations in 'remaining_tables', expands the current partial
+ plan with the access plan that results in lowest cost of the expanded
+ partial plan, and removes the corresponding relation from
+ 'remaining_tables'. The algorithm continues until it either constructs a
+ complete optimal plan, or constructs an optimal plartial plan with size =
+ search_depth.
+
+ The final optimal plan is stored in 'join->best_positions'. The
+ corresponding cost of the optimal plan is in 'join->best_read'.
+
+ NOTES
+ The procedure uses a recursive depth-first search where the depth of the
+ recursion (and thus the exhaustiveness of the search) is controlled by the
+ parameter 'search_depth'.
+
+ The pseudocode below describes the algorithm of
+ 'best_extension_by_limited_search'. The worst-case complexity of this
+ algorithm is O(N*N^search_depth/search_depth). When serch_depth >= N, then
+ the complexity of greedy_search is O(N!).
+
+ procedure best_extension_by_limited_search(
+ pplan in, // in, partial plan of tables-joined-so-far
+ pplan_cost, // in, cost of pplan
+ remaining_tables, // in, set of tables not referenced in pplan
+ best_plan_so_far, // in/out, best plan found so far
+ best_plan_so_far_cost,// in/out, cost of best_plan_so_far
+ search_depth) // in, maximum size of the plans being considered
+ {
+ for each table T from remaining_tables
+ {
+ // Calculate the cost of using table T as above
+ cost = complex-series-of-calculations;
+
+ // Add the cost to the cost so far.
+ pplan_cost+= cost;
+
+ if (pplan_cost >= best_plan_so_far_cost)
+ // pplan_cost already too great, stop search
+ continue;
+
+ pplan= expand pplan by best_access_method;
+ remaining_tables= remaining_tables - table T;
+ if (remaining_tables is not an empty set
+ and
+ search_depth > 1)
+ {
+ best_extension_by_limited_search(pplan, pplan_cost,
+ remaining_tables,
+ best_plan_so_far,
+ best_plan_so_far_cost,
+ search_depth - 1);
+ }
+ else
+ {
+ best_plan_so_far_cost= pplan_cost;
+ best_plan_so_far= pplan;
+ }
+ }
+ }
+
+ IMPLEMENTATION
+ When 'best_extension_by_limited_search' is called for the first time,
+ 'join->best_read' must be set to the largest possible value (e.g. DBL_MAX).
+ The actual implementation provides a way to optionally use pruning
+ heuristic (controlled by the parameter 'prune_level') to reduce the search
+ space by skipping some partial plans.
+ The parameter 'search_depth' provides control over the recursion
+ depth, and thus the size of the resulting optimal plan.
+
+ RETURN
+ None
+*/
+
+static void
+best_extension_by_limited_search(JOIN *join,
+ table_map remaining_tables,
+ uint idx,
+ double record_count,
+ double read_time,
+ uint search_depth,
+ uint prune_level)
+{
+ THD *thd= join->thd;
+ if (thd->killed) // Abort
+ return;
+
+ DBUG_ENTER("best_extension_by_limited_search");
+
+ /*
+ 'join' is a partial plan with lower cost than the best plan so far,
+ so continue expanding it further with the tables in 'remaining_tables'.
+ */
+ JOIN_TAB *s;
+ double best_record_count= DBL_MAX;
+ double best_read_time= DBL_MAX;
+
+ DBUG_EXECUTE("opt",
+ print_plan(join, read_time, record_count, idx, "part_plan"););
+
+ for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
+ {
+ table_map real_table_bit= s->table->map;
+ if ((remaining_tables & real_table_bit) && !(remaining_tables & s->dependent))
+ {
+ double current_record_count, current_read_time;
+
+ /* Find the best access method from 's' to the current partial plan */
+ best_access_path(join, s, thd, remaining_tables, idx, record_count, read_time);
+ /* Compute the cost of extending the plan with 's' */
+ current_record_count= record_count * join->positions[idx].records_read;
+ current_read_time= read_time + join->positions[idx].read_time;
+
+ /* Expand only partial plans with lower cost than the best QEP so far */
+ if ((current_read_time +
+ current_record_count / (double) TIME_FOR_COMPARE) >= join->best_read)
+ {
+ DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx,
+ "prune_by_cost"););
+ continue;
+ }
+
+ /*
+ Prune some less promising partial plans. This heuristic may miss
+ the optimal QEPs, thus it results in a non-exhaustive search.
+ */
+ if (prune_level == 1)
+ {
+ if (best_record_count > current_record_count ||
+ best_read_time > current_read_time ||
+ idx == join->const_tables && // 's' is the first table in the QEP
+ s->table == join->sort_by_table)
+ {
+ if (best_record_count >= current_record_count &&
+ best_read_time >= current_read_time &&
+ /* TODO: What is the reasoning behind this condition? */
+ (!(s->key_dependent & remaining_tables) ||
+ join->positions[idx].records_read < 2.0))
+ {
+ best_record_count= current_record_count;
+ best_read_time= current_read_time;
+ }
+ }
+ else
+ {
+ DBUG_EXECUTE("opt", print_plan(join, read_time, record_count, idx,
+ "pruned_by_heuristic"););
+ continue;
+ }
+ }
+
+ if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) )
+ { /* Recursively expand the current partial plan */
+ swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
+ best_extension_by_limited_search(join,
+ remaining_tables & ~real_table_bit,
+ idx + 1,
+ current_record_count,
+ current_read_time,
+ search_depth - 1,
+ prune_level);
+ if (thd->killed)
+ DBUG_VOID_RETURN;
+ swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
+ }
+ else
+ { /*
+ 'join' is either the best partial QEP with 'search_depth' relations,
+ or the best complete QEP so far, whichever is smaller.
+ */
+ current_read_time+= current_record_count / (double) TIME_FOR_COMPARE;
+ if (join->sort_by_table &&
+ join->sort_by_table != join->positions[join->const_tables].table->table)
+ /* We have to make a temp table */
+ current_read_time+= current_record_count;
+ if ((search_depth == 1) || (current_read_time < join->best_read))
+ {
+ memcpy((gptr) join->best_positions, (gptr) join->positions,
+ sizeof(POSITION) * (idx + 1));
+ join->best_read= current_read_time - 0.001;
+ }
+ DBUG_EXECUTE("opt",
+ print_plan(join, current_read_time, current_record_count, idx, "full_plan"););
+ }
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ TODO: this function is here only temporarily until 'greedy_search' is
+ tested and accepted.
+*/
static void
find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
double read_time)
@@ -2708,7 +4294,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
memcpy((gptr) join->best_positions,(gptr) join->positions,
sizeof(POSITION)*idx);
- join->best_read=read_time;
+ join->best_read= read_time - 0.001;
}
return;
}
@@ -2837,8 +4423,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
records=
((double) s->records / (double) rec *
(1.0 +
- ((double) (table->max_key_length-keyinfo->key_length) /
- (double) table->max_key_length)));
+ ((double) (table->s->max_key_length-keyinfo->key_length) /
+ (double) table->s->max_key_length)));
if (records < 2.0)
records=2.0; // Can't be as good as a unique
}
@@ -2885,7 +4471,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
/*
Assume that the first key part matches 1% of the file
- and that the hole key matches 10 (duplicates) or 1
+ and that the whole key matches 10 (duplicates) or 1
(unique) records.
Assume also that more key matches proportionally more
records
@@ -3004,7 +4590,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
/* Estimate cost of reading table. */
tmp= s->table->file->scan_time();
- if (s->on_expr) // Can't use join cache
+ if (s->table->map & join->outer_join) // Can't use join cache
{
/*
For each record we have to:
@@ -3113,13 +4699,13 @@ static void calc_used_field_length(THD *thd, JOIN_TAB *join_tab)
}
}
if (null_fields)
- rec_length+=(join_tab->table->null_fields+7)/8;
+ rec_length+=(join_tab->table->s->null_fields+7)/8;
if (join_tab->table->maybe_null)
rec_length+=sizeof(my_bool);
if (blobs)
{
uint blob_length=(uint) (join_tab->table->file->mean_rec_length-
- (join_tab->table->reclength- rec_length));
+ (join_tab->table->s->reclength- rec_length));
rec_length+=(uint) max(4,blob_length);
}
join_tab->used_fields=fields;
@@ -3178,11 +4764,12 @@ get_best_combination(JOIN *join)
KEYUSE *keyuse;
uint table_count;
THD *thd=join->thd;
+ DBUG_ENTER("get_best_combination");
table_count=join->tables;
if (!(join->join_tab=join_tab=
(JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*table_count)))
- return TRUE;
+ DBUG_RETURN(TRUE);
join->full_join=0;
@@ -3194,8 +4781,9 @@ get_best_combination(JOIN *join)
form=join->table[tablenr]=j->table;
used_tables|= form->map;
form->reginfo.join_tab=j;
- if (!j->on_expr)
+ if (!*j->on_expr_ref)
form->reginfo.not_exists_optimize=0; // Only with LEFT JOIN
+ DBUG_PRINT("info",("type: %d", j->type));
if (j->type == JT_CONST)
continue; // Handled in make_join_stat..
@@ -3211,13 +4799,13 @@ get_best_combination(JOIN *join)
join->full_join=1;
}
else if (create_ref_for_key(join, j, keyuse, used_tables))
- return TRUE; // Something went wrong
+ DBUG_RETURN(TRUE); // Something went wrong
}
for (i=0 ; i < table_count ; i++)
join->map2table[join->join_tab[i].table->tablenr]=join->join_tab+i;
update_depend_map(join);
- return 0;
+ DBUG_RETURN(0);
}
@@ -3230,6 +4818,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
uint keyparts,length,key;
TABLE *table;
KEY *keyinfo;
+ DBUG_ENTER("create_ref_for_key");
/* Use best key from find_best */
table=j->table;
@@ -3279,7 +4868,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
(keyparts+1)))) ||
!(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts)))
{
- return TRUE;
+ DBUG_RETURN(TRUE);
}
j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
j->ref.key_err=1;
@@ -3293,7 +4882,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
{
j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
if (keyuse->used_tables)
- return TRUE; // not supported yet. SerG
+ DBUG_RETURN(TRUE); // not supported yet. SerG
j->type=JT_FT;
}
@@ -3319,7 +4908,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
maybe_null ? (char*) key_buff : 0,
keyinfo->key_part[i].length, keyuse->val);
if (thd->is_fatal_error)
- return TRUE;
+ DBUG_RETURN(TRUE);
tmp.copy();
}
else
@@ -3328,7 +4917,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
&keyinfo->key_part[i],
(char*) key_buff,maybe_null);
/*
- Remeber if we are going to use REF_OR_NULL
+ Remember if we are going to use REF_OR_NULL
But only if field _really_ can be null i.e. we force JT_REF
instead of JT_REF_OR_NULL in case if field can't be null
*/
@@ -3339,7 +4928,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
} /* not ftkey */
*ref_key=0; // end_marker
if (j->type == JT_FT)
- return 0;
+ DBUG_RETURN(0);
if (j->type == JT_CONST)
j->table->const_table= 1;
else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY |
@@ -3363,7 +4952,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
}
else
j->type=JT_EQ_REF;
- return 0;
+ DBUG_RETURN(0);
}
@@ -3406,7 +4995,7 @@ bool
store_val_in_field(Field *field,Item *item)
{
bool error;
- THD *thd=current_thd;
+ THD *thd= field->table->in_use;
ha_rows cuted_fields=thd->cuted_fields;
/*
we should restore old value of count_cuted_fields because
@@ -3426,10 +5015,11 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
{
TABLE **tableptr;
JOIN_TAB *join_tab;
+ DBUG_ENTER("make_simple_join");
if (!(tableptr=(TABLE**) join->thd->alloc(sizeof(TABLE*))) ||
!(join_tab=(JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB))))
- return TRUE;
+ DBUG_RETURN(TRUE);
join->join_tab=join_tab;
join->table=tableptr; tableptr[0]=tmp_table;
join->tables=1;
@@ -3452,15 +5042,18 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join_tab->type= JT_ALL; /* Map through all records */
join_tab->keys.init(~0); /* test everything in quick */
join_tab->info=0;
- join_tab->on_expr=0;
+ join_tab->on_expr_ref=0;
+ join_tab->last_inner= 0;
+ join_tab->first_unmatched= 0;
join_tab->ref.key = -1;
join_tab->not_used_in_distinct=0;
join_tab->read_first_record= join_init_read_record;
join_tab->join=join;
+ join_tab->ref.key_parts= 0;
bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
tmp_table->status=0;
tmp_table->null_row=0;
- return FALSE;
+ DBUG_RETURN(FALSE);
}
@@ -3540,7 +5133,7 @@ static void add_not_null_conds(JOIN *join)
notnull->quick_fix_field();
DBUG_EXECUTE("where",print_where(notnull,
- referred_tab->table->table_name););
+ referred_tab->table->alias););
add_cond_and_fix(&referred_tab->select_cond, notnull);
}
}
@@ -3549,28 +5142,184 @@ static void add_not_null_conds(JOIN *join)
DBUG_VOID_RETURN;
}
+/*
+ Build a predicate guarded by match variables for embedding outer joins
+
+ SYNOPSIS
+ add_found_match_trig_cond()
+ tab the first inner table for most nested outer join
+ cond the predicate to be guarded
+ root_tab the first inner table to stop
+
+ DESCRIPTION
+ The function recursively adds guards for predicate cond
+ assending from tab to the first inner table next embedding
+ nested outer join and so on until it reaches root_tab
+ (root_tab can be 0).
+
+ RETURN VALUE
+ pointer to the guarded predicate, if success
+ 0, otherwise
+*/
+
+static COND*
+add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
+{
+ COND *tmp;
+ if (tab == root_tab || !cond)
+ return cond;
+ if ((tmp= add_found_match_trig_cond(tab->first_upper, cond, root_tab)))
+ {
+ tmp= new Item_func_trig_cond(tmp, &tab->found);
+ }
+ if (tmp)
+ tmp->quick_fix_field();
+ return tmp;
+}
+
+
+/*
+ Fill in outer join related info for the execution plan structure
+
+ SYNOPSIS
+ make_outerjoin_info()
+ join - reference to the info fully describing the query
+
+ DESCRIPTION
+ For each outer join operation left after simplification of the
+ original query the function set up the following pointers in the linear
+ structure join->join_tab representing the selected execution plan.
+ The first inner table t0 for the operation is set to refer to the last
+ inner table tk through the field t0->last_inner.
+ Any inner table ti for the operation are set to refer to the first
+ inner table ti->first_inner.
+ The first inner table t0 for the operation is set to refer to the
+ first inner table of the embedding outer join operation, if there is any,
+ through the field t0->first_upper.
+ The on expression for the outer join operation is attached to the
+ corresponding first inner table through the field t0->on_expr_ref.
+ Here ti are structures of the JOIN_TAB type.
+
+ EXAMPLE
+ For the query:
+ SELECT * FROM t1
+ LEFT JOIN
+ (t2, t3 LEFT JOIN t4 ON t3.a=t4.a)
+ ON (t1.a=t2.a AND t1.b=t3.b)
+ WHERE t1.c > 5,
+ given the execution plan with the table order t1,t2,t3,t4
+ is selected, the following references will be set;
+ t4->last_inner=[t4], t4->first_inner=[t4], t4->first_upper=[t2]
+ t2->last_inner=[t4], t2->first_inner=t3->first_inner=[t2],
+ on expression (t1.a=t2.a AND t1.b=t3.b) will be attached to
+ *t2->on_expr_ref, while t3.a=t4.a will be attached to *t4->on_expr_ref.
+
+ NOTES
+ The function assumes that the simplification procedure has been
+ already applied to the join query (see simplify_joins).
+ This function can be called only after the execution plan
+ has been chosen.
+*/
+
+static void
+make_outerjoin_info(JOIN *join)
+{
+ DBUG_ENTER("make_outerjoin_info");
+ for (uint i=join->const_tables ; i < join->tables ; i++)
+ {
+ JOIN_TAB *tab=join->join_tab+i;
+ TABLE *table=tab->table;
+ TABLE_LIST *tbl= table->pos_in_table_list;
+ TABLE_LIST *embedding= tbl->embedding;
+
+ if (tbl->outer_join)
+ {
+ /*
+ Table tab is the only one inner table for outer join.
+ (Like table t4 for the table reference t3 LEFT JOIN t4 ON t3.a=t4.a
+ is in the query above.)
+ */
+ tab->last_inner= tab->first_inner= tab;
+ tab->on_expr_ref= &tbl->on_expr;
+ tab->cond_equal= tbl->cond_equal;
+ if (embedding)
+ tab->first_upper= embedding->nested_join->first_nested;
+ }
+ for ( ; embedding ; embedding= embedding->embedding)
+ {
+ NESTED_JOIN *nested_join= embedding->nested_join;
+ if (!nested_join->counter)
+ {
+ /*
+ Table tab is the first inner table for nested_join.
+ Save reference to it in the nested join structure.
+ */
+ nested_join->first_nested= tab;
+ tab->on_expr_ref= &embedding->on_expr;
+ tab->cond_equal= tbl->cond_equal;
+ if (embedding->embedding)
+ tab->first_upper= embedding->embedding->nested_join->first_nested;
+ }
+ if (!tab->first_inner)
+ tab->first_inner= nested_join->first_nested;
+ if (++nested_join->counter < nested_join->join_list.elements)
+ break;
+ /* Table tab is the last inner table for nested join. */
+ nested_join->first_nested->last_inner= tab;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
static bool
make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
+ THD *thd= join->thd;
DBUG_ENTER("make_join_select");
if (select)
{
add_not_null_conds(join);
table_map used_tables;
- if (join->tables > 1)
- cond->update_used_tables(); // Tablenr may have changed
- if (join->const_tables == join->tables &&
- join->thd->lex->current_select->master_unit() ==
- &join->thd->lex->unit) // not upper level SELECT
- join->const_table_map|=RAND_TABLE_BIT;
- { // Check const tables
- COND *const_cond=
- make_cond_for_table(cond,join->const_table_map,(table_map) 0);
- DBUG_EXECUTE("where",print_where(const_cond,"constants"););
- if (const_cond && !const_cond->val_int())
- {
- DBUG_PRINT("info",("Found impossible WHERE condition"));
- DBUG_RETURN(1); // Impossible const condition
+ if (cond) /* Because of QUICK_GROUP_MIN_MAX_SELECT */
+ { /* there may be a select without a cond. */
+ if (join->tables > 1)
+ cond->update_used_tables(); // Tablenr may have changed
+ if (join->const_tables == join->tables &&
+ thd->lex->current_select->master_unit() ==
+ &thd->lex->unit) // not upper level SELECT
+ join->const_table_map|=RAND_TABLE_BIT;
+ { // Check const tables
+ COND *const_cond=
+ make_cond_for_table(cond,join->const_table_map,(table_map) 0);
+ DBUG_EXECUTE("where",print_where(const_cond,"constants"););
+ for (JOIN_TAB *tab= join->join_tab+join->const_tables;
+ tab < join->join_tab+join->tables ; tab++)
+ {
+ if (*tab->on_expr_ref)
+ {
+ JOIN_TAB *cond_tab= tab->first_inner;
+ COND *tmp= make_cond_for_table(*tab->on_expr_ref,
+ join->const_table_map,
+ ( table_map) 0);
+ if (!tmp)
+ continue;
+ tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
+ if (!tmp)
+ DBUG_RETURN(1);
+ tmp->quick_fix_field();
+ cond_tab->select_cond= !cond_tab->select_cond ? tmp :
+ new Item_cond_and(cond_tab->select_cond,tmp);
+ if (!cond_tab->select_cond)
+ DBUG_RETURN(1);
+ cond_tab->select_cond->quick_fix_field();
+ }
+ }
+ if (const_cond && !const_cond->val_int())
+ {
+ DBUG_PRINT("info",("Found impossible WHERE condition"));
+ DBUG_RETURN(1); // Impossible const condition
+ }
}
}
used_tables=((select->const_tables=join->const_table_map) |
@@ -3578,14 +5327,15 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
for (uint i=join->const_tables ; i < join->tables ; i++)
{
JOIN_TAB *tab=join->join_tab+i;
+ JOIN_TAB *first_inner_tab= tab->first_inner;
table_map current_map= tab->table->map;
+ bool use_quick_range=0;
/*
Following force including random expression in last table condition.
It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
*/
if (i == join->tables-1)
current_map|= OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
- bool use_quick_range=0;
used_tables|=current_map;
if (tab->type == JT_REF && tab->quick &&
@@ -3601,32 +5351,76 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
join->best_positions[i].records_read= rows2double(tab->quick->records);
}
- COND *tmp=make_cond_for_table(cond,used_tables,current_map);
- if (!tmp && tab->quick)
+ COND *tmp= NULL;
+ if (cond)
+ tmp= make_cond_for_table(cond,used_tables,current_map);
+ if (cond && !tmp && tab->quick)
{ // Outer join
- /*
- Hack to handle the case where we only refer to a table
- in the ON part of an OUTER JOIN.
- */
- tmp=new Item_int((longlong) 1,1); // Always true
+ if (tab->type != JT_ALL)
+ {
+ /*
+ Don't use the quick method
+ We come here in the case where we have 'key=constant' and
+ the test is removed by make_cond_for_table()
+ */
+ delete tab->quick;
+ tab->quick= 0;
+ }
+ else
+ {
+ /*
+ Hack to handle the case where we only refer to a table
+ in the ON part of an OUTER JOIN. In this case we want the code
+ below to check if we should use 'quick' instead.
+ */
+ DBUG_PRINT("info", ("Item_int"));
+ tmp= new Item_int((longlong) 1,1); // Always true
+ DBUG_PRINT("info", ("Item_int 0x%lx", (ulong)tmp));
+ }
+
}
- if (tmp)
+ if (tmp || !cond)
{
+ DBUG_EXECUTE("where",print_where(tmp,tab->table->alias););
SQL_SELECT *sel=tab->select=(SQL_SELECT*)
- join->thd->memdup((gptr) select, sizeof(SQL_SELECT));
+ thd->memdup((gptr) select, sizeof(SQL_SELECT));
if (!sel)
DBUG_RETURN(1); // End of memory
- add_cond_and_fix(&tab->select_cond, tmp);
- sel->cond= tab->select_cond;
+ /*
+ If tab is an inner table of an outer join operation,
+ add a match guard to the pushed down predicate.
+ The guard will turn the predicate on only after
+ the first match for outer tables is encountered.
+ */
+ if (cond)
+ {
+ /*
+ Because of QUICK_GROUP_MIN_MAX_SELECT there may be a select without
+ a cond, so neutralize the hack above.
+ */
+ if (!(tmp= add_found_match_trig_cond(first_inner_tab, tmp, 0)))
+ DBUG_RETURN(1);
+ tab->select_cond=sel->cond=tmp;
+ if (thd->variables.engine_condition_pushdown)
+ {
+ tab->table->file->pushed_cond= NULL;
+ /* Push condition to handler */
+ if (!tab->table->file->cond_push(tmp))
+ tab->table->file->pushed_cond= tmp;
+ }
+ }
+ else
+ tab->select_cond= sel->cond= NULL;
+
sel->head=tab->table;
- DBUG_EXECUTE("where",print_where(tmp,tab->table->table_name););
+ DBUG_EXECUTE("where",print_where(tmp,tab->table->alias););
if (tab->quick)
{
/* Use quick key read if it's a constant and it's not used
with key reading */
if (tab->needed_reg.is_clear_all() && tab->type != JT_EQ_REF
&& tab->type != JT_FT && (tab->type != JT_REF ||
- (uint) tab->ref.key == tab->quick->index))
+ (uint) tab->ref.key == tab->quick->index))
{
sel->quick=tab->quick; // Use value from get_quick_...
sel->quick_keys.clear_all();
@@ -3657,7 +5451,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
the index if we are using limit and this is the first table
*/
- if ((!tab->keys.is_subset(tab->const_keys) && i > 0) ||
+ if (cond &&
+ (!tab->keys.is_subset(tab->const_keys) && i > 0) ||
(!tab->const_keys.is_clear_all() && i == join->const_tables &&
join->unit->select_limit_cnt <
join->best_positions[i].records_read &&
@@ -3665,7 +5460,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
/* Join with outer join condition */
COND *orig_cond=sel->cond;
- sel->cond= and_conds(sel->cond, tab->on_expr);
+ sel->cond= and_conds(sel->cond, *tab->on_expr_ref);
/*
We can't call sel->cond->fix_fields,
@@ -3677,7 +5472,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
if (sel->cond && !sel->cond->fixed)
sel->cond->quick_fix_field();
- if (sel->test_quick_select(join->thd, tab->keys,
+ if (sel->test_quick_select(thd, tab->keys,
used_tables & ~ current_map,
(join->select_options &
OPTION_FOUND_ROWS ?
@@ -3689,8 +5484,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
we have to check isn't it only "impossible ON" instead
*/
sel->cond=orig_cond;
- if (!tab->on_expr ||
- sel->test_quick_select(join->thd, tab->keys,
+ if (!*tab->on_expr_ref ||
+ sel->test_quick_select(thd, tab->keys,
used_tables & ~ current_map,
(join->select_options &
OPTION_FOUND_ROWS ?
@@ -3724,30 +5519,96 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
}
if (i != join->const_tables && tab->use_quick != 2)
{ /* Read with cache */
- if ((tmp=make_cond_for_table(cond,
+ if (cond &&
+ (tmp=make_cond_for_table(cond,
join->const_table_map |
current_map,
current_map)))
{
DBUG_EXECUTE("where",print_where(tmp,"cache"););
tab->cache.select=(SQL_SELECT*)
- join->thd->memdup((gptr) sel, sizeof(SQL_SELECT));
+ thd->memdup((gptr) sel, sizeof(SQL_SELECT));
tab->cache.select->cond=tmp;
tab->cache.select->read_tables=join->const_table_map;
+ if (thd->variables.engine_condition_pushdown &&
+ (!tab->table->file->pushed_cond))
+ {
+ /* Push condition to handler */
+ if (!tab->table->file->cond_push(tmp))
+ tab->table->file->pushed_cond= tmp;
+ }
}
}
}
}
+
+ /*
+ Push down all predicates from on expressions.
+ Each of these predicated are guarded by a variable
+ that turns if off just before null complemented row for
+ outer joins is formed. Thus, the predicates from an
+ 'on expression' are guaranteed not to be checked for
+ the null complemented row.
+ */
+ JOIN_TAB *last_tab= tab;
+ while (first_inner_tab && first_inner_tab->last_inner == last_tab)
+ {
+ /*
+ Table tab is the last inner table of an outer join.
+ An on expression is always attached to it.
+ */
+ COND *on_expr= *first_inner_tab->on_expr_ref;
+
+ table_map used_tables= join->const_table_map |
+ OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
+ for (tab= join->join_tab+join->const_tables; tab <= last_tab ; tab++)
+ {
+ current_map= tab->table->map;
+ used_tables|= current_map;
+ COND *tmp= make_cond_for_table(on_expr, used_tables, current_map);
+ if (tmp)
+ {
+ JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab;
+ /*
+ First add the guards for match variables of
+ all embedding outer join operations.
+ */
+ if (!(tmp= add_found_match_trig_cond(cond_tab->first_inner,
+ tmp, first_inner_tab)))
+ DBUG_RETURN(1);
+ /*
+ Now add the guard turning the predicate off for
+ the null complemented row.
+ */
+ DBUG_PRINT("info", ("Item_func_trig_cond"));
+ tmp= new Item_func_trig_cond(tmp,
+ &first_inner_tab->not_null_compl);
+ DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx", (ulong) tmp));
+ if (tmp)
+ tmp->quick_fix_field();
+ /* Add the predicate to other pushed down predicates */
+ DBUG_PRINT("info", ("Item_cond_and"));
+ cond_tab->select_cond= !cond_tab->select_cond ? tmp :
+ new Item_cond_and(cond_tab->select_cond,tmp);
+ DBUG_PRINT("info", ("Item_cond_and 0x%lx",
+ (ulong)cond_tab->select_cond));
+ if (!cond_tab->select_cond)
+ DBUG_RETURN(1);
+ cond_tab->select_cond->quick_fix_field();
+ }
+ }
+ first_inner_tab= first_inner_tab->first_upper;
+ }
}
}
DBUG_RETURN(0);
}
-
static void
make_join_readinfo(JOIN *join, uint options)
{
uint i;
+
bool statistics= test(!(join->select_options & SELECT_DESCRIBE));
DBUG_ENTER("make_join_readinfo");
@@ -3831,7 +5692,7 @@ make_join_readinfo(JOIN *join, uint options)
*/
table->status=STATUS_NO_RECORD;
if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
- tab->use_quick != 2 && !tab->on_expr)
+ tab->use_quick != 2 && !tab->first_inner)
{
if ((options & SELECT_DESCRIBE) ||
!join_init_cache(join->thd,join->join_tab+join->const_tables,
@@ -3846,7 +5707,8 @@ make_join_readinfo(JOIN *join, uint options)
join->thd->server_status|=SERVER_QUERY_NO_GOOD_INDEX_USED;
tab->read_first_record= join_init_quick_read_record;
if (statistics)
- statistic_increment(select_range_check_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_range_check_count,
+ &LOCK_status);
}
else
{
@@ -3856,13 +5718,15 @@ make_join_readinfo(JOIN *join, uint options)
if (tab->select && tab->select->quick)
{
if (statistics)
- statistic_increment(select_range_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_range_count,
+ &LOCK_status);
}
else
{
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
if (statistics)
- statistic_increment(select_scan_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_scan_count,
+ &LOCK_status);
}
}
else
@@ -3870,13 +5734,15 @@ make_join_readinfo(JOIN *join, uint options)
if (tab->select && tab->select->quick)
{
if (statistics)
- statistic_increment(select_full_range_join_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_full_range_join_count,
+ &LOCK_status);
}
else
{
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
if (statistics)
- statistic_increment(select_full_join_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_full_join_count,
+ &LOCK_status);
}
}
if (!table->no_keyread)
@@ -3934,7 +5800,8 @@ bool error_if_full_join(JOIN *join)
{
if (tab->type == JT_ALL && (!tab->select || !tab->select->quick))
{
- my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
+ my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
+ ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
return(1);
}
}
@@ -4213,7 +6080,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
table_map not_const_tables= ~join->const_table_map;
table_map ref;
prev_ptr= &first_order;
- *simple_order= join->join_tab[join->const_tables].on_expr ? 0 : 1;
+ *simple_order= *join->join_tab[join->const_tables].on_expr_ref ? 0 : 1;
/* NOTE: A variable of not_const_tables ^ first_table; breaks gcc 2.7 */
@@ -4280,12 +6147,13 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
if (send_row)
{
- for (TABLE_LIST *table=tables; table ; table=table->next)
+ for (TABLE_LIST *table= tables; table; table= table->next_leaf)
mark_as_null_row(table->table); // All fields are NULL
if (having && having->val_int() == 0)
send_row=0;
}
- if (!(result->send_fields(fields,1)))
+ if (!(result->send_fields(fields,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
{
if (send_row)
{
@@ -4320,9 +6188,13 @@ static void clear_tables(JOIN *join)
class COND_CMP :public ilink {
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 delete(void *ptr __attribute__((unused)),
- size_t size __attribute__((unused))) {} /*lint -e715 */
+ size_t size __attribute__((unused)))
+ { TRASH(ptr, size); }
Item *and_level;
Item_func *cmp_func;
@@ -4336,6 +6208,805 @@ template class List<Item_func_match>;
template class List_iterator<Item_func_match>;
#endif
+
+/*
+ Find the multiple equality predicate containing a field
+
+ SYNOPSIS
+ find_item_equal()
+ cond_equal multiple equalities to search in
+ field field to look for
+ inherited_fl :out set up to TRUE if multiple equality is found
+ on upper levels (not on current level of cond_equal)
+
+ DESCRIPTION
+ The function retrieves the multiple equalities accessed through
+ the con_equal structure from current level and up looking for
+ an equality containing field. It stops retrieval as soon as the equality
+ is found and set up inherited_fl to TRUE if it's found on upper levels.
+
+ RETURN
+ Item_equal for the found multiple equality predicate if a success;
+ NULL - otherwise.
+*/
+
+Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
+ bool *inherited_fl)
+{
+ Item_equal *item= 0;
+ bool in_upper_level= FALSE;
+ while (cond_equal)
+ {
+ List_iterator_fast<Item_equal> li(cond_equal->current_level);
+ while ((item= li++))
+ {
+ if (item->contains(field))
+ goto finish;
+ }
+ in_upper_level= TRUE;
+ cond_equal= cond_equal->upper_levels;
+ }
+ in_upper_level= FALSE;
+finish:
+ *inherited_fl= in_upper_level;
+ return item;
+}
+
+
+/*
+ Check whether an item is a simple equality predicate and if so
+ create/find a multiple equality for this predicate
+
+ SYNOPSIS
+ check_equality()
+ item item to check
+ cond_equal multiple equalities that must hold together with the predicate
+
+ DESCRIPTION
+ This function first checks whether an item is a simple equality i.e.
+ the one that equates a field with another field or a constant
+ (item=constant_item or item=field_item).
+ If this is the case the function looks a for a multiple equality
+ in the lists referenced directly or indirectly by cond_equal inferring
+ the given simple equality. If it doesn't find any, it builds a multiple
+ equality that covers the predicate, i.e. the predicate can be inferred
+ from it.
+ The built multiple equality could be obtained in such a way:
+ create a binary multiple equality equivalent to the predicate, then
+ merge it, if possible, with one of old multiple equalities.
+ This guarantees that the set of multiple equalities covering equality
+ predicates will
+ be minimal.
+
+ EXAMPLE
+ For the where condition
+ WHERE a=b AND b=c AND
+ (b=2 OR f=e)
+ the check_equality will be called for the following equality
+ predicates a=b, b=c, b=2 and f=e.
+ For a=b it will be called with *cond_equal=(0,[]) and will transform
+ *cond_equal into (0,[Item_equal(a,b)]).
+ For b=c it will be called with *cond_equal=(0,[Item_equal(a,b)])
+ and will transform *cond_equal into CE=(0,[Item_equal(a,b,c)]).
+ For b=2 it will be called with *cond_equal=(ptr(CE),[])
+ and will transform *cond_equal into (ptr(CE),[Item_equal(2,a,b,c)]).
+ For f=e it will be called with *cond_equal=(ptr(CE), [])
+ and will transform *cond_equal into (ptr(CE),[Item_equal(f,e)]).
+
+ NOTES
+ Now only fields that have the same type defintions (verified by
+ the Field::eq_def method) are placed to the same multiple equalities.
+ Because of this some equality predicates are not eliminated and
+ can be used in the constant propagation procedure.
+ We could weeken the equlity test as soon as at least one of the
+ equal fields is to be equal to a constant. It would require a
+ more complicated implementation: we would have to store, in
+ general case, its own constant for each fields from the multiple
+ equality. But at the same time it would allow us to get rid
+ of constant propagation completely: it would be done by the call
+ to build_equal_items_for_cond.
+
+ IMPLEMENTATION
+ The implementation does not follow exactly the above rules to
+ build a new multiple equality for the equality predicate.
+ If it processes the equality of the form field1=field2, it
+ looks for multiple equalities me1 containig field1 and me2 containing
+ field2. If only one of them is found the fuction expands it with
+ the lacking field. If multiple equalities for both fields are
+ found they are merged. If both searches fail a new multiple equality
+ containing just field1 and field2 is added to the existing
+ multiple equalities.
+ If the function processes the predicate of the form field1=const,
+ it looks for a multiple equality containing field1. If found, the
+ function checks the constant of the multiple equality. If the value
+ is unknown, it is setup to const. Otherwise the value is compared with
+ const and the evaluation of the equality predicate is performed.
+ When expanding/merging equality predicates from the upper levels
+ the function first copies them for the current level. It looks
+ acceptable, as this happens rarely. The implementation without
+ copying would be much more complicated.
+
+ RETURN
+ TRUE - if the predicate is a simple equality predicate
+ FALSE - otherwise
+*/
+
+static bool check_equality(Item *item, COND_EQUAL *cond_equal)
+{
+ if (item->type() == Item::FUNC_ITEM &&
+ ((Item_func*) item)->functype() == Item_func::EQ_FUNC)
+ {
+ Item *left_item= ((Item_func*) item)->arguments()[0];
+ Item *right_item= ((Item_func*) item)->arguments()[1];
+ if (left_item->type() == Item::FIELD_ITEM &&
+ right_item->type() == Item::FIELD_ITEM)
+ {
+ /* The predicate the form field1=field2 is processed */
+
+ Field *left_field= ((Item_field*) left_item)->field;
+ Field *right_field= ((Item_field*) right_item)->field;
+
+ if (!left_field->eq_def(right_field))
+ return FALSE;
+
+ if (left_field->eq(right_field)) /* f = f */
+ return TRUE;
+
+ /* Search for multiple equalities containing field1 and/or field2 */
+ bool left_copyfl, right_copyfl;
+ Item_equal *left_item_equal=
+ find_item_equal(cond_equal, left_field, &left_copyfl);
+ Item_equal *right_item_equal=
+ find_item_equal(cond_equal, right_field, &right_copyfl);
+
+ if (left_item_equal && left_item_equal == right_item_equal)
+ {
+ /*
+ The equality predicate is inference of one of the existing
+ multiple equalities, i.e the condition is already covered
+ by upper level equalities
+ */
+ return TRUE;
+ }
+
+ /* Copy the found multiple equalities at the current level if needed */
+ if (left_copyfl)
+ {
+ /* left_item_equal of an upper level contains left_item */
+ left_item_equal= new Item_equal(left_item_equal);
+ cond_equal->current_level.push_back(left_item_equal);
+ }
+ if (right_copyfl)
+ {
+ /* right_item_equal of an upper level contains right_item */
+ right_item_equal= new Item_equal(right_item_equal);
+ cond_equal->current_level.push_back(right_item_equal);
+ }
+
+ if (left_item_equal)
+ {
+ /* left item was found in the current or one of the upper levels */
+ if (! right_item_equal)
+ left_item_equal->add((Item_field *) right_item);
+ else
+ {
+ /* Merge two multiple equalities forming a new one */
+ left_item_equal->merge(right_item_equal);
+ /* Remove the merged multiple equality from the list */
+ List_iterator<Item_equal> li(cond_equal->current_level);
+ while ((li++) != right_item_equal);
+ li.remove();
+ }
+ }
+ else
+ {
+ /* left item was not found neither the current nor in upper levels */
+ if (right_item_equal)
+ right_item_equal->add((Item_field *) left_item);
+ else
+ {
+ /* None of the fields was found in multiple equalities */
+ Item_equal *item= new Item_equal((Item_field *) left_item,
+ (Item_field *) right_item);
+ cond_equal->current_level.push_back(item);
+ }
+ }
+ return TRUE;
+ }
+
+ {
+ /* The predicate of the form field=const/const=field is processed */
+ Item *const_item= 0;
+ Item_field *field_item= 0;
+ if (left_item->type() == Item::FIELD_ITEM &&
+ right_item->const_item())
+ {
+ field_item= (Item_field*) left_item;
+ const_item= right_item;
+ }
+ else if (right_item->type() == Item::FIELD_ITEM &&
+ left_item->const_item())
+ {
+ field_item= (Item_field*) right_item;
+ const_item= left_item;
+ }
+ if (const_item &&
+ field_item->result_type() == const_item->result_type())
+ {
+ bool copyfl;
+
+ if (field_item->result_type() == STRING_RESULT &&
+ ((Field_str *) field_item->field)->charset() !=
+ ((Item_cond *) item)->compare_collation())
+ return FALSE;
+
+ Item_equal *item_equal = find_item_equal(cond_equal,
+ field_item->field, &copyfl);
+ if (copyfl)
+ {
+ item_equal= new Item_equal(item_equal);
+ cond_equal->current_level.push_back(item_equal);
+ }
+ if (item_equal)
+ {
+ /*
+ The flag cond_false will be set to 1 after this, if item_equal
+ already contains a constant and its value is not equal to
+ the value of const_item.
+ */
+ item_equal->add(const_item);
+ }
+ else
+ {
+ item_equal= new Item_equal(const_item, field_item);
+ cond_equal->current_level.push_back(item_equal);
+ }
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*
+ Replace all equality predicates in a condition by multiple equality items
+
+ SYNOPSIS
+ build_equal_items_for_cond()
+ cond condition(expression) where to make replacement
+ inherited path to all inherited multiple equality items
+
+ DESCRIPTION
+ At each 'and' level the function detects items for equality predicates
+ and replaced them by a set of multiple equality items of class Item_equal,
+ taking into account inherited equalities from upper levels.
+ If an equality predicate is used not in a conjunction it's just
+ replaced by a multiple equality predicate.
+ For each 'and' level the function set a pointer to the inherited
+ multiple equalities in the cond_equal field of the associated
+ object of the type Item_cond_and.
+ The function also traverses the cond tree and and for each field reference
+ sets a pointer to the multiple equality item containing the field, if there
+ is any. If this multiple equality equates fields to a constant the
+ function replace the field reference by the constant.
+ The function also determines the maximum number of members in
+ equality lists of each Item_cond_and object assigning it to
+ cond_equal->max_members of this object and updating accordingly
+ the upper levels COND_EQUAL structures.
+
+ NOTES
+ Multiple equality predicate =(f1,..fn) is equivalent to the conjuction of
+ f1=f2, .., fn-1=fn. It substitutes any inference from these
+ equality predicates that is equivalent to the conjunction.
+ Thus, =(a1,a2,a3) can substitute for ((a1=a3) AND (a2=a3) AND (a2=a1)) as
+ it is equivalent to ((a1=a2) AND (a2=a3)).
+ The function always makes a substitution of all equality predicates occured
+ in a conjuction for a minimal set of multiple equality predicates.
+ This set can be considered as a canonical representation of the
+ sub-conjunction of the equality predicates.
+ E.g. (t1.a=t2.b AND t2.b>5 AND t1.a=t3.c) is replaced by
+ (=(t1.a,t2.b,t3.c) AND t2.b>5), not by
+ (=(t1.a,t2.b) AND =(t1.a,t3.c) AND t2.b>5);
+ while (t1.a=t2.b AND t2.b>5 AND t3.c=t4.d) is replaced by
+ (=(t1.a,t2.b) AND =(t3.c=t4.d) AND t2.b>5),
+ but if additionally =(t4.d,t2.b) is inherited, it
+ will be replaced by (=(t1.a,t2.b,t3.c,t4.d) AND t2.b>5)
+
+ IMPLEMENTATION
+ The function performs the substitution in a recursive descent by
+ the condtion tree, passing to the next AND level a chain of multiple
+ equality predicates which have been built at the upper levels.
+ The Item_equal items built at the level are attached to other
+ non-equality conjucts as a sublist. The pointer to the inherited
+ multiple equalities is saved in the and condition object (Item_cond_and).
+ This chain allows us for any field reference occurence easyly to find a
+ multiple equality that must be held for this occurence.
+ For each AND level we do the following:
+ - scan it for all equality predicate (=) items
+ - join them into disjoint Item_equal() groups
+ - process the included OR conditions recursively to do the same for
+ lower AND levels.
+ We need to do things in this order as lower AND levels need to know about
+ all possible Item_equal objects in upper levels.
+
+ RETURN
+ pointer to the transformed condition
+*/
+
+static COND *build_equal_items_for_cond(COND *cond,
+ COND_EQUAL *inherited)
+{
+ Item_equal *item_equal;
+ uint members;
+ COND_EQUAL cond_equal;
+ cond_equal.upper_levels= inherited;
+
+ if (cond->type() == Item::COND_ITEM)
+ {
+ bool and_level= ((Item_cond*) cond)->functype() ==
+ Item_func::COND_AND_FUNC;
+ List<Item> *args= ((Item_cond*) cond)->argument_list();
+
+ List_iterator<Item> li(*args);
+ Item *item;
+
+ if (and_level)
+ {
+ /*
+ Retrieve all conjucts of this level detecting the equality
+ that are subject to substitution by multiple equality items and
+ removing each such predicate from the conjunction after having
+ found/created a multiple equality whose inference the predicate is.
+ */
+ while ((item= li++))
+ {
+ /*
+ PS/SP note: we can safely remove a node from AND-OR
+ structure here because it's restored before each
+ re-execution of any prepared statement/stored procedure.
+ */
+ if (check_equality(item, &cond_equal))
+ li.remove();
+ }
+
+ List_iterator_fast<Item_equal> it(cond_equal.current_level);
+ while ((item_equal= it++))
+ {
+ item_equal->fix_length_and_dec();
+ item_equal->update_used_tables();
+ members= item_equal->members();
+ if (cond_equal.max_members < members)
+ cond_equal.max_members= members;
+ }
+ members= cond_equal.max_members;
+ if (inherited && inherited->max_members < members)
+ {
+ do
+ {
+ inherited->max_members= members;
+ inherited= inherited->upper_levels;
+ }
+ while (inherited);
+ }
+
+ ((Item_cond_and*)cond)->cond_equal= cond_equal;
+ inherited= &(((Item_cond_and*)cond)->cond_equal);
+ }
+ /*
+ Make replacement of equality predicates for lower levels
+ of the condition expression.
+ */
+ li.rewind();
+ while((item= li++))
+ {
+ Item *new_item;
+ if ((new_item = build_equal_items_for_cond(item, inherited))!= item)
+ {
+ /* This replacement happens only for standalone equalities */
+ /*
+ This is ok with PS/SP as the replacement is done for
+ arguments of an AND/OR item, which are restored for each
+ execution of PS/SP.
+ */
+ li.replace(new_item);
+ }
+ }
+ if (and_level)
+ args->concat((List<Item> *)&cond_equal.current_level);
+ }
+ else if (cond->type() == Item::FUNC_ITEM)
+ {
+ /*
+ If an equality predicate forms the whole and level,
+ we call it standalone equality and it's processed here.
+ E.g. in the following where condition
+ WHERE a=5 AND (b=5 or a=c)
+ (b=5) and (a=c) are standalone equalities.
+ In general we can't leave alone standalone eqalities:
+ for WHERE a=b AND c=d AND (b=c OR d=5)
+ b=c is replaced by =(a,b,c,d).
+ */
+ if (check_equality(cond, &cond_equal) &&
+ (item_equal= cond_equal.current_level.pop()))
+ {
+ item_equal->fix_length_and_dec();
+ item_equal->update_used_tables();
+ return item_equal;
+ }
+ /*
+ For each field reference in cond, not from equalitym predicates,
+ set a pointer to the multiple equality if belongs to (if there is any)
+ */
+ cond= cond->transform(&Item::equal_fields_propagator,
+ (byte *) inherited);
+ cond->update_used_tables();
+ }
+ return cond;
+}
+
+
+/*
+ Build multiple equalities for a condition and all on expressions that
+ inherit these multiple equalities
+
+ SYNOPSIS
+ build_equal_items()
+ thd Thread handler
+ cond condition to build the multiple equalities for
+ inherited path to all inherited multiple equality items
+ join_list list of join tables to which the condition refers to
+ cond_equal_ref :out pointer to the structure to place built equalities in
+
+ DESCRIPTION
+ The function first applies the build_equal_items_for_cond function
+ to build all multiple equalities for condition cond utilizing equalities
+ referred through the parameter inherited. The extended set of
+ equalities is returned in the structure referred by the cond_equal_ref
+ parameter. After this the function calls itself recursively for
+ all on expressions whose direct references can be found in join_list
+ and who inherit directly the multiple equalities just having built.
+
+ NOTES
+ The on expression used in an outer join operation inherits all equalities
+ from the on expression of the embedding join, if there is any, or
+ otherwise - from the where condition.
+ This fact is not obvious, but presumably can be proved.
+ Consider the following query:
+ SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t2.a=t4.a
+ WHERE t1.a=t2.a;
+ If the on expression in the query inherits =(t1.a,t2.a), then we
+ can build the multiple equality =(t1.a,t2.a,t3.a,t4.a) that infers
+ the equality t3.a=t4.a. Although the on expression
+ t1.a=t3.a AND t2.a=t4.a AND t3.a=t4.a is not equivalent to the one
+ in the query the latter can be replaced by the former: the new query
+ will return the same result set as the original one.
+
+ Interesting that multiple equality =(t1.a,t2.a,t3.a,t4.a) allows us
+ to use t1.a=t3.a AND t3.a=t4.a under the on condition:
+ SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a
+ WHERE t1.a=t2.a
+ This query equivalent to:
+ SELECT * FROM (t1 LEFT JOIN (t3,t4) ON t1.a=t3.a AND t3.a=t4.a),t2
+ WHERE t1.a=t2.a
+ Similarly the original query can be rewritten to the query:
+ SELECT * FROM (t1,t2) LEFT JOIN (t3,t4) ON t2.a=t4.a AND t3.a=t4.a
+ WHERE t1.a=t2.a
+ that is equivalent to:
+ SELECT * FROM (t2 LEFT JOIN (t3,t4)ON t2.a=t4.a AND t3.a=t4.a), t1
+ WHERE t1.a=t2.a
+ Thus, applying equalities from the where condition we basically
+ can get more freedom in performing join operations.
+ Althogh we don't use this property now, it probably makes sense to use
+ it in the future.
+
+ RETURN
+ pointer to the transformed condition containing multiple equalities
+*/
+
+static COND *build_equal_items(THD *thd, COND *cond,
+ COND_EQUAL *inherited,
+ List<TABLE_LIST> *join_list,
+ COND_EQUAL **cond_equal_ref)
+{
+ COND_EQUAL *cond_equal= 0;
+
+ if (cond)
+ {
+ cond= build_equal_items_for_cond(cond, inherited);
+ cond->update_used_tables();
+ if (cond->type() == Item::COND_ITEM &&
+ ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ cond_equal= &((Item_cond_and*) cond)->cond_equal;
+ else if (cond->type() == Item::FUNC_ITEM &&
+ ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
+ {
+ cond_equal= new COND_EQUAL;
+ cond_equal->current_level.push_back((Item_equal *) cond);
+ }
+ }
+ if (cond_equal)
+ {
+ cond_equal->upper_levels= inherited;
+ inherited= cond_equal;
+ }
+ *cond_equal_ref= cond_equal;
+
+ if (join_list)
+ {
+ TABLE_LIST *table;
+ List_iterator<TABLE_LIST> li(*join_list);
+
+ while ((table= li++))
+ {
+ if (table->on_expr)
+ {
+ List<TABLE_LIST> *join_list= table->nested_join ?
+ &table->nested_join->join_list : NULL;
+ /*
+ We can modify table->on_expr because its old value will
+ be restored before re-execution of PS/SP.
+ */
+ table->on_expr= build_equal_items(thd, table->on_expr, inherited,
+ join_list, &table->cond_equal);
+ }
+ }
+ }
+
+ return cond;
+}
+
+
+/*
+ Compare field items by table order in the execution plan
+
+ SYNOPSIS
+ compare_fields_by_table_order()
+ field1 first field item to compare
+ field2 second field item to compare
+ table_join_idx index to tables determining table order
+
+ DESCRIPTION
+ field1 considered as better than field2 if the table containing
+ field1 is accessed earlier than the table containing field2.
+ The function finds out what of two fields is better according
+ this criteria.
+
+ RETURN
+ 1, if field1 is better than field2
+ -1, if field2 is better than field1
+ 0, otherwise
+*/
+
+static int compare_fields_by_table_order(Item_field *field1,
+ Item_field *field2,
+ void *table_join_idx)
+{
+ int cmp= 0;
+ bool outer_ref= 0;
+ if (field2->used_tables() & OUTER_REF_TABLE_BIT)
+ {
+ outer_ref= 1;
+ cmp= -1;
+ }
+ if (field2->used_tables() & OUTER_REF_TABLE_BIT)
+ {
+ outer_ref= 1;
+ cmp++;
+ }
+ if (outer_ref)
+ return cmp;
+ JOIN_TAB **idx= (JOIN_TAB **) table_join_idx;
+ cmp= idx[field2->field->table->tablenr]-idx[field1->field->table->tablenr];
+ return cmp < 0 ? -1 : (cmp ? 1 : 0);
+}
+
+
+/*
+ Generate minimal set of simple equalities equivalent to a multiple equality
+
+ SYNOPSIS
+ eliminate_item_equal()
+ cond condition to add the generated equality to
+ upper_levels structure to access multiple equality of upper levels
+ item_equal multiple equality to generate simple equality from
+
+ DESCRIPTION
+ The function retrieves the fields of the multiple equality item
+ item_equal and for each field f:
+ - if item_equal contains const it generates the equality f=const_item;
+ - otherwise, if f is not the first field, generates the equality
+ f=item_equal->get_first().
+ All generated equality are added to the cond conjunction.
+
+ NOTES
+ Before generating an equality function checks that it has not
+ been generated for multiple equalies of the upper levels.
+ E.g. for the following where condition
+ WHERE a=5 AND ((a=b AND b=c) OR c>4)
+ the upper level AND condition will contain =(5,a),
+ while the lower level AND condition will contain =(5,a,b,c).
+ When splitting =(5,a,b,c) into a separate equality predicates
+ we should omit 5=a, as we have it already in the upper level.
+ The following where condition gives us a more complicated case:
+ WHERE t1.a=t2.b AND t3.c=t4.d AND (t2.b=t3.c OR t4.e>5 ...) AND ...
+ Given the tables are accessed in the order t1->t2->t3->t4 for
+ the selected query execution plan the lower level multiple
+ equality =(t1.a,t2.b,t3.c,t4.d) formally should be converted to
+ t1.a=t2.b AND t1.a=t3.c AND t1.a=t4.d. But t1.a=t2.a will be
+ generated for the upper level. Also t3.c=t4.d will be generated there.
+ So only t1.a=t3.c should be left in the lower level.
+ If cond is equal to 0, then not more then one equality is generated
+ and a pointer to it is returned as the result of the function.
+
+ RETURN
+ The condition with generated simple equalities or
+ a pointer to the simple generated equality, if success.
+ 0, otherwise.
+*/
+
+static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
+ Item_equal *item_equal)
+{
+ List<Item> eq_list;
+ Item_func_eq *eq_item= 0;
+ if (((Item *) item_equal)->const_item() && !item_equal->val_int())
+ return new Item_int((longlong) 0,1);
+ Item *item_const= item_equal->get_const();
+ Item_equal_iterator it(*item_equal);
+ Item *head;
+ if (item_const)
+ head= item_const;
+ else
+ {
+ head= item_equal->get_first();
+ it++;
+ }
+ Item_field *item_field;
+ while ((item_field= it++))
+ {
+ Item_equal *upper= item_field->find_item_equal(upper_levels);
+ Item_field *item= item_field;
+ if (upper)
+ {
+ if (item_const && upper->get_const())
+ item= 0;
+ else
+ {
+ Item_equal_iterator li(*item_equal);
+ while ((item= li++) != item_field)
+ {
+ if (item->find_item_equal(upper_levels) == upper)
+ break;
+ }
+ }
+ }
+ if (item == item_field)
+ {
+ if (eq_item)
+ eq_list.push_back(eq_item);
+ eq_item= new Item_func_eq(item_field, head);
+ if (!eq_item)
+ return 0;
+ eq_item->set_cmp_func();
+ eq_item->quick_fix_field();
+ }
+ }
+
+ if (!cond && !eq_list.head())
+ {
+ if (!eq_item)
+ return new Item_int((longlong) 1,1);
+ return eq_item;
+ }
+
+ if (eq_item)
+ eq_list.push_back(eq_item);
+ if (!cond)
+ cond= new Item_cond_and(eq_list);
+ else
+ ((Item_cond *) cond)->add_at_head(&eq_list);
+
+ cond->quick_fix_field();
+ cond->update_used_tables();
+
+ return cond;
+}
+
+
+/*
+ Substitute every field reference in a condition by the best equal field
+ and eliminate all multiplle equality predicates
+
+ SYNOPSIS
+ substitute_for_best_equal_field()
+ cond condition to process
+ cond_equal multiple equalities to take into consideration
+ table_join_idx index to tables determining field preference
+
+ DESCRIPTION
+ The function retrieves the cond condition and for each encountered
+ multiple equality predicate it sorts the field references in it
+ according to the order of tables specified by the table_join_idx
+ parameter. Then it eliminates the multiple equality predicate it
+ replacing it by the conjunction of simple equality predicates
+ equating every field from the multiple equality to the first
+ field in it, or to the constant, if there is any.
+ After this the function retrieves all other conjuncted
+ predicates substitute every field reference by the field reference
+ to the first equal field or equal constant if there are any.
+
+ NOTES
+ At the first glance full sort of fields in multiple equality
+ seems to be an overkill. Yet it's not the case due to possible
+ new fields in multiple equality item of lower levels. We want
+ the order in them to comply with the order of upper levels.
+
+ RETURN
+ The transformed condition
+*/
+
+static COND* substitute_for_best_equal_field(COND *cond,
+ COND_EQUAL *cond_equal,
+ void *table_join_idx)
+{
+ Item_equal *item_equal;
+
+ if (cond->type() == Item::COND_ITEM)
+ {
+ List<Item> *cond_list= ((Item_cond*) cond)->argument_list();
+
+ bool and_level= ((Item_cond*) cond)->functype() ==
+ Item_func::COND_AND_FUNC;
+ if (and_level)
+ {
+ cond_equal= &((Item_cond_and *) cond)->cond_equal;
+ cond_list->disjoin((List<Item> *) &cond_equal->current_level);
+
+ List_iterator_fast<Item_equal> it(cond_equal->current_level);
+ while ((item_equal= it++))
+ {
+ item_equal->sort(&compare_fields_by_table_order, table_join_idx);
+ }
+ }
+
+ List_iterator<Item> li(*cond_list);
+ Item *item;
+ while ((item= li++))
+ {
+ Item *new_item =substitute_for_best_equal_field(item, cond_equal,
+ table_join_idx);
+ /*
+ This works OK with PS/SP re-execution as changes are made to
+ the arguments of AND/OR items only
+ */
+ if (new_item != item)
+ li.replace(new_item);
+ }
+
+ if (and_level)
+ {
+ List_iterator_fast<Item_equal> it(cond_equal->current_level);
+ while ((item_equal= it++))
+ {
+ eliminate_item_equal(cond, cond_equal->upper_levels, item_equal);
+ }
+ }
+ }
+ else if (cond->type() == Item::FUNC_ITEM &&
+ ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
+ {
+ item_equal= (Item_equal *) cond;
+ item_equal->sort(&compare_fields_by_table_order, table_join_idx);
+ if (cond_equal && cond_equal->current_level.head() == item_equal)
+ cond_equal= 0;
+ return eliminate_item_equal(0, cond_equal, item_equal);
+ }
+ else
+ cond->transform(&Item::replace_equal_field, 0);
+ return cond;
+}
+
+
/*
change field = field to field = const for each found field = const in the
and_level
@@ -4508,28 +7179,283 @@ propagate_cond_constants(THD *thd, I_List<COND_CMP> *save_list,
}
+/*
+ Simplify joins replacing outer joins by inner joins whenever it's possible
+
+ SYNOPSIS
+ simplify_joins()
+ join reference to the query info
+ join_list list representation of the join to be converted
+ conds conditions to add on expressions for converted joins
+ top true <=> conds is the where condition
+
+ DESCRIPTION
+ The function, during a retrieval of join_list, eliminates those
+ outer joins that can be converted into inner join, possibly nested.
+ It also moves the on expressions for the converted outer joins
+ and from inner joins to conds.
+ The function also calculates some attributes for nested joins:
+ - used_tables
+ - not_null_tables
+ - dep_tables.
+ - on_expr_dep_tables
+ The first two attributes are used to test whether an outer join can
+ be substituted for an inner join. The third attribute represents the
+ relation 'to be dependent on' for tables. If table t2 is dependent
+ on table t1, then in any evaluated execution plan table access to
+ table t2 must precede access to table t2. This relation is used also
+ to check whether the query contains invalid cross-references.
+ The forth attribute is an auxiliary one and is used to calculate
+ dep_tables.
+ As the attribute dep_tables qualifies possibles orders of tables in the
+ execution plan, the dependencies required by the straight join
+ modifiers are reflected in this attribute as well.
+ The function also removes all braces that can be removed from the join
+ expression without changing its meaning.
+
+ NOTES
+ An outer join can be replaced by an inner join if the where condition
+ or the on expression for an embedding nested join contains a conjunctive
+ predicate rejecting null values for some attribute of the inner tables.
+
+ E.g. in the query:
+ SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t1.a WHERE t2.b < 5
+ the predicate t2.b < 5 rejects nulls.
+ The query is converted first to:
+ SELECT * FROM t1 INNER JOIN t2 ON t2.a=t1.a WHERE t2.b < 5
+ then to the equivalent form:
+ SELECT * FROM t1, t2 ON t2.a=t1.a WHERE t2.b < 5 AND t2.a=t1.a.
+
+ Similarly the following query:
+ SELECT * from t1 LEFT JOIN (t2, t3) ON t2.a=t1.a t3.b=t1.b
+ WHERE t2.c < 5
+ is converted to:
+ SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a t3.b=t1.b
+
+ One conversion might trigger another:
+ SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t1.a
+ LEFT JOIN t3 ON t3.b=t2.b
+ WHERE t3 IS NOT NULL =>
+ SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t1.a, t3
+ WHERE t3 IS NOT NULL AND t3.b=t2.b =>
+ SELECT * FROM t1, t2, t3
+ WHERE t3 IS NOT NULL AND t3.b=t2.b AND t2.a=t1.a
+
+ The function removes all unnecessary braces from the expression
+ produced by the conversions.
+ E.g. SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b
+ finally is converted to:
+ SELECT * FROM t1, t2, t3 WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b
+
+ It also will remove braces from the following queries:
+ SELECT * from (t1 LEFT JOIN t2 ON t2.a=t1.a) LEFT JOIN t3 ON t3.b=t2.b
+ SELECT * from (t1, (t2,t3)) WHERE t1.a=t2.a AND t2.b=t3.b.
+
+ The benefit of this simplification procedure is that it might return
+ a query for which the optimizer can evaluate execution plan with more
+ join orders. With a left join operation the optimizer does not
+ consider any plan where one of the inner tables is before some of outer
+ tables.
+
+ IMPLEMENTATION.
+ The function is implemented by a recursive procedure. On the recursive
+ ascent all attributes are calculated, all outer joins that can be
+ converted are replaced and then all unnecessary braces are removed.
+ As join list contains join tables in the reverse order sequential
+ elimination of outer joins does not requite extra recursive calls.
+
+ EXAMPLES
+ Here is an example of a join query with invalid cross references:
+ SELECT * FROM t1 LEFT JOIN t2 ON t2.a=t3.a LEFT JOIN ON t3.b=t1.b
+
+ RETURN VALUE
+ The new condition, if success
+ 0, otherwise
+*/
+
+static COND *
+simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
+{
+ TABLE_LIST *table;
+ NESTED_JOIN *nested_join;
+ TABLE_LIST *prev_table= 0;
+ List_iterator<TABLE_LIST> li(*join_list);
+ DBUG_ENTER("simplify_joins");
+
+ /*
+ Try to simplify join operations from join_list.
+ The most outer join operation is checked for conversion first.
+ */
+ while ((table= li++))
+ {
+ table_map used_tables;
+ table_map not_null_tables= (table_map) 0;
+
+ if ((nested_join= table->nested_join))
+ {
+ /*
+ If the element of join_list is a nested join apply
+ the procedure to its nested join list first.
+ */
+ if (table->on_expr)
+ {
+ Item *expr;
+ /*
+ If an on expression E is attached to the table,
+ check all null rejected predicates in this expression.
+ If such a predicate over an attribute belonging to
+ an inner table of an embedded outer join is found,
+ the outer join is converted to an inner join and
+ the corresponding on expression is added to E.
+ */
+ expr= simplify_joins(join, &nested_join->join_list,
+ table->on_expr, FALSE);
+ table->prep_on_expr= table->on_expr= expr;
+ }
+ nested_join->used_tables= (table_map) 0;
+ nested_join->not_null_tables=(table_map) 0;
+ conds= simplify_joins(join, &nested_join->join_list, conds, top);
+ used_tables= nested_join->used_tables;
+ not_null_tables= nested_join->not_null_tables;
+ }
+ else
+ {
+ used_tables= table->table->map;
+ if (conds)
+ not_null_tables= conds->not_null_tables();
+ }
+
+ if (table->embedding)
+ {
+ table->embedding->nested_join->used_tables|= used_tables;
+ table->embedding->nested_join->not_null_tables|= not_null_tables;
+ }
+
+ if (!table->outer_join || (used_tables & not_null_tables))
+ {
+ /*
+ For some of the inner tables there are conjunctive predicates
+ that reject nulls => the outer join can be replaced by an inner join.
+ */
+ table->outer_join= 0;
+ if (table->on_expr)
+ {
+ /* Add on expression to the where condition. */
+ if (conds)
+ {
+ conds= and_conds(conds, table->on_expr);
+ /* conds is always a new item as both cond and on_expr existed */
+ DBUG_ASSERT(!conds->fixed);
+ conds->fix_fields(join->thd, 0, &conds);
+ }
+ else
+ conds= table->on_expr;
+ table->prep_on_expr= table->on_expr= 0;
+ }
+ }
+
+ if (!top)
+ continue;
+
+ /*
+ Only inner tables of non-convertible outer joins
+ remain with on_expr.
+ */
+ if (table->on_expr)
+ {
+ table->dep_tables|= table->on_expr->used_tables();
+ if (table->embedding)
+ {
+ table->dep_tables&= ~table->embedding->nested_join->used_tables;
+ /*
+ Embedding table depends on tables used
+ in embedded on expressions.
+ */
+ table->embedding->on_expr_dep_tables|= table->on_expr->used_tables();
+ }
+ else
+ table->dep_tables&= ~table->table->map;
+ }
+
+ if (prev_table)
+ {
+ /* The order of tables is reverse: prev_table follows table */
+ if (prev_table->straight)
+ prev_table->dep_tables|= used_tables;
+ if (prev_table->on_expr)
+ {
+ prev_table->dep_tables|= table->on_expr_dep_tables;
+ table_map prev_used_tables= prev_table->nested_join ?
+ prev_table->nested_join->used_tables :
+ prev_table->table->map;
+ /*
+ If on expression contains only references to inner tables
+ we still make the inner tables dependent on the outer tables.
+ It would be enough to set dependency only on one outer table
+ for them. Yet this is really a rare case.
+ */
+ if (!(prev_table->on_expr->used_tables() & ~prev_used_tables))
+ prev_table->dep_tables|= used_tables;
+ }
+ }
+ prev_table= table;
+ }
+
+ /* Flatten nested joins that can be flattened. */
+ li.rewind();
+ while((table= li++))
+ {
+ nested_join= table->nested_join;
+ if (nested_join && !table->on_expr)
+ {
+ TABLE_LIST *tbl;
+ List_iterator<TABLE_LIST> it(nested_join->join_list);
+ while ((tbl= it++))
+ {
+ tbl->embedding= table->embedding;
+ tbl->join_list= table->join_list;
+ }
+ li.replace(nested_join->join_list);
+ }
+ }
+ DBUG_RETURN(conds);
+}
+
+
static COND *
-optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value)
+optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
+ Item::cond_result *cond_value)
{
- SELECT_LEX *select= thd->lex->current_select;
+ THD *thd= join->thd;
+ SELECT_LEX *select= thd->lex->current_select;
DBUG_ENTER("optimize_cond");
- if (conds)
+
+ if (!conds)
+ *cond_value= Item::COND_TRUE;
+ else
{
+ /*
+ Build all multiple equality predicates and eliminate equality
+ predicates that can be inferred from these multiple equalities.
+ For each reference of a field included into a multiple equality
+ that occurs in a function set a pointer to the multiple equality
+ predicate. Substitute a constant instead of this field if the
+ multiple equality contains a constant.
+ */
DBUG_EXECUTE("where", print_where(conds, "original"););
+ conds= build_equal_items(join->thd, conds, NULL, join_list,
+ &join->cond_equal);
+ DBUG_EXECUTE("where",print_where(conds,"after equal_items"););
+
/* change field = field to field = const for each found field = const */
propagate_cond_constants(thd, (I_List<COND_CMP> *) 0, conds, conds);
/*
Remove all instances of item == item
Remove all and-levels where CONST item != CONST item
*/
- DBUG_EXECUTE("where", print_where(conds, "after const change"););
- conds= remove_eq_conds(thd, conds, cond_value);
- DBUG_EXECUTE("info", print_where(conds, "after remove"););
- }
- else
- {
- *cond_value= Item::COND_TRUE;
- select->prep_where= 0;
+ DBUG_EXECUTE("where",print_where(conds,"after const change"););
+ conds= remove_eq_conds(thd, conds, cond_value) ;
+ DBUG_EXECUTE("info",print_where(conds,"after remove"););
}
DBUG_RETURN(conds);
}
@@ -4636,6 +7562,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
21))))
{
cond=new_cond;
+ /*
+ Item_func_eq can't be fixed after creation so we do not check
+ cond->fixed, also it do not need tables so we use 0 as second
+ argument.
+ */
cond->fix_fields(thd, 0, &cond);
}
thd->insert_id(0); // Clear for next request
@@ -4650,10 +7581,20 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2))))
{
cond=new_cond;
+ /*
+ Item_func_eq can't be fixed after creation so we do not check
+ cond->fixed, also it do not need tables so we use 0 as second
+ argument.
+ */
cond->fix_fields(thd, 0, &cond);
}
}
}
+ if (cond->const_item())
+ {
+ *cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
+ return (COND*) 0;
+ }
}
else if (cond->const_item())
{
@@ -4733,7 +7674,6 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
return 0;
}
-
/****************************************************************************
Create internal temporary table
****************************************************************************/
@@ -4746,7 +7686,6 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
thd Thread handler
org_field field from which new field will be created
name New field name
- item Item to create a field for
table Temporary table
item !=NULL if item->result_field should point to new field.
This is relevant for how fill_record() is going to work:
@@ -4762,15 +7701,15 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
new_created field
*/
-static Field* create_tmp_field_from_field(THD *thd, Field* org_field,
- const char *name, TABLE *table,
- Item_field *item,
- uint convert_blob_length)
+Field* create_tmp_field_from_field(THD *thd, Field* org_field,
+ const char *name, TABLE *table,
+ Item_field *item, uint convert_blob_length)
{
Field *new_field;
- if (convert_blob_length && org_field->flags & BLOB_FLAG)
- new_field= new Field_varstring(convert_blob_length, org_field->maybe_null(),
+ if (convert_blob_length && (org_field->flags & BLOB_FLAG))
+ new_field= new Field_varstring(convert_blob_length,
+ org_field->maybe_null(),
org_field->field_name, table,
org_field->charset());
else
@@ -4783,8 +7722,9 @@ static Field* create_tmp_field_from_field(THD *thd, Field* org_field,
new_field->field_name= name;
if (org_field->maybe_null() || (item && item->maybe_null))
new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join
- if (org_field->type() == FIELD_TYPE_VAR_STRING)
- table->db_create_options|= HA_OPTION_PACK_RECORD;
+ if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
+ org_field->type() == MYSQL_TYPE_VARCHAR)
+ table->s->db_create_options|= HA_OPTION_PACK_RECORD;
}
return new_field;
}
@@ -4813,7 +7753,8 @@ static Field* create_tmp_field_from_field(THD *thd, Field* org_field,
0 on error
new_created field
*/
-static Field* create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
+
+static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
Item ***copy_func, bool modify_item,
uint convert_blob_length)
{
@@ -4831,22 +7772,20 @@ static Field* create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
item->name, table, item->unsigned_flag);
break;
case STRING_RESULT:
- if (item->max_length > 255)
- {
- if (convert_blob_length)
- new_field= new Field_varstring(convert_blob_length, maybe_null,
- item->name, table,
- item->collation.collation);
- else
- new_field= new Field_blob(item->max_length, maybe_null, item->name,
- table, item->collation.collation);
- }
+ if (item->max_length > 255 && convert_blob_length)
+ new_field= new Field_varstring(convert_blob_length, maybe_null,
+ item->name, table,
+ item->collation.collation);
else
- new_field= new Field_string(item->max_length, maybe_null, item->name,
- table, item->collation.collation);
+ new_field= item->make_string_field(table);
+ break;
+ case DECIMAL_RESULT:
+ new_field= new Field_new_decimal(item->max_length - (item->decimals?1:0),
+ maybe_null,
+ item->name, table, item->decimals);
break;
- case ROW_RESULT:
- default:
+ case ROW_RESULT:
+ default:
// This case should never be choosen
DBUG_ASSERT(0);
new_field= 0; // to satisfy compiler (uninitialized variable)
@@ -4859,6 +7798,36 @@ static Field* create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
return new_field;
}
+
+/*
+ Create field for information schema table
+
+ SYNOPSIS
+ create_tmp_field_for_schema()
+ thd Thread handler
+ table Temporary table
+ item Item to create a field for
+
+ RETURN
+ 0 on error
+ new_created field
+*/
+
+Field *create_tmp_field_for_schema(THD *thd, Item *item, TABLE *table)
+{
+ if (item->field_type() == MYSQL_TYPE_VARCHAR)
+ {
+ if (item->max_length > MAX_FIELD_VARCHARLENGTH /
+ item->collation.collation->mbmaxlen)
+ return new Field_blob(item->max_length, item->maybe_null,
+ item->name, table, item->collation.collation);
+ return new Field_varstring(item->max_length, item->maybe_null, item->name,
+ table, item->collation.collation);
+ }
+ return item->tmp_table_field_from_field_type(table);
+}
+
+
/*
Create field for temporary table
@@ -4896,64 +7865,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::SUM_FUNC_ITEM:
{
Item_sum *item_sum=(Item_sum*) item;
- bool maybe_null=item_sum->maybe_null;
- switch (item_sum->sum_func()) {
- case Item_sum::AVG_FUNC: /* Place for sum & count */
- if (group)
- return new Field_string(sizeof(double)+sizeof(longlong),
- 0, item->name,table,&my_charset_bin);
- else
- return new Field_double(item_sum->max_length,maybe_null,
- item->name, table, item_sum->decimals);
- case Item_sum::VARIANCE_FUNC: /* Place for sum & count */
- case Item_sum::STD_FUNC:
- if (group)
- return new Field_string(sizeof(double)*2+sizeof(longlong),
- 0, item->name,table,&my_charset_bin);
- else
- return new Field_double(item_sum->max_length, maybe_null,
- item->name,table,item_sum->decimals);
- case Item_sum::UNIQUE_USERS_FUNC:
- return new Field_long(9,maybe_null,item->name,table,1);
- case Item_sum::MIN_FUNC:
- case Item_sum::MAX_FUNC:
- if (item_sum->args[0]->type() == Item::FIELD_ITEM)
- {
- *from_field= ((Item_field*) item_sum->args[0])->field;
- return create_tmp_field_from_field(thd, *from_field, item->name, table,
- NULL, convert_blob_length);
- }
- /* fall through */
- default:
- switch (item_sum->result_type()) {
- case REAL_RESULT:
- return new Field_double(item_sum->max_length,maybe_null,
- item->name,table,item_sum->decimals);
- case INT_RESULT:
- return new Field_longlong(item_sum->max_length,maybe_null,
- item->name,table,item->unsigned_flag);
- case STRING_RESULT:
- if (item_sum->max_length > 255)
- {
- if (convert_blob_length)
- return new Field_varstring(convert_blob_length, maybe_null,
- item->name, table,
- item->collation.collation);
- else
- return new Field_blob(item_sum->max_length, maybe_null, item->name,
- table, item->collation.collation);
- }
- return new Field_string(item_sum->max_length,maybe_null,
- item->name,table,item->collation.collation);
- case ROW_RESULT:
- default:
- // This case should never be choosen
- DBUG_ASSERT(0);
- thd->fatal_error();
- return 0;
- }
- }
- /* We never come here */
+ Field *result= item_sum->create_tmp_field(group, table, convert_blob_length);
+ if (!result)
+ thd->fatal_error();
+ return result;
}
case Item::FIELD_ITEM:
case Item::DEFAULT_VALUE_ITEM:
@@ -4973,6 +7888,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::PROC_ITEM:
case Item::INT_ITEM:
case Item::REAL_ITEM:
+ case Item::DECIMAL_ITEM:
case Item::STRING_ITEM:
case Item::REF_ITEM:
case Item::NULL_ITEM:
@@ -4994,6 +7910,11 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
for send_fields
*/
+#define STRING_TOTAL_LENGTH_TO_PACK_ROWS 128
+#define AVG_STRING_LENGTH_TO_PACK_ROWS 64
+#define RATIO_TO_PACK_ROWS 2
+#define MIN_STRING_LENGTH_TO_PACK_ROWS 10
+
TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
@@ -5001,41 +7922,50 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
char *table_alias)
{
TABLE *table;
- uint i,field_count,reclength,null_count,null_pack_length,
- hidden_null_count, hidden_null_pack_length, hidden_field_count,
- blob_count,group_null_items;
- bool using_unique_constraint=0;
+ uint i,field_count,null_count,null_pack_length;
+ uint hidden_null_count, hidden_null_pack_length, hidden_field_count;
+ uint blob_count,group_null_items, string_count;
+ uint temp_pool_slot=MY_BIT_NONE;
+ ulong reclength, string_total_length;
+ bool using_unique_constraint= 0;
+ bool use_packed_rows= 0;
bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
- char *tmpname,path[FN_REFLEN];
+ char *tmpname,path[FN_REFLEN], filename[FN_REFLEN];
byte *pos,*group_buff;
uchar *null_flags;
- Field **reg_field, **from_field, **blob_field;
+ Field **reg_field, **from_field;
+ uint *blob_field;
Copy_field *copy=0;
KEY *keyinfo;
KEY_PART_INFO *key_part_info;
Item **copy_func;
MI_COLUMNDEF *recinfo;
- uint temp_pool_slot=MY_BIT_NONE;
-
+ uint total_uneven_bit_length= 0;
DBUG_ENTER("create_tmp_table");
DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d",
(int) distinct, (int) save_sum_fields,
(ulong) rows_limit,test(group)));
- statistic_increment(created_tmp_tables, &LOCK_status);
+ statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status);
if (use_temp_pool)
temp_pool_slot = bitmap_set_next(&temp_pool);
if (temp_pool_slot != MY_BIT_NONE) // we got a slot
- sprintf(path, "%s%s_%lx_%i", mysql_tmpdir, tmp_file_prefix,
- current_pid, temp_pool_slot);
- else // if we run out of slots or we are not using tempool
- sprintf(path,"%s%s%lx_%lx_%x",mysql_tmpdir,tmp_file_prefix,current_pid,
+ sprintf(filename, "%s_%lx_%i", tmp_file_prefix,
+ current_pid, temp_pool_slot);
+ else
+ {
+ /* if we run out of slots or we are not using tempool */
+ sprintf(filename,"%s%lx_%lx_%x",tmp_file_prefix,current_pid,
thd->thread_id, thd->tmp_table++);
+ }
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, path);
+ /*
+ No need for change table name to lower case as we are only creating
+ MyISAM or HEAP tables here
+ */
+ sprintf(path, "%s%s", mysql_tmpdir, filename);
if (group)
{
@@ -5044,7 +7974,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
else for (ORDER *tmp=group ; tmp ; tmp=tmp->next)
{
(*tmp->item)->marker=4; // Store null in key
- if ((*tmp->item)->max_length >= MAX_CHAR_WIDTH)
+ if ((*tmp->item)->max_length >= CONVERT_IF_BIGGER_TO_BLOB)
using_unique_constraint=1;
}
if (param->group_length >= MAX_BLOB_WIDTH)
@@ -5058,7 +7988,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!my_multi_malloc(MYF(MY_WME),
&table,sizeof(*table),
&reg_field, sizeof(Field*)*(field_count+1),
- &blob_field, sizeof(Field*)*(field_count+1),
+ &blob_field, sizeof(uint)*(field_count+1),
&from_field, sizeof(Field*)*field_count,
&copy_func,sizeof(*copy_func)*(param->func_count+1),
&param->keyinfo,sizeof(*param->keyinfo),
@@ -5088,28 +8018,35 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
bzero((char*) from_field,sizeof(Field*)*field_count);
table->field=reg_field;
- table->blob_field= (Field_blob**) blob_field;
- table->real_name=table->path=tmpname;
- table->table_name= table_alias;
+ table->alias= table_alias;
table->reginfo.lock_type=TL_WRITE; /* Will be updated */
table->db_stat=HA_OPEN_KEYFILE+HA_OPEN_RNDFILE;
- table->blob_ptr_size=mi_portable_sizeof_char_ptr;
table->map=1;
- table->tmp_table= TMP_TABLE;
- table->db_low_byte_first=1; // True for HEAP and MyISAM
table->temp_pool_slot = temp_pool_slot;
table->copy_blobs= 1;
table->in_use= thd;
- table->keys_for_keyread.init();
- table->keys_in_use.init();
- table->read_only_keys.init();
table->quick_keys.init();
table->used_keys.init();
table->keys_in_use_for_query.init();
+ table->s= &table->share_not_to_be_used;
+ table->s->blob_field= blob_field;
+ table->s->table_name= table->s->path= tmpname;
+ table->s->db= "";
+ table->s->blob_ptr_size= mi_portable_sizeof_char_ptr;
+ table->s->tmp_table= TMP_TABLE;
+ table->s->db_low_byte_first=1; // True for HEAP and MyISAM
+ table->s->table_charset= param->table_charset;
+ table->s->keys_for_keyread.init();
+ table->s->keys_in_use.init();
+ /* For easier error reporting */
+ table->s->table_cache_key= (char*) (table->s->db= "");
+
+
/* Calculate which type of fields we will store in the temporary table */
- reclength=blob_count=null_count=hidden_null_count=group_null_items=0;
+ reclength= string_total_length= 0;
+ blob_count= string_count= null_count= hidden_null_count= group_null_items= 0;
param->using_indirect_summary_function=0;
List_iterator_fast<Item> li(fields);
@@ -5149,13 +8086,19 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!new_field)
goto err; // Should be OOM
tmp_from_field++;
- *(reg_field++)= new_field;
reclength+=new_field->pack_length();
if (new_field->flags & BLOB_FLAG)
{
- *blob_field++= new_field;
+ *blob_field++= (uint) (reg_field - table->field);
blob_count++;
}
+ *(reg_field++)= new_field;
+ if (new_field->real_type() == MYSQL_TYPE_STRING ||
+ new_field->real_type() == MYSQL_TYPE_VARCHAR)
+ {
+ string_count++;
+ string_total_length+= new_field->pack_length();
+ }
thd->change_item_tree(argp, new Item_field(new_field));
if (!(new_field->flags & NOT_NULL_FLAG))
{
@@ -5166,6 +8109,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*/
(*argp)->maybe_null=1;
}
+ new_field->query_id= thd->query_id;
}
}
}
@@ -5181,10 +8125,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
We here distinguish between UNION and multi-table-updates by the fact
that in the later case group is set to the row pointer.
*/
- Field *new_field= create_tmp_field(thd, table, item, type, &copy_func,
- tmp_from_field, group != 0,
- not_all_columns || group !=0,
- param->convert_blob_length);
+ Field *new_field= (param->schema_table) ?
+ create_tmp_field_for_schema(thd, item, table) :
+ create_tmp_field(thd, table, item, type, &copy_func,
+ tmp_from_field, group != 0,
+ not_all_columns || group !=0,
+ param->convert_blob_length);
+
if (!new_field)
{
if (thd->is_fatal_error)
@@ -5197,9 +8144,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
reclength+=new_field->pack_length();
if (!(new_field->flags & NOT_NULL_FLAG))
null_count++;
+ if (new_field->type() == FIELD_TYPE_BIT)
+ total_uneven_bit_length+= new_field->field_length & 7;
if (new_field->flags & BLOB_FLAG)
{
- *blob_field++= new_field;
+ *blob_field++= (uint) (reg_field - table->field);
blob_count++;
}
if (item->marker == 4 && item->maybe_null)
@@ -5207,6 +8156,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
group_null_items++;
new_field->flags|= GROUP_FLAG;
}
+ new_field->query_id= thd->query_id;
*(reg_field++) =new_field;
}
if (!--hidden_field_count)
@@ -5221,7 +8171,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
OPTION_BIG_TABLES)
{
- table->file=get_new_handler(table,table->db_type=DB_TYPE_MYISAM);
+ table->file=get_new_handler(table,table->s->db_type= DB_TYPE_MYISAM);
if (group &&
(param->group_parts > table->file->max_key_parts() ||
param->group_length > table->file->max_key_length()))
@@ -5229,13 +8179,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
else
{
- table->file=get_new_handler(table,table->db_type=DB_TYPE_HEAP);
+ table->file=get_new_handler(table,table->s->db_type= DB_TYPE_HEAP);
}
if (!using_unique_constraint)
reclength+= group_null_items; // null flag is stored separately
- table->blob_fields=blob_count;
+ table->s->blob_fields= blob_count;
if (blob_count == 0)
{
/* We need to ensure that first byte is not 0 for the delete link */
@@ -5245,20 +8195,27 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
null_count++;
}
hidden_null_pack_length=(hidden_null_count+7)/8;
- null_pack_length=hidden_null_count+(null_count+7)/8;
+ null_pack_length= hidden_null_count +
+ (null_count + total_uneven_bit_length + 7) / 8;
reclength+=null_pack_length;
if (!reclength)
reclength=1; // Dummy select
+ /* Use packed rows if there is blobs or a lot of space to gain */
+ if (blob_count ||
+ string_total_length >= STRING_TOTAL_LENGTH_TO_PACK_ROWS &&
+ (reclength / string_total_length <= RATIO_TO_PACK_ROWS ||
+ string_total_length / string_count >= AVG_STRING_LENGTH_TO_PACK_ROWS))
+ use_packed_rows= 1;
- table->fields=field_count;
- table->reclength=reclength;
+ table->s->fields= field_count;
+ table->s->reclength= reclength;
{
uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
- table->rec_buff_length=alloc_length;
+ table->s->rec_buff_length= alloc_length;
if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME))))
goto err;
table->record[1]= table->record[0]+alloc_length;
- table->default_values= table->record[1]+alloc_length;
+ table->s->default_values= table->record[1]+alloc_length;
}
copy_func[0]=0; // End marker
@@ -5274,8 +8231,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
bfill(null_flags,null_pack_length,255); // Set null fields
table->null_flags= (uchar*) table->record[0];
- table->null_fields= null_count+ hidden_null_count;
- table->null_bytes= null_pack_length;
+ table->s->null_fields= null_count+ hidden_null_count;
+ table->s->null_bytes= null_pack_length;
}
null_count= (blob_count == 0) ? 1 : 0;
hidden_field_count=param->hidden_field_count;
@@ -5323,10 +8280,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
recinfo->length=length;
if (field->flags & BLOB_FLAG)
recinfo->type= (int) FIELD_BLOB;
- else if (!field->zero_pack() &&
- (field->type() == FIELD_TYPE_STRING ||
- field->type() == FIELD_TYPE_VAR_STRING) &&
- length >= 10 && blob_count)
+ else if (use_packed_rows &&
+ field->real_type() == MYSQL_TYPE_STRING &&
+ length >= MIN_STRING_LENGTH_TO_PACK_ROWS)
recinfo->type=FIELD_SKIP_ENDSPACE;
else
recinfo->type=FIELD_NORMAL;
@@ -5334,30 +8290,30 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
null_count=(null_count+7) & ~7; // move to next byte
// fix table name in field entry
- field->table_name= table->table_name;
+ field->table_name= &table->alias;
}
param->copy_field_end=copy;
param->recinfo=recinfo;
- store_record(table,default_values); // Make empty default record
+ store_record(table,s->default_values); // Make empty default record
if (thd->variables.tmp_table_size == ~(ulong) 0) // No limit
- table->max_rows= ~(ha_rows) 0;
+ table->s->max_rows= ~(ha_rows) 0;
else
- table->max_rows=(((table->db_type == DB_TYPE_HEAP) ?
- min(thd->variables.tmp_table_size,
- thd->variables.max_heap_table_size) :
- thd->variables.tmp_table_size)/ table->reclength);
- set_if_bigger(table->max_rows,1); // For dummy start options
- keyinfo=param->keyinfo;
+ table->s->max_rows= (((table->s->db_type == DB_TYPE_HEAP) ?
+ min(thd->variables.tmp_table_size,
+ thd->variables.max_heap_table_size) :
+ thd->variables.tmp_table_size)/ table->s->reclength);
+ set_if_bigger(table->s->max_rows,1); // For dummy start options
+ keyinfo= param->keyinfo;
if (group)
{
DBUG_PRINT("info",("Creating group key in temporary table"));
table->group=group; /* Table is grouped by key */
param->group_buff=group_buff;
- table->keys=1;
- table->uniques= test(using_unique_constraint);
+ table->s->keys=1;
+ table->s->uniques= test(using_unique_constraint);
table->key_info=keyinfo;
keyinfo->key_part=key_part_info;
keyinfo->flags=HA_NOSAME;
@@ -5365,6 +8321,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
keyinfo->key_length=0;
keyinfo->rec_per_key=0;
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
+ keyinfo->name= (char*) "group_key";
for (; group ; group=group->next,key_part_info++)
{
Field *field=(*group->item)->get_tmp_table_field();
@@ -5372,35 +8329,40 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
key_part_info->null_bit=0;
key_part_info->field= field;
key_part_info->offset= field->offset();
- key_part_info->length= (uint16) field->pack_length();
+ key_part_info->length= (uint16) field->key_length();
key_part_info->type= (uint8) field->key_type();
key_part_info->key_type =
((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT) ?
+ (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
+ (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
0 : FIELDFLAG_BINARY;
if (!using_unique_constraint)
{
group->buff=(char*) group_buff;
- if (!(group->field=field->new_field(thd->mem_root,table)))
+ if (!(group->field= field->new_key_field(thd->mem_root,table,
+ (char*) group_buff +
+ test(maybe_null),
+ field->null_ptr,
+ field->null_bit)))
goto err; /* purecov: inspected */
if (maybe_null)
{
/*
- To be able to group on NULL, we reserve place in group_buff
- for the NULL flag just before the column.
+ To be able to group on NULL, we reserved place in group_buff
+ for the NULL flag just before the column. (see above).
The field data is after this flag.
- The NULL flag is updated by 'end_update()' and 'end_write()'
+ The NULL flag is updated in 'end_update()' and 'end_write()'
*/
keyinfo->flags|= HA_NULL_ARE_EQUAL; // def. that NULL == NULL
key_part_info->null_bit=field->null_bit;
key_part_info->null_offset= (uint) (field->null_ptr -
(uchar*) table->record[0]);
- group->field->move_field((char*) ++group->buff);
- group_buff++;
+ group->buff++; // Pointer to field data
+ group_buff++; // Skipp null flag
}
- else
- group->field->move_field((char*) group_buff);
- group_buff+= key_part_info->length;
+ /* In GROUP BY 'a' and 'a ' are equal for VARCHAR fields */
+ key_part_info->key_part_flag|= HA_END_SPACE_ARE_EQUAL;
+ group_buff+= group->field->pack_length();
}
keyinfo->key_length+= key_part_info->length;
}
@@ -5419,14 +8381,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
null_pack_length-=hidden_null_pack_length;
keyinfo->key_parts= ((field_count-param->hidden_field_count)+
test(null_pack_length));
- set_if_smaller(table->max_rows, rows_limit);
+ set_if_smaller(table->s->max_rows, rows_limit);
param->end_write_records= rows_limit;
- table->distinct=1;
- table->keys=1;
+ table->distinct= 1;
+ table->s->keys= 1;
if (blob_count)
{
using_unique_constraint=1;
- table->uniques=1;
+ table->s->uniques= 1;
}
if (!(key_part_info= (KEY_PART_INFO*)
sql_calloc((keyinfo->key_parts)*sizeof(KEY_PART_INFO))))
@@ -5435,7 +8397,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
keyinfo->key_part=key_part_info;
keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL;
keyinfo->key_length=(uint16) reclength;
- keyinfo->name=(char*) "tmp";
+ keyinfo->name= (char*) "distinct_key";
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
keyinfo->rec_per_key=0;
if (null_pack_length)
@@ -5465,14 +8427,15 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
key_part_info->type= (uint8) (*reg_field)->key_type();
key_part_info->key_type =
((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT) ?
+ (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
+ (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
0 : FIELDFLAG_BINARY;
}
}
if (thd->is_fatal_error) // If end of memory
goto err; /* purecov: inspected */
- table->db_record_offset=1;
- if (table->db_type == DB_TYPE_MYISAM)
+ table->s->db_record_offset= 1;
+ if (table->s->db_type == DB_TYPE_MYISAM)
{
if (create_myisam_tmp_table(table,param,select_options))
goto err;
@@ -5481,21 +8444,128 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
DBUG_RETURN(table);
err:
- /*
- Hack to ensure that free_blobs() doesn't fail if blob_field is not yet
- complete
- */
- *table->blob_field= 0;
free_tmp_table(thd,table); /* purecov: inspected */
bitmap_clear_bit(&temp_pool, temp_pool_slot);
DBUG_RETURN(NULL); /* purecov: inspected */
}
+/****************************************************************************/
+
+/*
+ Create a reduced TABLE object with properly set up Field list from a
+ list of field definitions.
+
+ SYNOPSIS
+ create_virtual_tmp_table()
+ thd connection handle
+ field_list list of column definitions
+
+ DESCRIPTION
+ The created table doesn't have a table handler assotiated with
+ it, has no keys, no group/distinct, no copy_funcs array.
+ The sole purpose of this TABLE object is to use the power of Field
+ class to read/write data to/from table->record[0]. Then one can store
+ the record in any container (RB tree, hash, etc).
+ The table is created in THD mem_root, so are the table's fields.
+ Consequently, if you don't BLOB fields, you don't need to free it.
+
+ RETURN
+ 0 if out of memory, TABLE object in case of success
+*/
+
+TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
+{
+ uint field_count= field_list.elements;
+ Field **field;
+ create_field *cdef; /* column definition */
+ uint record_length= 0;
+ uint null_count= 0; /* number of columns which may be null */
+ uint null_pack_length; /* NULL representation array length */
+ TABLE_SHARE *s;
+ /* Create the table and list of all fields */
+ TABLE *table= (TABLE*) thd->calloc(sizeof(*table));
+ field= (Field**) thd->alloc((field_count + 1) * sizeof(Field*));
+ if (!table || !field)
+ return 0;
+
+ table->field= field;
+ table->s= s= &table->share_not_to_be_used;
+ s->fields= field_count;
+
+ /* Create all fields and calculate the total length of record */
+ List_iterator_fast<create_field> it(field_list);
+ while ((cdef= it++))
+ {
+ *field= make_field(0, cdef->length,
+ (uchar*) (f_maybe_null(cdef->pack_flag) ? "" : 0),
+ f_maybe_null(cdef->pack_flag) ? 1 : 0,
+ cdef->pack_flag, cdef->sql_type, cdef->charset,
+ cdef->geom_type, cdef->unireg_check,
+ cdef->interval, cdef->field_name, table);
+ if (!*field)
+ goto error;
+ record_length+= (**field).pack_length();
+ if (! ((**field).flags & NOT_NULL_FLAG))
+ ++null_count;
+ ++field;
+ }
+ *field= NULL; /* mark the end of the list */
+
+ null_pack_length= (null_count + 7)/8;
+ s->reclength= record_length + null_pack_length;
+ s->rec_buff_length= ALIGN_SIZE(s->reclength + 1);
+ table->record[0]= (byte*) thd->alloc(s->rec_buff_length);
+ if (!table->record[0])
+ goto error;
+
+ if (null_pack_length)
+ {
+ table->null_flags= (uchar*) table->record[0];
+ s->null_fields= null_count;
+ s->null_bytes= null_pack_length;
+ }
+
+ table->in_use= thd; /* field->reset() may access table->in_use */
+ {
+ /* Set up field pointers */
+ byte *null_pos= table->record[0];
+ byte *field_pos= null_pos + s->null_bytes;
+ uint null_bit= 1;
+
+ for (field= table->field; *field; ++field)
+ {
+ Field *cur_field= *field;
+ if ((cur_field->flags & NOT_NULL_FLAG))
+ cur_field->move_field((char*) field_pos);
+ else
+ {
+ cur_field->move_field((char*) field_pos, (uchar*) null_pos, null_bit);
+ null_bit<<= 1;
+ if (null_bit == (1 << 8))
+ {
+ ++null_pos;
+ null_bit= 1;
+ }
+ }
+ cur_field->reset();
+
+ field_pos+= cur_field->pack_length();
+ }
+ }
+ return table;
+error:
+ for (field= table->field; *field; ++field)
+ delete *field; /* just invokes field destructor */
+ return 0;
+}
+
+
static bool open_tmp_table(TABLE *table)
{
int error;
- if ((error=table->file->ha_open(table->real_name,O_RDWR,HA_OPEN_TMP_TABLE)))
+ if ((error=table->file->ha_open(table->s->table_name,O_RDWR,
+ HA_OPEN_TMP_TABLE)))
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
table->db_stat=0;
@@ -5513,9 +8583,9 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
MI_KEYDEF keydef;
MI_UNIQUEDEF uniquedef;
KEY *keyinfo=param->keyinfo;
-
DBUG_ENTER("create_myisam_tmp_table");
- if (table->keys)
+
+ if (table->s->keys)
{ // Get keys for ni_create
bool using_unique_constraint=0;
HA_KEYSEG *seg= (HA_KEYSEG*) sql_calloc(sizeof(*seg) *
@@ -5525,11 +8595,11 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
if (keyinfo->key_length >= table->file->max_key_length() ||
keyinfo->key_parts > table->file->max_key_parts() ||
- table->uniques)
+ table->s->uniques)
{
/* Can't create a key; Make a unique constraint instead of a key */
- table->keys=0;
- table->uniques=1;
+ table->s->keys= 0;
+ table->s->uniques= 1;
using_unique_constraint=1;
bzero((char*) &uniquedef,sizeof(uniquedef));
uniquedef.keysegs=keyinfo->key_parts;
@@ -5541,7 +8611,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
param->recinfo->type= FIELD_CHECK;
param->recinfo->length=MI_UNIQUE_HASH_LENGTH;
param->recinfo++;
- table->reclength+=MI_UNIQUE_HASH_LENGTH;
+ table->s->reclength+=MI_UNIQUE_HASH_LENGTH;
}
else
{
@@ -5562,21 +8632,18 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
{
seg->type=
((keyinfo->key_part[i].key_type & FIELDFLAG_BINARY) ?
- HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT);
- seg->bit_start=seg->length - table->blob_ptr_size;
+ HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
+ seg->bit_start= (uint8)(field->pack_length() - table->s->blob_ptr_size);
seg->flag= HA_BLOB_PART;
seg->length=0; // Whole blob in unique constraint
}
else
{
- seg->type=
- ((keyinfo->key_part[i].key_type & FIELDFLAG_BINARY) ?
- HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT);
- if (!(field->flags & ZEROFILL_FLAG) &&
- (field->type() == FIELD_TYPE_STRING ||
- field->type() == FIELD_TYPE_VAR_STRING) &&
+ seg->type= keyinfo->key_part[i].type;
+ /* Tell handler if it can do suffic space compression */
+ if (field->real_type() == MYSQL_TYPE_STRING &&
keyinfo->key_part[i].length > 4)
- seg->flag|=HA_SPACE_PACK;
+ seg->flag|= HA_SPACE_PACK;
}
if (!(field->flags & NOT_NULL_FLAG))
{
@@ -5585,7 +8652,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
/*
We are using a GROUP BY on something that contains NULL
In this case we have to tell MyISAM that two NULL should
- on INSERT be compared as equal
+ on INSERT be regarded at the same value
*/
if (!using_unique_constraint)
keydef.flag|= HA_NULL_ARE_EQUAL;
@@ -5599,10 +8666,10 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
OPTION_BIG_TABLES)
create_info.data_file_length= ~(ulonglong) 0;
- if ((error=mi_create(table->real_name,table->keys,&keydef,
+ if ((error=mi_create(table->s->table_name,table->s->keys,&keydef,
(uint) (param->recinfo-param->start_recinfo),
param->start_recinfo,
- table->uniques, &uniquedef,
+ table->s->uniques, &uniquedef,
&create_info,
HA_CREATE_TMP_TABLE)))
{
@@ -5610,8 +8677,9 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
table->db_stat=0;
goto err;
}
- statistic_increment(created_tmp_disk_tables, &LOCK_status);
- table->db_record_offset=1;
+ statistic_increment(table->in_use->status_var.created_tmp_disk_tables,
+ &LOCK_status);
+ table->s->db_record_offset= 1;
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
@@ -5623,7 +8691,7 @@ free_tmp_table(THD *thd, TABLE *entry)
{
const char *save_proc_info;
DBUG_ENTER("free_tmp_table");
- DBUG_PRINT("enter",("table: %s",entry->table_name));
+ DBUG_PRINT("enter",("table: %s",entry->alias));
save_proc_info=thd->proc_info;
thd->proc_info="removing tmp table";
@@ -5639,8 +8707,9 @@ free_tmp_table(THD *thd, TABLE *entry)
here and we have to ensure that delete_table gets the table name in
the original case.
*/
- if (!(test_flags & TEST_KEEP_TMP_TABLES) || entry->db_type == DB_TYPE_HEAP)
- entry->file->delete_table(entry->real_name);
+ if (!(test_flags & TEST_KEEP_TMP_TABLES) ||
+ entry->s->db_type == DB_TYPE_HEAP)
+ entry->file->delete_table(entry->s->table_name);
delete entry->file;
}
@@ -5670,14 +8739,15 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
int write_err;
DBUG_ENTER("create_myisam_from_heap");
- if (table->db_type != DB_TYPE_HEAP || error != HA_ERR_RECORD_FILE_FULL)
+ if (table->s->db_type != DB_TYPE_HEAP || error != HA_ERR_RECORD_FILE_FULL)
{
table->file->print_error(error,MYF(0));
DBUG_RETURN(1);
}
new_table= *table;
- new_table.db_type=DB_TYPE_MYISAM;
- if (!(new_table.file=get_new_handler(&new_table,DB_TYPE_MYISAM)))
+ new_table.s= &new_table.share_not_to_be_used;
+ new_table.s->db_type= DB_TYPE_MYISAM;
+ if (!(new_table.file= get_new_handler(&new_table,DB_TYPE_MYISAM)))
DBUG_RETURN(1); // End of memory
save_proc_info=thd->proc_info;
@@ -5727,13 +8797,15 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
/* remove heap table and change to use myisam table */
(void) table->file->ha_rnd_end();
(void) table->file->close();
- (void) table->file->delete_table(table->real_name);
+ (void) table->file->delete_table(table->s->table_name);
delete table->file;
table->file=0;
- *table =new_table;
+ *table= new_table;
+ table->s= &table->share_not_to_be_used;
table->file->change_table_ptr(table);
- thd->proc_info= (!strcmp(save_proc_info,"Copying to tmp table") ?
- "Copying to tmp table on disk" : save_proc_info);
+ if (save_proc_info)
+ thd->proc_info= (!strcmp(save_proc_info,"Copying to tmp table") ?
+ "Copying to tmp table on disk" : save_proc_info);
DBUG_RETURN(0);
err:
@@ -5742,7 +8814,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
(void) table->file->ha_rnd_end();
(void) new_table.file->close();
err1:
- new_table.file->delete_table(new_table.real_name);
+ new_table.file->delete_table(new_table.s->table_name);
delete new_table.file;
err2:
thd->proc_info=save_proc_info;
@@ -5750,46 +8822,33 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
}
-/****************************************************************************
- Make a join of all tables and write it on socket or to table
- Return: 0 if ok
- 1 if error is sent
- -1 if error should be sent
-****************************************************************************/
+/*
+ SYNOPSIS
+ setup_end_select_func()
+ join join to setup the function for.
-static int
-do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
-{
- int error= 0;
- JOIN_TAB *join_tab;
- int (*end_select)(JOIN *, struct st_join_table *,bool);
- DBUG_ENTER("do_select");
+ DESCRIPTION
+ Rows produced by a join sweep may end up in a temporary table or be sent
+ to a client. Setup the function of the nested loop join algorithm which
+ handles final fully constructed and matched records.
- join->procedure=procedure;
- /*
- Tell the client how many fields there are in a row
- */
- if (!table)
- join->result->send_fields(*fields,1);
- else
- {
- VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
- empty_record(table);
- }
- join->tmp_table= table; /* Save for easy recursion */
- join->fields= fields;
+ RETURN
+ end_select function to use. This function can't fail.
+*/
+static Next_select_func setup_end_select_func(JOIN *join)
+{
+ TABLE *table= join->tmp_table;
+ Next_select_func end_select;
/* Set up select_end */
if (table)
{
if (table->group && join->tmp_table_param.sum_func_count)
{
- if (table->keys)
+ if (table->s->keys)
{
DBUG_PRINT("info",("Using end_update"));
end_select=end_update;
- if (!table->file->inited)
- table->file->ha_index_init(0);
}
else
{
@@ -5810,42 +8869,88 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
}
else
{
- if (join->sort_and_group || (join->procedure &&
- join->procedure->flags & PROC_GROUP))
- end_select=end_send_group;
+ /* Test if data is accessed via QUICK_GROUP_MIN_MAX_SELECT. */
+ bool is_using_quick_group_min_max_select=
+ (join->join_tab->select && join->join_tab->select->quick &&
+ (join->join_tab->select->quick->get_type() ==
+ QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
+
+ if ((join->sort_and_group ||
+ (join->procedure && join->procedure->flags & PROC_GROUP)) &&
+ !is_using_quick_group_min_max_select)
+ end_select= end_send_group;
else
- end_select=end_send;
+ end_select= end_send;
}
- join->join_tab[join->tables-1].next_select=end_select;
+ return end_select;
+}
+
+
+/****************************************************************************
+ Make a join of all tables and write it on socket or to table
+ Return: 0 if ok
+ 1 if error is sent
+ -1 if error should be sent
+****************************************************************************/
+
+static int
+do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
+{
+ int rc= 0;
+ enum_nested_loop_state error= NESTED_LOOP_OK;
+ JOIN_TAB *join_tab;
+ DBUG_ENTER("do_select");
+
+ join->procedure=procedure;
+ join->tmp_table= table; /* Save for easy recursion */
+ join->fields= fields;
+
+ if (table)
+ {
+ VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
+ empty_record(table);
+ if (table->group && join->tmp_table_param.sum_func_count &&
+ table->s->keys && !table->file->inited)
+ table->file->ha_index_init(0);
+ }
+ /* Set up select_end */
+ join->join_tab[join->tables-1].next_select= setup_end_select_func(join);
join_tab=join->join_tab+join->const_tables;
join->send_records=0;
if (join->tables == join->const_tables)
{
/*
- HAVING will be chcked after processing aggregate functions,
+ HAVING will be checked after processing aggregate functions,
But WHERE should checkd here (we alredy have read tables)
*/
if (!join->conds || join->conds->val_int())
{
- if (!(error=(*end_select)(join,join_tab,0)) || error == -3)
- error=(*end_select)(join,join_tab,1);
+ Next_select_func end_select= join->join_tab[join->tables-1].next_select;
+ error= (*end_select)(join,join_tab,0);
+ if (error == NESTED_LOOP_OK || error == NESTED_LOOP_QUERY_LIMIT)
+ error= (*end_select)(join,join_tab,1);
}
else if (join->send_row_on_empty_set())
- error= join->result->send_data(*join->fields);
+ rc= join->result->send_data(*join->fields);
}
else
{
error= sub_select(join,join_tab,0);
- if (error >= 0)
+ if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
error= sub_select(join,join_tab,1);
- if (error == -3)
- error= 0; /* select_limit used */
+ if (error == NESTED_LOOP_QUERY_LIMIT)
+ error= NESTED_LOOP_OK; /* select_limit used */
}
+ if (error == NESTED_LOOP_NO_MORE_ROWS)
+ error= NESTED_LOOP_OK;
- if (error >= 0)
+ if (error == NESTED_LOOP_OK)
{
- error=0;
+ /*
+ Sic: this branch works even if rc != 0, e.g. when
+ send_data above returns an error.
+ */
if (!table) // If sending data to client
{
/*
@@ -5854,152 +8959,439 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
*/
join->join_free(0); // Unlock all cursors
if (join->result->send_eof())
- error= 1; // Don't send error
+ rc= 1; // Don't send error
}
DBUG_PRINT("info",("%ld records output",join->send_records));
}
+ else
+ rc= -1;
if (table)
{
- int tmp;
+ int tmp, new_errno= 0;
if ((tmp=table->file->extra(HA_EXTRA_NO_CACHE)))
{
DBUG_PRINT("error",("extra(HA_EXTRA_NO_CACHE) failed"));
- my_errno= tmp;
- error= -1;
+ new_errno= tmp;
}
if ((tmp=table->file->ha_index_or_rnd_end()))
{
DBUG_PRINT("error",("ha_index_or_rnd_end() failed"));
- my_errno= tmp;
- error= -1;
+ new_errno= tmp;
}
- if (error == -1)
- table->file->print_error(my_errno,MYF(0));
+ if (new_errno)
+ table->file->print_error(new_errno,MYF(0));
}
#ifndef DBUG_OFF
- if (error)
+ if (rc)
{
DBUG_PRINT("error",("Error: do_select() failed"));
}
#endif
- DBUG_RETURN(join->thd->net.report_error ? -1 : error);
+ DBUG_RETURN(join->thd->net.report_error ? -1 : rc);
}
-static int
+static enum_nested_loop_state
sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{
- int error;
+ enum_nested_loop_state rc;
if (end_of_records)
{
- if ((error=flush_cached_records(join,join_tab,FALSE)) < 0)
- return error; /* purecov: inspected */
- return sub_select(join,join_tab,end_of_records);
+ rc= flush_cached_records(join,join_tab,FALSE);
+ if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS)
+ rc= sub_select(join,join_tab,end_of_records);
+ return rc;
}
if (join->thd->killed) // If aborted by user
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
- return -2; /* purecov: inspected */
+ join->thd->send_kill_message();
+ return NESTED_LOOP_KILLED; /* purecov: inspected */
}
if (join_tab->use_quick != 2 || test_if_quick_select(join_tab) <= 0)
{
if (!store_record_in_cache(&join_tab->cache))
- return 0; // There is more room in cache
+ return NESTED_LOOP_OK; // There is more room in cache
return flush_cached_records(join,join_tab,FALSE);
}
- if ((error=flush_cached_records(join,join_tab,TRUE)) < 0)
- return error; /* purecov: inspected */
- return sub_select(join,join_tab,end_of_records); /* Use ordinary select */
+ rc= flush_cached_records(join, join_tab, TRUE);
+ if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS)
+ rc= sub_select(join, join_tab, end_of_records);
+ return rc;
}
+/*
+ Retrieve records ends with a given beginning from the result of a join
+
+ SYNPOSIS
+ sub_select()
+ join pointer to the structure providing all context info for the query
+ join_tab the first next table of the execution plan to be retrieved
+ end_records true when we need to perform final steps of retrival
-static int
+ DESCRIPTION
+ For a given partial join record consisting of records from the tables
+ preceding the table join_tab in the execution plan, the function
+ retrieves all matching full records from the result set and
+ send them to the result set stream.
+
+ NOTES
+ The function effectively implements the final (n-k) nested loops
+ of nested loops join algorithm, where k is the ordinal number of
+ the join_tab table and n is the total number of tables in the join query.
+ It performs nested loops joins with all conjunctive predicates from
+ the where condition pushed as low to the tables as possible.
+ E.g. for the query
+ SELECT * FROM t1,t2,t3
+ WHERE t1.a=t2.a AND t2.b=t3.b AND t1.a BETWEEN 5 AND 9
+ the predicate (t1.a BETWEEN 5 AND 9) will be pushed to table t1,
+ given the selected plan prescribes to nest retrievals of the
+ joined tables in the following order: t1,t2,t3.
+ A pushed down predicate are attached to the table which it pushed to,
+ at the field select_cond.
+ When executing a nested loop of level k the function runs through
+ the rows of 'join_tab' and for each row checks the pushed condition
+ attached to the table.
+ If it is false the function moves to the next row of the
+ table. If the condition is true the function recursively executes (n-k-1)
+ remaining embedded nested loops.
+ The situation becomes more complicated if outer joins are involved in
+ the execution plan. In this case the pushed down predicates can be
+ checked only at certain conditions.
+ Suppose for the query
+ SELECT * FROM t1 LEFT JOIN (t2,t3) ON t3.a=t1.a
+ WHERE t1>2 AND (t2.b>5 OR t2.b IS NULL)
+ the optimizer has chosen a plan with the table order t1,t2,t3.
+ The predicate P1=t1>2 will be pushed down to the table t1, while the
+ predicate P2=(t2.b>5 OR t2.b IS NULL) will be attached to the table
+ t2. But the second predicate can not be unconditionally tested right
+ after a row from t2 has been read. This can be done only after the
+ first row with t3.a=t1.a has been encountered.
+ Thus, the second predicate P2 is supplied with a guarded value that are
+ stored in the field 'found' of the first inner table for the outer join
+ (table t2). When the first row with t3.a=t1.a for the current row
+ of table t1 appears, the value becomes true. For now on the predicate
+ is evaluated immediately after the row of table t2 has been read.
+ When the first row with t3.a=t1.a has been encountered all
+ conditions attached to the inner tables t2,t3 must be evaluated.
+ Only when all of them are true the row is sent to the output stream.
+ If not, the function returns to the lowest nest level that has a false
+ attached condition.
+ The predicates from on expressions are also pushed down. If in the
+ the above example the on expression were (t3.a=t1.a AND t2.a=t1.a),
+ then t1.a=t2.a would be pushed down to table t2, and without any
+ guard.
+ If after the run through all rows of table t2, the first inner table
+ for the outer join operation, it turns out that no matches are
+ found for the current row of t1, then current row from table t1
+ is complemented by nulls for t2 and t3. Then the pushed down predicates
+ are checked for the composed row almost in the same way as it had
+ been done for the first row with a match. The only difference is
+ the predicates from on expressions are not checked.
+
+ IMPLEMENTATION
+ The function forms output rows for a current partial join of k
+ tables tables recursively.
+ For each partial join record ending with a certain row from
+ join_tab it calls sub_select that builds all possible matching
+ tails from the result set.
+ To be able check predicates conditionally items of the class
+ Item_func_trig_cond are employed.
+ An object of this class is constructed from an item of class COND
+ and a pointer to a guarding boolean variable.
+ When the value of the guard variable is true the value of the object
+ is the same as the value of the predicate, otherwise it's just returns
+ true.
+ To carry out a return to a nested loop level of join table t the pointer
+ to t is remembered in the field 'return_tab' of the join structure.
+ Consider the following query:
+ SELECT * FROM t1,
+ LEFT JOIN
+ (t2, t3 LEFT JOIN (t4,t5) ON t5.a=t3.a)
+ ON t4.a=t2.a
+ WHERE (t2.b=5 OR t2.b IS NULL) AND (t4.b=2 OR t4.b IS NULL)
+ Suppose the chosen execution plan dictates the order t1,t2,t3,t4,t5
+ and suppose for a given joined rows from tables t1,t2,t3 there are
+ no rows in the result set yet.
+ When first row from t5 that satisfies the on condition
+ t5.a=t3.a is found, the pushed down predicate t4.b=2 OR t4.b IS NULL
+ becomes 'activated', as well the predicate t4.a=t2.a. But
+ the predicate (t2.b=5 OR t2.b IS NULL) can not be checked until
+ t4.a=t2.a becomes true.
+ In order not to re-evaluate the predicates that were already evaluated
+ as attached pushed down predicates, a pointer to the the first
+ most inner unmatched table is maintained in join_tab->first_unmatched.
+ Thus, when the first row from t5 with t5.a=t3.a is found
+ this pointer for t5 is changed from t4 to t2.
+
+ STRUCTURE NOTES
+ join_tab->first_unmatched points always backwards to the first inner
+ table of the embedding nested join, if any.
+
+ RETURN
+ return one of enum_nested_loop_state, except NESTED_LOOP_NO_MORE_ROWS.
+*/
+
+static enum_nested_loop_state
sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{
-
join_tab->table->null_row=0;
if (end_of_records)
return (*join_tab->next_select)(join,join_tab+1,end_of_records);
- /* Cache variables for faster loop */
int error;
- bool found=0;
- COND *on_expr=join_tab->on_expr, *select_cond=join_tab->select_cond;
+ enum_nested_loop_state rc;
my_bool *report_error= &(join->thd->net.report_error);
+ READ_RECORD *info= &join_tab->read_record;
- if (!(error=(*join_tab->read_first_record)(join_tab)))
+ if (join->resume_nested_loop)
{
- bool not_exists_optimize= join_tab->table->reginfo.not_exists_optimize;
- bool not_used_in_distinct=join_tab->not_used_in_distinct;
- ha_rows found_records=join->found_records;
- READ_RECORD *info= &join_tab->read_record;
+ /* If not the last table, plunge down the nested loop */
+ if (join_tab < join->join_tab + join->tables - 1)
+ rc= (*join_tab->next_select)(join, join_tab + 1, 0);
+ else
+ {
+ join->resume_nested_loop= FALSE;
+ rc= NESTED_LOOP_OK;
+ }
+ }
+ else
+ {
+ join->return_tab= join_tab;
+
+ if (join_tab->last_inner)
+ {
+ /* join_tab is the first inner table for an outer join operation. */
+
+ /* Set initial state of guard variables for this table.*/
+ join_tab->found=0;
+ join_tab->not_null_compl= 1;
+ /* Set first_unmatched for the last inner table of this group */
+ join_tab->last_inner->first_unmatched= join_tab;
+ }
join->thd->row_count= 0;
- do
+
+ error= (*join_tab->read_first_record)(join_tab);
+ rc= evaluate_join_record(join, join_tab, error, report_error);
+ }
+
+ while (rc == NESTED_LOOP_OK)
+ {
+ error= info->read_record(info);
+ rc= evaluate_join_record(join, join_tab, error, report_error);
+ }
+
+ if (rc == NESTED_LOOP_NO_MORE_ROWS &&
+ join_tab->last_inner && !join_tab->found)
+ rc= evaluate_null_complemented_join_record(join, join_tab);
+
+ if (rc == NESTED_LOOP_NO_MORE_ROWS)
+ rc= NESTED_LOOP_OK;
+ return rc;
+}
+
+
+/*
+ Process one record of the nested loop join.
+
+ DESCRIPTION
+ This function will evaluate parts of WHERE/ON clauses that are
+ applicable to the partial record on hand and in case of success
+ submit this record to the next level of the nested loop.
+*/
+
+static enum_nested_loop_state
+evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
+ int error, my_bool *report_error)
+{
+ bool not_exists_optimize= join_tab->table->reginfo.not_exists_optimize;
+ bool not_used_in_distinct=join_tab->not_used_in_distinct;
+ ha_rows found_records=join->found_records;
+ COND *select_cond= join_tab->select_cond;
+
+ if (error > 0 || (*report_error)) // Fatal error
+ return NESTED_LOOP_ERROR;
+ if (error < 0)
+ return NESTED_LOOP_NO_MORE_ROWS;
+ if (join->thd->killed) // Aborted by user
+ {
+ join->thd->send_kill_message();
+ return NESTED_LOOP_KILLED; /* purecov: inspected */
+ }
+ DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond));
+ if (!select_cond || select_cond->val_int())
+ {
+ /*
+ There is no select condition or the attached pushed down
+ condition is true => a match is found.
+ */
+ bool found= 1;
+ while (join_tab->first_unmatched && found)
{
- if (join->thd->killed) // Aborted by user
- {
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
- return -2; /* purecov: inspected */
- }
- join->examined_rows++;
- join->thd->row_count++;
- if (!on_expr || on_expr->val_int())
+ /*
+ The while condition is always false if join_tab is not
+ the last inner join table of an outer join operation.
+ */
+ JOIN_TAB *first_unmatched= join_tab->first_unmatched;
+ /*
+ Mark that a match for current outer table is found.
+ This activates push down conditional predicates attached
+ to the all inner tables of the outer join.
+ */
+ first_unmatched->found= 1;
+ for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++)
{
- found=1;
- if (not_exists_optimize)
- break; // Searching after not null columns
- if (!select_cond || select_cond->val_int())
- {
- if ((error=(*join_tab->next_select)(join,join_tab+1,0)) < 0)
- return error;
- /*
- Test if this was a SELECT DISTINCT query on a table that
- was not in the field list; In this case we can abort if
- we found a row, as no new rows can be added to the result.
- */
- if (not_used_in_distinct && found_records != join->found_records)
- return 0;
- }
- else
+ /* Check all predicates that has just been activated. */
+ /*
+ Actually all predicates non-guarded by first_unmatched->found
+ will be re-evaluated again. It could be fixed, but, probably,
+ it's not worth doing now.
+ */
+ if (tab->select_cond && !tab->select_cond->val_int())
{
- /*
- This row failed selection, release lock on it.
- XXX: There is no table handler in MySQL which makes use of this
- call. It's kept from Gemini times. A lot of new code was added
- recently (i. e. subselects) without having it in mind.
- */
- info->file->unlock_row();
+ /* The condition attached to table tab is false */
+ if (tab == join_tab)
+ found= 0;
+ else
+ {
+ /*
+ Set a return point if rejected predicate is attached
+ not to the last table of the current nest level.
+ */
+ join->return_tab= tab;
+ return NESTED_LOOP_OK;
+ }
}
}
- } while (!(error=info->read_record(info)) && !(*report_error));
+ /*
+ Check whether join_tab is not the last inner table
+ for another embedding outer join.
+ */
+ if ((first_unmatched= first_unmatched->first_upper) &&
+ first_unmatched->last_inner != join_tab)
+ first_unmatched= 0;
+ join_tab->first_unmatched= first_unmatched;
+ }
+
+ /*
+ It was not just a return to lower loop level when one
+ of the newly activated predicates is evaluated as false
+ (See above join->return_tab= tab).
+ */
+ join->examined_rows++;
+ join->thd->row_count++;
+
+ if (found)
+ {
+ enum enum_nested_loop_state rc;
+ if (not_exists_optimize)
+ return NESTED_LOOP_NO_MORE_ROWS;
+ /* A match from join_tab is found for the current partial join. */
+ rc= (*join_tab->next_select)(join, join_tab+1, 0);
+ if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
+ return rc;
+ if (join->return_tab < join_tab)
+ return NESTED_LOOP_OK;
+ /*
+ Test if this was a SELECT DISTINCT query on a table that
+ was not in the field list; In this case we can abort if
+ we found a row, as no new rows can be added to the result.
+ */
+ if (not_used_in_distinct && found_records != join->found_records)
+ return NESTED_LOOP_OK;
+ }
+ else
+ join_tab->read_record.file->unlock_row();
}
- if (error > 0 || (*report_error)) // Fatal error
- return -1;
+ else
+ {
+ /*
+ The condition pushed down to the table join_tab rejects all rows
+ with the beginning coinciding with the current partial join.
+ */
+ join->examined_rows++;
+ join->thd->row_count++;
+ }
+ return NESTED_LOOP_OK;
+}
- if (!found && on_expr)
- { // OUTER JOIN
- restore_record(join_tab->table,default_values); // Make empty record
- mark_as_null_row(join_tab->table); // For group by without error
- if (!select_cond || select_cond->val_int())
+
+/*
+ DESCRIPTION
+ Construct a NULL complimented partial join record and feed it to the next
+ level of the nested loop. This function is used in case we have
+ an OUTER join and no matching record was found.
+*/
+
+static enum_nested_loop_state
+evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab)
+{
+ /*
+ The table join_tab is the first inner table of a outer join operation
+ and no matches has been found for the current outer row.
+ */
+ JOIN_TAB *last_inner_tab= join_tab->last_inner;
+ /* Cache variables for faster loop */
+ COND *select_cond;
+ for ( ; join_tab <= last_inner_tab ; join_tab++)
+ {
+ /* Change the the values of guard predicate variables. */
+ join_tab->found= 1;
+ join_tab->not_null_compl= 0;
+ /* The outer row is complemented by nulls for each inner tables */
+ restore_record(join_tab->table,s->default_values); // Make empty record
+ mark_as_null_row(join_tab->table); // For group by without error
+ select_cond= join_tab->select_cond;
+ /* Check all attached conditions for inner table rows. */
+ if (select_cond && !select_cond->val_int())
+ return NESTED_LOOP_OK;
+ }
+ join_tab--;
+ /*
+ The row complemented by nulls might be the first row
+ of embedding outer joins.
+ If so, perform the same actions as in the code
+ for the first regular outer join row above.
+ */
+ for ( ; ; )
+ {
+ JOIN_TAB *first_unmatched= join_tab->first_unmatched;
+ if ((first_unmatched= first_unmatched->first_upper) &&
+ first_unmatched->last_inner != join_tab)
+ first_unmatched= 0;
+ join_tab->first_unmatched= first_unmatched;
+ if (!first_unmatched)
+ break;
+ first_unmatched->found= 1;
+ for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++)
{
- if ((error=(*join_tab->next_select)(join,join_tab+1,0)) < 0)
- return error; /* purecov: inspected */
+ if (tab->select_cond && !tab->select_cond->val_int())
+ {
+ join->return_tab= tab;
+ return NESTED_LOOP_OK;
+ }
}
}
- return 0;
+ /*
+ The row complemented by nulls satisfies all conditions
+ attached to inner tables.
+ Send the row complemented by nulls to be joined with the
+ remaining tables.
+ */
+ return (*join_tab->next_select)(join, join_tab+1, 0);
}
-static int
+static enum_nested_loop_state
flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last)
{
+ enum_nested_loop_state rc= NESTED_LOOP_OK;
int error;
READ_RECORD *info;
if (!join_tab->cache.records)
- return 0; /* Nothing to do */
+ return NESTED_LOOP_OK; /* Nothing to do */
if (skip_last)
(void) store_record_in_cache(&join_tab->cache); // Must save this for later
if (join_tab->use_quick == 2)
@@ -6014,7 +9406,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last)
if ((error=join_init_read_record(join_tab)))
{
reset_cache_write(&join_tab->cache);
- return -error; /* No records or error */
+ return error < 0 ? NESTED_LOOP_NO_MORE_ROWS: NESTED_LOOP_ERROR;
}
for (JOIN_TAB *tmp=join->join_tab; tmp != join_tab ; tmp++)
@@ -6028,12 +9420,12 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last)
{
if (join->thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
- return -2; // Aborted by user /* purecov: inspected */
+ join->thd->send_kill_message();
+ return NESTED_LOOP_KILLED; // Aborted by user /* purecov: inspected */
}
SQL_SELECT *select=join_tab->select;
- if (!error && (!join_tab->cache.select ||
- !join_tab->cache.select->skip_record()))
+ if (rc == NESTED_LOOP_OK &&
+ (!join_tab->cache.select || !join_tab->cache.select->skip_record()))
{
uint i;
reset_cache_read(&join_tab->cache);
@@ -6041,11 +9433,14 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last)
{
read_cached_record(join_tab);
if (!select || !select->skip_record())
- if ((error=(join_tab->next_select)(join,join_tab+1,0)) < 0)
+ {
+ rc= (join_tab->next_select)(join,join_tab+1,0);
+ if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
{
reset_cache_write(&join_tab->cache);
- return error; /* purecov: inspected */
+ return rc;
}
+ }
}
}
} while (!(error=info->read_record(info)));
@@ -6054,10 +9449,10 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last)
read_cached_record(join_tab); // Restore current record
reset_cache_write(&join_tab->cache);
if (error > 0) // Fatal error
- return -1; /* purecov: inspected */
+ return NESTED_LOOP_ERROR; /* purecov: inspected */
for (JOIN_TAB *tmp2=join->join_tab; tmp2 != join_tab ; tmp2++)
tmp2->table->status=tmp2->status;
- return 0;
+ return NESTED_LOOP_OK;
}
@@ -6081,7 +9476,7 @@ int report_error(TABLE *table, int error)
*/
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
sql_print_error("Got error %d when reading table '%s'",
- error, table->path);
+ error, table->s->path);
table->file->print_error(error,MYF(0));
return 1;
}
@@ -6116,7 +9511,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
tab->info="const row not found";
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
- if (!table->outer_join || error > 0)
+ if (!table->maybe_null || error > 0)
DBUG_RETURN(error);
}
}
@@ -6135,7 +9530,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
tab->info="unique row not found";
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
- if (!table->outer_join || error > 0)
+ if (!table->maybe_null || error > 0)
DBUG_RETURN(error);
}
if (table->key_read)
@@ -6144,9 +9539,9 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
}
- if (tab->on_expr && !table->null_row)
+ if (*tab->on_expr_ref && !table->null_row)
{
- if ((table->null_row= test(tab->on_expr->val_int() == 0)))
+ if ((table->null_row= test((*tab->on_expr_ref)->val_int() == 0)))
mark_as_null_row(table);
}
if (!table->null_row)
@@ -6163,7 +9558,7 @@ join_read_system(JOIN_TAB *tab)
if (table->status & STATUS_GARBAGE) // If first read
{
if ((error=table->file->read_first_row(table->record[0],
- table->primary_key)))
+ table->s->primary_key)))
{
if (error != HA_ERR_END_OF_FILE)
return report_error(table, error);
@@ -6180,6 +9575,19 @@ join_read_system(JOIN_TAB *tab)
}
+/*
+ Read a table when there is at most one matching row
+
+ SYNOPSIS
+ join_read_const()
+ tab Table to read
+
+ RETURN
+ 0 Row was found
+ -1 Row was not found
+ 1 Got an error (other than row not found) during read
+*/
+
static int
join_read_const(JOIN_TAB *tab)
{
@@ -6187,6 +9595,7 @@ join_read_const(JOIN_TAB *tab)
TABLE *table= tab->table;
if (table->status & STATUS_GARBAGE) // If first read
{
+ table->status= 0;
if (cp_buffer_from_ref(tab->join->thd, &tab->ref))
error=HA_ERR_KEY_NOT_FOUND;
else
@@ -6197,6 +9606,7 @@ join_read_const(JOIN_TAB *tab)
}
if (error)
{
+ table->status= STATUS_NOT_FOUND;
mark_as_null_row(tab->table);
empty_record(table);
if (error != HA_ERR_KEY_NOT_FOUND)
@@ -6360,8 +9770,8 @@ test_if_quick_select(JOIN_TAB *tab)
static int
join_init_read_record(JOIN_TAB *tab)
{
- if (tab->select && tab->select->quick)
- tab->select->quick->reset();
+ if (tab->select && tab->select->quick && tab->select->quick->reset())
+ return 1;
init_read_record(&tab->read_record, tab->join->thd, tab->table,
tab->select,1,1);
return (*tab->read_record.read_record)(&tab->read_record);
@@ -6508,13 +9918,32 @@ join_read_next_same_or_null(READ_RECORD *info)
/*****************************************************************************
- The different end of select functions
- These functions returns < 0 when end is reached, 0 on ok and > 0 if a
- fatal error (like table corruption) was detected
+ DESCRIPTION
+ Functions that end one nested loop iteration. Different functions
+ are used to support GROUP BY clause and to redirect records
+ to a table (e.g. in case of SELECT into a temporary table) or to the
+ network client.
+
+ RETURN VALUES
+ NESTED_LOOP_OK - the record has been successfully handled
+ NESTED_LOOP_ERROR - a fatal error (like table corruption)
+ was detected
+ NESTED_LOOP_KILLED - thread shutdown was requested while processing
+ the record
+ NESTED_LOOP_QUERY_LIMIT - the record has been successfully handled;
+ additionally, the nested loop produced the
+ number of rows specified in the LIMIT clause
+ for the query
+ NESTED_LOOP_CURSOR_LIMIT - the record has been successfully handled;
+ additionally, there is a cursor and the nested
+ loop algorithm produced the number of rows
+ that is specified for current cursor fetch
+ operation.
+ All return values except NESTED_LOOP_OK abort the nested loop.
*****************************************************************************/
/* ARGSUSED */
-static int
+static enum_nested_loop_state
end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
bool end_of_records)
{
@@ -6523,14 +9952,14 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
int error;
if (join->having && join->having->val_int() == 0)
- DBUG_RETURN(0); // Didn't match having
+ DBUG_RETURN(NESTED_LOOP_OK); // Didn't match having
error=0;
if (join->procedure)
error=join->procedure->send_row(*join->fields);
else if (join->do_send_rows)
error=join->result->send_data(*join->fields);
if (error)
- DBUG_RETURN(-1); /* purecov: inspected */
+ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
if (++join->send_records >= join->unit->select_limit_cnt &&
join->do_send_rows)
{
@@ -6564,23 +9993,31 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
join->do_send_rows= 0;
if (join->unit->fake_select_lex)
join->unit->fake_select_lex->select_limit= HA_POS_ERROR;
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
}
- DBUG_RETURN(-3); // Abort nicely
+ DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); // Abort nicely
+ }
+ else if (join->send_records >= join->fetch_limit)
+ {
+ /*
+ There is a server side cursor and all rows for
+ this fetch request are sent.
+ */
+ DBUG_RETURN(NESTED_LOOP_CURSOR_LIMIT);
}
}
else
{
if (join->procedure && join->procedure->end_of_records())
- DBUG_RETURN(-1);
+ DBUG_RETURN(NESTED_LOOP_ERROR);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
/* ARGSUSED */
-static int
+static enum_nested_loop_state
end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
bool end_of_records)
{
@@ -6632,23 +10069,31 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
}
if (error > 0)
- DBUG_RETURN(-1); /* purecov: inspected */
+ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
if (end_of_records)
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
if (join->send_records >= join->unit->select_limit_cnt &&
join->do_send_rows)
{
if (!(join->select_options & OPTION_FOUND_ROWS))
- DBUG_RETURN(-3); // Abort nicely
+ DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); // Abort nicely
join->do_send_rows=0;
join->unit->select_limit_cnt = HA_POS_ERROR;
}
+ else if (join->send_records >= join->fetch_limit)
+ {
+ /*
+ There is a server side cursor and all rows
+ for this fetch request are sent.
+ */
+ DBUG_RETURN(NESTED_LOOP_CURSOR_LIMIT);
+ }
}
}
else
{
if (end_of_records)
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
join->first_record=1;
VOID(test_if_group_changed(join->group_fields));
}
@@ -6656,33 +10101,32 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
copy_fields(&join->tmp_table_param);
if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
- DBUG_RETURN(-1);
+ DBUG_RETURN(NESTED_LOOP_ERROR);
if (join->procedure)
join->procedure->add();
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
}
if (update_sum_func(join->sum_funcs))
- DBUG_RETURN(-1);
+ DBUG_RETURN(NESTED_LOOP_ERROR);
if (join->procedure)
join->procedure->add();
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
/* ARGSUSED */
-static int
+static enum_nested_loop_state
end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
bool end_of_records)
{
TABLE *table=join->tmp_table;
- int error;
DBUG_ENTER("end_write");
if (join->thd->killed) // Aborted by user
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
- DBUG_RETURN(-2); /* purecov: inspected */
+ join->thd->send_kill_message();
+ DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */
}
if (!end_of_records)
{
@@ -6707,6 +10151,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
#endif
if (!join->having || join->having->val_int())
{
+ int error;
join->found_records++;
if ((error=table->file->write_row(table->record[0])))
{
@@ -6715,28 +10160,28 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
goto end;
if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
error,1))
- DBUG_RETURN(-1); // Not a table_is_full error
- table->uniques=0; // To ensure rows are the same
+ DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error
+ table->s->uniques=0; // To ensure rows are the same
}
if (++join->send_records >= join->tmp_table_param.end_write_records &&
join->do_send_rows)
{
if (!(join->select_options & OPTION_FOUND_ROWS))
- DBUG_RETURN(-3);
+ DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT);
join->do_send_rows=0;
join->unit->select_limit_cnt = HA_POS_ERROR;
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
}
}
end:
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
/* Group by searching after group record and updating it if possible */
/* ARGSUSED */
-static int
+static enum_nested_loop_state
end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
bool end_of_records)
{
@@ -6746,11 +10191,11 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_ENTER("end_update");
if (end_of_records)
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
if (join->thd->killed) // Aborted by user
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
- DBUG_RETURN(-2); /* purecov: inspected */
+ join->thd->send_kill_message();
+ DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */
}
join->found_records++;
@@ -6760,9 +10205,6 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
Item *item= *group->item;
item->save_org_in_field(group->field);
-#ifdef EMBEDDED_LIBRARY
- join->thd->net.last_errno= 0;
-#endif
/* Store in the used key if the field was 0 */
if (item->maybe_null)
group->buff[-1]=item->null_value ? 1 : 0;
@@ -6777,36 +10219,43 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
+ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
}
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
- /* The null bits are already set */
+ /*
+ Copy null bits from group key to table
+ We can't copy all data as the key may have different format
+ as the row data (for example as with VARCHAR keys)
+ */
KEY_PART_INFO *key_part;
for (group=table->group,key_part=table->key_info[0].key_part;
group ;
group=group->next,key_part++)
- memcpy(table->record[0]+key_part->offset, group->buff, key_part->length);
-
+ {
+ if (key_part->null_bit)
+ memcpy(table->record[0]+key_part->offset, group->buff, 1);
+ }
init_tmptable_sum_functions(join->sum_funcs);
copy_funcs(join->tmp_table_param.items_to_copy);
if ((error=table->file->write_row(table->record[0])))
{
if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
error, 0))
- DBUG_RETURN(-1); // Not a table_is_full error
+ DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error
/* Change method to update rows */
table->file->ha_index_init(0);
join->join_tab[join->tables-1].next_select=end_unique_update;
}
join->send_records++;
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
+
/* Like end_update, but this is done with unique constraints instead of keys */
-static int
+static enum_nested_loop_state
end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
bool end_of_records)
{
@@ -6815,11 +10264,11 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_ENTER("end_unique_update");
if (end_of_records)
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
if (join->thd->killed) // Aborted by user
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
- DBUG_RETURN(-2); /* purecov: inspected */
+ join->thd->send_kill_message();
+ DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */
}
init_tmptable_sum_functions(join->sum_funcs);
@@ -6833,12 +10282,12 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if ((int) table->file->get_dup_key(error) < 0)
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
+ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
}
if (table->file->rnd_pos(table->record[1],table->file->dupp_ref))
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
+ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
}
restore_record(table,record[1]);
update_tmptable_sum_func(join->sum_funcs,table);
@@ -6846,27 +10295,26 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
+ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
}
}
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
/* ARGSUSED */
-static int
+static enum_nested_loop_state
end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
bool end_of_records)
{
TABLE *table=join->tmp_table;
- int error;
int idx= -1;
DBUG_ENTER("end_write_group");
if (join->thd->killed)
{ // Aborted by user
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
- DBUG_RETURN(-2); /* purecov: inspected */
+ join->thd->send_kill_message();
+ DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */
}
if (!join->first_record || end_of_records ||
(idx=test_if_group_changed(join->group_fields)) >= 0)
@@ -6885,35 +10333,27 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
copy_sum_funcs(join->sum_funcs,
join->sum_funcs_end[send_group_parts]);
- if (join->having && join->having->val_int() == 0)
- error= -1;
- else if ((error=table->file->write_row(table->record[0])))
+ if (!join->having || join->having->val_int())
{
- if (create_myisam_from_heap(join->thd, table,
- &join->tmp_table_param,
- error, 0))
- DBUG_RETURN(-1);
- /*
- If table->file->write_row() was failed because of 'out of memory'
- and tmp table succesfully created, reset error.
- */
- error=0;
+ int error= table->file->write_row(table->record[0]);
+ if (error && create_myisam_from_heap(join->thd, table,
+ &join->tmp_table_param,
+ error, 0))
+ DBUG_RETURN(NESTED_LOOP_ERROR);
}
- if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0)
+ if (join->rollup.state != ROLLUP::STATE_NONE)
{
if (join->rollup_write_data((uint) (idx+1), table))
- error= 1;
+ DBUG_RETURN(NESTED_LOOP_ERROR);
}
- if (error > 0)
- DBUG_RETURN(-1);
if (end_of_records)
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
}
else
{
if (end_of_records)
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
join->first_record=1;
VOID(test_if_group_changed(join->group_fields));
}
@@ -6922,17 +10362,17 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
copy_fields(&join->tmp_table_param);
copy_funcs(join->tmp_table_param.items_to_copy);
if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
- DBUG_RETURN(-1);
+ DBUG_RETURN(NESTED_LOOP_ERROR);
if (join->procedure)
join->procedure->add();
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
}
if (update_sum_func(join->sum_funcs))
- DBUG_RETURN(-1);
+ DBUG_RETURN(NESTED_LOOP_ERROR);
if (join->procedure)
join->procedure->add();
- DBUG_RETURN(0);
+ DBUG_RETURN(NESTED_LOOP_OK);
}
@@ -6962,11 +10402,11 @@ static bool test_if_ref(Item_field *left_item,Item *right_item)
/*
We can remove binary fields and numerical fields except float,
as float comparison isn't 100 % secure
- We have to keep binary strings to be able to check for end spaces
+ We have to keep normal strings to be able to check for end spaces
*/
if (field->binary() &&
- field->real_type() != FIELD_TYPE_STRING &&
- field->real_type() != FIELD_TYPE_VAR_STRING &&
+ field->real_type() != MYSQL_TYPE_STRING &&
+ field->real_type() != MYSQL_TYPE_VARCHAR &&
(field->type() != FIELD_TYPE_FLOAT || field->decimals() == 0))
{
return !store_val_in_field(field,right_item);
@@ -7156,13 +10596,13 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
}
-static uint find_shortest_key(TABLE *table, const key_map *usable_keys)
+uint find_shortest_key(TABLE *table, const key_map *usable_keys)
{
uint min_length= (uint) ~0;
uint best= MAX_KEY;
if (!usable_keys->is_clear_all())
{
- for (uint nr=0; nr < table->keys ; nr++)
+ for (uint nr=0; nr < table->s->keys ; nr++)
{
if (usable_keys->is_set(nr))
{
@@ -7228,7 +10668,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
- for (nr= 0 ; nr < table->keys ; nr++)
+ for (nr= 0 ; nr < table->s->keys ; nr++)
{
if (usable_keys->is_set(nr) &&
table->key_info[nr].key_length < min_length &&
@@ -7293,6 +10733,17 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
else if (select && select->quick) // Range found by opt_range
{
+ int quick_type= select->quick->get_type();
+ /*
+ assume results are not ordered when index merge is used
+ TODO: sergeyp: Results of all index merge selects actually are ordered
+ by clustered PK values.
+ */
+
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT)
+ DBUG_RETURN(0);
ref_key= select->quick->index;
ref_key_parts= select->quick->used_key_parts;
}
@@ -7374,8 +10825,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
if (!select->quick->reverse_sorted())
{
- // ORDER BY range_key DESC
- QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick,
+ int quick_type= select->quick->get_type();
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ DBUG_RETURN(0); // Use filesort
+
+ /* ORDER BY range_key DESC */
+ QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC((QUICK_RANGE_SELECT*)(select->quick),
used_key_parts);
if (!tmp || tmp->error)
{
@@ -7433,7 +10891,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
else
keys= usable_keys;
- for (nr=0; nr < table->keys ; nr++)
+ for (nr=0; nr < table->s->keys ; nr++)
{
uint not_used;
if (keys.is_set(nr))
@@ -7523,8 +10981,11 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
{
select->quick=tab->quick;
tab->quick=0;
- /* We can only use 'Only index' if quick key is same as ref_key */
- if (table->key_read && (uint) tab->ref.key != select->quick->index)
+ /*
+ We can only use 'Only index' if quick key is same as ref_key
+ and in index_merge 'Only index' cannot be used
+ */
+ if (table->key_read && ((uint) tab->ref.key != select->quick->index))
{
table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
@@ -7544,7 +11005,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
goto err;
}
}
- if (table->tmp_table)
+ if (table->s->tmp_table)
table->file->info(HA_STATUS_VARIABLE); // Get record count
table->sort.found_records=filesort(thd, table,sortorder, length,
select, filesort_limit, &examined_rows);
@@ -7555,6 +11016,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
tab->select= 0;
}
tab->select_cond=0;
+ tab->last_inner= 0;
+ tab->first_unmatched= 0;
tab->type=JT_ALL; // Read with normal read_record
tab->read_first_record= join_init_read_record;
tab->join->examined_rows+=examined_rows;
@@ -7618,7 +11081,7 @@ static bool compare_record(TABLE *table, Field **ptr)
{
for (; *ptr ; ptr++)
{
- if ((*ptr)->cmp_offset(table->rec_buff_length))
+ if ((*ptr)->cmp_offset(table->s->rec_buff_length))
return 1;
}
return 0;
@@ -7671,15 +11134,15 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
join->unit->select_limit_cnt= 1; // Only send first row
DBUG_RETURN(0);
}
- Field **first_field=entry->field+entry->fields - field_count;
+ Field **first_field=entry->field+entry->s->fields - field_count;
offset= field_count ?
- entry->field[entry->fields - field_count]->offset() : 0;
- reclength=entry->reclength-offset;
+ entry->field[entry->s->fields - field_count]->offset() : 0;
+ reclength=entry->s->reclength-offset;
free_io_cache(entry); // Safety
entry->file->info(HA_STATUS_VARIABLE);
- if (entry->db_type == DB_TYPE_HEAP ||
- (!entry->blob_fields &&
+ if (entry->s->db_type == DB_TYPE_HEAP ||
+ (!entry->s->blob_fields &&
((ALIGN_SIZE(reclength) + HASH_OVERHEAD) * entry->file->records <
thd->variables.sortbuff_size)))
error=remove_dup_with_hash_index(join->thd, entry,
@@ -7701,7 +11164,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
char *org_record,*new_record;
byte *record;
int error;
- ulong reclength=table->reclength-offset;
+ ulong reclength= table->s->reclength-offset;
DBUG_ENTER("remove_dup_with_compare");
org_record=(char*) (record=table->record[0])+offset;
@@ -7713,7 +11176,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
{
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
error=0;
goto err;
}
@@ -7734,7 +11197,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
}
if (copy_blobs(first_field))
{
- my_error(ER_OUTOFMEMORY,MYF(0));
+ my_message(ER_OUTOFMEMORY, ER(ER_OUTOFMEMORY), MYF(0));
error=0;
goto err;
}
@@ -7837,7 +11300,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
byte *org_key_pos;
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
error=0;
goto err;
}
@@ -7956,6 +11419,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
}
if (!(cache->field=(CACHE_FIELD*)
sql_alloc(sizeof(CACHE_FIELD)*(cache->fields+table_count*2)+(blobs+1)*
+
sizeof(CACHE_FIELD*))))
{
my_free((gptr) cache->buff,MYF(0)); /* purecov: inspected */
@@ -7989,10 +11453,10 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
}
}
/* Copy null bits from table */
- if (null_fields && tables[i].table->null_fields)
+ if (null_fields && tables[i].table->s->null_fields)
{ /* must copy null bits */
copy->str=(char*) tables[i].table->null_flags;
- copy->length=tables[i].table->null_bytes;
+ copy->length= tables[i].table->s->null_bytes;
copy->strip=0;
copy->blob_field=0;
length+=copy->length;
@@ -8204,71 +11668,145 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref)
*****************************************************************************/
/*
- Find order/group item in requested columns and change the item to point at
- it. If item doesn't exists, add it first in the field list
- Return 0 if ok.
+ Resolve an ORDER BY or GROUP BY column reference.
+
+ 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
+
+ DESCRIPTION
+ Given a column reference (represented by 'order') from a GROUP BY or ORDER
+ BY clause, find the actual column it represents. If the column being
+ resolved is from the GROUP BY clause, the procedure searches the SELECT
+ list 'fields' and the columns in the FROM list 'tables'. If 'order' is from
+ the ORDER BY clause, only the SELECT list is being searched.
+
+ If 'order' is resolved to an Item, then order->item is set to the found
+ Item. If there is no item for the found column (that is, it was resolved
+ into a table field), order->item is 'fixed' and is added to all_fields and
+ ref_pointer_array.
+
+ RETURN
+ 0 if OK
+ 1 if error occurred
*/
static int
-find_order_in_list(THD *thd, Item **ref_pointer_array,
- TABLE_LIST *tables,ORDER *order, List<Item> &fields,
- List<Item> &all_fields)
+find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+ ORDER *order, List<Item> &fields, List<Item> &all_fields,
+ bool is_group_field)
{
- Item *it= *order->item;
- if (it->type() == Item::INT_ITEM)
+ Item *order_item= *order->item; /* The item from the GROUP/ORDER caluse. */
+ Item::Type order_item_type;
+ Item **select_item; /* The corresponding item from the SELECT clause. */
+ Field *from_field; /* The corresponding field from the FROM clause. */
+
+ if (order_item->type() == Item::INT_ITEM)
{ /* Order by position */
- uint count= (uint) it->val_int();
+ uint count= (uint) order_item->val_int();
if (!count || count > fields.elements)
{
- my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
- MYF(0), it->full_name(), thd->where);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0),
+ order_item->full_name(), thd->where);
return 1;
}
- order->item= ref_pointer_array + count-1;
+ order->item= ref_pointer_array + count - 1;
order->in_field_list= 1;
+ order->counter= count;
+ order->counter_used= 1;
return 0;
}
+ /* Lookup the current GROUP/ORDER field in the SELECT clause. */
uint counter;
bool unaliased;
- Item **item= find_item_in_list(it, fields, &counter,
+ select_item= find_item_in_list(order_item, fields, &counter,
REPORT_EXCEPT_NOT_FOUND, &unaliased);
- if (!item)
- return 1;
+ if (!select_item)
+ return 1; /* Some error occured. */
+
- if (item != (Item **)not_found_item)
+ /* Check whether the resolved field is not ambiguos. */
+ if (select_item != not_found_item)
{
+ Item *view_ref= NULL;
/*
If we have found field not by its alias in select list but by its
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 && !it->fixed && it->fix_fields(thd, tables, order->item))
+ if (unaliased && !order_item->fixed && order_item->fix_fields(thd, tables,
+ order->item))
return 1;
- order->item= ref_pointer_array + counter;
- order->in_field_list=1;
- return 0;
+ /* Lookup the current GROUP field in the FROM clause. */
+ order_item_type= order_item->type();
+ 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;
+ }
+ 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 &&
+ ((Item_field*) (*select_item))->field->eq(from_field)) :
+ /*
+ in is field of view table => check that references on translation
+ table are same
+ */
+ ((*select_item)->type() == Item::REF_ITEM &&
+ 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.
+ */
+ {
+ order->item= ref_pointer_array + counter;
+ order->in_field_list=1;
+ return 0;
+ }
}
order->in_field_list=0;
/*
- We check it->fixed because Item_func_group_concat can put
+ We check order_item->fixed because Item_func_group_concat can put
arguments for which fix_fields already was called.
'it' reassigned in if condition because fix_field can change it.
*/
- if (!it->fixed &&
- (it->fix_fields(thd, tables, order->item) ||
- (it= *order->item)->check_cols(1) ||
+ if (!order_item->fixed &&
+ (order_item->fix_fields(thd, tables, order->item) ||
+ (order_item= *order->item)->check_cols(1) ||
thd->is_fatal_error))
return 1; // Wrong field
uint el= all_fields.elements;
- all_fields.push_front(it); // Add new field to field list
- ref_pointer_array[el]= it;
+ all_fields.push_front(order_item); // Add new field to field list
+ ref_pointer_array[el]= order_item;
order->item= ref_pointer_array + el;
return 0;
}
+
/*
Change order to point at item in select list. If item isn't a number
and doesn't exits in the select list, add it the the field list.
@@ -8281,7 +11819,7 @@ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
for (; order; order=order->next)
{
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
- all_fields))
+ all_fields, FALSE))
return 1;
}
return 0;
@@ -8295,7 +11833,7 @@ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
setup_group()
thd Thread handler
ref_pointer_array We store references to all fields that was not in
- 'fields' here.
+ 'fields' here.
fields All fields in the select part. Any item in 'order'
that is part of these list is replaced by a pointer
to this fields.
@@ -8333,13 +11871,12 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
for (; order; order=order->next)
{
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
- all_fields))
+ all_fields, TRUE))
return 1;
(*order->item)->marker=1; /* Mark found */
if ((*order->item)->with_sum_func)
{
- my_printf_error(ER_WRONG_GROUP_FIELD, ER(ER_WRONG_GROUP_FIELD),MYF(0),
- (*order->item)->full_name());
+ my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*order->item)->full_name());
return 1;
}
}
@@ -8354,9 +11891,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
if (item->type() != Item::SUM_FUNC_ITEM && !item->marker &&
!item->const_item())
{
- my_printf_error(ER_WRONG_FIELD_WITH_GROUP,
- ER(ER_WRONG_FIELD_WITH_GROUP),
- MYF(0),item->full_name());
+ my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), item->full_name());
return 1;
}
}
@@ -8544,7 +12079,7 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)))
DBUG_RETURN(0);
- for (; !(map & tables->table->map) ; tables=tables->next) ;
+ for (; !(map & tables->table->map); tables= tables->next_leaf);
if (map != tables->table->map)
DBUG_RETURN(0); // More than one table
DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr));
@@ -8563,22 +12098,47 @@ calc_group_buffer(JOIN *join,ORDER *group)
join->group= 1;
for (; group ; group=group->next)
{
- Field *field=(*group->item)->get_tmp_table_field();
+ Item *group_item= *group->item;
+ Field *field= group_item->get_tmp_table_field();
if (field)
{
if (field->type() == FIELD_TYPE_BLOB)
key_length+=MAX_BLOB_WIDTH; // Can't be used as a key
+ else if (field->type() == MYSQL_TYPE_VARCHAR)
+ key_length+= field->field_length + HA_KEY_BLOB_LENGTH;
else
- key_length+=field->pack_length();
+ key_length+= field->pack_length();
}
- else if ((*group->item)->result_type() == REAL_RESULT)
- key_length+=sizeof(double);
- else if ((*group->item)->result_type() == INT_RESULT)
- key_length+=sizeof(longlong);
else
- key_length+=(*group->item)->max_length;
+ {
+ switch (group_item->result_type()) {
+ case REAL_RESULT:
+ key_length+= sizeof(double);
+ break;
+ case INT_RESULT:
+ key_length+= sizeof(longlong);
+ break;
+ case DECIMAL_RESULT:
+ key_length+= my_decimal_get_binary_size(group_item->max_length -
+ (group_item->decimals ? 1 : 0),
+ group_item->decimals);
+ break;
+ case STRING_RESULT:
+ /*
+ Group strings are taken as varstrings and require an length field.
+ A field is not yet created by create_tmp_field()
+ and the sizes should match up.
+ */
+ key_length+= group_item->max_length + HA_KEY_BLOB_LENGTH;
+ break;
+ default:
+ /* This case should never be choosen */
+ DBUG_ASSERT(0);
+ join->thd->fatal_error();
+ }
+ }
parts++;
- if ((*group->item)->maybe_null)
+ if (group_item->maybe_null)
null_parts++;
}
join->tmp_table_param.group_length=key_length+null_parts;
@@ -8859,9 +12419,7 @@ bool JOIN::alloc_func_list()
field_list All items
send_fields Items in select list
before_group_by Set to 1 if this is called before GROUP BY handling
-
- NOTES
- Calls ::setup() for all item_sum objects in field_list
+ recompute Set to TRUE if sum_funcs must be recomputed
RETURN
0 ok
@@ -8869,23 +12427,21 @@ bool JOIN::alloc_func_list()
*/
bool JOIN::make_sum_func_list(List<Item> &field_list, List<Item> &send_fields,
- bool before_group_by)
+ bool before_group_by, bool recompute)
{
List_iterator_fast<Item> it(field_list);
Item_sum **func;
Item *item;
DBUG_ENTER("make_sum_func_list");
+ if (*sum_funcs && !recompute)
+ DBUG_RETURN(FALSE); /* We have already initialized sum_funcs. */
+
func= sum_funcs;
while ((item=it++))
{
if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
- {
*func++= (Item_sum*) item;
- /* let COUNT(DISTINCT) create the temporary table */
- if (((Item_sum*) item)->setup(thd))
- DBUG_RETURN(TRUE);
- }
}
if (before_group_by && rollup.state == ROLLUP::STATE_INITED)
{
@@ -8928,6 +12484,8 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
{
List_iterator_fast<Item> it(all_fields);
Item *item_field,*item;
+ DBUG_ENTER("change_to_use_tmp_fields");
+
res_selected_fields.empty();
res_all_fields.empty();
@@ -8951,8 +12509,8 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
else
item_field= (Item*) new Item_field(field);
if (!item_field)
- return TRUE; // Fatal error
- item_field->name= item->name; /*lint -e613 */
+ DBUG_RETURN(TRUE); // Fatal error
+ item_field->name= item->name;
#ifndef DBUG_OFF
if (_db_on_ && !item_field->name)
{
@@ -8976,7 +12534,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
for (i= 0; i < border; i++)
itr++;
itr.sublist(res_selected_fields, elements);
- return FALSE;
+ DBUG_RETURN(FALSE);
}
@@ -9030,6 +12588,31 @@ change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array,
Code for calculating functions
******************************************************************************/
+
+/*
+ Call ::setup for all sum functions
+
+ SYNOPSIS
+ setup_sum_funcs()
+ thd thread handler
+ func_ptr sum function list
+
+ RETURN
+ FALSE ok
+ TRUE error
+*/
+
+static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr)
+{
+ Item_sum *func;
+ DBUG_ENTER("setup_sum_funcs");
+ while ((func= *(func_ptr++)))
+ if (func->setup(thd))
+ DBUG_RETURN(TRUE);
+ DBUG_RETURN(FALSE);
+}
+
+
static void
init_tmptable_sum_functions(Item_sum **func_ptr)
{
@@ -9135,7 +12718,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
error=(int) cond->add(join_tab->select->cond);
join_tab->select_cond=join_tab->select->cond=cond;
}
- else if ((join_tab->select=make_select(join_tab->table, 0, 0, cond,&error)))
+ else if ((join_tab->select= make_select(join_tab->table, 0, 0, cond, 0,
+ &error)))
join_tab->select_cond=cond;
DBUG_RETURN(error ? TRUE : FALSE);
@@ -9325,12 +12909,16 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &sel_fields,
{
if (*group_tmp->item == item)
{
+ Item_null_result *null_item;
/*
This is an element that is used by the GROUP BY and should be
set to NULL in this level
*/
item->maybe_null= 1; // Value will be null sometimes
- Item_null_result *null_item= rollup.null_items[i];
+ null_item= rollup.null_items[i];
+ DBUG_ASSERT(null_item->result_field == 0 ||
+ null_item->result_field ==
+ ((Item_field *) item)->result_field);
null_item->result_field= ((Item_field *) item)->result_field;
item= null_item;
break;
@@ -9480,6 +13068,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
select_result *result=join->result;
Item *item_null= new Item_null();
CHARSET_INFO *cs= system_charset_info;
+ int quick_type;
DBUG_ENTER("select_describe");
DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
(ulong)join->select_lex, join->select_lex->type,
@@ -9571,14 +13160,20 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
JOIN_TAB *tab=join->join_tab+i;
TABLE *table=tab->table;
- char buff[512],*buff_ptr=buff;
- char buff1[512], buff2[512];
+ char buff[512];
+ char buff1[512], buff2[512], buff3[512];
+ char keylen_str_buf[64];
+ String extra(buff, sizeof(buff),cs);
char table_name_buffer[NAME_LEN];
String tmp1(buff1,sizeof(buff1),cs);
String tmp2(buff2,sizeof(buff2),cs);
+ String tmp3(buff3,sizeof(buff3),cs);
+ extra.length(0);
tmp1.length(0);
tmp2.length(0);
+ tmp3.length(0);
+ quick_type= -1;
item_list.empty();
/* id */
item_list.push_back(new Item_uint((uint32)
@@ -9588,7 +13183,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
strlen(join->select_lex->type),
cs));
if (tab->type == JT_ALL && tab->select && tab->select->quick)
- tab->type= JT_RANGE;
+ {
+ quick_type= tab->select->quick->get_type();
+ if ((quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE) ||
+ (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) ||
+ (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION))
+ tab->type = JT_INDEX_MERGE;
+ else
+ tab->type = JT_RANGE;
+ }
/* table */
if (table->derived_select_number)
{
@@ -9599,18 +13202,18 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(new Item_string(table_name_buffer, len, cs));
}
else
- item_list.push_back(new Item_string(table->table_name,
- strlen(table->table_name),
+ item_list.push_back(new Item_string(table->alias,
+ strlen(table->alias),
cs));
/* type */
item_list.push_back(new Item_string(join_type_str[tab->type],
strlen(join_type_str[tab->type]),
cs));
- uint j;
- /* possible_keys */
+ /* Build "possible_keys" value and add it to item_list */
if (!tab->keys.is_clear_all())
{
- for (j=0 ; j < table->keys ; j++)
+ uint j;
+ for (j=0 ; j < table->s->keys ; j++)
{
if (tab->keys.is_set(j))
{
@@ -9626,14 +13229,19 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
else
item_list.push_back(item_null);
- /* key key_len ref */
+
+ /* Build "key", "key_len", and "ref" values and add them to item_list */
if (tab->ref.key_parts)
{
KEY *key_info=table->key_info+ tab->ref.key;
+ register uint length;
item_list.push_back(new Item_string(key_info->name,
strlen(key_info->name),
system_charset_info));
- item_list.push_back(new Item_int((int32) tab->ref.key_length));
+ length= longlong2str(tab->ref.key_length, keylen_str_buf, 10) -
+ keylen_str_buf;
+ item_list.push_back(new Item_string(keylen_str_buf, length,
+ system_charset_info));
for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
{
if (tmp2.length())
@@ -9646,18 +13254,21 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
else if (tab->type == JT_NEXT)
{
KEY *key_info=table->key_info+ tab->index;
+ register uint length;
item_list.push_back(new Item_string(key_info->name,
strlen(key_info->name),cs));
- item_list.push_back(new Item_int((int32) key_info->key_length));
+ length= longlong2str(key_info->key_length, keylen_str_buf, 10) -
+ keylen_str_buf;
+ item_list.push_back(new Item_string(keylen_str_buf,
+ length,
+ system_charset_info));
item_list.push_back(item_null);
}
else if (tab->select && tab->select->quick)
{
- KEY *key_info=table->key_info+ tab->select->quick->index;
- item_list.push_back(new Item_string(key_info->name,
- strlen(key_info->name),cs));
- item_list.push_back(new Item_int((int32) tab->select->quick->
- max_used_key_length));
+ tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3);
+ item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
+ item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
item_list.push_back(item_null);
}
else
@@ -9666,52 +13277,87 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(item_null);
item_list.push_back(item_null);
}
- /* rows */
+ /* Add "rows" field to item_list. */
item_list.push_back(new Item_int((longlong) (ulonglong)
join->best_positions[i]. records_read,
21));
- /* extra */
+ /* Build "Extra" field and add it to item_list. */
my_bool key_read=table->key_read;
if ((tab->type == JT_NEXT || tab->type == JT_CONST) &&
table->used_keys.is_set(tab->index))
key_read=1;
-
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&
+ !((QUICK_ROR_INTERSECT_SELECT*)tab->select->quick)->need_to_fetch_row)
+ key_read=1;
+
if (tab->info)
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
else
{
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
+ {
+ extra.append("; Using ");
+ tab->select->quick->add_info_string(&extra);
+ }
if (tab->select)
{
if (tab->use_quick == 2)
{
char buf[MAX_KEY/8+1];
- sprintf(buff_ptr,"; Range checked for each record (index map: 0x%s)",
- tab->keys.print(buf));
- buff_ptr=strend(buff_ptr);
+ extra.append("; Range checked for each record (index map: 0x");
+ extra.append(tab->keys.print(buf));
+ extra.append(')');
}
- else
- buff_ptr=strmov(buff_ptr,"; Using where");
+ else if (tab->select->cond)
+ {
+ const COND *pushed_cond= tab->table->file->pushed_cond;
+
+ if (thd->variables.engine_condition_pushdown && pushed_cond)
+ {
+ extra.append("; Using where with pushed condition");
+ if (thd->lex->describe & DESCRIBE_EXTENDED)
+ {
+ extra.append(": ");
+ ((COND *)pushed_cond)->print(&extra);
+ }
+ }
+ else
+ extra.append("; Using where");
+ }
}
if (key_read)
- buff_ptr= strmov(buff_ptr,"; Using index");
+ {
+ if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
+ extra.append("; Using index for group-by");
+ else
+ extra.append("; Using index");
+ }
if (table->reginfo.not_exists_optimize)
- buff_ptr= strmov(buff_ptr,"; Not exists");
+ extra.append("; Not exists");
if (need_tmp_table)
{
need_tmp_table=0;
- buff_ptr= strmov(buff_ptr,"; Using temporary");
+ extra.append("; Using temporary");
}
if (need_order)
{
need_order=0;
- buff_ptr= strmov(buff_ptr,"; Using filesort");
+ extra.append("; Using filesort");
}
if (distinct & test_all_bits(used_tables,thd->used_tables))
- buff_ptr= strmov(buff_ptr,"; Distinct");
- if (buff_ptr == buff)
- buff_ptr+= 2; // Skip inital "; "
- item_list.push_back(new Item_string(buff+2,(uint) (buff_ptr - buff)-2,
- cs));
+ extra.append("; Distinct");
+
+ /* Skip initial "; "*/
+ const char *str= extra.ptr();
+ uint32 len= extra.length();
+ if (len)
+ {
+ str += 2;
+ len -= 2;
+ }
+ item_list.push_back(new Item_string(str, len, cs));
}
// For next iteration
used_tables|=table->map;
@@ -9730,10 +13376,10 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
-int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
+bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
{
DBUG_ENTER("mysql_explain_union");
- int res= 0;
+ bool res= 0;
SELECT_LEX *first= unit->first_select();
for (SELECT_LEX *sl= first;
@@ -9771,6 +13417,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
else
{
thd->lex->current_select= first;
+ unit->set_limit(unit->global_parameters, first);
res= mysql_select(thd, &first->ref_pointer_array,
(TABLE_LIST*) first->table_list.first,
first->with_wild, first->item_list,
@@ -9784,20 +13431,123 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
first->options | thd->options | SELECT_DESCRIBE,
result, unit, first);
}
- if (res > 0 || thd->net.report_error)
- res= -1; // mysql_explain_select do not report error
- DBUG_RETURN(res);
+ DBUG_RETURN(res || thd->net.report_error);
+}
+
+
+/*
+ Print joins from the FROM clause
+
+ SYNOPSIS
+ print_join()
+ thd thread handler
+ str string where table should be printed
+ tables list of tables in join
+*/
+
+static void print_join(THD *thd, String *str, List<TABLE_LIST> *tables)
+{
+ /* List is reversed => we should reverse it before using */
+ List_iterator_fast<TABLE_LIST> ti(*tables);
+ TABLE_LIST **table= (TABLE_LIST **)thd->alloc(sizeof(TABLE_LIST*) *
+ tables->elements);
+ if (table == 0)
+ return; // out of memory
+
+ for (TABLE_LIST **t= table + (tables->elements - 1); t >= table; t--)
+ *t= ti++;
+
+ DBUG_ASSERT(tables->elements >= 1);
+ (*table)->print(thd, str);
+
+ TABLE_LIST **end= table + tables->elements;
+ for(TABLE_LIST **tbl= table + 1; tbl < end; tbl++)
+ {
+ TABLE_LIST *curr= *tbl;
+ if (curr->outer_join)
+ str->append(" left join ", 11); // MySQL converts right to left joins
+ else if (curr->straight)
+ str->append(" straight_join ", 15);
+ else
+ str->append(" join ", 6);
+ curr->print(thd, str);
+ if (curr->on_expr)
+ {
+ str->append(" on(", 4);
+ curr->on_expr->print(str);
+ str->append(')');
+ }
+ }
+}
+
+
+/*
+ Print table as it should be in join list
+
+ SYNOPSIS
+ st_table_list::print();
+ str string where table should bbe printed
+*/
+
+void st_table_list::print(THD *thd, String *str)
+{
+ if (nested_join)
+ {
+ str->append('(');
+ print_join(thd, str, &nested_join->join_list);
+ str->append(')');
+ }
+ else
+ {
+ const char *cmp_name; // Name to compare with alias
+ if (view_name.str)
+ {
+ append_identifier(thd, str, view_db.str, view_db.length);
+ str->append('.');
+ append_identifier(thd, str, view_name.str, view_name.length);
+ cmp_name= view_name.str;
+ }
+ else if (derived)
+ {
+ str->append('(');
+ derived->print(str);
+ str->append(')');
+ cmp_name= ""; // Force printing of alias
+ }
+ else
+ {
+ append_identifier(thd, str, db, db_length);
+ str->append('.');
+ if (schema_table)
+ {
+ append_identifier(thd, str, schema_table_name,
+ strlen(schema_table_name));
+ cmp_name= schema_table_name;
+ }
+ else
+ {
+ append_identifier(thd, str, table_name, table_name_length);
+ cmp_name= table_name;
+ }
+ }
+ if (my_strcasecmp(table_alias_charset, cmp_name, alias))
+ {
+ str->append(' ');
+ append_identifier(thd, str, alias, strlen(alias));
+ }
+ }
}
void st_select_lex::print(THD *thd, String *str)
{
+ /* QQ: thd may not be set for sub queries, but this should be fixed */
if (!thd)
thd= current_thd;
str->append("select ", 7);
-
- //options
+
+ /* First add options */
if (options & SELECT_STRAIGHT_JOIN)
str->append("straight_join ", 14);
if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) &&
@@ -9838,60 +13588,8 @@ void st_select_lex::print(THD *thd, String *str)
if (table_list.elements)
{
str->append(" from ", 6);
- Item *next_on= 0;
- for (TABLE_LIST *table= (TABLE_LIST *) table_list.first;
- table;
- table= table->next)
- {
- if (table->derived)
- {
- str->append('(');
- table->derived->print(str);
- str->append(") ");
- str->append(table->alias);
- }
- else
- {
- str->append(table->db);
- str->append('.');
- str->append(table->real_name);
- if (my_strcasecmp(table_alias_charset, table->real_name, table->alias))
- {
- str->append(' ');
- str->append(table->alias);
- }
- }
-
- if (table->on_expr && ((table->outer_join & JOIN_TYPE_LEFT) ||
- !(table->outer_join & JOIN_TYPE_RIGHT)))
- next_on= table->on_expr;
-
- if (next_on)
- {
- str->append(" on(", 4);
- next_on->print(str);
- str->append(')');
- next_on= 0;
- }
-
- TABLE_LIST *next_table;
- if ((next_table= table->next))
- {
- if (table->outer_join & JOIN_TYPE_RIGHT)
- {
- str->append(" right join ", 12);
- if (!(table->outer_join & JOIN_TYPE_LEFT) &&
- table->on_expr)
- next_on= table->on_expr;
- }
- else if (next_table->straight)
- str->append(" straight_join ", 15);
- else if (next_table->outer_join & JOIN_TYPE_LEFT)
- str->append(" left join ", 11);
- else
- str->append(" join ", 6);
- }
- }
+ /* go through join tree */
+ print_join(thd, str, &top_join_list);
}
// Where
@@ -9954,17 +13652,18 @@ void st_select_lex::print(THD *thd, String *str)
res new select_result object
RETURN
- 0 - OK
- -1 - error
+ FALSE - OK
+ TRUE - error
*/
-int JOIN::change_result(select_result *res)
+bool JOIN::change_result(select_result *res)
{
DBUG_ENTER("JOIN::change_result");
result= res;
- if (!procedure && result->prepare(fields_list, select_lex->master_unit()))
+ if (!procedure && (result->prepare(fields_list, select_lex->master_unit()) ||
+ result->prepare2()))
{
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index caf4574fbec..82efb62f7a3 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -85,23 +85,41 @@ typedef struct st_join_cache {
/*
** The structs which holds the join connections and join states
*/
-
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
- JT_UNIQUE_SUBQUERY, JT_INDEX_SUBQUERY};
+ JT_UNIQUE_SUBQUERY, JT_INDEX_SUBQUERY, JT_INDEX_MERGE};
class JOIN;
+enum enum_nested_loop_state
+{
+ NESTED_LOOP_KILLED= -2, NESTED_LOOP_ERROR= -1,
+ NESTED_LOOP_OK= 0, NESTED_LOOP_NO_MORE_ROWS= 1,
+ NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4
+};
+
+typedef enum_nested_loop_state
+(*Next_select_func)(JOIN *, struct st_join_table *, bool);
+typedef int (*Read_record_func)(struct st_join_table *tab);
+
+
typedef struct st_join_table {
TABLE *table;
KEYUSE *keyuse; /* pointer to first used key */
SQL_SELECT *select;
COND *select_cond;
- QUICK_SELECT *quick;
- Item *on_expr;
+ QUICK_SELECT_I *quick;
+ Item **on_expr_ref; /* pointer to the associated on expression */
+ COND_EQUAL *cond_equal; /* multiple equalities for the on expression */
+ st_join_table *first_inner; /* first inner table for including outerjoin */
+ bool found; /* true after all matches or null complement */
+ bool not_null_compl;/* true before null complement is added */
+ st_join_table *last_inner; /* last table table for embedding outer join */
+ st_join_table *first_upper; /* first inner table for embedding outer join */
+ st_join_table *first_unmatched; /* used for optimization purposes only */
const char *info;
- int (*read_first_record)(struct st_join_table *tab);
- int (*next_select)(JOIN *,struct st_join_table *,bool);
+ Read_record_func read_first_record;
+ Next_select_func next_select;
READ_RECORD read_record;
double worst_seeks;
key_map const_keys; /* Keys with constant part */
@@ -126,6 +144,7 @@ typedef struct st_join_table {
typedef struct st_position /* Used in find_best */
{
double records_read;
+ double read_time;
JOIN_TAB *table;
KEYUSE *key;
} POSITION;
@@ -143,15 +162,31 @@ typedef struct st_rollup
class JOIN :public Sql_alloc
{
public:
- JOIN_TAB *join_tab,**best_ref,**map2table;
- JOIN_TAB *join_tab_save; //saved join_tab for subquery reexecution
+ JOIN_TAB *join_tab,**best_ref;
+ JOIN_TAB **map2table; // mapping between table indexes and JOIN_TABs
+ JOIN_TAB *join_tab_save; // saved join_tab for subquery reexecution
TABLE **table,**all_tables,*sort_by_table;
uint tables,const_tables;
uint send_group_parts;
bool sort_and_group,first_record,full_join,group, no_field_update;
bool do_send_rows;
+ /*
+ TRUE when we want to resume nested loop iterations when
+ fetching data from a cursor
+ */
+ bool resume_nested_loop;
table_map const_table_map,found_const_table_map,outer_join;
ha_rows send_records,found_records,examined_rows,row_limit, select_limit;
+ /*
+ Used to fetch no more than given amount of rows per one
+ fetch operation of server side cursor.
+ The value is checked in end_send and end_send_group in fashion, similar
+ to offset_limit_cnt:
+ - fetch_limit= HA_POS_ERROR if there is no cursor.
+ - when we open a cursor, we set fetch_limit to 0,
+ - on each fetch iteration we add num_rows to fetch to fetch_limit
+ */
+ ha_rows fetch_limit;
POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1];
double best_read;
List<Item> *fields;
@@ -209,8 +244,11 @@ class JOIN :public Sql_alloc
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
COND *conds; // ---"---
Item *conds_history; // store WHERE for explain
- TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec
+ TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_select
+ List<TABLE_LIST> *join_list; // list of joined tables in reverse order
+ COND_EQUAL *cond_equal;
SQL_SELECT *select; //created in optimisation phase
+ JOIN_TAB *return_tab; //used only for outer joins
Item **ref_pointer_array; //used pointer reference for this select
// Copy of above to be used with different lists
Item **items0, **items1, **items2, **items3, **current_ref_pointer_array;
@@ -234,11 +272,14 @@ class JOIN :public Sql_alloc
table= 0;
tables= 0;
const_tables= 0;
+ join_list= 0;
sort_and_group= 0;
first_record= 0;
do_send_rows= 1;
+ resume_nested_loop= FALSE;
send_records= 0;
found_records= 0;
+ fetch_limit= HA_POS_ERROR;
examined_rows= 0;
exec_tmp_table1= 0;
exec_tmp_table2= 0;
@@ -260,15 +301,16 @@ class JOIN :public Sql_alloc
hidden_group_fields= 0; /*safety*/
buffer_result= test(select_options & OPTION_BUFFER_RESULT) &&
!test(select_options & OPTION_FOUND_ROWS);
- all_fields= fields_arg;
- fields_list= fields_arg;
error= 0;
select= 0;
+ return_tab= 0;
ref_pointer_array= items0= items1= items2= items3= 0;
ref_pointer_array_size= 0;
zero_result_cause= 0;
optimized= 0;
+ cond_equal= 0;
+ all_fields= fields_arg;
fields_list= fields_arg;
bzero((char*) &keyuse,sizeof(keyuse));
tmp_table_param.copy_field=0;
@@ -287,7 +329,7 @@ class JOIN :public Sql_alloc
void restore_tmp();
bool alloc_func_list();
bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
- bool before_group_by);
+ bool before_group_by, bool recompute= FALSE);
inline void set_items_ref_array(Item **ptr)
{
@@ -315,7 +357,45 @@ class JOIN :public Sql_alloc
return (do_send_rows && tmp_table_param.sum_func_count != 0 &&
!group_list);
}
- int change_result(select_result *result);
+ bool change_result(select_result *result);
+};
+
+
+/*
+ Server-side cursor (now stands only for basic read-only cursor)
+ See class implementation in sql_select.cc
+*/
+
+class Cursor: public Sql_alloc, public Item_arena
+{
+ JOIN *join;
+ SELECT_LEX_UNIT *unit;
+
+ TABLE *open_tables;
+ MYSQL_LOCK *lock;
+ TABLE *derived_tables;
+ /* List of items created during execution */
+ query_id_t query_id;
+public:
+ select_send result;
+
+ /* Temporary implementation as now we replace THD state by value */
+ /* Save THD state into cursor */
+ void init_from_thd(THD *thd);
+ /* Restore THD from cursor to continue cursor execution */
+ void init_thd(THD *thd);
+ /* bzero cursor state in THD */
+ void reset_thd(THD *thd);
+
+ int open(JOIN *join);
+ void fetch(ulong num_rows);
+ void reset() { join= 0; }
+ bool is_open() const { return join != 0; }
+ void close();
+
+ void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
+ Cursor() :Item_arena(TRUE), join(0), unit(0) {}
+ ~Cursor();
};
@@ -332,6 +412,7 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
ulong select_options, ha_rows rows_limit,
char* alias);
+TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
@@ -343,10 +424,18 @@ void copy_fields(TMP_TABLE_PARAM *param);
void copy_funcs(Item **func_ptr);
bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
int error, bool ignore_last_dupp_error);
-
+uint find_shortest_key(TABLE *table, const key_map *usable_keys);
+Field* create_tmp_field_from_field(THD *thd, Field* org_field,
+ const char *name, TABLE *table,
+ Item_field *item, uint convert_blob_length);
+
/* functions from opt_sum.cc */
+bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
+/* from sql_delete.cc, used by opt_range.cc */
+extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b);
+
/* class to copying an field/item to a key struct */
class store_key :public Sql_alloc
@@ -360,15 +449,15 @@ class store_key :public Sql_alloc
:null_ptr(null),err(0)
{
if (field_arg->type() == FIELD_TYPE_BLOB)
- to_field=new Field_varstring(ptr, length, (uchar*) null, 1,
+ {
+ /* Key segments are always packed with a 2 byte length prefix */
+ to_field=new Field_varstring(ptr, length, 2, (uchar*) null, 1,
Field::NONE, field_arg->field_name,
field_arg->table, field_arg->charset());
- else
- {
- to_field=field_arg->new_field(thd->mem_root,field_arg->table);
- if (to_field)
- to_field->move_field(ptr, (uchar*) null, 1);
}
+ else
+ to_field=field_arg->new_key_field(thd->mem_root, field_arg->table,
+ ptr, (uchar*) null, 1);
}
virtual ~store_key() {} /* Not actually needed */
virtual bool copy()=0;
@@ -414,7 +503,7 @@ public:
{}
bool copy()
{
- return item->save_in_field(to_field, 1) || err != 0;
+ return item->save_in_field_no_warnings(to_field, 1) || err != 0;
}
const char *name() const { return "func"; }
};
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 7e0ee0dab68..d6027699257 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -20,6 +20,7 @@
#include "mysql_priv.h"
#include "sql_select.h" // For select_describe
#include "repl_failsafe.h"
+#include "sp_head.h"
#include <my_dir.h>
#ifdef HAVE_BERKELEY_DB
@@ -37,141 +38,17 @@ static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
#endif
static int
-store_create_info(THD *thd, TABLE *table, String *packet);
-
-
-/*
- Report list of databases
- A database is a directory in the mysql_data_home directory
-*/
-
-int
-mysqld_show_dbs(THD *thd,const char *wild)
-{
- Item_string *field=new Item_string("",0,thd->charset());
- List<Item> field_list;
- char *end;
- List<char> files;
- char *file_name;
- Protocol *protocol= thd->protocol;
- DBUG_ENTER("mysqld_show_dbs");
-
- field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0));
- field->max_length=NAME_LEN;
- end=strmov(field->name,"Database");
- if (wild && wild[0])
- strxmov(end," (",wild,")",NullS);
- field_list.push_back(field);
-
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
- if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
- DBUG_RETURN(1);
- List_iterator_fast<char> it(files);
-
- while ((file_name=it++))
- {
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
- acl_get(thd->host, thd->ip, thd->priv_user, file_name,0) ||
- (grant_option && !check_grant_db(thd, file_name)))
-#endif
- {
- protocol->prepare_for_resend();
- protocol->store(file_name, system_charset_info);
- if (protocol->write())
- DBUG_RETURN(-1);
- }
- }
- send_eof(thd);
- DBUG_RETURN(0);
-}
-
-
-/***************************************************************************
- List all open tables in a database
-***************************************************************************/
-
-int mysqld_show_open_tables(THD *thd,const char *wild)
-{
- List<Item> field_list;
- OPEN_TABLE_LIST *open_list;
- Protocol *protocol= thd->protocol;
- DBUG_ENTER("mysqld_show_open_tables");
-
- field_list.push_back(new Item_empty_string("Database",NAME_LEN));
- field_list.push_back(new Item_empty_string("Table",NAME_LEN));
- field_list.push_back(new Item_return_int("In_use", 1, MYSQL_TYPE_TINY));
- field_list.push_back(new Item_return_int("Name_locked", 4, MYSQL_TYPE_TINY));
-
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
-
- if (!(open_list=list_open_tables(thd,wild)) && thd->is_fatal_error)
- DBUG_RETURN(-1);
-
- for (; open_list ; open_list=open_list->next)
- {
- protocol->prepare_for_resend();
- protocol->store(open_list->db, system_charset_info);
- protocol->store(open_list->table, system_charset_info);
- protocol->store_tiny((longlong) open_list->in_use);
- protocol->store_tiny((longlong) open_list->locked);
- if (protocol->write())
- {
- DBUG_RETURN(-1);
- }
- }
- send_eof(thd);
- DBUG_RETURN(0);
-}
+store_create_info(THD *thd, TABLE_LIST *table_list, String *packet);
+static int
+view_store_create_info(THD *thd, TABLE_LIST *table, String *packet);
+static bool schema_table_store_record(THD *thd, TABLE *table);
/***************************************************************************
-** List all tables in a database (fast version)
-** A table is a .frm file in the current databasedir
-***************************************************************************/
-
-int mysqld_show_tables(THD *thd,const char *db,const char *wild)
-{
- Item_string *field=new Item_string("",0,thd->charset());
- List<Item> field_list;
- char path[FN_LEN],*end;
- List<char> files;
- char *file_name;
- Protocol *protocol= thd->protocol;
- DBUG_ENTER("mysqld_show_tables");
-
- field->name=(char*) thd->alloc(20+(uint) strlen(db)+
- (wild ? (uint) strlen(wild)+4:0));
- end=strxmov(field->name,"Tables_in_",db,NullS);
- if (wild && wild[0])
- strxmov(end," (",wild,")",NullS);
- field->max_length=NAME_LEN;
- (void) sprintf(path,"%s/%s",mysql_data_home,db);
- (void) unpack_dirname(path,path);
- field_list.push_back(field);
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
- if (mysql_find_files(thd,&files,db,path,wild,0))
- DBUG_RETURN(-1);
- List_iterator_fast<char> it(files);
- while ((file_name=it++))
- {
- protocol->prepare_for_resend();
- protocol->store(file_name, system_charset_info);
- if (protocol->write())
- DBUG_RETURN(-1);
- }
- send_eof(thd);
- DBUG_RETURN(0);
-}
-
-/***************************************************************************
** List all table types supported
***************************************************************************/
-int mysqld_show_storage_engines(THD *thd)
+bool mysqld_show_storage_engines(THD *thd)
{
List<Item> field_list;
Protocol *protocol= thd->protocol;
@@ -181,8 +58,9 @@ int mysqld_show_storage_engines(THD *thd)
field_list.push_back(new Item_empty_string("Support",10));
field_list.push_back(new Item_empty_string("Comment",80));
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
const char *default_type_name=
ha_get_storage_engine((enum db_type)thd->variables.table_type);
@@ -200,10 +78,10 @@ int mysqld_show_storage_engines(THD *thd)
protocol->store(option_name, system_charset_info);
protocol->store(types->comment, system_charset_info);
if (protocol->write())
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -220,12 +98,17 @@ struct show_privileges_st {
static struct show_privileges_st sys_privileges[]=
{
{"Alter", "Tables", "To alter the table"},
- {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
+ {"Alter routine", "Functions,Procedures", "To alter or drop stored functions/procedures"},
{"Create", "Databases,Tables,Indexes", "To create new databases and tables"},
+ {"Create routine","Functions,Procedures","To use CREATE FUNCTION/PROCEDURE"},
+ {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
+ {"Create view", "Tables", "To create new views"},
+ {"Create user", "Server Admin", "To create new users"},
{"Delete", "Tables", "To delete existing rows"},
- {"Drop", "Databases,Tables", "To drop databases and tables"},
+ {"Drop", "Databases,Tables", "To drop databases, tables, and views"},
+ {"Execute", "Functions,Procedures", "To execute stored routines"},
{"File", "File access on server", "To read and write files on the server"},
- {"Grant option", "Databases,Tables", "To give to other users those privileges you possess"},
+ {"Grant option", "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"},
{"Index", "Tables", "To create or drop indexes"},
{"Insert", "Tables", "To insert data into tables"},
{"Lock tables","Databases","To use LOCK TABLES (together with SELECT privilege)"},
@@ -236,14 +119,15 @@ static struct show_privileges_st sys_privileges[]=
{"Replication slave","Server Admin","To read binary log events from the master"},
{"Select", "Tables", "To retrieve rows from table"},
{"Show databases","Server Admin","To see all databases with SHOW DATABASES"},
- {"Shutdown","Server Admin", "To shutdown the server"},
+ {"Show view","Tables","To see views with SHOW CREATE VIEW"},
+ {"Shutdown","Server Admin", "To shut down the server"},
{"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
{"Update", "Tables", "To update existing rows"},
{"Usage","Server Admin","No privileges - allow connect only"},
{NullS, NullS, NullS}
};
-int mysqld_show_privileges(THD *thd)
+bool mysqld_show_privileges(THD *thd)
{
List<Item> field_list;
Protocol *protocol= thd->protocol;
@@ -253,8 +137,9 @@ int mysqld_show_privileges(THD *thd)
field_list.push_back(new Item_empty_string("Context",15));
field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
show_privileges_st *privilege= sys_privileges;
for (privilege= sys_privileges; privilege->privilege ; privilege++)
@@ -264,10 +149,10 @@ int mysqld_show_privileges(THD *thd)
protocol->store(privilege->context, system_charset_info);
protocol->store(privilege->comment, system_charset_info);
if (protocol->write())
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -307,7 +192,7 @@ static struct show_column_type_st sys_column_types[]=
"A very small integer"},
};
-int mysqld_show_column_types(THD *thd)
+bool mysqld_show_column_types(THD *thd)
{
List<Item> field_list;
Protocol *protocol= thd->protocol;
@@ -328,8 +213,9 @@ int mysqld_show_column_types(THD *thd)
field_list.push_back(new Item_empty_string("Default",NAME_LEN));
field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
/* TODO: Change the loop to not use 'i' */
for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
@@ -350,10 +236,10 @@ int mysqld_show_column_types(THD *thd)
protocol->store(sys_column_types[i].default_value, system_charset_info);
protocol->store(sys_column_types[i].comment, system_charset_info);
if (protocol->write())
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -427,7 +313,9 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
if (db && !(col_access & TABLE_ACLS))
{
table_list.db= (char*) db;
- table_list.real_name=file->name;
+ table_list.db_length= strlen(db);
+ table_list.table_name= file->name;
+ table_list.table_name_length= strlen(file->name);
table_list.grant.privilege=col_access;
if (check_grant(thd, TABLE_ACLS, &table_list, 1, UINT_MAX, 1))
continue;
@@ -448,358 +336,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
}
-/***************************************************************************
- Extended version of mysqld_show_tables
-***************************************************************************/
-
-int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
-{
- Item *item;
- List<char> files;
- List<Item> field_list;
- char path[FN_LEN];
- char *file_name;
- TABLE *table;
- Protocol *protocol= thd->protocol;
- TIME time;
- DBUG_ENTER("mysqld_extend_show_tables");
-
- (void) sprintf(path,"%s/%s",mysql_data_home,db);
- (void) unpack_dirname(path,path);
- field_list.push_back(item=new Item_empty_string("Name",NAME_LEN));
- field_list.push_back(item=new Item_empty_string("Engine",10));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Version", (longlong) 0, 21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("Row_format",10));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Rows",(longlong) 1,21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Avg_row_length",(int32) 0,21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Data_length",(longlong) 1,21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Max_data_length",(longlong) 1,21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Index_length",(longlong) 1,21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Data_free",(longlong) 1,21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Auto_increment",(longlong) 1,21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_datetime("Create_time"));
- item->maybe_null=1;
- field_list.push_back(item=new Item_datetime("Update_time"));
- item->maybe_null=1;
- field_list.push_back(item=new Item_datetime("Check_time"));
- item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("Collation",32));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("Create_options",255));
- item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("Comment",80));
- item->maybe_null=1;
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
-
- if (mysql_find_files(thd,&files,db,path,wild,0))
- DBUG_RETURN(-1);
- List_iterator_fast<char> it(files);
- while ((file_name=it++))
- {
- TABLE_LIST table_list;
- bzero((char*) &table_list,sizeof(table_list));
- protocol->prepare_for_resend();
- protocol->store(file_name, system_charset_info);
- table_list.db=(char*) db;
- table_list.real_name= table_list.alias= file_name;
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, file_name);
- if (!(table = open_ltable(thd, &table_list, TL_READ)))
- {
- for (uint i=2 ; i < field_list.elements ; i++)
- protocol->store_null();
- // Send error to Comment field
- protocol->store(thd->net.last_error, system_charset_info);
- thd->clear_error();
- }
- else
- {
- const char *str;
- handler *file=table->file;
- file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
- protocol->store(file->table_type(), system_charset_info);
- protocol->store((ulonglong) table->frm_version);
- str= ((table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ?
- "Compressed" :
- (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
- "Dynamic" : "Fixed");
- protocol->store(str, system_charset_info);
- protocol->store((ulonglong) file->records);
- protocol->store((ulonglong) file->mean_rec_length);
- protocol->store((ulonglong) file->data_file_length);
- if (file->max_data_file_length)
- protocol->store((ulonglong) file->max_data_file_length);
- else
- protocol->store_null();
- protocol->store((ulonglong) file->index_file_length);
- protocol->store((ulonglong) file->delete_length);
- if (table->found_next_number_field)
- {
- table->next_number_field=table->found_next_number_field;
- table->next_number_field->reset();
- file->update_auto_increment();
- protocol->store(table->next_number_field->val_int());
- table->next_number_field=0;
- }
- else
- protocol->store_null();
- if (!file->create_time)
- protocol->store_null();
- else
- {
- thd->variables.time_zone->gmt_sec_to_TIME(&time, file->create_time);
- protocol->store(&time);
- }
- if (!file->update_time)
- protocol->store_null();
- else
- {
- thd->variables.time_zone->gmt_sec_to_TIME(&time, file->update_time);
- protocol->store(&time);
- }
- if (!file->check_time)
- protocol->store_null();
- else
- {
- thd->variables.time_zone->gmt_sec_to_TIME(&time, file->check_time);
- protocol->store(&time);
- }
- str= (table->table_charset ? table->table_charset->name : "default");
- protocol->store(str, system_charset_info);
- if (file->table_flags() & HA_HAS_CHECKSUM)
- protocol->store((ulonglong)file->checksum());
- else
- protocol->store_null(); // Checksum
- {
- char option_buff[350],*ptr;
- ptr=option_buff;
- if (table->min_rows)
- {
- ptr=strmov(ptr," min_rows=");
- ptr=longlong10_to_str(table->min_rows,ptr,10);
- }
- if (table->max_rows)
- {
- ptr=strmov(ptr," max_rows=");
- ptr=longlong10_to_str(table->max_rows,ptr,10);
- }
- if (table->avg_row_length)
- {
- ptr=strmov(ptr," avg_row_length=");
- ptr=longlong10_to_str(table->avg_row_length,ptr,10);
- }
- if (table->db_create_options & HA_OPTION_PACK_KEYS)
- ptr=strmov(ptr," pack_keys=1");
- if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
- ptr=strmov(ptr," pack_keys=0");
- if (table->db_create_options & HA_OPTION_CHECKSUM)
- ptr=strmov(ptr," checksum=1");
- if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
- ptr=strmov(ptr," delay_key_write=1");
- if (table->row_type != ROW_TYPE_DEFAULT)
- ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) table->row_type],
- NullS);
- if (file->raid_type)
- {
- char buff[100];
- sprintf(buff," raid_type=%s raid_chunks=%d raid_chunksize=%ld",
- my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
- ptr=strmov(ptr,buff);
- }
- protocol->store(option_buff+1,
- (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)
- , system_charset_info);
- }
- {
- char *comment=table->file->update_table_comment(table->comment);
- protocol->store(comment, system_charset_info);
- if (comment != table->comment)
- my_free(comment,MYF(0));
- }
- close_thread_tables(thd,0);
- }
- if (protocol->write())
- DBUG_RETURN(-1);
- }
- send_eof(thd);
- DBUG_RETURN(0);
-}
-
-
-/***************************************************************************
-** List all columns in a table_list->real_name
-***************************************************************************/
-
-int
-mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
- bool verbose)
-{
- TABLE *table;
- handler *file;
- char tmp[MAX_FIELD_WIDTH];
- char tmp1[MAX_FIELD_WIDTH];
- Item *item;
- Protocol *protocol= thd->protocol;
- DBUG_ENTER("mysqld_show_fields");
- DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
- table_list->real_name));
-
- if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
- {
- send_error(thd);
- DBUG_RETURN(1);
- }
- file=table->file;
- file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- (void) get_table_grant(thd, table_list);
-#endif
- List<Item> field_list;
- field_list.push_back(new Item_empty_string("Field",NAME_LEN));
- field_list.push_back(new Item_empty_string("Type",40));
- if (verbose)
- field_list.push_back(new Item_empty_string("Collation",40));
- field_list.push_back(new Item_empty_string("Null",1));
- field_list.push_back(new Item_empty_string("Key",3));
- field_list.push_back(item=new Item_empty_string("Default",NAME_LEN));
- item->maybe_null=1;
- field_list.push_back(new Item_empty_string("Extra",20));
- if (verbose)
- {
- field_list.push_back(new Item_empty_string("Privileges",80));
- field_list.push_back(new Item_empty_string("Comment",255));
- }
- // Send first number of fields and records
- if (protocol->send_records_num(&field_list, (ulonglong)file->records) ||
- protocol->send_fields(&field_list,0))
- DBUG_RETURN(1);
- restore_record(table,default_values); // Get empty record
-
- Field **ptr,*field;
- for (ptr=table->field; (field= *ptr) ; ptr++)
- {
- if (!wild || !wild[0] ||
- !wild_case_compare(system_charset_info, field->field_name,wild))
- {
- {
- byte *pos;
- uint flags=field->flags;
- String type(tmp,sizeof(tmp), system_charset_info);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- uint col_access;
-#endif
- protocol->prepare_for_resend();
- protocol->store(field->field_name, system_charset_info);
- field->sql_type(type);
- protocol->store(type.ptr(), type.length(), system_charset_info);
- if (verbose)
- protocol->store(field->has_charset() ? field->charset()->name : "NULL",
- system_charset_info);
- /*
- Even if TIMESTAMP field can't contain NULL as its value it
- will accept NULL if you will try to insert such value and will
- convert NULL value to current TIMESTAMP. So YES here means
- that NULL is allowed for assignment (but may be won't be
- returned).
- */
- pos=(byte*) ((flags & NOT_NULL_FLAG) &&
- field->type() != FIELD_TYPE_TIMESTAMP ?
- "" : "YES");
- protocol->store((const char*) pos, system_charset_info);
- pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
- (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
- (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
- protocol->store((char*) pos, system_charset_info);
-
- if (table->timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_UN_FIELD)
- {
- /*
- We have NOW() as default value but we use CURRENT_TIMESTAMP form
- because it is more SQL standard comatible
- */
- protocol->store("CURRENT_TIMESTAMP", system_charset_info);
- }
- else if (field->unireg_check != Field::NEXT_NUMBER &&
- !field->is_null())
- { // Not null by default
- /*
- Note: we have to convert the default value into
- system_charset_info before sending.
- This is necessary for "SET NAMES binary":
- If the client character set is binary, we want to
- send metadata in UTF8 rather than in the column's
- character set.
- This conversion also makes "SHOW COLUMNS" and
- "SHOW CREATE TABLE" output consistent. Without
- this conversion the default values were displayed
- differently.
- */
- String def(tmp1,sizeof(tmp1), system_charset_info);
- type.set(tmp, sizeof(tmp), field->charset());
- field->val_str(&type);
- uint dummy_errors;
- def.copy(type.ptr(), type.length(), type.charset(),
- system_charset_info, &dummy_errors);
- protocol->store(def.ptr(), def.length(), def.charset());
- }
- else if (field->unireg_check == Field::NEXT_NUMBER ||
- field->maybe_null())
- protocol->store_null(); // Null as default
- else
- protocol->store("",0, system_charset_info); // empty string
-
- char *end=tmp;
- if (field->unireg_check == Field::NEXT_NUMBER)
- end=strmov(tmp,"auto_increment");
- protocol->store(tmp,(uint) (end-tmp), system_charset_info);
-
- if (verbose)
- {
- /* Add grant options & comments */
- end=tmp;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
- for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
- {
- if (col_access & 1)
- {
- *end++=',';
- end=strmov(end,grant_types.type_names[bitnr]);
- }
- }
-#else
- end=strmov(end,"");
-#endif
- protocol->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1),
- system_charset_info);
- protocol->store(field->comment.str, field->comment.length,
- system_charset_info);
- }
- if (protocol->write())
- DBUG_RETURN(1);
- }
- }
- }
- send_eof(thd);
- DBUG_RETURN(0);
-}
-
-
-int
+bool
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
@@ -808,38 +345,73 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
String buffer(buff, sizeof(buff), system_charset_info);
DBUG_ENTER("mysqld_show_create");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
- table_list->real_name));
+ table_list->table_name));
- /* Only one table for now */
- if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
+ /* Only one table for now, but VIEW can involve several tables */
+ if (open_and_lock_tables(thd, table_list))
{
- send_error(thd);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
+ }
+ /* TODO: add environment variables show when it become possible */
+ if (thd->lex->only_view && !table_list->view)
+ {
+ my_error(ER_WRONG_OBJECT, MYF(0),
+ table_list->db, table_list->table_name, "VIEW");
+ DBUG_RETURN(TRUE);
}
- buffer.length(0);
- if (store_create_info(thd, table, &buffer))
- DBUG_RETURN(-1);
+ table= table_list->table;
+
+ if ((table_list->view ?
+ view_store_create_info(thd, table_list, &buffer) :
+ store_create_info(thd, table_list, &buffer)))
+ DBUG_RETURN(TRUE);
List<Item> field_list;
- field_list.push_back(new Item_empty_string("Table",NAME_LEN));
- // 1024 is for not to confuse old clients
- field_list.push_back(new Item_empty_string("Create Table",
- max(buffer.length(),1024)));
+ if (table_list->view)
+ {
+ field_list.push_back(new Item_empty_string("View",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Create View",
+ max(buffer.length(),1024)));
+ }
+ else
+ {
+ field_list.push_back(new Item_empty_string("Table",NAME_LEN));
+ // 1024 is for not to confuse old clients
+ field_list.push_back(new Item_empty_string("Create Table",
+ max(buffer.length(),1024)));
+ }
- if (protocol->send_fields(&field_list, 1))
- DBUG_RETURN(1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
protocol->prepare_for_resend();
- protocol->store(table->table_name, system_charset_info);
+ buffer.length(0);
+ if (table_list->view)
+ {
+ protocol->store(table_list->view_name.str, system_charset_info);
+ if (view_store_create_info(thd, table_list, &buffer))
+ DBUG_RETURN(TRUE);
+ }
+ else
+ {
+ if (table_list->schema_table)
+ protocol->store(table_list->schema_table_name, system_charset_info);
+ else
+ protocol->store(table->alias, system_charset_info);
+ if (store_create_info(thd, table_list, &buffer))
+ DBUG_RETURN(TRUE);
+ }
protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
+
if (protocol->write())
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
-int mysqld_show_create_db(THD *thd, char *dbname,
- HA_CREATE_INFO *create_info)
+bool mysqld_show_create_db(THD *thd, char *dbname,
+ HA_CREATE_INFO *create_info)
{
int length;
char path[FN_REFLEN];
@@ -856,8 +428,8 @@ int mysqld_show_create_db(THD *thd, char *dbname,
if (check_db_name(dbname))
{
- net_printf(thd,ER_WRONG_DB_NAME, dbname);
- DBUG_RETURN(1);
+ my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
+ DBUG_RETURN(TRUE);
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -868,11 +440,11 @@ int mysqld_show_create_db(THD *thd, char *dbname,
thd->master_access);
if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
{
- net_printf(thd,ER_DBACCESS_DENIED_ERROR,
- thd->priv_user, thd->host_or_ip, dbname);
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->priv_user, thd->host_or_ip, dbname);
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
thd->priv_user, thd->host_or_ip, dbname);
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
#endif
@@ -886,8 +458,8 @@ int mysqld_show_create_db(THD *thd, char *dbname,
}
if (access(path,F_OK))
{
- net_printf(thd,ER_BAD_DB_ERROR,dbname);
- DBUG_RETURN(1);
+ my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
+ DBUG_RETURN(TRUE);
}
if (found_libchar)
path[length-1]= FN_LIBCHAR;
@@ -898,8 +470,9 @@ int mysqld_show_create_db(THD *thd, char *dbname,
field_list.push_back(new Item_empty_string("Database",NAME_LEN));
field_list.push_back(new Item_empty_string("Create Database",1024));
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
protocol->prepare_for_resend();
protocol->store(dbname, strlen(dbname), system_charset_info);
@@ -924,12 +497,12 @@ int mysqld_show_create_db(THD *thd, char *dbname,
protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
if (protocol->write())
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
-int
+bool
mysqld_show_logs(THD *thd)
{
List<Item> field_list;
@@ -940,113 +513,17 @@ mysqld_show_logs(THD *thd)
field_list.push_back(new Item_empty_string("Type",10));
field_list.push_back(new Item_empty_string("Status",10));
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
#ifdef HAVE_BERKELEY_DB
if ((have_berkeley_db == SHOW_OPTION_YES) && berkeley_show_logs(protocol))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
#endif
send_eof(thd);
- DBUG_RETURN(0);
-}
-
-
-int
-mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
-{
- TABLE *table;
- Protocol *protocol= thd->protocol;
- DBUG_ENTER("mysqld_show_keys");
- DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
- table_list->real_name));
-
- if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
- {
- send_error(thd);
- DBUG_RETURN(1);
- }
-
- List<Item> field_list;
- Item *item;
- field_list.push_back(new Item_empty_string("Table",NAME_LEN));
- field_list.push_back(new Item_return_int("Non_unique",1, MYSQL_TYPE_TINY));
- field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
- field_list.push_back(new Item_return_int("Seq_in_index",2, MYSQL_TYPE_TINY));
- field_list.push_back(new Item_empty_string("Column_name",NAME_LEN));
- field_list.push_back(item=new Item_empty_string("Collation",1));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("Cardinality",0,21));
- item->maybe_null=1;
- field_list.push_back(item=new Item_return_int("Sub_part",3,
- MYSQL_TYPE_SHORT));
- item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("Packed",10));
- item->maybe_null=1;
- field_list.push_back(new Item_empty_string("Null",3));
- field_list.push_back(new Item_empty_string("Index_type",16));
- field_list.push_back(new Item_empty_string("Comment",255));
- item->maybe_null=1;
-
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1);
-
- KEY *key_info=table->key_info;
- table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
- for (uint i=0 ; i < table->keys ; i++,key_info++)
- {
- KEY_PART_INFO *key_part= key_info->key_part;
- const char *str;
- for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
- {
- protocol->prepare_for_resend();
- protocol->store(table->table_name, system_charset_info);
- protocol->store_tiny((longlong) ((key_info->flags & HA_NOSAME) ? 0 :1));
- protocol->store(key_info->name, system_charset_info);
- protocol->store_tiny((longlong) (j+1));
- str=(key_part->field ? key_part->field->field_name :
- "?unknown field?");
- protocol->store(str, system_charset_info);
- if (table->file->index_flags(i, j, 0) & HA_READ_ORDER)
- protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ?
- "D" : "A"), 1, system_charset_info);
- else
- protocol->store_null(); /* purecov: inspected */
- KEY *key=table->key_info+i;
- if (key->rec_per_key[j])
- {
- ha_rows records=(table->file->records / key->rec_per_key[j]);
- protocol->store((ulonglong) records);
- }
- else
- protocol->store_null();
-
- /* Check if we have a key part that only uses part of the field */
- if (!(key_info->flags & HA_FULLTEXT) && (!key_part->field ||
- key_part->length != table->field[key_part->fieldnr-1]->key_length()))
- protocol->store_short((longlong) key_part->length /
- key_part->field->charset()->mbmaxlen);
- else
- protocol->store_null();
- protocol->store_null(); // No pack_information yet
-
- /* Null flag */
- uint flags= key_part->field ? key_part->field->flags : 0;
- char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
- protocol->store((const char*) pos, system_charset_info);
- protocol->store(table->file->index_type(i), system_charset_info);
- /* Comment */
- if (!table->keys_in_use.is_set(i))
- protocol->store("disabled",8, system_charset_info);
- else
- protocol->store("", 0, system_charset_info);
- if (protocol->write())
- DBUG_RETURN(1); /* purecov: inspected */
- }
- }
- send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -1060,13 +537,13 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
{
TABLE *table;
DBUG_ENTER("mysqld_list_fields");
- DBUG_PRINT("enter",("table: %s",table_list->real_name));
+ DBUG_PRINT("enter",("table: %s",table_list->table_name));
- if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
- {
- send_error(thd);
+ table_list->lock_type= TL_UNLOCK;
+ if (open_and_lock_tables(thd, table_list))
DBUG_VOID_RETURN;
- }
+ table= table_list->table;
+
List<Item> field_list;
Field **ptr,*field;
@@ -1076,8 +553,9 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
!wild_case_compare(system_charset_info, field->field_name,wild))
field_list.push_back(new Item_field(field));
}
- restore_record(table,default_values); // Get empty record
- if (thd->protocol->send_fields(&field_list,2))
+ restore_record(table, s->default_values); // Get empty record
+ if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS |
+ Protocol::SEND_EOF))
DBUG_VOID_RETURN;
thd->protocol->flush();
DBUG_VOID_RETURN;
@@ -1085,15 +563,15 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
int
-mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
+mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd)
{
Protocol *protocol= thd->protocol;
String *packet= protocol->storage_packet();
DBUG_ENTER("mysqld_dump_create_info");
- DBUG_PRINT("enter",("table: %s",table->real_name));
+ DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name));
protocol->prepare_for_resend();
- if (store_create_info(thd, table, packet))
+ if (store_create_info(thd, table_list, packet))
DBUG_RETURN(-1);
if (fd < 0)
@@ -1113,7 +591,7 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
/*
Go through all character combinations and ensure that sql_lex.cc can
- parse it as an identifer.
+ parse it as an identifier.
SYNOPSIS
require_quotes()
@@ -1228,14 +706,17 @@ static void append_directory(THD *thd, String *packet, const char *dir_type,
packet->append(dir_type);
packet->append(" DIRECTORY='", 12);
#ifdef __WIN__
- char *winfilename = thd->memdup(filename, length);
- for (uint i=0; i < length; i++)
- if (winfilename[i] == '\\')
- winfilename[i] = '/';
- packet->append(winfilename, length);
-#else
- packet->append(filename, length);
+ /* Convert \ to / to be able to create table on unix */
+ char *winfilename= (char*) thd->memdup(filename, length);
+ char *pos, *end;
+ for (pos= winfilename, end= pos+length ; pos < end ; pos++)
+ {
+ if (*pos == '\\')
+ *pos = '/';
+ }
+ filename= winfilename;
#endif
+ packet->append(filename, length);
packet->append('\'');
}
}
@@ -1244,15 +725,18 @@ static void append_directory(THD *thd, String *packet, const char *dir_type,
#define LIST_PROCESS_HOST_LEN 64
static int
-store_create_info(THD *thd, TABLE *table, String *packet)
+store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
{
List<Item> field_list;
- char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end, *alias;
+ char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end;
+ const char *alias;
String type(tmp, sizeof(tmp), system_charset_info);
Field **ptr,*field;
uint primary_key;
KEY *key_info;
+ TABLE *table= table_list->table;
handler *file= table->file;
+ TABLE_SHARE *share= table->s;
HA_CREATE_INFO create_info;
my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
MODE_ORACLE |
@@ -1263,18 +747,20 @@ store_create_info(THD *thd, TABLE *table, String *packet)
my_bool limited_mysql_mode= (thd->variables.sql_mode &
(MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
MODE_MYSQL40)) != 0;
-
DBUG_ENTER("store_create_info");
- DBUG_PRINT("enter",("table: %s",table->real_name));
+ DBUG_PRINT("enter",("table: %s", table->s->table_name));
- restore_record(table,default_values); // Get empty record
+ restore_record(table, s->default_values); // Get empty record
- if (table->tmp_table)
+ if (share->tmp_table)
packet->append("CREATE TEMPORARY TABLE ", 23);
else
packet->append("CREATE TABLE ", 13);
- alias= (lower_case_table_names == 2 ? table->table_name :
- table->real_name);
+ if (table_list->schema_table)
+ alias= table_list->schema_table_name;
+ else
+ alias= (lower_case_table_names == 2 ? table->alias :
+ share->table_name);
append_identifier(thd, packet, alias, strlen(alias));
packet->append(" (\n", 3);
@@ -1301,7 +787,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
if (field->has_charset() && !limited_mysql_mode && !foreign_db_mode)
{
- if (field->charset() != table->table_charset)
+ if (field->charset() != share->table_charset)
{
packet->append(" character set ", 15);
packet->append(field->charset()->csname);
@@ -1336,6 +822,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
field->unireg_check != Field::TIMESTAMP_UN_FIELD;
has_default= (field->type() != FIELD_TYPE_BLOB &&
+ !(field->flags & NO_DEFAULT_VALUE_FLAG) &&
field->unireg_check != Field::NEXT_NUMBER &&
!((foreign_db_mode || limited_mysql_mode) &&
has_now_default));
@@ -1386,9 +873,9 @@ store_create_info(THD *thd, TABLE *table, String *packet)
file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
bzero((char*) &create_info, sizeof(create_info));
file->update_create_info(&create_info);
- primary_key= table->primary_key;
+ primary_key= share->primary_key;
- for (uint i=0 ; i < table->keys ; i++,key_info++)
+ for (uint i=0 ; i < share->keys ; i++,key_info++)
{
KEY_PART_INFO *key_part= key_info->key_part;
bool found_primary=0;
@@ -1414,17 +901,17 @@ store_create_info(THD *thd, TABLE *table, String *packet)
!limited_mysql_mode && !foreign_db_mode)
{
if (key_info->algorithm == HA_KEY_ALG_BTREE)
- packet->append(" TYPE BTREE", 11);
-
+ packet->append(" USING BTREE", 12);
+
if (key_info->algorithm == HA_KEY_ALG_HASH)
- packet->append(" TYPE HASH", 10);
-
+ packet->append(" USING HASH", 11);
+
// +BAR: send USING only in non-default case: non-spatial rtree
if ((key_info->algorithm == HA_KEY_ALG_RTREE) &&
!(key_info->flags & HA_SPATIAL))
- packet->append(" TYPE RTREE", 11);
+ packet->append(" USING RTREE", 12);
- // No need to send TYPE FULLTEXT, it is sent as FULLTEXT KEY
+ // No need to send USING FULLTEXT, it is sent as FULLTEXT KEY
}
packet->append(" (", 2);
@@ -1472,58 +959,58 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append(" ENGINE=", 8);
packet->append(file->table_type());
- if (table->table_charset &&
+ if (share->table_charset &&
!(thd->variables.sql_mode & MODE_MYSQL323) &&
!(thd->variables.sql_mode & MODE_MYSQL40))
{
packet->append(" DEFAULT CHARSET=", 17);
- packet->append(table->table_charset->csname);
- if (!(table->table_charset->state & MY_CS_PRIMARY))
+ packet->append(share->table_charset->csname);
+ if (!(share->table_charset->state & MY_CS_PRIMARY))
{
packet->append(" COLLATE=", 9);
- packet->append(table->table_charset->name);
+ packet->append(table->s->table_charset->name);
}
}
- if (table->min_rows)
+ if (share->min_rows)
{
packet->append(" MIN_ROWS=", 10);
- end= longlong10_to_str(table->min_rows, buff, 10);
+ end= longlong10_to_str(share->min_rows, buff, 10);
packet->append(buff, (uint) (end- buff));
}
- if (table->max_rows)
+ if (share->max_rows && !table_list->schema_table)
{
packet->append(" MAX_ROWS=", 10);
- end= longlong10_to_str(table->max_rows, buff, 10);
+ end= longlong10_to_str(share->max_rows, buff, 10);
packet->append(buff, (uint) (end - buff));
}
- if (table->avg_row_length)
+ if (share->avg_row_length)
{
packet->append(" AVG_ROW_LENGTH=", 16);
- end= longlong10_to_str(table->avg_row_length, buff,10);
+ end= longlong10_to_str(share->avg_row_length, buff,10);
packet->append(buff, (uint) (end - buff));
}
- if (table->db_create_options & HA_OPTION_PACK_KEYS)
+ if (share->db_create_options & HA_OPTION_PACK_KEYS)
packet->append(" PACK_KEYS=1", 12);
- if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
+ if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
packet->append(" PACK_KEYS=0", 12);
- if (table->db_create_options & HA_OPTION_CHECKSUM)
+ if (share->db_create_options & HA_OPTION_CHECKSUM)
packet->append(" CHECKSUM=1", 11);
- if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
+ if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
packet->append(" DELAY_KEY_WRITE=1",18);
- if (table->row_type != ROW_TYPE_DEFAULT)
+ if (share->row_type != ROW_TYPE_DEFAULT)
{
packet->append(" ROW_FORMAT=",12);
- packet->append(ha_row_type[(uint) table->row_type]);
+ packet->append(ha_row_type[(uint) share->row_type]);
}
table->file->append_create_info(packet);
- if (table->comment && table->comment[0])
+ if (share->comment && share->comment[0])
{
packet->append(" COMMENT=", 9);
- append_unescaped(packet, table->comment, strlen(table->comment));
+ append_unescaped(packet, share->comment, strlen(share->comment));
}
if (file->raid_type)
{
@@ -1541,6 +1028,51 @@ store_create_info(THD *thd, TABLE *table, String *packet)
}
+static int
+view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
+{
+ my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
+ MODE_ORACLE |
+ MODE_MSSQL |
+ MODE_DB2 |
+ MODE_MAXDB |
+ MODE_ANSI)) != 0;
+ buff->append("CREATE ", 7);
+ if (!foreign_db_mode)
+ {
+ buff->append("ALGORITHM=", 10);
+ switch((int8)table->algorithm)
+ {
+ case VIEW_ALGORITHM_UNDEFINED:
+ buff->append("UNDEFINED ", 10);
+ break;
+ case VIEW_ALGORITHM_TMPTABLE:
+ buff->append("TEMPTABLE ", 10);
+ break;
+ case VIEW_ALGORITHM_MERGE:
+ buff->append("MERGE ", 6);
+ break;
+ default:
+ DBUG_ASSERT(0); // never should happen
+ }
+ }
+ buff->append("VIEW ", 5);
+ append_identifier(thd, buff, table->view_db.str, table->view_db.length);
+ 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);
+ if (table->with_check != VIEW_CHECK_NONE)
+ {
+ if (table->with_check == VIEW_CHECK_LOCAL)
+ buff->append(" WITH LOCAL CHECK OPTION", 24);
+ else
+ buff->append(" WITH CASCADED CHECK OPTION", 27);
+ }
+ return 0;
+}
+
+
/****************************************************************************
Return info about all processes
returns for each thread: thread id, user, host, db, command, info
@@ -1548,9 +1080,13 @@ store_create_info(THD *thd, TABLE *table, String *packet)
class thread_info :public ilink {
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 delete(void *ptr __attribute__((unused)),
- size_t size __attribute__((unused))) {} /*lint -e715 */
+ size_t size __attribute__((unused)))
+ { TRASH(ptr, size); }
ulong thread_id;
time_t start_time;
@@ -1584,7 +1120,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
field->maybe_null=1;
field_list.push_back(field=new Item_empty_string("Info",max_query_length));
field->maybe_null=1;
- if (protocol->send_fields(&field_list,1))
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_VOID_RETURN;
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
@@ -1617,7 +1154,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
thd_info->command=(int) tmp->command;
if ((mysys_var= tmp->mysys_var))
pthread_mutex_lock(&mysys_var->mutex);
- thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
+ thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
#ifndef EMBEDDED_LIBRARY
thd_info->state_info= (char*) (tmp->locked ? "Locked" :
tmp->net.reading_or_writing ?
@@ -1691,426 +1228,2554 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
Status functions
*****************************************************************************/
-static bool write_collation(Protocol *protocol, CHARSET_INFO *cs)
+
+static bool show_status_array(THD *thd, const char *wild,
+ show_var_st *variables,
+ enum enum_var_type value_type,
+ struct system_status_var *status_var,
+ const char *prefix, TABLE *table)
{
- protocol->prepare_for_resend();
- protocol->store(cs->name, system_charset_info);
- protocol->store(cs->csname, system_charset_info);
- protocol->store_short((longlong) cs->number);
- protocol->store((cs->state & MY_CS_PRIMARY) ? "Yes" : "",system_charset_info);
- protocol->store((cs->state & MY_CS_COMPILED)? "Yes" : "",system_charset_info);
- protocol->store_short((longlong) cs->strxfrm_multiply);
- return protocol->write();
+ char buff[1024], *prefix_end;
+ /* the variable name should not be longer then 80 characters */
+ char name_buffer[80];
+ int len;
+ LEX_STRING null_lex_str;
+ DBUG_ENTER("show_status_array");
+
+ null_lex_str.str= 0; // For sys_var->value_ptr()
+ null_lex_str.length= 0;
+
+ prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1);
+ len=name_buffer + sizeof(name_buffer) - prefix_end;
+
+ for (; variables->name; variables++)
+ {
+ strnmov(prefix_end, variables->name, len);
+ name_buffer[sizeof(name_buffer)-1]=0; /* Safety */
+ SHOW_TYPE show_type=variables->type;
+ if (show_type == SHOW_VARS)
+ {
+ show_status_array(thd, wild, (show_var_st *) variables->value,
+ value_type, status_var, variables->name, table);
+ }
+ else
+ {
+ if (!(wild && wild[0] && wild_case_compare(system_charset_info,
+ name_buffer, wild)))
+ {
+ char *value=variables->value;
+ const char *pos, *end;
+ long nr;
+ if (show_type == SHOW_SYS)
+ {
+ show_type= ((sys_var*) value)->type();
+ value= (char*) ((sys_var*) value)->value_ptr(thd, value_type,
+ &null_lex_str);
+ }
+
+ pos= end= buff;
+ switch (show_type) {
+ case SHOW_LONG_STATUS:
+ case SHOW_LONG_CONST_STATUS:
+ value= ((char *) status_var + (ulong) value);
+ /* fall through */
+ case SHOW_LONG:
+ case SHOW_LONG_CONST:
+ end= int10_to_str(*(long*) value, buff, 10);
+ break;
+ case SHOW_LONGLONG:
+ end= longlong10_to_str(*(longlong*) value, buff, 10);
+ break;
+ case SHOW_HA_ROWS:
+ end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
+ break;
+ case SHOW_BOOL:
+ end= strmov(buff, *(bool*) value ? "ON" : "OFF");
+ break;
+ case SHOW_MY_BOOL:
+ end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
+ break;
+ case SHOW_INT_CONST:
+ case SHOW_INT:
+ end= int10_to_str((long) *(uint32*) value, buff, 10);
+ break;
+ case SHOW_HAVE:
+ {
+ SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
+ pos= show_comp_option_name[(int) tmp];
+ end= strend(pos);
+ break;
+ }
+ case SHOW_CHAR:
+ {
+ if (!(pos= value))
+ pos= "";
+ end= strend(pos);
+ break;
+ }
+ case SHOW_STARTTIME:
+ nr= (long) (thd->query_start() - start_time);
+ end= int10_to_str(nr, buff, 10);
+ break;
+ case SHOW_QUESTION:
+ end= int10_to_str((long) thd->query_id, buff, 10);
+ break;
+#ifdef HAVE_REPLICATION
+ case SHOW_RPL_STATUS:
+ end= strmov(buff, rpl_status_type[(int)rpl_status]);
+ break;
+ case SHOW_SLAVE_RUNNING:
+ {
+ pthread_mutex_lock(&LOCK_active_mi);
+ end= strmov(buff, (active_mi->slave_running &&
+ active_mi->rli.slave_running) ? "ON" : "OFF");
+ pthread_mutex_unlock(&LOCK_active_mi);
+ break;
+ }
+ case SHOW_SLAVE_RETRIED_TRANS:
+ {
+ /*
+ TODO: in 5.1 with multimaster, have one such counter per line in SHOW
+ SLAVE STATUS, and have the sum over all lines here.
+ */
+ pthread_mutex_lock(&LOCK_active_mi);
+ pthread_mutex_lock(&active_mi->rli.data_lock);
+ end= int10_to_str(active_mi->rli.retried_trans, buff, 10);
+ pthread_mutex_unlock(&active_mi->rli.data_lock);
+ pthread_mutex_unlock(&LOCK_active_mi);
+ break;
+ }
+#endif /* HAVE_REPLICATION */
+ case SHOW_OPENTABLES:
+ end= int10_to_str((long) cached_tables(), buff, 10);
+ break;
+ case SHOW_CHAR_PTR:
+ {
+ if (!(pos= *(char**) value))
+ pos= "";
+ end= strend(pos);
+ break;
+ }
+ case SHOW_DOUBLE:
+ {
+ end= buff + sprintf(buff, "%f", *(double*) value);
+ break;
+ }
+#ifdef HAVE_OPENSSL
+ /* First group - functions relying on CTX */
+ case SHOW_SSL_CTX_SESS_ACCEPT:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept(ssl_acceptor_fd->
+ ssl_context)),
+ buff, 10);
+ break;
+ case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept_good(ssl_acceptor_fd->
+ ssl_context)),
+ buff, 10);
+ break;
+ case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect_good(ssl_acceptor_fd->
+ ssl_context)),
+ buff, 10);
+ break;
+ case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)),
+ buff, 10);
+ break;
+ case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)),
+ buff, 10);
+ break;
+ case SHOW_SSL_CTX_SESS_CB_HITS:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
+ ssl_context)),
+ buff, 10);
+ break;
+ case SHOW_SSL_CTX_SESS_HITS:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_hits(ssl_acceptor_fd->
+ ssl_context)),
+ buff, 10);
+ break;
+ case SHOW_SSL_CTX_SESS_CACHE_FULL:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_cache_full(ssl_acceptor_fd->
+ ssl_context)),
+ buff, 10);
+ break;
+ case SHOW_SSL_CTX_SESS_MISSES:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_misses(ssl_acceptor_fd->
+ ssl_context)),
+ buff, 10);
+ break;
+ case SHOW_SSL_CTX_SESS_TIMEOUTS:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)),
+ buff,10);
+ break;
+ case SHOW_SSL_CTX_SESS_NUMBER:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)),
+ buff,10);
+ break;
+ case SHOW_SSL_CTX_SESS_CONNECT:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)),
+ buff,10);
+ break;
+ case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)),
+ buff,10);
+ break;
+ case SHOW_SSL_CTX_GET_VERIFY_MODE:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)),
+ buff,10);
+ break;
+ case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)),
+ buff,10);
+ break;
+ case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
+ if (!ssl_acceptor_fd)
+ {
+ pos= "NONE";
+ end= pos+4;
+ break;
+ }
+ switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context))
+ {
+ case SSL_SESS_CACHE_OFF:
+ pos= "OFF";
+ break;
+ case SSL_SESS_CACHE_CLIENT:
+ pos= "CLIENT";
+ break;
+ case SSL_SESS_CACHE_SERVER:
+ pos= "SERVER";
+ break;
+ case SSL_SESS_CACHE_BOTH:
+ pos= "BOTH";
+ break;
+ case SSL_SESS_CACHE_NO_AUTO_CLEAR:
+ pos= "NO_AUTO_CLEAR";
+ break;
+ case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
+ pos= "NO_INTERNAL_LOOKUP";
+ break;
+ default:
+ pos= "Unknown";
+ break;
+ }
+ end= strend(pos);
+ break;
+ /* First group - functions relying on SSL */
+ case SHOW_SSL_GET_VERSION:
+ pos= (thd->net.vio->ssl_arg ?
+ SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
+ end= strend(pos);
+ break;
+ case SHOW_SSL_SESSION_REUSED:
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_session_reused((SSL*) thd->net.vio->
+ ssl_arg) :
+ 0),
+ buff, 10);
+ break;
+ case SHOW_SSL_GET_DEFAULT_TIMEOUT:
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_get_default_timeout((SSL*) thd->net.vio->
+ ssl_arg) :
+ 0),
+ buff, 10);
+ break;
+ case SHOW_SSL_GET_VERIFY_MODE:
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_get_verify_mode((SSL*) thd->net.vio->
+ ssl_arg):
+ 0),
+ buff, 10);
+ break;
+ case SHOW_SSL_GET_VERIFY_DEPTH:
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_get_verify_depth((SSL*) thd->net.vio->
+ ssl_arg):
+ 0),
+ buff, 10);
+ break;
+ case SHOW_SSL_GET_CIPHER:
+ pos= (thd->net.vio->ssl_arg ?
+ SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" );
+ end= strend(pos);
+ break;
+ case SHOW_SSL_GET_CIPHER_LIST:
+ if (thd->net.vio->ssl_arg)
+ {
+ char *to= buff;
+ for (int i=0 ; i++ ;)
+ {
+ const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i);
+ if (p == NULL)
+ break;
+ to= strmov(to, p);
+ *to++= ':';
+ }
+ if (to != buff)
+ to--; // Remove last ':'
+ end= to;
+ }
+ break;
+
+#endif /* HAVE_OPENSSL */
+ case SHOW_KEY_CACHE_LONG:
+ case SHOW_KEY_CACHE_CONST_LONG:
+ value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache;
+ end= int10_to_str(*(long*) value, buff, 10);
+ break;
+ case SHOW_UNDEF: // Show never happen
+ case SHOW_SYS:
+ break; // Return empty string
+ default:
+ break;
+ }
+ restore_record(table, s->default_values);
+ table->field[0]->store(name_buffer, strlen(name_buffer),
+ system_charset_info);
+ table->field[1]->store(pos, (uint32) (end - pos), system_charset_info);
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+
+ DBUG_RETURN(FALSE);
}
-int mysqld_show_collations(THD *thd, const char *wild)
+
+/* collect status for all running threads */
+
+void calc_sum_of_all_status(STATUS_VAR *to)
{
- char buff[8192];
- String packet2(buff,sizeof(buff),thd->charset());
- List<Item> field_list;
- CHARSET_INFO **cs;
- Protocol *protocol= thd->protocol;
+ DBUG_ENTER("calc_sum_of_all_status");
- DBUG_ENTER("mysqld_show_charsets");
+ /* Ensure that thread id not killed during loop */
+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
- field_list.push_back(new Item_empty_string("Collation",30));
- field_list.push_back(new Item_empty_string("Charset",30));
- field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT));
- field_list.push_back(new Item_empty_string("Default",30));
- field_list.push_back(new Item_empty_string("Compiled",30));
- field_list.push_back(new Item_return_int("Sortlen",3, FIELD_TYPE_SHORT));
+ I_List_iterator<THD> it(threads);
+ THD *tmp;
+
+ /* Get global values as base */
+ *to= global_status_var;
+
+ /* Add to this status from existing threads */
+ while ((tmp= it++))
+ add_to_status(to, &tmp->status_var);
+
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ DBUG_VOID_RETURN;
+}
+
+
+LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
+ const char* str, uint length,
+ bool allocate_lex_string)
+{
+ MEM_ROOT *mem= thd->mem_root;
+ if (allocate_lex_string)
+ lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING));
+ lex_str->str= strmake_root(mem, str, length);
+ lex_str->length= length;
+ return lex_str;
+}
+
+
+/* INFORMATION_SCHEMA name */
+LEX_STRING information_schema_name= {(char*)"information_schema", 18};
+extern ST_SCHEMA_TABLE schema_tables[];
+
+typedef struct st_index_field_values
+{
+ const char *db_value, *table_value;
+} INDEX_FIELD_VALUES;
+
+
+/*
+ Store record to I_S table, convert HEAP table
+ to MyISAM if necessary
+
+ SYNOPSIS
+ schema_table_store_record()
+ thd thread handler
+ table Information schema table to be updated
+
+ RETURN
+ 0 success
+ 1 error
+*/
+
+static bool schema_table_store_record(THD *thd, TABLE *table)
+{
+ int error;
+ if ((error= table->file->write_row(table->record[0])))
+ {
+ if (create_myisam_from_heap(thd, table,
+ table->pos_in_table_list->schema_table_param,
+ error, 0))
+ return 1;
+ }
+ return 0;
+}
+
+
+void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values)
+{
+ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
+ switch (lex->orig_sql_command) {
+ case SQLCOM_SHOW_DATABASES:
+ index_field_values->db_value= wild;
+ break;
+ case SQLCOM_SHOW_TABLES:
+ case SQLCOM_SHOW_TABLE_STATUS:
+ index_field_values->db_value= lex->current_select->db;
+ index_field_values->table_value= wild;
+ break;
+ default:
+ index_field_values->db_value= NullS;
+ index_field_values->table_value= NullS;
+ break;
+ }
+}
+
+
+int make_table_list(THD *thd, SELECT_LEX *sel,
+ char *db, char *table)
+{
+ Table_ident *table_ident;
+ LEX_STRING ident_db, ident_table;
+ ident_db.str= db;
+ ident_db.length= strlen(db);
+ ident_table.str= table;
+ ident_table.length= strlen(table);
+ table_ident= new Table_ident(thd, ident_db, ident_table, 1);
+ sel->init_query();
+ if(!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
+ (List<String> *) 0, (List<String> *) 0))
+ return 1;
+ return 0;
+}
- if (protocol->send_fields(&field_list, 1))
+
+bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
+{
+ if (item->type() == Item::FUNC_ITEM)
+ {
+ Item_func *item_func= (Item_func*)item;
+ Item **child;
+ Item **item_end= (item_func->arguments()) + item_func->argument_count();
+ for (child= item_func->arguments(); child != item_end; child++)
+ {
+ if (!uses_only_table_name_fields(*child, table))
+ return 0;
+ }
+ }
+ else if (item->type() == Item::FIELD_ITEM)
+ {
+ Item_field *item_field= (Item_field*)item;
+ CHARSET_INFO *cs= system_charset_info;
+ ST_SCHEMA_TABLE *schema_table= table->schema_table;
+ ST_FIELD_INFO *field_info= schema_table->fields_info;
+ const char *field_name1= field_info[schema_table->idx_field1].field_name;
+ const char *field_name2= field_info[schema_table->idx_field2].field_name;
+ if (table->table != item_field->field->table ||
+ (cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
+ (uchar *) item_field->field_name,
+ strlen(item_field->field_name), 0) &&
+ cs->coll->strnncollsp(cs, (uchar *) field_name2, strlen(field_name2),
+ (uchar *) item_field->field_name,
+ strlen(item_field->field_name), 0)))
+ return 0;
+ }
+ else if (item->type() == Item::REF_ITEM)
+ return uses_only_table_name_fields(item->real_item(), table);
+ if (item->type() == Item::SUBSELECT_ITEM &&
+ !item->const_item())
+ return 0;
+
+ return 1;
+}
+
+
+static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table)
+{
+ if (!cond)
+ return (COND*) 0;
+ if (cond->type() == Item::COND_ITEM)
+ {
+ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ {
+ /* Create new top level AND item */
+ Item_cond_and *new_cond=new Item_cond_and;
+ if (!new_cond)
+ return (COND*) 0;
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item=li++))
+ {
+ Item *fix= make_cond_for_info_schema(item, table);
+ if (fix)
+ new_cond->argument_list()->push_back(fix);
+ }
+ switch (new_cond->argument_list()->elements) {
+ case 0:
+ return (COND*) 0;
+ case 1:
+ return new_cond->argument_list()->head();
+ default:
+ new_cond->quick_fix_field();
+ return new_cond;
+ }
+ }
+ else
+ { // Or list
+ Item_cond_or *new_cond=new Item_cond_or;
+ if (!new_cond)
+ return (COND*) 0;
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item=li++))
+ {
+ Item *fix=make_cond_for_info_schema(item, table);
+ if (!fix)
+ return (COND*) 0;
+ new_cond->argument_list()->push_back(fix);
+ }
+ new_cond->quick_fix_field();
+ new_cond->top_level_item();
+ return new_cond;
+ }
+ }
+
+ if (!uses_only_table_name_fields(cond, table))
+ return (COND*) 0;
+ return cond;
+}
+
+
+enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
+{
+ return (enum enum_schema_tables) (schema_table - &schema_tables[0]);
+}
+
+
+/*
+ Add 'information_schema' name to db_names list
+
+ SYNOPSIS
+ schema_db_add()
+ thd thread handler
+ files list of db names
+ wild wild string
+ with_i_schema returns 1 if we added 'IS' name to list
+ otherwise returns 0
+
+ RETURN
+ 1 error
+ 0 success
+*/
+
+int schema_db_add(THD *thd, List<char> *files,
+ const char *wild, bool *with_i_schema)
+{
+ *with_i_schema= 0;
+ if (!wild || !wild_compare(information_schema_name.str, wild, 0))
+ {
+ *with_i_schema= 1;
+ if (files->push_back(thd->strdup(information_schema_name.str)))
+ return 1;
+ }
+ return 0;
+}
+
+
+int schema_tables_add(THD *thd, List<char> *files, const char *wild)
+{
+ ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
+ for ( ; tmp_schema_table->table_name; tmp_schema_table++)
+ {
+ if (tmp_schema_table->hidden)
+ continue;
+ if (wild)
+ {
+ if (lower_case_table_names)
+ {
+ if (wild_case_compare(files_charset_info,
+ tmp_schema_table->table_name,
+ wild))
+ continue;
+ }
+ else if (wild_compare(tmp_schema_table->table_name, wild, 0))
+ continue;
+ }
+ if (files->push_back(thd->strdup(tmp_schema_table->table_name)))
+ return 1;
+ }
+ return 0;
+}
+
+
+int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ LEX *lex= thd->lex;
+ TABLE *table= tables->table;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *old_all_select_lex= lex->all_selects_list;
+ SELECT_LEX *lsel= tables->schema_select_lex;
+ ST_SCHEMA_TABLE *schema_table= tables->schema_table;
+ SELECT_LEX sel;
+ INDEX_FIELD_VALUES idx_field_vals;
+ char path[FN_REFLEN], *end, *base_name, *file_name;
+ uint len;
+ bool with_i_schema;
+ enum enum_schema_tables schema_table_idx;
+ thr_lock_type lock_type;
+ List<char> bases;
+ List_iterator_fast<char> it(bases);
+ COND *partial_cond;
+ uint derived_tables= lex->derived_tables;
+ int error= 1;
+ DBUG_ENTER("get_all_tables");
+
+ LINT_INIT(end);
+ LINT_INIT(len);
+
+ if (lsel)
+ {
+ TABLE *old_open_tables= thd->open_tables;
+ TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first;
+ bool res;
+
+ lex->all_selects_list= lsel;
+ res= open_and_lock_tables(thd, show_table_list);
+ if (schema_table->process_table(thd, show_table_list,
+ table, res, show_table_list->db,
+ show_table_list->alias))
+ goto err;
+ close_thread_tables(thd, 0, 0, old_open_tables);
+ show_table_list->table= 0;
+ error= 0;
+ goto err;
+ }
+
+ schema_table_idx= get_schema_table_idx(schema_table);
+ lock_type= TL_UNLOCK;
+
+ if (schema_table_idx == SCH_TABLES)
+ lock_type= TL_READ;
+ get_index_field_values(lex, &idx_field_vals);
+
+ /* information schema name always is first in list */
+ if (schema_db_add(thd, &bases, idx_field_vals.db_value, &with_i_schema))
+ goto err;
+
+ if (mysql_find_files(thd, &bases, NullS, mysql_data_home,
+ idx_field_vals.db_value, 1))
+ goto err;
+
+ partial_cond= make_cond_for_info_schema(cond, tables);
+ it.rewind(); /* To get access to new elements in basis list */
+ while ((base_name= it++) ||
+ /*
+ generate error for non existing database.
+ (to save old behaviour for SHOW TABLES FROM db)
+ */
+ ((lex->orig_sql_command == SQLCOM_SHOW_TABLES ||
+ lex->orig_sql_command == SQLCOM_SHOW_TABLE_STATUS) &&
+ (base_name= select_lex->db) && !bases.elements))
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (with_i_schema || // don't check the rights if information schema db
+ !check_access(thd,SELECT_ACL, base_name, &thd->col_access,0,1) ||
+ thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
+ acl_get(thd->host, thd->ip, thd->priv_user, base_name,0) ||
+ (grant_option && !check_grant_db(thd, base_name)))
+#endif
+ {
+ List<char> files;
+ if (with_i_schema) // information schema table names
+ {
+ if (schema_tables_add(thd, &files, idx_field_vals.table_value))
+ goto err;
+ }
+ else
+ {
+ strxmov(path, mysql_data_home, "/", base_name, NullS);
+ end= path + (len= unpack_dirname(path,path));
+ len= FN_LEN - len;
+ if (mysql_find_files(thd, &files, base_name,
+ path, idx_field_vals.table_value, 0))
+ goto err;
+ }
+
+ List_iterator_fast<char> it_files(files);
+ while ((file_name= it_files++))
+ {
+ restore_record(table, s->default_values);
+ table->field[schema_table->idx_field1]->
+ store(base_name, strlen(base_name), system_charset_info);
+ table->field[schema_table->idx_field2]->
+ store(file_name, strlen(file_name),system_charset_info);
+ if (!partial_cond || partial_cond->val_int())
+ {
+ if (schema_table_idx == SCH_TABLE_NAMES)
+ {
+ if (lex->verbose || lex->orig_sql_command == SQLCOM_END)
+ {
+ if (with_i_schema)
+ {
+ table->field[3]->store("TEMPORARY", 9, system_charset_info);
+ }
+ else
+ {
+ my_snprintf(end, len, "/%s%s", file_name, reg_ext);
+ switch (mysql_frm_type(path)) {
+ case FRMTYPE_ERROR:
+ table->field[3]->store("ERROR", 5, system_charset_info);
+ break;
+ case FRMTYPE_TABLE:
+ table->field[3]->store("BASE TABLE", 10, system_charset_info);
+ break;
+ case FRMTYPE_VIEW:
+ table->field[3]->store("VIEW", 4, system_charset_info);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ }
+ if (schema_table_store_record(thd, table))
+ goto err;
+ }
+ else
+ {
+ int res;
+ TABLE *old_open_tables= thd->open_tables;
+ if (make_table_list(thd, &sel, base_name, file_name))
+ goto err;
+ TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first;
+ show_table_list->lock_type= lock_type;
+ lex->all_selects_list= &sel;
+ lex->derived_tables= 0;
+ res= open_and_lock_tables(thd, show_table_list);
+ if (schema_table->process_table(thd, show_table_list, table,
+ res, base_name,
+ show_table_list->alias))
+ goto err;
+ close_thread_tables(thd, 0, 0, old_open_tables);
+ }
+ }
+ }
+ /*
+ If we have information schema its always the first table and only
+ the first table. Reset for other tables.
+ */
+ with_i_schema= 0;
+ }
+ }
+
+ error= 0;
+err:
+ lex->derived_tables= derived_tables;
+ lex->all_selects_list= old_all_select_lex;
+ DBUG_RETURN(error);
+}
+
+
+bool store_schema_shemata(THD* thd, TABLE *table, const char *db_name,
+ const char* cs_name)
+{
+ restore_record(table, s->default_values);
+ table->field[1]->store(db_name, strlen(db_name), system_charset_info);
+ table->field[2]->store(cs_name, strlen(cs_name), system_charset_info);
+ return schema_table_store_record(thd, table);
+}
+
+
+int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ char path[FN_REFLEN];
+ bool found_libchar;
+ INDEX_FIELD_VALUES idx_field_vals;
+ List<char> files;
+ char *file_name;
+ uint length;
+ bool with_i_schema;
+ HA_CREATE_INFO create;
+ TABLE *table= tables->table;
+ DBUG_ENTER("fill_schema_shemata");
+
+ get_index_field_values(thd->lex, &idx_field_vals);
+ /* information schema name always is first in list */
+ if (schema_db_add(thd, &files, idx_field_vals.db_value, &with_i_schema))
+ DBUG_RETURN(1);
+ if (mysql_find_files(thd, &files, NullS, mysql_data_home,
+ idx_field_vals.db_value, 1))
DBUG_RETURN(1);
+ List_iterator_fast<char> it(files);
+ while ((file_name=it++))
+ {
+ if (with_i_schema) // information schema name is always first in list
+ {
+ if (store_schema_shemata(thd, table, file_name,
+ system_charset_info->csname))
+ DBUG_RETURN(1);
+ with_i_schema= 0;
+ continue;
+ }
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
+ acl_get(thd->host, thd->ip, thd->priv_user, file_name,0) ||
+ (grant_option && !check_grant_db(thd, file_name)))
+#endif
+ {
+ strxmov(path, mysql_data_home, "/", file_name, NullS);
+ length=unpack_dirname(path,path); // Convert if not unix
+ found_libchar= 0;
+ if (length && path[length-1] == FN_LIBCHAR)
+ {
+ found_libchar= 1;
+ path[length-1]=0; // remove ending '\'
+ }
+
+ if (found_libchar)
+ path[length-1]= FN_LIBCHAR;
+ strmov(path+length, MY_DB_OPT_FILE);
+ load_db_opt(thd, path, &create);
+ if (store_schema_shemata(thd, table, file_name,
+ create.default_table_charset->csname))
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
+ TABLE *table, bool res,
+ const char *base_name,
+ const char *file_name)
+{
+ const char *tmp_buff;
+ TIME time;
+ CHARSET_INFO *cs= system_charset_info;
+ DBUG_ENTER("get_schema_tables_record");
+
+ restore_record(table, s->default_values);
+ table->field[1]->store(base_name, strlen(base_name), cs);
+ table->field[2]->store(file_name, strlen(file_name), cs);
+ if (res)
+ {
+ /*
+ there was errors during opening tables
+ */
+ const char *error= thd->net.last_error;
+ table->field[20]->store(error, strlen(error), cs);
+ thd->clear_error();
+ }
+ else if (tables->view)
+ {
+ table->field[3]->store("VIEW", 4, cs);
+ table->field[20]->store("view", 4, cs);
+ }
+ else
+ {
+ TABLE *show_table= tables->table;
+ TABLE_SHARE *share= show_table->s;
+ handler *file= show_table->file;
+
+ file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
+ if (share->tmp_table == TMP_TABLE)
+ table->field[3]->store("TEMPORARY", 9, cs);
+ else
+ table->field[3]->store("BASE TABLE", 10, cs);
+
+ for (int i= 4; i < 20; i++)
+ {
+ if (i == 7 || (i > 12 && i < 17) || i == 18)
+ continue;
+ table->field[i]->set_notnull();
+ }
+ tmp_buff= file->table_type();
+ table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
+ table->field[5]->store((longlong) share->frm_version);
+ enum row_type row_type = file->get_row_type();
+ switch (row_type) {
+ case ROW_TYPE_NOT_USED:
+ case ROW_TYPE_DEFAULT:
+ tmp_buff= ((share->db_options_in_use &
+ HA_OPTION_COMPRESS_RECORD) ? "Compressed" :
+ (share->db_options_in_use & HA_OPTION_PACK_RECORD) ?
+ "Dynamic" : "Fixed");
+ break;
+ case ROW_TYPE_FIXED:
+ tmp_buff= "Fixed";
+ break;
+ case ROW_TYPE_DYNAMIC:
+ tmp_buff= "Dynamic";
+ break;
+ case ROW_TYPE_COMPRESSED:
+ tmp_buff= "Compressed";
+ break;
+ case ROW_TYPE_REDUNDANT:
+ tmp_buff= "Redundant";
+ break;
+ case ROW_TYPE_COMPACT:
+ tmp_buff= "Compact";
+ break;
+ }
+ table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
+ if (!tables->schema_table)
+ {
+ table->field[7]->store((longlong) file->records);
+ table->field[7]->set_notnull();
+ }
+ table->field[8]->store((longlong) file->mean_rec_length);
+ table->field[9]->store((longlong) file->data_file_length);
+ if (file->max_data_file_length)
+ {
+ table->field[10]->store((longlong) file->max_data_file_length);
+ }
+ table->field[11]->store((longlong) file->index_file_length);
+ table->field[12]->store((longlong) file->delete_length);
+ if (show_table->found_next_number_field)
+ {
+ show_table->next_number_field=show_table->found_next_number_field;
+ show_table->next_number_field->reset();
+ file->update_auto_increment();
+ table->field[13]->store((longlong) show_table->
+ next_number_field->val_int());
+ table->field[13]->set_notnull();
+ show_table->next_number_field=0;
+ }
+ if (file->create_time)
+ {
+ thd->variables.time_zone->gmt_sec_to_TIME(&time,
+ file->create_time);
+ table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[14]->set_notnull();
+ }
+ if (file->update_time)
+ {
+ thd->variables.time_zone->gmt_sec_to_TIME(&time,
+ file->update_time);
+ table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[15]->set_notnull();
+ }
+ if (file->check_time)
+ {
+ thd->variables.time_zone->gmt_sec_to_TIME(&time, file->check_time);
+ table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ table->field[16]->set_notnull();
+ }
+ tmp_buff= (share->table_charset ?
+ share->table_charset->name : "default");
+ table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);
+ if (file->table_flags() & (ulong) HA_HAS_CHECKSUM)
+ {
+ table->field[18]->store((longlong) file->checksum());
+ table->field[18]->set_notnull();
+ }
+
+ char option_buff[350],*ptr;
+ ptr=option_buff;
+ if (share->min_rows)
+ {
+ ptr=strmov(ptr," min_rows=");
+ ptr=longlong10_to_str(share->min_rows,ptr,10);
+ }
+ if (share->max_rows)
+ {
+ ptr=strmov(ptr," max_rows=");
+ ptr=longlong10_to_str(share->max_rows,ptr,10);
+ }
+ if (share->avg_row_length)
+ {
+ ptr=strmov(ptr," avg_row_length=");
+ ptr=longlong10_to_str(share->avg_row_length,ptr,10);
+ }
+ if (share->db_create_options & HA_OPTION_PACK_KEYS)
+ ptr=strmov(ptr," pack_keys=1");
+ if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
+ ptr=strmov(ptr," pack_keys=0");
+ if (share->db_create_options & HA_OPTION_CHECKSUM)
+ ptr=strmov(ptr," checksum=1");
+ if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
+ ptr=strmov(ptr," delay_key_write=1");
+ if (share->row_type != ROW_TYPE_DEFAULT)
+ ptr=strxmov(ptr, " row_format=",
+ ha_row_type[(uint) share->row_type],
+ NullS);
+ if (file->raid_type)
+ {
+ char buff[100];
+ my_snprintf(buff,sizeof(buff),
+ " raid_type=%s raid_chunks=%d raid_chunksize=%ld",
+ my_raid_type(file->raid_type), file->raid_chunks,
+ file->raid_chunksize/RAID_BLOCK_SIZE);
+ ptr=strmov(ptr,buff);
+ }
+ table->field[19]->store(option_buff+1,
+ (ptr == option_buff ? 0 :
+ (uint) (ptr-option_buff)-1), cs);
+ {
+ char *comment;
+ comment= show_table->file->update_table_comment(share->comment);
+ if (comment)
+ {
+ table->field[20]->store(comment, strlen(comment), cs);
+ if (comment != share->comment)
+ my_free(comment, MYF(0));
+ }
+ }
+ }
+ DBUG_RETURN(schema_table_store_record(thd, table));
+}
+
+static int get_schema_column_record(THD *thd, struct st_table_list *tables,
+ TABLE *table, bool res,
+ const char *base_name,
+ const char *file_name)
+{
+ LEX *lex= thd->lex;
+ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
+ CHARSET_INFO *cs= system_charset_info;
+ DBUG_ENTER("get_schema_column_record");
+ if (res)
+ {
+ if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS)
+ {
+ /*
+ I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
+ rather than in SHOW COLUMNS
+ */
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ thd->net.last_errno, thd->net.last_error);
+ thd->clear_error();
+ res= 0;
+ }
+ DBUG_RETURN(res);
+ }
+
+ TABLE *show_table= tables->table;
+ handler *file= show_table->file;
+ file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ restore_record(show_table, s->default_values);
+ Field **ptr,*field;
+ int count= 0;
+ for (ptr=show_table->field; (field= *ptr) ; ptr++)
+ {
+ if (!wild || !wild[0] ||
+ !wild_case_compare(system_charset_info, field->field_name,wild))
+ {
+ const char *tmp_buff;
+ byte *pos;
+ uint flags=field->flags;
+ char tmp[MAX_FIELD_WIDTH];
+ char tmp1[MAX_FIELD_WIDTH];
+ String type(tmp,sizeof(tmp), system_charset_info);
+ char *end= tmp;
+ count++;
+ restore_record(table, s->default_values);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ uint col_access;
+ check_access(thd,SELECT_ACL | EXTRA_ACL, base_name,
+ &tables->grant.privilege, 0, 0);
+ col_access= get_column_grant(thd, &tables->grant, tables->db,
+ tables->table_name,
+ field->field_name) & COL_ACLS;
+ if (lex->orig_sql_command != SQLCOM_SHOW_FIELDS && !col_access)
+ continue;
+ for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
+ {
+ if (col_access & 1)
+ {
+ *end++=',';
+ end=strmov(end,grant_types.type_names[bitnr]);
+ }
+ }
+#else
+ *end= 0;
+#endif
+ table->field[17]->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1), cs);
+
+ table->field[1]->store(base_name, strlen(base_name), cs);
+ table->field[2]->store(file_name, strlen(file_name), cs);
+ table->field[3]->store(field->field_name, strlen(field->field_name),
+ cs);
+ table->field[4]->store((longlong) count);
+ field->sql_type(type);
+ table->field[14]->store(type.ptr(), type.length(), cs);
+ tmp_buff= strchr(type.ptr(), '(');
+ table->field[7]->store(type.ptr(),
+ (tmp_buff ? tmp_buff - type.ptr() :
+ type.length()), cs);
+ if (show_table->timestamp_field == field &&
+ field->unireg_check != Field::TIMESTAMP_UN_FIELD)
+ {
+ table->field[5]->store("CURRENT_TIMESTAMP", 17, cs);
+ table->field[5]->set_notnull();
+ }
+ else if (field->unireg_check != Field::NEXT_NUMBER &&
+ !field->is_null() &&
+ !(field->flags & NO_DEFAULT_VALUE_FLAG))
+ {
+ String def(tmp1,sizeof(tmp1), cs);
+ type.set(tmp, sizeof(tmp), field->charset());
+ field->val_str(&type);
+ uint dummy_errors;
+ def.copy(type.ptr(), type.length(), type.charset(), cs, &dummy_errors);
+ table->field[5]->store(def.ptr(), def.length(), def.charset());
+ table->field[5]->set_notnull();
+ }
+ else if (field->unireg_check == Field::NEXT_NUMBER ||
+ field->maybe_null())
+ table->field[5]->set_null(); // Null as default
+ else
+ {
+ table->field[5]->store("",0, cs);
+ table->field[5]->set_notnull();
+ }
+ pos=(byte*) ((flags & NOT_NULL_FLAG) &&
+ field->type() != FIELD_TYPE_TIMESTAMP ?
+ "NO" : "YES");
+ table->field[6]->store((const char*) pos,
+ strlen((const char*) pos), cs);
+ if (field->has_charset())
+ {
+ table->field[8]->store((longlong) field->representation_length()/
+ field->charset()->mbmaxlen);
+ table->field[8]->set_notnull();
+ table->field[9]->store((longlong) field->representation_length());
+ table->field[9]->set_notnull();
+ }
+
+ {
+ uint dec =field->decimals();
+ switch (field->type()) {
+ case FIELD_TYPE_NEWDECIMAL:
+ table->field[10]->store((longlong) field->field_length);
+ table->field[10]->set_notnull();
+ table->field[11]->store((longlong) field->decimals());
+ table->field[11]->set_notnull();
+ break;
+ case FIELD_TYPE_DECIMAL:
+ {
+ uint int_part=field->field_length - (dec ? dec + 1 : 0);
+ table->field[10]->store((longlong) (int_part + dec - 1));
+ table->field[10]->set_notnull();
+ table->field[11]->store((longlong) field->decimals());
+ table->field[11]->set_notnull();
+ break;
+ }
+ case FIELD_TYPE_TINY:
+ case FIELD_TYPE_SHORT:
+ case FIELD_TYPE_LONG:
+ case FIELD_TYPE_LONGLONG:
+ case FIELD_TYPE_INT24:
+ case FIELD_TYPE_FLOAT:
+ case FIELD_TYPE_DOUBLE:
+ {
+ table->field[10]->store((longlong) field->field_length);
+ table->field[10]->set_notnull();
+ if (dec != NOT_FIXED_DEC)
+ {
+ table->field[11]->store((longlong) dec);
+ table->field[11]->set_notnull();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (field->has_charset())
+ {
+ pos=(byte*) field->charset()->csname;
+ table->field[12]->store((const char*) pos,
+ strlen((const char*) pos), cs);
+ table->field[12]->set_notnull();
+ pos=(byte*) field->charset()->name;
+ table->field[13]->store((const char*) pos,
+ strlen((const char*) pos), cs);
+ table->field[13]->set_notnull();
+ }
+ pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
+ (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
+ (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
+ table->field[15]->store((const char*) pos,
+ strlen((const char*) pos), cs);
+ end= tmp;
+ if (field->unireg_check == Field::NEXT_NUMBER)
+ end=strmov(tmp,"auto_increment");
+ table->field[16]->store(tmp, (uint) (end-tmp), cs);
+
+ end=tmp;
+ table->field[18]->store(field->comment.str, field->comment.length, cs);
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+
+int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ CHARSET_INFO **cs;
+ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
+ TABLE *table= tables->table;
+ CHARSET_INFO *scs= system_charset_info;
+ for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
+ {
+ CHARSET_INFO *tmp_cs= cs[0];
+ if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) &&
+ (tmp_cs->state & MY_CS_AVAILABLE) &&
+ !(wild && wild[0] &&
+ wild_case_compare(scs, tmp_cs->csname,wild)))
+ {
+ restore_record(table, s->default_values);
+ table->field[0]->store(tmp_cs->csname, strlen(tmp_cs->csname), scs);
+ table->field[1]->store(tmp_cs->name, strlen(tmp_cs->name), scs);
+ table->field[2]->store(tmp_cs->comment ? tmp_cs->comment : "",
+ strlen(tmp_cs->comment ? tmp_cs->comment : ""),
+ scs);
+ table->field[3]->store((longlong) tmp_cs->mbmaxlen);
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ CHARSET_INFO **cs;
+ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
+ TABLE *table= tables->table;
+ CHARSET_INFO *scs= system_charset_info;
for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
{
CHARSET_INFO **cl;
- if (!cs[0] || !(cs[0]->state & MY_CS_AVAILABLE) ||
- !(cs[0]->state & MY_CS_PRIMARY))
+ CHARSET_INFO *tmp_cs= cs[0];
+ if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
+ !(tmp_cs->state & MY_CS_PRIMARY))
continue;
for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
{
- if (!cl[0] || !(cl[0]->state & MY_CS_AVAILABLE) ||
- !my_charset_same(cs[0],cl[0]))
+ CHARSET_INFO *tmp_cl= cl[0];
+ if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
+ !my_charset_same(tmp_cs, tmp_cl))
continue;
if (!(wild && wild[0] &&
- wild_case_compare(system_charset_info,cl[0]->name,wild)))
+ wild_case_compare(scs, tmp_cl->name,wild)))
{
- if (write_collation(protocol, cl[0]))
- goto err;
+ const char *tmp_buff;
+ restore_record(table, s->default_values);
+ table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
+ table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
+ table->field[2]->store((longlong) tmp_cl->number);
+ tmp_buff= (tmp_cl->state & MY_CS_PRIMARY) ? "Yes" : "";
+ table->field[3]->store(tmp_buff, strlen(tmp_buff), scs);
+ tmp_buff= (tmp_cl->state & MY_CS_COMPILED)? "Yes" : "";
+ table->field[4]->store(tmp_buff, strlen(tmp_buff), scs);
+ table->field[5]->store((longlong) tmp_cl->strxfrm_multiply);
+ if (schema_table_store_record(thd, table))
+ return 1;
}
}
}
- send_eof(thd);
- DBUG_RETURN(0);
-err:
- DBUG_RETURN(1);
+ return 0;
}
-static bool write_charset(Protocol *protocol, CHARSET_INFO *cs)
-{
- protocol->prepare_for_resend();
- protocol->store(cs->csname, system_charset_info);
- protocol->store(cs->comment ? cs->comment : "", system_charset_info);
- protocol->store(cs->name, system_charset_info);
- protocol->store_short((longlong) cs->mbmaxlen);
- return protocol->write();
-}
-int mysqld_show_charsets(THD *thd, const char *wild)
+int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
{
- char buff[8192];
- String packet2(buff,sizeof(buff),thd->charset());
- List<Item> field_list;
CHARSET_INFO **cs;
- Protocol *protocol= thd->protocol;
+ TABLE *table= tables->table;
+ CHARSET_INFO *scs= system_charset_info;
+ for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
+ {
+ CHARSET_INFO **cl;
+ CHARSET_INFO *tmp_cs= cs[0];
+ if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
+ !(tmp_cs->state & MY_CS_PRIMARY))
+ continue;
+ for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
+ {
+ CHARSET_INFO *tmp_cl= cl[0];
+ if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
+ !my_charset_same(tmp_cs,tmp_cl))
+ continue;
+ restore_record(table, s->default_values);
+ table->field[0]->store(tmp_cl->name, strlen(tmp_cl->name), scs);
+ table->field[1]->store(tmp_cl->csname , strlen(tmp_cl->csname), scs);
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ }
+ return 0;
+}
+
- DBUG_ENTER("mysqld_show_charsets");
+bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
+ const char *wild, bool full_access, const char *sp_user)
+{
+ String tmp_string;
+ TIME time;
+ LEX *lex= thd->lex;
+ CHARSET_INFO *cs= system_charset_info;
+ const char *sp_db, *sp_name, *definer;
+ sp_db= get_field(thd->mem_root, proc_table->field[0]);
+ sp_name= get_field(thd->mem_root, proc_table->field[1]);
+ definer= get_field(thd->mem_root, proc_table->field[11]);
+ if (!full_access)
+ full_access= !strcmp(sp_user, definer);
+ if (!full_access && check_some_routine_access(thd, sp_db, sp_name))
+ return 0;
+
+ if (lex->orig_sql_command == SQLCOM_SHOW_STATUS_PROC &&
+ proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE ||
+ lex->orig_sql_command == SQLCOM_SHOW_STATUS_FUNC &&
+ proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION ||
+ lex->orig_sql_command == SQLCOM_END)
+ {
+ restore_record(table, s->default_values);
+ if (!wild || !wild[0] || !wild_compare(sp_name, wild, 0))
+ {
+ table->field[3]->store(sp_name, strlen(sp_name), cs);
+ get_field(thd->mem_root, proc_table->field[3], &tmp_string);
+ table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ table->field[2]->store(sp_db, strlen(sp_db), cs);
+ get_field(thd->mem_root, proc_table->field[2], &tmp_string);
+ table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ if (proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION)
+ {
+ get_field(thd->mem_root, proc_table->field[9], &tmp_string);
+ table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ table->field[5]->set_notnull();
+ }
+ if (full_access)
+ {
+ get_field(thd->mem_root, proc_table->field[10], &tmp_string);
+ table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ }
+ table->field[6]->store("SQL", 3, cs);
+ table->field[10]->store("SQL", 3, cs);
+ get_field(thd->mem_root, proc_table->field[6], &tmp_string);
+ table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ if (proc_table->field[5]->val_int() == SP_CONTAINS_SQL)
+ {
+ table->field[12]->store("CONTAINS SQL", 12 , cs);
+ }
+ get_field(thd->mem_root, proc_table->field[7], &tmp_string);
+ table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ bzero((char *)&time, sizeof(time));
+ ((Field_timestamp *) proc_table->field[12])->get_time(&time);
+ table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ bzero((char *)&time, sizeof(time));
+ ((Field_timestamp *) proc_table->field[13])->get_time(&time);
+ table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
+ get_field(thd->mem_root, proc_table->field[14], &tmp_string);
+ table->field[17]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ get_field(thd->mem_root, proc_table->field[15], &tmp_string);
+ table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ table->field[19]->store(definer, strlen(definer), cs);
+ return schema_table_store_record(thd, table);
+ }
+ }
+ return 0;
+}
- field_list.push_back(new Item_empty_string("Charset",30));
- field_list.push_back(new Item_empty_string("Description",60));
- field_list.push_back(new Item_empty_string("Default collation",60));
- field_list.push_back(new Item_return_int("Maxlen",3, FIELD_TYPE_SHORT));
- if (protocol->send_fields(&field_list, 1))
+int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ TABLE *proc_table;
+ TABLE_LIST proc_tables;
+ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
+ int res= 0;
+ TABLE *table= tables->table, *old_open_tables= thd->open_tables;
+ bool full_access;
+ char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
+ DBUG_ENTER("fill_schema_proc");
+
+ strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
+ bzero((char*) &proc_tables,sizeof(proc_tables));
+ proc_tables.db= (char*) "mysql";
+ proc_tables.db_length= 5;
+ proc_tables.table_name= proc_tables.alias= (char*) "proc";
+ proc_tables.table_name_length= 4;
+ proc_tables.lock_type= TL_READ;
+ full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1);
+ if (!(proc_table= open_ltable(thd, &proc_tables, TL_READ)))
+ {
DBUG_RETURN(1);
+ }
+ proc_table->file->ha_index_init(0);
+ if ((res= proc_table->file->index_first(proc_table->record[0])))
+ {
+ res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
+ goto err;
+ }
+ if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
+ {
+ res= 1;
+ goto err;
+ }
+ while (!proc_table->file->index_next(proc_table->record[0]))
+ {
+ if (store_schema_proc(thd, table, proc_table, wild, full_access, definer))
+ {
+ res= 1;
+ goto err;
+ }
+ }
- for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
+err:
+ proc_table->file->ha_index_end();
+ close_thread_tables(thd, 0, 0, old_open_tables);
+ DBUG_RETURN(res);
+}
+
+
+static int get_schema_stat_record(THD *thd, struct st_table_list *tables,
+ TABLE *table, bool res,
+ const char *base_name,
+ const char *file_name)
+{
+ CHARSET_INFO *cs= system_charset_info;
+ DBUG_ENTER("get_schema_stat_record");
+ if (res)
{
- if (cs[0] && (cs[0]->state & MY_CS_PRIMARY) &&
- (cs[0]->state & MY_CS_AVAILABLE) &&
- !(wild && wild[0] &&
- wild_case_compare(system_charset_info,cs[0]->csname,wild)))
+ if (thd->lex->orig_sql_command != SQLCOM_SHOW_KEYS)
+ {
+ /*
+ I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
+ rather than in SHOW KEYS
+ */
+ if (!tables->view)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ thd->net.last_errno, thd->net.last_error);
+ thd->clear_error();
+ res= 0;
+ }
+ DBUG_RETURN(res);
+ }
+ else if (!tables->view)
+ {
+ TABLE *show_table= tables->table;
+ KEY *key_info=show_table->key_info;
+ show_table->file->info(HA_STATUS_VARIABLE |
+ HA_STATUS_NO_LOCK |
+ HA_STATUS_TIME);
+ for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
+ {
+ KEY_PART_INFO *key_part= key_info->key_part;
+ const char *str;
+ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
+ {
+ restore_record(table, s->default_values);
+ table->field[1]->store(base_name, strlen(base_name), cs);
+ table->field[2]->store(file_name, strlen(file_name), cs);
+ table->field[3]->store((longlong) ((key_info->flags &
+ HA_NOSAME) ? 0 :1));
+ table->field[4]->store(base_name, strlen(base_name), cs);
+ table->field[5]->store(key_info->name, strlen(key_info->name), cs);
+ table->field[6]->store((longlong) (j+1));
+ str=(key_part->field ? key_part->field->field_name :
+ "?unknown field?");
+ table->field[7]->store(str, strlen(str), cs);
+ if (show_table->file->index_flags(i, j, 0) & HA_READ_ORDER)
+ {
+ table->field[8]->store(((key_part->key_part_flag &
+ HA_REVERSE_SORT) ?
+ "D" : "A"), 1, cs);
+ table->field[8]->set_notnull();
+ }
+ KEY *key=show_table->key_info+i;
+ if (key->rec_per_key[j])
+ {
+ ha_rows records=(show_table->file->records /
+ key->rec_per_key[j]);
+ table->field[9]->store((longlong) records);
+ table->field[9]->set_notnull();
+ }
+ if (!(key_info->flags & HA_FULLTEXT) &&
+ (!key_part->field ||
+ key_part->length !=
+ show_table->field[key_part->fieldnr-1]->key_length()))
+ {
+ table->field[10]->store((longlong) key_part->length /
+ key_part->field->charset()->mbmaxlen);
+ table->field[10]->set_notnull();
+ }
+ uint flags= key_part->field ? key_part->field->flags : 0;
+ const char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
+ table->field[12]->store(pos, strlen(pos), cs);
+ pos= show_table->file->index_type(i);
+ table->field[13]->store(pos, strlen(pos), cs);
+ if (!show_table->s->keys_in_use.is_set(i))
+ table->field[14]->store("disabled", 8, cs);
+ else
+ table->field[14]->store("", 0, cs);
+ table->field[14]->set_notnull();
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ DBUG_RETURN(res);
+}
+
+
+static int get_schema_views_record(THD *thd, struct st_table_list *tables,
+ TABLE *table, bool res,
+ const char *base_name,
+ const char *file_name)
+{
+ CHARSET_INFO *cs= system_charset_info;
+ DBUG_ENTER("get_schema_views_record");
+ if (!res)
+ {
+ if (tables->view)
{
- if (write_charset(protocol, cs[0]))
- goto err;
+ restore_record(table, s->default_values);
+ table->field[1]->store(tables->view_db.str, tables->view_db.length, cs);
+ table->field[2]->store(tables->view_name.str, tables->view_name.length,
+ cs);
+ table->field[3]->store(tables->query.str, tables->query.length, cs);
+
+ if (tables->with_check != VIEW_CHECK_NONE)
+ {
+ if (tables->with_check == VIEW_CHECK_LOCAL)
+ table->field[4]->store("LOCAL", 5, cs);
+ else
+ table->field[4]->store("CASCADED", 8, cs);
+ }
+ else
+ table->field[4]->store("NONE", 4, cs);
+
+ if (tables->updatable_view)
+ table->field[5]->store("YES", 3, cs);
+ else
+ table->field[5]->store("NO", 2, cs);
+ DBUG_RETURN(schema_table_store_record(thd, table));
}
}
- send_eof(thd);
+ else
+ {
+ if (tables->view)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ thd->net.last_errno, thd->net.last_error);
+ thd->clear_error();
+ }
DBUG_RETURN(0);
-err:
- DBUG_RETURN(1);
}
-
-int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
- enum enum_var_type value_type,
- pthread_mutex_t *mutex)
+bool store_constraints(THD *thd, TABLE *table, const char *db,
+ const char *tname, const char *key_name,
+ uint key_len, const char *con_type, uint con_len)
{
- char buff[1024];
- List<Item> field_list;
- Protocol *protocol= thd->protocol;
- LEX_STRING null_lex_str;
- DBUG_ENTER("mysqld_show");
+ CHARSET_INFO *cs= system_charset_info;
+ restore_record(table, s->default_values);
+ table->field[1]->store(db, strlen(db), cs);
+ table->field[2]->store(key_name, key_len, cs);
+ table->field[3]->store(db, strlen(db), cs);
+ table->field[4]->store(tname, strlen(tname), cs);
+ table->field[5]->store(con_type, con_len, cs);
+ return schema_table_store_record(thd, table);
+}
- field_list.push_back(new Item_empty_string("Variable_name",30));
- field_list.push_back(new Item_empty_string("Value",256));
- if (protocol->send_fields(&field_list,1))
- DBUG_RETURN(1); /* purecov: inspected */
- null_lex_str.str= 0; // For sys_var->value_ptr()
- null_lex_str.length= 0;
- pthread_mutex_lock(mutex);
- for (; variables->name; variables++)
+static int get_schema_constraints_record(THD *thd, struct st_table_list *tables,
+ TABLE *table, bool res,
+ const char *base_name,
+ const char *file_name)
+{
+ DBUG_ENTER("get_schema_constraints_record");
+ if (res)
{
- if (!(wild && wild[0] && wild_case_compare(system_charset_info,
- variables->name,wild)))
+ if (!tables->view)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ thd->net.last_errno, thd->net.last_error);
+ thd->clear_error();
+ DBUG_RETURN(0);
+ }
+ else if (!tables->view)
+ {
+ List<FOREIGN_KEY_INFO> f_key_list;
+ TABLE *show_table= tables->table;
+ KEY *key_info=show_table->key_info;
+ uint primary_key= show_table->s->primary_key;
+ show_table->file->info(HA_STATUS_VARIABLE |
+ HA_STATUS_NO_LOCK |
+ HA_STATUS_TIME);
+ for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
{
- protocol->prepare_for_resend();
- protocol->store(variables->name, system_charset_info);
- SHOW_TYPE show_type=variables->type;
- char *value=variables->value;
- const char *pos, *end;
- long nr;
+ if (i != primary_key && !(key_info->flags & HA_NOSAME))
+ continue;
- if (show_type == SHOW_SYS)
+ if (i == primary_key && !strcmp(key_info->name, primary_key_name))
{
- show_type= ((sys_var*) value)->type();
- value= (char*) ((sys_var*) value)->value_ptr(thd, value_type,
- &null_lex_str);
+ if (store_constraints(thd, table, base_name, file_name, key_info->name,
+ strlen(key_info->name), "PRIMARY KEY", 11))
+ DBUG_RETURN(1);
}
+ else if (key_info->flags & HA_NOSAME)
+ {
+ if (store_constraints(thd, table, base_name, file_name, key_info->name,
+ strlen(key_info->name), "UNIQUE", 6))
+ DBUG_RETURN(1);
+ }
+ }
- pos= end= buff;
- switch (show_type) {
- case SHOW_LONG:
- case SHOW_LONG_CONST:
- end= int10_to_str(*(long*) value, buff, 10);
- break;
- case SHOW_LONGLONG:
- end= longlong10_to_str(*(longlong*) value, buff, 10);
- break;
- case SHOW_HA_ROWS:
- end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
- break;
- case SHOW_BOOL:
- end= strmov(buff, *(bool*) value ? "ON" : "OFF");
- break;
- case SHOW_MY_BOOL:
- end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
- break;
- case SHOW_INT_CONST:
- case SHOW_INT:
- end= int10_to_str((long) *(uint32*) value, buff, 10);
- break;
- case SHOW_HAVE:
+ show_table->file->get_foreign_key_list(thd, &f_key_list);
+ FOREIGN_KEY_INFO *f_key_info;
+ List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
+ while ((f_key_info=it++))
+ {
+ if (store_constraints(thd, table, base_name, file_name,
+ f_key_info->forein_id->str,
+ strlen(f_key_info->forein_id->str),
+ "FOREIGN KEY", 11))
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(res);
+}
+
+
+void store_key_column_usage(TABLE *table, const char*db, const char *tname,
+ const char *key_name, uint key_len,
+ const char *con_type, uint con_len, longlong idx)
+{
+ CHARSET_INFO *cs= system_charset_info;
+ table->field[1]->store(db, strlen(db), cs);
+ table->field[2]->store(key_name, key_len, cs);
+ table->field[4]->store(db, strlen(db), cs);
+ table->field[5]->store(tname, strlen(tname), cs);
+ table->field[6]->store(con_type, con_len, cs);
+ table->field[7]->store((longlong) idx);
+}
+
+
+static int get_schema_key_column_usage_record(THD *thd,
+ struct st_table_list *tables,
+ TABLE *table, bool res,
+ const char *base_name,
+ const char *file_name)
+{
+ DBUG_ENTER("get_schema_key_column_usage_record");
+ if (res)
+ {
+ if (!tables->view)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ thd->net.last_errno, thd->net.last_error);
+ thd->clear_error();
+ DBUG_RETURN(0);
+ }
+ else if (!tables->view)
+ {
+ List<FOREIGN_KEY_INFO> f_key_list;
+ TABLE *show_table= tables->table;
+ KEY *key_info=show_table->key_info;
+ uint primary_key= show_table->s->primary_key;
+ show_table->file->info(HA_STATUS_VARIABLE |
+ HA_STATUS_NO_LOCK |
+ HA_STATUS_TIME);
+ for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
+ {
+ if (i != primary_key && !(key_info->flags & HA_NOSAME))
+ continue;
+ uint f_idx= 0;
+ KEY_PART_INFO *key_part= key_info->key_part;
+ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
{
- SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
- pos= show_comp_option_name[(int) tmp];
- end= strend(pos);
- break;
+ if (key_part->field)
+ {
+ f_idx++;
+ restore_record(table, s->default_values);
+ store_key_column_usage(table, base_name, file_name,
+ key_info->name,
+ strlen(key_info->name),
+ key_part->field->field_name,
+ strlen(key_part->field->field_name),
+ (longlong) f_idx);
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(1);
+ }
}
- case SHOW_CHAR:
+ }
+
+ show_table->file->get_foreign_key_list(thd, &f_key_list);
+ FOREIGN_KEY_INFO *f_key_info;
+ List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
+ while ((f_key_info= it++))
+ {
+ LEX_STRING *f_info;
+ List_iterator_fast<LEX_STRING> it(f_key_info->foreign_fields),
+ it1(f_key_info->referenced_fields);
+ uint f_idx= 0;
+ while ((f_info= it++))
{
- if (!(pos= value))
- pos= "";
- end= strend(pos);
- break;
- }
- case SHOW_STARTTIME:
- nr= (long) (thd->query_start() - start_time);
- end= int10_to_str(nr, buff, 10);
- break;
- case SHOW_QUESTION:
- end= int10_to_str((long) thd->query_id, buff, 10);
- break;
-#ifdef HAVE_REPLICATION
- case SHOW_RPL_STATUS:
- end= strmov(buff, rpl_status_type[(int)rpl_status]);
- break;
- case SHOW_SLAVE_RUNNING:
+ it1++; // Ignore r_info
+ f_idx++;
+ restore_record(table, s->default_values);
+ store_key_column_usage(table, base_name, file_name,
+ f_key_info->forein_id->str,
+ f_key_info->forein_id->length,
+ f_info->str, f_info->length,
+ (longlong) f_idx);
+ table->field[8]->store((longlong) f_idx);
+ table->field[8]->set_notnull();
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ DBUG_RETURN(res);
+}
+
+
+int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ DBUG_ENTER("fill_open_tables");
+ const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
+ TABLE *table= tables->table;
+ CHARSET_INFO *cs= system_charset_info;
+ OPEN_TABLE_LIST *open_list;
+ if (!(open_list=list_open_tables(thd,wild)) && thd->is_fatal_error)
+ DBUG_RETURN(1);
+
+ for (; open_list ; open_list=open_list->next)
+ {
+ restore_record(table, s->default_values);
+ table->field[0]->store(open_list->db, strlen(open_list->db), cs);
+ table->field[1]->store(open_list->table, strlen(open_list->table), cs);
+ table->field[2]->store((longlong) open_list->in_use);
+ table->field[3]->store((longlong) open_list->locked);
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ DBUG_ENTER("fill_variables");
+ int res= 0;
+ LEX *lex= thd->lex;
+ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ res= show_status_array(thd, wild, init_vars,
+ lex->option_type, 0, "", tables->table);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ DBUG_RETURN(res);
+}
+
+
+int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ DBUG_ENTER("fill_status");
+ LEX *lex= thd->lex;
+ const char *wild= lex->wild ? lex->wild->ptr() : NullS;
+ int res= 0;
+ STATUS_VAR tmp;
+ ha_update_statistics(); /* Export engines statistics */
+ pthread_mutex_lock(&LOCK_status);
+ if (lex->option_type == OPT_GLOBAL)
+ calc_sum_of_all_status(&tmp);
+ res= show_status_array(thd, wild, status_vars, OPT_GLOBAL,
+ (lex->option_type == OPT_GLOBAL ?
+ &tmp: &thd->status_var), "",tables->table);
+ pthread_mutex_unlock(&LOCK_status);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Find schema_tables elment by name
+
+ SYNOPSIS
+ find_schema_table()
+ thd thread handler
+ table_name table name
+
+ RETURN
+ 0 table not found
+ # pointer to 'shema_tables' element
+*/
+
+ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
+{
+ ST_SCHEMA_TABLE *schema_table= schema_tables;
+ for ( ; schema_table->table_name; schema_table++)
+ {
+ if (!my_strcasecmp(system_charset_info,
+ schema_table->table_name,
+ table_name))
+ return schema_table;
+ }
+ return 0;
+}
+
+
+ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx)
+{
+ return &schema_tables[schema_table_idx];
+}
+
+
+/*
+ Create information_schema table using schema_table data
+
+ SYNOPSIS
+ create_schema_table()
+ thd thread handler
+ schema_table pointer to 'shema_tables' element
+
+ RETURN
+ # Pointer to created table
+ 0 Can't create table
+*/
+
+TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
+{
+ int field_count= 0;
+ Item *item;
+ TABLE *table;
+ List<Item> field_list;
+ ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
+ ST_FIELD_INFO *fields_info= schema_table->fields_info;
+ CHARSET_INFO *cs= system_charset_info;
+ DBUG_ENTER("create_schema_table");
+
+ for ( ; fields_info->field_name; fields_info++)
+ {
+ switch (fields_info->field_type) {
+ case MYSQL_TYPE_LONG:
+ if (!(item= new Item_int(fields_info->field_name,
+ fields_info->value,
+ fields_info->field_length)))
{
- pthread_mutex_lock(&LOCK_active_mi);
- end= strmov(buff, (active_mi->slave_running &&
- active_mi->rli.slave_running) ? "ON" : "OFF");
- pthread_mutex_unlock(&LOCK_active_mi);
- break;
+ DBUG_RETURN(0);
}
- case SHOW_SLAVE_RETRIED_TRANS:
+ break;
+ case MYSQL_TYPE_TIMESTAMP:
+ if (!(item=new Item_datetime(fields_info->field_name)))
{
- /*
- TODO: in 5.1 with multimaster, have one such counter per line in SHOW
- SLAVE STATUS, and have the sum over all lines here.
- */
- pthread_mutex_lock(&LOCK_active_mi);
- pthread_mutex_lock(&active_mi->rli.data_lock);
- end= int10_to_str(active_mi->rli.retried_trans, buff, 10);
- pthread_mutex_unlock(&active_mi->rli.data_lock);
- pthread_mutex_unlock(&LOCK_active_mi);
- break;
+ DBUG_RETURN(0);
}
-#endif /* HAVE_REPLICATION */
- case SHOW_OPENTABLES:
- end= int10_to_str((long) cached_tables(), buff, 10);
- break;
- case SHOW_CHAR_PTR:
+ break;
+ default:
+ /* this should be changed when Item_empty_string is fixed(in 4.1) */
+ if (!(item= new Item_empty_string("", 0, cs)))
{
- if (!(pos= *(char**) value))
- pos= "";
- end= strend(pos);
- break;
+ DBUG_RETURN(0);
}
-#ifdef HAVE_OPENSSL
- /* First group - functions relying on CTX */
- case SHOW_SSL_CTX_SESS_ACCEPT:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_accept(ssl_acceptor_fd->
- ssl_context)),
- buff, 10);
- break;
- case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_accept_good(ssl_acceptor_fd->
- ssl_context)),
- buff, 10);
- break;
- case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect_good(ssl_acceptor_fd->
- ssl_context)),
- buff, 10);
- break;
- case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)),
- buff, 10);
- break;
- case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)),
- buff, 10);
- break;
- case SHOW_SSL_CTX_SESS_CB_HITS:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
- ssl_context)),
- buff, 10);
- break;
- case SHOW_SSL_CTX_SESS_HITS:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_hits(ssl_acceptor_fd->
- ssl_context)),
- buff, 10);
- break;
- case SHOW_SSL_CTX_SESS_CACHE_FULL:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_cache_full(ssl_acceptor_fd->
- ssl_context)),
- buff, 10);
- break;
- case SHOW_SSL_CTX_SESS_MISSES:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_misses(ssl_acceptor_fd->
- ssl_context)),
- buff, 10);
- break;
- case SHOW_SSL_CTX_SESS_TIMEOUTS:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)),
- buff,10);
- break;
- case SHOW_SSL_CTX_SESS_NUMBER:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)),
- buff,10);
- break;
- case SHOW_SSL_CTX_SESS_CONNECT:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)),
- buff,10);
- break;
- case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)),
- buff,10);
- break;
- case SHOW_SSL_CTX_GET_VERIFY_MODE:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)),
- buff,10);
- break;
- case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
- end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)),
- buff,10);
- break;
- case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
- if (!ssl_acceptor_fd)
- {
- pos= "NONE";
- end= pos+4;
- break;
- }
- switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context))
- {
- case SSL_SESS_CACHE_OFF:
- pos= "OFF";
- break;
- case SSL_SESS_CACHE_CLIENT:
- pos= "CLIENT";
- break;
- case SSL_SESS_CACHE_SERVER:
- pos= "SERVER";
- break;
- case SSL_SESS_CACHE_BOTH:
- pos= "BOTH";
- break;
- case SSL_SESS_CACHE_NO_AUTO_CLEAR:
- pos= "NO_AUTO_CLEAR";
- break;
- case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
- pos= "NO_INTERNAL_LOOKUP";
- break;
- default:
- pos= "Unknown";
- break;
- }
- end= strend(pos);
- break;
- /* First group - functions relying on SSL */
- case SHOW_SSL_GET_VERSION:
- pos= (thd->net.vio->ssl_arg ?
- SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
- end= strend(pos);
- break;
- case SHOW_SSL_SESSION_REUSED:
- end= int10_to_str((long) (thd->net.vio->ssl_arg ?
- SSL_session_reused((SSL*) thd->net.vio->
- ssl_arg) :
- 0),
- buff, 10);
- break;
- case SHOW_SSL_GET_DEFAULT_TIMEOUT:
- end= int10_to_str((long) (thd->net.vio->ssl_arg ?
- SSL_get_default_timeout((SSL*) thd->net.vio->
- ssl_arg) :
- 0),
- buff, 10);
- break;
- case SHOW_SSL_GET_VERIFY_MODE:
- end= int10_to_str((long) (thd->net.vio->ssl_arg ?
- SSL_get_verify_mode((SSL*) thd->net.vio->
- ssl_arg):
- 0),
- buff, 10);
- break;
- case SHOW_SSL_GET_VERIFY_DEPTH:
- end= int10_to_str((long) (thd->net.vio->ssl_arg ?
- SSL_get_verify_depth((SSL*) thd->net.vio->
- ssl_arg):
- 0),
- buff, 10);
- break;
- case SHOW_SSL_GET_CIPHER:
- pos= (thd->net.vio->ssl_arg ?
- SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" );
- end= strend(pos);
- break;
- case SHOW_SSL_GET_CIPHER_LIST:
- if (thd->net.vio->ssl_arg)
- {
- char *to= buff;
- for (int i=0 ; i++ ;)
- {
- const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i);
- if (p == NULL)
- break;
- to= strmov(to, p);
- *to++= ':';
- }
- if (to != buff)
- to--; // Remove last ':'
- end= to;
- }
- break;
+ item->max_length= fields_info->field_length * cs->mbmaxlen;
+ item->set_name(fields_info->field_name,
+ strlen(fields_info->field_name), cs);
+ break;
+ }
+ field_list.push_back(item);
+ item->maybe_null= fields_info->maybe_null;
+ field_count++;
+ }
+ TMP_TABLE_PARAM *tmp_table_param =
+ (TMP_TABLE_PARAM*) (thd->calloc(sizeof(TMP_TABLE_PARAM)));
+ tmp_table_param->init();
+ tmp_table_param->table_charset= cs;
+ tmp_table_param->field_count= field_count;
+ tmp_table_param->schema_table= 1;
+ SELECT_LEX *select_lex= thd->lex->current_select;
+ if (!(table= create_tmp_table(thd, tmp_table_param,
+ field_list, (ORDER*) 0, 0, 0,
+ (select_lex->options | thd->options |
+ TMP_TABLE_ALL_COLUMNS),
+ HA_POS_ERROR, table_list->alias)))
+ DBUG_RETURN(0);
+ table_list->schema_table_param= tmp_table_param;
+ DBUG_RETURN(table);
+}
-#endif /* HAVE_OPENSSL */
- case SHOW_KEY_CACHE_LONG:
- case SHOW_KEY_CACHE_CONST_LONG:
- value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache;
- end= int10_to_str(*(long*) value, buff, 10);
- break;
- case SHOW_UNDEF: // Show never happen
- case SHOW_SYS:
- break; // Return empty string
- default:
- break;
+
+/*
+ For old SHOW compatibility. It is used when
+ old SHOW doesn't have generated column names
+ Make list of fields for SHOW
+
+ SYNOPSIS
+ make_old_format()
+ thd thread handler
+ schema_table pointer to 'schema_tables' element
+
+ RETURN
+ -1 errror
+ 0 success
+*/
+
+int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
+{
+ ST_FIELD_INFO *field_info= schema_table->fields_info;
+ for ( ; field_info->field_name; field_info++)
+ {
+ if (field_info->old_name)
+ {
+ Item_field *field= new Item_field(NullS, NullS, field_info->field_name);
+ if (field)
+ {
+ field->set_name(field_info->old_name,
+ strlen(field_info->old_name),
+ system_charset_info);
+ if (add_item_to_list(thd, field))
+ return 1;
}
- if (protocol->store(pos, (uint32) (end - pos), system_charset_info) ||
- protocol->write())
- goto err; /* purecov: inspected */
}
}
- pthread_mutex_unlock(mutex);
- send_eof(thd);
+ return 0;
+}
+
+
+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;
+
+ 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);
+ if (!field || add_item_to_list(thd, field))
+ return 1;
+ buffer.length(0);
+ buffer.append(field_info->old_name);
+ if (lex->wild && lex->wild->ptr())
+ {
+ buffer.append(" (");
+ buffer.append(lex->wild->ptr());
+ buffer.append(")");
+ }
+ field->set_name(buffer.ptr(), buffer.length(), system_charset_info);
+ }
+ return 0;
+}
+
+
+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;
+
+ ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
+ buffer.length(0);
+ buffer.append(field_info->old_name);
+ buffer.append(lex->select_lex.db);
+ if (lex->wild && lex->wild->ptr())
+ {
+ buffer.append(" (");
+ buffer.append(lex->wild->ptr());
+ buffer.append(")");
+ }
+ Item_field *field= new Item_field(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);
+ if (thd->lex->verbose)
+ {
+ 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);
+ if (add_item_to_list(thd, field))
+ return 1;
+ field->set_name(field_info->old_name, strlen(field_info->old_name),
+ system_charset_info);
+ }
+ return 0;
+}
+
+
+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;
+ for (; *field_num >= 0; field_num++)
+ {
+ field_info= &schema_table->fields_info[*field_num];
+ if (!thd->lex->verbose && (*field_num == 13 ||
+ *field_num == 17 ||
+ *field_num == 18))
+ continue;
+ Item_field *field= new Item_field(NullS, NullS, field_info->field_name);
+ if (field)
+ {
+ field->set_name(field_info->old_name,
+ strlen(field_info->old_name),
+ system_charset_info);
+ if (add_item_to_list(thd, field))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+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;
+ 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);
+ if (field)
+ {
+ field->set_name(field_info->old_name,
+ strlen(field_info->old_name),
+ system_charset_info);
+ if (add_item_to_list(thd, field))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+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;
+ 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);
+ if (field)
+ {
+ field->set_name(field_info->old_name,
+ strlen(field_info->old_name),
+ system_charset_info);
+ if (add_item_to_list(thd, field))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ Create information_schema table
+
+ SYNOPSIS
+ mysql_schema_table()
+ thd thread handler
+ lex pointer to LEX
+ table_list pointer to table_list
+
+ RETURN
+ 0 success
+ 1 error
+*/
+
+int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
+{
+ TABLE *table;
+ DBUG_ENTER("mysql_schema_table");
+ if (!(table= table_list->schema_table->create_table(thd, table_list)))
+ {
+ DBUG_RETURN(1);
+ }
+ table->s->tmp_table= TMP_TABLE;
+ table->grant.privilege= SELECT_ACL;
+ /*
+ This test is necessary to make
+ case insensitive file systems +
+ upper case table names(information schema tables) +
+ views
+ working correctly
+ */
+ if (table_list->schema_table_name)
+ table->alias_name_used= my_strcasecmp(table_alias_charset,
+ table_list->schema_table_name,
+ table_list->alias);
+ table_list->table_name= (char*) table->s->table_name;
+ table_list->table_name_length= strlen(table->s->table_name);
+ table_list->table= table;
+ table->next= thd->derived_tables;
+ thd->derived_tables= table;
+ table_list->select_lex->options |= OPTION_SCHEMA_TABLE;
+ lex->safe_to_cache_query= 0;
+
+ if (table_list->schema_table_reformed) // show command
+ {
+ SELECT_LEX *sel= lex->current_select;
+ uint i= 0;
+ Item *item;
+ Field_translator *transl;
+
+ if (table_list->field_translation)
+ {
+ Field_translator *end= table_list->field_translation +
+ sel->item_list.elements;
+ for (transl= table_list->field_translation; transl < end; transl++)
+ {
+ if (!transl->item->fixed &&
+ transl->item->fix_fields(thd, table_list, &transl->item))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+ List_iterator_fast<Item> it(sel->item_list);
+ if (!(transl=
+ (Field_translator*)(thd->current_arena->
+ alloc(sel->item_list.elements *
+ sizeof(Field_translator)))))
+ {
+ DBUG_RETURN(1);
+ }
+ while ((item= it++))
+ {
+ char *name= item->name;
+ transl[i].item= item;
+ if (!item->fixed && item->fix_fields(thd, table_list, &transl[i].item))
+ DBUG_RETURN(1);
+ transl[i++].name= name;
+ }
+ table_list->field_translation= transl;
+ }
+
DBUG_RETURN(0);
+}
+
+
+/*
+ Generate select from information_schema table
+
+ SYNOPSIS
+ make_schema_select()
+ thd thread handler
+ sel pointer to SELECT_LEX
+ schema_table_idx index of 'schema_tables' element
+
+ RETURN
+ 0 success
+ 1 error
+*/
- err:
- pthread_mutex_unlock(mutex);
- DBUG_RETURN(1);
+int make_schema_select(THD *thd, SELECT_LEX *sel,
+ enum enum_schema_tables schema_table_idx)
+{
+ 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
+ */
+ make_lex_string(thd, &db, information_schema_name.str,
+ 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 */
+ !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
+ 0, 0, TL_READ, (List<String> *) 0,
+ (List<String> *) 0))
+ {
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
}
+
+/*
+ Fill temporary schema tables before SELECT
+
+ SYNOPSIS
+ get_schema_tables_result()
+ join join which use schema tables
+
+ RETURN
+ FALSE success
+ TRUE error
+*/
+
+bool get_schema_tables_result(JOIN *join)
+{
+ JOIN_TAB *tmp_join_tab= join->join_tab+join->tables;
+ THD *thd= join->thd;
+ LEX *lex= thd->lex;
+ bool result= 0;
+ DBUG_ENTER("get_schema_tables_result");
+
+ thd->no_warnings_for_error= 1;
+ for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
+ {
+ if (!tab->table || !tab->table->pos_in_table_list)
+ break;
+
+ TABLE_LIST *table_list= tab->table->pos_in_table_list;
+ if (table_list->schema_table && thd->fill_derived_tables())
+ {
+ TABLE_LIST **query_tables_last= lex->query_tables_last;
+ TABLE *old_derived_tables= thd->derived_tables;
+ MYSQL_LOCK *sql_lock= thd->lock;
+ lex->sql_command= SQLCOM_SHOW_FIELDS;
+ DBUG_ASSERT(!*query_tables_last);
+ if (&lex->unit != lex->current_select->master_unit()) // is subselect
+ {
+ table_list->table->file->extra(HA_EXTRA_RESET_STATE);
+ table_list->table->file->delete_all_rows();
+ free_io_cache(table_list->table);
+ filesort_free_buffers(table_list->table);
+ }
+ else
+ table_list->table->file->records= 0;
+
+ thd->derived_tables= 0;
+ thd->lock=0;
+ if (table_list->schema_table->fill_table(thd, table_list,
+ tab->select_cond))
+ result= 1;
+ thd->lock= sql_lock;
+ lex->sql_command= SQLCOM_SELECT;
+ thd->derived_tables= old_derived_tables;
+ lex->query_tables_last= query_tables_last;
+ *query_tables_last= 0;
+ }
+ }
+ thd->no_warnings_for_error= 0;
+ DBUG_RETURN(result);
+}
+
+
+ST_FIELD_INFO schema_fields_info[]=
+{
+ {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"SCHEMA_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
+ {"DEFAULT_CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"SQL_PATH", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO tables_fields_info[]=
+{
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
+ {"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ENGINE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine"},
+ {"VERSION", 21 , MYSQL_TYPE_LONG, 0, 1, "Version"},
+ {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format"},
+ {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 1, "Rows"},
+ {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Avg_row_length"},
+ {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_length"},
+ {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Max_data_length"},
+ {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Index_length"},
+ {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
+ {"AUTO_INCREMENT", 21 , MYSQL_TYPE_LONG, 0, 1, "Auto_increment"},
+ {"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Create_time"},
+ {"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Update_time"},
+ {"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Check_time"},
+ {"TABLE_COLLATION", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
+ {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
+ {"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options"},
+ {"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO columns_fields_info[]=
+{
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Field"},
+ {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
+ {"COLUMN_DEFAULT", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Default"},
+ {"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
+ {"DATA_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
+ {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type"},
+ {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key"},
+ {"EXTRA", 20, MYSQL_TYPE_STRING, 0, 0, "Extra"},
+ {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges"},
+ {"COLUMN_COMMENT", 255, MYSQL_TYPE_STRING, 0, 0, "Comment"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO charsets_fields_info[]=
+{
+ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
+ {"DEFAULT_COLLATE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Default collation"},
+ {"DESCRIPTION", 60, MYSQL_TYPE_STRING, 0, 0, "Description"},
+ {"MAXLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Maxlen"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO collation_fields_info[]=
+{
+ {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Collation"},
+ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
+ {"ID", 11, MYSQL_TYPE_LONG, 0, 0, "Id"},
+ {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default"},
+ {"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled"},
+ {"SORTLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Sortlen"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO coll_charset_app_fields_info[]=
+{
+ {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO proc_fields_info[]=
+{
+ {"SPECIFIC_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"ROUTINE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"},
+ {"ROUTINE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
+ {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type"},
+ {"DTD_IDENTIFIER", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"ROUTINE_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ROUTINE_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"EXTERNAL_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"EXTERNAL_LANGUAGE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"PARAMETER_STYLE", 8, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"IS_DETERMINISTIC", 3, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"SQL_DATA_ACCESS", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"SQL_PATH", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, "Security_type"},
+ {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, "Created"},
+ {"LAST_ALTERED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, "Modified"},
+ {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ROUTINE_COMMENT", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Comment"},
+ {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO stat_fields_info[]=
+{
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
+ {"NON_UNIQUE", 1, MYSQL_TYPE_LONG, 0, 0, "Non_unique"},
+ {"INDEX_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Key_name"},
+ {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONG, 0, 0, "Seq_in_index"},
+ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name"},
+ {"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation"},
+ {"CARDINALITY", 21, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
+ {"SUB_PART", 3, MYSQL_TYPE_LONG, 0, 1, "Sub_part"},
+ {"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed"},
+ {"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
+ {"INDEX_TYPE", 16, MYSQL_TYPE_STRING, 0, 0, "Index_type"},
+ {"COMMENT", 16, MYSQL_TYPE_STRING, 0, 1, "Comment"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO view_fields_info[]=
+{
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO user_privileges_fields_info[]=
+{
+ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO schema_privileges_fields_info[]=
+{
+ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO table_privileges_fields_info[]=
+{
+ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO column_privileges_fields_info[]=
+{
+ {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO table_constraints_fields_info[]=
+{
+ {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO key_column_usage_fields_info[]=
+{
+ {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONG, 0, 0, 0},
+ {"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONG, 0, 1, 0},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO table_names_fields_info[]=
+{
+ {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Tables_in_"},
+ {"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO open_tables_fields_info[]=
+{
+ {"Database", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
+ {"Table",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
+ {"In_use", 1, MYSQL_TYPE_LONG, 0, 0, "In_use"},
+ {"Name_locked", 4, MYSQL_TYPE_LONG, 0, 0, "Name_locked"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+ST_FIELD_INFO variables_fields_info[]=
+{
+ {"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"},
+ {"Value", 255, MYSQL_TYPE_STRING, 0, 0, "Value"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
+/*
+ Description of ST_FIELD_INFO in table.h
+*/
+
+ST_SCHEMA_TABLE schema_tables[]=
+{
+ {"SCHEMATA", schema_fields_info, create_schema_table,
+ fill_schema_shemata, make_schemata_old_format, 0, 1, -1, 0},
+ {"TABLES", tables_fields_info, create_schema_table,
+ get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0},
+ {"COLUMNS", columns_fields_info, create_schema_table,
+ get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0},
+ {"CHARACTER_SETS", charsets_fields_info, create_schema_table,
+ fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0},
+ {"COLLATIONS", collation_fields_info, create_schema_table,
+ fill_schema_collation, make_old_format, 0, -1, -1, 0},
+ {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
+ create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0},
+ {"ROUTINES", proc_fields_info, create_schema_table,
+ fill_schema_proc, make_proc_old_format, 0, -1, -1, 0},
+ {"STATISTICS", stat_fields_info, create_schema_table,
+ get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0},
+ {"VIEWS", view_fields_info, create_schema_table,
+ get_all_tables, 0, get_schema_views_record, 1, 2, 0},
+ {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table,
+ fill_schema_user_privileges, 0, 0, -1, -1, 0},
+ {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table,
+ fill_schema_schema_privileges, 0, 0, -1, -1, 0},
+ {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
+ fill_schema_table_privileges, 0, 0, -1, -1, 0},
+ {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
+ fill_schema_column_privileges, 0, 0, -1, -1, 0},
+ {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table,
+ get_all_tables, 0, get_schema_constraints_record, 3, 4, 0},
+ {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
+ get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0},
+ {"TABLE_NAMES", table_names_fields_info, create_schema_table,
+ get_all_tables, make_table_names_old_format, 0, 1, 2, 1},
+ {"OPEN_TABLES", open_tables_fields_info, create_schema_table,
+ fill_open_tables, make_old_format, 0, -1, -1, 1},
+ {"STATUS", variables_fields_info, create_schema_table, fill_status,
+ make_old_format, 0, -1, -1, 1},
+ {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
+ make_old_format, 0, -1, -1, 1},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+
#ifdef __GNUC__
template class List_iterator_fast<char>;
template class List<char>;
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
index 9f95ffa4884..1831c4a2f3d 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -78,3 +78,4 @@ int merge_buffers(SORTPARAM *param,IO_CACHE *from_file,
IO_CACHE *to_file, uchar *sort_buffer,
BUFFPEK *lastbuff,BUFFPEK *Fb,
BUFFPEK *Tb,int flag);
+void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length);
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index c1701e7e9bf..0424723d97f 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -684,6 +684,19 @@ void String::qs_append(double *d)
qs_append(ld);
}
+void String::qs_append(int i)
+{
+ char *buff= Ptr + str_length;
+ char *end= int10_to_str(i, buff, -10);
+ str_length+= (int) (end-buff);
+}
+
+void String::qs_append(uint i)
+{
+ char *buff= Ptr + str_length;
+ char *end= int10_to_str(i, buff, 10);
+ str_length+= (int) (end-buff);
+}
/*
Compare strings according to collation, without end space.
@@ -707,8 +720,8 @@ void String::qs_append(double *d)
int sortcmp(const String *s,const String *t, CHARSET_INFO *cs)
{
return cs->coll->strnncollsp(cs,
- (unsigned char *) s->ptr(),s->length(),
- (unsigned char *) t->ptr(),t->length());
+ (unsigned char *) s->ptr(),s->length(),
+ (unsigned char *) t->ptr(),t->length(), 0);
}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 8dff5558120..7ece9885040 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -72,9 +72,9 @@ public:
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr_arg,size_t size)
- {}
+ { TRASH(ptr_arg, size); }
static void operator delete(void *ptr_arg, MEM_ROOT *mem_root)
- {}
+ { /* never called */ }
~String() { free(); }
inline void set_charset(CHARSET_INFO *charset) { str_charset= charset; }
@@ -84,6 +84,7 @@ public:
inline char& operator [] (uint32 i) const { return Ptr[i]; }
inline void length(uint32 len) { str_length=len ; }
inline bool is_empty() { return (str_length == 0); }
+ inline void mark_as_const() { Alloced_length= 0;}
inline const char *ptr() const { return Ptr; }
inline char *c_ptr()
{
@@ -141,6 +142,34 @@ public:
bool set(longlong num, CHARSET_INFO *cs);
bool set(ulonglong num, CHARSET_INFO *cs);
bool set(double num,uint decimals, CHARSET_INFO *cs);
+
+ /*
+ PMG 2004.11.12
+ This is a method that works the same as perl's "chop". It simply
+ drops the last character of a string. This is useful in the case
+ of the federated storage handler where I'm building a unknown
+ number, list of values and fields to be used in a sql insert
+ statement to be run on the remote server, and have a comma after each.
+ When the list is complete, I "chop" off the trailing comma
+
+ ex.
+ String stringobj;
+ stringobj.append("VALUES ('foo', 'fi', 'fo',");
+ stringobj.chop();
+ stringobj.append(")");
+
+ In this case, the value of string was:
+
+ VALUES ('foo', 'fi', 'fo',
+ VALUES ('foo', 'fi', 'fo'
+ VALUES ('foo', 'fi', 'fo')
+
+ */
+ inline void chop()
+ {
+ Ptr[str_length--]= '\0';
+ }
+
inline void free()
{
if (alloced)
@@ -177,10 +206,6 @@ public:
}
}
}
- inline void shrink_to_length()
- {
- Alloced_length= str_length;
- }
bool is_alloced() { return alloced; }
inline String& operator = (const String &s)
{
@@ -293,6 +318,8 @@ public:
Ptr[str_length]= c;
str_length++;
}
+ void qs_append(int i);
+ void qs_append(uint i);
/* Inline (general) functions used by the protocol functions */
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f3f8511026b..18c90d549ec 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
/* drop and alter of tables */
#include "mysql_priv.h"
@@ -58,15 +57,15 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
Wait if global_read_lock (FLUSH TABLES WITH READ LOCK) is set.
RETURN
- 0 ok. In this case ok packet is sent to user
- -1 Error (Error message given but not sent to user)
+ FALSE OK. In this case ok packet is sent to user
+ TRUE Error
*/
-int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
- my_bool drop_temporary)
+bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
+ my_bool drop_temporary)
{
- int error= 0;
+ bool error= FALSE, need_start_waiters= FALSE;
DBUG_ENTER("mysql_rm_table");
/* mark for close and remove all cached entries */
@@ -75,24 +74,19 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
thd->mysys_var->current_cond= &COND_refresh;
VOID(pthread_mutex_lock(&LOCK_open));
- if (!drop_temporary && global_read_lock)
+ if (!drop_temporary)
{
- if (thd->global_read_lock)
+ if ((error= wait_if_global_read_lock(thd, 0, 1)))
{
- my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0),
- tables->real_name);
- error= 1;
+ my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), tables->table_name);
goto err;
}
- while (global_read_lock && ! thd->killed)
- {
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
- }
-
+ else
+ need_start_waiters= TRUE;
}
- error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary, 0);
+ error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0);
- err:
+err:
pthread_mutex_unlock(&LOCK_open);
pthread_mutex_lock(&thd->mysys_var->mutex);
@@ -100,10 +94,13 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
thd->mysys_var->current_cond= 0;
pthread_mutex_unlock(&thd->mysys_var->mutex);
+ if (need_start_waiters)
+ start_waiting_global_read_lock(thd);
+
if (error)
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
send_ok(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -111,11 +108,12 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
delete (drop) tables.
SYNOPSIS
- mysql_rm_table_part2_with_lock()
- thd Thread handle
- tables List of tables to delete
- if_exists If 1, don't give error if one table doesn't exists
- dont_log_query Don't write query to log files
+ mysql_rm_table_part2_with_lock()
+ thd Thread handle
+ tables List of tables to delete
+ if_exists If 1, don't give error if one table doesn't exists
+ dont_log_query Don't write query to log files. This will also not
+ generate warnings if the handler files doesn't exists
NOTES
Works like documented in mysql_rm_table(), but don't check
@@ -135,8 +133,8 @@ int mysql_rm_table_part2_with_lock(THD *thd,
thd->mysys_var->current_cond= &COND_refresh;
VOID(pthread_mutex_lock(&LOCK_open));
- error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary,
- dont_log_query);
+ error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 1,
+ dont_log_query);
pthread_mutex_unlock(&LOCK_open);
@@ -158,7 +156,9 @@ int mysql_rm_table_part2_with_lock(THD *thd,
if_exists If set, don't give an error if table doesn't exists.
In this case we give an warning of level 'NOTE'
drop_temporary Only drop temporary tables
- dont_log_query Don't log the query
+ drop_view Allow to delete VIEW .frm
+ dont_log_query Don't write query to log files. This will also not
+ generate warnings if the handler files doesn't exists
TODO:
When logging to the binary log, we should log
@@ -177,7 +177,8 @@ int mysql_rm_table_part2_with_lock(THD *thd,
*/
int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
- bool drop_temporary, bool dont_log_query)
+ bool drop_temporary, bool drop_view,
+ bool dont_log_query)
{
TABLE_LIST *table;
char path[FN_REFLEN], *alias;
@@ -189,11 +190,14 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (lock_table_names(thd, tables))
DBUG_RETURN(1);
- for (table=tables ; table ; table=table->next)
+ /* Don't give warnings for not found errors, as we already generate notes */
+ thd->no_warnings_for_error= 1;
+
+ for (table= tables; table; table= table->next_local)
{
char *db=table->db;
mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL);
- if (!close_temporary_table(thd, db, table->real_name))
+ if (!close_temporary_table(thd, db, table->table_name))
{
tmp_table_deleted=1;
continue; // removed temporary table
@@ -202,28 +206,34 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
error=0;
if (!drop_temporary)
{
- abort_locked_tables(thd,db,table->real_name);
- while (remove_table_from_cache(thd,db,table->real_name) && !thd->killed)
+ abort_locked_tables(thd,db,table->table_name);
+ while (remove_table_from_cache(thd, db, table->table_name, 0) &&
+ !thd->killed)
{
dropping_tables++;
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
dropping_tables--;
}
- drop_locked_tables(thd,db,table->real_name);
+ drop_locked_tables(thd,db,table->table_name);
if (thd->killed)
+ {
+ thd->no_warnings_for_error= 0;
DBUG_RETURN(-1);
- alias= (lower_case_table_names == 2) ? table->alias : table->real_name;
+ }
+ alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
/* remove form file and isam files */
strxmov(path, mysql_data_home, "/", db, "/", alias, reg_ext, NullS);
(void) unpack_filename(path,path);
}
- if (drop_temporary ||
- (access(path,F_OK) && ha_create_table_from_engine(thd,db,alias,TRUE)))
+ if (drop_temporary ||
+ (access(path,F_OK) &&
+ ha_create_table_from_engine(thd,db,alias,TRUE)) ||
+ (!drop_view && mysql_frm_type(path) != FRMTYPE_TABLE))
{
if (if_exists)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
- table->real_name);
+ table->table_name);
else
error= 1;
}
@@ -232,27 +242,42 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
char *end;
db_type table_type= get_table_type(path);
*(end=fn_ext(path))=0; // Remove extension for delete
- error=ha_delete_table(table_type, path);
- if (error == ENOENT && if_exists)
- error = 0;
+ error= ha_delete_table(thd, table_type, path, table->table_name,
+ !dont_log_query);
+ if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && if_exists)
+ error= 0;
if (error == HA_ERR_ROW_IS_REFERENCED)
{
/* the table is referenced by a foreign key constraint */
foreign_key_error=1;
}
- if (!error || error == ENOENT)
+ if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE)
{
+ int new_error;
/* Delete the table definition file */
strmov(end,reg_ext);
- if (!(error=my_delete(path,MYF(MY_WME))))
+ if (!(new_error=my_delete(path,MYF(MY_WME))))
+ {
some_tables_deleted=1;
+ /*
+ Destroy triggers for this table if there are any.
+
+ We won't need this as soon as we will have new .FRM format,
+ in which we will store trigger definitions in the same .FRM
+ files as table descriptions.
+ */
+ strmov(end, triggers_file_ext);
+ if (!access(path, F_OK))
+ new_error= my_delete(path, MYF(MY_WME));
+ }
+ error|= new_error;
}
}
if (error)
{
if (wrong_tables.length())
wrong_tables.append(',');
- wrong_tables.append(String(table->real_name,system_charset_info));
+ wrong_tables.append(String(table->table_name,system_charset_info));
}
}
thd->tmp_table_used= tmp_table_deleted;
@@ -261,31 +286,26 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
{
if (!foreign_key_error)
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
- wrong_tables.c_ptr());
+ wrong_tables.c_ptr());
else
- my_error(ER_ROW_IS_REFERENCED, MYF(0));
+ my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
error= 1;
}
if (some_tables_deleted || tmp_table_deleted || !error)
{
query_cache_invalidate3(thd, tables, 0);
- if (!dont_log_query)
+ if (!dont_log_query && mysql_bin_log.is_open())
{
- mysql_update_log.write(thd, thd->query,thd->query_length);
- if (mysql_bin_log.is_open())
- {
- if (!error)
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length,
- tmp_table_deleted && !some_tables_deleted,
- FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ if (!error)
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
+ mysql_bin_log.write(&qinfo);
}
}
- unlock_table_names(thd, tables);
+ unlock_table_names(thd, tables, (TABLE_LIST*) 0);
+ thd->no_warnings_for_error= 0;
DBUG_RETURN(error);
}
@@ -302,7 +322,7 @@ int quick_rm_table(enum db_type base,const char *db,
error=1; /* purecov: inspected */
my_snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home, db, table_name);
unpack_filename(path,path);
- return ha_delete_table(base,path) || error;
+ return ha_delete_table(current_thd, base, path, table_name, 0) || error;
}
/*
@@ -425,6 +445,171 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
/*
+ Prepare a create_table instance for packing
+
+ SYNOPSIS
+ prepare_create_field()
+ sql_field field to prepare for packing
+ blob_columns count for BLOBs
+ timestamps count for timestamps
+ table_flags table flags
+
+ DESCRIPTION
+ This function prepares a create_field instance.
+ Fields such as pack_flag are valid after this call.
+
+ RETURN VALUES
+ 0 ok
+ 1 Error
+*/
+
+int prepare_create_field(create_field *sql_field,
+ uint *blob_columns,
+ int *timestamps, int *timestamps_with_niladic,
+ uint table_flags)
+{
+ DBUG_ENTER("prepare_field");
+
+ /*
+ This code came from mysql_prepare_table.
+ Indent preserved to make patching easier
+ */
+ DBUG_ASSERT(sql_field->charset);
+
+ switch (sql_field->sql_type) {
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ sql_field->pack_flag=FIELDFLAG_BLOB |
+ pack_length_to_packflag(sql_field->pack_length -
+ portable_sizeof_char_ptr);
+ if (sql_field->charset->state & MY_CS_BINSORT)
+ sql_field->pack_flag|=FIELDFLAG_BINARY;
+ sql_field->length=8; // Unireg field length
+ sql_field->unireg_check=Field::BLOB_FIELD;
+ (*blob_columns)++;
+ break;
+ case FIELD_TYPE_GEOMETRY:
+#ifdef HAVE_SPATIAL
+ if (!(table_flags & HA_CAN_GEOMETRY))
+ {
+ my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED),
+ MYF(0), "GEOMETRY");
+ DBUG_RETURN(1);
+ }
+ sql_field->pack_flag=FIELDFLAG_GEOM |
+ pack_length_to_packflag(sql_field->pack_length -
+ portable_sizeof_char_ptr);
+ if (sql_field->charset->state & MY_CS_BINSORT)
+ sql_field->pack_flag|=FIELDFLAG_BINARY;
+ sql_field->length=8; // Unireg field length
+ sql_field->unireg_check=Field::BLOB_FIELD;
+ (*blob_columns)++;
+ break;
+#else
+ my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0),
+ sym_group_geom.name, sym_group_geom.needed_define);
+ DBUG_RETURN(1);
+#endif /*HAVE_SPATIAL*/
+ case MYSQL_TYPE_VARCHAR:
+#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
+ if (table_flags & HA_NO_VARCHAR)
+ {
+ /* convert VARCHAR to CHAR because handler is not yet up to date */
+ sql_field->sql_type= MYSQL_TYPE_VAR_STRING;
+ sql_field->pack_length= calc_pack_length(sql_field->sql_type,
+ (uint) sql_field->length);
+ if ((sql_field->length / sql_field->charset->mbmaxlen) >
+ MAX_FIELD_CHARLENGTH)
+ {
+ my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
+ MYF(0), sql_field->field_name, MAX_FIELD_CHARLENGTH);
+ DBUG_RETURN(1);
+ }
+ }
+#endif
+ /* fall through */
+ case FIELD_TYPE_STRING:
+ sql_field->pack_flag=0;
+ if (sql_field->charset->state & MY_CS_BINSORT)
+ sql_field->pack_flag|=FIELDFLAG_BINARY;
+ break;
+ case FIELD_TYPE_ENUM:
+ sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
+ FIELDFLAG_INTERVAL;
+ if (sql_field->charset->state & MY_CS_BINSORT)
+ sql_field->pack_flag|=FIELDFLAG_BINARY;
+ sql_field->unireg_check=Field::INTERVAL_FIELD;
+ check_duplicates_in_interval("ENUM",sql_field->field_name,
+ sql_field->interval,
+ sql_field->charset);
+ break;
+ case FIELD_TYPE_SET:
+ sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
+ FIELDFLAG_BITFIELD;
+ if (sql_field->charset->state & MY_CS_BINSORT)
+ sql_field->pack_flag|=FIELDFLAG_BINARY;
+ sql_field->unireg_check=Field::BIT_FIELD;
+ check_duplicates_in_interval("SET",sql_field->field_name,
+ sql_field->interval,
+ sql_field->charset);
+ break;
+ case FIELD_TYPE_DATE: // Rest of string types
+ case FIELD_TYPE_NEWDATE:
+ case FIELD_TYPE_TIME:
+ case FIELD_TYPE_DATETIME:
+ case FIELD_TYPE_NULL:
+ sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
+ break;
+ case FIELD_TYPE_BIT:
+ /*
+ We have sql_field->pack_flag already set here, see mysql_prepare_table().
+ */
+ break;
+ case FIELD_TYPE_NEWDECIMAL:
+ sql_field->pack_flag=(FIELDFLAG_NUMBER |
+ (sql_field->flags & UNSIGNED_FLAG ? 0 :
+ FIELDFLAG_DECIMAL) |
+ (sql_field->flags & ZEROFILL_FLAG ?
+ FIELDFLAG_ZEROFILL : 0) |
+ (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+ break;
+ case FIELD_TYPE_TIMESTAMP:
+ /* We should replace old TIMESTAMP fields with their newer analogs */
+ if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
+ {
+ if (!*timestamps)
+ {
+ sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
+ (*timestamps_with_niladic)++;
+ }
+ else
+ sql_field->unireg_check= Field::NONE;
+ }
+ else if (sql_field->unireg_check != Field::NONE)
+ (*timestamps_with_niladic)++;
+
+ (*timestamps)++;
+ /* fall-through */
+ default:
+ sql_field->pack_flag=(FIELDFLAG_NUMBER |
+ (sql_field->flags & UNSIGNED_FLAG ? 0 :
+ FIELDFLAG_DECIMAL) |
+ (sql_field->flags & ZEROFILL_FLAG ?
+ FIELDFLAG_ZEROFILL : 0) |
+ f_settype((uint) sql_field->sql_type) |
+ (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+ break;
+ }
+ if (!(sql_field->flags & NOT_NULL_FLAG))
+ sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
+ if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
+ sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
+ DBUG_RETURN(0);
+}
+
+/*
Preparation for table creation
SYNOPSIS
@@ -437,34 +622,43 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
DESCRIPTION
Prepares the table and key structures for table creation.
+ NOTES
+ sets create_info->varchar if the table has a varchar
+
RETURN VALUES
0 ok
-1 error
*/
-int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
- List<create_field> &fields,
- List<Key> &keys, bool tmp_table, uint &db_options,
- handler *file, KEY *&key_info_buffer,
- uint *key_count, int select_field_count)
+static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
+ List<create_field> *fields,
+ List<Key> *keys, bool tmp_table,
+ uint *db_options,
+ handler *file, KEY **key_info_buffer,
+ uint *key_count, int select_field_count)
{
const char *key_name;
create_field *sql_field,*dup_field;
uint field,null_fields,blob_columns;
+ uint max_key_length= file->max_key_length();
ulong pos;
KEY *key_info;
KEY_PART_INFO *key_part_info;
int timestamps= 0, timestamps_with_niladic= 0;
int field_no,dup_no;
int select_field_pos,auto_increment=0;
+ List_iterator<create_field> it(*fields),it2(*fields);
+ uint total_uneven_bit_length= 0;
DBUG_ENTER("mysql_prepare_table");
- List_iterator<create_field> it(fields),it2(fields);
- select_field_pos=fields.elements - select_field_count;
+ select_field_pos= fields->elements - select_field_count;
null_fields=blob_columns=0;
+ create_info->varchar= 0;
for (field_no=0; (sql_field=it++) ; field_no++)
{
+ CHARSET_INFO *save_cs;
+
if (!sql_field->charset)
sql_field->charset= create_info->default_table_charset;
/*
@@ -476,13 +670,13 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (create_info->table_charset && sql_field->charset != &my_charset_bin)
sql_field->charset= create_info->table_charset;
- CHARSET_INFO *savecs= sql_field->charset;
+ save_cs= sql_field->charset;
if ((sql_field->flags & BINCMP_FLAG) &&
!(sql_field->charset= get_charset_by_csname(sql_field->charset->csname,
MY_CS_BINSORT,MYF(0))))
{
char tmp[64];
- strmake(strmake(tmp, savecs->csname, sizeof(tmp)-4), "_bin", 4);
+ strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4), "_bin", 4);
my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
DBUG_RETURN(-1);
}
@@ -539,6 +733,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (sql_field->sql_type == FIELD_TYPE_SET)
{
+ uint32 field_length;
if (sql_field->def)
{
char *not_used;
@@ -554,11 +749,12 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
}
- calculate_interval_lengths(cs, interval, &dummy, &sql_field->length);
- sql_field->length+= (interval->count - 1);
+ calculate_interval_lengths(cs, interval, &dummy, &field_length);
+ sql_field->length= field_length + (interval->count - 1);
}
else /* FIELD_TYPE_ENUM */
{
+ uint32 field_length;
if (sql_field->def)
{
String str, *def= sql_field->def->val_str(&str);
@@ -569,20 +765,54 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
}
- calculate_interval_lengths(cs, interval, &sql_field->length, &dummy);
+ calculate_interval_lengths(cs, interval, &field_length, &dummy);
+ sql_field->length= field_length;
}
set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
}
+ if (sql_field->sql_type == FIELD_TYPE_BIT)
+ {
+ sql_field->pack_flag= FIELDFLAG_NUMBER;
+ if (file->table_flags() & HA_CAN_BIT_FIELD)
+ total_uneven_bit_length+= sql_field->length & 7;
+ else
+ sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
+ }
+
sql_field->create_length_to_internal_length();
+ if (sql_field->length > MAX_FIELD_VARCHARLENGTH &&
+ !(sql_field->flags & BLOB_FLAG))
+ {
+ /* Convert long VARCHAR columns to TEXT or BLOB */
+ char warn_buff[MYSQL_ERRMSG_SIZE];
- /* Don't pack keys in old tables if the user has requested this */
- if ((sql_field->flags & BLOB_FLAG) ||
- sql_field->sql_type == FIELD_TYPE_VAR_STRING &&
- create_info->row_type != ROW_TYPE_FIXED)
+ if (sql_field->def)
+ {
+ my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name,
+ MAX_FIELD_VARCHARLENGTH / sql_field->charset->mbmaxlen);
+ DBUG_RETURN(-1);
+ }
+ sql_field->sql_type= FIELD_TYPE_BLOB;
+ sql_field->flags|= BLOB_FLAG;
+ sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name,
+ "VARCHAR",
+ (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT");
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT,
+ warn_buff);
+ }
+
+ if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
{
- db_options|=HA_OPTION_PACK_RECORD;
+ if (sql_field->sql_type == FIELD_TYPE_BLOB)
+ {
+ /* The user has given a length to the blob column */
+ sql_field->sql_type= get_blob_type_from_length(sql_field->length);
+ sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0);
+ }
+ sql_field->length= 0; // Probably from an item
}
+
if (!(sql_field->flags & NOT_NULL_FLAG))
null_fields++;
@@ -605,7 +835,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
*/
if (field_no < select_field_pos || dup_no >= select_field_pos)
{
- my_error(ER_DUP_FIELDNAME,MYF(0),sql_field->field_name);
+ my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name);
DBUG_RETURN(-1);
}
else
@@ -617,6 +847,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
create_info->default_table_charset);
sql_field->length= dup_field->length;
sql_field->pack_length= dup_field->pack_length;
+ sql_field->key_length= dup_field->key_length;
sql_field->create_length_to_internal_length();
sql_field->decimals= dup_field->decimals;
sql_field->flags= dup_field->flags;
@@ -627,116 +858,29 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
}
+ /* Don't pack rows in old tables if the user has requested this */
+ if ((sql_field->flags & BLOB_FLAG) ||
+ sql_field->sql_type == MYSQL_TYPE_VARCHAR &&
+ create_info->row_type != ROW_TYPE_FIXED)
+ (*db_options)|= HA_OPTION_PACK_RECORD;
it2.rewind();
}
/* If fixed row records, we need one bit to check for deleted rows */
- if (!(db_options & HA_OPTION_PACK_RECORD))
+ if (!((*db_options) & HA_OPTION_PACK_RECORD))
null_fields++;
- pos=(null_fields+7)/8;
+ pos= (null_fields + total_uneven_bit_length + 7) / 8;
it.rewind();
while ((sql_field=it++))
{
- DBUG_ASSERT(sql_field->charset);
-
- switch (sql_field->sql_type) {
- case FIELD_TYPE_BLOB:
- case FIELD_TYPE_MEDIUM_BLOB:
- case FIELD_TYPE_TINY_BLOB:
- case FIELD_TYPE_LONG_BLOB:
- sql_field->pack_flag=FIELDFLAG_BLOB |
- pack_length_to_packflag(sql_field->pack_length -
- portable_sizeof_char_ptr);
- if (sql_field->charset->state & MY_CS_BINSORT)
- sql_field->pack_flag|=FIELDFLAG_BINARY;
- sql_field->length=8; // Unireg field length
- sql_field->unireg_check=Field::BLOB_FIELD;
- blob_columns++;
- break;
- case FIELD_TYPE_GEOMETRY:
-#ifdef HAVE_SPATIAL
- if (!(file->table_flags() & HA_CAN_GEOMETRY))
- {
- my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED),
- MYF(0), "GEOMETRY");
- DBUG_RETURN(-1);
- }
- sql_field->pack_flag=FIELDFLAG_GEOM |
- pack_length_to_packflag(sql_field->pack_length -
- portable_sizeof_char_ptr);
- if (sql_field->charset->state & MY_CS_BINSORT)
- sql_field->pack_flag|=FIELDFLAG_BINARY;
- sql_field->length=8; // Unireg field length
- sql_field->unireg_check=Field::BLOB_FIELD;
- blob_columns++;
- break;
-#else
- my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0),
- sym_group_geom.name, sym_group_geom.needed_define);
- DBUG_RETURN(-1);
-#endif /*HAVE_SPATIAL*/
- case FIELD_TYPE_VAR_STRING:
- case FIELD_TYPE_STRING:
- sql_field->pack_flag=0;
- if (sql_field->charset->state & MY_CS_BINSORT)
- sql_field->pack_flag|=FIELDFLAG_BINARY;
- break;
- case FIELD_TYPE_ENUM:
- sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
- FIELDFLAG_INTERVAL;
- if (sql_field->charset->state & MY_CS_BINSORT)
- sql_field->pack_flag|=FIELDFLAG_BINARY;
- sql_field->unireg_check=Field::INTERVAL_FIELD;
- check_duplicates_in_interval("ENUM",sql_field->field_name,
- sql_field->interval,
- sql_field->charset);
- break;
- case FIELD_TYPE_SET:
- sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
- FIELDFLAG_BITFIELD;
- if (sql_field->charset->state & MY_CS_BINSORT)
- sql_field->pack_flag|=FIELDFLAG_BINARY;
- sql_field->unireg_check=Field::BIT_FIELD;
- check_duplicates_in_interval("SET",sql_field->field_name,
- sql_field->interval,
- sql_field->charset);
- break;
- case FIELD_TYPE_DATE: // Rest of string types
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_NULL:
- sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
- break;
- case FIELD_TYPE_TIMESTAMP:
- /* We should replace old TIMESTAMP fields with their newer analogs */
- if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
- {
- if (!timestamps)
- {
- sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
- timestamps_with_niladic++;
- }
- else
- sql_field->unireg_check= Field::NONE;
- }
- else if (sql_field->unireg_check != Field::NONE)
- timestamps_with_niladic++;
+ DBUG_ASSERT(sql_field->charset != 0);
- timestamps++;
- /* fall-through */
- default:
- sql_field->pack_flag=(FIELDFLAG_NUMBER |
- (sql_field->flags & UNSIGNED_FLAG ? 0 :
- FIELDFLAG_DECIMAL) |
- (sql_field->flags & ZEROFILL_FLAG ?
- FIELDFLAG_ZEROFILL : 0) |
- f_settype((uint) sql_field->sql_type) |
- (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
- break;
- }
- if (!(sql_field->flags & NOT_NULL_FLAG))
- sql_field->pack_flag|=FIELDFLAG_MAYBE_NULL;
+ if (prepare_create_field(sql_field, &blob_columns,
+ &timestamps, &timestamps_with_niladic,
+ file->table_flags()))
+ DBUG_RETURN(-1);
+ if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
+ create_info->varchar= 1;
sql_field->offset= pos;
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
auto_increment++;
@@ -744,30 +888,33 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
if (timestamps_with_niladic > 1)
{
- my_error(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS,MYF(0));
+ my_message(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS,
+ ER(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS), MYF(0));
DBUG_RETURN(-1);
}
if (auto_increment > 1)
{
- my_error(ER_WRONG_AUTO_KEY,MYF(0));
+ my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
DBUG_RETURN(-1);
}
if (auto_increment &&
(file->table_flags() & HA_NO_AUTO_INCREMENT))
{
- my_error(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,MYF(0));
+ my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
+ ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
DBUG_RETURN(-1);
}
if (blob_columns && (file->table_flags() & HA_NO_BLOBS))
{
- my_error(ER_TABLE_CANT_HANDLE_BLOB,MYF(0));
+ my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
+ MYF(0));
DBUG_RETURN(-1);
}
/* Create keys */
- List_iterator<Key> key_iterator(keys), key_iterator2(keys);
+ List_iterator<Key> key_iterator(*keys), key_iterator2(*keys);
uint key_parts=0, fk_key_count=0;
bool primary_key=0,unique_key=0;
Key *key, *key2;
@@ -787,9 +934,9 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (fk_key->ref_columns.elements &&
fk_key->ref_columns.elements != fk_key->columns.elements)
{
- my_error(ER_WRONG_FK_DEF, MYF(0), fk_key->name ? fk_key->name :
- "foreign key without name",
- ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
+ my_error(ER_WRONG_FK_DEF, MYF(0),
+ (fk_key->name ? fk_key->name : "foreign key without name"),
+ ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
DBUG_RETURN(-1);
}
continue;
@@ -854,9 +1001,9 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
- key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)* *key_count);
+ (*key_info_buffer) = key_info= (KEY*) sql_calloc(sizeof(KEY)* *key_count);
key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
- if (!key_info_buffer || ! key_part_info)
+ if (!*key_info_buffer || ! key_part_info)
DBUG_RETURN(-1); // Out of memory
key_iterator.rewind();
@@ -888,8 +1035,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
key_info->flags= HA_SPATIAL;
break;
#else
- my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED),MYF(0),
- sym_group_geom.name, sym_group_geom.needed_define);
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ sym_group_geom.name, sym_group_geom.needed_define);
DBUG_RETURN(-1);
#endif
case Key::FOREIGN_KEY:
@@ -911,7 +1058,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
if (!(file->table_flags() & HA_CAN_FULLTEXT))
{
- my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0));
+ my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT),
+ MYF(0));
DBUG_RETURN(-1);
}
}
@@ -928,8 +1076,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
if (key_info->key_parts != 1)
{
- my_printf_error(ER_WRONG_ARGUMENTS,
- ER(ER_WRONG_ARGUMENTS),MYF(0),"SPATIAL INDEX");
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
DBUG_RETURN(-1);
}
}
@@ -938,17 +1085,15 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
#ifdef HAVE_RTREE_KEYS
if ((key_info->key_parts & 1) == 1)
{
- my_printf_error(ER_WRONG_ARGUMENTS,
- ER(ER_WRONG_ARGUMENTS),MYF(0),"RTREE INDEX");
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX");
DBUG_RETURN(-1);
}
/* TODO: To be deleted */
- my_printf_error(ER_NOT_SUPPORTED_YET, ER(ER_NOT_SUPPORTED_YET),
- MYF(0), "RTREE INDEX");
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RTREE INDEX");
DBUG_RETURN(-1);
#else
- my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED),MYF(0),
- sym_group_rtree.name, sym_group_rtree.needed_define);
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ sym_group_rtree.name, sym_group_rtree.needed_define);
DBUG_RETURN(-1);
#endif
}
@@ -957,6 +1102,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
CHARSET_INFO *ft_key_charset=0; // for FULLTEXT
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
+ uint length;
key_part_spec *dup_column;
it.rewind();
@@ -968,9 +1114,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
field++;
if (!sql_field)
{
- my_printf_error(ER_KEY_COLUMN_DOES_NOT_EXITS,
- ER(ER_KEY_COLUMN_DOES_NOT_EXITS),MYF(0),
- column->field_name);
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name);
DBUG_RETURN(-1);
}
while ((dup_column= cols2++) != column)
@@ -987,15 +1131,14 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
cols2.rewind();
if (key->type == Key::FULLTEXT)
{
- if ((sql_field->sql_type != FIELD_TYPE_STRING &&
- sql_field->sql_type != FIELD_TYPE_VAR_STRING &&
+ if ((sql_field->sql_type != MYSQL_TYPE_STRING &&
+ sql_field->sql_type != MYSQL_TYPE_VARCHAR &&
!f_is_blob(sql_field->pack_flag)) ||
sql_field->charset == &my_charset_bin ||
sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet
(ft_key_charset && sql_field->charset != ft_key_charset))
{
- my_printf_error(ER_BAD_FT_COLUMN,ER(ER_BAD_FT_COLUMN),MYF(0),
- column->field_name);
+ my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name);
DBUG_RETURN(-1);
}
ft_key_charset=sql_field->charset;
@@ -1016,28 +1159,25 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
if (!(file->table_flags() & HA_CAN_INDEX_BLOBS))
{
- my_printf_error(ER_BLOB_USED_AS_KEY,ER(ER_BLOB_USED_AS_KEY),MYF(0),
- column->field_name);
+ my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name);
DBUG_RETURN(-1);
}
if (!column->length)
{
- my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
- ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0),
- column->field_name);
+ my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name);
DBUG_RETURN(-1);
}
}
#ifdef HAVE_SPATIAL
- if (key->type == Key::SPATIAL)
+ if (key->type == Key::SPATIAL)
{
- if (!column->length )
+ if (!column->length)
{
/*
- BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
- Lately we'll extend this code to support more dimensions
+ 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
+ Lately we'll extend this code to support more dimensions
*/
- column->length=4*sizeof(double);
+ column->length= 4*sizeof(double);
}
}
#endif
@@ -1053,13 +1193,13 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
key_info->flags|= HA_NULL_PART_KEY;
if (!(file->table_flags() & HA_NULL_IN_KEY))
{
- my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX),
- MYF(0),column->field_name);
+ my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name);
DBUG_RETURN(-1);
}
if (key->type == Key::SPATIAL)
{
- my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0));
+ my_message(ER_SPATIAL_CANT_HAVE_NULL,
+ ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
DBUG_RETURN(-1);
}
}
@@ -1073,7 +1213,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
key_part_info->fieldnr= field;
key_part_info->offset= (uint16) sql_field->offset;
key_part_info->key_type=sql_field->pack_flag;
- uint length=sql_field->pack_length;
+ length= sql_field->key_length;
+
if (column->length)
{
if (f_is_blob(sql_field->pack_flag))
@@ -1105,7 +1246,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
(key_info->flags & HA_NOSAME))) &&
column->length != length)))
{
- my_error(ER_WRONG_SUB_KEY,MYF(0));
+ my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
DBUG_RETURN(-1);
}
else if (!(file->table_flags() & HA_NO_PREFIX_CHAR_KEYS))
@@ -1113,8 +1254,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
else if (length == 0)
{
- my_printf_error(ER_WRONG_KEY_COLUMN, ER(ER_WRONG_KEY_COLUMN), MYF(0),
- column->field_name);
+ my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name);
DBUG_RETURN(-1);
}
if (length > file->max_key_part_length())
@@ -1137,14 +1277,15 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
key_part_info->length=(uint16) length;
/* Use packed keys for long strings on the first column */
- if (!(db_options & HA_OPTION_NO_PACK_KEYS) &&
+ if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
(length >= KEY_DEFAULT_PACK_LENGTH &&
- (sql_field->sql_type == FIELD_TYPE_STRING ||
- sql_field->sql_type == FIELD_TYPE_VAR_STRING ||
+ (sql_field->sql_type == MYSQL_TYPE_STRING ||
+ sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
sql_field->pack_flag & FIELDFLAG_BLOB)))
{
- if (column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB))
- key_info->flags|= HA_BINARY_PACK_KEY;
+ if (column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB) ||
+ sql_field->sql_type == MYSQL_TYPE_VARCHAR)
+ key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
else
key_info->flags|= HA_PACK_KEY;
}
@@ -1158,7 +1299,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
if (primary_key)
{
- my_error(ER_MULTIPLE_PRI_KEY,MYF(0));
+ my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY),
+ MYF(0));
DBUG_RETURN(-1);
}
key_name=primary_key_name;
@@ -1166,10 +1308,10 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
else if (!(key_name = key->name))
key_name=make_unique_key_name(sql_field->field_name,
- key_info_buffer,key_info);
- if (check_if_keyname_exists(key_name,key_info_buffer,key_info))
+ *key_info_buffer, key_info);
+ if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
{
- my_error(ER_DUP_KEYNAME,MYF(0),key_name);
+ my_error(ER_DUP_KEYNAME, MYF(0), key_name);
DBUG_RETURN(-1);
}
key_info->name=(char*) key_name;
@@ -1183,7 +1325,6 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (!(key_info->flags & HA_NULL_PART_KEY))
unique_key=1;
key_info->key_length=(uint16) key_length;
- uint max_key_length= file->max_key_length();
if (key_length > max_key_length && key->type != Key::FULLTEXT)
{
my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
@@ -1194,16 +1335,16 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (!unique_key && !primary_key &&
(file->table_flags() & HA_REQUIRE_PRIMARY_KEY))
{
- my_error(ER_REQUIRES_PRIMARY_KEY,MYF(0));
+ my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
DBUG_RETURN(-1);
}
if (auto_increment > 0)
{
- my_error(ER_WRONG_AUTO_KEY,MYF(0));
+ my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
DBUG_RETURN(-1);
}
/* Sort keys in optimized order */
- qsort((gptr) key_info_buffer, *key_count, sizeof(KEY),
+ qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY),
(qsort_cmp) sort_keys);
DBUG_RETURN(0);
@@ -1211,6 +1352,77 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
/*
+ Preparation of create_field for SP function return values.
+ Based on code used in the inner loop of mysql_prepare_table() above
+
+ SYNOPSIS
+ sp_prepare_create_field()
+ thd Thread object
+ sql_field Field to prepare
+
+ DESCRIPTION
+ Prepares the field structures for field creation.
+
+*/
+
+void sp_prepare_create_field(THD *thd, create_field *sql_field)
+{
+ if (sql_field->sql_type == FIELD_TYPE_SET ||
+ sql_field->sql_type == FIELD_TYPE_ENUM)
+ {
+ uint32 field_length, dummy;
+ if (sql_field->sql_type == FIELD_TYPE_SET)
+ {
+ calculate_interval_lengths(sql_field->charset,
+ sql_field->interval, &dummy,
+ &field_length);
+ sql_field->length= field_length +
+ (sql_field->interval->count - 1);
+ }
+ else /* FIELD_TYPE_ENUM */
+ {
+ calculate_interval_lengths(sql_field->charset,
+ sql_field->interval,
+ &field_length, &dummy);
+ sql_field->length= field_length;
+ }
+ set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
+ }
+
+ if (sql_field->sql_type == FIELD_TYPE_BIT)
+ {
+ sql_field->pack_flag= FIELDFLAG_NUMBER |
+ FIELDFLAG_TREAT_BIT_AS_CHAR;
+ }
+ sql_field->create_length_to_internal_length();
+
+ if (sql_field->length > MAX_FIELD_VARCHARLENGTH &&
+ !(sql_field->flags & BLOB_FLAG))
+ {
+ /* Convert long VARCHAR columns to TEXT or BLOB */
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+
+ sql_field->sql_type= FIELD_TYPE_BLOB;
+ sql_field->flags|= BLOB_FLAG;
+ sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name,
+ "VARCHAR",
+ (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT");
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT,
+ warn_buff);
+ }
+
+ if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
+ {
+ if (sql_field->sql_type == FIELD_TYPE_BLOB)
+ {
+ /* The user has given a length to the blob column */
+ sql_field->sql_type= get_blob_type_from_length(sql_field->length);
+ sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0);
+ }
+ sql_field->length= 0; // Probably from an item
+ }
+}
+/*
Create a table
SYNOPSIS
@@ -1221,11 +1433,11 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
create_info Create information (like MAX_ROWS)
fields List of fields to create
keys List of keys to create
- tmp_table Set to 1 if this is an internal temporary table
+ internal_tmp_table Set to 1 if this is an internal temporary table
(From ALTER TABLE)
DESCRIPTION
- If one creates a temporary table, this is automaticly opened
+ If one creates a temporary table, this is automatically opened
no_log is needed for the case of CREATE ... SELECT,
as the logging will be done later in sql_insert.cc
@@ -1233,30 +1445,31 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
and must be zero for standard create of table.
RETURN VALUES
- 0 ok
- -1 error
+ FALSE OK
+ TRUE error
*/
-int mysql_create_table(THD *thd,const char *db, const char *table_name,
- HA_CREATE_INFO *create_info,
- List<create_field> &fields,
- List<Key> &keys,bool tmp_table,
- uint select_field_count)
+bool mysql_create_table(THD *thd,const char *db, const char *table_name,
+ HA_CREATE_INFO *create_info,
+ List<create_field> &fields,
+ List<Key> &keys,bool internal_tmp_table,
+ uint select_field_count)
{
char path[FN_REFLEN];
const char *alias;
- int error= -1;
uint db_options, key_count;
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 */
if (!fields.elements)
{
- my_error(ER_TABLE_MUST_HAVE_COLUMNS,MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
+ MYF(0));
+ DBUG_RETURN(TRUE);
}
if ((new_db_type= ha_checktype(create_info->db_type)) !=
create_info->db_type)
@@ -1268,7 +1481,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
ha_get_storage_engine(new_db_type),
table_name);
}
- db_options=create_info->table_options;
+ db_options= create_info->table_options;
if (create_info->row_type == ROW_TYPE_DYNAMIC)
db_options|=HA_OPTION_PACK_RECORD;
alias= table_case_name(create_info, table_name);
@@ -1285,8 +1498,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
(file->table_flags() & HA_NO_TEMP_TABLES))
{
- my_error(ER_ILLEGAL_HA,MYF(0),table_name);
- DBUG_RETURN(-1);
+ my_error(ER_ILLEGAL_HA, MYF(0), table_name);
+ DBUG_RETURN(TRUE);
}
#endif
@@ -1307,11 +1520,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
create_info->default_table_charset= db_info.default_table_charset;
}
- if (mysql_prepare_table(thd, create_info, fields,
- keys, tmp_table, db_options, file,
- key_info_buffer, &key_count,
+ if (mysql_prepare_table(thd, create_info, &fields,
+ &keys, internal_tmp_table, &db_options, file,
+ &key_info_buffer, &key_count,
select_field_count))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
/* Check if table exists */
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
@@ -1334,25 +1547,25 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
{
create_info->table_existed= 1; // Mark that table existed
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(error);
VOID(pthread_mutex_lock(&LOCK_open));
- if (!tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
+ if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
if (!access(path,F_OK))
{
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
{
create_info->table_existed= 1; // Mark that table existed
- error= 0;
+ error= FALSE;
}
else
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
goto end;
}
}
@@ -1378,10 +1591,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (create_if_not_exists)
{
create_info->table_existed= 1; // Mark that table existed
- error= 0;
+ error= FALSE;
}
else
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
goto end;
}
}
@@ -1409,21 +1622,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
}
thd->tmp_table_used= 1;
}
- if (!tmp_table)
+ if (!internal_tmp_table && mysql_bin_log.is_open())
{
- // Must be written before unlock
- mysql_update_log.write(thd,thd->query, thd->query_length);
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length,
- test(create_info->options &
- HA_LEX_CREATE_TMP_TABLE),
- FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
+ mysql_bin_log.write(&qinfo);
}
- error=0;
+ error= FALSE;
+
end:
VOID(pthread_mutex_unlock(&LOCK_open));
start_waiting_global_read_lock(thd);
@@ -1475,7 +1681,7 @@ make_unique_key_name(const char *field_name,KEY *start,KEY *end)
****************************************************************************/
TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
- const char *db, const char *name,
+ TABLE_LIST *create_table,
List<create_field> *extra_fields,
List<Key> *keys,
List<Item> *items,
@@ -1483,19 +1689,20 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
{
TABLE tmp_table; // Used during 'create_field()'
TABLE *table= 0;
- tmp_table.table_name=0;
uint select_field_count= items->elements;
- DBUG_ENTER("create_table_from_items");
-
/* Add selected items to field list */
List_iterator_fast<Item> it(*items);
Item *item;
Field *tmp_field;
- tmp_table.db_create_options=0;
+ DBUG_ENTER("create_table_from_items");
+
+ tmp_table.alias= 0;
+ tmp_table.s= &tmp_table.share_not_to_be_used;
+ tmp_table.s->db_create_options=0;
+ tmp_table.s->blob_ptr_size= portable_sizeof_char_ptr;
+ tmp_table.s->db_low_byte_first= test(create_info->db_type == DB_TYPE_MYISAM ||
+ create_info->db_type == DB_TYPE_HEAP);
tmp_table.null_row=tmp_table.maybe_null=0;
- tmp_table.blob_ptr_size=portable_sizeof_char_ptr;
- tmp_table.db_low_byte_first= test(create_info->db_type == DB_TYPE_MYISAM ||
- create_info->db_type == DB_TYPE_HEAP);
while ((item=it++))
{
@@ -1505,42 +1712,52 @@ 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);
if (!field ||
!(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ?
((Item_field *)item)->field :
(Field*) 0))))
DBUG_RETURN(0);
+ if (item->maybe_null)
+ cr_field->flags &= ~NOT_NULL_FLAG;
extra_fields->push_back(cr_field);
}
- /* create and lock table */
- /* QQ: create and open should be done atomic ! */
/*
+ create and lock table
+
We don't log the statement, it will be logged later.
+
If this is a HEAP table, the automatic DELETE FROM which is written to the
binlog when a HEAP table is opened for the first time since startup, must
not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we
don't want to delete from it) 2) it would be written before the CREATE
TABLE, which is a wrong order. So we keep binary logging disabled when we
open_table().
+ TODO: create and open should be done atomic !
*/
- tmp_disable_binlog(thd);
- if (!mysql_create_table(thd,db,name,create_info,*extra_fields,
- *keys,0,select_field_count))
{
- if (!(table=open_table(thd,db,name,name,(bool*) 0)))
- quick_rm_table(create_info->db_type,db,table_case_name(create_info,name));
+ tmp_disable_binlog(thd);
+ if (!mysql_create_table(thd, create_table->db, create_table->table_name,
+ create_info, *extra_fields, *keys, 0,
+ select_field_count))
+ {
+ if (!(table= open_table(thd, create_table, thd->mem_root, (bool*) 0)))
+ quick_rm_table(create_info->db_type, create_table->db,
+ table_case_name(create_info, create_table->table_name));
+ }
+ reenable_binlog(thd);
+ if (!table) // open failed
+ DBUG_RETURN(0);
}
- reenable_binlog(thd);
- if (!table)
- DBUG_RETURN(0);
+
table->reginfo.lock_type=TL_WRITE;
- if (!((*lock)=mysql_lock_tables(thd,&table,1)))
+ if (!((*lock)= mysql_lock_tables(thd, &table,1)))
{
VOID(pthread_mutex_lock(&LOCK_open));
hash_delete(&open_cache,(byte*) table);
VOID(pthread_mutex_unlock(&LOCK_open));
- quick_rm_table(create_info->db_type,db,table_case_name(create_info, name));
+ quick_rm_table(create_info->db_type, create_table->db,
+ table_case_name(create_info, create_table->table_name));
DBUG_RETURN(0);
}
table->file->extra(HA_EXTRA_WRITE_CACHE);
@@ -1561,11 +1778,12 @@ mysql_rename_table(enum db_type base,
{
char from[FN_REFLEN], to[FN_REFLEN];
char tmp_from[NAME_LEN+1], tmp_to[NAME_LEN+1];
- handler *file=get_new_handler((TABLE*) 0, base);
+ handler *file=(base == DB_TYPE_UNKNOWN ? 0 : get_new_handler((TABLE*) 0, base));
int error=0;
DBUG_ENTER("mysql_rename_table");
- if (lower_case_table_names == 2 && !(file->table_flags() & HA_FILE_BASED))
+ if (lower_case_table_names == 2 && file &&
+ !(file->table_flags() & HA_FILE_BASED))
{
/* Table handler expects to get all file names as lower case */
strmov(tmp_from, old_name);
@@ -1583,13 +1801,15 @@ mysql_rename_table(enum db_type base,
fn_format(from,from,"","",4);
fn_format(to,to, "","",4);
- if (!(error=file->rename_table((const char*) from,(const char *) to)))
+ if (!file ||
+ !(error=file->rename_table((const char*) from,(const char *) to)))
{
if (rename_file_ext(from,to,reg_ext))
{
error=my_errno;
/* Restore old file name */
- file->rename_table((const char*) to,(const char *) from);
+ if (file)
+ file->rename_table((const char*) to,(const char *) from);
}
}
delete file;
@@ -1620,7 +1840,7 @@ mysql_rename_table(enum db_type base,
static void wait_while_table_is_used(THD *thd,TABLE *table,
enum ha_extra_function function)
{
- DBUG_PRINT("enter",("table: %s", table->real_name));
+ DBUG_PRINT("enter",("table: %s", table->s->table_name));
DBUG_ENTER("wait_while_table_is_used");
safe_mutex_assert_owner(&LOCK_open);
@@ -1629,8 +1849,7 @@ static void wait_while_table_is_used(THD *thd,TABLE *table,
mysql_lock_abort(thd, table); // end threads waiting on lock
/* Wait until all there are no other threads that has this table open */
- while (remove_table_from_cache(thd,table->table_cache_key,
- table->real_name))
+ while (remove_table_from_cache(thd, table->s->db, table->s->table_name, 0))
{
dropping_tables++;
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
@@ -1656,7 +1875,7 @@ static void wait_while_table_is_used(THD *thd,TABLE *table,
Win32 clients must also have a WRITE LOCK on the table !
*/
-static bool close_cached_table(THD *thd, TABLE *table)
+void close_cached_table(THD *thd, TABLE *table)
{
DBUG_ENTER("close_cached_table");
@@ -1672,7 +1891,7 @@ static bool close_cached_table(THD *thd, TABLE *table)
/* When lock on LOCK_open is freed other threads can continue */
pthread_cond_broadcast(&COND_refresh);
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
static int send_check_errmsg(THD *thd, TABLE_LIST* table,
@@ -1685,7 +1904,7 @@ static int send_check_errmsg(THD *thd, TABLE_LIST* table,
protocol->store((char*) operator_name, system_charset_info);
protocol->store("error", 5, system_charset_info);
protocol->store(errmsg, system_charset_info);
- thd->net.last_error[0]=0;
+ thd->clear_error();
if (protocol->write())
return -1;
return 1;
@@ -1707,7 +1926,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
{
char* backup_dir= thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- char* table_name = table->real_name;
+ char* table_name = table->table_name;
char* db = thd->db ? thd->db : table->db;
if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
@@ -1768,8 +1987,8 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list,
{
char name[FN_REFLEN];
strxmov(name, mysql_data_home, "/", table_list->db, "/",
- table_list->real_name, NullS);
- if (openfrm(name, "", 0, 0, 0, &tmp_table))
+ table_list->table_name, NullS);
+ if (openfrm(thd, name, "", 0, 0, 0, &tmp_table))
DBUG_RETURN(0); // Can't open frm file
table= &tmp_table;
}
@@ -1795,7 +2014,7 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list,
if (!ext[0] || !ext[1])
goto end; // No data file
- strxmov(from, table->path, ext[1], NullS); // Name of data file
+ strxmov(from, table->s->path, ext[1], NullS); // Name of data file
if (!my_stat(from, &stat_info, MYF(0)))
goto end; // Can't use USE_FRM flag
@@ -1862,25 +2081,28 @@ end:
/*
RETURN VALUES
- 0 Message sent to net (admin operation went ok)
- -1 Message should be sent by caller
- (admin operation or network communication failed)
+ FALSE Message sent to net (admin operation went ok)
+ TRUE Message should be sent by caller
+ (admin operation or network communication failed)
*/
-static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
- HA_CHECK_OPT* check_opt,
- const char *operator_name,
- thr_lock_type lock_type,
- bool open_for_modify,
- uint extra_open_options,
- int (*prepare_func)(THD *, TABLE_LIST *,
- HA_CHECK_OPT *),
- int (handler::*operator_func)
- (THD *, HA_CHECK_OPT *))
+static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
+ HA_CHECK_OPT* check_opt,
+ const char *operator_name,
+ thr_lock_type lock_type,
+ bool open_for_modify,
+ bool no_warnings_for_error,
+ uint extra_open_options,
+ int (*prepare_func)(THD *, TABLE_LIST *,
+ HA_CHECK_OPT *),
+ int (handler::*operator_func)(THD *,
+ HA_CHECK_OPT *),
+ int (view_operator_func)(THD *, TABLE_LIST*))
{
- TABLE_LIST *table;
+ TABLE_LIST *table, *next_global_table;
List<Item> field_list;
Item *item;
Protocol *protocol= thd->protocol;
+ int result_code;
DBUG_ENTER("mysql_admin_table");
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
@@ -1891,22 +2113,33 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
item->maybe_null = 1;
field_list.push_back(item = new Item_empty_string("Msg_text", 255));
item->maybe_null = 1;
- if (protocol->send_fields(&field_list, 1))
- DBUG_RETURN(-1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL);
- for (table = tables; table; table = table->next)
+ for (table= tables; table; table= table->next_local)
{
char table_name[NAME_LEN*2+2];
char* db = table->db;
bool fatal_error=0;
- strxmov(table_name, db, ".", table->real_name, NullS);
+ strxmov(table_name, db, ".", table->table_name, NullS);
thd->open_options|= extra_open_options;
- table->table = open_ltable(thd, table, lock_type);
-#ifdef EMBEDDED_LIBRARY
- thd->net.last_errno= 0; // these errors shouldn't get client
-#endif
+ table->lock_type= lock_type;
+ /* open only one table from local list of command */
+ next_global_table= table->next_global;
+ table->next_global= 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;
+ /* if view are unsupported */
+ if (table->view && view_operator_func == NULL)
+ {
+ result_code= HA_ADMIN_NOT_IMPLEMENTED;
+ goto send_result;
+ }
thd->open_options&= ~extra_open_options;
if (prepare_func)
@@ -1922,8 +2155,17 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
}
}
+ /*
+ CHECK TABLE command is only command where VIEW allowed here and this
+ command use only temporary teble method for VIEWs resolving => there
+ can't be VIEW tree substitition of join view => if opening table
+ succeed then table->table will have real TABLE pointer as value (in
+ case of join view substitution table->table can be 0, but here it is
+ impossible)
+ */
if (!table->table)
{
+ char buf[ERRMSGSIZE+ERRMSGSIZE+2];
const char *err_msg;
protocol->prepare_for_resend();
protocol->store(table_name, system_charset_info);
@@ -1931,12 +2173,26 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
protocol->store("error",5, system_charset_info);
if (!(err_msg=thd->net.last_error))
err_msg=ER(ER_CHECK_NO_SUCH_TABLE);
+ /* if it was a view will check md5 sum */
+ if (table->view &&
+ view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM)
+ {
+ strxmov(buf, err_msg, "; ", ER(ER_VIEW_CHECKSUM), NullS);
+ err_msg= (const char *)buf;
+ }
protocol->store(err_msg, system_charset_info);
- thd->net.last_error[0]=0;
+ thd->clear_error();
if (protocol->write())
goto err;
continue;
}
+
+ if (table->view)
+ {
+ result_code= (*view_operator_func)(thd, table);
+ goto send_result;
+ }
+
table->table->pos_in_table_list= table;
if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify)
{
@@ -1955,14 +2211,14 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
}
/* Close all instances of the table to allow repair to rename files */
- if (lock_type == TL_WRITE && table->table->version)
+ if (lock_type == TL_WRITE && table->table->s->version)
{
pthread_mutex_lock(&LOCK_open);
const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
"Waiting to get writelock");
mysql_lock_abort(thd,table->table);
- while (remove_table_from_cache(thd, table->table->table_cache_key,
- table->table->real_name) &&
+ while (remove_table_from_cache(thd, table->table->s->db,
+ table->table->s->table_name, 0) &&
! thd->killed)
{
dropping_tables++;
@@ -1977,10 +2233,11 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
open_for_modify= 0;
}
- int result_code = (table->table->file->*operator_func)(thd, check_opt);
-#ifdef EMBEDDED_LIBRARY
- thd->net.last_errno= 0; // these errors shouldn't get client
-#endif
+ result_code = (table->table->file->*operator_func)(thd, check_opt);
+
+send_result:
+
+ thd->clear_error(); // these errors shouldn't get client
protocol->prepare_for_resend();
protocol->store(table_name, system_charset_info);
protocol->store(operator_name, system_charset_info);
@@ -2039,8 +2296,9 @@ send_result_message:
reopen the table and do ha_innobase::analyze() on it.
*/
close_thread_tables(thd);
- TABLE_LIST *save_next= table->next;
- table->next= 0;
+ TABLE_LIST *save_next_local= table->next_local,
+ *save_next_global= table->next_global;
+ table->next_local= table->next_global= 0;
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
result_code= mysql_recreate_table(thd, table, 0);
reenable_binlog(thd);
@@ -2052,9 +2310,17 @@ send_result_message:
result_code= 0; // analyze went ok
}
result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
- table->next= save_next;
+ table->next_local= save_next_local;
+ table->next_global= save_next_global;
goto send_result_message;
}
+ case HA_ADMIN_WRONG_CHECKSUM:
+ {
+ protocol->store("note", 4, system_charset_info);
+ protocol->store(ER(ER_VIEW_CHECKSUM), strlen(ER(ER_VIEW_CHECKSUM)),
+ system_charset_info);
+ break;
+ }
default: // Probably HA_ADMIN_INTERNAL_ERROR
protocol->store("error", 5, system_charset_info);
@@ -2064,12 +2330,12 @@ send_result_message:
break;
}
if (fatal_error)
- table->table->version=0; // Force close of table
+ table->table->s->version=0; // Force close of table
else if (open_for_modify)
{
pthread_mutex_lock(&LOCK_open);
- remove_table_from_cache(thd, table->table->table_cache_key,
- table->table->real_name);
+ remove_table_from_cache(thd, table->table->s->db,
+ table->table->s->table_name, 0);
pthread_mutex_unlock(&LOCK_open);
/* May be something modified consequently we have to invalidate cache */
query_cache_invalidate3(thd, table->table, 0);
@@ -2081,50 +2347,52 @@ send_result_message:
}
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
err:
close_thread_tables(thd); // Shouldn't be needed
if (table)
table->table=0;
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
-int mysql_backup_table(THD* thd, TABLE_LIST* table_list)
+bool mysql_backup_table(THD* thd, TABLE_LIST* table_list)
{
DBUG_ENTER("mysql_backup_table");
DBUG_RETURN(mysql_admin_table(thd, table_list, 0,
- "backup", TL_READ, 0, 0, 0,
- &handler::backup));
+ "backup", TL_READ, 0, 0, 0, 0,
+ &handler::backup, 0));
}
-int mysql_restore_table(THD* thd, TABLE_LIST* table_list)
+bool mysql_restore_table(THD* thd, TABLE_LIST* table_list)
{
DBUG_ENTER("mysql_restore_table");
DBUG_RETURN(mysql_admin_table(thd, table_list, 0,
- "restore", TL_WRITE, 1, 0,
+ "restore", TL_WRITE, 1, 1, 0,
&prepare_for_restore,
- &handler::restore));
+ &handler::restore, 0));
}
-int mysql_repair_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
+bool mysql_repair_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
{
DBUG_ENTER("mysql_repair_table");
DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
- "repair", TL_WRITE, 1, HA_OPEN_FOR_REPAIR,
+ "repair", TL_WRITE, 1,
+ test(check_opt->sql_flags & TT_USEFRM),
+ HA_OPEN_FOR_REPAIR,
&prepare_for_repair,
- &handler::repair));
+ &handler::repair, 0));
}
-int mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
+bool mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
{
DBUG_ENTER("mysql_optimize_table");
DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
- "optimize", TL_WRITE, 1,0,0,
- &handler::optimize));
+ "optimize", TL_WRITE, 1,0,0,0,
+ &handler::optimize, 0));
}
@@ -2137,11 +2405,11 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
tables Table list (one table only)
RETURN VALUES
- 0 ok
- -1 error
+ FALSE ok
+ TRUE error
*/
-int mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables,
+bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables,
LEX_STRING *key_cache_name)
{
HA_CHECK_OPT check_opt;
@@ -2154,13 +2422,13 @@ int mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables,
{
pthread_mutex_unlock(&LOCK_global_system_variables);
my_error(ER_UNKNOWN_KEY_CACHE, MYF(0), key_cache_name->str);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
pthread_mutex_unlock(&LOCK_global_system_variables);
check_opt.key_cache= key_cache;
DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt,
- "assign_to_keycache", TL_READ_NO_INSERT, 0,
- 0, 0, &handler::assign_to_keycache));
+ "assign_to_keycache", TL_READ_NO_INSERT, 0, 0,
+ 0, 0, &handler::assign_to_keycache, 0));
}
@@ -2212,16 +2480,16 @@ int reassign_keycache_tables(THD *thd, KEY_CACHE *src_cache,
tables Table list (one table only)
RETURN VALUES
- 0 ok
- -1 error
+ FALSE ok
+ TRUE error
*/
-int mysql_preload_keys(THD* thd, TABLE_LIST* tables)
+bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
{
DBUG_ENTER("mysql_preload_keys");
DBUG_RETURN(mysql_admin_table(thd, tables, 0,
- "preload_keys", TL_READ, 0, 0, 0,
- &handler::preload_keys));
+ "preload_keys", TL_READ, 0, 0, 0, 0,
+ &handler::preload_keys, 0));
}
@@ -2236,21 +2504,22 @@ int mysql_preload_keys(THD* thd, TABLE_LIST* tables)
table_ident Src table_ident
RETURN VALUES
- 0 ok
- -1 error
+ FALSE OK
+ TRUE error
*/
-int mysql_create_like_table(THD* thd, TABLE_LIST* table,
- HA_CREATE_INFO *create_info,
- Table_ident *table_ident)
+bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
+ HA_CREATE_INFO *create_info,
+ Table_ident *table_ident)
{
TABLE **tmp_table;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char *db= table->db;
- char *table_name= table->real_name;
+ char *table_name= table->table_name;
char *src_db= thd->db;
char *src_table= table_ident->table.str;
- int err, res= -1;
+ int err;
+ bool res= TRUE;
TABLE_LIST src_tables_list;
DBUG_ENTER("mysql_create_like_table");
@@ -2263,18 +2532,18 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table,
table_ident->db.str && check_db_name((src_db= table_ident->db.str)))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
+ bzero((gptr)&src_tables_list, sizeof(src_tables_list));
src_tables_list.db= table_ident->db.str ? table_ident->db.str : thd->db;
- src_tables_list.real_name= table_ident->table.str;
- src_tables_list.next= 0;
+ src_tables_list.table_name= table_ident->table.str;
if (lock_and_wait_for_table_name(thd, &src_tables_list))
goto err;
if ((tmp_table= find_temporary_table(thd, src_db, src_table)))
- strxmov(src_path, (*tmp_table)->path, reg_ext, NullS);
+ strxmov(src_path, (*tmp_table)->s->path, reg_ext, NullS);
else
{
strxmov(src_path, mysql_data_home, "/", src_db, "/", src_table,
@@ -2345,17 +2614,13 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table,
}
// Must be written before unlock
- mysql_update_log.write(thd,thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length,
- test(create_info->options &
- HA_LEX_CREATE_TMP_TABLE),
- FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
- res= 0;
+ res= FALSE;
goto err;
table_exists:
@@ -2364,9 +2629,9 @@ table_exists:
char warn_buff[MYSQL_ERRMSG_SIZE];
my_snprintf(warn_buff, sizeof(warn_buff),
ER(ER_TABLE_EXISTS_ERROR), table_name);
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR,warn_buff);
- res= 0;
+ res= FALSE;
}
else
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
@@ -2379,7 +2644,7 @@ err:
}
-int mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
+bool mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
{
#ifdef OS2
thr_lock_type lock_type = TL_WRITE;
@@ -2389,12 +2654,12 @@ int mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
DBUG_ENTER("mysql_analyze_table");
DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
- "analyze", lock_type, 1,0,0,
- &handler::analyze));
+ "analyze", lock_type, 1, 0, 0, 0,
+ &handler::analyze, 0));
}
-int mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt)
+bool mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt)
{
#ifdef OS2
thr_lock_type lock_type = TL_WRITE;
@@ -2405,8 +2670,8 @@ int mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt)
DBUG_ENTER("mysql_check_table");
DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
"check", lock_type,
- 0, HA_OPEN_FOR_REPAIR, 0,
- &handler::check));
+ 0, HA_OPEN_FOR_REPAIR, 0, 0,
+ &handler::check, &view_checksum));
}
@@ -2460,10 +2725,9 @@ mysql_discard_or_import_tablespace(THD *thd,
error=1;
if (error)
goto err;
- mysql_update_log.write(thd, thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
err:
@@ -2532,9 +2796,9 @@ int mysql_create_indexes(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
create_info.db_type=DB_TYPE_DEFAULT;
create_info.default_table_charset= thd->variables.collation_database;
db_options= 0;
- if (mysql_prepare_table(thd, &create_info, fields,
- keys, /*tmp_table*/ 0, db_options, table->file,
- key_info_buffer, key_count,
+ if (mysql_prepare_table(thd, &create_info, &fields,
+ &keys, /*tmp_table*/ 0, &db_options, table->file,
+ &key_info_buffer, key_count,
/*select_field_count*/ 0))
DBUG_RETURN(-1);
@@ -2557,7 +2821,7 @@ int mysql_create_indexes(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
create_info.default_table_charset= thd->variables.collation_database;
/* Cleanup the fields list. We do not want to create existing fields. */
fields.delete_elements();
- if (real_alter_table(thd, table_list->db, table_list->real_name,
+ if (real_alter_table(thd, table_list->db, table_list->table_name,
&create_info, table_list, table,
fields, keys, drop, alter, 0, (ORDER*)0,
ALTER_ADD_INDEX, DUP_ERROR))
@@ -2569,7 +2833,7 @@ int mysql_create_indexes(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
if (table->file->add_index(table, key_info_buffer, key_count)||
(my_snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home,
table_list->db, (lower_case_table_names == 2) ?
- table_list->alias: table_list->real_name, reg_ext) >=
+ table_list->alias: table_list->table_name, reg_ext) >=
(int) sizeof(path)) ||
! unpack_filename(path, path) ||
mysql_create_frm(thd, path, &create_info,
@@ -2654,7 +2918,7 @@ int mysql_drop_indexes(THD *thd, TABLE_LIST *table_list,
if ((drop_key)|| (drop.elements<= 0))
{
- if (real_alter_table(thd, table_list->db, table_list->real_name,
+ if (real_alter_table(thd, table_list->db, table_list->table_name,
&create_info, table_list, table,
fields, keys, drop, alter, 0, (ORDER*)0,
ALTER_DROP_INDEX, DUP_ERROR))
@@ -2665,13 +2929,13 @@ int mysql_drop_indexes(THD *thd, TABLE_LIST *table_list,
{
db_options= 0;
if (table->file->drop_index(table, key_numbers, key_count)||
- mysql_prepare_table(thd, &create_info, fields,
- keys, /*tmp_table*/ 0, db_options, table->file,
- key_info_buffer, key_count,
+ mysql_prepare_table(thd, &create_info, &fields,
+ &keys, /*tmp_table*/ 0, &db_options, table->file,
+ &key_info_buffer, key_count,
/*select_field_count*/ 0)||
(snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home,
table_list->db, (lower_case_table_names == 2)?
- table_list->alias: table_list->real_name, reg_ext)>=
+ table_list->alias: table_list->table_name, reg_ext)>=
(int)sizeof(path))||
! unpack_filename(path, path)||
mysql_create_frm(thd, path, &create_info,
@@ -2690,15 +2954,15 @@ int mysql_drop_indexes(THD *thd, TABLE_LIST *table_list,
Alter table
*/
-int mysql_alter_table(THD *thd,char *new_db, char *new_name,
- HA_CREATE_INFO *create_info,
- TABLE_LIST *table_list,
- List<create_field> &fields, List<Key> &keys,
- uint order_num, ORDER *order,
- enum enum_duplicates handle_duplicates, bool ignore,
- ALTER_INFO *alter_info, bool do_send_ok)
+bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
+ HA_CREATE_INFO *create_info,
+ TABLE_LIST *table_list,
+ List<create_field> &fields, List<Key> &keys,
+ uint order_num, ORDER *order,
+ enum enum_duplicates handle_duplicates, bool ignore,
+ ALTER_INFO *alter_info, bool do_send_ok)
{
- TABLE *table,*new_table;
+ TABLE *table,*new_table=0;
int error;
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
@@ -2707,10 +2971,11 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
ulonglong next_insert_id;
uint db_create_options, used_fields;
enum db_type old_db_type,new_db_type;
+ bool need_copy_table;
DBUG_ENTER("mysql_alter_table");
thd->proc_info="init";
- table_name=table_list->real_name;
+ table_name=table_list->table_name;
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
db=table_list->db;
@@ -2724,7 +2989,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
alter_info->tablespace_op));
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
/* Check that we are not trying to rename to an existing table */
if (new_name)
@@ -2751,12 +3016,12 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
else
{
- if (table->tmp_table)
+ if (table->s->tmp_table)
{
if (find_temporary_table(thd,new_db,new_name_buff))
{
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name_buff);
- DBUG_RETURN(-1);
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
+ DBUG_RETURN(TRUE);
}
}
else
@@ -2767,8 +3032,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
F_OK))
{
/* Table will be closed in do_command() */
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0), new_alias);
- DBUG_RETURN(-1);
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
+ DBUG_RETURN(TRUE);
}
}
}
@@ -2779,9 +3044,9 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
new_name= table_name;
}
- old_db_type=table->db_type;
+ old_db_type= table->s->db_type;
if (create_info->db_type == DB_TYPE_DEFAULT)
- create_info->db_type=old_db_type;
+ create_info->db_type= old_db_type;
if ((new_db_type= ha_checktype(create_info->db_type)) !=
create_info->db_type)
{
@@ -2793,10 +3058,11 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
new_name);
}
if (create_info->row_type == ROW_TYPE_NOT_USED)
- create_info->row_type=table->row_type;
+ create_info->row_type= table->s->row_type;
thd->proc_info="setup";
- if (alter_info->is_simple && !table->tmp_table)
+ if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
+ !table->s->tmp_table) // no need to touch frm
{
error=0;
if (new_name != table_name || new_db != db)
@@ -2807,7 +3073,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
error=0;
if (!access(new_name_buff,F_OK))
{
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name);
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
error= -1;
}
else
@@ -2824,37 +3090,37 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
switch (alter_info->keys_onoff) {
case LEAVE_AS_IS:
- break;
+ break;
case ENABLE:
- VOID(pthread_mutex_lock(&LOCK_open));
- wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
- VOID(pthread_mutex_unlock(&LOCK_open));
- error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
- /* COND_refresh will be signaled in close_thread_tables() */
- break;
+ VOID(pthread_mutex_lock(&LOCK_open));
+ wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
+ /* COND_refresh will be signaled in close_thread_tables() */
+ break;
case DISABLE:
- VOID(pthread_mutex_lock(&LOCK_open));
- wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
- VOID(pthread_mutex_unlock(&LOCK_open));
- error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
- /* COND_refresh will be signaled in close_thread_tables() */
- break;
+ VOID(pthread_mutex_lock(&LOCK_open));
+ wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
+ /* COND_refresh will be signaled in close_thread_tables() */
+ break;
}
}
+
if (error == HA_ERR_WRONG_COMMAND)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
- table->table_name);
+ table->alias);
error=0;
}
if (!error)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
if (do_send_ok)
@@ -2872,17 +3138,17 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* Full alter table */
- /* let new create options override the old ones */
+ /* Let new create options override the old ones */
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
- create_info->min_rows=table->min_rows;
+ create_info->min_rows= table->s->min_rows;
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
- create_info->max_rows=table->max_rows;
+ create_info->max_rows= table->s->max_rows;
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
- create_info->avg_row_length=table->avg_row_length;
+ create_info->avg_row_length= table->s->avg_row_length;
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
- create_info->default_table_charset= table->table_charset;
+ create_info->default_table_charset= table->s->table_charset;
- restore_record(table,default_values); // Empty record for DEFAULT
+ restore_record(table, s->default_values); // Empty record for DEFAULT
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
List_iterator<create_field> def_it(fields);
List_iterator<Alter_column> alter_it(alter_info->alter_list);
@@ -2951,8 +3217,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
if (def->sql_type == FIELD_TYPE_BLOB)
{
- my_error(ER_BLOB_CANT_HAVE_DEFAULT,MYF(0),def->change);
- DBUG_RETURN(-1);
+ my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
+ DBUG_RETURN(TRUE);
}
def->def=alter->def; // Use new default
alter_it.remove();
@@ -2965,8 +3231,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
if (def->change && ! def->field)
{
- my_error(ER_BAD_FIELD_ERROR,MYF(0),def->change,table_name);
- DBUG_RETURN(-1);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table_name);
+ DBUG_RETURN(TRUE);
}
if (!def->after)
create_list.push_back(def);
@@ -2983,22 +3249,23 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
if (!find)
{
- my_error(ER_BAD_FIELD_ERROR,MYF(0),def->after,table_name);
- DBUG_RETURN(-1);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table_name);
+ DBUG_RETURN(TRUE);
}
find_it.after(def); // Put element after this
}
}
if (alter_info->alter_list.elements)
{
- my_error(ER_BAD_FIELD_ERROR,MYF(0),alter_info->alter_list.head()->name,
- table_name);
- DBUG_RETURN(-1);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0),
+ alter_info->alter_list.head()->name, table_name);
+ DBUG_RETURN(TRUE);
}
if (!create_list.elements)
{
- my_error(ER_CANT_REMOVE_ALL_FIELDS,MYF(0));
- DBUG_RETURN(-1);
+ my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
+ MYF(0));
+ DBUG_RETURN(TRUE);
}
/*
@@ -3011,7 +3278,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
List<key_part_spec> key_parts;
KEY *key_info=table->key_info;
- for (uint i=0 ; i < table->keys ; i++,key_info++)
+ for (uint i=0 ; i < table->s->keys ; i++,key_info++)
{
char *key_name= key_info->name;
Alter_drop *drop;
@@ -3087,25 +3354,25 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
!my_strcasecmp(system_charset_info,key->name,primary_key_name))
{
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
}
if (alter_info->drop_list.elements)
{
- my_error(ER_CANT_DROP_FIELD_OR_KEY,MYF(0),
- alter_info->drop_list.head()->name);
+ my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
+ alter_info->drop_list.head()->name);
goto err;
}
if (alter_info->alter_list.elements)
{
- my_error(ER_CANT_DROP_FIELD_OR_KEY,MYF(0),
- alter_info->alter_list.head()->name);
+ my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
+ alter_info->alter_list.head()->name);
goto err;
}
- db_create_options=table->db_create_options & ~(HA_OPTION_PACK_RECORD);
+ db_create_options= table->s->db_create_options & ~(HA_OPTION_PACK_RECORD);
my_snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix,
current_pid, thd->thread_id);
/* Safety fix for innodb */
@@ -3117,7 +3384,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
create_info->db_type=new_db_type;
if (!create_info->comment)
- create_info->comment=table->comment;
+ create_info->comment= table->s->comment;
table->file->update_create_info(create_info);
if ((create_info->table_options &
@@ -3133,10 +3400,20 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
HA_OPTION_NO_DELAY_KEY_WRITE);
create_info->table_options|= db_create_options;
- if (table->tmp_table)
+ if (table->s->tmp_table)
create_info->options|=HA_LEX_CREATE_TMP_TABLE;
/*
+ better have a negative test here, instead of positive, like
+ alter_info->flags & ALTER_ADD_COLUMN|ALTER_ADD_INDEX|...
+ so that ALTER TABLE won't break when somebody will add new flag
+ */
+ need_copy_table=(alter_info->flags & ~(ALTER_CHANGE_COLUMN_DEFAULT|ALTER_OPTIONS) ||
+ create_info->used_fields & ~(HA_CREATE_USED_COMMENT|HA_CREATE_USED_PASSWORD) ||
+ table->s->tmp_table);
+ create_info->frm_only= !need_copy_table;
+
+ /*
Handling of symlinked tables:
If no rename:
Create new data file and index file on the same disk as the
@@ -3182,8 +3459,9 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
else
create_info->data_file_name=create_info->index_file_name=0;
+
+ /* We don't log the statement, it will be logged later. */
{
- /* We don't log the statement, it will be logged later. */
tmp_disable_binlog(thd);
error= mysql_create_table(thd, new_db, tmp_name,
create_info,create_list,key_list,1,0);
@@ -3191,39 +3469,49 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (error)
DBUG_RETURN(error);
}
- if (table->tmp_table)
- new_table=open_table(thd,new_db,tmp_name,tmp_name,0);
- else
+ if (need_copy_table)
{
- char path[FN_REFLEN];
- my_snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home,
- new_db, tmp_name);
- fn_format(path,path,"","",4);
- new_table=open_temporary_table(thd, path, new_db, tmp_name,0);
- }
- if (!new_table)
- {
- VOID(quick_rm_table(new_db_type,new_db,tmp_name));
- goto err;
+ if (table->s->tmp_table)
+ {
+ TABLE_LIST tbl;
+ 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);
+ }
+ else
+ {
+ char path[FN_REFLEN];
+ my_snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home,
+ new_db, tmp_name);
+ fn_format(path,path,"","",4);
+ new_table=open_temporary_table(thd, path, new_db, tmp_name,0);
+ }
+ if (!new_table)
+ {
+ VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ goto err;
+ }
}
-
/* We don't want update TIMESTAMP fields during ALTER TABLE. */
- new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
- new_table->next_number_field=new_table->found_next_number_field;
thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
thd->cuted_fields=0L;
thd->proc_info="copy to tmp table";
- next_insert_id=thd->next_insert_id; // Remember for loggin
+ next_insert_id=thd->next_insert_id; // Remember for logging
copied=deleted=0;
- if (!new_table->is_view)
+ if (new_table && !new_table->s->is_view)
+ {
+ new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+ new_table->next_number_field=new_table->found_next_number_field;
error=copy_data_between_tables(table,new_table,create_list,
handle_duplicates, ignore,
order_num, order, &copied, &deleted);
+ }
thd->last_insert_id=next_insert_id; // Needed for correct log
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
- if (table->tmp_table)
+ if (table->s->tmp_table)
{
/* We changed a temporary table */
if (error)
@@ -3242,7 +3530,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
thd->lock=0;
}
/* Remove link to old table and rename the new one */
- close_temporary_table(thd,table->table_cache_key,table_name);
+ close_temporary_table(thd, table->s->db, table_name);
/* Should pass the 'new_name' as we store table name in the cache */
if (rename_temporary_table(thd, new_table, new_db, new_name))
{ // Fatal error
@@ -3250,18 +3538,20 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
my_free((gptr) new_table,MYF(0));
goto err;
}
- mysql_update_log.write(thd, thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
goto end_temporary;
}
- intern_close_table(new_table); /* close temporary table */
- my_free((gptr) new_table,MYF(0));
+ if (new_table)
+ {
+ intern_close_table(new_table); /* close temporary table */
+ my_free((gptr) new_table,MYF(0));
+ }
VOID(pthread_mutex_lock(&LOCK_open));
if (error)
{
@@ -3273,7 +3563,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
/*
Data is copied. Now we rename the old table to a temp name,
rename the new one to the old name, remove all entries from the old table
- from the cash, free all locks, close the old table and remove it.
+ from the cache, free all locks, close the old table and remove it.
*/
thd->proc_info="rename result table";
@@ -3286,7 +3576,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (!access(new_name_buff,F_OK))
{
error=1;
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),new_name_buff);
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
VOID(quick_rm_table(new_db_type,new_db,tmp_name));
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
@@ -3302,12 +3592,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
close the original table at before doing the rename
*/
table_name=thd->strdup(table_name); // must be saved
- if (close_cached_table(thd, table))
- { // Aborted
- VOID(quick_rm_table(new_db_type,new_db,tmp_name));
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
+ close_cached_table(thd, table);
table=0; // Marker that table is closed
}
#if (!defined( __WIN__) && !defined( __EMX__) && !defined( OS2))
@@ -3317,6 +3602,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
error=0;
+ if (!need_copy_table)
+ new_db_type=old_db_type=DB_TYPE_UNKNOWN; // this type cannot happen in regular ALTER
if (mysql_rename_table(old_db_type,db,table_name,db,old_name))
{
error=1;
@@ -3361,7 +3648,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (table)
{
VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file
- remove_table_from_cache(thd,db,table_name); // Mark all in-use copies old
+ remove_table_from_cache(thd,db,table_name, 0); // Mark in-use copies old
mysql_lock_abort(thd,table); // end threads waiting on lock
}
VOID(quick_rm_table(old_db_type,db,old_name));
@@ -3385,11 +3672,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
goto err;
}
thd->proc_info="end";
- mysql_update_log.write(thd, thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
mysql_bin_log.write(&qinfo);
}
VOID(pthread_cond_broadcast(&COND_refresh));
@@ -3428,10 +3714,10 @@ end_temporary:
if (do_send_ok)
send_ok(thd,copied+deleted,0L,tmp_name);
thd->some_tables_deleted=0;
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
err:
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
@@ -3469,11 +3755,18 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (error)
DBUG_RETURN(-1);
- if (!(copy= new Copy_field[to->fields]))
+ if (!(copy= new Copy_field[to->s->fields]))
DBUG_RETURN(-1); /* purecov: inspected */
if (to->file->external_lock(thd, F_WRLCK))
DBUG_RETURN(-1);
+
+ /* We can abort alter table for any table type */
+ thd->no_trans_update= 0;
+ thd->abort_on_warning= !ignore && test(thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES));
+
from->file->info(HA_STATUS_VARIABLE);
to->file->start_bulk_insert(from->file->records);
@@ -3511,9 +3804,9 @@ copy_data_between_tables(TABLE *from,TABLE *to,
from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
bzero((char*) &tables,sizeof(tables));
- tables.table = from;
- tables.alias = tables.real_name= from->real_name;
- tables.db = from->table_cache_key;
+ tables.table= from;
+ tables.alias= tables.table_name= (char*) from->s->table_name;
+ tables.db= (char*) from->s->db;
error=1;
if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
@@ -3527,20 +3820,23 @@ copy_data_between_tables(TABLE *from,TABLE *to,
goto err;
};
- /* Handler must be told explicitly to retrieve all columns, because
- this function does not set field->query_id in the columns to the
- current query id */
+ /*
+ Handler must be told explicitly to retrieve all columns, because
+ this function does not set field->query_id in the columns to the
+ current query id
+ */
from->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1);
if (ignore ||
handle_duplicates == DUP_REPLACE)
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
thd->row_count= 0;
+ restore_record(to, s->default_values); // Create empty record
while (!(error=info.read_record(&info)))
{
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
error= 1;
break;
}
@@ -3552,6 +3848,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
else
to->next_number_field->reset();
}
+
for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
{
copy_ptr->do_copy(copy_ptr);
@@ -3566,6 +3863,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
to->file->print_error(error,MYF(0));
break;
}
+ to->file->restore_auto_increment();
delete_count++;
}
else
@@ -3575,7 +3873,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
free_io_cache(from);
delete [] copy; // This is never 0
- if (to->file->end_bulk_insert() && !error)
+ if (to->file->end_bulk_insert() && error <= 0)
{
to->file->print_error(my_errno,MYF(0));
error=1;
@@ -3595,6 +3893,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
err:
thd->variables.sql_mode= save_sql_mode;
+ thd->abort_on_warning= 0;
free_io_cache(from);
*copied= found_count;
*deleted=delete_count;
@@ -3616,8 +3915,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
RETURN
Like mysql_alter_table().
*/
-int mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
- bool do_send_ok)
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
+ bool do_send_ok)
{
DBUG_ENTER("mysql_recreate_table");
LEX *lex= thd->lex;
@@ -3626,11 +3925,12 @@ int mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
lex->key_list.empty();
lex->col_list.empty();
lex->alter_info.reset();
- lex->alter_info.is_simple= 0; // Force full recreate
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
- create_info.row_type=ROW_TYPE_DEFAULT;
+ create_info.row_type=ROW_TYPE_NOT_USED;
create_info.default_table_charset=default_charset_info;
+ /* Force alter table to recreate table */
+ lex->alter_info.flags= ALTER_CHANGE_COLUMN;
DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
table_list, lex->create_list,
lex->key_list, 0, (ORDER *) 0,
@@ -3638,7 +3938,7 @@ int mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
}
-int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
+bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
{
TABLE_LIST *table;
List<Item> field_list;
@@ -3650,15 +3950,16 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
item->maybe_null= 1;
field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
item->maybe_null= 1;
- if (protocol->send_fields(&field_list, 1))
- DBUG_RETURN(-1);
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
- for (table= tables; table; table= table->next)
+ for (table= tables; table; table= table->next_local)
{
char table_name[NAME_LEN*2+2];
TABLE *t;
- strxmov(table_name, table->db ,".", table->real_name, NullS);
+ strxmov(table_name, table->db ,".", table->table_name, NullS);
t= table->table= open_ltable(thd, table, TL_READ_NO_INSERT);
thd->clear_error(); // these errors shouldn't get client
@@ -3670,7 +3971,7 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
{
/* Table didn't exist */
protocol->store_null();
- thd->net.last_error[0]=0;
+ thd->clear_error();
}
else
{
@@ -3703,7 +4004,7 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
row_crc= my_checksum(row_crc, t->record[0],
((byte*) t->field[0]->ptr) - t->record[0]);
- for (uint i= 0; i < t->fields; i++ )
+ for (uint i= 0; i < t->s->fields; i++ )
{
Field *f= t->field[i];
if (f->type() == FIELD_TYPE_BLOB)
@@ -3732,11 +4033,11 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
}
send_eof(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
err:
close_thread_tables(thd); // Shouldn't be needed
if (table)
table->table=0;
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index d992c93f8fc..c2cd0d59cc3 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -79,7 +79,7 @@ void print_cached_tables(void)
{
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
printf("%-14.14s %-32s%6ld%8ld%10ld%6d %s\n",
- entry->table_cache_key,entry->real_name,entry->version,
+ entry->s->db, entry->s->table_name, entry->s->version,
entry->in_use ? entry->in_use->thread_id : 0L,
entry->in_use ? entry->in_use->dbug_thread_id : 0L,
entry->db_stat ? 1 : 0, entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
@@ -131,7 +131,7 @@ void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
{
if (sortorder->field->table_name)
{
- out.append(sortorder->field->table_name);
+ out.append(*sortorder->field->table_name);
out.append('.');
}
out.append(sortorder->field->field_name ? sortorder->field->field_name:
@@ -167,7 +167,7 @@ TEST_join(JOIN *join)
TABLE *form=tab->table;
char key_map_buff[128];
fprintf(DBUG_FILE,"%-16.16s type: %-7s q_keys: %s refs: %d key: %d len: %d\n",
- form->table_name,
+ form->alias,
join_type_str[tab->type],
tab->keys.print(key_map_buff),
tab->ref.key_parts,
@@ -181,9 +181,10 @@ TEST_join(JOIN *join)
" quick select checked for each record (keys: %s)\n",
tab->select->quick_keys.print(buf));
else if (tab->select->quick)
- fprintf(DBUG_FILE," quick select used on key %s, length: %d\n",
- form->key_info[tab->select->quick->index].name,
- tab->select->quick->max_used_key_length);
+ {
+ fprintf(DBUG_FILE, " quick select used:\n");
+ tab->select->quick->dbug_dump(18, false);
+ }
else
VOID(fputs(" select used\n",DBUG_FILE));
}
@@ -202,6 +203,104 @@ TEST_join(JOIN *join)
DBUG_VOID_RETURN;
}
+
+/*
+ Print the current state during query optimization.
+
+ SYNOPSIS
+ print_plan()
+ join pointer to the structure providing all context info for
+ the query
+ read_time the cost of the best partial plan
+ record_count estimate for the number of records returned by the best
+ partial plan
+ idx length of the partial QEP in 'join->positions';
+ also an index in the array 'join->best_ref';
+ info comment string to appear above the printout
+
+ DESCRIPTION
+ This function prints to the log file DBUG_FILE the members of 'join' that
+ are used during query optimization (join->positions, join->best_positions,
+ and join->best_ref) and few other related variables (read_time,
+ record_count).
+ Useful to trace query optimizer functions.
+
+ RETURN
+ None
+*/
+
+void
+print_plan(JOIN* join, double read_time, double record_count,
+ uint idx, const char *info)
+{
+ uint i;
+ POSITION pos;
+ JOIN_TAB *join_table;
+ JOIN_TAB **plan_nodes;
+ TABLE* table;
+
+ if (info == 0)
+ info= "";
+
+ DBUG_LOCK_FILE;
+ if (join->best_read == DBL_MAX)
+ {
+ fprintf(DBUG_FILE,"%s; idx:%u, best: DBL_MAX, current:%g\n",
+ info, idx, read_time);
+ }
+ else
+ {
+ fprintf(DBUG_FILE,"%s; idx: %u, best: %g, current: %g\n",
+ info, idx, join->best_read, read_time);
+ }
+
+ /* Print the tables in JOIN->positions */
+ fputs(" POSITIONS: ", DBUG_FILE);
+ for (i= 0; i < idx ; i++)
+ {
+ pos = join->positions[i];
+ table= pos.table->table;
+ if (table)
+ fputs(table->s->table_name, DBUG_FILE);
+ fputc(' ', DBUG_FILE);
+ }
+ fputc('\n', DBUG_FILE);
+
+ /*
+ Print the tables in JOIN->best_positions only if at least one complete plan
+ has been found. An indicator for this is the value of 'join->best_read'.
+ */
+ fputs("BEST_POSITIONS: ", DBUG_FILE);
+ if (join->best_read < DBL_MAX)
+ {
+ for (i= 0; i < idx ; i++)
+ {
+ pos= join->best_positions[i];
+ table= pos.table->table;
+ if (table)
+ fputs(table->s->table_name, DBUG_FILE);
+ fputc(' ', DBUG_FILE);
+ }
+ }
+ fputc('\n', DBUG_FILE);
+
+ /* Print the tables in JOIN->best_ref */
+ fputs(" BEST_REF: ", DBUG_FILE);
+ for (plan_nodes= join->best_ref ; *plan_nodes ; plan_nodes++)
+ {
+ join_table= (*plan_nodes);
+ fputs(join_table->table->s->table_name, DBUG_FILE);
+ fprintf(DBUG_FILE, "(%lu,%lu,%lu)",
+ (ulong) join_table->found_records,
+ (ulong) join_table->records,
+ (ulong) join_table->read_time);
+ fputc(' ', DBUG_FILE);
+ }
+ fputc('\n', DBUG_FILE);
+
+ DBUG_UNLOCK_FILE;
+}
+
#endif
typedef struct st_debug_lock
@@ -233,12 +332,12 @@ static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data,
if (data)
{
TABLE *table=(TABLE *)data->debug_print_param;
- if (table && table->tmp_table == NO_TMP_TABLE)
+ if (table && table->s->tmp_table == NO_TMP_TABLE)
{
TABLE_LOCK_INFO table_lock_info;
- table_lock_info.thread_id=table->in_use->thread_id;
- memcpy(table_lock_info.table_name, table->table_cache_key,
- table->key_length);
+ table_lock_info.thread_id= table->in_use->thread_id;
+ memcpy(table_lock_info.table_name, table->s->table_cache_key,
+ table->s->key_length);
table_lock_info.table_name[strlen(table_lock_info.table_name)]='.';
table_lock_info.waiting=wait;
table_lock_info.lock_text=text;
@@ -337,29 +436,24 @@ reads: %10lu\n\n",
}
-void mysql_print_status(THD *thd)
+void mysql_print_status()
{
char current_dir[FN_REFLEN];
+ STATUS_VAR tmp;
+
+ calc_sum_of_all_status(&tmp);
printf("\nStatus information:\n\n");
my_getwd(current_dir, sizeof(current_dir),MYF(0));
printf("Current dir: %s\n", current_dir);
printf("Running threads: %d Stack size: %ld\n", thread_count,
(long) thread_stack);
- if (thd)
- thd->proc_info="locks";
thr_print_locks(); // Write some debug info
#ifndef DBUG_OFF
- if (thd)
- thd->proc_info="table cache";
print_cached_tables();
#endif
/* Print key cache status */
- if (thd)
- thd->proc_info="key cache";
puts("\nKey caches:");
process_key_caches(print_key_cache_status);
- if (thd)
- thd->proc_info="status";
pthread_mutex_lock(&LOCK_status);
printf("\nhandler status:\n\
read_key: %10lu\n\
@@ -369,16 +463,20 @@ read_first: %10lu\n\
write: %10lu\n\
delete %10lu\n\
update: %10lu\n",
- ha_read_key_count, ha_read_next_count,
- ha_read_rnd_count, ha_read_first_count,
- ha_write_count, ha_delete_count, ha_update_count);
+ tmp.ha_read_key_count,
+ tmp.ha_read_next_count,
+ tmp.ha_read_rnd_count,
+ tmp.ha_read_first_count,
+ tmp.ha_write_count,
+ tmp.ha_delete_count,
+ tmp.ha_update_count);
pthread_mutex_unlock(&LOCK_status);
printf("\nTable status:\n\
Opened tables: %10lu\n\
Open tables: %10lu\n\
Open files: %10lu\n\
Open streams: %10lu\n",
- opened_tables,
+ tmp.opened_tables,
(ulong) cached_tables(),
(ulong) my_file_opened,
(ulong) my_stream_opened);
@@ -396,8 +494,6 @@ Next alarm time: %lu\n",
#endif
display_table_locks();
fflush(stdout);
- if (thd)
- thd->proc_info="malloc";
my_checkmalloc();
TERMINATE(stdout); // Write malloc information
@@ -428,6 +524,4 @@ Estimated memory (with thread stack): %ld\n",
(long) (thread_count * thread_stack + info.hblkhd + info.arena));
#endif
puts("");
- if (thd)
- thd->proc_info=0;
}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
new file mode 100644
index 00000000000..5b6f12eab52
--- /dev/null
+++ b/sql/sql_trigger.cc
@@ -0,0 +1,482 @@
+#include "mysql_priv.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
+#include "parse_file.h"
+
+static const LEX_STRING triggers_file_type= {(char *)"TRIGGERS", 8};
+
+const char * const triggers_file_ext= ".TRG";
+
+/*
+ Table of .TRG file field descriptors.
+ We have here only one field now because in nearest future .TRG
+ files will be merged into .FRM files (so we don't need something
+ like md5 or created fields).
+*/
+static File_option triggers_file_parameters[]=
+{
+ {{(char*)"triggers", 8}, offsetof(class Table_triggers_list, definitions_list),
+ FILE_OPTIONS_STRLIST},
+ {{0, 0}, 0, FILE_OPTIONS_STRING}
+};
+
+
+/*
+ Create or drop trigger for table.
+
+ SYNOPSIS
+ mysql_create_or_drop_trigger()
+ thd - current thread context (including trigger definition in LEX)
+ tables - table list containing one table for which trigger is created.
+ create - whenever we create (true) or drop (false) trigger
+
+ NOTE
+ This function is mainly responsible for opening and locking of table and
+ invalidation of all its instances in table cache after trigger creation.
+ Real work on trigger creation/dropping is done inside Table_triggers_list
+ methods.
+
+ RETURN VALUE
+ FALSE Success
+ TRUE error
+*/
+bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
+{
+ TABLE *table;
+ bool result= 0;
+
+ DBUG_ENTER("mysql_create_or_drop_trigger");
+
+ /*
+ QQ: This function could be merged in mysql_alter_table() function
+ But do we want this ?
+ */
+
+ if (open_and_lock_tables(thd, tables))
+ DBUG_RETURN(TRUE);
+
+ /*
+ TODO: We should check if user has TRIGGER privilege for table here.
+ Now we just require SUPER privilege for creating/dropping because
+ we don't have proper privilege checking for triggers in place yet.
+ */
+ 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
+ Table_triggers_list::create_trigger() because we want to avoid messing
+ with table cash for views and temporary tables.
+ */
+ if (tables->view || table->s->tmp_table != NO_TMP_TABLE)
+ {
+ my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
+ DBUG_RETURN(TRUE);
+ }
+
+ if (!table->triggers)
+ {
+ if (!create)
+ {
+ my_message(ER_TRG_DOES_NOT_EXIST, ER(ER_TRG_DOES_NOT_EXIST), MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ if (!(table->triggers= new (&table->mem_root) Table_triggers_list()))
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ We don't want perform our operations while global read lock is held
+ so we have to wait until its end and then prevent it from occuring
+ again until we are done. (Acquiring LOCK_open is not enough because
+ global read lock is held without helding LOCK_open).
+ */
+ if (wait_if_global_read_lock(thd, 0, 0))
+ DBUG_RETURN(TRUE);
+
+ VOID(pthread_mutex_lock(&LOCK_open));
+ result= (create ?
+ table->triggers->create_trigger(thd, tables):
+ table->triggers->drop_trigger(thd, tables));
+
+ /* It is sensible to invalidate table in any case */
+ close_cached_table(thd, table);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ start_waiting_global_read_lock(thd);
+
+ if (!result)
+ send_ok(thd);
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Create trigger for table.
+
+ SYNOPSIS
+ create_trigger()
+ thd - current thread context (including trigger definition in LEX)
+ tables - table list containing one open table for which trigger is
+ created.
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
+{
+ LEX *lex= thd->lex;
+ TABLE *table= tables->table;
+ char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
+ LEX_STRING dir, file;
+ LEX_STRING *trg_def, *name;
+ Item_trigger_field *trg_field;
+ List_iterator_fast<LEX_STRING> it(names_list);
+
+ /* We don't allow creation of several triggers of the same type yet */
+ if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time])
+ {
+ my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0));
+ return 1;
+ }
+
+ /* Let us check if trigger with the same name exists */
+ while ((name= it++))
+ {
+ if (my_strcasecmp(system_charset_info, lex->ident.str,
+ name->str) == 0)
+ {
+ my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0));
+ return 1;
+ }
+ }
+
+ /*
+ Let us check if all references to fields in old/new versions of row in
+ this trigger are ok.
+
+ NOTE: We do it here more from ease of use standpoint. We still have to
+ do some checks on each execution. E.g. we can catch privilege changes
+ only during execution. Also in near future, when we will allow access
+ to other tables from trigger we won't be able to catch changes in other
+ tables...
+
+ To simplify code a bit we have to create Fields for accessing to old row
+ values if we have ON UPDATE trigger.
+ */
+ if (!old_field && lex->trg_chistics.event == TRG_EVENT_UPDATE &&
+ prepare_old_row_accessors(table))
+ return 1;
+
+ for (trg_field= (Item_trigger_field *)(lex->trg_table_fields.first);
+ trg_field; trg_field= trg_field->next_trg_field)
+ {
+ trg_field->setup_field(thd, table, lex->trg_chistics.event);
+ if (!trg_field->fixed &&
+ trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0))
+ return 1;
+ }
+
+ /*
+ Here we are creating file with triggers and save all triggers in it.
+ sql_create_definition_file() files handles renaming and backup of older
+ versions
+ */
+ strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", tables->db, "/", NullS);
+ dir.length= unpack_filename(dir_buff, dir_buff);
+ dir.str= dir_buff;
+ file.length= strxnmov(file_buff, FN_REFLEN, tables->table_name,
+ triggers_file_ext, NullS) - file_buff;
+ file.str= file_buff;
+
+ /*
+ Soon we will invalidate table object and thus Table_triggers_list object
+ so don't care about place to which trg_def->ptr points and other
+ invariants (e.g. we don't bother to update names_list)
+
+ QQ: Hmm... probably we should not care about setting up active thread
+ mem_root too.
+ */
+ if (!(trg_def= (LEX_STRING *)alloc_root(&table->mem_root,
+ sizeof(LEX_STRING))) ||
+ definitions_list.push_back(trg_def, &table->mem_root))
+ return 1;
+
+ trg_def->str= thd->query;
+ trg_def->length= thd->query_length;
+
+ return sql_create_definition_file(&dir, &file, &triggers_file_type,
+ (gptr)this, triggers_file_parameters, 3);
+}
+
+
+/*
+ Drop trigger for table.
+
+ SYNOPSIS
+ drop_trigger()
+ thd - current thread context (including trigger definition in LEX)
+ tables - table list containing one open table for which trigger is
+ dropped.
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
+{
+ LEX *lex= thd->lex;
+ LEX_STRING *name;
+ List_iterator_fast<LEX_STRING> it_name(names_list);
+ List_iterator<LEX_STRING> it_def(definitions_list);
+
+ while ((name= it_name++))
+ {
+ it_def++;
+
+ if (my_strcasecmp(system_charset_info, lex->ident.str,
+ name->str) == 0)
+ {
+ /*
+ Again we don't care much about other things required for
+ clean trigger removing since table will be reopened anyway.
+ */
+ it_def.remove();
+
+ if (definitions_list.is_empty())
+ {
+ char path[FN_REFLEN];
+
+ /*
+ TODO: Probably instead of removing .TRG file we should move
+ to archive directory but this should be done as part of
+ parse_file.cc functionality (because we will need it
+ elsewhere).
+ */
+ strxnmov(path, FN_REFLEN, mysql_data_home, "/", tables->db, "/",
+ tables->table_name, triggers_file_ext, NullS);
+ unpack_filename(path, path);
+ return my_delete(path, MYF(MY_WME));
+ }
+ else
+ {
+ char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
+ LEX_STRING dir, file;
+
+ strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", tables->db,
+ "/", NullS);
+ dir.length= unpack_filename(dir_buff, dir_buff);
+ dir.str= dir_buff;
+ file.length= strxnmov(file_buff, FN_REFLEN, tables->table_name,
+ triggers_file_ext, NullS) - file_buff;
+ file.str= file_buff;
+
+ return sql_create_definition_file(&dir, &file, &triggers_file_type,
+ (gptr)this,
+ triggers_file_parameters, 3);
+ }
+ }
+ }
+
+ my_message(ER_TRG_DOES_NOT_EXIST, ER(ER_TRG_DOES_NOT_EXIST), MYF(0));
+ return 1;
+}
+
+
+Table_triggers_list::~Table_triggers_list()
+{
+ for (int i= 0; i < 3; i++)
+ for (int j= 0; j < 2; j++)
+ delete bodies[i][j];
+
+ if (old_field)
+ for (Field **fld_ptr= old_field; *fld_ptr; fld_ptr++)
+ delete *fld_ptr;
+}
+
+
+/*
+ Prepare array of Field objects which will represent OLD.* row values in
+ ON UPDATE trigger (by referencing to record[1] instead of record[0]).
+
+ SYNOPSIS
+ prepare_old_row_accessors()
+ table - pointer to TABLE object for which we are creating fields.
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+bool Table_triggers_list::prepare_old_row_accessors(TABLE *table)
+{
+ Field **fld, **old_fld;
+
+ if (!(old_field= (Field **)alloc_root(&table->mem_root,
+ (table->s->fields + 1) *
+ sizeof(Field*))))
+ return 1;
+
+ for (fld= table->field, old_fld= old_field; *fld; fld++, old_fld++)
+ {
+ /*
+ QQ: it is supposed that it is ok to use this function for field
+ cloning...
+ */
+ if (!(*old_fld= (*fld)->new_field(&table->mem_root, table)))
+ return 1;
+ (*old_fld)->move_field((my_ptrdiff_t)(table->record[1] -
+ table->record[0]));
+ }
+ *old_fld= 0;
+
+ return 0;
+}
+
+
+/*
+ Check whenever .TRG file for table exist and load all triggers it contains.
+
+ SYNOPSIS
+ check_n_load()
+ thd - current thread context
+ db - table's database name
+ table_name - table's name
+ table - pointer to table object
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+bool Table_triggers_list::check_n_load(THD *thd, const char *db,
+ const char *table_name, TABLE *table)
+{
+ char path_buff[FN_REFLEN];
+ LEX_STRING path;
+ File_parser *parser;
+
+ DBUG_ENTER("Table_triggers_list::check_n_load");
+
+ strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", db, "/", table_name,
+ triggers_file_ext, NullS);
+ path.length= unpack_filename(path_buff, path_buff);
+ path.str= path_buff;
+
+ // QQ: should we analyze errno somehow ?
+ if (access(path_buff, F_OK))
+ DBUG_RETURN(0);
+
+ /*
+ File exists so we got to load triggers
+ FIXME: A lot of things to do here e.g. how about other funcs and being
+ more paranoical ?
+ */
+
+ if ((parser= sql_parse_prepare(&path, &table->mem_root, 1)))
+ {
+ if (!strncmp(triggers_file_type.str, parser->type()->str,
+ parser->type()->length))
+ {
+ Table_triggers_list *triggers=
+ new (&table->mem_root) Table_triggers_list();
+
+ if (!triggers)
+ DBUG_RETURN(1);
+
+ if (parser->parse((gptr)triggers, &table->mem_root,
+ triggers_file_parameters, 1))
+ DBUG_RETURN(1);
+
+ table->triggers= triggers;
+
+ /* TODO: This could be avoided if there is no ON UPDATE trigger. */
+ if (triggers->prepare_old_row_accessors(table))
+ DBUG_RETURN(1);
+
+ List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
+ LEX_STRING *trg_create_str, *trg_name_str;
+ char *trg_name_buff;
+ LEX *old_lex= thd->lex, lex;
+
+ thd->lex= &lex;
+
+ while ((trg_create_str= it++))
+ {
+ lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length);
+
+ if (yyparse((void *)thd) || thd->is_fatal_error)
+ {
+ /*
+ Free lex associated resources
+ QQ: Do we really need all this stuff here ?
+ */
+ if (lex.sphead)
+ {
+ delete lex.sphead;
+ lex.sphead= 0;
+ }
+ goto err_with_lex_cleanup;
+ }
+
+ triggers->bodies[lex.trg_chistics.event]
+ [lex.trg_chistics.action_time]= lex.sphead;
+ lex.sphead= 0;
+
+ if (!(trg_name_buff= alloc_root(&table->mem_root,
+ sizeof(LEX_STRING) +
+ lex.ident.length + 1)))
+ goto err_with_lex_cleanup;
+
+ trg_name_str= (LEX_STRING *)trg_name_buff;
+ trg_name_buff+= sizeof(LEX_STRING);
+ memcpy(trg_name_buff, lex.ident.str,
+ lex.ident.length + 1);
+ trg_name_str->str= trg_name_buff;
+ trg_name_str->length= lex.ident.length;
+
+ if (triggers->names_list.push_back(trg_name_str, &table->mem_root))
+ goto err_with_lex_cleanup;
+
+ /*
+ Let us bind Item_trigger_field objects representing access to fields
+ in old/new versions of row in trigger to Field objects in table being
+ opened.
+
+ We ignore errors here, because if even something is wrong we still will
+ be willing to open table to perform some operations (e.g. SELECT)...
+ Anyway some things can be checked only during trigger execution.
+ */
+ for (Item_trigger_field *trg_field=
+ (Item_trigger_field *)(lex.trg_table_fields.first);
+ trg_field;
+ trg_field= trg_field->next_trg_field)
+ trg_field->setup_field(thd, table, lex.trg_chistics.event);
+
+ lex_end(&lex);
+ }
+ thd->lex= old_lex;
+
+ DBUG_RETURN(0);
+
+err_with_lex_cleanup:
+ // QQ: anything else ?
+ lex_end(&lex);
+ thd->lex= old_lex;
+ DBUG_RETURN(1);
+ }
+
+ /*
+ We don't care about this error message much because .TRG files will
+ be merged into .FRM anyway.
+ */
+ my_error(ER_WRONG_OBJECT, MYF(0),
+ table_name, triggers_file_ext, "TRIGGER");
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(1);
+}
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
new file mode 100644
index 00000000000..7dd6734eb89
--- /dev/null
+++ b/sql/sql_trigger.h
@@ -0,0 +1,78 @@
+/*
+ This class holds all information about triggers of table.
+
+ QQ: Will it be merged into TABLE in future ?
+*/
+class Table_triggers_list: public Sql_alloc
+{
+ /* Triggers as SPs grouped by event, action_time */
+ sp_head *bodies[3][2];
+ /*
+ Copy of TABLE::Field array with field pointers set to old version
+ of record, used for OLD values in trigger on UPDATE.
+ */
+ Field **old_field;
+ /*
+ Names of triggers.
+ Should correspond to order of triggers on definitions_list,
+ used in CREATE/DROP TRIGGER for looking up trigger by name.
+ */
+ List<LEX_STRING> names_list;
+
+public:
+ /*
+ Field responsible for storing triggers definitions in file.
+ It have to be public because we are using it directly from parser.
+ */
+ List<LEX_STRING> definitions_list;
+
+ Table_triggers_list():
+ old_field(0)
+ {
+ bzero((char *)bodies, sizeof(bodies));
+ }
+ ~Table_triggers_list();
+
+ bool create_trigger(THD *thd, TABLE_LIST *table);
+ bool drop_trigger(THD *thd, TABLE_LIST *table);
+ bool process_triggers(THD *thd, trg_event_type event,
+ trg_action_time_type time_type)
+ {
+ int res= 0;
+
+ if (bodies[event][time_type])
+ {
+#ifndef EMBEDDED_LIBRARY
+ /* Surpress OK packets in case if we will execute statements */
+ my_bool nsok= thd->net.no_send_ok;
+ thd->net.no_send_ok= TRUE;
+#endif
+
+ /*
+ FIXME: We should juggle with security context here (because trigger
+ should be invoked with creator rights).
+ */
+ res= bodies[event][time_type]->execute_function(thd, 0, 0, 0);
+
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ }
+
+ return res;
+ }
+
+ static bool check_n_load(THD *thd, const char *db, const char *table_name,
+ TABLE *table);
+
+ bool has_delete_triggers()
+ {
+ return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
+ bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]);
+ }
+
+ friend class Item_trigger_field;
+
+private:
+ bool prepare_old_row_accessors(TABLE *table);
+};
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 661bf6e8197..f5d64efb5e9 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -17,15 +17,15 @@
/* This implements 'user defined functions' */
/*
-** Known bugs:
-**
-** Memory for functions are never freed!
-** Shared libraries are not closed before mysqld exists;
-** - This is because we can't be sure if some threads is using
-** a functions.
-**
-** The buggs only affects applications that creates and frees a lot of
-** dynamic functions, so this shouldn't be a real problem.
+ Known bugs:
+
+ Memory for functions is never freed!
+ Shared libraries are not closed before mysqld exits;
+ - This is because we can't be sure if some threads are using
+ a function.
+
+ The bugs only affect applications that create and free a lot of
+ dynamic functions, so this shouldn't be a real problem.
*/
#ifdef __GNUC__
@@ -110,15 +110,15 @@ static char *init_syms(udf_func *tmp, char *nm)
*/
if (!tmp->func_init && !tmp->func_deinit && tmp->type != UDFTYPE_AGGREGATE)
{
- if (opt_allow_suspicious_udfs)
- sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), nm);
- else
+ if (!opt_allow_suspicious_udfs)
return nm;
+ if (current_thd->variables.log_warnings)
+ sql_print_warning(ER(ER_CANT_FIND_DL_ENTRY), nm);
}
-
return 0;
}
+
extern "C" byte* get_hash_key(const byte *buff,uint *length,
my_bool not_used __attribute__((unused)))
{
@@ -127,9 +127,10 @@ extern "C" byte* get_hash_key(const byte *buff,uint *length,
return (byte*) udf->name.str;
}
+
/*
-** Read all predeclared functions from mysql.func and accept all that
-** can be used.
+ Read all predeclared functions from mysql.func and accept all that
+ can be used.
*/
void udf_init()
@@ -163,7 +164,7 @@ void udf_init()
new_thd->db_length=5;
bzero((gptr) &tables,sizeof(tables));
- tables.alias= tables.real_name= (char*) "func";
+ tables.alias= tables.table_name= (char*) "func";
tables.lock_type = TL_READ;
tables.db=new_thd->db;
@@ -185,7 +186,7 @@ void udf_init()
char *dl_name= get_field(&mem, table->field[2]);
bool new_dl=0;
Item_udftype udftype=UDFTYPE_FUNCTION;
- if (table->fields >= 4) // New func table
+ if (table->s->fields >= 4) // New func table
udftype=(Item_udftype) table->field[3]->val_int();
/*
@@ -400,7 +401,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
if (!initialized)
{
- send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
DBUG_RETURN(1);
}
@@ -411,19 +412,19 @@ int mysql_create_function(THD *thd,udf_func *udf)
*/
if (strchr(udf->dl, '/'))
{
- send_error(thd, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS));
+ my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0));
DBUG_RETURN(1);
}
if (udf->name.length > NAME_LEN)
{
- net_printf(thd, ER_TOO_LONG_IDENT,udf->name);
+ my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name);
DBUG_RETURN(1);
}
rw_wrlock(&THR_LOCK_udf);
if ((hash_search(&udf_hash,(byte*) udf->name.str, udf->name.length)))
{
- net_printf(thd, ER_UDF_EXISTS, udf->name);
+ my_error(ER_UDF_EXISTS, MYF(0), udf->name);
goto err;
}
if (!(dl = find_udf_dl(udf->dl)))
@@ -432,7 +433,8 @@ int mysql_create_function(THD *thd,udf_func *udf)
{
DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)",
udf->dl,errno,dlerror()));
- net_printf(thd, ER_CANT_OPEN_LIBRARY, udf->dl, errno, dlerror());
+ my_error(ER_CANT_OPEN_LIBRARY, MYF(0),
+ udf->dl, errno, dlerror());
goto err;
}
new_dl=1;
@@ -442,17 +444,14 @@ int mysql_create_function(THD *thd,udf_func *udf)
char buf[MAX_FIELD_NAME+16], *missing;
if ((missing= init_syms(udf, buf)))
{
- net_printf(thd, ER_CANT_FIND_DL_ENTRY, missing);
+ my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), missing);
goto err;
}
}
udf->name.str=strdup_root(&mem,udf->name.str);
udf->dl=strdup_root(&mem,udf->dl);
if (!(u_d=add_udf(&udf->name,udf->returns,udf->dl,udf->type)))
- {
- send_error(thd,0); // End of memory
goto err;
- }
u_d->dlhandle = dl;
u_d->func=udf->func;
u_d->func_init=udf->func_init;
@@ -464,23 +463,23 @@ int mysql_create_function(THD *thd,udf_func *udf)
bzero((char*) &tables,sizeof(tables));
tables.db= (char*) "mysql";
- tables.real_name= tables.alias= (char*) "func";
+ tables.table_name= tables.alias= (char*) "func";
/* Allow creation of functions even if we can't open func table */
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
- restore_record(table,default_values); // Default values for fields
+ restore_record(table, s->default_values); // Default values for fields
table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info);
table->field[1]->store((longlong) u_d->returns);
table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info);
- if (table->fields >= 4) // If not old func format
+ if (table->s->fields >= 4) // If not old func format
table->field[3]->store((longlong) u_d->type);
error = table->file->write_row(table->record[0]);
close_thread_tables(thd);
if (error)
{
- net_printf(thd, ER_ERROR_ON_WRITE, "mysql.func",error);
+ my_error(ER_ERROR_ON_WRITE, MYF(0), "mysql.func", error);
del_udf(u_d);
goto err;
}
@@ -503,14 +502,14 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
DBUG_ENTER("mysql_drop_function");
if (!initialized)
{
- send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
DBUG_RETURN(1);
}
rw_wrlock(&THR_LOCK_udf);
if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name->str,
(uint) udf_name->length)))
{
- net_printf(thd, ER_FUNCTION_NOT_DEFINED, udf_name->str);
+ my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
goto err;
}
del_udf(udf);
@@ -523,7 +522,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
bzero((char*) &tables,sizeof(tables));
tables.db=(char*) "mysql";
- tables.real_name= tables.alias= (char*) "func";
+ tables.table_name= tables.alias= (char*) "func";
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
table->field[0]->store(udf_name->str, udf_name->length, system_charset_info);
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index d1f99a6d232..51ea6d4d627 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -103,6 +103,7 @@ class udf_handler :public Sql_alloc
*null_value=0;
return tmp;
}
+ my_decimal *val_decimal(my_bool *null_value, my_decimal *dec_buf);
void clear()
{
is_null= 0;
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index a54fb613fd2..00770ba02a2 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -24,14 +24,20 @@
#include "mysql_priv.h"
#include "sql_select.h"
-int mysql_union(THD *thd, LEX *lex, select_result *result,
- SELECT_LEX_UNIT *unit)
+bool mysql_union(THD *thd, LEX *lex, select_result *result,
+ SELECT_LEX_UNIT *unit, ulong setup_tables_done_option)
{
DBUG_ENTER("mysql_union");
- int res= 0;
- if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK, "")))
+ bool res;
+ if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK |
+ setup_tables_done_option, "")))
res= unit->exec();
- res|= unit->cleanup();
+ if (!res && thd->cursor && thd->cursor->is_open())
+ {
+ thd->cursor->set_unit(unit);
+ }
+ else
+ res|= unit->cleanup();
DBUG_RETURN(res);
}
@@ -43,12 +49,6 @@ int mysql_union(THD *thd, LEX *lex, select_result *result,
select_union::select_union(TABLE *table_par)
:table(table_par)
{
- bzero((char*) &info,sizeof(info));
- /*
- We can always use IGNORE because the temporary table will only
- contain a unique key if we are using not using UNION ALL
- */
- info.ignore= 1;
}
select_union::~select_union()
@@ -65,22 +65,21 @@ int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
bool select_union::send_data(List<Item> &values)
{
+ int error= 0;
if (unit->offset_limit_cnt)
{ // using limit offset,count
unit->offset_limit_cnt--;
return 0;
}
- fill_record(table->field, values, 1);
- if (thd->net.report_error || write_record(table,&info))
+ fill_record(thd, table->field, values, 1);
+ if (thd->net.report_error)
+ return 1;
+
+ if ((error= table->file->write_row(table->record[0])))
{
- if (thd->net.last_errno == ER_RECORD_FILE_FULL)
- {
- thd->clear_error(); // do not report user about table overflow
- if (create_myisam_from_heap(thd, table, &tmp_table_param,
- info.last_errno, 1))
- return 1;
- }
- else
+ /* create_myisam_from_heap will generate error if needed */
+ if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE &&
+ create_myisam_from_heap(thd, table, &tmp_table_param, error, 1))
return 1;
}
return 0;
@@ -98,8 +97,7 @@ bool select_union::flush()
int error;
if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
{
- table->file->print_error(error,MYF(0));
- ::send_error(thd);
+ table->file->print_error(error, MYF(0));
return 1;
}
return 0;
@@ -136,14 +134,14 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
fake_select_lex->ftfunc_list= &fake_select_lex->ftfunc_list_alloc;
fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
(byte **)
- &result_table_list.next);
+ &result_table_list.next_local);
return options_tmp;
}
-int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
- ulong additional_options,
- const char *tmp_table_alias)
+bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
+ ulong additional_options,
+ const char *tmp_table_alias)
{
SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
SELECT_LEX *sl, *first_select;
@@ -173,16 +171,16 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (!sl->join->procedure &&
result->prepare(sl->join->fields_list, this))
{
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
sl->join->select_options|= SELECT_DESCRIBE;
sl->join->reinit();
}
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
prepared= 1;
- res= 0;
+ res= FALSE;
thd_arg->lex->current_select= sl= first_select= first_select_in_union();
found_rows_for_union= first_select->options & OPTION_FOUND_ROWS;
@@ -208,22 +206,26 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
JOIN *join= new JOIN(thd_arg, sl->item_list,
sl->options | thd_arg->options | additional_options,
tmp_result);
+ /*
+ setup_tables_done_option should be set only for very first SELECT,
+ because it protect from secont setup_tables call for select-like non
+ select commands (DELETE/INSERT/...) and they use only very first
+ SELECT (for union it can be only INSERT ... SELECT).
+ */
+ additional_options&= ~OPTION_SETUP_TABLES_DONE;
if (!join)
goto err;
thd_arg->lex->current_select= sl;
- offset_limit_cnt= sl->offset_limit;
- select_limit_cnt= sl->select_limit+sl->offset_limit;
- if (select_limit_cnt < sl->select_limit)
- select_limit_cnt= HA_POS_ERROR; // no limit
+ set_limit(sl, sl);
can_skip_order_by= is_union &&
(!sl->braces || select_limit_cnt == HA_POS_ERROR);
-
+
res= join->prepare(&sl->ref_pointer_array,
(TABLE_LIST*) sl->table_list.first, sl->with_wild,
sl->where,
- (can_skip_order_by ? 0 : sl->order_list.elements) +
+ (can_skip_order_by ? 0 : sl->order_list.elements) +
sl->group_list.elements,
can_skip_order_by ?
(ORDER*) 0 : (ORDER *)sl->order_list.first,
@@ -235,7 +237,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
/* There are no * in the statement anymore (for PS) */
sl->with_wild= 0;
last_procedure= join->procedure;
- if (res || thd_arg->is_fatal_error)
+
+ if ((res= (res || thd_arg->is_fatal_error)))
goto err;
if (sl == first_select)
{
@@ -273,7 +276,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
while ((type= tp++, item_tmp= it++))
{
if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
}
@@ -287,6 +290,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
List_iterator_fast<Item> tp(types);
Item_arena *arena= thd->current_arena;
Item *type;
+
while ((type= tp++))
{
if (type->result_type() == STRING_RESULT &&
@@ -310,21 +314,17 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
bzero((char*) &result_table_list, sizeof(result_table_list));
result_table_list.db= (char*) "";
- result_table_list.real_name= result_table_list.alias= (char*) "union";
+ result_table_list.table_name= result_table_list.alias= (char*) "union";
result_table_list.table= table;
union_result->set_table(table);
thd_arg->lex->current_select= lex_select_save;
if (!item_list.elements)
{
- /*
- We're in statement prepare or in execution
- of a conventional statement.
- */
+ Field **field;
Item_arena *tmp_arena,backup;
tmp_arena= thd->change_arena_if_needed(&backup);
- Field **field;
for (field= table->field; *field; field++)
{
Item_field *item= new Item_field(*field);
@@ -332,7 +332,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
if (tmp_arena)
thd->restore_backup_item_arena(tmp_arena, &backup);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
if (tmp_arena)
@@ -341,11 +341,15 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
/* prepare fake select to initialize it correctly */
(void) init_prepare_fake_select_lex(thd);
+ /*
+ Should be done only once (the only item_list per statement).
+ */
+ DBUG_ASSERT(fake_select_lex->join == 0);
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
result)))
{
fake_select_lex->table_list.empty();
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
fake_select_lex->item_list= item_list;
@@ -362,17 +366,17 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
fake_select_lex->table_list.empty();
}
}
- else if (arena->is_stmt_execute())
+ else if (!arena->is_conventional())
{
/*
- We're in execution of a prepared statement: reset field items
- to point at fields from the created temporary table.
+ We're in execution of a prepared statement or stored procedure:
+ reset field items to point at fields from the created temporary table.
*/
List_iterator_fast<Item> it(item_list);
for (Field **field= table->field; *field; field++)
{
Item_field *item_field= (Item_field*) it++;
- DBUG_ASSERT(item_field);
+ DBUG_ASSERT(item_field != 0);
item_field->reset_field(*field);
}
}
@@ -380,15 +384,15 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= lex_select_save;
- DBUG_RETURN(res || thd_arg->is_fatal_error ? 1 : 0);
+ DBUG_RETURN(res || thd_arg->is_fatal_error);
err:
thd_arg->lex->current_select= lex_select_save;
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
-int st_select_lex_unit::exec()
+bool st_select_lex_unit::exec()
{
SELECT_LEX *lex_select_save= thd->lex->current_select;
SELECT_LEX *select_cursor=first_select_in_union();
@@ -397,7 +401,7 @@ int st_select_lex_unit::exec()
DBUG_ENTER("st_select_lex_unit::exec");
if (executed && !uncacheable && !describe)
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
executed= 1;
if (uncacheable || !item || !item->assigned() || describe)
@@ -462,7 +466,7 @@ int st_select_lex_unit::exec()
if (sl == union_distinct)
{
if (table->file->disable_indexes(HA_KEY_SWITCH_ALL))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
table->no_keyread=1;
}
res= sl->join->error;
@@ -501,7 +505,7 @@ int st_select_lex_unit::exec()
optimized= 1;
/* Send result to 'result' */
- res= -1;
+ res= TRUE;
{
List<Item_func_match> empty_list;
empty_list.empty();
@@ -516,11 +520,11 @@ int st_select_lex_unit::exec()
allocate JOIN for fake select only once (prevent
mysql_select automatic allocation)
*/
- if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
- result)))
+ if (!(fake_select_lex->join= new JOIN(thd, item_list,
+ fake_select_lex->options, result)))
{
fake_select_lex->table_list.empty();
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
/*
@@ -532,12 +536,14 @@ int st_select_lex_unit::exec()
else
{
JOIN_TAB *tab,*end;
- for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ for (tab=join->join_tab, end=tab+join->tables ;
+ tab && tab != end ;
+ tab++)
{
delete tab->select;
delete tab->quick;
}
- join->init(thd, item_list, thd->options, result);
+ join->init(thd, item_list, fake_select_lex->options, result);
}
res= mysql_select(thd, &fake_select_lex->ref_pointer_array,
&result_table_list,
@@ -545,7 +551,7 @@ int st_select_lex_unit::exec()
global_parameters->order_list.elements,
(ORDER*)global_parameters->order_list.first,
(ORDER*) NULL, NULL, (ORDER*) NULL,
- options_tmp | SELECT_NO_UNLOCK,
+ fake_select_lex->options | SELECT_NO_UNLOCK,
result, this, fake_select_lex);
fake_select_lex->table_list.empty();
@@ -565,14 +571,15 @@ int st_select_lex_unit::exec()
}
-int st_select_lex_unit::cleanup()
+bool st_select_lex_unit::cleanup()
{
int error= 0;
+ JOIN *join;
DBUG_ENTER("st_select_lex_unit::cleanup");
if (cleaned)
{
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
cleaned= 1;
@@ -584,9 +591,8 @@ int st_select_lex_unit::cleanup()
free_tmp_table(thd, table);
table= 0; // Safety
}
- JOIN *join;
- SELECT_LEX *sl= first_select_in_union();
- for (; sl; sl= sl->next_select())
+
+ for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
{
if ((join= sl->join))
{
@@ -611,6 +617,7 @@ int st_select_lex_unit::cleanup()
error|= join->cleanup();
delete join;
}
+
DBUG_RETURN(error);
}
@@ -646,19 +653,19 @@ void st_select_lex_unit::reinit_exec_mechanism()
old_result old select_result object
RETURN
- 0 - OK
- -1 - error
+ FALSE - OK
+ TRUE - error
*/
-int st_select_lex_unit::change_result(select_subselect *result,
- select_subselect *old_result)
+bool st_select_lex_unit::change_result(select_subselect *result,
+ select_subselect *old_result)
{
- int res= 0;
+ bool res= FALSE;
for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
{
if (sl->join && sl->join->result == old_result)
- if ((res= sl->join->change_result(result)))
- return (res);
+ if (sl->join->change_result(result))
+ return TRUE;
}
if (fake_select_lex && fake_select_lex->join)
res= fake_select_lex->join->change_result(result);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 6c12381b4bd..86aa0bf9890 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -22,31 +22,90 @@
#include "mysql_priv.h"
#include "sql_select.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields);
/* Return 0 if row hasn't changed */
-static bool compare_record(TABLE *table, ulong query_id)
+static bool compare_record(TABLE *table, query_id_t query_id)
{
- if (!table->blob_fields)
+ if (table->s->blob_fields + table->s->varchar_fields == 0)
return cmp_record(table,record[1]);
/* Compare null bits */
if (memcmp(table->null_flags,
- table->null_flags+table->rec_buff_length,
- table->null_bytes))
- return 1; // Diff in NULL value
+ table->null_flags+table->s->rec_buff_length,
+ table->s->null_bytes))
+ return TRUE; // Diff in NULL value
/* Compare updated fields */
for (Field **ptr=table->field ; *ptr ; ptr++)
{
if ((*ptr)->query_id == query_id &&
- (*ptr)->cmp_binary_offset(table->rec_buff_length))
- return 1;
+ (*ptr)->cmp_binary_offset(table->s->rec_buff_length))
+ return TRUE;
}
- return 0;
+ return FALSE;
}
+/*
+ check that all fields are real fields
+
+ SYNOPSIS
+ check_fields()
+ thd thread handler
+ items Items for check
+
+ RETURN
+ TRUE Items can't be used in UPDATE
+ FALSE Items are OK
+*/
+
+static bool check_fields(THD *thd, List<Item> &items)
+{
+ List_iterator<Item> it(items);
+ Item *item;
+ Item_field *field;
+ while ((item= it++))
+ {
+ if (!(field= item->filed_for_view_update()))
+ {
+ /* item has name, because it comes from VIEW SELECT list */
+ my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name);
+ return TRUE;
+ }
+ /*
+ we make temporary copy of Item_field, to avoid influence of changing
+ result_field on Item_ref which refer on this field
+ */
+ thd->change_item_tree(it.ref(), new Item_field(thd, field));
+ }
+ return FALSE;
+}
+
+
+/*
+ Process usual UPDATE
+
+ SYNOPSIS
+ mysql_update()
+ thd thread handler
+ fields fields for update
+ values values of fields for update
+ conds WHERE clause expression
+ order_num number of elemen in ORDER BY clause
+ order ORDER BY clause list
+ limit limit clause
+ handle_duplicates how to handle duplicates
+
+ RETURN
+ 0 - OK
+ 2 - privilege check and openning table passed, but we need to convert to
+ multi-update because of view substitution
+ 1 - error
+*/
+
int mysql_update(THD *thd,
TABLE_LIST *table_list,
List<Item> &fields,
@@ -54,45 +113,62 @@ int mysql_update(THD *thd,
COND *conds,
uint order_num, ORDER *order,
ha_rows limit,
- enum enum_duplicates handle_duplicates,
- bool ignore)
+ enum enum_duplicates handle_duplicates, bool ignore)
{
- bool using_limit=limit != HA_POS_ERROR;
+ bool using_limit= limit != HA_POS_ERROR;
bool safe_update= thd->options & OPTION_SAFE_UPDATES;
- bool used_key_is_modified, transactional_table, log_delayed;
+ bool used_key_is_modified, transactional_table;
+ int res;
int error=0;
uint used_index;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege;
#endif
- ulong query_id=thd->query_id, timestamp_query_id;
+ uint table_count= 0;
+ query_id_t query_id=thd->query_id, timestamp_query_id;
ha_rows updated, found;
key_map old_used_keys;
TABLE *table;
SQL_SELECT *select;
READ_RECORD info;
- TABLE_LIST *update_table_list= ((TABLE_LIST*)
- thd->lex->select_lex.table_list.first);
+ SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_update");
LINT_INIT(timestamp_query_id);
- if ((open_and_lock_tables(thd, table_list)))
- DBUG_RETURN(-1);
+ if (open_tables(thd, &table_list, &table_count))
+ DBUG_RETURN(1);
+
+ if (table_list->ancestor && table_list->ancestor->next_local)
+ {
+ DBUG_ASSERT(table_list->view != 0);
+ DBUG_PRINT("info", ("Switch to multi-update"));
+ /* pass counter value */
+ thd->lex->table_count= table_count;
+ /* convert to multiupdate */
+ return 2;
+ }
+
+ if (lock_tables(thd, table_list, table_count) ||
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
+ (thd->fill_derived_tables() &&
+ mysql_handle_derived(thd->lex, &mysql_derived_filling)))
+ DBUG_RETURN(1);
+
thd->proc_info="init";
table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
/* Calculate "table->used_keys" based on the WHERE */
- table->used_keys=table->keys_in_use;
+ table->used_keys= table->s->keys_in_use;
table->quick_keys.clear_all();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- want_privilege= table->grant.want_privilege;
+ /* TABLE_LIST contain right privilages request */
+ want_privilege= table_list->grant.want_privilege;
#endif
- if ((error= mysql_prepare_update(thd, table_list, update_table_list,
- &conds, order_num, order)))
- DBUG_RETURN(error);
+ if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
+ DBUG_RETURN(1);
old_used_keys= table->used_keys; // Keys used in WHERE
/*
@@ -107,10 +183,25 @@ int mysql_update(THD *thd,
/* Check the fields we are going to modify */
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- table->grant.want_privilege=want_privilege;
+ table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
#endif
- if (setup_fields(thd, 0, update_table_list, fields, 1, 0, 0))
- DBUG_RETURN(-1); /* purecov: inspected */
+ {
+ 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 (table_list->view && check_fields(thd, fields))
+ {
+ DBUG_RETURN(1);
+ }
+ if (!table_list->updatable || check_key_in_view(thd, table_list))
+ {
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
+ DBUG_RETURN(1);
+ }
if (table->timestamp_field)
{
// Don't set timestamp column if this is modified
@@ -122,25 +213,26 @@ int mysql_update(THD *thd,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Check values */
- table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
+ table_list->grant.want_privilege= table->grant.want_privilege=
+ (SELECT_ACL & ~table->grant.privilege);
#endif
- if (setup_fields(thd, 0, update_table_list, values, 1, 0, 0))
+ if (setup_fields(thd, 0, table_list, values, 1, 0, 0))
{
- free_underlaid_joins(thd, &thd->lex->select_lex);
- DBUG_RETURN(-1); /* purecov: inspected */
+ free_underlaid_joins(thd, select_lex);
+ DBUG_RETURN(1); /* purecov: inspected */
}
// Don't count on usage of 'only index' when calculating which key to use
table->used_keys.clear_all();
- select=make_select(table,0,0,conds,&error);
+ select= make_select(table, 0, 0, conds, 0, &error);
if (error ||
(select && select->check_quick(thd, safe_update, limit)) || !limit)
{
delete select;
- free_underlaid_joins(thd, &thd->lex->select_lex);
+ free_underlaid_joins(thd, select_lex);
if (error)
{
- DBUG_RETURN(-1); // Error in where
+ DBUG_RETURN(1); // Error in where
}
send_ok(thd); // No matching records
DBUG_RETURN(0);
@@ -156,21 +248,20 @@ int mysql_update(THD *thd,
goto err;
}
}
- init_ftfuncs(thd, &thd->lex->select_lex, 1);
+ init_ftfuncs(thd, select_lex, 1);
/* Check if we are modifying a key that we are used to search with */
+
if (select && select->quick)
{
- used_index=select->quick->index;
+ used_index= select->quick->index;
used_key_is_modified= (!select->quick->unique_key_range() &&
- check_if_key_used(table, used_index, fields));
+ select->quick->check_if_keys_used(&fields));
}
else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
used_key_is_modified=check_if_key_used(table, used_index, fields);
else
- {
used_key_is_modified=0;
- used_index= MAX_KEY;
- }
+
if (used_key_is_modified || order)
{
/*
@@ -224,8 +315,12 @@ int mysql_update(THD *thd,
if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX,
DISK_BUFFER_SIZE, MYF(MY_WME)))
goto err;
-
+
+ /* If quick select is used, initialize it before retrieving rows. */
+ if (select && select->quick && select->quick->reset())
+ goto err;
init_read_record(&info,thd,table,select,0,1);
+
thd->proc_info="Searching rows for update";
uint tmp_limit= limit;
@@ -280,6 +375,9 @@ int mysql_update(THD *thd,
if (ignore)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+
+ if (select && select->quick && select->quick->reset())
+ goto err;
init_read_record(&info,thd,table,select,0,1);
updated= found= 0;
@@ -288,22 +386,47 @@ int mysql_update(THD *thd,
thd->proc_info="Updating";
query_id=thd->query_id;
+ transactional_table= table->file->has_transactions();
+ thd->no_trans_update= 0;
+ thd->abort_on_warning= test(!ignore &&
+ (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES)));
+
while (!(error=info.read_record(&info)) && !thd->killed)
{
if (!(select && select->skip_record()))
{
store_record(table,record[1]);
- if (fill_record(fields,values, 0) || thd->net.report_error)
+ if (fill_record(thd, fields, values, 0))
break; /* purecov: inspected */
+
found++;
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_BEFORE);
+
if (compare_record(table, query_id))
{
+ if ((res= table_list->view_check_option(thd, ignore)) !=
+ VIEW_CHECK_OK)
+ {
+ found--;
+ if (res == VIEW_CHECK_SKIP)
+ continue;
+ else if (res == VIEW_CHECK_ERROR)
+ {
+ error= 1;
+ break;
+ }
+ }
if (!(error=table->file->update_row((byte*) table->record[1],
(byte*) table->record[0])))
{
updated++;
+ thd->no_trans_update= !transactional_table;
}
- else if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
+ else if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
{
thd->fatal_error(); // Force error message
table->file->print_error(error,MYF(0));
@@ -311,6 +434,10 @@ int mysql_update(THD *thd,
break;
}
}
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER);
+
if (!--limit && using_limit)
{
error= -1; // Simulate end of file
@@ -334,23 +461,22 @@ int mysql_update(THD *thd,
This must be before binlog writing and ha_autocommit_...
*/
if (updated)
+ {
query_cache_invalidate3(thd, table_list, 1);
+ }
- transactional_table= table->file->has_transactions();
- log_delayed= (transactional_table || table->tmp_table);
if ((updated || (error < 0)) && (error <= 0 || !transactional_table))
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed, FALSE);
+ transactional_table, FALSE);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1; // Rollback update
}
- if (!log_delayed)
+ if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (transactional_table)
@@ -365,32 +491,33 @@ int mysql_update(THD *thd,
thd->lock=0;
}
- free_underlaid_joins(thd, &thd->lex->select_lex);
- if (error >= 0)
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
- else
+ free_underlaid_joins(thd, select_lex);
+ if (error < 0)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
(ulong) thd->cuted_fields);
- send_ok(thd,
- (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
+ thd->row_count_func=
+ (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
+ send_ok(thd, (ulong) thd->row_count_func,
thd->insert_id_used ? thd->insert_id() : 0L,buff);
DBUG_PRINT("info",("%d records updated",updated));
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
+ thd->abort_on_warning= 0;
free_io_cache(table);
- DBUG_RETURN(0);
+ DBUG_RETURN((error >= 0 || thd->net.report_error) ? 1 : 0);
err:
delete select;
- free_underlaid_joins(thd, &thd->lex->select_lex);
+ free_underlaid_joins(thd, select_lex);
if (table->key_read)
{
table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
- DBUG_RETURN(-1);
+ thd->abort_on_warning= 0;
+ DBUG_RETURN(1);
}
/*
@@ -399,51 +526,50 @@ err:
SYNOPSIS
mysql_prepare_update()
thd - thread handler
- table_list - global table list
- update_table_list - local table list of UPDATE SELECT_LEX
+ table_list - global/local table list
conds - conditions
order_num - number of ORDER BY list entries
order - ORDER BY clause list
RETURN VALUE
- 0 - OK
- 1 - error (message is sent to user)
- -1 - error (message is not sent to user)
+ FALSE OK
+ TRUE error
*/
-int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
- TABLE_LIST *update_table_list,
+bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
Item **conds, uint order_num, ORDER *order)
{
TABLE *table= table_list->table;
TABLE_LIST tables;
List<Item> all_fields;
+ SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_update");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
+ table_list->grant.want_privilege= table->grant.want_privilege=
+ (SELECT_ACL & ~table->grant.privilege);
#endif
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
tables.table= table;
tables.alias= table_list->alias;
- if (setup_tables(update_table_list) ||
- setup_conds(thd, update_table_list, conds) ||
- thd->lex->select_lex.setup_ref_array(thd, order_num) ||
- setup_order(thd, thd->lex->select_lex.ref_pointer_array,
- update_table_list, all_fields, all_fields, order) ||
- setup_ftfuncs(&thd->lex->select_lex))
- DBUG_RETURN(-1);
+ if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables,
+ FALSE, 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,
+ table_list, all_fields, all_fields, order) ||
+ setup_ftfuncs(select_lex))
+ DBUG_RETURN(TRUE);
/* Check that we are not using table that we are updating in a sub select */
- if (find_real_table_in_list(table_list->next,
- table_list->db, table_list->real_name))
+ if (unique_table(table_list, table_list->next_global))
{
- my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
- DBUG_RETURN(-1);
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
+ DBUG_RETURN(TRUE);
}
-
- DBUG_RETURN(0);
+ select_lex->fix_prepare_information(thd, conds);
+ DBUG_RETURN(FALSE);
}
@@ -469,247 +595,269 @@ static table_map get_table_map(List<Item> *items)
/*
- Prepare tables for multi-update
- Analyse which tables need specific privileges and perform locking
- as required
+ make update specific preparation and checks after opening tables
+
+ SYNOPSIS
+ mysql_multi_update_prepare()
+ thd thread handler
+
+ RETURN
+ FALSE OK
+ TRUE Error
*/
-int mysql_multi_update_lock(THD *thd,
- TABLE_LIST *table_list,
- List<Item> *fields,
- SELECT_LEX *select_lex)
+bool mysql_multi_update_prepare(THD *thd)
{
+ LEX *lex= thd->lex;
+ ulong opened_tables;
+ TABLE_LIST *table_list= lex->query_tables;
+ TABLE_LIST *tl, *leaves;
+ List<Item> *fields= &lex->select_lex.item_list;
+ table_map tables_for_update;
int res;
- TABLE_LIST *tl;
- TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first;
+ bool update_view= 0;
+ /*
+ if this multi-update was converted from usual update, here is table
+ counter else junk will be assigned here, but then replaced with real
+ count in open_tables()
+ */
+ uint table_count= lex->table_count;
const bool using_lock_tables= thd->locked_tables != 0;
- bool initialized_dervied= 0;
- DBUG_ENTER("mysql_multi_update_lock");
+ bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
+ DBUG_ENTER("mysql_multi_update_prepare");
+
+ /* following need for prepared statements, to run next time multi-update */
+ thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
+ /* open tables and create derived ones, but do not lock and fill them */
+ if ((original_multiupdate && open_tables(thd, &table_list, & table_count)) ||
+ mysql_handle_derived(lex, &mysql_derived_prepare))
+ DBUG_RETURN(TRUE);
/*
- The following loop is here to to ensure that we only lock tables
- that we are going to update with a write lock
+ setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
+ second time, but this call will do nothing (there are check for second
+ call in setup_tables()).
*/
- for (;;)
- {
- table_map update_tables, derived_tables=0;
- uint tnr, table_count;
- if ((res=open_tables(thd, table_list, &table_count)))
- DBUG_RETURN(res);
+ if (setup_tables(thd, table_list, &lex->select_lex.where,
+ &lex->select_lex.leaf_tables, FALSE, FALSE))
+ DBUG_RETURN(TRUE);
+ leaves= lex->select_lex.leaf_tables;
- /* Only need to call lock_tables if we are not using LOCK TABLES */
- if (!using_lock_tables &&
- ((res= lock_tables(thd, table_list, table_count))))
- DBUG_RETURN(res);
+ 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))
+ DBUG_RETURN(TRUE);
- if (!initialized_dervied)
+ for (tl= table_list; tl ; tl= tl->next_local)
+ {
+ if (tl->view)
{
- initialized_dervied= 1;
- relink_tables_for_derived(thd);
- if ((res= mysql_handle_derived(thd->lex)))
- DBUG_RETURN(res);
+ update_view= 1;
+ break;
}
+ }
- /*
- Ensure that we have update privilege for all tables and columns in the
- SET part
- While we are here, initialize the table->map field to check which
- tables are updated and updatability of derived tables
- */
- for (tl= update_list, tnr=0 ; tl ; tl=tl->next)
+ if (update_view && check_fields(thd, *fields))
+ {
+ DBUG_RETURN(TRUE);
+ }
+
+ tables_for_update= get_table_map(fields);
+
+ /*
+ Setup timestamp handling and locking mode
+ */
+ for (tl= leaves; tl; tl= tl->next_leaf)
+ {
+ TABLE *table= tl->table;
+ /* Only set timestamp column if this is not modified */
+ if (table->timestamp_field &&
+ table->timestamp_field->query_id == thd->query_id)
+ table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+
+ /* if table will be updated then check that it is unique */
+ if (table->map & tables_for_update)
{
- TABLE *table= tl->table;
+ if (!tl->updatable || check_key_in_view(thd, tl))
+ {
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE");
+ DBUG_RETURN(TRUE);
+ }
+
+ DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
/*
- Update of derived tables is checked later
- We don't check privileges here, becasue then we would get error
- "UPDATE command denided .. for column N" instead of
- "Target table ... is not updatable"
+ If table will be updated we should not downgrade lock for it and
+ leave it as is.
*/
- if (!tl->derived)
- table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege);
- table->map= (table_map) 1 << (tnr++);
}
-
- if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0))
- DBUG_RETURN(-1);
-
- update_tables= get_table_map(fields);
-
- /* Unlock the tables in preparation for relocking */
- if (!using_lock_tables)
+ else
{
- mysql_unlock_tables(thd, thd->lock);
- thd->lock= 0;
+ DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias));
+ /*
+ If we are using the binary log, we need TL_READ_NO_INSERT to get
+ correct order of statements. Otherwise, we use a TL_READ lock to
+ improve performance.
+ */
+ tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ;
+ tl->updating= 0;
+ /* Update TABLE::lock_type accordingly. */
+ if (!tl->placeholder() && !tl->schema_table && !using_lock_tables)
+ tl->table->reginfo.lock_type= tl->lock_type;
}
- /*
- Count tables and setup timestamp handling
- Set also the table locking strategy according to the update map
- */
- for (tl= update_list; tl; tl= tl->next)
+ /* Check access privileges for table */
+ if (!tl->derived && !tl->belong_to_view)
{
- TABLE_LIST *save= tl->next;
- TABLE *table= tl->table;
- uint wants;
- /* if table will be updated then check that it is unique */
- if (table->map & update_tables)
- {
- /*
- Multi-update can't be constructed over-union => we always have
- single SELECT on top and have to check underlaying SELECTs of it
- */
- if (select_lex->check_updateable_in_subqueries(tl->db,
- tl->real_name))
- {
- my_error(ER_UPDATE_TABLE_USED, MYF(0),
- tl->real_name);
- DBUG_RETURN(-1);
- }
- DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
- tl->lock_type= thd->lex->multi_lock_option;
- tl->updating= 1;
- wants= UPDATE_ACL;
- }
- else
- {
- DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias));
- // If we are using the binary log, we need TL_READ_NO_INSERT to get
- // correct order of statements. Otherwise, we use a TL_READ lock to
- // improve performance.
- tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ;
- tl->updating= 0;
- wants= SELECT_ACL;
- }
-
- if (tl->derived)
- derived_tables|= table->map;
- else
- {
- tl->next= 0;
- if (!using_lock_tables)
- tl->table->reginfo.lock_type= tl->lock_type;
- if (check_access(thd, wants, tl->db, &tl->grant.privilege, 0, 0) ||
- (grant_option && check_grant(thd, wants, tl, 0, 0, 0)))
- {
- tl->next= save;
- DBUG_RETURN(1);
- }
- tl->next= save;
- }
+ uint want_privilege= tl->updating ? UPDATE_ACL : SELECT_ACL;
+ if (check_access(thd, want_privilege,
+ tl->db, &tl->grant.privilege, 0, 0) ||
+ (grant_option && check_grant(thd, want_privilege, tl, 0, 1, 0)))
+ DBUG_RETURN(TRUE);
}
+ }
- if (thd->lex->derived_tables && (update_tables & derived_tables))
+ /* check single table update for view compound from several tables */
+ for (tl= table_list; tl; tl= tl->next_local)
+ {
+ if (tl->table == 0)
{
- // find derived table which cause error
- for (tl= update_list; tl; tl= tl->next)
+ DBUG_ASSERT(tl->view &&
+ tl->ancestor && tl->ancestor->next_local);
+ TABLE_LIST *for_update= 0;
+ if (tl->check_single_table(&for_update, tables_for_update))
{
- if (tl->derived && (update_tables & tl->table->map))
- {
- my_printf_error(ER_NON_UPDATABLE_TABLE, ER(ER_NON_UPDATABLE_TABLE),
- MYF(0), tl->alias, "UPDATE");
- DBUG_RETURN(-1);
- }
+ my_error(ER_VIEW_MULTIUPDATE, MYF(0),
+ tl->view_db.str, tl->view_name.str);
+ DBUG_RETURN(-1);
}
}
+ }
- /* Relock the tables with the correct modes */
- res= lock_tables(thd, table_list, table_count);
- if (using_lock_tables)
- break; // Don't have to do setup_field()
+ opened_tables= thd->status_var.opened_tables;
+ /* now lock and fill tables */
+ if (lock_tables(thd, table_list, table_count))
+ DBUG_RETURN(TRUE);
+ /*
+ we have to re-call fixfields for fixed items, because lock maybe
+ reopened tables
+ */
+ if (opened_tables != thd->status_var.opened_tables)
+ {
/*
- We must setup fields again as the file may have been reopened
- during lock_tables
+ Fields items cleanup(). There are only Item_fields in the list, so we
+ do not do Item tree walking
*/
- {
- List_iterator_fast<Item> field_it(*fields);
- Item_field *item;
+ List_iterator_fast<Item> it(*fields);
+ Item *item;
+ while ((item= it++))
+ item->cleanup();
+
+ /* We have to cleanup translation tables of views. */
+ for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global)
+ tbl->cleanup_items();
+
+ if (setup_tables(thd, table_list, &lex->select_lex.where,
+ &lex->select_lex.leaf_tables, FALSE, 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))
+ DBUG_RETURN(TRUE);
+ }
- while ((item= (Item_field *) field_it++))
- {
- item->field->query_id= 0;
- item->cleanup();
- }
+ /*
+ Check that we are not using table that we are updating, but we should
+ skip all tables of UPDATE SELECT itself
+ */
+ lex->select_lex.exclude_from_table_unique_test= TRUE;
+ /* We only need SELECT privilege for columns in the values list */
+ for (tl= leaves; tl; tl= tl->next_leaf)
+ {
+ TABLE *table= tl->table;
+ TABLE_LIST *tlist;
+ if (!(tlist= tl->belong_to_view ? tl->belong_to_view : tl)->derived)
+ {
+ tlist->grant.want_privilege=
+ (SELECT_ACL & ~tlist->grant.privilege);
+ table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
+ }
+ DBUG_PRINT("info", ("table: %s want_privilege: %u", tl->alias,
+ (uint) table->grant.want_privilege));
+ if (tl->lock_type != TL_READ &&
+ tl->lock_type != TL_READ_NO_INSERT &&
+ unique_table(tl, table_list))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
+ DBUG_RETURN(TRUE);
}
- if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0))
- DBUG_RETURN(-1);
- /*
- If lock succeded and the table map didn't change since the above lock
- we can continue.
- */
- if (!res && update_tables == get_table_map(fields))
- break;
-
- /*
- There was some very unexpected changes in the table definition between
- open tables and lock tables. Close tables and try again.
- */
- close_thread_tables(thd);
}
-
- DBUG_RETURN(res);
+
+ if (thd->fill_derived_tables() &&
+ mysql_handle_derived(lex, &mysql_derived_filling))
+ DBUG_RETURN(TRUE);
+
+ DBUG_RETURN (FALSE);
}
+
/*
Setup multi-update handling and call SELECT to do the join
*/
-int mysql_multi_update(THD *thd,
- TABLE_LIST *table_list,
- List<Item> *fields,
- List<Item> *values,
- COND *conds,
- ulong options,
- enum enum_duplicates handle_duplicates, bool ignore,
- SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
+bool mysql_multi_update(THD *thd,
+ TABLE_LIST *table_list,
+ List<Item> *fields,
+ List<Item> *values,
+ COND *conds,
+ ulong options,
+ enum enum_duplicates handle_duplicates, bool ignore,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
{
- int res;
- TABLE_LIST *tl;
- TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first;
- List<Item> total_list;
multi_update *result;
DBUG_ENTER("mysql_multi_update");
- if ((res= mysql_multi_update_lock(thd, table_list, fields, select_lex)))
- DBUG_RETURN(res);
+ if (mysql_multi_update_prepare(thd))
+ DBUG_RETURN(TRUE);
- /* Setup timestamp handling */
- for (tl= update_list; tl; tl= tl->next)
- {
- TABLE *table= tl->table;
- /* Only set timestamp column if this is not modified */
- if (table->timestamp_field &&
- table->timestamp_field->query_id == thd->query_id)
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+ if (!(result= new multi_update(thd, table_list,
+ thd->lex->select_lex.leaf_tables,
+ fields, values,
+ handle_duplicates, ignore)))
+ DBUG_RETURN(TRUE);
- /* We only need SELECT privilege for columns in the values list */
- table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
- }
+ thd->no_trans_update= 0;
+ thd->abort_on_warning= test(thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES));
- if (!(result=new multi_update(thd, update_list, fields, values,
- handle_duplicates, ignore)))
- DBUG_RETURN(-1);
-
- res= mysql_select(thd, &select_lex->ref_pointer_array,
- select_lex->get_table_list(), select_lex->with_wild,
- total_list,
- conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
- (ORDER *)NULL,
- options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
- result, unit, select_lex);
+ List<Item> total_list;
+ (void) mysql_select(thd, &select_lex->ref_pointer_array,
+ table_list, select_lex->with_wild,
+ total_list,
+ conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
+ (ORDER *)NULL,
+ options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
+ OPTION_SETUP_TABLES_DONE,
+ result, unit, select_lex);
delete result;
- DBUG_RETURN(res);
+ thd->abort_on_warning= 0;
+ DBUG_RETURN(FALSE);
}
multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
+ TABLE_LIST *leaves_list,
List<Item> *field_list, List<Item> *value_list,
- enum enum_duplicates handle_duplicates_arg, bool ignore_arg)
- :all_tables(table_list), update_tables(0), thd(thd_arg), tmp_tables(0),
- updated(0), found(0), fields(field_list), values(value_list),
- table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg),
- do_update(1), trans_safe(0), transactional_tables(1), ignore(ignore_arg)
+ enum enum_duplicates handle_duplicates_arg,
+ bool ignore_arg)
+ :all_tables(table_list), leaves(leaves_list), update_tables(0),
+ thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list),
+ values(value_list), table_count(0), copy_field(0),
+ handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0),
+ transactional_tables(1), ignore(ignore_arg)
{}
@@ -737,7 +885,7 @@ int multi_update::prepare(List<Item> &not_used_values,
if (!tables_to_update)
{
- my_error(ER_NO_TABLES_USED, MYF(0));
+ my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0));
DBUG_RETURN(1);
}
@@ -756,8 +904,9 @@ int multi_update::prepare(List<Item> &not_used_values,
*/
update.empty();
- for (table_ref= all_tables; table_ref; table_ref=table_ref->next)
+ for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
{
+ /* TODO: add support of view of join support */
TABLE *table=table_ref->table;
if (tables_to_update & table->map)
{
@@ -765,7 +914,7 @@ int multi_update::prepare(List<Item> &not_used_values,
sizeof(*tl));
if (!tl)
DBUG_RETURN(1);
- update.link_in_list((byte*) tl, (byte**) &tl->next);
+ update.link_in_list((byte*) tl, (byte**) &tl->next_local);
tl->shared= table_count++;
table->no_keyread=1;
table->used_keys.clear_all();
@@ -777,7 +926,7 @@ int multi_update::prepare(List<Item> &not_used_values,
table_count= update.elements;
update_tables= (TABLE_LIST*) update.first;
- tmp_tables = (TABLE **) thd->calloc(sizeof(TABLE *) * table_count);
+ tmp_tables = (TABLE**) thd->calloc(sizeof(TABLE *) * table_count);
tmp_table_param = (TMP_TABLE_PARAM*) thd->calloc(sizeof(TMP_TABLE_PARAM) *
table_count);
fields_for_table= (List_item **) thd->alloc(sizeof(List_item *) *
@@ -824,12 +973,12 @@ int multi_update::prepare(List<Item> &not_used_values,
which will cause an error when reading a row.
(This issue is mostly relevent for MyISAM tables)
*/
- for (table_ref= all_tables; table_ref; table_ref=table_ref->next)
+ for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
{
TABLE *table=table_ref->table;
- if (!(tables_to_update & table->map) &&
- find_real_table_in_list(update_tables, table_ref->db,
- table_ref->real_name))
+ if (!(tables_to_update & table->map) &&
+ find_table_in_local_list(update_tables, table_ref->db,
+ table_ref->table_name))
table->no_cache= 1; // Disable row cache
}
DBUG_RETURN(thd->is_fatal_error != 0);
@@ -855,11 +1004,10 @@ multi_update::initialize_tables(JOIN *join)
DBUG_RETURN(1);
main_table=join->join_tab->table;
trans_safe= transactional_tables= main_table->file->has_transactions();
- log_delayed= trans_safe || main_table->tmp_table != NO_TMP_TABLE;
table_to_update= 0;
/* Create a temporary table for keys to all tables, except main table */
- for (table_ref= update_tables; table_ref; table_ref=table_ref->next)
+ for (table_ref= update_tables; table_ref; table_ref= table_ref->next_local)
{
TABLE *table=table_ref->table;
uint cnt= table_ref->shared;
@@ -949,30 +1097,29 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
case JT_SYSTEM:
case JT_CONST:
case JT_EQ_REF:
- return 1; // At most one matching row
+ return TRUE; // At most one matching row
case JT_REF:
return !check_if_key_used(table, join_tab->ref.key, *fields);
case JT_ALL:
/* If range search on index */
if (join_tab->quick)
- return !check_if_key_used(table, join_tab->quick->index,
- *fields);
+ return !join_tab->quick->check_if_keys_used(fields);
/* If scanning in clustered key */
if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
- table->primary_key < MAX_KEY)
- return !check_if_key_used(table, table->primary_key, *fields);
- return 1;
+ table->s->primary_key < MAX_KEY)
+ return !check_if_key_used(table, table->s->primary_key, *fields);
+ return TRUE;
default:
break; // Avoid compler warning
}
- return 0;
+ return FALSE;
}
multi_update::~multi_update()
{
TABLE_LIST *table;
- for (table= update_tables ; table; table= table->next)
+ for (table= update_tables ; table; table= table->next_local)
table->table->no_keyread= table->table->no_cache= 0;
if (tmp_tables)
@@ -999,7 +1146,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
TABLE_LIST *cur_table;
DBUG_ENTER("multi_update::send_data");
- for (cur_table= update_tables; cur_table ; cur_table= cur_table->next)
+ for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
{
TABLE *table= cur_table->table;
/*
@@ -1023,12 +1170,23 @@ bool multi_update::send_data(List<Item> &not_used_values)
{
table->status|= STATUS_UPDATED;
store_record(table,record[1]);
- if (fill_record(*fields_for_table[offset], *values_for_table[offset], 0))
+ if (fill_record(thd, *fields_for_table[offset],
+ *values_for_table[offset], 0))
DBUG_RETURN(1);
+
found++;
if (compare_record(table, thd->query_id))
{
int error;
+ if ((error= cur_table->view_check_option(thd, ignore)) !=
+ VIEW_CHECK_OK)
+ {
+ found--;
+ if (error == VIEW_CHECK_SKIP)
+ continue;
+ else if (error == VIEW_CHECK_ERROR)
+ DBUG_RETURN(1);
+ }
if (!updated++)
{
/*
@@ -1042,20 +1200,22 @@ bool multi_update::send_data(List<Item> &not_used_values)
table->record[0])))
{
updated--;
- if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
+ if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
{
thd->fatal_error(); // Force error message
table->file->print_error(error,MYF(0));
DBUG_RETURN(1);
}
}
+ else if (!table->file->has_transactions())
+ thd->no_trans_update= 1;
}
}
else
{
int error;
TABLE *tmp_table= tmp_tables[offset];
- fill_record(tmp_table->field+1, *values_for_table[offset], 1);
+ fill_record(thd, tmp_table->field+1, *values_for_table[offset], 1);
found++;
/* Store pointer to row */
memcpy((char*) tmp_table->field[0]->ptr,
@@ -1081,7 +1241,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
void multi_update::send_error(uint errcode,const char *err)
{
/* First send error what ever it is ... */
- ::send_error(thd,errcode,err);
+ my_error(errcode, MYF(0), err);
/* If nothing updated return */
if (!updated)
@@ -1116,7 +1276,7 @@ int multi_update::do_updates(bool from_send_error)
do_update= 0; // Don't retry this function
if (!found)
DBUG_RETURN(0);
- for (cur_table= update_tables; cur_table ; cur_table= cur_table->next)
+ for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
{
byte *ref_pos;
@@ -1178,17 +1338,13 @@ int multi_update::do_updates(bool from_send_error)
goto err;
}
updated++;
- if (table->tmp_table != NO_TMP_TABLE)
- log_delayed= 1;
}
}
if (updated != org_updated)
{
- if (table->tmp_table != NO_TMP_TABLE)
- log_delayed= 1; // Tmp tables forces delay log
if (table->file->has_transactions())
- log_delayed= transactional_tables= 1;
+ transactional_tables= 1;
else
trans_safe= 0; // Can't do safe rollback
}
@@ -1209,10 +1365,8 @@ err:
if (updated != org_updated)
{
- if (table->tmp_table != NO_TMP_TABLE)
- log_delayed= 1;
if (table->file->has_transactions())
- log_delayed= transactional_tables= 1;
+ transactional_tables= 1;
else
trans_safe= 0;
}
@@ -1224,7 +1378,7 @@ err:
bool multi_update::send_eof()
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
thd->proc_info="updating reference tables";
/* Does updates for the last n - 1 tables, returns 0 if ok */
@@ -1249,17 +1403,16 @@ bool multi_update::send_eof()
if (updated && (local_error <= 0 || !trans_safe))
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
if (local_error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed, FALSE);
+ transactional_tables, FALSE);
if (mysql_bin_log.write(&qinfo) && trans_safe)
local_error= 1; // Rollback update
}
- if (!log_delayed)
+ if (!transactional_tables)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
@@ -1274,15 +1427,15 @@ bool multi_update::send_eof()
/* Safety: If we haven't got an error before (should not happen) */
my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update",
MYF(0));
- ::send_error(thd);
- return 1;
+ return TRUE;
}
sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
(ulong) thd->cuted_fields);
- ::send_ok(thd,
- (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
+ thd->row_count_func=
+ (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
+ ::send_ok(thd, (ulong) thd->row_count_func,
thd->insert_id_used ? thd->insert_id() : 0L,buff);
- return 0;
+ return FALSE;
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
new file mode 100644
index 00000000000..ce08763015f
--- /dev/null
+++ b/sql/sql_view.cc
@@ -0,0 +1,1136 @@
+/* Copyright (C) 2004 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 "sql_select.h"
+#include "parse_file.h"
+#include "sp.h"
+#include "sp_head.h"
+
+#define MD5_BUFF_LENGTH 33
+
+static int mysql_register_view(THD *thd, TABLE_LIST *view,
+ enum_view_create_mode mode);
+
+const char *updatable_views_with_limit_names[]= { "NO", "YES", NullS };
+TYPELIB updatable_views_with_limit_typelib=
+{
+ array_elements(updatable_views_with_limit_names)-1, "",
+ updatable_views_with_limit_names,
+ 0
+};
+
+
+/*
+ Creating/altering VIEW procedure
+
+ SYNOPSIS
+ mysql_create_view()
+ thd - thread handler
+ mode - VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Error
+*/
+
+bool mysql_create_view(THD *thd,
+ enum_view_create_mode mode)
+{
+ LEX *lex= thd->lex;
+ bool link_to_local;
+ /* first table in list is target VIEW name => cut off it */
+ TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
+ TABLE_LIST *tables= lex->query_tables;
+ TABLE_LIST *tbl;
+ SELECT_LEX *select_lex= &lex->select_lex;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ SELECT_LEX *sl;
+#endif
+ SELECT_LEX_UNIT *unit= &lex->unit;
+ bool res= FALSE;
+ DBUG_ENTER("mysql_create_view");
+
+ if (lex->proc_list.first ||
+ lex->result)
+ {
+ my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), (lex->result ?
+ "INTO" :
+ "PROCEDURE"));
+ res= TRUE;
+ goto err;
+ }
+ if (lex->derived_tables ||
+ lex->variables_used || lex->param_list.elements)
+ {
+ int err= (lex->derived_tables ?
+ ER_VIEW_SELECT_DERIVED :
+ ER_VIEW_SELECT_VARIABLE);
+ my_message(err, ER(err), MYF(0));
+ res= TRUE;
+ goto err;
+ }
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ Privilege check for view creation:
+ - user has CREATE VIEW privilege on view table
+ - user has DROP privilege in case of ALTER VIEW or CREATE OR REPLACE
+ VIEW
+ - user has some (SELECT/UPDATE/INSERT/DELETE) privileges on columns of
+ underlying tables used on top of SELECT list (because it can be
+ (theoretically) updated, so it is enough to have UPDATE privilege on
+ them, for example)
+ - user has SELECT privilege on columns used in expressions of VIEW select
+ - for columns of underly tables used on top of SELECT list also will be
+ checked that we have not more privileges on correspondent column of view
+ table (i.e. user will not get some privileges by view creation)
+ */
+ if ((check_access(thd, CREATE_VIEW_ACL, view->db, &view->grant.privilege,
+ 0, 0) ||
+ grant_option && check_grant(thd, CREATE_VIEW_ACL, view, 0, 1, 0)) ||
+ (mode != VIEW_CREATE_NEW &&
+ (check_access(thd, DROP_ACL, view->db, &view->grant.privilege,
+ 0, 0) ||
+ grant_option && check_grant(thd, DROP_ACL, view, 0, 1, 0))))
+ DBUG_RETURN(TRUE);
+ for (sl= select_lex; sl; sl= sl->next_select())
+ {
+ for (tbl= sl->get_table_list(); tbl; tbl= tbl->next_local)
+ {
+ /*
+ Ensure that we have some privileges on this table, more strict check
+ will be done on column level after preparation,
+ */
+ if (check_some_access(thd, VIEW_ANY_ACL, tbl))
+ {
+ my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
+ "ANY", thd->priv_user, thd->host_or_ip, tbl->table_name);
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Mark this table as a table which will be checked after the prepare
+ phase
+ */
+ tbl->table_in_first_from_clause= 1;
+
+ /*
+ We need to check only SELECT_ACL for all normal fields, fields for
+ which we need "any" (SELECT/UPDATE/INSERT/DELETE) privilege will be
+ checked later
+ */
+ tbl->grant.want_privilege= SELECT_ACL;
+ /*
+ Make sure that all rights are loaded to the TABLE::grant field.
+
+ tbl->table_name will be correct name of table because VIEWs are
+ not opened yet.
+ */
+ fill_effective_table_privileges(thd, &tbl->grant, tbl->db,
+ tbl->table_name);
+ }
+ }
+
+ if (&lex->select_lex != lex->all_selects_list)
+ {
+ /* check tables of subqueries */
+ for (tbl= tables; tbl; tbl= tbl->next_global)
+ {
+ if (!tbl->table_in_first_from_clause)
+ {
+ if (check_access(thd, SELECT_ACL, tbl->db,
+ &tbl->grant.privilege, 0, 0) ||
+ grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 0))
+ {
+ res= TRUE;
+ goto err;
+ }
+ }
+ }
+ }
+ /*
+ Mark fields for special privilege check ("any" privilege)
+ */
+ for (sl= select_lex; sl; sl= sl->next_select())
+ {
+ List_iterator_fast<Item> it(sl->item_list);
+ Item *item;
+ while ((item= it++))
+ {
+ Item_field *field;
+ if ((field= item->filed_for_view_update()))
+ field->any_privileges= 1;
+ }
+ }
+#endif
+
+ if (open_and_lock_tables(thd, tables))
+ DBUG_RETURN(TRUE);
+
+ /*
+ check that tables are not temporary and this VIEW do not used in query
+ (it is possible with ALTERing VIEW)
+ */
+ for (tbl= tables; tbl; tbl= tbl->next_global)
+ {
+ /* is this table temporary and is not view? */
+ if (tbl->table->s->tmp_table != NO_TMP_TABLE && !tbl->view &&
+ !tbl->schema_table)
+ {
+ my_error(ER_VIEW_SELECT_TMPTABLE, MYF(0), tbl->alias);
+ res= TRUE;
+ goto err;
+ }
+
+ /* is this table view and the same view which we creates now? */
+ if (tbl->view &&
+ strcmp(tbl->view_db.str, view->db) == 0 &&
+ strcmp(tbl->view_name.str, view->table_name) == 0)
+ {
+ my_error(ER_NO_SUCH_TABLE, MYF(0), tbl->view_db.str, tbl->view_name.str);
+ res= TRUE;
+ goto err;
+ }
+
+ /*
+ Copy the privileges of the underlying VIEWs which were filled by
+ fill_effective_table_privileges
+ (they were not copied at derived tables processing)
+ */
+ tbl->table->grant.privilege= tbl->grant.privilege;
+ }
+
+ /* prepare select to resolve all fields */
+ lex->view_prepare_mode= 1;
+ if (unit->prepare(thd, 0, 0, view->view_name.str))
+ {
+ /*
+ some errors from prepare are reported to user, if is not then
+ it will be checked after err: label
+ */
+ res= TRUE;
+ goto err;
+ }
+
+ /* view list (list of view fields names) */
+ if (lex->view_list.elements)
+ {
+ List_iterator_fast<Item> it(select_lex->item_list);
+ List_iterator_fast<LEX_STRING> nm(lex->view_list);
+ Item *item;
+ LEX_STRING *name;
+
+ if (lex->view_list.elements != select_lex->item_list.elements)
+ {
+ my_message(ER_VIEW_WRONG_LIST, ER(ER_VIEW_WRONG_LIST), MYF(0));
+ goto err;
+ }
+ while ((item= it++, name= nm++))
+ item->set_name(name->str, name->length, system_charset_info);
+ }
+
+ /* Test absence of duplicates names */
+ {
+ Item *item;
+ List_iterator_fast<Item> it(select_lex->item_list);
+ it++;
+ while ((item= it++))
+ {
+ Item *check;
+ List_iterator_fast<Item> itc(select_lex->item_list);
+ while ((check= itc++) && check != item)
+ {
+ if (strcmp(item->name, check->name) == 0)
+ {
+ my_error(ER_DUP_FIELDNAME, MYF(0), item->name);
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+ }
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ Compare/check grants on view with grants of underlying tables
+ */
+ for (sl= select_lex; sl; sl= sl->next_select())
+ {
+ char *db= view->db ? view->db : thd->db;
+ List_iterator_fast<Item> it(sl->item_list);
+ Item *item;
+ fill_effective_table_privileges(thd, &view->grant, db,
+ view->table_name);
+ while ((item= it++))
+ {
+ Item_field *fld;
+ uint priv= (get_column_grant(thd, &view->grant, db,
+ view->table_name, item->name) &
+ VIEW_ANY_ACL);
+ if ((fld= item->filed_for_view_update()))
+ {
+ /*
+ Do we have more privileges on view field then underlying table field?
+ */
+ if (!fld->field->table->s->tmp_table && (~fld->have_privileges & priv))
+ {
+ /* VIEW column has more privileges */
+ my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
+ "create view", thd->priv_user, thd->host_or_ip, item->name,
+ view->table_name);
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+ }
+#endif
+
+ if (wait_if_global_read_lock(thd, 0, 0))
+ {
+ res= TRUE;
+ goto err;
+ }
+ VOID(pthread_mutex_lock(&LOCK_open));
+ res= mysql_register_view(thd, view, mode);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ if (view->revision != 1)
+ query_cache_invalidate3(thd, view, 0);
+ start_waiting_global_read_lock(thd);
+ if (res)
+ goto err;
+
+ send_ok(thd);
+ lex->link_first_table_back(view, link_to_local);
+ DBUG_RETURN(0);
+
+err:
+ thd->proc_info= "end";
+ lex->link_first_table_back(view, link_to_local);
+ unit->cleanup();
+ DBUG_RETURN(res || thd->net.report_error);
+}
+
+
+/* index of revision number in following table */
+static const int revision_number_position= 5;
+/* index of last required parameter for making view */
+static const int required_view_parameters= 7;
+
+/*
+ table of VIEW .frm field descriptors
+
+ Note that one should NOT change the order for this, as it's used by
+ parse()
+*/
+static File_option view_parameters[]=
+{{{(char*) "query", 5}, offsetof(TABLE_LIST, query),
+ FILE_OPTIONS_STRING},
+ {{(char*) "md5", 3}, offsetof(TABLE_LIST, md5),
+ FILE_OPTIONS_STRING},
+ {{(char*) "updatable", 9}, offsetof(TABLE_LIST, updatable_view),
+ FILE_OPTIONS_ULONGLONG},
+ {{(char*) "algorithm", 9}, offsetof(TABLE_LIST, algorithm),
+ FILE_OPTIONS_ULONGLONG},
+ {{(char*) "with_check_option", 17}, offsetof(TABLE_LIST, with_check),
+ FILE_OPTIONS_ULONGLONG},
+ {{(char*) "revision", 8}, offsetof(TABLE_LIST, revision),
+ FILE_OPTIONS_REV},
+ {{(char*) "timestamp", 9}, offsetof(TABLE_LIST, timestamp),
+ FILE_OPTIONS_TIMESTAMP},
+ {{(char*)"create-version", 14},offsetof(TABLE_LIST, file_version),
+ FILE_OPTIONS_ULONGLONG},
+ {{(char*) "source", 6}, offsetof(TABLE_LIST, source),
+ FILE_OPTIONS_ESTRING},
+ {{NullS, 0}, 0,
+ FILE_OPTIONS_STRING}
+};
+
+static LEX_STRING view_file_type[]= {{(char*)"VIEW", 4}};
+
+
+/*
+ Register VIEW (write .frm & process .frm's history backups)
+
+ SYNOPSIS
+ mysql_register_view()
+ thd - thread handler
+ view - view description
+ mode - VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
+
+ RETURN
+ 0 OK
+ -1 Error
+ 1 Error and error message given
+*/
+
+static int mysql_register_view(THD *thd, TABLE_LIST *view,
+ enum_view_create_mode mode)
+{
+ LEX *lex= thd->lex;
+ char buff[4096];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ char md5[MD5_BUFF_LENGTH];
+ bool can_be_merged;
+ char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
+ LEX_STRING dir, file;
+ DBUG_ENTER("mysql_register_view");
+
+ /* print query */
+ str.length(0);
+ {
+ ulong sql_mode= thd->variables.sql_mode & MODE_ANSI_QUOTES;
+ thd->variables.sql_mode&= ~MODE_ANSI_QUOTES;
+ lex->unit.print(&str);
+ thd->variables.sql_mode|= sql_mode;
+ }
+ str.append('\0');
+ DBUG_PRINT("VIEW", ("View: %s", str.ptr()));
+
+ /* print file name */
+ (void) my_snprintf(dir_buff, FN_REFLEN, "%s/%s/",
+ mysql_data_home, view->db);
+ unpack_filename(dir_buff, dir_buff);
+ dir.str= dir_buff;
+ dir.length= strlen(dir_buff);
+
+ file.str= file_buff;
+ file.length= (strxnmov(file_buff, FN_REFLEN, view->table_name, reg_ext,
+ NullS) - file_buff);
+ /* init timestamp */
+ if (!view->timestamp.str)
+ view->timestamp.str= view->timestamp_buffer;
+
+ /* check old .frm */
+ {
+ char path_buff[FN_REFLEN];
+ LEX_STRING path;
+ File_parser *parser;
+
+ path.str= path_buff;
+ fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME);
+ path.length= strlen(path_buff);
+
+ if (!access(path.str, F_OK))
+ {
+ if (mode == VIEW_CREATE_NEW)
+ {
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), view->alias);
+ DBUG_RETURN(-1);
+ }
+
+ if (!(parser= sql_parse_prepare(&path, thd->mem_root, 0)))
+ DBUG_RETURN(1);
+
+ if (!parser->ok() ||
+ strncmp("VIEW", parser->type()->str, parser->type()->length))
+ {
+ my_error(ER_WRONG_OBJECT, MYF(0),
+ (view->db ? view->db : thd->db), view->table_name, "VIEW");
+ DBUG_RETURN(-1);
+ }
+
+ /*
+ read revision number
+
+ TODO: read dependence list, too, to process cascade/restrict
+ TODO: special cascade/restrict procedure for alter?
+ */
+ if (parser->parse((gptr)view, thd->mem_root,
+ view_parameters + revision_number_position, 1))
+ {
+ DBUG_RETURN(thd->net.report_error? -1 : 0);
+ }
+ }
+ else
+ {
+ if (mode == VIEW_ALTER)
+ {
+ my_error(ER_NO_SUCH_TABLE, MYF(0), view->db, view->alias);
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+ /* fill structure */
+ view->query.str= (char*)str.ptr();
+ view->query.length= str.length()-1; // we do not need last \0
+ view->source.str= thd->query;
+ view->source.length= thd->query_length;
+ view->file_version= 1;
+ view->calc_md5(md5);
+ view->md5.str= md5;
+ view->md5.length= 32;
+ can_be_merged= lex->can_be_merged();
+ if (lex->create_view_algorithm == VIEW_ALGORITHM_MERGE &&
+ !lex->can_be_merged())
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_VIEW_MERGE,
+ ER(ER_WARN_VIEW_MERGE));
+ lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
+ }
+ view->algorithm= lex->create_view_algorithm;
+ view->with_check= lex->create_view_check;
+ if ((view->updatable_view= (can_be_merged &&
+ view->algorithm != VIEW_ALGORITHM_TMPTABLE)))
+ {
+ /* TODO: change here when we will support UNIONs */
+ for (TABLE_LIST *tbl= (TABLE_LIST *)lex->select_lex.table_list.first;
+ tbl;
+ tbl= tbl->next_local)
+ {
+ if ((tbl->view && !tbl->updatable_view) || tbl->schema_table)
+ {
+ view->updatable_view= 0;
+ break;
+ }
+ for (TABLE_LIST *up= tbl; up; up= up->embedding)
+ {
+ if (up->outer_join)
+ {
+ view->updatable_view= 0;
+ goto loop_out;
+ }
+ }
+ }
+ }
+loop_out:
+ /*
+ Check that table of main select do not used in subqueries.
+
+ This test can catch only very simple cases of such non-updateable views,
+ all other will be detected before updating commands execution.
+ (it is more optimisation then real check)
+
+ NOTE: this skip cases of using table via VIEWs, joined VIEWs, VIEWs with
+ UNION
+ */
+ if (view->updatable_view &&
+ !lex->select_lex.next_select() &&
+ !((TABLE_LIST*)lex->select_lex.table_list.first)->next_local &&
+ find_table_in_global_list(lex->query_tables->next_global,
+ lex->query_tables->db,
+ lex->query_tables->table_name))
+ {
+ view->updatable_view= 0;
+ }
+
+ if (view->with_check != VIEW_CHECK_NONE &&
+ !view->updatable_view)
+ {
+ my_error(ER_VIEW_NONUPD_CHECK, MYF(0), view->db, view->table_name);
+ DBUG_RETURN(-1);
+ }
+
+ if (sql_create_definition_file(&dir, &file, view_file_type,
+ (gptr)view, view_parameters, 3))
+ {
+ DBUG_RETURN(thd->net.report_error? -1 : 1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ read VIEW .frm and create structures
+
+ SYNOPSIS
+ mysql_make_view()
+ parser - parser object;
+ table - TABLE_LIST structure for filling
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+my_bool
+mysql_make_view(File_parser *parser, TABLE_LIST *table)
+{
+ DBUG_ENTER("mysql_make_view");
+ DBUG_PRINT("info", ("table=%p (%s)", table, table->table_name));
+
+ if (table->view)
+ {
+ DBUG_PRINT("info",
+ ("VIEW %s.%s is already processed on previous PS/SP execution",
+ table->view_db.str, table->view_name.str));
+ DBUG_RETURN(0);
+ }
+
+ SELECT_LEX *end;
+ THD *thd= current_thd;
+ LEX *old_lex= thd->lex, *lex;
+ SELECT_LEX *view_select;
+ int res= 0;
+
+ /*
+ For now we assume that tables will not be changed during PS life (it
+ will be TRUE as far as we make new table cache).
+ */
+ Item_arena *arena= thd->current_arena, backup;
+ if (arena->is_conventional())
+ arena= 0;
+ else
+ thd->set_n_backup_item_arena(arena, &backup);
+
+ /* init timestamp */
+ if (!table->timestamp.str)
+ table->timestamp.str= table->timestamp_buffer;
+ /*
+ TODO: when VIEWs will be stored in cache, table mem_root should
+ be used here
+ */
+ if (parser->parse((gptr)table, thd->mem_root, view_parameters,
+ required_view_parameters))
+ goto err;
+
+ /*
+ Save VIEW parameters, which will be wiped out by derived table
+ processing
+ */
+ table->view_db.str= table->db;
+ table->view_db.length= table->db_length;
+ table->view_name.str= table->table_name;
+ table->view_name.length= table->table_name_length;
+
+ /*TODO: md5 test here and warning if it is differ */
+
+ /*
+ TODO: TABLE mem root should be used here when VIEW will be stored in
+ TABLE cache
+
+ now Lex placed in statement memory
+ */
+ table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
+ lex_start(thd, (uchar*)table->query.str, table->query.length);
+ view_select= &lex->select_lex;
+ view_select->select_number= ++thd->select_number;
+ {
+ ulong options= thd->options;
+ /* switch off modes which can prevent normal parsing of VIEW
+ - MODE_REAL_AS_FLOAT affect only CREATE TABLE parsing
+ + MODE_PIPES_AS_CONCAT affect expression parsing
+ + MODE_ANSI_QUOTES affect expression parsing
+ + MODE_IGNORE_SPACE affect expression parsing
+ - MODE_NOT_USED not used :)
+ * MODE_ONLY_FULL_GROUP_BY affect execution
+ * MODE_NO_UNSIGNED_SUBTRACTION affect execution
+ - MODE_NO_DIR_IN_CREATE affect table creation only
+ - MODE_POSTGRESQL compounded from other modes
+ - MODE_ORACLE compounded from other modes
+ - MODE_MSSQL compounded from other modes
+ - MODE_DB2 compounded from other modes
+ - MODE_MAXDB affect only CREATE TABLE parsing
+ - MODE_NO_KEY_OPTIONS affect only SHOW
+ - MODE_NO_TABLE_OPTIONS affect only SHOW
+ - MODE_NO_FIELD_OPTIONS affect only SHOW
+ - MODE_MYSQL323 affect only SHOW
+ - MODE_MYSQL40 affect only SHOW
+ - MODE_ANSI compounded from other modes
+ (+ transaction mode)
+ ? MODE_NO_AUTO_VALUE_ON_ZERO affect UPDATEs
+ + MODE_NO_BACKSLASH_ESCAPES affect expression parsing
+ */
+ thd->options&= ~(MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES);
+ CHARSET_INFO *save_cs= thd->variables.character_set_client;
+ thd->variables.character_set_client= system_charset_info;
+ res= yyparse((void *)thd);
+ thd->variables.character_set_client= save_cs;
+ thd->options= options;
+ }
+ if (!res && !thd->is_fatal_error)
+ {
+ TABLE_LIST *top_view= (table->belong_to_view ?
+ table->belong_to_view :
+ table);
+ TABLE_LIST *view_tables= lex->query_tables;
+ TABLE_LIST *view_tables_tail= 0;
+ TABLE_LIST *tbl;
+
+ /*
+ Check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show
+ underlying tables.
+ Skip this step if we are opening view for prelocking only.
+ */
+ if (!table->prelocking_placeholder &&
+ (old_lex->sql_command == SQLCOM_SELECT && old_lex->describe))
+ {
+ if (check_table_access(thd, SELECT_ACL, view_tables, 1) &&
+ check_table_access(thd, SHOW_VIEW_ACL, table, 1))
+ {
+ my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0));
+ goto err;
+ }
+ }
+ else if (!table->prelocking_placeholder &&
+ old_lex->sql_command == SQLCOM_SHOW_CREATE)
+ {
+ if (check_table_access(thd, SHOW_VIEW_ACL, table, 0))
+ goto err;
+ }
+
+ /*
+ mark to avoid temporary table using and put view reference and find
+ last view table
+ */
+ for (tbl= view_tables;
+ tbl;
+ tbl= (view_tables_tail= tbl)->next_global)
+ {
+ tbl->skip_temporary= 1;
+ tbl->belong_to_view= top_view;
+ }
+
+ /*
+ Put tables of VIEW after VIEW TABLE_LIST
+
+ NOTE: It is important for UPDATE/INSERT/DELETE checks to have this
+ tables just after VIEW instead of tail of list, to be able check that
+ table is unique. Also we store old next table for the same purpose.
+ */
+ if (view_tables)
+ {
+ if (table->next_global)
+ {
+ view_tables_tail->next_global= table->next_global;
+ table->next_global->prev_global= &view_tables_tail->next_global;
+ }
+ else
+ {
+ old_lex->query_tables_last= &view_tables_tail->next_global;
+ }
+ view_tables->prev_global= &table->next_global;
+ table->next_global= view_tables;
+ }
+
+ /*
+ If we are opening this view as part of implicit LOCK TABLES, then
+ this view serves as simple placeholder and we should not continue
+ further processing.
+ */
+ if (table->prelocking_placeholder)
+ goto ok2;
+
+ old_lex->derived_tables|= DERIVED_VIEW;
+
+ /* move SQL_NO_CACHE & Co to whole query */
+ old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
+ lex->safe_to_cache_query);
+ /* move SQL_CACHE to whole query */
+ if (view_select->options & OPTION_TO_QUERY_CACHE)
+ old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
+
+ /*
+ check MERGE algorithm ability
+ - algorithm is not explicit TEMPORARY TABLE
+ - VIEW SELECT allow merging
+ - VIEW used in subquery or command support MERGE algorithm
+ */
+ if (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
+ lex->can_be_merged() &&
+ (table->select_lex->master_unit() != &old_lex->unit ||
+ old_lex->can_use_merged()) &&
+ !old_lex->can_not_use_merged())
+ {
+ /* 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;
+
+ /*
+ Process upper level tables of view. As far as we do noy suport union
+ here we can go through local tables of view most upper SELECT
+ */
+ for(tbl= view_tables;
+ tbl;
+ tbl= tbl->next_local)
+ {
+ /* next table should include SELECT_LEX under this table SELECT_LEX */
+ tbl->select_lex= table->select_lex;
+
+ /*
+ move lock type (TODO: should we issue error in case of TMPTABLE
+ algorithm and non-read locking)?
+ */
+ tbl->lock_type= table->lock_type;
+ }
+
+ /* multi table view */
+ if (view_tables->next_local)
+ {
+ /* make nested join structure for view tables */
+ NESTED_JOIN *nested_join;
+ if (!(nested_join= table->nested_join=
+ (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
+ goto err;
+ nested_join->join_list= view_select->top_join_list;
+
+ /* re-nest tables of VIEW */
+ {
+ List_iterator_fast<TABLE_LIST> ti(nested_join->join_list);
+ while ((tbl= ti++))
+ {
+ tbl->join_list= &nested_join->join_list;
+ tbl->embedding= table;
+ }
+ }
+ }
+
+ /* Store WHERE clause for post-processing in setup_ancestor */
+ 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
+ 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;
+ SELECT_LEX_UNIT *next_unit;
+ for (SELECT_LEX_UNIT *unit= lex->select_lex.first_inner_unit();
+ unit;
+ unit= next_unit)
+ {
+ if (unit == end_unit)
+ break;
+ SELECT_LEX_NODE *save_slave= unit->slave;
+ next_unit= unit->next_unit();
+ unit->include_down(table->select_lex);
+ unit->slave= save_slave; // fix include_down initialisation
+ }
+
+ /*
+ This SELECT_LEX will be linked in global SELECT_LEX list
+ to make it processed by mysql_handle_derived(),
+ but it will not be included to SELECT_LEX tree, because it
+ will not be executed
+ */
+ goto ok;
+ }
+
+ table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE;
+ DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE"));
+ view_select->linkage= DERIVED_TABLE_TYPE;
+ table->updatable= 0;
+ table->effective_with_check= VIEW_CHECK_NONE;
+ old_lex->subqueries= TRUE;
+
+ /* SELECT tree link */
+ lex->unit.include_down(table->select_lex);
+ lex->unit.slave= view_select; // fix include_down initialisation
+
+ table->derived= &lex->unit;
+ }
+ else
+ goto err;
+
+ok:
+ /* global SELECT list linking */
+ end= view_select; // primary SELECT_LEX is always last
+ end->link_next= old_lex->all_selects_list;
+ old_lex->all_selects_list->link_prev= &end->link_next;
+ old_lex->all_selects_list= lex->all_selects_list;
+ lex->all_selects_list->link_prev=
+ (st_select_lex_node**)&old_lex->all_selects_list;
+
+ok2:
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ thd->lex= old_lex;
+ DBUG_RETURN(0);
+
+err:
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ delete table->view;
+ table->view= 0; // now it is not VIEW placeholder
+ thd->lex= old_lex;
+ DBUG_RETURN(1);
+}
+
+
+/*
+ drop view
+
+ SYNOPSIS
+ mysql_drop_view()
+ thd - thread handler
+ views - views to delete
+ drop_mode - cascade/check
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Error
+*/
+
+bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
+{
+ DBUG_ENTER("mysql_drop_view");
+ char path[FN_REFLEN];
+ TABLE_LIST *view;
+ bool type= 0;
+
+ for (view= views; view; view= view->next_local)
+ {
+ strxnmov(path, FN_REFLEN, mysql_data_home, "/", view->db, "/",
+ view->table_name, reg_ext, NullS);
+ (void) unpack_filename(path, path);
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (access(path, F_OK) || (type= (mysql_frm_type(path) != FRMTYPE_VIEW)))
+ {
+ char name[FN_REFLEN];
+ my_snprintf(name, sizeof(name), "%s.%s", view->db, view->table_name);
+ if (thd->lex->drop_if_exists)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
+ name);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ continue;
+ }
+ if (type)
+ my_error(ER_WRONG_OBJECT, MYF(0), view->db, view->table_name, "VIEW");
+ else
+ my_error(ER_BAD_TABLE_ERROR, MYF(0), name);
+ goto err;
+ }
+ if (my_delete(path, MYF(MY_WME)))
+ goto err;
+ query_cache_invalidate3(thd, view, 0);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
+ send_ok(thd);
+ DBUG_RETURN(FALSE);
+
+err:
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(TRUE);
+
+}
+
+
+/*
+ Check type of .frm if we are not going to parse it
+
+ SYNOPSIS
+ mysql_frm_type()
+ path path to file
+
+ RETURN
+ FRMTYPE_ERROR error
+ FRMTYPE_TABLE table
+ FRMTYPE_VIEW view
+*/
+
+frm_type_enum mysql_frm_type(char *path)
+{
+ File file;
+ char header[10]; //"TYPE=VIEW\n" it is 10 characters
+ int length;
+ DBUG_ENTER("mysql_frm_type");
+
+ if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
+ {
+ DBUG_RETURN(FRMTYPE_ERROR);
+ }
+ length= my_read(file, (byte*) header, sizeof(header), MYF(MY_WME));
+ my_close(file, MYF(MY_WME));
+ if (length == (int) MY_FILE_ERROR)
+ DBUG_RETURN(FRMTYPE_ERROR);
+ if (length < (int) sizeof(header) ||
+ !strncmp(header, "TYPE=VIEW\n", sizeof(header)))
+ DBUG_RETURN(FRMTYPE_VIEW);
+ DBUG_RETURN(FRMTYPE_TABLE); // Is probably a .frm table
+}
+
+
+/*
+ check of key (primary or unique) presence in updatable view
+
+ SYNOPSIS
+ check_key_in_view()
+ thd thread handler
+ view view for check with opened table
+
+ DESCRIPTION
+ If it is VIEW and query have LIMIT clause then check that undertlying
+ table of viey contain one of following:
+ 1) primary key of underlying table
+ 2) unique key underlying table with fields for which NULL value is
+ impossible
+ 3) all fields of underlying table
+
+ RETURN
+ FALSE OK
+ TRUE view do not contain key or all fields
+*/
+
+bool check_key_in_view(THD *thd, TABLE_LIST *view)
+{
+ TABLE *table;
+ Field_translator *trans;
+ KEY *key_info, *key_info_end;
+ uint i, elements_in_view;
+ DBUG_ENTER("check_key_in_view");
+
+ /*
+ we do not support updatable UNIONs in VIEW, so we can check just limit of
+ LEX::select_lex
+ */
+ if ((!view->view && !view->belong_to_view) || thd->lex->sql_command == SQLCOM_INSERT ||
+ thd->lex->select_lex.select_limit == HA_POS_ERROR)
+ DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */
+ table= view->table;
+ if (view->belong_to_view)
+ view= view->belong_to_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;
+ DBUG_ASSERT(table != 0 && view->field_translation != 0);
+
+ /* Loop over all keys to see if a unique-not-null key is used */
+ for (;key_info != key_info_end ; key_info++)
+ {
+ if ((key_info->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
+ {
+ KEY_PART_INFO *key_part= key_info->key_part;
+ KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
+
+ /* check that all key parts are used */
+ for (;;)
+ {
+ uint k;
+ for (k= 0; k < elements_in_view; k++)
+ {
+ Item_field *field;
+ if ((field= trans[k].item->filed_for_view_update()) &&
+ field->field == key_part->field)
+ break;
+ }
+ if (k == elements_in_view)
+ break; // Key is not possible
+ if (++key_part == key_part_end)
+ DBUG_RETURN(FALSE); // Found usable key
+ }
+ }
+ }
+
+ DBUG_PRINT("info", ("checking if all fields of table are used"));
+ /* check all fields presence */
+ {
+ Field **field_ptr;
+ for (field_ptr= table->field; *field_ptr; field_ptr++)
+ {
+ for (i= 0; i < elements_in_view; i++)
+ {
+ Item_field *field;
+ if ((field= trans[i].item->filed_for_view_update()) &&
+ field->field == *field_ptr)
+ break;
+ }
+ if (i == elements_in_view) // If field didn't exists
+ {
+ /*
+ Keys or all fields of underlying tables are not foud => we have
+ to check variable updatable_views_with_limit to decide should we
+ issue an error or just a warning
+ */
+ if (thd->variables.updatable_views_with_limit)
+ {
+ /* update allowed, but issue warning */
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_WARN_VIEW_WITHOUT_KEY, ER(ER_WARN_VIEW_WITHOUT_KEY));
+ DBUG_RETURN(FALSE);
+ }
+ /* prohibit update */
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ insert fields from VIEW (MERGE algorithm) into given list
+
+ SYNOPSIS
+ insert_view_fields()
+ list list for insertion
+ view view for processing
+
+ RETURN
+ FALSE OK
+ TRUE error (is not sent to cliet)
+*/
+
+bool insert_view_fields(List<Item> *list, TABLE_LIST *view)
+{
+ uint elements_in_view= view->view->select_lex.item_list.elements;
+ Field_translator *trans;
+ DBUG_ENTER("insert_view_fields");
+
+ if (!(trans= view->field_translation))
+ DBUG_RETURN(FALSE);
+
+ for (uint i= 0; i < elements_in_view; i++)
+ {
+ Item_field *fld;
+ if ((fld= trans[i].item->filed_for_view_update()))
+ list->push_back(fld);
+ else
+ {
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "INSERT");
+ DBUG_RETURN(TRUE);
+ }
+ }
+ DBUG_RETURN(FALSE);
+}
+
+/*
+ checking view md5 check suum
+
+ SINOPSYS
+ view_checksum()
+ thd threar handler
+ view view for check
+
+ RETUIRN
+ HA_ADMIN_OK OK
+ HA_ADMIN_NOT_IMPLEMENTED it is not VIEW
+ HA_ADMIN_WRONG_CHECKSUM check sum is wrong
+*/
+
+int view_checksum(THD *thd, TABLE_LIST *view)
+{
+ char md5[MD5_BUFF_LENGTH];
+ if (!view->view || view->md5.length != 32)
+ return HA_ADMIN_NOT_IMPLEMENTED;
+ view->calc_md5(md5);
+ return (strncmp(md5, view->md5.str, 32) ?
+ HA_ADMIN_WRONG_CHECKSUM :
+ HA_ADMIN_OK);
+}
diff --git a/sql/sql_view.h b/sql/sql_view.h
new file mode 100644
index 00000000000..4e6aaf7f477
--- /dev/null
+++ b/sql/sql_view.h
@@ -0,0 +1,37 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2004 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
+*/
+
+bool mysql_create_view(THD *thd,
+ enum_view_create_mode mode);
+
+my_bool mysql_make_view(File_parser *parser, TABLE_LIST *table);
+
+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);
+
+frm_type_enum mysql_frm_type(char *path);
+
+int view_checksum(THD *thd, TABLE_LIST *view);
+
+extern TYPELIB updatable_views_with_limit_typelib;
+
+#define VIEW_ANY_ACL (SELECT_ACL | UPDATE_ACL | INSERT_ACL | DELETE_ACL)
+
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 594077dd4f3..80bf409f7a4 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -34,22 +34,38 @@
#include "slave.h"
#include "lex_symbol.h"
#include "item_create.h"
+#include "sp_head.h"
+#include "sp_pcontext.h"
+#include "sp_rcontext.h"
+#include "sp.h"
#include <myisam.h>
#include <myisammrg.h>
int yylex(void *yylval, void *yythd);
+const LEX_STRING null_lex_str={0,0};
+
#define yyoverflow(A,B,C,D,E,F) {ulong val= *(F); if(my_yyoverflow((B), (D), &val)) { yyerror((char*) (A)); return 2; } else { *(F)= (YYSIZE_T)val; }}
-#define WARN_DEPRECATED(A,B) \
+#define WARN_DEPRECATED(A,B) \
push_warning_printf(((THD *)yythd), MYSQL_ERROR::WARN_LEVEL_WARN, \
- ER_WARN_DEPRECATED_SYNTAX, \
- ER(ER_WARN_DEPRECATED_SYNTAX), (A), (B));
-
-inline Item *or_or_concat(THD *thd, Item* A, Item* B)
+ ER_WARN_DEPRECATED_SYNTAX, \
+ ER(ER_WARN_DEPRECATED_SYNTAX), (A), (B));
+
+#define TEST_ASSERT(A) \
+ if (!(A)) \
+ { \
+ yyerror(ER(ER_SYNTAX_ERROR)); \
+ YYABORT; \
+ }
+
+/* Helper for parsing "IS [NOT] truth_value" */
+inline Item *is_truth_value(Item *A, bool v1, bool v2)
{
- return (thd->variables.sql_mode & MODE_PIPES_AS_CONCAT ?
- (Item*) new Item_func_concat(A,B) : (Item*) new Item_cond_or(A,B));
+ return new Item_func_if(create_func_ifnull(A,
+ new Item_int((char *) (v2 ? "TRUE" : "FALSE"), v2, 1)),
+ new Item_int((char *) (v1 ? "TRUE" : "FALSE"), v1, 1),
+ new Item_int((char *) (v1 ? "FALSE" : "TRUE"),!v1, 1));
}
%}
@@ -82,10 +98,14 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B)
enum Item_udftype udf_type;
CHARSET_INFO *charset;
thr_lock_type lock_type;
- interval_type interval;
+ interval_type interval, interval_time_st;
timestamp_type date_time_type;
st_select_lex *select_lex;
chooser_compare_func_creator boolfunc2creator;
+ struct sp_cond_type *spcondtype;
+ struct { int vars, conds, hndlrs, curs; } spblock;
+ sp_name *spname;
+ struct st_lex *lex;
}
%{
@@ -94,494 +114,551 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%pure_parser /* We have threads */
-%token END_OF_INPUT
-
-%token CLOSE_SYM
-%token HANDLER_SYM
-%token LAST_SYM
-%token NEXT_SYM
-%token PREV_SYM
-
-%token DIV_SYM
-%token EQ
-%token EQUAL_SYM
-%token SOUNDS_SYM
-%token GE
-%token GT_SYM
-%token LE
-%token LT
-%token NE
-%token IS
-%token MOD_SYM
-%token SHIFT_LEFT
-%token SHIFT_RIGHT
-%token SET_VAR
-
-%token ABORT_SYM
-%token ADD
-%token AFTER_SYM
-%token ALTER
-%token ANALYZE_SYM
-%token ANY_SYM
-%token AVG_SYM
-%token BEGIN_SYM
-%token BINLOG_SYM
-%token CHANGE
-%token CLIENT_SYM
-%token COMMENT_SYM
-%token COMMIT_SYM
+%token END_OF_INPUT
+
+%token ABORT_SYM
+%token ACTION
+%token ADD
+%token ADDDATE_SYM
+%token AFTER_SYM
+%token AGAINST
+%token AGGREGATE_SYM
+%token ALGORITHM_SYM
+%token ALL
+%token ALTER
+%token ANALYZE_SYM
+%token AND_AND_SYM
+%token AND_SYM
+%token ANY_SYM
+%token AS
+%token ASC
+%token ASCII_SYM
+%token ASENSITIVE_SYM
+%token ATAN
+%token AUTO_INC
+%token AVG_ROW_LENGTH
+%token AVG_SYM
+%token BACKUP_SYM
+%token BEFORE_SYM
+%token BEGIN_SYM
+%token BENCHMARK_SYM
+%token BERKELEY_DB_SYM
+%token BIGINT
+%token BINARY
+%token BINLOG_SYM
+%token BIN_NUM
+%token BIT_AND
+%token BIT_OR
+%token BIT_SYM
+%token BIT_XOR
+%token BLOB_SYM
+%token BOOLEAN_SYM
+%token BOOL_SYM
+%token BOTH
+%token BTREE_SYM
+%token BY
+%token BYTE_SYM
+%token CACHE_SYM
+%token CALL_SYM
+%token CASCADE
+%token CASCADED
+%token CAST_SYM
+%token CHAIN_SYM
+%token CHANGE
+%token CHANGED
+%token CHARSET
+%token CHAR_SYM
+%token CHECKSUM_SYM
+%token CHECK_SYM
+%token CIPHER_SYM
+%token CLIENT_SYM
+%token CLOSE_SYM
+%token COALESCE
+%token COLLATE_SYM
+%token COLLATION_SYM
+%token COLUMNS
+%token COLUMN_SYM
+%token COMMENT_SYM
+%token COMMITTED_SYM
+%token COMMIT_SYM
+%token COMPACT_SYM
+%token COMPRESSED_SYM
+%token CONCAT
+%token CONCAT_WS
+%token CONCURRENT
+%token CONDITION_SYM
+%token CONNECTION_SYM
%token CONSISTENT_SYM
-%token COUNT_SYM
-%token CREATE
-%token CROSS
+%token CONSTRAINT
+%token CONTAINS_SYM
+%token CONTINUE_SYM
+%token CONVERT_SYM
+%token CONVERT_TZ_SYM
+%token COUNT_SYM
+%token CREATE
+%token CROSS
%token CUBE_SYM
-%token DELETE_SYM
-%token DUAL_SYM
-%token DO_SYM
-%token DROP
-%token EVENTS_SYM
-%token EXECUTE_SYM
-%token EXPANSION_SYM
-%token FLUSH_SYM
-%token HELP_SYM
-%token INSERT
-%token RELAY_THREAD
-%token KILL_SYM
-%token LOAD
-%token LOCKS_SYM
-%token LOCK_SYM
-%token MASTER_SYM
-%token MAX_SYM
-%token MIN_SYM
-%token NONE_SYM
-%token OPTIMIZE
-%token PURGE
-%token REPAIR
-%token REPLICATION
-%token RESET_SYM
-%token ROLLBACK_SYM
-%token ROLLUP_SYM
-%token SAVEPOINT_SYM
-%token SELECT_SYM
-%token SHOW
-%token SLAVE
-%token SNAPSHOT_SYM
-%token SQL_THREAD
-%token START_SYM
-%token STD_SYM
-%token VARIANCE_SYM
-%token STOP_SYM
-%token SUM_SYM
-%token ADDDATE_SYM
-%token SUPER_SYM
-%token TRUNCATE_SYM
-%token UNLOCK_SYM
-%token UNTIL_SYM
-%token UPDATE_SYM
-
-%token ACTION
-%token AGGREGATE_SYM
-%token ALL
-%token AND_SYM
-%token AS
-%token ASC
-%token AUTO_INC
-%token AVG_ROW_LENGTH
-%token BACKUP_SYM
-%token BERKELEY_DB_SYM
-%token BINARY
-%token BIT_SYM
-%token BOOL_SYM
-%token BOOLEAN_SYM
-%token BOTH
-%token BTREE_SYM
-%token BY
-%token BYTE_SYM
-%token CACHE_SYM
-%token CASCADE
-%token CAST_SYM
-%token CHARSET
-%token CHECKSUM_SYM
-%token CHECK_SYM
-%token COMMITTED_SYM
-%token COLLATE_SYM
-%token COLLATION_SYM
-%token COLUMNS
-%token COLUMN_SYM
-%token CONCURRENT
-%token CONSTRAINT
-%token CONVERT_SYM
+%token CURDATE
%token CURRENT_USER
-%token DATABASES
-%token DATA_SYM
-%token DEFAULT
-%token DELAYED_SYM
-%token DELAY_KEY_WRITE_SYM
-%token DESC
-%token DESCRIBE
-%token DES_KEY_FILE
-%token DISABLE_SYM
-%token DISCARD
-%token DISTINCT
+%token CURSOR_SYM
+%token CURTIME
+%token DATABASE
+%token DATABASES
+%token DATA_SYM
+%token DATETIME
+%token DATE_ADD_INTERVAL
+%token DATE_SUB_INTERVAL
+%token DATE_SYM
+%token DAY_HOUR_SYM
+%token DAY_MICROSECOND_SYM
+%token DAY_MINUTE_SYM
+%token DAY_SECOND_SYM
+%token DAY_SYM
+%token DEALLOCATE_SYM
+%token DECIMAL_NUM
+%token DECIMAL_SYM
+%token DECLARE_SYM
+%token DECODE_SYM
+%token DEFAULT
+%token DEFINER_SYM
+%token DELAYED_SYM
+%token DELAY_KEY_WRITE_SYM
+%token DELETE_SYM
+%token DESC
+%token DESCRIBE
+%token DES_DECRYPT_SYM
+%token DES_ENCRYPT_SYM
+%token DES_KEY_FILE
+%token DETERMINISTIC_SYM
+%token DIRECTORY_SYM
+%token DISABLE_SYM
+%token DISCARD
+%token DISTINCT
+%token DIV_SYM
+%token DOUBLE_SYM
+%token DO_SYM
+%token DROP
+%token DUAL_SYM
+%token DUMPFILE
%token DUPLICATE_SYM
-%token DYNAMIC_SYM
-%token ENABLE_SYM
-%token ENCLOSED
-%token ESCAPED
-%token DIRECTORY_SYM
-%token ESCAPE_SYM
-%token EXISTS
-%token EXTENDED_SYM
-%token FALSE_SYM
-%token FILE_SYM
-%token FIRST_SYM
-%token FIXED_SYM
-%token FLOAT_NUM
-%token FORCE_SYM
-%token FOREIGN
-%token FROM
-%token FULL
-%token FULLTEXT_SYM
-%token GLOBAL_SYM
-%token GRANT
-%token GRANTS
-%token GREATEST_SYM
-%token GROUP
-%token HAVING
-%token HASH_SYM
-%token HEX_NUM
-%token HIGH_PRIORITY
-%token HOSTS_SYM
-%token IDENT
-%token IDENT_QUOTED
-%token IGNORE_SYM
-%token IMPORT
-%token INDEX_SYM
-%token INDEXES
-%token INFILE
-%token INNER_SYM
-%token INNOBASE_SYM
-%token INTO
-%token IN_SYM
-%token ISOLATION
-%token JOIN_SYM
-%token KEYS
-%token KEY_SYM
-%token LEADING
-%token LEAST_SYM
-%token LEAVES
-%token LEVEL_SYM
-%token LEX_HOSTNAME
-%token LIKE
-%token LINES
-%token LOCAL_SYM
-%token LOG_SYM
-%token LOGS_SYM
-%token LONG_NUM
-%token LONG_SYM
-%token LOW_PRIORITY
-%token MASTER_HOST_SYM
-%token MASTER_USER_SYM
-%token MASTER_LOG_FILE_SYM
-%token MASTER_LOG_POS_SYM
-%token MASTER_PASSWORD_SYM
-%token MASTER_PORT_SYM
-%token MASTER_CONNECT_RETRY_SYM
-%token MASTER_SERVER_ID_SYM
-%token MASTER_SSL_SYM
-%token MASTER_SSL_CA_SYM
-%token MASTER_SSL_CAPATH_SYM
-%token MASTER_SSL_CERT_SYM
-%token MASTER_SSL_CIPHER_SYM
-%token MASTER_SSL_KEY_SYM
-%token RELAY_LOG_FILE_SYM
-%token RELAY_LOG_POS_SYM
-%token MATCH
-%token MAX_ROWS
-%token MAX_CONNECTIONS_PER_HOUR
-%token MAX_QUERIES_PER_HOUR
-%token MAX_UPDATES_PER_HOUR
-%token MEDIUM_SYM
-%token MIN_ROWS
-%token NAMES_SYM
-%token NATIONAL_SYM
-%token NATURAL
-%token NDBCLUSTER_SYM
-%token NEW_SYM
-%token NCHAR_SYM
-%token NCHAR_STRING
-%token NVARCHAR_SYM
-%token NOT
-%token NO_SYM
-%token NULL_SYM
-%token NUM
-%token OFFSET_SYM
-%token ON
-%token ONE_SHOT_SYM
-%token OPEN_SYM
-%token OPTION
-%token OPTIONALLY
-%token OR_SYM
-%token OR_OR_CONCAT
-%token ORDER_SYM
-%token OUTER
-%token OUTFILE
-%token DUMPFILE
-%token PACK_KEYS_SYM
-%token PARTIAL
-%token PRIMARY_SYM
-%token PRIVILEGES
-%token PROCESS
-%token PROCESSLIST_SYM
-%token QUERY_SYM
-%token RAID_0_SYM
-%token RAID_STRIPED_SYM
-%token RAID_TYPE
-%token RAID_CHUNKS
-%token RAID_CHUNKSIZE
-%token READ_SYM
-%token REAL_NUM
-%token REFERENCES
-%token REGEXP
-%token RELOAD
-%token RENAME
-%token REPEATABLE_SYM
-%token REQUIRE_SYM
-%token RESOURCES
-%token RESTORE_SYM
-%token RESTRICT
-%token REVOKE
-%token ROWS_SYM
-%token ROW_FORMAT_SYM
-%token ROW_SYM
-%token RTREE_SYM
-%token SET
-%token SEPARATOR_SYM
-%token SERIAL_SYM
-%token SERIALIZABLE_SYM
-%token SESSION_SYM
-%token SIMPLE_SYM
-%token SHUTDOWN
-%token SPATIAL_SYM
-%token SSL_SYM
-%token STARTING
-%token STATUS_SYM
-%token STORAGE_SYM
-%token STRAIGHT_JOIN
-%token SUBJECT_SYM
-%token TABLES
-%token TABLE_SYM
-%token TABLESPACE
-%token TEMPORARY
-%token TERMINATED
-%token TEXT_STRING
-%token TO_SYM
-%token TRAILING
-%token TRANSACTION_SYM
-%token TRUE_SYM
-%token TYPE_SYM
-%token TYPES_SYM
-%token FUNC_ARG0
-%token FUNC_ARG1
-%token FUNC_ARG2
-%token FUNC_ARG3
-%token UDF_RETURNS_SYM
-%token UDF_SONAME_SYM
-%token UDF_SYM
-%token UNCOMMITTED_SYM
-%token UNDERSCORE_CHARSET
-%token UNICODE_SYM
-%token UNION_SYM
-%token UNIQUE_SYM
-%token USAGE
-%token USE_FRM
-%token USE_SYM
-%token USING
-%token VALUE_SYM
-%token VALUES
-%token VARIABLES
-%token WHERE
-%token WITH
-%token WRITE_SYM
-%token NO_WRITE_TO_BINLOG
-%token X509_SYM
-%token XOR
-%token COMPRESSED_SYM
-
+%token DYNAMIC_SYM
+%token EACH_SYM
+%token ELSEIF_SYM
+%token ELT_FUNC
+%token ENABLE_SYM
+%token ENCLOSED
+%token ENCODE_SYM
+%token ENCRYPT
+%token END
+%token ENGINES_SYM
+%token ENGINE_SYM
+%token ENUM
+%token EQ
+%token EQUAL_SYM
%token ERRORS
-%token WARNINGS
-
-%token ASCII_SYM
-%token BIGINT
-%token BLOB_SYM
-%token CHAR_SYM
-%token CHANGED
-%token COALESCE
-%token DATETIME
-%token DATE_SYM
-%token DECIMAL_SYM
-%token DOUBLE_SYM
-%token ENUM
-%token FAST_SYM
-%token FLOAT_SYM
-%token GEOMETRY_SYM
-%token INT_SYM
-%token LIMIT
-%token LONGBLOB
-%token LONGTEXT
-%token MEDIUMBLOB
-%token MEDIUMINT
-%token MEDIUMTEXT
-%token NUMERIC_SYM
-%token PRECISION
-%token PREPARE_SYM
-%token DEALLOCATE_SYM
-%token QUICK
-%token REAL
-%token SIGNED_SYM
-%token SMALLINT
-%token STRING_SYM
-%token TEXT_SYM
-%token TIMESTAMP
-%token TIME_SYM
-%token TINYBLOB
-%token TINYINT
-%token TINYTEXT
-%token ULONGLONG_NUM
-%token UNSIGNED
-%token VARBINARY
-%token VARCHAR
-%token VARYING
-%token ZEROFILL
-
-%token ADDDATE_SYM
-%token AGAINST
-%token ATAN
-%token BETWEEN_SYM
-%token BIT_AND
-%token BIT_OR
-%token BIT_XOR
-%token CASE_SYM
-%token CONCAT
-%token CONCAT_WS
-%token CONVERT_TZ_SYM
-%token CURDATE
-%token CURTIME
-%token DATABASE
-%token DATE_ADD_INTERVAL
-%token DATE_SUB_INTERVAL
-%token DAY_HOUR_SYM
-%token DAY_MICROSECOND_SYM
-%token DAY_MINUTE_SYM
-%token DAY_SECOND_SYM
-%token DAY_SYM
-%token DECODE_SYM
-%token DES_ENCRYPT_SYM
-%token DES_DECRYPT_SYM
-%token ELSE
-%token ELT_FUNC
-%token ENCODE_SYM
-%token ENGINE_SYM
-%token ENGINES_SYM
-%token ENCRYPT
-%token EXPORT_SET
-%token EXTRACT_SYM
-%token FIELD_FUNC
-%token FORMAT_SYM
-%token FOR_SYM
-%token FROM_UNIXTIME
-%token GEOMCOLLFROMTEXT
-%token GEOMFROMTEXT
-%token GEOMFROMWKB
+%token ESCAPED
+%token ESCAPE_SYM
+%token EVENTS_SYM
+%token EXECUTE_SYM
+%token EXISTS
+%token EXIT_SYM
+%token EXPANSION_SYM
+%token EXPORT_SET
+%token EXTENDED_SYM
+%token EXTRACT_SYM
+%token FALSE_SYM
+%token FAST_SYM
+%token FETCH_SYM
+%token FIELD_FUNC
+%token FILE_SYM
+%token FIRST_SYM
+%token FIXED_SYM
+%token FLOAT_NUM
+%token FLOAT_SYM
+%token FLUSH_SYM
+%token FORCE_SYM
+%token FOREIGN
+%token FORMAT_SYM
+%token FOR_SYM
+%token FOUND_SYM
+%token FRAC_SECOND_SYM
+%token FROM
+%token FROM_UNIXTIME
+%token FULL
+%token FULLTEXT_SYM
+%token FUNCTION_SYM
+%token FUNC_ARG0
+%token FUNC_ARG1
+%token FUNC_ARG2
+%token FUNC_ARG3
+%token GE
+%token GEOMCOLLFROMTEXT
%token GEOMETRYCOLLECTION
-%token GROUP_CONCAT_SYM
-%token GROUP_UNIQUE_USERS
+%token GEOMETRY_SYM
+%token GEOMFROMTEXT
+%token GEOMFROMWKB
%token GET_FORMAT
-%token HOUR_MICROSECOND_SYM
-%token HOUR_MINUTE_SYM
-%token HOUR_SECOND_SYM
-%token HOUR_SYM
-%token IDENTIFIED_SYM
-%token IF
-%token INSERT_METHOD
-%token INTERVAL_SYM
-%token LAST_INSERT_ID
-%token LEFT
-%token LINEFROMTEXT
+%token GLOBAL_SYM
+%token GOTO_SYM
+%token GRANT
+%token GRANTS
+%token GREATEST_SYM
+%token GROUP
+%token GROUP_CONCAT_SYM
+%token GROUP_UNIQUE_USERS
+%token GT_SYM
+%token HANDLER_SYM
+%token HASH_SYM
+%token HAVING
+%token HELP_SYM
+%token HEX_NUM
+%token HIGH_PRIORITY
+%token HOSTS_SYM
+%token HOUR_MICROSECOND_SYM
+%token HOUR_MINUTE_SYM
+%token HOUR_SECOND_SYM
+%token HOUR_SYM
+%token IDENT
+%token IDENTIFIED_SYM
+%token IDENT_QUOTED
+%token IF
+%token IGNORE_SYM
+%token IMPORT
+%token INDEXES
+%token INDEX_SYM
+%token INFILE
+%token INNER_SYM
+%token INNOBASE_SYM
+%token INOUT_SYM
+%token INSENSITIVE_SYM
+%token INSERT
+%token INSERT_METHOD
+%token INTERVAL_SYM
+%token INTO
+%token INT_SYM
+%token INVOKER_SYM
+%token IN_SYM
+%token IS
+%token ISOLATION
+%token ISSUER_SYM
+%token ITERATE_SYM
+%token JOIN_SYM
+%token KEYS
+%token KEY_SYM
+%token KILL_SYM
+%token LABEL_SYM
+%token LANGUAGE_SYM
+%token LAST_INSERT_ID
+%token LAST_SYM
+%token LE
+%token LEADING
+%token LEAST_SYM
+%token LEAVES
+%token LEAVE_SYM
+%token LEFT
+%token LEVEL_SYM
+%token LEX_HOSTNAME
+%token LIKE
+%token LIMIT
+%token LINEFROMTEXT
+%token LINES
%token LINESTRING
-%token LOCATE
-%token MAKE_SET_SYM
-%token MASTER_POS_WAIT
+%token LOAD
+%token LOCAL_SYM
+%token LOCATE
+%token LOCATOR_SYM
+%token LOCKS_SYM
+%token LOCK_SYM
+%token LOGS_SYM
+%token LOG_SYM
+%token LONGBLOB
+%token LONGTEXT
+%token LONG_NUM
+%token LONG_SYM
+%token LOOP_SYM
+%token LOW_PRIORITY
+%token LT
+%token MAKE_SET_SYM
+%token MASTER_CONNECT_RETRY_SYM
+%token MASTER_HOST_SYM
+%token MASTER_LOG_FILE_SYM
+%token MASTER_LOG_POS_SYM
+%token MASTER_PASSWORD_SYM
+%token MASTER_PORT_SYM
+%token MASTER_POS_WAIT
+%token MASTER_SERVER_ID_SYM
+%token MASTER_SSL_CAPATH_SYM
+%token MASTER_SSL_CA_SYM
+%token MASTER_SSL_CERT_SYM
+%token MASTER_SSL_CIPHER_SYM
+%token MASTER_SSL_KEY_SYM
+%token MASTER_SSL_SYM
+%token MASTER_SYM
+%token MASTER_USER_SYM
+%token MATCH
+%token MAX_CONNECTIONS_PER_HOUR
+%token MAX_QUERIES_PER_HOUR
+%token MAX_ROWS
+%token MAX_SYM
+%token MAX_UPDATES_PER_HOUR
+%token MAX_USER_CONNECTIONS_SYM
+%token MEDIUMBLOB
+%token MEDIUMINT
+%token MEDIUMTEXT
+%token MEDIUM_SYM
+%token MERGE_SYM
%token MICROSECOND_SYM
-%token MINUTE_MICROSECOND_SYM
-%token MINUTE_SECOND_SYM
-%token MINUTE_SYM
-%token MODE_SYM
-%token MODIFY_SYM
-%token MONTH_SYM
-%token MLINEFROMTEXT
-%token MPOINTFROMTEXT
-%token MPOLYFROMTEXT
+%token MIGRATE_SYM
+%token MINUTE_MICROSECOND_SYM
+%token MINUTE_SECOND_SYM
+%token MINUTE_SYM
+%token MIN_ROWS
+%token MIN_SYM
+%token MLINEFROMTEXT
+%token MODE_SYM
+%token MODIFIES_SYM
+%token MODIFY_SYM
+%token MOD_SYM
+%token MONTH_SYM
+%token MPOINTFROMTEXT
+%token MPOLYFROMTEXT
%token MULTILINESTRING
%token MULTIPOINT
%token MULTIPOLYGON
-%token NOW_SYM
-%token OLD_PASSWORD
-%token PASSWORD
-%token POINTFROMTEXT
-%token POINT_SYM
-%token POLYFROMTEXT
+%token MUTEX_SYM
+%token NAMES_SYM
+%token NAME_SYM
+%token NATIONAL_SYM
+%token NATURAL
+%token NCHAR_STRING
+%token NCHAR_SYM
+%token NDBCLUSTER_SYM
+%token NE
+%token NEW_SYM
+%token NEXT_SYM
+%token NONE_SYM
+%token NOT2_SYM
+%token NOT_SYM
+%token NOW_SYM
+%token NO_SYM
+%token NO_WRITE_TO_BINLOG
+%token NULL_SYM
+%token NUM
+%token NUMERIC_SYM
+%token NVARCHAR_SYM
+%token OFFSET_SYM
+%token OLD_PASSWORD
+%token ON
+%token ONE_SHOT_SYM
+%token ONE_SYM
+%token OPEN_SYM
+%token OPTIMIZE
+%token OPTION
+%token OPTIONALLY
+%token OR2_SYM
+%token ORDER_SYM
+%token OR_OR_SYM
+%token OR_SYM
+%token OUTER
+%token OUTFILE
+%token OUT_SYM
+%token PACK_KEYS_SYM
+%token PARTIAL
+%token PASSWORD
+%token PHASE_SYM
+%token POINTFROMTEXT
+%token POINT_SYM
+%token POLYFROMTEXT
%token POLYGON
-%token POSITION_SYM
-%token PROCEDURE
-%token RAND
-%token REPLACE
-%token RIGHT
-%token ROUND
-%token SECOND_SYM
-%token SECOND_MICROSECOND_SYM
-%token SHARE_SYM
-%token SUBDATE_SYM
-%token SUBSTRING
-%token SUBSTRING_INDEX
-%token TRIM
-%token UDA_CHAR_SUM
-%token UDA_FLOAT_SUM
-%token UDA_INT_SUM
-%token UDF_CHAR_FUNC
-%token UDF_FLOAT_FUNC
-%token UDF_INT_FUNC
-%token UNIQUE_USERS
-%token UNIX_TIMESTAMP
-%token USER
-%token UTC_DATE_SYM
-%token UTC_TIME_SYM
-%token UTC_TIMESTAMP_SYM
-%token WEEK_SYM
-%token WHEN_SYM
-%token WORK_SYM
-%token YEAR_MONTH_SYM
-%token YEAR_SYM
-%token YEARWEEK
-%token BENCHMARK_SYM
-%token END
-%token THEN_SYM
-
-%token SQL_BIG_RESULT
-%token SQL_CACHE_SYM
-%token SQL_CALC_FOUND_ROWS
-%token SQL_NO_CACHE_SYM
-%token SQL_SMALL_RESULT
+%token POSITION_SYM
+%token PRECISION
+%token PREPARE_SYM
+%token PREV_SYM
+%token PRIMARY_SYM
+%token PRIVILEGES
+%token PROCEDURE
+%token PROCESS
+%token PROCESSLIST_SYM
+%token PURGE
+%token QUARTER_SYM
+%token QUERY_SYM
+%token QUICK
+%token RAID_0_SYM
+%token RAID_CHUNKS
+%token RAID_CHUNKSIZE
+%token RAID_STRIPED_SYM
+%token RAID_TYPE
+%token RAND
+%token READS_SYM
+%token READ_SYM
+%token REAL
+%token RECOVER_SYM
+%token REDUNDANT_SYM
+%token REFERENCES
+%token REGEXP
+%token RELAY_LOG_FILE_SYM
+%token RELAY_LOG_POS_SYM
+%token RELAY_THREAD
+%token RELEASE_SYM
+%token RELOAD
+%token RENAME
+%token REPAIR
+%token REPEATABLE_SYM
+%token REPEAT_SYM
+%token REPLACE
+%token REPLICATION
+%token REQUIRE_SYM
+%token RESET_SYM
+%token RESOURCES
+%token RESTORE_SYM
+%token RESTRICT
+%token RESUME_SYM
+%token RETURNS_SYM
+%token RETURN_SYM
+%token REVOKE
+%token RIGHT
+%token ROLLBACK_SYM
+%token ROLLUP_SYM
+%token ROUND
+%token ROUTINE_SYM
+%token ROWS_SYM
+%token ROW_COUNT_SYM
+%token ROW_FORMAT_SYM
+%token ROW_SYM
+%token RTREE_SYM
+%token SAVEPOINT_SYM
+%token SECOND_MICROSECOND_SYM
+%token SECOND_SYM
+%token SECURITY_SYM
+%token SELECT_SYM
+%token SENSITIVE_SYM
+%token SEPARATOR_SYM
+%token SERIALIZABLE_SYM
+%token SERIAL_SYM
+%token SESSION_SYM
+%token SET
+%token SET_VAR
+%token SHARE_SYM
+%token SHIFT_LEFT
+%token SHIFT_RIGHT
+%token SHOW
+%token SHUTDOWN
+%token SIGNED_SYM
+%token SIMPLE_SYM
+%token SLAVE
+%token SMALLINT
+%token SNAPSHOT_SYM
+%token SOUNDS_SYM
+%token SPATIAL_SYM
+%token SPECIFIC_SYM
+%token SQLEXCEPTION_SYM
+%token SQLSTATE_SYM
+%token SQLWARNING_SYM
+%token SQL_BIG_RESULT
%token SQL_BUFFER_RESULT
-
-%token ISSUER_SYM
+%token SQL_CACHE_SYM
+%token SQL_CALC_FOUND_ROWS
+%token SQL_NO_CACHE_SYM
+%token SQL_SMALL_RESULT
+%token SQL_SYM
+%token SQL_THREAD
+%token SSL_SYM
+%token STARTING
+%token START_SYM
+%token STATUS_SYM
+%token STD_SYM
+%token STDDEV_SAMP_SYM
+%token STOP_SYM
+%token STORAGE_SYM
+%token STRAIGHT_JOIN
+%token STRING_SYM
+%token SUBDATE_SYM
%token SUBJECT_SYM
-%token CIPHER_SYM
+%token SUBSTRING
+%token SUBSTRING_INDEX
+%token SUM_SYM
+%token SUPER_SYM
+%token SUSPEND_SYM
+%token TABLES
+%token TABLESPACE
+%token TABLE_SYM
+%token TEMPORARY
+%token TEMPTABLE_SYM
+%token TERMINATED
+%token TEXT_STRING
+%token TEXT_SYM
+%token TIMESTAMP
+%token TIMESTAMP_ADD
+%token TIMESTAMP_DIFF
+%token TIME_SYM
+%token TINYBLOB
+%token TINYINT
+%token TINYTEXT
+%token TO_SYM
+%token TRAILING
+%token TRANSACTION_SYM
+%token TRIGGER_SYM
+%token TRIM
+%token TRUE_SYM
+%token TRUNCATE_SYM
+%token TYPES_SYM
+%token TYPE_SYM
+%token UDF_RETURNS_SYM
+%token UDF_SONAME_SYM
+%token ULONGLONG_NUM
+%token UNCOMMITTED_SYM
+%token UNDEFINED_SYM
+%token UNDERSCORE_CHARSET
+%token UNDO_SYM
+%token UNICODE_SYM
+%token UNION_SYM
+%token UNIQUE_SYM
+%token UNIQUE_USERS
+%token UNIX_TIMESTAMP
+%token UNKNOWN_SYM
+%token UNLOCK_SYM
+%token UNLOCK_SYM
+%token UNSIGNED
+%token UNTIL_SYM
+%token UNTIL_SYM
+%token UPDATE_SYM
+%token UPDATE_SYM
+%token USAGE
+%token USER
+%token USE_FRM
+%token USE_SYM
+%token USING
+%token UTC_DATE_SYM
+%token UTC_TIMESTAMP_SYM
+%token UTC_TIME_SYM
+%token VAR_SAMP_SYM
+%token VALUES
+%token VALUE_SYM
+%token VARBINARY
+%token VARCHAR
+%token VARIABLES
+%token VARIANCE_SYM
+%token VARYING
+%token VIEW_SYM
+%token WARNINGS
+%token WEEK_SYM
+%token WHEN_SYM
+%token WHERE
+%token WHILE_SYM
+%token WITH
+%token WORK_SYM
+%token WRITE_SYM
+%token X509_SYM
+%token XA_SYM
+%token XOR
+%token YEARWEEK
+%token YEAR_MONTH_SYM
+%token YEAR_SYM
+%token ZEROFILL
-%token BEFORE_SYM
%left SET_VAR
-%left OR_OR_CONCAT OR_SYM XOR
-%left AND_SYM
+%left OR_OR_SYM OR_SYM OR2_SYM XOR
+%left AND_SYM AND_AND_SYM
%left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE
%left EQ EQUAL_SYM GE GT_SYM LE LT NE IS LIKE REGEXP IN_SYM
%left '|'
@@ -591,20 +668,21 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%left '*' '/' '%' DIV_SYM MOD_SYM
%left '^'
%left NEG '~'
-%right NOT
+%right NOT_SYM NOT2_SYM
%right BINARY COLLATE_SYM
%type <lex_str>
- IDENT IDENT_QUOTED TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM
+ IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM
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
%type <lex_str_ptr>
opt_table_alias
%type <table>
- table_ident table_ident_nodb references
+ table_ident table_ident_nodb references xid
%type <simple_string>
remember_name remember_end opt_ident opt_db text_or_password
@@ -614,15 +692,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
text_string opt_gconcat_separator
%type <num>
- type int_type real_type order_dir opt_field_spec lock_option
+ type int_type real_type order_dir lock_option
udf_type if_exists opt_local opt_table_options table_options
table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type
opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct
opt_ignore_leaves fulltext_options spatial_type union_option
- start_transaction_opts
+ start_transaction_opts opt_chain opt_release
+ union_opt select_derived_init
%type <ulong_num>
- ULONG_NUM raid_types merge_insert_types
+ ulong_num raid_types merge_insert_types
%type <ulonglong_number>
ulonglong_num
@@ -633,17 +712,23 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <item>
literal text_literal insert_ident order_ident
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
- table_wild no_in_expr expr_expr simple_expr no_and_expr
+ bool_term bool_factor bool_test bool_pri
+ predicate bit_expr bit_term bit_factor value_expr term factor
+ table_wild simple_expr udf_expr
using_list expr_or_default set_expr_or_default interval_expr
param_marker singlerow_subselect singlerow_subselect_init
exists_subselect exists_subselect_init geometry_function
signed_literal now_or_signed_literal opt_escape
+ sp_opt_default
+ simple_ident_nospvar simple_ident_q
+ field_or_var
%type <item_num>
NUM_literal
%type <item_list>
- expr_list udf_expr_list when_list ident_list ident_list_arg
+ expr_list udf_expr_list udf_expr_list2 when_list
+ ident_list ident_list_arg
%type <key_type>
key_type opt_unique_or_fulltext constraint_key_type
@@ -659,14 +744,14 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <table_list>
join_table_list join_table
-
-%type <udf>
- UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC
- UDA_CHAR_SUM UDA_FLOAT_SUM UDA_INT_SUM
+ table_factor table_ref
+ select_derived derived_table_list
%type <date_time_type> date_time_type;
%type <interval> interval
+%type <interval_time_st> interval_time_st
+
%type <db_type> storage_engines
%type <row_type> row_types
@@ -695,6 +780,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <variable> internal_variable_name
%type <select_lex> in_subselect in_subselect_init
+ get_select_lex
%type <boolfunc2creator> comp_op
@@ -702,7 +788,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename
show describe load alter optimize keycache preload flush
- reset purge begin commit rollback savepoint
+ reset purge begin commit rollback savepoint release
slave master_def master_defs master_file_def slave_until_opts
repair restore backup analyze check start checksum
field_list field_list_item field_spec kill column_def key_def
@@ -710,7 +796,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
select_item_list select_item values_list no_braces
opt_limit_clause delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item
- when_list2 expr_list2 handler
+ when_list2 expr_list2 udf_expr_list3 handler
opt_precision opt_ignore opt_column opt_restrict
grant revoke set lock unlock string_list field_options field_option
field_opt_list opt_binary table_lock_list table_lock
@@ -718,9 +804,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_delete_options opt_delete_option varchar nchar nvarchar
opt_outer table_list table_name opt_option opt_place
opt_attribute opt_attribute_list attribute column_list column_list_id
- opt_column_list grant_privileges opt_table user_list grant_option
- grant_privilege grant_privilege_list
- flush_options flush_option
+ opt_column_list grant_privileges opt_table grant_list grant_option
+ object_privilege object_privilege_list user_list rename_list
+ clear_privileges flush_options flush_option
equal optional_braces opt_key_definition key_usage_list2
opt_mi_check_type opt_to mi_check_types normal_join
table_to_table_list table_to_table opt_table_list opt_as
@@ -731,12 +817,22 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
subselect_end select_var_list select_var_list_init help opt_len
opt_extended_describe
prepare prepare_src execute deallocate
+ statement sp_suid opt_view_list view_list or_replace algorithm
+ sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
+ load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
END_OF_INPUT
+%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
+%type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list
+%type <spcondtype> sp_cond sp_hcond
+%type <spblock> sp_decls sp_decl
+%type <lex> sp_cursor_stmt
+%type <spname> sp_name
+
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
- ',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_CONCAT BETWEEN_SYM CASE_SYM
- THEN_SYM WHEN_SYM DIV_SYM MOD_SYM
+ ',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_SYM BETWEEN_SYM CASE_SYM
+ THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM
%%
@@ -747,7 +843,7 @@ query:
if (!thd->bootstrap &&
(!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
{
- send_error(thd,ER_EMPTY_QUERY);
+ my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0));
YYABORT;
}
else
@@ -758,10 +854,16 @@ query:
| verb_clause END_OF_INPUT {};
verb_clause:
+ statement
+ | begin
+ ;
+
+/* Verb clauses, except begin */
+statement:
alter
| analyze
| backup
- | begin
+ | call
| change
| check
| checksum
@@ -786,6 +888,7 @@ verb_clause:
| preload
| prepare
| purge
+ | release
| rename
| repair
| replace
@@ -803,6 +906,7 @@ verb_clause:
| unlock
| update
| use
+ | xa
;
deallocate:
@@ -934,16 +1038,16 @@ master_def:
Lex->mi.password = $3.str;
}
|
- MASTER_PORT_SYM EQ ULONG_NUM
+ MASTER_PORT_SYM EQ ulong_num
{
Lex->mi.port = $3;
}
|
- MASTER_CONNECT_RETRY_SYM EQ ULONG_NUM
+ MASTER_CONNECT_RETRY_SYM EQ ulong_num
{
Lex->mi.connect_retry = $3;
}
- | MASTER_SSL_SYM EQ ULONG_NUM
+ | MASTER_SSL_SYM EQ ulong_num
{
Lex->mi.ssl= $3 ?
LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE;
@@ -997,7 +1101,7 @@ master_file_def:
{
Lex->mi.relay_log_name = $3.str;
}
- | RELAY_LOG_POS_SYM EQ ULONG_NUM
+ | RELAY_LOG_POS_SYM EQ ulong_num
{
Lex->mi.relay_log_pos = $3;
/* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */
@@ -1062,19 +1166,1345 @@ create:
lex->name=$4.str;
lex->create_info.options=$3;
}
- | CREATE udf_func_type UDF_SYM IDENT_sys
+ | CREATE udf_func_type FUNCTION_SYM sp_name
{
LEX *lex=Lex;
- lex->sql_command = SQLCOM_CREATE_FUNCTION;
- lex->udf.name = $4;
+ lex->spname= $4;
lex->udf.type= $2;
}
- UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys
+ create_function_tail
+ {}
+ | CREATE PROCEDURE sp_name
+ {
+ LEX *lex= Lex;
+ sp_head *sp;
+
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE");
+ YYABORT;
+ }
+ /* Order is important here: new - reset - init */
+ sp= new sp_head();
+ sp->reset_thd_mem_root(YYTHD);
+ sp->init(lex);
+
+ sp->m_type= TYPE_ENUM_PROCEDURE;
+ lex->sphead= sp;
+ /*
+ * We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ * stored procedure, otherwise yylex will chop it into pieces
+ * at each ';'.
+ */
+ sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
+ YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
+ }
+ '('
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->m_param_begin= lex->tok_start+1;
+ }
+ sp_pdparam_list
+ ')'
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->m_param_end= lex->tok_start;
+ bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
+ }
+ sp_c_chistics
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->m_chistics= &lex->sp_chistics;
+ lex->sphead->m_body_begin= lex->tok_start;
+ }
+ sp_proc_stmt
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+
+ if (sp->check_backpatch(YYTHD))
+ YYABORT;
+ sp->init_strings(YYTHD, lex, $3);
+ lex->sql_command= SQLCOM_CREATE_PROCEDURE;
+ /* Restore flag if it was cleared above */
+ if (sp->m_old_cmq)
+ YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
+ sp->restore_thd_mem_root(YYTHD);
+ }
+ | CREATE or_replace algorithm VIEW_SYM table_ident
+ {
+ 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;
+ }
+ opt_view_list AS select_init check_option
+ {}
+ | CREATE TRIGGER_SYM ident trg_action_time trg_event
+ ON table_ident FOR_SYM EACH_SYM ROW_SYM
+ {
+ LEX *lex= Lex;
+ sp_head *sp;
+
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER");
+ YYABORT;
+ }
+
+ if (!(sp= new sp_head()))
+ YYABORT;
+ sp->reset_thd_mem_root(YYTHD);
+ sp->init(lex);
+
+ sp->m_type= TYPE_ENUM_TRIGGER;
+ lex->sphead= sp;
+ /*
+ We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ stored procedure, otherwise yylex will chop it into pieces
+ at each ';'.
+ */
+ sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
+ YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
+
+ bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
+ lex->sphead->m_chistics= &lex->sp_chistics;
+ lex->sphead->m_body_begin= lex->tok_start;
+ }
+ sp_proc_stmt
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+
+ lex->sql_command= SQLCOM_CREATE_TRIGGER;
+ sp->init_strings(YYTHD, lex, NULL);
+ /* Restore flag if it was cleared above */
+ if (sp->m_old_cmq)
+ YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
+ sp->restore_thd_mem_root(YYTHD);
+
+ lex->ident= $3;
+
+ /*
+ We have to do it after parsing trigger body, because some of
+ sp_proc_stmt alternatives are not saving/restoring LEX, so
+ lex->query_tables can be wiped out.
+
+ QQ: What are other consequences of this?
+
+ QQ: Could we loosen lock type in certain cases ?
+ */
+ if (!lex->select_lex.add_table_to_list(YYTHD, $7,
+ (LEX_STRING*) 0,
+ TL_OPTION_UPDATING,
+ TL_WRITE))
+ YYABORT;
+ }
+ | CREATE USER clear_privileges grant_list
+ {
+ Lex->sql_command = SQLCOM_CREATE_USER;
+ }
+ ;
+
+clear_privileges:
+ /* Nothing */
+ {
+ LEX *lex=Lex;
+ lex->users_list.empty();
+ lex->columns.empty();
+ lex->grant= lex->grant_tot_col= 0;
+ lex->all_privileges= 0;
+ lex->select_lex.db= 0;
+ lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
+ lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
+ bzero((char *)&(lex->mqh),sizeof(lex->mqh));
+ }
+ ;
+
+sp_name:
+ ident '.' ident
+ {
+ $$= new sp_name($1, $3);
+ $$->init_qname(YYTHD);
+ }
+ | ident
+ {
+ $$= sp_name_current_db_new(YYTHD, $1);
+ }
+ ;
+
+create_function_tail:
+ RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys
{
LEX *lex=Lex;
- lex->udf.returns=(Item_result) $7;
- lex->udf.dl=$9.str;
+ lex->sql_command = SQLCOM_CREATE_FUNCTION;
+ lex->udf.name = lex->spname->m_name;
+ lex->udf.returns=(Item_result) $2;
+ lex->udf.dl=$4.str;
+ }
+ | '('
+ {
+ LEX *lex= Lex;
+ sp_head *sp;
+
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
+ YYABORT;
+ }
+ /* Order is important here: new - reset - init */
+ sp= new sp_head();
+ sp->reset_thd_mem_root(YYTHD);
+ sp->init(lex);
+
+ sp->m_type= TYPE_ENUM_FUNCTION;
+ lex->sphead= sp;
+ /*
+ * We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ * stored procedure, otherwise yylex will chop it into pieces
+ * at each ';'.
+ */
+ sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
+ YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
+ lex->sphead->m_param_begin= lex->tok_start+1;
+ }
+ sp_fdparam_list ')'
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->m_param_end= lex->tok_start;
+ }
+ RETURNS_SYM
+ {
+ LEX *lex= Lex;
+ lex->charset= NULL;
+ lex->length= lex->dec= NULL;
+ lex->interval_list.empty();
+ lex->type= 0;
+ }
+ type
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ LEX_STRING cmt = { 0, 0 };
+ create_field *new_field;
+ uint unused1= 0;
+ int unused2= 0;
+
+ if (!(new_field= new_create_field(YYTHD, (char*) "",
+ (enum enum_field_types)$8,
+ lex->length, lex->dec, lex->type,
+ (Item *)0, (Item *) 0, &cmt, 0,
+ &lex->interval_list,
+ (lex->charset ? lex->charset :
+ default_charset_info),
+ lex->uint_geom_type)))
+ YYABORT;
+
+ sp->m_returns_cs= new_field->charset;
+
+ if (new_field->sql_type == FIELD_TYPE_SET ||
+ new_field->sql_type == FIELD_TYPE_ENUM)
+ {
+ new_field->interval=
+ sp->create_typelib(&new_field->interval_list);
+ }
+ sp_prepare_create_field(YYTHD, new_field);
+
+ if (prepare_create_field(new_field, &unused1, &unused2, &unused2,
+ 0))
+ YYABORT;
+
+ sp->m_returns= new_field->sql_type;
+ sp->m_returns_cs= new_field->charset;
+ sp->m_returns_len= new_field->length;
+ sp->m_returns_pack= new_field->pack_flag;
+ sp->m_returns_typelib= new_field->interval;
+ new_field->interval= NULL;
+
+ bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
+ }
+ sp_c_chistics
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->m_chistics= &lex->sp_chistics;
+ lex->sphead->m_body_begin= lex->tok_start;
+ }
+ sp_proc_stmt
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+
+ if (sp->m_multi_results)
+ {
+ my_message(ER_SP_NO_RETSET_IN_FUNC, ER(ER_SP_NO_RETSET_IN_FUNC),
+ MYF(0));
+ YYABORT;
+ }
+ if (sp->check_backpatch(YYTHD))
+ YYABORT;
+ lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
+ sp->init_strings(YYTHD, lex, lex->spname);
+ /* Restore flag if it was cleared above */
+ if (sp->m_old_cmq)
+ YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
+ sp->restore_thd_mem_root(YYTHD);
+ }
+ ;
+
+sp_a_chistics:
+ /* Empty */ {}
+ | sp_a_chistics sp_chistic {}
+ ;
+
+sp_c_chistics:
+ /* Empty */ {}
+ | sp_c_chistics sp_c_chistic {}
+ ;
+
+/* Characteristics for both create and alter */
+sp_chistic:
+ COMMENT_SYM TEXT_STRING_sys
+ { Lex->sp_chistics.comment= $2; }
+ | LANGUAGE_SYM SQL_SYM
+ { /* Just parse it, we only have one language for now. */ }
+ | NO_SYM SQL_SYM
+ { Lex->sp_chistics.daccess= SP_NO_SQL; }
+ | CONTAINS_SYM SQL_SYM
+ { Lex->sp_chistics.daccess= SP_CONTAINS_SQL; }
+ | READS_SYM SQL_SYM DATA_SYM
+ { Lex->sp_chistics.daccess= SP_READS_SQL_DATA; }
+ | MODIFIES_SYM SQL_SYM DATA_SYM
+ { Lex->sp_chistics.daccess= SP_MODIFIES_SQL_DATA; }
+ | sp_suid
+ { }
+ ;
+
+/* Create characteristics */
+sp_c_chistic:
+ sp_chistic { }
+ | DETERMINISTIC_SYM { Lex->sp_chistics.detistic= TRUE; }
+ | not DETERMINISTIC_SYM { Lex->sp_chistics.detistic= FALSE; }
+ ;
+
+sp_suid:
+ SQL_SYM SECURITY_SYM DEFINER_SYM
+ {
+ Lex->sp_chistics.suid= SP_IS_SUID;
+ }
+ | SQL_SYM SECURITY_SYM INVOKER_SYM
+ {
+ Lex->sp_chistics.suid= SP_IS_NOT_SUID;
+ }
+ ;
+
+call:
+ CALL_SYM sp_name
+ {
+ LEX *lex = Lex;
+
+ lex->sql_command= SQLCOM_CALL;
+ lex->spname= $2;
+ lex->value_list.empty();
+ sp_add_to_hash(&lex->spprocs, $2);
+ }
+ '(' sp_cparam_list ')' {}
+ ;
+
+/* CALL parameters */
+sp_cparam_list:
+ /* Empty */
+ | sp_cparams
+ ;
+
+sp_cparams:
+ sp_cparams ',' expr
+ {
+ Lex->value_list.push_back($3);
+ }
+ | expr
+ {
+ Lex->value_list.push_back($1);
+ }
+ ;
+
+/* Stored FUNCTION parameter declaration list */
+sp_fdparam_list:
+ /* Empty */
+ | sp_fdparams
+ ;
+
+sp_fdparams:
+ sp_fdparams ',' sp_fdparam
+ | sp_fdparam
+ ;
+
+sp_fdparam:
+ ident type
+ {
+ LEX *lex= Lex;
+ sp_pcontext *spc= lex->spcont;
+
+ if (spc->find_pvar(&$1, TRUE))
+ {
+ my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
+ YYABORT;
+ }
+ spc->push_pvar(&$1, (enum enum_field_types)$2, sp_param_in);
+ }
+ ;
+
+/* Stored PROCEDURE parameter declaration list */
+sp_pdparam_list:
+ /* Empty */
+ | sp_pdparams
+ ;
+
+sp_pdparams:
+ sp_pdparams ',' sp_pdparam
+ | sp_pdparam
+ ;
+
+sp_pdparam:
+ sp_opt_inout ident type
+ {
+ LEX *lex= Lex;
+ sp_pcontext *spc= lex->spcont;
+
+ if (spc->find_pvar(&$2, TRUE))
+ {
+ my_error(ER_SP_DUP_PARAM, MYF(0), $2.str);
+ YYABORT;
+ }
+ spc->push_pvar(&$2, (enum enum_field_types)$3,
+ (sp_param_mode_t)$1);
+ }
+ ;
+
+sp_opt_inout:
+ /* Empty */ { $$= sp_param_in; }
+ | IN_SYM { $$= sp_param_in; }
+ | OUT_SYM { $$= sp_param_out; }
+ | INOUT_SYM { $$= sp_param_inout; }
+ ;
+
+sp_proc_stmts:
+ /* Empty */ {}
+ | sp_proc_stmts sp_proc_stmt ';'
+ ;
+
+sp_proc_stmts1:
+ sp_proc_stmt ';' {}
+ | sp_proc_stmts1 sp_proc_stmt ';'
+ ;
+
+sp_decls:
+ /* Empty */
+ {
+ $$.vars= $$.conds= $$.hndlrs= $$.curs= 0;
+ }
+ | sp_decls sp_decl ';'
+ {
+ /* We check for declarations out of (standard) order this way
+ because letting the grammar rules reflect it caused tricky
+ shift/reduce conflicts with the wrong result. (And we get
+ better error handling this way.) */
+ if (($2.vars || $2.conds) && ($1.curs || $1.hndlrs))
+ { /* Variable or condition following cursor or handler */
+ my_message(ER_SP_VARCOND_AFTER_CURSHNDLR,
+ ER(ER_SP_VARCOND_AFTER_CURSHNDLR), MYF(0));
+ YYABORT;
+ }
+ if ($2.curs && $1.hndlrs)
+ { /* Cursor following handler */
+ my_message(ER_SP_CURSOR_AFTER_HANDLER,
+ ER(ER_SP_CURSOR_AFTER_HANDLER), MYF(0));
+ YYABORT;
+ }
+ $$.vars= $1.vars + $2.vars;
+ $$.conds= $1.conds + $2.conds;
+ $$.hndlrs= $1.hndlrs + $2.hndlrs;
+ $$.curs= $1.curs + $2.curs;
+ }
+ ;
+
+sp_decl:
+ DECLARE_SYM sp_decl_idents type
+ { Lex->sphead->reset_lex(YYTHD); }
+ sp_opt_default
+ {
+ LEX *lex= Lex;
+ sp_pcontext *ctx= lex->spcont;
+ uint max= ctx->context_pvars();
+ enum enum_field_types type= (enum enum_field_types)$3;
+ Item *it= $5;
+
+ for (uint i = max-$2 ; i < max ; i++)
+ {
+ ctx->set_type(i, type);
+ if (! it)
+ ctx->set_isset(i, FALSE);
+ else
+ {
+ sp_instr_set *in= new sp_instr_set(lex->sphead->instructions(),
+ ctx,
+ ctx->pvar_context2index(i),
+ it, type, lex,
+ (i == max - 1));
+
+ /*
+ The last instruction is assigned to be responsible for
+ freeing LEX.
+ */
+ lex->sphead->add_instr(in);
+ ctx->set_isset(i, TRUE);
+ ctx->set_default(i, it);
+ }
+ }
+ lex->sphead->restore_lex(YYTHD);
+ $$.vars= $2;
+ $$.conds= $$.hndlrs= $$.curs= 0;
+ }
+ | DECLARE_SYM ident CONDITION_SYM FOR_SYM sp_cond
+ {
+ LEX *lex= Lex;
+ sp_pcontext *spc= lex->spcont;
+
+ if (spc->find_cond(&$2, TRUE))
+ {
+ my_error(ER_SP_DUP_COND, MYF(0), $2.str);
+ YYABORT;
+ }
+ YYTHD->lex->spcont->push_cond(&$2, $5);
+ $$.vars= $$.hndlrs= $$.curs= 0;
+ $$.conds= 1;
+ }
+ | DECLARE_SYM sp_handler_type HANDLER_SYM FOR_SYM
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ sp_instr_hpush_jump *i=
+ new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
+ ctx->current_pvars());
+
+ sp->add_instr(i);
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ sp->m_in_handler= TRUE;
+ }
+ sp_hcond_list sp_proc_stmt
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ sp_label_t *hlab= lex->spcont->pop_label(); /* After this hdlr */
+ sp_instr_hreturn *i;
+
+ if ($2 == SP_HANDLER_CONTINUE)
+ {
+ i= new sp_instr_hreturn(sp->instructions(), ctx,
+ ctx->current_pvars());
+ sp->add_instr(i);
+ }
+ else
+ { /* EXIT or UNDO handler, just jump to the end of the block */
+ i= new sp_instr_hreturn(sp->instructions(), ctx, 0);
+
+ sp->add_instr(i);
+ sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
+ }
+ lex->sphead->backpatch(hlab);
+ sp->m_in_handler= FALSE;
+ $$.vars= $$.conds= $$.curs= 0;
+ $$.hndlrs= $6;
+ ctx->add_handlers($6);
+ }
+ | DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ uint offp;
+ sp_instr_cpush *i;
+
+ if (ctx->find_cursor(&$2, &offp, TRUE))
+ {
+ my_error(ER_SP_DUP_CURS, MYF(0), $2.str);
+ delete $5;
+ YYABORT;
+ }
+ i= new sp_instr_cpush(sp->instructions(), ctx, $5);
+ sp->add_instr(i);
+ ctx->push_cursor(&$2);
+ $$.vars= $$.conds= $$.hndlrs= 0;
+ $$.curs= 1;
+ }
+ ;
+
+sp_cursor_stmt:
+ {
+ Lex->sphead->reset_lex(YYTHD);
+
+ /* We use statement here just be able to get a better
+ error message. Using 'select' works too, but will then
+ result in a generic "syntax error" if a non-select
+ statement is given. */
+ }
+ statement
+ {
+ LEX *lex= Lex;
+
+ if (lex->sql_command != SQLCOM_SELECT)
+ {
+ my_message(ER_SP_BAD_CURSOR_QUERY, ER(ER_SP_BAD_CURSOR_QUERY),
+ MYF(0));
+ YYABORT;
+ }
+ if (lex->result)
+ {
+ my_message(ER_SP_BAD_CURSOR_SELECT, ER(ER_SP_BAD_CURSOR_SELECT),
+ MYF(0));
+ YYABORT;
+ }
+ lex->sp_lex_in_use= TRUE;
+ $$= lex;
+ lex->sphead->restore_lex(YYTHD);
+ }
+ ;
+
+sp_handler_type:
+ EXIT_SYM { $$= SP_HANDLER_EXIT; }
+ | CONTINUE_SYM { $$= SP_HANDLER_CONTINUE; }
+/* | UNDO_SYM { QQ No yet } */
+ ;
+
+sp_hcond_list:
+ sp_hcond
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+
+ if (ctx->find_handler($1))
+ {
+ my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
+ YYABORT;
+ }
+ else
+ {
+ sp_instr_hpush_jump *i=
+ (sp_instr_hpush_jump *)sp->last_instruction();
+
+ i->add_condition($1);
+ ctx->push_handler($1);
+ $$= 1;
+ }
+ }
+ | sp_hcond_list ',' sp_hcond
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+
+ if (ctx->find_handler($3))
+ {
+ my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
+ YYABORT;
+ }
+ else
+ {
+ sp_instr_hpush_jump *i=
+ (sp_instr_hpush_jump *)sp->last_instruction();
+
+ i->add_condition($3);
+ ctx->push_handler($3);
+ $$= $1 + 1;
+ }
+ }
+ ;
+
+sp_cond:
+ ulong_num
+ { /* mysql errno */
+ $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$->type= sp_cond_type_t::number;
+ $$->mysqlerr= $1;
+ }
+ | SQLSTATE_SYM opt_value TEXT_STRING_literal
+ { /* SQLSTATE */
+ if (!sp_cond_check(&$3))
+ {
+ my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str);
+ YYABORT;
+ }
+ $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$->type= sp_cond_type_t::state;
+ memcpy($$->sqlstate, $3.str, 5);
+ $$->sqlstate[5]= '\0';
+ }
+ ;
+
+opt_value:
+ /* Empty */ {}
+ | VALUE_SYM {}
+ ;
+
+sp_hcond:
+ sp_cond
+ {
+ $$= $1;
+ }
+ | ident /* CONDITION name */
+ {
+ $$= Lex->spcont->find_cond(&$1);
+ if ($$ == NULL)
+ {
+ my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
+ YYABORT;
+ }
+ }
+ | SQLWARNING_SYM /* SQLSTATEs 01??? */
+ {
+ $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$->type= sp_cond_type_t::warning;
+ }
+ | not FOUND_SYM /* SQLSTATEs 02??? */
+ {
+ $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$->type= sp_cond_type_t::notfound;
+ }
+ | SQLEXCEPTION_SYM /* All other SQLSTATEs */
+ {
+ $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
+ $$->type= sp_cond_type_t::exception;
+ }
+ ;
+
+sp_decl_idents:
+ ident
+ {
+ LEX *lex= Lex;
+ sp_pcontext *spc= lex->spcont;
+
+ if (spc->find_pvar(&$1, TRUE))
+ {
+ my_error(ER_SP_DUP_VAR, MYF(0), $1.str);
+ YYABORT;
+ }
+ spc->push_pvar(&$1, (enum_field_types)0, sp_param_in);
+ $$= 1;
+ }
+ | sp_decl_idents ',' ident
+ {
+ LEX *lex= Lex;
+ sp_pcontext *spc= lex->spcont;
+
+ if (spc->find_pvar(&$3, TRUE))
+ {
+ my_error(ER_SP_DUP_VAR, MYF(0), $3.str);
+ YYABORT;
+ }
+ spc->push_pvar(&$3, (enum_field_types)0, sp_param_in);
+ $$= $1 + 1;
+ }
+ ;
+
+sp_opt_default:
+ /* Empty */ { $$ = NULL; }
+ | DEFAULT expr { $$ = $2; }
+ ;
+
+sp_proc_stmt:
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->reset_lex(YYTHD);
+ lex->sphead->m_tmp_query= lex->tok_start;
+ }
+ statement
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+
+ if ((lex->sql_command == SQLCOM_SELECT && !lex->result) ||
+ sp_multi_results_command(lex->sql_command))
+ {
+ /* We maybe have one or more SELECT without INTO */
+ sp->m_multi_results= TRUE;
+ }
+ if (lex->sql_command == SQLCOM_CHANGE_DB)
+ { /* "USE db" doesn't work in a procedure */
+ my_message(ER_SP_NO_USE, ER(ER_SP_NO_USE), MYF(0));
+ YYABORT;
+ }
+ /*
+ Don't add an instruction for SET statements, since all
+ instructions for them were already added during processing
+ of "set" rule.
+ */
+ DBUG_ASSERT(lex->sql_command != SQLCOM_SET_OPTION ||
+ lex->var_list.is_empty());
+ if (lex->sql_command != SQLCOM_SET_OPTION)
+ {
+ sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
+ lex->spcont, lex);
+
+ /* Extract the query statement from the tokenizer:
+ The end is either lex->tok_end or tok->ptr. */
+ if (lex->ptr - lex->tok_end > 1)
+ i->m_query.length= lex->ptr - sp->m_tmp_query;
+ else
+ i->m_query.length= lex->tok_end - sp->m_tmp_query;
+ i->m_query.str= strmake_root(YYTHD->mem_root,
+ (char *)sp->m_tmp_query,
+ i->m_query.length);
+ sp->add_instr(i);
+ }
+ sp->restore_lex(YYTHD);
+ }
+ | RETURN_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+
+ if (sp->m_type == TYPE_ENUM_PROCEDURE)
+ {
+ my_message(ER_SP_BADRETURN, ER(ER_SP_BADRETURN), MYF(0));
+ YYABORT;
+ }
+ else
+ {
+ sp_instr_freturn *i;
+
+ i= new sp_instr_freturn(sp->instructions(), lex->spcont,
+ $3, sp->m_returns, lex);
+ sp->add_instr(i);
+ sp->m_has_return= TRUE;
+ }
+ sp->restore_lex(YYTHD);
+ }
+ | IF sp_if END IF {}
+ | CASE_SYM WHEN_SYM
+ {
+ Lex->sphead->m_simple_case= FALSE;
+ }
+ sp_case END CASE_SYM {}
+ | CASE_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr WHEN_SYM
+ {
+ /* We "fake" this by using an anonymous variable which we
+ set to the expression. Note that all WHENs are evaluate
+ at the same frame level, so we then know that it's the
+ top-most variable in the frame. */
+ LEX *lex= Lex;
+ uint offset= lex->spcont->current_pvars();
+ sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
+ lex->spcont, offset, $3,
+ MYSQL_TYPE_STRING, lex, TRUE);
+ LEX_STRING dummy={(char*)"", 0};
+
+ lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
+ lex->sphead->add_instr(i);
+ lex->sphead->m_simple_case= TRUE;
+ lex->sphead->restore_lex(YYTHD);
+ }
+ sp_case END CASE_SYM
+ {
+ Lex->spcont->pop_pvar();
+ }
+ | sp_labeled_control
+ {}
+ | { /* Unlabeled controls get a secret label. */
+ LEX *lex= Lex;
+
+ lex->spcont->push_label((char *)"", lex->sphead->instructions());
}
+ sp_unlabeled_control
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->backpatch(lex->spcont->pop_label());
+ }
+ | LEAVE_SYM IDENT
+ {
+ LEX *lex= Lex;
+ sp_head *sp = lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ sp_label_t *lab= ctx->find_label($2.str);
+
+ if (! lab)
+ {
+ my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", $2.str);
+ YYABORT;
+ }
+ else
+ {
+ uint ip= sp->instructions();
+ sp_instr_jump *i;
+ sp_instr_hpop *ih;
+ sp_instr_cpop *ic;
+
+ ih= new sp_instr_hpop(ip++, ctx, 0);
+ sp->push_backpatch(ih, lab);
+ sp->add_instr(ih);
+ ic= new sp_instr_cpop(ip++, ctx, 0);
+ sp->push_backpatch(ic, lab);
+ sp->add_instr(ic);
+ i= new sp_instr_jump(ip, ctx);
+ sp->push_backpatch(i, lab); /* Jumping forward */
+ sp->add_instr(i);
+ }
+ }
+ | ITERATE_SYM IDENT
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ sp_label_t *lab= ctx->find_label($2.str);
+
+ if (! lab || lab->type != SP_LAB_ITER)
+ {
+ my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", $2.str);
+ YYABORT;
+ }
+ else
+ {
+ sp_instr_jump *i;
+ uint ip= sp->instructions();
+ uint n;
+
+ n= ctx->diff_handlers(lab->ctx);
+ if (n)
+ sp->add_instr(new sp_instr_hpop(ip++, ctx, n));
+ n= ctx->diff_cursors(lab->ctx);
+ if (n)
+ sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
+ i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */
+ sp->add_instr(i);
+ }
+ }
+ | LABEL_SYM IDENT
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ sp_label_t *lab= ctx->find_label($2.str);
+
+ if (lab)
+ {
+ my_error(ER_SP_LABEL_REDEFINE, MYF(0), $2.str);
+ YYABORT;
+ }
+ else
+ {
+ lab= ctx->push_label($2.str, sp->instructions());
+ lab->type= SP_LAB_GOTO;
+ lab->ctx= ctx;
+ sp->backpatch(lab);
+ }
+ }
+ | GOTO_SYM IDENT
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ uint ip= lex->sphead->instructions();
+ sp_label_t *lab;
+ sp_instr_jump *i;
+ sp_instr_hpop *ih;
+ sp_instr_cpop *ic;
+
+ if (sp->m_in_handler)
+ {
+ my_message(ER_SP_GOTO_IN_HNDLR, ER(ER_SP_GOTO_IN_HNDLR), MYF(0));
+ YYABORT;
+ }
+ lab= ctx->find_label($2.str);
+ if (! lab)
+ {
+ lab= (sp_label_t *)YYTHD->alloc(sizeof(sp_label_t));
+ lab->name= $2.str;
+ lab->ip= 0;
+ lab->type= SP_LAB_REF;
+ lab->ctx= ctx;
+
+ ih= new sp_instr_hpop(ip++, ctx, 0);
+ sp->push_backpatch(ih, lab);
+ sp->add_instr(ih);
+ ic= new sp_instr_cpop(ip++, ctx, 0);
+ sp->add_instr(ic);
+ sp->push_backpatch(ic, lab);
+ i= new sp_instr_jump(ip, ctx);
+ sp->push_backpatch(i, lab); /* Jumping forward */
+ sp->add_instr(i);
+ }
+ else
+ {
+ uint n;
+
+ n= ctx->diff_handlers(lab->ctx);
+ if (n)
+ {
+ ih= new sp_instr_hpop(ip++, ctx, n);
+ sp->add_instr(ih);
+ }
+ n= ctx->diff_cursors(lab->ctx);
+ if (n)
+ {
+ ic= new sp_instr_cpop(ip++, ctx, n);
+ sp->add_instr(ic);
+ }
+ i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */
+ sp->add_instr(i);
+ }
+ }
+ | OPEN_SYM ident
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ uint offset;
+ sp_instr_copen *i;
+
+ if (! lex->spcont->find_cursor(&$2, &offset))
+ {
+ my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
+ YYABORT;
+ }
+ i= new sp_instr_copen(sp->instructions(), lex->spcont, offset);
+ sp->add_instr(i);
+ }
+ | FETCH_SYM sp_opt_fetch_noise ident INTO
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ uint offset;
+ sp_instr_cfetch *i;
+
+ if (! lex->spcont->find_cursor(&$3, &offset))
+ {
+ my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $3.str);
+ YYABORT;
+ }
+ i= new sp_instr_cfetch(sp->instructions(), lex->spcont, offset);
+ sp->add_instr(i);
+ }
+ sp_fetch_list
+ { }
+ | CLOSE_SYM ident
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ uint offset;
+ sp_instr_cclose *i;
+
+ if (! lex->spcont->find_cursor(&$2, &offset))
+ {
+ my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
+ YYABORT;
+ }
+ i= new sp_instr_cclose(sp->instructions(), lex->spcont, offset);
+ sp->add_instr(i);
+ }
+ ;
+
+sp_opt_fetch_noise:
+ /* Empty */
+ | NEXT_SYM FROM
+ | FROM
+ ;
+
+sp_fetch_list:
+ ident
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *spc= lex->spcont;
+ sp_pvar_t *spv;
+
+ if (!spc || !(spv = spc->find_pvar(&$1)))
+ {
+ my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
+ YYABORT;
+ }
+ else
+ {
+ /* An SP local variable */
+ sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction();
+
+ i->add_to_varlist(spv);
+ spv->isset= TRUE;
+ }
+ }
+ |
+ sp_fetch_list ',' ident
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *spc= lex->spcont;
+ sp_pvar_t *spv;
+
+ if (!spc || !(spv = spc->find_pvar(&$3)))
+ {
+ my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str);
+ YYABORT;
+ }
+ else
+ {
+ /* An SP local variable */
+ sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction();
+
+ i->add_to_varlist(spv);
+ spv->isset= TRUE;
+ }
+ }
+ ;
+
+sp_if:
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr THEN_SYM
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx,
+ $2, lex);
+
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ sp->add_instr(i);
+ sp->restore_lex(YYTHD);
+ }
+ sp_proc_stmts1
+ {
+ sp_head *sp= Lex->sphead;
+ sp_pcontext *ctx= Lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump *i = new sp_instr_jump(ip, ctx);
+
+ sp->add_instr(i);
+ sp->backpatch(ctx->pop_label());
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ }
+ sp_elseifs
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->backpatch(lex->spcont->pop_label());
+ }
+ ;
+
+sp_elseifs:
+ /* Empty */
+ | ELSEIF_SYM sp_if
+ | ELSE sp_proc_stmts1
+ ;
+
+sp_case:
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr THEN_SYM
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= Lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump_if_not *i;
+
+ if (! sp->m_simple_case)
+ i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
+ else
+ { /* Simple case: <caseval> = <whenval> */
+ LEX_STRING ivar;
+
+ ivar.str= (char *)"_tmp_";
+ ivar.length= 5;
+ Item *var= (Item*) new Item_splocal(ivar,
+ ctx->current_pvars()-1);
+ Item *expr= new Item_func_eq(var, $2);
+
+ i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
+ lex->variables_used= 1;
+ }
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ sp->add_instr(i);
+ sp->restore_lex(YYTHD);
+ }
+ sp_proc_stmts1
+ {
+ sp_head *sp= Lex->sphead;
+ sp_pcontext *ctx= Lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump *i = new sp_instr_jump(ip, ctx);
+
+ sp->add_instr(i);
+ sp->backpatch(ctx->pop_label());
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ }
+ sp_whens
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->backpatch(lex->spcont->pop_label());
+ }
+ ;
+
+sp_whens:
+ /* Empty */
+ {
+ sp_head *sp= Lex->sphead;
+ uint ip= sp->instructions();
+ sp_instr_error *i= new sp_instr_error(ip, Lex->spcont,
+ ER_SP_CASE_NOT_FOUND);
+
+ sp->add_instr(i);
+ }
+ | ELSE sp_proc_stmts1 {}
+ | WHEN_SYM sp_case {}
+ ;
+
+sp_labeled_control:
+ IDENT ':'
+ {
+ LEX *lex= Lex;
+ sp_pcontext *ctx= lex->spcont;
+ sp_label_t *lab= ctx->find_label($1.str);
+
+ if (lab)
+ {
+ my_error(ER_SP_LABEL_REDEFINE, MYF(0), $1.str);
+ YYABORT;
+ }
+ else
+ {
+ lab= lex->spcont->push_label($1.str,
+ lex->sphead->instructions());
+ lab->type= SP_LAB_ITER;
+ }
+ }
+ sp_unlabeled_control sp_opt_label
+ {
+ LEX *lex= Lex;
+
+ if ($5.str)
+ {
+ sp_label_t *lab= lex->spcont->find_label($5.str);
+
+ if (!lab ||
+ my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
+ {
+ my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str);
+ YYABORT;
+ }
+ }
+ lex->sphead->backpatch(lex->spcont->pop_label());
+ }
+ ;
+
+sp_opt_label:
+ /* Empty */ { $$= null_lex_str; }
+ | IDENT { $$= $1; }
+ ;
+
+sp_unlabeled_control:
+ BEGIN_SYM
+ { /* QQ This is just a dummy for grouping declarations and statements
+ together. No [[NOT] ATOMIC] yet, and we need to figure out how
+ make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
+ LEX *lex= Lex;
+ sp_label_t *lab= lex->spcont->last_label();
+
+ lab->type= SP_LAB_BEGIN;
+ lex->spcont= lex->spcont->push_context();
+ }
+ sp_decls
+ sp_proc_stmts
+ END
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+
+ sp->backpatch(ctx->last_label()); /* We always have a label */
+ if ($3.hndlrs)
+ sp->add_instr(new sp_instr_hpop(sp->instructions(), ctx,
+ $3.hndlrs));
+ if ($3.curs)
+ sp->add_instr(new sp_instr_cpop(sp->instructions(), ctx,
+ $3.curs));
+ lex->spcont= ctx->pop_context();
+ }
+ | LOOP_SYM
+ sp_proc_stmts1 END LOOP_SYM
+ {
+ LEX *lex= Lex;
+ uint ip= lex->sphead->instructions();
+ sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
+ sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip);
+
+ lex->sphead->add_instr(i);
+ }
+ | WHILE_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr DO_SYM
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ uint ip= sp->instructions();
+ sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
+ $3, lex);
+
+ /* Jumping forward */
+ sp->push_backpatch(i, lex->spcont->last_label());
+ sp->add_instr(i);
+ sp->restore_lex(YYTHD);
+ }
+ sp_proc_stmts1 END WHILE_SYM
+ {
+ LEX *lex= Lex;
+ uint ip= lex->sphead->instructions();
+ sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
+ sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip);
+
+ lex->sphead->add_instr(i);
+ }
+ | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr END REPEAT_SYM
+ {
+ LEX *lex= Lex;
+ uint ip= lex->sphead->instructions();
+ sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
+ sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
+ $5, lab->ip,
+ lex);
+ lex->sphead->add_instr(i);
+ lex->sphead->restore_lex(YYTHD);
+ }
+ ;
+
+trg_action_time:
+ BEFORE_SYM
+ { Lex->trg_chistics.action_time= TRG_ACTION_BEFORE; }
+ | AFTER_SYM
+ { Lex->trg_chistics.action_time= TRG_ACTION_AFTER; }
+ ;
+
+trg_event:
+ INSERT
+ { Lex->trg_chistics.event= TRG_EVENT_INSERT; }
+ | UPDATE_SYM
+ { Lex->trg_chistics.event= TRG_EVENT_UPDATE; }
+ | DELETE_SYM
+ { Lex->trg_chistics.event= TRG_EVENT_DELETE; }
;
create2:
@@ -1116,6 +2546,10 @@ create_select:
lex->sql_command= SQLCOM_INSERT_SELECT;
else if (lex->sql_command == SQLCOM_REPLACE)
lex->sql_command= SQLCOM_REPLACE_SELECT;
+ /*
+ The following work only with the local list, the global list
+ is created correctly in this case
+ */
lex->current_select->table_list.save_and_clear(&lex->save_list);
mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LIST;
@@ -1125,7 +2559,13 @@ create_select:
Select->parsing_place= NO_MATTER;
}
opt_select_from
- { Lex->current_select->table_list.push_front(&Lex->save_list); }
+ {
+ /*
+ The following work only with the local list, the global list
+ is created correctly in this case
+ */
+ Lex->current_select->table_list.push_front(&Lex->save_list);
+ }
;
opt_as:
@@ -1157,7 +2597,7 @@ table_option:
opt_if_not_exists:
/* empty */ { $$= 0; }
- | IF NOT EXISTS { $$=HA_LEX_CREATE_IF_NOT_EXISTS; };
+ | IF not EXISTS { $$=HA_LEX_CREATE_IF_NOT_EXISTS; };
opt_create_table_options:
/* empty */
@@ -1173,22 +2613,22 @@ create_table_options:
| create_table_option ',' create_table_options;
create_table_option:
- ENGINE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; }
- | TYPE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; WARN_DEPRECATED("TYPE=storage_engine","ENGINE=storage_engine"); }
+ ENGINE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; }
+ | TYPE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; WARN_DEPRECATED("TYPE=storage_engine","ENGINE=storage_engine"); Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; }
| MAX_ROWS opt_equal ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;}
| MIN_ROWS opt_equal ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;}
- | AVG_ROW_LENGTH opt_equal ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
- | PASSWORD opt_equal TEXT_STRING_sys { Lex->create_info.password=$3.str; }
- | COMMENT_SYM opt_equal TEXT_STRING_sys { Lex->create_info.comment=$3.str; }
+ | AVG_ROW_LENGTH opt_equal ulong_num { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
+ | PASSWORD opt_equal TEXT_STRING_sys { Lex->create_info.password=$3.str; Lex->create_info.used_fields|= HA_CREATE_USED_PASSWORD; }
+ | COMMENT_SYM opt_equal TEXT_STRING_sys { Lex->create_info.comment=$3.str; Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT; }
| AUTO_INC opt_equal ulonglong_num { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;}
- | PACK_KEYS_SYM opt_equal ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_PACK_KEYS : HA_OPTION_NO_PACK_KEYS; Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;}
+ | PACK_KEYS_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_PACK_KEYS : HA_OPTION_NO_PACK_KEYS; Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;}
| PACK_KEYS_SYM opt_equal DEFAULT { Lex->create_info.table_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;}
- | CHECKSUM_SYM opt_equal ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; }
- | DELAY_KEY_WRITE_SYM opt_equal ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; }
- | ROW_FORMAT_SYM opt_equal row_types { Lex->create_info.row_type= $3; }
+ | CHECKSUM_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; Lex->create_info.used_fields|= HA_CREATE_USED_CHECKSUM; }
+ | DELAY_KEY_WRITE_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; Lex->create_info.used_fields|= HA_CREATE_USED_DELAY_KEY_WRITE; }
+ | ROW_FORMAT_SYM opt_equal row_types { Lex->create_info.row_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_ROW_FORMAT; }
| RAID_TYPE opt_equal raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | RAID_CHUNKS opt_equal ULONG_NUM { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | RAID_CHUNKSIZE opt_equal ULONG_NUM { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | RAID_CHUNKS opt_equal ulong_num { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | RAID_CHUNKSIZE opt_equal ulong_num { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
| UNION_SYM opt_equal '(' table_list ')'
{
/* Move the union list to the merge_list */
@@ -1196,18 +2636,20 @@ create_table_option:
TABLE_LIST *table_list= lex->select_lex.get_table_list();
lex->create_info.merge_list= lex->select_lex.table_list;
lex->create_info.merge_list.elements--;
- lex->create_info.merge_list.first= (byte*) (table_list->next);
+ lex->create_info.merge_list.first=
+ (byte*) (table_list->next_local);
lex->select_lex.table_list.elements=1;
- lex->select_lex.table_list.next= (byte**) &(table_list->next);
- table_list->next=0;
+ lex->select_lex.table_list.next=
+ (byte**) &(table_list->next_local);
+ table_list->next_local= 0;
lex->create_info.used_fields|= HA_CREATE_USED_UNION;
}
| default_charset
| default_collation
| INSERT_METHOD opt_equal merge_insert_types { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;}
- | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys
- { Lex->create_info.data_file_name= $4.str; }
- | INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.index_file_name= $4.str; };
+ | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.data_file_name= $4.str; Lex->create_info.used_fields|= HA_CREATE_USED_DATADIR; }
+ | INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.index_file_name= $4.str; Lex->create_info.used_fields|= HA_CREATE_USED_INDEXDIR; }
+ ;
default_charset:
opt_default charset opt_equal charset_name_or_default
@@ -1217,9 +2659,9 @@ default_charset:
cinfo->default_table_charset && $4 &&
!my_charset_same(cinfo->default_table_charset,$4))
{
- net_printf(YYTHD, ER_CONFLICTING_DECLARATIONS,
- "CHARACTER SET ", cinfo->default_table_charset->csname,
- "CHARACTER SET ", $4->csname);
+ my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
+ "CHARACTER SET ", cinfo->default_table_charset->csname,
+ "CHARACTER SET ", $4->csname);
YYABORT;
}
Lex->create_info.default_table_charset= $4;
@@ -1234,8 +2676,8 @@ default_collation:
cinfo->default_table_charset && $4 &&
!my_charset_same(cinfo->default_table_charset,$4))
{
- net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
- $4->name, cinfo->default_table_charset->csname);
+ my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
+ $4->name, cinfo->default_table_charset->csname);
YYABORT;
}
Lex->create_info.default_table_charset= $4;
@@ -1247,7 +2689,7 @@ storage_engines:
{
$$ = ha_resolve_by_name($1.str,$1.length);
if ($$ == DB_TYPE_UNKNOWN) {
- net_printf(YYTHD, ER_UNKNOWN_STORAGE_ENGINE, $1.str);
+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str);
YYABORT;
}
};
@@ -1256,12 +2698,14 @@ row_types:
DEFAULT { $$= ROW_TYPE_DEFAULT; }
| FIXED_SYM { $$= ROW_TYPE_FIXED; }
| DYNAMIC_SYM { $$= ROW_TYPE_DYNAMIC; }
- | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; };
+ | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; }
+ | REDUNDANT_SYM { $$= ROW_TYPE_REDUNDANT; }
+ | COMPACT_SYM { $$= ROW_TYPE_COMPACT; };
raid_types:
RAID_STRIPED_SYM { $$= RAID_TYPE_0; }
| RAID_0_SYM { $$= RAID_TYPE_0; }
- | ULONG_NUM { $$=$1;};
+ | ulong_num { $$=$1;};
merge_insert_types:
NO_SYM { $$= MERGE_INSERT_DISABLED; }
@@ -1279,6 +2723,7 @@ udf_func_type:
udf_type:
STRING_SYM {$$ = (int) STRING_RESULT; }
| REAL {$$ = (int) REAL_RESULT; }
+ | DECIMAL_SYM {$$ = (int) DECIMAL_RESULT; }
| INT_SYM {$$ = (int) INT_RESULT; };
field_list:
@@ -1362,7 +2807,7 @@ field_spec:
LEX *lex=Lex;
lex->length=lex->dec=0; lex->type=0;
lex->default_value= lex->on_update_value= 0;
- lex->comment=0;
+ lex->comment=null_lex_str;
lex->charset=NULL;
}
type opt_attribute
@@ -1372,7 +2817,7 @@ field_spec:
(enum enum_field_types) $3,
lex->length,lex->dec,lex->type,
lex->default_value, lex->on_update_value,
- lex->comment,
+ &lex->comment,
lex->change,&lex->interval_list,lex->charset,
lex->uint_geom_type))
YYABORT;
@@ -1382,8 +2827,10 @@ type:
int_type opt_len field_options { $$=$1; }
| real_type opt_precision field_options { $$=$1; }
| FLOAT_SYM float_options field_options { $$=FIELD_TYPE_FLOAT; }
- | BIT_SYM opt_len { Lex->length=(char*) "1";
- $$=FIELD_TYPE_TINY; }
+ | BIT_SYM { Lex->length= (char*) "1";
+ $$=FIELD_TYPE_BIT; }
+ | BIT_SYM '(' NUM ')' { Lex->length= $3.str;
+ $$=FIELD_TYPE_BIT; }
| BOOL_SYM { Lex->length=(char*) "1";
$$=FIELD_TYPE_TINY; }
| BOOLEAN_SYM { Lex->length=(char*) "1";
@@ -1405,13 +2852,13 @@ type:
Lex->charset=&my_charset_bin;
$$=FIELD_TYPE_STRING; }
| varchar '(' NUM ')' opt_binary { Lex->length=$3.str;
- $$=FIELD_TYPE_VAR_STRING; }
+ $$= MYSQL_TYPE_VARCHAR; }
| nvarchar '(' NUM ')' { Lex->length=$3.str;
- $$=FIELD_TYPE_VAR_STRING;
+ $$= MYSQL_TYPE_VARCHAR;
Lex->charset=national_charset_info; }
| VARBINARY '(' NUM ')' { Lex->length=$3.str;
Lex->charset=&my_charset_bin;
- $$=FIELD_TYPE_VAR_STRING; }
+ $$= MYSQL_TYPE_VARCHAR; }
| YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; }
| DATE_SYM { $$=FIELD_TYPE_DATE; }
| TIME_SYM { $$=FIELD_TYPE_TIME; }
@@ -1433,18 +2880,18 @@ type:
$$=FIELD_TYPE_TINY_BLOB; }
| BLOB_SYM opt_len { Lex->charset=&my_charset_bin;
$$=FIELD_TYPE_BLOB; }
- | spatial_type {
+ | spatial_type
+ {
#ifdef HAVE_SPATIAL
- Lex->charset=&my_charset_bin;
- Lex->uint_geom_type= (uint)$1;
- $$=FIELD_TYPE_GEOMETRY;
+ Lex->charset=&my_charset_bin;
+ Lex->uint_geom_type= (uint)$1;
+ $$=FIELD_TYPE_GEOMETRY;
#else
- net_printf(Lex->thd, ER_FEATURE_DISABLED,
- sym_group_geom.name,
- sym_group_geom.needed_define);
- YYABORT;
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ sym_group_geom.name, sym_group_geom.needed_define);
+ YYABORT;
#endif
- }
+ }
| MEDIUMBLOB { Lex->charset=&my_charset_bin;
$$=FIELD_TYPE_MEDIUM_BLOB; }
| LONGBLOB { Lex->charset=&my_charset_bin;
@@ -1457,11 +2904,11 @@ type:
| MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
| LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; }
| DECIMAL_SYM float_options field_options
- { $$=FIELD_TYPE_DECIMAL;}
+ { $$=FIELD_TYPE_NEWDECIMAL;}
| NUMERIC_SYM float_options field_options
- { $$=FIELD_TYPE_DECIMAL;}
+ { $$=FIELD_TYPE_NEWDECIMAL;}
| FIXED_SYM float_options field_options
- { $$=FIELD_TYPE_DECIMAL;}
+ { $$=FIELD_TYPE_NEWDECIMAL;}
| ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary
{ $$=FIELD_TYPE_ENUM; }
| SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary
@@ -1523,8 +2970,8 @@ real_type:
float_options:
- /* empty */ {}
- | '(' NUM ')' { Lex->length=$2.str; }
+ /* empty */ { Lex->dec=Lex->length= (char*)0; }
+ | '(' NUM ')' { Lex->length=$2.str; Lex->dec= (char*)0; }
| precision {};
precision:
@@ -1565,7 +3012,7 @@ opt_attribute_list:
attribute:
NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; }
- | NOT NULL_SYM { Lex->type|= NOT_NULL_FLAG; }
+ | not NULL_SYM { Lex->type|= NOT_NULL_FLAG; }
| DEFAULT now_or_signed_literal { Lex->default_value=$2; }
| ON UPDATE_SYM NOW_SYM optional_braces
{ Lex->on_update_value= new Item_func_now_local(); }
@@ -1594,14 +3041,14 @@ attribute:
lex->type|= UNIQUE_KEY_FLAG;
lex->alter_info.flags|= ALTER_ADD_INDEX;
}
- | COMMENT_SYM TEXT_STRING_sys { Lex->comment= &$2; }
+ | COMMENT_SYM TEXT_STRING_sys { Lex->comment= $2; }
| BINARY { Lex->type|= BINCMP_FLAG; }
| COLLATE_SYM collation_name
{
if (Lex->charset && !my_charset_same(Lex->charset,$2))
{
- net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
- $2->name,Lex->charset->csname);
+ my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
+ $2->name,Lex->charset->csname);
YYABORT;
}
else
@@ -1626,7 +3073,7 @@ charset_name:
{
if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0))))
{
- net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,$1.str);
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str);
YYABORT;
}
}
@@ -1644,7 +3091,7 @@ old_or_new_charset_name:
if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0))) &&
!($$=get_old_charset_by_name($1.str)))
{
- net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,$1.str);
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str);
YYABORT;
}
}
@@ -1660,7 +3107,7 @@ collation_name:
{
if (!($$=get_charset_by_name($1.str,MYF(0))))
{
- net_printf(YYTHD,ER_UNKNOWN_COLLATION,$1.str);
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), $1.str);
YYABORT;
}
};
@@ -1684,9 +3131,10 @@ opt_binary:
| BYTE_SYM { Lex->charset=&my_charset_bin; }
| UNICODE_SYM
{
- if (!(Lex->charset=get_charset_by_csname("ucs2",MY_CS_PRIMARY,MYF(0))))
+ if (!(Lex->charset=get_charset_by_csname("ucs2",
+ MY_CS_PRIMARY,MYF(0))))
{
- net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,"ucs2");
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
YYABORT;
}
}
@@ -1748,8 +3196,8 @@ key_type:
#ifdef HAVE_SPATIAL
$$= Key::SPATIAL;
#else
- net_printf(Lex->thd, ER_FEATURE_DISABLED,
- sym_group_geom.name, sym_group_geom.needed_define);
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ sym_group_geom.name, sym_group_geom.needed_define);
YYABORT;
#endif
};
@@ -1781,8 +3229,8 @@ opt_unique_or_fulltext:
#ifdef HAVE_SPATIAL
$$= Key::SPATIAL;
#else
- net_printf(Lex->thd, ER_FEATURE_DISABLED,
- sym_group_geom.name, sym_group_geom.needed_define);
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ sym_group_geom.name, sym_group_geom.needed_define);
YYABORT;
#endif
}
@@ -1810,14 +3258,10 @@ key_part:
| ident '(' NUM ')'
{
int key_part_len= atoi($3.str);
-#if MYSQL_VERSION_ID < 50000
if (!key_part_len)
{
- my_printf_error(ER_UNKNOWN_ERROR,
- "Key part '%s' length cannot be 0",
- MYF(0), $1.str);
+ my_error(ER_KEY_PART_0, MYF(0), $1.str);
}
-#endif
$$=new key_part_spec($1.str,(uint) key_part_len);
};
@@ -1826,8 +3270,8 @@ opt_ident:
| field_ident { $$=$1.str; };
opt_component:
- /* empty */ { $$.str= 0; $$.length= 0; }
- | '.' ident { $$=$2; };
+ /* empty */ { $$= null_lex_str; }
+ | '.' ident { $$= $2; };
string_list:
text_string { Lex->interval_list.push_back($1); }
@@ -1857,8 +3301,7 @@ alter:
lex->create_info.db_type= DB_TYPE_DEFAULT;
lex->create_info.default_table_charset= NULL;
lex->create_info.row_type= ROW_TYPE_NOT_USED;
- lex->alter_info.reset();
- lex->alter_info.is_simple= 1;
+ lex->alter_info.reset();
lex->alter_info.flags= 0;
}
alter_list
@@ -1873,14 +3316,61 @@ alter:
LEX *lex=Lex;
lex->sql_command=SQLCOM_ALTER_DB;
lex->name= $3;
- };
+ }
+ | ALTER PROCEDURE sp_name
+ {
+ LEX *lex= Lex;
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
+ YYABORT;
+ }
+ bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
+ }
+ sp_a_chistics
+ {
+ LEX *lex=Lex;
+
+ lex->sql_command= SQLCOM_ALTER_PROCEDURE;
+ lex->spname= $3;
+ }
+ | ALTER FUNCTION_SYM sp_name
+ {
+ LEX *lex= Lex;
+
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
+ YYABORT;
+ }
+ bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
+ }
+ sp_a_chistics
+ {
+ LEX *lex=Lex;
+
+ lex->sql_command= SQLCOM_ALTER_FUNCTION;
+ lex->spname= $3;
+ }
+ | ALTER algorithm VIEW_SYM table_ident
+ {
+ THD *thd= YYTHD;
+ 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);
+ }
+ opt_view_list AS select_init check_option
+ {}
+ ;
ident_or_empty:
/* empty */ { $$= 0; }
| ident { $$= $1.str; };
-
alter_list:
| DISCARD TABLESPACE { Lex->alter_info.tablespace_op= DISCARD_TABLESPACE; }
| IMPORT TABLESPACE { Lex->alter_info.tablespace_op= IMPORT_TABLESPACE; }
@@ -1888,27 +3378,27 @@ alter_list:
| alter_list ',' alter_list_item;
add_column:
- ADD opt_column
+ ADD opt_column
{
LEX *lex=Lex;
- lex->change=0;
- lex->alter_info.flags|= ALTER_ADD_COLUMN;
+ lex->change=0;
+ lex->alter_info.flags|= ALTER_ADD_COLUMN;
};
alter_list_item:
- add_column column_def opt_place { Lex->alter_info.is_simple= 0; }
- | ADD key_def
- {
- LEX *lex=Lex;
- lex->alter_info.is_simple= 0;
- lex->alter_info.flags|= ALTER_ADD_INDEX;
+ add_column column_def opt_place { }
+ | ADD key_def
+ {
+ Lex->alter_info.flags|= ALTER_ADD_INDEX;
}
- | add_column '(' field_list ')' { Lex->alter_info.is_simple= 0; }
+ | add_column '(' field_list ')'
+ {
+ Lex->alter_info.flags|= ALTER_ADD_COLUMN | ALTER_ADD_INDEX;
+ }
| CHANGE opt_column field_ident
{
LEX *lex=Lex;
- lex->change= $3.str;
- lex->alter_info.is_simple= 0;
+ lex->change= $3.str;
lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
}
field_spec opt_place
@@ -1917,9 +3407,8 @@ alter_list_item:
LEX *lex=Lex;
lex->length=lex->dec=0; lex->type=0;
lex->default_value= lex->on_update_value= 0;
- lex->comment=0;
+ lex->comment=null_lex_str;
lex->charset= NULL;
- lex->alter_info.is_simple= 0;
lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
}
type opt_attribute
@@ -1929,7 +3418,7 @@ alter_list_item:
(enum enum_field_types) $5,
lex->length,lex->dec,lex->type,
lex->default_value, lex->on_update_value,
- lex->comment,
+ &lex->comment,
$3.str, &lex->interval_list, lex->charset,
lex->uint_geom_type))
YYABORT;
@@ -1939,17 +3428,18 @@ alter_list_item:
{
LEX *lex=Lex;
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::COLUMN,
- $3.str));
- lex->alter_info.is_simple= 0;
+ $3.str));
lex->alter_info.flags|= ALTER_DROP_COLUMN;
}
- | DROP FOREIGN KEY_SYM opt_ident { Lex->alter_info.is_simple= 0; }
+ | DROP FOREIGN KEY_SYM opt_ident
+ {
+ Lex->alter_info.flags|= ALTER_DROP_INDEX;
+ }
| DROP PRIMARY_SYM KEY_SYM
{
LEX *lex=Lex;
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
primary_key_name));
- lex->alter_info.is_simple= 0;
lex->alter_info.flags|= ALTER_DROP_INDEX;
}
| DROP key_or_index field_ident
@@ -1957,25 +3447,32 @@ alter_list_item:
LEX *lex=Lex;
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str));
- lex->alter_info.is_simple= 0;
lex->alter_info.flags|= ALTER_DROP_INDEX;
}
- | DISABLE_SYM KEYS { Lex->alter_info.keys_onoff= DISABLE; }
- | ENABLE_SYM KEYS { Lex->alter_info.keys_onoff= ENABLE; }
+ | DISABLE_SYM KEYS
+ {
+ LEX *lex=Lex;
+ lex->alter_info.keys_onoff= DISABLE;
+ lex->alter_info.flags|= ALTER_KEYS_ONOFF;
+ }
+ | ENABLE_SYM KEYS
+ {
+ LEX *lex=Lex;
+ lex->alter_info.keys_onoff= ENABLE;
+ lex->alter_info.flags|= ALTER_KEYS_ONOFF;
+ }
| ALTER opt_column field_ident SET DEFAULT signed_literal
{
LEX *lex=Lex;
lex->alter_info.alter_list.push_back(new Alter_column($3.str,$6));
- lex->alter_info.is_simple= 0;
- lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
+ lex->alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT;
}
| ALTER opt_column field_ident DROP DEFAULT
{
LEX *lex=Lex;
lex->alter_info.alter_list.push_back(new Alter_column($3.str,
(Item*) 0));
- lex->alter_info.is_simple= 0;
- lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
+ lex->alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT;
}
| RENAME opt_to table_ident
{
@@ -1985,7 +3482,7 @@ alter_list_item:
if (check_table_name($3->table.str,$3->table.length) ||
$3->db.str && check_db_name($3->db.str))
{
- net_printf(lex->thd,ER_WRONG_TABLE_NAME,$3->table.str);
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str);
YYABORT;
}
lex->alter_info.flags|= ALTER_RENAME;
@@ -2000,27 +3497,25 @@ alter_list_item:
$5= $5 ? $5 : $4;
if (!my_charset_same($4,$5))
{
- net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
- $5->name,$4->csname);
+ my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
+ $5->name, $4->csname);
YYABORT;
}
LEX *lex= Lex;
- lex->create_info.table_charset=
+ lex->create_info.table_charset=
lex->create_info.default_table_charset= $5;
lex->create_info.used_fields|= (HA_CREATE_USED_CHARSET |
HA_CREATE_USED_DEFAULT_CHARSET);
- lex->alter_info.is_simple= 0;
+ lex->alter_info.flags|= ALTER_CONVERT;
}
- | create_table_options_space_separated
+ | create_table_options_space_separated
{
LEX *lex=Lex;
- lex->alter_info.is_simple= 0;
lex->alter_info.flags|= ALTER_OPTIONS;
}
- | order_clause
+ | order_clause
{
LEX *lex=Lex;
- lex->alter_info.is_simple= 0;
lex->alter_info.flags|= ALTER_ORDER;
};
@@ -2034,9 +3529,10 @@ opt_ignore:
;
opt_restrict:
- /* empty */ {}
- | RESTRICT {}
- | CASCADE {};
+ /* empty */ { Lex->drop_mode= DROP_DEFAULT; }
+ | RESTRICT { Lex->drop_mode= DROP_RESTRICT; }
+ | CASCADE { Lex->drop_mode= DROP_CASCADE; }
+ ;
opt_place:
/* empty */ {}
@@ -2054,7 +3550,7 @@ opt_to:
*/
slave:
- START_SYM SLAVE slave_thread_opts
+ START_SYM SLAVE slave_thread_opts
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_START;
@@ -2134,7 +3630,8 @@ slave_until:
!((lex->mi.log_file_name && lex->mi.pos) ||
(lex->mi.relay_log_name && lex->mi.relay_log_pos)))
{
- send_error(lex->thd, ER_BAD_SLAVE_UNTIL_COND);
+ my_message(ER_BAD_SLAVE_UNTIL_COND,
+ ER(ER_BAD_SLAVE_UNTIL_COND), MYF(0));
YYABORT;
}
@@ -2222,9 +3719,15 @@ analyze:
check:
CHECK_SYM table_or_tables
{
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_CHECK;
- lex->check_opt.init();
+ LEX *lex=Lex;
+
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "CHECK");
+ YYABORT;
+ }
+ lex->sql_command = SQLCOM_CHECK;
+ lex->check_opt.init();
}
table_list opt_mi_check_type
{}
@@ -2270,8 +3773,25 @@ rename:
}
table_to_table_list
{}
+ | RENAME USER clear_privileges rename_list
+ {
+ Lex->sql_command = SQLCOM_RENAME_USER;
+ }
;
+rename_list:
+ user TO_SYM user
+ {
+ if (Lex->users_list.push_back($1) || Lex->users_list.push_back($3))
+ YYABORT;
+ }
+ | rename_list ',' user TO_SYM user
+ {
+ if (Lex->users_list.push_back($3) || Lex->users_list.push_back($5))
+ YYABORT;
+ }
+ ;
+
table_to_table_list:
table_to_table
| table_to_table_list ',' table_to_table;
@@ -2293,7 +3813,7 @@ keycache:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_ASSIGN_TO_KEYCACHE;
- lex->name_and_length= $5;
+ lex->ident= $5;
}
;
@@ -2540,8 +4060,12 @@ select_item:
YYABORT;
if ($4.str)
$2->set_name($4.str,$4.length,system_charset_info);
- else if (!$2->name)
- $2->set_name($1,(uint) ($3 - $1), YYTHD->charset());
+ else if (!$2->name) {
+ char *str = $1;
+ if (str[-1] == '`')
+ str--;
+ $2->set_name(str,(uint) ($3 - str), YYTHD->charset());
+ }
};
remember_name:
@@ -2555,7 +4079,7 @@ select_item2:
| expr { $$=$1; };
select_alias:
- /* empty */ { $$.str=0;}
+ /* empty */ { $$=null_lex_str;}
| AS ident { $$=$2; }
| AS TEXT_STRING_sys { $$=$2; }
| ident { $$=$1; }
@@ -2568,184 +4092,154 @@ optional_braces:
/* all possible expressions */
expr:
- expr_expr { $$= $1; }
- | simple_expr { $$= $1; }
- ;
-
-comp_op: EQ { $$ = &comp_eq_creator; }
- | GE { $$ = &comp_ge_creator; }
- | GT_SYM { $$ = &comp_gt_creator; }
- | LE { $$ = &comp_le_creator; }
- | LT { $$ = &comp_lt_creator; }
- | NE { $$ = &comp_ne_creator; }
+ bool_term { Select->expr_list.push_front(new List<Item>); }
+ bool_or_expr
+ {
+ List<Item> *list= Select->expr_list.pop();
+ if (list->elements)
+ {
+ list->push_front($1);
+ $$= new Item_cond_or(*list);
+ /* optimize construction of logical OR to reduce
+ amount of objects for complex expressions */
+ }
+ else
+ $$= $1;
+ delete list;
+ }
;
-all_or_any: ALL { $$ = 1; }
- | ANY_SYM { $$ = 0; }
+bool_or_expr:
+ /* empty */
+ | bool_or_expr or bool_term
+ { Select->expr_list.head()->push_back($3); }
;
-/* expressions that begin with 'expr' */
-expr_expr:
- expr IN_SYM '(' expr_list ')'
- { $4->push_front($1); $$= new Item_func_in(*$4); }
- | expr NOT IN_SYM '(' expr_list ')'
- { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); }
- | expr IN_SYM in_subselect
- { $$= new Item_in_subselect($1, $3); }
- | expr NOT IN_SYM in_subselect
+bool_term:
+ bool_term XOR bool_term { $$= new Item_cond_xor($1,$3); }
+ | bool_factor { Select->expr_list.push_front(new List<Item>); }
+ bool_and_expr
{
- $$= new Item_func_not(new Item_in_subselect($1, $4));
+ List<Item> *list= Select->expr_list.pop();
+ if (list->elements)
+ {
+ list->push_front($1);
+ $$= new Item_cond_and(*list);
+ /* optimize construction of logical AND to reduce
+ amount of objects for complex expressions */
+ }
+ else
+ $$= $1;
+ delete list;
}
- | expr BETWEEN_SYM no_and_expr AND_SYM expr
- { $$= new Item_func_between($1,$3,$5); }
- | expr NOT BETWEEN_SYM no_and_expr AND_SYM expr
- { $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
- | expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
- | expr OR_SYM expr { $$= new Item_cond_or($1,$3); }
- | expr XOR expr { $$= new Item_cond_xor($1,$3); }
- | expr AND_SYM expr { $$= new Item_cond_and($1,$3); }
- | expr SOUNDS_SYM LIKE expr
- {
- $$= new Item_func_eq(new Item_func_soundex($1),
- new Item_func_soundex($4));
- }
- | expr LIKE simple_expr opt_escape
- { $$= new Item_func_like($1,$3,$4); }
- | expr NOT LIKE simple_expr opt_escape
- { $$= new Item_func_not(new Item_func_like($1,$4,$5));}
- | expr REGEXP expr { $$= new Item_func_regex($1,$3); }
- | expr NOT REGEXP expr
- { $$= new Item_func_not(new Item_func_regex($1,$4)); }
- | expr IS NULL_SYM { $$= new Item_func_isnull($1); }
- | expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
- | expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
- | expr comp_op expr %prec EQ { $$= (*$2)(0)->create($1,$3); }
- | expr comp_op all_or_any in_subselect %prec EQ
- {
- $$= all_any_subquery_creator($1, $2, $3, $4);
- }
- | expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
- | expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
- | expr '+' expr { $$= new Item_func_plus($1,$3); }
- | expr '-' expr { $$= new Item_func_minus($1,$3); }
- | expr '*' expr { $$= new Item_func_mul($1,$3); }
- | expr '/' expr { $$= new Item_func_div($1,$3); }
- | expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); }
- | expr MOD_SYM expr { $$= new Item_func_mod($1,$3); }
- | expr '|' expr { $$= new Item_func_bit_or($1,$3); }
- | expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
- | expr '&' expr { $$= new Item_func_bit_and($1,$3); }
- | expr '%' expr { $$= new Item_func_mod($1,$3); }
- | expr '+' interval_expr interval
- { $$= new Item_date_add_interval($1,$3,$4,0); }
- | expr '-' interval_expr interval
- { $$= new Item_date_add_interval($1,$3,$4,1); }
;
-/* expressions that begin with 'expr' that do NOT follow IN_SYM */
-no_in_expr:
- no_in_expr BETWEEN_SYM no_and_expr AND_SYM expr
- { $$= new Item_func_between($1,$3,$5); }
- | no_in_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr
- { $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
- | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
- | no_in_expr OR_SYM expr { $$= new Item_cond_or($1,$3); }
- | no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); }
- | no_in_expr AND_SYM expr { $$= new Item_cond_and($1,$3); }
- | no_in_expr SOUNDS_SYM LIKE expr
- {
- $$= new Item_func_eq(new Item_func_soundex($1),
- new Item_func_soundex($4));
- }
- | no_in_expr LIKE simple_expr opt_escape
- { $$= new Item_func_like($1,$3,$4); }
- | no_in_expr NOT LIKE simple_expr opt_escape
- { $$= new Item_func_not(new Item_func_like($1,$4,$5)); }
- | no_in_expr REGEXP expr { $$= new Item_func_regex($1,$3); }
- | no_in_expr NOT REGEXP expr
- { $$= new Item_func_not(new Item_func_regex($1,$4)); }
- | no_in_expr IS NULL_SYM { $$= new Item_func_isnull($1); }
- | no_in_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
- | no_in_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
- | no_in_expr comp_op expr %prec EQ { $$= (*$2)(0)->create($1,$3); }
- | no_in_expr comp_op all_or_any in_subselect %prec EQ
- {
- all_any_subquery_creator($1, $2, $3, $4);
- }
- | no_in_expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
- | no_in_expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
- | no_in_expr '+' expr { $$= new Item_func_plus($1,$3); }
- | no_in_expr '-' expr { $$= new Item_func_minus($1,$3); }
- | no_in_expr '*' expr { $$= new Item_func_mul($1,$3); }
- | no_in_expr '/' expr { $$= new Item_func_div($1,$3); }
- | no_in_expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); }
- | no_in_expr '|' expr { $$= new Item_func_bit_or($1,$3); }
- | no_in_expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
- | no_in_expr '&' expr { $$= new Item_func_bit_and($1,$3); }
- | no_in_expr '%' expr { $$= new Item_func_mod($1,$3); }
- | no_in_expr MOD_SYM expr { $$= new Item_func_mod($1,$3); }
- | no_in_expr '+' interval_expr interval
- { $$= new Item_date_add_interval($1,$3,$4,0); }
- | no_in_expr '-' interval_expr interval
- { $$= new Item_date_add_interval($1,$3,$4,1); }
- | simple_expr;
+bool_and_expr:
+ /* empty */
+ | bool_and_expr and bool_factor
+ { Select->expr_list.head()->push_back($3); }
+ ;
-/* expressions that begin with 'expr' that does NOT follow AND */
-no_and_expr:
- no_and_expr IN_SYM '(' expr_list ')'
+bool_factor:
+ NOT_SYM bool_factor { $$= negate_expression(YYTHD, $2); }
+ | bool_test ;
+
+bool_test:
+ bool_pri IS TRUE_SYM { $$= is_truth_value($1,1,0); }
+ | bool_pri IS not TRUE_SYM { $$= is_truth_value($1,0,0); }
+ | bool_pri IS FALSE_SYM { $$= is_truth_value($1,0,1); }
+ | bool_pri IS not FALSE_SYM { $$= is_truth_value($1,1,1); }
+ | bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); }
+ | bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); }
+ | bool_pri ;
+
+bool_pri:
+ bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); }
+ | bool_pri IS not NULL_SYM { $$= new Item_func_isnotnull($1); }
+ | bool_pri EQUAL_SYM predicate { $$= new Item_func_equal($1,$3); }
+ | bool_pri comp_op predicate %prec EQ
+ { $$= (*$2)(0)->create($1,$3); }
+ | bool_pri comp_op all_or_any in_subselect %prec EQ
+ { $$= all_any_subquery_creator($1, $2, $3, $4); }
+ | predicate ;
+
+predicate:
+ bit_expr IN_SYM '(' expr_list ')'
{ $4->push_front($1); $$= new Item_func_in(*$4); }
- | no_and_expr NOT IN_SYM '(' expr_list ')'
- { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); }
- | no_and_expr IN_SYM in_subselect
- { $$= new Item_in_subselect($1, $3); }
- | no_and_expr NOT IN_SYM in_subselect
- {
- $$= new Item_func_not(new Item_in_subselect($1, $4));
- }
- | no_and_expr BETWEEN_SYM no_and_expr AND_SYM expr
+ | bit_expr not IN_SYM '(' expr_list ')'
+ { $5->push_front($1); $$= negate_expression(YYTHD, new Item_func_in(*$5)); }
+ | bit_expr IN_SYM in_subselect
+ { $$= new Item_in_subselect($1, $3); }
+ | bit_expr not IN_SYM in_subselect
+ { $$= negate_expression(YYTHD, new Item_in_subselect($1, $4)); }
+ | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
{ $$= new Item_func_between($1,$3,$5); }
- | no_and_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr
- { $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
- | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
- | no_and_expr OR_SYM expr { $$= new Item_cond_or($1,$3); }
- | no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); }
- | no_and_expr SOUNDS_SYM LIKE expr
- {
- $$= new Item_func_eq(new Item_func_soundex($1),
- new Item_func_soundex($4));
- }
- | no_and_expr LIKE simple_expr opt_escape
- { $$= new Item_func_like($1,$3,$4); }
- | no_and_expr NOT LIKE simple_expr opt_escape
- { $$= new Item_func_not(new Item_func_like($1,$4,$5)); }
- | no_and_expr REGEXP expr { $$= new Item_func_regex($1,$3); }
- | no_and_expr NOT REGEXP expr
- { $$= new Item_func_not(new Item_func_regex($1,$4)); }
- | no_and_expr IS NULL_SYM { $$= new Item_func_isnull($1); }
- | no_and_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
- | no_and_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
- | no_and_expr comp_op expr %prec EQ { $$= (*$2)(0)->create($1,$3); }
- | no_and_expr comp_op all_or_any in_subselect %prec EQ
- {
- all_any_subquery_creator($1, $2, $3, $4);
- }
- | no_and_expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
- | no_and_expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
- | no_and_expr '+' expr { $$= new Item_func_plus($1,$3); }
- | no_and_expr '-' expr { $$= new Item_func_minus($1,$3); }
- | no_and_expr '*' expr { $$= new Item_func_mul($1,$3); }
- | no_and_expr '/' expr { $$= new Item_func_div($1,$3); }
- | no_and_expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); }
- | no_and_expr '|' expr { $$= new Item_func_bit_or($1,$3); }
- | no_and_expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
- | no_and_expr '&' expr { $$= new Item_func_bit_and($1,$3); }
- | no_and_expr '%' expr { $$= new Item_func_mod($1,$3); }
- | no_and_expr MOD_SYM expr { $$= new Item_func_mod($1,$3); }
- | no_and_expr '+' interval_expr interval
+ | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate
+ { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); }
+ | bit_expr SOUNDS_SYM LIKE bit_expr
+ { $$= new Item_func_eq(new Item_func_soundex($1),
+ new Item_func_soundex($4)); }
+ | bit_expr LIKE simple_expr opt_escape
+ { $$= new Item_func_like($1,$3,$4); }
+ | bit_expr not LIKE simple_expr opt_escape
+ { $$= new Item_func_not(new Item_func_like($1,$4,$5)); }
+ | bit_expr REGEXP bit_expr { $$= new Item_func_regex($1,$3); }
+ | bit_expr not REGEXP bit_expr
+ { $$= negate_expression(YYTHD, new Item_func_regex($1,$4)); }
+ | bit_expr ;
+
+bit_expr:
+ bit_expr '|' bit_term { $$= new Item_func_bit_or($1,$3); }
+ | bit_term ;
+
+bit_term:
+ bit_term '&' bit_factor { $$= new Item_func_bit_and($1,$3); }
+ | bit_factor ;
+
+bit_factor:
+ bit_factor SHIFT_LEFT value_expr
+ { $$= new Item_func_shift_left($1,$3); }
+ | bit_factor SHIFT_RIGHT value_expr
+ { $$= new Item_func_shift_right($1,$3); }
+ | value_expr ;
+
+value_expr:
+ value_expr '+' term { $$= new Item_func_plus($1,$3); }
+ | value_expr '-' term { $$= new Item_func_minus($1,$3); }
+ | value_expr '+' interval_expr interval
{ $$= new Item_date_add_interval($1,$3,$4,0); }
- | no_and_expr '-' interval_expr interval
+ | value_expr '-' interval_expr interval
{ $$= new Item_date_add_interval($1,$3,$4,1); }
- | simple_expr;
+ | term ;
+
+term:
+ term '*' factor { $$= new Item_func_mul($1,$3); }
+ | term '/' factor { $$= new Item_func_div($1,$3); }
+ | term '%' factor { $$= new Item_func_mod($1,$3); }
+ | term DIV_SYM factor { $$= new Item_func_int_div($1,$3); }
+ | term MOD_SYM factor { $$= new Item_func_mod($1,$3); }
+ | factor ;
+
+factor:
+ factor '^' simple_expr { $$= new Item_func_bit_xor($1,$3); }
+ | simple_expr ;
+
+or: OR_SYM | OR2_SYM;
+and: AND_SYM | AND_AND_SYM;
+not: NOT_SYM | NOT2_SYM;
+not2: '!' | NOT2_SYM;
+
+comp_op: EQ { $$ = &comp_eq_creator; }
+ | GE { $$ = &comp_ge_creator; }
+ | GT_SYM { $$ = &comp_gt_creator; }
+ | LE { $$ = &comp_le_creator; }
+ | LT { $$ = &comp_lt_creator; }
+ | NE { $$ = &comp_ne_creator; }
+ ;
+
+all_or_any: ALL { $$ = 1; }
+ | ANY_SYM { $$ = 0; }
+ ;
interval_expr:
INTERVAL_SYM expr { $$=$2; }
@@ -2765,12 +4259,16 @@ simple_expr:
| '@' ident_or_text SET_VAR expr
{
$$= new Item_func_set_user_var($2,$4);
- Lex->uncacheable(UNCACHEABLE_RAND);
+ LEX *lex= Lex;
+ lex->uncacheable(UNCACHEABLE_RAND);
+ lex->variables_used= 1;
}
| '@' ident_or_text
{
$$= new Item_func_get_user_var($2);
- Lex->uncacheable(UNCACHEABLE_RAND);
+ LEX *lex= Lex;
+ lex->uncacheable(UNCACHEABLE_RAND);
+ lex->variables_used= 1;
}
| '@' '@' opt_var_ident_type ident_or_text opt_component
{
@@ -2782,19 +4280,15 @@ simple_expr:
}
if (!($$= get_system_var(YYTHD, (enum_var_type) $3, $4, $5)))
YYABORT;
+ Lex->variables_used= 1;
}
| sum_expr
- | '+' expr %prec NEG { $$= $2; }
- | '-' expr %prec NEG { $$= new Item_func_neg($2); }
- | '~' expr %prec NEG { $$= new Item_func_bit_neg($2); }
- | NOT expr %prec NEG
- {
- $$= negate_expression(YYTHD, $2);
- }
- | '!' expr %prec NEG
- {
- $$= negate_expression(YYTHD, $2);
- }
+ | simple_expr OR_OR_SYM simple_expr
+ { $$= new Item_func_concat($1, $3); }
+ | '+' simple_expr %prec NEG { $$= $2; }
+ | '-' simple_expr %prec NEG { $$= new Item_func_neg($2); }
+ | '~' simple_expr %prec NEG { $$= new Item_func_bit_neg($2); }
+ | not2 simple_expr %prec NEG { $$= negate_expression(YYTHD, $2); }
| '(' expr ')' { $$= $2; }
| '(' expr ',' expr_list ')'
{
@@ -2809,20 +4303,22 @@ simple_expr:
| EXISTS exists_subselect { $$= $2; }
| singlerow_subselect { $$= $1; }
| '{' ident expr '}' { $$= $3; }
- | MATCH ident_list_arg AGAINST '(' expr fulltext_options ')'
+ | MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')'
{ $2->push_front($5);
Select->add_ftfunc_to_list((Item_func_match*)
($$=new Item_func_match(*$2,$6))); }
| ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); }
- | BINARY expr %prec NEG
+ | BINARY simple_expr %prec NEG
{
- $$= create_func_cast($2, ITEM_CAST_CHAR, -1, &my_charset_bin);
+ $$= create_func_cast($2, ITEM_CAST_CHAR, -1, 0, &my_charset_bin);
}
| CAST_SYM '(' expr AS cast_type ')'
{
+ LEX *lex= Lex;
$$= create_func_cast($3, $5,
- Lex->length ? atoi(Lex->length) : -1,
- Lex->charset);
+ lex->length ? atoi(lex->length) : -1,
+ lex->dec ? atoi(lex->dec) : 0,
+ lex->charset);
}
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
{ $$= new Item_func_case(* $4, $2, $5 ); }
@@ -2830,6 +4326,7 @@ simple_expr:
{
$$= create_func_cast($3, $5,
Lex->length ? atoi(Lex->length) : -1,
+ Lex->dec ? atoi(Lex->dec) : 0,
Lex->charset);
}
| CONVERT_SYM '(' expr USING charset_name ')'
@@ -2842,9 +4339,9 @@ simple_expr:
{
if (!$1.symbol->create_func)
{
- net_printf(Lex->thd, ER_FEATURE_DISABLED,
- $1.symbol->group->name,
- $1.symbol->group->needed_define);
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ $1.symbol->group->name,
+ $1.symbol->group->needed_define);
YYABORT;
}
$$= ((Item*(*)(void))($1.symbol->create_func))();
@@ -2853,9 +4350,9 @@ simple_expr:
{
if (!$1.symbol->create_func)
{
- net_printf(Lex->thd, ER_FEATURE_DISABLED,
- $1.symbol->group->name,
- $1.symbol->group->needed_define);
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ $1.symbol->group->name,
+ $1.symbol->group->needed_define);
YYABORT;
}
$$= ((Item*(*)(Item*))($1.symbol->create_func))($3);
@@ -2864,9 +4361,9 @@ simple_expr:
{
if (!$1.symbol->create_func)
{
- net_printf(Lex->thd, ER_FEATURE_DISABLED,
- $1.symbol->group->name,
- $1.symbol->group->needed_define);
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ $1.symbol->group->name,
+ $1.symbol->group->needed_define);
YYABORT;
}
$$= ((Item*(*)(Item*,Item*))($1.symbol->create_func))($3,$5);
@@ -2875,9 +4372,9 @@ simple_expr:
{
if (!$1.symbol->create_func)
{
- net_printf(Lex->thd, ER_FEATURE_DISABLED,
- $1.symbol->group->name,
- $1.symbol->group->needed_define);
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ $1.symbol->group->name,
+ $1.symbol->group->needed_define);
YYABORT;
}
$$= ((Item*(*)(Item*,Item*,Item*))($1.symbol->create_func))($3,$5,$7);
@@ -2886,6 +4383,8 @@ simple_expr:
{ $$= new Item_date_add_interval($3, $5, INTERVAL_DAY, 0);}
| ADDDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3, $6, $7, 0); }
+ | REPEAT_SYM '(' expr ',' expr ')'
+ { $$= new Item_func_repeat($3,$5); }
| ATAN '(' expr ')'
{ $$= new Item_func_atan($3); }
| ATAN '(' expr ',' expr ')'
@@ -2904,7 +4403,8 @@ simple_expr:
{ $5->push_front($3); $$= new Item_func_concat_ws(*$5); }
| CONVERT_TZ_SYM '(' expr ',' expr ',' expr ')'
{
- Lex->time_zone_tables_used= &fake_time_zone_tables_list;
+ if (Lex->add_time_zone_tables_to_query_tables(YYTHD))
+ YYABORT;
$$= new Item_func_convert_tz($3, $5, $7);
}
| CURDATE optional_braces
@@ -2976,8 +4476,8 @@ simple_expr:
#ifdef HAVE_SPATIAL
$$= $1;
#else
- net_printf(Lex->thd, ER_FEATURE_DISABLED,
- sym_group_geom.name, sym_group_geom.needed_define);
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ sym_group_geom.name, sym_group_geom.needed_define);
YYABORT;
#endif
}
@@ -3055,8 +4555,10 @@ simple_expr:
}
| OLD_PASSWORD '(' expr ')'
{ $$= new Item_func_old_password($3); }
- | POSITION_SYM '(' no_in_expr IN_SYM expr ')'
+ | POSITION_SYM '(' bit_expr IN_SYM expr ')'
{ $$ = new Item_func_locate($5,$3); }
+ | QUARTER_SYM '(' expr ')'
+ { $$ = new Item_func_quarter($3); }
| RAND '(' expr ')'
{ $$= new Item_func_rand($3); Lex->uncacheable(UNCACHEABLE_RAND);}
| RAND '(' ')'
@@ -3068,6 +4570,11 @@ simple_expr:
| ROUND '(' expr ')'
{ $$= new Item_func_round($3, new Item_int((char*)"0",0,1),0); }
| ROUND '(' expr ',' expr ')' { $$= new Item_func_round($3,$5,0); }
+ | ROW_COUNT_SYM '(' ')'
+ {
+ $$= new Item_func_row_count();
+ Lex->safe_to_cache_query= 0;
+ }
| SUBDATE_SYM '(' expr ',' expr ')'
{ $$= new Item_date_add_interval($3, $5, INTERVAL_DAY, 1);}
| SUBDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')'
@@ -3090,6 +4597,10 @@ simple_expr:
{ $$= new Item_datetime_typecast($3); }
| TIMESTAMP '(' expr ',' expr ')'
{ $$= new Item_func_add_time($3, $5, 1, 0); }
+ | TIMESTAMP_ADD '(' interval_time_st ',' expr ',' expr ')'
+ { $$= new Item_date_add_interval($7,$5,$3,0); }
+ | TIMESTAMP_DIFF '(' interval_time_st ',' expr ',' expr ')'
+ { $$= new Item_func_timestamp_diff($5,$7,$3); }
| TRIM '(' expr ')'
{ $$= new Item_func_trim($3); }
| TRIM '(' LEADING expr FROM expr ')'
@@ -3110,48 +4621,109 @@ simple_expr:
{ $$= new Item_func_round($3,$5,1); }
| TRUE_SYM
{ $$= new Item_int((char*) "TRUE",1,1); }
- | UDA_CHAR_SUM '(' udf_expr_list ')'
- {
- if ($3 != NULL)
- $$ = new Item_sum_udf_str($1, *$3);
- else
- $$ = new Item_sum_udf_str($1);
- }
- | UDA_FLOAT_SUM '(' udf_expr_list ')'
- {
- if ($3 != NULL)
- $$ = new Item_sum_udf_float($1, *$3);
- else
- $$ = new Item_sum_udf_float($1);
- }
- | UDA_INT_SUM '(' udf_expr_list ')'
- {
- if ($3 != NULL)
- $$ = new Item_sum_udf_int($1, *$3);
- else
- $$ = new Item_sum_udf_int($1);
- }
- | UDF_CHAR_FUNC '(' udf_expr_list ')'
- {
- if ($3 != NULL)
- $$ = new Item_func_udf_str($1, *$3);
- else
- $$ = new Item_func_udf_str($1);
- }
- | UDF_FLOAT_FUNC '(' udf_expr_list ')'
- {
- if ($3 != NULL)
- $$ = new Item_func_udf_float($1, *$3);
- else
- $$ = new Item_func_udf_float($1);
- }
- | UDF_INT_FUNC '(' udf_expr_list ')'
+ | ident '.' ident '(' udf_expr_list ')'
{
- if ($3 != NULL)
- $$ = new Item_func_udf_int($1, *$3);
+ LEX *lex= Lex;
+ sp_name *name= new sp_name($1, $3);
+
+ name->init_qname(YYTHD);
+ sp_add_to_hash(&lex->spfuns, name);
+ if ($5)
+ $$= new Item_func_sp(name, *$5);
else
- $$ = new Item_func_udf_int($1);
+ $$= new Item_func_sp(name);
+ lex->safe_to_cache_query=0;
}
+ | IDENT_sys '(' udf_expr_list ')'
+ {
+#ifdef HAVE_DLOPEN
+ udf_func *udf;
+
+ if (using_udf_functions && (udf=find_udf($1.str, $1.length)))
+ {
+ switch (udf->returns) {
+ case STRING_RESULT:
+ if (udf->type == UDFTYPE_FUNCTION)
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_str(udf, *$3);
+ else
+ $$ = new Item_func_udf_str(udf);
+ }
+ else
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_str(udf, *$3);
+ else
+ $$ = new Item_sum_udf_str(udf);
+ }
+ break;
+ case REAL_RESULT:
+ if (udf->type == UDFTYPE_FUNCTION)
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_float(udf, *$3);
+ else
+ $$ = new Item_func_udf_float(udf);
+ }
+ else
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_float(udf, *$3);
+ else
+ $$ = new Item_sum_udf_float(udf);
+ }
+ break;
+ case INT_RESULT:
+ if (udf->type == UDFTYPE_FUNCTION)
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_int(udf, *$3);
+ else
+ $$ = new Item_func_udf_int(udf);
+ }
+ else
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_int(udf, *$3);
+ else
+ $$ = new Item_sum_udf_int(udf);
+ }
+ break;
+ case DECIMAL_RESULT:
+ if (udf->type == UDFTYPE_FUNCTION)
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_decimal(udf, *$3);
+ else
+ $$ = new Item_func_udf_decimal(udf);
+ }
+ else
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_decimal(udf, *$3);
+ else
+ $$ = new Item_sum_udf_decimal(udf);
+ }
+ break;
+ default:
+ YYABORT;
+ }
+ }
+ else
+#endif /* HAVE_DLOPEN */
+ {
+ LEX *lex= Lex;
+ sp_name *name= sp_name_current_db_new(YYTHD, $1);
+
+ sp_add_to_hash(&lex->spfuns, name);
+ if ($3)
+ $$= new Item_func_sp(name, *$3);
+ else
+ $$= new Item_func_sp(name);
+ lex->safe_to_cache_query=0;
+ }
+ }
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
{
$$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
@@ -3184,7 +4756,7 @@ simple_expr:
{ $$= new Item_func_yearweek($3,new Item_int((char*) "0",0,1)); }
| YEARWEEK '(' expr ',' expr ')'
{ $$= new Item_func_yearweek($3, $5); }
- | BENCHMARK_SYM '(' ULONG_NUM ',' expr ')'
+ | BENCHMARK_SYM '(' ulong_num ',' expr ')'
{
$$=new Item_func_benchmark($3,$5);
Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -3193,7 +4765,9 @@ simple_expr:
{ $$=new Item_extract( $3, $5); };
geometry_function:
- GEOMFROMTEXT '(' expr ')'
+ CONTAINS_SYM '(' expr ',' expr ')'
+ { $$= GEOM_NEW(Item_func_spatial_rel($3, $5, Item_func::SP_CONTAINS_FUNC)); }
+ | GEOMFROMTEXT '(' expr ')'
{ $$= GEOM_NEW(Item_func_geometry_from_text($3)); }
| GEOMFROMTEXT '(' expr ',' expr ')'
{ $$= GEOM_NEW(Item_func_geometry_from_text($3, $5)); }
@@ -3259,12 +4833,43 @@ fulltext_options:
;
udf_expr_list:
- /* empty */ { $$= NULL; }
- | expr_list { $$= $1;};
+ /* empty */ { $$= NULL; }
+ | udf_expr_list2 { $$= $1;}
+ ;
+
+udf_expr_list2:
+ { Select->expr_list.push_front(new List<Item>); }
+ udf_expr_list3
+ { $$= Select->expr_list.pop(); }
+ ;
+
+udf_expr_list3:
+ udf_expr
+ {
+ Select->expr_list.head()->push_back($1);
+ }
+ | udf_expr_list3 ',' udf_expr
+ {
+ Select->expr_list.head()->push_back($3);
+ }
+ ;
+
+udf_expr:
+ remember_name expr remember_end select_alias
+ {
+ if ($4.str)
+ $2->set_name($4.str,$4.length,system_charset_info);
+ else
+ $2->set_name($1,(uint) ($3 - $1), YYTHD->charset());
+ $$= $2;
+ }
+ ;
sum_expr:
AVG_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_avg($3); }
+ | AVG_SYM '(' DISTINCT in_sum_expr ')'
+ { $$=new Item_sum_avg_distinct($4); }
| BIT_AND '(' in_sum_expr ')'
{ $$=new Item_sum_and($3); }
| BIT_OR '(' in_sum_expr ')'
@@ -3285,14 +4890,29 @@ sum_expr:
{ $$= new Item_sum_unique_users($3,atoi($5.str),atoi($7.str),$9); }
| MIN_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_min($3); }
+/*
+ According to ANSI SQL, DISTINCT is allowed and has
+ no sence inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...)
+ is processed like an ordinary MIN | MAX()
+ */
+ | MIN_SYM '(' DISTINCT in_sum_expr ')'
+ { $$=new Item_sum_min($4); }
| MAX_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_max($3); }
+ | MAX_SYM '(' DISTINCT in_sum_expr ')'
+ { $$=new Item_sum_max($4); }
| STD_SYM '(' in_sum_expr ')'
- { $$=new Item_sum_std($3); }
+ { $$=new Item_sum_std($3, 0); }
| VARIANCE_SYM '(' in_sum_expr ')'
- { $$=new Item_sum_variance($3); }
+ { $$=new Item_sum_variance($3, 0); }
+ | STDDEV_SAMP_SYM '(' in_sum_expr ')'
+ { $$=new Item_sum_std($3, 1); }
+ | VAR_SAMP_SYM '(' in_sum_expr ')'
+ { $$=new Item_sum_variance($3, 1); }
| SUM_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_sum($3); }
+ | SUM_SYM '(' DISTINCT in_sum_expr ')'
+ { $$=new Item_sum_sum_distinct($4); }
| GROUP_CONCAT_SYM '(' opt_distinct
{ Select->in_sum_expr++; }
expr_list opt_gorder_clause
@@ -3345,16 +4965,17 @@ in_sum_expr:
};
cast_type:
- BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; }
- | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; }
- | NCHAR_SYM opt_len { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; }
- | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; }
- | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; }
- | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; }
- | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; }
- | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->length= (char*)0; }
- | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->length= (char*)0; }
- | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->length= (char*)0; }
+ BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; }
+ | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; Lex->dec= 0; }
+ | NCHAR_SYM opt_len { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; }
+ | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | DECIMAL_SYM float_options { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
;
expr_list:
@@ -3406,58 +5027,95 @@ when_list2:
sel->when_list.head()->push_back($5);
};
+/* Warning - may return NULL in case of incomplete SELECT */
+table_ref:
+ table_factor { $$=$1; }
+ | join_table { $$=$1; }
+ {
+ LEX *lex= Lex;
+ if (!($$= lex->current_select->nest_last_join(lex->thd)))
+ YYABORT;
+ }
+ ;
+
join_table_list:
- join_table { $$=$1; }
- | join_table_list ',' join_table_list { $$=$3; }
- | join_table_list normal_join join_table_list { $$=$3; }
- | join_table_list STRAIGHT_JOIN join_table_list
- { $$=$3 ; $1->next->straight=1; }
- | join_table_list normal_join join_table_list ON expr
- { add_join_on($3,$5); $$=$3; }
- | join_table_list normal_join join_table_list
+ derived_table_list { TEST_ASSERT($$=$1); }
+ ;
+
+/* Warning - may return NULL in case of incomplete SELECT */
+derived_table_list:
+ table_ref { $$=$1; }
+ | derived_table_list ',' table_ref
+ {
+ TEST_ASSERT($1 && ($$=$3));
+ }
+ ;
+
+join_table:
+ table_ref normal_join table_ref { TEST_ASSERT($1 && ($$=$3)); }
+ | table_ref STRAIGHT_JOIN table_factor
+ { TEST_ASSERT($1 && ($$=$3)); $3->straight=1; }
+ | table_ref normal_join table_ref ON expr
+ { TEST_ASSERT($1 && ($$=$3)); add_join_on($3,$5); }
+ | table_ref normal_join table_ref
USING
{
SELECT_LEX *sel= Select;
- sel->db1=$1->db; sel->table1=$1->alias;
- sel->db2=$3->db; sel->table2=$3->alias;
+ TEST_ASSERT($1 && $3);
+ sel->save_names_for_using_list($1, $3);
}
'(' using_list ')'
{ add_join_on($3,$7); $$=$3; }
- | join_table_list LEFT opt_outer JOIN_SYM join_table_list ON expr
- { add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
- | join_table_list LEFT opt_outer JOIN_SYM join_table_list
+ | table_ref LEFT opt_outer JOIN_SYM table_ref ON expr
+ { TEST_ASSERT($1 && $5); add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
+ | table_ref LEFT opt_outer JOIN_SYM table_factor
{
SELECT_LEX *sel= Select;
- sel->db1=$1->db; sel->table1=$1->alias;
- sel->db2=$5->db; sel->table2=$5->alias;
+ TEST_ASSERT($1 && $5);
+ sel->save_names_for_using_list($1, $5);
}
USING '(' using_list ')'
{ add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
- | join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table_list
+ | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
{
- add_join_natural($1,$1->next);
- $1->next->outer_join|=JOIN_TYPE_LEFT;
+ TEST_ASSERT($1 && $6);
+ add_join_natural($1,$6);
+ $6->outer_join|=JOIN_TYPE_LEFT;
$$=$6;
}
- | join_table_list RIGHT opt_outer JOIN_SYM join_table_list ON expr
- { add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; }
- | join_table_list RIGHT opt_outer JOIN_SYM join_table_list
+ | table_ref RIGHT opt_outer JOIN_SYM table_ref ON expr
+ {
+ LEX *lex= Lex;
+ TEST_ASSERT($1 && $5);
+ if (!($$= lex->current_select->convert_right_join()))
+ YYABORT;
+ add_join_on($$, $7);
+ }
+ | table_ref RIGHT opt_outer JOIN_SYM table_factor
{
SELECT_LEX *sel= Select;
- sel->db1=$1->db; sel->table1=$1->alias;
- sel->db2=$5->db; sel->table2=$5->alias;
+ TEST_ASSERT($1 && $5);
+ sel->save_names_for_using_list($1, $5);
}
USING '(' using_list ')'
- { add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; }
- | join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table_list
+ {
+ LEX *lex= Lex;
+ if (!($$= lex->current_select->convert_right_join()))
+ YYABORT;
+ add_join_on($$, $9);
+ }
+ | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
{
- add_join_natural($1->next,$1);
- $1->outer_join|=JOIN_TYPE_RIGHT;
- $$=$6;
+ TEST_ASSERT($1 && $6);
+ add_join_natural($6,$1);
+ LEX *lex= Lex;
+ if (!($$= lex->current_select->convert_right_join()))
+ YYABORT;
}
- | join_table_list NATURAL JOIN_SYM join_table_list
- { add_join_natural($1,$1->next); $$=$4; };
+ | table_ref NATURAL JOIN_SYM table_factor
+ { TEST_ASSERT($1 && ($$=$4)); add_join_natural($1,$4); };
+
normal_join:
JOIN_SYM {}
@@ -3465,7 +5123,8 @@ normal_join:
| CROSS JOIN_SYM {}
;
-join_table:
+/* Warning - may return NULL in case of incomplete SELECT */
+table_factor:
{
SELECT_LEX *sel= Select;
sel->use_index_ptr=sel->ignore_index_ptr=0;
@@ -3481,44 +5140,104 @@ join_table:
sel->get_use_index(),
sel->get_ignore_index())))
YYABORT;
+ sel->add_joined_table($$);
}
- | '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
- { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
- | '(' select_derived union_opt ')' opt_table_alias
+ | '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
+ { TEST_ASSERT($3 && $7); add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
+ | select_derived_init get_select_lex select_derived2
+ {
+ LEX *lex= Lex;
+ SELECT_LEX *sel= lex->current_select;
+ if ($1)
+ {
+ if (sel->set_braces(1))
+ {
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ }
+ /* select in braces, can't contain global parameters */
+ if (sel->master_unit()->fake_select_lex)
+ sel->master_unit()->global_parameters=
+ sel->master_unit()->fake_select_lex;
+ }
+ if ($2->init_nested_join(lex->thd))
+ YYABORT;
+ $$= 0;
+ /* incomplete derived tables return NULL, we must be
+ nested in select_derived rule to be here. */
+ }
+ | '(' get_select_lex select_derived union_opt ')' opt_table_alias
{
- LEX *lex=Lex;
- SELECT_LEX_UNIT *unit= lex->current_select->master_unit();
- lex->current_select= unit->outer_select();
- if (!($$= lex->current_select->
- add_table_to_list(lex->thd, new Table_ident(unit), $5, 0,
- TL_READ,(List<String> *)0,
- (List<String> *)0)))
+ /* Use $2 instead of Lex->current_select as derived table will
+ alter value of Lex->current_select. */
+
+ if (!($3 || $6) && $2->embedding &&
+ !$2->embedding->nested_join->join_list.elements)
+ {
+ /* we have a derived table ($3 == NULL) but no alias,
+ Since we are nested in further parentheses so we
+ can pass NULL to the outer level parentheses
+ Permits parsing of "((((select ...))) as xyz)" */
+ $$= 0;
+ }
+ else
+ if (!$3)
+ {
+ /* Handle case of derived table, alias may be NULL if there
+ are no outer parentheses, add_table_to_list() will throw
+ error in this case */
+ LEX *lex=Lex;
+ SELECT_LEX *sel= lex->current_select;
+ SELECT_LEX_UNIT *unit= sel->master_unit();
+ lex->current_select= sel= unit->outer_select();
+ if (!($$= sel->
+ add_table_to_list(lex->thd, new Table_ident(unit), $6, 0,
+ TL_READ,(List<String> *)0,
+ (List<String> *)0)))
+ YYABORT;
+ sel->add_joined_table($$);
+ }
+ else
+ if ($4 || $6)
+ {
+ /* simple nested joins cannot have aliases or unions */
+ yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
+ }
+ else
+ $$= $3;
}
- | '(' join_table_list ')' { $$=$2; };
+ ;
+/* handle contents of parentheses in join expression */
select_derived:
- SELECT_SYM select_derived2
- | '(' select_derived ')'
+ get_select_lex
{
- LEX *lex= Lex;
- SELECT_LEX * sel= lex->current_select;
- if (sel->set_braces(1))
- {
+ LEX *lex= Lex;
+ if ($1->init_nested_join(lex->thd))
+ YYABORT;
+ }
+ derived_table_list
+ {
+ LEX *lex= Lex;
+ /* for normal joins, $3 != NULL and end_nested_join() != NULL,
+ for derived tables, both must equal NULL */
+
+ if (!($$= $1->end_nested_join(lex->thd)) && $3)
+ YYABORT;
+ if (!$3 && $$)
+ {
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
- }
- /* select in braces, can't contain global parameters */
- if (sel->master_unit()->fake_select_lex)
- sel->master_unit()->global_parameters=
- sel->master_unit()->fake_select_lex;
- };
+ }
+ }
+ ;
select_derived2:
{
LEX *lex= Lex;
- lex->derived_tables= 1;
+ lex->derived_tables|= DERIVED_SUBQUERY;
if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
lex->sql_command <= (int)SQLCOM_HA_READ) ||
lex->sql_command == (int)SQLCOM_KILL)
@@ -3540,6 +5259,29 @@ select_derived2:
opt_select_from
;
+get_select_lex:
+ /* Empty */ { $$= Select; }
+ ;
+
+select_derived_init:
+ SELECT_SYM
+ {
+ LEX *lex= Lex;
+ SELECT_LEX *sel= lex->current_select;
+ TABLE_LIST *embedding;
+ if (!sel->embedding || sel->end_nested_join(lex->thd))
+ {
+ /* we are not in parentheses */
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ }
+ embedding= Select->embedding;
+ $$= embedding &&
+ !embedding->nested_join->join_list.elements;
+ /* return true if we are deeply nested */
+ }
+ ;
+
opt_outer:
/* empty */ {}
| OUTER {};
@@ -3609,23 +5351,29 @@ using_list:
};
interval:
- DAY_HOUR_SYM { $$=INTERVAL_DAY_HOUR; }
+ interval_time_st {}
+ | DAY_HOUR_SYM { $$=INTERVAL_DAY_HOUR; }
| DAY_MICROSECOND_SYM { $$=INTERVAL_DAY_MICROSECOND; }
| DAY_MINUTE_SYM { $$=INTERVAL_DAY_MINUTE; }
| DAY_SECOND_SYM { $$=INTERVAL_DAY_SECOND; }
- | DAY_SYM { $$=INTERVAL_DAY; }
| HOUR_MICROSECOND_SYM { $$=INTERVAL_HOUR_MICROSECOND; }
| HOUR_MINUTE_SYM { $$=INTERVAL_HOUR_MINUTE; }
| HOUR_SECOND_SYM { $$=INTERVAL_HOUR_SECOND; }
- | HOUR_SYM { $$=INTERVAL_HOUR; }
| MICROSECOND_SYM { $$=INTERVAL_MICROSECOND; }
| MINUTE_MICROSECOND_SYM { $$=INTERVAL_MINUTE_MICROSECOND; }
| MINUTE_SECOND_SYM { $$=INTERVAL_MINUTE_SECOND; }
+ | SECOND_MICROSECOND_SYM { $$=INTERVAL_SECOND_MICROSECOND; }
+ | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; };
+
+interval_time_st:
+ DAY_SYM { $$=INTERVAL_DAY; }
+ | WEEK_SYM { $$=INTERVAL_WEEK; }
+ | HOUR_SYM { $$=INTERVAL_HOUR; }
+ | FRAC_SECOND_SYM { $$=INTERVAL_MICROSECOND; }
| MINUTE_SYM { $$=INTERVAL_MINUTE; }
| MONTH_SYM { $$=INTERVAL_MONTH; }
- | SECOND_MICROSECOND_SYM { $$=INTERVAL_SECOND_MICROSECOND; }
+ | QUARTER_SYM { $$=INTERVAL_QUARTER; }
| SECOND_SYM { $$=INTERVAL_SECOND; }
- | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; }
| YEAR_SYM { $$=INTERVAL_YEAR; }
;
@@ -3686,8 +5434,11 @@ having_clause:
opt_escape:
ESCAPE_SYM simple_expr { $$= $2; }
| /* empty */
- {
- $$= new Item_string("\\", 1, &my_charset_latin1);
+ {
+
+ $$= ((YYTHD->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ?
+ new Item_string("", 0, &my_charset_latin1) :
+ new Item_string("\\", 1, &my_charset_latin1));
}
;
@@ -3713,12 +5464,12 @@ olap_opt:
LEX *lex=Lex;
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
- net_printf(lex->thd, ER_WRONG_USAGE, "WITH CUBE",
+ my_error(ER_WRONG_USAGE, MYF(0), "WITH CUBE",
"global union parameters");
YYABORT;
}
lex->current_select->olap= CUBE_TYPE;
- net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "CUBE");
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "CUBE");
YYABORT; /* To be deleted in 5.1 */
}
| WITH ROLLUP_SYM
@@ -3726,7 +5477,7 @@ olap_opt:
LEX *lex= Lex;
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
- net_printf(lex->thd, ER_WRONG_USAGE, "WITH ROLLUP",
+ my_error(ER_WRONG_USAGE, MYF(0), "WITH ROLLUP",
"global union parameters");
YYABORT;
}
@@ -3750,9 +5501,8 @@ order_clause:
lex->current_select->olap !=
UNSPECIFIED_OLAP_TYPE)
{
- net_printf(lex->thd, ER_WRONG_USAGE,
- "CUBE/ROLLUP",
- "ORDER BY");
+ my_error(ER_WRONG_USAGE, MYF(0),
+ "CUBE/ROLLUP", "ORDER BY");
YYABORT;
}
} order_list;
@@ -3790,21 +5540,21 @@ limit_clause:
;
limit_options:
- ULONG_NUM
+ ulong_num
{
SELECT_LEX *sel= Select;
sel->select_limit= $1;
sel->offset_limit= 0L;
sel->explicit_limit= 1;
}
- | ULONG_NUM ',' ULONG_NUM
+ | ulong_num ',' ulong_num
{
SELECT_LEX *sel= Select;
sel->select_limit= $3;
sel->offset_limit= $1;
sel->explicit_limit= 1;
}
- | ULONG_NUM OFFSET_SYM ULONG_NUM
+ | ulong_num OFFSET_SYM ulong_num
{
SELECT_LEX *sel= Select;
sel->select_limit= $1;
@@ -3827,11 +5577,12 @@ delete_limit_clause:
sel->explicit_limit= 1;
};
-ULONG_NUM:
- NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
+ulong_num:
+ NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
+ | HEX_NUM { int error; $$= (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); }
- | REAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
+ | DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
| FLOAT_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
;
@@ -3839,7 +5590,7 @@ ulonglong_num:
NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
- | REAL_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
+ | DECIMAL_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| FLOAT_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
;
@@ -3850,9 +5601,7 @@ procedure_clause:
LEX *lex=Lex;
if (&lex->select_lex != lex->current_select)
{
- net_printf(lex->thd, ER_WRONG_USAGE,
- "PROCEDURE",
- "subquery");
+ my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery");
YYABORT;
}
lex->proc_list.elements=0;
@@ -3900,11 +5649,32 @@ select_var_list:
| select_var_ident {}
;
-select_var_ident: '@' ident_or_text
+select_var_ident:
+ '@' ident_or_text
+ {
+ LEX *lex=Lex;
+ if (lex->result)
+ ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($2,0,0,(enum_field_types)0));
+ else
+ YYABORT;
+ }
+ | ident_or_text
{
LEX *lex=Lex;
- if (lex->result && ((select_dumpvar *)lex->result)->var_list.push_back((LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING))))
+ sp_pvar_t *t;
+
+ if (!lex->spcont || !(t=lex->spcont->find_pvar(&$1)))
+ {
+ my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
YYABORT;
+ }
+ if (! lex->result)
+ YYABORT;
+ else
+ {
+ ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($1,1,t->offset,t->type));
+ t->isset= TRUE;
+ }
}
;
@@ -3982,22 +5752,56 @@ drop:
lex->drop_if_exists=$3;
lex->name=$4.str;
}
- | DROP UDF_SYM IDENT_sys
+ | DROP FUNCTION_SYM if_exists sp_name
{
LEX *lex=Lex;
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
+ YYABORT;
+ }
lex->sql_command = SQLCOM_DROP_FUNCTION;
- lex->udf.name = $3;
+ lex->drop_if_exists= $3;
+ lex->spname= $4;
}
- | DROP USER
+ | DROP PROCEDURE if_exists sp_name
{
LEX *lex=Lex;
- lex->sql_command = SQLCOM_DROP_USER;
- lex->users_list.empty();
+ if (lex->sphead)
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
+ YYABORT;
+ }
+ lex->sql_command = SQLCOM_DROP_PROCEDURE;
+ lex->drop_if_exists= $3;
+ lex->spname= $4;
}
- user_list
- {}
- ;
+ | DROP USER clear_privileges user_list
+ {
+ Lex->sql_command = SQLCOM_DROP_USER;
+ }
+ | DROP VIEW_SYM if_exists table_list opt_restrict
+ {
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ lex->sql_command= SQLCOM_DROP_VIEW;
+ lex->drop_if_exists= $3;
+ }
+ | DROP TRIGGER_SYM ident '.' ident
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_DROP_TRIGGER;
+ /* QQ: Could we loosen lock type in certain cases ? */
+ if (!lex->select_lex.add_table_to_list(YYTHD,
+ new Table_ident($3),
+ (LEX_STRING*) 0,
+ TL_OPTION_UPDATING,
+ TL_WRITE))
+ YYABORT;
+ lex->ident= $5;
+ }
+ ;
table_list:
table_name
@@ -4029,8 +5833,8 @@ insert:
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_INSERT;
- lex->duplicates= DUP_ERROR;
- mysql_init_select(lex);
+ lex->duplicates= DUP_ERROR;
+ 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;
@@ -4050,7 +5854,7 @@ replace:
LEX *lex=Lex;
lex->sql_command = SQLCOM_REPLACE;
lex->duplicates= DUP_REPLACE;
- mysql_init_select(lex);
+ mysql_init_select(lex);
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
}
replace_lock_option insert2
@@ -4060,7 +5864,6 @@ replace:
}
insert_field_spec
{}
- {}
;
insert_lock_option:
@@ -4100,11 +5903,6 @@ insert_field_spec:
}
ident_eq_list;
-opt_field_spec:
- /* empty */ { }
- | '(' fields ')' { }
- | '(' ')' { };
-
fields:
fields ',' insert_ident { Lex->field_list.push_back($3); }
| insert_ident { Lex->field_list.push_back($1); };
@@ -4126,7 +5924,7 @@ ident_eq_list:
ident_eq_value;
ident_eq_value:
- simple_ident equal expr_or_default
+ simple_ident_nospvar equal expr_or_default
{
LEX *lex=Lex;
if (lex->field_list.push_back($1) ||
@@ -4200,19 +5998,20 @@ update:
{
LEX *lex= Lex;
if (lex->select_lex.table_list.elements > 1)
- {
lex->sql_command= SQLCOM_UPDATE_MULTI;
- lex->multi_lock_option= $3;
- }
else if (lex->select_lex.get_table_list()->derived)
{
/* it is single table update and it is update of derived table */
- net_printf(lex->thd, ER_NON_UPDATABLE_TABLE,
- lex->select_lex.get_table_list()->alias, "UPDATE");
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
+ lex->select_lex.get_table_list()->alias, "UPDATE");
YYABORT;
}
- else
- Select->set_lock_for_tables($3);
+ /*
+ In case of multi-update setting write lock for all tables may
+ be too pessimistic. We will decrease lock level if possible in
+ mysql_multi_update().
+ */
+ Select->set_lock_for_tables($3);
}
where_clause opt_order_clause delete_limit_clause {}
;
@@ -4222,7 +6021,7 @@ update_list:
| update_elem;
update_elem:
- simple_ident equal expr_or_default
+ simple_ident_nospvar equal expr_or_default
{
if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3))
YYABORT;
@@ -4233,13 +6032,13 @@ insert_update_list:
| insert_update_elem;
insert_update_elem:
- simple_ident equal expr_or_default
- {
+ simple_ident_nospvar equal expr_or_default
+ {
LEX *lex= Lex;
if (lex->update_list.push_back($1) ||
lex->value_list.push_back($3))
- YYABORT;
- };
+ YYABORT;
+ };
opt_low_priority:
/* empty */ { $$= YYTHD->update_lock_default; }
@@ -4252,7 +6051,7 @@ delete:
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_DELETE;
- mysql_init_select(lex);
+ mysql_init_select(lex);
lex->lock_option= lex->thd->update_lock_default;
lex->ignore= 0;
lex->select_lex.init_order();
@@ -4333,6 +6132,9 @@ show: SHOW
{
LEX *lex=Lex;
lex->wild=0;
+ lex->lock_option= TL_READ;
+ mysql_init_select(lex);
+ lex->current_select->parsing_place= SELECT_LIST;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
}
show_param
@@ -4340,42 +6142,58 @@ show: SHOW
;
show_param:
- DATABASES wild
- { Lex->sql_command= SQLCOM_SHOW_DATABASES; }
- | TABLES opt_db wild
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_TABLES;
- lex->select_lex.db= $2;
- }
- | TABLE_SYM STATUS_SYM opt_db wild
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_TABLES;
- lex->describe= DESCRIBE_EXTENDED;
- lex->select_lex.db= $3;
- }
- | OPEN_SYM TABLES opt_db wild
+ DATABASES wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_DATABASES;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_SCHEMATA))
+ YYABORT;
+ }
+ | opt_full TABLES opt_db wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_TABLES;
+ lex->select_lex.db= $3;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
+ YYABORT;
+ }
+ | TABLE_SYM STATUS_SYM opt_db wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_TABLE_STATUS;
+ lex->select_lex.db= $3;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLES))
+ YYABORT;
+ }
+ | OPEN_SYM TABLES opt_db wild_and_where
{
LEX *lex= Lex;
- lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_OPEN_TABLES;
lex->select_lex.db= $3;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_OPEN_TABLES))
+ YYABORT;
}
| ENGINE_SYM storage_engines
{ Lex->create_info.db_type= $2; }
show_engine_param
- | opt_full COLUMNS from_or_in table_ident opt_db wild
+ | opt_full COLUMNS from_or_in table_ident opt_db wild_and_where
{
- Lex->sql_command= SQLCOM_SHOW_FIELDS;
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_FIELDS;
if ($5)
$4->change_db($5);
- if (!Select->add_table_to_list(YYTHD, $4, NULL, 0))
+ if (prepare_schema_table(YYTHD, lex, $4, SCH_COLUMNS))
YYABORT;
}
| NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
TEXT_STRING_sys AND_SYM MASTER_LOG_POS_SYM EQ ulonglong_num
AND_SYM MASTER_SERVER_ID_SYM EQ
- ULONG_NUM
+ ulong_num
{
Lex->sql_command = SQLCOM_SHOW_NEW_MASTER;
Lex->mi.log_file_name = $8.str;
@@ -4395,13 +6213,15 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
} opt_limit_clause_init
- | keys_or_index from_or_in table_ident opt_db
- {
- Lex->sql_command= SQLCOM_SHOW_KEYS;
+ | keys_or_index from_or_in table_ident opt_db where_clause
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_KEYS;
if ($4)
$3->change_db($4);
- if (!Select->add_table_to_list(YYTHD, $3, NULL, 0))
- YYABORT;
+ if (prepare_schema_table(YYTHD, lex, $3, SCH_STATISTICS))
+ YYABORT;
}
| COLUMN_SYM TYPES_SYM
{
@@ -4432,22 +6252,46 @@ show_param:
{ Lex->sql_command = SQLCOM_SHOW_WARNS;}
| ERRORS opt_limit_clause_init
{ Lex->sql_command = SQLCOM_SHOW_ERRORS;}
- | STATUS_SYM wild
- { Lex->sql_command= SQLCOM_SHOW_STATUS; }
+ | opt_var_type STATUS_SYM wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_STATUS;
+ lex->option_type= (enum_var_type) $1;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_STATUS))
+ YYABORT;
+ }
| INNOBASE_SYM STATUS_SYM
{ Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS; WARN_DEPRECATED("SHOW INNODB STATUS", "SHOW ENGINE INNODB STATUS"); }
+ | MUTEX_SYM STATUS_SYM
+ { Lex->sql_command = SQLCOM_SHOW_MUTEX_STATUS; }
| opt_full PROCESSLIST_SYM
{ Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
- | opt_var_type VARIABLES wild
+ | opt_var_type VARIABLES wild_and_where
{
- THD *thd= YYTHD;
- thd->lex->sql_command= SQLCOM_SHOW_VARIABLES;
- thd->lex->option_type= (enum_var_type) $1;
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_VARIABLES;
+ lex->option_type= (enum_var_type) $1;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_VARIABLES))
+ YYABORT;
}
- | charset wild
- { Lex->sql_command= SQLCOM_SHOW_CHARSETS; }
- | COLLATION_SYM wild
- { Lex->sql_command= SQLCOM_SHOW_COLLATIONS; }
+ | charset wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_CHARSETS;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_CHARSETS))
+ YYABORT;
+ }
+ | COLLATION_SYM wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_COLLATIONS;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_COLLATIONS))
+ YYABORT;
+ }
| BERKELEY_DB_SYM LOGS_SYM
{ Lex->sql_command= SQLCOM_SHOW_LOGS; WARN_DEPRECATED("SHOW BDB LOGS", "SHOW ENGINE BDB LOGS"); }
| LOGS_SYM
@@ -4472,7 +6316,7 @@ show_param:
curr_user->host.str= (char *) "%";
curr_user->host.length= 1;
}
- curr_user->password.str=NullS;
+ curr_user->password=null_lex_str;
lex->grant_user= curr_user;
}
| GRANTS FOR_SYM user
@@ -4480,7 +6324,7 @@ show_param:
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_GRANTS;
lex->grant_user=$3;
- lex->grant_user->password.str=NullS;
+ lex->grant_user->password=null_lex_str;
}
| CREATE DATABASE opt_if_not_exists ident
{
@@ -4490,9 +6334,19 @@ show_param:
}
| CREATE TABLE_SYM table_ident
{
- Lex->sql_command = SQLCOM_SHOW_CREATE;
- if (!Select->add_table_to_list(YYTHD, $3, NULL,0))
+ LEX *lex= Lex;
+ lex->sql_command = SQLCOM_SHOW_CREATE;
+ if (!lex->select_lex.add_table_to_list(YYTHD, $3, NULL,0))
+ YYABORT;
+ lex->only_view= 0;
+ }
+ | CREATE VIEW_SYM table_ident
+ {
+ LEX *lex= Lex;
+ lex->sql_command = SQLCOM_SHOW_CREATE;
+ if (!lex->select_lex.add_table_to_list(YYTHD, $3, NULL, 0))
YYABORT;
+ lex->only_view= 1;
}
| MASTER_SYM STATUS_SYM
{
@@ -4501,7 +6355,41 @@ show_param:
| SLAVE STATUS_SYM
{
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- };
+ }
+ | CREATE PROCEDURE sp_name
+ {
+ LEX *lex= Lex;
+
+ lex->sql_command = SQLCOM_SHOW_CREATE_PROC;
+ lex->spname= $3;
+ }
+ | CREATE FUNCTION_SYM sp_name
+ {
+ LEX *lex= Lex;
+
+ lex->sql_command = SQLCOM_SHOW_CREATE_FUNC;
+ lex->spname= $3;
+ }
+ | PROCEDURE STATUS_SYM wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_STATUS_PROC;
+ if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
+ YYABORT;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
+ YYABORT;
+ }
+ | FUNCTION_SYM STATUS_SYM wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_STATUS_FUNC;
+ if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
+ YYABORT;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
+ YYABORT;
+ };
show_engine_param:
STATUS_SYM
@@ -4511,7 +6399,7 @@ show_engine_param:
Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS;
break;
default:
- net_printf(YYTHD, ER_NOT_SUPPORTED_YET, "STATUS");
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "STATUS");
YYABORT;
}
}
@@ -4522,7 +6410,7 @@ show_engine_param:
Lex->sql_command = SQLCOM_SHOW_LOGS;
break;
default:
- net_printf(YYTHD, ER_NOT_SUPPORTED_YET, "LOGS");
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "LOGS");
YYABORT;
}
};
@@ -4539,12 +6427,6 @@ opt_db:
/* empty */ { $$= 0; }
| from_or_in ident { $$= $2.str; };
-wild:
- /* empty */
- | LIKE TEXT_STRING_sys
- { Lex->wild= new (YYTHD->mem_root) String($2.str, $2.length,
- system_charset_info); };
-
opt_full:
/* empty */ { Lex->verbose=0; }
| FULL { Lex->verbose=1; };
@@ -4561,16 +6443,33 @@ binlog_from:
/* empty */ { Lex->mi.pos = 4; /* skip magic number */ }
| FROM ulonglong_num { Lex->mi.pos = $2; };
+wild_and_where:
+ /* empty */
+ | LIKE TEXT_STRING_sys
+ { Lex->wild= new (YYTHD->mem_root) String($2.str, $2.length,
+ system_charset_info); }
+ | WHERE expr
+ {
+ Select->where= $2;
+ if ($2)
+ $2->top_level_item();
+ }
+ ;
+
/* A Oracle compatible synonym for show */
describe:
describe_command table_ident
{
- LEX *lex=Lex;
- lex->wild=0;
- lex->verbose=0;
- lex->sql_command=SQLCOM_SHOW_FIELDS;
- if (!Select->add_table_to_list(lex->thd, $2, NULL,0))
+ LEX *lex= Lex;
+ lex->lock_option= TL_READ;
+ mysql_init_select(lex);
+ lex->current_select->parsing_place= SELECT_LIST;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_FIELDS;
+ lex->select_lex.db= 0;
+ lex->verbose= 0;
+ if (prepare_schema_table(YYTHD, lex, $2, SCH_COLUMNS))
YYABORT;
}
opt_describe_column {}
@@ -4672,37 +6571,29 @@ purge_option:
}
| BEFORE_SYM expr
{
- if ($2->check_cols(1) || $2->fix_fields(Lex->thd, 0, &$2))
- {
- net_printf(Lex->thd, ER_WRONG_ARGUMENTS, "PURGE LOGS BEFORE");
- YYABORT;
- }
- Item *tmp= new Item_func_unix_timestamp($2);
- /*
- it is OK only emulate fix_fieds, because we need only
- value of constant
- */
- tmp->quick_fix_field();
- Lex->sql_command = SQLCOM_PURGE_BEFORE;
- Lex->purge_time= (ulong) tmp->val_int();
+ LEX *lex= Lex;
+ lex->value_list.empty();
+ lex->value_list.push_front($2);
+ lex->sql_command= SQLCOM_PURGE_BEFORE;
}
;
/* kill threads */
kill:
- KILL_SYM expr
+ KILL_SYM kill_option expr
{
LEX *lex=Lex;
- if ($2->fix_fields(lex->thd, 0, &$2) || $2->check_cols(1))
- {
- send_error(lex->thd, ER_SET_CONSTANTS_ONLY);
- YYABORT;
- }
- lex->sql_command=SQLCOM_KILL;
- lex->thread_id= (ulong) $2->val_int();
+ lex->value_list.empty();
+ lex->value_list.push_front($3);
+ lex->sql_command= SQLCOM_KILL;
};
+kill_option:
+ /* empty */ { Lex->type= 0; }
+ | CONNECTION_SYM { Lex->type= 0; }
+ | QUERY_SYM { Lex->type= ONLY_KILL_QUERY; };
+
/* change database */
use: USE_SYM ident
@@ -4714,34 +6605,53 @@ use: USE_SYM ident
/* import, export of files */
-load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING_sys
+load: LOAD DATA_SYM
+ {
+ LEX *lex=Lex;
+ lex->fname_start= lex->ptr;
+ }
+ load_data
+ {}
+ |
+ LOAD TABLE_SYM table_ident FROM MASTER_SYM
+ {
+ Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
+ if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
+ YYABORT;
+ };
+
+load_data:
+ load_data_lock opt_local INFILE TEXT_STRING_sys
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_LOAD;
- lex->lock_option= $3;
- lex->local_file= $4;
+ lex->lock_option= $1;
+ lex->local_file= $2;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
- if (!(lex->exchange= new sql_exchange($6.str,0)))
- YYABORT;
- lex->field_list.empty();
- }
- opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term
- opt_ignore_lines opt_field_spec
- {
- if (!Select->add_table_to_list(YYTHD, $11, NULL, TL_OPTION_UPDATING))
+ if (!(lex->exchange= new sql_exchange($4.str, 0)))
YYABORT;
+ }
+ opt_duplicate INTO
+ {
+ LEX *lex=Lex;
+ lex->fname_end= lex->ptr;
}
- |
- LOAD TABLE_SYM table_ident FROM MASTER_SYM
+ TABLE_SYM table_ident
{
- Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
- if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
- YYABORT;
-
+ LEX *lex=Lex;
+ if (!Select->add_table_to_list(YYTHD, $10, NULL, TL_OPTION_UPDATING,
+ lex->lock_option))
+ YYABORT;
+ lex->field_list.empty();
+ lex->update_list.empty();
+ lex->value_list.empty();
}
+ opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
+ opt_load_data_set_spec
+ {}
|
- LOAD DATA_SYM FROM MASTER_SYM
+ FROM MASTER_SYM
{
Lex->sql_command = SQLCOM_LOAD_MASTER_DATA;
};
@@ -4772,24 +6682,24 @@ field_term_list:
field_term:
TERMINATED BY text_string
{
- DBUG_ASSERT(Lex->exchange);
+ DBUG_ASSERT(Lex->exchange != 0);
Lex->exchange->field_term= $3;
}
| OPTIONALLY ENCLOSED BY text_string
{
LEX *lex= Lex;
- DBUG_ASSERT(lex->exchange);
+ DBUG_ASSERT(lex->exchange != 0);
lex->exchange->enclosed= $4;
lex->exchange->opt_enclosed= 1;
}
| ENCLOSED BY text_string
{
- DBUG_ASSERT(Lex->exchange);
+ DBUG_ASSERT(Lex->exchange != 0);
Lex->exchange->enclosed= $3;
}
| ESCAPED BY text_string
{
- DBUG_ASSERT(Lex->exchange);
+ DBUG_ASSERT(Lex->exchange != 0);
Lex->exchange->escaped= $3;
};
@@ -4804,12 +6714,12 @@ line_term_list:
line_term:
TERMINATED BY text_string
{
- DBUG_ASSERT(Lex->exchange);
+ DBUG_ASSERT(Lex->exchange != 0);
Lex->exchange->line_term= $3;
}
| STARTING BY text_string
{
- DBUG_ASSERT(Lex->exchange);
+ DBUG_ASSERT(Lex->exchange != 0);
Lex->exchange->line_start= $3;
};
@@ -4817,10 +6727,33 @@ opt_ignore_lines:
/* empty */
| IGNORE_SYM NUM LINES
{
- DBUG_ASSERT(Lex->exchange);
+ DBUG_ASSERT(Lex->exchange != 0);
Lex->exchange->skip_lines= atol($2.str);
};
+opt_field_or_var_spec:
+ /* empty */ { }
+ | '(' fields_or_vars ')' { }
+ | '(' ')' { };
+
+fields_or_vars:
+ fields_or_vars ',' field_or_var
+ { Lex->field_list.push_back($3); }
+ | field_or_var
+ { Lex->field_list.push_back($1); }
+ ;
+
+field_or_var:
+ simple_ident_nospvar {$$= $1;}
+ | '@' ident_or_text
+ { $$= new Item_user_var_as_out_param($2); }
+ ;
+
+opt_load_data_set_spec:
+ /* empty */ { }
+ | SET insert_update_list { };
+
+
/* Common definitions */
text_literal:
@@ -4842,15 +6775,25 @@ text_string:
{ $$= new (YYTHD->mem_root) String($1.str,$1.length,YYTHD->variables.collation_connection); }
| HEX_NUM
{
- Item *tmp = new Item_varbinary($1.str,$1.length);
+ Item *tmp= new Item_hex_string($1.str, $1.length);
/*
- it is OK only emulate fix_fieds, because we need only
+ it is OK only emulate fix_fields, because we need only
value of constant
*/
$$= tmp ?
tmp->quick_fix_field(), tmp->val_str((String*) 0) :
(String*) 0;
}
+ | BIN_NUM
+ {
+ Item *tmp= new Item_bin_string($1.str, $1.length);
+ /*
+ it is OK only emulate fix_fields, because we need only
+ value of constant
+ */
+ $$= tmp ? tmp->quick_fix_field(), tmp->val_str((String*) 0) :
+ (String*) 0;
+ }
;
param_marker:
@@ -4864,7 +6807,7 @@ param_marker:
(uchar *) thd->query));
if (!($$= item) || lex->param_list.push_back(item))
{
- send_error(thd, ER_OUT_OF_RESOURCES);
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
YYABORT;
}
}
@@ -4892,10 +6835,11 @@ literal:
| NUM_literal { $$ = $1; }
| NULL_SYM { $$ = new Item_null();
Lex->next_state=MY_LEX_OPERATOR_OR_IDENT;}
- | HEX_NUM { $$ = new Item_varbinary($1.str,$1.length);}
+ | HEX_NUM { $$ = new Item_hex_string($1.str, $1.length);}
+ | BIN_NUM { $$= new Item_bin_string($1.str, $1.length); }
| UNDERSCORE_CHARSET HEX_NUM
{
- Item *tmp= new Item_varbinary($2.str,$2.length);
+ Item *tmp= new Item_hex_string($2.str, $2.length);
/*
it is OK only emulate fix_fieds, because we need only
value of constant
@@ -4907,6 +6851,20 @@ literal:
str ? str->length() : 0,
Lex->charset);
}
+ | UNDERSCORE_CHARSET BIN_NUM
+ {
+ Item *tmp= new Item_bin_string($2.str, $2.length);
+ /*
+ it is OK only emulate fix_fieds, because we need only
+ value of constant
+ */
+ String *str= tmp ?
+ tmp->quick_fix_field(), tmp->val_str((String*) 0) :
+ (String*) 0;
+ $$= new Item_string(str ? str->ptr() : "",
+ str ? str->length() : 0,
+ Lex->charset);
+ }
| DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; }
| TIMESTAMP text_literal { $$ = $2; };
@@ -4915,16 +6873,30 @@ NUM_literal:
NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); }
| LONG_NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); }
| ULONGLONG_NUM { $$ = new Item_uint($1.str, $1.length); }
- | REAL_NUM { $$ = new Item_real($1.str, $1.length); }
- | FLOAT_NUM { $$ = new Item_float($1.str, $1.length); }
+ | DECIMAL_NUM
+ {
+ $$= new Item_decimal($1.str, $1.length, YYTHD->charset());
+ if (YYTHD->net.report_error)
+ {
+ YYABORT;
+ }
+ }
+ | FLOAT_NUM
+ {
+ $$ = new Item_float($1.str, $1.length);
+ if (YYTHD->net.report_error)
+ {
+ YYABORT;
+ }
+ }
;
-
+
/**********************************************************************
-** Createing different items.
+** Creating different items.
**********************************************************************/
insert_ident:
- simple_ident { $$=$1; }
+ simple_ident_nospvar { $$=$1; }
| table_wild { $$=$1; };
table_wild:
@@ -4936,8 +6908,8 @@ table_wild:
| ident '.' ident '.' '*'
{
$$ = new Item_field((YYTHD->client_capabilities &
- CLIENT_NO_SCHEMA ? NullS : $1.str),
- $3.str,"*");
+ CLIENT_NO_SCHEMA ? NullS : $1.str),
+ $3.str,"*");
Lex->current_select->with_wild++;
}
;
@@ -4948,28 +6920,101 @@ order_ident:
simple_ident:
ident
{
+ sp_pvar_t *spv;
+ LEX *lex = Lex;
+ sp_pcontext *spc = lex->spcont;
+
+ if (spc && (spv = spc->find_pvar(&$1)))
+ { /* We're compiling a stored procedure and found a variable */
+ $$ = (Item*) new Item_splocal($1, spv->offset);
+ lex->variables_used= 1;
+ lex->safe_to_cache_query=0;
+ }
+ else
+ {
+ 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);
+ }
+ }
+ | simple_ident_q { $$= $1; }
+ ;
+
+simple_ident_nospvar:
+ 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_ref(NullS,NullS,$1.str);
}
- | ident '.' ident
+ | simple_ident_q { $$= $1; }
+ ;
+
+simple_ident_q:
+ ident '.' ident
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
- SELECT_LEX *sel= lex->current_select;
- if (sel->no_table_names_allowed)
- {
- my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
- ER(ER_TABLENAME_NOT_ALLOWED_HERE),
- MYF(0), $1.str, thd->where);
- }
- $$= (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);
- }
+
+ /*
+ FIXME This will work ok in simple_ident_nospvar case because
+ we can't meet simple_ident_nospvar in trigger now. But it
+ should be changed in future.
+ */
+ if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
+ (!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
+ !my_strcasecmp(system_charset_info, $1.str, "OLD")))
+ {
+ Item_trigger_field *trg_fld;
+ bool new_row= ($1.str[0]=='N' || $1.str[0]=='n');
+
+ if (lex->trg_chistics.event == TRG_EVENT_INSERT &&
+ !new_row)
+ {
+ my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT");
+ YYABORT;
+ }
+
+ if (lex->trg_chistics.event == TRG_EVENT_DELETE &&
+ new_row)
+ {
+ my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE");
+ YYABORT;
+ }
+
+ if (!(trg_fld= new Item_trigger_field(new_row ?
+ Item_trigger_field::NEW_ROW:
+ Item_trigger_field::OLD_ROW,
+ $3.str)))
+ YYABORT;
+
+ /*
+ Let us add this item to list of all Item_trigger_field objects
+ in trigger.
+ */
+ lex->trg_table_fields.link_in_list((byte *)trg_fld,
+ (byte**)&trg_fld->next_trg_field);
+
+ $$= (Item *)trg_fld;
+ }
+ else
+ {
+ SELECT_LEX *sel= lex->current_select;
+ if (sel->no_table_names_allowed)
+ {
+ my_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ MYF(0), $1.str, thd->where);
+ }
+ $$= (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);
+ }
+ }
| '.' ident '.' ident
{
THD *thd= YYTHD;
@@ -4977,9 +7022,8 @@ simple_ident:
SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
- my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
- ER(ER_TABLENAME_NOT_ALLOWED_HERE),
- MYF(0), $2.str, thd->where);
+ my_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ MYF(0), $2.str, thd->where);
}
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
@@ -4993,9 +7037,8 @@ simple_ident:
SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
- my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
- ER(ER_TABLENAME_NOT_ALLOWED_HERE),
- MYF(0), $3.str, thd->where);
+ my_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ MYF(0), $3.str, thd->where);
}
$$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
@@ -5037,8 +7080,8 @@ IDENT_sys:
$1.length, &dummy_error);
if (wlen < $1.length)
{
- net_printf(YYTHD, ER_INVALID_CHARACTER_STRING, cs->csname,
- $1.str + wlen);
+ my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
+ cs->csname, $1.str + wlen);
YYABORT;
}
$$= $1;
@@ -5085,7 +7128,7 @@ ident:
;
ident_or_text:
- ident { $$=$1;}
+ ident { $$=$1;}
| TEXT_STRING_sys { $$=$1;}
| LEX_HOSTNAME { $$=$1;};
@@ -5133,6 +7176,7 @@ keyword:
| AFTER_SYM {}
| AGAINST {}
| AGGREGATE_SYM {}
+ | ALGORITHM_SYM {}
| ANY_SYM {}
| ASCII_SYM {}
| AUTO_INC {}
@@ -5148,6 +7192,8 @@ keyword:
| BYTE_SYM {}
| BTREE_SYM {}
| CACHE_SYM {}
+ | CASCADED {}
+ | CHAIN_SYM {}
| CHANGED {}
| CHARSET {}
| CHECKSUM_SYM {}
@@ -5155,18 +7201,22 @@ keyword:
| 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 {}
@@ -5186,6 +7236,7 @@ keyword:
| EXPANSION_SYM {}
| EXTENDED_SYM {}
| FAST_SYM {}
+ | FOUND_SYM {}
| DISABLE_SYM {}
| ENABLE_SYM {}
| FULL {}
@@ -5193,6 +7244,7 @@ keyword:
| FIRST_SYM {}
| FIXED_SYM {}
| FLUSH_SYM {}
+ | FRAC_SECOND_SYM {}
| GEOMETRY_SYM {}
| GEOMETRYCOLLECTION {}
| GET_FORMAT {}
@@ -5204,6 +7256,7 @@ keyword:
| HOSTS_SYM {}
| HOUR_SYM {}
| IDENTIFIED_SYM {}
+ | INVOKER_SYM {}
| IMPORT {}
| INDEXES {}
| ISOLATION {}
@@ -5211,6 +7264,8 @@ keyword:
| INNOBASE_SYM {}
| INSERT_METHOD {}
| RELAY_THREAD {}
+ | LABEL_SYM {}
+ | LANGUAGE_SYM {}
| LAST_SYM {}
| LEAVES {}
| LEVEL_SYM {}
@@ -5237,8 +7292,11 @@ keyword:
| MAX_CONNECTIONS_PER_HOUR {}
| MAX_QUERIES_PER_HOUR {}
| MAX_UPDATES_PER_HOUR {}
+ | MAX_USER_CONNECTIONS_SYM {}
| MEDIUM_SYM {}
+ | MERGE_SYM {}
| MICROSECOND_SYM {}
+ | MIGRATE_SYM {}
| MINUTE_SYM {}
| MIN_ROWS {}
| MODIFY_SYM {}
@@ -5247,6 +7305,8 @@ keyword:
| MULTILINESTRING {}
| MULTIPOINT {}
| MULTIPOLYGON {}
+ | MUTEX_SYM {}
+ | NAME_SYM {}
| NAMES_SYM {}
| NATIONAL_SYM {}
| NCHAR_SYM {}
@@ -5259,16 +7319,20 @@ keyword:
| 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 {}
| PROCESSLIST_SYM {}
+ | QUARTER_SYM {}
| QUERY_SYM {}
| QUICK {}
| RAID_0_SYM {}
@@ -5276,6 +7340,8 @@ keyword:
| RAID_CHUNKSIZE {}
| RAID_STRIPED_SYM {}
| RAID_TYPE {}
+ | RECOVER_SYM {}
+ | REDUNDANT_SYM {}
| RELAY_LOG_FILE_SYM {}
| RELAY_LOG_POS_SYM {}
| RELOAD {}
@@ -5285,14 +7351,18 @@ keyword:
| 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 {}
@@ -5315,27 +7385,37 @@ keyword:
| SUBDATE_SYM {}
| SUBJECT_SYM {}
| SUPER_SYM {}
+ | SUSPEND_SYM {}
+ | TABLES {}
| TABLESPACE {}
| TEMPORARY {}
+ | TEMPTABLE_SYM {}
| TEXT_SYM {}
| TRANSACTION_SYM {}
| TRUNCATE_SYM {}
| TIMESTAMP {}
+ | TIMESTAMP_ADD {}
+ | TIMESTAMP_DIFF {}
| TIME_SYM {}
- | TYPE_SYM {}
| TYPES_SYM {}
+ | TYPE_SYM {}
| UDF_RETURNS_SYM {}
- | UDF_SYM {}
+ | FUNCTION_SYM {}
| UNCOMMITTED_SYM {}
+ | UNDEFINED_SYM {}
| UNICODE_SYM {}
+ | UNKNOWN_SYM {}
| UNTIL_SYM {}
| USER {}
| USE_FRM {}
| VARIABLES {}
+ | VIEW_SYM {}
| VALUE_SYM {}
| WARNINGS {}
+ | WEEK_SYM {}
| WORK_SYM {}
| X509_SYM {}
+ | XA_SYM {}
| YEAR_SYM {}
;
@@ -5346,7 +7426,7 @@ set:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_SET_OPTION;
- mysql_init_select(lex);
+ mysql_init_select(lex);
lex->option_type=OPT_SESSION;
lex->var_list.empty();
lex->one_shot_set= 0;
@@ -5360,26 +7440,84 @@ opt_option:
| OPTION {};
option_value_list:
- option_value_ext
- | option_value_list ',' option_value_ext;
+ option_type_value
+ | option_value_list ',' option_type_value;
-option_value_ext:
- option_type_ext sys_option_value {}
- | option_type option_value {}
- ;
+option_type_value:
+ {
+ if (Lex->sphead)
+ {
+ /*
+ If we are in SP we want have own LEX for each assignment.
+ This is mostly because it is hard for several sp_instr_set
+ and sp_instr_set_trigger instructions share one LEX.
+ (Well, it is theoretically possible but adds some extra
+ overhead on preparation for execution stage and IMO less
+ robust).
+
+ QQ: May be we should simply prohibit group assignments in SP?
+ */
+ LEX *lex;
+ Lex->sphead->reset_lex(YYTHD);
+ lex= Lex;
+
+ /* Set new LEX as if we at start of set rule. */
+ lex->sql_command= SQLCOM_SET_OPTION;
+ mysql_init_select(lex);
+ lex->option_type=OPT_SESSION;
+ lex->var_list.empty();
+ lex->one_shot_set= 0;
+ lex->sphead->m_tmp_query= lex->tok_start;
+ }
+ }
+ option_type option_value
+ {
+ LEX *lex= Lex;
+
+ if (lex->sphead)
+ {
+ sp_head *sp= lex->sphead;
+
+ if (!lex->var_list.is_empty())
+ {
+ /*
+ We have assignment to user or system variable or
+ option setting, so we should construct sp_instr_stmt
+ for it.
+ */
+ LEX_STRING qbuff;
+ sp_instr_stmt *i;
+
+ if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont,
+ lex)))
+ YYABORT;
+
+ if (lex->ptr - lex->tok_end > 1)
+ qbuff.length= lex->ptr - sp->m_tmp_query;
+ else
+ qbuff.length= lex->tok_end - sp->m_tmp_query;
+
+ if (!(qbuff.str= alloc_root(YYTHD->mem_root, qbuff.length + 5)))
+ YYABORT;
+
+ strmake(strmake(qbuff.str, "SET ", 4), (char *)sp->m_tmp_query,
+ qbuff.length);
+ qbuff.length+= 4;
+ i->m_query= qbuff;
+ sp->add_instr(i);
+ }
+ lex->sphead->restore_lex(YYTHD);
+ }
+ };
-option_type_ext:
- option_type {}
+option_type:
+ /* empty */ {}
| GLOBAL_SYM { Lex->option_type= OPT_GLOBAL; }
| LOCAL_SYM { Lex->option_type= OPT_SESSION; }
| SESSION_SYM { Lex->option_type= OPT_SESSION; }
+ | ONE_SHOT_SYM { Lex->option_type= OPT_SESSION; Lex->one_shot_set= 1; }
;
-option_type:
- /* empty */ {}
- | ONE_SHOT_SYM { Lex->option_type= OPT_SESSION; Lex->one_shot_set= 1; }
- ;
-
opt_var_type:
/* empty */ { $$=OPT_SESSION; }
| GLOBAL_SYM { $$=OPT_GLOBAL; }
@@ -5394,37 +7532,89 @@ opt_var_ident_type:
| SESSION_SYM '.' { $$=OPT_SESSION; }
;
-sys_option_value:
- internal_variable_name equal set_expr_or_default
- {
- LEX *lex=Lex;
- lex->var_list.push_back(new set_var(lex->option_type, $1.var,
- &$1.base_name, $3));
- }
- | TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types
- {
- LEX *lex=Lex;
- LEX_STRING tmp;
- tmp.str=0;
- tmp.length=0;
- lex->var_list.push_back(new set_var(lex->option_type,
- find_sys_var("tx_isolation"),
- &tmp,
- new Item_int((int32) $4)));
- }
- ;
-
option_value:
- '@' ident_or_text equal expr
- {
- Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
- }
+ '@' ident_or_text equal expr
+ {
+ Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
+ }
+ | internal_variable_name equal set_expr_or_default
+ {
+ LEX *lex=Lex;
+
+ if ($1.var == &trg_new_row_fake_var)
+ {
+ /* We are in trigger and assigning value to field of new row */
+ Item *it;
+ sp_instr_set_trigger_field *i;
+ if (lex->query_tables)
+ {
+ my_message(ER_SP_SUBSELECT_NYI, ER(ER_SP_SUBSELECT_NYI),
+ MYF(0));
+ YYABORT;
+ }
+ if ($3)
+ it= $3;
+ else
+ {
+ /* QQ: Shouldn't this be field's default value ? */
+ it= new Item_null();
+ }
+
+ if (!(i= new sp_instr_set_trigger_field(
+ lex->sphead->instructions(), lex->spcont,
+ $1.base_name, it)))
+ YYABORT;
+
+ /*
+ Let us add this item to list of all Item_trigger_field
+ objects in trigger.
+ */
+ lex->trg_table_fields.link_in_list((byte *)&i->trigger_field,
+ (byte **)&i->trigger_field.next_trg_field);
+
+ lex->sphead->add_instr(i);
+ }
+ else if ($1.var)
+ { /* System variable */
+ lex->var_list.push_back(new set_var(lex->option_type, $1.var,
+ &$1.base_name, $3));
+ }
+ else
+ {
+ /* An SP local variable */
+ sp_pcontext *ctx= lex->spcont;
+ sp_pvar_t *spv;
+ sp_instr_set *i;
+ Item *it;
+
+ spv= ctx->find_pvar(&$1.base_name);
+
+ if ($3)
+ it= $3;
+ else if (spv->dflt)
+ it= spv->dflt;
+ else
+ it= new Item_null();
+ i= new sp_instr_set(lex->sphead->instructions(), ctx,
+ spv->offset, it, spv->type, lex, TRUE);
+ lex->sphead->add_instr(i);
+ spv->isset= TRUE;
+ }
+ }
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
- {
- LEX *lex=Lex;
- lex->var_list.push_back(new set_var((enum_var_type) $3, $4.var,
- &$4.base_name, $6));
- }
+ {
+ LEX *lex=Lex;
+ lex->var_list.push_back(new set_var((enum_var_type) $3, $4.var,
+ &$4.base_name, $6));
+ }
+ | TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types
+ {
+ LEX *lex=Lex;
+ lex->var_list.push_back(new set_var(lex->option_type,
+ find_sys_var("tx_isolation"),
+ &null_lex_str,
+ new Item_int((int32) $4)));
+ }
| charset old_or_new_charset_name_or_default
{
THD *thd= YYTHD;
@@ -5434,13 +7624,13 @@ option_value:
}
| NAMES_SYM charset_name_or_default opt_collate
{
- THD *thd= YYTHD;
LEX *lex= Lex;
$2= $2 ? $2 : global_system_variables.character_set_client;
$3= $3 ? $3 : $2;
if (!my_charset_same($2,$3))
{
- net_printf(thd,ER_COLLATION_CHARSET_MISMATCH,$3->name,$2->csname);
+ my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
+ $3->name, $2->csname);
YYABORT;
}
lex->var_list.push_back(new set_var_collation_client($3,$3,$3));
@@ -5451,7 +7641,7 @@ option_value:
LEX_USER *user;
if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
YYABORT;
- user->host.str=0;
+ user->host=null_lex_str;
user->user.str=thd->priv_user;
thd->lex->var_list.push_back(new set_var_password(user, $3));
}
@@ -5464,33 +7654,76 @@ option_value:
internal_variable_name:
ident
{
- sys_var *tmp=find_sys_var($1.str, $1.length);
- if (!tmp)
- YYABORT;
- $$.var= tmp;
- $$.base_name.str=0;
- $$.base_name.length=0;
- /*
- If this is time_zone variable we should open time zone
- describing tables
- */
- if (tmp == &sys_time_zone)
- Lex->time_zone_tables_used= &fake_time_zone_tables_list;
+ LEX *lex= Lex;
+ sp_pcontext *spc= lex->spcont;
+ sp_pvar_t *spv;
+
+ /* We have to lookup here since local vars can shadow sysvars */
+ if (!spc || !(spv = spc->find_pvar(&$1)))
+ {
+ /* Not an SP local variable */
+ sys_var *tmp=find_sys_var($1.str, $1.length);
+ if (!tmp)
+ YYABORT;
+ $$.var= tmp;
+ $$.base_name= null_lex_str;
+ /*
+ If this is time_zone variable we should open time zone
+ describing tables
+ */
+ if (tmp == &sys_time_zone &&
+ lex->add_time_zone_tables_to_query_tables(YYTHD))
+ YYABORT;
+ }
+ else
+ {
+ /* An SP local variable */
+ $$.var= NULL;
+ $$.base_name= $1;
+ }
}
| ident '.' ident
{
+ LEX *lex= Lex;
if (check_reserved_words(&$1))
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
- sys_var *tmp=find_sys_var($3.str, $3.length);
- if (!tmp)
- YYABORT;
- if (!tmp->is_struct())
- net_printf(YYTHD, ER_VARIABLE_IS_NOT_STRUCT, $3.str);
- $$.var= tmp;
- $$.base_name= $1;
+ if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
+ (!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
+ !my_strcasecmp(system_charset_info, $1.str, "OLD")))
+ {
+ if ($1.str[0]=='O' || $1.str[0]=='o')
+ {
+ my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", "");
+ YYABORT;
+ }
+ if (lex->trg_chistics.event == TRG_EVENT_DELETE)
+ {
+ my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0),
+ "NEW", "on DELETE");
+ YYABORT;
+ }
+ if (lex->trg_chistics.action_time == TRG_ACTION_AFTER)
+ {
+ my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after ");
+ YYABORT;
+ }
+ /* This special combination will denote field of NEW row */
+ $$.var= &trg_new_row_fake_var;
+ $$.base_name= $3;
+ }
+ else
+ {
+ sys_var *tmp=find_sys_var($3.str, $3.length);
+ if (!tmp)
+ YYABORT;
+ if (!tmp->is_struct())
+ my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
+ $$.var= tmp;
+ $$.base_name= $1;
+ }
}
| DEFAULT '.' ident
{
@@ -5498,7 +7731,7 @@ internal_variable_name:
if (!tmp)
YYABORT;
if (!tmp->is_struct())
- net_printf(YYTHD, ER_VARIABLE_IS_NOT_STRUCT, $3.str);
+ my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
$$.var= tmp;
$$.base_name.str= (char*) "default";
$$.base_name.length= 7;
@@ -5543,7 +7776,14 @@ set_expr_or_default:
lock:
LOCK_SYM table_or_tables
{
- Lex->sql_command=SQLCOM_LOCK_TABLES;
+ LEX *lex= Lex;
+
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "LOCK");
+ YYABORT;
+ }
+ lex->sql_command= SQLCOM_LOCK_TABLES;
}
table_lock_list
{}
@@ -5573,7 +7813,19 @@ lock_option:
;
unlock:
- UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }
+ UNLOCK_SYM
+ {
+ LEX *lex= Lex;
+
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "UNLOCK");
+ YYABORT;
+ }
+ lex->sql_command= SQLCOM_UNLOCK_TABLES;
+ }
+ table_or_tables
+ {}
;
@@ -5610,8 +7862,8 @@ handler:
;
handler_read_or_scan:
- handler_scan_function { Lex->backup_dir= 0; }
- | ident handler_rkey_function { Lex->backup_dir= $1.str; }
+ handler_scan_function { Lex->ident= null_lex_str; }
+ | ident handler_rkey_function { Lex->ident= $1; }
;
handler_scan_function:
@@ -5645,53 +7897,35 @@ handler_rkey_mode:
/* GRANT / REVOKE */
revoke:
- REVOKE
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_REVOKE;
- lex->users_list.empty();
- lex->columns.empty();
- lex->grant= lex->grant_tot_col=0;
- lex->select_lex.db=0;
- lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
- lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
- bzero((char*) &lex->mqh, sizeof(lex->mqh));
- }
- revoke_command
+ REVOKE clear_privileges revoke_command
{}
;
revoke_command:
- grant_privileges ON opt_table FROM user_list
- {}
+ grant_privileges ON opt_table FROM grant_list
+ {
+ Lex->sql_command = SQLCOM_REVOKE;
+ }
|
- ALL opt_privileges ',' GRANT OPTION FROM user_list
+ ALL opt_privileges ',' GRANT OPTION FROM grant_list
{
Lex->sql_command = SQLCOM_REVOKE_ALL;
}
;
grant:
- GRANT
- {
- LEX *lex=Lex;
- lex->users_list.empty();
- lex->columns.empty();
- lex->sql_command = SQLCOM_GRANT;
- lex->grant= lex->grant_tot_col= 0;
- lex->select_lex.db= 0;
- lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
- lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
- bzero((char *)&(lex->mqh),sizeof(lex->mqh));
- }
- grant_privileges ON opt_table TO_SYM user_list
+ GRANT clear_privileges grant_privileges ON opt_table TO_SYM grant_list
require_clause grant_options
- {}
+ { Lex->sql_command= SQLCOM_GRANT; }
;
grant_privileges:
- grant_privilege_list {}
- | ALL opt_privileges { Lex->grant = GLOBAL_ACLS;}
+ object_privilege_list { }
+ | ALL opt_privileges
+ {
+ Lex->all_privileges= 1;
+ Lex->grant= GLOBAL_ACLS;
+ }
;
opt_privileges:
@@ -5699,11 +7933,11 @@ opt_privileges:
| PRIVILEGES
;
-grant_privilege_list:
- grant_privilege
- | grant_privilege_list ',' grant_privilege;
+object_privilege_list:
+ object_privilege
+ | object_privilege_list ',' object_privilege;
-grant_privilege:
+object_privilege:
SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list {}
| INSERT { Lex->which_columns = INSERT_ACL;} opt_column_list {}
| UPDATE_SYM { Lex->which_columns = UPDATE_ACL; } opt_column_list {}
@@ -5724,8 +7958,13 @@ grant_privilege:
| SUPER_SYM { Lex->grant |= SUPER_ACL;}
| CREATE TEMPORARY TABLES { Lex->grant |= CREATE_TMP_ACL;}
| LOCK_SYM TABLES { Lex->grant |= LOCK_TABLES_ACL; }
- | REPLICATION SLAVE { Lex->grant |= REPL_SLAVE_ACL;}
- | REPLICATION CLIENT_SYM { Lex->grant |= REPL_CLIENT_ACL;}
+ | REPLICATION SLAVE { Lex->grant |= REPL_SLAVE_ACL; }
+ | REPLICATION CLIENT_SYM { Lex->grant |= REPL_CLIENT_ACL; }
+ | CREATE VIEW_SYM { Lex->grant |= CREATE_VIEW_ACL; }
+ | SHOW VIEW_SYM { Lex->grant |= SHOW_VIEW_ACL; }
+ | CREATE ROUTINE_SYM { Lex->grant |= CREATE_PROC_ACL; }
+ | ALTER ROUTINE_SYM { Lex->grant |= ALTER_PROC_ACL; }
+ | CREATE USER { Lex->grant |= CREATE_USER_ACL; }
;
@@ -5745,7 +7984,7 @@ require_list_element:
LEX *lex=Lex;
if (lex->x509_subject)
{
- net_printf(lex->thd,ER_DUP_ARGUMENT, "SUBJECT");
+ my_error(ER_DUP_ARGUMENT, MYF(0), "SUBJECT");
YYABORT;
}
lex->x509_subject=$2.str;
@@ -5755,7 +7994,7 @@ require_list_element:
LEX *lex=Lex;
if (lex->x509_issuer)
{
- net_printf(lex->thd,ER_DUP_ARGUMENT, "ISSUER");
+ my_error(ER_DUP_ARGUMENT, MYF(0), "ISSUER");
YYABORT;
}
lex->x509_issuer=$2.str;
@@ -5765,7 +8004,7 @@ require_list_element:
LEX *lex=Lex;
if (lex->ssl_cipher)
{
- net_printf(lex->thd,ER_DUP_ARGUMENT, "CIPHER");
+ my_error(ER_DUP_ARGUMENT, MYF(0), "CIPHER");
YYABORT;
}
lex->ssl_cipher=$2.str;
@@ -5781,7 +8020,8 @@ opt_table:
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
- send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE);
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
+ ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
YYABORT;
}
}
@@ -5793,7 +8033,8 @@ opt_table:
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
- send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE);
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
+ ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
YYABORT;
}
}
@@ -5805,7 +8046,8 @@ opt_table:
lex->grant= GLOBAL_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
- send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE);
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
+ ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
YYABORT;
}
}
@@ -5821,8 +8063,18 @@ opt_table:
user_list:
+ user { if (Lex->users_list.push_back($1)) YYABORT;}
+ | user_list ',' user
+ {
+ if (Lex->users_list.push_back($3))
+ YYABORT;
+ }
+ ;
+
+
+grant_list:
grant_user { if (Lex->users_list.push_back($1)) YYABORT;}
- | user_list ',' grant_user
+ | grant_list ',' grant_user
{
if (Lex->users_list.push_back($3))
YYABORT;
@@ -5857,9 +8109,9 @@ grant_user:
}
}
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
- { $$=$1; $1->password=$5 ; }
+ { $$= $1; $1->password= $5; }
| user
- { $$=$1; $1->password.str=NullS; }
+ { $$= $1; $1->password= null_lex_str; }
;
@@ -5927,52 +8179,109 @@ grant_option_list:
grant_option:
GRANT OPTION { Lex->grant |= GRANT_ACL;}
- | MAX_QUERIES_PER_HOUR ULONG_NUM
+ | MAX_QUERIES_PER_HOUR ulong_num
{
- Lex->mqh.questions=$2;
- Lex->mqh.bits |= 1;
+ LEX *lex=Lex;
+ lex->mqh.questions=$2;
+ lex->mqh.specified_limits|= USER_RESOURCES::QUERIES_PER_HOUR;
+ }
+ | MAX_UPDATES_PER_HOUR ulong_num
+ {
+ LEX *lex=Lex;
+ lex->mqh.updates=$2;
+ lex->mqh.specified_limits|= USER_RESOURCES::UPDATES_PER_HOUR;
}
- | MAX_UPDATES_PER_HOUR ULONG_NUM
+ | MAX_CONNECTIONS_PER_HOUR ulong_num
{
- Lex->mqh.updates=$2;
- Lex->mqh.bits |= 2;
+ LEX *lex=Lex;
+ lex->mqh.conn_per_hour= $2;
+ lex->mqh.specified_limits|= USER_RESOURCES::CONNECTIONS_PER_HOUR;
}
- | MAX_CONNECTIONS_PER_HOUR ULONG_NUM
+ | MAX_USER_CONNECTIONS_SYM ulong_num
{
- Lex->mqh.connections=$2;
- Lex->mqh.bits |= 4;
+ LEX *lex=Lex;
+ lex->mqh.user_conn= $2;
+ lex->mqh.specified_limits|= USER_RESOURCES::USER_CONNECTIONS;
}
;
begin:
- BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN; Lex->start_transaction_opt= 0;} opt_work {}
+ BEGIN_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_BEGIN;
+ lex->start_transaction_opt= 0;
+ }
+ opt_work {}
;
opt_work:
/* empty */ {}
- | WORK_SYM {;}
+ | WORK_SYM {}
;
+opt_chain:
+ /* empty */ { $$= (YYTHD->variables.completion_type == 1); }
+ | AND_SYM NO_SYM CHAIN_SYM { $$=0; }
+ | AND_SYM CHAIN_SYM { $$=1; }
+ ;
+
+opt_release:
+ /* empty */ { $$= (YYTHD->variables.completion_type == 2); }
+ | RELEASE_SYM { $$=1; }
+ | NO_SYM RELEASE_SYM { $$=0; }
+ ;
+
+opt_savepoint:
+ /* empty */ {}
+ | SAVEPOINT_SYM {}
+ ;
+
commit:
- COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;};
+ COMMIT_SYM opt_work opt_chain opt_release
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_COMMIT;
+ lex->tx_chain= $3;
+ lex->tx_release= $4;
+ }
+ ;
rollback:
- ROLLBACK_SYM
+ ROLLBACK_SYM opt_work opt_chain opt_release
{
- Lex->sql_command = SQLCOM_ROLLBACK;
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_ROLLBACK;
+ lex->tx_chain= $3;
+ lex->tx_release= $4;
}
- | ROLLBACK_SYM TO_SYM SAVEPOINT_SYM ident
+ | ROLLBACK_SYM opt_work
+ TO_SYM opt_savepoint ident
{
- Lex->sql_command = SQLCOM_ROLLBACK_TO_SAVEPOINT;
- Lex->savepoint_name = $4.str;
- };
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_ROLLBACK_TO_SAVEPOINT;
+ lex->ident= $5;
+ }
+ ;
+
savepoint:
SAVEPOINT_SYM ident
{
- Lex->sql_command = SQLCOM_SAVEPOINT;
- Lex->savepoint_name = $2.str;
- };
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SAVEPOINT;
+ lex->ident= $2;
+ }
+ ;
+release:
+ RELEASE_SYM SAVEPOINT_SYM ident
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_RELEASE_SAVEPOINT;
+ lex->ident= $3;
+ }
+ ;
+
/*
UNIONS : glue selects together
*/
@@ -5990,7 +8299,7 @@ union_list:
if (lex->exchange)
{
/* Only the last SELECT can have INTO...... */
- net_printf(lex->thd, ER_WRONG_USAGE, "UNION", "INTO");
+ my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO");
YYABORT;
}
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
@@ -6010,13 +8319,12 @@ union_list:
;
union_opt:
- union_list {}
- | optional_order_or_limit {}
+ /* Empty */ { $$= 0; }
+ | union_list { $$= 1; }
+ | union_order_or_limit { $$= 1; }
;
-optional_order_or_limit:
- /* Empty */ {}
- |
+union_order_or_limit:
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
@@ -6114,3 +8422,118 @@ subselect_end:
lex->current_select = lex->current_select->return_after_parsing();
};
+opt_view_list:
+ /* empty */ {}
+ | '(' view_list ')'
+ ;
+
+view_list:
+ ident
+ {
+ Lex->view_list.push_back((LEX_STRING*)
+ sql_memdup(&$1, sizeof(LEX_STRING)));
+ }
+ | view_list ',' ident
+ {
+ Lex->view_list.push_back((LEX_STRING*)
+ sql_memdup(&$3, sizeof(LEX_STRING)));
+ }
+ ;
+
+or_replace:
+ /* empty */ { Lex->create_view_mode= VIEW_CREATE_NEW; }
+ | OR_SYM REPLACE { Lex->create_view_mode= VIEW_CREATE_OR_REPLACE; }
+ ;
+
+algorithm:
+ /* empty */
+ { Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; }
+ | ALGORITHM_SYM EQ UNDEFINED_SYM
+ { Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; }
+ | ALGORITHM_SYM EQ MERGE_SYM
+ { Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; }
+ | ALGORITHM_SYM EQ TEMPTABLE_SYM
+ { Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; }
+ ;
+check_option:
+ /* empty */
+ { Lex->create_view_check= VIEW_CHECK_NONE; }
+ | WITH CHECK_SYM OPTION
+ { Lex->create_view_check= VIEW_CHECK_CASCADED; }
+ | WITH CASCADED CHECK_SYM OPTION
+ { Lex->create_view_check= VIEW_CHECK_CASCADED; }
+ | WITH LOCAL_SYM CHECK_SYM OPTION
+ { Lex->create_view_check= VIEW_CHECK_LOCAL; }
+ ;
+
+xa: XA_SYM begin_or_start xid opt_join_or_resume
+ {
+ Lex->sql_command = SQLCOM_XA_START;
+ }
+ | XA_SYM END xid opt_suspend_or_migrate
+ {
+ Lex->sql_command = SQLCOM_XA_END;
+ }
+ | XA_SYM PREPARE_SYM xid
+ {
+ Lex->sql_command = SQLCOM_XA_PREPARE;
+ }
+ | XA_SYM COMMIT_SYM xid opt_one_phase
+ {
+ Lex->sql_command = SQLCOM_XA_COMMIT;
+ }
+ | XA_SYM ROLLBACK_SYM xid
+ {
+ Lex->sql_command = SQLCOM_XA_ROLLBACK;
+ }
+ | XA_SYM RECOVER_SYM
+ {
+ Lex->sql_command = SQLCOM_XA_RECOVER;
+ }
+ ;
+
+xid: text_string
+ {
+ TEST_ASSERT($1->length() <= MAXGTRIDSIZE);
+ if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
+ YYABORT;
+ Lex->xid->set(1L, $1->ptr(), $1->length(), 0, 0);
+ }
+ | text_string ',' text_string
+ {
+ TEST_ASSERT($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
+ if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
+ YYABORT;
+ Lex->xid->set(1L, $1->ptr(), $1->length(), $3->ptr(), $3->length());
+ }
+ | text_string ',' text_string ',' ulong_num
+ {
+ TEST_ASSERT($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
+ if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
+ YYABORT;
+ Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length());
+ }
+ ;
+
+begin_or_start: BEGIN_SYM {}
+ | START_SYM {}
+ ;
+
+opt_join_or_resume:
+ /* nothing */ { Lex->xa_opt=XA_NONE; }
+ | JOIN_SYM { Lex->xa_opt=XA_JOIN; }
+ | RESUME_SYM { Lex->xa_opt=XA_RESUME; }
+ ;
+
+opt_one_phase:
+ /* nothing */ { Lex->xa_opt=XA_NONE; }
+ | ONE_SYM PHASE_SYM { Lex->xa_opt=XA_ONE_PHASE; }
+ ;
+
+opt_suspend_or_migrate:
+ /* nothing */ { Lex->xa_opt=XA_NONE; }
+ | SUSPEND_SYM { Lex->xa_opt=XA_SUSPEND; }
+ | FOR_SYM MIGRATE_SYM { Lex->xa_opt=XA_FOR_MIGRATE; }
+ ;
+
+
diff --git a/sql/strfunc.cc b/sql/strfunc.cc
index 81aca092cec..c822d10af46 100644
--- a/sql/strfunc.cc
+++ b/sql/strfunc.cc
@@ -147,10 +147,10 @@ uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match)
uint find_type2(TYPELIB *typelib, const char *x, uint length, CHARSET_INFO *cs)
{
- int find,pos;
+ int pos;
const char *j;
DBUG_ENTER("find_type2");
- DBUG_PRINT("enter",("x: '%s' lib: 0x%lx",x,typelib));
+ DBUG_PRINT("enter",("x: '%.*s' lib: 0x%lx", length, x, typelib));
if (!typelib->count)
{
@@ -158,7 +158,7 @@ uint find_type2(TYPELIB *typelib, const char *x, uint length, CHARSET_INFO *cs)
DBUG_RETURN(0);
}
- for (find=0, pos=0 ; (j=typelib->type_names[pos]) ; pos++)
+ for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
{
if (!my_strnncoll(cs, (const uchar*) x, length,
(const uchar*) j, typelib->type_lengths[pos]))
diff --git a/sql/structs.h b/sql/structs.h
index ba081b570c1..7a70bfc0f4f 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -74,7 +74,7 @@ typedef struct st_key_part_info { /* Info about a key part */
uint16 store_length;
uint16 key_type;
uint16 fieldnr; /* Fieldnum in UNIREG */
- uint8 key_part_flag; /* 0 or HA_REVERSE_SORT */
+ uint16 key_part_flag; /* 0 or HA_REVERSE_SORT */
uint8 type;
uint8 null_bit; /* Position to null_bit */
} KEY_PART_INFO ;
@@ -98,6 +98,7 @@ typedef struct st_key {
union {
int bdb_return_if_eq;
} handler;
+ struct st_table *table;
} KEY;
@@ -163,9 +164,10 @@ typedef struct st_known_date_time_format {
enum SHOW_TYPE
{
SHOW_UNDEF,
- SHOW_LONG, SHOW_LONGLONG, SHOW_INT, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_BOOL,
- SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUESTION,
+ SHOW_LONG, SHOW_LONGLONG, SHOW_INT, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_DOUBLE,
+ SHOW_BOOL, SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUESTION,
SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_SYS, SHOW_HA_ROWS,
+ SHOW_VARS,
#ifdef HAVE_OPENSSL
SHOW_SSL_CTX_SESS_ACCEPT, SHOW_SSL_CTX_SESS_ACCEPT_GOOD,
SHOW_SSL_GET_VERSION, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE,
@@ -181,7 +183,8 @@ enum SHOW_TYPE
SHOW_SSL_GET_CIPHER_LIST,
#endif /* HAVE_OPENSSL */
SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, SHOW_SLAVE_RETRIED_TRANS,
- SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG
+ SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG,
+ SHOW_LONG_STATUS, SHOW_LONG_CONST_STATUS
};
enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED};
@@ -203,16 +206,65 @@ typedef struct st_lex_user {
} LEX_USER;
+/*
+ This structure specifies the maximum amount of resources which
+ can be consumed by each account. Zero value of a member means
+ there is no limit.
+*/
typedef struct user_resources {
- uint questions, updates, connections, bits;
+ /* Maximum number of queries/statements per hour. */
+ uint questions;
+ /*
+ Maximum number of updating statements per hour (which statements are
+ updating is defined by uc_update_queries array).
+ */
+ uint updates;
+ /* Maximum number of connections established per hour. */
+ uint conn_per_hour;
+ /* Maximum number of concurrent connections. */
+ uint user_conn;
+ /*
+ Values of this enum and specified_limits member are used by the
+ parser to store which user limits were specified in GRANT statement.
+ */
+ enum {QUERIES_PER_HOUR= 1, UPDATES_PER_HOUR= 2, CONNECTIONS_PER_HOUR= 4,
+ USER_CONNECTIONS= 8};
+ uint specified_limits;
} USER_RESOURCES;
+
+/*
+ This structure is used for counting resources consumed and for checking
+ them against specified user limits.
+*/
typedef struct user_conn {
- char *user, *host;
- uint len, connections, conn_per_hour, updates, questions, user_len;
+ /*
+ Pointer to user+host key (pair separated by '\0') defining the entity
+ for which resources are counted (By default it is user account thus
+ priv_user/priv_host pair is used. If --old-style-user-limits option
+ is enabled, resources are counted for each user+host separately).
+ */
+ char *user;
+ /* Pointer to host part of the key. */
+ char *host;
+ /* Total length of the key. */
+ uint len;
+ /* Current amount of concurrent connections for this account. */
+ uint connections;
+ /*
+ Current number of connections per hour, number of updating statements
+ per hour and total number of statements per hour for this account.
+ */
+ uint conn_per_hour, updates, questions;
+ /* Maximum amount of resources which account is allowed to consume. */
USER_RESOURCES user_resources;
+ /*
+ The moment of time when per hour counters were reset last time
+ (i.e. start of "hour" for conn_per_hour, updates, questions counters).
+ */
time_t intime;
} USER_CONN;
+
/* Bits in form->update */
#define REG_MAKE_DUPP 1 /* Make a copy of record when read */
#define REG_NEW_RECORD 2 /* Write a new record if not found */
diff --git a/sql/table.cc b/sql/table.cc
index cdcd5148787..8e0f52e1910 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -20,7 +20,7 @@
#include "mysql_priv.h"
#include <errno.h>
#include <m_ctype.h>
-
+#include "md5.h"
/* Functions defined in this file */
@@ -61,8 +61,8 @@ static byte* get_field_name(Field **buff,uint *length,
5 Error (see frm_error: charset unavailable)
*/
-int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
- uint ha_open_flags, TABLE *outparam)
+int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
+ uint prgflag, uint ha_open_flags, TABLE *outparam)
{
reg1 uint i;
reg2 uchar *strpos;
@@ -76,76 +76,103 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
my_string record;
const char **int_array;
bool use_hash, null_field_first;
+ bool error_reported= FALSE;
File file;
Field **field_ptr,*reg_field;
KEY *keyinfo;
KEY_PART_INFO *key_part;
uchar *null_pos;
- uint null_bit, new_frm_ver, field_pack_length;
+ uint null_bit_pos, new_frm_ver, field_pack_length;
SQL_CRYPT *crypted=0;
MEM_ROOT **root_ptr, *old_root;
+ TABLE_SHARE *share;
DBUG_ENTER("openfrm");
- DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam));
-
- bzero((char*) outparam,sizeof(*outparam));
- outparam->blob_ptr_size=sizeof(char*);
- disk_buff=NULL; record= NULL; keynames=NullS;
- outparam->db_stat = db_stat;
- error=1;
+ DBUG_PRINT("enter",("name: '%s' form: 0x%lx",name,outparam));
- init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
+ error= 1;
+ disk_buff= NULL;
root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
old_root= *root_ptr;
- *root_ptr= &outparam->mem_root;
- outparam->real_name=strdup_root(&outparam->mem_root,
- name+dirname_length(name));
- outparam->table_name=my_strdup(alias,MYF(MY_WME));
- if (!outparam->real_name || !outparam->table_name)
- goto err_end;
- *fn_ext(outparam->real_name)='\0'; // Remove extension
+ bzero((char*) outparam,sizeof(*outparam));
+ outparam->in_use= thd;
+ outparam->s= share= &outparam->share_not_to_be_used;
- if ((file=my_open(fn_format(index_file,name,"",reg_ext,MY_UNPACK_FILENAME),
+ if ((file=my_open(fn_format(index_file, name, "", reg_ext,
+ MY_UNPACK_FILENAME),
O_RDONLY | O_SHARE,
MYF(0)))
< 0)
+ goto err;
+
+ error= 4;
+ if (my_read(file,(byte*) head,64,MYF(MY_NABP)))
+ goto err;
+
+ if (memcmp(head, "TYPE=", 5) == 0)
{
- goto err_end; /* purecov: inspected */
+ // new .frm
+ my_close(file,MYF(MY_WME));
+
+ if (db_stat & NO_ERR_ON_NEW_FRM)
+ DBUG_RETURN(5);
+ file= -1;
+ // caller can't process new .frm
+ goto err;
}
- error=4;
- if (!(outparam->path= strdup_root(&outparam->mem_root,name)))
- goto err_not_open;
- *fn_ext(outparam->path)='\0'; // Remove extension
- if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err_not_open;
+ share->blob_ptr_size= sizeof(char*);
+ outparam->db_stat= db_stat;
+ init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
+ *root_ptr= &outparam->mem_root;
+
+ share->table_name= strdup_root(&outparam->mem_root,
+ name+dirname_length(name));
+ share->path= strdup_root(&outparam->mem_root, name);
+ outparam->alias= my_strdup(alias, MYF(MY_WME));
+ if (!share->table_name || !share->path || !outparam->alias)
+ goto err;
+ *fn_ext(share->table_name)='\0'; // Remove extension
+ *fn_ext(share->path)='\0'; // Remove extension
+
if (head[0] != (uchar) 254 || head[1] != 1 ||
- (head[2] != FRM_VER && head[2] != FRM_VER+1 && head[2] != FRM_VER+3))
- goto err_not_open; /* purecov: inspected */
+ (head[2] != FRM_VER && head[2] != FRM_VER+1 &&
+ ! (head[2] >= FRM_VER+3 && head[2] <= FRM_VER+4)))
+ goto err; /* purecov: inspected */
new_field_pack_flag=head[27];
new_frm_ver= (head[2] - FRM_VER);
field_pack_length= new_frm_ver < 2 ? 11 : 17;
error=3;
if (!(pos=get_form_pos(file,head,(TYPELIB*) 0)))
- goto err_not_open; /* purecov: inspected */
+ goto err; /* purecov: inspected */
*fn_ext(index_file)='\0'; // Remove .frm extension
- outparam->frm_version= head[2];
- outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3));
- outparam->db_create_options=db_create_options=uint2korr(head+30);
- outparam->db_options_in_use=outparam->db_create_options;
- null_field_first=0;
+ share->frm_version= head[2];
+ /*
+ Check if .frm file created by MySQL 5.0. In this case we want to
+ display CHAR fields as CHAR and not as VARCHAR.
+ We do it this way as we want to keep the old frm version to enable
+ MySQL 4.1 to read these files.
+ */
+ 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_create_options= db_create_options=uint2korr(head+30);
+ share->db_options_in_use= share->db_create_options;
+ null_field_first= 0;
if (!head[32]) // New frm file in 3.23
{
- outparam->avg_row_length=uint4korr(head+34);
- outparam->row_type=(row_type) head[40];
- outparam->raid_type= head[41];
- outparam->raid_chunks= head[42];
- outparam->raid_chunksize= uint4korr(head+43);
- outparam->table_charset=get_charset((uint) head[38],MYF(0));
- null_field_first=1;
+ share->avg_row_length= uint4korr(head+34);
+ share-> row_type= (row_type) head[40];
+ share->raid_type= head[41];
+ share->raid_chunks= head[42];
+ share->raid_chunksize= uint4korr(head+43);
+ share->table_charset= get_charset((uint) head[38],MYF(0));
+ null_field_first= 1;
}
- if (!outparam->table_charset)
+ if (!share->table_charset)
{
/* unknown charset in head[38] or pre-3.23 frm */
if (use_mb(default_charset_info))
@@ -156,35 +183,34 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
"so character column sizes may have changed",
name);
}
- outparam->table_charset=default_charset_info;
+ share->table_charset= default_charset_info;
}
- outparam->db_record_offset=1;
+ share->db_record_offset= 1;
if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
- outparam->blob_ptr_size=portable_sizeof_char_ptr;
- /* Set temporaryly a good value for db_low_byte_first */
- outparam->db_low_byte_first=test(outparam->db_type != DB_TYPE_ISAM);
+ share->blob_ptr_size= portable_sizeof_char_ptr;
+ /* Set temporarily a good value for db_low_byte_first */
+ share->db_low_byte_first= test(share->db_type != DB_TYPE_ISAM);
error=4;
- outparam->max_rows=uint4korr(head+18);
- outparam->min_rows=uint4korr(head+22);
+ share->max_rows= uint4korr(head+18);
+ share->min_rows= uint4korr(head+22);
/* Read keyinformation */
key_info_length= (uint) uint2korr(head+28);
VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
if (read_string(file,(gptr*) &disk_buff,key_info_length))
- goto err_not_open; /* purecov: inspected */
+ goto err; /* purecov: inspected */
if (disk_buff[0] & 0x80)
{
- outparam->keys= keys= (disk_buff[1] << 7) | (disk_buff[0] & 0x7f);
- outparam->key_parts= key_parts= uint2korr(disk_buff+2);
+ share->keys= keys= (disk_buff[1] << 7) | (disk_buff[0] & 0x7f);
+ share->key_parts= key_parts= uint2korr(disk_buff+2);
}
else
{
- outparam->keys= keys= disk_buff[0];
- outparam->key_parts= key_parts= disk_buff[1];
+ share->keys= keys= disk_buff[0];
+ share->key_parts= key_parts= disk_buff[1];
}
- outparam->keys_for_keyread.init(0);
- outparam->keys_in_use.init(keys);
- outparam->read_only_keys.init(keys);
+ share->keys_for_keyread.init(0);
+ share->keys_in_use.init(keys);
outparam->quick_keys.init();
outparam->used_keys.init();
outparam->keys_in_use_for_query.init();
@@ -192,7 +218,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root,
n_length+uint2korr(disk_buff+4))))
- goto err_not_open; /* purecov: inspected */
+ goto err; /* purecov: inspected */
bzero((char*) keyinfo,n_length);
outparam->key_info=keyinfo;
key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys);
@@ -201,11 +227,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
ulong *rec_per_key;
if (!(rec_per_key= (ulong*) alloc_root(&outparam->mem_root,
sizeof(ulong*)*key_parts)))
- goto err_not_open;
+ goto err;
for (i=0 ; i < keys ; i++, keyinfo++)
{
- if (new_frm_ver == 3)
+ keyinfo->table= outparam;
+ if (new_frm_ver >= 3)
{
keyinfo->flags= (uint) uint2korr(strpos) ^ HA_NOSAME;
keyinfo->key_length= (uint) uint2korr(strpos+2);
@@ -254,9 +281,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keynames=(char*) key_part;
strpos+= (strmov(keynames, (char *) strpos) - keynames)+1;
- outparam->reclength = uint2korr((head+16));
+ share->reclength = uint2korr((head+16));
if (*(head+26) == 1)
- outparam->system=1; /* one-record-database */
+ share->system= 1; /* one-record-database */
#ifdef HAVE_CRYPTED_FRM
else if (*(head+26) == 2)
{
@@ -268,84 +295,97 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
#endif
/* Allocate handler */
- if (!(outparam->file= get_new_handler(outparam,outparam->db_type)))
- goto err_not_open;
+ if (!(outparam->file= get_new_handler(outparam, share->db_type)))
+ goto err;
error=4;
outparam->reginfo.lock_type= TL_UNLOCK;
outparam->current_lock=F_UNLCK;
- if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN)) records=2;
- else records=1;
- if (prgflag & (READ_ALL+EXTRA_RECORD)) records++;
+ if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN))
+ records=2;
+ else
+ records=1;
+ if (prgflag & (READ_ALL+EXTRA_RECORD))
+ records++;
/* QQ: TODO, remove the +1 from below */
- rec_buff_length=ALIGN_SIZE(outparam->reclength+1+
- outparam->file->extra_rec_buf_length());
- if (!(outparam->record[0]= (byte*)
- (record = (char *) alloc_root(&outparam->mem_root,
- rec_buff_length * records))))
- goto err_not_open; /* purecov: inspected */
- record[outparam->reclength]=0; // For purify and ->c_ptr()
- outparam->rec_buff_length=rec_buff_length;
- if (my_pread(file,(byte*) record,(uint) outparam->reclength,
+ rec_buff_length= ALIGN_SIZE(share->reclength + 1 +
+ outparam->file->extra_rec_buf_length());
+ share->rec_buff_length= rec_buff_length;
+ if (!(record= (char *) alloc_root(&outparam->mem_root,
+ rec_buff_length * records)))
+ goto err; /* purecov: inspected */
+ share->default_values= (byte *) record;
+ if (my_pread(file,(byte*) record, (uint) share->reclength,
(ulong) (uint2korr(head+6)+
((uint2korr(head+14) == 0xffff ?
uint4korr(head+47) : uint2korr(head+14)))),
MYF(MY_NABP)))
- goto err_not_open; /* purecov: inspected */
- /* HACK: table->record[2] is used instead of table->default_values here */
- for (i=0 ; i < records ; i++, record+=rec_buff_length)
+ goto err; /* purecov: inspected */
+
+ if (records == 1)
{
- outparam->record[i]=(byte*) record;
- if (i)
- memcpy(record,record-rec_buff_length,(uint) outparam->reclength);
+ /* We are probably in hard repair, and the buffers should not be used */
+ outparam->record[0]= outparam->record[1]= share->default_values;
}
-
- if (records == 2)
- { /* fix for select */
- outparam->default_values=outparam->record[1];
- if (db_stat & HA_READ_ONLY)
- outparam->record[1]=outparam->record[0]; /* purecov: inspected */
+ else
+ {
+ outparam->record[0]= (byte *) record+ rec_buff_length;
+ if (records > 2)
+ outparam->record[1]= (byte *) record+ rec_buff_length*2;
+ else
+ outparam->record[1]= outparam->record[0]; // Safety
}
- outparam->insert_values=0; /* for INSERT ... UPDATE */
+#ifdef HAVE_purify
+ /*
+ We need this because when we read var-length rows, we are not updating
+ bytes after end of varchar
+ */
+ if (records > 1)
+ {
+ memcpy(outparam->record[0], share->default_values, rec_buff_length);
+ if (records > 2)
+ memcpy(outparam->record[1], share->default_values, rec_buff_length);
+ }
+#endif
VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
- if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open;
+ if (my_read(file,(byte*) head,288,MYF(MY_NABP)))
+ goto err;
#ifdef HAVE_CRYPTED_FRM
if (crypted)
{
crypted->decode((char*) head+256,288-256);
if (sint2korr(head+284) != 0) // Should be 0
- goto err_not_open; // Wrong password
+ goto err; // Wrong password
}
#endif
- outparam->fields= uint2korr(head+258);
- pos=uint2korr(head+260); /* Length of all screens */
- n_length=uint2korr(head+268);
- interval_count=uint2korr(head+270);
- interval_parts=uint2korr(head+272);
- int_length=uint2korr(head+274);
- outparam->null_fields=uint2korr(head+282);
- com_length=uint2korr(head+284);
- outparam->comment=strdup_root(&outparam->mem_root,
- (char*) head+47);
+ share->fields= uint2korr(head+258);
+ pos= uint2korr(head+260); /* Length of all screens */
+ n_length= uint2korr(head+268);
+ interval_count= uint2korr(head+270);
+ interval_parts= uint2korr(head+272);
+ int_length= uint2korr(head+274);
+ share->null_fields= uint2korr(head+282);
+ com_length= uint2korr(head+284);
+ share->comment= strdup_root(&outparam->mem_root, (char*) head+47);
- DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d com_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length, com_length));
+ DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d com_length: %d", interval_count,interval_parts, share->keys,n_length,int_length, com_length));
if (!(field_ptr = (Field **)
alloc_root(&outparam->mem_root,
- (uint) ((outparam->fields+1)*sizeof(Field*)+
+ (uint) ((share->fields+1)*sizeof(Field*)+
interval_count*sizeof(TYPELIB)+
- (outparam->fields+interval_parts+
+ (share->fields+interval_parts+
keys+3)*sizeof(my_string)+
(n_length+int_length+com_length)))))
- goto err_not_open; /* purecov: inspected */
+ goto err; /* purecov: inspected */
outparam->field=field_ptr;
- read_length=(uint) (outparam->fields * field_pack_length +
+ read_length=(uint) (share->fields * field_pack_length +
pos+ (uint) (n_length+int_length+com_length));
if (read_string(file,(gptr*) &disk_buff,read_length))
- goto err_not_open; /* purecov: inspected */
+ goto err; /* purecov: inspected */
#ifdef HAVE_CRYPTED_FRM
if (crypted)
{
@@ -356,31 +396,31 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
#endif
strpos= disk_buff+pos;
- outparam->intervals= (TYPELIB*) (field_ptr+outparam->fields+1);
- int_array= (const char **) (outparam->intervals+interval_count);
- names= (char*) (int_array+outparam->fields+interval_parts+keys+3);
+ share->intervals= (TYPELIB*) (field_ptr+share->fields+1);
+ int_array= (const char **) (share->intervals+interval_count);
+ names= (char*) (int_array+share->fields+interval_parts+keys+3);
if (!interval_count)
- outparam->intervals=0; // For better debugging
- memcpy((char*) names, strpos+(outparam->fields*field_pack_length),
+ share->intervals= 0; // For better debugging
+ memcpy((char*) names, strpos+(share->fields*field_pack_length),
(uint) (n_length+int_length));
- comment_pos=names+(n_length+int_length);
+ comment_pos= names+(n_length+int_length);
memcpy(comment_pos, disk_buff+read_length-com_length, com_length);
- fix_type_pointers(&int_array,&outparam->fieldnames,1,&names);
- fix_type_pointers(&int_array,outparam->intervals,interval_count,
+ fix_type_pointers(&int_array, &share->fieldnames, 1, &names);
+ fix_type_pointers(&int_array, share->intervals, interval_count,
&names);
{
/* Set ENUM and SET lengths */
TYPELIB *interval;
- for (interval= outparam->intervals;
- interval < outparam->intervals + interval_count;
+ for (interval= share->intervals;
+ interval < share->intervals + interval_count;
interval++)
{
uint count= (uint) (interval->count + 1) * sizeof(uint);
if (!(interval->type_lengths= (uint *) alloc_root(&outparam->mem_root,
count)))
- goto err_not_open;
+ goto err;
for (count= 0; count < interval->count; count++)
interval->type_lengths[count]= strlen(interval->type_names[count]);
interval->type_lengths[count]= 0;
@@ -388,33 +428,33 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
}
if (keynames)
- fix_type_pointers(&int_array,&outparam->keynames,1,&keynames);
+ fix_type_pointers(&int_array, &share->keynames, 1, &keynames);
VOID(my_close(file,MYF(MY_WME)));
file= -1;
- record=(char*) outparam->record[0]-1; /* Fieldstart = 1 */
+ record= (char*) outparam->record[0]-1; /* Fieldstart = 1 */
if (null_field_first)
{
outparam->null_flags=null_pos=(uchar*) record+1;
- null_bit= (db_create_options & HA_OPTION_PACK_RECORD) ? 1 : 2;
- outparam->null_bytes=(outparam->null_fields+null_bit+6)/8;
+ null_bit_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1;
+ share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8;
}
else
{
- outparam->null_bytes=(outparam->null_fields+7)/8;
- outparam->null_flags=null_pos=
- (uchar*) (record+1+outparam->reclength-outparam->null_bytes);
- null_bit=1;
+ share->null_bytes= (share->null_fields+7)/8;
+ outparam->null_flags= null_pos=
+ (uchar*) (record+1+share->reclength-share->null_bytes);
+ null_bit_pos= 0;
}
- use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
+ use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH;
if (use_hash)
- use_hash= !hash_init(&outparam->name_hash,
+ use_hash= !hash_init(&share->name_hash,
system_charset_info,
- outparam->fields,0,0,
+ share->fields,0,0,
(hash_get_key) get_field_name,0,0);
- for (i=0 ; i < outparam->fields; i++, strpos+=field_pack_length, field_ptr++)
+ for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
{
uint pack_flag, interval_nr, unireg_type, recpos, field_length;
enum_field_types field_type;
@@ -422,7 +462,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
Field::geometry_type geom_type= Field::GEOM_GEOMETRY;
LEX_STRING comment;
- if (new_frm_ver == 3)
+ if (new_frm_ver >= 3)
{
/* new frm file in 4.1 */
field_length= uint2korr(strpos+3);
@@ -430,11 +470,10 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
pack_flag= uint2korr(strpos+8);
unireg_type= (uint) strpos[10];
interval_nr= (uint) strpos[12];
-
uint comment_length=uint2korr(strpos+15);
field_type=(enum_field_types) (uint) strpos[13];
- // charset and geometry_type share the same byte in frm
+ /* charset and geometry_type share the same byte in frm */
if (field_type == FIELD_TYPE_GEOMETRY)
{
#ifdef HAVE_SPATIAL
@@ -442,7 +481,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
charset= &my_charset_bin;
#else
error= 4; // unsupported field type
- goto err_not_open;
+ goto err;
#endif
}
else
@@ -453,7 +492,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
{
error= 5; // Unknown or unavailable charset
errarg= (int) strpos[14];
- goto err_not_open;
+ goto err;
}
}
if (!comment_length)
@@ -473,6 +512,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
field_length= (uint) strpos[3];
recpos= uint2korr(strpos+4),
pack_flag= uint2korr(strpos+6);
+ pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files
unireg_type= (uint) strpos[8];
interval_nr= (uint) strpos[10];
@@ -489,7 +529,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (!f_is_blob(pack_flag))
{
// 3.23 or 4.0 string
- if (!(charset= get_charset_by_csname(outparam->table_charset->csname,
+ if (!(charset= get_charset_by_csname(share->table_charset->csname,
MY_CS_BINSORT, MYF(0))))
charset= &my_charset_bin;
}
@@ -497,51 +537,58 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
charset= &my_charset_bin;
}
else
- charset= outparam->table_charset;
+ charset= share->table_charset;
bzero((char*) &comment, sizeof(comment));
}
if (interval_nr && charset->mbminlen > 1)
{
/* Unescape UCS2 intervals from HEX notation */
- TYPELIB *interval= outparam->intervals + interval_nr - 1;
+ TYPELIB *interval= share->intervals + interval_nr - 1;
unhex_type2(interval);
}
*field_ptr=reg_field=
make_field(record+recpos,
(uint32) field_length,
- null_pos,null_bit,
+ null_pos, null_bit_pos,
pack_flag,
field_type,
charset,
geom_type,
(Field::utype) MTYP_TYPENR(unireg_type),
(interval_nr ?
- outparam->intervals+interval_nr-1 :
+ share->intervals+interval_nr-1 :
(TYPELIB*) 0),
- outparam->fieldnames.type_names[i],
+ share->fieldnames.type_names[i],
outparam);
if (!reg_field) // Not supported field type
{
error= 4;
- goto err_not_open; /* purecov: inspected */
+ goto err; /* purecov: inspected */
}
reg_field->comment=comment;
- if (!(reg_field->flags & NOT_NULL_FLAG))
+ if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag))
{
- if ((null_bit<<=1) == 256)
+ if ((null_bit_pos+= field_length & 7) > 7)
{
- null_pos++;
- null_bit=1;
+ null_pos++;
+ null_bit_pos-= 8;
}
}
+ if (!(reg_field->flags & NOT_NULL_FLAG))
+ {
+ if (!(null_bit_pos= (null_bit_pos + 1) & 7))
+ null_pos++;
+ }
+ if (f_no_default(pack_flag))
+ reg_field->flags|= NO_DEFAULT_VALUE_FLAG;
if (reg_field->unireg_check == Field::NEXT_NUMBER)
outparam->found_next_number_field= reg_field;
if (outparam->timestamp_field == reg_field)
- outparam->timestamp_field_offset=i;
+ share->timestamp_field_offset= i;
if (use_hash)
- (void) my_hash_insert(&outparam->name_hash,(byte*) field_ptr); // Will never fail
+ (void) my_hash_insert(&share->name_hash,(byte*) field_ptr); // never fail
}
*field_ptr=0; // End marker
@@ -549,15 +596,15 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (key_parts)
{
uint primary_key=(uint) (find_type((char*) primary_key_name,
- &outparam->keynames, 3) - 1);
+ &share->keynames, 3) - 1);
uint ha_option=outparam->file->table_flags();
keyinfo=outparam->key_info;
key_part=keyinfo->key_part;
- for (uint key=0 ; key < outparam->keys ; key++,keyinfo++)
+ for (uint key=0 ; key < share->keys ; key++,keyinfo++)
{
uint usable_parts=0;
- keyinfo->name=(char*) outparam->keynames.type_names[key];
+ keyinfo->name=(char*) share->keynames.type_names[key];
/* Fix fulltext keys for old .frm files */
if (outparam->key_info[key].flags & HA_FULLTEXT)
outparam->key_info[key].algorithm= HA_KEY_ALG_FULLTEXT;
@@ -590,8 +637,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(uint) key_part->offset,
(uint) key_part->length);
#ifdef EXTRA_DEBUG
- if (key_part->fieldnr > outparam->fields)
- goto err_not_open; // sanity check
+ if (key_part->fieldnr > share->fields)
+ goto err; // sanity check
#endif
if (key_part->fieldnr)
{ // Should always be true !
@@ -607,10 +654,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keyinfo->key_length+= HA_KEY_NULL_LENGTH;
}
if (field->type() == FIELD_TYPE_BLOB ||
- field->real_type() == FIELD_TYPE_VAR_STRING)
+ field->real_type() == MYSQL_TYPE_VARCHAR)
{
if (field->type() == FIELD_TYPE_BLOB)
key_part->key_part_flag|= HA_BLOB_PART;
+ else
+ key_part->key_part_flag|= HA_VAR_LENGTH_PART;
keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
key_part->store_length+=HA_KEY_BLOB_LENGTH;
keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
@@ -621,6 +670,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (!(field->flags & BINARY_FLAG))
keyinfo->flags|= HA_END_SPACE_KEY;
}
+ if (field->type() == MYSQL_TYPE_BIT)
+ key_part->key_part_flag|= HA_BIT_PART;
+
if (i == 0 && key != primary_key)
field->flags |=
((keyinfo->flags & HA_NOSAME) &&
@@ -633,8 +685,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
{
if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY)
{
- outparam->read_only_keys.clear_bit(key);
- outparam->keys_for_keyread.set_bit(key);
+ share->keys_for_keyread.set_bit(key);
field->part_of_key.set_bit(key);
}
if (outparam->file->index_flags(key, i, 1) & HA_READ_ORDER)
@@ -652,7 +703,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
the primary key, then we can use any key to find this column
*/
if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX)
- field->part_of_key= outparam->keys_in_use;
+ field->part_of_key= share->keys_in_use;
}
if (field->key_length() != key_part->length)
{
@@ -680,16 +731,16 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
}
keyinfo->usable_key_parts=usable_parts; // Filesort
- set_if_bigger(outparam->max_key_length,keyinfo->key_length+
- keyinfo->key_parts);
- outparam->total_key_length+= keyinfo->key_length;
+ set_if_bigger(share->max_key_length,keyinfo->key_length+
+ keyinfo->key_parts);
+ share->total_key_length+= keyinfo->key_length;
if (keyinfo->flags & HA_NOSAME)
- set_if_bigger(outparam->max_unique_length,keyinfo->key_length);
+ set_if_bigger(share->max_unique_length, keyinfo->key_length);
}
if (primary_key < MAX_KEY &&
- (outparam->keys_in_use.is_set(primary_key)))
+ (share->keys_in_use.is_set(primary_key)))
{
- outparam->primary_key=primary_key;
+ share->primary_key= primary_key;
/*
If we are using an integer as the primary key then allow the user to
refer to it as '_rowid'
@@ -702,27 +753,25 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
}
}
else
- outparam->primary_key = MAX_KEY; // we do not have a primary key
+ share->primary_key = MAX_KEY; // we do not have a primary key
}
else
- outparam->primary_key= MAX_KEY;
+ share->primary_key= MAX_KEY;
x_free((gptr) disk_buff);
disk_buff=0;
if (new_field_pack_flag <= 1)
- { /* Old file format with default null */
- uint null_length=(outparam->null_fields+7)/8;
- bfill(outparam->null_flags,null_length,255);
- bfill(outparam->null_flags+outparam->rec_buff_length,null_length,255);
- if (records > 2)
- bfill(outparam->null_flags+outparam->rec_buff_length*2,null_length,255);
+ {
+ /* Old file format with default as not null */
+ uint null_length= (share->null_fields+7)/8;
+ bfill(share->default_values + (outparam->null_flags - (uchar*) record),
+ null_length, 255);
}
-
if ((reg_field=outparam->found_next_number_field))
{
- if ((int) (outparam->next_number_index= (uint)
+ if ((int) (share->next_number_index= (uint)
find_ref_key(outparam,reg_field,
- &outparam->next_number_key_offset)) < 0)
+ &share->next_number_key_offset)) < 0)
{
reg_field->unireg_check=Field::NONE; /* purecov: inspected */
outparam->found_next_number_field=0;
@@ -731,84 +780,85 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
reg_field->flags|=AUTO_INCREMENT_FLAG;
}
- if (outparam->blob_fields)
+ if (share->blob_fields)
{
Field **ptr;
- Field_blob **save;
-
- if (!(outparam->blob_field=save=
- (Field_blob**) alloc_root(&outparam->mem_root,
- (uint) (outparam->blob_fields+1)*
- sizeof(Field_blob*))))
- goto err_not_open;
- for (ptr=outparam->field ; *ptr ; ptr++)
+ uint i, *save;
+
+ /* Store offsets to blob fields to find them fast */
+ if (!(share->blob_field= save=
+ (uint*) alloc_root(&outparam->mem_root,
+ (uint) (share->blob_fields* sizeof(uint)))))
+ goto err;
+ for (i=0, ptr= outparam->field ; *ptr ; ptr++, i++)
{
if ((*ptr)->flags & BLOB_FLAG)
- (*save++)= (Field_blob*) *ptr;
+ (*save++)= i;
}
- *save=0; // End marker
}
- else
- outparam->blob_field=
- (Field_blob**) (outparam->field+outparam->fields); // Point at null ptr
- /* The table struct is now initialzed; Open the table */
+ /* The table struct is now initialized; Open the table */
error=2;
if (db_stat)
{
- int err;
+ int ha_err;
unpack_filename(index_file,index_file);
- if ((err=(outparam->file->
- ha_open(index_file,
- (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
- (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
- ((db_stat & HA_WAIT_IF_LOCKED) ||
- (specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
- HA_OPEN_WAIT_IF_LOCKED :
- (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
- HA_OPEN_ABORT_IF_LOCKED :
- HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
+ if ((ha_err= (outparam->file->
+ ha_open(index_file,
+ (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
+ (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
+ ((db_stat & HA_WAIT_IF_LOCKED) ||
+ (specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
+ HA_OPEN_WAIT_IF_LOCKED :
+ (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
+ HA_OPEN_ABORT_IF_LOCKED :
+ HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
{
/* Set a flag if the table is crashed and it can be auto. repaired */
- outparam->crashed=((err == HA_ERR_CRASHED_ON_USAGE) &&
- outparam->file->auto_repair() &&
- !(ha_open_flags & HA_OPEN_FOR_REPAIR));
+ share->crashed= ((ha_err == HA_ERR_CRASHED_ON_USAGE) &&
+ outparam->file->auto_repair() &&
+ !(ha_open_flags & HA_OPEN_FOR_REPAIR));
- if (err==HA_ERR_NO_SUCH_TABLE)
+ if (ha_err == HA_ERR_NO_SUCH_TABLE)
{
/* The table did not exists in storage engine, use same error message
as if the .frm file didn't exist */
error= 1;
my_errno= ENOENT;
}
- goto err_not_open; /* purecov: inspected */
+ else
+ {
+ outparam->file->print_error(ha_err, MYF(0));
+ error_reported= TRUE;
+ }
+ goto err; /* purecov: inspected */
}
}
- outparam->db_low_byte_first=outparam->file->low_byte_first();
+ share->db_low_byte_first= outparam->file->low_byte_first();
*root_ptr= old_root;
- opened_tables++;
+ thd->status_var.opened_tables++;
#ifndef DBUG_OFF
if (use_hash)
- (void) hash_check(&outparam->name_hash);
+ (void) hash_check(&share->name_hash);
#endif
DBUG_RETURN (0);
- err_not_open:
+ err:
x_free((gptr) disk_buff);
if (file > 0)
VOID(my_close(file,MYF(MY_WME)));
- err_end: /* Here when no file */
delete crypted;
*root_ptr= old_root;
- frm_error(error, outparam, name, ME_ERROR + ME_WAITTANG, errarg);
+ if (! error_reported)
+ frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG, errarg);
delete outparam->file;
- outparam->file=0; // For easyer errorchecking
+ outparam->file=0; // For easier errorchecking
outparam->db_stat=0;
- hash_free(&outparam->name_hash);
- free_root(&outparam->mem_root,MYF(0));
- my_free(outparam->table_name,MYF(MY_ALLOW_ZERO_PTR));
+ hash_free(&share->name_hash);
+ free_root(&outparam->mem_root, MYF(0)); // Safe to call on bzero'd root
+ my_free((char*) outparam->alias, MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN (error);
} /* openfrm */
@@ -821,21 +871,18 @@ int closefrm(register TABLE *table)
DBUG_ENTER("closefrm");
if (table->db_stat)
error=table->file->close();
- if (table->table_name)
- {
- my_free(table->table_name,MYF(0));
- table->table_name=0;
- }
- if (table->fields)
+ my_free((char*) table->alias, MYF(MY_ALLOW_ZERO_PTR));
+ table->alias= 0;
+ if (table->field)
{
for (Field **ptr=table->field ; *ptr ; ptr++)
delete *ptr;
- table->fields=0;
+ table->field= 0;
}
delete table->file;
- table->file=0; /* For easyer errorchecking */
- hash_free(&table->name_hash);
- free_root(&table->mem_root,MYF(0));
+ table->file= 0; /* For easier errorchecking */
+ hash_free(&table->s->name_hash);
+ free_root(&table->mem_root, MYF(0));
DBUG_RETURN(error);
}
@@ -844,8 +891,11 @@ int closefrm(register TABLE *table)
void free_blobs(register TABLE *table)
{
- for (Field_blob **ptr=table->blob_field ; *ptr ; ptr++)
- (*ptr)->free();
+ uint *ptr, *end;
+ for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
+ ptr != end ;
+ ptr++)
+ ((Field_blob*) table->field[*ptr])->free();
}
@@ -993,6 +1043,7 @@ static void frm_error(int error, TABLE *form, const char *name,
int err_no;
char buff[FN_REFLEN];
const char *form_dev="",*datext;
+ const char *real_name= (char*) name+dirname_length(name);
DBUG_ENTER("frm_error");
switch (error) {
@@ -1003,11 +1054,11 @@ static void frm_error(int error, TABLE *form, const char *name,
uint length=dirname_part(buff,name);
buff[length-1]=0;
db=buff+dirname_length(buff);
- my_error(ER_NO_SUCH_TABLE,MYF(0),db,form->real_name);
+ my_error(ER_NO_SUCH_TABLE, MYF(0), db, real_name);
}
else
- my_error(ER_FILE_NOT_FOUND,errortype,
- fn_format(buff,name,form_dev,reg_ext,0),my_errno);
+ my_error(ER_FILE_NOT_FOUND, errortype,
+ fn_format(buff, name, form_dev, reg_ext, 0), my_errno);
break;
case 2:
{
@@ -1016,7 +1067,7 @@ static void frm_error(int error, TABLE *form, const char *name,
err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ?
ER_FILE_USED : ER_CANT_OPEN_FILE;
my_error(err_no,errortype,
- fn_format(buff,form->real_name,form_dev,datext,2),my_errno);
+ fn_format(buff,real_name,form_dev,datext,2),my_errno);
break;
}
case 5:
@@ -1030,13 +1081,13 @@ static void frm_error(int error, TABLE *form, const char *name,
}
my_printf_error(ER_UNKNOWN_COLLATION,
"Unknown collation '%s' in table '%-.64s' definition",
- MYF(0), csname, form->real_name);
+ MYF(0), csname, real_name);
break;
}
default: /* Better wrong error than none */
case 4:
- my_error(ER_NOT_FORM_FILE,errortype,
- fn_format(buff,name,form_dev,reg_ext,0));
+ my_error(ER_NOT_FORM_FILE, errortype,
+ fn_format(buff, name, form_dev, reg_ext, 0));
break;
}
DBUG_VOID_RETURN;
@@ -1045,7 +1096,7 @@ static void frm_error(int error, TABLE *form, const char *name,
/*
** fix a str_type to a array type
- ** typeparts sepearated with some char. differents types are separated
+ ** typeparts separated with some char. differents types are separated
** with a '\0'
*/
@@ -1107,22 +1158,27 @@ TYPELIB *typelib(List<String> &strings)
}
- /*
- ** Search after a field with given start & length
- ** If an exact field isn't found, return longest field with starts
- ** at right position.
- ** Return 0 on error, else field number+1
- ** This is needed because in some .frm fields 'fieldnr' was saved wrong
- */
+/*
+ Search after a field with given start & length
+ If an exact field isn't found, return longest field with starts
+ at right position.
+
+ NOTES
+ This is needed because in some .frm fields 'fieldnr' was saved wrong
+
+ RETURN
+ 0 error
+ # field number +1
+*/
static uint find_field(TABLE *form,uint start,uint length)
{
Field **field;
- uint i,pos;
+ uint i, pos, fields;
pos=0;
-
- for (field=form->field, i=1 ; i<= form->fields ; i++,field++)
+ fields= form->s->fields;
+ for (field=form->field, i=1 ; i<= fields ; i++,field++)
{
if ((*field)->offset() == start)
{
@@ -1137,7 +1193,7 @@ static uint find_field(TABLE *form,uint start,uint length)
}
- /* Check that the integer is in the internvall */
+ /* Check that the integer is in the internal */
int set_zone(register int nr, int min_zone, int max_zone)
{
@@ -1201,7 +1257,7 @@ void append_unescaped(String *res, const char *pos, uint length)
res->append('n');
break;
case '\r':
- res->append('\\'); /* This gives better readbility */
+ res->append('\\'); /* This gives better readability */
res->append('r');
break;
case '\\':
@@ -1250,7 +1306,11 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
if ((file= my_create(name, CREATE_MODE, create_flags, MYF(MY_WME))) >= 0)
{
bzero((char*) fileinfo,64);
- fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+3; // Header
+ /* header */
+ fileinfo[0]=(uchar) 254;
+ fileinfo[1]= 1;
+ fileinfo[2]= FRM_VER+3+ test(create_info->varchar);
+
fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
fileinfo[4]=1;
int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
@@ -1266,6 +1326,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers
int2store(fileinfo+30,create_info->table_options);
fileinfo[32]=0; // No filename anymore
+ fileinfo[33]=5; // Mark for 5.0 frm file
int4store(fileinfo+34,create_info->avg_row_length);
fileinfo[38]= (create_info->default_table_charset ?
create_info->default_table_charset->number : 0);
@@ -1290,17 +1351,20 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
{
+ TABLE_SHARE *share= table->s;
DBUG_ENTER("update_create_info_from_table");
- create_info->max_rows=table->max_rows;
- create_info->min_rows=table->min_rows;
- create_info->table_options=table->db_create_options;
- create_info->avg_row_length=table->avg_row_length;
- create_info->row_type=table->row_type;
- create_info->raid_type=table->raid_type;
- create_info->raid_chunks=table->raid_chunks;
- create_info->raid_chunksize=table->raid_chunksize;
- create_info->default_table_charset=table->table_charset;
+
+ create_info->max_rows= share->max_rows;
+ create_info->min_rows= share->min_rows;
+ create_info->table_options= share->db_create_options;
+ create_info->avg_row_length= share->avg_row_length;
+ create_info->row_type= share->row_type;
+ create_info->raid_type= share->raid_type;
+ create_info->raid_chunks= share->raid_chunks;
+ create_info->raid_chunksize= share->raid_chunksize;
+ create_info->default_table_charset= share->table_charset;
create_info->table_charset= 0;
+
DBUG_VOID_RETURN;
}
@@ -1336,8 +1400,12 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res)
field->val_str(&str);
if (!(length= str.length()))
+ {
+ res->length(0);
return 1;
- to= strmake_root(mem, str.ptr(), length);
+ }
+ if (!(to= strmake_root(mem, str.ptr(), length)))
+ length= 0; // Safety fix
res->set(to, length, ((Field_str*)field)->charset());
return 0;
}
@@ -1403,7 +1471,7 @@ bool check_db_name(char *name)
if (use_mb(system_charset_info))
{
int len=my_ismbchar(system_charset_info, name,
- name+system_charset_info->mbmaxlen);
+ name+system_charset_info->mbmaxlen);
if (len)
{
name += len;
@@ -1472,7 +1540,7 @@ bool check_column_name(const char *name)
{
const char *start= name;
bool last_char_is_space= TRUE;
-
+
while (*name)
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
@@ -1480,7 +1548,7 @@ bool check_column_name(const char *name)
if (use_mb(system_charset_info))
{
int len=my_ismbchar(system_charset_info, name,
- name+system_charset_info->mbmaxlen);
+ name+system_charset_info->mbmaxlen);
if (len)
{
name += len;
@@ -1515,12 +1583,588 @@ db_type get_table_type(const char *name)
error=my_read(file,(byte*) head,4,MYF(MY_NABP));
my_close(file,MYF(0));
if (error || head[0] != (uchar) 254 || head[1] != 1 ||
- (head[2] != FRM_VER && head[2] != FRM_VER+1 && head[2] != FRM_VER+3))
+ (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)));
}
+/*
+ calculate md5 of query
+
+ SYNOPSIS
+ st_table_list::calc_md5()
+ buffer buffer for md5 writing
+*/
+
+void st_table_list::calc_md5(char *buffer)
+{
+ my_MD5_CTX context;
+ uchar digest[16];
+ my_MD5Init(&context);
+ my_MD5Update(&context,(uchar *) query.str, query.length);
+ my_MD5Final(digest, &context);
+ sprintf((char *) buffer,
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ digest[0], digest[1], digest[2], digest[3],
+ digest[4], digest[5], digest[6], digest[7],
+ digest[8], digest[9], digest[10], digest[11],
+ digest[12], digest[13], digest[14], digest[15]);
+}
+
+
+/*
+ set ancestor TABLE for table place holder of VIEW
+
+ DESCRIPTION
+ Replace all views that only uses one table with the table itself.
+ This allows us to treat the view as a simple table and even update
+ it
+
+ SYNOPSIS
+ st_table_list::set_ancestor()
+*/
+
+void st_table_list::set_ancestor()
+{
+ TABLE_LIST *tbl;
+
+ if ((tbl= ancestor))
+ {
+ /* This is a view. Process all tables of view */
+ DBUG_ASSERT(view);
+ do
+ {
+ if (tbl->ancestor) // This is a view
+ {
+ /*
+ This is the only case where set_ancestor is called on an object
+ that may not be a view (in which case ancestor is 0)
+ */
+ tbl->ancestor->set_ancestor();
+ }
+ tbl->table->grant= grant;
+ } while ((tbl= tbl->next_local));
+
+ /* if view contain only one table, substitute TABLE of it */
+ if (!ancestor->next_local)
+ {
+ table= ancestor->table;
+ schema_table= ancestor->schema_table;
+ }
+ }
+}
+
+
+/*
+ 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
+ {
+ DBUG_ASSERT(tbl->view && tbl->ancestor &&
+ tbl->ancestor->next_local);
+ 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
+ {
+ DBUG_ASSERT(tbl->view && tbl->ancestor &&
+ tbl->ancestor->next_local);
+ 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).
+ If there are underlying view(s) procedure first will be called for them.
+
+ RETURN
+ FALSE - OK
+ TRUE - error
+*/
+
+bool st_table_list::setup_ancestor(THD *thd, Item **conds,
+ uint8 check_opt_type)
+{
+ 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, (char *)&res))
+ return TRUE;
+
+ for (tbl= ancestor; tbl; tbl= tbl->next_local)
+ {
+ if (tbl->ancestor &&
+ tbl->setup_ancestor(thd, conds,
+ (check_opt_type == VIEW_CHECK_CASCADED ?
+ VIEW_CHECK_CASCADED :
+ VIEW_CHECK_NONE)))
+ 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;
+
+ 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++)
+ {
+ if (!transl->item->fixed &&
+ transl->item->fix_fields(thd, ancestor, &transl->item))
+ goto err;
+ }
+ for (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 (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();
+
+ /* WHERE/ON resolved => we can rename fields */
+ for (transl= field_translation; transl < end; transl++)
+ {
+ transl->item->rename((char *)transl->name);
+ }
+ goto ok;
+ }
+
+ /* 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
+ }
+
+ select_lex->no_wrap_view_item= 1;
+
+ /*
+ Resolve all view items against ancestor table.
+
+ 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 */
+
+ for (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 (where ||
+ (check_opt_type == VIEW_CHECK_CASCADED &&
+ ancestor->check_option))
+ {
+ Item_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)
+ check_option= where->copy_andor_structure(thd);
+ if (check_opt_type == VIEW_CHECK_CASCADED)
+ {
+ check_option= and_conds(check_option, ancestor->check_option);
+ }
+ }
+
+ /*
+ 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)
+ {
+ /* Go up to join tree and try to find left join */
+ for (; tbl; tbl= tbl->embedding)
+ {
+ if (tbl->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)
+ */
+ tbl->on_expr= and_conds(tbl->on_expr, where);
+ break;
+ }
+ }
+ 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);
+ }
+ }
+ }
+
+ 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;
+
+ /* WHERE/ON resolved => we can rename fields */
+ {
+ Field_translator *end= field_translation + select->item_list.elements;
+ for (transl= field_translation; transl < end; transl++)
+ {
+ transl->item->rename((char *)transl->name);
+ }
+ }
+
+ /* full text function moving to current select */
+ if (view->select_lex.ftfunc_list->elements)
+ {
+ Item_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);
+ }
+
+ goto ok;
+
+err:
+ res= TRUE;
+ /* 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)
+ {
+ 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);
+}
+
+
+/*
+ Find underlying base tables (TABLE_LIST) which represent given
+ table_to_find (TABLE)
+
+ SYNOPSIS
+ st_table_list::find_underlying_table()
+ table_to_find table to find
+
+ RETURN
+ 0 table is not found
+ found table reference
+*/
+
+st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find)
+{
+ /* is this real table and table which we are looking for? */
+ if (table == table_to_find && ancestor == 0)
+ return this;
+
+ for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ {
+ TABLE_LIST *result;
+ if ((result= tbl->find_underlying_table(table_to_find)))
+ return result;
+ }
+ return 0;
+}
+
+/*
+ cleunup items belonged to view fields translation table
+
+ SYNOPSIS
+ st_table_list::cleanup_items()
+*/
+
+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++)
+ transl->item->walk(&Item::cleanup_processor, 0);
+}
+
+
+/*
+ check CHECK OPTION condition
+
+ SYNOPSIS
+ check_option()
+ ignore_failure ignore check option fail
+
+ RETURN
+ VIEW_CHECK_OK OK
+ VIEW_CHECK_ERROR FAILED
+ VIEW_CHECK_SKIP FAILED, but continue
+*/
+
+int st_table_list::view_check_option(THD *thd, bool ignore_failure)
+{
+ if (check_option && check_option->val_int() == 0)
+ {
+ if (ignore_failure)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED),
+ view_db.str, view_name.str);
+ return(VIEW_CHECK_SKIP);
+ }
+ else
+ {
+ my_error(ER_VIEW_CHECK_FAILED, MYF(0), view_db.str, view_name.str);
+ return(VIEW_CHECK_ERROR);
+ }
+ }
+ return(VIEW_CHECK_OK);
+}
+
+
+/*
+ Find table in underlying tables by mask and check that only this
+ table belong to given mask
+
+ SYNOPSIS
+ st_table_list::check_single_table()
+ table reference on variable where to store found table
+ (should be 0 on call, to find table, or point to table for
+ unique test)
+ map bit mask of tables
+
+ RETURN
+ FALSE table not found or found only one
+ TRUE found several tables
+*/
+
+bool st_table_list::check_single_table(st_table_list **table, table_map map)
+{
+ for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ {
+ if (tbl->table)
+ {
+ if (tbl->table->map & map)
+ {
+ if (*table)
+ return TRUE;
+ else
+ *table= tbl;
+ }
+ }
+ else
+ if (tbl->check_single_table(table, map))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ Set insert_values buffer
+
+ SYNOPSIS
+ set_insert_values()
+ mem_root memory pool for allocating
+
+ RETURN
+ FALSE - OK
+ TRUE - out of memory
+*/
+
+bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
+{
+ if (table)
+ {
+ if (!table->insert_values &&
+ !(table->insert_values= (byte *)alloc_root(mem_root,
+ table->s->rec_buff_length)))
+ return TRUE;
+ }
+ else
+ {
+ DBUG_ASSERT(view && ancestor && ancestor->next_local);
+ for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ if (tbl->set_insert_values(mem_root))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+void Field_iterator_view::set(TABLE_LIST *table)
+{
+ ptr= table->field_translation;
+ array_end= ptr + table->view->select_lex.item_list.elements;
+}
+
+
+const char *Field_iterator_table::name()
+{
+ return (*ptr)->field_name;
+}
+
+
+Item *Field_iterator_table::item(THD *thd)
+{
+ return new Item_field(thd, *ptr);
+}
+
+
+const char *Field_iterator_view::name()
+{
+ return ptr->name;
+}
+
+
/*****************************************************************************
** Instansiate templates
*****************************************************************************/
diff --git a/sql/table.h b/sql/table.h
index 77153e5d8cd..0a4a06a75d1 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -20,6 +20,8 @@
class Item; /* Needed by ORDER */
class GRANT_TABLE;
class st_select_lex_unit;
+class st_select_lex;
+class COND_EQUAL;
/* Order clause list element */
@@ -27,12 +29,16 @@ typedef struct st_order {
struct st_order *next;
Item **item; /* Point at item in select fields */
Item *item_ptr; /* Storage for initial item */
+ Item **item_copy; /* For SPs; the original item ptr */
+ int counter; /* position in SELECT list, correct
+ only if counter_used is true*/
bool asc; /* true if ascending */
bool free_me; /* true if item isn't shared */
bool in_field_list; /* true if in select field list */
+ bool counter_used; /* parameter was counter of columns */
Field *field; /* If tmp-table group */
char *buff; /* If tmp-table group */
- table_map used,depend_map;
+ table_map used, depend_map;
} ORDER;
typedef struct st_grant_info
@@ -45,6 +51,13 @@ typedef struct st_grant_info
enum tmp_table_type {NO_TMP_TABLE=0, TMP_TABLE=1, TRANSACTIONAL_TMP_TABLE=2};
+enum frm_type_enum
+{
+ FRMTYPE_ERROR= 0,
+ FRMTYPE_TABLE,
+ FRMTYPE_VIEW
+};
+
typedef struct st_filesort_info
{
IO_CACHE *io_cache; /* If sorted through filebyte */
@@ -75,49 +88,119 @@ enum timestamp_auto_set_type
#define clear_timestamp_auto_bits(_target_, _bits_) \
(_target_)= (enum timestamp_auto_set_type)((int)(_target_) & ~(int)(_bits_))
-/* Table cache entry struct */
-
class Field_timestamp;
class Field_blob;
+class Table_triggers_list;
-struct st_table {
- handler *file;
- Field **field; /* Pointer to fields */
- Field_blob **blob_field; /* Pointer to blob fields */
+/* This structure is shared between different table objects */
+
+typedef struct st_table_share
+{
/* hash of field names (contains pointers to elements of field array) */
- HASH name_hash;
- byte *record[2]; /* Pointer to records */
- byte *default_values; /* Default values for INSERT */
- byte *insert_values; /* used by INSERT ... UPDATE */
- uint fields; /* field count */
- uint reclength; /* Recordlength */
- uint rec_buff_length;
- uint keys,key_parts,primary_key,max_key_length,max_unique_length;
- uint total_key_length;
- uint uniques;
- uint null_fields; /* number of null fields */
- uint blob_fields; /* number of blob fields */
- key_map keys_in_use, keys_for_keyread, read_only_keys;
- key_map quick_keys;
- key_map used_keys; /* keys that cover all used table fields */
- key_map keys_in_use_for_query;
- KEY *key_info; /* data of keys in database */
+ HASH name_hash; /* hash of field names */
+ MEM_ROOT mem_root;
TYPELIB keynames; /* Pointers to keynames */
- ha_rows max_rows; /* create information */
- ha_rows min_rows; /* create information */
- ulong avg_row_length; /* create information */
- ulong raid_chunksize;
TYPELIB fieldnames; /* Pointer to fieldnames */
TYPELIB *intervals; /* pointer to interval info */
+#ifdef NOT_YET
+ pthread_mutex_t mutex; /* For locking the share */
+ pthread_cond_t cond; /* To signal that share is ready */
+ struct st_table *open_tables; /* link to open tables */
+ struct st_table *used_next, /* Link to used tables */
+ **used_prev;
+ /* The following is copied to each TABLE on OPEN */
+ Field **field;
+ KEY *key_info; /* data of keys in database */
+#endif
+ uint *blob_field; /* Index to blobs in Field arrray*/
+ byte *default_values; /* row with default values */
+ char *comment; /* Comment about table */
+ CHARSET_INFO *table_charset; /* Default charset of string fields */
+
+ /* A pair "database_name\0table_name\0", widely used as simply a db name */
+ char *table_cache_key;
+ const char *db; /* Pointer to db */
+ const char *table_name; /* Table name (for open) */
+ const char *path; /* Path to .frm file (from datadir) */
+ key_map keys_in_use; /* Keys in use for table */
+ key_map keys_for_keyread;
+ ulong avg_row_length; /* create information */
+ ulong raid_chunksize;
+ ulong version, flush_version;
+ ulong timestamp_offset; /* Set to offset+1 of record */
+ ulong reclength; /* Recordlength */
+
+ ha_rows min_rows, max_rows; /* create information */
enum db_type db_type; /* table_type for handler */
enum row_type row_type; /* How rows are stored */
+ enum tmp_table_type tmp_table;
+
+ uint blob_ptr_size; /* 4 or 8 */
+ uint null_bytes;
+ uint key_length; /* Length of table_cache_key */
+ uint fields; /* Number of fields */
+ uint rec_buff_length; /* Size of table->record[] buffer */
+ uint keys, key_parts;
+ uint max_key_length, max_unique_length, total_key_length;
+ uint uniques; /* Number of UNIQUE index */
+ uint null_fields; /* number of null fields */
+ uint blob_fields; /* number of blob fields */
+ uint varchar_fields; /* number of varchar fields */
uint db_create_options; /* Create options from database */
uint db_options_in_use; /* Options in use */
uint db_record_offset; /* if HA_REC_IN_SEQ */
- uint db_stat; /* mode of file as in handler.h */
- uint raid_type,raid_chunks;
- uint status; /* Used by postfix.. */
- uint system; /* Set if system record */
+ uint raid_type, raid_chunks;
+ uint open_count; /* Number of tables in open list */
+ /* Index of auto-updated TIMESTAMP field in field array */
+ uint primary_key;
+ uint timestamp_field_offset;
+ uint next_number_index;
+ uint next_number_key_offset;
+ uchar frm_version;
+ my_bool system; /* Set if system record */
+ my_bool crypted; /* If .frm file is crypted */
+ my_bool db_low_byte_first; /* Portable row format */
+ my_bool crashed;
+ my_bool is_view;
+ my_bool name_lock, replace_with_name_lock;
+} TABLE_SHARE;
+
+
+/* Information for one open table */
+
+struct st_table {
+ TABLE_SHARE *s;
+ handler *file;
+#ifdef NOT_YET
+ struct st_table *used_next, **used_prev; /* Link to used tables */
+ struct st_table *open_next, **open_prev; /* Link to open tables */
+#endif
+ struct st_table *next, *prev;
+
+ THD *in_use; /* Which thread uses this */
+ Field **field; /* Pointer to fields */
+
+ byte *record[2]; /* Pointer to records */
+ byte *insert_values; /* used by INSERT ... UPDATE */
+ key_map quick_keys, used_keys, keys_in_use_for_query;
+ KEY *key_info; /* data of keys in database */
+
+ Field *next_number_field, /* Set if next_number is activated */
+ *found_next_number_field, /* Set on open */
+ *rowid_field;
+ Field_timestamp *timestamp_field;
+
+ /* Table's triggers, 0 if there are no of them */
+ Table_triggers_list *triggers;
+ struct st_table_list *pos_in_table_list;/* Element referring to this table */
+ ORDER *group;
+ const char *alias; /* alias or table name */
+ uchar *null_flags;
+ query_id_t query_id;
+
+ ha_rows quick_rows[MAX_KEY];
+ key_part_map const_key_parts[MAX_KEY];
+ uint quick_key_parts[MAX_KEY];
/*
If this table has TIMESTAMP field with auto-set property (pointed by
@@ -132,111 +215,305 @@ struct st_table {
as example).
*/
timestamp_auto_set_type timestamp_field_type;
- /* Index of auto-updated TIMESTAMP field in field array */
- uint timestamp_field_offset;
+ table_map map; /* ID bit of table (1,2,4,8,16...) */
- uint next_number_index;
- uint blob_ptr_size; /* 4 or 8 */
- uint next_number_key_offset;
- int current_lock; /* Type of lock on table */
- enum tmp_table_type tmp_table;
+ uint tablenr,used_fields;
+ uint temp_pool_slot; /* Used by intern temp tables */
+ uint status; /* What's in record[0] */
+ uint db_stat; /* mode of file as in handler.h */
+ /* number of select if it is derived table */
+ uint derived_select_number;
+ int current_lock; /* Type of lock on table */
my_bool copy_blobs; /* copy_blobs when storing */
+
+ /*
+ 0 or JOIN_TYPE_{LEFT|RIGHT}. Currently this is only compared to 0.
+ If maybe_null !=0, this table is inner w.r.t. some outer join operation,
+ and null_row may be true.
+ */
+ uint maybe_null;
/*
- Used in outer joins: if true, all columns are considered to have NULL
- values, including columns declared as "not null".
+ If true, the current table row is considered to have all columns set to
+ NULL, including columns declared as "not null" (see maybe_null).
*/
my_bool null_row;
- /* 0 or JOIN_TYPE_{LEFT|RIGHT}, same as TABLE_LIST::outer_join */
- my_bool outer_join;
- my_bool maybe_null; /* true if (outer_join != 0) */
my_bool force_index;
my_bool distinct,const_table,no_rows;
- my_bool key_read;
- my_bool crypted;
- my_bool db_low_byte_first; /* Portable row format */
+ my_bool key_read, no_keyread;
my_bool locked_by_flush;
my_bool locked_by_name;
my_bool fulltext_searched;
- my_bool crashed;
- my_bool is_view;
- my_bool no_keyread, no_cache;
- my_bool clear_query_id; /* To reset query_id for tables and cols */
+ my_bool no_cache;
+ /* To signal that we should reset query_id for tables and cols */
+ my_bool clear_query_id;
my_bool auto_increment_field_not_null;
- Field *next_number_field, /* Set if next_number is activated */
- *found_next_number_field, /* Set on open */
- *rowid_field;
- Field_timestamp *timestamp_field;
-#if MYSQL_VERSION_ID < 40100
- /*
- Indicates whenever we have to set field_length members of all TIMESTAMP
- fields to 19 (to honour 'new_mode' variable) or to original
- field_length values.
- */
- my_bool timestamp_mode;
-#endif
- my_string comment; /* Comment about table */
- CHARSET_INFO *table_charset; /* Default charset of string fields */
+ my_bool insert_or_update; /* Can be used by the handler */
+ my_bool alias_name_used; /* true if table_name is alias */
+
REGINFO reginfo; /* field connections */
MEM_ROOT mem_root;
GRANT_INFO grant;
-
- /* A pair "database_name\0table_name\0", widely used as simply a db name */
- char *table_cache_key;
- char *table_name,*real_name,*path;
- uint key_length; /* Length of key */
- uint tablenr,used_fields,null_bytes;
- table_map map; /* ID bit of table (1,2,4,8,16...) */
- ulong version,flush_version;
- uchar *null_flags;
FILESORT_INFO sort;
- ORDER *group;
- ha_rows quick_rows[MAX_KEY];
- uint quick_key_parts[MAX_KEY];
- key_part_map const_key_parts[MAX_KEY];
- ulong query_id;
- uchar frm_version;
-
- union /* Temporary variables */
- {
- uint temp_pool_slot; /* Used by intern temp tables */
- struct st_table_list *pos_in_table_list;
- };
- /* number of select if it is derived table */
- uint derived_select_number;
- THD *in_use; /* Which thread uses this */
- struct st_table *next,*prev;
+ TABLE_SHARE share_not_to_be_used; /* To be deleted when true shares */
+};
+
+
+typedef struct st_foreign_key_info
+{
+ LEX_STRING *forein_id;
+ LEX_STRING *referenced_db;
+ LEX_STRING *referenced_table;
+ LEX_STRING *constraint_method;
+ List<LEX_STRING> foreign_fields;
+ List<LEX_STRING> referenced_fields;
+} FOREIGN_KEY_INFO;
+
+
+enum enum_schema_tables
+{
+ SCH_SCHEMATA= 0, SCH_TABLES, SCH_COLUMNS, SCH_CHARSETS, SCH_COLLATIONS,
+ SCH_COLLATION_CHARACTER_SET_APPLICABILITY, SCH_PROCEDURES, SCH_STATISTICS,
+ SCH_VIEWS, SCH_USER_PRIVILEGES, SCH_SCHEMA_PRIVILEGES, SCH_TABLE_PRIVILEGES,
+ SCH_COLUMN_PRIVILEGES, SCH_TABLE_CONSTRAINTS, SCH_KEY_COLUMN_USAGE,
+ SCH_TABLE_NAMES, SCH_OPEN_TABLES, SCH_STATUS, SCH_VARIABLES
};
+typedef struct st_field_info
+{
+ const char* field_name;
+ uint field_length;
+ enum enum_field_types field_type;
+ int value;
+ bool maybe_null;
+ const char* old_name;
+} ST_FIELD_INFO;
+
+
+struct st_table_list;
+typedef class Item COND;
+
+typedef struct st_schema_table
+{
+ const char* table_name;
+ ST_FIELD_INFO *fields_info;
+ /* Create information_schema table */
+ TABLE *(*create_table) (THD *thd, struct st_table_list *table_list);
+ /* Fill table with data */
+ int (*fill_table) (THD *thd, struct st_table_list *tables, COND *cond);
+ /* Handle fileds for old SHOW */
+ int (*old_format) (THD *thd, struct st_schema_table *schema_table);
+ int (*process_table) (THD *thd, struct st_table_list *tables,
+ TABLE *table, bool res, const char *base_name,
+ const char *file_name);
+ int idx_field1, idx_field2;
+ bool hidden;
+} 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
+
+/* view WITH CHECK OPTION parameter options */
+#define VIEW_CHECK_NONE 0
+#define VIEW_CHECK_LOCAL 1
+#define VIEW_CHECK_CASCADED 2
+
+/* result of view WITH CHECK OPTION parameter check */
+#define VIEW_CHECK_OK 0
+#define VIEW_CHECK_ERROR 1
+#define VIEW_CHECK_SKIP 2
+
+struct st_lex;
+class select_union;
+class TMP_TABLE_PARAM;
+
+struct Field_translator
+{
+ Item *item;
+ const char *name;
+};
+
+
typedef struct st_table_list
{
- struct st_table_list *next;
- char *db, *alias, *real_name;
- char *option; /* Used by cache index */
+ /* link in a local table list (used by SQL_LIST) */
+ struct st_table_list *next_local;
+ /* link in a global list of all queries tables */
+ struct st_table_list *next_global, **prev_global;
+ char *db, *alias, *table_name, *schema_table_name;
+ char *option; /* Used by cache index */
Item *on_expr; /* Used with outer join */
+ /*
+ The scturcture of ON expression presented in the member above
+ can be changed during certain optimizations. This member
+ contains a snapshot of AND-OR structure of the ON expression
+ made after permanent transformations of the parse tree, and is
+ used to restore ON clause before every reexecution of a prepared
+ statement or stored procedure.
+ */
+ Item *prep_on_expr;
+ COND_EQUAL *cond_equal; /* Used with outer join */
struct st_table_list *natural_join; /* natural join on this table*/
/* ... join ... USE INDEX ... IGNORE INDEX */
- List<String> *use_index, *ignore_index;
- TABLE *table; /* opened table */
- st_table_list *table_list; /* pointer to node of list of all tables */
- class st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
- GRANT_INFO grant;
+ List<String> *use_index, *ignore_index;
+ TABLE *table; /* opened table */
+ /*
+ select_result for derived table to pass it from table creation to table
+ filling procedure
+ */
+ select_union *derived_result;
+ /*
+ Reference from aux_tables to local list entry of main select of
+ multi-delete statement:
+ delete t1 from t2,t1 where t1.a<'B' and t2.b=t1.b;
+ here it will be reference of first occurrence of t1 to second (as you
+ can see this lists can't be merged)
+ */
+ st_table_list *correspondent_table;
+ st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
+ ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
+ st_select_lex *schema_select_lex;
+ bool schema_table_reformed;
+ TMP_TABLE_PARAM *schema_table_param;
+ /* link to select_lex where this table was used */
+ st_select_lex *select_lex;
+ st_lex *view; /* link on VIEW lex for merging */
+ Field_translator *field_translation; /* array of VIEW fields */
+ /* list of ancestor(s) of this table (underlying table(s)/view(s) */
+ st_table_list *ancestor;
+ /* most upper view this table belongs to */
+ st_table_list *belong_to_view;
+ /* list of join table tree leaves */
+ st_table_list *next_leaf;
+ Item *where; /* VIEW WHERE clause condition */
+ Item *check_option; /* WITH CHECK OPTION condition */
+ LEX_STRING query; /* text of (CRETE/SELECT) statement */
+ LEX_STRING md5; /* md5 of query text */
+ LEX_STRING source; /* source of CREATE VIEW */
+ LEX_STRING view_db; /* saved view database */
+ LEX_STRING view_name; /* saved view name */
+ LEX_STRING timestamp; /* GMT time stamp of last operation */
+ ulonglong file_version; /* version of file's field set */
+ ulonglong updatable_view; /* VIEW can be updated */
+ ulonglong revision; /* revision control number */
+ ulonglong algorithm; /* 0 any, 1 tmp tables , 2 merging */
+ ulonglong with_check; /* WITH CHECK OPTION */
+ /*
+ effective value of WITH CHECK OPTION (differ for temporary table
+ algorithm)
+ */
+ uint8 effective_with_check;
+ uint effective_algorithm; /* which algorithm was really used */
+ uint privilege_backup; /* place for saving privileges */
+ GRANT_INFO grant;
+ /* data need by some engines in query cache*/
+ ulonglong engine_data;
+ /* call back function for asking handler about caching in query cache */
+ qc_engine_callback callback_func;
thr_lock_type lock_type;
uint outer_join; /* Which join type */
uint shared; /* Used in multi-upd */
- uint32 db_length, real_name_length;
+ uint32 db_length, table_name_length;
+ bool updatable; /* VIEW/TABLE can be updated now */
bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */
- bool force_index; /* Prefer index over table scan */
- bool ignore_leaves; /* Preload only non-leaf nodes */
+ 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 */
+ st_table_list *embedding; /* nested join containing the table */
+ List<struct st_table_list> *join_list;/* join list the table belongs to */
bool cacheable_table; /* stop PS caching */
- /* used in multi-upd privelege check */
- bool table_in_update_from_clause;
+ /* used in multi-upd/views privilege check */
+ bool table_in_first_from_clause;
+ bool skip_temporary; /* this table shouldn't be temporary */
+ /* TRUE if this merged view contain auto_increment field */
+ bool contain_auto_increment;
+ /* FRMTYPE_ERROR if any type is acceptable */
+ enum frm_type_enum required_type;
+ char timestamp_buffer[20]; /* buffer for timestamp (19+1) */
+ /*
+ This TABLE_LIST object is just placeholder for prelocking, it will be
+ used for implicit LOCK TABLES only and won't be used in real statement.
+ */
+ bool prelocking_placeholder;
+
+ 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);
+ 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);
+ bool set_insert_values(MEM_ROOT *mem_root);
+ st_table_list *find_underlying_table(TABLE *table);
} TABLE_LIST;
+class Item;
+
+class Field_iterator: public Sql_alloc
+{
+public:
+ virtual ~Field_iterator() {}
+ virtual void set(TABLE_LIST *)= 0;
+ 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 Field *field()= 0;
+};
+
+
+class Field_iterator_table: public Field_iterator
+{
+ Field **ptr;
+public:
+ Field_iterator_table() :ptr(0) {}
+ void set(TABLE_LIST *table) { ptr= table->table->field; }
+ void set_table(TABLE *table) { ptr= table->field; }
+ void next() { ptr++; }
+ bool end_of_fields() { return *ptr == 0; }
+ const char *name();
+ Item *item(THD *thd);
+ Field *field() { return *ptr; }
+};
+
+
+class Field_iterator_view: public Field_iterator
+{
+ Field_translator *ptr, *array_end;
+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 **item_ptr() {return &ptr->item; }
+ Field *field() { return 0; }
+};
+
+
+typedef struct st_nested_join
+{
+ List<TABLE_LIST> join_list; /* list of elements in the nested join */
+ table_map used_tables; /* bitmap of tables in the nested join */
+ table_map not_null_tables; /* tables that rejects nulls */
+ struct st_join_table *first_nested;/* the first nested table in the plan */
+ uint counter; /* to count tables in the nested join */
+} NESTED_JOIN;
+
+
typedef struct st_changed_table_list
{
struct st_changed_table_list *next;
@@ -244,8 +521,8 @@ typedef struct st_changed_table_list
uint32 key_length;
} CHANGED_TABLE_LIST;
-typedef struct st_open_table_list
-{
+
+typedef struct st_open_table_list{
struct st_open_table_list *next;
char *db,*table;
uint32 in_use,locked;
diff --git a/sql/time.cc b/sql/time.cc
index e76b169b336..a3ec2283860 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -33,15 +33,6 @@ int calc_weekday(long daynr,bool sunday_first_day_of_week)
DBUG_RETURN ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
}
- /* Calc days in one year. works with 0 <= year <= 99 */
-
-uint calc_days_in_year(uint year)
-{
- return (year & 3) == 0 && (year%100 || (year%400 == 0 && year)) ?
- 366 : 365;
-}
-
-
/*
The bits in week_format has the following meaning:
WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week
@@ -195,14 +186,22 @@ ulong convert_month_to_period(ulong month)
NOTE
See description of str_to_datetime() for more information.
*/
+
timestamp_type
str_to_datetime_with_warn(const char *str, uint length, TIME *l_time,
uint flags)
{
int was_cut;
- timestamp_type ts_type= str_to_datetime(str, length, l_time, flags, &was_cut);
- if (was_cut)
- make_truncated_value_warning(current_thd, str, length, ts_type);
+ THD *thd= current_thd;
+ timestamp_type ts_type;
+
+ ts_type= str_to_datetime(str, length, l_time,
+ (flags | (thd->variables.sql_mode &
+ (MODE_INVALID_DATES |
+ MODE_NO_ZERO_DATE))),
+ &was_cut);
+ if (was_cut || ts_type <= MYSQL_TIMESTAMP_ERROR)
+ make_truncated_value_warning(current_thd, str, length, ts_type, NullS);
return ts_type;
}
@@ -258,101 +257,13 @@ str_to_time_with_warn(const char *str, uint length, TIME *l_time)
int was_cut;
bool ret_val= str_to_time(str, length, l_time, &was_cut);
if (was_cut)
- make_truncated_value_warning(current_thd, str, length, MYSQL_TIMESTAMP_TIME);
+ make_truncated_value_warning(current_thd, str, length,
+ MYSQL_TIMESTAMP_TIME, NullS);
return ret_val;
}
/*
- Convert datetime value specified as number to broken-down TIME
- representation and form value of DATETIME type as side-effect.
-
- SYNOPSIS
- number_to_TIME()
- nr - datetime value as number
- time_res - pointer for structure for broken-down representation
- fuzzy_date - indicates whenever we allow fuzzy dates
- was_cut - set ot 1 if there was some kind of error during
- conversion or to 0 if everything was OK.
-
- DESCRIPTION
- Convert a datetime value of formats YYMMDD, YYYYMMDD, YYMMDDHHMSS,
- YYYYMMDDHHMMSS to broken-down TIME representation. Return value in
- YYYYMMDDHHMMSS format as side-effect.
-
- This function also checks if datetime value fits in DATETIME range.
-
- RETURN VALUE
- Datetime value in YYYYMMDDHHMMSS format.
- If input value is not valid datetime value then 0 is returned.
-*/
-
-longlong number_to_TIME(longlong nr, TIME *time_res, bool fuzzy_date,
- int *was_cut)
-{
- long part1,part2;
-
- *was_cut= 0;
-
- if (nr == LL(0) || nr >= LL(10000101000000))
- goto ok;
- if (nr < 101)
- goto err;
- if (nr <= (YY_PART_YEAR-1)*10000L+1231L)
- {
- nr= (nr+20000000L)*1000000L; // YYMMDD, year: 2000-2069
- goto ok;
- }
- if (nr < (YY_PART_YEAR)*10000L+101L)
- goto err;
- if (nr <= 991231L)
- {
- nr= (nr+19000000L)*1000000L; // YYMMDD, year: 1970-1999
- goto ok;
- }
- if (nr < 10000101L)
- goto err;
- if (nr <= 99991231L)
- {
- nr= nr*1000000L;
- goto ok;
- }
- if (nr < 101000000L)
- goto err;
- if (nr <= (YY_PART_YEAR-1)*LL(10000000000)+LL(1231235959))
- {
- nr= nr+LL(20000000000000); // YYMMDDHHMMSS, 2000-2069
- goto ok;
- }
- if (nr < YY_PART_YEAR*LL(10000000000)+ LL(101000000))
- goto err;
- if (nr <= LL(991231235959))
- nr= nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999
-
- ok:
- part1=(long) (nr/LL(1000000));
- part2=(long) (nr - (longlong) part1*LL(1000000));
- time_res->year= (int) (part1/10000L); part1%=10000L;
- time_res->month= (int) part1 / 100;
- time_res->day= (int) part1 % 100;
- time_res->hour= (int) (part2/10000L); part2%=10000L;
- time_res->minute=(int) part2 / 100;
- time_res->second=(int) part2 % 100;
-
- if (time_res->year <= 9999 && time_res->month <= 12 &&
- time_res->day <= 31 && time_res->hour <= 23 &&
- time_res->minute <= 59 && time_res->second <= 59 &&
- (fuzzy_date || (time_res->month != 0 && time_res->day != 0) || nr==0))
- return nr;
-
- err:
-
- *was_cut= 1;
- return LL(0);
-}
-
-
-/*
Convert a system time structure to TIME
*/
@@ -772,16 +683,15 @@ void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
void make_truncated_value_warning(THD *thd, const char *str_val,
- uint str_length, timestamp_type time_type)
+ uint str_length, timestamp_type time_type,
+ const char *field_name)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
const char *type_str;
-
+ CHARSET_INFO *cs= &my_charset_latin1;
char buff[128];
String str(buff,(uint32) sizeof(buff), system_charset_info);
- str.length(0);
- str.append(str_val, str_length);
- str.append('\0');
+ str.copy(str_val, str_length, system_charset_info);
switch (time_type) {
case MYSQL_TIMESTAMP_DATE:
@@ -795,84 +705,18 @@ void make_truncated_value_warning(THD *thd, const char *str_val,
type_str= "datetime";
break;
}
- sprintf(warn_buff, ER(ER_TRUNCATED_WRONG_VALUE),
- type_str, str.ptr());
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE, warn_buff);
-}
-
-
-/* Convert time value to integer in YYYYMMDDHHMMSS format */
-
-ulonglong TIME_to_ulonglong_datetime(const TIME *time)
-{
- return ((ulonglong) (time->year * 10000UL +
- time->month * 100UL +
- time->day) * ULL(1000000) +
- (ulonglong) (time->hour * 10000UL +
- time->minute * 100UL +
- time->second));
-}
-
-
-/* Convert TIME value to integer in YYYYMMDD format */
-
-ulonglong TIME_to_ulonglong_date(const TIME *time)
-{
- return (ulonglong) (time->year * 10000UL + time->month * 100UL + time->day);
-}
-
-
-/*
- Convert TIME value to integer in HHMMSS format.
- This function doesn't take into account time->day member:
- it's assumed that days have been converted to hours already.
-*/
-
-ulonglong TIME_to_ulonglong_time(const TIME *time)
-{
- return (ulonglong) (time->hour * 10000UL +
- time->minute * 100UL +
- time->second);
+ if (field_name)
+ cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ type_str, str.c_ptr(), field_name,
+ (ulong) thd->row_count);
+ else
+ cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
+ ER(ER_TRUNCATED_WRONG_VALUE),
+ type_str, str.c_ptr());
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE, warn_buff);
}
-/*
- Convert struct TIME (date and time split into year/month/day/hour/...
- to a number in format YYYYMMDDHHMMSS (DATETIME),
- YYYYMMDD (DATE) or HHMMSS (TIME).
-
- SYNOPSIS
- TIME_to_ulonglong()
-
- DESCRIPTION
- The function is used when we need to convert value of time item
- to a number if it's used in numeric context, i. e.:
- SELECT NOW()+1, CURDATE()+0, CURTIMIE()+0;
- SELECT ?+1;
-
- NOTE
- This function doesn't check that given TIME structure members are
- in valid range. If they are not, return value won't reflect any
- valid date either.
-*/
-
-ulonglong TIME_to_ulonglong(const TIME *time)
-{
- switch (time->time_type) {
- case MYSQL_TIMESTAMP_DATETIME:
- return TIME_to_ulonglong_datetime(time);
- case MYSQL_TIMESTAMP_DATE:
- return TIME_to_ulonglong_date(time);
- case MYSQL_TIMESTAMP_TIME:
- return TIME_to_ulonglong_time(time);
- case MYSQL_TIMESTAMP_NONE:
- case MYSQL_TIMESTAMP_ERROR:
- return ULL(0);
- default:
- DBUG_ASSERT(0);
- }
- return 0;
-}
-
#endif
diff --git a/sql/tztime.cc b/sql/tztime.cc
index c45271966f9..983c630071e 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -1395,44 +1395,72 @@ extern "C" byte* my_offset_tzs_get_key(Time_zone_offset *entry, uint *length,
/*
- Prepare table list with time zone related tables from preallocated array.
+ Prepare table list with time zone related tables from preallocated array
+ and add to global table list.
SYNOPSIS
tz_init_table_list()
- tz_tabs - pointer to preallocated array of 4 TABLE_LIST objects.
+ tz_tabs - pointer to preallocated array of 4 TABLE_LIST objects
+ global_next_ptr - pointer to variable which points to global_next member
+ of last element of global table list (or list root
+ then list is empty) (in/out).
DESCRIPTION
This function prepares list of TABLE_LIST objects which can be used
- for opening of time zone tables from preallocated array.
+ for opening of time zone tables from preallocated array. It also links
+ this list to the end of global table list (it will read and update
+ accordingly variable pointed by global_next_ptr for this).
*/
-void
-tz_init_table_list(TABLE_LIST *tz_tabs)
+static void
+tz_init_table_list(TABLE_LIST *tz_tabs, TABLE_LIST ***global_next_ptr)
{
bzero(tz_tabs, sizeof(TABLE_LIST) * 4);
- tz_tabs[0].alias= tz_tabs[0].real_name= (char*)"time_zone_name";
- tz_tabs[1].alias= tz_tabs[1].real_name= (char*)"time_zone";
- tz_tabs[2].alias= tz_tabs[2].real_name= (char*)"time_zone_transition_type";
- tz_tabs[3].alias= tz_tabs[3].real_name= (char*)"time_zone_transition";
- tz_tabs[0].next= tz_tabs+1;
- tz_tabs[1].next= tz_tabs+2;
- tz_tabs[2].next= tz_tabs+3;
+ tz_tabs[0].alias= tz_tabs[0].table_name= (char*)"time_zone_name";
+ tz_tabs[1].alias= tz_tabs[1].table_name= (char*)"time_zone";
+ tz_tabs[2].alias= tz_tabs[2].table_name= (char*)"time_zone_transition_type";
+ tz_tabs[3].alias= tz_tabs[3].table_name= (char*)"time_zone_transition";
+ tz_tabs[0].next_global= tz_tabs[0].next_local= tz_tabs+1;
+ tz_tabs[1].next_global= tz_tabs[1].next_local= tz_tabs+2;
+ tz_tabs[2].next_global= tz_tabs[2].next_local= tz_tabs+3;
tz_tabs[0].lock_type= tz_tabs[1].lock_type= tz_tabs[2].lock_type=
tz_tabs[3].lock_type= TL_READ;
tz_tabs[0].db= tz_tabs[1].db= tz_tabs[2].db= tz_tabs[3].db= (char *)"mysql";
+
+ /* Link into global list */
+ tz_tabs[0].prev_global= *global_next_ptr;
+ tz_tabs[1].prev_global= &tz_tabs[0].next_global;
+ tz_tabs[2].prev_global= &tz_tabs[1].next_global;
+ tz_tabs[3].prev_global= &tz_tabs[2].next_global;
+
+ **global_next_ptr= tz_tabs;
+ /* Update last-global-pointer to point to pointer in last table */
+ *global_next_ptr= &tz_tabs[3].next_global;
}
/*
- Create table list with time zone related tables.
+ Fake table list object, pointer to which is returned by
+ my_tz_get_tables_list() as indication of error.
+*/
+TABLE_LIST fake_time_zone_tables_list;
+
+/*
+ Create table list with time zone related tables and add it to the end
+ of global table list.
SYNOPSIS
my_tz_get_table_list()
- thd - current thread object
+ thd - current thread object
+ global_next_ptr - pointer to variable which points to global_next member
+ of last element of global table list (or list root
+ then list is empty) (in/out).
DESCRIPTION
This function creates list of TABLE_LIST objects allocated in thd's
- memroot, which can be used for opening of time zone tables.
+ memroot, which can be used for opening of time zone tables. It will also
+ link this list to the end of global table list (it will read and update
+ accordingly variable pointed by global_next_ptr for this).
NOTE
my_tz_check_n_skip_implicit_tables() function depends on fact that
@@ -1444,19 +1472,20 @@ tz_init_table_list(TABLE_LIST *tz_tabs)
*/
TABLE_LIST *
-my_tz_get_table_list(THD *thd)
+my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr)
{
TABLE_LIST *tz_tabs;
+ DBUG_ENTER("my_tz_get_table_list");
if (!time_zone_tables_exist)
- return 0;
+ DBUG_RETURN(0);
if (!(tz_tabs= (TABLE_LIST *)thd->alloc(sizeof(TABLE_LIST) * 4)))
- return &fake_time_zone_tables_list;
+ DBUG_RETURN(&fake_time_zone_tables_list);
- tz_init_table_list(tz_tabs);
+ tz_init_table_list(tz_tabs, global_next_ptr);
- return tz_tabs;
+ DBUG_RETURN(tz_tabs);
}
@@ -1490,12 +1519,11 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
{
THD *thd;
TABLE_LIST *tables= 0;
- TABLE_LIST tables_buff[5];
+ TABLE_LIST tables_buff[5], **last_global_next_ptr;
TABLE *table;
TZ_NAMES_ENTRY *tmp_tzname;
my_bool return_val= 1;
int res;
- uint counter;
DBUG_ENTER("my_tz_init");
/*
@@ -1553,16 +1581,18 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
thd->db= my_strdup("mysql",MYF(0));
thd->db_length= 5; // Safety
bzero((char*) &tables_buff, sizeof(TABLE_LIST));
- tables_buff[0].alias= tables_buff[0].real_name=
+ tables_buff[0].alias= tables_buff[0].table_name=
(char*)"time_zone_leap_second";
tables_buff[0].lock_type= TL_READ;
tables_buff[0].db= thd->db;
- tables_buff[0].next= tables_buff + 1;
- /* Fill TABLE_LIST for rest of the time zone describing tables */
- tz_init_table_list(tables_buff + 1);
+ /*
+ Fill TABLE_LIST for the rest of the time zone describing tables
+ and link it to first one.
+ */
+ last_global_next_ptr= &(tables_buff[0].next_global);
+ tz_init_table_list(tables_buff + 1, &last_global_next_ptr);
- if (open_tables(thd, tables_buff, &counter) ||
- lock_tables(thd, tables_buff, counter))
+ if (simple_open_n_lock_tables(thd, tables_buff))
{
sql_print_warning("Can't open and lock time zone table: %s "
"trying to live without them", thd->net.last_error);
@@ -1761,8 +1791,9 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
and it is specifically for this purpose).
*/
table= tz_tables->table;
- tz_tables= tz_tables->next;
- table->field[0]->store(tz_name->ptr(), tz_name->length(), &my_charset_latin1);
+ tz_tables= tz_tables->next_local;
+ table->field[0]->store(tz_name->ptr(), tz_name->length(),
+ &my_charset_latin1);
/*
It is OK to ignore ha_index_init()/ha_index_end() return values since
mysql.time_zone* tables are MyISAM and these operations always succeed
@@ -1793,7 +1824,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
using the only index in this table).
*/
table= tz_tables->table;
- tz_tables= tz_tables->next;
+ tz_tables= tz_tables->next_local;
table->field[0]->store((longlong)tzid);
(void)table->file->ha_index_init(0);
@@ -1820,7 +1851,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
Right - using special index.
*/
table= tz_tables->table;
- tz_tables= tz_tables->next;
+ tz_tables= tz_tables->next_local;
table->field[0]->store((longlong)tzid);
(void)table->file->ha_index_init(0);
@@ -2147,7 +2178,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
DBUG_PRINT("enter", ("time zone name='%s'",
name ? ((String *)name)->c_ptr() : "NULL"));
- DBUG_ASSERT(!time_zone_tables_exist || tz_tables);
+ DBUG_ASSERT(!time_zone_tables_exist || tz_tables || current_thd->slave_thread);
if (!name)
DBUG_RETURN(0);
@@ -2179,7 +2210,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
(const byte *)name->ptr(),
name->length())))
result_tz= tmp_tzname->tz;
- else if (time_zone_tables_exist)
+ else if (time_zone_tables_exist && tz_tables)
result_tz= tz_load_from_open_tables(name, tz_tables);
}
@@ -2188,6 +2219,58 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
DBUG_RETURN(result_tz);
}
+
+/*
+ A more standalone version of my_tz_find(): will open tz tables if needed.
+ This is so far only used by replication, where time zone setting does not
+ happen in the usual query context.
+
+ SYNOPSIS
+ my_tz_find_with_opening_tz_tables()
+ thd - pointer to thread's THD structure
+ name - time zone specification
+
+ DESCRIPTION
+ This function tries to find a time zone which matches the named passed in
+ argument. If it fails, it will open time zone tables and re-try the
+ search.
+ This function is needed for the slave SQL thread, which does not do the
+ addition of time zone tables which is usually done during query parsing
+ (as time zone setting by slave does not happen in mysql_parse() but
+ before). So it needs to open tz tables by itself if needed.
+ See notes of my_tz_find() as they also apply here.
+
+ RETURN VALUE
+ Pointer to corresponding Time_zone object. 0 - in case of bad time zone
+ specification or other error.
+
+*/
+Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
+{
+ Time_zone *tz;
+ DBUG_ENTER("my_tz_find_with_opening_tables");
+ DBUG_ASSERT(thd);
+ DBUG_ASSERT(thd->slave_thread); // intended for use with slave thread only
+ if (!(tz= my_tz_find(name, 0)) && time_zone_tables_exist)
+ {
+ /*
+ Probably we have not loaded this time zone yet so let us look it up in
+ our time zone tables. Note that if we don't have tz tables on this
+ slave, we don't even try.
+ */
+ TABLE_LIST tables[4];
+ TABLE_LIST *dummy;
+ TABLE_LIST **dummyp= &dummy;
+ tz_init_table_list(tables, &dummyp);
+ if (simple_open_n_lock_tables(thd, tables))
+ DBUG_RETURN(0);
+ tz= my_tz_find(name, tables);
+ /* We need to close tables _now_ to not pollute coming query */
+ close_thread_tables(thd);
+ }
+ DBUG_RETURN(tz);
+}
+
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
diff --git a/sql/tztime.h b/sql/tztime.h
index 2214c1b29d6..777e521d761 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -59,11 +59,13 @@ public:
extern Time_zone * my_tz_UTC;
extern Time_zone * my_tz_SYSTEM;
-extern TABLE_LIST * my_tz_get_table_list(THD *thd);
+extern TABLE_LIST * my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr);
extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables);
+extern Time_zone * my_tz_find_with_opening_tz_tables(THD *thd, const String *name);
extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
extern void my_tz_free();
+extern TABLE_LIST fake_time_zone_tables_list;
/*
Check if we have pointer to the begining of list of implicitly used time
@@ -95,10 +97,4 @@ inline bool my_tz_check_n_skip_implicit_tables(TABLE_LIST **table,
return FALSE;
}
-/*
- Maximum length of time zone name that we support
- (Time zone name is char(64) in db)
-*/
-#define MAX_TIME_ZONE_NAME_LENGTH 72
-
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
diff --git a/sql/udf_example.cc b/sql/udf_example.cc
index 50de0f187fe..a186b4fbf6c 100644
--- a/sql/udf_example.cc
+++ b/sql/udf_example.cc
@@ -56,7 +56,9 @@
**
** Function 'myfunc_int' returns summary length of all its arguments.
**
-** Function 'sequence' returns an sequence starting from a certain number
+** Function 'sequence' returns an sequence starting from a certain number.
+**
+** Function 'myfunc_argument_name' returns name of argument.
**
** On the end is a couple of functions that converts hostnames to ip and
** vice versa.
@@ -82,6 +84,7 @@
** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
** CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
+** CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so";
**
** After this the functions will work exactly like native MySQL functions.
** Functions should be created only once.
@@ -94,6 +97,7 @@
** DROP FUNCTION lookup;
** DROP FUNCTION reverse_lookup;
** DROP FUNCTION avgcost;
+** DROP FUNCTION myfunc_argument_name;
**
** The CREATE FUNCTION and DROP FUNCTION update the func@mysql table. All
** Active function will be reloaded on every restart of server
@@ -987,4 +991,43 @@ avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* error )
return data->totalprice/double(data->totalquantity);
}
+extern "C" {
+my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
+ char *message);
+char *myfunc_argument_name(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *length, char *null_value,
+ char *error);
+}
+
+my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
+ char *message)
+{
+ if (args->arg_count != 1)
+ {
+ strmov(message,"myfunc_argument_name_init accepts only one argument");
+ return 1;
+ }
+ initid->max_length= args->attribute_lengths[0];
+ initid->maybe_null= 1;
+ initid->const_item= 1;
+ return 0;
+}
+
+char *myfunc_argument_name(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *length, char *null_value,
+ char *error)
+{
+ if (!args->attributes[0])
+ {
+ null_value= 0;
+ return 0;
+ }
+ (*length)--; // space for ending \0 (for debugging purposes)
+ if (*length > args->attribute_lengths[0])
+ *length= args->attribute_lengths[0];
+ memcpy(result, args->attributes[0], *length);
+ result[*length]= 0;
+ return result;
+}
+
#endif /* HAVE_DLOPEN */
diff --git a/sql/uniques.cc b/sql/uniques.cc
index d060965aa66..b08727705e4 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -63,12 +63,255 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
comp_func_fixed_arg);
/* If the following fail's the next add will also fail */
my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16);
+ /*
+ If you change the following, change it in get_max_elements function, too.
+ */
max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size);
open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE,
MYF(MY_WME));
}
+/*
+ Calculate log2(n!)
+
+ NOTES
+ Stirling's approximate formula is used:
+
+ n! ~= sqrt(2*M_PI*n) * (n/M_E)^n
+
+ Derivation of formula used for calculations is as follows:
+
+ log2(n!) = log(n!)/log(2) = log(sqrt(2*M_PI*n)*(n/M_E)^n) / log(2) =
+
+ = (log(2*M_PI*n)/2 + n*log(n/M_E)) / log(2).
+*/
+
+inline double log2_n_fact(double x)
+{
+ return (log(2*M_PI*x)/2 + x*log(x/M_E)) / M_LN2;
+}
+
+
+/*
+ Calculate cost of merge_buffers function call for given sequence of
+ input stream lengths and store the number of rows in result stream in *last.
+
+ SYNOPSIS
+ get_merge_buffers_cost()
+ buff_elems Array of #s of elements in buffers
+ elem_size Size of element stored in buffer
+ first Pointer to first merged element size
+ last Pointer to last merged element size
+
+ RETURN
+ Cost of merge_buffers operation in disk seeks.
+
+ NOTES
+ It is assumed that no rows are eliminated during merge.
+ The cost is calculated as
+
+ cost(read_and_write) + cost(merge_comparisons).
+
+ All bytes in the sequences is read and written back during merge so cost
+ of disk io is 2*elem_size*total_buf_elems/IO_SIZE (2 is for read + write)
+
+ For comparisons cost calculations we assume that all merged sequences have
+ the same length, so each of total_buf_size elements will be added to a sort
+ heap with (n_buffers-1) elements. This gives the comparison cost:
+
+ total_buf_elems* log2(n_buffers) / TIME_FOR_COMPARE_ROWID;
+*/
+
+static double get_merge_buffers_cost(uint *buff_elems, uint elem_size,
+ uint *first, uint *last)
+{
+ uint total_buf_elems= 0;
+ for (uint *pbuf= first; pbuf <= last; pbuf++)
+ total_buf_elems+= *pbuf;
+ *last= total_buf_elems;
+
+ int n_buffers= last - first + 1;
+
+ /* Using log2(n)=log(n)/log(2) formula */
+ return 2*((double)total_buf_elems*elem_size) / IO_SIZE +
+ total_buf_elems*log((double) n_buffers) / (TIME_FOR_COMPARE_ROWID * M_LN2);
+}
+
+
+/*
+ Calculate cost of merging buffers into one in Unique::get, i.e. calculate
+ how long (in terms of disk seeks) the two calls
+ merge_many_buffs(...);
+ merge_buffers(...);
+ will take.
+
+ SYNOPSIS
+ get_merge_many_buffs_cost()
+ buffer buffer space for temporary data, at least
+ Unique::get_cost_calc_buff_size bytes
+ maxbuffer # of full buffers
+ max_n_elems # of elements in first maxbuffer buffers
+ last_n_elems # of elements in last buffer
+ elem_size size of buffer element
+
+ NOTES
+ maxbuffer+1 buffers are merged, where first maxbuffer buffers contain
+ max_n_elems elements each and last buffer contains last_n_elems elements.
+
+ The current implementation does a dumb simulation of merge_many_buffs
+ function actions.
+
+ RETURN
+ Cost of merge in disk seeks.
+*/
+
+static double get_merge_many_buffs_cost(uint *buffer,
+ uint maxbuffer, uint max_n_elems,
+ uint last_n_elems, int elem_size)
+{
+ register int i;
+ double total_cost= 0.0;
+ uint *buff_elems= buffer; /* #s of elements in each of merged sequences */
+
+ /*
+ Set initial state: first maxbuffer sequences contain max_n_elems elements
+ each, last sequence contains last_n_elems elements.
+ */
+ for(i = 0; i < (int)maxbuffer; i++)
+ buff_elems[i]= max_n_elems;
+ buff_elems[maxbuffer]= last_n_elems;
+
+ /*
+ Do it exactly as merge_many_buff function does, calling
+ get_merge_buffers_cost to get cost of merge_buffers.
+ */
+ if (maxbuffer >= MERGEBUFF2)
+ {
+ while (maxbuffer >= MERGEBUFF2)
+ {
+ uint lastbuff= 0;
+ for (i = 0; i <= (int) maxbuffer - MERGEBUFF*3/2; i += MERGEBUFF)
+ {
+ total_cost+=get_merge_buffers_cost(buff_elems, elem_size,
+ buff_elems + i,
+ buff_elems + i + MERGEBUFF-1);
+ lastbuff++;
+ }
+ total_cost+=get_merge_buffers_cost(buff_elems, elem_size,
+ buff_elems + i,
+ buff_elems + maxbuffer);
+ maxbuffer= lastbuff;
+ }
+ }
+
+ /* Simulate final merge_buff call. */
+ total_cost += get_merge_buffers_cost(buff_elems, elem_size,
+ buff_elems, buff_elems + maxbuffer);
+ return total_cost;
+}
+
+
+/*
+ Calculate cost of using Unique for processing nkeys elements of size
+ key_size using max_in_memory_size memory.
+
+ SYNOPSIS
+ Unique::get_use_cost()
+ buffer space for temporary data, use Unique::get_cost_calc_buff_size
+ to get # bytes needed.
+ nkeys #of elements in Unique
+ key_size size of each elements in bytes
+ max_in_memory_size amount of memory Unique will be allowed to use
+
+ RETURN
+ Cost in disk seeks.
+
+ NOTES
+ cost(using_unqiue) =
+ cost(create_trees) + (see #1)
+ cost(merge) + (see #2)
+ cost(read_result) (see #3)
+
+ 1. Cost of trees creation
+ For each Unique::put operation there will be 2*log2(n+1) elements
+ comparisons, where n runs from 1 tree_size (we assume that all added
+ elements are different). Together this gives:
+
+ n_compares = 2*(log2(2) + log2(3) + ... + log2(N+1)) = 2*log2((N+1)!)
+
+ then cost(tree_creation) = n_compares*ROWID_COMPARE_COST;
+
+ Total cost of creating trees:
+ (n_trees - 1)*max_size_tree_cost + non_max_size_tree_cost.
+
+ Approximate value of log2(N!) is calculated by log2_n_fact function.
+
+ 2. Cost of merging.
+ If only one tree is created by Unique no merging will be necessary.
+ Otherwise, we model execution of merge_many_buff function and count
+ #of merges. (The reason behind this is that number of buffers is small,
+ while size of buffers is big and we don't want to loose precision with
+ O(x)-style formula)
+
+ 3. If only one tree is created by Unique no disk io will happen.
+ Otherwise, ceil(key_len*n_keys) disk seeks are necessary. We assume
+ these will be random seeks.
+*/
+
+double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size,
+ ulong max_in_memory_size)
+{
+ ulong max_elements_in_tree;
+ ulong last_tree_elems;
+ int n_full_trees; /* number of trees in unique - 1 */
+ double result;
+
+ max_elements_in_tree=
+ max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size);
+
+ n_full_trees= nkeys / max_elements_in_tree;
+ last_tree_elems= nkeys % max_elements_in_tree;
+
+ /* Calculate cost of creating trees */
+ result= 2*log2_n_fact(last_tree_elems + 1.0);
+ if (n_full_trees)
+ result+= n_full_trees * log2_n_fact(max_elements_in_tree + 1.0);
+ result /= TIME_FOR_COMPARE_ROWID;
+
+ DBUG_PRINT("info",("unique trees sizes: %u=%u*%lu + %lu", nkeys,
+ n_full_trees, n_full_trees?max_elements_in_tree:0,
+ last_tree_elems));
+
+ if (!n_full_trees)
+ return result;
+
+ /*
+ There is more then one tree and merging is necessary.
+ First, add cost of writing all trees to disk, assuming that all disk
+ writes are sequential.
+ */
+ result += DISK_SEEK_BASE_COST * n_full_trees *
+ ceil(((double) key_size)*max_elements_in_tree / IO_SIZE);
+ result += DISK_SEEK_BASE_COST * ceil(((double) key_size)*last_tree_elems / IO_SIZE);
+
+ /* Cost of merge */
+ double merge_cost= get_merge_many_buffs_cost(buffer, n_full_trees,
+ max_elements_in_tree,
+ last_tree_elems, key_size);
+ if (merge_cost < 0.0)
+ return merge_cost;
+
+ result += merge_cost;
+ /*
+ Add cost of reading the resulting sequence, assuming there were no
+ duplicate elements.
+ */
+ result += ceil((double)key_size*nkeys/IO_SIZE);
+
+ return result;
+}
+
Unique::~Unique()
{
close_cached_file(&file);
@@ -84,6 +327,7 @@ bool Unique::flush()
elements+= tree.elements_in_tree;
file_ptr.count=tree.elements_in_tree;
file_ptr.file_pos=my_b_tell(&file);
+
if (tree_walk(&tree, (tree_walk_action) unique_write_to_file,
(void*) this, left_root_right) ||
insert_dynamic(&file_ptrs, (gptr) &file_ptr))
@@ -94,6 +338,237 @@ bool Unique::flush()
/*
+ Clear the tree and the file.
+ You must call reset() if you want to reuse Unique after walk().
+*/
+
+void
+Unique::reset()
+{
+ reset_tree(&tree);
+ /*
+ If elements != 0, some trees were stored in the file (see how
+ flush() works). Note, that we can not count on my_b_tell(&file) == 0
+ here, because it can return 0 right after walk(), and walk() does not
+ reset any Unique member.
+ */
+ if (elements)
+ {
+ reset_dynamic(&file_ptrs);
+ reinit_io_cache(&file, WRITE_CACHE, 0L, 0, 1);
+ }
+ elements= 0;
+}
+
+/*
+ The comparison function, passed to queue_init() in merge_walk() must
+ use comparison function of Uniques::tree, but compare members of struct
+ BUFFPEK.
+*/
+
+struct BUFFPEK_COMPARE_CONTEXT
+{
+ qsort_cmp2 key_compare;
+ void *key_compare_arg;
+};
+
+C_MODE_START
+
+static int buffpek_compare(void *arg, byte *key_ptr1, byte *key_ptr2)
+{
+ BUFFPEK_COMPARE_CONTEXT *ctx= (BUFFPEK_COMPARE_CONTEXT *) arg;
+ return ctx->key_compare(ctx->key_compare_arg,
+ *((byte **) key_ptr1), *((byte **)key_ptr2));
+}
+
+C_MODE_END
+
+
+/*
+ DESCRIPTION
+ Function is very similar to merge_buffers, but instead of writing sorted
+ unique keys to the output file, it invokes walk_action for each key.
+ This saves I/O if you need to pass through all unique keys only once.
+ SYNOPSIS
+ merge_walk()
+ All params are 'IN' (but see comment for begin, end):
+ merge_buffer buffer to perform cached piece-by-piece loading
+ of trees; initially the buffer is empty
+ merge_buffer_size size of merge_buffer. Must be aligned with
+ key_length
+ key_length size of tree element; key_length * (end - begin)
+ must be less or equal than merge_buffer_size.
+ begin pointer to BUFFPEK struct for the first tree.
+ end pointer to BUFFPEK struct for the last tree;
+ end > begin and [begin, end) form a consecutive
+ range. BUFFPEKs structs in that range are used and
+ overwritten in merge_walk().
+ walk_action element visitor. Action is called for each unique
+ key.
+ walk_action_arg argument to walk action. Passed to it on each call.
+ compare elements comparison function
+ compare_arg comparison function argument
+ file file with all trees dumped. Trees in the file
+ must contain sorted unique values. Cache must be
+ initialized in read mode.
+ RETURN VALUE
+ 0 ok
+ <> 0 error
+*/
+
+static bool merge_walk(uchar *merge_buffer, uint merge_buffer_size,
+ uint key_length, BUFFPEK *begin, BUFFPEK *end,
+ tree_walk_action walk_action, void *walk_action_arg,
+ qsort_cmp2 compare, void *compare_arg,
+ IO_CACHE *file)
+{
+ BUFFPEK_COMPARE_CONTEXT compare_context = { compare, compare_arg };
+ QUEUE queue;
+ if (end <= begin ||
+ merge_buffer_size < key_length * (end - begin + 1) ||
+ init_queue(&queue, end - begin, offsetof(BUFFPEK, key), 0,
+ buffpek_compare, &compare_context))
+ return 1;
+ /* we need space for one key when a piece of merge buffer is re-read */
+ merge_buffer_size-= key_length;
+ uchar *save_key_buff= merge_buffer + merge_buffer_size;
+ uint max_key_count_per_piece= merge_buffer_size/(end-begin)/key_length;
+ /* if piece_size is aligned reuse_freed_buffer will always hit */
+ uint piece_size= max_key_count_per_piece * key_length;
+ uint bytes_read; /* to hold return value of read_to_buffer */
+ BUFFPEK *top;
+ int res= 1;
+ /*
+ Invariant: queue must contain top element from each tree, until a tree
+ is not completely walked through.
+ Here we're forcing the invariant, inserting one element from each tree
+ to the queue.
+ */
+ for (top= begin; top != end; ++top)
+ {
+ top->base= merge_buffer + (top - begin) * piece_size;
+ top->max_keys= max_key_count_per_piece;
+ bytes_read= read_to_buffer(file, top, key_length);
+ if (bytes_read == (uint) (-1))
+ goto end;
+ DBUG_ASSERT(bytes_read);
+ queue_insert(&queue, (byte *) top);
+ }
+ top= (BUFFPEK *) queue_top(&queue);
+ while (queue.elements > 1)
+ {
+ /*
+ Every iteration one element is removed from the queue, and one is
+ inserted by the rules of the invariant. If two adjacent elements on
+ the top of the queue are not equal, biggest one is unique, because all
+ elements in each tree are unique. Action is applied only to unique
+ elements.
+ */
+ void *old_key= top->key;
+ /*
+ read next key from the cache or from the file and push it to the
+ queue; this gives new top.
+ */
+ top->key+= key_length;
+ if (--top->mem_count)
+ queue_replaced(&queue);
+ else /* next piece should be read */
+ {
+ /* save old_key not to overwrite it in read_to_buffer */
+ memcpy(save_key_buff, old_key, key_length);
+ old_key= save_key_buff;
+ bytes_read= read_to_buffer(file, top, key_length);
+ if (bytes_read == (uint) (-1))
+ goto end;
+ else if (bytes_read > 0) /* top->key, top->mem_count are reset */
+ queue_replaced(&queue); /* in read_to_buffer */
+ else
+ {
+ /*
+ Tree for old 'top' element is empty: remove it from the queue and
+ give all its memory to the nearest tree.
+ */
+ queue_remove(&queue, 0);
+ reuse_freed_buff(&queue, top, key_length);
+ }
+ }
+ top= (BUFFPEK *) queue_top(&queue);
+ /* new top has been obtained; if old top is unique, apply the action */
+ if (compare(compare_arg, old_key, top->key))
+ {
+ if (walk_action(old_key, 1, walk_action_arg))
+ goto end;
+ }
+ }
+ /*
+ Applying walk_action to the tail of the last tree: this is safe because
+ either we had only one tree in the beginning, either we work with the
+ last tree in the queue.
+ */
+ do
+ {
+ do
+ {
+ if (walk_action(top->key, 1, walk_action_arg))
+ goto end;
+ top->key+= key_length;
+ }
+ while (--top->mem_count);
+ bytes_read= read_to_buffer(file, top, key_length);
+ if (bytes_read == (uint) (-1))
+ goto end;
+ }
+ while (bytes_read);
+ res= 0;
+end:
+ delete_queue(&queue);
+ return res;
+}
+
+
+/*
+ DESCRIPTION
+ Walks consecutively through all unique elements:
+ if all elements are in memory, then it simply invokes 'tree_walk', else
+ all flushed trees are loaded to memory piece-by-piece, pieces are
+ sorted, and action is called for each unique value.
+ Note: so as merging resets file_ptrs state, this method can change
+ internal Unique state to undefined: if you want to reuse Unique after
+ walk() you must call reset() first!
+ SYNOPSIS
+ Unique:walk()
+ All params are 'IN':
+ action function-visitor, typed in include/my_tree.h
+ function is called for each unique element
+ arg argument for visitor, which is passed to it on each call
+ RETURN VALUE
+ 0 OK
+ <> 0 error
+ */
+
+bool Unique::walk(tree_walk_action action, void *walk_action_arg)
+{
+ if (elements == 0) /* the whole tree is in memory */
+ return tree_walk(&tree, action, walk_action_arg, left_root_right);
+
+ /* flush current tree to the file to have some memory for merge buffer */
+ if (flush())
+ return 1;
+ if (flush_io_cache(&file) || reinit_io_cache(&file, READ_CACHE, 0L, 0, 0))
+ return 1;
+ uchar *merge_buffer= (uchar *) my_malloc(max_in_memory_size, MYF(0));
+ if (merge_buffer == 0)
+ return 1;
+ int res= merge_walk(merge_buffer, max_in_memory_size, size,
+ (BUFFPEK *) file_ptrs.buffer,
+ (BUFFPEK *) file_ptrs.buffer + file_ptrs.elements,
+ action, walk_action_arg,
+ tree.compare, tree.custom_arg, &file);
+ x_free(merge_buffer);
+ return res;
+}
+
+/*
Modify the TABLE element so that when one calls init_records()
the rows will be read in priority order.
*/
@@ -114,7 +589,7 @@ bool Unique::get(TABLE *table)
return 0;
}
}
- /* Not enough memory; Save the result to file */
+ /* Not enough memory; Save the result to file && free memory used by tree */
if (flush())
return 1;
diff --git a/sql/unireg.cc b/sql/unireg.cc
index a550b06a466..95a383e0f01 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -40,7 +40,7 @@ static bool pack_header(uchar *forminfo,enum db_type table_type,
static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
create_field *last_field);
static bool pack_fields(File file, List<create_field> &create_fields);
-static bool make_empty_rec(int file, enum db_type table_type,
+static bool make_empty_rec(THD *thd, int file, enum db_type table_type,
uint table_options,
List<create_field> &create_fields,
uint reclength,uint null_fields);
@@ -134,7 +134,7 @@ bool mysql_create_frm(THD *thd, my_string file_name,
VOID(my_seek(file,
(ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
MY_SEEK_SET,MYF(0)));
- if (make_empty_rec(file,create_info->db_type,create_info->table_options,
+ if (make_empty_rec(thd,file,create_info->db_type,create_info->table_options,
create_fields,reclength,null_fields))
goto err;
@@ -210,7 +210,7 @@ err3:
keys number of keys to create
key_info Keys to create
db_file Handler to use. May be zero, in which case we use
- create_info->db_type
+ create_info->db_type
RETURN
0 ok
1 error
@@ -224,11 +224,11 @@ int rea_create_table(THD *thd, my_string file_name,
DBUG_ENTER("rea_create_table");
if (mysql_create_frm(thd, file_name, create_info,
- create_fields, keys, key_info, NULL))
+ create_fields, keys, key_info, NULL))
DBUG_RETURN(1);
- if (ha_create_table(file_name,create_info,0))
+ if (!create_info->frm_only && ha_create_table(file_name,create_info,0))
{
- my_delete(file_name,MYF(0));
+ my_delete(file_name,MYF(0));
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -332,7 +332,7 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
pos[6]=pos[7]=0; // For the future
pos+=8;
key_parts+=key->key_parts;
- DBUG_PRINT("loop",("flags: %d key_parts: %d at %lx",
+ DBUG_PRINT("loop",("flags: %d key_parts: %d at 0x%lx",
key->flags,key->key_parts,
key->key_part));
for (key_part=key->key_part,key_part_end=key_part+key->key_parts ;
@@ -394,7 +394,7 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
if (create_fields.elements > MAX_FIELDS)
{
- my_error(ER_TOO_MANY_FIELDS,MYF(0));
+ my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
DBUG_RETURN(1);
}
@@ -481,7 +481,7 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
if (info_length+(ulong) create_fields.elements*FCOMP+288+
n_length+int_length+com_length > 65535L || int_count > 255)
{
- my_error(ER_TOO_MANY_FIELDS,MYF(0));
+ my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
DBUG_RETURN(1);
}
@@ -640,7 +640,7 @@ static bool pack_fields(File file,List<create_field> &create_fields)
/* save an empty record on start of formfile */
-static bool make_empty_rec(File file,enum db_type table_type,
+static bool make_empty_rec(THD *thd, File file,enum db_type table_type,
uint table_options,
List<create_field> &create_fields,
uint reclength, uint null_fields)
@@ -652,10 +652,12 @@ static bool make_empty_rec(File file,enum db_type table_type,
TABLE table;
create_field *field;
handler *handler;
+ enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
DBUG_ENTER("make_empty_rec");
/* We need a table to generate columns for default values */
bzero((char*) &table,sizeof(table));
+ table.s= &table.share_not_to_be_used;
handler= get_new_handler((TABLE*) 0, table_type);
if (!handler ||
@@ -665,9 +667,9 @@ static bool make_empty_rec(File file,enum db_type table_type,
DBUG_RETURN(1);
}
- table.in_use= current_thd;
- table.db_low_byte_first= handler->low_byte_first();
- table.blob_ptr_size=portable_sizeof_char_ptr;
+ table.in_use= thd;
+ table.s->db_low_byte_first= handler->low_byte_first();
+ table.s->blob_ptr_size= portable_sizeof_char_ptr;
firstpos=reclength;
null_count=0;
@@ -677,15 +679,18 @@ static bool make_empty_rec(File file,enum db_type table_type,
null_count++;
}
bfill(buff,(null_length=(null_fields+7)/8),255);
- null_pos=buff;
+ null_pos= buff + null_count / 8;
List_iterator<create_field> it(create_fields);
+ thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values
while ((field=it++))
{
+ /*
+ regfield don't have to be deleted as it's allocated with sql_alloc()
+ */
Field *regfield=make_field((char*) buff+field->offset,field->length,
- field->flags & NOT_NULL_FLAG ? 0:
- null_pos+null_count/8,
- 1 << (null_count & 7),
+ null_pos,
+ null_count & 7,
field->pack_flag,
field->sql_type,
field->charset,
@@ -694,6 +699,8 @@ static bool make_empty_rec(File file,enum db_type table_type,
field->interval,
field->field_name,
&table);
+ if (!regfield)
+ goto err; // End of memory
if (!(field->flags & NOT_NULL_FLAG))
null_count++;
@@ -707,7 +714,14 @@ static bool make_empty_rec(File file,enum db_type table_type,
if (field->def &&
(regfield->real_type() != FIELD_TYPE_YEAR ||
field->def->val_int() != 0))
- (void) field->def->save_in_field(regfield, 1);
+ {
+ if (field->def->save_in_field(regfield, 1))
+ {
+ my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name);
+ error= 1;
+ goto err;
+ }
+ }
else if (regfield->real_type() == FIELD_TYPE_ENUM &&
(field->flags & NOT_NULL_FLAG))
{
@@ -720,13 +734,15 @@ static bool make_empty_rec(File file,enum db_type table_type,
regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)),system_charset_info);
else
regfield->reset();
- delete regfield;
}
/* Fill not used startpos */
bfill((byte*) buff+null_length,firstpos-null_length,255);
error=(int) my_write(file,(byte*) buff,(uint) reclength,MYF_RW);
+
+err:
my_free((gptr) buff,MYF(MY_FAE));
delete handler;
+ thd->count_cuted_fields= old_count_cuted_fields;
DBUG_RETURN(error);
} /* make_empty_rec */
diff --git a/sql/unireg.h b/sql/unireg.h
index 70df9a89c8f..8d88683241b 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -37,8 +37,8 @@
#define SHAREDIR "share/"
#endif
-#define ER(X) errmesg[(X)-1000]
-#define ER_SAFE(X) (((X) >= 1000 && (X) < ER_ERROR_MESSAGES + 1000) ? ER(X) : "Invalid error code")
+#define ER(X) errmesg[(X) - ER_ERROR_FIRST]
+#define ER_SAFE(X) (((X) >= ER_ERROR_FIRST && (X) <= ER_ERROR_LAST) ? ER(X) : "Invalid error code")
#define ERRMAPP 1 /* Errormap f|r my_error */
@@ -60,9 +60,14 @@
#define MAX_MBWIDTH 3 /* Max multibyte sequence */
#define MAX_FIELD_CHARLENGTH 255
+#define MAX_FIELD_VARCHARLENGTH 65535
+#define CONVERT_IF_BIGGER_TO_BLOB 512 /* Used for CREATE ... SELECT */
+
/* Max column width +1 */
#define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1)
+#define MAX_BIT_FIELD_LENGTH 64 /* Max length in bits for bit fields */
+
#define MAX_DATE_WIDTH 10 /* YYYY-MM-DD */
#define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */
#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */
@@ -118,12 +123,12 @@
#define SPECIAL_LOG_QUERIES_NOT_USING_INDEXES 4096 /* Log q not using indexes */
/* Extern defines */
-#define store_record(A,B) bmove_align((A)->B,(A)->record[0],(size_t) (A)->reclength)
-#define restore_record(A,B) bmove_align((A)->record[0],(A)->B,(size_t) (A)->reclength)
-#define cmp_record(A,B) memcmp((A)->record[0],(A)->B,(size_t) (A)->reclength)
+#define store_record(A,B) bmove_align((A)->B,(A)->record[0],(size_t) (A)->s->reclength)
+#define restore_record(A,B) bmove_align((A)->record[0],(A)->B,(size_t) (A)->s->reclength)
+#define cmp_record(A,B) memcmp((A)->record[0],(A)->B,(size_t) (A)->s->reclength)
#define empty_record(A) { \
- restore_record((A),default_values); \
- bfill((A)->null_flags,(A)->null_bytes,255);\
+ restore_record((A),s->default_values); \
+ bfill((A)->null_flags,(A)->s->null_bytes,255);\
}
/* Defines for use with openfrm, openprt and openfrd */
@@ -141,11 +146,13 @@
#define DONT_GIVE_ERROR 256 /* Don't do frm_error on openfrm */
#define READ_SCREENS 1024 /* Read screens, info and helpfile */
#define DELAYED_OPEN 4096 /* Open table later */
+#define NO_ERR_ON_NEW_FRM 8192 /* stop error sending on new format */
#define SC_INFO_LENGTH 4 /* Form format constant */
#define TE_INFO_LENGTH 3
#define MTYP_NOEMPTY_BIT 128
+#define FRM_VER_TRUE_VARCHAR (FRM_VER+4)
/*
Minimum length pattern before Turbo Boyer-Moore is used
for SELECT "text" LIKE "%pattern%", excluding the two
diff --git a/strings/Makefile.am b/strings/Makefile.am
index 83f935a3fd2..a98908ad54a 100644
--- a/strings/Makefile.am
+++ b/strings/Makefile.am
@@ -16,35 +16,35 @@
# This file is public domain and comes with NO WARRANTY of any kind
-INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include
+INCLUDES = -I$(top_srcdir)/include
pkglib_LIBRARIES = libmystrings.a
# Exact one of ASSEMBLER_X
if ASSEMBLER_x86
ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s
-CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c
+CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c
else
if ASSEMBLER_sparc32
# These file MUST all be on the same line!! Otherwise automake
# generats a very broken makefile
ASRCS = bmove_upp-sparc.s strappend-sparc.s strend-sparc.s strinstr-sparc.s strmake-sparc.s strmov-sparc.s strnmov-sparc.s strstr-sparc.s
-CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c
+CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c my_strtoll10.c
else
#no assembler
ASRCS =
# These file MUST all be on the same line!! Otherwise automake
# generats a very broken makefile
-CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c
+CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c my_strtoll10.c
endif
endif
libmystrings_a_SOURCES = $(ASRCS) $(CSRCS)
noinst_PROGRAMS = conf_to_src
# Default charset definitions
-EXTRA_DIST = ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-win1250ch.c \
- ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-utf8.c \
- ctype-ucs2.c ctype-uca.c ctype-tis620.c ctype-ujis.c \
- xml.c strto.c strings-x86.s \
+EXTRA_DIST = ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-win1250ch.c \
+ ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-utf8.c \
+ ctype-ucs2.c ctype-uca.c ctype-tis620.c ctype-ujis.c \
+ xml.c decimal.c strto.c strings-x86.s \
longlong2str.c longlong2str-x86.s \
my_strtoll10.c my_strtoll10-x86.s \
strxmov.c bmove_upp.c strappend.c strcont.c strend.c \
@@ -53,7 +53,7 @@ EXTRA_DIST = ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-win1250ch.c \
bmove_upp-sparc.s strappend-sparc.s strend-sparc.s \
strinstr-sparc.s strmake-sparc.s strmov-sparc.s \
strnmov-sparc.s strstr-sparc.s strxmov-sparc.s \
- t_ctype.h
+ t_ctype.h
libmystrings_a_LIBADD=
conf_to_src_SOURCES = conf_to_src.c xml.c ctype.c bcmp.c
@@ -72,8 +72,16 @@ if ASSEMBLER
$(AS) $(ASFLAGS) -o $@ $<
endif
-str_test: str_test.c $(LIBRARIES)
- $(LINK) $(FLAGS) -DMAIN $INCLUDES $(srcdir)/str_test.c $(LDADD) $(LIBS) $(pkglib_LIBRARIES)
+FLAGS=$(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) @NOINST_LDFLAGS@
+
+str_test: str_test.c $(pkglib_LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(INCLUDES) $(srcdir)/str_test.c $(LDADD) $(pkglib_LIBRARIES)
+
+test_decimal$(EXEEXT): decimal.c $(pkglib_LIBRARIES)
+ $(CP) $(srcdir)/decimal.c ./test_decimal.c
+ $(LINK) $(FLAGS) -DMAIN ./test_decimal.c $(LDADD) $(pkglib_LIBRARIES)
+ $(RM) -f ./test_decimal.c
# Don't update the files from bitkeeper
%::SCCS/s.%
+
diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c
index 07b30205f89..ab6691e68b0 100644
--- a/strings/ctype-big5.c
+++ b/strings/ctype-big5.c
@@ -264,24 +264,33 @@ static int my_strnncoll_big5(CHARSET_INFO *cs __attribute__((unused)),
static int my_strnncollsp_big5(CHARSET_INFO * cs __attribute__((unused)),
const uchar *a, uint a_length,
- const uchar *b, uint b_length)
+ const uchar *b, uint b_length,
+ my_bool diff_if_only_endspace_difference)
{
uint length= min(a_length, b_length);
int res= my_strnncoll_big5_internal(&a, &b, length);
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
+
if (!res && a_length != b_length)
{
const uchar *end;
int swap= 1;
+ if (diff_if_only_endspace_difference)
+ res= 1; /* Assume 'a' is bigger */
/*
Check the next not space character of the longer key. If it's < ' ',
then it's smaller than the other key.
*/
if (a_length < b_length)
{
- /* put shorter key in a */
+ /* put longer key in a */
a_length= b_length;
a= b;
- swap= -1; /* swap sign of result */
+ swap= -1; /* swap sign of result */
+ res= -res;
}
for (end= a + a_length-length; a < end ; a++)
{
@@ -410,7 +419,7 @@ static my_bool my_like_range_big5(CHARSET_INFO *cs __attribute__((unused)),
*min_str++= *max_str++ = *ptr;
continue;
}
- if (*ptr == w_one) /* '_' in SQL */
+ if (*ptr == w_one) /* '_' in SQL */
{
*min_str++='\0'; /* This should be min char */
*max_str++=max_sort_char;
@@ -418,7 +427,13 @@ static my_bool my_like_range_big5(CHARSET_INFO *cs __attribute__((unused)),
}
if (*ptr == w_many) /* '%' in SQL */
{
- *min_length= (uint) (min_str-min_org);
+ /*
+ Calculate length of keys:
+ 'a\0\0... is the smallest possible string when we have space expand
+ a\ff\ff... is the biggest possible string
+ */
+ *min_length= ((cs->state & MY_CS_BINSORT) ? (uint) (min_str - min_org) :
+ res_length);
*max_length= res_length;
do {
*min_str++ = 0;
@@ -428,26 +443,27 @@ static my_bool my_like_range_big5(CHARSET_INFO *cs __attribute__((unused)),
}
*min_str++= *max_str++ = *ptr;
}
- *min_length= *max_length= (uint) (min_str-min_org);
+
+ *min_length= *max_length= (uint) (min_str-min_org);
while (min_str != min_end)
- {
- *min_str++ = ' '; /* Because if key compression */
- *max_str++ = ' ';
- }
+ *min_str++= *max_str++= ' ';
return 0;
}
+
static int ismbchar_big5(CHARSET_INFO *cs __attribute__((unused)),
const char* p, const char *e)
{
return (isbig5head(*(p)) && (e)-(p)>1 && isbig5tail(*((p)+1))? 2: 0);
}
+
static int mbcharlen_big5(CHARSET_INFO *cs __attribute__((unused)), uint c)
{
return (isbig5head(c)? 2 : 1);
}
+
/* page 0 0xA140-0xC7FC */
static uint16 tab_big5_uni0[]={
0x3000,0xFF0C,0x3001,0x3002,0xFF0E,0x2022,0xFF1B,0xFF1A,
@@ -6314,6 +6330,7 @@ static MY_COLLATION_HANDLER my_collation_big5_chinese_ci_handler =
my_strnncoll_big5,
my_strnncollsp_big5,
my_strnxfrm_big5,
+ my_strnxfrmlen_simple,
my_like_range_big5,
my_wildcmp_mb,
my_strcasecmp_mb,
diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c
index 425985e6bc1..9f0e334d3a9 100644
--- a/strings/ctype-bin.c
+++ b/strings/ctype-bin.c
@@ -110,7 +110,9 @@ static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)),
static int my_strnncollsp_binary(CHARSET_INFO * cs __attribute__((unused)),
const uchar *s, uint slen,
- const uchar *t, uint tlen)
+ const uchar *t, uint tlen,
+ my_bool diff_if_only_endspace_difference
+ __attribute__((unused)))
{
return my_strnncoll_binary(cs,s,slen,t,tlen,0);
}
@@ -137,6 +139,9 @@ static int my_strnncoll_8bit_bin(CHARSET_INFO * cs __attribute__((unused)),
slen Length of 's'
t String to compare
tlen Length of 't'
+ diff_if_only_endspace_difference
+ Set to 1 if the strings should be regarded as different
+ if they only difference in end space
NOTE
This function is used for character strings with binary collations.
@@ -151,10 +156,16 @@ static int my_strnncoll_8bit_bin(CHARSET_INFO * cs __attribute__((unused)),
static int my_strnncollsp_8bit_bin(CHARSET_INFO * cs __attribute__((unused)),
const uchar *a, uint a_length,
- const uchar *b, uint b_length)
+ const uchar *b, uint b_length,
+ my_bool diff_if_only_endspace_difference)
{
const uchar *end;
uint length;
+ int res;
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
end= a + (length= min(a_length, b_length));
while (a < end)
@@ -162,6 +173,7 @@ static int my_strnncollsp_8bit_bin(CHARSET_INFO * cs __attribute__((unused)),
if (*a++ != *b++)
return ((int) a[-1] - (int) b[-1]);
}
+ res= 0;
if (a_length != b_length)
{
int swap= 1;
@@ -169,12 +181,15 @@ static int my_strnncollsp_8bit_bin(CHARSET_INFO * cs __attribute__((unused)),
Check the next not space character of the longer key. If it's < ' ',
then it's smaller than the other key.
*/
+ if (diff_if_only_endspace_difference)
+ res= 1; /* Assume 'a' is bigger */
if (a_length < b_length)
{
/* put shorter key in s */
a_length= b_length;
a= b;
swap= -1; /* swap sign of result */
+ res= -res;
}
for (end= a + a_length-length; a < end ; a++)
{
@@ -182,7 +197,7 @@ static int my_strnncollsp_8bit_bin(CHARSET_INFO * cs __attribute__((unused)),
return (*a < ' ') ? -swap : swap;
}
}
- return 0;
+ return res;
}
@@ -439,6 +454,7 @@ MY_COLLATION_HANDLER my_collation_8bit_bin_handler =
my_strnncoll_8bit_bin,
my_strnncollsp_8bit_bin,
my_strnxfrm_8bit_bin,
+ my_strnxfrmlen_simple,
my_like_range_simple,
my_wildcmp_bin,
my_strcasecmp_bin,
@@ -453,6 +469,7 @@ static MY_COLLATION_HANDLER my_collation_binary_handler =
my_strnncoll_binary,
my_strnncollsp_binary,
my_strnxfrm_bin,
+ my_strnxfrmlen_simple,
my_like_range_simple,
my_wildcmp_bin,
my_strcasecmp_bin,
diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c
new file mode 100644
index 00000000000..47bf1167c8c
--- /dev/null
+++ b/strings/ctype-cp932.c
@@ -0,0 +1,5552 @@
+/* Copyright (C) 2000 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* This file is for cp932 charaset (Windows Japanese),
+ and created based on ctype-sjis.c file */
+
+#include <my_global.h>
+#include "m_string.h"
+#include "m_ctype.h"
+
+#ifdef HAVE_CHARSET_cp932
+
+
+/*
+ * This comment is parsed by configure to create ctype.c,
+ * so don't change it unless you know what you are doing.
+ *
+ * .configure. strxfrm_multiply_cp932=1
+ * .configure. mbmaxlen_cp932=2
+ */
+
+static uchar NEAR ctype_cp932[257] =
+{
+ 0, /* For standard library */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* NUL ^A - ^G */
+ 0040, 0050, 0050, 0050, 0050, 0050, 0040, 0040, /* ^H - ^O */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^P - ^W */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^X - ^Z ^[ ^\ ^] ^^ ^_ */
+ 0110, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* SPC ! " # $ % ^ ' */
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* ( ) * + , - . / */
+ 0204, 0204, 0204, 0204, 0204, 0204, 0204, 0204, /* 0 1 2 3 4 5 6 7 */
+ 0204, 0204, 0020, 0020, 0020, 0020, 0020, 0020, /* 8 9 : ; < = > ? */
+ 0020, 0201, 0201, 0201, 0201, 0201, 0201, 0001, /* @ A B C D E F G */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* H I J K L M N O */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* P Q R S T U V W */
+ 0001, 0001, 0001, 0020, 0020, 0020, 0020, 0020, /* X Y Z [ \ ] ^ _ */
+ 0020, 0202, 0202, 0202, 0202, 0202, 0202, 0002, /* ` a b c d e f g */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* h i j k l m n o */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* p q r s t u v w */
+ 0002, 0002, 0002, 0020, 0020, 0020, 0020, 0040, /* x y z { | } + DEL */
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0000, 0000, 0000
+};
+
+static uchar NEAR to_lower_cp932[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377'
+};
+
+static uchar NEAR to_upper_cp932[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377'
+};
+
+static uchar NEAR sort_order_cp932[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377'
+};
+
+#define iscp932head(c) ((0x81<=(c) && (c)<=0x9f) || \
+ ((0xe0<=(c)) && (c)<=0xfc))
+#define iscp932tail(c) ((0x40<=(c) && (c)<=0x7e) || \
+ (0x80<=(c) && (c)<=0xfc))
+
+
+static int ismbchar_cp932(CHARSET_INFO *cs __attribute__((unused)),
+ const char* p, const char *e)
+{
+ return (iscp932head((uchar) *p) && (e-p)>1 && iscp932tail((uchar)p[1]) ? 2: 0);
+}
+
+static int mbcharlen_cp932(CHARSET_INFO *cs __attribute__((unused)),uint c)
+{
+ return (iscp932head((uchar) c) ? 2 : 1);
+}
+
+
+#define cp932code(c,d) ((((uint) (uchar)(c)) << 8) | (uint) (uchar) (d))
+
+
+static int my_strnncoll_cp932_internal(CHARSET_INFO *cs,
+ const uchar **a_res, uint a_length,
+ const uchar **b_res, uint b_length)
+{
+ const uchar *a= *a_res, *b= *b_res;
+ const uchar *a_end= a + a_length;
+ const uchar *b_end= b + b_length;
+ while (a < a_end && b < b_end)
+ {
+ if (ismbchar_cp932(cs,(char*) a, (char*) a_end) &&
+ ismbchar_cp932(cs,(char*) b, (char*) b_end))
+ {
+ uint a_char= cp932code(*a, *(a+1));
+ uint b_char= cp932code(*b, *(b+1));
+ if (a_char != b_char)
+ return a_char - b_char;
+ a += 2;
+ b += 2;
+ } else
+ {
+ if (sort_order_cp932[(uchar)*a] != sort_order_cp932[(uchar)*b])
+ return sort_order_cp932[(uchar)*a] - sort_order_cp932[(uchar)*b];
+ a++;
+ b++;
+ }
+ }
+ *a_res= a;
+ *b_res= b;
+ return 0;
+}
+
+
+static int my_strnncoll_cp932(CHARSET_INFO *cs __attribute__((unused)),
+ const uchar *a, uint a_length,
+ const uchar *b, uint b_length,
+ my_bool b_is_prefix)
+{
+ int res= my_strnncoll_cp932_internal(cs, &a, a_length, &b, b_length);
+ if (b_is_prefix && a_length > b_length)
+ a_length= b_length;
+ return res ? res : (int) (a_length - b_length);
+}
+
+
+static int my_strnncollsp_cp932(CHARSET_INFO *cs __attribute__((unused)),
+ const uchar *a, uint a_length,
+ const uchar *b, uint b_length,
+ my_bool diff_if_only_endspace_difference
+ __attribute__((unused)))
+{
+ const uchar *a_end= a + a_length;
+ const uchar *b_end= b + b_length;
+ int res= my_strnncoll_cp932_internal(cs, &a, a_length, &b, b_length);
+ if (!res && (a != a_end || b != b_end))
+ {
+ int swap= 0;
+ /*
+ Check the next not space character of the longer key. If it's < ' ',
+ then it's smaller than the other key.
+ */
+ if (a == a_end)
+ {
+ /* put shorter key in a */
+ a_end= b_end;
+ a= b;
+ swap= -1; /* swap sign of result */
+ }
+ for (; a < a_end ; a++)
+ {
+ if (*a != ' ')
+ return ((int) *a - (int) ' ') ^ swap;
+ }
+ }
+ return res;
+}
+
+
+
+static int my_strnxfrm_cp932(CHARSET_INFO *cs __attribute__((unused)),
+ uchar *dest, uint len,
+ const uchar *src, uint srclen)
+{
+ uchar *d_end = dest + len;
+ uchar *s_end = (uchar*) src + srclen;
+ while (dest < d_end && src < s_end)
+ {
+ if (ismbchar_cp932(cs,(char*) src, (char*) s_end))
+ {
+ *dest++ = *src++;
+ if (dest < d_end && src < s_end)
+ *dest++ = *src++;
+ }
+ else
+ *dest++ = sort_order_cp932[(uchar)*src++];
+ }
+ if (len > srclen)
+ bfill(dest, len - srclen, ' ');
+ return len;
+}
+
+
+/*
+** Calculate min_str and max_str that ranges a LIKE string.
+** Arguments:
+** ptr Pointer to LIKE string.
+** ptr_length Length of LIKE string.
+** escape Escape character in LIKE. (Normally '\').
+** All escape characters should be removed from min_str and max_str
+** res_length Length of min_str and max_str.
+** min_str Smallest case sensitive string that ranges LIKE.
+** Should be space padded to res_length.
+** max_str Largest case sensitive string that ranges LIKE.
+** Normally padded with the biggest character sort value.
+**
+** The function should return 0 if ok and 1 if the LIKE string can't be
+** optimized !
+*/
+
+#define max_sort_char ((char) 255)
+
+static my_bool my_like_range_cp932(CHARSET_INFO *cs __attribute__((unused)),
+ const char *ptr,uint ptr_length,
+ pbool escape, pbool w_one, pbool w_many,
+ uint res_length, char *min_str,char *max_str,
+ uint *min_length,uint *max_length)
+{
+ const char *end=ptr+ptr_length;
+ char *min_org=min_str;
+ char *min_end=min_str+res_length;
+
+ while (ptr < end && min_str < min_end) {
+ if (ismbchar_cp932(cs, ptr, end)) {
+ *min_str++ = *max_str++ = *ptr++;
+ if (min_str < min_end)
+ *min_str++ = *max_str++ = *ptr++;
+ continue;
+ }
+ if (*ptr == escape && ptr+1 < end) {
+ ptr++; /* Skip escape */
+ if (ismbchar_cp932(cs, ptr, end))
+ *min_str++ = *max_str++ = *ptr++;
+ if (min_str < min_end)
+ *min_str++ = *max_str++ = *ptr++;
+ continue;
+ }
+ if (*ptr == w_one) { /* '_' in SQL */
+ *min_str++ = '\0'; /* This should be min char */
+ *max_str++ = max_sort_char;
+ ptr++;
+ continue;
+ }
+ if (*ptr == w_many)
+ { /* '%' in SQL */
+ *min_length = (uint)(min_str - min_org);
+ *max_length = res_length;
+ do
+ {
+ *min_str++= 0;
+ *max_str++= max_sort_char;
+ } while (min_str < min_end);
+ return 0;
+ }
+ *min_str++ = *max_str++ = *ptr++;
+ }
+ *min_length = *max_length = (uint)(min_str - min_org);
+ while (min_str < min_end)
+ *min_str++ = *max_str++ = ' '; /* Because if key compression */
+ return 0;
+}
+
+/* page 0 0x00A1-0x00DF */
+static uint16 tab_cp932_uni0[]={
+0xFF61,0xFF62,0xFF63,0xFF64,0xFF65,0xFF66,0xFF67,0xFF68,
+0xFF69,0xFF6A,0xFF6B,0xFF6C,0xFF6D,0xFF6E,0xFF6F,0xFF70,
+0xFF71,0xFF72,0xFF73,0xFF74,0xFF75,0xFF76,0xFF77,0xFF78,
+0xFF79,0xFF7A,0xFF7B,0xFF7C,0xFF7D,0xFF7E,0xFF7F,0xFF80,
+0xFF81,0xFF82,0xFF83,0xFF84,0xFF85,0xFF86,0xFF87,0xFF88,
+0xFF89,0xFF8A,0xFF8B,0xFF8C,0xFF8D,0xFF8E,0xFF8F,0xFF90,
+0xFF91,0xFF92,0xFF93,0xFF94,0xFF95,0xFF96,0xFF97,0xFF98,
+0xFF99,0xFF9A,0xFF9B,0xFF9C,0xFF9D,0xFF9E,0xFF9F};
+
+/* page 1 0x8140-0x84BE */
+static uint16 tab_cp932_uni1[]={
+0x3000,0x3001,0x3002,0xFF0C,0xFF0E,0x30FB,0xFF1A,0xFF1B,
+0xFF1F,0xFF01,0x309B,0x309C,0x00B4,0xFF40,0x00A8,0xFF3E,
+0xFFE3,0xFF3F,0x30FD,0x30FE,0x309D,0x309E,0x3003,0x4EDD,
+0x3005,0x3006,0x3007,0x30FC,0x2015,0x2010,0xFF0F,0xFF3C,
+0xFF5E,0x2225,0xFF5C,0x2026,0x2025,0x2018,0x2019,0x201C,
+0x201D,0xFF08,0xFF09,0x3014,0x3015,0xFF3B,0xFF3D,0xFF5B,
+0xFF5D,0x3008,0x3009,0x300A,0x300B,0x300C,0x300D,0x300E,
+0x300F,0x3010,0x3011,0xFF0B,0xFF0D,0x00B1,0x00D7, 0,
+0x00F7,0xFF1D,0x2260,0xFF1C,0xFF1E,0x2266,0x2267,0x221E,
+0x2234,0x2642,0x2640,0x00B0,0x2032,0x2033,0x2103,0xFFE5,
+0xFF04,0xFFE0,0xFFE1,0xFF05,0xFF03,0xFF06,0xFF0A,0xFF20,
+0x00A7,0x2606,0x2605,0x25CB,0x25CF,0x25CE,0x25C7,0x25C6,
+0x25A1,0x25A0,0x25B3,0x25B2,0x25BD,0x25BC,0x203B,0x3012,
+0x2192,0x2190,0x2191,0x2193,0x3013, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x2208,0x220B,0x2286,0x2287,0x2282,0x2283,0x222A,0x2229,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x2227,0x2228,0xFFE2,0x21D2,0x21D4,0x2200,0x2203, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x2220,0x22A5,0x2312,0x2202,0x2207,0x2261,
+0x2252,0x226A,0x226B,0x221A,0x223D,0x221D,0x2235,0x222B,
+0x222C, 0, 0, 0, 0, 0, 0, 0,
+0x212B,0x2030,0x266F,0x266D,0x266A,0x2020,0x2021,0x00B6,
+ 0, 0, 0, 0,0x25EF, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xFF10,
+0xFF11,0xFF12,0xFF13,0xFF14,0xFF15,0xFF16,0xFF17,0xFF18,
+0xFF19, 0, 0, 0, 0, 0, 0, 0,
+0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,
+0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,
+0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,
+0xFF39,0xFF3A, 0, 0, 0, 0, 0, 0,
+ 0,0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,
+0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,
+0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,
+0xFF58,0xFF59,0xFF5A, 0, 0, 0, 0,0x3041,
+0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,
+0x304A,0x304B,0x304C,0x304D,0x304E,0x304F,0x3050,0x3051,
+0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058,0x3059,
+0x305A,0x305B,0x305C,0x305D,0x305E,0x305F,0x3060,0x3061,
+0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,0x3069,
+0x306A,0x306B,0x306C,0x306D,0x306E,0x306F,0x3070,0x3071,
+0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,0x3079,
+0x307A,0x307B,0x307C,0x307D,0x307E,0x307F,0x3080,0x3081,
+0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,
+0x308A,0x308B,0x308C,0x308D,0x308E,0x308F,0x3090,0x3091,
+0x3092,0x3093, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x30A1,0x30A2,0x30A3,0x30A4,0x30A5,0x30A6,0x30A7,0x30A8,
+0x30A9,0x30AA,0x30AB,0x30AC,0x30AD,0x30AE,0x30AF,0x30B0,
+0x30B1,0x30B2,0x30B3,0x30B4,0x30B5,0x30B6,0x30B7,0x30B8,
+0x30B9,0x30BA,0x30BB,0x30BC,0x30BD,0x30BE,0x30BF,0x30C0,
+0x30C1,0x30C2,0x30C3,0x30C4,0x30C5,0x30C6,0x30C7,0x30C8,
+0x30C9,0x30CA,0x30CB,0x30CC,0x30CD,0x30CE,0x30CF,0x30D0,
+0x30D1,0x30D2,0x30D3,0x30D4,0x30D5,0x30D6,0x30D7,0x30D8,
+0x30D9,0x30DA,0x30DB,0x30DC,0x30DD,0x30DE,0x30DF, 0,
+0x30E0,0x30E1,0x30E2,0x30E3,0x30E4,0x30E5,0x30E6,0x30E7,
+0x30E8,0x30E9,0x30EA,0x30EB,0x30EC,0x30ED,0x30EE,0x30EF,
+0x30F0,0x30F1,0x30F2,0x30F3,0x30F4,0x30F5,0x30F6, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x0391,
+0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,
+0x039A,0x039B,0x039C,0x039D,0x039E,0x039F,0x03A0,0x03A1,
+0x03A3,0x03A4,0x03A5,0x03A6,0x03A7,0x03A8,0x03A9, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x03B1,
+0x03B2,0x03B3,0x03B4,0x03B5,0x03B6,0x03B7,0x03B8,0x03B9,
+0x03BA,0x03BB,0x03BC,0x03BD,0x03BE,0x03BF,0x03C0,0x03C1,
+0x03C3,0x03C4,0x03C5,0x03C6,0x03C7,0x03C8,0x03C9, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,0x0416,
+0x0417,0x0418,0x0419,0x041A,0x041B,0x041C,0x041D,0x041E,
+0x041F,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,
+0x0427,0x0428,0x0429,0x042A,0x042B,0x042C,0x042D,0x042E,
+0x042F, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,
+0x0437,0x0438,0x0439,0x043A,0x043B,0x043C,0x043D, 0,
+0x043E,0x043F,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,
+0x0446,0x0447,0x0448,0x0449,0x044A,0x044B,0x044C,0x044D,
+0x044E,0x044F, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x2500,
+0x2502,0x250C,0x2510,0x2518,0x2514,0x251C,0x252C,0x2524,
+0x2534,0x253C,0x2501,0x2503,0x250F,0x2513,0x251B,0x2517,
+0x2523,0x2533,0x252B,0x253B,0x254B,0x2520,0x252F,0x2528,
+0x2537,0x253F,0x251D,0x2530,0x2525,0x2538,0x2542};
+
+/* page 2 0x8740-0x879C - NEC Row 13 */
+static uint16 tab_cp932_uni2[]={
+0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,
+0x2468,0x2469,0x246A,0x246B,0x246C,0x246D,0x246E,0x246F,
+0x2470,0x2471,0x2472,0x2473,0x2160,0x2161,0x2162,0x2163,
+0x2164,0x2165,0x2166,0x2167,0x2168,0x2169, 0,0x3349,
+0x3314,0x3322,0x334D,0x3318,0x3327,0x3303,0x3336,0x3351,
+0x3357,0x330D,0x3326,0x3323,0x332B,0x334A,0x333B,0x339C,
+0x339D,0x339E,0x338E,0x338F,0x33C4,0x33A1, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x337B, 0,
+0x301D,0x301F,0x2116,0x33CD,0x2121,0x32A4,0x32A5,0x32A6,
+0x32A7,0x32A8,0x3231,0x3232,0x3239,0x337E,0x337D,0x337C,
+0x2252,0x2261,0x222B,0x222E,0x2211,0x221A,0x22A5,0x2220,
+0x221F,0x22BF,0x2235,0x2229,0x222A};
+
+/* page 3 0x889F-0x9FFC */
+static uint16 tab_cp932_uni3[]={
+0x4E9C,0x5516,0x5A03,0x963F,0x54C0,0x611B,0x6328,0x59F6,
+0x9022,0x8475,0x831C,0x7A50,0x60AA,0x63E1,0x6E25,0x65ED,
+0x8466,0x82A6,0x9BF5,0x6893,0x5727,0x65A1,0x6271,0x5B9B,
+0x59D0,0x867B,0x98F4,0x7D62,0x7DBE,0x9B8E,0x6216,0x7C9F,
+0x88B7,0x5B89,0x5EB5,0x6309,0x6697,0x6848,0x95C7,0x978D,
+0x674F,0x4EE5,0x4F0A,0x4F4D,0x4F9D,0x5049,0x56F2,0x5937,
+0x59D4,0x5A01,0x5C09,0x60DF,0x610F,0x6170,0x6613,0x6905,
+0x70BA,0x754F,0x7570,0x79FB,0x7DAD,0x7DEF,0x80C3,0x840E,
+0x8863,0x8B02,0x9055,0x907A,0x533B,0x4E95,0x4EA5,0x57DF,
+0x80B2,0x90C1,0x78EF,0x4E00,0x58F1,0x6EA2,0x9038,0x7A32,
+0x8328,0x828B,0x9C2F,0x5141,0x5370,0x54BD,0x54E1,0x56E0,
+0x59FB,0x5F15,0x98F2,0x6DEB,0x80E4,0x852D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9662,0x9670,0x96A0,0x97FB,0x540B,0x53F3,0x5B87,
+0x70CF,0x7FBD,0x8FC2,0x96E8,0x536F,0x9D5C,0x7ABA,0x4E11,
+0x7893,0x81FC,0x6E26,0x5618,0x5504,0x6B1D,0x851A,0x9C3B,
+0x59E5,0x53A9,0x6D66,0x74DC,0x958F,0x5642,0x4E91,0x904B,
+0x96F2,0x834F,0x990C,0x53E1,0x55B6,0x5B30,0x5F71,0x6620,
+0x66F3,0x6804,0x6C38,0x6CF3,0x6D29,0x745B,0x76C8,0x7A4E,
+0x9834,0x82F1,0x885B,0x8A60,0x92ED,0x6DB2,0x75AB,0x76CA,
+0x99C5,0x60A6,0x8B01,0x8D8A,0x95B2,0x698E,0x53AD,0x5186,
+ 0,0x5712,0x5830,0x5944,0x5BB4,0x5EF6,0x6028,0x63A9,
+0x63F4,0x6CBF,0x6F14,0x708E,0x7114,0x7159,0x71D5,0x733F,
+0x7E01,0x8276,0x82D1,0x8597,0x9060,0x925B,0x9D1B,0x5869,
+0x65BC,0x6C5A,0x7525,0x51F9,0x592E,0x5965,0x5F80,0x5FDC,
+0x62BC,0x65FA,0x6A2A,0x6B27,0x6BB4,0x738B,0x7FC1,0x8956,
+0x9D2C,0x9D0E,0x9EC4,0x5CA1,0x6C96,0x837B,0x5104,0x5C4B,
+0x61B6,0x81C6,0x6876,0x7261,0x4E59,0x4FFA,0x5378,0x6069,
+0x6E29,0x7A4F,0x97F3,0x4E0B,0x5316,0x4EEE,0x4F55,0x4F3D,
+0x4FA1,0x4F73,0x52A0,0x53EF,0x5609,0x590F,0x5AC1,0x5BB6,
+0x5BE1,0x79D1,0x6687,0x679C,0x67B6,0x6B4C,0x6CB3,0x706B,
+0x73C2,0x798D,0x79BE,0x7A3C,0x7B87,0x82B1,0x82DB,0x8304,
+0x8377,0x83EF,0x83D3,0x8766,0x8AB2,0x5629,0x8CA8,0x8FE6,
+0x904E,0x971E,0x868A,0x4FC4,0x5CE8,0x6211,0x7259,0x753B,
+0x81E5,0x82BD,0x86FE,0x8CC0,0x96C5,0x9913,0x99D5,0x4ECB,
+0x4F1A,0x89E3,0x56DE,0x584A,0x58CA,0x5EFB,0x5FEB,0x602A,
+0x6094,0x6062,0x61D0,0x6212,0x62D0,0x6539, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9B41,0x6666,0x68B0,0x6D77,0x7070,0x754C,0x7686,
+0x7D75,0x82A5,0x87F9,0x958B,0x968E,0x8C9D,0x51F1,0x52BE,
+0x5916,0x54B3,0x5BB3,0x5D16,0x6168,0x6982,0x6DAF,0x788D,
+0x84CB,0x8857,0x8A72,0x93A7,0x9AB8,0x6D6C,0x99A8,0x86D9,
+0x57A3,0x67FF,0x86CE,0x920E,0x5283,0x5687,0x5404,0x5ED3,
+0x62E1,0x64B9,0x683C,0x6838,0x6BBB,0x7372,0x78BA,0x7A6B,
+0x899A,0x89D2,0x8D6B,0x8F03,0x90ED,0x95A3,0x9694,0x9769,
+0x5B66,0x5CB3,0x697D,0x984D,0x984E,0x639B,0x7B20,0x6A2B,
+ 0,0x6A7F,0x68B6,0x9C0D,0x6F5F,0x5272,0x559D,0x6070,
+0x62EC,0x6D3B,0x6E07,0x6ED1,0x845B,0x8910,0x8F44,0x4E14,
+0x9C39,0x53F6,0x691B,0x6A3A,0x9784,0x682A,0x515C,0x7AC3,
+0x84B2,0x91DC,0x938C,0x565B,0x9D28,0x6822,0x8305,0x8431,
+0x7CA5,0x5208,0x82C5,0x74E6,0x4E7E,0x4F83,0x51A0,0x5BD2,
+0x520A,0x52D8,0x52E7,0x5DFB,0x559A,0x582A,0x59E6,0x5B8C,
+0x5B98,0x5BDB,0x5E72,0x5E79,0x60A3,0x611F,0x6163,0x61BE,
+0x63DB,0x6562,0x67D1,0x6853,0x68FA,0x6B3E,0x6B53,0x6C57,
+0x6F22,0x6F97,0x6F45,0x74B0,0x7518,0x76E3,0x770B,0x7AFF,
+0x7BA1,0x7C21,0x7DE9,0x7F36,0x7FF0,0x809D,0x8266,0x839E,
+0x89B3,0x8ACC,0x8CAB,0x9084,0x9451,0x9593,0x9591,0x95A2,
+0x9665,0x97D3,0x9928,0x8218,0x4E38,0x542B,0x5CB8,0x5DCC,
+0x73A9,0x764C,0x773C,0x5CA9,0x7FEB,0x8D0B,0x96C1,0x9811,
+0x9854,0x9858,0x4F01,0x4F0E,0x5371,0x559C,0x5668,0x57FA,
+0x5947,0x5B09,0x5BC4,0x5C90,0x5E0C,0x5E7E,0x5FCC,0x63EE,
+0x673A,0x65D7,0x65E2,0x671F,0x68CB,0x68C4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6A5F,0x5E30,0x6BC5,0x6C17,0x6C7D,0x757F,0x7948,
+0x5B63,0x7A00,0x7D00,0x5FBD,0x898F,0x8A18,0x8CB4,0x8D77,
+0x8ECC,0x8F1D,0x98E2,0x9A0E,0x9B3C,0x4E80,0x507D,0x5100,
+0x5993,0x5B9C,0x622F,0x6280,0x64EC,0x6B3A,0x72A0,0x7591,
+0x7947,0x7FA9,0x87FB,0x8ABC,0x8B70,0x63AC,0x83CA,0x97A0,
+0x5409,0x5403,0x55AB,0x6854,0x6A58,0x8A70,0x7827,0x6775,
+0x9ECD,0x5374,0x5BA2,0x811A,0x8650,0x9006,0x4E18,0x4E45,
+0x4EC7,0x4F11,0x53CA,0x5438,0x5BAE,0x5F13,0x6025,0x6551,
+ 0,0x673D,0x6C42,0x6C72,0x6CE3,0x7078,0x7403,0x7A76,
+0x7AAE,0x7B08,0x7D1A,0x7CFE,0x7D66,0x65E7,0x725B,0x53BB,
+0x5C45,0x5DE8,0x62D2,0x62E0,0x6319,0x6E20,0x865A,0x8A31,
+0x8DDD,0x92F8,0x6F01,0x79A6,0x9B5A,0x4EA8,0x4EAB,0x4EAC,
+0x4F9B,0x4FA0,0x50D1,0x5147,0x7AF6,0x5171,0x51F6,0x5354,
+0x5321,0x537F,0x53EB,0x55AC,0x5883,0x5CE1,0x5F37,0x5F4A,
+0x602F,0x6050,0x606D,0x631F,0x6559,0x6A4B,0x6CC1,0x72C2,
+0x72ED,0x77EF,0x80F8,0x8105,0x8208,0x854E,0x90F7,0x93E1,
+0x97FF,0x9957,0x9A5A,0x4EF0,0x51DD,0x5C2D,0x6681,0x696D,
+0x5C40,0x66F2,0x6975,0x7389,0x6850,0x7C81,0x50C5,0x52E4,
+0x5747,0x5DFE,0x9326,0x65A4,0x6B23,0x6B3D,0x7434,0x7981,
+0x79BD,0x7B4B,0x7DCA,0x82B9,0x83CC,0x887F,0x895F,0x8B39,
+0x8FD1,0x91D1,0x541F,0x9280,0x4E5D,0x5036,0x53E5,0x533A,
+0x72D7,0x7396,0x77E9,0x82E6,0x8EAF,0x99C6,0x99C8,0x99D2,
+0x5177,0x611A,0x865E,0x55B0,0x7A7A,0x5076,0x5BD3,0x9047,
+0x9685,0x4E32,0x6ADB,0x91E7,0x5C51,0x5C48, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6398,0x7A9F,0x6C93,0x9774,0x8F61,0x7AAA,0x718A,
+0x9688,0x7C82,0x6817,0x7E70,0x6851,0x936C,0x52F2,0x541B,
+0x85AB,0x8A13,0x7FA4,0x8ECD,0x90E1,0x5366,0x8888,0x7941,
+0x4FC2,0x50BE,0x5211,0x5144,0x5553,0x572D,0x73EA,0x578B,
+0x5951,0x5F62,0x5F84,0x6075,0x6176,0x6167,0x61A9,0x63B2,
+0x643A,0x656C,0x666F,0x6842,0x6E13,0x7566,0x7A3D,0x7CFB,
+0x7D4C,0x7D99,0x7E4B,0x7F6B,0x830E,0x834A,0x86CD,0x8A08,
+0x8A63,0x8B66,0x8EFD,0x981A,0x9D8F,0x82B8,0x8FCE,0x9BE8,
+ 0,0x5287,0x621F,0x6483,0x6FC0,0x9699,0x6841,0x5091,
+0x6B20,0x6C7A,0x6F54,0x7A74,0x7D50,0x8840,0x8A23,0x6708,
+0x4EF6,0x5039,0x5026,0x5065,0x517C,0x5238,0x5263,0x55A7,
+0x570F,0x5805,0x5ACC,0x5EFA,0x61B2,0x61F8,0x62F3,0x6372,
+0x691C,0x6A29,0x727D,0x72AC,0x732E,0x7814,0x786F,0x7D79,
+0x770C,0x80A9,0x898B,0x8B19,0x8CE2,0x8ED2,0x9063,0x9375,
+0x967A,0x9855,0x9A13,0x9E78,0x5143,0x539F,0x53B3,0x5E7B,
+0x5F26,0x6E1B,0x6E90,0x7384,0x73FE,0x7D43,0x8237,0x8A00,
+0x8AFA,0x9650,0x4E4E,0x500B,0x53E4,0x547C,0x56FA,0x59D1,
+0x5B64,0x5DF1,0x5EAB,0x5F27,0x6238,0x6545,0x67AF,0x6E56,
+0x72D0,0x7CCA,0x88B4,0x80A1,0x80E1,0x83F0,0x864E,0x8A87,
+0x8DE8,0x9237,0x96C7,0x9867,0x9F13,0x4E94,0x4E92,0x4F0D,
+0x5348,0x5449,0x543E,0x5A2F,0x5F8C,0x5FA1,0x609F,0x68A7,
+0x6A8E,0x745A,0x7881,0x8A9E,0x8AA4,0x8B77,0x9190,0x4E5E,
+0x9BC9,0x4EA4,0x4F7C,0x4FAF,0x5019,0x5016,0x5149,0x516C,
+0x529F,0x52B9,0x52FE,0x539A,0x53E3,0x5411, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x540E,0x5589,0x5751,0x57A2,0x597D,0x5B54,0x5B5D,
+0x5B8F,0x5DE5,0x5DE7,0x5DF7,0x5E78,0x5E83,0x5E9A,0x5EB7,
+0x5F18,0x6052,0x614C,0x6297,0x62D8,0x63A7,0x653B,0x6602,
+0x6643,0x66F4,0x676D,0x6821,0x6897,0x69CB,0x6C5F,0x6D2A,
+0x6D69,0x6E2F,0x6E9D,0x7532,0x7687,0x786C,0x7A3F,0x7CE0,
+0x7D05,0x7D18,0x7D5E,0x7DB1,0x8015,0x8003,0x80AF,0x80B1,
+0x8154,0x818F,0x822A,0x8352,0x884C,0x8861,0x8B1B,0x8CA2,
+0x8CFC,0x90CA,0x9175,0x9271,0x783F,0x92FC,0x95A4,0x964D,
+ 0,0x9805,0x9999,0x9AD8,0x9D3B,0x525B,0x52AB,0x53F7,
+0x5408,0x58D5,0x62F7,0x6FE0,0x8C6A,0x8F5F,0x9EB9,0x514B,
+0x523B,0x544A,0x56FD,0x7A40,0x9177,0x9D60,0x9ED2,0x7344,
+0x6F09,0x8170,0x7511,0x5FFD,0x60DA,0x9AA8,0x72DB,0x8FBC,
+0x6B64,0x9803,0x4ECA,0x56F0,0x5764,0x58BE,0x5A5A,0x6068,
+0x61C7,0x660F,0x6606,0x6839,0x68B1,0x6DF7,0x75D5,0x7D3A,
+0x826E,0x9B42,0x4E9B,0x4F50,0x53C9,0x5506,0x5D6F,0x5DE6,
+0x5DEE,0x67FB,0x6C99,0x7473,0x7802,0x8A50,0x9396,0x88DF,
+0x5750,0x5EA7,0x632B,0x50B5,0x50AC,0x518D,0x6700,0x54C9,
+0x585E,0x59BB,0x5BB0,0x5F69,0x624D,0x63A1,0x683D,0x6B73,
+0x6E08,0x707D,0x91C7,0x7280,0x7815,0x7826,0x796D,0x658E,
+0x7D30,0x83DC,0x88C1,0x8F09,0x969B,0x5264,0x5728,0x6750,
+0x7F6A,0x8CA1,0x51B4,0x5742,0x962A,0x583A,0x698A,0x80B4,
+0x54B2,0x5D0E,0x57FC,0x7895,0x9DFA,0x4F5C,0x524A,0x548B,
+0x643E,0x6628,0x6714,0x67F5,0x7A84,0x7B56,0x7D22,0x932F,
+0x685C,0x9BAD,0x7B39,0x5319,0x518A,0x5237, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5BDF,0x62F6,0x64AE,0x64E6,0x672D,0x6BBA,0x85A9,
+0x96D1,0x7690,0x9BD6,0x634C,0x9306,0x9BAB,0x76BF,0x6652,
+0x4E09,0x5098,0x53C2,0x5C71,0x60E8,0x6492,0x6563,0x685F,
+0x71E6,0x73CA,0x7523,0x7B97,0x7E82,0x8695,0x8B83,0x8CDB,
+0x9178,0x9910,0x65AC,0x66AB,0x6B8B,0x4ED5,0x4ED4,0x4F3A,
+0x4F7F,0x523A,0x53F8,0x53F2,0x55E3,0x56DB,0x58EB,0x59CB,
+0x59C9,0x59FF,0x5B50,0x5C4D,0x5E02,0x5E2B,0x5FD7,0x601D,
+0x6307,0x652F,0x5B5C,0x65AF,0x65BD,0x65E8,0x679D,0x6B62,
+ 0,0x6B7B,0x6C0F,0x7345,0x7949,0x79C1,0x7CF8,0x7D19,
+0x7D2B,0x80A2,0x8102,0x81F3,0x8996,0x8A5E,0x8A69,0x8A66,
+0x8A8C,0x8AEE,0x8CC7,0x8CDC,0x96CC,0x98FC,0x6B6F,0x4E8B,
+0x4F3C,0x4F8D,0x5150,0x5B57,0x5BFA,0x6148,0x6301,0x6642,
+0x6B21,0x6ECB,0x6CBB,0x723E,0x74BD,0x75D4,0x78C1,0x793A,
+0x800C,0x8033,0x81EA,0x8494,0x8F9E,0x6C50,0x9E7F,0x5F0F,
+0x8B58,0x9D2B,0x7AFA,0x8EF8,0x5B8D,0x96EB,0x4E03,0x53F1,
+0x57F7,0x5931,0x5AC9,0x5BA4,0x6089,0x6E7F,0x6F06,0x75BE,
+0x8CEA,0x5B9F,0x8500,0x7BE0,0x5072,0x67F4,0x829D,0x5C61,
+0x854A,0x7E1E,0x820E,0x5199,0x5C04,0x6368,0x8D66,0x659C,
+0x716E,0x793E,0x7D17,0x8005,0x8B1D,0x8ECA,0x906E,0x86C7,
+0x90AA,0x501F,0x52FA,0x5C3A,0x6753,0x707C,0x7235,0x914C,
+0x91C8,0x932B,0x82E5,0x5BC2,0x5F31,0x60F9,0x4E3B,0x53D6,
+0x5B88,0x624B,0x6731,0x6B8A,0x72E9,0x73E0,0x7A2E,0x816B,
+0x8DA3,0x9152,0x9996,0x5112,0x53D7,0x546A,0x5BFF,0x6388,
+0x6A39,0x7DAC,0x9700,0x56DA,0x53CE,0x5468, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5B97,0x5C31,0x5DDE,0x4FEE,0x6101,0x62FE,0x6D32,
+0x79C0,0x79CB,0x7D42,0x7E4D,0x7FD2,0x81ED,0x821F,0x8490,
+0x8846,0x8972,0x8B90,0x8E74,0x8F2F,0x9031,0x914B,0x916C,
+0x96C6,0x919C,0x4EC0,0x4F4F,0x5145,0x5341,0x5F93,0x620E,
+0x67D4,0x6C41,0x6E0B,0x7363,0x7E26,0x91CD,0x9283,0x53D4,
+0x5919,0x5BBF,0x6DD1,0x795D,0x7E2E,0x7C9B,0x587E,0x719F,
+0x51FA,0x8853,0x8FF0,0x4FCA,0x5CFB,0x6625,0x77AC,0x7AE3,
+0x821C,0x99FF,0x51C6,0x5FAA,0x65EC,0x696F,0x6B89,0x6DF3,
+ 0,0x6E96,0x6F64,0x76FE,0x7D14,0x5DE1,0x9075,0x9187,
+0x9806,0x51E6,0x521D,0x6240,0x6691,0x66D9,0x6E1A,0x5EB6,
+0x7DD2,0x7F72,0x66F8,0x85AF,0x85F7,0x8AF8,0x52A9,0x53D9,
+0x5973,0x5E8F,0x5F90,0x6055,0x92E4,0x9664,0x50B7,0x511F,
+0x52DD,0x5320,0x5347,0x53EC,0x54E8,0x5546,0x5531,0x5617,
+0x5968,0x59BE,0x5A3C,0x5BB5,0x5C06,0x5C0F,0x5C11,0x5C1A,
+0x5E84,0x5E8A,0x5EE0,0x5F70,0x627F,0x6284,0x62DB,0x638C,
+0x6377,0x6607,0x660C,0x662D,0x6676,0x677E,0x68A2,0x6A1F,
+0x6A35,0x6CBC,0x6D88,0x6E09,0x6E58,0x713C,0x7126,0x7167,
+0x75C7,0x7701,0x785D,0x7901,0x7965,0x79F0,0x7AE0,0x7B11,
+0x7CA7,0x7D39,0x8096,0x83D6,0x848B,0x8549,0x885D,0x88F3,
+0x8A1F,0x8A3C,0x8A54,0x8A73,0x8C61,0x8CDE,0x91A4,0x9266,
+0x937E,0x9418,0x969C,0x9798,0x4E0A,0x4E08,0x4E1E,0x4E57,
+0x5197,0x5270,0x57CE,0x5834,0x58CC,0x5B22,0x5E38,0x60C5,
+0x64FE,0x6761,0x6756,0x6D44,0x72B6,0x7573,0x7A63,0x84B8,
+0x8B72,0x91B8,0x9320,0x5631,0x57F4,0x98FE, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x62ED,0x690D,0x6B96,0x71ED,0x7E54,0x8077,0x8272,
+0x89E6,0x98DF,0x8755,0x8FB1,0x5C3B,0x4F38,0x4FE1,0x4FB5,
+0x5507,0x5A20,0x5BDD,0x5BE9,0x5FC3,0x614E,0x632F,0x65B0,
+0x664B,0x68EE,0x699B,0x6D78,0x6DF1,0x7533,0x75B9,0x771F,
+0x795E,0x79E6,0x7D33,0x81E3,0x82AF,0x85AA,0x89AA,0x8A3A,
+0x8EAB,0x8F9B,0x9032,0x91DD,0x9707,0x4EBA,0x4EC1,0x5203,
+0x5875,0x58EC,0x5C0B,0x751A,0x5C3D,0x814E,0x8A0A,0x8FC5,
+0x9663,0x976D,0x7B25,0x8ACF,0x9808,0x9162,0x56F3,0x53A8,
+ 0,0x9017,0x5439,0x5782,0x5E25,0x63A8,0x6C34,0x708A,
+0x7761,0x7C8B,0x7FE0,0x8870,0x9042,0x9154,0x9310,0x9318,
+0x968F,0x745E,0x9AC4,0x5D07,0x5D69,0x6570,0x67A2,0x8DA8,
+0x96DB,0x636E,0x6749,0x6919,0x83C5,0x9817,0x96C0,0x88FE,
+0x6F84,0x647A,0x5BF8,0x4E16,0x702C,0x755D,0x662F,0x51C4,
+0x5236,0x52E2,0x59D3,0x5F81,0x6027,0x6210,0x653F,0x6574,
+0x661F,0x6674,0x68F2,0x6816,0x6B63,0x6E05,0x7272,0x751F,
+0x76DB,0x7CBE,0x8056,0x58F0,0x88FD,0x897F,0x8AA0,0x8A93,
+0x8ACB,0x901D,0x9192,0x9752,0x9759,0x6589,0x7A0E,0x8106,
+0x96BB,0x5E2D,0x60DC,0x621A,0x65A5,0x6614,0x6790,0x77F3,
+0x7A4D,0x7C4D,0x7E3E,0x810A,0x8CAC,0x8D64,0x8DE1,0x8E5F,
+0x78A9,0x5207,0x62D9,0x63A5,0x6442,0x6298,0x8A2D,0x7A83,
+0x7BC0,0x8AAC,0x96EA,0x7D76,0x820C,0x8749,0x4ED9,0x5148,
+0x5343,0x5360,0x5BA3,0x5C02,0x5C16,0x5DDD,0x6226,0x6247,
+0x64B0,0x6813,0x6834,0x6CC9,0x6D45,0x6D17,0x67D3,0x6F5C,
+0x714E,0x717D,0x65CB,0x7A7F,0x7BAD,0x7DDA, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x7E4A,0x7FA8,0x817A,0x821B,0x8239,0x85A6,0x8A6E,
+0x8CCE,0x8DF5,0x9078,0x9077,0x92AD,0x9291,0x9583,0x9BAE,
+0x524D,0x5584,0x6F38,0x7136,0x5168,0x7985,0x7E55,0x81B3,
+0x7CCE,0x564C,0x5851,0x5CA8,0x63AA,0x66FE,0x66FD,0x695A,
+0x72D9,0x758F,0x758E,0x790E,0x7956,0x79DF,0x7C97,0x7D20,
+0x7D44,0x8607,0x8A34,0x963B,0x9061,0x9F20,0x50E7,0x5275,
+0x53CC,0x53E2,0x5009,0x55AA,0x58EE,0x594F,0x723D,0x5B8B,
+0x5C64,0x531D,0x60E3,0x60F3,0x635C,0x6383,0x633F,0x63BB,
+ 0,0x64CD,0x65E9,0x66F9,0x5DE3,0x69CD,0x69FD,0x6F15,
+0x71E5,0x4E89,0x75E9,0x76F8,0x7A93,0x7CDF,0x7DCF,0x7D9C,
+0x8061,0x8349,0x8358,0x846C,0x84BC,0x85FB,0x88C5,0x8D70,
+0x9001,0x906D,0x9397,0x971C,0x9A12,0x50CF,0x5897,0x618E,
+0x81D3,0x8535,0x8D08,0x9020,0x4FC3,0x5074,0x5247,0x5373,
+0x606F,0x6349,0x675F,0x6E2C,0x8DB3,0x901F,0x4FD7,0x5C5E,
+0x8CCA,0x65CF,0x7D9A,0x5352,0x8896,0x5176,0x63C3,0x5B58,
+0x5B6B,0x5C0A,0x640D,0x6751,0x905C,0x4ED6,0x591A,0x592A,
+0x6C70,0x8A51,0x553E,0x5815,0x59A5,0x60F0,0x6253,0x67C1,
+0x8235,0x6955,0x9640,0x99C4,0x9A28,0x4F53,0x5806,0x5BFE,
+0x8010,0x5CB1,0x5E2F,0x5F85,0x6020,0x614B,0x6234,0x66FF,
+0x6CF0,0x6EDE,0x80CE,0x817F,0x82D4,0x888B,0x8CB8,0x9000,
+0x902E,0x968A,0x9EDB,0x9BDB,0x4EE3,0x53F0,0x5927,0x7B2C,
+0x918D,0x984C,0x9DF9,0x6EDD,0x7027,0x5353,0x5544,0x5B85,
+0x6258,0x629E,0x62D3,0x6CA2,0x6FEF,0x7422,0x8A17,0x9438,
+0x6FC1,0x8AFE,0x8338,0x51E7,0x86F8,0x53EA, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x53E9,0x4F46,0x9054,0x8FB0,0x596A,0x8131,0x5DFD,
+0x7AEA,0x8FBF,0x68DA,0x8C37,0x72F8,0x9C48,0x6A3D,0x8AB0,
+0x4E39,0x5358,0x5606,0x5766,0x62C5,0x63A2,0x65E6,0x6B4E,
+0x6DE1,0x6E5B,0x70AD,0x77ED,0x7AEF,0x7BAA,0x7DBB,0x803D,
+0x80C6,0x86CB,0x8A95,0x935B,0x56E3,0x58C7,0x5F3E,0x65AD,
+0x6696,0x6A80,0x6BB5,0x7537,0x8AC7,0x5024,0x77E5,0x5730,
+0x5F1B,0x6065,0x667A,0x6C60,0x75F4,0x7A1A,0x7F6E,0x81F4,
+0x8718,0x9045,0x99B3,0x7BC9,0x755C,0x7AF9,0x7B51,0x84C4,
+ 0,0x9010,0x79E9,0x7A92,0x8336,0x5AE1,0x7740,0x4E2D,
+0x4EF2,0x5B99,0x5FE0,0x62BD,0x663C,0x67F1,0x6CE8,0x866B,
+0x8877,0x8A3B,0x914E,0x92F3,0x99D0,0x6A17,0x7026,0x732A,
+0x82E7,0x8457,0x8CAF,0x4E01,0x5146,0x51CB,0x558B,0x5BF5,
+0x5E16,0x5E33,0x5E81,0x5F14,0x5F35,0x5F6B,0x5FB4,0x61F2,
+0x6311,0x66A2,0x671D,0x6F6E,0x7252,0x753A,0x773A,0x8074,
+0x8139,0x8178,0x8776,0x8ABF,0x8ADC,0x8D85,0x8DF3,0x929A,
+0x9577,0x9802,0x9CE5,0x52C5,0x6357,0x76F4,0x6715,0x6C88,
+0x73CD,0x8CC3,0x93AE,0x9673,0x6D25,0x589C,0x690E,0x69CC,
+0x8FFD,0x939A,0x75DB,0x901A,0x585A,0x6802,0x63B4,0x69FB,
+0x4F43,0x6F2C,0x67D8,0x8FBB,0x8526,0x7DB4,0x9354,0x693F,
+0x6F70,0x576A,0x58F7,0x5B2C,0x7D2C,0x722A,0x540A,0x91E3,
+0x9DB4,0x4EAD,0x4F4E,0x505C,0x5075,0x5243,0x8C9E,0x5448,
+0x5824,0x5B9A,0x5E1D,0x5E95,0x5EAD,0x5EF7,0x5F1F,0x608C,
+0x62B5,0x633A,0x63D0,0x68AF,0x6C40,0x7887,0x798E,0x7A0B,
+0x7DE0,0x8247,0x8A02,0x8AE6,0x8E44,0x9013, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x90B8,0x912D,0x91D8,0x9F0E,0x6CE5,0x6458,0x64E2,
+0x6575,0x6EF4,0x7684,0x7B1B,0x9069,0x93D1,0x6EBA,0x54F2,
+0x5FB9,0x64A4,0x8F4D,0x8FED,0x9244,0x5178,0x586B,0x5929,
+0x5C55,0x5E97,0x6DFB,0x7E8F,0x751C,0x8CBC,0x8EE2,0x985B,
+0x70B9,0x4F1D,0x6BBF,0x6FB1,0x7530,0x96FB,0x514E,0x5410,
+0x5835,0x5857,0x59AC,0x5C60,0x5F92,0x6597,0x675C,0x6E21,
+0x767B,0x83DF,0x8CED,0x9014,0x90FD,0x934D,0x7825,0x783A,
+0x52AA,0x5EA6,0x571F,0x5974,0x6012,0x5012,0x515A,0x51AC,
+ 0,0x51CD,0x5200,0x5510,0x5854,0x5858,0x5957,0x5B95,
+0x5CF6,0x5D8B,0x60BC,0x6295,0x642D,0x6771,0x6843,0x68BC,
+0x68DF,0x76D7,0x6DD8,0x6E6F,0x6D9B,0x706F,0x71C8,0x5F53,
+0x75D8,0x7977,0x7B49,0x7B54,0x7B52,0x7CD6,0x7D71,0x5230,
+0x8463,0x8569,0x85E4,0x8A0E,0x8B04,0x8C46,0x8E0F,0x9003,
+0x900F,0x9419,0x9676,0x982D,0x9A30,0x95D8,0x50CD,0x52D5,
+0x540C,0x5802,0x5C0E,0x61A7,0x649E,0x6D1E,0x77B3,0x7AE5,
+0x80F4,0x8404,0x9053,0x9285,0x5CE0,0x9D07,0x533F,0x5F97,
+0x5FB3,0x6D9C,0x7279,0x7763,0x79BF,0x7BE4,0x6BD2,0x72EC,
+0x8AAD,0x6803,0x6A61,0x51F8,0x7A81,0x6934,0x5C4A,0x9CF6,
+0x82EB,0x5BC5,0x9149,0x701E,0x5678,0x5C6F,0x60C7,0x6566,
+0x6C8C,0x8C5A,0x9041,0x9813,0x5451,0x66C7,0x920D,0x5948,
+0x90A3,0x5185,0x4E4D,0x51EA,0x8599,0x8B0E,0x7058,0x637A,
+0x934B,0x6962,0x99B4,0x7E04,0x7577,0x5357,0x6960,0x8EDF,
+0x96E3,0x6C5D,0x4E8C,0x5C3C,0x5F10,0x8FE9,0x5302,0x8CD1,
+0x8089,0x8679,0x5EFF,0x65E5,0x4E73,0x5165, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5982,0x5C3F,0x97EE,0x4EFB,0x598A,0x5FCD,0x8A8D,
+0x6FE1,0x79B0,0x7962,0x5BE7,0x8471,0x732B,0x71B1,0x5E74,
+0x5FF5,0x637B,0x649A,0x71C3,0x7C98,0x4E43,0x5EFC,0x4E4B,
+0x57DC,0x56A2,0x60A9,0x6FC3,0x7D0D,0x80FD,0x8133,0x81BF,
+0x8FB2,0x8997,0x86A4,0x5DF4,0x628A,0x64AD,0x8987,0x6777,
+0x6CE2,0x6D3E,0x7436,0x7834,0x5A46,0x7F75,0x82AD,0x99AC,
+0x4FF3,0x5EC3,0x62DD,0x6392,0x6557,0x676F,0x76C3,0x724C,
+0x80CC,0x80BA,0x8F29,0x914D,0x500D,0x57F9,0x5A92,0x6885,
+ 0,0x6973,0x7164,0x72FD,0x8CB7,0x58F2,0x8CE0,0x966A,
+0x9019,0x877F,0x79E4,0x77E7,0x8429,0x4F2F,0x5265,0x535A,
+0x62CD,0x67CF,0x6CCA,0x767D,0x7B94,0x7C95,0x8236,0x8584,
+0x8FEB,0x66DD,0x6F20,0x7206,0x7E1B,0x83AB,0x99C1,0x9EA6,
+0x51FD,0x7BB1,0x7872,0x7BB8,0x8087,0x7B48,0x6AE8,0x5E61,
+0x808C,0x7551,0x7560,0x516B,0x9262,0x6E8C,0x767A,0x9197,
+0x9AEA,0x4F10,0x7F70,0x629C,0x7B4F,0x95A5,0x9CE9,0x567A,
+0x5859,0x86E4,0x96BC,0x4F34,0x5224,0x534A,0x53CD,0x53DB,
+0x5E06,0x642C,0x6591,0x677F,0x6C3E,0x6C4E,0x7248,0x72AF,
+0x73ED,0x7554,0x7E41,0x822C,0x85E9,0x8CA9,0x7BC4,0x91C6,
+0x7169,0x9812,0x98EF,0x633D,0x6669,0x756A,0x76E4,0x78D0,
+0x8543,0x86EE,0x532A,0x5351,0x5426,0x5983,0x5E87,0x5F7C,
+0x60B2,0x6249,0x6279,0x62AB,0x6590,0x6BD4,0x6CCC,0x75B2,
+0x76AE,0x7891,0x79D8,0x7DCB,0x7F77,0x80A5,0x88AB,0x8AB9,
+0x8CBB,0x907F,0x975E,0x98DB,0x6A0B,0x7C38,0x5099,0x5C3E,
+0x5FAE,0x6787,0x6BD8,0x7435,0x7709,0x7F8E, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9F3B,0x67CA,0x7A17,0x5339,0x758B,0x9AED,0x5F66,
+0x819D,0x83F1,0x8098,0x5F3C,0x5FC5,0x7562,0x7B46,0x903C,
+0x6867,0x59EB,0x5A9B,0x7D10,0x767E,0x8B2C,0x4FF5,0x5F6A,
+0x6A19,0x6C37,0x6F02,0x74E2,0x7968,0x8868,0x8A55,0x8C79,
+0x5EDF,0x63CF,0x75C5,0x79D2,0x82D7,0x9328,0x92F2,0x849C,
+0x86ED,0x9C2D,0x54C1,0x5F6C,0x658C,0x6D5C,0x7015,0x8CA7,
+0x8CD3,0x983B,0x654F,0x74F6,0x4E0D,0x4ED8,0x57E0,0x592B,
+0x5A66,0x5BCC,0x51A8,0x5E03,0x5E9C,0x6016,0x6276,0x6577,
+ 0,0x65A7,0x666E,0x6D6E,0x7236,0x7B26,0x8150,0x819A,
+0x8299,0x8B5C,0x8CA0,0x8CE6,0x8D74,0x961C,0x9644,0x4FAE,
+0x64AB,0x6B66,0x821E,0x8461,0x856A,0x90E8,0x5C01,0x6953,
+0x98A8,0x847A,0x8557,0x4F0F,0x526F,0x5FA9,0x5E45,0x670D,
+0x798F,0x8179,0x8907,0x8986,0x6DF5,0x5F17,0x6255,0x6CB8,
+0x4ECF,0x7269,0x9B92,0x5206,0x543B,0x5674,0x58B3,0x61A4,
+0x626E,0x711A,0x596E,0x7C89,0x7CDE,0x7D1B,0x96F0,0x6587,
+0x805E,0x4E19,0x4F75,0x5175,0x5840,0x5E63,0x5E73,0x5F0A,
+0x67C4,0x4E26,0x853D,0x9589,0x965B,0x7C73,0x9801,0x50FB,
+0x58C1,0x7656,0x78A7,0x5225,0x77A5,0x8511,0x7B86,0x504F,
+0x5909,0x7247,0x7BC7,0x7DE8,0x8FBA,0x8FD4,0x904D,0x4FBF,
+0x52C9,0x5A29,0x5F01,0x97AD,0x4FDD,0x8217,0x92EA,0x5703,
+0x6355,0x6B69,0x752B,0x88DC,0x8F14,0x7A42,0x52DF,0x5893,
+0x6155,0x620A,0x66AE,0x6BCD,0x7C3F,0x83E9,0x5023,0x4FF8,
+0x5305,0x5446,0x5831,0x5949,0x5B9D,0x5CF0,0x5CEF,0x5D29,
+0x5E96,0x62B1,0x6367,0x653E,0x65B9,0x670B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6CD5,0x6CE1,0x70F9,0x7832,0x7E2B,0x80DE,0x82B3,
+0x840C,0x84EC,0x8702,0x8912,0x8A2A,0x8C4A,0x90A6,0x92D2,
+0x98FD,0x9CF3,0x9D6C,0x4E4F,0x4EA1,0x508D,0x5256,0x574A,
+0x59A8,0x5E3D,0x5FD8,0x5FD9,0x623F,0x66B4,0x671B,0x67D0,
+0x68D2,0x5192,0x7D21,0x80AA,0x81A8,0x8B00,0x8C8C,0x8CBF,
+0x927E,0x9632,0x5420,0x982C,0x5317,0x50D5,0x535C,0x58A8,
+0x64B2,0x6734,0x7267,0x7766,0x7A46,0x91E6,0x52C3,0x6CA1,
+0x6B86,0x5800,0x5E4C,0x5954,0x672C,0x7FFB,0x51E1,0x76C6,
+ 0,0x6469,0x78E8,0x9B54,0x9EBB,0x57CB,0x59B9,0x6627,
+0x679A,0x6BCE,0x54E9,0x69D9,0x5E55,0x819C,0x6795,0x9BAA,
+0x67FE,0x9C52,0x685D,0x4EA6,0x4FE3,0x53C8,0x62B9,0x672B,
+0x6CAB,0x8FC4,0x4FAD,0x7E6D,0x9EBF,0x4E07,0x6162,0x6E80,
+0x6F2B,0x8513,0x5473,0x672A,0x9B45,0x5DF3,0x7B95,0x5CAC,
+0x5BC6,0x871C,0x6E4A,0x84D1,0x7A14,0x8108,0x5999,0x7C8D,
+0x6C11,0x7720,0x52D9,0x5922,0x7121,0x725F,0x77DB,0x9727,
+0x9D61,0x690B,0x5A7F,0x5A18,0x51A5,0x540D,0x547D,0x660E,
+0x76DF,0x8FF7,0x9298,0x9CF4,0x59EA,0x725D,0x6EC5,0x514D,
+0x68C9,0x7DBF,0x7DEC,0x9762,0x9EBA,0x6478,0x6A21,0x8302,
+0x5984,0x5B5F,0x6BDB,0x731B,0x76F2,0x7DB2,0x8017,0x8499,
+0x5132,0x6728,0x9ED9,0x76EE,0x6762,0x52FF,0x9905,0x5C24,
+0x623B,0x7C7E,0x8CB0,0x554F,0x60B6,0x7D0B,0x9580,0x5301,
+0x4E5F,0x51B6,0x591C,0x723A,0x8036,0x91CE,0x5F25,0x77E2,
+0x5384,0x5F79,0x7D04,0x85AC,0x8A33,0x8E8D,0x9756,0x67F3,
+0x85AE,0x9453,0x6109,0x6108,0x6CB9,0x7652, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x8AED,0x8F38,0x552F,0x4F51,0x512A,0x52C7,0x53CB,
+0x5BA5,0x5E7D,0x60A0,0x6182,0x63D6,0x6709,0x67DA,0x6E67,
+0x6D8C,0x7336,0x7337,0x7531,0x7950,0x88D5,0x8A98,0x904A,
+0x9091,0x90F5,0x96C4,0x878D,0x5915,0x4E88,0x4F59,0x4E0E,
+0x8A89,0x8F3F,0x9810,0x50AD,0x5E7C,0x5996,0x5BB9,0x5EB8,
+0x63DA,0x63FA,0x64C1,0x66DC,0x694A,0x69D8,0x6D0B,0x6EB6,
+0x7194,0x7528,0x7AAF,0x7F8A,0x8000,0x8449,0x84C9,0x8981,
+0x8B21,0x8E0A,0x9065,0x967D,0x990A,0x617E,0x6291,0x6B32,
+ 0,0x6C83,0x6D74,0x7FCC,0x7FFC,0x6DC0,0x7F85,0x87BA,
+0x88F8,0x6765,0x83B1,0x983C,0x96F7,0x6D1B,0x7D61,0x843D,
+0x916A,0x4E71,0x5375,0x5D50,0x6B04,0x6FEB,0x85CD,0x862D,
+0x89A7,0x5229,0x540F,0x5C65,0x674E,0x68A8,0x7406,0x7483,
+0x75E2,0x88CF,0x88E1,0x91CC,0x96E2,0x9678,0x5F8B,0x7387,
+0x7ACB,0x844E,0x63A0,0x7565,0x5289,0x6D41,0x6E9C,0x7409,
+0x7559,0x786B,0x7C92,0x9686,0x7ADC,0x9F8D,0x4FB6,0x616E,
+0x65C5,0x865C,0x4E86,0x4EAE,0x50DA,0x4E21,0x51CC,0x5BEE,
+0x6599,0x6881,0x6DBC,0x731F,0x7642,0x77AD,0x7A1C,0x7CE7,
+0x826F,0x8AD2,0x907C,0x91CF,0x9675,0x9818,0x529B,0x7DD1,
+0x502B,0x5398,0x6797,0x6DCB,0x71D0,0x7433,0x81E8,0x8F2A,
+0x96A3,0x9C57,0x9E9F,0x7460,0x5841,0x6D99,0x7D2F,0x985E,
+0x4EE4,0x4F36,0x4F8B,0x51B7,0x52B1,0x5DBA,0x601C,0x73B2,
+0x793C,0x82D3,0x9234,0x96B7,0x96F6,0x970A,0x9E97,0x9F62,
+0x66A6,0x6B74,0x5217,0x52A3,0x70C8,0x88C2,0x5EC9,0x604B,
+0x6190,0x6F23,0x7149,0x7C3E,0x7DF4,0x806F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x84EE,0x9023,0x932C,0x5442,0x9B6F,0x6AD3,0x7089,
+0x8CC2,0x8DEF,0x9732,0x52B4,0x5A41,0x5ECA,0x5F04,0x6717,
+0x697C,0x6994,0x6D6A,0x6F0F,0x7262,0x72FC,0x7BED,0x8001,
+0x807E,0x874B,0x90CE,0x516D,0x9E93,0x7984,0x808B,0x9332,
+0x8AD6,0x502D,0x548C,0x8A71,0x6B6A,0x8CC4,0x8107,0x60D1,
+0x67A0,0x9DF2,0x4E99,0x4E98,0x9C10,0x8A6B,0x85C1,0x8568,
+0x6900,0x6E7E,0x7897,0x8155, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5F0C,0x4E10,0x4E15,0x4E2A,0x4E31,0x4E36,0x4E3C,0x4E3F,
+0x4E42,0x4E56,0x4E58,0x4E82,0x4E85,0x8C6B,0x4E8A,0x8212,
+0x5F0D,0x4E8E,0x4E9E,0x4E9F,0x4EA0,0x4EA2,0x4EB0,0x4EB3,
+0x4EB6,0x4ECE,0x4ECD,0x4EC4,0x4EC6,0x4EC2,0x4ED7,0x4EDE,
+0x4EED,0x4EDF,0x4EF7,0x4F09,0x4F5A,0x4F30,0x4F5B,0x4F5D,
+0x4F57,0x4F47,0x4F76,0x4F88,0x4F8F,0x4F98,0x4F7B,0x4F69,
+0x4F70,0x4F91,0x4F6F,0x4F86,0x4F96,0x5118,0x4FD4,0x4FDF,
+0x4FCE,0x4FD8,0x4FDB,0x4FD1,0x4FDA,0x4FD0,0x4FE4,0x4FE5,
+0x501A,0x5028,0x5014,0x502A,0x5025,0x5005,0x4F1C,0x4FF6,
+0x5021,0x5029,0x502C,0x4FFE,0x4FEF,0x5011,0x5006,0x5043,
+0x5047,0x6703,0x5055,0x5050,0x5048,0x505A,0x5056,0x506C,
+0x5078,0x5080,0x509A,0x5085,0x50B4,0x50B2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x50C9,0x50CA,0x50B3,0x50C2,0x50D6,0x50DE,0x50E5,
+0x50ED,0x50E3,0x50EE,0x50F9,0x50F5,0x5109,0x5101,0x5102,
+0x5116,0x5115,0x5114,0x511A,0x5121,0x513A,0x5137,0x513C,
+0x513B,0x513F,0x5140,0x5152,0x514C,0x5154,0x5162,0x7AF8,
+0x5169,0x516A,0x516E,0x5180,0x5182,0x56D8,0x518C,0x5189,
+0x518F,0x5191,0x5193,0x5195,0x5196,0x51A4,0x51A6,0x51A2,
+0x51A9,0x51AA,0x51AB,0x51B3,0x51B1,0x51B2,0x51B0,0x51B5,
+0x51BD,0x51C5,0x51C9,0x51DB,0x51E0,0x8655,0x51E9,0x51ED,
+ 0,0x51F0,0x51F5,0x51FE,0x5204,0x520B,0x5214,0x520E,
+0x5227,0x522A,0x522E,0x5233,0x5239,0x524F,0x5244,0x524B,
+0x524C,0x525E,0x5254,0x526A,0x5274,0x5269,0x5273,0x527F,
+0x527D,0x528D,0x5294,0x5292,0x5271,0x5288,0x5291,0x8FA8,
+0x8FA7,0x52AC,0x52AD,0x52BC,0x52B5,0x52C1,0x52CD,0x52D7,
+0x52DE,0x52E3,0x52E6,0x98ED,0x52E0,0x52F3,0x52F5,0x52F8,
+0x52F9,0x5306,0x5308,0x7538,0x530D,0x5310,0x530F,0x5315,
+0x531A,0x5323,0x532F,0x5331,0x5333,0x5338,0x5340,0x5346,
+0x5345,0x4E17,0x5349,0x534D,0x51D6,0x535E,0x5369,0x536E,
+0x5918,0x537B,0x5377,0x5382,0x5396,0x53A0,0x53A6,0x53A5,
+0x53AE,0x53B0,0x53B6,0x53C3,0x7C12,0x96D9,0x53DF,0x66FC,
+0x71EE,0x53EE,0x53E8,0x53ED,0x53FA,0x5401,0x543D,0x5440,
+0x542C,0x542D,0x543C,0x542E,0x5436,0x5429,0x541D,0x544E,
+0x548F,0x5475,0x548E,0x545F,0x5471,0x5477,0x5470,0x5492,
+0x547B,0x5480,0x5476,0x5484,0x5490,0x5486,0x54C7,0x54A2,
+0x54B8,0x54A5,0x54AC,0x54C4,0x54C8,0x54A8, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x54AB,0x54C2,0x54A4,0x54BE,0x54BC,0x54D8,0x54E5,
+0x54E6,0x550F,0x5514,0x54FD,0x54EE,0x54ED,0x54FA,0x54E2,
+0x5539,0x5540,0x5563,0x554C,0x552E,0x555C,0x5545,0x5556,
+0x5557,0x5538,0x5533,0x555D,0x5599,0x5580,0x54AF,0x558A,
+0x559F,0x557B,0x557E,0x5598,0x559E,0x55AE,0x557C,0x5583,
+0x55A9,0x5587,0x55A8,0x55DA,0x55C5,0x55DF,0x55C4,0x55DC,
+0x55E4,0x55D4,0x5614,0x55F7,0x5616,0x55FE,0x55FD,0x561B,
+0x55F9,0x564E,0x5650,0x71DF,0x5634,0x5636,0x5632,0x5638,
+ 0,0x566B,0x5664,0x562F,0x566C,0x566A,0x5686,0x5680,
+0x568A,0x56A0,0x5694,0x568F,0x56A5,0x56AE,0x56B6,0x56B4,
+0x56C2,0x56BC,0x56C1,0x56C3,0x56C0,0x56C8,0x56CE,0x56D1,
+0x56D3,0x56D7,0x56EE,0x56F9,0x5700,0x56FF,0x5704,0x5709,
+0x5708,0x570B,0x570D,0x5713,0x5718,0x5716,0x55C7,0x571C,
+0x5726,0x5737,0x5738,0x574E,0x573B,0x5740,0x574F,0x5769,
+0x57C0,0x5788,0x5761,0x577F,0x5789,0x5793,0x57A0,0x57B3,
+0x57A4,0x57AA,0x57B0,0x57C3,0x57C6,0x57D4,0x57D2,0x57D3,
+0x580A,0x57D6,0x57E3,0x580B,0x5819,0x581D,0x5872,0x5821,
+0x5862,0x584B,0x5870,0x6BC0,0x5852,0x583D,0x5879,0x5885,
+0x58B9,0x589F,0x58AB,0x58BA,0x58DE,0x58BB,0x58B8,0x58AE,
+0x58C5,0x58D3,0x58D1,0x58D7,0x58D9,0x58D8,0x58E5,0x58DC,
+0x58E4,0x58DF,0x58EF,0x58FA,0x58F9,0x58FB,0x58FC,0x58FD,
+0x5902,0x590A,0x5910,0x591B,0x68A6,0x5925,0x592C,0x592D,
+0x5932,0x5938,0x593E,0x7AD2,0x5955,0x5950,0x594E,0x595A,
+0x5958,0x5962,0x5960,0x5967,0x596C,0x5969, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5978,0x5981,0x599D,0x4F5E,0x4FAB,0x59A3,0x59B2,
+0x59C6,0x59E8,0x59DC,0x598D,0x59D9,0x59DA,0x5A25,0x5A1F,
+0x5A11,0x5A1C,0x5A09,0x5A1A,0x5A40,0x5A6C,0x5A49,0x5A35,
+0x5A36,0x5A62,0x5A6A,0x5A9A,0x5ABC,0x5ABE,0x5ACB,0x5AC2,
+0x5ABD,0x5AE3,0x5AD7,0x5AE6,0x5AE9,0x5AD6,0x5AFA,0x5AFB,
+0x5B0C,0x5B0B,0x5B16,0x5B32,0x5AD0,0x5B2A,0x5B36,0x5B3E,
+0x5B43,0x5B45,0x5B40,0x5B51,0x5B55,0x5B5A,0x5B5B,0x5B65,
+0x5B69,0x5B70,0x5B73,0x5B75,0x5B78,0x6588,0x5B7A,0x5B80,
+ 0,0x5B83,0x5BA6,0x5BB8,0x5BC3,0x5BC7,0x5BC9,0x5BD4,
+0x5BD0,0x5BE4,0x5BE6,0x5BE2,0x5BDE,0x5BE5,0x5BEB,0x5BF0,
+0x5BF6,0x5BF3,0x5C05,0x5C07,0x5C08,0x5C0D,0x5C13,0x5C20,
+0x5C22,0x5C28,0x5C38,0x5C39,0x5C41,0x5C46,0x5C4E,0x5C53,
+0x5C50,0x5C4F,0x5B71,0x5C6C,0x5C6E,0x4E62,0x5C76,0x5C79,
+0x5C8C,0x5C91,0x5C94,0x599B,0x5CAB,0x5CBB,0x5CB6,0x5CBC,
+0x5CB7,0x5CC5,0x5CBE,0x5CC7,0x5CD9,0x5CE9,0x5CFD,0x5CFA,
+0x5CED,0x5D8C,0x5CEA,0x5D0B,0x5D15,0x5D17,0x5D5C,0x5D1F,
+0x5D1B,0x5D11,0x5D14,0x5D22,0x5D1A,0x5D19,0x5D18,0x5D4C,
+0x5D52,0x5D4E,0x5D4B,0x5D6C,0x5D73,0x5D76,0x5D87,0x5D84,
+0x5D82,0x5DA2,0x5D9D,0x5DAC,0x5DAE,0x5DBD,0x5D90,0x5DB7,
+0x5DBC,0x5DC9,0x5DCD,0x5DD3,0x5DD2,0x5DD6,0x5DDB,0x5DEB,
+0x5DF2,0x5DF5,0x5E0B,0x5E1A,0x5E19,0x5E11,0x5E1B,0x5E36,
+0x5E37,0x5E44,0x5E43,0x5E40,0x5E4E,0x5E57,0x5E54,0x5E5F,
+0x5E62,0x5E64,0x5E47,0x5E75,0x5E76,0x5E7A,0x9EBC,0x5E7F,
+0x5EA0,0x5EC1,0x5EC2,0x5EC8,0x5ED0,0x5ECF, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5ED6,0x5EE3,0x5EDD,0x5EDA,0x5EDB,0x5EE2,0x5EE1,
+0x5EE8,0x5EE9,0x5EEC,0x5EF1,0x5EF3,0x5EF0,0x5EF4,0x5EF8,
+0x5EFE,0x5F03,0x5F09,0x5F5D,0x5F5C,0x5F0B,0x5F11,0x5F16,
+0x5F29,0x5F2D,0x5F38,0x5F41,0x5F48,0x5F4C,0x5F4E,0x5F2F,
+0x5F51,0x5F56,0x5F57,0x5F59,0x5F61,0x5F6D,0x5F73,0x5F77,
+0x5F83,0x5F82,0x5F7F,0x5F8A,0x5F88,0x5F91,0x5F87,0x5F9E,
+0x5F99,0x5F98,0x5FA0,0x5FA8,0x5FAD,0x5FBC,0x5FD6,0x5FFB,
+0x5FE4,0x5FF8,0x5FF1,0x5FDD,0x60B3,0x5FFF,0x6021,0x6060,
+ 0,0x6019,0x6010,0x6029,0x600E,0x6031,0x601B,0x6015,
+0x602B,0x6026,0x600F,0x603A,0x605A,0x6041,0x606A,0x6077,
+0x605F,0x604A,0x6046,0x604D,0x6063,0x6043,0x6064,0x6042,
+0x606C,0x606B,0x6059,0x6081,0x608D,0x60E7,0x6083,0x609A,
+0x6084,0x609B,0x6096,0x6097,0x6092,0x60A7,0x608B,0x60E1,
+0x60B8,0x60E0,0x60D3,0x60B4,0x5FF0,0x60BD,0x60C6,0x60B5,
+0x60D8,0x614D,0x6115,0x6106,0x60F6,0x60F7,0x6100,0x60F4,
+0x60FA,0x6103,0x6121,0x60FB,0x60F1,0x610D,0x610E,0x6147,
+0x613E,0x6128,0x6127,0x614A,0x613F,0x613C,0x612C,0x6134,
+0x613D,0x6142,0x6144,0x6173,0x6177,0x6158,0x6159,0x615A,
+0x616B,0x6174,0x616F,0x6165,0x6171,0x615F,0x615D,0x6153,
+0x6175,0x6199,0x6196,0x6187,0x61AC,0x6194,0x619A,0x618A,
+0x6191,0x61AB,0x61AE,0x61CC,0x61CA,0x61C9,0x61F7,0x61C8,
+0x61C3,0x61C6,0x61BA,0x61CB,0x7F79,0x61CD,0x61E6,0x61E3,
+0x61F6,0x61FA,0x61F4,0x61FF,0x61FD,0x61FC,0x61FE,0x6200,
+0x6208,0x6209,0x620D,0x620C,0x6214,0x621B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x621E,0x6221,0x622A,0x622E,0x6230,0x6232,0x6233,
+0x6241,0x624E,0x625E,0x6263,0x625B,0x6260,0x6268,0x627C,
+0x6282,0x6289,0x627E,0x6292,0x6293,0x6296,0x62D4,0x6283,
+0x6294,0x62D7,0x62D1,0x62BB,0x62CF,0x62FF,0x62C6,0x64D4,
+0x62C8,0x62DC,0x62CC,0x62CA,0x62C2,0x62C7,0x629B,0x62C9,
+0x630C,0x62EE,0x62F1,0x6327,0x6302,0x6308,0x62EF,0x62F5,
+0x6350,0x633E,0x634D,0x641C,0x634F,0x6396,0x638E,0x6380,
+0x63AB,0x6376,0x63A3,0x638F,0x6389,0x639F,0x63B5,0x636B,
+ 0,0x6369,0x63BE,0x63E9,0x63C0,0x63C6,0x63E3,0x63C9,
+0x63D2,0x63F6,0x63C4,0x6416,0x6434,0x6406,0x6413,0x6426,
+0x6436,0x651D,0x6417,0x6428,0x640F,0x6467,0x646F,0x6476,
+0x644E,0x652A,0x6495,0x6493,0x64A5,0x64A9,0x6488,0x64BC,
+0x64DA,0x64D2,0x64C5,0x64C7,0x64BB,0x64D8,0x64C2,0x64F1,
+0x64E7,0x8209,0x64E0,0x64E1,0x62AC,0x64E3,0x64EF,0x652C,
+0x64F6,0x64F4,0x64F2,0x64FA,0x6500,0x64FD,0x6518,0x651C,
+0x6505,0x6524,0x6523,0x652B,0x6534,0x6535,0x6537,0x6536,
+0x6538,0x754B,0x6548,0x6556,0x6555,0x654D,0x6558,0x655E,
+0x655D,0x6572,0x6578,0x6582,0x6583,0x8B8A,0x659B,0x659F,
+0x65AB,0x65B7,0x65C3,0x65C6,0x65C1,0x65C4,0x65CC,0x65D2,
+0x65DB,0x65D9,0x65E0,0x65E1,0x65F1,0x6772,0x660A,0x6603,
+0x65FB,0x6773,0x6635,0x6636,0x6634,0x661C,0x664F,0x6644,
+0x6649,0x6641,0x665E,0x665D,0x6664,0x6667,0x6668,0x665F,
+0x6662,0x6670,0x6683,0x6688,0x668E,0x6689,0x6684,0x6698,
+0x669D,0x66C1,0x66B9,0x66C9,0x66BE,0x66BC, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x66C4,0x66B8,0x66D6,0x66DA,0x66E0,0x663F,0x66E6,
+0x66E9,0x66F0,0x66F5,0x66F7,0x670F,0x6716,0x671E,0x6726,
+0x6727,0x9738,0x672E,0x673F,0x6736,0x6741,0x6738,0x6737,
+0x6746,0x675E,0x6760,0x6759,0x6763,0x6764,0x6789,0x6770,
+0x67A9,0x677C,0x676A,0x678C,0x678B,0x67A6,0x67A1,0x6785,
+0x67B7,0x67EF,0x67B4,0x67EC,0x67B3,0x67E9,0x67B8,0x67E4,
+0x67DE,0x67DD,0x67E2,0x67EE,0x67B9,0x67CE,0x67C6,0x67E7,
+0x6A9C,0x681E,0x6846,0x6829,0x6840,0x684D,0x6832,0x684E,
+ 0,0x68B3,0x682B,0x6859,0x6863,0x6877,0x687F,0x689F,
+0x688F,0x68AD,0x6894,0x689D,0x689B,0x6883,0x6AAE,0x68B9,
+0x6874,0x68B5,0x68A0,0x68BA,0x690F,0x688D,0x687E,0x6901,
+0x68CA,0x6908,0x68D8,0x6922,0x6926,0x68E1,0x690C,0x68CD,
+0x68D4,0x68E7,0x68D5,0x6936,0x6912,0x6904,0x68D7,0x68E3,
+0x6925,0x68F9,0x68E0,0x68EF,0x6928,0x692A,0x691A,0x6923,
+0x6921,0x68C6,0x6979,0x6977,0x695C,0x6978,0x696B,0x6954,
+0x697E,0x696E,0x6939,0x6974,0x693D,0x6959,0x6930,0x6961,
+0x695E,0x695D,0x6981,0x696A,0x69B2,0x69AE,0x69D0,0x69BF,
+0x69C1,0x69D3,0x69BE,0x69CE,0x5BE8,0x69CA,0x69DD,0x69BB,
+0x69C3,0x69A7,0x6A2E,0x6991,0x69A0,0x699C,0x6995,0x69B4,
+0x69DE,0x69E8,0x6A02,0x6A1B,0x69FF,0x6B0A,0x69F9,0x69F2,
+0x69E7,0x6A05,0x69B1,0x6A1E,0x69ED,0x6A14,0x69EB,0x6A0A,
+0x6A12,0x6AC1,0x6A23,0x6A13,0x6A44,0x6A0C,0x6A72,0x6A36,
+0x6A78,0x6A47,0x6A62,0x6A59,0x6A66,0x6A48,0x6A38,0x6A22,
+0x6A90,0x6A8D,0x6AA0,0x6A84,0x6AA2,0x6AA3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6A97,0x8617,0x6ABB,0x6AC3,0x6AC2,0x6AB8,0x6AB3,
+0x6AAC,0x6ADE,0x6AD1,0x6ADF,0x6AAA,0x6ADA,0x6AEA,0x6AFB,
+0x6B05,0x8616,0x6AFA,0x6B12,0x6B16,0x9B31,0x6B1F,0x6B38,
+0x6B37,0x76DC,0x6B39,0x98EE,0x6B47,0x6B43,0x6B49,0x6B50,
+0x6B59,0x6B54,0x6B5B,0x6B5F,0x6B61,0x6B78,0x6B79,0x6B7F,
+0x6B80,0x6B84,0x6B83,0x6B8D,0x6B98,0x6B95,0x6B9E,0x6BA4,
+0x6BAA,0x6BAB,0x6BAF,0x6BB2,0x6BB1,0x6BB3,0x6BB7,0x6BBC,
+0x6BC6,0x6BCB,0x6BD3,0x6BDF,0x6BEC,0x6BEB,0x6BF3,0x6BEF,
+ 0,0x9EBE,0x6C08,0x6C13,0x6C14,0x6C1B,0x6C24,0x6C23,
+0x6C5E,0x6C55,0x6C62,0x6C6A,0x6C82,0x6C8D,0x6C9A,0x6C81,
+0x6C9B,0x6C7E,0x6C68,0x6C73,0x6C92,0x6C90,0x6CC4,0x6CF1,
+0x6CD3,0x6CBD,0x6CD7,0x6CC5,0x6CDD,0x6CAE,0x6CB1,0x6CBE,
+0x6CBA,0x6CDB,0x6CEF,0x6CD9,0x6CEA,0x6D1F,0x884D,0x6D36,
+0x6D2B,0x6D3D,0x6D38,0x6D19,0x6D35,0x6D33,0x6D12,0x6D0C,
+0x6D63,0x6D93,0x6D64,0x6D5A,0x6D79,0x6D59,0x6D8E,0x6D95,
+0x6FE4,0x6D85,0x6DF9,0x6E15,0x6E0A,0x6DB5,0x6DC7,0x6DE6,
+0x6DB8,0x6DC6,0x6DEC,0x6DDE,0x6DCC,0x6DE8,0x6DD2,0x6DC5,
+0x6DFA,0x6DD9,0x6DE4,0x6DD5,0x6DEA,0x6DEE,0x6E2D,0x6E6E,
+0x6E2E,0x6E19,0x6E72,0x6E5F,0x6E3E,0x6E23,0x6E6B,0x6E2B,
+0x6E76,0x6E4D,0x6E1F,0x6E43,0x6E3A,0x6E4E,0x6E24,0x6EFF,
+0x6E1D,0x6E38,0x6E82,0x6EAA,0x6E98,0x6EC9,0x6EB7,0x6ED3,
+0x6EBD,0x6EAF,0x6EC4,0x6EB2,0x6ED4,0x6ED5,0x6E8F,0x6EA5,
+0x6EC2,0x6E9F,0x6F41,0x6F11,0x704C,0x6EEC,0x6EF8,0x6EFE,
+0x6F3F,0x6EF2,0x6F31,0x6EEF,0x6F32,0x6ECC};
+
+/* page 4 0xE040-0xEAA4 */
+static uint16 tab_cp932_uni4[]={
+0x6F3E,0x6F13,0x6EF7,0x6F86,0x6F7A,0x6F78,0x6F81,0x6F80,
+0x6F6F,0x6F5B,0x6FF3,0x6F6D,0x6F82,0x6F7C,0x6F58,0x6F8E,
+0x6F91,0x6FC2,0x6F66,0x6FB3,0x6FA3,0x6FA1,0x6FA4,0x6FB9,
+0x6FC6,0x6FAA,0x6FDF,0x6FD5,0x6FEC,0x6FD4,0x6FD8,0x6FF1,
+0x6FEE,0x6FDB,0x7009,0x700B,0x6FFA,0x7011,0x7001,0x700F,
+0x6FFE,0x701B,0x701A,0x6F74,0x701D,0x7018,0x701F,0x7030,
+0x703E,0x7032,0x7051,0x7063,0x7099,0x7092,0x70AF,0x70F1,
+0x70AC,0x70B8,0x70B3,0x70AE,0x70DF,0x70CB,0x70DD, 0,
+0x70D9,0x7109,0x70FD,0x711C,0x7119,0x7165,0x7155,0x7188,
+0x7166,0x7162,0x714C,0x7156,0x716C,0x718F,0x71FB,0x7184,
+0x7195,0x71A8,0x71AC,0x71D7,0x71B9,0x71BE,0x71D2,0x71C9,
+0x71D4,0x71CE,0x71E0,0x71EC,0x71E7,0x71F5,0x71FC,0x71F9,
+0x71FF,0x720D,0x7210,0x721B,0x7228,0x722D,0x722C,0x7230,
+0x7232,0x723B,0x723C,0x723F,0x7240,0x7246,0x724B,0x7258,
+0x7274,0x727E,0x7282,0x7281,0x7287,0x7292,0x7296,0x72A2,
+0x72A7,0x72B9,0x72B2,0x72C3,0x72C6,0x72C4,0x72CE,0x72D2,
+0x72E2,0x72E0,0x72E1,0x72F9,0x72F7,0x500F,0x7317,0x730A,
+0x731C,0x7316,0x731D,0x7334,0x732F,0x7329,0x7325,0x733E,
+0x734E,0x734F,0x9ED8,0x7357,0x736A,0x7368,0x7370,0x7378,
+0x7375,0x737B,0x737A,0x73C8,0x73B3,0x73CE,0x73BB,0x73C0,
+0x73E5,0x73EE,0x73DE,0x74A2,0x7405,0x746F,0x7425,0x73F8,
+0x7432,0x743A,0x7455,0x743F,0x745F,0x7459,0x7441,0x745C,
+0x7469,0x7470,0x7463,0x746A,0x7476,0x747E,0x748B,0x749E,
+0x74A7,0x74CA,0x74CF,0x74D4,0x73F1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x74E0,0x74E3,0x74E7,0x74E9,0x74EE,0x74F2,0x74F0,0x74F1,
+0x74F8,0x74F7,0x7504,0x7503,0x7505,0x750C,0x750E,0x750D,
+0x7515,0x7513,0x751E,0x7526,0x752C,0x753C,0x7544,0x754D,
+0x754A,0x7549,0x755B,0x7546,0x755A,0x7569,0x7564,0x7567,
+0x756B,0x756D,0x7578,0x7576,0x7586,0x7587,0x7574,0x758A,
+0x7589,0x7582,0x7594,0x759A,0x759D,0x75A5,0x75A3,0x75C2,
+0x75B3,0x75C3,0x75B5,0x75BD,0x75B8,0x75BC,0x75B1,0x75CD,
+0x75CA,0x75D2,0x75D9,0x75E3,0x75DE,0x75FE,0x75FF, 0,
+0x75FC,0x7601,0x75F0,0x75FA,0x75F2,0x75F3,0x760B,0x760D,
+0x7609,0x761F,0x7627,0x7620,0x7621,0x7622,0x7624,0x7634,
+0x7630,0x763B,0x7647,0x7648,0x7646,0x765C,0x7658,0x7661,
+0x7662,0x7668,0x7669,0x766A,0x7667,0x766C,0x7670,0x7672,
+0x7676,0x7678,0x767C,0x7680,0x7683,0x7688,0x768B,0x768E,
+0x7696,0x7693,0x7699,0x769A,0x76B0,0x76B4,0x76B8,0x76B9,
+0x76BA,0x76C2,0x76CD,0x76D6,0x76D2,0x76DE,0x76E1,0x76E5,
+0x76E7,0x76EA,0x862F,0x76FB,0x7708,0x7707,0x7704,0x7729,
+0x7724,0x771E,0x7725,0x7726,0x771B,0x7737,0x7738,0x7747,
+0x775A,0x7768,0x776B,0x775B,0x7765,0x777F,0x777E,0x7779,
+0x778E,0x778B,0x7791,0x77A0,0x779E,0x77B0,0x77B6,0x77B9,
+0x77BF,0x77BC,0x77BD,0x77BB,0x77C7,0x77CD,0x77D7,0x77DA,
+0x77DC,0x77E3,0x77EE,0x77FC,0x780C,0x7812,0x7926,0x7820,
+0x792A,0x7845,0x788E,0x7874,0x7886,0x787C,0x789A,0x788C,
+0x78A3,0x78B5,0x78AA,0x78AF,0x78D1,0x78C6,0x78CB,0x78D4,
+0x78BE,0x78BC,0x78C5,0x78CA,0x78EC, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x78E7,0x78DA,0x78FD,0x78F4,0x7907,0x7912,0x7911,0x7919,
+0x792C,0x792B,0x7940,0x7960,0x7957,0x795F,0x795A,0x7955,
+0x7953,0x797A,0x797F,0x798A,0x799D,0x79A7,0x9F4B,0x79AA,
+0x79AE,0x79B3,0x79B9,0x79BA,0x79C9,0x79D5,0x79E7,0x79EC,
+0x79E1,0x79E3,0x7A08,0x7A0D,0x7A18,0x7A19,0x7A20,0x7A1F,
+0x7980,0x7A31,0x7A3B,0x7A3E,0x7A37,0x7A43,0x7A57,0x7A49,
+0x7A61,0x7A62,0x7A69,0x9F9D,0x7A70,0x7A79,0x7A7D,0x7A88,
+0x7A97,0x7A95,0x7A98,0x7A96,0x7AA9,0x7AC8,0x7AB0, 0,
+0x7AB6,0x7AC5,0x7AC4,0x7ABF,0x9083,0x7AC7,0x7ACA,0x7ACD,
+0x7ACF,0x7AD5,0x7AD3,0x7AD9,0x7ADA,0x7ADD,0x7AE1,0x7AE2,
+0x7AE6,0x7AED,0x7AF0,0x7B02,0x7B0F,0x7B0A,0x7B06,0x7B33,
+0x7B18,0x7B19,0x7B1E,0x7B35,0x7B28,0x7B36,0x7B50,0x7B7A,
+0x7B04,0x7B4D,0x7B0B,0x7B4C,0x7B45,0x7B75,0x7B65,0x7B74,
+0x7B67,0x7B70,0x7B71,0x7B6C,0x7B6E,0x7B9D,0x7B98,0x7B9F,
+0x7B8D,0x7B9C,0x7B9A,0x7B8B,0x7B92,0x7B8F,0x7B5D,0x7B99,
+0x7BCB,0x7BC1,0x7BCC,0x7BCF,0x7BB4,0x7BC6,0x7BDD,0x7BE9,
+0x7C11,0x7C14,0x7BE6,0x7BE5,0x7C60,0x7C00,0x7C07,0x7C13,
+0x7BF3,0x7BF7,0x7C17,0x7C0D,0x7BF6,0x7C23,0x7C27,0x7C2A,
+0x7C1F,0x7C37,0x7C2B,0x7C3D,0x7C4C,0x7C43,0x7C54,0x7C4F,
+0x7C40,0x7C50,0x7C58,0x7C5F,0x7C64,0x7C56,0x7C65,0x7C6C,
+0x7C75,0x7C83,0x7C90,0x7CA4,0x7CAD,0x7CA2,0x7CAB,0x7CA1,
+0x7CA8,0x7CB3,0x7CB2,0x7CB1,0x7CAE,0x7CB9,0x7CBD,0x7CC0,
+0x7CC5,0x7CC2,0x7CD8,0x7CD2,0x7CDC,0x7CE2,0x9B3B,0x7CEF,
+0x7CF2,0x7CF4,0x7CF6,0x7CFA,0x7D06, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x7D02,0x7D1C,0x7D15,0x7D0A,0x7D45,0x7D4B,0x7D2E,0x7D32,
+0x7D3F,0x7D35,0x7D46,0x7D73,0x7D56,0x7D4E,0x7D72,0x7D68,
+0x7D6E,0x7D4F,0x7D63,0x7D93,0x7D89,0x7D5B,0x7D8F,0x7D7D,
+0x7D9B,0x7DBA,0x7DAE,0x7DA3,0x7DB5,0x7DC7,0x7DBD,0x7DAB,
+0x7E3D,0x7DA2,0x7DAF,0x7DDC,0x7DB8,0x7D9F,0x7DB0,0x7DD8,
+0x7DDD,0x7DE4,0x7DDE,0x7DFB,0x7DF2,0x7DE1,0x7E05,0x7E0A,
+0x7E23,0x7E21,0x7E12,0x7E31,0x7E1F,0x7E09,0x7E0B,0x7E22,
+0x7E46,0x7E66,0x7E3B,0x7E35,0x7E39,0x7E43,0x7E37, 0,
+0x7E32,0x7E3A,0x7E67,0x7E5D,0x7E56,0x7E5E,0x7E59,0x7E5A,
+0x7E79,0x7E6A,0x7E69,0x7E7C,0x7E7B,0x7E83,0x7DD5,0x7E7D,
+0x8FAE,0x7E7F,0x7E88,0x7E89,0x7E8C,0x7E92,0x7E90,0x7E93,
+0x7E94,0x7E96,0x7E8E,0x7E9B,0x7E9C,0x7F38,0x7F3A,0x7F45,
+0x7F4C,0x7F4D,0x7F4E,0x7F50,0x7F51,0x7F55,0x7F54,0x7F58,
+0x7F5F,0x7F60,0x7F68,0x7F69,0x7F67,0x7F78,0x7F82,0x7F86,
+0x7F83,0x7F88,0x7F87,0x7F8C,0x7F94,0x7F9E,0x7F9D,0x7F9A,
+0x7FA3,0x7FAF,0x7FB2,0x7FB9,0x7FAE,0x7FB6,0x7FB8,0x8B71,
+0x7FC5,0x7FC6,0x7FCA,0x7FD5,0x7FD4,0x7FE1,0x7FE6,0x7FE9,
+0x7FF3,0x7FF9,0x98DC,0x8006,0x8004,0x800B,0x8012,0x8018,
+0x8019,0x801C,0x8021,0x8028,0x803F,0x803B,0x804A,0x8046,
+0x8052,0x8058,0x805A,0x805F,0x8062,0x8068,0x8073,0x8072,
+0x8070,0x8076,0x8079,0x807D,0x807F,0x8084,0x8086,0x8085,
+0x809B,0x8093,0x809A,0x80AD,0x5190,0x80AC,0x80DB,0x80E5,
+0x80D9,0x80DD,0x80C4,0x80DA,0x80D6,0x8109,0x80EF,0x80F1,
+0x811B,0x8129,0x8123,0x812F,0x814B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x968B,0x8146,0x813E,0x8153,0x8151,0x80FC,0x8171,0x816E,
+0x8165,0x8166,0x8174,0x8183,0x8188,0x818A,0x8180,0x8182,
+0x81A0,0x8195,0x81A4,0x81A3,0x815F,0x8193,0x81A9,0x81B0,
+0x81B5,0x81BE,0x81B8,0x81BD,0x81C0,0x81C2,0x81BA,0x81C9,
+0x81CD,0x81D1,0x81D9,0x81D8,0x81C8,0x81DA,0x81DF,0x81E0,
+0x81E7,0x81FA,0x81FB,0x81FE,0x8201,0x8202,0x8205,0x8207,
+0x820A,0x820D,0x8210,0x8216,0x8229,0x822B,0x8238,0x8233,
+0x8240,0x8259,0x8258,0x825D,0x825A,0x825F,0x8264, 0,
+0x8262,0x8268,0x826A,0x826B,0x822E,0x8271,0x8277,0x8278,
+0x827E,0x828D,0x8292,0x82AB,0x829F,0x82BB,0x82AC,0x82E1,
+0x82E3,0x82DF,0x82D2,0x82F4,0x82F3,0x82FA,0x8393,0x8303,
+0x82FB,0x82F9,0x82DE,0x8306,0x82DC,0x8309,0x82D9,0x8335,
+0x8334,0x8316,0x8332,0x8331,0x8340,0x8339,0x8350,0x8345,
+0x832F,0x832B,0x8317,0x8318,0x8385,0x839A,0x83AA,0x839F,
+0x83A2,0x8396,0x8323,0x838E,0x8387,0x838A,0x837C,0x83B5,
+0x8373,0x8375,0x83A0,0x8389,0x83A8,0x83F4,0x8413,0x83EB,
+0x83CE,0x83FD,0x8403,0x83D8,0x840B,0x83C1,0x83F7,0x8407,
+0x83E0,0x83F2,0x840D,0x8422,0x8420,0x83BD,0x8438,0x8506,
+0x83FB,0x846D,0x842A,0x843C,0x855A,0x8484,0x8477,0x846B,
+0x84AD,0x846E,0x8482,0x8469,0x8446,0x842C,0x846F,0x8479,
+0x8435,0x84CA,0x8462,0x84B9,0x84BF,0x849F,0x84D9,0x84CD,
+0x84BB,0x84DA,0x84D0,0x84C1,0x84C6,0x84D6,0x84A1,0x8521,
+0x84FF,0x84F4,0x8517,0x8518,0x852C,0x851F,0x8515,0x8514,
+0x84FC,0x8540,0x8563,0x8558,0x8548, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8541,0x8602,0x854B,0x8555,0x8580,0x85A4,0x8588,0x8591,
+0x858A,0x85A8,0x856D,0x8594,0x859B,0x85EA,0x8587,0x859C,
+0x8577,0x857E,0x8590,0x85C9,0x85BA,0x85CF,0x85B9,0x85D0,
+0x85D5,0x85DD,0x85E5,0x85DC,0x85F9,0x860A,0x8613,0x860B,
+0x85FE,0x85FA,0x8606,0x8622,0x861A,0x8630,0x863F,0x864D,
+0x4E55,0x8654,0x865F,0x8667,0x8671,0x8693,0x86A3,0x86A9,
+0x86AA,0x868B,0x868C,0x86B6,0x86AF,0x86C4,0x86C6,0x86B0,
+0x86C9,0x8823,0x86AB,0x86D4,0x86DE,0x86E9,0x86EC, 0,
+0x86DF,0x86DB,0x86EF,0x8712,0x8706,0x8708,0x8700,0x8703,
+0x86FB,0x8711,0x8709,0x870D,0x86F9,0x870A,0x8734,0x873F,
+0x8737,0x873B,0x8725,0x8729,0x871A,0x8760,0x875F,0x8778,
+0x874C,0x874E,0x8774,0x8757,0x8768,0x876E,0x8759,0x8753,
+0x8763,0x876A,0x8805,0x87A2,0x879F,0x8782,0x87AF,0x87CB,
+0x87BD,0x87C0,0x87D0,0x96D6,0x87AB,0x87C4,0x87B3,0x87C7,
+0x87C6,0x87BB,0x87EF,0x87F2,0x87E0,0x880F,0x880D,0x87FE,
+0x87F6,0x87F7,0x880E,0x87D2,0x8811,0x8816,0x8815,0x8822,
+0x8821,0x8831,0x8836,0x8839,0x8827,0x883B,0x8844,0x8842,
+0x8852,0x8859,0x885E,0x8862,0x886B,0x8881,0x887E,0x889E,
+0x8875,0x887D,0x88B5,0x8872,0x8882,0x8897,0x8892,0x88AE,
+0x8899,0x88A2,0x888D,0x88A4,0x88B0,0x88BF,0x88B1,0x88C3,
+0x88C4,0x88D4,0x88D8,0x88D9,0x88DD,0x88F9,0x8902,0x88FC,
+0x88F4,0x88E8,0x88F2,0x8904,0x890C,0x890A,0x8913,0x8943,
+0x891E,0x8925,0x892A,0x892B,0x8941,0x8944,0x893B,0x8936,
+0x8938,0x894C,0x891D,0x8960,0x895E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8966,0x8964,0x896D,0x896A,0x896F,0x8974,0x8977,0x897E,
+0x8983,0x8988,0x898A,0x8993,0x8998,0x89A1,0x89A9,0x89A6,
+0x89AC,0x89AF,0x89B2,0x89BA,0x89BD,0x89BF,0x89C0,0x89DA,
+0x89DC,0x89DD,0x89E7,0x89F4,0x89F8,0x8A03,0x8A16,0x8A10,
+0x8A0C,0x8A1B,0x8A1D,0x8A25,0x8A36,0x8A41,0x8A5B,0x8A52,
+0x8A46,0x8A48,0x8A7C,0x8A6D,0x8A6C,0x8A62,0x8A85,0x8A82,
+0x8A84,0x8AA8,0x8AA1,0x8A91,0x8AA5,0x8AA6,0x8A9A,0x8AA3,
+0x8AC4,0x8ACD,0x8AC2,0x8ADA,0x8AEB,0x8AF3,0x8AE7, 0,
+0x8AE4,0x8AF1,0x8B14,0x8AE0,0x8AE2,0x8AF7,0x8ADE,0x8ADB,
+0x8B0C,0x8B07,0x8B1A,0x8AE1,0x8B16,0x8B10,0x8B17,0x8B20,
+0x8B33,0x97AB,0x8B26,0x8B2B,0x8B3E,0x8B28,0x8B41,0x8B4C,
+0x8B4F,0x8B4E,0x8B49,0x8B56,0x8B5B,0x8B5A,0x8B6B,0x8B5F,
+0x8B6C,0x8B6F,0x8B74,0x8B7D,0x8B80,0x8B8C,0x8B8E,0x8B92,
+0x8B93,0x8B96,0x8B99,0x8B9A,0x8C3A,0x8C41,0x8C3F,0x8C48,
+0x8C4C,0x8C4E,0x8C50,0x8C55,0x8C62,0x8C6C,0x8C78,0x8C7A,
+0x8C82,0x8C89,0x8C85,0x8C8A,0x8C8D,0x8C8E,0x8C94,0x8C7C,
+0x8C98,0x621D,0x8CAD,0x8CAA,0x8CBD,0x8CB2,0x8CB3,0x8CAE,
+0x8CB6,0x8CC8,0x8CC1,0x8CE4,0x8CE3,0x8CDA,0x8CFD,0x8CFA,
+0x8CFB,0x8D04,0x8D05,0x8D0A,0x8D07,0x8D0F,0x8D0D,0x8D10,
+0x9F4E,0x8D13,0x8CCD,0x8D14,0x8D16,0x8D67,0x8D6D,0x8D71,
+0x8D73,0x8D81,0x8D99,0x8DC2,0x8DBE,0x8DBA,0x8DCF,0x8DDA,
+0x8DD6,0x8DCC,0x8DDB,0x8DCB,0x8DEA,0x8DEB,0x8DDF,0x8DE3,
+0x8DFC,0x8E08,0x8E09,0x8DFF,0x8E1D,0x8E1E,0x8E10,0x8E1F,
+0x8E42,0x8E35,0x8E30,0x8E34,0x8E4A, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8E47,0x8E49,0x8E4C,0x8E50,0x8E48,0x8E59,0x8E64,0x8E60,
+0x8E2A,0x8E63,0x8E55,0x8E76,0x8E72,0x8E7C,0x8E81,0x8E87,
+0x8E85,0x8E84,0x8E8B,0x8E8A,0x8E93,0x8E91,0x8E94,0x8E99,
+0x8EAA,0x8EA1,0x8EAC,0x8EB0,0x8EC6,0x8EB1,0x8EBE,0x8EC5,
+0x8EC8,0x8ECB,0x8EDB,0x8EE3,0x8EFC,0x8EFB,0x8EEB,0x8EFE,
+0x8F0A,0x8F05,0x8F15,0x8F12,0x8F19,0x8F13,0x8F1C,0x8F1F,
+0x8F1B,0x8F0C,0x8F26,0x8F33,0x8F3B,0x8F39,0x8F45,0x8F42,
+0x8F3E,0x8F4C,0x8F49,0x8F46,0x8F4E,0x8F57,0x8F5C, 0,
+0x8F62,0x8F63,0x8F64,0x8F9C,0x8F9F,0x8FA3,0x8FAD,0x8FAF,
+0x8FB7,0x8FDA,0x8FE5,0x8FE2,0x8FEA,0x8FEF,0x9087,0x8FF4,
+0x9005,0x8FF9,0x8FFA,0x9011,0x9015,0x9021,0x900D,0x901E,
+0x9016,0x900B,0x9027,0x9036,0x9035,0x9039,0x8FF8,0x904F,
+0x9050,0x9051,0x9052,0x900E,0x9049,0x903E,0x9056,0x9058,
+0x905E,0x9068,0x906F,0x9076,0x96A8,0x9072,0x9082,0x907D,
+0x9081,0x9080,0x908A,0x9089,0x908F,0x90A8,0x90AF,0x90B1,
+0x90B5,0x90E2,0x90E4,0x6248,0x90DB,0x9102,0x9112,0x9119,
+0x9132,0x9130,0x914A,0x9156,0x9158,0x9163,0x9165,0x9169,
+0x9173,0x9172,0x918B,0x9189,0x9182,0x91A2,0x91AB,0x91AF,
+0x91AA,0x91B5,0x91B4,0x91BA,0x91C0,0x91C1,0x91C9,0x91CB,
+0x91D0,0x91D6,0x91DF,0x91E1,0x91DB,0x91FC,0x91F5,0x91F6,
+0x921E,0x91FF,0x9214,0x922C,0x9215,0x9211,0x925E,0x9257,
+0x9245,0x9249,0x9264,0x9248,0x9295,0x923F,0x924B,0x9250,
+0x929C,0x9296,0x9293,0x929B,0x925A,0x92CF,0x92B9,0x92B7,
+0x92E9,0x930F,0x92FA,0x9344,0x932E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9319,0x9322,0x931A,0x9323,0x933A,0x9335,0x933B,0x935C,
+0x9360,0x937C,0x936E,0x9356,0x93B0,0x93AC,0x93AD,0x9394,
+0x93B9,0x93D6,0x93D7,0x93E8,0x93E5,0x93D8,0x93C3,0x93DD,
+0x93D0,0x93C8,0x93E4,0x941A,0x9414,0x9413,0x9403,0x9407,
+0x9410,0x9436,0x942B,0x9435,0x9421,0x943A,0x9441,0x9452,
+0x9444,0x945B,0x9460,0x9462,0x945E,0x946A,0x9229,0x9470,
+0x9475,0x9477,0x947D,0x945A,0x947C,0x947E,0x9481,0x947F,
+0x9582,0x9587,0x958A,0x9594,0x9596,0x9598,0x9599, 0,
+0x95A0,0x95A8,0x95A7,0x95AD,0x95BC,0x95BB,0x95B9,0x95BE,
+0x95CA,0x6FF6,0x95C3,0x95CD,0x95CC,0x95D5,0x95D4,0x95D6,
+0x95DC,0x95E1,0x95E5,0x95E2,0x9621,0x9628,0x962E,0x962F,
+0x9642,0x964C,0x964F,0x964B,0x9677,0x965C,0x965E,0x965D,
+0x965F,0x9666,0x9672,0x966C,0x968D,0x9698,0x9695,0x9697,
+0x96AA,0x96A7,0x96B1,0x96B2,0x96B0,0x96B4,0x96B6,0x96B8,
+0x96B9,0x96CE,0x96CB,0x96C9,0x96CD,0x894D,0x96DC,0x970D,
+0x96D5,0x96F9,0x9704,0x9706,0x9708,0x9713,0x970E,0x9711,
+0x970F,0x9716,0x9719,0x9724,0x972A,0x9730,0x9739,0x973D,
+0x973E,0x9744,0x9746,0x9748,0x9742,0x9749,0x975C,0x9760,
+0x9764,0x9766,0x9768,0x52D2,0x976B,0x9771,0x9779,0x9785,
+0x977C,0x9781,0x977A,0x9786,0x978B,0x978F,0x9790,0x979C,
+0x97A8,0x97A6,0x97A3,0x97B3,0x97B4,0x97C3,0x97C6,0x97C8,
+0x97CB,0x97DC,0x97ED,0x9F4F,0x97F2,0x7ADF,0x97F6,0x97F5,
+0x980F,0x980C,0x9838,0x9824,0x9821,0x9837,0x983D,0x9846,
+0x984F,0x984B,0x986B,0x986F,0x9870, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9871,0x9874,0x9873,0x98AA,0x98AF,0x98B1,0x98B6,0x98C4,
+0x98C3,0x98C6,0x98E9,0x98EB,0x9903,0x9909,0x9912,0x9914,
+0x9918,0x9921,0x991D,0x991E,0x9924,0x9920,0x992C,0x992E,
+0x993D,0x993E,0x9942,0x9949,0x9945,0x9950,0x994B,0x9951,
+0x9952,0x994C,0x9955,0x9997,0x9998,0x99A5,0x99AD,0x99AE,
+0x99BC,0x99DF,0x99DB,0x99DD,0x99D8,0x99D1,0x99ED,0x99EE,
+0x99F1,0x99F2,0x99FB,0x99F8,0x9A01,0x9A0F,0x9A05,0x99E2,
+0x9A19,0x9A2B,0x9A37,0x9A45,0x9A42,0x9A40,0x9A43, 0,
+0x9A3E,0x9A55,0x9A4D,0x9A5B,0x9A57,0x9A5F,0x9A62,0x9A65,
+0x9A64,0x9A69,0x9A6B,0x9A6A,0x9AAD,0x9AB0,0x9ABC,0x9AC0,
+0x9ACF,0x9AD1,0x9AD3,0x9AD4,0x9ADE,0x9ADF,0x9AE2,0x9AE3,
+0x9AE6,0x9AEF,0x9AEB,0x9AEE,0x9AF4,0x9AF1,0x9AF7,0x9AFB,
+0x9B06,0x9B18,0x9B1A,0x9B1F,0x9B22,0x9B23,0x9B25,0x9B27,
+0x9B28,0x9B29,0x9B2A,0x9B2E,0x9B2F,0x9B32,0x9B44,0x9B43,
+0x9B4F,0x9B4D,0x9B4E,0x9B51,0x9B58,0x9B74,0x9B93,0x9B83,
+0x9B91,0x9B96,0x9B97,0x9B9F,0x9BA0,0x9BA8,0x9BB4,0x9BC0,
+0x9BCA,0x9BB9,0x9BC6,0x9BCF,0x9BD1,0x9BD2,0x9BE3,0x9BE2,
+0x9BE4,0x9BD4,0x9BE1,0x9C3A,0x9BF2,0x9BF1,0x9BF0,0x9C15,
+0x9C14,0x9C09,0x9C13,0x9C0C,0x9C06,0x9C08,0x9C12,0x9C0A,
+0x9C04,0x9C2E,0x9C1B,0x9C25,0x9C24,0x9C21,0x9C30,0x9C47,
+0x9C32,0x9C46,0x9C3E,0x9C5A,0x9C60,0x9C67,0x9C76,0x9C78,
+0x9CE7,0x9CEC,0x9CF0,0x9D09,0x9D08,0x9CEB,0x9D03,0x9D06,
+0x9D2A,0x9D26,0x9DAF,0x9D23,0x9D1F,0x9D44,0x9D15,0x9D12,
+0x9D41,0x9D3F,0x9D3E,0x9D46,0x9D48, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9D5D,0x9D5E,0x9D64,0x9D51,0x9D50,0x9D59,0x9D72,0x9D89,
+0x9D87,0x9DAB,0x9D6F,0x9D7A,0x9D9A,0x9DA4,0x9DA9,0x9DB2,
+0x9DC4,0x9DC1,0x9DBB,0x9DB8,0x9DBA,0x9DC6,0x9DCF,0x9DC2,
+0x9DD9,0x9DD3,0x9DF8,0x9DE6,0x9DED,0x9DEF,0x9DFD,0x9E1A,
+0x9E1B,0x9E1E,0x9E75,0x9E79,0x9E7D,0x9E81,0x9E88,0x9E8B,
+0x9E8C,0x9E92,0x9E95,0x9E91,0x9E9D,0x9EA5,0x9EA9,0x9EB8,
+0x9EAA,0x9EAD,0x9761,0x9ECC,0x9ECE,0x9ECF,0x9ED0,0x9ED4,
+0x9EDC,0x9EDE,0x9EDD,0x9EE0,0x9EE5,0x9EE8,0x9EEF, 0,
+0x9EF4,0x9EF6,0x9EF7,0x9EF9,0x9EFB,0x9EFC,0x9EFD,0x9F07,
+0x9F08,0x76B7,0x9F15,0x9F21,0x9F2C,0x9F3E,0x9F4A,0x9F52,
+0x9F54,0x9F63,0x9F5F,0x9F60,0x9F61,0x9F66,0x9F67,0x9F6C,
+0x9F6A,0x9F77,0x9F72,0x9F76,0x9F95,0x9F9C,0x9FA0,0x582F,
+0x69C7,0x9059,0x7464,0x51DC,0x7199};
+
+/* page 5 0xED40-0xEEFC -
+IBM Selected Kanji and Non-Kanji(NEC implementation) */
+static uint16 tab_cp932_uni5[]={
+0x7E8A,0x891C,0x9348,0x9288,0x84DC,0x4FC9,0x70BB,0x6631,
+0x68C8,0x92F9,0x66FB,0x5F45,0x4E28,0x4EE1,0x4EFC,0x4F00,
+0x4F03,0x4F39,0x4F56,0x4F92,0x4F8A,0x4F9A,0x4F94,0x4FCD,
+0x5040,0x5022,0x4FFF,0x501E,0x5046,0x5070,0x5042,0x5094,
+0x50F4,0x50D8,0x514A,0x5164,0x519D,0x51BE,0x51EC,0x5215,
+0x529C,0x52A6,0x52C0,0x52DB,0x5300,0x5307,0x5324,0x5372,
+0x5393,0x53B2,0x53DD,0xFA0E,0x549C,0x548A,0x54A9,0x54FF,
+0x5586,0x5759,0x5765,0x57AC,0x57C8,0x57C7,0xFA0F, 0,
+0xFA10,0x589E,0x58B2,0x590B,0x5953,0x595B,0x595D,0x5963,
+0x59A4,0x59BA,0x5B56,0x5BC0,0x752F,0x5BD8,0x5BEC,0x5C1E,
+0x5CA6,0x5CBA,0x5CF5,0x5D27,0x5D53,0xFA11,0x5D42,0x5D6D,
+0x5DB8,0x5DB9,0x5DD0,0x5F21,0x5F34,0x5F67,0x5FB7,0x5FDE,
+0x605D,0x6085,0x608A,0x60DE,0x60D5,0x6120,0x60F2,0x6111,
+0x6137,0x6130,0x6198,0x6213,0x62A6,0x63F5,0x6460,0x649D,
+0x64CE,0x654E,0x6600,0x6615,0x663B,0x6609,0x662E,0x661E,
+0x6624,0x6665,0x6657,0x6659,0xFA12,0x6673,0x6699,0x66A0,
+0x66B2,0x66BF,0x66FA,0x670E,0xF929,0x6766,0x67BB,0x6852,
+0x67C0,0x6801,0x6844,0x68CF,0xFA13,0x6968,0xFA14,0x6998,
+0x69E2,0x6A30,0x6A6B,0x6A46,0x6A73,0x6A7E,0x6AE2,0x6AE4,
+0x6BD6,0x6C3F,0x6C5C,0x6C86,0x6C6F,0x6CDA,0x6D04,0x6D87,
+0x6D6F,0x6D96,0x6DAC,0x6DCF,0x6DF8,0x6DF2,0x6DFC,0x6E39,
+0x6E5C,0x6E27,0x6E3C,0x6EBF,0x6F88,0x6FB5,0x6FF5,0x7005,
+0x7007,0x7028,0x7085,0x70AB,0x710F,0x7104,0x715C,0x7146,
+0x7147,0xFA15,0x71C1,0x71FE,0x72B1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x72BE,0x7324,0xFA16,0x7377,0x73BD,0x73C9,0x73D6,0x73E3,
+0x73D2,0x7407,0x73F5,0x7426,0x742A,0x7429,0x742E,0x7462,
+0x7489,0x749F,0x7501,0x756F,0x7682,0x769C,0x769E,0x769B,
+0x76A6,0xFA17,0x7746,0x52AF,0x7821,0x784E,0x7864,0x787A,
+0x7930,0xFA18,0xFA19,0xFA1A,0x7994,0xFA1B,0x799B,0x7AD1,
+0x7AE7,0xFA1C,0x7AEB,0x7B9E,0xFA1D,0x7D48,0x7D5C,0x7DB7,
+0x7DA0,0x7DD6,0x7E52,0x7F47,0x7FA1,0xFA1E,0x8301,0x8362,
+0x837F,0x83C7,0x83F6,0x8448,0x84B4,0x8553,0x8559, 0,
+0x856B,0xFA1F,0x85B0,0xFA20,0xFA21,0x8807,0x88F5,0x8A12,
+0x8A37,0x8A79,0x8AA7,0x8ABE,0x8ADF,0xFA22,0x8AF6,0x8B53,
+0x8B7F,0x8CF0,0x8CF4,0x8D12,0x8D76,0xFA23,0x8ECF,0xFA24,
+0xFA25,0x9067,0x90DE,0xFA26,0x9115,0x9127,0x91DA,0x91D7,
+0x91DE,0x91ED,0x91EE,0x91E4,0x91E5,0x9206,0x9210,0x920A,
+0x923A,0x9240,0x923C,0x924E,0x9259,0x9251,0x9239,0x9267,
+0x92A7,0x9277,0x9278,0x92E7,0x92D7,0x92D9,0x92D0,0xFA27,
+0x92D5,0x92E0,0x92D3,0x9325,0x9321,0x92FB,0xFA28,0x931E,
+0x92FF,0x931D,0x9302,0x9370,0x9357,0x93A4,0x93C6,0x93DE,
+0x93F8,0x9431,0x9445,0x9448,0x9592,0xF9DC,0xFA29,0x969D,
+0x96AF,0x9733,0x973B,0x9743,0x974D,0x974F,0x9751,0x9755,
+0x9857,0x9865,0xFA2A,0xFA2B,0x9927,0xFA2C,0x999E,0x9A4E,
+0x9AD9,0x9ADC,0x9B75,0x9B72,0x9B8F,0x9BB1,0x9BBB,0x9C00,
+0x9D70,0x9D6B,0xFA2D,0x9E19,0x9ED1, 0, 0,0x2170,
+0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,
+0x2179,0xFFE2,0xFFE4,0xFF07,0xFF02};
+
+/* page 6 0xF040-0xF9FC - User defined characters */
+static uint16 tab_cp932_uni6[]={
+0xE000,0xE001,0xE002,0xE003,0xE004,0xE005,0xE006,0xE007,
+0xE008,0xE009,0xE00A,0xE00B,0xE00C,0xE00D,0xE00E,0xE00F,
+0xE010,0xE011,0xE012,0xE013,0xE014,0xE015,0xE016,0xE017,
+0xE018,0xE019,0xE01A,0xE01B,0xE01C,0xE01D,0xE01E,0xE01F,
+0xE020,0xE021,0xE022,0xE023,0xE024,0xE025,0xE026,0xE027,
+0xE028,0xE029,0xE02A,0xE02B,0xE02C,0xE02D,0xE02E,0xE02F,
+0xE030,0xE031,0xE032,0xE033,0xE034,0xE035,0xE036,0xE037,
+0xE038,0xE039,0xE03A,0xE03B,0xE03C,0xE03D,0xE03E, 0,
+0xE03F,0xE040,0xE041,0xE042,0xE043,0xE044,0xE045,0xE046,
+0xE047,0xE048,0xE049,0xE04A,0xE04B,0xE04C,0xE04D,0xE04E,
+0xE04F,0xE050,0xE051,0xE052,0xE053,0xE054,0xE055,0xE056,
+0xE057,0xE058,0xE059,0xE05A,0xE05B,0xE05C,0xE05D,0xE05E,
+0xE05F,0xE060,0xE061,0xE062,0xE063,0xE064,0xE065,0xE066,
+0xE067,0xE068,0xE069,0xE06A,0xE06B,0xE06C,0xE06D,0xE06E,
+0xE06F,0xE070,0xE071,0xE072,0xE073,0xE074,0xE075,0xE076,
+0xE077,0xE078,0xE079,0xE07A,0xE07B,0xE07C,0xE07D,0xE07E,
+0xE07F,0xE080,0xE081,0xE082,0xE083,0xE084,0xE085,0xE086,
+0xE087,0xE088,0xE089,0xE08A,0xE08B,0xE08C,0xE08D,0xE08E,
+0xE08F,0xE090,0xE091,0xE092,0xE093,0xE094,0xE095,0xE096,
+0xE097,0xE098,0xE099,0xE09A,0xE09B,0xE09C,0xE09D,0xE09E,
+0xE09F,0xE0A0,0xE0A1,0xE0A2,0xE0A3,0xE0A4,0xE0A5,0xE0A6,
+0xE0A7,0xE0A8,0xE0A9,0xE0AA,0xE0AB,0xE0AC,0xE0AD,0xE0AE,
+0xE0AF,0xE0B0,0xE0B1,0xE0B2,0xE0B3,0xE0B4,0xE0B5,0xE0B6,
+0xE0B7,0xE0B8,0xE0B9,0xE0BA,0xE0BB, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE0BC,0xE0BD,0xE0BE,0xE0BF,0xE0C0,0xE0C1,0xE0C2,0xE0C3,
+0xE0C4,0xE0C5,0xE0C6,0xE0C7,0xE0C8,0xE0C9,0xE0CA,0xE0CB,
+0xE0CC,0xE0CD,0xE0CE,0xE0CF,0xE0D0,0xE0D1,0xE0D2,0xE0D3,
+0xE0D4,0xE0D5,0xE0D6,0xE0D7,0xE0D8,0xE0D9,0xE0DA,0xE0DB,
+0xE0DC,0xE0DD,0xE0DE,0xE0DF,0xE0E0,0xE0E1,0xE0E2,0xE0E3,
+0xE0E4,0xE0E5,0xE0E6,0xE0E7,0xE0E8,0xE0E9,0xE0EA,0xE0EB,
+0xE0EC,0xE0ED,0xE0EE,0xE0EF,0xE0F0,0xE0F1,0xE0F2,0xE0F3,
+0xE0F4,0xE0F5,0xE0F6,0xE0F7,0xE0F8,0xE0F9,0xE0FA, 0,
+0xE0FB,0xE0FC,0xE0FD,0xE0FE,0xE0FF,0xE100,0xE101,0xE102,
+0xE103,0xE104,0xE105,0xE106,0xE107,0xE108,0xE109,0xE10A,
+0xE10B,0xE10C,0xE10D,0xE10E,0xE10F,0xE110,0xE111,0xE112,
+0xE113,0xE114,0xE115,0xE116,0xE117,0xE118,0xE119,0xE11A,
+0xE11B,0xE11C,0xE11D,0xE11E,0xE11F,0xE120,0xE121,0xE122,
+0xE123,0xE124,0xE125,0xE126,0xE127,0xE128,0xE129,0xE12A,
+0xE12B,0xE12C,0xE12D,0xE12E,0xE12F,0xE130,0xE131,0xE132,
+0xE133,0xE134,0xE135,0xE136,0xE137,0xE138,0xE139,0xE13A,
+0xE13B,0xE13C,0xE13D,0xE13E,0xE13F,0xE140,0xE141,0xE142,
+0xE143,0xE144,0xE145,0xE146,0xE147,0xE148,0xE149,0xE14A,
+0xE14B,0xE14C,0xE14D,0xE14E,0xE14F,0xE150,0xE151,0xE152,
+0xE153,0xE154,0xE155,0xE156,0xE157,0xE158,0xE159,0xE15A,
+0xE15B,0xE15C,0xE15D,0xE15E,0xE15F,0xE160,0xE161,0xE162,
+0xE163,0xE164,0xE165,0xE166,0xE167,0xE168,0xE169,0xE16A,
+0xE16B,0xE16C,0xE16D,0xE16E,0xE16F,0xE170,0xE171,0xE172,
+0xE173,0xE174,0xE175,0xE176,0xE177, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE178,0xE179,0xE17A,0xE17B,0xE17C,0xE17D,0xE17E,0xE17F,
+0xE180,0xE181,0xE182,0xE183,0xE184,0xE185,0xE186,0xE187,
+0xE188,0xE189,0xE18A,0xE18B,0xE18C,0xE18D,0xE18E,0xE18F,
+0xE190,0xE191,0xE192,0xE193,0xE194,0xE195,0xE196,0xE197,
+0xE198,0xE199,0xE19A,0xE19B,0xE19C,0xE19D,0xE19E,0xE19F,
+0xE1A0,0xE1A1,0xE1A2,0xE1A3,0xE1A4,0xE1A5,0xE1A6,0xE1A7,
+0xE1A8,0xE1A9,0xE1AA,0xE1AB,0xE1AC,0xE1AD,0xE1AE,0xE1AF,
+0xE1B0,0xE1B1,0xE1B2,0xE1B3,0xE1B4,0xE1B5,0xE1B6, 0,
+0xE1B7,0xE1B8,0xE1B9,0xE1BA,0xE1BB,0xE1BC,0xE1BD,0xE1BE,
+0xE1BF,0xE1C0,0xE1C1,0xE1C2,0xE1C3,0xE1C4,0xE1C5,0xE1C6,
+0xE1C7,0xE1C8,0xE1C9,0xE1CA,0xE1CB,0xE1CC,0xE1CD,0xE1CE,
+0xE1CF,0xE1D0,0xE1D1,0xE1D2,0xE1D3,0xE1D4,0xE1D5,0xE1D6,
+0xE1D7,0xE1D8,0xE1D9,0xE1DA,0xE1DB,0xE1DC,0xE1DD,0xE1DE,
+0xE1DF,0xE1E0,0xE1E1,0xE1E2,0xE1E3,0xE1E4,0xE1E5,0xE1E6,
+0xE1E7,0xE1E8,0xE1E9,0xE1EA,0xE1EB,0xE1EC,0xE1ED,0xE1EE,
+0xE1EF,0xE1F0,0xE1F1,0xE1F2,0xE1F3,0xE1F4,0xE1F5,0xE1F6,
+0xE1F7,0xE1F8,0xE1F9,0xE1FA,0xE1FB,0xE1FC,0xE1FD,0xE1FE,
+0xE1FF,0xE200,0xE201,0xE202,0xE203,0xE204,0xE205,0xE206,
+0xE207,0xE208,0xE209,0xE20A,0xE20B,0xE20C,0xE20D,0xE20E,
+0xE20F,0xE210,0xE211,0xE212,0xE213,0xE214,0xE215,0xE216,
+0xE217,0xE218,0xE219,0xE21A,0xE21B,0xE21C,0xE21D,0xE21E,
+0xE21F,0xE220,0xE221,0xE222,0xE223,0xE224,0xE225,0xE226,
+0xE227,0xE228,0xE229,0xE22A,0xE22B,0xE22C,0xE22D,0xE22E,
+0xE22F,0xE230,0xE231,0xE232,0xE233, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE234,0xE235,0xE236,0xE237,0xE238,0xE239,0xE23A,0xE23B,
+0xE23C,0xE23D,0xE23E,0xE23F,0xE240,0xE241,0xE242,0xE243,
+0xE244,0xE245,0xE246,0xE247,0xE248,0xE249,0xE24A,0xE24B,
+0xE24C,0xE24D,0xE24E,0xE24F,0xE250,0xE251,0xE252,0xE253,
+0xE254,0xE255,0xE256,0xE257,0xE258,0xE259,0xE25A,0xE25B,
+0xE25C,0xE25D,0xE25E,0xE25F,0xE260,0xE261,0xE262,0xE263,
+0xE264,0xE265,0xE266,0xE267,0xE268,0xE269,0xE26A,0xE26B,
+0xE26C,0xE26D,0xE26E,0xE26F,0xE270,0xE271,0xE272, 0,
+0xE273,0xE274,0xE275,0xE276,0xE277,0xE278,0xE279,0xE27A,
+0xE27B,0xE27C,0xE27D,0xE27E,0xE27F,0xE280,0xE281,0xE282,
+0xE283,0xE284,0xE285,0xE286,0xE287,0xE288,0xE289,0xE28A,
+0xE28B,0xE28C,0xE28D,0xE28E,0xE28F,0xE290,0xE291,0xE292,
+0xE293,0xE294,0xE295,0xE296,0xE297,0xE298,0xE299,0xE29A,
+0xE29B,0xE29C,0xE29D,0xE29E,0xE29F,0xE2A0,0xE2A1,0xE2A2,
+0xE2A3,0xE2A4,0xE2A5,0xE2A6,0xE2A7,0xE2A8,0xE2A9,0xE2AA,
+0xE2AB,0xE2AC,0xE2AD,0xE2AE,0xE2AF,0xE2B0,0xE2B1,0xE2B2,
+0xE2B3,0xE2B4,0xE2B5,0xE2B6,0xE2B7,0xE2B8,0xE2B9,0xE2BA,
+0xE2BB,0xE2BC,0xE2BD,0xE2BE,0xE2BF,0xE2C0,0xE2C1,0xE2C2,
+0xE2C3,0xE2C4,0xE2C5,0xE2C6,0xE2C7,0xE2C8,0xE2C9,0xE2CA,
+0xE2CB,0xE2CC,0xE2CD,0xE2CE,0xE2CF,0xE2D0,0xE2D1,0xE2D2,
+0xE2D3,0xE2D4,0xE2D5,0xE2D6,0xE2D7,0xE2D8,0xE2D9,0xE2DA,
+0xE2DB,0xE2DC,0xE2DD,0xE2DE,0xE2DF,0xE2E0,0xE2E1,0xE2E2,
+0xE2E3,0xE2E4,0xE2E5,0xE2E6,0xE2E7,0xE2E8,0xE2E9,0xE2EA,
+0xE2EB,0xE2EC,0xE2ED,0xE2EE,0xE2EF, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE2F0,0xE2F1,0xE2F2,0xE2F3,0xE2F4,0xE2F5,0xE2F6,0xE2F7,
+0xE2F8,0xE2F9,0xE2FA,0xE2FB,0xE2FC,0xE2FD,0xE2FE,0xE2FF,
+0xE300,0xE301,0xE302,0xE303,0xE304,0xE305,0xE306,0xE307,
+0xE308,0xE309,0xE30A,0xE30B,0xE30C,0xE30D,0xE30E,0xE30F,
+0xE310,0xE311,0xE312,0xE313,0xE314,0xE315,0xE316,0xE317,
+0xE318,0xE319,0xE31A,0xE31B,0xE31C,0xE31D,0xE31E,0xE31F,
+0xE320,0xE321,0xE322,0xE323,0xE324,0xE325,0xE326,0xE327,
+0xE328,0xE329,0xE32A,0xE32B,0xE32C,0xE32D,0xE32E, 0,
+0xE32F,0xE330,0xE331,0xE332,0xE333,0xE334,0xE335,0xE336,
+0xE337,0xE338,0xE339,0xE33A,0xE33B,0xE33C,0xE33D,0xE33E,
+0xE33F,0xE340,0xE341,0xE342,0xE343,0xE344,0xE345,0xE346,
+0xE347,0xE348,0xE349,0xE34A,0xE34B,0xE34C,0xE34D,0xE34E,
+0xE34F,0xE350,0xE351,0xE352,0xE353,0xE354,0xE355,0xE356,
+0xE357,0xE358,0xE359,0xE35A,0xE35B,0xE35C,0xE35D,0xE35E,
+0xE35F,0xE360,0xE361,0xE362,0xE363,0xE364,0xE365,0xE366,
+0xE367,0xE368,0xE369,0xE36A,0xE36B,0xE36C,0xE36D,0xE36E,
+0xE36F,0xE370,0xE371,0xE372,0xE373,0xE374,0xE375,0xE376,
+0xE377,0xE378,0xE379,0xE37A,0xE37B,0xE37C,0xE37D,0xE37E,
+0xE37F,0xE380,0xE381,0xE382,0xE383,0xE384,0xE385,0xE386,
+0xE387,0xE388,0xE389,0xE38A,0xE38B,0xE38C,0xE38D,0xE38E,
+0xE38F,0xE390,0xE391,0xE392,0xE393,0xE394,0xE395,0xE396,
+0xE397,0xE398,0xE399,0xE39A,0xE39B,0xE39C,0xE39D,0xE39E,
+0xE39F,0xE3A0,0xE3A1,0xE3A2,0xE3A3,0xE3A4,0xE3A5,0xE3A6,
+0xE3A7,0xE3A8,0xE3A9,0xE3AA,0xE3AB, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE3AC,0xE3AD,0xE3AE,0xE3AF,0xE3B0,0xE3B1,0xE3B2,0xE3B3,
+0xE3B4,0xE3B5,0xE3B6,0xE3B7,0xE3B8,0xE3B9,0xE3BA,0xE3BB,
+0xE3BC,0xE3BD,0xE3BE,0xE3BF,0xE3C0,0xE3C1,0xE3C2,0xE3C3,
+0xE3C4,0xE3C5,0xE3C6,0xE3C7,0xE3C8,0xE3C9,0xE3CA,0xE3CB,
+0xE3CC,0xE3CD,0xE3CE,0xE3CF,0xE3D0,0xE3D1,0xE3D2,0xE3D3,
+0xE3D4,0xE3D5,0xE3D6,0xE3D7,0xE3D8,0xE3D9,0xE3DA,0xE3DB,
+0xE3DC,0xE3DD,0xE3DE,0xE3DF,0xE3E0,0xE3E1,0xE3E2,0xE3E3,
+0xE3E4,0xE3E5,0xE3E6,0xE3E7,0xE3E8,0xE3E9,0xE3EA, 0,
+0xE3EB,0xE3EC,0xE3ED,0xE3EE,0xE3EF,0xE3F0,0xE3F1,0xE3F2,
+0xE3F3,0xE3F4,0xE3F5,0xE3F6,0xE3F7,0xE3F8,0xE3F9,0xE3FA,
+0xE3FB,0xE3FC,0xE3FD,0xE3FE,0xE3FF,0xE400,0xE401,0xE402,
+0xE403,0xE404,0xE405,0xE406,0xE407,0xE408,0xE409,0xE40A,
+0xE40B,0xE40C,0xE40D,0xE40E,0xE40F,0xE410,0xE411,0xE412,
+0xE413,0xE414,0xE415,0xE416,0xE417,0xE418,0xE419,0xE41A,
+0xE41B,0xE41C,0xE41D,0xE41E,0xE41F,0xE420,0xE421,0xE422,
+0xE423,0xE424,0xE425,0xE426,0xE427,0xE428,0xE429,0xE42A,
+0xE42B,0xE42C,0xE42D,0xE42E,0xE42F,0xE430,0xE431,0xE432,
+0xE433,0xE434,0xE435,0xE436,0xE437,0xE438,0xE439,0xE43A,
+0xE43B,0xE43C,0xE43D,0xE43E,0xE43F,0xE440,0xE441,0xE442,
+0xE443,0xE444,0xE445,0xE446,0xE447,0xE448,0xE449,0xE44A,
+0xE44B,0xE44C,0xE44D,0xE44E,0xE44F,0xE450,0xE451,0xE452,
+0xE453,0xE454,0xE455,0xE456,0xE457,0xE458,0xE459,0xE45A,
+0xE45B,0xE45C,0xE45D,0xE45E,0xE45F,0xE460,0xE461,0xE462,
+0xE463,0xE464,0xE465,0xE466,0xE467, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE468,0xE469,0xE46A,0xE46B,0xE46C,0xE46D,0xE46E,0xE46F,
+0xE470,0xE471,0xE472,0xE473,0xE474,0xE475,0xE476,0xE477,
+0xE478,0xE479,0xE47A,0xE47B,0xE47C,0xE47D,0xE47E,0xE47F,
+0xE480,0xE481,0xE482,0xE483,0xE484,0xE485,0xE486,0xE487,
+0xE488,0xE489,0xE48A,0xE48B,0xE48C,0xE48D,0xE48E,0xE48F,
+0xE490,0xE491,0xE492,0xE493,0xE494,0xE495,0xE496,0xE497,
+0xE498,0xE499,0xE49A,0xE49B,0xE49C,0xE49D,0xE49E,0xE49F,
+0xE4A0,0xE4A1,0xE4A2,0xE4A3,0xE4A4,0xE4A5,0xE4A6, 0,
+0xE4A7,0xE4A8,0xE4A9,0xE4AA,0xE4AB,0xE4AC,0xE4AD,0xE4AE,
+0xE4AF,0xE4B0,0xE4B1,0xE4B2,0xE4B3,0xE4B4,0xE4B5,0xE4B6,
+0xE4B7,0xE4B8,0xE4B9,0xE4BA,0xE4BB,0xE4BC,0xE4BD,0xE4BE,
+0xE4BF,0xE4C0,0xE4C1,0xE4C2,0xE4C3,0xE4C4,0xE4C5,0xE4C6,
+0xE4C7,0xE4C8,0xE4C9,0xE4CA,0xE4CB,0xE4CC,0xE4CD,0xE4CE,
+0xE4CF,0xE4D0,0xE4D1,0xE4D2,0xE4D3,0xE4D4,0xE4D5,0xE4D6,
+0xE4D7,0xE4D8,0xE4D9,0xE4DA,0xE4DB,0xE4DC,0xE4DD,0xE4DE,
+0xE4DF,0xE4E0,0xE4E1,0xE4E2,0xE4E3,0xE4E4,0xE4E5,0xE4E6,
+0xE4E7,0xE4E8,0xE4E9,0xE4EA,0xE4EB,0xE4EC,0xE4ED,0xE4EE,
+0xE4EF,0xE4F0,0xE4F1,0xE4F2,0xE4F3,0xE4F4,0xE4F5,0xE4F6,
+0xE4F7,0xE4F8,0xE4F9,0xE4FA,0xE4FB,0xE4FC,0xE4FD,0xE4FE,
+0xE4FF,0xE500,0xE501,0xE502,0xE503,0xE504,0xE505,0xE506,
+0xE507,0xE508,0xE509,0xE50A,0xE50B,0xE50C,0xE50D,0xE50E,
+0xE50F,0xE510,0xE511,0xE512,0xE513,0xE514,0xE515,0xE516,
+0xE517,0xE518,0xE519,0xE51A,0xE51B,0xE51C,0xE51D,0xE51E,
+0xE51F,0xE520,0xE521,0xE522,0xE523, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE524,0xE525,0xE526,0xE527,0xE528,0xE529,0xE52A,0xE52B,
+0xE52C,0xE52D,0xE52E,0xE52F,0xE530,0xE531,0xE532,0xE533,
+0xE534,0xE535,0xE536,0xE537,0xE538,0xE539,0xE53A,0xE53B,
+0xE53C,0xE53D,0xE53E,0xE53F,0xE540,0xE541,0xE542,0xE543,
+0xE544,0xE545,0xE546,0xE547,0xE548,0xE549,0xE54A,0xE54B,
+0xE54C,0xE54D,0xE54E,0xE54F,0xE550,0xE551,0xE552,0xE553,
+0xE554,0xE555,0xE556,0xE557,0xE558,0xE559,0xE55A,0xE55B,
+0xE55C,0xE55D,0xE55E,0xE55F,0xE560,0xE561,0xE562, 0,
+0xE563,0xE564,0xE565,0xE566,0xE567,0xE568,0xE569,0xE56A,
+0xE56B,0xE56C,0xE56D,0xE56E,0xE56F,0xE570,0xE571,0xE572,
+0xE573,0xE574,0xE575,0xE576,0xE577,0xE578,0xE579,0xE57A,
+0xE57B,0xE57C,0xE57D,0xE57E,0xE57F,0xE580,0xE581,0xE582,
+0xE583,0xE584,0xE585,0xE586,0xE587,0xE588,0xE589,0xE58A,
+0xE58B,0xE58C,0xE58D,0xE58E,0xE58F,0xE590,0xE591,0xE592,
+0xE593,0xE594,0xE595,0xE596,0xE597,0xE598,0xE599,0xE59A,
+0xE59B,0xE59C,0xE59D,0xE59E,0xE59F,0xE5A0,0xE5A1,0xE5A2,
+0xE5A3,0xE5A4,0xE5A5,0xE5A6,0xE5A7,0xE5A8,0xE5A9,0xE5AA,
+0xE5AB,0xE5AC,0xE5AD,0xE5AE,0xE5AF,0xE5B0,0xE5B1,0xE5B2,
+0xE5B3,0xE5B4,0xE5B5,0xE5B6,0xE5B7,0xE5B8,0xE5B9,0xE5BA,
+0xE5BB,0xE5BC,0xE5BD,0xE5BE,0xE5BF,0xE5C0,0xE5C1,0xE5C2,
+0xE5C3,0xE5C4,0xE5C5,0xE5C6,0xE5C7,0xE5C8,0xE5C9,0xE5CA,
+0xE5CB,0xE5CC,0xE5CD,0xE5CE,0xE5CF,0xE5D0,0xE5D1,0xE5D2,
+0xE5D3,0xE5D4,0xE5D5,0xE5D6,0xE5D7,0xE5D8,0xE5D9,0xE5DA,
+0xE5DB,0xE5DC,0xE5DD,0xE5DE,0xE5DF, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE5E0,0xE5E1,0xE5E2,0xE5E3,0xE5E4,0xE5E5,0xE5E6,0xE5E7,
+0xE5E8,0xE5E9,0xE5EA,0xE5EB,0xE5EC,0xE5ED,0xE5EE,0xE5EF,
+0xE5F0,0xE5F1,0xE5F2,0xE5F3,0xE5F4,0xE5F5,0xE5F6,0xE5F7,
+0xE5F8,0xE5F9,0xE5FA,0xE5FB,0xE5FC,0xE5FD,0xE5FE,0xE5FF,
+0xE600,0xE601,0xE602,0xE603,0xE604,0xE605,0xE606,0xE607,
+0xE608,0xE609,0xE60A,0xE60B,0xE60C,0xE60D,0xE60E,0xE60F,
+0xE610,0xE611,0xE612,0xE613,0xE614,0xE615,0xE616,0xE617,
+0xE618,0xE619,0xE61A,0xE61B,0xE61C,0xE61D,0xE61E, 0,
+0xE61F,0xE620,0xE621,0xE622,0xE623,0xE624,0xE625,0xE626,
+0xE627,0xE628,0xE629,0xE62A,0xE62B,0xE62C,0xE62D,0xE62E,
+0xE62F,0xE630,0xE631,0xE632,0xE633,0xE634,0xE635,0xE636,
+0xE637,0xE638,0xE639,0xE63A,0xE63B,0xE63C,0xE63D,0xE63E,
+0xE63F,0xE640,0xE641,0xE642,0xE643,0xE644,0xE645,0xE646,
+0xE647,0xE648,0xE649,0xE64A,0xE64B,0xE64C,0xE64D,0xE64E,
+0xE64F,0xE650,0xE651,0xE652,0xE653,0xE654,0xE655,0xE656,
+0xE657,0xE658,0xE659,0xE65A,0xE65B,0xE65C,0xE65D,0xE65E,
+0xE65F,0xE660,0xE661,0xE662,0xE663,0xE664,0xE665,0xE666,
+0xE667,0xE668,0xE669,0xE66A,0xE66B,0xE66C,0xE66D,0xE66E,
+0xE66F,0xE670,0xE671,0xE672,0xE673,0xE674,0xE675,0xE676,
+0xE677,0xE678,0xE679,0xE67A,0xE67B,0xE67C,0xE67D,0xE67E,
+0xE67F,0xE680,0xE681,0xE682,0xE683,0xE684,0xE685,0xE686,
+0xE687,0xE688,0xE689,0xE68A,0xE68B,0xE68C,0xE68D,0xE68E,
+0xE68F,0xE690,0xE691,0xE692,0xE693,0xE694,0xE695,0xE696,
+0xE697,0xE698,0xE699,0xE69A,0xE69B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE69C,0xE69D,0xE69E,0xE69F,0xE6A0,0xE6A1,0xE6A2,0xE6A3,
+0xE6A4,0xE6A5,0xE6A6,0xE6A7,0xE6A8,0xE6A9,0xE6AA,0xE6AB,
+0xE6AC,0xE6AD,0xE6AE,0xE6AF,0xE6B0,0xE6B1,0xE6B2,0xE6B3,
+0xE6B4,0xE6B5,0xE6B6,0xE6B7,0xE6B8,0xE6B9,0xE6BA,0xE6BB,
+0xE6BC,0xE6BD,0xE6BE,0xE6BF,0xE6C0,0xE6C1,0xE6C2,0xE6C3,
+0xE6C4,0xE6C5,0xE6C6,0xE6C7,0xE6C8,0xE6C9,0xE6CA,0xE6CB,
+0xE6CC,0xE6CD,0xE6CE,0xE6CF,0xE6D0,0xE6D1,0xE6D2,0xE6D3,
+0xE6D4,0xE6D5,0xE6D6,0xE6D7,0xE6D8,0xE6D9,0xE6DA, 0,
+0xE6DB,0xE6DC,0xE6DD,0xE6DE,0xE6DF,0xE6E0,0xE6E1,0xE6E2,
+0xE6E3,0xE6E4,0xE6E5,0xE6E6,0xE6E7,0xE6E8,0xE6E9,0xE6EA,
+0xE6EB,0xE6EC,0xE6ED,0xE6EE,0xE6EF,0xE6F0,0xE6F1,0xE6F2,
+0xE6F3,0xE6F4,0xE6F5,0xE6F6,0xE6F7,0xE6F8,0xE6F9,0xE6FA,
+0xE6FB,0xE6FC,0xE6FD,0xE6FE,0xE6FF,0xE700,0xE701,0xE702,
+0xE703,0xE704,0xE705,0xE706,0xE707,0xE708,0xE709,0xE70A,
+0xE70B,0xE70C,0xE70D,0xE70E,0xE70F,0xE710,0xE711,0xE712,
+0xE713,0xE714,0xE715,0xE716,0xE717,0xE718,0xE719,0xE71A,
+0xE71B,0xE71C,0xE71D,0xE71E,0xE71F,0xE720,0xE721,0xE722,
+0xE723,0xE724,0xE725,0xE726,0xE727,0xE728,0xE729,0xE72A,
+0xE72B,0xE72C,0xE72D,0xE72E,0xE72F,0xE730,0xE731,0xE732,
+0xE733,0xE734,0xE735,0xE736,0xE737,0xE738,0xE739,0xE73A,
+0xE73B,0xE73C,0xE73D,0xE73E,0xE73F,0xE740,0xE741,0xE742,
+0xE743,0xE744,0xE745,0xE746,0xE747,0xE748,0xE749,0xE74A,
+0xE74B,0xE74C,0xE74D,0xE74E,0xE74F,0xE750,0xE751,0xE752,
+0xE753,0xE754,0xE755,0xE756,0xE757, 0, 0, 0};
+
+/* page 7 0xFA40-0xFC4B -
+IBM Selected Kanji and Non-Kanji */
+static uint16 tab_cp932_uni7[]={
+0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,
+0x2178,0x2179,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,
+0x2166,0x2167,0x2168,0x2169,0xFFE2,0xFFE4,0xFF07,0xFF02,
+0x3231,0x2116,0x2121,0x2235,0x7E8A,0x891C,0x9348,0x9288,
+0x84DC,0x4FC9,0x70BB,0x6631,0x68C8,0x92F9,0x66FB,0x5F45,
+0x4E28,0x4EE1,0x4EFC,0x4F00,0x4F03,0x4F39,0x4F56,0x4F92,
+0x4F8A,0x4F9A,0x4F94,0x4FCD,0x5040,0x5022,0x4FFF,0x501E,
+0x5046,0x5070,0x5042,0x5094,0x50F4,0x50D8,0x514A, 0,
+0x5164,0x519D,0x51BE,0x51EC,0x5215,0x529C,0x52A6,0x52C0,
+0x52DB,0x5300,0x5307,0x5324,0x5372,0x5393,0x53B2,0x53DD,
+0xFA0E,0x549C,0x548A,0x54A9,0x54FF,0x5586,0x5759,0x5765,
+0x57AC,0x57C8,0x57C7,0xFA0F,0xFA10,0x589E,0x58B2,0x590B,
+0x5953,0x595B,0x595D,0x5963,0x59A4,0x59BA,0x5B56,0x5BC0,
+0x752F,0x5BD8,0x5BEC,0x5C1E,0x5CA6,0x5CBA,0x5CF5,0x5D27,
+0x5D53,0xFA11,0x5D42,0x5D6D,0x5DB8,0x5DB9,0x5DD0,0x5F21,
+0x5F34,0x5F67,0x5FB7,0x5FDE,0x605D,0x6085,0x608A,0x60DE,
+0x60D5,0x6120,0x60F2,0x6111,0x6137,0x6130,0x6198,0x6213,
+0x62A6,0x63F5,0x6460,0x649D,0x64CE,0x654E,0x6600,0x6615,
+0x663B,0x6609,0x662E,0x661E,0x6624,0x6665,0x6657,0x6659,
+0xFA12,0x6673,0x6699,0x66A0,0x66B2,0x66BF,0x66FA,0x670E,
+0xF929,0x6766,0x67BB,0x6852,0x67C0,0x6801,0x6844,0x68CF,
+0xFA13,0x6968,0xFA14,0x6998,0x69E2,0x6A30,0x6A6B,0x6A46,
+0x6A73,0x6A7E,0x6AE2,0x6AE4,0x6BD6,0x6C3F,0x6C5C,0x6C86,
+0x6C6F,0x6CDA,0x6D04,0x6D87,0x6D6F, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6D96,0x6DAC,0x6DCF,0x6DF8,0x6DF2,0x6DFC,0x6E39,0x6E5C,
+0x6E27,0x6E3C,0x6EBF,0x6F88,0x6FB5,0x6FF5,0x7005,0x7007,
+0x7028,0x7085,0x70AB,0x710F,0x7104,0x715C,0x7146,0x7147,
+0xFA15,0x71C1,0x71FE,0x72B1,0x72BE,0x7324,0xFA16,0x7377,
+0x73BD,0x73C9,0x73D6,0x73E3,0x73D2,0x7407,0x73F5,0x7426,
+0x742A,0x7429,0x742E,0x7462,0x7489,0x749F,0x7501,0x756F,
+0x7682,0x769C,0x769E,0x769B,0x76A6,0xFA17,0x7746,0x52AF,
+0x7821,0x784E,0x7864,0x787A,0x7930,0xFA18,0xFA19, 0,
+0xFA1A,0x7994,0xFA1B,0x799B,0x7AD1,0x7AE7,0xFA1C,0x7AEB,
+0x7B9E,0xFA1D,0x7D48,0x7D5C,0x7DB7,0x7DA0,0x7DD6,0x7E52,
+0x7F47,0x7FA1,0xFA1E,0x8301,0x8362,0x837F,0x83C7,0x83F6,
+0x8448,0x84B4,0x8553,0x8559,0x856B,0xFA1F,0x85B0,0xFA20,
+0xFA21,0x8807,0x88F5,0x8A12,0x8A37,0x8A79,0x8AA7,0x8ABE,
+0x8ADF,0xFA22,0x8AF6,0x8B53,0x8B7F,0x8CF0,0x8CF4,0x8D12,
+0x8D76,0xFA23,0x8ECF,0xFA24,0xFA25,0x9067,0x90DE,0xFA26,
+0x9115,0x9127,0x91DA,0x91D7,0x91DE,0x91ED,0x91EE,0x91E4,
+0x91E5,0x9206,0x9210,0x920A,0x923A,0x9240,0x923C,0x924E,
+0x9259,0x9251,0x9239,0x9267,0x92A7,0x9277,0x9278,0x92E7,
+0x92D7,0x92D9,0x92D0,0xFA27,0x92D5,0x92E0,0x92D3,0x9325,
+0x9321,0x92FB,0xFA28,0x931E,0x92FF,0x931D,0x9302,0x9370,
+0x9357,0x93A4,0x93C6,0x93DE,0x93F8,0x9431,0x9445,0x9448,
+0x9592,0xF9DC,0xFA29,0x969D,0x96AF,0x9733,0x973B,0x9743,
+0x974D,0x974F,0x9751,0x9755,0x9857,0x9865,0xFA2A,0xFA2B,
+0x9927,0xFA2C,0x999E,0x9A4E,0x9AD9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9ADC,0x9B75,0x9B72,0x9B8F,0x9BB1,0x9BBB,0x9C00,0x9D70,
+0x9D6B,0xFA2D,0x9E19,0x9ED1};
+
+static int func_cp932_uni_onechar(int code){
+ if ((code>=0x00A1)&&(code<=0x00DF))
+ return(tab_cp932_uni0[code-0x00A1]);
+ if ((code>=0x8140)&&(code<=0x84BE))
+ return(tab_cp932_uni1[code-0x8140]);
+ if ((code>=0x8740)&&(code<=0x879C))
+ return(tab_cp932_uni2[code-0x8740]);
+ if ((code>=0x889F)&&(code<=0x9FFC))
+ return(tab_cp932_uni3[code-0x889F]);
+ if ((code>=0xE040)&&(code<=0xEAA4))
+ return(tab_cp932_uni4[code-0xE040]);
+ if ((code>=0xED40)&&(code<=0xEEFC))
+ return(tab_cp932_uni5[code-0xED40]);
+ if ((code>=0xF040)&&(code<=0xF9FC))
+ return(tab_cp932_uni6[code-0xF040]);
+ if ((code>=0xFA40)&&(code<=0xFC4B))
+ return(tab_cp932_uni7[code-0xFA40]);
+ return(0);
+}
+
+/* page 0 0x005C-0x00F7 */
+static uint16 tab_uni_cp9320[]={
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8198,0x814E, 0, 0, 0,
+ 0, 0, 0, 0,0x818B,0x817D, 0, 0,
+0x814C, 0,0x81F7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x817E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8180};
+
+/* page 1 0x0391-0x0451 */
+static uint16 tab_uni_cp9321[]={
+0x839F,0x83A0,0x83A1,0x83A2,0x83A3,0x83A4,0x83A5,0x83A6,
+0x83A7,0x83A8,0x83A9,0x83AA,0x83AB,0x83AC,0x83AD,0x83AE,
+0x83AF, 0,0x83B0,0x83B1,0x83B2,0x83B3,0x83B4,0x83B5,
+0x83B6, 0, 0, 0, 0, 0, 0, 0,
+0x83BF,0x83C0,0x83C1,0x83C2,0x83C3,0x83C4,0x83C5,0x83C6,
+0x83C7,0x83C8,0x83C9,0x83CA,0x83CB,0x83CC,0x83CD,0x83CE,
+0x83CF, 0,0x83D0,0x83D1,0x83D2,0x83D3,0x83D4,0x83D5,
+0x83D6, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8446, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x8440,
+0x8441,0x8442,0x8443,0x8444,0x8445,0x8447,0x8448,0x8449,
+0x844A,0x844B,0x844C,0x844D,0x844E,0x844F,0x8450,0x8451,
+0x8452,0x8453,0x8454,0x8455,0x8456,0x8457,0x8458,0x8459,
+0x845A,0x845B,0x845C,0x845D,0x845E,0x845F,0x8460,0x8470,
+0x8471,0x8472,0x8473,0x8474,0x8475,0x8477,0x8478,0x8479,
+0x847A,0x847B,0x847C,0x847D,0x847E,0x8480,0x8481,0x8482,
+0x8483,0x8484,0x8485,0x8486,0x8487,0x8488,0x8489,0x848A,
+0x848B,0x848C,0x848D,0x848E,0x848F,0x8490,0x8491, 0,
+0x8476};
+
+/* page 2 0x2010-0x2473 */
+static uint16 tab_uni_cp9322[]={
+0x815D, 0, 0, 0, 0,0x815C, 0, 0,
+0x8165,0x8166, 0, 0,0x8167,0x8168, 0, 0,
+0x81F5,0x81F6, 0, 0, 0,0x8164,0x8163, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x81F1, 0,0x818C,0x818D, 0, 0, 0, 0,
+ 0, 0, 0,0x81A6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x818E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8782, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x8784, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x81F0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8754,0x8755,0x8756,0x8757,0x8758,0x8759,0x875A,0x875B,
+0x875C,0x875D, 0, 0, 0, 0, 0, 0,
+0xFA40,0xFA41,0xFA42,0xFA43,0xFA44,0xFA45,0xFA46,0xFA47,
+0xFA48,0xFA49, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x81A9,0x81AA,0x81A8,0x81AB, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x81CB, 0,0x81CC, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x81CD, 0,0x81DD,0x81CE, 0, 0, 0,0x81DE,
+0x81B8, 0, 0,0x81B9, 0, 0, 0, 0,
+ 0,0x8794, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x81E3, 0, 0,0x81E5,0x8187,0x8798,
+0x81DA, 0, 0, 0, 0,0x8161, 0,0x81C8,
+0x81C9,0x81BF,0x81BE,0x81E7,0x81E8, 0,0x8793, 0,
+ 0, 0, 0, 0,0x8188,0x81E6, 0, 0,
+ 0, 0, 0, 0, 0,0x81E4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x81E0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8182,0x81DF, 0, 0, 0, 0,0x8185,0x8186,
+ 0, 0,0x81E1,0x81E2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x81BC,0x81BD, 0, 0,0x81BA,0x81BB,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x81DB, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x8799,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x81DC, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8740,0x8741,0x8742,0x8743,0x8744,0x8745,0x8746,0x8747,
+0x8748,0x8749,0x874A,0x874B,0x874C,0x874D,0x874E,0x874F,
+0x8750,0x8751,0x8752,0x8753};
+
+/* page 3 0x2500-0x266F */
+static uint16 tab_uni_cp9323[]={
+0x849F,0x84AA,0x84A0,0x84AB, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x84A1, 0, 0,0x84AC,
+0x84A2, 0, 0,0x84AD,0x84A4, 0, 0,0x84AF,
+0x84A3, 0, 0,0x84AE,0x84A5,0x84BA, 0, 0,
+0x84B5, 0, 0,0x84B0,0x84A7,0x84BC, 0, 0,
+0x84B7, 0, 0,0x84B2,0x84A6, 0, 0,0x84B6,
+0x84BB, 0, 0,0x84B1,0x84A8, 0, 0,0x84B8,
+0x84BD, 0, 0,0x84B3,0x84A9, 0, 0,0x84B9,
+ 0, 0,0x84BE, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x84B4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x81A1,0x81A0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x81A3,0x81A2, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x81A5,0x81A4, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x819F,0x819E,
+ 0, 0, 0,0x819B, 0, 0,0x819D,0x819C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x81FC,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x819A,0x8199, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x818A, 0,0x8189, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x81F4, 0, 0,0x81F3, 0,0x81F2
+};
+
+/* page 4 0x3000-0x30FE */
+static uint16 tab_uni_cp9324[]={
+0x8140,0x8141,0x8142,0x8156, 0,0x8158,0x8159,0x815A,
+0x8171,0x8172,0x8173,0x8174,0x8175,0x8176,0x8177,0x8178,
+0x8179,0x817A,0x81A7,0x81AC,0x816B,0x816C, 0, 0,
+ 0, 0, 0, 0, 0,0x8780, 0,0x8781,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x829F,0x82A0,0x82A1,0x82A2,0x82A3,0x82A4,0x82A5,
+0x82A6,0x82A7,0x82A8,0x82A9,0x82AA,0x82AB,0x82AC,0x82AD,
+0x82AE,0x82AF,0x82B0,0x82B1,0x82B2,0x82B3,0x82B4,0x82B5,
+0x82B6,0x82B7,0x82B8,0x82B9,0x82BA,0x82BB,0x82BC,0x82BD,
+0x82BE,0x82BF,0x82C0,0x82C1,0x82C2,0x82C3,0x82C4,0x82C5,
+0x82C6,0x82C7,0x82C8,0x82C9,0x82CA,0x82CB,0x82CC,0x82CD,
+0x82CE,0x82CF,0x82D0,0x82D1,0x82D2,0x82D3,0x82D4,0x82D5,
+0x82D6,0x82D7,0x82D8,0x82D9,0x82DA,0x82DB,0x82DC,0x82DD,
+0x82DE,0x82DF,0x82E0,0x82E1,0x82E2,0x82E3,0x82E4,0x82E5,
+0x82E6,0x82E7,0x82E8,0x82E9,0x82EA,0x82EB,0x82EC,0x82ED,
+0x82EE,0x82EF,0x82F0,0x82F1, 0, 0, 0, 0,
+ 0, 0, 0,0x814A,0x814B,0x8154,0x8155, 0,
+ 0,0x8340,0x8341,0x8342,0x8343,0x8344,0x8345,0x8346,
+0x8347,0x8348,0x8349,0x834A,0x834B,0x834C,0x834D,0x834E,
+0x834F,0x8350,0x8351,0x8352,0x8353,0x8354,0x8355,0x8356,
+0x8357,0x8358,0x8359,0x835A,0x835B,0x835C,0x835D,0x835E,
+0x835F,0x8360,0x8361,0x8362,0x8363,0x8364,0x8365,0x8366,
+0x8367,0x8368,0x8369,0x836A,0x836B,0x836C,0x836D,0x836E,
+0x836F,0x8370,0x8371,0x8372,0x8373,0x8374,0x8375,0x8376,
+0x8377,0x8378,0x8379,0x837A,0x837B,0x837C,0x837D,0x837E,
+0x8380,0x8381,0x8382,0x8383,0x8384,0x8385,0x8386,0x8387,
+0x8388,0x8389,0x838A,0x838B,0x838C,0x838D,0x838E,0x838F,
+0x8390,0x8391,0x8392,0x8393,0x8394,0x8395,0x8396, 0,
+ 0, 0, 0,0x8145,0x815B,0x8152,0x8153};
+
+/* page 5 0x3230-0x33CD */
+static uint16 tab_uni_cp9325[]={
+ 0,0x878A,0x878B, 0, 0, 0, 0, 0,
+ 0,0x878C, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8785,0x8786,0x8787,0x8788,
+0x8789, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8765, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x8769, 0, 0,
+ 0, 0, 0, 0,0x8760, 0, 0, 0,
+0x8763, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8761,0x876B, 0, 0,0x876A,0x8764,
+ 0, 0, 0,0x876C, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8766, 0,
+ 0, 0, 0,0x876E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x875F,0x876D, 0, 0,0x8762, 0, 0,
+ 0,0x8767, 0, 0, 0, 0, 0,0x8768,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x877E,0x878F,0x878E,0x878D, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8772,0x8773,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x876F,0x8770,0x8771, 0,
+ 0,0x8775, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8774, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x8783};
+
+/* page 6 0x4E00-0x9481 */
+static uint16 tab_uni_cp9326[]={
+0x88EA,0x929A, 0,0x8EB5, 0, 0, 0,0x969C,
+0x8FE4,0x8E4F,0x8FE3,0x89BA, 0,0x9573,0x975E, 0,
+0x98A0,0x894E, 0, 0,0x8A8E,0x98A1,0x90A2,0x99C0,
+0x8B75,0x95B8, 0, 0, 0, 0,0x8FE5, 0,
+ 0,0x97BC, 0, 0, 0, 0,0x95C0, 0,
+0xFA68, 0,0x98A2, 0, 0,0x9286, 0, 0,
+ 0,0x98A3,0x8BF8, 0, 0, 0,0x98A4, 0,
+0x8ADB,0x924F, 0,0x8EE5,0x98A5, 0, 0,0x98A6,
+ 0, 0,0x98A7,0x9454, 0,0x8B76, 0, 0,
+ 0, 0, 0,0x9456, 0,0x93E1,0x8CC1,0x9652,
+ 0, 0, 0, 0, 0,0xE568,0x98A8,0x8FE6,
+0x98A9,0x89B3, 0, 0, 0,0x8BE3,0x8CEE,0x96E7,
+ 0, 0,0x9BA4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9790, 0,0x93FB, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8AA3, 0,
+0x8B54, 0,0x98AA, 0, 0,0x98AB,0x97B9, 0,
+0x975C,0x9188,0x98AD,0x8E96,0x93F1, 0,0x98B0, 0,
+ 0,0x895D,0x8CDD, 0,0x8CDC,0x88E4, 0, 0,
+0x986A,0x9869, 0,0x8DB1,0x889F, 0,0x98B1,0x98B2,
+0x98B3,0x9653,0x98B4, 0,0x8CF0,0x88E5,0x9692, 0,
+0x8B9C, 0, 0,0x8B9D,0x8B9E,0x92E0,0x97BA, 0,
+0x98B5, 0, 0,0x98B6, 0, 0,0x98B7, 0,
+ 0, 0,0x906C, 0, 0, 0, 0, 0,
+0x8F59,0x906D,0x98BC, 0,0x98BA, 0,0x98BB,0x8B77,
+ 0, 0,0x8DA1,0x89EE, 0,0x98B9,0x98B8,0x95A7,
+ 0, 0, 0, 0,0x8E65,0x8E64,0x91BC,0x98BD,
+0x9574,0x90E5, 0, 0, 0,0x8157,0x98BE,0x98C0,
+ 0,0xFA69, 0,0x91E3,0x97DF,0x88C8, 0, 0,
+ 0, 0, 0, 0, 0,0x98BF,0x89BC, 0,
+0x8BC2, 0,0x9287, 0, 0, 0,0x8C8F,0x98C1,
+ 0, 0, 0,0x9443,0xFA6A, 0, 0, 0,
+0xFA6B,0x8AE9, 0,0xFA6C, 0, 0, 0, 0,
+ 0,0x98C2,0x88C9, 0, 0,0x8CDE,0x8AEA,0x959A,
+0x94B0,0x8B78, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x89EF, 0,0x98E5,0x9360, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x948C,
+0x98C4, 0, 0, 0,0x94BA, 0,0x97E0, 0,
+0x904C,0xFA6D,0x8E66, 0,0x8E97,0x89BE, 0, 0,
+ 0, 0, 0,0x92CF, 0, 0,0x9241,0x98C8,
+ 0, 0, 0, 0, 0,0x88CA,0x92E1,0x8F5A,
+0x8DB2,0x9743, 0,0x91CC, 0,0x89BD,0xFA6E,0x98C7,
+ 0,0x975D,0x98C3,0x98C5,0x8DEC,0x98C6,0x9B43, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x98CE, 0, 0, 0, 0, 0,0x98D1,
+0x98CF, 0, 0,0x89C0, 0,0x95B9,0x98C9, 0,
+ 0, 0, 0,0x98CD,0x8CF1, 0, 0,0x8E67,
+ 0, 0, 0,0x8AA4, 0, 0,0x98D2, 0,
+0x98CA, 0,0xFA70,0x97E1, 0,0x8E98, 0,0x98CB,
+ 0,0x98D0,0xFA6F, 0,0xFA72, 0,0x98D3, 0,
+0x98CC, 0,0xFA71,0x8B9F, 0,0x88CB, 0, 0,
+0x8BA0,0x89BF, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x9B44, 0,0x9699,0x958E,0x8CF2,
+ 0, 0, 0, 0, 0,0x904E,0x97B5, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x95D6,
+ 0, 0,0x8C57,0x91A3,0x89E2, 0, 0, 0,
+ 0,0xFA61,0x8F72, 0, 0,0xFA73,0x98D7, 0,
+0x98DC,0x98DA, 0, 0,0x98D5, 0, 0,0x91AD,
+0x98D8, 0,0x98DB,0x98D9, 0,0x95DB, 0,0x98D6,
+ 0,0x904D, 0,0x9693,0x98DD,0x98DE, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8F43,0x98EB,
+ 0, 0, 0,0x946F, 0,0x9555,0x98E6, 0,
+0x95EE, 0,0x89B4, 0, 0, 0,0x98EA,0xFA76,
+ 0, 0, 0, 0, 0,0x98E4,0x98ED, 0,
+ 0,0x9171, 0,0x8CC2, 0,0x947B, 0,0xE0C5,
+ 0,0x98EC,0x937C, 0,0x98E1, 0,0x8CF4, 0,
+ 0,0x8CF3,0x98DF, 0, 0, 0,0xFA77,0x8ED8,
+ 0,0x98E7,0xFA75,0x95ED,0x926C,0x98E3,0x8C91, 0,
+0x98E0,0x98E8,0x98E2,0x97CF,0x98E9,0x9860, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8BE4, 0,
+ 0,0x8C90, 0, 0, 0, 0, 0, 0,
+0xFA74, 0,0xFA7A,0x98EE, 0, 0,0xFA78,0x98EF,
+0x98F3,0x88CC, 0, 0, 0, 0, 0,0x95CE,
+0x98F2, 0, 0, 0, 0,0x98F1,0x98F5, 0,
+ 0, 0,0x98F4, 0,0x92E2, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x8C92, 0, 0,
+ 0, 0, 0, 0,0x98F6, 0, 0, 0,
+0xFA79, 0,0x8EC3, 0,0x91A4,0x92E3,0x8BF4, 0,
+0x98F7, 0, 0, 0, 0,0x8B55, 0, 0,
+0x98F8, 0, 0, 0, 0,0x98FA, 0, 0,
+ 0, 0, 0, 0, 0,0x9654, 0, 0,
+ 0,0x8C86, 0, 0,0xFA7B, 0, 0, 0,
+0x8E50,0x94F5,0x98F9, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8DC3,0x9762, 0, 0,
+ 0, 0,0x98FC,0x9942,0x98FB,0x8DC2, 0,0x8F9D,
+ 0, 0, 0, 0, 0, 0,0x8C58, 0,
+ 0, 0,0x9943, 0, 0,0x8BCD, 0, 0,
+ 0,0x9940,0x9941, 0, 0,0x93AD, 0,0x919C,
+ 0,0x8BA1, 0, 0, 0,0x966C,0x9944, 0,
+0xFA7D, 0,0x97BB, 0, 0, 0,0x9945, 0,
+ 0, 0, 0,0x9948, 0,0x9946, 0,0x916D,
+ 0, 0, 0, 0, 0,0x9947,0x9949, 0,
+ 0, 0, 0, 0,0xFA7C,0x994B, 0, 0,
+ 0,0x994A, 0,0x95C6, 0, 0, 0, 0,
+0x8B56,0x994D,0x994E, 0,0x89AD, 0, 0, 0,
+ 0,0x994C, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8EF2, 0,0x9951,0x9950,0x994F, 0,
+0x98D4, 0,0x9952, 0, 0, 0, 0,0x8F9E,
+ 0,0x9953, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x9744, 0, 0, 0, 0, 0,
+ 0, 0,0x96D7, 0, 0, 0, 0,0x9955,
+ 0, 0,0x9954,0x9957,0x9956, 0, 0,0x9958,
+0x9959,0x88F2, 0,0x8CB3,0x8C5A,0x8F5B,0x929B,0x8BA2,
+0x90E6,0x8CF5,0xFA7E,0x8D8E,0x995B,0x96C6,0x9365, 0,
+0x8E99, 0,0x995A, 0,0x995C, 0, 0, 0,
+ 0, 0,0x937D, 0,0x8A95, 0, 0, 0,
+ 0, 0,0x995D, 0,0xFA80,0x93FC, 0, 0,
+0x9153,0x995F,0x9960,0x94AA,0x8CF6,0x985A,0x9961, 0,
+ 0,0x8BA4, 0, 0, 0,0x95BA,0x91B4,0x8BEF,
+0x9354, 0, 0, 0,0x8C93, 0, 0, 0,
+0x9962, 0,0x9963, 0, 0,0x93E0,0x897E, 0,
+ 0,0x9966,0x8DFB, 0,0x9965,0x8DC4, 0,0x9967,
+0xE3EC,0x9968,0x9660,0x9969, 0,0x996A,0x996B,0x8FE7,
+ 0,0x8ECA, 0, 0, 0,0xFA81, 0, 0,
+0x8AA5, 0,0x996E, 0,0x996C,0x96BB,0x996D, 0,
+0x9579,0x996F,0x9970,0x9971,0x937E, 0, 0, 0,
+0x9975,0x9973,0x9974,0x9972,0x8DE1,0x9976,0x96E8,0x97E2,
+ 0, 0, 0, 0, 0,0x9977,0xFA82, 0,
+ 0, 0, 0, 0,0x90A6,0x9978,0x8F79, 0,
+ 0,0x9979, 0,0x929C,0x97BD,0x9380, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x99C3, 0,
+ 0, 0, 0,0x997A,0xEAA3,0x8BC3, 0, 0,
+0x997B,0x967D, 0, 0, 0, 0,0x8F88,0x91FA,
+ 0,0x997D,0x93E2, 0,0xFA83,0x997E, 0, 0,
+0x9980,0x8A4D, 0, 0, 0,0x9981,0x8BA5, 0,
+0x93CA,0x899A,0x8F6F, 0, 0,0x949F,0x9982, 0,
+0x9381, 0, 0,0x906E,0x9983, 0,0x95AA,0x90D8,
+0x8AA0, 0,0x8AA7,0x9984, 0, 0,0x9986, 0,
+ 0,0x8C59, 0, 0,0x9985,0xFA84, 0,0x97F1,
+ 0, 0, 0, 0, 0,0x8F89, 0, 0,
+ 0, 0, 0, 0,0x94BB,0x95CA, 0,0x9987,
+ 0,0x9798,0x9988, 0, 0, 0,0x9989, 0,
+0x939E, 0, 0,0x998A, 0, 0,0x90A7,0x8DFC,
+0x8C94,0x998B,0x8E68,0x8D8F, 0, 0, 0, 0,
+ 0, 0, 0,0x92E4,0x998D, 0, 0,0x91A5,
+ 0, 0,0x8DED,0x998E,0x998F,0x914F, 0,0x998C,
+ 0, 0, 0, 0,0x9991, 0,0x9655, 0,
+ 0, 0, 0,0x8D84, 0, 0,0x9990, 0,
+ 0, 0, 0,0x8C95,0x8DDC,0x948D, 0, 0,
+ 0,0x9994,0x9992, 0, 0, 0, 0,0x959B,
+0x8FE8,0x999B,0x8A84,0x9995,0x9993,0x916E, 0, 0,
+ 0, 0, 0, 0, 0,0x9997, 0,0x9996,
+ 0, 0, 0,0x8A63, 0, 0, 0,0x8C80,
+0x999C,0x97AB, 0, 0, 0,0x9998, 0, 0,
+ 0,0x999D,0x999A, 0,0x9999, 0, 0, 0,
+ 0, 0, 0,0x97CD,0xFA85, 0, 0,0x8CF7,
+0x89C1, 0, 0,0x97F2, 0, 0,0xFA86, 0,
+ 0,0x8F95,0x9377,0x8D85,0x99A0,0x99A1, 0,0xFB77,
+ 0,0x97E3, 0, 0,0x984A,0x99A3, 0, 0,
+ 0,0x8CF8, 0, 0,0x99A2, 0,0x8A4E, 0,
+0xFA87,0x99A4, 0,0x9675, 0,0x92BA, 0,0x9745,
+ 0,0x95D7, 0, 0, 0,0x99A5, 0, 0,
+ 0, 0,0xE8D3, 0, 0,0x93AE, 0,0x99A6,
+0x8AA8,0x96B1, 0,0xFA88, 0,0x8F9F,0x99A7,0x95E5,
+0x99AB, 0,0x90A8,0x99A8,0x8BCE, 0,0x99A9,0x8AA9,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8C4D,0x99AC, 0,0x99AD, 0, 0,
+0x99AE,0x99AF,0x8ED9, 0, 0, 0,0x8CF9,0x96DC,
+0xFA89,0x96E6,0x93F5, 0, 0,0x95EF,0x99B0,0xFA8A,
+0x99B1, 0, 0, 0, 0,0x99B3, 0,0x99B5,
+0x99B4, 0, 0, 0, 0,0x99B6,0x89BB,0x966B,
+ 0,0x8DFA,0x99B7, 0, 0,0x9178, 0, 0,
+0x8FA0,0x8BA7, 0,0x99B8,0xFA8B, 0, 0, 0,
+ 0, 0,0x94D9, 0, 0, 0, 0,0x99B9,
+ 0,0x99BA, 0,0x99BB, 0, 0, 0, 0,
+0x99BC,0x9543,0x8BE6,0x88E3, 0, 0, 0,0x93BD,
+0x99BD,0x8F5C, 0,0x90E7, 0,0x99BF,0x99BE,0x8FA1,
+0x8CDF,0x99C1,0x94BC, 0, 0,0x99C2, 0, 0,
+ 0,0x94DA,0x91B2,0x91EC,0x8BA6, 0, 0,0x93EC,
+0x9250, 0,0x948E, 0,0x966D, 0,0x99C4, 0,
+0x90E8, 0, 0, 0, 0, 0,0x8C54, 0,
+ 0,0x99C5, 0, 0, 0, 0,0x99C6,0x894B,
+0x88F3,0x8AEB,0xFA8C,0x91A6,0x8B70,0x9791, 0,0x99C9,
+0x89B5, 0, 0,0x99C8, 0, 0, 0,0x8BA8,
+ 0, 0,0x99CA, 0,0x96EF, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xFA8D, 0, 0,0x99CB, 0,
+0x97D0, 0,0x8CFA, 0, 0, 0, 0,0x8CB4,
+0x99CC, 0, 0, 0, 0,0x99CE,0x99CD, 0,
+0x907E,0x8958, 0, 0, 0,0x897D,0x99CF, 0,
+0x99D0, 0,0xFA8E,0x8CB5, 0, 0,0x99D1, 0,
+ 0, 0, 0,0x8B8E, 0, 0, 0, 0,
+ 0, 0,0x8E51,0x99D2, 0, 0, 0, 0,
+0x9694,0x8DB3,0x8B79,0x9746,0x916F,0x94BD,0x8EFB, 0,
+ 0, 0, 0, 0,0x8F66, 0,0x8EE6,0x8EF3,
+ 0,0x8F96, 0,0x94BE, 0,0xFA8F, 0,0x99D5,
+ 0,0x8962,0x9170,0x8CFB,0x8CC3,0x8BE5, 0, 0,
+0x99D9,0x9240,0x91FC,0x8BA9,0x8FA2,0x99DA,0x99D8,0x89C2,
+0x91E4,0x8EB6,0x8E6A,0x8945, 0, 0,0x8A90,0x8D86,
+0x8E69, 0,0x99DB, 0, 0, 0, 0, 0,
+ 0,0x99DC, 0,0x8B68,0x8A65, 0, 0, 0,
+0x8D87,0x8B67,0x92DD,0x8944,0x93AF,0x96BC,0x8D40,0x9799,
+0x9366,0x8CFC, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8C4E, 0,0x99E5, 0,0x8BE1,
+0x9669, 0, 0, 0, 0, 0,0x94DB, 0,
+ 0,0x99E4, 0,0x8ADC,0x99DF,0x99E0,0x99E2, 0,
+ 0, 0, 0, 0, 0, 0,0x99E3, 0,
+0x8B7A,0x9081, 0,0x95AB,0x99E1,0x99DD,0x8CE1, 0,
+0x99DE, 0,0x9843, 0, 0, 0,0x95F0, 0,
+0x92E6,0x8CE0,0x8D90, 0, 0, 0,0x99E6, 0,
+ 0,0x93DB, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x99EA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8EFC, 0,0x8EF4, 0, 0, 0, 0, 0,
+0x99ED,0x99EB, 0,0x96A1, 0,0x99E8,0x99F1,0x99EC,
+ 0, 0, 0,0x99EF,0x8CC4,0x96BD, 0, 0,
+0x99F0, 0, 0, 0,0x99F2, 0,0x99F4, 0,
+ 0, 0,0xFA92,0x8DEE,0x9861, 0,0x99E9,0x99E7,
+0x99F3, 0,0x99EE, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xFA91, 0, 0, 0,
+ 0, 0,0x99F6, 0,0x9A42,0x99F8, 0, 0,
+0x99FC,0xFA93, 0,0x9A40,0x99F9, 0, 0,0x9A5D,
+ 0, 0,0x8DE7,0x8A50, 0, 0, 0, 0,
+0x99F7, 0, 0, 0,0x9A44,0x88F4,0x9A43, 0,
+0x88A3,0x9569,0x9A41, 0,0x99FA, 0, 0,0x99F5,
+0x99FB,0x8DC6, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9A45, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x88F5,0x9A4E, 0, 0,0x9A46,0x9A47, 0,
+0x8FA3,0x9689, 0, 0, 0,0x9A4C,0x9A4B, 0,
+ 0, 0,0x934E, 0, 0, 0, 0, 0,
+ 0, 0,0x9A4D, 0, 0,0x9A4A, 0,0xFA94,
+ 0, 0, 0, 0,0x8953, 0,0x8DB4,0x904F,
+ 0, 0, 0, 0, 0, 0, 0,0x9A48,
+0x9382, 0, 0, 0,0x9A49, 0,0x88A0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9A53,0x9742,
+ 0,0x8FA5, 0,0x9A59, 0, 0, 0, 0,
+0x9A58,0x9A4F, 0, 0, 0, 0,0x91C1, 0,
+0x9A50, 0, 0, 0,0x91ED,0x9A55,0x8FA4, 0,
+ 0, 0, 0, 0,0x9A52, 0, 0,0x96E2,
+ 0, 0, 0,0x8C5B, 0, 0,0x9A56,0x9A57,
+ 0, 0, 0, 0,0x9A54,0x9A5A, 0, 0,
+ 0, 0, 0,0x9A51, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x9A60,0x9A65, 0,0x9A61, 0,
+0x9A5C, 0, 0,0x9A66,0x9150, 0,0xFA95,0x9A68,
+ 0,0x8D41,0x9A5E,0x929D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9A62,0x9A5B,0x8AAB, 0,0x8AEC,0x8A85,0x9A63,0x9A5F,
+ 0, 0, 0, 0, 0, 0, 0,0x8C96,
+0x9A69,0x9A67,0x9172,0x8B69,0x8BAA, 0,0x9A64, 0,
+0x8BF2, 0, 0, 0, 0, 0,0x8963, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9A6D,0x9A6B, 0,0x9AA5,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9A70, 0, 0, 0,
+ 0, 0,0x9A6A, 0,0x9A6E, 0, 0,0x9A6C,
+ 0, 0, 0,0x8E6B,0x9A6F, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x9A72,
+ 0,0x9A77, 0, 0, 0,0x9A75,0x9A74, 0,
+ 0, 0, 0, 0, 0, 0,0x9251, 0,
+ 0,0x89C3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9A71, 0,0x9A73,0x8FA6,
+0x8952, 0, 0,0x9A76, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x89DC, 0, 0, 0, 0, 0,0x9A82,
+ 0,0x8FFA,0x9A7D, 0,0x9A7B, 0,0x9A7C, 0,
+0x9A7E, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x895C, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9158, 0,0x9A78, 0,
+0x9A79, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8A9A, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9A81, 0, 0, 0,
+0x8AED, 0,0x9A84,0x9A80,0x9A83, 0, 0, 0,
+ 0, 0, 0, 0,0x95AC, 0, 0, 0,
+0x93D3, 0,0x94B6, 0, 0, 0, 0, 0,
+0x9A86, 0, 0, 0, 0, 0,0x9A85,0x8A64,
+ 0, 0,0x9A87, 0, 0, 0, 0,0x9A8A,
+ 0, 0, 0, 0,0x9A89, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9A88, 0,0x9458, 0, 0,0x9A8B, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9A8C, 0,
+ 0, 0, 0, 0,0x9A8E, 0,0x9A8D, 0,
+ 0, 0, 0, 0,0x9A90, 0, 0, 0,
+0x9A93,0x9A91,0x9A8F,0x9A92, 0, 0, 0, 0,
+0x9A94, 0, 0, 0, 0, 0,0x9A95, 0,
+ 0,0x9A96, 0,0x9A97, 0, 0, 0,0x9A98,
+0x9964, 0,0x8EFA,0x8E6C, 0, 0,0x89F1, 0,
+0x88F6, 0, 0,0x9263, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9A99, 0,
+0x8DA2, 0,0x88CD,0x907D, 0, 0, 0, 0,
+ 0,0x9A9A,0x8CC5, 0, 0,0x8D91, 0,0x9A9C,
+0x9A9B, 0, 0,0x95DE,0x9A9D, 0, 0, 0,
+0x9A9F,0x9A9E, 0,0x9AA0, 0,0x9AA1, 0,0x8C97,
+ 0, 0,0x8980,0x9AA2, 0, 0,0x9AA4, 0,
+0x9AA3, 0, 0, 0,0x9AA6, 0, 0,0x9379,
+ 0, 0, 0, 0, 0, 0,0x9AA7,0x88B3,
+0x8DDD, 0, 0, 0, 0,0x8C5C, 0, 0,
+0x926E, 0, 0, 0, 0, 0, 0,0x9AA8,
+0x9AA9, 0, 0,0x9AAB, 0, 0, 0, 0,
+0x9AAC, 0,0x8DE2, 0, 0, 0, 0,0x8BCF,
+ 0, 0,0x9656, 0, 0, 0,0x9AAA,0x9AAD,
+0x8DBF,0x8D42, 0, 0, 0, 0, 0, 0,
+ 0,0xFA96, 0, 0, 0, 0, 0, 0,
+ 0,0x9AB1, 0, 0,0x8DA3,0xFA97,0x9252, 0,
+ 0,0x9AAE,0x92D8, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x9AB2,
+ 0, 0,0x9082, 0, 0, 0, 0, 0,
+0x9AB0,0x9AB3, 0,0x8C5E, 0, 0, 0, 0,
+ 0, 0, 0,0x9AB4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9AB5, 0,0x8D43,0x8A5F,0x9AB7, 0, 0, 0,
+ 0, 0,0x9AB8, 0,0xFA98, 0, 0, 0,
+0x9AB9, 0, 0,0x9AB6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9AAF, 0, 0,0x9ABA, 0, 0,0x9ABB,0xFA9A,
+0xFA99, 0, 0,0x9684, 0, 0,0x8FE9, 0,
+ 0, 0,0x9ABD,0x9ABE,0x9ABC, 0,0x9AC0, 0,
+ 0, 0, 0, 0,0x9457, 0, 0,0x88E6,
+0x9575, 0, 0,0x9AC1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8FFB, 0, 0,0x8EB7,
+ 0,0x947C,0x8AEE, 0,0x8DE9, 0, 0, 0,
+0x9678, 0,0x93B0, 0, 0,0x8C98,0x91CD, 0,
+ 0, 0,0x9ABF,0x9AC2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x91C2, 0, 0,
+ 0,0x9AC3, 0, 0, 0,0x9AC4, 0, 0,
+ 0,0x9AC6, 0, 0,0x92E7, 0, 0, 0,
+ 0, 0,0x8AAC, 0, 0, 0, 0,0xEA9F,
+0x8981,0x95F1, 0, 0,0x8FEA,0x9367, 0, 0,
+ 0, 0,0x8DE4, 0, 0,0x9ACC, 0, 0,
+0x95BB,0x97DB, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x89F2,0x9AC8, 0, 0, 0, 0,
+ 0,0x9159,0x9ACB, 0,0x9383, 0, 0,0x9368,
+0x9384,0x94B7,0x92CB, 0, 0, 0,0x8DC7, 0,
+ 0, 0,0x9AC7, 0, 0, 0, 0, 0,
+ 0,0x8996, 0,0x9355, 0, 0, 0, 0,
+0x9AC9, 0,0x9AC5, 0, 0,0x906F, 0, 0,
+ 0,0x9ACD, 0, 0, 0, 0,0x8F6D, 0,
+ 0, 0, 0,0x8BAB, 0,0x9ACE, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x95E6, 0, 0, 0,0x919D,
+ 0, 0, 0, 0,0x92C4, 0,0xFA9D,0x9AD0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x966E, 0, 0,0x9AD1, 0, 0,0x9AD6, 0,
+ 0, 0,0xFA9E,0x95AD, 0, 0, 0, 0,
+0x9AD5,0x9ACF,0x9AD2,0x9AD4, 0, 0,0x8DA4, 0,
+ 0,0x95C7, 0, 0, 0,0x9AD7, 0,0x9264,
+ 0, 0,0x89F3, 0,0x8FEB, 0, 0, 0,
+ 0,0x9AD9, 0,0x9AD8, 0,0x8D88, 0,0x9ADA,
+0x9ADC,0x9ADB, 0, 0,0x9ADE, 0,0x9AD3,0x9AE0,
+ 0, 0, 0, 0,0x9ADF,0x9ADD, 0, 0,
+ 0, 0, 0,0x8E6D,0x9070, 0,0x9173,0x9AE1,
+0x90BA,0x88EB,0x9484, 0, 0, 0, 0,0x92D9,
+ 0,0x9AE3,0x9AE2,0x9AE4,0x9AE5,0x9AE6, 0, 0,
+ 0, 0,0x9AE7, 0, 0, 0, 0, 0,
+ 0,0x95CF,0x9AE8,0xFA9F, 0, 0, 0,0x89C4,
+0x9AE9, 0, 0, 0, 0,0x975B,0x8A4F, 0,
+0x99C7,0x8F67,0x91BD,0x9AEA,0x96E9, 0, 0, 0,
+ 0, 0,0x96B2, 0, 0,0x9AEC, 0,0x91E5,
+ 0,0x9356,0x91BE,0x9576,0x9AED,0x9AEE,0x899B, 0,
+ 0,0x8EB8,0x9AEF, 0, 0, 0, 0,0x88CE,
+0x9AF0, 0, 0, 0, 0, 0,0x9AF1, 0,
+ 0, 0, 0, 0,0x8982, 0, 0,0x8AEF,
+0x93DE,0x95F2, 0, 0, 0, 0,0x9AF5,0x9174,
+0x9AF4,0x8C5F, 0,0xFAA0,0x967A,0x9AF3, 0,0x9385,
+0x9AF7, 0,0x9AF6,0xFAA1, 0,0xFAA2, 0, 0,
+0x9AF9, 0,0x9AF8,0xFAA3, 0,0x899C, 0,0x9AFA,
+0x8FA7,0x9AFC,0x9244, 0,0x9AFB, 0,0x95B1, 0,
+ 0, 0, 0,0x8F97,0x937A, 0, 0, 0,
+0x9B40, 0, 0, 0, 0,0x8D44, 0, 0,
+ 0,0x9B41,0x9440,0x94DC,0x96CF, 0, 0, 0,
+ 0, 0,0x9444, 0, 0,0x9B4A, 0, 0,
+ 0, 0, 0,0x8B57, 0, 0,0x9764, 0,
+ 0,0x96AD, 0,0x9BAA, 0,0x9B42, 0, 0,
+ 0, 0, 0,0x9B45,0xFAA4,0x91C3, 0, 0,
+0x9657, 0, 0, 0,0x9369, 0, 0, 0,
+ 0, 0,0x9B46, 0, 0, 0, 0, 0,
+ 0,0x9685,0xFAA5,0x8DC8, 0, 0,0x8FA8, 0,
+ 0, 0, 0, 0, 0, 0,0x9B47, 0,
+ 0,0x8E6F, 0,0x8E6E, 0, 0, 0, 0,
+0x88B7,0x8CC6, 0,0x90A9,0x88CF, 0, 0, 0,
+ 0,0x9B4B,0x9B4C, 0,0x9B49, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x8957,0x8AAD, 0,
+0x9B48, 0,0x96C3,0x9550, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x88A6, 0,
+ 0, 0, 0,0x88F7, 0, 0, 0,0x8E70,
+ 0,0x88D0, 0,0x88A1, 0, 0, 0, 0,
+ 0,0x9B51, 0, 0, 0, 0, 0, 0,
+ 0,0x9B4F, 0, 0, 0, 0, 0, 0,
+0x96BA, 0,0x9B52, 0,0x9B50, 0, 0,0x9B4E,
+0x9050, 0, 0, 0, 0,0x9B4D, 0, 0,
+ 0,0x95D8, 0, 0, 0, 0, 0,0x8CE2,
+ 0, 0, 0, 0, 0,0x9B56,0x9B57, 0,
+ 0, 0, 0, 0,0x8FA9, 0, 0, 0,
+0x9B53,0x984B, 0, 0, 0, 0,0x946B, 0,
+ 0,0x9B55, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8DA5, 0, 0, 0, 0, 0,
+ 0, 0,0x9B58, 0, 0, 0,0x9577, 0,
+ 0, 0,0x9B59, 0,0x9B54, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x96B9,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x947D, 0, 0, 0, 0, 0,
+ 0, 0,0x9B5A,0x9551, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9B5B,0x9B5F,0x9B5C, 0,
+ 0,0x89C5,0x9B5E, 0, 0, 0, 0, 0,
+ 0,0x8EB9, 0,0x9B5D,0x8C99, 0, 0, 0,
+0x9B6B, 0, 0, 0, 0, 0,0x9B64,0x9B61,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9284, 0,0x9B60, 0, 0,0x9B62, 0,
+ 0,0x9B63, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x9B65,0x9B66, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x8AF0, 0,0x9B68,0x9B67, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9B69, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8FEC, 0, 0, 0, 0, 0,
+ 0, 0,0x9B6C, 0,0x92DA, 0, 0, 0,
+0x8964, 0,0x9B6A, 0, 0, 0,0x9B6D, 0,
+ 0, 0, 0, 0, 0, 0,0x9B6E, 0,
+0x9B71, 0, 0,0x9B6F, 0,0x9B70, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8E71,0x9B72, 0, 0,0x8D45,0x9B73,0xFAA6,0x8E9A,
+0x91B6, 0,0x9B74,0x9B75,0x8E79,0x8D46, 0,0x96D0,
+ 0, 0, 0,0x8B47,0x8CC7,0x9B76,0x8A77, 0,
+ 0,0x9B77, 0,0x91B7, 0, 0, 0, 0,
+0x9B78,0x9BA1, 0,0x9B79, 0,0x9B7A, 0, 0,
+0x9B7B, 0,0x9B7D, 0, 0, 0, 0, 0,
+0x9B7E, 0, 0,0x9B80, 0,0x91EE, 0,0x8946,
+0x8EE7,0x88C0, 0,0x9176,0x8AAE,0x8EB3, 0,0x8D47,
+ 0, 0, 0, 0, 0,0x9386, 0,0x8F40,
+0x8AAF,0x9288,0x92E8,0x88B6,0x8B58,0x95F3, 0,0x8EC0,
+ 0, 0,0x8B71,0x90E9,0x8EBA,0x9747,0x9B81, 0,
+ 0, 0, 0, 0, 0, 0,0x8B7B, 0,
+0x8DC9, 0, 0,0x8A51,0x8983,0x8FAA,0x89C6, 0,
+0x9B82,0x9765, 0, 0, 0, 0, 0,0x8F68,
+0xFAA7, 0,0x8EE2,0x9B83,0x8AF1,0x93D0,0x96A7,0x9B84,
+ 0,0x9B85, 0, 0,0x9578, 0, 0, 0,
+0x9B87, 0,0x8AA6,0x8BF5,0x9B86, 0, 0, 0,
+0xFAA9, 0, 0,0x8AB0, 0,0x9051,0x9B8B,0x8E40,
+ 0,0x89C7,0x9B8A, 0,0x9B88,0x9B8C,0x9B89,0x944A,
+0x9ECB,0x9052, 0,0x9B8D,0xFAAA, 0,0x97BE, 0,
+0x9B8E, 0, 0,0x9B90, 0,0x929E,0x9B8F, 0,
+0x90A1, 0,0x8E9B, 0, 0, 0,0x91CE,0x8EF5,
+ 0,0x9595,0x90EA, 0,0x8ECB,0x9B91,0x8FAB,0x9B92,
+0x9B93,0x88D1,0x91B8,0x9071, 0,0x9B94,0x93B1,0x8FAC,
+ 0,0x8FAD, 0,0x9B95, 0, 0,0x90EB, 0,
+ 0, 0,0x8FAE, 0, 0, 0,0xFAAB, 0,
+0x9B96, 0,0x9B97, 0,0x96DE, 0, 0, 0,
+0x9B98, 0, 0, 0, 0,0x8BC4, 0, 0,
+ 0,0x8F41, 0, 0, 0, 0, 0, 0,
+0x9B99,0x9B9A,0x8EDA,0x904B,0x93F2,0x9073,0x94F6,0x9441,
+0x8BC7,0x9B9B, 0, 0, 0,0x8B8F,0x9B9C, 0,
+0x8BFC, 0,0x93CD,0x89AE, 0,0x8E72,0x9B9D,0x9BA0,
+0x9B9F,0x8BFB, 0,0x9B9E, 0,0x9357, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x91AE, 0,
+0x936A,0x8EC6, 0, 0,0x9177,0x979A, 0, 0,
+ 0, 0, 0, 0,0x9BA2, 0,0x9BA3,0x93D4,
+ 0,0x8E52, 0, 0, 0, 0,0x9BA5, 0,
+ 0,0x9BA6, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9BA7, 0, 0, 0,
+0x8AF2,0x9BA8, 0, 0,0x9BA9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x89AA, 0, 0, 0, 0,0xFAAC, 0,
+0x915A,0x8AE2, 0,0x9BAB,0x96A6, 0, 0, 0,
+ 0,0x91D0, 0,0x8A78, 0, 0,0x9BAD,0x9BAF,
+0x8ADD, 0,0xFAAD,0x9BAC,0x9BAE, 0,0x9BB1, 0,
+ 0, 0, 0, 0, 0,0x9BB0, 0,0x9BB2,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9BB3, 0, 0, 0, 0, 0, 0,
+0x93BB,0x8BAC, 0, 0, 0, 0, 0, 0,
+0x89E3,0x9BB4,0x9BB9, 0, 0,0x9BB7, 0,0x95F5,
+0x95F4, 0, 0, 0, 0,0xFAAE,0x9387, 0,
+ 0, 0,0x9BB6,0x8F73, 0,0x9BB5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x9092,
+ 0, 0, 0,0x9BBA, 0, 0,0x8DE8, 0,
+ 0,0x9BC0, 0, 0,0x9BC1,0x9BBB,0x8A52,0x9BBC,
+0x9BC5,0x9BC4,0x9BC3,0x9BBF, 0, 0, 0,0x9BBE,
+ 0, 0,0x9BC2, 0, 0, 0, 0,0xFAAF,
+ 0,0x95F6, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xFAB2, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x9BC9,0x9BC6, 0,0x9BC8, 0,
+0x9792, 0,0x9BC7,0xFAB0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9BBD, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9093, 0, 0,0x9BCA,0xFAB3, 0,0x8DB5,
+ 0, 0, 0,0x9BCB, 0, 0,0x9BCC, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x9BCF, 0,0x9BCE, 0, 0,0x9BCD,
+ 0, 0, 0,0x9388,0x9BB8, 0, 0, 0,
+0x9BD5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x9BD1, 0, 0,
+ 0, 0,0x9BD0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9BD2, 0,0x9BD3, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x9BD6,
+0xFAB4,0xFAB5,0x97E4, 0,0x9BD7,0x9BD4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9BD8, 0, 0,0x8ADE,0x9BD9, 0, 0,
+0xFAB6, 0,0x9BDB,0x9BDA, 0, 0,0x9BDC, 0,
+ 0, 0, 0,0x9BDD, 0,0x90EC,0x8F42, 0,
+ 0,0x8F84, 0,0x9183, 0,0x8D48,0x8DB6,0x8D49,
+0x8B90, 0, 0,0x9BDE, 0, 0,0x8DB7, 0,
+ 0,0x8CC8,0x9BDF,0x96A4,0x9462,0x9BE0, 0,0x8D4A,
+ 0, 0, 0,0x8AAA, 0,0x9246,0x8BD0, 0,
+ 0, 0,0x8E73,0x957A, 0, 0,0x94BF, 0,
+ 0, 0, 0,0x9BE1,0x8AF3, 0, 0, 0,
+ 0,0x9BE4, 0, 0, 0, 0,0x929F, 0,
+ 0,0x9BE3,0x9BE2,0x9BE5, 0,0x92E9, 0, 0,
+ 0, 0, 0, 0, 0,0x9083, 0, 0,
+ 0, 0, 0,0x8E74, 0,0x90C8, 0,0x91D1,
+0x8B41, 0, 0,0x92A0, 0, 0,0x9BE6,0x9BE7,
+0x8FED, 0, 0, 0, 0,0x9658, 0, 0,
+0x9BEA, 0, 0,0x9BE9,0x9BE8,0x959D, 0,0x9BF1,
+ 0, 0, 0, 0,0x9679, 0,0x9BEB, 0,
+ 0, 0, 0, 0,0x9BED,0x968B, 0,0x9BEC,
+ 0, 0, 0, 0, 0, 0, 0,0x9BEE,
+ 0,0x94A6,0x9BEF,0x95BC,0x9BF0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8AB1,0x95BD,0x944E,0x9BF2,0x9BF3, 0,
+0x8D4B,0x8AB2,0x9BF4,0x8CB6,0x9763,0x9748,0x8AF4,0x9BF6,
+ 0,0x92A1, 0,0x8D4C,0x8FAF, 0, 0,0x94DD,
+ 0, 0,0x8FB0, 0, 0, 0, 0,0x8F98,
+ 0, 0, 0, 0, 0,0x92EA,0x95F7,0x9358,
+ 0, 0,0x8D4D, 0,0x957B, 0, 0, 0,
+0x9BF7, 0, 0, 0, 0, 0,0x9378,0x8DC0,
+ 0, 0, 0,0x8CC9, 0,0x92EB, 0, 0,
+ 0, 0, 0, 0, 0,0x88C1,0x8F8E,0x8D4E,
+0x9766, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9BF8,0x9BF9,0x9470, 0, 0, 0, 0,
+0x9BFA,0x97F5,0x984C, 0, 0, 0, 0,0x9BFC,
+0x9BFB, 0, 0,0x8A66, 0, 0,0x9C40, 0,
+ 0, 0,0x9C43,0x9C44, 0,0x9C42, 0,0x955F,
+0x8FB1,0x9C46,0x9C45,0x9C41, 0, 0, 0, 0,
+0x9C47,0x9C48, 0, 0,0x9C49, 0, 0, 0,
+0x9C4C,0x9C4A, 0,0x9C4B,0x9C4D, 0,0x8984,0x92EC,
+0x9C4E, 0,0x8C9A,0x89F4,0x9455, 0,0x9C4F,0x93F9,
+ 0,0x95D9, 0,0x9C50,0x984D, 0, 0, 0,
+ 0,0x9C51,0x95BE,0x9C54,0x989F,0x98AF, 0,0x8EAE,
+0x93F3,0x9C55, 0,0x8B7C,0x92A2,0x88F8,0x9C56,0x95A4,
+0x8D4F, 0, 0,0x926F, 0, 0, 0,0x92ED,
+ 0,0xFAB7, 0, 0, 0,0x96ED,0x8CB7,0x8CCA,
+ 0,0x9C57, 0, 0, 0,0x9C58, 0,0x9C5E,
+ 0,0x8EE3, 0, 0,0xFAB8,0x92A3, 0,0x8BAD,
+0x9C59, 0, 0, 0,0x954A, 0,0x9265, 0,
+ 0,0x9C5A, 0, 0, 0,0xFA67, 0, 0,
+0x9C5B, 0,0x8BAE, 0,0x9C5C, 0,0x9C5D, 0,
+ 0,0x9C5F, 0,0x9396, 0, 0,0x9C60,0x9C61,
+ 0,0x9C62, 0, 0,0x9C53,0x9C52, 0, 0,
+ 0,0x9C63,0x8C60, 0, 0, 0,0x9546,0xFAB9,
+ 0,0x8DCA,0x9556,0x92A4,0x956A,0x9C64, 0, 0,
+0x8FB2,0x8965, 0,0x9C65, 0, 0, 0,0x9C66,
+ 0,0x96F0, 0, 0,0x94DE, 0, 0,0x9C69,
+0x899D,0x90AA,0x9C68,0x9C67,0x8C61,0x91D2, 0,0x9C6D,
+0x9C6B, 0,0x9C6A,0x97A5,0x8CE3, 0, 0, 0,
+0x8F99,0x9C6C,0x936B,0x8F5D, 0, 0, 0,0x93BE,
+0x9C70,0x9C6F, 0, 0, 0, 0,0x9C6E, 0,
+0x9C71,0x8CE4, 0, 0, 0, 0, 0, 0,
+0x9C72,0x959C,0x8F7A, 0, 0,0x9C73,0x94F7, 0,
+ 0, 0, 0,0x93BF,0x92A5, 0, 0,0xFABA,
+ 0,0x934F, 0, 0,0x9C74,0x8B4A, 0, 0,
+ 0, 0, 0,0x9053, 0,0x954B, 0, 0,
+ 0, 0, 0, 0,0x8AF5,0x9445, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9C75,0x8E75,
+0x9659,0x965A, 0, 0,0x899E,0x9C7A,0xFABB, 0,
+0x9289, 0, 0, 0,0x9C77, 0, 0, 0,
+ 0, 0, 0,0x89F5, 0, 0, 0, 0,
+0x9CAB,0x9C79, 0, 0, 0,0x944F, 0, 0,
+0x9C78, 0, 0,0x9C76, 0,0x8D9A, 0,0x9C7C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9C83,0x9C89,
+0x9C81, 0,0x937B, 0, 0,0x9C86,0x957C, 0,
+ 0,0x9C80, 0,0x9C85,0x97E5,0x8E76, 0, 0,
+0x91D3,0x9C7D, 0, 0, 0,0x8B7D,0x9C88,0x90AB,
+0x8985,0x9C82,0x89F6,0x9C87, 0, 0, 0,0x8BAF,
+ 0,0x9C84, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x9C8A, 0, 0, 0, 0, 0,
+ 0,0x9C8C,0x9C96,0x9C94, 0, 0,0x9C91, 0,
+ 0, 0,0x9C90,0x97F6, 0,0x9C92, 0, 0,
+0x8BB0, 0,0x8D50, 0, 0,0x8F9A, 0, 0,
+ 0,0x9C99,0x9C8B, 0, 0,0xFABC, 0,0x9C8F,
+0x9C7E, 0,0x89F8,0x9C93,0x9C95,0x9270, 0, 0,
+0x8DA6,0x89B6,0x9C8D,0x9C98,0x9C97,0x8BB1, 0,0x91A7,
+0x8A86, 0, 0, 0, 0,0x8C62, 0,0x9C8E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9C9A, 0,0x9C9D,0x9C9F,0xFABD, 0, 0,
+ 0,0x8EBB,0xFABE,0x9CA5,0x92EE,0x9C9B, 0, 0,
+ 0, 0,0x9CA3, 0,0x89F7, 0,0x9CA1,0x9CA2,
+ 0, 0,0x9C9E,0x9CA0, 0, 0, 0,0x8CE5,
+0x9749, 0, 0,0x8AB3, 0, 0,0x8978,0x9CA4,
+ 0,0x9459,0x88AB, 0, 0, 0, 0, 0,
+ 0, 0,0x94DF,0x9C7B,0x9CAA,0x9CAE,0x96E3, 0,
+0x9CA7, 0, 0, 0,0x9389,0x9CAC, 0, 0,
+ 0, 0, 0, 0, 0,0x8FEE,0x9CAD,0x93D5,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9866, 0,0x9CA9, 0,0xFAC0, 0, 0,
+0x9CAF, 0,0x8D9B, 0,0x90C9, 0,0xFABF,0x88D2,
+0x9CA8,0x9CA6, 0,0x9179, 0, 0, 0,0x9C9C,
+0x8E53, 0, 0, 0, 0, 0, 0, 0,
+0x91C4,0x9CBB,0xFAC2,0x917A,0x9CB6, 0,0x9CB3,0x9CB4,
+ 0,0x8EE4,0x9CB7,0x9CBA, 0, 0, 0, 0,
+0x9CB5,0x8F44, 0,0x9CB8, 0, 0,0x9CB2, 0,
+0x96FA,0x96F9, 0, 0, 0,0x9CBC,0x9CBD,0x88D3,
+ 0,0xFAC3, 0, 0, 0,0x9CB1, 0, 0,
+ 0, 0,0x8BF0,0x88A4, 0, 0, 0,0x8AB4,
+0xFAC1,0x9CB9, 0, 0, 0, 0, 0,0x9CC1,
+0x9CC0, 0, 0, 0,0x9CC5, 0, 0, 0,
+0xFAC5, 0, 0, 0,0x9CC6, 0, 0,0xFAC4,
+ 0, 0, 0, 0,0x9CC4,0x9CC7,0x9CBF,0x9CC3,
+ 0, 0,0x9CC8, 0,0x9CC9, 0, 0,0x9CBE,
+0x8E9C, 0,0x9CC2,0x91D4,0x8D51,0x9CB0,0x9054, 0,
+ 0, 0, 0,0x9CD6, 0,0x95E7, 0, 0,
+0x9CCC,0x9CCD,0x9CCE, 0, 0,0x9CD5, 0,0x9CD4,
+ 0, 0,0x969D,0x8AB5, 0,0x9CD2, 0,0x8C64,
+0x8A53, 0, 0,0x9CCF, 0, 0,0x97B6,0x9CD1,
+0x88D4,0x9CD3, 0,0x9CCA,0x9CD0,0x9CD7,0x8C63,0x9CCB,
+ 0, 0, 0, 0, 0, 0,0x977C, 0,
+ 0, 0,0x974A, 0, 0, 0, 0,0x9CDA,
+ 0, 0,0x9CDE, 0, 0, 0,0x919E, 0,
+0x97F7,0x9CDF, 0, 0,0x9CDC, 0,0x9CD9, 0,
+0xFAC6,0x9CD8,0x9CDD, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x95AE, 0, 0,0x93B2,
+ 0,0x8C65, 0,0x9CE0,0x9CDB, 0,0x9CE1, 0,
+ 0, 0,0x8C9B, 0, 0, 0,0x89AF, 0,
+ 0, 0,0x9CE9, 0, 0, 0,0x8AB6, 0,
+ 0, 0, 0,0x9CE7, 0, 0,0x9CE8,0x8DA7,
+0x9CE6,0x9CE4,0x9CE3,0x9CEA,0x9CE2,0x9CEC, 0, 0,
+0x89F9, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x9CEE, 0, 0,0x9CED, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x92A6, 0,0x9CF1, 0,0x9CEF,0x9CE5,
+0x8C9C, 0,0x9CF0, 0,0x9CF4,0x9CF3,0x9CF5,0x9CF2,
+0x9CF6, 0, 0, 0, 0, 0, 0, 0,
+0x9CF7,0x9CF8,0x95E8, 0,0x9CFA,0x9CF9,0x8F5E, 0,
+0x90AC,0x89E4,0x89FA,0xFAC7,0x9CFB, 0,0x88BD, 0,
+ 0, 0,0x90CA,0x9CFC, 0,0xE6C1,0x9D40,0x8C81,
+ 0,0x9D41, 0, 0, 0, 0,0x90ED, 0,
+ 0, 0,0x9D42, 0, 0, 0,0x9D43,0x8B59,
+0x9D44, 0,0x9D45,0x9D46,0x91D5, 0, 0, 0,
+0x8CCB, 0, 0,0x96DF, 0, 0, 0,0x965B,
+0x8F8A,0x9D47, 0, 0, 0, 0, 0,0x90EE,
+0xE7BB,0x94E0, 0,0x8EE8, 0,0x8DCB,0x9D48, 0,
+ 0, 0, 0,0x91C5, 0,0x95A5, 0, 0,
+0x91EF, 0, 0,0x9D4B, 0, 0,0x9D49, 0,
+0x9D4C, 0, 0,0x9D4A, 0, 0, 0, 0,
+0x9D4D, 0, 0, 0, 0, 0,0x95AF, 0,
+ 0,0x88B5, 0, 0, 0, 0,0x957D, 0,
+ 0,0x94E1, 0, 0,0x9D4E, 0,0x9D51,0x8FB3,
+0x8B5A, 0,0x9D4F,0x9D56,0x8FB4, 0, 0, 0,
+ 0,0x9D50,0x9463, 0, 0, 0, 0, 0,
+ 0,0x977D,0x9D52,0x9D53,0x9D57,0x938A,0x9D54,0x8D52,
+0x90DC, 0, 0,0x9D65,0x94B2, 0,0x91F0, 0,
+ 0, 0, 0, 0, 0, 0,0xFAC8, 0,
+ 0, 0, 0,0x94E2,0x9DAB, 0, 0, 0,
+ 0,0x95F8, 0, 0, 0,0x92EF, 0, 0,
+ 0,0x9695, 0,0x9D5A,0x899F,0x928A, 0, 0,
+ 0, 0,0x9D63, 0, 0,0x9253,0x9D5D,0x9D64,
+0x9D5F,0x9D66,0x9D62, 0,0x9D61,0x948F, 0,0x9D5B,
+0x89FB,0x9D59,0x8B91,0x91F1,0x9D55, 0, 0,0x9D58,
+0x8D53,0x90D9, 0,0x8FB5,0x9D60,0x9471, 0, 0,
+0x8B92,0x8A67, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8A87,0x9040,0x9D68,0x9D6D,
+ 0,0x9D69, 0,0x8C9D, 0,0x9D6E,0x8E41,0x8D89,
+ 0, 0, 0, 0, 0, 0,0x8F45,0x9D5C,
+ 0,0x8E9D,0x9D6B, 0, 0, 0, 0,0x8E77,
+0x9D6C,0x88C2, 0, 0,0x9D67, 0, 0, 0,
+ 0,0x92A7, 0, 0, 0, 0, 0, 0,
+ 0,0x8B93, 0, 0, 0, 0, 0,0x8BB2,
+ 0, 0, 0, 0, 0, 0, 0,0x9D6A,
+0x88A5, 0, 0,0x8DC1, 0, 0, 0,0x9055,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x92F0, 0, 0,0x94D2,0x9D70,0x917D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x91A8, 0, 0,0x8E4A,0x9D71, 0,0x9D73,
+0x9D6F, 0, 0, 0, 0,0x95DF, 0,0x92BB,
+ 0, 0, 0, 0,0x917B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x95F9,
+0x8ECC,0x9D80, 0,0x9D7E, 0, 0,0x9098, 0,
+ 0, 0,0x8C9E, 0, 0, 0,0x9D78,0x8FB7,
+ 0, 0,0x93E6,0x9450, 0, 0, 0, 0,
+0x9D76, 0, 0,0x917C, 0, 0, 0, 0,
+0x8EF6,0x9D7B, 0, 0,0x8FB6, 0,0x9D75,0x9D7A,
+ 0, 0,0x9472, 0, 0, 0,0x9D74, 0,
+0x8C40, 0, 0,0x8A7C, 0, 0, 0,0x9D7C,
+0x97A9,0x8DCC,0x9254,0x9D79, 0,0x90DA, 0,0x8D54,
+0x9084,0x8986,0x915B,0x9D77,0x8B64, 0, 0, 0,
+ 0, 0,0x8C66, 0,0x92CD,0x9D7D, 0, 0,
+ 0, 0, 0,0x917E, 0, 0,0x9D81, 0,
+0x9D83, 0, 0,0x91B5,0x9D89, 0,0x9D84, 0,
+ 0,0x9D86, 0, 0, 0, 0, 0,0x9560,
+0x92F1, 0,0x9D87, 0, 0, 0,0x974B, 0,
+ 0, 0,0x9767,0x8AB7, 0, 0, 0, 0,
+ 0,0x88AC, 0,0x9D85, 0, 0, 0, 0,
+ 0,0x9D82, 0, 0, 0, 0,0x8AF6, 0,
+ 0, 0, 0, 0,0x8987,0xFAC9,0x9D88, 0,
+ 0, 0,0x9768, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9D8C, 0,
+ 0, 0, 0, 0, 0,0x91B9, 0,0x9D93,
+ 0, 0, 0,0x9D8D, 0, 0,0x9D8A,0x9D91,
+ 0, 0, 0, 0,0x9D72, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9D8E, 0,
+0x9D92, 0, 0, 0,0x94C0,0x938B, 0, 0,
+ 0, 0, 0, 0,0x9D8B, 0,0x9D8F, 0,
+ 0, 0,0x8C67, 0, 0, 0,0x8DEF, 0,
+ 0, 0,0x90DB, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9D97, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9345, 0, 0, 0, 0, 0, 0, 0,
+0xFACA, 0, 0, 0, 0, 0, 0,0x9D94,
+ 0,0x9680, 0, 0, 0, 0, 0,0x9D95,
+ 0, 0, 0, 0, 0, 0,0x9D96, 0,
+0x96CC, 0,0x90A0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8C82, 0, 0, 0, 0,
+0x9D9D, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8E54,0x9D9A, 0,0x9D99, 0, 0,
+ 0, 0,0x9451, 0, 0,0xFACB,0x93B3, 0,
+ 0, 0, 0, 0,0x9350,0x9D9B, 0, 0,
+ 0,0x9D9C, 0,0x958F, 0,0x9464,0x8E42, 0,
+0x90EF, 0,0x966F, 0, 0, 0, 0, 0,
+ 0,0x8A68, 0,0x9DA3,0x9D9E, 0, 0, 0,
+ 0,0x9769,0x9DA5, 0, 0,0x9DA1, 0,0x9DA2,
+ 0, 0, 0, 0, 0,0x9180,0xFACC, 0,
+ 0, 0,0x9DA0, 0,0x9D5E, 0, 0, 0,
+0x9DA4, 0,0x9D9F, 0, 0, 0, 0, 0,
+0x9DA9,0x9DAA,0x9346,0x9DAC, 0, 0,0x8E43,0x9DA7,
+ 0, 0, 0, 0,0x8B5B, 0, 0,0x9DAD,
+ 0,0x9DA6,0x9DB1, 0,0x9DB0, 0,0x9DAF, 0,
+ 0, 0,0x9DB2, 0, 0,0x9DB4,0x8FEF, 0,
+0x9DB3, 0, 0, 0, 0,0x9DB7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9DB5, 0, 0, 0,0x9DB6,0x9D90, 0, 0,
+ 0, 0, 0,0x9DB9,0x9DB8, 0, 0, 0,
+ 0, 0,0x9D98,0x9DBA,0x9DAE, 0, 0,0x8E78,
+ 0, 0, 0, 0,0x9DBB,0x9DBC,0x9DBE,0x9DBD,
+0x9DBF,0x89FC, 0,0x8D55, 0, 0,0x95FA,0x90AD,
+ 0, 0, 0, 0, 0,0x8CCC, 0, 0,
+0x9DC1, 0, 0, 0, 0,0x9DC4,0xFACD,0x9571,
+ 0,0x8B7E, 0, 0, 0,0x9DC3,0x9DC2,0x9473,
+0x9DC5,0x8BB3, 0, 0, 0,0x9DC7,0x9DC6, 0,
+ 0, 0,0x8AB8,0x8E55, 0, 0,0x93D6, 0,
+ 0, 0, 0, 0,0x8C68, 0, 0, 0,
+0x9094, 0,0x9DC8, 0,0x90AE,0x9347, 0,0x957E,
+0x9DC9, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x9DCA,0x9DCB, 0, 0, 0,0x95B6,
+0x9B7C,0x90C4, 0, 0,0x956B, 0,0x8DD6, 0,
+0x94E3,0x94C1, 0, 0, 0, 0, 0,0x936C,
+ 0,0x97BF, 0,0x9DCD,0x8ECE, 0, 0,0x9DCE,
+ 0,0x88B4, 0, 0,0x8BD2,0x90CB, 0,0x9580,
+ 0, 0, 0,0x9DCF,0x8E61,0x9266, 0,0x8E7A,
+0x9056, 0, 0, 0, 0, 0, 0,0x9DD0,
+ 0,0x95FB, 0, 0,0x8997,0x8E7B, 0, 0,
+ 0,0x9DD3, 0,0x9DD1,0x9DD4,0x97B7,0x9DD2, 0,
+ 0, 0, 0,0x90F9,0x9DD5, 0, 0,0x91B0,
+ 0, 0,0x9DD6, 0, 0, 0, 0,0x8AF8,
+ 0,0x9DD8, 0,0x9DD7, 0, 0, 0, 0,
+0x9DD9,0x9DDA,0x8AF9, 0, 0,0x93FA,0x9255,0x8B8C,
+0x8E7C,0x9181, 0, 0,0x8F7B,0x88AE, 0, 0,
+ 0,0x9DDB, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x89A0,0x9DDF, 0, 0, 0, 0,
+0xFACE, 0,0x8D56,0x9DDE, 0, 0,0x8DA9,0x8FB8,
+ 0,0xFAD1,0x9DDD, 0,0x8FB9, 0,0x96BE,0x8DA8,
+ 0, 0, 0,0x88D5,0x90CC,0xFACF, 0, 0,
+ 0, 0, 0, 0,0x9DE4, 0,0xFAD3,0x90AF,
+0x8966, 0, 0, 0,0xFAD4,0x8F74, 0,0x9686,
+0x8DF0, 0, 0, 0, 0,0x8FBA,0xFAD2,0x90A5,
+ 0,0xFA63, 0, 0,0x9DE3,0x9DE1,0x9DE2, 0,
+ 0, 0, 0,0xFAD0,0x928B, 0, 0,0x9E45,
+ 0,0x9DE8,0x8E9E,0x8D57,0x9DE6, 0, 0, 0,
+ 0,0x9DE7, 0,0x9057, 0, 0, 0,0x9DE5,
+ 0, 0,0x8E4E, 0, 0, 0, 0,0xFAD6,
+ 0,0xFAD7, 0, 0, 0,0x9DEA,0x9DE9,0x9DEE,
+ 0,0xFAD7,0x9DEF, 0,0x9DEB,0xFAD5,0x8A41,0x9DEC,
+0x9DED,0x94D3, 0, 0, 0, 0,0x9581,0x8C69,
+0x9DF0, 0, 0,0xFAD9,0x90B0, 0,0x8FBB, 0,
+ 0, 0,0x9271, 0, 0, 0, 0, 0,
+ 0,0x8BC5, 0,0x9DF1,0x9DF5, 0, 0,0x89C9,
+0x9DF2,0x9DF4, 0, 0, 0, 0,0x9DF3, 0,
+ 0,0x8F8B, 0, 0, 0, 0,0x9267,0x88C3,
+0x9DF6,0xFADA, 0, 0, 0,0x9DF7, 0, 0,
+0xFADB, 0,0x92A8, 0, 0, 0,0x97EF, 0,
+ 0, 0, 0,0x8E62, 0, 0,0x95E9, 0,
+ 0, 0,0xFADC, 0,0x965C, 0, 0, 0,
+0x9E41,0x9DF9, 0, 0,0x9DFC, 0,0x9DFB,0xFADD,
+ 0,0x9DF8, 0, 0,0x9E40, 0, 0,0x93DC,
+ 0,0x9DFA, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9E42, 0,
+ 0,0x8F8C,0x9E43, 0,0x976A,0x9498, 0, 0,
+0x9E44, 0, 0, 0, 0, 0,0x9E46, 0,
+ 0,0x9E47, 0, 0, 0, 0, 0, 0,
+0x9E48, 0,0x8BC8,0x8967,0x8D58,0x9E49, 0,0x9E4A,
+0x8F91,0x9182,0xFADE,0xFA66,0x99D6,0x915D,0x915C,0x91D6,
+0x8DC5, 0, 0,0x98F0, 0, 0, 0, 0,
+0x8C8E,0x974C, 0,0x95FC, 0,0x959E,0xFADF,0x9E4B,
+ 0, 0, 0, 0,0x8DF1,0x92BD,0x9E4C,0x984E,
+ 0, 0, 0,0x965D, 0,0x92A9,0x9E4D,0x8AFA,
+ 0, 0, 0, 0, 0, 0,0x9E4E,0x9E4F,
+0x96D8, 0,0x96A2,0x9696,0x967B,0x8E44,0x9E51, 0,
+ 0,0x8EE9, 0, 0,0x9670, 0,0x9E53,0x9E56,
+0x9E55, 0,0x8AF7, 0, 0,0x8B80, 0,0x9E52,
+ 0,0x9E54, 0, 0, 0, 0,0x9E57, 0,
+ 0,0x9099, 0, 0, 0, 0,0x979B,0x88C7,
+0x8DDE,0x91BA, 0,0x8EDB, 0, 0,0x8FF1, 0,
+ 0,0x9E5A, 0, 0,0x936D, 0,0x9E58,0x91A9,
+0x9E59,0x8FF0,0x96DB,0x9E5B,0x9E5C,0x9788,0xFAE1, 0,
+ 0, 0,0x9E61, 0, 0,0x8D59, 0,0x9474,
+0x9E5E,0x938C,0x9DDC,0x9DE0, 0,0x8B6E, 0,0x9466,
+ 0, 0, 0, 0,0x9E60, 0,0x8FBC,0x94C2,
+ 0, 0, 0, 0, 0,0x9E66, 0,0x94F8,
+ 0,0x9E5D, 0,0x9E63,0x9E62, 0, 0, 0,
+0x90CD, 0, 0, 0, 0,0x968D, 0,0x97D1,
+ 0, 0,0x9687, 0,0x89CA,0x8E7D, 0, 0,
+0x9867,0x9E65,0x9095, 0, 0, 0,0x9E64, 0,
+ 0,0x9E5F, 0, 0, 0, 0, 0,0x8CCD,
+ 0, 0, 0,0x9E6B,0x9E69, 0,0x89CB,0x9E67,
+0x9E6D,0x9E73, 0,0xFAE2, 0, 0, 0, 0,
+0xFAE4,0x91C6, 0, 0,0x95BF, 0,0x9E75, 0,
+ 0, 0,0x9541, 0, 0, 0,0x9E74,0x9490,
+0x965E,0x8AB9, 0,0x90F5,0x8F5F, 0, 0, 0,
+0x92D1, 0,0x974D, 0, 0,0x9E70,0x9E6F, 0,
+ 0, 0,0x9E71, 0,0x9E6E, 0, 0,0x9E76,
+ 0,0x9E6C, 0, 0,0x9E6A, 0,0x9E72,0x9E68,
+ 0,0x928C, 0,0x96F6,0x8EC4,0x8DF2, 0, 0,
+ 0, 0, 0,0x8DB8, 0, 0,0x968F,0x8A60,
+ 0,0xFAE5,0x92CC,0x93C8,0x8968, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x90F0, 0, 0,0x90B2,0x8C49,
+ 0, 0, 0, 0, 0, 0,0x9E78, 0,
+ 0,0x8D5A,0x8A9C, 0, 0, 0, 0, 0,
+ 0,0x9E7A,0x8A94,0x9E81, 0, 0, 0, 0,
+ 0, 0,0x9E7D, 0,0x90F1, 0, 0, 0,
+0x8A6A,0x8DAA, 0, 0,0x8A69,0x8DCD, 0, 0,
+0x9E7B,0x8C85,0x8C6A,0x938D,0xFAE6, 0,0x9E79, 0,
+0x88C4, 0, 0, 0, 0,0x9E7C,0x9E7E, 0,
+0x8BCB,0x8C4B,0xFAE3,0x8ABA,0x8B6A, 0, 0, 0,
+ 0,0x9E82, 0, 0,0x8DF7,0x9691, 0,0x8E56,
+ 0, 0, 0,0x9E83, 0, 0, 0,0x954F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9E8F, 0,0x89B1,0x9E84,
+ 0, 0, 0, 0, 0, 0,0x9E95,0x9E85,
+ 0,0x97C0, 0,0x9E8C, 0,0x947E, 0, 0,
+ 0, 0, 0, 0, 0,0x9E94, 0,0x9E87,
+ 0, 0, 0,0x88B2,0x9E89, 0, 0,0x8D5B,
+ 0, 0, 0,0x9E8B, 0,0x9E8A, 0,0x9E86,
+0x9E91, 0,0x8FBD, 0, 0, 0,0x9AEB,0x8CE6,
+0x979C, 0, 0, 0, 0,0x9E88, 0,0x92F2,
+0x8A42,0x8DAB, 0,0x9E80, 0,0x9E90,0x8A81, 0,
+ 0,0x9E8E,0x9E92, 0,0x938E, 0, 0, 0,
+ 0, 0, 0, 0,0x8AFC, 0,0x9EB0, 0,
+0xFA64,0x96C7,0x9E97,0x8AFB, 0,0x9E9E, 0,0xFAE7,
+ 0, 0,0x965F, 0,0x9E9F,0x9EA1, 0,0x9EA5,
+0x9E99, 0,0x9249, 0, 0, 0, 0,0x938F,
+0x9EA9,0x9E9C, 0,0x9EA6, 0, 0, 0,0x9EA0,
+ 0, 0, 0, 0, 0, 0,0x9058,0x9EAA,
+ 0, 0,0x90B1, 0, 0, 0, 0, 0,
+ 0,0x9EA8,0x8ABB, 0, 0, 0, 0, 0,
+0x986F,0x9E96, 0, 0,0x9EA4,0x88D6, 0, 0,
+0x9E98, 0, 0,0x96B8,0x9E9D,0x9041,0x92C5,0x9E93,
+ 0, 0,0x9EA3, 0, 0, 0, 0, 0,
+ 0,0x909A,0x9EAD,0x8A91,0x8C9F, 0, 0, 0,
+ 0,0x9EAF,0x9E9A,0x9EAE, 0,0x9EA7,0x9E9B, 0,
+0x9EAB, 0,0x9EAC, 0, 0, 0, 0, 0,
+0x9EBD, 0, 0, 0,0x93CC, 0,0x9EA2, 0,
+ 0,0x9EB9, 0, 0, 0,0x9EBB, 0,0x92D6,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x976B, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x9596,0x9EB6,0x91C8, 0, 0,
+ 0,0x9EBC,0x915E, 0,0x9EB3,0x9EC0,0x9EBF, 0,
+0x93ED,0x9EBE,0x93E8, 0, 0, 0, 0, 0,
+0xFAE9, 0,0x9EC2,0x9EB5, 0,0x8BC6,0x9EB8,0x8F7C,
+ 0, 0, 0,0x9480,0x9EBA,0x8BC9, 0,0x9EB2,
+0x9EB4,0x9EB1, 0, 0,0x984F,0x8A79,0x9EB7, 0,
+ 0,0x9EC1,0x8A54, 0, 0, 0, 0, 0,
+ 0, 0,0x8DE5, 0, 0, 0,0x897C, 0,
+ 0,0x9ED2, 0, 0,0x9850,0x9ED5, 0, 0,
+0xFAEB, 0, 0,0x9059,0x9ED4, 0, 0, 0,
+0x9ED3, 0, 0, 0, 0, 0, 0,0x9ED0,
+ 0, 0, 0, 0, 0, 0,0x9EC4, 0,
+ 0,0x9EE1,0x9EC3, 0,0x9ED6, 0, 0, 0,
+ 0, 0, 0,0x9ECE, 0, 0,0x9EC9,0x9EC6,
+ 0,0x9EC7, 0,0x9ECF, 0, 0, 0,0xEAA0,
+ 0, 0,0x9ECC,0x8D5C,0x92C6,0x9184,0x9ECA, 0,
+0x9EC5, 0, 0,0x9EC8, 0, 0, 0, 0,
+0x976C,0x968A, 0, 0, 0,0x9ECD,0x9ED7, 0,
+ 0, 0,0xFAEC, 0, 0, 0, 0,0x9EDF,
+0x9ED8, 0, 0,0x9EE5, 0,0x9EE3, 0, 0,
+ 0, 0,0x9EDE, 0, 0, 0, 0, 0,
+ 0,0x9EDD, 0,0x92CE, 0,0x9185, 0,0x9EDB,
+ 0, 0,0x9ED9, 0, 0,0x9EE0, 0, 0,
+ 0, 0,0x9EE6,0x94F3,0x9EEC, 0, 0, 0,
+ 0, 0,0x9EE7,0x9EEA,0x9EE4, 0, 0,0x9294,
+ 0,0x9557, 0,0x9EDA, 0, 0,0x9EE2,0x8FBE,
+ 0,0x96CD,0x9EF6,0x9EE9, 0, 0, 0, 0,
+ 0,0x8CA0,0x89A1,0x8A7E, 0, 0,0x9ED1, 0,
+0xFAED, 0, 0, 0, 0,0x8FBF,0x9EEE, 0,
+0x9EF5,0x8EF7,0x8A92, 0, 0,0x924D, 0, 0,
+ 0, 0, 0, 0,0x9EEB, 0,0xFAEF,0x9EF0,
+0x9EF4, 0, 0,0x8BB4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8B6B,0x9EF2, 0, 0, 0, 0, 0,0x8B40,
+ 0,0x93C9,0x9EF1, 0, 0, 0,0x9EF3, 0,
+ 0, 0, 0,0xFAEE, 0, 0, 0, 0,
+ 0, 0,0x9EED,0xFAF0, 0, 0, 0, 0,
+0x9EEF, 0, 0, 0, 0, 0,0xFAF1,0x8A80,
+0x9268, 0, 0, 0,0x9EFA, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x9EF8,0x8CE7, 0,
+0x9EF7, 0, 0, 0, 0, 0, 0,0x9F40,
+ 0, 0, 0, 0,0x9E77, 0, 0, 0,
+0x9EF9, 0,0x9EFB,0x9EFC, 0, 0, 0, 0,
+ 0, 0,0x9F4B, 0,0x9F47, 0,0x9E8D, 0,
+ 0, 0, 0,0x9F46, 0, 0, 0, 0,
+0x9F45, 0, 0,0x9F42, 0, 0, 0, 0,
+ 0,0x9EE8,0x9F44,0x9F43, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9F49, 0,0x9845, 0, 0, 0, 0,
+ 0, 0,0x9F4C,0x8BF9, 0, 0,0x9F48,0x9F4A,
+ 0, 0,0xFAF2, 0,0xFAF3, 0, 0, 0,
+0x94A5, 0,0x9F4D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x9F51,0x9F4E, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9793,0x9F4F, 0, 0,
+ 0, 0,0x9EDC, 0, 0, 0, 0, 0,
+ 0, 0,0x9F52, 0, 0, 0,0x9F53, 0,
+ 0, 0, 0, 0, 0,0x8954, 0,0x9F55,
+0x8C87,0x8E9F, 0,0x8BD3, 0, 0, 0,0x89A2,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x977E, 0, 0, 0, 0,0x9F57,
+0x9F56,0x9F59,0x8B5C, 0, 0,0x8BD4,0x8ABC, 0,
+ 0, 0, 0,0x9F5C, 0, 0, 0,0x9F5B,
+ 0,0x9F5D, 0, 0,0x89CC, 0,0x9256, 0,
+0x9F5E, 0, 0,0x8ABD,0x9F60, 0, 0, 0,
+ 0,0x9F5F, 0,0x9F61, 0, 0, 0,0x9F62,
+ 0,0x9F63,0x8E7E,0x90B3,0x8D9F, 0,0x9590, 0,
+ 0,0x95E0,0x9863, 0, 0, 0, 0,0x8E95,
+ 0, 0, 0,0x8DCE,0x97F0, 0, 0, 0,
+0x9F64,0x9F65, 0,0x8E80, 0, 0, 0,0x9F66,
+0x9F67, 0, 0,0x9F69,0x9F68, 0,0x9677, 0,
+ 0,0x8F7D,0x8EEA,0x8E63, 0,0x9F6A, 0, 0,
+ 0, 0, 0, 0, 0,0x9F6C,0x9042, 0,
+0x9F6B, 0, 0, 0, 0, 0,0x9F6D, 0,
+ 0, 0, 0, 0,0x9F6E, 0, 0, 0,
+ 0, 0,0x9F6F,0x9F70, 0, 0, 0,0x9F71,
+ 0,0x9F73,0x9F72,0x9F74,0x89A3,0x9269, 0,0x9F75,
+ 0, 0,0x8E45,0x8A6B,0x9F76, 0, 0,0x9361,
+0x9ACA, 0, 0, 0, 0,0x8B42,0x9F77, 0,
+ 0, 0, 0,0x9F78, 0,0x95EA,0x9688, 0,
+ 0, 0,0x93C5,0x9F79,0x94E4, 0,0xFAF4, 0,
+0x94F9, 0, 0,0x96D1, 0, 0, 0,0x9F7A,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x9F7C,0x9F7B, 0, 0,0x9F7E,
+ 0, 0, 0,0x9F7D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9F81, 0, 0, 0, 0, 0, 0,0x8E81,
+ 0,0x96AF, 0,0x9F82,0x9F83, 0, 0,0x8B43,
+ 0, 0, 0,0x9F84, 0, 0, 0, 0,
+ 0, 0, 0,0x9F86,0x9F85, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9085, 0, 0,0x9558,
+0x8969, 0, 0, 0, 0, 0,0x94C3,0xFAF5,
+0x92F3,0x8F60,0x8B81, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x94C4, 0,
+0x8EAC, 0, 0, 0, 0,0x9F88, 0,0x8ABE,
+ 0, 0,0x8998, 0,0xFAF6,0x93F0,0x9F87,0x8D5D,
+0x9272, 0,0x9F89, 0, 0, 0, 0, 0,
+0x9F91, 0,0x9F8A, 0, 0, 0, 0,0xFAF8,
+0x91BF, 0,0x8B82,0x9F92, 0, 0, 0, 0,
+ 0, 0,0x8C88, 0, 0,0x8B44,0x9F90, 0,
+ 0,0x9F8E,0x9F8B,0x9780, 0, 0,0xFAF7, 0,
+0x92BE, 0, 0, 0,0x93D7,0x9F8C, 0, 0,
+0x9F94, 0,0x9F93,0x8C42, 0, 0,0x89AB, 0,
+ 0,0x8DB9,0x9F8D,0x9F8F, 0, 0, 0, 0,
+ 0,0x9676,0x91F2, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x9697, 0, 0,0x9F9C, 0,
+ 0,0x9F9D, 0,0x89CD, 0, 0, 0, 0,
+0x95A6,0x96FB,0x9F9F,0x8EA1,0x8FC0,0x9F98,0x9F9E,0x8988,
+ 0,0x8BB5, 0, 0,0x9F95,0x9F9A, 0, 0,
+ 0,0x90F2,0x9491, 0,0x94E5, 0, 0, 0,
+ 0, 0, 0,0x9F97, 0,0x9640, 0,0x9F99,
+ 0,0x9FA2,0xFAF9,0x9FA0, 0,0x9F9B, 0, 0,
+ 0,0x9641,0x9467,0x8B83, 0,0x9344, 0, 0,
+0x928D, 0,0x9FA3, 0, 0, 0, 0,0x9FA1,
+0x91D7,0x9F96, 0,0x896A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xFAFA, 0, 0, 0,
+ 0, 0, 0,0x976D,0x9FAE, 0, 0, 0,
+ 0, 0,0x9FAD, 0, 0, 0, 0,0x90F4,
+ 0,0x9FAA, 0,0x978C, 0, 0,0x93B4,0x9FA4,
+ 0, 0, 0, 0, 0,0x92C3, 0, 0,
+ 0,0x896B,0x8D5E,0x9FA7, 0, 0, 0, 0,
+ 0, 0,0x8F46,0x9FAC, 0,0x9FAB,0x9FA6, 0,
+0x9FA9, 0, 0,0x8A88, 0,0x9FA8,0x9468, 0,
+ 0,0x97AC, 0, 0,0x8FF2,0x90F3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9FB4,0x9FB2, 0,0x956C, 0, 0, 0,
+ 0, 0, 0,0x9FAF,0x9FB1, 0,0x8959, 0,
+ 0,0x8D5F,0x9851, 0,0x8A5C, 0,0x9582,0xFAFC,
+ 0, 0, 0, 0,0x9781, 0, 0,0x8A43,
+0x905A,0x9FB3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x9FB8, 0,0xFAFB,
+0x8FC1, 0, 0, 0,0x974F, 0,0x9FB5, 0,
+ 0, 0, 0,0x9FB0, 0,0x9FB6,0xFB40, 0,
+ 0,0x97DC, 0,0x9393,0x93C0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xFB41, 0, 0,0x8A55,
+ 0, 0,0x8974, 0, 0,0x9FBC, 0, 0,
+0x9FBF, 0, 0, 0,0x97C1, 0, 0, 0,
+0x9784, 0, 0, 0, 0,0x9FC6,0x9FC0,0x9FBD,
+ 0, 0, 0,0x97D2,0x9FC3, 0, 0,0xFB42,
+ 0,0x8F69,0x9FC5, 0, 0,0x9FCA, 0, 0,
+0x9391,0x9FC8, 0, 0, 0, 0,0x9FC2, 0,
+ 0,0x9257, 0, 0,0x9FC9, 0,0x9FBE, 0,
+0x9FC4, 0,0x9FCB,0x88FA,0x9FC1, 0,0x9FCC, 0,
+ 0,0x905B,0xFB44,0x8F7E, 0,0x95A3, 0,0x8DAC,
+0xFB43,0x9FB9,0x9FC7,0x9359,0xFB45, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x90B4, 0,0x8A89,
+0x8DCF,0x8FC2,0x9FBB,0x8F61, 0, 0, 0, 0,
+ 0, 0, 0,0x8C6B, 0,0x9FBA, 0, 0,
+ 0,0x9FD0,0x8F8D,0x8CB8, 0,0x9FDF, 0,0x9FD9,
+0x8B94,0x936E, 0,0x9FD4,0x9FDD,0x88AD,0x8951,0xFB48,
+ 0,0x89B7, 0,0x9FD6,0x91AA,0x9FCD,0x9FCF,0x8D60,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9FE0,0xFB46,0x9FDB, 0,0xFB49, 0,0x9FD3, 0,
+ 0, 0, 0,0x9FDA, 0, 0, 0, 0,
+ 0, 0,0x96A9, 0, 0,0x9FD8,0x9FDC, 0,
+ 0, 0, 0, 0, 0, 0,0x8CCE, 0,
+0x8FC3, 0, 0,0x9258,0xFB47, 0, 0,0x9FD2,
+ 0, 0, 0, 0, 0, 0, 0,0x974E,
+ 0, 0, 0,0x9FD5, 0, 0,0x9FCE,0x9392,
+ 0, 0,0x9FD1, 0, 0, 0,0x9FD7, 0,
+ 0, 0, 0, 0, 0, 0,0x9870,0x8EBC,
+0x969E, 0,0x9FE1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x94AC, 0, 0,0x9FED,
+0x8CB9, 0, 0, 0, 0, 0,0x8F80, 0,
+0x9FE3, 0, 0, 0,0x97AD,0x8D61, 0,0x9FF0,
+ 0, 0,0x88EC, 0, 0,0x9FEE, 0, 0,
+ 0, 0,0x9FE2, 0, 0, 0, 0,0x9FE8,
+ 0, 0,0x9FEA, 0, 0, 0,0x976E,0x9FE5,
+ 0, 0,0x934D, 0, 0,0x9FE7, 0,0xFB4A,
+ 0, 0,0x9FEF, 0,0x9FE9,0x96C5, 0, 0,
+ 0,0x9FE4, 0,0x8EA0,0x9FFC, 0, 0, 0,
+ 0,0x8A8A, 0,0x9FE6,0x9FEB,0x9FEC, 0, 0,
+ 0, 0, 0, 0, 0,0x91EA,0x91D8, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9FF4, 0, 0,0x9FFA,
+ 0, 0,0x9FF8, 0,0x9348, 0, 0,0xE042,
+0x9FF5, 0, 0, 0, 0, 0,0x9FF6,0x9FDE,
+ 0,0x8B99,0x9559, 0, 0, 0,0x8EBD, 0,
+ 0,0x8D97, 0, 0, 0, 0, 0,0x9852,
+ 0,0x9FF2, 0,0xE041,0x8989,0x9186, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9499, 0,0x8ABF,0x97F8, 0, 0, 0, 0,
+ 0, 0, 0,0x969F,0x92D0, 0, 0, 0,
+ 0,0x9FF9,0x9FFB, 0, 0, 0, 0, 0,
+0x9151, 0, 0, 0, 0, 0,0xE040,0x9FF7,
+ 0,0x9FF1, 0, 0, 0,0x8AC1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8C89, 0, 0, 0,
+0xE04E, 0, 0,0xE049,0x90F6, 0, 0,0x8A83,
+ 0, 0, 0, 0,0x8F81, 0,0xE052, 0,
+ 0, 0, 0, 0, 0,0xE04B,0x92AA,0xE048,
+0x92D7, 0, 0, 0,0xE06B, 0, 0, 0,
+0xE045, 0,0xE044, 0,0xE04D, 0, 0, 0,
+0xE047,0xE046,0xE04C, 0,0x909F, 0,0xE043, 0,
+0xFB4B, 0, 0, 0, 0, 0,0xE04F, 0,
+ 0,0xE050, 0, 0, 0, 0, 0,0x8AC0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE055, 0,0xE054,0xE056, 0, 0, 0,
+ 0, 0,0xE059, 0, 0, 0, 0, 0,
+ 0,0x9362, 0,0xE053, 0,0xFB4C, 0, 0,
+ 0,0xE057, 0, 0, 0, 0, 0, 0,
+0x8C83,0x91F7,0xE051,0x945A, 0, 0,0xE058, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE05D,0xE05B, 0, 0,
+0xE05E, 0, 0,0xE061, 0, 0, 0,0xE05A,
+0x8D8A,0x9447, 0, 0,0x9FB7, 0, 0, 0,
+ 0, 0, 0,0x9794,0xE05C, 0,0xE060,0x91F3,
+ 0,0xE05F, 0,0xE04A, 0,0xFB4D,0xE889, 0,
+ 0, 0,0xE064, 0, 0, 0,0xE068, 0,
+ 0,0xE066, 0, 0, 0,0xFB4E, 0,0xFB4F,
+ 0,0xE062, 0,0xE063, 0, 0, 0,0xE067,
+ 0,0xE065, 0, 0, 0,0x956D, 0, 0,
+0xE06D, 0,0xE06A,0xE069, 0,0xE06C,0x93D2,0xE06E,
+ 0, 0, 0, 0, 0, 0,0x9295,0x91EB,
+0xFB50, 0, 0, 0,0x90A3, 0, 0, 0,
+0xE06F, 0,0xE071, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE070, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9FF3, 0, 0, 0,
+ 0,0xE072, 0, 0, 0, 0, 0, 0,
+0x93E5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE073, 0, 0, 0, 0,
+ 0, 0, 0,0x89CE, 0, 0, 0,0x9394,
+0x8A44, 0, 0, 0, 0, 0, 0, 0,
+0x8B84, 0, 0, 0,0x8EDC,0x8DD0, 0, 0,
+ 0, 0, 0, 0, 0,0xFB51, 0, 0,
+ 0,0x9846,0x9086, 0, 0, 0,0x898A, 0,
+ 0, 0,0xE075, 0, 0, 0, 0, 0,
+ 0,0xE074, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xFB52,0xE078,0x9259,0xE07B,0xE076,
+ 0, 0, 0,0xE07A, 0, 0, 0, 0,
+0xE079,0x935F,0x88D7,0xFA62, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x97F3, 0, 0,0xE07D, 0, 0, 0,0x8947,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE080, 0, 0, 0,0xE07E, 0,0xE07C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE077, 0, 0, 0, 0, 0, 0,
+ 0,0x9642, 0, 0, 0,0xE082, 0, 0,
+ 0, 0, 0, 0,0xFB54, 0, 0, 0,
+ 0,0xE081, 0, 0, 0, 0, 0,0xFB53,
+ 0, 0, 0, 0,0x898B, 0, 0, 0,
+ 0,0xE084,0x95B0, 0,0xE083, 0, 0, 0,
+ 0,0x96B3, 0, 0, 0, 0,0x8FC5, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x9152, 0,
+ 0, 0, 0, 0,0x8FC4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xFB56,0xFB57,
+ 0,0x97F9, 0, 0,0xE08A, 0,0x90F7, 0,
+ 0, 0, 0, 0, 0,0xE086,0xE08B, 0,
+ 0,0x898C, 0, 0,0xFB55, 0, 0, 0,
+ 0, 0,0xE089, 0,0x9481,0xE085,0xE088,0x8FC6,
+ 0,0x94CF, 0, 0,0xE08C, 0,0x8ECF, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x90F8, 0, 0,
+ 0, 0, 0, 0,0xE08F, 0, 0, 0,
+0xE087, 0,0x8C46, 0, 0, 0, 0,0xE08D,
+ 0, 0, 0, 0,0x976F,0xE090, 0, 0,
+ 0,0xEAA4, 0, 0, 0, 0, 0,0x8F6E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE091, 0, 0, 0,0xE092, 0, 0, 0,
+ 0,0x944D, 0, 0, 0, 0, 0, 0,
+ 0,0xE094, 0, 0, 0, 0,0xE095, 0,
+ 0,0xFB59, 0,0x9452, 0, 0, 0, 0,
+0x9395,0xE097, 0, 0, 0, 0,0xE099, 0,
+0x97D3, 0,0xE096, 0,0xE098,0x898D, 0,0xE093,
+ 0, 0, 0, 0, 0, 0, 0,0x9A7A,
+0xE09A, 0, 0, 0, 0,0x9187,0x8E57,0xE09C,
+ 0, 0, 0, 0,0xE09B,0x9043,0x99D7, 0,
+ 0, 0, 0, 0, 0,0xE09D, 0, 0,
+ 0,0xE09F, 0,0xE08E,0xE09E, 0,0xFB5A,0xE0A0,
+ 0, 0, 0, 0, 0, 0,0x949A, 0,
+ 0, 0, 0, 0, 0,0xE0A1, 0, 0,
+0xE0A2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE0A3, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE0A4, 0,0x92DC, 0,0xE0A6,0xE0A5, 0, 0,
+0xE0A7, 0,0xE0A8, 0, 0,0x8EDD,0x9583, 0,
+ 0, 0,0x96EA,0xE0A9,0xE0AA,0x9175,0x8EA2,0xE0AB,
+0xE0AC, 0, 0, 0, 0, 0,0xE0AD,0x95D0,
+0x94C5, 0, 0,0xE0AE,0x9476, 0, 0, 0,
+ 0, 0,0x92AB, 0, 0, 0, 0, 0,
+0xE0AF,0x89E5, 0,0x8B8D, 0,0x96C4, 0,0x96B4,
+ 0,0x89B2,0x9853, 0, 0, 0, 0,0x9671,
+ 0,0x95A8, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x90B5, 0,0xE0B0, 0, 0, 0,
+ 0,0x93C1, 0, 0, 0,0x8CA1,0xE0B1, 0,
+0x8DD2,0xE0B3,0xE0B2, 0, 0, 0, 0,0xE0B4,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE0B5, 0, 0, 0,0xE0B6, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8B5D, 0,0xE0B7, 0, 0, 0, 0,0xE0B8,
+ 0, 0, 0, 0,0x8CA2, 0, 0,0x94C6,
+ 0,0xFB5B,0xE0BA, 0, 0, 0,0x8FF3, 0,
+ 0,0xE0B9, 0, 0, 0, 0,0xFB5C, 0,
+ 0, 0,0x8BB6,0xE0BB,0xE0BD, 0,0xE0BC, 0,
+ 0, 0, 0, 0, 0, 0,0xE0BE, 0,
+0x8CCF, 0,0xE0BF, 0, 0, 0, 0,0x8BE7,
+ 0,0x915F, 0,0x8D9D, 0, 0, 0, 0,
+0xE0C1,0xE0C2,0xE0C0, 0, 0, 0, 0, 0,
+ 0,0x8EEB, 0, 0,0x93C6,0x8BB7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE0C4,
+0x924B,0xE0C3, 0, 0,0x9854,0x9482, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE0C7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE0C9,0xE0C6,
+ 0, 0, 0,0x96D2,0xE0C8,0xE0CA, 0,0x97C2,
+ 0, 0, 0, 0,0xFB5D,0xE0CE, 0, 0,
+ 0,0xE0CD,0x9296,0x944C, 0, 0,0x8CA3,0xE0CC,
+ 0, 0, 0, 0,0xE0CB, 0,0x9750,0x9751,
+ 0, 0, 0, 0, 0, 0,0xE0CF,0x898E,
+ 0, 0, 0, 0,0x8D96,0x8E82, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE0D0,0xE0D1,
+ 0, 0, 0, 0, 0, 0, 0,0xE0D3,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8F62, 0, 0, 0, 0,
+0xE0D5, 0,0xE0D4, 0, 0, 0, 0, 0,
+0xE0D6, 0,0x8A6C, 0, 0,0xE0D8, 0,0xFB5F,
+0xE0D7, 0,0xE0DA,0xE0D9, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8CBA, 0, 0,0x97A6,
+ 0,0x8BCA, 0,0x89A4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8BE8, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x8ADF, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x97E6,0xE0DC, 0, 0, 0, 0,
+ 0, 0, 0,0xE0DE, 0,0xFB60, 0, 0,
+0xE0DF, 0,0x89CF, 0, 0, 0, 0, 0,
+0xE0DB,0xFB61,0x8E58, 0, 0,0x92BF,0xE0DD, 0,
+ 0, 0,0xFB64, 0, 0, 0,0xFB62, 0,
+ 0, 0, 0, 0, 0, 0,0xE0E2, 0,
+0x8EEC, 0, 0,0xFB63, 0,0xE0E0, 0, 0,
+ 0, 0,0x8C5D, 0, 0,0x94C7,0xE0E1, 0,
+ 0,0xE0FC, 0, 0, 0,0xFB66, 0, 0,
+0xE0E7, 0, 0, 0, 0, 0,0x8CBB, 0,
+ 0, 0, 0,0x8B85, 0,0xE0E4,0x979D,0xFB65,
+ 0,0x97AE, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x91F4, 0, 0,0xE0E6,0xFB67, 0,
+ 0,0xFB69,0xFB68, 0, 0, 0,0xFB6A, 0,
+ 0, 0,0xE0E8,0x97D4,0x8BD5,0x94FA,0x9469, 0,
+ 0, 0,0xE0E9, 0, 0, 0, 0,0xE0EB,
+ 0,0xE0EE, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE0EA, 0, 0,
+ 0,0xE0ED,0x8CE8,0x896C,0xE0EF, 0,0x9090,0xE0EC,
+0x97DA, 0,0xFB6B,0xE0F2,0xEAA2, 0, 0, 0,
+ 0,0xE0F0,0xE0F3, 0, 0, 0, 0,0xE0E5,
+0xE0F1, 0, 0,0x8DBA, 0, 0,0xE0F4, 0,
+ 0, 0, 0, 0, 0, 0,0xE0F5, 0,
+ 0, 0, 0,0x979E, 0, 0, 0, 0,
+ 0,0xFB6C, 0,0xE0F6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE0F7,0xFB6D,
+ 0, 0,0xE0E3, 0, 0, 0, 0,0xE0F8,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8AC2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x8EA3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE0F9, 0, 0, 0, 0,0xE0FA,
+ 0, 0, 0, 0,0xE0FB, 0, 0, 0,
+ 0, 0, 0, 0,0x895A, 0, 0, 0,
+0xE140, 0,0x955A,0xE141, 0, 0,0x8AA2,0xE142,
+ 0,0xE143, 0, 0, 0, 0,0xE144, 0,
+0xE146,0xE147,0xE145, 0, 0, 0,0x9572,0xE149,
+0xE148, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xFB6E, 0,0xE14B,0xE14A,0xE14C, 0, 0,
+ 0, 0, 0, 0,0xE14D,0xE14F,0xE14E, 0,
+ 0,0x8D99, 0,0xE151, 0,0xE150, 0, 0,
+0x8AC3, 0,0x9072, 0,0x935B, 0,0xE152,0x90B6,
+ 0, 0, 0,0x8E59, 0,0x8999,0xE153, 0,
+0x9770, 0, 0,0x95E1,0xE154, 0, 0,0xFAA8,
+0x9363,0x9752,0x8D62,0x905C, 0, 0, 0,0x926A,
+0x99B2, 0,0x92AC,0x89E6,0xE155, 0, 0, 0,
+ 0, 0, 0, 0,0xE156, 0,0xE15B, 0,
+ 0,0xE159,0xE158,0x9DC0,0x8A45,0xE157, 0,0x88D8,
+ 0,0x94A8, 0, 0,0x94C8, 0, 0, 0,
+ 0,0x97AF,0xE15C,0xE15A,0x927B,0x90A4, 0, 0,
+0x94A9, 0,0x954C, 0,0xE15E,0x97AA,0x8C6C,0xE15F,
+ 0,0xE15D,0x94D4,0xE160, 0,0xE161, 0,0xFB6F,
+0x88D9, 0, 0,0x8FF4,0xE166, 0,0xE163,0x93EB,
+0xE162, 0, 0, 0, 0, 0, 0,0x8B45,
+ 0, 0,0xE169, 0, 0, 0,0xE164,0xE165,
+ 0,0xE168,0xE167,0x9544, 0, 0,0x9161,0x9160,
+ 0,0x8B5E, 0, 0,0xE16A, 0, 0, 0,
+ 0, 0,0xE16B, 0, 0,0xE16C, 0, 0,
+ 0, 0, 0,0xE16E, 0,0xE16D, 0, 0,
+ 0, 0, 0,0x8975, 0, 0, 0, 0,
+ 0,0xE176,0x94E6,0xE170, 0,0xE172, 0, 0,
+0xE174,0x905D, 0, 0,0xE175,0xE173,0x8EBE, 0,
+ 0, 0,0xE16F,0xE171, 0,0x9561, 0,0x8FC7,
+ 0, 0,0xE178, 0, 0,0xE177, 0, 0,
+ 0, 0,0xE179, 0,0x8EA4,0x8DAD, 0, 0,
+0x9397,0xE17A, 0,0x92C9, 0, 0,0xE17C, 0,
+ 0, 0,0x979F,0xE17B, 0, 0, 0, 0,
+ 0,0x9189, 0, 0, 0, 0, 0, 0,
+0xE182, 0,0xE184,0xE185,0x9273, 0, 0, 0,
+ 0, 0,0xE183, 0,0xE180, 0,0xE17D,0xE17E,
+ 0,0xE181, 0, 0, 0, 0, 0, 0,
+ 0,0xE188, 0,0xE186, 0,0xE187, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE189,
+0xE18B,0xE18C,0xE18D, 0,0xE18E, 0, 0,0xE18A,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE190, 0, 0, 0,0xE18F, 0, 0, 0,
+ 0, 0, 0,0xE191, 0, 0, 0, 0,
+ 0, 0,0x97C3, 0, 0, 0,0xE194,0xE192,
+0xE193, 0, 0, 0,0x8AE0, 0, 0, 0,
+ 0, 0,0x96FC, 0, 0, 0,0x95C8, 0,
+0xE196, 0, 0, 0,0xE195, 0, 0, 0,
+ 0,0xE197,0xE198, 0, 0, 0, 0,0xE19C,
+0xE199,0xE19A,0xE19B, 0,0xE19D, 0, 0, 0,
+0xE19E, 0,0xE19F, 0, 0, 0,0xE1A0, 0,
+0xE1A1, 0,0x94AD,0x936F,0xE1A2,0x9492,0x9553, 0,
+0xE1A3, 0,0xFB70,0xE1A4,0x9349, 0,0x8A46,0x8D63,
+0xE1A5, 0, 0,0xE1A6, 0, 0,0xE1A7, 0,
+0x8E48, 0, 0,0xE1A9, 0, 0,0xE1A8, 0,
+ 0,0xE1AA,0xE1AB,0xFB73,0xFB71, 0,0xFB72, 0,
+ 0, 0, 0, 0, 0, 0,0xFB74, 0,
+ 0, 0, 0, 0, 0, 0,0x94E7, 0,
+0xE1AC, 0, 0, 0,0xE1AD, 0, 0,0xEA89,
+0xE1AE,0xE1AF,0xE1B0, 0, 0, 0, 0,0x8E4D,
+ 0, 0,0xE1B1,0x9475, 0, 0,0x967E, 0,
+0x896D, 0,0x8976, 0, 0,0xE1B2, 0, 0,
+ 0, 0,0xE1B4, 0, 0, 0,0xE1B3,0x9390,
+ 0, 0, 0,0x90B7,0x9F58, 0,0xE1B5,0x96BF,
+ 0,0xE1B6, 0,0x8AC4,0x94D5,0xE1B7, 0,0xE1B8,
+ 0, 0,0xE1B9, 0, 0, 0,0x96DA, 0,
+ 0, 0,0x96D3, 0,0x92BC, 0, 0, 0,
+0x918A, 0, 0,0xE1BB, 0, 0,0x8F82, 0,
+ 0,0x8FC8, 0, 0,0xE1BE, 0, 0,0xE1BD,
+0xE1BC,0x94FB, 0,0x8AC5,0x8CA7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE1C4, 0, 0,0xE1C1,0x905E,
+0x96B0, 0, 0, 0,0xE1C0,0xE1C2,0xE1C3, 0,
+ 0,0xE1BF, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE1C5,
+0xE1C6, 0,0x92AD, 0,0x8AE1, 0, 0, 0,
+0x9285, 0, 0, 0, 0, 0,0xFB76,0xE1C7,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE1C8,0xE1CB, 0, 0, 0, 0,
+ 0,0x9087, 0,0x93C2, 0,0xE1CC,0x9672, 0,
+0xE1C9, 0, 0,0xE1CA, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE1CF, 0, 0, 0, 0,0xE1CE,0xE1CD,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE1D1, 0, 0,0xE1D0, 0,
+ 0,0xE1D2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE1D4, 0,
+0xE1D3, 0, 0, 0, 0,0x95CB, 0, 0,
+ 0, 0, 0, 0,0x8F75,0x97C4, 0, 0,
+0xE1D5, 0, 0,0x93B5, 0, 0,0xE1D6, 0,
+ 0,0xE1D7, 0,0xE1DB,0xE1D9,0xE1DA, 0,0xE1D8,
+ 0, 0, 0, 0, 0, 0, 0,0xE1DC,
+ 0, 0, 0, 0, 0,0xE1DD, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE1DE,
+ 0, 0,0xE1DF,0x96B5,0xE1E0, 0, 0, 0,
+ 0, 0,0x96EE,0xE1E1, 0,0x926D, 0,0x948A,
+ 0,0x8BE9, 0, 0, 0,0x925A,0xE1E2,0x8BB8,
+ 0, 0, 0,0x90CE, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE1E3, 0, 0, 0,
+ 0, 0,0x8DBB, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE1E4, 0, 0, 0,
+ 0, 0,0xE1E5, 0,0x8CA4,0x8DD3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE1E7,0xFB78, 0, 0, 0,0x9375,0x8DD4,0x8B6D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x9643, 0,0x946A, 0, 0, 0,
+ 0, 0,0x9376, 0, 0, 0, 0,0x8D7B,
+ 0, 0, 0, 0, 0,0xE1E9, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xFB79, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x8FC9, 0, 0,
+ 0, 0, 0, 0,0xFB7A, 0, 0, 0,
+ 0, 0, 0,0x97B0,0x8D64, 0, 0,0x8CA5,
+ 0, 0,0x94A1, 0,0xE1EB, 0, 0, 0,
+ 0, 0,0xFB7B, 0,0xE1ED, 0, 0, 0,
+ 0,0x8CE9, 0, 0, 0, 0,0xE1EC,0x92F4,
+ 0, 0, 0, 0,0xE1EF,0x8A56,0xE1EA, 0,
+ 0,0x94E8, 0,0x894F, 0,0x8DEA, 0,0x9871,
+ 0, 0,0xE1EE, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE1F0, 0, 0, 0,0x95C9,
+ 0,0x90D7,0xE1F2, 0, 0, 0, 0,0xE1F3,
+ 0, 0, 0, 0, 0,0xE1F1, 0, 0,
+ 0, 0,0x8A6D, 0,0xE1F9, 0,0xE1F8, 0,
+ 0,0x8EA5, 0, 0, 0,0xE1FA,0xE1F5, 0,
+ 0, 0,0xE1FB,0xE1F6, 0, 0, 0, 0,
+0x94D6,0xE1F4, 0, 0,0xE1F7, 0, 0, 0,
+ 0, 0,0xE241, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE240,
+0x9681, 0, 0, 0,0xE1FC, 0, 0,0x88E9,
+ 0, 0, 0, 0,0xE243, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE242, 0, 0,
+ 0,0x8FCA, 0, 0, 0, 0, 0,0xE244,
+ 0, 0, 0, 0, 0, 0,0x9162, 0,
+ 0,0xE246,0xE245, 0, 0, 0, 0, 0,
+ 0,0xE247, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE1E6, 0,
+ 0, 0,0xE1E8,0xE249,0xE248, 0, 0, 0,
+0xFB7C, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8EA6, 0,0x97E7, 0,0x8ED0, 0,
+0xE24A,0x8C56, 0, 0, 0, 0, 0,0x8B5F,
+0x8B46,0x8E83, 0, 0, 0, 0, 0, 0,
+0x9753, 0, 0,0xE250, 0,0xE24F,0x9163,0xE24C,
+ 0, 0,0xE24E, 0, 0,0x8F6A,0x905F,0xE24D,
+0xE24B, 0,0x9449, 0, 0,0x8FCB, 0, 0,
+0x955B, 0, 0, 0, 0,0x8DD5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x9398,
+ 0, 0,0xE251, 0, 0, 0, 0,0xE252,
+0xE268,0x8BD6, 0, 0,0x985C,0x9154, 0, 0,
+ 0, 0,0xE253, 0, 0,0x89D0,0x92F5,0x959F,
+ 0, 0, 0, 0,0xFB81, 0, 0, 0,
+ 0, 0, 0,0xFB83, 0,0xE254, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8B9A,0xE255,
+ 0, 0,0xE257, 0, 0, 0,0xE258, 0,
+0x9448, 0, 0,0xE259, 0, 0, 0, 0,
+ 0,0xE25A,0xE25B, 0, 0,0x8BD7,0x89D1,0x93C3,
+0x8F47,0x8E84, 0, 0, 0, 0, 0, 0,
+ 0,0xE25C, 0,0x8F48, 0, 0, 0, 0,
+ 0,0x89C8,0x9562, 0, 0,0xE25D, 0, 0,
+0x94E9, 0, 0, 0, 0, 0, 0,0x9164,
+ 0,0xE260, 0,0xE261,0x9489, 0,0x9060,0xE25E,
+ 0,0x9281, 0, 0,0xE25F, 0, 0, 0,
+0x8FCC, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x88DA, 0, 0, 0, 0,
+0x8B48, 0, 0, 0, 0, 0, 0, 0,
+0xE262, 0, 0,0x92F6, 0,0xE263,0x90C5, 0,
+ 0, 0, 0, 0,0x96AB, 0, 0,0x9542,
+0xE264,0xE265,0x9274, 0,0x97C5, 0, 0,0xE267,
+0xE266, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8EED, 0,
+ 0,0xE269,0x88EE, 0, 0, 0, 0,0xE26C,
+ 0, 0, 0,0xE26A,0x89D2,0x8C6D,0xE26B,0x8D65,
+0x8D92, 0,0x95E4,0xE26D, 0, 0,0x9673, 0,
+ 0,0xE26F, 0, 0, 0,0x90CF,0x896E,0x89B8,
+0x88AA, 0, 0, 0, 0, 0, 0,0xE26E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE270,0xE271,0x8FF5, 0, 0, 0, 0,
+ 0,0xE272, 0,0x8A6E, 0, 0, 0, 0,
+0xE274, 0, 0, 0,0x8C8A, 0,0x8B86, 0,
+ 0,0xE275,0x8BF3, 0, 0,0xE276, 0,0x90FA,
+ 0,0x93CB, 0,0x90DE,0x8DF3, 0, 0, 0,
+0xE277, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x9282,0x918B, 0,0xE279,0xE27B,0xE278,
+0xE27A, 0, 0, 0, 0, 0, 0,0x8C41,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE27C,0x8C45, 0, 0, 0,0x8B87,0x9771,
+0xE27E, 0, 0, 0, 0, 0,0xE280, 0,
+ 0, 0,0x894D, 0, 0, 0, 0,0xE283,
+ 0, 0, 0,0x8A96,0xE282,0xE281, 0,0xE285,
+0xE27D, 0,0xE286,0x97A7, 0,0xE287, 0,0xE288,
+ 0,0xFB84,0x9AF2,0xE28A, 0,0xE289, 0, 0,
+ 0,0xE28B,0xE28C, 0,0x97B3,0xE28D, 0,0xE8ED,
+0x8FCD,0xE28E,0xE28F,0x8F76, 0,0x93B6,0xE290,0xFB85,
+ 0, 0,0x9247,0xFB87, 0,0xE291, 0,0x925B,
+0xE292, 0, 0, 0, 0, 0,0x8BA3, 0,
+0x995E,0x927C,0x8EB1, 0, 0, 0, 0,0x8AC6,
+ 0, 0,0xE293, 0,0xE2A0, 0,0xE296, 0,
+0x8B88, 0,0xE295,0xE2A2, 0, 0, 0,0xE294,
+ 0,0x8FCE, 0, 0, 0, 0, 0, 0,
+0xE298,0xE299, 0,0x934A, 0, 0,0xE29A, 0,
+0x8A7D, 0, 0, 0, 0,0x9079,0x9584, 0,
+0xE29C, 0, 0, 0,0x91E6, 0, 0, 0,
+ 0, 0, 0,0xE297, 0,0xE29B,0xE29D, 0,
+ 0,0x8DF9, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE2A4,0x954D, 0,
+0x94A4,0x9399, 0,0x8BD8,0xE2A3,0xE2A1, 0,0x94B3,
+0xE29E,0x927D,0x939B, 0,0x939A, 0,0x8DF4, 0,
+ 0, 0, 0, 0, 0,0xE2B6, 0, 0,
+ 0, 0, 0, 0, 0,0xE2A6, 0,0xE2A8,
+ 0, 0, 0, 0,0xE2AB, 0,0xE2AC, 0,
+0xE2A9,0xE2AA, 0, 0,0xE2A7,0xE2A5, 0, 0,
+ 0, 0,0xE29F, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x95CD,0x89D3,
+ 0, 0, 0,0xE2B3, 0,0xE2B0, 0,0xE2B5,
+ 0, 0,0xE2B4, 0,0x9493,0x96A5, 0,0x8E5A,
+0xE2AE,0xE2B7,0xE2B2, 0,0xE2B1,0xE2AD,0xFB88,0xE2AF,
+ 0,0x8AC7, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x925C, 0, 0,0x90FB, 0, 0,
+ 0,0x94A0, 0, 0,0xE2BC, 0, 0, 0,
+0x94A2, 0, 0, 0, 0, 0, 0, 0,
+0x90DF,0xE2B9, 0, 0,0x94CD, 0,0xE2BD,0x95D1,
+ 0,0x927A, 0,0xE2B8,0xE2BA, 0, 0,0xE2BB,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE2BE, 0, 0,
+0x8EC2, 0, 0, 0,0x93C4,0xE2C3,0xE2C2, 0,
+ 0,0xE2BF, 0, 0, 0,0x9855, 0, 0,
+ 0, 0, 0,0xE2C8, 0, 0,0xE2CC,0xE2C9,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE2C5, 0, 0, 0, 0, 0, 0,0xE2C6,
+ 0, 0, 0, 0, 0,0xE2CB, 0, 0,
+ 0,0xE2C0,0x99D3,0xE2C7,0xE2C1, 0, 0,0xE2CA,
+ 0, 0, 0, 0, 0, 0, 0,0xE2D0,
+ 0,0x8AC8, 0,0xE2CD, 0, 0, 0,0xE2CE,
+ 0, 0,0xE2CF,0xE2D2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE2D1,
+0x94F4, 0, 0, 0, 0,0xE2D3,0x97FA,0x95EB,
+0xE2D8, 0, 0,0xE2D5, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE2D4,0x90D0, 0,0xE2D7,
+0xE2D9, 0, 0, 0,0xE2D6, 0,0xE2DD, 0,
+0xE2DA, 0, 0, 0, 0, 0, 0,0xE2DB,
+0xE2C4, 0, 0, 0,0xE2DC,0xE2DE, 0, 0,
+ 0, 0, 0, 0,0xE2DF, 0, 0, 0,
+ 0, 0, 0,0x95C4, 0,0xE2E0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x96E0, 0,
+ 0,0x8BCC,0x8C48,0xE2E1, 0, 0, 0, 0,
+ 0,0x95B2, 0,0x9088, 0,0x96AE, 0, 0,
+0xE2E2, 0,0x97B1, 0, 0,0x9494, 0,0x9165,
+0x9453, 0, 0,0x8F6C, 0, 0, 0,0x88BE,
+ 0,0xE2E7,0xE2E5, 0,0xE2E3,0x8A9F, 0,0x8FCF,
+0xE2E8, 0, 0,0xE2E6, 0,0xE2E4,0xE2EC, 0,
+ 0,0xE2EB,0xE2EA,0xE2E9, 0, 0, 0, 0,
+ 0,0xE2ED, 0, 0, 0,0xE2EE,0x90B8, 0,
+0xE2EF, 0,0xE2F1, 0, 0,0xE2F0, 0, 0,
+ 0, 0,0x8CD0, 0, 0, 0,0x9157, 0,
+ 0, 0,0xE2F3, 0, 0, 0,0x939C, 0,
+0xE2F2, 0, 0, 0,0xE2F4, 0,0x95B3,0x918C,
+0x8D66, 0,0xE2F5, 0, 0, 0, 0,0x97C6,
+ 0, 0, 0, 0, 0, 0, 0,0xE2F7,
+ 0, 0,0xE2F8, 0,0xE2F9, 0,0xE2FA, 0,
+0x8E85, 0,0xE2FB,0x8C6E, 0, 0,0x8B8A, 0,
+0x8B49, 0,0xE340, 0,0x96F1,0x8D67,0xE2FC, 0,
+ 0, 0,0xE343,0x96E4, 0,0x945B, 0, 0,
+0x9552, 0, 0, 0,0x8F83,0xE342, 0,0x8ED1,
+0x8D68,0x8E86,0x8B89,0x95B4,0xE341, 0, 0, 0,
+0x9166,0x9661,0x8DF5, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8E87,0x92DB, 0,0xE346,0x97DD,
+0x8DD7, 0,0xE347,0x9061, 0,0xE349, 0, 0,
+ 0,0x8FD0,0x8DAE, 0, 0, 0, 0,0xE348,
+ 0, 0,0x8F49,0x8CBC,0x9167,0xE344,0xE34A, 0,
+0xFB8A, 0, 0,0xE345,0x8C6F, 0,0xE34D,0xE351,
+0x8C8B, 0, 0, 0, 0, 0,0xE34C, 0,
+ 0, 0, 0,0xE355,0xFB8B, 0,0x8D69, 0,
+ 0,0x978D,0x88BA,0xE352, 0, 0,0x8B8B, 0,
+0xE34F, 0, 0, 0, 0, 0,0xE350, 0,
+ 0,0x939D,0xE34E,0xE34B, 0,0x8A47,0x90E2, 0,
+ 0,0x8CA6, 0, 0, 0,0xE357, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE354, 0, 0, 0, 0, 0,0xE356,
+ 0, 0, 0,0xE353, 0, 0, 0, 0,
+ 0,0x8C70,0x91B1,0xE358,0x918E, 0, 0,0xE365,
+0xFB8D, 0,0xE361,0xE35B, 0, 0, 0, 0,
+ 0, 0, 0,0xE35F,0x8EF8,0x88DB,0xE35A,0xE362,
+0xE366,0x8D6A,0x96D4, 0,0x92D4,0xE35C, 0,0xFB8C,
+0xE364, 0,0xE359,0x925D, 0,0xE35E,0x88BB,0x96C8,
+ 0, 0, 0, 0, 0, 0, 0,0xE35D,
+ 0, 0,0x8BD9,0x94EA, 0, 0, 0,0x918D,
+ 0,0x97CE,0x8F8F, 0, 0,0xE38E,0xFB8E, 0,
+0xE367, 0,0x90FC, 0,0xE363,0xE368,0xE36A, 0,
+0x92F7,0xE36D, 0, 0,0xE369, 0, 0, 0,
+0x95D2,0x8AC9, 0, 0,0x96C9, 0, 0,0x88DC,
+ 0, 0,0xE36C, 0,0x97FB, 0, 0, 0,
+ 0, 0, 0,0xE36B, 0, 0, 0, 0,
+ 0,0x898F, 0, 0,0x93EA,0xE36E, 0, 0,
+ 0,0xE375,0xE36F,0xE376, 0, 0, 0, 0,
+ 0, 0,0xE372, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x949B, 0, 0,0x8EC8,0xE374,
+ 0,0xE371,0xE377,0xE370, 0, 0,0x8F63, 0,
+ 0, 0, 0,0x9644, 0, 0,0x8F6B, 0,
+ 0,0xE373,0xE380, 0, 0,0xE37B, 0,0xE37E,
+ 0,0xE37C,0xE381,0xE37A, 0,0xE360,0x90D1, 0,
+ 0,0x94C9, 0,0xE37D, 0, 0,0xE378, 0,
+ 0, 0,0x9140,0x8C71, 0,0x8F4A, 0, 0,
+ 0, 0,0xFB8F, 0,0x9044,0x9155,0xE384, 0,
+ 0,0xE386,0xE387, 0, 0,0xE383,0xE385, 0,
+ 0, 0, 0, 0, 0, 0,0xE379,0xE382,
+ 0,0xE38A,0xE389, 0, 0,0x969A, 0, 0,
+0x8C4A, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE388, 0,0xE38C,0xE38B,0xE38F, 0,0xE391,
+ 0, 0,0x8E5B,0xE38D, 0, 0, 0, 0,
+0xE392,0xE393,0xFA5C, 0,0xE394, 0,0xE39A,0x935A,
+0xE396, 0,0xE395,0xE397,0xE398, 0,0xE399, 0,
+ 0, 0, 0,0xE39B,0xE39C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8ACA, 0,
+0xE39D, 0,0xE39E, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE39F, 0,0xFB90,
+ 0, 0, 0, 0,0xE3A0,0xE3A1,0xE3A2, 0,
+0xE3A3,0xE3A4, 0, 0,0xE3A6,0xE3A5, 0, 0,
+0xE3A7, 0, 0, 0, 0, 0, 0,0xE3A8,
+0xE3A9, 0, 0, 0, 0, 0, 0,0xE3AC,
+0xE3AA,0xE3AB,0x8DDF,0x8C72, 0, 0,0x9275, 0,
+0x94B1, 0,0x8F90, 0, 0,0x946C, 0,0x94EB,
+0xE3AD,0x9CEB, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE3AE,0xE3B0, 0,0x9785,0xE3AF,0xE3B2,
+0xE3B1, 0,0x9772, 0,0xE3B3, 0,0x94FC, 0,
+ 0, 0, 0, 0,0xE3B4, 0, 0, 0,
+ 0, 0,0xE3B7, 0, 0,0xE3B6,0xE3B5, 0,
+ 0,0xFB91, 0,0xE3B8,0x8C51, 0, 0, 0,
+0x9141,0x8B60, 0, 0, 0, 0,0xE3BC,0xE3B9,
+ 0, 0,0xE3BA, 0, 0, 0,0xE3BD, 0,
+0xE3BE,0xE3BB, 0, 0, 0,0x8948, 0, 0,
+ 0,0x89A5, 0, 0, 0,0xE3C0,0xE3C1, 0,
+ 0, 0,0xE3C2, 0,0x9782, 0, 0, 0,
+ 0, 0,0x8F4B, 0,0xE3C4,0xE3C3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9089,0xE3C5, 0, 0, 0, 0,0xE3C6, 0,
+ 0,0xE3C7, 0,0x8AE3, 0, 0, 0, 0,
+0x8ACB, 0, 0,0xE3C8, 0, 0, 0, 0,
+ 0,0xE3C9, 0,0x967C,0x9783, 0, 0, 0,
+0x9773,0x9856, 0,0x8D6C,0xE3CC,0x8ED2,0xE3CB, 0,
+ 0, 0, 0,0xE3CD,0x8EA7, 0, 0, 0,
+0x91CF, 0,0xE3CE, 0, 0,0x8D6B, 0,0x96D5,
+0xE3CF,0xE3D0, 0, 0,0xE3D1, 0, 0, 0,
+ 0,0xE3D2, 0, 0, 0, 0, 0, 0,
+0xE3D3, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8EA8, 0, 0,0x96EB, 0,
+ 0, 0, 0,0xE3D5, 0,0x925E, 0,0xE3D4,
+ 0, 0, 0, 0, 0, 0,0xE3D7, 0,
+ 0, 0,0xE3D6, 0, 0, 0, 0, 0,
+ 0, 0,0xE3D8, 0, 0, 0,0x90B9, 0,
+0xE3D9, 0,0xE3DA, 0, 0, 0,0x95B7,0xE3DB,
+ 0,0x918F,0xE3DC, 0, 0, 0, 0, 0,
+0xE3DD, 0, 0, 0, 0, 0, 0,0x97FC,
+0xE3E0, 0,0xE3DF,0xE3DE,0x92AE, 0,0xE3E1,0x9045,
+ 0,0xE3E2, 0, 0, 0,0xE3E3,0x9857,0xE3E4,
+ 0, 0, 0, 0,0xE3E5,0xE3E7,0xE3E6,0x94A3,
+ 0,0x93F7, 0,0x985D,0x94A7, 0, 0, 0,
+ 0, 0, 0,0xE3E9, 0, 0,0x8FD1, 0,
+0x9549, 0,0xE3EA,0xE3E8, 0,0x8ACC, 0, 0,
+ 0,0x8CD2,0x8E88, 0, 0,0x94EC, 0, 0,
+ 0,0x8CA8,0x9662, 0,0xE3ED,0xE3EB, 0,0x8D6D,
+ 0,0x8D6E,0x88E7, 0,0x8DE6, 0, 0, 0,
+ 0, 0,0x9478, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x88DD,0xE3F2, 0,0x925F, 0,
+ 0, 0, 0, 0,0x9477, 0,0x91D9, 0,
+ 0, 0, 0, 0, 0, 0,0xE3F4, 0,
+ 0,0xE3F0,0xE3F3,0xE3EE, 0,0xE3F1,0x9645, 0,
+ 0,0x8CD3, 0, 0,0x88FB,0xE3EF, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE3F6,
+ 0,0xE3F7, 0, 0,0x93B7, 0, 0, 0,
+0x8BB9, 0, 0, 0,0xE445,0x945C, 0, 0,
+ 0, 0,0x8E89, 0, 0,0x8BBA,0x90C6,0x9865,
+0x96AC,0xE3F5,0x90D2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8B72,0xE3F8, 0, 0, 0, 0,
+ 0, 0, 0,0xE3FA, 0, 0, 0, 0,
+ 0,0xE3F9, 0, 0, 0, 0, 0,0xE3FB,
+ 0,0x9245, 0,0x945D, 0, 0, 0, 0,
+ 0,0x92AF, 0, 0, 0, 0,0xE442, 0,
+ 0, 0, 0, 0, 0, 0,0xE441, 0,
+ 0, 0, 0,0xE3FC, 0, 0,0x9074, 0,
+0x9585,0xE444, 0,0xE443,0x8D6F,0x9872, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE454,
+ 0, 0, 0, 0, 0,0xE448,0xE449, 0,
+ 0, 0, 0,0x8EEE, 0, 0,0xE447, 0,
+0x8D98,0xE446, 0, 0,0xE44A, 0, 0, 0,
+0x92B0,0x95A0,0x9142, 0, 0, 0, 0,0x91DA,
+0xE44E, 0,0xE44F,0xE44B, 0, 0, 0, 0,
+0xE44C, 0,0xE44D, 0, 0, 0, 0,0x8D70,
+ 0, 0, 0,0xE455, 0,0xE451, 0, 0,
+ 0, 0,0x9586, 0,0x968C,0x9547, 0, 0,
+0xE450, 0, 0,0xE453,0xE452, 0, 0, 0,
+0x9663,0xE456, 0, 0, 0, 0, 0, 0,
+0xE457, 0, 0,0x9156, 0,0xE458, 0, 0,
+0xE45A, 0,0xE45E, 0, 0,0xE45B,0xE459,0x945E,
+0xE45C, 0,0xE45D, 0, 0, 0,0x89B0, 0,
+0xE464,0xE45F, 0, 0, 0,0xE460, 0, 0,
+ 0,0xE461, 0,0x919F, 0, 0, 0, 0,
+0xE463,0xE462,0xE465, 0, 0, 0, 0,0xE466,
+0xE467, 0, 0,0x9062, 0,0x89E7, 0,0xE468,
+0x97D5, 0,0x8EA9, 0, 0,0x8F4C, 0, 0,
+ 0, 0, 0,0x8E8A,0x9276, 0, 0, 0,
+ 0, 0,0xE469,0xE46A,0x8950, 0,0xE46B, 0,
+ 0,0xE46C,0xE46D, 0, 0,0xE46E, 0,0xE46F,
+0x8BBB,0x9DA8,0xE470, 0,0x90E3,0xE471,0x8EC9, 0,
+0xE472, 0,0x98AE, 0, 0, 0,0xE473,0x95DC,
+0x8ADA, 0, 0,0x9143,0x8F77, 0,0x9591,0x8F4D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE474,0x8D71,0xE475,0x94CA, 0,0xE484, 0,
+ 0, 0, 0,0xE477, 0,0x91C7,0x9495,0x8CBD,
+0xE476,0x9144, 0, 0, 0, 0, 0, 0,
+0xE478, 0, 0, 0, 0, 0, 0,0x92F8,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE47A,0xE479,0xE47C, 0, 0,0xE47B, 0,0xE47D,
+ 0, 0,0xE480, 0,0xE47E, 0,0x8ACD, 0,
+0xE481, 0,0xE482,0xE483, 0, 0,0x8DAF,0x97C7,
+ 0,0xE485,0x9046, 0, 0, 0,0x8990,0xE486,
+0xE487, 0, 0, 0, 0, 0,0xE488, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x88F0, 0,0xE489, 0, 0,
+ 0, 0,0xE48A, 0, 0, 0, 0, 0,
+ 0,0x9587, 0, 0, 0,0x8EC5, 0,0xE48C,
+ 0, 0, 0, 0, 0,0x8A48,0x88B0, 0,
+ 0, 0, 0,0xE48B,0xE48E,0x946D, 0,0x9063,
+ 0,0x89D4, 0,0x9646, 0, 0, 0, 0,
+0x8C7C,0x8BDA, 0,0xE48D, 0,0x89E8, 0, 0,
+ 0, 0, 0, 0, 0,0x8AA1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x8991,0xE492,0x97E8,0x91DB, 0, 0,0x9563,
+ 0,0xE49E, 0,0x89D5,0xE49C, 0,0xE49A,0xE491,
+ 0,0xE48F, 0,0xE490, 0,0x8EE1,0x8BEA,0x9297,
+ 0, 0, 0,0x93CF, 0, 0, 0, 0,
+ 0,0x8970, 0,0xE494,0xE493, 0, 0, 0,
+ 0,0xE499,0xE495,0xE498, 0, 0, 0, 0,
+ 0,0xFB93,0x96CE,0xE497,0x89D6,0x8A9D,0xE49B, 0,
+ 0,0xE49D, 0, 0, 0, 0,0x8C73, 0,
+ 0, 0, 0, 0, 0, 0,0xE4A1,0xE4AA,
+0xE4AB, 0, 0, 0,0x88A9, 0, 0, 0,
+ 0, 0, 0,0xE4B2, 0, 0, 0, 0,
+0x88EF, 0, 0,0xE4A9, 0, 0, 0,0xE4A8,
+ 0,0xE4A3,0xE4A2, 0,0xE4A0,0xE49F,0x9283, 0,
+0x91F9,0xE4A5, 0, 0, 0, 0, 0, 0,
+0xE4A4, 0, 0, 0, 0,0xE4A7, 0, 0,
+ 0,0x9190,0x8C74, 0, 0, 0, 0,0x8960,
+0xE4A6, 0,0x8D72, 0, 0, 0, 0, 0,
+0x9191, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xFB94, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE4B8, 0,0xE4B9, 0,0x89D7,
+ 0, 0, 0,0x89AC,0xE4B6, 0, 0,0xFB95,
+ 0, 0, 0, 0, 0,0xE4AC, 0,0xE4B4,
+ 0,0xE4BB,0xE4B5, 0, 0, 0,0xE4B3, 0,
+ 0, 0, 0,0xE496, 0, 0,0xE4B1, 0,
+ 0, 0,0xE4AD, 0, 0, 0,0x8ACE,0xE4AF,
+0xE4BA, 0,0xE4B0, 0, 0, 0, 0, 0,
+0xE4BC, 0,0xE4AE,0x949C, 0, 0, 0, 0,
+ 0,0x9789, 0, 0, 0,0xE4B7, 0, 0,
+ 0, 0, 0, 0, 0,0xE4CD, 0, 0,
+ 0,0xE4C5, 0, 0, 0,0x909B, 0,0xFB96,
+ 0, 0,0x8B65, 0,0x8BDB, 0,0xE4C0, 0,
+ 0, 0, 0,0x89D9, 0, 0,0x8FD2, 0,
+0xE4C3, 0, 0, 0,0x8DD8, 0, 0,0x9370,
+0xE4C8, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x95EC, 0,0xE4BF, 0, 0, 0,0x89D8,
+0x8CD4,0x9548,0xE4C9, 0,0xE4BD, 0,0xFB97,0xE4C6,
+ 0, 0, 0,0xE4D0, 0,0xE4C1, 0, 0,
+ 0, 0, 0,0xE4C2,0x93B8, 0, 0,0xE4C7,
+ 0, 0, 0,0xE4C4,0x9647,0xE4CA,0x88DE, 0,
+ 0, 0, 0,0xE4BE, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE4CC, 0,0xE4CB, 0, 0, 0, 0, 0,
+ 0,0x948B,0xE4D2, 0,0xE4DD, 0, 0, 0,
+ 0,0x8A9E, 0, 0, 0,0xE4E0, 0, 0,
+0xE4CE, 0, 0, 0,0xE4D3,0x978E, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE4DC, 0,
+0xFB98,0x9774, 0, 0, 0, 0,0x97A8, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x9298,
+ 0, 0, 0,0x8A8B, 0, 0, 0, 0,
+ 0,0x9592,0xE4E2,0x939F, 0, 0,0x88AF, 0,
+ 0,0xE4DB, 0,0xE4D7,0x9192,0xE4D1,0xE4D9,0xE4DE,
+ 0,0x944B, 0, 0, 0,0x88A8, 0,0xE4D6,
+ 0,0xE4DF,0x9598, 0, 0, 0, 0, 0,
+ 0, 0,0xE4DA, 0,0xE4D5, 0, 0, 0,
+ 0, 0, 0,0x8FD3, 0, 0, 0, 0,
+0x8F4E, 0, 0, 0,0x8EAA, 0, 0, 0,
+ 0,0x96D6, 0, 0,0x9566, 0, 0,0xE4E5,
+ 0,0xE4EE, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE4D8, 0, 0,
+ 0, 0,0x8A97, 0,0xFB99, 0, 0, 0,
+0x8FF6,0xE4E3, 0,0xE4E8,0x9193, 0, 0,0xE4E4,
+ 0,0xE4EB, 0, 0,0x927E, 0,0xE4EC, 0,
+ 0,0x9775,0xE4E1,0x8A57, 0,0xE4E7, 0, 0,
+0xE4EA,0x96AA, 0, 0, 0, 0,0xE4ED, 0,
+ 0,0xE4E6,0xE4E9, 0,0xFA60, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9648, 0,0x9840, 0,
+ 0, 0, 0, 0,0xE4F1, 0, 0, 0,
+ 0, 0, 0, 0,0xE4F8, 0, 0,0xE4F0,
+0x8EC1, 0, 0, 0, 0, 0,0xE4CF, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x95CC, 0,0x96A0,0xE4F7,0xE4F6, 0,0xE4F2,
+0xE4F3, 0,0x8955, 0, 0, 0, 0,0xE4F5,
+ 0,0xE4EF, 0, 0, 0, 0,0x92D3, 0,
+ 0, 0, 0, 0,0xE4F4,0x88FC, 0, 0,
+ 0, 0, 0, 0, 0,0x91A0, 0, 0,
+ 0, 0, 0, 0, 0,0x95C1, 0, 0,
+0xE4F9,0xE540, 0,0x94D7, 0, 0, 0, 0,
+0xE4FC,0x8FD4,0x8EC7,0xE542, 0, 0,0x8BBC, 0,
+ 0, 0, 0,0xFB9A, 0,0xE543, 0,0x9599,
+0xE4FB,0xFB9B,0xE4D4, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE4FA, 0, 0, 0, 0,
+0x986E,0x93A0,0x9593,0xFB9C, 0,0xE54A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE550,
+ 0, 0, 0, 0, 0, 0,0xE551, 0,
+0xE544, 0, 0, 0,0x9496, 0, 0,0xE54E,
+0xE546, 0,0xE548, 0, 0, 0, 0, 0,
+0xE552,0xE547, 0, 0,0xE54B, 0, 0,0x8992,
+ 0,0x93E3, 0,0xE54C,0xE54F, 0, 0, 0,
+ 0, 0, 0, 0,0xE545, 0,0x9145, 0,
+0xE549,0x8E46,0x9064,0x8C4F,0x96F2, 0,0x96F7,0x8F92,
+0xFB9E, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE556,0xE554, 0, 0, 0, 0, 0,
+ 0,0x986D, 0, 0, 0, 0, 0, 0,
+ 0,0xE553, 0, 0, 0,0x9795, 0,0xE555,
+0xE557, 0, 0, 0, 0,0xE558, 0, 0,
+ 0, 0, 0, 0,0xE55B,0xE559, 0, 0,
+ 0, 0, 0, 0,0x93A1,0xE55A, 0, 0,
+ 0,0x94CB,0xE54D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x8F93,
+ 0,0xE55C,0xE561,0x9194, 0, 0,0xE560, 0,
+ 0, 0,0xE541, 0, 0, 0,0xE562,0x9168,
+ 0, 0,0xE55D,0xE55F, 0, 0, 0, 0,
+ 0, 0, 0,0xE55E, 0, 0,0x9F50,0x9F41,
+ 0, 0,0xE564, 0, 0, 0, 0, 0,
+ 0, 0,0xE563, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x9796, 0,0xE1BA,
+0xE565, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE566,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE567,0x8CD5, 0,
+0x8B73, 0, 0, 0,0xE569,0x997C, 0, 0,
+ 0, 0,0x8B95, 0,0x97B8, 0,0x8BF1,0xE56A,
+ 0, 0, 0, 0, 0, 0, 0,0xE56B,
+ 0, 0, 0,0x928E, 0, 0, 0, 0,
+ 0,0xE56C, 0, 0, 0, 0, 0, 0,
+ 0,0x93F8, 0,0x88B8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x89E1,0xE571,0xE572, 0, 0, 0,
+ 0, 0, 0,0xE56D, 0,0x8E5C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE56E,0x9461, 0, 0, 0,
+ 0,0xE56F,0xE570,0xE57A, 0, 0, 0,0xE574,
+0xE577, 0, 0, 0, 0, 0,0xE573, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE575, 0,0xE576,0x8ED6,
+ 0,0xE578, 0,0x9260, 0,0x8C75,0x8A61, 0,
+ 0, 0, 0, 0,0xE57B, 0, 0, 0,
+ 0,0x8A5E, 0,0xE581, 0, 0,0xE57C,0xE580,
+ 0, 0, 0, 0,0x94B8, 0, 0, 0,
+ 0,0xE57D, 0, 0,0xE57E,0x9567,0x94D8,0xE582,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x91FB,0xE58C, 0,0xE588, 0, 0,0x89E9, 0,
+0xE586, 0,0x9649,0xE587, 0, 0,0xE584, 0,
+0xE585,0xE58A,0xE58D, 0, 0,0xE58B, 0, 0,
+ 0,0xE589,0xE583, 0, 0, 0, 0, 0,
+0x9277, 0,0xE594, 0,0x96A8, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE592, 0, 0,
+ 0,0xE593, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE58E, 0, 0,0xE590,
+ 0, 0, 0,0xE591, 0, 0, 0,0xE58F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x90E4, 0,0x9858,0xE598, 0,0xE599, 0,
+ 0, 0, 0,0xE59F, 0,0x9049, 0,0xE59B,
+ 0,0xE59E, 0, 0, 0, 0, 0,0xE596,
+0xE595, 0, 0,0xE5A0, 0, 0,0x89DA, 0,
+0xE59C, 0,0xE5A1, 0, 0, 0,0xE59D, 0,
+ 0, 0, 0, 0,0xE59A, 0,0x92B1, 0,
+0xE597, 0, 0, 0, 0, 0, 0,0x9488,
+ 0, 0,0xE5A5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x975A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE5A4,
+ 0, 0,0xE5A3, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE5AC, 0, 0, 0,0xE5A6,
+ 0, 0, 0,0xE5AE, 0, 0, 0, 0,
+ 0, 0,0x9786,0xE5B1, 0,0xE5A8, 0, 0,
+0xE5A9, 0, 0, 0,0xE5AD, 0,0xE5B0,0xE5AF,
+ 0, 0, 0,0xE5A7, 0, 0, 0, 0,
+0xE5AA, 0,0xE5BB, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE5B4, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE5B2,
+ 0, 0,0xE5B3, 0, 0, 0,0xE5B8,0xE5B9,
+ 0,0x8A49, 0,0x8B61, 0, 0,0xE5B7, 0,
+ 0, 0, 0, 0, 0,0xE5A2, 0,0xFBA1,
+ 0, 0, 0, 0, 0,0xE5B6,0xE5BA,0xE5B5,
+ 0,0xE5BC, 0, 0, 0,0xE5BE,0xE5BD, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE5C0,0xE5BF,0xE579, 0, 0, 0,0xE5C4,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE5C1, 0, 0, 0, 0,0xE5C2, 0,
+ 0,0xE5C3, 0,0xE5C5, 0, 0, 0, 0,
+0x8C8C, 0,0xE5C7, 0,0xE5C6, 0,0x8F4F, 0,
+ 0, 0, 0, 0,0x8D73,0x9FA5, 0, 0,
+ 0, 0,0xE5C8,0x8F70, 0, 0, 0,0x8A58,
+ 0,0xE5C9, 0,0x8971, 0,0x8FD5,0xE5CA, 0,
+ 0,0x8D74,0xE5CB,0x88DF, 0, 0, 0, 0,
+0x955C, 0, 0,0xE5CC, 0, 0, 0, 0,
+0x908A, 0,0xE5D3, 0, 0,0xE5D0, 0,0x928F,
+ 0, 0, 0, 0, 0,0xE5D1,0xE5CE,0x8BDC,
+ 0,0xE5CD,0xE5D4, 0, 0, 0, 0, 0,
+0x8C55, 0, 0,0x91DC, 0,0xE5DA, 0, 0,
+ 0, 0,0xE5D6, 0, 0, 0,0x91B3,0xE5D5,
+ 0,0xE5D8, 0, 0, 0, 0,0xE5CF, 0,
+ 0, 0,0xE5D9, 0,0xE5DB, 0, 0, 0,
+ 0, 0, 0,0x94ED, 0, 0,0xE5D7, 0,
+0xE5DC,0xE5DE, 0, 0,0x8CD1,0xE5D2, 0,0x88BF,
+ 0, 0, 0, 0, 0, 0, 0,0xE5DD,
+ 0,0x8DD9,0x97F4,0xE5DF,0xE5E0,0x9195, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x97A0,
+ 0, 0, 0, 0,0xE5E1,0x9754, 0, 0,
+0xE5E2,0xE5E3, 0, 0,0x95E2,0xE5E4, 0,0x8DBE,
+ 0,0x97A1, 0, 0, 0, 0, 0, 0,
+0xE5E9, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE5EA,0x8FD6,0xE5E8,0xFBA2, 0, 0,
+0x9787,0xE5E5, 0, 0,0xE5E7,0x90BB,0x909E, 0,
+ 0, 0,0xE5E6, 0,0xE5EB, 0, 0,0x95A1,
+ 0, 0,0xE5ED, 0,0xE5EC, 0, 0, 0,
+0x8A8C, 0,0x964A,0xE5EE, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xFA5D,0xE5FA,0xE5F0, 0,
+ 0, 0, 0, 0, 0,0xE5F1, 0, 0,
+ 0, 0,0xE5F2,0xE5F3, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE5F7, 0,
+0xE5F8, 0, 0,0xE5F6, 0, 0, 0, 0,
+ 0,0xE5F4, 0,0xE5EF,0xE5F5, 0, 0, 0,
+ 0, 0, 0, 0,0xE5F9,0xE8B5, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x89A6, 0,
+ 0, 0, 0, 0, 0, 0,0xE5FC,0x8BDD,
+0xE5FB, 0, 0, 0,0xE641, 0,0xE640, 0,
+ 0, 0,0xE643, 0, 0,0xE642, 0,0xE644,
+ 0, 0,0x8F50, 0,0xE645, 0, 0,0xE646,
+ 0, 0, 0, 0, 0, 0,0xE647,0x90BC,
+ 0,0x9776, 0,0xE648, 0, 0,0x95A2,0x9465,
+0xE649, 0,0xE64A,0x8CA9, 0, 0, 0,0x8B4B,
+ 0, 0, 0,0xE64B, 0, 0,0x8E8B,0x9460,
+0xE64C, 0,0x8A6F, 0, 0, 0, 0, 0,
+ 0,0xE64D, 0, 0, 0, 0,0xE64F,0x9797,
+ 0,0xE64E,0x9065, 0,0xE650, 0, 0,0xE651,
+ 0, 0,0xE652,0x8ACF, 0, 0, 0, 0,
+ 0, 0,0xE653, 0, 0,0xE654, 0,0xE655,
+0xE656, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8A70, 0, 0, 0, 0, 0,
+ 0, 0,0xE657, 0,0xE658,0xE659, 0, 0,
+ 0, 0, 0,0x89F0, 0, 0,0x9047,0xE65A,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE65B, 0, 0, 0,
+0xE65C, 0, 0, 0, 0, 0, 0, 0,
+0x8CBE, 0,0x92F9,0xE65D, 0, 0, 0, 0,
+0x8C76, 0,0x9075, 0,0xE660, 0,0x93A2, 0,
+0xE65F, 0,0xFBA3,0x8C50, 0, 0,0xE65E,0x91F5,
+0x8B4C, 0, 0,0xE661, 0,0xE662, 0,0x8FD7,
+ 0, 0, 0,0x8C8D, 0,0xE663, 0, 0,
+ 0, 0,0x964B, 0, 0,0x90DD, 0, 0,
+ 0,0x8B96, 0,0x96F3,0x9169, 0,0xE664,0xFBA4,
+ 0, 0,0x9066,0x9290,0x8FD8, 0, 0, 0,
+ 0,0xE665, 0, 0, 0, 0,0xE668, 0,
+0xE669, 0, 0, 0, 0, 0, 0, 0,
+0x8DBC,0x91C0,0xE667, 0,0x8FD9,0x955D, 0, 0,
+ 0, 0, 0,0xE666, 0, 0,0x8E8C, 0,
+0x8972, 0,0xE66D,0x8C77, 0, 0,0x8E8E, 0,
+ 0,0x8E8D, 0,0x986C,0xE66C,0xE66B,0x9146, 0,
+0x8B6C,0x9862,0x8A59,0x8FDA, 0, 0, 0, 0,
+ 0,0xFBA5, 0, 0,0xE66A, 0, 0, 0,
+ 0, 0,0xE66F, 0,0xE670,0xE66E, 0,0x8CD6,
+ 0,0x975F, 0, 0,0x8E8F,0x9446, 0, 0,
+ 0,0xE673, 0,0x90BE, 0,0x9261, 0, 0,
+0x9755, 0,0xE676, 0, 0, 0,0x8CEA, 0,
+0x90BD,0xE672, 0,0xE677,0x8CEB,0xE674,0xE675,0xFBA6,
+0xE671, 0, 0, 0,0x90E0,0x93C7, 0, 0,
+0x924E, 0,0x89DB, 0, 0, 0, 0, 0,
+ 0,0x94EE, 0, 0,0x8B62, 0,0xFBA7,0x92B2,
+ 0, 0,0xE67A, 0,0xE678, 0, 0,0x926B,
+ 0, 0, 0,0x90BF,0x8AD0,0xE679, 0,0x907A,
+ 0, 0,0x97C8, 0, 0, 0,0x985F, 0,
+ 0, 0,0xE67B,0xE687,0x92B3, 0,0xE686,0xFBA8,
+0xE683,0xE68B,0xE684, 0,0xE680, 0,0x92FA,0xE67E,
+ 0, 0, 0,0xE67C, 0,0x9740,0x8E90, 0,
+ 0,0xE681, 0,0xE67D, 0, 0,0xFBAA,0xE685,
+0x8F94, 0,0x8CBF, 0, 0, 0,0x91F8, 0,
+0x9664,0x8979,0x88E0, 0,0x93A3, 0, 0,0xE689,
+ 0, 0, 0, 0,0xE688, 0,0x93E4, 0,
+0xE68D, 0, 0, 0,0xE682, 0,0xE68C,0xE68E,
+ 0,0x8CAA,0xE68A,0x8D75, 0,0x8ED3, 0, 0,
+0xE68F,0x9777, 0, 0, 0, 0,0xE692, 0,
+0xE695, 0, 0,0xE693,0x9554, 0, 0, 0,
+ 0, 0, 0,0xE690, 0, 0, 0, 0,
+ 0,0x8BDE, 0, 0, 0, 0,0xE694, 0,
+ 0,0xE696, 0, 0, 0, 0, 0, 0,
+ 0,0xE69A, 0, 0,0xE697, 0,0xE699,0xE698,
+ 0, 0, 0,0xFBAB, 0, 0,0xE69B, 0,
+0x8EAF, 0,0xE69D,0xE69C,0x9588, 0, 0,0xE69F,
+ 0, 0, 0, 0, 0, 0,0x8C78, 0,
+ 0, 0, 0,0xE69E,0xE6A0, 0, 0,0xE6A1,
+0x8B63,0xE3BF,0x8FF7, 0,0xE6A2, 0, 0,0x8CEC,
+ 0, 0, 0, 0, 0,0xE6A3, 0,0xFBAC,
+0xE6A4, 0, 0,0x8E5D, 0, 0, 0, 0,
+ 0, 0,0x9DCC, 0,0xE6A5, 0,0xE6A6, 0,
+0x8F51, 0,0xE6A7,0xE6A8, 0, 0,0xE6A9, 0,
+ 0,0xE6AA,0xE6AB, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x924A,
+ 0, 0,0xE6AC, 0, 0, 0, 0,0xE6AE,
+ 0,0xE6AD, 0, 0, 0, 0,0x93A4, 0,
+0xE6AF, 0,0x964C, 0,0xE6B0, 0,0xE6B1, 0,
+0xE6B2, 0, 0, 0, 0,0xE6B3, 0, 0,
+ 0, 0,0x93D8, 0, 0, 0, 0, 0,
+ 0,0x8FDB,0xE6B4, 0, 0, 0, 0, 0,
+ 0, 0,0x8D8B,0x98AC,0xE6B5, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE6B6,0x955E,0xE6B7, 0,0xE6BF, 0, 0, 0,
+ 0, 0,0xE6B8, 0, 0,0xE6BA, 0, 0,
+ 0,0xE6B9,0xE6BB, 0,0x9665,0xE6BC,0xE6BD, 0,
+ 0, 0, 0, 0,0xE6BE, 0, 0, 0,
+0xE6C0, 0, 0, 0, 0,0x8A4C,0x92E5, 0,
+0x9589,0x8DE0,0x8D76, 0, 0, 0, 0,0x956E,
+0x89DD,0x94CC,0xE6C3,0x8AD1,0x90D3,0xE6C2,0xE6C7,0x9299,
+0x96E1, 0,0xE6C5,0xE6C6,0x8B4D, 0,0xE6C8,0x9483,
+0x91DD, 0, 0,0x94EF,0x935C,0xE6C4, 0,0x9666,
+0x89EA,0xE6CA,0x9847,0x92C0,0x9864, 0, 0,0x8E91,
+0xE6C9, 0,0x91AF, 0, 0,0xE6DA,0x9147, 0,
+ 0,0x93F6, 0,0x956F, 0, 0, 0, 0,
+ 0, 0,0xE6CD,0x8E5E,0x8E92, 0,0x8FDC, 0,
+0x9485, 0,0x8CAB,0xE6CC,0xE6CB, 0,0x958A, 0,
+ 0, 0,0x8EBF, 0, 0,0x9371, 0, 0,
+0xFBAD, 0, 0, 0,0xFBAE, 0, 0, 0,
+ 0, 0,0xE6CF,0xE6D0,0x8D77,0xE6CE, 0, 0,
+ 0, 0, 0, 0,0xE6D1,0xE6D2, 0,0xE6D4,
+0x91A1, 0,0xE6D3,0x8AE4, 0,0xE6D6, 0,0xE6D5,
+0xE6D7, 0,0xFBAF,0xE6D9,0xE6DB, 0,0xE6DC, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x90D4, 0,0x8ECD,0xE6DD,
+ 0, 0, 0,0x8A71, 0,0xE6DE, 0, 0,
+0x9196,0xE6DF, 0,0xE6E0,0x958B, 0,0xFBB0,0x8B4E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE6E1, 0, 0, 0,0x92B4, 0, 0,
+ 0, 0,0x897A, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE6E2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x8EEF, 0, 0, 0, 0,
+0x9096, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x91AB, 0, 0, 0, 0,
+ 0, 0,0xE6E5, 0, 0, 0,0xE6E4, 0,
+ 0, 0,0xE6E3, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE6EB,0xE6E9, 0, 0,0xE6E6,
+ 0, 0, 0, 0, 0, 0,0xE6E8, 0,
+ 0, 0,0xE6E7,0xE6EA, 0,0x8B97, 0,0xE6EE,
+ 0,0x90D5, 0,0xE6EF, 0, 0, 0, 0,
+0x8CD7, 0,0xE6EC,0xE6ED, 0, 0, 0,0x9848,
+ 0, 0, 0,0x92B5, 0,0x9148, 0, 0,
+ 0, 0, 0, 0,0xE6F0, 0, 0,0xE6F3,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE6F1,0xE6F2,0x9778, 0, 0, 0, 0,0x93A5,
+0xE6F6, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE6F4,0xE6F5,0xE6F7,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE748, 0, 0, 0, 0, 0,
+0xE6FA, 0, 0, 0,0xE6FB,0xE6F9, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE6F8, 0,0x92FB, 0, 0,0xE740,
+0xE744,0xE741,0xE6FC, 0,0xE742, 0, 0, 0,
+0xE743, 0, 0, 0, 0,0xE74A, 0, 0,
+ 0,0xE745, 0, 0, 0, 0, 0,0x90D6,
+0xE747, 0, 0,0xE749,0xE746, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE74C, 0,0x8F52, 0,0xE74B, 0,
+ 0, 0, 0, 0,0xE74D, 0, 0, 0,
+ 0,0xE74E, 0, 0,0xE751,0xE750, 0,0xE74F,
+ 0, 0,0xE753,0xE752, 0,0x96F4, 0, 0,
+ 0,0xE755, 0,0xE754,0xE756, 0, 0, 0,
+ 0,0xE757, 0, 0, 0, 0, 0, 0,
+ 0,0xE759, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE758,0x9067,0xE75A, 0, 0,0x8BEB,
+0xE75B,0xE75D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE75E, 0,
+ 0, 0, 0, 0, 0,0xE75F,0xE75C, 0,
+0xE760, 0,0x8ED4,0xE761,0x8B4F,0x8C52, 0,0xFBB2,
+ 0, 0,0x8CAC, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE762, 0, 0, 0,0x93EE,
+ 0, 0,0x935D,0xE763, 0, 0, 0, 0,
+ 0, 0, 0,0xE766, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x8EB2, 0, 0,0xE765,0xE764,0x8C79,0xE767, 0,
+ 0, 0, 0,0x8A72, 0,0xE769, 0, 0,
+ 0,0x8DDA,0xE768, 0,0xE771, 0, 0, 0,
+ 0, 0,0xE76B,0xE76D,0x95E3,0xE76A, 0, 0,
+ 0,0xE76C, 0,0xE770,0xE76E,0x8B50, 0,0xE76F,
+ 0, 0, 0, 0, 0, 0,0xE772, 0,
+ 0,0x9479,0x97D6, 0, 0, 0, 0,0x8F53,
+ 0, 0, 0,0xE773, 0, 0, 0, 0,
+0x9741,0xE775, 0,0xE774, 0, 0,0xE778,0x9760,
+ 0, 0,0xE777, 0,0x8A8D,0xE776,0xE77B, 0,
+ 0,0xE77A, 0, 0,0xE779,0x9351,0xE77C, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE77D,
+ 0, 0, 0, 0,0xE77E, 0, 0,0x8D8C,
+ 0,0x8C44,0xE780,0xE781,0xE782, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x9068,0xE783, 0,0x8EAB,0xE784,
+ 0, 0, 0,0xE785, 0, 0, 0,0x999F,
+0x999E, 0, 0, 0, 0,0xE786,0xE390,0xE787,
+0x9243,0x904A,0x945F, 0, 0, 0, 0,0xE788,
+ 0, 0,0x95D3,0x92D2,0x8D9E, 0, 0,0x9248,
+ 0, 0,0x8949, 0,0x9698,0x9076, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x8C7D, 0,
+ 0,0x8BDF, 0, 0,0x95D4, 0, 0, 0,
+ 0, 0,0xE789, 0, 0, 0, 0, 0,
+ 0, 0,0xE78B, 0, 0,0xE78A,0x89DE, 0,
+ 0,0x93F4,0xE78C,0x9497, 0,0x9352, 0,0xE78D,
+0x8F71, 0, 0, 0,0xE78F, 0, 0,0x96C0,
+0xE79E,0xE791,0xE792, 0, 0,0x92C7, 0, 0,
+0x91DE,0x9197, 0,0x93A6, 0,0xE790,0x8B74, 0,
+ 0, 0, 0,0xE799, 0,0xE796,0xE7A3,0x93A7,
+0x9280,0xE793, 0,0x92FC,0x9372,0xE794,0xE798,0x9080,
+ 0,0x9487,0x92CA, 0, 0,0x90C0,0xE797,0x91AC,
+0x91A2,0xE795,0x88A7,0x9841, 0, 0, 0,0xE79A,
+ 0, 0, 0, 0, 0, 0,0x91DF, 0,
+ 0,0x8F54,0x9069, 0, 0,0xE79C,0xE79B, 0,
+0x88ED,0xE79D, 0, 0,0x954E, 0,0xE7A5, 0,
+ 0,0x93D9,0x908B, 0, 0,0x9278, 0,0x8BF6,
+ 0,0xE7A4,0x9756,0x895E, 0,0x95D5,0x89DF,0xE79F,
+0xE7A0,0xE7A1,0xE7A2,0x93B9,0x9242,0x88E1,0xE7A6, 0,
+0xE7A7,0xEAA1, 0, 0,0x91BB, 0,0xE7A8, 0,
+0x8993,0x916B, 0,0x8CAD, 0,0x9779, 0,0xFBB5,
+0xE7A9,0x934B, 0, 0, 0,0x9198,0x8ED5,0xE7AA,
+ 0, 0,0xE7AD, 0, 0,0x8F85,0xE7AB,0x914A,
+0x9149, 0,0x88E2, 0,0x97C9,0xE7AF, 0,0x94F0,
+0xE7B1,0xE7B0,0xE7AE,0xE284,0x8AD2, 0, 0,0xE78E,
+ 0,0xE7B3,0xE7B2, 0, 0, 0, 0,0xE7B4,
+ 0,0x9757, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x93DF, 0, 0,0x964D, 0,
+0xE7B5, 0,0x8ED7, 0, 0, 0, 0,0xE7B6,
+ 0,0xE7B7, 0, 0, 0,0xE7B8, 0, 0,
+0x9340, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x88E8, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x8D78, 0, 0, 0,0x9859, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE7BC, 0, 0,0xFBB6, 0,
+ 0,0x8C53,0xE7B9, 0,0xE7BA, 0, 0, 0,
+0x9594, 0, 0, 0, 0,0x8A73, 0, 0,
+ 0, 0, 0, 0, 0,0x9758, 0,0x8BBD,
+ 0, 0, 0, 0, 0,0x9373, 0, 0,
+ 0, 0,0xE7BD, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE7BE, 0, 0,0xFBB8, 0, 0,
+ 0,0xE7BF, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xFBB9,
+ 0, 0, 0, 0, 0,0x9341, 0, 0,
+0xE7C1, 0,0xE7C0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x93D1,0xE7C2,0x8F55,0x8EDE,0x947A,0x9291, 0,
+ 0, 0,0x8EF0, 0,0x908C, 0,0xE7C3, 0,
+0xE7C4, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x907C,0xE7C5, 0,0xE7C6, 0, 0,
+ 0,0xE7C7,0x978F, 0,0x8F56, 0, 0, 0,
+ 0, 0,0xE7C9,0xE7C8, 0,0x8D79, 0,0x8D93,
+0x8E5F, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xE7CC, 0, 0, 0, 0,0x8F86,
+ 0,0xE7CB, 0,0xE7CA, 0,0x91E7, 0, 0,
+0x8CED, 0,0x90C1, 0, 0, 0, 0,0x94AE,
+ 0, 0, 0, 0,0x8F58, 0, 0, 0,
+ 0, 0,0xE7CD, 0,0x8FDD, 0, 0, 0,
+ 0, 0,0xE7D0,0xE7CE, 0, 0, 0,0xE7CF,
+ 0, 0, 0, 0,0xE7D2,0xE7D1, 0, 0,
+0x8FF8, 0,0xE7D3, 0, 0, 0, 0, 0,
+0xE7D4,0xE7D5, 0, 0, 0, 0,0x94CE,0x8DD1,
+0x8EDF,0xE7D6, 0,0xE7D7,0x97A2,0x8F64,0x96EC,0x97CA,
+0xE7D8,0x8BE0, 0, 0, 0, 0,0xE7D9,0xFBBB,
+0x9342, 0,0xFBBA,0xE7DC,0x8A98,0x906A,0xFBBC,0xE7DA,
+ 0,0xE7DB, 0,0x92DE,0xFBBF,0xFBC0,0x9674,0x8BFA,
+ 0, 0, 0, 0, 0,0xFBBD,0xFBBE, 0,
+ 0, 0, 0, 0, 0,0xE7DE,0xE7DF, 0,
+ 0, 0, 0, 0,0xE7DD, 0, 0,0xE7E1,
+ 0, 0, 0, 0, 0, 0,0xFBC1, 0,
+ 0, 0,0xFBC3, 0, 0,0x93DD,0x8A62, 0,
+0xFBC2,0xE7E5, 0, 0,0xE7E2,0xE7E4, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE7E0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE86E, 0, 0,0xE7E3, 0, 0, 0,
+ 0, 0, 0, 0,0x97E9, 0, 0,0x8CD8,
+ 0,0xFBCA,0xFBC4, 0,0xFBC6, 0, 0,0xE7ED,
+0xFBC5, 0, 0, 0,0x9353,0xE7E8, 0, 0,
+0xE7EB,0xE7E9, 0,0xE7EE, 0, 0,0xFBC7, 0,
+0xE7EF,0xFBC9, 0, 0, 0, 0, 0,0xE7E7,
+ 0,0xFBC8,0xE7F4,0x8994, 0, 0,0xE7E6, 0,
+ 0, 0,0x94AB, 0,0xE7EA, 0,0x8FDE,0xFBCB,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x8D7A, 0, 0, 0, 0, 0,0xFBCD,
+0xFBCE, 0, 0, 0, 0, 0,0x9667, 0,
+0x8BE2, 0, 0,0x8F65, 0,0x93BA, 0, 0,
+0xFA5F, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x914C, 0,0xE7F2, 0,0xE7EC,0xE7F1, 0,
+0x96C1, 0,0x92B6,0xE7F3,0xE7F0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xFBCC,
+ 0, 0, 0, 0, 0,0x914B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE7F7,
+ 0,0xE7F6, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE7F5,
+0xFBD2, 0,0x964E,0xFBD6, 0,0xFBD4, 0,0xFBD0,
+ 0,0xFBD1, 0, 0, 0, 0, 0, 0,
+0xFBD5, 0, 0, 0,0x8F9B, 0, 0,0xFBCF,
+ 0,0xE7F8,0x95DD, 0, 0,0x8973, 0, 0,
+ 0, 0,0x9565,0x9292, 0, 0, 0, 0,
+0x8B98,0xFA65,0xE7FA,0xFBD9,0x8D7C, 0, 0,0xFBDC,
+ 0, 0,0xFBDE, 0, 0, 0,0x8E4B, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE7F9,
+0x908D, 0, 0, 0, 0, 0, 0, 0,
+0x908E,0xE840,0xE842, 0, 0,0xFBDD,0xFBDB, 0,
+0x8FF9,0xFBD8,0xE841,0xE843, 0,0xFBD7,0x8BD1, 0,
+0x9564, 0, 0,0x8EE0,0x9842, 0,0xE7FC,0x8DF6,
+ 0, 0,0x985E, 0, 0,0xE845, 0, 0,
+ 0, 0,0xE844,0xE846, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE7FB, 0, 0, 0,
+0xFA5E, 0, 0,0x93E7, 0,0x9374, 0, 0,
+ 0, 0, 0, 0,0x92D5, 0,0xE84B,0xFBE0,
+ 0, 0, 0,0x9262,0xE847, 0, 0, 0,
+0xE848, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8C4C, 0,0xE84A, 0,
+0xFBDF, 0, 0, 0, 0,0x8CAE, 0, 0,
+ 0, 0, 0, 0,0xE849, 0,0x8FDF, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8A99, 0, 0, 0,
+ 0, 0, 0, 0,0xE84F, 0,0x8DBD,0x9199,
+ 0, 0,0x92C8, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xFBE1, 0, 0,0x8A5A,
+ 0, 0, 0, 0,0xE84D,0xE84E,0x92C1, 0,
+0xE84C, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE850, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE856, 0, 0,0xFBE2, 0,
+0xE859, 0, 0, 0, 0, 0, 0, 0,
+0xE858,0x934C, 0, 0, 0, 0,0xE851,0xE852,
+0xE855, 0, 0, 0, 0,0xE857,0xFBE3, 0,
+ 0,0x8BBE, 0, 0,0xE85A,0xE854, 0, 0,
+0xE853, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xFBE4, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE85E, 0, 0, 0,0xE85F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE860, 0, 0,0xE85D,0xE85C, 0, 0, 0,
+0x8FE0,0x93A8,0xE85B, 0, 0, 0, 0, 0,
+ 0,0xE864, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xE862, 0, 0, 0, 0,
+ 0,0xFBE5, 0, 0, 0,0xE863,0xE861, 0,
+0x91F6, 0,0xE865, 0, 0, 0, 0, 0,
+ 0,0xE866, 0, 0,0xE868,0xFBE6, 0, 0,
+0xFBE7, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x8AD3,0xE867,0x96F8, 0, 0, 0, 0,
+ 0, 0,0xE873,0xE869, 0, 0,0xE86C, 0,
+0xE86A, 0,0xE86B, 0, 0, 0, 0, 0,
+ 0, 0,0xE86D, 0, 0, 0, 0, 0,
+0xE86F, 0, 0, 0, 0,0xE870, 0,0xE871,
+ 0, 0, 0, 0,0xE874,0xE872,0xE875,0xE877,
+ 0,0xE876};
+
+/* page 7 0x9577-0x9FA0 */
+static uint16 tab_uni_cp9327[]={
+0x92B7, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x96E5, 0,0xE878,0x914D, 0, 0, 0,
+0xE879, 0,0x95C2,0xE87A,0x8A4A, 0, 0, 0,
+0x895B, 0,0x8AD5,0xFBE8,0x8AD4,0xE87B, 0,0xE87C,
+ 0,0xE87D,0xE87E, 0, 0, 0, 0, 0,
+ 0,0xE880, 0,0x8AD6,0x8A74,0x8D7D,0x94B4, 0,
+0xE882,0xE881, 0, 0, 0, 0,0xE883, 0,
+ 0, 0, 0,0x897B, 0, 0, 0, 0,
+ 0, 0,0xE886, 0,0xE885,0xE884, 0,0xE887,
+ 0, 0, 0, 0,0xE88A, 0, 0, 0,
+0x88C5, 0, 0,0xE888, 0,0xE88C,0xE88B, 0,
+ 0, 0, 0, 0, 0,0xE88E,0xE88D,0xE88F,
+ 0,0x93AC, 0, 0, 0,0xE890, 0, 0,
+ 0, 0,0xE891,0xE893, 0, 0,0xE892, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x958C, 0, 0,
+ 0, 0,0xE894, 0, 0, 0, 0, 0,
+ 0,0xE895, 0,0x8DE3, 0, 0, 0,0xE896,
+0xE897, 0, 0,0x9668, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x916A, 0, 0, 0,
+0x88A2,0x91C9, 0,0xE898, 0,0x958D, 0, 0,
+ 0, 0, 0, 0,0xE89B,0xE899,0x8D7E, 0,
+0xE89A,0x8CC0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x95C3,0xE89D,0xE89F,0xE89E,
+0xE8A0, 0, 0,0x8940,0x9077,0x8F9C,0x8AD7,0xE8A1,
+ 0, 0, 0,0x9486, 0,0xE8A3, 0, 0,
+ 0,0x8941, 0,0xE8A2,0x92C2, 0,0x97CB,0x93A9,
+0xE89C,0x97A4, 0,0x8CAF, 0, 0,0x977A, 0,
+ 0, 0, 0, 0, 0, 0,0x8BF7,0x97B2,
+ 0,0x8C47, 0,0x91E0,0xE440, 0,0xE8A4,0x8A4B,
+0x908F, 0, 0, 0, 0,0x8A75,0xE8A6, 0,
+0xE8A7,0xE8A5,0x8C84, 0,0x8DDB,0x8FE1,0xFBEB, 0,
+ 0,0x8942, 0, 0,0x97D7, 0, 0, 0,
+0xE8A9,0xE7AC, 0,0xE8A8, 0, 0, 0, 0,
+0xFBEC,0xE8AC,0xE8AA,0xE8AB, 0,0xE8AD, 0,0xE8AE,
+0x97EA,0xE8AF,0xE8B0, 0,0x90C7,0x94B9, 0, 0,
+ 0,0x909D,0x8AE5, 0, 0,0x9759,0x89EB,0x8F57,
+0x8CD9, 0,0xE8B3, 0,0xE8B2,0x8E93,0xE8B4,0xE8B1,
+ 0, 0,0x8E47, 0, 0, 0,0xE8B8,0xE5AB,
+ 0, 0,0x99D4, 0,0x9097,0xE8B6, 0, 0,
+ 0, 0, 0,0x97A3,0x93EF, 0, 0, 0,
+ 0,0x894A, 0,0x90E1,0x8EB4, 0, 0, 0,
+ 0,0x95B5, 0,0x895F, 0, 0, 0,0x97EB,
+0x978B, 0,0xE8B9, 0,0x9364, 0, 0, 0,
+ 0,0x8EF9, 0, 0, 0,0xE8BA, 0,0xE8BB,
+0x906B,0xE8BC, 0,0x97EC, 0, 0,0xE8B7,0xE8BE,
+0xE8C0, 0,0xE8BF, 0,0xE8BD, 0, 0,0xE8C1,
+ 0, 0,0xE8C2, 0, 0,0x919A, 0,0x89E0,
+ 0, 0, 0, 0, 0,0xE8C3, 0, 0,
+0x96B6, 0, 0,0xE8C4, 0, 0, 0, 0,
+ 0,0xE8C5, 0,0x9849,0xFBED, 0, 0, 0,
+ 0,0x9E50,0xE8C6, 0,0xFBEE, 0,0xE8C7,0xE8C8,
+ 0, 0, 0,0xE8CC,0xFBEF,0xE8C9, 0,0xE8CA,
+ 0,0xE8CB,0xE8CD, 0, 0, 0,0xFBF0, 0,
+0xFBF1, 0,0xFBF2,0x90C2, 0, 0,0xFBF3,0x96F5,
+ 0, 0,0x90C3, 0, 0,0xE8CE, 0,0x94F1,
+ 0,0xE8CF,0xEA72,0x96CA, 0,0xE8D0, 0,0xE8D1,
+ 0,0xE8D2,0x8A76, 0,0xE8D4, 0,0x9078, 0,
+ 0, 0,0xE8D5, 0, 0,0x8C43, 0, 0,
+ 0, 0,0xE8D6,0xE8DA, 0,0xE8D8, 0, 0,
+ 0, 0,0xE8D9, 0, 0,0x8A93,0xE8D7,0xE8DB,
+ 0, 0, 0, 0,0xE8DC, 0,0x88C6, 0,
+0xE8DD,0xE8DE, 0, 0, 0, 0, 0, 0,
+ 0,0x8FE2, 0, 0, 0,0xE8DF, 0, 0,
+ 0,0x8B66, 0, 0,0xE8E2, 0, 0,0xE8E1,
+ 0,0xE8E0, 0, 0,0xE691, 0,0x95DA, 0,
+ 0, 0, 0, 0,0xE8E3,0xE8E4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE8E5, 0, 0,0xE8E6,
+ 0,0xE8E7, 0, 0,0xE8E8, 0, 0, 0,
+ 0, 0, 0, 0,0x8AD8, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xE8E9, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE8EA,0x9442,
+ 0, 0, 0,0xE8EC,0x89B9, 0,0xE8EF,0xE8EE,
+ 0, 0, 0, 0,0x8943, 0, 0, 0,
+0x8BBF, 0,0x95C5,0x92B8,0x8DA0, 0,0x8D80,0x8F87,
+ 0,0x907B, 0, 0, 0,0xE8F1, 0, 0,
+0xE8F0,0x9761,0x8AE6,0x94D0,0x93DA, 0, 0, 0,
+0x909C,0x97CC, 0,0x8C7A, 0, 0, 0, 0,
+ 0, 0,0xE8F4, 0, 0,0xE8F3, 0, 0,
+ 0, 0, 0, 0, 0,0x966A,0x93AA, 0,
+ 0, 0, 0, 0, 0,0x896F, 0, 0,
+0xE8F5,0xE8F2, 0, 0,0x9570,0x978A,0xE8F6, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE8F7,
+ 0, 0, 0, 0,0xE8F9,0x91E8,0x8A7A,0x8A7B,
+0xE8F8, 0, 0, 0, 0,0x8AE7,0x8CB0, 0,
+0xFBF4,0x8AE8, 0, 0,0x935E, 0, 0,0x97DE,
+ 0, 0, 0, 0, 0, 0,0xFBF5, 0,
+0x8CDA, 0, 0, 0,0xE8FA, 0, 0, 0,
+0xE8FB,0xE8FC,0xE940, 0,0xE942,0xE941, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x9597, 0,0xE943, 0, 0, 0, 0,
+0xE944, 0,0xE945, 0, 0, 0, 0,0xE946,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE948,0xE947, 0,0xE949,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x94F2,0xE3CA, 0, 0,
+0x9048, 0, 0,0x8B51, 0, 0, 0, 0,
+ 0, 0,0xE94A, 0,0xE94B, 0,0x99AA,0x9F5A,
+0x94D1, 0, 0,0x88F9, 0,0x88B9, 0, 0,
+ 0, 0, 0, 0, 0,0x8E94,0x964F,0x8FFC,
+ 0, 0, 0, 0,0xE94C, 0,0x96DD, 0,
+ 0, 0,0xE94D,0x977B, 0,0x8961, 0, 0,
+ 0,0x8E60, 0,0xE94E,0x89EC,0xE94F, 0, 0,
+ 0,0xE950, 0, 0, 0, 0,0xE952,0xE953,
+ 0,0xE955,0xE951, 0, 0,0xE954, 0, 0,
+0xFBF8,0x8AD9, 0, 0, 0,0xE956, 0,0xE957,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE958,0xE959,
+ 0, 0, 0,0xE95A, 0, 0,0xE95C, 0,
+ 0, 0,0xE95B, 0,0xE95E,0xE961, 0, 0,
+ 0,0xE95D,0xE95F,0xE960, 0, 0,0xE962, 0,
+0x8BC0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x8EF1,
+0xE963,0xE964,0x8D81, 0, 0, 0, 0,0xFBFA,
+ 0, 0, 0, 0, 0, 0,0xE965, 0,
+ 0,0x8A5D, 0, 0, 0,0x946E,0xE966,0xE967,
+ 0, 0, 0, 0,0x9279,0x93E9, 0, 0,
+ 0, 0, 0, 0, 0,0xE968, 0, 0,
+ 0, 0,0x949D, 0, 0,0x91CA,0x8977,0x8BEC,
+ 0,0x8BED, 0, 0, 0, 0, 0, 0,
+ 0,0x9293,0xE96D,0x8BEE, 0, 0,0x89ED, 0,
+ 0,0xE96C, 0, 0,0xE96A, 0,0xE96B, 0,
+0xE969, 0, 0,0xE977, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xE96E,0xE96F,
+ 0, 0,0xE970,0xE971, 0, 0, 0, 0,
+ 0,0xE973, 0, 0,0xE972, 0, 0, 0,
+0x8F78, 0,0xE974, 0, 0, 0,0xE976, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x8B52,
+0xE975, 0, 0,0x919B,0x8CB1, 0, 0, 0,
+ 0, 0,0xE978, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x91CB, 0, 0,0xE979, 0, 0, 0,
+ 0,0x93AB, 0, 0, 0, 0, 0, 0,
+0xE97A, 0, 0, 0, 0, 0, 0,0xE980,
+ 0,0xE97D, 0,0xE97C,0xE97E, 0,0xE97B, 0,
+ 0, 0, 0, 0, 0, 0,0xE982,0xFBFB,
+ 0, 0, 0, 0, 0, 0,0xE981, 0,
+0xE984, 0, 0,0x8BC1,0xE983, 0, 0, 0,
+0xE985, 0, 0,0xE986, 0,0xE988,0xE987, 0,
+ 0, 0,0xE989,0xE98B,0xE98A, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x8D9C, 0, 0, 0, 0,0xE98C, 0,
+ 0,0xE98D, 0, 0, 0, 0, 0, 0,
+ 0,0x8A5B, 0, 0, 0,0xE98E, 0, 0,
+ 0,0xE98F, 0, 0, 0,0x9091, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xE990, 0,0xE991, 0,0xE992,0xE993, 0, 0,
+ 0,0x8D82,0xFBFC, 0, 0,0xFC40, 0,0xE994,
+0xE995, 0, 0,0xE996,0xE997, 0, 0,0xE998,
+ 0, 0, 0,0x94AF,0xE99A, 0,0x9545,0xE99B,
+0xE999, 0,0xE99D, 0, 0,0xE99C, 0, 0,
+0xE99E, 0, 0, 0,0xE99F, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE9A0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xE9A1, 0,0xE9A2, 0, 0, 0, 0,
+0xE9A3, 0, 0,0xE9A4,0xE9A5, 0,0xE9A6, 0,
+0xE9A7,0xE9A8,0xE9A9,0xE9AA, 0, 0, 0,0xE9AB,
+0xE9AC, 0,0x9F54,0xE9AD, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE2F6,0x8B53, 0, 0,
+ 0, 0,0x8A40,0x8DB0,0xE9AF,0xE9AE,0x96A3, 0,
+ 0, 0, 0, 0, 0, 0,0xE9B1,0xE9B2,
+0xE9B0, 0,0xE9B3, 0, 0,0x9682, 0, 0,
+ 0,0xE9B4, 0,0x8B9B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x9844, 0, 0,0xFC42, 0,0xE9B5,0xFC41, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE9B7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x88BC,
+0xFC43, 0,0xE9B8,0x95A9,0xE9B6, 0, 0,0xE9B9,
+0xE9BA, 0, 0, 0, 0, 0, 0, 0,
+0xE9BB,0xE9BC, 0, 0, 0, 0, 0, 0,
+ 0,0xE9BD, 0,0x968E,0x8E4C, 0,0x8DF8,0x914E,
+ 0, 0,0xFC44, 0, 0,0xE9BE, 0, 0,
+ 0, 0,0xE9C1, 0,0xFC45, 0, 0, 0,
+ 0,0xE9BF, 0, 0, 0, 0, 0,0xE9C2,
+ 0, 0,0x8CEF,0xE9C0, 0, 0, 0, 0,
+0xE9C3, 0,0xE9C4,0xE9C5, 0,0xE9C9, 0,0x8E49,
+ 0, 0, 0, 0,0x91E2, 0, 0, 0,
+ 0, 0,0xE9CA,0xE9C7,0xE9C6,0xE9C8, 0, 0,
+ 0,0x8C7E, 0, 0, 0, 0, 0, 0,
+ 0,0xE9CE,0xE9CD,0xE9CC, 0, 0,0x88B1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xFC46, 0, 0, 0,0xE9D8, 0,0xE9D4,
+ 0,0xE9D5,0xE9D1,0xE9D7, 0,0xE9D3,0x8A82, 0,
+ 0,0x986B, 0,0xE9D6,0xE9D2,0xE9D0,0xE9CF, 0,
+ 0, 0, 0, 0,0xE9DA, 0, 0, 0,
+ 0, 0,0xE9DD, 0, 0,0xE9DC,0xE9DB, 0,
+ 0, 0, 0, 0, 0, 0,0x9568,0xE9D9,
+0x88F1,0xE9DE, 0,0xE9E0, 0, 0, 0, 0,
+ 0, 0,0x8A8F,0xE9CB,0x8956, 0, 0,0xE9E2,
+ 0, 0, 0, 0, 0, 0, 0,0xE9E1,
+0xE9DF,0x924C, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x9690, 0, 0, 0, 0,
+0x97D8, 0, 0,0xE9E3, 0, 0, 0, 0,
+ 0,0xE9E4, 0, 0, 0, 0, 0, 0,
+0xE9E5, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xE9E6,
+ 0,0xE9E7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x92B9, 0,
+0xE9E8, 0,0x94B5, 0,0xE9ED,0xE9E9, 0, 0,
+ 0,0xE9EA, 0, 0,0x9650,0x96C2, 0,0x93CE,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xE9EE, 0, 0,0xE9EF,
+0x93BC,0xE9EC,0xE9EB, 0, 0, 0, 0,0x89A8,
+ 0, 0, 0,0xE9F7, 0, 0,0xE9F6, 0,
+ 0, 0, 0, 0,0x8995, 0, 0, 0,
+0xE9F4, 0, 0, 0,0xE9F3, 0, 0,0xE9F1,
+ 0,0x8A9B, 0,0xE9F0,0x8EB0,0x89A7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x8D83, 0, 0,0xE9FA,
+0xE9F9, 0,0xE9F8, 0, 0,0xE9F5, 0,0xE9FB,
+ 0,0xE9FC, 0, 0, 0, 0, 0, 0,
+ 0,0xEA44,0xEA43, 0, 0, 0, 0, 0,
+ 0, 0,0xEA45, 0, 0,0x894C,0xEA40,0xEA41,
+ 0,0x8D94,0x96B7, 0, 0,0xEA42, 0, 0,
+ 0, 0, 0, 0,0xFC48,0x9651, 0, 0,
+0xEA4A,0xFC47, 0,0xEA46, 0, 0, 0, 0,
+ 0, 0, 0,0xEA4B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xEA48, 0,0xEA47, 0, 0, 0, 0, 0,
+0x8C7B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xEA4C, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xEA4D, 0, 0,
+ 0, 0,0xEA4E, 0,0xEA49, 0, 0, 0,
+0xE9F2, 0, 0,0xEA4F, 0,0x92DF, 0, 0,
+ 0,0xEA53, 0,0xEA54,0xEA52, 0, 0, 0,
+ 0, 0,0xEA51,0xEA57, 0,0xEA50, 0,0xEA55,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xEA56, 0, 0, 0,0xEA59, 0, 0, 0,
+ 0, 0,0xEA58, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0xEA5B,
+ 0, 0, 0, 0, 0, 0,0xEA5C, 0,
+0xEA5D, 0, 0,0x9868, 0, 0, 0, 0,
+ 0,0xEA5A,0x91E9,0x8DEB, 0, 0,0xEA5E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0xFC4A,0xEA5F,0xEA60, 0, 0,0xEA61,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xEA62, 0,
+ 0,0x8CB2,0xEA63, 0, 0, 0,0xEA64, 0,
+0x8EAD, 0,0xEA65, 0, 0, 0, 0, 0,
+ 0,0xEA66, 0, 0,0xEA67,0xEA68, 0, 0,
+ 0, 0,0xEA6B,0xEA69,0x985B, 0,0xEA6A, 0,
+0x97ED, 0, 0, 0, 0, 0,0xEA6C, 0,
+0x97D9, 0, 0, 0, 0, 0,0xEA6D,0x949E,
+ 0, 0,0xEA6E,0xEA70, 0, 0,0xEA71, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xEA6F,0x8D8D,0x96CB,0x9683,0x9BF5, 0,0x9F80,
+0x969B, 0, 0, 0, 0,0x89A9, 0, 0,
+ 0, 0, 0, 0, 0,0xEA73,0x8B6F,0xEA74,
+0xEA75,0xEA76,0xFC4B,0x8D95, 0,0xEA77, 0, 0,
+ 0,0xE0D2,0x96D9, 0,0x91E1,0xEA78,0xEA7A,0xEA79,
+ 0,0xEA7B, 0, 0, 0, 0,0xEA7C, 0,
+ 0,0xEA7D, 0, 0, 0, 0, 0, 0,
+0xEA7E, 0, 0, 0, 0,0xEA80, 0,0xEA81,
+0xEA82, 0,0xEA83, 0,0xEA84,0xEA85,0xEA86, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xEA87,0xEA88, 0, 0, 0, 0, 0,0x9343,
+ 0, 0, 0, 0,0x8CDB, 0,0xEA8A, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x916C,0xEA8B, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0xEA8C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x9540, 0, 0,0xEA8D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0xEA8E,0xE256, 0, 0,0xE6D8,
+0xE8EB, 0, 0,0xEA8F, 0,0xEA90, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0xEA92,0xEA93,0xEA94,0x97EE,0xEA91, 0, 0,0xEA95,
+0xEA96, 0, 0,0xEA98, 0,0xEA97, 0, 0,
+ 0, 0, 0,0xEA9A, 0, 0, 0,0xEA9B,
+0xEA99, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x97B4, 0,
+ 0, 0, 0, 0, 0, 0,0xEA9C, 0,
+ 0, 0, 0, 0, 0,0xEA9D,0xE273, 0,
+ 0,0xEA9E};
+
+/* page 8 0xE000-0xE757 - User defined characters */
+static uint16 tab_uni_cp9328[]={
+0xF040,0xF041,0xF042,0xF043,0xF044,0xF045,0xF046,0xF047,
+0xF048,0xF049,0xF04A,0xF04B,0xF04C,0xF04D,0xF04E,0xF04F,
+0xF050,0xF051,0xF052,0xF053,0xF054,0xF055,0xF056,0xF057,
+0xF058,0xF059,0xF05A,0xF05B,0xF05C,0xF05D,0xF05E,0xF05F,
+0xF060,0xF061,0xF062,0xF063,0xF064,0xF065,0xF066,0xF067,
+0xF068,0xF069,0xF06A,0xF06B,0xF06C,0xF06D,0xF06E,0xF06F,
+0xF070,0xF071,0xF072,0xF073,0xF074,0xF075,0xF076,0xF077,
+0xF078,0xF079,0xF07A,0xF07B,0xF07C,0xF07D,0xF07E,0xF080,
+0xF081,0xF082,0xF083,0xF084,0xF085,0xF086,0xF087,0xF088,
+0xF089,0xF08A,0xF08B,0xF08C,0xF08D,0xF08E,0xF08F,0xF090,
+0xF091,0xF092,0xF093,0xF094,0xF095,0xF096,0xF097,0xF098,
+0xF099,0xF09A,0xF09B,0xF09C,0xF09D,0xF09E,0xF09F,0xF0A0,
+0xF0A1,0xF0A2,0xF0A3,0xF0A4,0xF0A5,0xF0A6,0xF0A7,0xF0A8,
+0xF0A9,0xF0AA,0xF0AB,0xF0AC,0xF0AD,0xF0AE,0xF0AF,0xF0B0,
+0xF0B1,0xF0B2,0xF0B3,0xF0B4,0xF0B5,0xF0B6,0xF0B7,0xF0B8,
+0xF0B9,0xF0BA,0xF0BB,0xF0BC,0xF0BD,0xF0BE,0xF0BF,0xF0C0,
+0xF0C1,0xF0C2,0xF0C3,0xF0C4,0xF0C5,0xF0C6,0xF0C7,0xF0C8,
+0xF0C9,0xF0CA,0xF0CB,0xF0CC,0xF0CD,0xF0CE,0xF0CF,0xF0D0,
+0xF0D1,0xF0D2,0xF0D3,0xF0D4,0xF0D5,0xF0D6,0xF0D7,0xF0D8,
+0xF0D9,0xF0DA,0xF0DB,0xF0DC,0xF0DD,0xF0DE,0xF0DF,0xF0E0,
+0xF0E1,0xF0E2,0xF0E3,0xF0E4,0xF0E5,0xF0E6,0xF0E7,0xF0E8,
+0xF0E9,0xF0EA,0xF0EB,0xF0EC,0xF0ED,0xF0EE,0xF0EF,0xF0F0,
+0xF0F1,0xF0F2,0xF0F3,0xF0F4,0xF0F5,0xF0F6,0xF0F7,0xF0F8,
+0xF0F9,0xF0FA,0xF0FB,0xF0FC,0xF140,0xF141,0xF142,0xF143,
+0xF144,0xF145,0xF146,0xF147,0xF148,0xF149,0xF14A,0xF14B,
+0xF14C,0xF14D,0xF14E,0xF14F,0xF150,0xF151,0xF152,0xF153,
+0xF154,0xF155,0xF156,0xF157,0xF158,0xF159,0xF15A,0xF15B,
+0xF15C,0xF15D,0xF15E,0xF15F,0xF160,0xF161,0xF162,0xF163,
+0xF164,0xF165,0xF166,0xF167,0xF168,0xF169,0xF16A,0xF16B,
+0xF16C,0xF16D,0xF16E,0xF16F,0xF170,0xF171,0xF172,0xF173,
+0xF174,0xF175,0xF176,0xF177,0xF178,0xF179,0xF17A,0xF17B,
+0xF17C,0xF17D,0xF17E,0xF180,0xF181,0xF182,0xF183,0xF184,
+0xF185,0xF186,0xF187,0xF188,0xF189,0xF18A,0xF18B,0xF18C,
+0xF18D,0xF18E,0xF18F,0xF190,0xF191,0xF192,0xF193,0xF194,
+0xF195,0xF196,0xF197,0xF198,0xF199,0xF19A,0xF19B,0xF19C,
+0xF19D,0xF19E,0xF19F,0xF1A0,0xF1A1,0xF1A2,0xF1A3,0xF1A4,
+0xF1A5,0xF1A6,0xF1A7,0xF1A8,0xF1A9,0xF1AA,0xF1AB,0xF1AC,
+0xF1AD,0xF1AE,0xF1AF,0xF1B0,0xF1B1,0xF1B2,0xF1B3,0xF1B4,
+0xF1B5,0xF1B6,0xF1B7,0xF1B8,0xF1B9,0xF1BA,0xF1BB,0xF1BC,
+0xF1BD,0xF1BE,0xF1BF,0xF1C0,0xF1C1,0xF1C2,0xF1C3,0xF1C4,
+0xF1C5,0xF1C6,0xF1C7,0xF1C8,0xF1C9,0xF1CA,0xF1CB,0xF1CC,
+0xF1CD,0xF1CE,0xF1CF,0xF1D0,0xF1D1,0xF1D2,0xF1D3,0xF1D4,
+0xF1D5,0xF1D6,0xF1D7,0xF1D8,0xF1D9,0xF1DA,0xF1DB,0xF1DC,
+0xF1DD,0xF1DE,0xF1DF,0xF1E0,0xF1E1,0xF1E2,0xF1E3,0xF1E4,
+0xF1E5,0xF1E6,0xF1E7,0xF1E8,0xF1E9,0xF1EA,0xF1EB,0xF1EC,
+0xF1ED,0xF1EE,0xF1EF,0xF1F0,0xF1F1,0xF1F2,0xF1F3,0xF1F4,
+0xF1F5,0xF1F6,0xF1F7,0xF1F8,0xF1F9,0xF1FA,0xF1FB,0xF1FC,
+0xF240,0xF241,0xF242,0xF243,0xF244,0xF245,0xF246,0xF247,
+0xF248,0xF249,0xF24A,0xF24B,0xF24C,0xF24D,0xF24E,0xF24F,
+0xF250,0xF251,0xF252,0xF253,0xF254,0xF255,0xF256,0xF257,
+0xF258,0xF259,0xF25A,0xF25B,0xF25C,0xF25D,0xF25E,0xF25F,
+0xF260,0xF261,0xF262,0xF263,0xF264,0xF265,0xF266,0xF267,
+0xF268,0xF269,0xF26A,0xF26B,0xF26C,0xF26D,0xF26E,0xF26F,
+0xF270,0xF271,0xF272,0xF273,0xF274,0xF275,0xF276,0xF277,
+0xF278,0xF279,0xF27A,0xF27B,0xF27C,0xF27D,0xF27E,0xF280,
+0xF281,0xF282,0xF283,0xF284,0xF285,0xF286,0xF287,0xF288,
+0xF289,0xF28A,0xF28B,0xF28C,0xF28D,0xF28E,0xF28F,0xF290,
+0xF291,0xF292,0xF293,0xF294,0xF295,0xF296,0xF297,0xF298,
+0xF299,0xF29A,0xF29B,0xF29C,0xF29D,0xF29E,0xF29F,0xF2A0,
+0xF2A1,0xF2A2,0xF2A3,0xF2A4,0xF2A5,0xF2A6,0xF2A7,0xF2A8,
+0xF2A9,0xF2AA,0xF2AB,0xF2AC,0xF2AD,0xF2AE,0xF2AF,0xF2B0,
+0xF2B1,0xF2B2,0xF2B3,0xF2B4,0xF2B5,0xF2B6,0xF2B7,0xF2B8,
+0xF2B9,0xF2BA,0xF2BB,0xF2BC,0xF2BD,0xF2BE,0xF2BF,0xF2C0,
+0xF2C1,0xF2C2,0xF2C3,0xF2C4,0xF2C5,0xF2C6,0xF2C7,0xF2C8,
+0xF2C9,0xF2CA,0xF2CB,0xF2CC,0xF2CD,0xF2CE,0xF2CF,0xF2D0,
+0xF2D1,0xF2D2,0xF2D3,0xF2D4,0xF2D5,0xF2D6,0xF2D7,0xF2D8,
+0xF2D9,0xF2DA,0xF2DB,0xF2DC,0xF2DD,0xF2DE,0xF2DF,0xF2E0,
+0xF2E1,0xF2E2,0xF2E3,0xF2E4,0xF2E5,0xF2E6,0xF2E7,0xF2E8,
+0xF2E9,0xF2EA,0xF2EB,0xF2EC,0xF2ED,0xF2EE,0xF2EF,0xF2F0,
+0xF2F1,0xF2F2,0xF2F3,0xF2F4,0xF2F5,0xF2F6,0xF2F7,0xF2F8,
+0xF2F9,0xF2FA,0xF2FB,0xF2FC,0xF340,0xF341,0xF342,0xF343,
+0xF344,0xF345,0xF346,0xF347,0xF348,0xF349,0xF34A,0xF34B,
+0xF34C,0xF34D,0xF34E,0xF34F,0xF350,0xF351,0xF352,0xF353,
+0xF354,0xF355,0xF356,0xF357,0xF358,0xF359,0xF35A,0xF35B,
+0xF35C,0xF35D,0xF35E,0xF35F,0xF360,0xF361,0xF362,0xF363,
+0xF364,0xF365,0xF366,0xF367,0xF368,0xF369,0xF36A,0xF36B,
+0xF36C,0xF36D,0xF36E,0xF36F,0xF370,0xF371,0xF372,0xF373,
+0xF374,0xF375,0xF376,0xF377,0xF378,0xF379,0xF37A,0xF37B,
+0xF37C,0xF37D,0xF37E,0xF380,0xF381,0xF382,0xF383,0xF384,
+0xF385,0xF386,0xF387,0xF388,0xF389,0xF38A,0xF38B,0xF38C,
+0xF38D,0xF38E,0xF38F,0xF390,0xF391,0xF392,0xF393,0xF394,
+0xF395,0xF396,0xF397,0xF398,0xF399,0xF39A,0xF39B,0xF39C,
+0xF39D,0xF39E,0xF39F,0xF3A0,0xF3A1,0xF3A2,0xF3A3,0xF3A4,
+0xF3A5,0xF3A6,0xF3A7,0xF3A8,0xF3A9,0xF3AA,0xF3AB,0xF3AC,
+0xF3AD,0xF3AE,0xF3AF,0xF3B0,0xF3B1,0xF3B2,0xF3B3,0xF3B4,
+0xF3B5,0xF3B6,0xF3B7,0xF3B8,0xF3B9,0xF3BA,0xF3BB,0xF3BC,
+0xF3BD,0xF3BE,0xF3BF,0xF3C0,0xF3C1,0xF3C2,0xF3C3,0xF3C4,
+0xF3C5,0xF3C6,0xF3C7,0xF3C8,0xF3C9,0xF3CA,0xF3CB,0xF3CC,
+0xF3CD,0xF3CE,0xF3CF,0xF3D0,0xF3D1,0xF3D2,0xF3D3,0xF3D4,
+0xF3D5,0xF3D6,0xF3D7,0xF3D8,0xF3D9,0xF3DA,0xF3DB,0xF3DC,
+0xF3DD,0xF3DE,0xF3DF,0xF3E0,0xF3E1,0xF3E2,0xF3E3,0xF3E4,
+0xF3E5,0xF3E6,0xF3E7,0xF3E8,0xF3E9,0xF3EA,0xF3EB,0xF3EC,
+0xF3ED,0xF3EE,0xF3EF,0xF3F0,0xF3F1,0xF3F2,0xF3F3,0xF3F4,
+0xF3F5,0xF3F6,0xF3F7,0xF3F8,0xF3F9,0xF3FA,0xF3FB,0xF3FC,
+0xF440,0xF441,0xF442,0xF443,0xF444,0xF445,0xF446,0xF447,
+0xF448,0xF449,0xF44A,0xF44B,0xF44C,0xF44D,0xF44E,0xF44F,
+0xF450,0xF451,0xF452,0xF453,0xF454,0xF455,0xF456,0xF457,
+0xF458,0xF459,0xF45A,0xF45B,0xF45C,0xF45D,0xF45E,0xF45F,
+0xF460,0xF461,0xF462,0xF463,0xF464,0xF465,0xF466,0xF467,
+0xF468,0xF469,0xF46A,0xF46B,0xF46C,0xF46D,0xF46E,0xF46F,
+0xF470,0xF471,0xF472,0xF473,0xF474,0xF475,0xF476,0xF477,
+0xF478,0xF479,0xF47A,0xF47B,0xF47C,0xF47D,0xF47E,0xF480,
+0xF481,0xF482,0xF483,0xF484,0xF485,0xF486,0xF487,0xF488,
+0xF489,0xF48A,0xF48B,0xF48C,0xF48D,0xF48E,0xF48F,0xF490,
+0xF491,0xF492,0xF493,0xF494,0xF495,0xF496,0xF497,0xF498,
+0xF499,0xF49A,0xF49B,0xF49C,0xF49D,0xF49E,0xF49F,0xF4A0,
+0xF4A1,0xF4A2,0xF4A3,0xF4A4,0xF4A5,0xF4A6,0xF4A7,0xF4A8,
+0xF4A9,0xF4AA,0xF4AB,0xF4AC,0xF4AD,0xF4AE,0xF4AF,0xF4B0,
+0xF4B1,0xF4B2,0xF4B3,0xF4B4,0xF4B5,0xF4B6,0xF4B7,0xF4B8,
+0xF4B9,0xF4BA,0xF4BB,0xF4BC,0xF4BD,0xF4BE,0xF4BF,0xF4C0,
+0xF4C1,0xF4C2,0xF4C3,0xF4C4,0xF4C5,0xF4C6,0xF4C7,0xF4C8,
+0xF4C9,0xF4CA,0xF4CB,0xF4CC,0xF4CD,0xF4CE,0xF4CF,0xF4D0,
+0xF4D1,0xF4D2,0xF4D3,0xF4D4,0xF4D5,0xF4D6,0xF4D7,0xF4D8,
+0xF4D9,0xF4DA,0xF4DB,0xF4DC,0xF4DD,0xF4DE,0xF4DF,0xF4E0,
+0xF4E1,0xF4E2,0xF4E3,0xF4E4,0xF4E5,0xF4E6,0xF4E7,0xF4E8,
+0xF4E9,0xF4EA,0xF4EB,0xF4EC,0xF4ED,0xF4EE,0xF4EF,0xF4F0,
+0xF4F1,0xF4F2,0xF4F3,0xF4F4,0xF4F5,0xF4F6,0xF4F7,0xF4F8,
+0xF4F9,0xF4FA,0xF4FB,0xF4FC,0xF540,0xF541,0xF542,0xF543,
+0xF544,0xF545,0xF546,0xF547,0xF548,0xF549,0xF54A,0xF54B,
+0xF54C,0xF54D,0xF54E,0xF54F,0xF550,0xF551,0xF552,0xF553,
+0xF554,0xF555,0xF556,0xF557,0xF558,0xF559,0xF55A,0xF55B,
+0xF55C,0xF55D,0xF55E,0xF55F,0xF560,0xF561,0xF562,0xF563,
+0xF564,0xF565,0xF566,0xF567,0xF568,0xF569,0xF56A,0xF56B,
+0xF56C,0xF56D,0xF56E,0xF56F,0xF570,0xF571,0xF572,0xF573,
+0xF574,0xF575,0xF576,0xF577,0xF578,0xF579,0xF57A,0xF57B,
+0xF57C,0xF57D,0xF57E,0xF580,0xF581,0xF582,0xF583,0xF584,
+0xF585,0xF586,0xF587,0xF588,0xF589,0xF58A,0xF58B,0xF58C,
+0xF58D,0xF58E,0xF58F,0xF590,0xF591,0xF592,0xF593,0xF594,
+0xF595,0xF596,0xF597,0xF598,0xF599,0xF59A,0xF59B,0xF59C,
+0xF59D,0xF59E,0xF59F,0xF5A0,0xF5A1,0xF5A2,0xF5A3,0xF5A4,
+0xF5A5,0xF5A6,0xF5A7,0xF5A8,0xF5A9,0xF5AA,0xF5AB,0xF5AC,
+0xF5AD,0xF5AE,0xF5AF,0xF5B0,0xF5B1,0xF5B2,0xF5B3,0xF5B4,
+0xF5B5,0xF5B6,0xF5B7,0xF5B8,0xF5B9,0xF5BA,0xF5BB,0xF5BC,
+0xF5BD,0xF5BE,0xF5BF,0xF5C0,0xF5C1,0xF5C2,0xF5C3,0xF5C4,
+0xF5C5,0xF5C6,0xF5C7,0xF5C8,0xF5C9,0xF5CA,0xF5CB,0xF5CC,
+0xF5CD,0xF5CE,0xF5CF,0xF5D0,0xF5D1,0xF5D2,0xF5D3,0xF5D4,
+0xF5D5,0xF5D6,0xF5D7,0xF5D8,0xF5D9,0xF5DA,0xF5DB,0xF5DC,
+0xF5DD,0xF5DE,0xF5DF,0xF5E0,0xF5E1,0xF5E2,0xF5E3,0xF5E4,
+0xF5E5,0xF5E6,0xF5E7,0xF5E8,0xF5E9,0xF5EA,0xF5EB,0xF5EC,
+0xF5ED,0xF5EE,0xF5EF,0xF5F0,0xF5F1,0xF5F2,0xF5F3,0xF5F4,
+0xF5F5,0xF5F6,0xF5F7,0xF5F8,0xF5F9,0xF5FA,0xF5FB,0xF5FC,
+0xF640,0xF641,0xF642,0xF643,0xF644,0xF645,0xF646,0xF647,
+0xF648,0xF649,0xF64A,0xF64B,0xF64C,0xF64D,0xF64E,0xF64F,
+0xF650,0xF651,0xF652,0xF653,0xF654,0xF655,0xF656,0xF657,
+0xF658,0xF659,0xF65A,0xF65B,0xF65C,0xF65D,0xF65E,0xF65F,
+0xF660,0xF661,0xF662,0xF663,0xF664,0xF665,0xF666,0xF667,
+0xF668,0xF669,0xF66A,0xF66B,0xF66C,0xF66D,0xF66E,0xF66F,
+0xF670,0xF671,0xF672,0xF673,0xF674,0xF675,0xF676,0xF677,
+0xF678,0xF679,0xF67A,0xF67B,0xF67C,0xF67D,0xF67E,0xF680,
+0xF681,0xF682,0xF683,0xF684,0xF685,0xF686,0xF687,0xF688,
+0xF689,0xF68A,0xF68B,0xF68C,0xF68D,0xF68E,0xF68F,0xF690,
+0xF691,0xF692,0xF693,0xF694,0xF695,0xF696,0xF697,0xF698,
+0xF699,0xF69A,0xF69B,0xF69C,0xF69D,0xF69E,0xF69F,0xF6A0,
+0xF6A1,0xF6A2,0xF6A3,0xF6A4,0xF6A5,0xF6A6,0xF6A7,0xF6A8,
+0xF6A9,0xF6AA,0xF6AB,0xF6AC,0xF6AD,0xF6AE,0xF6AF,0xF6B0,
+0xF6B1,0xF6B2,0xF6B3,0xF6B4,0xF6B5,0xF6B6,0xF6B7,0xF6B8,
+0xF6B9,0xF6BA,0xF6BB,0xF6BC,0xF6BD,0xF6BE,0xF6BF,0xF6C0,
+0xF6C1,0xF6C2,0xF6C3,0xF6C4,0xF6C5,0xF6C6,0xF6C7,0xF6C8,
+0xF6C9,0xF6CA,0xF6CB,0xF6CC,0xF6CD,0xF6CE,0xF6CF,0xF6D0,
+0xF6D1,0xF6D2,0xF6D3,0xF6D4,0xF6D5,0xF6D6,0xF6D7,0xF6D8,
+0xF6D9,0xF6DA,0xF6DB,0xF6DC,0xF6DD,0xF6DE,0xF6DF,0xF6E0,
+0xF6E1,0xF6E2,0xF6E3,0xF6E4,0xF6E5,0xF6E6,0xF6E7,0xF6E8,
+0xF6E9,0xF6EA,0xF6EB,0xF6EC,0xF6ED,0xF6EE,0xF6EF,0xF6F0,
+0xF6F1,0xF6F2,0xF6F3,0xF6F4,0xF6F5,0xF6F6,0xF6F7,0xF6F8,
+0xF6F9,0xF6FA,0xF6FB,0xF6FC,0xF740,0xF741,0xF742,0xF743,
+0xF744,0xF745,0xF746,0xF747,0xF748,0xF749,0xF74A,0xF74B,
+0xF74C,0xF74D,0xF74E,0xF74F,0xF750,0xF751,0xF752,0xF753,
+0xF754,0xF755,0xF756,0xF757,0xF758,0xF759,0xF75A,0xF75B,
+0xF75C,0xF75D,0xF75E,0xF75F,0xF760,0xF761,0xF762,0xF763,
+0xF764,0xF765,0xF766,0xF767,0xF768,0xF769,0xF76A,0xF76B,
+0xF76C,0xF76D,0xF76E,0xF76F,0xF770,0xF771,0xF772,0xF773,
+0xF774,0xF775,0xF776,0xF777,0xF778,0xF779,0xF77A,0xF77B,
+0xF77C,0xF77D,0xF77E,0xF780,0xF781,0xF782,0xF783,0xF784,
+0xF785,0xF786,0xF787,0xF788,0xF789,0xF78A,0xF78B,0xF78C,
+0xF78D,0xF78E,0xF78F,0xF790,0xF791,0xF792,0xF793,0xF794,
+0xF795,0xF796,0xF797,0xF798,0xF799,0xF79A,0xF79B,0xF79C,
+0xF79D,0xF79E,0xF79F,0xF7A0,0xF7A1,0xF7A2,0xF7A3,0xF7A4,
+0xF7A5,0xF7A6,0xF7A7,0xF7A8,0xF7A9,0xF7AA,0xF7AB,0xF7AC,
+0xF7AD,0xF7AE,0xF7AF,0xF7B0,0xF7B1,0xF7B2,0xF7B3,0xF7B4,
+0xF7B5,0xF7B6,0xF7B7,0xF7B8,0xF7B9,0xF7BA,0xF7BB,0xF7BC,
+0xF7BD,0xF7BE,0xF7BF,0xF7C0,0xF7C1,0xF7C2,0xF7C3,0xF7C4,
+0xF7C5,0xF7C6,0xF7C7,0xF7C8,0xF7C9,0xF7CA,0xF7CB,0xF7CC,
+0xF7CD,0xF7CE,0xF7CF,0xF7D0,0xF7D1,0xF7D2,0xF7D3,0xF7D4,
+0xF7D5,0xF7D6,0xF7D7,0xF7D8,0xF7D9,0xF7DA,0xF7DB,0xF7DC,
+0xF7DD,0xF7DE,0xF7DF,0xF7E0,0xF7E1,0xF7E2,0xF7E3,0xF7E4,
+0xF7E5,0xF7E6,0xF7E7,0xF7E8,0xF7E9,0xF7EA,0xF7EB,0xF7EC,
+0xF7ED,0xF7EE,0xF7EF,0xF7F0,0xF7F1,0xF7F2,0xF7F3,0xF7F4,
+0xF7F5,0xF7F6,0xF7F7,0xF7F8,0xF7F9,0xF7FA,0xF7FB,0xF7FC,
+0xF840,0xF841,0xF842,0xF843,0xF844,0xF845,0xF846,0xF847,
+0xF848,0xF849,0xF84A,0xF84B,0xF84C,0xF84D,0xF84E,0xF84F,
+0xF850,0xF851,0xF852,0xF853,0xF854,0xF855,0xF856,0xF857,
+0xF858,0xF859,0xF85A,0xF85B,0xF85C,0xF85D,0xF85E,0xF85F,
+0xF860,0xF861,0xF862,0xF863,0xF864,0xF865,0xF866,0xF867,
+0xF868,0xF869,0xF86A,0xF86B,0xF86C,0xF86D,0xF86E,0xF86F,
+0xF870,0xF871,0xF872,0xF873,0xF874,0xF875,0xF876,0xF877,
+0xF878,0xF879,0xF87A,0xF87B,0xF87C,0xF87D,0xF87E,0xF880,
+0xF881,0xF882,0xF883,0xF884,0xF885,0xF886,0xF887,0xF888,
+0xF889,0xF88A,0xF88B,0xF88C,0xF88D,0xF88E,0xF88F,0xF890,
+0xF891,0xF892,0xF893,0xF894,0xF895,0xF896,0xF897,0xF898,
+0xF899,0xF89A,0xF89B,0xF89C,0xF89D,0xF89E,0xF89F,0xF8A0,
+0xF8A1,0xF8A2,0xF8A3,0xF8A4,0xF8A5,0xF8A6,0xF8A7,0xF8A8,
+0xF8A9,0xF8AA,0xF8AB,0xF8AC,0xF8AD,0xF8AE,0xF8AF,0xF8B0,
+0xF8B1,0xF8B2,0xF8B3,0xF8B4,0xF8B5,0xF8B6,0xF8B7,0xF8B8,
+0xF8B9,0xF8BA,0xF8BB,0xF8BC,0xF8BD,0xF8BE,0xF8BF,0xF8C0,
+0xF8C1,0xF8C2,0xF8C3,0xF8C4,0xF8C5,0xF8C6,0xF8C7,0xF8C8,
+0xF8C9,0xF8CA,0xF8CB,0xF8CC,0xF8CD,0xF8CE,0xF8CF,0xF8D0,
+0xF8D1,0xF8D2,0xF8D3,0xF8D4,0xF8D5,0xF8D6,0xF8D7,0xF8D8,
+0xF8D9,0xF8DA,0xF8DB,0xF8DC,0xF8DD,0xF8DE,0xF8DF,0xF8E0,
+0xF8E1,0xF8E2,0xF8E3,0xF8E4,0xF8E5,0xF8E6,0xF8E7,0xF8E8,
+0xF8E9,0xF8EA,0xF8EB,0xF8EC,0xF8ED,0xF8EE,0xF8EF,0xF8F0,
+0xF8F1,0xF8F2,0xF8F3,0xF8F4,0xF8F5,0xF8F6,0xF8F7,0xF8F8,
+0xF8F9,0xF8FA,0xF8FB,0xF8FC,0xF940,0xF941,0xF942,0xF943,
+0xF944,0xF945,0xF946,0xF947,0xF948,0xF949,0xF94A,0xF94B,
+0xF94C,0xF94D,0xF94E,0xF94F,0xF950,0xF951,0xF952,0xF953,
+0xF954,0xF955,0xF956,0xF957,0xF958,0xF959,0xF95A,0xF95B,
+0xF95C,0xF95D,0xF95E,0xF95F,0xF960,0xF961,0xF962,0xF963,
+0xF964,0xF965,0xF966,0xF967,0xF968,0xF969,0xF96A,0xF96B,
+0xF96C,0xF96D,0xF96E,0xF96F,0xF970,0xF971,0xF972,0xF973,
+0xF974,0xF975,0xF976,0xF977,0xF978,0xF979,0xF97A,0xF97B,
+0xF97C,0xF97D,0xF97E,0xF980,0xF981,0xF982,0xF983,0xF984,
+0xF985,0xF986,0xF987,0xF988,0xF989,0xF98A,0xF98B,0xF98C,
+0xF98D,0xF98E,0xF98F,0xF990,0xF991,0xF992,0xF993,0xF994,
+0xF995,0xF996,0xF997,0xF998,0xF999,0xF99A,0xF99B,0xF99C,
+0xF99D,0xF99E,0xF99F,0xF9A0,0xF9A1,0xF9A2,0xF9A3,0xF9A4,
+0xF9A5,0xF9A6,0xF9A7,0xF9A8,0xF9A9,0xF9AA,0xF9AB,0xF9AC,
+0xF9AD,0xF9AE,0xF9AF,0xF9B0,0xF9B1,0xF9B2,0xF9B3,0xF9B4,
+0xF9B5,0xF9B6,0xF9B7,0xF9B8,0xF9B9,0xF9BA,0xF9BB,0xF9BC,
+0xF9BD,0xF9BE,0xF9BF,0xF9C0,0xF9C1,0xF9C2,0xF9C3,0xF9C4,
+0xF9C5,0xF9C6,0xF9C7,0xF9C8,0xF9C9,0xF9CA,0xF9CB,0xF9CC,
+0xF9CD,0xF9CE,0xF9CF,0xF9D0,0xF9D1,0xF9D2,0xF9D3,0xF9D4,
+0xF9D5,0xF9D6,0xF9D7,0xF9D8,0xF9D9,0xF9DA,0xF9DB,0xF9DC,
+0xF9DD,0xF9DE,0xF9DF,0xF9E0,0xF9E1,0xF9E2,0xF9E3,0xF9E4,
+0xF9E5,0xF9E6,0xF9E7,0xF9E8,0xF9E9,0xF9EA,0xF9EB,0xF9EC,
+0xF9ED,0xF9EE,0xF9EF,0xF9F0,0xF9F1,0xF9F2,0xF9F3,0xF9F4,
+0xF9F5,0xF9F6,0xF9F7,0xF9F8,0xF9F9,0xF9FA,0xF9FB,0xF9FC};
+
+/* page 9 0xF920-0xFA2D */
+static uint16 tab_uni_cp9329[]={
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xFAE0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0xFBE9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0xFA90,0xFA9B,
+0xFA9C,0xFAB1,0xFAD8,0xFAE8,0xFAEA,0xFB58,0xFB5E,0xFB75,
+0xFB7D,0xFB7E,0xFB80,0xFB82,0xFB86,0xFB89,0xFB92,0xFB9D,
+0xFB9F,0xFBA0,0xFBA9,0xFBB1,0xFBB3,0xFBB4,0xFBB7,0xFBD3,
+0xFBDA,0xFBEA,0xFBF6,0xFBF7,0xFBF9,0xFC49};
+
+/* page 10 0xFF01-0xFFE5 */
+static uint16 tab_uni_cp93210[]={
+0x8149,0xFA57,0x8194,0x8190,0x8193,0x8195,0xFA56,0x8169,
+0x816A,0x8196,0x817B,0x8143,0x817C,0x8144,0x815E,0x824F,
+0x8250,0x8251,0x8252,0x8253,0x8254,0x8255,0x8256,0x8257,
+0x8258,0x8146,0x8147,0x8183,0x8181,0x8184,0x8148,0x8197,
+0x8260,0x8261,0x8262,0x8263,0x8264,0x8265,0x8266,0x8267,
+0x8268,0x8269,0x826A,0x826B,0x826C,0x826D,0x826E,0x826F,
+0x8270,0x8271,0x8272,0x8273,0x8274,0x8275,0x8276,0x8277,
+0x8278,0x8279,0x816D,0x815F,0x816E,0x814F,0x8151,0x814D,
+0x8281,0x8282,0x8283,0x8284,0x8285,0x8286,0x8287,0x8288,
+0x8289,0x828A,0x828B,0x828C,0x828D,0x828E,0x828F,0x8290,
+0x8291,0x8292,0x8293,0x8294,0x8295,0x8296,0x8297,0x8298,
+0x8299,0x829A,0x816F,0x8162,0x8170,0x8160, 0, 0,
+0x00A1,0x00A2,0x00A3,0x00A4,0x00A5,0x00A6,0x00A7,0x00A8,
+0x00A9,0x00AA,0x00AB,0x00AC,0x00AD,0x00AE,0x00AF,0x00B0,
+0x00B1,0x00B2,0x00B3,0x00B4,0x00B5,0x00B6,0x00B7,0x00B8,
+0x00B9,0x00BA,0x00BB,0x00BC,0x00BD,0x00BE,0x00BF,0x00C0,
+0x00C1,0x00C2,0x00C3,0x00C4,0x00C5,0x00C6,0x00C7,0x00C8,
+0x00C9,0x00CA,0x00CB,0x00CC,0x00CD,0x00CE,0x00CF,0x00D0,
+0x00D1,0x00D2,0x00D3,0x00D4,0x00D5,0x00D6,0x00D7,0x00D8,
+0x00D9,0x00DA,0x00DB,0x00DC,0x00DD,0x00DE,0x00DF, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x8191,
+0x8192,0x81CA,0x8150,0xFA55,0x818F};
+
+static int func_uni_cp932_onechar(int code){
+ if ((code>=0x005C)&&(code<=0x00F7))
+ return(tab_uni_cp9320[code-0x005C]);
+ if ((code>=0x0391)&&(code<=0x0451))
+ return(tab_uni_cp9321[code-0x0391]);
+ if ((code>=0x2010)&&(code<=0x2473))
+ return(tab_uni_cp9322[code-0x2010]);
+ if ((code>=0x2500)&&(code<=0x266F))
+ return(tab_uni_cp9323[code-0x2500]);
+ if ((code>=0x3000)&&(code<=0x30FE))
+ return(tab_uni_cp9324[code-0x3000]);
+ if ((code>=0x3230)&&(code<=0x33CD))
+ return(tab_uni_cp9325[code-0x3230]);
+ if ((code>=0x4E00)&&(code<=0x9481))
+ return(tab_uni_cp9326[code-0x4E00]);
+ if ((code>=0x9577)&&(code<=0x9FA0))
+ return(tab_uni_cp9327[code-0x9577]);
+ if ((code>=0xE000)&&(code<=0xE757))
+ return(tab_uni_cp9328[code-0xE000]);
+ if ((code>=0xF920)&&(code<=0xFA2D))
+ return(tab_uni_cp9329[code-0xF920]);
+ if ((code>=0xFF01)&&(code<=0xFFE5))
+ return(tab_uni_cp93210[code-0xFF01]);
+ return(0);
+}
+
+
+static int
+my_wc_mb_cp932(CHARSET_INFO *cs __attribute__((unused)),
+ my_wc_t wc, uchar *s, uchar *e)
+{
+ int code;
+
+ if (s >= e)
+ return MY_CS_TOOSMALL;
+
+ if ((int) wc < 0x80)
+ {
+ s[0]= (uchar) wc;
+ return 1;
+ }
+
+ if (!(code=func_uni_cp932_onechar(wc)))
+ return MY_CS_ILUNI;
+
+ if (code>=0xA1 && code <= 0xDF)
+ {
+ s[0]= code;
+ return 1;
+ }
+
+ s[0]=code>>8;
+ s[1]=code&0xFF;
+ return 2;
+}
+
+
+static int
+my_mb_wc_cp932(CHARSET_INFO *cs __attribute__((unused)),
+ my_wc_t *pwc, const uchar *s, const uchar *e){
+ int hi=s[0];
+
+ if (s >= e)
+ return MY_CS_TOOFEW(0);
+
+ if (hi < 0x80)
+ {
+ pwc[0]=hi;
+ return 1;
+ }
+
+ if (hi >= 0xA1 && hi <= 0xDF)
+ {
+ pwc[0]= func_cp932_uni_onechar(hi);
+ return 1;
+ }
+
+ if (s+2>e)
+ return MY_CS_TOOFEW(0);
+
+ if (!(pwc[0]=func_cp932_uni_onechar((hi<<8)+s[1])))
+ return MY_CS_ILSEQ;
+
+ return 2;
+}
+
+static
+uint my_numcells_cp932(CHARSET_INFO *cs __attribute__((unused)),
+ const char *str, const char *strend)
+{
+ uint clen= 0;
+ const unsigned char *b= (const unsigned char *) str;
+ const unsigned char *e= (const unsigned char *) strend;
+
+ for (clen= 0; b < e; )
+ {
+ if (*b >= 0xA1 && *b <= 0xDF)
+ {
+ clen++;
+ b++;
+ }
+ else if (*b > 0x7F)
+ {
+ clen+= 2;
+ b+= 2;
+ }
+ else
+ {
+ clen++;
+ b++;
+ }
+ }
+ return clen;
+}
+
+/*
+ Returns a well formed length of a cp932 string.
+ cp932 additional characters are also accepted.
+*/
+static
+uint my_well_formed_len_cp932(CHARSET_INFO *cs __attribute__((unused)),
+ const char *b, const char *e, uint pos, int *error)
+{
+ const char *b0= b;
+ *error= 0;
+ while (pos && b < e)
+ {
+ /*
+ Cast to int8 for extra safety.
+ "char" can be unsigned by default
+ on some platforms.
+ */
+ if (((int8)b[0]) >= 0)
+ {
+ /* Single byte ascii character */
+ b++;
+ }
+ else if (iscp932head((uchar)*b) && (e-b)>1 && iscp932tail((uchar)b[1]))
+ {
+ /* Double byte character */
+ b+= 2;
+ }
+ else if (((uchar)*b) >= 0xA1 && ((uchar)*b) <= 0xDF)
+ {
+ /* Half width kana */
+ b++;
+ }
+ else
+ {
+ /* Wrong byte sequence */
+ *error= 1;
+ break;
+ }
+ }
+ return b - b0;
+}
+
+
+static MY_COLLATION_HANDLER my_collation_ci_handler =
+{
+ NULL, /* init */
+ my_strnncoll_cp932,
+ my_strnncollsp_cp932,
+ my_strnxfrm_cp932,
+ my_strnxfrmlen_simple,
+ my_like_range_cp932,
+ my_wildcmp_mb, /* wildcmp */
+ my_strcasecmp_8bit,
+ my_instr_mb,
+ my_hash_sort_simple,
+};
+
+
+static MY_CHARSET_HANDLER my_charset_handler=
+{
+ NULL, /* init */
+ ismbchar_cp932,
+ mbcharlen_cp932,
+ my_numchars_mb,
+ my_charpos_mb,
+ my_well_formed_len_cp932,
+ my_lengthsp_8bit,
+ my_numcells_cp932,
+ my_mb_wc_cp932, /* mb_wc */
+ my_wc_mb_cp932, /* wc_mb */
+ my_caseup_str_8bit,
+ my_casedn_str_8bit,
+ my_caseup_8bit,
+ my_casedn_8bit,
+ my_snprintf_8bit,
+ my_long10_to_str_8bit,
+ my_longlong10_to_str_8bit,
+ my_fill_8bit,
+ my_strntol_8bit,
+ my_strntoul_8bit,
+ my_strntoll_8bit,
+ my_strntoull_8bit,
+ my_strntod_8bit,
+ my_strtoll10_8bit,
+ my_scan_8bit
+};
+
+
+CHARSET_INFO my_charset_cp932_japanese_ci=
+{
+ 95,0,0, /* number */
+ MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM, /* state */
+ "cp932", /* cs name */
+ "cp932_japanese_ci", /* name */
+ "", /* comment */
+ NULL, /* tailoring */
+ ctype_cp932,
+ to_lower_cp932,
+ to_upper_cp932,
+ sort_order_cp932,
+ NULL, /* contractions */
+ NULL, /* sort_order_big*/
+ NULL, /* tab_to_uni */
+ NULL, /* tab_from_uni */
+ NULL, /* state_map */
+ NULL, /* ident_map */
+ 1, /* strxfrm_multiply */
+ 1, /* mbminlen */
+ 2, /* mbmaxlen */
+ 0, /* min_sort_char */
+ 255, /* max_sort_char */
+ &my_charset_handler,
+ &my_collation_ci_handler
+};
+
+CHARSET_INFO my_charset_cp932_bin=
+{
+ 96,0,0, /* number */
+ MY_CS_COMPILED|MY_CS_BINSORT, /* state */
+ "cp932", /* cs name */
+ "cp932_bin", /* name */
+ "", /* comment */
+ NULL, /* tailoring */
+ ctype_cp932,
+ to_lower_cp932,
+ to_upper_cp932,
+ NULL, /* sort_order */
+ NULL, /* contractions */
+ NULL, /* sort_order_big*/
+ NULL, /* tab_to_uni */
+ NULL, /* tab_from_uni */
+ NULL, /* state_map */
+ NULL, /* ident_map */
+ 1, /* strxfrm_multiply */
+ 1, /* mbminlen */
+ 2, /* mbmaxlen */
+ 0, /* min_sort_char */
+ 255, /* max_sort_char */
+ &my_charset_handler,
+ &my_collation_mb_bin_handler
+};
+
+#endif
diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c
index 5725e81b15e..f5a410afc50 100644
--- a/strings/ctype-czech.c
+++ b/strings/ctype-czech.c
@@ -275,8 +275,10 @@ static int my_strnncoll_czech(CHARSET_INFO *cs __attribute__((unused)),
static
int my_strnncollsp_czech(CHARSET_INFO * cs,
- const uchar *s, uint slen,
- const uchar *t, uint tlen)
+ const uchar *s, uint slen,
+ const uchar *t, uint tlen,
+ my_bool diff_if_only_endspace_difference
+ __attribute__((unused)))
{
for ( ; slen && s[slen-1] == ' ' ; slen--);
for ( ; tlen && t[tlen-1] == ' ' ; tlen--);
@@ -354,7 +356,7 @@ static int my_strnxfrm_czech(CHARSET_INFO *cs __attribute__((unused)),
#ifdef REAL_MYSQL
-#define min_sort_char ' '
+#define min_sort_char 0
#define max_sort_char '9'
#define EXAMPLE
@@ -393,8 +395,17 @@ static my_bool my_like_range_czech(CHARSET_INFO *cs __attribute__((unused)),
*min_str++= *max_str++ = *ptr;
}
- *min_length= (uint) (min_str - min_org);
+
+ if (cs->state & MY_CS_BINSORT)
+ *min_length= (uint) (min_str - min_org);
+ else
+ {
+ /* 'a\0\0... is the smallest possible string */
+ *min_length= res_length;
+ }
+ /* a\ff\ff... is the biggest possible string */
*max_length= res_length;
+
while (min_str != min_end)
{
*min_str++ = min_sort_char; /* Because of key compression */
@@ -582,6 +593,7 @@ static MY_COLLATION_HANDLER my_collation_latin2_czech_ci_handler =
my_strnncoll_czech,
my_strnncollsp_czech,
my_strnxfrm_czech,
+ my_strnxfrmlen_simple,
my_like_range_czech,
my_wildcmp_8bit,
my_strcasecmp_8bit,
diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c
index ee792d9c3e4..289b7309ea0 100644
--- a/strings/ctype-euc_kr.c
+++ b/strings/ctype-euc_kr.c
@@ -8641,6 +8641,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler =
my_strnncoll_simple, /* strnncoll */
my_strnncollsp_simple,
my_strnxfrm_simple, /* strnxfrm */
+ my_strnxfrmlen_simple,
my_like_range_simple, /* like_range */
my_wildcmp_mb, /* wildcmp */
my_strcasecmp_mb,
diff --git a/strings/ctype-eucjpms.c b/strings/ctype-eucjpms.c
new file mode 100644
index 00000000000..ab12446754a
--- /dev/null
+++ b/strings/ctype-eucjpms.c
@@ -0,0 +1,8740 @@
+/* Copyright (C) 2002 MySQL AB & tommy@valley.ne.jp.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* This file is for Japanese EUC charset, and created based on
+ctype-ujis.c file.
+ */
+
+/*
+ * This comment is parsed by configure to create ctype.c,
+ * so don't change it unless you know what you are doing.
+ *
+ * .configure. mbmaxlen_eucjpms=3
+ */
+
+#include <my_global.h>
+#include "m_string.h"
+#include "m_ctype.h"
+
+#ifdef HAVE_CHARSET_eucjpms
+
+
+static uchar NEAR ctype_eucjpms[257] =
+{
+ 0, /* For standard library */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* NUL ^A - ^G */
+ 0040, 0050, 0050, 0050, 0050, 0050, 0040, 0040, /* ^H - ^O */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^P - ^W */
+ 0040, 0040, 0040, 0040, 0040, 0040, 0040, 0040, /* ^X - ^Z ^[ ^\ ^] ^^ ^_ */
+ 0110, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* SPC ! " # $ % ^ ' */
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020, /* ( ) * + , - . / */
+ 0204, 0204, 0204, 0204, 0204, 0204, 0204, 0204, /* 0 1 2 3 4 5 6 7 */
+ 0204, 0204, 0020, 0020, 0020, 0020, 0020, 0020, /* 8 9 : ; < = > ? */
+ 0020, 0201, 0201, 0201, 0201, 0201, 0201, 0001, /* @ A B C D E F G */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* H I J K L M N O */
+ 0001, 0001, 0001, 0001, 0001, 0001, 0001, 0001, /* P Q R S T U V W */
+ 0001, 0001, 0001, 0020, 0020, 0020, 0020, 0020, /* X Y Z [ \ ] ^ _ */
+ 0020, 0202, 0202, 0202, 0202, 0202, 0202, 0002, /* ` a b c d e f g */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* h i j k l m n o */
+ 0002, 0002, 0002, 0002, 0002, 0002, 0002, 0002, /* p q r s t u v w */
+ 0002, 0002, 0002, 0020, 0020, 0020, 0020, 0040, /* x y z { | } + DEL */
+ 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
+ 0000, 0000, 0000, 0000, 0000, 0000, 0020, 0020,
+ 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
+ 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
+ 0000, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0020,
+ 0020, 0020, 0020, 0020, 0020, 0020, 0020, 0000,
+};
+
+static uchar NEAR to_lower_eucjpms[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '[', '\\', ']', '^', '_',
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377'
+};
+
+static uchar NEAR to_upper_eucjpms[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375',(uchar) '\376',(uchar) '\377'
+};
+
+static uchar NEAR sort_order_eucjpms[]=
+{
+ '\000','\001','\002','\003','\004','\005','\006','\007',
+ '\010','\011','\012','\013','\014','\015','\016','\017',
+ '\020','\021','\022','\023','\024','\025','\026','\027',
+ '\030','\031','\032','\033','\034','\035','\036','\037',
+ ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '{', '|', '}', '~', '\177',
+ (uchar) '\200',(uchar) '\201',(uchar) '\202',(uchar) '\203',(uchar) '\204',(uchar) '\205',(uchar) '\206',(uchar) '\207',
+ (uchar) '\210',(uchar) '\211',(uchar) '\212',(uchar) '\213',(uchar) '\214',(uchar) '\215',(uchar) '\216',(uchar) '\217',
+ (uchar) '\220',(uchar) '\221',(uchar) '\222',(uchar) '\223',(uchar) '\224',(uchar) '\225',(uchar) '\226',(uchar) '\227',
+ (uchar) '\230',(uchar) '\231',(uchar) '\232',(uchar) '\233',(uchar) '\234',(uchar) '\235',(uchar) '\236',(uchar) '\237',
+ (uchar) '\240',(uchar) '\241',(uchar) '\242',(uchar) '\243',(uchar) '\244',(uchar) '\245',(uchar) '\246',(uchar) '\247',
+ (uchar) '\250',(uchar) '\251',(uchar) '\252',(uchar) '\253',(uchar) '\254',(uchar) '\255',(uchar) '\256',(uchar) '\257',
+ (uchar) '\260',(uchar) '\261',(uchar) '\262',(uchar) '\263',(uchar) '\264',(uchar) '\265',(uchar) '\266',(uchar) '\267',
+ (uchar) '\270',(uchar) '\271',(uchar) '\272',(uchar) '\273',(uchar) '\274',(uchar) '\275',(uchar) '\276',(uchar) '\277',
+ (uchar) '\300',(uchar) '\301',(uchar) '\302',(uchar) '\303',(uchar) '\304',(uchar) '\305',(uchar) '\306',(uchar) '\307',
+ (uchar) '\310',(uchar) '\311',(uchar) '\312',(uchar) '\313',(uchar) '\314',(uchar) '\315',(uchar) '\316',(uchar) '\317',
+ (uchar) '\320',(uchar) '\321',(uchar) '\322',(uchar) '\323',(uchar) '\324',(uchar) '\325',(uchar) '\326',(uchar) '\327',
+ (uchar) '\330',(uchar) '\331',(uchar) '\332',(uchar) '\333',(uchar) '\334',(uchar) '\335',(uchar) '\336',(uchar) '\337',
+ (uchar) '\340',(uchar) '\341',(uchar) '\342',(uchar) '\343',(uchar) '\344',(uchar) '\345',(uchar) '\346',(uchar) '\347',
+ (uchar) '\350',(uchar) '\351',(uchar) '\352',(uchar) '\353',(uchar) '\354',(uchar) '\355',(uchar) '\356',(uchar) '\357',
+ (uchar) '\360',(uchar) '\361',(uchar) '\362',(uchar) '\363',(uchar) '\364',(uchar) '\365',(uchar) '\366',(uchar) '\367',
+ (uchar) '\370',(uchar) '\371',(uchar) '\372',(uchar) '\373',(uchar) '\374',(uchar) '\375', (uchar) (uchar) '\376', (uchar) '\377'
+};
+
+
+#define iseucjpms(c) ((0xa1<=((c)&0xff) && ((c)&0xff)<=0xfe))
+#define iskata(c) ((0xa1<=((c)&0xff) && ((c)&0xff)<=0xdf))
+#define iseucjpms_ss2(c) (((c)&0xff) == 0x8e)
+#define iseucjpms_ss3(c) (((c)&0xff) == 0x8f)
+
+
+static int ismbchar_eucjpms(CHARSET_INFO *cs __attribute__((unused)),
+ const char* p, const char *e)
+{
+ return ((*(uchar*)(p)<0x80)? 0:\
+ iseucjpms(*(p)) && (e)-(p)>1 && iseucjpms(*((p)+1))? 2:\
+ iseucjpms_ss2(*(p)) && (e)-(p)>1 && iskata(*((p)+1))? 2:\
+ iseucjpms_ss3(*(p)) && (e)-(p)>2 && iseucjpms(*((p)+1)) && iseucjpms(*((p)+2))? 3:\
+ 0);
+}
+
+static int mbcharlen_eucjpms(CHARSET_INFO *cs __attribute__((unused)),uint c)
+{
+ return (iseucjpms(c)? 2: iseucjpms_ss2(c)? 2: iseucjpms_ss3(c)? 3: 1);
+}
+
+
+static uint16 tab_jisx0201_uni[256]={
+ 0,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
+0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F,
+0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
+0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0xFF61,0xFF62,0xFF63,0xFF64,0xFF65,0xFF66,0xFF67,
+0xFF68,0xFF69,0xFF6A,0xFF6B,0xFF6C,0xFF6D,0xFF6E,0xFF6F,
+0xFF70,0xFF71,0xFF72,0xFF73,0xFF74,0xFF75,0xFF76,0xFF77,
+0xFF78,0xFF79,0xFF7A,0xFF7B,0xFF7C,0xFF7D,0xFF7E,0xFF7F,
+0xFF80,0xFF81,0xFF82,0xFF83,0xFF84,0xFF85,0xFF86,0xFF87,
+0xFF88,0xFF89,0xFF8A,0xFF8B,0xFF8C,0xFF8D,0xFF8E,0xFF8F,
+0xFF90,0xFF91,0xFF92,0xFF93,0xFF94,0xFF95,0xFF96,0xFF97,
+0xFF98,0xFF99,0xFF9A,0xFF9B,0xFF9C,0xFF9D,0xFF9E,0xFF9F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+static int
+my_mb_wc_jisx0201(CHARSET_INFO *cs __attribute__((unused)),
+ my_wc_t *wc,const uchar *s,
+ const uchar *e __attribute__((unused)))
+{
+ wc[0]=tab_jisx0201_uni[*s];
+ return (!wc[0] && s[0]) ? MY_CS_ILSEQ : 1;
+}
+
+
+static int
+my_wc_mb_jisx0201(CHARSET_INFO *cs __attribute__((unused)),
+ my_wc_t wc, uchar *s,
+ uchar *e __attribute__((unused)))
+{
+
+ if ((int) wc <= 0x7D)
+ {
+ *s = (uchar) wc;
+ return (wc == 0x5C) ? MY_CS_ILUNI : 1;
+ }
+
+ if (wc >= 0xFF61 && wc <= 0xFF9F)
+ {
+ *s = (uchar) (wc - 0xFEC0);
+ return 1;
+ }
+
+ return MY_CS_ILUNI;
+}
+
+
+/* page 0 0x2121-0x217E */
+static uint16 tab_jisx0208_uni0[]={
+0x3000,0x3001,0x3002,0xFF0C,0xFF0E,0x30FB,0xFF1A,0xFF1B,
+0xFF1F,0xFF01,0x309B,0x309C,0x00B4,0xFF40,0x00A8,0xFF3E,
+0xFFE3,0xFF3F,0x30FD,0x30FE,0x309D,0x309E,0x3003,0x4EDD,
+0x3005,0x3006,0x3007,0x30FC,0x2015,0x2010,0xFF0F,0xFF3C,
+0xFF5E,0x2225,0xFF5C,0x2026,0x2025,0x2018,0x2019,0x201C,
+0x201D,0xFF08,0xFF09,0x3014,0x3015,0xFF3B,0xFF3D,0xFF5B,
+0xFF5D,0x3008,0x3009,0x300A,0x300B,0x300C,0x300D,0x300E,
+0x300F,0x3010,0x3011,0xFF0B,0xFF0D,0x00B1,0x00D7,0x00F7,
+0xFF1D,0x2260,0xFF1C,0xFF1E,0x2266,0x2267,0x221E,0x2234,
+0x2642,0x2640,0x00B0,0x2032,0x2033,0x2103,0xFFE5,0xFF04,
+0xFFE0,0xFFE1,0xFF05,0xFF03,0xFF06,0xFF0A,0xFF20,0x00A7,
+0x2606,0x2605,0x25CB,0x25CF,0x25CE,0x25C7};
+
+/* page 1 0x2221-0x227E */
+static uint16 tab_jisx0208_uni1[]={
+0x25C6,0x25A1,0x25A0,0x25B3,0x25B2,0x25BD,0x25BC,0x203B,
+0x3012,0x2192,0x2190,0x2191,0x2193,0x3013, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x2208,0x220B,0x2286,0x2287,0x2282,0x2283,0x222A,
+0x2229, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x2227,0x2228,0xFFE2,0x21D2,0x21D4,0x2200,0x2203,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x2220,0x22A5,0x2312,0x2202,0x2207,
+0x2261,0x2252,0x226A,0x226B,0x221A,0x223D,0x221D,0x2235,
+0x222B,0x222C, 0, 0, 0, 0, 0, 0,
+ 0,0x212B,0x2030,0x266F,0x266D,0x266A,0x2020,0x2021,
+0x00B6, 0, 0, 0, 0,0x25EF};
+
+/* page 2 0x2330-0x237A */
+static uint16 tab_jisx0208_uni2[]={
+0xFF10,0xFF11,0xFF12,0xFF13,0xFF14,0xFF15,0xFF16,0xFF17,
+0xFF18,0xFF19, 0, 0, 0, 0, 0, 0,
+ 0,0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,
+0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,
+0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,
+0xFF38,0xFF39,0xFF3A, 0, 0, 0, 0, 0,
+ 0,0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,
+0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,
+0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,
+0xFF58,0xFF59,0xFF5A};
+
+/* page 3 0x2421-0x2473 */
+static uint16 tab_jisx0208_uni3[]={
+0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,0x3048,
+0x3049,0x304A,0x304B,0x304C,0x304D,0x304E,0x304F,0x3050,
+0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058,
+0x3059,0x305A,0x305B,0x305C,0x305D,0x305E,0x305F,0x3060,
+0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,
+0x3069,0x306A,0x306B,0x306C,0x306D,0x306E,0x306F,0x3070,
+0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,
+0x3079,0x307A,0x307B,0x307C,0x307D,0x307E,0x307F,0x3080,
+0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,
+0x3089,0x308A,0x308B,0x308C,0x308D,0x308E,0x308F,0x3090,
+0x3091,0x3092,0x3093};
+
+/* page 4 0x2521-0x2576 */
+static uint16 tab_jisx0208_uni4[]={
+0x30A1,0x30A2,0x30A3,0x30A4,0x30A5,0x30A6,0x30A7,0x30A8,
+0x30A9,0x30AA,0x30AB,0x30AC,0x30AD,0x30AE,0x30AF,0x30B0,
+0x30B1,0x30B2,0x30B3,0x30B4,0x30B5,0x30B6,0x30B7,0x30B8,
+0x30B9,0x30BA,0x30BB,0x30BC,0x30BD,0x30BE,0x30BF,0x30C0,
+0x30C1,0x30C2,0x30C3,0x30C4,0x30C5,0x30C6,0x30C7,0x30C8,
+0x30C9,0x30CA,0x30CB,0x30CC,0x30CD,0x30CE,0x30CF,0x30D0,
+0x30D1,0x30D2,0x30D3,0x30D4,0x30D5,0x30D6,0x30D7,0x30D8,
+0x30D9,0x30DA,0x30DB,0x30DC,0x30DD,0x30DE,0x30DF,0x30E0,
+0x30E1,0x30E2,0x30E3,0x30E4,0x30E5,0x30E6,0x30E7,0x30E8,
+0x30E9,0x30EA,0x30EB,0x30EC,0x30ED,0x30EE,0x30EF,0x30F0,
+0x30F1,0x30F2,0x30F3,0x30F4,0x30F5,0x30F6};
+
+/* page 5 0x2621-0x2658 */
+static uint16 tab_jisx0208_uni5[]={
+0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,
+0x0399,0x039A,0x039B,0x039C,0x039D,0x039E,0x039F,0x03A0,
+0x03A1,0x03A3,0x03A4,0x03A5,0x03A6,0x03A7,0x03A8,0x03A9,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x03B1,0x03B2,0x03B3,0x03B4,0x03B5,0x03B6,0x03B7,0x03B8,
+0x03B9,0x03BA,0x03BB,0x03BC,0x03BD,0x03BE,0x03BF,0x03C0,
+0x03C1,0x03C3,0x03C4,0x03C5,0x03C6,0x03C7,0x03C8,0x03C9
+};
+
+/* page 6 0x2721-0x2771 */
+static uint16 tab_jisx0208_uni6[]={
+0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,0x0416,
+0x0417,0x0418,0x0419,0x041A,0x041B,0x041C,0x041D,0x041E,
+0x041F,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,
+0x0427,0x0428,0x0429,0x042A,0x042B,0x042C,0x042D,0x042E,
+0x042F, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,
+0x0437,0x0438,0x0439,0x043A,0x043B,0x043C,0x043D,0x043E,
+0x043F,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,
+0x0447,0x0448,0x0449,0x044A,0x044B,0x044C,0x044D,0x044E,
+0x044F};
+
+/* page 7 0x2821-0x2840 */
+static uint16 tab_jisx0208_uni7[]={
+0x2500,0x2502,0x250C,0x2510,0x2518,0x2514,0x251C,0x252C,
+0x2524,0x2534,0x253C,0x2501,0x2503,0x250F,0x2513,0x251B,
+0x2517,0x2523,0x2533,0x252B,0x253B,0x254B,0x2520,0x252F,
+0x2528,0x2537,0x253F,0x251D,0x2530,0x2525,0x2538,0x2542
+};
+
+/* page 8 0x3021-0x307E */
+static uint16 tab_jisx0208_uni8[]={
+0x4E9C,0x5516,0x5A03,0x963F,0x54C0,0x611B,0x6328,0x59F6,
+0x9022,0x8475,0x831C,0x7A50,0x60AA,0x63E1,0x6E25,0x65ED,
+0x8466,0x82A6,0x9BF5,0x6893,0x5727,0x65A1,0x6271,0x5B9B,
+0x59D0,0x867B,0x98F4,0x7D62,0x7DBE,0x9B8E,0x6216,0x7C9F,
+0x88B7,0x5B89,0x5EB5,0x6309,0x6697,0x6848,0x95C7,0x978D,
+0x674F,0x4EE5,0x4F0A,0x4F4D,0x4F9D,0x5049,0x56F2,0x5937,
+0x59D4,0x5A01,0x5C09,0x60DF,0x610F,0x6170,0x6613,0x6905,
+0x70BA,0x754F,0x7570,0x79FB,0x7DAD,0x7DEF,0x80C3,0x840E,
+0x8863,0x8B02,0x9055,0x907A,0x533B,0x4E95,0x4EA5,0x57DF,
+0x80B2,0x90C1,0x78EF,0x4E00,0x58F1,0x6EA2,0x9038,0x7A32,
+0x8328,0x828B,0x9C2F,0x5141,0x5370,0x54BD,0x54E1,0x56E0,
+0x59FB,0x5F15,0x98F2,0x6DEB,0x80E4,0x852D};
+
+/* page 9 0x3121-0x317E */
+static uint16 tab_jisx0208_uni9[]={
+0x9662,0x9670,0x96A0,0x97FB,0x540B,0x53F3,0x5B87,0x70CF,
+0x7FBD,0x8FC2,0x96E8,0x536F,0x9D5C,0x7ABA,0x4E11,0x7893,
+0x81FC,0x6E26,0x5618,0x5504,0x6B1D,0x851A,0x9C3B,0x59E5,
+0x53A9,0x6D66,0x74DC,0x958F,0x5642,0x4E91,0x904B,0x96F2,
+0x834F,0x990C,0x53E1,0x55B6,0x5B30,0x5F71,0x6620,0x66F3,
+0x6804,0x6C38,0x6CF3,0x6D29,0x745B,0x76C8,0x7A4E,0x9834,
+0x82F1,0x885B,0x8A60,0x92ED,0x6DB2,0x75AB,0x76CA,0x99C5,
+0x60A6,0x8B01,0x8D8A,0x95B2,0x698E,0x53AD,0x5186,0x5712,
+0x5830,0x5944,0x5BB4,0x5EF6,0x6028,0x63A9,0x63F4,0x6CBF,
+0x6F14,0x708E,0x7114,0x7159,0x71D5,0x733F,0x7E01,0x8276,
+0x82D1,0x8597,0x9060,0x925B,0x9D1B,0x5869,0x65BC,0x6C5A,
+0x7525,0x51F9,0x592E,0x5965,0x5F80,0x5FDC};
+
+/* page 10 0x3221-0x327E */
+static uint16 tab_jisx0208_uni10[]={
+0x62BC,0x65FA,0x6A2A,0x6B27,0x6BB4,0x738B,0x7FC1,0x8956,
+0x9D2C,0x9D0E,0x9EC4,0x5CA1,0x6C96,0x837B,0x5104,0x5C4B,
+0x61B6,0x81C6,0x6876,0x7261,0x4E59,0x4FFA,0x5378,0x6069,
+0x6E29,0x7A4F,0x97F3,0x4E0B,0x5316,0x4EEE,0x4F55,0x4F3D,
+0x4FA1,0x4F73,0x52A0,0x53EF,0x5609,0x590F,0x5AC1,0x5BB6,
+0x5BE1,0x79D1,0x6687,0x679C,0x67B6,0x6B4C,0x6CB3,0x706B,
+0x73C2,0x798D,0x79BE,0x7A3C,0x7B87,0x82B1,0x82DB,0x8304,
+0x8377,0x83EF,0x83D3,0x8766,0x8AB2,0x5629,0x8CA8,0x8FE6,
+0x904E,0x971E,0x868A,0x4FC4,0x5CE8,0x6211,0x7259,0x753B,
+0x81E5,0x82BD,0x86FE,0x8CC0,0x96C5,0x9913,0x99D5,0x4ECB,
+0x4F1A,0x89E3,0x56DE,0x584A,0x58CA,0x5EFB,0x5FEB,0x602A,
+0x6094,0x6062,0x61D0,0x6212,0x62D0,0x6539};
+
+/* page 11 0x3321-0x337E */
+static uint16 tab_jisx0208_uni11[]={
+0x9B41,0x6666,0x68B0,0x6D77,0x7070,0x754C,0x7686,0x7D75,
+0x82A5,0x87F9,0x958B,0x968E,0x8C9D,0x51F1,0x52BE,0x5916,
+0x54B3,0x5BB3,0x5D16,0x6168,0x6982,0x6DAF,0x788D,0x84CB,
+0x8857,0x8A72,0x93A7,0x9AB8,0x6D6C,0x99A8,0x86D9,0x57A3,
+0x67FF,0x86CE,0x920E,0x5283,0x5687,0x5404,0x5ED3,0x62E1,
+0x64B9,0x683C,0x6838,0x6BBB,0x7372,0x78BA,0x7A6B,0x899A,
+0x89D2,0x8D6B,0x8F03,0x90ED,0x95A3,0x9694,0x9769,0x5B66,
+0x5CB3,0x697D,0x984D,0x984E,0x639B,0x7B20,0x6A2B,0x6A7F,
+0x68B6,0x9C0D,0x6F5F,0x5272,0x559D,0x6070,0x62EC,0x6D3B,
+0x6E07,0x6ED1,0x845B,0x8910,0x8F44,0x4E14,0x9C39,0x53F6,
+0x691B,0x6A3A,0x9784,0x682A,0x515C,0x7AC3,0x84B2,0x91DC,
+0x938C,0x565B,0x9D28,0x6822,0x8305,0x8431};
+
+/* page 12 0x3421-0x347E */
+static uint16 tab_jisx0208_uni12[]={
+0x7CA5,0x5208,0x82C5,0x74E6,0x4E7E,0x4F83,0x51A0,0x5BD2,
+0x520A,0x52D8,0x52E7,0x5DFB,0x559A,0x582A,0x59E6,0x5B8C,
+0x5B98,0x5BDB,0x5E72,0x5E79,0x60A3,0x611F,0x6163,0x61BE,
+0x63DB,0x6562,0x67D1,0x6853,0x68FA,0x6B3E,0x6B53,0x6C57,
+0x6F22,0x6F97,0x6F45,0x74B0,0x7518,0x76E3,0x770B,0x7AFF,
+0x7BA1,0x7C21,0x7DE9,0x7F36,0x7FF0,0x809D,0x8266,0x839E,
+0x89B3,0x8ACC,0x8CAB,0x9084,0x9451,0x9593,0x9591,0x95A2,
+0x9665,0x97D3,0x9928,0x8218,0x4E38,0x542B,0x5CB8,0x5DCC,
+0x73A9,0x764C,0x773C,0x5CA9,0x7FEB,0x8D0B,0x96C1,0x9811,
+0x9854,0x9858,0x4F01,0x4F0E,0x5371,0x559C,0x5668,0x57FA,
+0x5947,0x5B09,0x5BC4,0x5C90,0x5E0C,0x5E7E,0x5FCC,0x63EE,
+0x673A,0x65D7,0x65E2,0x671F,0x68CB,0x68C4};
+
+/* page 13 0x3521-0x357E */
+static uint16 tab_jisx0208_uni13[]={
+0x6A5F,0x5E30,0x6BC5,0x6C17,0x6C7D,0x757F,0x7948,0x5B63,
+0x7A00,0x7D00,0x5FBD,0x898F,0x8A18,0x8CB4,0x8D77,0x8ECC,
+0x8F1D,0x98E2,0x9A0E,0x9B3C,0x4E80,0x507D,0x5100,0x5993,
+0x5B9C,0x622F,0x6280,0x64EC,0x6B3A,0x72A0,0x7591,0x7947,
+0x7FA9,0x87FB,0x8ABC,0x8B70,0x63AC,0x83CA,0x97A0,0x5409,
+0x5403,0x55AB,0x6854,0x6A58,0x8A70,0x7827,0x6775,0x9ECD,
+0x5374,0x5BA2,0x811A,0x8650,0x9006,0x4E18,0x4E45,0x4EC7,
+0x4F11,0x53CA,0x5438,0x5BAE,0x5F13,0x6025,0x6551,0x673D,
+0x6C42,0x6C72,0x6CE3,0x7078,0x7403,0x7A76,0x7AAE,0x7B08,
+0x7D1A,0x7CFE,0x7D66,0x65E7,0x725B,0x53BB,0x5C45,0x5DE8,
+0x62D2,0x62E0,0x6319,0x6E20,0x865A,0x8A31,0x8DDD,0x92F8,
+0x6F01,0x79A6,0x9B5A,0x4EA8,0x4EAB,0x4EAC};
+
+/* page 14 0x3621-0x367E */
+static uint16 tab_jisx0208_uni14[]={
+0x4F9B,0x4FA0,0x50D1,0x5147,0x7AF6,0x5171,0x51F6,0x5354,
+0x5321,0x537F,0x53EB,0x55AC,0x5883,0x5CE1,0x5F37,0x5F4A,
+0x602F,0x6050,0x606D,0x631F,0x6559,0x6A4B,0x6CC1,0x72C2,
+0x72ED,0x77EF,0x80F8,0x8105,0x8208,0x854E,0x90F7,0x93E1,
+0x97FF,0x9957,0x9A5A,0x4EF0,0x51DD,0x5C2D,0x6681,0x696D,
+0x5C40,0x66F2,0x6975,0x7389,0x6850,0x7C81,0x50C5,0x52E4,
+0x5747,0x5DFE,0x9326,0x65A4,0x6B23,0x6B3D,0x7434,0x7981,
+0x79BD,0x7B4B,0x7DCA,0x82B9,0x83CC,0x887F,0x895F,0x8B39,
+0x8FD1,0x91D1,0x541F,0x9280,0x4E5D,0x5036,0x53E5,0x533A,
+0x72D7,0x7396,0x77E9,0x82E6,0x8EAF,0x99C6,0x99C8,0x99D2,
+0x5177,0x611A,0x865E,0x55B0,0x7A7A,0x5076,0x5BD3,0x9047,
+0x9685,0x4E32,0x6ADB,0x91E7,0x5C51,0x5C48};
+
+/* page 15 0x3721-0x377E */
+static uint16 tab_jisx0208_uni15[]={
+0x6398,0x7A9F,0x6C93,0x9774,0x8F61,0x7AAA,0x718A,0x9688,
+0x7C82,0x6817,0x7E70,0x6851,0x936C,0x52F2,0x541B,0x85AB,
+0x8A13,0x7FA4,0x8ECD,0x90E1,0x5366,0x8888,0x7941,0x4FC2,
+0x50BE,0x5211,0x5144,0x5553,0x572D,0x73EA,0x578B,0x5951,
+0x5F62,0x5F84,0x6075,0x6176,0x6167,0x61A9,0x63B2,0x643A,
+0x656C,0x666F,0x6842,0x6E13,0x7566,0x7A3D,0x7CFB,0x7D4C,
+0x7D99,0x7E4B,0x7F6B,0x830E,0x834A,0x86CD,0x8A08,0x8A63,
+0x8B66,0x8EFD,0x981A,0x9D8F,0x82B8,0x8FCE,0x9BE8,0x5287,
+0x621F,0x6483,0x6FC0,0x9699,0x6841,0x5091,0x6B20,0x6C7A,
+0x6F54,0x7A74,0x7D50,0x8840,0x8A23,0x6708,0x4EF6,0x5039,
+0x5026,0x5065,0x517C,0x5238,0x5263,0x55A7,0x570F,0x5805,
+0x5ACC,0x5EFA,0x61B2,0x61F8,0x62F3,0x6372};
+
+/* page 16 0x3821-0x387E */
+static uint16 tab_jisx0208_uni16[]={
+0x691C,0x6A29,0x727D,0x72AC,0x732E,0x7814,0x786F,0x7D79,
+0x770C,0x80A9,0x898B,0x8B19,0x8CE2,0x8ED2,0x9063,0x9375,
+0x967A,0x9855,0x9A13,0x9E78,0x5143,0x539F,0x53B3,0x5E7B,
+0x5F26,0x6E1B,0x6E90,0x7384,0x73FE,0x7D43,0x8237,0x8A00,
+0x8AFA,0x9650,0x4E4E,0x500B,0x53E4,0x547C,0x56FA,0x59D1,
+0x5B64,0x5DF1,0x5EAB,0x5F27,0x6238,0x6545,0x67AF,0x6E56,
+0x72D0,0x7CCA,0x88B4,0x80A1,0x80E1,0x83F0,0x864E,0x8A87,
+0x8DE8,0x9237,0x96C7,0x9867,0x9F13,0x4E94,0x4E92,0x4F0D,
+0x5348,0x5449,0x543E,0x5A2F,0x5F8C,0x5FA1,0x609F,0x68A7,
+0x6A8E,0x745A,0x7881,0x8A9E,0x8AA4,0x8B77,0x9190,0x4E5E,
+0x9BC9,0x4EA4,0x4F7C,0x4FAF,0x5019,0x5016,0x5149,0x516C,
+0x529F,0x52B9,0x52FE,0x539A,0x53E3,0x5411};
+
+/* page 17 0x3921-0x397E */
+static uint16 tab_jisx0208_uni17[]={
+0x540E,0x5589,0x5751,0x57A2,0x597D,0x5B54,0x5B5D,0x5B8F,
+0x5DE5,0x5DE7,0x5DF7,0x5E78,0x5E83,0x5E9A,0x5EB7,0x5F18,
+0x6052,0x614C,0x6297,0x62D8,0x63A7,0x653B,0x6602,0x6643,
+0x66F4,0x676D,0x6821,0x6897,0x69CB,0x6C5F,0x6D2A,0x6D69,
+0x6E2F,0x6E9D,0x7532,0x7687,0x786C,0x7A3F,0x7CE0,0x7D05,
+0x7D18,0x7D5E,0x7DB1,0x8015,0x8003,0x80AF,0x80B1,0x8154,
+0x818F,0x822A,0x8352,0x884C,0x8861,0x8B1B,0x8CA2,0x8CFC,
+0x90CA,0x9175,0x9271,0x783F,0x92FC,0x95A4,0x964D,0x9805,
+0x9999,0x9AD8,0x9D3B,0x525B,0x52AB,0x53F7,0x5408,0x58D5,
+0x62F7,0x6FE0,0x8C6A,0x8F5F,0x9EB9,0x514B,0x523B,0x544A,
+0x56FD,0x7A40,0x9177,0x9D60,0x9ED2,0x7344,0x6F09,0x8170,
+0x7511,0x5FFD,0x60DA,0x9AA8,0x72DB,0x8FBC};
+
+/* page 18 0x3A21-0x3A7E */
+static uint16 tab_jisx0208_uni18[]={
+0x6B64,0x9803,0x4ECA,0x56F0,0x5764,0x58BE,0x5A5A,0x6068,
+0x61C7,0x660F,0x6606,0x6839,0x68B1,0x6DF7,0x75D5,0x7D3A,
+0x826E,0x9B42,0x4E9B,0x4F50,0x53C9,0x5506,0x5D6F,0x5DE6,
+0x5DEE,0x67FB,0x6C99,0x7473,0x7802,0x8A50,0x9396,0x88DF,
+0x5750,0x5EA7,0x632B,0x50B5,0x50AC,0x518D,0x6700,0x54C9,
+0x585E,0x59BB,0x5BB0,0x5F69,0x624D,0x63A1,0x683D,0x6B73,
+0x6E08,0x707D,0x91C7,0x7280,0x7815,0x7826,0x796D,0x658E,
+0x7D30,0x83DC,0x88C1,0x8F09,0x969B,0x5264,0x5728,0x6750,
+0x7F6A,0x8CA1,0x51B4,0x5742,0x962A,0x583A,0x698A,0x80B4,
+0x54B2,0x5D0E,0x57FC,0x7895,0x9DFA,0x4F5C,0x524A,0x548B,
+0x643E,0x6628,0x6714,0x67F5,0x7A84,0x7B56,0x7D22,0x932F,
+0x685C,0x9BAD,0x7B39,0x5319,0x518A,0x5237};
+
+/* page 19 0x3B21-0x3B7E */
+static uint16 tab_jisx0208_uni19[]={
+0x5BDF,0x62F6,0x64AE,0x64E6,0x672D,0x6BBA,0x85A9,0x96D1,
+0x7690,0x9BD6,0x634C,0x9306,0x9BAB,0x76BF,0x6652,0x4E09,
+0x5098,0x53C2,0x5C71,0x60E8,0x6492,0x6563,0x685F,0x71E6,
+0x73CA,0x7523,0x7B97,0x7E82,0x8695,0x8B83,0x8CDB,0x9178,
+0x9910,0x65AC,0x66AB,0x6B8B,0x4ED5,0x4ED4,0x4F3A,0x4F7F,
+0x523A,0x53F8,0x53F2,0x55E3,0x56DB,0x58EB,0x59CB,0x59C9,
+0x59FF,0x5B50,0x5C4D,0x5E02,0x5E2B,0x5FD7,0x601D,0x6307,
+0x652F,0x5B5C,0x65AF,0x65BD,0x65E8,0x679D,0x6B62,0x6B7B,
+0x6C0F,0x7345,0x7949,0x79C1,0x7CF8,0x7D19,0x7D2B,0x80A2,
+0x8102,0x81F3,0x8996,0x8A5E,0x8A69,0x8A66,0x8A8C,0x8AEE,
+0x8CC7,0x8CDC,0x96CC,0x98FC,0x6B6F,0x4E8B,0x4F3C,0x4F8D,
+0x5150,0x5B57,0x5BFA,0x6148,0x6301,0x6642};
+
+/* page 20 0x3C21-0x3C7E */
+static uint16 tab_jisx0208_uni20[]={
+0x6B21,0x6ECB,0x6CBB,0x723E,0x74BD,0x75D4,0x78C1,0x793A,
+0x800C,0x8033,0x81EA,0x8494,0x8F9E,0x6C50,0x9E7F,0x5F0F,
+0x8B58,0x9D2B,0x7AFA,0x8EF8,0x5B8D,0x96EB,0x4E03,0x53F1,
+0x57F7,0x5931,0x5AC9,0x5BA4,0x6089,0x6E7F,0x6F06,0x75BE,
+0x8CEA,0x5B9F,0x8500,0x7BE0,0x5072,0x67F4,0x829D,0x5C61,
+0x854A,0x7E1E,0x820E,0x5199,0x5C04,0x6368,0x8D66,0x659C,
+0x716E,0x793E,0x7D17,0x8005,0x8B1D,0x8ECA,0x906E,0x86C7,
+0x90AA,0x501F,0x52FA,0x5C3A,0x6753,0x707C,0x7235,0x914C,
+0x91C8,0x932B,0x82E5,0x5BC2,0x5F31,0x60F9,0x4E3B,0x53D6,
+0x5B88,0x624B,0x6731,0x6B8A,0x72E9,0x73E0,0x7A2E,0x816B,
+0x8DA3,0x9152,0x9996,0x5112,0x53D7,0x546A,0x5BFF,0x6388,
+0x6A39,0x7DAC,0x9700,0x56DA,0x53CE,0x5468};
+
+/* page 21 0x3D21-0x3D7E */
+static uint16 tab_jisx0208_uni21[]={
+0x5B97,0x5C31,0x5DDE,0x4FEE,0x6101,0x62FE,0x6D32,0x79C0,
+0x79CB,0x7D42,0x7E4D,0x7FD2,0x81ED,0x821F,0x8490,0x8846,
+0x8972,0x8B90,0x8E74,0x8F2F,0x9031,0x914B,0x916C,0x96C6,
+0x919C,0x4EC0,0x4F4F,0x5145,0x5341,0x5F93,0x620E,0x67D4,
+0x6C41,0x6E0B,0x7363,0x7E26,0x91CD,0x9283,0x53D4,0x5919,
+0x5BBF,0x6DD1,0x795D,0x7E2E,0x7C9B,0x587E,0x719F,0x51FA,
+0x8853,0x8FF0,0x4FCA,0x5CFB,0x6625,0x77AC,0x7AE3,0x821C,
+0x99FF,0x51C6,0x5FAA,0x65EC,0x696F,0x6B89,0x6DF3,0x6E96,
+0x6F64,0x76FE,0x7D14,0x5DE1,0x9075,0x9187,0x9806,0x51E6,
+0x521D,0x6240,0x6691,0x66D9,0x6E1A,0x5EB6,0x7DD2,0x7F72,
+0x66F8,0x85AF,0x85F7,0x8AF8,0x52A9,0x53D9,0x5973,0x5E8F,
+0x5F90,0x6055,0x92E4,0x9664,0x50B7,0x511F};
+
+/* page 22 0x3E21-0x3E7E */
+static uint16 tab_jisx0208_uni22[]={
+0x52DD,0x5320,0x5347,0x53EC,0x54E8,0x5546,0x5531,0x5617,
+0x5968,0x59BE,0x5A3C,0x5BB5,0x5C06,0x5C0F,0x5C11,0x5C1A,
+0x5E84,0x5E8A,0x5EE0,0x5F70,0x627F,0x6284,0x62DB,0x638C,
+0x6377,0x6607,0x660C,0x662D,0x6676,0x677E,0x68A2,0x6A1F,
+0x6A35,0x6CBC,0x6D88,0x6E09,0x6E58,0x713C,0x7126,0x7167,
+0x75C7,0x7701,0x785D,0x7901,0x7965,0x79F0,0x7AE0,0x7B11,
+0x7CA7,0x7D39,0x8096,0x83D6,0x848B,0x8549,0x885D,0x88F3,
+0x8A1F,0x8A3C,0x8A54,0x8A73,0x8C61,0x8CDE,0x91A4,0x9266,
+0x937E,0x9418,0x969C,0x9798,0x4E0A,0x4E08,0x4E1E,0x4E57,
+0x5197,0x5270,0x57CE,0x5834,0x58CC,0x5B22,0x5E38,0x60C5,
+0x64FE,0x6761,0x6756,0x6D44,0x72B6,0x7573,0x7A63,0x84B8,
+0x8B72,0x91B8,0x9320,0x5631,0x57F4,0x98FE};
+
+/* page 23 0x3F21-0x3F7E */
+static uint16 tab_jisx0208_uni23[]={
+0x62ED,0x690D,0x6B96,0x71ED,0x7E54,0x8077,0x8272,0x89E6,
+0x98DF,0x8755,0x8FB1,0x5C3B,0x4F38,0x4FE1,0x4FB5,0x5507,
+0x5A20,0x5BDD,0x5BE9,0x5FC3,0x614E,0x632F,0x65B0,0x664B,
+0x68EE,0x699B,0x6D78,0x6DF1,0x7533,0x75B9,0x771F,0x795E,
+0x79E6,0x7D33,0x81E3,0x82AF,0x85AA,0x89AA,0x8A3A,0x8EAB,
+0x8F9B,0x9032,0x91DD,0x9707,0x4EBA,0x4EC1,0x5203,0x5875,
+0x58EC,0x5C0B,0x751A,0x5C3D,0x814E,0x8A0A,0x8FC5,0x9663,
+0x976D,0x7B25,0x8ACF,0x9808,0x9162,0x56F3,0x53A8,0x9017,
+0x5439,0x5782,0x5E25,0x63A8,0x6C34,0x708A,0x7761,0x7C8B,
+0x7FE0,0x8870,0x9042,0x9154,0x9310,0x9318,0x968F,0x745E,
+0x9AC4,0x5D07,0x5D69,0x6570,0x67A2,0x8DA8,0x96DB,0x636E,
+0x6749,0x6919,0x83C5,0x9817,0x96C0,0x88FE};
+
+/* page 24 0x4021-0x407E */
+static uint16 tab_jisx0208_uni24[]={
+0x6F84,0x647A,0x5BF8,0x4E16,0x702C,0x755D,0x662F,0x51C4,
+0x5236,0x52E2,0x59D3,0x5F81,0x6027,0x6210,0x653F,0x6574,
+0x661F,0x6674,0x68F2,0x6816,0x6B63,0x6E05,0x7272,0x751F,
+0x76DB,0x7CBE,0x8056,0x58F0,0x88FD,0x897F,0x8AA0,0x8A93,
+0x8ACB,0x901D,0x9192,0x9752,0x9759,0x6589,0x7A0E,0x8106,
+0x96BB,0x5E2D,0x60DC,0x621A,0x65A5,0x6614,0x6790,0x77F3,
+0x7A4D,0x7C4D,0x7E3E,0x810A,0x8CAC,0x8D64,0x8DE1,0x8E5F,
+0x78A9,0x5207,0x62D9,0x63A5,0x6442,0x6298,0x8A2D,0x7A83,
+0x7BC0,0x8AAC,0x96EA,0x7D76,0x820C,0x8749,0x4ED9,0x5148,
+0x5343,0x5360,0x5BA3,0x5C02,0x5C16,0x5DDD,0x6226,0x6247,
+0x64B0,0x6813,0x6834,0x6CC9,0x6D45,0x6D17,0x67D3,0x6F5C,
+0x714E,0x717D,0x65CB,0x7A7F,0x7BAD,0x7DDA};
+
+/* page 25 0x4121-0x417E */
+static uint16 tab_jisx0208_uni25[]={
+0x7E4A,0x7FA8,0x817A,0x821B,0x8239,0x85A6,0x8A6E,0x8CCE,
+0x8DF5,0x9078,0x9077,0x92AD,0x9291,0x9583,0x9BAE,0x524D,
+0x5584,0x6F38,0x7136,0x5168,0x7985,0x7E55,0x81B3,0x7CCE,
+0x564C,0x5851,0x5CA8,0x63AA,0x66FE,0x66FD,0x695A,0x72D9,
+0x758F,0x758E,0x790E,0x7956,0x79DF,0x7C97,0x7D20,0x7D44,
+0x8607,0x8A34,0x963B,0x9061,0x9F20,0x50E7,0x5275,0x53CC,
+0x53E2,0x5009,0x55AA,0x58EE,0x594F,0x723D,0x5B8B,0x5C64,
+0x531D,0x60E3,0x60F3,0x635C,0x6383,0x633F,0x63BB,0x64CD,
+0x65E9,0x66F9,0x5DE3,0x69CD,0x69FD,0x6F15,0x71E5,0x4E89,
+0x75E9,0x76F8,0x7A93,0x7CDF,0x7DCF,0x7D9C,0x8061,0x8349,
+0x8358,0x846C,0x84BC,0x85FB,0x88C5,0x8D70,0x9001,0x906D,
+0x9397,0x971C,0x9A12,0x50CF,0x5897,0x618E};
+
+/* page 26 0x4221-0x427E */
+static uint16 tab_jisx0208_uni26[]={
+0x81D3,0x8535,0x8D08,0x9020,0x4FC3,0x5074,0x5247,0x5373,
+0x606F,0x6349,0x675F,0x6E2C,0x8DB3,0x901F,0x4FD7,0x5C5E,
+0x8CCA,0x65CF,0x7D9A,0x5352,0x8896,0x5176,0x63C3,0x5B58,
+0x5B6B,0x5C0A,0x640D,0x6751,0x905C,0x4ED6,0x591A,0x592A,
+0x6C70,0x8A51,0x553E,0x5815,0x59A5,0x60F0,0x6253,0x67C1,
+0x8235,0x6955,0x9640,0x99C4,0x9A28,0x4F53,0x5806,0x5BFE,
+0x8010,0x5CB1,0x5E2F,0x5F85,0x6020,0x614B,0x6234,0x66FF,
+0x6CF0,0x6EDE,0x80CE,0x817F,0x82D4,0x888B,0x8CB8,0x9000,
+0x902E,0x968A,0x9EDB,0x9BDB,0x4EE3,0x53F0,0x5927,0x7B2C,
+0x918D,0x984C,0x9DF9,0x6EDD,0x7027,0x5353,0x5544,0x5B85,
+0x6258,0x629E,0x62D3,0x6CA2,0x6FEF,0x7422,0x8A17,0x9438,
+0x6FC1,0x8AFE,0x8338,0x51E7,0x86F8,0x53EA};
+
+/* page 27 0x4321-0x437E */
+static uint16 tab_jisx0208_uni27[]={
+0x53E9,0x4F46,0x9054,0x8FB0,0x596A,0x8131,0x5DFD,0x7AEA,
+0x8FBF,0x68DA,0x8C37,0x72F8,0x9C48,0x6A3D,0x8AB0,0x4E39,
+0x5358,0x5606,0x5766,0x62C5,0x63A2,0x65E6,0x6B4E,0x6DE1,
+0x6E5B,0x70AD,0x77ED,0x7AEF,0x7BAA,0x7DBB,0x803D,0x80C6,
+0x86CB,0x8A95,0x935B,0x56E3,0x58C7,0x5F3E,0x65AD,0x6696,
+0x6A80,0x6BB5,0x7537,0x8AC7,0x5024,0x77E5,0x5730,0x5F1B,
+0x6065,0x667A,0x6C60,0x75F4,0x7A1A,0x7F6E,0x81F4,0x8718,
+0x9045,0x99B3,0x7BC9,0x755C,0x7AF9,0x7B51,0x84C4,0x9010,
+0x79E9,0x7A92,0x8336,0x5AE1,0x7740,0x4E2D,0x4EF2,0x5B99,
+0x5FE0,0x62BD,0x663C,0x67F1,0x6CE8,0x866B,0x8877,0x8A3B,
+0x914E,0x92F3,0x99D0,0x6A17,0x7026,0x732A,0x82E7,0x8457,
+0x8CAF,0x4E01,0x5146,0x51CB,0x558B,0x5BF5};
+
+/* page 28 0x4421-0x447E */
+static uint16 tab_jisx0208_uni28[]={
+0x5E16,0x5E33,0x5E81,0x5F14,0x5F35,0x5F6B,0x5FB4,0x61F2,
+0x6311,0x66A2,0x671D,0x6F6E,0x7252,0x753A,0x773A,0x8074,
+0x8139,0x8178,0x8776,0x8ABF,0x8ADC,0x8D85,0x8DF3,0x929A,
+0x9577,0x9802,0x9CE5,0x52C5,0x6357,0x76F4,0x6715,0x6C88,
+0x73CD,0x8CC3,0x93AE,0x9673,0x6D25,0x589C,0x690E,0x69CC,
+0x8FFD,0x939A,0x75DB,0x901A,0x585A,0x6802,0x63B4,0x69FB,
+0x4F43,0x6F2C,0x67D8,0x8FBB,0x8526,0x7DB4,0x9354,0x693F,
+0x6F70,0x576A,0x58F7,0x5B2C,0x7D2C,0x722A,0x540A,0x91E3,
+0x9DB4,0x4EAD,0x4F4E,0x505C,0x5075,0x5243,0x8C9E,0x5448,
+0x5824,0x5B9A,0x5E1D,0x5E95,0x5EAD,0x5EF7,0x5F1F,0x608C,
+0x62B5,0x633A,0x63D0,0x68AF,0x6C40,0x7887,0x798E,0x7A0B,
+0x7DE0,0x8247,0x8A02,0x8AE6,0x8E44,0x9013};
+
+/* page 29 0x4521-0x457E */
+static uint16 tab_jisx0208_uni29[]={
+0x90B8,0x912D,0x91D8,0x9F0E,0x6CE5,0x6458,0x64E2,0x6575,
+0x6EF4,0x7684,0x7B1B,0x9069,0x93D1,0x6EBA,0x54F2,0x5FB9,
+0x64A4,0x8F4D,0x8FED,0x9244,0x5178,0x586B,0x5929,0x5C55,
+0x5E97,0x6DFB,0x7E8F,0x751C,0x8CBC,0x8EE2,0x985B,0x70B9,
+0x4F1D,0x6BBF,0x6FB1,0x7530,0x96FB,0x514E,0x5410,0x5835,
+0x5857,0x59AC,0x5C60,0x5F92,0x6597,0x675C,0x6E21,0x767B,
+0x83DF,0x8CED,0x9014,0x90FD,0x934D,0x7825,0x783A,0x52AA,
+0x5EA6,0x571F,0x5974,0x6012,0x5012,0x515A,0x51AC,0x51CD,
+0x5200,0x5510,0x5854,0x5858,0x5957,0x5B95,0x5CF6,0x5D8B,
+0x60BC,0x6295,0x642D,0x6771,0x6843,0x68BC,0x68DF,0x76D7,
+0x6DD8,0x6E6F,0x6D9B,0x706F,0x71C8,0x5F53,0x75D8,0x7977,
+0x7B49,0x7B54,0x7B52,0x7CD6,0x7D71,0x5230};
+
+/* page 30 0x4621-0x467E */
+static uint16 tab_jisx0208_uni30[]={
+0x8463,0x8569,0x85E4,0x8A0E,0x8B04,0x8C46,0x8E0F,0x9003,
+0x900F,0x9419,0x9676,0x982D,0x9A30,0x95D8,0x50CD,0x52D5,
+0x540C,0x5802,0x5C0E,0x61A7,0x649E,0x6D1E,0x77B3,0x7AE5,
+0x80F4,0x8404,0x9053,0x9285,0x5CE0,0x9D07,0x533F,0x5F97,
+0x5FB3,0x6D9C,0x7279,0x7763,0x79BF,0x7BE4,0x6BD2,0x72EC,
+0x8AAD,0x6803,0x6A61,0x51F8,0x7A81,0x6934,0x5C4A,0x9CF6,
+0x82EB,0x5BC5,0x9149,0x701E,0x5678,0x5C6F,0x60C7,0x6566,
+0x6C8C,0x8C5A,0x9041,0x9813,0x5451,0x66C7,0x920D,0x5948,
+0x90A3,0x5185,0x4E4D,0x51EA,0x8599,0x8B0E,0x7058,0x637A,
+0x934B,0x6962,0x99B4,0x7E04,0x7577,0x5357,0x6960,0x8EDF,
+0x96E3,0x6C5D,0x4E8C,0x5C3C,0x5F10,0x8FE9,0x5302,0x8CD1,
+0x8089,0x8679,0x5EFF,0x65E5,0x4E73,0x5165};
+
+/* page 31 0x4721-0x477E */
+static uint16 tab_jisx0208_uni31[]={
+0x5982,0x5C3F,0x97EE,0x4EFB,0x598A,0x5FCD,0x8A8D,0x6FE1,
+0x79B0,0x7962,0x5BE7,0x8471,0x732B,0x71B1,0x5E74,0x5FF5,
+0x637B,0x649A,0x71C3,0x7C98,0x4E43,0x5EFC,0x4E4B,0x57DC,
+0x56A2,0x60A9,0x6FC3,0x7D0D,0x80FD,0x8133,0x81BF,0x8FB2,
+0x8997,0x86A4,0x5DF4,0x628A,0x64AD,0x8987,0x6777,0x6CE2,
+0x6D3E,0x7436,0x7834,0x5A46,0x7F75,0x82AD,0x99AC,0x4FF3,
+0x5EC3,0x62DD,0x6392,0x6557,0x676F,0x76C3,0x724C,0x80CC,
+0x80BA,0x8F29,0x914D,0x500D,0x57F9,0x5A92,0x6885,0x6973,
+0x7164,0x72FD,0x8CB7,0x58F2,0x8CE0,0x966A,0x9019,0x877F,
+0x79E4,0x77E7,0x8429,0x4F2F,0x5265,0x535A,0x62CD,0x67CF,
+0x6CCA,0x767D,0x7B94,0x7C95,0x8236,0x8584,0x8FEB,0x66DD,
+0x6F20,0x7206,0x7E1B,0x83AB,0x99C1,0x9EA6};
+
+/* page 32 0x4821-0x487E */
+static uint16 tab_jisx0208_uni32[]={
+0x51FD,0x7BB1,0x7872,0x7BB8,0x8087,0x7B48,0x6AE8,0x5E61,
+0x808C,0x7551,0x7560,0x516B,0x9262,0x6E8C,0x767A,0x9197,
+0x9AEA,0x4F10,0x7F70,0x629C,0x7B4F,0x95A5,0x9CE9,0x567A,
+0x5859,0x86E4,0x96BC,0x4F34,0x5224,0x534A,0x53CD,0x53DB,
+0x5E06,0x642C,0x6591,0x677F,0x6C3E,0x6C4E,0x7248,0x72AF,
+0x73ED,0x7554,0x7E41,0x822C,0x85E9,0x8CA9,0x7BC4,0x91C6,
+0x7169,0x9812,0x98EF,0x633D,0x6669,0x756A,0x76E4,0x78D0,
+0x8543,0x86EE,0x532A,0x5351,0x5426,0x5983,0x5E87,0x5F7C,
+0x60B2,0x6249,0x6279,0x62AB,0x6590,0x6BD4,0x6CCC,0x75B2,
+0x76AE,0x7891,0x79D8,0x7DCB,0x7F77,0x80A5,0x88AB,0x8AB9,
+0x8CBB,0x907F,0x975E,0x98DB,0x6A0B,0x7C38,0x5099,0x5C3E,
+0x5FAE,0x6787,0x6BD8,0x7435,0x7709,0x7F8E};
+
+/* page 33 0x4921-0x497E */
+static uint16 tab_jisx0208_uni33[]={
+0x9F3B,0x67CA,0x7A17,0x5339,0x758B,0x9AED,0x5F66,0x819D,
+0x83F1,0x8098,0x5F3C,0x5FC5,0x7562,0x7B46,0x903C,0x6867,
+0x59EB,0x5A9B,0x7D10,0x767E,0x8B2C,0x4FF5,0x5F6A,0x6A19,
+0x6C37,0x6F02,0x74E2,0x7968,0x8868,0x8A55,0x8C79,0x5EDF,
+0x63CF,0x75C5,0x79D2,0x82D7,0x9328,0x92F2,0x849C,0x86ED,
+0x9C2D,0x54C1,0x5F6C,0x658C,0x6D5C,0x7015,0x8CA7,0x8CD3,
+0x983B,0x654F,0x74F6,0x4E0D,0x4ED8,0x57E0,0x592B,0x5A66,
+0x5BCC,0x51A8,0x5E03,0x5E9C,0x6016,0x6276,0x6577,0x65A7,
+0x666E,0x6D6E,0x7236,0x7B26,0x8150,0x819A,0x8299,0x8B5C,
+0x8CA0,0x8CE6,0x8D74,0x961C,0x9644,0x4FAE,0x64AB,0x6B66,
+0x821E,0x8461,0x856A,0x90E8,0x5C01,0x6953,0x98A8,0x847A,
+0x8557,0x4F0F,0x526F,0x5FA9,0x5E45,0x670D};
+
+/* page 34 0x4A21-0x4A7E */
+static uint16 tab_jisx0208_uni34[]={
+0x798F,0x8179,0x8907,0x8986,0x6DF5,0x5F17,0x6255,0x6CB8,
+0x4ECF,0x7269,0x9B92,0x5206,0x543B,0x5674,0x58B3,0x61A4,
+0x626E,0x711A,0x596E,0x7C89,0x7CDE,0x7D1B,0x96F0,0x6587,
+0x805E,0x4E19,0x4F75,0x5175,0x5840,0x5E63,0x5E73,0x5F0A,
+0x67C4,0x4E26,0x853D,0x9589,0x965B,0x7C73,0x9801,0x50FB,
+0x58C1,0x7656,0x78A7,0x5225,0x77A5,0x8511,0x7B86,0x504F,
+0x5909,0x7247,0x7BC7,0x7DE8,0x8FBA,0x8FD4,0x904D,0x4FBF,
+0x52C9,0x5A29,0x5F01,0x97AD,0x4FDD,0x8217,0x92EA,0x5703,
+0x6355,0x6B69,0x752B,0x88DC,0x8F14,0x7A42,0x52DF,0x5893,
+0x6155,0x620A,0x66AE,0x6BCD,0x7C3F,0x83E9,0x5023,0x4FF8,
+0x5305,0x5446,0x5831,0x5949,0x5B9D,0x5CF0,0x5CEF,0x5D29,
+0x5E96,0x62B1,0x6367,0x653E,0x65B9,0x670B};
+
+/* page 35 0x4B21-0x4B7E */
+static uint16 tab_jisx0208_uni35[]={
+0x6CD5,0x6CE1,0x70F9,0x7832,0x7E2B,0x80DE,0x82B3,0x840C,
+0x84EC,0x8702,0x8912,0x8A2A,0x8C4A,0x90A6,0x92D2,0x98FD,
+0x9CF3,0x9D6C,0x4E4F,0x4EA1,0x508D,0x5256,0x574A,0x59A8,
+0x5E3D,0x5FD8,0x5FD9,0x623F,0x66B4,0x671B,0x67D0,0x68D2,
+0x5192,0x7D21,0x80AA,0x81A8,0x8B00,0x8C8C,0x8CBF,0x927E,
+0x9632,0x5420,0x982C,0x5317,0x50D5,0x535C,0x58A8,0x64B2,
+0x6734,0x7267,0x7766,0x7A46,0x91E6,0x52C3,0x6CA1,0x6B86,
+0x5800,0x5E4C,0x5954,0x672C,0x7FFB,0x51E1,0x76C6,0x6469,
+0x78E8,0x9B54,0x9EBB,0x57CB,0x59B9,0x6627,0x679A,0x6BCE,
+0x54E9,0x69D9,0x5E55,0x819C,0x6795,0x9BAA,0x67FE,0x9C52,
+0x685D,0x4EA6,0x4FE3,0x53C8,0x62B9,0x672B,0x6CAB,0x8FC4,
+0x4FAD,0x7E6D,0x9EBF,0x4E07,0x6162,0x6E80};
+
+/* page 36 0x4C21-0x4C7E */
+static uint16 tab_jisx0208_uni36[]={
+0x6F2B,0x8513,0x5473,0x672A,0x9B45,0x5DF3,0x7B95,0x5CAC,
+0x5BC6,0x871C,0x6E4A,0x84D1,0x7A14,0x8108,0x5999,0x7C8D,
+0x6C11,0x7720,0x52D9,0x5922,0x7121,0x725F,0x77DB,0x9727,
+0x9D61,0x690B,0x5A7F,0x5A18,0x51A5,0x540D,0x547D,0x660E,
+0x76DF,0x8FF7,0x9298,0x9CF4,0x59EA,0x725D,0x6EC5,0x514D,
+0x68C9,0x7DBF,0x7DEC,0x9762,0x9EBA,0x6478,0x6A21,0x8302,
+0x5984,0x5B5F,0x6BDB,0x731B,0x76F2,0x7DB2,0x8017,0x8499,
+0x5132,0x6728,0x9ED9,0x76EE,0x6762,0x52FF,0x9905,0x5C24,
+0x623B,0x7C7E,0x8CB0,0x554F,0x60B6,0x7D0B,0x9580,0x5301,
+0x4E5F,0x51B6,0x591C,0x723A,0x8036,0x91CE,0x5F25,0x77E2,
+0x5384,0x5F79,0x7D04,0x85AC,0x8A33,0x8E8D,0x9756,0x67F3,
+0x85AE,0x9453,0x6109,0x6108,0x6CB9,0x7652};
+
+/* page 37 0x4D21-0x4D7E */
+static uint16 tab_jisx0208_uni37[]={
+0x8AED,0x8F38,0x552F,0x4F51,0x512A,0x52C7,0x53CB,0x5BA5,
+0x5E7D,0x60A0,0x6182,0x63D6,0x6709,0x67DA,0x6E67,0x6D8C,
+0x7336,0x7337,0x7531,0x7950,0x88D5,0x8A98,0x904A,0x9091,
+0x90F5,0x96C4,0x878D,0x5915,0x4E88,0x4F59,0x4E0E,0x8A89,
+0x8F3F,0x9810,0x50AD,0x5E7C,0x5996,0x5BB9,0x5EB8,0x63DA,
+0x63FA,0x64C1,0x66DC,0x694A,0x69D8,0x6D0B,0x6EB6,0x7194,
+0x7528,0x7AAF,0x7F8A,0x8000,0x8449,0x84C9,0x8981,0x8B21,
+0x8E0A,0x9065,0x967D,0x990A,0x617E,0x6291,0x6B32,0x6C83,
+0x6D74,0x7FCC,0x7FFC,0x6DC0,0x7F85,0x87BA,0x88F8,0x6765,
+0x83B1,0x983C,0x96F7,0x6D1B,0x7D61,0x843D,0x916A,0x4E71,
+0x5375,0x5D50,0x6B04,0x6FEB,0x85CD,0x862D,0x89A7,0x5229,
+0x540F,0x5C65,0x674E,0x68A8,0x7406,0x7483};
+
+/* page 38 0x4E21-0x4E7E */
+static uint16 tab_jisx0208_uni38[]={
+0x75E2,0x88CF,0x88E1,0x91CC,0x96E2,0x9678,0x5F8B,0x7387,
+0x7ACB,0x844E,0x63A0,0x7565,0x5289,0x6D41,0x6E9C,0x7409,
+0x7559,0x786B,0x7C92,0x9686,0x7ADC,0x9F8D,0x4FB6,0x616E,
+0x65C5,0x865C,0x4E86,0x4EAE,0x50DA,0x4E21,0x51CC,0x5BEE,
+0x6599,0x6881,0x6DBC,0x731F,0x7642,0x77AD,0x7A1C,0x7CE7,
+0x826F,0x8AD2,0x907C,0x91CF,0x9675,0x9818,0x529B,0x7DD1,
+0x502B,0x5398,0x6797,0x6DCB,0x71D0,0x7433,0x81E8,0x8F2A,
+0x96A3,0x9C57,0x9E9F,0x7460,0x5841,0x6D99,0x7D2F,0x985E,
+0x4EE4,0x4F36,0x4F8B,0x51B7,0x52B1,0x5DBA,0x601C,0x73B2,
+0x793C,0x82D3,0x9234,0x96B7,0x96F6,0x970A,0x9E97,0x9F62,
+0x66A6,0x6B74,0x5217,0x52A3,0x70C8,0x88C2,0x5EC9,0x604B,
+0x6190,0x6F23,0x7149,0x7C3E,0x7DF4,0x806F};
+
+/* page 39 0x4F21-0x4F53 */
+static uint16 tab_jisx0208_uni39[]={
+0x84EE,0x9023,0x932C,0x5442,0x9B6F,0x6AD3,0x7089,0x8CC2,
+0x8DEF,0x9732,0x52B4,0x5A41,0x5ECA,0x5F04,0x6717,0x697C,
+0x6994,0x6D6A,0x6F0F,0x7262,0x72FC,0x7BED,0x8001,0x807E,
+0x874B,0x90CE,0x516D,0x9E93,0x7984,0x808B,0x9332,0x8AD6,
+0x502D,0x548C,0x8A71,0x6B6A,0x8CC4,0x8107,0x60D1,0x67A0,
+0x9DF2,0x4E99,0x4E98,0x9C10,0x8A6B,0x85C1,0x8568,0x6900,
+0x6E7E,0x7897,0x8155};
+
+/* page 40 0x5021-0x507E */
+static uint16 tab_jisx0208_uni40[]={
+0x5F0C,0x4E10,0x4E15,0x4E2A,0x4E31,0x4E36,0x4E3C,0x4E3F,
+0x4E42,0x4E56,0x4E58,0x4E82,0x4E85,0x8C6B,0x4E8A,0x8212,
+0x5F0D,0x4E8E,0x4E9E,0x4E9F,0x4EA0,0x4EA2,0x4EB0,0x4EB3,
+0x4EB6,0x4ECE,0x4ECD,0x4EC4,0x4EC6,0x4EC2,0x4ED7,0x4EDE,
+0x4EED,0x4EDF,0x4EF7,0x4F09,0x4F5A,0x4F30,0x4F5B,0x4F5D,
+0x4F57,0x4F47,0x4F76,0x4F88,0x4F8F,0x4F98,0x4F7B,0x4F69,
+0x4F70,0x4F91,0x4F6F,0x4F86,0x4F96,0x5118,0x4FD4,0x4FDF,
+0x4FCE,0x4FD8,0x4FDB,0x4FD1,0x4FDA,0x4FD0,0x4FE4,0x4FE5,
+0x501A,0x5028,0x5014,0x502A,0x5025,0x5005,0x4F1C,0x4FF6,
+0x5021,0x5029,0x502C,0x4FFE,0x4FEF,0x5011,0x5006,0x5043,
+0x5047,0x6703,0x5055,0x5050,0x5048,0x505A,0x5056,0x506C,
+0x5078,0x5080,0x509A,0x5085,0x50B4,0x50B2};
+
+/* page 41 0x5121-0x517E */
+static uint16 tab_jisx0208_uni41[]={
+0x50C9,0x50CA,0x50B3,0x50C2,0x50D6,0x50DE,0x50E5,0x50ED,
+0x50E3,0x50EE,0x50F9,0x50F5,0x5109,0x5101,0x5102,0x5116,
+0x5115,0x5114,0x511A,0x5121,0x513A,0x5137,0x513C,0x513B,
+0x513F,0x5140,0x5152,0x514C,0x5154,0x5162,0x7AF8,0x5169,
+0x516A,0x516E,0x5180,0x5182,0x56D8,0x518C,0x5189,0x518F,
+0x5191,0x5193,0x5195,0x5196,0x51A4,0x51A6,0x51A2,0x51A9,
+0x51AA,0x51AB,0x51B3,0x51B1,0x51B2,0x51B0,0x51B5,0x51BD,
+0x51C5,0x51C9,0x51DB,0x51E0,0x8655,0x51E9,0x51ED,0x51F0,
+0x51F5,0x51FE,0x5204,0x520B,0x5214,0x520E,0x5227,0x522A,
+0x522E,0x5233,0x5239,0x524F,0x5244,0x524B,0x524C,0x525E,
+0x5254,0x526A,0x5274,0x5269,0x5273,0x527F,0x527D,0x528D,
+0x5294,0x5292,0x5271,0x5288,0x5291,0x8FA8};
+
+/* page 42 0x5221-0x527E */
+static uint16 tab_jisx0208_uni42[]={
+0x8FA7,0x52AC,0x52AD,0x52BC,0x52B5,0x52C1,0x52CD,0x52D7,
+0x52DE,0x52E3,0x52E6,0x98ED,0x52E0,0x52F3,0x52F5,0x52F8,
+0x52F9,0x5306,0x5308,0x7538,0x530D,0x5310,0x530F,0x5315,
+0x531A,0x5323,0x532F,0x5331,0x5333,0x5338,0x5340,0x5346,
+0x5345,0x4E17,0x5349,0x534D,0x51D6,0x535E,0x5369,0x536E,
+0x5918,0x537B,0x5377,0x5382,0x5396,0x53A0,0x53A6,0x53A5,
+0x53AE,0x53B0,0x53B6,0x53C3,0x7C12,0x96D9,0x53DF,0x66FC,
+0x71EE,0x53EE,0x53E8,0x53ED,0x53FA,0x5401,0x543D,0x5440,
+0x542C,0x542D,0x543C,0x542E,0x5436,0x5429,0x541D,0x544E,
+0x548F,0x5475,0x548E,0x545F,0x5471,0x5477,0x5470,0x5492,
+0x547B,0x5480,0x5476,0x5484,0x5490,0x5486,0x54C7,0x54A2,
+0x54B8,0x54A5,0x54AC,0x54C4,0x54C8,0x54A8};
+
+/* page 43 0x5321-0x537E */
+static uint16 tab_jisx0208_uni43[]={
+0x54AB,0x54C2,0x54A4,0x54BE,0x54BC,0x54D8,0x54E5,0x54E6,
+0x550F,0x5514,0x54FD,0x54EE,0x54ED,0x54FA,0x54E2,0x5539,
+0x5540,0x5563,0x554C,0x552E,0x555C,0x5545,0x5556,0x5557,
+0x5538,0x5533,0x555D,0x5599,0x5580,0x54AF,0x558A,0x559F,
+0x557B,0x557E,0x5598,0x559E,0x55AE,0x557C,0x5583,0x55A9,
+0x5587,0x55A8,0x55DA,0x55C5,0x55DF,0x55C4,0x55DC,0x55E4,
+0x55D4,0x5614,0x55F7,0x5616,0x55FE,0x55FD,0x561B,0x55F9,
+0x564E,0x5650,0x71DF,0x5634,0x5636,0x5632,0x5638,0x566B,
+0x5664,0x562F,0x566C,0x566A,0x5686,0x5680,0x568A,0x56A0,
+0x5694,0x568F,0x56A5,0x56AE,0x56B6,0x56B4,0x56C2,0x56BC,
+0x56C1,0x56C3,0x56C0,0x56C8,0x56CE,0x56D1,0x56D3,0x56D7,
+0x56EE,0x56F9,0x5700,0x56FF,0x5704,0x5709};
+
+/* page 44 0x5421-0x547E */
+static uint16 tab_jisx0208_uni44[]={
+0x5708,0x570B,0x570D,0x5713,0x5718,0x5716,0x55C7,0x571C,
+0x5726,0x5737,0x5738,0x574E,0x573B,0x5740,0x574F,0x5769,
+0x57C0,0x5788,0x5761,0x577F,0x5789,0x5793,0x57A0,0x57B3,
+0x57A4,0x57AA,0x57B0,0x57C3,0x57C6,0x57D4,0x57D2,0x57D3,
+0x580A,0x57D6,0x57E3,0x580B,0x5819,0x581D,0x5872,0x5821,
+0x5862,0x584B,0x5870,0x6BC0,0x5852,0x583D,0x5879,0x5885,
+0x58B9,0x589F,0x58AB,0x58BA,0x58DE,0x58BB,0x58B8,0x58AE,
+0x58C5,0x58D3,0x58D1,0x58D7,0x58D9,0x58D8,0x58E5,0x58DC,
+0x58E4,0x58DF,0x58EF,0x58FA,0x58F9,0x58FB,0x58FC,0x58FD,
+0x5902,0x590A,0x5910,0x591B,0x68A6,0x5925,0x592C,0x592D,
+0x5932,0x5938,0x593E,0x7AD2,0x5955,0x5950,0x594E,0x595A,
+0x5958,0x5962,0x5960,0x5967,0x596C,0x5969};
+
+/* page 45 0x5521-0x557E */
+static uint16 tab_jisx0208_uni45[]={
+0x5978,0x5981,0x599D,0x4F5E,0x4FAB,0x59A3,0x59B2,0x59C6,
+0x59E8,0x59DC,0x598D,0x59D9,0x59DA,0x5A25,0x5A1F,0x5A11,
+0x5A1C,0x5A09,0x5A1A,0x5A40,0x5A6C,0x5A49,0x5A35,0x5A36,
+0x5A62,0x5A6A,0x5A9A,0x5ABC,0x5ABE,0x5ACB,0x5AC2,0x5ABD,
+0x5AE3,0x5AD7,0x5AE6,0x5AE9,0x5AD6,0x5AFA,0x5AFB,0x5B0C,
+0x5B0B,0x5B16,0x5B32,0x5AD0,0x5B2A,0x5B36,0x5B3E,0x5B43,
+0x5B45,0x5B40,0x5B51,0x5B55,0x5B5A,0x5B5B,0x5B65,0x5B69,
+0x5B70,0x5B73,0x5B75,0x5B78,0x6588,0x5B7A,0x5B80,0x5B83,
+0x5BA6,0x5BB8,0x5BC3,0x5BC7,0x5BC9,0x5BD4,0x5BD0,0x5BE4,
+0x5BE6,0x5BE2,0x5BDE,0x5BE5,0x5BEB,0x5BF0,0x5BF6,0x5BF3,
+0x5C05,0x5C07,0x5C08,0x5C0D,0x5C13,0x5C20,0x5C22,0x5C28,
+0x5C38,0x5C39,0x5C41,0x5C46,0x5C4E,0x5C53};
+
+/* page 46 0x5621-0x567E */
+static uint16 tab_jisx0208_uni46[]={
+0x5C50,0x5C4F,0x5B71,0x5C6C,0x5C6E,0x4E62,0x5C76,0x5C79,
+0x5C8C,0x5C91,0x5C94,0x599B,0x5CAB,0x5CBB,0x5CB6,0x5CBC,
+0x5CB7,0x5CC5,0x5CBE,0x5CC7,0x5CD9,0x5CE9,0x5CFD,0x5CFA,
+0x5CED,0x5D8C,0x5CEA,0x5D0B,0x5D15,0x5D17,0x5D5C,0x5D1F,
+0x5D1B,0x5D11,0x5D14,0x5D22,0x5D1A,0x5D19,0x5D18,0x5D4C,
+0x5D52,0x5D4E,0x5D4B,0x5D6C,0x5D73,0x5D76,0x5D87,0x5D84,
+0x5D82,0x5DA2,0x5D9D,0x5DAC,0x5DAE,0x5DBD,0x5D90,0x5DB7,
+0x5DBC,0x5DC9,0x5DCD,0x5DD3,0x5DD2,0x5DD6,0x5DDB,0x5DEB,
+0x5DF2,0x5DF5,0x5E0B,0x5E1A,0x5E19,0x5E11,0x5E1B,0x5E36,
+0x5E37,0x5E44,0x5E43,0x5E40,0x5E4E,0x5E57,0x5E54,0x5E5F,
+0x5E62,0x5E64,0x5E47,0x5E75,0x5E76,0x5E7A,0x9EBC,0x5E7F,
+0x5EA0,0x5EC1,0x5EC2,0x5EC8,0x5ED0,0x5ECF};
+
+/* page 47 0x5721-0x577E */
+static uint16 tab_jisx0208_uni47[]={
+0x5ED6,0x5EE3,0x5EDD,0x5EDA,0x5EDB,0x5EE2,0x5EE1,0x5EE8,
+0x5EE9,0x5EEC,0x5EF1,0x5EF3,0x5EF0,0x5EF4,0x5EF8,0x5EFE,
+0x5F03,0x5F09,0x5F5D,0x5F5C,0x5F0B,0x5F11,0x5F16,0x5F29,
+0x5F2D,0x5F38,0x5F41,0x5F48,0x5F4C,0x5F4E,0x5F2F,0x5F51,
+0x5F56,0x5F57,0x5F59,0x5F61,0x5F6D,0x5F73,0x5F77,0x5F83,
+0x5F82,0x5F7F,0x5F8A,0x5F88,0x5F91,0x5F87,0x5F9E,0x5F99,
+0x5F98,0x5FA0,0x5FA8,0x5FAD,0x5FBC,0x5FD6,0x5FFB,0x5FE4,
+0x5FF8,0x5FF1,0x5FDD,0x60B3,0x5FFF,0x6021,0x6060,0x6019,
+0x6010,0x6029,0x600E,0x6031,0x601B,0x6015,0x602B,0x6026,
+0x600F,0x603A,0x605A,0x6041,0x606A,0x6077,0x605F,0x604A,
+0x6046,0x604D,0x6063,0x6043,0x6064,0x6042,0x606C,0x606B,
+0x6059,0x6081,0x608D,0x60E7,0x6083,0x609A};
+
+/* page 48 0x5821-0x587E */
+static uint16 tab_jisx0208_uni48[]={
+0x6084,0x609B,0x6096,0x6097,0x6092,0x60A7,0x608B,0x60E1,
+0x60B8,0x60E0,0x60D3,0x60B4,0x5FF0,0x60BD,0x60C6,0x60B5,
+0x60D8,0x614D,0x6115,0x6106,0x60F6,0x60F7,0x6100,0x60F4,
+0x60FA,0x6103,0x6121,0x60FB,0x60F1,0x610D,0x610E,0x6147,
+0x613E,0x6128,0x6127,0x614A,0x613F,0x613C,0x612C,0x6134,
+0x613D,0x6142,0x6144,0x6173,0x6177,0x6158,0x6159,0x615A,
+0x616B,0x6174,0x616F,0x6165,0x6171,0x615F,0x615D,0x6153,
+0x6175,0x6199,0x6196,0x6187,0x61AC,0x6194,0x619A,0x618A,
+0x6191,0x61AB,0x61AE,0x61CC,0x61CA,0x61C9,0x61F7,0x61C8,
+0x61C3,0x61C6,0x61BA,0x61CB,0x7F79,0x61CD,0x61E6,0x61E3,
+0x61F6,0x61FA,0x61F4,0x61FF,0x61FD,0x61FC,0x61FE,0x6200,
+0x6208,0x6209,0x620D,0x620C,0x6214,0x621B};
+
+/* page 49 0x5921-0x597E */
+static uint16 tab_jisx0208_uni49[]={
+0x621E,0x6221,0x622A,0x622E,0x6230,0x6232,0x6233,0x6241,
+0x624E,0x625E,0x6263,0x625B,0x6260,0x6268,0x627C,0x6282,
+0x6289,0x627E,0x6292,0x6293,0x6296,0x62D4,0x6283,0x6294,
+0x62D7,0x62D1,0x62BB,0x62CF,0x62FF,0x62C6,0x64D4,0x62C8,
+0x62DC,0x62CC,0x62CA,0x62C2,0x62C7,0x629B,0x62C9,0x630C,
+0x62EE,0x62F1,0x6327,0x6302,0x6308,0x62EF,0x62F5,0x6350,
+0x633E,0x634D,0x641C,0x634F,0x6396,0x638E,0x6380,0x63AB,
+0x6376,0x63A3,0x638F,0x6389,0x639F,0x63B5,0x636B,0x6369,
+0x63BE,0x63E9,0x63C0,0x63C6,0x63E3,0x63C9,0x63D2,0x63F6,
+0x63C4,0x6416,0x6434,0x6406,0x6413,0x6426,0x6436,0x651D,
+0x6417,0x6428,0x640F,0x6467,0x646F,0x6476,0x644E,0x652A,
+0x6495,0x6493,0x64A5,0x64A9,0x6488,0x64BC};
+
+/* page 50 0x5A21-0x5A7E */
+static uint16 tab_jisx0208_uni50[]={
+0x64DA,0x64D2,0x64C5,0x64C7,0x64BB,0x64D8,0x64C2,0x64F1,
+0x64E7,0x8209,0x64E0,0x64E1,0x62AC,0x64E3,0x64EF,0x652C,
+0x64F6,0x64F4,0x64F2,0x64FA,0x6500,0x64FD,0x6518,0x651C,
+0x6505,0x6524,0x6523,0x652B,0x6534,0x6535,0x6537,0x6536,
+0x6538,0x754B,0x6548,0x6556,0x6555,0x654D,0x6558,0x655E,
+0x655D,0x6572,0x6578,0x6582,0x6583,0x8B8A,0x659B,0x659F,
+0x65AB,0x65B7,0x65C3,0x65C6,0x65C1,0x65C4,0x65CC,0x65D2,
+0x65DB,0x65D9,0x65E0,0x65E1,0x65F1,0x6772,0x660A,0x6603,
+0x65FB,0x6773,0x6635,0x6636,0x6634,0x661C,0x664F,0x6644,
+0x6649,0x6641,0x665E,0x665D,0x6664,0x6667,0x6668,0x665F,
+0x6662,0x6670,0x6683,0x6688,0x668E,0x6689,0x6684,0x6698,
+0x669D,0x66C1,0x66B9,0x66C9,0x66BE,0x66BC};
+
+/* page 51 0x5B21-0x5B7E */
+static uint16 tab_jisx0208_uni51[]={
+0x66C4,0x66B8,0x66D6,0x66DA,0x66E0,0x663F,0x66E6,0x66E9,
+0x66F0,0x66F5,0x66F7,0x670F,0x6716,0x671E,0x6726,0x6727,
+0x9738,0x672E,0x673F,0x6736,0x6741,0x6738,0x6737,0x6746,
+0x675E,0x6760,0x6759,0x6763,0x6764,0x6789,0x6770,0x67A9,
+0x677C,0x676A,0x678C,0x678B,0x67A6,0x67A1,0x6785,0x67B7,
+0x67EF,0x67B4,0x67EC,0x67B3,0x67E9,0x67B8,0x67E4,0x67DE,
+0x67DD,0x67E2,0x67EE,0x67B9,0x67CE,0x67C6,0x67E7,0x6A9C,
+0x681E,0x6846,0x6829,0x6840,0x684D,0x6832,0x684E,0x68B3,
+0x682B,0x6859,0x6863,0x6877,0x687F,0x689F,0x688F,0x68AD,
+0x6894,0x689D,0x689B,0x6883,0x6AAE,0x68B9,0x6874,0x68B5,
+0x68A0,0x68BA,0x690F,0x688D,0x687E,0x6901,0x68CA,0x6908,
+0x68D8,0x6922,0x6926,0x68E1,0x690C,0x68CD};
+
+/* page 52 0x5C21-0x5C7E */
+static uint16 tab_jisx0208_uni52[]={
+0x68D4,0x68E7,0x68D5,0x6936,0x6912,0x6904,0x68D7,0x68E3,
+0x6925,0x68F9,0x68E0,0x68EF,0x6928,0x692A,0x691A,0x6923,
+0x6921,0x68C6,0x6979,0x6977,0x695C,0x6978,0x696B,0x6954,
+0x697E,0x696E,0x6939,0x6974,0x693D,0x6959,0x6930,0x6961,
+0x695E,0x695D,0x6981,0x696A,0x69B2,0x69AE,0x69D0,0x69BF,
+0x69C1,0x69D3,0x69BE,0x69CE,0x5BE8,0x69CA,0x69DD,0x69BB,
+0x69C3,0x69A7,0x6A2E,0x6991,0x69A0,0x699C,0x6995,0x69B4,
+0x69DE,0x69E8,0x6A02,0x6A1B,0x69FF,0x6B0A,0x69F9,0x69F2,
+0x69E7,0x6A05,0x69B1,0x6A1E,0x69ED,0x6A14,0x69EB,0x6A0A,
+0x6A12,0x6AC1,0x6A23,0x6A13,0x6A44,0x6A0C,0x6A72,0x6A36,
+0x6A78,0x6A47,0x6A62,0x6A59,0x6A66,0x6A48,0x6A38,0x6A22,
+0x6A90,0x6A8D,0x6AA0,0x6A84,0x6AA2,0x6AA3};
+
+/* page 53 0x5D21-0x5D7E */
+static uint16 tab_jisx0208_uni53[]={
+0x6A97,0x8617,0x6ABB,0x6AC3,0x6AC2,0x6AB8,0x6AB3,0x6AAC,
+0x6ADE,0x6AD1,0x6ADF,0x6AAA,0x6ADA,0x6AEA,0x6AFB,0x6B05,
+0x8616,0x6AFA,0x6B12,0x6B16,0x9B31,0x6B1F,0x6B38,0x6B37,
+0x76DC,0x6B39,0x98EE,0x6B47,0x6B43,0x6B49,0x6B50,0x6B59,
+0x6B54,0x6B5B,0x6B5F,0x6B61,0x6B78,0x6B79,0x6B7F,0x6B80,
+0x6B84,0x6B83,0x6B8D,0x6B98,0x6B95,0x6B9E,0x6BA4,0x6BAA,
+0x6BAB,0x6BAF,0x6BB2,0x6BB1,0x6BB3,0x6BB7,0x6BBC,0x6BC6,
+0x6BCB,0x6BD3,0x6BDF,0x6BEC,0x6BEB,0x6BF3,0x6BEF,0x9EBE,
+0x6C08,0x6C13,0x6C14,0x6C1B,0x6C24,0x6C23,0x6C5E,0x6C55,
+0x6C62,0x6C6A,0x6C82,0x6C8D,0x6C9A,0x6C81,0x6C9B,0x6C7E,
+0x6C68,0x6C73,0x6C92,0x6C90,0x6CC4,0x6CF1,0x6CD3,0x6CBD,
+0x6CD7,0x6CC5,0x6CDD,0x6CAE,0x6CB1,0x6CBE};
+
+/* page 54 0x5E21-0x5E7E */
+static uint16 tab_jisx0208_uni54[]={
+0x6CBA,0x6CDB,0x6CEF,0x6CD9,0x6CEA,0x6D1F,0x884D,0x6D36,
+0x6D2B,0x6D3D,0x6D38,0x6D19,0x6D35,0x6D33,0x6D12,0x6D0C,
+0x6D63,0x6D93,0x6D64,0x6D5A,0x6D79,0x6D59,0x6D8E,0x6D95,
+0x6FE4,0x6D85,0x6DF9,0x6E15,0x6E0A,0x6DB5,0x6DC7,0x6DE6,
+0x6DB8,0x6DC6,0x6DEC,0x6DDE,0x6DCC,0x6DE8,0x6DD2,0x6DC5,
+0x6DFA,0x6DD9,0x6DE4,0x6DD5,0x6DEA,0x6DEE,0x6E2D,0x6E6E,
+0x6E2E,0x6E19,0x6E72,0x6E5F,0x6E3E,0x6E23,0x6E6B,0x6E2B,
+0x6E76,0x6E4D,0x6E1F,0x6E43,0x6E3A,0x6E4E,0x6E24,0x6EFF,
+0x6E1D,0x6E38,0x6E82,0x6EAA,0x6E98,0x6EC9,0x6EB7,0x6ED3,
+0x6EBD,0x6EAF,0x6EC4,0x6EB2,0x6ED4,0x6ED5,0x6E8F,0x6EA5,
+0x6EC2,0x6E9F,0x6F41,0x6F11,0x704C,0x6EEC,0x6EF8,0x6EFE,
+0x6F3F,0x6EF2,0x6F31,0x6EEF,0x6F32,0x6ECC};
+
+/* page 55 0x5F21-0x5F7E */
+static uint16 tab_jisx0208_uni55[]={
+0x6F3E,0x6F13,0x6EF7,0x6F86,0x6F7A,0x6F78,0x6F81,0x6F80,
+0x6F6F,0x6F5B,0x6FF3,0x6F6D,0x6F82,0x6F7C,0x6F58,0x6F8E,
+0x6F91,0x6FC2,0x6F66,0x6FB3,0x6FA3,0x6FA1,0x6FA4,0x6FB9,
+0x6FC6,0x6FAA,0x6FDF,0x6FD5,0x6FEC,0x6FD4,0x6FD8,0x6FF1,
+0x6FEE,0x6FDB,0x7009,0x700B,0x6FFA,0x7011,0x7001,0x700F,
+0x6FFE,0x701B,0x701A,0x6F74,0x701D,0x7018,0x701F,0x7030,
+0x703E,0x7032,0x7051,0x7063,0x7099,0x7092,0x70AF,0x70F1,
+0x70AC,0x70B8,0x70B3,0x70AE,0x70DF,0x70CB,0x70DD,0x70D9,
+0x7109,0x70FD,0x711C,0x7119,0x7165,0x7155,0x7188,0x7166,
+0x7162,0x714C,0x7156,0x716C,0x718F,0x71FB,0x7184,0x7195,
+0x71A8,0x71AC,0x71D7,0x71B9,0x71BE,0x71D2,0x71C9,0x71D4,
+0x71CE,0x71E0,0x71EC,0x71E7,0x71F5,0x71FC};
+
+/* page 56 0x6021-0x607E */
+static uint16 tab_jisx0208_uni56[]={
+0x71F9,0x71FF,0x720D,0x7210,0x721B,0x7228,0x722D,0x722C,
+0x7230,0x7232,0x723B,0x723C,0x723F,0x7240,0x7246,0x724B,
+0x7258,0x7274,0x727E,0x7282,0x7281,0x7287,0x7292,0x7296,
+0x72A2,0x72A7,0x72B9,0x72B2,0x72C3,0x72C6,0x72C4,0x72CE,
+0x72D2,0x72E2,0x72E0,0x72E1,0x72F9,0x72F7,0x500F,0x7317,
+0x730A,0x731C,0x7316,0x731D,0x7334,0x732F,0x7329,0x7325,
+0x733E,0x734E,0x734F,0x9ED8,0x7357,0x736A,0x7368,0x7370,
+0x7378,0x7375,0x737B,0x737A,0x73C8,0x73B3,0x73CE,0x73BB,
+0x73C0,0x73E5,0x73EE,0x73DE,0x74A2,0x7405,0x746F,0x7425,
+0x73F8,0x7432,0x743A,0x7455,0x743F,0x745F,0x7459,0x7441,
+0x745C,0x7469,0x7470,0x7463,0x746A,0x7476,0x747E,0x748B,
+0x749E,0x74A7,0x74CA,0x74CF,0x74D4,0x73F1};
+
+/* page 57 0x6121-0x617E */
+static uint16 tab_jisx0208_uni57[]={
+0x74E0,0x74E3,0x74E7,0x74E9,0x74EE,0x74F2,0x74F0,0x74F1,
+0x74F8,0x74F7,0x7504,0x7503,0x7505,0x750C,0x750E,0x750D,
+0x7515,0x7513,0x751E,0x7526,0x752C,0x753C,0x7544,0x754D,
+0x754A,0x7549,0x755B,0x7546,0x755A,0x7569,0x7564,0x7567,
+0x756B,0x756D,0x7578,0x7576,0x7586,0x7587,0x7574,0x758A,
+0x7589,0x7582,0x7594,0x759A,0x759D,0x75A5,0x75A3,0x75C2,
+0x75B3,0x75C3,0x75B5,0x75BD,0x75B8,0x75BC,0x75B1,0x75CD,
+0x75CA,0x75D2,0x75D9,0x75E3,0x75DE,0x75FE,0x75FF,0x75FC,
+0x7601,0x75F0,0x75FA,0x75F2,0x75F3,0x760B,0x760D,0x7609,
+0x761F,0x7627,0x7620,0x7621,0x7622,0x7624,0x7634,0x7630,
+0x763B,0x7647,0x7648,0x7646,0x765C,0x7658,0x7661,0x7662,
+0x7668,0x7669,0x766A,0x7667,0x766C,0x7670};
+
+/* page 58 0x6221-0x627E */
+static uint16 tab_jisx0208_uni58[]={
+0x7672,0x7676,0x7678,0x767C,0x7680,0x7683,0x7688,0x768B,
+0x768E,0x7696,0x7693,0x7699,0x769A,0x76B0,0x76B4,0x76B8,
+0x76B9,0x76BA,0x76C2,0x76CD,0x76D6,0x76D2,0x76DE,0x76E1,
+0x76E5,0x76E7,0x76EA,0x862F,0x76FB,0x7708,0x7707,0x7704,
+0x7729,0x7724,0x771E,0x7725,0x7726,0x771B,0x7737,0x7738,
+0x7747,0x775A,0x7768,0x776B,0x775B,0x7765,0x777F,0x777E,
+0x7779,0x778E,0x778B,0x7791,0x77A0,0x779E,0x77B0,0x77B6,
+0x77B9,0x77BF,0x77BC,0x77BD,0x77BB,0x77C7,0x77CD,0x77D7,
+0x77DA,0x77DC,0x77E3,0x77EE,0x77FC,0x780C,0x7812,0x7926,
+0x7820,0x792A,0x7845,0x788E,0x7874,0x7886,0x787C,0x789A,
+0x788C,0x78A3,0x78B5,0x78AA,0x78AF,0x78D1,0x78C6,0x78CB,
+0x78D4,0x78BE,0x78BC,0x78C5,0x78CA,0x78EC};
+
+/* page 59 0x6321-0x637E */
+static uint16 tab_jisx0208_uni59[]={
+0x78E7,0x78DA,0x78FD,0x78F4,0x7907,0x7912,0x7911,0x7919,
+0x792C,0x792B,0x7940,0x7960,0x7957,0x795F,0x795A,0x7955,
+0x7953,0x797A,0x797F,0x798A,0x799D,0x79A7,0x9F4B,0x79AA,
+0x79AE,0x79B3,0x79B9,0x79BA,0x79C9,0x79D5,0x79E7,0x79EC,
+0x79E1,0x79E3,0x7A08,0x7A0D,0x7A18,0x7A19,0x7A20,0x7A1F,
+0x7980,0x7A31,0x7A3B,0x7A3E,0x7A37,0x7A43,0x7A57,0x7A49,
+0x7A61,0x7A62,0x7A69,0x9F9D,0x7A70,0x7A79,0x7A7D,0x7A88,
+0x7A97,0x7A95,0x7A98,0x7A96,0x7AA9,0x7AC8,0x7AB0,0x7AB6,
+0x7AC5,0x7AC4,0x7ABF,0x9083,0x7AC7,0x7ACA,0x7ACD,0x7ACF,
+0x7AD5,0x7AD3,0x7AD9,0x7ADA,0x7ADD,0x7AE1,0x7AE2,0x7AE6,
+0x7AED,0x7AF0,0x7B02,0x7B0F,0x7B0A,0x7B06,0x7B33,0x7B18,
+0x7B19,0x7B1E,0x7B35,0x7B28,0x7B36,0x7B50};
+
+/* page 60 0x6421-0x647E */
+static uint16 tab_jisx0208_uni60[]={
+0x7B7A,0x7B04,0x7B4D,0x7B0B,0x7B4C,0x7B45,0x7B75,0x7B65,
+0x7B74,0x7B67,0x7B70,0x7B71,0x7B6C,0x7B6E,0x7B9D,0x7B98,
+0x7B9F,0x7B8D,0x7B9C,0x7B9A,0x7B8B,0x7B92,0x7B8F,0x7B5D,
+0x7B99,0x7BCB,0x7BC1,0x7BCC,0x7BCF,0x7BB4,0x7BC6,0x7BDD,
+0x7BE9,0x7C11,0x7C14,0x7BE6,0x7BE5,0x7C60,0x7C00,0x7C07,
+0x7C13,0x7BF3,0x7BF7,0x7C17,0x7C0D,0x7BF6,0x7C23,0x7C27,
+0x7C2A,0x7C1F,0x7C37,0x7C2B,0x7C3D,0x7C4C,0x7C43,0x7C54,
+0x7C4F,0x7C40,0x7C50,0x7C58,0x7C5F,0x7C64,0x7C56,0x7C65,
+0x7C6C,0x7C75,0x7C83,0x7C90,0x7CA4,0x7CAD,0x7CA2,0x7CAB,
+0x7CA1,0x7CA8,0x7CB3,0x7CB2,0x7CB1,0x7CAE,0x7CB9,0x7CBD,
+0x7CC0,0x7CC5,0x7CC2,0x7CD8,0x7CD2,0x7CDC,0x7CE2,0x9B3B,
+0x7CEF,0x7CF2,0x7CF4,0x7CF6,0x7CFA,0x7D06};
+
+/* page 61 0x6521-0x657E */
+static uint16 tab_jisx0208_uni61[]={
+0x7D02,0x7D1C,0x7D15,0x7D0A,0x7D45,0x7D4B,0x7D2E,0x7D32,
+0x7D3F,0x7D35,0x7D46,0x7D73,0x7D56,0x7D4E,0x7D72,0x7D68,
+0x7D6E,0x7D4F,0x7D63,0x7D93,0x7D89,0x7D5B,0x7D8F,0x7D7D,
+0x7D9B,0x7DBA,0x7DAE,0x7DA3,0x7DB5,0x7DC7,0x7DBD,0x7DAB,
+0x7E3D,0x7DA2,0x7DAF,0x7DDC,0x7DB8,0x7D9F,0x7DB0,0x7DD8,
+0x7DDD,0x7DE4,0x7DDE,0x7DFB,0x7DF2,0x7DE1,0x7E05,0x7E0A,
+0x7E23,0x7E21,0x7E12,0x7E31,0x7E1F,0x7E09,0x7E0B,0x7E22,
+0x7E46,0x7E66,0x7E3B,0x7E35,0x7E39,0x7E43,0x7E37,0x7E32,
+0x7E3A,0x7E67,0x7E5D,0x7E56,0x7E5E,0x7E59,0x7E5A,0x7E79,
+0x7E6A,0x7E69,0x7E7C,0x7E7B,0x7E83,0x7DD5,0x7E7D,0x8FAE,
+0x7E7F,0x7E88,0x7E89,0x7E8C,0x7E92,0x7E90,0x7E93,0x7E94,
+0x7E96,0x7E8E,0x7E9B,0x7E9C,0x7F38,0x7F3A};
+
+/* page 62 0x6621-0x667E */
+static uint16 tab_jisx0208_uni62[]={
+0x7F45,0x7F4C,0x7F4D,0x7F4E,0x7F50,0x7F51,0x7F55,0x7F54,
+0x7F58,0x7F5F,0x7F60,0x7F68,0x7F69,0x7F67,0x7F78,0x7F82,
+0x7F86,0x7F83,0x7F88,0x7F87,0x7F8C,0x7F94,0x7F9E,0x7F9D,
+0x7F9A,0x7FA3,0x7FAF,0x7FB2,0x7FB9,0x7FAE,0x7FB6,0x7FB8,
+0x8B71,0x7FC5,0x7FC6,0x7FCA,0x7FD5,0x7FD4,0x7FE1,0x7FE6,
+0x7FE9,0x7FF3,0x7FF9,0x98DC,0x8006,0x8004,0x800B,0x8012,
+0x8018,0x8019,0x801C,0x8021,0x8028,0x803F,0x803B,0x804A,
+0x8046,0x8052,0x8058,0x805A,0x805F,0x8062,0x8068,0x8073,
+0x8072,0x8070,0x8076,0x8079,0x807D,0x807F,0x8084,0x8086,
+0x8085,0x809B,0x8093,0x809A,0x80AD,0x5190,0x80AC,0x80DB,
+0x80E5,0x80D9,0x80DD,0x80C4,0x80DA,0x80D6,0x8109,0x80EF,
+0x80F1,0x811B,0x8129,0x8123,0x812F,0x814B};
+
+/* page 63 0x6721-0x677E */
+static uint16 tab_jisx0208_uni63[]={
+0x968B,0x8146,0x813E,0x8153,0x8151,0x80FC,0x8171,0x816E,
+0x8165,0x8166,0x8174,0x8183,0x8188,0x818A,0x8180,0x8182,
+0x81A0,0x8195,0x81A4,0x81A3,0x815F,0x8193,0x81A9,0x81B0,
+0x81B5,0x81BE,0x81B8,0x81BD,0x81C0,0x81C2,0x81BA,0x81C9,
+0x81CD,0x81D1,0x81D9,0x81D8,0x81C8,0x81DA,0x81DF,0x81E0,
+0x81E7,0x81FA,0x81FB,0x81FE,0x8201,0x8202,0x8205,0x8207,
+0x820A,0x820D,0x8210,0x8216,0x8229,0x822B,0x8238,0x8233,
+0x8240,0x8259,0x8258,0x825D,0x825A,0x825F,0x8264,0x8262,
+0x8268,0x826A,0x826B,0x822E,0x8271,0x8277,0x8278,0x827E,
+0x828D,0x8292,0x82AB,0x829F,0x82BB,0x82AC,0x82E1,0x82E3,
+0x82DF,0x82D2,0x82F4,0x82F3,0x82FA,0x8393,0x8303,0x82FB,
+0x82F9,0x82DE,0x8306,0x82DC,0x8309,0x82D9};
+
+/* page 64 0x6821-0x687E */
+static uint16 tab_jisx0208_uni64[]={
+0x8335,0x8334,0x8316,0x8332,0x8331,0x8340,0x8339,0x8350,
+0x8345,0x832F,0x832B,0x8317,0x8318,0x8385,0x839A,0x83AA,
+0x839F,0x83A2,0x8396,0x8323,0x838E,0x8387,0x838A,0x837C,
+0x83B5,0x8373,0x8375,0x83A0,0x8389,0x83A8,0x83F4,0x8413,
+0x83EB,0x83CE,0x83FD,0x8403,0x83D8,0x840B,0x83C1,0x83F7,
+0x8407,0x83E0,0x83F2,0x840D,0x8422,0x8420,0x83BD,0x8438,
+0x8506,0x83FB,0x846D,0x842A,0x843C,0x855A,0x8484,0x8477,
+0x846B,0x84AD,0x846E,0x8482,0x8469,0x8446,0x842C,0x846F,
+0x8479,0x8435,0x84CA,0x8462,0x84B9,0x84BF,0x849F,0x84D9,
+0x84CD,0x84BB,0x84DA,0x84D0,0x84C1,0x84C6,0x84D6,0x84A1,
+0x8521,0x84FF,0x84F4,0x8517,0x8518,0x852C,0x851F,0x8515,
+0x8514,0x84FC,0x8540,0x8563,0x8558,0x8548};
+
+/* page 65 0x6921-0x697E */
+static uint16 tab_jisx0208_uni65[]={
+0x8541,0x8602,0x854B,0x8555,0x8580,0x85A4,0x8588,0x8591,
+0x858A,0x85A8,0x856D,0x8594,0x859B,0x85EA,0x8587,0x859C,
+0x8577,0x857E,0x8590,0x85C9,0x85BA,0x85CF,0x85B9,0x85D0,
+0x85D5,0x85DD,0x85E5,0x85DC,0x85F9,0x860A,0x8613,0x860B,
+0x85FE,0x85FA,0x8606,0x8622,0x861A,0x8630,0x863F,0x864D,
+0x4E55,0x8654,0x865F,0x8667,0x8671,0x8693,0x86A3,0x86A9,
+0x86AA,0x868B,0x868C,0x86B6,0x86AF,0x86C4,0x86C6,0x86B0,
+0x86C9,0x8823,0x86AB,0x86D4,0x86DE,0x86E9,0x86EC,0x86DF,
+0x86DB,0x86EF,0x8712,0x8706,0x8708,0x8700,0x8703,0x86FB,
+0x8711,0x8709,0x870D,0x86F9,0x870A,0x8734,0x873F,0x8737,
+0x873B,0x8725,0x8729,0x871A,0x8760,0x875F,0x8778,0x874C,
+0x874E,0x8774,0x8757,0x8768,0x876E,0x8759};
+
+/* page 66 0x6A21-0x6A7E */
+static uint16 tab_jisx0208_uni66[]={
+0x8753,0x8763,0x876A,0x8805,0x87A2,0x879F,0x8782,0x87AF,
+0x87CB,0x87BD,0x87C0,0x87D0,0x96D6,0x87AB,0x87C4,0x87B3,
+0x87C7,0x87C6,0x87BB,0x87EF,0x87F2,0x87E0,0x880F,0x880D,
+0x87FE,0x87F6,0x87F7,0x880E,0x87D2,0x8811,0x8816,0x8815,
+0x8822,0x8821,0x8831,0x8836,0x8839,0x8827,0x883B,0x8844,
+0x8842,0x8852,0x8859,0x885E,0x8862,0x886B,0x8881,0x887E,
+0x889E,0x8875,0x887D,0x88B5,0x8872,0x8882,0x8897,0x8892,
+0x88AE,0x8899,0x88A2,0x888D,0x88A4,0x88B0,0x88BF,0x88B1,
+0x88C3,0x88C4,0x88D4,0x88D8,0x88D9,0x88DD,0x88F9,0x8902,
+0x88FC,0x88F4,0x88E8,0x88F2,0x8904,0x890C,0x890A,0x8913,
+0x8943,0x891E,0x8925,0x892A,0x892B,0x8941,0x8944,0x893B,
+0x8936,0x8938,0x894C,0x891D,0x8960,0x895E};
+
+/* page 67 0x6B21-0x6B7E */
+static uint16 tab_jisx0208_uni67[]={
+0x8966,0x8964,0x896D,0x896A,0x896F,0x8974,0x8977,0x897E,
+0x8983,0x8988,0x898A,0x8993,0x8998,0x89A1,0x89A9,0x89A6,
+0x89AC,0x89AF,0x89B2,0x89BA,0x89BD,0x89BF,0x89C0,0x89DA,
+0x89DC,0x89DD,0x89E7,0x89F4,0x89F8,0x8A03,0x8A16,0x8A10,
+0x8A0C,0x8A1B,0x8A1D,0x8A25,0x8A36,0x8A41,0x8A5B,0x8A52,
+0x8A46,0x8A48,0x8A7C,0x8A6D,0x8A6C,0x8A62,0x8A85,0x8A82,
+0x8A84,0x8AA8,0x8AA1,0x8A91,0x8AA5,0x8AA6,0x8A9A,0x8AA3,
+0x8AC4,0x8ACD,0x8AC2,0x8ADA,0x8AEB,0x8AF3,0x8AE7,0x8AE4,
+0x8AF1,0x8B14,0x8AE0,0x8AE2,0x8AF7,0x8ADE,0x8ADB,0x8B0C,
+0x8B07,0x8B1A,0x8AE1,0x8B16,0x8B10,0x8B17,0x8B20,0x8B33,
+0x97AB,0x8B26,0x8B2B,0x8B3E,0x8B28,0x8B41,0x8B4C,0x8B4F,
+0x8B4E,0x8B49,0x8B56,0x8B5B,0x8B5A,0x8B6B};
+
+/* page 68 0x6C21-0x6C7E */
+static uint16 tab_jisx0208_uni68[]={
+0x8B5F,0x8B6C,0x8B6F,0x8B74,0x8B7D,0x8B80,0x8B8C,0x8B8E,
+0x8B92,0x8B93,0x8B96,0x8B99,0x8B9A,0x8C3A,0x8C41,0x8C3F,
+0x8C48,0x8C4C,0x8C4E,0x8C50,0x8C55,0x8C62,0x8C6C,0x8C78,
+0x8C7A,0x8C82,0x8C89,0x8C85,0x8C8A,0x8C8D,0x8C8E,0x8C94,
+0x8C7C,0x8C98,0x621D,0x8CAD,0x8CAA,0x8CBD,0x8CB2,0x8CB3,
+0x8CAE,0x8CB6,0x8CC8,0x8CC1,0x8CE4,0x8CE3,0x8CDA,0x8CFD,
+0x8CFA,0x8CFB,0x8D04,0x8D05,0x8D0A,0x8D07,0x8D0F,0x8D0D,
+0x8D10,0x9F4E,0x8D13,0x8CCD,0x8D14,0x8D16,0x8D67,0x8D6D,
+0x8D71,0x8D73,0x8D81,0x8D99,0x8DC2,0x8DBE,0x8DBA,0x8DCF,
+0x8DDA,0x8DD6,0x8DCC,0x8DDB,0x8DCB,0x8DEA,0x8DEB,0x8DDF,
+0x8DE3,0x8DFC,0x8E08,0x8E09,0x8DFF,0x8E1D,0x8E1E,0x8E10,
+0x8E1F,0x8E42,0x8E35,0x8E30,0x8E34,0x8E4A};
+
+/* page 69 0x6D21-0x6D7E */
+static uint16 tab_jisx0208_uni69[]={
+0x8E47,0x8E49,0x8E4C,0x8E50,0x8E48,0x8E59,0x8E64,0x8E60,
+0x8E2A,0x8E63,0x8E55,0x8E76,0x8E72,0x8E7C,0x8E81,0x8E87,
+0x8E85,0x8E84,0x8E8B,0x8E8A,0x8E93,0x8E91,0x8E94,0x8E99,
+0x8EAA,0x8EA1,0x8EAC,0x8EB0,0x8EC6,0x8EB1,0x8EBE,0x8EC5,
+0x8EC8,0x8ECB,0x8EDB,0x8EE3,0x8EFC,0x8EFB,0x8EEB,0x8EFE,
+0x8F0A,0x8F05,0x8F15,0x8F12,0x8F19,0x8F13,0x8F1C,0x8F1F,
+0x8F1B,0x8F0C,0x8F26,0x8F33,0x8F3B,0x8F39,0x8F45,0x8F42,
+0x8F3E,0x8F4C,0x8F49,0x8F46,0x8F4E,0x8F57,0x8F5C,0x8F62,
+0x8F63,0x8F64,0x8F9C,0x8F9F,0x8FA3,0x8FAD,0x8FAF,0x8FB7,
+0x8FDA,0x8FE5,0x8FE2,0x8FEA,0x8FEF,0x9087,0x8FF4,0x9005,
+0x8FF9,0x8FFA,0x9011,0x9015,0x9021,0x900D,0x901E,0x9016,
+0x900B,0x9027,0x9036,0x9035,0x9039,0x8FF8};
+
+/* page 70 0x6E21-0x6E7E */
+static uint16 tab_jisx0208_uni70[]={
+0x904F,0x9050,0x9051,0x9052,0x900E,0x9049,0x903E,0x9056,
+0x9058,0x905E,0x9068,0x906F,0x9076,0x96A8,0x9072,0x9082,
+0x907D,0x9081,0x9080,0x908A,0x9089,0x908F,0x90A8,0x90AF,
+0x90B1,0x90B5,0x90E2,0x90E4,0x6248,0x90DB,0x9102,0x9112,
+0x9119,0x9132,0x9130,0x914A,0x9156,0x9158,0x9163,0x9165,
+0x9169,0x9173,0x9172,0x918B,0x9189,0x9182,0x91A2,0x91AB,
+0x91AF,0x91AA,0x91B5,0x91B4,0x91BA,0x91C0,0x91C1,0x91C9,
+0x91CB,0x91D0,0x91D6,0x91DF,0x91E1,0x91DB,0x91FC,0x91F5,
+0x91F6,0x921E,0x91FF,0x9214,0x922C,0x9215,0x9211,0x925E,
+0x9257,0x9245,0x9249,0x9264,0x9248,0x9295,0x923F,0x924B,
+0x9250,0x929C,0x9296,0x9293,0x929B,0x925A,0x92CF,0x92B9,
+0x92B7,0x92E9,0x930F,0x92FA,0x9344,0x932E};
+
+/* page 71 0x6F21-0x6F7E */
+static uint16 tab_jisx0208_uni71[]={
+0x9319,0x9322,0x931A,0x9323,0x933A,0x9335,0x933B,0x935C,
+0x9360,0x937C,0x936E,0x9356,0x93B0,0x93AC,0x93AD,0x9394,
+0x93B9,0x93D6,0x93D7,0x93E8,0x93E5,0x93D8,0x93C3,0x93DD,
+0x93D0,0x93C8,0x93E4,0x941A,0x9414,0x9413,0x9403,0x9407,
+0x9410,0x9436,0x942B,0x9435,0x9421,0x943A,0x9441,0x9452,
+0x9444,0x945B,0x9460,0x9462,0x945E,0x946A,0x9229,0x9470,
+0x9475,0x9477,0x947D,0x945A,0x947C,0x947E,0x9481,0x947F,
+0x9582,0x9587,0x958A,0x9594,0x9596,0x9598,0x9599,0x95A0,
+0x95A8,0x95A7,0x95AD,0x95BC,0x95BB,0x95B9,0x95BE,0x95CA,
+0x6FF6,0x95C3,0x95CD,0x95CC,0x95D5,0x95D4,0x95D6,0x95DC,
+0x95E1,0x95E5,0x95E2,0x9621,0x9628,0x962E,0x962F,0x9642,
+0x964C,0x964F,0x964B,0x9677,0x965C,0x965E};
+
+/* page 72 0x7021-0x707E */
+static uint16 tab_jisx0208_uni72[]={
+0x965D,0x965F,0x9666,0x9672,0x966C,0x968D,0x9698,0x9695,
+0x9697,0x96AA,0x96A7,0x96B1,0x96B2,0x96B0,0x96B4,0x96B6,
+0x96B8,0x96B9,0x96CE,0x96CB,0x96C9,0x96CD,0x894D,0x96DC,
+0x970D,0x96D5,0x96F9,0x9704,0x9706,0x9708,0x9713,0x970E,
+0x9711,0x970F,0x9716,0x9719,0x9724,0x972A,0x9730,0x9739,
+0x973D,0x973E,0x9744,0x9746,0x9748,0x9742,0x9749,0x975C,
+0x9760,0x9764,0x9766,0x9768,0x52D2,0x976B,0x9771,0x9779,
+0x9785,0x977C,0x9781,0x977A,0x9786,0x978B,0x978F,0x9790,
+0x979C,0x97A8,0x97A6,0x97A3,0x97B3,0x97B4,0x97C3,0x97C6,
+0x97C8,0x97CB,0x97DC,0x97ED,0x9F4F,0x97F2,0x7ADF,0x97F6,
+0x97F5,0x980F,0x980C,0x9838,0x9824,0x9821,0x9837,0x983D,
+0x9846,0x984F,0x984B,0x986B,0x986F,0x9870};
+
+/* page 73 0x7121-0x717E */
+static uint16 tab_jisx0208_uni73[]={
+0x9871,0x9874,0x9873,0x98AA,0x98AF,0x98B1,0x98B6,0x98C4,
+0x98C3,0x98C6,0x98E9,0x98EB,0x9903,0x9909,0x9912,0x9914,
+0x9918,0x9921,0x991D,0x991E,0x9924,0x9920,0x992C,0x992E,
+0x993D,0x993E,0x9942,0x9949,0x9945,0x9950,0x994B,0x9951,
+0x9952,0x994C,0x9955,0x9997,0x9998,0x99A5,0x99AD,0x99AE,
+0x99BC,0x99DF,0x99DB,0x99DD,0x99D8,0x99D1,0x99ED,0x99EE,
+0x99F1,0x99F2,0x99FB,0x99F8,0x9A01,0x9A0F,0x9A05,0x99E2,
+0x9A19,0x9A2B,0x9A37,0x9A45,0x9A42,0x9A40,0x9A43,0x9A3E,
+0x9A55,0x9A4D,0x9A5B,0x9A57,0x9A5F,0x9A62,0x9A65,0x9A64,
+0x9A69,0x9A6B,0x9A6A,0x9AAD,0x9AB0,0x9ABC,0x9AC0,0x9ACF,
+0x9AD1,0x9AD3,0x9AD4,0x9ADE,0x9ADF,0x9AE2,0x9AE3,0x9AE6,
+0x9AEF,0x9AEB,0x9AEE,0x9AF4,0x9AF1,0x9AF7};
+
+/* page 74 0x7221-0x727E */
+static uint16 tab_jisx0208_uni74[]={
+0x9AFB,0x9B06,0x9B18,0x9B1A,0x9B1F,0x9B22,0x9B23,0x9B25,
+0x9B27,0x9B28,0x9B29,0x9B2A,0x9B2E,0x9B2F,0x9B32,0x9B44,
+0x9B43,0x9B4F,0x9B4D,0x9B4E,0x9B51,0x9B58,0x9B74,0x9B93,
+0x9B83,0x9B91,0x9B96,0x9B97,0x9B9F,0x9BA0,0x9BA8,0x9BB4,
+0x9BC0,0x9BCA,0x9BB9,0x9BC6,0x9BCF,0x9BD1,0x9BD2,0x9BE3,
+0x9BE2,0x9BE4,0x9BD4,0x9BE1,0x9C3A,0x9BF2,0x9BF1,0x9BF0,
+0x9C15,0x9C14,0x9C09,0x9C13,0x9C0C,0x9C06,0x9C08,0x9C12,
+0x9C0A,0x9C04,0x9C2E,0x9C1B,0x9C25,0x9C24,0x9C21,0x9C30,
+0x9C47,0x9C32,0x9C46,0x9C3E,0x9C5A,0x9C60,0x9C67,0x9C76,
+0x9C78,0x9CE7,0x9CEC,0x9CF0,0x9D09,0x9D08,0x9CEB,0x9D03,
+0x9D06,0x9D2A,0x9D26,0x9DAF,0x9D23,0x9D1F,0x9D44,0x9D15,
+0x9D12,0x9D41,0x9D3F,0x9D3E,0x9D46,0x9D48};
+
+/* page 75 0x7321-0x737E */
+static uint16 tab_jisx0208_uni75[]={
+0x9D5D,0x9D5E,0x9D64,0x9D51,0x9D50,0x9D59,0x9D72,0x9D89,
+0x9D87,0x9DAB,0x9D6F,0x9D7A,0x9D9A,0x9DA4,0x9DA9,0x9DB2,
+0x9DC4,0x9DC1,0x9DBB,0x9DB8,0x9DBA,0x9DC6,0x9DCF,0x9DC2,
+0x9DD9,0x9DD3,0x9DF8,0x9DE6,0x9DED,0x9DEF,0x9DFD,0x9E1A,
+0x9E1B,0x9E1E,0x9E75,0x9E79,0x9E7D,0x9E81,0x9E88,0x9E8B,
+0x9E8C,0x9E92,0x9E95,0x9E91,0x9E9D,0x9EA5,0x9EA9,0x9EB8,
+0x9EAA,0x9EAD,0x9761,0x9ECC,0x9ECE,0x9ECF,0x9ED0,0x9ED4,
+0x9EDC,0x9EDE,0x9EDD,0x9EE0,0x9EE5,0x9EE8,0x9EEF,0x9EF4,
+0x9EF6,0x9EF7,0x9EF9,0x9EFB,0x9EFC,0x9EFD,0x9F07,0x9F08,
+0x76B7,0x9F15,0x9F21,0x9F2C,0x9F3E,0x9F4A,0x9F52,0x9F54,
+0x9F63,0x9F5F,0x9F60,0x9F61,0x9F66,0x9F67,0x9F6C,0x9F6A,
+0x9F77,0x9F72,0x9F76,0x9F95,0x9F9C,0x9FA0};
+
+/* page 76 0x7421-0x7426 */
+static uint16 tab_jisx0208_uni76[]={
+0x582F,0x69C7,0x9059,0x7464,0x51DC,0x7199};
+
+/* page 77 0x2D21 - 0x2D7C */
+static uint16 tab_nec13_uni0[]={
+0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,
+0x2468,0x2469,0x246A,0x246B,0x246C,0x246D,0x246E,0x246F,
+0x2470,0x2471,0x2472,0x2473,0x2160,0x2161,0x2162,0x2163,
+0x2164,0x2165,0x2166,0x2167,0x2168,0x2169, 0,0x3349,
+0x3314,0x3322,0x334D,0x3318,0x3327,0x3303,0x3336,0x3351,
+0x3357,0x330D,0x3326,0x3323,0x332B,0x334A,0x333B,0x339C,
+0x339D,0x339E,0x338E,0x338F,0x33C4,0x33A1, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x337B,0x301D,
+0x301F,0x2116,0x33CD,0x2121,0x32A4,0x32A5,0x32A6,0x32A7,
+0x32A8,0x3231,0x3232,0x3239,0x337E,0x337D,0x337C,0x2252,
+0x2261,0x222B,0x222E,0x2211,0x221A,0x22A5,0x2220,0x221F,
+0x22BF,0x2235,0x2229,0x222A};
+
+static int
+my_jisx0208_uni_onechar(int code){
+ if ((code>=0x2121)&&(code<=0x217E))
+ return(tab_jisx0208_uni0[code-0x2121]);
+ if ((code>=0x2221)&&(code<=0x227E))
+ return(tab_jisx0208_uni1[code-0x2221]);
+ if ((code>=0x2330)&&(code<=0x237A))
+ return(tab_jisx0208_uni2[code-0x2330]);
+ if ((code>=0x2421)&&(code<=0x2473))
+ return(tab_jisx0208_uni3[code-0x2421]);
+ if ((code>=0x2521)&&(code<=0x2576))
+ return(tab_jisx0208_uni4[code-0x2521]);
+ if ((code>=0x2621)&&(code<=0x2658))
+ return(tab_jisx0208_uni5[code-0x2621]);
+ if ((code>=0x2721)&&(code<=0x2771))
+ return(tab_jisx0208_uni6[code-0x2721]);
+ if ((code>=0x2821)&&(code<=0x2840))
+ return(tab_jisx0208_uni7[code-0x2821]);
+ if ((code>=0x3021)&&(code<=0x307E))
+ return(tab_jisx0208_uni8[code-0x3021]);
+ if ((code>=0x3121)&&(code<=0x317E))
+ return(tab_jisx0208_uni9[code-0x3121]);
+ if ((code>=0x3221)&&(code<=0x327E))
+ return(tab_jisx0208_uni10[code-0x3221]);
+ if ((code>=0x3321)&&(code<=0x337E))
+ return(tab_jisx0208_uni11[code-0x3321]);
+ if ((code>=0x3421)&&(code<=0x347E))
+ return(tab_jisx0208_uni12[code-0x3421]);
+ if ((code>=0x3521)&&(code<=0x357E))
+ return(tab_jisx0208_uni13[code-0x3521]);
+ if ((code>=0x3621)&&(code<=0x367E))
+ return(tab_jisx0208_uni14[code-0x3621]);
+ if ((code>=0x3721)&&(code<=0x377E))
+ return(tab_jisx0208_uni15[code-0x3721]);
+ if ((code>=0x3821)&&(code<=0x387E))
+ return(tab_jisx0208_uni16[code-0x3821]);
+ if ((code>=0x3921)&&(code<=0x397E))
+ return(tab_jisx0208_uni17[code-0x3921]);
+ if ((code>=0x3A21)&&(code<=0x3A7E))
+ return(tab_jisx0208_uni18[code-0x3A21]);
+ if ((code>=0x3B21)&&(code<=0x3B7E))
+ return(tab_jisx0208_uni19[code-0x3B21]);
+ if ((code>=0x3C21)&&(code<=0x3C7E))
+ return(tab_jisx0208_uni20[code-0x3C21]);
+ if ((code>=0x3D21)&&(code<=0x3D7E))
+ return(tab_jisx0208_uni21[code-0x3D21]);
+ if ((code>=0x3E21)&&(code<=0x3E7E))
+ return(tab_jisx0208_uni22[code-0x3E21]);
+ if ((code>=0x3F21)&&(code<=0x3F7E))
+ return(tab_jisx0208_uni23[code-0x3F21]);
+ if ((code>=0x4021)&&(code<=0x407E))
+ return(tab_jisx0208_uni24[code-0x4021]);
+ if ((code>=0x4121)&&(code<=0x417E))
+ return(tab_jisx0208_uni25[code-0x4121]);
+ if ((code>=0x4221)&&(code<=0x427E))
+ return(tab_jisx0208_uni26[code-0x4221]);
+ if ((code>=0x4321)&&(code<=0x437E))
+ return(tab_jisx0208_uni27[code-0x4321]);
+ if ((code>=0x4421)&&(code<=0x447E))
+ return(tab_jisx0208_uni28[code-0x4421]);
+ if ((code>=0x4521)&&(code<=0x457E))
+ return(tab_jisx0208_uni29[code-0x4521]);
+ if ((code>=0x4621)&&(code<=0x467E))
+ return(tab_jisx0208_uni30[code-0x4621]);
+ if ((code>=0x4721)&&(code<=0x477E))
+ return(tab_jisx0208_uni31[code-0x4721]);
+ if ((code>=0x4821)&&(code<=0x487E))
+ return(tab_jisx0208_uni32[code-0x4821]);
+ if ((code>=0x4921)&&(code<=0x497E))
+ return(tab_jisx0208_uni33[code-0x4921]);
+ if ((code>=0x4A21)&&(code<=0x4A7E))
+ return(tab_jisx0208_uni34[code-0x4A21]);
+ if ((code>=0x4B21)&&(code<=0x4B7E))
+ return(tab_jisx0208_uni35[code-0x4B21]);
+ if ((code>=0x4C21)&&(code<=0x4C7E))
+ return(tab_jisx0208_uni36[code-0x4C21]);
+ if ((code>=0x4D21)&&(code<=0x4D7E))
+ return(tab_jisx0208_uni37[code-0x4D21]);
+ if ((code>=0x4E21)&&(code<=0x4E7E))
+ return(tab_jisx0208_uni38[code-0x4E21]);
+ if ((code>=0x4F21)&&(code<=0x4F53))
+ return(tab_jisx0208_uni39[code-0x4F21]);
+ if ((code>=0x5021)&&(code<=0x507E))
+ return(tab_jisx0208_uni40[code-0x5021]);
+ if ((code>=0x5121)&&(code<=0x517E))
+ return(tab_jisx0208_uni41[code-0x5121]);
+ if ((code>=0x5221)&&(code<=0x527E))
+ return(tab_jisx0208_uni42[code-0x5221]);
+ if ((code>=0x5321)&&(code<=0x537E))
+ return(tab_jisx0208_uni43[code-0x5321]);
+ if ((code>=0x5421)&&(code<=0x547E))
+ return(tab_jisx0208_uni44[code-0x5421]);
+ if ((code>=0x5521)&&(code<=0x557E))
+ return(tab_jisx0208_uni45[code-0x5521]);
+ if ((code>=0x5621)&&(code<=0x567E))
+ return(tab_jisx0208_uni46[code-0x5621]);
+ if ((code>=0x5721)&&(code<=0x577E))
+ return(tab_jisx0208_uni47[code-0x5721]);
+ if ((code>=0x5821)&&(code<=0x587E))
+ return(tab_jisx0208_uni48[code-0x5821]);
+ if ((code>=0x5921)&&(code<=0x597E))
+ return(tab_jisx0208_uni49[code-0x5921]);
+ if ((code>=0x5A21)&&(code<=0x5A7E))
+ return(tab_jisx0208_uni50[code-0x5A21]);
+ if ((code>=0x5B21)&&(code<=0x5B7E))
+ return(tab_jisx0208_uni51[code-0x5B21]);
+ if ((code>=0x5C21)&&(code<=0x5C7E))
+ return(tab_jisx0208_uni52[code-0x5C21]);
+ if ((code>=0x5D21)&&(code<=0x5D7E))
+ return(tab_jisx0208_uni53[code-0x5D21]);
+ if ((code>=0x5E21)&&(code<=0x5E7E))
+ return(tab_jisx0208_uni54[code-0x5E21]);
+ if ((code>=0x5F21)&&(code<=0x5F7E))
+ return(tab_jisx0208_uni55[code-0x5F21]);
+ if ((code>=0x6021)&&(code<=0x607E))
+ return(tab_jisx0208_uni56[code-0x6021]);
+ if ((code>=0x6121)&&(code<=0x617E))
+ return(tab_jisx0208_uni57[code-0x6121]);
+ if ((code>=0x6221)&&(code<=0x627E))
+ return(tab_jisx0208_uni58[code-0x6221]);
+ if ((code>=0x6321)&&(code<=0x637E))
+ return(tab_jisx0208_uni59[code-0x6321]);
+ if ((code>=0x6421)&&(code<=0x647E))
+ return(tab_jisx0208_uni60[code-0x6421]);
+ if ((code>=0x6521)&&(code<=0x657E))
+ return(tab_jisx0208_uni61[code-0x6521]);
+ if ((code>=0x6621)&&(code<=0x667E))
+ return(tab_jisx0208_uni62[code-0x6621]);
+ if ((code>=0x6721)&&(code<=0x677E))
+ return(tab_jisx0208_uni63[code-0x6721]);
+ if ((code>=0x6821)&&(code<=0x687E))
+ return(tab_jisx0208_uni64[code-0x6821]);
+ if ((code>=0x6921)&&(code<=0x697E))
+ return(tab_jisx0208_uni65[code-0x6921]);
+ if ((code>=0x6A21)&&(code<=0x6A7E))
+ return(tab_jisx0208_uni66[code-0x6A21]);
+ if ((code>=0x6B21)&&(code<=0x6B7E))
+ return(tab_jisx0208_uni67[code-0x6B21]);
+ if ((code>=0x6C21)&&(code<=0x6C7E))
+ return(tab_jisx0208_uni68[code-0x6C21]);
+ if ((code>=0x6D21)&&(code<=0x6D7E))
+ return(tab_jisx0208_uni69[code-0x6D21]);
+ if ((code>=0x6E21)&&(code<=0x6E7E))
+ return(tab_jisx0208_uni70[code-0x6E21]);
+ if ((code>=0x6F21)&&(code<=0x6F7E))
+ return(tab_jisx0208_uni71[code-0x6F21]);
+ if ((code>=0x7021)&&(code<=0x707E))
+ return(tab_jisx0208_uni72[code-0x7021]);
+ if ((code>=0x7121)&&(code<=0x717E))
+ return(tab_jisx0208_uni73[code-0x7121]);
+ if ((code>=0x7221)&&(code<=0x727E))
+ return(tab_jisx0208_uni74[code-0x7221]);
+ if ((code>=0x7321)&&(code<=0x737E))
+ return(tab_jisx0208_uni75[code-0x7321]);
+ if ((code>=0x7421)&&(code<=0x7426))
+ return(tab_jisx0208_uni76[code-0x7421]);
+ if ((code>=0x2D21)&&(code<=0x2D7C))
+ return(tab_nec13_uni0[code-0x2D21]);
+ return(0);
+}
+
+/* page 0 0x005C-0x005C */
+static uint16 tab_uni_jisx02080[]={
+0x5C};
+
+/* page 1 0x00A2-0x00B6 */
+static uint16 tab_uni_jisx02081[]={
+ 0, 0, 0, 0, 0,0x2178,0x212F, 0,
+ 0, 0, 0, 0, 0, 0,0x216B,0x215E,
+ 0, 0,0x212D, 0,0x2279};
+
+/* page 2 0x00D7-0x00D7 */
+static uint16 tab_uni_jisx02082[]={
+0x215F};
+
+/* page 3 0x00F7-0x00F7 */
+static uint16 tab_uni_jisx02083[]={
+0x07};
+
+/* page 4 0x0391-0x03C9 */
+static uint16 tab_uni_jisx02084[]={
+0x2621,0x2622,0x2623,0x2624,0x2625,0x2626,0x2627,0x2628,
+0x2629,0x262A,0x262B,0x262C,0x262D,0x262E,0x262F,0x2630,
+0x2631, 0,0x2632,0x2633,0x2634,0x2635,0x2636,0x2637,
+0x2638, 0, 0, 0, 0, 0, 0, 0,
+0x2641,0x2642,0x2643,0x2644,0x2645,0x2646,0x2647,0x2648,
+0x2649,0x264A,0x264B,0x264C,0x264D,0x264E,0x264F,0x2650,
+0x2651, 0,0x2652,0x2653,0x2654,0x2655,0x2656,0x2657,
+0x2658};
+
+/* page 5 0x0401-0x0451 */
+static uint16 tab_uni_jisx02085[]={
+0x2727, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x2721,
+0x2722,0x2723,0x2724,0x2725,0x2726,0x2728,0x2729,0x272A,
+0x272B,0x272C,0x272D,0x272E,0x272F,0x2730,0x2731,0x2732,
+0x2733,0x2734,0x2735,0x2736,0x2737,0x2738,0x2739,0x273A,
+0x273B,0x273C,0x273D,0x273E,0x273F,0x2740,0x2741,0x2751,
+0x2752,0x2753,0x2754,0x2755,0x2756,0x2758,0x2759,0x275A,
+0x275B,0x275C,0x275D,0x275E,0x275F,0x2760,0x2761,0x2762,
+0x2763,0x2764,0x2765,0x2766,0x2767,0x2768,0x2769,0x276A,
+0x276B,0x276C,0x276D,0x276E,0x276F,0x2770,0x2771, 0,
+0x2757};
+
+/* page 6 0x2010-0x203B */
+static uint16 tab_uni_jisx02086[]={
+0x213E, 0, 0, 0, 0,0x213D, 0, 0,
+0x2146,0x2147, 0, 0,0x2148,0x2149, 0, 0,
+0x2277,0x2278, 0, 0, 0,0x2145,0x2144, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x2273, 0,0x216C,0x216D, 0, 0, 0, 0,
+ 0, 0, 0,0x2228};
+
+/* page 7 0x2100-0x2116 */
+static uint16 tab_uni_jisx02087[]={
+ 0, 0, 0,0x216E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x2D62};
+
+/* page 8 0x2120-0x212B */
+static uint16 tab_uni_jisx02088[]={
+ 0,0x2D64, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x2272};
+
+/* page 9 0x2160-0x2169 */
+static uint16 tab_uni_jisx02089[]={
+0x2D35,0x2D36,0x2D37,0x2D38,0x2D39,0x2D3A,0x2D3B,0x2D3C,
+0x2D3D,0x2D3E};
+
+/* page 10 0x2190-0x2193 */
+static uint16 tab_uni_jisx020810[]={
+0x222B,0x222C,0x222A,0x222D};
+
+/* page 11 0x21D2-0x21D4 */
+static uint16 tab_uni_jisx020811[]={
+0x224D, 0,0x224E};
+
+/* page 12 0x2200-0x223D */
+static uint16 tab_uni_jisx020812[]={
+0x224F, 0,0x225F,0x2250, 0, 0, 0,0x2260,
+0x223A, 0, 0,0x223B, 0, 0, 0, 0,
+ 0,0x2D74, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x2265, 0, 0,0x2267,0x2167,0x2D78,
+0x225C, 0, 0, 0, 0,0x2142, 0,0x224A,
+0x224B,0x2241,0x2240,0x2269,0x226A, 0,0x2D73, 0,
+ 0, 0, 0, 0,0x2168,0x2268, 0, 0,
+ 0, 0, 0, 0, 0,0x2266};
+
+/* page 13 0x2252-0x226B */
+static uint16 tab_uni_jisx020813[]={
+0x2262, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x2162,0x2261,
+ 0, 0, 0, 0,0x2165,0x2166, 0, 0,
+0x2263,0x2264};
+
+/* page 14 0x2282-0x2287 */
+static uint16 tab_uni_jisx020814[]={
+0x223E,0x223F, 0, 0,0x223C,0x223D};
+
+/* page 15 0x22A0-0x22BF */
+static uint16 tab_uni_jisx020815[]={
+ 0, 0, 0, 0, 0,0x225D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x2D79};
+
+/* page 16 0x2312-0x2312 */
+static uint16 tab_uni_jisx020816[]={
+0x225E};
+
+/* page 17 0x2460-0x2473 */
+static uint16 tab_uni_jisx020817[]={
+0x2D21,0x2D22,0x2D23,0x2D24,0x2D25,0x2D26,0x2D27,0x2D28,
+0x2D29,0x2D2A,0x2D2B,0x2D2C,0x2D2D,0x2D2E,0x2D2F,0x2D30,
+0x2D31,0x2D32,0x2D33,0x2D34};
+
+/* page 18 0x2500-0x254B */
+static uint16 tab_uni_jisx020818[]={
+0x2821,0x282C,0x2822,0x282D, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x2823, 0, 0,0x282E,
+0x2824, 0, 0,0x282F,0x2826, 0, 0,0x2831,
+0x2825, 0, 0,0x2830,0x2827,0x283C, 0, 0,
+0x2837, 0, 0,0x2832,0x2829,0x283E, 0, 0,
+0x2839, 0, 0,0x2834,0x2828, 0, 0,0x2838,
+0x283D, 0, 0,0x2833,0x282A, 0, 0,0x283A,
+0x283F, 0, 0,0x2835,0x282B, 0, 0,0x283B,
+ 0, 0,0x2840, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x2836};
+
+/* page 19 0x25A0-0x25CF */
+static uint16 tab_uni_jisx020819[]={
+0x2223,0x2222, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x2225,0x2224, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x2227,0x2226, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x2221,0x217E,
+ 0, 0, 0,0x217B, 0, 0,0x217D,0x217C
+};
+
+/* page 20 0x25EF-0x25EF */
+static uint16 tab_uni_jisx020820[]={
+0x227E};
+
+/* page 21 0x2605-0x2606 */
+static uint16 tab_uni_jisx020821[]={
+0x217A,0x2179};
+
+/* page 22 0x2640-0x2642 */
+static uint16 tab_uni_jisx020822[]={
+0x216A, 0,0x2169};
+
+/* page 23 0x266A-0x266F */
+static uint16 tab_uni_jisx020823[]={
+0x2276, 0, 0,0x2275, 0,0x2274};
+
+/* page 24 0x3000-0x301F */
+static uint16 tab_uni_jisx020824[]={
+0x2121,0x2122,0x2123,0x2137, 0,0x2139,0x213A,0x213B,
+0x2152,0x2153,0x2154,0x2155,0x2156,0x2157,0x2158,0x2159,
+0x215A,0x215B,0x2229,0x222E,0x214C,0x214D, 0, 0,
+ 0, 0, 0, 0, 0,0x2D60, 0,0x2D61};
+
+/* page 25 0x3041-0x30FE */
+static uint16 tab_uni_jisx020825[]={
+0x2421,0x2422,0x2423,0x2424,0x2425,0x2426,0x2427,0x2428,
+0x2429,0x242A,0x242B,0x242C,0x242D,0x242E,0x242F,0x2430,
+0x2431,0x2432,0x2433,0x2434,0x2435,0x2436,0x2437,0x2438,
+0x2439,0x243A,0x243B,0x243C,0x243D,0x243E,0x243F,0x2440,
+0x2441,0x2442,0x2443,0x2444,0x2445,0x2446,0x2447,0x2448,
+0x2449,0x244A,0x244B,0x244C,0x244D,0x244E,0x244F,0x2450,
+0x2451,0x2452,0x2453,0x2454,0x2455,0x2456,0x2457,0x2458,
+0x2459,0x245A,0x245B,0x245C,0x245D,0x245E,0x245F,0x2460,
+0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,
+0x2469,0x246A,0x246B,0x246C,0x246D,0x246E,0x246F,0x2470,
+0x2471,0x2472,0x2473, 0, 0, 0, 0, 0,
+ 0, 0,0x212B,0x212C,0x2135,0x2136, 0, 0,
+0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527,0x2528,
+0x2529,0x252A,0x252B,0x252C,0x252D,0x252E,0x252F,0x2530,
+0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,0x2538,
+0x2539,0x253A,0x253B,0x253C,0x253D,0x253E,0x253F,0x2540,
+0x2541,0x2542,0x2543,0x2544,0x2545,0x2546,0x2547,0x2548,
+0x2549,0x254A,0x254B,0x254C,0x254D,0x254E,0x254F,0x2550,
+0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,0x2558,
+0x2559,0x255A,0x255B,0x255C,0x255D,0x255E,0x255F,0x2560,
+0x2561,0x2562,0x2563,0x2564,0x2565,0x2566,0x2567,0x2568,
+0x2569,0x256A,0x256B,0x256C,0x256D,0x256E,0x256F,0x2570,
+0x2571,0x2572,0x2573,0x2574,0x2575,0x2576, 0, 0,
+ 0, 0,0x2126,0x213C,0x2133,0x2134};
+
+/* page 26 0x3230-0x3239 */
+static uint16 tab_uni_jisx020826[]={
+ 0,0x2D6A,0x2D6B, 0, 0, 0, 0, 0,
+ 0,0x2D6C};
+
+/* page 27 0x32A0-0x32A8 */
+static uint16 tab_uni_jisx020827[]={
+ 0, 0, 0, 0,0x2D65,0x2D66,0x2D67,0x2D68,
+0x2D69};
+
+/* page 28 0x3300-0x33CD */
+static uint16 tab_uni_jisx020828[]={
+ 0, 0, 0,0x2D46, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x2D4A, 0, 0,
+ 0, 0, 0, 0,0x2D41, 0, 0, 0,
+0x2D44, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x2D42,0x2D4C, 0, 0,0x2D4B,0x2D45,
+ 0, 0, 0,0x2D4D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x2D47, 0,
+ 0, 0, 0,0x2D4F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x2D40,0x2D4E, 0, 0,0x2D43, 0, 0,
+ 0,0x2D48, 0, 0, 0, 0, 0,0x2D49,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x2D5F,0x2D6F,0x2D6E,0x2D6D, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x2D53,0x2D54,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x2D50,0x2D51,0x2D52, 0,
+ 0,0x2D56, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x2D55, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x2D63};
+
+/* page 29 0x4E00-0x5516 */
+static uint16 tab_uni_jisx020829[]={
+0x306C,0x437A, 0,0x3C37, 0, 0, 0,0x4B7C,
+0x3E66,0x3B30,0x3E65,0x323C, 0,0x4954,0x4D3F, 0,
+0x5022,0x312F, 0, 0,0x336E,0x5023,0x4024,0x5242,
+0x3556,0x4A3A, 0, 0, 0, 0,0x3E67, 0,
+ 0,0x4E3E, 0, 0, 0, 0,0x4A42, 0,
+ 0, 0,0x5024, 0, 0,0x4366, 0, 0,
+ 0,0x5025,0x367A, 0, 0, 0,0x5026, 0,
+0x345D,0x4330, 0,0x3C67,0x5027, 0, 0,0x5028,
+ 0, 0,0x5029,0x4735, 0,0x3557, 0, 0,
+ 0, 0, 0,0x4737, 0,0x4663,0x3843,0x4B33,
+ 0, 0, 0, 0, 0,0x6949,0x502A,0x3E68,
+0x502B,0x3235, 0, 0, 0,0x3665,0x3870,0x4C69,
+ 0, 0,0x5626, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4D70, 0,0x467D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3425, 0,
+0x3535, 0,0x502C, 0, 0,0x502D,0x4E3B, 0,
+0x4D3D,0x4168,0x502F,0x3B76,0x4673, 0,0x5032, 0,
+ 0,0x313E,0x385F, 0,0x385E,0x3066, 0, 0,
+0x4F4B,0x4F4A, 0,0x3A33,0x3021, 0,0x5033,0x5034,
+0x5035,0x4B34,0x5036, 0,0x3872,0x3067,0x4B72, 0,
+0x357C, 0, 0,0x357D,0x357E,0x4462,0x4E3C, 0,
+0x5037, 0, 0,0x5038, 0, 0,0x5039, 0,
+ 0, 0,0x3F4D, 0, 0, 0, 0, 0,
+0x3D3A,0x3F4E,0x503E, 0,0x503C, 0,0x503D,0x3558,
+ 0, 0,0x3A23,0x3270, 0,0x503B,0x503A,0x4A29,
+ 0, 0, 0, 0,0x3B46,0x3B45,0x423E,0x503F,
+0x4955,0x4067, 0, 0, 0,0x2138,0x5040,0x5042,
+ 0, 0, 0,0x4265,0x4E61,0x304A, 0, 0,
+ 0, 0, 0, 0, 0,0x5041,0x323E, 0,
+0x3644, 0,0x4367, 0, 0, 0,0x376F,0x5043,
+ 0, 0, 0,0x4724, 0, 0, 0, 0,
+ 0,0x346B, 0, 0, 0, 0, 0, 0,
+ 0,0x5044,0x304B, 0, 0,0x3860,0x346C,0x497A,
+0x4832,0x3559, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3271, 0,0x5067,0x4541, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x476C,
+0x5046, 0, 0, 0,0x483C, 0,0x4E62, 0,
+0x3F2D, 0,0x3B47, 0,0x3B77,0x3240, 0, 0,
+ 0, 0, 0,0x4451, 0, 0,0x4322,0x504A,
+ 0, 0, 0, 0, 0,0x304C,0x4463,0x3D3B,
+0x3A34,0x4D24, 0,0x424E, 0,0x323F, 0,0x5049,
+ 0,0x4D3E,0x5045,0x5047,0x3A6E,0x5048,0x5524, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5050, 0, 0, 0, 0, 0,0x5053,
+0x5051, 0, 0,0x3242, 0,0x4A3B,0x504B, 0,
+ 0, 0, 0,0x504F,0x3873, 0, 0,0x3B48,
+ 0, 0, 0,0x3426, 0, 0,0x5054, 0,
+0x504C, 0, 0,0x4E63, 0,0x3B78, 0,0x504D,
+ 0,0x5052, 0, 0, 0, 0,0x5055, 0,
+0x504E, 0, 0,0x3621, 0,0x304D, 0, 0,
+0x3622,0x3241, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5525, 0,0x4B79,0x496E,0x3874,
+ 0, 0, 0, 0, 0,0x3F2F,0x4E37, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4A58,
+ 0, 0,0x3738,0x4225,0x3264, 0, 0, 0,
+ 0, 0,0x3D53, 0, 0, 0,0x5059, 0,
+0x505E,0x505C, 0, 0,0x5057, 0, 0,0x422F,
+0x505A, 0,0x505D,0x505B, 0,0x4A5D, 0,0x5058,
+ 0,0x3F2E, 0,0x4B73,0x505F,0x5060, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3D24,0x506D,
+ 0, 0, 0,0x4750, 0,0x4936,0x5068, 0,
+0x4A70, 0,0x3236, 0, 0, 0,0x506C, 0,
+ 0, 0, 0, 0, 0,0x5066,0x506F, 0,
+ 0,0x4152, 0,0x3844, 0,0x475C, 0,0x6047,
+ 0,0x506E,0x455D, 0,0x5063, 0,0x3876, 0,
+ 0,0x3875,0x5061, 0, 0, 0, 0,0x3C5A,
+ 0,0x5069, 0,0x4A6F,0x434D,0x5065,0x3771, 0,
+0x5062,0x506A,0x5064,0x4E51,0x506B,0x4F41, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3666, 0,
+ 0,0x3770, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5070, 0, 0, 0,0x5071,
+0x5075,0x304E, 0, 0, 0, 0, 0,0x4A50,
+0x5074, 0, 0, 0, 0,0x5073,0x5077, 0,
+ 0, 0,0x5076, 0,0x4464, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3772, 0, 0,
+ 0, 0, 0, 0,0x5078, 0, 0, 0,
+ 0, 0,0x3C45, 0,0x4226,0x4465,0x3676, 0,
+0x5079, 0, 0, 0, 0,0x3536, 0, 0,
+0x507A, 0, 0, 0, 0,0x507C, 0, 0,
+ 0, 0, 0, 0, 0,0x4B35, 0, 0,
+ 0,0x3766, 0, 0, 0, 0, 0, 0,
+0x3B31,0x4877,0x507B, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3A45,0x4D43, 0, 0,
+ 0, 0,0x507E,0x5123,0x507D,0x3A44, 0,0x3D7D,
+ 0, 0, 0, 0, 0, 0,0x3739, 0,
+ 0, 0,0x5124, 0, 0,0x364F, 0, 0,
+ 0,0x5121,0x5122, 0, 0,0x462F, 0,0x417C,
+ 0,0x3623, 0, 0, 0,0x4B4D,0x5125, 0,
+ 0, 0,0x4E3D, 0, 0, 0,0x5126, 0,
+ 0, 0, 0,0x5129, 0,0x5127, 0,0x414E,
+ 0, 0, 0, 0, 0,0x5128,0x512A, 0,
+ 0, 0, 0, 0, 0,0x512C, 0, 0,
+ 0,0x512B, 0,0x4A48, 0, 0, 0, 0,
+0x3537,0x512E,0x512F, 0,0x322F, 0, 0, 0,
+ 0,0x512D, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3C74, 0,0x5132,0x5131,0x5130, 0,
+0x5056, 0,0x5133, 0, 0, 0, 0,0x3D7E,
+ 0,0x5134, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4D25, 0, 0, 0, 0, 0,
+ 0, 0,0x4C59, 0, 0, 0, 0,0x5136,
+ 0, 0,0x5135,0x5138,0x5137, 0, 0,0x5139,
+0x513A,0x3074, 0,0x3835,0x373B,0x3D3C,0x437B,0x3624,
+0x4068,0x3877, 0,0x396E,0x513C,0x4C48,0x4546, 0,
+0x3B79, 0,0x513B, 0,0x513D, 0, 0, 0,
+ 0, 0,0x455E, 0,0x3375, 0, 0, 0,
+ 0, 0,0x513E, 0, 0,0x467E, 0, 0,
+0x4134,0x5140,0x5141,0x482C,0x3878,0x4F3B,0x5142, 0,
+ 0,0x3626, 0, 0, 0,0x4A3C,0x4236,0x3671,
+0x4535, 0, 0, 0,0x3773, 0, 0, 0,
+0x5143, 0,0x5144, 0, 0,0x4662,0x315F, 0,
+ 0,0x5147,0x3A7D, 0,0x5146,0x3A46, 0,0x5148,
+0x666E,0x5149,0x4B41,0x514A, 0,0x514B,0x514C,0x3E69,
+ 0,0x3C4C, 0, 0, 0, 0, 0, 0,
+0x3427, 0,0x514F, 0,0x514D,0x4C3D,0x514E, 0,
+0x495A,0x5150,0x5151,0x5152,0x455F, 0, 0, 0,
+0x5156,0x5154,0x5155,0x5153,0x3A63,0x5157,0x4C6A,0x4E64,
+ 0, 0, 0, 0, 0,0x5158, 0, 0,
+ 0, 0, 0, 0,0x4028,0x5159,0x3D5A, 0,
+ 0,0x515A, 0,0x437C,0x4E3F,0x4560, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5245, 0,
+ 0, 0, 0,0x515B,0x7425,0x3645, 0, 0,
+0x515C,0x4B5E, 0, 0, 0, 0,0x3D68,0x427C,
+ 0,0x515E,0x4664, 0, 0,0x515F, 0, 0,
+0x5160,0x332E, 0, 0, 0,0x5161,0x3627, 0,
+0x464C,0x317A,0x3D50, 0, 0,0x4821,0x5162, 0,
+0x4561, 0, 0,0x3F4F,0x5163, 0,0x4A2C,0x405A,
+0x3422, 0,0x3429,0x5164, 0, 0,0x5166, 0,
+ 0,0x373A, 0, 0,0x5165, 0, 0,0x4E73,
+ 0, 0, 0, 0, 0,0x3D69, 0, 0,
+ 0, 0, 0, 0,0x483D,0x4A4C, 0,0x5167,
+ 0,0x4D78,0x5168, 0, 0, 0,0x5169, 0,
+0x457E, 0, 0,0x516A, 0, 0,0x4029,0x3A7E,
+0x3774,0x516B,0x3B49,0x396F, 0, 0, 0, 0,
+ 0, 0, 0,0x4466,0x516D, 0, 0,0x4227,
+ 0, 0,0x3A6F,0x516E,0x516F,0x4130, 0,0x516C,
+ 0, 0, 0, 0,0x5171, 0,0x4B36, 0,
+ 0, 0, 0,0x3964, 0, 0,0x5170, 0,
+ 0, 0, 0,0x3775,0x3A5E,0x476D, 0, 0,
+ 0,0x5174,0x5172, 0, 0, 0, 0,0x497B,
+0x3E6A,0x517B,0x3364,0x5175,0x5173,0x414F, 0, 0,
+ 0, 0, 0, 0, 0,0x5177, 0,0x5176,
+ 0, 0, 0,0x3344, 0, 0, 0,0x3760,
+0x517C,0x4E2D, 0, 0, 0,0x5178, 0, 0,
+ 0,0x517D,0x517A, 0,0x5179, 0, 0, 0,
+ 0, 0, 0,0x4E4F, 0, 0, 0,0x3879,
+0x3243, 0, 0,0x4E74, 0, 0, 0, 0,
+ 0,0x3D75,0x4558,0x3965,0x5222,0x5223, 0, 0,
+ 0,0x4E65, 0, 0,0x4F2B,0x5225, 0, 0,
+ 0,0x387A, 0, 0,0x5224, 0,0x332F, 0,
+ 0,0x5226, 0,0x4B56, 0,0x443C, 0,0x4D26,
+ 0,0x4A59, 0, 0, 0,0x5227, 0, 0,
+ 0, 0,0x7055, 0, 0,0x4630, 0,0x5228,
+0x342A,0x4C33, 0, 0, 0,0x3E21,0x5229,0x4A67,
+0x522D, 0,0x402A,0x522A,0x3650, 0,0x522B,0x342B,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x372E,0x522E, 0,0x522F, 0, 0,
+0x5230,0x5231,0x3C5B, 0, 0, 0,0x387B,0x4C5E,
+ 0,0x4C68,0x4677, 0, 0,0x4A71,0x5232, 0,
+0x5233, 0, 0, 0, 0,0x5235, 0,0x5237,
+0x5236, 0, 0, 0, 0,0x5238,0x323D,0x4B4C,
+ 0,0x3A7C,0x5239, 0, 0,0x4159, 0, 0,
+0x3E22,0x3629, 0,0x523A, 0, 0, 0, 0,
+ 0, 0,0x485B, 0, 0, 0, 0,0x523B,
+ 0,0x523C, 0,0x523D, 0, 0, 0, 0,
+0x523E,0x4924,0x3668,0x3065, 0, 0, 0,0x463F,
+0x523F,0x3D3D, 0,0x4069, 0,0x5241,0x5240,0x3E23,
+0x3861,0x5243,0x483E, 0, 0,0x5244, 0, 0,
+ 0,0x485C,0x4234,0x426E,0x3628, 0, 0,0x466E,
+0x4331, 0,0x476E, 0,0x4B4E, 0,0x5246, 0,
+0x406A, 0, 0, 0, 0, 0,0x3735, 0,
+ 0,0x5247, 0, 0, 0, 0,0x5248,0x312C,
+0x3075,0x346D, 0,0x4228,0x3551,0x4D71, 0,0x524B,
+0x3237, 0, 0,0x524A, 0, 0, 0,0x362A,
+ 0, 0,0x524C, 0,0x4C71, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x524D, 0,
+0x4E52, 0,0x387C, 0, 0, 0, 0,0x3836,
+0x524E, 0, 0, 0, 0,0x5250,0x524F, 0,
+0x3F5F,0x3139, 0, 0, 0,0x315E,0x5251, 0,
+0x5252, 0, 0,0x3837, 0, 0,0x5253, 0,
+ 0, 0, 0,0x356E, 0, 0, 0, 0,
+ 0, 0,0x3B32,0x5254, 0, 0, 0, 0,
+0x4B74,0x3A35,0x355A,0x4D27,0x4150,0x483F,0x3C7D, 0,
+ 0, 0, 0, 0,0x3D47, 0,0x3C68,0x3C75,
+ 0,0x3D76, 0,0x4840, 0, 0, 0,0x5257,
+ 0,0x3143,0x4151,0x387D,0x3845,0x3667, 0, 0,
+0x525B,0x4321,0x427E,0x362B,0x3E24,0x525C,0x525A,0x3244,
+0x4266,0x3C38,0x3B4B,0x3126, 0, 0,0x3370,0x3966,
+0x3B4A, 0,0x525D, 0, 0, 0, 0, 0,
+ 0,0x525E, 0,0x3549,0x3346, 0, 0, 0,
+0x3967,0x3548,0x445F,0x3125,0x4631,0x4C3E,0x3921,0x4D79,
+0x4547,0x387E, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x372F, 0,0x5267, 0,0x3663,
+0x4B4A, 0, 0, 0, 0, 0,0x485D, 0,
+ 0,0x5266, 0,0x345E,0x5261,0x5262,0x5264, 0,
+ 0, 0, 0, 0, 0, 0,0x5265, 0,
+0x355B,0x3F61, 0,0x4A2D,0x5263,0x525F,0x3863, 0,
+0x5260, 0,0x4F24, 0, 0, 0,0x4A72, 0,
+0x4468,0x3862,0x3970, 0, 0, 0,0x5268, 0,
+ 0,0x465D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x526C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3C7E, 0,0x3C76, 0, 0, 0, 0, 0,
+0x526F,0x526D, 0,0x4C23, 0,0x526A,0x5273,0x526E,
+ 0, 0, 0,0x5271,0x3846,0x4C3F, 0, 0,
+0x5272, 0, 0, 0,0x5274, 0,0x5276, 0,
+ 0, 0, 0,0x3A70,0x4F42, 0,0x526B,0x5269,
+0x5275, 0,0x5270, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5278, 0,0x5323,0x527A, 0, 0,
+0x527E, 0, 0,0x5321,0x527B, 0, 0,0x533E,
+ 0, 0,0x3A69,0x3331, 0, 0, 0, 0,
+0x5279, 0, 0, 0,0x5325,0x3076,0x5324, 0,
+0x3025,0x494A,0x5322, 0,0x527C, 0, 0,0x5277,
+0x527D,0x3A48, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5326, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3077,0x532F, 0, 0,0x5327,0x5328, 0,
+0x3E25,0x4B69, 0, 0, 0,0x532D,0x532C, 0,
+ 0, 0,0x452F, 0, 0, 0, 0, 0,
+ 0, 0,0x532E, 0, 0,0x532B, 0, 0,
+ 0, 0, 0, 0,0x3134, 0,0x3A36,0x3F30,
+ 0, 0, 0, 0, 0, 0, 0,0x5329,
+0x4562, 0, 0, 0,0x532A, 0,0x3022};
+
+/* page 30 0x552E-0x5563 */
+static uint16 tab_uni_jisx020830[]={
+0x5334,0x4D23, 0,0x3E27, 0,0x533A, 0, 0,
+ 0, 0,0x5339,0x5330, 0, 0, 0, 0,
+0x4243, 0,0x5331, 0, 0, 0,0x426F,0x5336,
+0x3E26, 0, 0, 0, 0, 0,0x5333, 0,
+ 0,0x4C64, 0, 0, 0,0x373C, 0, 0,
+0x5337,0x5338, 0, 0, 0, 0,0x5335,0x533B,
+ 0, 0, 0, 0, 0,0x5332};
+
+/* page 31 0x557B-0x576A */
+static uint16 tab_uni_jisx020831[]={
+0x5341,0x5346, 0,0x5342, 0,0x533D, 0, 0,
+0x5347,0x4131, 0, 0,0x5349, 0,0x3922,0x533F,
+0x437D, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5343,0x533C,0x342D,
+ 0,0x346E,0x3365,0x5344,0x5340, 0, 0, 0,
+ 0, 0, 0, 0,0x3776,0x534A,0x5348,0x4153,
+0x354A,0x362C, 0,0x5345, 0,0x3674, 0, 0,
+ 0, 0, 0,0x3144, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x534E,0x534C, 0,0x5427, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5351, 0, 0, 0, 0, 0,0x534B,
+ 0,0x534F, 0, 0,0x534D, 0, 0, 0,
+0x3B4C,0x5350, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x5353, 0,0x5358, 0,
+ 0, 0,0x5356,0x5355, 0, 0, 0, 0,
+ 0, 0, 0,0x4332, 0, 0,0x3245, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5352, 0,0x5354,0x3E28,0x3133, 0, 0,
+0x5357, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x325E, 0,
+ 0, 0, 0, 0,0x5362, 0,0x3E7C,0x535E,
+ 0,0x535C, 0,0x535D, 0,0x535F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x313D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4139, 0,0x5359, 0,0x535A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x337A, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5361, 0, 0, 0,0x346F, 0,0x5364,
+0x5360,0x5363, 0, 0, 0, 0, 0, 0,
+ 0,0x4A2E, 0, 0, 0,0x4655, 0,0x4838,
+ 0, 0, 0, 0, 0,0x5366, 0, 0,
+ 0, 0, 0,0x5365,0x3345, 0, 0,0x5367,
+ 0, 0, 0, 0,0x536A, 0, 0, 0,
+ 0,0x5369, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5368, 0,0x4739,
+ 0, 0,0x536B, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x536C, 0, 0, 0, 0,
+ 0,0x536E, 0,0x536D, 0, 0, 0, 0,
+ 0,0x5370, 0, 0, 0,0x5373,0x5371,0x536F,
+0x5372, 0, 0, 0, 0,0x5374, 0, 0,
+ 0, 0, 0,0x5375, 0, 0,0x5376, 0,
+0x5377, 0, 0, 0,0x5378,0x5145, 0,0x3C7C,
+0x3B4D, 0, 0,0x3273, 0,0x3078, 0, 0,
+0x4344, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5379, 0,0x3A24, 0,0x304F,
+0x3F5E, 0, 0, 0, 0, 0,0x537A,0x3847,
+ 0, 0,0x3971, 0,0x537C,0x537B, 0, 0,
+0x4A60,0x537D, 0, 0, 0,0x5421,0x537E, 0,
+0x5422, 0,0x5423, 0,0x3777, 0, 0,0x3160,
+0x5424, 0, 0,0x5426, 0,0x5425, 0, 0,
+ 0,0x5428, 0, 0,0x455A, 0, 0, 0,
+ 0, 0, 0,0x5429,0x3035,0x3A5F, 0, 0,
+ 0, 0,0x373D, 0, 0,0x434F, 0, 0,
+ 0, 0, 0, 0,0x542A,0x542B, 0, 0,
+0x542D, 0, 0, 0, 0,0x542E, 0,0x3A64,
+ 0, 0, 0, 0,0x3651, 0, 0,0x4B37,
+ 0, 0, 0,0x542C,0x542F,0x3A41,0x3923, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5433, 0,
+ 0,0x3A25, 0,0x4333, 0, 0,0x5430,0x445A
+};
+
+/* page 32 0x577F-0x5A9B */
+static uint16 tab_uni_jisx020832[]={
+0x5434, 0, 0,0x3F62, 0, 0, 0, 0,
+ 0,0x5432,0x5435, 0,0x373F, 0, 0, 0,
+ 0, 0, 0, 0,0x5436, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5437, 0,0x3924,0x3340,0x5439, 0, 0,
+ 0, 0, 0,0x543A, 0, 0, 0, 0,
+ 0,0x543B, 0, 0,0x5438, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5431, 0, 0,0x543C, 0, 0,0x543D,
+ 0, 0, 0, 0,0x4B64, 0, 0,0x3E6B,
+ 0, 0, 0,0x543F,0x5440,0x543E, 0,0x5442,
+ 0, 0, 0, 0, 0,0x4738, 0, 0,
+0x3068,0x4956, 0, 0,0x5443, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3E7D, 0, 0,
+0x3C39, 0,0x475D,0x3470, 0,0x3A6B, 0, 0,
+ 0,0x4B59, 0,0x4632, 0, 0,0x3778,0x424F,
+ 0, 0, 0,0x5441,0x5444, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4244, 0,
+ 0, 0,0x5445, 0, 0, 0,0x5446, 0,
+ 0, 0,0x5448, 0, 0,0x4469, 0, 0,
+ 0, 0, 0,0x342E, 0, 0, 0, 0,
+0x7421,0x3161,0x4A73, 0, 0,0x3E6C,0x4548, 0,
+ 0, 0, 0,0x3A66, 0, 0,0x544E, 0,
+ 0,0x4A3D,0x4E5D, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3274,0x544A, 0, 0, 0,
+ 0, 0,0x413A,0x544D, 0,0x4563, 0, 0,
+0x4549,0x4564,0x4839,0x444D, 0, 0, 0,0x3A49,
+ 0, 0, 0,0x5449, 0, 0, 0, 0,
+ 0, 0,0x3176, 0,0x4536, 0, 0, 0,
+ 0,0x544B, 0,0x5447, 0, 0,0x3F50, 0,
+ 0, 0,0x544F, 0, 0, 0, 0,0x3D4E,
+ 0, 0, 0, 0,0x362D, 0,0x5450, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4A68, 0, 0, 0,
+0x417D, 0, 0, 0, 0,0x4446, 0, 0,
+0x5452, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4B4F, 0, 0,0x5453, 0, 0,0x5458,
+ 0, 0, 0, 0,0x4A2F, 0, 0, 0,
+ 0,0x5457,0x5451,0x5454,0x5456, 0, 0,0x3A26,
+ 0, 0,0x4A49, 0, 0, 0,0x5459, 0,
+0x4345, 0, 0,0x3275, 0,0x3E6D, 0, 0,
+ 0, 0,0x545B, 0,0x545A, 0,0x3968, 0,
+0x545C,0x545E,0x545D, 0, 0,0x5460, 0,0x5455,
+0x5462, 0, 0, 0, 0,0x5461,0x545F, 0,
+ 0, 0, 0, 0,0x3B4E,0x3F51, 0,0x4154,
+0x5463,0x403C,0x306D,0x4764, 0, 0, 0, 0,
+0x445B, 0,0x5465,0x5464,0x5466,0x5467,0x5468, 0,
+ 0, 0, 0,0x5469, 0, 0, 0, 0,
+ 0, 0,0x4A51,0x546A, 0, 0, 0, 0,
+0x3246,0x546B, 0, 0, 0, 0,0x4D3C,0x3330,
+ 0,0x5249,0x3D48,0x423F,0x546C,0x4C6B, 0, 0,
+ 0, 0, 0,0x4C34, 0, 0,0x546E, 0,
+0x4267, 0,0x4537,0x4240,0x4957,0x546F,0x5470,0x317B,
+ 0, 0,0x3C3A,0x5471, 0, 0, 0, 0,
+0x3050,0x5472, 0, 0, 0, 0, 0,0x5473,
+ 0, 0, 0, 0, 0,0x3162, 0, 0,
+0x3471,0x4660,0x4A74, 0, 0, 0, 0,0x5477,
+0x4155,0x5476,0x3740, 0, 0,0x4B5B,0x5475, 0,
+0x4565,0x5479, 0,0x5478, 0, 0, 0, 0,
+ 0,0x547B, 0,0x547A, 0, 0,0x317C, 0,
+0x547C,0x3E29,0x547E,0x4325, 0,0x547D, 0,0x4A33,
+ 0, 0, 0, 0,0x3D77,0x455B, 0, 0,
+ 0,0x5521, 0, 0, 0, 0,0x3925, 0,
+ 0, 0,0x5522,0x4721,0x485E,0x4C51, 0, 0,
+ 0, 0, 0,0x4725, 0, 0,0x552B, 0,
+ 0, 0, 0, 0,0x3538, 0, 0,0x4D45,
+ 0, 0,0x4C2F, 0,0x562C, 0,0x5523, 0,
+ 0, 0, 0, 0,0x5526, 0,0x4245, 0,
+ 0,0x4B38, 0, 0, 0,0x454A, 0, 0,
+ 0, 0, 0,0x5527, 0, 0, 0, 0,
+ 0, 0,0x4B65, 0,0x3A4A, 0, 0,0x3E2A,
+ 0, 0, 0, 0, 0, 0, 0,0x5528,
+ 0, 0,0x3B50, 0,0x3B4F, 0, 0, 0,
+ 0,0x3039,0x3848, 0,0x402B,0x3051, 0, 0,
+ 0, 0,0x552C,0x552D, 0,0x552A, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3138,0x342F,
+ 0,0x5529, 0,0x4C45,0x4931, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3028,
+ 0, 0, 0, 0,0x3079, 0, 0, 0,
+0x3B51, 0,0x3052, 0,0x3023, 0, 0, 0,
+ 0, 0,0x5532, 0, 0, 0, 0, 0,
+ 0, 0,0x5530, 0, 0, 0, 0, 0,
+ 0,0x4C3C, 0,0x5533, 0,0x5531, 0, 0,
+0x552F,0x3F31, 0, 0, 0, 0,0x552E, 0,
+ 0, 0,0x4A5A, 0, 0, 0, 0, 0,
+0x3864, 0, 0, 0, 0, 0,0x5537,0x5538,
+ 0, 0, 0, 0, 0,0x3E2B, 0, 0,
+ 0,0x5534,0x4F2C, 0, 0, 0, 0,0x474C,
+ 0, 0,0x5536, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3A27, 0, 0, 0, 0,
+ 0, 0, 0,0x5539, 0, 0, 0,0x4958,
+ 0, 0, 0,0x553A, 0,0x5535, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4C3B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x475E, 0, 0, 0, 0,
+ 0, 0, 0,0x553B,0x4932};
+
+/* page 33 0x5ABC-0x5D29 */
+static uint16 tab_uni_jisx020833[]={
+0x553C,0x5540,0x553D, 0, 0,0x3247,0x553F, 0,
+ 0, 0, 0, 0, 0,0x3C3B, 0,0x553E,
+0x3779, 0, 0, 0,0x554C, 0, 0, 0,
+ 0, 0,0x5545,0x5542, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4364, 0,0x5541,
+ 0, 0,0x5543, 0, 0,0x5544, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5546,0x5547,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3472, 0,0x5549,
+0x5548, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x554A, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3E6E, 0,
+ 0, 0, 0, 0, 0, 0,0x554D, 0,
+0x445C, 0, 0, 0,0x3145, 0,0x554B, 0,
+ 0, 0,0x554E, 0, 0, 0, 0, 0,
+ 0, 0,0x554F, 0,0x5552, 0, 0,0x5550,
+ 0,0x5551, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3B52,0x5553, 0, 0,
+0x3926,0x5554, 0,0x3B7A,0x4238, 0,0x5555,0x5556,
+0x3B5A,0x3927, 0,0x4C52, 0, 0, 0,0x3528,
+0x3849,0x5557,0x3358, 0, 0,0x5558, 0,0x4239,
+ 0, 0, 0, 0,0x5559,0x5623, 0,0x555A,
+ 0,0x555B, 0, 0,0x555C, 0,0x555E, 0,
+ 0, 0, 0, 0,0x555F, 0, 0,0x5560,
+ 0,0x4270, 0,0x3127,0x3C69,0x3042, 0,0x4157,
+0x3430,0x3C35, 0,0x3928, 0, 0, 0, 0,
+ 0,0x4566, 0,0x3D21,0x3431,0x4368,0x446A,0x3038,
+0x3539,0x4A75, 0,0x3C42, 0, 0,0x3552,0x406B,
+0x3C3C,0x4D28,0x5561, 0, 0, 0, 0, 0,
+ 0, 0,0x355C, 0,0x3A4B, 0, 0,0x3332,
+0x3163,0x3E2C,0x3248, 0,0x5562,0x4D46, 0, 0,
+ 0, 0, 0,0x3D49, 0, 0,0x3C64,0x5563,
+0x3473,0x4652,0x4C29,0x5564, 0,0x5565, 0, 0,
+0x4959, 0, 0, 0,0x5567, 0,0x3428,0x3677,
+0x5566, 0, 0, 0, 0, 0, 0,0x3432,
+ 0,0x3F32,0x556B,0x3B21, 0,0x3249,0x556A, 0,
+0x5568,0x556C,0x5569,0x472B,0x5C4D,0x3F33, 0,0x556D,
+ 0, 0,0x4E40, 0,0x556E, 0, 0,0x5570,
+ 0,0x437E,0x556F, 0,0x4023, 0,0x3B7B, 0,
+ 0, 0,0x4250,0x3C77, 0,0x4975,0x406C, 0,
+0x3C4D,0x5571,0x3E2D,0x5572,0x5573,0x3053,0x423A,0x3F52,
+ 0,0x5574,0x4633,0x3E2E, 0,0x3E2F, 0,0x5575,
+ 0, 0,0x406D, 0, 0, 0,0x3E30, 0,
+ 0, 0, 0, 0,0x5576, 0,0x5577, 0,
+0x4C60, 0, 0, 0,0x5578, 0, 0, 0,
+ 0,0x3646, 0, 0, 0,0x3D22, 0, 0,
+ 0, 0, 0, 0,0x5579,0x557A,0x3C5C,0x3F2C,
+0x4674,0x3F54,0x4878,0x4722,0x3649,0x557B, 0, 0,
+ 0,0x356F,0x557C, 0,0x367E, 0,0x464F,0x3230,
+ 0,0x3B53,0x557D,0x5622,0x5621,0x367D, 0,0x557E,
+ 0,0x4538, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4230, 0,0x454B,0x3C48, 0, 0,
+0x4158,0x4D7A, 0, 0, 0, 0, 0, 0,
+0x5624, 0,0x5625,0x4656, 0,0x3B33, 0, 0,
+ 0, 0,0x5627, 0, 0,0x5628, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5629, 0, 0, 0,0x3474,0x562A, 0, 0,
+0x562B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x322C, 0, 0,
+ 0, 0, 0, 0,0x413B,0x3464, 0,0x562D,
+0x4C28, 0, 0, 0, 0,0x4252, 0,0x3359,
+ 0, 0,0x562F,0x5631,0x345F, 0, 0,0x562E,
+0x5630, 0,0x5633, 0, 0, 0, 0, 0,
+ 0,0x5632, 0,0x5634, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5635, 0, 0,
+ 0, 0, 0, 0,0x463D,0x362E, 0, 0,
+ 0, 0, 0, 0,0x3265,0x5636,0x563B, 0,
+ 0,0x5639, 0,0x4A77,0x4A76, 0, 0, 0,
+ 0, 0,0x4567, 0, 0, 0,0x5638,0x3D54,
+ 0,0x5637, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3F72, 0, 0, 0,0x563C,
+ 0, 0,0x3A6A, 0, 0,0x5642, 0, 0,
+0x5643,0x563D,0x3333,0x563E,0x5647,0x5646,0x5645,0x5641,
+ 0, 0, 0,0x5640, 0, 0,0x5644, 0,
+ 0, 0, 0, 0, 0,0x4A78};
+
+/* page 34 0x5D4B-0x6BF3 */
+static uint16 tab_uni_jisx020834[]={
+0x564B,0x5648, 0,0x564A, 0,0x4D72, 0,0x5649,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x563F, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3F73, 0,
+ 0,0x564C, 0, 0,0x3A37, 0, 0, 0,
+0x564D, 0, 0,0x564E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5651,
+ 0,0x5650, 0, 0,0x564F, 0, 0, 0,
+0x4568,0x563A, 0, 0, 0,0x5657, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5653, 0, 0, 0, 0,0x5652,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5654, 0,0x5655, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x5658, 0, 0,0x4E66,
+ 0,0x5659,0x5656, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x565A, 0,
+ 0,0x3460,0x565B, 0, 0, 0, 0,0x565D,
+0x565C, 0, 0,0x565E, 0, 0, 0, 0,
+0x565F, 0,0x406E,0x3D23, 0, 0,0x3D64, 0,
+0x4163, 0,0x3929,0x3A38,0x392A,0x3570, 0, 0,
+0x5660, 0, 0,0x3A39, 0, 0,0x384A,0x5661,
+0x4C26,0x4743,0x5662, 0,0x392B, 0, 0, 0,
+0x342C, 0,0x4327,0x3652, 0, 0, 0,0x3B54,
+0x495B, 0, 0,0x4841, 0, 0, 0, 0,
+0x5663,0x3475, 0, 0, 0, 0,0x5666, 0,
+ 0, 0, 0,0x4421, 0, 0,0x5665,0x5664,
+0x5667, 0,0x446B, 0, 0, 0, 0, 0,
+ 0, 0,0x3F63, 0, 0, 0, 0, 0,
+0x3B55, 0,0x404A, 0,0x4253,0x3522, 0, 0,
+0x4422, 0, 0,0x5668,0x5669,0x3E6F, 0, 0,
+ 0, 0,0x4B39, 0, 0,0x566C, 0, 0,
+0x566B,0x566A,0x497D, 0,0x5673, 0, 0, 0,
+ 0,0x4B5A, 0,0x566D, 0, 0, 0, 0,
+ 0,0x566F,0x4B6B, 0,0x566E, 0, 0, 0,
+ 0, 0, 0, 0,0x5670, 0,0x4828,0x5671,
+0x4A3E,0x5672, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3433,
+0x4A3F,0x472F,0x5674,0x5675, 0,0x392C,0x3434,0x5676,
+0x3838,0x4D44,0x4D29,0x3476,0x5678, 0,0x4423, 0,
+0x392D,0x3E31, 0, 0,0x485F, 0, 0,0x3E32,
+ 0, 0, 0, 0,0x3D78, 0, 0, 0,
+ 0, 0,0x446C,0x4A79,0x4539, 0, 0,0x392E,
+ 0,0x495C, 0, 0, 0,0x5679, 0, 0,
+ 0, 0, 0,0x4559,0x3A42, 0, 0, 0,
+0x384B, 0,0x446D, 0, 0, 0, 0, 0,
+ 0, 0,0x3043,0x3D6E,0x392F,0x4D47, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x567A,0x567B,
+0x4751, 0, 0, 0, 0,0x567C,0x4E77,0x4F2D,
+ 0, 0, 0, 0,0x567E,0x567D, 0, 0,
+0x3347, 0, 0,0x5721, 0, 0, 0,0x5724,
+0x5725, 0,0x5723, 0,0x4940,0x3E33,0x5727,0x5726,
+0x5722, 0, 0, 0, 0,0x5728,0x5729, 0,
+ 0,0x572A, 0, 0, 0,0x572D,0x572B, 0,
+0x572C,0x572E, 0,0x3164,0x446E,0x572F, 0,0x377A,
+0x3276,0x4736, 0,0x5730,0x467B, 0,0x4A5B, 0,
+0x5731,0x4F2E, 0, 0, 0, 0,0x5732,0x4A40,
+0x5735,0x5021,0x5031, 0,0x3C30,0x4675,0x5736, 0,
+0x355D,0x4424,0x307A,0x5737,0x4A26,0x3930, 0, 0,
+0x4350, 0, 0, 0,0x446F, 0, 0, 0,
+ 0, 0,0x4C6F,0x3839,0x384C, 0,0x5738, 0,
+ 0, 0,0x5739, 0,0x573F, 0,0x3C65, 0,
+ 0, 0,0x4425, 0,0x362F,0x573A, 0, 0,
+ 0,0x492B, 0,0x4346, 0, 0,0x573B, 0,
+ 0, 0, 0, 0, 0,0x573C, 0,0x3630,
+ 0,0x573D, 0,0x573E, 0, 0,0x5740, 0,
+0x4576, 0, 0,0x5741,0x5742, 0,0x5743, 0,
+ 0,0x5734,0x5733, 0, 0, 0,0x5744,0x3741,
+ 0, 0, 0,0x4927, 0, 0,0x3A4C,0x4937,
+0x4426,0x494B,0x5745, 0, 0,0x3E34,0x3146, 0,
+0x5746, 0, 0, 0,0x5747, 0,0x4C72, 0,
+ 0,0x4860, 0, 0,0x574A,0x317D,0x402C,0x5749,
+0x5748,0x3742,0x4254, 0,0x574E,0x574C, 0,0x574B,
+0x4E27,0x3865, 0, 0, 0,0x3D79,0x574D,0x454C,
+0x3D3E, 0, 0, 0,0x4640,0x5751,0x5750, 0,
+ 0, 0, 0,0x574F, 0,0x5752,0x3866, 0,
+ 0, 0, 0, 0, 0,0x5753,0x497C,0x3D5B,
+ 0, 0,0x5754,0x4879, 0, 0, 0, 0,
+0x4641,0x4427, 0, 0, 0, 0,0x4530, 0,
+ 0,0x5755,0x352B, 0, 0, 0, 0, 0,
+0x3F34, 0,0x492C, 0, 0, 0, 0, 0,
+ 0,0x3477,0x4726, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5756,0x3B56,0x4B3A,0x4B3B, 0,
+ 0,0x317E,0x575B, 0, 0,0x4369, 0, 0,
+ 0,0x5758, 0, 0, 0, 0, 0, 0,
+0x3277, 0, 0, 0, 0,0x582D,0x575A, 0,
+ 0, 0,0x4730, 0, 0,0x5759, 0, 0,
+0x5757, 0,0x397A, 0,0x575D, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5763,0x5769,0x5761, 0,0x455C,
+ 0, 0,0x5766,0x495D, 0, 0,0x5760, 0,
+0x5765,0x4E67,0x3B57, 0, 0,0x4255,0x575E, 0,
+ 0, 0,0x355E,0x5768,0x402D,0x3165,0x5762,0x3278,
+0x5767, 0, 0, 0,0x3631, 0,0x5764, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x576A,
+ 0, 0, 0, 0, 0, 0,0x576C,0x5776,
+0x5774, 0, 0,0x5771, 0, 0, 0,0x5770,
+0x4E78, 0,0x5772, 0, 0,0x3632, 0,0x3931,
+ 0, 0,0x3D7A, 0, 0, 0,0x5779,0x576B,
+ 0, 0, 0, 0,0x576F,0x575F, 0,0x327A,
+0x5773,0x5775,0x4351, 0, 0,0x3A28,0x3238,0x576D,
+0x5778,0x5777,0x3633, 0,0x4229,0x3366, 0, 0,
+ 0, 0,0x3743, 0,0x576E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x577A, 0,
+0x577D,0x5821, 0, 0, 0, 0,0x3C3D, 0,
+0x5827,0x4470,0x577B, 0, 0, 0, 0,0x5825,
+ 0,0x3279, 0,0x5823,0x5824, 0, 0,0x577E,
+0x5822, 0, 0, 0,0x3867,0x4D2A, 0, 0,
+0x3435, 0, 0,0x3159,0x5826, 0,0x473A,0x302D,
+ 0, 0, 0, 0, 0, 0, 0,0x4861,
+0x575C,0x582C,0x5830,0x4C65, 0,0x5829, 0, 0,
+ 0,0x4569,0x582E, 0, 0, 0, 0, 0,
+ 0, 0,0x3E70,0x582F,0x4657, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4F47, 0,
+0x582B, 0, 0, 0, 0,0x5831, 0,0x397B,
+ 0,0x404B, 0, 0,0x3054,0x582A,0x5828, 0,
+0x415A, 0, 0, 0,0x577C,0x3B34, 0, 0,
+ 0, 0, 0, 0, 0,0x4246,0x583D, 0,
+0x415B,0x5838, 0,0x5835,0x5836, 0,0x3C66,0x5839,
+0x583C, 0, 0, 0, 0,0x5837,0x3D25, 0,
+0x583A, 0, 0,0x5834, 0,0x4C7C,0x4C7B, 0,
+ 0, 0,0x583E,0x583F,0x3055, 0, 0, 0,
+ 0, 0,0x5833, 0, 0, 0, 0,0x3672,
+0x3026, 0, 0, 0,0x3436, 0,0x583B, 0,
+ 0, 0, 0, 0,0x5843,0x5842, 0, 0,
+ 0,0x5847, 0, 0, 0, 0, 0, 0,
+ 0,0x5848, 0, 0, 0, 0, 0, 0,
+ 0,0x5846,0x5849,0x5841,0x5845, 0, 0,0x584A,
+ 0,0x584B, 0, 0,0x5840,0x3B7C, 0,0x5844,
+0x4256,0x3932,0x5832,0x3F35, 0, 0, 0, 0,
+0x5858, 0,0x4A69, 0, 0,0x584E,0x584F,0x5850,
+ 0, 0,0x5857, 0,0x5856, 0, 0,0x4B7D,
+0x3437, 0,0x5854, 0,0x3745,0x3334, 0, 0,
+0x5851, 0, 0,0x4E38,0x5853,0x3056,0x5855, 0,
+0x584C,0x5852,0x5859,0x3744,0x584D, 0, 0, 0,
+ 0, 0, 0,0x4D5D, 0, 0, 0,0x4D2B,
+ 0, 0, 0, 0,0x585C, 0, 0,0x5860,
+ 0, 0, 0,0x417E, 0,0x4E79,0x5861, 0,
+ 0,0x585E, 0,0x585B, 0, 0,0x585A,0x585F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4A30, 0, 0,0x4634, 0,0x3746, 0,
+0x5862,0x585D, 0,0x5863, 0, 0, 0,0x377B,
+ 0, 0, 0,0x3231, 0, 0, 0,0x586B,
+ 0, 0, 0,0x3438, 0, 0, 0, 0,
+0x5869, 0, 0,0x586A,0x3A29,0x5868,0x5866,0x5865,
+0x586C,0x5864,0x586E, 0, 0,0x327B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5870, 0, 0,0x586F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4428,
+ 0,0x5873, 0,0x5871,0x5867,0x377C, 0,0x5872,
+ 0,0x5876,0x5875,0x5877,0x5874,0x5878, 0, 0,
+ 0, 0, 0, 0, 0,0x5879,0x587A,0x4A6A,
+ 0,0x587C,0x587B,0x3D3F, 0,0x402E,0x3266,0x327C,
+ 0,0x587D, 0,0x303F, 0, 0, 0,0x404C,
+0x587E, 0,0x6C43,0x5921,0x3761, 0,0x5922, 0,
+ 0, 0, 0,0x406F, 0, 0, 0,0x5923,
+ 0, 0, 0,0x5924,0x353A,0x5925, 0,0x5926,
+0x5927,0x4257, 0, 0, 0,0x384D, 0, 0,
+0x4C61, 0, 0, 0,0x4B3C,0x3D6A,0x5928, 0,
+ 0, 0, 0, 0,0x4070,0x6E3D,0x4862, 0,
+0x3C6A, 0,0x3A4D,0x5929, 0, 0, 0, 0,
+0x4247, 0,0x4A27, 0, 0,0x4271, 0, 0,
+0x592C, 0, 0,0x592A, 0,0x592D, 0, 0,
+0x592B, 0, 0, 0, 0,0x592E, 0, 0,
+ 0, 0, 0,0x4A31, 0, 0,0x3037, 0,
+ 0, 0, 0,0x495E, 0, 0,0x4863, 0,
+ 0,0x592F, 0,0x5932,0x3E35,0x353B, 0,0x5930,
+0x5937,0x3E36, 0, 0, 0, 0,0x5931,0x4744,
+ 0, 0, 0, 0, 0, 0,0x4D5E,0x5933,
+0x5934,0x5938,0x456A,0x5935,0x3933,0x405E, 0, 0,
+0x5946,0x4834, 0,0x4272, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4864,0x5A2D, 0, 0, 0, 0,0x4A7A, 0,
+ 0, 0,0x4471, 0, 0, 0,0x4B75, 0,
+0x593B,0x3221,0x436A, 0, 0, 0, 0,0x5944,
+ 0, 0,0x4334,0x593E,0x5945,0x5940,0x5947,0x5943,
+ 0,0x5942,0x476F, 0,0x593C,0x327D,0x593A,0x3571,
+0x4273,0x5936, 0, 0,0x5939,0x3934,0x405B, 0,
+0x3E37,0x5941,0x4752, 0, 0,0x3572,0x3348, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3367,0x3F21,0x5949,0x594E, 0,0x594A, 0,
+0x377D, 0,0x594F,0x3B22,0x3969, 0, 0, 0,
+ 0, 0, 0,0x3D26,0x593D, 0,0x3B7D,0x594C,
+ 0, 0, 0, 0,0x3B58,0x594D,0x3044, 0,
+ 0,0x5948, 0, 0, 0, 0,0x4429, 0,
+ 0, 0, 0, 0, 0, 0,0x3573, 0,
+ 0, 0, 0, 0,0x3634, 0, 0, 0,
+ 0, 0, 0, 0,0x594B,0x3027, 0, 0,
+0x3A43, 0, 0, 0,0x3F36, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4472,
+ 0, 0,0x4854,0x5951,0x415E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x422A, 0,
+ 0,0x3B2B,0x5952, 0,0x5954,0x5950, 0, 0,
+ 0, 0,0x4A61, 0,0x443D, 0, 0, 0,
+ 0,0x415C, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4A7B,0x3C4E,0x5960, 0,
+0x595F, 0, 0,0x3F78, 0, 0, 0,0x377E,
+ 0, 0, 0,0x5959,0x3E39, 0, 0,0x4668,
+0x4731, 0, 0, 0, 0,0x5957, 0, 0,
+0x415D, 0, 0, 0, 0,0x3C78,0x595C, 0,
+ 0,0x3E38, 0,0x5956,0x595B, 0, 0,0x4753,
+ 0, 0, 0,0x5955, 0,0x3721, 0, 0,
+0x335D, 0, 0, 0,0x595D,0x4E2B,0x3A4E,0x4335,
+0x595A, 0,0x405C, 0,0x3935,0x3F64,0x3166,0x413C,
+0x5958,0x3545, 0, 0, 0, 0, 0,0x3747,
+ 0,0x444F,0x595E, 0, 0, 0, 0, 0,
+0x415F, 0, 0,0x5961, 0,0x5963, 0, 0,
+0x4237,0x5969, 0,0x5964, 0, 0,0x5966, 0,
+ 0, 0, 0, 0,0x4941,0x4473, 0,0x5967,
+ 0, 0, 0,0x4D2C, 0, 0, 0,0x4D48,
+0x3439, 0, 0, 0, 0, 0,0x302E, 0,
+0x5965, 0, 0, 0, 0, 0,0x5962, 0,
+ 0, 0, 0,0x3478, 0, 0, 0, 0,
+ 0,0x3167, 0,0x5968, 0, 0, 0,0x4D49,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x596C, 0, 0, 0, 0,
+ 0, 0,0x423B, 0,0x5973, 0, 0, 0,
+0x596D, 0, 0,0x596A,0x5971, 0, 0, 0,
+ 0,0x5953, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x596E, 0,0x5972, 0, 0,
+ 0,0x4842,0x456B, 0, 0, 0, 0, 0,
+ 0,0x596B, 0,0x596F, 0, 0, 0,0x3748,
+ 0, 0, 0,0x3A71, 0, 0, 0,0x405D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5977, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4526, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x5974, 0,0x4B60, 0,
+ 0, 0, 0, 0,0x5975, 0, 0, 0,
+ 0, 0, 0,0x5976, 0,0x4C4E, 0,0x4022,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3762, 0, 0, 0, 0,0x597D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3B35,
+0x597A, 0,0x5979, 0, 0, 0, 0,0x4732,
+ 0, 0, 0,0x4635, 0, 0, 0, 0,
+ 0,0x4531,0x597B, 0, 0, 0,0x597C, 0,
+0x496F, 0,0x4745,0x3B23, 0,0x4071, 0,0x4B50,
+ 0, 0, 0, 0, 0, 0,0x3349, 0,
+0x5A25,0x597E, 0, 0, 0, 0,0x4D4A,0x5A27,
+ 0, 0,0x5A23, 0,0x5A24, 0, 0, 0,
+ 0, 0,0x4160, 0, 0, 0, 0,0x5A22,
+ 0,0x593F, 0, 0, 0,0x5A26, 0,0x5A21,
+ 0, 0, 0, 0, 0,0x5A2B,0x5A2C,0x4527,
+0x5A2E, 0, 0,0x3B24,0x5A29, 0, 0, 0,
+ 0,0x353C, 0, 0,0x5A2F, 0,0x5A28,0x5A33,
+ 0,0x5A32, 0,0x5A31, 0, 0, 0,0x5A34,
+ 0, 0,0x5A36,0x3E71, 0,0x5A35, 0, 0,
+ 0, 0,0x5A39, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5A37, 0, 0,
+ 0,0x5A38,0x5970, 0, 0, 0, 0, 0,
+0x5A3B,0x5A3A, 0, 0, 0, 0, 0,0x5978,
+0x5A3C,0x5A30, 0, 0,0x3B59, 0, 0, 0,
+ 0,0x5A3D,0x5A3E,0x5A40,0x5A3F,0x5A41,0x327E, 0,
+0x3936, 0, 0,0x4A7C,0x402F, 0, 0, 0,
+ 0, 0,0x384E, 0, 0,0x5A43, 0, 0,
+ 0, 0,0x5A46, 0,0x4952, 0,0x355F, 0,
+ 0, 0,0x5A45,0x5A44,0x4754,0x5A47,0x3635, 0,
+ 0, 0,0x5A49,0x5A48, 0, 0, 0,0x343A,
+0x3B36, 0, 0,0x4658, 0, 0, 0, 0,
+ 0,0x3749, 0, 0, 0,0x3F74, 0,0x5A4A,
+ 0,0x4030,0x4528, 0,0x495F,0x5A4B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5A4C,
+0x5A4D, 0, 0, 0,0x4A38,0x555D,0x4046, 0,
+ 0,0x494C, 0,0x3A58, 0,0x4865,0x4843, 0,
+ 0, 0, 0, 0,0x454D, 0,0x4E41, 0,
+0x5A4F,0x3C50, 0, 0,0x5A50, 0,0x3036, 0,
+ 0,0x3654,0x404D, 0,0x4960, 0, 0, 0,
+0x5A51,0x3B42,0x4347, 0,0x3B5B,0x3F37, 0, 0,
+ 0, 0, 0, 0,0x5A52, 0,0x4A7D, 0,
+ 0,0x3177,0x3B5C, 0, 0, 0,0x5A55, 0,
+0x5A53,0x5A56,0x4E39,0x5A54, 0, 0, 0, 0,
+0x407B,0x5A57, 0, 0,0x4232, 0, 0,0x5A58,
+ 0, 0, 0, 0,0x347A, 0,0x5A5A, 0,
+0x5A59, 0, 0, 0, 0,0x5A5B,0x5A5C,0x347B,
+ 0, 0,0x467C,0x4336,0x356C,0x3B5D,0x4161, 0,
+ 0,0x3D5C,0x3030, 0, 0, 0,0x5A5D, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3222,
+0x5A61, 0, 0, 0, 0, 0, 0,0x3937,
+0x5A60, 0, 0,0x3A2B,0x3E3A, 0, 0,0x5A5F,
+ 0,0x3E3B, 0,0x4C40,0x3A2A, 0, 0, 0,
+0x3057,0x404E, 0, 0, 0, 0, 0, 0,
+ 0,0x5A66, 0, 0,0x4031,0x3147, 0, 0,
+ 0, 0,0x3D55, 0,0x4B66,0x3A72, 0, 0,
+ 0, 0,0x3E3C, 0,0x4027, 0, 0, 0,
+ 0,0x5A65,0x5A63,0x5A64, 0, 0, 0, 0,
+ 0,0x436B, 0, 0,0x5B26, 0,0x5A6A,0x3B7E,
+0x3938,0x5A68, 0, 0, 0, 0,0x5A69, 0,
+0x3F38, 0, 0, 0,0x5A67, 0, 0,0x3B2F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5A6C,0x5A6B,0x5A70, 0, 0,0x5A71,
+ 0,0x5A6D, 0,0x3322,0x5A6E,0x5A6F,0x4855, 0,
+ 0, 0, 0,0x4961,0x374A,0x5A72, 0, 0,
+ 0,0x4032, 0,0x3E3D, 0, 0, 0,0x4352,
+ 0, 0, 0, 0, 0, 0,0x3647, 0,
+0x5A73,0x5A77, 0, 0,0x324B,0x5A74,0x5A76, 0,
+ 0, 0, 0,0x5A75, 0, 0,0x3D6B, 0,
+ 0, 0, 0,0x4348,0x3045,0x5A78, 0, 0,
+ 0, 0,0x5A79, 0, 0, 0, 0,0x442A,
+ 0, 0, 0,0x4E71, 0, 0, 0, 0,
+0x3B43, 0, 0,0x4A6B, 0, 0, 0, 0,
+ 0,0x4B3D, 0, 0, 0,0x5B22,0x5A7B, 0,
+ 0,0x5A7E, 0,0x5A7D, 0, 0,0x5A7A, 0,
+ 0,0x5B21, 0, 0,0x465E, 0,0x5A7C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5B23, 0, 0,0x3D6C,0x5B24,
+ 0,0x4D4B,0x4778, 0, 0,0x5B25, 0, 0,
+ 0, 0, 0,0x5B27, 0, 0,0x5B28, 0,
+ 0, 0, 0, 0, 0,0x5B29, 0,0x364A,
+0x3148,0x3939,0x5B2A, 0,0x5B2B,0x3D71,0x4162, 0,
+ 0,0x5258,0x413E,0x413D,0x4258,0x3A47, 0, 0,
+0x5072, 0, 0, 0, 0,0x376E,0x4D2D, 0,
+0x4A7E, 0,0x497E, 0,0x5B2C, 0, 0, 0,
+ 0,0x3A73,0x443F,0x5B2D,0x4F2F, 0, 0, 0,
+0x4B3E, 0,0x442B,0x5B2E,0x347C, 0, 0, 0,
+ 0, 0, 0,0x5B2F,0x5B30,0x4C5A, 0,0x4C24,
+0x4B76,0x4B5C,0x3B25,0x5B32, 0, 0,0x3C6B, 0,
+ 0,0x4B51, 0,0x5B34,0x5B37,0x5B36, 0,0x3479,
+ 0, 0,0x3560, 0,0x5B33, 0,0x5B35, 0,
+ 0, 0, 0,0x5B38, 0, 0,0x3F79, 0,
+ 0, 0, 0,0x4D7B,0x3049,0x3A60,0x423C, 0,
+0x3C5D, 0, 0,0x3E73, 0, 0,0x5B3B, 0,
+ 0,0x454E, 0,0x5B39,0x422B,0x5B3A,0x3E72,0x4C5D,
+0x5B3C,0x5B3D,0x4D68, 0, 0, 0, 0,0x5B42,
+ 0, 0,0x393A, 0,0x4755,0x5B3F,0x456C,0x5A5E,
+0x5A62, 0,0x354F, 0,0x4747, 0, 0, 0,
+ 0,0x5B41, 0,0x3E3E,0x4844, 0, 0, 0,
+ 0, 0,0x5B47, 0,0x487A, 0,0x5B3E, 0,
+0x5B44,0x5B43, 0, 0, 0,0x404F, 0, 0,
+ 0, 0,0x4B6D, 0,0x4E53, 0, 0,0x4B67,
+ 0,0x324C,0x3B5E, 0, 0,0x4F48,0x5B46,0x3F75,
+ 0, 0, 0,0x5B45, 0, 0,0x5B40, 0,
+ 0, 0, 0, 0,0x384F, 0, 0, 0,
+0x5B4C,0x5B4A, 0,0x324D,0x5B48,0x5B4E,0x5B54, 0,
+ 0, 0, 0, 0, 0, 0,0x4248, 0,
+ 0,0x4A41, 0,0x5B56, 0, 0, 0,0x4922,
+ 0, 0, 0,0x5B55,0x4770,0x4B3F,0x343B, 0,
+0x4077,0x3D40, 0, 0, 0,0x4453, 0,0x4D2E,
+ 0, 0,0x5B51,0x5B50, 0, 0, 0,0x5B52,
+ 0,0x5B4F, 0, 0,0x5B57, 0,0x5B4D, 0,
+ 0,0x5B4B, 0,0x5B53,0x5B49, 0,0x436C, 0,
+0x4C78,0x3C46,0x3A74, 0, 0, 0, 0, 0,
+0x3A3A, 0, 0,0x4B6F,0x3341, 0, 0,0x444E,
+0x464A,0x3149, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4072, 0, 0,0x4034,0x372A, 0, 0, 0,
+ 0, 0, 0,0x5B59, 0, 0,0x393B,0x337C,
+ 0, 0, 0, 0, 0, 0,0x5B5B,0x3374,
+0x5B61, 0, 0, 0, 0, 0, 0,0x5B5E,
+ 0,0x4073, 0, 0, 0,0x334B,0x3A2C, 0,
+ 0,0x334A,0x3A4F, 0, 0,0x5B5C,0x3765,0x374B,
+0x456D, 0, 0,0x5B5A, 0,0x3046, 0, 0,
+ 0, 0,0x5B5D,0x5B5F, 0,0x364D,0x372C, 0,
+0x343C,0x354B, 0, 0, 0, 0,0x5B62, 0,
+ 0,0x3A79,0x4B71, 0,0x3B37, 0, 0, 0,
+0x5B63, 0, 0, 0,0x4930, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5B6F, 0,0x3233,0x5B64, 0, 0, 0,
+ 0, 0, 0,0x5B75,0x5B65, 0,0x4E42, 0,
+0x5B6C, 0,0x475F, 0, 0, 0, 0, 0,
+ 0, 0,0x5B74, 0,0x5B67, 0, 0, 0,
+0x3034,0x5B69, 0, 0,0x393C, 0, 0, 0,
+0x5B6B, 0,0x5B6A, 0,0x5B66,0x5B71, 0,0x3E3F,
+ 0, 0, 0,0x546D,0x3868,0x4D7C, 0, 0,
+ 0, 0,0x5B68, 0,0x4474,0x3323,0x3A2D, 0,
+0x5B60, 0,0x5B70,0x3361, 0, 0,0x5B6E,0x5B72,
+ 0,0x456E, 0, 0, 0, 0, 0, 0,
+ 0,0x347E, 0,0x5C32, 0, 0,0x4C49,0x5B77,
+0x347D, 0,0x5B7E, 0, 0, 0, 0,0x4B40,
+ 0,0x5C21,0x5C23, 0,0x5C27,0x5B79, 0,0x432A,
+ 0, 0, 0, 0,0x456F,0x5C2B,0x5B7C, 0,
+0x5C28, 0, 0, 0,0x5C22, 0, 0, 0,
+ 0, 0, 0,0x3F39,0x5C2C, 0, 0,0x4033,
+ 0, 0, 0, 0, 0, 0,0x5C2A,0x343D,
+ 0, 0, 0, 0, 0,0x4F50,0x5B76, 0,
+ 0,0x5C26,0x3058, 0, 0,0x5B78, 0, 0,
+0x4C3A,0x5B7D,0x3F22,0x4447,0x5B73, 0, 0,0x5C25,
+ 0, 0, 0, 0, 0, 0,0x3F7A,0x5C2F,
+0x3371,0x3821, 0, 0, 0, 0,0x5C31,0x5B7A,
+0x5C30, 0,0x5C29,0x5B7B, 0,0x5C2D, 0,0x5C2E,
+ 0, 0, 0, 0, 0,0x5C3F, 0, 0,
+ 0,0x464E, 0,0x5C24, 0, 0,0x5C3B, 0,
+ 0, 0,0x5C3D, 0,0x4458, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4D4C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4976,0x5C38,0x424A, 0, 0, 0,0x5C3E,0x413F,
+ 0,0x5C35,0x5C42,0x5C41, 0,0x466F,0x5C40,0x466A,
+ 0, 0, 0, 0, 0, 0, 0,0x5C44,
+0x5C37, 0,0x3648,0x5C3A,0x3D5D, 0, 0, 0,
+0x4760,0x5C3C,0x364B, 0,0x5C34,0x5C36,0x5C33, 0,
+ 0,0x4F30,0x335A,0x5C39, 0, 0,0x5C43,0x3335,
+ 0, 0, 0, 0, 0, 0, 0,0x3A67,
+ 0, 0, 0,0x315D, 0, 0,0x5C54, 0,
+ 0,0x4F31,0x5C57, 0, 0, 0, 0, 0,
+0x3F3A,0x5C56, 0, 0, 0,0x5C55, 0, 0,
+ 0, 0, 0, 0,0x5C52, 0, 0, 0,
+ 0, 0, 0,0x5C46, 0, 0,0x5C63,0x5C45,
+ 0,0x5C58, 0, 0, 0, 0, 0, 0,
+0x5C50, 0, 0,0x5C4B,0x5C48, 0,0x5C49, 0,
+0x5C51, 0, 0, 0,0x7422, 0, 0,0x5C4E,
+0x393D,0x4448,0x4164,0x5C4C, 0,0x5C47, 0, 0,
+0x5C4A, 0, 0, 0, 0,0x4D4D,0x4B6A, 0,
+ 0, 0,0x5C4F,0x5C59, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x5C61,0x5C5A, 0, 0,
+0x5C67, 0,0x5C65, 0, 0, 0, 0,0x5C60,
+ 0, 0, 0, 0, 0, 0,0x5C5F, 0,
+0x4450, 0,0x4165, 0,0x5C5D, 0, 0,0x5C5B,
+ 0, 0,0x5C62, 0, 0, 0, 0,0x5C68,
+0x4875,0x5C6E, 0, 0, 0, 0, 0,0x5C69,
+0x5C6C,0x5C66, 0, 0,0x4374, 0,0x4938, 0,
+0x5C5C, 0, 0,0x5C64,0x3E40, 0,0x4C4F,0x5C78,
+0x5C6B, 0, 0, 0, 0, 0,0x3822,0x3223,
+0x335F, 0, 0,0x5C53, 0, 0, 0, 0,
+ 0, 0,0x3E41,0x5C70, 0,0x5C77,0x3C79,0x3372,
+ 0, 0,0x432E, 0, 0, 0, 0, 0,
+ 0,0x5C6D, 0, 0,0x5C72,0x5C76, 0, 0,
+0x3636, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x354C,0x5C74, 0,
+ 0, 0, 0, 0,0x3521, 0,0x464B,0x5C73,
+ 0, 0, 0,0x5C75, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5C6F,
+ 0, 0, 0, 0, 0,0x5C71, 0, 0,
+ 0, 0, 0, 0,0x3360,0x4349, 0, 0,
+ 0,0x5C7C, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5C7A,0x3869, 0,0x5C79, 0, 0,
+ 0, 0, 0, 0,0x5D21, 0, 0, 0,
+ 0,0x5B58, 0, 0, 0,0x5C7B, 0,0x5C7D,
+0x5C7E, 0, 0, 0, 0, 0, 0,0x5D2C,
+ 0,0x5D28, 0,0x5B6D, 0, 0, 0, 0,
+0x5D27, 0, 0, 0, 0,0x5D26, 0, 0,
+0x5D23, 0, 0, 0, 0, 0,0x5C6A,0x5D25,
+0x5D24, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5D2A, 0,
+0x4F26, 0, 0, 0, 0, 0, 0,0x5D2D,
+0x367B, 0, 0,0x5D29,0x5D2B, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4827, 0,0x5D2E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5D32,
+0x5D2F, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4D73,0x5D30, 0, 0, 0, 0,0x5C5E,
+ 0, 0, 0, 0, 0, 0, 0,0x5D33,
+ 0, 0, 0,0x5D34, 0, 0, 0, 0,
+ 0, 0,0x3135, 0,0x5D36,0x3767,0x3C21, 0,
+0x3655, 0, 0, 0,0x3224, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4D5F,
+ 0, 0, 0, 0,0x5D38,0x5D37,0x5D3A,0x353D,
+ 0, 0,0x3656,0x343E, 0, 0, 0, 0,
+0x5D3D, 0, 0, 0,0x5D3C, 0,0x5D3E, 0,
+ 0,0x324E, 0,0x4337, 0,0x5D3F, 0, 0,
+0x343F,0x5D41, 0, 0, 0, 0,0x5D40, 0,
+0x5D42, 0, 0, 0,0x5D43, 0,0x5D44,0x3B5F,
+0x4035,0x3A21, 0,0x4970, 0, 0,0x4A62,0x4F44,
+ 0, 0, 0, 0,0x3B75, 0, 0, 0,
+0x3A50,0x4E72, 0, 0, 0,0x5D45,0x5D46, 0,
+0x3B60, 0, 0, 0,0x5D47,0x5D48, 0, 0,
+0x5D4A,0x5D49, 0,0x4B58, 0, 0,0x3D5E,0x3C6C,
+0x3B44, 0,0x5D4B, 0, 0, 0, 0, 0,
+ 0, 0,0x5D4D,0x3F23, 0,0x5D4C, 0, 0,
+ 0, 0, 0,0x5D4E, 0, 0, 0, 0,
+ 0,0x5D4F, 0, 0, 0, 0, 0,0x5D50,
+0x5D51, 0, 0, 0,0x5D52, 0,0x5D54,0x5D53,
+0x5D55,0x3225,0x434A, 0,0x5D56, 0, 0,0x3B26,
+0x334C,0x5D57, 0, 0,0x4542,0x544C, 0, 0,
+ 0, 0,0x3523,0x5D58, 0, 0, 0, 0,
+0x5D59, 0,0x4A6C,0x4B68, 0, 0, 0,0x4647,
+0x5D5A,0x4866, 0, 0, 0,0x487B, 0, 0,
+0x4C53, 0, 0, 0,0x5D5B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5D5D,0x5D5C, 0, 0,0x5D5F, 0, 0, 0,
+0x5D5E};
+
+/* page 35 0x6C08-0x6CF3 */
+static uint16 tab_uni_jisx020835[]={
+0x5D61, 0, 0, 0, 0, 0, 0,0x3B61,
+ 0,0x4C31, 0,0x5D62,0x5D63, 0, 0,0x3524,
+ 0, 0, 0,0x5D64, 0, 0, 0, 0,
+ 0, 0, 0,0x5D66,0x5D65, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3F65, 0, 0,0x4939,
+0x314A, 0, 0, 0, 0, 0,0x4845, 0,
+0x4475,0x3D41,0x3561, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4846, 0,
+0x3C2E, 0, 0, 0, 0,0x5D68, 0,0x3440,
+ 0, 0,0x3178, 0, 0,0x4672,0x5D67,0x393E,
+0x4353, 0,0x5D69, 0, 0, 0, 0, 0,
+0x5D71, 0,0x5D6A, 0, 0, 0, 0, 0,
+0x4241, 0,0x3562,0x5D72, 0, 0, 0, 0,
+ 0, 0,0x3768, 0, 0,0x3525,0x5D70, 0,
+ 0,0x5D6E,0x5D6B,0x4D60, 0, 0, 0, 0,
+0x4440, 0, 0, 0,0x4659,0x5D6C, 0, 0,
+0x5D74, 0,0x5D73,0x3723, 0, 0,0x322D, 0,
+ 0,0x3A3B,0x5D6D,0x5D6F, 0, 0, 0, 0,
+ 0,0x4B57,0x4274, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x4B77, 0, 0,0x5D7C, 0,
+ 0,0x5D7D, 0,0x324F, 0, 0, 0, 0,
+0x4A28,0x4C7D,0x5E21,0x3C23,0x3E42,0x5D78,0x5D7E,0x3168,
+ 0,0x3637, 0, 0,0x5D75,0x5D7A, 0, 0,
+ 0,0x4074,0x4771, 0,0x4867, 0, 0, 0,
+ 0, 0, 0,0x5D77, 0,0x4B21, 0,0x5D79,
+ 0,0x5E24, 0,0x5E22, 0,0x5D7B, 0, 0,
+ 0,0x4B22,0x4748,0x3563, 0,0x4525, 0, 0,
+0x436D, 0,0x5E25, 0, 0, 0, 0,0x5E23,
+0x4259,0x5D76, 0,0x314B};
+
+/* page 36 0x6D0B-0x7409 */
+static uint16 tab_uni_jisx020836[]={
+0x4D4E,0x5E30, 0, 0, 0, 0, 0,0x5E2F,
+ 0, 0, 0, 0,0x4076, 0,0x5E2C, 0,
+0x4D6C, 0, 0,0x4636,0x5E26, 0, 0, 0,
+ 0, 0,0x4445, 0, 0, 0,0x314C,0x393F,
+0x5E29, 0, 0, 0, 0, 0, 0,0x3D27,
+0x5E2E, 0,0x5E2D,0x5E28, 0,0x5E2B, 0, 0,
+0x3368, 0,0x5E2A,0x4749, 0, 0,0x4E2E, 0,
+ 0,0x3E74,0x4075, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5E36,0x5E34,
+ 0,0x494D, 0, 0, 0, 0, 0, 0,
+0x5E31,0x5E33, 0,0x313A, 0, 0,0x3940,0x4F32,
+ 0,0x333D, 0,0x4962, 0, 0, 0, 0,
+ 0,0x4D61, 0, 0,0x3324,0x3F3B,0x5E35, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5E3A, 0, 0,0x3E43, 0, 0,
+ 0,0x4D30, 0,0x5E37, 0, 0, 0, 0,
+0x5E32, 0,0x5E38, 0, 0, 0,0x4E5E, 0,
+0x4573,0x4642, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3336, 0, 0,0x3155,
+ 0, 0,0x5E3E, 0, 0,0x5E41, 0, 0,
+ 0,0x4E43, 0, 0, 0,0x4D64, 0, 0,
+ 0, 0,0x5E48,0x5E42,0x5E3F, 0, 0, 0,
+0x4E54,0x5E45, 0, 0, 0, 0,0x3D4A,0x5E47,
+ 0, 0,0x5E4C, 0, 0,0x4571,0x5E4A, 0,
+ 0, 0, 0,0x5E44, 0, 0,0x4338, 0,
+ 0,0x5E4B, 0,0x5E40, 0,0x5E46, 0,0x5E4D,
+0x307C,0x5E43, 0,0x5E4E, 0, 0,0x3F3C, 0,
+0x3D5F, 0,0x4A25, 0,0x3A2E, 0,0x5E3B,0x5E49,
+0x453A, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4036, 0,0x3369,0x3A51,0x3E44,0x5E3D,
+0x3D42, 0, 0, 0, 0, 0, 0, 0,
+0x374C, 0,0x5E3C, 0, 0, 0,0x5E52,0x3D6D,
+0x383A, 0,0x5E61, 0,0x5E5B,0x3574,0x454F, 0,
+0x5E56,0x5E5F,0x302F,0x3132, 0, 0,0x3239, 0,
+0x5E58,0x422C,0x5E4F,0x5E51,0x3941, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5E62, 0,0x5E5D,
+ 0, 0, 0,0x5E55, 0, 0, 0, 0,
+0x5E5C, 0, 0, 0, 0, 0, 0,0x4C2B,
+ 0, 0,0x5E5A,0x5E5E, 0, 0, 0, 0,
+ 0, 0, 0,0x3850, 0,0x3E45, 0, 0,
+0x4339, 0, 0, 0,0x5E54, 0, 0, 0,
+ 0, 0, 0, 0,0x4D2F, 0, 0, 0,
+0x5E57, 0, 0,0x5E50,0x4572, 0, 0,0x5E53,
+ 0, 0, 0,0x5E59, 0, 0, 0, 0,
+ 0, 0, 0,0x4F51,0x3C3E,0x4B7E, 0,0x5E63,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x482E, 0, 0,0x5E6F,0x383B, 0, 0,
+ 0, 0, 0,0x3D60, 0,0x5E65, 0, 0,
+ 0,0x4E2F,0x3942, 0,0x5E72, 0, 0,0x306E,
+ 0, 0,0x5E70, 0, 0, 0, 0,0x5E64,
+ 0, 0, 0, 0,0x5E6A, 0, 0,0x5E6C,
+ 0, 0, 0,0x4D4F,0x5E67, 0, 0,0x452E,
+ 0, 0,0x5E69, 0, 0, 0, 0,0x5E71,
+ 0,0x5E6B,0x4C47, 0, 0, 0,0x5E66, 0,
+0x3C22,0x5E7E, 0, 0, 0, 0,0x336A, 0,
+0x5E68,0x5E6D,0x5E6E, 0, 0, 0, 0, 0,
+ 0, 0,0x426C,0x425A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5E76, 0, 0,0x5E7C, 0, 0,0x5E7A,
+ 0,0x4529, 0, 0,0x5F23,0x5E77, 0, 0,
+ 0, 0, 0,0x5E78,0x5E60, 0,0x3579,0x493A,
+ 0, 0, 0,0x3C3F, 0, 0,0x3977, 0,
+ 0, 0, 0, 0,0x4F33, 0,0x5E74, 0,
+0x5F22,0x3169,0x4166, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4779, 0,0x3441,
+0x4E7A, 0, 0, 0, 0, 0, 0, 0,
+0x4C21,0x4452, 0, 0, 0, 0,0x5E7B,0x5E7D,
+ 0, 0, 0, 0, 0,0x4132, 0, 0,
+ 0, 0, 0,0x5F21,0x5E79, 0,0x5E73, 0,
+ 0, 0,0x3443, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3769, 0, 0, 0,0x5F2F, 0, 0,
+0x5F2A,0x4078, 0, 0,0x3363, 0, 0, 0,
+ 0,0x3D61, 0,0x5F33, 0, 0, 0, 0,
+ 0, 0,0x5F2C,0x442C,0x5F29,0x4459, 0, 0,
+ 0,0x5F4C, 0, 0, 0,0x5F26, 0,0x5F25,
+ 0,0x5F2E, 0, 0, 0,0x5F28,0x5F27,0x5F2D,
+ 0,0x4021, 0,0x5F24, 0, 0, 0, 0,
+ 0, 0, 0,0x5F30, 0, 0,0x5F31, 0,
+ 0, 0, 0, 0,0x3442, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5F36, 0,
+0x5F35,0x5F37, 0, 0, 0, 0, 0,0x5F3A,
+ 0, 0, 0, 0, 0, 0,0x4543, 0,
+0x5F34, 0, 0, 0, 0, 0,0x5F38, 0,
+ 0, 0, 0, 0, 0,0x3763,0x4279,0x5F32,
+0x473B, 0, 0,0x5F39, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5F3E,0x5F3C, 0, 0,0x5F3F, 0, 0,
+0x5F42, 0, 0, 0,0x5F3B,0x396A,0x4728, 0,
+ 0,0x5E39, 0, 0, 0, 0, 0, 0,
+0x4D74,0x5F3D, 0,0x5F41,0x4275, 0,0x5F40, 0,
+0x5F2B, 0, 0,0x6F69, 0, 0, 0,0x5F45,
+ 0, 0, 0,0x5F49, 0, 0,0x5F47, 0,
+ 0, 0, 0, 0, 0, 0,0x5F43, 0,
+0x5F44, 0, 0, 0,0x5F48, 0,0x5F46, 0,
+ 0, 0,0x494E, 0, 0,0x5F4E, 0,0x5F4B,
+0x5F4A, 0,0x5F4D,0x4654,0x5F4F, 0, 0, 0,
+ 0, 0, 0,0x4375,0x426D, 0, 0, 0,
+ 0,0x4025, 0, 0, 0,0x5F50, 0,0x5F52,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5F51, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5E75, 0, 0, 0, 0,0x5F53, 0,
+ 0, 0, 0, 0, 0,0x4667, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5F54, 0, 0, 0, 0, 0, 0, 0,
+0x3250, 0, 0, 0,0x4574,0x3325, 0, 0,
+ 0, 0, 0, 0, 0,0x3564, 0, 0,
+ 0,0x3C5E,0x3A52, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4F27,0x3F66,
+ 0, 0, 0,0x316A, 0, 0, 0,0x5F56,
+ 0, 0, 0, 0, 0, 0,0x5F55, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5F59,0x433A,0x5F5C,0x5F57, 0, 0, 0,
+0x5F5B, 0, 0, 0, 0,0x5F5A,0x4540,0x3059,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4E75, 0, 0,
+0x5F5E, 0, 0, 0,0x3128, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5F60, 0,
+ 0, 0,0x5F5F, 0,0x5F5D, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5F58, 0,
+ 0, 0, 0, 0, 0, 0,0x4B23, 0,
+ 0, 0,0x5F62, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5F61, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x316B, 0, 0, 0, 0,0x5F64,0x4A32,
+ 0,0x5F63, 0, 0, 0, 0,0x4C35, 0,
+ 0, 0, 0,0x3E47, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x4133, 0, 0, 0, 0,
+ 0,0x3E46, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4E7B, 0,
+ 0,0x5F6A, 0,0x4079, 0, 0, 0, 0,
+ 0, 0,0x5F66,0x5F6B, 0, 0,0x316C, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5F69,
+ 0,0x4761,0x5F65,0x5F68,0x3E48, 0,0x4851, 0,
+ 0,0x5F6C, 0,0x3C51, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x407A, 0, 0, 0, 0, 0,
+ 0,0x5F6F, 0, 0, 0,0x5F67, 0,0x3727,
+ 0, 0, 0, 0,0x5F6D, 0, 0, 0,
+ 0,0x4D50,0x5F70, 0, 0, 0,0x7426, 0,
+ 0, 0, 0, 0,0x3D4F, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5F71, 0, 0,
+ 0,0x5F72, 0, 0, 0, 0,0x472E, 0,
+ 0, 0, 0, 0, 0, 0,0x5F74, 0,
+ 0, 0, 0,0x5F75, 0, 0, 0, 0,
+0x4733, 0, 0, 0, 0,0x4575,0x5F77, 0,
+ 0, 0, 0,0x5F79, 0,0x4E55, 0,0x5F76,
+ 0,0x5F78,0x316D, 0,0x5F73, 0, 0, 0,
+ 0, 0, 0, 0,0x535B,0x5F7A, 0, 0,
+ 0, 0,0x4167,0x3B38,0x5F7C, 0, 0, 0,
+ 0,0x5F7B,0x3F24,0x5259, 0, 0, 0, 0,
+ 0, 0,0x5F7D, 0, 0, 0,0x6021, 0,
+0x5F6E,0x5F7E, 0, 0,0x6022, 0, 0, 0,
+ 0, 0, 0,0x477A, 0, 0, 0, 0,
+ 0, 0,0x6023, 0, 0,0x6024, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6025, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6026, 0,0x445E,
+ 0,0x6028,0x6027, 0, 0,0x6029, 0,0x602A,
+ 0, 0,0x3C5F,0x4963, 0, 0, 0,0x4C6C,
+0x602B,0x602C,0x4156,0x3C24,0x602D,0x602E, 0, 0,
+ 0, 0, 0,0x602F,0x4A52,0x4847, 0, 0,
+0x6030,0x4757, 0, 0, 0, 0, 0,0x442D,
+ 0, 0, 0, 0, 0,0x6031,0x3267, 0,
+0x356D, 0,0x4C46, 0,0x4C36, 0,0x3234,0x4F34,
+ 0, 0, 0, 0,0x4B52, 0,0x4A2A, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4037,
+ 0,0x6032, 0, 0, 0, 0,0x4643, 0,
+ 0, 0,0x3823,0x6033, 0,0x3A54,0x6035,0x6034,
+ 0, 0, 0, 0,0x6036, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6037,
+ 0, 0, 0,0x6038, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x353E, 0,0x6039,
+ 0, 0, 0, 0,0x603A, 0, 0, 0,
+ 0,0x3824, 0, 0,0x4848, 0, 0,0x603C,
+ 0, 0, 0,0x3E75, 0, 0,0x603B, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3638,
+0x603D,0x603F, 0,0x603E, 0, 0, 0, 0,
+ 0, 0, 0,0x6040, 0,0x3851, 0,0x6041,
+ 0, 0, 0, 0,0x3669, 0,0x4140, 0,
+0x397D, 0, 0, 0, 0,0x6043,0x6044,0x6042,
+ 0, 0, 0, 0, 0, 0,0x3C6D, 0,
+ 0,0x4648,0x3639, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6046,0x432C,0x6045, 0,
+ 0,0x4F35,0x4762, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6049,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x604B,0x6048, 0, 0, 0,
+0x4C54,0x604A,0x604C, 0,0x4E44, 0, 0, 0,
+ 0, 0,0x6050, 0, 0, 0,0x604F,0x4376,
+0x472D, 0, 0,0x3825,0x604E, 0, 0, 0,
+ 0,0x604D, 0,0x4D31,0x4D32, 0, 0, 0,
+ 0, 0, 0,0x6051,0x316E, 0, 0, 0,
+ 0,0x3976,0x3B62, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6052,0x6053, 0, 0, 0,
+ 0, 0, 0, 0,0x6055, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3D43, 0, 0, 0, 0,0x6057, 0,0x6056,
+ 0, 0, 0, 0, 0,0x6058, 0,0x334D,
+ 0, 0,0x605A, 0, 0,0x6059, 0,0x605C,
+0x605B, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x383C, 0, 0,0x4E28, 0,0x364C, 0,
+0x3226, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x366A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3461, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4E68,
+0x605E, 0, 0, 0, 0, 0, 0, 0,
+0x6060, 0, 0, 0, 0,0x6061, 0,0x3251,
+ 0, 0, 0, 0, 0,0x605D, 0,0x3B39,
+ 0, 0,0x4441,0x605F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6064, 0,0x3C6E, 0, 0,
+ 0, 0,0x6062, 0, 0, 0, 0,0x373E,
+ 0, 0,0x4849,0x6063, 0, 0,0x607E, 0,
+ 0, 0, 0, 0, 0,0x6069, 0, 0,
+ 0, 0, 0,0x383D, 0, 0, 0, 0,
+0x3565, 0,0x6066,0x4D7D, 0, 0,0x4E30};
+
+/* page 37 0x7422-0x7845 */
+static uint16 tab_uni_jisx020837[]={
+0x4276, 0, 0,0x6068, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x606A,0x4E56,0x3657,0x487C,0x474A, 0, 0, 0,
+0x606B, 0, 0, 0, 0,0x606D, 0,0x6070,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x606C, 0, 0, 0,0x606F,
+0x386A,0x314D,0x6071, 0,0x3F70,0x606E,0x4E5C, 0,
+ 0,0x6074,0x7424, 0, 0, 0, 0,0x6072,
+0x6075, 0, 0, 0, 0,0x6067,0x6073, 0,
+ 0,0x3A3C, 0, 0,0x6076, 0, 0, 0,
+ 0, 0, 0, 0,0x6077, 0, 0, 0,
+ 0,0x4D7E, 0, 0, 0, 0, 0, 0,
+ 0,0x6078, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6079, 0, 0, 0,
+0x6065, 0, 0, 0, 0,0x607A, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3444, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3C25, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x607B, 0, 0, 0, 0,0x607C, 0, 0,
+ 0, 0,0x607D, 0, 0, 0, 0, 0,
+ 0, 0,0x313B, 0, 0, 0,0x6121, 0,
+0x493B,0x6122, 0, 0,0x3424,0x6123, 0,0x6124,
+ 0, 0, 0, 0,0x6125, 0,0x6127,0x6128,
+0x6126, 0, 0, 0,0x4953,0x612A,0x6129, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x612C,0x612B,0x612D, 0, 0, 0, 0,
+ 0, 0,0x612E,0x6130,0x612F, 0, 0,0x3979,
+ 0,0x6132, 0,0x6131, 0, 0,0x3445, 0,
+0x3F53, 0,0x453C, 0,0x6133,0x4038, 0, 0,
+ 0,0x3B3A, 0,0x3179,0x6134, 0,0x4D51, 0,
+ 0,0x4A63,0x6135, 0, 0, 0,0x4544,0x4D33,
+0x3943,0x3F3D, 0, 0, 0,0x434B,0x5234, 0,
+0x442E,0x3268,0x6136, 0, 0, 0, 0, 0,
+ 0, 0,0x6137, 0,0x613C, 0, 0,0x613A,
+0x6139,0x5A42,0x3326,0x6138, 0,0x305A, 0,0x482A,
+ 0, 0,0x484A, 0, 0, 0, 0,0x4E31,
+0x613D,0x613B,0x435C,0x4026, 0, 0,0x482B, 0,
+0x492D, 0,0x613F,0x4E2C,0x374D,0x6140, 0,0x613E,
+0x4856,0x6141, 0,0x6142, 0, 0,0x305B, 0,
+ 0,0x3E76,0x6147, 0,0x6144,0x466D,0x6143, 0,
+ 0, 0, 0, 0, 0,0x3526, 0, 0,
+0x614A, 0, 0, 0,0x6145,0x6146, 0,0x6149,
+0x6148,0x4925, 0, 0,0x4142,0x4141, 0,0x353F,
+ 0, 0,0x614B, 0, 0, 0, 0, 0,
+0x614C, 0, 0,0x614D, 0, 0, 0, 0,
+ 0,0x614F, 0,0x614E, 0, 0, 0, 0,
+ 0,0x3156, 0, 0, 0, 0, 0,0x6157,
+0x4868,0x6151, 0,0x6153, 0, 0,0x6155,0x3F3E,
+ 0, 0,0x6156,0x6154,0x3C40, 0, 0, 0,
+0x6150,0x6152, 0,0x4942, 0,0x3E49, 0, 0,
+0x6159, 0, 0,0x6158, 0, 0, 0, 0,
+0x615A, 0,0x3C26,0x3A2F, 0, 0,0x4577,0x615B,
+ 0,0x444B, 0, 0,0x615D, 0, 0, 0,
+0x4E21,0x615C, 0, 0, 0, 0, 0,0x4169,
+ 0, 0, 0, 0, 0, 0,0x6162, 0,
+0x6164,0x6165,0x4354, 0, 0, 0, 0, 0,
+0x6163, 0,0x6160, 0,0x615E,0x615F, 0,0x6161,
+ 0, 0, 0, 0, 0, 0, 0,0x6168,
+ 0,0x6166, 0,0x6167, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6169,0x616B,0x616C,
+0x616D, 0,0x616E, 0, 0,0x616A, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6170, 0,
+ 0, 0,0x616F, 0, 0, 0, 0, 0,
+ 0,0x6171, 0, 0, 0, 0, 0, 0,
+0x4E45, 0, 0, 0,0x6174,0x6172,0x6173, 0,
+ 0, 0,0x3462, 0, 0, 0, 0, 0,
+0x4C7E, 0, 0, 0,0x4A4A, 0,0x6176, 0,
+ 0, 0,0x6175, 0, 0, 0, 0,0x6177,
+0x6178, 0, 0, 0, 0,0x617C,0x6179,0x617A,
+0x617B, 0,0x617D, 0, 0, 0,0x617E, 0,
+0x6221, 0, 0, 0,0x6222, 0,0x6223, 0,
+0x482F,0x4550,0x6224,0x4772,0x4934, 0,0x6225, 0,
+ 0,0x6226,0x452A, 0,0x3327,0x3944,0x6227, 0,
+ 0,0x6228, 0, 0,0x6229, 0,0x3B29, 0,
+ 0,0x622B, 0, 0,0x622A, 0, 0,0x622C,
+0x622D, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4869, 0,0x622E, 0,
+ 0, 0,0x622F, 0, 0,0x7369,0x6230,0x6231,
+0x6232, 0, 0, 0, 0,0x3B2E, 0, 0,
+0x6233,0x4756, 0, 0,0x4B5F, 0,0x314E, 0,
+0x3157, 0, 0,0x6234, 0, 0, 0, 0,
+0x6236, 0, 0, 0,0x6235,0x4570, 0, 0,
+ 0,0x4039,0x5D39, 0,0x6237,0x4C41, 0,0x6238,
+ 0,0x3446,0x4857,0x6239, 0,0x623A, 0, 0,
+0x623B, 0, 0, 0,0x4C5C, 0, 0, 0,
+0x4C55, 0,0x443E, 0, 0, 0,0x416A, 0,
+ 0,0x623D, 0, 0,0x3D62, 0, 0,0x3E4A,
+ 0, 0,0x6240, 0, 0,0x623F,0x623E,0x487D,
+ 0,0x3447,0x3829, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6246, 0, 0,0x6243,0x3F3F,0x4C32, 0,
+ 0, 0,0x6242,0x6244,0x6245, 0, 0,0x6241,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6247,0x6248, 0,
+0x442F, 0,0x3463, 0, 0, 0,0x4365, 0,
+ 0, 0, 0, 0, 0,0x6249, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x624A,0x624D, 0, 0, 0, 0, 0,0x3F67,
+ 0,0x4644, 0,0x624E,0x4B53, 0,0x624B, 0,
+ 0,0x624C, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6251,
+ 0, 0, 0, 0,0x6250,0x624F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6253, 0, 0,0x6252, 0, 0,0x6254,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6256, 0,0x6255, 0,
+ 0, 0, 0,0x4A4D, 0, 0, 0, 0,
+ 0, 0,0x3D56,0x4E46, 0, 0,0x6257, 0,
+ 0,0x4637, 0, 0,0x6258, 0, 0,0x6259,
+ 0,0x625D,0x625B,0x625C, 0,0x625A, 0, 0,
+ 0, 0, 0, 0, 0,0x625E, 0, 0,
+ 0, 0, 0,0x625F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6260, 0, 0,
+0x6261,0x4C37,0x6262, 0, 0, 0, 0, 0,
+0x4C70,0x6263, 0,0x434E, 0,0x476A, 0,0x366B,
+ 0, 0, 0,0x433B,0x6264,0x363A, 0, 0,
+ 0,0x4050, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6265, 0, 0, 0, 0, 0,
+0x3A3D, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6266, 0, 0, 0, 0, 0,
+0x6267, 0,0x3826,0x3A55, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6269, 0,
+ 0, 0, 0,0x4556,0x3A56,0x354E, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4B24, 0,0x474B, 0, 0, 0, 0, 0,
+0x4557, 0, 0, 0, 0,0x395C, 0, 0,
+ 0, 0, 0,0x626B};
+
+/* page 38 0x785D-0x7E9C */
+static uint16 tab_uni_jisx020838[]={
+0x3E4B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4E32,0x3945,
+ 0, 0,0x3827, 0, 0,0x4823, 0,0x626D,
+ 0, 0, 0, 0, 0, 0, 0,0x626F,
+ 0, 0, 0, 0,0x386B, 0, 0, 0,
+ 0,0x626E,0x4476, 0, 0, 0, 0,0x6271,
+0x3337,0x626C, 0, 0,0x486A, 0,0x3130, 0,
+0x3A6C, 0,0x4F52, 0, 0,0x6270, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6272, 0,
+ 0, 0,0x4A4B, 0,0x4059,0x6274, 0, 0,
+ 0, 0,0x6275, 0, 0, 0, 0, 0,
+0x6273, 0, 0, 0, 0,0x334E, 0,0x627B,
+ 0,0x627A, 0, 0,0x3C27, 0, 0, 0,
+0x627C,0x6277, 0, 0, 0,0x627D,0x6278, 0,
+ 0, 0, 0,0x4858,0x6276, 0, 0,0x6279,
+ 0, 0, 0, 0, 0,0x6322, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6321,0x4B61, 0, 0, 0,0x627E,
+ 0, 0,0x306B, 0, 0, 0, 0,0x6324,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6323, 0, 0, 0,0x3E4C, 0, 0, 0,
+ 0, 0,0x6325, 0, 0, 0, 0, 0,
+ 0,0x4143, 0, 0,0x6327,0x6326, 0, 0,
+ 0, 0, 0, 0,0x6328, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6268, 0, 0, 0,0x626A,0x632A,0x6329,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3C28, 0,0x4E69,
+ 0,0x3C52, 0,0x632B,0x3737, 0, 0, 0,
+ 0, 0,0x3540,0x3527,0x3B63, 0, 0, 0,
+ 0, 0, 0,0x4D34, 0, 0,0x6331, 0,
+0x6330,0x4144,0x632D, 0, 0,0x632F, 0, 0,
+0x3D4B,0x3F40,0x632E,0x632C, 0,0x472A, 0, 0,
+0x3E4D, 0, 0,0x493C, 0, 0, 0, 0,
+0x3A57, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4578, 0, 0,0x6332, 0, 0,
+ 0, 0,0x6333,0x6349,0x3658, 0, 0,0x4F3D,
+0x4135, 0, 0, 0, 0,0x6334, 0, 0,
+0x3252,0x4477,0x4A21, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6335, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x357A,0x6336, 0, 0,0x6338, 0, 0,
+ 0,0x6339, 0,0x4729, 0, 0,0x633A, 0,
+ 0, 0, 0, 0,0x633B,0x633C, 0, 0,
+0x3659,0x3253,0x4645,0x3D28,0x3B64, 0, 0, 0,
+ 0, 0, 0, 0,0x633D, 0,0x3D29, 0,
+ 0, 0, 0, 0,0x324A,0x4943, 0, 0,
+0x633E, 0, 0,0x486B, 0, 0, 0, 0,
+ 0, 0,0x4145, 0,0x6341, 0,0x6342,0x4769,
+ 0,0x3F41,0x633F, 0,0x4361, 0, 0,0x6340,
+ 0, 0, 0,0x3E4E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x305C, 0,
+ 0, 0, 0,0x3529, 0, 0, 0, 0,
+ 0, 0, 0,0x6343, 0, 0,0x4478, 0,
+0x6344,0x4047, 0, 0, 0, 0, 0,0x4C2D,
+ 0, 0,0x4923,0x6345,0x6346,0x4355, 0,0x4E47,
+ 0, 0,0x6348,0x6347, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3C6F, 0, 0,0x634A,0x3070, 0, 0,
+ 0, 0,0x634D, 0, 0, 0,0x634B,0x3254,
+0x374E,0x634C,0x3946,0x3972, 0,0x4A66,0x634E, 0,
+ 0,0x4B54, 0, 0,0x6350, 0, 0, 0,
+0x4051,0x314F,0x323A,0x302C, 0, 0, 0, 0,
+ 0, 0,0x634F, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6351,0x6352,0x3E77, 0,
+ 0, 0, 0, 0,0x6353, 0,0x334F, 0,
+ 0, 0, 0,0x6355, 0, 0, 0,0x376A,
+ 0,0x3566, 0, 0,0x6356,0x3675, 0, 0,
+0x6357, 0,0x407C, 0,0x464D, 0,0x4060,0x3A75,
+ 0, 0, 0,0x6358, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4362,0x416B, 0,
+0x635A,0x635C,0x6359,0x635B, 0, 0, 0, 0,
+ 0, 0,0x3722, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x635D,0x3726, 0, 0,
+ 0,0x3567,0x4D52,0x635F, 0, 0, 0, 0,
+ 0,0x6360, 0, 0, 0,0x312E, 0, 0,
+ 0, 0,0x6363, 0, 0, 0,0x3376,0x6362,
+0x6361, 0,0x6365,0x635E, 0,0x6366,0x4E29, 0,
+0x6367, 0,0x6368, 0, 0,0x5474,0x636A, 0,
+0x6369, 0, 0, 0,0x636B,0x636C, 0,0x4E35,
+0x636D, 0,0x706F,0x3E4F,0x636E,0x636F,0x3D57, 0,
+0x4638,0x6370, 0, 0, 0,0x4328, 0, 0,
+0x6371, 0,0x433C,0x6372, 0, 0, 0, 0,
+ 0,0x3625, 0,0x513F,0x435D,0x3C33, 0, 0,
+ 0, 0,0x3448, 0, 0,0x6373, 0,0x6422,
+ 0,0x6376, 0,0x3568, 0,0x6375,0x6424, 0,
+ 0, 0,0x6374, 0,0x3E50, 0, 0, 0,
+ 0, 0, 0,0x6378,0x6379, 0,0x452B, 0,
+ 0,0x637A, 0,0x335E, 0, 0, 0, 0,
+0x3F5A,0x4964, 0,0x637C, 0, 0, 0,0x4268,
+ 0, 0, 0, 0, 0, 0,0x6377, 0,
+0x637B,0x637D, 0, 0,0x3A7B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6426,0x492E, 0,0x4826,0x4579, 0,0x365A,0x6425,
+0x6423, 0,0x4835,0x637E,0x435E,0x457B, 0,0x457A,
+ 0,0x3A76, 0, 0, 0, 0, 0, 0,
+0x6438, 0, 0, 0, 0, 0, 0, 0,
+0x6428, 0,0x642A, 0, 0, 0, 0,0x642D,
+ 0,0x642E, 0,0x642B,0x642C, 0, 0,0x6429,
+0x6427, 0, 0, 0, 0,0x6421, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4A4F,0x3255, 0, 0, 0,0x6435, 0,
+0x6432, 0,0x6437, 0, 0,0x6436, 0,0x4773,
+0x4C27, 0,0x3B3B,0x6430,0x6439,0x6434, 0,0x6433,
+0x642F, 0,0x6431, 0,0x3449, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x433D, 0, 0,
+0x407D, 0, 0, 0,0x4822, 0, 0,0x643E,
+ 0, 0, 0,0x4824, 0, 0, 0, 0,
+ 0, 0, 0,0x4061,0x643B, 0, 0,0x484F,
+ 0,0x643F,0x4A53, 0,0x435B, 0,0x643A,0x643C,
+ 0, 0,0x643D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6440, 0, 0,0x3C44, 0, 0, 0,0x4646,
+0x6445,0x6444, 0, 0,0x6441, 0, 0, 0,
+0x4F36, 0, 0, 0, 0, 0,0x644A, 0,
+ 0,0x644E,0x644B, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6447, 0, 0, 0, 0,
+ 0, 0,0x6448, 0, 0, 0, 0, 0,
+0x644D, 0, 0, 0,0x6442,0x5255,0x6449,0x6443,
+ 0, 0,0x644C, 0, 0, 0, 0, 0,
+ 0, 0,0x6452, 0,0x344A, 0,0x644F, 0,
+ 0, 0,0x6450, 0, 0,0x6451,0x6454, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6453,0x4876, 0, 0, 0, 0,
+0x6455,0x4E7C,0x4A6D,0x645A, 0, 0,0x6457, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6456,
+0x4052, 0,0x6459,0x645B, 0, 0, 0,0x6458,
+ 0,0x645F, 0,0x645C, 0, 0, 0, 0,
+ 0, 0,0x645D,0x6446, 0, 0, 0,0x645E,
+0x6460, 0, 0, 0, 0, 0, 0,0x6461,
+ 0, 0, 0, 0, 0, 0,0x4A46, 0,
+0x6462, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4C62, 0, 0,0x364E,0x3729,0x6463, 0,
+ 0, 0, 0, 0,0x4A34, 0,0x3F68, 0,
+0x4C30, 0, 0,0x6464, 0,0x4E33, 0, 0,
+0x4774, 0,0x4146,0x4734, 0, 0,0x3D4D, 0,
+ 0, 0,0x3040, 0,0x6469,0x6467, 0,0x6465,
+0x3421, 0,0x3E51,0x646A, 0, 0,0x6468, 0,
+0x6466,0x646E, 0, 0,0x646D,0x646C,0x646B, 0,
+ 0, 0, 0, 0,0x646F, 0, 0, 0,
+0x6470,0x403A, 0,0x6471, 0,0x6473, 0, 0,
+0x6472, 0, 0, 0, 0,0x3852, 0, 0,
+ 0,0x4138, 0, 0, 0,0x6475, 0, 0,
+ 0,0x457C, 0,0x6474, 0, 0, 0,0x6476,
+ 0,0x4A35,0x416C,0x3947, 0,0x6477, 0, 0,
+ 0, 0,0x4E48, 0, 0, 0, 0, 0,
+ 0, 0,0x6479, 0, 0,0x647A, 0,0x647B,
+ 0,0x647C, 0,0x3B65, 0,0x647D,0x374F, 0,
+ 0,0x356A, 0,0x352A, 0,0x6521, 0,0x4C73,
+0x3948,0x647E, 0, 0, 0,0x6524,0x4C66, 0,
+0x473C, 0, 0,0x4933, 0, 0, 0,0x3D63,
+0x6523, 0,0x3C53,0x3949,0x3B66,0x3569,0x4A36,0x6522,
+ 0, 0, 0,0x4147,0x4B42,0x3A77, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3B67,0x445D,
+ 0,0x6527,0x4E5F,0x3A59, 0,0x6528,0x3F42, 0,
+0x652A, 0, 0, 0,0x3E52,0x3A30, 0, 0,
+ 0, 0,0x6529, 0, 0,0x3D2A,0x383E,0x4148,
+0x6525,0x652B, 0, 0, 0, 0,0x6526,0x3750,
+ 0,0x652E,0x6532,0x376B, 0, 0, 0, 0,
+ 0,0x652D, 0, 0, 0, 0,0x6536, 0,
+ 0,0x394A, 0, 0,0x4D6D,0x303C,0x6533, 0,
+ 0,0x356B, 0,0x6530, 0, 0, 0, 0,
+ 0,0x6531, 0, 0,0x457D,0x652F,0x652C, 0,
+0x3328,0x4064, 0, 0,0x3828, 0, 0, 0,
+0x6538, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6535, 0, 0, 0,
+ 0, 0,0x6537, 0, 0, 0,0x6534, 0,
+ 0, 0, 0, 0,0x3751,0x4233,0x6539,0x416E,
+ 0, 0,0x6546, 0, 0,0x6542,0x653C, 0,
+ 0, 0, 0, 0, 0, 0,0x6540,0x3C7A,
+0x305D,0x653B,0x6543,0x6547,0x394B,0x4C56, 0,0x4456,
+0x653D, 0, 0,0x6545, 0,0x653A,0x433E, 0,
+0x653F,0x303D,0x4C4A, 0, 0, 0, 0, 0,
+ 0, 0,0x653E, 0, 0,0x365B,0x486C, 0,
+ 0, 0,0x416D, 0,0x4E50,0x3D6F, 0, 0,
+0x656E, 0, 0,0x6548, 0,0x407E, 0,0x6544,
+0x6549,0x654B, 0,0x4479,0x654E, 0, 0,0x654A,
+ 0, 0, 0,0x4A54,0x344B, 0, 0,0x4C4B,
+ 0, 0,0x305E, 0, 0,0x654D, 0,0x4E7D,
+ 0, 0, 0, 0, 0, 0,0x654C, 0,
+ 0, 0, 0, 0,0x316F, 0, 0,0x466C,
+0x654F, 0, 0, 0,0x6556,0x6550,0x6557, 0,
+ 0, 0, 0, 0, 0,0x6553, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x477B, 0,
+ 0,0x3C4A,0x6555, 0,0x6552,0x6558,0x6551, 0,
+ 0,0x3D44, 0, 0, 0, 0,0x4B25, 0,
+ 0,0x3D4C, 0, 0,0x6554,0x6560, 0, 0,
+0x655C, 0,0x655F, 0,0x655D,0x6561,0x655B, 0,
+0x6541,0x4053, 0, 0,0x484B, 0,0x655E, 0,
+ 0,0x6559, 0, 0, 0,0x4121,0x3752, 0,
+0x3D2B, 0, 0, 0, 0, 0, 0,0x3F25,
+0x4136,0x6564, 0, 0,0x6566,0x6567, 0, 0,
+0x6563,0x6565, 0, 0, 0, 0, 0, 0,
+ 0,0x655A,0x6562, 0,0x656A,0x6569, 0, 0,
+0x4B7A, 0, 0,0x372B, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6568, 0,0x656C,0x656B,
+0x656F, 0,0x6571, 0, 0,0x3B3C,0x656D, 0,
+ 0, 0, 0,0x6572,0x6573, 0, 0,0x6574,
+ 0,0x657A,0x453B,0x6576, 0,0x6575,0x6577,0x6578,
+ 0,0x6579, 0, 0, 0, 0,0x657B,0x657C
+};
+
+/* page 39 0x7F36-0x8358 */
+static uint16 tab_uni_jisx020839[]={
+0x344C, 0,0x657D, 0,0x657E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6621,
+ 0, 0, 0, 0, 0, 0,0x6622,0x6623,
+0x6624, 0,0x6625,0x6626, 0, 0,0x6628,0x6627,
+ 0, 0,0x6629, 0, 0, 0, 0, 0,
+ 0,0x662A,0x662B, 0, 0, 0, 0, 0,
+ 0,0x662E,0x662C,0x662D,0x3A61,0x3753, 0, 0,
+0x4356, 0,0x4833, 0,0x3D70, 0, 0,0x474D,
+ 0,0x486D,0x662F,0x586D, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6630,0x6632, 0,0x4D65,
+0x6631,0x6634,0x6633, 0,0x4D53, 0,0x6635, 0,
+0x487E, 0, 0, 0, 0, 0,0x6636, 0,
+ 0, 0, 0, 0,0x6639, 0, 0,0x6638,
+0x6637, 0, 0, 0, 0,0x663A,0x3732, 0,
+ 0, 0,0x4122,0x3541, 0, 0, 0, 0,
+0x663E,0x663B, 0, 0,0x663C, 0, 0, 0,
+0x663F, 0,0x6640,0x663D, 0, 0, 0,0x3129,
+ 0, 0, 0,0x3227, 0, 0, 0,0x6642,
+0x6643, 0, 0, 0,0x6644, 0,0x4D62, 0,
+ 0, 0, 0, 0,0x3D2C, 0,0x6646,0x6645,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3F69,0x6647, 0, 0, 0, 0,
+0x6648, 0, 0,0x6649, 0,0x3465, 0, 0,
+ 0, 0,0x344D, 0, 0,0x664A, 0, 0,
+ 0, 0, 0,0x664B, 0,0x4B5D,0x4D63, 0,
+ 0, 0,0x4D54,0x4F37, 0,0x394D,0x664E,0x3C54,
+0x664D, 0, 0, 0, 0,0x664F,0x3C29, 0,
+ 0, 0,0x4251, 0,0x6650, 0, 0,0x394C,
+ 0,0x4C57,0x6651,0x6652, 0, 0,0x6653, 0,
+ 0, 0, 0,0x6654, 0, 0, 0, 0,
+ 0, 0,0x6655, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3C2A, 0, 0,
+0x4C6D, 0, 0, 0, 0,0x6657, 0,0x433F,
+ 0,0x6656, 0, 0, 0, 0, 0, 0,
+0x6659, 0, 0, 0,0x6658, 0, 0, 0,
+ 0, 0, 0, 0,0x665A, 0, 0, 0,
+0x403B, 0,0x665B, 0,0x665C, 0, 0, 0,
+0x4A39,0x665D, 0,0x416F,0x665E, 0, 0, 0,
+ 0, 0,0x665F, 0, 0, 0, 0, 0,
+ 0,0x4E7E,0x6662, 0,0x6661,0x6660,0x4430, 0,
+0x6663,0x3F26, 0,0x6664, 0, 0, 0,0x6665,
+0x4F38,0x6666, 0, 0, 0, 0,0x6667,0x6669,
+0x6668,0x4825, 0,0x4679, 0,0x4F3E,0x4829, 0,
+ 0, 0, 0, 0, 0,0x666B, 0, 0,
+0x3E53, 0,0x492A, 0,0x666C,0x666A, 0,0x344E,
+ 0, 0, 0,0x3854,0x3B68, 0, 0,0x486E,
+ 0, 0, 0,0x382A,0x4B43, 0,0x666F,0x666D,
+ 0,0x394E, 0,0x394F,0x3069, 0,0x3A68, 0,
+ 0, 0, 0, 0,0x4759, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x305F,0x6674, 0,
+0x4340, 0, 0, 0, 0, 0,0x4758, 0,
+0x425B, 0, 0, 0, 0, 0, 0, 0,
+0x6676, 0, 0,0x6672,0x6675,0x6670, 0,0x6673,
+0x4B26, 0, 0,0x3855, 0, 0,0x307D,0x6671,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6678, 0,0x6679, 0, 0,0x4639, 0,
+ 0, 0,0x363B, 0, 0, 0,0x6726,0x473D,
+ 0, 0, 0, 0,0x3B69, 0, 0,0x363C,
+0x4048,0x4F46,0x4C2E,0x6677,0x4054, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3553,0x667A, 0, 0,
+ 0, 0, 0, 0, 0,0x667C, 0, 0,
+ 0, 0, 0,0x667B, 0, 0, 0, 0,
+ 0,0x667D, 0,0x4326, 0,0x473E, 0, 0,
+ 0, 0, 0,0x4431, 0, 0, 0, 0,
+0x6723, 0, 0, 0, 0, 0, 0, 0,
+0x6722, 0, 0, 0, 0,0x667E, 0, 0,
+0x3F55, 0,0x4965,0x6725, 0,0x6724,0x3950,0x4F53,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6735, 0, 0, 0, 0, 0,0x6729,
+0x672A, 0, 0, 0, 0,0x3C70, 0, 0,
+0x6728, 0,0x3978,0x6727, 0, 0,0x672B, 0,
+ 0, 0,0x4432,0x4A22,0x4123, 0, 0, 0,
+ 0,0x425C,0x672F, 0,0x6730,0x672C, 0, 0,
+ 0, 0,0x672D, 0,0x672E, 0, 0, 0,
+ 0,0x3951, 0, 0, 0,0x6736, 0,0x6732,
+ 0, 0, 0, 0,0x4966, 0,0x4B6C,0x4928,
+ 0, 0,0x6731, 0, 0,0x6734,0x6733, 0,
+ 0, 0,0x4B44,0x6737, 0, 0, 0, 0,
+ 0, 0,0x6738, 0, 0,0x4137, 0,0x6739,
+ 0, 0,0x673B, 0,0x673F, 0, 0,0x673C,
+0x673A,0x473F,0x673D, 0,0x673E, 0, 0, 0,
+0x3232, 0,0x6745,0x6740, 0, 0, 0,0x6741,
+ 0, 0, 0,0x6742, 0,0x4221, 0, 0,
+ 0, 0,0x6744,0x6743,0x6746, 0, 0, 0,
+ 0,0x6747,0x6748, 0, 0,0x3F43, 0,0x3269,
+ 0,0x6749,0x4E57, 0,0x3C2B, 0, 0,0x3D2D,
+ 0, 0, 0, 0, 0,0x3B6A,0x4357, 0,
+ 0, 0, 0, 0,0x674A,0x674B,0x3131, 0,
+0x674C, 0, 0,0x674D,0x674E, 0, 0,0x674F,
+ 0,0x6750,0x363D,0x5A2A,0x6751, 0,0x4065,0x6752,
+0x3C4B, 0,0x6753, 0,0x5030, 0, 0, 0,
+0x6754,0x4A5E,0x345C, 0, 0,0x4124,0x3D58, 0,
+0x4971,0x3D2E, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6755,0x3952,0x6756,0x484C, 0,
+0x6764, 0, 0, 0, 0,0x6758, 0,0x4249,
+0x4775,0x383F,0x6757,0x4125, 0, 0, 0, 0,
+ 0, 0,0x6759, 0, 0, 0, 0, 0,
+ 0,0x447A, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x675B,0x675A,0x675D, 0, 0,0x675C,
+ 0,0x675E, 0, 0,0x6760, 0,0x675F, 0,
+0x344F, 0,0x6761, 0,0x6762,0x6763, 0, 0,
+0x3A31,0x4E49, 0,0x6765,0x3F27, 0, 0, 0,
+0x3170,0x6766,0x6767, 0, 0, 0, 0, 0,
+0x6768, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3072, 0,0x6769,
+ 0, 0, 0, 0,0x676A, 0, 0, 0,
+ 0, 0, 0,0x4967, 0, 0, 0,0x3C47,
+ 0,0x676C, 0, 0, 0, 0, 0,0x3329,
+0x3032, 0, 0, 0, 0,0x676B,0x676E,0x474E,
+ 0,0x3F44, 0,0x3256, 0,0x4B27, 0, 0,
+ 0, 0,0x375D,0x365C, 0,0x676D, 0,0x326A,
+ 0, 0, 0, 0, 0, 0, 0,0x3423,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3171,0x6772,0x4E6A,0x425D, 0,
+ 0,0x4944, 0,0x677E, 0,0x3257,0x677C, 0,
+0x677A,0x6771, 0,0x676F, 0,0x6770, 0,0x3C63,
+0x366C,0x4377, 0, 0, 0,0x4651, 0, 0,
+ 0, 0, 0,0x3151, 0,0x6774,0x6773, 0,
+ 0, 0, 0,0x6779,0x6775,0x6778, 0, 0,
+ 0, 0, 0, 0,0x4C50,0x6777,0x3258,0x337D,
+0x677B, 0, 0,0x677D, 0, 0, 0, 0,
+0x3754, 0, 0, 0, 0, 0, 0, 0,
+0x6823,0x682C,0x682D, 0, 0, 0,0x302B, 0,
+ 0, 0, 0, 0, 0,0x6834, 0, 0,
+ 0, 0,0x3071, 0, 0,0x682B, 0, 0,
+ 0,0x682A, 0,0x6825,0x6824, 0,0x6822,0x6821,
+0x4363, 0,0x427B,0x6827, 0, 0, 0, 0,
+ 0, 0,0x6826, 0, 0, 0, 0,0x6829,
+ 0, 0, 0,0x4170,0x3755, 0, 0, 0,
+ 0,0x3141,0x6828, 0,0x3953, 0, 0, 0,
+ 0, 0,0x4171};
+
+/* page 40 0x8373-0x8B9A */
+static uint16 tab_uni_jisx020840[]={
+0x683A, 0,0x683B, 0,0x3259, 0, 0, 0,
+0x322E,0x6838, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x682E, 0,0x6836, 0,0x683D,0x6837,
+ 0, 0, 0,0x6835, 0, 0, 0, 0,
+0x6776, 0, 0,0x6833, 0, 0, 0,0x682F,
+ 0, 0, 0,0x3450,0x6831,0x683C, 0,0x6832,
+ 0, 0, 0, 0, 0,0x683E, 0,0x6830,
+0x477C, 0, 0, 0, 0, 0,0x4D69, 0,
+ 0, 0,0x6839, 0, 0, 0, 0, 0,
+ 0, 0,0x684F, 0, 0, 0,0x6847, 0,
+ 0, 0,0x3F7B, 0, 0, 0, 0,0x3546,
+ 0,0x365D, 0,0x6842, 0, 0, 0, 0,
+0x325B, 0, 0,0x3E54, 0,0x6845, 0, 0,
+ 0,0x3A5A, 0, 0,0x4551,0x684A, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4A6E, 0,
+0x6841, 0, 0, 0,0x325A,0x3856,0x4929,0x684B,
+ 0,0x683F, 0, 0,0x6848, 0, 0, 0,
+0x6852, 0,0x6843, 0, 0, 0, 0, 0,
+0x6844,0x463A, 0, 0,0x6849, 0, 0, 0,
+0x6846,0x4B28,0x684C,0x3060, 0, 0, 0, 0,
+0x6840, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x684E, 0,0x684D,
+ 0, 0, 0, 0, 0, 0,0x476B,0x6854,
+ 0,0x685F, 0, 0, 0, 0,0x337E, 0,
+ 0, 0,0x6862, 0, 0,0x6850, 0, 0,
+ 0,0x6855,0x4D6E, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x685E, 0, 0,0x4D55, 0,
+ 0, 0, 0,0x4E2A, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4378, 0, 0, 0,
+0x336B, 0, 0, 0, 0, 0,0x4972,0x6864,
+0x4621, 0, 0,0x3031, 0, 0,0x685D, 0,
+0x6859,0x4172,0x6853,0x685B,0x6860, 0,0x472C, 0,
+ 0, 0,0x302A, 0,0x6858, 0,0x6861,0x4978,
+ 0, 0, 0, 0, 0, 0, 0,0x685C,
+ 0,0x6857, 0, 0, 0, 0, 0, 0,
+0x3E55, 0, 0, 0, 0,0x3D2F, 0, 0,
+ 0,0x3C2C, 0, 0, 0, 0,0x4C58, 0,
+ 0,0x4947, 0, 0,0x6867, 0,0x6870, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x685A, 0, 0, 0, 0,0x3377,
+ 0, 0, 0, 0, 0,0x3E78,0x6865, 0,
+0x686A,0x4173, 0, 0,0x6866, 0,0x686D, 0,
+ 0,0x435F, 0,0x686E, 0, 0,0x4D56,0x6863,
+0x3338, 0,0x6869, 0, 0,0x686C,0x4C2C, 0,
+ 0, 0, 0,0x686F, 0, 0,0x6868,0x686B,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4B29, 0,0x4F21, 0, 0, 0, 0,
+ 0,0x6873, 0, 0, 0, 0, 0, 0,
+ 0,0x687A, 0, 0,0x6872,0x3C43, 0, 0,
+ 0, 0, 0,0x6851, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4A4E, 0,
+0x4C22,0x6879,0x6878, 0,0x6874,0x6875, 0,0x3136,
+ 0, 0, 0, 0,0x6877, 0,0x6871, 0,
+ 0, 0, 0,0x4455, 0, 0, 0, 0,
+ 0,0x6876,0x307E, 0, 0, 0, 0, 0,
+ 0, 0,0x4222, 0, 0, 0, 0, 0,
+ 0, 0,0x4A43, 0, 0,0x687B,0x6921, 0,
+0x4859, 0, 0, 0, 0,0x687E,0x3E56,0x3C49,
+0x6923, 0, 0,0x363E, 0, 0, 0, 0,
+ 0, 0,0x6924, 0,0x4979,0x687D, 0,0x6856,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x687C, 0, 0, 0, 0,0x4F4F,0x4622,0x4973,
+ 0, 0,0x692B, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6931, 0, 0, 0,
+ 0, 0, 0,0x6932, 0,0x6925, 0, 0,
+ 0,0x4776, 0, 0,0x692F,0x6927, 0,0x6929,
+ 0, 0, 0, 0, 0,0x6933,0x6928, 0,
+ 0,0x692C, 0, 0,0x3172, 0,0x4665, 0,
+0x692D,0x6930, 0, 0, 0, 0, 0, 0,
+ 0,0x6926, 0,0x4126, 0,0x692A,0x3B27,0x3F45,
+0x3730,0x4C74, 0,0x4C79,0x3D72, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6937,0x6935,
+ 0, 0, 0, 0, 0, 0,0x4F4E, 0,
+ 0, 0, 0, 0, 0, 0,0x6934, 0,
+ 0, 0,0x4D75, 0,0x6936,0x6938, 0, 0,
+ 0, 0,0x6939, 0, 0, 0, 0, 0,
+ 0,0x693C,0x693A, 0, 0, 0, 0, 0,
+ 0,0x4623,0x693B, 0, 0, 0,0x484D,0x692E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3D73, 0,0x693D,0x6942,
+0x4174, 0, 0,0x6941, 0, 0, 0,0x6922,
+ 0, 0, 0,0x6943,0x4149, 0, 0,0x693E,
+0x6940, 0, 0, 0, 0, 0, 0, 0,
+0x693F, 0, 0,0x5D31,0x5D22, 0, 0,0x6945,
+ 0, 0, 0, 0, 0, 0, 0,0x6944,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4D76, 0,0x623C,0x6946, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6947, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6948,0x3857, 0,0x3554, 0, 0,
+ 0,0x694A,0x515D, 0, 0, 0, 0,0x3575,
+ 0,0x4E3A, 0,0x3673,0x694B, 0, 0, 0,
+ 0, 0, 0, 0,0x694C, 0, 0, 0,
+0x436E, 0, 0, 0, 0, 0,0x694D, 0,
+ 0, 0, 0, 0, 0, 0,0x467A, 0,
+0x303A, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3263,
+0x6952,0x6953, 0, 0, 0, 0, 0, 0,
+0x694E, 0,0x3B3D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x694F,0x4742, 0, 0, 0, 0,0x6950,0x6951,
+0x695B, 0, 0, 0,0x6955,0x6958, 0, 0,
+ 0, 0, 0,0x6954, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6956, 0,0x6957,0x3C58, 0,0x6959, 0,
+0x4341, 0,0x3756,0x3342, 0, 0, 0, 0,
+ 0,0x695C, 0, 0, 0, 0,0x333F, 0,
+0x6961, 0, 0,0x695D,0x6960, 0, 0, 0,
+ 0,0x483A, 0, 0, 0, 0,0x695E, 0,
+ 0,0x695F,0x4948,0x485A,0x6962, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x427D,0x696C, 0,
+0x6968, 0, 0,0x326B, 0,0x6966, 0,0x4B2A,
+0x6967, 0, 0,0x6964, 0,0x6965,0x696A,0x696D,
+ 0, 0,0x696B, 0, 0, 0,0x6969,0x6963,
+ 0, 0, 0, 0, 0,0x4358, 0,0x6974,
+ 0,0x4C2A, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6972, 0, 0, 0,0x6973, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x696E, 0, 0,0x6970, 0, 0, 0,
+0x6971, 0, 0, 0,0x696F, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4066, 0,
+0x4F39,0x6978, 0,0x6979, 0, 0, 0, 0,
+0x6A21, 0,0x3F2A, 0,0x697B, 0,0x697E, 0,
+ 0, 0, 0, 0,0x6976,0x6975, 0, 0,
+0x6A22, 0, 0,0x325C, 0,0x697C, 0,0x6A23,
+ 0, 0, 0,0x697D, 0, 0, 0, 0,
+ 0,0x697A, 0,0x4433, 0,0x6977, 0, 0,
+ 0, 0, 0, 0,0x4768, 0, 0,0x6A27,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4D3B, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6A26, 0, 0,0x6A25,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6A2E, 0, 0, 0,0x6A28, 0, 0, 0,
+0x6A30, 0, 0, 0, 0, 0, 0,0x4D66,
+0x6A33, 0,0x6A2A, 0, 0,0x6A2B, 0, 0,
+ 0,0x6A2F, 0,0x6A32,0x6A31, 0, 0, 0,
+0x6A29, 0, 0, 0, 0,0x6A2C, 0,0x6A3D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6A36, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6A34, 0, 0,0x6A35,
+ 0, 0, 0,0x6A3A,0x6A3B, 0,0x332A, 0,
+0x3542, 0, 0,0x6A39, 0, 0, 0, 0,
+ 0, 0,0x6A24, 0, 0, 0, 0, 0,
+ 0, 0,0x6A38,0x6A3C,0x6A37, 0,0x6A3E, 0,
+ 0, 0,0x6A40,0x6A3F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6A42,0x6A41,
+0x695A, 0, 0, 0,0x6A46, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6A43, 0,
+ 0, 0, 0,0x6A44, 0, 0,0x6A45, 0,
+0x6A47, 0, 0, 0, 0,0x376C, 0,0x6A49,
+ 0,0x6A48, 0,0x3D30, 0, 0, 0, 0,
+ 0,0x3954,0x5E27, 0, 0, 0, 0,0x6A4A,
+0x3D51, 0, 0, 0,0x3339, 0,0x6A4B, 0,
+0x3152, 0,0x3E57,0x6A4C, 0, 0,0x3955,0x6A4D,
+0x3061, 0, 0, 0, 0,0x493D, 0, 0,
+0x6A4E, 0, 0, 0, 0,0x3F6A, 0,0x6A55,
+ 0, 0,0x6A52, 0,0x436F, 0, 0, 0,
+ 0, 0,0x6A53,0x6A50,0x365E, 0,0x6A4F,0x6A56,
+ 0, 0, 0, 0, 0,0x3736, 0, 0,
+0x425E, 0,0x6A5C, 0, 0, 0, 0,0x6A58,
+ 0, 0, 0,0x4235,0x6A57, 0,0x6A5A, 0,
+ 0, 0, 0,0x6A51, 0, 0, 0,0x6A5B,
+ 0,0x6A5D, 0, 0, 0, 0, 0, 0,
+0x486F, 0, 0,0x6A59, 0,0x6A5E,0x6A60, 0,
+ 0,0x3853,0x6A54, 0,0x3041, 0, 0, 0,
+ 0, 0, 0, 0,0x6A5F, 0,0x3A5B,0x4E76,
+0x6A61,0x6A62,0x4175, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4E22, 0, 0, 0,
+ 0,0x6A63,0x4D35, 0, 0,0x6A64,0x6A65, 0,
+ 0,0x4A64,0x6A66, 0,0x3A40, 0,0x4E23, 0,
+ 0, 0, 0, 0, 0,0x6A6B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6A6C,
+0x3E58,0x6A6A, 0, 0, 0,0x4D67,0x6A67, 0,
+ 0,0x6A69,0x403D,0x3F7E, 0, 0, 0,0x6A68,
+ 0,0x6A6D, 0, 0,0x4A23, 0, 0,0x6A6F,
+ 0,0x6A6E, 0, 0, 0,0x336C, 0,0x4B2B,
+0x6A70, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6A7C,0x6A72, 0, 0, 0, 0,
+ 0, 0,0x6A73, 0, 0, 0, 0,0x6A74,
+0x6A75, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6A79, 0,0x6A7A, 0, 0,
+0x6A78, 0, 0, 0, 0, 0,0x6A76, 0,
+0x6A71,0x6A77, 0, 0, 0, 0, 0, 0,
+ 0,0x6A7B,0x7037, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3228, 0, 0, 0, 0,
+ 0, 0, 0,0x6A7E,0x365F,0x6A7D, 0, 0,
+ 0,0x6B22, 0,0x6B21, 0, 0, 0,0x6B24,
+ 0, 0,0x6B23, 0,0x6B25, 0, 0,0x3D31,
+ 0,0x6B26, 0, 0,0x6B27, 0, 0, 0,
+ 0, 0, 0,0x6B28,0x403E, 0,0x4D57, 0,
+0x6B29, 0, 0,0x4A24,0x4746,0x6B2A, 0,0x6B2B,
+0x382B, 0, 0, 0,0x352C, 0, 0, 0,
+0x6B2C, 0, 0,0x3B6B,0x4741,0x6B2D, 0,0x3350,
+ 0, 0, 0, 0, 0, 0,0x6B2E, 0,
+ 0, 0, 0,0x6B30,0x4D77, 0,0x6B2F,0x3F46,
+ 0,0x6B31, 0, 0,0x6B32, 0, 0,0x6B33,
+0x3451, 0, 0, 0, 0, 0, 0,0x6B34,
+ 0, 0,0x6B35, 0,0x6B36,0x6B37, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3351,
+ 0, 0, 0, 0, 0, 0, 0,0x6B38,
+ 0,0x6B39,0x6B3A, 0, 0, 0, 0, 0,
+0x3272, 0, 0,0x3F28,0x6B3B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6B3C, 0, 0, 0,0x6B3D, 0, 0,
+ 0, 0, 0, 0, 0,0x3840, 0,0x447B,
+0x6B3E, 0, 0, 0, 0,0x3757, 0,0x3F56,
+ 0,0x6B41, 0,0x4624, 0,0x6B40, 0, 0,
+0x3731, 0, 0,0x6B3F,0x4277,0x352D, 0, 0,
+0x6B42, 0,0x6B43, 0,0x3E59, 0, 0, 0,
+0x376D, 0,0x6B44, 0, 0, 0, 0,0x4B2C,
+ 0, 0,0x405F, 0, 0, 0,0x3576, 0,
+0x4C75,0x414A, 0,0x6B45, 0, 0, 0,0x3F47,
+0x4370,0x3E5A, 0, 0, 0, 0,0x6B46, 0,
+ 0, 0, 0,0x6B49, 0,0x6B4A, 0, 0,
+ 0, 0, 0, 0, 0,0x3A3E,0x4242,0x6B48,
+ 0,0x3E5B,0x493E, 0, 0, 0, 0, 0,
+0x6B47, 0, 0,0x3B6C, 0,0x3153, 0,0x6B4E,
+0x3758, 0, 0,0x3B6E, 0, 0,0x3B6D, 0,
+0x4F4D,0x6B4D,0x6B4C,0x4127, 0,0x354D,0x4F43,0x333A,
+0x3E5C, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6B4B, 0, 0, 0, 0, 0,0x6B50,
+ 0,0x6B51,0x6B4F, 0,0x3858, 0,0x4D40, 0,
+ 0,0x3B6F,0x4727, 0, 0, 0,0x6B54, 0,
+0x4040, 0,0x4342, 0, 0,0x4D36, 0,0x6B57,
+ 0, 0, 0,0x386C, 0,0x403F,0x6B53, 0,
+0x6B58,0x386D,0x6B55,0x6B56, 0,0x6B52, 0, 0,
+ 0,0x4062,0x4649, 0, 0,0x432F, 0,0x325D,
+ 0, 0, 0, 0, 0, 0,0x4870, 0,
+ 0,0x3543, 0, 0,0x4434, 0, 0,0x6B5B,
+ 0,0x6B59, 0, 0,0x434C, 0, 0, 0,
+0x4041,0x3452,0x6B5A, 0,0x3F5B, 0, 0,0x4E4A,
+ 0, 0, 0,0x4F40, 0, 0, 0,0x6B5C,
+0x6B67,0x4435, 0,0x6B66, 0,0x6B63,0x6B6B,0x6B64,
+ 0,0x6B60, 0,0x447C,0x6B5F, 0, 0, 0,
+0x6B5D, 0,0x4D21,0x3B70, 0, 0,0x6B61, 0,
+0x6B5E, 0, 0, 0,0x6B65,0x3D74, 0,0x3841,
+ 0, 0, 0,0x427A, 0,0x4B45,0x315A,0x3062,
+ 0,0x4625, 0, 0,0x6B69, 0, 0, 0,
+ 0,0x6B68, 0,0x4666, 0,0x6B6D, 0, 0,
+ 0,0x6B62, 0,0x6B6C,0x6B6E, 0,0x382C,0x6B6A,
+0x3956, 0,0x3C55, 0, 0,0x6B6F,0x4D58, 0,
+ 0, 0, 0,0x6B72, 0,0x6B75, 0, 0,
+0x6B73,0x4935, 0, 0, 0, 0, 0, 0,
+0x6B70, 0, 0, 0, 0, 0,0x3660, 0,
+ 0, 0, 0,0x6B74, 0, 0,0x6B76, 0,
+ 0, 0, 0, 0, 0, 0,0x6B7A, 0,
+ 0,0x6B77, 0,0x6B79,0x6B78, 0, 0, 0,
+ 0, 0, 0,0x6B7B, 0,0x3C31, 0,0x6B7D,
+0x6B7C,0x4968, 0, 0,0x6C21, 0, 0, 0,
+ 0, 0, 0,0x3759, 0, 0, 0, 0,
+0x6B7E,0x6C22, 0, 0,0x6C23,0x3544,0x6641,0x3E79,
+ 0,0x6C24, 0, 0,0x386E, 0, 0, 0,
+ 0, 0,0x6C25, 0, 0,0x6C26, 0, 0,
+0x3B3E, 0, 0, 0, 0, 0, 0,0x5A4E,
+ 0,0x6C27, 0,0x6C28, 0,0x3D32, 0,0x6C29,
+0x6C2A, 0, 0,0x6C2B, 0, 0,0x6C2C,0x6C2D
+};
+
+/* page 41 0x8C37-0x8D16 */
+static uint16 tab_uni_jisx020841[]={
+0x432B, 0, 0,0x6C2E, 0, 0, 0, 0,
+0x6C30, 0,0x6C2F, 0, 0, 0, 0,0x4626,
+ 0,0x6C31, 0,0x4B2D, 0,0x6C32, 0,0x6C33,
+ 0,0x6C34, 0, 0, 0, 0,0x6C35, 0,
+ 0, 0, 0,0x465A, 0, 0, 0, 0,
+ 0, 0,0x3E5D,0x6C36, 0, 0, 0, 0,
+ 0, 0, 0,0x396B,0x502E,0x6C37, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6C38,0x493F,0x6C39, 0,0x6C41, 0, 0,
+ 0, 0, 0,0x6C3A, 0, 0,0x6C3C, 0,
+ 0, 0,0x6C3B,0x6C3D, 0,0x4B46,0x6C3E,0x6C3F,
+ 0, 0, 0, 0, 0,0x6C40, 0, 0,
+ 0,0x6C42, 0, 0, 0, 0,0x332D,0x4467,
+ 0,0x4969,0x3A62,0x3957, 0, 0, 0, 0,
+0x494F,0x325F,0x484E,0x6C45,0x3453,0x4055,0x6C44,0x6C49,
+0x4379,0x4C63, 0,0x6C47,0x6C48,0x352E, 0,0x6C4A,
+0x4763,0x425F, 0, 0,0x4871,0x453D,0x6C46, 0,
+0x4B47,0x326C,0x6C4C,0x4F28,0x4442,0x4F45, 0, 0,
+0x3B71,0x6C4B, 0,0x4231, 0, 0,0x6C5C,0x4128,
+ 0, 0,0x4678, 0,0x4950, 0, 0, 0,
+ 0, 0, 0,0x6C4F,0x3B3F,0x3B72, 0,0x3E5E,
+ 0,0x4765, 0,0x382D,0x6C4E,0x6C4D, 0,0x496A,
+ 0, 0, 0,0x3C41, 0, 0,0x4552, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6C51,0x6C52,0x3958,0x6C50, 0,
+ 0, 0, 0, 0, 0,0x6C53,0x6C54, 0,
+0x6C56,0x4223, 0,0x6C55,0x3466, 0,0x6C58, 0,
+0x6C57,0x6C59, 0, 0,0x6C5B,0x6C5D, 0,0x6C5E
+};
+
+/* page 42 0x8D64-0x8F64 */
+static uint16 tab_uni_jisx020842[]={
+0x4056, 0,0x3C4F,0x6C5F, 0, 0, 0,0x3352,
+ 0,0x6C60, 0, 0,0x4176,0x6C61, 0,0x6C62,
+0x496B, 0, 0,0x352F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6C63, 0, 0,
+ 0,0x4436, 0, 0, 0, 0,0x315B, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6C64, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3C71,
+ 0, 0, 0, 0,0x3F76, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x422D,
+ 0, 0, 0, 0, 0, 0,0x6C67, 0,
+ 0, 0,0x6C66, 0, 0, 0,0x6C65, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6C6D,
+0x6C6B, 0, 0,0x6C68, 0, 0, 0, 0,
+ 0, 0,0x6C6A, 0, 0, 0,0x6C69,0x6C6C,
+ 0,0x3577, 0,0x6C70, 0,0x4057, 0,0x6C71,
+ 0, 0, 0, 0,0x3859, 0,0x6C6E,0x6C6F,
+ 0, 0, 0,0x4F29, 0, 0, 0,0x4437,
+ 0,0x4129, 0, 0, 0, 0, 0, 0,
+0x6C72, 0, 0,0x6C75, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6C73,0x6C74,0x4D59, 0,
+ 0, 0, 0,0x4627,0x6C78, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6C76,0x6C77,0x6C79, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6D29, 0,
+ 0, 0, 0, 0,0x6C7C, 0, 0, 0,
+0x6C7D,0x6C7B, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6C7A, 0,
+0x447D, 0, 0,0x6D21,0x6D25,0x6D22,0x6C7E, 0,
+0x6D23, 0, 0, 0,0x6D24, 0, 0, 0,
+ 0,0x6D2B, 0, 0, 0,0x6D26, 0, 0,
+ 0, 0, 0,0x4058,0x6D28, 0, 0,0x6D2A,
+0x6D27, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6D2D, 0,
+0x3D33, 0,0x6D2C, 0, 0, 0, 0, 0,
+0x6D2E, 0, 0, 0, 0,0x6D2F, 0, 0,
+0x6D32,0x6D31, 0,0x6D30, 0, 0,0x6D34,0x6D33,
+ 0,0x4C76, 0, 0, 0,0x6D36, 0,0x6D35,
+0x6D37, 0, 0, 0, 0,0x6D38, 0, 0,
+ 0, 0, 0, 0, 0,0x6D3A, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6D39,0x3F48,
+0x6D3B, 0, 0,0x366D,0x6D3C,0x6D3E, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6D3F, 0, 0, 0, 0, 0,
+ 0,0x6D40,0x6D3D, 0,0x6D41, 0,0x3C56,0x6D42,
+0x3530,0x3733, 0, 0, 0, 0,0x382E, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6D43,
+ 0, 0, 0,0x4670, 0, 0,0x453E,0x6D44,
+ 0, 0, 0, 0, 0, 0, 0,0x6D47,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3C34, 0, 0,0x6D46,
+0x6D45,0x375A,0x6D48, 0, 0, 0, 0,0x3353,
+ 0,0x6D4A, 0, 0, 0,0x3A5C,0x6D49, 0,
+0x6D52, 0, 0, 0, 0, 0,0x6D4C,0x6D4E,
+0x4A65,0x6D4B, 0, 0, 0,0x6D4D, 0,0x6D51,
+0x6D4F,0x3531, 0,0x6D50, 0, 0, 0, 0,
+ 0, 0,0x6D53, 0, 0,0x475A,0x4E58, 0,
+ 0, 0, 0,0x3D34, 0, 0, 0,0x6D54,
+ 0, 0, 0, 0,0x4D22,0x6D56, 0,0x6D55,
+ 0, 0,0x6D59,0x4D41, 0, 0,0x6D58, 0,
+0x336D,0x6D57,0x6D5C, 0, 0,0x6D5B, 0, 0,
+0x6D5A,0x4532,0x6D5D, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6D5E, 0, 0, 0, 0,
+0x6D5F, 0, 0,0x396C, 0,0x3725,0x6D60,0x6D61,
+0x6D62};
+
+/* page 43 0x8F9B-0x9132 */
+static uint16 tab_uni_jisx020843[]={
+0x3F49,0x6D63, 0,0x3C2D,0x6D64, 0, 0, 0,
+0x6D65, 0, 0, 0,0x5221,0x517E, 0, 0,
+ 0, 0,0x6D66,0x6570,0x6D67,0x4324,0x3F2B,0x4740,
+ 0, 0, 0, 0,0x6D68, 0, 0,0x4A55,
+0x4454,0x397E, 0, 0,0x4329, 0, 0,0x312A,
+ 0,0x4B78,0x3F57, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x375E, 0, 0,0x3661, 0,
+ 0,0x4A56, 0, 0, 0, 0, 0,0x6D69,
+ 0, 0, 0, 0, 0, 0, 0,0x6D6B,
+ 0, 0,0x6D6A,0x3260, 0, 0,0x4676,0x6D6C,
+0x4777, 0,0x4533, 0,0x6D6D,0x3D52, 0, 0,
+ 0,0x6D6F, 0, 0,0x4C42,0x6D7E,0x6D71,0x6D72,
+ 0, 0,0x4449, 0, 0,0x4260,0x4177, 0,
+0x4628, 0,0x6D70,0x3555, 0, 0, 0, 0,
+0x6D79, 0,0x6D76,0x6E25,0x4629,0x4360,0x6D73, 0,
+0x447E,0x4553,0x6D74,0x6D78,0x3F60, 0,0x4767,0x444C,
+ 0, 0,0x4042,0x6D77,0x422E,0x4224,0x6D75,0x3029,
+0x4F22, 0, 0, 0,0x6D7A, 0, 0, 0,
+ 0, 0, 0,0x4261, 0, 0,0x3D35,0x3F4A,
+ 0, 0,0x6D7C,0x6D7B, 0,0x306F,0x6D7D, 0,
+ 0,0x492F, 0,0x6E27, 0, 0,0x465B,0x3F6B,
+ 0, 0,0x4359, 0,0x3678, 0,0x6E26,0x4D37,
+0x313F, 0,0x4A57,0x3261,0x6E21,0x6E22,0x6E23,0x6E24,
+0x463B,0x4323,0x3063,0x6E28, 0,0x6E29,0x7423, 0,
+ 0,0x423D, 0,0x6E2A, 0,0x3173,0x414C, 0,
+0x382F, 0,0x4D5A, 0, 0,0x6E2B,0x452C, 0,
+ 0, 0,0x4178,0x3C57,0x6E2C, 0, 0,0x6E2F,
+ 0, 0,0x3D65,0x6E2D,0x412B,0x412A, 0,0x3064,
+ 0,0x4E4B,0x6E31, 0,0x4872,0x6E33,0x6E32,0x6E30,
+0x6364,0x3454, 0, 0,0x6D6E, 0,0x6E35,0x6E34,
+ 0, 0, 0, 0,0x6E36, 0,0x4D38, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4661, 0, 0,0x4B2E, 0,0x6E37, 0,0x3C59,
+ 0, 0, 0, 0,0x6E38, 0,0x6E39, 0,
+ 0, 0,0x6E3A, 0, 0,0x4521, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x306A, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3959,
+ 0, 0, 0,0x4F3A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6E3E, 0, 0, 0, 0, 0,0x3734,0x6E3B,
+ 0,0x6E3C, 0, 0, 0,0x4974, 0, 0,
+ 0, 0,0x3354, 0, 0, 0, 0, 0,
+ 0, 0,0x4D39, 0,0x363F, 0, 0, 0,
+ 0, 0,0x4554, 0, 0, 0, 0,0x6E3F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6E40,
+ 0, 0, 0, 0, 0, 0,0x6E41, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4522, 0, 0,0x6E43, 0,0x6E42
+};
+
+/* page 44 0x9149-0x92B9 */
+static uint16 tab_uni_jisx020844[]={
+0x4653,0x6E44,0x3D36,0x3C60,0x475B,0x4371, 0, 0,
+ 0,0x3C72, 0,0x3F6C, 0,0x6E45, 0,0x6E46,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3F5D,0x6E47, 0,0x6E48, 0, 0, 0,
+0x6E49,0x4D6F, 0,0x3D37, 0, 0, 0, 0,
+ 0,0x6E4B,0x6E4A, 0,0x395A, 0,0x3973,0x3B40,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6E4E, 0, 0, 0, 0,0x3D66, 0,
+0x6E4D, 0,0x6E4C, 0,0x4269, 0, 0,0x386F,
+ 0,0x4043, 0, 0, 0, 0,0x4830, 0,
+ 0, 0, 0,0x3D39, 0, 0, 0, 0,
+ 0,0x6E4F, 0,0x3E5F, 0, 0, 0, 0,
+ 0,0x6E52,0x6E50, 0, 0, 0,0x6E51, 0,
+ 0, 0, 0,0x6E54,0x6E53, 0, 0,0x3E7A,
+ 0,0x6E55, 0, 0, 0, 0, 0,0x6E56,
+0x6E57, 0, 0, 0, 0,0x4850,0x3A53,0x3C61,
+0x6E58, 0,0x6E59,0x4E24,0x3D45,0x4C6E,0x4E4C,0x6E5A,
+0x3662, 0, 0, 0, 0,0x6E5B, 0,0x4523,
+ 0, 0,0x6E5E,0x3378,0x3F4B, 0,0x6E5C, 0,
+0x6E5D, 0,0x4460, 0, 0,0x4B55,0x367C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6E60,0x6E61, 0, 0,
+ 0, 0, 0,0x6E5F, 0, 0,0x6E63, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x465F,0x3343, 0, 0,
+0x6E67, 0, 0,0x6E64,0x6E66, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6E62, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6F4F, 0, 0,0x6E65, 0, 0, 0, 0,
+ 0, 0, 0,0x4E6B, 0, 0,0x385A, 0,
+ 0, 0, 0, 0, 0, 0,0x6E6F, 0,
+ 0, 0, 0,0x4534,0x6E6A, 0, 0,0x6E6D,
+0x6E6B, 0,0x6E70, 0, 0, 0, 0,0x6E71,
+ 0, 0, 0, 0, 0, 0,0x6E69, 0,
+ 0,0x6E76,0x3174, 0, 0,0x6E68, 0, 0,
+ 0,0x482D, 0,0x6E6C, 0,0x3E60, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x395B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4B48, 0,0x3664,
+ 0, 0,0x3D46, 0,0x463C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x412D, 0,0x6E74, 0,0x6E6E,0x6E73, 0,0x4C43,
+ 0,0x4438,0x6E75,0x6E72, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x412C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6E79, 0,
+0x6E78};
+
+/* page 45 0x92CF-0x93E8 */
+static uint16 tab_uni_jisx020845[]={
+0x6E77, 0, 0,0x4B2F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3D7B, 0, 0,
+ 0, 0,0x6E7A,0x4A5F, 0, 0,0x3154, 0,
+ 0, 0, 0,0x4946,0x4372, 0, 0, 0,
+ 0,0x3578, 0,0x6E7C, 0,0x395D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3B2C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6E7B,0x3F6D, 0, 0, 0, 0, 0, 0,
+ 0,0x3F6E,0x6F21,0x6F23, 0, 0, 0, 0,
+ 0,0x3E7B, 0,0x6F22,0x6F24, 0, 0,0x3653,
+ 0,0x4945, 0, 0,0x3C62,0x4F23, 0,0x6E7E,
+0x3A78, 0, 0,0x4F3F, 0, 0,0x6F26, 0,
+ 0, 0, 0,0x6F25,0x6F27, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6E7D, 0, 0,
+ 0, 0, 0, 0,0x4669, 0,0x4555, 0,
+ 0, 0, 0, 0, 0,0x4457, 0,0x6F2C,
+ 0, 0, 0, 0,0x4343,0x6F28, 0, 0,
+ 0,0x6F29, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x372D, 0,0x6F2B,
+ 0, 0, 0, 0, 0, 0,0x3830, 0,
+ 0, 0, 0, 0, 0,0x6F2A, 0,0x3E61,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3379, 0, 0,
+ 0, 0, 0, 0, 0,0x6F30, 0,0x3A3F,
+0x4179, 0, 0,0x444A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x333B, 0, 0, 0, 0,0x6F2E,0x6F2F,0x4443,
+ 0,0x6F2D, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6F31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6F37, 0, 0, 0,
+ 0,0x6F3A, 0, 0, 0, 0, 0, 0,
+ 0,0x6F39,0x452D, 0, 0, 0, 0,0x6F32,
+0x6F33,0x6F36, 0, 0, 0, 0,0x6F38, 0,
+ 0, 0,0x3640, 0, 0,0x6F3B,0x6F35, 0,
+ 0,0x6F34};
+
+/* page 46 0x9403-0x9481 */
+static uint16 tab_uni_jisx020846[]={
+0x6F3F, 0, 0, 0,0x6F40, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6F41, 0, 0,
+0x6F3E,0x6F3D, 0, 0, 0,0x3E62,0x462A,0x6F3C,
+ 0, 0, 0, 0, 0, 0,0x6F45, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6F43, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6F44,0x6F42, 0,0x4278, 0,0x6F46,
+ 0, 0, 0, 0, 0, 0,0x6F47, 0,
+ 0,0x6F49, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3455,0x6F48,
+0x4C7A, 0, 0, 0, 0, 0, 0,0x6F54,
+0x6F4A, 0, 0,0x6F4D, 0,0x6F4B, 0,0x6F4C,
+ 0, 0, 0, 0, 0, 0, 0,0x6F4E,
+ 0, 0, 0, 0, 0,0x6F50, 0, 0,
+ 0, 0,0x6F51, 0,0x6F52, 0, 0, 0,
+ 0,0x6F55,0x6F53,0x6F56,0x6F58, 0,0x6F57};
+
+/* page 47 0x9577-0x95E5 */
+static uint16 tab_uni_jisx020847[]={
+0x4439, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4C67, 0,0x6F59,0x412E, 0, 0, 0,
+0x6F5A, 0,0x4A44,0x6F5B,0x332B, 0, 0, 0,
+0x313C, 0,0x3457, 0,0x3456,0x6F5C, 0,0x6F5D,
+ 0,0x6F5E,0x6F5F, 0, 0, 0, 0, 0,
+ 0,0x6F60, 0,0x3458,0x3355,0x395E,0x4836, 0,
+0x6F62,0x6F61, 0, 0, 0, 0,0x6F63, 0,
+ 0, 0, 0,0x315C, 0, 0, 0, 0,
+ 0, 0,0x6F66, 0,0x6F65,0x6F64, 0,0x6F67,
+ 0, 0, 0, 0,0x6F6A, 0, 0, 0,
+0x3047, 0, 0,0x6F68, 0,0x6F6C,0x6F6B, 0,
+ 0, 0, 0, 0, 0,0x6F6E,0x6F6D,0x6F6F,
+ 0,0x462E, 0, 0, 0,0x6F70, 0, 0,
+ 0, 0,0x6F71,0x6F73, 0, 0,0x6F72};
+
+/* page 48 0x961C-0x9874 */
+static uint16 tab_uni_jisx020848[]={
+0x496C, 0, 0, 0, 0,0x6F74, 0, 0,
+ 0, 0, 0, 0,0x6F75, 0,0x3A65, 0,
+ 0, 0,0x6F76,0x6F77, 0, 0,0x4B49, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x414B,
+ 0, 0, 0,0x3024,0x424B, 0,0x6F78, 0,
+0x496D, 0, 0, 0, 0, 0, 0,0x6F7B,
+0x6F79,0x395F, 0,0x6F7A,0x3842, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4A45,
+0x6F7D,0x7021,0x6F7E,0x7022, 0, 0,0x3121,0x3F58,
+0x3D7C,0x3459,0x7023, 0, 0, 0,0x4766, 0,
+0x7025, 0, 0, 0,0x3122, 0,0x7024,0x4444,
+ 0,0x4E4D,0x462B,0x6F7C,0x4E26, 0,0x3831, 0,
+ 0,0x4D5B, 0, 0, 0, 0, 0, 0,
+ 0,0x3679,0x4E34, 0,0x3728, 0,0x4262,0x6721,
+ 0,0x7026,0x332C,0x3F6F, 0, 0, 0, 0,
+0x3356,0x7028, 0,0x7029,0x7027,0x3764, 0,0x3A5D,
+0x3E63, 0, 0, 0,0x3123, 0, 0,0x4E59,
+ 0, 0, 0,0x702B,0x6E2E, 0,0x702A, 0,
+ 0, 0, 0, 0,0x702E,0x702C,0x702D, 0,
+0x702F, 0,0x7030,0x4E6C,0x7031,0x7032, 0,0x4049,
+0x483B, 0, 0, 0,0x3F7D,0x3467, 0, 0,
+0x4D3A,0x326D,0x3D38,0x385B, 0,0x7035, 0,0x7034,
+0x3B73,0x7036,0x7033, 0, 0,0x3B28, 0, 0,
+ 0,0x703A,0x6A2D, 0, 0,0x5256, 0,0x3F77,
+0x7038, 0, 0, 0, 0, 0,0x4E25,0x4671,
+ 0, 0, 0, 0,0x312B, 0,0x4063,0x3C36,
+ 0, 0, 0, 0,0x4A37, 0,0x3140, 0,
+ 0, 0,0x4E6D,0x4D6B, 0,0x703B, 0,0x4545,
+ 0, 0, 0, 0,0x3C7B, 0, 0, 0,
+0x703C, 0,0x703D,0x3F4C,0x703E, 0,0x4E6E, 0,
+ 0,0x7039,0x7040,0x7042, 0,0x7041, 0,0x703F,
+ 0, 0,0x7043, 0, 0,0x7044, 0, 0,
+0x417A, 0,0x3262, 0, 0, 0, 0, 0,
+0x7045, 0, 0,0x4C38, 0, 0,0x7046, 0,
+ 0, 0, 0, 0,0x7047, 0,0x4F2A, 0,
+ 0, 0, 0, 0,0x5B31,0x7048, 0, 0,
+ 0,0x7049,0x704A, 0, 0, 0,0x704E, 0,
+0x704B, 0,0x704C, 0,0x704D,0x704F, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4044, 0,
+ 0, 0,0x4C77, 0, 0,0x4045, 0, 0,
+0x7050, 0,0x4873, 0,0x7051,0x7353,0x4C4C, 0,
+0x7052, 0,0x7053, 0,0x7054,0x3357, 0,0x7056,
+ 0,0x3F59, 0, 0, 0,0x7057, 0, 0,
+0x3724, 0, 0, 0, 0,0x7058,0x705C, 0,
+0x705A, 0, 0, 0, 0,0x705B, 0, 0,
+0x3373,0x7059,0x705D, 0, 0, 0, 0,0x705E,
+ 0,0x3048, 0,0x705F,0x7060, 0, 0, 0,
+ 0, 0, 0, 0,0x3E64, 0, 0, 0,
+0x7061, 0, 0, 0,0x3547, 0, 0,0x7064,
+ 0, 0,0x7063, 0,0x7062, 0, 0,0x6B71,
+ 0,0x4A5C, 0, 0, 0, 0, 0,0x7065,
+0x7066, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x7067,
+ 0, 0,0x7068, 0,0x7069, 0, 0,0x706A,
+ 0, 0, 0, 0, 0, 0, 0,0x345A,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x706B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x706C,0x4723, 0, 0, 0,0x706E,0x323B,
+ 0,0x7071,0x7070, 0, 0, 0, 0,0x3124,
+ 0, 0, 0,0x3641, 0,0x4A47,0x443A,0x3A22,
+ 0,0x3960,0x3D67, 0,0x3F5C, 0, 0, 0,
+0x7073, 0, 0,0x7072,0x4D42,0x3468,0x4852,0x465C,
+ 0, 0, 0,0x3F7C,0x4E4E, 0,0x375B, 0,
+ 0, 0, 0, 0, 0,0x7076, 0, 0,
+0x7075, 0, 0, 0, 0, 0, 0, 0,
+0x4B4B,0x462C, 0, 0, 0, 0, 0, 0,
+0x3150, 0, 0,0x7077,0x7074, 0, 0,0x4951,
+0x4D6A,0x7078, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x7079, 0, 0, 0, 0,0x707B,
+0x426A,0x335B,0x335C,0x707A, 0, 0, 0, 0,
+0x3469,0x3832, 0, 0,0x346A, 0, 0,0x453F,
+ 0, 0,0x4E60, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x385C, 0, 0, 0,0x707C,
+ 0, 0, 0,0x707D,0x707E,0x7121, 0,0x7123,
+0x7122};
+
+/* page 49 0x98A8-0x98C6 */
+static uint16 tab_uni_jisx020849[]={
+0x4977, 0,0x7124, 0, 0, 0, 0,0x7125,
+ 0,0x7126, 0, 0, 0, 0,0x7127, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x7129,0x7128, 0,0x712A};
+
+/* page 50 0x98DB-0x9957 */
+static uint16 tab_uni_jisx020850[]={
+0x4874,0x664C, 0, 0,0x3F29, 0, 0,0x3532,
+ 0, 0, 0, 0, 0, 0,0x712B, 0,
+0x712C, 0,0x522C,0x5D3B,0x4853, 0, 0,0x307B,
+ 0,0x303B, 0, 0, 0, 0, 0, 0,
+ 0,0x3B74,0x4B30,0x3E7E, 0, 0, 0, 0,
+0x712D, 0,0x4C5F, 0, 0, 0,0x712E,0x4D5C,
+ 0,0x3142, 0, 0, 0,0x3B41, 0,0x712F,
+0x326E,0x7130, 0, 0, 0,0x7131, 0, 0,
+ 0, 0,0x7133,0x7134, 0,0x7136,0x7132, 0,
+ 0,0x7135, 0, 0, 0,0x345B, 0, 0,
+ 0,0x7137, 0,0x7138, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x7139,0x713A, 0, 0, 0,0x713B,
+ 0, 0,0x713D, 0, 0, 0,0x713C, 0,
+0x713F,0x7142, 0, 0, 0,0x713E,0x7140,0x7141,
+ 0, 0,0x7143, 0,0x3642};
+
+/* page 51 0x9996-0x9A6B */
+static uint16 tab_uni_jisx020851[]={
+0x3C73,0x7144,0x7145,0x3961, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x7146,
+ 0, 0,0x333E, 0, 0, 0,0x474F,0x7147,
+0x7148, 0, 0, 0, 0,0x435A,0x466B, 0,
+ 0, 0, 0, 0, 0, 0,0x7149, 0,
+ 0, 0, 0,0x477D, 0, 0,0x424C,0x3158,
+0x366E, 0,0x366F, 0, 0, 0, 0, 0,
+ 0, 0,0x4373,0x714E,0x3670, 0, 0,0x326F,
+ 0, 0,0x714D, 0, 0,0x714B, 0,0x714C,
+ 0,0x714A, 0, 0,0x7158, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x714F,
+0x7150, 0, 0,0x7151,0x7152, 0, 0, 0,
+ 0, 0,0x7154, 0, 0,0x7153, 0, 0,
+ 0,0x3D59, 0,0x7155, 0, 0, 0,0x7157,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3533,0x7156, 0, 0,0x417B,0x3833, 0, 0,
+ 0, 0, 0,0x7159, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x424D, 0, 0,0x715A, 0, 0,
+ 0, 0,0x462D, 0, 0, 0, 0, 0,
+ 0,0x715B, 0, 0, 0, 0, 0, 0,
+0x7160, 0,0x715E, 0,0x715D,0x715F, 0,0x715C,
+ 0, 0, 0, 0, 0, 0, 0,0x7162,
+ 0, 0, 0, 0, 0, 0, 0,0x7161,
+ 0,0x7164, 0, 0,0x3643,0x7163, 0, 0,
+ 0,0x7165, 0, 0,0x7166, 0,0x7168,0x7167,
+ 0, 0, 0,0x7169,0x716B,0x716A};
+
+/* page 52 0x9AA8-0x9B5A */
+static uint16 tab_uni_jisx020852[]={
+0x397C, 0, 0, 0, 0,0x716C, 0, 0,
+0x716D, 0, 0, 0, 0, 0, 0, 0,
+0x333C, 0, 0, 0,0x716E, 0, 0, 0,
+0x716F, 0, 0, 0,0x3F71, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x7170,
+ 0,0x7171, 0,0x7172,0x7173, 0, 0, 0,
+0x3962, 0, 0, 0, 0, 0,0x7174,0x7175,
+ 0, 0,0x7176,0x7177, 0, 0,0x7178, 0,
+ 0, 0,0x4831,0x717A, 0,0x4926,0x717B,0x7179,
+ 0,0x717D, 0, 0,0x717C, 0, 0,0x717E,
+ 0, 0, 0,0x7221, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x7222, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x7223, 0,0x7224, 0, 0, 0, 0,0x7225,
+ 0, 0,0x7226,0x7227, 0,0x7228, 0,0x7229,
+0x722A,0x722B,0x722C, 0, 0, 0,0x722D,0x722E,
+ 0,0x5D35,0x722F, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6478,0x3534, 0, 0, 0,
+ 0,0x3321,0x3A32,0x7231,0x7230,0x4C25, 0, 0,
+ 0, 0, 0, 0, 0,0x7233,0x7234,0x7232,
+ 0,0x7235, 0, 0,0x4B62, 0, 0, 0,
+0x7236, 0,0x357B};
+
+/* page 53 0x9B6F-0x9C78 */
+static uint16 tab_uni_jisx020853[]={
+0x4F25, 0, 0, 0, 0,0x7237, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x7239, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x303E,
+ 0, 0,0x723A,0x4A2B,0x7238, 0, 0,0x723B,
+0x723C, 0, 0, 0, 0, 0, 0, 0,
+0x723D,0x723E, 0, 0, 0, 0, 0, 0,
+ 0,0x723F, 0,0x4B6E,0x3B2D, 0,0x3A7A,0x412F,
+ 0, 0, 0, 0, 0,0x7240, 0, 0,
+ 0, 0,0x7243, 0, 0, 0, 0, 0,
+ 0,0x7241, 0, 0, 0, 0, 0,0x7244,
+ 0, 0,0x3871,0x7242, 0, 0, 0, 0,
+0x7245, 0,0x7246,0x7247, 0,0x724B, 0,0x3B2A,
+ 0, 0, 0, 0,0x4264, 0, 0, 0,
+ 0, 0,0x724C,0x7249,0x7248,0x724A, 0, 0,
+ 0,0x375F, 0, 0, 0, 0, 0, 0,
+ 0,0x7250,0x724F,0x724E, 0, 0,0x3033, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x725A, 0,0x7256,
+ 0,0x7257,0x7253,0x7259, 0,0x7255,0x3362, 0,
+ 0,0x4F4C, 0,0x7258,0x7254,0x7252,0x7251, 0,
+ 0, 0, 0, 0,0x725C, 0, 0, 0,
+ 0, 0,0x725F, 0, 0,0x725E,0x725D, 0,
+ 0, 0, 0, 0, 0, 0,0x4949,0x725B,
+0x3073,0x7260, 0,0x7262, 0, 0, 0, 0,
+ 0, 0,0x336F,0x724D,0x3137, 0, 0,0x7264,
+ 0, 0, 0, 0, 0, 0, 0,0x7263,
+0x7261,0x432D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x4B70, 0, 0, 0, 0,
+0x4E5A, 0, 0,0x7265, 0, 0, 0, 0,
+ 0,0x7266, 0, 0, 0, 0, 0, 0,
+0x7267, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x7268,
+ 0,0x7269};
+
+/* page 54 0x9CE5-0x9DFD */
+static uint16 tab_uni_jisx020854[]={
+0x443B, 0,0x726A, 0,0x4837, 0,0x726F,0x726B,
+ 0, 0, 0,0x726C, 0, 0,0x4B31,0x4C44,
+ 0,0x4650, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x7270, 0,
+ 0,0x7271,0x463E,0x726E,0x726D, 0, 0, 0,
+ 0,0x322A, 0, 0, 0,0x7279, 0, 0,
+0x7278, 0, 0, 0, 0, 0,0x3175, 0,
+ 0, 0,0x7276, 0, 0, 0,0x7275, 0,
+ 0,0x7273, 0,0x337B, 0,0x7272,0x3C32,0x3229,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3963, 0,
+ 0,0x727C,0x727B, 0,0x727A, 0, 0,0x7277,
+ 0,0x727D, 0,0x727E, 0, 0, 0, 0,
+ 0, 0, 0,0x7325,0x7324, 0, 0, 0,
+ 0, 0, 0, 0,0x7326, 0, 0,0x312D,
+0x7321,0x7322, 0,0x3974,0x4C39, 0, 0,0x7323,
+ 0, 0, 0, 0, 0, 0, 0,0x4B32,
+ 0, 0,0x732B, 0, 0,0x7327, 0, 0,
+ 0, 0, 0, 0, 0,0x732C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x7329, 0,0x7328, 0, 0, 0,
+ 0, 0,0x375C, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x732D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x732E,
+ 0, 0, 0, 0,0x732F, 0,0x732A, 0,
+ 0, 0,0x7274, 0, 0,0x7330, 0,0x4461,
+ 0, 0, 0,0x7334, 0,0x7335,0x7333, 0,
+ 0, 0, 0, 0,0x7332,0x7338, 0,0x7331,
+ 0,0x7336, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x7337, 0, 0, 0,0x733A, 0,
+ 0, 0, 0, 0,0x7339, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x733C, 0, 0, 0, 0, 0, 0,
+0x733D, 0,0x733E, 0, 0,0x4F49, 0, 0,
+ 0, 0, 0,0x733B,0x426B,0x3A6D, 0, 0,
+0x733F};
+
+/* page 55 0x9E1A-0x9E1E */
+static uint16 tab_uni_jisx020855[]={
+0x7340,0x7341, 0, 0,0x7342};
+
+/* page 56 0x9E75-0x9F77 */
+static uint16 tab_uni_jisx020856[]={
+0x7343, 0, 0,0x3834,0x7344, 0, 0, 0,
+0x7345, 0,0x3C2F, 0,0x7346, 0, 0, 0,
+ 0, 0, 0,0x7347, 0, 0,0x7348,0x7349,
+ 0, 0, 0, 0,0x734C,0x734A,0x4F3C, 0,
+0x734B, 0,0x4E6F, 0, 0, 0, 0, 0,
+0x734D, 0,0x4E5B, 0, 0, 0, 0, 0,
+0x734E,0x477E, 0, 0,0x734F,0x7351, 0, 0,
+0x7352, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x7350,0x396D,0x4C4D,0x4B63,0x5677,
+ 0,0x5D60,0x4B7B, 0, 0, 0, 0,0x322B,
+ 0, 0, 0, 0, 0, 0, 0,0x7354,
+0x3550,0x7355,0x7356,0x7357, 0,0x3975, 0,0x7358,
+ 0, 0, 0,0x6054,0x4C5B, 0,0x4263,0x7359,
+0x735B,0x735A, 0,0x735C, 0, 0, 0, 0,
+0x735D, 0, 0,0x735E, 0, 0, 0, 0,
+ 0, 0,0x735F, 0, 0, 0, 0,0x7360,
+ 0,0x7361,0x7362, 0,0x7363, 0,0x7364,0x7365,
+0x7366, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x7367,0x7368, 0, 0, 0, 0,
+ 0,0x4524, 0, 0, 0, 0,0x385D, 0,
+0x736A, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x414D,0x736B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x736C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4921, 0,
+ 0,0x736D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x736E,0x6337, 0,
+ 0,0x6C5A,0x706D, 0, 0,0x736F, 0,0x7370,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x7372,0x7373,0x7374,0x4E70,0x7371, 0,
+ 0,0x7375,0x7376, 0, 0,0x7378, 0,0x7377,
+ 0, 0, 0, 0, 0,0x737A, 0, 0,
+ 0,0x737B,0x7379};
+
+/* page 57 0x9F8D-0x9FA0 */
+static uint16 tab_uni_jisx020857[]={
+0x4E36, 0, 0, 0, 0, 0, 0, 0,
+0x737C, 0, 0, 0, 0, 0, 0,0x737D,
+0x6354, 0, 0,0x737E};
+
+/* page 58 0xFF01-0xFF5E */
+static uint16 tab_uni_jisx020858[]={
+0x212A, 0,0x2174,0x2170,0x2173,0x2175, 0,0x214A,
+0x214B,0x2176,0x215C,0x2124,0x215D,0x2125,0x213F,0x2330,
+0x2331,0x2332,0x2333,0x2334,0x2335,0x2336,0x2337,0x2338,
+0x2339,0x2127,0x2128,0x2163,0x2161,0x2164,0x2129,0x2177,
+0x2341,0x2342,0x2343,0x2344,0x2345,0x2346,0x2347,0x2348,
+0x2349,0x234A,0x234B,0x234C,0x234D,0x234E,0x234F,0x2350,
+0x2351,0x2352,0x2353,0x2354,0x2355,0x2356,0x2357,0x2358,
+0x2359,0x235A,0x214E,0x2140,0x214F,0x2130,0x2132,0x212E,
+0x2361,0x2362,0x2363,0x2364,0x2365,0x2366,0x2367,0x2368,
+0x2369,0x236A,0x236B,0x236C,0x236D,0x236E,0x236F,0x2370,
+0x2371,0x2372,0x2373,0x2374,0x2375,0x2376,0x2377,0x2378,
+0x2379,0x237A,0x2150,0x2143,0x2151,0x2141};
+
+/* page 59 0xFFE0-0xFFE5 */
+static uint16 tab_uni_jisx020859[]={
+0x2171,0x2172,0x224C,0x2131, 0,0x216F};
+
+static int
+my_uni_jisx0208_onechar(int code){
+ if ((code>=0x005C)&&(code<=0x005C))
+ return(tab_uni_jisx02080[code-0x005C]);
+ if ((code>=0x00A2)&&(code<=0x00B6))
+ return(tab_uni_jisx02081[code-0x00A2]);
+ if ((code>=0x00D7)&&(code<=0x00D7))
+ return(tab_uni_jisx02082[code-0x00D7]);
+ if ((code>=0x00F7)&&(code<=0x00F7))
+ return(tab_uni_jisx02083[code-0x00F7]);
+ if ((code>=0x0391)&&(code<=0x03C9))
+ return(tab_uni_jisx02084[code-0x0391]);
+ if ((code>=0x0401)&&(code<=0x0451))
+ return(tab_uni_jisx02085[code-0x0401]);
+ if ((code>=0x2010)&&(code<=0x203B))
+ return(tab_uni_jisx02086[code-0x2010]);
+ if ((code>=0x2100)&&(code<=0x2116))
+ return(tab_uni_jisx02087[code-0x2100]);
+ if ((code>=0x2120)&&(code<=0x212B))
+ return(tab_uni_jisx02088[code-0x2120]);
+ if ((code>=0x2160)&&(code<=0x2169))
+ return(tab_uni_jisx02089[code-0x2160]);
+ if ((code>=0x2190)&&(code<=0x2193))
+ return(tab_uni_jisx020810[code-0x2190]);
+ if ((code>=0x21D2)&&(code<=0x21D4))
+ return(tab_uni_jisx020811[code-0x21D2]);
+ if ((code>=0x2200)&&(code<=0x223D))
+ return(tab_uni_jisx020812[code-0x2200]);
+ if ((code>=0x2252)&&(code<=0x226B))
+ return(tab_uni_jisx020813[code-0x2252]);
+ if ((code>=0x2282)&&(code<=0x2287))
+ return(tab_uni_jisx020814[code-0x2282]);
+ if ((code>=0x22A0)&&(code<=0x22BF))
+ return(tab_uni_jisx020815[code-0x22A0]);
+ if ((code>=0x2312)&&(code<=0x2312))
+ return(tab_uni_jisx020816[code-0x2312]);
+ if ((code>=0x2460)&&(code<=0x2473))
+ return(tab_uni_jisx020817[code-0x2460]);
+ if ((code>=0x2500)&&(code<=0x254B))
+ return(tab_uni_jisx020818[code-0x2500]);
+ if ((code>=0x25A0)&&(code<=0x25CF))
+ return(tab_uni_jisx020819[code-0x25A0]);
+ if ((code>=0x25EF)&&(code<=0x25EF))
+ return(tab_uni_jisx020820[code-0x25EF]);
+ if ((code>=0x2605)&&(code<=0x2606))
+ return(tab_uni_jisx020821[code-0x2605]);
+ if ((code>=0x2640)&&(code<=0x2642))
+ return(tab_uni_jisx020822[code-0x2640]);
+ if ((code>=0x266A)&&(code<=0x266F))
+ return(tab_uni_jisx020823[code-0x266A]);
+ if ((code>=0x3000)&&(code<=0x301F))
+ return(tab_uni_jisx020824[code-0x3000]);
+ if ((code>=0x3041)&&(code<=0x30FE))
+ return(tab_uni_jisx020825[code-0x3041]);
+ if ((code>=0x3230)&&(code<=0x3239))
+ return(tab_uni_jisx020826[code-0x3230]);
+ if ((code>=0x32A0)&&(code<=0x32A8))
+ return(tab_uni_jisx020827[code-0x32A0]);
+ if ((code>=0x3300)&&(code<=0x33CD))
+ return(tab_uni_jisx020828[code-0x3300]);
+ if ((code>=0x4E00)&&(code<=0x5516))
+ return(tab_uni_jisx020829[code-0x4E00]);
+ if ((code>=0x552E)&&(code<=0x5563))
+ return(tab_uni_jisx020830[code-0x552E]);
+ if ((code>=0x557B)&&(code<=0x576A))
+ return(tab_uni_jisx020831[code-0x557B]);
+ if ((code>=0x577F)&&(code<=0x5A9B))
+ return(tab_uni_jisx020832[code-0x577F]);
+ if ((code>=0x5ABC)&&(code<=0x5D29))
+ return(tab_uni_jisx020833[code-0x5ABC]);
+ if ((code>=0x5D4B)&&(code<=0x6BF3))
+ return(tab_uni_jisx020834[code-0x5D4B]);
+ if ((code>=0x6C08)&&(code<=0x6CF3))
+ return(tab_uni_jisx020835[code-0x6C08]);
+ if ((code>=0x6D0B)&&(code<=0x7409))
+ return(tab_uni_jisx020836[code-0x6D0B]);
+ if ((code>=0x7422)&&(code<=0x7845))
+ return(tab_uni_jisx020837[code-0x7422]);
+ if ((code>=0x785D)&&(code<=0x7E9C))
+ return(tab_uni_jisx020838[code-0x785D]);
+ if ((code>=0x7F36)&&(code<=0x8358))
+ return(tab_uni_jisx020839[code-0x7F36]);
+ if ((code>=0x8373)&&(code<=0x8B9A))
+ return(tab_uni_jisx020840[code-0x8373]);
+ if ((code>=0x8C37)&&(code<=0x8D16))
+ return(tab_uni_jisx020841[code-0x8C37]);
+ if ((code>=0x8D64)&&(code<=0x8F64))
+ return(tab_uni_jisx020842[code-0x8D64]);
+ if ((code>=0x8F9B)&&(code<=0x9132))
+ return(tab_uni_jisx020843[code-0x8F9B]);
+ if ((code>=0x9149)&&(code<=0x92B9))
+ return(tab_uni_jisx020844[code-0x9149]);
+ if ((code>=0x92CF)&&(code<=0x93E8))
+ return(tab_uni_jisx020845[code-0x92CF]);
+ if ((code>=0x9403)&&(code<=0x9481))
+ return(tab_uni_jisx020846[code-0x9403]);
+ if ((code>=0x9577)&&(code<=0x95E5))
+ return(tab_uni_jisx020847[code-0x9577]);
+ if ((code>=0x961C)&&(code<=0x9874))
+ return(tab_uni_jisx020848[code-0x961C]);
+ if ((code>=0x98A8)&&(code<=0x98C6))
+ return(tab_uni_jisx020849[code-0x98A8]);
+ if ((code>=0x98DB)&&(code<=0x9957))
+ return(tab_uni_jisx020850[code-0x98DB]);
+ if ((code>=0x9996)&&(code<=0x9A6B))
+ return(tab_uni_jisx020851[code-0x9996]);
+ if ((code>=0x9AA8)&&(code<=0x9B5A))
+ return(tab_uni_jisx020852[code-0x9AA8]);
+ if ((code>=0x9B6F)&&(code<=0x9C78))
+ return(tab_uni_jisx020853[code-0x9B6F]);
+ if ((code>=0x9CE5)&&(code<=0x9DFD))
+ return(tab_uni_jisx020854[code-0x9CE5]);
+ if ((code>=0x9E1A)&&(code<=0x9E1E))
+ return(tab_uni_jisx020855[code-0x9E1A]);
+ if ((code>=0x9E75)&&(code<=0x9F77))
+ return(tab_uni_jisx020856[code-0x9E75]);
+ if ((code>=0x9F8D)&&(code<=0x9FA0))
+ return(tab_uni_jisx020857[code-0x9F8D]);
+ if ((code>=0xFF01)&&(code<=0xFF5E))
+ return(tab_uni_jisx020858[code-0xFF01]);
+ if ((code>=0xFFE0)&&(code<=0xFFE5))
+ return(tab_uni_jisx020859[code-0xFFE0]);
+ return(0);
+}
+
+
+/* page 0 0x007E-0x007E */
+static uint16 tab_uni_jisx02120[]={
+ 0};
+
+/* page 1 0x00A1-0x017E */
+static uint16 tab_uni_jisx02121[]={
+0x2242, 0, 0,0x2270, 0, 0, 0, 0,
+0x226D,0x226C, 0, 0, 0,0x226E,0x2234, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x2231,
+ 0,0x226B, 0, 0, 0, 0,0x2244,0x2A22,
+0x2A21,0x2A24,0x2A2A,0x2A23,0x2A29,0x2921,0x2A2E,0x2A32,
+0x2A31,0x2A34,0x2A33,0x2A40,0x2A3F,0x2A42,0x2A41, 0,
+0x2A50,0x2A52,0x2A51,0x2A54,0x2A58,0x2A53, 0,0x292C,
+0x2A63,0x2A62,0x2A65,0x2A64,0x2A72,0x2930,0x294E,0x2B22,
+0x2B21,0x2B24,0x2B2A,0x2B23,0x2B29,0x2941,0x2B2E,0x2B32,
+0x2B31,0x2B34,0x2B33,0x2B40,0x2B3F,0x2B42,0x2B41,0x2943,
+0x2B50,0x2B52,0x2B51,0x2B54,0x2B58,0x2B53, 0,0x294C,
+0x2B63,0x2B62,0x2B65,0x2B64,0x2B72,0x2950,0x2B73,0x2A27,
+0x2B27,0x2A25,0x2B25,0x2A28,0x2B28,0x2A2B,0x2B2B,0x2A2C,
+0x2B2C,0x2A2F,0x2B2F,0x2A2D,0x2B2D,0x2A30,0x2B30,0x2922,
+0x2942,0x2A37,0x2B37, 0, 0,0x2A36,0x2B36,0x2A38,
+0x2B38,0x2A35,0x2B35,0x2A3A,0x2B3A,0x2A3B,0x2B3B,0x2A3D,
+0x2B3D,0x2A3C, 0,0x2A3E,0x2B3E,0x2924,0x2944,0x2A47,
+0x2B47,0x2A45,0x2B45, 0, 0,0x2A46,0x2B46,0x2A44,
+0x2945,0x2926,0x2946,0x2A48,0x2B48,0x2A49,0x2B49,0x2947,
+0x2A4A,0x2B4A,0x2A4C,0x2B4C,0x2A4B,0x2B4B,0x2929,0x2949,
+0x2928,0x2948,0x2A4D,0x2B4D,0x2A4F,0x2B4F,0x2A4E,0x2B4E,
+0x294A,0x292B,0x294B,0x2A57,0x2B57, 0, 0,0x2A56,
+0x2B56,0x292D,0x294D,0x2A59,0x2B59,0x2A5B,0x2B5B,0x2A5A,
+0x2B5A,0x2A5C,0x2B5C,0x2A5D,0x2B5D,0x2A5F,0x2B5F,0x2A5E,
+0x2B5E,0x2A61,0x2B61,0x2A60,0x2B60,0x292F,0x294F,0x2A6C,
+0x2B6C,0x2A69,0x2B69,0x2A66,0x2B66,0x2A6B,0x2B6B,0x2A68,
+0x2B68,0x2A6A,0x2B6A,0x2A71,0x2B71,0x2A74,0x2B74,0x2A73,
+0x2A75,0x2B75,0x2A77,0x2B77,0x2A76,0x2B76};
+
+/* page 2 0x01CD-0x01DC */
+static uint16 tab_uni_jisx02122[]={
+0x2A26,0x2B26,0x2A43,0x2B43,0x2A55,0x2B55,0x2A67,0x2B67,
+0x2A70,0x2B70,0x2A6D,0x2B6D,0x2A6F,0x2B6F,0x2A6E,0x2B6E
+};
+
+/* page 3 0x01F5-0x01F5 */
+static uint16 tab_uni_jisx02123[]={
+0x2B39};
+
+/* page 4 0x02C7-0x02DD */
+static uint16 tab_uni_jisx02124[]={
+0x2230, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x222F,0x2232,0x2236,0x2235, 0,0x2233};
+
+/* page 5 0x0384-0x0390 */
+static uint16 tab_uni_jisx02125[]={
+0x2238,0x2239,0x2661, 0,0x2662,0x2663,0x2664, 0,
+0x2667, 0,0x2669,0x266C,0x2676};
+
+/* page 6 0x03AA-0x03CE */
+static uint16 tab_uni_jisx02126[]={
+0x2665,0x266A,0x2671,0x2672,0x2673,0x2674,0x267B, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x2678, 0, 0, 0, 0, 0, 0, 0,
+0x2675,0x267A,0x2677,0x2679,0x267C};
+
+/* page 7 0x0402-0x040F */
+static uint16 tab_uni_jisx02127[]={
+0x2742,0x2743,0x2744,0x2745,0x2746,0x2747,0x2748,0x2749,
+0x274A,0x274B,0x274C, 0,0x274D,0x274E};
+
+/* page 8 0x0452-0x045F */
+static uint16 tab_uni_jisx02128[]={
+0x2772,0x2773,0x2774,0x2775,0x2776,0x2777,0x2778,0x2779,
+0x277A,0x277B,0x277C, 0,0x277D,0x277E};
+
+/* page 9 0x2122-0x2122 */
+static uint16 tab_uni_jisx02129[]={
+0x226F};
+
+/* page 10 0x2170-0x2179 */
+static uint16 tab_uni_jisx021210[]={
+0x7373,0x7374,0x7375,0x7376,0x7377,0x7378,0x7379,0x737A,
+0x737B,0x737C};
+
+/* page 11 0x4E02-0x4F19 */
+static uint16 tab_uni_jisx021211[]={
+0x3021, 0,0x3022,0x3023, 0, 0, 0, 0,
+ 0, 0,0x3024, 0, 0, 0, 0, 0,
+0x3025, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3026, 0, 0,
+ 0,0x3027,0x3028, 0, 0, 0,0x3029, 0,
+ 0,0x302A, 0, 0,0x302B,0x302C,0x302D, 0,
+ 0, 0, 0,0x302E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x302F,0x3030,
+ 0, 0,0x3031, 0, 0,0x3032, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3033,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3034, 0,0x3035, 0, 0, 0, 0, 0,
+ 0,0x3036, 0, 0, 0, 0,0x3037,0x3038,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3039,0x303A, 0, 0, 0,0x303B,
+ 0, 0, 0, 0, 0,0x303C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x303D, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x303E,0x303F, 0, 0,
+ 0, 0, 0,0x3040, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3041, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3042,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3043, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3044, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3045,0x3046, 0, 0, 0, 0,0x3047,0x3048,
+0x3049, 0, 0, 0, 0, 0,0x304A, 0,
+ 0, 0, 0, 0, 0,0x304B, 0,0x304C,
+ 0,0x304D, 0,0x304E, 0, 0, 0, 0,
+ 0, 0,0x742F,0x304F,0x3050,0x3051,0x3052, 0,
+0x3053,0x3054, 0, 0, 0, 0,0x3055, 0,
+ 0,0x3056,0x3057, 0, 0, 0, 0, 0,
+0x3058, 0, 0,0x3059,0x305A,0x305B, 0,0x305C
+};
+
+/* page 12 0x4F2E-0x5166 */
+static uint16 tab_uni_jisx021212[]={
+0x305D, 0, 0,0x305E, 0,0x3060, 0,0x3061,
+ 0,0x3062, 0,0x3063, 0,0x3064, 0, 0,
+0x3065, 0,0x3066, 0,0x3067, 0, 0, 0,
+ 0, 0,0x3068,0x3069, 0,0x306A,0x306B, 0,
+ 0, 0, 0, 0,0x306C, 0,0x306D, 0,
+0x306E, 0,0x306F, 0, 0, 0, 0, 0,
+ 0,0x3070,0x305F, 0, 0,0x3071, 0, 0,
+ 0, 0, 0, 0,0x3072, 0,0x3073, 0,
+0x3074, 0, 0,0x3075, 0, 0, 0, 0,
+ 0,0x3076,0x3077,0x3078,0x3079, 0, 0,0x307A,
+0x307B, 0, 0,0x307C,0x307D, 0,0x307E,0x3121,
+ 0, 0, 0,0x3122,0x3123, 0,0x3124, 0,
+0x3125, 0,0x3126, 0,0x3127,0x3128,0x3129, 0,
+ 0,0x312A, 0,0x312B,0x312C, 0, 0, 0,
+0x312D,0x312E, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x312F, 0, 0, 0,
+ 0,0x3130, 0,0x3131, 0,0x3132,0x3133,0x3134,
+0x3135, 0,0x3136,0x3137, 0, 0, 0,0x3138,
+0x3139, 0,0x313A,0x313B, 0,0x313C,0x313D,0x313E,
+ 0,0x313F, 0, 0,0x3140, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3141, 0,
+ 0, 0,0x3142, 0,0x3143, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3144, 0,0x3145, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3146,0x3147,
+ 0,0x3148,0x3149,0x314A, 0, 0,0x314B, 0,
+ 0,0x314C, 0, 0,0x314D, 0,0x314E, 0,
+0x314F, 0,0x3150, 0, 0,0x3151, 0, 0,
+ 0,0x3152,0x3153, 0, 0,0x3154,0x3155,0x3156,
+0x3157, 0, 0, 0,0x3158, 0, 0, 0,
+ 0,0x3159, 0, 0, 0, 0, 0, 0,
+0x315A, 0,0x315B, 0,0x315C,0x315D, 0,0x315E,
+ 0, 0, 0, 0, 0,0x3176, 0, 0,
+ 0, 0,0x315F,0x3160,0x3161, 0, 0,0x3162,
+0x3163, 0, 0, 0,0x3164, 0,0x3165, 0,
+0x3166, 0, 0,0x3167,0x3168,0x3169, 0, 0,
+ 0,0x316A, 0,0x316B, 0, 0, 0, 0,
+ 0,0x316C,0x316D, 0,0x316E,0x316F, 0, 0,
+0x3170,0x3171, 0, 0,0x3172, 0, 0,0x3173,
+ 0, 0,0x3174,0x3175, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3177, 0,0x3178,0x3179, 0,
+0x317A, 0, 0, 0,0x317B, 0, 0, 0,
+0x317C,0x317D,0x317E, 0,0x3221,0x3222,0x3223, 0,
+0x3224, 0, 0, 0, 0,0x3225,0x3226, 0,
+0x3227,0x3228,0x3229,0x322A,0x322B, 0, 0, 0,
+ 0, 0, 0, 0,0x322C, 0, 0, 0,
+ 0,0x322D,0x322E, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x322F,0x3230, 0, 0,0x3231,
+ 0, 0,0x3232, 0, 0,0x3233,0x3234, 0,
+ 0,0x3235, 0, 0, 0, 0,0x3236, 0,
+0x3237, 0,0x3238, 0, 0,0x3239,0x323A, 0,
+ 0, 0,0x323B, 0, 0, 0,0x323C,0x323D,
+ 0,0x323E, 0, 0,0x323F, 0,0x3240, 0,
+0x3241, 0,0x3242,0x3243, 0, 0, 0, 0,
+ 0,0x3244, 0,0x3245,0x3251, 0,0x7430, 0,
+0x3246, 0, 0, 0,0x3247, 0, 0, 0,
+0x3248, 0, 0, 0, 0,0x3249, 0, 0,
+0x324A,0x324B,0x324C, 0, 0,0x324D,0x324E,0x324F,
+0x3250, 0,0x3252, 0, 0, 0, 0, 0,
+ 0,0x3253, 0,0x3254, 0,0x3255,0x3256,0x3257,
+0x3258, 0, 0, 0, 0,0x3259, 0, 0,
+ 0,0x325A,0x325B, 0, 0, 0,0x325C,0x325D,
+ 0,0x325E, 0,0x325F, 0,0x3260,0x3261,0x3262,
+ 0, 0,0x3263,0x3264, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3265, 0, 0, 0,
+ 0, 0, 0, 0,0x3266, 0, 0, 0,
+ 0,0x3267, 0, 0, 0,0x3268, 0,0x3269,
+ 0,0x326A,0x326B, 0, 0, 0, 0, 0,
+ 0,0x326C, 0, 0, 0, 0,0x326D, 0,
+0x326E};
+
+/* page 13 0x517E-0x5515 */
+static uint16 tab_uni_jisx021213[]={
+0x326F, 0, 0, 0, 0,0x3270,0x3271, 0,
+ 0, 0, 0, 0, 0,0x3272, 0, 0,
+0x3273, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3274, 0, 0, 0, 0,0x3275,
+ 0, 0, 0,0x3276, 0,0x3277, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3278,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3279, 0,0x327A, 0,0x327B, 0,
+0x327C,0x327D, 0, 0,0x327E, 0, 0, 0,
+ 0, 0,0x3321, 0, 0, 0, 0, 0,
+ 0,0x3322, 0,0x3323,0x3324,0x3325, 0,0x3326,
+ 0, 0,0x3327, 0, 0, 0, 0, 0,
+0x3328, 0, 0, 0,0x3329, 0, 0,0x332A,
+ 0, 0, 0, 0, 0, 0,0x7431, 0,
+0x332B, 0, 0, 0,0x332C,0x332D,0x332E, 0,
+ 0,0x332F, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3330,0x3331, 0, 0,0x3332,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3333,0x3334, 0,0x3335,
+0x3336, 0,0x3337, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3338, 0, 0, 0,
+ 0, 0,0x3339, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x333A,0x333B, 0, 0,0x333C,
+ 0, 0, 0, 0, 0, 0,0x333D, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x333E,
+ 0, 0, 0,0x333F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3340,
+ 0,0x3341,0x3342, 0,0x3343, 0,0x3344, 0,
+ 0,0x3345,0x3346,0x3347, 0, 0, 0, 0,
+0x3348, 0, 0, 0, 0, 0, 0, 0,
+0x3349, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x334A,0x334B,0x334C, 0, 0, 0, 0,
+ 0, 0,0x334D, 0,0x334E, 0, 0,0x334F,
+ 0, 0, 0, 0,0x3350, 0,0x3351, 0,
+ 0, 0, 0, 0, 0,0x3352, 0,0x3353,
+0x3354,0x3355,0x3356, 0,0x3357, 0,0x3358, 0,
+ 0, 0, 0, 0, 0, 0,0x3359,0x335A,
+0x335B,0x335C, 0, 0, 0, 0, 0, 0,
+ 0,0x335D,0x335E, 0, 0, 0, 0, 0,
+0x335F,0x3360,0x3361, 0,0x3362,0x3363, 0,0x3364,
+ 0, 0,0x3365, 0, 0, 0,0x3366, 0,
+0x3367, 0,0x3368, 0, 0, 0,0x3369, 0,
+ 0,0x336A, 0,0x336B, 0, 0,0x336C, 0,
+0x336D, 0, 0, 0, 0,0x336E,0x336F, 0,
+ 0, 0, 0,0x3370, 0, 0, 0,0x3371,
+ 0, 0,0x3372,0x3373,0x3374, 0,0x3375, 0,
+ 0, 0,0x3376,0x3377, 0, 0,0x3378, 0,
+0x3379,0x337A, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x337B, 0, 0,0x337C, 0, 0,
+ 0,0x7432, 0, 0,0x337D,0x337E,0x3421, 0,
+ 0, 0, 0,0x3422, 0,0x3423, 0, 0,
+ 0, 0,0x3424, 0, 0,0x3425,0x3426, 0,
+0x3427,0x3428, 0, 0, 0, 0,0x7433,0x3429,
+ 0,0x342A,0x342B,0x342C, 0,0x342D,0x342E,0x342F,
+ 0, 0,0x3430, 0,0x3431, 0, 0,0x3432,
+ 0, 0, 0, 0, 0, 0,0x3433,0x3434,
+0x3435, 0, 0, 0,0x3436, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3438,0x3437, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3439, 0,0x343A, 0, 0,
+ 0, 0, 0,0x343B, 0,0x343C, 0,0x343D,
+ 0, 0, 0, 0, 0, 0,0x343E,0x343F,
+ 0, 0, 0, 0,0x3440, 0, 0, 0,
+ 0, 0, 0,0x3441, 0, 0, 0, 0,
+0x3442, 0, 0, 0, 0,0x3443, 0, 0,
+ 0,0x3444,0x3445, 0, 0, 0, 0, 0,
+0x3446, 0, 0, 0, 0,0x3447,0x3448, 0,
+ 0, 0, 0,0x3449, 0, 0, 0,0x344A,
+ 0, 0, 0,0x344B, 0, 0,0x344C, 0,
+ 0, 0, 0, 0,0x344D,0x344E, 0, 0,
+ 0,0x344F, 0, 0,0x3450, 0,0x3451,0x3452,
+ 0,0x3453,0x3454, 0,0x3455, 0, 0,0x3456,
+ 0, 0,0x3457, 0, 0, 0, 0,0x3458,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3459, 0, 0,0x345A,0x345B, 0,0x345C,
+ 0, 0, 0, 0,0x345D, 0, 0,0x345E,
+0x345F, 0,0x3460, 0, 0, 0, 0, 0,
+0x3461,0x3462, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3463,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3464, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3465, 0, 0,
+ 0, 0, 0, 0,0x3466, 0, 0, 0,
+ 0, 0, 0,0x3467, 0, 0, 0, 0,
+ 0,0x3468,0x3469, 0,0x346A, 0, 0, 0,
+ 0,0x346B, 0,0x346C, 0, 0,0x346D,0x346E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x346F,0x3470, 0,
+ 0,0x3471, 0, 0, 0, 0, 0,0x3472,
+ 0,0x3473, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3474, 0, 0, 0,0x3475, 0,0x3476, 0,
+0x3477,0x3478, 0,0x3479, 0,0x347A, 0,0x347B,
+0x347C, 0, 0, 0, 0, 0,0x347D, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x347E, 0,0x3521, 0,0x3522, 0,0x3523,
+ 0, 0,0x3524,0x3525,0x7435, 0, 0,0x3526,
+ 0, 0, 0,0x3527, 0, 0, 0,0x3528,
+0x3529, 0, 0, 0, 0, 0,0x352A, 0,
+ 0,0x352B, 0,0x352C, 0, 0, 0, 0,
+0x352D,0x352E, 0,0x352F,0x3530, 0, 0,0x3531,
+0x3532, 0, 0,0x3533, 0, 0, 0, 0,
+ 0,0x3534, 0,0x3535,0x3536,0x3537, 0, 0,
+ 0,0x3538, 0, 0, 0, 0, 0, 0,
+0x3539, 0, 0, 0,0x353A, 0, 0,0x353B,
+0x353C, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x353D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x353E, 0,0x353F, 0,
+ 0,0x3540, 0, 0, 0, 0, 0, 0,
+0x3541, 0, 0, 0, 0, 0,0x3542, 0,
+0x3543,0x3544,0x3545,0x3546, 0, 0, 0,0x3547,
+ 0, 0,0x3548,0x3549, 0, 0,0x354A,0x354B,
+0x354C, 0, 0, 0, 0, 0, 0,0x354D
+};
+
+/* page 14 0x552A-0x5566 */
+static uint16 tab_uni_jisx021214[]={
+0x354E,0x354F, 0, 0, 0, 0, 0, 0,
+0x3550, 0, 0,0x3551,0x3552, 0, 0, 0,
+ 0,0x3553,0x3554,0x3555, 0, 0, 0,0x3556,
+ 0, 0, 0, 0, 0,0x3557, 0,0x3558,
+0x3559, 0, 0,0x355A, 0, 0,0x355B,0x355C,
+ 0, 0, 0, 0, 0, 0,0x355D, 0,
+0x355E,0x355F, 0, 0,0x3560, 0,0x3561,0x3562,
+ 0, 0,0x3563, 0,0x3564};
+
+/* page 15 0x557F-0x5C36 */
+static uint16 tab_uni_jisx021215[]={
+0x3565, 0,0x3566,0x3567, 0, 0, 0,0x3568,
+ 0,0x3569, 0, 0, 0, 0, 0,0x356A,
+0x356B, 0,0x356C,0x356D,0x356E,0x356F, 0, 0,
+0x3570, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3571,0x3572, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3573, 0,
+ 0, 0, 0,0x3574, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3575, 0,0x3576, 0,0x3577, 0, 0,0x3578,
+ 0, 0,0x3579, 0,0x357A,0x357B, 0,0x357C,
+ 0, 0,0x357D,0x357E,0x3621, 0, 0, 0,
+0x3622,0x3623, 0, 0,0x3624, 0, 0,0x3625,
+ 0, 0, 0,0x3626, 0, 0, 0, 0,
+ 0, 0,0x3627, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3628,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3629, 0, 0, 0, 0, 0,0x362A, 0,
+ 0,0x362B, 0,0x362C, 0, 0,0x362D,0x362E,
+0x362F,0x3630,0x3631,0x3632, 0, 0, 0, 0,
+ 0, 0,0x3633, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3634, 0, 0,
+ 0,0x3635, 0, 0,0x3636, 0,0x3637, 0,
+0x3638, 0,0x3639, 0,0x363A,0x363B,0x363C, 0,
+0x363D,0x363E,0x363F, 0,0x3640,0x3641, 0,0x3642,
+ 0, 0,0x3643, 0,0x3644, 0,0x3645, 0,
+0x3646, 0, 0, 0, 0,0x3647, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3648,
+ 0,0x3649,0x364A,0x364B,0x364C, 0, 0,0x364D,
+ 0, 0,0x364E, 0, 0, 0,0x364F, 0,
+0x3650, 0,0x3651,0x3652, 0, 0,0x3653, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3654,0x3655, 0,
+ 0,0x3656, 0, 0,0x3657,0x3658, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3659, 0,
+ 0, 0,0x365A,0x365B, 0, 0,0x365C,0x365D,
+0x365E, 0, 0, 0, 0, 0, 0,0x365F,
+0x3660,0x3661,0x3662, 0,0x3663,0x3664,0x3665, 0,
+ 0, 0,0x3666, 0,0x3667, 0, 0, 0,
+0x3668, 0, 0, 0, 0, 0, 0,0x3669,
+ 0, 0, 0, 0, 0, 0,0x366A, 0,
+ 0, 0,0x366B,0x366C,0x366D,0x3670,0x3671, 0,
+0x366E,0x366F, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3672, 0, 0,0x3673,0x3674, 0,
+0x3675, 0,0x3676, 0, 0,0x3677,0x3678,0x3679,
+0x367A,0x367B, 0, 0,0x367D, 0,0x367E, 0,
+ 0, 0,0x367C, 0, 0, 0, 0,0x3721,
+0x3722, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3723,0x3724, 0, 0, 0, 0,
+0x3725, 0, 0,0x3726, 0,0x3727, 0, 0,
+ 0, 0,0x3728, 0, 0, 0,0x3729, 0,
+ 0, 0, 0,0x372A,0x372B, 0,0x372C, 0,
+ 0,0x372D, 0,0x372E,0x372F,0x3730,0x3731, 0,
+ 0, 0,0x3732,0x3733, 0,0x3734, 0,0x3735,
+0x3736, 0, 0, 0,0x3737,0x3738, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3739,0x373A,
+0x373B, 0, 0, 0, 0, 0,0x373C,0x373D,
+ 0, 0, 0, 0, 0,0x373E,0x373F, 0,
+ 0, 0, 0,0x3740, 0, 0, 0, 0,
+ 0, 0,0x7436, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3741, 0, 0,0x3742, 0,
+0x3743,0x3744, 0, 0,0x3745, 0,0x3746,0x3747,
+0x3748,0x3749,0x374A, 0,0x374B,0x374C,0x374D, 0,
+0x374E, 0,0x374F,0x3750,0x3751,0x3752, 0,0x3753,
+ 0, 0,0x3754, 0,0x3755, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3756, 0, 0,
+ 0, 0, 0, 0, 0,0x3757,0x3760, 0,
+0x3758, 0,0x3759,0x375A, 0,0x375B,0x375C,0x375D,
+0x375E, 0,0x375F, 0, 0, 0, 0, 0,
+0x3761,0x3762,0x3763, 0, 0,0x3764, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3765, 0, 0, 0, 0,0x3766, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3767,0x3768, 0, 0, 0,0x3769, 0, 0,
+0x376A, 0, 0, 0, 0, 0,0x376B, 0,
+ 0, 0, 0, 0, 0, 0,0x376C,0x376D,
+ 0, 0,0x377E, 0, 0,0x376E, 0,0x376F,
+0x3770, 0,0x3771, 0, 0, 0,0x3772, 0,
+ 0,0x3773, 0, 0, 0, 0,0x3774,0x3775,
+ 0,0x3776, 0, 0, 0, 0,0x3777,0x3778,
+0x3779, 0, 0, 0,0x377A,0x377B, 0, 0,
+ 0,0x377C,0x377D, 0, 0,0x3821,0x3822, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3823, 0, 0,0x3824,
+0x3825,0x3826, 0, 0, 0, 0, 0,0x3827,
+0x3828, 0, 0, 0, 0, 0,0x3829, 0,
+ 0, 0, 0,0x382A, 0, 0, 0, 0,
+ 0, 0,0x382B, 0, 0, 0, 0, 0,
+0x382C, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x382D, 0, 0,0x382E,0x382F, 0,
+0x3830,0x3831, 0, 0, 0, 0,0x3832, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3833, 0,0x3834, 0, 0,0x3835, 0, 0,
+0x3836,0x3837, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3838, 0, 0, 0,0x3839, 0, 0,
+0x383A,0x383B,0x383C, 0, 0, 0, 0, 0,
+0x383D,0x383E,0x383F,0x3840, 0,0x3841,0x3842, 0,
+0x3843,0x3844, 0, 0, 0,0x3845, 0,0x3846,
+ 0, 0, 0, 0, 0, 0,0x3847,0x7439,
+ 0,0x3848,0x3849,0x384A, 0, 0, 0,0x384B,
+ 0, 0,0x384C, 0, 0, 0, 0, 0,
+ 0, 0,0x384D,0x384E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3850, 0, 0,
+ 0, 0, 0,0x3851, 0,0x384F, 0, 0,
+ 0,0x3852, 0, 0, 0, 0,0x3853,0x3854,
+ 0,0x3855, 0,0x3856, 0,0x3857, 0,0x3858,
+ 0, 0, 0,0x3859, 0, 0,0x385A, 0,
+ 0, 0,0x385B,0x385C, 0, 0, 0, 0,
+ 0, 0,0x385D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x385E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x385F,0x3860,
+ 0, 0, 0, 0,0x3861,0x3862, 0, 0,
+ 0, 0, 0,0x3863,0x3864,0x3865, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3867, 0,
+ 0, 0,0x3868, 0,0x3869,0x386A, 0, 0,
+ 0,0x386B, 0, 0, 0, 0, 0, 0,
+0x386C,0x386D, 0, 0,0x386E, 0,0x386F,0x3870,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3871, 0, 0, 0,0x3872, 0, 0,0x3873,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3874,0x3875, 0, 0, 0,
+ 0, 0,0x3876, 0,0x3877, 0,0x3878,0x3879,
+0x387A, 0,0x387B, 0,0x387C, 0, 0, 0,
+ 0, 0, 0, 0,0x387D, 0,0x387E, 0,
+0x3921, 0, 0,0x3922, 0, 0,0x3923,0x3924,
+ 0, 0,0x3925, 0,0x3926,0x3927, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3928,0x3929, 0,0x392A,
+ 0, 0, 0,0x392B, 0, 0,0x392C, 0,
+0x392D, 0, 0, 0, 0, 0, 0, 0,
+0x392E, 0, 0, 0, 0,0x392F, 0, 0,
+0x3930, 0, 0, 0, 0, 0,0x3931,0x3932,
+0x3933,0x3934, 0, 0,0x3935, 0, 0, 0,
+0x3936, 0, 0,0x3937, 0,0x3938, 0, 0,
+ 0, 0,0x3939, 0,0x393A,0x393B, 0, 0,
+ 0,0x393C, 0,0x393D, 0, 0,0x393E, 0,
+ 0, 0, 0,0x393F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3940,0x3941,
+0x3942, 0, 0, 0,0x3943,0x3944, 0, 0,
+0x3945, 0, 0, 0, 0, 0, 0,0x3946,
+0x3947, 0,0x3948,0x3949, 0,0x394A, 0, 0,
+0x394B, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x394C, 0, 0, 0,0x394D, 0, 0,
+ 0, 0, 0, 0, 0,0x394E,0x394F,0x3950,
+ 0, 0, 0,0x3951,0x3952, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3953,
+ 0, 0, 0, 0,0x3954,0x3955, 0, 0,
+0x3956,0x3957, 0,0x3958, 0, 0,0x3959, 0,
+ 0,0x395A, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x395B,0x395C, 0,
+0x395D,0x395E, 0, 0, 0,0x395F, 0, 0,
+ 0,0x3960, 0, 0, 0, 0,0x3961, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3962,
+ 0, 0, 0, 0,0x3963, 0,0x3964, 0,
+0x3965, 0, 0, 0, 0, 0,0x3966, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3967, 0, 0,0x3968,0x3969, 0, 0,0x396A,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x396B, 0, 0, 0,
+ 0,0x396C, 0, 0,0x396D, 0, 0,0x396E,
+ 0, 0,0x396F, 0, 0,0x3970, 0,0x3971,
+0x3972,0x3973, 0,0x3974, 0, 0, 0, 0,
+0x3975, 0, 0, 0, 0,0x3976, 0, 0,
+ 0, 0,0x3977,0x3978,0x3979, 0,0x397A, 0,
+ 0,0x397B, 0,0x397C,0x397D, 0, 0, 0,
+0x397E, 0, 0, 0, 0,0x3A21, 0,0x3A22,
+ 0,0x3A23, 0, 0, 0, 0, 0, 0,
+0x3A24, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3A25, 0,0x3A26, 0, 0,
+ 0,0x3A27, 0, 0, 0, 0,0x3A28, 0,
+ 0, 0, 0,0x3A29, 0, 0, 0,0x3A2A,
+ 0, 0, 0, 0, 0, 0,0x3A2B,0x3A2C,
+ 0, 0, 0, 0, 0, 0,0x3A2D, 0,
+ 0,0x3A2E,0x3A2F, 0, 0, 0, 0, 0,
+ 0,0x3A30, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3A31, 0,0x3A33, 0,0x3A34, 0,0x3A35, 0,
+ 0, 0,0x3A36, 0, 0, 0,0x3A37, 0,
+ 0, 0, 0, 0, 0, 0,0x3A38, 0,
+ 0, 0, 0, 0, 0,0x3A32, 0, 0,
+ 0,0x3A39, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3A3A, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3A3B,0x3A3C, 0, 0,
+ 0, 0, 0,0x3A3D, 0, 0, 0,0x3A3E,
+ 0, 0, 0, 0, 0, 0, 0,0x3A3F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3A40, 0, 0, 0, 0, 0,0x3A41,
+0x3A42, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3A43,0x3A44,0x3A45,
+0x3A46, 0,0x3A47, 0, 0,0x3A48, 0,0x3A49,
+ 0, 0, 0,0x3A4A, 0, 0, 0,0x3A4B,
+ 0,0x3A4C,0x3A4D, 0,0x3A4E,0x3A4F, 0,0x3A50,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3A51,0x3A52, 0, 0,0x3A53,0x3A54, 0,
+0x3A55, 0,0x3A56,0x3A57, 0, 0, 0, 0,
+0x3A58, 0, 0,0x3A59, 0,0x3A5A, 0, 0,
+ 0,0x3A5B,0x3A5C, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3A5D, 0,
+0x3A5E, 0, 0, 0, 0, 0, 0,0x3A5F,
+0x3A60,0x3A61,0x3A62,0x3A63, 0, 0, 0, 0,
+ 0,0x3A64, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x743A, 0, 0,
+0x3A65, 0,0x3A66, 0, 0,0x3A67, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3A68, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3A69, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3A6A, 0, 0, 0, 0, 0, 0,0x3A6B,
+0x3A6C, 0, 0, 0,0x3A6D, 0, 0,0x3A6E,
+ 0, 0,0x3A6F, 0,0x3A70,0x3A71, 0,0x3A72,
+ 0,0x3A73, 0,0x3A74, 0, 0,0x3A75,0x3A76
+};
+
+/* page 16 0x5C59-0x5EEB */
+static uint16 tab_uni_jisx021216[]={
+0x3A77,0x3A78, 0,0x3A79, 0, 0, 0, 0,
+ 0,0x3A7A,0x3A7B, 0, 0, 0,0x3A7C,0x3A7D,
+0x3A7E, 0, 0, 0,0x3B21, 0, 0,0x3B22,
+ 0, 0, 0,0x3B23,0x3B24, 0, 0, 0,
+ 0,0x3B25,0x3B26,0x3B27,0x3B28, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3B29,0x3B2A,
+ 0,0x3B2B, 0, 0, 0, 0,0x3B2C, 0,
+ 0,0x3B2D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3B2E, 0,0x3B2F,0x3B30,
+ 0,0x3B31,0x3B32, 0, 0,0x3B33, 0, 0,
+ 0,0x3B34, 0, 0, 0, 0, 0, 0,
+ 0,0x3B35, 0,0x3B36,0x3B37, 0, 0, 0,
+ 0,0x3B38, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3B39, 0,0x3B3A, 0, 0, 0, 0, 0,
+ 0,0x3B3B, 0, 0, 0, 0,0x3B3D, 0,
+ 0, 0, 0, 0,0x3B3C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3B3E, 0, 0,
+0x3B3F,0x3B40, 0,0x3B41,0x743B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3B42, 0, 0, 0, 0,0x3B43, 0, 0,
+ 0, 0, 0, 0,0x3B44, 0, 0, 0,
+ 0,0x3B45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3B47,0x3B48, 0,0x3B49,0x3B4A, 0,
+ 0, 0,0x3B46, 0, 0, 0, 0, 0,
+0x3B4B, 0, 0,0x3B4C, 0, 0, 0, 0,
+0x3B4D, 0, 0, 0,0x3B4E, 0,0x3B4F, 0,
+ 0,0x3B50,0x3B51, 0, 0,0x3B52, 0,0x3B53,
+ 0,0x3B57, 0, 0, 0, 0, 0, 0,
+0x3B55, 0,0x743C, 0,0x3B54, 0, 0, 0,
+0x3B56, 0, 0, 0, 0, 0,0x3B58,0x3B59,
+0x3B5A,0x3B5B, 0,0x3B5C, 0, 0, 0, 0,
+ 0,0x3B5D, 0, 0,0x3B5E, 0, 0,0x3B5F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3B60,0x3B61, 0, 0, 0,0x3B62,0x3B63, 0,
+0x3B64, 0,0x3B65, 0, 0, 0, 0,0x3B66,
+ 0,0x3B67, 0, 0, 0, 0, 0, 0,
+ 0,0x3B68,0x3B69,0x3B6A,0x3B6B, 0, 0, 0,
+0x3B6C, 0,0x3B6D, 0, 0, 0,0x3B6E,0x3B6F,
+ 0, 0, 0, 0, 0, 0,0x3B70, 0,
+ 0, 0,0x3B71, 0, 0, 0, 0,0x3B72,
+ 0,0x6674, 0,0x3B73, 0, 0, 0,0x3B74,
+0x3B75, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3B76, 0, 0, 0,0x3B77, 0,
+ 0, 0,0x3B78, 0, 0,0x3B7A, 0,0x3B79,
+ 0, 0, 0, 0, 0, 0, 0,0x3B7B,
+0x3B7C, 0, 0, 0, 0, 0, 0,0x3B7D,
+ 0, 0, 0,0x3B7E, 0, 0, 0, 0,
+0x3C21, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3C22,
+0x3C23, 0, 0, 0, 0, 0, 0,0x3C24,
+ 0, 0, 0, 0, 0, 0,0x3C25, 0,
+ 0, 0, 0, 0,0x3C26, 0, 0, 0,
+ 0,0x3C27, 0,0x3C28,0x3C29, 0, 0,0x3C2A,
+ 0, 0, 0, 0, 0, 0,0x3C2B,0x3C2C,
+ 0, 0, 0, 0, 0, 0, 0,0x3C2E,
+ 0, 0, 0, 0, 0,0x3C2D, 0, 0,
+ 0,0x3C2F, 0, 0,0x3C30, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3C31, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3C34, 0,0x3C32, 0, 0, 0, 0,0x3C33,
+0x3C35, 0, 0, 0, 0,0x3C36, 0,0x3C37,
+ 0, 0,0x3C38,0x3C39, 0,0x3C3A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3C3B,
+ 0,0x3C3C,0x3C3D,0x3C3E,0x3C3F,0x3C40, 0,0x3C41,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3C42,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3C43, 0, 0,0x3C44, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x3C45, 0,0x3C46,0x3C47, 0, 0,0x3C48,
+ 0,0x3C49, 0,0x3C4A, 0, 0, 0, 0,
+0x3C4B, 0,0x3C4C, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3C4D,0x3C4E,0x3C4F, 0,
+ 0, 0, 0, 0, 0,0x3C50, 0, 0,
+ 0, 0,0x3C52,0x3C51, 0,0x3C53, 0, 0,
+0x3C54,0x3C55, 0,0x3C56,0x3C57, 0, 0, 0,
+ 0, 0, 0,0x3C58, 0,0x3C59, 0, 0,
+ 0, 0, 0, 0,0x3C5A, 0, 0, 0,
+ 0, 0,0x3C5B};
+
+/* page 17 0x5F02-0x6149 */
+static uint16 tab_uni_jisx021217[]={
+0x3C5C, 0, 0, 0,0x3C5D,0x3C5E,0x3C5F, 0,
+ 0, 0, 0, 0,0x3C60, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3C61,
+ 0, 0,0x3C62,0x3C63, 0, 0, 0,0x3C64,
+0x3C65,0x3C66,0x3C67, 0, 0, 0,0x3C68, 0,
+ 0,0x3C69,0x3C6A, 0,0x3C6B, 0,0x3C6C, 0,
+ 0, 0,0x3C6D, 0,0x3C6E, 0, 0, 0,
+ 0,0x3C6F, 0,0x3C70, 0,0x3C71,0x3C72, 0,
+ 0, 0,0x3C73,0x3C74, 0,0x3C75, 0, 0,
+ 0, 0, 0,0x3C76, 0, 0,0x3C77, 0,
+ 0, 0,0x3C78, 0, 0, 0,0x3C79, 0,
+ 0,0x3C7A, 0, 0, 0, 0,0x3C7B, 0,
+ 0,0x3C7C,0x3C7D, 0, 0,0x3C7E, 0, 0,
+ 0, 0, 0, 0, 0,0x3D21, 0, 0,
+0x3D22, 0,0x3D23,0x3D24, 0, 0,0x3D25, 0,
+0x3D26, 0, 0,0x3D27,0x3D28, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3D29,
+ 0, 0, 0,0x3D2A, 0,0x3D2B, 0, 0,
+ 0, 0, 0, 0,0x3D2C, 0, 0, 0,
+ 0, 0,0x3D2D,0x3D2E, 0, 0, 0, 0,
+0x3D2F, 0,0x3D32, 0, 0,0x3D30, 0, 0,
+ 0,0x3D31,0x3D33, 0, 0,0x3D34,0x3D35,0x3D36,
+ 0, 0, 0, 0, 0,0x743E,0x3D37, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3D38, 0, 0,0x3D39,0x3D3A,0x3D3B,
+ 0,0x3D3C, 0, 0, 0, 0,0x3D3D,0x3D3E,
+0x3D3F,0x3D40,0x3D41, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3D42, 0, 0,0x3D43,
+0x3D44, 0, 0, 0, 0, 0,0x3D45,0x3D46,
+0x3D47, 0,0x3D48,0x3D49,0x3D4A,0x3D4B, 0, 0,
+0x3D4C,0x3D4D, 0, 0,0x3D4E, 0, 0, 0,
+0x3D4F, 0,0x3D50, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3D51, 0, 0,
+0x3D52, 0, 0,0x3D53, 0, 0, 0, 0,
+ 0,0x3D54,0x3D55, 0, 0,0x3D56,0x3D57, 0,
+0x3D58, 0, 0, 0, 0,0x3D59, 0, 0,
+ 0, 0,0x3D5A, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3D5B, 0, 0, 0, 0,
+ 0,0x3D5C, 0,0x3D5D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3D5E, 0,
+ 0, 0, 0, 0, 0,0x3D5F,0x3D60,0x3D61,
+ 0, 0,0x3D62, 0, 0, 0, 0,0x3D63,
+ 0, 0,0x3D64, 0,0x3D65,0x3D66, 0, 0,
+ 0, 0, 0,0x3D67, 0, 0, 0,0x3D68,
+ 0, 0, 0, 0, 0,0x3D69, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3D6A,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3D6B,0x3D6C, 0, 0,
+0x3D6D, 0, 0,0x743F,0x3D6E, 0,0x3D6F, 0,
+0x3D70, 0, 0, 0,0x3D71, 0, 0,0x3D72,
+ 0,0x3D73, 0,0x3D74, 0, 0,0x3D75, 0,
+ 0, 0, 0,0x3D76,0x3D77, 0, 0, 0,
+0x3D78, 0,0x3D79,0x3D7A, 0, 0,0x3D7B, 0,
+ 0, 0, 0, 0, 0, 0,0x3D7C,0x3D7D,
+ 0, 0, 0, 0, 0,0x3D7E, 0, 0,
+ 0,0x3E21, 0, 0,0x3E22, 0, 0, 0,
+0x3E23, 0,0x3E24, 0, 0, 0,0x3E25,0x3E26,
+0x3E27,0x3E28, 0, 0,0x3E29,0x3E2A, 0, 0,
+ 0, 0,0x3E2B,0x3E2C, 0, 0, 0,0x3E2D,
+ 0,0x3E2E, 0,0x3E2F,0x3E30, 0, 0, 0,
+0x3E31, 0, 0,0x3E32, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3E33, 0, 0,0x3E34, 0, 0,0x3E35, 0,
+ 0, 0,0x3E36,0x3E37, 0, 0, 0, 0,
+0x3E38, 0, 0, 0, 0,0x3E39, 0, 0,
+0x3E3A, 0,0x3E3B, 0, 0, 0,0x3E3C,0x3E3D,
+0x3E3E,0x3E3F,0x3E40, 0,0x3E41,0x3E42, 0,0x3E43,
+ 0, 0,0x3E44, 0,0x3E45, 0,0x7440, 0,
+0x3E46, 0, 0, 0, 0, 0, 0, 0,
+0x3E47,0x3E48, 0, 0, 0, 0,0x3E49,0x3E4A,
+ 0, 0, 0,0x3E4B,0x3E4C,0x3E4D, 0,0x3E4E,
+ 0, 0, 0, 0, 0, 0, 0,0x3E4F,
+ 0, 0, 0,0x3E50,0x3E51, 0, 0,0x3E52
+};
+
+/* page 18 0x615E-0x6290 */
+static uint16 tab_uni_jisx021218[]={
+0x3E53, 0,0x3E54, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x3E55, 0,
+ 0, 0, 0, 0,0x3E56, 0, 0, 0,
+ 0, 0,0x3E57, 0, 0,0x3E58,0x3E59, 0,
+ 0,0x3E5A,0x3E5B,0x3E5C, 0,0x3E5D,0x3E5E, 0,
+ 0, 0, 0, 0, 0,0x3E5F, 0,0x3E60,
+ 0, 0, 0, 0,0x3E61,0x3E62, 0, 0,
+ 0,0x3E63,0x3E64, 0, 0, 0,0x3E65,0x3E66,
+ 0,0x3E67,0x3E68, 0, 0, 0, 0,0x3E69,
+ 0, 0,0x3E6A, 0,0x3E6B, 0, 0,0x3E6C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x3E6D,0x3E6E, 0, 0,0x3E6F, 0,
+ 0, 0,0x3E70,0x3E71,0x3E72, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3E73,0x3E74, 0, 0, 0, 0, 0,0x3E75,
+ 0, 0, 0, 0, 0, 0,0x3E76,0x3E77,
+0x3E78,0x3E79, 0,0x3E7A,0x3E7B, 0, 0,0x3E7E,
+ 0,0x3E7C, 0,0x3E7D, 0, 0,0x3F21,0x3F22,
+ 0,0x3F23, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3F24, 0,0x3F25,0x3F26, 0,
+ 0,0x3F27, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3F28, 0,0x3F29,
+ 0, 0, 0, 0, 0, 0,0x3F2A, 0,
+ 0, 0,0x3F2B, 0,0x3F2C,0x3F2D, 0, 0,
+ 0,0x3F2E, 0,0x3F2F, 0,0x3F30, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3F31, 0, 0, 0,0x3F32,
+ 0, 0, 0, 0,0x3F33,0x3F34,0x3F35, 0,
+0x3F36, 0, 0, 0, 0, 0,0x3F37, 0,
+ 0, 0,0x3F38,0x3F39,0x3F3A, 0,0x3F3B, 0,
+0x3F3C, 0, 0, 0,0x3F3D, 0,0x3F3E, 0,
+ 0, 0, 0, 0, 0, 0,0x3F3F, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3F40,
+ 0,0x3F41, 0, 0, 0,0x3F42, 0, 0,
+ 0, 0, 0, 0,0x3F43, 0, 0,0x3F44,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3F45,
+0x3F46,0x3F47,0x3F48};
+
+/* page 19 0x62A6-0x679B */
+static uint16 tab_uni_jisx021219[]={
+0x3F49, 0,0x3F4A, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x3F4B, 0, 0,
+0x3F4C,0x3F4D, 0, 0,0x3F4E, 0, 0, 0,
+0x3F4F,0x3F50, 0, 0, 0, 0,0x3F51, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x3F52, 0, 0, 0, 0, 0, 0,0x3F53,
+0x3F54, 0, 0, 0,0x3F55, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x3F56, 0, 0, 0,
+ 0, 0, 0, 0,0x3F57, 0,0x3F58, 0,
+ 0, 0, 0, 0, 0, 0,0x3F59,0x3F5A,
+ 0, 0, 0, 0, 0,0x3F5B,0x3F5C, 0,
+ 0, 0, 0, 0,0x3F5D,0x3F5E, 0,0x3F5F,
+ 0, 0,0x3F60, 0, 0,0x3F61, 0, 0,
+0x3F62, 0,0x3F63, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x3F64,0x3F65, 0, 0,0x3F66,
+ 0, 0, 0, 0, 0, 0, 0,0x3F67,
+0x3F68, 0, 0,0x3F69, 0, 0,0x3F6A, 0,
+ 0, 0, 0,0x3F6B,0x3F6C,0x3F6D,0x3F6E, 0,
+0x3F6F, 0, 0, 0,0x3F70,0x3F71, 0, 0,
+0x3F72, 0, 0, 0,0x3F73,0x3F74,0x3F75, 0,
+ 0, 0,0x3F76, 0, 0,0x3F77, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x3F78,
+0x3F79, 0, 0, 0, 0, 0,0x3F7A,0x3F7B,
+ 0, 0, 0,0x3F7C, 0, 0,0x3F7D,0x3F7E,
+ 0, 0,0x4021, 0, 0, 0,0x4022,0x4023,
+ 0,0x4024, 0, 0,0x4025, 0,0x4026, 0,
+ 0,0x4027, 0, 0,0x4028, 0, 0, 0,
+ 0, 0,0x4029, 0, 0, 0,0x402A,0x402B,
+ 0, 0, 0,0x402C,0x402D, 0, 0, 0,
+0x402E, 0, 0, 0, 0, 0,0x402F, 0,
+0x4030, 0, 0, 0, 0, 0, 0,0x4031,
+0x4032,0x4033, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4034,
+ 0, 0, 0,0x4035, 0, 0, 0,0x4036,
+ 0, 0,0x4037, 0, 0, 0, 0, 0,
+0x4038, 0, 0,0x4039, 0,0x403A,0x403B,0x403C,
+ 0, 0, 0, 0, 0, 0,0x403D, 0,
+ 0, 0,0x403E, 0, 0, 0, 0,0x403F,
+ 0, 0, 0, 0,0x4040, 0,0x4041, 0,
+ 0, 0, 0, 0,0x4042,0x4043, 0,0x4044,
+ 0, 0,0x4045,0x4046, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x4047,0x4048, 0, 0, 0,
+ 0, 0,0x4049, 0,0x404A, 0,0x404B, 0,
+ 0, 0,0x404C, 0, 0, 0, 0, 0,
+0x404D, 0,0x404E, 0,0x404F, 0,0x4050,0x4051,
+ 0, 0, 0,0x4052,0x4053, 0, 0, 0,
+ 0,0x4054,0x4055, 0, 0, 0, 0,0x4056,
+ 0, 0, 0, 0, 0, 0, 0,0x4057,
+ 0,0x4058, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4059, 0, 0,
+ 0,0x405A, 0,0x405B,0x405C,0x405D,0x405E, 0,
+ 0, 0, 0, 0,0x405F,0x4060,0x4061,0x4062,
+ 0,0x4063,0x4064,0x4065, 0,0x4066, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4067,
+ 0, 0, 0, 0, 0,0x4068,0x4069, 0,
+ 0, 0, 0, 0, 0,0x406A, 0,0x406B,
+ 0, 0, 0, 0, 0, 0, 0,0x406C,
+ 0,0x406D, 0, 0, 0, 0, 0, 0,
+ 0,0x406E,0x406F,0x4070, 0, 0, 0, 0,
+ 0, 0,0x4071,0x4072, 0,0x4073, 0,0x4074,
+ 0,0x4075, 0,0x4076, 0,0x4077, 0, 0,
+0x4078, 0,0x4079, 0, 0, 0,0x407A, 0,
+ 0, 0, 0, 0, 0,0x407B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x407C,
+0x407D,0x407E, 0, 0, 0, 0,0x4121, 0,
+ 0, 0, 0,0x4122,0x4123,0x4124,0x4125, 0,
+0x4126, 0,0x4127,0x4128, 0, 0, 0,0x4129,
+ 0,0x412A, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x412B,0x412C,
+ 0, 0, 0,0x412D,0x412E, 0, 0,0x412F,
+ 0, 0,0x4130, 0, 0, 0, 0,0x4131,
+ 0,0x4132, 0, 0, 0,0x4133, 0, 0,
+ 0,0x4134, 0,0x4135, 0, 0,0x4136, 0,
+ 0, 0,0x4137,0x4138,0x4139, 0, 0, 0,
+ 0,0x413A, 0, 0, 0,0x413B,0x413C, 0,
+0x413D, 0, 0,0x413E, 0,0x413F, 0, 0,
+0x4140,0x4141, 0, 0,0x4142, 0, 0, 0,
+0x4143, 0, 0,0x4144, 0, 0, 0, 0,
+0x4145, 0, 0,0x4146, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4147, 0,0x4148,0x4149,
+ 0, 0, 0, 0, 0,0x414A, 0, 0,
+ 0,0x414B, 0,0x414C, 0, 0, 0, 0,
+0x7441, 0,0x414D, 0,0x414E, 0,0x414F, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4150,0x4151, 0, 0, 0, 0, 0,
+ 0,0x4152, 0, 0, 0,0x4153, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4154, 0, 0,0x4155,
+ 0, 0, 0,0x4156, 0, 0, 0,0x4157,
+ 0, 0, 0, 0,0x4158, 0, 0, 0,
+ 0, 0, 0, 0,0x4159, 0, 0,0x415A,
+ 0, 0,0x415B, 0, 0, 0, 0,0x415C,
+ 0, 0,0x415D, 0, 0,0x415E, 0, 0,
+0x415F, 0, 0, 0, 0, 0, 0, 0,
+0x4160, 0, 0, 0,0x4161,0x4162,0x4163, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4164, 0, 0,0x4165, 0, 0, 0,
+ 0, 0,0x4166,0x4167, 0, 0, 0, 0,
+0x4168, 0,0x4169, 0, 0, 0,0x416A, 0,
+0x416B, 0,0x416C, 0, 0, 0, 0, 0,
+ 0,0x416D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x416E, 0,0x416F, 0,0x4170,0x4171,
+ 0, 0, 0,0x4172, 0, 0, 0, 0,
+0x4173,0x4174,0x4175, 0, 0, 0,0x4176, 0,
+ 0, 0,0x4177,0x4178, 0, 0, 0,0x4179,
+ 0, 0, 0,0x417A,0x417B, 0, 0,0x417C,
+0x417D, 0, 0, 0, 0, 0, 0,0x417E,
+0x4221, 0, 0,0x4222,0x4223,0x4224,0x4225, 0,
+0x4226, 0, 0,0x4227,0x4228,0x4229,0x422A, 0,
+0x422B, 0,0x422C,0x422D, 0,0x422E, 0, 0,
+ 0,0x4230, 0,0x422F, 0,0x7442, 0, 0,
+ 0, 0,0x4231, 0, 0, 0, 0,0x4232,
+0x4233, 0, 0, 0,0x4234, 0,0x4235, 0,
+0x4237, 0, 0,0x4236, 0, 0, 0, 0,
+ 0,0x4238,0x4239,0x423A, 0,0x423B,0x423C, 0,
+ 0, 0,0x423D,0x423E, 0, 0, 0,0x7443,
+ 0, 0, 0, 0,0x4240,0x4241,0x4242, 0,
+ 0, 0, 0, 0, 0,0x4244, 0,0x4245,
+ 0,0x4247,0x4248,0x4249, 0,0x424A,0x424C, 0,
+0x4243,0x4246,0x424B, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x424D,0x424E,0x424F,
+ 0, 0,0x4250, 0,0x4251, 0, 0, 0,
+ 0, 0, 0,0x4252,0x4253,0x4254,0x4255, 0,
+ 0,0x4256,0x4257, 0, 0, 0,0x4258, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4259,
+ 0, 0, 0,0x425A,0x425B, 0, 0,0x425C,
+ 0, 0, 0, 0, 0,0x425D, 0, 0,
+ 0,0x425E,0x425F, 0,0x4260,0x4261, 0, 0,
+ 0, 0,0x4262, 0, 0, 0,0x4263, 0,
+0x4264,0x4265, 0, 0, 0, 0,0x4266, 0,
+ 0, 0, 0, 0, 0,0x4267, 0, 0,
+ 0,0x4268, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4269, 0, 0,0x426A,0x426B, 0,
+0x426C, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x426D,0x423F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x426E,
+ 0,0x426F, 0, 0, 0, 0, 0, 0,
+0x4270, 0, 0, 0, 0,0x4271, 0, 0,
+ 0, 0, 0,0x4272, 0, 0,0x4273, 0,
+ 0, 0,0x4274, 0,0x4275, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4276, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4277, 0, 0, 0, 0, 0, 0,0x4278,
+ 0,0x4279,0x427A, 0, 0, 0,0x427B, 0,
+ 0, 0, 0, 0, 0, 0,0x427C,0x427D,
+ 0, 0, 0, 0, 0, 0, 0,0x427E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4321, 0, 0, 0, 0, 0,0x4322, 0,
+0x4323, 0, 0, 0, 0, 0,0x4324, 0,
+0x4325, 0, 0, 0, 0,0x4326, 0, 0,
+ 0, 0, 0,0x4327, 0, 0,0x4328, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4329,0x432A, 0,0x432B, 0,0x432C, 0, 0,
+0x432D, 0,0x432E,0x432F, 0,0x4330};
+
+/* page 20 0x67B0-0x6801 */
+static uint16 tab_uni_jisx021220[]={
+0x4331,0x4332,0x4333, 0, 0,0x4334, 0, 0,
+ 0, 0, 0,0x4335,0x4336,0x4337, 0, 0,
+0x4339, 0,0x433A,0x433B, 0,0x433C, 0, 0,
+0x433D,0x433E, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x433F, 0, 0, 0, 0,0x4340,
+ 0,0x4341, 0, 0,0x4342, 0, 0, 0,
+ 0,0x4343, 0, 0, 0, 0,0x4344, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4345, 0,0x4346, 0, 0, 0,0x4347,0x4348,
+ 0,0x4338, 0, 0, 0, 0, 0, 0,
+ 0,0x7446};
+
+/* page 21 0x6814-0x6917 */
+static uint16 tab_uni_jisx021221[]={
+0x434A, 0, 0, 0, 0,0x434B, 0, 0,
+ 0,0x434C, 0,0x434D, 0, 0, 0, 0,
+ 0, 0, 0,0x434F,0x434E, 0, 0, 0,
+0x4350,0x4351, 0,0x4352,0x4353,0x4354, 0,0x4355,
+ 0, 0, 0, 0, 0, 0, 0,0x4356,
+ 0, 0, 0,0x4357, 0, 0, 0, 0,
+0x4358,0x4359, 0, 0, 0, 0,0x435A, 0,
+0x435B, 0, 0, 0, 0, 0,0x4349, 0,
+ 0,0x435C, 0,0x435D,0x435E, 0, 0,0x435F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4360,
+ 0, 0,0x4361,0x4362,0x4363,0x4364,0x4365, 0,
+ 0,0x4366, 0, 0, 0,0x4367,0x4368,0x4369,
+0x436A, 0, 0, 0, 0, 0,0x436B, 0,
+0x436C, 0,0x436D, 0,0x436E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x436F, 0,0x4370, 0,0x4371, 0,
+0x4372, 0, 0, 0, 0,0x4373, 0,0x4374,
+ 0,0x4375, 0, 0, 0,0x4376,0x4377, 0,
+ 0, 0,0x4378, 0, 0, 0,0x4379, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x437A,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x437B, 0, 0,0x437C, 0, 0, 0,
+0x437D, 0, 0,0x437E,0x4421,0x4422, 0,0x4423,
+ 0, 0,0x4424, 0, 0,0x4425, 0, 0,
+0x4426,0x4427, 0, 0, 0, 0, 0, 0,
+ 0,0x4428, 0, 0,0x4429, 0,0x442A,0x442B,
+0x442C,0x442D, 0, 0,0x442E,0x442F, 0, 0,
+ 0,0x4430,0x4431, 0, 0, 0, 0,0x4432,
+0x4433,0x4434, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4435, 0, 0,0x4436,0x4437, 0,
+ 0, 0, 0, 0,0x4438,0x4439, 0,0x443A,
+ 0, 0,0x443B,0x443C};
+
+/* page 22 0x6931-0x6D3F */
+static uint16 tab_uni_jisx021222[]={
+0x443D, 0,0x443E, 0,0x443F, 0, 0,0x4440,
+ 0, 0,0x4441, 0, 0, 0, 0, 0,
+ 0,0x4442, 0, 0,0x4443, 0, 0, 0,
+0x4444, 0, 0, 0, 0,0x4445, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4446, 0,
+ 0, 0,0x4447, 0, 0, 0, 0, 0,
+ 0, 0,0x4448,0x4449,0x444A,0x444B, 0,0x444C,
+0x444D, 0, 0,0x444E, 0, 0, 0,0x444F,
+0x4450,0x4451, 0, 0, 0, 0, 0, 0,
+ 0,0x4452,0x4453, 0, 0, 0,0x4454,0x4455,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4456, 0, 0, 0,
+ 0,0x4457, 0, 0, 0,0x4458, 0,0x4459,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x445A, 0, 0, 0,0x445B,0x445C, 0,0x445D,
+ 0, 0,0x445E, 0,0x445F, 0,0x4460, 0,
+ 0, 0, 0, 0, 0, 0,0x4461,0x4462,
+ 0,0x4463, 0,0x4464, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4465, 0, 0,0x4466,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4467, 0, 0, 0, 0,0x4468,0x4469, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x446A, 0, 0,0x446B, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x446C,0x446D, 0,
+0x446E, 0,0x446F, 0,0x4470, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4471, 0,0x4472,
+0x4473, 0,0x4474, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4475, 0,
+0x4476, 0, 0, 0,0x4477, 0, 0, 0,
+ 0,0x4478, 0, 0,0x4479, 0, 0,0x447A,
+ 0, 0, 0,0x447B, 0, 0, 0,0x447C,
+ 0, 0, 0, 0, 0, 0, 0,0x447D,
+ 0,0x447E, 0,0x4521, 0, 0,0x4522, 0,
+ 0, 0,0x4523, 0, 0,0x4524,0x4525, 0,
+ 0, 0, 0, 0,0x4526,0x4527, 0, 0,
+0x4528,0x4529, 0, 0, 0,0x452A, 0,0x452B,
+0x452C,0x452D, 0, 0,0x452E,0x452F, 0, 0,
+ 0, 0,0x4530, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x4531, 0, 0,0x4532, 0,
+ 0,0x4533,0x7449, 0, 0, 0, 0, 0,
+0x4534, 0,0x4535, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4536, 0, 0,
+0x4537, 0,0x4538, 0, 0,0x4539,0x453A, 0,
+0x453B, 0,0x453C, 0, 0, 0, 0, 0,
+0x453D, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x453E, 0,0x453F,0x4540,0x4541, 0,
+ 0, 0, 0, 0,0x4542, 0, 0, 0,
+ 0, 0,0x4543, 0, 0, 0,0x4544,0x4545,
+0x4546, 0, 0,0x4547, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4548,0x4549,0x454A, 0,
+ 0, 0, 0, 0, 0,0x454B, 0,0x454D,
+0x454C, 0, 0,0x454E, 0, 0, 0,0x454F,
+ 0, 0, 0,0x4550,0x4551,0x4552, 0, 0,
+ 0, 0, 0,0x4553,0x4554, 0, 0, 0,
+ 0,0x744A, 0,0x4555, 0, 0,0x4556, 0,
+ 0, 0, 0,0x4557, 0, 0, 0,0x4558,
+0x4559,0x455A, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x455B,0x455C, 0, 0, 0,
+ 0,0x455D,0x455E, 0, 0,0x455F,0x4560, 0,
+0x4561, 0, 0, 0, 0, 0,0x4562,0x4563,
+0x4564, 0, 0, 0, 0, 0,0x4565, 0,
+ 0, 0,0x4566, 0, 0,0x4567, 0, 0,
+ 0, 0, 0,0x4568, 0, 0, 0,0x4569,
+ 0, 0,0x456A,0x456B, 0, 0,0x456C, 0,
+ 0, 0, 0, 0,0x456D,0x456E, 0, 0,
+ 0, 0,0x456F, 0, 0, 0,0x4570, 0,
+ 0, 0, 0, 0, 0,0x4571, 0, 0,
+ 0,0x4572, 0, 0,0x4573, 0, 0, 0,
+ 0,0x4574, 0, 0, 0,0x4575, 0,0x4576,
+ 0, 0, 0, 0,0x4577, 0, 0,0x4578,
+ 0, 0, 0, 0, 0, 0,0x4579, 0,
+ 0, 0,0x457A, 0, 0,0x457B, 0,0x457C,
+ 0, 0, 0, 0,0x457D, 0, 0, 0,
+ 0, 0, 0, 0,0x457E,0x4621, 0, 0,
+ 0,0x4622, 0, 0,0x4623, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4624, 0,
+ 0, 0,0x4625, 0, 0, 0,0x4626,0x4627,
+ 0,0x4628,0x4629, 0, 0, 0, 0,0x462A,
+0x462B, 0, 0,0x462C,0x462D,0x462E, 0,0x462F,
+ 0, 0, 0, 0, 0, 0, 0,0x4630,
+0x4631, 0, 0, 0,0x4632,0x4633, 0, 0,
+ 0, 0,0x4634,0x4635, 0, 0, 0, 0,
+0x4636, 0, 0,0x4637, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4638, 0, 0,
+ 0,0x4639, 0, 0, 0, 0, 0, 0,
+0x463A, 0,0x463B, 0, 0,0x463C,0x463D, 0,
+ 0, 0, 0, 0, 0,0x463E, 0, 0,
+0x463F, 0, 0, 0, 0, 0,0x4640, 0,
+0x4641, 0, 0, 0, 0, 0,0x4642, 0,
+ 0,0x4643, 0,0x4644,0x4645, 0, 0, 0,
+0x4646, 0, 0, 0,0x4647,0x4648, 0,0x4649,
+ 0,0x464A, 0, 0, 0, 0, 0, 0,
+0x464B, 0, 0, 0, 0, 0,0x464C, 0,
+ 0, 0, 0, 0, 0,0x464D,0x464E,0x464F,
+ 0, 0, 0,0x4650, 0,0x4651, 0, 0,
+ 0, 0,0x4652, 0,0x4653,0x4654, 0, 0,
+ 0,0x4655,0x4656, 0, 0, 0,0x4657, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4658,0x4659, 0,0x465A, 0,0x465B, 0,
+ 0,0x465C, 0,0x465D, 0, 0, 0, 0,
+0x465E, 0,0x465F,0x4660, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4736, 0,
+ 0, 0,0x4661, 0,0x4662, 0,0x4663, 0,
+ 0, 0, 0,0x4664, 0,0x4665, 0,0x4666,
+0x4667, 0,0x4668, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4669,0x466A,0x466B, 0,
+0x466C, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x466D,0x466E, 0,0x466F,0x4670,
+ 0, 0, 0,0x4671, 0, 0,0x4672, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4673,
+ 0,0x4674, 0,0x4675, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4676, 0, 0, 0,0x4677, 0, 0,
+ 0, 0, 0, 0,0x4678, 0,0x4679,0x467A,
+0x467B,0x467C, 0,0x467D, 0,0x467E, 0, 0,
+ 0,0x4721, 0,0x4722, 0, 0, 0,0x4723,
+ 0, 0, 0, 0, 0, 0,0x4724, 0,
+0x4725, 0,0x4726,0x4727, 0,0x4728, 0, 0,
+ 0,0x4729, 0,0x472A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x472B, 0, 0,0x472C, 0,
+ 0,0x472D, 0, 0, 0,0x472E,0x472F, 0,
+0x4730, 0,0x4731, 0, 0, 0, 0, 0,
+ 0,0x4732, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4733,0x4734,0x4735,
+ 0, 0, 0, 0, 0,0x4737,0x4738, 0,
+0x4739, 0, 0, 0, 0, 0, 0, 0,
+0x473A, 0, 0,0x473B, 0, 0,0x473C};
+
+/* page 23 0x6D57-0x6E04 */
+static uint16 tab_uni_jisx021223[]={
+0x473D, 0, 0, 0, 0, 0, 0,0x473E,
+0x473F, 0,0x4740, 0, 0, 0,0x4741, 0,
+0x4742, 0, 0, 0, 0, 0, 0, 0,
+0x4743,0x4744, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4745, 0, 0,
+ 0, 0, 0,0x4746, 0, 0, 0, 0,
+0x4747, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4748,0x4749, 0,0x474A, 0,0x474B,
+0x474C,0x474D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x474E, 0,0x474F, 0, 0,
+ 0, 0, 0, 0, 0,0x4750, 0, 0,
+0x4751, 0,0x4752, 0, 0, 0,0x4753, 0,
+0x4754, 0, 0, 0, 0,0x4755, 0, 0,
+ 0,0x4756, 0,0x4757, 0, 0, 0,0x4758,
+0x4759, 0, 0, 0, 0, 0, 0,0x475A,
+ 0, 0, 0, 0,0x475B, 0,0x475C, 0,
+0x475D,0x475E, 0,0x475F, 0, 0,0x4760, 0,
+ 0, 0,0x4761, 0, 0, 0, 0, 0,
+0x4762,0x4763, 0,0x744C, 0,0x4764, 0,0x4765,
+ 0,0x744B, 0, 0, 0,0x4766, 0, 0,
+ 0,0x4767, 0, 0, 0,0x4768};
+
+/* page 24 0x6E1E-0x6ECF */
+static uint16 tab_uni_jisx021224[]={
+0x4769, 0, 0, 0,0x476A, 0, 0, 0,
+ 0,0x476B, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x476C, 0, 0, 0,
+0x476D, 0, 0,0x476E, 0,0x476F,0x4770, 0,
+ 0, 0, 0, 0, 0, 0,0x4771,0x4772,
+ 0, 0,0x4773,0x4774, 0,0x4775, 0, 0,
+ 0,0x4776, 0,0x4777,0x4778,0x4779,0x477A, 0,
+ 0,0x477B, 0, 0, 0, 0,0x477C,0x477D,
+0x477E, 0, 0, 0,0x4821,0x4822, 0, 0,
+ 0, 0,0x4823, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4824, 0, 0,
+ 0, 0, 0, 0, 0,0x4825, 0,0x4826,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4827,
+ 0, 0, 0, 0, 0,0x4828, 0, 0,
+ 0, 0, 0,0x4829, 0, 0, 0, 0,
+ 0, 0,0x482A, 0, 0, 0, 0, 0,
+ 0,0x482B, 0, 0, 0, 0, 0,0x482C,
+0x482D, 0, 0,0x482E, 0,0x482F, 0, 0,
+ 0, 0, 0, 0, 0,0x4830, 0, 0,
+ 0,0x4831,0x4832,0x4833, 0,0x4834, 0, 0,
+ 0,0x4835,0x4836, 0,0x4837, 0, 0,0x4838,
+0x4839,0x483A};
+
+/* page 25 0x6EEB-0x70E4 */
+static uint16 tab_uni_jisx021225[]={
+0x483B, 0,0x483C,0x483D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x483E, 0,
+0x483F, 0,0x4840, 0, 0, 0, 0, 0,
+ 0,0x4841, 0, 0, 0,0x4842, 0,0x4843,
+ 0,0x4844,0x4845, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x4846, 0,0x4847, 0,0x4848,
+0x4849, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x484A, 0, 0,0x484B,0x484C,
+ 0, 0,0x4853, 0,0x484D,0x484E, 0, 0,
+0x484F, 0, 0,0x4850, 0, 0, 0, 0,
+0x4851,0x4852, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4854, 0,0x4855,0x4856,
+0x4857, 0, 0, 0,0x4858, 0,0x4859,0x485A,
+ 0, 0,0x485B,0x485C, 0, 0,0x485D,0x485E,
+ 0, 0, 0, 0, 0,0x485F, 0, 0,
+ 0,0x4860, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4861,0x4862, 0, 0, 0, 0,
+0x4863, 0, 0, 0,0x4864,0x4865, 0, 0,
+0x4866,0x4867,0x4868, 0, 0,0x4869, 0,0x486A,
+0x486B,0x486C, 0,0x486D, 0, 0, 0,0x486E,
+ 0, 0, 0, 0,0x486F,0x4870, 0, 0,
+ 0, 0,0x4871,0x4872,0x4873,0x4874, 0, 0,
+ 0, 0, 0,0x4875,0x4876,0x4877, 0, 0,
+ 0, 0,0x4878,0x4879, 0, 0, 0, 0,
+ 0,0x487A, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x487B, 0,0x487C,0x487D, 0,0x487E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4921,
+ 0, 0, 0,0x4922, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4923,0x4924, 0,
+ 0, 0, 0, 0, 0,0x4925, 0, 0,
+ 0, 0,0x4926, 0, 0, 0,0x4927, 0,
+ 0,0x4928,0x4929, 0, 0,0x492A, 0, 0,
+ 0, 0,0x492B,0x492C,0x492D, 0, 0, 0,
+ 0, 0,0x492E, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x492F, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4930, 0, 0,
+0x4931, 0, 0, 0, 0,0x744D, 0, 0,
+ 0, 0, 0, 0,0x4932, 0, 0, 0,
+ 0,0x4933, 0, 0,0x4934, 0,0x4935, 0,
+ 0,0x4936, 0, 0, 0, 0, 0, 0,
+0x4937,0x4938, 0, 0, 0,0x4939,0x493A,0x493B,
+0x493C, 0, 0,0x4941, 0, 0, 0, 0,
+ 0,0x493D,0x493E, 0, 0, 0, 0, 0,
+ 0, 0,0x493F,0x4940, 0, 0, 0, 0,
+ 0,0x4942,0x4943, 0, 0, 0, 0, 0,
+ 0,0x4944, 0,0x4945, 0, 0, 0, 0,
+ 0, 0,0x4946,0x4947, 0, 0, 0, 0,
+ 0, 0, 0,0x4948, 0, 0,0x4949, 0,
+ 0, 0,0x494A,0x494B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x494C,0x494D,0x494E,0x494F,0x4950, 0, 0,
+0x4951, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4952, 0, 0, 0, 0, 0, 0,
+0x4953, 0, 0, 0, 0,0x4954,0x4955, 0,
+ 0,0x4956, 0, 0,0x4957, 0, 0, 0,
+0x742E, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4958,
+ 0, 0, 0, 0, 0, 0,0x4959, 0,
+0x495A,0x495B,0x495C,0x495D, 0,0x495E, 0, 0,
+ 0,0x495F, 0, 0, 0, 0, 0, 0,
+ 0,0x4960};
+
+/* page 26 0x70FA-0x71DC */
+static uint16 tab_uni_jisx021226[]={
+0x4961, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4962,0x4963,0x4964,0x4965,0x4966, 0, 0,
+ 0,0x4967,0x4968, 0, 0,0x4969, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x496A, 0,0x496B, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x496C, 0,0x496D, 0,0x496E,0x496F,0x4970,
+ 0, 0, 0, 0, 0, 0,0x4971, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4972,
+ 0, 0, 0,0x4973,0x4974,0x4975, 0, 0,
+0x4976,0x4977, 0, 0, 0, 0,0x4978, 0,
+0x4979, 0, 0, 0, 0,0x497A, 0, 0,
+0x497B, 0,0x497C, 0,0x497D, 0,0x497E, 0,
+ 0, 0, 0, 0, 0, 0,0x4A21, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4A22,
+ 0, 0, 0, 0, 0, 0,0x4A23, 0,
+ 0, 0, 0,0x4A24, 0,0x4A25, 0, 0,
+ 0, 0,0x4A26, 0, 0, 0, 0, 0,
+0x4A27, 0, 0, 0, 0, 0, 0, 0,
+0x4A28,0x4A29, 0, 0, 0, 0,0x4A2A, 0,
+0x4A2B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4A2C,0x4A2D, 0,
+0x4A2E,0x4A2F, 0, 0, 0, 0, 0, 0,
+0x4A30, 0, 0, 0, 0,0x4A31,0x4A32,0x4A33,
+ 0, 0,0x4A34, 0, 0, 0, 0, 0,
+ 0,0x4A35,0x4A36, 0, 0, 0, 0, 0,
+ 0,0x4A37, 0, 0,0x4A38, 0, 0,0x4A39,
+0x4A3A, 0,0x4A3B};
+
+/* page 27 0x71F8-0x7E9E */
+static uint16 tab_uni_jisx021227[]={
+0x4A3C, 0, 0, 0, 0, 0,0x4A3D, 0,
+0x4A3E, 0, 0, 0, 0, 0, 0,0x4A3F,
+0x4A40,0x4A41, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x4A42, 0, 0, 0,0x4A43,
+ 0, 0,0x4A44, 0, 0,0x4A45, 0,0x4A46,
+ 0, 0, 0, 0,0x4A47, 0, 0, 0,
+ 0, 0, 0,0x4A48, 0, 0, 0,0x4A49,
+ 0, 0, 0, 0,0x4A4A, 0, 0, 0,
+0x4A4B,0x4A4C, 0, 0, 0, 0, 0, 0,
+ 0,0x4A4D,0x4A4E,0x4A4F, 0,0x4A50, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4A51,0x4A52,
+0x4A53, 0, 0,0x4A54, 0,0x4A55,0x4A56, 0,
+ 0, 0,0x4A57, 0,0x4A58, 0,0x4A59, 0,
+0x4A5A, 0, 0,0x4A5B, 0, 0, 0, 0,
+0x4A5C, 0, 0,0x4A5D, 0, 0,0x4A5E,0x4A5F,
+ 0,0x4A60, 0, 0, 0, 0, 0,0x4A61,
+0x4A62, 0, 0,0x4A63,0x4A64, 0, 0,0x4A65,
+ 0, 0, 0, 0,0x4A66, 0, 0, 0,
+ 0,0x4A67, 0, 0, 0,0x4A68,0x4A69, 0,
+ 0, 0, 0,0x4A6A, 0, 0, 0, 0,
+ 0, 0, 0,0x4A6B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4A6C, 0, 0, 0, 0,0x4A6D,0x4A6E, 0,
+ 0,0x4A6F, 0, 0,0x4A70, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4A71, 0,
+ 0,0x4A72, 0, 0, 0, 0, 0,0x4A73,
+ 0,0x4A74, 0, 0,0x4A75, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4A76,0x4A77, 0,
+0x4A78, 0, 0, 0, 0, 0, 0,0x4A79,
+ 0, 0, 0, 0, 0,0x4A7A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x4A7B,0x4A7C, 0, 0, 0,
+ 0, 0,0x4A7D,0x4A7E, 0, 0,0x4B21, 0,
+ 0, 0,0x4B22, 0,0x4B23,0x4B24, 0,0x4B25,
+ 0, 0, 0,0x4B26, 0,0x4B27, 0, 0,
+ 0, 0,0x4B28,0x4B29, 0, 0, 0, 0,
+0x4B2A,0x4B2B, 0, 0, 0, 0,0x4B2C, 0,
+ 0, 0,0x4B2D, 0,0x4B2E, 0, 0,0x4B2F,
+0x4B30, 0, 0, 0,0x4B31, 0, 0, 0,
+ 0,0x4B32,0x4B33, 0, 0,0x4B34, 0, 0,
+ 0, 0,0x4B35,0x4B36, 0,0x4B37, 0, 0,
+ 0, 0, 0,0x4B38, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4B39, 0, 0,
+0x4B3A, 0,0x4B3B, 0, 0, 0,0x4B3C, 0,
+0x4B3D, 0, 0, 0, 0,0x4B3E,0x4B3F,0x4B40,
+0x4B41, 0, 0, 0, 0, 0,0x4B42,0x4B43,
+ 0,0x4B44, 0,0x4B45,0x4B46, 0,0x4B47,0x4B48,
+ 0,0x4B49, 0, 0, 0, 0, 0,0x4B4A,
+ 0,0x4B4B, 0, 0,0x4B4C, 0, 0, 0,
+0x4B4D,0x4B4E, 0,0x4B4F, 0,0x4B50,0x4B51, 0,
+ 0, 0, 0, 0, 0, 0,0x4B52, 0,
+0x4B53, 0, 0,0x4B54, 0,0x4B55, 0,0x4B56,
+0x4B57, 0, 0, 0,0x4B58, 0,0x4B59,0x4B5A,
+0x4B5B, 0,0x4B5C, 0, 0,0x4B5D,0x4B5E, 0,
+ 0, 0,0x4B5F,0x4B60, 0,0x4B61, 0, 0,
+ 0, 0, 0, 0, 0,0x4B62, 0,0x4B63,
+ 0,0x4B64, 0, 0,0x4B65,0x4B66, 0,0x4B67,
+ 0, 0, 0, 0, 0,0x4B68,0x4B69, 0,
+ 0,0x4B6A, 0,0x4B6B,0x4B6C, 0, 0,0x4B6D,
+ 0, 0,0x4B6E,0x4B6F, 0, 0,0x4B70, 0,
+ 0,0x4B71, 0, 0, 0,0x4B72, 0, 0,
+ 0,0x4B73, 0,0x4B74, 0, 0,0x4B75,0x4B76,
+ 0,0x4B77, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4B78,0x4B79, 0,0x4B7A,
+ 0,0x4B7B,0x4B7C,0x4B7D, 0,0x4B7E, 0,0x4C21,
+0x4C22,0x4C23, 0, 0,0x4C24, 0, 0,0x4C25,
+ 0, 0,0x4C26, 0, 0, 0, 0, 0,
+ 0,0x4C27, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4C28,0x4C29, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4C2A, 0,0x4C2B, 0,
+0x4C2C,0x4C2D,0x4C2E,0x4C2F,0x4C30,0x4C31,0x4C32,0x4C33,
+0x4C34,0x4C35, 0, 0, 0, 0, 0, 0,
+ 0,0x4C36, 0, 0, 0, 0, 0, 0,
+0x4C37, 0, 0,0x4C38,0x4C39, 0,0x4C3A,0x4C3B,
+ 0, 0, 0,0x4C3C, 0,0x4C3D, 0, 0,
+ 0,0x4C3E,0x4C3F, 0, 0, 0, 0,0x4C40,
+ 0, 0, 0, 0, 0,0x4C41, 0, 0,
+ 0, 0,0x4C42, 0, 0, 0,0x4C43,0x4C44,
+0x4C45, 0, 0,0x4C46, 0,0x4C47,0x4C48, 0,
+ 0,0x4C49,0x4C4A, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4C4B,0x4C4C, 0, 0, 0,0x4C4D,0x4C4E,0x4C4F,
+ 0,0x4C50, 0, 0, 0, 0, 0,0x4C51,
+0x4C52,0x4C53,0x4C54, 0, 0, 0, 0, 0,
+0x4C55,0x4C56,0x4C57, 0,0x4C58, 0, 0,0x4C59,
+0x4C5A,0x4C5B, 0,0x4C5C, 0, 0,0x4C5D, 0,
+0x4C5E,0x4C5F,0x4C60,0x4C61, 0, 0,0x4C62,0x4C63,
+ 0,0x4C64,0x4C65, 0, 0,0x4C66, 0, 0,
+ 0,0x4C67, 0,0x4C68, 0, 0, 0,0x4C69,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4C6A,0x4C6B, 0, 0,0x4C6C, 0, 0, 0,
+0x4C6D, 0, 0,0x4C6E, 0, 0, 0, 0,
+0x4C6F, 0,0x4C70,0x4C71, 0, 0,0x4C72,0x4C73,
+ 0, 0, 0, 0,0x4C74, 0, 0, 0,
+0x4C75, 0,0x4C76,0x4C77, 0, 0, 0,0x4C78,
+ 0, 0, 0, 0,0x4C79, 0, 0, 0,
+ 0, 0,0x4C7A,0x4C7B,0x4C7C, 0, 0,0x4C7D,
+ 0,0x7450, 0, 0, 0, 0,0x4C7E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4D21, 0, 0, 0,0x4D22,0x4D23,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4D24,0x4D25, 0, 0,0x4D26, 0, 0,0x4D27,
+ 0,0x4D28,0x4D29, 0, 0, 0, 0,0x4D2A,
+ 0, 0, 0, 0, 0, 0,0x4D2B, 0,
+ 0,0x4D2C, 0, 0, 0,0x4D2D,0x4D2E,0x4D2F,
+0x4D30, 0, 0,0x4D31, 0, 0, 0,0x4D32,
+0x4D33, 0, 0, 0, 0, 0,0x4D34, 0,
+0x4D35, 0,0x4D36, 0, 0, 0, 0,0x4D37,
+ 0, 0, 0, 0, 0, 0,0x4D38,0x4D39,
+ 0,0x4D3A, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x4D3B,
+ 0,0x4D3C, 0, 0, 0, 0, 0, 0,
+ 0,0x4D3D,0x4D3E,0x4D3F,0x4D40,0x4D41,0x4D42, 0,
+ 0,0x4D43, 0, 0, 0,0x4D44, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x4D45, 0,0x4D46,0x4D47, 0,0x4D48, 0, 0,
+ 0,0x4D49, 0, 0,0x4D4A, 0, 0, 0,
+ 0, 0,0x4D4B, 0,0x4D4C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4D4D, 0, 0, 0,
+ 0, 0,0x4D4E, 0, 0, 0, 0,0x4D4F,
+0x4D50,0x4D51, 0, 0,0x4D52, 0,0x4D53, 0,
+ 0, 0, 0, 0,0x4D54, 0,0x4D55,0x4D56,
+ 0, 0, 0, 0, 0, 0, 0,0x4D57,
+ 0, 0, 0, 0,0x4D58, 0, 0,0x4D59,
+0x4D5A,0x4D5B, 0, 0,0x4D5C, 0, 0,0x4D5D,
+ 0, 0, 0, 0,0x4D5E, 0,0x4D5F,0x4D60,
+ 0,0x4D61, 0, 0, 0, 0, 0, 0,
+ 0,0x4D62, 0, 0, 0, 0, 0, 0,
+0x4D63, 0,0x4D64,0x4D65,0x4D66, 0, 0,0x4D67,
+0x4D68, 0,0x4D69, 0,0x4D6A, 0, 0,0x4D6B,
+ 0, 0,0x4D6C,0x4D6D, 0,0x4D6E,0x4D6F, 0,
+ 0,0x4D70, 0,0x4D71,0x4D72,0x4D73,0x4D74, 0,
+ 0, 0, 0,0x4D75, 0,0x4D76,0x4D77, 0,
+ 0,0x4D78, 0, 0, 0,0x4D79, 0, 0,
+ 0, 0,0x4D7A,0x4D7B, 0,0x4D7C, 0, 0,
+0x4D7D,0x4D7E,0x4E21, 0,0x4E22, 0, 0, 0,
+0x4E24,0x4E25, 0,0x4E26,0x4E27,0x4E28, 0, 0,
+ 0,0x4E29,0x4E23,0x4E2A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4E2B, 0, 0,
+ 0,0x4E2C, 0, 0, 0, 0, 0,0x4E2D,
+ 0, 0, 0, 0,0x4E2E,0x4E2F, 0, 0,
+ 0, 0, 0, 0, 0,0x4E30,0x4E31,0x4E32,
+ 0,0x4E33, 0, 0,0x4E34, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x4E35,0x7451, 0, 0,0x4E36, 0, 0,
+ 0, 0, 0, 0,0x4E37,0x4E38, 0, 0,
+ 0, 0, 0, 0, 0,0x4E39, 0, 0,
+ 0, 0, 0,0x4E3A,0x4E3B,0x4E3C,0x7452,0x4E3D,
+0x4E3E, 0,0x4E3F,0x4E40,0x4E41,0x4E42,0x4E43,0x4E44,
+0x4E45, 0,0x4E46, 0, 0,0x4E47, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4E48, 0, 0,
+ 0,0x4E49, 0, 0, 0,0x4E4A, 0, 0,
+ 0,0x4E4B, 0,0x4E4C,0x4E4D, 0,0x4E4E, 0,
+ 0, 0, 0, 0,0x4E4F, 0, 0, 0,
+ 0,0x4E50, 0, 0, 0, 0, 0, 0,
+0x4E51, 0, 0, 0, 0, 0,0x4E52, 0,
+0x4E53, 0, 0, 0,0x4E54, 0, 0, 0,
+0x4E55,0x4E56, 0, 0, 0, 0,0x4E57, 0,
+ 0,0x4E58, 0, 0,0x4E59, 0, 0, 0,
+0x4E5A, 0, 0, 0, 0, 0,0x4E5B, 0,
+ 0, 0,0x4E5C, 0, 0, 0,0x4E5D, 0,
+ 0, 0,0x4E5E, 0,0x4E5F,0x4E60, 0,0x4E61,
+ 0,0x4E62,0x4E63, 0,0x4E64, 0, 0, 0,
+ 0, 0,0x4E65, 0, 0, 0, 0, 0,
+0x4E66, 0, 0, 0, 0,0x4E67,0x4E68,0x4E69,
+ 0, 0, 0, 0,0x4E6A,0x4E6B,0x4E6C, 0,
+ 0,0x4E6D, 0, 0, 0,0x4E6E,0x4E6F, 0,
+ 0, 0,0x4E70, 0, 0,0x4E71,0x4E72, 0,
+ 0, 0,0x4E73, 0, 0,0x4E74,0x4E75,0x4E76,
+ 0, 0,0x4E77, 0, 0, 0,0x4E78,0x4E79,
+ 0, 0, 0, 0,0x4E7A, 0,0x4E7B,0x4E7C,
+0x4E7D, 0,0x4E7E, 0,0x4F21, 0, 0,0x4F22,
+ 0, 0,0x4F23, 0,0x4F24, 0, 0, 0,
+0x4F25, 0,0x4F26,0x4F27,0x4F28, 0, 0, 0,
+ 0, 0,0x4F29, 0, 0,0x4F2A, 0, 0,
+0x4F2B, 0, 0, 0,0x4F2C, 0, 0, 0,
+ 0, 0, 0, 0,0x4F2D,0x4F2E, 0, 0,
+ 0, 0, 0, 0,0x4F2F,0x4F30,0x4F31, 0,
+ 0, 0,0x4F32, 0, 0, 0, 0,0x4F33,
+ 0, 0,0x4F34, 0, 0, 0, 0,0x4F35,
+ 0, 0,0x4F36, 0, 0, 0,0x4F37,0x4F38,
+ 0,0x4F39, 0, 0, 0,0x4F3A, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x4F3B, 0,
+ 0, 0, 0,0x4F3C, 0, 0, 0, 0,
+ 0,0x4F3D, 0, 0, 0, 0, 0, 0,
+ 0,0x4F3E,0x4F3F, 0, 0,0x4F40, 0, 0,
+ 0,0x4F41, 0, 0, 0, 0,0x4F42,0x4F43,
+0x4F44, 0, 0, 0,0x4F45, 0,0x4F46, 0,
+ 0, 0,0x4F47, 0,0x4F48, 0, 0, 0,
+0x4F49,0x4F4A, 0, 0,0x4F4B, 0, 0, 0,
+0x4F4C, 0, 0,0x4F4D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4F4E,0x4F4F, 0,
+ 0,0x4F50, 0, 0, 0,0x4F51,0x4F52, 0,
+ 0,0x4F53, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4F54, 0, 0,
+ 0,0x4F55,0x4F56,0x4F57, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x4F58,0x4F59, 0,
+0x4F5A, 0, 0, 0, 0,0x4F5B, 0,0x4F5C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x4F5D,0x4F5E, 0, 0,0x4F5F,
+0x4F60, 0, 0, 0,0x4F61, 0,0x4F62, 0,
+ 0, 0,0x4F63, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x4F64, 0,0x4F65, 0,
+0x4F66,0x4F67, 0,0x4F68,0x4F69, 0, 0, 0,
+0x4F6A, 0,0x4F6B, 0, 0, 0,0x4F6C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4F6D, 0, 0, 0,0x4F6E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x4F6F, 0, 0, 0, 0,0x4F70,
+ 0, 0, 0, 0,0x4F71, 0, 0, 0,
+0x4F72, 0, 0, 0, 0,0x4F74,0x4F75,0x4F76,
+ 0,0x4F73, 0, 0,0x4F77, 0, 0, 0,
+0x4F78, 0, 0, 0,0x4F79,0x4F7A, 0, 0,
+0x4F7B,0x4F7C,0x4F7D,0x4F7E, 0, 0, 0, 0,
+ 0, 0, 0,0x5021, 0,0x5022, 0,0x5023,
+ 0, 0, 0, 0, 0, 0, 0,0x5024,
+0x5025,0x5026, 0, 0,0x5027, 0,0x5028, 0,
+ 0, 0,0x5029,0x502A, 0,0x502B,0x502C, 0,
+ 0, 0, 0,0x502E, 0, 0, 0,0x502F,
+0x5030,0x5031, 0, 0,0x502D, 0,0x5032, 0,
+ 0, 0,0x5033, 0, 0, 0, 0, 0,
+ 0, 0,0x5034,0x5035, 0, 0,0x5037,0x5038,
+ 0, 0,0x5039,0x503A, 0, 0, 0,0x503B,
+0x5036, 0, 0, 0, 0, 0,0x503C, 0,
+ 0, 0, 0, 0,0x503D, 0, 0, 0,
+0x503E, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x503F, 0,0x5040, 0,0x5041,0x5042,
+0x5043, 0, 0, 0, 0,0x5044, 0,0x5045,
+ 0,0x5046, 0, 0, 0,0x5047, 0, 0,
+0x7454,0x5048, 0, 0,0x5049,0x504A, 0, 0,
+ 0, 0, 0,0x504B, 0,0x504C, 0,0x504D,
+ 0, 0, 0, 0,0x504E,0x504F,0x5050, 0,
+ 0, 0,0x5051,0x5052, 0, 0, 0,0x5053,
+ 0,0x5054, 0, 0,0x5055, 0, 0, 0,
+0x5056, 0, 0,0x5057,0x5058, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5059,
+ 0,0x505A, 0,0x505B, 0, 0, 0, 0,
+ 0, 0,0x505C, 0, 0, 0, 0, 0,
+ 0,0x505D, 0,0x505E,0x505F, 0,0x5060, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5061,0x5062, 0, 0, 0,
+ 0,0x5063, 0,0x5064,0x5065,0x5066,0x5067, 0,
+0x5068, 0, 0,0x5069,0x506A, 0, 0, 0,
+ 0,0x506B, 0, 0, 0, 0, 0, 0,
+0x506C,0x506D, 0,0x506E, 0, 0, 0,0x506F,
+ 0,0x5070, 0, 0,0x5071, 0, 0, 0,
+0x5072, 0, 0,0x5073, 0, 0, 0, 0,
+ 0, 0,0x5074, 0,0x5075, 0, 0,0x5076,
+0x5077, 0,0x5078, 0, 0, 0, 0,0x5079,
+ 0, 0, 0, 0,0x507A, 0,0x507B, 0,
+ 0, 0,0x507C, 0, 0,0x507D,0x507E, 0,
+0x5121, 0,0x5122, 0, 0,0x5123, 0, 0,
+ 0, 0,0x5124,0x5125, 0,0x5126, 0, 0,
+ 0,0x5127, 0, 0, 0, 0, 0, 0,
+0x5128, 0, 0, 0,0x5129, 0, 0, 0,
+ 0, 0,0x512A,0x512B, 0, 0, 0,0x512C,
+ 0,0x512D,0x512E, 0,0x512F, 0, 0, 0,
+ 0,0x5130, 0, 0, 0,0x5131, 0, 0,
+ 0, 0, 0,0x5132, 0, 0,0x5133, 0,
+ 0,0x5134, 0, 0, 0, 0, 0,0x5135,
+ 0, 0, 0,0x5136, 0,0x5137, 0,0x5138,
+0x5139, 0, 0, 0,0x513A,0x513B, 0, 0,
+0x513C,0x513D,0x513E, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x513F,0x5140, 0,0x5141,
+0x5142, 0, 0, 0,0x5143, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5144,0x5145, 0,
+ 0,0x5146, 0, 0,0x5147,0x5148, 0,0x5149,
+0x514A, 0, 0, 0, 0,0x514B, 0,0x514C,
+ 0, 0,0x514D, 0, 0,0x514E, 0, 0,
+ 0, 0, 0, 0, 0,0x514F, 0, 0,
+0x5150, 0, 0, 0, 0, 0,0x5151, 0,
+0x5152, 0,0x5153, 0, 0,0x5154,0x5155, 0,
+ 0, 0,0x5156,0x5157, 0, 0, 0, 0,
+0x5158,0x5159, 0, 0,0x515A, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x515B, 0,
+0x515C, 0, 0,0x515D, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x515E, 0, 0, 0,
+ 0, 0, 0,0x515F, 0,0x5160, 0, 0,
+ 0,0x5161, 0,0x5162,0x5163, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5164, 0,
+ 0,0x5165, 0, 0,0x5166, 0,0x5167, 0,
+ 0,0x5168, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5169, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x7459,
+0x516A,0x516B, 0,0x516C,0x516D, 0, 0, 0,
+ 0,0x516E, 0, 0,0x516F, 0, 0, 0,
+ 0, 0, 0,0x5170, 0,0x5171,0x5172, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5173,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x5174, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5175,
+ 0, 0, 0,0x5176, 0, 0, 0,0x5177,
+ 0,0x5178,0x5179,0x517A, 0,0x517B,0x517C,0x517D,
+0x517E,0x5221, 0, 0,0x5222, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5223, 0,0x5224,
+0x5225,0x5226, 0, 0, 0, 0, 0,0x5227,
+ 0, 0, 0, 0, 0, 0,0x5228, 0,
+ 0, 0, 0, 0, 0,0x5229, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x522A, 0, 0, 0,0x522B, 0,0x522C, 0,
+ 0,0x522D,0x522E, 0, 0,0x522F, 0,0x5230,
+ 0, 0,0x5231,0x5232, 0, 0, 0,0x5233,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x5234, 0, 0, 0,
+ 0,0x5235, 0, 0, 0, 0,0x5236, 0,
+0x5237,0x5238, 0, 0, 0, 0,0x5239, 0,
+ 0, 0, 0,0x523A, 0, 0,0x523B, 0,
+0x523C, 0, 0, 0, 0,0x523D, 0, 0,
+ 0, 0, 0, 0,0x523E, 0, 0,0x523F,
+0x5240, 0,0x5241, 0, 0,0x5242,0x5243, 0,
+ 0, 0,0x5244,0x5245,0x5246,0x5247, 0, 0,
+ 0, 0,0x5248, 0, 0,0x5249, 0, 0,
+0x524A, 0,0x524B, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x524C, 0,0x524D,0x524E,
+ 0,0x524F,0x5250,0x5251, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5252, 0,0x5253, 0, 0, 0, 0, 0,
+ 0, 0,0x5254, 0,0x5255,0x5256, 0, 0,
+0x5257,0x5258,0x5259, 0,0x525A, 0,0x525B, 0,
+ 0,0x525C,0x525D,0x525E,0x525F, 0,0x5260, 0,
+ 0,0x5261, 0,0x5262,0x5263, 0,0x5264,0x5265,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5266, 0,0x5267, 0, 0, 0, 0,
+0x5268, 0, 0, 0, 0,0x5269,0x526A, 0,
+0x526B, 0, 0, 0,0x526C, 0, 0, 0,
+ 0,0x526D, 0,0x526E,0x526F, 0,0x5270, 0,
+ 0,0x5271,0x5272, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5273, 0,
+ 0, 0,0x5274, 0, 0, 0, 0, 0,
+ 0,0x5276,0x5277,0x5278, 0,0x5275, 0, 0,
+ 0,0x5279,0x527A,0x527B,0x527C,0x527D,0x527E, 0,
+ 0,0x5321, 0,0x5322, 0, 0, 0,0x5323,
+ 0,0x5324, 0, 0, 0,0x5325,0x5326, 0,
+0x5327, 0,0x5328, 0, 0, 0, 0, 0,
+ 0,0x5329, 0, 0,0x532A,0x532B, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x532C,0x532D,
+ 0, 0, 0, 0, 0, 0, 0,0x532E,
+ 0, 0, 0, 0,0x532F, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5330, 0,
+0x5331, 0, 0, 0, 0, 0,0x5332, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5333, 0, 0, 0, 0, 0,0x5334,0x5335,
+ 0, 0,0x5336,0x5337,0x5338, 0, 0,0x5339,
+ 0, 0, 0, 0,0x533A, 0, 0,0x533B,
+0x533C,0x533D, 0, 0, 0,0x533E, 0,0x533F,
+ 0, 0, 0,0x5340,0x5341,0x5342, 0,0x5343,
+ 0,0x5344,0x5345, 0, 0,0x5346, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5347, 0,
+ 0,0x5348, 0,0x5349, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x534A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x534B, 0, 0, 0,0x534C,
+0x534D,0x534E, 0, 0, 0, 0, 0,0x534F,
+ 0,0x5350,0x5351,0x5352, 0, 0,0x5353, 0,
+ 0, 0, 0, 0, 0,0x5354,0x5355, 0,
+ 0, 0, 0,0x5356, 0, 0,0x5357, 0,
+ 0, 0,0x5358, 0, 0,0x5359, 0, 0,
+ 0,0x535A, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x535B,0x535C,0x535D, 0,
+0x535E,0x535F, 0, 0, 0, 0, 0,0x5360,
+0x5361, 0, 0, 0, 0,0x5362, 0, 0,
+ 0,0x5363, 0,0x5364, 0, 0, 0,0x5365,
+ 0,0x5366,0x5367, 0,0x5368,0x5369, 0, 0,
+ 0, 0, 0, 0, 0,0x536A, 0,0x536B,
+ 0, 0,0x536C, 0, 0, 0, 0, 0,
+0x536D, 0, 0, 0, 0, 0, 0, 0,
+0x536E, 0,0x536F,0x5370, 0, 0, 0,0x5371,
+ 0,0x5372,0x5373,0x5374, 0,0x5375,0x5376, 0,
+0x5377, 0, 0,0x5378,0x5379,0x537A, 0, 0,
+ 0,0x537B, 0, 0, 0, 0,0x537C,0x537D,
+ 0, 0, 0, 0, 0,0x537E,0x5421, 0,
+0x745C, 0, 0, 0, 0, 0,0x5422,0x5423,
+ 0, 0,0x5424, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5425, 0, 0,0x5426,0x5427,
+ 0,0x5428, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5429,0x542A,0x542B,0x542C,0x542D, 0,
+ 0, 0, 0, 0,0x542E,0x542F,0x5430, 0,
+ 0, 0, 0, 0, 0, 0,0x745D,0x5431,
+ 0,0x5432, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5434, 0, 0,0x5435,0x5436, 0,
+ 0, 0,0x5437,0x5438, 0,0x5439, 0, 0,
+ 0,0x543A, 0, 0, 0,0x543B,0x543C, 0,
+ 0,0x543D,0x543E, 0, 0, 0, 0, 0,
+0x5433, 0, 0, 0, 0, 0, 0, 0,
+0x543F, 0, 0, 0, 0, 0, 0, 0,
+0x5440,0x5441, 0, 0, 0,0x5442, 0,0x5443,
+ 0, 0, 0, 0,0x5444,0x5445, 0, 0,
+0x5446, 0, 0, 0, 0, 0, 0,0x5447,
+0x5448, 0, 0, 0,0x5449,0x544A, 0,0x544B,
+ 0, 0, 0,0x544C, 0, 0,0x544D, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x544E,
+ 0, 0, 0, 0,0x544F,0x5450, 0,0x5451,
+ 0, 0, 0, 0, 0, 0,0x5452, 0,
+0x5453, 0,0x5454, 0, 0, 0, 0, 0,
+0x5455, 0, 0, 0, 0, 0, 0,0x5456,
+ 0,0x5457,0x5458, 0, 0,0x5459, 0, 0,
+ 0, 0, 0,0x545A, 0, 0,0x545B,0x545C,
+ 0, 0, 0,0x545D, 0, 0, 0, 0,
+0x545E, 0, 0, 0, 0, 0,0x545F, 0,
+ 0,0x5460, 0, 0, 0, 0,0x5461,0x5462,
+ 0, 0,0x5463, 0, 0,0x5464, 0, 0,
+ 0,0x5465, 0, 0, 0,0x5466, 0, 0,
+0x5467, 0,0x5468, 0, 0,0x5469,0x546A};
+
+/* page 28 0x7F3B-0x8044 */
+static uint16 tab_uni_jisx021228[]={
+0x546C,0x546B,0x546D,0x546E,0x546F, 0, 0, 0,
+0x5470,0x5471, 0, 0,0x5472, 0, 0, 0,
+ 0, 0, 0, 0,0x5473, 0, 0,0x5474,
+0x5475, 0, 0, 0, 0, 0, 0, 0,
+0x5476,0x5477,0x5478, 0, 0, 0,0x5479, 0,
+0x547A,0x547B,0x547C,0x547D, 0, 0, 0, 0,
+ 0, 0,0x547E, 0, 0, 0,0x5521, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5522,0x5523,0x5524,0x5525, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5526, 0,0x5527, 0,0x5528,0x5529,0x552A, 0,
+ 0, 0, 0,0x552B,0x552C, 0, 0, 0,
+ 0,0x552D, 0, 0, 0, 0,0x552E,0x552F,
+ 0, 0, 0,0x5530, 0, 0, 0,0x5531,
+ 0, 0,0x5532, 0, 0, 0, 0, 0,
+ 0,0x5533, 0, 0, 0, 0, 0, 0,
+ 0,0x5534, 0, 0,0x5535,0x5536, 0, 0,
+0x5537, 0, 0, 0, 0,0x5538, 0, 0,
+ 0, 0, 0,0x5539,0x553A, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x553B, 0, 0, 0,0x553C, 0, 0, 0,
+0x553D, 0,0x553E, 0, 0,0x553F, 0, 0,
+ 0,0x5540, 0,0x5541,0x5542, 0, 0,0x5543,
+ 0, 0, 0, 0, 0, 0, 0,0x5544,
+ 0, 0,0x5545,0x5546,0x5547, 0, 0, 0,
+ 0, 0, 0, 0,0x5548,0x5549, 0,0x554A,
+ 0, 0,0x554B,0x554C,0x554D, 0,0x554E, 0,
+0x554F,0x5550, 0,0x5551, 0, 0, 0, 0,
+ 0, 0,0x5552,0x5553,0x5554,0x5555, 0, 0,
+ 0,0x5556, 0,0x5557, 0, 0, 0, 0,
+ 0,0x5558, 0,0x5559, 0,0x555A, 0, 0,
+ 0,0x555B,0x555C, 0,0x555D, 0,0x555E,0x555F,
+ 0,0x5560, 0,0x5561, 0,0x5562, 0, 0,
+ 0,0x5563};
+
+/* page 29 0x8060-0x8362 */
+static uint16 tab_uni_jisx021229[]={
+0x5564, 0, 0, 0,0x5565, 0,0x5566, 0,
+ 0, 0, 0, 0, 0,0x5567, 0, 0,
+ 0,0x5568, 0, 0, 0,0x5569, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x556A, 0, 0, 0, 0, 0, 0,
+0x556B, 0, 0, 0, 0, 0,0x556C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x556D, 0,0x556E, 0,
+ 0, 0, 0, 0, 0, 0,0x556F,0x5570,
+ 0, 0, 0,0x5571, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5572,0x5573, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5574, 0, 0, 0, 0,0x5575, 0,0x5576,
+ 0, 0,0x5577, 0,0x5578,0x5579, 0,0x557A,
+0x557B, 0, 0, 0, 0, 0, 0, 0,
+0x557C, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x557D,0x557E, 0,
+0x5621, 0,0x5622,0x5623, 0, 0,0x5624, 0,
+ 0,0x5625,0x5626, 0, 0, 0,0x5627, 0,
+ 0, 0, 0,0x5628, 0, 0, 0, 0,
+ 0, 0, 0,0x5629, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x562A,0x562B,
+0x562C, 0, 0, 0,0x562D, 0,0x562E, 0,
+0x562F, 0, 0, 0,0x5630, 0, 0,0x5631,
+ 0, 0, 0, 0,0x5632, 0, 0, 0,
+0x5633, 0, 0, 0, 0,0x5634, 0, 0,
+ 0, 0,0x5635, 0,0x5636, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5637, 0,0x5638,
+ 0, 0,0x5639, 0,0x563A, 0, 0, 0,
+ 0, 0,0x563B, 0, 0, 0, 0,0x563C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x563D,0x563E, 0, 0, 0, 0, 0,0x563F,
+0x5640,0x5641, 0, 0, 0,0x5642, 0,0x5643,
+ 0, 0, 0, 0, 0, 0, 0,0x5644,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5645, 0, 0,0x5647,0x5648,0x5649, 0,
+ 0, 0, 0,0x564A, 0, 0,0x564B, 0,
+0x5646, 0, 0, 0, 0, 0,0x564C, 0,
+0x564D, 0, 0,0x564E, 0, 0,0x564F, 0,
+ 0, 0,0x5650, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5651, 0,
+ 0, 0,0x5652, 0,0x5653, 0, 0, 0,
+ 0, 0, 0,0x5654, 0, 0, 0, 0,
+ 0, 0, 0,0x5656, 0,0x5657, 0, 0,
+ 0, 0,0x5658,0x5655, 0, 0,0x5659,0x565A,
+ 0, 0, 0, 0, 0,0x565B, 0,0x565C,
+ 0, 0, 0,0x565D, 0,0x565E,0x565F, 0,
+ 0,0x5660, 0, 0,0x5661, 0, 0, 0,
+ 0, 0, 0,0x5662,0x5663, 0, 0, 0,
+0x5664,0x5665,0x5666, 0, 0,0x5667,0x5668, 0,
+0x5669,0x566A, 0, 0, 0,0x566B, 0,0x566C,
+0x566D, 0, 0,0x566E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x566F,
+ 0, 0, 0,0x5670,0x5671, 0, 0, 0,
+ 0,0x5672,0x5673, 0, 0,0x5674, 0, 0,
+ 0,0x5675,0x5676, 0, 0, 0, 0, 0,
+0x5677, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5678, 0,0x5679, 0, 0, 0,
+ 0, 0,0x567A, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x567B,0x567C,0x567D,0x567E, 0,
+ 0, 0, 0,0x5721, 0, 0,0x5722,0x5723,
+ 0,0x5724, 0, 0, 0, 0,0x5725, 0,
+ 0, 0, 0, 0,0x5726, 0, 0, 0,
+0x5727, 0, 0,0x5728, 0, 0, 0,0x5729,
+ 0, 0, 0, 0, 0,0x572A, 0, 0,
+ 0, 0, 0, 0,0x572B, 0, 0, 0,
+ 0, 0, 0,0x572C, 0,0x572D, 0,0x572E,
+0x572F,0x5730, 0,0x5731,0x5732, 0, 0,0x5733,
+ 0,0x5734,0x5735, 0, 0, 0,0x5736, 0,
+ 0,0x5737, 0, 0,0x5738, 0,0x5739, 0,
+0x573A, 0,0x573B,0x573C, 0, 0, 0, 0,
+0x573D,0x573E, 0,0x573F,0x5740, 0, 0,0x5741,
+0x5742,0x5743,0x5744, 0, 0, 0,0x5745, 0,
+0x5746, 0,0x5747, 0,0x5748, 0, 0,0x5749,
+ 0, 0,0x574A, 0,0x574B, 0,0x574C,0x574D,
+ 0, 0, 0, 0, 0, 0,0x574E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x574F, 0, 0, 0, 0,0x5750, 0, 0,
+ 0, 0,0x5751, 0, 0, 0, 0, 0,
+0x5752, 0,0x5753, 0,0x5754, 0, 0, 0,
+0x5755, 0,0x5756, 0, 0,0x5757, 0,0x5758,
+ 0, 0, 0, 0, 0, 0,0x5759,0x575A,
+ 0, 0, 0, 0, 0,0x575B,0x575C, 0,
+0x575D,0x575E, 0, 0, 0, 0, 0,0x575F,
+0x5760, 0,0x5761,0x5762, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5764, 0,0x5765,0x5766,0x5767,
+ 0,0x5768,0x5769, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x576A,0x576B,0x576C, 0,
+0x576D, 0, 0,0x576E, 0, 0, 0,0x576F,
+ 0, 0,0x5770, 0,0x5771,0x5772, 0, 0,
+ 0, 0,0x5773,0x5774,0x5775, 0, 0,0x5776,
+ 0, 0, 0, 0, 0,0x5777,0x5778, 0,
+ 0,0x5779, 0,0x583E,0x5763,0x577A,0x577B,0x577C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x745F};
+
+/* page 30 0x8370-0x8419 */
+static uint16 tab_uni_jisx021230[]={
+0x577D, 0, 0, 0, 0, 0, 0, 0,
+0x577E, 0, 0, 0, 0,0x5821, 0,0x5822,
+0x5823, 0,0x5824, 0,0x5825, 0,0x5826, 0,
+ 0, 0, 0, 0, 0,0x5827, 0, 0,
+ 0, 0,0x5828, 0,0x5829,0x582A, 0, 0,
+0x582B,0x582C, 0,0x582D,0x582E,0x582F, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5830,0x5831,
+ 0,0x5832, 0, 0,0x5833,0x584C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5834,0x5835,
+0x5836, 0, 0, 0, 0, 0, 0,0x5837,
+ 0,0x5838, 0, 0, 0, 0, 0,0x5839,
+0x583A,0x583B, 0, 0,0x583C, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x583D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x583F, 0,0x5840, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x5841, 0,
+0x5842,0x5843, 0, 0,0x5844, 0, 0, 0,
+ 0,0x5845, 0, 0, 0, 0,0x5846, 0,
+ 0, 0,0x5847, 0, 0, 0, 0,0x5848,
+ 0,0x5849, 0, 0, 0,0x584A, 0, 0,
+ 0,0x584B};
+
+/* page 31 0x842F-0x8880 */
+static uint16 tab_uni_jisx021231[]={
+0x584D, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x584E, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x584F, 0,
+0x5850,0x5851, 0,0x5852, 0, 0,0x5853, 0,
+0x5854, 0,0x5855,0x5856, 0, 0, 0,0x5857,
+ 0,0x5858,0x5859,0x585A, 0,0x585B, 0, 0,
+ 0,0x585C, 0, 0, 0,0x585D,0x585E, 0,
+0x585F, 0, 0,0x5860, 0, 0, 0, 0,
+ 0,0x5861, 0, 0,0x5862,0x5863, 0,0x5864,
+ 0,0x5865, 0, 0, 0,0x5866,0x5867, 0,
+ 0, 0,0x5868, 0, 0, 0,0x5869, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x586A,0x586B, 0,0x586C, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x586D,
+ 0, 0, 0, 0, 0, 0, 0,0x586E,
+ 0,0x586F,0x5870,0x5871, 0, 0, 0, 0,
+0x5872, 0,0x5873, 0, 0,0x5874, 0, 0,
+ 0, 0, 0,0x5875, 0, 0,0x5876,0x5877,
+ 0,0x5878, 0,0x5879, 0, 0, 0, 0,
+0x587A,0x587B, 0, 0, 0,0x587C, 0, 0,
+0x587D, 0, 0, 0,0x587E, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5921, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5922, 0, 0,0x5923, 0, 0, 0, 0,
+0x5924,0x5925,0x5926,0x5927, 0, 0, 0, 0,
+0x5928, 0, 0,0x592A,0x592B, 0,0x592C, 0,
+ 0, 0, 0,0x592D,0x592E, 0, 0, 0,
+0x592F, 0, 0, 0, 0,0x5930, 0,0x5931,
+ 0,0x5932, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x5933, 0,0x5934,
+ 0, 0, 0,0x5935,0x5936,0x5937,0x5938, 0,
+0x5939, 0, 0,0x593A,0x593B, 0, 0, 0,
+0x593C, 0, 0,0x5929,0x593D,0x593E, 0,0x593F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5940, 0, 0, 0, 0, 0, 0,0x5941,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5942,0x5943,0x5944,0x5945,0x5946, 0, 0,0x5947,
+ 0, 0,0x5948, 0, 0,0x5949,0x594A,0x594B,
+0x594C,0x594D,0x594E,0x594F, 0,0x5950, 0, 0,
+ 0, 0, 0, 0,0x5951, 0, 0, 0,
+0x5952, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5953,0x5954,0x5955, 0,0x5956, 0,
+0x5957, 0,0x5958, 0, 0, 0,0x5959,0x595A,
+ 0, 0,0x595B, 0,0x595C,0x595D, 0, 0,
+0x595E, 0, 0, 0,0x595F, 0, 0, 0,
+ 0,0x5960, 0, 0, 0, 0,0x5961, 0,
+0x5962,0x5963, 0,0x5964, 0, 0,0x5965, 0,
+0x5966, 0, 0, 0, 0, 0,0x5974, 0,
+ 0,0x7461, 0, 0, 0,0x5967, 0,0x5968,
+0x5969,0x596A, 0, 0, 0,0x596B,0x596C,0x596D,
+0x596E, 0, 0,0x596F, 0, 0, 0, 0,
+0x5970, 0, 0,0x5971,0x5972, 0, 0,0x5973,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5975, 0,0x5976, 0, 0, 0, 0,
+0x5977,0x5978, 0, 0, 0, 0, 0,0x5979,
+ 0,0x597A, 0, 0, 0, 0,0x597B, 0,
+ 0, 0, 0, 0,0x597C, 0, 0,0x597D,
+ 0, 0, 0, 0, 0,0x597E, 0, 0,
+0x5A21,0x5A22, 0, 0, 0,0x5A23,0x5A24, 0,
+ 0, 0, 0, 0, 0, 0,0x5A25,0x5A26,
+ 0,0x5A27,0x5A28,0x5A29, 0, 0, 0, 0,
+ 0,0x5A2A,0x5A2B, 0,0x5A2C, 0, 0,0x5A2D,
+ 0, 0,0x5A2E, 0, 0, 0, 0, 0,
+0x5A2F, 0,0x5A30, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5A31,
+ 0,0x5A32, 0,0x5A33, 0,0x5A34,0x5A35, 0,
+ 0,0x5A36,0x3866,0x5A37, 0, 0, 0,0x5A38,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5A39,0x5A3A, 0, 0,0x5A3B,
+0x5A3C,0x5A3D,0x5A3E, 0, 0, 0,0x5A3F, 0,
+ 0,0x5A40,0x5A41,0x5A42,0x5A43,0x5A44, 0, 0,
+ 0, 0,0x5A45, 0, 0,0x5A46, 0, 0,
+0x5A47, 0, 0, 0, 0, 0,0x5A48,0x5A49,
+0x5A4A, 0, 0,0x5A4B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5A6D, 0, 0, 0, 0,0x5A4C, 0,
+ 0, 0,0x5A4D, 0, 0, 0, 0,0x5A4E,
+ 0,0x5A4F, 0,0x5A50, 0,0x5A51, 0, 0,
+ 0, 0,0x5A52, 0, 0, 0, 0,0x5A53,
+0x5A54,0x5A55, 0, 0, 0, 0,0x5A56, 0,
+ 0, 0,0x5A57, 0,0x5A58,0x5A59,0x5A5A, 0,
+0x5A5B,0x5A5C,0x5A5D, 0, 0, 0, 0, 0,
+0x5A5E,0x5A5F,0x5A60, 0,0x5A61, 0,0x5A62, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5A63,0x5A64, 0, 0,0x5A65, 0,
+0x5A66, 0, 0,0x5A67, 0,0x5A68, 0, 0,
+ 0,0x5A69, 0, 0,0x5A6A, 0,0x5A6B, 0,
+0x5A6C, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5A6E, 0,0x5A6F,0x5A70, 0,
+ 0, 0, 0, 0, 0,0x5A71,0x5A72, 0,
+0x5A73, 0, 0, 0,0x5A74, 0, 0,0x5A75,
+0x5A76,0x5A77, 0, 0,0x5A78,0x5A79, 0, 0,
+ 0, 0,0x5A7A, 0, 0, 0, 0,0x5A7B,
+0x5A7C, 0,0x5A7D, 0,0x5A7E, 0, 0, 0,
+ 0,0x5B21, 0, 0, 0, 0, 0,0x5B22,
+0x5B23, 0,0x5B24,0x5B25, 0, 0, 0, 0,
+ 0, 0,0x5B26,0x5B27, 0,0x5B28,0x5B29,0x5B2A,
+ 0,0x5B2B, 0, 0,0x5B2C, 0,0x5B2D, 0,
+ 0, 0, 0, 0, 0, 0,0x5B2E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5B2F, 0, 0, 0, 0,0x5B30, 0,
+ 0, 0,0x5B31, 0, 0,0x5B32,0x5B33, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5B34, 0,0x5B35,0x5B36, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x5B37, 0, 0, 0,
+ 0, 0, 0, 0,0x5B38,0x5B39,0x5B3A,0x5B3B,
+0x5B3C,0x5B3D,0x5B3E, 0,0x5B3F,0x5B40, 0, 0,
+ 0,0x5B41, 0, 0,0x5B42, 0,0x5B43, 0,
+0x5B44,0x5B45,0x5B46, 0, 0, 0, 0,0x5B47,
+ 0,0x5B48, 0, 0,0x5B49, 0, 0, 0,
+0x5B4A, 0, 0, 0, 0,0x5B4B,0x5B4C,0x5B4D,
+ 0, 0,0x5B4E, 0, 0, 0,0x5B4F, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5B50,
+0x5B51, 0,0x5B52, 0, 0, 0, 0, 0,
+ 0,0x5B53,0x5B54,0x5B55, 0, 0, 0,0x5B56,
+ 0, 0, 0, 0, 0, 0,0x5B57,0x5B58,
+ 0, 0,0x5B59,0x5B5A, 0,0x5B5B, 0, 0,
+0x5B5C, 0, 0,0x5B5D,0x5B5E,0x5B5F, 0, 0,
+ 0, 0, 0,0x5B60,0x5B61, 0,0x5B62, 0,
+ 0, 0,0x5B63, 0,0x5B64, 0, 0, 0,
+ 0,0x5B65, 0,0x5B66, 0, 0, 0, 0,
+0x5B67, 0,0x5B68, 0,0x5B69, 0, 0,0x5B6A,
+0x7464, 0,0x5B6B,0x5B6C,0x5B6D, 0, 0, 0,
+ 0,0x5B6E, 0,0x5B70,0x5B71,0x5B72, 0, 0,
+ 0,0x5B73,0x5B6F,0x5B74,0x5B75,0x5B76, 0,0x5B77,
+0x5B78, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5B79, 0, 0, 0, 0,0x5B7A,0x5B7B,
+ 0,0x5B7C, 0,0x5B7D, 0, 0,0x5B7E, 0,
+ 0, 0, 0,0x5C21, 0,0x5C22, 0, 0,
+ 0, 0,0x5C23, 0,0x5C24, 0,0x5C25, 0,
+ 0,0x5C26,0x5C27,0x5C28,0x5C29, 0, 0,0x5C2A,
+ 0, 0,0x5C2B, 0, 0, 0,0x5C2C,0x5C2D,
+ 0,0x5C2E, 0,0x5C2F, 0,0x5C30, 0, 0,
+0x5C31,0x5C32, 0, 0, 0,0x5C33, 0, 0,
+ 0, 0,0x5C34, 0, 0, 0, 0, 0,
+ 0, 0,0x5C35, 0, 0, 0, 0, 0,
+ 0, 0,0x5C36, 0,0x5C37, 0, 0, 0,
+ 0,0x5C38};
+
+/* page 32 0x8898-0x89BC */
+static uint16 tab_uni_jisx021232[]={
+0x5C39, 0,0x5C3A,0x5C3B,0x5C3C, 0, 0,0x5C3D,
+0x5C3E, 0, 0, 0, 0, 0, 0, 0,
+0x5C3F, 0,0x5C40, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5C41, 0, 0,0x5C42,0x5C43, 0,
+0x5C44, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5C45,0x5C46,0x5C47,0x5C48,0x5C49, 0,
+ 0,0x5C4A,0x5C4B,0x5C4C, 0, 0, 0, 0,
+ 0, 0, 0,0x5C4D, 0, 0,0x5C4E, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5C4F,
+ 0, 0, 0, 0, 0, 0, 0,0x5C50,
+0x5C51,0x5C52, 0, 0, 0,0x5C53, 0,0x5C54,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5C55, 0, 0, 0, 0,0x5C56, 0,
+ 0, 0, 0, 0, 0,0x5C57,0x5C58,0x5C59,
+ 0, 0, 0, 0, 0,0x5C5A,0x5C5B, 0,
+0x5C5C,0x5C5D,0x5C5E, 0,0x5C5F, 0, 0, 0,
+0x5C60, 0, 0, 0, 0, 0,0x5C61,0x5C62,
+0x5C63, 0, 0, 0, 0, 0, 0, 0,
+0x5C64,0x5C65,0x5C66, 0, 0,0x5C67, 0, 0,
+ 0,0x5C68,0x5C69, 0, 0, 0,0x5C6A, 0,
+0x5C6B, 0,0x5C6C, 0, 0,0x5C6D,0x5C6E, 0,
+ 0,0x5C6F, 0, 0, 0, 0, 0,0x5C70,
+ 0, 0,0x5C71, 0, 0, 0, 0,0x5C72,
+ 0, 0,0x5C73,0x5C74,0x5C75, 0, 0, 0,
+ 0,0x5C76,0x5C77,0x5C78, 0, 0, 0, 0,
+ 0, 0, 0,0x5C79, 0, 0,0x5C7A, 0,
+0x5C7B, 0, 0,0x5C7C, 0,0x5C7D, 0, 0,
+ 0, 0,0x5C7E,0x5D21,0x5D22,0x5D23, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5D24, 0, 0, 0,0x5D25, 0, 0,
+0x5D26, 0, 0, 0,0x5D27,0x5D28, 0, 0,
+ 0, 0, 0,0x5D29,0x5D2A, 0, 0,0x5D2B,
+0x5D2C, 0, 0, 0, 0,0x5D2D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5D2E, 0, 0, 0,0x5D2F,0x5D30,0x5D31,0x5D32,
+ 0, 0, 0, 0,0x5D33};
+
+/* page 33 0x89D4-0x8B9F */
+static uint16 tab_uni_jisx021233[]={
+0x5D34,0x5D35,0x5D36,0x5D37,0x5D38, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5D39, 0, 0, 0,0x5D3A, 0,0x5D3B,
+ 0,0x5D3C, 0, 0, 0,0x5D3D, 0,0x5D3E,
+ 0, 0,0x5D3F, 0, 0,0x5D40, 0, 0,
+ 0,0x5D41, 0,0x5D42, 0, 0, 0, 0,
+0x5D43,0x5D44, 0,0x5D45, 0, 0, 0, 0,
+ 0, 0, 0,0x5D46, 0,0x5D47,0x5D48, 0,
+0x5D49,0x5D4A, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5D4B, 0,0x5D4C, 0,0x5D4D, 0,
+0x5D4E, 0,0x5D4F, 0, 0, 0, 0,0x5D50,
+0x5D51, 0, 0,0x5D52, 0, 0, 0, 0,
+ 0,0x5D53, 0,0x5D54, 0, 0, 0, 0,
+ 0,0x5D55,0x5D56, 0,0x5D57, 0, 0,0x5D58,
+ 0,0x5D59, 0,0x5D5A, 0,0x5D5B, 0, 0,
+ 0,0x5D5C,0x5D5D, 0, 0, 0, 0,0x5D5E,
+ 0, 0,0x5D5F,0x5D60,0x5D61, 0, 0, 0,
+0x5D62,0x5D63, 0, 0, 0,0x5D64, 0, 0,
+ 0,0x5D65, 0,0x5D66, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5D67,0x5D68,0x5D69, 0,0x5D6A,0x5D6B,0x5D6C,
+ 0, 0,0x5D6D,0x5D6E,0x5D6F, 0, 0,0x5D70,
+ 0, 0,0x5D71, 0, 0, 0, 0,0x5D72,
+ 0, 0, 0,0x5D73,0x5D74, 0,0x5D75, 0,
+ 0, 0,0x5D76,0x5D77, 0,0x5D78, 0, 0,
+ 0, 0, 0,0x5D79, 0, 0, 0, 0,
+ 0, 0, 0,0x5D7A, 0,0x5D7B, 0, 0,
+ 0, 0,0x5D7C,0x5D7D, 0, 0, 0,0x5D7E,
+ 0, 0,0x5E21,0x5E22, 0, 0, 0,0x5E23,
+ 0, 0,0x5E24, 0, 0, 0, 0,0x5E25,
+ 0, 0,0x5E26, 0,0x5E27,0x5E28,0x5E29, 0,
+ 0, 0, 0, 0, 0,0x5E2A, 0,0x5E2B,
+0x5E2C,0x5E2D, 0,0x5E2E, 0, 0, 0, 0,
+ 0,0x5E2F, 0,0x5E30, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5E31, 0, 0, 0,0x5E32, 0, 0, 0,
+0x5E33,0x5E34,0x5E35, 0, 0, 0, 0, 0,
+0x5E36, 0, 0,0x5E37, 0, 0, 0, 0,
+ 0,0x5E38,0x5E39, 0, 0, 0,0x5E3F,0x5E3A,
+ 0, 0, 0, 0, 0,0x5E3B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5E3C, 0,0x5E3D,0x5E3E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5E40, 0, 0,0x5E41, 0, 0, 0,
+ 0, 0, 0,0x5E42, 0, 0, 0, 0,
+0x5E43, 0, 0, 0, 0, 0,0x5E44,0x5E45,
+0x5E46,0x5E47,0x5E48, 0,0x5E49, 0, 0, 0,
+ 0,0x5E4E, 0, 0, 0, 0,0x5E4A,0x5E4B,
+0x5E4C, 0, 0, 0, 0,0x5E4D, 0, 0,
+ 0, 0,0x5E4F, 0, 0, 0, 0,0x5E50,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5E51, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5E52, 0,0x5E53,0x5E54, 0, 0,
+0x5E55, 0,0x5E56,0x7466, 0,0x5E57, 0, 0,
+0x5E58,0x5E59, 0, 0, 0, 0, 0,0x5E5A,
+ 0,0x5E5B, 0,0x5E5C, 0, 0, 0, 0,
+0x5E5D,0x5E5E, 0, 0, 0, 0, 0, 0,
+0x5E5F, 0,0x5E60,0x5E61};
+
+/* page 34 0x8C38-0x8CA4 */
+static uint16 tab_uni_jisx021234[]={
+0x5E62,0x5E63, 0, 0, 0,0x5E64,0x5E65, 0,
+ 0, 0, 0, 0, 0,0x5E66, 0,0x5E67,
+ 0,0x5E68, 0,0x5E69, 0, 0, 0,0x5E6A,
+ 0,0x5E6B, 0,0x5E6C,0x5E6D, 0, 0,0x5E6E,
+0x5E6F,0x5E72, 0,0x5E70, 0,0x5E71, 0, 0,
+ 0, 0, 0,0x5E73,0x5E74, 0,0x5E75, 0,
+0x5E76,0x5E77, 0, 0, 0,0x5E78, 0, 0,
+ 0, 0, 0,0x5E79, 0,0x5E7A,0x5E7B, 0,
+ 0, 0, 0,0x5E7C, 0, 0,0x5E7D, 0,
+ 0, 0, 0, 0, 0, 0,0x5E7E,0x5F21,
+ 0, 0, 0,0x5F22, 0, 0, 0, 0,
+0x5F23, 0,0x5F24,0x5F25, 0, 0, 0, 0,
+ 0,0x5F26, 0,0x5F27,0x5F28, 0, 0, 0,
+ 0, 0, 0, 0,0x5F29};
+
+/* page 35 0x8CB9-0x8D1B */
+static uint16 tab_uni_jisx021235[]={
+0x5F2A,0x5F2B, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x5F2C,0x5F2D, 0, 0,
+0x5F2E, 0,0x5F2F, 0, 0, 0,0x5F30, 0,
+ 0, 0, 0, 0,0x5F32,0x5F31, 0, 0,
+0x5F33, 0, 0, 0,0x5F34, 0, 0, 0,
+0x5F35, 0, 0, 0, 0, 0, 0,0x5F36,
+ 0, 0, 0,0x5F37, 0, 0,0x5F38,0x5F39,
+ 0,0x5F3A, 0,0x7467,0x5F3B, 0,0x5F3C,0x5F3D,
+ 0, 0, 0, 0, 0,0x5F3E,0x5F3F, 0,
+0x5F40, 0,0x5F41, 0, 0, 0, 0, 0,
+0x5F42, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5F43, 0, 0, 0, 0,0x5F44, 0,
+ 0, 0,0x5F45};
+
+/* page 36 0x8D65-0x8F65 */
+static uint16 tab_uni_jisx021236[]={
+0x5F46, 0, 0, 0,0x5F47, 0, 0,0x5F48,
+ 0,0x5F49, 0, 0, 0, 0, 0, 0,
+ 0,0x7468, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x5F4A, 0, 0,0x5F4B, 0,0x5F4C,
+ 0, 0, 0,0x5F4D, 0, 0, 0, 0,
+0x5F4E, 0, 0,0x5F4F,0x5F50, 0, 0, 0,
+0x5F51, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x5F52,0x5F53,0x5F54, 0, 0, 0, 0,
+ 0,0x5F55, 0, 0, 0, 0,0x5F56,0x5F57,
+ 0, 0,0x5F58, 0, 0,0x5F59, 0, 0,
+0x5F5A, 0,0x5F5B, 0,0x5F5C, 0,0x5F5D,0x5F6F,
+ 0, 0, 0,0x5F5E, 0, 0, 0, 0,
+0x5F5F,0x5F60,0x5F61,0x5F62, 0,0x5F63, 0, 0,
+ 0,0x5F64, 0, 0,0x5F65, 0, 0,0x5F66,
+0x5F67, 0,0x5F68, 0,0x5F69, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x5F6A,
+0x5F6B, 0,0x5F6C, 0, 0, 0, 0,0x5F6D,
+ 0, 0, 0,0x5F6E,0x5F70,0x5F71, 0,0x5F72,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x5F73, 0, 0, 0,0x5F74, 0, 0,0x5F75,
+0x5F76,0x5F77, 0, 0, 0, 0,0x5F78, 0,
+ 0, 0, 0, 0,0x5F79, 0, 0,0x5F7A,
+ 0,0x5F7B, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x5F7C,0x5F7D,0x5F7E,0x6021, 0,
+ 0,0x6022,0x6023, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6024, 0,0x6025, 0,
+ 0,0x6026,0x6027,0x6028,0x6029, 0, 0, 0,
+0x602A, 0, 0,0x602B,0x602C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x602D, 0,
+0x602E,0x602F,0x6030, 0, 0, 0, 0,0x6031,
+ 0, 0, 0, 0, 0, 0,0x6032,0x6033,
+0x6034,0x6035, 0, 0,0x6036,0x6037, 0, 0,
+ 0, 0, 0, 0,0x6038, 0, 0,0x6039,
+0x603A, 0,0x603B,0x603C,0x603D, 0, 0, 0,
+ 0, 0, 0, 0,0x603E,0x603F,0x6040, 0,
+ 0, 0, 0, 0, 0,0x6041,0x6042, 0,
+ 0, 0, 0, 0,0x6043, 0, 0, 0,
+ 0, 0, 0,0x6044, 0,0x6045, 0, 0,
+0x6046, 0, 0, 0, 0,0x6047,0x6048, 0,
+0x6049,0x604A, 0, 0, 0,0x604B, 0, 0,
+ 0, 0,0x604C, 0,0x604D, 0, 0, 0,
+0x604E,0x604F, 0, 0, 0, 0,0x6050, 0,
+0x6051, 0, 0, 0, 0,0x6052,0x6053, 0,
+ 0, 0, 0,0x6054,0x6055, 0,0x6056,0x6057,
+ 0, 0,0x6058, 0, 0, 0, 0, 0,
+ 0, 0,0x6059, 0,0x605A, 0, 0,0x605B,
+ 0, 0, 0, 0, 0, 0, 0,0x605C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x605D, 0, 0, 0, 0,
+0x6064,0x605E, 0,0x605F,0x6060, 0, 0, 0,
+ 0, 0,0x6061, 0,0x6062,0x6063, 0, 0,
+ 0, 0, 0,0x6065, 0,0x6066, 0, 0,
+ 0, 0,0x6067,0x6068, 0, 0, 0, 0,
+ 0, 0,0x6069,0x606A, 0, 0, 0, 0,
+ 0,0x606B,0x606C,0x606D, 0, 0, 0, 0,
+ 0,0x606E, 0,0x606F,0x6070, 0,0x6071, 0,
+0x6072, 0,0x6073,0x6074, 0, 0, 0,0x6075,
+0x6076,0x6077, 0, 0, 0, 0, 0,0x6078,
+0x6079,0x607A,0x607B, 0, 0,0x607C, 0, 0,
+ 0, 0, 0,0x607D,0x607E, 0,0x6121, 0,
+ 0, 0,0x6122, 0, 0, 0, 0, 0,
+ 0, 0,0x6123, 0,0x6124,0x6125,0x6126,0x6127,
+0x6128, 0, 0,0x6129, 0, 0, 0, 0,
+0x612A,0x612B, 0, 0, 0, 0, 0, 0,
+0x612C};
+
+/* page 37 0x8F9D-0x9484 */
+static uint16 tab_uni_jisx021237[]={
+0x612D, 0, 0,0x612E,0x612F, 0, 0,0x6130,
+0x6131,0x6132, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6133,0x6134, 0,0x6135, 0, 0, 0, 0,
+ 0,0x6136, 0,0x6137,0x6138, 0, 0, 0,
+ 0,0x6139, 0, 0, 0,0x613A,0x613B, 0,
+0x613C, 0, 0,0x613D, 0,0x613E,0x613F, 0,
+0x6140, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6141, 0, 0,0x6142,0x6143,
+ 0, 0, 0,0x6144, 0, 0, 0, 0,
+ 0,0x6145, 0, 0,0x6146, 0, 0, 0,
+0x6147,0x6148, 0, 0, 0, 0,0x6149, 0,
+ 0,0x614A, 0, 0, 0,0x614B, 0,0x614C,
+ 0, 0, 0,0x614D, 0, 0, 0,0x614E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x614F, 0, 0,0x6150, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6151,0x6152,0x6154, 0,0x6155,
+0x6156, 0,0x6153, 0, 0, 0,0x6157,0x6158,
+ 0, 0,0x6159, 0, 0, 0, 0, 0,
+ 0, 0,0x615A, 0, 0, 0,0x615B,0x615C,
+ 0, 0, 0, 0, 0, 0, 0,0x615D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x615E, 0,
+0x615F, 0, 0, 0, 0,0x6160, 0, 0,
+ 0,0x6161,0x6162, 0, 0, 0, 0,0x6163,
+ 0, 0, 0,0x6164, 0, 0, 0,0x6165,
+ 0, 0, 0, 0,0x6166, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6167, 0, 0,0x6168, 0, 0,0x6169,0x616A,
+ 0,0x616B, 0,0x616C, 0, 0, 0, 0,
+0x616D, 0,0x616E,0x616F,0x6170, 0,0x6171, 0,
+ 0, 0, 0,0x6172,0x6173,0x6174, 0, 0,
+0x6175, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6176, 0,0x6177,0x6178,0x6179,
+ 0,0x617A, 0, 0, 0, 0, 0, 0,
+0x617B,0x617D, 0, 0, 0, 0,0x617E,0x6221,
+0x6222, 0,0x6223,0x6224, 0, 0, 0,0x617C,
+ 0, 0, 0, 0, 0,0x622D, 0, 0,
+0x6225, 0,0x6226,0x6227,0x6228, 0, 0,0x6229,
+0x622A,0x746C,0x622B, 0, 0, 0, 0, 0,
+0x622C, 0, 0, 0, 0, 0,0x622F, 0,
+ 0, 0,0x6230,0x6231, 0, 0, 0,0x6232,
+ 0,0x622E, 0, 0, 0, 0, 0, 0,
+ 0,0x6233,0x6234,0x6235, 0, 0, 0,0x6236,
+0x6237,0x6238, 0,0x6239, 0, 0, 0, 0,
+0x623A, 0, 0,0x623B, 0, 0, 0,0x623C,
+0x746E,0x623D,0x623E,0x623F, 0,0x6240, 0,0x6241,
+ 0,0x6242, 0,0x6243, 0,0x6245,0x6246, 0,
+0x6244, 0,0x6247, 0,0x6248, 0, 0, 0,
+ 0,0x6249,0x624A, 0,0x624B, 0, 0,0x624C,
+ 0,0x624D,0x624E, 0,0x624F,0x6250, 0,0x6251,
+0x6252, 0, 0, 0, 0, 0,0x6253, 0,
+ 0, 0,0x6254,0x6255, 0, 0, 0, 0,
+ 0, 0,0x6256, 0, 0, 0,0x6257, 0,
+ 0, 0,0x6258, 0,0x6259,0x625A,0x625B, 0,
+ 0, 0, 0, 0,0x625C, 0, 0,0x625D,
+ 0, 0,0x625E, 0, 0, 0, 0, 0,
+0x625F, 0, 0, 0, 0, 0, 0,0x6260,
+ 0, 0, 0, 0,0x6261,0x6262,0x6263, 0,
+ 0, 0, 0, 0,0x6264, 0,0x6265, 0,
+0x6266,0x6267, 0, 0, 0,0x6268, 0, 0,
+ 0,0x6269, 0, 0,0x626A, 0,0x626B,0x626C,
+0x626D, 0, 0,0x626E, 0, 0, 0, 0,
+ 0,0x626F, 0, 0,0x6270, 0, 0, 0,
+ 0,0x6271, 0,0x6272, 0, 0, 0,0x6273,
+0x6274,0x6275, 0,0x6276,0x6277,0x6278,0x6279, 0,
+ 0,0x627A, 0, 0, 0, 0,0x627B,0x627C,
+0x627D, 0,0x627E, 0, 0,0x6321,0x6322, 0,
+0x6323, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6324,0x6325,
+ 0, 0,0x6326, 0,0x6327,0x6328, 0, 0,
+ 0,0x6329, 0, 0, 0, 0, 0,0x632A,
+0x632B, 0, 0, 0,0x632C,0x632D, 0,0x632E,
+0x632F,0x6330,0x6331,0x6332,0x6333, 0, 0, 0,
+ 0, 0,0x6334, 0,0x6335, 0,0x6336, 0,
+0x6337, 0, 0,0x6338,0x6339, 0, 0,0x633A,
+0x633B,0x633C,0x633D, 0,0x633E,0x633F, 0,0x6340,
+ 0, 0, 0,0x6341, 0,0x6342,0x6343, 0,
+ 0,0x6344, 0,0x6345, 0, 0, 0,0x6346,
+0x6347, 0, 0, 0, 0, 0,0x6348,0x6349,
+0x634A,0x634B, 0,0x634C, 0, 0, 0, 0,
+ 0,0x634D,0x634E,0x634F, 0, 0,0x6350, 0,
+0x6351,0x6352, 0,0x6353,0x6354,0x6355, 0,0x6356,
+ 0,0x6357, 0,0x6358, 0,0x6359,0x635A, 0,
+ 0,0x635B,0x635C, 0, 0,0x635D, 0, 0,
+0x635E,0x635F,0x6360, 0,0x6361, 0, 0, 0,
+ 0, 0, 0,0x6362,0x6363, 0, 0,0x6364,
+0x6365, 0, 0,0x6366,0x6367, 0, 0, 0,
+0x6368, 0,0x6369,0x636A,0x636B, 0, 0, 0,
+ 0,0x636C,0x636D,0x636E, 0, 0, 0, 0,
+0x636F,0x6370,0x6371,0x6372,0x6373, 0,0x6374,0x6375,
+0x6376, 0,0x6377, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6378,0x6379,0x637A, 0, 0,
+0x637B,0x637C, 0, 0, 0,0x637D, 0, 0,
+ 0, 0,0x637E, 0,0x6421, 0, 0, 0,
+ 0, 0,0x6422,0x6423, 0, 0, 0,0x6424,
+0x6425, 0,0x6426,0x6427, 0, 0,0x6428, 0,
+ 0, 0,0x6429, 0, 0,0x642A, 0, 0,
+ 0,0x642B, 0,0x642C, 0,0x642D,0x642E,0x642F,
+0x6430, 0,0x6431,0x6432,0x6433,0x6434,0x6435, 0,
+0x6436,0x6437,0x6438,0x6439, 0, 0,0x643A,0x643B,
+0x643C,0x643D, 0,0x643E, 0, 0,0x643F, 0,
+0x6440, 0,0x6441,0x6442,0x6443, 0, 0,0x6444,
+0x6445, 0,0x6446,0x6447,0x6448, 0,0x6449, 0,
+0x644A, 0,0x644B,0x644C, 0, 0, 0,0x644D,
+ 0,0x644E, 0,0x644F, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6450, 0,0x6451, 0,
+ 0, 0,0x6452,0x6453, 0,0x6454, 0, 0,
+ 0, 0, 0,0x6455, 0, 0, 0, 0,
+0x6456, 0, 0, 0,0x6457, 0, 0,0x6458,
+0x6459, 0, 0, 0, 0, 0, 0,0x645A,
+0x645B,0x645C,0x645D, 0,0x645E, 0, 0,0x645F,
+0x6460, 0,0x6461, 0,0x6462,0x6463, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6464,0x6465,
+ 0,0x6466,0x6467, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6468,0x6469,0x646A, 0, 0, 0,
+ 0, 0, 0,0x646B,0x646C,0x646D, 0, 0,
+0x646E, 0,0x646F,0x6470, 0,0x6471, 0, 0,
+ 0,0x6472, 0, 0, 0, 0, 0,0x6473,
+0x6474, 0,0x6475, 0,0x6476,0x6477, 0, 0,
+0x6478, 0,0x6479,0x647A,0x647B, 0,0x647C,0x647D,
+ 0,0x647E, 0, 0, 0,0x6521, 0, 0,
+0x6522, 0,0x6523,0x6524,0x6525,0x6526, 0, 0,
+ 0, 0, 0,0x6527, 0,0x6528,0x6529, 0,
+0x652A, 0,0x652B, 0, 0,0x652C, 0, 0,
+0x652D, 0, 0,0x652E, 0, 0,0x652F, 0,
+ 0,0x6530, 0, 0,0x6531, 0,0x6532,0x6533,
+ 0,0x6534, 0,0x6535,0x653B, 0,0x6536, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x6537,
+0x6538,0x6539, 0, 0, 0,0x653A, 0, 0,
+ 0, 0, 0, 0,0x653C, 0, 0,0x653D,
+0x653E,0x653F,0x6540, 0,0x6541,0x6542,0x6543,0x6544,
+0x6545, 0, 0, 0, 0, 0,0x6546, 0,
+ 0, 0, 0, 0,0x6547, 0, 0,0x6548,
+ 0,0x6549,0x654A, 0, 0,0x654B, 0, 0,
+ 0,0x654C,0x654D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x654F,0x6550,0x654E,0x6551,0x6552, 0,
+0x6553, 0, 0, 0,0x6554,0x6555, 0,0x6556,
+ 0, 0, 0,0x6557,0x6558, 0, 0, 0,
+0x6559,0x655A,0x655B, 0, 0, 0, 0, 0,
+0x655C,0x655D,0x655E, 0, 0, 0, 0, 0,
+ 0, 0,0x655F, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6560,0x6561, 0,0x6562,0x6563,0x6564,0x6565,
+ 0, 0, 0, 0, 0, 0,0x6566, 0,
+0x6568, 0,0x6567, 0, 0, 0,0x6569, 0,
+0x656A, 0, 0,0x656B, 0,0x656C, 0,0x656D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x656E, 0, 0, 0,0x656F, 0, 0,0x6570,
+ 0, 0,0x6571, 0,0x6572, 0,0x6573, 0,
+ 0, 0, 0,0x6574, 0, 0,0x6575, 0,
+0x6576,0x6577,0x6578, 0,0x6579,0x657A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x657C,0x657B
+};
+
+/* page 38 0x9578-0x95E6 */
+static uint16 tab_uni_jisx021238[]={
+0x657D,0x657E, 0, 0, 0, 0,0x6621, 0,
+ 0, 0, 0, 0,0x6622, 0, 0, 0,
+0x6623, 0, 0, 0,0x6624,0x6625,0x6626, 0,
+ 0, 0,0x7471, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6627,0x6628,0x6629,
+ 0,0x662A, 0, 0, 0, 0,0x662B, 0,
+ 0,0x662C, 0,0x662D,0x662E, 0, 0, 0,
+ 0, 0, 0, 0,0x662F, 0,0x6630, 0,
+ 0, 0,0x6631, 0, 0,0x6632, 0,0x6633,
+ 0, 0, 0, 0, 0, 0,0x6634, 0,
+0x6635,0x6636, 0,0x6637, 0, 0, 0, 0,
+0x6638,0x6639,0x663A,0x663B, 0, 0, 0, 0,
+ 0,0x663C,0x663D, 0, 0,0x663E,0x663F,0x6640,
+0x6641, 0, 0, 0,0x6642, 0,0x6643};
+
+/* page 39 0x961D-0x986C */
+static uint16 tab_uni_jisx021239[]={
+0x6644,0x6645, 0, 0, 0,0x6646, 0,0x6647,
+0x6648,0x6649, 0, 0, 0, 0, 0,0x664A,
+ 0, 0, 0, 0,0x664B, 0,0x664C, 0,
+ 0, 0,0x664D,0x664E,0x664F,0x6650, 0,0x6651,
+0x6652, 0, 0, 0,0x6653, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6654, 0,0x6655,
+ 0,0x6656,0x6657,0x6658, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6659, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x665A, 0, 0, 0, 0, 0,0x665B,
+ 0, 0, 0, 0, 0, 0,0x665C,0x665D,
+ 0,0x665E,0x665F, 0,0x6660,0x6661,0x6662,0x6663,
+ 0, 0, 0, 0,0x6664, 0, 0, 0,
+ 0, 0, 0, 0,0x6665, 0, 0, 0,
+ 0,0x6666, 0, 0, 0,0x6667, 0, 0,
+0x6668, 0,0x6669, 0, 0, 0, 0,0x666A,
+0x666B,0x666C, 0, 0,0x666D, 0, 0, 0,
+ 0,0x666E,0x666F, 0, 0, 0,0x6670, 0,
+ 0, 0, 0, 0, 0,0x6671, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6672, 0, 0,
+ 0, 0, 0, 0, 0,0x6673, 0, 0,
+ 0, 0, 0,0x6675, 0,0x6676, 0, 0,
+0x6677,0x6678,0x6679, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x667A, 0, 0, 0,
+ 0, 0,0x667B, 0,0x667C, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x667D, 0, 0,
+ 0, 0, 0, 0, 0,0x667E,0x6721, 0,
+0x6722, 0, 0, 0,0x6723, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6724,0x6725, 0,
+0x6726, 0, 0, 0,0x6727,0x6728,0x6729, 0,
+ 0, 0, 0,0x672A, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x672B, 0,0x672C, 0,
+ 0, 0, 0, 0, 0, 0,0x7474, 0,
+ 0, 0, 0, 0,0x672D, 0,0x672E, 0,
+ 0, 0, 0, 0, 0,0x672F, 0, 0,
+0x7475,0x6730,0x6731, 0,0x7476, 0, 0, 0,
+0x6732, 0,0x6733,0x6734, 0,0x6735,0x6736, 0,
+ 0, 0, 0, 0, 0, 0,0x6737, 0,
+ 0, 0,0x6738, 0, 0,0x6739, 0, 0,
+ 0,0x673A, 0, 0, 0, 0,0x673B, 0,
+ 0,0x673C,0x673D,0x673E, 0, 0,0x673F, 0,
+0x6740, 0,0x6741,0x6742, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6743, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6744,0x6745,0x6746, 0,0x6747,0x6748, 0, 0,
+ 0,0x6749,0x674A, 0, 0,0x674B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,0x674C,
+ 0,0x674D, 0, 0,0x674E,0x674F, 0, 0,
+0x6750,0x6751, 0,0x6752,0x6753,0x6754, 0,0x6755,
+ 0,0x6756,0x6757, 0,0x6758, 0, 0,0x6759,
+0x675A, 0,0x675B, 0,0x675C,0x675D, 0,0x675E,
+0x675F,0x6760, 0,0x6761,0x6762, 0, 0,0x6763,
+ 0, 0,0x6764,0x6765,0x6766, 0,0x676A, 0,
+0x6767,0x6768, 0,0x6769,0x676B, 0, 0,0x676C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x676D, 0,0x676E, 0, 0,0x676F,
+ 0, 0,0x6770,0x6771, 0,0x6772, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x6773, 0, 0,0x6774, 0, 0,
+0x6776,0x6777, 0, 0, 0, 0, 0,0x6778,
+ 0,0x6779, 0, 0,0x6775, 0, 0,0x677A,
+ 0,0x677B, 0,0x677C, 0, 0,0x677D, 0,
+0x6828,0x677E, 0, 0, 0, 0,0x6821, 0,
+ 0,0x6822,0x6823,0x6824, 0,0x6825,0x6826, 0,
+0x6827, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6829, 0, 0, 0, 0, 0,0x682A,
+ 0, 0,0x682B, 0, 0,0x682C, 0, 0,
+ 0, 0, 0, 0,0x682D,0x682E,0x682F, 0,
+ 0,0x6830,0x6831, 0,0x6832,0x6833, 0, 0,
+ 0, 0, 0, 0, 0,0x6834,0x6835, 0,
+0x6836,0x6837, 0, 0, 0,0x6838, 0,0x6839
+};
+
+/* page 40 0x98AB-0x98CC */
+static uint16 tab_uni_jisx021240[]={
+0x683A, 0,0x683B,0x683C, 0,0x683D, 0, 0,
+ 0,0x683E, 0, 0,0x683F,0x6840, 0,0x6841,
+0x6842, 0, 0, 0,0x6843, 0, 0,0x6844,
+ 0, 0,0x6845, 0, 0,0x6846, 0, 0,
+ 0,0x6847};
+
+/* page 41 0x98E1-0x9960 */
+static uint16 tab_uni_jisx021241[]={
+0x6848, 0,0x6849, 0,0x684A,0x684B,0x684C, 0,
+ 0,0x684D, 0, 0, 0, 0, 0, 0,
+ 0, 0,0x684E, 0, 0,0x684F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6850, 0, 0, 0, 0,0x6851,0x6852,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6853, 0, 0, 0,0x6854,0x6855,0x6856, 0,
+ 0,0x6857,0x6858,0x6859, 0, 0,0x685A, 0,
+ 0,0x685B, 0, 0, 0,0x685C,0x685D, 0,
+ 0, 0,0x685E, 0, 0, 0, 0, 0,
+0x685F,0x6860,0x6861,0x6862,0x6863, 0, 0, 0,
+0x6864,0x6865,0x6866,0x6867, 0, 0, 0,0x6868,
+0x6869, 0, 0, 0, 0,0x686A,0x686B,0x686C,
+ 0, 0, 0, 0,0x686D,0x686E, 0, 0,
+ 0, 0, 0,0x686F, 0, 0, 0,0x6870,
+0x6871, 0,0x6872,0x6873, 0,0x6874,0x6875,0x6876
+};
+
+/* page 42 0x999B-0x9A5D */
+static uint16 tab_uni_jisx021242[]={
+0x6877, 0,0x6878,0x747A,0x6879, 0, 0, 0,
+ 0, 0, 0,0x687A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x687B,0x687C,0x687D,
+ 0, 0,0x687E, 0, 0, 0,0x6921,0x6922,
+ 0, 0,0x6923, 0,0x6924, 0, 0, 0,
+0x6925, 0, 0, 0, 0, 0,0x6926, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6927,0x6928, 0, 0, 0, 0,0x6929,0x692A,
+ 0,0x692B, 0,0x692C, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x692D, 0, 0,0x692E,
+0x692F,0x6930, 0, 0, 0,0x6931, 0, 0,
+ 0,0x6932,0x6933, 0, 0, 0,0x6934, 0,
+ 0, 0,0x6935,0x6936, 0, 0, 0,0x6937,
+0x6938,0x6939, 0, 0, 0, 0, 0, 0,
+0x693A,0x693B, 0, 0, 0,0x693C,0x693D, 0,
+ 0, 0, 0,0x693E, 0, 0, 0, 0,
+ 0, 0, 0,0x693F, 0,0x6940, 0,0x6941,
+0x6942,0x6943, 0, 0,0x6944, 0, 0, 0,
+ 0, 0,0x6945,0x6946, 0, 0, 0, 0,
+0x6947, 0,0x6948,0x6949, 0,0x694A, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x694C, 0,
+ 0,0x694D, 0, 0,0x694B, 0, 0,0x694E,
+0x694F,0x6950, 0,0x6951, 0, 0,0x6952, 0,
+ 0,0x6953, 0,0x6954, 0, 0, 0, 0,
+ 0, 0,0x6955};
+
+/* page 43 0x9AAA-0x9C7B */
+static uint16 tab_uni_jisx021243[]={
+0x6956, 0,0x6957, 0,0x6958,0x6959, 0, 0,
+0x695A, 0,0x695B,0x695C,0x695D, 0, 0,0x695E,
+ 0,0x695F, 0, 0,0x6960,0x6961, 0,0x6962,
+ 0,0x6963, 0, 0,0x6964, 0,0x6965, 0,
+ 0, 0, 0, 0,0x6966, 0,0x6967, 0,
+0x6968, 0, 0,0x6969,0x696A,0x696B, 0,0x747B,
+ 0,0x696C,0x696D, 0, 0, 0,0x696E, 0,
+ 0, 0,0x696F,0x6970, 0,0x6971, 0,0x6972,
+ 0, 0,0x6973, 0, 0, 0, 0, 0,
+0x6974,0x6975, 0,0x6976, 0, 0, 0,0x6977,
+0x6978, 0, 0,0x6979, 0,0x697A,0x697B,0x697C,
+0x697D,0x697E,0x6A21,0x6A22, 0, 0,0x6A23,0x6A24,
+ 0,0x6A25,0x6A26,0x6A27,0x6A28, 0,0x6A29, 0,
+0x6A2A, 0, 0, 0,0x6A2B, 0, 0,0x6A2C,
+ 0,0x6A2D,0x6A2E, 0, 0, 0,0x6A2F, 0,
+ 0, 0, 0, 0,0x6A30, 0, 0, 0,
+ 0,0x6A31, 0,0x6A32, 0, 0, 0, 0,
+ 0,0x6A33,0x6A34,0x6A35, 0,0x6A36, 0,0x6A37,
+0x6A38, 0, 0,0x6A39, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6A3A, 0,
+ 0,0x6A3B,0x6A3C, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6A3D,0x6A3E,0x6A3F, 0, 0,
+ 0,0x6A40, 0, 0,0x6A41, 0, 0,0x6A42,
+ 0,0x6A43, 0,0x6A44,0x6A45, 0,0x6A46, 0,
+0x6A47,0x6A48,0x6A49,0x6A4A,0x6A4B, 0, 0, 0,
+0x747C,0x6A4C, 0,0x6A4D, 0,0x6A4E,0x6A4F,0x6A50,
+ 0, 0, 0, 0, 0,0x6A51,0x6A52, 0,
+ 0, 0,0x6A53,0x6A54,0x6A55,0x6A56, 0,0x6A57,
+0x6A58,0x6A59, 0,0x6A5A, 0,0x6A5B,0x6A5C, 0,
+ 0, 0,0x6A5D, 0, 0, 0, 0, 0,
+0x6A5E, 0, 0,0x6A5F,0x6A60, 0, 0, 0,
+ 0, 0, 0, 0,0x6A61,0x6A62, 0,0x6A63,
+ 0, 0,0x6A64, 0, 0, 0,0x6A65,0x6A66,
+0x6A67, 0, 0, 0, 0,0x6A68,0x6A69, 0,
+ 0,0x6A6A,0x6A6B, 0,0x6A6C,0x6A6D, 0,0x6A6E,
+ 0, 0, 0, 0, 0,0x6A6F,0x6A70, 0,
+ 0, 0, 0, 0,0x6A71, 0,0x6A72, 0,
+ 0, 0, 0, 0, 0,0x6A73,0x6A74, 0,
+ 0, 0, 0,0x6A75, 0,0x6A76, 0, 0,
+ 0, 0, 0,0x6A77, 0,0x6A78, 0, 0,
+0x6A79,0x6A7A, 0, 0, 0,0x6A7B, 0, 0,
+ 0,0x6A7C, 0, 0, 0,0x6A7D,0x6A7E,0x6B21,
+0x6B22, 0, 0,0x6B23, 0,0x6B24,0x6B25, 0,
+0x6B26, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6B27, 0, 0, 0,0x6B28, 0,0x6B29,
+ 0, 0, 0, 0,0x6B2A, 0,0x6B2B,0x6B2C,
+0x6B2D, 0,0x6B2E, 0,0x6B2F, 0, 0, 0,
+0x6B30,0x6B31, 0, 0,0x6B32,0x6B33,0x6B34,0x6B35,
+0x6B36, 0, 0, 0, 0, 0, 0,0x6B37,
+ 0, 0, 0,0x6B38,0x6B39,0x6B3A, 0, 0,
+ 0, 0, 0,0x6B3B, 0, 0, 0,0x6B3C,
+ 0,0x6B3D,0x6B3E,0x6B3F, 0, 0, 0,0x6B40,
+0x6B41, 0, 0, 0,0x6B42,0x6B43,0x6B44, 0,
+ 0,0x6B45,0x6B46, 0,0x6B47, 0,0x6B48, 0,
+ 0,0x6B49,0x6B50,0x6B4A,0x6B4B,0x6B4C, 0, 0,
+ 0,0x6B4D, 0, 0, 0, 0,0x6B52,0x6B4E,
+0x6B4F,0x6B51, 0, 0,0x6B53, 0,0x6B54, 0,
+0x6B55, 0, 0,0x6B56, 0,0x6B57, 0, 0,
+ 0,0x6B58};
+
+/* page 44 0x9CE6-0x9E1D */
+static uint16 tab_uni_jisx021244[]={
+0x6B59, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6B5A, 0, 0, 0,
+ 0,0x6B5B, 0,0x6B5C, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6B5E, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6B5D, 0, 0,
+ 0, 0, 0,0x6B5F, 0, 0, 0, 0,
+ 0,0x6B60,0x6B61, 0, 0, 0,0x6B62,0x6B63,
+0x6B64, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6B65,0x6B66, 0,0x6B67,0x6B68,0x6B69, 0,
+ 0, 0, 0, 0,0x6B6A, 0,0x6B6B,0x6B6D,
+ 0, 0, 0, 0,0x6B6E,0x6B6F, 0,0x6B6C,
+ 0,0x6B70, 0, 0,0x6B71, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6B72,0x6B73, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6B74, 0, 0,0x6B76,0x6B75, 0,0x6B77,
+ 0, 0, 0,0x6B78,0x6B79,0x6B7A, 0, 0,
+ 0, 0,0x6B7B, 0, 0, 0, 0, 0,
+0x6B7C,0x6B7D, 0, 0, 0,0x6B7E,0x6C21, 0,
+0x6C22, 0, 0, 0, 0,0x6C23,0x6C24, 0,
+0x6C25, 0, 0, 0,0x6C26, 0, 0,0x6C27,
+0x6C28, 0, 0, 0,0x6C29,0x6C2A, 0,0x6C2B,
+0x6C2C,0x6C2D,0x6C2E, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x6C2F, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6C30, 0,0x6C31, 0,
+0x6C32, 0, 0,0x6C33, 0, 0, 0,0x6C34,
+ 0, 0, 0,0x6C35, 0, 0,0x6C36, 0,
+ 0,0x6C37, 0, 0, 0,0x6C38, 0, 0,
+ 0,0x6C39, 0,0x6C3A,0x6C3B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6C3C,0x6C3D,
+0x6C3E,0x6C3F, 0, 0,0x6C40, 0, 0, 0,
+0x6C41,0x6C42,0x6C43, 0, 0, 0, 0,0x6C44,
+ 0,0x6C45, 0,0x6C46, 0,0x6C47, 0, 0,
+0x6C48, 0,0x6C49, 0, 0,0x6C4A,0x6C4B, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x6C4C, 0, 0, 0,0x6C4E, 0, 0, 0,
+ 0,0x6C4F, 0, 0,0x6C4D, 0, 0, 0,
+0x6C50, 0,0x6C51,0x6C52,0x6C53, 0, 0,0x6C54,
+0x6C55, 0, 0,0x6C56, 0, 0,0x6C57,0x6C58
+};
+
+/* page 45 0x9E7A-0x9FA5 */
+static uint16 tab_uni_jisx021245[]={
+0x6C59,0x6C5A,0x6C5B, 0, 0, 0,0x6C5C, 0,
+0x6C5D,0x6C5E,0x6C5F,0x6C60, 0,0x6C61, 0, 0,
+ 0, 0, 0, 0,0x6C62,0x6C63, 0, 0,
+ 0, 0, 0, 0,0x6C64, 0,0x6C65, 0,
+ 0,0x6C66, 0, 0,0x6C67, 0, 0, 0,
+ 0, 0,0x6C68, 0, 0, 0,0x6C69, 0,
+ 0, 0,0x6C6A, 0,0x6C6B,0x6C6C,0x6C6D, 0,
+ 0,0x6C6E,0x6C6F,0x6C70, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,0x6C71, 0,0x6C72, 0,
+ 0,0x6C73, 0, 0, 0, 0, 0,0x747E,
+ 0, 0, 0,0x6C74, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6C75, 0, 0,
+ 0, 0,0x6C76, 0, 0,0x6C77, 0, 0,
+ 0, 0,0x6C78,0x6C79,0x6C7A, 0,0x6C7B,0x6C7C,
+0x6C7D, 0, 0,0x6C7E, 0, 0,0x6D21, 0,
+ 0, 0, 0, 0, 0,0x6D22, 0, 0,
+0x6D23,0x6D24, 0, 0, 0, 0, 0,0x6D25,
+ 0, 0, 0, 0, 0,0x6D26,0x6D27,0x6D28,
+0x6D29, 0,0x6D2A, 0,0x6D2B,0x6D2C, 0,0x6D2D,
+0x6D2E,0x6D2F, 0, 0, 0,0x6D30, 0, 0,
+0x6D31, 0, 0, 0,0x6D32, 0, 0, 0,
+0x6D33,0x6D34, 0, 0, 0,0x6D35, 0,0x6D36,
+0x6D37, 0,0x6D38, 0, 0,0x6D39, 0,0x6D3A,
+0x6D3B, 0,0x6D3C,0x6D3D, 0,0x6D3E, 0,0x6D3F,
+ 0,0x6D40,0x6D41,0x6D42,0x6D43,0x6D44, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,0x6D45, 0,0x6D46,0x6D47,0x6D48,0x6D49, 0,
+0x6D4A, 0, 0,0x6D4B,0x6D4C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x6D4D,0x6D4E,
+ 0, 0, 0,0x6D4F,0x6D50,0x6D51,0x6D52,0x6D53,
+ 0,0x6D54, 0,0x6D55, 0, 0, 0, 0,
+0x6D56, 0, 0,0x6D57, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x6D58,0x6D59,0x6D5A,
+0x6D5B, 0,0x6D5C, 0,0x6D5D,0x6D5E, 0, 0,
+ 0, 0, 0, 0,0x6D5F, 0, 0,0x6D60,
+0x6D61,0x6D62, 0,0x6D63};
+
+/* page 46 0xF929-0xF929 */
+static uint16 tab_uni_jisx021246[]={
+0x7445};
+
+/* page 47 0xF9DC-0xF9DC */
+static uint16 tab_uni_jisx021247[]={
+0x7472};
+
+/* page 48 0xFA00-0xFA2D */
+static uint16 tab_uni_jisx021248[]={
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,0x7434,0x7437,
+0x7438,0x743D,0x7444,0x7447,0x7448,0x744E,0x744F,0x7453,
+0x7455,0x7456,0x7457,0x7458,0x745A,0x745B,0x745E,0x7460,
+0x7462,0x7463,0x7465,0x7469,0x746A,0x746B,0x746D,0x746F,
+0x7470,0x7473,0x7477,0x7478,0x7479,0x747D};
+
+/* page 49 0xFF00-0XFF07 */
+static uint16 tab_uni_jisx021249[]={
+ 0, 0,0x742A, 0, 0, 0, 0,0x7429};
+
+/* page 50 0xFFE4-0xFFE4 */
+static uint16 tab_uni_jisx021250[]={
+0x2243};
+
+static int
+my_uni_jisx0212_onechar(int code){
+ if ((code>=0x007E)&&(code<=0x007E))
+ return(tab_uni_jisx02120[code-0x007E]);
+ if ((code>=0x00A1)&&(code<=0x017E))
+ return(tab_uni_jisx02121[code-0x00A1]);
+ if ((code>=0x01CD)&&(code<=0x01DC))
+ return(tab_uni_jisx02122[code-0x01CD]);
+ if ((code>=0x01F5)&&(code<=0x01F5))
+ return(tab_uni_jisx02123[code-0x01F5]);
+ if ((code>=0x02C7)&&(code<=0x02DD))
+ return(tab_uni_jisx02124[code-0x02C7]);
+ if ((code>=0x0384)&&(code<=0x0390))
+ return(tab_uni_jisx02125[code-0x0384]);
+ if ((code>=0x03AA)&&(code<=0x03CE))
+ return(tab_uni_jisx02126[code-0x03AA]);
+ if ((code>=0x0402)&&(code<=0x040F))
+ return(tab_uni_jisx02127[code-0x0402]);
+ if ((code>=0x0452)&&(code<=0x045F))
+ return(tab_uni_jisx02128[code-0x0452]);
+ if ((code>=0x2122)&&(code<=0x2122))
+ return(tab_uni_jisx02129[code-0x2122]);
+ if ((code>=0x2170)&&(code<=0x2179))
+ return(tab_uni_jisx021210[code-0x2170]);
+ if ((code>=0x4E02)&&(code<=0x4F19))
+ return(tab_uni_jisx021211[code-0x4E02]);
+ if ((code>=0x4F2E)&&(code<=0x5166))
+ return(tab_uni_jisx021212[code-0x4F2E]);
+ if ((code>=0x517E)&&(code<=0x5515))
+ return(tab_uni_jisx021213[code-0x517E]);
+ if ((code>=0x552A)&&(code<=0x5566))
+ return(tab_uni_jisx021214[code-0x552A]);
+ if ((code>=0x557F)&&(code<=0x5C36))
+ return(tab_uni_jisx021215[code-0x557F]);
+ if ((code>=0x5C59)&&(code<=0x5EEB))
+ return(tab_uni_jisx021216[code-0x5C59]);
+ if ((code>=0x5F02)&&(code<=0x6149))
+ return(tab_uni_jisx021217[code-0x5F02]);
+ if ((code>=0x615E)&&(code<=0x6290))
+ return(tab_uni_jisx021218[code-0x615E]);
+ if ((code>=0x62A6)&&(code<=0x679B))
+ return(tab_uni_jisx021219[code-0x62A6]);
+ if ((code>=0x67B0)&&(code<=0x6801))
+ return(tab_uni_jisx021220[code-0x67B0]);
+ if ((code>=0x6814)&&(code<=0x6917))
+ return(tab_uni_jisx021221[code-0x6814]);
+ if ((code>=0x6931)&&(code<=0x6D3F))
+ return(tab_uni_jisx021222[code-0x6931]);
+ if ((code>=0x6D57)&&(code<=0x6E04))
+ return(tab_uni_jisx021223[code-0x6D57]);
+ if ((code>=0x6E1E)&&(code<=0x6ECF))
+ return(tab_uni_jisx021224[code-0x6E1E]);
+ if ((code>=0x6EEB)&&(code<=0x70E4))
+ return(tab_uni_jisx021225[code-0x6EEB]);
+ if ((code>=0x70FA)&&(code<=0x71DC))
+ return(tab_uni_jisx021226[code-0x70FA]);
+ if ((code>=0x71F8)&&(code<=0x7E9E))
+ return(tab_uni_jisx021227[code-0x71F8]);
+ if ((code>=0x7F3B)&&(code<=0x8044))
+ return(tab_uni_jisx021228[code-0x7F3B]);
+ if ((code>=0x8060)&&(code<=0x8362))
+ return(tab_uni_jisx021229[code-0x8060]);
+ if ((code>=0x8370)&&(code<=0x8419))
+ return(tab_uni_jisx021230[code-0x8370]);
+ if ((code>=0x842F)&&(code<=0x8880))
+ return(tab_uni_jisx021231[code-0x842F]);
+ if ((code>=0x8898)&&(code<=0x89BC))
+ return(tab_uni_jisx021232[code-0x8898]);
+ if ((code>=0x89D4)&&(code<=0x8B9F))
+ return(tab_uni_jisx021233[code-0x89D4]);
+ if ((code>=0x8C38)&&(code<=0x8CA4))
+ return(tab_uni_jisx021234[code-0x8C38]);
+ if ((code>=0x8CB9)&&(code<=0x8D1B))
+ return(tab_uni_jisx021235[code-0x8CB9]);
+ if ((code>=0x8D65)&&(code<=0x8F65))
+ return(tab_uni_jisx021236[code-0x8D65]);
+ if ((code>=0x8F9D)&&(code<=0x9484))
+ return(tab_uni_jisx021237[code-0x8F9D]);
+ if ((code>=0x9578)&&(code<=0x95E6))
+ return(tab_uni_jisx021238[code-0x9578]);
+ if ((code>=0x961D)&&(code<=0x986C))
+ return(tab_uni_jisx021239[code-0x961D]);
+ if ((code>=0x98AB)&&(code<=0x98CC))
+ return(tab_uni_jisx021240[code-0x98AB]);
+ if ((code>=0x98E1)&&(code<=0x9960))
+ return(tab_uni_jisx021241[code-0x98E1]);
+ if ((code>=0x999B)&&(code<=0x9A5D))
+ return(tab_uni_jisx021242[code-0x999B]);
+ if ((code>=0x9AAA)&&(code<=0x9C7B))
+ return(tab_uni_jisx021243[code-0x9AAA]);
+ if ((code>=0x9CE6)&&(code<=0x9E1D))
+ return(tab_uni_jisx021244[code-0x9CE6]);
+ if ((code>=0x9E7A)&&(code<=0x9FA5))
+ return(tab_uni_jisx021245[code-0x9E7A]);
+ if ((code>=0xF929)&&(code<=0xF929))
+ return(tab_uni_jisx021246[code-0xF929]);
+ if ((code>=0xF9DC)&&(code<=0xF9DC))
+ return(tab_uni_jisx021247[code-0xF9DC]);
+ if ((code>=0xFA00)&&(code<=0xFA2D))
+ return(tab_uni_jisx021248[code-0xFA00]);
+ if ((code>=0xFF00)&&(code<=0xFF07))
+ return(tab_uni_jisx021249[code-0xFF00]);
+ if ((code>=0xFFE4)&&(code<=0xFFE4))
+ return(tab_uni_jisx021250[code-0xFFE4]);
+ return(0);
+}
+
+/* page 0 0x222F-0x2244 */
+static uint16 tab_jisx0212_uni0[]={
+0x02D8,0x02C7,0x00B8,0x02D9,0x02DD,0x00AF,0x02DB,0x02DA,
+0xFF5E,0x0384,0x0385, 0, 0, 0, 0, 0,
+ 0, 0, 0,0x00A1,0xFFE4,0x00BF};
+
+/* page 1 0x226B-0x2271 */
+static uint16 tab_jisx0212_uni1[]={
+0x00BA,0x00AA,0x00A9,0x00AE,0x2122,0x00A4,0x2116};
+
+/* page 2 0x2661-0x267C */
+static uint16 tab_jisx0212_uni2[]={
+0x0386,0x0388,0x0389,0x038A,0x03AA, 0,0x038C, 0,
+0x038E,0x03AB, 0,0x038F, 0, 0, 0, 0,
+0x03AC,0x03AD,0x03AE,0x03AF,0x03CA,0x0390,0x03CC,0x03C2,
+0x03CD,0x03CB,0x03B0,0x03CE};
+
+/* page 3 0x2742-0x274E */
+static uint16 tab_jisx0212_uni3[]={
+0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,0x0408,0x0409,
+0x040A,0x040B,0x040C,0x040E,0x040F};
+
+/* page 4 0x2772-0x277E */
+static uint16 tab_jisx0212_uni4[]={
+0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,0x0458,0x0459,
+0x045A,0x045B,0x045C,0x045E,0x045F};
+
+/* page 5 0x2921-0x2950 */
+static uint16 tab_jisx0212_uni5[]={
+0x00C6,0x0110, 0,0x0126, 0,0x0132, 0,0x0141,
+0x013F, 0,0x014A,0x00D8,0x0152, 0,0x0166,0x00DE,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+0x00E6,0x0111,0x00F0,0x0127,0x0131,0x0133,0x0138,0x0142,
+0x0140,0x0149,0x014B,0x00F8,0x0153,0x00DF,0x0167,0x00FE
+};
+
+/* page 6 0x2A21-0x2A77 */
+static uint16 tab_jisx0212_uni6[]={
+0x00C1,0x00C0,0x00C4,0x00C2,0x0102,0x01CD,0x0100,0x0104,
+0x00C5,0x00C3,0x0106,0x0108,0x010C,0x00C7,0x010A,0x010E,
+0x00C9,0x00C8,0x00CB,0x00CA,0x011A,0x0116,0x0112,0x0118,
+ 0,0x011C,0x011E,0x0122,0x0120,0x0124,0x00CD,0x00CC,
+0x00CF,0x00CE,0x01CF,0x0130,0x012A,0x012E,0x0128,0x0134,
+0x0136,0x0139,0x013D,0x013B,0x0143,0x0147,0x0145,0x00D1,
+0x00D3,0x00D2,0x00D6,0x00D4,0x01D1,0x0150,0x014C,0x00D5,
+0x0154,0x0158,0x0156,0x015A,0x015C,0x0160,0x015E,0x0164,
+0x0162,0x00DA,0x00D9,0x00DC,0x00DB,0x016C,0x01D3,0x0170,
+0x016A,0x0172,0x016E,0x0168,0x01D7,0x01DB,0x01D9,0x01D5,
+0x0174,0x00DD,0x0178,0x0176,0x0179,0x017D,0x017B};
+
+/* page 7 0x2B21-0x2B77 */
+static uint16 tab_jisx0212_uni7[]={
+0x00E1,0x00E0,0x00E4,0x00E2,0x0103,0x01CE,0x0101,0x0105,
+0x00E5,0x00E3,0x0107,0x0109,0x010D,0x00E7,0x010B,0x010F,
+0x00E9,0x00E8,0x00EB,0x00EA,0x011B,0x0117,0x0113,0x0119,
+0x01F5,0x011D,0x011F, 0,0x0121,0x0125,0x00ED,0x00EC,
+0x00EF,0x00EE,0x01D0, 0,0x012B,0x012F,0x0129,0x0135,
+0x0137,0x013A,0x013E,0x013C,0x0144,0x0148,0x0146,0x00F1,
+0x00F3,0x00F2,0x00F6,0x00F4,0x01D2,0x0151,0x014D,0x00F5,
+0x0155,0x0159,0x0157,0x015B,0x015D,0x0161,0x015F,0x0165,
+0x0163,0x00FA,0x00F9,0x00FC,0x00FB,0x016D,0x01D4,0x0171,
+0x016B,0x0173,0x016F,0x0169,0x01D8,0x01DC,0x01DA,0x01D6,
+0x0175,0x00FD,0x00FF,0x0177,0x017A,0x017E,0x017C};
+
+/* page 8 0x3021-0x307E */
+static uint16 tab_jisx0212_uni8[]={
+0x4E02,0x4E04,0x4E05,0x4E0C,0x4E12,0x4E1F,0x4E23,0x4E24,
+0x4E28,0x4E2B,0x4E2E,0x4E2F,0x4E30,0x4E35,0x4E40,0x4E41,
+0x4E44,0x4E47,0x4E51,0x4E5A,0x4E5C,0x4E63,0x4E68,0x4E69,
+0x4E74,0x4E75,0x4E79,0x4E7F,0x4E8D,0x4E96,0x4E97,0x4E9D,
+0x4EAF,0x4EB9,0x4EC3,0x4ED0,0x4EDA,0x4EDB,0x4EE0,0x4EE1,
+0x4EE2,0x4EE8,0x4EEF,0x4EF1,0x4EF3,0x4EF5,0x4EFD,0x4EFE,
+0x4EFF,0x4F00,0x4F02,0x4F03,0x4F08,0x4F0B,0x4F0C,0x4F12,
+0x4F15,0x4F16,0x4F17,0x4F19,0x4F2E,0x4F31,0x4F60,0x4F33,
+0x4F35,0x4F37,0x4F39,0x4F3B,0x4F3E,0x4F40,0x4F42,0x4F48,
+0x4F49,0x4F4B,0x4F4C,0x4F52,0x4F54,0x4F56,0x4F58,0x4F5F,
+0x4F63,0x4F6A,0x4F6C,0x4F6E,0x4F71,0x4F77,0x4F78,0x4F79,
+0x4F7A,0x4F7D,0x4F7E,0x4F81,0x4F82,0x4F84};
+
+/* page 9 0x3121-0x317E */
+static uint16 tab_jisx0212_uni9[]={
+0x4F85,0x4F89,0x4F8A,0x4F8C,0x4F8E,0x4F90,0x4F92,0x4F93,
+0x4F94,0x4F97,0x4F99,0x4F9A,0x4F9E,0x4F9F,0x4FB2,0x4FB7,
+0x4FB9,0x4FBB,0x4FBC,0x4FBD,0x4FBE,0x4FC0,0x4FC1,0x4FC5,
+0x4FC6,0x4FC8,0x4FC9,0x4FCB,0x4FCC,0x4FCD,0x4FCF,0x4FD2,
+0x4FDC,0x4FE0,0x4FE2,0x4FF0,0x4FF2,0x4FFC,0x4FFD,0x4FFF,
+0x5000,0x5001,0x5004,0x5007,0x500A,0x500C,0x500E,0x5010,
+0x5013,0x5017,0x5018,0x501B,0x501C,0x501D,0x501E,0x5022,
+0x5027,0x502E,0x5030,0x5032,0x5033,0x5035,0x5040,0x5041,
+0x5042,0x5045,0x5046,0x504A,0x504C,0x504E,0x5051,0x5052,
+0x5053,0x5057,0x5059,0x505F,0x5060,0x5062,0x5063,0x5066,
+0x5067,0x506A,0x506D,0x5070,0x5071,0x503B,0x5081,0x5083,
+0x5084,0x5086,0x508A,0x508E,0x508F,0x5090};
+
+/* page 10 0x3221-0x327E */
+static uint16 tab_jisx0212_uni10[]={
+0x5092,0x5093,0x5094,0x5096,0x509B,0x509C,0x509E,0x509F,
+0x50A0,0x50A1,0x50A2,0x50AA,0x50AF,0x50B0,0x50B9,0x50BA,
+0x50BD,0x50C0,0x50C3,0x50C4,0x50C7,0x50CC,0x50CE,0x50D0,
+0x50D3,0x50D4,0x50D8,0x50DC,0x50DD,0x50DF,0x50E2,0x50E4,
+0x50E6,0x50E8,0x50E9,0x50EF,0x50F1,0x50F6,0x50FA,0x50FE,
+0x5103,0x5106,0x5107,0x5108,0x510B,0x510C,0x510D,0x510E,
+0x50F2,0x5110,0x5117,0x5119,0x511B,0x511C,0x511D,0x511E,
+0x5123,0x5127,0x5128,0x512C,0x512D,0x512F,0x5131,0x5133,
+0x5134,0x5135,0x5138,0x5139,0x5142,0x514A,0x514F,0x5153,
+0x5155,0x5157,0x5158,0x515F,0x5164,0x5166,0x517E,0x5183,
+0x5184,0x518B,0x518E,0x5198,0x519D,0x51A1,0x51A3,0x51AD,
+0x51B8,0x51BA,0x51BC,0x51BE,0x51BF,0x51C2};
+
+/* page 11 0x3321-0x337E */
+static uint16 tab_jisx0212_uni11[]={
+0x51C8,0x51CF,0x51D1,0x51D2,0x51D3,0x51D5,0x51D8,0x51DE,
+0x51E2,0x51E5,0x51EE,0x51F2,0x51F3,0x51F4,0x51F7,0x5201,
+0x5202,0x5205,0x5212,0x5213,0x5215,0x5216,0x5218,0x5222,
+0x5228,0x5231,0x5232,0x5235,0x523C,0x5245,0x5249,0x5255,
+0x5257,0x5258,0x525A,0x525C,0x525F,0x5260,0x5261,0x5266,
+0x526E,0x5277,0x5278,0x5279,0x5280,0x5282,0x5285,0x528A,
+0x528C,0x5293,0x5295,0x5296,0x5297,0x5298,0x529A,0x529C,
+0x52A4,0x52A5,0x52A6,0x52A7,0x52AF,0x52B0,0x52B6,0x52B7,
+0x52B8,0x52BA,0x52BB,0x52BD,0x52C0,0x52C4,0x52C6,0x52C8,
+0x52CC,0x52CF,0x52D1,0x52D4,0x52D6,0x52DB,0x52DC,0x52E1,
+0x52E5,0x52E8,0x52E9,0x52EA,0x52EC,0x52F0,0x52F1,0x52F4,
+0x52F6,0x52F7,0x5300,0x5303,0x530A,0x530B};
+
+/* page 12 0x3421-0x347E */
+static uint16 tab_jisx0212_uni12[]={
+0x530C,0x5311,0x5313,0x5318,0x531B,0x531C,0x531E,0x531F,
+0x5325,0x5327,0x5328,0x5329,0x532B,0x532C,0x532D,0x5330,
+0x5332,0x5335,0x533C,0x533D,0x533E,0x5342,0x534C,0x534B,
+0x5359,0x535B,0x5361,0x5363,0x5365,0x536C,0x536D,0x5372,
+0x5379,0x537E,0x5383,0x5387,0x5388,0x538E,0x5393,0x5394,
+0x5399,0x539D,0x53A1,0x53A4,0x53AA,0x53AB,0x53AF,0x53B2,
+0x53B4,0x53B5,0x53B7,0x53B8,0x53BA,0x53BD,0x53C0,0x53C5,
+0x53CF,0x53D2,0x53D3,0x53D5,0x53DA,0x53DD,0x53DE,0x53E0,
+0x53E6,0x53E7,0x53F5,0x5402,0x5413,0x541A,0x5421,0x5427,
+0x5428,0x542A,0x542F,0x5431,0x5434,0x5435,0x5443,0x5444,
+0x5447,0x544D,0x544F,0x545E,0x5462,0x5464,0x5466,0x5467,
+0x5469,0x546B,0x546D,0x546E,0x5474,0x547F};
+
+/* page 13 0x3521-0x357E */
+static uint16 tab_jisx0212_uni13[]={
+0x5481,0x5483,0x5485,0x5488,0x5489,0x548D,0x5491,0x5495,
+0x5496,0x549C,0x549F,0x54A1,0x54A6,0x54A7,0x54A9,0x54AA,
+0x54AD,0x54AE,0x54B1,0x54B7,0x54B9,0x54BA,0x54BB,0x54BF,
+0x54C6,0x54CA,0x54CD,0x54CE,0x54E0,0x54EA,0x54EC,0x54EF,
+0x54F6,0x54FC,0x54FE,0x54FF,0x5500,0x5501,0x5505,0x5508,
+0x5509,0x550C,0x550D,0x550E,0x5515,0x552A,0x552B,0x5532,
+0x5535,0x5536,0x553B,0x553C,0x553D,0x5541,0x5547,0x5549,
+0x554A,0x554D,0x5550,0x5551,0x5558,0x555A,0x555B,0x555E,
+0x5560,0x5561,0x5564,0x5566,0x557F,0x5581,0x5582,0x5586,
+0x5588,0x558E,0x558F,0x5591,0x5592,0x5593,0x5594,0x5597,
+0x55A3,0x55A4,0x55AD,0x55B2,0x55BF,0x55C1,0x55C3,0x55C6,
+0x55C9,0x55CB,0x55CC,0x55CE,0x55D1,0x55D2};
+
+/* page 14 0x3621-0x367E */
+static uint16 tab_jisx0212_uni14[]={
+0x55D3,0x55D7,0x55D8,0x55DB,0x55DE,0x55E2,0x55E9,0x55F6,
+0x55FF,0x5605,0x5608,0x560A,0x560D,0x560E,0x560F,0x5610,
+0x5611,0x5612,0x5619,0x562C,0x5630,0x5633,0x5635,0x5637,
+0x5639,0x563B,0x563C,0x563D,0x563F,0x5640,0x5641,0x5643,
+0x5644,0x5646,0x5649,0x564B,0x564D,0x564F,0x5654,0x565E,
+0x5660,0x5661,0x5662,0x5663,0x5666,0x5669,0x566D,0x566F,
+0x5671,0x5672,0x5675,0x5684,0x5685,0x5688,0x568B,0x568C,
+0x5695,0x5699,0x569A,0x569D,0x569E,0x569F,0x56A6,0x56A7,
+0x56A8,0x56A9,0x56AB,0x56AC,0x56AD,0x56B1,0x56B3,0x56B7,
+0x56BE,0x56C5,0x56C9,0x56CA,0x56CB,0x56CF,0x56D0,0x56CC,
+0x56CD,0x56D9,0x56DC,0x56DD,0x56DF,0x56E1,0x56E4,0x56E5,
+0x56E6,0x56E7,0x56E8,0x56F1,0x56EB,0x56ED};
+
+/* page 15 0x3721-0x377E */
+static uint16 tab_jisx0212_uni15[]={
+0x56F6,0x56F7,0x5701,0x5702,0x5707,0x570A,0x570C,0x5711,
+0x5715,0x571A,0x571B,0x571D,0x5720,0x5722,0x5723,0x5724,
+0x5725,0x5729,0x572A,0x572C,0x572E,0x572F,0x5733,0x5734,
+0x573D,0x573E,0x573F,0x5745,0x5746,0x574C,0x574D,0x5752,
+0x5762,0x5765,0x5767,0x5768,0x576B,0x576D,0x576E,0x576F,
+0x5770,0x5771,0x5773,0x5774,0x5775,0x5777,0x5779,0x577A,
+0x577B,0x577C,0x577E,0x5781,0x5783,0x578C,0x5794,0x5797,
+0x5799,0x579A,0x579C,0x579D,0x579E,0x579F,0x57A1,0x5795,
+0x57A7,0x57A8,0x57A9,0x57AC,0x57B8,0x57BD,0x57C7,0x57C8,
+0x57CC,0x57CF,0x57D5,0x57DD,0x57DE,0x57E4,0x57E6,0x57E7,
+0x57E9,0x57ED,0x57F0,0x57F5,0x57F6,0x57F8,0x57FD,0x57FE,
+0x57FF,0x5803,0x5804,0x5808,0x5809,0x57E1};
+
+/* page 16 0x3821-0x387E */
+static uint16 tab_jisx0212_uni16[]={
+0x580C,0x580D,0x581B,0x581E,0x581F,0x5820,0x5826,0x5827,
+0x582D,0x5832,0x5839,0x583F,0x5849,0x584C,0x584D,0x584F,
+0x5850,0x5855,0x585F,0x5861,0x5864,0x5867,0x5868,0x5878,
+0x587C,0x587F,0x5880,0x5881,0x5887,0x5888,0x5889,0x588A,
+0x588C,0x588D,0x588F,0x5890,0x5894,0x5896,0x589D,0x58A0,
+0x58A1,0x58A2,0x58A6,0x58A9,0x58B1,0x58B2,0x58C4,0x58BC,
+0x58C2,0x58C8,0x58CD,0x58CE,0x58D0,0x58D2,0x58D4,0x58D6,
+0x58DA,0x58DD,0x58E1,0x58E2,0x58E9,0x58F3,0x5905,0x5906,
+0x590B,0x590C,0x5912,0x5913,0x5914,0x8641,0x591D,0x5921,
+0x5923,0x5924,0x5928,0x592F,0x5930,0x5933,0x5935,0x5936,
+0x593F,0x5943,0x5946,0x5952,0x5953,0x5959,0x595B,0x595D,
+0x595E,0x595F,0x5961,0x5963,0x596B,0x596D};
+
+/* page 17 0x3921-0x397E */
+static uint16 tab_jisx0212_uni17[]={
+0x596F,0x5972,0x5975,0x5976,0x5979,0x597B,0x597C,0x598B,
+0x598C,0x598E,0x5992,0x5995,0x5997,0x599F,0x59A4,0x59A7,
+0x59AD,0x59AE,0x59AF,0x59B0,0x59B3,0x59B7,0x59BA,0x59BC,
+0x59C1,0x59C3,0x59C4,0x59C8,0x59CA,0x59CD,0x59D2,0x59DD,
+0x59DE,0x59DF,0x59E3,0x59E4,0x59E7,0x59EE,0x59EF,0x59F1,
+0x59F2,0x59F4,0x59F7,0x5A00,0x5A04,0x5A0C,0x5A0D,0x5A0E,
+0x5A12,0x5A13,0x5A1E,0x5A23,0x5A24,0x5A27,0x5A28,0x5A2A,
+0x5A2D,0x5A30,0x5A44,0x5A45,0x5A47,0x5A48,0x5A4C,0x5A50,
+0x5A55,0x5A5E,0x5A63,0x5A65,0x5A67,0x5A6D,0x5A77,0x5A7A,
+0x5A7B,0x5A7E,0x5A8B,0x5A90,0x5A93,0x5A96,0x5A99,0x5A9C,
+0x5A9E,0x5A9F,0x5AA0,0x5AA2,0x5AA7,0x5AAC,0x5AB1,0x5AB2,
+0x5AB3,0x5AB5,0x5AB8,0x5ABA,0x5ABB,0x5ABF};
+
+/* page 18 0x3A21-0x3A7E */
+static uint16 tab_jisx0212_uni18[]={
+0x5AC4,0x5AC6,0x5AC8,0x5ACF,0x5ADA,0x5ADC,0x5AE0,0x5AE5,
+0x5AEA,0x5AEE,0x5AF5,0x5AF6,0x5AFD,0x5B00,0x5B01,0x5B08,
+0x5B17,0x5B34,0x5B19,0x5B1B,0x5B1D,0x5B21,0x5B25,0x5B2D,
+0x5B38,0x5B41,0x5B4B,0x5B4C,0x5B52,0x5B56,0x5B5E,0x5B68,
+0x5B6E,0x5B6F,0x5B7C,0x5B7D,0x5B7E,0x5B7F,0x5B81,0x5B84,
+0x5B86,0x5B8A,0x5B8E,0x5B90,0x5B91,0x5B93,0x5B94,0x5B96,
+0x5BA8,0x5BA9,0x5BAC,0x5BAD,0x5BAF,0x5BB1,0x5BB2,0x5BB7,
+0x5BBA,0x5BBC,0x5BC0,0x5BC1,0x5BCD,0x5BCF,0x5BD6,0x5BD7,
+0x5BD8,0x5BD9,0x5BDA,0x5BE0,0x5BEF,0x5BF1,0x5BF4,0x5BFD,
+0x5C0C,0x5C17,0x5C1E,0x5C1F,0x5C23,0x5C26,0x5C29,0x5C2B,
+0x5C2C,0x5C2E,0x5C30,0x5C32,0x5C35,0x5C36,0x5C59,0x5C5A,
+0x5C5C,0x5C62,0x5C63,0x5C67,0x5C68,0x5C69};
+
+/* page 19 0x3B21-0x3B7E */
+static uint16 tab_jisx0212_uni19[]={
+0x5C6D,0x5C70,0x5C74,0x5C75,0x5C7A,0x5C7B,0x5C7C,0x5C7D,
+0x5C87,0x5C88,0x5C8A,0x5C8F,0x5C92,0x5C9D,0x5C9F,0x5CA0,
+0x5CA2,0x5CA3,0x5CA6,0x5CAA,0x5CB2,0x5CB4,0x5CB5,0x5CBA,
+0x5CC9,0x5CCB,0x5CD2,0x5CDD,0x5CD7,0x5CEE,0x5CF1,0x5CF2,
+0x5CF4,0x5D01,0x5D06,0x5D0D,0x5D12,0x5D2B,0x5D23,0x5D24,
+0x5D26,0x5D27,0x5D31,0x5D34,0x5D39,0x5D3D,0x5D3F,0x5D42,
+0x5D43,0x5D46,0x5D48,0x5D55,0x5D51,0x5D59,0x5D4A,0x5D5F,
+0x5D60,0x5D61,0x5D62,0x5D64,0x5D6A,0x5D6D,0x5D70,0x5D79,
+0x5D7A,0x5D7E,0x5D7F,0x5D81,0x5D83,0x5D88,0x5D8A,0x5D92,
+0x5D93,0x5D94,0x5D95,0x5D99,0x5D9B,0x5D9F,0x5DA0,0x5DA7,
+0x5DAB,0x5DB0,0x5DB4,0x5DB8,0x5DB9,0x5DC3,0x5DC7,0x5DCB,
+0x5DD0,0x5DCE,0x5DD8,0x5DD9,0x5DE0,0x5DE4};
+
+/* page 20 0x3C21-0x3C7E */
+static uint16 tab_jisx0212_uni20[]={
+0x5DE9,0x5DF8,0x5DF9,0x5E00,0x5E07,0x5E0D,0x5E12,0x5E14,
+0x5E15,0x5E18,0x5E1F,0x5E20,0x5E2E,0x5E28,0x5E32,0x5E35,
+0x5E3E,0x5E4B,0x5E50,0x5E49,0x5E51,0x5E56,0x5E58,0x5E5B,
+0x5E5C,0x5E5E,0x5E68,0x5E6A,0x5E6B,0x5E6C,0x5E6D,0x5E6E,
+0x5E70,0x5E80,0x5E8B,0x5E8E,0x5EA2,0x5EA4,0x5EA5,0x5EA8,
+0x5EAA,0x5EAC,0x5EB1,0x5EB3,0x5EBD,0x5EBE,0x5EBF,0x5EC6,
+0x5ECC,0x5ECB,0x5ECE,0x5ED1,0x5ED2,0x5ED4,0x5ED5,0x5EDC,
+0x5EDE,0x5EE5,0x5EEB,0x5F02,0x5F06,0x5F07,0x5F08,0x5F0E,
+0x5F19,0x5F1C,0x5F1D,0x5F21,0x5F22,0x5F23,0x5F24,0x5F28,
+0x5F2B,0x5F2C,0x5F2E,0x5F30,0x5F34,0x5F36,0x5F3B,0x5F3D,
+0x5F3F,0x5F40,0x5F44,0x5F45,0x5F47,0x5F4D,0x5F50,0x5F54,
+0x5F58,0x5F5B,0x5F60,0x5F63,0x5F64,0x5F67};
+
+/* page 21 0x3D21-0x3D7E */
+static uint16 tab_jisx0212_uni21[]={
+0x5F6F,0x5F72,0x5F74,0x5F75,0x5F78,0x5F7A,0x5F7D,0x5F7E,
+0x5F89,0x5F8D,0x5F8F,0x5F96,0x5F9C,0x5F9D,0x5FA2,0x5FA7,
+0x5FAB,0x5FA4,0x5FAC,0x5FAF,0x5FB0,0x5FB1,0x5FB8,0x5FC4,
+0x5FC7,0x5FC8,0x5FC9,0x5FCB,0x5FD0,0x5FD1,0x5FD2,0x5FD3,
+0x5FD4,0x5FDE,0x5FE1,0x5FE2,0x5FE8,0x5FE9,0x5FEA,0x5FEC,
+0x5FED,0x5FEE,0x5FEF,0x5FF2,0x5FF3,0x5FF6,0x5FFA,0x5FFC,
+0x6007,0x600A,0x600D,0x6013,0x6014,0x6017,0x6018,0x601A,
+0x601F,0x6024,0x602D,0x6033,0x6035,0x6040,0x6047,0x6048,
+0x6049,0x604C,0x6051,0x6054,0x6056,0x6057,0x605D,0x6061,
+0x6067,0x6071,0x607E,0x607F,0x6082,0x6086,0x6088,0x608A,
+0x608E,0x6091,0x6093,0x6095,0x6098,0x609D,0x609E,0x60A2,
+0x60A4,0x60A5,0x60A8,0x60B0,0x60B1,0x60B7};
+
+/* page 22 0x3E21-0x3E7E */
+static uint16 tab_jisx0212_uni22[]={
+0x60BB,0x60BE,0x60C2,0x60C4,0x60C8,0x60C9,0x60CA,0x60CB,
+0x60CE,0x60CF,0x60D4,0x60D5,0x60D9,0x60DB,0x60DD,0x60DE,
+0x60E2,0x60E5,0x60F2,0x60F5,0x60F8,0x60FC,0x60FD,0x6102,
+0x6107,0x610A,0x610C,0x6110,0x6111,0x6112,0x6113,0x6114,
+0x6116,0x6117,0x6119,0x611C,0x611E,0x6122,0x612A,0x612B,
+0x6130,0x6131,0x6135,0x6136,0x6137,0x6139,0x6141,0x6145,
+0x6146,0x6149,0x615E,0x6160,0x616C,0x6172,0x6178,0x617B,
+0x617C,0x617F,0x6180,0x6181,0x6183,0x6184,0x618B,0x618D,
+0x6192,0x6193,0x6197,0x6198,0x619C,0x619D,0x619F,0x61A0,
+0x61A5,0x61A8,0x61AA,0x61AD,0x61B8,0x61B9,0x61BC,0x61C0,
+0x61C1,0x61C2,0x61CE,0x61CF,0x61D5,0x61DC,0x61DD,0x61DE,
+0x61DF,0x61E1,0x61E2,0x61E7,0x61E9,0x61E5};
+
+/* page 23 0x3F21-0x3F7E */
+static uint16 tab_jisx0212_uni23[]={
+0x61EC,0x61ED,0x61EF,0x6201,0x6203,0x6204,0x6207,0x6213,
+0x6215,0x621C,0x6220,0x6222,0x6223,0x6227,0x6229,0x622B,
+0x6239,0x623D,0x6242,0x6243,0x6244,0x6246,0x624C,0x6250,
+0x6251,0x6252,0x6254,0x6256,0x625A,0x625C,0x6264,0x626D,
+0x626F,0x6273,0x627A,0x627D,0x628D,0x628E,0x628F,0x6290,
+0x62A6,0x62A8,0x62B3,0x62B6,0x62B7,0x62BA,0x62BE,0x62BF,
+0x62C4,0x62CE,0x62D5,0x62D6,0x62DA,0x62EA,0x62F2,0x62F4,
+0x62FC,0x62FD,0x6303,0x6304,0x630A,0x630B,0x630D,0x6310,
+0x6313,0x6316,0x6318,0x6329,0x632A,0x632D,0x6335,0x6336,
+0x6339,0x633C,0x6341,0x6342,0x6343,0x6344,0x6346,0x634A,
+0x634B,0x634E,0x6352,0x6353,0x6354,0x6358,0x635B,0x6365,
+0x6366,0x636C,0x636D,0x6371,0x6374,0x6375};
+
+/* page 24 0x4021-0x407E */
+static uint16 tab_jisx0212_uni24[]={
+0x6378,0x637C,0x637D,0x637F,0x6382,0x6384,0x6387,0x638A,
+0x6390,0x6394,0x6395,0x6399,0x639A,0x639E,0x63A4,0x63A6,
+0x63AD,0x63AE,0x63AF,0x63BD,0x63C1,0x63C5,0x63C8,0x63CE,
+0x63D1,0x63D3,0x63D4,0x63D5,0x63DC,0x63E0,0x63E5,0x63EA,
+0x63EC,0x63F2,0x63F3,0x63F5,0x63F8,0x63F9,0x6409,0x640A,
+0x6410,0x6412,0x6414,0x6418,0x641E,0x6420,0x6422,0x6424,
+0x6425,0x6429,0x642A,0x642F,0x6430,0x6435,0x643D,0x643F,
+0x644B,0x644F,0x6451,0x6452,0x6453,0x6454,0x645A,0x645B,
+0x645C,0x645D,0x645F,0x6460,0x6461,0x6463,0x646D,0x6473,
+0x6474,0x647B,0x647D,0x6485,0x6487,0x648F,0x6490,0x6491,
+0x6498,0x6499,0x649B,0x649D,0x649F,0x64A1,0x64A3,0x64A6,
+0x64A8,0x64AC,0x64B3,0x64BD,0x64BE,0x64BF};
+
+/* page 25 0x4121-0x417E */
+static uint16 tab_jisx0212_uni25[]={
+0x64C4,0x64C9,0x64CA,0x64CB,0x64CC,0x64CE,0x64D0,0x64D1,
+0x64D5,0x64D7,0x64E4,0x64E5,0x64E9,0x64EA,0x64ED,0x64F0,
+0x64F5,0x64F7,0x64FB,0x64FF,0x6501,0x6504,0x6508,0x6509,
+0x650A,0x650F,0x6513,0x6514,0x6516,0x6519,0x651B,0x651E,
+0x651F,0x6522,0x6526,0x6529,0x652E,0x6531,0x653A,0x653C,
+0x653D,0x6543,0x6547,0x6549,0x6550,0x6552,0x6554,0x655F,
+0x6560,0x6567,0x656B,0x657A,0x657D,0x6581,0x6585,0x658A,
+0x6592,0x6595,0x6598,0x659D,0x65A0,0x65A3,0x65A6,0x65AE,
+0x65B2,0x65B3,0x65B4,0x65BF,0x65C2,0x65C8,0x65C9,0x65CE,
+0x65D0,0x65D4,0x65D6,0x65D8,0x65DF,0x65F0,0x65F2,0x65F4,
+0x65F5,0x65F9,0x65FE,0x65FF,0x6600,0x6604,0x6608,0x6609,
+0x660D,0x6611,0x6612,0x6615,0x6616,0x661D};
+
+/* page 26 0x4221-0x427E */
+static uint16 tab_jisx0212_uni26[]={
+0x661E,0x6621,0x6622,0x6623,0x6624,0x6626,0x6629,0x662A,
+0x662B,0x662C,0x662E,0x6630,0x6631,0x6633,0x6639,0x6637,
+0x6640,0x6645,0x6646,0x664A,0x664C,0x6651,0x664E,0x6657,
+0x6658,0x6659,0x665B,0x665C,0x6660,0x6661,0x66FB,0x666A,
+0x666B,0x666C,0x667E,0x6673,0x6675,0x667F,0x6677,0x6678,
+0x6679,0x667B,0x6680,0x667C,0x668B,0x668C,0x668D,0x6690,
+0x6692,0x6699,0x669A,0x669B,0x669C,0x669F,0x66A0,0x66A4,
+0x66AD,0x66B1,0x66B2,0x66B5,0x66BB,0x66BF,0x66C0,0x66C2,
+0x66C3,0x66C8,0x66CC,0x66CE,0x66CF,0x66D4,0x66DB,0x66DF,
+0x66E8,0x66EB,0x66EC,0x66EE,0x66FA,0x6705,0x6707,0x670E,
+0x6713,0x6719,0x671C,0x6720,0x6722,0x6733,0x673E,0x6745,
+0x6747,0x6748,0x674C,0x6754,0x6755,0x675D};
+
+/* page 27 0x4321-0x437E */
+static uint16 tab_jisx0212_uni27[]={
+0x6766,0x676C,0x676E,0x6774,0x6776,0x677B,0x6781,0x6784,
+0x678E,0x678F,0x6791,0x6793,0x6796,0x6798,0x6799,0x679B,
+0x67B0,0x67B1,0x67B2,0x67B5,0x67BB,0x67BC,0x67BD,0x67F9,
+0x67C0,0x67C2,0x67C3,0x67C5,0x67C8,0x67C9,0x67D2,0x67D7,
+0x67D9,0x67DC,0x67E1,0x67E6,0x67F0,0x67F2,0x67F6,0x67F7,
+0x6852,0x6814,0x6819,0x681D,0x681F,0x6828,0x6827,0x682C,
+0x682D,0x682F,0x6830,0x6831,0x6833,0x683B,0x683F,0x6844,
+0x6845,0x684A,0x684C,0x6855,0x6857,0x6858,0x685B,0x686B,
+0x686E,0x686F,0x6870,0x6871,0x6872,0x6875,0x6879,0x687A,
+0x687B,0x687C,0x6882,0x6884,0x6886,0x6888,0x6896,0x6898,
+0x689A,0x689C,0x68A1,0x68A3,0x68A5,0x68A9,0x68AA,0x68AE,
+0x68B2,0x68BB,0x68C5,0x68C8,0x68CC,0x68CF};
+
+/* page 28 0x4421-0x447E */
+static uint16 tab_jisx0212_uni28[]={
+0x68D0,0x68D1,0x68D3,0x68D6,0x68D9,0x68DC,0x68DD,0x68E5,
+0x68E8,0x68EA,0x68EB,0x68EC,0x68ED,0x68F0,0x68F1,0x68F5,
+0x68F6,0x68FB,0x68FC,0x68FD,0x6906,0x6909,0x690A,0x6910,
+0x6911,0x6913,0x6916,0x6917,0x6931,0x6933,0x6935,0x6938,
+0x693B,0x6942,0x6945,0x6949,0x694E,0x6957,0x695B,0x6963,
+0x6964,0x6965,0x6966,0x6968,0x6969,0x696C,0x6970,0x6971,
+0x6972,0x697A,0x697B,0x697F,0x6980,0x698D,0x6992,0x6996,
+0x6998,0x69A1,0x69A5,0x69A6,0x69A8,0x69AB,0x69AD,0x69AF,
+0x69B7,0x69B8,0x69BA,0x69BC,0x69C5,0x69C8,0x69D1,0x69D6,
+0x69D7,0x69E2,0x69E5,0x69EE,0x69EF,0x69F1,0x69F3,0x69F5,
+0x69FE,0x6A00,0x6A01,0x6A03,0x6A0F,0x6A11,0x6A15,0x6A1A,
+0x6A1D,0x6A20,0x6A24,0x6A28,0x6A30,0x6A32};
+
+/* page 29 0x4521-0x457E */
+static uint16 tab_jisx0212_uni29[]={
+0x6A34,0x6A37,0x6A3B,0x6A3E,0x6A3F,0x6A45,0x6A46,0x6A49,
+0x6A4A,0x6A4E,0x6A50,0x6A51,0x6A52,0x6A55,0x6A56,0x6A5B,
+0x6A64,0x6A67,0x6A6A,0x6A71,0x6A73,0x6A7E,0x6A81,0x6A83,
+0x6A86,0x6A87,0x6A89,0x6A8B,0x6A91,0x6A9B,0x6A9D,0x6A9E,
+0x6A9F,0x6AA5,0x6AAB,0x6AAF,0x6AB0,0x6AB1,0x6AB4,0x6ABD,
+0x6ABE,0x6ABF,0x6AC6,0x6AC9,0x6AC8,0x6ACC,0x6AD0,0x6AD4,
+0x6AD5,0x6AD6,0x6ADC,0x6ADD,0x6AE4,0x6AE7,0x6AEC,0x6AF0,
+0x6AF1,0x6AF2,0x6AFC,0x6AFD,0x6B02,0x6B03,0x6B06,0x6B07,
+0x6B09,0x6B0F,0x6B10,0x6B11,0x6B17,0x6B1B,0x6B1E,0x6B24,
+0x6B28,0x6B2B,0x6B2C,0x6B2F,0x6B35,0x6B36,0x6B3B,0x6B3F,
+0x6B46,0x6B4A,0x6B4D,0x6B52,0x6B56,0x6B58,0x6B5D,0x6B60,
+0x6B67,0x6B6B,0x6B6E,0x6B70,0x6B75,0x6B7D};
+
+/* page 30 0x4621-0x467E */
+static uint16 tab_jisx0212_uni30[]={
+0x6B7E,0x6B82,0x6B85,0x6B97,0x6B9B,0x6B9F,0x6BA0,0x6BA2,
+0x6BA3,0x6BA8,0x6BA9,0x6BAC,0x6BAD,0x6BAE,0x6BB0,0x6BB8,
+0x6BB9,0x6BBD,0x6BBE,0x6BC3,0x6BC4,0x6BC9,0x6BCC,0x6BD6,
+0x6BDA,0x6BE1,0x6BE3,0x6BE6,0x6BE7,0x6BEE,0x6BF1,0x6BF7,
+0x6BF9,0x6BFF,0x6C02,0x6C04,0x6C05,0x6C09,0x6C0D,0x6C0E,
+0x6C10,0x6C12,0x6C19,0x6C1F,0x6C26,0x6C27,0x6C28,0x6C2C,
+0x6C2E,0x6C33,0x6C35,0x6C36,0x6C3A,0x6C3B,0x6C3F,0x6C4A,
+0x6C4B,0x6C4D,0x6C4F,0x6C52,0x6C54,0x6C59,0x6C5B,0x6C5C,
+0x6C6B,0x6C6D,0x6C6F,0x6C74,0x6C76,0x6C78,0x6C79,0x6C7B,
+0x6C85,0x6C86,0x6C87,0x6C89,0x6C94,0x6C95,0x6C97,0x6C98,
+0x6C9C,0x6C9F,0x6CB0,0x6CB2,0x6CB4,0x6CC2,0x6CC6,0x6CCD,
+0x6CCF,0x6CD0,0x6CD1,0x6CD2,0x6CD4,0x6CD6};
+
+/* page 31 0x4721-0x477E */
+static uint16 tab_jisx0212_uni31[]={
+0x6CDA,0x6CDC,0x6CE0,0x6CE7,0x6CE9,0x6CEB,0x6CEC,0x6CEE,
+0x6CF2,0x6CF4,0x6D04,0x6D07,0x6D0A,0x6D0E,0x6D0F,0x6D11,
+0x6D13,0x6D1A,0x6D26,0x6D27,0x6D28,0x6C67,0x6D2E,0x6D2F,
+0x6D31,0x6D39,0x6D3C,0x6D3F,0x6D57,0x6D5E,0x6D5F,0x6D61,
+0x6D65,0x6D67,0x6D6F,0x6D70,0x6D7C,0x6D82,0x6D87,0x6D91,
+0x6D92,0x6D94,0x6D96,0x6D97,0x6D98,0x6DAA,0x6DAC,0x6DB4,
+0x6DB7,0x6DB9,0x6DBD,0x6DBF,0x6DC4,0x6DC8,0x6DCA,0x6DCE,
+0x6DCF,0x6DD6,0x6DDB,0x6DDD,0x6DDF,0x6DE0,0x6DE2,0x6DE5,
+0x6DE9,0x6DEF,0x6DF0,0x6DF4,0x6DF6,0x6DFC,0x6E00,0x6E04,
+0x6E1E,0x6E22,0x6E27,0x6E32,0x6E36,0x6E39,0x6E3B,0x6E3C,
+0x6E44,0x6E45,0x6E48,0x6E49,0x6E4B,0x6E4F,0x6E51,0x6E52,
+0x6E53,0x6E54,0x6E57,0x6E5C,0x6E5D,0x6E5E};
+
+/* page 32 0x4821-0x487E */
+static uint16 tab_jisx0212_uni32[]={
+0x6E62,0x6E63,0x6E68,0x6E73,0x6E7B,0x6E7D,0x6E8D,0x6E93,
+0x6E99,0x6EA0,0x6EA7,0x6EAD,0x6EAE,0x6EB1,0x6EB3,0x6EBB,
+0x6EBF,0x6EC0,0x6EC1,0x6EC3,0x6EC7,0x6EC8,0x6ECA,0x6ECD,
+0x6ECE,0x6ECF,0x6EEB,0x6EED,0x6EEE,0x6EF9,0x6EFB,0x6EFD,
+0x6F04,0x6F08,0x6F0A,0x6F0C,0x6F0D,0x6F16,0x6F18,0x6F1A,
+0x6F1B,0x6F26,0x6F29,0x6F2A,0x6F2F,0x6F30,0x6F33,0x6F36,
+0x6F3B,0x6F3C,0x6F2D,0x6F4F,0x6F51,0x6F52,0x6F53,0x6F57,
+0x6F59,0x6F5A,0x6F5D,0x6F5E,0x6F61,0x6F62,0x6F68,0x6F6C,
+0x6F7D,0x6F7E,0x6F83,0x6F87,0x6F88,0x6F8B,0x6F8C,0x6F8D,
+0x6F90,0x6F92,0x6F93,0x6F94,0x6F96,0x6F9A,0x6F9F,0x6FA0,
+0x6FA5,0x6FA6,0x6FA7,0x6FA8,0x6FAE,0x6FAF,0x6FB0,0x6FB5,
+0x6FB6,0x6FBC,0x6FC5,0x6FC7,0x6FC8,0x6FCA};
+
+/* page 33 0x4921-0x497E */
+static uint16 tab_jisx0212_uni33[]={
+0x6FDA,0x6FDE,0x6FE8,0x6FE9,0x6FF0,0x6FF5,0x6FF9,0x6FFC,
+0x6FFD,0x7000,0x7005,0x7006,0x7007,0x700D,0x7017,0x7020,
+0x7023,0x702F,0x7034,0x7037,0x7039,0x703C,0x7043,0x7044,
+0x7048,0x7049,0x704A,0x704B,0x7054,0x7055,0x705D,0x705E,
+0x704E,0x7064,0x7065,0x706C,0x706E,0x7075,0x7076,0x707E,
+0x7081,0x7085,0x7086,0x7094,0x7095,0x7096,0x7097,0x7098,
+0x709B,0x70A4,0x70AB,0x70B0,0x70B1,0x70B4,0x70B7,0x70CA,
+0x70D1,0x70D3,0x70D4,0x70D5,0x70D6,0x70D8,0x70DC,0x70E4,
+0x70FA,0x7103,0x7104,0x7105,0x7106,0x7107,0x710B,0x710C,
+0x710F,0x711E,0x7120,0x712B,0x712D,0x712F,0x7130,0x7131,
+0x7138,0x7141,0x7145,0x7146,0x7147,0x714A,0x714B,0x7150,
+0x7152,0x7157,0x715A,0x715C,0x715E,0x7160};
+
+/* page 34 0x4A21-0x4A7E */
+static uint16 tab_jisx0212_uni34[]={
+0x7168,0x7179,0x7180,0x7185,0x7187,0x718C,0x7192,0x719A,
+0x719B,0x71A0,0x71A2,0x71AF,0x71B0,0x71B2,0x71B3,0x71BA,
+0x71BF,0x71C0,0x71C1,0x71C4,0x71CB,0x71CC,0x71D3,0x71D6,
+0x71D9,0x71DA,0x71DC,0x71F8,0x71FE,0x7200,0x7207,0x7208,
+0x7209,0x7213,0x7217,0x721A,0x721D,0x721F,0x7224,0x722B,
+0x722F,0x7234,0x7238,0x7239,0x7241,0x7242,0x7243,0x7245,
+0x724E,0x724F,0x7250,0x7253,0x7255,0x7256,0x725A,0x725C,
+0x725E,0x7260,0x7263,0x7268,0x726B,0x726E,0x726F,0x7271,
+0x7277,0x7278,0x727B,0x727C,0x727F,0x7284,0x7289,0x728D,
+0x728E,0x7293,0x729B,0x72A8,0x72AD,0x72AE,0x72B1,0x72B4,
+0x72BE,0x72C1,0x72C7,0x72C9,0x72CC,0x72D5,0x72D6,0x72D8,
+0x72DF,0x72E5,0x72F3,0x72F4,0x72FA,0x72FB};
+
+/* page 35 0x4B21-0x4B7E */
+static uint16 tab_jisx0212_uni35[]={
+0x72FE,0x7302,0x7304,0x7305,0x7307,0x730B,0x730D,0x7312,
+0x7313,0x7318,0x7319,0x731E,0x7322,0x7324,0x7327,0x7328,
+0x732C,0x7331,0x7332,0x7335,0x733A,0x733B,0x733D,0x7343,
+0x734D,0x7350,0x7352,0x7356,0x7358,0x735D,0x735E,0x735F,
+0x7360,0x7366,0x7367,0x7369,0x736B,0x736C,0x736E,0x736F,
+0x7371,0x7377,0x7379,0x737C,0x7380,0x7381,0x7383,0x7385,
+0x7386,0x738E,0x7390,0x7393,0x7395,0x7397,0x7398,0x739C,
+0x739E,0x739F,0x73A0,0x73A2,0x73A5,0x73A6,0x73AA,0x73AB,
+0x73AD,0x73B5,0x73B7,0x73B9,0x73BC,0x73BD,0x73BF,0x73C5,
+0x73C6,0x73C9,0x73CB,0x73CC,0x73CF,0x73D2,0x73D3,0x73D6,
+0x73D9,0x73DD,0x73E1,0x73E3,0x73E6,0x73E7,0x73E9,0x73F4,
+0x73F5,0x73F7,0x73F9,0x73FA,0x73FB,0x73FD};
+
+/* page 36 0x4C21-0x4C7E */
+static uint16 tab_jisx0212_uni36[]={
+0x73FF,0x7400,0x7401,0x7404,0x7407,0x740A,0x7411,0x741A,
+0x741B,0x7424,0x7426,0x7428,0x7429,0x742A,0x742B,0x742C,
+0x742D,0x742E,0x742F,0x7430,0x7431,0x7439,0x7440,0x7443,
+0x7444,0x7446,0x7447,0x744B,0x744D,0x7451,0x7452,0x7457,
+0x745D,0x7462,0x7466,0x7467,0x7468,0x746B,0x746D,0x746E,
+0x7471,0x7472,0x7480,0x7481,0x7485,0x7486,0x7487,0x7489,
+0x748F,0x7490,0x7491,0x7492,0x7498,0x7499,0x749A,0x749C,
+0x749F,0x74A0,0x74A1,0x74A3,0x74A6,0x74A8,0x74A9,0x74AA,
+0x74AB,0x74AE,0x74AF,0x74B1,0x74B2,0x74B5,0x74B9,0x74BB,
+0x74BF,0x74C8,0x74C9,0x74CC,0x74D0,0x74D3,0x74D8,0x74DA,
+0x74DB,0x74DE,0x74DF,0x74E4,0x74E8,0x74EA,0x74EB,0x74EF,
+0x74F4,0x74FA,0x74FB,0x74FC,0x74FF,0x7506};
+
+/* page 37 0x4D21-0x4D7E */
+static uint16 tab_jisx0212_uni37[]={
+0x7512,0x7516,0x7517,0x7520,0x7521,0x7524,0x7527,0x7529,
+0x752A,0x752F,0x7536,0x7539,0x753D,0x753E,0x753F,0x7540,
+0x7543,0x7547,0x7548,0x754E,0x7550,0x7552,0x7557,0x755E,
+0x755F,0x7561,0x756F,0x7571,0x7579,0x757A,0x757B,0x757C,
+0x757D,0x757E,0x7581,0x7585,0x7590,0x7592,0x7593,0x7595,
+0x7599,0x759C,0x75A2,0x75A4,0x75B4,0x75BA,0x75BF,0x75C0,
+0x75C1,0x75C4,0x75C6,0x75CC,0x75CE,0x75CF,0x75D7,0x75DC,
+0x75DF,0x75E0,0x75E1,0x75E4,0x75E7,0x75EC,0x75EE,0x75EF,
+0x75F1,0x75F9,0x7600,0x7602,0x7603,0x7604,0x7607,0x7608,
+0x760A,0x760C,0x760F,0x7612,0x7613,0x7615,0x7616,0x7619,
+0x761B,0x761C,0x761D,0x761E,0x7623,0x7625,0x7626,0x7629,
+0x762D,0x7632,0x7633,0x7635,0x7638,0x7639};
+
+/* page 38 0x4E21-0x4E7E */
+static uint16 tab_jisx0212_uni38[]={
+0x763A,0x763C,0x764A,0x7640,0x7641,0x7643,0x7644,0x7645,
+0x7649,0x764B,0x7655,0x7659,0x765F,0x7664,0x7665,0x766D,
+0x766E,0x766F,0x7671,0x7674,0x7681,0x7685,0x768C,0x768D,
+0x7695,0x769B,0x769C,0x769D,0x769F,0x76A0,0x76A2,0x76A3,
+0x76A4,0x76A5,0x76A6,0x76A7,0x76A8,0x76AA,0x76AD,0x76BD,
+0x76C1,0x76C5,0x76C9,0x76CB,0x76CC,0x76CE,0x76D4,0x76D9,
+0x76E0,0x76E6,0x76E8,0x76EC,0x76F0,0x76F1,0x76F6,0x76F9,
+0x76FC,0x7700,0x7706,0x770A,0x770E,0x7712,0x7714,0x7715,
+0x7717,0x7719,0x771A,0x771C,0x7722,0x7728,0x772D,0x772E,
+0x772F,0x7734,0x7735,0x7736,0x7739,0x773D,0x773E,0x7742,
+0x7745,0x7746,0x774A,0x774D,0x774E,0x774F,0x7752,0x7756,
+0x7757,0x775C,0x775E,0x775F,0x7760,0x7762};
+
+/* page 39 0x4F21-0x4F7E */
+static uint16 tab_jisx0212_uni39[]={
+0x7764,0x7767,0x776A,0x776C,0x7770,0x7772,0x7773,0x7774,
+0x777A,0x777D,0x7780,0x7784,0x778C,0x778D,0x7794,0x7795,
+0x7796,0x779A,0x779F,0x77A2,0x77A7,0x77AA,0x77AE,0x77AF,
+0x77B1,0x77B5,0x77BE,0x77C3,0x77C9,0x77D1,0x77D2,0x77D5,
+0x77D9,0x77DE,0x77DF,0x77E0,0x77E4,0x77E6,0x77EA,0x77EC,
+0x77F0,0x77F1,0x77F4,0x77F8,0x77FB,0x7805,0x7806,0x7809,
+0x780D,0x780E,0x7811,0x781D,0x7821,0x7822,0x7823,0x782D,
+0x782E,0x7830,0x7835,0x7837,0x7843,0x7844,0x7847,0x7848,
+0x784C,0x784E,0x7852,0x785C,0x785E,0x7860,0x7861,0x7863,
+0x7864,0x7868,0x786A,0x786E,0x787A,0x787E,0x788A,0x788F,
+0x7894,0x7898,0x78A1,0x789D,0x789E,0x789F,0x78A4,0x78A8,
+0x78AC,0x78AD,0x78B0,0x78B1,0x78B2,0x78B3};
+
+/* page 40 0x5021-0x507E */
+static uint16 tab_jisx0212_uni40[]={
+0x78BB,0x78BD,0x78BF,0x78C7,0x78C8,0x78C9,0x78CC,0x78CE,
+0x78D2,0x78D3,0x78D5,0x78D6,0x78E4,0x78DB,0x78DF,0x78E0,
+0x78E1,0x78E6,0x78EA,0x78F2,0x78F3,0x7900,0x78F6,0x78F7,
+0x78FA,0x78FB,0x78FF,0x7906,0x790C,0x7910,0x791A,0x791C,
+0x791E,0x791F,0x7920,0x7925,0x7927,0x7929,0x792D,0x7931,
+0x7934,0x7935,0x793B,0x793D,0x793F,0x7944,0x7945,0x7946,
+0x794A,0x794B,0x794F,0x7951,0x7954,0x7958,0x795B,0x795C,
+0x7967,0x7969,0x796B,0x7972,0x7979,0x797B,0x797C,0x797E,
+0x798B,0x798C,0x7991,0x7993,0x7994,0x7995,0x7996,0x7998,
+0x799B,0x799C,0x79A1,0x79A8,0x79A9,0x79AB,0x79AF,0x79B1,
+0x79B4,0x79B8,0x79BB,0x79C2,0x79C4,0x79C7,0x79C8,0x79CA,
+0x79CF,0x79D4,0x79D6,0x79DA,0x79DD,0x79DE};
+
+/* page 41 0x5121-0x517E */
+static uint16 tab_jisx0212_uni41[]={
+0x79E0,0x79E2,0x79E5,0x79EA,0x79EB,0x79ED,0x79F1,0x79F8,
+0x79FC,0x7A02,0x7A03,0x7A07,0x7A09,0x7A0A,0x7A0C,0x7A11,
+0x7A15,0x7A1B,0x7A1E,0x7A21,0x7A27,0x7A2B,0x7A2D,0x7A2F,
+0x7A30,0x7A34,0x7A35,0x7A38,0x7A39,0x7A3A,0x7A44,0x7A45,
+0x7A47,0x7A48,0x7A4C,0x7A55,0x7A56,0x7A59,0x7A5C,0x7A5D,
+0x7A5F,0x7A60,0x7A65,0x7A67,0x7A6A,0x7A6D,0x7A75,0x7A78,
+0x7A7E,0x7A80,0x7A82,0x7A85,0x7A86,0x7A8A,0x7A8B,0x7A90,
+0x7A91,0x7A94,0x7A9E,0x7AA0,0x7AA3,0x7AAC,0x7AB3,0x7AB5,
+0x7AB9,0x7ABB,0x7ABC,0x7AC6,0x7AC9,0x7ACC,0x7ACE,0x7AD1,
+0x7ADB,0x7AE8,0x7AE9,0x7AEB,0x7AEC,0x7AF1,0x7AF4,0x7AFB,
+0x7AFD,0x7AFE,0x7B07,0x7B14,0x7B1F,0x7B23,0x7B27,0x7B29,
+0x7B2A,0x7B2B,0x7B2D,0x7B2E,0x7B2F,0x7B30};
+
+/* page 42 0x5221-0x527E */
+static uint16 tab_jisx0212_uni42[]={
+0x7B31,0x7B34,0x7B3D,0x7B3F,0x7B40,0x7B41,0x7B47,0x7B4E,
+0x7B55,0x7B60,0x7B64,0x7B66,0x7B69,0x7B6A,0x7B6D,0x7B6F,
+0x7B72,0x7B73,0x7B77,0x7B84,0x7B89,0x7B8E,0x7B90,0x7B91,
+0x7B96,0x7B9B,0x7B9E,0x7BA0,0x7BA5,0x7BAC,0x7BAF,0x7BB0,
+0x7BB2,0x7BB5,0x7BB6,0x7BBA,0x7BBB,0x7BBC,0x7BBD,0x7BC2,
+0x7BC5,0x7BC8,0x7BCA,0x7BD4,0x7BD6,0x7BD7,0x7BD9,0x7BDA,
+0x7BDB,0x7BE8,0x7BEA,0x7BF2,0x7BF4,0x7BF5,0x7BF8,0x7BF9,
+0x7BFA,0x7BFC,0x7BFE,0x7C01,0x7C02,0x7C03,0x7C04,0x7C06,
+0x7C09,0x7C0B,0x7C0C,0x7C0E,0x7C0F,0x7C19,0x7C1B,0x7C20,
+0x7C25,0x7C26,0x7C28,0x7C2C,0x7C31,0x7C33,0x7C34,0x7C36,
+0x7C39,0x7C3A,0x7C46,0x7C4A,0x7C55,0x7C51,0x7C52,0x7C53,
+0x7C59,0x7C5A,0x7C5B,0x7C5C,0x7C5D,0x7C5E};
+
+/* page 43 0x5321-0x537E */
+static uint16 tab_jisx0212_uni43[]={
+0x7C61,0x7C63,0x7C67,0x7C69,0x7C6D,0x7C6E,0x7C70,0x7C72,
+0x7C79,0x7C7C,0x7C7D,0x7C86,0x7C87,0x7C8F,0x7C94,0x7C9E,
+0x7CA0,0x7CA6,0x7CB0,0x7CB6,0x7CB7,0x7CBA,0x7CBB,0x7CBC,
+0x7CBF,0x7CC4,0x7CC7,0x7CC8,0x7CC9,0x7CCD,0x7CCF,0x7CD3,
+0x7CD4,0x7CD5,0x7CD7,0x7CD9,0x7CDA,0x7CDD,0x7CE6,0x7CE9,
+0x7CEB,0x7CF5,0x7D03,0x7D07,0x7D08,0x7D09,0x7D0F,0x7D11,
+0x7D12,0x7D13,0x7D16,0x7D1D,0x7D1E,0x7D23,0x7D26,0x7D2A,
+0x7D2D,0x7D31,0x7D3C,0x7D3D,0x7D3E,0x7D40,0x7D41,0x7D47,
+0x7D48,0x7D4D,0x7D51,0x7D53,0x7D57,0x7D59,0x7D5A,0x7D5C,
+0x7D5D,0x7D65,0x7D67,0x7D6A,0x7D70,0x7D78,0x7D7A,0x7D7B,
+0x7D7F,0x7D81,0x7D82,0x7D83,0x7D85,0x7D86,0x7D88,0x7D8B,
+0x7D8C,0x7D8D,0x7D91,0x7D96,0x7D97,0x7D9D};
+
+/* page 44 0x5421-0x547E */
+static uint16 tab_jisx0212_uni44[]={
+0x7D9E,0x7DA6,0x7DA7,0x7DAA,0x7DB3,0x7DB6,0x7DB7,0x7DB9,
+0x7DC2,0x7DC3,0x7DC4,0x7DC5,0x7DC6,0x7DCC,0x7DCD,0x7DCE,
+0x7DD7,0x7DD9,0x7E00,0x7DE2,0x7DE5,0x7DE6,0x7DEA,0x7DEB,
+0x7DED,0x7DF1,0x7DF5,0x7DF6,0x7DF9,0x7DFA,0x7E08,0x7E10,
+0x7E11,0x7E15,0x7E17,0x7E1C,0x7E1D,0x7E20,0x7E27,0x7E28,
+0x7E2C,0x7E2D,0x7E2F,0x7E33,0x7E36,0x7E3F,0x7E44,0x7E45,
+0x7E47,0x7E4E,0x7E50,0x7E52,0x7E58,0x7E5F,0x7E61,0x7E62,
+0x7E65,0x7E6B,0x7E6E,0x7E6F,0x7E73,0x7E78,0x7E7E,0x7E81,
+0x7E86,0x7E87,0x7E8A,0x7E8D,0x7E91,0x7E95,0x7E98,0x7E9A,
+0x7E9D,0x7E9E,0x7F3C,0x7F3B,0x7F3D,0x7F3E,0x7F3F,0x7F43,
+0x7F44,0x7F47,0x7F4F,0x7F52,0x7F53,0x7F5B,0x7F5C,0x7F5D,
+0x7F61,0x7F63,0x7F64,0x7F65,0x7F66,0x7F6D};
+
+/* page 45 0x5521-0x557E */
+static uint16 tab_jisx0212_uni45[]={
+0x7F71,0x7F7D,0x7F7E,0x7F7F,0x7F80,0x7F8B,0x7F8D,0x7F8F,
+0x7F90,0x7F91,0x7F96,0x7F97,0x7F9C,0x7FA1,0x7FA2,0x7FA6,
+0x7FAA,0x7FAD,0x7FB4,0x7FBC,0x7FBF,0x7FC0,0x7FC3,0x7FC8,
+0x7FCE,0x7FCF,0x7FDB,0x7FDF,0x7FE3,0x7FE5,0x7FE8,0x7FEC,
+0x7FEE,0x7FEF,0x7FF2,0x7FFA,0x7FFD,0x7FFE,0x7FFF,0x8007,
+0x8008,0x800A,0x800D,0x800E,0x800F,0x8011,0x8013,0x8014,
+0x8016,0x801D,0x801E,0x801F,0x8020,0x8024,0x8026,0x802C,
+0x802E,0x8030,0x8034,0x8035,0x8037,0x8039,0x803A,0x803C,
+0x803E,0x8040,0x8044,0x8060,0x8064,0x8066,0x806D,0x8071,
+0x8075,0x8081,0x8088,0x808E,0x809C,0x809E,0x80A6,0x80A7,
+0x80AB,0x80B8,0x80B9,0x80C8,0x80CD,0x80CF,0x80D2,0x80D4,
+0x80D5,0x80D7,0x80D8,0x80E0,0x80ED,0x80EE};
+
+/* page 46 0x5621-0x567E */
+static uint16 tab_jisx0212_uni46[]={
+0x80F0,0x80F2,0x80F3,0x80F6,0x80F9,0x80FA,0x80FE,0x8103,
+0x810B,0x8116,0x8117,0x8118,0x811C,0x811E,0x8120,0x8124,
+0x8127,0x812C,0x8130,0x8135,0x813A,0x813C,0x8145,0x8147,
+0x814A,0x814C,0x8152,0x8157,0x8160,0x8161,0x8167,0x8168,
+0x8169,0x816D,0x816F,0x8177,0x8181,0x8190,0x8184,0x8185,
+0x8186,0x818B,0x818E,0x8196,0x8198,0x819B,0x819E,0x81A2,
+0x81AE,0x81B2,0x81B4,0x81BB,0x81CB,0x81C3,0x81C5,0x81CA,
+0x81CE,0x81CF,0x81D5,0x81D7,0x81DB,0x81DD,0x81DE,0x81E1,
+0x81E4,0x81EB,0x81EC,0x81F0,0x81F1,0x81F2,0x81F5,0x81F6,
+0x81F8,0x81F9,0x81FD,0x81FF,0x8200,0x8203,0x820F,0x8213,
+0x8214,0x8219,0x821A,0x821D,0x8221,0x8222,0x8228,0x8232,
+0x8234,0x823A,0x8243,0x8244,0x8245,0x8246};
+
+/* page 47 0x5721-0x577E */
+static uint16 tab_jisx0212_uni47[]={
+0x824B,0x824E,0x824F,0x8251,0x8256,0x825C,0x8260,0x8263,
+0x8267,0x826D,0x8274,0x827B,0x827D,0x827F,0x8280,0x8281,
+0x8283,0x8284,0x8287,0x8289,0x828A,0x828E,0x8291,0x8294,
+0x8296,0x8298,0x829A,0x829B,0x82A0,0x82A1,0x82A3,0x82A4,
+0x82A7,0x82A8,0x82A9,0x82AA,0x82AE,0x82B0,0x82B2,0x82B4,
+0x82B7,0x82BA,0x82BC,0x82BE,0x82BF,0x82C6,0x82D0,0x82D5,
+0x82DA,0x82E0,0x82E2,0x82E4,0x82E8,0x82EA,0x82ED,0x82EF,
+0x82F6,0x82F7,0x82FD,0x82FE,0x8300,0x8301,0x8307,0x8308,
+0x830A,0x830B,0x8354,0x831B,0x831D,0x831E,0x831F,0x8321,
+0x8322,0x832C,0x832D,0x832E,0x8330,0x8333,0x8337,0x833A,
+0x833C,0x833D,0x8342,0x8343,0x8344,0x8347,0x834D,0x834E,
+0x8351,0x8355,0x8356,0x8357,0x8370,0x8378};
+
+/* page 48 0x5821-0x587E */
+static uint16 tab_jisx0212_uni48[]={
+0x837D,0x837F,0x8380,0x8382,0x8384,0x8386,0x838D,0x8392,
+0x8394,0x8395,0x8398,0x8399,0x839B,0x839C,0x839D,0x83A6,
+0x83A7,0x83A9,0x83AC,0x83BE,0x83BF,0x83C0,0x83C7,0x83C9,
+0x83CF,0x83D0,0x83D1,0x83D4,0x83DD,0x8353,0x83E8,0x83EA,
+0x83F6,0x83F8,0x83F9,0x83FC,0x8401,0x8406,0x840A,0x840F,
+0x8411,0x8415,0x8419,0x83AD,0x842F,0x8439,0x8445,0x8447,
+0x8448,0x844A,0x844D,0x844F,0x8451,0x8452,0x8456,0x8458,
+0x8459,0x845A,0x845C,0x8460,0x8464,0x8465,0x8467,0x846A,
+0x8470,0x8473,0x8474,0x8476,0x8478,0x847C,0x847D,0x8481,
+0x8485,0x8492,0x8493,0x8495,0x849E,0x84A6,0x84A8,0x84A9,
+0x84AA,0x84AF,0x84B1,0x84B4,0x84BA,0x84BD,0x84BE,0x84C0,
+0x84C2,0x84C7,0x84C8,0x84CC,0x84CF,0x84D3};
+
+/* page 49 0x5921-0x597E */
+static uint16 tab_jisx0212_uni49[]={
+0x84DC,0x84E7,0x84EA,0x84EF,0x84F0,0x84F1,0x84F2,0x84F7,
+0x8532,0x84FA,0x84FB,0x84FD,0x8502,0x8503,0x8507,0x850C,
+0x850E,0x8510,0x851C,0x851E,0x8522,0x8523,0x8524,0x8525,
+0x8527,0x852A,0x852B,0x852F,0x8533,0x8534,0x8536,0x853F,
+0x8546,0x854F,0x8550,0x8551,0x8552,0x8553,0x8556,0x8559,
+0x855C,0x855D,0x855E,0x855F,0x8560,0x8561,0x8562,0x8564,
+0x856B,0x856F,0x8579,0x857A,0x857B,0x857D,0x857F,0x8581,
+0x8585,0x8586,0x8589,0x858B,0x858C,0x858F,0x8593,0x8598,
+0x859D,0x859F,0x85A0,0x85A2,0x85A5,0x85A7,0x85B4,0x85B6,
+0x85B7,0x85B8,0x85BC,0x85BD,0x85BE,0x85BF,0x85C2,0x85C7,
+0x85CA,0x85CB,0x85CE,0x85AD,0x85D8,0x85DA,0x85DF,0x85E0,
+0x85E6,0x85E8,0x85ED,0x85F3,0x85F6,0x85FC};
+
+/* page 50 0x5A21-0x5A7E */
+static uint16 tab_jisx0212_uni50[]={
+0x85FF,0x8600,0x8604,0x8605,0x860D,0x860E,0x8610,0x8611,
+0x8612,0x8618,0x8619,0x861B,0x861E,0x8621,0x8627,0x8629,
+0x8636,0x8638,0x863A,0x863C,0x863D,0x8640,0x8642,0x8646,
+0x8652,0x8653,0x8656,0x8657,0x8658,0x8659,0x865D,0x8660,
+0x8661,0x8662,0x8663,0x8664,0x8669,0x866C,0x866F,0x8675,
+0x8676,0x8677,0x867A,0x868D,0x8691,0x8696,0x8698,0x869A,
+0x869C,0x86A1,0x86A6,0x86A7,0x86A8,0x86AD,0x86B1,0x86B3,
+0x86B4,0x86B5,0x86B7,0x86B8,0x86B9,0x86BF,0x86C0,0x86C1,
+0x86C3,0x86C5,0x86D1,0x86D2,0x86D5,0x86D7,0x86DA,0x86DC,
+0x86E0,0x86E3,0x86E5,0x86E7,0x8688,0x86FA,0x86FC,0x86FD,
+0x8704,0x8705,0x8707,0x870B,0x870E,0x870F,0x8710,0x8713,
+0x8714,0x8719,0x871E,0x871F,0x8721,0x8723};
+
+/* page 51 0x5B21-0x5B7E */
+static uint16 tab_jisx0212_uni51[]={
+0x8728,0x872E,0x872F,0x8731,0x8732,0x8739,0x873A,0x873C,
+0x873D,0x873E,0x8740,0x8743,0x8745,0x874D,0x8758,0x875D,
+0x8761,0x8764,0x8765,0x876F,0x8771,0x8772,0x877B,0x8783,
+0x8784,0x8785,0x8786,0x8787,0x8788,0x8789,0x878B,0x878C,
+0x8790,0x8793,0x8795,0x8797,0x8798,0x8799,0x879E,0x87A0,
+0x87A3,0x87A7,0x87AC,0x87AD,0x87AE,0x87B1,0x87B5,0x87BE,
+0x87BF,0x87C1,0x87C8,0x87C9,0x87CA,0x87CE,0x87D5,0x87D6,
+0x87D9,0x87DA,0x87DC,0x87DF,0x87E2,0x87E3,0x87E4,0x87EA,
+0x87EB,0x87ED,0x87F1,0x87F3,0x87F8,0x87FA,0x87FF,0x8801,
+0x8803,0x8806,0x8809,0x880A,0x880B,0x8810,0x8819,0x8812,
+0x8813,0x8814,0x8818,0x881A,0x881B,0x881C,0x881E,0x881F,
+0x8828,0x882D,0x882E,0x8830,0x8832,0x8835};
+
+/* page 52 0x5C21-0x5C7E */
+static uint16 tab_jisx0212_uni52[]={
+0x883A,0x883C,0x8841,0x8843,0x8845,0x8848,0x8849,0x884A,
+0x884B,0x884E,0x8851,0x8855,0x8856,0x8858,0x885A,0x885C,
+0x885F,0x8860,0x8864,0x8869,0x8871,0x8879,0x887B,0x8880,
+0x8898,0x889A,0x889B,0x889C,0x889F,0x88A0,0x88A8,0x88AA,
+0x88BA,0x88BD,0x88BE,0x88C0,0x88CA,0x88CB,0x88CC,0x88CD,
+0x88CE,0x88D1,0x88D2,0x88D3,0x88DB,0x88DE,0x88E7,0x88EF,
+0x88F0,0x88F1,0x88F5,0x88F7,0x8901,0x8906,0x890D,0x890E,
+0x890F,0x8915,0x8916,0x8918,0x8919,0x891A,0x891C,0x8920,
+0x8926,0x8927,0x8928,0x8930,0x8931,0x8932,0x8935,0x8939,
+0x893A,0x893E,0x8940,0x8942,0x8945,0x8946,0x8949,0x894F,
+0x8952,0x8957,0x895A,0x895B,0x895C,0x8961,0x8962,0x8963,
+0x896B,0x896E,0x8970,0x8973,0x8975,0x897A};
+
+/* page 53 0x5D21-0x5D7E */
+static uint16 tab_jisx0212_uni53[]={
+0x897B,0x897C,0x897D,0x8989,0x898D,0x8990,0x8994,0x8995,
+0x899B,0x899C,0x899F,0x89A0,0x89A5,0x89B0,0x89B4,0x89B5,
+0x89B6,0x89B7,0x89BC,0x89D4,0x89D5,0x89D6,0x89D7,0x89D8,
+0x89E5,0x89E9,0x89EB,0x89ED,0x89F1,0x89F3,0x89F6,0x89F9,
+0x89FD,0x89FF,0x8A04,0x8A05,0x8A07,0x8A0F,0x8A11,0x8A12,
+0x8A14,0x8A15,0x8A1E,0x8A20,0x8A22,0x8A24,0x8A26,0x8A2B,
+0x8A2C,0x8A2F,0x8A35,0x8A37,0x8A3D,0x8A3E,0x8A40,0x8A43,
+0x8A45,0x8A47,0x8A49,0x8A4D,0x8A4E,0x8A53,0x8A56,0x8A57,
+0x8A58,0x8A5C,0x8A5D,0x8A61,0x8A65,0x8A67,0x8A75,0x8A76,
+0x8A77,0x8A79,0x8A7A,0x8A7B,0x8A7E,0x8A7F,0x8A80,0x8A83,
+0x8A86,0x8A8B,0x8A8F,0x8A90,0x8A92,0x8A96,0x8A97,0x8A99,
+0x8A9F,0x8AA7,0x8AA9,0x8AAE,0x8AAF,0x8AB3};
+
+/* page 54 0x5E21-0x5E7E */
+static uint16 tab_jisx0212_uni54[]={
+0x8AB6,0x8AB7,0x8ABB,0x8ABE,0x8AC3,0x8AC6,0x8AC8,0x8AC9,
+0x8ACA,0x8AD1,0x8AD3,0x8AD4,0x8AD5,0x8AD7,0x8ADD,0x8ADF,
+0x8AEC,0x8AF0,0x8AF4,0x8AF5,0x8AF6,0x8AFC,0x8AFF,0x8B05,
+0x8B06,0x8B0B,0x8B11,0x8B1C,0x8B1E,0x8B1F,0x8B0A,0x8B2D,
+0x8B30,0x8B37,0x8B3C,0x8B42,0x8B43,0x8B44,0x8B45,0x8B46,
+0x8B48,0x8B52,0x8B53,0x8B54,0x8B59,0x8B4D,0x8B5E,0x8B63,
+0x8B6D,0x8B76,0x8B78,0x8B79,0x8B7C,0x8B7E,0x8B81,0x8B84,
+0x8B85,0x8B8B,0x8B8D,0x8B8F,0x8B94,0x8B95,0x8B9C,0x8B9E,
+0x8B9F,0x8C38,0x8C39,0x8C3D,0x8C3E,0x8C45,0x8C47,0x8C49,
+0x8C4B,0x8C4F,0x8C51,0x8C53,0x8C54,0x8C57,0x8C58,0x8C5B,
+0x8C5D,0x8C59,0x8C63,0x8C64,0x8C66,0x8C68,0x8C69,0x8C6D,
+0x8C73,0x8C75,0x8C76,0x8C7B,0x8C7E,0x8C86};
+
+/* page 55 0x5F21-0x5F7E */
+static uint16 tab_jisx0212_uni55[]={
+0x8C87,0x8C8B,0x8C90,0x8C92,0x8C93,0x8C99,0x8C9B,0x8C9C,
+0x8CA4,0x8CB9,0x8CBA,0x8CC5,0x8CC6,0x8CC9,0x8CCB,0x8CCF,
+0x8CD6,0x8CD5,0x8CD9,0x8CDD,0x8CE1,0x8CE8,0x8CEC,0x8CEF,
+0x8CF0,0x8CF2,0x8CF5,0x8CF7,0x8CF8,0x8CFE,0x8CFF,0x8D01,
+0x8D03,0x8D09,0x8D12,0x8D17,0x8D1B,0x8D65,0x8D69,0x8D6C,
+0x8D6E,0x8D7F,0x8D82,0x8D84,0x8D88,0x8D8D,0x8D90,0x8D91,
+0x8D95,0x8D9E,0x8D9F,0x8DA0,0x8DA6,0x8DAB,0x8DAC,0x8DAF,
+0x8DB2,0x8DB5,0x8DB7,0x8DB9,0x8DBB,0x8DC0,0x8DC5,0x8DC6,
+0x8DC7,0x8DC8,0x8DCA,0x8DCE,0x8DD1,0x8DD4,0x8DD5,0x8DD7,
+0x8DD9,0x8DE4,0x8DE5,0x8DE7,0x8DEC,0x8DF0,0x8DBC,0x8DF1,
+0x8DF2,0x8DF4,0x8DFD,0x8E01,0x8E04,0x8E05,0x8E06,0x8E0B,
+0x8E11,0x8E14,0x8E16,0x8E20,0x8E21,0x8E22};
+
+/* page 56 0x6021-0x607E */
+static uint16 tab_jisx0212_uni56[]={
+0x8E23,0x8E26,0x8E27,0x8E31,0x8E33,0x8E36,0x8E37,0x8E38,
+0x8E39,0x8E3D,0x8E40,0x8E41,0x8E4B,0x8E4D,0x8E4E,0x8E4F,
+0x8E54,0x8E5B,0x8E5C,0x8E5D,0x8E5E,0x8E61,0x8E62,0x8E69,
+0x8E6C,0x8E6D,0x8E6F,0x8E70,0x8E71,0x8E79,0x8E7A,0x8E7B,
+0x8E82,0x8E83,0x8E89,0x8E90,0x8E92,0x8E95,0x8E9A,0x8E9B,
+0x8E9D,0x8E9E,0x8EA2,0x8EA7,0x8EA9,0x8EAD,0x8EAE,0x8EB3,
+0x8EB5,0x8EBA,0x8EBB,0x8EC0,0x8EC1,0x8EC3,0x8EC4,0x8EC7,
+0x8ECF,0x8ED1,0x8ED4,0x8EDC,0x8EE8,0x8EEE,0x8EF0,0x8EF1,
+0x8EF7,0x8EF9,0x8EFA,0x8EED,0x8F00,0x8F02,0x8F07,0x8F08,
+0x8F0F,0x8F10,0x8F16,0x8F17,0x8F18,0x8F1E,0x8F20,0x8F21,
+0x8F23,0x8F25,0x8F27,0x8F28,0x8F2C,0x8F2D,0x8F2E,0x8F34,
+0x8F35,0x8F36,0x8F37,0x8F3A,0x8F40,0x8F41};
+
+/* page 57 0x6121-0x617E */
+static uint16 tab_jisx0212_uni57[]={
+0x8F43,0x8F47,0x8F4F,0x8F51,0x8F52,0x8F53,0x8F54,0x8F55,
+0x8F58,0x8F5D,0x8F5E,0x8F65,0x8F9D,0x8FA0,0x8FA1,0x8FA4,
+0x8FA5,0x8FA6,0x8FB5,0x8FB6,0x8FB8,0x8FBE,0x8FC0,0x8FC1,
+0x8FC6,0x8FCA,0x8FCB,0x8FCD,0x8FD0,0x8FD2,0x8FD3,0x8FD5,
+0x8FE0,0x8FE3,0x8FE4,0x8FE8,0x8FEE,0x8FF1,0x8FF5,0x8FF6,
+0x8FFB,0x8FFE,0x9002,0x9004,0x9008,0x900C,0x9018,0x901B,
+0x9028,0x9029,0x902F,0x902A,0x902C,0x902D,0x9033,0x9034,
+0x9037,0x903F,0x9043,0x9044,0x904C,0x905B,0x905D,0x9062,
+0x9066,0x9067,0x906C,0x9070,0x9074,0x9079,0x9085,0x9088,
+0x908B,0x908C,0x908E,0x9090,0x9095,0x9097,0x9098,0x9099,
+0x909B,0x90A0,0x90A1,0x90A2,0x90A5,0x90B0,0x90B2,0x90B3,
+0x90B4,0x90B6,0x90BD,0x90CC,0x90BE,0x90C3};
+
+/* page 58 0x6221-0x627E */
+static uint16 tab_jisx0212_uni58[]={
+0x90C4,0x90C5,0x90C7,0x90C8,0x90D5,0x90D7,0x90D8,0x90D9,
+0x90DC,0x90DD,0x90DF,0x90E5,0x90D2,0x90F6,0x90EB,0x90EF,
+0x90F0,0x90F4,0x90FE,0x90FF,0x9100,0x9104,0x9105,0x9106,
+0x9108,0x910D,0x9110,0x9114,0x9116,0x9117,0x9118,0x911A,
+0x911C,0x911E,0x9120,0x9125,0x9122,0x9123,0x9127,0x9129,
+0x912E,0x912F,0x9131,0x9134,0x9136,0x9137,0x9139,0x913A,
+0x913C,0x913D,0x9143,0x9147,0x9148,0x914F,0x9153,0x9157,
+0x9159,0x915A,0x915B,0x9161,0x9164,0x9167,0x916D,0x9174,
+0x9179,0x917A,0x917B,0x9181,0x9183,0x9185,0x9186,0x918A,
+0x918E,0x9191,0x9193,0x9194,0x9195,0x9198,0x919E,0x91A1,
+0x91A6,0x91A8,0x91AC,0x91AD,0x91AE,0x91B0,0x91B1,0x91B2,
+0x91B3,0x91B6,0x91BB,0x91BC,0x91BD,0x91BF};
+
+/* page 59 0x6321-0x637E */
+static uint16 tab_jisx0212_uni59[]={
+0x91C2,0x91C3,0x91C5,0x91D3,0x91D4,0x91D7,0x91D9,0x91DA,
+0x91DE,0x91E4,0x91E5,0x91E9,0x91EA,0x91EC,0x91ED,0x91EE,
+0x91EF,0x91F0,0x91F1,0x91F7,0x91F9,0x91FB,0x91FD,0x9200,
+0x9201,0x9204,0x9205,0x9206,0x9207,0x9209,0x920A,0x920C,
+0x9210,0x9212,0x9213,0x9216,0x9218,0x921C,0x921D,0x9223,
+0x9224,0x9225,0x9226,0x9228,0x922E,0x922F,0x9230,0x9233,
+0x9235,0x9236,0x9238,0x9239,0x923A,0x923C,0x923E,0x9240,
+0x9242,0x9243,0x9246,0x9247,0x924A,0x924D,0x924E,0x924F,
+0x9251,0x9258,0x9259,0x925C,0x925D,0x9260,0x9261,0x9265,
+0x9267,0x9268,0x9269,0x926E,0x926F,0x9270,0x9275,0x9276,
+0x9277,0x9278,0x9279,0x927B,0x927C,0x927D,0x927F,0x9288,
+0x9289,0x928A,0x928D,0x928E,0x9292,0x9297};
+
+/* page 60 0x6421-0x647E */
+static uint16 tab_jisx0212_uni60[]={
+0x9299,0x929F,0x92A0,0x92A4,0x92A5,0x92A7,0x92A8,0x92AB,
+0x92AF,0x92B2,0x92B6,0x92B8,0x92BA,0x92BB,0x92BC,0x92BD,
+0x92BF,0x92C0,0x92C1,0x92C2,0x92C3,0x92C5,0x92C6,0x92C7,
+0x92C8,0x92CB,0x92CC,0x92CD,0x92CE,0x92D0,0x92D3,0x92D5,
+0x92D7,0x92D8,0x92D9,0x92DC,0x92DD,0x92DF,0x92E0,0x92E1,
+0x92E3,0x92E5,0x92E7,0x92E8,0x92EC,0x92EE,0x92F0,0x92F9,
+0x92FB,0x92FF,0x9300,0x9302,0x9308,0x930D,0x9311,0x9314,
+0x9315,0x931C,0x931D,0x931E,0x931F,0x9321,0x9324,0x9325,
+0x9327,0x9329,0x932A,0x9333,0x9334,0x9336,0x9337,0x9347,
+0x9348,0x9349,0x9350,0x9351,0x9352,0x9355,0x9357,0x9358,
+0x935A,0x935E,0x9364,0x9365,0x9367,0x9369,0x936A,0x936D,
+0x936F,0x9370,0x9371,0x9373,0x9374,0x9376};
+
+/* page 61 0x6521-0x657E */
+static uint16 tab_jisx0212_uni61[]={
+0x937A,0x937D,0x937F,0x9380,0x9381,0x9382,0x9388,0x938A,
+0x938B,0x938D,0x938F,0x9392,0x9395,0x9398,0x939B,0x939E,
+0x93A1,0x93A3,0x93A4,0x93A6,0x93A8,0x93AB,0x93B4,0x93B5,
+0x93B6,0x93BA,0x93A9,0x93C1,0x93C4,0x93C5,0x93C6,0x93C7,
+0x93C9,0x93CA,0x93CB,0x93CC,0x93CD,0x93D3,0x93D9,0x93DC,
+0x93DE,0x93DF,0x93E2,0x93E6,0x93E7,0x93F9,0x93F7,0x93F8,
+0x93FA,0x93FB,0x93FD,0x9401,0x9402,0x9404,0x9408,0x9409,
+0x940D,0x940E,0x940F,0x9415,0x9416,0x9417,0x941F,0x942E,
+0x942F,0x9431,0x9432,0x9433,0x9434,0x943B,0x943F,0x943D,
+0x9443,0x9445,0x9448,0x944A,0x944C,0x9455,0x9459,0x945C,
+0x945F,0x9461,0x9463,0x9468,0x946B,0x946D,0x946E,0x946F,
+0x9471,0x9472,0x9484,0x9483,0x9578,0x9579};
+
+/* page 62 0x6621-0x667E */
+static uint16 tab_jisx0212_uni62[]={
+0x957E,0x9584,0x9588,0x958C,0x958D,0x958E,0x959D,0x959E,
+0x959F,0x95A1,0x95A6,0x95A9,0x95AB,0x95AC,0x95B4,0x95B6,
+0x95BA,0x95BD,0x95BF,0x95C6,0x95C8,0x95C9,0x95CB,0x95D0,
+0x95D1,0x95D2,0x95D3,0x95D9,0x95DA,0x95DD,0x95DE,0x95DF,
+0x95E0,0x95E4,0x95E6,0x961D,0x961E,0x9622,0x9624,0x9625,
+0x9626,0x962C,0x9631,0x9633,0x9637,0x9638,0x9639,0x963A,
+0x963C,0x963D,0x9641,0x9652,0x9654,0x9656,0x9657,0x9658,
+0x9661,0x966E,0x9674,0x967B,0x967C,0x967E,0x967F,0x9681,
+0x9682,0x9683,0x9684,0x9689,0x9691,0x9696,0x969A,0x969D,
+0x969F,0x96A4,0x96A5,0x96A6,0x96A9,0x96AE,0x96AF,0x96B3,
+0x96BA,0x96CA,0x96D2,0x5DB2,0x96D8,0x96DA,0x96DD,0x96DE,
+0x96DF,0x96E9,0x96EF,0x96F1,0x96FA,0x9702};
+
+/* page 63 0x6721-0x677E */
+static uint16 tab_jisx0212_uni63[]={
+0x9703,0x9705,0x9709,0x971A,0x971B,0x971D,0x9721,0x9722,
+0x9723,0x9728,0x9731,0x9733,0x9741,0x9743,0x974A,0x974E,
+0x974F,0x9755,0x9757,0x9758,0x975A,0x975B,0x9763,0x9767,
+0x976A,0x976E,0x9773,0x9776,0x9777,0x9778,0x977B,0x977D,
+0x977F,0x9780,0x9789,0x9795,0x9796,0x9797,0x9799,0x979A,
+0x979E,0x979F,0x97A2,0x97AC,0x97AE,0x97B1,0x97B2,0x97B5,
+0x97B6,0x97B8,0x97B9,0x97BA,0x97BC,0x97BE,0x97BF,0x97C1,
+0x97C4,0x97C5,0x97C7,0x97C9,0x97CA,0x97CC,0x97CD,0x97CE,
+0x97D0,0x97D1,0x97D4,0x97D7,0x97D8,0x97D9,0x97DD,0x97DE,
+0x97E0,0x97DB,0x97E1,0x97E4,0x97EF,0x97F1,0x97F4,0x97F7,
+0x97F8,0x97FA,0x9807,0x980A,0x9819,0x980D,0x980E,0x9814,
+0x9816,0x981C,0x981E,0x9820,0x9823,0x9826};
+
+/* page 64 0x6821-0x687E */
+static uint16 tab_jisx0212_uni64[]={
+0x982B,0x982E,0x982F,0x9830,0x9832,0x9833,0x9835,0x9825,
+0x983E,0x9844,0x9847,0x984A,0x9851,0x9852,0x9853,0x9856,
+0x9857,0x9859,0x985A,0x9862,0x9863,0x9865,0x9866,0x986A,
+0x986C,0x98AB,0x98AD,0x98AE,0x98B0,0x98B4,0x98B7,0x98B8,
+0x98BA,0x98BB,0x98BF,0x98C2,0x98C5,0x98C8,0x98CC,0x98E1,
+0x98E3,0x98E5,0x98E6,0x98E7,0x98EA,0x98F3,0x98F6,0x9902,
+0x9907,0x9908,0x9911,0x9915,0x9916,0x9917,0x991A,0x991B,
+0x991C,0x991F,0x9922,0x9926,0x9927,0x992B,0x9931,0x9932,
+0x9933,0x9934,0x9935,0x9939,0x993A,0x993B,0x993C,0x9940,
+0x9941,0x9946,0x9947,0x9948,0x994D,0x994E,0x9954,0x9958,
+0x9959,0x995B,0x995C,0x995E,0x995F,0x9960,0x999B,0x999D,
+0x999F,0x99A6,0x99B0,0x99B1,0x99B2,0x99B5};
+
+/* page 65 0x6921-0x697E */
+static uint16 tab_jisx0212_uni65[]={
+0x99B9,0x99BA,0x99BD,0x99BF,0x99C3,0x99C9,0x99D3,0x99D4,
+0x99D9,0x99DA,0x99DC,0x99DE,0x99E7,0x99EA,0x99EB,0x99EC,
+0x99F0,0x99F4,0x99F5,0x99F9,0x99FD,0x99FE,0x9A02,0x9A03,
+0x9A04,0x9A0B,0x9A0C,0x9A10,0x9A11,0x9A16,0x9A1E,0x9A20,
+0x9A22,0x9A23,0x9A24,0x9A27,0x9A2D,0x9A2E,0x9A33,0x9A35,
+0x9A36,0x9A38,0x9A47,0x9A41,0x9A44,0x9A4A,0x9A4B,0x9A4C,
+0x9A4E,0x9A51,0x9A54,0x9A56,0x9A5D,0x9AAA,0x9AAC,0x9AAE,
+0x9AAF,0x9AB2,0x9AB4,0x9AB5,0x9AB6,0x9AB9,0x9ABB,0x9ABE,
+0x9ABF,0x9AC1,0x9AC3,0x9AC6,0x9AC8,0x9ACE,0x9AD0,0x9AD2,
+0x9AD5,0x9AD6,0x9AD7,0x9ADB,0x9ADC,0x9AE0,0x9AE4,0x9AE5,
+0x9AE7,0x9AE9,0x9AEC,0x9AF2,0x9AF3,0x9AF5,0x9AF9,0x9AFA,
+0x9AFD,0x9AFF,0x9B00,0x9B01,0x9B02,0x9B03};
+
+/* page 66 0x6A21-0x6A7E */
+static uint16 tab_jisx0212_uni66[]={
+0x9B04,0x9B05,0x9B08,0x9B09,0x9B0B,0x9B0C,0x9B0D,0x9B0E,
+0x9B10,0x9B12,0x9B16,0x9B19,0x9B1B,0x9B1C,0x9B20,0x9B26,
+0x9B2B,0x9B2D,0x9B33,0x9B34,0x9B35,0x9B37,0x9B39,0x9B3A,
+0x9B3D,0x9B48,0x9B4B,0x9B4C,0x9B55,0x9B56,0x9B57,0x9B5B,
+0x9B5E,0x9B61,0x9B63,0x9B65,0x9B66,0x9B68,0x9B6A,0x9B6B,
+0x9B6C,0x9B6D,0x9B6E,0x9B73,0x9B75,0x9B77,0x9B78,0x9B79,
+0x9B7F,0x9B80,0x9B84,0x9B85,0x9B86,0x9B87,0x9B89,0x9B8A,
+0x9B8B,0x9B8D,0x9B8F,0x9B90,0x9B94,0x9B9A,0x9B9D,0x9B9E,
+0x9BA6,0x9BA7,0x9BA9,0x9BAC,0x9BB0,0x9BB1,0x9BB2,0x9BB7,
+0x9BB8,0x9BBB,0x9BBC,0x9BBE,0x9BBF,0x9BC1,0x9BC7,0x9BC8,
+0x9BCE,0x9BD0,0x9BD7,0x9BD8,0x9BDD,0x9BDF,0x9BE5,0x9BE7,
+0x9BEA,0x9BEB,0x9BEF,0x9BF3,0x9BF7,0x9BF8};
+
+/* page 67 0x6B21-0x6B7E */
+static uint16 tab_jisx0212_uni67[]={
+0x9BF9,0x9BFA,0x9BFD,0x9BFF,0x9C00,0x9C02,0x9C0B,0x9C0F,
+0x9C11,0x9C16,0x9C18,0x9C19,0x9C1A,0x9C1C,0x9C1E,0x9C22,
+0x9C23,0x9C26,0x9C27,0x9C28,0x9C29,0x9C2A,0x9C31,0x9C35,
+0x9C36,0x9C37,0x9C3D,0x9C41,0x9C43,0x9C44,0x9C45,0x9C49,
+0x9C4A,0x9C4E,0x9C4F,0x9C50,0x9C53,0x9C54,0x9C56,0x9C58,
+0x9C5B,0x9C5D,0x9C5E,0x9C5F,0x9C63,0x9C69,0x9C6A,0x9C5C,
+0x9C6B,0x9C68,0x9C6E,0x9C70,0x9C72,0x9C75,0x9C77,0x9C7B,
+0x9CE6,0x9CF2,0x9CF7,0x9CF9,0x9D0B,0x9D02,0x9D11,0x9D17,
+0x9D18,0x9D1C,0x9D1D,0x9D1E,0x9D2F,0x9D30,0x9D32,0x9D33,
+0x9D34,0x9D3A,0x9D3C,0x9D45,0x9D3D,0x9D42,0x9D43,0x9D47,
+0x9D4A,0x9D53,0x9D54,0x9D5F,0x9D63,0x9D62,0x9D65,0x9D69,
+0x9D6A,0x9D6B,0x9D70,0x9D76,0x9D77,0x9D7B};
+
+/* page 68 0x6C21-0x6C7E */
+static uint16 tab_jisx0212_uni68[]={
+0x9D7C,0x9D7E,0x9D83,0x9D84,0x9D86,0x9D8A,0x9D8D,0x9D8E,
+0x9D92,0x9D93,0x9D95,0x9D96,0x9D97,0x9D98,0x9DA1,0x9DAA,
+0x9DAC,0x9DAE,0x9DB1,0x9DB5,0x9DB9,0x9DBC,0x9DBF,0x9DC3,
+0x9DC7,0x9DC9,0x9DCA,0x9DD4,0x9DD5,0x9DD6,0x9DD7,0x9DDA,
+0x9DDE,0x9DDF,0x9DE0,0x9DE5,0x9DE7,0x9DE9,0x9DEB,0x9DEE,
+0x9DF0,0x9DF3,0x9DF4,0x9DFE,0x9E0A,0x9E02,0x9E07,0x9E0E,
+0x9E10,0x9E11,0x9E12,0x9E15,0x9E16,0x9E19,0x9E1C,0x9E1D,
+0x9E7A,0x9E7B,0x9E7C,0x9E80,0x9E82,0x9E83,0x9E84,0x9E85,
+0x9E87,0x9E8E,0x9E8F,0x9E96,0x9E98,0x9E9B,0x9E9E,0x9EA4,
+0x9EA8,0x9EAC,0x9EAE,0x9EAF,0x9EB0,0x9EB3,0x9EB4,0x9EB5,
+0x9EC6,0x9EC8,0x9ECB,0x9ED5,0x9EDF,0x9EE4,0x9EE7,0x9EEC,
+0x9EED,0x9EEE,0x9EF0,0x9EF1,0x9EF2,0x9EF5};
+
+/* page 69 0x6D21-0x6D63 */
+static uint16 tab_jisx0212_uni69[]={
+0x9EF8,0x9EFF,0x9F02,0x9F03,0x9F09,0x9F0F,0x9F10,0x9F11,
+0x9F12,0x9F14,0x9F16,0x9F17,0x9F19,0x9F1A,0x9F1B,0x9F1F,
+0x9F22,0x9F26,0x9F2A,0x9F2B,0x9F2F,0x9F31,0x9F32,0x9F34,
+0x9F37,0x9F39,0x9F3A,0x9F3C,0x9F3D,0x9F3F,0x9F41,0x9F43,
+0x9F44,0x9F45,0x9F46,0x9F47,0x9F53,0x9F55,0x9F56,0x9F57,
+0x9F58,0x9F5A,0x9F5D,0x9F5E,0x9F68,0x9F69,0x9F6D,0x9F6E,
+0x9F6F,0x9F70,0x9F71,0x9F73,0x9F75,0x9F7A,0x9F7D,0x9F8F,
+0x9F90,0x9F91,0x9F92,0x9F94,0x9F96,0x9F97,0x9F9E,0x9FA1,
+0x9FA2,0x9FA3,0x9FA5};
+
+/* page 70 0x7371-0x737E IBM Kanji and Nonkanji */
+static uint16 tab_jisx0212_uni70[]={
+ 0, 0,0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,
+0x2176,0x2177,0x2178,0x2179,0x2160,0x2161};
+
+/* page 71 0x7421-0x747E IBM Kanji and Nonkanji*/
+static uint16 tab_jisx0212_uni71[]={
+0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,
+0xFF07,0xFF02,0x3231,0x2116,0x2121,0x70BB,0x4EFC,0x50F4,
+0x51EC,0x5307,0x5324,0xFA0E,0x548A,0x5759,0xFA0F,0xFA10,
+0x589E,0x5BEC,0x5CF5,0x5D53,0xFA11,0x5FB7,0x6085,0x6120,
+0x654E,0x663B,0x6665,0xFA12,0xF929,0x6801,0xFA13,0xFA14,
+0x6A6B,0x6AE2,0x6DF8,0x6DF2,0x7028,0xFA15,0xFA16,0x7501,
+0x7682,0x769E,0xFA17,0x7930,0xFA18,0xFA19,0xFA1A,0xFA1B,
+0x7AE7,0xFA1C,0xFA1D,0x7DA0,0x7DD6,0xFA1E,0x8362,0xFA1F,
+0x85B0,0xFA20,0xFA21,0x8807,0xFA22,0x8B7F,0x8CF4,0x8D76,
+0xFA23,0xFA24,0xFA25,0x90DE,0xFA26,0x9115,0xFA27,0xFA28,
+0x9592,0xF9DC,0xFA29,0x973B,0x974D,0x9751,0xFA2A,0xFA2B,
+0xFA2C,0x999E,0x9AD9,0x9B72,0xFA2D,0x9ED1};
+
+static int
+my_jisx0212_uni_onechar(int code){
+ if ((code>=0x222F)&&(code<=0x2244))
+ return(tab_jisx0212_uni0[code-0x222F]);
+ if ((code>=0x226B)&&(code<=0x2271))
+ return(tab_jisx0212_uni1[code-0x226B]);
+ if ((code>=0x2661)&&(code<=0x267C))
+ return(tab_jisx0212_uni2[code-0x2661]);
+ if ((code>=0x2742)&&(code<=0x274E))
+ return(tab_jisx0212_uni3[code-0x2742]);
+ if ((code>=0x2772)&&(code<=0x277E))
+ return(tab_jisx0212_uni4[code-0x2772]);
+ if ((code>=0x2921)&&(code<=0x2950))
+ return(tab_jisx0212_uni5[code-0x2921]);
+ if ((code>=0x2A21)&&(code<=0x2A77))
+ return(tab_jisx0212_uni6[code-0x2A21]);
+ if ((code>=0x2B21)&&(code<=0x2B77))
+ return(tab_jisx0212_uni7[code-0x2B21]);
+ if ((code>=0x3021)&&(code<=0x307E))
+ return(tab_jisx0212_uni8[code-0x3021]);
+ if ((code>=0x3121)&&(code<=0x317E))
+ return(tab_jisx0212_uni9[code-0x3121]);
+ if ((code>=0x3221)&&(code<=0x327E))
+ return(tab_jisx0212_uni10[code-0x3221]);
+ if ((code>=0x3321)&&(code<=0x337E))
+ return(tab_jisx0212_uni11[code-0x3321]);
+ if ((code>=0x3421)&&(code<=0x347E))
+ return(tab_jisx0212_uni12[code-0x3421]);
+ if ((code>=0x3521)&&(code<=0x357E))
+ return(tab_jisx0212_uni13[code-0x3521]);
+ if ((code>=0x3621)&&(code<=0x367E))
+ return(tab_jisx0212_uni14[code-0x3621]);
+ if ((code>=0x3721)&&(code<=0x377E))
+ return(tab_jisx0212_uni15[code-0x3721]);
+ if ((code>=0x3821)&&(code<=0x387E))
+ return(tab_jisx0212_uni16[code-0x3821]);
+ if ((code>=0x3921)&&(code<=0x397E))
+ return(tab_jisx0212_uni17[code-0x3921]);
+ if ((code>=0x3A21)&&(code<=0x3A7E))
+ return(tab_jisx0212_uni18[code-0x3A21]);
+ if ((code>=0x3B21)&&(code<=0x3B7E))
+ return(tab_jisx0212_uni19[code-0x3B21]);
+ if ((code>=0x3C21)&&(code<=0x3C7E))
+ return(tab_jisx0212_uni20[code-0x3C21]);
+ if ((code>=0x3D21)&&(code<=0x3D7E))
+ return(tab_jisx0212_uni21[code-0x3D21]);
+ if ((code>=0x3E21)&&(code<=0x3E7E))
+ return(tab_jisx0212_uni22[code-0x3E21]);
+ if ((code>=0x3F21)&&(code<=0x3F7E))
+ return(tab_jisx0212_uni23[code-0x3F21]);
+ if ((code>=0x4021)&&(code<=0x407E))
+ return(tab_jisx0212_uni24[code-0x4021]);
+ if ((code>=0x4121)&&(code<=0x417E))
+ return(tab_jisx0212_uni25[code-0x4121]);
+ if ((code>=0x4221)&&(code<=0x427E))
+ return(tab_jisx0212_uni26[code-0x4221]);
+ if ((code>=0x4321)&&(code<=0x437E))
+ return(tab_jisx0212_uni27[code-0x4321]);
+ if ((code>=0x4421)&&(code<=0x447E))
+ return(tab_jisx0212_uni28[code-0x4421]);
+ if ((code>=0x4521)&&(code<=0x457E))
+ return(tab_jisx0212_uni29[code-0x4521]);
+ if ((code>=0x4621)&&(code<=0x467E))
+ return(tab_jisx0212_uni30[code-0x4621]);
+ if ((code>=0x4721)&&(code<=0x477E))
+ return(tab_jisx0212_uni31[code-0x4721]);
+ if ((code>=0x4821)&&(code<=0x487E))
+ return(tab_jisx0212_uni32[code-0x4821]);
+ if ((code>=0x4921)&&(code<=0x497E))
+ return(tab_jisx0212_uni33[code-0x4921]);
+ if ((code>=0x4A21)&&(code<=0x4A7E))
+ return(tab_jisx0212_uni34[code-0x4A21]);
+ if ((code>=0x4B21)&&(code<=0x4B7E))
+ return(tab_jisx0212_uni35[code-0x4B21]);
+ if ((code>=0x4C21)&&(code<=0x4C7E))
+ return(tab_jisx0212_uni36[code-0x4C21]);
+ if ((code>=0x4D21)&&(code<=0x4D7E))
+ return(tab_jisx0212_uni37[code-0x4D21]);
+ if ((code>=0x4E21)&&(code<=0x4E7E))
+ return(tab_jisx0212_uni38[code-0x4E21]);
+ if ((code>=0x4F21)&&(code<=0x4F7E))
+ return(tab_jisx0212_uni39[code-0x4F21]);
+ if ((code>=0x5021)&&(code<=0x507E))
+ return(tab_jisx0212_uni40[code-0x5021]);
+ if ((code>=0x5121)&&(code<=0x517E))
+ return(tab_jisx0212_uni41[code-0x5121]);
+ if ((code>=0x5221)&&(code<=0x527E))
+ return(tab_jisx0212_uni42[code-0x5221]);
+ if ((code>=0x5321)&&(code<=0x537E))
+ return(tab_jisx0212_uni43[code-0x5321]);
+ if ((code>=0x5421)&&(code<=0x547E))
+ return(tab_jisx0212_uni44[code-0x5421]);
+ if ((code>=0x5521)&&(code<=0x557E))
+ return(tab_jisx0212_uni45[code-0x5521]);
+ if ((code>=0x5621)&&(code<=0x567E))
+ return(tab_jisx0212_uni46[code-0x5621]);
+ if ((code>=0x5721)&&(code<=0x577E))
+ return(tab_jisx0212_uni47[code-0x5721]);
+ if ((code>=0x5821)&&(code<=0x587E))
+ return(tab_jisx0212_uni48[code-0x5821]);
+ if ((code>=0x5921)&&(code<=0x597E))
+ return(tab_jisx0212_uni49[code-0x5921]);
+ if ((code>=0x5A21)&&(code<=0x5A7E))
+ return(tab_jisx0212_uni50[code-0x5A21]);
+ if ((code>=0x5B21)&&(code<=0x5B7E))
+ return(tab_jisx0212_uni51[code-0x5B21]);
+ if ((code>=0x5C21)&&(code<=0x5C7E))
+ return(tab_jisx0212_uni52[code-0x5C21]);
+ if ((code>=0x5D21)&&(code<=0x5D7E))
+ return(tab_jisx0212_uni53[code-0x5D21]);
+ if ((code>=0x5E21)&&(code<=0x5E7E))
+ return(tab_jisx0212_uni54[code-0x5E21]);
+ if ((code>=0x5F21)&&(code<=0x5F7E))
+ return(tab_jisx0212_uni55[code-0x5F21]);
+ if ((code>=0x6021)&&(code<=0x607E))
+ return(tab_jisx0212_uni56[code-0x6021]);
+ if ((code>=0x6121)&&(code<=0x617E))
+ return(tab_jisx0212_uni57[code-0x6121]);
+ if ((code>=0x6221)&&(code<=0x627E))
+ return(tab_jisx0212_uni58[code-0x6221]);
+ if ((code>=0x6321)&&(code<=0x637E))
+ return(tab_jisx0212_uni59[code-0x6321]);
+ if ((code>=0x6421)&&(code<=0x647E))
+ return(tab_jisx0212_uni60[code-0x6421]);
+ if ((code>=0x6521)&&(code<=0x657E))
+ return(tab_jisx0212_uni61[code-0x6521]);
+ if ((code>=0x6621)&&(code<=0x667E))
+ return(tab_jisx0212_uni62[code-0x6621]);
+ if ((code>=0x6721)&&(code<=0x677E))
+ return(tab_jisx0212_uni63[code-0x6721]);
+ if ((code>=0x6821)&&(code<=0x687E))
+ return(tab_jisx0212_uni64[code-0x6821]);
+ if ((code>=0x6921)&&(code<=0x697E))
+ return(tab_jisx0212_uni65[code-0x6921]);
+ if ((code>=0x6A21)&&(code<=0x6A7E))
+ return(tab_jisx0212_uni66[code-0x6A21]);
+ if ((code>=0x6B21)&&(code<=0x6B7E))
+ return(tab_jisx0212_uni67[code-0x6B21]);
+ if ((code>=0x6C21)&&(code<=0x6C7E))
+ return(tab_jisx0212_uni68[code-0x6C21]);
+ if ((code>=0x6D21)&&(code<=0x6D63))
+ return(tab_jisx0212_uni69[code-0x6D21]);
+ if ((code>=0x7371)&&(code<=0x737E))
+ return(tab_jisx0212_uni70[code-0x7371]);
+ if ((code>=0x7421)&&(code<=0x747E))
+ return(tab_jisx0212_uni71[code-0x7421]);
+ return(0);
+}
+
+/*
+ EUC-JP encoding subcomponents:
+ [x00-x7F] # ASCII/JIS-Roman (one-byte/character)
+ [x8E][xA0-xDF] # half-width katakana (two bytes/char)
+ [x8F][xA1-xFE][xA1-xFE] # JIS X 0212-1990 (three bytes/char)
+ [xA1-xFE][xA1-xFE] # JIS X 0208:1997 (two bytes/char)
+*/
+
+static
+uint my_well_formed_len_eucjpms(CHARSET_INFO *cs __attribute__((unused)),
+ const char *beg, const char *end, uint pos, int *error)
+{
+ const uchar *b= (uchar *) beg;
+ *error=0;
+
+ for ( ; pos && b < (uchar*) end; pos--, b++)
+ {
+ char *chbeg;
+ uint ch= *b;
+
+ if (ch <= 0x7F) /* one byte */
+ continue;
+
+ chbeg= (char *) b++;
+ if (b >= (uchar *) end) /* need more bytes */
+ return chbeg - beg; /* unexpected EOL */
+
+ if (ch == 0x8E) /* [x8E][xA0-xDF] */
+ {
+ if (*b >= 0xA0 && *b <= 0xDF)
+ continue;
+ *error=1;
+ return chbeg - beg; /* invalid sequence */
+ }
+
+ if (ch == 0x8F) /* [x8F][xA1-xFE][xA1-xFE] */
+ {
+ ch= *b++;
+ if (b >= (uchar*) end)
+ {
+ *error= 1;
+ return chbeg - beg; /* unexpected EOL */
+ }
+ }
+
+ if (ch >= 0xA1 && ch <= 0xFE &&
+ *b >= 0xA1 && *b <= 0xFE) /* [xA1-xFE][xA1-xFE] */
+ continue;
+ *error=1;
+ return chbeg - beg; /* invalid sequence */
+ }
+ return b - (uchar *) beg;
+}
+
+
+static
+uint my_numcells_eucjp(CHARSET_INFO *cs __attribute__((unused)),
+ const char *str, const char *strend)
+{
+ uint clen= 0;
+ const unsigned char *b= (const unsigned char *) str;
+ const unsigned char *e= (const unsigned char *) strend;
+
+ for (clen= 0; b < e; )
+ {
+ if (*b == 0x8E)
+ {
+ clen++;
+ b+= 2;
+ }
+ else if (*b == 0x8F)
+ {
+ clen+= 2;
+ b+= 3;
+ }
+ else if (*b & 0x80)
+ {
+ clen+= 2;
+ b+= 2;
+ }
+ else
+ {
+ clen++;
+ b++;
+ }
+ }
+ return clen;
+}
+
+static int
+my_mb_wc_euc_jp(CHARSET_INFO *cs,my_wc_t *pwc, const uchar *s, const uchar *e)
+{
+ int c1,c2,c3;
+
+ if (s >= e)
+ return MY_CS_TOOFEW(0);
+
+ c1=s[0];
+
+ /* Ascii code set */
+ if (c1<=0x7F)
+ {
+ *pwc=c1;
+ return 1;
+ }
+
+ if (s+2>e)
+ return MY_CS_TOOFEW(0);
+
+ c2=s[1];
+
+
+ /* JIS X 0208 code set */
+ if (c1>=0xA1 && c1<=0xFE)
+ {
+ if (c2 < 0xA1 || c2 >0xFE)
+ return MY_CS_ILSEQ;
+
+ if (c1 < 0xF5)
+ {
+ pwc[0]=my_jisx0208_uni_onechar( ((c1-0x80) << 8) + (c2-0x80));
+ if (!pwc[0])
+ return MY_CS_ILSEQ;
+ }
+ else
+ {
+ /* User defined range */
+ pwc[0]=0xE000 + 94*(c1-0xF5) +(c2-0xA1);
+ }
+ return 2;
+ }
+
+ /* JIS X 0201 code set (Half Width Tatakana) */
+ if (c1==0x8E)
+ {
+ int ret;
+
+ if (c2<0xA1 || c2>0xDF)
+ return MY_CS_ILSEQ;
+
+ ret = my_mb_wc_jisx0201(cs,pwc,s+1,e);
+ if (ret!=1)
+ return ret;
+ return 2;
+ }
+
+ /* JIS X 0212 code set */
+ if (c1==0x8F)
+ {
+ if (c2<0xA1 || c2>=0xFF)
+ return MY_CS_ILSEQ;
+
+ if (s+3>e)
+ return MY_CS_TOOFEW(0);
+
+ c3=s[2];
+ if (c3 < 0xA1 || c3>=0xFF)
+ return MY_CS_ILSEQ;
+
+ if (c2<0xF5)
+ {
+ pwc[0]=my_jisx0212_uni_onechar((c2-0x80)*256 + (c3-0x80));
+ if (!pwc)
+ return MY_CS_ILSEQ;
+ }
+ else
+ {
+ /* User defined range */
+ pwc[0]= 0xE3AC + 94*(c2-0xF5) + (c3-0xA1);
+ }
+ return 3;
+ }
+
+ return MY_CS_ILSEQ;
+}
+
+static int
+my_wc_mb_euc_jp(CHARSET_INFO *c,my_wc_t wc, unsigned char *s, unsigned char *e)
+{
+ unsigned char c1;
+ int jp;
+
+ if (s >= e)
+ return MY_CS_TOOSMALL;
+
+ if ((int) wc < 0x80)
+ {
+ *s= (uchar) wc;
+ return 1;
+ }
+
+ if ((jp=my_uni_jisx0208_onechar(wc)))
+ {
+ if (s+2>e)
+ return MY_CS_TOOSMALL;
+
+ jp+=0x8080;
+ s[0]=jp>>8;
+ s[1]=jp&0xFF;
+ return 2;
+ }
+
+ /* Half width Katakana */
+ if (my_wc_mb_jisx0201(c,wc,s,e) == 1)
+ {
+ if (s+2>e)
+ return MY_CS_TOOSMALL;
+ s[1]= s[0];
+ s[0]= 0x8E;
+ return 2;
+ }
+
+
+ if ((jp=my_uni_jisx0212_onechar(wc)))
+ {
+ if (s+3>e)
+ return MY_CS_TOOSMALL;
+
+ jp+=0x8080;
+ s[0]=0x8F;
+ s[1]=jp>>8;
+ s[2]=jp&0xFF;
+ return 3;
+ }
+
+
+ /* User defined range */
+ if (wc>=0xE000 && wc<0xE3AC)
+ {
+ if (s+2>e)
+ return MY_CS_TOOSMALL;
+
+ c1=((unsigned)(wc-0xE000)/94)+0xF5;
+ s[0]=c1;
+ c1=((unsigned)(wc-0xE000)%94)+0xa1;
+ s[1]=c1;
+ return 2;
+ }
+
+
+ /* User defined range */
+ if (wc>=0xE3AC && wc<0xE758)
+ {
+ if (s+3>e)
+ return MY_CS_TOOSMALL;
+
+ s[0]=0x8F;
+ c1=((unsigned)(wc-0xE3AC)/94)+0xF5;
+ s[1]=c1;
+ c1=((unsigned)(wc-0xE3AC)%94)+0xa1;
+ s[2]=c1;
+ return 3;
+ }
+
+ return MY_CS_ILUNI;
+}
+
+
+static MY_COLLATION_HANDLER my_collation_ci_handler =
+{
+ NULL, /* init */
+ my_strnncoll_simple,/* strnncoll */
+ my_strnncollsp_simple,
+ my_strnxfrm_simple, /* strnxfrm */
+ my_strnxfrmlen_simple,
+ my_like_range_simple,/* like_range */
+ my_wildcmp_mb, /* wildcmp */
+ my_strcasecmp_mb,
+ my_instr_mb,
+ my_hash_sort_simple,
+};
+
+static MY_CHARSET_HANDLER my_charset_handler=
+{
+ NULL, /* init */
+ ismbchar_eucjpms,
+ mbcharlen_eucjpms,
+ my_numchars_mb,
+ my_charpos_mb,
+ my_well_formed_len_eucjpms,
+ my_lengthsp_8bit,
+ my_numcells_eucjp,
+ my_mb_wc_euc_jp, /* mb_wc */
+ my_wc_mb_euc_jp, /* wc_mb */
+ my_caseup_str_mb,
+ my_casedn_str_mb,
+ my_caseup_mb,
+ my_casedn_mb,
+ my_snprintf_8bit,
+ my_long10_to_str_8bit,
+ my_longlong10_to_str_8bit,
+ my_fill_8bit,
+ my_strntol_8bit,
+ my_strntoul_8bit,
+ my_strntoll_8bit,
+ my_strntoull_8bit,
+ my_strntod_8bit,
+ my_strtoll10_8bit,
+ my_scan_8bit
+};
+
+
+
+CHARSET_INFO my_charset_eucjpms_japanese_ci=
+{
+ 97,0,0, /* number */
+ MY_CS_COMPILED|MY_CS_PRIMARY, /* state */
+ "eucjpms", /* cs name */
+ "eucjpms_japanese_ci", /* name */
+ "", /* comment */
+ NULL, /* tailoring */
+ ctype_eucjpms,
+ to_lower_eucjpms,
+ to_upper_eucjpms,
+ sort_order_eucjpms,
+ NULL, /* sort_order_big*/
+ NULL, /* contractions */
+ NULL, /* tab_to_uni */
+ NULL, /* tab_from_uni */
+ NULL, /* state_map */
+ NULL, /* ident_map */
+ 1, /* strxfrm_multiply */
+ 1, /* mbminlen */
+ 3, /* mbmaxlen */
+ 0, /* min_sort_char */
+ 255, /* max_sort_char */
+ &my_charset_handler,
+ &my_collation_ci_handler
+};
+
+
+CHARSET_INFO my_charset_eucjpms_bin=
+{
+ 98,0,0, /* number */
+ MY_CS_COMPILED|MY_CS_BINSORT, /* state */
+ "eucjpms", /* cs name */
+ "eucjpms_bin", /* name */
+ "", /* comment */
+ NULL, /* tailoring */
+ ctype_eucjpms,
+ to_lower_eucjpms,
+ to_upper_eucjpms,
+ NULL, /* sort_order */
+ NULL, /* contractions */
+ NULL, /* sort_order_big*/
+ NULL, /* tab_to_uni */
+ NULL, /* tab_from_uni */
+ NULL, /* state_map */
+ NULL, /* ident_map */
+ 1, /* strxfrm_multiply */
+ 1, /* mbminlen */
+ 3, /* mbmaxlen */
+ 0, /* min_sort_char */
+ 255, /* max_sort_char */
+ &my_charset_handler,
+ &my_collation_mb_bin_handler
+};
+
+
+#endif
diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c
index f17cc94723f..73e4132dd7f 100644
--- a/strings/ctype-gb2312.c
+++ b/strings/ctype-gb2312.c
@@ -5692,6 +5692,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler =
my_strnncoll_simple, /* strnncoll */
my_strnncollsp_simple,
my_strnxfrm_simple, /* strnxfrm */
+ my_strnxfrmlen_simple,
my_like_range_simple, /* like_range */
my_wildcmp_mb, /* wildcmp */
my_strcasecmp_mb, /* instr */
diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c
index 9daa9f90f3c..d4f9627ecf7 100644
--- a/strings/ctype-gbk.c
+++ b/strings/ctype-gbk.c
@@ -2625,14 +2625,22 @@ int my_strnncoll_gbk(CHARSET_INFO *cs __attribute__((unused)),
static int my_strnncollsp_gbk(CHARSET_INFO * cs __attribute__((unused)),
const uchar *a, uint a_length,
- const uchar *b, uint b_length)
+ const uchar *b, uint b_length,
+ my_bool diff_if_only_endspace_difference)
{
uint length= min(a_length, b_length);
int res= my_strnncoll_gbk_internal(&a, &b, length);
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
+
if (!res && a_length != b_length)
{
const uchar *end;
int swap= 1;
+ if (diff_if_only_endspace_difference)
+ res= 1; /* Assume 'a' is bigger */
/*
Check the next not space character of the longer key. If it's < ' ',
then it's smaller than the other key.
@@ -2643,6 +2651,7 @@ static int my_strnncollsp_gbk(CHARSET_INFO * cs __attribute__((unused)),
a_length= b_length;
a= b;
swap= -1; /* swap sign of result */
+ res= -res;
}
for (end= a + a_length-length; a < end ; a++)
{
@@ -2731,22 +2740,26 @@ static my_bool my_like_range_gbk(CHARSET_INFO *cs __attribute__((unused)),
}
if (*ptr == w_many) /* '%' in SQL */
{
- *min_length= (uint) (min_str - min_org);
+ /*
+ Calculate length of keys:
+ 'a\0\0... is the smallest possible string when we have space expand
+ a\ff\ff... is the biggest possible string
+ */
+ *min_length= ((cs->state & MY_CS_BINSORT) ? (uint) (min_str - min_org) :
+ res_length);
*max_length= res_length;
do {
*min_str++= 0;
- *max_str++ = max_sort_char;
+ *max_str++= max_sort_char;
} while (min_str != min_end);
return 0;
}
*min_str++= *max_str++ = *ptr;
}
+
*min_length= *max_length = (uint) (min_str - min_org);
while (min_str != min_end)
- {
- *min_str++ = ' '; /* Because if key compression */
- *max_str++ = ' ';
- }
+ *min_str++= *max_str++= ' '; /* Because if key compression */
return 0;
}
@@ -9926,6 +9939,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler =
my_strnncoll_gbk,
my_strnncollsp_gbk,
my_strnxfrm_gbk,
+ my_strnxfrmlen_simple,
my_like_range_gbk,
my_wildcmp_mb,
my_strcasecmp_mb,
diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c
index 4ab101add5b..fdf9f4a6d91 100644
--- a/strings/ctype-latin1.c
+++ b/strings/ctype-latin1.c
@@ -572,11 +572,16 @@ static int my_strnncoll_latin1_de(CHARSET_INFO *cs __attribute__((unused)),
static int my_strnncollsp_latin1_de(CHARSET_INFO *cs __attribute__((unused)),
const uchar *a, uint a_length,
- const uchar *b, uint b_length)
+ const uchar *b, uint b_length,
+ my_bool diff_if_only_endspace_difference)
{
- const uchar *a_end= a + a_length;
- const uchar *b_end= b + b_length;
+ const uchar *a_end= a + a_length, *b_end= b + b_length;
uchar a_char, a_extend= 0, b_char, b_extend= 0;
+ int res;
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
while ((a < a_end || a_extend) && (b < b_end || b_extend))
{
@@ -609,9 +614,12 @@ static int my_strnncollsp_latin1_de(CHARSET_INFO *cs __attribute__((unused)),
if (b_extend)
return -1;
+ res= 0;
if (a != a_end || b != b_end)
{
int swap= 1;
+ if (diff_if_only_endspace_difference)
+ res= 1; /* Assume 'a' is bigger */
/*
Check the next not space character of the longer key. If it's < ' ',
then it's smaller than the other key.
@@ -622,6 +630,7 @@ static int my_strnncollsp_latin1_de(CHARSET_INFO *cs __attribute__((unused)),
a_end= b_end;
a= b;
swap= -1; /* swap sign of result */
+ res= -res;
}
for ( ; a < a_end ; a++)
{
@@ -629,7 +638,7 @@ static int my_strnncollsp_latin1_de(CHARSET_INFO *cs __attribute__((unused)),
return (*a < ' ') ? -swap : swap;
}
}
- return 0;
+ return res;
}
@@ -684,6 +693,7 @@ static MY_COLLATION_HANDLER my_collation_german2_ci_handler=
my_strnncoll_latin1_de,
my_strnncollsp_latin1_de,
my_strnxfrm_latin1_de,
+ my_strnxfrmlen_simple,
my_like_range_simple,
my_wildcmp_8bit,
my_strcasecmp_8bit,
diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c
index cbbd035c631..b603a8ea0a8 100644
--- a/strings/ctype-mb.c
+++ b/strings/ctype-mb.c
@@ -365,6 +365,9 @@ static int my_strnncoll_mb_bin(CHARSET_INFO * cs __attribute__((unused)),
slen Length of 's'
t String to compare
tlen Length of 't'
+ diff_if_only_endspace_difference
+ Set to 1 if the strings should be regarded as different
+ if they only difference in end space
NOTE
This function is used for character strings with binary collations.
@@ -379,10 +382,16 @@ static int my_strnncoll_mb_bin(CHARSET_INFO * cs __attribute__((unused)),
static int my_strnncollsp_mb_bin(CHARSET_INFO * cs __attribute__((unused)),
const uchar *a, uint a_length,
- const uchar *b, uint b_length)
+ const uchar *b, uint b_length,
+ my_bool diff_if_only_endspace_difference)
{
const uchar *end;
uint length;
+ int res;
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
end= a + (length= min(a_length, b_length));
while (a < end)
@@ -390,9 +399,12 @@ static int my_strnncollsp_mb_bin(CHARSET_INFO * cs __attribute__((unused)),
if (*a++ != *b++)
return ((int) a[-1] - (int) b[-1]);
}
+ res= 0;
if (a_length != b_length)
{
int swap= 1;
+ if (diff_if_only_endspace_difference)
+ res= 1; /* Assume 'a' is bigger */
/*
Check the next not space character of the longer key. If it's < ' ',
then it's smaller than the other key.
@@ -403,6 +415,7 @@ static int my_strnncollsp_mb_bin(CHARSET_INFO * cs __attribute__((unused)),
a_length= b_length;
a= b;
swap= -1; /* swap sign of result */
+ res= -res;
}
for (end= a + a_length-length; a < end ; a++)
{
@@ -410,7 +423,7 @@ static int my_strnncollsp_mb_bin(CHARSET_INFO * cs __attribute__((unused)),
return (*a < ' ') ? -swap : swap;
}
}
- return 0;
+ return res;
}
@@ -527,9 +540,15 @@ my_bool my_like_range_mb(CHARSET_INFO *cs,
if (charlen < (uint) (min_str - min_org))
min_str= min_org + charlen;
- /* Write min key */
- *min_length= (uint) (min_str - min_org);
+ /*
+ Calculate length of keys:
+ 'a\0\0... is the smallest possible string when we have space expand
+ a\ff\ff... is the biggest possible string
+ */
+ *min_length= ((cs->state & MY_CS_BINSORT) ? (uint) (min_str - min_org) :
+ res_length);
*max_length= res_length;
+ /* Create min key */
do
{
*min_str++= (char) cs->min_sort_char;
@@ -545,14 +564,14 @@ my_bool my_like_range_mb(CHARSET_INFO *cs,
}
*min_str++= *max_str++ = *ptr;
}
- *min_length= *max_length = (uint) (min_str - min_org);
+ *min_length= *max_length = (uint) (min_str - min_org);
while (min_str != min_end)
- *min_str++= ' '; /* Because if key compression */
- pad_max_char(cs, max_str, max_end);
+ *min_str++= *max_str++= ' '; /* Because if key compression */
return 0;
}
+
static int my_wildcmp_mb_bin(CHARSET_INFO *cs,
const char *str,const char *str_end,
const char *wildstr,const char *wildend,
@@ -896,6 +915,7 @@ MY_COLLATION_HANDLER my_collation_mb_bin_handler =
my_strnncoll_mb_bin,
my_strnncollsp_mb_bin,
my_strnxfrm_mb_bin,
+ my_strnxfrmlen_simple,
my_like_range_simple,
my_wildcmp_mb_bin,
my_strcasecmp_mb_bin,
diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c
index bd5131b7448..5fa1a1b18a0 100644
--- a/strings/ctype-simple.c
+++ b/strings/ctype-simple.c
@@ -22,6 +22,15 @@
#include "stdarg.h"
/*
+ Returns the number of bytes required for strnxfrm().
+*/
+uint my_strnxfrmlen_simple(CHARSET_INFO *cs, uint len)
+{
+ return len * (cs->strxfrm_multiply ? cs->strxfrm_multiply : 1);
+}
+
+
+/*
Converts a string into its sort key.
SYNOPSIS
@@ -112,6 +121,9 @@ int my_strnncoll_simple(CHARSET_INFO * cs, const uchar *s, uint slen,
a_length Length of 'a'
b Second string to compare
b_length Length of 'b'
+ diff_if_only_endspace_difference
+ Set to 1 if the strings should be regarded as different
+ if they only difference in end space
IMPLEMENTATION
If one string is shorter as the other, then we space extend the other
@@ -130,10 +142,16 @@ int my_strnncoll_simple(CHARSET_INFO * cs, const uchar *s, uint slen,
*/
int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, uint a_length,
- const uchar *b, uint b_length)
+ const uchar *b, uint b_length,
+ my_bool diff_if_only_endspace_difference)
{
const uchar *map= cs->sort_order, *end;
uint length;
+ int res;
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
end= a + (length= min(a_length, b_length));
while (a < end)
@@ -141,9 +159,12 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, uint a_length,
if (map[*a++] != map[*b++])
return ((int) map[a[-1]] - (int) map[b[-1]]);
}
+ res= 0;
if (a_length != b_length)
{
int swap= 1;
+ if (diff_if_only_endspace_difference)
+ res= 1; /* Assume 'a' is bigger */
/*
Check the next not space character of the longer key. If it's < ' ',
then it's smaller than the other key.
@@ -154,6 +175,7 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, uint a_length,
a_length= b_length;
a= b;
swap= -1; /* swap sign of result */
+ res= -res;
}
for (end= a + a_length-length; a < end ; a++)
{
@@ -161,7 +183,7 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, uint a_length,
return (*a < ' ') ? -swap : swap;
}
}
- return 0;
+ return res;
}
@@ -259,14 +281,19 @@ void my_hash_sort_simple(CHARSET_INFO *cs,
ulong *nr1, ulong *nr2)
{
register uchar *sort_order=cs->sort_order;
- const uchar *pos = key;
+ const uchar *end= key + len;
- key+= len;
+ /*
+ Remove end space. We have to do this to be able to compare
+ 'A ' and 'A' as identical
+ */
+ while (end > key && end[-1] == ' ')
+ end--;
- for (; pos < (uchar*) key ; pos++)
+ for (; key < (uchar*) end ; key++)
{
nr1[0]^=(ulong) ((((uint) nr1[0] & 63)+nr2[0]) *
- ((uint) sort_order[(uint) *pos])) + (nr1[0] << 8);
+ ((uint) sort_order[(uint) *key])) + (nr1[0] << 8);
nr2[0]+=3;
}
}
@@ -867,7 +894,7 @@ int my_longlong10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)),
while (long_val != 0)
{
long quo= long_val/10;
- *--p = '0' + (long_val - quo*10);
+ *--p = '0' + (char)(long_val - quo*10);
long_val= quo;
}
@@ -1017,8 +1044,10 @@ my_bool my_like_range_simple(CHARSET_INFO *cs,
}
if (*ptr == w_many) /* '%' in SQL */
{
- *min_length= (uint) (min_str - min_org);
- *max_length=res_length;
+ /* Calculate length of keys */
+ *min_length= ((cs->state & MY_CS_BINSORT) ? (uint) (min_str - min_org) :
+ res_length);
+ *max_length= res_length;
do
{
*min_str++= 0;
@@ -1028,10 +1057,10 @@ my_bool my_like_range_simple(CHARSET_INFO *cs,
}
*min_str++= *max_str++ = *ptr;
}
- *min_length= *max_length = (uint) (min_str - min_org);
+ *min_length= *max_length = (uint) (min_str - min_org);
while (min_str != min_end)
- *min_str++ = *max_str++ = ' '; /* Because if key compression */
+ *min_str++= *max_str++ = ' '; /* Because if key compression */
return 0;
}
@@ -1346,6 +1375,7 @@ MY_COLLATION_HANDLER my_collation_8bit_simple_ci_handler =
my_strnncoll_simple,
my_strnncollsp_simple,
my_strnxfrm_simple,
+ my_strnxfrmlen_simple,
my_like_range_simple,
my_wildcmp_8bit,
my_strcasecmp_8bit,
diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c
index 35182db3345..62cb5427dd9 100644
--- a/strings/ctype-sjis.c
+++ b/strings/ctype-sjis.c
@@ -244,14 +244,21 @@ static int my_strnncoll_sjis(CHARSET_INFO *cs __attribute__((unused)),
static int my_strnncollsp_sjis(CHARSET_INFO *cs __attribute__((unused)),
const uchar *a, uint a_length,
- const uchar *b, uint b_length)
+ const uchar *b, uint b_length,
+ my_bool diff_if_only_endspace_difference)
{
- const uchar *a_end= a + a_length;
- const uchar *b_end= b + b_length;
+ const uchar *a_end= a + a_length, *b_end= b + b_length;
int res= my_strnncoll_sjis_internal(cs, &a, a_length, &b, b_length);
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
+
if (!res && (a != a_end || b != b_end))
{
int swap= 1;
+ if (diff_if_only_endspace_difference)
+ res= 1; /* Assume 'a' is bigger */
/*
Check the next not space character of the longer key. If it's < ' ',
then it's smaller than the other key.
@@ -262,6 +269,7 @@ static int my_strnncollsp_sjis(CHARSET_INFO *cs __attribute__((unused)),
a_end= b_end;
a= b;
swap= -1; /* swap sign of result */
+ res= -res;
}
for (; a < a_end ; a++)
{
@@ -349,8 +357,14 @@ static my_bool my_like_range_sjis(CHARSET_INFO *cs __attribute__((unused)),
}
if (*ptr == w_many)
{ /* '%' in SQL */
- *min_length = (uint)(min_str - min_org);
- *max_length = res_length;
+ /*
+ Calculate length of keys:
+ 'a\0\0... is the smallest possible string when we have space expand
+ a\ff\ff... is the biggest possible string
+ */
+ *min_length= ((cs->state & MY_CS_BINSORT) ? (uint) (min_str - min_org) :
+ res_length);
+ *max_length= res_length;
do
{
*min_str++= 0;
@@ -360,9 +374,10 @@ static my_bool my_like_range_sjis(CHARSET_INFO *cs __attribute__((unused)),
}
*min_str++ = *max_str++ = *ptr++;
}
- *min_length = *max_length = (uint)(min_str - min_org);
- while (min_str < min_end)
- *min_str++ = *max_str++ = ' '; /* Because if key compression */
+
+ *min_length= *max_length= (uint) (min_str - min_org);
+ while (min_str != min_end)
+ *min_str++= *max_str++= ' '; /* Because if key compression */
return 0;
}
@@ -4610,6 +4625,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler =
my_strnncoll_sjis,
my_strnncollsp_sjis,
my_strnxfrm_sjis,
+ my_strnxfrmlen_simple,
my_like_range_sjis,
my_wildcmp_mb, /* wildcmp */
my_strcasecmp_8bit,
diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c
index 6a6c55d214e..b6c54f1b375 100644
--- a/strings/ctype-tis620.c
+++ b/strings/ctype-tis620.c
@@ -320,7 +320,7 @@ static int t_ctype[][TOT_LEVELS] = {
/*0xFC*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xFD*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
/*0xFE*/ { IGNORE, IGNORE, IGNORE, IGNORE, X },
-/* Utilize 0xFF for max_sort_chr in my_like_range_tis620 */
+ /* Utilize 0xFF for max_sort_chr in my_like_range_tis620 */
/*0xFF*/ { 255 /*IGNORE*/, IGNORE, IGNORE, IGNORE, X },
};
@@ -559,12 +559,16 @@ int my_strnncoll_tis620(CHARSET_INFO *cs __attribute__((unused)),
static
int my_strnncollsp_tis620(CHARSET_INFO * cs __attribute__((unused)),
const uchar *a0, uint a_length,
- const uchar *b0, uint b_length)
+ const uchar *b0, uint b_length,
+ my_bool diff_if_only_endspace_difference)
{
- uchar buf[80] ;
- uchar *end, *a, *b, *alloced= NULL;
+ uchar buf[80], *end, *a, *b, *alloced= NULL;
uint length;
int res= 0;
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
a= buf;
if ((a_length + b_length +2) > (int) sizeof(buf))
@@ -590,6 +594,8 @@ int my_strnncollsp_tis620(CHARSET_INFO * cs __attribute__((unused)),
if (a_length != b_length)
{
int swap= 1;
+ if (diff_if_only_endspace_difference)
+ res= 1; /* Assume 'a' is bigger */
/*
Check the next not space character of the longer key. If it's < ' ',
then it's smaller than the other key.
@@ -600,6 +606,7 @@ int my_strnncollsp_tis620(CHARSET_INFO * cs __attribute__((unused)),
a_length= b_length;
a= b;
swap= -1; /* swap sign of result */
+ res= -res;
}
for (end= a + a_length-length; a < end ; a++)
{
@@ -687,8 +694,14 @@ my_bool my_like_range_tis620(CHARSET_INFO *cs __attribute__((unused)),
}
if (*ptr == w_many) /* '%' in SQL */
{
- *min_length= (uint) (min_str - min_org);
- *max_length=res_length;
+ /*
+ Calculate length of keys:
+ 'a\0\0... is the smallest possible string when we have space expand
+ a\ff\ff... is the biggest possible string
+ */
+ *min_length= ((cs->state & MY_CS_BINSORT) ? (uint) (min_str - min_org) :
+ res_length);
+ *max_length= res_length;
do
{
*min_str++ = 0;
@@ -698,10 +711,10 @@ my_bool my_like_range_tis620(CHARSET_INFO *cs __attribute__((unused)),
}
*min_str++= *max_str++ = *ptr;
}
- *min_length= *max_length = (uint) (min_str - min_org);
+ *min_length= *max_length = (uint) (min_str - min_org);
while (min_str != min_end)
- *min_str++ = *max_str++ = ' '; /* Because of key compression */
+ *min_str++= *max_str++ = ' '; /* Because of key compression */
return 0;
}
@@ -914,6 +927,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler =
my_strnncoll_tis620,
my_strnncollsp_tis620,
my_strnxfrm_tis620,
+ my_strnxfrmlen_simple,
my_like_range_tis620,
my_wildcmp_8bit, /* wildcmp */
my_strcasecmp_8bit,
diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c
index 53c4fabaf08..3204bd2e1f6 100644
--- a/strings/ctype-uca.c
+++ b/strings/ctype-uca.c
@@ -7048,6 +7048,9 @@ static int my_strnncoll_uca(CHARSET_INFO *cs,
slen First string length
t Second string
tlen Seconf string length
+ diff_if_only_endspace_difference
+ Set to 1 if the strings should be regarded as different
+ if they only difference in end space
NOTES:
Works exactly the same with my_strnncoll_uca(),
@@ -7085,13 +7088,16 @@ static int my_strnncoll_uca(CHARSET_INFO *cs,
static int my_strnncollsp_uca(CHARSET_INFO *cs,
my_uca_scanner_handler *scanner_handler,
const uchar *s, uint slen,
- const uchar *t, uint tlen)
+ const uchar *t, uint tlen,
+ my_bool diff_if_only_endspace_difference)
{
- my_uca_scanner sscanner;
- my_uca_scanner tscanner;
- int s_res;
- int t_res;
+ my_uca_scanner sscanner, tscanner;
+ int s_res, t_res;
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
+
scanner_handler->init(&sscanner, cs, s, slen);
scanner_handler->init(&tscanner, cs, t, tlen);
@@ -7113,7 +7119,7 @@ static int my_strnncollsp_uca(CHARSET_INFO *cs,
return (s_res - t_res);
s_res= scanner_handler->next(&sscanner);
} while (s_res > 0);
- return 0;
+ return diff_if_only_endspace_difference ? 1 : 0;
}
if (s_res < 0 && t_res > 0)
@@ -7128,7 +7134,7 @@ static int my_strnncollsp_uca(CHARSET_INFO *cs,
return (s_res - t_res);
t_res= scanner_handler->next(&tscanner);
} while (t_res > 0);
- return 0;
+ return diff_if_only_endspace_difference ? -1 : 0;
}
return ( s_res - t_res );
@@ -7949,11 +7955,13 @@ static int my_strnncoll_any_uca(CHARSET_INFO *cs,
}
static int my_strnncollsp_any_uca(CHARSET_INFO *cs,
- const uchar *s, uint slen,
- const uchar *t, uint tlen)
+ const uchar *s, uint slen,
+ const uchar *t, uint tlen,
+ my_bool diff_if_only_endspace_difference)
{
return my_strnncollsp_uca(cs, &my_any_uca_scanner_handler,
- s, slen, t, tlen);
+ s, slen, t, tlen,
+ diff_if_only_endspace_difference);
}
static void my_hash_sort_any_uca(CHARSET_INFO *cs,
@@ -7986,11 +7994,13 @@ static int my_strnncoll_ucs2_uca(CHARSET_INFO *cs,
}
static int my_strnncollsp_ucs2_uca(CHARSET_INFO *cs,
- const uchar *s, uint slen,
- const uchar *t, uint tlen)
+ const uchar *s, uint slen,
+ const uchar *t, uint tlen,
+ my_bool diff_if_only_endspace_difference)
{
return my_strnncollsp_uca(cs, &my_ucs2_uca_scanner_handler,
- s, slen, t, tlen);
+ s, slen, t, tlen,
+ diff_if_only_endspace_difference);
}
static void my_hash_sort_ucs2_uca(CHARSET_INFO *cs,
@@ -8014,6 +8024,7 @@ MY_COLLATION_HANDLER my_collation_ucs2_uca_handler =
my_strnncoll_ucs2_uca,
my_strnncollsp_ucs2_uca,
my_strnxfrm_ucs2_uca,
+ my_strnxfrmlen_simple,
my_like_range_ucs2,
my_wildcmp_uca,
NULL,
@@ -8494,6 +8505,7 @@ MY_COLLATION_HANDLER my_collation_any_uca_handler =
my_strnncoll_any_uca,
my_strnncollsp_any_uca,
my_strnxfrm_any_uca,
+ my_strnxfrmlen_simple,
my_like_range_mb,
my_wildcmp_uca,
NULL,
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index f5d0721fa9b..73d15da8a4a 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -137,6 +137,9 @@ static void my_hash_sort_ucs2(CHARSET_INFO *cs, const uchar *s, uint slen,
int res;
const uchar *e=s+slen;
+ while (e > s+1 && e[-1] == ' ' && e[-2] == '\0')
+ e-= 2;
+
while ((s < e) && (res=my_ucs2_uni(cs,&wc, (uchar *)s, (uchar*)e)) >0)
{
int plane = (wc>>8) & 0xFF;
@@ -247,14 +250,16 @@ static int my_strnncoll_ucs2(CHARSET_INFO *cs,
static int my_strnncollsp_ucs2(CHARSET_INFO *cs __attribute__((unused)),
const uchar *s, uint slen,
- const uchar *t, uint tlen)
+ const uchar *t, uint tlen,
+ my_bool diff_if_only_endspace_difference
+ __attribute__((unused)))
{
const uchar *se, *te;
uint minlen;
/* extra safety to make sure the lengths are even numbers */
- slen= (slen >> 1) << 1;
- tlen= (tlen >> 1) << 1;
+ slen&= ~1;
+ tlen&= ~1;
se= s + slen;
te= t + tlen;
@@ -367,7 +372,7 @@ static int my_strnxfrm_ucs2(CHARSET_INFO *cs,
dst+=res;
}
if (dst < de)
- cs->cset->fill(cs, dst, de - dst, ' ');
+ cs->cset->fill(cs, (char*) dst, de - dst, ' ');
return dstlen;
}
@@ -921,15 +926,16 @@ bs:
return (negative ? -((longlong) res) : (longlong) res);
}
-double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
- char *nptr, uint length,
- char **endptr, int *err)
+
+double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
+ char *nptr, uint length,
+ char **endptr, int *err)
{
char buf[256];
double res;
register char *b=buf;
register const uchar *s= (const uchar*) nptr;
- register const uchar *end;
+ const uchar *end;
my_wc_t wc;
int cnv;
@@ -1043,7 +1049,7 @@ int my_ll10tostr_ucs2(CHARSET_INFO *cs __attribute__((unused)),
while (long_val != 0)
{
long quo= long_val/10;
- *--p = '0' + (long_val - quo*10);
+ *--p = '0' + (char)(long_val - quo*10);
long_val= quo;
}
@@ -1352,8 +1358,11 @@ int my_strnncoll_ucs2_bin(CHARSET_INFO *cs,
static int my_strnncollsp_ucs2_bin(CHARSET_INFO *cs,
const uchar *s, uint slen,
- const uchar *t, uint tlen)
+ const uchar *t, uint tlen,
+ my_bool diff_if_only_endspace_difference
+ __attribute__((unused)))
{
+ /* TODO: Needs to be fixed to handle end space! */
return my_strnncoll_ucs2_bin(cs,s,slen,t,tlen,0);
}
@@ -1376,7 +1385,7 @@ int my_strnxfrm_ucs2_bin(CHARSET_INFO *cs __attribute__((unused)),
if (dst != src)
memcpy(dst,src,srclen= min(dstlen,srclen));
if (dstlen > srclen)
- cs->cset->fill(cs, dst + srclen, dstlen - srclen, ' ');
+ cs->cset->fill(cs, (char*) dst + srclen, dstlen - srclen, ' ');
return dstlen;
}
@@ -1444,8 +1453,14 @@ my_bool my_like_range_ucs2(CHARSET_INFO *cs,
}
if (ptr[0] == '\0' && ptr[1] == w_many) /* '%' in SQL */
{
- *min_length= (uint) (min_str - min_org);
- *max_length=res_length;
+ /*
+ Calculate length of keys:
+ 'a\0\0... is the smallest possible string when we have space expand
+ a\ff\ff... is the biggest possible string
+ */
+ *min_length= ((cs->state & MY_CS_BINSORT) ? (uint) (min_str - min_org) :
+ res_length);
+ *max_length= res_length;
do {
*min_str++ = 0;
*min_str++ = 0;
@@ -1457,7 +1472,6 @@ my_bool my_like_range_ucs2(CHARSET_INFO *cs,
*min_str++= *max_str++ = ptr[0];
*min_str++= *max_str++ = ptr[1];
}
- *min_length= *max_length = (uint) (min_str - min_org);
/* Temporary fix for handling w_one at end of string (key compression) */
{
@@ -1469,15 +1483,17 @@ my_bool my_like_range_ucs2(CHARSET_INFO *cs,
}
}
+ *min_length= *max_length = (uint) (min_str - min_org);
while (min_str + 1 < min_end)
{
*min_str++ = *max_str++ = '\0';
- *min_str++ = *max_str++ = ' '; /* Because if key compression */
+ *min_str++ = *max_str++ = ' '; /* Because if key compression */
}
return 0;
}
+
ulong my_scan_ucs2(CHARSET_INFO *cs __attribute__((unused)),
const char *str, const char *end, int sequence_type)
{
@@ -1506,6 +1522,7 @@ static MY_COLLATION_HANDLER my_collation_ucs2_general_ci_handler =
my_strnncoll_ucs2,
my_strnncollsp_ucs2,
my_strnxfrm_ucs2,
+ my_strnxfrmlen_simple,
my_like_range_ucs2,
my_wildcmp_ucs2_ci,
my_strcasecmp_ucs2,
@@ -1520,6 +1537,7 @@ static MY_COLLATION_HANDLER my_collation_ucs2_bin_handler =
my_strnncoll_ucs2_bin,
my_strnncollsp_ucs2_bin,
my_strnxfrm_ucs2_bin,
+ my_strnxfrmlen_simple,
my_like_range_simple,
my_wildcmp_ucs2_bin,
my_strcasecmp_ucs2_bin,
diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c
index 612dda2b3eb..7bcf1c83bab 100644
--- a/strings/ctype-ujis.c
+++ b/strings/ctype-ujis.c
@@ -8510,6 +8510,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler =
my_strnncoll_simple,/* strnncoll */
my_strnncollsp_simple,
my_strnxfrm_simple, /* strnxfrm */
+ my_strnxfrmlen_simple,
my_like_range_simple,/* like_range */
my_wildcmp_mb, /* wildcmp */
my_strcasecmp_mb,
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index 230b44796e8..14b3934e815 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -1923,12 +1923,20 @@ static void my_caseup_utf8(CHARSET_INFO *cs, char *s, uint slen)
}
}
-static void my_hash_sort_utf8(CHARSET_INFO *cs, const uchar *s, uint slen, ulong *n1, ulong *n2)
+static void my_hash_sort_utf8(CHARSET_INFO *cs, const uchar *s, uint slen,
+ ulong *n1, ulong *n2)
{
my_wc_t wc;
int res;
const uchar *e=s+slen;
+ /*
+ Remove end space. We have to do this to be able to compare
+ 'A ' and 'A' as identical
+ */
+ while (e > s && e[-1] == ' ')
+ e--;
+
while ((s < e) && (res=my_utf8_uni(cs,&wc, (uchar *)s, (uchar*)e))>0 )
{
int plane = (wc>>8) & 0xFF;
@@ -2021,6 +2029,9 @@ static int my_strnncoll_utf8(CHARSET_INFO *cs,
a_length Length of 'a'
b Second string to compare
b_length Length of 'b'
+ diff_if_only_endspace_difference
+ Set to 1 if the strings should be regarded as different
+ if they only difference in end space
IMPLEMENTATION
If one string is shorter as the other, then we space extend the other
@@ -2039,13 +2050,17 @@ static int my_strnncoll_utf8(CHARSET_INFO *cs,
*/
static int my_strnncollsp_utf8(CHARSET_INFO *cs,
- const uchar *s, uint slen,
- const uchar *t, uint tlen)
+ const uchar *s, uint slen,
+ const uchar *t, uint tlen,
+ my_bool diff_if_only_endspace_difference)
{
- int s_res,t_res;
+ int s_res, t_res, res;
my_wc_t s_wc,t_wc;
- const uchar *se= s+slen;
- const uchar *te= t+tlen;
+ const uchar *se= s+slen, *te= t+tlen;
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+ diff_if_only_endspace_difference= 0;
+#endif
while ( s < se && t < te )
{
@@ -2074,16 +2089,20 @@ static int my_strnncollsp_utf8(CHARSET_INFO *cs,
slen= se-s;
tlen= te-t;
+ res= 0;
if (slen != tlen)
{
int swap= 1;
+ if (diff_if_only_endspace_difference)
+ res= 1; /* Assume 'a' is bigger */
if (slen < tlen)
{
slen= tlen;
s= t;
se= te;
swap= -1;
+ res= -res;
}
/*
This following loop uses the fact that in UTF-8
@@ -2101,7 +2120,7 @@ static int my_strnncollsp_utf8(CHARSET_INFO *cs,
return (*s < ' ') ? -swap : swap;
}
}
- return 0;
+ return res;
}
@@ -2214,6 +2233,12 @@ int my_wildcmp_utf8(CHARSET_INFO *cs,
}
+static
+uint my_strnxfrmlen_utf8(CHARSET_INFO *cs __attribute__((unused)), uint len)
+{
+ return (len * 2 + 2) / 3;
+}
+
static int my_strnxfrm_utf8(CHARSET_INFO *cs,
uchar *dst, uint dstlen,
const uchar *src, uint srclen)
@@ -2221,29 +2246,33 @@ static int my_strnxfrm_utf8(CHARSET_INFO *cs,
my_wc_t wc;
int res;
int plane;
- uchar *de = dst + dstlen;
+ uchar *de= dst + dstlen;
+ uchar *de_beg= de - 1;
const uchar *se = src + srclen;
- while( src < se && dst < de )
+ while (dst < de_beg)
{
- if ((res=my_utf8_uni(cs,&wc, src, se))<0)
- {
+ if ((res=my_utf8_uni(cs,&wc, src, se)) <= 0)
break;
- }
src+=res;
- srclen-=res;
plane=(wc>>8) & 0xFF;
wc = uni_plane[plane] ? uni_plane[plane][wc & 0xFF].sort : wc;
- if ((res=my_uni_utf8(cs,wc,dst,de)) <0)
- {
- break;
- }
- dst+=res;
+ *dst++= (uchar)(wc >> 8);
+ *dst++= (uchar)(wc & 0xFF);
+
+ }
+
+ while (dst < de_beg) /* Fill the tail with keys for space character */
+ {
+ *dst++= 0x00;
+ *dst++= 0x20;
}
- if (dst < de)
- bfill(dst, de - dst, ' ');
+
+ if (dst < de) /* Clear the last byte, if "dstlen" was an odd number */
+ *dst= 0x00;
+
return dstlen;
}
@@ -2282,6 +2311,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler =
my_strnncoll_utf8,
my_strnncollsp_utf8,
my_strnxfrm_utf8,
+ my_strnxfrmlen_utf8,
my_like_range_mb,
my_wildcmp_utf8,
my_strcasecmp_utf8,
diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c
index d843971b93f..8c58520f965 100644
--- a/strings/ctype-win1250ch.c
+++ b/strings/ctype-win1250ch.c
@@ -479,7 +479,9 @@ static int my_strnncoll_win1250ch(CHARSET_INFO *cs __attribute__((unused)),
static
int my_strnncollsp_win1250ch(CHARSET_INFO * cs,
const uchar *s, uint slen,
- const uchar *t, uint tlen)
+ const uchar *t, uint tlen,
+ my_bool diff_if_only_endspace_difference
+ __attribute__((unused)))
{
for ( ; slen && s[slen-1] == ' ' ; slen--);
for ( ; tlen && t[tlen-1] == ' ' ; tlen--);
@@ -596,11 +598,19 @@ my_like_range_win1250ch(CHARSET_INFO *cs __attribute__((unused)),
if (*min_str != min_sort_char)
only_min_found= 0;
min_str++;
- *max_str++ = like_range_prefix_max_win1250ch[(uint)(*ptr)];
+ *max_str++= like_range_prefix_max_win1250ch[(uint)(*ptr)];
}
- *min_length = (uint) (min_str - min_org);
- *max_length = res_length;
+ if (cs->state & MY_CS_BINSORT)
+ *min_length= (uint) (min_str - min_org);
+ else
+ {
+ /* 'a\0\0... is the smallest possible string */
+ *min_length= res_length;
+ }
+ /* a\ff\ff... is the biggest possible string */
+ *max_length= res_length;
+
while (min_str != min_end)
{
*min_str++ = min_sort_char;
@@ -616,6 +626,7 @@ static MY_COLLATION_HANDLER my_collation_czech_ci_handler =
my_strnncoll_win1250ch,
my_strnncollsp_win1250ch,
my_strnxfrm_win1250ch,
+ my_strnxfrmlen_simple,
my_like_range_win1250ch,
my_wildcmp_8bit,
my_strcasecmp_8bit,
diff --git a/strings/decimal.c b/strings/decimal.c
new file mode 100644
index 00000000000..9af95511f6d
--- /dev/null
+++ b/strings/decimal.c
@@ -0,0 +1,2966 @@
+/* Copyright (C) 2000 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#line 18 "decimal.c"
+
+/*
+=======================================================================
+ NOTE: this library implements SQL standard "exact numeric" type
+ and is not at all generic, but rather intentinally crippled to
+ follow the standard :)
+=======================================================================
+ Quoting the standard
+ (SQL:2003, Part 2 Foundations, aka ISO/IEC 9075-2:2003)
+
+4.4.2 Characteristics of numbers, page 27:
+
+ An exact numeric type has a precision P and a scale S. P is a positive
+ integer that determines the number of significant digits in a
+ particular radix R, where R is either 2 or 10. S is a non-negative
+ integer. Every value of an exact numeric type of scale S is of the
+ form n*10^{-S}, where n is an integer such that ­-R^P <= n <= R^P.
+
+ [...]
+
+ If an assignment of some number would result in a loss of its most
+ significant digit, an exception condition is raised. If least
+ significant digits are lost, implementation-defined rounding or
+ truncating occurs, with no exception condition being raised.
+
+ [...]
+
+ Whenever an exact or approximate numeric value is assigned to an exact
+ numeric value site, an approximation of its value that preserves
+ leading significant digits after rounding or truncating is represented
+ in the declared type of the target. The value is converted to have the
+ precision and scale of the target. The choice of whether to truncate
+ or round is implementation-defined.
+
+ [...]
+
+ All numeric values between the smallest and the largest value,
+ inclusive, in a given exact numeric type have an approximation
+ obtained by rounding or truncation for that type; it is
+ implementation-defined which other numeric values have such
+ approximations.
+
+5.3 <literal>, page 143
+
+ <exact numeric literal> ::=
+ <unsigned integer> [ <period> [ <unsigned integer> ] ]
+ | <period> <unsigned integer>
+
+6.1 <data type>, page 165:
+
+ 19) The <scale> of an <exact numeric type> shall not be greater than
+ the <precision> of the <exact numeric type>.
+
+ 20) For the <exact numeric type>s DECIMAL and NUMERIC:
+
+ a) The maximum value of <precision> is implementation-defined.
+ <precision> shall not be greater than this value.
+ b) The maximum value of <scale> is implementation-defined. <scale>
+ shall not be greater than this maximum value.
+
+ 21) NUMERIC specifies the data type exact numeric, with the decimal
+ precision and scale specified by the <precision> and <scale>.
+
+ 22) DECIMAL specifies the data type exact numeric, with the decimal
+ scale specified by the <scale> and the implementation-defined
+ decimal precision equal to or greater than the value of the
+ specified <precision>.
+
+6.26 <numeric value expression>, page 241:
+
+ 1) If the declared type of both operands of a dyadic arithmetic
+ operator is exact numeric, then the declared type of the result is
+ an implementation-defined exact numeric type, with precision and
+ scale determined as follows:
+
+ a) Let S1 and S2 be the scale of the first and second operands
+ respectively.
+ b) The precision of the result of addition and subtraction is
+ implementation-defined, and the scale is the maximum of S1 and S2.
+ c) The precision of the result of multiplication is
+ implementation-defined, and the scale is S1 + S2.
+ d) The precision and scale of the result of division are
+ implementation-defined.
+*/
+
+#include <my_global.h>
+#include <m_ctype.h>
+#include <myisampack.h>
+#include <my_sys.h> /* for my_alloca */
+#include <m_string.h>
+#include <decimal.h>
+
+/*
+ Internally decimal numbers are stored base 10^9 (see DIG_BASE below)
+ So one variable of type decimal_digit_t is limited:
+
+ 0 < decimal_digit <= DIG_MAX < DIG_BASE
+
+ in the struct st_decimal_t:
+
+ intg is the number of *decimal* digits (NOT number of decimal_digit_t's !)
+ before the point
+ frac - number of decimal digits after the point
+ buf is an array of decimal_digit_t's
+ len is the length of buf (length of allocated space) in decimal_digit_t's,
+ not in bytes
+*/
+typedef decimal_digit_t dec1;
+typedef longlong dec2;
+
+#define DIG_PER_DEC1 9
+#define DIG_MASK 100000000
+#define DIG_BASE 1000000000
+#define DIG_MAX (DIG_BASE-1)
+#define DIG_BASE2 ((dec2)DIG_BASE * (dec2)DIG_BASE)
+#define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1)
+static const dec1 powers10[DIG_PER_DEC1+1]={
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
+static const int dig2bytes[DIG_PER_DEC1+1]={0, 1, 1, 2, 2, 3, 3, 4, 4, 4};
+static const dec1 frac_max[DIG_PER_DEC1-1]={
+ 900000000, 990000000, 999000000,
+ 999900000, 999990000, 999999000,
+ 999999900, 999999990 };
+
+#ifdef HAVE_purify
+#define sanity(d) DBUG_ASSERT((d)->len > 0)
+#else
+#define sanity(d) DBUG_ASSERT((d)->len >0 && ((d)->buf[0] | \
+ (d)->buf[(d)->len-1] | 1))
+#endif
+
+#define FIX_INTG_FRAC_ERROR(len, intg1, frac1, error) \
+ do \
+ { \
+ if (unlikely(intg1+frac1 > (len))) \
+ { \
+ if (unlikely(intg1 > (len))) \
+ { \
+ intg1=(len); \
+ frac1=0; \
+ error=E_DEC_OVERFLOW; \
+ } \
+ else \
+ { \
+ frac1=(len)-intg1; \
+ error=E_DEC_TRUNCATED; \
+ } \
+ } \
+ else \
+ error=E_DEC_OK; \
+ } while(0)
+
+#define ADD(to, from1, from2, carry) /* assume carry <= 1 */ \
+ do \
+ { \
+ dec1 a=(from1)+(from2)+(carry); \
+ if (((carry)= a >= DIG_BASE)) /* no division here! */ \
+ a-=DIG_BASE; \
+ (to)=a; \
+ } while(0)
+
+#define ADD2(to, from1, from2, carry) \
+ do \
+ { \
+ dec1 a=(from1)+(from2)+(carry); \
+ if (((carry)= a >= DIG_BASE)) \
+ a-=DIG_BASE; \
+ if (unlikely(a >= DIG_BASE)) \
+ { \
+ a-=DIG_BASE; \
+ carry++; \
+ } \
+ (to)=a; \
+ } while(0)
+
+#define SUB(to, from1, from2, carry) /* to=from1-from2 */ \
+ do \
+ { \
+ dec1 a=(from1)-(from2)-(carry); \
+ if (((carry)= a < 0)) \
+ a+=DIG_BASE; \
+ (to)=a; \
+ } while(0)
+
+#define SUB2(to, from1, from2, carry) /* to=from1-from2 */ \
+ do \
+ { \
+ dec1 a=(from1)-(from2)-(carry); \
+ if (((carry)= a < 0)) \
+ a+=DIG_BASE; \
+ if (unlikely(a < 0)) \
+ { \
+ a+=DIG_BASE; \
+ carry++; \
+ } \
+ (to)=a; \
+ } while(0)
+
+/*
+ Get maximum value for given precision and scale
+
+ SYNOPSIS
+ max_decimal()
+ precision/scale - see decimal_bin_size() below
+ to - decimal where where the result will be stored
+ to->buf and to->len must be set.
+*/
+
+void max_decimal(int precision, int frac, decimal_t *to)
+{
+ int intpart;
+ dec1 *buf= to->buf;
+ DBUG_ASSERT(precision && precision >= frac);
+
+ to->sign= 0;
+ if ((intpart= to->intg= (precision - frac)))
+ {
+ int firstdigits= intpart % DIG_PER_DEC1;
+ if (firstdigits)
+ *buf++= powers10[firstdigits] - 1; /* get 9 99 999 ... */
+ for(intpart/= DIG_PER_DEC1; intpart; intpart--)
+ *buf++= DIG_MAX;
+ }
+
+ if ((to->frac= frac))
+ {
+ int lastdigits= frac % DIG_PER_DEC1;
+ for(frac/= DIG_PER_DEC1; frac; frac--)
+ *buf++= DIG_MAX;
+ if (lastdigits)
+ *buf= frac_max[lastdigits - 1];
+ }
+}
+
+
+static dec1 *remove_leading_zeroes(decimal_t *from, int *intg_result)
+{
+ int intg= from->intg, i;
+ dec1 *buf0= from->buf;
+ i= ((intg - 1) % DIG_PER_DEC1) + 1;
+ while (intg > 0 && *buf0 == 0)
+ {
+ intg-= i;
+ i= DIG_PER_DEC1;
+ buf0++;
+ }
+ if (intg > 0)
+ {
+ for (i= (intg - 1) % DIG_PER_DEC1; *buf0 < powers10[i--]; intg--) ;
+ DBUG_ASSERT(intg > 0);
+ }
+ else
+ intg=0;
+ *intg_result= intg;
+ return buf0;
+}
+
+
+/*
+ Remove ending 0 digits from fraction part
+
+ SYNOPSIS
+ decimal_optimize_fraction()
+ from number for processing
+*/
+
+void decimal_optimize_fraction(decimal_t *from)
+{
+ int frac= from->frac, i;
+ dec1 *buf0= from->buf + ROUND_UP(from->intg) + ROUND_UP(frac) - 1;
+
+ if (frac == 0)
+ return;
+
+ i= ((frac - 1) % DIG_PER_DEC1 + 1);
+ while (frac > 0 && *buf0 == 0)
+ {
+ frac-= i;
+ i= DIG_PER_DEC1;
+ buf0--;
+ }
+ if (frac > 0)
+ {
+ for (i= DIG_PER_DEC1 - ((frac - 1) % DIG_PER_DEC1);
+ *buf0 % powers10[i++] == 0;
+ frac--);
+ }
+ from->frac= frac;
+}
+
+
+/*
+ Convert decimal to its printable string representation
+
+ SYNOPSIS
+ decimal2string()
+ from - value to convert
+ to - points to buffer where string representation
+ should be stored
+ *to_len - in: size of to buffer
+ out: length of the actually written string
+ fixed_precision - 0 if representation can be variable length and
+ fixed_decimals will not be checked in this case.
+ Put number as with fixed point position with this
+ number of digits (sign counted and decimal point is
+ counted)
+ fixed_decimals - number digits after point.
+ filler - character to fill gaps in case of fixed_precision > 0
+
+ RETURN VALUE
+ E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
+*/
+
+int decimal2string(decimal_t *from, char *to, int *to_len,
+ int fixed_precision, int fixed_decimals,
+ char filler)
+{
+ int len, intg, frac=from->frac, i, intg_len, frac_len, fill;
+ /* number digits before decimal point */
+ int fixed_intg= (fixed_precision ?
+ (fixed_precision -
+ (from->sign ? 1 : 0) -
+ (fixed_decimals ? 1 : 0) -
+ fixed_decimals) :
+ 0);
+ int error=E_DEC_OK;
+ char *s=to;
+ dec1 *buf, *buf0=from->buf, tmp;
+
+ DBUG_ASSERT(*to_len >= 2+from->sign);
+ DBUG_ASSERT(fixed_precision == 0 ||
+ (fixed_precision < *to_len &&
+ fixed_precision > ((from->sign ? 1 : 0) +
+ (fixed_decimals ? 1 : 0))));
+
+ /* removing leading zeroes */
+ buf0= remove_leading_zeroes(from, &intg);
+ if (unlikely(intg+frac==0))
+ {
+ intg=1;
+ tmp=0;
+ buf0=&tmp;
+ }
+
+ intg_len= fixed_precision ? fixed_intg : (intg ? intg : 1);
+ frac_len= fixed_precision ? fixed_decimals : frac;
+ len= from->sign + intg_len + test(frac) + frac_len;
+ if (fixed_precision)
+ {
+ if (frac > fixed_decimals)
+ {
+ error= E_DEC_TRUNCATED;
+ frac= fixed_decimals;
+ }
+ if (intg > fixed_intg)
+ {
+ error= E_DEC_OVERFLOW;
+ intg= fixed_intg;
+ }
+ }
+ else if (unlikely(len > --*to_len)) /* reserve one byte for \0 */
+ {
+ int i=len-*to_len;
+ error= (frac && i <= frac + 1) ? E_DEC_TRUNCATED : E_DEC_OVERFLOW;
+ if (frac && i >= frac + 1) i--;
+ if (i > frac)
+ {
+ intg-= i-frac;
+ frac= 0;
+ }
+ else
+ frac-=i;
+ len= from->sign + intg_len + test(frac) + frac_len;
+ }
+ *to_len=len;
+ s[len]=0;
+
+ if (from->sign)
+ *s++='-';
+
+ if (frac)
+ {
+ char *s1= s + intg_len;
+ fill= frac_len - frac;
+ buf=buf0+ROUND_UP(intg);
+ *s1++='.';
+ for (; frac>0; frac-=DIG_PER_DEC1)
+ {
+ dec1 x=*buf++;
+ for (i=min(frac, DIG_PER_DEC1); i; i--)
+ {
+ dec1 y=x/DIG_MASK;
+ *s1++='0'+(uchar)y;
+ x-=y*DIG_MASK;
+ x*=10;
+ }
+ }
+ for(; fill; fill--)
+ *s1++=filler;
+ }
+
+ fill= intg_len - intg;
+ if (intg == 0)
+ fill--; /* symbol 0 before digital point */
+ for(; fill; fill--)
+ *s++=filler;
+ if (intg)
+ {
+ s+=intg;
+ for (buf=buf0+ROUND_UP(intg); intg>0; intg-=DIG_PER_DEC1)
+ {
+ dec1 x=*--buf;
+ for (i=min(intg, DIG_PER_DEC1); i; i--)
+ {
+ dec1 y=x/10;
+ *--s='0'+(uchar)(x-y*10);
+ x=y;
+ }
+ }
+ }
+ else
+ *s= '0';
+ return error;
+}
+
+
+/*
+ Return bounds of decimal digits in the number
+
+ SYNOPSIS
+ digits_bounds()
+ from - decimal number for processing
+ start_result - index (from 0 ) of first decimal digits will
+ be written by this address
+ end_result - index of position just after last decimal digit
+ be written by this address
+*/
+
+static void digits_bounds(decimal_t *from, int *start_result, int *end_result)
+{
+ int start, stop, i;
+ dec1 *buf_beg= from->buf;
+ dec1 *end= from->buf + ROUND_UP(from->intg) + ROUND_UP(from->frac);
+ dec1 *buf_end= end - 1;
+
+ /* find non-zero digit from number begining */
+ while (buf_beg < end && *buf_beg == 0)
+ buf_beg++;
+
+ if (buf_beg >= end)
+ {
+ /* it is zero */
+ *start_result= *end_result= 0;
+ return;
+ }
+
+ /* find non-zero decimal digit from number begining */
+ if (buf_beg == from->buf && from->intg)
+ {
+ start= DIG_PER_DEC1 - (i= ((from->intg-1) % DIG_PER_DEC1 + 1));
+ i--;
+ }
+ else
+ {
+ i= DIG_PER_DEC1 - 1;
+ start= (buf_beg - from->buf) * DIG_PER_DEC1;
+ }
+ if (buf_beg < end)
+ for (; *buf_beg < powers10[i--]; start++) ;
+ *start_result= start; /* index of first decimal digit (from 0) */
+
+ /* find non-zero digit at the end */
+ while (buf_end > buf_beg && *buf_end == 0)
+ buf_end--;
+ /* find non-zero decimal digit from the end */
+ if (buf_end == end - 1 && from->frac)
+ {
+ stop= ((buf_end - from->buf) * DIG_PER_DEC1 +
+ (i= ((from->frac - 1) % DIG_PER_DEC1 + 1)));
+ i= DIG_PER_DEC1 - i + 1;
+ }
+ else
+ {
+ stop= (buf_end - from->buf + 1) * DIG_PER_DEC1;
+ i= 1;
+ }
+ for (; *buf_end % powers10[i++] == 0; stop--);
+ *end_result= stop; /* index of position after last decimal digit (from 0) */
+}
+
+
+/*
+ Left shift for alignment of data in buffer
+
+ SYNOPSIS
+ do_mini_left_shift()
+ dec pointer to decimal number which have to be shifted
+ shift number of decimal digits on which it should be shifted
+ beg/end bounds of decimal digits (see digits_bounds())
+
+ NOTE
+ Result fitting in the buffer should be garanted.
+ 'shift' have to be from 1 to DIG_PER_DEC1-1 (inclusive)
+*/
+
+void do_mini_left_shift(decimal_t *dec, int shift, int beg, int last)
+{
+ dec1 *from= dec->buf + ROUND_UP(beg + 1) - 1;
+ dec1 *end= dec->buf + ROUND_UP(last) - 1;
+ int c_shift= DIG_PER_DEC1 - shift;
+ DBUG_ASSERT(from >= dec->buf);
+ DBUG_ASSERT(end < dec->buf + dec->len);
+ if (beg % DIG_PER_DEC1 < shift)
+ *(from - 1)= (*from) / powers10[c_shift];
+ for(; from < end; from++)
+ *from= ((*from % powers10[c_shift]) * powers10[shift] +
+ (*(from + 1)) / powers10[c_shift]);
+ *from= (*from % powers10[c_shift]) * powers10[shift];
+}
+
+
+/*
+ Right shift for alignment of data in buffer
+
+ SYNOPSIS
+ do_mini_left_shift()
+ dec pointer to decimal number which have to be shifted
+ shift number of decimal digits on which it should be shifted
+ beg/end bounds of decimal digits (see digits_bounds())
+
+ NOTE
+ Result fitting in the buffer should be garanted.
+ 'shift' have to be from 1 to DIG_PER_DEC1-1 (inclusive)
+*/
+
+void do_mini_right_shift(decimal_t *dec, int shift, int beg, int last)
+{
+ dec1 *from= dec->buf + ROUND_UP(last) - 1;
+ dec1 *end= dec->buf + ROUND_UP(beg + 1) - 1;
+ int c_shift= DIG_PER_DEC1 - shift;
+ DBUG_ASSERT(from < dec->buf + dec->len);
+ DBUG_ASSERT(end >= dec->buf);
+ if (DIG_PER_DEC1 - ((last - 1) % DIG_PER_DEC1 + 1) < shift)
+ *(from + 1)= (*from % powers10[shift]) * powers10[c_shift];
+ for(; from > end; from--)
+ *from= (*from / powers10[shift] +
+ (*(from - 1) % powers10[shift]) * powers10[c_shift]);
+ *from= *from / powers10[shift];
+}
+
+
+/*
+ Shift of decimal digits in given number (with rounding if it need)
+
+ SYNOPSIS
+ decimal_shift()
+ dec number to be shifted
+ shift number of decimal positions
+ shift > 0 means shift to left shift
+ shift < 0 meand right shift
+ NOTE
+ In fact it is multipling on 10^shift.
+ RETURN
+ E_DEC_OK OK
+ E_DEC_OVERFLOW operation lead to overflow, number is untoched
+ E_DEC_TRUNCATED number was rounded to fit into buffer
+*/
+
+int decimal_shift(decimal_t *dec, int shift)
+{
+ /* index of first non zero digit (all indexes from 0) */
+ int beg;
+ /* index of position after last decimal digit */
+ int end;
+ /* index of digit position just after point */
+ int point= ROUND_UP(dec->intg) * DIG_PER_DEC1;
+ /* new point position */
+ int new_point= point + shift;
+ /* number of digits in result */
+ int digits_int, digits_frac;
+ /* length of result and new fraction in big digits*/
+ int new_len, new_frac_len;
+ /* return code */
+ int err= E_DEC_OK;
+ int new_front;
+
+ if (shift == 0)
+ return E_DEC_OK;
+
+ digits_bounds(dec, &beg, &end);
+
+ if (beg == end)
+ {
+ decimal_make_zero(dec);
+ return E_DEC_OK;
+ }
+
+ digits_int= new_point - beg;
+ set_if_bigger(digits_int, 0);
+ digits_frac= end - new_point;
+ set_if_bigger(digits_frac, 0);
+
+ if ((new_len= ROUND_UP(digits_int) + (new_frac_len= ROUND_UP(digits_frac))) >
+ dec->len)
+ {
+ int lack= new_len - dec->len;
+ int diff;
+
+ if (new_frac_len < lack)
+ return E_DEC_OVERFLOW; /* lack more then we have in fraction */
+
+ /* cat off fraction part to allow new number to fit in our buffer */
+ err= E_DEC_TRUNCATED;
+ new_frac_len-= lack;
+ diff= digits_frac - (new_frac_len * DIG_PER_DEC1);
+ /* Make rounding method as parameter? */
+ decimal_round(dec, dec, end - point - diff, HALF_UP);
+ end-= diff;
+ digits_frac= new_frac_len * DIG_PER_DEC1;
+
+ if (end <= beg)
+ {
+ /*
+ we lost all digits (they will be shifted out of buffer), so we can
+ just return 0
+ */
+ decimal_make_zero(dec);
+ return E_DEC_TRUNCATED;
+ }
+ }
+
+ if (shift % DIG_PER_DEC1)
+ {
+ int l_mini_shift, r_mini_shift, mini_shift;
+ int do_left;
+ /*
+ Calculate left/right shift to align decimal digits inside our bug
+ digits correctly
+ */
+ if (shift > 0)
+ {
+ l_mini_shift= shift % DIG_PER_DEC1;
+ r_mini_shift= DIG_PER_DEC1 - l_mini_shift;
+ /*
+ It is left shift so prefer left shift, but if we have not place from
+ left, we have to have it from right, because we checked length of
+ result
+ */
+ do_left= l_mini_shift <= beg;
+ DBUG_ASSERT(do_left || (dec->len * DIG_PER_DEC1 - end) >= r_mini_shift);
+ }
+ else
+ {
+ r_mini_shift= (-shift) % DIG_PER_DEC1;
+ l_mini_shift= DIG_PER_DEC1 - r_mini_shift;
+ /* see comment above */
+ do_left= !((dec->len * DIG_PER_DEC1 - end) >= r_mini_shift);
+ DBUG_ASSERT(!do_left || l_mini_shift <= beg);
+ }
+ if (do_left)
+ {
+ do_mini_left_shift(dec, l_mini_shift, beg, end);
+ mini_shift=- l_mini_shift;
+ }
+ else
+ {
+ do_mini_right_shift(dec, r_mini_shift, beg, end);
+ mini_shift= r_mini_shift;
+ }
+ new_point+= mini_shift;
+ /*
+ If number is shifted and correctly aligned in buffer we can
+ finish
+ */
+ if (!(shift+= mini_shift) && (new_point - digits_int) < DIG_PER_DEC1)
+ {
+ dec->intg= digits_int;
+ dec->frac= digits_frac;
+ return err; /* already shifted as it should be */
+ }
+ beg+= mini_shift;
+ end+= mini_shift;
+ }
+
+ /* if new 'decimal front' is in first digit, we do not need move digits */
+ if ((new_front= (new_point - digits_int)) >= DIG_PER_DEC1 ||
+ new_front < 0)
+ {
+ /* need to move digits */
+ int d_shift;
+ dec1 *to, *barier;
+ if (new_front > 0)
+ {
+ /* move left */
+ d_shift= new_front / DIG_PER_DEC1;
+ to= dec->buf + (ROUND_UP(beg + 1) - 1 - d_shift);
+ barier= dec->buf + (ROUND_UP(end) - 1 - d_shift);
+ DBUG_ASSERT(to >= dec->buf);
+ DBUG_ASSERT(barier + d_shift < dec->buf + dec->len);
+ for(; to <= barier; to++)
+ *to= *(to + d_shift);
+ for(barier+= d_shift; to <= barier; to++)
+ *to= 0;
+ d_shift= -d_shift;
+ }
+ else
+ {
+ /* move right */
+ d_shift= (1 - new_front) / DIG_PER_DEC1;
+ to= dec->buf + ROUND_UP(end) - 1 + d_shift;
+ barier= dec->buf + ROUND_UP(beg + 1) - 1 + d_shift;
+ DBUG_ASSERT(to < dec->buf + dec->len);
+ DBUG_ASSERT(barier - d_shift >= dec->buf);
+ for(; to >= barier; to--)
+ *to= *(to - d_shift);
+ for(barier-= d_shift; to >= barier; to--)
+ *to= 0;
+ }
+ d_shift*= DIG_PER_DEC1;
+ beg+= d_shift;
+ end+= d_shift;
+ new_point+= d_shift;
+ }
+
+ /*
+ If there are gaps then fill ren with 0.
+
+ Only one of following 'for' loops will work becouse beg <= end
+ */
+ 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;
+ dec->intg= digits_int;
+ dec->frac= digits_frac;
+ return err;
+}
+
+
+/*
+ Convert string to decimal
+
+ SYNOPSIS
+ internal_str2decl()
+ from - value to convert. Doesn't have to be \0 terminated!
+ to - decimal where where the result will be stored
+ to->buf and to->len must be set.
+ end - Pointer to pointer to end of string. Will on return be
+ set to the char after the last used character
+ fixed - use to->intg, to->frac as limits for input number
+
+ NOTE
+ to->intg and to->frac can be modified even when fixed=1
+ (but only decreased, in this case)
+
+ RETURN VALUE
+ E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_BAD_NUM/E_DEC_OOM
+ In case of E_DEC_FATAL_ERROR *to is set to decimal zero
+ (to make error handling easier)
+*/
+
+int
+internal_str2dec(const char *from, decimal_t *to, char **end, my_bool fixed)
+{
+ const char *s= from, *s1, *endp, *end_of_string= *end;
+ int i, intg, frac, error, intg1, frac1;
+ dec1 x,*buf;
+ sanity(to);
+
+ error= E_DEC_BAD_NUM; /* In case of bad number */
+ while (s < end_of_string && my_isspace(&my_charset_latin1, *s))
+ s++;
+ if (s == end_of_string)
+ goto fatal_error;
+
+ if ((to->sign= (*s == '-')))
+ s++;
+ else if (*s == '+')
+ s++;
+
+ s1=s;
+ while (s < end_of_string && my_isdigit(&my_charset_latin1, *s))
+ s++;
+ intg=s-s1;
+ if (s < end_of_string && *s=='.')
+ {
+ endp= s+1;
+ while (endp < end_of_string && my_isdigit(&my_charset_latin1, *endp))
+ endp++;
+ frac= endp - s - 1;
+ }
+ else
+ {
+ frac= 0;
+ endp= s;
+ }
+
+ *end= (char*) endp;
+
+ if (frac+intg == 0)
+ goto fatal_error;
+
+ error= 0;
+ if (fixed)
+ {
+ if (frac > to->frac)
+ {
+ error=E_DEC_TRUNCATED;
+ frac=to->frac;
+ }
+ if (intg > to->intg)
+ {
+ error=E_DEC_OVERFLOW;
+ intg=to->intg;
+ }
+ intg1=ROUND_UP(intg);
+ frac1=ROUND_UP(frac);
+ if (intg1+frac1 > to->len)
+ {
+ error= E_DEC_OOM;
+ goto fatal_error;
+ }
+ }
+ else
+ {
+ intg1=ROUND_UP(intg);
+ frac1=ROUND_UP(frac);
+ FIX_INTG_FRAC_ERROR(to->len, intg1, frac1, error);
+ if (unlikely(error))
+ {
+ frac=frac1*DIG_PER_DEC1;
+ if (error == E_DEC_OVERFLOW)
+ intg=intg1*DIG_PER_DEC1;
+ }
+ }
+ /* Error is guranteed to be set here */
+ to->intg=intg;
+ to->frac=frac;
+
+ buf=to->buf+intg1;
+ s1=s;
+
+ for (x=0, i=0; intg; intg--)
+ {
+ x+= (*--s - '0')*powers10[i];
+
+ if (unlikely(++i == DIG_PER_DEC1))
+ {
+ *--buf=x;
+ x=0;
+ i=0;
+ }
+ }
+ if (i)
+ *--buf=x;
+
+ buf=to->buf+intg1;
+ for (x=0, i=0; frac; frac--)
+ {
+ x= (*++s1 - '0') + x*10;
+
+ if (unlikely(++i == DIG_PER_DEC1))
+ {
+ *buf++=x;
+ x=0;
+ i=0;
+ }
+ }
+ if (i)
+ *buf=x*powers10[DIG_PER_DEC1-i];
+
+ /* Handle exponent */
+ if (endp+1 < end_of_string && (*endp == 'e' || *endp == 'E'))
+ {
+ int str_error;
+ longlong exp= my_strtoll10(endp+1, (char**) &end_of_string, &str_error);
+
+ if (end_of_string != endp +1) /* If at least one digit */
+ {
+ *end= (char*) end_of_string;
+ if (str_error > 0)
+ {
+ error= E_DEC_BAD_NUM;
+ goto fatal_error;
+ }
+ if (exp > INT_MAX/2 || (str_error == 0 && exp < 0))
+ {
+ error= E_DEC_OVERFLOW;
+ goto fatal_error;
+ }
+ if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW)
+ {
+ error= E_DEC_TRUNCATED;
+ goto fatal_error;
+ }
+ if (error != E_DEC_OVERFLOW)
+ error= decimal_shift(to, (int) exp);
+ }
+ }
+ return error;
+
+fatal_error:
+ decimal_make_zero(to);
+ return error;
+}
+
+
+/*
+ Convert decimal to double
+
+ SYNOPSIS
+ decimal2double()
+ from - value to convert
+ to - result will be stored there
+
+ RETURN VALUE
+ E_DEC_OK
+*/
+
+int decimal2double(decimal_t *from, double *to)
+{
+ double x=0, t=DIG_BASE;
+ int intg, frac;
+ dec1 *buf=from->buf;
+
+ for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1)
+ x=x*DIG_BASE + *buf++;
+ for (frac=from->frac; frac > 0; frac-=DIG_PER_DEC1, t*=DIG_BASE)
+ x+=*buf++/t;
+ *to=from->sign ? -x : x;
+ return E_DEC_OK;
+}
+
+/*
+ Convert double to decimal
+
+ SYNOPSIS
+ double2decimal()
+ from - value to convert
+ to - result will be stored there
+
+ RETURN VALUE
+ E_DEC_OK/E_DEC_OVERFLOW/E_DEC_TRUNCATED
+*/
+
+int double2decimal(double from, decimal_t *to)
+{
+ /* TODO: fix it, when we'll have dtoa */
+ char s[400], *end;
+ sprintf(s, "%f", from);
+ end= strend(s);
+ return string2decimal(s, to, &end);
+}
+
+static int ull2dec(ulonglong from, decimal_t *to)
+{
+ int intg1, error=E_DEC_OK;
+ ulonglong x=from;
+ dec1 *buf;
+
+ sanity(to);
+
+ for (intg1=1; from >= DIG_BASE; intg1++, from/=DIG_BASE);
+ if (unlikely(intg1 > to->len))
+ {
+ intg1=to->len;
+ error=E_DEC_OVERFLOW;
+ }
+ to->frac=0;
+ to->intg=intg1*DIG_PER_DEC1;
+
+ for (buf=to->buf+intg1; intg1; intg1--)
+ {
+ ulonglong y=x/DIG_BASE;
+ *--buf=(dec1)(x-y*DIG_BASE);
+ x=y;
+ }
+ return error;
+}
+
+int ulonglong2decimal(ulonglong from, decimal_t *to)
+{
+ to->sign=0;
+ return ull2dec(from, to);
+}
+
+int longlong2decimal(longlong from, decimal_t *to)
+{
+ if ((to->sign= from < 0))
+ return ull2dec(-from, to);
+ return ull2dec(from, to);
+}
+
+int decimal2ulonglong(decimal_t *from, ulonglong *to)
+{
+ dec1 *buf=from->buf;
+ ulonglong x=0;
+ int intg, frac;
+
+ if (from->sign)
+ {
+ *to=ULL(0);
+ return E_DEC_OVERFLOW;
+ }
+
+ for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1)
+ {
+ ulonglong y=x;
+ x=x*DIG_BASE + *buf++;
+ if (unlikely(y > (ULONGLONG_MAX/DIG_BASE) || x < y))
+ {
+ *to=y;
+ return E_DEC_OVERFLOW;
+ }
+ }
+ *to=x;
+ for (frac=from->frac; unlikely(frac > 0); frac-=DIG_PER_DEC1)
+ if (*buf++)
+ return E_DEC_TRUNCATED;
+ return E_DEC_OK;
+}
+
+int decimal2longlong(decimal_t *from, longlong *to)
+{
+ dec1 *buf=from->buf;
+ longlong x=0;
+ int intg, frac;
+
+ for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1)
+ {
+ longlong y=x;
+ /*
+ Attention: trick!
+ we're calculating -|from| instead of |from| here
+ because |LONGLONG_MIN| > LONGLONG_MAX
+ so we can convert -9223372036854775808 correctly
+ */
+ x=x*DIG_BASE - *buf++;
+ if (unlikely(y < (LONGLONG_MIN/DIG_BASE) || x > y))
+ {
+ *to= from->sign ? y : -y;
+ return E_DEC_OVERFLOW;
+ }
+ }
+ /* boundary case: 9223372036854775808 */
+ if (unlikely(from->sign==0 && x < 0 && -x < 0))
+ {
+ *to= -1-x;
+ return E_DEC_OVERFLOW;
+ }
+
+ *to=from->sign ? x : -x;
+ for (frac=from->frac; unlikely(frac > 0); frac-=DIG_PER_DEC1)
+ if (*buf++)
+ return E_DEC_TRUNCATED;
+ return E_DEC_OK;
+}
+
+/*
+ Convert decimal to its binary fixed-length representation
+ two representations of the same length can be compared with memcmp
+ with the correct -1/0/+1 result
+
+ SYNOPSIS
+ decimal2bin()
+ from - value to convert
+ to - points to buffer where string representation should be stored
+ precision/scale - see decimal_bin_size() below
+
+ NOTE
+ the buffer is assumed to be of the size decimal_bin_size(precision, scale)
+
+ RETURN VALUE
+ E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
+
+ DESCRIPTION
+ for storage decimal numbers are converted to the "binary" format.
+
+ This format has the following properties:
+ 1. length of the binary representation depends on the {precision, scale}
+ as provided by the caller and NOT on the intg/frac of the decimal to
+ convert.
+ 2. binary representations of the same {precision, scale} can be compared
+ with memcmp - with the same result as decimal_cmp() of the original
+ decimals (not taking into account possible precision loss during
+ conversion).
+
+ This binary format is as follows:
+ 1. First the number is converted to have a requested precision and scale.
+ 2. Every full DIG_PER_DEC1 digits of intg part are stored in 4 bytes
+ as is
+ 3. The first intg % DIG_PER_DEC1 digits are stored in the reduced
+ number of bytes (enough bytes to store this number of digits -
+ see dig2bytes)
+ 4. same for frac - full decimal_digit_t's are stored as is,
+ the last frac % DIG_PER_DEC1 digits - in the reduced number of bytes.
+ 5. If the number is negative - every byte is inversed.
+ 5. The very first bit of the resulting byte array is inverted (because
+ memcmp compares unsigned bytes, see property 2 above)
+
+ Example:
+
+ 1234567890.1234
+
+ internally is represented as 3 decimal_digit_t's
+
+ 1 234567890 123400000
+
+ (assuming we want a binary representation with precision=14, scale=4)
+ in hex it's
+
+ 00-00-00-01 0D-FB-38-D2 07-5A-EF-40
+
+ now, middle decimal_digit_t is full - it stores 9 decimal digits. It goes
+ into binary representation as is:
+
+
+ ........... 0D-FB-38-D2 ............
+
+ First decimal_digit_t has only one decimal digit. We can store one digit in
+ one byte, no need to waste four:
+
+ 01 0D-FB-38-D2 ............
+
+ now, last digit. It's 123400000. We can store 1234 in two bytes:
+
+ 01 0D-FB-38-D2 04-D2
+
+ So, we've packed 12 bytes number in 7 bytes.
+ And now we invert the highest bit to get the final result:
+
+ 81 0D FB 38 D2 04 D2
+
+ And for -1234567890.1234 it would be
+
+ 7E F2 04 37 2D FB 2D
+*/
+int decimal2bin(decimal_t *from, char *to, int precision, int frac)
+{
+ dec1 mask=from->sign ? -1 : 0, *buf1=from->buf, *stop1;
+ int error=E_DEC_OK, intg=precision-frac,
+ isize1, intg1, intg1x, from_intg,
+ intg0=intg/DIG_PER_DEC1,
+ frac0=frac/DIG_PER_DEC1,
+ intg0x=intg-intg0*DIG_PER_DEC1,
+ frac0x=frac-frac0*DIG_PER_DEC1,
+ frac1=from->frac/DIG_PER_DEC1,
+ frac1x=from->frac-frac1*DIG_PER_DEC1,
+ isize0=intg0*sizeof(dec1)+dig2bytes[intg0x],
+ fsize0=frac0*sizeof(dec1)+dig2bytes[frac0x],
+ fsize1=frac1*sizeof(dec1)+dig2bytes[frac1x];
+ char *orig_to= to;
+
+ buf1= remove_leading_zeroes(from, &from_intg);
+
+ if (unlikely(from_intg+fsize1==0))
+ {
+ mask=0; /* just in case */
+ intg=1;
+ buf1=&mask;
+ }
+
+ intg1=from_intg/DIG_PER_DEC1;
+ intg1x=from_intg-intg1*DIG_PER_DEC1;
+ isize1=intg1*sizeof(dec1)+dig2bytes[intg1x];
+
+ if (intg < from_intg)
+ {
+ buf1+=intg1-intg0+(intg1x>0)-(intg0x>0);
+ intg1=intg0; intg1x=intg0x;
+ error=E_DEC_OVERFLOW;
+ }
+ else if (isize0 > isize1)
+ {
+ while (isize0-- > isize1)
+ *to++= (char)mask;
+ }
+ if (fsize0 < fsize1)
+ {
+ frac1=frac0; frac1x=frac0x;
+ error=E_DEC_TRUNCATED;
+ }
+ else if (fsize0 > fsize1 && frac1x)
+ {
+ if (frac0 == frac1)
+ {
+ frac1x=frac0x;
+ fsize0= fsize1;
+ }
+ else
+ {
+ frac1++;
+ frac1x=0;
+ }
+ }
+
+ /* intg1x part */
+ if (intg1x)
+ {
+ int i=dig2bytes[intg1x];
+ dec1 x=(*buf1++ % powers10[intg1x]) ^ mask;
+ switch (i)
+ {
+ case 1: mi_int1store(to, x); break;
+ case 2: mi_int2store(to, x); break;
+ case 3: mi_int3store(to, x); break;
+ case 4: mi_int4store(to, x); break;
+ default: DBUG_ASSERT(0);
+ }
+ to+=i;
+ }
+
+ /* intg1+frac1 part */
+ for (stop1=buf1+intg1+frac1; buf1 < stop1; to+=sizeof(dec1))
+ {
+ dec1 x=*buf1++ ^ mask;
+ DBUG_ASSERT(sizeof(dec1) == 4);
+ mi_int4store(to, x);
+ }
+
+ /* frac1x part */
+ if (frac1x)
+ {
+ dec1 x;
+ int i=dig2bytes[frac1x],
+ lim=(frac1 < frac0 ? DIG_PER_DEC1 : frac0x);
+ while (frac1x < lim && dig2bytes[frac1x] == i)
+ frac1x++;
+ x=(*buf1 / powers10[DIG_PER_DEC1 - frac1x]) ^ mask;
+ switch (i)
+ {
+ case 1: mi_int1store(to, x); break;
+ case 2: mi_int2store(to, x); break;
+ case 3: mi_int3store(to, x); break;
+ case 4: mi_int4store(to, x); break;
+ default: DBUG_ASSERT(0);
+ }
+ to+=i;
+ }
+ if (fsize0 > fsize1)
+ {
+ while (fsize0-- > fsize1)
+ *to++=(uchar)mask;
+ }
+ orig_to[0]^= 0x80;
+ return error;
+}
+
+/*
+ Restores decimal from its binary fixed-length representation
+
+ SYNOPSIS
+ bin2decimal()
+ from - value to convert
+ to - result
+ precision/scale - see decimal_bin_size() below
+
+ NOTE
+ see decimal2bin()
+ the buffer is assumed to be of the size decimal_bin_size(precision, scale)
+
+ RETURN VALUE
+ E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
+*/
+
+int bin2decimal(char *from, decimal_t *to, int precision, int scale)
+{
+ int error=E_DEC_OK, intg=precision-scale,
+ intg0=intg/DIG_PER_DEC1, frac0=scale/DIG_PER_DEC1,
+ intg0x=intg-intg0*DIG_PER_DEC1, frac0x=scale-frac0*DIG_PER_DEC1,
+ intg1=intg0+(intg0x>0), frac1=frac0+(frac0x>0);
+ dec1 *buf=to->buf, mask=(*from & 0x80) ? 0 : -1;
+ char *stop;
+ char *d_copy;
+ int bin_size= decimal_bin_size(precision, scale);
+
+ sanity(to);
+ d_copy= (char *)my_alloca(bin_size);
+ memcpy(d_copy, from, bin_size);
+ d_copy[0]^= 0x80;
+ from= d_copy;
+
+ FIX_INTG_FRAC_ERROR(to->len, intg1, frac1, error);
+ if (unlikely(error))
+ {
+ if (intg1 < intg0+(intg0x>0))
+ {
+ from+=dig2bytes[intg0x]+sizeof(dec1)*(intg0-intg1);
+ frac0=frac0x=intg0x=0;
+ intg0=intg1;
+ }
+ else
+ {
+ frac0x=0;
+ frac0=frac1;
+ }
+ }
+
+ to->sign=(mask != 0);
+ to->intg=intg0*DIG_PER_DEC1+intg0x;
+ to->frac=frac0*DIG_PER_DEC1+frac0x;
+
+ if (intg0x)
+ {
+ int i=dig2bytes[intg0x];
+ dec1 x;
+ switch (i)
+ {
+ case 1: x=mi_sint1korr(from); break;
+ case 2: x=mi_sint2korr(from); break;
+ case 3: x=mi_sint3korr(from); break;
+ case 4: x=mi_sint4korr(from); break;
+ default: DBUG_ASSERT(0);
+ }
+ from+=i;
+ *buf=x ^ mask;
+ if (buf > to->buf || *buf != 0)
+ buf++;
+ else
+ to->intg-=intg0x;
+ }
+ for (stop=from+intg0*sizeof(dec1); from < stop; from+=sizeof(dec1))
+ {
+ DBUG_ASSERT(sizeof(dec1) == 4);
+ *buf=mi_sint4korr(from) ^ mask;
+ if (buf > to->buf || *buf != 0)
+ buf++;
+ else
+ to->intg-=DIG_PER_DEC1;
+ }
+ DBUG_ASSERT(to->intg >=0);
+ for (stop=from+frac0*sizeof(dec1); from < stop; from+=sizeof(dec1))
+ {
+ DBUG_ASSERT(sizeof(dec1) == 4);
+ *buf=mi_sint4korr(from) ^ mask;
+ buf++;
+ }
+ if (frac0x)
+ {
+ int i=dig2bytes[frac0x];
+ dec1 x;
+ switch (i)
+ {
+ case 1: x=mi_sint1korr(from); break;
+ case 2: x=mi_sint2korr(from); break;
+ case 3: x=mi_sint3korr(from); break;
+ case 4: x=mi_sint4korr(from); break;
+ default: DBUG_ASSERT(0);
+ }
+ *buf=(x ^ mask) * powers10[DIG_PER_DEC1 - frac0x];
+ buf++;
+ }
+ my_afree(d_copy);
+ return error;
+}
+
+/*
+ Returns the size of array to hold a decimal with given precision and scale
+
+ RETURN VALUE
+ size in dec1
+ (multiply by sizeof(dec1) to get the size if bytes)
+*/
+
+int decimal_size(int precision, int scale)
+{
+ DBUG_ASSERT(scale >= 0 && precision > 0 && scale <= precision);
+ return ROUND_UP(precision-scale)+ROUND_UP(scale);
+}
+
+/*
+ Returns the size of array to hold a binary representation of a decimal
+
+ RETURN VALUE
+ size in bytes
+*/
+
+int decimal_bin_size(int precision, int scale)
+{
+ int intg=precision-scale,
+ intg0=intg/DIG_PER_DEC1, frac0=scale/DIG_PER_DEC1,
+ intg0x=intg-intg0*DIG_PER_DEC1, frac0x=scale-frac0*DIG_PER_DEC1;
+
+ DBUG_ASSERT(scale >= 0 && precision > 0 && scale <= precision);
+ return intg0*sizeof(dec1)+dig2bytes[intg0x]+
+ frac0*sizeof(dec1)+dig2bytes[frac0x];
+}
+
+/*
+ Rounds the decimal to "scale" digits
+
+ SYNOPSIS
+ decimal_round()
+ from - decimal to round,
+ to - result buffer. from==to is allowed
+ scale - to what position to round. can be negative!
+ mode - round to nearest even or truncate
+
+ NOTES
+ scale can be negative !
+ one TRUNCATED error (line XXX below) isn't treated very logical :(
+
+ RETURN VALUE
+ E_DEC_OK/E_DEC_TRUNCATED
+*/
+
+int
+decimal_round(decimal_t *from, decimal_t *to, int scale,
+ decimal_round_mode mode)
+{
+ int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1,
+ frac1=ROUND_UP(from->frac), round_digit,
+ intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len,
+ intg1=ROUND_UP(from->intg +
+ (((intg0 + frac0)>0) && (from->buf[0] == DIG_MAX)));
+ dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0;
+
+ sanity(to);
+
+ switch (mode) {
+ case HALF_UP:
+ case HALF_EVEN: round_digit=5; break;
+ case CEILING: round_digit= from->sign ? 10 : 0; break;
+ case FLOOR: round_digit= from->sign ? 0 : 10; break;
+ case TRUNCATE: round_digit=10; break;
+ default: DBUG_ASSERT(0);
+ }
+
+ if (unlikely(frac0+intg0 > len))
+ {
+ frac0=len-intg0;
+ scale=frac0*DIG_PER_DEC1;
+ error=E_DEC_TRUNCATED;
+ }
+
+ if (scale+from->intg < 0)
+ {
+ decimal_make_zero(to);
+ return E_DEC_OK;
+ }
+
+ if (to != from || intg1>intg0)
+ {
+ dec1 *p0= buf0+intg0+max(frac1, frac0);
+ dec1 *p1= buf1+intg1+max(frac1, frac0);
+
+ to->buf[0]= 0;
+ while (buf0 < p0)
+ *(--p1) = *(--p0);
+
+ intg0= intg1;
+ buf0=to->buf;
+ buf1=to->buf;
+ to->sign=from->sign;
+ to->intg=min(intg0, len)*DIG_PER_DEC1;
+ }
+
+ if (frac0 > frac1)
+ {
+ buf1+=intg0+frac1;
+ while (frac0-- > frac1)
+ *buf1++=0;
+ goto done;
+ }
+
+ if (scale >= from->frac)
+ goto done; /* nothing to do */
+
+ buf0+=intg0+frac0-1;
+ buf1+=intg0+frac0-1;
+ if (scale == frac0*DIG_PER_DEC1)
+ {
+ DBUG_ASSERT(frac0+intg0 >= 0);
+ x=buf0[1]/DIG_MASK;
+ if (x > round_digit ||
+ (round_digit == 5 && x == 5 && (mode == HALF_UP ||
+ (frac0+intg0 > 0 && *buf0 & 1))))
+ {
+ if (frac0+intg0>0)
+ (*buf1)++;
+ else
+ *(++buf1)=DIG_BASE;
+ }
+ else if (frac0+intg0==0)
+ {
+ decimal_make_zero(to);
+ return E_DEC_OK;
+ }
+ }
+ else
+ {
+ int pos=frac0*DIG_PER_DEC1-scale-1;
+ DBUG_ASSERT(frac0+intg0 > 0);
+ x=*buf1 / powers10[pos];
+ y=x % 10;
+ if (y > round_digit ||
+ (round_digit == 5 && y == 5 && (mode == HALF_UP || (x/10) & 1)))
+ x+=10;
+ *buf1=powers10[pos]*(x-y);
+ }
+ if (frac0 < 0)
+ {
+ dec1 *end=to->buf+intg0, *buf=buf1+1;
+ while (buf < end)
+ *buf++=0;
+ }
+ if (*buf1 >= DIG_BASE)
+ {
+ carry=1;
+ *buf1-=DIG_BASE;
+ while (carry && --buf1 >= to->buf)
+ ADD(*buf1, *buf1, 0, carry);
+ if (unlikely(carry))
+ {
+ /* shifting the number to create space for new digit */
+ if (frac0+intg0 >= len)
+ {
+ frac0--;
+ scale=frac0*DIG_PER_DEC1;
+ error=E_DEC_TRUNCATED; /* XXX */
+ }
+ for (buf1=to->buf+intg0+max(frac0,0); buf1 > to->buf; buf1--)
+ {
+ buf1[0]=buf1[-1];
+ }
+ *buf1=1;
+ to->intg++;
+ }
+ }
+ else
+ {
+ while (unlikely(*buf1 == 0) && buf1 >= to->buf)
+ buf1--;
+ if (buf1 < to->buf)
+ {
+ decimal_make_zero(to);
+ return E_DEC_OK;
+ }
+ }
+ if (scale<0) scale=0;
+
+done:
+ to->frac=scale;
+ return error;
+}
+
+/*
+ Returns the size of the result of the operation
+
+ SYNOPSIS
+ decimal_result_size()
+ from1 - operand of the unary operation or first operand of the
+ binary operation
+ from2 - second operand of the binary operation
+ op - operation. one char '+', '-', '*', '/' are allowed
+ others may be added later
+ param - extra param to the operation. unused for '+', '-', '*'
+ scale increment for '/'
+
+ NOTE
+ returned valued may be larger than the actual buffer requred
+ in the operation, as decimal_result_size, by design, operates on
+ precision/scale values only and not on the actual decimal number
+
+ RETURN VALUE
+ size of to->buf array in dec1 elements. to get size in bytes
+ multiply by sizeof(dec1)
+*/
+
+int decimal_result_size(decimal_t *from1, decimal_t *from2, char op, int param)
+{
+ switch (op) {
+ case '-':
+ return ROUND_UP(max(from1->intg, from2->intg)) +
+ ROUND_UP(max(from1->frac, from2->frac));
+ case '+':
+ return ROUND_UP(max(from1->intg, from2->intg)+1) +
+ ROUND_UP(max(from1->frac, from2->frac));
+ case '*':
+ return ROUND_UP(from1->intg+from2->intg)+
+ ROUND_UP(from1->frac)+ROUND_UP(from2->frac);
+ case '/':
+ return ROUND_UP(from1->intg+from2->intg+1+from1->frac+from2->frac+param);
+ default: DBUG_ASSERT(0);
+ }
+ return -1; /* shut up the warning */
+}
+
+static int do_add(decimal_t *from1, decimal_t *from2, decimal_t *to)
+{
+ int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
+ frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac),
+ frac0=max(frac1, frac2), intg0=max(intg1, intg2), error;
+ dec1 *buf1, *buf2, *buf0, *stop, *stop2, x, carry;
+
+ sanity(to);
+
+ /* is there a need for extra word because of carry ? */
+ x=intg1 > intg2 ? from1->buf[0] :
+ intg2 > intg1 ? from2->buf[0] :
+ from1->buf[0] + from2->buf[0] ;
+ if (unlikely(x > DIG_MASK*9)) /* yes, there is */
+ {
+ intg0++;
+ to->buf[0]=0; /* safety */
+ }
+
+ FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error);
+ buf0=to->buf+intg0+frac0;
+
+ to->sign=from1->sign;
+ to->frac=max(from1->frac, from2->frac);
+ to->intg=intg0*DIG_PER_DEC1;
+ if (unlikely(error))
+ {
+ set_if_smaller(to->frac, frac0*DIG_PER_DEC1);
+ set_if_smaller(frac1, frac0);
+ set_if_smaller(frac2, frac0);
+ set_if_smaller(intg1, intg0);
+ set_if_smaller(intg2, intg0);
+ }
+
+ /* part 1 - max(frac) ... min (frac) */
+ if (frac1 > frac2)
+ {
+ buf1=from1->buf+intg1+frac1;
+ stop=from1->buf+intg1+frac2;
+ buf2=from2->buf+intg2+frac2;
+ stop2=from1->buf+(intg1 > intg2 ? intg1-intg2 : 0);
+ }
+ else
+ {
+ buf1=from2->buf+intg2+frac2;
+ stop=from2->buf+intg2+frac1;
+ buf2=from1->buf+intg1+frac1;
+ stop2=from2->buf+(intg2 > intg1 ? intg2-intg1 : 0);
+ }
+ while (buf1 > stop)
+ *--buf0=*--buf1;
+
+ /* part 2 - min(frac) ... min(intg) */
+ carry=0;
+ while (buf1 > stop2)
+ {
+ ADD(*--buf0, *--buf1, *--buf2, carry);
+ }
+
+ /* part 3 - min(intg) ... max(intg) */
+ buf1= intg1 > intg2 ? ((stop=from1->buf)+intg1-intg2) :
+ ((stop=from2->buf)+intg2-intg1) ;
+ while (buf1 > stop)
+ {
+ ADD(*--buf0, *--buf1, 0, carry);
+ }
+
+ if (unlikely(carry))
+ *--buf0=1;
+ DBUG_ASSERT(buf0 == to->buf || buf0 == to->buf+1);
+
+ return error;
+}
+
+/* to=from1-from2.
+ if to==0, return -1/0/+1 - the result of the comparison */
+static int do_sub(decimal_t *from1, decimal_t *from2, decimal_t *to)
+{
+ int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
+ frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac);
+ int frac0=max(frac1, frac2), error;
+ dec1 *buf1, *buf2, *buf0, *stop1, *stop2, *start1, *start2, carry=0;
+
+ /* let carry:=1 if from2 > from1 */
+ start1=buf1=from1->buf; stop1=buf1+intg1;
+ start2=buf2=from2->buf; stop2=buf2+intg2;
+ if (unlikely(*buf1 == 0))
+ {
+ while (buf1 < stop1 && *buf1 == 0)
+ buf1++;
+ start1=buf1;
+ intg1=stop1-buf1;
+ }
+ if (unlikely(*buf2 == 0))
+ {
+ while (buf2 < stop2 && *buf2 == 0)
+ buf2++;
+ start2=buf2;
+ intg2=stop2-buf2;
+ }
+ if (intg2 > intg1)
+ carry=1;
+ else if (intg2 == intg1)
+ {
+ while (unlikely(stop1[frac1-1] == 0))
+ frac1--;
+ while (unlikely(stop2[frac2-1] == 0))
+ frac2--;
+ while (buf1 < stop1+frac1 && buf2 < stop2+frac2 && *buf1 == *buf2)
+ buf1++, buf2++;
+ if (buf1 < stop1+frac1)
+ if (buf2 < stop2+frac2)
+ carry= *buf2 > *buf1;
+ else
+ carry= 0;
+ else
+ if (buf2 < stop2+frac2)
+ carry=1;
+ else /* short-circuit everything: from1 == from2 */
+ {
+ if (to == 0) /* decimal_cmp() */
+ return 0;
+ decimal_make_zero(to);
+ return E_DEC_OK;
+ }
+ }
+
+ if (to == 0) /* decimal_cmp() */
+ return carry == from1->sign ? 1 : -1;
+
+ sanity(to);
+
+ to->sign=from1->sign;
+
+ /* ensure that always from1 > from2 (and intg1 >= intg2) */
+ if (carry)
+ {
+ swap_variables(decimal_t *,from1,from1);
+ swap_variables(dec1 *,start1, start2);
+ swap_variables(int,intg1,intg2);
+ swap_variables(int,frac1,frac2);
+ to->sign= 1 - to->sign;
+ }
+
+ FIX_INTG_FRAC_ERROR(to->len, intg1, frac0, error);
+ buf0=to->buf+intg1+frac0;
+
+ to->frac=max(from1->frac, from2->frac);
+ to->intg=intg1*DIG_PER_DEC1;
+ if (unlikely(error))
+ {
+ set_if_smaller(to->frac, frac0*DIG_PER_DEC1);
+ set_if_smaller(frac1, frac0);
+ set_if_smaller(frac2, frac0);
+ set_if_smaller(intg2, intg1);
+ }
+ carry=0;
+
+ /* part 1 - max(frac) ... min (frac) */
+ if (frac1 > frac2)
+ {
+ buf1=start1+intg1+frac1;
+ stop1=start1+intg1+frac2;
+ buf2=start2+intg2+frac2;
+ while (frac0-- > frac1)
+ *--buf0=0;
+ while (buf1 > stop1)
+ *--buf0=*--buf1;
+ }
+ else
+ {
+ buf1=start1+intg1+frac1;
+ buf2=start2+intg2+frac2;
+ stop2=start2+intg2+frac1;
+ while (frac0-- > frac2)
+ *--buf0=0;
+ while (buf2 > stop2)
+ {
+ SUB(*--buf0, 0, *--buf2, carry);
+ }
+ }
+
+ /* part 2 - min(frac) ... intg2 */
+ while (buf2 > start2)
+ {
+ SUB(*--buf0, *--buf1, *--buf2, carry);
+ }
+
+ /* part 3 - intg2 ... intg1 */
+ while (carry && buf1 > start1)
+ {
+ SUB(*--buf0, *--buf1, 0, carry);
+ }
+
+ while (buf1 > start1)
+ *--buf0=*--buf1;
+
+ while (buf0 > to->buf)
+ *--buf0=0;
+
+ return error;
+}
+
+int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to)
+{
+ if (likely(from1->sign == from2->sign))
+ return do_add(from1, from2, to);
+ return do_sub(from1, from2, to);
+}
+
+int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to)
+{
+ if (likely(from1->sign == from2->sign))
+ return do_sub(from1, from2, to);
+ return do_add(from1, from2, to);
+}
+
+int decimal_cmp(decimal_t *from1, decimal_t *from2)
+{
+ if (likely(from1->sign == from2->sign))
+ return do_sub(from1, from2, 0);
+ return from1->sign > from2->sign ? -1 : 1;
+}
+
+int decimal_is_zero(decimal_t *from)
+{
+ dec1 *buf1=from->buf,
+ *end=buf1+ROUND_UP(from->intg)+ROUND_UP(from->frac);
+ while (buf1 < end)
+ if (*buf1++)
+ return 0;
+ return 1;
+}
+
+/*
+ multiply two decimals
+
+ SYNOPSIS
+ decimal_mul()
+ from1, from2 - factors
+ to - product
+
+ RETURN VALUE
+ E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW;
+
+ NOTES
+ in this implementation, with sizeof(dec1)=4 we have DIG_PER_DEC1=9,
+ and 63-digit number will take only 7 dec1 words (basically a 7-digit
+ "base 999999999" number). Thus there's no need in fast multiplication
+ algorithms, 7-digit numbers can be multiplied with a naive O(n*n)
+ method.
+
+ XXX if this library is to be used with huge numbers of thousands of
+ digits, fast multiplication must be implemented.
+*/
+int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to)
+{
+ int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
+ frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac),
+ intg0=ROUND_UP(from1->intg+from2->intg),
+ frac0=frac1+frac2, error, i, j;
+ dec1 *buf1=from1->buf+intg1, *buf2=from2->buf+intg2, *buf0,
+ *start2, *stop2, *stop1, *start0, carry;
+
+ sanity(to);
+
+ i=intg0;
+ j=frac0;
+ FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error);
+ to->sign=from1->sign != from2->sign;
+ to->frac=from1->frac+from2->frac;
+ to->intg=intg0*DIG_PER_DEC1;
+
+ if (unlikely(error))
+ {
+ set_if_smaller(to->frac, frac0*DIG_PER_DEC1);
+ set_if_smaller(to->intg, intg0*DIG_PER_DEC1);
+ if (unlikely(i > intg0))
+ {
+ i-=intg0;
+ j=i >> 1;
+ intg1-= j;
+ intg2-=i-j;
+ frac1=frac2=0; /* frac0 is already 0 here */
+ }
+ else
+ {
+ j-=frac0;
+ i=j >> 1;
+ frac1-= i;
+ frac2-=j-i;
+ }
+ }
+ start0=to->buf+intg0+frac0-1;
+ start2=buf2+frac2-1;
+ stop1=buf1-intg1;
+ stop2=buf2-intg2;
+
+ bzero(to->buf, (intg0+frac0)*sizeof(dec1));
+
+ for (buf1+=frac1-1; buf1 >= stop1; buf1--, start0--)
+ {
+ carry=0;
+ for (buf0=start0, buf2=start2; buf2 >= stop2; buf2--, buf0--)
+ {
+ dec1 hi, lo;
+ dec2 p= ((dec2)*buf1) * ((dec2)*buf2);
+ hi=(dec1)(p/DIG_BASE);
+ lo=(dec1)(p-((dec2)hi)*DIG_BASE);
+ ADD2(*buf0, *buf0, lo, carry);
+ carry+=hi;
+ }
+ for (; carry; buf0--)
+ ADD(*buf0, *buf0, 0, carry);
+ }
+ return error;
+}
+
+/*
+ naive division algorithm (Knuth's Algorithm D in 4.3.1) -
+ it's ok for short numbers
+ also we're using alloca() to allocate a temporary buffer
+
+ XXX if this library is to be used with huge numbers of thousands of
+ digits, fast division must be implemented and alloca should be
+ changed to malloc (or at least fallback to malloc if alloca() fails)
+ but then, decimal_mul() should be rewritten too :(
+*/
+static int do_div_mod(decimal_t *from1, decimal_t *from2,
+ decimal_t *to, decimal_t *mod, int scale_incr)
+{
+ int frac1=ROUND_UP(from1->frac)*DIG_PER_DEC1, prec1=from1->intg+frac1,
+ frac2=ROUND_UP(from2->frac)*DIG_PER_DEC1, prec2=from2->intg+frac2,
+ error, i, intg0, frac0, len1, len2, dintg, div=(!mod);
+ dec1 *buf0, *buf1=from1->buf, *buf2=from2->buf, *tmp1,
+ *start2, *stop2, *stop1, *stop0, norm2, carry, *start1, dcarry;
+ dec2 norm_factor, x, guess, y;
+
+ LINT_INIT(error);
+
+ if (mod)
+ to=mod;
+
+ sanity(to);
+
+ /* removing all the leading zeroes */
+ i=((prec1-1) % DIG_PER_DEC1)+1;
+ while (prec1 > 0 && *buf1 == 0)
+ {
+ prec1-=i;
+ i=DIG_PER_DEC1;
+ buf1++;
+ }
+ if (prec1 <= 0)
+ { /* short-circuit everything: from1 == 0 */
+ decimal_make_zero(to);
+ return E_DEC_OK;
+ }
+ for (i=(prec1-1) % DIG_PER_DEC1; *buf1 < powers10[i--]; prec1--) ;
+ DBUG_ASSERT(prec1 > 0);
+
+ i=((prec2-1) % DIG_PER_DEC1)+1;
+ while (prec2 > 0 && *buf2 == 0)
+ {
+ prec2-=i;
+ i=DIG_PER_DEC1;
+ buf2++;
+ }
+ if (prec2 <= 0) /* short-circuit everything: from2 == 0 */
+ return E_DEC_DIV_ZERO;
+
+ for (i=(prec2-1) % DIG_PER_DEC1; *buf2 < powers10[i--]; prec2--) ;
+ DBUG_ASSERT(prec2 > 0);
+
+ /* let's fix scale_incr, taking into account frac1,frac2 increase */
+ if ((scale_incr-= frac1 - from1->frac + frac2 - from2->frac) < 0)
+ scale_incr=0;
+
+ dintg=(prec1-frac1)-(prec2-frac2)+(*buf1 >= *buf2);
+ if (dintg < 0)
+ {
+ dintg/=DIG_PER_DEC1;
+ intg0=0;
+ }
+ else
+ intg0=ROUND_UP(dintg);
+ if (mod)
+ {
+ /* we're calculating N1 % N2.
+ The result will have
+ frac=max(frac1, frac2), as for subtraction
+ intg=intg2
+ */
+ to->sign=from1->sign;
+ to->frac=max(from1->frac, from2->frac);
+ frac0=0;
+ }
+ else
+ {
+ /*
+ we're calculating N1/N2. N1 is in the buf1, has prec1 digits
+ N2 is in the buf2, has prec2 digits. Scales are frac1 and
+ frac2 accordingly.
+ Thus, the result will have
+ frac = ROUND_UP(frac1+frac2+scale_incr)
+ and
+ intg = (prec1-frac1) - (prec2-frac2) + 1
+ prec = intg+frac
+ */
+ frac0=ROUND_UP(frac1+frac2+scale_incr);
+ FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error);
+ to->sign=from1->sign != from2->sign;
+ to->intg=intg0*DIG_PER_DEC1;
+ to->frac=frac0*DIG_PER_DEC1;
+ }
+ buf0=to->buf;
+ stop0=buf0+intg0+frac0;
+ if (likely(div))
+ while (dintg++ < 0)
+ *buf0++=0;
+
+ len1=(i=ROUND_UP(prec1))+ROUND_UP(2*frac2+scale_incr+1) + 1;
+ set_if_bigger(len1, 3);
+ if (!(tmp1=(dec1 *)my_alloca(len1*sizeof(dec1))))
+ return E_DEC_OOM;
+ memcpy(tmp1, buf1, i*sizeof(dec1));
+ bzero(tmp1+i, (len1-i)*sizeof(dec1));
+
+ start1=tmp1;
+ stop1=start1+len1;
+ start2=buf2;
+ stop2=buf2+ROUND_UP(prec2)-1;
+
+ /* removing end zeroes */
+ while (*stop2 == 0 && stop2 >= start2)
+ stop2--;
+ len2= stop2++ - start2;
+
+ /*
+ calculating norm2 (normalized *start2) - we need *start2 to be large
+ (at least > DIG_BASE/2), but unlike Knuth's Alg. D we don't want to
+ normalize input numbers (as we don't make a copy of the divisor).
+ Thus we normalize first dec1 of buf2 only, and we'll normalize *start1
+ on the fly for the purpose of guesstimation only.
+ It's also faster, as we're saving on normalization of buf2
+ */
+ norm_factor=DIG_BASE/(*start2+1);
+ norm2=(dec1)(norm_factor*start2[0]);
+ if (likely(len2>0))
+ norm2+=(dec1)(norm_factor*start2[1]/DIG_BASE);
+
+ if (*start1 < *start2)
+ dcarry=*start1++;
+ else
+ dcarry=0;
+
+ /* main loop */
+ for (; buf0 < stop0; buf0++)
+ {
+ /* short-circuit, if possible */
+ if (unlikely(dcarry == 0 && *start1 < *start2))
+ guess=0;
+ else
+ {
+ /* D3: make a guess */
+ x=start1[0]+((dec2)dcarry)*DIG_BASE;
+ y=start1[1];
+ guess=(norm_factor*x+norm_factor*y/DIG_BASE)/norm2;
+ if (unlikely(guess >= DIG_BASE))
+ guess=DIG_BASE-1;
+ if (likely(len2>0))
+ {
+ /* hmm, this is a suspicious trick - I removed normalization here */
+ if (start2[1]*guess > (x-guess*start2[0])*DIG_BASE+y)
+ guess--;
+ if (unlikely(start2[1]*guess > (x-guess*start2[0])*DIG_BASE+y))
+ guess--;
+ DBUG_ASSERT(start2[1]*guess <= (x-guess*start2[0])*DIG_BASE+y);
+ }
+
+ /* D4: multiply and subtract */
+ buf2=stop2;
+ buf1=start1+len2;
+ DBUG_ASSERT(buf1 < stop1);
+ for (carry=0; buf2 > start2; buf1--)
+ {
+ dec1 hi, lo;
+ x=guess * (*--buf2);
+ hi=(dec1)(x/DIG_BASE);
+ lo=(dec1)(x-((dec2)hi)*DIG_BASE);
+ SUB2(*buf1, *buf1, lo, carry);
+ carry+=hi;
+ }
+ carry= dcarry < carry;
+
+ /* D5: check the remainder */
+ if (unlikely(carry))
+ {
+ /* D6: correct the guess */
+ guess--;
+ buf2=stop2;
+ buf1=start1+len2;
+ for (carry=0; buf2 > start2; buf1--)
+ {
+ ADD(*buf1, *buf1, *--buf2, carry);
+ }
+ }
+ }
+ if (likely(div))
+ *buf0=(dec1)guess;
+ dcarry= *start1;
+ start1++;
+ }
+ if (mod)
+ {
+ /*
+ now the result is in tmp1, it has
+ intg=prec1-frac1
+ frac=max(frac1, frac2)=to->frac
+ */
+ if (dcarry)
+ *--start1=dcarry;
+ buf0=to->buf;
+ intg0=ROUND_UP(prec1-frac1)-(start1-tmp1);
+ frac0=ROUND_UP(to->frac);
+ error=E_DEC_OK;
+ if (unlikely(frac0==0 && intg0==0))
+ {
+ decimal_make_zero(to);
+ goto done;
+ }
+ if (intg0<=0)
+ {
+ if (unlikely(-intg0 >= to->len))
+ {
+ decimal_make_zero(to);
+ error=E_DEC_TRUNCATED;
+ goto done;
+ }
+ stop1=start1+frac0;
+ frac0+=intg0;
+ to->intg=0;
+ while (intg0++ < 0)
+ *buf0++=0;
+ }
+ else
+ {
+ if (unlikely(intg0 > to->len))
+ {
+ frac0=0;
+ intg0=to->len;
+ error=E_DEC_OVERFLOW;
+ goto done;
+ }
+ DBUG_ASSERT(intg0 <= ROUND_UP(from2->intg));
+ stop1=start1+frac0+intg0;
+ to->intg=min(intg0*DIG_PER_DEC1, from2->intg);
+ }
+ if (unlikely(intg0+frac0 > to->len))
+ {
+ stop1-=to->len-frac0-intg0;
+ frac0=to->len-intg0;
+ to->frac=frac0*DIG_PER_DEC1;
+ error=E_DEC_TRUNCATED;
+ }
+ while (start1 < stop1)
+ *buf0++=*start1++;
+ }
+done:
+ my_afree(tmp1);
+ return error;
+}
+
+/*
+ division of two decimals
+
+ SYNOPSIS
+ decimal_div()
+ from1 - dividend
+ from2 - divisor
+ to - quotient
+
+ RETURN VALUE
+ E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_DIV_ZERO;
+
+ NOTES
+ see do_div_mod()
+*/
+
+int
+decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, int scale_incr)
+{
+ return do_div_mod(from1, from2, to, 0, scale_incr);
+}
+
+/*
+ modulus
+
+ SYNOPSIS
+ decimal_mod()
+ from1 - dividend
+ from2 - divisor
+ to - modulus
+
+ RETURN VALUE
+ E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_DIV_ZERO;
+
+ NOTES
+ see do_div_mod()
+
+ DESCRIPTION
+ the modulus R in R = M mod N
+
+ is defined as
+
+ 0 <= |R| < |M|
+ sign R == sign M
+ R = M - k*N, where k is integer
+
+ thus, there's no requirement for M or N to be integers
+*/
+
+int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to)
+{
+ return do_div_mod(from1, from2, 0, to, 0);
+}
+
+#ifdef MAIN
+
+int full= 0;
+decimal_t a, b, c;
+char buf1[100], buf2[100], buf3[100];
+
+void dump_decimal(decimal_t *d)
+{
+ int i;
+ printf("/* intg=%d, frac=%d, sign=%d, buf[]={", d->intg, d->frac, d->sign);
+ for (i=0; i < ROUND_UP(d->frac)+ROUND_UP(d->intg)-1; i++)
+ printf("%09d, ", d->buf[i]);
+ printf("%09d} */ ", d->buf[i]);
+}
+
+
+void check_result_code(int actual, int want)
+{
+ if (actual != want)
+ {
+ printf("\n^^^^^^^^^^^^^ must return %d\n", want);
+ exit(1);
+ }
+}
+
+
+void print_decimal(decimal_t *d, const char *orig, int actual, int want)
+{
+ char s[100];
+ int slen=sizeof(s);
+
+ if (full) dump_decimal(d);
+ decimal2string(d, s, &slen, 0, 0, 0);
+ printf("'%s'", s);
+ check_result_code(actual, want);
+ if (orig && strcmp(orig, s))
+ {
+ printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig);
+ exit(1);
+ }
+}
+
+void test_d2s()
+{
+ char s[100];
+ int slen, res;
+
+ /***********************************/
+ printf("==== decimal2string ====\n");
+ a.buf[0]=12345; a.intg=5; a.frac=0; a.sign=0;
+ slen=sizeof(s);
+ res=decimal2string(&a, s, &slen, 0, 0, 0);
+ dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
+
+ a.buf[1]=987000000; a.frac=3;
+ slen=sizeof(s);
+ res=decimal2string(&a, s, &slen, 0, 0, 0);
+ dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
+
+ a.sign=1;
+ slen=sizeof(s);
+ res=decimal2string(&a, s, &slen, 0, 0, 0);
+ dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
+
+ slen=8;
+ res=decimal2string(&a, s, &slen, 0, 0, 0);
+ dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
+
+ slen=5;
+ res=decimal2string(&a, s, &slen, 0, 0, 0);
+ dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
+
+ a.buf[0]=987000000; a.frac=3; a.intg=0;
+ slen=sizeof(s);
+ res=decimal2string(&a, s, &slen, 0, 0, 0);
+ dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
+}
+
+void test_s2d(const char *s, const char *orig, int ex)
+{
+ char s1[100], *end;
+ int res;
+ sprintf(s1, "'%s'", s);
+ end= strend(s);
+ printf("len=%2d %-30s => res=%d ", a.len, s1,
+ (res= string2decimal(s, &a, &end)));
+ print_decimal(&a, orig, res, ex);
+ printf("\n");
+}
+
+void test_d2f(const char *s, int ex)
+{
+ char s1[100], *end;
+ double x;
+ int res;
+
+ sprintf(s1, "'%s'", s);
+ end= strend(s);
+ string2decimal(s, &a, &end);
+ res=decimal2double(&a, &x);
+ if (full) dump_decimal(&a);
+ printf("%-40s => res=%d %.*g\n", s1, res, a.intg+a.frac, x);
+ check_result_code(res, ex);
+}
+
+void test_d2b2d(const char *str, int p, int s, const char *orig, int ex)
+{
+ char s1[100], buf[100], *end;
+ int res, i, size=decimal_bin_size(p, s);
+
+ sprintf(s1, "'%s'", str);
+ end= strend(str);
+ string2decimal(str, &a, &end);
+ res=decimal2bin(&a, buf, p, s);
+ printf("%-31s {%2d, %2d} => res=%d size=%-2d ", s1, p, s, res, size);
+ if (full)
+ {
+ printf("0x");
+ for (i=0; i < size; i++)
+ printf("%02x", ((uchar *)buf)[i]);
+ }
+ res=bin2decimal(buf, &a, p, s);
+ printf(" => res=%d ", res);
+ print_decimal(&a, orig, res, ex);
+ printf("\n");
+}
+
+void test_f2d(double from, int ex)
+{
+ int res;
+
+ res=double2decimal(from, &a);
+ printf("%-40.*f => res=%d ", DBL_DIG-2, from, res);
+ print_decimal(&a, 0, res, ex);
+ printf("\n");
+}
+
+void test_ull2d(ulonglong from, const char *orig, int ex)
+{
+ char s[100];
+ int res;
+
+ res=ulonglong2decimal(from, &a);
+ longlong10_to_str(from,s,10);
+ printf("%-40s => res=%d ", s, res);
+ print_decimal(&a, orig, res, ex);
+ printf("\n");
+}
+
+void test_ll2d(longlong from, const char *orig, int ex)
+{
+ char s[100];
+ int res;
+
+ res=longlong2decimal(from, &a);
+ longlong10_to_str(from,s,-10);
+ printf("%-40s => res=%d ", s, res);
+ print_decimal(&a, orig, res, ex);
+ printf("\n");
+}
+
+void test_d2ull(const char *s, const char *orig, int ex)
+{
+ char s1[100], *end;
+ ulonglong x;
+ int res;
+
+ end= strend(s);
+ string2decimal(s, &a, &end);
+ res=decimal2ulonglong(&a, &x);
+ if (full) dump_decimal(&a);
+ longlong10_to_str(x,s1,10);
+ printf("%-40s => res=%d %s\n", s, res, s1);
+ check_result_code(res, ex);
+ if (orig && strcmp(orig, s1))
+ {
+ printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig);
+ exit(1);
+ }
+}
+
+void test_d2ll(const char *s, const char *orig, int ex)
+{
+ char s1[100], *end;
+ longlong x;
+ int res;
+
+ end= strend(s);
+ string2decimal(s, &a, &end);
+ res=decimal2longlong(&a, &x);
+ if (full) dump_decimal(&a);
+ longlong10_to_str(x,s1,-10);
+ printf("%-40s => res=%d %s\n", s, res, s1);
+ check_result_code(res, ex);
+ if (orig && strcmp(orig, s1))
+ {
+ printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig);
+ exit(1);
+ }
+}
+
+void test_da(const char *s1, const char *s2, const char *orig, int ex)
+{
+ char s[100], *end;
+ int res;
+ sprintf(s, "'%s' + '%s'", s1, s2);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
+ res=decimal_add(&a, &b, &c);
+ printf("%-40s => res=%d ", s, res);
+ print_decimal(&c, orig, res, ex);
+ printf("\n");
+}
+
+void test_ds(const char *s1, const char *s2, const char *orig, int ex)
+{
+ char s[100], *end;
+ int res;
+ sprintf(s, "'%s' - '%s'", s1, s2);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
+ res=decimal_sub(&a, &b, &c);
+ printf("%-40s => res=%d ", s, res);
+ print_decimal(&c, orig, res, ex);
+ printf("\n");
+}
+
+void test_dc(const char *s1, const char *s2, int orig)
+{
+ char s[100], *end;
+ int res;
+ sprintf(s, "'%s' <=> '%s'", s1, s2);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
+ res=decimal_cmp(&a, &b);
+ printf("%-40s => res=%d\n", s, res);
+ if (orig != res)
+ {
+ printf("\n^^^^^^^^^^^^^ must've been %d\n", orig);
+ exit(1);
+ }
+}
+
+void test_dm(const char *s1, const char *s2, const char *orig, int ex)
+{
+ char s[100], *end;
+ int res;
+ sprintf(s, "'%s' * '%s'", s1, s2);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
+ res=decimal_mul(&a, &b, &c);
+ printf("%-40s => res=%d ", s, res);
+ print_decimal(&c, orig, res, ex);
+ printf("\n");
+}
+
+void test_dv(const char *s1, const char *s2, const char *orig, int ex)
+{
+ char s[100], *end;
+ int res;
+ sprintf(s, "'%s' / '%s'", s1, s2);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
+ res=decimal_div(&a, &b, &c, 5);
+ printf("%-40s => res=%d ", s, res);
+ check_result_code(res, ex);
+ if (res == E_DEC_DIV_ZERO)
+ printf("E_DEC_DIV_ZERO");
+ else
+ print_decimal(&c, orig, res, ex);
+ printf("\n");
+}
+
+void test_md(const char *s1, const char *s2, const char *orig, int ex)
+{
+ char s[100], *end;
+ int res;
+ sprintf(s, "'%s' %% '%s'", s1, s2);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
+ res=decimal_mod(&a, &b, &c);
+ printf("%-40s => res=%d ", s, res);
+ check_result_code(res, ex);
+ if (res == E_DEC_DIV_ZERO)
+ printf("E_DEC_DIV_ZERO");
+ else
+ print_decimal(&c, orig, res, ex);
+ printf("\n");
+}
+
+const char *round_mode[]=
+{"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"};
+
+void test_ro(const char *s1, int n, decimal_round_mode mode, const char *orig,
+ int ex)
+{
+ char s[100], *end;
+ int res;
+ sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ res=decimal_round(&a, &b, n, mode);
+ printf("%-40s => res=%d ", s, res);
+ print_decimal(&b, orig, res, ex);
+ printf("\n");
+}
+
+
+void test_mx(int precision, int frac, const char *orig)
+{
+ char s[100];
+ sprintf(s, "%d, %d", precision, frac);
+ max_decimal(precision, frac, &a);
+ printf("%-40s => ", s);
+ print_decimal(&a, orig, 0, 0);
+ printf("\n");
+}
+
+
+void test_pr(const char *s1, int prec, int dec, char filler, const char *orig,
+ int ex)
+{
+ char s[100], *end;
+ char s2[100];
+ int slen= sizeof(s2);
+ int res;
+
+ sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ res= decimal2string(&a, s2, &slen, prec, dec, filler);
+ printf("%-40s => res=%d '%s'", s, res, s2);
+ check_result_code(res, ex);
+ if (orig && strcmp(orig, s2))
+ {
+ printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig);
+ exit(1);
+ }
+ printf("\n");
+}
+
+
+void test_sh(const char *s1, int shift, const char *orig, int ex)
+{
+ char s[100], *end;
+ int res;
+ sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift));
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ res= decimal_shift(&a, shift);
+ printf("%-40s => res=%d ", s, res);
+ print_decimal(&a, orig, res, ex);
+ printf("\n");
+}
+
+
+void test_fr(const char *s1, const char *orig)
+{
+ char s[100], *end;
+ sprintf(s, "'%s'", s1);
+ printf("%-40s => ", s);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ decimal_optimize_fraction(&a);
+ print_decimal(&a, orig, 0, 0);
+ printf("\n");
+}
+
+
+int main()
+{
+ a.buf=(void*)buf1;
+ a.len=sizeof(buf1)/sizeof(dec1);
+ b.buf=(void*)buf2;
+ b.len=sizeof(buf2)/sizeof(dec1);
+ c.buf=(void*)buf3;
+ c.len=sizeof(buf3)/sizeof(dec1);
+
+ if (full)
+ test_d2s();
+
+ printf("==== string2decimal ====\n");
+ test_s2d("12345", "12345", 0);
+ test_s2d("12345.", "12345", 0);
+ test_s2d("123.45", "123.45", 0);
+ test_s2d("-123.45", "-123.45", 0);
+ test_s2d(".00012345000098765", "0.00012345000098765", 0);
+ test_s2d(".12345000098765", "0.12345000098765", 0);
+ test_s2d("-.000000012345000098765", "-0.000000012345000098765", 0);
+ test_s2d("1234500009876.5", "1234500009876.5", 0);
+ a.len=1;
+ test_s2d("123450000098765", "98765", 2);
+ test_s2d("123450.000098765", "123450", 1);
+ a.len=sizeof(buf1)/sizeof(dec1);
+ test_s2d("123E5", "12300000", 0);
+ test_s2d("123E-2", "1.23", 0);
+
+ printf("==== decimal2double ====\n");
+ test_d2f("12345", 0);
+ test_d2f("123.45", 0);
+ test_d2f("-123.45", 0);
+ test_d2f("0.00012345000098765", 0);
+ test_d2f("1234500009876.5", 0);
+
+ printf("==== double2decimal ====\n");
+ test_f2d(12345, 0);
+ test_f2d(1.0/3, 0);
+ test_f2d(-123.45, 0);
+ test_f2d(0.00012345000098765, 0);
+ test_f2d(1234500009876.5, 0);
+
+ printf("==== ulonglong2decimal ====\n");
+ test_ull2d(ULL(12345), "12345", 0);
+ test_ull2d(ULL(0), "0", 0);
+ test_ull2d(ULL(18446744073709551615), "18446744073709551615", 0);
+
+ printf("==== decimal2ulonglong ====\n");
+ test_d2ull("12345", "12345", 0);
+ test_d2ull("0", "0", 0);
+ test_d2ull("18446744073709551615", "18446744073709551615", 0);
+ test_d2ull("18446744073709551616", "18446744073", 2);
+ test_d2ull("-1", "0", 2);
+ test_d2ull("1.23", "1", 1);
+ test_d2ull("9999999999999999999999999.000", "9999999999999999", 2);
+
+ printf("==== longlong2decimal ====\n");
+ test_ll2d(LL(-12345), "-12345", 0);
+ test_ll2d(LL(-1), "-1", 0);
+ test_ll2d(LL(-9223372036854775807), "-9223372036854775807", 0);
+ test_ll2d(ULL(9223372036854775808), "-9223372036854775808", 0);
+
+ printf("==== decimal2longlong ====\n");
+ test_d2ll("18446744073709551615", "18446744073", 2);
+ test_d2ll("-1", "-1", 0);
+ test_d2ll("-1.23", "-1", 1);
+ test_d2ll("-9223372036854775807", "-9223372036854775807", 0);
+ test_d2ll("-9223372036854775808", "-9223372036854775808", 0);
+ test_d2ll("9223372036854775808", "9223372036854775807", 2);
+
+ printf("==== do_add ====\n");
+ test_da(".00012345000098765" ,"123.45", "123.45012345000098765", 0);
+ test_da(".1" ,".45", "0.55", 0);
+ test_da("1234500009876.5" ,".00012345000098765", "1234500009876.50012345000098765", 0);
+ test_da("9999909999999.5" ,".555", "9999910000000.055", 0);
+ test_da("99999999" ,"1", "100000000", 0);
+ test_da("989999999" ,"1", "990000000", 0);
+ test_da("999999999" ,"1", "1000000000", 0);
+ test_da("12345" ,"123.45", "12468.45", 0);
+ test_da("-12345" ,"-123.45", "-12468.45", 0);
+ test_ds("-12345" ,"123.45", "-12468.45", 0);
+ test_ds("12345" ,"-123.45", "12468.45", 0);
+
+ printf("==== do_sub ====\n");
+ test_ds(".00012345000098765", "123.45","-123.44987654999901235", 0);
+ test_ds("1234500009876.5", ".00012345000098765","1234500009876.49987654999901235", 0);
+ test_ds("9999900000000.5", ".555","9999899999999.945", 0);
+ test_ds("1111.5551", "1111.555","0.0001", 0);
+ test_ds(".555", ".555","0", 0);
+ test_ds("10000000", "1","9999999", 0);
+ test_ds("1000001000", ".1","1000000999.9", 0);
+ test_ds("1000000000", ".1","999999999.9", 0);
+ test_ds("12345", "123.45","12221.55", 0);
+ test_ds("-12345", "-123.45","-12221.55", 0);
+ test_da("-12345", "123.45","-12221.55", 0);
+ test_da("12345", "-123.45","12221.55", 0);
+ test_ds("123.45", "12345","-12221.55", 0);
+ test_ds("-123.45", "-12345","12221.55", 0);
+ test_da("123.45", "-12345","-12221.55", 0);
+ test_da("-123.45", "12345","12221.55", 0);
+ test_da("5", "-6.0","-1.0", 0);
+
+ printf("==== decimal_mul ====\n");
+ test_dm("12", "10","120", 0);
+ test_dm("-123.456", "98765.4321","-12193185.1853376", 0);
+ test_dm("-123456000000", "98765432100000","-12193185185337600000000000", 0);
+ test_dm("123456", "987654321","121931851853376", 0);
+ test_dm("123456", "9876543210","1219318518533760", 0);
+ test_dm("123", "0.01","1.23", 0);
+ test_dm("123", "0","0", 0);
+
+ printf("==== decimal_div ====\n");
+ test_dv("120", "10","12.000000000", 0);
+ test_dv("123", "0.01","12300.000000000", 0);
+ test_dv("120", "100000000000.00000","0.000000001200000000", 0);
+ test_dv("123", "0","", 4);
+ test_dv("-12193185.1853376", "98765.4321","-123.456000000000000000", 0);
+ test_dv("121931851853376", "987654321","123456.000000000", 0);
+ test_dv("0", "987","0", 0);
+ test_dv("1", "3","0.333333333", 0);
+ test_dv("1.000000000000", "3","0.333333333333333333", 0);
+ test_dv("1", "1","1.000000000", 0);
+ test_dv("0.0123456789012345678912345", "9999999999","0.000000000001234567890246913578148141", 0);
+ test_dv("10.333000000", "12.34500","0.837019036046982584042122316", 0);
+ test_dv("10.000000000060", "2","5.000000000030000000", 0);
+
+ printf("==== decimal_mod ====\n");
+ test_md("234","10","4", 0);
+ test_md("234.567","10.555","2.357", 0);
+ test_md("-234.567","10.555","-2.357", 0);
+ test_md("234.567","-10.555","2.357", 0);
+ c.buf[1]=0x3ABECA;
+ test_md("99999999999999999999999999999999999999","3","0", 0);
+ if (c.buf[1] != 0x3ABECA)
+ {
+ printf("%X - overflow\n", c.buf[1]);
+ exit(1);
+ }
+
+ printf("==== decimal2bin/bin2decimal ====\n");
+ test_d2b2d("-10.55", 4, 2,"-10.55", 0);
+ test_d2b2d("0.0123456789012345678912345", 30, 25,"0.0123456789012345678912345", 0);
+ test_d2b2d("12345", 5, 0,"12345", 0);
+ test_d2b2d("12345", 10, 3,"12345.000", 0);
+ test_d2b2d("123.45", 10, 3,"123.450", 0);
+ test_d2b2d("-123.45", 20, 10,"-123.4500000000", 0);
+ test_d2b2d(".00012345000098765", 15, 14,"0.00012345000098", 0);
+ test_d2b2d(".00012345000098765", 22, 20,"0.00012345000098765000", 0);
+ test_d2b2d(".12345000098765", 30, 20,"0.12345000098765000000", 0);
+ test_d2b2d("-.000000012345000098765", 30, 20,"-0.00000001234500009876", 0);
+ test_d2b2d("1234500009876.5", 30, 5,"1234500009876.50000", 0);
+ test_d2b2d("111111111.11", 10, 2,"11111111.11", 0);
+ test_d2b2d("000000000.01", 7, 3,"0.010", 0);
+ test_d2b2d("123.4", 10, 2, "123.40", 0);
+
+
+ printf("==== decimal_cmp ====\n");
+ test_dc("12","13",-1);
+ test_dc("13","12",1);
+ test_dc("-10","10",-1);
+ test_dc("10","-10",1);
+ test_dc("-12","-13",1);
+ test_dc("0","12",-1);
+ test_dc("-10","0",-1);
+ test_dc("4","4",0);
+
+ printf("==== decimal_round ====\n");
+ test_ro("5678.123451",-4,TRUNCATE,"0", 0);
+ test_ro("5678.123451",-3,TRUNCATE,"5000", 0);
+ test_ro("5678.123451",-2,TRUNCATE,"5600", 0);
+ test_ro("5678.123451",-1,TRUNCATE,"5670", 0);
+ test_ro("5678.123451",0,TRUNCATE,"5678", 0);
+ test_ro("5678.123451",1,TRUNCATE,"5678.1", 0);
+ test_ro("5678.123451",2,TRUNCATE,"5678.12", 0);
+ test_ro("5678.123451",3,TRUNCATE,"5678.123", 0);
+ test_ro("5678.123451",4,TRUNCATE,"5678.1234", 0);
+ test_ro("5678.123451",5,TRUNCATE,"5678.12345", 0);
+ test_ro("5678.123451",6,TRUNCATE,"5678.123451", 0);
+ test_ro("-5678.123451",-4,TRUNCATE,"0", 0);
+ memset(buf2, 33, sizeof(buf2));
+ test_ro("99999999999999999999999999999999999999",-31,TRUNCATE,"99999990000000000000000000000000000000", 0);
+ test_ro("15.1",0,HALF_UP,"15", 0);
+ test_ro("15.5",0,HALF_UP,"16", 0);
+ test_ro("15.9",0,HALF_UP,"16", 0);
+ test_ro("-15.1",0,HALF_UP,"-15", 0);
+ test_ro("-15.5",0,HALF_UP,"-16", 0);
+ test_ro("-15.9",0,HALF_UP,"-16", 0);
+ test_ro("15.1",1,HALF_UP,"15.1", 0);
+ test_ro("-15.1",1,HALF_UP,"-15.1", 0);
+ test_ro("15.17",1,HALF_UP,"15.2", 0);
+ test_ro("15.4",-1,HALF_UP,"20", 0);
+ test_ro("-15.4",-1,HALF_UP,"-20", 0);
+ test_ro("5.4",-1,HALF_UP,"10", 0);
+ test_ro(".999", 0, HALF_UP, "1", 0);
+ memset(buf2, 33, sizeof(buf2));
+ test_ro("999999999", -9, HALF_UP, "1000000000", 0);
+ test_ro("15.1",0,HALF_EVEN,"15", 0);
+ test_ro("15.5",0,HALF_EVEN,"16", 0);
+ test_ro("14.5",0,HALF_EVEN,"14", 0);
+ test_ro("15.9",0,HALF_EVEN,"16", 0);
+ test_ro("15.1",0,CEILING,"16", 0);
+ test_ro("-15.1",0,CEILING,"-15", 0);
+ test_ro("15.1",0,FLOOR,"15", 0);
+ test_ro("-15.1",0,FLOOR,"-16", 0);
+ test_ro("999999999999999999999.999", 0, CEILING,"1000000000000000000000", 0);
+ test_ro("-999999999999999999999.999", 0, FLOOR,"-1000000000000000000000", 0);
+
+ b.buf[0]=DIG_BASE+1;
+ b.buf++;
+ test_ro(".3", 0, HALF_UP, "0", 0);
+ b.buf--;
+ if (b.buf[0] != DIG_BASE+1)
+ {
+ printf("%d - underflow\n", b.buf[0]);
+ exit(1);
+ }
+
+ printf("==== max_decimal ====\n");
+ test_mx(1,1,"0.9");
+ test_mx(1,0,"9");
+ test_mx(2,1,"9.9");
+ test_mx(4,2,"99.99");
+ test_mx(6,3,"999.999");
+ test_mx(8,4,"9999.9999");
+ test_mx(10,5,"99999.99999");
+ test_mx(12,6,"999999.999999");
+ test_mx(14,7,"9999999.9999999");
+ test_mx(16,8,"99999999.99999999");
+ test_mx(18,9,"999999999.999999999");
+ test_mx(20,10,"9999999999.9999999999");
+ test_mx(20,20,"0.99999999999999999999");
+ test_mx(20,0,"99999999999999999999");
+ test_mx(40,20,"99999999999999999999.99999999999999999999");
+
+ printf("==== decimal2string ====\n");
+ test_pr("123.123", 0, 0, 0, "123.123", 0);
+ test_pr("123.123", 7, 3, '0', "123.123", 0);
+ test_pr("123.123", 9, 3, '0', "00123.123", 0);
+ test_pr("123.123", 9, 4, '0', "0123.1230", 0);
+ test_pr("123.123", 9, 5, '0', "123.12300", 0);
+ test_pr("123.123", 9, 2, '0', "000123.12", 1);
+ test_pr("123.123", 9, 6, '0', "23.123000", 2);
+
+ printf("==== decimal_shift ====\n");
+ test_sh("123.123", 1, "1231.23", 0);
+ test_sh("123457189.123123456789000", 1, "1234571891.23123456789", 0);
+ test_sh("123457189.123123456789000", 4, "1234571891231.23456789", 0);
+ test_sh("123457189.123123456789000", 8, "12345718912312345.6789", 0);
+ test_sh("123457189.123123456789000", 9, "123457189123123456.789", 0);
+ test_sh("123457189.123123456789000", 10, "1234571891231234567.89", 0);
+ test_sh("123457189.123123456789000", 17, "12345718912312345678900000", 0);
+ test_sh("123457189.123123456789000", 18, "123457189123123456789000000", 0);
+ test_sh("123457189.123123456789000", 19, "1234571891231234567890000000", 0);
+ test_sh("123457189.123123456789000", 26, "12345718912312345678900000000000000", 0);
+ test_sh("123457189.123123456789000", 27, "123457189123123456789000000000000000", 0);
+ test_sh("123457189.123123456789000", 28, "1234571891231234567890000000000000000", 0);
+ test_sh("000000000000000000000000123457189.123123456789000", 26, "12345718912312345678900000000000000", 0);
+ test_sh("00000000123457189.123123456789000", 27, "123457189123123456789000000000000000", 0);
+ test_sh("00000000000000000123457189.123123456789000", 28, "1234571891231234567890000000000000000", 0);
+ test_sh("123", 1, "1230", 0);
+ test_sh("123", 10, "1230000000000", 0);
+ test_sh(".123", 1, "1.23", 0);
+ test_sh(".123", 10, "1230000000", 0);
+ test_sh(".123", 14, "12300000000000", 0);
+ test_sh("000.000", 1000, "0", 0);
+ test_sh("000.", 1000, "0", 0);
+ test_sh(".000", 1000, "0", 0);
+ test_sh("1", 1000, "1", 2);
+ test_sh("123.123", -1, "12.3123", 0);
+ test_sh("123987654321.123456789000", -1, "12398765432.1123456789", 0);
+ test_sh("123987654321.123456789000", -2, "1239876543.21123456789", 0);
+ test_sh("123987654321.123456789000", -3, "123987654.321123456789", 0);
+ test_sh("123987654321.123456789000", -8, "1239.87654321123456789", 0);
+ test_sh("123987654321.123456789000", -9, "123.987654321123456789", 0);
+ test_sh("123987654321.123456789000", -10, "12.3987654321123456789", 0);
+ test_sh("123987654321.123456789000", -11, "1.23987654321123456789", 0);
+ test_sh("123987654321.123456789000", -12, "0.123987654321123456789", 0);
+ test_sh("123987654321.123456789000", -13, "0.0123987654321123456789", 0);
+ test_sh("123987654321.123456789000", -14, "0.00123987654321123456789", 0);
+ test_sh("00000087654321.123456789000", -14, "0.00000087654321123456789", 0);
+ a.len= 2;
+ test_sh("123.123", -2, "1.23123", 0);
+ test_sh("123.123", -3, "0.123123", 0);
+ test_sh("123.123", -6, "0.000123123", 0);
+ test_sh("123.123", -7, "0.0000123123", 0);
+ test_sh("123.123", -15, "0.000000000000123123", 0);
+ test_sh("123.123", -16, "0.000000000000012312", 1);
+ test_sh("123.123", -17, "0.000000000000001231", 1);
+ test_sh("123.123", -18, "0.000000000000000123", 1);
+ test_sh("123.123", -19, "0.000000000000000012", 1);
+ test_sh("123.123", -20, "0.000000000000000001", 1);
+ test_sh("123.123", -21, "0", 1);
+ test_sh(".000000000123", -1, "0.0000000000123", 0);
+ test_sh(".000000000123", -6, "0.000000000000000123", 0);
+ test_sh(".000000000123", -7, "0.000000000000000012", 1);
+ test_sh(".000000000123", -8, "0.000000000000000001", 1);
+ test_sh(".000000000123", -9, "0", 1);
+ test_sh(".000000000123", 1, "0.00000000123", 0);
+ test_sh(".000000000123", 8, "0.0123", 0);
+ test_sh(".000000000123", 9, "0.123", 0);
+ test_sh(".000000000123", 10, "1.23", 0);
+ test_sh(".000000000123", 17, "12300000", 0);
+ test_sh(".000000000123", 18, "123000000", 0);
+ test_sh(".000000000123", 19, "1230000000", 0);
+ test_sh(".000000000123", 20, "12300000000", 0);
+ test_sh(".000000000123", 21, "123000000000", 0);
+ test_sh(".000000000123", 22, "1230000000000", 0);
+ test_sh(".000000000123", 23, "12300000000000", 0);
+ test_sh(".000000000123", 24, "123000000000000", 0);
+ test_sh(".000000000123", 25, "1230000000000000", 0);
+ test_sh(".000000000123", 26, "12300000000000000", 0);
+ test_sh(".000000000123", 27, "123000000000000000", 0);
+ test_sh(".000000000123", 28, "0.000000000123", 2);
+ test_sh("123456789.987654321", -1, "12345678.998765432", 1);
+ test_sh("123456789.987654321", -2, "1234567.899876543", 1);
+ test_sh("123456789.987654321", -8, "1.234567900", 1);
+ test_sh("123456789.987654321", -9, "0.123456789987654321", 0);
+ test_sh("123456789.987654321", -10, "0.012345678998765432", 1);
+ test_sh("123456789.987654321", -17, "0.000000001234567900", 1);
+ test_sh("123456789.987654321", -18, "0.000000000123456790", 1);
+ test_sh("123456789.987654321", -19, "0.000000000012345679", 1);
+ test_sh("123456789.987654321", -26, "0.000000000000000001", 1);
+ test_sh("123456789.987654321", -27, "0", 1);
+ test_sh("123456789.987654321", 1, "1234567900", 1);
+ test_sh("123456789.987654321", 2, "12345678999", 1);
+ test_sh("123456789.987654321", 4, "1234567899877", 1);
+ test_sh("123456789.987654321", 8, "12345678998765432", 1);
+ test_sh("123456789.987654321", 9, "123456789987654321", 0);
+ test_sh("123456789.987654321", 10, "123456789.987654321", 2);
+ test_sh("123456789.987654321", 0, "123456789.987654321", 0);
+ a.len= sizeof(buf1)/sizeof(dec1);
+
+ printf("==== decimal_optimize_fraction ====\n");
+ test_fr("1.123456789000000000", "1.123456789");
+ test_fr("1.12345678000000000", "1.12345678");
+ test_fr("1.1234567000000000", "1.1234567");
+ test_fr("1.123456000000000", "1.123456");
+ test_fr("1.12345000000000", "1.12345");
+ test_fr("1.1234000000000", "1.1234");
+ test_fr("1.123000000000", "1.123");
+ test_fr("1.12000000000", "1.12");
+ test_fr("1.1000000000", "1.1");
+ test_fr("1.000000000", "1");
+ test_fr("1.0", "1");
+ test_fr("10000000000000000000.0", "10000000000000000000");
+
+ return 0;
+}
+#endif
diff --git a/strings/llstr.c b/strings/llstr.c
index 966b347ac7e..ac034cbe2e2 100644
--- a/strings/llstr.c
+++ b/strings/llstr.c
@@ -30,6 +30,6 @@
char *llstr(longlong value,char *buff)
{
- longlong2str(value,buff,-10);
+ longlong10_to_str(value,buff,-10);
return buff;
}
diff --git a/strings/my_strtoll10.c b/strings/my_strtoll10.c
index 5217564087c..cca7c8ab396 100644
--- a/strings/my_strtoll10.c
+++ b/strings/my_strtoll10.c
@@ -46,7 +46,7 @@ static unsigned long lfactor[9]=
from string nptr and converts it to an signed or unsigned
long long integer value.
Space characters and tab are ignored.
- A sign character might precede the the digit characters. The number
+ A sign character might precede the digit characters. The number
may have any number of pre-zero digits.
The function stops reading the string nptr at the first character
diff --git a/strings/my_vsnprintf.c b/strings/my_vsnprintf.c
index 268f7d18f2a..4d7c17e977c 100644
--- a/strings/my_vsnprintf.c
+++ b/strings/my_vsnprintf.c
@@ -52,15 +52,30 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
if (*fmt == '-')
fmt++;
length= width= pre_zero= have_long= 0;
- for (;my_isdigit(&my_charset_latin1,*fmt); fmt++)
+ if (*fmt == '*')
{
- length=length*10+ (uint) (*fmt-'0');
- if (!length)
- pre_zero= 1; /* first digit was 0 */
+ fmt++;
+ length= va_arg(ap, int);
}
+ else
+ for (; my_isdigit(&my_charset_latin1, *fmt); fmt++)
+ {
+ length= length * 10 + (uint)(*fmt - '0');
+ if (!length)
+ pre_zero= 1; /* first digit was 0 */
+ }
if (*fmt == '.')
- for (fmt++;my_isdigit(&my_charset_latin1,*fmt); fmt++)
- width=width*10+ (uint) (*fmt-'0');
+ {
+ fmt++;
+ if (*fmt == '*')
+ {
+ fmt++;
+ width= va_arg(ap, int);
+ }
+ else
+ for (; my_isdigit(&my_charset_latin1, *fmt); fmt++)
+ width= width * 10 + (uint)(*fmt - '0');
+ }
else
width= ~0;
if (*fmt == 'l')
diff --git a/strings/xml.c b/strings/xml.c
index 6ba52ea41a8..d19c3dab241 100644
--- a/strings/xml.c
+++ b/strings/xml.c
@@ -135,7 +135,7 @@ static int my_xml_value(MY_XML_PARSER *st, const char *str, uint len)
static int my_xml_enter(MY_XML_PARSER *st, const char *str, uint len)
{
- if ( (st->attrend-st->attr+len+1)>sizeof(st->attr))
+ if ((uint) (st->attrend-st->attr+len+1) > sizeof(st->attr))
{
sprintf(st->errstr,"To deep XML");
return MY_XML_ERROR;
diff --git a/support-files/MySQL-shared-compat.spec.sh b/support-files/MySQL-shared-compat.spec.sh
index e3c88c9415f..ffc96fd6fff 100644
--- a/support-files/MySQL-shared-compat.spec.sh
+++ b/support-files/MySQL-shared-compat.spec.sh
@@ -26,7 +26,8 @@
#
# Change this to match the version of the shared libs you want to include
#
-%define version41 @MYSQL_NO_DASH_VERSION@
+%define version50 @MYSQL_NO_DASH_VERSION@
+%define version41 4.1.9
%define version40 4.0.23
%define version3 3.23.58
@@ -37,30 +38,32 @@ License: GPL
Group: Applications/Databases
URL: http://www.mysql.com/
Autoreqprov: on
-Version: %{version41}
+Version: %{version50}
Release: 0
BuildRoot: %{_tmppath}/%{name}-%{version}-build
Obsoletes: MySQL-shared, mysql-shared
Provides: MySQL-shared
-Summary: MySQL shared client libraries for MySQL %{version41}, %{version40} and %{version3}
+Summary: MySQL shared client libraries for MySQL %{version}, %{version41}, %{version40} and %{version3}
# We simply use the "MySQL-shared" subpackages as input sources instead of
# rebuilding all from source
-Source0: MySQL-shared-%{version41}-0.%{_arch}.rpm
-Source1: MySQL-shared-%{version40}-0.%{_arch}.rpm
-Source2: MySQL-shared-%{version3}-1.%{_arch}.rpm
+Source0: MySQL-shared-%{version50}-0.%{_arch}.rpm
+Source1: MySQL-shared-%{version41}-0.%{_arch}.rpm
+Source2: MySQL-shared-%{version40}-0.%{_arch}.rpm
+Source3: MySQL-shared-%{version3}-1.%{_arch}.rpm
# No need to include the RPMs once more - they can be downloaded seperately
# if you want to rebuild this package
NoSource: 0
NoSource: 1
NoSource: 2
+NoSource: 3
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
-This package includes the shared libraries for both MySQL %{version3},
-MySQL %{version40} as well as MySQL %{version41}.
+This package includes the shared libraries for MySQL %{version3},
+MySQL %{version40}, %{version41} as well as MySQL %{version50}.
Install this package instead of "MySQL-shared", if you have applications
installed that are dynamically linked against older versions of the MySQL
-client library but you want to upgrade to MySQL 4.1.xx without breaking the
+client library but you want to upgrade to MySQL %{version} without breaking the
library dependencies.
%install
@@ -70,6 +73,7 @@ cd $RPM_BUILD_ROOT
rpm2cpio %{SOURCE0} | cpio -iv --make-directories
rpm2cpio %{SOURCE1} | cpio -iv --make-directories
rpm2cpio %{SOURCE2} | cpio -iv --make-directories
+rpm2cpio %{SOURCE3} | cpio -iv --make-directories
/sbin/ldconfig -n $RPM_BUILD_ROOT%{_libdir}
%clean
diff --git a/support-files/debian/gomi b/support-files/debian/gomi
index 4c9460578be..70251058af0 100644
--- a/support-files/debian/gomi
+++ b/support-files/debian/gomi
@@ -2,8 +2,6 @@ Docs/Makefile
dbug/Makefile
extra/Makefile
heap/Makefile
-isam/Makefile
-merge/Makefile
mysys/Makefile
readline/Makefile
regex/Makefile
diff --git a/support-files/my-huge.cnf.sh b/support-files/my-huge.cnf.sh
index d25686f1c21..f7a47054658 100644
--- a/support-files/my-huge.cnf.sh
+++ b/support-files/my-huge.cnf.sh
@@ -48,7 +48,7 @@ thread_concurrency = 8
# Replication Master Server (default)
# binary logging is required for replication
-log-bin
+log-bin=mysql-bin
# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
@@ -108,7 +108,7 @@ server-id = 1
#master-port = <port>
#
# binary logging - not required for slaves, but recommended
-#log-bin
+#log-bin=mysql-bin
# Point the following paths to different dedicated disks
#tmpdir = /tmp/
diff --git a/support-files/my-innodb-heavy-4G.cnf.sh b/support-files/my-innodb-heavy-4G.cnf.sh
index 062d106ce6a..b3f43272a7d 100644
--- a/support-files/my-innodb-heavy-4G.cnf.sh
+++ b/support-files/my-innodb-heavy-4G.cnf.sh
@@ -189,7 +189,7 @@ tmp_table_size = 64M
# Enable binary logging. This is required for acting as a MASTER in a
# replication configuration. You also need the binary log if you need
# the ability to do point in time recovery from your latest backup.
-log_bin
+log-bin=mysql-bin
# If you're using replication with chained slaves (A->B->C), you need to
# enable this option on server B. It enables logging of updates done by
diff --git a/support-files/my-large.cnf.sh b/support-files/my-large.cnf.sh
index 59aca4b32f2..1e7d9f7aade 100644
--- a/support-files/my-large.cnf.sh
+++ b/support-files/my-large.cnf.sh
@@ -48,7 +48,7 @@ thread_concurrency = 8
# Replication Master Server (default)
# binary logging is required for replication
-log-bin
+log-bin=mysql-bin
# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
@@ -108,7 +108,7 @@ server-id = 1
#master-port = <port>
#
# binary logging - not required for slaves, but recommended
-#log-bin
+#log-bin=mysql-bin
# Point the following paths to different dedicated disks
#tmpdir = /tmp/
diff --git a/support-files/my-medium.cnf.sh b/support-files/my-medium.cnf.sh
index 529740d59f0..99b6e823f39 100644
--- a/support-files/my-medium.cnf.sh
+++ b/support-files/my-medium.cnf.sh
@@ -46,7 +46,7 @@ myisam_sort_buffer_size = 8M
# Replication Master Server (default)
# binary logging is required for replication
-log-bin
+log-bin=mysql-bin
# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
@@ -106,7 +106,7 @@ server-id = 1
#master-port = <port>
#
# binary logging - not required for slaves, but recommended
-#log-bin
+#log-bin=mysql-bin
# Point the following paths to different dedicated disks
#tmpdir = /tmp/
diff --git a/support-files/my-small.cnf.sh b/support-files/my-small.cnf.sh
index b2ecca6127e..288df893b4c 100644
--- a/support-files/my-small.cnf.sh
+++ b/support-files/my-small.cnf.sh
@@ -46,7 +46,7 @@ thread_stack = 64K
server-id = 1
# Uncomment the following if you want to log updates
-#log-bin
+#log-bin=mysql-bin
# Uncomment the following if you are NOT using BDB tables
#skip-bdb
diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh
index f9015824e6b..071b7696908 100644
--- a/support-files/mysql.server.sh
+++ b/support-files/mysql.server.sh
@@ -39,19 +39,30 @@
# If you want to affect other MySQL variables, you should make your changes
# in the /etc/my.cnf, ~/.my.cnf or other MySQL configuration files.
+# If you change base dir, you must also change datadir
+
basedir=
+datadir=
# The following variables are only set for letting mysql.server find things.
# Set some defaults
-datadir=@localstatedir@
pid_file=
+server_pid_file=
+use_mysqld_safe=1
+user=@MYSQLD_USER@
if test -z "$basedir"
then
basedir=@prefix@
bindir=@bindir@
+ datadir=@localstatedir@
+ sbindir=@sbindir@
+ libexecdir=@libexecdir@
else
bindir="$basedir/bin"
+ datadir="$basedir/data"
+ sbindir="$basedir/bin"
+ libexecdir="$basedir/bin"
fi
#
@@ -82,12 +93,29 @@ case `echo "testing\c"`,`echo -n testing` in
*) echo_n= echo_c='\c' ;;
esac
-parse_arguments() {
+parse_server_arguments() {
for arg do
case "$arg" in
- --basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
+ --basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'`
+ bindir="$basedir/bin"
+ datadir="$basedir/data"
+ sbindir="$basedir/bin"
+ libexecdir="$basedir/bin"
+ ;;
--datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
+ --user=*) user=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
+ --pid-file=*) server_pid_file=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
+ --use-mysqld_safe) use_mysqld_safe=1;;
+ --use-manager) use_mysqld_safe=0;;
+ esac
+ done
+}
+
+parse_manager_arguments() {
+ for arg do
+ case "$arg" in
--pid-file=*) pid_file=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
+ --user=*) user=`echo "$arg" | sed -e 's/^[^=]*=//'` ;;
esac
done
}
@@ -120,7 +148,7 @@ wait_for_pid () {
}
# Get arguments from the my.cnf file,
-# groups [mysqld] [mysql_server] and [mysql.server]
+# the only group, which is read from now on is [mysqld]
if test -x ./bin/my_print_defaults
then
print_defaults="./bin/my_print_defaults"
@@ -159,30 +187,47 @@ else
fi
#
-# Test if someone changed datadir; In this case we should also read the
-# default arguments from this directory
+# Read defaults file from 'basedir'. If there is no defaults file there
+# check if it's in the old (depricated) place (datadir) and read it from there
#
extra_args=""
-if test "$datadir" != "@localstatedir@"
+if test -r "$basedir/my.cnf"
then
- extra_args="-e $datadir/my.cnf"
+ extra_args="-e $basedir/my.cnf"
+else
+ if test -r "$datadir/my.cnf"
+ then
+ extra_args="-e $datadir/my.cnf"
+ fi
fi
-parse_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server`
+parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server`
+
+# Look for the pidfile
+parse_manager_arguments `$print_defaults $extra_args manager`
#
# Set pid file if not given
#
if test -z "$pid_file"
then
- pid_file=$datadir/`@HOSTNAME@`.pid
+ pid_file=$datadir/mysqlmanager-`@HOSTNAME@`.pid
else
case "$pid_file" in
/* ) ;;
* ) pid_file="$datadir/$pid_file" ;;
esac
fi
+if test -z "$server_pid_file"
+then
+ server_pid_file=$datadir/`@HOSTNAME@`.pid
+else
+ case "$server_pid_file" in
+ /* ) ;;
+ * ) server_pid_file="$datadir/$server_pid_file" ;;
+ esac
+fi
# Safeguard (relative paths, core dumps..)
cd $basedir
@@ -191,42 +236,75 @@ case "$mode" in
'start')
# Start daemon
- if test -x $bindir/mysqld_safe
+ manager=$bindir/mysqlmanager
+ if test -x $libexecdir/mysqlmanager
+ then
+ manager=$libexecdir/mysqlmanager
+ elif test -x $bindir/mysqlmanager
+ then
+ manager=$sbindir/mysqlmanager
+ fi
+
+ echo $echo_n "Starting MySQL"
+ if test -x $manager -a "$use_mysqld_safe" = "0"
then
# Give extra arguments to mysqld with the my.cnf file. This script may
# be overwritten at next upgrade.
- echo $echo_n "Starting MySQL"
- $bindir/mysqld_safe --datadir=$datadir --pid-file=$pid_file >/dev/null 2>&1 &
+ $manager --user=$user --pid-file=$pid_file >/dev/null 2>&1 &
+ wait_for_pid created
+
+ # Make lock for RedHat / SuSE
+ if test -w /var/lock/subsys
+ then
+ touch /var/lock/subsys/mysqlmanager
+ fi
+ elif test -x $bindir/mysqld_safe
+ then
+ # Give extra arguments to mysqld with the my.cnf file. This script
+ # may be overwritten at next upgrade.
+ pid_file=$server_pid_file
+ $bindir/mysqld_safe --datadir=$datadir --pid-file=$server_pid_file >/dev/null 2>&1 &
wait_for_pid created
-
+
# Make lock for RedHat / SuSE
if test -w /var/lock/subsys
then
touch /var/lock/subsys/mysql
fi
else
- log_failure_msg "Can't execute $bindir/mysqld_safe"
+ log_failure_msg "Couldn't find MySQL manager or server"
fi
;;
'stop')
# Stop daemon. We use a signal here to avoid having to know the
# root password.
+
+ # The RedHat / SuSE lock directory to remove
+ lock_dir=/var/lock/subsys/mysqlmanager
+
+ # If the manager pid_file doesn't exist, try the server's
+ if test ! -s "$pid_file"
+ then
+ pid_file=$server_pid_file
+ lock_dir=/var/lock/subsys/mysql
+ fi
+
if test -s "$pid_file"
then
- mysqld_pid=`cat $pid_file`
+ mysqlmanager_pid=`cat $pid_file`
echo $echo_n "Shutting down MySQL"
- kill $mysqld_pid
- # mysqld should remove the pid_file when it exits, so wait for it.
+ kill $mysqlmanager_pid
+ # mysqlmanager should remove the pid_file when it exits, so wait for it.
wait_for_pid removed
# delete lock for RedHat / SuSE
- if test -f /var/lock/subsys/mysql
+ if test -f $lock_dir
then
- rm -f /var/lock/subsys/mysql
+ rm -f $lock_dir
fi
else
- log_failure_msg "MySQL PID file could not be found!"
+ log_failure_msg "MySQL manager or server PID file could not be found!"
fi
;;
@@ -235,17 +313,17 @@ case "$mode" in
# running or not, start it again.
$0 stop
$0 start
- ;;
+ ;;
'reload')
- if test -s "$pid_file" ; then
- mysqld_pid=`cat $pid_file`
+ if test -s "$server_pid_file" ; then
+ mysqld_pid=`cat $server_pid_file`
kill -HUP $mysqld_pid && log_success_msg "Reloading service MySQL"
- touch $pid_file
+ touch $server_pid_file
else
log_failure_msg "MySQL PID file could not be found!"
fi
- ;;
+ ;;
*)
# usage
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 1de315b6458..5e7499c5e5c 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -213,7 +213,7 @@ Optional MySQL server binary that supports additional features like:
- Archive Storage Engine
- CSV Storage Engine
- Example Storage Engine
- - MyISAM RAID
+ - Federated Storage Engine
- User Defined Functions (UDFs).
To activate this binary, just install this package in addition to
@@ -327,11 +327,11 @@ BuildMySQL "--enable-shared \
--with-berkeley-db \
--with-innodb \
--with-ndbcluster \
- --with-raid \
--with-archive \
--with-csv-storage-engine \
--with-example-storage-engine \
--with-blackhole-storage-engine \
+ --with-federated-storage-engine \
--with-embedded-server \
--with-comment=\"MySQL Community Edition - Max (GPL)\" \
--with-server-suffix='-Max'"
@@ -423,9 +423,11 @@ ln -s %{_sysconfdir}/init.d/mysql $RPM_BUILD_ROOT%{_sbindir}/rcmysql
# (safe_mysqld will be gone in MySQL 4.1)
ln -sf ./mysqld_safe $RBR%{_bindir}/safe_mysqld
-# Touch the place where the my.cnf config file might be located
+# Touch the place where the my.cnf config file and mysqlmanager.passwd
+# (MySQL Instance Manager password file) might be located
# Just to make sure it's in the file list and marked as a config file
touch $RBR%{_sysconfdir}/my.cnf
+touch $RBR%{_sysconfdir}/mysqlmanager.passwd
%pre server
# Shut down a previously installed server first
@@ -534,8 +536,6 @@ fi
%doc %attr(644, root, root) %{_infodir}/mysql.info*
-%doc %attr(644, root, man) %{_mandir}/man1/isamchk.1*
-%doc %attr(644, root, man) %{_mandir}/man1/isamlog.1*
%doc %attr(644, root, man) %{_mandir}/man1/mysql_zap.1*
%doc %attr(644, root, man) %{_mandir}/man1/mysqld.1*
%doc %attr(644, root, man) %{_mandir}/man1/mysql_fix_privilege_tables.1*
@@ -545,9 +545,8 @@ fi
%doc %attr(644, root, man) %{_mandir}/man1/replace.1*
%ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf
+%ghost %config(noreplace,missingok) %{_sysconfdir}/mysqlmanager.passwd
-%attr(755, root, root) %{_bindir}/isamchk
-%attr(755, root, root) %{_bindir}/isamlog
%attr(755, root, root) %{_bindir}/my_print_defaults
%attr(755, root, root) %{_bindir}/myisamchk
%attr(755, root, root) %{_bindir}/myisam_ftdump
@@ -568,7 +567,6 @@ fi
%attr(755, root, root) %{_bindir}/mysqld_safe
%attr(755, root, root) %{_bindir}/mysqlhotcopy
%attr(755, root, root) %{_bindir}/mysqltest
-%attr(755, root, root) %{_bindir}/pack_isam
%attr(755, root, root) %{_bindir}/perror
%attr(755, root, root) %{_bindir}/replace
%attr(755, root, root) %{_bindir}/resolve_stack_dump
@@ -576,6 +574,7 @@ fi
%attr(755, root, root) %{_bindir}/safe_mysqld
%attr(755, root, root) %{_sbindir}/mysqld
+%attr(755, root, root) %{_sbindir}/mysqlmanager
%attr(755, root, root) %{_sbindir}/rcmysql
%attr(644, root, root) %{_libdir}/mysql/mysqld.sym
@@ -648,7 +647,6 @@ fi
%{_includedir}/mysql/*
%{_libdir}/mysql/libdbug.a
%{_libdir}/mysql/libheap.a
-%{_libdir}/mysql/libmerge.a
%if %{have_libgcc}
%{_libdir}/mysql/libmygcc.a
%endif
@@ -660,7 +658,6 @@ fi
%{_libdir}/mysql/libmysqlclient_r.la
%{_libdir}/mysql/libmystrings.a
%{_libdir}/mysql/libmysys.a
-%{_libdir}/mysql/libnisam.a
%{_libdir}/mysql/libvio.a
%files shared
@@ -672,9 +669,9 @@ fi
%defattr(-, root, root, 0755)
%attr(-, root, root) %{_datadir}/sql-bench
%attr(-, root, root) %{_datadir}/mysql-test
-%attr(755, root, root) %{_bindir}/mysqlmanager
-%attr(755, root, root) %{_bindir}/mysqlmanager-pwgen
-%attr(755, root, root) %{_bindir}/mysqlmanagerc
+%attr(755, root, root) %{_bindir}/mysqltestmanager
+%attr(755, root, root) %{_bindir}/mysqltestmanager-pwgen
+%attr(755, root, root) %{_bindir}/mysqltestmanagerc
%files Max
%defattr(-, root, root, 0755)
@@ -698,6 +695,21 @@ fi
- removed the MySQL manual files (html/ps/texi) - they have been removed
from the MySQL sources and are now available seperately.
+* Mon Apr 4 2005 Petr Chardin <petr@mysql.com>
+
+- old mysqlmanager, mysqlmanagerc and mysqlmanager-pwger renamed into
+ mysqltestmanager, mysqltestmanager and mysqltestmanager-pwgen respectively
+
+* Fri Mar 18 2005 Lenz Grimmer <lenz@mysql.com>
+
+- Disabled RAID in the Max binaries once and for all (it has finally been
+ removed from the source tree)
+
+* Sun Feb 20 2005 Petr Chardin <petr@mysql.com>
+
+- Install MySQL Instance Manager together with mysqld, touch mysqlmanager
+ password file
+
* Mon Feb 14 2005 Lenz Grimmer <lenz@mysql.com>
- Fixed the compilation comments and moved them into the separate build sections
@@ -713,6 +725,15 @@ fi
- replaced obsoleted "BuildPrereq" with "BuildRequires" instead
+* Thu Jan 13 2005 Lenz Grimmer <lenz@mysql.com>
+
+- enabled the "Federated" storage engine for the max binary
+
+* Tue Jan 04 2005 Petr Chardin <petr@mysql.com>
+
+- ISAM and merge storage engines were purged. As well as appropriate
+ tools and manpages (isamchk and isamlog)
+
* Thu Dec 31 2004 Lenz Grimmer <lenz@mysql.com>
- enabled the "Archive" storage engine for the max binary
diff --git a/tests/Makefile.am b/tests/Makefile.am
index de4fbb2a4f2..a4bcd38afb1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -34,9 +34,11 @@ noinst_PROGRAMS = insert_test select_test thread_test
#
INCLUDES = -I$(top_srcdir)/include $(openssl_includes)
LIBS = @CLIENT_LIBS@
-LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysql/libmysqlclient.la
-mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS)
-mysql_client_test_SOURCES= mysql_client_test.c
+LDADD = @CLIENT_EXTRA_LDFLAGS@ \
+ $(top_builddir)/libmysql/libmysqlclient.la
+mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) \
+ $(top_builddir)/mysys/libmysys.a
+mysql_client_test_SOURCES= mysql_client_test.c
insert_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
select_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
@@ -44,7 +46,7 @@ select_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
DEFS = -DUNDEF_THREADS_HACK
thread_test.o: thread_test.c
- $(COMPILE) -c @MT_INCLUDES@ $(INCLUDES) $<
+ $(COMPILE) -c $(INCLUDES) $<
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/tests/connect_test.c b/tests/connect_test.c
index fd81ad635ad..c68ade9f78f 100644
--- a/tests/connect_test.c
+++ b/tests/connect_test.c
@@ -46,6 +46,7 @@ int main(int argc, char **argv)
perror("");
exit(1);
}
+ sock->reconnect= 1;
if (mysql_select_db(sock,"test"))
{
diff --git a/tests/deadlock_test.c b/tests/deadlock_test.c
index 65a0df5c215..ab8158e0cd8 100644
--- a/tests/deadlock_test.c
+++ b/tests/deadlock_test.c
@@ -227,6 +227,7 @@ int main()
!mysql_real_connect(&sel, host, user, pass, db, 0,0,0 ) ||
!mysql_real_connect(&del_ins, host, user, pass, db, 0,0,0 ))
die("Error in mysql_real_connect(): %s", mysql_error(&lock));
+ lock.reconnect= sel.reconnect= del_ins.reconnect= 1;
permute(order, num_queries);
printf("count = %d\n", count);
diff --git a/tests/grant.pl b/tests/grant.pl
index cd6a2eb80de..4f2bd1a61cb 100644
--- a/tests/grant.pl
+++ b/tests/grant.pl
@@ -201,7 +201,7 @@ safe_query("select * from mysql.db where user = '$opt_user'");
safe_query("grant CREATE,UPDATE,DROP on $opt_database.* to $user");
user_connect(0);
user_query("create table $opt_database.test2 (a int not null)");
-user_query("update test,test2 SET test.a=1 where 1");
+user_query("update test,test2 SET test.a=1 where 1",1);
user_query("update test,test2 SET test.a=test2.a where 1",1);
safe_query("grant SELECT on $opt_database.* to $user");
user_connect(0);
@@ -375,7 +375,7 @@ user_query("delete from $opt_database.test where a=2");
user_query("delete from $opt_database.test where A=2");
user_query("update test set b=5 where b>0");
user_query("update test set a=11 where b>5",1);
-user_query("update test,test2 SET test.b=5 where b>0");
+user_query("update test,test2 SET test.b=5 where b>0",1);
user_query("update test,test2 SET test.a=11 where b>0",1);
user_query("update test,test2 SET test.b=test2.a where b>0",1);
user_query("update test,test2 SET test.b=11 where test2.a>0",1);
diff --git a/tests/insert_test.c b/tests/insert_test.c
index 052c12bfdf0..2b659e9eecb 100644
--- a/tests/insert_test.c
+++ b/tests/insert_test.c
@@ -40,6 +40,7 @@ int main(int argc, char **argv)
perror("");
exit(1);
}
+ mysql.reconnect= 1;
num = atoi(argv[2]);
count = 0;
diff --git a/tests/list_test.c b/tests/list_test.c
index 06bf16d2751..1d50e703133 100644
--- a/tests/list_test.c
+++ b/tests/list_test.c
@@ -43,6 +43,7 @@ int main(int argc, char **argv)
perror("");
exit(1);
}
+ mysql.reconnect= 1;
if (mysql_select_db(sock,argv[1]) < 0)
{
diff --git a/tests/mail_to_db.pl b/tests/mail_to_db.pl
index dc40fb3ede6..5ceda392313 100755
--- a/tests/mail_to_db.pl
+++ b/tests/mail_to_db.pl
@@ -17,7 +17,7 @@ use DBI;
use Getopt::Long;
$| = 1;
-$VER = "2.6";
+$VER = "3.0";
$opt_help = 0;
$opt_version = 0;
@@ -26,7 +26,6 @@ $opt_host = undef();
$opt_port = undef();
$opt_socket = undef();
$opt_db = "mail";
-$opt_table = "mails";
$opt_user = undef();
$opt_password = undef();
$opt_max_mail_size = 65536;
@@ -97,7 +96,7 @@ sub main
print "the my.cnf file. This command is available from the latest MySQL\n";
print "distribution.\n";
}
- GetOptions("help","version","host=s","port=i","socket=s","db=s","table=s",
+ GetOptions("help","version","host=s","port=i","socket=s","db=s",
"user=s","password=s","max_mail_size=i","create","test",
"no_path","debug","stop_on_error","stdin")
|| die "Wrong option! See $progname --help\n";
@@ -123,7 +122,6 @@ sub main
|| die "Couldn't connect: $DBI::errstr\n";
die "You must specify the database; use --db=" if (!defined($opt_db));
- die "You must specify the table; use --table=" if (!defined($opt_table));
create_table($dbh) if ($opt_create);
@@ -218,9 +216,9 @@ sub main
print "Total number of mails:\t\t\t\t";
print $mail_inserted + $ignored;
print " (OK: ";
- print sprintf("%.1f", (($mail_inserted / ($mail_inserted+$ignored)) * 100));
+ print sprintf("%.1f", ($mail_inserted + $ignored) ? (($mail_inserted / ($mail_inserted+$ignored)) * 100) : 0.0);
print "% Ignored: ";
- print sprintf("%.1f", (($ignored / ($mail_inserted + $ignored)) * 100));
+ print sprintf("%.1f", ($mail_inserted + $ignored) ? (($ignored / ($mail_inserted + $ignored)) * 100) : 0);
print "%)\n";
print "################################ End Report ##################################\n";
exit(0);
@@ -232,13 +230,15 @@ sub main
sub create_table
{
- my ($dbh) = @_;
+ my ($dbh)= @_;
my ($sth, $query);
- $query = <<EOF;
-CREATE TABLE $opt_table
+ $query= <<EOF;
+CREATE TABLE my_mail
(
mail_id MEDIUMINT UNSIGNED NOT NULL auto_increment,
+ message_id VARCHAR(255),
+ in_reply_to VARCHAR(255),
date DATETIME NOT NULL,
time_zone VARCHAR(20),
mail_from VARCHAR(120) NOT NULL,
@@ -250,6 +250,8 @@ CREATE TABLE $opt_table
file VARCHAR(64) NOT NULL,
hash INTEGER NOT NULL,
KEY (mail_id),
+ KEY (message_id),
+ KEY (in_reply_to),
PRIMARY KEY (mail_from, date, hash))
TYPE=MyISAM COMMENT=''
EOF
@@ -277,7 +279,7 @@ sub process_mail_file
chop if (substr($_, -1, 1) eq "\r");
if ($type ne "message")
{
- if (/^Reply-To: (.*)/i)
+ if (/^Reply-To:\s*(.*)/i)
{
$type = "reply";
$values{$type} = $1;
@@ -302,14 +304,27 @@ sub process_mail_file
$type = "subject";
$values{$type} = $1;
}
+ elsif (/^Message-Id:\s*(.*)/i)
+ {
+ $type = "message_id";
+ s/^\s*(<.*>)\s*/$1/;
+ $values{$type} = $1;
+ }
+ elsif (/^In-Reply-To:\s*(.*)/i)
+ {
+ $type = "in_reply_to";
+ s/^\s*(<.*>)\s*/$1/;
+ $values{$type} = $1;
+ }
elsif (/^Date: (.*)/i)
{
date_parser($1, \%values, $file_name);
$type = "rubbish";
}
- elsif (/^[\w\W-]+:\s/)
+ # Catch those fields that we don't or can't handle (yet)
+ elsif (/^[\w\W-]+:/)
{
- $type = "rubbish";
+ $type = "rubbish";
}
elsif ($_ eq "")
{
@@ -319,6 +334,10 @@ sub process_mail_file
else
{
s/^\s*/ /;
+ if ($type eq 'message_id' || $type eq 'in_reply_to')
+ {
+ s/^\s*(<.*>)\s*/$1/;
+ }
$values{$type} .= $_;
}
}
@@ -421,8 +440,10 @@ sub update_table
goto restart; # Some mails may have duplicated messages
}
- $q = "INSERT INTO $opt_table (";
+ $q = "INSERT INTO my_mail (";
$q.= "mail_id,";
+ $q.= "message_id,";
+ $q.= "in_reply_to,";
$q.= "date,";
$q.= "time_zone,";
$q.= "mail_from,";
@@ -435,6 +456,12 @@ sub update_table
$q.= "hash";
$q.= ") VALUES (";
$q.= "NULL,";
+ $q.= (defined($values->{'message_id'}) ?
+ $dbh->quote($values->{'message_id'}) : "NULL");
+ $q.= ",";
+ $q.= (defined($values->{'in_reply_to'}) ?
+ $dbh->quote($values->{'in_reply_to'}) : "NULL");
+ $q.= ",";
$q.= "'" . $values->{'date'} . "',";
$q.= (defined($values->{'time_zone'}) ?
$dbh->quote($values->{'time_zone'}) : "NULL");
@@ -575,7 +602,6 @@ Options:
--port=# TCP/IP port to be used with connection.
--socket=... MySQL UNIX socket to be used with connection.
--db=... Database to be used.
---table=... Table name for mails.
--user=... Username for connecting.
--password=... Password for the user.
--stdin Read mails from stdin.
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index cb274682f9b..d484c9af7ee 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -21,6 +21,12 @@
Main author: venu ( venu@mysql.com )
***************************************************************************/
+/*
+ XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
+ DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.
+*/
+
+
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
@@ -30,6 +36,7 @@
#define VER "2.1"
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
+#define MAX_KEY 64
/* set default options */
static int opt_testcase = 0;
@@ -237,6 +244,7 @@ static void client_connect()
fprintf(stdout, "\n Check the connection options using --help or -?\n");
exit(1);
}
+ mysql->reconnect= 1;
if (!opt_silent)
fprintf(stdout, " OK");
@@ -245,7 +253,12 @@ static void client_connect()
mysql_autocommit(mysql, TRUE);
if (!opt_silent)
+ {
+ fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n",
+ mysql_get_server_info(mysql),
+ (ulong) mysql_get_server_version(mysql));
fprintf(stdout, "\n Creating a test database '%s' ...", current_db);
+ }
strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS);
rc= mysql_query(mysql, query);
@@ -510,16 +523,18 @@ int my_process_stmt_result(MYSQL_STMT *stmt)
buffer[i].buffer= (void *) data[i];
buffer[i].is_null= &is_null[i];
}
- my_print_result_metadata(result);
rc= mysql_stmt_bind_result(stmt, buffer);
check_execute(stmt, rc);
+ rc= 1;
+ mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc);
rc= mysql_stmt_store_result(stmt);
check_execute(stmt, rc);
+ my_print_result_metadata(result);
mysql_field_seek(result, 0);
- while (mysql_stmt_fetch(stmt) == 0)
+ while ((rc= mysql_stmt_fetch(stmt)) == 0)
{
if (!opt_silent)
{
@@ -552,6 +567,7 @@ int my_process_stmt_result(MYSQL_STMT *stmt)
}
row_count++;
}
+ DIE_UNLESS(rc == MYSQL_NO_DATA);
if (!opt_silent)
{
if (row_count)
@@ -652,10 +668,12 @@ static void verify_prepare_field(MYSQL_RES *result,
fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)",
field->org_name, org_name);
fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type);
- fprintf(stdout, "\n table :`%s`\t(expected: `%s`)",
- field->table, table);
- fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)",
- field->org_table, org_table);
+ if (table)
+ fprintf(stdout, "\n table :`%s`\t(expected: `%s`)",
+ field->table, table);
+ if (org_table)
+ 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`)",
field->length, length * cs->mbmaxlen);
@@ -675,16 +693,30 @@ static void verify_prepare_field(MYSQL_RES *result,
expect.
*/
if (cs->mbmaxlen == 1)
- DIE_UNLESS(field->type == type);
- DIE_UNLESS(strcmp(field->table, table) == 0);
- DIE_UNLESS(strcmp(field->org_table, org_table) == 0);
+ {
+ if (field->type != type)
+ {
+ fprintf(stderr, "Expected field type: %d, got type: %d\n",
+ (int) type, (int) field->type);
+ DIE_UNLESS(field->type == type);
+ }
+ }
+ if (table)
+ DIE_UNLESS(strcmp(field->table, table) == 0);
+ if (org_table)
+ DIE_UNLESS(strcmp(field->org_table, org_table) == 0);
DIE_UNLESS(strcmp(field->db, db) == 0);
/*
Character set should be taken into account for multibyte encodings, such
as utf8. Field length is calculated as number of characters * maximum
number of bytes a character can occupy.
*/
- DIE_UNLESS(field->length == length * cs->mbmaxlen);
+ if (length && field->length != length * cs->mbmaxlen)
+ {
+ fprintf(stderr, "Expected field length: %d, got length: %d\n",
+ (int) (length * cs->mbmaxlen), (int) field->length);
+ DIE_UNLESS(field->length == length * cs->mbmaxlen);
+ }
if (def)
DIE_UNLESS(strcmp(field->def, def) == 0);
}
@@ -708,8 +740,8 @@ static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count)
{
ulonglong affected_rows= mysql_stmt_affected_rows(stmt);
if (!opt_silent)
- fprintf(stdout, "\n total affected rows: `%lld` (expected: `%lld`)",
- affected_rows, exp_count);
+ fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)",
+ (long) affected_rows, (long) exp_count);
DIE_UNLESS(affected_rows == exp_count);
}
@@ -720,8 +752,8 @@ static void verify_affected_rows(ulonglong exp_count)
{
ulonglong affected_rows= mysql_affected_rows(mysql);
if (!opt_silent)
- fprintf(stdout, "\n total affected rows: `%lld` (expected: `%lld`)",
- affected_rows, exp_count);
+ fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)",
+ (long) affected_rows, (long) exp_count);
DIE_UNLESS(affected_rows == exp_count);
}
@@ -754,8 +786,8 @@ static void execute_prepare_query(const char *query, ulonglong exp_count)
affected_rows= mysql_stmt_affected_rows(stmt);
if (!opt_silent)
- fprintf(stdout, "\n total affected rows: `%lld` (expected: `%lld`)",
- affected_rows, exp_count);
+ fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)",
+ (long) affected_rows, (long) exp_count);
DIE_UNLESS(affected_rows == exp_count);
mysql_stmt_close(stmt);
@@ -803,6 +835,218 @@ static void client_use_result()
}
+/*
+ Accepts arbitrary number of queries and runs them against the database.
+ Used to fill tables for each test.
+*/
+
+void fill_tables(const char **query_list, unsigned query_count)
+{
+ int rc;
+ const char **query;
+ DBUG_ENTER("fill_tables");
+ for (query= query_list; query < query_list + query_count;
+ ++query)
+ {
+ rc= mysql_query(mysql, *query);
+ myquery(rc);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ All state of fetch from one statement: statement handle, out buffers,
+ fetch position.
+ See fetch_n for for the only use case.
+*/
+
+enum { MAX_COLUMN_LENGTH= 255 };
+
+typedef struct st_stmt_fetch
+{
+ const char *query;
+ unsigned stmt_no;
+ MYSQL_STMT *handle;
+ my_bool is_open;
+ MYSQL_BIND *bind_array;
+ char **out_data;
+ unsigned long *out_data_length;
+ unsigned column_count;
+ unsigned row_count;
+} Stmt_fetch;
+
+
+/*
+ Create statement handle, prepare it with statement, execute and allocate
+ fetch buffers.
+*/
+
+void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg,
+ const char *query_arg)
+{
+ unsigned long type= CURSOR_TYPE_READ_ONLY;
+ int rc;
+ unsigned i;
+ MYSQL_RES *metadata;
+ DBUG_ENTER("stmt_fetch_init");
+
+ /* Save query and statement number for error messages */
+ fetch->stmt_no= stmt_no_arg;
+ fetch->query= query_arg;
+
+ fetch->handle= mysql_stmt_init(mysql);
+
+ rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query));
+ check_execute(fetch->handle, rc);
+
+ /*
+ The attribute is sent to server on execute and asks to open read-only
+ for result set
+ */
+ mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE,
+ (const void*) &type);
+
+ rc= mysql_stmt_execute(fetch->handle);
+ check_execute(fetch->handle, rc);
+
+ /* Find out total number of columns in result set */
+ metadata= mysql_stmt_result_metadata(fetch->handle);
+ fetch->column_count= mysql_num_fields(metadata);
+ mysql_free_result(metadata);
+
+ /*
+ Now allocate bind handles and buffers for output data:
+ calloc memory to reduce number of MYSQL_BIND members we need to
+ set up.
+ */
+
+ fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) *
+ fetch->column_count);
+ fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count);
+ fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) *
+ fetch->column_count);
+ for (i= 0; i < fetch->column_count; ++i)
+ {
+ fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH);
+ fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING;
+ fetch->bind_array[i].buffer= fetch->out_data[i];
+ fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH;
+ fetch->bind_array[i].length= fetch->out_data_length + i;
+ }
+
+ mysql_stmt_bind_result(fetch->handle, fetch->bind_array);
+
+ fetch->row_count= 0;
+ fetch->is_open= TRUE;
+
+ /* Ready for reading rows */
+ DBUG_VOID_RETURN;
+}
+
+
+/* Fetch and print one row from cursor */
+
+int stmt_fetch_fetch_row(Stmt_fetch *fetch)
+{
+ int rc;
+ unsigned i;
+ DBUG_ENTER("stmt_fetch_fetch_row");
+
+ if ((rc= mysql_stmt_fetch(fetch->handle)) == 0)
+ {
+ ++fetch->row_count;
+ if (!opt_silent)
+ printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count);
+ for (i= 0; i < fetch->column_count; ++i)
+ {
+ fetch->out_data[i][fetch->out_data_length[i]]= '\0';
+ if (!opt_silent)
+ printf("column %d: %s\n", i+1, fetch->out_data[i]);
+ }
+ }
+ else
+ fetch->is_open= FALSE;
+ DBUG_RETURN(rc);
+}
+
+
+void stmt_fetch_close(Stmt_fetch *fetch)
+{
+ unsigned i;
+ DBUG_ENTER("stmt_fetch_close");
+
+ for (i= 0; i < fetch->column_count; ++i)
+ free(fetch->out_data[i]);
+ free(fetch->out_data);
+ free(fetch->out_data_length);
+ free(fetch->bind_array);
+ mysql_stmt_close(fetch->handle);
+ DBUG_VOID_RETURN;
+}
+
+/*
+ For given array of queries, open query_count cursors and fetch
+ from them in simultaneous manner.
+ In case there was an error in one of the cursors, continue
+ reading from the rest.
+*/
+
+my_bool fetch_n(const char **query_list, unsigned query_count)
+{
+ unsigned open_statements= query_count;
+ int rc, error_count= 0;
+ Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) *
+ query_count);
+ Stmt_fetch *fetch;
+ DBUG_ENTER("fetch_n");
+
+ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+ {
+ /* Init will exit(1) in case of error */
+ stmt_fetch_init(fetch, fetch - fetch_array,
+ query_list[fetch - fetch_array]);
+ }
+
+ while (open_statements)
+ {
+ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+ {
+ if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch)))
+ {
+ open_statements--;
+ /*
+ We try to fetch from the rest of the statements in case of
+ error
+ */
+ if (rc != MYSQL_NO_DATA)
+ {
+ fprintf(stderr,
+ "Got error reading rows from statement %d,\n"
+ "query is: %s,\n"
+ "error message: %s", (int) (fetch - fetch_array),
+ fetch->query,
+ mysql_stmt_error(fetch->handle));
+ error_count++;
+ }
+ }
+ }
+ }
+ if (error_count)
+ fprintf(stderr, "Fetch FAILED");
+ else
+ {
+ unsigned total_row_count= 0;
+ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+ total_row_count+= fetch->row_count;
+ if (!opt_silent)
+ printf("Success, total rows fetched: %d\n", total_row_count);
+ }
+ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+ stmt_fetch_close(fetch);
+ free(fetch_array);
+ DBUG_RETURN(error_count != 0);
+}
+
/* Separate thread query to test some cases */
static my_bool thread_query(char *query)
@@ -826,6 +1070,7 @@ static my_bool thread_query(char *query)
error= 1;
goto end;
}
+ l_mysql->reconnect= 1;
if (mysql_query(l_mysql, (char *)query))
{
fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql));
@@ -1185,7 +1430,9 @@ static void test_prepare_field_result()
"t1", "test_prepare_field_result", current_db, 10, 0);
verify_prepare_field(result, 3, "ts_c", "ts_c", MYSQL_TYPE_TIMESTAMP,
"t1", "test_prepare_field_result", current_db, 19, 0);
- verify_prepare_field(result, 4, "char_c", "char_c", MYSQL_TYPE_VAR_STRING,
+ verify_prepare_field(result, 4, "char_c", "char_c",
+ (mysql_get_server_version(mysql) <= 50000 ?
+ MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING),
"t1", "test_prepare_field_result", current_db, 4, 0);
verify_field_count(result, 5);
@@ -1239,6 +1486,7 @@ static void test_prepare()
double double_data, o_double_data;
ulong length[7], len;
my_bool is_null[7];
+ char llbuf[22];
MYSQL_BIND bind[7];
myheader("test_prepare");
@@ -1353,11 +1601,11 @@ static void test_prepare()
if (!opt_silent)
{
fprintf(stdout, "\n");
-
fprintf(stdout, "\n\t tiny : %d (%lu)", tiny_data, length[0]);
fprintf(stdout, "\n\t short : %d (%lu)", small_data, length[3]);
fprintf(stdout, "\n\t int : %d (%lu)", int_data, length[2]);
- fprintf(stdout, "\n\t big : %lld (%lu)", big_data, length[4]);
+ fprintf(stdout, "\n\t big : %s (%lu)", llstr(big_data, llbuf),
+ length[4]);
fprintf(stdout, "\n\t float : %f (%lu)", real_data, length[5]);
fprintf(stdout, "\n\t double : %f (%lu)", double_data, length[6]);
@@ -1696,6 +1944,7 @@ static void test_fetch_null()
myquery(rc);
/* fetch */
+ bzero(bind, sizeof(bind));
for (i= 0; i < (int) array_elements(bind); i++)
{
bind[i].buffer_type= MYSQL_TYPE_LONG;
@@ -2049,7 +2298,9 @@ session_id char(9) NOT NULL, \
"(\"abj\", 1, 2, 3, 2003-08-30), "
"(\"abk\", 1, 2, 3, 2003-08-30), "
"(\"abl\", 1, 2, 3, 2003-08-30), "
- "(\"abq\", 1, 2, 3, 2003-08-30), "
+ "(\"abq\", 1, 2, 3, 2003-08-30) ");
+ myquery(rc);
+ rc= mysql_query(mysql, "INSERT INTO test_select VALUES "
"(\"abw\", 1, 2, 3, 2003-08-30), "
"(\"abe\", 1, 2, 3, 2003-08-30), "
"(\"abr\", 1, 2, 3, 2003-08-30), "
@@ -2764,11 +3015,13 @@ static void test_long_data_str1()
bind[0].buffer= (void *) &data; /* this buffer won't be altered */
bind[0].buffer_length= 16;
bind[0].length= &blob_length;
+ bind[0].error= &bind[0].error_value;
rc= mysql_stmt_bind_result(stmt, bind);
data[16]= 0;
rc= mysql_stmt_fetch(stmt);
- DIE_UNLESS(rc == 0);
+ DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED);
+ DIE_UNLESS(bind[0].error_value);
DIE_UNLESS(strlen(data) == 16);
DIE_UNLESS(blob_length == max_blob_length);
@@ -3105,7 +3358,7 @@ static void test_bind_result()
MYSQL_STMT *stmt;
int rc;
int nData;
- ulong length, length1;
+ ulong length1;
char szData[100];
MYSQL_BIND bind[2];
my_bool is_null[2];
@@ -3132,10 +3385,10 @@ static void test_bind_result()
/* fetch */
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (void *) &nData; /* integer data */
bind[0].is_null= &is_null[0];
- bind[0].length= 0;
bind[1].buffer_type= MYSQL_TYPE_STRING;
bind[1].buffer= szData; /* string data */
@@ -3170,7 +3423,6 @@ static void test_bind_result()
DIE_UNLESS(strcmp(szData, "MySQL") == 0);
DIE_UNLESS(length1 == 5);
- length= 99;
rc= mysql_stmt_fetch(stmt);
check_execute(stmt, rc);
@@ -3204,7 +3456,7 @@ static void test_bind_result_ext()
MYSQL_BIND bind[8];
ulong length[8];
my_bool is_null[8];
-
+ char llbuf[22];
myheader("test_bind_result_ext");
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bind_result");
@@ -3226,6 +3478,7 @@ static void test_bind_result_ext()
rc= mysql_commit(mysql);
myquery(rc);
+ bzero(bind, sizeof(bind));
for (i= 0; i < (int) array_elements(bind); i++)
{
bind[i].length= &length[i];
@@ -3277,7 +3530,7 @@ static void test_bind_result_ext()
fprintf(stdout, "\n data (tiny) : %d", t_data);
fprintf(stdout, "\n data (short) : %d", s_data);
fprintf(stdout, "\n data (int) : %d", i_data);
- fprintf(stdout, "\n data (big) : %lld", b_data);
+ fprintf(stdout, "\n data (big) : %s", llstr(b_data, llbuf));
fprintf(stdout, "\n data (float) : %f", f_data);
fprintf(stdout, "\n data (double) : %f", d_data);
@@ -3344,37 +3597,46 @@ static void test_bind_result_ext1()
rc= mysql_commit(mysql);
myquery(rc);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_STRING;
bind[0].buffer= (void *) t_data;
bind[0].buffer_length= sizeof(t_data);
+ bind[0].error= &bind[0].error_value;
bind[1].buffer_type= MYSQL_TYPE_FLOAT;
bind[1].buffer= (void *)&s_data;
bind[1].buffer_length= 0;
+ bind[1].error= &bind[1].error_value;
bind[2].buffer_type= MYSQL_TYPE_SHORT;
bind[2].buffer= (void *)&i_data;
bind[2].buffer_length= 0;
+ bind[2].error= &bind[2].error_value;
bind[3].buffer_type= MYSQL_TYPE_TINY;
bind[3].buffer= (void *)&b_data;
bind[3].buffer_length= 0;
+ bind[3].error= &bind[3].error_value;
bind[4].buffer_type= MYSQL_TYPE_LONG;
bind[4].buffer= (void *)&f_data;
bind[4].buffer_length= 0;
+ bind[4].error= &bind[4].error_value;
bind[5].buffer_type= MYSQL_TYPE_STRING;
bind[5].buffer= (void *)d_data;
bind[5].buffer_length= sizeof(d_data);
+ bind[5].error= &bind[5].error_value;
bind[6].buffer_type= MYSQL_TYPE_LONG;
bind[6].buffer= (void *)&bData;
bind[6].buffer_length= 0;
+ bind[6].error= &bind[6].error_value;
bind[7].buffer_type= MYSQL_TYPE_DOUBLE;
bind[7].buffer= (void *)&szData;
bind[7].buffer_length= 0;
+ bind[7].error= &bind[7].error_value;
for (i= 0; i < array_elements(bind); i++)
{
@@ -3392,7 +3654,8 @@ static void test_bind_result_ext1()
check_execute(stmt, rc);
rc= mysql_stmt_fetch(stmt);
- check_execute(stmt, rc);
+ printf("rc=%d\n", rc);
+ DIE_UNLESS(rc == 0);
if (!opt_silent)
{
@@ -3627,6 +3890,7 @@ static void test_fetch_date()
rc= mysql_commit(mysql);
myquery(rc);
+ bzero(bind, sizeof(bind));
for (i= 0; i < array_elements(bind); i++)
{
bind[i].is_null= &is_null[i];
@@ -3908,40 +4172,40 @@ static void test_prepare_ext()
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prepare_ext");
myquery(rc);
- sql= (char *)"CREATE TABLE test_prepare_ext\
- (\
- 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, \
- 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, \
- c29 longblob, \
- c30 longtext, \
- c31 enum('one', 'two', 'three'), \
- c32 set('monday', 'tuesday', 'wednesday'))";
+ sql= (char *)"CREATE TABLE test_prepare_ext"
+ "("
+ " 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,"
+ " 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,"
+ " c29 longblob,"
+ " c30 longtext,"
+ " c31 enum('one', 'two', 'three'),"
+ " c32 set('monday', 'tuesday', 'wednesday'))";
rc= mysql_query(mysql, sql);
myquery(rc);
@@ -4307,6 +4571,7 @@ static void test_stmt_close()
myerror("connection failed");
exit(1);
}
+ lmysql->reconnect= 1;
if (!opt_silent)
fprintf(stdout, " OK");
@@ -4428,8 +4693,6 @@ static void test_set_variable()
get_bind[1].buffer_type= MYSQL_TYPE_LONG;
get_bind[1].buffer= (void *)&get_count;
- get_bind[1].is_null= 0;
- get_bind[1].length= 0;
rc= mysql_stmt_execute(stmt1);
check_execute(stmt1, rc);
@@ -5033,7 +5296,7 @@ static void test_manual_sample()
affected_rows= mysql_stmt_affected_rows(stmt);
if (!opt_silent)
- fprintf(stdout, "\n total affected rows: %lld", affected_rows);
+ fprintf(stdout, "\n total affected rows: %ld", (ulong) affected_rows);
if (affected_rows != 1) /* validate affected rows */
{
fprintf(stderr, "\n invalid affected rows by MySQL");
@@ -5058,7 +5321,7 @@ static void test_manual_sample()
affected_rows= mysql_stmt_affected_rows(stmt);
if (!opt_silent)
- fprintf(stdout, "\n total affected rows: %lld", affected_rows);
+ fprintf(stdout, "\n total affected rows: %ld", (ulong) affected_rows);
if (affected_rows != 1) /* validate affected rows */
{
fprintf(stderr, "\n invalid affected rows by MySQL");
@@ -5093,7 +5356,6 @@ static void test_prepare_alter()
{
MYSQL_STMT *stmt;
int rc, id;
- long length;
MYSQL_BIND bind[1];
my_bool is_null;
@@ -5128,7 +5390,6 @@ static void test_prepare_alter()
check_execute(stmt, rc);
id= 30;
- length= 0;
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
@@ -5199,6 +5460,7 @@ DROP TABLE IF EXISTS test_multi_tab";
fprintf(stdout, "\n connection failed(%s)", mysql_error(mysql_local));
exit(1);
}
+ mysql_local->reconnect= 1;
rc= mysql_query(mysql_local, query);
myquery(rc);
@@ -5213,9 +5475,9 @@ DROP TABLE IF EXISTS test_multi_tab";
mysql_free_result(result);
}
else if (!opt_silent)
- fprintf(stdout, "OK, %lld row(s) affected, %d warning(s)\n",
- mysql_affected_rows(mysql_local),
- mysql_warning_count(mysql_local));
+ fprintf(stdout, "OK, %ld row(s) affected, %ld warning(s)\n",
+ (ulong) mysql_affected_rows(mysql_local),
+ (ulong) mysql_warning_count(mysql_local));
exp_value= (uint) mysql_affected_rows(mysql_local);
if (rows[count] != exp_value)
@@ -5307,6 +5569,7 @@ static void test_prepare_multi_statements()
fprintf(stderr, "\n connection failed(%s)", mysql_error(mysql_local));
exit(1);
}
+ mysql_local->reconnect= 1;
strmov(query, "select 1; select 'another value'");
stmt= mysql_simple_prepare(mysql_local, query);
check_stmt_r(stmt);
@@ -5344,6 +5607,7 @@ static void test_store_result()
myquery(rc);
/* fetch */
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (void *) &nData; /* integer data */
bind[0].length= &length;
@@ -5593,6 +5857,7 @@ static void test_subselect()
MYSQL_STMT *stmt;
int rc, id;
MYSQL_BIND bind[1];
+ DBUG_ENTER("test_subselect");
myheader("test_subselect");
@@ -5698,6 +5963,7 @@ static void test_subselect()
DIE_UNLESS(rc == MYSQL_NO_DATA);
mysql_stmt_close(stmt);
+ DBUG_VOID_RETURN;
}
@@ -5805,7 +6071,7 @@ static void test_bind_date_conv(uint row_count)
for (count= 0; count < row_count; count++)
{
rc= mysql_stmt_fetch(stmt);
- check_execute(stmt, rc);
+ DIE_UNLESS(rc == 0 || rc == MYSQL_DATA_TRUNCATED);
if (!opt_silent)
fprintf(stdout, "\n");
@@ -5821,14 +6087,8 @@ static void test_bind_date_conv(uint row_count)
DIE_UNLESS(tm[i].day == 0 || tm[i].day == day+count);
DIE_UNLESS(tm[i].hour == 0 || tm[i].hour == hour+count);
-#ifdef NOT_USED
- /*
- minute causes problems from date<->time, don't assert, instead
- validate separatly in another routine
- */
DIE_UNLESS(tm[i].minute == 0 || tm[i].minute == minute+count);
DIE_UNLESS(tm[i].second == 0 || tm[i].second == sec+count);
-#endif
DIE_UNLESS(tm[i].second_part == 0 ||
tm[i].second_part == second_part+count);
}
@@ -6059,13 +6319,15 @@ static void test_buffers()
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
- bzero(buffer, 20); /* Avoid overruns in printf() */
+ bzero(buffer, sizeof(buffer)); /* Avoid overruns in printf() */
+ bzero(bind, sizeof(bind));
bind[0].length= &length;
bind[0].is_null= &is_null;
bind[0].buffer_length= 1;
bind[0].buffer_type= MYSQL_TYPE_STRING;
bind[0].buffer= (void *)buffer;
+ bind[0].error= &bind[0].error_value;
rc= mysql_stmt_bind_result(stmt, bind);
check_execute(stmt, rc);
@@ -6075,7 +6337,8 @@ static void test_buffers()
buffer[1]= 'X';
rc= mysql_stmt_fetch(stmt);
- check_execute(stmt, rc);
+ DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED);
+ DIE_UNLESS(bind[0].error_value);
if (!opt_silent)
fprintf(stdout, "\n data: %s (%lu)", buffer, length);
DIE_UNLESS(buffer[0] == 'M');
@@ -6109,7 +6372,8 @@ static void test_buffers()
check_execute(stmt, rc);
rc= mysql_stmt_fetch(stmt);
- check_execute(stmt, rc);
+ DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED);
+ DIE_UNLESS(bind[0].error_value);
if (!opt_silent)
fprintf(stdout, "\n data: %s (%lu)", buffer, length);
DIE_UNLESS(strncmp(buffer, "Popula", 6) == 0);
@@ -6246,10 +6510,9 @@ static void test_fetch_nobuffs()
fprintf(stdout, "\n total rows : %d", rc);
DIE_UNLESS(rc == 1);
+ bzero(bind, sizeof(MYSQL_BIND));
bind[0].buffer_type= MYSQL_TYPE_STRING;
bind[0].buffer= (void *)str[0];
- bind[0].is_null= 0;
- bind[0].length= 0;
bind[0].buffer_length= sizeof(str[0]);
bind[1]= bind[2]= bind[3]= bind[0];
bind[1].buffer= (void *)str[1];
@@ -6294,7 +6557,7 @@ static void test_ushort_bug()
ulonglong longlong_value;
int rc;
uchar tiny_value;
-
+ char llbuf[22];
myheader("test_ushort_bug");
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_ushort");
@@ -6306,7 +6569,8 @@ static void test_ushort_bug()
d smallint unsigned)");
myquery(rc);
- rc= mysql_query(mysql, "INSERT INTO test_ushort VALUES(35999, 35999, 35999, 200)");
+ rc= mysql_query(mysql,
+ "INSERT INTO test_ushort VALUES(35999, 35999, 35999, 200)");
myquery(rc);
@@ -6316,24 +6580,23 @@ static void test_ushort_bug()
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_SHORT;
bind[0].buffer= (void *)&short_value;
- bind[0].is_null= 0;
+ bind[0].is_unsigned= TRUE;
bind[0].length= &s_length;
bind[1].buffer_type= MYSQL_TYPE_LONG;
bind[1].buffer= (void *)&long_value;
- bind[1].is_null= 0;
bind[1].length= &l_length;
bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
bind[2].buffer= (void *)&longlong_value;
- bind[2].is_null= 0;
bind[2].length= &ll_length;
bind[3].buffer_type= MYSQL_TYPE_TINY;
bind[3].buffer= (void *)&tiny_value;
- bind[3].is_null= 0;
+ bind[3].is_unsigned= TRUE;
bind[3].length= &t_length;
rc= mysql_stmt_bind_result(stmt, bind);
@@ -6346,7 +6609,8 @@ static void test_ushort_bug()
{
fprintf(stdout, "\n ushort : %d (%ld)", short_value, s_length);
fprintf(stdout, "\n ulong : %lu (%ld)", (ulong) long_value, l_length);
- fprintf(stdout, "\n longlong : %lld (%ld)", longlong_value, ll_length);
+ fprintf(stdout, "\n longlong : %s (%ld)", llstr(longlong_value, llbuf),
+ ll_length);
fprintf(stdout, "\n tinyint : %d (%ld)", tiny_value, t_length);
}
@@ -6381,6 +6645,7 @@ static void test_sshort_bug()
ulonglong longlong_value;
int rc;
uchar tiny_value;
+ char llbuf[22];
myheader("test_sshort_bug");
@@ -6403,24 +6668,22 @@ static void test_sshort_bug()
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_SHORT;
bind[0].buffer= (void *)&short_value;
- bind[0].is_null= 0;
bind[0].length= &s_length;
bind[1].buffer_type= MYSQL_TYPE_LONG;
bind[1].buffer= (void *)&long_value;
- bind[1].is_null= 0;
bind[1].length= &l_length;
bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
bind[2].buffer= (void *)&longlong_value;
- bind[2].is_null= 0;
bind[2].length= &ll_length;
bind[3].buffer_type= MYSQL_TYPE_TINY;
bind[3].buffer= (void *)&tiny_value;
- bind[3].is_null= 0;
+ bind[3].is_unsigned= TRUE;
bind[3].length= &t_length;
rc= mysql_stmt_bind_result(stmt, bind);
@@ -6433,7 +6696,8 @@ static void test_sshort_bug()
{
fprintf(stdout, "\n sshort : %d (%ld)", short_value, s_length);
fprintf(stdout, "\n slong : %ld (%ld)", (long) long_value, l_length);
- fprintf(stdout, "\n longlong : %lld (%ld)", longlong_value, ll_length);
+ fprintf(stdout, "\n longlong : %s (%ld)", llstr(longlong_value, llbuf),
+ ll_length);
fprintf(stdout, "\n tinyint : %d (%ld)", tiny_value, t_length);
}
@@ -6468,6 +6732,7 @@ static void test_stiny_bug()
ulonglong longlong_value;
int rc;
uchar tiny_value;
+ char llbuf[22];
myheader("test_stiny_bug");
@@ -6490,24 +6755,21 @@ static void test_stiny_bug()
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_SHORT;
bind[0].buffer= (void *)&short_value;
- bind[0].is_null= 0;
bind[0].length= &s_length;
bind[1].buffer_type= MYSQL_TYPE_LONG;
bind[1].buffer= (void *)&long_value;
- bind[1].is_null= 0;
bind[1].length= &l_length;
bind[2].buffer_type= MYSQL_TYPE_LONGLONG;
bind[2].buffer= (void *)&longlong_value;
- bind[2].is_null= 0;
bind[2].length= &ll_length;
bind[3].buffer_type= MYSQL_TYPE_TINY;
bind[3].buffer= (void *)&tiny_value;
- bind[3].is_null= 0;
bind[3].length= &t_length;
rc= mysql_stmt_bind_result(stmt, bind);
@@ -6520,7 +6782,8 @@ static void test_stiny_bug()
{
fprintf(stdout, "\n sshort : %d (%ld)", short_value, s_length);
fprintf(stdout, "\n slong : %ld (%ld)", (long) long_value, l_length);
- fprintf(stdout, "\n longlong : %lld (%ld)", longlong_value, ll_length);
+ fprintf(stdout, "\n longlong : %s (%ld)", llstr(longlong_value, llbuf),
+ ll_length);
fprintf(stdout, "\n tinyint : %d (%ld)", tiny_value, t_length);
}
@@ -6600,10 +6863,10 @@ static void test_field_misc()
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_STRING;
bind[0].buffer= table_type;
bind[0].length= &type_length;
- bind[0].is_null= 0;
bind[0].buffer_length= NAME_LEN;
rc= mysql_stmt_bind_result(stmt, bind);
@@ -6633,7 +6896,8 @@ static void test_field_misc()
verify_prepare_field(result, 0,
"@@table_type", "", /* field and its org name */
- MYSQL_TYPE_STRING, /* field type */
+ mysql_get_server_version(mysql) <= 50000 ?
+ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
"", "", /* table and its org name */
"", type_length, 0); /* db name, length */
@@ -6673,10 +6937,10 @@ static void test_field_misc()
DIE_UNLESS(1 == my_process_stmt_result(stmt));
verify_prepare_field(result, 0,
- "@@max_allowed_packet", "", /* field and its org name */
+ "@@max_allowed_packet", "", /* field and its org name */
MYSQL_TYPE_LONGLONG, /* field type */
"", "", /* table and its org name */
- "", 10, 0); /* db name, length */
+ "", 10, 0); /* db name, length */
mysql_free_result(result);
mysql_stmt_close(stmt);
@@ -6782,6 +7046,7 @@ static void test_set_option()
bug #89 (reported by mark@mysql.com)
*/
+#ifndef EMBEDDED_LIBRARY
static void test_prepare_grant()
{
int rc;
@@ -6833,6 +7098,7 @@ static void test_prepare_grant()
mysql_close(lmysql);
exit(1);
}
+ lmysql->reconnect= 1;
if (!opt_silent)
fprintf(stdout, " OK");
@@ -6873,7 +7139,7 @@ static void test_prepare_grant()
}
}
-
+#endif
/*
Test a crash when invalid/corrupted .frm is used in the
@@ -6908,11 +7174,10 @@ static void test_frm_bug()
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_STRING;
bind[0].buffer= data_dir;
bind[0].buffer_length= FN_REFLEN;
- bind[0].is_null= 0;
- bind[0].length= 0;
bind[1]= bind[0];
rc= mysql_stmt_bind_result(stmt, bind);
@@ -6999,7 +7264,7 @@ static void test_decimal_bug()
*/
bzero((char*) bind, sizeof(bind));
- bind[0].buffer_type= MYSQL_TYPE_STRING;
+ bind[0].buffer_type= MYSQL_TYPE_NEWDECIMAL;
bind[0].buffer= (void *)data;
bind[0].buffer_length= 25;
bind[0].is_null= &is_null;
@@ -7108,23 +7373,33 @@ static void test_explain_bug()
mysql_num_fields(result));
DIE_UNLESS(6 == mysql_num_fields(result));
- verify_prepare_field(result, 0, "Field", "", MYSQL_TYPE_VAR_STRING,
- "", "", "", NAME_LEN, 0);
+ verify_prepare_field(result, 0, "Field", "COLUMN_NAME",
+ mysql_get_server_version(mysql) <= 50000 ?
+ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+ 0, 0, "", 64, 0);
- verify_prepare_field(result, 1, "Type", "", MYSQL_TYPE_VAR_STRING,
- "", "", "", 40, 0);
+ verify_prepare_field(result, 1, "Type", "COLUMN_TYPE",
+ MYSQL_TYPE_BLOB, 0, 0, "", 0, 0);
- verify_prepare_field(result, 2, "Null", "", MYSQL_TYPE_VAR_STRING,
- "", "", "", 1, 0);
+ verify_prepare_field(result, 2, "Null", "IS_NULLABLE",
+ mysql_get_server_version(mysql) <= 50000 ?
+ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+ 0, 0, "", 3, 0);
- verify_prepare_field(result, 3, "Key", "", MYSQL_TYPE_VAR_STRING,
- "", "", "", 3, 0);
+ verify_prepare_field(result, 3, "Key", "COLUMN_KEY",
+ mysql_get_server_version(mysql) <= 50000 ?
+ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+ 0, 0, "", 3, 0);
- verify_prepare_field(result, 4, "Default", "", MYSQL_TYPE_VAR_STRING,
- "", "", "", NAME_LEN, 0);
+ verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT",
+ mysql_get_server_version(mysql) <= 50000 ?
+ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+ 0, 0, "", 64, 0);
- verify_prepare_field(result, 5, "Extra", "", MYSQL_TYPE_VAR_STRING,
- "", "", "", 20, 0);
+ verify_prepare_field(result, 5, "Extra", "EXTRA",
+ mysql_get_server_version(mysql) <= 50000 ?
+ MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING,
+ 0, 0, "", 20, 0);
mysql_free_result(result);
mysql_stmt_close(stmt);
@@ -7159,7 +7434,7 @@ static void test_explain_bug()
"", "", "", 10, 0);
verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING,
- "", "", "", NAME_LEN*64, 0);
+ "", "", "", NAME_LEN*MAX_KEY, 0);
verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN, 0);
@@ -7268,6 +7543,7 @@ static void test_drop_temp()
mysql_close(lmysql);
exit(1);
}
+ lmysql->reconnect= 1;
if (!opt_silent)
fprintf(stdout, " OK");
@@ -7480,13 +7756,13 @@ static void test_logs()
if (!opt_silent)
{
- fprintf(stdout, "\n id : %d", id);
- fprintf(stdout, "\n name : %s(%ld)", data, length);
+ fprintf(stdout, "id : %d\n", id);
+ fprintf(stdout, "name : %s(%ld)\n", data, length);
}
DIE_UNLESS(id == 9876);
- DIE_UNLESS(length == 19); /* Due to VARCHAR(20) */
- DIE_UNLESS(strcmp(data, "MySQL - Open Source") == 0);
+ DIE_UNLESS(length == 19 || length == 20); /* Due to VARCHAR(20) */
+ DIE_UNLESS(is_prefix(data, "MySQL - Open Source") == 1);
rc= mysql_stmt_fetch(stmt);
check_execute(stmt, rc);
@@ -7632,17 +7908,13 @@ static void test_fetch_seek()
stmt= mysql_simple_prepare(mysql, "select * from t1");
check_stmt(stmt);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (void *)&c1;
- bind[0].buffer_length= 0;
- bind[0].is_null= 0;
- bind[0].length= 0;
bind[1].buffer_type= MYSQL_TYPE_STRING;
bind[1].buffer= (void *)c2;
bind[1].buffer_length= sizeof(c2);
- bind[1].is_null= 0;
- bind[1].length= 0;
bind[2]= bind[1];
bind[2].buffer= (void *)c3;
@@ -7732,6 +8004,7 @@ static void test_fetch_offset()
stmt= mysql_simple_prepare(mysql, "select * from t1");
check_stmt(stmt);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_STRING;
bind[0].buffer= (void *)data;
bind[0].buffer_length= 11;
@@ -7818,6 +8091,7 @@ static void test_fetch_column()
stmt= mysql_simple_prepare(mysql, "select * from t1 order by c2 desc");
check_stmt(stmt);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (void *)&bc1;
bind[0].buffer_length= 0;
@@ -8065,10 +8339,9 @@ static void test_free_result()
stmt= mysql_simple_prepare(mysql, "select * from test_free_result");
check_stmt(stmt);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (void *)&bc1;
- bind[0].buffer_length= 0;
- bind[0].is_null= 0;
bind[0].length= &bl1;
rc= mysql_stmt_execute(stmt);
@@ -8146,6 +8419,7 @@ static void test_free_store_result()
stmt= mysql_simple_prepare(mysql, "select * from test_free_result");
check_stmt(stmt);
+ bzero(bind, sizeof(bind));
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (void *)&bc1;
bind[0].buffer_length= 0;
@@ -8536,10 +8810,6 @@ static void test_bug1500()
rc= my_process_stmt_result(stmt);
DIE_UNLESS(rc == 1);
- /*
- FIXME If we comment out next string server will crash too :(
- This is another manifestation of bug #1663
- */
mysql_stmt_close(stmt);
/* This should work too */
@@ -8710,7 +8980,7 @@ static void test_subqueries()
int rc, i;
const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s, (a-1, b-1) in (select a, b from t2) as in_row_s FROM t1, (select a x, b y from t2) tt WHERE x=a";
- myheader("test_subquery");
+ myheader("test_subqueries");
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
myquery(rc);
@@ -8761,7 +9031,7 @@ static void test_distinct()
const char *query=
"SELECT 2+count(distinct b), group_concat(a) FROM t1 group by a";
- myheader("test_subquery");
+ myheader("test_distinct");
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
myquery(rc);
@@ -9559,7 +9829,7 @@ static void test_bug3035()
{
MYSQL_STMT *stmt;
int rc;
- MYSQL_BIND bind_array[12];
+ MYSQL_BIND bind_array[12], *bind= bind_array, *bind_end= bind + 12;
int8 int8_val;
uint8 uint8_val;
int16 int16_val;
@@ -9612,6 +9882,9 @@ static void test_bug3035()
bzero(bind_array, sizeof(bind_array));
+ for (bind= bind_array; bind < bind_end; bind++)
+ bind->error= &bind->error_value;
+
bind_array[0].buffer_type= MYSQL_TYPE_TINY;
bind_array[0].buffer= (void *) &int8_val;
@@ -9717,7 +9990,15 @@ static void test_bug3035()
DIE_UNLESS(!strcmp(ulonglong_as_string, "0"));
rc= mysql_stmt_fetch(stmt);
- check_execute(stmt, rc);
+
+ if (!opt_silent)
+ {
+ printf("Truncation mask: ");
+ for (bind= bind_array; bind < bind_end; bind++)
+ printf("%d", (int) bind->error_value);
+ printf("\n");
+ }
+ DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED || rc == 0);
DIE_UNLESS(int8_val == int8_max);
DIE_UNLESS(uint8_val == uint8_max);
@@ -10500,6 +10781,433 @@ static void test_bug4030()
mysql_stmt_close(stmt);
}
+static void test_view()
+{
+ MYSQL_STMT *stmt;
+ int rc, i;
+ MYSQL_BIND bind[1];
+ char str_data[50];
+ ulong length = 0L;
+ long is_null = 0L;
+ const char *query=
+ "SELECT COUNT(*) FROM v1 WHERE SERVERNAME=?";
+
+ myheader("test_view");
+
+ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2,t3,v1");
+ myquery(rc);
+
+ rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1,t2,t3");
+ myquery(rc);
+ rc= mysql_query(mysql,"CREATE TABLE t1 ("
+ " SERVERGRP varchar(20) NOT NULL default '', "
+ " DBINSTANCE varchar(20) NOT NULL default '', "
+ " PRIMARY KEY (SERVERGRP)) "
+ " CHARSET=latin1 collate=latin1_bin");
+ myquery(rc);
+ rc= mysql_query(mysql,"CREATE TABLE t2 ("
+ " SERVERNAME varchar(20) NOT NULL, "
+ " SERVERGRP varchar(20) NOT NULL, "
+ " PRIMARY KEY (SERVERNAME)) "
+ " CHARSET=latin1 COLLATE latin1_bin");
+ myquery(rc);
+ rc= mysql_query(mysql,
+ "CREATE TABLE t3 ("
+ " SERVERGRP varchar(20) BINARY NOT NULL, "
+ " TABNAME varchar(30) NOT NULL, MAPSTATE char(1) NOT NULL, "
+ " ACTSTATE char(1) NOT NULL , "
+ " LOCAL_NAME varchar(30) NOT NULL, "
+ " CHG_DATE varchar(8) NOT NULL default '00000000', "
+ " CHG_TIME varchar(6) NOT NULL default '000000', "
+ " MXUSER varchar(12) NOT NULL default '', "
+ " PRIMARY KEY (SERVERGRP, TABNAME, MAPSTATE, ACTSTATE, "
+ " LOCAL_NAME)) CHARSET=latin1 COLLATE latin1_bin");
+ myquery(rc);
+ rc= mysql_query(mysql,"CREATE VIEW v1 AS select sql_no_cache"
+ " T0001.SERVERNAME AS SERVERNAME, T0003.TABNAME AS"
+ " TABNAME,T0003.LOCAL_NAME AS LOCAL_NAME,T0002.DBINSTANCE AS"
+ " DBINSTANCE from t2 T0001 join t1 T0002 join t3 T0003 where"
+ " ((T0002.SERVERGRP = T0001.SERVERGRP) and"
+ " (T0002.SERVERGRP = T0003.SERVERGRP)"
+ " and (T0003.MAPSTATE = _latin1'A') and"
+ " (T0003.ACTSTATE = _latin1' '))");
+ myquery(rc);
+
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ check_execute(stmt, rc);
+
+ strcpy(str_data, "TEST");
+ bind[0].buffer_type= FIELD_TYPE_STRING;
+ bind[0].buffer= (char *)&str_data;
+ bind[0].buffer_length= 50;
+ bind[0].length= &length;
+ length= 4;
+ bind[0].is_null= (char*)&is_null;
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt,rc);
+
+ for (i= 0; i < 3; i++)
+ {
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ assert(1 == my_process_stmt_result(stmt));
+ }
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "DROP TABLE t1,t2,t3");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP VIEW v1");
+ myquery(rc);
+}
+
+
+static void test_view_where()
+{
+ MYSQL_STMT *stmt;
+ int rc, i;
+ const char *query=
+ "select v1.c,v2.c from v1, v2";
+
+ myheader("test_view_where");
+
+ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1,v2");
+ myquery(rc);
+
+ rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,v2,t1");
+ myquery(rc);
+ rc= mysql_query(mysql,"CREATE TABLE t1 (a int, b int)");
+ myquery(rc);
+ rc= mysql_query(mysql,"insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10)");
+ myquery(rc);
+ rc= mysql_query(mysql,"create view v1 (c) as select b from t1 where a<3");
+ myquery(rc);
+ rc= mysql_query(mysql,"create view v2 (c) as select b from t1 where a>=3");
+ myquery(rc);
+
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ check_execute(stmt, rc);
+
+ for (i= 0; i < 3; i++)
+ {
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ assert(4 == my_process_stmt_result(stmt));
+ }
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP VIEW v1, v2");
+ myquery(rc);
+}
+
+
+static void test_view_2where()
+{
+ MYSQL_STMT *stmt;
+ int rc, i;
+ MYSQL_BIND bind[8];
+ char parms[8][100];
+ ulong length[8];
+ const char *query=
+ "select relid, report, handle, log_group, username, variant, type, "
+ "version, erfdat, erftime, erfname, aedat, aetime, aename, dependvars, "
+ "inactive from V_LTDX where mandt = ? and relid = ? and report = ? and "
+ "handle = ? and log_group = ? and username in ( ? , ? ) and type = ?";
+
+ myheader("test_view_2where");
+
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS LTDX");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP VIEW IF EXISTS V_LTDX");
+ myquery(rc);
+ rc= mysql_query(mysql,
+ "CREATE TABLE LTDX (MANDT char(3) NOT NULL default '000', "
+ " RELID char(2) NOT NULL, REPORT varchar(40) NOT NULL,"
+ " HANDLE varchar(4) NOT NULL, LOG_GROUP varchar(4) NOT NULL,"
+ " USERNAME varchar(12) NOT NULL,"
+ " VARIANT varchar(12) NOT NULL,"
+ " TYPE char(1) NOT NULL, SRTF2 int(11) NOT NULL,"
+ " VERSION varchar(6) NOT NULL default '000000',"
+ " ERFDAT varchar(8) NOT NULL default '00000000',"
+ " ERFTIME varchar(6) NOT NULL default '000000',"
+ " ERFNAME varchar(12) NOT NULL,"
+ " AEDAT varchar(8) NOT NULL default '00000000',"
+ " AETIME varchar(6) NOT NULL default '000000',"
+ " AENAME varchar(12) NOT NULL,"
+ " DEPENDVARS varchar(10) NOT NULL,"
+ " INACTIVE char(1) NOT NULL, CLUSTR smallint(6) NOT NULL,"
+ " CLUSTD blob,"
+ " PRIMARY KEY (MANDT, RELID, REPORT, HANDLE, LOG_GROUP, "
+ "USERNAME, VARIANT, TYPE, SRTF2))"
+ " CHARSET=latin1 COLLATE latin1_bin");
+ myquery(rc);
+ rc= mysql_query(mysql,
+ "CREATE VIEW V_LTDX AS select T0001.MANDT AS "
+ " MANDT,T0001.RELID AS RELID,T0001.REPORT AS "
+ " REPORT,T0001.HANDLE AS HANDLE,T0001.LOG_GROUP AS "
+ " LOG_GROUP,T0001.USERNAME AS USERNAME,T0001.VARIANT AS "
+ " VARIANT,T0001.TYPE AS TYPE,T0001.VERSION AS "
+ " VERSION,T0001.ERFDAT AS ERFDAT,T0001.ERFTIME AS "
+ " ERFTIME,T0001.ERFNAME AS ERFNAME,T0001.AEDAT AS "
+ " AEDAT,T0001.AETIME AS AETIME,T0001.AENAME AS "
+ " AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS "
+ " INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)");
+ myquery(rc);
+ for (i=0; i < 8; i++) {
+ strcpy(parms[i], "1");
+ bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+ bind[i].buffer = (char *)&parms[i];
+ bind[i].buffer_length = 100;
+ bind[i].is_null = 0;
+ bind[i].length = &length[i];
+ length[i] = 1;
+ }
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt,rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ assert(0 == my_process_stmt_result(stmt));
+
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "DROP VIEW V_LTDX");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP TABLE LTDX");
+ myquery(rc);
+}
+
+
+static void test_view_star()
+{
+ MYSQL_STMT *stmt;
+ int rc, i;
+ MYSQL_BIND bind[8];
+ char parms[8][100];
+ ulong length[8];
+ const char *query= "SELECT * FROM vt1 WHERE a IN (?,?)";
+
+ myheader("test_view_star");
+
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, vt1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, vt1");
+ myquery(rc);
+ rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
+ myquery(rc);
+ rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1");
+ myquery(rc);
+ for (i= 0; i < 2; i++) {
+ sprintf((char *)&parms[i], "%d", i);
+ bind[i].buffer_type = MYSQL_TYPE_VAR_STRING;
+ bind[i].buffer = (char *)&parms[i];
+ bind[i].buffer_length = 100;
+ bind[i].is_null = 0;
+ bind[i].length = &length[i];
+ length[i] = 1;
+ }
+
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt,rc);
+
+ for (i= 0; i < 3; i++)
+ {
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ assert(0 == my_process_stmt_result(stmt));
+ }
+
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP VIEW vt1");
+ myquery(rc);
+}
+
+
+static void test_view_insert()
+{
+ MYSQL_STMT *insert_stmt, *select_stmt;
+ int rc, i;
+ MYSQL_BIND bind[1];
+ int my_val = 0;
+ ulong my_length = 0L;
+ long my_null = 0L;
+ const char *query=
+ "insert into v1 values (?)";
+
+ myheader("test_view_insert");
+
+ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
+ myquery(rc);
+ rc = mysql_query(mysql, "DROP VIEW IF EXISTS t1,v1");
+ myquery(rc);
+
+ rc= mysql_query(mysql,"create table t1 (a int, primary key (a))");
+ myquery(rc);
+
+ rc= mysql_query(mysql, "create view v1 as select a from t1 where a>=1");
+ myquery(rc);
+
+ insert_stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(insert_stmt, query, strlen(query));
+ check_execute(insert_stmt, rc);
+ query= "select * from t1";
+ select_stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(select_stmt, query, strlen(query));
+ check_execute(select_stmt, rc);
+
+ bind[0].buffer_type = FIELD_TYPE_LONG;
+ bind[0].buffer = (char *)&my_val;
+ bind[0].length = &my_length;
+ bind[0].is_null = (char*)&my_null;
+ rc= mysql_stmt_bind_param(insert_stmt, bind);
+ check_execute(insert_stmt, rc);
+
+ for (i= 0; i < 3; i++)
+ {
+ my_val= i;
+
+ rc= mysql_stmt_execute(insert_stmt);
+ check_execute(insert_stmt, rc);
+
+ rc= mysql_stmt_execute(select_stmt);
+ check_execute(select_stmt, rc);
+ assert(i + 1 == (int) my_process_stmt_result(select_stmt));
+ }
+ mysql_stmt_close(insert_stmt);
+ mysql_stmt_close(select_stmt);
+
+ rc= mysql_query(mysql, "DROP VIEW v1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+}
+
+
+static void test_left_join_view()
+{
+ MYSQL_STMT *stmt;
+ int rc, i;
+ const char *query=
+ "select t1.a, v1.x from t1 left join v1 on (t1.a= v1.x);";
+
+ myheader("test_left_join_view");
+
+ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,v1");
+ myquery(rc);
+
+ rc = mysql_query(mysql, "DROP VIEW IF EXISTS v1,t1");
+ myquery(rc);
+ rc= mysql_query(mysql,"CREATE TABLE t1 (a int)");
+ myquery(rc);
+ rc= mysql_query(mysql,"insert into t1 values (1), (2), (3)");
+ myquery(rc);
+ rc= mysql_query(mysql,"create view v1 (x) as select a from t1 where a > 1");
+ myquery(rc);
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ check_execute(stmt, rc);
+
+ for (i= 0; i < 3; i++)
+ {
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ assert(3 == my_process_stmt_result(stmt));
+ }
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "DROP VIEW v1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+}
+
+
+static void test_view_insert_fields()
+{
+ MYSQL_STMT *stmt;
+ char parm[11][1000];
+ ulong l[11];
+ int rc, i;
+ MYSQL_BIND bind[11];
+ const char *query= "INSERT INTO `v1` ( `K1C4` ,`K2C4` ,`K3C4` ,`K4N4` ,`F1C4` ,`F2I4` ,`F3N5` ,`F7F8` ,`F6N4` ,`F5C8` ,`F9D8` ) VALUES( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )";
+
+ myheader("test_view_insert_fields");
+
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1, v1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP VIEW IF EXISTS t1, v1");
+ myquery(rc);
+ rc= mysql_query(mysql,
+ "CREATE TABLE t1 (K1C4 varchar(4) NOT NULL,"
+ "K2C4 varchar(4) NOT NULL, K3C4 varchar(4) NOT NULL,"
+ "K4N4 varchar(4) NOT NULL default '0000',"
+ "F1C4 varchar(4) NOT NULL, F2I4 int(11) NOT NULL,"
+ "F3N5 varchar(5) NOT NULL default '00000',"
+ "F4I4 int(11) NOT NULL default '0', F5C8 varchar(8) NOT NULL,"
+ "F6N4 varchar(4) NOT NULL default '0000',"
+ "F7F8 double NOT NULL default '0',"
+ "F8F8 double NOT NULL default '0',"
+ "F9D8 decimal(8,2) NOT NULL default '0.00',"
+ "PRIMARY KEY (K1C4,K2C4,K3C4,K4N4)) "
+ "CHARSET=latin1 COLLATE latin1_bin");
+ myquery(rc);
+ rc= mysql_query(mysql,
+ "CREATE VIEW v1 AS select sql_no_cache "
+ " K1C4 AS K1C4, K2C4 AS K2C4, K3C4 AS K3C4, K4N4 AS K4N4, "
+ " F1C4 AS F1C4, F2I4 AS F2I4, F3N5 AS F3N5,"
+ " F7F8 AS F7F8, F6N4 AS F6N4, F5C8 AS F5C8, F9D8 AS F9D8"
+ " from t1 T0001");
+
+ for (i= 0; i < 11; i++)
+ {
+ l[i]= 20;
+ bind[i].buffer_type= MYSQL_TYPE_STRING;
+ bind[i].is_null= 0;
+ bind[i].buffer= (char *)&parm[i];
+
+ strcpy(parm[i], "1");
+ bind[i].buffer_length= 2;
+ bind[i].length= &l[i];
+ }
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ check_execute(stmt, rc);
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ mysql_stmt_close(stmt);
+
+ query= "select * from t1";
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ check_execute(stmt, rc);
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ assert(1 == my_process_stmt_result(stmt));
+
+ mysql_stmt_close(stmt);
+ rc= mysql_query(mysql, "DROP VIEW v1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+
+}
static void test_bug5126()
{
@@ -10644,7 +11352,7 @@ static void test_bug5399()
for (stmt= stmt_list; stmt != stmt_list + NUM_OF_USED_STMT; ++stmt)
{
- sprintf(buff, "select %d", stmt - stmt_list);
+ sprintf(buff, "select %d", (int) (stmt - stmt_list));
*stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(*stmt, buff, strlen(buff));
check_execute(*stmt, rc);
@@ -10839,7 +11547,7 @@ static void test_bug5194()
if (!opt_silent)
printf("Insert: query length= %d, row count= %d, param count= %lu\n",
- strlen(query), nrows, mysql_stmt_param_count(stmt));
+ (int) strlen(query), nrows, mysql_stmt_param_count(stmt));
/* bind the parameter array and execute the query */
rc= mysql_stmt_bind_param(stmt, bind);
@@ -10992,14 +11700,13 @@ static void test_bug6059()
{
MYSQL_STMT *stmt;
const char *stmt_text;
- int rc;
myheader("test_bug6059");
stmt_text= "SELECT 'foo' INTO OUTFILE 'x.3'";
stmt= mysql_stmt_init(mysql);
- rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ (void) mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
DIE_UNLESS(mysql_stmt_field_count(stmt) == 0);
mysql_stmt_close(stmt);
}
@@ -11051,6 +11758,62 @@ static void test_bug6046()
}
+
+static void test_basic_cursors()
+{
+ const char *basic_tables[]=
+ {
+ "DROP TABLE IF EXISTS t1, t2",
+
+ "CREATE TABLE t1 "
+ "(id INTEGER NOT NULL PRIMARY KEY, "
+ " name VARCHAR(20) NOT NULL)",
+
+ "INSERT INTO t1 (id, name) VALUES "
+ " (2, 'Ja'), (3, 'Ede'), "
+ " (4, 'Haag'), (5, 'Kabul'), "
+ " (6, 'Almere'), (7, 'Utrecht'), "
+ " (8, 'Qandahar'), (9, 'Amsterdam'), "
+ " (10, 'Amersfoort'), (11, 'Constantine')",
+
+ "CREATE TABLE t2 "
+ "(id INTEGER NOT NULL PRIMARY KEY, "
+ " name VARCHAR(20) NOT NULL)",
+
+ "INSERT INTO t2 (id, name) VALUES "
+ " (4, 'Guam'), (5, 'Aruba'), "
+ " (6, 'Angola'), (7, 'Albania'), "
+ " (8, 'Anguilla'), (9, 'Argentina'), "
+ " (10, 'Azerbaijan'), (11, 'Afghanistan'), "
+ " (12, 'Burkina Faso'), (13, 'Faroe Islands')"
+ };
+ const char *queries[]=
+ {
+ "SELECT * FROM t1",
+ "SELECT * FROM t2"
+ };
+
+ DBUG_ENTER("test_basic_cursors");
+ myheader("test_basic_cursors");
+
+ fill_tables(basic_tables, sizeof(basic_tables)/sizeof(*basic_tables));
+
+ fetch_n(queries, sizeof(queries)/sizeof(*queries));
+ DBUG_VOID_RETURN;
+}
+
+
+static void test_cursors_with_union()
+{
+ const char *queries[]=
+ {
+ "SELECT t1.name FROM t1 UNION SELECT t2.name FROM t2",
+ "SELECT t1.id FROM t1 WHERE t1.id < 5"
+ };
+ myheader("test_cursors_with_union");
+ fetch_n(queries, sizeof(queries)/sizeof(*queries));
+}
+
/*
Altough mysql_create_db(), mysql_rm_db() are deprecated since 4.0 they
should not crash server and should not hang in case of errors.
@@ -11089,6 +11852,7 @@ static void test_bug6096()
MYSQL_FIELD *query_field_list, *stmt_field_list;
ulong query_field_count, stmt_field_count;
int rc;
+ my_bool update_max_length= TRUE;
uint i;
myheader("test_bug6096");
@@ -11124,8 +11888,8 @@ static void test_bug6096()
check_execute(stmt, rc);
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
- rc= 1;
- mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc);
+ mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
+ (void*) &update_max_length);
mysql_stmt_store_result(stmt);
stmt_metadata= mysql_stmt_result_metadata(stmt);
stmt_field_list= mysql_fetch_fields(stmt_metadata);
@@ -11300,7 +12064,7 @@ static void test_datetime_ranges()
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
- DIE_UNLESS(mysql_warning_count(mysql) != 2);
+ DIE_UNLESS(mysql_warning_count(mysql) == 2);
verify_col_data("t1", "day_ovfl", "838:59:59");
verify_col_data("t1", "day", "828:30:30");
@@ -11511,6 +12275,299 @@ static void test_rewind(void)
}
+static void test_truncation()
+{
+ MYSQL_STMT *stmt;
+ const char *stmt_text;
+ int rc;
+ uint bind_count;
+ MYSQL_BIND *bind_array, *bind;
+
+ myheader("test_truncation");
+
+ /* Prepare the test table */
+ rc= mysql_query(mysql, "drop table if exists t1");
+ myquery(rc);
+
+ stmt_text= "create table t1 ("
+ "i8 tinyint, ui8 tinyint unsigned, "
+ "i16 smallint, i16_1 smallint, "
+ "ui16 smallint unsigned, i32 int, i32_1 int, "
+ "d double, d_1 double, ch char(30), ch_1 char(30), "
+ "tx text, tx_1 text, ch_2 char(30) "
+ ")";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+ stmt_text= "insert into t1 VALUES ("
+ "-10, " /* i8 */
+ "200, " /* ui8 */
+ "32000, " /* i16 */
+ "-32767, " /* i16_1 */
+ "64000, " /* ui16 */
+ "1073741824, " /* i32 */
+ "1073741825, " /* i32_1 */
+ "123.456, " /* d */
+ "-12345678910, " /* d_1 */
+ "'111111111111111111111111111111',"/* ch */
+ "'abcdef', " /* ch_1 */
+ "'12345 ', " /* tx */
+ "'12345.67 ', " /* tx_1 */
+ "'12345.67abc'" /* ch_2 */
+ ")";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt_text= "select i8 c1, i8 c2, ui8 c3, i16_1 c4, ui16 c5, "
+ " i16 c6, ui16 c7, i32 c8, i32_1 c9, i32_1 c10, "
+ " d c11, d_1 c12, d_1 c13, ch c14, ch_1 c15, tx c16, "
+ " tx_1 c17, ch_2 c18 "
+ "from t1";
+
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ check_execute(stmt, rc);
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ bind_count= (uint) mysql_stmt_field_count(stmt);
+
+ /*************** Fill in the bind structure and bind it **************/
+ bind_array= malloc(sizeof(MYSQL_BIND) * bind_count);
+ bzero(bind_array, sizeof(MYSQL_BIND) * bind_count);
+ for (bind= bind_array; bind < bind_array + bind_count; bind++)
+ bind->error= &bind->error_value;
+ bind= bind_array;
+
+ bind->buffer= malloc(sizeof(uint8));
+ bind->buffer_type= MYSQL_TYPE_TINY;
+ bind->is_unsigned= TRUE;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(uint32));
+ bind->buffer_type= MYSQL_TYPE_LONG;
+ bind->is_unsigned= TRUE;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(int8));
+ bind->buffer_type= MYSQL_TYPE_TINY;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(uint16));
+ bind->buffer_type= MYSQL_TYPE_SHORT;
+ bind->is_unsigned= TRUE;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(int16));
+ bind->buffer_type= MYSQL_TYPE_SHORT;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(uint16));
+ bind->buffer_type= MYSQL_TYPE_SHORT;
+ bind->is_unsigned= TRUE;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(int8));
+ bind->buffer_type= MYSQL_TYPE_TINY;
+ bind->is_unsigned= TRUE;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(float));
+ bind->buffer_type= MYSQL_TYPE_FLOAT;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(float));
+ bind->buffer_type= MYSQL_TYPE_FLOAT;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(double));
+ bind->buffer_type= MYSQL_TYPE_DOUBLE;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(longlong));
+ bind->buffer_type= MYSQL_TYPE_LONGLONG;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(ulonglong));
+ bind->buffer_type= MYSQL_TYPE_LONGLONG;
+ bind->is_unsigned= TRUE;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(longlong));
+ bind->buffer_type= MYSQL_TYPE_LONGLONG;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(longlong));
+ bind->buffer_type= MYSQL_TYPE_LONGLONG;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(longlong));
+ bind->buffer_type= MYSQL_TYPE_LONGLONG;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(longlong));
+ bind->buffer_type= MYSQL_TYPE_LONGLONG;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(double));
+ bind->buffer_type= MYSQL_TYPE_DOUBLE;
+
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ bind->buffer= malloc(sizeof(double));
+ bind->buffer_type= MYSQL_TYPE_DOUBLE;
+
+ rc= mysql_stmt_bind_result(stmt, bind_array);
+ check_execute(stmt, rc);
+ rc= mysql_stmt_fetch(stmt);
+ DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED);
+
+ /*************** Verify truncation results ***************************/
+ bind= bind_array;
+
+ /* signed tiny -> tiny */
+ DIE_UNLESS(*bind->error && * (int8*) bind->buffer == -10);
+
+ /* signed tiny -> uint32 */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(*bind->error && * (int32*) bind->buffer == -10);
+
+ /* unsigned tiny -> tiny */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(*bind->error && * (uint8*) bind->buffer == 200);
+
+ /* short -> ushort */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(*bind->error && * (int16*) bind->buffer == -32767);
+
+ /* ushort -> short */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(*bind->error && * (uint16*) bind->buffer == 64000);
+
+ /* short -> ushort (no truncation, data is in the range of target type) */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(! *bind->error && * (uint16*) bind->buffer == 32000);
+
+ /* ushort -> utiny */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(*bind->error && * (int8*) bind->buffer == 0);
+
+ /* int -> float: no truncation, the number is a power of two */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(! *bind->error && * (float*) bind->buffer == 1073741824);
+
+ /* int -> float: truncation, not enough bits in float */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(*bind->error);
+
+ /* int -> double: no truncation */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(! *bind->error && * (double*) bind->buffer == 1073741825);
+
+ /* double -> longlong: fractional part is lost */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+
+ /* double -> ulonglong, negative fp number to unsigned integer */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ /* Value in the buffer is not defined: don't test it */
+ DIE_UNLESS(*bind->error);
+
+ /* double -> longlong, negative fp number to signed integer: no loss */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(! *bind->error && * (longlong*) bind->buffer == LL(-12345678910));
+
+ /* big numeric string -> number */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(*bind->error);
+
+ /* junk string -> number */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(*bind->error && *(longlong*) bind->buffer == 0);
+
+ /* string with trailing spaces -> number */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(! *bind->error && *(longlong*) bind->buffer == 12345);
+
+ /* string with trailing spaces -> double */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ DIE_UNLESS(! *bind->error && *(double*) bind->buffer == 12345.67);
+
+ /* string with trailing junk -> double */
+ DIE_UNLESS(++bind < bind_array + bind_count);
+ /*
+ XXX: There must be a truncation error: but it's not the way the server
+ behaves, so let's leave it for now.
+ */
+ DIE_UNLESS(*(double*) bind->buffer == 12345.67);
+ /*
+ TODO: string -> double, double -> time, double -> string (truncation
+ errors are not supported here yet)
+ longlong -> time/date/datetime
+ date -> time, date -> timestamp, date -> number
+ time -> string, time -> date, time -> timestamp,
+ number -> date string -> date
+ */
+ /*************** Cleanup *********************************************/
+
+ mysql_stmt_close(stmt);
+
+ for (bind= bind_array; bind < bind_array + bind_count; bind++)
+ free(bind->buffer);
+ free(bind_array);
+
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+static void test_truncation_option()
+{
+ MYSQL_STMT *stmt;
+ const char *stmt_text;
+ int rc;
+ uint8 buf;
+ my_bool option= 0;
+ my_bool error;
+ MYSQL_BIND bind;
+
+ myheader("test_truncation_option");
+
+ /* Prepare the test table */
+ stmt_text= "select -1";
+
+ stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ check_execute(stmt, rc);
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ bzero(&bind, sizeof(MYSQL_BIND));
+
+ bind.buffer= (void*) &buf;
+ bind.buffer_type= MYSQL_TYPE_TINY;
+ bind.is_unsigned= TRUE;
+ bind.error= &error;
+
+ rc= mysql_stmt_bind_result(stmt, &bind);
+ check_execute(stmt, rc);
+ rc= mysql_stmt_fetch(stmt);
+ DIE_UNLESS(rc == MYSQL_DATA_TRUNCATED);
+ DIE_UNLESS(error);
+ rc= mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, (char*) &option);
+ myquery(rc);
+ /* need to rebind for the new setting to take effect */
+ 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);
+ /* The only change is rc - error pointers are still filled in */
+ DIE_UNLESS(error == 1);
+ /* restore back the defaults */
+ option= 1;
+ mysql_options(mysql, MYSQL_REPORT_DATA_TRUNCATION, (char*) &option);
+
+ mysql_stmt_close(stmt);
+}
+
+
/* Bug#6761 - mysql_list_fields doesn't work */
static void test_bug6761(void)
@@ -11541,7 +12598,7 @@ static void test_bug8330()
const char *stmt_text;
MYSQL_STMT *stmt[2];
int i, rc;
- char *query= "select a,b from t1 where a=?";
+ const char *query= "select a,b from t1 where a=?";
MYSQL_BIND bind[2];
long lval[2];
@@ -11605,6 +12662,41 @@ static void test_bug7990()
}
+static void test_view_sp_list_fields()
+{
+ int rc;
+ MYSQL_RES *res;
+
+ myheader("test_view_sp_list_fields");
+
+ rc= mysql_query(mysql, "DROP FUNCTION IF EXISTS f1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS v1, t1, t2");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1, t1, t2");
+ myquery(rc);
+ rc= mysql_query(mysql, "create function f1 () returns int return 5");
+ myquery(rc);
+ rc= mysql_query(mysql, "create table t1 (s1 char,s2 char)");
+ myquery(rc);
+ rc= mysql_query(mysql, "create table t2 (s1 int);");
+ myquery(rc);
+ rc= mysql_query(mysql, "create view v1 as select s2,sum(s1) - \
+count(s2) as vx from t1 group by s2 having sum(s1) - count(s2) < (select f1() \
+from t2);");
+ myquery(rc);
+ res= mysql_list_fields(mysql, "v1", NullS);
+ DIE_UNLESS(res != 0 && mysql_num_fields(res) != 0);
+ rc= mysql_query(mysql, "DROP FUNCTION f1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP VIEW v1");
+ myquery(rc);
+ rc= mysql_query(mysql, "DROP TABLE t1, t2");
+ myquery(rc);
+
+}
+
+
/*
Test mysql_real_escape_string() with gbk charset
@@ -11655,6 +12747,167 @@ static void test_bug8378()
#endif
}
+
+static void test_bug8722()
+{
+ MYSQL_STMT *stmt;
+ int rc;
+ const char *stmt_text;
+
+ myheader("test_bug8722");
+ /* Prepare test data */
+ stmt_text= "drop table if exists t1, v1";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+ stmt_text= "CREATE TABLE t1 (c1 varchar(10), c2 varchar(10), c3 varchar(10),"
+ " c4 varchar(10), c5 varchar(10), c6 varchar(10),"
+ " c7 varchar(10), c8 varchar(10), c9 varchar(10),"
+ "c10 varchar(10))";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+ stmt_text= "INSERT INTO t1 VALUES (1,2,3,4,5,6,7,8,9,10)";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+ stmt_text= "CREATE VIEW v1 AS SELECT * FROM t1";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+ /* Note: if you uncomment following block everything works fine */
+/*
+ rc= mysql_query(mysql, "sellect * from v1");
+ myquery(rc);
+ mysql_free_result(mysql_store_result(mysql));
+*/
+
+ stmt= mysql_stmt_init(mysql);
+ stmt_text= "select * from v1";
+ rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ check_execute(stmt, rc);
+ mysql_stmt_close(stmt);
+ stmt_text= "drop table if exists t1, v1";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+}
+
+
+MYSQL_STMT *open_cursor(const char *query)
+{
+ int rc;
+ const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
+
+ MYSQL_STMT *stmt= mysql_stmt_init(mysql);
+ rc= mysql_stmt_prepare(stmt, query, strlen(query));
+ check_execute(stmt, rc);
+
+ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
+ return stmt;
+}
+
+
+static void test_bug8880()
+{
+ MYSQL_STMT *stmt_list[2], **stmt;
+ MYSQL_STMT **stmt_list_end= (MYSQL_STMT**) stmt_list + 2;
+ int rc;
+
+ myheader("test_bug8880");
+
+ mysql_query(mysql, "drop table if exists t1");
+ mysql_query(mysql, "create table t1 (a int not null primary key, b int)");
+ rc= mysql_query(mysql, "insert into t1 values (1,1)");
+ myquery(rc); /* one check is enough */
+ /*
+ when inserting 2 rows everything works well
+ mysql_query(mysql, "INSERT INTO t1 VALUES (1,1),(2,2)");
+ */
+ for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
+ *stmt= open_cursor("select a from t1");
+ for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
+ {
+ rc= mysql_stmt_execute(*stmt);
+ check_execute(*stmt, rc);
+ }
+ for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
+ mysql_stmt_close(*stmt);
+}
+
+
+static void test_bug9159()
+{
+ MYSQL_STMT *stmt;
+ int rc;
+ const char *stmt_text= "select a, b from t1";
+ const unsigned long type= CURSOR_TYPE_READ_ONLY;
+
+ myheader("test_bug9159");
+
+ mysql_query(mysql, "drop table if exists t1");
+ mysql_query(mysql, "create table t1 (a int not null primary key, b int)");
+ rc= mysql_query(mysql, "insert into t1 values (1,1)");
+ myquery(rc);
+
+ stmt= mysql_stmt_init(mysql);
+ mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+ mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void *)&type);
+
+ mysql_stmt_execute(stmt);
+ mysql_stmt_close(stmt);
+ rc= mysql_query(mysql, "drop table if exists t1");
+ myquery(rc);
+}
+
+
+/* Crash when opening a cursor to a query with DISTICNT and no key */
+
+static void test_bug9520()
+{
+ MYSQL_STMT *stmt;
+ MYSQL_BIND bind[1];
+ char a[6];
+ ulong a_len;
+ int rc, row_count= 0;
+
+ myheader("test_bug9520");
+
+ mysql_query(mysql, "drop table if exists t1");
+ mysql_query(mysql, "create table t1 (a char(5), b char(5), c char(5),"
+ " primary key (a, b, c))");
+ rc= mysql_query(mysql, "insert into t1 values ('x', 'y', 'z'), "
+ " ('a', 'b', 'c'), ('k', 'l', 'm')");
+ myquery(rc);
+
+ stmt= open_cursor("select distinct b from t1");
+
+ /*
+ Not crashes with:
+ stmt= open_cursor("select distinct a from t1");
+ */
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+
+ bzero(bind, sizeof(bind));
+ bind[0].buffer_type= MYSQL_TYPE_STRING;
+ bind[0].buffer= (char*) a;
+ bind[0].buffer_length= sizeof(a);
+ bind[0].length= &a_len;
+
+ mysql_stmt_bind_result(stmt, bind);
+
+ while (!(rc= mysql_stmt_fetch(stmt)))
+ row_count++;
+
+ DIE_UNLESS(rc == MYSQL_NO_DATA);
+
+ printf("Fetched %d rows\n", row_count);
+ DBUG_ASSERT(row_count == 3);
+
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+}
+
+
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -11716,6 +12969,7 @@ and you are welcome to modify and redistribute it under the GPL license\n");
static struct my_tests_st my_tests[]= {
+ { "test_view_sp_list_fields", test_view_sp_list_fields},
{ "client_query", client_query },
{ "test_prepare_insert_update", test_prepare_insert_update},
#if NOT_YET_WORKING
@@ -11862,9 +13116,24 @@ static struct my_tests_st my_tests[]= {
{ "test_conversion", test_conversion },
{ "test_rewind", test_rewind },
{ "test_bug6761", test_bug6761 },
+ { "test_view", test_view },
+ { "test_view_where", test_view_where },
+ { "test_view_2where", test_view_2where },
+ { "test_view_star", test_view_star },
+ { "test_view_insert", test_view_insert },
+ { "test_left_join_view", test_left_join_view },
+ { "test_view_insert_fields", test_view_insert_fields },
+ { "test_basic_cursors", test_basic_cursors },
+ { "test_cursors_with_union", test_cursors_with_union },
+ { "test_truncation", test_truncation },
+ { "test_truncation_option", test_truncation_option },
{ "test_bug8330", test_bug8330 },
{ "test_bug7990", test_bug7990 },
{ "test_bug8378", test_bug8378 },
+ { "test_bug8722", test_bug8722 },
+ { "test_bug8880", test_bug8880 },
+ { "test_bug9159", test_bug9159 },
+ { "test_bug9520", test_bug9520 },
{ 0, 0 }
};
@@ -11975,7 +13244,6 @@ int main(int argc, char **argv)
/* Start of tests */
test_count= 1;
start_time= time((time_t *)0);
-
if (!argc)
{
for (fptr= my_tests; fptr->name; fptr++)
@@ -12005,11 +13273,6 @@ int main(int argc, char **argv)
}
}
- /*
- XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
- DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.
- */
-
end_time= time((time_t *)0);
total_time+= difftime(end_time, start_time);
diff --git a/tests/pmail.pl b/tests/pmail.pl
index c7f8d4ee368..02d5d60ac0f 100755
--- a/tests/pmail.pl
+++ b/tests/pmail.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/perl -w
#
# Prints mails to standard output
#
@@ -9,21 +9,25 @@
use DBI;
use Getopt::Long;
-$VER="1.5";
+$VER="2.0";
@fldnms= ("mail_from","mail_to","cc","date","time_zone","file","sbj","txt");
-$fields=8;
-@mail= (@from,@to,@cc,@date,@time_zone,@file,@sbj,@txt);
+my $fields= 0;
+my $base_q= "";
+my $mail_count= 0;
$opt_user= $opt_password= "";
$opt_socket= "/tmp/mysql.sock";
$opt_port= 3306;
$opt_db="mail";
-$opt_table="mails";
+$opt_table="my_mail";
$opt_help=$opt_count=0;
+$opt_thread= 0;
+$opt_host= "";
+$opt_message_id= 0;
GetOptions("help","count","port=i","db=s","table=s","host=s","password=s",
- "user=s","socket=s") || usage();
+ "user=s","socket=s", "thread","message_id") || usage();
if ($opt_host eq '')
{
@@ -39,81 +43,194 @@ if ($opt_help || !$ARGV[0])
#### Connect and parsing the query to MySQL
####
-$dbh= DBI->connect("DBI:mysql:$opt_db:$opt_host:port=$opt_port:mysql_socket=$opt_mysql_socket", $opt_user,$opt_password, { PrintError => 0})
+$dbh= DBI->connect("DBI:mysql:$opt_db:$opt_host:port=$opt_port:mysql_socket=$opt_socket", $opt_user,$opt_password, { PrintError => 0})
|| die $DBI::errstr;
-if ($opt_count)
-{
- count_mails();
-}
+main();
-$fields=0;
-$query = "select ";
-foreach $val (@fldnms)
+####
+#### main
+####
+
+sub main
{
- if (!$fields)
+ my ($row, $val, $q, $mail, $sth);
+
+ if ($opt_count)
{
- $query.= "$val";
+ count_mails();
}
- else
+
+ $base_q= "SELECT ";
+ foreach $val (@fldnms)
+ {
+ if (!$fields)
+ {
+ $base_q.= "$val";
+ }
+ else
+ {
+ $base_q.= ",$val";
+ }
+ $fields++;
+ }
+ $base_q.= ",message_id" if ($opt_thread || $opt_message_id);
+ $base_q.= " FROM $opt_table";
+ $q= " WHERE $ARGV[0]";
+
+ $sth= $dbh->prepare($base_q . $q);
+ if (!$sth->execute)
+ {
+ print "$DBI::errstr\n";
+ $sth->finish;
+ die;
+ }
+ for (; ($row= $sth->fetchrow_arrayref); $mail_count++)
{
- $query.= ",$val";
+ for ($i= 0; $i < $fields; $i++)
+ {
+ if ($opt_message_id)
+ {
+ $mail[$fields][$mail_count]= $row->[$fields];
+ $mail[$fields][$mail_count].= "\nNumber of Replies: " . get_nr_replies($row->[$fields]);
+ }
+ $mail[$i][$mail_count]= $row->[$i];
+ }
+ if ($opt_thread)
+ {
+ get_mail_by_message_id($row->[$fields], $mail);
+ }
}
- $fields++;
+ print_mails($mail);
}
-$query.= " from $opt_table where $ARGV[0] order by date desc";
####
-#### Send query and save result
+#### Function, which fetches mail by searching in-reply-to with
+#### a given message_id. Saves the value (mail) in mail variable.
+#### Returns the message id of the mail found and searches again
+#### and saves, until no more mails are found with that message_id.
####
-$sth= $dbh->prepare($query);
-if (!$sth->execute)
+sub get_mail_by_message_id
{
- print "$DBI::errstr\n";
- $sth->finish;
- die;
-}
-for ($i=0; ($row= $sth->fetchrow_arrayref); $i++)
-{
- for ($j=0; $j < $fields; $j++)
+ my ($message_id, $mail)= @_;
+ my ($q, $query, $i, $row, $sth);
+
+ $q= " WHERE in_reply_to = \"$message_id\"";
+ $query= $base_q . $q;
+ $sth= $dbh->prepare($query);
+ if (!$sth->execute)
+ {
+ print "QUERY: $query\n$DBI::errstr\n";
+ $sth->finish;
+ die;
+ }
+ while (($row= $sth->fetchrow_arrayref))
{
- $mail[$j][$i]= $row->[$j];
+ $mail_count++;
+ for ($i= 0; $i < $fields; $i++)
+ {
+ if ($opt_message_id)
+ {
+ $mail[$fields][$mail_count]= $row->[$fields];
+ $mail[$fields][$mail_count].= "\nNumber of Replies: " . get_nr_replies($row->[$fields]);
+ }
+ $mail[$i][$mail_count]= $row->[$i];
+ }
+ $new_message_id= $row->[$fields];
+ if (defined($new_message_id) && length($new_message_id))
+ {
+ get_mail_by_message_id($new_message_id, $mail);
+ }
}
+ return;
}
####
-#### Print to stderr
+#### Get number of replies for a given message_id
####
-for ($i=0; $mail[0][$i]; $i++)
+sub get_nr_replies
{
- print "#" x 33;
- print " " . ($i+1) . ". Mail ";
- print "#" x 33;
- print "\nFrom: $mail[0][$i]\n";
- print "To: $mail[1][$i]\n";
- print "Cc: $mail[2][$i]\n";
- print "Date: $mail[3][$i]\n";
- print "Timezone: $mail[4][$i]\n";
- print "File: $mail[5][$i]\n";
- print "Subject: $mail[6][$i]\n";
- print "Message:\n$mail[7][$i]\n";
-}
-print "#" x 20;
-print " Summary: ";
-if ($i == 1)
-{
- print "$i Mail ";
- print "matches the query ";
+ my ($message_id)= @_;
+ my ($sth, $sth2, $q, $row, $row2, $nr_replies);
+
+ $nr_replies= 0;
+ $q= "SELECT COUNT(*) FROM my_mail WHERE in_reply_to=\"$message_id\"";
+ $sth= $dbh->prepare($q);
+ if (!$sth->execute)
+ {
+ print "QUERY: $q\n$DBI::errstr\n";
+ $sth->finish;
+ die;
+ }
+ while (($row= $sth->fetchrow_arrayref))
+ {
+ if (($nr_replies= $row->[0]))
+ {
+ $q= "SELECT message_id FROM my_mail WHERE in_reply_to=\"$message_id\"";
+ $sth2= $dbh->prepare($q);
+ if (!$sth2->execute)
+ {
+ print "QUERY: $q\n$DBI::errstr\n";
+ $sth->finish;
+ die;
+ }
+ while (($row2= $sth2->fetchrow_arrayref))
+ {
+ # There may be several replies to the same mail. Also the
+ # replies to the 'parent' mail may contain several replies
+ # and so on. Thus we need to calculate it recursively.
+ $nr_replies+= get_nr_replies($row2->[0]);
+ }
+ }
+ return $nr_replies;
+ }
}
-else
+
+####
+#### Print mails
+####
+
+sub print_mails
{
- print "$i Mails ";
- print "match the query ";
-}
-print "#" x 20;
-print "\n";
+ my ($mail)= @_;
+ my ($i);
+
+ for ($i=0; $mail[0][$i]; $i++)
+ {
+ print "#" x 33;
+ print " " . ($i+1) . ". Mail ";
+ print "#" x 33;
+ print "\n";
+ if ($opt_message_id)
+ {
+ print "Msg ID: $mail[$fields][$i]\n";
+ }
+ print "From: $mail[0][$i]\n";
+ print "To: $mail[1][$i]\n";
+ print "Cc:" . (defined($mail[2][$i]) ? $mail[2][$i] : "") . "\n";
+ print "Date: $mail[3][$i]\n";
+ print "Timezone: $mail[4][$i]\n";
+ print "File: $mail[5][$i]\n";
+ print "Subject: $mail[6][$i]\n";
+ print "Message:\n$mail[7][$i]\n";
+ }
+ print "#" x 20;
+ print " Summary: ";
+ if ($i == 1)
+ {
+ print "$i Mail ";
+ print "matches the query ";
+ }
+ else
+ {
+ print "$i Mails ";
+ print "match the query ";
+ }
+ print "#" x 20;
+ print "\n";
+}
####
#### Count mails that matches the query, but don't show them
@@ -121,6 +238,8 @@ print "\n";
sub count_mails
{
+ my ($sth);
+
$sth= $dbh->prepare("select count(*) from $opt_table where $ARGV[0]");
if (!$sth->execute)
{
@@ -154,15 +273,21 @@ sub usage
Usage: pmail [options] "SQL where clause"
Options:
- --help show this help
- --count Shows how many mails matches the query, but not the mails.
- --db= database to use (Default: $opt_db)
- --table= table to use (Default: $opt_table)
- --host= Hostname which to connect (Default: $opt_host)
- --socket= Unix socket to be used for connection (Default: $opt_socket)
- --password= Password to use for mysql
- --user= User to be used for mysql connection, if not current user
- --port= mysql port to be used (Default: $opt_port)
+ --help show this help
+ --count Shows how many mails matches the query, but not the mails.
+ --db= database to use (Default: $opt_db)
+ --host= Hostname which to connect (Default: $opt_host)
+ --socket= Unix socket to be used for connection (Default: $opt_socket)
+ --password= Password to use for mysql
+ --user= User to be used for mysql connection, if not current user
+ --port= mysql port to be used (Default: $opt_port)
+ --thread Will search for possible replies to emails found by the search
+ criteria. Replies, if found, will be displayed right after the
+ original mail.
+ --message_id Display message_id on top of each mail. Useful when searching
+ email threads with --thread. On the second line is the number
+ of replies to the same thread, starting counting from that
+ mail (excluding possible parent mails).
"SQL where clause" is the end of the select clause,
where the condition is expressed. The result will
be the mail(s) that matches the condition and
@@ -176,18 +301,20 @@ sub usage
- Subject
- Message text
The field names that can be used in the where clause are:
- Field Type
- - mail_from varchar(120)
- - date datetime
- - sbj varchar(200)
- - txt mediumtext
- - cc text
- - mail_to text
- - time_zone varchar(6)
- - reply varchar(120)
- - file varchar(32)
- - hash int(11)
- An example of the pmail:
+ Field Type
+ - message_id varchar(255) # Use with --thread and --message_id
+ - in_reply_to varchar(255) # Internally used by --thread
+ - mail_from varchar(120)
+ - date datetime
+ - sbj varchar(200)
+ - txt mediumtext
+ - cc text
+ - mail_to text
+ - time_zone varchar(6)
+ - reply varchar(120)
+ - file varchar(32)
+ - hash int(11)
+ An example of pmail:
pmail "txt like '%libmysql.dll%' and sbj like '%delphi%'"
NOTE: the txt field is NOT case sensitive!
EOF
diff --git a/tests/select_test.c b/tests/select_test.c
index ee2a9192865..64c4fec5167 100644
--- a/tests/select_test.c
+++ b/tests/select_test.c
@@ -44,6 +44,7 @@ int main(int argc, char **argv)
perror("");
exit(1);
}
+ mysql.reconnect= 1;
count = 0;
num = atoi(argv[2]);
diff --git a/tests/showdb_test.c b/tests/showdb_test.c
index df2b3037c00..08229fc51ee 100644
--- a/tests/showdb_test.c
+++ b/tests/showdb_test.c
@@ -45,6 +45,7 @@ int main(int argc, char **argv)
perror("");
exit(1);
}
+ mysql.reconnect= 1;
count = 0;
num = atoi(argv[2]);
diff --git a/tests/ssl_test.c b/tests/ssl_test.c
index b18e493c267..85f490cb02e 100644
--- a/tests/ssl_test.c
+++ b/tests/ssl_test.c
@@ -51,6 +51,7 @@ int main(int argc, char **argv)
perror("");
exit(1);
}
+ mysql.reconnect= 1;
count = 0;
num = atoi(argv[2]);
while (count < num)
diff --git a/tests/thread_test.c b/tests/thread_test.c
index 06f335fe1a6..f8577857d0a 100644
--- a/tests/thread_test.c
+++ b/tests/thread_test.c
@@ -55,6 +55,7 @@ unsigned __stdcall test_thread(void *arg __attribute__((unused)))
perror("");
goto end;
}
+ mysql.reconnect= 1;
if (verbose) { putchar('*'); fflush(stdout); }
for (count=0 ; count < number_of_tests ; count++)
{
diff --git a/tests/udf_test b/tests/udf_test
index 4621a7b34a5..15ad640f984 100644
--- a/tests/udf_test
+++ b/tests/udf_test
@@ -9,6 +9,7 @@ CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
+CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so";
select metaphon("hello");
select myfunc_double("hello","world");
@@ -20,6 +21,7 @@ create temporary table t1 (a int,b double);
insert into t1 values (1,5),(1,4),(2,8),(3,9),(4,11);
select avgcost(a,b) from t1;
select avgcost(a,b) from t1 group by a;
+select a, myfunc_argument_name(a), myfunc_argument_name(a as b) from t1;
drop table t1;
DROP FUNCTION metaphon;
@@ -28,3 +30,4 @@ DROP FUNCTION myfunc_int;
DROP FUNCTION lookup;
DROP FUNCTION reverse_lookup;
DROP FUNCTION avgcost;
+DROP FUNCTION myfunc_argument_name;
diff --git a/tests/udf_test.res b/tests/udf_test.res
index 66634e13616..de9e9969f3a 100644
--- a/tests/udf_test.res
+++ b/tests/udf_test.res
@@ -35,6 +35,12 @@ CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so"
Query OK, 0 rows affected
--------------
+CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so"
+--------------
+
+Query OK, 0 rows affected
+
+--------------
select metaphon("hello")
--------------
@@ -107,6 +113,18 @@ avgcost(a,b)
4 rows in set
--------------
+select a, myfunc_argument_name(a) from t1;
+--------------
+
+a myfunc_argument_name(a) myfunc_argument_name(a as b)
+1 a b
+1 a b
+2 a b
+3 a b
+4 a b
+5 rows in set
+
+--------------
drop table t1
--------------
@@ -148,4 +166,10 @@ DROP FUNCTION avgcost
Query OK, 0 rows affected
+--------------
+DROP FUNCTION myfunc_argument_name;
+--------------
+
+Query OK, 0 rows affected
+
Bye
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 5528df4dd68..3b84aafeaa9 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -15,12 +15,13 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Process this file with automake to create Makefile.in
-INCLUDES=@MT_INCLUDES@ -I$(top_srcdir)/include $(openssl_includes)
+INCLUDES=-I$(top_srcdir)/include $(openssl_includes) \
+ -I$(top_builddir)/include
LDADD= @CLIENT_EXTRA_LDFLAGS@ @openssl_libs@ \
$(top_builddir)/libmysql_r/libmysqlclient_r.la @ZLIB_LIBS@
-bin_PROGRAMS= mysqlmanager
-mysqlmanager_SOURCES= mysqlmanager.c
-mysqlmanager_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
+bin_PROGRAMS= mysqltestmanager
+mysqltestmanager_SOURCES= mysqlmanager.c
+mysqltestmanager_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES)
DEF= -DUNDEF_THREADS_HACK
# Don't update the files from bitkeeper
diff --git a/tools/mysqlmanager.c b/tools/mysqlmanager.c
index 27caa1e0255..4a5c08be50a 100644
--- a/tools/mysqlmanager.c
+++ b/tools/mysqlmanager.c
@@ -557,14 +557,13 @@ HANDLE_DECL(handle_set_exec_stderr)
static int set_exec_param(struct manager_thd* thd, char* args_start,
char* args_end, PARAM_TYPE param_type)
{
- int num_args;
const char* error=0;
struct manager_exec* e;
char* arg_p;
char* param;
int param_size;
- if ((num_args=tokenize_args(args_start,&args_end))<2)
+ if (tokenize_args(args_start,&args_end) < 2)
{
error="Too few arguments";
goto err;
@@ -607,12 +606,11 @@ err:
HANDLE_DECL(handle_start_exec)
{
- int num_args;
struct manager_exec* e;
int ident_len;
const char* error=0;
struct timespec t;
- if ((num_args=tokenize_args(args_start,&args_end))<1)
+ if (tokenize_args(args_start,&args_end) < 1)
{
error="Too few arguments";
goto err;
@@ -656,12 +654,11 @@ err:
HANDLE_DECL(handle_stop_exec)
{
- int num_args;
struct timespec abstime;
struct manager_exec* e;
int ident_len;
const char* error=0;
- if ((num_args=tokenize_args(args_start,&args_end))<2)
+ if (tokenize_args(args_start,&args_end) <2)
{
error="Too few arguments";
goto err;
@@ -877,7 +874,10 @@ static void manager_exec_connect(struct manager_exec* e)
{
if (mysql_real_connect(&e->mysql,e->con_host,e->con_user,e->con_pass,0,
e->con_port,e->con_sock,0))
+ {
+ e->mysql.reconnect= 1;
return;
+ }
sleep(1);
}
e->error="Could not connect to MySQL server withing the number of tries";
diff --git a/vio/test-sslserver.c b/vio/test-sslserver.c
index d05e50af16b..e4d32a75264 100644
--- a/vio/test-sslserver.c
+++ b/vio/test-sslserver.c
@@ -91,12 +91,7 @@ main(int argc __attribute__((unused)), char** argv)
struct sockaddr_in sa_cli;
int listen_sd;
int err;
-
-#if defined(__sgi) && _NO_XOPEN4 && _NO_XOPEN5
- socklen_t client_len;
-#else
- size_t client_len;
-#endif
+ size_socket client_len;
int reuseaddr = 1; /* better testing, uh? */
MY_INIT(argv[0]);
diff --git a/vio/vio.c b/vio/vio.c
index 978780d2632..6227493b994 100644
--- a/vio/vio.c
+++ b/vio/vio.c
@@ -27,19 +27,23 @@
* Helper to fill most of the Vio* with defaults.
*/
-void vio_reset(Vio* vio, enum enum_vio_type type,
- my_socket sd, HANDLE hPipe,
- my_bool localhost)
+static void vio_init(Vio* vio, enum enum_vio_type type,
+ my_socket sd, HANDLE hPipe, uint flags)
{
- DBUG_ENTER("vio_reset");
- DBUG_PRINT("enter", ("type=%d sd=%d localhost=%d", type, sd, localhost));
+ DBUG_ENTER("vio_init");
+ DBUG_PRINT("enter", ("type: %d sd: %d flags: %d", type, sd, flags));
+#ifndef HAVE_VIO_READ_BUFF
+ flags&= ~VIO_BUFFERED_READ;
+#endif
bzero((char*) vio, sizeof(*vio));
vio->type = type;
vio->sd = sd;
vio->hPipe = hPipe;
- vio->localhost= localhost;
-#ifdef HAVE_VIO
+ vio->localhost= flags & VIO_LOCALHOST;
+ if ((flags & VIO_BUFFERED_READ) &&
+ !(vio->read_buffer= (char*)my_malloc(VIO_READ_BUFFER_SIZE, MYF(MY_WME))))
+ flags&= ~VIO_BUFFERED_READ;
#ifdef __WIN__
if (type == VIO_TYPE_NAMEDPIPE)
{
@@ -100,7 +104,7 @@ void vio_reset(Vio* vio, enum enum_vio_type type,
{
vio->viodelete =vio_delete;
vio->vioerrno =vio_errno;
- vio->read =vio_read;
+ vio->read= (flags & VIO_BUFFERED_READ) ? vio_read_buff : vio_read;
vio->write =vio_write;
vio->fastsend =vio_fastsend;
vio->viokeepalive =vio_keepalive;
@@ -112,21 +116,30 @@ void vio_reset(Vio* vio, enum enum_vio_type type,
vio->is_blocking =vio_is_blocking;
vio->timeout =vio_timeout;
}
-#endif /* HAVE_VIO */
DBUG_VOID_RETURN;
}
+/* Reset initialized VIO to use with another transport type */
+
+void vio_reset(Vio* vio, enum enum_vio_type type,
+ my_socket sd, HANDLE hPipe, uint flags)
+{
+ my_free(vio->read_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ vio_init(vio, type, sd, hPipe, flags);
+}
+
+
/* Open the socket or TCP/IP connection and read the fnctl() status */
-Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost)
+Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags)
{
Vio *vio;
DBUG_ENTER("vio_new");
- DBUG_PRINT("enter", ("sd=%d", sd));
+ DBUG_PRINT("enter", ("sd: %d", sd));
if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME))))
{
- vio_reset(vio, type, sd, 0, localhost);
+ vio_init(vio, type, sd, 0, flags);
sprintf(vio->desc,
(vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
vio->sd);
@@ -162,7 +175,7 @@ Vio *vio_new_win32pipe(HANDLE hPipe)
DBUG_ENTER("vio_new_handle");
if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
{
- vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
+ vio_init(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, VIO_LOCALHOST);
strmov(vio->desc, "named pipe");
}
DBUG_RETURN(vio);
@@ -178,7 +191,7 @@ Vio *vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE handle_m
DBUG_ENTER("vio_new_win32shared_memory");
if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
{
- vio_reset(vio, VIO_TYPE_SHARED_MEMORY, 0, 0, TRUE);
+ vio_init(vio, VIO_TYPE_SHARED_MEMORY, 0, 0, VIO_LOCALHOST);
vio->handle_file_map= handle_file_map;
vio->handle_map= handle_map;
vio->event_server_wrote= event_server_wrote;
@@ -203,11 +216,8 @@ void vio_delete(Vio* vio)
if (vio)
{
if (vio->type != VIO_CLOSED)
-#ifdef HAVE_VIO /*WAX*/
vio->vioclose(vio);
-#else
- vio_close(vio);
-#endif
+ my_free((gptr) vio->read_buffer, MYF(MY_ALLOW_ZERO_PTR));
my_free((gptr) vio,MYF(0));
}
}
diff --git a/vio/viosocket.c b/vio/viosocket.c
index 77922594469..ea85a69e2d4 100644
--- a/vio/viosocket.c
+++ b/vio/viosocket.c
@@ -33,8 +33,10 @@ int vio_read(Vio * vio, gptr buf, int size)
{
int r;
DBUG_ENTER("vio_read");
- DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+ /* Ensure nobody uses vio_read_buff and vio_read simultaneously */
+ DBUG_ASSERT(vio->read_end == vio->read_pos);
#ifdef __WIN__
r = recv(vio->sd, buf, size,0);
#else
@@ -52,11 +54,55 @@ int vio_read(Vio * vio, gptr buf, int size)
}
+/*
+ Buffered read: if average read size is small it may
+ reduce number of syscalls.
+*/
+
+int vio_read_buff(Vio *vio, gptr buf, int size)
+{
+ int rc;
+#define VIO_UNBUFFERED_READ_MIN_SIZE 2048
+ DBUG_ENTER("vio_read_buff");
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+
+ if (vio->read_pos < vio->read_end)
+ {
+ rc= min(vio->read_end - vio->read_pos, size);
+ memcpy(buf, vio->read_pos, rc);
+ vio->read_pos+= rc;
+ /*
+ Do not try to read from the socket now even if rc < size:
+ vio_read can return -1 due to an error or non-blocking mode, and
+ the safest way to handle it is to move to a separate branch.
+ */
+ }
+ else if (size < VIO_UNBUFFERED_READ_MIN_SIZE)
+ {
+ rc= vio_read(vio, vio->read_buffer, VIO_READ_BUFFER_SIZE);
+ if (rc > 0)
+ {
+ if (rc > size)
+ {
+ vio->read_pos= vio->read_buffer + size;
+ vio->read_end= vio->read_buffer + rc;
+ rc= size;
+ }
+ memcpy(buf, vio->read_buffer, rc);
+ }
+ }
+ else
+ rc= vio_read(vio, buf, size);
+ DBUG_RETURN(rc);
+#undef VIO_UNBUFFERED_READ_MIN_SIZE
+}
+
+
int vio_write(Vio * vio, const gptr buf, int size)
{
int r;
DBUG_ENTER("vio_write");
- DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
#ifdef __WIN__
r = send(vio->sd, buf, size,0);
#else
@@ -174,7 +220,7 @@ int vio_keepalive(Vio* vio, my_bool set_keep_alive)
int r=0;
uint opt = 0;
DBUG_ENTER("vio_keepalive");
- DBUG_PRINT("enter", ("sd=%d, set_keep_alive=%d", vio->sd, (int)
+ DBUG_PRINT("enter", ("sd: %d, set_keep_alive: %d", vio->sd, (int)
set_keep_alive));
if (vio->type != VIO_TYPE_NAMEDPIPE)
{
@@ -333,7 +379,7 @@ int vio_read_pipe(Vio * vio, gptr buf, int size)
{
DWORD length;
DBUG_ENTER("vio_read_pipe");
- DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
if (!ReadFile(vio->hPipe, buf, size, &length, NULL))
DBUG_RETURN(-1);
@@ -347,7 +393,7 @@ int vio_write_pipe(Vio * vio, const gptr buf, int size)
{
DWORD length;
DBUG_ENTER("vio_write_pipe");
- DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL))
DBUG_RETURN(-1);
@@ -391,7 +437,7 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size)
char *current_postion;
DBUG_ENTER("vio_read_shared_memory");
- DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
remain_local = size;
current_postion=buf;
@@ -452,7 +498,7 @@ int vio_write_shared_memory(Vio * vio, const gptr buf, int size)
char *current_postion;
DBUG_ENTER("vio_write_shared_memory");
- DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
remain = size;
current_postion = buf;
diff --git a/vio/viossl.c b/vio/viossl.c
index 07713c83763..400d8842fd3 100644
--- a/vio/viossl.c
+++ b/vio/viossl.c
@@ -99,7 +99,7 @@ int vio_ssl_read(Vio * vio, gptr buf, int size)
{
int r;
DBUG_ENTER("vio_ssl_read");
- DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d, ssl_=%p",
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d, ssl_: 0x%p",
vio->sd, buf, size, vio->ssl_arg));
if ((r= SSL_read((SSL*) vio->ssl_arg, buf, size)) < 0)
@@ -117,7 +117,7 @@ int vio_ssl_write(Vio * vio, const gptr buf, int size)
{
int r;
DBUG_ENTER("vio_ssl_write");
- DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
if ((r= SSL_write((SSL*) vio->ssl_arg, buf, size)) < 0)
report_errors();
@@ -157,7 +157,7 @@ int vio_ssl_keepalive(Vio* vio, my_bool set_keep_alive)
{
int r=0;
DBUG_ENTER("vio_ssl_keepalive");
- DBUG_PRINT("enter", ("sd=%d, set_keep_alive=%d", vio->sd, (int)
+ DBUG_PRINT("enter", ("sd: %d, set_keep_alive: %d", vio->sd, (int)
set_keep_alive));
if (vio->type != VIO_TYPE_NAMEDPIPE)
{
@@ -227,7 +227,7 @@ my_socket vio_ssl_fd(Vio* vio)
my_bool vio_ssl_peer_addr(Vio * vio, char *buf, uint16 *port)
{
DBUG_ENTER("vio_ssl_peer_addr");
- DBUG_PRINT("enter", ("sd=%d", vio->sd));
+ DBUG_PRINT("enter", ("sd: %d", vio->sd));
if (vio->localhost)
{
strmov(buf,"127.0.0.1");
@@ -250,7 +250,7 @@ my_bool vio_ssl_peer_addr(Vio * vio, char *buf, uint16 *port)
*port= 0;
#endif
}
- DBUG_PRINT("exit", ("addr=%s", buf));
+ DBUG_PRINT("exit", ("addr: %s", buf));
DBUG_RETURN(0);
}
@@ -279,7 +279,7 @@ int sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout)
my_bool net_blocking;
enum enum_vio_type old_type;
DBUG_ENTER("sslaccept");
- DBUG_PRINT("enter", ("sd=%d ptr=%p", vio->sd,ptr));
+ DBUG_PRINT("enter", ("sd: %d ptr: Ox%p", vio->sd,ptr));
old_type= vio->type;
net_blocking = vio_is_blocking(vio);
@@ -294,7 +294,8 @@ int sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout)
vio_blocking(vio, net_blocking, &unused);
DBUG_RETURN(1);
}
- DBUG_PRINT("info", ("ssl_=%p timeout=%ld",(SSL*) vio->ssl_arg, timeout));
+ DBUG_PRINT("info", ("ssl_: Ox%p timeout: %ld",
+ (SSL*) vio->ssl_arg, timeout));
SSL_clear((SSL*) vio->ssl_arg);
SSL_SESSION_set_timeout(SSL_get_session((SSL*) vio->ssl_arg), timeout);
SSL_set_fd((SSL*) vio->ssl_arg,vio->sd);
@@ -352,7 +353,8 @@ int sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio, long timeout)
my_bool net_blocking;
enum enum_vio_type old_type;
DBUG_ENTER("sslconnect");
- DBUG_PRINT("enter", ("sd=%d ptr=%p ctx: %p", vio->sd,ptr,ptr->ssl_context));
+ DBUG_PRINT("enter", ("sd: %d ptr: 0x%p ctx: 0x%p",
+ vio->sd,ptr,ptr->ssl_context));
old_type= vio->type;
net_blocking = vio_is_blocking(vio);
@@ -367,7 +369,8 @@ int sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio, long timeout)
vio_blocking(vio, net_blocking, &unused);
DBUG_RETURN(1);
}
- DBUG_PRINT("info", ("ssl_=%p timeout=%ld",(SSL*) vio->ssl_arg, timeout));
+ DBUG_PRINT("info", ("ssl_: 0x%p timeout: %ld",
+ (SSL*) vio->ssl_arg, timeout));
SSL_clear((SSL*) vio->ssl_arg);
SSL_SESSION_set_timeout(SSL_get_session((SSL*) vio->ssl_arg), timeout);
SSL_set_fd ((SSL*) vio->ssl_arg, vio->sd);
diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c
index 498d10da0ee..44a077c33fc 100644
--- a/vio/viosslfactories.c
+++ b/vio/viosslfactories.c
@@ -80,7 +80,7 @@ static int
vio_set_cert_stuff(SSL_CTX *ctx, const char *cert_file, const char *key_file)
{
DBUG_ENTER("vio_set_cert_stuff");
- DBUG_PRINT("enter", ("ctx=%p, cert_file=%s, key_file=%s",
+ DBUG_PRINT("enter", ("ctx: %p, cert_file: %s, key_file: %s",
ctx, cert_file, key_file));
if (cert_file != NULL)
{
@@ -131,7 +131,7 @@ vio_verify_callback(int ok, X509_STORE_CTX *ctx)
int err,depth;
DBUG_ENTER("vio_verify_callback");
- DBUG_PRINT("enter", ("ok=%d, ctx=%p", ok, ctx));
+ DBUG_PRINT("enter", ("ok: %d, ctx: 0x%p", ok, ctx));
err_cert=X509_STORE_CTX_get_current_cert(ctx);
err= X509_STORE_CTX_get_error(ctx);
depth= X509_STORE_CTX_get_error_depth(ctx);
@@ -220,7 +220,7 @@ new_VioSSLConnectorFd(const char* key_file,
DH *dh;
DBUG_ENTER("new_VioSSLConnectorFd");
DBUG_PRINT("enter",
- ("key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s, cipher=%s",
+ ("key_file: %s, cert_file: %s, ca_path: %s, ca_file: %s, cipher: %s",
key_file, cert_file, ca_path, ca_file, cipher));
if (!(ptr=((struct st_VioSSLConnectorFd*)
@@ -315,7 +315,7 @@ new_VioSSLAcceptorFd(const char *key_file,
DH *dh;
DBUG_ENTER("new_VioSSLAcceptorFd");
DBUG_PRINT("enter",
- ("key_file=%s, cert_file=%s, ca_path=%s, ca_file=%s, cipher=%s",
+ ("key_file: %s, cert_file: %s, ca_path: %s, ca_file: %s, cipher: %s",
key_file, cert_file, ca_path, ca_file, cipher));
ptr= ((struct st_VioSSLAcceptorFd*)